Exemplo n.º 1
0
Arquivo: index.js Projeto: Omati/Emma
const getOptions = function (options, done) {
  var SearchIndex = {}
  SearchIndex.options = Object.assign({}, {
    indexPath: 'si',
    keySeparator: '○',
    logLevel: 'ERROR',
    logHandler: Logger.createDefaultHandler()
  }, options)
  SearchIndex.options.log = Logger.get('search-index')
  // We pass the log level as string because the Logger[logLevel] returns
  // an object, and Object.assign deosn't make deep assign so it breakes
  // We used toUpperCase() for backward compatibility
  SearchIndex.options.log.setLevel(Logger[SearchIndex.options.logLevel.toUpperCase()])
  // Use the global one because the library doesn't support providing handler to named logger
  Logger.setHandler(SearchIndex.options.logHandler)
  if (!options.indexes) {
    level(SearchIndex.options.indexPath || 'si', {
      valueEncoding: 'json',
      db: down
    }, function (err, db) {
      SearchIndex.options.indexes = db
      return done(err, SearchIndex)
    })
  } else {
    return done(null, SearchIndex)
  }
}
Exemplo n.º 2
0
 postLog.push(function() {
   var stackTrace = Logger.formatStackTraceString(message['stack']);
   var logger = Logger;
   if (context.name) {
     logger = Logger.get(context['name']);
   }
   logger.info("Stack trace: ", stackTrace);
 });
 HawtioMainNav._module.factory('HawtioPerspective', [function() {
   var log = Logger.get('hawtio-dummy-perspective');
   return {
     add: function(id, perspective) {
       log.debug("add called for id: ", id);
     },
     remove: function(id) {
       log.debug("remove called for id: ", id);
       return undefined;
     },
     setCurrent: function(id) {
       log.debug("setCurrent called for id: ", id);
     },
     getCurrent: function(id) {
       log.debug("getCurrent called for id: ", id);
       return undefined;
     },
     getLabels: function() {
       return [];
     }
   };
 }]);
Exemplo n.º 4
0
var Logger = require('js-logger');
var markdown = require('markdown').markdown;
var fs = require('fs');

var logLevel = Logger[ (process.env["LOG_LEVEL"] || "warn").trim().toUpperCase() ] || Logger.WARN;
Logger.setLevel(logLevel);

var log = Logger.get("concordion-js");
var transformNodeLog = Logger.get('concordion-js.transformNode');
var transformLinkLog = Logger.get('concordion-js.transformLink');
var resolveLog = Logger.get('concordion-js.resolve');
var perfLog = Logger.get('concordion-js.perf');

var consoleHandler = Logger.createDefaultHandler();
var myHandler = function (messages, context) {
    //jQuery.post('/logs', { message: messages[0], level: context.level });
};

Logger.setHandler(function (messages, context) {
    consoleHandler(messages, context);
    myHandler(messages, context);
});

perfLog.time('runtime');

require('pegjs-require');

perfLog.time('concordion-expr.pegjs');
var cexpr = require('./concordion-expr.pegjs');
perfLog.timeEnd('concordion-expr.pegjs');
//var cexpr = require('./concordion-expr');
Exemplo n.º 5
0
export function getLogger(name : string) : Logger {
  return Logger.get(name);
}
Exemplo n.º 6
0
define(function(require, exports, module) {
    var $ = require('jquery');
    var Logger = require('js-logger');
    Logger.useDefaults();
    var L = Logger.get('main');
    var Converter = require('Converter');
    var Renderer = require('Renderer');
    var Player = require('Player');

    var musicjson;

    /*
    var examples = [
        './examples/scales.xml',
        './examples/sonata16.xml', // x
        './examples/adeste.xml',
        './examples/inv4.xml',
        './examples/inv1.xml',
        './examples/test_notations.xml',
        './examples/blank_a7.xml'
    ];
    */

    function load(url) {
        L.debug('load...... ' + url);
        // use xml example instead of using templates.js
        $.ajax({
            url: url,
            data: null,
            success: function(data) {
                musicjson = Converter.toJSON(data);
                /*
                var valid = tv4.validate(musicjson, schema);
                if(valid) { console.log('pre-validation success'); }
                else { console.log(tv4.error); }
                */

                var $container = $('#container');
                var renderer = new Renderer(musicjson, { $container: $container });
                renderer.draw();

                var player = new Player(renderer);
                player.load(function() {
                    L.debug('loaded');
                }, '/bower_components/midi-soundfonts/FluidR3_GM/');

                $('#play').off('click');
                $('#stop').off('click');
                $('#play').on('click', function() {
                    player.play();
                });

                $('#stop').on('click', function() {
                    player.stop();
                });

                /*
                var valid = tv4.validate(musicjson, schema);
                if(valid) { console.log('post-validation success'); }
                else { console.log(tv4.error); }
                */
            },
            dataType: 'xml'
        });
    }

    /*
    $(document).ready(function() {
        $.getJSON('/schema/musicjson.json', function(schema) {
            onReady(schema);
        });
    });
    */
    var defaultUrl = $('#score').val();
    load(defaultUrl);

    $('#score').on('change', function() {
        $('#container').empty();
        var url = $('#score').val();
        load(url);
    });
});
Exemplo n.º 7
0
var HawtioCore = (function () {

    function HawtioCoreClass() {

    }

    /**
     * The app's injector, set once bootstrap is completed
     */
    Object.defineProperty(HawtioCoreClass.prototype, "injector", {
      get: function() {
        if (HawtioCore.UpgradeAdapter) {
          return HawtioCore.UpgradeAdapter.ng1Injector;
        }
        return HawtioCore._injector;
      },
      enumerable: true,
      configurable: true
    });

    var HawtioCore = new HawtioCoreClass();

    /**
     * This plugin's name and angular module
     */
    HawtioCore.pluginName = "hawtio-core";
    /**
     * This plugins logger instance
     */
    var log = Logger.get(HawtioCore.pluginName);

    var _module = angular.module(HawtioCore.pluginName, []);
    _module.config(["$locationProvider", function ($locationProvider) {
      $locationProvider.html5Mode(true);
    }]);

    _module.run(['documentBase', function (documentBase) {
      log.debug("loaded");
    }]);

    var dummyLocalStorage = {
      length: 0,
      key: function(index) { return undefined; },
      getItem: function (key) { return dummyLocalStorage[key]; },
      setItem: function (key, data) { dummyLocalStorage[key] = data; },
      removeItem: function(key) {
        var removed = dummyLocalStorage[key];
        delete dummyLocalStorage[key];
        return removed;
      },
      clear: function() {

      }
    };
    HawtioCore.dummyLocalStorage = dummyLocalStorage;

    HawtioCore.documentBase = function() {
      var base = $('head').find('base');
      var answer = '/'
      if (base && base.length > 0) {
        answer = base.attr('href');
      } else {
        log.warn("Document is missing a 'base' tag, defaulting to '/'");
      }
      //log.debug("Document base: ", answer);
      return answer;
    }

    /**
     * services, mostly stubs
     */
    // localStorage service, returns a dummy impl
    // if for some reason it's not in the window
    // object
    _module.factory('localStorage', function() {
      return window.localStorage || dummyLocalStorage;
    });

    // Holds the document base so plugins can easily
    // figure out absolute URLs when needed
    _module.factory('documentBase', function() {
      return HawtioCore.documentBase();
    });


    // Holds a mapping of plugins to layouts, plugins use
    // this to specify a full width view, tree view or their
    // own custom view
    _module.factory('viewRegistry', function() {
      return {};
    });

    // Placeholder service for the help registry
    _module.factory('helpRegistry', function() {
      return {
        addUserDoc: function() {},
        addDevDoc: function() {},
        addSubTopic: function() {},
        getOrCreateTopic: function() { return undefined; },
        mapTopicName: function() { return undefined; },
        mapSubTopicName: function() { return undefined; },
        getTopics: function() { return undefined; },
        disableAutodiscover: function() {},
        discoverHelpFiles: function() {}
      };
    });

    // Placeholder service for the preferences registry
    _module.factory('preferencesRegistry', function() {
      return {
        addTab: function() {},
        getTab: function() { return undefined; },
        getTabs: function() { return undefined; }
      };
    });

    // Placeholder service for the page title service
    _module.factory('pageTitle', function() {
      return {
        addTitleElement: function() {},
        getTitle: function() { return undefined; },
        getTitleWithSeparator: function() { return undefined; },
        getTitleExcluding: function() { return undefined; },
        getTitleArrayExcluding: function() { return undefined; }
      };
    });

    // service for the javascript object that does notifications
    _module.factory('toastr', ["$window", function ($window) {
      var answer = $window.toastr;
      if (!answer) {
        // lets avoid any NPEs
        answer = {};
        $window.toastr = answer;
      }
      return answer;
    }]);

    _module.factory('HawtioDashboard', function() {
      return {
        hasDashboard: false,
        inDashboard: false,
        getAddLink: function() {
          return '';
        }
      };
    });

    // Placeholder service for branding
    _module.factory('branding', function() {
      return {};
    });

    // Placeholder user details service
    _module.factory('userDetails', function() {
      return {
        logout: function() {
          log.debug("Dummy userDetails.logout()");
        }
      };
    });

    hawtioPluginLoader.addModule("ng");
    hawtioPluginLoader.addModule(require('angular-sanitize'));
    hawtioPluginLoader.addModule(HawtioCore.pluginName);

    // bootstrap the app
    $(function () {

      jQuery.uaMatch = function( ua ) {
        ua = ua.toLowerCase();

        var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
          /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
          /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
          /(msie) ([\w.]+)/.exec( ua ) ||
          ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
          [];

        return {
          browser: match[ 1 ] || "",
          version: match[ 2 ] || "0"
        };
      };

      // Don't clobber any existing jQuery.browser in case it's different
      if ( !jQuery.browser ) {
        var matched = jQuery.uaMatch( navigator.userAgent );
        var browser = {};

        if ( matched.browser ) {
          browser[ matched.browser ] = true;
          browser.version = matched.version;
        }

        // Chrome is Webkit, but Webkit is also Safari.
        if ( browser.chrome ) {
          browser.webkit = true;
        } else if ( browser.webkit ) {
          browser.safari = true;
        }

        jQuery.browser = browser;
      }

      if (window.ng && window.ng.upgrade) {
        // Create this here so that plugins can use pre-bootstrap tasks
        // to add providers
        HawtioCore.UpgradeAdapter = new ng.upgrade.UpgradeAdapter();
      }

      hawtioPluginLoader.loadPlugins(function() {

        if (HawtioCore.injector || HawtioCore.UpgradeAdapterRef) {
          log.debug("Application already bootstrapped");
          return;
        }

        var strictDi = localStorage['hawtioCoreStrictDi'] || false;
        if (strictDi) {
          log.debug("Using strict dependency injection");
        }

        var bootstrapEl = hawtioPluginLoader.getBootstrapElement();
        log.debug("Using bootstrap element: ", bootstrapEl);

        // bootstrap in hybrid mode if angular2 is detected
        if (HawtioCore.UpgradeAdapter) {
          log.debug("ngUpgrade detected, bootstrapping in Angular 1/2 hybrid mode");
          HawtioCore.UpgradeAdapterRef = HawtioCore.UpgradeAdapter.bootstrap(bootstrapEl, hawtioPluginLoader.getModules(), { strictDi: strictDi });
          HawtioCore._injector = HawtioCore.UpgradeAdapterRef.ng1Injector;
        } else {

          HawtioCore._injector = angular.bootstrap(bootstrapEl, hawtioPluginLoader.getModules(), {
            strictDi: strictDi
          });
        }
        log.debug("Bootstrapped application");
      });
    });
    return HawtioCore;
})();
Exemplo n.º 8
0
 childLoggers.forEach(function(child) {
   Logger.get(child.logger).setLevel(Logger[child.level]);
 });
Exemplo n.º 9
0
var hawtioPluginLoader = (function(self) {

  var log = Logger.get('hawtio-loader');

  var bootstrapEl = document.documentElement;

  self.log = log;

  /**
   * List of URLs that the plugin loader will try and discover
   * plugins from
   * @type {Array}
   */
  self.urls = [];

  /**
   * Holds all of the angular modules that need to be bootstrapped
   * @type {Array}
   */
  self.modules = [];

  /**
   * Tasks to be run before bootstrapping, tasks can be async.
   * Supply a function that takes the next task to be
   * executed as an argument and be sure to call the passed
   * in function.
   *
   * @type {Array}
   */
  self.tasks = [];

  self.setBootstrapElement = function(el) {
    log.debug("Setting bootstrap element to: ", el);
    bootstrapEl = el;
  }

  self.getBootstrapElement = function() {
    return bootstrapEl;
  }

  self.registerPreBootstrapTask = function(task, front) {
    var tObj = task;
    var unnamed = 'unnamed-task-' + (self.tasks.length + 1)
    if (angular.isFunction(task)) {
      log.debug("Adding legacy task");
      tObj = {
        name: unnamed,
        task: task
      }
    }
    if (!task.name) {
      task.name = unnamed;
    }
    if (task.depends && !angular.isArray(task.depends) && task.depends !== '*') {
      task.depends = [task.depends];
    }
    if (!front) {
      self.tasks.push(tObj);
    } else {
      self.tasks.unshift(tObj);
    }
  };

  self.addModule = function(module) {
    log.debug("Adding module: " + module);
    self.modules.push(module);
  };

  self.addUrl = function(url) {
    log.debug("Adding URL: " + url);
    self.urls.push(url);
  };

  self.getModules = function() {
    return self.modules;
  };

  self.loaderCallback = null;

  self.setLoaderCallback = function(cb) {
    self.loaderCallback = cb;
    // log.debug("Setting callback to : ", self.loaderCallback);
  };

  function intersection(search, needle) {
    if (!angular.isArray(needle)) {
      needle = [needle];
    }
    //self.log.debug("Search: ", search);
    //self.log.debug("Needle: ", needle);
    var answer = [];
    needle.forEach(function(n) {
      search.forEach(function(s) {
        if (n === s) {
          answer.push(s);
        }
      });
    });
    return answer;
  }


  self.loadPlugins = function(callback) {

    var lcb = self.loaderCallback;

    var plugins = {};

    var urlsToLoad = self.urls.length;
    var totalUrls = urlsToLoad;

    var bootstrap = function() {
      var executedTasks = [];
      var deferredTasks = [];

      var bootstrapTask = {
        name: 'Hawtio Bootstrap',
        depends: '*',
        runs: 0,
        task: function(next) {
          function listTasks() {
            deferredTasks.forEach(function(task) {
              self.log.info("  name: " + task.name + " depends: ", task.depends);
            });
          }
          if (deferredTasks.length > 0) {
            self.log.info("tasks yet to run: ");
            listTasks();
            bootstrapTask.runs = bootstrapTask.runs + 1;
            self.log.info("Task list restarted : ", bootstrapTask.runs, " times");
            if (bootstrapTask.runs === 5) {
              self.log.info("Orphaned tasks: ");
              listTasks();
              deferredTasks.length = 0;
            } else {
              deferredTasks.push(bootstrapTask);
            }
          }
          self.log.debug("Executed tasks: ", executedTasks);
          next();
        }
      }

      self.registerPreBootstrapTask(bootstrapTask);

      var executeTask = function() {
        var tObj = null;
        var tmp = [];
        // if we've executed all of the tasks, let's drain any deferred tasks
        // into the regular task queue
        if (self.tasks.length === 0) {
          tObj = deferredTasks.shift();
        }
        // first check and see what tasks have executed and see if we can pull a task
        // from the deferred queue
        while(!tObj && deferredTasks.length > 0) {
          var task = deferredTasks.shift();
          if (task.depends === '*') {
            if (self.tasks.length > 0) {
              tmp.push(task);
            } else {
              tObj = task;
            }
          } else {
            var intersect = intersection(executedTasks, task.depends);
            if (intersect.length === task.depends.length) {
              tObj = task;
            } else {
              tmp.push(task);
            }
          }
        }
        if (tmp.length > 0) {
          tmp.forEach(function(task) {
            deferredTasks.push(task);
          });
        }
        // no deferred tasks to execute, let's get a new task
        if (!tObj) {
          tObj = self.tasks.shift();
        }
        // check if task has dependencies
        if (tObj && tObj.depends && self.tasks.length > 0) {
          self.log.debug("Task '" + tObj.name + "' has dependencies: ", tObj.depends);
          if (tObj.depends === '*') {
            if (self.tasks.length > 0) {
              self.log.debug("Task '" + tObj.name + "' wants to run after all other tasks, deferring");
              deferredTasks.push(tObj);
              executeTask();
              return;
            }
          } else {
            var intersect = intersection(executedTasks, tObj.depends);
            if (intersect.length != tObj.depends.length) {
              self.log.debug("Deferring task: '" + tObj.name + "'");
              deferredTasks.push(tObj);
              executeTask();
              return;
            }
          }
        }
        if (tObj) {
          self.log.debug("Executing task: '" + tObj.name + "'");
          //self.log.debug("ExecutedTasks: ", executedTasks);
          var called = false;
          var next = function() {
            if (next.notFired) {
              next.notFired = false;
              executedTasks.push(tObj.name);
              setTimeout(executeTask, 1);
            }
          }
          next.notFired = true;
          tObj.task(next);
        } else {
          self.log.debug("All tasks executed");
          setTimeout(callback, 1);
        }
      };
      setTimeout(executeTask, 1);
    };

    var loadScripts = function() {

      // keep track of when scripts are loaded so we can execute the callback
      var loaded = 0;
      $.each(plugins, function(key, data) {
        loaded = loaded + data.Scripts.length;
      });

      var totalScripts = loaded;

      var scriptLoaded = function() {
        $.ajaxSetup({async:true});
        loaded = loaded - 1;
        if (lcb) {
          lcb.scriptLoaderCallback(lcb, totalScripts, loaded + 1);
        }
        if (loaded === 0) {
          bootstrap();
        }
      };

      if (loaded > 0) {
        $.each(plugins, function(key, data) {

          data.Scripts.forEach( function(script) {

            // log.debug("Loading script: ", data.Name + " script: " + script);

            var scriptName = data.Context + "/" + script;
            log.debug("Fetching script: ", scriptName);
            $.ajaxSetup({async:false});
            $.getScript(scriptName)
            .done(function(textStatus) {
              log.debug("Loaded script: ", scriptName);
            })
            .fail(function(jqxhr, settings, exception) {
              log.info("Failed loading script: \"", exception.message, "\" (<a href=\"", scriptName, ":", exception.lineNumber, "\">", scriptName, ":", exception.lineNumber, "</a>)");
            })
            .always(scriptLoaded);
          });
        });
      } else {
        // no scripts to load, so just do the callback
        $.ajaxSetup({async:true});
        bootstrap();
      }
    };

    if (urlsToLoad === 0) {
      loadScripts();
    } else {
      var urlLoaded = function () {
        urlsToLoad = urlsToLoad - 1;
        if (lcb) {
          lcb.urlLoaderCallback(lcb, totalUrls, urlsToLoad + 1);
        }
        if (urlsToLoad === 0) {
          loadScripts();
        }
      };

      var regex = new RegExp(/^jolokia:/);

      $.each(self.urls, function(index, url) {

        if (regex.test(url)) {
          var parts = url.split(':');
          parts = parts.reverse();
          parts.pop();

          url = parts.pop();
          var attribute = parts.reverse().join(':');
          var jolokia = new Jolokia(url);

          try {
            var data = jolokia.getAttribute(attribute, null);
            $.extend(plugins, data);
          } catch (Exception) {
            // console.error("Error fetching data: " + Exception);
          }
          urlLoaded();
        } else {

          log.debug("Trying url: ", url);

          $.get(url, function (data) {
            if (angular.isString(data)) {
              try {
                data = angular.fromJson(data);
              } catch (error) {
                // ignore this source of plugins
                return;
              }
            }
            // log.debug("got data: ", data);
            $.extend(plugins, data);
          }).always(function() {
            urlLoaded();
          });
        }
      });
    }
  };

  self.debug = function() {
    log.debug("urls and modules");
    log.debug(self.urls);
    log.debug(self.modules);
  };

  self.setLoaderCallback({
    scriptLoaderCallback: function (self, total, remaining) {
      log.debug("Total scripts: ", total, " Remaining: ", remaining);
    },
    urlLoaderCallback: function (self, total, remaining) {
      log.debug("Total URLs: ", total, " Remaining: ", remaining);
    }
  });

  return self;

})(hawtioPluginLoader || {}, window, undefined);
(function(HawtioMainNav) {

  function documentBase($document) {
    var base = $document.find('base');
    return base.attr('href');
  }

  function trimLeading(text, prefix) {
    if (text && prefix) {
      if (_.startsWith(text, prefix) || text.indexOf(prefix) === 0) {
        return text.substring(prefix.length);
      }
    }
    return text;
  }

  HawtioMainNav.pluginName = 'hawtio-nav';
  var log = Logger.get(HawtioMainNav.pluginName);

  // Actions class with some pre-defined actions
  var Actions = (function() {
    function Actions() {}
    Object.defineProperty(Actions, "ADD", {
      get: function() {
        return 'hawtio-main-nav-add';
      },
      enumerable: true,
      configurable: true
    });
    Object.defineProperty(Actions, "REMOVE", {
      get: function() {
        return 'hawtio-main-nav-remove';
      },
      enumerable: true,
      configurable: true
    });
    Object.defineProperty(Actions, "CHANGED", {
      get: function() {
        return 'hawtio-main-nav-change';
      },
      enumerable: true,
      configurable: true
    });
    Object.defineProperty(Actions, "REDRAW", {
      get: function() {
        return 'hawtio-main-nav-redraw';
      },
      enumerable: true,
      configurable: true
    });
    return Actions;
  })();
  HawtioMainNav.Actions = Actions;

  // Class RegistryImpl
  var RegistryImpl = (function() {
    function RegistryImpl(root) {
      this.items = [];
      this.root = root;
      /*
         this.on(HawtioMainNav.Actions.ADD, 'log', function (item) {
         console.log('Adding item with id: ', item.id);
         });
         this.on(HawtioMainNav.Actions.REMOVE, 'log', function (item) {
         console.log('Removing item with id: ', item.id);
         });
         */
    }
    RegistryImpl.prototype.builder = function() {
      return new HawtioMainNav.NavItemBuilderImpl();
    };
    RegistryImpl.prototype.add = function(item) {
      var _this = this;
      var items = [];
      for (var _i = 1; _i < arguments.length; _i++) {
        items[_i - 1] = arguments[_i];
      }
      var toAdd = _.union([item], items);
      this.items = _.union(this.items, toAdd);
      toAdd.forEach(function(item) {
        _this.root.dispatchEvent(new CustomEvent(HawtioMainNav.Actions.ADD, {
          detail: {
            item: item
          }
        }));
      });
      this.root.dispatchEvent(new CustomEvent(HawtioMainNav.Actions.CHANGED, {
        detail: {
          items: this.items
        }
      }));
      this.root.dispatchEvent(new CustomEvent(HawtioMainNav.Actions.REDRAW, {
        detail: {}
      }));
    };
    RegistryImpl.prototype.remove = function(search) {
      var _this = this;
      var removed = _.remove(this.items, search);
      removed.forEach(function(item) {
        _this.root.dispatchEvent(new CustomEvent(HawtioMainNav.Actions.REMOVE, {
          detail: {
            item: item
          }
        }));
      });
      this.root.dispatchEvent(new CustomEvent(HawtioMainNav.Actions.CHANGED, {
        detail: {
          items: this.items
        }
      }));
      this.root.dispatchEvent(new CustomEvent(HawtioMainNav.Actions.REDRAW, {
        detail: {}
      }));
      return removed;
    };
    RegistryImpl.prototype.iterate = function(iterator) {
      this.items.forEach(iterator);
    };
    RegistryImpl.prototype.selected = function() {
      var valid = _.filter(this.items, function(item) {
        if (!item.isValid) {
          return true;
        }
        return item.isValid()
      });
      var answer = _.find(valid, function(item) {
        if (!item.isSelected) {
          return false;
        }
        return item.isSelected();
      });
      return answer;
    };
    RegistryImpl.prototype.on = function(action, key, fn) {
      var _this = this;
      switch (action) {
        case HawtioMainNav.Actions.ADD:
          this.root.addEventListener(HawtioMainNav.Actions.ADD, function(event) {
            //log.debug("event key: ", key, " event: ", event);
            fn(event.detail.item);
          });
          if (this.items.length > 0) {
            this.items.forEach(function(item) {
              _this.root.dispatchEvent(new CustomEvent(HawtioMainNav.Actions.ADD, {
                detail: {
                  item: item
                }
              }));
            });
          }
          break;
        case HawtioMainNav.Actions.REMOVE:
          this.root.addEventListener(HawtioMainNav.Actions.REMOVE, function(event) {
            //log.debug("event key: ", key, " event: ", event);
            fn(event.detail.item);
          });
          break;
        case HawtioMainNav.Actions.CHANGED:
          this.root.addEventListener(HawtioMainNav.Actions.CHANGED, function(event) {
            //log.debug("event key: ", key, " event: ", event);
            fn(event.detail.items);
          });
          if (this.items.length > 0) {
            this.root.dispatchEvent(new CustomEvent(HawtioMainNav.Actions.CHANGED, {
              detail: {
                items: _this.items
              }
            }));
          }
          break;
        case HawtioMainNav.Actions.REDRAW:
          this.root.addEventListener(HawtioMainNav.Actions.REDRAW, function(event) {
            //log.debug("event key: ", key, " event: ", event);
            fn(event);
          });
          var event = new CustomEvent(HawtioMainNav.Actions.REDRAW, {
            detail: {
              text: ''
            }
          });
          this.root.dispatchEvent(event);
          break;
        default:
      }
    };
    return RegistryImpl;
  })();

  // Factory for registry, used to create angular service
  function createRegistry(root) {
    return new RegistryImpl(root);
  }
  HawtioMainNav.createRegistry = createRegistry;

  // Class NavItemBuilderImpl
  var NavItemBuilderImpl = (function() {
    function NavItemBuilderImpl() {
      this.self = {
        id: ''
      };
    }
    NavItemBuilderImpl.join = function() {
      var paths = [];
      for (var _i = 0; _i < arguments.length; _i++) {
        paths[_i - 0] = arguments[_i];
      }
      var tmp = [];
      var length = paths.length - 1;
      paths.forEach(function (path, index) {
        if (!path || path === '') {
          return;
        }
        if (index !== 0 && path.charAt(0) === '/') {
          path = path.slice(1);
        }
        if (index !== length && path.charAt(path.length) === '/') {
          path = path.slice(0, path.length - 1);
        }
        if (path && path !== '') {
          tmp.push(path);
        }
      });
      var rc = tmp.join('/');
      return rc;
    };
    NavItemBuilderImpl.prototype.id = function(id) {
      this.self.id = id;
      return this;
    };
    NavItemBuilderImpl.prototype.rank = function(rank) {
      this.self.rank = rank;
      return this;
    };
    NavItemBuilderImpl.prototype.title = function(title) {
      this.self.title = title;
      return this;
    };
    NavItemBuilderImpl.prototype.tooltip = function(tooltip) {
      this.self.tooltip = tooltip;
      return this;
    };
    NavItemBuilderImpl.prototype.page = function(page) {
      this.self.page = page;
      return this;
    };
    NavItemBuilderImpl.prototype.reload = function(reload) {
      this.self.reload = reload;
      return this;
    };
    NavItemBuilderImpl.prototype.attributes = function(attributes) {
      this.self.attributes = attributes;
      return this;
    };
    NavItemBuilderImpl.prototype.linkAttributes = function(attributes) {
      this.self.linkAttributes = attributes;
      return this;
    };
    NavItemBuilderImpl.prototype.context = function(context) {
      this.self.context = context;
      return this;
    };
    NavItemBuilderImpl.prototype.href = function(href) {
      this.self.href = href;
      return this;
    };
    NavItemBuilderImpl.prototype.click = function(click) {
      this.self.click = click;
      return this;
    };
    NavItemBuilderImpl.prototype.isSelected = function(isSelected) {
      this.self.isSelected = isSelected;
      return this;
    };
    NavItemBuilderImpl.prototype.isValid = function(isValid) {
      this.self.isValid = isValid;
      return this;
    };
    NavItemBuilderImpl.prototype.show = function(show) {
      this.self.show = show;
      return this;
    };
    NavItemBuilderImpl.prototype.template = function(template) {
      this.self.template = template;
      return this;
    };
    NavItemBuilderImpl.prototype.defaultPage = function(defaultPage) {
      this.self.defaultPage = defaultPage;
      return this;
    };
    NavItemBuilderImpl.prototype.tabs = function(item) {
      var items = [];
      for (var _i = 1; _i < arguments.length; _i++) {
        items[_i - 1] = arguments[_i];
      }
      this.self.tabs = _.union(this.self.tabs, [item], items);
      return this;
    };
    NavItemBuilderImpl.prototype.subPath = function(title, path, page, rank, reload, isValid) {

      var parent = this.self;
      if (!this.self.tabs) {
        this.self.tabs = [];
      }
      var tab = {
        id: parent.id + '-' + path,
        title: function() {
          return title;
        },
        href: function() {
          if (parent.href) {
            return NavItemBuilderImpl.join(parent.href(), path);
          }
          return path;
        }
      };
      if (!_.isUndefined(page)) {
        tab.page = function() {
          return page;
        };
      }
      if (!_.isUndefined(rank)) {
        tab.rank = rank;
      }
      if (!_.isUndefined(reload)) {
        tab.reload = reload;
      }
      if (!_.isUndefined(isValid)) {
        tab.isValid = isValid;
      }
      this.self.tabs.push(tab);
      return this;
    };
    NavItemBuilderImpl.prototype.build = function() {
      var answer = _.cloneDeep(this.self);
      this.self = {
        id: ''
      };
      return answer;
    };
    return NavItemBuilderImpl;
  })();
  HawtioMainNav.NavItemBuilderImpl = NavItemBuilderImpl;

  // Factory functions
  HawtioMainNav.createBuilder = function() {
    return new HawtioMainNav.NavItemBuilderImpl();
  };

  // Plugin initialization
  var _module = angular.module(HawtioMainNav.pluginName, ['ngRoute']);
  HawtioMainNav._module = _module;

  _module.constant('layoutFull', 'templates/main-nav/layoutFull.html');

  _module.config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) {
    $locationProvider.html5Mode({
      enabled: true,
      requireBase: true
    });
    $routeProvider.otherwise({ templateUrl: 'templates/main-nav/welcome.html' });
  }]);

  _module.controller('HawtioNav.WelcomeController', ['$scope', '$location', 'WelcomePageRegistry', 'HawtioNav', '$timeout', '$document', function($scope, $location, welcome, nav, $timeout, $document) {

    function gotoNavItem(item) {
      if (item && item.href) {
        var href = trimLeading(item.href(), documentBase($document));
        var uri = new URI(href);
        var search = _.merge($location.search(), uri.query(true));
        log.debug("Going to item id: ", item.id, " href: ", uri.path(), " query: ", search);
        $timeout(function() {
          $location.path(uri.path()).search(search);
        }, 10);
      }
    }

    function gotoFirstAvailableNav() {
      var candidates = [];
      nav.iterate(function(item) {
        var isValid = item.isValid || function() { return true; };
        var show = item.show || function() { return true; };
        if (isValid() && show()) {
          candidates.push(item);
        }
      });
      var rankedCandidates = sortByRank(candidates);
      gotoNavItem(rankedCandidates[0]);
    }

    $timeout(function() {
      var search = $location.search();
      if (search.tab) {
        var tab = search.tab;
        var selected;
        nav.iterate(function (item) {
          if (!selected && item.id === tab) {
            selected = item;
          }
        });
        if (selected) {
          gotoNavItem(selected);
          return;
        }
      }
      var candidates = [];
      nav.iterate(function(item) {
        if ('defaultPage' in item) {
          var page = item.defaultPage;
          if (!('rank' in page)) {
            candidates.push(item);
            return;
          }
          var index = _.findIndex(candidates, function(i) {
            if ('rank' in i && item.rank > i.rank) {
              return true;
            }
          });
          if (index < 0) {
            candidates.push(item);
          } else {
            candidates.splice(index, 0, item);
          }
        }
      });

      function welcomePageFallback() {
        if (welcome.pages.length === 0) {
          log.debug("No welcome pages, going to first available nav");
          gotoFirstAvailableNav();
        }
        var sortedPages = _.sortBy(welcome.pages, function(page) { return page.rank; });
        var page = _.find(sortedPages, function(page) {
          if ('isValid' in page) {
            return page.isValid();
          }
          return true;
        });
        if (page) {
          gotoNavItem(page);
        } else {
          gotoFirstAvailableNav();
        }
      }

      function evalCandidates(candidates) {
        if (candidates.length === 0) {
          welcomePageFallback();
          return;
        }
        var item = candidates.pop();
        var remaining = candidates;
        log.debug("Trying candidate: ", item, " remaining: ", remaining);
        if (!item) {
          welcomePageFallback();
          return;
        }
        var func = item.defaultPage.isValid;
        if (func) {
          var yes = function() {
            gotoNavItem(item);
          };
          var no = function() {
            evalCandidates(remaining);
          };
          try {
            func(yes, no);
          } catch (err) {
            log.debug("Failed to eval item: ", item.id, " error: ", err);
            no();
          }
        } else {
          evalCandidates(remaining);
        }
      }
      evalCandidates(candidates);
    }, 500);
  }]);

  _module.controller('HawtioNav.ViewController', ['$scope', '$route', '$location', 'layoutFull', 'viewRegistry', function($scope, $route, $location, layoutFull, viewRegistry) {

    findViewPartial();

    $scope.$on("$routeChangeSuccess", function (event, current, previous) {
      findViewPartial();
    });

    function searchRegistryViaQuery(query) {
      var answer = undefined;
      if (!query || _.keys(query).length === 0) {
        log.debug("No query, skipping query matching");
        return;
      }
      var keys = _.keys(viewRegistry);
      var candidates = _.filter(keys, function(key) { return key.charAt(0) === '{'; });
      candidates.forEach(function(candidate) {
        if (!answer) {
          try {
            var obj = angular.fromJson(candidate);
            if (_.isObject(obj)) {
              _.merge(obj, query, function(a, b) {
                if (a) {
                  if (a === b) {
                    answer = viewRegistry[candidate];
                  } else {
                    answer = undefined;
                  }
                }
              });
            }
          } catch (e) {
            // ignore and move on...
            log.debug("Unable to parse json: ", candidate);
          }
        }
      });
      return answer;
    }

    function searchRegistry(path) {
      var answer = undefined;
      _.forIn(viewRegistry, function (value, key) {
        if (!answer) {
          try {
            var reg = new RegExp(key, "");
            if (reg.exec(path)) {
              answer = value;
            }
          } catch (e) {
            log.debug("Invalid RegExp " + key + " for viewRegistry value: " + value);
          }
        }
      });
      return answer;
    }

    function findViewPartial() {
      var answer = null;
      var hash = $location.search();
      answer = searchRegistryViaQuery(hash);
      if (answer) {
        log.debug("View partial matched on query");
      }
      if (!answer) {
        var path = $location.path();
        if (path) {
          answer = searchRegistry(path);
          if (answer) {
            log.debug("View partial matched on path name");
          }
        }
      }
      if (!answer) {
        answer = layoutFull;
        log.debug("Using default view partial");
      }
      $scope.viewPartial = answer;

      log.debug("Using view partial: " + answer);
      return answer;
    }
  }]);

  _module.run(['HawtioNav', '$rootScope', '$route', '$document', function(HawtioNav, $rootScope, $route, $document) {
    HawtioNav.on(HawtioMainNav.Actions.CHANGED, "$apply", function(item) {
      if(!$rootScope.$$phase) {
        $rootScope.$apply();
      }
    });

    var href = documentBase($document);

    function applyBaseHref(item) {
      if (!item.preBase) {
        item.preBase = item.href;
        item.href = function() {
          if (href) {
            var preBase = item.preBase();
            if (preBase && preBase.charAt(0) === '/') {
              preBase = preBase.substr(1);
	            return href + preBase;
            }
          }
          return item.preBase();
        };
      }
    }
    HawtioNav.on(HawtioMainNav.Actions.ADD, "htmlBaseRewriter", function(item) {
			if (item.href) {
	      applyBaseHref(item);
	      _.forEach(item.tabs, applyBaseHref);
			}
    });
    HawtioNav.on(HawtioMainNav.Actions.ADD, "$apply", function(item) {
      var oldClick = item.click;
      item.click = function($event) {
        if (!($event instanceof jQuery.Event)) {
          try {
            if(!$rootScope.$$phase) {
              $rootScope.$apply();
            }
          } catch (e) {
            // ignore
          }
        }
        if (oldClick) {
          oldClick($event);
        }
      };
    });
    $route.reload();
    log.debug("loaded");
  }]);
  adminjsCore.hawtioPluginLoader.addModule(HawtioMainNav.pluginName);
  adminjsCore.hawtioPluginLoader.addModule(require('angular-route'));

  // helper function for testing nav items
  function itemIsValid(item) {
    if (!('isValid' in item)) {
      return true;
    }
    if (_.isFunction(item.isValid)) {
      return item.isValid();
    }
    return false;
  }

  // Construct once and share between invocations to avoid memory leaks
  var tmpLink = $('<a>');
  function addIsSelected($location, item) {
    if (!('isSelected' in item) && 'href' in item) {
      item.isSelected = function() {
        // item.href() might be relative, in which
        // case we should let the browser resolve
        // what the full path should be
        tmpLink.attr("href", item.href());
        var href = new URI(tmpLink[0].href);
        var itemPath = trimLeading(href.path(), '/');
        if (itemPath === '') {
          // log.debug("nav item: ", item.id, " returning empty href, can't be selected");
          return false;
        }
        var current = new URI();
        var path = trimLeading(current.path(), '/');
        var query = current.query(true);
        var mainTab = query['main-tab'];
        var subTab = query['sub-tab'];
        if (itemPath !== '' && !mainTab && !subTab) {
          if (item.isSubTab && _.startsWith(path, itemPath)) {
            return true;
          }
          if (item.tabs) {
            var answer = _.any(item.tabs, function(subTab) {
              var answer = subTab.isSelected();
              return answer;
            });
            if (answer) {
              return true;
            }
          }
        }
        var answer = false;
        if (item.isSubTab) {
          if (!subTab) {
            answer = _.startsWith(path, itemPath);
          } else {
            answer = subTab === item.id;
          }
        } else {
          if (!mainTab) {
            answer = _.startsWith(path, itemPath);
          } else {
            answer = mainTab === item.id;
          }
        }
        return answer;
      };
    }
  }

  function drawNavItem($templateCache, $compile, scope, element, item) {
    if (!itemIsValid(item)) {
      return;
    }
    var newScope = scope.$new();
    item.hide = function() { return item.show && !item.show(); };
    newScope.item = item;
    var template = null;
    if (_.isFunction(item.template)) {
      template = item.template();
    } else {
      template = $templateCache.get('templates/main-nav/navItem.html');
    }
    if (item.attributes || item.linkAttributes) {
      var tmpEl = $(template);
      if (item.attributes) {
        tmpEl.attr(item.attributes);
      }
      if (item.linkAttributes) {
        tmpEl.find('a').attr(item.linkAttributes);
      }
      template = tmpEl.prop('outerHTML');
    }
    element.append($compile(template)(newScope));
  }

  function sortByRank(collection) {
    var answer = [];
    collection.forEach(function(item) {
      rankItem(item, answer);
    });
    return answer;
  }

  function rankItem(item, collection) {
    if (!('rank' in item) || collection.length === 0) {
      collection.push(item);
      return;
    }
    var index = _.findIndex(collection, function(i) {
      if ('rank' in i && item.rank > i.rank) {
        return true;
      }
    });
    if (!('rank' in collection[0])) {
      index = 0;
    }
    if (index < 0) {
      collection.push(item);
    } else {
      collection.splice(index, 0, item);
    }
  }

  HawtioMainNav._module.directive('hawtioSubTabs', ['HawtioNav', '$templateCache', '$compile', '$location', '$rootScope', function(HawtioNav, $templateCache, $compile, $location, $rootScope) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {

        scope.$watch(_.debounce(function() {
          var selected = HawtioNav.selected();
          if (scope.selected !== selected) {
            scope.selected = selected;
            scope.$broadcast('hawtio-nav-subtab-redraw');
            scope.$apply();
          }
        }, 100, { trailing: true }));

        scope.$on('hawtio-nav-subtab-redraw', function() {
          log.debug("Redrawing sub-tabs");
          element.empty();
          var selectedNav = scope.selected
          if (!selectedNav || !selectedNav.tabs) {
            return;
          }
          if (attrs['showHeading']) {
            var heading = angular.extend({}, selectedNav, {
              template: function() { return $templateCache.get('templates/main-nav/subTabHeader.html'); }});
              drawNavItem($templateCache, $compile, scope, element, heading);
          }
          var rankedTabs = sortByRank(selectedNav.tabs);
          rankedTabs.forEach(function(item) {
            drawNavItem($templateCache, $compile, scope, element, item);
          });
        });
        scope.$broadcast('hawtio-nav-subtab-redraw');
      }
    };
  }]);

  HawtioMainNav._module.directive("hawtioMainNav", ["HawtioNav", "$templateCache", "$compile", "$location", "$rootScope", function(HawtioNav, $templateCache, $compile, $location, $rootScope) {
    var config = {
      nav: {},
      numKeys: 0,
      numValid: 0
    };
    var iterationFunc = function(item) {
      if (itemIsValid(item)) {
        config.numValid = config.numValid + 1;
      }
    };
    HawtioNav.on(HawtioMainNav.Actions.ADD, 'subTabEnricher', function(item) {
      if (item.tabs && item.tabs.length > 0) {
        item.tabs.forEach(function (subItem) {
          subItem.isSubTab = true;
          if (!subItem.oldHref) {
            subItem.oldHref = subItem.href;
            subItem.href = function() {
              var uri = new URI(subItem.oldHref());
              if (uri.path() === "") {
                return "";
              }
              uri.search(function(search) {
                _.merge(search, uri.query(true));
                if (!search['main-tab']) {
                  search['main-tab'] = item.id;
                }
                search['sub-tab'] = subItem.id;
              });
              return uri.toString();
            };
          }
        });
      }
    });
    HawtioNav.on(HawtioMainNav.Actions.ADD, 'hrefEnricher', function(item) {
      item.isSubTab = false;
      if (item.href && !item.oldHref) {
        item.oldHref = item.href;
        item.href = function() {
          var oldHref = item.oldHref();
          if (!oldHref) {
            log.debug("Item: ", item.id, " returning null for href()");
            return "";
          }
          var uri = new URI(oldHref);
          if (uri.path() === "") {
            return "";
          }
          uri.search(function(search) {
            if (!search['main-tab']) {
              search['main-tab'] = item.id;
            }
            _.merge(search, uri.query(true));
            if (!search['sub-tab'] && item.tabs && item.tabs.length > 0) {
              var sorted = sortByRank(item.tabs);
              search['sub-tab'] = sorted[0].id;
            }
          });
          return uri.toString();
        };
      }
    });
    HawtioNav.on(HawtioMainNav.Actions.ADD, 'isSelectedEnricher', function(item) {
      addIsSelected($location, item);
      if (item.tabs) {
        item.tabs.forEach(function(item) { addIsSelected($location, item); });
      }
    });
    HawtioNav.on(HawtioMainNav.Actions.ADD, 'PrimaryController', function(item) {
      config.nav[item.id] = item;
    });
    HawtioNav.on(HawtioMainNav.Actions.REMOVE, 'PrimaryController', function(item) {
      delete config.nav[item.id];
    });
    HawtioNav.on(HawtioMainNav.Actions.CHANGED, 'PrimaryController', function(items) {
      config.numKeys = items.length;
      config.numValid = 0;
      items.forEach(iterationFunc);
    });
    return {
      restrict: 'A',
      replace: false,
      controller: ["$scope", "$element", "$attrs", function($scope, $element, $attrs) {
        $scope.config = config;
        $scope.$on('hawtio-nav-redraw', function() {
          log.debug("Redrawing main nav");
          $element.empty();

          var rankedContexts = [];
          // first add any contextual menus (like perspectives)
          HawtioNav.iterate(function(item) {
            if (!('context' in item)) {
              return;
            }
            if (!item.context) {
              return;
            }
            rankItem(item, rankedContexts);
          });
          rankedContexts.forEach(function (item) {
            drawNavItem($templateCache, $compile, $scope, $element, item);
          });
          // then add the rest of the nav items
          var rankedTabs = [];
          HawtioNav.iterate(function(item) {
            if (item.context) {
              return;
            }
            rankItem(item, rankedTabs);
          });
          rankedTabs.forEach(function (item) {
            drawNavItem($templateCache, $compile, $scope, $element, item);
          });
        });
      }],
      link: function(scope, element, attr) {
        scope.$watch(_.debounce(function() {
          var oldValid = config.numValid;
          var oldKeys = config.numKeys;
          config.numValid = 0;
          config.numKeys = 0;
          HawtioNav.iterate(iterationFunc);
          if (config.numValid !== oldValid || config.numKeys !== oldKeys) {
            scope.$broadcast('hawtio-nav-redraw');
            scope.$apply();
          }
        }, 500, { trailing: true }));
        scope.$broadcast('hawtio-nav-redraw');
      }
    };
  }]);

  // provider so it's possible to get a nav builder in _module.config()
  HawtioMainNav._module.provider('HawtioNavBuilder', [function HawtioNavBuilderProvider() {
    this.$get = function() {
      return {};
    };
    this.create = function() {
      return HawtioMainNav.createBuilder();
    };
    this.join = NavItemBuilderImpl.join;

    function setRoute($routeProvider, tab) {
      log.debug("Setting route: ", tab.href(), " to template URL: ", tab.page());
      var config = {
        templateUrl: tab.page()
      };
      if (!_.isUndefined(tab.reload)) {
        config.reloadOnSearch = tab.reload;
      }
      $routeProvider.when(tab.href(), config);
    }
    this.configureRouting = function($routeProvider, tab) {
      if (_.isUndefined(tab.page)) {
        if (tab.tabs) {
          var target = _.first(tab.tabs)['href'];
          if (target) {
            log.debug("Setting route: ", tab.href(), " to redirect to ", target());
            $routeProvider.when(tab.href(), {
              reloadOnSearch: tab.reload,
              redirectTo: target()
            });
          }
        }
      } else {
        setRoute($routeProvider, tab);
      }
      if (tab.tabs) {
        tab.tabs.forEach(function(tab) {
          return setRoute($routeProvider, tab);
        });
      }
    };
  }]);

  HawtioMainNav._module.factory('HawtioPerspective', [function() {
    var log = Logger.get('hawtio-dummy-perspective');
    return {
      add: function(id, perspective) {
        log.debug("add called for id: ", id);
      },
      remove: function(id) {
        log.debug("remove called for id: ", id);
        return undefined;
      },
      setCurrent: function(id) {
        log.debug("setCurrent called for id: ", id);
      },
      getCurrent: function(id) {
        log.debug("getCurrent called for id: ", id);
        return undefined;
      },
      getLabels: function() {
        return [];
      }
    };
  }]);

  HawtioMainNav._module.factory('WelcomePageRegistry', [function() {
    return {
      pages: []
    };
  }]);

  HawtioMainNav._module.factory('HawtioNav', ['$window', '$rootScope', function($window, $rootScope) {
    var registry = HawtioMainNav.createRegistry(window);
    return registry;
  }]);

  angular.module("hawtio-nav").run(["$templateCache", function($templateCache) {$templateCache.put("templates/main-nav/layoutFull.html","<div ng-view></div>\n\n\n");
  $templateCache.put("templates/main-nav/layoutTest.html","<div>\n  <h1>Test Layout</h1>\n  <div ng-view>\n\n\n  </div>\n</div>\n\n\n");
  $templateCache.put("templates/main-nav/navItem.html","<li ng-class=\"{ active: item.isSelected() }\" ng-hide=\"item.hide()\">\n  <a ng-href=\"{{item.href()}}\" ng-click=\"item.click($event)\" ng-bind-html=\"item.title()\" title=\"{{item.tooltip()}}\"></a>\n</li>\n");
  $templateCache.put("templates/main-nav/subTabHeader.html","<li class=\"header\">\n  <a href=\"\"><strong>{{item.title()}}</strong></a>\n</li>\n");
  $templateCache.put("templates/main-nav/welcome.html","<div ng-controller=\"HawtioNav.WelcomeController\"></div>\n");}]);

})(HawtioMainNav || (HawtioMainNav = {}));