text: /*
   * JQuery URL Parser plugin, v2.2.1
   * Developed and maintanined by Mark Perkins, mark@allmarkedup.com
   * Source repository: https://github.com/allmarkedup/jQuery-URL-Parser
   * Licensed under an MIT-style license. See https://github.com/allmarkedup/jQuery-URL-Parser/blob/master/LICENSE for details.
   */ 
  
  ;(function(factory) {
    if (typeof define === 'function' && define.amd) {
      // AMD available; use anonymous module
      if ( typeof jQuery !== 'undefined' ) {
        define(['jquery'], factory);  
      } else {
        define([], factory);
      }
    } else {
      // No AMD available; mutate global vars
      if ( typeof jQuery !== 'undefined' ) {
        factory(jQuery);
      } else {
        factory();
      }
    }
  })(function($, undefined) {
  
    var tag2attr = {
        a       : 'href',
        img     : 'src',
        form    : 'action',
        base    : 'href',
        script  : 'src',
        iframe  : 'src',
        link    : 'href'
      },
  
      key = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'], // keys available to query
  
      aliases = { 'anchor' : 'fragment' }, // aliases for backwards compatability
  
      parser = {
        strict : /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,  //less intuitive, more accurate to the specs
        loose :  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // more intuitive, fails on relative paths and deviates from specs
      },
  
      toString = Object.prototype.toString,
  
      isint = /^[0-9]+$/;
  
    function parseUri( url, strictMode ) {
      var str = decodeURI( url ),
      res   = parser[ strictMode || false ? 'strict' : 'loose' ].exec( str ),
      uri = { attr : {}, param : {}, seg : {} },
      i   = 14;
  
      while ( i-- ) {
        uri.attr[ key[i] ] = res[i] || '';
      }
  
      // build query and fragment parameters    
      uri.param['query'] = parseString(uri.attr['query']);
      uri.param['fragment'] = parseString(uri.attr['fragment']);
  
      // split path and fragement into segments   
      uri.seg['path'] = uri.attr.path.replace(/^\/+|\/+$/g,'').split('/');     
      uri.seg['fragment'] = uri.attr.fragment.replace(/^\/+|\/+$/g,'').split('/');
  
      // compile a 'base' domain attribute        
      uri.attr['base'] = uri.attr.host ? (uri.attr.protocol ?  uri.attr.protocol+'://'+uri.attr.host : uri.attr.host) + (uri.attr.port ? ':'+uri.attr.port : '') : '';      
  
      return uri;
    };
  
    function getAttrName( elm ) {
      var tn = elm.tagName;
      if ( typeof tn !== 'undefined' ) return tag2attr[tn.toLowerCase()];
      return tn;
    }
  
    function promote(parent, key) {
      if (parent[key].length == 0) return parent[key] = {};
      var t = {};
      for (var i in parent[key]) t[i] = parent[key][i];
      parent[key] = t;
      return t;
    }
  
    function parse(parts, parent, key, val) {
      var part = parts.shift();
      if (!part) {
        if (isArray(parent[key])) {
          parent[key].push(val);
        } else if ('object' == typeof parent[key]) {
          parent[key] = val;
        } else if ('undefined' == typeof parent[key]) {
          parent[key] = val;
        } else {
          parent[key] = [parent[key], val];
        }
      } else {
        var obj = parent[key] = parent[key] || [];
        if (']' == part) {
          if (isArray(obj)) {
            if ('' != val) obj.push(val);
          } else if ('object' == typeof obj) {
            obj[keys(obj).length] = val;
          } else {
            obj = parent[key] = [parent[key], val];
          }
        } else if (~part.indexOf(']')) {
          part = part.substr(0, part.length - 1);
          if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
          parse(parts, obj, part, val);
          // key
        } else {
          if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
          parse(parts, obj, part, val);
        }
      }
    }
  
    function merge(parent, key, val) {
      if (~key.indexOf(']')) {
        var parts = key.split('['),
        len = parts.length,
        last = len - 1;
        parse(parts, parent, 'base', val);
      } else {
        if (!isint.test(key) && isArray(parent.base)) {
          var t = {};
          for (var k in parent.base) t[k] = parent.base[k];
          parent.base = t;
        }
        set(parent.base, key, val);
      }
      return parent;
    }
  
    function parseString(str) {
      return reduce(String(str).split(/&|;/), function(ret, pair) {
        try {
          pair = decodeURIComponent(pair.replace(/\+/g, ' '));
        } catch(e) {
          // ignore
        }
        var eql = pair.indexOf('='),
          brace = lastBraceInKey(pair),
          key = pair.substr(0, brace || eql),
          val = pair.substr(brace || eql, pair.length),
          val = val.substr(val.indexOf('=') + 1, val.length);
  
        if ('' == key) key = pair, val = '';
  
        return merge(ret, key, val);
      }, { base: {} }).base;
    }
  
    function set(obj, key, val) {
      var v = obj[key];
      if (undefined === v) {
        obj[key] = val;
      } else if (isArray(v)) {
        v.push(val);
      } else {
        obj[key] = [v, val];
      }
    }
  
    function lastBraceInKey(str) {
      var len = str.length,
         brace, c;
      for (var i = 0; i < len; ++i) {
        c = str[i];
        if (']' == c) brace = false;
        if ('[' == c) brace = true;
        if ('=' == c && !brace) return i;
      }
    }
  
    function reduce(obj, accumulator){
      var i = 0,
        l = obj.length >> 0,
        curr = arguments[2];
      while (i < l) {
        if (i in obj) curr = accumulator.call(undefined, curr, obj[i], i, obj);
        ++i;
      }
      return curr;
    }
  
    function isArray(vArg) {
      return Object.prototype.toString.call(vArg) === "[object Array]";
    }
  
    function keys(obj) {
      var keys = [];
      for ( prop in obj ) {
        if ( obj.hasOwnProperty(prop) ) keys.push(prop);
      }
      return keys;
    }
  
    function purl( url, strictMode ) {
      if ( arguments.length === 1 && url === true ) {
        strictMode = true;
        url = undefined;
      }
      strictMode = strictMode || false;
      url = url || window.location.toString();
  
      return {
  
        data : parseUri(url, strictMode),
  
        // get various attributes from the URI
        attr : function( attr ) {
          attr = aliases[attr] || attr;
          return typeof attr !== 'undefined' ? this.data.attr[attr] : this.data.attr;
        },
  
        // return query string parameters
        param : function( param ) {
          return typeof param !== 'undefined' ? this.data.param.query[param] : this.data.param.query;
        },
  
        // return fragment parameters
        fparam : function( param ) {
          return typeof param !== 'undefined' ? this.data.param.fragment[param] : this.data.param.fragment;
        },
  
        // return path segments
        segment : function( seg ) {
          if ( typeof seg === 'undefined' ) {
            return this.data.seg.path;
          } else {
            seg = seg < 0 ? this.data.seg.path.length + seg : seg - 1; // negative segments count from the end
            return this.data.seg.path[seg];                    
          }
        },
  
        // return fragment segments
        fsegment : function( seg ) {
          if ( typeof seg === 'undefined' ) {
            return this.data.seg.fragment;                    
          } else {
            seg = seg < 0 ? this.data.seg.fragment.length + seg : seg - 1; // negative segments count from the end
            return this.data.seg.fragment[seg];                    
          }
        }
  
      };
  
    };
  
    if ( typeof $ !== 'undefined' ) {
  
      $.fn.url = function( strictMode ) {
        var url = '';
        if ( this.length ) {
          url = $(this).attr( getAttrName(this[0]) ) || '';
        }    
        return purl( url, strictMode );
      };
  
      $.url = purl;
  
    } else {
      window.purl = purl;
    }
  
  });
  