Added app, tests, lint to BUCK file for web/gui2

Change-Id: I94912cb18f31db26971b66c9d851fb57f022df54
diff --git a/web/gui2/src/main/webapp/app/detectbrowser.directive.ts b/web/gui2/src/main/webapp/app/detectbrowser.directive.ts
index 2c2b335..b69ca39 100644
--- a/web/gui2/src/main/webapp/app/detectbrowser.directive.ts
+++ b/web/gui2/src/main/webapp/app/detectbrowser.directive.ts
@@ -37,10 +37,14 @@
         let browser = '';
         if (fs.isChrome()) {
             browser = 'chrome';
+        } else if (fs.isChromeHeadless()) {
+            browser = 'chromeheadless';
         } else if (fs.isSafari()) {
             browser = 'safari';
         } else if (fs.isFirefox()) {
             browser = 'firefox';
+        } else {
+            this.log.warn('Unknown browser:', window.navigator.vendor);
         }
         body.classList.add(browser);
 //        body.classed(browser, true);
diff --git a/web/gui2/src/main/webapp/app/fw/layer/detailspanel.service.ts b/web/gui2/src/main/webapp/app/fw/layer/detailspanel.service.ts
index dcd33b0..5699262 100644
--- a/web/gui2/src/main/webapp/app/fw/layer/detailspanel.service.ts
+++ b/web/gui2/src/main/webapp/app/fw/layer/detailspanel.service.ts
@@ -29,7 +29,7 @@
 export class DetailsPanelService {
 
   constructor(
-      private etc: EditableTextService,
+      private ets: EditableTextService,
       private fs: FnService,
       private is: IconService,
       private log: LogService,
diff --git a/web/gui2/src/main/webapp/app/fw/layer/loading.service.ts b/web/gui2/src/main/webapp/app/fw/layer/loading.service.ts
index 6c31f15..0d03ad6 100644
--- a/web/gui2/src/main/webapp/app/fw/layer/loading.service.ts
+++ b/web/gui2/src/main/webapp/app/fw/layer/loading.service.ts
@@ -36,7 +36,7 @@
 @Injectable()
 export class LoadingService {
     images: any[] = [];
-    idx: number = 0;
+    idx = 0;
     img: any;
     theme: string;
     task: any;
@@ -60,7 +60,7 @@
         let idx: number;
 
         this.dbg('preload images start...');
-        for (idx=1; idx<=nImgs; idx++) {
+        for (idx = 1; idx <= nImgs ; idx++) {
             this.addImg('light', idx);
             this.addImg('dark', idx);
         }
@@ -68,7 +68,7 @@
     }
 
     addImg(theme: string, idx: number) {
-        let img = new Image();
+        const img = new Image();
         img.src = this.fname(idx, theme);
         this.images.push(img);
     }
@@ -87,7 +87,7 @@
     startAnim() {
         this.dbg('start ANIMATION');
         this.theme = this.ts.getTheme();
-        let div = d3.select('#'+id);
+        let div = d3.select('#' + id);
         if (div.empty()) {
             div = d3.select('body')
                 .append('div')
@@ -107,7 +107,7 @@
             clearInterval(this.task);
             this.task = null;
         }
-        d3.select('#'+id).remove();
+        d3.select('#' + id).remove();
     }
 
     // schedule function to start animation in the future
diff --git a/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts b/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts
index 4189418..0691c72 100644
--- a/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts
+++ b/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts
@@ -89,12 +89,12 @@
      *  host:   if defined, is the host address to use
      */
     createWebSocket(opts, _host_: string = '') {
-        let wsport = (opts && opts.wsport) || null;
+        const wsport = (opts && opts.wsport) || null;
 
         this.webSockOpts = opts; // preserved for future calls
 
 //        this.host = _host_ || this.host();
-        let url = this.ufs.wsUrl('core', wsport, _host_);
+        const url = this.ufs.wsUrl('core', wsport, _host_);
 
         this.log.debug('Attempting to open websocket to: ' + url);
         this.ws = this.wsock.newWebSocket(url);
@@ -126,10 +126,10 @@
      * If the websocket is not up yet, we store it in a pending list.
      */
     sendEvent(evType, payload) {
-        let ev = <EventType> {
+        const ev = <EventType> {
             event: evType,
             payload: payload
-        }
+        };
 
         if (this.wsUp) {
             this._send(ev);
diff --git a/web/gui2/src/main/webapp/app/fw/svg/glyph.service.ts b/web/gui2/src/main/webapp/app/fw/svg/glyph.service.ts
index 5b080ea..7e8adb4 100644
--- a/web/gui2/src/main/webapp/app/fw/svg/glyph.service.ts
+++ b/web/gui2/src/main/webapp/app/fw/svg/glyph.service.ts
@@ -96,7 +96,7 @@
     registerGlyphs(data: Map<string, string>, overwrite: boolean = false): boolean {
         const dups: string[] = [];
         const missvb: string[] = [];
-        for (let [key, value] of data.entries()) {
+        for (const [key, value] of data.entries()) {
             const vbk = '_' + key;
             const vb = data.get(vbk);
 
@@ -120,7 +120,7 @@
             return false;
         }
 
-        for (let [key, value] of data.entries()) {
+        for (const [key, value] of data.entries()) {
 //        angular.forEach(data, function (value, key) {
             if (key[0] !== '_') {
                 this.addToMap(key, value, vb, overwrite, dups);
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon.directive.ts b/web/gui2/src/main/webapp/app/fw/svg/icon.directive.ts
index 95699d0..a8de561 100644
--- a/web/gui2/src/main/webapp/app/fw/svg/icon.directive.ts
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon.directive.ts
@@ -29,7 +29,7 @@
 })
 export class IconDirective implements OnInit {
     @Input() iconId: string;
-    @Input() iconSize: number = 20;
+    @Input() iconSize = 20;
 
     constructor(
         private el: ElementRef,
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon.service.ts b/web/gui2/src/main/webapp/app/fw/svg/icon.service.ts
index 8d9d3c6..674cbbf 100644
--- a/web/gui2/src/main/webapp/app/fw/svg/icon.service.ts
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon.service.ts
@@ -27,65 +27,65 @@
     // Maps icon ID to the glyph ID it uses.
     // NOTE: icon ID maps to a CSS class for styling that icon
     ['active', 'checkMark'],
-    ['inactive','xMark'],
+    ['inactive', 'xMark'],
 
-    ['plus','plus'],
-    ['minus','minus'],
-    ['play','play'],
-    ['stop','stop'],
+    ['plus', 'plus'],
+    ['minus', 'minus'],
+    ['play', 'play'],
+    ['stop', 'stop'],
 
-    ['upload','upload'],
-    ['download','download'],
-    ['delta','delta'],
-    ['nonzero','nonzero'],
-    ['close','xClose'],
+    ['upload', 'upload'],
+    ['download', 'download'],
+    ['delta', 'delta'],
+    ['nonzero', 'nonzero'],
+    ['close', 'xClose'],
 
-    ['topo','topo'],
+    ['topo', 'topo'],
 
-    ['refresh','refresh'],
-    ['query','query'],
-    ['garbage','garbage'],
+    ['refresh', 'refresh'],
+    ['query', 'query'],
+    ['garbage', 'garbage'],
 
 
-    ['upArrow','triangleUp'],
-    ['downArrow','triangleDown'],
+    ['upArrow', 'triangleUp'],
+    ['downArrow', 'triangleDown'],
 
-    ['appInactive','unknown'],
+    ['appInactive', 'unknown'],
 
-    ['node','node'],
-    ['devIcon_SWITCH','switch'],
-    ['devIcon_ROADM','roadm'],
-    ['devIcon_OTN','otn'],
+    ['node', 'node'],
+    ['devIcon_SWITCH', 'switch'],
+    ['devIcon_ROADM', 'roadm'],
+    ['devIcon_OTN', 'otn'],
 
-    ['portIcon_DEFAULT','m_ports'],
+    ['portIcon_DEFAULT', 'm_ports'],
 
-    ['meter','meterTable'], // TODO: m_meter icon?
+    ['meter', 'meterTable'], // TODO: m_meter icon?
 
-    ['deviceTable','switch'],
-    ['flowTable','flowTable'],
-    ['portTable','portTable'],
-    ['groupTable','groupTable'],
-    ['meterTable','meterTable'],
-    ['pipeconfTable','pipeconfTable'],
+    ['deviceTable', 'switch'],
+    ['flowTable', 'flowTable'],
+    ['portTable', 'portTable'],
+    ['groupTable', 'groupTable'],
+    ['meterTable', 'meterTable'],
+    ['pipeconfTable', 'pipeconfTable'],
 
-    ['hostIcon_endstation','endstation'],
-    ['hostIcon_router','router'],
-    ['hostIcon_bgpSpeaker','bgpSpeaker'],
+    ['hostIcon_endstation', 'endstation'],
+    ['hostIcon_router', 'router'],
+    ['hostIcon_bgpSpeaker', 'bgpSpeaker'],
 
     // navigation menu icons...
-    ['nav_apps','bird'],
-    ['nav_settings','cog'],
-    ['nav_cluster','node'],
-    ['nav_processors','allTraffic'],
+    ['nav_apps', 'bird'],
+    ['nav_settings', 'cog'],
+    ['nav_cluster', 'node'],
+    ['nav_processors', 'allTraffic'],
 
-    ['nav_topo','topo'],
-    ['nav_topo2','m_cloud'],
-    ['nav_devs','switch'],
-    ['nav_links','ports'],
-    ['nav_hosts','endstation'],
-    ['nav_intents','relatedIntents'],
-    ['nav_tunnels','ports'], // TODO: use tunnel glyph, when available
-    ['nav_yang','yang'],
+    ['nav_topo', 'topo'],
+    ['nav_topo2', 'm_cloud'],
+    ['nav_devs', 'switch'],
+    ['nav_links', 'ports'],
+    ['nav_hosts', 'endstation'],
+    ['nav_intents', 'relatedIntents'],
+    ['nav_tunnels', 'ports'], // TODO: use tunnel glyph, when available
+    ['nav_yang', 'yang'],
 ]);
 
 /**
@@ -104,7 +104,7 @@
     }
 
     ensureIconLibDefs() {
-        let body = d3.select('body');
+        const body = d3.select('body');
         let svg = body.select('svg#IconLibDefs');
         if (svg.empty()) {
             svg = body.append('svg').attr('id', 'IconLibDefs');
@@ -125,9 +125,9 @@
      *      Defaults to 'embeddedIcon'.
      */
     loadIcon(div, glyphId: string = 'unknown', size: number = 20, installGlyph: boolean = true, svgClass: string = 'embeddedIcon') {
-        let dim = size || 20;
-        let svgCls = svgClass || 'embeddedIcon';
-        let gid = glyphId || 'unknown';
+        const dim = size || 20;
+        const svgCls = svgClass || 'embeddedIcon';
+        const gid = glyphId || 'unknown';
         let g;
         let svgIcon: any;
 
@@ -168,7 +168,7 @@
      * @param svgClass The CSS class used to identify the SVG layer.
      *      Defaults to 'embeddedIcon'.
      */
-    loadIconByClass(div, iconCls: string, size: number, installGlyph: boolean, svgClass='embeddedIcon') {
+    loadIconByClass(div, iconCls: string, size: number, installGlyph: boolean, svgClass= 'embeddedIcon') {
         this.loadIcon(div, glyphMapping.get(iconCls), size, installGlyph, svgClass);
         div.select('svg g').classed(iconCls, true);
     }
@@ -202,7 +202,7 @@
      * Returns the D3 selection of the glyph (use) element.
      */
     addDeviceIcon(elem, glyphId, iconDim) {
-        let gid = this.gs.glyphDefined(glyphId) ? glyphId : 'query';
+        const gid = this.gs.glyphDefined(glyphId) ? glyphId : 'query';
         return elem.append('use').attr({
             'xlink:href': '#' + gid,
             width: iconDim,
@@ -211,9 +211,9 @@
     }
 
     addHostIcon(elem, radius, glyphId) {
-        let dim = radius * 1.5;
-        let xlate = -dim / 2;
-        let g = elem.append('g')
+        const dim = radius * 1.5;
+        const xlate = -dim / 2;
+        const g = elem.append('g')
                 .attr('class', 'svgIcon hostIcon');
 
         g.append('circle').attr('r', radius);
diff --git a/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.ts b/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.ts
index 99b94d2..45be81f 100644
--- a/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.ts
+++ b/web/gui2/src/main/webapp/app/fw/svg/icon/icon.component.ts
@@ -35,7 +35,7 @@
 })
 export class IconComponent implements OnInit {
     @Input() iconId: string;
-    @Input() iconSize: number = 20;
+    @Input() iconSize = 20;
 
     constructor(
         private is: IconService,
diff --git a/web/gui2/src/main/webapp/app/fw/util/fn.service.ts b/web/gui2/src/main/webapp/app/fw/util/fn.service.ts
index 25a0558..0726afc 100644
--- a/web/gui2/src/main/webapp/app/fw/util/fn.service.ts
+++ b/web/gui2/src/main/webapp/app/fw/util/fn.service.ts
@@ -24,43 +24,43 @@
 // TODO Move all this trie stuff to its own class
 // Angular>=2 Tightened up on types to avoid compiler errors
 interface TrieC {
-    p: any,
-    s: string[]
+    p: any;
+    s: string[];
 }
 // trie operation
 function _trieOp(op: string, trie, word: string, data) {
-    var p = trie,
-        w: string = word.toUpperCase(),
-        s: Array<string> = w.split(''),
-        c:TrieC = { p: p, s: s },
-        t = [],
-        x: number = 0,
-        f1 = op === '+' ? add : probe,
-        f2 = op === '+' ? insert : remove;
+    const p = trie;
+    const w: string = word.toUpperCase();
+    const s: Array<string> = w.split('');
+    let c: TrieC = { p: p, s: s };
+    let t = [];
+    let  x = 0;
+    const f1 = op === '+' ? add : probe;
+    const f2 = op === '+' ? insert : remove;
 
-    function add(c):TrieC {
-        var q = c.s.shift(),
-            np = c.p[q];
+    function add(cAdded): TrieC {
+        const q = cAdded.s.shift();
+        let np = cAdded.p[q];
 
         if (!np) {
-            c.p[q] = {};
-            np = c.p[q];
+            cAdded.p[q] = {};
+            np = cAdded.p[q];
             x = 1;
         }
-        return { p: np, s: c.s };
+        return { p: np, s: cAdded.s };
     }
 
-    function probe(c):TrieC {
-        var q = c.s.shift(),
-            k:number = Object.keys(c.p).length,
-            np = c.p[q];
+    function probe(cProbed): TrieC {
+        const q = cProbed.s.shift();
+        const k: number = Object.keys(cProbed.p).length;
+        const np = cProbed.p[q];
 
-        t.push({ q: q, k: k, p: c.p });
+        t.push({ q: q, k: k, p: cProbed.p });
         if (!np) {
             t = [];
             return { p: [], s: [] };
         }
-        return { p: np, s: c.s };
+        return { p: np, s: cProbed.s };
     }
 
     function insert() {
@@ -72,7 +72,7 @@
         if (t.length) {
             t = t.reverse();
             while (t.length) {
-                let d = t.shift();
+                const d = t.shift();
                 delete d.p[d.q];
                 if (d.k > 1) {
                     t = [];
@@ -109,9 +109,9 @@
 //    -1 for a partial match (word is a prefix to an existing word)
 //    data for the word for an exact match
 function trieLookup(trie, word) {
-    var s = word.toUpperCase().split(''),
-        p = trie,
-        n;
+    const s = word.toUpperCase().split('');
+    let p = trie;
+    let n;
 
     while (s.length) {
         n = s.shift();
@@ -142,10 +142,11 @@
         private log: LogService
     ) {
         this.route.queryParams.subscribe(params => {
-            let debugparam: string = params['debug'];
+            const debugparam: string = params['debug'];
+            log.debug('Param:', debugparam);
             this.parseDebugFlags(debugparam);
         });
-        log.debug("FnService constructed");
+        log.debug('FnService constructed');
     }
 
     isF(f) {
@@ -174,8 +175,8 @@
      * Returns true if current browser determined to be a mobile device
      */
     isMobile() {
-        var ua = window.navigator.userAgent,
-            patt = /iPhone|iPod|iPad|Silk|Android|BlackBerry|Opera Mini|IEMobile/;
+        const ua = window.navigator.userAgent;
+        const patt = /iPhone|iPod|iPad|Silk|Android|BlackBerry|Opera Mini|IEMobile/;
         return patt.test(ua);
     }
 
@@ -183,14 +184,21 @@
      * Returns true if the current browser determined to be Chrome
      */
     isChrome() {
-        let isChromium = (window as any).chrome;
-        let vendorName = window.navigator.vendor;
+        const isChromium = (window as any).chrome;
+        const vendorName = window.navigator.vendor;
 
-        let isOpera = window.navigator.userAgent.indexOf('OPR') > -1;
+        const isOpera = window.navigator.userAgent.indexOf('OPR') > -1;
         return (isChromium !== null &&
         isChromium !== undefined &&
         vendorName === 'Google Inc.' &&
-        isOpera == false);
+        isOpera === false);
+    }
+
+    isChromeHeadless() {
+        const vendorName = window.navigator.vendor;
+        const headlessChrome = window.navigator.userAgent.indexOf('HeadlessChrome') > -1;
+
+        return (vendorName === 'Google Inc.' && headlessChrome === true);
     }
 
     /**
@@ -226,8 +234,8 @@
     }
 
     parseDebugFlags(dbgstr: string): void {
-        let bits = dbgstr ? dbgstr.split(',') : [];
-        bits.forEach(function (key) {
+        const bits = dbgstr ? dbgstr.split(',') : [];
+        bits.forEach((key) => {
             this.debugFlags.set(key, true);
         });
         this.log.debug('Debug flags:', dbgstr);
diff --git a/web/gui2/src/main/webapp/app/fw/util/lion.service.ts b/web/gui2/src/main/webapp/app/fw/util/lion.service.ts
index 0090734..a33ef6b 100644
--- a/web/gui2/src/main/webapp/app/fw/util/lion.service.ts
+++ b/web/gui2/src/main/webapp/app/fw/util/lion.service.ts
@@ -67,7 +67,7 @@
         this.log.info('LION service: Locale... [' + data.locale + ']');
         this.log.info('LION service: Bundles installed...');
 
-        for (let p in this.ubercache) {
+        for (const p in this.ubercache) {
             if (this.ubercache[p]) {
                 this.log.info('            :=> ', p);
             }
diff --git a/web/gui2/src/main/webapp/app/fw/util/theme.service.ts b/web/gui2/src/main/webapp/app/fw/util/theme.service.ts
index 884fe5d..e5c9564 100644
--- a/web/gui2/src/main/webapp/app/fw/util/theme.service.ts
+++ b/web/gui2/src/main/webapp/app/fw/util/theme.service.ts
@@ -23,7 +23,7 @@
 @Injectable()
 export class ThemeService {
     themes: string[] = ['light', 'dark'];
-    thidx: number = 0;
+    thidx = 0;
 
     constructor(
         private log: LogService
diff --git a/web/gui2/src/main/webapp/app/onos.module.ts b/web/gui2/src/main/webapp/app/onos.module.ts
index 717893e..8e4af34 100644
--- a/web/gui2/src/main/webapp/app/onos.module.ts
+++ b/web/gui2/src/main/webapp/app/onos.module.ts
@@ -39,10 +39,10 @@
 import { OnosService } from './onos.service';
 
 const onosRoutes: Routes = [
-  { path: 'apps', component: AppsComponent },        // All except default should be driven by
-  { path: 'device', component: DeviceComponent },    // servlet like {INJECTED-VIEW-DATA-START}
-  { path: '**', component: DeviceComponent } //Change to Topo(2) when it's ready for normal behaviour
-]
+  { path: 'apps', component: AppsComponent },     // All except default should be driven by
+  { path: 'device', component: DeviceComponent }, // servlet like {INJECTED-VIEW-DATA-START}
+  { path: '**', component: DeviceComponent } // Change to Topo(2) when it's ready for normal behaviour
+];
 
 /**
  * ONOS GUI -- Main Application Module
diff --git a/web/gui2/src/main/webapp/app/view/apps/triggerform.directive.ts b/web/gui2/src/main/webapp/app/view/apps/triggerform.directive.ts
index 2bf9cd7..7134c3a 100644
--- a/web/gui2/src/main/webapp/app/view/apps/triggerform.directive.ts
+++ b/web/gui2/src/main/webapp/app/view/apps/triggerform.directive.ts
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 import { Directive } from '@angular/core';
+import { LogService } from '../../log.service';
 
 /**
  * ONOS GUI -- Apps -- Trigger Form Directive
@@ -23,6 +24,10 @@
 })
 export class TriggerFormDirective {
 
-  constructor() { }
+    constructor(
+        private log: LogService,
+    ) {
+        this.log.debug('TriggerFormDirective constructed');
+    }
 
 }