text: /* eslint-disable */
  /*
   UriTemplates Template Processor - Version: @VERSION - Dated: @DATE
   (c) marc.portier@gmail.com - 2011-2012
   Licensed under APLv2 (http://opensource.org/licenses/Apache-2.0)
   */
  
  ;
  var uritemplate = (function() {
  
  // Below are the functions we originally used from jQuery.
  // The implementations below are often more naive then what is inside jquery, but they suffice for our needs.
  
      function isFunction(fn) {
          return typeof fn == 'function';
      }
  
      function isEmptyObject (obj) {
          for(var name in obj){
              return false;
          }
          return true;
      }
  
      function extend(base, newprops) {
          for (var name in newprops) {
              base[name] = newprops[name];
          }
          return base;
      }
  
      /**
       * Create a runtime cache around retrieved values from the context.
       * This allows for dynamic (function) results to be kept the same for multiple
       * occuring expansions within one template.
       * Note: Uses key-value tupples to be able to cache null values as well.
       */
          //TODO move this into prep-processing
      function CachingContext(context) {
          this.raw = context;
          this.cache = {};
      }
      CachingContext.prototype.get = function(key) {
          var val = this.lookupRaw(key);
          var result = val;
  
          if (isFunction(val)) { // check function-result-cache
              var tupple = this.cache[key];
              if (tupple !== null && tupple !== undefined) {
                  result = tupple.val;
              } else {
                  result = val(this.raw);
                  this.cache[key] = {key: key, val: result};
                  // NOTE: by storing tupples we make sure a null return is validly consistent too in expansions
              }
          }
          return result;
      };
  
      CachingContext.prototype.lookupRaw = function(key) {
          return CachingContext.lookup(this, this.raw, key);
      };
  
      CachingContext.lookup = function(me, context, key) {
          var result = context[key];
          if (result !== undefined) {
              return result;
          } else {
              var keyparts = key.split('.');
              var i = 0, keysplits = keyparts.length - 1;
              for (i = 0; i<keysplits; i++) {
                  var leadKey = keyparts.slice(0, keysplits - i).join('.');
                  var trailKey = keyparts.slice(-i-1).join('.');
                  var leadContext = context[leadKey];
                  if (leadContext !== undefined) {
                      return CachingContext.lookup(me, leadContext, trailKey);
                  }
              }
              return undefined;
          }
      };
  
  
      function UriTemplate(set) {
          this.set = set;
      }
  
      UriTemplate.prototype.expand = function(context) {
          var cache = new CachingContext(context);
          var res = "";
          var i = 0, cnt = this.set.length;
          for (i = 0; i<cnt; i++ ) {
              res += this.set[i].expand(cache);
          }
          return res;
      };
  
  //TODO: change since draft-0.6 about characters in literals
      /* extract:
       The characters outside of expressions in a URI Template string are intended to be copied literally to the URI-reference if the character is allowed in a URI (reserved / unreserved / pct-encoded) or, if not allowed, copied to the URI-reference in its UTF-8 pct-encoded form.
       */
      function Literal(txt ) {
          this.txt = txt;
      }
  
      Literal.prototype.expand = function() {
          return this.txt;
      };
  
  
  
      var RESERVEDCHARS_RE = new RegExp("[:/?#\\[\\]@!$&()*+,;=']","g");
      function encodeNormal(val) {
          return encodeURIComponent(val).replace(RESERVEDCHARS_RE, function(s) {return escape(s);} );
      }
  
  //var SELECTEDCHARS_RE = new RegExp("[]","g");
      function encodeReserved(val) {
          //return encodeURI(val).replace(SELECTEDCHARS_RE, function(s) {return escape(s)} );
          return encodeURI(val); // no need for additional replace if selected-chars is empty
      }
  
  
      function addUnNamed(name, key, val) {
          return key + (key.length > 0 ? "=" : "") + val;
      }
  
      function addNamed(name, key, val, noName) {
          noName = noName || false;
          if (noName) { name = ""; }
  
          if (!key || key.length === 0)  {
              key = name;
          }
          return key + (key.length > 0 ? "=" : "") + val;
      }
  
      function addLabeled(name, key, val, noName) {
          noName = noName || false;
          if (noName) { name = ""; }
  
          if (!key || key.length === 0)  {
              key = name;
          }
          return key + (key.length > 0 && val ? "=" : "") + val;
      }
  
  
      var simpleConf = {
          prefix : "",     joiner : ",",     encode : encodeNormal,    builder : addUnNamed
      };
      var reservedConf = {
          prefix : "",     joiner : ",",     encode : encodeReserved,  builder : addUnNamed
      };
      var fragmentConf = {
          prefix : "#",    joiner : ",",     encode : encodeReserved,  builder : addUnNamed
      };
      var pathParamConf = {
          prefix : ";",    joiner : ";",     encode : encodeNormal,    builder : addLabeled
      };
      var formParamConf = {
          prefix : "?",    joiner : "&",     encode : encodeNormal,    builder : addNamed
      };
      var formContinueConf = {
          prefix : "&",    joiner : "&",     encode : encodeNormal,    builder : addNamed
      };
      var pathHierarchyConf = {
          prefix : "/",    joiner : "/",     encode : encodeNormal,    builder : addUnNamed
      };
      var labelConf = {
          prefix : ".",    joiner : ".",     encode : encodeNormal,    builder : addUnNamed
      };
  
  
      function Expression(conf, vars ) {
          extend(this, conf);
          this.vars = vars;
      }
  
      Expression.build = function(ops, vars) {
          var conf;
          switch(ops) {
              case ''  : conf = simpleConf; break;
              case '+' : conf = reservedConf; break;
              case '#' : conf = fragmentConf; break;
              case ';' : conf = pathParamConf; break;
              case '?' : conf = formParamConf; break;
              case '&' : conf = formContinueConf; break;
              case '/' : conf = pathHierarchyConf; break;
              case '.' : conf = labelConf; break;
              default  : throw "Unexpected operator: '"+ops+"'";
          }
          return new Expression(conf, vars);
      };
  
      Expression.prototype.expand = function(context) {
          var joiner = this.prefix;
          var nextjoiner = this.joiner;
          var buildSegment = this.builder;
          var res = "";
          var i = 0, cnt = this.vars.length;
  
          for (i = 0 ; i< cnt; i++) {
              var varspec = this.vars[i];
              varspec.addValues(context, this.encode, function(key, val, noName) {
                  var segm = buildSegment(varspec.name, key, val, noName);
                  if (segm !== null && segm !== undefined) {
                      res += joiner + segm;
                      joiner = nextjoiner;
                  }
              });
          }
          return res;
      };
  
  
  
      var UNBOUND = {};
  
      /**
       * Helper class to help grow a string of (possibly encoded) parts until limit is reached
       */
      function Buffer(limit) {
          this.str = "";
          if (limit === UNBOUND) {
              this.appender = Buffer.UnboundAppend;
          } else {
              this.len = 0;
              this.limit = limit;
              this.appender = Buffer.BoundAppend;
          }
      }
  
      Buffer.prototype.append = function(part, encoder) {
          return this.appender(this, part, encoder);
      };
  
      Buffer.UnboundAppend = function(me, part, encoder) {
          part = encoder ? encoder(part) : part;
          me.str += part;
          return me;
      };
  
      Buffer.BoundAppend = function(me, part, encoder) {
          part = part.substring(0, me.limit - me.len);
          me.len += part.length;
  
          part = encoder ? encoder(part) : part;
          me.str += part;
          return me;
      };
  
  
      function arrayToString(arr, encoder, maxLength) {
          var buffer = new Buffer(maxLength);
          var joiner = "";
  
          var i = 0, cnt = arr.length;
          for (i=0; i<cnt; i++) {
              if (arr[i] !== null && arr[i] !== undefined) {
                  buffer.append(joiner).append(arr[i], encoder);
                  joiner = ",";
              }
          }
          return buffer.str;
      }
  
      function objectToString(obj, encoder, maxLength) {
          var buffer = new Buffer(maxLength);
          var joiner = "";
          var k;
  
          for (k in obj) {
              if (obj.hasOwnProperty(k) ) {
                  if (obj[k] !== null && obj[k] !== undefined) {
                      buffer.append(joiner + k + ',').append(obj[k], encoder);
                      joiner = ",";
                  }
              }
          }
          return buffer.str;
      }
  
  
      function simpleValueHandler(me, val, valprops, encoder, adder) {
          var result;
  
          if (valprops.isArr) {
              result = arrayToString(val, encoder, me.maxLength);
          } else if (valprops.isObj) {
              result = objectToString(val, encoder, me.maxLength);
          } else {
              var buffer = new Buffer(me.maxLength);
              result = buffer.append(val, encoder).str;
          }
  
          adder("", result);
      }
  
      function explodeValueHandler(me, val, valprops, encoder, adder) {
          if (valprops.isArr) {
              var i = 0, cnt = val.length;
              for (i = 0; i<cnt; i++) {
                  adder("", encoder(val[i]) );
              }
          } else if (valprops.isObj) {
              var k;
              for (k in val) {
                  if (val.hasOwnProperty(k)) {
                      adder(k, encoder(val[k]) );
                  }
              }
          } else { // explode-requested, but single value
              adder("", encoder(val));
          }
      }
  
      function valueProperties(val) {
          var isArr = false;
          var isObj = false;
          var isUndef = true;  //note: "" is empty but not undef
  
          if (val !== null && val !== undefined) {
              isArr = (val.constructor === Array);
              isObj = (val.constructor === Object);
              isUndef = (isArr && val.length === 0) || (isObj && isEmptyObject(val));
          }
  
          return {isArr: isArr, isObj: isObj, isUndef: isUndef};
      }
  
  
      function VarSpec (name, vhfn, nums) {
          this.name = unescape(name);
          this.valueHandler = vhfn;
          this.maxLength = nums;
      }
  
  
      VarSpec.build = function(name, expl, part, nums) {
          var valueHandler, valueModifier;
  
          if (!!expl) { //interprete as boolean
              valueHandler = explodeValueHandler;
          } else {
              valueHandler = simpleValueHandler;
          }
  
          if (!part) {
              nums = UNBOUND;
          }
  
          return new VarSpec(name, valueHandler, nums);
      };
  
  
      VarSpec.prototype.addValues = function(context, encoder, adder) {
          var val = context.get(this.name);
          var valprops = valueProperties(val);
          if (valprops.isUndef) { return; } // ignore empty values
          this.valueHandler(this, val, valprops, encoder, adder);
      };
  
  
  
  //----------------------------------------------parsing logic
  // How each varspec should look like
      var VARSPEC_RE=/([^*:]*)((\*)|(:)([0-9]+))?/;
  
      var match2varspec = function(m) {
          var name = m[1];
          var expl = m[3];
          var part = m[4];
          var nums = parseInt(m[5], 10);
  
          return VarSpec.build(name, expl, part, nums);
      };
  
  
  // Splitting varspecs in list with:
      var LISTSEP=",";
  
  // How each template should look like
      var TEMPL_RE=/(\{([+#.;?&\/])?(([^.*:,{}|@!=$()][^*:,{}$()]*)(\*|:([0-9]+))?(,([^.*:,{}][^*:,{}]*)(\*|:([0-9]+))?)*)\})/g;
  // Note: reserved operators: |!@ are left out of the regexp in order to make those templates degrade into literals
  // (as expected by the spec - see tests.html "reserved operators")
  
  
      var match2expression = function(m) {
          var expr = m[0];
          var ops = m[2] || '';
          var vars = m[3].split(LISTSEP);
          var i = 0, len = vars.length;
          for (i = 0; i<len; i++) {
              var match;
              if ( (match = vars[i].match(VARSPEC_RE)) === null) {
                  throw "unexpected parse error in varspec: " + vars[i];
              }
              vars[i] = match2varspec(match);
          }
  
          return Expression.build(ops, vars);
      };
  
  
      var pushLiteralSubstr = function(set, src, from, to) {
          if (from < to) {
              var literal = src.substr(from, to - from);
              set.push(new Literal(literal));
          }
      };
  
      var parse = function(str) {
          var lastpos = 0;
          var comp = [];
  
          var match;
          var pattern = TEMPL_RE;
          pattern.lastIndex = 0; // just to be sure
          while ((match = pattern.exec(str)) !== null) {
              var newpos = match.index;
              pushLiteralSubstr(comp, str, lastpos, newpos);
  
              comp.push(match2expression(match));
              lastpos = pattern.lastIndex;
          }
          pushLiteralSubstr(comp, str, lastpos, str.length);
  
          return new UriTemplate(comp);
      };
  
  
  //-------------------------------------------comments and ideas
  
  //TODO: consider building cache of previously parsed uris or even parsed expressions?
  
      return parse;
  
  }());
  