text: (function (root, factory) {
      var routing = factory();
      if (typeof define === 'function' && define.amd) {
          // AMD. Register as an anonymous module.
          define([], routing.Routing);
      } else if (typeof module === 'object' && module.exports) {
          // Node. Does not work with strict CommonJS, but
          // only CommonJS-like environments that support module.exports,
          // like Node.
          module.exports = routing.Routing;
      } else {
          // Browser globals (root is window)
          root.Routing = routing.Routing;
          root.fos = {
              Router: routing.Router
          };
      }
  }(this, function () {
      'use strict';
  
  /**
   * @fileoverview This file defines the Router class.
   *
   * You can compile this file by running the following command from the Resources folder:
   *
   *    npm install && npm run build
   */
  
  /**
   * Class Router
   */
  
  var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
  
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  var Router = function () {
  
      /**
       * @constructor
       * @param {Router.Context=} context
       * @param {Object.<string, Router.Route>=} routes
       */
      function Router(context, routes) {
          _classCallCheck(this, Router);
  
          this.context_ = context || { base_url: '', prefix: '', host: '', port: '', scheme: '' };
          this.setRoutes(routes || {});
      }
  
      /**
       * Returns the current instance.
       * @returns {Router}
       */
  
  
      _createClass(Router, [{
          key: 'setRoutingData',
  
  
          /**
           * Sets data for the current instance
           * @param {Object} data
           */
          value: function setRoutingData(data) {
              this.setBaseUrl(data['base_url']);
              this.setRoutes(data['routes']);
  
              if ('prefix' in data) {
                  this.setPrefix(data['prefix']);
              }
              if ('port' in data) {
                  this.setPort(data['port']);
              }
  
              this.setHost(data['host']);
              this.setScheme(data['scheme']);
          }
  
          /**
           * @param {Object.<string, Router.Route>} routes
           */
  
      }, {
          key: 'setRoutes',
          value: function setRoutes(routes) {
              this.routes_ = Object.freeze(routes);
          }
  
          /**
           * @return {Object.<string, Router.Route>} routes
           */
  
      }, {
          key: 'getRoutes',
          value: function getRoutes() {
              return this.routes_;
          }
  
          /**
           * @param {string} baseUrl
           */
  
      }, {
          key: 'setBaseUrl',
          value: function setBaseUrl(baseUrl) {
              this.context_.base_url = baseUrl;
          }
  
          /**
           * @return {string}
           */
  
      }, {
          key: 'getBaseUrl',
          value: function getBaseUrl() {
              return this.context_.base_url;
          }
  
          /**
           * @param {string} prefix
           */
  
      }, {
          key: 'setPrefix',
          value: function setPrefix(prefix) {
              this.context_.prefix = prefix;
          }
  
          /**
           * @param {string} scheme
           */
  
      }, {
          key: 'setScheme',
          value: function setScheme(scheme) {
              this.context_.scheme = scheme;
          }
  
          /**
           * @return {string}
           */
  
      }, {
          key: 'getScheme',
          value: function getScheme() {
              return this.context_.scheme;
          }
  
          /**
           * @param {string} host
           */
  
      }, {
          key: 'setHost',
          value: function setHost(host) {
              this.context_.host = host;
          }
  
          /**
           * @return {string}
           */
  
      }, {
          key: 'getHost',
          value: function getHost() {
              return this.context_.host;
          }
  
          /**
           * @param {string} port
          */
  
      }, {
          key: 'setPort',
          value: function setPort(port) {
              this.context_.port = port;
          }
  
          /**
           * @return {string}
           */
  
      }, {
          key: 'getPort',
          value: function getPort() {
              return this.context_.port;
          }
      }, {
          key: 'buildQueryParams',
  
  
          /**
           * Builds query string params added to a URL.
           * Port of jQuery's $.param() function, so credit is due there.
           *
           * @param {string} prefix
           * @param {Array|Object|string} params
           * @param {Function} add
           */
          value: function buildQueryParams(prefix, params, add) {
              var _this = this;
  
              var name = void 0;
              var rbracket = new RegExp(/\[\]$/);
  
              if (params instanceof Array) {
                  params.forEach(function (val, i) {
                      if (rbracket.test(prefix)) {
                          add(prefix, val);
                      } else {
                          _this.buildQueryParams(prefix + '[' + ((typeof val === 'undefined' ? 'undefined' : _typeof(val)) === 'object' ? i : '') + ']', val, add);
                      }
                  });
              } else if ((typeof params === 'undefined' ? 'undefined' : _typeof(params)) === 'object') {
                  for (name in params) {
                      this.buildQueryParams(prefix + '[' + name + ']', params[name], add);
                  }
              } else {
                  add(prefix, params);
              }
          }
  
          /**
           * Returns a raw route object.
           *
           * @param {string} name
           * @return {Router.Route}
           */
  
      }, {
          key: 'getRoute',
          value: function getRoute(name) {
              var prefixedName = this.context_.prefix + name;
  
              if (!(prefixedName in this.routes_)) {
                  // Check first for default route before failing
                  if (!(name in this.routes_)) {
                      throw new Error('The route "' + name + '" does not exist.');
                  }
              } else {
                  name = prefixedName;
              }
  
              return this.routes_[name];
          }
  
          /**
           * Generates the URL for a route.
           *
           * @param {string} name
           * @param {Object.<string, string>} opt_params
           * @param {boolean} absolute
           * @return {string}
           */
  
      }, {
          key: 'generate',
          value: function generate(name, opt_params) {
              var absolute = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  
              var route = this.getRoute(name),
                  params = opt_params || {},
                  unusedParams = _extends({}, params),
                  url = '',
                  optional = true,
                  host = '',
                  port = typeof this.getPort() == "undefined" || this.getPort() === null ? '' : this.getPort();
  
              route.tokens.forEach(function (token) {
                  if ('text' === token[0]) {
                      url = token[1] + url;
                      optional = false;
  
                      return;
                  }
  
                  if ('variable' === token[0]) {
                      var hasDefault = route.defaults && token[3] in route.defaults;
                      if (false === optional || !hasDefault || token[3] in params && params[token[3]] != route.defaults[token[3]]) {
                          var value = void 0;
  
                          if (token[3] in params) {
                              value = params[token[3]];
                              delete unusedParams[token[3]];
                          } else if (hasDefault) {
                              value = route.defaults[token[3]];
                          } else if (optional) {
                              return;
                          } else {
                              throw new Error('The route "' + name + '" requires the parameter "' + token[3] + '".');
                          }
  
                          var empty = true === value || false === value || '' === value;
  
                          if (!empty || !optional) {
                              var encodedValue = encodeURIComponent(value).replace(/%2F/g, '/');
  
                              if ('null' === encodedValue && null === value) {
                                  encodedValue = '';
                              }
  
                              url = token[1] + encodedValue + url;
                          }
  
                          optional = false;
                      } else if (hasDefault && token[3] in unusedParams) {
                          delete unusedParams[token[3]];
                      }
  
                      return;
                  }
  
                  throw new Error('The token type "' + token[0] + '" is not supported.');
              });
  
              if (url === '') {
                  url = '/';
              }
  
              route.hosttokens.forEach(function (token) {
                  var value = void 0;
  
                  if ('text' === token[0]) {
                      host = token[1] + host;
  
                      return;
                  }
  
                  if ('variable' === token[0]) {
                      if (token[3] in params) {
                          value = params[token[3]];
                          delete unusedParams[token[3]];
                      } else if (route.defaults && token[3] in route.defaults) {
                          value = route.defaults[token[3]];
                      }
  
                      host = token[1] + value + host;
                  }
              });
              // Foo-bar!
              url = this.context_.base_url + url;
              if (route.requirements && "_scheme" in route.requirements && this.getScheme() != route.requirements["_scheme"]) {
                  url = route.requirements["_scheme"] + "://" + (host || this.getHost()) + url;
              } else if ("undefined" !== typeof route.schemes && "undefined" !== typeof route.schemes[0] && this.getScheme() !== route.schemes[0]) {
                  url = route.schemes[0] + "://" + (host || this.getHost()) + url;
              } else if (host && this.getHost() !== host + ('' === port ? '' : ':' + port)) {
                  url = this.getScheme() + "://" + host + ('' === port ? '' : ':' + port) + url;
              } else if (absolute === true) {
                  url = this.getScheme() + "://" + this.getHost() + url;
              }
  
              if (Object.keys(unusedParams).length > 0) {
                  var prefix = void 0;
                  var queryParams = [];
                  var add = function add(key, value) {
                      // if value is a function then call it and assign it's return value as value
                      value = typeof value === 'function' ? value() : value;
  
                      // change null to empty string
                      value = value === null ? '' : value;
  
                      queryParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
                  };
  
                  for (prefix in unusedParams) {
                      this.buildQueryParams(prefix, unusedParams[prefix], add);
                  }
  
                  url = url + '?' + queryParams.join('&').replace(/%20/g, '+');
              }
  
              return url;
          }
      }], [{
          key: 'getInstance',
          value: function getInstance() {
              return Routing;
          }
  
          /**
           * Configures the current Router instance with the provided data.
           * @param {Object} data
           */
  
      }, {
          key: 'setData',
          value: function setData(data) {
              var router = Router.getInstance();
  
              router.setRoutingData(data);
          }
      }]);
  
      return Router;
  }();
  
  /**
   * @typedef {{
   *     tokens: (Array.<Array.<string>>),
   *     defaults: (Object.<string, string>),
   *     requirements: Object,
   *     hosttokens: (Array.<string>)
   * }}
   */
  
  
  Router.Route;
  
  /**
   * @typedef {{
   *     base_url: (string)
   * }}
   */
  Router.Context;
  
  /**
   * Router singleton.
   * @const
   * @type {Router}
   */
  var Routing = new Router();
  
      return { Router: Router, Routing: Routing };
  }));