UNPKG

angular-state-router

Version:

An AngularJS state-based router designed for flexibility and ease of use.

1,309 lines (1,055 loc) 94.6 kB
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ 'use strict'; module.exports = ['$state', function ($state) { return { restrict: 'A', scope: { }, link: function(scope, element, attrs) { element.css('cursor', 'pointer'); element.on('click', function(e) { $state.change(attrs.sref); e.preventDefault(); }); } }; }]; },{}],2:[function(require,module,exports){ 'use strict'; /* global angular:false */ // CommonJS if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){ module.exports = 'angular-state-router'; } // Instantiate module angular.module('angular-state-router', []) .provider('$state', require('./services/state-router')) .factory('$urlManager', require('./services/url-manager')) .factory('$resolution', require('./services/resolution')) .factory('$enact', require('./services/enact')) .factory('$queueHandler', require('./services/queue-handler')) .run(['$rootScope', '$state', '$urlManager', '$resolution', '$enact', function($rootScope, $state, $urlManager, $resolution, $enact) { // Update location changes $rootScope.$on('$locationChangeSuccess', function() { $urlManager.location(arguments); }); $urlManager.$ready(); $resolution.$ready(); $enact.$ready(); // Initialize $state.$ready(); }]) .directive('sref', require('./directives/sref')); },{"./directives/sref":1,"./services/enact":3,"./services/queue-handler":4,"./services/resolution":5,"./services/state-router":6,"./services/url-manager":7}],3:[function(require,module,exports){ 'use strict'; module.exports = ['$q', '$injector', '$state', '$rootScope', function($q, $injector, $state, $rootScope) { // Instance var _self = {}; /** * Process actions * * @param {Object} actions An array of actions items * @return {Promise} A promise fulfilled when actions processed */ var _act = function(actions) { var actionPromises = []; angular.forEach(actions, function(value) { var action = angular.isString(value) ? $injector.get(value) : $injector.invoke(value); actionPromises.push($q.when(action)); }); return $q.all(actionPromises); }; _self.process = _act; /** * Register middleware layer */ _self.$ready = function() { $state.$use(function(request, next) { var current = $state.current(); if(!current) { return next(); } $rootScope.$broadcast('$stateActionBegin'); _act(current.actions || []).then(function() { $rootScope.$broadcast('$stateActionEnd'); next(); }, function(err) { $rootScope.$broadcast('$stateActionError', err); next(new Error('Error processing state actions')); }); }, 100); }; return _self; }]; },{}],4:[function(require,module,exports){ 'use strict'; module.exports = ['$rootScope', function($rootScope) { /** * Execute a series of functions; used in tandem with middleware */ var Queue = function() { var _list = []; var _data = null; var _self = { /** * Add a handler * * @param {Mixed} handler A Function or an Array of Functions to add to the queue * @return {Queue} Itself; chainable */ add: function(handler, priority) { if(handler && handler.constructor === Array) { handler.forEach(function(layer) { layer.priority = typeof layer.priority === 'undefined' ? 1 : layer.priority; }); _list = _list.concat(handler); } else { handler.priority = priority || (typeof handler.priority === 'undefined' ? 1 : handler.priority); _list.push(handler); } return this; }, /** * Data object * * @param {Object} data A data object made available to each handler * @return {Queue} Itself; chainable */ data: function(data) { _data = data; return this; }, /** * Begin execution and trigger callback at the end * * @param {Function} callback A callback, function(err) * @return {Queue} Itself; chainable */ execute: function(callback) { var nextHandler; var executionList = _list.slice(0).sort(function(a, b) { return Math.max(-1, Math.min(1, b.priority - a.priority)); }); nextHandler = function() { $rootScope.$evalAsync(function() { var handler = executionList.shift(); // Complete if(!handler) { callback(null); // Next handler } else { handler.call(null, _data, function(err) { // Error if(err) { callback(err); // Continue } else { nextHandler(); } }); } }); }; // Start nextHandler(); } }; return _self; }; // Instance return { /** * Factory method * * @return {Queue} A queue */ create: function() { return Queue(); } }; }]; },{}],5:[function(require,module,exports){ 'use strict'; module.exports = ['$q', '$injector', '$state', '$rootScope', function($q, $injector, $state, $rootScope) { // Instance var _self = {}; /** * Resolve * * @param {Object} resolve A hash Object of items to resolve * @return {Promise} A promise fulfilled when templates retireved */ var _resolve = function(resolve) { var resolvesPromises = {}; angular.forEach(resolve, function(value, key) { var resolution = angular.isString(value) ? $injector.get(value) : $injector.invoke(value, null, null, key); resolvesPromises[key] = $q.when(resolution); }); return $q.all(resolvesPromises); }; _self.resolve = _resolve; /** * Register middleware layer */ _self.$ready = function() { $state.$use(function(request, next) { var current = $state.current(); if(!current) { return next(); } $rootScope.$broadcast('$stateResolveBegin'); _resolve(current.resolve || {}).then(function(locals) { angular.extend(request.locals, locals); $rootScope.$broadcast('$stateResolveEnd'); next(); }, function(err) { $rootScope.$broadcast('$stateResolveError', err); next(new Error('Error resolving state')); }); }, 101); }; return _self; }]; },{}],6:[function(require,module,exports){ 'use strict'; var UrlDictionary = require('../utils/url-dictionary'); var Parameters = require('../utils/parameters'); module.exports = [function StateRouterProvider() { // Provider var _provider = this; // Configuration, global options var _configuration = { historyLength: 5 }; // State definition library var _stateLibrary = {}; var _stateCache = {}; // URL to state dictionary var _urlDictionary = new UrlDictionary(); // Middleware layers var _layerList = []; /** * Parse state notation name-params. * * Assume all parameter values are strings * * @param {String} nameParams A name-params string * @return {Object} A name string and param Object */ var _parseName = function(nameParams) { if(nameParams && nameParams.match(/^[a-zA-Z0-9_\.]*\(.*\)$/)) { var npart = nameParams.substring(0, nameParams.indexOf('(')); var ppart = Parameters( nameParams.substring(nameParams.indexOf('(')+1, nameParams.lastIndexOf(')')) ); return { name: npart, params: ppart }; } else { return { name: nameParams, params: null }; } }; /** * Add default values to a state * * @param {Object} data An Object * @return {Object} An Object */ var _setStateDefaults = function(data) { // Default values data.inherit = (typeof data.inherit === 'undefined') ? true : data.inherit; return data; }; /** * Validate state name * * @param {String} name A unique identifier for the state; using dot-notation * @return {Boolean} True if name is valid, false if not */ var _validateStateName = function(name) { name = name || ''; // TODO optimize with RegExp var nameChain = name.split('.'); for(var i=0; i<nameChain.length; i++) { if(!nameChain[i].match(/[a-zA-Z0-9_]+/)) { return false; } } return true; }; /** * Validate state query * * @param {String} query A query for the state; using dot-notation * @return {Boolean} True if name is valid, false if not */ var _validateStateQuery = function(query) { query = query || ''; // TODO optimize with RegExp var nameChain = query.split('.'); for(var i=0; i<nameChain.length; i++) { if(!nameChain[i].match(/(\*(\*)?|[a-zA-Z0-9_]+)/)) { return false; } } return true; }; /** * Compare two states, compares values. * * @return {Boolean} True if states are the same, false if states are different */ var _compareStates = function(a, b) { a = a || {}; b = b || {}; return a.name === b.name && angular.equals(a.params, b.params); }; /** * Get a list of parent states * * @param {String} name A unique identifier for the state; using dot-notation * @return {Array} An Array of parent states */ var _getNameChain = function(name) { var nameList = name.split('.'); return nameList .map(function(item, i, list) { return list.slice(0, i+1).join('.'); }) .filter(function(item) { return item !== null; }); }; /** * Internal method to crawl library heirarchy * * @param {String} name A unique identifier for the state; using state-notation * @return {Object} A state data Object */ var _getState = function(name) { name = name || ''; var state = null; // Only use valid state queries if(!_validateStateName(name)) { return null; // Use cache if exists } else if(_stateCache[name]) { return _stateCache[name]; } var nameChain = _getNameChain(name); var stateChain = nameChain .map(function(name, i) { var item = angular.copy(_stateLibrary[name]); return item; }) .filter(function(parent) { return !!parent; }); // Walk up checking inheritance for(var i=stateChain.length-1; i>=0; i--) { if(stateChain[i]) { var nextState = stateChain[i]; state = angular.merge(nextState, state || {}); } if(state && state.inherit === false) break; } // Store in cache _stateCache[name] = state; return state; }; /** * Internal method to store a state definition. Parameters should be included in data Object not state name. * * @param {String} name A unique identifier for the state; using state-notation * @param {Object} data A state definition data Object * @return {Object} A state data Object */ var _defineState = function(name, data) { if(name === null || typeof name === 'undefined') { throw new Error('Name cannot be null.'); // Only use valid state names } else if(!_validateStateName(name)) { throw new Error('Invalid state name.'); } // Create state var state = angular.copy(data); // Use defaults _setStateDefaults(state); // Named state state.name = name; // Set definition _stateLibrary[name] = state; // Reset cache _stateCache = {}; // URL mapping if(state.url) { _urlDictionary.add(state.url, state); } return data; }; /** * Set configuration data parameters for StateRouter * * Including parameters: * * - historyLength {Number} Defaults to 5 * - initialLocation {Object} An Object{name:String, params:Object} for initial state transition * * @param {Object} options A data Object * @return {$stateProvider} Itself; chainable */ this.options = function(options) { angular.extend(_configuration, options || {}); return _provider; }; /** * Set/get state * * @param {String} name A unique identifier for the state; using state-notation * @param {Object} data A state definition data Object * @return {$stateProvider} Itself; chainable */ this.state = function(name, state) { // Get if(!state) { return _getState(name); } // Set _defineState(name, state); return _provider; }; /** * Set initialization parameters; deferred to $ready() * * @param {String} name A iniital state * @param {Object} params A data object of params * @return {$stateProvider} Itself; chainable */ this.init = function(name, params) { _configuration.initialLocation = { name: name, params: params }; return _provider; }; /** * Get instance */ this.$get = ['$rootScope', '$location', '$q', '$queueHandler', function StateRouterFactory($rootScope, $location, $q, $queueHandler) { // State var _current; var _transitionQueue = []; var _isReady = true; var _options; var _initalLocation; var _history = []; var _isInit = false; /** * Internal method to add history and correct length * * @param {Object} data An Object */ var _pushHistory = function(data) { // Keep the last n states (e.g. - defaults 5) var historyLength = _options.historyLength || 5; if(data) { _history.push(data); } // Update length if(_history.length > historyLength) { _history.splice(0, _history.length - historyLength); } }; /** * Internal method to fulfill change state request. Parameters in `params` takes precedence over state-notation `name` expression. * * @param {String} name A unique identifier for the state; using state-notation including optional parameters * @param {Object} params A data object of params * @return {Promise} A promise fulfilled when state change occurs */ var _changeState = function(name, params) { var deferred = $q.defer(); $rootScope.$evalAsync(function() { params = params || {}; // Parse state-notation expression var nameExpr = _parseName(name); name = nameExpr.name; params = angular.extend(nameExpr.params || {}, params); // Special name notation if(name === '.' && _current) { name = _current.name; } var error = null; var request = { name: name, params: params, locals: {}, promise: deferred.promise }; // Compile execution phases var queue = $queueHandler.create().data(request); var nextState = angular.copy(_getState(name)); var prevState = _current; if(nextState) { // Set locals nextState.locals = request.locals; // Set parameters nextState.params = angular.extend(nextState.params || {}, params); } // Does not exist if(nextState === null) { queue.add(function(data, next) { error = new Error('Requested state was not defined.'); error.code = 'notfound'; $rootScope.$broadcast('$stateChangeErrorNotFound', error, request); next(error); }, 200); // State not changed } else if(_compareStates(prevState, nextState)) { queue.add(function(data, next) { _current = nextState; next(); }, 200); // Valid state exists } else { // Process started queue.add(function(data, next) { $rootScope.$broadcast('$stateChangeBegin', request); next(); }, 201); // Make state change queue.add(function(data, next) { if(prevState) _pushHistory(prevState); _current = nextState; next(); }, 200); // Add middleware queue.add(_layerList); // Process ended queue.add(function(data, next) { $rootScope.$broadcast('$stateChangeEnd', request); next(); }, -200); } // Run queue.execute(function(err) { if(err) { $rootScope.$broadcast('$stateChangeError', err, request); deferred.reject(err); } else { deferred.resolve(); } }); }); return deferred.promise; }; /** * Internal method to change to state and broadcast completion * * @param {String} name A unique identifier for the state; using state-notation including optional parameters * @param {Object} params A data object of params * @return {Promise} A promise fulfilled when state change occurs */ var _changeStateAndBroadcastComplete = function(name, params) { return _changeState(name, params).then(function() { $rootScope.$broadcast('$stateChangeComplete', null, _current); }, function(err) { $rootScope.$broadcast('$stateChangeComplete', err, _current); }); }; /** * Reloads the current state * * @return {Promise} A promise fulfilled when state change occurs */ var _reloadState = function() { var deferred = $q.defer(); $rootScope.$evalAsync(function() { var n = _current.name; var p = angular.copy(_current.params); if(!_current.params) { _current.params = {}; } _current.params.deprecated = true; // Notify $rootScope.$broadcast('$stateReload', null, _current); _changeStateAndBroadcastComplete(n, p).then(function() { deferred.resolve(); }, function(err) { deferred.reject(err); }); }); return deferred.promise; }; // Instance var _inst; _inst = { /** * Get options * * @return {Object} A configured options */ options: function() { // Hasn't been initialized if(!_options) { _options = angular.copy(_configuration); } return _options; }, /** * Set/get state. Reloads state if current state is affected by defined * state (when redefining parent or current state) * * @param {String} name A unique identifier for the state; using state-notation * @param {Object} data A state definition data Object * @return {$state} Itself; chainable */ state: function(name, state) { // Get if(!state) { return _getState(name); } // Set _defineState(name, state); return _inst; }, /** * Internal method to add middleware; called during state transition * * @param {Function} handler A callback, function(request, next) * @param {Number} priority A number denoting priority * @return {$state} Itself; chainable */ $use: function(handler, priority) { if(typeof handler !== 'function') { throw new Error('Middleware must be a function.'); } if(typeof priority !== 'undefined') handler.priority = priority; _layerList.push(handler); return _inst; }, /** * Internal method to perform initialization * * @return {$state} Itself; chainable */ $ready: function() { $rootScope.$evalAsync(function() { if(!_isInit) { _isInit = true; // Configuration if(!_options) { _options = angular.copy(_configuration); } // Initial location if(_options.hasOwnProperty('initialLocation')) { _initalLocation = angular.copy(_options.initialLocation); } var readyDeferred = null; // Initial location if($location.url() !== '') { readyDeferred = _inst.$location($location.url()); // Initialize with state } else if(_initalLocation) { readyDeferred = _changeStateAndBroadcastComplete(_initalLocation.name, _initalLocation.params); } $q.when(readyDeferred).then(function() { $rootScope.$broadcast('$stateInit'); }); } }); return _inst; }, // Parse state notation name-params. parse: _parseName, /** * Retrieve definition of states * * @return {Object} A hash of all defined states */ library: function() { return _stateLibrary; }, // Validation validate: { name: _validateStateName, query: _validateStateQuery }, /** * Retrieve history * * @return {[type]} [description] */ history: function() { return _history; }, /** * Request state transition, asynchronous operation * * @param {String} name A unique identifier for the state; using dot-notation * @param {Object} [params] A parameters data object * @return {Promise} A promise fulfilled when state change complete */ change: function(name, params) { return _changeStateAndBroadcastComplete(name, params); }, /** * Reloads the current state * * @return {Promise} A promise fulfilled when state change occurs */ reload: _reloadState, /** * Internal method to change state based on $location.url(), asynchronous operation using internal methods, quiet fallback. * * @param {String} url A url matching defind states * @param {Function} [callback] A callback, function(err) * @return {$state} Itself; chainable */ $location: function(url) { var data = _urlDictionary.lookup(url); if(data) { var state = data.ref; if(state) { // Parse params from url return _changeStateAndBroadcastComplete(state.name, data.params); } } else if(!!url && url !== '') { var error = new Error('Requested state was not defined.'); error.code = 'notfound'; $rootScope.$broadcast('$stateChangeErrorNotFound', error, { url: url }); } return $q.reject(new Error('Unable to find location in library')); }, /** * Retrieve copy of current state * * @return {Object} A copy of current state */ current: function() { return (!_current) ? null : angular.copy(_current); }, /** * Check query against current state * * @param {Mixed} query A string using state notation or a RegExp * @param {Object} params A parameters data object * @return {Boolean} A true if state is parent to current state */ active: function(query, params) { query = query || ''; // No state if(!_current) { return false; // Use RegExp matching } else if(query instanceof RegExp) { return !!_current.name.match(query); // String; state dot-notation } else if(typeof query === 'string') { // Cast string to RegExp if(query.match(/^\/.*\/$/)) { var casted = query.substr(1, query.length-2); return !!_current.name.match(new RegExp(casted)); // Transform to state notation } else { var transformed = query .split('.') .map(function(item) { if(item === '*') { return '[a-zA-Z0-9_]*'; } else if(item === '**') { return '[a-zA-Z0-9_\\.]*'; } else { return item; } }) .join('\\.'); return !!_current.name.match(new RegExp(transformed)); } } // Non-matching return false; } }; return _inst; }]; }]; },{"../utils/parameters":8,"../utils/url-dictionary":9}],7:[function(require,module,exports){ 'use strict'; var UrlDictionary = require('../utils/url-dictionary'); module.exports = ['$state', '$location', '$rootScope', function($state, $location, $rootScope) { var _url = $location.url(); // Instance var _self = {}; /** * Update URL based on state */ var _update = function() { var current = $state.current(); if(current && current.url) { var path; path = current.url; // Add parameters or use default parameters var params = current.params || {}; var query = {}; for(var name in params) { var re = new RegExp(':'+name, 'g'); if(path.match(re)) { path = path.replace(re, params[name]); } else { query[name] = params[name]; } } $location.path(path); $location.search(query); _url = $location.url(); } }; /** * Update url based on state */ _self.update = function() { _update(); }; /** * Detect URL change and dispatch state change */ _self.location = function() { var lastUrl = _url; var nextUrl = $location.url(); if(nextUrl !== lastUrl) { _url = nextUrl; $state.$location(_url); $rootScope.$broadcast('$locationStateUpdate'); } }; /** * Register middleware layer */ _self.$ready = function() { $state.$use(function(request, next) { _update(); next(); }); }; return _self; }]; },{"../utils/url-dictionary":9}],8:[function(require,module,exports){ 'use strict'; // Parse Object literal name-value pairs var reParseObjectLiteral = /([,{]\s*(("|')(.*?)\3|\w*)|(:\s*([+-]?(?=\.\d|\d)(?:\d+)?(?:\.?\d*)(?:[eE][+-]?\d+)?|true|false|null|("|')(.*?)\7|\[[^\]]*\])))/g; // Match Strings var reString = /^("|')(.*?)\1$/; // TODO Add escaped string quotes \' and \" to string matcher // Match Number (int/float/exponential) var reNumber = /^[+-]?(?=\.\d|\d)(?:\d+)?(?:\.?\d*)(?:[eE][+-]?\d+)?$/; /** * Parse string value into Boolean/Number/Array/String/null. * * Strings are surrounded by a pair of matching quotes * * @param {String} value A String value to parse * @return {Mixed} A Boolean/Number/Array/String/null */ var _resolveValue = function(value) { // Boolean: true if(value === 'true') { return true; // Boolean: false } else if(value === 'false') { return false; // Null } else if(value === 'null') { return null; // String } else if(value.match(reString)) { return value.substr(1, value.length-2); // Number } else if(value.match(reNumber)) { return +value; // NaN } else if(value === 'NaN') { return NaN; // TODO add matching with Arrays and parse } // Unable to resolve return value; }; // Find values in an object literal var _listify = function(str) { // Trim str = str.replace(/^\s*/, '').replace(/\s*$/, ''); if(str.match(/^\s*{.*}\s*$/) === null) { throw new Error('Parameters expects an Object'); } var sanitizeName = function(name) { return name.replace(/^[\{,]?\s*["']?/, '').replace(/["']?\s*$/, ''); }; var sanitizeValue = function(value) { var str = value.replace(/^(:)?\s*/, '').replace(/\s*$/, ''); return _resolveValue(str); }; return str.match(reParseObjectLiteral).map(function(item, i, list) { return i%2 === 0 ? sanitizeName(item) : sanitizeValue(item); }); }; /** * Create a params Object from string * * @param {String} str A stringified version of Object literal */ var Parameters = function(str) { str = str || ''; // Instance var _self = {}; _listify(str).forEach(function(item, i, list) { if(i%2 === 0) { _self[item] = list[i+1]; } }); return _self; }; module.exports = Parameters; module.exports.resolveValue = _resolveValue; module.exports.listify = _listify; },{}],9:[function(require,module,exports){ 'use strict'; var Url = require('./url'); /** * Constructor */ function UrlDictionary() { this._patterns = []; this._refs = []; this._params = []; } /** * Associate a URL pattern with a reference * * @param {String} pattern A URL pattern * @param {Object} ref A data Object */ UrlDictionary.prototype.add = function(pattern, ref) { pattern = pattern || ''; var _self = this; var i = this._patterns.length; var pathChain; var params = {}; if(pattern.indexOf('?') === -1) { pathChain = Url(pattern).path().split('/'); } else { pathChain = Url(pattern).path().split('/'); } // Start var searchExpr = '^'; // Items (pathChain.forEach(function(chunk, i) { if(i!==0) { searchExpr += '\\/'; } if(chunk[0] === ':') { searchExpr += '[^\\/?]*'; params[chunk.substring(1)] = new RegExp(searchExpr); } else { searchExpr += chunk; } })); // End searchExpr += '[\\/]?$'; this._patterns[i] = new RegExp(searchExpr); this._refs[i] = ref; this._params[i] = params; }; /** * Find a reference according to a URL pattern and retrieve params defined in URL * * @param {String} url A URL to test for * @param {Object} defaults A data Object of default parameter values * @return {Object} A reference to a stored object */ UrlDictionary.prototype.lookup = function(url, defaults) { url = url || ''; var p = Url(url).path(); var q = Url(url).queryparams(); var _self = this; // Check dictionary var _findPattern = function(check) { check = check || ''; for(var i=_self._patterns.length-1; i>=0; i--) { if(check.match(_self._patterns[i]) !== null) { return i; } } return -1; }; var i = _findPattern(p); // Matching pattern found if(i !== -1) { // Retrieve params in pattern match var params = {}; for(var n in this._params[i]) { var paramParser = this._params[i][n]; var urlMatch = (url.match(paramParser) || []).pop() || ''; var varMatch = urlMatch.split('/').pop(); params[n] = varMatch; } // Retrieve params in querystring match params = angular.extend(q, params); return { url: url, ref: this._refs[i], params: params }; // Not in dictionary } else { return null; } }; module.exports = UrlDictionary; },{"./url":10}],10:[function(require,module,exports){ 'use strict'; function Url(url) { url = url || ''; // Instance var _self = { /** * Get the path of a URL * * @return {String} A querystring from URL */ path: function() { return url.indexOf('?') === -1 ? url : url.substring(0, url.indexOf('?')); }, /** * Get the querystring of a URL * * @return {String} A querystring from URL */ querystring: function() { return url.indexOf('?') === -1 ? '' : url.substring(url.indexOf('?')+1); }, /** * Get the querystring of a URL parameters as a hash * * @return {String} A querystring from URL */ queryparams: function() { var pairs = _self.querystring().split('&'); var params = {}; for(var i=0; i<pairs.length; i++) { if(pairs[i] === '') continue; var nameValue = pairs[i].split('='); params[nameValue[0]] = (typeof nameValue[1] === 'undefined' || nameValue[1] === '') ? true : decodeURIComponent(nameValue[1]); } return params; } }; return _self; } module.exports = Url; },{}]},{},[2]) //# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIvVXNlcnMvaGVucnkudHNlbmcvc3JjL2FuZ3VsYXItc3RhdGUtcm91dGVyL3NyYy9kaXJlY3RpdmVzL3NyZWYuanMiLCIvVXNlcnMvaGVucnkudHNlbmcvc3JjL2FuZ3VsYXItc3RhdGUtcm91dGVyL3NyYy9pbmRleC5qcyIsIi9Vc2Vycy9oZW5yeS50c2VuZy9zcmMvYW5ndWxhci1zdGF0ZS1yb3V0ZXIvc3JjL3NlcnZpY2VzL2VuYWN0LmpzIiwiL1VzZXJzL2hlbnJ5LnRzZW5nL3NyYy9hbmd1bGFyLXN0YXRlLXJvdXRlci9zcmMvc2VydmljZXMvcXVldWUtaGFuZGxlci5qcyIsIi9Vc2Vycy9oZW5yeS50c2VuZy9zcmMvYW5ndWxhci1zdGF0ZS1yb3V0ZXIvc3JjL3NlcnZpY2VzL3Jlc29sdXRpb24uanMiLCIvVXNlcnMvaGVucnkudHNlbmcvc3JjL2FuZ3VsYXItc3RhdGUtcm91dGVyL3NyYy9zZXJ2aWNlcy9zdGF0ZS1yb3V0ZXIuanMiLCIvVXNlcnMvaGVucnkudHNlbmcvc3JjL2FuZ3VsYXItc3RhdGUtcm91dGVyL3NyYy9zZXJ2aWNlcy91cmwtbWFuYWdlci5qcyIsIi9Vc2Vycy9oZW5yeS50c2VuZy9zcmMvYW5ndWxhci1zdGF0ZS1yb3V0ZXIvc3JjL3V0aWxzL3BhcmFtZXRlcnMuanMiLCIvVXNlcnMvaGVucnkudHNlbmcvc3JjL2FuZ3VsYXItc3RhdGUtcm91dGVyL3NyYy91dGlscy91cmwtZGljdGlvbmFyeS5qcyIsIi9Vc2Vycy9oZW5yeS50c2VuZy9zcmMvYW5ndWxhci1zdGF0ZS1yb3V0ZXIvc3JjL3V0aWxzL3VybC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBOztBQUVBLE9BQU8sVUFBVSxDQUFDLFVBQVUsVUFBVSxRQUFRO0VBQzVDLE9BQU87SUFDTCxVQUFVO0lBQ1YsT0FBTzs7SUFFUCxNQUFNLFNBQVMsT0FBTyxTQUFTLE9BQU87TUFD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O0VBRWpCLElBQUksUUFBUTs7O0VBR1osSUFBSSxlQUFlLFNBQVMsT0FBTztJQUNqQyxRQUFRLFNBQVM7SUFDakIsSUFBSSxJQUFJLEVBQUUsTUFBTSxVQUFVLE9BQU8sR0FBRyxHQUFHLEdBQUcsS0FBSztNQUM3QyxHQUFHLE1BQU0sTUFBTSxNQUFNLFVBQVUsUUFBUSxNQUFNO1FBQzNDLE9BQU87OztJQUdYLE9BQU8sQ0FBQzs7O0VBR1YsSUFBSSxJQUFJLGFBQWE7OztFQUdyQixHQUFHLE1BQU0sQ0FBQyxHQUFHOzs7SUFHWCxJQUFJLFNBQVM7SUFDYixJQUFJLElBQUksS0FBSyxLQUFLLFFBQVEsSUFBSTtNQUM1QixJQUFJLGNBQWMsS0FBSyxRQUFRLEdBQUc7TUFDbEMsSUFBSSxXQUFXLENBQUMsSUFBSSxNQUFNLGdCQUFnQixJQUFJLFNBQVM7TUFDdkQsSUFBSSxXQUFXLFNBQVMsTUFBTSxLQUFLO01BQ25DLE9BQU8sS0FBSzs7OztJQUlkLFNBQVMsUUFBUSxPQUFPLEdBQUc7O0lBRTNCLE9BQU87TUFDTCxLQUFLO01BQ0wsS0FBSyxLQUFLLE1BQU07TUFDaEIsUUFBUTs7OztTQUlMO0lBQ0wsT0FBTzs7OztBQUlYLE9BQU8sVUFBVTtBQUNqQjs7QUNuSEE7O0FBRUEsU0FBUyxJQUFJLEtBQUs7RUFDaEIsTUFBTSxPQUFPOzs7RUFHYixJQUFJLFFBQVE7Ozs7Ozs7SUFPVixNQUFNLFdBQVc7TUFDZixPQUFPLElBQUksUUFBUSxTQUFTLENBQUMsSUFBSSxNQUFNLElBQUksVUFBVSxHQUFHLElBQUksUUFBUTs7Ozs7Ozs7SUFRdEUsYUFBYSxXQUFXO01BQ3RCLE9BQU8sSUFBSSxRQUFRLFNBQVMsQ0FBQyxJQUFJLEtBQUssSUFBSSxVQUFVLElBQUksUUFBUSxLQUFLOzs7Ozs7OztJQVF2RSxhQUFhLFdBQVc7TUFDdEIsSUFBSSxRQUFRLE1BQU0sY0FBYyxNQUFNO01BQ3RDLElBQUksU0FBUzs7TUFFYixJQUFJLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSxRQUFRLEtBQUs7UUFDaEMsR0FBRyxNQUFNLE9BQU8sSUFBSTtRQUNwQixJQUFJLFlBQVksTUFBTSxHQUFHLE1BQU07UUFDL0IsT0FBTyxVQUFVLE1BQU0sQ0FBQyxPQUFPLFVBQVUsT0FBTyxlQUFlLFVBQVUsT0FBTyxNQUFNLE9BQU8sbUJBQW1CLFVBQVU7OztNQUc1SCxPQUFPOzs7O0VBSVgsT0FBTzs7O0FBR1QsT0FBTyxVQUFVO0FBQ2pCIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZigh