diff --git a/README.md b/README.md
index 5977cf1..3349d8a 100644
--- a/README.md
+++ b/README.md
@@ -344,7 +344,6 @@ http://opensource.org/licenses/BSD-2-Clause
Changes log
-----------
-
###0.1.10###
- `Messenger` performance improvement
- `MLSuperCombo` support for remote list of options
diff --git a/lib/abstract/facet.js b/lib/abstract/facet.js
index e679fb4..38d7859 100644
--- a/lib/abstract/facet.js
+++ b/lib/abstract/facet.js
@@ -1,7 +1,7 @@
'use strict';
-var _ = require('mol-proto');
+var _ = require('milo-core').proto;
module.exports = Facet;
diff --git a/lib/abstract/faceted_object.js b/lib/abstract/faceted_object.js
index fbcabc5..b1b36fc 100644
--- a/lib/abstract/faceted_object.js
+++ b/lib/abstract/faceted_object.js
@@ -2,10 +2,10 @@
var Facet = require('./facet')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , FacetError = require('../util/error').Facet;
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , Match = check.Match;
module.exports = FacetedObject;
@@ -31,7 +31,7 @@ function FacetedObject() {
// FacetedObject class itself is not meant to be instantiated - it has no facets
// It may change, as adding facets is possible to instances
if (this.constructor == FacetedObject)
- throw new FacetError('FacetedObject is an abstract class, can\'t be instantiated');
+ throw new Error('FacetedObject is an abstract class, can\'t be instantiated');
// instantiate class facets
if (this.facetsClasses)
@@ -110,7 +110,7 @@ function FacetedObject$addFacet(FacetClass, facetConfig, facetName, throwOnError
// check that this facetName was not already used in the class
if (protoFacets && protoFacets[facetName])
- throw new FacetError('facet ' + facetName + ' is already part of the class ' + this.constructor.name);
+ throw new Error('facet ' + facetName + ' is already part of the class ' + this.constructor.name);
// check that this faceName does not already exist on the faceted object
if (this[facetName]) {
@@ -118,7 +118,7 @@ function FacetedObject$addFacet(FacetClass, facetConfig, facetName, throwOnError
if (throwOnErrors === false)
return logger.error('FacetedObject addFacet: ', message);
else
- throw new FacetError(message);
+ throw new Error(message);
}
// instantiate the facet
@@ -176,7 +176,7 @@ function FacetedObject$$createFacetedClass(name, facetsClasses, facetsConfig) {
if (facetsConfig)
_.eachKey(facetsConfig, function(fctConfig, fctName) {
if (! facetsClasses.hasOwnProperty(fctName))
- throw new FacetError('configuration for facet (' + fctName + ') passed that is not in class');
+ throw new Error('configuration for facet (' + fctName + ') passed that is not in class');
});
// create subclass of the current class (this refers to the class that calls this method)
diff --git a/lib/abstract/mixin.js b/lib/abstract/mixin.js
deleted file mode 100644
index fe74fc8..0000000
--- a/lib/abstract/mixin.js
+++ /dev/null
@@ -1,211 +0,0 @@
-'use strict';
-
-var _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , MixinError = require('../util/error').Mixin
- , config = require('../config');
-
-
-module.exports = Mixin;
-
-/**
- * `milo.classes.Mixin` - an abstract Mixin class.
- * Can be subclassed using:
- * ```
- * var MyMixin = _.createSubclass(milo.classes.Mixin, 'MyMixin');
- * ```
- *
- * Mixin pattern is also used, but Mixin in milo is implemented as a separate object that is stored on the property of the host object and can create proxy methods on the host object if required.
- * Classes [Messenger](../messenger/index.js.html) and [MessageSource](../messenger/m_source.js.html) are subclasses of Mixin abstract class. `this` in proxy methods refers to Mixin instance, the reference to the host object is `this._hostObject`.
- *
- * @param {Object} hostObject Optional object where a Mixin instance will be stored on. It is used to proxy methods and also to find the reference when it is needed for host object implementation.
- * @param {Object} proxyMethods Optional map of proxy method names as keys and Mixin methods names as values, so proxied methods can be renamed to avoid name-space conflicts if two different Mixin instances with the same method names are put on the object
- * @param {List} arguments all constructor arguments will be passed to init method of Mixin subclass together with hostObject and proxyMethods
- * @return {Mixin}
- */
-function Mixin(hostObject, proxyMethods) { // , other args - passed to init method
- check(hostObject, Match.Optional(Match.OneOf(Object, Function)));
-
- // store hostObject
- _.defineProperty(this, '_hostObject', hostObject);
-
- // proxy methods to hostObject
- if (proxyMethods)
- this._createProxyMethods(proxyMethods);
-
- // calling init if it is defined in the class
- if (this.init)
- this.init.apply(this, arguments);
-}
-
-
-/**
- * ####Mixin instance methods####
- * These methods are called by constructor, they are not to be called from subclasses.
- *
- * - [_createProxyMethod](#_createProxyMethod)
- * - [_createProxyMethods](#_createProxyMethods)
- */
-_.extendProto(Mixin, {
- _createProxyMethod: _createProxyMethod, // deprecated, should not be used
- _createProxyMethods: _createProxyMethods // deprecated, should not be used
-});
-
-
-/**
- * ####Mixin class methods####
- * These method should be called in host class declaration.
- *
- * - [useWith](#Mixin$$useWith)
- */
-_.extend(Mixin, {
- useWith: Mixin$$useWith
-});
-
-
-/**
- * Creates a proxied method of Mixin subclass on host object.
- *
- * @param {String} mixinMethodName name of method in Mixin subclass
- * @param {String} proxyMethodName name of created proxy method on host object
- * @param {Object} hostObject Optional reference to the host object; if not specified the host object passed to constructor wil be used. It allows to use the same instance of Mixin on two host objects.
- */
-function _createProxyMethod(proxyMethodName, mixinMethodName, hostObject) {
- hostObject = hostObject || this._hostObject;
-
- // Mixin class does not allow shadowing methods that exist on the host object
- if (hostObject[proxyMethodName])
- throw new MixinError('method ' + proxyMethodName +
- ' already defined in host object');
-
- var method = this[mixinMethodName]
- check(method, Function);
-
- // Bind proxied Mixin's method to Mixin instance
- var boundMethod = method.bind(this);
-
- _.defineProperty(hostObject, proxyMethodName, boundMethod, _.WRIT);
-}
-
-
-/**
- * Creates proxied methods of Mixin subclass on host object.
- *
- * @param {Hash[String]|Array[String]} proxyMethods map of names of methods, key - proxy method name, value - mixin method name. Can be array.
- * @param {Object} hostObject an optional reference to the host object; if not specified the host object passed to constructor wil be used. It allows to use the same instance of Mixin on two host objects.
- */
-function _createProxyMethods(proxyMethods, hostObject) {
- check(proxyMethods, Match.Optional(Match.OneOf([String], Match.ObjectHash(String))));
-
- // creating and binding proxy methods on the host object
- if (Array.isArray(proxyMethods))
- proxyMethods.forEach(function(methodName) {
- // method called this way to allow using _createProxyMethods with objects
- // that are not inheriting from Mixin
- _createProxyMethod.call(this, methodName, methodName, hostObject);
- }, this);
- else
- _.eachKey(proxyMethods, function(mixinMethodName, proxyMethodName) {
- // method called this way to allow using _createProxyMethods with objects
- // that are not inheriting from Mixin
- _createProxyMethod.call(this, proxyMethodName, mixinMethodName, hostObject);
- }, this);
-}
-
-
-/**
- * Sets mixin instance property name on the host class
- * Can be called only once
- *
- * @private
- * @param {Function} this Mixin subclass (not instance)
- * @param {Function} hostClass
- * @param {String} instanceKey
- */
-function Mixin_setInstanceKey(hostClass, method, instanceKey) {
- check(hostClass, Function);
- check(instanceKey, Match.IdentifierString);
-
- var prop = config.mixin.instancePropertiesMap
- , instanceKeys = hostClass[prop] = hostClass[prop] || {};
-
- if (instanceKeys[method.name])
- throw new Error('Mixin: instance property for method with name '
- + method.name + ' is already set');
-
- instanceKeys[method.name] = instanceKey;
-}
-
-
-/**
- * Adds method of Mixin subclass to host class prototype.
- *
- * @private
- * @param {Function} this Mixin subclass (not instance)
- * @param {String} mixinMethodName name of method in Mixin subclass
- * @param {String} hostMethodName (optional) name of created proxy method on host object, same if not specified
- * @param {Object} hostObject object class, must be specified as the last parameter (2nd or 3rd)
- */
-function Mixin_addMethod(hostClass, instanceKey, mixinMethodName, hostMethodName) {
- var method = this.prototype[mixinMethodName];
- check(method, Function);
-
- var wrappedMethod = _wrapMixinMethod.call(this, method);
-
- _.defineProperty(hostClass.prototype, hostMethodName, wrappedMethod, _.WRIT);
-
- Mixin_setInstanceKey(hostClass, method, instanceKey)
-}
-
-
-/**
- * Returns method that will be exposed on the host class prototype
- *
- * @private
- * @param {Function} this Mixin subclass (not instance)
- * @return {Function}
- */
-function _wrapMixinMethod(method) {
- return function() { // ,... arguments
- var mixinInstance = _getMixinInstance.call(this, method.name);
- return method.apply(mixinInstance, arguments);
- }
-}
-
-
-/**
- * Returns the reference to the instance of mixin subclass.
- * This method is used when methods are exposed on the host class prototype (using addMehtods) rather than on host instance.
- * Subclasses should not use this methods - whenever subclass method is exposed on the prototype it will be wrapped to set correct context for the subclass method.
- *
- * @private
- * @return {Object}
- */
-function _getMixinInstance(methodName) {
- if (this instanceof Mixin) return this;
- var instanceKeys = this.constructor[config.mixin.instancePropertiesMap]
- return this[instanceKeys[methodName]];
-}
-
-
-/**
- * Adds methods of Mixin subclass to host class prototype.
- *
- * @param {Function} this Mixin subclass (not instance)
- * @param {Object} hostClass host object class; must be specified.
- * @param {String} instanceKey the name of the property the host class instance will store mixin instance on
- * @param {Hash[String]|Array[String]} mixinMethods map of names of methods, key - host method name, value - mixin method name. Can be array.
- */
-function Mixin$$useWith(hostClass, instanceKey, mixinMethods) {
- check(mixinMethods, Match.Optional(Match.OneOf([String], Match.ObjectHash(String))));
-
- if (Array.isArray(mixinMethods))
- mixinMethods.forEach(function(methodName) {
- Mixin_addMethod.call(this, hostClass, instanceKey, methodName, methodName);
- }, this);
- else
- _.eachKey(mixinMethods, function(mixinMethodName, hostMethodName) {
- Mixin_addMethod.call(this, hostClass, instanceKey, mixinMethodName, hostMethodName);
- }, this);
-}
diff --git a/lib/abstract/registry.js b/lib/abstract/registry.js
index 599d91d..5d50105 100644
--- a/lib/abstract/registry.js
+++ b/lib/abstract/registry.js
@@ -1,8 +1,8 @@
'use strict';
-var _ = require('mol-proto')
- , RegistryError = require('../util/error').Registry
- , check = require('../util/check')
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
module.exports = ClassRegistry;
@@ -58,10 +58,10 @@ function add(aClass, name) {
if (aClass != this.FoundationClass)
check(aClass, Match.Subclass(this.FoundationClass), 'class must be a sub(class) of a foundation class');
} else
- throw new RegistryError('foundation class must be set before adding classes to registry');
+ throw new Error('foundation class must be set before adding classes to registry');
if (this.__registeredClasses[name])
- throw new RegistryError('class "' + name + '" is already registered');
+ throw new Error('class "' + name + '" is already registered');
this.__registeredClasses[name] = aClass;
};
@@ -93,7 +93,7 @@ function remove(nameOrClass) {
: nameOrClass.name;
if (! this.__registeredClasses[name])
- throw new RegistryError('class is not registered');
+ throw new Error('class is not registered');
delete this.__registeredClasses[name];
};
diff --git a/lib/attributes/a_bind.js b/lib/attributes/a_bind.js
index fca474d..4545f4d 100644
--- a/lib/attributes/a_bind.js
+++ b/lib/attributes/a_bind.js
@@ -1,10 +1,10 @@
'use strict';
var Attribute = require('./a_class')
- , AttributeError = require('../util/error').Attribute
, config = require('../config')
- , _ = require('mol-proto')
- , check = require('../util/check')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
@@ -87,7 +87,7 @@ function attrName() {
var bindTo = value.match(ATTRIBUTE_REGEXP);
if (! bindTo)
- throw new AttributeError('invalid bind attribute ' + value);
+ throw new Error('invalid bind attribute ' + value);
this.compClass = bindTo[1] || 'Component';
this.compFacets = (bindTo[2] && bindTo[2].split(FACETS_SPLIT_REGEXP)) || undefined;
@@ -107,7 +107,7 @@ function validate() {
check(this.compName, Match.IdentifierString);
if (! this.compClass)
- throw new AttributeError('empty component class name ' + this.compClass);
+ throw new Error('empty component class name ' + this.compClass);
return this;
}
diff --git a/lib/attributes/a_class.js b/lib/attributes/a_class.js
index 6753342..e219d74 100644
--- a/lib/attributes/a_class.js
+++ b/lib/attributes/a_class.js
@@ -1,9 +1,9 @@
'use strict';
-var _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , toBeImplemented = require('../util/error').toBeImplemented;
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , Match = check.Match;
module.exports = Attribute;
@@ -111,3 +111,8 @@ function Attribute$set(value) {
function Attribute$decorate() {
this.set(this.render());
}
+
+
+function toBeImplemented() {
+ throw new Error('calling the method of an absctract class');
+}
diff --git a/lib/attributes/a_load.js b/lib/attributes/a_load.js
index aae2f9c..9843b9f 100644
--- a/lib/attributes/a_load.js
+++ b/lib/attributes/a_load.js
@@ -1,9 +1,8 @@
'use strict';
var Attribute = require('./a_class')
- , AttributeError = require('../util/error').Attribute
, config = require('../config')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
/**
diff --git a/lib/binder.js b/lib/binder.js
index 17c7cdf..8e7f42c 100644
--- a/lib/binder.js
+++ b/lib/binder.js
@@ -7,9 +7,9 @@ var miloMail = require('./services/mail')
, ComponentInfo = require('./components/c_info')
, Scope = require('./components/scope')
, BindAttribute = require('./attributes/a_bind')
- , BinderError = require('./util/error').Binder
- , _ = require('mol-proto')
- , check = require('./util/check')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, utilDom = require('./util/dom')
, Match = check.Match;
diff --git a/lib/classes.js b/lib/classes.js
index 4bafc02..88156c1 100644
--- a/lib/classes.js
+++ b/lib/classes.js
@@ -1,5 +1,7 @@
'use strict';
+var coreClasses = require('milo-core').classes;
+
//
// milo.classes
// -----------
@@ -11,10 +13,10 @@ var classes = {
FacetedObject: require('./abstract/faceted_object'),
Scope: require('./components/scope'),
ClassRegistry: require('./abstract/registry'),
- Mixin: require('./abstract/mixin'),
- MessageSource: require('./messenger/m_source'),
- MessengerMessageSource: require('./messenger/msngr_source'),
- MessengerAPI: require('./messenger/m_api'),
+ Mixin: coreClasses.Mixin,
+ MessageSource: coreClasses.MessageSource,
+ MessengerMessageSource: coreClasses.MessengerMessageSource,
+ MessengerAPI: coreClasses.MessengerAPI,
DOMEventsSource: require('./components/msg_src/dom_events'),
Transaction: require('./command/transaction'),
TransactionHistory: require('./command/transaction_history')
diff --git a/lib/command/actions_history.js b/lib/command/actions_history.js
index 47c1718..1195897 100644
--- a/lib/command/actions_history.js
+++ b/lib/command/actions_history.js
@@ -1,8 +1,9 @@
'use strict';
-var _ = require('mol-proto')
- , logger = require('../util/logger');
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger;
module.exports = ActionsHistory;
diff --git a/lib/command/index.js b/lib/command/index.js
index 442b8bb..2f04fed 100644
--- a/lib/command/index.js
+++ b/lib/command/index.js
@@ -1,10 +1,11 @@
'use strict';
-var _ = require('mol-proto')
- , check = require('../util/check')
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match
- , logger = require('../util/logger');
+ , logger = miloCore.util.logger;
var UNDO_COMMAND = '_undoCommand';
diff --git a/lib/command/transaction.js b/lib/command/transaction.js
index db8deca..fd239ab 100644
--- a/lib/command/transaction.js
+++ b/lib/command/transaction.js
@@ -2,7 +2,7 @@
var ActionsHistory = require('./actions_history')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
module.exports = Transaction;
diff --git a/lib/command/transaction_history.js b/lib/command/transaction_history.js
index a6a5ddf..066879d 100644
--- a/lib/command/transaction_history.js
+++ b/lib/command/transaction_history.js
@@ -3,9 +3,10 @@
var ActionsHistory = require('./actions_history')
, Transaction = require('./transaction')
- , logger = require('../util/logger')
- , Messenger = require('../messenger')
- , _ = require('mol-proto');
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , Messenger = miloCore.Messenger
+ , _ = miloCore.proto;
module.exports = TransactionHistory;
diff --git a/lib/components/ComponentTemplate.js b/lib/components/ComponentTemplate.js
index 99d99a4..41b49c0 100644
--- a/lib/components/ComponentTemplate.js
+++ b/lib/components/ComponentTemplate.js
@@ -1,8 +1,8 @@
'use strict';
var Component = require('../c_class')
- , componentsRegistry = require('../c_registry');
-
+ , componentsRegistry = require('../c_registry')
+ , _ = require('milo-core').proto;
var MyComponent = Component.createComponentClass('MyComponent', {
container: undefined, // optional
@@ -13,3 +13,9 @@ var MyComponent = Component.createComponentClass('MyComponent', {
componentsRegistry.add(MyComponent);
module.exports = MyComponent;
+
+
+_.extendProto(MyComponent, {
+ init: MyComponent$init
+ // ...
+});
diff --git a/lib/components/c_class.js b/lib/components/c_class.js
index b5ce7e3..720befc 100644
--- a/lib/components/c_class.js
+++ b/lib/components/c_class.js
@@ -5,19 +5,18 @@ var FacetedObject = require('../abstract/faceted_object')
, facetsRegistry = require('./c_facets/cf_registry')
, ComponentFacet = facetsRegistry.get('ComponentFacet')
, componentUtils = require('./c_utils')
- , Messenger = require('../messenger')
- , _ = require('mol-proto')
- , check = require('../util/check')
+ , miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match
, config = require('../config')
, miloComponentName = require('../util/component_name')
- , logger = require('../util/logger')
+ , logger = miloCore.util.logger
, domUtils = require('../util/dom')
- , ComponentError = require('../util/error').Component
, BindAttribute = require('../attributes/a_bind')
, Scope = require('./scope')
- , DOMStorage = require('../util/storage')
- , jsonParse = require('../util/json_parse');
+ , DOMStorage = require('../util/storage');
var _makeComponentConditionFunc = componentUtils._makeComponentConditionFunc;
@@ -237,7 +236,7 @@ function Component_domStorageSerializer(component) {
function Component_domStorageParser(compStr, compClassName) {
- var state = jsonParse(compStr);
+ var state = _.jsonParse(compStr);
if (state)
return Component.createFromState(state);
}
@@ -261,7 +260,7 @@ function Component$$create(info, throwOnErrors) {
logger.error('Component', message, ';using base Component class instead');
ComponentClass = Component;
} else
- throw new ComponentError(message);
+ throw new Error(message);
}
var aComponent = new ComponentClass(info.scope, info.el, info.name, info);
@@ -290,7 +289,7 @@ function Component$$copy(component, deepCopy) {
check(deepCopy, Match.Optional(Boolean));
if (deepCopy && !component.container)
- throw new ComponentError('Cannot deep copy component without container facet');
+ throw new Error('Cannot deep copy component without container facet');
// copy DOM element, using Dom facet if it is available
var newEl = component.dom
@@ -421,7 +420,7 @@ function _createComponentWrapElement(state, newUniqueName) {
var children = domUtils.children(wrapEl);
if (children.length != 1)
- throw new ComponentError('cannot create component: incorrect HTML, elements number: ' + children.length + ' (should be 1)');
+ throw new Error('cannot create component: incorrect HTML, elements number: ' + children.length + ' (should be 1)');
var compEl = children[0];
var attr = new BindAttribute(compEl);
attr.compName = newUniqueName ? miloComponentName() : state.compName;
diff --git a/lib/components/c_facet.js b/lib/components/c_facet.js
index 248796f..e699977 100644
--- a/lib/components/c_facet.js
+++ b/lib/components/c_facet.js
@@ -14,10 +14,10 @@
*/
var Facet = require('../abstract/facet')
- , Messenger = require('../messenger')
- , FacetError = require('../util/error').Facet
+ , miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
, componentUtils = require('./c_utils')
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
var ComponentFacet = _.createSubclass(Facet, 'ComponentFacet');
@@ -117,15 +117,15 @@ function ComponentFacet$onConfigMessages(messageSubscribers) {
context: this.owner
};
else
- throw new FacetError('unknown subscriber context in configuration: ' + subscriber.context);
+ throw new Error('unknown subscriber context in configuration: ' + subscriber.context);
return this.on(messages, subscriber);
}
- throw new FacetError('unknown subscriber context type in configuration: ' + contextType);
+ throw new Error('unknown subscriber context type in configuration: ' + contextType);
}
- throw new FacetError('unknown subscriber type in configuration: ' + subscriberType);
+ throw new Error('unknown subscriber type in configuration: ' + subscriberType);
}, this);
return notYetRegisteredMap;
diff --git a/lib/components/c_facets/Container.js b/lib/components/c_facets/Container.js
index 8f7559d..6036423 100644
--- a/lib/components/c_facets/Container.js
+++ b/lib/components/c_facets/Container.js
@@ -4,10 +4,11 @@
var ComponentFacet = require('../c_facet')
, miloBinder = require('../../binder')
, Scope = require('../scope')
- , _ = require('mol-proto')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger
, facetsRegistry = require('./cf_registry')
- , domUtils = require('../../util/dom')
- , logger = require('../../util/logger');
+ , domUtils = require('../../util/dom');
/**
diff --git a/lib/components/c_facets/Data.js b/lib/components/c_facets/Data.js
index bd6dc6d..0bf6adf 100644
--- a/lib/components/c_facets/Data.js
+++ b/lib/components/c_facets/Data.js
@@ -1,23 +1,24 @@
'use strict';
-var Mixin = require('../../abstract/mixin')
+var miloCore = require('milo-core')
+ , Mixin = miloCore.classes.Mixin
, ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Messenger = require('../../messenger')
+ , Messenger = miloCore.Messenger
, DOMEventsSource = require('../msg_src/dom_events')
, DataMsgAPI = require('../msg_api/data')
, getElementDataAccess = require('../msg_api/de_data')
- , pathUtils = require('../../model/path_utils')
- , ModelPath = require('../../model/m_path')
- , modelUtils = require('../../model/model_utils')
- , changeDataHandler = require('../../model/change_data')
+ , Model = miloCore.Model
+ , pathUtils = Model._utils.path
+ , modelUtils = Model._utils.model
+ , changeDataHandler = Model._utils.changeDataHandler
, getTransactionFlag = changeDataHandler.getTransactionFlag
, setTransactionFlag = changeDataHandler.setTransactionFlag
, postTransactionFinished = changeDataHandler.postTransactionFinished
- , _ = require('mol-proto')
- , logger = require('../../util/logger');
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger;
/**
@@ -72,7 +73,7 @@ module.exports = Data;
* ModelPath methods added to Data prototype
*/
['push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {
- var method = ModelPath.prototype[methodName];
+ var method = Model.Path.prototype[methodName];
_.defineProperty(Data.prototype, methodName, method);
});
diff --git a/lib/components/c_facets/Dom.js b/lib/components/c_facets/Dom.js
index 5494f25..175310f 100644
--- a/lib/components/c_facets/Dom.js
+++ b/lib/components/c_facets/Dom.js
@@ -3,15 +3,15 @@
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , _ = require('mol-proto')
- , check = require('../../util/check')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match
+ , doT = miloCore.util.doT
, binder = require('../../binder')
, BindAttribute = require('../../attributes/a_bind')
- , DomFacetError = require('../../util/error').DomFacet
, domUtils = require('../../util/dom')
- , config = require('../../config')
- , doT = require('dot');
+ , config = require('../../config');
/**
@@ -149,7 +149,7 @@ function _attachCssClasses(el, methodName, cssClasses, enforce) {
else if (typeof cssClasses == 'string')
callMethod(cssClasses);
else
- throw new DomFacetError('unknown type of CSS classes parameter');
+ throw new Error('unknown type of CSS classes parameter');
function callMethod(cssCls) {
doToggle
@@ -265,7 +265,7 @@ var findDirections = {
// or downwards (direction = "down")
function find(direction, iterator) {
if (! findDirections.hasOwnProperty(direction))
- throw new DomFacetError('incorrect find direction: ' + direction);
+ throw new Error('incorrect find direction: ' + direction);
var el = this.owner.el
, scope = this.owner.scope
diff --git a/lib/components/c_facets/Drag.js b/lib/components/c_facets/Drag.js
index 2551f6b..8680fe8 100644
--- a/lib/components/c_facets/Drag.js
+++ b/lib/components/c_facets/Drag.js
@@ -8,8 +8,9 @@ var ComponentFacet = require('../c_facet')
, DOMEventsSource = require('../msg_src/dom_events')
, Component = require('../c_class')
, DragDrop = require('../../util/dragdrop')
- , _ = require('mol-proto')
- , logger = require('../../util/logger');
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger;
/**
diff --git a/lib/components/c_facets/Drop.js b/lib/components/c_facets/Drop.js
index 87e2158..7b6658b 100644
--- a/lib/components/c_facets/Drop.js
+++ b/lib/components/c_facets/Drop.js
@@ -8,9 +8,7 @@ var ComponentFacet = require('../c_facet')
, DOMEventsSource = require('../msg_src/dom_events')
, DropMsgAPI = require('../msg_api/drop')
, DragDrop = require('../../util/dragdrop')
- , DropError = require('../../util/error').Drop
- , _ = require('mol-proto')
- , _handleDropDependency;
+ , _ = require('milo-core').proto;
/**
* `milo.registry.facets.get('Drop')`
@@ -119,7 +117,7 @@ function postToService(eventType, event) {
}
-_handleDropDependency = _.throttle(_handleDropDependencyNothrottle, 50);
+var _handleDropDependency = _.throttle(_handleDropDependencyNothrottle, 50);
function _handleDropDependencyNothrottle(dt, originalDropComponent) {
var allow = this.config.allow
, parentAllowed = true;
@@ -170,7 +168,7 @@ function _isDropAllowed(dt, originalDropComponent) {
return !! _.result(test, this.owner, meta, dt);
}
default:
- throw new DropError('Incorrect allowed components in config');
+ throw new Error('Incorrect allowed components in config');
}
} else {
var dataTypes = allow && allow.dataTypes
diff --git a/lib/components/c_facets/Events.js b/lib/components/c_facets/Events.js
index 0585269..4eb75d0 100644
--- a/lib/components/c_facets/Events.js
+++ b/lib/components/c_facets/Events.js
@@ -2,9 +2,10 @@
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Messenger = require('../../messenger')
+ , miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
, DOMEventsSource = require('../msg_src/dom_events')
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
/**
diff --git a/lib/components/c_facets/Frame.js b/lib/components/c_facets/Frame.js
index e8b916f..0543271 100644
--- a/lib/components/c_facets/Frame.js
+++ b/lib/components/c_facets/Frame.js
@@ -3,10 +3,11 @@
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Messenger = require('../../messenger')
+ , miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
, FrameMessageSource = require('../msg_src/frame')
, domEventsConstructors = require('../../services/de_constrs')
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
/**
diff --git a/lib/components/c_facets/Item.js b/lib/components/c_facets/Item.js
index 9b39507..65da4bd 100644
--- a/lib/components/c_facets/Item.js
+++ b/lib/components/c_facets/Item.js
@@ -3,8 +3,9 @@
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Model = require('../../model')
- , _ = require('mol-proto')
+ , miloCore = require('milo-core')
+ , Model = miloCore.Model
+ , _ = miloCore.proto
, miloMail = require('../../services/mail');
diff --git a/lib/components/c_facets/List.js b/lib/components/c_facets/List.js
index 034bbd1..209e820 100644
--- a/lib/components/c_facets/List.js
+++ b/lib/components/c_facets/List.js
@@ -3,16 +3,16 @@
var ComponentFacet = require('../c_facet')
, Component = require('../c_class')
, facetsRegistry = require('./cf_registry')
- , _ = require('mol-proto')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
, miloMail = require('../../services/mail')
, miloBinder = require('../../binder')
- , miloUtil = require('../../util')
- , ListError = miloUtil.error.List
- , logger = miloUtil.logger
- , doT = require('dot')
- , check = miloUtil.check
+ , logger = miloCore.util.logger
+ , doT = miloCore.util.doT
+ , check = miloCore.util.check
, Match = check.Match
- , domUtils = miloUtil.dom
+ , domUtils = require('../../util/dom')
+ , componentName = require('../../util/component_name')
, miloConfig = require('../../config');
@@ -105,7 +105,7 @@ function onChildrenBound() {
}
// Component must have one child with an Item facet
- if (! foundItem) throw new ListError('No child component has Item facet');
+ if (! foundItem) throw new Error('No child component has Item facet');
this.list.itemSample = foundItem;
@@ -208,7 +208,7 @@ function List$addItem(index, itemData) {
function List$_addItem(index) {
index = index || this.count();
if (this.item(index))
- throw ListError('attempt to create item with ID of existing item');
+ throw Error('attempt to create item with ID of existing item');
// Copy component
var component = Component.copy(this.itemSample, true);
@@ -265,12 +265,12 @@ function List$addItems(count, index) { // ,... items data
function List$_addItems(count, index) {
check(count, Match.Integer);
if (count < 0)
- throw new ListError('can\'t add negative number of items');
+ throw new Error('can\'t add negative number of items');
if (count == 0) return;
var itemsHTML = this.itemsTemplate({
- componentName: miloUtil.componentName,
+ componentName: componentName,
count: count
});
diff --git a/lib/components/c_facets/ModelFacet.js b/lib/components/c_facets/ModelFacet.js
index 886933f..076d7d4 100644
--- a/lib/components/c_facets/ModelFacet.js
+++ b/lib/components/c_facets/ModelFacet.js
@@ -2,9 +2,10 @@
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Model = require('../../model')
- , Mixin = require('../../abstract/mixin')
- , _ = require('mol-proto');
+ , miloCore = require('milo-core')
+ , Model = miloCore.Model
+ , Mixin = miloCore.classes.Mixin
+ , _ = miloCore.proto;
// generic drag handler, should be overridden
diff --git a/lib/components/c_facets/Options.js b/lib/components/c_facets/Options.js
index f8a671c..7d84edc 100644
--- a/lib/components/c_facets/Options.js
+++ b/lib/components/c_facets/Options.js
@@ -2,9 +2,9 @@
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Model = require('../../model')
-
- , _ = require('mol-proto');
+ , miloCore = require('milo-core')
+ , Model = miloCore.Model
+ , _ = miloCore.proto;
// generic drag handler, should be overridden
diff --git a/lib/components/c_facets/Template.js b/lib/components/c_facets/Template.js
index a35d6d3..4c6c119 100644
--- a/lib/components/c_facets/Template.js
+++ b/lib/components/c_facets/Template.js
@@ -14,9 +14,10 @@
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , _ = require('mol-proto')
- , check = require('../../util/check')
- , logger = require('../../util/logger')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , logger = miloCore.util.logger
, Match = check.Match
, binder = require('../../binder');
diff --git a/lib/components/c_facets/Transfer.js b/lib/components/c_facets/Transfer.js
index 0d00889..6b64c35 100644
--- a/lib/components/c_facets/Transfer.js
+++ b/lib/components/c_facets/Transfer.js
@@ -2,7 +2,7 @@
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
/**
diff --git a/lib/components/c_facets/facet_template.js b/lib/components/c_facets/facet_template.js
index 6a5f8d4..34d7cb3 100644
--- a/lib/components/c_facets/facet_template.js
+++ b/lib/components/c_facets/facet_template.js
@@ -2,8 +2,7 @@
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
-
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var = _.createSubclass(ComponentFacet, '');
diff --git a/lib/components/c_info.js b/lib/components/c_info.js
index 2e9b680..40bbbd2 100644
--- a/lib/components/c_info.js
+++ b/lib/components/c_info.js
@@ -4,9 +4,9 @@ var componentsRegistry = require('./c_registry')
, facetsRegistry = require('./c_facets/cf_registry')
, componentName = require('../util/component_name')
, Scope = require('./scope')
- , BinderError = require('../util/error').Binder
- , logger = require('../util/logger')
- , _ = require('mol-proto');
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , _ = miloCore.proto;
module.exports = ComponentInfo;
@@ -109,7 +109,7 @@ function reportBinderError(throwOnErrors, message) {
if (throwOnErrors === false)
logger.error('ComponentInfo binder error:', message);
else
- throw new BinderError(message);
+ throw new Error(message);
};
diff --git a/lib/components/c_utils.js b/lib/components/c_utils.js
index 862c5fa..9487b9c 100644
--- a/lib/components/c_utils.js
+++ b/lib/components/c_utils.js
@@ -1,8 +1,10 @@
'use strict';
var config = require('../config')
- , check = require('../util/check')
- , Match = check.Match;
+ , miloCore = require('milo-core')
+ , check = miloCore.util.check
+ , Match = check.Match
+ , _ = miloCore.proto;
var componentUtils = module.exports = {
diff --git a/lib/components/msg_api/data.js b/lib/components/msg_api/data.js
index 0c6433e..7451ea6 100644
--- a/lib/components/msg_api/data.js
+++ b/lib/components/msg_api/data.js
@@ -1,10 +1,11 @@
'use strict';
-var MessengerAPI = require('../../messenger/m_api')
- , getElementDataAccess = require('./de_data')
- , _ = require('mol-proto')
- , check = require('../../util/check')
+var getElementDataAccess = require('./de_data')
+ , miloCore = require('milo-core')
+ , MessengerAPI = miloCore.classes.MessengerAPI
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
diff --git a/lib/components/msg_api/de_data.js b/lib/components/msg_api/de_data.js
index 5691a70..bca5517 100644
--- a/lib/components/msg_api/de_data.js
+++ b/lib/components/msg_api/de_data.js
@@ -1,7 +1,7 @@
'use strict';
-var _ = require('mol-proto');
+var _ = require('milo-core').proto;
/**
diff --git a/lib/components/msg_api/drop.js b/lib/components/msg_api/drop.js
index ab7a102..7929ab9 100644
--- a/lib/components/msg_api/drop.js
+++ b/lib/components/msg_api/drop.js
@@ -1,7 +1,7 @@
'use strict';
-var MessengerAPI = require('../../messenger/m_api')
+var MessengerAPI = require('milo-core').classes.MessengerAPI;
var DropMsgAPI = _.createSubclass(MessengerAPI, 'DropMsgAPI', true);
diff --git a/lib/components/msg_src/dom_events.js b/lib/components/msg_src/dom_events.js
index b6e6c6f..b40f935 100644
--- a/lib/components/msg_src/dom_events.js
+++ b/lib/components/msg_src/dom_events.js
@@ -2,10 +2,11 @@
var DOMEmitterSource = require('../../services/dom_source')
- , MessageSource = require('../../messenger/m_source')
+ , miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
, Component = require('../c_class')
- , _ = require('mol-proto')
- , check = require('../../util/check')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
var DOMEventsSource = _.createSubclass(DOMEmitterSource, 'DOMEventsSource', true);
diff --git a/lib/components/msg_src/frame.js b/lib/components/msg_src/frame.js
index 264abc5..c1a1752 100644
--- a/lib/components/msg_src/frame.js
+++ b/lib/components/msg_src/frame.js
@@ -2,13 +2,13 @@
// ###component iframe source
-var MessageSource = require('../../messenger/m_source')
- , Component = require('../c_class')
- , _ = require('mol-proto')
- , check = require('../../util/check')
- , logger = require('../../util/logger')
- , Match = check.Match
- , FrameMessageSourceError = require('../../util/error').FrameMessageSource;
+var Component = require('../c_class')
+ , miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , logger = miloCore.util.logger
+ , Match = check.Match;
var FrameMessageSource = _.createSubclass(MessageSource, 'FrameMessageSource', true);
@@ -33,7 +33,7 @@ function init(hostObject, proxyMethods, messengerAPIOrClass, component) {
this.component = component;
if (component.el.tagName.toLowerCase() != 'iframe')
- throw new FrameMessageSourceError('component for FrameMessageSource can only be attached to iframe element');
+ throw new Error('component for FrameMessageSource can only be attached to iframe element');
MessageSource.prototype.init.apply(this, arguments);
}
diff --git a/lib/components/scope.js b/lib/components/scope.js
index 00a49a8..5e1da6c 100644
--- a/lib/components/scope.js
+++ b/lib/components/scope.js
@@ -1,11 +1,11 @@
'use strict';
-var _ = require('mol-proto')
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
, componentName = require('../util/component_name')
- , check = require('../util/check')
+ , check = miloCore.util.check
, Match = check.Match
- , ScopeError = require('../util/error').Scope
- , logger = require('../util/logger');
+ , logger = miloCore.util.logger;
/**
@@ -62,7 +62,7 @@ function Scope$_add(object, name) {
name = object.name;
if (this.hasOwnProperty(name))
- throw new ScopeError('duplicate object name: ' + name);
+ throw new Error('duplicate object name: ' + name);
checkName(name);
__add.call(this, object, name);
@@ -176,7 +176,7 @@ function Scope$_filter(callback, thisArg) {
*/
function checkName(name) {
if (! allowedNamePattern.test(name))
- throw new ScopeError('name should start from letter, this name is not allowed: ' + name);
+ throw new Error('name should start from letter, this name is not allowed: ' + name);
}
diff --git a/lib/components/ui/Button.js b/lib/components/ui/Button.js
index ecf061a..8838f66 100644
--- a/lib/components/ui/Button.js
+++ b/lib/components/ui/Button.js
@@ -1,7 +1,8 @@
'use strict';
var Component = require('../c_class')
- , componentsRegistry = require('../c_registry');
+ , componentsRegistry = require('../c_registry')
+ , _ = require('milo-core').proto;
var MLButton = Component.createComponentClass('MLButton', {
diff --git a/lib/components/ui/Combo.js b/lib/components/ui/Combo.js
index cac2316..7bbfca7 100644
--- a/lib/components/ui/Combo.js
+++ b/lib/components/ui/Combo.js
@@ -2,7 +2,7 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var COMBO_CHANGE_MESSAGE = 'mlcombochange';
diff --git a/lib/components/ui/ComboList.js b/lib/components/ui/ComboList.js
index 15c1a59..0090a62 100644
--- a/lib/components/ui/ComboList.js
+++ b/lib/components/ui/ComboList.js
@@ -2,7 +2,7 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var COMBO_LIST_CHANGE_MESSAGE = 'mlcombolistchange';
diff --git a/lib/components/ui/Date.js b/lib/components/ui/Date.js
index a89ba13..5571ca0 100644
--- a/lib/components/ui/Date.js
+++ b/lib/components/ui/Date.js
@@ -2,7 +2,7 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var MLDate = Component.createComponentClass('MLDate', {
events: undefined,
diff --git a/lib/components/ui/FoldTree.js b/lib/components/ui/FoldTree.js
index 517f903..90c37b0 100644
--- a/lib/components/ui/FoldTree.js
+++ b/lib/components/ui/FoldTree.js
@@ -1,6 +1,6 @@
'use strict';
-var doT = require('dot')
+var doT = require('milo-core').util.doT
, componentsRegistry = require('../c_registry')
, Component = require('../c_class')
, miloCount = require('../../util/count');
diff --git a/lib/components/ui/Image.js b/lib/components/ui/Image.js
index a7fe13d..62615d0 100644
--- a/lib/components/ui/Image.js
+++ b/lib/components/ui/Image.js
@@ -2,7 +2,7 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var IMAGE_CHANGE_MESSAGE = 'mlimagechange';
diff --git a/lib/components/ui/Input.js b/lib/components/ui/Input.js
index ec3460a..4db997d 100644
--- a/lib/components/ui/Input.js
+++ b/lib/components/ui/Input.js
@@ -2,7 +2,7 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var MLInput = Component.createComponentClass('MLInput', {
diff --git a/lib/components/ui/InputList.js b/lib/components/ui/InputList.js
index 914d45b..2eade31 100644
--- a/lib/components/ui/InputList.js
+++ b/lib/components/ui/InputList.js
@@ -2,7 +2,7 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var INPUT_LIST_CHANGE_MESSAGE = 'mlinputlistchange';
diff --git a/lib/components/ui/List.js b/lib/components/ui/List.js
index 4954e89..a754ccd 100644
--- a/lib/components/ui/List.js
+++ b/lib/components/ui/List.js
@@ -2,7 +2,7 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var LIST_CHANGE_MESSAGE = 'mllistchange'
, DELETE_BUTTON_NAME = 'deleteBtn';
diff --git a/lib/components/ui/ListItem.js b/lib/components/ui/ListItem.js
index ec8d5ac..75c527b 100644
--- a/lib/components/ui/ListItem.js
+++ b/lib/components/ui/ListItem.js
@@ -3,7 +3,7 @@
var Component = require('../c_class')
, DragDrop = require('../../util/dragdrop')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var LISTITEM_CHANGE_MESSAGE = 'mllistitemchange'
diff --git a/lib/components/ui/RadioGroup.js b/lib/components/ui/RadioGroup.js
index f86b118..8a68a90 100644
--- a/lib/components/ui/RadioGroup.js
+++ b/lib/components/ui/RadioGroup.js
@@ -3,7 +3,7 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
, miloCount = require('../../util/count')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var RADIO_CHANGE_MESSAGE = 'mlradiogroupchange'
diff --git a/lib/components/ui/Select.js b/lib/components/ui/Select.js
index 1cffd10..4d2b827 100644
--- a/lib/components/ui/Select.js
+++ b/lib/components/ui/Select.js
@@ -2,7 +2,7 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var MLSelect = Component.createComponentClass('MLSelect', {
diff --git a/lib/components/ui/SuperCombo.js b/lib/components/ui/SuperCombo.js
index 054452e..fb15c3a 100644
--- a/lib/components/ui/SuperCombo.js
+++ b/lib/components/ui/SuperCombo.js
@@ -7,9 +7,10 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto')
- , doT = require('dot')
- , logger = require('../../util/logger');
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , doT = miloCore.util.doT
+ , logger = miloCore.util.logger;
var COMBO_OPEN = 'ml-ui-supercombo-open';
var COMBO_CHANGE_MESSAGE = 'mlsupercombochange';
diff --git a/lib/components/ui/Textarea.js b/lib/components/ui/Textarea.js
index de4232e..90afedf 100644
--- a/lib/components/ui/Textarea.js
+++ b/lib/components/ui/Textarea.js
@@ -2,8 +2,9 @@
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto')
- , logger = require('../../util/logger');
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger;
var MLTextarea = Component.createComponentClass('MLTextarea', {
diff --git a/lib/components/ui/Time.js b/lib/components/ui/Time.js
index 85468d3..044d6db 100644
--- a/lib/components/ui/Time.js
+++ b/lib/components/ui/Time.js
@@ -1,7 +1,8 @@
'use strict';
var Component = require('../c_class')
- , componentsRegistry = require('../c_registry');
+ , componentsRegistry = require('../c_registry')
+ , _ = require('milo-core').proto;
var MLTime = Component.createComponentClass('MLTime', {
diff --git a/lib/components/ui/bootstrap/Alert.js b/lib/components/ui/bootstrap/Alert.js
index 0ac35a0..2b304b7 100644
--- a/lib/components/ui/bootstrap/Alert.js
+++ b/lib/components/ui/bootstrap/Alert.js
@@ -3,10 +3,11 @@
var Component = require('../../c_class')
, componentsRegistry = require('../../c_registry')
, componentName = require('../../../util/component_name')
- , logger = require('../../../util/logger')
- , check = require('../../../util/check')
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , check = miloCore.util.check
, Match = check.Match
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
var ALERT_CSS_CLASSES = {
diff --git a/lib/components/ui/bootstrap/Dialog.js b/lib/components/ui/bootstrap/Dialog.js
index 53d0a68..d0489db 100644
--- a/lib/components/ui/bootstrap/Dialog.js
+++ b/lib/components/ui/bootstrap/Dialog.js
@@ -3,10 +3,11 @@
var Component = require('../../c_class')
, componentsRegistry = require('../../c_registry')
, componentName = require('../../../util/component_name')
- , logger = require('../../../util/logger')
- , check = require('../../../util/check')
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , check = miloCore.util.check
, Match = check.Match
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
var DEFAULT_BUTTONS = [ { type: 'default', label: 'OK', result: 'OK' } ];
diff --git a/lib/components/ui/bootstrap/Dropdown.js b/lib/components/ui/bootstrap/Dropdown.js
index 6b4bfd4..118c68d 100644
--- a/lib/components/ui/bootstrap/Dropdown.js
+++ b/lib/components/ui/bootstrap/Dropdown.js
@@ -2,8 +2,9 @@
var Component = require('../../c_class')
, componentsRegistry = require('../../c_registry')
- , _ = require('mol-proto')
- , logger = require('../../../util/logger')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger
, DOMListeners = require('../../../util/dom_listeners');
diff --git a/lib/config.js b/lib/config.js
index 9c9058e..0089e11 100644
--- a/lib/config.js
+++ b/lib/config.js
@@ -18,15 +18,13 @@
// ```
-var _ = require('mol-proto')
- , doT = require('dot');
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , doT = miloCore.util.doT;
-module.exports = config;
+var config = module.exports = miloCore.config;
-function config(options) {
- _.deepExtend(config, options);
-}
config({
attrs: {
@@ -35,9 +33,6 @@ config({
},
componentRef: '___milo_component',
componentPrefix: 'milo_',
- mixin: {
- instancePropertiesMap: '___mixin_instances'
- },
template: {
compile: doT.compile
},
@@ -72,7 +67,5 @@ config({
timeout: 15000,
responsePrefix: 'response_'
}
- },
- check: true,
- debug: false
+ }
});
diff --git a/lib/loader.js b/lib/loader.js
index 5b336c9..5f1c96f 100644
--- a/lib/loader.js
+++ b/lib/loader.js
@@ -3,11 +3,12 @@
var miloMail = require('./services/mail')
, request = require('./util/request')
- , logger = require('./util/logger')
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , _ = miloCore.proto
, utilDom = require('./util/dom')
, config = require('./config')
- , LoadAttribute = require('./attributes/a_load')
- , LoaderError = require('./util/error').Loader;
+ , LoadAttribute = require('./attributes/a_load');
module.exports = loader;
@@ -79,7 +80,7 @@ function _loadViewsInElement(rootEl, removeAttribute, callback) {
function loadView(el, removeAttribute, callback) {
if (utilDom.children(el).length)
- throw new LoaderError('can\'t load html into element that is not empty');
+ throw new Error('can\'t load html into element that is not empty');
var attr = new LoadAttribute(el);
diff --git a/lib/messenger/index.js b/lib/messenger/index.js
deleted file mode 100644
index 55ed027..0000000
--- a/lib/messenger/index.js
+++ /dev/null
@@ -1,665 +0,0 @@
-'use strict';
-
-var Mixin = require('../abstract/mixin')
- // , MessageSource = require('./message_source')
- , MessageSource = require('./m_source')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , MessengerError = require('../util/error').Messenger;
-
-
-/**
- * `milo.Messenger`
- * A generic Messenger class that is used for all kinds of messaging in milo. It is subclassed from [Mixin](../abstract/mixin.js.html) and it proxies its methods to the host object for convenience.
- * All facets and components have messenger attached to them. Messenger class interoperates with [MessageSource](./m_source.js.html) class that connects the messenger to some external source of messages (e.g., DOM events) and [MessengerAPI](./m_api.js.html) class that allows to define higher level messages than messages that exist on the source.
- * Messenger class is used internally in milo and can be used together with any objects/classes in the application.
- * milo also defines a global messenger [milo.mail](../mail/index.js.html) that dispatches `domready` event and can be used for any application wide messaging.
- * To initialize your app after DOM is ready use:
- * ```
- * milo.mail.on('domready', function() {
- * // application starts
- * });
- * ```
- * or the following shorter form of the same:
- * ```
- * milo(function() {
- * // application starts
- * });
- * ```
- */
-var Messenger = _.createSubclass(Mixin, 'Messenger');
-
-var messagesSplitRegExp = Messenger.messagesSplitRegExp = /\s*(?:\,|\s)\s*/;
-
-
-/**
- * ####Messenger instance methods####
- *
- * - [init](#init)
- * - [on](#Messenger$on) (alias - onMessage, deprecated)
- * - [off](#Messenger$off) (alias - offMessage, deprecated)
- * - [onMessages](#onMessages)
- * - [offMessages](#offMessages)
- * - [once](#once)
- * - [onceSync](#onceSync)
- * - [postMessage](#postMessage)
- * - [getSubscribers](#getSubscribers)
- *
- * "Private" methods
- *
- * - [_chooseSubscribersHash](#_chooseSubscribersHash)
- * - [_registerSubscriber](#_registerSubscriber)
- * - [_removeSubscriber](#_removeSubscriber)
- * - [_removeAllSubscribers](#_removeAllSubscribers)
- * - [_callPatternSubscribers](#_callPatternSubscribers)
- * - [_callSubscribers](#_callSubscribers)
- * - [_setMessageSource](#_setMessageSource)
- * - [getMessageSource](#getMessageSource)
- */
-_.extendProto(Messenger, {
- init: init, // called by Mixin (superclass)
- destroy: Messenger$destroy,
- on: Messenger$on,
- once: Messenger$once,
- onceSync: Messenger$onceSync,
- onSync: Messenger$onSync,
- onAsync: Messenger$onAsync,
- onMessage: Messenger$on, // deprecated
- off: Messenger$off,
- offMessage: Messenger$off, // deprecated
- onMessages: onMessages,
- offMessages: offMessages,
- offAll: Messenger$offAll,
- postMessage: postMessage,
- postMessageSync: postMessageSync,
- getSubscribers: getSubscribers,
- getMessageSource: getMessageSource,
- _chooseSubscribersHash: _chooseSubscribersHash,
- _registerSubscriber: _registerSubscriber,
- _removeSubscriber: _removeSubscriber,
- _removeAllSubscribers: _removeAllSubscribers,
- _callPatternSubscribers: _callPatternSubscribers,
- _callSubscribers: _callSubscribers,
- _callSubscriber: _callSubscriber,
- _setMessageSource: _setMessageSource
-});
-
-
-/**
- * A default map of proxy methods used by ComponentFacet and Component classes to pass to Messenger when it is instantiated.
- * This map is for convenience only, it is NOT used internally by Messenger, a host class should pass it for methods to be proxied this way.
- */
-Messenger.defaultMethods = {
- on: 'on',
- onSync: 'onSync',
- once: 'once',
- onceSync: 'onceSync',
- off: 'off',
- onMessages: 'onMessages',
- offMessages: 'offMessages',
- postMessage: 'postMessage',
- postMessageSync: 'postMessageSync',
- getSubscribers: 'getSubscribers'
-};
-
-
-module.exports = Messenger;
-
-
-Messenger.subscriptions = [];
-
-
-/**
- * Messenger instance method
- * Initializes Messenger. Method is called by Mixin class constructor.
- * See [on](#Messenger$on) method, [Messenger](#Messenger) class above and [MessageSource](./m_source.js.html) class.
- *
- * @param {Object} hostObject Optional object that stores the messenger on one of its properties. It is used to proxy methods of messenger and also as a context for subscribers when they are called by the Messenger. See `on` method.
- * @param {Object} proxyMethods Optional map of method names; key - proxy method name, value - messenger's method name.
- * @param {MessageSource} messageSource Optional messageSource linked to the messenger. If messageSource is supplied, the reference to the messenger will stored on its 'messenger' property
- */
-function init(hostObject, proxyMethods, messageSource) {
- // hostObject and proxyMethods are used in Mixin and checked there
- if (messageSource)
- this._setMessageSource(messageSource);
-
- _initializeSubscribers.call(this);
-}
-
-
-function _initializeSubscribers() {
- _.defineProperties(this, {
- _messageSubscribers: {},
- _patternMessageSubscribers: {},
- }, _.CONF);
-}
-
-
-/**
- * Destroys messenger. Maybe needs to unsubscribe all subscribers
- */
-function Messenger$destroy() {
- this.offAll();
- var messageSource = this.getMessageSource();
- if (messageSource)
- messageSource.destroy();
-}
-
-
-/**
- * Messenger instance method.
- * Registers a subscriber function for a certain message(s).
- * This method returns `true` if the subscription was successful. It can be unsuccessful if the passed subscriber has already been subscribed to this message type - double subscription never happens and it is safe to subscribe again - no error or warning is thrown or logged.
- * Subscriber is passed two parameters: `message` (string) and `data` (object). Data object is supplied when message is dispatched, Messenger itself adds nothing to it. For example, [events facet](../components/c_facets/Events.js.html) sends actual DOM event when it posts message.
- * Usage:
- * ```
- * // subscribes onMouseUpDown to two DOM events on component via events facet.
- * myComp.events.on('mousedown mouseup', onMouseUpDown);
- * function onMouseUpDown(eventType, event) {
- * // ...
- * }
- *
- * myComp.data.on(/.+/, function(msg, data) {
- * logger.debug(msg, data);
- * }); // subscribes anonymous function to all non-empty messages on data facet
- * // it will not be possible to unsubscribe anonymous subscriber separately,
- * // but myComp.data.off(/.+/) will unsubscribe it
- * ```
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added, so it can subscribe to the source.
- * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `on` when they proxy it.
- * See [postMessage](#postMessage).
- *
- * @param {String|Array[String]|RegExp} messages Message types that should envoke the subscriber.
- * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.
- * If an array of strings is passed, each string is a message type to subscribe for.
- * If a RegExp is passed, the subscriber will be envoked when the message dispatched on the messenger matches the pattern (or IS the RegExp with identical pattern).
- * Pattern subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.
- * @param {Function|Object} subscriber Message subscriber - a function that will be called when the message is dispatched on the messenger (usually via proxied postMessage method of host object).
- * If hostObject was supplied to Messenger constructor, hostObject will be the context (the value of this) for the subscriber envocation.
- * Subscriber can also be an object with properties `subscriber` (function) and `context` ("this" value when subscriber is called)
- * @return {Boolean}
- */
-function Messenger$on(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber);
-}
-
-
-function Messenger$once(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1 });
-}
-
-function Messenger$onceSync(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1, sync: true });
-}
-
-
-function Messenger$onSync(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: true });
-}
-
-
-function Messenger$onAsync(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: false });
-}
-
-
-function _Messenger_onWithOptions(messages, subscriber, options) {
- check(messages, Match.OneOf(String, [String], RegExp));
- check(subscriber, Match.OneOf(Function, {
- subscriber: Function,
- context: Match.Any,
- options: Match.Optional(Object),
- }));
-
- if (typeof subscriber == 'function') {
- subscriber = {
- subscriber: subscriber,
- context: this._hostObject,
- };
- }
-
- if (options) {
- subscriber.options = subscriber.options || {};
- _.extend(subscriber.options, options);
- }
-
- return _Messenger_on.call(this, messages, subscriber);
-}
-
-
-function _Messenger_on(messages, subscriber) {
- _.defineProperty(subscriber, '__messages', messages);
- return _eachMessage.call(this, '_registerSubscriber', messages, subscriber);
-}
-
-
-function _eachMessage(methodName, messages, subscriber) {
- if (typeof messages == 'string')
- messages = messages.split(messagesSplitRegExp);
-
- var subscribersHash = this._chooseSubscribersHash(messages);
-
- if (messages instanceof RegExp)
- return this[methodName](subscribersHash, messages, subscriber);
-
- else {
- var changed = false;
-
- messages.forEach(function(message) {
- var subscriptionChanged = this[methodName](subscribersHash, message, subscriber);
- changed = changed || subscriptionChanged;
- }, this);
-
- return changed;
- }
-}
-
-
-/**
- * "Private" Messenger instance method
- * It is called by [on](#Messenger$on) to register subscriber for one message type.
- * Returns `true` if this subscriber is not yet registered for this type of message.
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added.
- *
- * @private
- * @param {Object} subscribersHash The map of subscribers determined by [on](#Messenger$on) based on Message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
- * @param {String} message Message type
- * @param {Function|Object} subscriber Subscriber function to be added or object with properties `subscriber` (function) and `context` (value of "this" when subscriber is called)
- * @return {Boolean}
- */
-function _registerSubscriber(subscribersHash, message, subscriber) {
- if (! (subscribersHash[message] && subscribersHash[message].length)) {
- subscribersHash[message] = [];
- if (message instanceof RegExp)
- subscribersHash[message].pattern = message;
- if (this._messageSource)
- this._messageSource.onSubscriberAdded(message);
- var noSubscribers = true;
- }
-
- var msgSubscribers = subscribersHash[message];
- var notYetRegistered = noSubscribers || _indexOfSubscriber.call(this, msgSubscribers, subscriber) == -1;
-
- if (notYetRegistered)
- msgSubscribers.push(subscriber);
-
- return notYetRegistered;
-}
-
-
-/**
- * Finds subscriber index in the list
- *
- * @param {Array[Function|Object]} list list of subscribers
- * @param {Function|Object} subscriber subscriber function or object with properties `subscriber` (function) and `context` ("this" object)
- */
-function _indexOfSubscriber(list, subscriber) {
- var self = this;
- return _.findIndex(list, function(subscr){
- return subscriber.subscriber == subscr.subscriber
- && subscriber.context == subscr.context
- });
-}
-
-
-/**
- * Messenger instance method.
- * Subscribes to multiple messages passed as map together with subscribers.
- * Usage:
- * ```
- * myComp.events.onMessages({
- * 'mousedown': onMouseDown,
- * 'mouseup': onMouseUp
- * });
- * function onMouseDown(eventType, event) {}
- * function onMouseUp(eventType, event) {}
- * ```
- * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was added.
- * It is NOT possible to add pattern subscriber using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.
- *
- * @param {Object[Function]} messageSubscribers Map of message subscribers to be added
- * @return {Object[Boolean]}
- */
-function onMessages(messageSubscribers) {
- check(messageSubscribers, Match.ObjectHash(Match.OneOf(Function, { subscriber: Function, context: Match.Any })));
-
- var notYetRegisteredMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {
- return this.on(messages, subscriber);
- }, this);
-
- return notYetRegisteredMap;
-}
-
-
-/**
- * Messenger instance method.
- * Removes a subscriber for message(s). Removes all subscribers for the message if subscriber isn't passed.
- * This method returns `true` if the subscriber was registered. No error or warning is thrown or logged if you remove subscriber that was not registered.
- * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `off` when they proxy it.
- * Usage:
- * ```
- * // unsubscribes onMouseUpDown from two DOM events.
- * myComp.events.off('mousedown mouseup', onMouseUpDown);
- * ```
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.
- *
- * @param {String|Array[String]|RegExp} messages Message types that a subscriber should be removed for.
- * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.
- * If an array of strings is passed, each string is a message type to remove a subscriber for.
- * If a RegExp is passed, the pattern subscriber will be removed.
- * RegExp subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.
- * @param {Function} subscriber Message subscriber - Optional function that will be removed from the list of subscribers for the message(s). If subscriber is not supplied, all subscribers will be removed from this message(s).
- * @return {Boolean}
- */
-function Messenger$off(messages, subscriber) {
- check(messages, Match.OneOf(String, [String], RegExp));
- check(subscriber, Match.Optional(Match.OneOf(Function, {
- subscriber: Function,
- context: Match.Any,
- options: Match.Optional(Object),
- // __messages: Match.Optional(Match.OneOf(String, [String], RegExp))
- })));
-
- return _Messenger_off.call(this, messages, subscriber);
-}
-
-
-function _Messenger_off(messages, subscriber) {
- return _eachMessage.call(this, '_removeSubscriber', messages, subscriber);
-}
-
-
-/**
- * "Private" Messenger instance method
- * It is called by [off](#Messenger$off) to remove subscriber for one message type.
- * Returns `true` if this subscriber was registered for this type of message.
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.
- *
- * @private
- * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
- * @param {String} message Message type
- * @param {Function} subscriber Subscriber function to be removed
- * @return {Boolean}
- */
-function _removeSubscriber(subscribersHash, message, subscriber) {
- var msgSubscribers = subscribersHash[message];
- if (! msgSubscribers || ! msgSubscribers.length)
- return false; // nothing removed
-
- if (subscriber) {
- if (typeof subscriber == 'function')
- subscriber = { subscriber: subscriber, context: this._hostObject };
-
- var subscriberIndex = _indexOfSubscriber.call(this, msgSubscribers, subscriber);
- if (subscriberIndex == -1)
- return false; // nothing removed
- msgSubscribers.splice(subscriberIndex, 1);
- if (! msgSubscribers.length)
- this._removeAllSubscribers(subscribersHash, message);
-
- } else
- this._removeAllSubscribers(subscribersHash, message);
-
- return true; // subscriber(s) removed
-}
-
-
-/**
- * "Private" Messenger instance method
- * It is called by [_removeSubscriber](#_removeSubscriber) to remove all subscribers for one message type.
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified that all message subscribers were removed so it can unsubscribe from the source.
- *
- * @private
- * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
- * @param {String} message Message type
- */
-function _removeAllSubscribers(subscribersHash, message) {
- delete subscribersHash[message];
- if (this._messageSource && typeof message == 'string')
- this._messageSource.onSubscriberRemoved(message);
-}
-
-
-/**
- * Messenger instance method.
- * Unsubscribes from multiple messages passed as map together with subscribers.
- * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was removed.
- * If a subscriber for one of the messages is not supplied, all subscribers for this message will be removed.
- * Usage:
- * ```
- * myComp.events.offMessages({
- * 'mousedown': onMouseDown,
- * 'mouseup': onMouseUp,
- * 'click': undefined // all subscribers to this message will be removed
- * });
- * ```
- * It is NOT possible to remove pattern subscriber(s) using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.
- *
- * @param {Object[Function]} messageSubscribers Map of message subscribers to be removed
- * @return {Object[Boolean]}
- */
-function offMessages(messageSubscribers) {
- check(messageSubscribers, Match.ObjectHash(Match.Optional(Match.OneOf(Function, { subscriber: Function, context: Match.Any }))));
-
- var subscriberRemovedMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {
- return this.off(messages, subscriber);
- }, this);
-
- return subscriberRemovedMap;
-}
-
-
-/**
- * Unsubscribes all subscribers
- */
-function Messenger$offAll() {
- _offAllSubscribers.call(this, this._patternMessageSubscribers);
- _offAllSubscribers.call(this, this._messageSubscribers);
-}
-
-
-function _offAllSubscribers(subscribersHash) {
- _.eachKey(subscribersHash, function(subscribers, message) {
- this._removeAllSubscribers(subscribersHash, message);
- }, this);
-}
-
-
-// TODO - send event to messageSource
-
-
-/**
- * Messenger instance method.
- * Dispatches the message calling all subscribers registered for this message and, if the message is a string, calling all pattern subscribers when message matches the pattern.
- * Each subscriber is passed the same parameters that are passed to theis method.
- * The context of the subscriber envocation is set to the host object (`this._hostObject`) that was passed to the messenger constructor.
- * Subscribers are called in the next tick ("asynchronously") apart from those that were subscribed with `onSync` (or that have `options.sync == true`).
- *
- * @param {String|RegExp} message message to be dispatched
- * If the message is a string, the subscribers registered with exactly this message will be called and also pattern subscribers registered with the pattern that matches the dispatched message.
- * If the message is RegExp, only the subscribers registered with exactly this pattern will be called.
- * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
- * @param {Function} callback optional callback to pass to subscriber
- * @param {Boolean} _synchronous if true passed, subscribers will be envoked synchronously apart from those that have `options.sync == false`. This parameter should not be used, instead postMessageSync should be used.
- */
-function postMessage(message, data, callback, _synchronous) {
- check(message, Match.OneOf(String, RegExp));
- check(callback, Match.Optional(Function));
-
- var subscribersHash = this._chooseSubscribersHash(message);
- var msgSubscribers = subscribersHash[message];
-
- this._callSubscribers(message, data, callback, msgSubscribers, _synchronous);
-
- if (typeof message == 'string')
- this._callPatternSubscribers(message, data, callback, msgSubscribers, _synchronous);
-}
-
-
-/**
- * Same as postMessage apart from envoking subscribers synchronously, apart from those subscribed with `onAsync` (or with `options.sync == false`).
- *
- * @param {String|RegExp} message
- * @param {Any} data
- * @param {Function} callback
- */
-function postMessageSync(message, data, callback) {
- this.postMessage(message, data, callback, true);
-}
-
-
-/**
- * "Private" Messenger instance method
- * Envokes pattern subscribers with the pattern that matches the message.
- * The method is called by [postMessage](#postMessage) - see more information there.
- *
- * @private
- * @param {String} message message to be dispatched. Pattern subscribers registered with the pattern that matches the dispatched message will be called.
- * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
- * @param {Function} callback optional callback to pass to subscriber
- * @param {Array[Function|Object]} calledMsgSubscribers array of subscribers already called, they won't be called again if they are among pattern subscribers.
- */
-function _callPatternSubscribers(message, data, callback, calledMsgSubscribers, _synchronous) {
- _.eachKey(this._patternMessageSubscribers,
- function(patternSubscribers) {
- var pattern = patternSubscribers.pattern;
- if (pattern.test(message)) {
- if (calledMsgSubscribers) {
- var patternSubscribers = patternSubscribers.filter(function(subscriber) {
- var index = _indexOfSubscriber.call(this, calledMsgSubscribers, subscriber);
- return index == -1;
- });
- }
- this._callSubscribers(message, data, callback, patternSubscribers, _synchronous);
- }
- }
- , this);
-}
-
-
-/**
- * "Private" Messenger instance method
- * Envokes subscribers from the passed list.
- * The method is called by [postMessage](#postMessage) and [_callPatternSubscribers](#_callPatternSubscribers).
- *
- * @private
- * @param {String} message message to be dispatched, passed to subscribers as the first parameter.
- * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
- * @param {Array[Function|Object]} msgSubscribers the array of message subscribers to be called. Each subscriber is called with the host object (see Messenger constructor) as the context.
- * @param {Function} callback optional callback to pass to subscriber
- */
-function _callSubscribers(message, data, callback, msgSubscribers, _synchronous) {
- if (msgSubscribers && msgSubscribers.length) {
- // cloning is necessary as some of the subscribers
- // can be unsubscribed during the dispatch
- // so this array would change in the process
- msgSubscribers = msgSubscribers.slice();
-
- msgSubscribers.forEach(function(subscriber) {
- this._callSubscriber(subscriber, message, data, callback, _synchronous);
- }, this);
- }
-}
-
-
-function _callSubscriber(subscriber, message, data, callback, _synchronous) {
- var syncSubscriber = subscriber.options && subscriber.options.sync
- , synchro = (_synchronous && syncSubscriber !== false)
- || syncSubscriber;
-
- var dispatchTimes = subscriber.options && subscriber.options.dispatchTimes;
- if (dispatchTimes) {
- if (dispatchTimes <= 1) {
- var messages = subscriber.__messages;
- this.off(messages, subscriber);
- } else if (dispatchTimes > 1)
- subscriber.options.dispatchTimes--;
- }
-
- if (synchro)
- subscriber.subscriber.call(subscriber.context, message, data, callback);
- else
- _.deferMethod(subscriber.subscriber, 'call', subscriber.context, message, data, callback);
-}
-
-
-/**
- * Messenger instance method.
- * Returns the array of subscribers that would be called if the message were dispatched.
- * If `includePatternSubscribers === false`, pattern subscribers with matching patters will not be included (by default they are included).
- * If there are no subscribers to the message, `undefined` will be returned, not an empty array, so it is safe to use the result in boolean tests.
- *
- * @param {String|RegExp} message Message to get subscribers for.
- * If the message is RegExp, only pattern subscribers registered with exactly this pattern will be returned.
- * If the message is String, subscribers registered with the string messages and pattern subscribers registered with matching pattern will be returned (unless the second parameter is false).
- * @param {Boolean} includePatternSubscribers Optional false to prevent inclusion of patter subscribers, by default they are included.
- * @return {Array|undefined}
- */
-function getSubscribers(message, includePatternSubscribers) {
- check(message, Match.OneOf(String, RegExp));
-
- var subscribersHash = this._chooseSubscribersHash(message);
- var msgSubscribers = subscribersHash[message]
- ? [].concat(subscribersHash[message])
- : [];
-
- // pattern subscribers are incuded by default
- if (includePatternSubscribers !== false && typeof message == 'string') {
- _.eachKey(this._patternMessageSubscribers,
- function(patternSubscribers) {
- var pattern = patternSubscribers.pattern;
- if (patternSubscribers && patternSubscribers.length
- && pattern.test(message))
- _.appendArray(msgSubscribers, patternSubscribers);
- }
- );
- }
-
- // return undefined if there are no subscribers
- return msgSubscribers.length
- ? msgSubscribers
- : undefined;
-}
-
-
-/**
- * "Private" Messenger instance method
- * Returns the map of subscribers for a given message type.
- *
- * @private
- * @param {String|RegExp} message Message to choose the map of subscribers for
- * @return {Object[Function]}
- */
-function _chooseSubscribersHash(message) {
- return message instanceof RegExp
- ? this._patternMessageSubscribers
- : this._messageSubscribers;
-}
-
-
-/**
- * Messenger instance method
- * Sets [MessageSource](./m_source.js.html) for the messenger also setting the reference to the messenger in the MessageSource.
- * MessageSource can be passed to message constructor; this method allows to set it at a later time. For example, the subclasses of [ComponentFacet](../components/c_facet.js.html) use this method to set different MessageSource'es in the messenger that is created by ComponentFacet.
- * Currently the method is implemented in such way that it can be called only once - MessageSource cannot be changed after this method is called.
- *
- * @param {MessageSource} messageSource an instance of MessageSource class to attach to this messenger (and to have this messenger attached to it too)
- */
-function _setMessageSource(messageSource) {
- check(messageSource, MessageSource);
-
- _.defineProperty(this, '_messageSource', messageSource);
- messageSource.messenger = this;
-}
-
-
-/**
- * Messenger instance method
- * Returns messenger MessageSource
- *
- * @return {MessageSource}
- */
-function getMessageSource() {
- return this._messageSource
-}
diff --git a/lib/messenger/m_api.js b/lib/messenger/m_api.js
deleted file mode 100644
index 69c6dbf..0000000
--- a/lib/messenger/m_api.js
+++ /dev/null
@@ -1,191 +0,0 @@
-'use strict';
-
-var _ = require('mol-proto')
- , logger = require('../util/logger');
-
-
-module.exports = MessengerAPI;
-
-
-/**
- * `milo.classes.MessengerAPI`
- * Base class, subclasses of which can supplement the functionality of [MessageSource](./m_source.js.html) by implementing three methods:
- *
- * - `translateToSourceMessage` to translate source messages (recieved from external source via `MessageSOurce`) to internal messages (that are dispatched on Messenger), allowing to make internal messages more detailed than source messages. For example, [Data facet](../components/c_facets/Data.js.html) uses [DataMsgAPI](../components/msg_api/data.js.html) to define several internal messages related to the change of state in contenteditable DOM element.
- * - `createInternalData` to modify message data received from source to some more meaningful or more detailed message data that will be dispatched on Messenger. For example, [Data facet](../components/c_facets/Data.js.html) uses [DataMsgAPI](../components/msg_api/data.js.html) (subclass of MessengerAPI) to translate DOM messages to data change messages.
- * - `filterSourceMessage` to enable/disable message dispatch based on some conditions in data.
- *
- * If `MessageSource` constructor is not passed an instance of some subclass of `MessengerAPI`, it automatically creates an instance of MessengerAPI that defines all 3 of those methods in a trivial way. See these methods below for their signatures.
- *
- * @constructor
- * @this {MessengerAPI}
- * @return {MessengerAPI}
- */
-function MessengerAPI() {
- if (this.init)
- this.init.apply(this, arguments);
-}
-
-
-/**
- * ####MessengerAPI instance methods####
- *
- * - [init](#init) - initializes MessengerAPI
- * - [addInternalMessage](#addInternalMessage) - adds internal message
- * - [removeInternalMessage](#removeInternalMessage) - removes internal message
- * - [getInternalMessages](#getInternalMessages) - returns the list of internal messages for given source message
- *
- * These methods should be redefined by subclass:
- *
- * - [translateToSourceMessage](#translateToSourceMessage) - converts internal message type to source (external) message type
- * - [createInternalData](#createInternalData) - converts source message data received via MessageSource to internal message data
- * - [filterSourceMessage](#filterSourceMessage) - filters source message based on the data of the message and the corresponding internal message that is about to be sent on Messenger
- */
-_.extendProto(MessengerAPI, {
- init: init,
- destroy: MessengerAPI$destroy,
- addInternalMessage: addInternalMessage,
- removeInternalMessage: removeInternalMessage,
- getInternalMessages: getInternalMessages,
-
- // should be redefined by subclass
- translateToSourceMessage: translateToSourceMessage,
- createInternalData: createInternalData,
- filterSourceMessage: filterSourceMessage
-});
-
-
-/**
- * MessengerAPI instance method
- * Called by MessengerAPI constructor. Subclasses that re-implement `init` method should call this method using: `MessengerAPI.prototype.init.apply(this, arguments)`
- */
-function init() {
- _.defineProperty(this, '_internalMessages', {});
-}
-
-
-/**
- * Destroys messenger API
- */
-function MessengerAPI$destroy() {
-
-}
-
-
-/**
- * MessengerAPI instance method
- * Translates internal `message` to source message, adds internal `message` to the list, making sure the same `message` wasn't passed before (it would indicate Messenger error).
- * Returns source message if it is used first time (so that `MessageSource` subcribes to this source message) or `undefined`.
- *
- * @param {String} message internal message to be translated and added
- * @return {String|undefined}
- */
-function addInternalMessage(message) {
- var internalMsgs
- , sourceMessage = this.translateToSourceMessage(message);
-
- if (typeof sourceMessage == 'undefined') return;
-
- if (this._internalMessages.hasOwnProperty(sourceMessage)) {
- internalMsgs = this._internalMessages[sourceMessage];
- if (internalMsgs.indexOf(message) == -1)
- internalMsgs.push(message);
- else
- logger.warn('Duplicate addInternalMessage call for internal message ' + message);
- } else {
- internalMsgs = this._internalMessages[sourceMessage] = [];
- internalMsgs.push(message);
- return sourceMessage;
- }
-}
-
-
-/**
- * MessengerAPI instance method
- * Removes internal `message` from the list connected to corresponding source message (`translateToSourceMessage` is used for translation).
- * Returns source message, if the last internal message was removed (so that `MessageSource` can unsubscribe from this source message), or `undefined`.
- *
- * @param {String} message internal message to be translated and removed
- * @return {String|undefined}
- */
-function removeInternalMessage(message) {
- var sourceMessage = this.translateToSourceMessage(message);
-
- if (typeof sourceMessage == 'undefined') return;
-
- var internalMsgs = this._internalMessages[sourceMessage];
-
- if (internalMsgs && internalMsgs.length) {
- var messageIndex = internalMsgs.indexOf(message);
- if (messageIndex >= 0) {
- internalMsgs.splice(messageIndex, 1);
- if (internalMsgs.length == 0) {
- delete this._internalMessages[sourceMessage];
- return sourceMessage;
- }
- } else
- unexpectedNotificationWarning();
- } else
- unexpectedNotificationWarning();
-
-
- function unexpectedNotificationWarning() {
- logger.warn('notification received: un-subscribe from internal message ' + message
- + ' without previous subscription notification');
- }
-}
-
-
-/**
- * MessengerAPI instance method
- * Returns the array of internal messages that were translated to given `sourceMessage`.
- * This method is used by `MessageSource` to dispatch source message on the `Mesenger`.
- *
- * @param {String} sourceMessage source message
- * @return {Array[String]}
- */
-function getInternalMessages(sourceMessage) {
- return this._internalMessages[sourceMessage];
-}
-
-
-/**
- * MessengerAPI instance method
- * Subclasses should re-implement this method to define the rule for translation of internal `message` to source message. This class simply returns the same `message`.
- *
- * @param {String} message internal message to be translated
- * @return {String}
- */
-function translateToSourceMessage(message) {
- return message
-}
-
-
-/**
- * MessengerAPI instance method
- * Subclasses should re-implement this method to define the rule for translation of source message data to internal message data. This class simply returns the same `sourceData`.
- * This method is used in [dispatchMessage](./m_source.js.html#dispatchMessage) method of `MessageSource`.
- *
- * @param {String} sourceMessage source message, can be used in translation rule
- * @param {String} message internal message, can be used in translation rule
- * @param {Object} sourceData data received from source that has to be translated to data that will be sent to internal Messenger subscriber
- * @return {Object}
- */
-function createInternalData(sourceMessage, message, sourceData) {
- return sourceData;
-}
-
-
-/**
- * MessengerAPI instance method
- * Subclasses should re-implement this method to define the dispatch filter for internal messages. This method should return `true` to allow and `false` to prevent internal message dispatch. This class always returns `true`.
- * This method is used in [dispatchMessage](./m_source.js.html#dispatchMessage) method of `MessageSource`.
- *
- * @param {String} sourceMessage source message, can be used in filter rule
- * @param {String} message internal message, can be used in filter rule
- * @param {Object} internalData data translated by `createInternalData` method from source data, can be used in filter rule
- * @return {Boolean}
- */
-function filterSourceMessage(sourceMessage, message, internalData) {
- return true;
-}
diff --git a/lib/messenger/m_api_rx.js b/lib/messenger/m_api_rx.js
deleted file mode 100644
index 281b347..0000000
--- a/lib/messenger/m_api_rx.js
+++ /dev/null
@@ -1,112 +0,0 @@
-'use strict';
-
-var MessengerAPI = require('./m_api')
- , _ = require('mol-proto');
-
-
-/**
- * A generic subsclass of [MessengerAPI](./m_api.js.html) that supports pattern subscriptions to source.
- * Can be useful if the source is another Messenger.
- */
- var MessengerRegexpAPI = _.createSubclass(MessengerAPI, 'MessengerRegexpAPI');
-
- module.exports = MessengerRegexpAPI;
-
-
-_.extendProto(MessengerRegexpAPI, {
- init: init,
- addInternalMessage: addInternalMessage,
- removeInternalMessage: removeInternalMessage,
- getInternalMessages: getInternalMessages
-});
-
-
-/**
- * MessengerRegexpAPI instance method
- * Called by MessengerRegexpAPI constructor.
- */
-function init() {
- MessengerAPI.prototype.init.apply(this, arguments);
- _.defineProperties(this, {
- _patternInternalMessages: {}
- });
- this._catchAllSubscribed = false;
-}
-
-
-/**
- * MessengerRegexpAPI instance method
- * Augments MessengerAPI method by storing regexp
- *
- * @param {String} message internal message to be translated and added
- * @return {String|RegExp|undefined}
- */
-function addInternalMessage(message) {
- var sourceMessage = MessengerAPI.prototype.addInternalMessage.apply(this, arguments);
-
- // store regexp itself if sourceMessage is regexp
- if (sourceMessage && sourceMessage instanceof RegExp) {
- this._internalMessages[sourceMessage].pattern = sourceMessage;
- this._patternInternalMessages[sourceMessage] = this._internalMessages[sourceMessage];
- if (this._catchAllSubscribed) return;
- this._catchAllSubscribed = true;
- return /.*/;
- }
-
- return sourceMessage;
-}
-
-
-/**
- * MessengerRegexpAPI instance method
- * Augments MessengerAPI method by removing regexp subscirption
- *
- * @param {String} message internal message to be translated and added
- * @return {String|RegExp|undefined}
- */
-function removeInternalMessage(message) {
- var sourceMessage = MessengerAPI.prototype.removeInternalMessage.apply(this, arguments);
-
- if (sourceMessage && sourceMessage instanceof RegExp) {
- delete this._patternInternalMessages[sourceMessage];
- var noPatternInternalMessages = ! Object.keys(this._patternInternalMessages).length;
- if (noPatternInternalMessages) {
- this._catchAllSubscribed = false;
- return /.*/;
- }
- }
-
- return sourceMessage;
-}
-
-
-/**
- * MessengerAPI instance method
- * Augments MessengerAPI method by returning messages subscribed with regexp
- * This method is used by `MessageSource` to dispatch source message on the `Mesenger`.
- *
- * @param {String|RegExp} sourceMessage source message
- * @return {Array[String]}
- */
-function getInternalMessages(sourceMessage) {
- var internalMessages = MessengerAPI.prototype.getInternalMessages.apply(this, arguments);
-
- // add internal messages for regexp source subscriptions
- if (typeof sourceMessage == 'string') {
- internalMessages = internalMessages || [];
- var internalMessagesHash = _.object(internalMessages, true);
-
- _.eachKey(this._patternInternalMessages, function(patternMessages) {
- var sourcePattern = patternMessages.pattern;
-
- if (sourcePattern.test(sourceMessage))
- patternMessages.forEach(function(message) {
- if (internalMessagesHash[message]) return;
- internalMessages.push(message);
- internalMessagesHash[message] = true;
- });
- });
- }
-
- return internalMessages;
-}
diff --git a/lib/messenger/m_source.js b/lib/messenger/m_source.js
deleted file mode 100644
index c99b429..0000000
--- a/lib/messenger/m_source.js
+++ /dev/null
@@ -1,170 +0,0 @@
-'use strict';
-
-var Mixin = require('../abstract/mixin')
- , MessengerAPI = require('./m_api')
- , logger = require('../util/logger')
- , toBeImplemented = require('../util/error').toBeImplemented
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match;
-
-
-/**
- * `milo.classes.MessageSource`
- * An abstract class (subclass of [Mixin](../abstract/mixin.js.html)) for connecting [Messenger](./index.js.html) to external sources of messages (like DOM events) and defining higher level messages.
- * An instance of MessageSource can either be passed to Messenger constructor or later using `_setMessageSource` method of Messenger. Once set, MessageSource of Messenger cannot be changed.
- */
-var MessageSource = _.createSubclass(Mixin, 'MessageSource', true);
-
-module.exports = MessageSource;
-
-
-/**
- * ####MessageSource instance methods####
- *
- * - [init](#init) - initializes messageSource - called by Mixin superclass
- * - [setMessenger](#setMessenger) - connects Messenger to MessageSource, is called from `init` or `_setMessageSource` methods of [Messenger](./index.js.html).
- * - [onSubscriberAdded](#onSubscriberAdded) - called by Messenger to notify when the first subscriber for an internal message was added, so MessageSource can subscribe to source
- * - [onSubscriberRemoved](#onSubscriberRemoved) - called by Messenger to notify when the last subscriber for an internal message was removed, so MessageSource can unsubscribe from source
- * - [dispatchMessage](#dispatchMessage) - dispatches source message. MessageSource subclass should implement mechanism when on actual source message this method is called.
- *
- * Methods below should be implemented in subclass:
- *
- * - [trigger](#trigger) - triggers messages on the source (an optional method)
- * - [addSourceSubscriber](#addSourceSubscriber) - adds listener/subscriber to external message
- * - [removeSourceSubscriber](#removeSourceSubscriber) - removes listener/subscriber from external message
- */
-_.extendProto(MessageSource, {
- init: init,
- destroy: MessageSource$destroy,
- setMessenger: setMessenger,
- onSubscriberAdded: onSubscriberAdded,
- onSubscriberRemoved: onSubscriberRemoved,
- dispatchMessage: dispatchMessage,
- postMessage: postMessage,
- _prepareMessengerAPI: _prepareMessengerAPI,
-
- // Methods below must be implemented in subclass
- trigger: toBeImplemented,
- addSourceSubscriber: toBeImplemented,
- removeSourceSubscriber: toBeImplemented
-});
-
-
-/**
- * MessageSource instance method.
- * Called by Mixin constructor.
- * MessageSource constructor should be passed the same parameters as this method signature.
- * If an instance of [MessengerAPI](./m_api.js.html) is passed as the third parameter, it extends MessageSource functionality to allow it to define new messages, to filter messages based on their data and to change message data. See [MessengerAPI](./m_api.js.html).
- *
- * @param {Object} hostObject Optional object that stores the MessageSource on one of its properties. It is used to proxy methods of MessageSource.
- * @param {Object[String]} proxyMethods Optional map of method names; key - proxy method name, value - MessageSource's method name.
- * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI.
- */
-function init(hostObject, proxyMethods, messengerAPI) {
- this._prepareMessengerAPI(messengerAPI);
-}
-
-
-/**
- * Destroys message source
- */
-function MessageSource$destroy() {
- if (this.messengerAPI)
- this.messengerAPI.destroy();
-}
-
-
-/**
- * MessageSource instance method.
- * Sets reference to Messenger instance.
- *
- * @param {Messenger} messenger reference to Messenger instance linked to this MessageSource
- */
-function setMessenger(messenger) {
- _.defineProperty(this, 'messenger', messenger);
-}
-
-
-/**
- * MessageSource instance method.
- * Prepares [MessengerAPI](./m_api.js.html) passed to constructor by proxying its methods to itself or if MessengerAPI wasn't passed defines two methods to avoid checking their availability every time the message is dispatched.
- *
- * @private
- * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI
- */
-function _prepareMessengerAPI(messengerAPI) {
- check(messengerAPI, Match.Optional(MessengerAPI));
-
- if (! messengerAPI)
- messengerAPI = new MessengerAPI;
-
- _.defineProperty(this, 'messengerAPI', messengerAPI);
-}
-
-
-/**
- * MessageSource instance method.
- * Subscribes to external source using `addSourceSubscriber` method that should be implemented in subclass.
- * This method is called by [Messenger](./index.js.html) when the first subscriber to the `message` is added.
- * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.addInternalMessage` will return undefined if this `sourceMessage` was already subscribed to to prevent duplicate subscription.
- *
- * @param {String} message internal Messenger message that has to be subscribed to at the external source of messages.
- */
-function onSubscriberAdded(message) {
- var newSourceMessage = this.messengerAPI.addInternalMessage(message);
- if (typeof newSourceMessage != 'undefined')
- this.addSourceSubscriber(newSourceMessage);
-}
-
-
-/**
- * MessageSource instance method.
- * Unsubscribes from external source using `removeSourceSubscriber` method that should be implemented in subclass.
- * This method is called by [Messenger](./index.js.html) when the last subscriber to the `message` is removed.
- * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.removeInternalMessage` will return undefined if this `sourceMessage` was not yet subscribed to to prevent unsubscription without previous subscription.
- *
- * @param {String} message internal Messenger message that has to be unsubscribed from at the external source of messages.
- */
-function onSubscriberRemoved(message) {
- var removedSourceMessage = this.messengerAPI.removeInternalMessage(message);
- if (typeof removedSourceMessage != 'undefined')
- this.removeSourceSubscriber(removedSourceMessage);
-}
-
-
-/**
- * MessageSource instance method.
- * Dispatches sourceMessage to Messenger.
- * Mechanism that calls this method when the source message is received should be implemented by subclass (see [DOMEventsSource](../components/msg_src/dom_events.js.html) for example).
- * Delegates to supplied or default [MessengerAPI](./m_api.js.html) to create internal message data (`createInternalData`) and to filter the message based on its data and/or message (`filterSourceMessage`).
- * Base MessengerAPI class implements these two methods in a trivial way (`createInternalData` simply returns external data, `filterSourceMessage` returns `true`), they are meant to be implemented by subclass.
- *
- * @param {String} sourceMessage source message received from external source
- * @param {Object} sourceData data received from external source
- */
-function dispatchMessage(sourceMessage, sourceData) {
- var api = this.messengerAPI
- , internalMessages = api.getInternalMessages(sourceMessage);
-
- if (internalMessages)
- internalMessages.forEach(function (message) {
- var internalData = api.createInternalData(sourceMessage, message, sourceData);
-
- var shouldDispatch = api.filterSourceMessage(sourceMessage, message, internalData);
- if (shouldDispatch)
- this.postMessage(message, internalData);
-
- }, this);
-}
-
-
-/**
- * Posts message on the messenger. This method is separated so specific message sources can make message dispatch synchronous by using `postMessageSync`
- *
- * @param {String} message
- * @param {Object} data
- */
-function postMessage(message, data) {
- this.messenger.postMessage(message, data);
-}
diff --git a/lib/messenger/msngr_source.js b/lib/messenger/msngr_source.js
deleted file mode 100644
index 8fbcbfb..0000000
--- a/lib/messenger/msngr_source.js
+++ /dev/null
@@ -1,67 +0,0 @@
-'use strict';
-
-
-var MessageSource = require('./m_source')
- , _ = require('mol-proto')
- , check = require('../util/check');
-
-
-/**
- * Subclass of MessageSource that allows to connect Messenger to another Messenger using it as external source.
- */
-var MessengerMessageSource = _.createSubclass(MessageSource, 'MessengerMessageSource');
-
-module.exports = MessengerMessageSource;
-
-
-/**
- * ####MessengerMessageSource instance methods####
- */
-_.extendProto(MessengerMessageSource, {
- init: init,
- addSourceSubscriber: addSourceSubscriber,
- removeSourceSubscriber: removeSourceSubscriber,
- postMessage: MessengerMessageSource$postMessage
-});
-
-/**
- * Initializes MessengerMessageSource
- * Defines one parameter in addition to [MessageSource](./m_source.js.html) parameters
- *
- * @param {Messenger} sourceMessenger messenger this message source connects to
- */
-function init(hostObject, proxyMethods, messengerAPI, sourceMessenger) {
- MessageSource.prototype.init.apply(this, arguments);
- this.sourceMessenger = sourceMessenger;
-}
-
-
-/**
- * Subscribes to source message. See [MessageSource](./m_source.js.html) docs.
- *
- * @param {String|Regex} sourceMessage source message to subscribe to
- */
-function addSourceSubscriber(sourceMessage) {
- this.sourceMessenger.onSync(sourceMessage, { context: this, subscriber: this.dispatchMessage });
-}
-
-
-/**
- * Unsubscribes from source message. See [MessageSource](./m_source.js.html) docs.
- *
- * @param {String|Regex} sourceMessage source message to unsubscribe from
- */
-function removeSourceSubscriber(sourceMessage) {
- this.sourceMessenger.off(sourceMessage, { context: this, subscriber: this.dispatchMessage });
-}
-
-
-/**
- * Overrides defalut message source to dispatch messages synchronously
- *
- * @param {String} message
- * @param {Object} data
- */
-function MessengerMessageSource$postMessage(message, data) {
- this.messenger.postMessageSync(message, data);
-}
diff --git a/lib/milo.js b/lib/milo.js
index 9edd4c0..7115ff7 100644
--- a/lib/milo.js
+++ b/lib/milo.js
@@ -1,7 +1,7 @@
'use strict';
-var core = require('milo-core');
-var _ = require('mol-proto');
+var miloCore = require('milo-core')
+ , _ = miloCore.proto;
// register included facets
@@ -48,9 +48,9 @@ function milo(func) {
* - [registry](./registry.js.html) - registries of fasets and components classes
*/
_.extend(milo, {
- Messenger: core.Messenger,
- Model: core.Model,
- minder: core.minder,
+ Messenger: miloCore.Messenger,
+ Model: miloCore.Model,
+ minder: miloCore.minder,
loader: require('./loader'),
binder: require('./binder'),
mail: require('./services/mail'),
@@ -63,7 +63,7 @@ _.extend(milo, {
Component: require('./components/c_class'),
Command: require('./command'),
registry: require('./registry'),
- milo_version: '0.1.4',
+ milo_version: '0.1.10',
createComponentClass: require('./util/create_component_class'),
destroy: destroy
});
@@ -81,8 +81,8 @@ if (typeof window == 'object') {
function destroy() {
+ miloCore.destroy();
milo.mail.destroy();
milo.window.destroy();
- milo.minder.destroy();
milo.util.destroy();
}
diff --git a/lib/minder.js b/lib/minder.js
deleted file mode 100644
index c9275af..0000000
--- a/lib/minder.js
+++ /dev/null
@@ -1,218 +0,0 @@
-'use strict';
-
-var Connector = require('./model/connector')
- , Messenger = require('./messenger')
- , _ = require('mol-proto')
- , logger = require('./util/logger');
-
-
-module.exports = minder;
-
-
-/**
- * This function creates one or many Connector objects that
- * create live reactive connection between objects implementing
- * dataSource interface:
- * Objects should emit messages when any part of their data changes,
- * methods `on` and `off` should be implemented to subscribe/unsubscribe
- * to change notification messages, methods `set` and `get` should be implemented to get/set data
- * on path objects, pointing to particular parts of the object, method `path`
- * should return path object for a given path string (see path utils for path string syntax).
- * Both Model and Data facet are such data sources, they can be linked by Connector object.
- *
- * @param {Object} ds1 the first data source. Instead of the first data source an array can be passed with arrays of Connection objects parameters in each array element.
- * @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
- * @param {Object} ds2 the second data source
- * @param {Object} options not implemented yet
- */
-function minder(ds1, mode, ds2, options) {
- if (Array.isArray(ds1)) {
- var connDescriptions = ds1;
- var connectors = connDescriptions.map(function(descr) {
- return new Connector(descr[0], descr[1], descr[2], descr[3]);
- });
- connectors.forEach(_addConnector);
- return connectors;
- } else {
- var cnct = new Connector(ds1, mode, ds2, options);
- _addConnector(cnct);
- return cnct;
- }
-}
-
-
-/**
- * messenger of minder where it emits events related to all connectors
- * @type {Messenger}
- */
-var _messenger = new Messenger(minder, Messenger.defaultMethods);
-
-
-var _connectors = []
- , _receivedMessages = []
- , _isPropagating = false;
-
-
-_.extend(minder, {
- getConnectors: minder_getConnectors,
- getExpandedConnections: minder_getExpandedConnections,
- isPropagating: minder_isPropagating,
- whenPropagationCompleted: minder_whenPropagationCompleted,
- destroyConnector: minder_destroyConnector,
- destroy: minder_destroy
-});
-
-
-function _addConnector(cnct) {
- cnct.___minder_id = _connectors.push(cnct) - 1;
- cnct.on(/.*/, onConnectorMessage);
- minder.postMessage('added', { connector: cnct });
- minder.postMessage('turnedon', { connector: cnct });
-}
-
-
-function onConnectorMessage(msg, data) {
- var data = data ? _.clone(data) : {};
- _.extend(data, {
- id: this.___minder_id,
- connector: this
- });
- minder.postMessage(msg, data);
- if (! _receivedMessages.length && ! _isPropagating) {
- _.defer(_idleCheck);
- _isPropagating = true;
- }
-
- _receivedMessages.push({ msg: msg, data: data });
-}
-
-
-function _idleCheck() {
- if (_receivedMessages.length) {
- _receivedMessages.length = 0;
- _.defer(_idleCheck);
- minder.postMessage('propagationticked');
- } else {
- _isPropagating = false;
- minder.postMessage('propagationcompleted');
- }
-}
-
-
-function minder_isPropagating() {
- return _isPropagating;
-}
-
-
-function minder_whenPropagationCompleted(callback) {
- if (_isPropagating)
- minder.once('propagationcompleted', executeCallback);
- else
- _.defer(executeCallback);
-
- function executeCallback() {
- if (_isPropagating)
- minder.once('propagationcompleted', executeCallback);
- else
- callback();
- }
-}
-
-
-function minder_getConnectors(onOff) {
- if (typeof onOff == 'undefined')
- return _connectors;
-
- return _connectors.filter(function(cnct) {
- return cnct.isOn === onOff;
- });
-}
-
-
-function minder_destroyConnector(cnct) {
- cnct.destroy();
- var index = _connectors.indexOf(cnct);
- if (index >= 0)
- delete _connectors[index];
- else
- logger.warn('minder: connector destroyed that is not registered in minder');
-}
-
-
-function minder_getExpandedConnections(onOff, searchStr) {
- var connectors = minder.getConnectors(onOff);
- var connections = connectors.map(function(cnct) {
- var connection = {
- leftSource: _getExpandedSource(cnct.ds1),
- rightSource: _getExpandedSource(cnct.ds2),
- mode: cnct.mode,
- isOn: cnct.isOn
- };
-
- if (cnct.options)
- connection.options = cnct.options;
-
- return connection;
- });
-
- if (searchStr)
- connections = connections.filter(function(cnctn) {
- return _sourceMatchesString(cnctn.leftSource, searchStr)
- || _sourceMatchesString(cnctn.rightSource, searchStr);
- });
-
- return connections;
-}
-
-
-function _getExpandedSource(ds) {
- var source = [];
- if (typeof ds == 'function') {
- if (ds._model && ds._accessPath) {
- source.unshift(ds._accessPath);
- ds = ds._model;
- }
-
- source.unshift(ds);
- ds = ds._hostObject;
- }
-
- if (typeof ds == 'object') {
- source.unshift(ds);
-
- if (ds.owner)
- source.unshift(ds.owner);
- }
-
- return source;
-}
-
-
-function _sourceMatchesString(source, matchStr) {
- return source.some(function(srcNode) {
- var className = srcNode.constructor && srcNode.constructor.name;
- return _stringMatch(className, matchStr)
- || _stringMatch(srcNode.name, matchStr)
- || _stringMatch(srcNode, matchStr);
- });
-}
-
-
-function _stringMatch(str, substr) {
- return str && typeof str == 'string' && str.indexOf(substr) >= 0;
-}
-
-
-function minder_destroy() {
- _connectors.forEach(function(cnct) {
- destroyDS(cnct.ds1);
- destroyDS(cnct.ds2);
- cnct.destroy();
- });
- _messenger.destroy();
- minder._destroyed = true;
-
- function destroyDS(ds) {
- if (ds && !ds._destroyed) ds.destroy();
- }
-}
diff --git a/lib/model/change_data.js b/lib/model/change_data.js
deleted file mode 100644
index 52eb8ba..0000000
--- a/lib/model/change_data.js
+++ /dev/null
@@ -1,234 +0,0 @@
-'use strict';
-
-
-var facetsRegistry = require('../components/c_facets/cf_registry')
- , logger = require('../util/logger')
- , config = require('../config')
- , pathUtils = require('./path_utils')
- , _ = require('mol-proto');
-
-/**
- * Utility function to process "changedata" messages emitted by Connector object.
- */
-module.exports = changeDataHandler;
-
-
-_.extend(changeDataHandler, {
- setTransactionFlag: setTransactionFlag,
- getTransactionFlag: getTransactionFlag,
- passTransactionFlag: passTransactionFlag,
- postTransactionFinished: postTransactionFinished
-});
-
-
-/**
- * Change data uses hidden property on accessor methods to pass flag that the accessor is executed as a part of change transaction.
- * Accessor methods are supposed to store this flag in a local variable and to clear it (because another accessor can be executed in or out of transaction) using `getTransactionFlag`
- *
- * @private
- * @param {Function} func accessor method reference
- * @param {Boolean} flag a flag to be set
- */
-function setTransactionFlag(func, flag) {
- _.defineProperty(func, '__inChangeTransaction', flag, _.CONF | _.WRIT);
-}
-
-
-/**
- * Retrieves and clears transaction flag from accessor method
- *
- * @private
- * @param {Function} func accessor method reference
- * @return {Boolean}
- */
-function getTransactionFlag(func) {
- var inTransaction = func.__inChangeTransaction;
- delete func.__inChangeTransaction;
- return inTransaction;
-}
-
-
-function passTransactionFlag(fromFunc, toFunc) {
- var inTransaction = getTransactionFlag(fromFunc);
- setTransactionFlag(toFunc, inTransaction);
- return inTransaction;
-}
-
-
-/**
- * Posts message on this to indicate the end of transaction unless `inChangeTransaction` is `true`.
- */
-function postTransactionFinished() {
- this.postMessageSync('datachanges', { transaction: false, changes: [] });
-}
-
-
-/**
- * subscriber to "changedata" event emitted by [Connector](./connector.js.html) object to enable reactive connections
- * Used by Data facet, Model and ModelPath. Can be used by any object that implements get/set/del/splice api and sets data deeply to the whole tree.
- * Object should call `changeDataHandler.initialize.call(this)` in its constructor.
- * TODO: optimize messages list to avoid setting duplicate values down the tree
- *
- * @param {String} msg should be "changedata" here
- * @param {Object} data batch of data change desciption objects
- * @param {Function} callback callback to call before and after the data is processed
- */
-function changeDataHandler(message, data, callback) {
- processChanges.call(this, data.changes, callback);
-}
-
-
-// map of message types to methods
-var CHANGE_TYPE_TO_METHOD_MAP = {
- 'added': 'set',
- 'changed': 'set',
- 'deleted': 'del',
- 'removed': 'del'
-};
-
-
-/**
- * Processes queued "changedata" messages.
- * Posts "changestarted" and "changecompleted" messages and calls callback
- *
- * @param {[Function]} callback optional callback that is called with `(null, false)` parameters before change processing starts and `(null, true)` after it's finished.
- */
-function processChanges(transaction, callback) {
- notify.call(this, callback, false);
- processTransaction.call(this,
- prepareTransaction(
- validateTransaction(transaction)));
- notify.call(this, callback, true);
-}
-
-
-function notify(callback, changeFinished) {
- callback && callback(null, changeFinished);
- this.postMessage(changeFinished ? 'changecompleted' : 'changestarted');
-}
-
-
-/**
- * Checks that all messages from the transaction come from the same source.
- * Hack: reverses the transaction if it comes from the Data facet
- * Returns the reference to the transaction (for chaining)
- *
- * @param {Array} transaction transaction of data changes
- * @return {Array}
- */
-function validateTransaction(transaction) {
- var source = transaction[0].source
- , sameSource = true;
-
- if (transaction.length > 1) {
- for (var i = 1, len = transaction.length; i < len; i++)
- if (transaction[i].source != source) {
- logger.error('changedata: changes from different sources in the same transaction, sources:', transaction[i].source.name, source.name);
- sameSource = false;
- source = transaction[i].source;
- }
- }
-
- return transaction;
-}
-
-
-function prepareTransaction(transaction) {
- var todo = []
- , pathsToSplice = []
- , pathsToChange = []
- , hadSplice
- , exitLoop = {};
-
-
- try { transaction.forEach(checkChange); }
- catch (e) { if (e != exitLoop) throw e; }
-
- return todo;
-
-
- function checkChange(data) {
- (data.type == 'splice' ? checkSplice : checkMethod)(data);
- }
-
-
- function checkSplice(data) {
- var parsedPath = pathUtils.parseAccessPath(data.path);
- var parentPathChanged = pathsToChange.some(function(parentPath) {
- if (parsedPath.length < parentPath.length) return;
- return _pathIsParentOf(parentPath, parsedPath);
- });
-
- if (parentPathChanged) return;
-
- todo.push(data);
-
- if (! config.debug) throw exitLoop;
- pathsToSplice.push(parsedPath);
- hadSplice = true;
- }
-
-
- function checkMethod(data) {
- var parsedPath = pathUtils.parseAccessPath(data.path);
- var parentPathSpliced = pathsToSplice && pathsToSplice.some(function(parentPath) {
- if (parsedPath.length <= parentPath.length
- || parsedPath[parentPath.length].syntax != 'array') return;
- return _pathIsParentOf(parentPath, parsedPath);
- });
-
- if (parentPathSpliced) return;
- if (hadSplice) logger.error('changedata: child change is executed after splice; probably data source did not emit message with data.type=="finished"');
-
- var parentPathChanged = pathsToChange.some(function(parentPath) {
- if (parsedPath.length <= parentPath.length) return;
- return _pathIsParentOf(parentPath, parsedPath);
- });
-
- if (parentPathChanged) return;
-
- pathsToChange.push(parsedPath);
-
- todo.push(data);
- }
-
-
- function _pathIsParentOf(parentPath, childPath) {
- return parentPath.every(function(pathNode, index) {
- return pathNode.property == childPath[index].property;
- });
- }
-}
-
-
-function processTransaction(transaction) {
- transaction.forEach(processChange, this);
- postTransactionFinished.call(this, false);
-
- function processChange(data) {
- var modelPath = this.path(data.path, data.type != 'removed' && data.type != 'deleted');
- if (! modelPath) return;
- (data.type == 'splice' ? executeSplice : executeMethod)(modelPath, data);
- }
-}
-
-
-function executeSplice(modelPath, data) {
- var index = data.index
- , howMany = data.removed.length
- , spliceArgs = [index, howMany];
-
- spliceArgs = spliceArgs.concat(data.newValue.slice(index, index + data.addedCount));
- setTransactionFlag(modelPath.splice, true);
- modelPath.splice.apply(modelPath, spliceArgs);
-}
-
-
-function executeMethod(modelPath, data) {
- var methodName = CHANGE_TYPE_TO_METHOD_MAP[data.type];
- if (methodName) {
- setTransactionFlag(modelPath[methodName], true);
- modelPath[methodName](data.newValue);
- } else
- logger.error('unknown data change type');
-}
diff --git a/lib/model/connector.js b/lib/model/connector.js
deleted file mode 100644
index 5400561..0000000
--- a/lib/model/connector.js
+++ /dev/null
@@ -1,412 +0,0 @@
-'use strict';
-
-var ConnectorError = require('../util/error').Connector
- , Messenger = require('../messenger')
- , pathUtils = require('./path_utils')
- , _ = require('mol-proto')
- , logger = require('../util/logger');
-
-
-module.exports = Connector;
-
-
-var modePattern = /^(\<*)\-+(\>*)$/;
-
-
-/**
- * Connector
- * Class that creates connector object for data connection between
- * two data-sources
- * Data-sources should implement the following API:
- * get() - get value from datasource or its path
- * set(value) - set value to datasource or to its path
- * on(path, subscriber) - subscription to data changes with "*" support
- * off(path, subscriber)
- * path(accessPath) - to return the object that gives reference to some part of datasource
- * and complies with that api too.
- *
- * ####Events####
- *
- * - 'turnedon' - connector was turned on
- * - 'turnedoff' - connector was turned off
- * - 'changestarted' - change on connected datasource is started
- * - 'changecompleted' - change on connected datasource is completed
- * - 'destroyed' - connector was destroyed
- *
- * @param {Object} ds1 the first data source.
- * @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
- * @param {Object} ds2 the second data source
- * @param {Object} options not implemented yet
- * @return {Connector} when called with `new`, creates a Connector object.
- */
-function Connector(ds1, mode, ds2, options) {
- setupMode.call(this, mode);
-
- _.extend(this, {
- ds1: ds1,
- ds2: ds2,
- isOn: false,
- _changesQueue1: [],
- _changesQueue2: [],
- _messenger: new Messenger(this, Messenger.defaultMethods)
- });
-
- if (options) {
- this.options = options;
-
- var pathTranslation = options.pathTranslation;
- if (pathTranslation) {
- pathTranslation = _.clone(pathTranslation);
- var patternTranslation = getPatternTranslations(pathTranslation);
- _.extend(this, {
- pathTranslation1: reverseTranslationRules(pathTranslation),
- pathTranslation2: pathTranslation,
- patternTranslation1: reversePatternTranslationRules(patternTranslation),
- patternTranslation2: patternTranslation
- });
- }
-
- var dataTranslation = options.dataTranslation;
- if (dataTranslation) {
- _.extend(this, {
- dataTranslation1: dataTranslation['<-'],
- dataTranslation2: dataTranslation['->']
- });
- }
-
- var dataValidation = options.dataValidation;
- if (dataValidation) {
- _.extend(this, {
- dataValidation1: dataValidation['<-'],
- dataValidation2: dataValidation['->']
- });
- }
- }
-
- this.turnOn();
-}
-
-
-function setupMode(mode){
- var parsedMode = mode.match(modePattern);
-
- if (! parsedMode)
- modeParseError();
-
- var depth1 = parsedMode[1].length
- , depth2 = parsedMode[2].length;
-
- if (depth1 && depth2 && depth1 != depth2)
- modeParseError();
-
- if (! depth1 && ! depth2)
- modeParseError();
-
- _.extend(this, {
- mode: mode,
- depth1: depth1,
- depth2: depth2,
- });
-
- function modeParseError() {
- throw new ConnectorError('invalid Connector mode: ' + mode);
- }
-}
-
-
-_.extendProto(Connector, {
- turnOn: Connector$turnOn,
- turnOff: Connector$turnOff,
- destroy: Connector$destroy,
- changeMode: Connector$changeMode,
- deferChangeMode: Connector$deferChangeMode
-});
-
-/**
- * Function change the mode of the connection
- *
- * @param @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
- * @return {Object[String]}
- */
-function Connector$changeMode(mode) {
- this.turnOff();
- setupMode.call(this, mode);
- this.turnOn();
- return this;
-}
-
-
-/**
- * Function change the mode of the connection
- *
- * @param @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
- * @return {Object[String]}
- */
-function Connector$deferChangeMode(mode) {
- _.deferMethod(this, 'changeMode', mode);
- return this;
-}
-
-
-/**
- * Function that reverses translation rules for paths of connected odata sources
- *
- * @param {Object[String]} rules map of paths defining the translation rules
- * @return {Object[String]}
- */
-function reverseTranslationRules(rules) {
- var reverseRules = {};
- _.eachKey(rules, function(path2_value, path1_key) {
- reverseRules[path2_value] = path1_key;
- });
- return reverseRules;
-}
-
-
-function getPatternTranslations(pathTranslation) {
- var patternTranslation = [];
- _.eachKey(pathTranslation, function(path2_value, path1_key) {
- var starIndex1 = path1_key.indexOf('*')
- , starIndex2 = path2_value.indexOf('*');
- if (starIndex1 >= 0 && starIndex2 >= 0) { // pattern translation
- if (path1_key.slice(starIndex1) != path2_value.slice(starIndex2))
- _throwInvalidTranslation(path1_key, path2_value);
- delete pathTranslation[path1_key];
-
- patternTranslation.push({
- fromPattern: pathUtils.createRegexPath(path1_key),
- fromStaticPath: _getStaticPath(path1_key, starIndex1),
- toPattern: pathUtils.createRegexPath(path2_value),
- toStaticPath: _getStaticPath(path2_value, starIndex2)
- });
- } else if (starIndex1 >= 0 || starIndex2 >= 0) // pattern only on one side of translation
- _throwInvalidTranslation(path1_key, path2_value);
- });
-
- return patternTranslation;
-
-
- function _throwInvalidTranslation(path1, path2) {
- throw new ConnectorError('Invalid pattern translation: ' + path1 + ', ' + path2);
- }
-
-
- function _getStaticPath(path, starIndex) {
- return path.replace(/[\.\[]?\*.*$/, '');
- }
-}
-
-
-function reversePatternTranslationRules(patternTranslation) {
- return patternTranslation.map(function(pt) {
- return {
- fromPattern: pt.toPattern,
- fromStaticPath: pt.toStaticPath,
- toPattern: pt.fromPattern,
- toStaticPath: pt.fromStaticPath
- };
- });
-}
-
-
-/**
- * turnOn
- * Method of Connector that enables connection (if it was previously disabled)
- */
-function Connector$turnOn() {
- if (this.isOn)
- return logger.warn('data sources are already connected');
-
- var subscriptionPath = this._subscriptionPath =
- new Array(this.depth1 || this.depth2).join('*');
-
- var subscriptionPattern = pathUtils.createRegexPath(subscriptionPath);
-
- var self = this;
- if (this.depth1)
- this._link1 = linkDataSource('_link2', this.ds2, this.ds1, this._changesQueue1, this.pathTranslation1, this.patternTranslation1, this.dataTranslation1, this.dataValidation1);
- if (this.depth2)
- this._link2 = linkDataSource('_link1', this.ds1, this.ds2, this._changesQueue2, this.pathTranslation2, this.patternTranslation2, this.dataTranslation2, this.dataValidation2);
-
- this.isOn = true;
- this.postMessage('turnedon');
-
-
- function linkDataSource(reverseLink, fromDS, toDS, changesQueue, pathTranslation, patternTranslation, dataTranslation, dataValidation) {
- fromDS.onSync('datachanges', onData);
- return onData;
-
- function onData(message, batch) {
- var sendData = {
- changes: [],
- transaction: batch.transaction
- }
-
- batch.changes.forEach(function(change) {
- var sourcePath = change.path
- , targetPath = translatePath(sourcePath);
-
- if (typeof targetPath == 'undefined') return;
-
- var change = _.clone(change);
- _.extend(change, {
- source: fromDS,
- path: targetPath
- });
-
- translateData(sourcePath, change);
- validateData(sourcePath, change);
- });
-
- if (! changesQueue.length)
- _.defer(postChangeData);
-
- changesQueue.push(sendData);
-
-
- function translatePath(sourcePath) {
- if (pathTranslation) {
- var translatedPath = pathTranslation[sourcePath];
- if (translatedPath) return translatedPath;
- if (!patternTranslation.length) return;
- var pt = _.find(patternTranslation, function(pTranslation) {
- return pTranslation.fromPattern.test(sourcePath);
- });
- if (!pt) return;
- var translatedPath = sourcePath.replace(pt.fromStaticPath, pt.toStaticPath);
- } else if (! ((subscriptionPattern instanceof RegExp
- && subscriptionPattern.test(sourcePath))
- || subscriptionPattern == sourcePath)) return;
-
- return translatedPath || sourcePath;
- }
-
-
- function translateData(sourcePath, change) {
- if (dataTranslation) {
- var translate = dataTranslation[sourcePath];
- if (translate && typeof translate == 'function') {
- change.oldValue = translate(change.oldValue);
- change.newValue = translate(change.newValue);
- }
- }
- }
-
-
- function validateData(sourcePath, change) {
- propagateData(change);
-
- if (dataValidation) {
- var validators = dataValidation[sourcePath]
- , passedCount = 0
- , alreadyFailed = false;
-
- if (validators)
- validators.forEach(callValidator);
- }
-
-
- function callValidator(validator) {
- validator(change.newValue, function(err, response) {
- response.path = sourcePath;
- if (! alreadyFailed && (err || response.valid) && ++passedCount == validators.length) {
- fromDS.postMessage('validated', response);
- } else if (! response.valid) {
- alreadyFailed = true;
- fromDS.postMessage('validated', response);
- }
- });
- }
- }
-
-
- function propagateData(change) {
- sendData.changes.push(change);
- }
-
-
- function postChangeData() {
- // prevent endless loop of updates for 2-way connection
- if (self[reverseLink]) var callback = subscriptionSwitch;
-
- var transactions = mergeTransactions(changesQueue);
- changesQueue.length = 0;
- transactions.forEach(function(transaction) {
- // send data change instruction as message
- toDS.postMessageSync('changedata', { changes: transaction }, callback);
- });
- }
-
-
- function subscriptionSwitch(err, changeFinished) {
- if (err) return;
- var onOff = changeFinished ? 'onSync' : 'off';
- toDS[onOff]('datachanges', self[reverseLink]);
-
- var message = changeFinished ? 'changecompleted' : 'changestarted';
- self.postMessage(message, { source: fromDS, target: toDS });
- }
-
-
- function mergeTransactions(batches) {
- var transactions = []
- , currentTransaction;
-
- batches.forEach(function(batch) {
- if (! batch.transaction) currentTransaction = undefined;
- if (! batch.changes.length) return;
-
- if (batch.transaction) {
- if (currentTransaction)
- _.appendArray(currentTransaction, batch.changes);
- else {
- currentTransaction = _.clone(batch.changes);
- transactions.push(currentTransaction);
- }
- } else
- transactions.push(batch.changes);
- });
-
- return transactions;
- }
- }
- }
-}
-
-
-/**
- * turnOff
- * Method of Connector that disables connection (if it was previously enabled)
- */
-function Connector$turnOff() {
- if (! this.isOn)
- return logger.warn('data sources are already disconnected');
-
- var self = this;
- unlinkDataSource(this.ds1, '_link2', this.pathTranslation2);
- unlinkDataSource(this.ds2, '_link1', this.pathTranslation1);
-
- this.isOn = false;
- this.postMessage('turnedoff');
-
-
- function unlinkDataSource(fromDS, linkName, pathTranslation) {
- if (self[linkName]) {
- fromDS.off('datachanges', self[linkName]);
- delete self[linkName];
- }
- }
-}
-
-
-/**
- * Destroys connector object by turning it off and removing references to connected sources
- */
-function Connector$destroy() {
- this.turnOff();
- this.postMessage('destroyed');
- this._messenger.destroy();
- delete this.ds1;
- delete this.ds2;
- this._destroyed = true;
-}
diff --git a/lib/model/demo.js b/lib/model/demo.js
deleted file mode 100644
index 40d177f..0000000
--- a/lib/model/demo.js
+++ /dev/null
@@ -1,48 +0,0 @@
-'use strict';
-
-
-var Model = require('./index');
-
-
-var m = new Model;
-
-var year = m('.info.DOB.year').get();
-// undefined, but doesn't fail, like in Angular
-
-m('.info.DOB.year').set(1982);
-
-var year = m('.info.DOB.year').get();
-// 1982
-
-var data = m('.info').get();
-// { DOB: { year: 1982 } }
-
-var mData = m.get();
-// { info: { DOB: { year: 1982 } } }
-
-
-
-var m = new Model;
-
-m.on(/.*/, onChange);
-
-function onChange(msg, data) {
- // should be replaced with console if this demo is used
- logger.log(msg, ' : ', data);
-}
-
-m('.list[0].info.name').set('Clifton');
-// logged:
-// .list : { type: 'added', newValue: [] }
-// .list[0] : { type: 'added', newValue: {} }
-// .list[0].info : { type: 'added', newValue: {} }
-// .list[0].info.name : { type: 'added', newValue: 'Clifton' }
-
-m('.list[0].info.name').set('Clifton Cunnigham');
-// logged:
-// .list[0].info.name : { type: 'changed',
-// oldValue: 'Clifton',
-// newValue: 'Clifton Cunnigham' }
-
-var name = m('.list[0].info.name').get();
-// 'Clifton Cunnigham'
diff --git a/lib/model/index.js b/lib/model/index.js
deleted file mode 100644
index b83939e..0000000
--- a/lib/model/index.js
+++ /dev/null
@@ -1,244 +0,0 @@
-'use strict';
-
-var ModelPath = require('./m_path')
- , synthesize = require('./synthesize')
- , pathUtils = require('./path_utils')
- , changeDataHandler = require('./change_data')
- , Messenger = require('../messenger')
- , MessengerMessageSource = require('../messenger/msngr_source')
- , ModelMsgAPI = require('./m_msg_api')
- , ModelError = require('../util/error').Model
- , Mixin = require('../abstract/mixin')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , logger = require('../util/logger')
- , jsonParse = require('../util/json_parse');
-
-
-module.exports = Model;
-
-
-/**
- * `milo.Model`
- * Model class instantiates objects that allow deep data access with __safe getters__ that return undefined (rather than throwing exception) when properties/items of unexisting objects/arrays are requested and __safe setters__ that create object trees when properties/items of unexisting objects/arrays are set and also post messages to allow subscription on changes and enable data reactivity.
- * Reactivity is implememnted via [Connector](./connector.js.html) that can be instantiated either directly or with more convenient interface of [milo.minder](../minder.js.html). At the moment model can be connected to [Data facet](../components/c_facets/Data.js.html) or to another model or [ModelPath](./m_path.js.html).
- * Model constructor returns objects that are functions at the same time; when called they return ModelPath objects that allow get/set access to any point in model data. See [ModelData](#ModelData) below.
- *
- * You can subscribe to model changes with `on` method by passing model access path in place of message, pattern or string with any number of stars to subscribe to a certain depth in model (e.g., `'***'` to subscribe to three levels).
- *
- * @constructor
- * @param {Object|Array} data optional initial array data. If it is planned to connect model to view it is usually better to instantiate an empty Model (`var m = new Model`), connect it to [Component](../components/c_class.js.html)'s [Data facet](../components/c_facets/Data.js.html) (e.g., `milo.minder(m, '<<->>', c.data);`) and then set the model with `m.set(data)` - the view will be automatically updated.
- * @param {Object} hostObject optional object that hosts model on one of its properties. Can be used when model itself is the context of the message subscriber and you need to travers to this object (although it is possible to set any context). Can also be used to proxy model's methods to the host like [Model facet](../components/c_facets/ModelFacet.js.html) is doing.
- * @param {Object} options pass { reactive: false } to use model without messaging when it is not needed - it makes it much faster
- * @return {Model}
- */
-function Model(data, hostObject, options) {
- // `model` will be returned by constructor instead of `this`. `model`
- // (`modelPath` function) should return a ModelPath object with "synthesized" methods
- // to get/set model properties, to subscribe to property changes, etc.
- // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.
- var model = function modelPath(accessPath) { // , ... arguments that will be interpolated
- return Model$path.apply(model, arguments);
- };
- model.__proto__ = Model.prototype;
-
- model._hostObject = hostObject;
- model._options = options || {};
-
- if (model._options.reactive !== false) {
- model._prepareMessengers();
- // subscribe to "changedata" message to enable reactive connections
- model.onSync('changedata', changeDataHandler);
- }
-
- if (data) model._data = data;
-
- return model;
-}
-
-Model.prototype.__proto__ = Model.__proto__;
-
-
-/**
- * ####Model instance methods####
- *
- * - [path](#path) - returns ModelPath object that allows access to any point in Model
- * - [get](#Model$get) - get model data
- * - set - set model data, synthesized
- * - splice - splice model data (as array or pseudo-array), synthesized
- * - [len](./m_path.js.html#ModelPath$len) - returns length of array (or pseudo-array) in model in safe way, 0 if no length is set
- * - [push](./m_path.js.html#ModelPath$push) - add items to the end of array (or pseudo-array) in model
- * - [pop](./m_path.js.html#ModelPath$pop) - remove item from the end of array (or pseudo-array) in model
- * - [unshift](./m_path.js.html#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in model
- * - [shift](./m_path.js.html#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in model
- * - [proxyMessenger](#proxyMessenger) - proxy model's Messenger methods to host object
- * - [proxyMethods](#proxyMethods) - proxy model methods to host object
- */
-_.extendProto(Model, {
- path: Model$path,
- get: Model$get,
- proxyMessenger: proxyMessenger, // deprecated, should not be used
- proxyMethods: proxyMethods,
- _prepareMessengers: _prepareMessengers,
- _getHostObject: _getHostObject,
- destroy: Model$destroy
-});
-
-// set, del, splice are added to model
-_.extendProto(Model, synthesize.modelMethods);
-
-
-/**
- * - Path: ModelPath class as `milo.Model.Path`
- * - [registerWithDOMStorage](#Model$$registerWithDOMStorage)
- */
-_.extend(Model, {
- Path: ModelPath,
- registerWithDOMStorage: Model$$registerWithDOMStorage,
- useWith: Model$$useWith
-});
-
-
-/**
- * Expose Messenger methods on Facet prototype
- */
-var MESSENGER_PROPERTY = '_messenger';
-Messenger.useWith(Model, MESSENGER_PROPERTY, Messenger.defaultMethods);
-
-
-/**
- * ModelPath methods added to Model prototype
- */
-['len', 'push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {
- var method = ModelPath.prototype[methodName];
- _.defineProperty(Model.prototype, methodName, method);
-});
-
-
-/**
- * Model instance method.
- * Get model data.
- *
- * @return {Any}
- */
-function Model$get() {
- return this._data;
-}
-
-
-/**
- * Model instance method.
- * Returns ModelPath object that implements the same API as model but allows access to any point inside model as defined by `accessPath`.
- * See [ModelPath](./m_path.js.html) class for more information.
- *
- * @param {String} accessPath string that defines path to access model.
- * Path string consists of parts to define either property access (`".name"` to access property name) or array item access (`"[1]"` to access item with index 1).
- * Access path can contain as many parts as necessary (e.g. `".list[0].name"` to access property `name` in the first element of array stored in property `list`.
- * @param {List} arguments additional arguments of this method can be used to create interpolated paths.
- * E.g. `m.path("[$1].$2", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m("[" + id + "]." + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.
- * @return {ModelPath}
- */
-function Model$path(accessPath) { // , ... arguments that will be interpolated
- if (! accessPath) return this;
-
- // "null" is context to pass to ModelPath, first parameter of bind
- // "this" (model) is added in front of all arguments
- _.splice(arguments, 0, 0, null, this);
-
- // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...
- return new (Function.prototype.bind.apply(ModelPath, arguments));
-}
-
-
-/**
- * Model instance method.
- * Proxy model's Messenger methods to host object.
- *
- * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.
- */
-function proxyMessenger(modelHostObject) {
- modelHostObject = modelHostObject || this._hostObject;
- Mixin.prototype._createProxyMethods.call(this[MESSENGER_PROPERTY], Messenger.defaultMethods, modelHostObject);
-}
-
-
-var modelMethodsToProxy = ['path', 'get', 'set', 'del', 'splice', 'len', 'push', 'pop', 'unshift', 'shift'];
-
-
-/**
- * Expose model methods on
- * See same method in Mixin class for parameters meaning
- *
- * @param {Function} hostClass
- * @param {[type]} instanceKey
- * @param {[type]} mixinMethods optional
- */
-function Model$$useWith(hostClass, instanceKey, mixinMethods) {
- mixinMethods = mixinMethods || modelMethodsToProxy;
- Mixin.useWith.call(Model, hostClass, instanceKey, mixinMethods);
-}
-
-
-/**
- * Model instance method.
- * Proxy model methods to host object.
- *
- * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.
- */
-function proxyMethods(modelHostObject) {
- modelHostObject = modelHostObject || this._hostObject;
- Mixin.prototype._createProxyMethods.call(this, modelMethodsToProxy, modelHostObject);
-}
-
-
-/**
- * Model instance method.
- * Create and connect internal and external model's messengers.
- * External messenger's methods are proxied on the model and they allows "*" subscriptions.
- */
-function _prepareMessengers() {
- // model will post all its changes on internal messenger
- var internalMessenger = new Messenger(this, undefined, undefined);
-
- // message source to connect internal messenger to external
- var internalMessengerSource = new MessengerMessageSource(this, undefined, new ModelMsgAPI, internalMessenger);
-
- // external messenger to which all model users will subscribe,
- // that will allow "*" subscriptions and support "changedata" message api.
- var externalMessenger = new Messenger(this, undefined, internalMessengerSource);
-
- _.defineProperty(this, MESSENGER_PROPERTY, externalMessenger);
- _.defineProperty(this, '_internalMessenger', internalMessenger);
-}
-
-
-function _getHostObject() {
- return this._hostObject;
-}
-
-
-function Model$$registerWithDOMStorage() {
- var DOMStorage = require('../util/storage');
- DOMStorage.registerDataType('Model', Model_domStorageSerializer, Model_domStorageParser);
- DOMStorage.registerDataType('ModelPath', Model_domStorageSerializer, Model_domStorageParser, 'Model');
-}
-
-
-function Model_domStorageSerializer(value) {
- var data = value.get();
- return JSON.stringify(data);
-}
-
-
-function Model_domStorageParser(valueStr) {
- var data = jsonParse(valueStr);
- return new Model(data);
-}
-
-
-function Model$destroy() {
- this[MESSENGER_PROPERTY].destroy();
- this._internalMessenger.destroy();
- this._destroyed = true;
-}
diff --git a/lib/model/m_msg_api.js b/lib/model/m_msg_api.js
deleted file mode 100644
index 54e88d6..0000000
--- a/lib/model/m_msg_api.js
+++ /dev/null
@@ -1,37 +0,0 @@
-'use strict';
-
-var MessengerRegexpAPI = require('../messenger/m_api_rx')
- , pathUtils = require('./path_utils')
- , _ = require('mol-proto');
-
-
-/**
- * Subclass of MessengerRegexpAPI that is used to translate messages of external messenger of Model to internal messenger of Model.
- */
-var ModelMsgAPI = _.createSubclass(MessengerRegexpAPI, 'ModelMsgAPI');
-
-module.exports = ModelMsgAPI;
-
-
-/**
- * ####ModelMsgAPI instance methods####
- *
- * - [translateToSourceMessage](#translateToSourceMessage) - translates subscription paths with "*"s to regex, leaving other strings untouched
- */
-_.extendProto(ModelMsgAPI, {
- translateToSourceMessage: translateToSourceMessage,
-});
-
-
-/**
- * ModelMsgAPI instance method
- * Translates subscription paths with "*"s to regex, leaving other strings untouched.
- *
- * @param {String} accessPath relative access path to be translated
- * @return {RegExp|String}
- */
-function translateToSourceMessage(accessPath) {
- if (accessPath instanceof RegExp) return accessPath;
-
- return pathUtils.createRegexPath(accessPath);
-}
diff --git a/lib/model/m_path.js b/lib/model/m_path.js
deleted file mode 100644
index fd41a38..0000000
--- a/lib/model/m_path.js
+++ /dev/null
@@ -1,295 +0,0 @@
-'use strict';
-
-var synthesize = require('./synthesize')
- , pathUtils = require('./path_utils')
- , changeDataHandler = require('./change_data')
- , Messenger = require('../messenger')
- , ModelPathMsgAPI = require('./path_msg_api')
- , MessengerMessageSource = require('../messenger/msngr_source')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match;
-
-
-module.exports = ModelPath;
-
-
-/**
- * `milo.Model.Path`
- * ModelPath object that allows access to any point inside [Model](./index.js.html) as defined by `accessPath`
- *
- * @constructor
- * @param {Model} model Model instance that ModelPath gives access to.
- * @param {String} accessPath string that defines path to access model.
- * Path string consists of parts to define either property access (`".name"` to access property name) or array item access (`"[1]"` to access item with index 1).
- * Access path can contain as many parts as necessary (e.g. `".list[0].name"` to access property `name` in the first element of array stored in property `list`.
- * @param {List} arguments additional arguments of this method can be used to create interpolated paths.
- * E.g. `m.path("[$1].$2", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m("[" + id + "]." + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.
- * @return {ModelPath}
- */
-function ModelPath(model, path) { // ,... - additional arguments for interpolation
- // check(model, Model);
- check(path, String);
-
- // `modelPath` will be returned by constructor instead of `this`. `modelPath`
- // (`modelPath_path` function) should also return a ModelPath object with "synthesized" methods
- // to get/set model properties, to subscribe to property changes, etc.
- // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.
- var modelPath = function modelPath_path(accessPath) { // , ... arguments that will be interpolated
- return ModelPath$path.apply(modelPath, arguments);
- };
- modelPath.__proto__ = ModelPath.prototype;
-
-
- _.defineProperties(modelPath, {
- _model: model,
- _path: path,
- _args: _.slice(arguments, 1), // path will be the first element of this array
- _options: model._options
- });
-
- // parse access path
- var parsedPath = pathUtils.parseAccessPath(path);
-
- // compute access path string
- _.defineProperty(modelPath, '_accessPath', interpolateAccessPath(parsedPath, modelPath._args));
-
- if (modelPath._options.reactive !== false) {
- // messenger fails on "*" subscriptions
- modelPath._prepareMessenger();
- // subscribe to "changedata" message to enable reactive connections
- modelPath.onSync('changedata', changeDataHandler);
- }
-
- // compiling getter and setter
- var methods = synthesize(path, parsedPath);
-
- // adding methods to model path
- _.defineProperties(modelPath, methods);
-
- Object.freeze(modelPath);
-
- return modelPath;
-}
-
-ModelPath.prototype.__proto__ = ModelPath.__proto__;
-
-
-/**
- * Interpolates path elements to compute real path
- *
- * @param {Array} parsedPath parsed path - array of path nodes
- * @param {Array} args path interpolation arguments, args[0] is path itself
- * @return {String}
- */
-function interpolateAccessPath(parsedPath, args) {
- return parsedPath.reduce(function(accessPathStr, currNode, index) {
- var interpolate = currNode.interpolate;
- return accessPathStr +
- (interpolate
- ? (currNode.syntax == 'array'
- ? '[' + args[interpolate] + ']'
- : '.' + args[interpolate])
- : currNode.property);
- }, '');
-}
-
-
-/**
- * ####ModelPath instance methods####
- *
- * - [path](#ModelPath$path) - gives access to path inside ModelPath
- * - get - synthesized
- * - set - synthesized
- * - splice - splice model data (as array or pseudo-array), synthesized
- * - [len](#ModelPath$len) - returns length of array (or pseudo-array) in safe way, 0 if no length is set
- * - [push](#ModelPath$push) - add items to the end of array (or pseudo-array) in ModelPath
- * - [pop](#ModelPath$pop) - remove item from the end of array (or pseudo-array) in ModelPath
- * - [unshift](#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in ModelPath
- * - [shift](#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in ModelPath
- */
-_.extendProto(ModelPath, {
- path: ModelPath$path,
- len: ModelPath$len,
- push: ModelPath$push,
- pop: ModelPath$pop,
- unshift: ModelPath$unshift,
- shift: ModelPath$shift,
- _prepareMessenger: _prepareMessenger,
- _getDefinition: _getDefinition,
- destroy: ModelPath$destroy
-});
-
-
-_.extend(ModelPath, {
- _createFromDefinition: _createFromDefinition
-})
-
-
-/**
- * Expose Messenger methods on Facet prototype
- */
-var MESSENGER_PROPERTY = '_messenger';
-Messenger.useWith(ModelPath, MESSENGER_PROPERTY, Messenger.defaultMethods);
-
-
-/**
- * ModelPath instance method
- * Gives access to path inside ModelPath. Method works similarly to [path method](#Model$path) of model, using relative paths.
- *
- * @param {String} accessPath string that defines path to access model.
- * Path string consists of parts to define either property access (`".name"` to access property name) or array item access (`"[1]"` to access item with index 1).
- * Access path can contain as many parts as necessary (e.g. `".list[0].name"` to access property `name` in the first element of array stored in property `list`.
- * @param {List} arguments additional arguments of this method can be used to create interpolated paths.
- * E.g. `m.path("[$1].$2", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m("[" + id + "]." + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.
- * @return {ModelPath}
- */
-function ModelPath$path(accessPath) { // , ... arguments that will be interpolated
- if (! accessPath) return this;
-
- var thisPathArgsCount = this._args.length - 1;
-
- if (thisPathArgsCount > 0) {// this path has interpolated arguments too
- accessPath = accessPath.replace(/\$[1-9][0-9]*/g, function(str) {
- return '$' + (+str.slice(1) + thisPathArgsCount);
- });
- }
-
- var newPath = this._path + accessPath;
-
- // this._model is added in front of all arguments as the first parameter
- // of ModelPath constructor
- var args = [this._model, newPath]
- .concat(this._args.slice(1)) // remove old path from _args, as it is 1 based
- .concat(_.slice(arguments, 1)); // add new interpolation arguments
-
- // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...
- return _.newApply(ModelPath, args);
-}
-
-
-/**
- * ModelPath and Model instance method
- * Returns length property and sets it to 0 if it wasn't set.
- *
- * @return {Any}
- */
-function ModelPath$len() {
- return this.path('.length').get() || 0;
-}
-
-
-/**
- * ModelPath and Model instance method
- * Adds items to the end of array (or pseudo-array). Returns new length.
- *
- * @param {List} arguments list of items that will be added to array (pseudo array)
- * @return {Integer}
- */
-function ModelPath$push() { // arguments
- var length = this.len();
- var newLength = length + arguments.length;
-
- _.splice(arguments, 0, 0, length, 0);
- this.splice.apply(this, arguments);
-
- return newLength;
-}
-
-
-/**
- * ModelPath and Model instance method
- * Removes item from the end of array (or pseudo-array). Returns this item.
- *
- * @return {Any}
- */
-function ModelPath$pop() {
- return this.splice(this.len() - 1, 1)[0];
-}
-
-
-/**
- * ModelPath and Model instance method
- * Inserts items to the beginning of the array. Returns new length.
- *
- * @param {List} arguments items to be inserted in the beginning of array
- * @return {Integer}
- */
-function ModelPath$unshift() { // arguments
- var length = this.len();
- length += arguments.length;
-
- _.splice(arguments, 0, 0, 0, 0);
- this.splice.apply(this, arguments);
-
- return length;
-}
-
-
-/**
- * ModelPath and Model instance method
- * Removes the item from the beginning of array (or pseudo-array). Returns this item.
- *
- * @return {Any}
- */
-function ModelPath$shift() { // arguments
- return this.splice(0, 1)[0];
-}
-
-
-/**
- * ModelPath instance method
- * Initializes ModelPath mesenger with Model's messenger as its source ([MessengerMessageSource](../messenger/msngr_source.js.html)) and [ModelPathMsgAPI](./path_msg_api.js.html) as [MessengerAPI](../messenger/m_api.js.html)
- */
-function _prepareMessenger() {
- var mPathAPI = new ModelPathMsgAPI(this._accessPath);
-
- // create MessengerMessageSource connected to Model's messenger
- var modelMessageSource = new MessengerMessageSource(this, undefined, mPathAPI, this._model);
-
- // create messenger with model passed as hostObject (default message dispatch context)
- // and without proxying methods (we don't want to proxy them to Model)
- var mPathMessenger = new Messenger(this, undefined, modelMessageSource);
-
- // store messenger on ModelPath instance
- _.defineProperty(this, MESSENGER_PROPERTY, mPathMessenger);
-}
-
-
-/**
- * Returns the object allowing to recreate model path
- *
- * @return {Object}
- */
-function _getDefinition() {
- return {
- model: this._model,
- path: this._path,
- args: this._args
- };
-}
-
-
-/**
- * Class method
- * Creates modelPath object from definition created by _getDefinition
- *
- * @param {Object} definition
- * @return {ModelPath}
- */
-function _createFromDefinition(definition) {
- check(definition, {
- model: Function, // Model
- path: String,
- args: Array
- });
-
- var m = definition.model;
-
- return m.apply(m, definition.args);
-}
-
-
-function ModelPath$destroy() {
- this[MESSENGER_PROPERTY].destroy();
-}
diff --git a/lib/model/model_utils.js b/lib/model/model_utils.js
deleted file mode 100644
index e65a652..0000000
--- a/lib/model/model_utils.js
+++ /dev/null
@@ -1,19 +0,0 @@
-'use strict';
-
-
-var modelUtils = {
- normalizeSpliceIndex: normalizeSpliceIndex
-};
-
-module.exports = modelUtils;
-
-
-function normalizeSpliceIndex(spliceIndex, length) {
- return spliceIndex > length
- ? length
- : spliceIndex >= 0
- ? spliceIndex
- : spliceIndex + length > 0
- ? spliceIndex + length
- : 0;
-}
diff --git a/lib/model/path_msg_api.js b/lib/model/path_msg_api.js
deleted file mode 100644
index 25aca0a..0000000
--- a/lib/model/path_msg_api.js
+++ /dev/null
@@ -1,99 +0,0 @@
-'use strict';
-
-var MessengerAPI = require('../messenger/m_api')
- , pathUtils = require('./path_utils')
- , logger = require('../util/logger')
- , _ = require('mol-proto');
-
-
-/**
- * Subclass of MessengerAPI that is used to translate messages of Messenger on ModelPath to Messenger on Model.
- */
-var ModelPathMsgAPI = _.createSubclass(MessengerAPI, 'ModelPathMsgAPI');
-
-module.exports = ModelPathMsgAPI;
-
-
-/**
- * ####ModelPathMsgAPI instance methods####
- *
- * - [init](#init) - initializes ModelPathMsgAPI
- * - [translateToSourceMessage](#translateToSourceMessage) - translates relative access paths of ModelPath to full path of Model
- * - [createInternalData](#createInternalData) - changes path in message on model to relative path and adds `fullPath` property to message data
- */
-_.extendProto(ModelPathMsgAPI, {
- init: init,
- translateToSourceMessage: translateToSourceMessage,
- createInternalData: createInternalData,
-});
-
-
-/**
- * ModelPathMsgAPI instance method
- * Called by MessengerAPI constructor.
- *
- * @param {String} rootPath root path of model path
- */
-function init(rootPath) {
- MessengerAPI.prototype.init.apply(this, arguments);
- this.rootPath = rootPath;
-}
-
-/**
- * ModelPathMsgAPI instance method
- * Translates relative access paths of ModelPath to full path of Model.
- *
- * @param {String} accessPath relative access path to be translated
- * @return {String}
- */
-function translateToSourceMessage(message) {
- // TODO should prepend RegExes
- // TODO should not prepend changedata too???
- if (message instanceof RegExp)
- return message;
- if (message == 'datachanges')
- return message;
-
- return this.rootPath + message;
-}
-
-
-/**
- * ModelPathMsgAPI instance method
- * Changes path in message on model to relative path and adds `fullPath` property to message data.
- *
- * @param {String} sourceMessage full access path on Model
- * @param {String} message relative access path on ModelPath
- * @param {Object} sourceData data received from Model, will be translated as described to be dispatched to ModelPath
- * @return {Object}
- */
-function createInternalData(sourceMessage, message, sourceData) {
- // TODO return on changedata too???
- if (message == 'datachanges') {
- var internalChanges = sourceData.changes
- .map(truncateChangePath, this)
- .filter(function(change) { return change; });
- var internalData = {
- changes: internalChanges,
- transaction: sourceData.transaction
- };
-
- return internalData
- }
-
- var internalData = truncateChangePath.call(this, sourceData);
- return internalData;
-}
-
-
-function truncateChangePath(change) {
- var fullPath = change.path
- , path = _.unPrefix(fullPath, this.rootPath);
-
- if (typeof path == 'string') {
- var change = _.clone(change);
- change.fullPath = fullPath;
- change.path = path;
- return change;
- }
-}
diff --git a/lib/model/path_utils.js b/lib/model/path_utils.js
deleted file mode 100644
index 38ff719..0000000
--- a/lib/model/path_utils.js
+++ /dev/null
@@ -1,143 +0,0 @@
-'use strict';
-
-//
-// ### model path utils
-
-var check = require('../util/check')
- , Match = check.Match
- , _ = require('mol-proto')
- , ModelError = require('../util/error').Model;
-
-var pathUtils = {
- parseAccessPath: parseAccessPath,
- createRegexPath: createRegexPath,
- getPathNodeKey: getPathNodeKey,
- wrapMessengerMethods: wrapMessengerMethods
-};
-
-module.exports = pathUtils;
-
-
-var propertyPathSyntax = '\\.[A-Za-z_-][A-Za-z0-9_-]*'
- , arrayPathSyntax = '\\[[0-9]+\\]'
- , interpolationSyntax = '\\$[1-9][0-9]*'
- , propertyInterpolateSyntax = '\\.' + interpolationSyntax
- , arrayInterpolateSyntax = '\\[' + interpolationSyntax + '\\]'
-
- , propertyStarSyntax = '\\.\\*'
- , arrayStarSyntax = '\\[\\*\\]'
- , starSyntax = '\\*'
-
- , pathParseSyntax = [
- propertyPathSyntax,
- arrayPathSyntax,
- propertyInterpolateSyntax,
- arrayInterpolateSyntax
- ].join('|')
- , pathParsePattern = new RegExp(pathParseSyntax, 'g')
-
- , patternPathParseSyntax = [
- pathParseSyntax,
- propertyStarSyntax,
- arrayStarSyntax,
- starSyntax
- ].join('|')
- , patternPathParsePattern = new RegExp(patternPathParseSyntax, 'g')
-
- //, targetPathParsePattern = /\.[A-Za-z][A-Za-z0-9_]*|\[[0-9]+\]|\.\$[1-9][0-9]*|\[\$[1-9][0-9]*\]|\$[1-9][0-9]/g
- , pathNodeTypes = {
- '.': { syntax: 'object', empty: '{}' },
- '[': { syntax: 'array', empty: '[]'},
- '*': { syntax: 'match', empty: '{}'},
- };
-
-function parseAccessPath(path, nodeParsePattern) {
- nodeParsePattern = nodeParsePattern || pathParsePattern;
-
- var parsedPath = [];
-
- if (! path)
- return parsedPath;
-
- var unparsed = path.replace(nodeParsePattern, function(nodeStr) {
- var pathNode = { property: nodeStr };
- _.extend(pathNode, pathNodeTypes[nodeStr[0]]);
- if (nodeStr[1] == '$')
- pathNode.interpolate = getPathNodeKey(pathNode, true);
-
- parsedPath.push(pathNode);
- return '';
- });
- if (unparsed)
- throw new ModelError('incorrect model path: ' + path);
-
- return parsedPath;
-}
-
-
-var nodeRegex = {
- '.*': propertyPathSyntax,
- '[*]': arrayPathSyntax
-};
-nodeRegex['*'] = nodeRegex['.*'] + '|' + nodeRegex['[*]'];
-
-function createRegexPath(path) {
- check(path, Match.OneOf(String, RegExp));
-
- if (path instanceof RegExp || path.indexOf('*') == -1)
- return path;
-
- var parsedPath = pathUtils.parseAccessPath(path, patternPathParsePattern)
- , regexStr = '^'
- // , regexStrEnd = ''
- , patternsStarted = false;
-
- parsedPath.forEach(function(pathNode) {
- var prop = pathNode.property
- , regex = nodeRegex[prop];
-
- if (regex) {
- // regexStr += '(' + regex;
- // regexStrEnd += '|)';
- regexStr += '(' + regex + '|)';
- // regexStrEnd += '|)';
- patternsStarted = true;
- } else {
- // if (patternsStarted)
- // throw new ModelError('"*" path segment cannot be in the middle of the path: ' + path);
- regexStr += prop.replace(/(\.|\[|\])/g, '\\$1'); // add slash in front of symbols that have special meaning in regex
- }
- });
-
- regexStr += /* regexStrEnd + */ '$';
-
- try {
- return new RegExp(regexStr);
- } catch (e) {
- throw new ModelError('can\'t construct regex for path pattern: ' + path);
- }
-}
-
-
-function getPathNodeKey(pathNode, interpolated) {
- var prop = pathNode.property
- , startIndex = interpolated ? 2 : 1;
- return pathNode.syntax == 'array'
- ? prop.slice(startIndex, prop.length - 1)
- : prop.slice(startIndex);
-}
-
-
-// TODO allow for multiple messages in a string
-function wrapMessengerMethods(methodsNames) {
- methodsNames = methodsNames || ['on', 'off'];
- var wrappedMethods = _.mapToObject(methodsNames, function(methodName) {
- var origMethod = this[methodName];
- // replacing message subsribe/unsubscribe/etc. to convert "*" message patterns to regexps
- return function(path, subscriber) {
- var regexPath = createRegexPath(path);
- origMethod.call(this, regexPath, subscriber);
- };
- }, this);
- _.defineProperties(this, wrappedMethods);
-}
diff --git a/lib/model/synthesize/create_tree.dot.js b/lib/model/synthesize/create_tree.dot.js
deleted file mode 100644
index e65d920..0000000
--- a/lib/model/synthesize/create_tree.dot.js
+++ /dev/null
@@ -1,82 +0,0 @@
-'use strict';
-/* Only use this style of comments, not "//" */
-
-/**
- * Inserts code to create model tree as neccessary for `set` and `splice` accessors and to add messages to send list if the tree changes.
- */
-{{## def.createTree:method:
- var wasDef = true;
- var old = m;
-
- {{ var emptyProp = it.parsedPath[0] && it.parsedPath[0].empty; }}
- {{? emptyProp }}
- {{ /* create top level model if it was not previously defined */ }}
- if (! m) {
- m = {{# def.modelAccessPrefix }} = {{= emptyProp }};
- wasDef = false;
-
- if (this._options.reactive !== false) {
- {{# def.addMsg }} '', type: 'added',
- newValue: m });
- }
- }
- {{??}}
- {{? method == 'splice' }}
- if (! m) {
- {{?}}
- m = {{# def.modelAccessPrefix }} = cloneTree(value);
- wasDef = typeof old != 'undefined';
- {{? method == 'splice' }}
- }
- {{?}}
- {{?}}
-
-
- {{ /* create model tree if it doesn't exist */ }}
- {{ var modelDataProperty = '';
- var nextNode = it.parsedPath[0];
- var count = it.parsedPath.length - 1;
-
- for (var i = 0; i < count; i++) {
- var currNode = nextNode;
- var currProp = currNode.property;
- nextNode = it.parsedPath[i + 1];
- var emptyProp = nextNode && nextNode.empty;
- }}
-
- {{# def.createTreeStep }}
-
- {{ } /* for loop */ }}
-#}}
-
-
-/**
- * Inserts code to create one step in the model tree
- */
-{{## def.createTreeStep:
- {{# def.changeAccessPath }}
-
- if (! {{# def.wasDefined }}) {
- {{ /* property does not exist */ }}
- m = m{{# def.currProp }} = {{= emptyProp }};
-
- if (this._options.reactive !== false) {
- {{# def.addMsg }} accessPath, type: 'added',
- newValue: m });
- }
-
- } else if (typeof m{{# def.currProp }} != 'object') {
- {{ /* property is not object */ }}
- var old = m{{# def.currProp }};
- m = m{{# def.currProp }} = {{= emptyProp }};
-
- if (this._options.reactive !== false) {
- {{# def.addMsg }} accessPath, type: 'changed',
- oldValue: old, newValue: m });
- }
-
- } else {
- {{ /* property exists, just traverse down the model tree */ }}
- m = m{{# def.currProp }};
- }
-#}}
diff --git a/lib/model/synthesize/defines.dot.js b/lib/model/synthesize/defines.dot.js
deleted file mode 100644
index 4f20e93..0000000
--- a/lib/model/synthesize/defines.dot.js
+++ /dev/null
@@ -1,69 +0,0 @@
-'use strict';
-/* Only use this style of comments, not "//" */
-
-/**
- * Inserts initialization code
- */
- {{## def.initVars:method:
- var m = {{# def.modelAccessPrefix }};
- var messages = [], messagesHash = {};
- var accessPath = '';
- var treeDoesNotExist;
- /* hack to prevent sending finished events to allow for propagation of batches without splitting them */
- var inChangeTransaction = getTransactionFlag( {{= method }} );
- #}}
-
-/**
- * Inserts the beginning of function call to add message to list
- */
-{{## def.addMsg: addChangeMessage(messages, messagesHash, { path: #}}
-
-/**
- * Inserts current property/index for both normal and interpolated properties/indexes
- */
-{{## def.currProp:{{? currNode.interpolate }}[this._args[ {{= currNode.interpolate }} ]]{{??}}{{= currProp }}{{?}} #}}
-
-/**
- * Inserts condition to test whether normal/interpolated property/index exists
- */
-{{## def.wasDefined: m.hasOwnProperty(
- {{? currNode.interpolate }}
- this._args[ {{= currNode.interpolate }} ]
- {{??}}
- '{{= it.getPathNodeKey(currNode) }}'
- {{?}}
-) #}}
-
-
-/**
- * Inserts code to update access path for current property
- * Because of the possibility of interpolated properties, it can't be calculated in template, it can only be calculated during accessor call.
- */
-{{## def.changeAccessPath:
- accessPath += {{? currNode.interpolate }}
- {{? currNode.syntax == 'array' }}
- '[' + this._args[ {{= currNode.interpolate }} ] + ']';
- {{??}}
- '.' + this._args[ {{= currNode.interpolate }} ];
- {{?}}
- {{??}}
- '{{= currProp }}';
- {{?}}
-#}}
-
-
-/**
- * Inserts code to post stored messages
- */
-{{## def.postMessages:
- if (messages.length) {
- {{# def.modelPostBatchCode }}('datachanges', {
- changes: messages,
- transaction: inChangeTransaction
- });
-
- messages.forEach(function(msg) {
- {{# def.modelPostMessageCode }}(msg.path, msg);
- }, this);
- }
-#}}
diff --git a/lib/model/synthesize/delete.dot.js b/lib/model/synthesize/delete.dot.js
deleted file mode 100644
index 246c5ad..0000000
--- a/lib/model/synthesize/delete.dot.js
+++ /dev/null
@@ -1,41 +0,0 @@
-'use strict';
-/* Only use this style of comments, not "//" */
-
-{{# def.include_defines }}
-{{# def.include_traverse_tree }}
-
-method = function del() {
- {{# def.initVars:'del' }}
-
- {{? it.parsedPath.length }}
- {{# def.traverseTree }}
-
- {{
- var currNode = it.parsedPath[count];
- var currProp = currNode.property;
- }}
-
- if (! treeDoesNotExist && m && m.hasOwnProperty && {{# def.wasDefined}}) {
- var old = m{{# def.currProp }};
- delete m{{# def.currProp }};
- {{# def.changeAccessPath }}
- var didDelete = true;
- }
- {{??}}
- if (typeof m != 'undefined') {
- var old = m;
- {{# def.modelAccessPrefix }} = undefined;
- var didDelete = true;
- }
- {{?}}
-
- if (didDelete && this._options.reactive !== false) {
- {{# def.addMsg }} accessPath, type: 'deleted', oldValue: old });
-
- addTreeChangesMessages(messages, messagesHash,
- accessPath, old, undefined); /* defined in the function that synthesizes ModelPath setter */
-
- {{ /* post all stored messages */ }}
- {{# def.postMessages }}
- }
-};
diff --git a/lib/model/synthesize/getter.dot.js b/lib/model/synthesize/getter.dot.js
deleted file mode 100644
index 42fad41..0000000
--- a/lib/model/synthesize/getter.dot.js
+++ /dev/null
@@ -1,12 +0,0 @@
-'use strict';
-/* Only use this style of comments, not "//" */
-
-method = function get() {
- var m = {{# def.modelAccessPrefix }};
- return m {{~ it.parsedPath :pathNode }}
- {{? pathNode.interpolate}}
- && (m = m[this._args[ {{= pathNode.interpolate }} ]])
- {{??}}
- && (m = m{{= pathNode.property }})
- {{?}} {{~}};
-};
diff --git a/lib/model/synthesize/index.js b/lib/model/synthesize/index.js
deleted file mode 100644
index e27fca0..0000000
--- a/lib/model/synthesize/index.js
+++ /dev/null
@@ -1,203 +0,0 @@
-'use strict';
-
-var pathUtils = require('../path_utils')
- , modelUtils = require('../model_utils')
- , logger = require('../../util/logger')
- , miloCount = require('../../util/count')
- , fs = require('fs')
- , doT = require('dot')
- , _ = require('mol-proto')
- , changeDataHandler = require('../change_data')
- , getTransactionFlag = changeDataHandler.getTransactionFlag
- , postTransactionFinished = changeDataHandler.postTransactionFinished;
-
-
-/**
- * Templates to synthesize model getters and setters
- */
-var templates = {
- get: fs.readFileSync(__dirname + '/getter.dot.js'),
- set: fs.readFileSync(__dirname + '/setter.dot.js'),
- del: fs.readFileSync(__dirname + '/delete.dot.js'),
- splice: fs.readFileSync(__dirname + '/splice.dot.js')
-};
-
-var include_defines = fs.readFileSync(__dirname + '/defines.dot.js')
- , include_create_tree = fs.readFileSync(__dirname + '/create_tree.dot.js')
- , include_traverse_tree = fs.readFileSync(__dirname + '/traverse_tree.dot.js');
-
-var dotDef = {
- include_defines: include_defines,
- include_create_tree: include_create_tree,
- include_traverse_tree: include_traverse_tree,
- getPathNodeKey: pathUtils.getPathNodeKey,
- modelAccessPrefix: 'this._model._data',
- modelPostMessageCode: 'this._model._internalMessenger.postMessage',
- modelPostBatchCode: 'this._model.postMessageSync',
- internalMessenger: 'this._model._internalMessenger'
-};
-
-var modelDotDef = _(dotDef).clone().extend({
- modelAccessPrefix: 'this._data',
- modelPostMessageCode: 'this._internalMessenger.postMessage',
- modelPostBatchCode: 'this.postMessageSync',
- internalMessenger: 'this._internalMessenger'
-})._();
-
-
-var dotSettings = _.clone(doT.templateSettings);
-dotSettings.strip = false;
-
-var synthesizers = _.mapKeys(templates, function(tmpl) {
- return doT.template(tmpl, dotSettings, dotDef);
-});
-
-
-var modelSynthesizers = _.mapToObject(['set', 'del', 'splice'], function(methodName) {
- return doT.template(templates[methodName], dotSettings, modelDotDef);
-});
-
-
-/**
- * Function that synthesizes accessor methods.
- * Function is memoized so accessors are cached (up to 1000).
- *
- * @param {String} path Model/ModelPath access path
- * @param {Array} parsedPath array of path nodes
- * @return {Object[Function]}
- */
-var synthesizePathMethods = _.memoize(_synthesizePathMethods, undefined, 1000);
-
-function _synthesizePathMethods(path, parsedPath) {
- var methods = _.mapKeys(synthesizers, function(synthszr) {
- return _synthesize(synthszr, path, parsedPath);
- });
- return methods;
-}
-
-
-var normalizeSpliceIndex = modelUtils.normalizeSpliceIndex; // used in splice.dot.js
-
-
-function _synthesize(synthesizer, path, parsedPath) {
- var method
- , methodCode = synthesizer({
- parsedPath: parsedPath,
- getPathNodeKey: pathUtils.getPathNodeKey
- });
-
- try {
- eval(methodCode);
- } catch (e) {
- throw ModelError('ModelPath method compilation error; path: ' + path + ', code: ' + methodCode);
- }
-
- return method;
-
-
- // functions used by methods `set`, `delete` and `splice` (synthesized by template)
- function addChangeMessage(messages, messagesHash, msg) {
- messages.push(msg);
- messagesHash[msg.path] = msg;
- }
-
- function addTreeChangesMessages(messages, messagesHash, rootPath, oldValue, newValue) {
- var oldIsTree = valueIsTree(oldValue)
- , newIsTree = valueIsTree(newValue);
-
- if (newIsTree)
- addMessages(messages, messagesHash, rootPath, newValue, 'added', 'newValue');
-
- if (oldIsTree)
- addMessages(messages, messagesHash, rootPath, oldValue, 'removed', 'oldValue');
- }
-
- function addMessages(messages, messagesHash, rootPath, obj, msgType, valueProp) {
- _addMessages(rootPath, obj);
-
-
- function _addMessages(rootPath, obj) {
- if (Array.isArray(obj)) {
- var pathSyntax = rootPath + '[$$]';
- obj.forEach(function(value, index) {
- addMessage(value, index, pathSyntax);
- });
- } else {
- var pathSyntax = rootPath + '.$$';
- _.eachKey(obj, function(value, key) {
- addMessage(value, key, pathSyntax);
- });
- }
- }
-
- function addMessage(value, key, pathSyntax) {
- var path = pathSyntax.replace('$$', key)
- , existingMsg = messagesHash[path];
-
- if (existingMsg) {
- if (existingMsg.type == msgType)
- logger.error('setter error: same message type posted on the same path');
- else {
- existingMsg.type = 'changed';
- existingMsg[valueProp] = value;
- }
- } else {
- var msg = { path: path, type: msgType };
- msg[valueProp] = value;
- addChangeMessage(messages, messagesHash, msg);
- }
-
- if (valueIsTree(value))
- _addMessages(path, value);
- }
- }
-
- function cloneTree(value) {
- return valueIsNormalObject(value)
- ? _.deepClone(value)
- : value;
- }
-
- function protectValue(value) {
- return ! valueIsNormalObject(value)
- ? value
- : Array.isArray(value)
- ? value.slice()
- : Object.create(value);
- }
-
- function valueIsTree(value) {
- return valueIsNormalObject(value)
- && Object.keys(value).length;
- }
-
- function valueIsNormalObject(value) {
- return value != null
- && typeof value == "object"
- && ! (value instanceof Date)
- && ! (value instanceof RegExp);
- }
-
- function addBatchIdsToMessage(msg, batchId, msgId) {
- _.defineProperties(msg, {
- __batch_id: batchId,
- __msg_id: msgId
- });
- }
-}
-
-
-/**
- * Exports `synthesize` function with the following:
- *
- * - .modelMethods.set - `set` method for Model
- * - .modelMethods.del - `del` method for Model
- * - .modelMethods.splice - `splice` method for Model
- */
-module.exports = synthesizePathMethods;
-
-var modelMethods = _.mapKeys(modelSynthesizers, function(synthesizer) {
- return _synthesize(synthesizer, '', []);
-});
-
-synthesizePathMethods.modelMethods = modelMethods;
diff --git a/lib/model/synthesize/setter.dot.js b/lib/model/synthesize/setter.dot.js
deleted file mode 100644
index 25f42c3..0000000
--- a/lib/model/synthesize/setter.dot.js
+++ /dev/null
@@ -1,49 +0,0 @@
-'use strict';
-/* Only use this style of comments, not "//" */
-
-{{# def.include_defines }}
-{{# def.include_create_tree }}
-
-
-/**
- * Template that synthesizes setter for Model and for ModelPath
- */
-method = function set(value) {
- {{# def.initVars:'set' }}
-
- {{# def.createTree:'set' }}
-
- {{
- currNode = nextNode;
- currProp = currNode && currNode.property;
- }}
-
- {{ /* assign value to the last property */ }}
- {{? currProp }}
- wasDef = {{# def.wasDefined}};
- {{# def.changeAccessPath }}
-
- var old = m{{# def.currProp }};
-
- {{ /* clone value to prevent same reference in linked models */ }}
- m{{# def.currProp }} = cloneTree(value);
- {{?}}
-
- {{ /* add message related to the last property change */ }}
- if (this._options.reactive !== false) {
- if (! wasDef)
- {{# def.addMsg }} accessPath, type: 'added',
- newValue: value });
- else if (old != value)
- {{# def.addMsg }} accessPath, type: 'changed',
- oldValue: old, newValue: value });
-
- {{ /* add message related to changes in (sub)properties inside removed and assigned value */ }}
- if (! wasDef || old != value)
- addTreeChangesMessages(messages, messagesHash,
- accessPath, old, value); /* defined in the function that synthesizes ModelPath setter */
-
- {{ /* post all stored messages */ }}
- {{# def.postMessages }}
- }
-};
diff --git a/lib/model/synthesize/splice.dot.js b/lib/model/synthesize/splice.dot.js
deleted file mode 100644
index 5b26407..0000000
--- a/lib/model/synthesize/splice.dot.js
+++ /dev/null
@@ -1,91 +0,0 @@
-'use strict';
-/* Only use this style of comments, not "//" */
-
-{{# def.include_defines }}
-{{# def.include_create_tree }}
-{{# def.include_traverse_tree }}
-
-method = function splice(spliceIndex, spliceHowMany) { /* ,... - extra arguments to splice into array */
- {{# def.initVars:'splice' }}
-
- var argsLen = arguments.length;
- var addItems = argsLen > 2;
-
- if (addItems) {
- {{ /* only create model tree if items are inserted in array */ }}
-
- {{ /* if model is undefined it will be set to an empty array */ }}
- var value = [];
- {{# def.createTree:'splice' }}
-
- {{? nextNode }}
- {{
- var currNode = nextNode;
- var currProp = currNode.property;
- var emptyProp = '[]';
- }}
-
- {{# def.createTreeStep }}
- {{?}}
-
- } else if (spliceHowMany > 0) {
- {{ /* if items are not inserted, only traverse model tree if items are deleted from array */ }}
- {{? it.parsedPath.length }}
- {{# def.traverseTree }}
-
- {{
- var currNode = it.parsedPath[count];
- var currProp = currNode.property;
- }}
-
- {{ /* extra brace closes 'else' in def.traverseTreeStep */ }}
- {{# def.traverseTreeStep }} }
- {{?}}
- }
-
- {{ /* splice items */ }}
- if (addItems || (! treeDoesNotExist && m
- && m.length > spliceIndex ) ) {
- var oldLength = m.length = m.length || 0;
-
- arguments[0] = spliceIndex = normalizeSpliceIndex(spliceIndex, m.length);
-
- {{ /* clone added arguments to prevent same references in linked models */ }}
- if (addItems)
- for (var i = 2; i < argsLen; i++)
- arguments[i] = cloneTree(arguments[i]);
-
- {{ /* actual splice call */ }}
- var removed = Array.prototype.splice.apply(m, arguments);
-
- if (this._options.reactive !== false) {
- {{# def.addMsg }} accessPath, type: 'splice',
- index: spliceIndex, removed: removed, addedCount: addItems ? argsLen - 2 : 0,
- newValue: m });
-
- if (removed && removed.length)
- removed.forEach(function(item, index) {
- var itemPath = accessPath + '[' + (spliceIndex + index) + ']';
- {{# def.addMsg }} itemPath, type: 'removed', oldValue: item });
-
- if (valueIsTree(item))
- addMessages(messages, messagesHash, itemPath, item, 'removed', 'oldValue');
- });
-
- if (addItems)
- for (var i = 2; i < argsLen; i++) {
- var item = arguments[i];
- var itemPath = accessPath + '[' + (spliceIndex + i - 2) + ']';
- {{# def.addMsg }} itemPath, type: 'added', newValue: item });
-
- if (valueIsTree(item))
- addMessages(messages, messagesHash, itemPath, item, 'added', 'newValue');
- }
-
- {{ /* post all stored messages */ }}
- {{# def.postMessages }}
- }
- }
-
- return removed || [];
-}
diff --git a/lib/model/synthesize/traverse_tree.dot.js b/lib/model/synthesize/traverse_tree.dot.js
deleted file mode 100644
index 63c66d5..0000000
--- a/lib/model/synthesize/traverse_tree.dot.js
+++ /dev/null
@@ -1,37 +0,0 @@
-'use strict';
-/* Only use this style of comments, not "//" */
-
-/**
- * Inserts code to traverse model tree for `delete` and `splice` accessors.
- */
-{{## def.traverseTree:
- {{
- var count = it.parsedPath.length-1;
-
- for (var i = 0; i < count; i++) {
- var currNode = it.parsedPath[i];
- var currProp = currNode.property;
- }}
- {{# def.traverseTreeStep }}
-
- {{ } /* for loop */
-
- var i = count;
- while (i--) { /* closing braces for else's above */
- }}
- }
- {{ } /* while loop */ }}
-#}}
-
-
-/**
- * Inserts code to traverse one step in the model tree
- */
-{{## def.traverseTreeStep:
- if (! (m && m.hasOwnProperty && {{# def.wasDefined}} ) )
- treeDoesNotExist = true;
- else {
- m = m{{# def.currProp }};
- {{# def.changeAccessPath }}
- {{ /* brace from else is not closed on purpose - all braces are closed in while loop */ }}
-#}}
diff --git a/lib/services/de_constrs.js b/lib/services/de_constrs.js
index e1b6854..2679d1b 100644
--- a/lib/services/de_constrs.js
+++ b/lib/services/de_constrs.js
@@ -4,7 +4,7 @@
// ###dom events constructors
-var _ = require('mol-proto');
+var _ = require('milo-core').proto;
// https://developer.mozilla.org/en-US/docs/Web/Reference/Events
diff --git a/lib/services/dom_source.js b/lib/services/dom_source.js
index 56b9a99..abb610b 100644
--- a/lib/services/dom_source.js
+++ b/lib/services/dom_source.js
@@ -1,11 +1,12 @@
'use strict';
-var MessageSource = require('../messenger/m_source')
+var miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
, Component = require('../components/c_class')
, domEventsConstructors = require('./de_constrs') // TODO merge with DOMEventSource ??
- , _ = require('mol-proto')
- , check = require('../util/check')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
var DOMEmitterSource = _.createSubclass(MessageSource, 'DOMEmitterSource', true);
diff --git a/lib/services/mail/index.js b/lib/services/mail/index.js
index 0f0cbd2..fc58882 100644
--- a/lib/services/mail/index.js
+++ b/lib/services/mail/index.js
@@ -14,10 +14,11 @@
**/
-var Messenger = require('../../messenger')
+var miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
, MailMsgAPI = require('./mail_api')
, MailMessageSource = require('./mail_source')
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
var miloMail = new Messenger;
diff --git a/lib/services/mail/mail_api.js b/lib/services/mail/mail_api.js
index 19902b2..af5f343 100644
--- a/lib/services/mail/mail_api.js
+++ b/lib/services/mail/mail_api.js
@@ -1,8 +1,9 @@
'use strict';
-var MessengerAPI = require('../../messenger/m_api')
- , _ = require('mol-proto')
- , check = require('../../util/check')
+var miloCore = require('milo-core')
+ , MessengerAPI = miloCore.classes.MessengerAPI
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
diff --git a/lib/services/mail/mail_source.js b/lib/services/mail/mail_source.js
index abf78f1..6b8ca7a 100644
--- a/lib/services/mail/mail_source.js
+++ b/lib/services/mail/mail_source.js
@@ -1,10 +1,10 @@
'use strict';
-var MessageSource = require('../../messenger/m_source')
+var miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
, domEventsConstructors = require('../de_constrs')
- , MailMessageSourceError = require('../../util/error').MailMessageSource
- , _ = require('mol-proto')
- , check = require('../../util/check')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
diff --git a/lib/services/window.js b/lib/services/window.js
index 30ff77f..5784b7c 100644
--- a/lib/services/window.js
+++ b/lib/services/window.js
@@ -1,8 +1,10 @@
'use strict';
-var Messenger = require('../messenger')
- , DOMEmitterSource = require('./dom_source');
+var miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
+ , DOMEmitterSource = require('./dom_source')
+ , _ = miloCore.proto;
var windowService = new Messenger;
diff --git a/lib/util/check.js b/lib/util/check.js
deleted file mode 100644
index cfadb2e..0000000
--- a/lib/util/check.js
+++ /dev/null
@@ -1,374 +0,0 @@
-'use strict';
-
-/**
- * `milo.utils.check`
- *
- * Check is a module for parameters checking extracted from [Meteor](http://docs.meteor.com/) framework.
- *
- * It allows to both document and to check parameter types in your function
- * making code both readable and stable.
- *
- *
- * ### Usage
- *```
- * var check = milo.check
- * , Match = check.Match;
- *
- * function My(name, obj, cb) {
- * // if any of checks fail an error will be thrown
- * check(name, String);
- * check(obj, Match.ObjectIncluding({ options: Object }));
- * check(cb, Function);
- *
- * // ... your code
- * }
- *```
- * See [Meteor docs](http://docs.meteor.com/#match) to see how it works
- *
- *
- * ### Patterns
- *
- * All patterns and functions described in Meteor docs work.
- *
- * Unlike in Meteor, Object pattern matches instance of any class,
- * not only plain object.
- *
- * In addition to patterns described in Meteor docs the following patterns are implemented
- *
- * * Match.__ObjectHash__(_pattern_)
- *
- * Matches an object where all properties match a given pattern
- *
- * * Match.__Subclass__(_constructor_ [, _matchThisClassToo_])
- *
- * Matches a class that is a subclass of a given class. If the second parameter
- * is true, it will also match the class itself.
- *
- * Without this pattern to check if _MySubclass_ is a subclass of _MyClass_
- * you would have to use
- *
- * check(MySubclass, Match.Where(function() {
- * return MySubclass.prototype instanceof MyClass;
- * });
- *
- *
- * Things we explicitly do NOT support:
- * - heterogenous arrays
-**/
-
-var _ = require('mol-proto')
- , config = require('../config');
-
-var check = function (value, pattern) {
- if (config.check === false)
- return;
-
- // Record that check got called, if somebody cared.
- try {
- checkSubtree(value, pattern);
- } catch (err) {
- if ((err instanceof Match.Error) && err.path)
- err.message += " in field " + err.path;
- throw err;
- }
-};
-
-module.exports = check;
-
-var Match = check.Match = {
- Optional: function (pattern) {
- return new Optional(pattern);
- },
- OneOf: function (/* arguments */) {
- return new OneOf(arguments);
- },
- Any: ['__any__'],
- Where: function (condition) {
- return new Where(condition);
- },
- ObjectIncluding: function (pattern) {
- return new ObjectIncluding(pattern);
- },
- // Matches only signed 32-bit integers
- Integer: ['__integer__'],
-
- // Matches string that is a valid identifier, will not allow javascript reserved words
- IdentifierString: /^[a-z_$][0-9a-z_$]*$/i,
-
- // Matches hash (object) with values matching pattern
- ObjectHash: function(pattern) {
- return new ObjectHash(pattern);
- },
-
- Subclass: function(Superclass, matchSuperclassToo) {
- return new Subclass(Superclass, matchSuperclassToo);
- },
-
- // XXX matchers should know how to describe themselves for errors
- Error: TypeError,
-
- // Meteor.makeErrorType("Match.Error", function (msg) {
- // this.message = "Match error: " + msg;
- // The path of the value that failed to match. Initially empty, this gets
- // populated by catching and rethrowing the exception as it goes back up the
- // stack.
- // E.g.: "vals[3].entity.created"
- // this.path = "";
- // If this gets sent over DDP, don't give full internal details but at least
- // provide something better than 500 Internal server error.
- // this.sanitizedError = new Meteor.Error(400, "Match failed");
- // }),
-
- // Tests to see if value matches pattern. Unlike check, it merely returns true
- // or false (unless an error other than Match.Error was thrown).
- test: function (value, pattern) {
- try {
- checkSubtree(value, pattern);
- return true;
- } catch (e) {
- if (e instanceof Match.Error)
- return false;
- // Rethrow other errors.
- throw e;
- }
- }
-};
-
-function Optional(pattern) {
- this.pattern = pattern;
-};
-
-function OneOf(choices) {
- if (choices.length == 0)
- throw new Error("Must provide at least one choice to Match.OneOf");
- this.choices = choices;
-};
-
-function Where(condition) {
- this.condition = condition;
-};
-
-function ObjectIncluding(pattern) {
- this.pattern = pattern;
-};
-
-function ObjectHash(pattern) {
- this.pattern = pattern;
-};
-
-function Subclass(Superclass, matchSuperclassToo) {
- this.Superclass = Superclass;
- this.matchSuperclass = matchSuperclassToo;
-};
-
-var typeofChecks = [
- [String, "string"],
- [Number, "number"],
- [Boolean, "boolean"],
- [Function, "function"],
- // While we don't allow undefined in JSON, this is good for optional
- // arguments with OneOf.
- [undefined, "undefined"]
-];
-
-function checkSubtree(value, pattern) {
- // Match anything!
- if (pattern === Match.Any)
- return;
-
- // Basic atomic types.
- // Do not match boxed objects (e.g. String, Boolean)
- for (var i = 0; i < typeofChecks.length; ++i) {
- if (pattern === typeofChecks[i][0]) {
- if (typeof value === typeofChecks[i][1])
- return;
- throw new Match.Error("Expected " + typeofChecks[i][1] + ", got " +
- typeof value);
- }
- }
- if (pattern === null) {
- if (value === null)
- return;
- throw new Match.Error("Expected null, got " + JSON.stringify(value));
- }
-
- // Match.Integer is special type encoded with array
- if (pattern === Match.Integer) {
- // There is no consistent and reliable way to check if variable is a 64-bit
- // integer. One of the popular solutions is to get reminder of division by 1
- // but this method fails on really large floats with big precision.
- // E.g.: 1.348192308491824e+23 % 1 === 0 in V8
- // Bitwise operators work consistantly but always cast variable to 32-bit
- // signed integer according to JavaScript specs.
- if (typeof value === 'number' && (value | 0) === value)
- return
- throw new Match.Error('Expected Integer, got '
- + (value instanceof Object ? JSON.stringify(value) : value));
- }
-
- if (pattern === Match.IdentifierString) {
- if (typeof value === 'string' && Match.IdentifierString.test(value)
- && _jsKeywords.indexOf(key) == -1)
- return;
- throw new Match.Error('Expected identifier string, got '
- + (value instanceof Object ? JSON.stringify(value) : value));
- }
-
- // "Object" is shorthand for Match.ObjectIncluding({});
- if (pattern === Object)
- pattern = Match.ObjectIncluding({});
-
- // Array (checked AFTER Any, which is implemented as an Array).
- if (pattern instanceof Array) {
- if (pattern.length !== 1)
- throw Error("Bad pattern: arrays must have one type element" +
- JSON.stringify(pattern));
- if (!Array.isArray(value)) {
- throw new Match.Error("Expected array, got " + JSON.stringify(value));
- }
-
- value.forEach(function (valueElement, index) {
- try {
- checkSubtree(valueElement, pattern[0]);
- } catch (err) {
- if (err instanceof Match.Error) {
- err.path = _prependPath(index, err.path);
- }
- throw err;
- }
- });
- return;
- }
-
- // Arbitrary validation checks. The condition can return false or throw a
- // Match.Error (ie, it can internally use check()) to fail.
- if (pattern instanceof Where) {
- if (pattern.condition(value))
- return;
- // XXX this error is terrible
- throw new Match.Error("Failed Match.Where validation");
- }
-
-
- if (pattern instanceof Optional)
- pattern = Match.OneOf(undefined, pattern.pattern);
-
- if (pattern instanceof OneOf) {
- for (var i = 0; i < pattern.choices.length; ++i) {
- try {
- checkSubtree(value, pattern.choices[i]);
- // No error? Yay, return.
- return;
- } catch (err) {
- // Other errors should be thrown. Match errors just mean try another
- // choice.
- if (!(err instanceof Match.Error))
- throw err;
- }
- }
- // XXX this error is terrible
- throw new Match.Error("Failed Match.OneOf or Match.Optional validation");
- }
-
- // A function that isn't something we special-case is assumed to be a
- // constructor.
- if (pattern instanceof Function) {
- if (value instanceof pattern)
- return;
- // XXX what if .name isn't defined
- throw new Match.Error("Expected " + pattern.constructor.name);
- }
-
- var unknownKeysAllowed = false;
- if (pattern instanceof ObjectIncluding) {
- unknownKeysAllowed = true;
- pattern = pattern.pattern;
- }
-
- if (pattern instanceof ObjectHash) {
- var keyPattern = pattern.pattern;
- var emptyHash = true;
- for (var key in value) {
- emptyHash = false;
- check(value[key], keyPattern);
- }
- if (emptyHash)
- throw new Match.Error("Expected " + pattern.constructor.name);
- return;
- }
-
- if (pattern instanceof Subclass) {
- var Superclass = pattern.Superclass;
- if (pattern.matchSuperclass && value == Superclass)
- return;
- if (! (value.prototype instanceof Superclass))
- throw new Match.Error("Expected " + pattern.constructor.name + " of " + Superclass.name);
- return;
- }
-
- if (typeof pattern !== "object")
- throw Error("Bad pattern: unknown pattern type");
-
- // An object, with required and optional keys. Note that this does NOT do
- // structural matches against objects of special types that happen to match
- // the pattern: this really needs to be a plain old {Object}!
- if (typeof value !== 'object')
- throw new Match.Error("Expected object, got " + typeof value);
- if (value === null)
- throw new Match.Error("Expected object, got null");
-
- var requiredPatterns = {};
- var optionalPatterns = {};
-
- _.eachKey(pattern, function(subPattern, key) {
- if (pattern[key] instanceof Optional)
- optionalPatterns[key] = pattern[key].pattern;
- else
- requiredPatterns[key] = pattern[key];
- }, this, true);
-
- _.eachKey(value, function(subValue, key) {
- var subValue = value[key];
- try {
- if (requiredPatterns.hasOwnProperty(key)) {
- checkSubtree(subValue, requiredPatterns[key]);
- delete requiredPatterns[key];
- } else if (optionalPatterns.hasOwnProperty(key)) {
- checkSubtree(subValue, optionalPatterns[key]);
- } else {
- if (!unknownKeysAllowed)
- throw new Match.Error("Unknown key");
- }
- } catch (err) {
- if (err instanceof Match.Error)
- err.path = _prependPath(key, err.path);
- throw err;
- }
- }, this, true);
-
- _.eachKey(requiredPatterns, function(value, key) {
- throw new Match.Error("Missing key '" + key + "'");
- }, this, true);
-};
-
-
-var _jsKeywords = ["do", "if", "in", "for", "let", "new", "try", "var", "case",
- "else", "enum", "eval", "false", "null", "this", "true", "void", "with",
- "break", "catch", "class", "const", "super", "throw", "while", "yield",
- "delete", "export", "import", "public", "return", "static", "switch",
- "typeof", "default", "extends", "finally", "package", "private", "continue",
- "debugger", "function", "arguments", "interface", "protected", "implements",
- "instanceof"];
-
-// Assumes the base of path is already escaped properly
-// returns key + base
-function _prependPath(key, base) {
- if ((typeof key) === "number" || key.match(/^[0-9]+$/))
- key = "[" + key + "]";
- else if (!key.match(Match.IdentifierString) || _jsKeywords.indexOf(key) != -1)
- key = JSON.stringify([key]);
-
- if (base && base[0] !== "[")
- return key + '.' + base;
- return key + base;
-};
diff --git a/lib/util/create_component_class.js b/lib/util/create_component_class.js
index 88bbd55..bdb63fd 100644
--- a/lib/util/create_component_class.js
+++ b/lib/util/create_component_class.js
@@ -1,5 +1,8 @@
'use strict';
+var _ = require('milo-core').proto;
+
+
module.exports = createComponentClass;
/**
@@ -32,4 +35,4 @@ function createComponentClass(config) {
componentRegistry.add(ComponentClass);
return ComponentClass;
-}
\ No newline at end of file
+}
diff --git a/lib/util/dom.js b/lib/util/dom.js
index 007642f..6848510 100644
--- a/lib/util/dom.js
+++ b/lib/util/dom.js
@@ -2,8 +2,9 @@
var config = require('../config')
- , _ = require('mol-proto')
- , logger = require('./logger');
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger;
var domUtils = {
children: children,
diff --git a/lib/util/dom_listeners.js b/lib/util/dom_listeners.js
index a8913d8..d3efd7a 100644
--- a/lib/util/dom_listeners.js
+++ b/lib/util/dom_listeners.js
@@ -1,8 +1,7 @@
'use strict';
-var _ = require('mol-proto')
- , check = require('./check');
+var _ = require('milo-core').proto;
module.exports = DOMListeners;
diff --git a/lib/util/domready.js b/lib/util/domready.js
index 00e96aa..3e6ec84 100644
--- a/lib/util/domready.js
+++ b/lib/util/domready.js
@@ -1,7 +1,7 @@
'use strict';
-var _ = require('mol-proto');
+var _ = require('milo-core').proto;
module.exports = domReady;
diff --git a/lib/util/dragdrop.js b/lib/util/dragdrop.js
index d5955a9..4d46ff6 100644
--- a/lib/util/dragdrop.js
+++ b/lib/util/dragdrop.js
@@ -1,11 +1,11 @@
'use strict';
var Component = require('../components/c_class')
- , Messenger = require('../messenger')
+ , miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
, dragDropConfig = require('../config').dragDrop
, componentMetaRegex = dragDropConfig.dataTypes.componentMetaRegex
- , jsonParse = require('./json_parse')
- , _ = require('mol-proto')
+ , _ = miloCore.proto
, base32 = require('base32');
@@ -66,7 +66,7 @@ function DragDrop$isComponent() {
function DragDrop$getComponentState() {
var dataType = DragDrop.componentDataType()
, stateStr = this.dataTransfer.getData(dataType)
- , state = jsonParse(stateStr);
+ , state = _.jsonParse(stateStr);
return state;
}
diff --git a/lib/util/error.js b/lib/util/error.js
index 4bc43c0..00bdf47 100644
--- a/lib/util/error.js
+++ b/lib/util/error.js
@@ -4,7 +4,7 @@
'use strict';
-var _ = require('mol-proto');
+var _ = require('milo-core').proto;
// module exports error classes for all names defined in this array
diff --git a/lib/util/fragment.js b/lib/util/fragment.js
index 6daae43..2c91805 100644
--- a/lib/util/fragment.js
+++ b/lib/util/fragment.js
@@ -5,9 +5,10 @@ var Component = require('../components/c_class')
, BindAttribute = require('../attributes/a_bind')
, binder = require('../binder')
, domUtils = require('./dom')
- , logger = require('./logger')
- , check = require('./check')
- , _ = require('mol-proto');
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , check = miloCore.util.check
+ , _ = miloCore.proto;
var createRangePaths = _createNodesAndPathsFunc(domUtils.treePathOf);
diff --git a/lib/util/index.js b/lib/util/index.js
index cc0bc49..0f92d49 100644
--- a/lib/util/index.js
+++ b/lib/util/index.js
@@ -1,14 +1,16 @@
'use strict';
+var miloCore = require('milo-core');
+
/**
* `milo.util`
*/
var util = {
- logger: require('./logger'),
+ logger: miloCore.util.logger,
request: require('./request'),
websocket: require('./websocket'),
- check: require('./check'),
- error: require('./error'),
+ check: miloCore.util.check,
+ error: require('./error'), // deprecated
count: require('./count'), // deprecated
uniqueId: require('./count'),
componentName: require('./component_name'),
@@ -16,13 +18,13 @@ var util = {
domListeners: require('./dom_listeners'),
selection: require('./selection'),
fragment: require('./fragment'),
- jsonParse: require('./json_parse'),
+ jsonParse: require('./json_parse'), // deprecated
storage: require('./storage'),
domReady: require('./domready'),
dragDrop: require('./dragdrop'),
- dialog: require('../components/ui/bootstrap/Dialog'),
- alert: require('../components/ui/bootstrap/Alert'),
- doT: require('dot'),
+ dialog: require('../components/ui/bootstrap/Dialog'), // deprecated - should be used from registry
+ alert: require('../components/ui/bootstrap/Alert'), // deprecated - should be used from registry
+ doT: miloCore.util.doT,
destroy: util_destroy
};
diff --git a/lib/util/logger.js b/lib/util/logger.js
deleted file mode 100644
index f65e483..0000000
--- a/lib/util/logger.js
+++ /dev/null
@@ -1,28 +0,0 @@
-'use strict';
-
-//
-// milo.utils.logger
-// -----------
-
-// Application logger that has error, warn, info and debug
-// methods, that can be suppressed by setting log level.
-
-// Properties:
-
-// - level
-
-// - 0 - error
-// - 1 - warn
-// - 2 - info
-// - 3 - debug (default)
-
-// - enabled
-
-// true by default. Set to false to disable all logging in browser console.
-
-
-var Logger = require('./logger_class');
-
-var logger = new Logger({ level: 3 });
-
-module.exports = logger;
diff --git a/lib/util/logger_class.js b/lib/util/logger_class.js
deleted file mode 100644
index efde224..0000000
--- a/lib/util/logger_class.js
+++ /dev/null
@@ -1,123 +0,0 @@
-'use strict';
-
-// ### Logger Class
-
-// Properties:
-
-// - level
-
-// - 0 - error
-// - 1 - warn
-// - 2 - info
-// - 3 - debug (default)
-
-// - enabled
-
-// true by default. Set to false to disable all logging in browser console.
-
-
-var _ = require('mol-proto');
-
-
-/**
- * Log levels.
- */
-
-var levels = [
- 'error',
- 'warn',
- 'info',
- 'debug'
-];
-
-var maxLevelLength = Math.max.apply(Math, levels.map(function(level) { return level.length; }));
-
-/**
- * Colors for log levels.
- */
-
-var colors = [
- 31,
- 33,
- 36,
- 90
-];
-
-/**
- * Pads the nice output to the longest log level.
- */
-function pad(str) {
- if (str.length < maxLevelLength)
- return str + new Array(maxLevelLength - str.length + 1).join(' ');
-
- return str;
-};
-
-
-function colored(str, color) {
- return '\x1B[' + color + 'm' + str + ' -\x1B[39m';
-}
-
-
-var DEFAULT_OPTIONS = {
- level: 3,
- throwLevel: -1, // never throw
- enabled: true,
- logPrefix: ''
-}
-
-
-/**
- * Logger (console).
- *
- * @api public
- */
-var Logger = function (opts) {
- _.extend(this, DEFAULT_OPTIONS);
- _.extend(this, opts || {});
-};
-
-
-/**
- * Log method.
- *
- * @api public
- */
-
-Logger.prototype.log = function (type) {
- var index = levels.indexOf(type);
-
- if (! this.enabled || index > this.level)
- return this;
-
- var args = _.slice(arguments, 1);
-
- if (index <= this.throwLevel)
- throw new Error([this.logPrefix, type + ':'].concat(args).join(' '));
-
- console.log.apply(
- console
- , [ this.logPrefixColor
- ? ' ' + colored(this.logPrefix, this.logPrefixColor)
- : this.logPrefix,
- (this.colors
- ? ' ' + colored(pad(type), colors[index])
- : type) + ':'
- ].concat(args)
- );
-
- return this;
-};
-
-/**
- * Generate methods.
- */
-
-levels.forEach(function (name) {
- Logger.prototype[name] = function () {
- this.log.apply(this, [name].concat(_.toArray(arguments)));
- };
-});
-
-
-module.exports = Logger;
diff --git a/lib/util/request.js b/lib/util/request.js
index 137c1ee..a9a6abb 100644
--- a/lib/util/request.js
+++ b/lib/util/request.js
@@ -21,11 +21,12 @@
// Only generic request and get, json, post convenience methods are currently implemented.
-var _ = require('mol-proto')
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
, count = require('./count')
, config = require('../config')
- , logger = require('./logger')
- , Messenger = require('../messenger');
+ , logger = miloCore.util.logger
+ , Messenger = miloCore.Messenger;
module.exports = request;
diff --git a/lib/util/selection/index.js b/lib/util/selection/index.js
index a4c5ae1..222371f 100644
--- a/lib/util/selection/index.js
+++ b/lib/util/selection/index.js
@@ -6,9 +6,10 @@ var domUtils = require('../dom')
, setCaretPosition = domUtils.setCaretPosition
, getComponentsFromRange = domUtils.getComponentsFromRange
, deleteRangeWithComponents = domUtils.deleteRangeWithComponents
- , logger = require('../logger')
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
, Component = require('../../components/c_class')
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
module.exports = TextSelection;
diff --git a/lib/util/storage/index.js b/lib/util/storage/index.js
index 7310062..4abafb4 100644
--- a/lib/util/storage/index.js
+++ b/lib/util/storage/index.js
@@ -1,13 +1,12 @@
'use strict';
-var DOMStorageError = require('../error').createClass('DomStorageError')
- , Messenger = require('../../messenger')
+var miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
, StorageMessageSource = require('./msg_src')
, config = require('../../config')
- , jsonParse = require('../json_parse')
- , _ = require('mol-proto')
- , check = require('../check')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
require('./model')
@@ -371,13 +370,13 @@ function _parseData(valueStr, valueType) {
: valueStr;
}
var dataParsers = {
- Object: jsonParse,
- Array: jsonParse,
+ Object: _.jsonParse,
+ Array: _.jsonParse,
Date: function(valStr) { return new Date(valStr); },
boolean: function(valStr) { return valStr == 'true'; },
- number: function(valStr) { return Number(valStr); },
- function: function(valStr) { return _.toFunction(valStr); },
- RegExp: function(valStr) { return _.toRegExp(valStr); }
+ number: Number,
+ function: _.toFunction,
+ RegExp: _.toRegExp
};
diff --git a/lib/util/storage/model.js b/lib/util/storage/model.js
index ff667bb..b9e694c 100644
--- a/lib/util/storage/model.js
+++ b/lib/util/storage/model.js
@@ -1,6 +1,8 @@
'use strict';
-var Model = require('milo-core').Model
+var miloCore = require('milo-core')
+ , Model = miloCore.Model
+ , _ = miloCore.proto;
Model.registerWithDOMStorage = Model$$registerWithDOMStorage;
diff --git a/lib/util/storage/msg_src.js b/lib/util/storage/msg_src.js
index 9487e8c..0e50783 100644
--- a/lib/util/storage/msg_src.js
+++ b/lib/util/storage/msg_src.js
@@ -1,11 +1,11 @@
'use strict';
-var MessageSource = require('../../messenger/m_source')
- , _ = require('mol-proto')
+var miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
+ , _ = miloCore.proto
, config = require('../../config')
- , miloCount = require('../../util/count')
- , StorageMessageSourceError = require('../../util/error').StorageMessageSource;
+ , miloCount = require('../../util/count');
var StorageMessageSource = _.createSubclass(MessageSource, 'StorageMessageSource', true);
@@ -27,7 +27,7 @@ module.exports = StorageMessageSource;
function init(hostObject, proxyMethods, messengerAPIOrClass) {
if (hostObject.constructor.name != 'DOMStorage')
- throw new StorageMessageSourceError('hostObject should be an instance of DOMStorage');
+ throw new Error('hostObject should be an instance of DOMStorage');
this.storage = hostObject;
this.messageKey = config.domStorage.messageKey;
this.window = hostObject.window;
diff --git a/lib/util/websocket/index.js b/lib/util/websocket/index.js
index e634725..deb7172 100644
--- a/lib/util/websocket/index.js
+++ b/lib/util/websocket/index.js
@@ -5,7 +5,7 @@
**/
-var Messenger = require('../../messenger')
+var Messenger = require('milo-core').Messenger
, WSMessageSource = require('./msg_src')
, WSMsgAPI = require('./msg_api');
diff --git a/lib/util/websocket/msg_api.js b/lib/util/websocket/msg_api.js
index e012f36..bb60453 100644
--- a/lib/util/websocket/msg_api.js
+++ b/lib/util/websocket/msg_api.js
@@ -1,8 +1,9 @@
'use strict';
-var MessengerAPI = require('../../messenger/m_api')
- , _ = require('mol-proto')
- , check = require('../../util/check')
+var miloCore = require('milo-core')
+ , MessengerAPI = miloCore.classes.MessengerAPI
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
diff --git a/lib/util/websocket/msg_src.js b/lib/util/websocket/msg_src.js
index 26001b3..5a61dc6 100644
--- a/lib/util/websocket/msg_src.js
+++ b/lib/util/websocket/msg_src.js
@@ -1,12 +1,13 @@
'use strict';
-var MessageSource = require('../../messenger/m_source')
- , _ = require('mol-proto')
- , logger = require('../../util/logger')
+var miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger
, uniqueId = require('../../util/count')
, config = require('../../config')
- , check = require('../../util/check')
+ , check = miloCore.util.check
, Match = check.Match;
diff --git a/milo.bundle.js b/milo.bundle.js
index 98ea807..80ff4fc 100644
--- a/milo.bundle.js
+++ b/milo.bundle.js
@@ -2,7 +2,7 @@
'use strict';
-var _ = require('mol-proto');
+var _ = require('milo-core').proto;
module.exports = Facet;
@@ -29,15 +29,15 @@ _.extendProto(Facet, {
init: function() {}
});
-},{"mol-proto":150}],2:[function(require,module,exports){
+},{"milo-core":105}],2:[function(require,module,exports){
'use strict';
var Facet = require('./facet')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , FacetError = require('../util/error').Facet;
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , Match = check.Match;
module.exports = FacetedObject;
@@ -63,7 +63,7 @@ function FacetedObject() {
// FacetedObject class itself is not meant to be instantiated - it has no facets
// It may change, as adding facets is possible to instances
if (this.constructor == FacetedObject)
- throw new FacetError('FacetedObject is an abstract class, can\'t be instantiated');
+ throw new Error('FacetedObject is an abstract class, can\'t be instantiated');
// instantiate class facets
if (this.facetsClasses)
@@ -142,7 +142,7 @@ function FacetedObject$addFacet(FacetClass, facetConfig, facetName, throwOnError
// check that this facetName was not already used in the class
if (protoFacets && protoFacets[facetName])
- throw new FacetError('facet ' + facetName + ' is already part of the class ' + this.constructor.name);
+ throw new Error('facet ' + facetName + ' is already part of the class ' + this.constructor.name);
// check that this faceName does not already exist on the faceted object
if (this[facetName]) {
@@ -150,7 +150,7 @@ function FacetedObject$addFacet(FacetClass, facetConfig, facetName, throwOnError
if (throwOnErrors === false)
return logger.error('FacetedObject addFacet: ', message);
else
- throw new FacetError(message);
+ throw new Error(message);
}
// instantiate the facet
@@ -208,7 +208,7 @@ function FacetedObject$$createFacetedClass(name, facetsClasses, facetsConfig) {
if (facetsConfig)
_.eachKey(facetsConfig, function(fctConfig, fctName) {
if (! facetsClasses.hasOwnProperty(fctName))
- throw new FacetError('configuration for facet (' + fctName + ') passed that is not in class');
+ throw new Error('configuration for facet (' + fctName + ') passed that is not in class');
});
// create subclass of the current class (this refers to the class that calls this method)
@@ -238,225 +238,12 @@ function FacetedObject$$createFacetedClass(name, facetsClasses, facetsConfig) {
}
};
-},{"../util/check":90,"../util/error":98,"./facet":1,"mol-proto":150}],3:[function(require,module,exports){
-'use strict';
-
-var _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , MixinError = require('../util/error').Mixin
- , config = require('../config');
-
-
-module.exports = Mixin;
-
-/**
- * `milo.classes.Mixin` - an abstract Mixin class.
- * Can be subclassed using:
- * ```
- * var MyMixin = _.createSubclass(milo.classes.Mixin, 'MyMixin');
- * ```
- *
- * Mixin pattern is also used, but Mixin in milo is implemented as a separate object that is stored on the property of the host object and can create proxy methods on the host object if required.
- * Classes [Messenger](../messenger/index.js.html) and [MessageSource](../messenger/m_source.js.html) are subclasses of Mixin abstract class. `this` in proxy methods refers to Mixin instance, the reference to the host object is `this._hostObject`.
- *
- * @param {Object} hostObject Optional object where a Mixin instance will be stored on. It is used to proxy methods and also to find the reference when it is needed for host object implementation.
- * @param {Object} proxyMethods Optional map of proxy method names as keys and Mixin methods names as values, so proxied methods can be renamed to avoid name-space conflicts if two different Mixin instances with the same method names are put on the object
- * @param {List} arguments all constructor arguments will be passed to init method of Mixin subclass together with hostObject and proxyMethods
- * @return {Mixin}
- */
-function Mixin(hostObject, proxyMethods) { // , other args - passed to init method
- check(hostObject, Match.Optional(Match.OneOf(Object, Function)));
-
- // store hostObject
- _.defineProperty(this, '_hostObject', hostObject);
-
- // proxy methods to hostObject
- if (proxyMethods)
- this._createProxyMethods(proxyMethods);
-
- // calling init if it is defined in the class
- if (this.init)
- this.init.apply(this, arguments);
-}
-
-
-/**
- * ####Mixin instance methods####
- * These methods are called by constructor, they are not to be called from subclasses.
- *
- * - [_createProxyMethod](#_createProxyMethod)
- * - [_createProxyMethods](#_createProxyMethods)
- */
-_.extendProto(Mixin, {
- _createProxyMethod: _createProxyMethod, // deprecated, should not be used
- _createProxyMethods: _createProxyMethods // deprecated, should not be used
-});
-
-
-/**
- * ####Mixin class methods####
- * These method should be called in host class declaration.
- *
- * - [useWith](#Mixin$$useWith)
- */
-_.extend(Mixin, {
- useWith: Mixin$$useWith
-});
-
-
-/**
- * Creates a proxied method of Mixin subclass on host object.
- *
- * @param {String} mixinMethodName name of method in Mixin subclass
- * @param {String} proxyMethodName name of created proxy method on host object
- * @param {Object} hostObject Optional reference to the host object; if not specified the host object passed to constructor wil be used. It allows to use the same instance of Mixin on two host objects.
- */
-function _createProxyMethod(proxyMethodName, mixinMethodName, hostObject) {
- hostObject = hostObject || this._hostObject;
-
- // Mixin class does not allow shadowing methods that exist on the host object
- if (hostObject[proxyMethodName])
- throw new MixinError('method ' + proxyMethodName +
- ' already defined in host object');
-
- var method = this[mixinMethodName]
- check(method, Function);
-
- // Bind proxied Mixin's method to Mixin instance
- var boundMethod = method.bind(this);
-
- _.defineProperty(hostObject, proxyMethodName, boundMethod, _.WRIT);
-}
-
-
-/**
- * Creates proxied methods of Mixin subclass on host object.
- *
- * @param {Hash[String]|Array[String]} proxyMethods map of names of methods, key - proxy method name, value - mixin method name. Can be array.
- * @param {Object} hostObject an optional reference to the host object; if not specified the host object passed to constructor wil be used. It allows to use the same instance of Mixin on two host objects.
- */
-function _createProxyMethods(proxyMethods, hostObject) {
- check(proxyMethods, Match.Optional(Match.OneOf([String], Match.ObjectHash(String))));
-
- // creating and binding proxy methods on the host object
- if (Array.isArray(proxyMethods))
- proxyMethods.forEach(function(methodName) {
- // method called this way to allow using _createProxyMethods with objects
- // that are not inheriting from Mixin
- _createProxyMethod.call(this, methodName, methodName, hostObject);
- }, this);
- else
- _.eachKey(proxyMethods, function(mixinMethodName, proxyMethodName) {
- // method called this way to allow using _createProxyMethods with objects
- // that are not inheriting from Mixin
- _createProxyMethod.call(this, proxyMethodName, mixinMethodName, hostObject);
- }, this);
-}
-
-
-/**
- * Sets mixin instance property name on the host class
- * Can be called only once
- *
- * @private
- * @param {Function} this Mixin subclass (not instance)
- * @param {Function} hostClass
- * @param {String} instanceKey
- */
-function Mixin_setInstanceKey(hostClass, method, instanceKey) {
- check(hostClass, Function);
- check(instanceKey, Match.IdentifierString);
-
- var prop = config.mixin.instancePropertiesMap
- , instanceKeys = hostClass[prop] = hostClass[prop] || {};
-
- if (instanceKeys[method.name])
- throw new Error('Mixin: instance property for method with name '
- + method.name + ' is already set');
-
- instanceKeys[method.name] = instanceKey;
-}
-
-
-/**
- * Adds method of Mixin subclass to host class prototype.
- *
- * @private
- * @param {Function} this Mixin subclass (not instance)
- * @param {String} mixinMethodName name of method in Mixin subclass
- * @param {String} hostMethodName (optional) name of created proxy method on host object, same if not specified
- * @param {Object} hostObject object class, must be specified as the last parameter (2nd or 3rd)
- */
-function Mixin_addMethod(hostClass, instanceKey, mixinMethodName, hostMethodName) {
- var method = this.prototype[mixinMethodName];
- check(method, Function);
-
- var wrappedMethod = _wrapMixinMethod.call(this, method);
-
- _.defineProperty(hostClass.prototype, hostMethodName, wrappedMethod, _.WRIT);
-
- Mixin_setInstanceKey(hostClass, method, instanceKey)
-}
-
-
-/**
- * Returns method that will be exposed on the host class prototype
- *
- * @private
- * @param {Function} this Mixin subclass (not instance)
- * @return {Function}
- */
-function _wrapMixinMethod(method) {
- return function() { // ,... arguments
- var mixinInstance = _getMixinInstance.call(this, method.name);
- return method.apply(mixinInstance, arguments);
- }
-}
-
-
-/**
- * Returns the reference to the instance of mixin subclass.
- * This method is used when methods are exposed on the host class prototype (using addMehtods) rather than on host instance.
- * Subclasses should not use this methods - whenever subclass method is exposed on the prototype it will be wrapped to set correct context for the subclass method.
- *
- * @private
- * @return {Object}
- */
-function _getMixinInstance(methodName) {
- if (this instanceof Mixin) return this;
- var instanceKeys = this.constructor[config.mixin.instancePropertiesMap]
- return this[instanceKeys[methodName]];
-}
-
-
-/**
- * Adds methods of Mixin subclass to host class prototype.
- *
- * @param {Function} this Mixin subclass (not instance)
- * @param {Object} hostClass host object class; must be specified.
- * @param {String} instanceKey the name of the property the host class instance will store mixin instance on
- * @param {Hash[String]|Array[String]} mixinMethods map of names of methods, key - host method name, value - mixin method name. Can be array.
- */
-function Mixin$$useWith(hostClass, instanceKey, mixinMethods) {
- check(mixinMethods, Match.Optional(Match.OneOf([String], Match.ObjectHash(String))));
-
- if (Array.isArray(mixinMethods))
- mixinMethods.forEach(function(methodName) {
- Mixin_addMethod.call(this, hostClass, instanceKey, methodName, methodName);
- }, this);
- else
- _.eachKey(mixinMethods, function(mixinMethodName, hostMethodName) {
- Mixin_addMethod.call(this, hostClass, instanceKey, mixinMethodName, hostMethodName);
- }, this);
-}
-
-},{"../config":65,"../util/check":90,"../util/error":98,"mol-proto":150}],4:[function(require,module,exports){
+},{"./facet":1,"milo-core":105}],3:[function(require,module,exports){
'use strict';
-var _ = require('mol-proto')
- , RegistryError = require('../util/error').Registry
- , check = require('../util/check')
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
module.exports = ClassRegistry;
@@ -512,10 +299,10 @@ function add(aClass, name) {
if (aClass != this.FoundationClass)
check(aClass, Match.Subclass(this.FoundationClass), 'class must be a sub(class) of a foundation class');
} else
- throw new RegistryError('foundation class must be set before adding classes to registry');
+ throw new Error('foundation class must be set before adding classes to registry');
if (this.__registeredClasses[name])
- throw new RegistryError('class "' + name + '" is already registered');
+ throw new Error('class "' + name + '" is already registered');
this.__registeredClasses[name] = aClass;
};
@@ -547,7 +334,7 @@ function remove(nameOrClass) {
: nameOrClass.name;
if (! this.__registeredClasses[name])
- throw new RegistryError('class is not registered');
+ throw new Error('class is not registered');
delete this.__registeredClasses[name];
};
@@ -571,14 +358,14 @@ function setClass(FoundationClass) {
_.defineProperty(this, 'FoundationClass', FoundationClass, _.ENUM);
}
-},{"../util/check":90,"../util/error":98,"mol-proto":150}],5:[function(require,module,exports){
+},{"milo-core":105}],4:[function(require,module,exports){
'use strict';
var Attribute = require('./a_class')
- , AttributeError = require('../util/error').Attribute
, config = require('../config')
- , _ = require('mol-proto')
- , check = require('../util/check')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
@@ -661,7 +448,7 @@ function attrName() {
var bindTo = value.match(ATTRIBUTE_REGEXP);
if (! bindTo)
- throw new AttributeError('invalid bind attribute ' + value);
+ throw new Error('invalid bind attribute ' + value);
this.compClass = bindTo[1] || 'Component';
this.compFacets = (bindTo[2] && bindTo[2].split(FACETS_SPLIT_REGEXP)) || undefined;
@@ -681,7 +468,7 @@ function validate() {
check(this.compName, Match.IdentifierString);
if (! this.compClass)
- throw new AttributeError('empty component class name ' + this.compClass);
+ throw new Error('empty component class name ' + this.compClass);
return this;
}
@@ -721,13 +508,13 @@ function BindAttribute$$setInfo(el, componentClass, componentName, componentFace
attr.decorate();
}
-},{"../config":65,"../util/check":90,"../util/error":98,"./a_class":6,"mol-proto":150}],6:[function(require,module,exports){
+},{"../config":64,"./a_class":5,"milo-core":105}],5:[function(require,module,exports){
'use strict';
-var _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , toBeImplemented = require('../util/error').toBeImplemented;
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , Match = check.Match;
module.exports = Attribute;
@@ -836,13 +623,17 @@ function Attribute$decorate() {
this.set(this.render());
}
-},{"../util/check":90,"../util/error":98,"mol-proto":150}],7:[function(require,module,exports){
+
+function toBeImplemented() {
+ throw new Error('calling the method of an absctract class');
+}
+
+},{"milo-core":105}],6:[function(require,module,exports){
'use strict';
var Attribute = require('./a_class')
- , AttributeError = require('../util/error').Attribute
, config = require('../config')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
/**
@@ -923,7 +714,7 @@ function render() {
return this.loadUrl;
}
-},{"../config":65,"../util/error":98,"./a_class":6,"mol-proto":150}],8:[function(require,module,exports){
+},{"../config":64,"./a_class":5,"milo-core":105}],7:[function(require,module,exports){
'use strict';
/**
@@ -937,7 +728,7 @@ var attributes = module.exports = {
load: require('./a_load')
};
-},{"./a_bind":5,"./a_load":7}],9:[function(require,module,exports){
+},{"./a_bind":4,"./a_load":6}],8:[function(require,module,exports){
'use strict';
var miloMail = require('./services/mail')
@@ -947,9 +738,9 @@ var miloMail = require('./services/mail')
, ComponentInfo = require('./components/c_info')
, Scope = require('./components/scope')
, BindAttribute = require('./attributes/a_bind')
- , BinderError = require('./util/error').Binder
- , _ = require('mol-proto')
- , check = require('./util/check')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, utilDom = require('./util/dom')
, Match = check.Match;
@@ -1103,9 +894,11 @@ function createBinderScope(scopeEl, scopeObjectFactory, rootScope, bindRootEleme
}
}
-},{"./attributes/a_bind":5,"./components/c_facets/cf_registry":31,"./components/c_info":32,"./components/c_registry":33,"./components/scope":41,"./services/mail":84,"./util/check":90,"./util/dom":94,"./util/error":98,"mol-proto":150}],10:[function(require,module,exports){
+},{"./attributes/a_bind":4,"./components/c_facets/cf_registry":30,"./components/c_info":31,"./components/c_registry":32,"./components/scope":40,"./services/mail":70,"./util/dom":79,"milo-core":105}],9:[function(require,module,exports){
'use strict';
+var coreClasses = require('milo-core').classes;
+
//
// milo.classes
// -----------
@@ -1117,10 +910,10 @@ var classes = {
FacetedObject: require('./abstract/faceted_object'),
Scope: require('./components/scope'),
ClassRegistry: require('./abstract/registry'),
- Mixin: require('./abstract/mixin'),
- MessageSource: require('./messenger/m_source'),
- MessengerMessageSource: require('./messenger/msngr_source'),
- MessengerAPI: require('./messenger/m_api'),
+ Mixin: coreClasses.Mixin,
+ MessageSource: coreClasses.MessageSource,
+ MessengerMessageSource: coreClasses.MessengerMessageSource,
+ MessengerAPI: coreClasses.MessengerAPI,
DOMEventsSource: require('./components/msg_src/dom_events'),
Transaction: require('./command/transaction'),
TransactionHistory: require('./command/transaction_history')
@@ -1128,12 +921,13 @@ var classes = {
module.exports = classes;
-},{"./abstract/facet":1,"./abstract/faceted_object":2,"./abstract/mixin":3,"./abstract/registry":4,"./command/transaction":14,"./command/transaction_history":15,"./components/msg_src/dom_events":39,"./components/scope":41,"./messenger/m_api":68,"./messenger/m_source":70,"./messenger/msngr_source":71}],11:[function(require,module,exports){
+},{"./abstract/facet":1,"./abstract/faceted_object":2,"./abstract/registry":3,"./command/transaction":13,"./command/transaction_history":14,"./components/msg_src/dom_events":38,"./components/scope":40,"milo-core":105}],10:[function(require,module,exports){
'use strict';
-var _ = require('mol-proto')
- , logger = require('../util/logger');
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger;
module.exports = ActionsHistory;
@@ -1277,7 +1071,7 @@ function ActionsHistory$getDescription() {
};
}
-},{"../util/logger":102,"mol-proto":150}],12:[function(require,module,exports){
+},{"milo-core":105}],11:[function(require,module,exports){
'use strict';
var ClassRegistry = require('../abstract/registry')
@@ -1294,14 +1088,15 @@ commandsRegistry.add(Command);
module.exports = commandsRegistry;
-},{"../abstract/registry":4,"./index":13}],13:[function(require,module,exports){
+},{"../abstract/registry":3,"./index":12}],12:[function(require,module,exports){
'use strict';
-var _ = require('mol-proto')
- , check = require('../util/check')
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match
- , logger = require('../util/logger');
+ , logger = miloCore.util.logger;
var UNDO_COMMAND = '_undoCommand';
@@ -1493,12 +1288,12 @@ function Command$getDescription() {
};
}
-},{"../util/check":90,"../util/logger":102,"mol-proto":150}],14:[function(require,module,exports){
+},{"milo-core":105}],13:[function(require,module,exports){
'use strict';
var ActionsHistory = require('./actions_history')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
module.exports = Transaction;
@@ -1567,15 +1362,16 @@ function Transaction$getDescription() {
}
}
-},{"./actions_history":11,"mol-proto":150}],15:[function(require,module,exports){
+},{"./actions_history":10,"milo-core":105}],14:[function(require,module,exports){
'use strict';
var ActionsHistory = require('./actions_history')
, Transaction = require('./transaction')
- , logger = require('../util/logger')
- , Messenger = require('../messenger')
- , _ = require('mol-proto');
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , Messenger = miloCore.Messenger
+ , _ = miloCore.proto;
module.exports = TransactionHistory;
@@ -1724,7 +1520,7 @@ function TransactionHistory$destroy() {
delete this.transactions;
}
-},{"../messenger":67,"../util/logger":102,"./actions_history":11,"./transaction":14,"mol-proto":150}],16:[function(require,module,exports){
+},{"./actions_history":10,"./transaction":13,"milo-core":105}],15:[function(require,module,exports){
'use strict';
@@ -1732,19 +1528,18 @@ var FacetedObject = require('../abstract/faceted_object')
, facetsRegistry = require('./c_facets/cf_registry')
, ComponentFacet = facetsRegistry.get('ComponentFacet')
, componentUtils = require('./c_utils')
- , Messenger = require('../messenger')
- , _ = require('mol-proto')
- , check = require('../util/check')
+ , miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match
, config = require('../config')
, miloComponentName = require('../util/component_name')
- , logger = require('../util/logger')
+ , logger = miloCore.util.logger
, domUtils = require('../util/dom')
- , ComponentError = require('../util/error').Component
, BindAttribute = require('../attributes/a_bind')
, Scope = require('./scope')
- , DOMStorage = require('../util/storage')
- , jsonParse = require('../util/json_parse');
+ , DOMStorage = require('../util/storage');
var _makeComponentConditionFunc = componentUtils._makeComponentConditionFunc;
@@ -1964,7 +1759,7 @@ function Component_domStorageSerializer(component) {
function Component_domStorageParser(compStr, compClassName) {
- var state = jsonParse(compStr);
+ var state = _.jsonParse(compStr);
if (state)
return Component.createFromState(state);
}
@@ -1988,7 +1783,7 @@ function Component$$create(info, throwOnErrors) {
logger.error('Component', message, ';using base Component class instead');
ComponentClass = Component;
} else
- throw new ComponentError(message);
+ throw new Error(message);
}
var aComponent = new ComponentClass(info.scope, info.el, info.name, info);
@@ -2017,7 +1812,7 @@ function Component$$copy(component, deepCopy) {
check(deepCopy, Match.Optional(Boolean));
if (deepCopy && !component.container)
- throw new ComponentError('Cannot deep copy component without container facet');
+ throw new Error('Cannot deep copy component without container facet');
// copy DOM element, using Dom facet if it is available
var newEl = component.dom
@@ -2148,7 +1943,7 @@ function _createComponentWrapElement(state, newUniqueName) {
var children = domUtils.children(wrapEl);
if (children.length != 1)
- throw new ComponentError('cannot create component: incorrect HTML, elements number: ' + children.length + ' (should be 1)');
+ throw new Error('cannot create component: incorrect HTML, elements number: ' + children.length + ' (should be 1)');
var compEl = children[0];
var attr = new BindAttribute(compEl);
attr.compName = newUniqueName ? miloComponentName() : state.compName;
@@ -2647,7 +2442,7 @@ function Component$isDestroyed() {
return this._destroyed;
}
-},{"../abstract/faceted_object":2,"../attributes/a_bind":5,"../binder":9,"../config":65,"../messenger":67,"../util/check":90,"../util/component_name":91,"../util/dom":94,"../util/error":98,"../util/json_parse":101,"../util/logger":102,"../util/storage":106,"./c_facets/cf_registry":31,"./c_utils":34,"./scope":41,"mol-proto":150}],17:[function(require,module,exports){
+},{"../abstract/faceted_object":2,"../attributes/a_bind":4,"../binder":8,"../config":64,"../util/component_name":76,"../util/dom":79,"../util/storage":89,"./c_facets/cf_registry":30,"./c_utils":33,"./scope":40,"milo-core":105}],16:[function(require,module,exports){
'use strict';
/**
@@ -2664,10 +2459,10 @@ function Component$isDestroyed() {
*/
var Facet = require('../abstract/facet')
- , Messenger = require('../messenger')
- , FacetError = require('../util/error').Facet
+ , miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
, componentUtils = require('./c_utils')
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
var ComponentFacet = _.createSubclass(Facet, 'ComponentFacet');
@@ -2767,15 +2562,15 @@ function ComponentFacet$onConfigMessages(messageSubscribers) {
context: this.owner
};
else
- throw new FacetError('unknown subscriber context in configuration: ' + subscriber.context);
+ throw new Error('unknown subscriber context in configuration: ' + subscriber.context);
return this.on(messages, subscriber);
}
- throw new FacetError('unknown subscriber context type in configuration: ' + contextType);
+ throw new Error('unknown subscriber context type in configuration: ' + contextType);
}
- throw new FacetError('unknown subscriber type in configuration: ' + subscriberType);
+ throw new Error('unknown subscriber type in configuration: ' + subscriberType);
}, this);
return notYetRegisteredMap;
@@ -2868,17 +2663,18 @@ function requiresFacet(facetName) {
|| facetRequire.indexOf(_.firstLowerCase(facetName)) >= 0);
}
-},{"../abstract/facet":1,"../messenger":67,"../util/error":98,"./c_utils":34,"mol-proto":150}],18:[function(require,module,exports){
+},{"../abstract/facet":1,"./c_utils":33,"milo-core":105}],17:[function(require,module,exports){
'use strict';
var ComponentFacet = require('../c_facet')
, miloBinder = require('../../binder')
, Scope = require('../scope')
- , _ = require('mol-proto')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger
, facetsRegistry = require('./cf_registry')
- , domUtils = require('../../util/dom')
- , logger = require('../../util/logger');
+ , domUtils = require('../../util/dom');
/**
@@ -3057,27 +2853,28 @@ function Container$remove(comp) {
this.owner.el.removeChild(comp.el);
}
-},{"../../binder":9,"../../util/dom":94,"../../util/logger":102,"../c_facet":17,"../scope":41,"./cf_registry":31,"mol-proto":150}],19:[function(require,module,exports){
+},{"../../binder":8,"../../util/dom":79,"../c_facet":16,"../scope":40,"./cf_registry":30,"milo-core":105}],18:[function(require,module,exports){
'use strict';
-var Mixin = require('../../abstract/mixin')
+var miloCore = require('milo-core')
+ , Mixin = miloCore.classes.Mixin
, ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Messenger = require('../../messenger')
+ , Messenger = miloCore.Messenger
, DOMEventsSource = require('../msg_src/dom_events')
, DataMsgAPI = require('../msg_api/data')
, getElementDataAccess = require('../msg_api/de_data')
- , pathUtils = require('../../model/path_utils')
- , ModelPath = require('../../model/m_path')
- , modelUtils = require('../../model/model_utils')
- , changeDataHandler = require('../../model/change_data')
+ , Model = miloCore.Model
+ , pathUtils = Model._utils.path
+ , modelUtils = Model._utils.model
+ , changeDataHandler = Model._utils.changeDataHandler
, getTransactionFlag = changeDataHandler.getTransactionFlag
, setTransactionFlag = changeDataHandler.setTransactionFlag
, postTransactionFinished = changeDataHandler.postTransactionFinished
- , _ = require('mol-proto')
- , logger = require('../../util/logger');
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger;
/**
@@ -3132,7 +2929,7 @@ module.exports = Data;
* ModelPath methods added to Data prototype
*/
['push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {
- var method = ModelPath.prototype[methodName];
+ var method = Model.Path.prototype[methodName];
_.defineProperty(Data.prototype, methodName, method);
});
@@ -3716,21 +3513,21 @@ function Data$setState(state) {
return this.set(state.state);
}
-},{"../../abstract/mixin":3,"../../messenger":67,"../../model/change_data":73,"../../model/m_path":76,"../../model/model_utils":77,"../../model/path_utils":79,"../../util/logger":102,"../c_facet":17,"../msg_api/data":36,"../msg_api/de_data":37,"../msg_src/dom_events":39,"./cf_registry":31,"mol-proto":150}],20:[function(require,module,exports){
+},{"../c_facet":16,"../msg_api/data":35,"../msg_api/de_data":36,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":105}],19:[function(require,module,exports){
'use strict';
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , _ = require('mol-proto')
- , check = require('../../util/check')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match
+ , doT = miloCore.util.doT
, binder = require('../../binder')
, BindAttribute = require('../../attributes/a_bind')
- , DomFacetError = require('../../util/error').DomFacet
, domUtils = require('../../util/dom')
- , config = require('../../config')
- , doT = require('dot');
+ , config = require('../../config');
/**
@@ -3868,7 +3665,7 @@ function _attachCssClasses(el, methodName, cssClasses, enforce) {
else if (typeof cssClasses == 'string')
callMethod(cssClasses);
else
- throw new DomFacetError('unknown type of CSS classes parameter');
+ throw new Error('unknown type of CSS classes parameter');
function callMethod(cssCls) {
doToggle
@@ -3984,7 +3781,7 @@ var findDirections = {
// or downwards (direction = "down")
function find(direction, iterator) {
if (! findDirections.hasOwnProperty(direction))
- throw new DomFacetError('incorrect find direction: ' + direction);
+ throw new Error('incorrect find direction: ' + direction);
var el = this.owner.el
, scope = this.owner.scope
@@ -4054,7 +3851,7 @@ function hasTextAfterSelection() {
return isText;
}
-},{"../../attributes/a_bind":5,"../../binder":9,"../../config":65,"../../util/check":90,"../../util/dom":94,"../../util/error":98,"../c_facet":17,"./cf_registry":31,"dot":115,"mol-proto":150}],21:[function(require,module,exports){
+},{"../../attributes/a_bind":4,"../../binder":8,"../../config":64,"../../util/dom":79,"../c_facet":16,"./cf_registry":30,"milo-core":105}],20:[function(require,module,exports){
'use strict';
//
@@ -4065,8 +3862,9 @@ var ComponentFacet = require('../c_facet')
, DOMEventsSource = require('../msg_src/dom_events')
, Component = require('../c_class')
, DragDrop = require('../../util/dragdrop')
- , _ = require('mol-proto')
- , logger = require('../../util/logger');
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger;
/**
@@ -4271,7 +4069,7 @@ function _dragIsDisabled(event) {
return false;
}
-},{"../../util/dragdrop":97,"../../util/logger":102,"../c_class":16,"../c_facet":17,"../msg_src/dom_events":39,"./cf_registry":31,"mol-proto":150}],22:[function(require,module,exports){
+},{"../../util/dragdrop":82,"../c_class":15,"../c_facet":16,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":105}],21:[function(require,module,exports){
'use strict';
//
@@ -4282,9 +4080,7 @@ var ComponentFacet = require('../c_facet')
, DOMEventsSource = require('../msg_src/dom_events')
, DropMsgAPI = require('../msg_api/drop')
, DragDrop = require('../../util/dragdrop')
- , DropError = require('../../util/error').Drop
- , _ = require('mol-proto')
- , _handleDropDependency;
+ , _ = require('milo-core').proto;
/**
* `milo.registry.facets.get('Drop')`
@@ -4393,7 +4189,7 @@ function postToService(eventType, event) {
}
-_handleDropDependency = _.throttle(_handleDropDependencyNothrottle, 50);
+var _handleDropDependency = _.throttle(_handleDropDependencyNothrottle, 50);
function _handleDropDependencyNothrottle(dt, originalDropComponent) {
var allow = this.config.allow
, parentAllowed = true;
@@ -4444,7 +4240,7 @@ function _isDropAllowed(dt, originalDropComponent) {
return !! _.result(test, this.owner, meta, dt);
}
default:
- throw new DropError('Incorrect allowed components in config');
+ throw new Error('Incorrect allowed components in config');
}
} else {
var dataTypes = allow && allow.dataTypes
@@ -4459,14 +4255,15 @@ function _isDropAllowed(dt, originalDropComponent) {
// TODO test for other data types
}
-},{"../../util/dragdrop":97,"../../util/error":98,"../c_facet":17,"../msg_api/drop":38,"../msg_src/dom_events":39,"./cf_registry":31,"mol-proto":150}],23:[function(require,module,exports){
+},{"../../util/dragdrop":82,"../c_facet":16,"../msg_api/drop":37,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":105}],22:[function(require,module,exports){
'use strict';
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Messenger = require('../../messenger')
+ , miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
, DOMEventsSource = require('../msg_src/dom_events')
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
/**
@@ -4518,16 +4315,17 @@ function Events$init() {
_.defineProperty(this, MSG_SOURCE_KEY, domEventsSource);
}
-},{"../../messenger":67,"../c_facet":17,"../msg_src/dom_events":39,"./cf_registry":31,"mol-proto":150}],24:[function(require,module,exports){
+},{"../c_facet":16,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":105}],23:[function(require,module,exports){
'use strict';
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Messenger = require('../../messenger')
+ , miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
, FrameMessageSource = require('../msg_src/frame')
, domEventsConstructors = require('../../services/de_constrs')
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
/**
@@ -4707,14 +4505,15 @@ function _makeWhenReadyFunc(isReadyFunc, event) {
}
}
-},{"../../messenger":67,"../../services/de_constrs":82,"../c_facet":17,"../msg_src/frame":40,"./cf_registry":31,"mol-proto":150}],25:[function(require,module,exports){
+},{"../../services/de_constrs":68,"../c_facet":16,"../msg_src/frame":39,"./cf_registry":30,"milo-core":105}],24:[function(require,module,exports){
'use strict';
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Model = require('../../model')
- , _ = require('mol-proto')
+ , miloCore = require('milo-core')
+ , Model = miloCore.Model
+ , _ = miloCore.proto
, miloMail = require('../../services/mail');
@@ -4785,22 +4584,22 @@ function ItemFacet$extractItem() {
this.list.extractItem(this.index);
}
-},{"../../model":74,"../../services/mail":84,"../c_facet":17,"./cf_registry":31,"mol-proto":150}],26:[function(require,module,exports){
+},{"../../services/mail":70,"../c_facet":16,"./cf_registry":30,"milo-core":105}],25:[function(require,module,exports){
'use strict';
var ComponentFacet = require('../c_facet')
, Component = require('../c_class')
, facetsRegistry = require('./cf_registry')
- , _ = require('mol-proto')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
, miloMail = require('../../services/mail')
, miloBinder = require('../../binder')
- , miloUtil = require('../../util')
- , ListError = miloUtil.error.List
- , logger = miloUtil.logger
- , doT = require('dot')
- , check = miloUtil.check
+ , logger = miloCore.util.logger
+ , doT = miloCore.util.doT
+ , check = miloCore.util.check
, Match = check.Match
- , domUtils = miloUtil.dom
+ , domUtils = require('../../util/dom')
+ , componentName = require('../../util/component_name')
, miloConfig = require('../../config');
@@ -4893,7 +4692,7 @@ function onChildrenBound() {
}
// Component must have one child with an Item facet
- if (! foundItem) throw new ListError('No child component has Item facet');
+ if (! foundItem) throw new Error('No child component has Item facet');
this.list.itemSample = foundItem;
@@ -4996,7 +4795,7 @@ function List$addItem(index, itemData) {
function List$_addItem(index) {
index = index || this.count();
if (this.item(index))
- throw ListError('attempt to create item with ID of existing item');
+ throw Error('attempt to create item with ID of existing item');
// Copy component
var component = Component.copy(this.itemSample, true);
@@ -5053,12 +4852,12 @@ function List$addItems(count, index) { // ,... items data
function List$_addItems(count, index) {
check(count, Match.Integer);
if (count < 0)
- throw new ListError('can\'t add negative number of items');
+ throw new Error('can\'t add negative number of items');
if (count == 0) return;
var itemsHTML = this.itemsTemplate({
- componentName: miloUtil.componentName,
+ componentName: componentName,
count: count
});
@@ -5217,14 +5016,15 @@ function List$destroy() {
ComponentFacet.prototype.destroy.apply(this, arguments);
}
-},{"../../binder":9,"../../config":65,"../../services/mail":84,"../../util":100,"../c_class":16,"../c_facet":17,"./cf_registry":31,"dot":115,"mol-proto":150}],27:[function(require,module,exports){
+},{"../../binder":8,"../../config":64,"../../services/mail":70,"../../util/component_name":76,"../../util/dom":79,"../c_class":15,"../c_facet":16,"./cf_registry":30,"milo-core":105}],26:[function(require,module,exports){
'use strict';
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Model = require('../../model')
- , Mixin = require('../../abstract/mixin')
- , _ = require('mol-proto');
+ , miloCore = require('milo-core')
+ , Model = miloCore.Model
+ , Mixin = miloCore.classes.Mixin
+ , _ = miloCore.proto;
// generic drag handler, should be overridden
@@ -5293,14 +5093,14 @@ function ModelFacet$destroy() {
ComponentFacet.prototype.destroy.apply(this, arguments);
}
-},{"../../abstract/mixin":3,"../../model":74,"../c_facet":17,"./cf_registry":31,"mol-proto":150}],28:[function(require,module,exports){
+},{"../c_facet":16,"./cf_registry":30,"milo-core":105}],27:[function(require,module,exports){
'use strict';
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , Model = require('../../model')
-
- , _ = require('mol-proto');
+ , miloCore = require('milo-core')
+ , Model = miloCore.Model
+ , _ = miloCore.proto;
// generic drag handler, should be overridden
@@ -5334,7 +5134,7 @@ function Options$destroy() {
ComponentFacet.prototype.destroy.apply(this, arguments);
}
-},{"../../model":74,"../c_facet":17,"./cf_registry":31,"mol-proto":150}],29:[function(require,module,exports){
+},{"../c_facet":16,"./cf_registry":30,"milo-core":105}],28:[function(require,module,exports){
'use strict';
//
@@ -5351,9 +5151,10 @@ function Options$destroy() {
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , _ = require('mol-proto')
- , check = require('../../util/check')
- , logger = require('../../util/logger')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , logger = miloCore.util.logger
, Match = check.Match
, binder = require('../../binder');
@@ -5442,12 +5243,12 @@ function Template$binder() {
logger.error('TemplateFacet: Binder called without container facet.');
}
-},{"../../binder":9,"../../util/check":90,"../../util/logger":102,"../c_facet":17,"./cf_registry":31,"mol-proto":150}],30:[function(require,module,exports){
+},{"../../binder":8,"../c_facet":16,"./cf_registry":30,"milo-core":105}],29:[function(require,module,exports){
'use strict';
var ComponentFacet = require('../c_facet')
, facetsRegistry = require('./cf_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
/**
@@ -5545,7 +5346,7 @@ function Transfer$getComponentMeta() {
};
}
-},{"../c_facet":17,"./cf_registry":31,"mol-proto":150}],31:[function(require,module,exports){
+},{"../c_facet":16,"./cf_registry":30,"milo-core":105}],30:[function(require,module,exports){
'use strict';
var ClassRegistry = require('../../abstract/registry')
@@ -5564,16 +5365,16 @@ facetsRegistry.add(ComponentFacet);
module.exports = facetsRegistry;
-},{"../../abstract/registry":4,"../c_facet":17}],32:[function(require,module,exports){
+},{"../../abstract/registry":3,"../c_facet":16}],31:[function(require,module,exports){
'use strict';
var componentsRegistry = require('./c_registry')
, facetsRegistry = require('./c_facets/cf_registry')
, componentName = require('../util/component_name')
, Scope = require('./scope')
- , BinderError = require('../util/error').Binder
- , logger = require('../util/logger')
- , _ = require('mol-proto');
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , _ = miloCore.proto;
module.exports = ComponentInfo;
@@ -5676,7 +5477,7 @@ function reportBinderError(throwOnErrors, message) {
if (throwOnErrors === false)
logger.error('ComponentInfo binder error:', message);
else
- throw new BinderError(message);
+ throw new Error(message);
};
@@ -5696,7 +5497,7 @@ function hasContainerFacet(ComponentClass, extraFacetsClasses) {
}
}
-},{"../util/component_name":91,"../util/error":98,"../util/logger":102,"./c_facets/cf_registry":31,"./c_registry":33,"./scope":41,"mol-proto":150}],33:[function(require,module,exports){
+},{"../util/component_name":76,"./c_facets/cf_registry":30,"./c_registry":32,"./scope":40,"milo-core":105}],32:[function(require,module,exports){
'use strict';
var ClassRegistry = require('../abstract/registry')
@@ -5713,12 +5514,14 @@ componentsRegistry.add(Component);
module.exports = componentsRegistry;
-},{"../abstract/registry":4,"./c_class":16}],34:[function(require,module,exports){
+},{"../abstract/registry":3,"./c_class":15}],33:[function(require,module,exports){
'use strict';
var config = require('../config')
- , check = require('../util/check')
- , Match = check.Match;
+ , miloCore = require('milo-core')
+ , check = miloCore.util.check
+ , Match = check.Match
+ , _ = miloCore.proto;
var componentUtils = module.exports = {
@@ -5804,7 +5607,7 @@ function _getContainingComponent(el, returnCurrent, conditionFunc) {
return _getContainingComponent(el.parentNode, true, conditionFunc);
}
-},{"../config":65,"../util/check":90}],35:[function(require,module,exports){
+},{"../config":64,"milo-core":105}],34:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
@@ -5817,14 +5620,15 @@ componentsRegistry.add(View);
module.exports = View;
-},{"../c_class":16,"../c_registry":33}],36:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32}],35:[function(require,module,exports){
'use strict';
-var MessengerAPI = require('../../messenger/m_api')
- , getElementDataAccess = require('./de_data')
- , _ = require('mol-proto')
- , check = require('../../util/check')
+var getElementDataAccess = require('./de_data')
+ , miloCore = require('milo-core')
+ , MessengerAPI = miloCore.classes.MessengerAPI
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
@@ -5902,11 +5706,11 @@ function createInternalData(sourceMessage, message, data) {
return internalData;
}
-},{"../../messenger/m_api":68,"../../util/check":90,"./de_data":37,"mol-proto":150}],37:[function(require,module,exports){
+},{"./de_data":36,"milo-core":105}],36:[function(require,module,exports){
'use strict';
-var _ = require('mol-proto');
+var _ = require('milo-core').proto;
/**
@@ -6046,11 +5850,11 @@ function inputChangeEvent(el) {
: inputElementTypes.byDefault.event;
}
-},{"mol-proto":150}],38:[function(require,module,exports){
+},{"milo-core":105}],37:[function(require,module,exports){
'use strict';
-var MessengerAPI = require('../../messenger/m_api')
+var MessengerAPI = require('milo-core').classes.MessengerAPI;
var DropMsgAPI = _.createSubclass(MessengerAPI, 'DropMsgAPI', true);
@@ -6098,15 +5902,16 @@ function filterSourceMessage(sourceMessage, message, data) { // data is DOM even
return ok;
}
-},{"../../messenger/m_api":68}],39:[function(require,module,exports){
+},{"milo-core":105}],38:[function(require,module,exports){
'use strict';
var DOMEmitterSource = require('../../services/dom_source')
- , MessageSource = require('../../messenger/m_source')
+ , miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
, Component = require('../c_class')
- , _ = require('mol-proto')
- , check = require('../../util/check')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
, Match = check.Match;
var DOMEventsSource = _.createSubclass(DOMEmitterSource, 'DOMEventsSource', true);
@@ -6144,18 +5949,18 @@ function emitter() {
return this.component.el;
}
-},{"../../messenger/m_source":70,"../../services/dom_source":83,"../../util/check":90,"../c_class":16,"mol-proto":150}],40:[function(require,module,exports){
+},{"../../services/dom_source":69,"../c_class":15,"milo-core":105}],39:[function(require,module,exports){
'use strict';
// ###component iframe source
-var MessageSource = require('../../messenger/m_source')
- , Component = require('../c_class')
- , _ = require('mol-proto')
- , check = require('../../util/check')
- , logger = require('../../util/logger')
- , Match = check.Match
- , FrameMessageSourceError = require('../../util/error').FrameMessageSource;
+var Component = require('../c_class')
+ , miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , logger = miloCore.util.logger
+ , Match = check.Match;
var FrameMessageSource = _.createSubclass(MessageSource, 'FrameMessageSource', true);
@@ -6180,7 +5985,7 @@ function init(hostObject, proxyMethods, messengerAPIOrClass, component) {
this.component = component;
if (component.el.tagName.toLowerCase() != 'iframe')
- throw new FrameMessageSourceError('component for FrameMessageSource can only be attached to iframe element');
+ throw new Error('component for FrameMessageSource can only be attached to iframe element');
MessageSource.prototype.init.apply(this, arguments);
}
@@ -6220,15 +6025,15 @@ function handleEvent(event) {
this.dispatchMessage(event.data.type, event);
}
-},{"../../messenger/m_source":70,"../../util/check":90,"../../util/error":98,"../../util/logger":102,"../c_class":16,"mol-proto":150}],41:[function(require,module,exports){
+},{"../c_class":15,"milo-core":105}],40:[function(require,module,exports){
'use strict';
-var _ = require('mol-proto')
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
, componentName = require('../util/component_name')
- , check = require('../util/check')
+ , check = miloCore.util.check
, Match = check.Match
- , ScopeError = require('../util/error').Scope
- , logger = require('../util/logger');
+ , logger = miloCore.util.logger;
/**
@@ -6285,7 +6090,7 @@ function Scope$_add(object, name) {
name = object.name;
if (this.hasOwnProperty(name))
- throw new ScopeError('duplicate object name: ' + name);
+ throw new Error('duplicate object name: ' + name);
checkName(name);
__add.call(this, object, name);
@@ -6399,7 +6204,7 @@ function Scope$_filter(callback, thisArg) {
*/
function checkName(name) {
if (! allowedNamePattern.test(name))
- throw new ScopeError('name should start from letter, this name is not allowed: ' + name);
+ throw new Error('name should start from letter, this name is not allowed: ' + name);
}
@@ -6486,11 +6291,12 @@ function Scope$$rename(obj, name, renameInScope) {
obj.name = name;
}
-},{"../util/check":90,"../util/component_name":91,"../util/error":98,"../util/logger":102,"mol-proto":150}],42:[function(require,module,exports){
+},{"../util/component_name":76,"milo-core":105}],41:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
- , componentsRegistry = require('../c_registry');
+ , componentsRegistry = require('../c_registry')
+ , _ = require('milo-core').proto;
var MLButton = Component.createComponentClass('MLButton', {
@@ -6519,12 +6325,12 @@ function MLButton$isDisabled() {
}
-},{"../c_class":16,"../c_registry":33}],43:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],42:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var COMBO_CHANGE_MESSAGE = 'mlcombochange';
@@ -6612,12 +6418,12 @@ function onOptionsChange(msg, data) {
});
}
-},{"../c_class":16,"../c_registry":33,"mol-proto":150}],44:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],43:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var COMBO_LIST_CHANGE_MESSAGE = 'mlcombolistchange';
@@ -6758,12 +6564,12 @@ function onAddItem(msg, data) {
this.events.postMessage('milo_combolistadditem', data);
}
-},{"../c_class":16,"../c_registry":33,"mol-proto":150}],45:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],44:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var MLDate = Component.createComponentClass('MLDate', {
events: undefined,
@@ -6851,7 +6657,7 @@ function toISO8601Format(date) {
function pad(n) { return n < 10 ? '0' + n : n; }
}
-},{"../c_class":16,"../c_registry":33,"mol-proto":150}],46:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],45:[function(require,module,exports){
'use strict';
@@ -6866,10 +6672,10 @@ componentsRegistry.add(MLDropTarget);
module.exports = MLDropTarget;
-},{"../c_class":16,"../c_registry":33}],47:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32}],46:[function(require,module,exports){
'use strict';
-var doT = require('dot')
+var doT = require('milo-core').util.doT
, componentsRegistry = require('../c_registry')
, Component = require('../c_class')
, miloCount = require('../../util/count');
@@ -6970,7 +6776,7 @@ function MLFoldTree$renderTree (data) {
}
}
-},{"../../util/count":92,"../c_class":16,"../c_registry":33,"dot":115}],48:[function(require,module,exports){
+},{"../../util/count":77,"../c_class":15,"../c_registry":32,"milo-core":105}],47:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
@@ -6990,7 +6796,7 @@ componentsRegistry.add(MLGroup);
module.exports = MLGroup;
-},{"../c_class":16,"../c_registry":33}],49:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32}],48:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
@@ -7009,12 +6815,12 @@ componentsRegistry.add(MLHyperlink);
module.exports = MLHyperlink;
-},{"../c_class":16,"../c_registry":33}],50:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32}],49:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var IMAGE_CHANGE_MESSAGE = 'mlimagechange';
@@ -7103,12 +6909,12 @@ function onModelChange(path, data) {
dispatchChangeMessage.call(this);
}
-},{"../c_class":16,"../c_registry":33,"mol-proto":150}],51:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],50:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var MLInput = Component.createComponentClass('MLInput', {
@@ -7141,12 +6947,12 @@ function MLInput$setMaxLength(length) {
this.el.setAttribute('maxlength', length);
}
-},{"../c_class":16,"../c_registry":33,"mol-proto":150}],52:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],51:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var INPUT_LIST_CHANGE_MESSAGE = 'mlinputlistchange';
@@ -7264,12 +7070,12 @@ function MLInputList_del() {
function MLInputList_splice() { // ... arguments
this.model.splice.apply(this.model, arguments);
}
-},{"../c_class":16,"../c_registry":33,"mol-proto":150}],53:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],52:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var LIST_CHANGE_MESSAGE = 'mllistchange'
, DELETE_BUTTON_NAME = 'deleteBtn';
@@ -7328,13 +7134,13 @@ function onChildrenBound() {
this._connector = milo.minder(this.model, '<<<-', this.data).deferChangeMode('<<<->>>');
}
-},{"../c_class":16,"../c_registry":33,"mol-proto":150}],54:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],53:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, DragDrop = require('../../util/dragdrop')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var LISTITEM_CHANGE_MESSAGE = 'mllistitemchange'
@@ -7473,13 +7279,13 @@ function _sendChangeMessage() {
-},{"../../util/dragdrop":97,"../c_class":16,"../c_registry":33,"mol-proto":150}],55:[function(require,module,exports){
+},{"../../util/dragdrop":82,"../c_class":15,"../c_registry":32,"milo-core":105}],54:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
, miloCount = require('../../util/count')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var RADIO_CHANGE_MESSAGE = 'mlradiogroupchange'
@@ -7637,12 +7443,12 @@ function MLRadioGroup$destroy() {
Component.prototype.destroy.apply(this, arguments);
}
-},{"../../util/count":92,"../c_class":16,"../c_registry":33,"mol-proto":150}],56:[function(require,module,exports){
+},{"../../util/count":77,"../c_class":15,"../c_registry":32,"milo-core":105}],55:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto');
+ , _ = require('milo-core').proto;
var MLSelect = Component.createComponentClass('MLSelect', {
@@ -7696,7 +7502,7 @@ function onOptionsChange(path, data) {
this.template.render({ selectOptions: this.model.get() });
}
-},{"../c_class":16,"../c_registry":33,"mol-proto":150}],57:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],56:[function(require,module,exports){
'use strict';
/**
@@ -7706,9 +7512,10 @@ function onOptionsChange(path, data) {
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto')
- , doT = require('dot')
- , logger = require('../../util/logger');
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , doT = miloCore.util.doT
+ , logger = miloCore.util.logger;
var COMBO_OPEN = 'ml-ui-supercombo-open';
var COMBO_CHANGE_MESSAGE = 'mlsupercombochange';
@@ -8320,7 +8127,7 @@ function _setData() {
this.setFilteredOptions(this._optionsData);
}
-},{"../../util/logger":102,"../c_class":16,"../c_registry":33,"dot":115,"mol-proto":150}],58:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],57:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
@@ -8339,13 +8146,14 @@ componentsRegistry.add(MLText);
module.exports = MLText;
-},{"../c_class":16,"../c_registry":33}],59:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32}],58:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
, componentsRegistry = require('../c_registry')
- , _ = require('mol-proto')
- , logger = require('../../util/logger');
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger;
var MLTextarea = Component.createComponentClass('MLTextarea', {
@@ -8428,11 +8236,12 @@ function MLTextarea$destroy() {
function MLTextarea$disable(disable) {
this.el.disabled = disable;
}
-},{"../../util/logger":102,"../c_class":16,"../c_registry":33,"mol-proto":150}],60:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],59:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
- , componentsRegistry = require('../c_registry');
+ , componentsRegistry = require('../c_registry')
+ , _ = require('milo-core').proto;
var MLTime = Component.createComponentClass('MLTime', {
@@ -8490,7 +8299,7 @@ function MLTime_del() {
this.el.value = '';
}
-},{"../c_class":16,"../c_registry":33}],61:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32,"milo-core":105}],60:[function(require,module,exports){
'use strict';
var Component = require('../c_class')
@@ -8510,16 +8319,17 @@ componentsRegistry.add(MLWrapper);
module.exports = MLWrapper;
-},{"../c_class":16,"../c_registry":33}],62:[function(require,module,exports){
+},{"../c_class":15,"../c_registry":32}],61:[function(require,module,exports){
'use strict';
var Component = require('../../c_class')
, componentsRegistry = require('../../c_registry')
, componentName = require('../../../util/component_name')
- , logger = require('../../../util/logger')
- , check = require('../../../util/check')
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , check = miloCore.util.check
, Match = check.Match
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
var ALERT_CSS_CLASSES = {
@@ -8680,16 +8490,17 @@ function _toggleAlert(doShow) {
this.el[doShow ? 'focus' : 'blur']();
}
-},{"../../../util/check":90,"../../../util/component_name":91,"../../../util/logger":102,"../../c_class":16,"../../c_registry":33,"mol-proto":150}],63:[function(require,module,exports){
+},{"../../../util/component_name":76,"../../c_class":15,"../../c_registry":32,"milo-core":105}],62:[function(require,module,exports){
'use strict';
var Component = require('../../c_class')
, componentsRegistry = require('../../c_registry')
, componentName = require('../../../util/component_name')
- , logger = require('../../../util/logger')
- , check = require('../../../util/check')
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , check = miloCore.util.check
, Match = check.Match
- , _ = require('mol-proto');
+ , _ = miloCore.proto;
var DEFAULT_BUTTONS = [ { type: 'default', label: 'OK', result: 'OK' } ];
@@ -9022,13 +8833,14 @@ function MLDialog$destroy() {
Component.prototype.destroy.apply(this, arguments);
}
-},{"../../../util/check":90,"../../../util/component_name":91,"../../../util/logger":102,"../../c_class":16,"../../c_registry":33,"mol-proto":150}],64:[function(require,module,exports){
+},{"../../../util/component_name":76,"../../c_class":15,"../../c_registry":32,"milo-core":105}],63:[function(require,module,exports){
'use strict';
var Component = require('../../c_class')
, componentsRegistry = require('../../c_registry')
- , _ = require('mol-proto')
- , logger = require('../../../util/logger')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger
, DOMListeners = require('../../../util/dom_listeners');
@@ -9136,7 +8948,7 @@ function MLDropdown$toggleMenu(doShow) {
: 'none';
}
-},{"../../../util/dom_listeners":95,"../../../util/logger":102,"../../c_class":16,"../../c_registry":33,"mol-proto":150}],65:[function(require,module,exports){
+},{"../../../util/dom_listeners":80,"../../c_class":15,"../../c_registry":32,"milo-core":105}],64:[function(require,module,exports){
'use strict';
@@ -9157,15 +8969,13 @@ function MLDropdown$toggleMenu(doShow) {
// ```
-var _ = require('mol-proto')
- , doT = require('dot');
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , doT = miloCore.util.doT;
-module.exports = config;
+var config = module.exports = miloCore.config;
-function config(options) {
- _.deepExtend(config, options);
-}
config({
attrs: {
@@ -9174,9 +8984,6 @@ config({
},
componentRef: '___milo_component',
componentPrefix: 'milo_',
- mixin: {
- instancePropertiesMap: '___mixin_instances'
- },
template: {
compile: doT.compile
},
@@ -9211,22 +9018,21 @@ config({
timeout: 15000,
responsePrefix: 'response_'
}
- },
- check: true,
- debug: false
+ }
});
-},{"dot":115,"mol-proto":150}],66:[function(require,module,exports){
+},{"milo-core":105}],65:[function(require,module,exports){
'use strict';
var miloMail = require('./services/mail')
, request = require('./util/request')
- , logger = require('./util/logger')
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , _ = miloCore.proto
, utilDom = require('./util/dom')
, config = require('./config')
- , LoadAttribute = require('./attributes/a_load')
- , LoaderError = require('./util/error').Loader;
+ , LoadAttribute = require('./attributes/a_load');
module.exports = loader;
@@ -9298,7 +9104,7 @@ function _loadViewsInElement(rootEl, removeAttribute, callback) {
function loadView(el, removeAttribute, callback) {
if (utilDom.children(el).length)
- throw new LoaderError('can\'t load html into element that is not empty');
+ throw new Error('can\'t load html into element that is not empty');
var attr = new LoadAttribute(el);
@@ -9318,9512 +9124,7842 @@ function loadView(el, removeAttribute, callback) {
});
}
-},{"./attributes/a_load":7,"./config":65,"./services/mail":84,"./util/dom":94,"./util/error":98,"./util/logger":102,"./util/request":104}],67:[function(require,module,exports){
+},{"./attributes/a_load":6,"./config":64,"./services/mail":70,"./util/dom":79,"./util/request":87,"milo-core":105}],66:[function(require,module,exports){
'use strict';
-var Mixin = require('../abstract/mixin')
- // , MessageSource = require('./message_source')
- , MessageSource = require('./m_source')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , MessengerError = require('../util/error').Messenger;
+var miloCore = require('milo-core')
+ , _ = miloCore.proto;
-/**
- * `milo.Messenger`
- * A generic Messenger class that is used for all kinds of messaging in milo. It is subclassed from [Mixin](../abstract/mixin.js.html) and it proxies its methods to the host object for convenience.
- * All facets and components have messenger attached to them. Messenger class interoperates with [MessageSource](./m_source.js.html) class that connects the messenger to some external source of messages (e.g., DOM events) and [MessengerAPI](./m_api.js.html) class that allows to define higher level messages than messages that exist on the source.
- * Messenger class is used internally in milo and can be used together with any objects/classes in the application.
- * milo also defines a global messenger [milo.mail](../mail/index.js.html) that dispatches `domready` event and can be used for any application wide messaging.
- * To initialize your app after DOM is ready use:
- * ```
- * milo.mail.on('domready', function() {
- * // application starts
- * });
- * ```
- * or the following shorter form of the same:
- * ```
- * milo(function() {
- * // application starts
- * });
- * ```
- */
-var Messenger = _.createSubclass(Mixin, 'Messenger');
+// register included facets
+require('./use_facets');
-var messagesSplitRegExp = Messenger.messagesSplitRegExp = /\s*(?:\,|\s)\s*/;
+// register included components
+require('./use_components');
/**
- * ####Messenger instance methods####
- *
- * - [init](#init)
- * - [on](#Messenger$on) (alias - onMessage, deprecated)
- * - [off](#Messenger$off) (alias - offMessage, deprecated)
- * - [onMessages](#onMessages)
- * - [offMessages](#offMessages)
- * - [once](#once)
- * - [onceSync](#onceSync)
- * - [postMessage](#postMessage)
- * - [getSubscribers](#getSubscribers)
+ * `milo`
*
- * "Private" methods
+ * A minimalist browser framework that binds DOM elements to JS components and components to models.
*
- * - [_chooseSubscribersHash](#_chooseSubscribersHash)
- * - [_registerSubscriber](#_registerSubscriber)
- * - [_removeSubscriber](#_removeSubscriber)
- * - [_removeAllSubscribers](#_removeAllSubscribers)
- * - [_callPatternSubscribers](#_callPatternSubscribers)
- * - [_callSubscribers](#_callSubscribers)
- * - [_setMessageSource](#_setMessageSource)
- * - [getMessageSource](#getMessageSource)
+ * `milo` is available as global object in the browser.
+ * At the moment it is not possiible to require it with browserify to have it bundled with the app because of the way [brfs](https://github.com/substack/brfs) browserify plugin is implemented.
+ * It is possible though to require `milo` with node to use universal parts of the framework (abstract classes, Messenger, Model, etc.):
+ * ```
+ * var milo = require('mol-milo');
+ * ```
+ *
+ * `milo` itself is a function that in the browser can be used to delay execution until DOM is ready.
*/
-_.extendProto(Messenger, {
- init: init, // called by Mixin (superclass)
- destroy: Messenger$destroy,
- on: Messenger$on,
- once: Messenger$once,
- onceSync: Messenger$onceSync,
- onSync: Messenger$onSync,
- onAsync: Messenger$onAsync,
- onMessage: Messenger$on, // deprecated
- off: Messenger$off,
- offMessage: Messenger$off, // deprecated
- onMessages: onMessages,
- offMessages: offMessages,
- offAll: Messenger$offAll,
- postMessage: postMessage,
- postMessageSync: postMessageSync,
- getSubscribers: getSubscribers,
- getMessageSource: getMessageSource,
- _chooseSubscribersHash: _chooseSubscribersHash,
- _registerSubscriber: _registerSubscriber,
- _removeSubscriber: _removeSubscriber,
- _removeAllSubscribers: _removeAllSubscribers,
- _callPatternSubscribers: _callPatternSubscribers,
- _callSubscribers: _callSubscribers,
- _callSubscriber: _callSubscriber,
- _setMessageSource: _setMessageSource
-});
+function milo(func) {
+ milo.util.domReady(func);
+}
/**
- * A default map of proxy methods used by ComponentFacet and Component classes to pass to Messenger when it is instantiated.
- * This map is for convenience only, it is NOT used internally by Messenger, a host class should pass it for methods to be proxied this way.
+ * ####Milo packages####
+ *
+ * - [loader](./loader.js.html) - loading subviews into page
+ * - [binder](./binder.js.html) - components instantiation and binding of DOM elements to them
+ * - [minder](./minder.js.html) - data reactivity, one or two way, shallow or deep, as you like it
+ * - [mail](./mail/index.js.html) - applicaiton level messenger, also connects to messages from other windows dispatched with `window.postMessage`.
+ * - [config](./config.js.html) - milo configuration
+ * - [util](./util/index.js.html) - logger, request, dom, check, error, etc.
+ * - [classes](./classes.js.html) - abstract and base classes
+ * - [attributes](./attributes/index.js.html) - classes that wrap DOM elements attributes recognized by milo
+ * - [ComponentFacet](./components/c_facet.js.html) - base class of Component facet
+ * - [Component](./components/c_class.js.html) - base Component class
+ * - [Messenger](./messenger/index.js.html) - generic Messenger used in most other milo classes, can be mixed into app classes too.
+ * - [Model](./model/index.js.html) - Model class that emits messages on changes to any depth without timer based watching
+ * - [registry](./registry.js.html) - registries of fasets and components classes
*/
-Messenger.defaultMethods = {
- on: 'on',
- onSync: 'onSync',
- once: 'once',
- onceSync: 'onceSync',
- off: 'off',
- onMessages: 'onMessages',
- offMessages: 'offMessages',
- postMessage: 'postMessage',
- postMessageSync: 'postMessageSync',
- getSubscribers: 'getSubscribers'
-};
+_.extend(milo, {
+ Messenger: miloCore.Messenger,
+ Model: miloCore.Model,
+ minder: miloCore.minder,
+ loader: require('./loader'),
+ binder: require('./binder'),
+ mail: require('./services/mail'),
+ window: require('./services/window'),
+ config: require('./config'),
+ util: require('./util'),
+ classes: require('./classes'),
+ attributes: require('./attributes'),
+ ComponentFacet: require('./components/c_facet'),
+ Component: require('./components/c_class'),
+ Command: require('./command'),
+ registry: require('./registry'),
+ milo_version: '0.1.10',
+ createComponentClass: require('./util/create_component_class'),
+ destroy: destroy
+});
-module.exports = Messenger;
+// export for node/browserify
+if (typeof module == 'object' && module.exports)
+ module.exports = milo;
+
+// global milo for browser
+if (typeof window == 'object') {
+ window.milo = milo;
+ milo.mail.trigger('miloready');
+}
-Messenger.subscriptions = [];
+function destroy() {
+ miloCore.destroy();
+ milo.mail.destroy();
+ milo.window.destroy();
+ milo.util.destroy();
+}
+},{"./attributes":7,"./binder":8,"./classes":9,"./command":12,"./components/c_class":15,"./components/c_facet":16,"./config":64,"./loader":65,"./registry":67,"./services/mail":70,"./services/window":73,"./use_components":74,"./use_facets":75,"./util":85,"./util/create_component_class":78,"milo-core":105}],67:[function(require,module,exports){
+'use strict';
/**
- * Messenger instance method
- * Initializes Messenger. Method is called by Mixin class constructor.
- * See [on](#Messenger$on) method, [Messenger](#Messenger) class above and [MessageSource](./m_source.js.html) class.
+ * Registries of facets and of components
*
- * @param {Object} hostObject Optional object that stores the messenger on one of its properties. It is used to proxy methods of messenger and also as a context for subscribers when they are called by the Messenger. See `on` method.
- * @param {Object} proxyMethods Optional map of method names; key - proxy method name, value - messenger's method name.
- * @param {MessageSource} messageSource Optional messageSource linked to the messenger. If messageSource is supplied, the reference to the messenger will stored on its 'messenger' property
+ * - [facets](./components/c_facets/cf_registry.js.html)
+ * - [components](./components/c_registry.js.html)
*/
-function init(hostObject, proxyMethods, messageSource) {
- // hostObject and proxyMethods are used in Mixin and checked there
- if (messageSource)
- this._setMessageSource(messageSource);
+var registry = module.exports = {
+ facets: require('./components/c_facets/cf_registry'),
+ components: require('./components/c_registry'),
+ commands: require('./command/cmd_registry')
+};
- _initializeSubscribers.call(this);
-}
+},{"./command/cmd_registry":11,"./components/c_facets/cf_registry":30,"./components/c_registry":32}],68:[function(require,module,exports){
+'use strict';
+//
+// ###dom events constructors
-function _initializeSubscribers() {
- _.defineProperties(this, {
- _messageSubscribers: {},
- _patternMessageSubscribers: {},
- }, _.CONF);
-}
+var _ = require('milo-core').proto;
-/**
- * Destroys messenger. Maybe needs to unsubscribe all subscribers
- */
-function Messenger$destroy() {
- this.offAll();
- var messageSource = this.getMessageSource();
- if (messageSource)
- messageSource.destroy();
-}
+// https://developer.mozilla.org/en-US/docs/Web/Reference/Events
-/**
- * Messenger instance method.
- * Registers a subscriber function for a certain message(s).
- * This method returns `true` if the subscription was successful. It can be unsuccessful if the passed subscriber has already been subscribed to this message type - double subscription never happens and it is safe to subscribe again - no error or warning is thrown or logged.
- * Subscriber is passed two parameters: `message` (string) and `data` (object). Data object is supplied when message is dispatched, Messenger itself adds nothing to it. For example, [events facet](../components/c_facets/Events.js.html) sends actual DOM event when it posts message.
- * Usage:
- * ```
- * // subscribes onMouseUpDown to two DOM events on component via events facet.
- * myComp.events.on('mousedown mouseup', onMouseUpDown);
- * function onMouseUpDown(eventType, event) {
- * // ...
- * }
- *
- * myComp.data.on(/.+/, function(msg, data) {
- * logger.debug(msg, data);
- * }); // subscribes anonymous function to all non-empty messages on data facet
- * // it will not be possible to unsubscribe anonymous subscriber separately,
- * // but myComp.data.off(/.+/) will unsubscribe it
- * ```
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added, so it can subscribe to the source.
- * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `on` when they proxy it.
- * See [postMessage](#postMessage).
- *
- * @param {String|Array[String]|RegExp} messages Message types that should envoke the subscriber.
- * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.
- * If an array of strings is passed, each string is a message type to subscribe for.
- * If a RegExp is passed, the subscriber will be envoked when the message dispatched on the messenger matches the pattern (or IS the RegExp with identical pattern).
- * Pattern subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.
- * @param {Function|Object} subscriber Message subscriber - a function that will be called when the message is dispatched on the messenger (usually via proxied postMessage method of host object).
- * If hostObject was supplied to Messenger constructor, hostObject will be the context (the value of this) for the subscriber envocation.
- * Subscriber can also be an object with properties `subscriber` (function) and `context` ("this" value when subscriber is called)
- * @return {Boolean}
- */
-function Messenger$on(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber);
-}
-
+var eventTypes = {
+ ClipboardEvent: ['copy', 'cut', 'paste', 'beforecopy', 'beforecut', 'beforepaste'],
+ Event: ['input', 'readystatechange'],
+ FocusEvent: ['focus', 'blur', 'focusin', 'focusout'],
+ KeyboardEvent: ['keydown', 'keypress', 'keyup'],
+ MouseEvent: ['click', 'contextmenu', 'dblclick', 'mousedown', 'mouseup',
+ 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover',
+ 'show' /* context menu */],
+ TouchEvent: ['touchstart', 'touchend', 'touchmove', 'touchenter', 'touchleave', 'touchcancel'],
+};
-function Messenger$once(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1 });
-}
-function Messenger$onceSync(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1, sync: true });
+// mock window and event constructors for testing
+if (typeof window != 'undefined')
+ var global = window;
+else {
+ global = {};
+ _.eachKey(eventTypes, function(eTypes, eventConstructorName) {
+ var eventConstructor = _.makeFunction(eventConstructorName, 'type', 'properties',
+ 'this.type = type; _.extend(this, properties);');
+ global[eventConstructorName] = eventConstructor;
+ });
}
-function Messenger$onSync(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: true });
-}
+var domEventsConstructors = {};
+_.eachKey(eventTypes, function(eTypes, eventConstructorName) {
+ eTypes.forEach(function(type) {
+ if (Object.hasOwnProperty(domEventsConstructors, type))
+ throw new Error('duplicate event type ' + type);
-function Messenger$onAsync(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: false });
-}
+ domEventsConstructors[type] = global[eventConstructorName];
+ });
+});
-function _Messenger_onWithOptions(messages, subscriber, options) {
- check(messages, Match.OneOf(String, [String], RegExp));
- check(subscriber, Match.OneOf(Function, {
- subscriber: Function,
- context: Match.Any,
- options: Match.Optional(Object),
- }));
+module.exports = domEventsConstructors;
- if (typeof subscriber == 'function') {
- subscriber = {
- subscriber: subscriber,
- context: this._hostObject,
- };
- }
+},{"milo-core":105}],69:[function(require,module,exports){
+'use strict';
- if (options) {
- subscriber.options = subscriber.options || {};
- _.extend(subscriber.options, options);
- }
- return _Messenger_on.call(this, messages, subscriber);
-}
+var miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
+ , Component = require('../components/c_class')
+ , domEventsConstructors = require('./de_constrs') // TODO merge with DOMEventSource ??
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , Match = check.Match;
+var DOMEmitterSource = _.createSubclass(MessageSource, 'DOMEmitterSource', true);
-function _Messenger_on(messages, subscriber) {
- _.defineProperty(subscriber, '__messages', messages);
- return _eachMessage.call(this, '_registerSubscriber', messages, subscriber);
-}
+_.extendProto(DOMEmitterSource, {
+ // implementing MessageSource interface
+ init: init,
+ destroy: DOMEmitterSource$destroy,
+ addSourceSubscriber: _.partial(sourceSubscriberMethod, 'addEventListener'),
+ removeSourceSubscriber: _.partial(sourceSubscriberMethod, 'removeEventListener'),
+ postMessage: DOMEmitterSource$postMessage,
+ trigger: trigger,
-function _eachMessage(methodName, messages, subscriber) {
- if (typeof messages == 'string')
- messages = messages.split(messagesSplitRegExp);
+ // class specific methods
+ emitter: emitter,
+ handleEvent: handleEvent, // event dispatcher - as defined by Event DOM API
+});
- var subscribersHash = this._chooseSubscribersHash(messages);
+module.exports = DOMEmitterSource;
- if (messages instanceof RegExp)
- return this[methodName](subscribersHash, messages, subscriber);
- else {
- var changed = false;
+var useCapturePattern = /__capture$/
+ , useCapturePostfix = '__capture';
- messages.forEach(function(message) {
- var subscriptionChanged = this[methodName](subscribersHash, message, subscriber);
- changed = changed || subscriptionChanged;
- }, this);
- return changed;
- }
+// init DOM event source
+function init(hostObject, proxyMethods, messengerAPIOrClass, eventEmitter) {
+ this.eventEmitter = eventEmitter;
+ MessageSource.prototype.init.apply(this, arguments);
}
-/**
- * "Private" Messenger instance method
- * It is called by [on](#Messenger$on) to register subscriber for one message type.
- * Returns `true` if this subscriber is not yet registered for this type of message.
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added.
- *
- * @private
- * @param {Object} subscribersHash The map of subscribers determined by [on](#Messenger$on) based on Message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
- * @param {String} message Message type
- * @param {Function|Object} subscriber Subscriber function to be added or object with properties `subscriber` (function) and `context` (value of "this" when subscriber is called)
- * @return {Boolean}
- */
-function _registerSubscriber(subscribersHash, message, subscriber) {
- if (! (subscribersHash[message] && subscribersHash[message].length)) {
- subscribersHash[message] = [];
- if (message instanceof RegExp)
- subscribersHash[message].pattern = message;
- if (this._messageSource)
- this._messageSource.onSubscriberAdded(message);
- var noSubscribers = true;
- }
-
- var msgSubscribers = subscribersHash[message];
- var notYetRegistered = noSubscribers || _indexOfSubscriber.call(this, msgSubscribers, subscriber) == -1;
+function DOMEmitterSource$destroy() {
+ MessageSource.prototype.destroy.apply(this, arguments);
+ delete this.eventEmitter;
+}
- if (notYetRegistered)
- msgSubscribers.push(subscriber);
- return notYetRegistered;
+// get DOM element of component
+function emitter() {
+ return this.eventEmitter;
}
-/**
- * Finds subscriber index in the list
- *
- * @param {Array[Function|Object]} list list of subscribers
- * @param {Function|Object} subscriber subscriber function or object with properties `subscriber` (function) and `context` ("this" object)
- */
-function _indexOfSubscriber(list, subscriber) {
- var self = this;
- return _.findIndex(list, function(subscr){
- return subscriber.subscriber == subscr.subscriber
- && subscriber.context == subscr.context
- });
+function sourceSubscriberMethod(method, eventType) {
+ if (! (eventType && typeof eventType == 'string')) return;
+ var capture = useCapturePattern.test(eventType);
+ eventType = eventType.replace(useCapturePattern, '');
+ this.emitter()[method](eventType, this, capture);
}
-/**
- * Messenger instance method.
- * Subscribes to multiple messages passed as map together with subscribers.
- * Usage:
- * ```
- * myComp.events.onMessages({
- * 'mousedown': onMouseDown,
- * 'mouseup': onMouseUp
- * });
- * function onMouseDown(eventType, event) {}
- * function onMouseUp(eventType, event) {}
- * ```
- * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was added.
- * It is NOT possible to add pattern subscriber using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.
- *
- * @param {Object[Function]} messageSubscribers Map of message subscribers to be added
- * @return {Object[Boolean]}
- */
-function onMessages(messageSubscribers) {
- check(messageSubscribers, Match.ObjectHash(Match.OneOf(Function, { subscriber: Function, context: Match.Any })));
+// event dispatcher - as defined by Event DOM API
+function handleEvent(event) {
+ var isCapturePhase;
+ if (typeof window != 'undefined')
+ isCapturePhase = event.eventPhase == window.Event.CAPTURING_PHASE;
- var notYetRegisteredMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {
- return this.on(messages, subscriber);
- }, this);
+ if (isCapturePhase)
+ event += useCapturePostfix;
- return notYetRegisteredMap;
+ this.dispatchMessage(event.type, event);
}
-/**
- * Messenger instance method.
- * Removes a subscriber for message(s). Removes all subscribers for the message if subscriber isn't passed.
- * This method returns `true` if the subscriber was registered. No error or warning is thrown or logged if you remove subscriber that was not registered.
- * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `off` when they proxy it.
- * Usage:
- * ```
- * // unsubscribes onMouseUpDown from two DOM events.
- * myComp.events.off('mousedown mouseup', onMouseUpDown);
- * ```
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.
- *
- * @param {String|Array[String]|RegExp} messages Message types that a subscriber should be removed for.
- * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.
- * If an array of strings is passed, each string is a message type to remove a subscriber for.
- * If a RegExp is passed, the pattern subscriber will be removed.
- * RegExp subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.
- * @param {Function} subscriber Message subscriber - Optional function that will be removed from the list of subscribers for the message(s). If subscriber is not supplied, all subscribers will be removed from this message(s).
- * @return {Boolean}
- */
-function Messenger$off(messages, subscriber) {
- check(messages, Match.OneOf(String, [String], RegExp));
- check(subscriber, Match.Optional(Match.OneOf(Function, {
- subscriber: Function,
- context: Match.Any,
- options: Match.Optional(Object),
- // __messages: Match.Optional(Match.OneOf(String, [String], RegExp))
- })));
-
- return _Messenger_off.call(this, messages, subscriber);
+function DOMEmitterSource$postMessage(message, data) {
+ this.messenger.postMessageSync(message, data);
}
-function _Messenger_off(messages, subscriber) {
- return _eachMessage.call(this, '_removeSubscriber', messages, subscriber);
-}
+function trigger(eventType, properties) {
+ check(eventType, String);
+ check(properties, Match.Optional(Object));
+ eventType = eventType.replace(useCapturePattern, '');
+ var EventConstructor = domEventsConstructors[eventType];
-/**
- * "Private" Messenger instance method
- * It is called by [off](#Messenger$off) to remove subscriber for one message type.
- * Returns `true` if this subscriber was registered for this type of message.
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.
- *
- * @private
- * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
- * @param {String} message Message type
- * @param {Function} subscriber Subscriber function to be removed
- * @return {Boolean}
- */
-function _removeSubscriber(subscribersHash, message, subscriber) {
- var msgSubscribers = subscribersHash[message];
- if (! msgSubscribers || ! msgSubscribers.length)
- return false; // nothing removed
-
- if (subscriber) {
- if (typeof subscriber == 'function')
- subscriber = { subscriber: subscriber, context: this._hostObject };
-
- var subscriberIndex = _indexOfSubscriber.call(this, msgSubscribers, subscriber);
- if (subscriberIndex == -1)
- return false; // nothing removed
- msgSubscribers.splice(subscriberIndex, 1);
- if (! msgSubscribers.length)
- this._removeAllSubscribers(subscribersHash, message);
+ if (typeof EventConstructor != 'function')
+ throw new Error('unsupported event type');
- } else
- this._removeAllSubscribers(subscribersHash, message);
+ // check if it is correct
+ if (typeof properties != 'undefined')
+ properties.type = eventType;
- return true; // subscriber(s) removed
+ var domEvent = new EventConstructor(eventType, properties);
+ var notCancelled = this.emitter().dispatchEvent(domEvent);
+ return notCancelled;
}
+},{"../components/c_class":15,"./de_constrs":68,"milo-core":105}],70:[function(require,module,exports){
+'use strict';
/**
- * "Private" Messenger instance method
- * It is called by [_removeSubscriber](#_removeSubscriber) to remove all subscribers for one message type.
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified that all message subscribers were removed so it can unsubscribe from the source.
+ * `milo.mail`
+ * It is an application level messenger that is an instance of Messenger class.
*
- * @private
- * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
- * @param {String} message Message type
- */
-function _removeAllSubscribers(subscribersHash, message) {
- delete subscribersHash[message];
- if (this._messageSource && typeof message == 'string')
- this._messageSource.onSubscriberRemoved(message);
-}
+ * At the moment, in addition to application messages that you define, you can subscribe to __domready__ message that is guaranteed to fire once,
+ * even if DOM was ready at the time of the subscription.
+ *
+ * Messaging between frames is available via milo.mail. See [Frame facet](../components/c_facets/Frame.js.html).
+ *
+ * See [Messenger](../messenger/index.js.html).
+ *
+**/
-/**
- * Messenger instance method.
- * Unsubscribes from multiple messages passed as map together with subscribers.
- * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was removed.
- * If a subscriber for one of the messages is not supplied, all subscribers for this message will be removed.
- * Usage:
- * ```
- * myComp.events.offMessages({
- * 'mousedown': onMouseDown,
- * 'mouseup': onMouseUp,
- * 'click': undefined // all subscribers to this message will be removed
- * });
- * ```
- * It is NOT possible to remove pattern subscriber(s) using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.
- *
- * @param {Object[Function]} messageSubscribers Map of message subscribers to be removed
- * @return {Object[Boolean]}
- */
-function offMessages(messageSubscribers) {
- check(messageSubscribers, Match.ObjectHash(Match.Optional(Match.OneOf(Function, { subscriber: Function, context: Match.Any }))));
+var miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
+ , MailMsgAPI = require('./mail_api')
+ , MailMessageSource = require('./mail_source')
+ , _ = miloCore.proto;
- var subscriberRemovedMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {
- return this.off(messages, subscriber);
- }, this);
- return subscriberRemovedMap;
-}
+var miloMail = new Messenger;
+var mailMsgSource = new MailMessageSource(miloMail, { trigger: 'trigger' }, new MailMsgAPI);
-/**
- * Unsubscribes all subscribers
- */
-function Messenger$offAll() {
- _offAllSubscribers.call(this, this._patternMessageSubscribers);
- _offAllSubscribers.call(this, this._messageSubscribers);
-}
+miloMail._setMessageSource(mailMsgSource);
-function _offAllSubscribers(subscribersHash) {
- _.eachKey(subscribersHash, function(subscribers, message) {
- this._removeAllSubscribers(subscribersHash, message);
- }, this);
-}
+module.exports = miloMail;
+},{"./mail_api":71,"./mail_source":72,"milo-core":105}],71:[function(require,module,exports){
+'use strict';
-// TODO - send event to messageSource
+var miloCore = require('milo-core')
+ , MessengerAPI = miloCore.classes.MessengerAPI
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , Match = check.Match;
-/**
- * Messenger instance method.
- * Dispatches the message calling all subscribers registered for this message and, if the message is a string, calling all pattern subscribers when message matches the pattern.
- * Each subscriber is passed the same parameters that are passed to theis method.
- * The context of the subscriber envocation is set to the host object (`this._hostObject`) that was passed to the messenger constructor.
- * Subscribers are called in the next tick ("asynchronously") apart from those that were subscribed with `onSync` (or that have `options.sync == true`).
- *
- * @param {String|RegExp} message message to be dispatched
- * If the message is a string, the subscribers registered with exactly this message will be called and also pattern subscribers registered with the pattern that matches the dispatched message.
- * If the message is RegExp, only the subscribers registered with exactly this pattern will be called.
- * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
- * @param {Function} callback optional callback to pass to subscriber
- * @param {Boolean} _synchronous if true passed, subscribers will be envoked synchronously apart from those that have `options.sync == false`. This parameter should not be used, instead postMessageSync should be used.
- */
-function postMessage(message, data, callback, _synchronous) {
- check(message, Match.OneOf(String, RegExp));
- check(callback, Match.Optional(Function));
+var MailMsgAPI = _.createSubclass(MessengerAPI, 'MailMsgAPI', true);
- var subscribersHash = this._chooseSubscribersHash(message);
- var msgSubscribers = subscribersHash[message];
- this._callSubscribers(message, data, callback, msgSubscribers, _synchronous);
+_.extendProto(MailMsgAPI, {
+ translateToSourceMessage: translateToSourceMessage,
+ filterSourceMessage: filterSourceMessage
+});
- if (typeof message == 'string')
- this._callPatternSubscribers(message, data, callback, msgSubscribers, _synchronous);
-}
+module.exports = MailMsgAPI;
-/**
- * Same as postMessage apart from envoking subscribers synchronously, apart from those subscribed with `onAsync` (or with `options.sync == false`).
- *
- * @param {String|RegExp} message
- * @param {Any} data
- * @param {Function} callback
- */
-function postMessageSync(message, data, callback) {
- this.postMessage(message, data, callback, true);
+// TODO: this function should return relevant DOM event dependent on element tag
+// Can also implement beforedatachanged event to allow preventing the change
+// translateToDomEvent
+var windowMessageRegExp = /^message\:/
+ , windowMessagePrefix = 'message:';
+
+function translateToSourceMessage(message) {
+ if (message == 'domready')
+ return 'readystatechange';
+ else if (windowMessageRegExp.test(message))
+ return 'message';
}
-/**
- * "Private" Messenger instance method
- * Envokes pattern subscribers with the pattern that matches the message.
- * The method is called by [postMessage](#postMessage) - see more information there.
- *
- * @private
- * @param {String} message message to be dispatched. Pattern subscribers registered with the pattern that matches the dispatched message will be called.
- * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
- * @param {Function} callback optional callback to pass to subscriber
- * @param {Array[Function|Object]} calledMsgSubscribers array of subscribers already called, they won't be called again if they are among pattern subscribers.
- */
-function _callPatternSubscribers(message, data, callback, calledMsgSubscribers, _synchronous) {
- _.eachKey(this._patternMessageSubscribers,
- function(patternSubscribers) {
- var pattern = patternSubscribers.pattern;
- if (pattern.test(message)) {
- if (calledMsgSubscribers) {
- var patternSubscribers = patternSubscribers.filter(function(subscriber) {
- var index = _indexOfSubscriber.call(this, calledMsgSubscribers, subscriber);
- return index == -1;
- });
- }
- this._callSubscribers(message, data, callback, patternSubscribers, _synchronous);
- }
- }
- , this);
-}
+// filterDataMessage
+function filterSourceMessage(sourceMessage, msgType, msgData) {
+ if (sourceMessage == 'readystatechange') {
+ //return document.readyState == 'interactive';
+ // return false;
+ // _.defineProperty(this, '_domReadyFired', true, _.WRIT);
+ return true;
+ } else if (sourceMessage == 'message')
+ return windowMessagePrefix + msgData.data.type == msgType;
+};
+},{"milo-core":105}],72:[function(require,module,exports){
+'use strict';
-/**
- * "Private" Messenger instance method
- * Envokes subscribers from the passed list.
- * The method is called by [postMessage](#postMessage) and [_callPatternSubscribers](#_callPatternSubscribers).
- *
- * @private
- * @param {String} message message to be dispatched, passed to subscribers as the first parameter.
- * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
- * @param {Array[Function|Object]} msgSubscribers the array of message subscribers to be called. Each subscriber is called with the host object (see Messenger constructor) as the context.
- * @param {Function} callback optional callback to pass to subscriber
- */
-function _callSubscribers(message, data, callback, msgSubscribers, _synchronous) {
- if (msgSubscribers && msgSubscribers.length) {
- // cloning is necessary as some of the subscribers
- // can be unsubscribed during the dispatch
- // so this array would change in the process
- msgSubscribers = msgSubscribers.slice();
+var miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
+ , domEventsConstructors = require('../de_constrs')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , Match = check.Match;
- msgSubscribers.forEach(function(subscriber) {
- this._callSubscriber(subscriber, message, data, callback, _synchronous);
- }, this);
- }
-}
+var MailMessageSource = _.createSubclass(MessageSource, 'MailMessageSource', true);
-function _callSubscriber(subscriber, message, data, callback, _synchronous) {
- var syncSubscriber = subscriber.options && subscriber.options.sync
- , synchro = (_synchronous && syncSubscriber !== false)
- || syncSubscriber;
- var dispatchTimes = subscriber.options && subscriber.options.dispatchTimes;
- if (dispatchTimes) {
- if (dispatchTimes <= 1) {
- var messages = subscriber.__messages;
- this.off(messages, subscriber);
- } else if (dispatchTimes > 1)
- subscriber.options.dispatchTimes--;
- }
+_.extendProto(MailMessageSource, {
+ // implementing MessageSource interface
+ addSourceSubscriber: addSourceSubscriber,
+ removeSourceSubscriber: removeSourceSubscriber,
+ trigger: trigger,
- if (synchro)
- subscriber.subscriber.call(subscriber.context, message, data, callback);
- else
- _.deferMethod(subscriber.subscriber, 'call', subscriber.context, message, data, callback);
-}
+ // class specific methods
+ _windowSubscriberMethod: _windowSubscriberMethod,
+ handleEvent: handleEvent, // event dispatcher - as defined by Event DOM API
+});
-/**
- * Messenger instance method.
- * Returns the array of subscribers that would be called if the message were dispatched.
- * If `includePatternSubscribers === false`, pattern subscribers with matching patters will not be included (by default they are included).
- * If there are no subscribers to the message, `undefined` will be returned, not an empty array, so it is safe to use the result in boolean tests.
- *
- * @param {String|RegExp} message Message to get subscribers for.
- * If the message is RegExp, only pattern subscribers registered with exactly this pattern will be returned.
- * If the message is String, subscribers registered with the string messages and pattern subscribers registered with matching pattern will be returned (unless the second parameter is false).
- * @param {Boolean} includePatternSubscribers Optional false to prevent inclusion of patter subscribers, by default they are included.
- * @return {Array|undefined}
- */
-function getSubscribers(message, includePatternSubscribers) {
- check(message, Match.OneOf(String, RegExp));
+module.exports = MailMessageSource;
- var subscribersHash = this._chooseSubscribersHash(message);
- var msgSubscribers = subscribersHash[message]
- ? [].concat(subscribersHash[message])
- : [];
- // pattern subscribers are incuded by default
- if (includePatternSubscribers !== false && typeof message == 'string') {
- _.eachKey(this._patternMessageSubscribers,
- function(patternSubscribers) {
- var pattern = patternSubscribers.pattern;
- if (patternSubscribers && patternSubscribers.length
- && pattern.test(message))
- _.appendArray(msgSubscribers, patternSubscribers);
- }
- );
- }
+function addSourceSubscriber(sourceMessage) {
+ if (isReadyStateChange(sourceMessage)) {
+ if (document.readyState == 'loading')
+ document.addEventListener('readystatechange', this, false);
+ else {
+ var EventConstructor = domEventsConstructors.readystatechange;
+ var domEvent = new EventConstructor('readystatechange', { target: document });
+ this.dispatchMessage('readystatechange', domEvent);
+ }
+ } else
+ this._windowSubscriberMethod('addEventListener', sourceMessage);
+}
- // return undefined if there are no subscribers
- return msgSubscribers.length
- ? msgSubscribers
- : undefined;
+
+function removeSourceSubscriber(sourceMessage) {
+ if (isReadyStateChange(sourceMessage))
+ document.removeEventListener('readystatechange', this, false);
+ else
+ this._windowSubscriberMethod('removeEventListener', sourceMessage);
}
-/**
- * "Private" Messenger instance method
- * Returns the map of subscribers for a given message type.
- *
- * @private
- * @param {String|RegExp} message Message to choose the map of subscribers for
- * @return {Object[Function]}
- */
-function _chooseSubscribersHash(message) {
- return message instanceof RegExp
- ? this._patternMessageSubscribers
- : this._messageSubscribers;
+function isReadyStateChange(sourceMessage) {
+ return sourceMessage == 'readystatechange' && typeof document == 'object';
}
+function isWindowMessage(sourceMessage) {
+ return sourceMessage == 'message' && typeof window == 'object';
+}
-/**
- * Messenger instance method
- * Sets [MessageSource](./m_source.js.html) for the messenger also setting the reference to the messenger in the MessageSource.
- * MessageSource can be passed to message constructor; this method allows to set it at a later time. For example, the subclasses of [ComponentFacet](../components/c_facet.js.html) use this method to set different MessageSource'es in the messenger that is created by ComponentFacet.
- * Currently the method is implemented in such way that it can be called only once - MessageSource cannot be changed after this method is called.
- *
- * @param {MessageSource} messageSource an instance of MessageSource class to attach to this messenger (and to have this messenger attached to it too)
- */
-function _setMessageSource(messageSource) {
- check(messageSource, MessageSource);
+function _windowSubscriberMethod(method, sourceMessage) {
+ if (isWindowMessage(sourceMessage))
+ window[method]('message', this, false);
+}
- _.defineProperty(this, '_messageSource', messageSource);
- messageSource.messenger = this;
+
+// event dispatcher - as defined by Event DOM API
+function handleEvent(event) {
+ this.dispatchMessage(event.type, event);
}
-/**
- * Messenger instance method
- * Returns messenger MessageSource
- *
- * @return {MessageSource}
- */
-function getMessageSource() {
- return this._messageSource
+function trigger(msgType, data) {
+ data = data || {};
+ data.type = 'message:' + msgType;
+
+ if (typeof window == 'object')
+ window.postMessage(data, '*')
}
-},{"../abstract/mixin":3,"../util/check":90,"../util/error":98,"./m_source":70,"mol-proto":150}],68:[function(require,module,exports){
+},{"../de_constrs":68,"milo-core":105}],73:[function(require,module,exports){
'use strict';
-var _ = require('mol-proto')
- , logger = require('../util/logger');
+var miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
+ , DOMEmitterSource = require('./dom_source')
+ , _ = miloCore.proto;
-module.exports = MessengerAPI;
+var windowService = new Messenger;
+var domEmitterSource = new DOMEmitterSource(windowService, { trigger: 'trigger' }, undefined, window);
+windowService._setMessageSource(domEmitterSource);
-/**
- * `milo.classes.MessengerAPI`
- * Base class, subclasses of which can supplement the functionality of [MessageSource](./m_source.js.html) by implementing three methods:
- *
- * - `translateToSourceMessage` to translate source messages (recieved from external source via `MessageSOurce`) to internal messages (that are dispatched on Messenger), allowing to make internal messages more detailed than source messages. For example, [Data facet](../components/c_facets/Data.js.html) uses [DataMsgAPI](../components/msg_api/data.js.html) to define several internal messages related to the change of state in contenteditable DOM element.
- * - `createInternalData` to modify message data received from source to some more meaningful or more detailed message data that will be dispatched on Messenger. For example, [Data facet](../components/c_facets/Data.js.html) uses [DataMsgAPI](../components/msg_api/data.js.html) (subclass of MessengerAPI) to translate DOM messages to data change messages.
- * - `filterSourceMessage` to enable/disable message dispatch based on some conditions in data.
- *
- * If `MessageSource` constructor is not passed an instance of some subclass of `MessengerAPI`, it automatically creates an instance of MessengerAPI that defines all 3 of those methods in a trivial way. See these methods below for their signatures.
- *
- * @constructor
- * @this {MessengerAPI}
- * @return {MessengerAPI}
- */
-function MessengerAPI() {
- if (this.init)
- this.init.apply(this, arguments);
-}
+module.exports = windowService;
-/**
- * ####MessengerAPI instance methods####
- *
- * - [init](#init) - initializes MessengerAPI
- * - [addInternalMessage](#addInternalMessage) - adds internal message
- * - [removeInternalMessage](#removeInternalMessage) - removes internal message
- * - [getInternalMessages](#getInternalMessages) - returns the list of internal messages for given source message
- *
- * These methods should be redefined by subclass:
- *
- * - [translateToSourceMessage](#translateToSourceMessage) - converts internal message type to source (external) message type
- * - [createInternalData](#createInternalData) - converts source message data received via MessageSource to internal message data
- * - [filterSourceMessage](#filterSourceMessage) - filters source message based on the data of the message and the corresponding internal message that is about to be sent on Messenger
- */
-_.extendProto(MessengerAPI, {
- init: init,
- destroy: MessengerAPI$destroy,
- addInternalMessage: addInternalMessage,
- removeInternalMessage: removeInternalMessage,
- getInternalMessages: getInternalMessages,
- // should be redefined by subclass
- translateToSourceMessage: translateToSourceMessage,
- createInternalData: createInternalData,
- filterSourceMessage: filterSourceMessage
+_.extend(windowService, {
+ isTop: windowService_isTop
});
-/**
- * MessengerAPI instance method
- * Called by MessengerAPI constructor. Subclasses that re-implement `init` method should call this method using: `MessengerAPI.prototype.init.apply(this, arguments)`
- */
-function init() {
- _.defineProperty(this, '_internalMessages', {});
+function windowService_isTop() {
+ return window.top == window.self || window.__karma__;
}
+},{"./dom_source":69,"milo-core":105}],74:[function(require,module,exports){
+'use strict';
-/**
- * Destroys messenger API
- */
-function MessengerAPI$destroy() {
+require('./components/classes/View');
+require('./components/ui/Group');
+require('./components/ui/Wrapper');
+require('./components/ui/Text');
+require('./components/ui/Select');
+require('./components/ui/Input');
+require('./components/ui/InputList');
+require('./components/ui/Textarea');
+require('./components/ui/RadioGroup');
+require('./components/ui/Button');
+require('./components/ui/Hyperlink');
+require('./components/ui/List');
+require('./components/ui/ListItem');
+require('./components/ui/Time');
+require('./components/ui/Date');
+require('./components/ui/Combo');
+require('./components/ui/SuperCombo');
+require('./components/ui/ComboList');
+require('./components/ui/Image');
+require('./components/ui/DropTarget');
+require('./components/ui/FoldTree');
-}
+require('./components/ui/bootstrap/Dropdown');
+// require('./components/ui/bootstrap/Dialog');
+},{"./components/classes/View":34,"./components/ui/Button":41,"./components/ui/Combo":42,"./components/ui/ComboList":43,"./components/ui/Date":44,"./components/ui/DropTarget":45,"./components/ui/FoldTree":46,"./components/ui/Group":47,"./components/ui/Hyperlink":48,"./components/ui/Image":49,"./components/ui/Input":50,"./components/ui/InputList":51,"./components/ui/List":52,"./components/ui/ListItem":53,"./components/ui/RadioGroup":54,"./components/ui/Select":55,"./components/ui/SuperCombo":56,"./components/ui/Text":57,"./components/ui/Textarea":58,"./components/ui/Time":59,"./components/ui/Wrapper":60,"./components/ui/bootstrap/Dropdown":63}],75:[function(require,module,exports){
+'use strict';
-/**
- * MessengerAPI instance method
- * Translates internal `message` to source message, adds internal `message` to the list, making sure the same `message` wasn't passed before (it would indicate Messenger error).
- * Returns source message if it is used first time (so that `MessageSource` subcribes to this source message) or `undefined`.
- *
- * @param {String} message internal message to be translated and added
- * @return {String|undefined}
- */
-function addInternalMessage(message) {
- var internalMsgs
- , sourceMessage = this.translateToSourceMessage(message);
+require('./components/c_facets/Dom');
+require('./components/c_facets/Data');
+require('./components/c_facets/Frame');
+require('./components/c_facets/Events');
+require('./components/c_facets/Options');
+require('./components/c_facets/Template');
+require('./components/c_facets/Container');
+require('./components/c_facets/ModelFacet');
+require('./components/c_facets/Drag');
+require('./components/c_facets/Drop');
+require('./components/c_facets/List');
+require('./components/c_facets/Item');
+require('./components/c_facets/Transfer');
- if (typeof sourceMessage == 'undefined') return;
+},{"./components/c_facets/Container":17,"./components/c_facets/Data":18,"./components/c_facets/Dom":19,"./components/c_facets/Drag":20,"./components/c_facets/Drop":21,"./components/c_facets/Events":22,"./components/c_facets/Frame":23,"./components/c_facets/Item":24,"./components/c_facets/List":25,"./components/c_facets/ModelFacet":26,"./components/c_facets/Options":27,"./components/c_facets/Template":28,"./components/c_facets/Transfer":29}],76:[function(require,module,exports){
+'use strict';
- if (this._internalMessages.hasOwnProperty(sourceMessage)) {
- internalMsgs = this._internalMessages[sourceMessage];
- if (internalMsgs.indexOf(message) == -1)
- internalMsgs.push(message);
- else
- logger.warn('Duplicate addInternalMessage call for internal message ' + message);
- } else {
- internalMsgs = this._internalMessages[sourceMessage] = [];
- internalMsgs.push(message);
- return sourceMessage;
- }
-}
+var count = require('./count')
+ , config = require('../config')
+ , prefix = config.componentPrefix;
-/**
- * MessengerAPI instance method
- * Removes internal `message` from the list connected to corresponding source message (`translateToSourceMessage` is used for translation).
- * Returns source message, if the last internal message was removed (so that `MessageSource` can unsubscribe from this source message), or `undefined`.
- *
- * @param {String} message internal message to be translated and removed
- * @return {String|undefined}
- */
-function removeInternalMessage(message) {
- var sourceMessage = this.translateToSourceMessage(message);
+module.exports = componentName;
- if (typeof sourceMessage == 'undefined') return;
- var internalMsgs = this._internalMessages[sourceMessage];
+function componentName() {
+ return prefix + count();
+}
- if (internalMsgs && internalMsgs.length) {
- var messageIndex = internalMsgs.indexOf(message);
- if (messageIndex >= 0) {
- internalMsgs.splice(messageIndex, 1);
- if (internalMsgs.length == 0) {
- delete this._internalMessages[sourceMessage];
- return sourceMessage;
- }
- } else
- unexpectedNotificationWarning();
- } else
- unexpectedNotificationWarning();
+},{"../config":64,"./count":77}],77:[function(require,module,exports){
+'use strict';
+var timestamp = Date.now()
+ , count = ''
+ , uniqueID = '' + timestamp;
- function unexpectedNotificationWarning() {
- logger.warn('notification received: un-subscribe from internal message ' + message
- + ' without previous subscription notification');
+function uniqueCount() {
+ var newTimestamp = Date.now();
+ uniqueID = '' + newTimestamp;
+ if (timestamp == newTimestamp) {
+ count = count === '' ? 0 : count + 1;
+ uniqueID += '_' + count;
+ } else {
+ timestamp = newTimestamp;
+ count = '';
}
-}
+ return uniqueID;
+}
-/**
- * MessengerAPI instance method
- * Returns the array of internal messages that were translated to given `sourceMessage`.
- * This method is used by `MessageSource` to dispatch source message on the `Mesenger`.
- *
- * @param {String} sourceMessage source message
- * @return {Array[String]}
- */
-function getInternalMessages(sourceMessage) {
- return this._internalMessages[sourceMessage];
+uniqueCount.get = function() {
+ return uniqueID;
}
+module.exports = uniqueCount;
-/**
- * MessengerAPI instance method
- * Subclasses should re-implement this method to define the rule for translation of internal `message` to source message. This class simply returns the same `message`.
- *
- * @param {String} message internal message to be translated
- * @return {String}
- */
-function translateToSourceMessage(message) {
- return message
-}
+},{}],78:[function(require,module,exports){
+'use strict';
+var _ = require('milo-core').proto;
-/**
- * MessengerAPI instance method
- * Subclasses should re-implement this method to define the rule for translation of source message data to internal message data. This class simply returns the same `sourceData`.
- * This method is used in [dispatchMessage](./m_source.js.html#dispatchMessage) method of `MessageSource`.
- *
- * @param {String} sourceMessage source message, can be used in translation rule
- * @param {String} message internal message, can be used in translation rule
- * @param {Object} sourceData data received from source that has to be translated to data that will be sent to internal Messenger subscriber
- * @return {Object}
- */
-function createInternalData(sourceMessage, message, sourceData) {
- return sourceData;
-}
+module.exports = createComponentClass;
/**
- * MessengerAPI instance method
- * Subclasses should re-implement this method to define the dispatch filter for internal messages. This method should return `true` to allow and `false` to prevent internal message dispatch. This class always returns `true`.
- * This method is used in [dispatchMessage](./m_source.js.html#dispatchMessage) method of `MessageSource`.
+ * Utility function which creates and registers new milo component. The component created will have
+ * a reference to the super class used in its creation (Accessable using .super).
*
- * @param {String} sourceMessage source message, can be used in filter rule
- * @param {String} message internal message, can be used in filter rule
- * @param {Object} internalData data translated by `createInternalData` method from source data, can be used in filter rule
- * @return {Boolean}
+ * @param {string} config.className - The name of the new component
+ * @param {string} ['Component'] config.superClassName - The name of an existing component to be used as the new component's super class
+ * @param {object=} config.facets - Facet configuration (Hash of facet name {string} to config {object})
+ * @param {object=} config.methods - Methods of the new component (Hash of function name {string} to function {function})
+ * @param {object=} config.staticMethods - Static methods of the new component (Hash of function name {string} to function {function})
*/
-function filterSourceMessage(sourceMessage, message, internalData) {
- return true;
+function createComponentClass(config) {
+ var componentRegistry = milo.registry.components;
+ var SuperClass = componentRegistry.get(config.superClassName || 'Component');
+ var ComponentClass = SuperClass.createComponentClass(config.className, config.facets);
+
+ if(config.methods) {
+ _.extendProto(ComponentClass, config.methods);
+ }
+
+ if(config.staticMethods) {
+ if(config.staticMethods.super !== undefined) throw '\'super\' is a reserved keyword';
+
+ _.extend(ComponentClass, config.staticMethods);
+ }
+
+ ComponentClass.super = SuperClass.prototype;
+
+ componentRegistry.add(ComponentClass);
+
+ return ComponentClass;
}
-},{"../util/logger":102,"mol-proto":150}],69:[function(require,module,exports){
+},{"milo-core":105}],79:[function(require,module,exports){
'use strict';
-var MessengerAPI = require('./m_api')
- , _ = require('mol-proto');
+var config = require('../config')
+ , miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger;
-/**
- * A generic subsclass of [MessengerAPI](./m_api.js.html) that supports pattern subscriptions to source.
- * Can be useful if the source is another Messenger.
- */
- var MessengerRegexpAPI = _.createSubclass(MessengerAPI, 'MessengerRegexpAPI');
+var domUtils = {
+ children: children,
+ filterNodeListByType: filterNodeListByType,
+ containingElement: containingElement,
+ selectElementContents: selectElementContents,
+ selectElementText: selectElementText,
+ getElementOffset: getElementOffset,
+ setCaretPosition: setCaretPosition,
+ getSelectionDirection: getSelectionDirection,
+ setSelection: setSelection,
+ clearSelection: clearSelection,
+ removeElement: removeElement,
+ unwrapElement: unwrapElement,
+ wrapInElement: wrapInElement,
+ detachComponent: detachComponent,
+ firstTextNode: firstTextNode,
+ lastTextNode: lastTextNode,
+ trimNodeRight: trimNodeRight,
+ trimNodeLeft: trimNodeLeft,
+ stripHtml: stripHtml,
+ htmlEntities: htmlEntities,
+ walkTree: walkTree,
+ createTreeWalker: createTreeWalker,
- module.exports = MessengerRegexpAPI;
+ treePathOf: treePathOf,
+ getNodeAtTreePath: getNodeAtTreePath,
+ insertAtTreePath: insertAtTreePath,
+ isTreePathBefore: isTreePathBefore,
+ getNodeWindow: getNodeWindow,
-_.extendProto(MessengerRegexpAPI, {
- init: init,
- addInternalMessage: addInternalMessage,
- removeInternalMessage: removeInternalMessage,
- getInternalMessages: getInternalMessages
-});
+ getComponentsFromRange: getComponentsFromRange,
+ deleteRangeWithComponents: deleteRangeWithComponents,
+ forEachNodesInRange: forEachNodesInRange,
+ areRangesEqual: areRangesEqual,
+
+ addDebugPoint: addDebugPoint
+};
+
+module.exports = domUtils;
/**
- * MessengerRegexpAPI instance method
- * Called by MessengerRegexpAPI constructor.
+ * Returns the list of element children of DOM element
+ *
+ * @param {Element} el element to return the children of (only DOM elements)
+ * @return {Array[Element]}
*/
-function init() {
- MessengerAPI.prototype.init.apply(this, arguments);
- _.defineProperties(this, {
- _patternInternalMessages: {}
- });
- this._catchAllSubscribed = false;
-}
+ function children(el) {
+ return filterNodeListByType(el.childNodes, Node.ELEMENT_NODE);
+ }
/**
- * MessengerRegexpAPI instance method
- * Augments MessengerAPI method by storing regexp
+ * Filters the list of nodes by type
*
- * @param {String} message internal message to be translated and added
- * @return {String|RegExp|undefined}
+ * @param {NodeList} nodeList the list of nodes, for example childNodes property of DOM element
+ * @param {Integer} nodeType an integer constant [defined by DOM API](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType), e.g. `Node.ELEMENT_NODE` or `Node.TEXT_NODE`
+ * @return {Array[Node]}
*/
-function addInternalMessage(message) {
- var sourceMessage = MessengerAPI.prototype.addInternalMessage.apply(this, arguments);
-
- // store regexp itself if sourceMessage is regexp
- if (sourceMessage && sourceMessage instanceof RegExp) {
- this._internalMessages[sourceMessage].pattern = sourceMessage;
- this._patternInternalMessages[sourceMessage] = this._internalMessages[sourceMessage];
- if (this._catchAllSubscribed) return;
- this._catchAllSubscribed = true;
- return /.*/;
- }
-
- return sourceMessage;
+function filterNodeListByType(nodeList, nodeType) {
+ return _.filter(nodeList, function (node) {
+ return node.nodeType == nodeType;
+ });
}
/**
- * MessengerRegexpAPI instance method
- * Augments MessengerAPI method by removing regexp subscirption
- *
- * @param {String} message internal message to be translated and added
- * @return {String|RegExp|undefined}
+ * Find nearest parent element for node.
+ * If node is an element, it will be returned.
+ *
+ * @param {Node} node
+ * @return {Element|null}
*/
-function removeInternalMessage(message) {
- var sourceMessage = MessengerAPI.prototype.removeInternalMessage.apply(this, arguments);
-
- if (sourceMessage && sourceMessage instanceof RegExp) {
- delete this._patternInternalMessages[sourceMessage];
- var noPatternInternalMessages = ! Object.keys(this._patternInternalMessages).length;
- if (noPatternInternalMessages) {
- this._catchAllSubscribed = false;
- return /.*/;
- }
+function containingElement(node) {
+ while (node) {
+ if (node.nodeType == Node.ELEMENT_NODE)
+ return node;
+ node = node.parentNode;
}
-
- return sourceMessage;
+ return null;
}
/**
- * MessengerAPI instance method
- * Augments MessengerAPI method by returning messages subscribed with regexp
- * This method is used by `MessageSource` to dispatch source message on the `Mesenger`.
+ * Selects inner contents of DOM element
*
- * @param {String|RegExp} sourceMessage source message
- * @return {Array[String]}
+ * @param {Element} el DOM element
*/
-function getInternalMessages(sourceMessage) {
- var internalMessages = MessengerAPI.prototype.getInternalMessages.apply(this, arguments);
-
- // add internal messages for regexp source subscriptions
- if (typeof sourceMessage == 'string') {
- internalMessages = internalMessages || [];
- var internalMessagesHash = _.object(internalMessages, true);
+function selectElementContents(el) {
+ var doc = el.ownerDocument;
+ if (! doc) return logger.error('selectElementContents: element has no document');
+ var range = doc.createRange();
+ range.selectNodeContents(el);
+ var win = getNodeWindow(el)
+ , sel = win.getSelection();
+ sel.removeAllRanges();
+ sel.addRange(range);
+}
- _.eachKey(this._patternInternalMessages, function(patternMessages) {
- var sourcePattern = patternMessages.pattern;
- if (sourcePattern.test(sourceMessage))
- patternMessages.forEach(function(message) {
- if (internalMessagesHash[message]) return;
- internalMessages.push(message);
- internalMessagesHash[message] = true;
- });
- });
- }
+/**
+ * Selects text inside element
+ * @param {Element} el
+ */
+function selectElementText(el) {
+ var fromNode = firstTextNode(el)
+ , toNode = lastTextNode(el);
- return internalMessages;
+ if (fromNode && toNode)
+ setSelection(fromNode, 0, toNode, toNode.textContent.length);
}
-},{"./m_api":68,"mol-proto":150}],70:[function(require,module,exports){
-'use strict';
-
-var Mixin = require('../abstract/mixin')
- , MessengerAPI = require('./m_api')
- , logger = require('../util/logger')
- , toBeImplemented = require('../util/error').toBeImplemented
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match;
-
/**
- * `milo.classes.MessageSource`
- * An abstract class (subclass of [Mixin](../abstract/mixin.js.html)) for connecting [Messenger](./index.js.html) to external sources of messages (like DOM events) and defining higher level messages.
- * An instance of MessageSource can either be passed to Messenger constructor or later using `_setMessageSource` method of Messenger. Once set, MessageSource of Messenger cannot be changed.
+ * Sets the caret position to the position in the node
+ *
+ * @param {Node} node DOM node
+ * @param {Number} pos caret position
*/
-var MessageSource = _.createSubclass(Mixin, 'MessageSource', true);
-
-module.exports = MessageSource;
-
+function setCaretPosition(node, pos) {
+ var doc = node.ownerDocument;
+ if (! doc) return logger.error('setCaretPosition: element has no document');
+ var range = doc.createRange();
+ range.setStart(node, pos);
+ var win = getNodeWindow(node)
+ , sel = win.getSelection();
+ sel.removeAllRanges();
+ sel.addRange(range);
+}
/**
- * ####MessageSource instance methods####
- *
- * - [init](#init) - initializes messageSource - called by Mixin superclass
- * - [setMessenger](#setMessenger) - connects Messenger to MessageSource, is called from `init` or `_setMessageSource` methods of [Messenger](./index.js.html).
- * - [onSubscriberAdded](#onSubscriberAdded) - called by Messenger to notify when the first subscriber for an internal message was added, so MessageSource can subscribe to source
- * - [onSubscriberRemoved](#onSubscriberRemoved) - called by Messenger to notify when the last subscriber for an internal message was removed, so MessageSource can unsubscribe from source
- * - [dispatchMessage](#dispatchMessage) - dispatches source message. MessageSource subclass should implement mechanism when on actual source message this method is called.
+ * get the direction of a selection
*
- * Methods below should be implemented in subclass:
+ * 1 forward, -1 backward, 0 no direction, undefined one of the node is detached or in a different frame
*
- * - [trigger](#trigger) - triggers messages on the source (an optional method)
- * - [addSourceSubscriber](#addSourceSubscriber) - adds listener/subscriber to external message
- * - [removeSourceSubscriber](#removeSourceSubscriber) - removes listener/subscriber from external message
+ * @param {sel} a selection object
+ * @return {-1|0|1|undefined}
*/
-_.extendProto(MessageSource, {
- init: init,
- destroy: MessageSource$destroy,
- setMessenger: setMessenger,
- onSubscriberAdded: onSubscriberAdded,
- onSubscriberRemoved: onSubscriberRemoved,
- dispatchMessage: dispatchMessage,
- postMessage: postMessage,
- _prepareMessengerAPI: _prepareMessengerAPI,
-
- // Methods below must be implemented in subclass
- trigger: toBeImplemented,
- addSourceSubscriber: toBeImplemented,
- removeSourceSubscriber: toBeImplemented
-});
+function getSelectionDirection(sel){
+ return _getDirection(sel.anchorNode, sel.anchorOffset, sel.focusNode, sel.focusOffset);
+}
+function _getDirection(fromNode, startOffset, toNode, endOffset){
+ var docPosition = fromNode.compareDocumentPosition(toNode);
+ if (docPosition & Node.DOCUMENT_POSITION_FOLLOWING){
+ return 1;
+ }
+ else if (docPosition & Node.DOCUMENT_POSITION_PRECEDING){
+ return -1;
+ }
+ else if (fromNode == toNode){
+ if (startOffset < endOffset){
+ return 1;
+ }
+ else if (startOffset > endOffset){
+ return -1;
+ }
+ else {
+ return 0;
+ }
+ }
+}
/**
- * MessageSource instance method.
- * Called by Mixin constructor.
- * MessageSource constructor should be passed the same parameters as this method signature.
- * If an instance of [MessengerAPI](./m_api.js.html) is passed as the third parameter, it extends MessageSource functionality to allow it to define new messages, to filter messages based on their data and to change message data. See [MessengerAPI](./m_api.js.html).
+ * Selects a range in a document
*
- * @param {Object} hostObject Optional object that stores the MessageSource on one of its properties. It is used to proxy methods of MessageSource.
- * @param {Object[String]} proxyMethods Optional map of method names; key - proxy method name, value - MessageSource's method name.
- * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI.
+ * @param {Node} fromNode DOM node to start selection in
+ * @param {Number} startOffset
+ * @param {Node} toNode DOM node to end selection in
+ * @param {Number} endOffset
*/
-function init(hostObject, proxyMethods, messengerAPI) {
- this._prepareMessengerAPI(messengerAPI);
-}
+function setSelection(fromNode, startOffset, toNode, endOffset) {
+ var doc = fromNode.ownerDocument;
+ if (! doc) return logger('setCaretPosition: element has no document');
+ var backward = _getDirection(fromNode, startOffset, toNode, endOffset) == -1;
+ var range = doc.createRange();
+ var container, originalContentEditable;
+ // does not work in non contentEditable items
+ var win = getNodeWindow(fromNode)
+ , sel = win.getSelection();
-/**
- * Destroys message source
- */
-function MessageSource$destroy() {
- if (this.messengerAPI)
- this.messengerAPI.destroy();
-}
+ if (backward){
+ range.setStart(toNode, endOffset);
+ range.setEnd(fromNode, startOffset);
+ range.collapse(false);
+ }
+ else {
+ range.setStart(fromNode, startOffset);
+ range.setEnd(toNode, endOffset);
+ }
+
+ container = range.commonAncestorContainer == Node.ELEMENT_NODE ?
+ range.commonAncestorContainer :
+ range.commonAncestorContainer.parentElement;
+
+ if (!container.isContentEditable){
+ originalContentEditable = container.contentEditable; // false or inherit
+ container.contentEditable = "true";
+ }
+
+ sel.removeAllRanges();
+ sel.addRange(range);
+
+ if (backward){
+ sel.extend(toNode, endOffset);
+ }
+
+ if (originalContentEditable){
+ // restoring contentEditable
+ container.contentEditable = originalContentEditable;
+ }
+}
/**
- * MessageSource instance method.
- * Sets reference to Messenger instance.
- *
- * @param {Messenger} messenger reference to Messenger instance linked to this MessageSource
+ * Clears selection in a given window
+ * @param {Window} win
*/
-function setMessenger(messenger) {
- _.defineProperty(this, 'messenger', messenger);
+function clearSelection(win) {
+ win = win || window;
+ var sel = win.getSelection();
+ sel.removeAllRanges();
}
/**
- * MessageSource instance method.
- * Prepares [MessengerAPI](./m_api.js.html) passed to constructor by proxying its methods to itself or if MessengerAPI wasn't passed defines two methods to avoid checking their availability every time the message is dispatched.
+ * Calculates an element's total top and left offset from the document edge.
*
- * @private
- * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI
+ * @param {Element} el the element for which position needs to be returned
+ * @param {includeBorder} if is to include the border width
+ * @return {Object} vector object with properties topOffset and leftOffset
*/
-function _prepareMessengerAPI(messengerAPI) {
- check(messengerAPI, Match.Optional(MessengerAPI));
+function getElementOffset(el, includeBorder) {
+ var yPos, xPos;
- if (! messengerAPI)
- messengerAPI = new MessengerAPI;
+ yPos = el.offsetTop;
+ xPos = el.offsetLeft;
+ el = el.offsetParent;
- _.defineProperty(this, 'messengerAPI', messengerAPI);
+ while (el) {
+ yPos += el.offsetTop + getBorder(el, 'Height', includeBorder);
+ xPos += el.offsetLeft + getBorder(el, 'Width', includeBorder);
+ el = el.offsetParent;
+ }
+
+ return { topOffset: yPos, leftOffset: xPos };
+}
+
+
+function getBorder(el, type, includeBorder) {
+ if (includeBorder) {
+ var side = (type == 'Height') ? 'top' : 'left',
+ styles = window.getComputedStyle(el),
+ sideValue = parseInt(styles.getPropertyValue('border-' + side + '-width'), 10);
+
+ if (sideValue) return sideValue;
+ }
+ return 0;
}
/**
- * MessageSource instance method.
- * Subscribes to external source using `addSourceSubscriber` method that should be implemented in subclass.
- * This method is called by [Messenger](./index.js.html) when the first subscriber to the `message` is added.
- * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.addInternalMessage` will return undefined if this `sourceMessage` was already subscribed to to prevent duplicate subscription.
+ * Removes element from the document
*
- * @param {String} message internal Messenger message that has to be subscribed to at the external source of messages.
+ * @param {Element} el the element to be removed
*/
-function onSubscriberAdded(message) {
- var newSourceMessage = this.messengerAPI.addInternalMessage(message);
- if (typeof newSourceMessage != 'undefined')
- this.addSourceSubscriber(newSourceMessage);
+function removeElement(el) {
+ var parent = el.parentNode;
+ if (parent){
+ parent.removeChild(el);
+ parent.normalize();
+ }
}
/**
- * MessageSource instance method.
- * Unsubscribes from external source using `removeSourceSubscriber` method that should be implemented in subclass.
- * This method is called by [Messenger](./index.js.html) when the last subscriber to the `message` is removed.
- * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.removeInternalMessage` will return undefined if this `sourceMessage` was not yet subscribed to to prevent unsubscription without previous subscription.
+ * Returns the first child text node of an element
*
- * @param {String} message internal Messenger message that has to be unsubscribed from at the external source of messages.
+ * @param {Element|Node} node the node to be searched, if the node is text node we return the node.
+ * @return {TextNode}
*/
-function onSubscriberRemoved(message) {
- var removedSourceMessage = this.messengerAPI.removeInternalMessage(message);
- if (typeof removedSourceMessage != 'undefined')
- this.removeSourceSubscriber(removedSourceMessage);
+function firstTextNode(node) {
+ if (node.nodeType == Node.TEXT_NODE) return node;
+ var treeWalker = createTreeWalker(node, NodeFilter.SHOW_TEXT);
+ return treeWalker.firstChild();
}
/**
- * MessageSource instance method.
- * Dispatches sourceMessage to Messenger.
- * Mechanism that calls this method when the source message is received should be implemented by subclass (see [DOMEventsSource](../components/msg_src/dom_events.js.html) for example).
- * Delegates to supplied or default [MessengerAPI](./m_api.js.html) to create internal message data (`createInternalData`) and to filter the message based on its data and/or message (`filterSourceMessage`).
- * Base MessengerAPI class implements these two methods in a trivial way (`createInternalData` simply returns external data, `filterSourceMessage` returns `true`), they are meant to be implemented by subclass.
+ * Returns the last child text node of an element
*
- * @param {String} sourceMessage source message received from external source
- * @param {Object} sourceData data received from external source
+ * @param {Element|Node} node the node to be searched, if the node is text node we return the node.
+ * @return {TextNode}
*/
-function dispatchMessage(sourceMessage, sourceData) {
- var api = this.messengerAPI
- , internalMessages = api.getInternalMessages(sourceMessage);
-
- if (internalMessages)
- internalMessages.forEach(function (message) {
- var internalData = api.createInternalData(sourceMessage, message, sourceData);
-
- var shouldDispatch = api.filterSourceMessage(sourceMessage, message, internalData);
- if (shouldDispatch)
- this.postMessage(message, internalData);
-
- }, this);
+function lastTextNode(node) {
+ if (node.nodeType == Node.TEXT_NODE) return node;
+ var treeWalker = createTreeWalker(node, NodeFilter.SHOW_TEXT);
+ return treeWalker.lastChild();
}
/**
- * Posts message on the messenger. This method is separated so specific message sources can make message dispatch synchronous by using `postMessageSync`
- *
- * @param {String} message
- * @param {Object} data
+ * Removes element from the document putting its children in its place
+ *
+ * @param {Element} el the element to be "unwrapped"
*/
-function postMessage(message, data) {
- this.messenger.postMessage(message, data);
-}
-
-},{"../abstract/mixin":3,"../util/check":90,"../util/error":98,"../util/logger":102,"./m_api":68,"mol-proto":150}],71:[function(require,module,exports){
-'use strict';
-
+function unwrapElement(el) {
+ var parent = el.parentNode;
-var MessageSource = require('./m_source')
- , _ = require('mol-proto')
- , check = require('../util/check');
+ if (parent) {
+ var frag = document.createDocumentFragment();
+ // must be copied to avoid iterating a mutating list of childNodes
+ var children = _.slice(el.childNodes);
+ children.forEach(frag.appendChild, frag);
+ parent.replaceChild(frag, el);
+ parent.normalize();
+ }
+}
/**
- * Subclass of MessageSource that allows to connect Messenger to another Messenger using it as external source.
+ * Wraps an element in another element
+ *
+ * @param {Element} wrapIntoEl
+ * @param {Element} el
*/
-var MessengerMessageSource = _.createSubclass(MessageSource, 'MessengerMessageSource');
-
-module.exports = MessengerMessageSource;
+function wrapInElement(wrapIntoEl, el) {
+ var parent = el.parentNode;
+ if (parent) {
+ parent.insertBefore(wrapIntoEl, el);
+ wrapIntoEl.appendChild(el);
+ }
+}
-/**
- * ####MessengerMessageSource instance methods####
- */
-_.extendProto(MessengerMessageSource, {
- init: init,
- addSourceSubscriber: addSourceSubscriber,
- removeSourceSubscriber: removeSourceSubscriber,
- postMessage: MessengerMessageSource$postMessage
-});
/**
- * Initializes MessengerMessageSource
- * Defines one parameter in addition to [MessageSource](./m_source.js.html) parameters
+ * Trims a text node of trailing spaces, and returns true if a trim was performed.
*
- * @param {Messenger} sourceMessenger messenger this message source connects to
+ * @param {TextNode} node
+ * @return {Boolean}
*/
-function init(hostObject, proxyMethods, messengerAPI, sourceMessenger) {
- MessageSource.prototype.init.apply(this, arguments);
- this.sourceMessenger = sourceMessenger;
+function trimNodeRight(node) {
+ return _trimNode(node, 'trimRight');
}
/**
- * Subscribes to source message. See [MessageSource](./m_source.js.html) docs.
+ * Trims a text node of leading spaces, and returns true if a trim was performed.
*
- * @param {String|Regex} sourceMessage source message to subscribe to
+ * @param {TextNode} node
+ * @return {Boolean}
*/
-function addSourceSubscriber(sourceMessage) {
- this.sourceMessenger.onSync(sourceMessage, { context: this, subscriber: this.dispatchMessage });
+function trimNodeLeft(node) {
+ return _trimNode(node, 'trimLeft');
+}
+
+
+function _trimNode(node, methodName) {
+ var len = node.length;
+ node.textContent = node.textContent[methodName]();
+ return len !== node.length;
}
/**
- * Unsubscribes from source message. See [MessageSource](./m_source.js.html) docs.
+ * Removes the reference to component from element
*
- * @param {String|Regex} sourceMessage source message to unsubscribe from
+ * @param {Element} el
*/
-function removeSourceSubscriber(sourceMessage) {
- this.sourceMessenger.off(sourceMessage, { context: this, subscriber: this.dispatchMessage });
+function detachComponent(el) {
+ delete el[config.componentRef];
}
/**
- * Overrides defalut message source to dispatch messages synchronously
- *
- * @param {String} message
- * @param {Object} data
+ * Retrieves the content of a html string
+ * @param {String} str Any string
+ * @return {String} returns the string cleaned of any html content.
*/
-function MessengerMessageSource$postMessage(message, data) {
- this.messenger.postMessageSync(message, data);
+function stripHtml(str) {
+ var div = document.createElement('DIV');
+ div.innerHTML = str;
+ return div.textContent || '';
}
-},{"../util/check":90,"./m_source":70,"mol-proto":150}],72:[function(require,module,exports){
-'use strict';
-
-var core = require('milo-core');
-var _ = require('mol-proto');
-
-
-// register included facets
-require('./use_facets');
-
-// register included components
-require('./use_components');
-
/**
- * `milo`
- *
- * A minimalist browser framework that binds DOM elements to JS components and components to models.
- *
- * `milo` is available as global object in the browser.
- * At the moment it is not possiible to require it with browserify to have it bundled with the app because of the way [brfs](https://github.com/substack/brfs) browserify plugin is implemented.
- * It is possible though to require `milo` with node to use universal parts of the framework (abstract classes, Messenger, Model, etc.):
- * ```
- * var milo = require('mol-milo');
- * ```
- *
- * `milo` itself is a function that in the browser can be used to delay execution until DOM is ready.
+ * Convenience wrapper for native TreeWalker that automatically walks the tree and calls an iterator function.
+ * This will not iterate the root element.
+ * @param {HTMLElement} root The containing root element to be walked. Will not be iterated.
+ * @param {NodeFiler} filter A NodeFilter constant, see https://developer.mozilla.org/en/docs/Web/API/TreeWalker
+ * @param {Function} iterator A function to be called on each node. Returning 'false' will break.
+ * @param {Object} context An optional context to passed, defaults to root.
*/
-function milo(func) {
- milo.util.domReady(func);
+function walkTree(root, filter, iterator, context) {
+ var tw = document.createTreeWalker(root, filter);
+ while(tw.nextNode()) {
+ var result = iterator.call(context || root, tw.currentNode);
+ if (result === false) break;
+ }
}
/**
- * ####Milo packages####
+ * Returns array of child indexes of element path inside root element in DOM tree using breadth first tree traversal.
+ * Returns undefined if the element is not inside root element, 0 if the root element itself is passed.
*
- * - [loader](./loader.js.html) - loading subviews into page
- * - [binder](./binder.js.html) - components instantiation and binding of DOM elements to them
- * - [minder](./minder.js.html) - data reactivity, one or two way, shallow or deep, as you like it
- * - [mail](./mail/index.js.html) - applicaiton level messenger, also connects to messages from other windows dispatched with `window.postMessage`.
- * - [config](./config.js.html) - milo configuration
- * - [util](./util/index.js.html) - logger, request, dom, check, error, etc.
- * - [classes](./classes.js.html) - abstract and base classes
- * - [attributes](./attributes/index.js.html) - classes that wrap DOM elements attributes recognized by milo
- * - [ComponentFacet](./components/c_facet.js.html) - base class of Component facet
- * - [Component](./components/c_class.js.html) - base Component class
- * - [Messenger](./messenger/index.js.html) - generic Messenger used in most other milo classes, can be mixed into app classes too.
- * - [Model](./model/index.js.html) - Model class that emits messages on changes to any depth without timer based watching
- * - [registry](./registry.js.html) - registries of fasets and components classes
+ * @param {Element} rootEl element to search
+ * @param {Element} el element to find the index of
+ * @return {Array[Number]}
*/
-_.extend(milo, {
- Messenger: core.Messenger,
- Model: core.Model,
- minder: core.minder,
- loader: require('./loader'),
- binder: require('./binder'),
- mail: require('./services/mail'),
- window: require('./services/window'),
- config: require('./config'),
- util: require('./util'),
- classes: require('./classes'),
- attributes: require('./attributes'),
- ComponentFacet: require('./components/c_facet'),
- Component: require('./components/c_class'),
- Command: require('./command'),
- registry: require('./registry'),
- milo_version: '0.1.4',
- createComponentClass: require('./util/create_component_class'),
- destroy: destroy
-});
-
+function treePathOf(rootEl, el) {
+ if (! (rootEl && rootEl.contains(el))) return;
-// export for node/browserify
-if (typeof module == 'object' && module.exports)
- module.exports = milo;
+ var treePath = []
+ , node = rootEl;
-// global milo for browser
-if (typeof window == 'object') {
- window.milo = milo;
- milo.mail.trigger('miloready');
-}
+ while (node != el) {
+ var nodeIndex = _.findIndex(node.childNodes, containsEl);
+ treePath.push(nodeIndex);
+ node = node.childNodes[nodeIndex];
+ }
+ return treePath;
-function destroy() {
- milo.mail.destroy();
- milo.window.destroy();
- milo.minder.destroy();
- milo.util.destroy();
+ function containsEl(child) {
+ return child.contains(el);
+ }
}
-},{"./attributes":8,"./binder":9,"./classes":10,"./command":13,"./components/c_class":16,"./components/c_facet":17,"./config":65,"./loader":66,"./registry":81,"./services/mail":84,"./services/window":87,"./use_components":88,"./use_facets":89,"./util":100,"./util/create_component_class":93,"milo-core":124,"mol-proto":150}],73:[function(require,module,exports){
-'use strict';
-
-
-var facetsRegistry = require('../components/c_facets/cf_registry')
- , logger = require('../util/logger')
- , config = require('../config')
- , pathUtils = require('./path_utils')
- , _ = require('mol-proto');
/**
- * Utility function to process "changedata" messages emitted by Connector object.
+ * Returns element at given tree path
+ *
+ * @param {Element} rootEl
+ * @param {Array[Number]} treePath
+ * @param {Boolean} nearest return nearest possible node if exact node does not exist
+ * @return {Node}
*/
-module.exports = changeDataHandler;
+function getNodeAtTreePath(rootEl, treePath, nearest) {
+ if (!treePath) return;
+ var len = treePath.length;
+ if (len === 0) return rootEl;
-_.extend(changeDataHandler, {
- setTransactionFlag: setTransactionFlag,
- getTransactionFlag: getTransactionFlag,
- passTransactionFlag: passTransactionFlag,
- postTransactionFinished: postTransactionFinished
-});
+ var node = rootEl;
+ for (var i = 0; i < len; i++) {
+ var children = node.childNodes;
+ if (! children) {
+ if (! nearest) node = undefined;
+ break;
+ }
+ var childIndex = treePath[i]
+ , child = children[childIndex];
+ if (! child) {
+ node = nearest
+ ? children[children.length - 1]
+ : undefined;
+ break;
+ }
+ node = child;
+ }
-/**
- * Change data uses hidden property on accessor methods to pass flag that the accessor is executed as a part of change transaction.
- * Accessor methods are supposed to store this flag in a local variable and to clear it (because another accessor can be executed in or out of transaction) using `getTransactionFlag`
- *
- * @private
- * @param {Function} func accessor method reference
- * @param {Boolean} flag a flag to be set
- */
-function setTransactionFlag(func, flag) {
- _.defineProperty(func, '__inChangeTransaction', flag, _.CONF | _.WRIT);
+ return node;
}
/**
- * Retrieves and clears transaction flag from accessor method
+ * Inserts an element inside root at a given path in tree (that has the same meaning as the index returned by `treePathOf` function). If element is already in the root's tree, it will be removed first and then moved to the passed treeIndex
+ * Insertion at index 0 is not possible and will return undefined as it would mean replacing the root element.
*
- * @private
- * @param {Function} func accessor method reference
- * @return {Boolean}
- */
-function getTransactionFlag(func) {
- var inTransaction = func.__inChangeTransaction;
- delete func.__inChangeTransaction;
- return inTransaction;
-}
+ * @param {Element} rootEl element into which to insert
+ * @param {Number} treeIndex index in DOM tree inside root element (see treePathOf)
+ * @param {Element} el element to be inserted
+ * @return {Boolean} true if was successfully inserted
+ */
+function insertAtTreePath(rootEl, treePath, el, nearest) {
+ var toNormalize = el.nodeType == Node.TEXT_NODE;
+ if (rootEl.contains(el))
+ removeElement(el); // can't use removeChild as rootEl here is not an immediate parent
+ if (treePath.length == 0) return;
-function passTransactionFlag(fromFunc, toFunc) {
- var inTransaction = getTransactionFlag(fromFunc);
- setTransactionFlag(toFunc, inTransaction);
- return inTransaction;
+ var parent = getNodeAtTreePath(rootEl, treePath.slice(0, -1), nearest)
+ , children = parent.childNodes;
+
+ if (! children) {
+ if (nearest) {
+ parent = parent.parentNode;
+ children = parent.childNodes;
+ } else return;
+ }
+
+ var childIndex = treePath[treePath.length - 1]
+ , child = children[childIndex];
+
+ if (child) {
+ parent.insertBefore(el, child);
+ if (toNormalize) parent.normalize();
+ return true;
+ } else if (children.length === 0 && (childIndex === 0 || nearest)) {
+ parent.appendChild(el);
+ if (toNormalize) parent.normalize();
+ return true;
+ } else {
+ child = children[childIndex - 1];
+ if (child || nearest) {
+ parent.appendChild(el);
+ if (toNormalize) parent.normalize();
+ return true;
+ }
+ }
}
/**
- * Posts message on this to indicate the end of transaction unless `inChangeTransaction` is `true`.
+ * Returns `true` if the first tree path points to a node which is before the other in the document order.
+ * @param {Array} path1 A treepath array
+ * @param {Array} path2 A treepath array
+ * @return {Boolean}
*/
-function postTransactionFinished() {
- this.postMessageSync('datachanges', { transaction: false, changes: [] });
+function isTreePathBefore(path1, path2) {
+ var i = 0
+ , isBefore;
+ if (!Array.isArray(path1) && Array.isArray(path2))
+ return logger.error('isTreePathBefore: One or both paths are not valid treepath arrays.');
+
+ for (i; i < path1.length; i++) {
+ if (path1[i] < path2[i]) {
+ isBefore = true;
+ break;
+ } else if (path1[i] > path2[i]) {
+ isBefore = false;
+ break;
+ }
+ }
+
+ if (typeof isBefore == 'undefined')
+ if (path1.length < path2.length)
+ logger.warn('isTreePathBefore: One node is inside another');
+
+ return isBefore || false;
}
/**
- * subscriber to "changedata" event emitted by [Connector](./connector.js.html) object to enable reactive connections
- * Used by Data facet, Model and ModelPath. Can be used by any object that implements get/set/del/splice api and sets data deeply to the whole tree.
- * Object should call `changeDataHandler.initialize.call(this)` in its constructor.
- * TODO: optimize messages list to avoid setting duplicate values down the tree
- *
- * @param {String} msg should be "changedata" here
- * @param {Object} data batch of data change desciption objects
- * @param {Function} callback callback to call before and after the data is processed
+ * Converts non latin characters to HTML entity codes.
+ * @param {String} str the string to convert
+ * @return {String} the string with html entities
*/
-function changeDataHandler(message, data, callback) {
- processChanges.call(this, data.changes, callback);
+function htmlEntities(str) {
+ return str.replace(/[\u00A0-\u99999<>\&]/gim, function(i) {
+ return ''+i.charCodeAt(0)+';';
+ });
}
-// map of message types to methods
-var CHANGE_TYPE_TO_METHOD_MAP = {
- 'added': 'set',
- 'changed': 'set',
- 'deleted': 'del',
- 'removed': 'del'
-};
+function createTreeWalker(el, whatToShow) {
+ whatToShow = whatToShow || (NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT);
+ return document.createTreeWalker(el, whatToShow);
+}
/**
- * Processes queued "changedata" messages.
- * Posts "changestarted" and "changecompleted" messages and calls callback
+ * Returns the reference to the window the node is in
*
- * @param {[Function]} callback optional callback that is called with `(null, false)` parameters before change processing starts and `(null, true)` after it's finished.
+ * @param {Node} node
+ * @return {Window}
*/
-function processChanges(transaction, callback) {
- notify.call(this, callback, false);
- processTransaction.call(this,
- prepareTransaction(
- validateTransaction(transaction)));
- notify.call(this, callback, true);
+function getNodeWindow(node) {
+ var doc = node.ownerDocument;
+ return doc && (doc.defaultView || doc.parentWindow);
}
-function notify(callback, changeFinished) {
- callback && callback(null, changeFinished);
- this.postMessage(changeFinished ? 'changecompleted' : 'changestarted');
-}
-
/**
- * Checks that all messages from the transaction come from the same source.
- * Hack: reverses the transaction if it comes from the Data facet
- * Returns the reference to the transaction (for chaining)
- *
- * @param {Array} transaction transaction of data changes
- * @return {Array}
+ * do something for each nodes contained in a range
+ *
+ * @param {range} a range
+ * @param {cb} a function taking a node as argument
+
*/
-function validateTransaction(transaction) {
- var source = transaction[0].source
- , sameSource = true;
+function forEachNodesInRange(range, cb){
+ var rangeContainer = range.commonAncestorContainer
+ , doc = rangeContainer.ownerDocument;
- if (transaction.length > 1) {
- for (var i = 1, len = transaction.length; i < len; i++)
- if (transaction[i].source != source) {
- logger.error('changedata: changes from different sources in the same transaction, sources:', transaction[i].source.name, source.name);
- sameSource = false;
- source = transaction[i].source;
- }
+ function isNodeInsideRange(node){
+ var nodeRange = document.createRange();
+ var isInside = false;
+ nodeRange.selectNode(node);
+
+ if (nodeRange.compareBoundaryPoints(window.Range.START_TO_START, range) != -1
+ && nodeRange.compareBoundaryPoints(window.Range.END_TO_END, range) != 1){
+ isInside = true;
+ }
+ nodeRange.detach();
+ return isInside;
}
- return transaction;
+ var treeWalker = doc.createTreeWalker(rangeContainer,
+ NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
+
+ var currentNode;
+ while (currentNode = treeWalker.nextNode()){ // should be assignment
+ if (isNodeInsideRange(currentNode)){
+ cb(currentNode);
+ }
+ }
}
+/**
+ * get all components contained in a range
+ *
+ * @param {range} a DOM range.
+ */
+function getComponentsFromRange(range) {
+ var win = getNodeWindow(range.startContainer)
+ , Component = win.milo.Component;
-function prepareTransaction(transaction) {
- var todo = []
- , pathsToSplice = []
- , pathsToChange = []
- , hadSplice
- , exitLoop = {};
+ var components = [];
+ forEachNodesInRange(range, function (node){
+ if (node.nodeType != Node.TEXT_NODE) {
+ var comp = Component.getComponent(node);
+ if (comp)
+ components.push(comp);
+ }
+ });
+ return components;
+}
- try { transaction.forEach(checkChange); }
- catch (e) { if (e != exitLoop) throw e; }
+/**
+ * delete a range
+ *
+ * @param {range} delete a DOM range and all the components inside
+ */
+function deleteRangeWithComponents(range) {
+ var components = getComponentsFromRange(range);
- return todo;
+ components.forEach(function(comp) {
+ comp.destroy(true);
+ });
+ range.deleteContents();
+}
- function checkChange(data) {
- (data.type == 'splice' ? checkSplice : checkMethod)(data);
- }
+/**
+ * check if two ranges are equivalent
+ *
+ * @param {range} range1
+ * @param {range} range2
+ * @return {Boolean} are the two ranges equivalent
+ */
+function areRangesEqual(range1, range2){
+ return range1.compareBoundaryPoints(window.Range.START_TO_START, range2) == 0 && range1.compareBoundaryPoints(window.Range.END_TO_END, range2) == 0;
+}
- function checkSplice(data) {
- var parsedPath = pathUtils.parseAccessPath(data.path);
- var parentPathChanged = pathsToChange.some(function(parentPath) {
- if (parsedPath.length < parentPath.length) return;
- return _pathIsParentOf(parentPath, parsedPath);
- });
+/**
+ * Adds a single pixel div to the body at a given x and y position. Useful for debugging position specific code.
+ * @param {Number} x
+ * @param {Number} y
+ */
+function addDebugPoint(x, y) {
+ var dbEl = document.createElement('div');
+ dbEl.setAttribute('style', 'width: 1px; height: 1px; position:fixed; left:'+x+'px; top:'+y+'px; background-color:red; z-index: 100');
+ setTimeout(function() {document.body.appendChild(dbEl);}, 200);
+}
- if (parentPathChanged) return;
+},{"../config":64,"milo-core":105}],80:[function(require,module,exports){
+'use strict';
- todo.push(data);
- if (! config.debug) throw exitLoop;
- pathsToSplice.push(parsedPath);
- hadSplice = true;
- }
+var _ = require('milo-core').proto;
- function checkMethod(data) {
- var parsedPath = pathUtils.parseAccessPath(data.path);
- var parentPathSpliced = pathsToSplice && pathsToSplice.some(function(parentPath) {
- if (parsedPath.length <= parentPath.length
- || parsedPath[parentPath.length].syntax != 'array') return;
- return _pathIsParentOf(parentPath, parsedPath);
- });
+module.exports = DOMListeners;
- if (parentPathSpliced) return;
- if (hadSplice) logger.error('changedata: child change is executed after splice; probably data source did not emit message with data.type=="finished"');
- var parentPathChanged = pathsToChange.some(function(parentPath) {
- if (parsedPath.length <= parentPath.length) return;
- return _pathIsParentOf(parentPath, parsedPath);
- });
-
- if (parentPathChanged) return;
+function DOMListeners() {
+ this.listeners = [];
+}
- pathsToChange.push(parsedPath);
- todo.push(data);
- }
+_.extendProto(DOMListeners, {
+ add: DOMListeners$add,
+ remove: DOMListeners$remove,
+ removeAll: DOMListeners$removeAll
+});
- function _pathIsParentOf(parentPath, childPath) {
- return parentPath.every(function(pathNode, index) {
- return pathNode.property == childPath[index].property;
- });
- }
+function DOMListeners$add(target, eventType, handler) {
+ this.listeners.push({
+ target: target,
+ eventType: eventType,
+ handler: handler
+ });
+ target.addEventListener(eventType, handler);
}
-function processTransaction(transaction) {
- transaction.forEach(processChange, this);
- postTransactionFinished.call(this, false);
+function DOMListeners$remove(target, eventType, handler) {
+ var listener = {
+ target: target,
+ eventType: eventType,
+ handler: handler
+ };
+ var idx = _.findIndex(this.listeners, _.partial(_.isEqual, listener));
- function processChange(data) {
- var modelPath = this.path(data.path, data.type != 'removed' && data.type != 'deleted');
- if (! modelPath) return;
- (data.type == 'splice' ? executeSplice : executeMethod)(modelPath, data);
+ if (idx > -1) {
+ this.listeners.splice(idx, 1);
+ _removeListener(listener);
}
}
-function executeSplice(modelPath, data) {
- var index = data.index
- , howMany = data.removed.length
- , spliceArgs = [index, howMany];
-
- spliceArgs = spliceArgs.concat(data.newValue.slice(index, index + data.addedCount));
- setTransactionFlag(modelPath.splice, true);
- modelPath.splice.apply(modelPath, spliceArgs);
+function DOMListeners$removeAll() {
+ this.listeners.forEach(_removeListener);
+ this.listeners = [];
}
-function executeMethod(modelPath, data) {
- var methodName = CHANGE_TYPE_TO_METHOD_MAP[data.type];
- if (methodName) {
- setTransactionFlag(modelPath[methodName], true);
- modelPath[methodName](data.newValue);
- } else
- logger.error('unknown data change type');
+function _removeListener(l) {
+ l.target.removeEventListener(l.eventType, l.handler);
}
-},{"../components/c_facets/cf_registry":31,"../config":65,"../util/logger":102,"./path_utils":79,"mol-proto":150}],74:[function(require,module,exports){
+},{"milo-core":105}],81:[function(require,module,exports){
'use strict';
-var ModelPath = require('./m_path')
- , synthesize = require('./synthesize')
- , pathUtils = require('./path_utils')
- , changeDataHandler = require('./change_data')
- , Messenger = require('../messenger')
- , MessengerMessageSource = require('../messenger/msngr_source')
- , ModelMsgAPI = require('./m_msg_api')
- , ModelError = require('../util/error').Model
- , Mixin = require('../abstract/mixin')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , logger = require('../util/logger')
- , jsonParse = require('../util/json_parse');
+var _ = require('milo-core').proto;
-module.exports = Model;
+module.exports = domReady;
-/**
- * `milo.Model`
- * Model class instantiates objects that allow deep data access with __safe getters__ that return undefined (rather than throwing exception) when properties/items of unexisting objects/arrays are requested and __safe setters__ that create object trees when properties/items of unexisting objects/arrays are set and also post messages to allow subscription on changes and enable data reactivity.
- * Reactivity is implememnted via [Connector](./connector.js.html) that can be instantiated either directly or with more convenient interface of [milo.minder](../minder.js.html). At the moment model can be connected to [Data facet](../components/c_facets/Data.js.html) or to another model or [ModelPath](./m_path.js.html).
- * Model constructor returns objects that are functions at the same time; when called they return ModelPath objects that allow get/set access to any point in model data. See [ModelData](#ModelData) below.
- *
- * You can subscribe to model changes with `on` method by passing model access path in place of message, pattern or string with any number of stars to subscribe to a certain depth in model (e.g., `'***'` to subscribe to three levels).
- *
- * @constructor
- * @param {Object|Array} data optional initial array data. If it is planned to connect model to view it is usually better to instantiate an empty Model (`var m = new Model`), connect it to [Component](../components/c_class.js.html)'s [Data facet](../components/c_facets/Data.js.html) (e.g., `milo.minder(m, '<<->>', c.data);`) and then set the model with `m.set(data)` - the view will be automatically updated.
- * @param {Object} hostObject optional object that hosts model on one of its properties. Can be used when model itself is the context of the message subscriber and you need to travers to this object (although it is possible to set any context). Can also be used to proxy model's methods to the host like [Model facet](../components/c_facets/ModelFacet.js.html) is doing.
- * @param {Object} options pass { reactive: false } to use model without messaging when it is not needed - it makes it much faster
- * @return {Model}
- */
-function Model(data, hostObject, options) {
- // `model` will be returned by constructor instead of `this`. `model`
- // (`modelPath` function) should return a ModelPath object with "synthesized" methods
- // to get/set model properties, to subscribe to property changes, etc.
- // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.
- var model = function modelPath(accessPath) { // , ... arguments that will be interpolated
- return Model$path.apply(model, arguments);
- };
- model.__proto__ = Model.prototype;
- model._hostObject = hostObject;
- model._options = options || {};
+var domReadyFuncs = []
+ , domReadySubscribed = false;
- if (model._options.reactive !== false) {
- model._prepareMessengers();
- // subscribe to "changedata" message to enable reactive connections
- model.onSync('changedata', changeDataHandler);
- }
- if (data) model._data = data;
+function domReady(func) { // , arguments
+ var self = this
+ , args = _.slice(arguments, 1);
+ if (isReady.call(this))
+ callFunc();
+ else {
+ if (!domReadySubscribed) {
+ document.addEventListener('readystatechange', onDomReady);
+ domReadySubscribed = true;
+ }
+ domReadyFuncs.push(callFunc); // closure is added, so every time different function will be called
+ }
- return model;
+ function callFunc() {
+ func.apply(self, args);
+ }
}
-Model.prototype.__proto__ = Model.__proto__;
+
+function onDomReady() {
+ document.removeEventListener('readystatechange', onDomReady);
+ domReadyFuncs.forEach(function(func) { func(); });
+}
-/**
- * ####Model instance methods####
- *
- * - [path](#path) - returns ModelPath object that allows access to any point in Model
- * - [get](#Model$get) - get model data
- * - set - set model data, synthesized
- * - splice - splice model data (as array or pseudo-array), synthesized
- * - [len](./m_path.js.html#ModelPath$len) - returns length of array (or pseudo-array) in model in safe way, 0 if no length is set
- * - [push](./m_path.js.html#ModelPath$push) - add items to the end of array (or pseudo-array) in model
- * - [pop](./m_path.js.html#ModelPath$pop) - remove item from the end of array (or pseudo-array) in model
- * - [unshift](./m_path.js.html#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in model
- * - [shift](./m_path.js.html#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in model
- * - [proxyMessenger](#proxyMessenger) - proxy model's Messenger methods to host object
- * - [proxyMethods](#proxyMethods) - proxy model methods to host object
- */
-_.extendProto(Model, {
- path: Model$path,
- get: Model$get,
- proxyMessenger: proxyMessenger, // deprecated, should not be used
- proxyMethods: proxyMethods,
- _prepareMessengers: _prepareMessengers,
- _getHostObject: _getHostObject,
- destroy: Model$destroy
+_.extend(domReady, {
+ isReady: isReady
});
-// set, del, splice are added to model
-_.extendProto(Model, synthesize.modelMethods);
-
-/**
- * - Path: ModelPath class as `milo.Model.Path`
- * - [registerWithDOMStorage](#Model$$registerWithDOMStorage)
- */
-_.extend(Model, {
- Path: ModelPath,
- registerWithDOMStorage: Model$$registerWithDOMStorage,
- useWith: Model$$useWith
-});
+function isReady() {
+ var readyState = document.readyState;
+ return readyState == 'loading' ? false : readyState;
+}
+},{"milo-core":105}],82:[function(require,module,exports){
+'use strict';
-/**
- * Expose Messenger methods on Facet prototype
- */
-var MESSENGER_PROPERTY = '_messenger';
-Messenger.useWith(Model, MESSENGER_PROPERTY, Messenger.defaultMethods);
+var Component = require('../components/c_class')
+ , miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
+ , dragDropConfig = require('../config').dragDrop
+ , componentMetaRegex = dragDropConfig.dataTypes.componentMetaRegex
+ , _ = miloCore.proto
+ , base32 = require('base32');
-/**
- * ModelPath methods added to Model prototype
- */
-['len', 'push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {
- var method = ModelPath.prototype[methodName];
- _.defineProperty(Model.prototype, methodName, method);
-});
+module.exports = DragDrop;
/**
- * Model instance method.
- * Get model data.
+ * Wrapper for event.dataTransfer of drag-drop HTML API
*
- * @return {Any}
+ * @constructor
+ * @param {event} DOM event
+ * @return {DragDrop}
*/
-function Model$get() {
- return this._data;
+function DragDrop(event) {
+ this.event = event;
+ this.dataTransfer = event.dataTransfer;
+ this.types = event.dataTransfer.types;
}
-
/**
- * Model instance method.
- * Returns ModelPath object that implements the same API as model but allows access to any point inside model as defined by `accessPath`.
- * See [ModelPath](./m_path.js.html) class for more information.
- *
- * @param {String} accessPath string that defines path to access model.
- * Path string consists of parts to define either property access (`".name"` to access property name) or array item access (`"[1]"` to access item with index 1).
- * Access path can contain as many parts as necessary (e.g. `".list[0].name"` to access property `name` in the first element of array stored in property `list`.
- * @param {List} arguments additional arguments of this method can be used to create interpolated paths.
- * E.g. `m.path("[$1].$2", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m("[" + id + "]." + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.
- * @return {ModelPath}
+ * Usage:
+ * var testDT = new DragDrop(event);
+ * testDT.setComponentMeta(newComponent, {test: 'test', test2: 'test2'});
+ * testDT.getComponentMeta();
*/
-function Model$path(accessPath) { // , ... arguments that will be interpolated
- if (! accessPath) return this;
- // "null" is context to pass to ModelPath, first parameter of bind
- // "this" (model) is added in front of all arguments
- _.splice(arguments, 0, 0, null, this);
+_.extend(DragDrop, {
+ componentDataType: DragDrop$$componentDataType
+});
- // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...
- return new (Function.prototype.bind.apply(ModelPath, arguments));
+_.extendProto(DragDrop, {
+ isComponent: DragDrop$isComponent,
+ getComponentState: DragDrop$getComponentState,
+ setComponentState: DragDrop$setComponentState,
+ getComponentMeta: DragDrop$getComponentMeta,
+ setComponentMeta: DragDrop$setComponentMeta,
+ getAllowedEffects: DragDrop$getAllowedEffects,
+ setAllowedEffects: DragDrop$setAllowedEffects,
+ getDropEffect: DragDrop$getDropEffect,
+ setDropEffect: DragDrop$setDropEffect,
+ isEffectAllowed: DragDrop$isEffectAllowed,
+ getData: DragDrop$getData,
+ setData: DragDrop$setData,
+ clearData: DragDrop$clearData
+});
+
+
+function DragDrop$$componentDataType() {
+ return dragDropConfig.dataTypes.component;
}
-/**
- * Model instance method.
- * Proxy model's Messenger methods to host object.
- *
- * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.
- */
-function proxyMessenger(modelHostObject) {
- modelHostObject = modelHostObject || this._hostObject;
- Mixin.prototype._createProxyMethods.call(this[MESSENGER_PROPERTY], Messenger.defaultMethods, modelHostObject);
+function DragDrop$isComponent() {
+ return _.indexOf(this.types, DragDrop.componentDataType()) >= 0;
}
-var modelMethodsToProxy = ['path', 'get', 'set', 'del', 'splice', 'len', 'push', 'pop', 'unshift', 'shift'];
-
+function DragDrop$getComponentState() {
+ var dataType = DragDrop.componentDataType()
+ , stateStr = this.dataTransfer.getData(dataType)
+ , state = _.jsonParse(stateStr);
-/**
- * Expose model methods on
- * See same method in Mixin class for parameters meaning
- *
- * @param {Function} hostClass
- * @param {[type]} instanceKey
- * @param {[type]} mixinMethods optional
- */
-function Model$$useWith(hostClass, instanceKey, mixinMethods) {
- mixinMethods = mixinMethods || modelMethodsToProxy;
- Mixin.useWith.call(Model, hostClass, instanceKey, mixinMethods);
+ return state;
}
-/**
- * Model instance method.
- * Proxy model methods to host object.
- *
- * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.
- */
-function proxyMethods(modelHostObject) {
- modelHostObject = modelHostObject || this._hostObject;
- Mixin.prototype._createProxyMethods.call(this, modelMethodsToProxy, modelHostObject);
+function DragDrop$setComponentState(component, stateStr){
+ if (! stateStr) {
+ var state = component.getTransferState({ requestedBy: 'drag' });
+ stateStr = JSON.stringify(state);
+ }
+ var dataType = DragDrop.componentDataType();
+
+ stateStr && this.dataTransfer.setData(dataType, stateStr);
+ this.dataTransfer.setData('text/html', component.el.outerHTML);
+ return stateStr;
}
-/**
- * Model instance method.
- * Create and connect internal and external model's messengers.
- * External messenger's methods are proxied on the model and they allows "*" subscriptions.
- */
-function _prepareMessengers() {
- // model will post all its changes on internal messenger
- var internalMessenger = new Messenger(this, undefined, undefined);
+function DragDrop$setComponentMeta(component, params, data) {
+ var meta = _componentMeta(component);
- // message source to connect internal messenger to external
- var internalMessengerSource = new MessengerMessageSource(this, undefined, new ModelMsgAPI, internalMessenger);
+ var paramsStr = _.toQueryString(params);
+ var dataType = dragDropConfig.dataTypes.componentMetaTemplate
+ .replace('%class', _encode(meta.compClass || ''))
+ .replace('%name', _encode(meta.compName || ''))
+ .replace('%params', _encode(paramsStr || ''));
- // external messenger to which all model users will subscribe,
- // that will allow "*" subscriptions and support "changedata" message api.
- var externalMessenger = new Messenger(this, undefined, internalMessengerSource);
+ if (data && typeof data == 'object') data = JSON.stringify(data);
- _.defineProperty(this, MESSENGER_PROPERTY, externalMessenger);
- _.defineProperty(this, '_internalMessenger', internalMessenger);
+ this.dataTransfer.setData(dataType, data || '');
+
+ return dataType;
}
-function _getHostObject() {
- return this._hostObject;
+function _encode(str) {
+ return base32.encode(str).toLowerCase();
}
-function Model$$registerWithDOMStorage() {
- var DOMStorage = require('../util/storage');
- DOMStorage.registerDataType('Model', Model_domStorageSerializer, Model_domStorageParser);
- DOMStorage.registerDataType('ModelPath', Model_domStorageSerializer, Model_domStorageParser, 'Model');
+function _componentMeta(component) {
+ return component.transfer
+ ? component.transfer.getComponentMeta()
+ : {
+ compClass: component.constructor.name,
+ compName: component.name
+ };
}
-function Model_domStorageSerializer(value) {
- var data = value.get();
- return JSON.stringify(data);
-}
+function DragDrop$getComponentMeta() {
+ var match;
+ var metaDataType = _.find(this.types, function (dType) {
+ match = dType.match(componentMetaRegex);
+ return !!match;
+ });
+ if (!metaDataType) return;
+ for (var i=1; i<4; i++)
+ match[i] = base32.decode(match[i]);
-function Model_domStorageParser(valueStr) {
- var data = jsonParse(valueStr);
- return new Model(data);
+ return {
+ compClass: match[1],
+ compName: match[2],
+ params: _.fromQueryString(match[3]),
+ metaDataType: metaDataType,
+ metaData: _.jsonParse(this.dataTransfer.getData(metaDataType))
+ ? _.jsonParse(this.dataTransfer.getData(metaDataType))
+ : this.dataTransfer.getData(metaDataType)
+ };
}
-function Model$destroy() {
- this[MESSENGER_PROPERTY].destroy();
- this._internalMessenger.destroy();
- this._destroyed = true;
+// as defined here: https://developer.mozilla.org/en-US/docs/DragDrop/Drag_Operations#dragstart
+function DragDrop$getAllowedEffects() {
+ return this.dataTransfer.effectAllowed;
}
-},{"../abstract/mixin":3,"../messenger":67,"../messenger/msngr_source":71,"../util/check":90,"../util/error":98,"../util/json_parse":101,"../util/logger":102,"../util/storage":106,"./change_data":73,"./m_msg_api":75,"./m_path":76,"./path_utils":79,"./synthesize":80,"mol-proto":150}],75:[function(require,module,exports){
-'use strict';
-var MessengerRegexpAPI = require('../messenger/m_api_rx')
- , pathUtils = require('./path_utils')
- , _ = require('mol-proto');
+function DragDrop$setAllowedEffects(effects) {
+ this.dataTransfer.effectAllowed = effects;
+}
-/**
- * Subclass of MessengerRegexpAPI that is used to translate messages of external messenger of Model to internal messenger of Model.
- */
-var ModelMsgAPI = _.createSubclass(MessengerRegexpAPI, 'ModelMsgAPI');
+function DragDrop$getDropEffect() {
+ return this.dataTransfer.dropEffect;
+}
-module.exports = ModelMsgAPI;
+function DragDrop$setDropEffect(effect) {
+ this.dataTransfer.dropEffect = effect;
+}
-/**
- * ####ModelMsgAPI instance methods####
- *
- * - [translateToSourceMessage](#translateToSourceMessage) - translates subscription paths with "*"s to regex, leaving other strings untouched
- */
-_.extendProto(ModelMsgAPI, {
- translateToSourceMessage: translateToSourceMessage,
-});
+function DragDrop$isEffectAllowed(effect) {
+ var allowedEffects = this.getAllowedEffects()
+ , isCopy = effect == 'copy'
+ , isMove = effect == 'move'
+ , isLink = effect == 'link'
+ , isAllowed = isCopy || isLink || isMove;
-/**
- * ModelMsgAPI instance method
- * Translates subscription paths with "*"s to regex, leaving other strings untouched.
- *
- * @param {String} accessPath relative access path to be translated
- * @return {RegExp|String}
- */
-function translateToSourceMessage(accessPath) {
- if (accessPath instanceof RegExp) return accessPath;
+ switch (allowedEffects) {
+ case 'copy':
+ case 'move':
+ case 'link':
+ return allowedEffects == effect;
+ case 'copyLink':
+ return isCopy || isLink;
+ case 'copyMove':
+ return isCopy || isMove;
+ case 'linkMove':
+ return isLink || isMove;
+ case 'all':
+ case 'uninitialized':
+ return isAllowed;
+ case 'none':
+ return false;
+ }
+}
- return pathUtils.createRegexPath(accessPath);
+
+function DragDrop$getData(dataType) {
+ return this.dataTransfer.getData(dataType);
}
-},{"../messenger/m_api_rx":69,"./path_utils":79,"mol-proto":150}],76:[function(require,module,exports){
-'use strict';
-var synthesize = require('./synthesize')
- , pathUtils = require('./path_utils')
- , changeDataHandler = require('./change_data')
- , Messenger = require('../messenger')
- , ModelPathMsgAPI = require('./path_msg_api')
- , MessengerMessageSource = require('../messenger/msngr_source')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match;
+function DragDrop$setData(dataType, dataStr) {
+ this.dataTransfer.setData(dataType, dataStr);
+}
-module.exports = ModelPath;
+function DragDrop$clearData(dataType) {
+ this.dataTransfer.clearData(dataType);
+}
/**
- * `milo.Model.Path`
- * ModelPath object that allows access to any point inside [Model](./index.js.html) as defined by `accessPath`
- *
- * @constructor
- * @param {Model} model Model instance that ModelPath gives access to.
- * @param {String} accessPath string that defines path to access model.
- * Path string consists of parts to define either property access (`".name"` to access property name) or array item access (`"[1]"` to access item with index 1).
- * Access path can contain as many parts as necessary (e.g. `".list[0].name"` to access property `name` in the first element of array stored in property `list`.
- * @param {List} arguments additional arguments of this method can be used to create interpolated paths.
- * E.g. `m.path("[$1].$2", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m("[" + id + "]." + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.
- * @return {ModelPath}
+ * Drag drop service compensating for the lack of communication from drop target to drag source in DOM API
*/
-function ModelPath(model, path) { // ,... - additional arguments for interpolation
- // check(model, Model);
- check(path, String);
+var dragDropService = new Messenger;
- // `modelPath` will be returned by constructor instead of `this`. `modelPath`
- // (`modelPath_path` function) should also return a ModelPath object with "synthesized" methods
- // to get/set model properties, to subscribe to property changes, etc.
- // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.
- var modelPath = function modelPath_path(accessPath) { // , ... arguments that will be interpolated
- return ModelPath$path.apply(modelPath, arguments);
- };
- modelPath.__proto__ = ModelPath.prototype;
+var _currentDragDrop, _currentDragFacet;
+_.extend(DragDrop, {
+ service: dragDropService,
+ destroy: DragDrop_destroy
+});
- _.defineProperties(modelPath, {
- _model: model,
- _path: path,
- _args: _.slice(arguments, 1), // path will be the first element of this array
- _options: model._options
- });
- // parse access path
- var parsedPath = pathUtils.parseAccessPath(path);
+dragDropService.onMessages({
+ // data is DragDropDataTransfer instance
+ // fired by Drag facet on "dragstart" event
+ 'dragdropstarted': onDragDropStarted,
+ // data is object with at least dropEffect property
+ // fired by Drop facet on "drop" event
+ 'dragdropcompleted': onDragDropCompleted,
+ // fired by Drag facet on "dragend" event to complete drag
+ // if drop happended in another window or if it was cancelled
+ 'completedragdrop': onCompleteDragDrop
+});
- // compute access path string
- _.defineProperty(modelPath, '_accessPath', interpolateAccessPath(parsedPath, modelPath._args));
- if (modelPath._options.reactive !== false) {
- // messenger fails on "*" subscriptions
- modelPath._prepareMessenger();
- // subscribe to "changedata" message to enable reactive connections
- modelPath.onSync('changedata', changeDataHandler);
- }
+_.extend(dragDropService, {
+ getCurrentDragDrop: getCurrentDragDrop
+});
- // compiling getter and setter
- var methods = synthesize(path, parsedPath);
- // adding methods to model path
- _.defineProperties(modelPath, methods);
+function onDragDropStarted(msg, data) {
+ _currentDragDrop = data.dragDrop;
+ _currentDragFacet = data.dragFacet;
+}
- Object.freeze(modelPath);
- return modelPath;
+function onDragDropCompleted(msg, data) {
+ _currentDragFacet && _currentDragFacet.postMessageSync('dragdropcompleted', data);
+ _currentDragDrop = undefined;
+ _currentDragFacet = undefined;
}
-ModelPath.prototype.__proto__ = ModelPath.__proto__;
-
-/**
- * Interpolates path elements to compute real path
- *
- * @param {Array} parsedPath parsed path - array of path nodes
- * @param {Array} args path interpolation arguments, args[0] is path itself
- * @return {String}
- */
-function interpolateAccessPath(parsedPath, args) {
- return parsedPath.reduce(function(accessPathStr, currNode, index) {
- var interpolate = currNode.interpolate;
- return accessPathStr +
- (interpolate
- ? (currNode.syntax == 'array'
- ? '[' + args[interpolate] + ']'
- : '.' + args[interpolate])
- : currNode.property);
- }, '');
+function onCompleteDragDrop(msg, data) {
+ if (_currentDragDrop)
+ dragDropService.postMessageSync('dragdropcompleted', data);
}
-/**
- * ####ModelPath instance methods####
- *
- * - [path](#ModelPath$path) - gives access to path inside ModelPath
- * - get - synthesized
- * - set - synthesized
- * - splice - splice model data (as array or pseudo-array), synthesized
- * - [len](#ModelPath$len) - returns length of array (or pseudo-array) in safe way, 0 if no length is set
- * - [push](#ModelPath$push) - add items to the end of array (or pseudo-array) in ModelPath
- * - [pop](#ModelPath$pop) - remove item from the end of array (or pseudo-array) in ModelPath
- * - [unshift](#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in ModelPath
- * - [shift](#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in ModelPath
- */
-_.extendProto(ModelPath, {
- path: ModelPath$path,
- len: ModelPath$len,
- push: ModelPath$push,
- pop: ModelPath$pop,
- unshift: ModelPath$unshift,
- shift: ModelPath$shift,
- _prepareMessenger: _prepareMessenger,
- _getDefinition: _getDefinition,
- destroy: ModelPath$destroy
-});
+function getCurrentDragDrop() {
+ return _currentDragDrop;
+}
-_.extend(ModelPath, {
- _createFromDefinition: _createFromDefinition
-})
+function DragDrop_destroy() {
+ dragDropService.offAll();
+}
+},{"../components/c_class":15,"../config":64,"base32":95,"milo-core":105}],83:[function(require,module,exports){
+//
+// milo.utils.error
+// -----------
-/**
- * Expose Messenger methods on Facet prototype
- */
-var MESSENGER_PROPERTY = '_messenger';
-Messenger.useWith(ModelPath, MESSENGER_PROPERTY, Messenger.defaultMethods);
+'use strict';
+var _ = require('milo-core').proto;
-/**
- * ModelPath instance method
- * Gives access to path inside ModelPath. Method works similarly to [path method](#Model$path) of model, using relative paths.
- *
- * @param {String} accessPath string that defines path to access model.
- * Path string consists of parts to define either property access (`".name"` to access property name) or array item access (`"[1]"` to access item with index 1).
- * Access path can contain as many parts as necessary (e.g. `".list[0].name"` to access property `name` in the first element of array stored in property `list`.
- * @param {List} arguments additional arguments of this method can be used to create interpolated paths.
- * E.g. `m.path("[$1].$2", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m("[" + id + "]." + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.
- * @return {ModelPath}
- */
-function ModelPath$path(accessPath) { // , ... arguments that will be interpolated
- if (! accessPath) return this;
- var thisPathArgsCount = this._args.length - 1;
+// module exports error classes for all names defined in this array
+var errorClassNames = ['AbstractClass', 'Mixin', 'Messenger', 'Component',
+ 'Attribute', 'Binder', 'Loader', 'MailMessageSource', 'Facet',
+ 'Scope', 'Model', 'DomFacet', 'EditableFacet',
+ 'List', 'Connector', 'Registry', 'FrameMessageSource',
+ 'Drop', 'Angular', 'StorageMessageSource'];
- if (thisPathArgsCount > 0) {// this path has interpolated arguments too
- accessPath = accessPath.replace(/\$[1-9][0-9]*/g, function(str) {
- return '$' + (+str.slice(1) + thisPathArgsCount);
- });
- }
+var error = {
+ toBeImplemented: error$toBeImplemented,
+ createClass: error$createClass
+};
- var newPath = this._path + accessPath;
+errorClassNames.forEach(function(name) {
+ error[name] = error$createClass(name + 'Error');
+});
- // this._model is added in front of all arguments as the first parameter
- // of ModelPath constructor
- var args = [this._model, newPath]
- .concat(this._args.slice(1)) // remove old path from _args, as it is 1 based
- .concat(_.slice(arguments, 1)); // add new interpolation arguments
+module.exports = error;
- // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...
- return _.newApply(ModelPath, args);
-}
+function error$createClass(errorClassName) {
+ var ErrorClass = _.makeFunction(errorClassName, 'message',
+ 'this.name = "' + errorClassName + '"; \
+ this.message = message || "There was an error";');
+ _.makeSubclass(ErrorClass, Error);
-/**
- * ModelPath and Model instance method
- * Returns length property and sets it to 0 if it wasn't set.
- *
- * @return {Any}
- */
-function ModelPath$len() {
- return this.path('.length').get() || 0;
+ return ErrorClass;
}
-/**
- * ModelPath and Model instance method
- * Adds items to the end of array (or pseudo-array). Returns new length.
- *
- * @param {List} arguments list of items that will be added to array (pseudo array)
- * @return {Integer}
- */
-function ModelPath$push() { // arguments
- var length = this.len();
- var newLength = length + arguments.length;
+function error$toBeImplemented() {
+ throw new error.AbstractClass('calling the method of an absctract class');
+}
- _.splice(arguments, 0, 0, length, 0);
- this.splice.apply(this, arguments);
+},{"milo-core":105}],84:[function(require,module,exports){
+'use strict';
- return newLength;
-}
+var Component = require('../components/c_class')
+ , BindAttribute = require('../attributes/a_bind')
+ , binder = require('../binder')
+ , domUtils = require('./dom')
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , check = miloCore.util.check
+ , _ = miloCore.proto;
-/**
- * ModelPath and Model instance method
- * Removes item from the end of array (or pseudo-array). Returns this item.
- *
- * @return {Any}
- */
-function ModelPath$pop() {
- return this.splice(this.len() - 1, 1)[0];
-}
+var createRangePaths = _createNodesAndPathsFunc(domUtils.treePathOf);
+var createRangeNodes = _createNodesAndPathsFunc(domUtils.getNodeAtTreePath);
-/**
- * ModelPath and Model instance method
- * Inserts items to the beginning of the array. Returns new length.
- *
- * @param {List} arguments items to be inserted in the beginning of array
- * @return {Integer}
- */
-function ModelPath$unshift() { // arguments
- var length = this.len();
- length += arguments.length;
- _.splice(arguments, 0, 0, 0, 0);
- this.splice.apply(this, arguments);
+var fragmentUtils = module.exports = {
+ getState: fragment_getState,
+ getStateAsync: fragment_getStateAsync,
- return length;
-}
+ expandRangeToSiblings: expandRangeToSiblings,
+ getRangeSiblings: getRangeSiblings,
+ createRangeFromSiblings: createRangeFromSiblings,
+ createRangeFromNodes: createRangeFromSiblings, // alias
+ createRangePaths: createRangePaths,
+ createRangeNodes: createRangeNodes
+};
/**
- * ModelPath and Model instance method
- * Removes the item from the beginning of array (or pseudo-array). Returns this item.
- *
- * @return {Any}
+ * Creates an object with the state of wrapped range with components, including partially selected. The range will be cloned and wrapped in component with container facet before getting its state.
+ * This function will log error and return undefined if range has no common ancestor that has component with container facet
+ *
+ * @param {Range} range DOM Range instance
+ * @param {Boolean} renameChildren optional parameter, `true` to rename fragment child components
+ * @param {String} wrapperClassName optional parameter to wrap in a custom component class
+ * @return {Object}
*/
-function ModelPath$shift() { // arguments
- return this.splice(0, 1)[0];
+function fragment_getState(range, renameChildren, wrapperClassName) {
+ var rangeContainer = _getRangeContainer(range);
+ if (! rangeContainer) {
+ logger.error('fragment.getState: range has no common container');
+ return;
+ }
+
+ var frag = range.cloneContents()
+ , wrapper = _wrapFragmentInContainer(frag, wrapperClassName);
+
+ _transferStates(rangeContainer, wrapper);
+ if (renameChildren) _renameChildren(wrapper);
+ var wrapperState = wrapper.getState();
+ _.deferMethod(wrapper, 'destroy');
+ return wrapperState;
}
/**
- * ModelPath instance method
- * Initializes ModelPath mesenger with Model's messenger as its source ([MessengerMessageSource](../messenger/msngr_source.js.html)) and [ModelPathMsgAPI](./path_msg_api.js.html) as [MessengerAPI](../messenger/m_api.js.html)
+ * Creates an object with the state of wrapped range with components, including partially selected. The range will be cloned and wrapped in component with container facet before getting its state.
+ * This function will return result and any error via callback.
+ *
+ * @param {Range} range DOM Range instance
+ * @param {Boolean} renameChildren optional parameter, `true` to rename fragment child components
+ * @param {Function} callback always the last parameter, optional parameters can be dropped; result is passed via callback with any error as first parameter
*/
-function _prepareMessenger() {
- var mPathAPI = new ModelPathMsgAPI(this._accessPath);
+function fragment_getStateAsync(range, renameChildren, callback) {
+ try {
+ var rangeContainer = _getRangeContainer(range);
+ if (! rangeContainer) {
+ callback(new Error('fragment.getState: range has no common container'));
+ return; // do NOT connect return to previous callback, getState should return undefined
+ }
- // create MessengerMessageSource connected to Model's messenger
- var modelMessageSource = new MessengerMessageSource(this, undefined, mPathAPI, this._model);
+ if (typeof renameChildren == 'function') {
+ callback = renameChildren;
+ renameChildren = false;
+ }
- // create messenger with model passed as hostObject (default message dispatch context)
- // and without proxying methods (we don't want to proxy them to Model)
- var mPathMessenger = new Messenger(this, undefined, modelMessageSource);
+ var frag = range.cloneContents()
+ , wrapper = _wrapFragmentInContainer(frag);
- // store messenger on ModelPath instance
- _.defineProperty(this, MESSENGER_PROPERTY, mPathMessenger);
+ _transferStates(rangeContainer, wrapper);
+ _.defer(function() {
+ wrapper.broadcast('stateready');
+ _.defer(function() {
+ if (renameChildren) _renameChildren(wrapper);
+ var wrapperState = wrapper.getState();
+ wrapper.destroy();
+ callback(null, wrapperState);
+ });
+ });
+ } catch (err) {
+ callback(err);
+ }
}
-/**
- * Returns the object allowing to recreate model path
- *
- * @return {Object}
- */
-function _getDefinition() {
- return {
- model: this._model,
- path: this._path,
- args: this._args
- };
-}
-
+function _wrapFragmentInContainer(frag, wrapperClassName) {
+ var wrapEl = document.createElement('div')
+ , attr = new BindAttribute(wrapEl);
-/**
- * Class method
- * Creates modelPath object from definition created by _getDefinition
- *
- * @param {Object} definition
- * @return {ModelPath}
- */
-function _createFromDefinition(definition) {
- check(definition, {
- model: Function, // Model
- path: String,
- args: Array
+ _.extend(attr, {
+ compClass: wrapperClassName || 'Component',
+ compFacets: wrapperClassName ? [] : ['container'],
+ compName: 'wrapper'
});
- var m = definition.model;
+ attr.decorate();
- return m.apply(m, definition.args);
+ wrapEl.appendChild(frag);
+ var scope = binder(wrapEl);
+ return scope.wrapper;
}
-function ModelPath$destroy() {
- this[MESSENGER_PROPERTY].destroy();
+function _getRangeContainer(range) {
+ var el = domUtils.containingElement(range.commonAncestorContainer);
+ return Component.getContainingComponent(el, true, 'container');
}
-},{"../messenger":67,"../messenger/msngr_source":71,"../util/check":90,"./change_data":73,"./path_msg_api":78,"./path_utils":79,"./synthesize":80,"mol-proto":150}],77:[function(require,module,exports){
-'use strict';
+function _transferStates(fromComp, toComp) {
+ var fromScope = fromComp.container.scope;
+ toComp.container.scope._each(function(toChildComp, name) {
+ var fromChildComp = fromScope[name];
+ if (! fromChildComp) return logger.error('fragment.getState: conponent', name, 'not found in range');
+ var state = fromChildComp._getState(true);
+ toChildComp.setState(state);
+ });
+}
-var modelUtils = {
- normalizeSpliceIndex: normalizeSpliceIndex
-};
-module.exports = modelUtils;
+function _renameChildren(comp) {
+ comp.container.scope._each(function(child) {
+ child.rename();
+ });
+}
-function normalizeSpliceIndex(spliceIndex, length) {
- return spliceIndex > length
- ? length
- : spliceIndex >= 0
- ? spliceIndex
- : spliceIndex + length > 0
- ? spliceIndex + length
- : 0;
+function expandRangeToSiblings(range) {
+ var siblings = getRangeSiblings(range);
+ range = createRangeFromSiblings(siblings);
+ return range;
}
-},{}],78:[function(require,module,exports){
-'use strict';
-var MessengerAPI = require('../messenger/m_api')
- , pathUtils = require('./path_utils')
- , logger = require('../util/logger')
- , _ = require('mol-proto');
+function createRangeFromSiblings(nodes) {
+ var range = document.createRange();
+ if (nodes.siblings) {
+ range.setStartBefore(nodes.start);
+ range.setEndAfter(nodes.end);
+ } else
+ range.selectNode(nodes.start);
+ return range;
+}
-/**
- * Subclass of MessengerAPI that is used to translate messages of Messenger on ModelPath to Messenger on Model.
- */
-var ModelPathMsgAPI = _.createSubclass(MessengerAPI, 'ModelPathMsgAPI');
+function getRangeSiblings(range) {
+ var containerNode = range.commonAncestorContainer
+ , startNode = range.startContainer
+ , endNode = range.endContainer;
-module.exports = ModelPathMsgAPI;
+ if (startNode == endNode) {
+ if (startNode != containerNode) logger.error('deleteSelectionCommand logical error: start==end, but container is different');
+ return { siblings: false, start: startNode };
+ }
+ if (startNode == containerNode || endNode == containerNode)
+ return { siblings: false, start: containerNode };
-/**
- * ####ModelPathMsgAPI instance methods####
- *
- * - [init](#init) - initializes ModelPathMsgAPI
- * - [translateToSourceMessage](#translateToSourceMessage) - translates relative access paths of ModelPath to full path of Model
- * - [createInternalData](#createInternalData) - changes path in message on model to relative path and adds `fullPath` property to message data
- */
-_.extendProto(ModelPathMsgAPI, {
- init: init,
- translateToSourceMessage: translateToSourceMessage,
- createInternalData: createInternalData,
-});
+ var startSibling = _findContainingChild(containerNode, startNode);
+ var endSibling = _findContainingChild(containerNode, endNode);
+ if (startSibling && endSibling) {
+ if (startSibling == endSibling) {
+ logger.error('deleteSelectionCommand logical error: same siblings');
+ return { siblings: false, start: startSibling };
+ } else
+ return { siblings: true, start: startSibling, end: endSibling };
+ }
+}
-/**
- * ModelPathMsgAPI instance method
- * Called by MessengerAPI constructor.
- *
- * @param {String} rootPath root path of model path
- */
-function init(rootPath) {
- MessengerAPI.prototype.init.apply(this, arguments);
- this.rootPath = rootPath;
+
+function _findContainingChild(containerNode, selNode) {
+ return _.find(containerNode.childNodes, function(node) {
+ return node.contains(selNode);
+ });
}
-/**
- * ModelPathMsgAPI instance method
- * Translates relative access paths of ModelPath to full path of Model.
- *
- * @param {String} accessPath relative access path to be translated
- * @return {String}
- */
-function translateToSourceMessage(message) {
- // TODO should prepend RegExes
- // TODO should not prepend changedata too???
- if (message instanceof RegExp)
- return message;
- if (message == 'datachanges')
- return message;
-
- return this.rootPath + message;
+
+function _createNodesAndPathsFunc(func) {
+ return function(rootEl, fromObj) {
+ var toObj = {
+ siblings: fromObj.siblings,
+ start: func(rootEl, fromObj.start)
+ };
+ if (toObj.siblings)
+ toObj.end = func(rootEl, fromObj.end);
+ return toObj;
+ };
}
+
+},{"../attributes/a_bind":4,"../binder":8,"../components/c_class":15,"./dom":79,"milo-core":105}],85:[function(require,module,exports){
+'use strict';
+
+var miloCore = require('milo-core');
+
/**
- * ModelPathMsgAPI instance method
- * Changes path in message on model to relative path and adds `fullPath` property to message data.
- *
- * @param {String} sourceMessage full access path on Model
- * @param {String} message relative access path on ModelPath
- * @param {Object} sourceData data received from Model, will be translated as described to be dispatched to ModelPath
- * @return {Object}
+ * `milo.util`
*/
-function createInternalData(sourceMessage, message, sourceData) {
- // TODO return on changedata too???
- if (message == 'datachanges') {
- var internalChanges = sourceData.changes
- .map(truncateChangePath, this)
- .filter(function(change) { return change; });
- var internalData = {
- changes: internalChanges,
- transaction: sourceData.transaction
- };
+var util = {
+ logger: miloCore.util.logger,
+ request: require('./request'),
+ websocket: require('./websocket'),
+ check: miloCore.util.check,
+ error: require('./error'), // deprecated
+ count: require('./count'), // deprecated
+ uniqueId: require('./count'),
+ componentName: require('./component_name'),
+ dom: require('./dom'),
+ domListeners: require('./dom_listeners'),
+ selection: require('./selection'),
+ fragment: require('./fragment'),
+ jsonParse: require('./json_parse'), // deprecated
+ storage: require('./storage'),
+ domReady: require('./domready'),
+ dragDrop: require('./dragdrop'),
+ dialog: require('../components/ui/bootstrap/Dialog'), // deprecated - should be used from registry
+ alert: require('../components/ui/bootstrap/Alert'), // deprecated - should be used from registry
+ doT: miloCore.util.doT,
+ destroy: util_destroy
+};
- return internalData
- }
+module.exports = util;
- var internalData = truncateChangePath.call(this, sourceData);
- return internalData;
+
+function util_destroy() {
+ util.request.destroy();
+ util.dragDrop.destroy();
}
+},{"../components/ui/bootstrap/Alert":61,"../components/ui/bootstrap/Dialog":62,"./component_name":76,"./count":77,"./dom":79,"./dom_listeners":80,"./domready":81,"./dragdrop":82,"./error":83,"./fragment":84,"./json_parse":86,"./request":87,"./selection":88,"./storage":89,"./websocket":92,"milo-core":105}],86:[function(require,module,exports){
+'use strict';
-function truncateChangePath(change) {
- var fullPath = change.path
- , path = _.unPrefix(fullPath, this.rootPath);
- if (typeof path == 'string') {
- var change = _.clone(change);
- change.fullPath = fullPath;
- change.path = path;
- return change;
- }
+module.exports = jsonParse;
+
+
+/**
+ * `milo.util.jsonParse`
+ * Safe JSON.parse, returns undefined if JSON.parse throws an exception
+ *
+ * @param {String} str - JSON string representation of object
+ * @return {Object|undefined}
+ */
+function jsonParse(str) {
+ try {
+ return JSON.parse(str);
+ } catch (e) {}
}
-},{"../messenger/m_api":68,"../util/logger":102,"./path_utils":79,"mol-proto":150}],79:[function(require,module,exports){
+},{}],87:[function(require,module,exports){
'use strict';
-//
-// ### model path utils
-
-var check = require('../util/check')
- , Match = check.Match
- , _ = require('mol-proto')
- , ModelError = require('../util/error').Model;
+// milo.utils.request
+// -----------
-var pathUtils = {
- parseAccessPath: parseAccessPath,
- createRegexPath: createRegexPath,
- getPathNodeKey: getPathNodeKey,
- wrapMessengerMethods: wrapMessengerMethods
-};
+// Convenience functions wrapping XMLHTTPRequest functionality.
-module.exports = pathUtils;
+// ```
+// var request = milo.utils.request
+// , opts: { method: 'GET' };
+// request(url, opts, function(err, data) {
+// logger.debug(data);
+// });
-var propertyPathSyntax = '\\.[A-Za-z_-][A-Za-z0-9_-]*'
- , arrayPathSyntax = '\\[[0-9]+\\]'
- , interpolationSyntax = '\\$[1-9][0-9]*'
- , propertyInterpolateSyntax = '\\.' + interpolationSyntax
- , arrayInterpolateSyntax = '\\[' + interpolationSyntax + '\\]'
+// request.get(url, function(err, data) {
+// logger.debug(data);
+// });
+// ```
- , propertyStarSyntax = '\\.\\*'
- , arrayStarSyntax = '\\[\\*\\]'
- , starSyntax = '\\*'
+// Only generic request and get, json, post convenience methods are currently implemented.
- , pathParseSyntax = [
- propertyPathSyntax,
- arrayPathSyntax,
- propertyInterpolateSyntax,
- arrayInterpolateSyntax
- ].join('|')
- , pathParsePattern = new RegExp(pathParseSyntax, 'g')
- , patternPathParseSyntax = [
- pathParseSyntax,
- propertyStarSyntax,
- arrayStarSyntax,
- starSyntax
- ].join('|')
- , patternPathParsePattern = new RegExp(patternPathParseSyntax, 'g')
+var miloCore = require('milo-core')
+ , _ = miloCore.proto
+ , count = require('./count')
+ , config = require('../config')
+ , logger = miloCore.util.logger
+ , Messenger = miloCore.Messenger;
- //, targetPathParsePattern = /\.[A-Za-z][A-Za-z0-9_]*|\[[0-9]+\]|\.\$[1-9][0-9]*|\[\$[1-9][0-9]*\]|\$[1-9][0-9]/g
- , pathNodeTypes = {
- '.': { syntax: 'object', empty: '{}' },
- '[': { syntax: 'array', empty: '[]'},
- '*': { syntax: 'match', empty: '{}'},
- };
+module.exports = request;
-function parseAccessPath(path, nodeParsePattern) {
- nodeParsePattern = nodeParsePattern || pathParsePattern;
- var parsedPath = [];
+var _pendingRequests = [];
- if (! path)
- return parsedPath;
+var promiseThen = createPromiseOverride('then');
+var promiseCatch = createPromiseOverride('catch');
- var unparsed = path.replace(nodeParsePattern, function(nodeStr) {
- var pathNode = { property: nodeStr };
- _.extend(pathNode, pathNodeTypes[nodeStr[0]]);
- if (nodeStr[1] == '$')
- pathNode.interpolate = getPathNodeKey(pathNode, true);
+/**
+ * Creates a function which is used to override standard promise behaviour and allow promise instances
+ * created to maintain a reference to the request object no matter if .then() or .catch() is called.
+ */
+function createPromiseOverride(functionName) {
+ return function() {
+ var promise = Promise.prototype[functionName].apply(this, arguments);
+ keepRequestObject(promise, this._request);
+ return promise;
+ }
+}
- parsedPath.push(pathNode);
- return '';
- });
- if (unparsed)
- throw new ModelError('incorrect model path: ' + path);
- return parsedPath;
-}
+function request(url, opts, callback) {
+ opts.url = url;
+ opts.contentType = opts.contentType || 'application/json;charset=UTF-8';
+ if (_messenger) request.postMessageSync('request', { options: opts });
+ var req = new XMLHttpRequest();
+ req.open(opts.method, opts.url, true);
+ req.setRequestHeader('Content-Type', opts.contentType);
+ setRequestHeaders(req, opts.headers);
-var nodeRegex = {
- '.*': propertyPathSyntax,
- '[*]': arrayPathSyntax
-};
-nodeRegex['*'] = nodeRegex['.*'] + '|' + nodeRegex['[*]'];
+ req.timeout = opts.timeout || config.request.defaults.timeout;
+ req.onreadystatechange = req.ontimeout = req.onabort = onReady;
-function createRegexPath(path) {
- check(path, Match.OneOf(String, RegExp));
+ var xPromise = _createXPromise(req);
- if (path instanceof RegExp || path.indexOf('*') == -1)
- return path;
+ req.send(JSON.stringify(opts.data));
+ req[config.request.optionsKey] = opts;
- var parsedPath = pathUtils.parseAccessPath(path, patternPathParsePattern)
- , regexStr = '^'
- // , regexStrEnd = ''
- , patternsStarted = false;
+ _pendingRequests.push(req);
- parsedPath.forEach(function(pathNode) {
- var prop = pathNode.property
- , regex = nodeRegex[prop];
-
- if (regex) {
- // regexStr += '(' + regex;
- // regexStrEnd += '|)';
- regexStr += '(' + regex + '|)';
- // regexStrEnd += '|)';
- patternsStarted = true;
- } else {
- // if (patternsStarted)
- // throw new ModelError('"*" path segment cannot be in the middle of the path: ' + path);
- regexStr += prop.replace(/(\.|\[|\])/g, '\\$1'); // add slash in front of symbols that have special meaning in regex
- }
+ return xPromise.promise;
+
+ function onReady(e) {
+ _onReady(req, callback, xPromise, e.type);
+ }
+}
+
+
+function _createXPromise(request) {
+ var resolvePromise, rejectPromise;
+ var promise = new Promise(function(resolve, reject) {
+ resolvePromise = resolve;
+ rejectPromise = reject;
});
- regexStr += /* regexStrEnd + */ '$';
+ keepRequestObject(promise, request);
+ promise.catch(_.noop); // Sometimes errors are handled within callbacks, so uncaught promise error message should be suppressed.
- try {
- return new RegExp(regexStr);
- } catch (e) {
- throw new ModelError('can\'t construct regex for path pattern: ' + path);
+ return {
+ promise: promise,
+ resolve: resolvePromise,
+ reject: rejectPromise
}
}
+// Ensures that the promise (and any promises created when calling .then/.catch) has a reference to the original request object
+function keepRequestObject(promise, request) {
+ promise._request = request;
+ promise.then = promiseThen;
+ promise.catch = promiseCatch;
-function getPathNodeKey(pathNode, interpolated) {
- var prop = pathNode.property
- , startIndex = interpolated ? 2 : 1;
- return pathNode.syntax == 'array'
- ? prop.slice(startIndex, prop.length - 1)
- : prop.slice(startIndex);
+ return promise;
}
-// TODO allow for multiple messages in a string
-function wrapMessengerMethods(methodsNames) {
- methodsNames = methodsNames || ['on', 'off'];
- var wrappedMethods = _.mapToObject(methodsNames, function(methodName) {
- var origMethod = this[methodName];
- // replacing message subsribe/unsubscribe/etc. to convert "*" message patterns to regexps
- return function(path, subscriber) {
- var regexPath = createRegexPath(path);
- origMethod.call(this, regexPath, subscriber);
- };
- }, this);
- _.defineProperties(this, wrappedMethods);
+function setRequestHeaders(req, headers) {
+ if (headers)
+ _.eachKey(headers, function(value, key) {
+ req.setRequestHeader(key, value);
+ });
}
-},{"../util/check":90,"../util/error":98,"mol-proto":150}],80:[function(require,module,exports){
-'use strict';
-
-var pathUtils = require('../path_utils')
- , modelUtils = require('../model_utils')
- , logger = require('../../util/logger')
- , miloCount = require('../../util/count')
- , fs = require('fs')
- , doT = require('dot')
- , _ = require('mol-proto')
- , changeDataHandler = require('../change_data')
- , getTransactionFlag = changeDataHandler.getTransactionFlag
- , postTransactionFinished = changeDataHandler.postTransactionFinished;
+function _onReady(req, callback, xPromise, eventType) {
+ if (req.readyState != 4) return;
+ if (!req.status && eventType == 'readystatechange') return;
+ _.spliceItem(_pendingRequests, req);
-/**
- * Templates to synthesize model getters and setters
- */
-var templates = {
- get: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\nmethod = function get() {\n var m = {{# def.modelAccessPrefix }};\n return m {{~ it.parsedPath :pathNode }}\n {{? pathNode.interpolate}}\n && (m = m[this._args[ {{= pathNode.interpolate }} ]])\n {{??}}\n && (m = m{{= pathNode.property }})\n {{?}} {{~}};\n};\n",
- set: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n{{# def.include_defines }}\n{{# def.include_create_tree }}\n\n\n/**\n * Template that synthesizes setter for Model and for ModelPath\n */\nmethod = function set(value) {\n {{# def.initVars:'set' }}\n\n {{# def.createTree:'set' }}\n\n {{\n currNode = nextNode;\n currProp = currNode && currNode.property;\n }}\n\n {{ /* assign value to the last property */ }}\n {{? currProp }}\n wasDef = {{# def.wasDefined}};\n {{# def.changeAccessPath }}\n\n var old = m{{# def.currProp }};\n\n {{ /* clone value to prevent same reference in linked models */ }}\n m{{# def.currProp }} = cloneTree(value);\n {{?}}\n\n {{ /* add message related to the last property change */ }}\n if (this._options.reactive !== false) {\n if (! wasDef)\n {{# def.addMsg }} accessPath, type: 'added',\n newValue: value });\n else if (old != value)\n {{# def.addMsg }} accessPath, type: 'changed',\n oldValue: old, newValue: value });\n\n {{ /* add message related to changes in (sub)properties inside removed and assigned value */ }}\n if (! wasDef || old != value)\n addTreeChangesMessages(messages, messagesHash,\n accessPath, old, value); /* defined in the function that synthesizes ModelPath setter */\n\n {{ /* post all stored messages */ }}\n {{# def.postMessages }}\n }\n};\n",
- del: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n{{# def.include_defines }}\n{{# def.include_traverse_tree }}\n\nmethod = function del() {\n {{# def.initVars:'del' }}\n\n {{? it.parsedPath.length }}\n {{# def.traverseTree }}\n\n {{\n var currNode = it.parsedPath[count];\n var currProp = currNode.property; \n }}\n\n if (! treeDoesNotExist && m && m.hasOwnProperty && {{# def.wasDefined}}) {\n var old = m{{# def.currProp }};\n delete m{{# def.currProp }};\n {{# def.changeAccessPath }}\n var didDelete = true;\n }\n {{??}}\n if (typeof m != 'undefined') {\n var old = m;\n {{# def.modelAccessPrefix }} = undefined;\n var didDelete = true;\n }\n {{?}}\n\n if (didDelete && this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'deleted', oldValue: old });\n\n addTreeChangesMessages(messages, messagesHash,\n accessPath, old, undefined); /* defined in the function that synthesizes ModelPath setter */\n\n {{ /* post all stored messages */ }}\n {{# def.postMessages }}\n }\n};\n",
- splice: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n{{# def.include_defines }}\n{{# def.include_create_tree }}\n{{# def.include_traverse_tree }}\n\nmethod = function splice(spliceIndex, spliceHowMany) { /* ,... - extra arguments to splice into array */\n {{# def.initVars:'splice' }}\n\n var argsLen = arguments.length;\n var addItems = argsLen > 2;\n\n if (addItems) {\n {{ /* only create model tree if items are inserted in array */ }}\n\n {{ /* if model is undefined it will be set to an empty array */ }} \n var value = [];\n {{# def.createTree:'splice' }}\n\n {{? nextNode }}\n {{\n var currNode = nextNode;\n var currProp = currNode.property;\n var emptyProp = '[]';\n }}\n\n {{# def.createTreeStep }}\n {{?}}\n\n } else if (spliceHowMany > 0) {\n {{ /* if items are not inserted, only traverse model tree if items are deleted from array */ }}\n {{? it.parsedPath.length }}\n {{# def.traverseTree }}\n\n {{\n var currNode = it.parsedPath[count];\n var currProp = currNode.property; \n }}\n\n {{ /* extra brace closes 'else' in def.traverseTreeStep */ }}\n {{# def.traverseTreeStep }} }\n {{?}}\n }\n\n {{ /* splice items */ }}\n if (addItems || (! treeDoesNotExist && m\n && m.length > spliceIndex ) ) {\n var oldLength = m.length = m.length || 0;\n\n arguments[0] = spliceIndex = normalizeSpliceIndex(spliceIndex, m.length);\n\n {{ /* clone added arguments to prevent same references in linked models */ }}\n if (addItems)\n for (var i = 2; i < argsLen; i++)\n arguments[i] = cloneTree(arguments[i]);\n\n {{ /* actual splice call */ }}\n var removed = Array.prototype.splice.apply(m, arguments);\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'splice',\n index: spliceIndex, removed: removed, addedCount: addItems ? argsLen - 2 : 0,\n newValue: m });\n\n if (removed && removed.length)\n removed.forEach(function(item, index) {\n var itemPath = accessPath + '[' + (spliceIndex + index) + ']';\n {{# def.addMsg }} itemPath, type: 'removed', oldValue: item });\n\n if (valueIsTree(item))\n addMessages(messages, messagesHash, itemPath, item, 'removed', 'oldValue');\n });\n\n if (addItems)\n for (var i = 2; i < argsLen; i++) {\n var item = arguments[i];\n var itemPath = accessPath + '[' + (spliceIndex + i - 2) + ']';\n {{# def.addMsg }} itemPath, type: 'added', newValue: item });\n\n if (valueIsTree(item))\n addMessages(messages, messagesHash, itemPath, item, 'added', 'newValue');\n }\n\n {{ /* post all stored messages */ }}\n {{# def.postMessages }}\n }\n }\n\n return removed || [];\n}\n"
-};
+ var error;
+ try {
+ if ( req.status >= 200 && req.status < 400 ) {
+ try {
+ postMessage('success');
+ callback && callback(null, req.responseText, req);
+ } catch(e) { error = e; }
+ xPromise.resolve(req.responseText);
+ }
+ else {
+ var errorReason = req.status || eventType;
+ try {
+ postMessage('error');
+ postMessage('error' + errorReason);
+ callback && callback(errorReason, req.responseText, req);
+ } catch(e) { error = e; }
+ xPromise.reject({ reason: errorReason, response: req.responseText });
+ }
+ } catch(e) {
+ error = error || e;
+ }
-var include_defines = "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n/**\n * Inserts initialization code\n */\n {{## def.initVars:method:\n var m = {{# def.modelAccessPrefix }};\n var messages = [], messagesHash = {};\n var accessPath = '';\n var treeDoesNotExist;\n /* hack to prevent sending finished events to allow for propagation of batches without splitting them */\n var inChangeTransaction = getTransactionFlag( {{= method }} );\n #}}\n\n/**\n * Inserts the beginning of function call to add message to list\n */\n{{## def.addMsg: addChangeMessage(messages, messagesHash, { path: #}}\n\n/**\n * Inserts current property/index for both normal and interpolated properties/indexes\n */\n{{## def.currProp:{{? currNode.interpolate }}[this._args[ {{= currNode.interpolate }} ]]{{??}}{{= currProp }}{{?}} #}}\n\n/**\n * Inserts condition to test whether normal/interpolated property/index exists\n */\n{{## def.wasDefined: m.hasOwnProperty(\n {{? currNode.interpolate }}\n this._args[ {{= currNode.interpolate }} ]\n {{??}}\n '{{= it.getPathNodeKey(currNode) }}'\n {{?}}\n) #}}\n\n\n/**\n * Inserts code to update access path for current property\n * Because of the possibility of interpolated properties, it can't be calculated in template, it can only be calculated during accessor call.\n */\n{{## def.changeAccessPath:\n accessPath += {{? currNode.interpolate }}\n {{? currNode.syntax == 'array' }}\n '[' + this._args[ {{= currNode.interpolate }} ] + ']';\n {{??}}\n '.' + this._args[ {{= currNode.interpolate }} ];\n {{?}}\n {{??}}\n '{{= currProp }}';\n {{?}}\n#}}\n\n\n/**\n * Inserts code to post stored messages\n */\n{{## def.postMessages:\n if (messages.length) {\n {{# def.modelPostBatchCode }}('datachanges', {\n changes: messages,\n transaction: inChangeTransaction\n });\n\n messages.forEach(function(msg) {\n {{# def.modelPostMessageCode }}(msg.path, msg);\n }, this);\n }\n#}}\n"
- , include_create_tree = "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n/**\n * Inserts code to create model tree as neccessary for `set` and `splice` accessors and to add messages to send list if the tree changes.\n */\n{{## def.createTree:method:\n var wasDef = true;\n var old = m;\n\n {{ var emptyProp = it.parsedPath[0] && it.parsedPath[0].empty; }}\n {{? emptyProp }}\n {{ /* create top level model if it was not previously defined */ }}\n if (! m) {\n m = {{# def.modelAccessPrefix }} = {{= emptyProp }};\n wasDef = false;\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} '', type: 'added',\n newValue: m });\n }\n }\n {{??}}\n {{? method == 'splice' }}\n if (! m) {\n {{?}}\n m = {{# def.modelAccessPrefix }} = cloneTree(value);\n wasDef = typeof old != 'undefined';\n {{? method == 'splice' }}\n }\n {{?}} \n {{?}}\n\n\n {{ /* create model tree if it doesn't exist */ }}\n {{ var modelDataProperty = '';\n var nextNode = it.parsedPath[0];\n var count = it.parsedPath.length - 1;\n\n for (var i = 0; i < count; i++) {\n var currNode = nextNode;\n var currProp = currNode.property;\n nextNode = it.parsedPath[i + 1];\n var emptyProp = nextNode && nextNode.empty;\n }}\n\n {{# def.createTreeStep }}\n\n {{ } /* for loop */ }}\n#}}\n\n\n/**\n * Inserts code to create one step in the model tree\n */\n{{## def.createTreeStep:\n {{# def.changeAccessPath }}\n\n if (! {{# def.wasDefined }}) { \n {{ /* property does not exist */ }}\n m = m{{# def.currProp }} = {{= emptyProp }};\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'added', \n newValue: m });\n }\n\n } else if (typeof m{{# def.currProp }} != 'object') {\n {{ /* property is not object */ }}\n var old = m{{# def.currProp }};\n m = m{{# def.currProp }} = {{= emptyProp }};\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'changed', \n oldValue: old, newValue: m });\n }\n\n } else {\n {{ /* property exists, just traverse down the model tree */ }}\n m = m{{# def.currProp }};\n }\n#}}\n"
- , include_traverse_tree = "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n/**\n * Inserts code to traverse model tree for `delete` and `splice` accessors.\n */\n{{## def.traverseTree:\n {{ \n var count = it.parsedPath.length-1;\n\n for (var i = 0; i < count; i++) { \n var currNode = it.parsedPath[i];\n var currProp = currNode.property;\n }}\n {{# def.traverseTreeStep }}\n\n {{ } /* for loop */\n\n var i = count;\n while (i--) { /* closing braces for else's above */\n }}\n }\n {{ } /* while loop */ }}\n#}}\n\n\n/**\n * Inserts code to traverse one step in the model tree\n */\n{{## def.traverseTreeStep:\n if (! (m && m.hasOwnProperty && {{# def.wasDefined}} ) )\n treeDoesNotExist = true;\n else {\n m = m{{# def.currProp }};\n {{# def.changeAccessPath }}\n {{ /* brace from else is not closed on purpose - all braces are closed in while loop */ }}\n#}}\n";
+ // not removing subscription creates memory leak, deleting property would not remove subscription
+ req.onreadystatechange = req.ontimeout = req.onabort = undefined;
-var dotDef = {
- include_defines: include_defines,
- include_create_tree: include_create_tree,
- include_traverse_tree: include_traverse_tree,
- getPathNodeKey: pathUtils.getPathNodeKey,
- modelAccessPrefix: 'this._model._data',
- modelPostMessageCode: 'this._model._internalMessenger.postMessage',
- modelPostBatchCode: 'this._model.postMessageSync',
- internalMessenger: 'this._model._internalMessenger'
-};
+ if (!_pendingRequests.length)
+ postMessage('requestscompleted');
-var modelDotDef = _(dotDef).clone().extend({
- modelAccessPrefix: 'this._data',
- modelPostMessageCode: 'this._internalMessenger.postMessage',
- modelPostBatchCode: 'this.postMessageSync',
- internalMessenger: 'this._internalMessenger'
-})._();
+ if (error) throw new Error('Exception: ' + error);
+ function postMessage(msg) {
+ if (_messenger) request.postMessage(msg,
+ { status: status, response: req.responseText });
+ }
+}
-var dotSettings = _.clone(doT.templateSettings);
-dotSettings.strip = false;
-var synthesizers = _.mapKeys(templates, function(tmpl) {
- return doT.template(tmpl, dotSettings, dotDef);
+_.extend(request, {
+ get: request$get,
+ post: request$post,
+ json: request$json,
+ jsonp: request$jsonp,
+ file: request$file,
+ useMessenger: request$useMessenger,
+ destroy: request$destroy,
+ whenRequestsCompleted: whenRequestsCompleted
});
-var modelSynthesizers = _.mapToObject(['set', 'del', 'splice'], function(methodName) {
- return doT.template(templates[methodName], dotSettings, modelDotDef);
-});
+var _messenger;
-/**
- * Function that synthesizes accessor methods.
- * Function is memoized so accessors are cached (up to 1000).
- *
- * @param {String} path Model/ModelPath access path
- * @param {Array} parsedPath array of path nodes
- * @return {Object[Function]}
- */
-var synthesizePathMethods = _.memoize(_synthesizePathMethods, undefined, 1000);
+function request$useMessenger() {
+ _messenger = new Messenger(request, ['on', 'once', 'onSync', 'off', 'onMessages', 'offMessages', 'postMessage', 'postMessageSync']);
+}
-function _synthesizePathMethods(path, parsedPath) {
- var methods = _.mapKeys(synthesizers, function(synthszr) {
- return _synthesize(synthszr, path, parsedPath);
- });
- return methods;
+
+function request$get(url, callback) {
+ return request(url, { method: 'GET' }, callback);
}
-var normalizeSpliceIndex = modelUtils.normalizeSpliceIndex; // used in splice.dot.js
+function request$post(url, data, callback) {
+ return request(url, { method: 'POST', data: data }, callback);
+}
-function _synthesize(synthesizer, path, parsedPath) {
- var method
- , methodCode = synthesizer({
- parsedPath: parsedPath,
- getPathNodeKey: pathUtils.getPathNodeKey
- });
+function request$json(url, callback) {
+ var promise = request(url, { method: 'GET' });
- try {
- eval(methodCode);
- } catch (e) {
- throw ModelError('ModelPath method compilation error; path: ' + path + ', code: ' + methodCode);
- }
+ var jsonPromise = promise.then(JSON.parse);
- return method;
+ if (callback)
+ jsonPromise
+ .then(function(data) { callback(null, data); })
+ .catch(function(errData) { callback(errData.reason, errData.response); });
+ return jsonPromise;
+}
- // functions used by methods `set`, `delete` and `splice` (synthesized by template)
- function addChangeMessage(messages, messagesHash, msg) {
- messages.push(msg);
- messagesHash[msg.path] = msg;
- }
- function addTreeChangesMessages(messages, messagesHash, rootPath, oldValue, newValue) {
- var oldIsTree = valueIsTree(oldValue)
- , newIsTree = valueIsTree(newValue);
+var jsonpOptions = { method: 'GET', jsonp: true };
+function request$jsonp(url, callback) {
+ var script = document.createElement('script'),
+ xPromise = _createXPromise(script),
+ head = window.document.head,
+ uniqueCallback = config.request.jsonpCallbackPrefix + count();
- if (newIsTree)
- addMessages(messages, messagesHash, rootPath, newValue, 'added', 'newValue');
-
- if (oldIsTree)
- addMessages(messages, messagesHash, rootPath, oldValue, 'removed', 'oldValue');
- }
+ var opts = _.extend({ url: url }, jsonpOptions);
+ if (_messenger) request.postMessageSync('request', { options: opts });
- function addMessages(messages, messagesHash, rootPath, obj, msgType, valueProp) {
- _addMessages(rootPath, obj);
+ if (! _.isEqual(_.omitKeys(opts, 'url'), jsonpOptions))
+ logger.warn('Ignored not allowed request options change in JSONP request - only URL can be changed');
+ var timeout = setTimeout(function() {
+ var err = new Error('No JSONP response or no callback in response');
+ _onResult(err);
+ }, config.request.jsonpTimeout);
- function _addMessages(rootPath, obj) {
- if (Array.isArray(obj)) {
- var pathSyntax = rootPath + '[$$]';
- obj.forEach(function(value, index) {
- addMessage(value, index, pathSyntax);
- });
- } else {
- var pathSyntax = rootPath + '.$$';
- _.eachKey(obj, function(value, key) {
- addMessage(value, key, pathSyntax);
- });
- }
- }
+ window[uniqueCallback] = _.partial(_onResult, null);
- function addMessage(value, key, pathSyntax) {
- var path = pathSyntax.replace('$$', key)
- , existingMsg = messagesHash[path];
+ _pendingRequests.push(window[uniqueCallback]);
- if (existingMsg) {
- if (existingMsg.type == msgType)
- logger.error('setter error: same message type posted on the same path');
- else {
- existingMsg.type = 'changed';
- existingMsg[valueProp] = value;
- }
- } else {
- var msg = { path: path, type: msgType };
- msg[valueProp] = value;
- addChangeMessage(messages, messagesHash, msg);
- }
+ script.type = 'text/javascript';
+ script.src = opts.url + (opts.url.indexOf('?') == -1 ? '?' : '&') + 'callback=' + uniqueCallback;
- if (valueIsTree(value))
- _addMessages(path, value);
+ head.appendChild(script);
+
+ return xPromise.promise;
+
+
+ function _onResult(err, result) {
+ _.spliceItem(_pendingRequests, window[uniqueCallback]);
+ try {
+ postMessage(err ? 'error' : 'success', err, result);
+ if (err) {
+ logger.error('No JSONP response or timeout');
+ postMessage('errorjsonptimeout', err);
+ }
+ callback && callback(err, result);
}
- }
+ catch(e) { var error = e; }
+ if (err) xPromise.reject(err);
+ else xPromise.resolve(result);
- function cloneTree(value) {
- return valueIsNormalObject(value)
- ? _.deepClone(value)
- : value;
- }
+ cleanUp();
+ if (!_pendingRequests.length)
+ postMessage('requestscompleted');
- function protectValue(value) {
- return ! valueIsNormalObject(value)
- ? value
- : Array.isArray(value)
- ? value.slice()
- : Object.create(value);
+ if (error) throw error;
}
- function valueIsTree(value) {
- return valueIsNormalObject(value)
- && Object.keys(value).length;
- }
- function valueIsNormalObject(value) {
- return value != null
- && typeof value == "object"
- && ! (value instanceof Date)
- && ! (value instanceof RegExp);
+ function cleanUp() {
+ clearTimeout(timeout);
+ head.removeChild(script);
+ delete window[uniqueCallback];
}
- function addBatchIdsToMessage(msg, batchId, msgId) {
- _.defineProperties(msg, {
- __batch_id: batchId,
- __msg_id: msgId
- });
+
+ function postMessage(msg, status, result) {
+ if (_messenger) request.postMessage(msg,
+ { status: status, response: result });
}
}
-/**
- * Exports `synthesize` function with the following:
- *
- * - .modelMethods.set - `set` method for Model
- * - .modelMethods.del - `del` method for Model
- * - .modelMethods.splice - `splice` method for Model
- */
-module.exports = synthesizePathMethods;
-
-var modelMethods = _.mapKeys(modelSynthesizers, function(synthesizer) {
- return _synthesize(synthesizer, '', []);
-});
+function request$file(opts, fileData, callback, progress) {
+ if (typeof opts == 'string')
+ opts = { method: 'POST', url: opts };
-synthesizePathMethods.modelMethods = modelMethods;
+ opts.method = opts.method || 'POST';
+ opts.file = true;
-},{"../../util/count":92,"../../util/logger":102,"../change_data":73,"../model_utils":77,"../path_utils":79,"dot":115,"fs":113,"mol-proto":150}],81:[function(require,module,exports){
-'use strict';
+ if (_messenger) request.postMessageSync('request', { options: opts });
-/**
- * Registries of facets and of components
- *
- * - [facets](./components/c_facets/cf_registry.js.html)
- * - [components](./components/c_registry.js.html)
- */
-var registry = module.exports = {
- facets: require('./components/c_facets/cf_registry'),
- components: require('./components/c_registry'),
- commands: require('./command/cmd_registry')
-};
+ var req = new XMLHttpRequest();
+ if (progress) req.upload.onprogress = progress;
-},{"./command/cmd_registry":12,"./components/c_facets/cf_registry":31,"./components/c_registry":33}],82:[function(require,module,exports){
-'use strict';
+ req.open(opts.method, opts.url, true);
+ setRequestHeaders(req, opts.headers);
-//
-// ###dom events constructors
+ req.timeout = opts.timeout || config.request.defaults.timeout;
+ req.onreadystatechange = req.ontimeout = req.onabort = onReady;
+ var xPromise = _createXPromise(req);
-var _ = require('mol-proto');
+ if (opts.binary)
+ req.send(fileData);
+ else {
+ var formData = new FormData();
+ formData.append('file', fileData);
+ req.send(formData);
+ }
+ _pendingRequests.push(req);
-// https://developer.mozilla.org/en-US/docs/Web/Reference/Events
+ return xPromise.promise;
-var eventTypes = {
- ClipboardEvent: ['copy', 'cut', 'paste', 'beforecopy', 'beforecut', 'beforepaste'],
- Event: ['input', 'readystatechange'],
- FocusEvent: ['focus', 'blur', 'focusin', 'focusout'],
- KeyboardEvent: ['keydown', 'keypress', 'keyup'],
- MouseEvent: ['click', 'contextmenu', 'dblclick', 'mousedown', 'mouseup',
- 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover',
- 'show' /* context menu */],
- TouchEvent: ['touchstart', 'touchend', 'touchmove', 'touchenter', 'touchleave', 'touchcancel'],
-};
+ function onReady(e) {
+ if (progress) req.upload.onprogress = undefined;
+ _onReady(req, callback, xPromise, e.type);
+ }
+}
-// mock window and event constructors for testing
-if (typeof window != 'undefined')
- var global = window;
-else {
- global = {};
- _.eachKey(eventTypes, function(eTypes, eventConstructorName) {
- var eventConstructor = _.makeFunction(eventConstructorName, 'type', 'properties',
- 'this.type = type; _.extend(this, properties);');
- global[eventConstructorName] = eventConstructor;
- });
+function request$destroy() {
+ if (_messenger) _messenger.destroy();
+ request._destroyed = true;
}
-var domEventsConstructors = {};
+function whenRequestsCompleted(callback, timeout) {
+ callback = _.once(callback);
+ if (timeout)
+ _.delay(callback, timeout, 'timeout');
-_.eachKey(eventTypes, function(eTypes, eventConstructorName) {
- eTypes.forEach(function(type) {
- if (Object.hasOwnProperty(domEventsConstructors, type))
- throw new Error('duplicate event type ' + type);
+ if (_pendingRequests.length)
+ _messenger.once('requestscompleted', callback);
+ else
+ _.defer(callback);
+}
- domEventsConstructors[type] = global[eventConstructorName];
- });
-});
+},{"../config":64,"./count":77,"milo-core":105}],88:[function(require,module,exports){
+'use strict';
-module.exports = domEventsConstructors;
-
-},{"mol-proto":150}],83:[function(require,module,exports){
-'use strict';
+var domUtils = require('../dom')
+ , containingElement = domUtils.containingElement
+ , setCaretPosition = domUtils.setCaretPosition
+ , getComponentsFromRange = domUtils.getComponentsFromRange
+ , deleteRangeWithComponents = domUtils.deleteRangeWithComponents
+ , miloCore = require('milo-core')
+ , logger = miloCore.util.logger
+ , Component = require('../../components/c_class')
+ , _ = miloCore.proto;
+module.exports = TextSelection;
-var MessageSource = require('../messenger/m_source')
- , Component = require('../components/c_class')
- , domEventsConstructors = require('./de_constrs') // TODO merge with DOMEventSource ??
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match;
-var DOMEmitterSource = _.createSubclass(MessageSource, 'DOMEmitterSource', true);
+/**
+ * Text selection class.
+ * Serves as a helper to manage current selection
+ * The object cannot be reused, if the selection changes some of its properties may contain information related to previous selection
+ *
+ * @param {Window} win window in which text selection is processed
+ */
+function TextSelection(win) {
+ if (! this instanceof TextSelection)
+ return new TextSelection(win);
+ this.window = win || window;
+ this.init();
+}
-_.extendProto(DOMEmitterSource, {
- // implementing MessageSource interface
- init: init,
- destroy: DOMEmitterSource$destroy,
- addSourceSubscriber: _.partial(sourceSubscriberMethod, 'addEventListener'),
- removeSourceSubscriber: _.partial(sourceSubscriberMethod, 'removeEventListener'),
- postMessage: DOMEmitterSource$postMessage,
- trigger: trigger,
+/**
+ * TextSelection instance method
+ * Returns selection start element
+ *
+ * @return {Element|null}
+ */
+var TextSelection$startElement =
+ _.partial(_getElement, '_startElement', 'startContainer');
- // class specific methods
- emitter: emitter,
- handleEvent: handleEvent, // event dispatcher - as defined by Event DOM API
-});
-module.exports = DOMEmitterSource;
+/**
+ * TextSelection instance method
+ * Returns selection end element
+ *
+ * @return {Element|null}
+ */
+var TextSelection$endElement =
+ _.partial(_getElement, '_endElement', 'endContainer');
-var useCapturePattern = /__capture$/
- , useCapturePostfix = '__capture';
+/**
+ * TextSelection instance method
+ * Returns selection end element
+ *
+ * @return {Element|null}
+ */
+var TextSelection$containingElement =
+ _.partial(_getElement, '_containingElement', 'commonAncestorContainer');
-// init DOM event source
-function init(hostObject, proxyMethods, messengerAPIOrClass, eventEmitter) {
- this.eventEmitter = eventEmitter;
- MessageSource.prototype.init.apply(this, arguments);
-}
+/**
+ * TextSelection instance method
+ * Returns selection start Component
+ *
+ * @return {Component}
+ */
+var TextSelection$startComponent =
+ _.partial(_getComponent, '_startComponent', 'startElement');
-function DOMEmitterSource$destroy() {
- MessageSource.prototype.destroy.apply(this, arguments);
- delete this.eventEmitter;
-}
+/**
+ * TextSelection instance method
+ * Returns selection end Component
+ *
+ * @return {Component}
+ */
+var TextSelection$endComponent =
+ _.partial(_getComponent, '_endComponent', 'endElement');
-// get DOM element of component
-function emitter() {
- return this.eventEmitter;
-}
+/**
+ * TextSelection instance method
+ * Returns selection end Component
+ *
+ * @return {Component}
+ */
+var TextSelection$containingComponent =
+ _.partial(_getComponent, '_containingComponent', 'containingElement');
-function sourceSubscriberMethod(method, eventType) {
- if (! (eventType && typeof eventType == 'string')) return;
- var capture = useCapturePattern.test(eventType);
- eventType = eventType.replace(useCapturePattern, '');
- this.emitter()[method](eventType, this, capture);
-}
+_.extendProto(TextSelection, {
+ init: TextSelection$init,
+ text: TextSelection$text,
+ textNodes: TextSelection$textNodes,
+ clear: TextSelection$clear,
+ startElement: TextSelection$startElement,
+ endElement: TextSelection$endElement,
+ containingElement: TextSelection$containingElement,
-// event dispatcher - as defined by Event DOM API
-function handleEvent(event) {
- var isCapturePhase;
- if (typeof window != 'undefined')
- isCapturePhase = event.eventPhase == window.Event.CAPTURING_PHASE;
+ startComponent: TextSelection$startComponent,
+ endComponent: TextSelection$endComponent,
+ containingComponent: TextSelection$containingComponent,
- if (isCapturePhase)
- event += useCapturePostfix;
+ containedComponents: TextSelection$containedComponents,
+ eachContainedComponent: TextSelection$eachContainedComponent,
+ del: TextSelection$del,
+ _getPostDeleteSelectionPoint: _getPostDeleteSelectionPoint,
+ _selectAfterDelete: _selectAfterDelete,
- this.dispatchMessage(event.type, event);
-}
+ getRange: TextSelection$getRange,
+ getState: TextSelection$getState,
+ getNormalizedRange: TextSelection$$getNormalizedRange,
+ getDirection: TextSelection$$getDirection
+});
-function DOMEmitterSource$postMessage(message, data) {
- this.messenger.postMessageSync(message, data);
-}
+_.extend(TextSelection, {
+ createFromRange: TextSelection$$createFromRange,
+ createFromState: TextSelection$$createFromState,
+ createStateObject: TextSelection$$createStateObject
+});
-function trigger(eventType, properties) {
- check(eventType, String);
- check(properties, Match.Optional(Object));
+/**
+ * TextSelection instance method
+ * Initializes TextSelection from the current selection
+ */
+function TextSelection$init() {
+ this.selection = this.window.getSelection();
+ if (this.selection.rangeCount)
+ this.range = this.selection.getRangeAt(0);
+ this.isCollapsed = this.selection.isCollapsed;
+}
- eventType = eventType.replace(useCapturePattern, '');
- var EventConstructor = domEventsConstructors[eventType];
- if (typeof EventConstructor != 'function')
- throw new Error('unsupported event type');
+/**
+ * TextSelection instance method
+ * Retrieves and returns selection text
+ *
+ * @return {String}
+ */
+function TextSelection$text() {
+ if (! this.range) return undefined;
- // check if it is correct
- if (typeof properties != 'undefined')
- properties.type = eventType;
+ if (! this._text)
+ this._text = this.range.toString();
- var domEvent = new EventConstructor(eventType, properties);
- var notCancelled = this.emitter().dispatchEvent(domEvent);
- return notCancelled;
+ return this._text;
}
-},{"../components/c_class":16,"../messenger/m_source":70,"../util/check":90,"./de_constrs":82,"mol-proto":150}],84:[function(require,module,exports){
-'use strict';
/**
- * `milo.mail`
- * It is an application level messenger that is an instance of Messenger class.
- *
- * At the moment, in addition to application messages that you define, you can subscribe to __domready__ message that is guaranteed to fire once,
- * even if DOM was ready at the time of the subscription.
- *
- * Messaging between frames is available via milo.mail. See [Frame facet](../components/c_facets/Frame.js.html).
+ * TextSelection instance method
+ * Retrieves and returns selection text nodes
*
- * See [Messenger](../messenger/index.js.html).
- *
-**/
+ * @return {Array[Node]}
+ */
+function TextSelection$textNodes() {
+ if (! this.range) return undefined;
+ if (! this._textNodes)
+ this._textNodes = _getTextNodes.call(this);
+ return this._textNodes;
+}
-var Messenger = require('../../messenger')
- , MailMsgAPI = require('./mail_api')
- , MailMessageSource = require('./mail_source')
- , _ = require('mol-proto');
+function TextSelection$clear() {
+ this.selection.removeAllRanges();
+}
-var miloMail = new Messenger;
-var mailMsgSource = new MailMessageSource(miloMail, { trigger: 'trigger' }, new MailMsgAPI);
+/**
+ * Retrieves text and text nodes from selection saving them on properties of object
+ *
+ * @private
+ * @param {TextSelection} this
+ */
+function _getTextNodes() {
+ // list of selected text nodes
+ var textNodes = [];
-miloMail._setMessageSource(mailMsgSource);
+ if (this.isCollapsed)
+ return textNodes;
+ // create TreeWalker to traverse the tree to select all text nodes
+ var selStart = this.range.startContainer
+ , selEnd = this.range.endContainer
+ , rangeContainer = this.range.commonAncestorContainer;
-module.exports = miloMail;
+ var treeWalker = this.window.document.createTreeWalker(rangeContainer, NodeFilter.SHOW_TEXT);
+ var node = treeWalker.currentNode = selStart;
-},{"../../messenger":67,"./mail_api":85,"./mail_source":86,"mol-proto":150}],85:[function(require,module,exports){
-'use strict';
+ // traverse DOM tree to collect all selected text nodes
+ while (node && (! inEnd || selEnd.contains(node))) {
+ textNodes.push(node);
+ var inEnd = inEnd || selEnd.contains(node);
+ node = treeWalker.nextNode();
+ }
+ return textNodes;
+}
-var MessengerAPI = require('../../messenger/m_api')
- , _ = require('mol-proto')
- , check = require('../../util/check')
- , Match = check.Match;
+/**
+ * Retrieves and returns start/end element from selection saving them on properties of object
+ *
+ * @private
+ * @param {TextSelection} this
+ * @return {Element|null}
+ */
+function _getElement(thisPropName, rangePropName) {
+ if (! this.range) return undefined;
-var MailMsgAPI = _.createSubclass(MessengerAPI, 'MailMsgAPI', true);
+ if (typeof this[thisPropName] == 'undefined')
+ this[thisPropName] = containingElement(this.range[rangePropName]);
+ return this[thisPropName];
+}
-_.extendProto(MailMsgAPI, {
- translateToSourceMessage: translateToSourceMessage,
- filterSourceMessage: filterSourceMessage
-});
+/**
+ * Retrieves and returns start/end component from selection saving them on properties of object
+ *
+ * @private
+ * @param {TextSelection} this
+ * @return {Component}
+ */
+function _getComponent(thisPropName, elMethodName) {
+ if (! this.range) return undefined;
-module.exports = MailMsgAPI;
+ if (typeof this[thisPropName] == 'undefined')
+ this[thisPropName] = Component.getContainingComponent(this[elMethodName]());
+ return this[thisPropName];
+}
-// TODO: this function should return relevant DOM event dependent on element tag
-// Can also implement beforedatachanged event to allow preventing the change
-// translateToDomEvent
-var windowMessageRegExp = /^message\:/
- , windowMessagePrefix = 'message:';
+function TextSelection$containedComponents() {
+ if (this._containedComponents)
+ return this._containedComponents;
-function translateToSourceMessage(message) {
- if (message == 'domready')
- return 'readystatechange';
- else if (windowMessageRegExp.test(message))
- return 'message';
-}
+ var components = this._containedComponents = [];
+ if (this.isCollapsed || ! this.range) return components;
-// filterDataMessage
-function filterSourceMessage(sourceMessage, msgType, msgData) {
- if (sourceMessage == 'readystatechange') {
- //return document.readyState == 'interactive';
- // return false;
- // _.defineProperty(this, '_domReadyFired', true, _.WRIT);
- return true;
- } else if (sourceMessage == 'message')
- return windowMessagePrefix + msgData.data.type == msgType;
-};
+ return getComponentsFromRange(this.range);
+}
-},{"../../messenger/m_api":68,"../../util/check":90,"mol-proto":150}],86:[function(require,module,exports){
-'use strict';
-var MessageSource = require('../../messenger/m_source')
- , domEventsConstructors = require('../de_constrs')
- , MailMessageSourceError = require('../../util/error').MailMessageSource
- , _ = require('mol-proto')
- , check = require('../../util/check')
- , Match = check.Match;
+function TextSelection$eachContainedComponent(callback, thisArg) {
+ if (this.isCollapsed || ! this.range) return;
+ var components = this.containedComponents();
-var MailMessageSource = _.createSubclass(MessageSource, 'MailMessageSource', true);
+ components.forEach(callback, thisArg);
+}
-_.extendProto(MailMessageSource, {
- // implementing MessageSource interface
- addSourceSubscriber: addSourceSubscriber,
- removeSourceSubscriber: removeSourceSubscriber,
- trigger: trigger,
+/**
+ * TextSelection instance method
+ * Deletes the current selection and all components in it
+ *
+ * @param {Boolean} selectEndContainer set to true if the end container should be selected after deletion
+ */
+function TextSelection$del(selectEndContainer) {
+ if (this.isCollapsed || ! this.range) return;
- // class specific methods
- _windowSubscriberMethod: _windowSubscriberMethod,
- handleEvent: handleEvent, // event dispatcher - as defined by Event DOM API
-});
+ var selPoint = this._getPostDeleteSelectionPoint(selectEndContainer);
+ deleteRangeWithComponents(this.range);
-module.exports = MailMessageSource;
+ this._selectAfterDelete(selPoint);
+ selPoint.node.parentNode.normalize();
+}
-function addSourceSubscriber(sourceMessage) {
- if (isReadyStateChange(sourceMessage)) {
- if (document.readyState == 'loading')
- document.addEventListener('readystatechange', this, false);
- else {
- var EventConstructor = domEventsConstructors.readystatechange;
- var domEvent = new EventConstructor('readystatechange', { target: document });
- this.dispatchMessage('readystatechange', domEvent);
- }
- } else
- this._windowSubscriberMethod('addEventListener', sourceMessage);
+function _getPostDeleteSelectionPoint(selectEndContainer) {
+ var selNode = this.range.startContainer;
+ var selOffset = this.range.startOffset;
+ if (selectEndContainer && this.range.startContainer != this.range.endContainer) {
+ selNode = this.range.endContainer;
+ selOffset = 0;
+ }
+ return { node: selNode, offset: selOffset };
}
-function removeSourceSubscriber(sourceMessage) {
- if (isReadyStateChange(sourceMessage))
- document.removeEventListener('readystatechange', this, false);
- else
- this._windowSubscriberMethod('removeEventListener', sourceMessage);
-}
+function _selectAfterDelete(selPoint) {
+ var selNode = selPoint.node
+ , selOffset = selPoint.offset;
+ if (!selNode) return;
+ if (selNode.nodeType == Node.TEXT_NODE)
+ selNode.textContent = selNode.textContent.trimRight();
+ if (!selNode.nodeValue)
+ selNode.nodeValue = '\u00A0'; //non-breaking space, \u200B for zero width space;
-function isReadyStateChange(sourceMessage) {
- return sourceMessage == 'readystatechange' && typeof document == 'object';
+ var position = selOffset > selNode.length ? selNode.length : selOffset;
+ setCaretPosition(selNode, position);
}
-function isWindowMessage(sourceMessage) {
- return sourceMessage == 'message' && typeof window == 'object';
-}
-function _windowSubscriberMethod(method, sourceMessage) {
- if (isWindowMessage(sourceMessage))
- window[method]('message', this, false);
+/**
+ * Returns selection range
+ *
+ * @return {Range}
+ */
+function TextSelection$getRange() {
+ return this.range;
}
-// event dispatcher - as defined by Event DOM API
-function handleEvent(event) {
- this.dispatchMessage(event.type, event);
+/**
+ * Stores selection window, nodes and offsets in object
+ */
+function TextSelection$getState(rootEl) {
+ var r = this.range;
+ var doc = rootEl.ownerDocument
+ , win = doc.defaultView || doc.parentWindow;
+ if (!r) return { window: win };
+ return TextSelection.createStateObject(rootEl, r.startContainer, r.startOffset, r.endContainer, r.endOffset);
}
-function trigger(msgType, data) {
- data = data || {};
- data.type = 'message:' + msgType;
-
- if (typeof window == 'object')
- window.postMessage(data, '*')
+function TextSelection$$createStateObject(rootEl, startContainer, startOffset, endContainer, endOffset) {
+ endContainer = endContainer || startContainer;
+ endOffset = endOffset || startOffset;
+ var doc = rootEl.ownerDocument
+ , win = doc.defaultView || doc.parentWindow;
+ return {
+ window: win,
+ rootEl: rootEl,
+ start: _getSelectionPointState(rootEl, startContainer, startOffset),
+ end: _getSelectionPointState(rootEl, endContainer, endOffset)
+ };
}
-},{"../../messenger/m_source":70,"../../util/check":90,"../../util/error":98,"../de_constrs":82,"mol-proto":150}],87:[function(require,module,exports){
-'use strict';
-
-var Messenger = require('../messenger')
- , DOMEmitterSource = require('./dom_source');
+function _getSelectionPointState(rootEl, node, offset) {
+ var treePath = domUtils.treePathOf(rootEl, node);
+ if (! treePath) logger.error('Selection point is outside of root element');
+ return {
+ treePath: treePath,
+ offset: offset
+ };
+}
-var windowService = new Messenger;
-var domEmitterSource = new DOMEmitterSource(windowService, { trigger: 'trigger' }, undefined, window);
-windowService._setMessageSource(domEmitterSource);
+/**
+ * Restores actual selection to the stored range
+ */
+function TextSelection$$createFromState(state) {
+ var domUtils = state.window.milo.util.dom;
+ if (state.rootEl && state.start && state.end) {
+ var startNode = _selectionNodeFromState(state.rootEl, state.start)
+ , endNode = _selectionNodeFromState(state.rootEl, state.end);
-module.exports = windowService;
+ try {
+ domUtils.setSelection(startNode, state.start.offset, endNode, state.end.offset);
+ return new TextSelection(state.window);
+ } catch(e) {
+ logger.error('Text selection: can\'t create selection', e, e.message);
+ }
+ } else {
+ domUtils.clearSelection(state.window);
+ return new TextSelection(state.window);
+ }
+}
-_.extend(windowService, {
- isTop: windowService_isTop
-});
+function _selectionNodeFromState(rootEl, pointState) {
+ var node = domUtils.getNodeAtTreePath(rootEl, pointState.treePath);
+ if (! node) logger.error('TextSelection createFromState: no node at treePath');
+ return node;
+}
-function windowService_isTop() {
- return window.top == window.self || window.__karma__;
-}
+/**
+ * Creates selection from passed range
+ *
+ * @param {Range} range
+ * @param {Boolean} backward
+ *
+ * @return {TextSelection}
+ */
+function TextSelection$$createFromRange(range, backward) {
+ var win = range.startContainer.ownerDocument.defaultView
+ , sel = win.getSelection()
+ , endRange;
-},{"../messenger":67,"./dom_source":83}],88:[function(require,module,exports){
-'use strict';
+ sel.removeAllRanges();
-require('./components/classes/View');
-require('./components/ui/Group');
-require('./components/ui/Wrapper');
-require('./components/ui/Text');
-require('./components/ui/Select');
-require('./components/ui/Input');
-require('./components/ui/InputList');
-require('./components/ui/Textarea');
-require('./components/ui/RadioGroup');
-require('./components/ui/Button');
-require('./components/ui/Hyperlink');
-require('./components/ui/List');
-require('./components/ui/ListItem');
-require('./components/ui/Time');
-require('./components/ui/Date');
-require('./components/ui/Combo');
-require('./components/ui/SuperCombo');
-require('./components/ui/ComboList');
-require('./components/ui/Image');
-require('./components/ui/DropTarget');
-require('./components/ui/FoldTree');
+ if (backward){
+ endRange = range.cloneRange();
+ endRange.collapse(false);
-require('./components/ui/bootstrap/Dropdown');
-// require('./components/ui/bootstrap/Dialog');
+ sel.addRange(endRange);
+ sel.extend(range.startContainer, range.startOffset)
+ }
+ else {
+ sel.addRange(range);
+ }
-},{"./components/classes/View":35,"./components/ui/Button":42,"./components/ui/Combo":43,"./components/ui/ComboList":44,"./components/ui/Date":45,"./components/ui/DropTarget":46,"./components/ui/FoldTree":47,"./components/ui/Group":48,"./components/ui/Hyperlink":49,"./components/ui/Image":50,"./components/ui/Input":51,"./components/ui/InputList":52,"./components/ui/List":53,"./components/ui/ListItem":54,"./components/ui/RadioGroup":55,"./components/ui/Select":56,"./components/ui/SuperCombo":57,"./components/ui/Text":58,"./components/ui/Textarea":59,"./components/ui/Time":60,"./components/ui/Wrapper":61,"./components/ui/bootstrap/Dropdown":64}],89:[function(require,module,exports){
-'use strict';
+ return new TextSelection(win);
+}
-require('./components/c_facets/Dom');
-require('./components/c_facets/Data');
-require('./components/c_facets/Frame');
-require('./components/c_facets/Events');
-require('./components/c_facets/Options');
-require('./components/c_facets/Template');
-require('./components/c_facets/Container');
-require('./components/c_facets/ModelFacet');
-require('./components/c_facets/Drag');
-require('./components/c_facets/Drop');
-require('./components/c_facets/List');
-require('./components/c_facets/Item');
-require('./components/c_facets/Transfer');
+/**
+ * Returns a normalized copy of the range
+ * If you triple click an item, the end of the range is positioned at the beginning of the NEXT node.
+ * this function returns a range with the end positioned at the end of the last textnode contained
+ * inside a component with the "editable" facet
+ *
+ * @return {range}
+ */
+function TextSelection$$getNormalizedRange(){
+ var doc = this.range.commonAncestorContainer.ownerDocument
+ , tw, previousNode
+ , newRange = this.range.cloneRange();
-},{"./components/c_facets/Container":18,"./components/c_facets/Data":19,"./components/c_facets/Dom":20,"./components/c_facets/Drag":21,"./components/c_facets/Drop":22,"./components/c_facets/Events":23,"./components/c_facets/Frame":24,"./components/c_facets/Item":25,"./components/c_facets/List":26,"./components/c_facets/ModelFacet":27,"./components/c_facets/Options":28,"./components/c_facets/Template":29,"./components/c_facets/Transfer":30}],90:[function(require,module,exports){
-'use strict';
+ if (newRange.endContainer.nodeType !== Node.TEXT_NODE) {
+ tw = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT);
+ tw.currentNode = newRange.endContainer;
+ previousNode = tw.previousNode();
+ newRange.setEnd(previousNode, previousNode.length);
+ }
+
+ return newRange;
+}
/**
- * `milo.utils.check`
- *
- * Check is a module for parameters checking extracted from [Meteor](http://docs.meteor.com/) framework.
- *
- * It allows to both document and to check parameter types in your function
- * making code both readable and stable.
- *
- *
- * ### Usage
- *```
- * var check = milo.check
- * , Match = check.Match;
- *
- * function My(name, obj, cb) {
- * // if any of checks fail an error will be thrown
- * check(name, String);
- * check(obj, Match.ObjectIncluding({ options: Object }));
- * check(cb, Function);
- *
- * // ... your code
- * }
- *```
- * See [Meteor docs](http://docs.meteor.com/#match) to see how it works
- *
- *
- * ### Patterns
- *
- * All patterns and functions described in Meteor docs work.
- *
- * Unlike in Meteor, Object pattern matches instance of any class,
- * not only plain object.
- *
- * In addition to patterns described in Meteor docs the following patterns are implemented
- *
- * * Match.__ObjectHash__(_pattern_)
- *
- * Matches an object where all properties match a given pattern
- *
- * * Match.__Subclass__(_constructor_ [, _matchThisClassToo_])
- *
- * Matches a class that is a subclass of a given class. If the second parameter
- * is true, it will also match the class itself.
- *
- * Without this pattern to check if _MySubclass_ is a subclass of _MyClass_
- * you would have to use
- *
- * check(MySubclass, Match.Where(function() {
- * return MySubclass.prototype instanceof MyClass;
- * });
+ * get the direction of a selection
*
+ * 1 forward, -1 backward, 0 no direction, undefined one of the node is detached or in a different frame
*
- * Things we explicitly do NOT support:
- * - heterogenous arrays
-**/
+ * @return {-1|0|1|undefined}
+ */
+function TextSelection$$getDirection(){
+ return domUtils.getSelectionDirection(this.selection);
+}
-var _ = require('mol-proto')
- , config = require('../config');
-var check = function (value, pattern) {
- if (config.check === false)
- return;
+},{"../../components/c_class":15,"../dom":79,"milo-core":105}],89:[function(require,module,exports){
+'use strict';
- // Record that check got called, if somebody cared.
- try {
- checkSubtree(value, pattern);
- } catch (err) {
- if ((err instanceof Match.Error) && err.path)
- err.message += " in field " + err.path;
- throw err;
- }
-};
-module.exports = check;
+var miloCore = require('milo-core')
+ , Messenger = miloCore.Messenger
+ , StorageMessageSource = require('./msg_src')
+ , config = require('../../config')
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , Match = check.Match;
-var Match = check.Match = {
- Optional: function (pattern) {
- return new Optional(pattern);
- },
- OneOf: function (/* arguments */) {
- return new OneOf(arguments);
- },
- Any: ['__any__'],
- Where: function (condition) {
- return new Where(condition);
- },
- ObjectIncluding: function (pattern) {
- return new ObjectIncluding(pattern);
- },
- // Matches only signed 32-bit integers
- Integer: ['__integer__'],
+require('./model')
- // Matches string that is a valid identifier, will not allow javascript reserved words
- IdentifierString: /^[a-z_$][0-9a-z_$]*$/i,
+module.exports = DOMStorage;
- // Matches hash (object) with values matching pattern
- ObjectHash: function(pattern) {
- return new ObjectHash(pattern);
- },
- Subclass: function(Superclass, matchSuperclassToo) {
- return new Subclass(Superclass, matchSuperclassToo);
- },
+// shared keys stored by all instances, include key prefixes
+var _storedKeys = {
+ true: {}, // session storage
+ false: {} // local storage
+};
- // XXX matchers should know how to describe themselves for errors
- Error: TypeError,
- // Meteor.makeErrorType("Match.Error", function (msg) {
- // this.message = "Match error: " + msg;
- // The path of the value that failed to match. Initially empty, this gets
- // populated by catching and rethrowing the exception as it goes back up the
- // stack.
- // E.g.: "vals[3].entity.created"
- // this.path = "";
- // If this gets sent over DDP, don't give full internal details but at least
- // provide something better than 500 Internal server error.
- // this.sanitizedError = new Meteor.Error(400, "Match failed");
- // }),
+/**
+ * DOMStorage class to simplify storage and retrieval of multiple items with types preservation to DOM storage (localStorage and sessionStorage).
+ * Types will be stored in the key created from value keys with appended `milo.config.domStorage.typeSuffix`
+ *
+ * @param {String} keyPrefix prefix that will be added to all keys followed by `milo.config.domStorage.prefixSeparator` ("/" by default).
+ * @param {Boolean} sessionOnly true to use sessionStorage. localStorage will be used by default.
+ * @param {Window} win window to work in
+ */
+function DOMStorage(keyPrefix, sessionOnly, win) {
+ if (typeof window == 'undefined') return;
+ win = win || window;
- // Tests to see if value matches pattern. Unlike check, it merely returns true
- // or false (unless an error other than Match.Error was thrown).
- test: function (value, pattern) {
- try {
- checkSubtree(value, pattern);
- return true;
- } catch (e) {
- if (e instanceof Match.Error)
- return false;
- // Rethrow other errors.
- throw e;
- }
- }
-};
+ keyPrefix = config.domStorage.root +
+ (keyPrefix
+ ? keyPrefix + config.domStorage.prefixSeparator
+ : '');
-function Optional(pattern) {
- this.pattern = pattern;
-};
+ _.defineProperties(this, {
+ keyPrefix: keyPrefix,
+ sessionOnly: !! sessionOnly,
+ window: win,
+ _storage: sessionOnly ? win.sessionStorage : win.localStorage,
+ _typeSuffix: config.domStorage.typeSuffix,
+ _keys: {}
+ }, _.WRIT);
+}
-function OneOf(choices) {
- if (choices.length == 0)
- throw new Error("Must provide at least one choice to Match.OneOf");
- this.choices = choices;
-};
-function Where(condition) {
- this.condition = condition;
-};
+_.extendProto(DOMStorage, {
+ get: DOMStorage$get,
+ set: DOMStorage$set,
+ remove: DOMStorage$remove,
+ hasItem: DOMStorage$hasItem,
+ getItem: DOMStorage$getItem,
+ setItem: DOMStorage$setItem,
+ removeItem: DOMStorage$removeItem,
+ _storageKey: DOMStorage$_storageKey,
+ _domStorageKey: DOMStorage$_domStorageKey,
+ getAllKeys: DOMStorage$getAllKeys,
+ getAllItems: DOMStorage$getAllItems,
+ createMessenger: DOMStorage$createMessenger,
+ destroy: DOMStorage$destroy
+});
-function ObjectIncluding(pattern) {
- this.pattern = pattern;
-};
-function ObjectHash(pattern) {
- this.pattern = pattern;
-};
+/**
+ * Expose Mesenger and MessageSource methods on DOMStorage
+ */
+Messenger.useWith(DOMStorage, '_messenger', Messenger.defaultMethods);
+StorageMessageSource.useWith(DOMStorage, '_messageSource', ['trigger']);
-function Subclass(Superclass, matchSuperclassToo) {
- this.Superclass = Superclass;
- this.matchSuperclass = matchSuperclassToo;
-};
-var typeofChecks = [
- [String, "string"],
- [Number, "number"],
- [Boolean, "boolean"],
- [Function, "function"],
- // While we don't allow undefined in JSON, this is good for optional
- // arguments with OneOf.
- [undefined, "undefined"]
-];
+var _sessionStorage = new DOMStorage('', true)
+ , _localStorage = new DOMStorage('', false);
-function checkSubtree(value, pattern) {
- // Match anything!
- if (pattern === Match.Any)
- return;
+var _domStorage = {
+ true: _sessionStorage,
+ false: _localStorage
+ };
- // Basic atomic types.
- // Do not match boxed objects (e.g. String, Boolean)
- for (var i = 0; i < typeofChecks.length; ++i) {
- if (pattern === typeofChecks[i][0]) {
- if (typeof value === typeofChecks[i][1])
- return;
- throw new Match.Error("Expected " + typeofChecks[i][1] + ", got " +
- typeof value);
- }
- }
- if (pattern === null) {
- if (value === null)
- return;
- throw new Match.Error("Expected null, got " + JSON.stringify(value));
- }
+_.extend(DOMStorage, {
+ registerDataType: DOMStorage$$registerDataType,
+ local: _localStorage,
+ session: _sessionStorage,
+ storage: _domStorage,
+ _storedKeys: _storedKeys // exposed for testing
+});
- // Match.Integer is special type encoded with array
- if (pattern === Match.Integer) {
- // There is no consistent and reliable way to check if variable is a 64-bit
- // integer. One of the popular solutions is to get reminder of division by 1
- // but this method fails on really large floats with big precision.
- // E.g.: 1.348192308491824e+23 % 1 === 0 in V8
- // Bitwise operators work consistantly but always cast variable to 32-bit
- // signed integer according to JavaScript specs.
- if (typeof value === 'number' && (value | 0) === value)
- return
- throw new Match.Error('Expected Integer, got '
- + (value instanceof Object ? JSON.stringify(value) : value));
- }
- if (pattern === Match.IdentifierString) {
- if (typeof value === 'string' && Match.IdentifierString.test(value)
- && _jsKeywords.indexOf(key) == -1)
- return;
- throw new Match.Error('Expected identifier string, got '
- + (value instanceof Object ? JSON.stringify(value) : value));
- }
+/**
+ * Sets data to DOM storage. `this.keyPrefix` is prepended to keys.
+ *
+ * @param {Object} data single object can be passed in which case keys will be used as keys in local storage.
+ * @param {List} arguments alternatively just the list of arguments can be passed where arguments can be sequentially used as keys and values.
+ */
+function DOMStorage$set(data) { // or arguments
+ if (typeof data == 'object')
+ _.eachKey(data, function(value, key) {
+ this.setItem(key, value);
+ }, this);
+ else {
+ var argsLen = arguments.length;
+ if (argsLen % 2)
+ throw new DomStorageError('DOMStorage: set should have even number of arguments or object');
- // "Object" is shorthand for Match.ObjectIncluding({});
- if (pattern === Object)
- pattern = Match.ObjectIncluding({});
+ for (var i = 0; i < argsLen; i++) {
+ var key = arguments[i]
+ , value = arguments[++i];
- // Array (checked AFTER Any, which is implemented as an Array).
- if (pattern instanceof Array) {
- if (pattern.length !== 1)
- throw Error("Bad pattern: arrays must have one type element" +
- JSON.stringify(pattern));
- if (!Array.isArray(value)) {
- throw new Match.Error("Expected array, got " + JSON.stringify(value));
+ this.setItem(key, value);
}
-
- value.forEach(function (valueElement, index) {
- try {
- checkSubtree(valueElement, pattern[0]);
- } catch (err) {
- if (err instanceof Match.Error) {
- err.path = _prependPath(index, err.path);
- }
- throw err;
- }
- });
- return;
}
+}
- // Arbitrary validation checks. The condition can return false or throw a
- // Match.Error (ie, it can internally use check()) to fail.
- if (pattern instanceof Where) {
- if (pattern.condition(value))
- return;
- // XXX this error is terrible
- throw new Match.Error("Failed Match.Where validation");
- }
+/**
+ * Gets data from DOM storage. `this.keyPrefix` is prepended to passed keys, but returned object will have keys without root keys.
+ *
+ * @param {List} arguments keys can be passed as strings or arrays of strings
+ * @returns {Object}
+ */
+function DOMStorage$get() { // , ... arguments
+ var data = {};
+ _.deepForEach(arguments, function(key) {
+ data[key] = this.getItem(key);
+ }, this);
+ return data;
+}
- if (pattern instanceof Optional)
- pattern = Match.OneOf(undefined, pattern.pattern);
- if (pattern instanceof OneOf) {
- for (var i = 0; i < pattern.choices.length; ++i) {
- try {
- checkSubtree(value, pattern.choices[i]);
- // No error? Yay, return.
- return;
- } catch (err) {
- // Other errors should be thrown. Match errors just mean try another
- // choice.
- if (!(err instanceof Match.Error))
- throw err;
- }
- }
- // XXX this error is terrible
- throw new Match.Error("Failed Match.OneOf or Match.Optional validation");
- }
+/**
+ * Removes keys from DOM storage. `this.keyPrefix` is prepended to passed keys.
+ *
+ * @param {List} arguments keys can be passed as strings or arrays of strings
+ */
+function DOMStorage$remove() { //, ... arguments
+ _.deepForEach(arguments, function(key) {
+ this.removeItem(key);
+ }, this);
+}
- // A function that isn't something we special-case is assumed to be a
- // constructor.
- if (pattern instanceof Function) {
- if (value instanceof pattern)
- return;
- // XXX what if .name isn't defined
- throw new Match.Error("Expected " + pattern.constructor.name);
- }
- var unknownKeysAllowed = false;
- if (pattern instanceof ObjectIncluding) {
- unknownKeysAllowed = true;
- pattern = pattern.pattern;
- }
+/**
+ * Check for presence of single item in DOM storage. `this.keyPrefix` is prepended to passed key.
+ *
+ * @param {String} key
+ * @return {Boolean}
+ */
+function DOMStorage$hasItem(key) {
+ var pKey = this._storageKey(key);
+ return this._storage.getItem(pKey) != null;
+}
- if (pattern instanceof ObjectHash) {
- var keyPattern = pattern.pattern;
- var emptyHash = true;
- for (var key in value) {
- emptyHash = false;
- check(value[key], keyPattern);
- }
- if (emptyHash)
- throw new Match.Error("Expected " + pattern.constructor.name);
- return;
- }
- if (pattern instanceof Subclass) {
- var Superclass = pattern.Superclass;
- if (pattern.matchSuperclass && value == Superclass)
- return;
- if (! (value.prototype instanceof Superclass))
- throw new Match.Error("Expected " + pattern.constructor.name + " of " + Superclass.name);
- return;
+/**
+ * Gets single item from DOM storage prepending `this.keyPrefix` to passed key.
+ * Reads type of the originally stored value from `key + this._typeSuffix` and converts data to the original type.
+ *
+ * @param {String} key
+ * @return {Any}
+ */
+function DOMStorage$getItem(key) {
+ var pKey = this._storageKey(key);
+ var dataType = _getKeyDataType.call(this, pKey);
+ var valueStr = this._storage.getItem(pKey);
+ var value = _parseData(valueStr, dataType);
+ return value;
+}
+
+
+/**
+ * Sets single item to DOM storage prepending `this.keyPrefix` to passed key.
+ * Stores type of the stored value to `key + this._typeSuffix`.
+ *
+ * @param {String} key
+ * @return {Any}
+ */
+function DOMStorage$setItem(key, value) {
+ var pKey = this._storageKey(key);
+ var dataType = _setKeyDataType.call(this, pKey, value);
+ var valueStr = _serializeData(value, dataType);
+ try {
+ this._storage.setItem(pKey, valueStr);
+ } catch(e) {
+ if (e.name == 'QuotaExceededError') {
+ var cfg = config.domStorage.quotaExceeded;
+ if (cfg.message)
+ milo.mail.postMessage('quotaexceedederror', value);
+ if (cfg.throwError)
+ throw e;
+ } else
+ throw e;
}
+ this._keys[key] = true;
+ _domStorage[this.sessionOnly]._keys[pKey] = true;
+}
- if (typeof pattern !== "object")
- throw Error("Bad pattern: unknown pattern type");
- // An object, with required and optional keys. Note that this does NOT do
- // structural matches against objects of special types that happen to match
- // the pattern: this really needs to be a plain old {Object}!
- if (typeof value !== 'object')
- throw new Match.Error("Expected object, got " + typeof value);
- if (value === null)
- throw new Match.Error("Expected object, got null");
+/**
+ * Removes single item from DOM storage prepending `this.keyPrefix` to passed key.
+ * Type of the stored value (in `key + this._typeSuffix` key) is also removed.
+ *
+ * @param {String} key
+ * @return {Any}
+ */
+function DOMStorage$removeItem(key) {
+ var pKey = this._storageKey(key);
+ this._storage.removeItem(pKey);
+ _removeKeyDataType.call(this, pKey)
+ delete this._keys[key];
+ delete _domStorage[this.sessionOnly]._keys[pKey];
+}
- var requiredPatterns = {};
- var optionalPatterns = {};
- _.eachKey(pattern, function(subPattern, key) {
- if (pattern[key] instanceof Optional)
- optionalPatterns[key] = pattern[key].pattern;
- else
- requiredPatterns[key] = pattern[key];
- }, this, true);
+/**
+ * Returns the array of all keys stored by this instance of DOMStorage
+ *
+ * @return {Array}
+ */
+function DOMStorage$getAllKeys() {
+ var storedKeys = Object.keys(this._keys);
+ var keysInStorage = storedKeys.filter(function(key) {
+ if (this.hasItem(key)) return true;
+ else delete this._keys[key];
+ }, this);
+ return keysInStorage;
+}
- _.eachKey(value, function(subValue, key) {
- var subValue = value[key];
- try {
- if (requiredPatterns.hasOwnProperty(key)) {
- checkSubtree(subValue, requiredPatterns[key]);
- delete requiredPatterns[key];
- } else if (optionalPatterns.hasOwnProperty(key)) {
- checkSubtree(subValue, optionalPatterns[key]);
- } else {
- if (!unknownKeysAllowed)
- throw new Match.Error("Unknown key");
- }
- } catch (err) {
- if (err instanceof Match.Error)
- err.path = _prependPath(key, err.path);
- throw err;
- }
- }, this, true);
-
- _.eachKey(requiredPatterns, function(value, key) {
- throw new Match.Error("Missing key '" + key + "'");
- }, this, true);
-};
-
-
-var _jsKeywords = ["do", "if", "in", "for", "let", "new", "try", "var", "case",
- "else", "enum", "eval", "false", "null", "this", "true", "void", "with",
- "break", "catch", "class", "const", "super", "throw", "while", "yield",
- "delete", "export", "import", "public", "return", "static", "switch",
- "typeof", "default", "extends", "finally", "package", "private", "continue",
- "debugger", "function", "arguments", "interface", "protected", "implements",
- "instanceof"];
-
-// Assumes the base of path is already escaped properly
-// returns key + base
-function _prependPath(key, base) {
- if ((typeof key) === "number" || key.match(/^[0-9]+$/))
- key = "[" + key + "]";
- else if (!key.match(Match.IdentifierString) || _jsKeywords.indexOf(key) != -1)
- key = JSON.stringify([key]);
-
- if (base && base[0] !== "[")
- return key + '.' + base;
- return key + base;
-};
-
-},{"../config":65,"mol-proto":150}],91:[function(require,module,exports){
-'use strict';
-
-var count = require('./count')
- , config = require('../config')
- , prefix = config.componentPrefix;
-
-
-module.exports = componentName;
-
-
-function componentName() {
- return prefix + count();
-}
-
-},{"../config":65,"./count":92}],92:[function(require,module,exports){
-'use strict';
-
-var timestamp = Date.now()
- , count = ''
- , uniqueID = '' + timestamp;
-function uniqueCount() {
- var newTimestamp = Date.now();
- uniqueID = '' + newTimestamp;
- if (timestamp == newTimestamp) {
- count = count === '' ? 0 : count + 1;
- uniqueID += '_' + count;
- } else {
- timestamp = newTimestamp;
- count = '';
- }
-
- return uniqueID;
-}
-
-uniqueCount.get = function() {
- return uniqueID;
+/**
+ * Returns the map with all keys and values (deserialized) stored using this instance of DOMStorage
+ *
+ * @return {Object}
+ */
+function DOMStorage$getAllItems() {
+ return this.get(this.getAllKeys());
}
-module.exports = uniqueCount;
-
-},{}],93:[function(require,module,exports){
-'use strict';
-
-module.exports = createComponentClass;
/**
- * Utility function which creates and registers new milo component. The component created will have
- * a reference to the super class used in its creation (Accessable using .super).
+ * Returns prefixed key for DOM storage for given unprefixed key.
*
- * @param {string} config.className - The name of the new component
- * @param {string} ['Component'] config.superClassName - The name of an existing component to be used as the new component's super class
- * @param {object=} config.facets - Facet configuration (Hash of facet name {string} to config {object})
- * @param {object=} config.methods - Methods of the new component (Hash of function name {string} to function {function})
- * @param {object=} config.staticMethods - Static methods of the new component (Hash of function name {string} to function {function})
+ * @param {String} key
+ * @return {String}
*/
-function createComponentClass(config) {
- var componentRegistry = milo.registry.components;
- var SuperClass = componentRegistry.get(config.superClassName || 'Component');
- var ComponentClass = SuperClass.createComponentClass(config.className, config.facets);
-
- if(config.methods) {
- _.extendProto(ComponentClass, config.methods);
- }
-
- if(config.staticMethods) {
- if(config.staticMethods.super !== undefined) throw '\'super\' is a reserved keyword';
-
- _.extend(ComponentClass, config.staticMethods);
- }
-
- ComponentClass.super = SuperClass.prototype;
-
- componentRegistry.add(ComponentClass);
-
- return ComponentClass;
+function DOMStorage$_storageKey(key) {
+ return this.keyPrefix + key;
}
-},{}],94:[function(require,module,exports){
-'use strict';
-
-
-var config = require('../config')
- , _ = require('mol-proto')
- , logger = require('./logger');
-
-var domUtils = {
- children: children,
- filterNodeListByType: filterNodeListByType,
- containingElement: containingElement,
- selectElementContents: selectElementContents,
- selectElementText: selectElementText,
- getElementOffset: getElementOffset,
- setCaretPosition: setCaretPosition,
- getSelectionDirection: getSelectionDirection,
- setSelection: setSelection,
- clearSelection: clearSelection,
- removeElement: removeElement,
- unwrapElement: unwrapElement,
- wrapInElement: wrapInElement,
- detachComponent: detachComponent,
- firstTextNode: firstTextNode,
- lastTextNode: lastTextNode,
- trimNodeRight: trimNodeRight,
- trimNodeLeft: trimNodeLeft,
- stripHtml: stripHtml,
- htmlEntities: htmlEntities,
- walkTree: walkTree,
- createTreeWalker: createTreeWalker,
-
- treePathOf: treePathOf,
- getNodeAtTreePath: getNodeAtTreePath,
- insertAtTreePath: insertAtTreePath,
- isTreePathBefore: isTreePathBefore,
-
- getNodeWindow: getNodeWindow,
-
- getComponentsFromRange: getComponentsFromRange,
- deleteRangeWithComponents: deleteRangeWithComponents,
- forEachNodesInRange: forEachNodesInRange,
- areRangesEqual: areRangesEqual,
-
- addDebugPoint: addDebugPoint
-};
-
-module.exports = domUtils;
/**
- * Returns the list of element children of DOM element
+ * Returns unprefixed key to be used with this instance of DOMStorage fir given actual key in storage
+ * If key has different prefix from the keyPrefix returns undefined
*
- * @param {Element} el element to return the children of (only DOM elements)
- * @return {Array[Element]}
+ * @param {String} storageKey actual key in local/session storage
+ * @return {String}
*/
- function children(el) {
- return filterNodeListByType(el.childNodes, Node.ELEMENT_NODE);
- }
+function DOMStorage$_domStorageKey(storageKey) {
+ if (storageKey.indexOf(this._typeSuffix) >= 0) return;
+ return _.unPrefix(storageKey, this.keyPrefix);
+}
/**
- * Filters the list of nodes by type
+ * Gets originally stored data type for given (prefixed) `key`.
*
- * @param {NodeList} nodeList the list of nodes, for example childNodes property of DOM element
- * @param {Integer} nodeType an integer constant [defined by DOM API](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType), e.g. `Node.ELEMENT_NODE` or `Node.TEXT_NODE`
- * @return {Array[Node]}
+ * @param {String} pKey prefixed key of stored value
+ * @return {String}
*/
-function filterNodeListByType(nodeList, nodeType) {
- return _.filter(nodeList, function (node) {
- return node.nodeType == nodeType;
- });
+function _getKeyDataType(pKey) {
+ pKey = _dataTypeKey.call(this, pKey);
+ return this._storage.getItem(pKey);
}
/**
- * Find nearest parent element for node.
- * If node is an element, it will be returned.
+ * Stores data type for given (prefixed) `key` and `value`.
+ * Returns data type for `value`.
*
- * @param {Node} node
- * @return {Element|null}
+ * @param {String} pKey prefixed key of stored value
+ * @param {Any} value
+ * @return {String}
*/
-function containingElement(node) {
- while (node) {
- if (node.nodeType == Node.ELEMENT_NODE)
- return node;
- node = node.parentNode;
- }
- return null;
+function _setKeyDataType(pKey, value) {
+ var dataType = _getValueType(value);
+ pKey = _dataTypeKey.call(this, pKey);
+ this._storage.setItem(pKey, dataType);
+ return dataType;
}
/**
- * Selects inner contents of DOM element
+ * Removes stored data type for given (prefixed) `key`.
*
- * @param {Element} el DOM element
+ * @param {String} pKey prefixed key of stored value
*/
-function selectElementContents(el) {
- var doc = el.ownerDocument;
- if (! doc) return logger.error('selectElementContents: element has no document');
- var range = doc.createRange();
- range.selectNodeContents(el);
- var win = getNodeWindow(el)
- , sel = win.getSelection();
- sel.removeAllRanges();
- sel.addRange(range);
+function _removeKeyDataType(pKey) {
+ pKey = _dataTypeKey.call(this, pKey);
+ this._storage.removeItem(pKey);
}
/**
- * Selects text inside element
- * @param {Element} el
+ * Returns the key to store data type for given (prefixed) `key`.
+ *
+ * @param {String} pKey prefixed key of stored value
+ * @return {String}
*/
-function selectElementText(el) {
- var fromNode = firstTextNode(el)
- , toNode = lastTextNode(el);
-
- if (fromNode && toNode)
- setSelection(fromNode, 0, toNode, toNode.textContent.length);
+function _dataTypeKey(pKey) {
+ return pKey + this._typeSuffix;
}
/**
- * Sets the caret position to the position in the node
- *
- * @param {Node} node DOM node
- * @param {Number} pos caret position
+ * Returns type of value as string. Class name returned for objects ('null' for null).
+ * @param {Any} value
+ * @return {String}
*/
-function setCaretPosition(node, pos) {
- var doc = node.ownerDocument;
- if (! doc) return logger.error('setCaretPosition: element has no document');
- var range = doc.createRange();
- range.setStart(node, pos);
- var win = getNodeWindow(node)
- , sel = win.getSelection();
- sel.removeAllRanges();
- sel.addRange(range);
+function _getValueType(value) {
+ var valueType = typeof value
+ , className = value && value.constructor.name
+ , dataType = valuesDataTypes[className];
+ return dataType || (
+ valueType != 'object'
+ ? valueType
+ : value == null
+ ? 'null'
+ : value.constructor.name);
+}
+var valuesDataTypes = {
+ // can be registered with `registerDataType`
}
+
/**
- * get the direction of a selection
- *
- * 1 forward, -1 backward, 0 no direction, undefined one of the node is detached or in a different frame
+ * Serializes value to be stored in DOM storage.
*
- * @param {sel} a selection object
- * @return {-1|0|1|undefined}
+ * @param {Any} value value to be serialized
+ * @param {String} valueType optional data type to define serializer, _getValueType is used if not passed.
+ * @return {String}
*/
-function getSelectionDirection(sel){
- return _getDirection(sel.anchorNode, sel.anchorOffset, sel.focusNode, sel.focusOffset);
+function _serializeData(value, valueType) {
+ valueType = valueType || _getValueType(value);
+ var serializer = dataSerializers[valueType];
+ return serializer
+ ? serializer(value, valueType)
+ : value && value.toString == Object.prototype.toString
+ ? JSON.stringify(value)
+ : '' + value;
+}
+var dataSerializers = {
+ 'Array': JSON.stringify
}
-function _getDirection(fromNode, startOffset, toNode, endOffset){
- var docPosition = fromNode.compareDocumentPosition(toNode);
- if (docPosition & Node.DOCUMENT_POSITION_FOLLOWING){
- return 1;
- }
- else if (docPosition & Node.DOCUMENT_POSITION_PRECEDING){
- return -1;
- }
- else if (fromNode == toNode){
- if (startOffset < endOffset){
- return 1;
- }
- else if (startOffset > endOffset){
- return -1;
- }
- else {
- return 0;
- }
- }
+
+/**
+ * Parses string retrieved from DOM storage.
+ *
+ * @param {String} valueStr
+ * @param {String} valueType data type that defines parser. Original sring will be returned if parser is not defined.
+ * @return {Any}
+ */
+function _parseData(valueStr, valueType) {
+ var parser = dataParsers[valueType];
+ return parser
+ ? parser(valueStr, valueType)
+ : valueStr;
}
+var dataParsers = {
+ Object: _.jsonParse,
+ Array: _.jsonParse,
+ Date: function(valStr) { return new Date(valStr); },
+ boolean: function(valStr) { return valStr == 'true'; },
+ number: Number,
+ function: _.toFunction,
+ RegExp: _.toRegExp
+};
+
/**
- * Selects a range in a document
+ * Registers data type to be saved in DOM storage. Class name can be used or result of `typeof` operator for non-objects to override default conversions.
*
- * @param {Node} fromNode DOM node to start selection in
- * @param {Number} startOffset
- * @param {Node} toNode DOM node to end selection in
- * @param {Number} endOffset
+ * @param {String} valueType class (constructor) name or the string returned by typeof.
+ * @param {Function} serializer optional serializer for this type
+ * @param {Function} parser optional parser for this type
+ * @param {[String]} storeAsDataType optional name of stored data type if different from valueType
*/
-function setSelection(fromNode, startOffset, toNode, endOffset) {
- var doc = fromNode.ownerDocument;
- if (! doc) return logger('setCaretPosition: element has no document');
- var backward = _getDirection(fromNode, startOffset, toNode, endOffset) == -1;
- var range = doc.createRange();
- var container, originalContentEditable;
- // does not work in non contentEditable items
+function DOMStorage$$registerDataType(valueType, serializer, parser, storeAsDataType) {
+ if (serializer) dataSerializers[valueType] = serializer;
+ if (parser) dataParsers[valueType] = parser;
+ valuesDataTypes[valueType] = storeAsDataType || valueType;
+}
- var win = getNodeWindow(fromNode)
- , sel = win.getSelection();
+function DOMStorage$createMessenger() {
+ var storageMessageSource = new StorageMessageSource(this);
+ var messenger = new Messenger(this, undefined, storageMessageSource);
+ _.defineProperties(this, {
+ _messenger: messenger,
+ _messageSource: storageMessageSource
+ }, _.WRIT);
+}
- if (backward){
- range.setStart(toNode, endOffset);
- range.setEnd(fromNode, startOffset);
- range.collapse(false);
- }
- else {
- range.setStart(fromNode, startOffset);
- range.setEnd(toNode, endOffset);
- }
- container = range.commonAncestorContainer == Node.ELEMENT_NODE ?
- range.commonAncestorContainer :
- range.commonAncestorContainer.parentElement;
+function DOMStorage$destroy() {
+ this._storage = undefined;
+ this.window = undefined;
+ if (this._messenger) this._messenger.destroy();
+ this._destroyed = true;
+}
- if (!container.isContentEditable){
- originalContentEditable = container.contentEditable; // false or inherit
- container.contentEditable = "true";
- }
+},{"../../config":64,"./model":90,"./msg_src":91,"milo-core":105}],90:[function(require,module,exports){
+'use strict';
- sel.removeAllRanges();
- sel.addRange(range);
+var miloCore = require('milo-core')
+ , Model = miloCore.Model
+ , _ = miloCore.proto;
- if (backward){
- sel.extend(toNode, endOffset);
- }
+Model.registerWithDOMStorage = Model$$registerWithDOMStorage;
- if (originalContentEditable){
- // restoring contentEditable
- container.contentEditable = originalContentEditable;
- }
+
+function Model$$registerWithDOMStorage() {
+ var DOMStorage = require('./index');
+ DOMStorage.registerDataType('Model', Model_domStorageSerializer, Model_domStorageParser);
+ DOMStorage.registerDataType('ModelPath', Model_domStorageSerializer, Model_domStorageParser, 'Model');
}
-/**
- * Clears selection in a given window
- * @param {Window} win
- */
-function clearSelection(win) {
- win = win || window;
- var sel = win.getSelection();
- sel.removeAllRanges();
+
+function Model_domStorageSerializer(value) {
+ var data = value.get();
+ return JSON.stringify(data);
}
-/**
- * Calculates an element's total top and left offset from the document edge.
- *
- * @param {Element} el the element for which position needs to be returned
- * @param {includeBorder} if is to include the border width
- * @return {Object} vector object with properties topOffset and leftOffset
- */
-function getElementOffset(el, includeBorder) {
- var yPos, xPos;
+function Model_domStorageParser(valueStr) {
+ var data = _.jsonParse(valueStr);
+ return new Model(data);
+}
- yPos = el.offsetTop;
- xPos = el.offsetLeft;
- el = el.offsetParent;
+},{"./index":89,"milo-core":105}],91:[function(require,module,exports){
+'use strict';
- while (el) {
- yPos += el.offsetTop + getBorder(el, 'Height', includeBorder);
- xPos += el.offsetLeft + getBorder(el, 'Width', includeBorder);
- el = el.offsetParent;
- }
- return { topOffset: yPos, leftOffset: xPos };
-}
+var miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
+ , _ = miloCore.proto
+ , config = require('../../config')
+ , miloCount = require('../../util/count');
+var StorageMessageSource = _.createSubclass(MessageSource, 'StorageMessageSource', true);
-function getBorder(el, type, includeBorder) {
- if (includeBorder) {
- var side = (type == 'Height') ? 'top' : 'left',
- styles = window.getComputedStyle(el),
- sideValue = parseInt(styles.getPropertyValue('border-' + side + '-width'), 10);
- if (sideValue) return sideValue;
- }
- return 0;
-}
+_.extendProto(StorageMessageSource, {
+ // implementing MessageSource interface
+ init: init,
+ addSourceSubscriber: StorageMessageSource$addSourceSubscriber,
+ removeSourceSubscriber: StorageMessageSource$removeSourceSubscriber,
+ postMessage: StorageMessageSource$postMessage,
+ trigger: StorageMessageSource$trigger,
+
+ //class specific methods
+ handleEvent: handleEvent // event dispatcher - as defined by Event DOM API
+});
+module.exports = StorageMessageSource;
-/**
- * Removes element from the document
- *
- * @param {Element} el the element to be removed
- */
-function removeElement(el) {
- var parent = el.parentNode;
- if (parent){
- parent.removeChild(el);
- parent.normalize();
- }
+
+function init(hostObject, proxyMethods, messengerAPIOrClass) {
+ if (hostObject.constructor.name != 'DOMStorage')
+ throw new Error('hostObject should be an instance of DOMStorage');
+ this.storage = hostObject;
+ this.messageKey = config.domStorage.messageKey;
+ this.window = hostObject.window;
+ MessageSource.prototype.init.apply(this, arguments);
}
-/**
- * Returns the first child text node of an element
- *
- * @param {Element|Node} node the node to be searched, if the node is text node we return the node.
- * @return {TextNode}
- */
-function firstTextNode(node) {
- if (node.nodeType == Node.TEXT_NODE) return node;
- var treeWalker = createTreeWalker(node, NodeFilter.SHOW_TEXT);
- return treeWalker.firstChild();
+function StorageMessageSource$addSourceSubscriber(sourceMessage) {
+ this.window.addEventListener('storage', this, false);
}
-/**
- * Returns the last child text node of an element
- *
- * @param {Element|Node} node the node to be searched, if the node is text node we return the node.
- * @return {TextNode}
- */
-function lastTextNode(node) {
- if (node.nodeType == Node.TEXT_NODE) return node;
- var treeWalker = createTreeWalker(node, NodeFilter.SHOW_TEXT);
- return treeWalker.lastChild();
+function StorageMessageSource$removeSourceSubscriber(sourceMessage) {
+ this.window.removeEventListener('storage', this, false);
}
-/**
- * Removes element from the document putting its children in its place
- *
- * @param {Element} el the element to be "unwrapped"
- */
-function unwrapElement(el) {
- var parent = el.parentNode;
-
- if (parent) {
- var frag = document.createDocumentFragment();
- // must be copied to avoid iterating a mutating list of childNodes
- var children = _.slice(el.childNodes);
- children.forEach(frag.appendChild, frag);
- parent.replaceChild(frag, el);
- parent.normalize();
- }
+function StorageMessageSource$postMessage(message, data) {
+ this.messenger.postMessageSync(message, data);
}
-/**
- * Wraps an element in another element
- *
- * @param {Element} wrapIntoEl
- * @param {Element} el
- */
-function wrapInElement(wrapIntoEl, el) {
- var parent = el.parentNode;
-
- if (parent) {
- parent.insertBefore(wrapIntoEl, el);
- wrapIntoEl.appendChild(el);
- }
+function StorageMessageSource$trigger(msgType, data) {
+ var key = this.messageKey + msgType;
+ data = data || {};
+ data[config.domStorage.messageTimestamp] = miloCount();
+ _.deferMethod(this.storage, 'setItem', key, data);
}
-/**
- * Trims a text node of trailing spaces, and returns true if a trim was performed.
- *
- * @param {TextNode} node
- * @return {Boolean}
- */
-function trimNodeRight(node) {
- return _trimNode(node, 'trimRight');
+function handleEvent(event) {
+ if (event.storageArea != this.storage._storage) return;
+ var key = this.storage._domStorageKey(event.key); if (! key) return;
+ var msgType = _.unPrefix(key, this.messageKey); if (! msgType) return;
+ var data = this.storage.getItem(key); if (! data) return;
+ this.dispatchMessage(msgType, data);
}
+},{"../../config":64,"../../util/count":77,"milo-core":105}],92:[function(require,module,exports){
+'use strict';
/**
- * Trims a text node of leading spaces, and returns true if a trim was performed.
- *
- * @param {TextNode} node
- * @return {Boolean}
- */
-function trimNodeLeft(node) {
- return _trimNode(node, 'trimLeft');
-}
+ * `milo.util.websocket`
+**/
-function _trimNode(node, methodName) {
- var len = node.length;
- node.textContent = node.textContent[methodName]();
- return len !== node.length;
-}
+var Messenger = require('milo-core').Messenger
+ , WSMessageSource = require('./msg_src')
+ , WSMsgAPI = require('./msg_api');
-/**
- * Removes the reference to component from element
- *
- * @param {Element} el
- */
-function detachComponent(el) {
- delete el[config.componentRef];
+function websocket() {
+ var wsMessenger = new Messenger;
+ var wsMsgSource = new WSMessageSource(wsMessenger, { send: 'trigger', connect: 'connect' }, new WSMsgAPI);
+ wsMessenger._setMessageSource(wsMsgSource);
+ return wsMessenger;
}
-/**
- * Retrieves the content of a html string
- * @param {String} str Any string
- * @return {String} returns the string cleaned of any html content.
- */
-function stripHtml(str) {
- var div = document.createElement('DIV');
- div.innerHTML = str;
- return div.textContent || '';
-}
+module.exports = websocket;
+},{"./msg_api":93,"./msg_src":94,"milo-core":105}],93:[function(require,module,exports){
+'use strict';
-/**
- * Convenience wrapper for native TreeWalker that automatically walks the tree and calls an iterator function.
- * This will not iterate the root element.
- * @param {HTMLElement} root The containing root element to be walked. Will not be iterated.
- * @param {NodeFiler} filter A NodeFilter constant, see https://developer.mozilla.org/en/docs/Web/API/TreeWalker
- * @param {Function} iterator A function to be called on each node. Returning 'false' will break.
- * @param {Object} context An optional context to passed, defaults to root.
- */
-function walkTree(root, filter, iterator, context) {
- var tw = document.createTreeWalker(root, filter);
- while(tw.nextNode()) {
- var result = iterator.call(context || root, tw.currentNode);
- if (result === false) break;
- }
-}
+var miloCore = require('milo-core')
+ , MessengerAPI = miloCore.classes.MessengerAPI
+ , _ = miloCore.proto
+ , check = miloCore.util.check
+ , Match = check.Match;
-/**
- * Returns array of child indexes of element path inside root element in DOM tree using breadth first tree traversal.
- * Returns undefined if the element is not inside root element, 0 if the root element itself is passed.
- *
- * @param {Element} rootEl element to search
- * @param {Element} el element to find the index of
- * @return {Array[Number]}
- */
-function treePathOf(rootEl, el) {
- if (! (rootEl && rootEl.contains(el))) return;
+var WSMsgAPI = _.createSubclass(MessengerAPI, 'WSMsgAPI', true);
- var treePath = []
- , node = rootEl;
- while (node != el) {
- var nodeIndex = _.findIndex(node.childNodes, containsEl);
- treePath.push(nodeIndex);
- node = node.childNodes[nodeIndex];
- }
+_.extendProto(WSMsgAPI, {
+ translateToSourceMessage: translateToSourceMessage,
+ filterSourceMessage: filterSourceMessage,
+ createInternalData: createInternalData
+});
- return treePath;
+module.exports = WSMsgAPI;
- function containsEl(child) {
- return child.contains(el);
+
+var SOCKET_MESSAGES = ['open', 'close', 'error', 'message'];
+
+function translateToSourceMessage(message) {
+ return SOCKET_MESSAGES.indexOf(message) >= 0
+ ? message
+ : 'message';
+}
+
+
+function filterSourceMessage(sourceMessage, message, msgData) {
+ if (SOCKET_MESSAGES.indexOf(message) >= 0) return true; // internal message is one of external messages
+ if (sourceMessage == 'message') {
+ var msgType = msgData && msgData.type;
+ return msgType == message; // type equals internal message
}
+};
+
+
+function createInternalData(sourceMessage, message, event) {
+ var internalData = sourceMessage == 'message'
+ ? _.jsonParse(event.data) || event.data
+ : event;
+ return internalData;
}
+},{"milo-core":105}],94:[function(require,module,exports){
+'use strict';
-/**
- * Returns element at given tree path
- *
- * @param {Element} rootEl
- * @param {Array[Number]} treePath
- * @param {Boolean} nearest return nearest possible node if exact node does not exist
- * @return {Node}
- */
-function getNodeAtTreePath(rootEl, treePath, nearest) {
- if (!treePath) return;
- var len = treePath.length;
- if (len === 0) return rootEl;
+var miloCore = require('milo-core')
+ , MessageSource = miloCore.classes.MessageSource
+ , _ = miloCore.proto
+ , logger = miloCore.util.logger
+ , uniqueId = require('../../util/count')
+ , config = require('../../config')
+ , check = miloCore.util.check
+ , Match = check.Match;
- var node = rootEl;
- for (var i = 0; i < len; i++) {
- var children = node.childNodes;
- if (! children) {
- if (! nearest) node = undefined;
- break;
- }
- var childIndex = treePath[i]
- , child = children[childIndex];
- if (! child) {
- node = nearest
- ? children[children.length - 1]
- : undefined;
- break;
- }
- node = child;
- }
+var WSMessageSource = _.createSubclass(MessageSource, 'WSMessageSource', true);
- return node;
-}
+_.extendProto(WSMessageSource, {
+ // implementing MessageSource interface
+ addSourceSubscriber: addSourceSubscriber,
+ removeSourceSubscriber: removeSourceSubscriber,
+
+ // class specific methods
+ handleEvent: WSMessageSource$handleEvent,
+ connect: WSMessageSource$connect,
+ trigger: WSMessageSource$trigger
+});
-/**
- * Inserts an element inside root at a given path in tree (that has the same meaning as the index returned by `treePathOf` function). If element is already in the root's tree, it will be removed first and then moved to the passed treeIndex
- * Insertion at index 0 is not possible and will return undefined as it would mean replacing the root element.
- *
- * @param {Element} rootEl element into which to insert
- * @param {Number} treeIndex index in DOM tree inside root element (see treePathOf)
- * @param {Element} el element to be inserted
- * @return {Boolean} true if was successfully inserted
- */
-function insertAtTreePath(rootEl, treePath, el, nearest) {
- var toNormalize = el.nodeType == Node.TEXT_NODE;
- if (rootEl.contains(el))
- removeElement(el); // can't use removeChild as rootEl here is not an immediate parent
- if (treePath.length == 0) return;
+module.exports = WSMessageSource;
- var parent = getNodeAtTreePath(rootEl, treePath.slice(0, -1), nearest)
- , children = parent.childNodes;
- if (! children) {
- if (nearest) {
- parent = parent.parentNode;
- children = parent.childNodes;
- } else return;
- }
+function WSMessageSource$connect(options) {
+ this._options = options = options || {};
- var childIndex = treePath[treePath.length - 1]
- , child = children[childIndex];
+ var host = options.host || window.location.host.replace(/:.*/, '')
+ , port = options.port || '8080';
- if (child) {
- parent.insertBefore(el, child);
- if (toNormalize) parent.normalize();
- return true;
- } else if (children.length === 0 && (childIndex === 0 || nearest)) {
- parent.appendChild(el);
- if (toNormalize) parent.normalize();
- return true;
- } else {
- child = children[childIndex - 1];
- if (child || nearest) {
- parent.appendChild(el);
- if (toNormalize) parent.normalize();
- return true;
- }
+ var self = this;
+
+ if (this._ws) {
+ // TODO should unsubscribe differently
+ this._ws.onopen = this.ws.onmessage = this.ws.onclose = this.ws.onerror = undefined;
+ this._ws.close();
}
+
+ this._ws = new WebSocket('ws://' + host + ':' + port);
+
+ // TODO reconnect
}
-/**
- * Returns `true` if the first tree path points to a node which is before the other in the document order.
- * @param {Array} path1 A treepath array
- * @param {Array} path2 A treepath array
- * @return {Boolean}
- */
-function isTreePathBefore(path1, path2) {
- var i = 0
- , isBefore;
- if (!Array.isArray(path1) && Array.isArray(path2))
- return logger.error('isTreePathBefore: One or both paths are not valid treepath arrays.');
-
- for (i; i < path1.length; i++) {
- if (path1[i] < path2[i]) {
- isBefore = true;
- break;
- } else if (path1[i] > path2[i]) {
- isBefore = false;
- break;
- }
- }
-
- if (typeof isBefore == 'undefined')
- if (path1.length < path2.length)
- logger.warn('isTreePathBefore: One node is inside another');
- return isBefore || false;
+function addSourceSubscriber (sourceMessage) {
+ _wsSubscriberMethod.call(this, 'addEventListener', sourceMessage);
}
-/**
- * Converts non latin characters to HTML entity codes.
- * @param {String} str the string to convert
- * @return {String} the string with html entities
- */
-function htmlEntities(str) {
- return str.replace(/[\u00A0-\u99999<>\&]/gim, function(i) {
- return ''+i.charCodeAt(0)+';';
- });
+function removeSourceSubscriber (sourceMessage) {
+ _wsSubscriberMethod.call(this, 'removeEventListener', sourceMessage);
}
-function createTreeWalker(el, whatToShow) {
- whatToShow = whatToShow || (NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT);
- return document.createTreeWalker(el, whatToShow);
+function _wsSubscriberMethod (method, sourceMessage) {
+ if (!this._ws) return logger.error('websocket is not created');
+ this._ws[method](sourceMessage, this);
}
-/**
- * Returns the reference to the window the node is in
- *
- * @param {Node} node
- * @return {Window}
- */
-function getNodeWindow(node) {
- var doc = node.ownerDocument;
- return doc && (doc.defaultView || doc.parentWindow);
+// event dispatcher - as defined by Event DOM API
+function WSMessageSource$handleEvent (event) {
+ this.dispatchMessage(event.type, event);
}
+function WSMessageSource$trigger (msg, data, callback) {
+ if (!this._ws) return logger.error('websocket is not created');
-/**
- * do something for each nodes contained in a range
- *
- * @param {range} a range
- * @param {cb} a function taking a node as argument
+ data = data || {};
+ data.type = msg;
- */
-function forEachNodesInRange(range, cb){
- var rangeContainer = range.commonAncestorContainer
- , doc = rangeContainer.ownerDocument;
+ var self = this;
+
+ if (callback) {
+ data.callbackCorrId = uniqueId();
+ var interval = _.delay(onTimeout, config.websocket.rpc.timeout);
+ toggleRpcSubscription('once', data.callbackCorrId);
+ }
- function isNodeInsideRange(node){
- var nodeRange = document.createRange();
- var isInside = false;
- nodeRange.selectNode(node);
+ this._ws.send(JSON.stringify(data));
- if (nodeRange.compareBoundaryPoints(window.Range.START_TO_START, range) != -1
- && nodeRange.compareBoundaryPoints(window.Range.END_TO_END, range) != 1){
- isInside = true;
- }
- nodeRange.detach();
- return isInside;
+
+ function onTimeout() {
+ toggleRpcSubscription('off', data.callbackCorrId);
+ callback(new Error('websocket rpc: timeout'));
}
- var treeWalker = doc.createTreeWalker(rangeContainer,
- NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
+ function onResponse(msg, msgData) {
+ clearInterval(interval);
+ if (typeof msgData == 'object') {
+ var err = msgData.error ? new Error(msgData.error) : null;
+ callback(err, msgData.data)
+ } else
+ callback(new Error('websocket rpc: invalid response data'), msgData);
+ }
- var currentNode;
- while (currentNode = treeWalker.nextNode()){ // should be assignment
- if (isNodeInsideRange(currentNode)){
- cb(currentNode);
- }
+ function toggleRpcSubscription(onOff, corrId) {
+ self.messenger[onOff](config.websocket.rpc.responsePrefix + corrId, onResponse);
}
}
-/**
- * get all components contained in a range
- *
- * @param {range} a DOM range.
- */
-function getComponentsFromRange(range) {
- var win = getNodeWindow(range.startContainer)
- , Component = win.milo.Component;
+},{"../../config":64,"../../util/count":77,"milo-core":105}],95:[function(require,module,exports){
+;(function(){
- var components = [];
- forEachNodesInRange(range, function (node){
- if (node.nodeType != Node.TEXT_NODE) {
- var comp = Component.getComponent(node);
- if (comp)
- components.push(comp);
- }
- });
+// This would be the place to edit if you want a different
+// Base32 implementation
- return components;
-}
+var alphabet = '0123456789abcdefghjkmnpqrtuvwxyz'
+var alias = { o:0, i:1, l:1, s:5 }
/**
- * delete a range
+ * Build a lookup table and memoize it
*
- * @param {range} delete a DOM range and all the components inside
+ * Return an object that maps a character to its
+ * byte value.
*/
-function deleteRangeWithComponents(range) {
- var components = getComponentsFromRange(range);
-
- components.forEach(function(comp) {
- comp.destroy(true);
- });
- range.deleteContents();
+var lookup = function() {
+ var table = {}
+ // Invert 'alphabet'
+ for (var i = 0; i < alphabet.length; i++) {
+ table[alphabet[i]] = i
+ }
+ // Splice in 'alias'
+ for (var key in alias) {
+ if (!alias.hasOwnProperty(key)) continue
+ table[key] = table['' + alias[key]]
+ }
+ lookup = function() { return table }
+ return table
}
/**
- * check if two ranges are equivalent
+ * A streaming encoder
*
- * @param {range} range1
- * @param {range} range2
- * @return {Boolean} are the two ranges equivalent
+ * var encoder = new base32.Encoder()
+ * var output1 = encoder.update(input1)
+ * var output2 = encoder.update(input2)
+ * var lastoutput = encode.update(lastinput, true)
*/
-function areRangesEqual(range1, range2){
- return range1.compareBoundaryPoints(window.Range.START_TO_START, range2) == 0 && range1.compareBoundaryPoints(window.Range.END_TO_END, range2) == 0;
-}
-
-/**
- * Adds a single pixel div to the body at a given x and y position. Useful for debugging position specific code.
- * @param {Number} x
- * @param {Number} y
- */
-function addDebugPoint(x, y) {
- var dbEl = document.createElement('div');
- dbEl.setAttribute('style', 'width: 1px; height: 1px; position:fixed; left:'+x+'px; top:'+y+'px; background-color:red; z-index: 100');
- setTimeout(function() {document.body.appendChild(dbEl);}, 200);
-}
+function Encoder() {
+ var skip = 0 // how many bits we will skip from the first byte
+ var bits = 0 // 5 high bits, carry from one byte to the next
-},{"../config":65,"./logger":102,"mol-proto":150}],95:[function(require,module,exports){
-'use strict';
+ this.output = ''
+ // Read one byte of input
+ // Should not really be used except by "update"
+ this.readByte = function(byte) {
+ // coerce the byte to an int
+ if (typeof byte == 'string') byte = byte.charCodeAt(0)
-var _ = require('mol-proto')
- , check = require('./check');
+ if (skip < 0) { // we have a carry from the previous byte
+ bits |= (byte >> (-skip))
+ } else { // no carry
+ bits = (byte << skip) & 248
+ }
+ if (skip > 3) {
+ // not enough data to produce a character, get us another one
+ skip -= 8
+ return 1
+ }
-module.exports = DOMListeners;
+ if (skip < 4) {
+ // produce a character
+ this.output += alphabet[bits >> 3]
+ skip += 5
+ }
+ return 0
+ }
-function DOMListeners() {
- this.listeners = [];
+ // Flush any remaining bits left in the stream
+ this.finish = function(check) {
+ var output = this.output + (skip < 0 ? alphabet[bits >> 3] : '') + (check ? '$' : '')
+ this.output = ''
+ return output
+ }
}
+/**
+ * Process additional input
+ *
+ * input: string of bytes to convert
+ * flush: boolean, should we flush any trailing bits left
+ * in the stream
+ * returns: a string of characters representing 'input' in base32
+ */
-_.extendProto(DOMListeners, {
- add: DOMListeners$add,
- remove: DOMListeners$remove,
- removeAll: DOMListeners$removeAll
-});
+Encoder.prototype.update = function(input, flush) {
+ for (var i = 0; i < input.length; ) {
+ i += this.readByte(input[i])
+ }
+ // consume all output
+ var output = this.output
+ this.output = ''
+ if (flush) {
+ output += this.finish()
+ }
+ return output
+}
+// Functions analogously to Encoder
-function DOMListeners$add(target, eventType, handler) {
- this.listeners.push({
- target: target,
- eventType: eventType,
- handler: handler
- });
- target.addEventListener(eventType, handler);
-}
+function Decoder() {
+ var skip = 0 // how many bits we have from the previous character
+ var byte = 0 // current byte we're producing
+ this.output = ''
-function DOMListeners$remove(target, eventType, handler) {
- var listener = {
- target: target,
- eventType: eventType,
- handler: handler
- };
- var idx = _.findIndex(this.listeners, _.partial(_.isEqual, listener));
+ // Consume a character from the stream, store
+ // the output in this.output. As before, better
+ // to use update().
+ this.readChar = function(char) {
+ if (typeof char != 'string'){
+ if (typeof char == 'number') {
+ char = String.fromCharCode(char)
+ }
+ }
+ char = char.toLowerCase()
+ var val = lookup()[char]
+ if (typeof val == 'undefined') {
+ // character does not exist in our lookup table
+ return // skip silently. An alternative would be:
+ // throw Error('Could not find character "' + char + '" in lookup table.')
+ }
+ val <<= 3 // move to the high bits
+ byte |= val >>> skip
+ skip += 5
+ if (skip >= 8) {
+ // we have enough to preduce output
+ this.output += String.fromCharCode(byte)
+ skip -= 8
+ if (skip > 0) byte = (val << (5 - skip)) & 255
+ else byte = 0
+ }
- if (idx > -1) {
- this.listeners.splice(idx, 1);
- _removeListener(listener);
}
-}
-
-function DOMListeners$removeAll() {
- this.listeners.forEach(_removeListener);
- this.listeners = [];
+ this.finish = function(check) {
+ var output = this.output + (skip < 0 ? alphabet[bits >> 3] : '') + (check ? '$' : '')
+ this.output = ''
+ return output
+ }
}
-
-function _removeListener(l) {
- l.target.removeEventListener(l.eventType, l.handler);
+Decoder.prototype.update = function(input, flush) {
+ for (var i = 0; i < input.length; i++) {
+ this.readChar(input[i])
+ }
+ var output = this.output
+ this.output = ''
+ if (flush) {
+ output += this.finish()
+ }
+ return output
}
-},{"./check":90,"mol-proto":150}],96:[function(require,module,exports){
-'use strict';
+/** Convenience functions
+ *
+ * These are the ones to use if you just have a string and
+ * want to convert it without dealing with streams and whatnot.
+ */
+// String of data goes in, Base32-encoded string comes out.
+function encode(input) {
+ var encoder = new Encoder()
+ var output = encoder.update(input, true)
+ return output
+}
-var _ = require('mol-proto');
+// Base32-encoded string goes in, decoded data comes out.
+function decode(input) {
+ var decoder = new Decoder()
+ var output = decoder.update(input, true)
+ return output
+}
+var base32 = {
+ Decoder: Decoder,
+ Encoder: Encoder,
+ encode: encode,
+ decode: decode
+}
-module.exports = domReady;
+if (typeof window !== 'undefined') {
+ // we're in a browser - OMG!
+ window.base32 = base32
+}
+if (typeof module !== 'undefined' && module.exports) {
+ // nodejs/browserify
+ module.exports = base32
+}
+})();
-var domReadyFuncs = []
- , domReadySubscribed = false;
+},{}],96:[function(require,module,exports){
+// not implemented
+// The reason for having an empty file and not throwing is to allow
+// untraditional implementation of this module.
-function domReady(func) { // , arguments
- var self = this
- , args = _.slice(arguments, 1);
- if (isReady.call(this))
- callFunc();
- else {
- if (!domReadySubscribed) {
- document.addEventListener('readystatechange', onDomReady);
- domReadySubscribed = true;
- }
- domReadyFuncs.push(callFunc); // closure is added, so every time different function will be called
- }
+},{}],97:[function(require,module,exports){
+'use strict';
- function callFunc() {
- func.apply(self, args);
- }
-}
+var _ = require('mol-proto')
+ , check = require('../util/check')
+ , Match = check.Match
+ , config = require('../config');
-function onDomReady() {
- document.removeEventListener('readystatechange', onDomReady);
- domReadyFuncs.forEach(function(func) { func(); });
-}
+module.exports = Mixin;
+/**
+ * `milo.classes.Mixin` - an abstract Mixin class.
+ * Can be subclassed using:
+ * ```
+ * var MyMixin = _.createSubclass(milo.classes.Mixin, 'MyMixin');
+ * ```
+ *
+ * Mixin pattern is also used, but Mixin in milo is implemented as a separate object that is stored on the property of the host object and can create proxy methods on the host object if required.
+ * Classes [Messenger](../messenger/index.js.html) and [MessageSource](../messenger/m_source.js.html) are subclasses of Mixin abstract class. `this` in proxy methods refers to Mixin instance, the reference to the host object is `this._hostObject`.
+ *
+ * @param {Object} hostObject Optional object where a Mixin instance will be stored on. It is used to proxy methods and also to find the reference when it is needed for host object implementation.
+ * @param {Object} proxyMethods Optional map of proxy method names as keys and Mixin methods names as values, so proxied methods can be renamed to avoid name-space conflicts if two different Mixin instances with the same method names are put on the object
+ * @param {List} arguments all constructor arguments will be passed to init method of Mixin subclass together with hostObject and proxyMethods
+ * @return {Mixin}
+ */
+function Mixin(hostObject, proxyMethods) { // , other args - passed to init method
+ check(hostObject, Match.Optional(Match.OneOf(Object, Function)));
-_.extend(domReady, {
- isReady: isReady
-});
+ // store hostObject
+ _.defineProperty(this, '_hostObject', hostObject);
+ // proxy methods to hostObject
+ if (proxyMethods)
+ this._createProxyMethods(proxyMethods);
-function isReady() {
- var readyState = document.readyState;
- return readyState == 'loading' ? false : readyState;
+ // calling init if it is defined in the class
+ if (this.init)
+ this.init.apply(this, arguments);
}
-},{"mol-proto":150}],97:[function(require,module,exports){
-'use strict';
-
-var Component = require('../components/c_class')
- , Messenger = require('../messenger')
- , dragDropConfig = require('../config').dragDrop
- , componentMetaRegex = dragDropConfig.dataTypes.componentMetaRegex
- , jsonParse = require('./json_parse')
- , _ = require('mol-proto')
- , base32 = require('base32');
-
-module.exports = DragDrop;
+/**
+ * ####Mixin instance methods####
+ * These methods are called by constructor, they are not to be called from subclasses.
+ *
+ * - [_createProxyMethod](#_createProxyMethod)
+ * - [_createProxyMethods](#_createProxyMethods)
+ */
+_.extendProto(Mixin, {
+ _createProxyMethod: _createProxyMethod, // deprecated, should not be used
+ _createProxyMethods: _createProxyMethods // deprecated, should not be used
+});
/**
- * Wrapper for event.dataTransfer of drag-drop HTML API
+ * ####Mixin class methods####
+ * These method should be called in host class declaration.
*
- * @constructor
- * @param {event} DOM event
- * @return {DragDrop}
+ * - [useWith](#Mixin$$useWith)
*/
-function DragDrop(event) {
- this.event = event;
- this.dataTransfer = event.dataTransfer;
- this.types = event.dataTransfer.types;
-}
+_.extend(Mixin, {
+ useWith: Mixin$$useWith
+});
+
/**
- * Usage:
- * var testDT = new DragDrop(event);
- * testDT.setComponentMeta(newComponent, {test: 'test', test2: 'test2'});
- * testDT.getComponentMeta();
+ * Creates a proxied method of Mixin subclass on host object.
+ *
+ * @param {String} mixinMethodName name of method in Mixin subclass
+ * @param {String} proxyMethodName name of created proxy method on host object
+ * @param {Object} hostObject Optional reference to the host object; if not specified the host object passed to constructor wil be used. It allows to use the same instance of Mixin on two host objects.
*/
+function _createProxyMethod(proxyMethodName, mixinMethodName, hostObject) {
+ hostObject = hostObject || this._hostObject;
-_.extend(DragDrop, {
- componentDataType: DragDrop$$componentDataType
-});
+ // Mixin class does not allow shadowing methods that exist on the host object
+ if (hostObject[proxyMethodName])
+ throw new Error('method ' + proxyMethodName +
+ ' already defined in host object');
-_.extendProto(DragDrop, {
- isComponent: DragDrop$isComponent,
- getComponentState: DragDrop$getComponentState,
- setComponentState: DragDrop$setComponentState,
- getComponentMeta: DragDrop$getComponentMeta,
- setComponentMeta: DragDrop$setComponentMeta,
- getAllowedEffects: DragDrop$getAllowedEffects,
- setAllowedEffects: DragDrop$setAllowedEffects,
- getDropEffect: DragDrop$getDropEffect,
- setDropEffect: DragDrop$setDropEffect,
- isEffectAllowed: DragDrop$isEffectAllowed,
- getData: DragDrop$getData,
- setData: DragDrop$setData,
- clearData: DragDrop$clearData
-});
+ var method = this[mixinMethodName]
+ check(method, Function);
+ // Bind proxied Mixin's method to Mixin instance
+ var boundMethod = method.bind(this);
-function DragDrop$$componentDataType() {
- return dragDropConfig.dataTypes.component;
+ _.defineProperty(hostObject, proxyMethodName, boundMethod, _.WRIT);
}
-function DragDrop$isComponent() {
- return _.indexOf(this.types, DragDrop.componentDataType()) >= 0;
+/**
+ * Creates proxied methods of Mixin subclass on host object.
+ *
+ * @param {Hash[String]|Array[String]} proxyMethods map of names of methods, key - proxy method name, value - mixin method name. Can be array.
+ * @param {Object} hostObject an optional reference to the host object; if not specified the host object passed to constructor wil be used. It allows to use the same instance of Mixin on two host objects.
+ */
+function _createProxyMethods(proxyMethods, hostObject) {
+ check(proxyMethods, Match.Optional(Match.OneOf([String], Match.ObjectHash(String))));
+
+ // creating and binding proxy methods on the host object
+ if (Array.isArray(proxyMethods))
+ proxyMethods.forEach(function(methodName) {
+ // method called this way to allow using _createProxyMethods with objects
+ // that are not inheriting from Mixin
+ _createProxyMethod.call(this, methodName, methodName, hostObject);
+ }, this);
+ else
+ _.eachKey(proxyMethods, function(mixinMethodName, proxyMethodName) {
+ // method called this way to allow using _createProxyMethods with objects
+ // that are not inheriting from Mixin
+ _createProxyMethod.call(this, proxyMethodName, mixinMethodName, hostObject);
+ }, this);
}
-function DragDrop$getComponentState() {
- var dataType = DragDrop.componentDataType()
- , stateStr = this.dataTransfer.getData(dataType)
- , state = jsonParse(stateStr);
-
- return state;
-}
+/**
+ * Sets mixin instance property name on the host class
+ * Can be called only once
+ *
+ * @private
+ * @param {Function} this Mixin subclass (not instance)
+ * @param {Function} hostClass
+ * @param {String} instanceKey
+ */
+function Mixin_setInstanceKey(hostClass, method, instanceKey) {
+ check(hostClass, Function);
+ check(instanceKey, Match.IdentifierString);
+ var prop = config.mixin.instancePropertiesMap
+ , instanceKeys = hostClass[prop] = hostClass[prop] || {};
-function DragDrop$setComponentState(component, stateStr){
- if (! stateStr) {
- var state = component.getTransferState({ requestedBy: 'drag' });
- stateStr = JSON.stringify(state);
- }
- var dataType = DragDrop.componentDataType();
+ if (instanceKeys[method.name])
+ throw new Error('Mixin: instance property for method with name '
+ + method.name + ' is already set');
- stateStr && this.dataTransfer.setData(dataType, stateStr);
- this.dataTransfer.setData('text/html', component.el.outerHTML);
- return stateStr;
+ instanceKeys[method.name] = instanceKey;
}
-function DragDrop$setComponentMeta(component, params, data) {
- var meta = _componentMeta(component);
-
- var paramsStr = _.toQueryString(params);
- var dataType = dragDropConfig.dataTypes.componentMetaTemplate
- .replace('%class', _encode(meta.compClass || ''))
- .replace('%name', _encode(meta.compName || ''))
- .replace('%params', _encode(paramsStr || ''));
+/**
+ * Adds method of Mixin subclass to host class prototype.
+ *
+ * @private
+ * @param {Function} this Mixin subclass (not instance)
+ * @param {String} mixinMethodName name of method in Mixin subclass
+ * @param {String} hostMethodName (optional) name of created proxy method on host object, same if not specified
+ * @param {Object} hostObject object class, must be specified as the last parameter (2nd or 3rd)
+ */
+function Mixin_addMethod(hostClass, instanceKey, mixinMethodName, hostMethodName) {
+ var method = this.prototype[mixinMethodName];
+ check(method, Function);
- if (data && typeof data == 'object') data = JSON.stringify(data);
+ var wrappedMethod = _wrapMixinMethod.call(this, method);
- this.dataTransfer.setData(dataType, data || '');
+ _.defineProperty(hostClass.prototype, hostMethodName, wrappedMethod, _.WRIT);
- return dataType;
+ Mixin_setInstanceKey(hostClass, method, instanceKey)
}
-function _encode(str) {
- return base32.encode(str).toLowerCase();
+/**
+ * Returns method that will be exposed on the host class prototype
+ *
+ * @private
+ * @param {Function} this Mixin subclass (not instance)
+ * @return {Function}
+ */
+function _wrapMixinMethod(method) {
+ return function() { // ,... arguments
+ var mixinInstance = _getMixinInstance.call(this, method.name);
+ return method.apply(mixinInstance, arguments);
+ }
}
-function _componentMeta(component) {
- return component.transfer
- ? component.transfer.getComponentMeta()
- : {
- compClass: component.constructor.name,
- compName: component.name
- };
+/**
+ * Returns the reference to the instance of mixin subclass.
+ * This method is used when methods are exposed on the host class prototype (using addMehtods) rather than on host instance.
+ * Subclasses should not use this methods - whenever subclass method is exposed on the prototype it will be wrapped to set correct context for the subclass method.
+ *
+ * @private
+ * @return {Object}
+ */
+function _getMixinInstance(methodName) {
+ if (this instanceof Mixin) return this;
+ var instanceKeys = this.constructor[config.mixin.instancePropertiesMap]
+ return this[instanceKeys[methodName]];
}
-function DragDrop$getComponentMeta() {
- var match;
- var metaDataType = _.find(this.types, function (dType) {
- match = dType.match(componentMetaRegex);
- return !!match;
- });
- if (!metaDataType) return;
-
- for (var i=1; i<4; i++)
- match[i] = base32.decode(match[i]);
-
- return {
- compClass: match[1],
- compName: match[2],
- params: _.fromQueryString(match[3]),
- metaDataType: metaDataType,
- metaData: _.jsonParse(this.dataTransfer.getData(metaDataType))
- ? _.jsonParse(this.dataTransfer.getData(metaDataType))
- : this.dataTransfer.getData(metaDataType)
- };
-}
-
+/**
+ * Adds methods of Mixin subclass to host class prototype.
+ *
+ * @param {Function} this Mixin subclass (not instance)
+ * @param {Object} hostClass host object class; must be specified.
+ * @param {String} instanceKey the name of the property the host class instance will store mixin instance on
+ * @param {Hash[String]|Array[String]} mixinMethods map of names of methods, key - host method name, value - mixin method name. Can be array.
+ */
+function Mixin$$useWith(hostClass, instanceKey, mixinMethods) {
+ check(mixinMethods, Match.Optional(Match.OneOf([String], Match.ObjectHash(String))));
-// as defined here: https://developer.mozilla.org/en-US/docs/DragDrop/Drag_Operations#dragstart
-function DragDrop$getAllowedEffects() {
- return this.dataTransfer.effectAllowed;
+ if (Array.isArray(mixinMethods))
+ mixinMethods.forEach(function(methodName) {
+ Mixin_addMethod.call(this, hostClass, instanceKey, methodName, methodName);
+ }, this);
+ else
+ _.eachKey(mixinMethods, function(mixinMethodName, hostMethodName) {
+ Mixin_addMethod.call(this, hostClass, instanceKey, mixinMethodName, hostMethodName);
+ }, this);
}
+},{"../config":99,"../util/check":116,"mol-proto":122}],98:[function(require,module,exports){
+'use strict';
-function DragDrop$setAllowedEffects(effects) {
- this.dataTransfer.effectAllowed = effects;
-}
+//
+// milo.classes
+// -----------
+// This module contains foundation classes
-function DragDrop$getDropEffect() {
- return this.dataTransfer.dropEffect;
-}
+var classes = {
+ Mixin: require('./abstract/mixin'),
+ MessageSource: require('./messenger/m_source'),
+ MessengerMessageSource: require('./messenger/msngr_source'),
+ MessengerAPI: require('./messenger/m_api'),
+ MessengerRegexpAPI: require('./messenger/m_api_rx')
+};
+module.exports = classes;
-function DragDrop$setDropEffect(effect) {
- this.dataTransfer.dropEffect = effect;
-}
+},{"./abstract/mixin":97,"./messenger/m_api":101,"./messenger/m_api_rx":102,"./messenger/m_source":103,"./messenger/msngr_source":104}],99:[function(require,module,exports){
+'use strict';
-function DragDrop$isEffectAllowed(effect) {
- var allowedEffects = this.getAllowedEffects()
- , isCopy = effect == 'copy'
- , isMove = effect == 'move'
- , isLink = effect == 'link'
- , isAllowed = isCopy || isLink || isMove;
+var _ = require('mol-proto');
- switch (allowedEffects) {
- case 'copy':
- case 'move':
- case 'link':
- return allowedEffects == effect;
- case 'copyLink':
- return isCopy || isLink;
- case 'copyMove':
- return isCopy || isMove;
- case 'linkMove':
- return isLink || isMove;
- case 'all':
- case 'uninitialized':
- return isAllowed;
- case 'none':
- return false;
- }
-}
+module.exports = config;
-function DragDrop$getData(dataType) {
- return this.dataTransfer.getData(dataType);
+function config(options) {
+ _.deepExtend(config, options);
}
+config({
+ mixin: {
+ instancePropertiesMap: '___mixin_instances'
+ },
+ check: true,
+ debug: false
+});
-function DragDrop$setData(dataType, dataStr) {
- this.dataTransfer.setData(dataType, dataStr);
-}
-
+},{"mol-proto":122}],100:[function(require,module,exports){
+'use strict';
-function DragDrop$clearData(dataType) {
- this.dataTransfer.clearData(dataType);
-}
+var Mixin = require('../abstract/mixin')
+ , MessageSource = require('./m_source')
+ , _ = require('mol-proto')
+ , check = require('../util/check')
+ , Match = check.Match;
/**
- * Drag drop service compensating for the lack of communication from drop target to drag source in DOM API
+ * `milo.Messenger`
+ * A generic Messenger class that is used for all kinds of messaging in milo. It is subclassed from [Mixin](../abstract/mixin.js.html) and it proxies its methods to the host object for convenience.
+ * All facets and components have messenger attached to them. Messenger class interoperates with [MessageSource](./m_source.js.html) class that connects the messenger to some external source of messages (e.g., DOM events) and [MessengerAPI](./m_api.js.html) class that allows to define higher level messages than messages that exist on the source.
+ * Messenger class is used internally in milo and can be used together with any objects/classes in the application.
+ * milo also defines a global messenger [milo.mail](../mail/index.js.html) that dispatches `domready` event and can be used for any application wide messaging.
+ * To initialize your app after DOM is ready use:
+ * ```
+ * milo.mail.on('domready', function() {
+ * // application starts
+ * });
+ * ```
+ * or the following shorter form of the same:
+ * ```
+ * milo(function() {
+ * // application starts
+ * });
+ * ```
*/
-var dragDropService = new Messenger;
-
-var _currentDragDrop, _currentDragFacet;
-
-_.extend(DragDrop, {
- service: dragDropService,
- destroy: DragDrop_destroy
-});
-
-
-dragDropService.onMessages({
- // data is DragDropDataTransfer instance
- // fired by Drag facet on "dragstart" event
- 'dragdropstarted': onDragDropStarted,
- // data is object with at least dropEffect property
- // fired by Drop facet on "drop" event
- 'dragdropcompleted': onDragDropCompleted,
- // fired by Drag facet on "dragend" event to complete drag
- // if drop happended in another window or if it was cancelled
- 'completedragdrop': onCompleteDragDrop
-});
-
+var Messenger = _.createSubclass(Mixin, 'Messenger');
-_.extend(dragDropService, {
- getCurrentDragDrop: getCurrentDragDrop
-});
+var messagesSplitRegExp = Messenger.messagesSplitRegExp = /\s*(?:\,|\s)\s*/;
-function onDragDropStarted(msg, data) {
- _currentDragDrop = data.dragDrop;
- _currentDragFacet = data.dragFacet;
-}
+/**
+ * ####Messenger instance methods####
+ *
+ * - [init](#init)
+ * - [on](#Messenger$on) (alias - onMessage, deprecated)
+ * - [off](#Messenger$off) (alias - offMessage, deprecated)
+ * - [onMessages](#onMessages)
+ * - [offMessages](#offMessages)
+ * - [once](#once)
+ * - [onceSync](#onceSync)
+ * - [postMessage](#postMessage)
+ * - [getSubscribers](#getSubscribers)
+ *
+ * "Private" methods
+ *
+ * - [_chooseSubscribersHash](#_chooseSubscribersHash)
+ * - [_registerSubscriber](#_registerSubscriber)
+ * - [_removeSubscriber](#_removeSubscriber)
+ * - [_removeAllSubscribers](#_removeAllSubscribers)
+ * - [_callPatternSubscribers](#_callPatternSubscribers)
+ * - [_callSubscribers](#_callSubscribers)
+ * - [_setMessageSource](#_setMessageSource)
+ * - [getMessageSource](#getMessageSource)
+ */
+_.extendProto(Messenger, {
+ init: init, // called by Mixin (superclass)
+ destroy: Messenger$destroy,
+ on: Messenger$on,
+ once: Messenger$once,
+ onceSync: Messenger$onceSync,
+ onSync: Messenger$onSync,
+ onAsync: Messenger$onAsync,
+ onMessage: Messenger$on, // deprecated
+ off: Messenger$off,
+ offMessage: Messenger$off, // deprecated
+ onMessages: onMessages,
+ offMessages: offMessages,
+ offAll: Messenger$offAll,
+ postMessage: postMessage,
+ postMessageSync: postMessageSync,
+ getSubscribers: getSubscribers,
+ getMessageSource: getMessageSource,
+ _chooseSubscribersHash: _chooseSubscribersHash,
+ _registerSubscriber: _registerSubscriber,
+ _removeSubscriber: _removeSubscriber,
+ _removeAllSubscribers: _removeAllSubscribers,
+ _callPatternSubscribers: _callPatternSubscribers,
+ _callSubscribers: _callSubscribers,
+ _callSubscriber: _callSubscriber,
+ _setMessageSource: _setMessageSource
+});
-function onDragDropCompleted(msg, data) {
- _currentDragFacet && _currentDragFacet.postMessageSync('dragdropcompleted', data);
- _currentDragDrop = undefined;
- _currentDragFacet = undefined;
+/**
+ * A default map of proxy methods used by ComponentFacet and Component classes to pass to Messenger when it is instantiated.
+ * This map is for convenience only, it is NOT used internally by Messenger, a host class should pass it for methods to be proxied this way.
+ */
+Messenger.defaultMethods = {
+ on: 'on',
+ onSync: 'onSync',
+ once: 'once',
+ onceSync: 'onceSync',
+ off: 'off',
+ onMessages: 'onMessages',
+ offMessages: 'offMessages',
+ postMessage: 'postMessage',
+ postMessageSync: 'postMessageSync',
+ getSubscribers: 'getSubscribers'
+};
+
+
+module.exports = Messenger;
+
+
+Messenger.subscriptions = [];
+
+
+/**
+ * Messenger instance method
+ * Initializes Messenger. Method is called by Mixin class constructor.
+ * See [on](#Messenger$on) method, [Messenger](#Messenger) class above and [MessageSource](./m_source.js.html) class.
+ *
+ * @param {Object} hostObject Optional object that stores the messenger on one of its properties. It is used to proxy methods of messenger and also as a context for subscribers when they are called by the Messenger. See `on` method.
+ * @param {Object} proxyMethods Optional map of method names; key - proxy method name, value - messenger's method name.
+ * @param {MessageSource} messageSource Optional messageSource linked to the messenger. If messageSource is supplied, the reference to the messenger will stored on its 'messenger' property
+ */
+function init(hostObject, proxyMethods, messageSource) {
+ // hostObject and proxyMethods are used in Mixin and checked there
+ if (messageSource)
+ this._setMessageSource(messageSource);
+
+ _initializeSubscribers.call(this);
}
-function onCompleteDragDrop(msg, data) {
- if (_currentDragDrop)
- dragDropService.postMessageSync('dragdropcompleted', data);
+function _initializeSubscribers() {
+ _.defineProperties(this, {
+ _messageSubscribers: {},
+ _patternMessageSubscribers: {},
+ }, _.CONF);
}
-function getCurrentDragDrop() {
- return _currentDragDrop;
+/**
+ * Destroys messenger. Maybe needs to unsubscribe all subscribers
+ */
+function Messenger$destroy() {
+ this.offAll();
+ var messageSource = this.getMessageSource();
+ if (messageSource)
+ messageSource.destroy();
}
-function DragDrop_destroy() {
- dragDropService.offAll();
+/**
+ * Messenger instance method.
+ * Registers a subscriber function for a certain message(s).
+ * This method returns `true` if the subscription was successful. It can be unsuccessful if the passed subscriber has already been subscribed to this message type - double subscription never happens and it is safe to subscribe again - no error or warning is thrown or logged.
+ * Subscriber is passed two parameters: `message` (string) and `data` (object). Data object is supplied when message is dispatched, Messenger itself adds nothing to it. For example, [events facet](../components/c_facets/Events.js.html) sends actual DOM event when it posts message.
+ * Usage:
+ * ```
+ * // subscribes onMouseUpDown to two DOM events on component via events facet.
+ * myComp.events.on('mousedown mouseup', onMouseUpDown);
+ * function onMouseUpDown(eventType, event) {
+ * // ...
+ * }
+ *
+ * myComp.data.on(/.+/, function(msg, data) {
+ * logger.debug(msg, data);
+ * }); // subscribes anonymous function to all non-empty messages on data facet
+ * // it will not be possible to unsubscribe anonymous subscriber separately,
+ * // but myComp.data.off(/.+/) will unsubscribe it
+ * ```
+ * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added, so it can subscribe to the source.
+ * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `on` when they proxy it.
+ * See [postMessage](#postMessage).
+ *
+ * @param {String|Array[String]|RegExp} messages Message types that should envoke the subscriber.
+ * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.
+ * If an array of strings is passed, each string is a message type to subscribe for.
+ * If a RegExp is passed, the subscriber will be envoked when the message dispatched on the messenger matches the pattern (or IS the RegExp with identical pattern).
+ * Pattern subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.
+ * @param {Function|Object} subscriber Message subscriber - a function that will be called when the message is dispatched on the messenger (usually via proxied postMessage method of host object).
+ * If hostObject was supplied to Messenger constructor, hostObject will be the context (the value of this) for the subscriber envocation.
+ * Subscriber can also be an object with properties `subscriber` (function) and `context` ("this" value when subscriber is called)
+ * @return {Boolean}
+ */
+function Messenger$on(messages, subscriber) {
+ return _Messenger_onWithOptions.call(this, messages, subscriber);
}
-},{"../components/c_class":16,"../config":65,"../messenger":67,"./json_parse":101,"base32":112,"mol-proto":150}],98:[function(require,module,exports){
-//
-// milo.utils.error
-// -----------
-'use strict';
+function Messenger$once(messages, subscriber) {
+ return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1 });
+}
-var _ = require('mol-proto');
+function Messenger$onceSync(messages, subscriber) {
+ return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1, sync: true });
+}
-// module exports error classes for all names defined in this array
-var errorClassNames = ['AbstractClass', 'Mixin', 'Messenger', 'Component',
- 'Attribute', 'Binder', 'Loader', 'MailMessageSource', 'Facet',
- 'Scope', 'Model', 'DomFacet', 'EditableFacet',
- 'List', 'Connector', 'Registry', 'FrameMessageSource',
- 'Drop', 'Angular', 'StorageMessageSource'];
+function Messenger$onSync(messages, subscriber) {
+ return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: true });
+}
-var error = {
- toBeImplemented: error$toBeImplemented,
- createClass: error$createClass
-};
-errorClassNames.forEach(function(name) {
- error[name] = error$createClass(name + 'Error');
-});
+function Messenger$onAsync(messages, subscriber) {
+ return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: false });
+}
-module.exports = error;
+function _Messenger_onWithOptions(messages, subscriber, options) {
+ check(messages, Match.OneOf(String, [String], RegExp));
+ check(subscriber, Match.OneOf(Function, {
+ subscriber: Function,
+ context: Match.Any,
+ options: Match.Optional(Object),
+ }));
-function error$createClass(errorClassName) {
- var ErrorClass = _.makeFunction(errorClassName, 'message',
- 'this.name = "' + errorClassName + '"; \
- this.message = message || "There was an error";');
- _.makeSubclass(ErrorClass, Error);
+ if (typeof subscriber == 'function') {
+ subscriber = {
+ subscriber: subscriber,
+ context: this._hostObject,
+ };
+ }
- return ErrorClass;
+ if (options) {
+ subscriber.options = subscriber.options || {};
+ _.extend(subscriber.options, options);
+ }
+
+ return _Messenger_on.call(this, messages, subscriber);
}
-function error$toBeImplemented() {
- throw new error.AbstractClass('calling the method of an absctract class');
+function _Messenger_on(messages, subscriber) {
+ _.defineProperty(subscriber, '__messages', messages);
+ return _eachMessage.call(this, '_registerSubscriber', messages, subscriber);
}
-},{"mol-proto":150}],99:[function(require,module,exports){
-'use strict';
-
-var Component = require('../components/c_class')
- , BindAttribute = require('../attributes/a_bind')
- , binder = require('../binder')
- , domUtils = require('./dom')
- , logger = require('./logger')
- , check = require('./check')
- , _ = require('mol-proto');
+function _eachMessage(methodName, messages, subscriber) {
+ if (typeof messages == 'string')
+ messages = messages.split(messagesSplitRegExp);
+ var subscribersHash = this._chooseSubscribersHash(messages);
-var createRangePaths = _createNodesAndPathsFunc(domUtils.treePathOf);
-var createRangeNodes = _createNodesAndPathsFunc(domUtils.getNodeAtTreePath);
+ if (messages instanceof RegExp)
+ return this[methodName](subscribersHash, messages, subscriber);
+ else {
+ var changed = false;
-var fragmentUtils = module.exports = {
- getState: fragment_getState,
- getStateAsync: fragment_getStateAsync,
+ messages.forEach(function(message) {
+ var subscriptionChanged = this[methodName](subscribersHash, message, subscriber);
+ changed = changed || subscriptionChanged;
+ }, this);
- expandRangeToSiblings: expandRangeToSiblings,
- getRangeSiblings: getRangeSiblings,
- createRangeFromSiblings: createRangeFromSiblings,
- createRangeFromNodes: createRangeFromSiblings, // alias
- createRangePaths: createRangePaths,
- createRangeNodes: createRangeNodes
-};
+ return changed;
+ }
+}
/**
- * Creates an object with the state of wrapped range with components, including partially selected. The range will be cloned and wrapped in component with container facet before getting its state.
- * This function will log error and return undefined if range has no common ancestor that has component with container facet
- *
- * @param {Range} range DOM Range instance
- * @param {Boolean} renameChildren optional parameter, `true` to rename fragment child components
- * @param {String} wrapperClassName optional parameter to wrap in a custom component class
- * @return {Object}
- */
-function fragment_getState(range, renameChildren, wrapperClassName) {
- var rangeContainer = _getRangeContainer(range);
- if (! rangeContainer) {
- logger.error('fragment.getState: range has no common container');
- return;
+ * "Private" Messenger instance method
+ * It is called by [on](#Messenger$on) to register subscriber for one message type.
+ * Returns `true` if this subscriber is not yet registered for this type of message.
+ * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added.
+ *
+ * @private
+ * @param {Object} subscribersHash The map of subscribers determined by [on](#Messenger$on) based on Message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
+ * @param {String} message Message type
+ * @param {Function|Object} subscriber Subscriber function to be added or object with properties `subscriber` (function) and `context` (value of "this" when subscriber is called)
+ * @return {Boolean}
+ */
+function _registerSubscriber(subscribersHash, message, subscriber) {
+ if (! (subscribersHash[message] && subscribersHash[message].length)) {
+ subscribersHash[message] = [];
+ if (message instanceof RegExp)
+ subscribersHash[message].pattern = message;
+ if (this._messageSource)
+ this._messageSource.onSubscriberAdded(message);
+ var noSubscribers = true;
}
- var frag = range.cloneContents()
- , wrapper = _wrapFragmentInContainer(frag, wrapperClassName);
+ var msgSubscribers = subscribersHash[message];
+ var notYetRegistered = noSubscribers || _indexOfSubscriber.call(this, msgSubscribers, subscriber) == -1;
- _transferStates(rangeContainer, wrapper);
- if (renameChildren) _renameChildren(wrapper);
- var wrapperState = wrapper.getState();
- _.deferMethod(wrapper, 'destroy');
- return wrapperState;
+ if (notYetRegistered)
+ msgSubscribers.push(subscriber);
+
+ return notYetRegistered;
}
/**
- * Creates an object with the state of wrapped range with components, including partially selected. The range will be cloned and wrapped in component with container facet before getting its state.
- * This function will return result and any error via callback.
- *
- * @param {Range} range DOM Range instance
- * @param {Boolean} renameChildren optional parameter, `true` to rename fragment child components
- * @param {Function} callback always the last parameter, optional parameters can be dropped; result is passed via callback with any error as first parameter
+ * Finds subscriber index in the list
+ *
+ * @param {Array[Function|Object]} list list of subscribers
+ * @param {Function|Object} subscriber subscriber function or object with properties `subscriber` (function) and `context` ("this" object)
*/
-function fragment_getStateAsync(range, renameChildren, callback) {
- try {
- var rangeContainer = _getRangeContainer(range);
- if (! rangeContainer) {
- callback(new Error('fragment.getState: range has no common container'));
- return; // do NOT connect return to previous callback, getState should return undefined
- }
-
- if (typeof renameChildren == 'function') {
- callback = renameChildren;
- renameChildren = false;
- }
+function _indexOfSubscriber(list, subscriber) {
+ var self = this;
+ return _.findIndex(list, function(subscr){
+ return subscriber.subscriber == subscr.subscriber
+ && subscriber.context == subscr.context
+ });
+}
- var frag = range.cloneContents()
- , wrapper = _wrapFragmentInContainer(frag);
- _transferStates(rangeContainer, wrapper);
- _.defer(function() {
- wrapper.broadcast('stateready');
- _.defer(function() {
- if (renameChildren) _renameChildren(wrapper);
- var wrapperState = wrapper.getState();
- wrapper.destroy();
- callback(null, wrapperState);
- });
- });
- } catch (err) {
- callback(err);
- }
-}
+/**
+ * Messenger instance method.
+ * Subscribes to multiple messages passed as map together with subscribers.
+ * Usage:
+ * ```
+ * myComp.events.onMessages({
+ * 'mousedown': onMouseDown,
+ * 'mouseup': onMouseUp
+ * });
+ * function onMouseDown(eventType, event) {}
+ * function onMouseUp(eventType, event) {}
+ * ```
+ * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was added.
+ * It is NOT possible to add pattern subscriber using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.
+ *
+ * @param {Object[Function]} messageSubscribers Map of message subscribers to be added
+ * @return {Object[Boolean]}
+ */
+function onMessages(messageSubscribers) {
+ check(messageSubscribers, Match.ObjectHash(Match.OneOf(Function, { subscriber: Function, context: Match.Any })));
+ var notYetRegisteredMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {
+ return this.on(messages, subscriber);
+ }, this);
-function _wrapFragmentInContainer(frag, wrapperClassName) {
- var wrapEl = document.createElement('div')
- , attr = new BindAttribute(wrapEl);
+ return notYetRegisteredMap;
+}
- _.extend(attr, {
- compClass: wrapperClassName || 'Component',
- compFacets: wrapperClassName ? [] : ['container'],
- compName: 'wrapper'
- });
- attr.decorate();
+/**
+ * Messenger instance method.
+ * Removes a subscriber for message(s). Removes all subscribers for the message if subscriber isn't passed.
+ * This method returns `true` if the subscriber was registered. No error or warning is thrown or logged if you remove subscriber that was not registered.
+ * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `off` when they proxy it.
+ * Usage:
+ * ```
+ * // unsubscribes onMouseUpDown from two DOM events.
+ * myComp.events.off('mousedown mouseup', onMouseUpDown);
+ * ```
+ * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.
+ *
+ * @param {String|Array[String]|RegExp} messages Message types that a subscriber should be removed for.
+ * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.
+ * If an array of strings is passed, each string is a message type to remove a subscriber for.
+ * If a RegExp is passed, the pattern subscriber will be removed.
+ * RegExp subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.
+ * @param {Function} subscriber Message subscriber - Optional function that will be removed from the list of subscribers for the message(s). If subscriber is not supplied, all subscribers will be removed from this message(s).
+ * @return {Boolean}
+ */
+function Messenger$off(messages, subscriber) {
+ check(messages, Match.OneOf(String, [String], RegExp));
+ check(subscriber, Match.Optional(Match.OneOf(Function, {
+ subscriber: Function,
+ context: Match.Any,
+ options: Match.Optional(Object),
+ // __messages: Match.Optional(Match.OneOf(String, [String], RegExp))
+ })));
- wrapEl.appendChild(frag);
- var scope = binder(wrapEl);
- return scope.wrapper;
+ return _Messenger_off.call(this, messages, subscriber);
}
-function _getRangeContainer(range) {
- var el = domUtils.containingElement(range.commonAncestorContainer);
- return Component.getContainingComponent(el, true, 'container');
+function _Messenger_off(messages, subscriber) {
+ return _eachMessage.call(this, '_removeSubscriber', messages, subscriber);
}
-function _transferStates(fromComp, toComp) {
- var fromScope = fromComp.container.scope;
- toComp.container.scope._each(function(toChildComp, name) {
- var fromChildComp = fromScope[name];
- if (! fromChildComp) return logger.error('fragment.getState: conponent', name, 'not found in range');
- var state = fromChildComp._getState(true);
- toChildComp.setState(state);
- });
-}
+/**
+ * "Private" Messenger instance method
+ * It is called by [off](#Messenger$off) to remove subscriber for one message type.
+ * Returns `true` if this subscriber was registered for this type of message.
+ * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.
+ *
+ * @private
+ * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
+ * @param {String} message Message type
+ * @param {Function} subscriber Subscriber function to be removed
+ * @return {Boolean}
+ */
+function _removeSubscriber(subscribersHash, message, subscriber) {
+ var msgSubscribers = subscribersHash[message];
+ if (! msgSubscribers || ! msgSubscribers.length)
+ return false; // nothing removed
+ if (subscriber) {
+ if (typeof subscriber == 'function')
+ subscriber = { subscriber: subscriber, context: this._hostObject };
-function _renameChildren(comp) {
- comp.container.scope._each(function(child) {
- child.rename();
- });
-}
+ var subscriberIndex = _indexOfSubscriber.call(this, msgSubscribers, subscriber);
+ if (subscriberIndex == -1)
+ return false; // nothing removed
+ msgSubscribers.splice(subscriberIndex, 1);
+ if (! msgSubscribers.length)
+ this._removeAllSubscribers(subscribersHash, message);
+ } else
+ this._removeAllSubscribers(subscribersHash, message);
-function expandRangeToSiblings(range) {
- var siblings = getRangeSiblings(range);
- range = createRangeFromSiblings(siblings);
- return range;
+ return true; // subscriber(s) removed
}
-function createRangeFromSiblings(nodes) {
- var range = document.createRange();
- if (nodes.siblings) {
- range.setStartBefore(nodes.start);
- range.setEndAfter(nodes.end);
- } else
- range.selectNode(nodes.start);
- return range;
+/**
+ * "Private" Messenger instance method
+ * It is called by [_removeSubscriber](#_removeSubscriber) to remove all subscribers for one message type.
+ * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified that all message subscribers were removed so it can unsubscribe from the source.
+ *
+ * @private
+ * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
+ * @param {String} message Message type
+ */
+function _removeAllSubscribers(subscribersHash, message) {
+ delete subscribersHash[message];
+ if (this._messageSource && typeof message == 'string')
+ this._messageSource.onSubscriberRemoved(message);
}
-function getRangeSiblings(range) {
- var containerNode = range.commonAncestorContainer
- , startNode = range.startContainer
- , endNode = range.endContainer;
+/**
+ * Messenger instance method.
+ * Unsubscribes from multiple messages passed as map together with subscribers.
+ * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was removed.
+ * If a subscriber for one of the messages is not supplied, all subscribers for this message will be removed.
+ * Usage:
+ * ```
+ * myComp.events.offMessages({
+ * 'mousedown': onMouseDown,
+ * 'mouseup': onMouseUp,
+ * 'click': undefined // all subscribers to this message will be removed
+ * });
+ * ```
+ * It is NOT possible to remove pattern subscriber(s) using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.
+ *
+ * @param {Object[Function]} messageSubscribers Map of message subscribers to be removed
+ * @return {Object[Boolean]}
+ */
+function offMessages(messageSubscribers) {
+ check(messageSubscribers, Match.ObjectHash(Match.Optional(Match.OneOf(Function, { subscriber: Function, context: Match.Any }))));
- if (startNode == endNode) {
- if (startNode != containerNode) logger.error('deleteSelectionCommand logical error: start==end, but container is different');
- return { siblings: false, start: startNode };
- }
+ var subscriberRemovedMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {
+ return this.off(messages, subscriber);
+ }, this);
- if (startNode == containerNode || endNode == containerNode)
- return { siblings: false, start: containerNode };
+ return subscriberRemovedMap;
+}
- var startSibling = _findContainingChild(containerNode, startNode);
- var endSibling = _findContainingChild(containerNode, endNode);
- if (startSibling && endSibling) {
- if (startSibling == endSibling) {
- logger.error('deleteSelectionCommand logical error: same siblings');
- return { siblings: false, start: startSibling };
- } else
- return { siblings: true, start: startSibling, end: endSibling };
- }
-}
-
-
-function _findContainingChild(containerNode, selNode) {
- return _.find(containerNode.childNodes, function(node) {
- return node.contains(selNode);
- });
+/**
+ * Unsubscribes all subscribers
+ */
+function Messenger$offAll() {
+ _offAllSubscribers.call(this, this._patternMessageSubscribers);
+ _offAllSubscribers.call(this, this._messageSubscribers);
}
-function _createNodesAndPathsFunc(func) {
- return function(rootEl, fromObj) {
- var toObj = {
- siblings: fromObj.siblings,
- start: func(rootEl, fromObj.start)
- };
- if (toObj.siblings)
- toObj.end = func(rootEl, fromObj.end);
- return toObj;
- };
+function _offAllSubscribers(subscribersHash) {
+ _.eachKey(subscribersHash, function(subscribers, message) {
+ this._removeAllSubscribers(subscribersHash, message);
+ }, this);
}
+// TODO - send event to messageSource
-},{"../attributes/a_bind":5,"../binder":9,"../components/c_class":16,"./check":90,"./dom":94,"./logger":102,"mol-proto":150}],100:[function(require,module,exports){
-'use strict';
/**
- * `milo.util`
+ * Messenger instance method.
+ * Dispatches the message calling all subscribers registered for this message and, if the message is a string, calling all pattern subscribers when message matches the pattern.
+ * Each subscriber is passed the same parameters that are passed to theis method.
+ * The context of the subscriber envocation is set to the host object (`this._hostObject`) that was passed to the messenger constructor.
+ * Subscribers are called in the next tick ("asynchronously") apart from those that were subscribed with `onSync` (or that have `options.sync == true`).
+ *
+ * @param {String|RegExp} message message to be dispatched
+ * If the message is a string, the subscribers registered with exactly this message will be called and also pattern subscribers registered with the pattern that matches the dispatched message.
+ * If the message is RegExp, only the subscribers registered with exactly this pattern will be called.
+ * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
+ * @param {Function} callback optional callback to pass to subscriber
+ * @param {Boolean} _synchronous if true passed, subscribers will be envoked synchronously apart from those that have `options.sync == false`. This parameter should not be used, instead postMessageSync should be used.
*/
-var util = {
- logger: require('./logger'),
- request: require('./request'),
- websocket: require('./websocket'),
- check: require('./check'),
- error: require('./error'),
- count: require('./count'), // deprecated
- uniqueId: require('./count'),
- componentName: require('./component_name'),
- dom: require('./dom'),
- domListeners: require('./dom_listeners'),
- selection: require('./selection'),
- fragment: require('./fragment'),
- jsonParse: require('./json_parse'),
- storage: require('./storage'),
- domReady: require('./domready'),
- dragDrop: require('./dragdrop'),
- dialog: require('../components/ui/bootstrap/Dialog'),
- alert: require('../components/ui/bootstrap/Alert'),
- doT: require('dot'),
- destroy: util_destroy
-};
+function postMessage(message, data, callback, _synchronous) {
+ check(message, Match.OneOf(String, RegExp));
+ check(callback, Match.Optional(Function));
-module.exports = util;
+ var subscribersHash = this._chooseSubscribersHash(message);
+ var msgSubscribers = subscribersHash[message];
+ this._callSubscribers(message, data, callback, msgSubscribers, _synchronous);
-function util_destroy() {
- util.request.destroy();
- util.dragDrop.destroy();
+ if (typeof message == 'string')
+ this._callPatternSubscribers(message, data, callback, msgSubscribers, _synchronous);
}
-},{"../components/ui/bootstrap/Alert":62,"../components/ui/bootstrap/Dialog":63,"./check":90,"./component_name":91,"./count":92,"./dom":94,"./dom_listeners":95,"./domready":96,"./dragdrop":97,"./error":98,"./fragment":99,"./json_parse":101,"./logger":102,"./request":104,"./selection":105,"./storage":106,"./websocket":109,"dot":115}],101:[function(require,module,exports){
-'use strict';
-
-
-module.exports = jsonParse;
-
/**
- * `milo.util.jsonParse`
- * Safe JSON.parse, returns undefined if JSON.parse throws an exception
+ * Same as postMessage apart from envoking subscribers synchronously, apart from those subscribed with `onAsync` (or with `options.sync == false`).
*
- * @param {String} str - JSON string representation of object
- * @return {Object|undefined}
+ * @param {String|RegExp} message
+ * @param {Any} data
+ * @param {Function} callback
*/
-function jsonParse(str) {
- try {
- return JSON.parse(str);
- } catch (e) {}
+function postMessageSync(message, data, callback) {
+ this.postMessage(message, data, callback, true);
}
-},{}],102:[function(require,module,exports){
-'use strict';
-
-//
-// milo.utils.logger
-// -----------
-
-// Application logger that has error, warn, info and debug
-// methods, that can be suppressed by setting log level.
-// Properties:
+/**
+ * "Private" Messenger instance method
+ * Envokes pattern subscribers with the pattern that matches the message.
+ * The method is called by [postMessage](#postMessage) - see more information there.
+ *
+ * @private
+ * @param {String} message message to be dispatched. Pattern subscribers registered with the pattern that matches the dispatched message will be called.
+ * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
+ * @param {Function} callback optional callback to pass to subscriber
+ * @param {Array[Function|Object]} calledMsgSubscribers array of subscribers already called, they won't be called again if they are among pattern subscribers.
+ */
+function _callPatternSubscribers(message, data, callback, calledMsgSubscribers, _synchronous) {
+ _.eachKey(this._patternMessageSubscribers,
+ function(patternSubscribers) {
+ var pattern = patternSubscribers.pattern;
+ if (pattern.test(message)) {
+ if (calledMsgSubscribers) {
+ var patternSubscribers = patternSubscribers.filter(function(subscriber) {
+ var index = _indexOfSubscriber.call(this, calledMsgSubscribers, subscriber);
+ return index == -1;
+ });
+ }
+ this._callSubscribers(message, data, callback, patternSubscribers, _synchronous);
+ }
+ }
+ , this);
+}
-// - level
-// - 0 - error
-// - 1 - warn
-// - 2 - info
-// - 3 - debug (default)
+/**
+ * "Private" Messenger instance method
+ * Envokes subscribers from the passed list.
+ * The method is called by [postMessage](#postMessage) and [_callPatternSubscribers](#_callPatternSubscribers).
+ *
+ * @private
+ * @param {String} message message to be dispatched, passed to subscribers as the first parameter.
+ * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
+ * @param {Array[Function|Object]} msgSubscribers the array of message subscribers to be called. Each subscriber is called with the host object (see Messenger constructor) as the context.
+ * @param {Function} callback optional callback to pass to subscriber
+ */
+function _callSubscribers(message, data, callback, msgSubscribers, _synchronous) {
+ if (msgSubscribers && msgSubscribers.length) {
+ // cloning is necessary as some of the subscribers
+ // can be unsubscribed during the dispatch
+ // so this array would change in the process
+ msgSubscribers = msgSubscribers.slice();
-// - enabled
+ msgSubscribers.forEach(function(subscriber) {
+ this._callSubscriber(subscriber, message, data, callback, _synchronous);
+ }, this);
+ }
+}
-// true by default. Set to false to disable all logging in browser console.
+function _callSubscriber(subscriber, message, data, callback, _synchronous) {
+ var syncSubscriber = subscriber.options && subscriber.options.sync
+ , synchro = (_synchronous && syncSubscriber !== false)
+ || syncSubscriber;
-var Logger = require('./logger_class');
+ var dispatchTimes = subscriber.options && subscriber.options.dispatchTimes;
+ if (dispatchTimes) {
+ if (dispatchTimes <= 1) {
+ var messages = subscriber.__messages;
+ this.off(messages, subscriber);
+ } else if (dispatchTimes > 1)
+ subscriber.options.dispatchTimes--;
+ }
-var logger = new Logger({ level: 3 });
+ if (synchro)
+ subscriber.subscriber.call(subscriber.context, message, data, callback);
+ else
+ _.deferMethod(subscriber.subscriber, 'call', subscriber.context, message, data, callback);
+}
-module.exports = logger;
-},{"./logger_class":103}],103:[function(require,module,exports){
-'use strict';
+/**
+ * Messenger instance method.
+ * Returns the array of subscribers that would be called if the message were dispatched.
+ * If `includePatternSubscribers === false`, pattern subscribers with matching patters will not be included (by default they are included).
+ * If there are no subscribers to the message, `undefined` will be returned, not an empty array, so it is safe to use the result in boolean tests.
+ *
+ * @param {String|RegExp} message Message to get subscribers for.
+ * If the message is RegExp, only pattern subscribers registered with exactly this pattern will be returned.
+ * If the message is String, subscribers registered with the string messages and pattern subscribers registered with matching pattern will be returned (unless the second parameter is false).
+ * @param {Boolean} includePatternSubscribers Optional false to prevent inclusion of patter subscribers, by default they are included.
+ * @return {Array|undefined}
+ */
+function getSubscribers(message, includePatternSubscribers) {
+ check(message, Match.OneOf(String, RegExp));
-// ### Logger Class
+ var subscribersHash = this._chooseSubscribersHash(message);
+ var msgSubscribers = subscribersHash[message]
+ ? [].concat(subscribersHash[message])
+ : [];
-// Properties:
+ // pattern subscribers are incuded by default
+ if (includePatternSubscribers !== false && typeof message == 'string') {
+ _.eachKey(this._patternMessageSubscribers,
+ function(patternSubscribers) {
+ var pattern = patternSubscribers.pattern;
+ if (patternSubscribers && patternSubscribers.length
+ && pattern.test(message))
+ _.appendArray(msgSubscribers, patternSubscribers);
+ }
+ );
+ }
-// - level
+ // return undefined if there are no subscribers
+ return msgSubscribers.length
+ ? msgSubscribers
+ : undefined;
+}
-// - 0 - error
-// - 1 - warn
-// - 2 - info
-// - 3 - debug (default)
-// - enabled
+/**
+ * "Private" Messenger instance method
+ * Returns the map of subscribers for a given message type.
+ *
+ * @private
+ * @param {String|RegExp} message Message to choose the map of subscribers for
+ * @return {Object[Function]}
+ */
+function _chooseSubscribersHash(message) {
+ return message instanceof RegExp
+ ? this._patternMessageSubscribers
+ : this._messageSubscribers;
+}
-// true by default. Set to false to disable all logging in browser console.
+/**
+ * Messenger instance method
+ * Sets [MessageSource](./m_source.js.html) for the messenger also setting the reference to the messenger in the MessageSource.
+ * MessageSource can be passed to message constructor; this method allows to set it at a later time. For example, the subclasses of [ComponentFacet](../components/c_facet.js.html) use this method to set different MessageSource'es in the messenger that is created by ComponentFacet.
+ * Currently the method is implemented in such way that it can be called only once - MessageSource cannot be changed after this method is called.
+ *
+ * @param {MessageSource} messageSource an instance of MessageSource class to attach to this messenger (and to have this messenger attached to it too)
+ */
+function _setMessageSource(messageSource) {
+ check(messageSource, MessageSource);
-var _ = require('mol-proto');
+ _.defineProperty(this, '_messageSource', messageSource);
+ messageSource.messenger = this;
+}
/**
- * Log levels.
+ * Messenger instance method
+ * Returns messenger MessageSource
+ *
+ * @return {MessageSource}
*/
+function getMessageSource() {
+ return this._messageSource
+}
-var levels = [
- 'error',
- 'warn',
- 'info',
- 'debug'
-];
+},{"../abstract/mixin":97,"../util/check":116,"./m_source":103,"mol-proto":122}],101:[function(require,module,exports){
+'use strict';
+
+var _ = require('mol-proto')
+ , logger = require('../util/logger');
+
+
+module.exports = MessengerAPI;
-var maxLevelLength = Math.max.apply(Math, levels.map(function(level) { return level.length; }));
/**
- * Colors for log levels.
+ * `milo.classes.MessengerAPI`
+ * Base class, subclasses of which can supplement the functionality of [MessageSource](./m_source.js.html) by implementing three methods:
+ *
+ * - `translateToSourceMessage` to translate source messages (recieved from external source via `MessageSOurce`) to internal messages (that are dispatched on Messenger), allowing to make internal messages more detailed than source messages. For example, [Data facet](../components/c_facets/Data.js.html) uses [DataMsgAPI](../components/msg_api/data.js.html) to define several internal messages related to the change of state in contenteditable DOM element.
+ * - `createInternalData` to modify message data received from source to some more meaningful or more detailed message data that will be dispatched on Messenger. For example, [Data facet](../components/c_facets/Data.js.html) uses [DataMsgAPI](../components/msg_api/data.js.html) (subclass of MessengerAPI) to translate DOM messages to data change messages.
+ * - `filterSourceMessage` to enable/disable message dispatch based on some conditions in data.
+ *
+ * If `MessageSource` constructor is not passed an instance of some subclass of `MessengerAPI`, it automatically creates an instance of MessengerAPI that defines all 3 of those methods in a trivial way. See these methods below for their signatures.
+ *
+ * @constructor
+ * @this {MessengerAPI}
+ * @return {MessengerAPI}
*/
+function MessengerAPI() {
+ if (this.init)
+ this.init.apply(this, arguments);
+}
-var colors = [
- 31,
- 33,
- 36,
- 90
-];
/**
- * Pads the nice output to the longest log level.
+ * ####MessengerAPI instance methods####
+ *
+ * - [init](#init) - initializes MessengerAPI
+ * - [addInternalMessage](#addInternalMessage) - adds internal message
+ * - [removeInternalMessage](#removeInternalMessage) - removes internal message
+ * - [getInternalMessages](#getInternalMessages) - returns the list of internal messages for given source message
+ *
+ * These methods should be redefined by subclass:
+ *
+ * - [translateToSourceMessage](#translateToSourceMessage) - converts internal message type to source (external) message type
+ * - [createInternalData](#createInternalData) - converts source message data received via MessageSource to internal message data
+ * - [filterSourceMessage](#filterSourceMessage) - filters source message based on the data of the message and the corresponding internal message that is about to be sent on Messenger
*/
-function pad(str) {
- if (str.length < maxLevelLength)
- return str + new Array(maxLevelLength - str.length + 1).join(' ');
+_.extendProto(MessengerAPI, {
+ init: init,
+ destroy: MessengerAPI$destroy,
+ addInternalMessage: addInternalMessage,
+ removeInternalMessage: removeInternalMessage,
+ getInternalMessages: getInternalMessages,
- return str;
-};
+ // should be redefined by subclass
+ translateToSourceMessage: translateToSourceMessage,
+ createInternalData: createInternalData,
+ filterSourceMessage: filterSourceMessage
+});
-function colored(str, color) {
- return '\x1B[' + color + 'm' + str + ' -\x1B[39m';
+/**
+ * MessengerAPI instance method
+ * Called by MessengerAPI constructor. Subclasses that re-implement `init` method should call this method using: `MessengerAPI.prototype.init.apply(this, arguments)`
+ */
+function init() {
+ _.defineProperty(this, '_internalMessages', {});
}
-var DEFAULT_OPTIONS = {
- level: 3,
- throwLevel: -1, // never throw
- enabled: true,
- logPrefix: ''
+/**
+ * Destroys messenger API
+ */
+function MessengerAPI$destroy() {
+
}
/**
- * Logger (console).
+ * MessengerAPI instance method
+ * Translates internal `message` to source message, adds internal `message` to the list, making sure the same `message` wasn't passed before (it would indicate Messenger error).
+ * Returns source message if it is used first time (so that `MessageSource` subcribes to this source message) or `undefined`.
*
- * @api public
+ * @param {String} message internal message to be translated and added
+ * @return {String|undefined}
*/
-var Logger = function (opts) {
- _.extend(this, DEFAULT_OPTIONS);
- _.extend(this, opts || {});
-};
+function addInternalMessage(message) {
+ var internalMsgs
+ , sourceMessage = this.translateToSourceMessage(message);
+
+ if (typeof sourceMessage == 'undefined') return;
+
+ if (this._internalMessages.hasOwnProperty(sourceMessage)) {
+ internalMsgs = this._internalMessages[sourceMessage];
+ if (internalMsgs.indexOf(message) == -1)
+ internalMsgs.push(message);
+ else
+ logger.warn('Duplicate addInternalMessage call for internal message ' + message);
+ } else {
+ internalMsgs = this._internalMessages[sourceMessage] = [];
+ internalMsgs.push(message);
+ return sourceMessage;
+ }
+}
/**
- * Log method.
+ * MessengerAPI instance method
+ * Removes internal `message` from the list connected to corresponding source message (`translateToSourceMessage` is used for translation).
+ * Returns source message, if the last internal message was removed (so that `MessageSource` can unsubscribe from this source message), or `undefined`.
*
- * @api public
+ * @param {String} message internal message to be translated and removed
+ * @return {String|undefined}
*/
+function removeInternalMessage(message) {
+ var sourceMessage = this.translateToSourceMessage(message);
-Logger.prototype.log = function (type) {
- var index = levels.indexOf(type);
+ if (typeof sourceMessage == 'undefined') return;
- if (! this.enabled || index > this.level)
- return this;
+ var internalMsgs = this._internalMessages[sourceMessage];
- var args = _.slice(arguments, 1);
+ if (internalMsgs && internalMsgs.length) {
+ var messageIndex = internalMsgs.indexOf(message);
+ if (messageIndex >= 0) {
+ internalMsgs.splice(messageIndex, 1);
+ if (internalMsgs.length == 0) {
+ delete this._internalMessages[sourceMessage];
+ return sourceMessage;
+ }
+ } else
+ unexpectedNotificationWarning();
+ } else
+ unexpectedNotificationWarning();
- if (index <= this.throwLevel)
- throw new Error([this.logPrefix, type + ':'].concat(args).join(' '));
- console.log.apply(
- console
- , [ this.logPrefixColor
- ? ' ' + colored(this.logPrefix, this.logPrefixColor)
- : this.logPrefix,
- (this.colors
- ? ' ' + colored(pad(type), colors[index])
- : type) + ':'
- ].concat(args)
- );
+ function unexpectedNotificationWarning() {
+ logger.warn('notification received: un-subscribe from internal message ' + message
+ + ' without previous subscription notification');
+ }
+}
- return this;
-};
/**
- * Generate methods.
+ * MessengerAPI instance method
+ * Returns the array of internal messages that were translated to given `sourceMessage`.
+ * This method is used by `MessageSource` to dispatch source message on the `Mesenger`.
+ *
+ * @param {String} sourceMessage source message
+ * @return {Array[String]}
*/
+function getInternalMessages(sourceMessage) {
+ return this._internalMessages[sourceMessage];
+}
-levels.forEach(function (name) {
- Logger.prototype[name] = function () {
- this.log.apply(this, [name].concat(_.toArray(arguments)));
- };
-});
-
-
-module.exports = Logger;
-},{"mol-proto":150}],104:[function(require,module,exports){
-'use strict';
+/**
+ * MessengerAPI instance method
+ * Subclasses should re-implement this method to define the rule for translation of internal `message` to source message. This class simply returns the same `message`.
+ *
+ * @param {String} message internal message to be translated
+ * @return {String}
+ */
+function translateToSourceMessage(message) {
+ return message
+}
-// milo.utils.request
-// -----------
-// Convenience functions wrapping XMLHTTPRequest functionality.
+/**
+ * MessengerAPI instance method
+ * Subclasses should re-implement this method to define the rule for translation of source message data to internal message data. This class simply returns the same `sourceData`.
+ * This method is used in [dispatchMessage](./m_source.js.html#dispatchMessage) method of `MessageSource`.
+ *
+ * @param {String} sourceMessage source message, can be used in translation rule
+ * @param {String} message internal message, can be used in translation rule
+ * @param {Object} sourceData data received from source that has to be translated to data that will be sent to internal Messenger subscriber
+ * @return {Object}
+ */
+function createInternalData(sourceMessage, message, sourceData) {
+ return sourceData;
+}
-// ```
-// var request = milo.utils.request
-// , opts: { method: 'GET' };
-// request(url, opts, function(err, data) {
-// logger.debug(data);
-// });
+/**
+ * MessengerAPI instance method
+ * Subclasses should re-implement this method to define the dispatch filter for internal messages. This method should return `true` to allow and `false` to prevent internal message dispatch. This class always returns `true`.
+ * This method is used in [dispatchMessage](./m_source.js.html#dispatchMessage) method of `MessageSource`.
+ *
+ * @param {String} sourceMessage source message, can be used in filter rule
+ * @param {String} message internal message, can be used in filter rule
+ * @param {Object} internalData data translated by `createInternalData` method from source data, can be used in filter rule
+ * @return {Boolean}
+ */
+function filterSourceMessage(sourceMessage, message, internalData) {
+ return true;
+}
-// request.get(url, function(err, data) {
-// logger.debug(data);
-// });
-// ```
+},{"../util/logger":118,"mol-proto":122}],102:[function(require,module,exports){
+'use strict';
-// Only generic request and get, json, post convenience methods are currently implemented.
+var MessengerAPI = require('./m_api')
+ , _ = require('mol-proto');
-var _ = require('mol-proto')
- , count = require('./count')
- , config = require('../config')
- , logger = require('./logger')
- , Messenger = require('../messenger');
+/**
+ * A generic subsclass of [MessengerAPI](./m_api.js.html) that supports pattern subscriptions to source.
+ * Can be useful if the source is another Messenger.
+ */
+ var MessengerRegexpAPI = _.createSubclass(MessengerAPI, 'MessengerRegexpAPI');
-module.exports = request;
+ module.exports = MessengerRegexpAPI;
-var _pendingRequests = [];
+_.extendProto(MessengerRegexpAPI, {
+ init: init,
+ addInternalMessage: addInternalMessage,
+ removeInternalMessage: removeInternalMessage,
+ getInternalMessages: getInternalMessages
+});
-var promiseThen = createPromiseOverride('then');
-var promiseCatch = createPromiseOverride('catch');
/**
- * Creates a function which is used to override standard promise behaviour and allow promise instances
- * created to maintain a reference to the request object no matter if .then() or .catch() is called.
+ * MessengerRegexpAPI instance method
+ * Called by MessengerRegexpAPI constructor.
*/
-function createPromiseOverride(functionName) {
- return function() {
- var promise = Promise.prototype[functionName].apply(this, arguments);
- keepRequestObject(promise, this._request);
- return promise;
- }
+function init() {
+ MessengerAPI.prototype.init.apply(this, arguments);
+ _.defineProperties(this, {
+ _patternInternalMessages: {}
+ });
+ this._catchAllSubscribed = false;
}
-function request(url, opts, callback) {
- opts.url = url;
- opts.contentType = opts.contentType || 'application/json;charset=UTF-8';
- if (_messenger) request.postMessageSync('request', { options: opts });
-
- var req = new XMLHttpRequest();
- req.open(opts.method, opts.url, true);
- req.setRequestHeader('Content-Type', opts.contentType);
- setRequestHeaders(req, opts.headers);
-
- req.timeout = opts.timeout || config.request.defaults.timeout;
- req.onreadystatechange = req.ontimeout = req.onabort = onReady;
-
- var xPromise = _createXPromise(req);
-
- req.send(JSON.stringify(opts.data));
- req[config.request.optionsKey] = opts;
-
- _pendingRequests.push(req);
-
- return xPromise.promise;
-
- function onReady(e) {
- _onReady(req, callback, xPromise, e.type);
+/**
+ * MessengerRegexpAPI instance method
+ * Augments MessengerAPI method by storing regexp
+ *
+ * @param {String} message internal message to be translated and added
+ * @return {String|RegExp|undefined}
+ */
+function addInternalMessage(message) {
+ var sourceMessage = MessengerAPI.prototype.addInternalMessage.apply(this, arguments);
+
+ // store regexp itself if sourceMessage is regexp
+ if (sourceMessage && sourceMessage instanceof RegExp) {
+ this._internalMessages[sourceMessage].pattern = sourceMessage;
+ this._patternInternalMessages[sourceMessage] = this._internalMessages[sourceMessage];
+ if (this._catchAllSubscribed) return;
+ this._catchAllSubscribed = true;
+ return /.*/;
}
-}
+ return sourceMessage;
+}
-function _createXPromise(request) {
- var resolvePromise, rejectPromise;
- var promise = new Promise(function(resolve, reject) {
- resolvePromise = resolve;
- rejectPromise = reject;
- });
- keepRequestObject(promise, request);
- promise.catch(_.noop); // Sometimes errors are handled within callbacks, so uncaught promise error message should be suppressed.
+/**
+ * MessengerRegexpAPI instance method
+ * Augments MessengerAPI method by removing regexp subscirption
+ *
+ * @param {String} message internal message to be translated and added
+ * @return {String|RegExp|undefined}
+ */
+function removeInternalMessage(message) {
+ var sourceMessage = MessengerAPI.prototype.removeInternalMessage.apply(this, arguments);
- return {
- promise: promise,
- resolve: resolvePromise,
- reject: rejectPromise
+ if (sourceMessage && sourceMessage instanceof RegExp) {
+ delete this._patternInternalMessages[sourceMessage];
+ var noPatternInternalMessages = ! Object.keys(this._patternInternalMessages).length;
+ if (noPatternInternalMessages) {
+ this._catchAllSubscribed = false;
+ return /.*/;
+ }
}
+
+ return sourceMessage;
}
-// Ensures that the promise (and any promises created when calling .then/.catch) has a reference to the original request object
-function keepRequestObject(promise, request) {
- promise._request = request;
- promise.then = promiseThen;
- promise.catch = promiseCatch;
- return promise;
-}
+/**
+ * MessengerAPI instance method
+ * Augments MessengerAPI method by returning messages subscribed with regexp
+ * This method is used by `MessageSource` to dispatch source message on the `Mesenger`.
+ *
+ * @param {String|RegExp} sourceMessage source message
+ * @return {Array[String]}
+ */
+function getInternalMessages(sourceMessage) {
+ var internalMessages = MessengerAPI.prototype.getInternalMessages.apply(this, arguments);
+ // add internal messages for regexp source subscriptions
+ if (typeof sourceMessage == 'string') {
+ internalMessages = internalMessages || [];
+ var internalMessagesHash = _.object(internalMessages, true);
-function setRequestHeaders(req, headers) {
- if (headers)
- _.eachKey(headers, function(value, key) {
- req.setRequestHeader(key, value);
+ _.eachKey(this._patternInternalMessages, function(patternMessages) {
+ var sourcePattern = patternMessages.pattern;
+
+ if (sourcePattern.test(sourceMessage))
+ patternMessages.forEach(function(message) {
+ if (internalMessagesHash[message]) return;
+ internalMessages.push(message);
+ internalMessagesHash[message] = true;
+ });
});
-}
+ }
-function _onReady(req, callback, xPromise, eventType) {
- if (req.readyState != 4) return;
- if (!req.status && eventType == 'readystatechange') return;
+ return internalMessages;
+}
- _.spliceItem(_pendingRequests, req);
+},{"./m_api":101,"mol-proto":122}],103:[function(require,module,exports){
+'use strict';
- var error;
- try {
- if ( req.status >= 200 && req.status < 400 ) {
- try {
- postMessage('success');
- callback && callback(null, req.responseText, req);
- } catch(e) { error = e; }
- xPromise.resolve(req.responseText);
- }
- else {
- var errorReason = req.status || eventType;
- try {
- postMessage('error');
- postMessage('error' + errorReason);
- callback && callback(errorReason, req.responseText, req);
- } catch(e) { error = e; }
- xPromise.reject({ reason: errorReason, response: req.responseText });
- }
- } catch(e) {
- error = error || e;
- }
+var Mixin = require('../abstract/mixin')
+ , MessengerAPI = require('./m_api')
+ , logger = require('../util/logger')
+ , _ = require('mol-proto')
+ , check = require('../util/check')
+ , Match = check.Match;
- // not removing subscription creates memory leak, deleting property would not remove subscription
- req.onreadystatechange = req.ontimeout = req.onabort = undefined;
- if (!_pendingRequests.length)
- postMessage('requestscompleted');
+/**
+ * `milo.classes.MessageSource`
+ * An abstract class (subclass of [Mixin](../abstract/mixin.js.html)) for connecting [Messenger](./index.js.html) to external sources of messages (like DOM events) and defining higher level messages.
+ * An instance of MessageSource can either be passed to Messenger constructor or later using `_setMessageSource` method of Messenger. Once set, MessageSource of Messenger cannot be changed.
+ */
+var MessageSource = _.createSubclass(Mixin, 'MessageSource', true);
- if (error) throw new Error('Exception: ' + error);
+module.exports = MessageSource;
- function postMessage(msg) {
- if (_messenger) request.postMessage(msg,
- { status: status, response: req.responseText });
- }
-}
+/**
+ * ####MessageSource instance methods####
+ *
+ * - [init](#init) - initializes messageSource - called by Mixin superclass
+ * - [setMessenger](#setMessenger) - connects Messenger to MessageSource, is called from `init` or `_setMessageSource` methods of [Messenger](./index.js.html).
+ * - [onSubscriberAdded](#onSubscriberAdded) - called by Messenger to notify when the first subscriber for an internal message was added, so MessageSource can subscribe to source
+ * - [onSubscriberRemoved](#onSubscriberRemoved) - called by Messenger to notify when the last subscriber for an internal message was removed, so MessageSource can unsubscribe from source
+ * - [dispatchMessage](#dispatchMessage) - dispatches source message. MessageSource subclass should implement mechanism when on actual source message this method is called.
+ *
+ * Methods below should be implemented in subclass:
+ *
+ * - [trigger](#trigger) - triggers messages on the source (an optional method)
+ * - [addSourceSubscriber](#addSourceSubscriber) - adds listener/subscriber to external message
+ * - [removeSourceSubscriber](#removeSourceSubscriber) - removes listener/subscriber from external message
+ */
+_.extendProto(MessageSource, {
+ init: init,
+ destroy: MessageSource$destroy,
+ setMessenger: setMessenger,
+ onSubscriberAdded: onSubscriberAdded,
+ onSubscriberRemoved: onSubscriberRemoved,
+ dispatchMessage: dispatchMessage,
+ postMessage: postMessage,
+ _prepareMessengerAPI: _prepareMessengerAPI,
-_.extend(request, {
- get: request$get,
- post: request$post,
- json: request$json,
- jsonp: request$jsonp,
- file: request$file,
- useMessenger: request$useMessenger,
- destroy: request$destroy,
- whenRequestsCompleted: whenRequestsCompleted
+ // Methods below must be implemented in subclass
+ trigger: toBeImplemented,
+ addSourceSubscriber: toBeImplemented,
+ removeSourceSubscriber: toBeImplemented
});
-var _messenger;
-
-
-function request$useMessenger() {
- _messenger = new Messenger(request, ['on', 'once', 'onSync', 'off', 'onMessages', 'offMessages', 'postMessage', 'postMessageSync']);
+/**
+ * MessageSource instance method.
+ * Called by Mixin constructor.
+ * MessageSource constructor should be passed the same parameters as this method signature.
+ * If an instance of [MessengerAPI](./m_api.js.html) is passed as the third parameter, it extends MessageSource functionality to allow it to define new messages, to filter messages based on their data and to change message data. See [MessengerAPI](./m_api.js.html).
+ *
+ * @param {Object} hostObject Optional object that stores the MessageSource on one of its properties. It is used to proxy methods of MessageSource.
+ * @param {Object[String]} proxyMethods Optional map of method names; key - proxy method name, value - MessageSource's method name.
+ * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI.
+ */
+function init(hostObject, proxyMethods, messengerAPI) {
+ this._prepareMessengerAPI(messengerAPI);
}
-function request$get(url, callback) {
- return request(url, { method: 'GET' }, callback);
+/**
+ * Destroys message source
+ */
+function MessageSource$destroy() {
+ if (this.messengerAPI)
+ this.messengerAPI.destroy();
}
-function request$post(url, data, callback) {
- return request(url, { method: 'POST', data: data }, callback);
+/**
+ * MessageSource instance method.
+ * Sets reference to Messenger instance.
+ *
+ * @param {Messenger} messenger reference to Messenger instance linked to this MessageSource
+ */
+function setMessenger(messenger) {
+ _.defineProperty(this, 'messenger', messenger);
}
-function request$json(url, callback) {
- var promise = request(url, { method: 'GET' });
-
- var jsonPromise = promise.then(JSON.parse);
-
- if (callback)
- jsonPromise
- .then(function(data) { callback(null, data); })
- .catch(function(errData) { callback(errData.reason, errData.response); });
-
- return jsonPromise;
-}
-
-
-var jsonpOptions = { method: 'GET', jsonp: true };
-function request$jsonp(url, callback) {
- var script = document.createElement('script'),
- xPromise = _createXPromise(script),
- head = window.document.head,
- uniqueCallback = config.request.jsonpCallbackPrefix + count();
-
- var opts = _.extend({ url: url }, jsonpOptions);
- if (_messenger) request.postMessageSync('request', { options: opts });
-
- if (! _.isEqual(_.omitKeys(opts, 'url'), jsonpOptions))
- logger.warn('Ignored not allowed request options change in JSONP request - only URL can be changed');
-
- var timeout = setTimeout(function() {
- var err = new Error('No JSONP response or no callback in response');
- _onResult(err);
- }, config.request.jsonpTimeout);
-
- window[uniqueCallback] = _.partial(_onResult, null);
-
- _pendingRequests.push(window[uniqueCallback]);
-
- script.type = 'text/javascript';
- script.src = opts.url + (opts.url.indexOf('?') == -1 ? '?' : '&') + 'callback=' + uniqueCallback;
-
- head.appendChild(script);
-
- return xPromise.promise;
-
-
- function _onResult(err, result) {
- _.spliceItem(_pendingRequests, window[uniqueCallback]);
- try {
- postMessage(err ? 'error' : 'success', err, result);
- if (err) {
- logger.error('No JSONP response or timeout');
- postMessage('errorjsonptimeout', err);
- }
- callback && callback(err, result);
- }
- catch(e) { var error = e; }
- if (err) xPromise.reject(err);
- else xPromise.resolve(result);
-
- cleanUp();
- if (!_pendingRequests.length)
- postMessage('requestscompleted');
-
- if (error) throw error;
- }
-
-
- function cleanUp() {
- clearTimeout(timeout);
- head.removeChild(script);
- delete window[uniqueCallback];
- }
+/**
+ * MessageSource instance method.
+ * Prepares [MessengerAPI](./m_api.js.html) passed to constructor by proxying its methods to itself or if MessengerAPI wasn't passed defines two methods to avoid checking their availability every time the message is dispatched.
+ *
+ * @private
+ * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI
+ */
+function _prepareMessengerAPI(messengerAPI) {
+ check(messengerAPI, Match.Optional(MessengerAPI));
+ if (! messengerAPI)
+ messengerAPI = new MessengerAPI;
- function postMessage(msg, status, result) {
- if (_messenger) request.postMessage(msg,
- { status: status, response: result });
- }
+ _.defineProperty(this, 'messengerAPI', messengerAPI);
}
-function request$file(opts, fileData, callback, progress) {
- if (typeof opts == 'string')
- opts = { method: 'POST', url: opts };
-
- opts.method = opts.method || 'POST';
- opts.file = true;
-
- if (_messenger) request.postMessageSync('request', { options: opts });
-
- var req = new XMLHttpRequest();
- if (progress) req.upload.onprogress = progress;
-
- req.open(opts.method, opts.url, true);
- setRequestHeaders(req, opts.headers);
+/**
+ * MessageSource instance method.
+ * Subscribes to external source using `addSourceSubscriber` method that should be implemented in subclass.
+ * This method is called by [Messenger](./index.js.html) when the first subscriber to the `message` is added.
+ * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.addInternalMessage` will return undefined if this `sourceMessage` was already subscribed to to prevent duplicate subscription.
+ *
+ * @param {String} message internal Messenger message that has to be subscribed to at the external source of messages.
+ */
+function onSubscriberAdded(message) {
+ var newSourceMessage = this.messengerAPI.addInternalMessage(message);
+ if (typeof newSourceMessage != 'undefined')
+ this.addSourceSubscriber(newSourceMessage);
+}
- req.timeout = opts.timeout || config.request.defaults.timeout;
- req.onreadystatechange = req.ontimeout = req.onabort = onReady;
- var xPromise = _createXPromise(req);
+/**
+ * MessageSource instance method.
+ * Unsubscribes from external source using `removeSourceSubscriber` method that should be implemented in subclass.
+ * This method is called by [Messenger](./index.js.html) when the last subscriber to the `message` is removed.
+ * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.removeInternalMessage` will return undefined if this `sourceMessage` was not yet subscribed to to prevent unsubscription without previous subscription.
+ *
+ * @param {String} message internal Messenger message that has to be unsubscribed from at the external source of messages.
+ */
+function onSubscriberRemoved(message) {
+ var removedSourceMessage = this.messengerAPI.removeInternalMessage(message);
+ if (typeof removedSourceMessage != 'undefined')
+ this.removeSourceSubscriber(removedSourceMessage);
+}
- if (opts.binary)
- req.send(fileData);
- else {
- var formData = new FormData();
- formData.append('file', fileData);
- req.send(formData);
- }
- _pendingRequests.push(req);
+/**
+ * MessageSource instance method.
+ * Dispatches sourceMessage to Messenger.
+ * Mechanism that calls this method when the source message is received should be implemented by subclass (see [DOMEventsSource](../components/msg_src/dom_events.js.html) for example).
+ * Delegates to supplied or default [MessengerAPI](./m_api.js.html) to create internal message data (`createInternalData`) and to filter the message based on its data and/or message (`filterSourceMessage`).
+ * Base MessengerAPI class implements these two methods in a trivial way (`createInternalData` simply returns external data, `filterSourceMessage` returns `true`), they are meant to be implemented by subclass.
+ *
+ * @param {String} sourceMessage source message received from external source
+ * @param {Object} sourceData data received from external source
+ */
+function dispatchMessage(sourceMessage, sourceData) {
+ var api = this.messengerAPI
+ , internalMessages = api.getInternalMessages(sourceMessage);
- return xPromise.promise;
+ if (internalMessages)
+ internalMessages.forEach(function (message) {
+ var internalData = api.createInternalData(sourceMessage, message, sourceData);
- function onReady(e) {
- if (progress) req.upload.onprogress = undefined;
- _onReady(req, callback, xPromise, e.type);
- }
+ var shouldDispatch = api.filterSourceMessage(sourceMessage, message, internalData);
+ if (shouldDispatch)
+ this.postMessage(message, internalData);
+
+ }, this);
}
-function request$destroy() {
- if (_messenger) _messenger.destroy();
- request._destroyed = true;
+/**
+ * Posts message on the messenger. This method is separated so specific message sources can make message dispatch synchronous by using `postMessageSync`
+ *
+ * @param {String} message
+ * @param {Object} data
+ */
+function postMessage(message, data) {
+ this.messenger.postMessage(message, data);
}
-function whenRequestsCompleted(callback, timeout) {
- callback = _.once(callback);
- if (timeout)
- _.delay(callback, timeout, 'timeout');
-
- if (_pendingRequests.length)
- _messenger.once('requestscompleted', callback);
- else
- _.defer(callback);
+function toBeImplemented() {
+ throw new Error('calling the method of an absctract class');
}
-},{"../config":65,"../messenger":67,"./count":92,"./logger":102,"mol-proto":150}],105:[function(require,module,exports){
+},{"../abstract/mixin":97,"../util/check":116,"../util/logger":118,"./m_api":101,"mol-proto":122}],104:[function(require,module,exports){
'use strict';
-var domUtils = require('../dom')
- , containingElement = domUtils.containingElement
- , setCaretPosition = domUtils.setCaretPosition
- , getComponentsFromRange = domUtils.getComponentsFromRange
- , deleteRangeWithComponents = domUtils.deleteRangeWithComponents
- , logger = require('../logger')
- , Component = require('../../components/c_class')
- , _ = require('mol-proto');
-
-module.exports = TextSelection;
+var MessageSource = require('./m_source')
+ , _ = require('mol-proto')
+ , check = require('../util/check');
/**
- * Text selection class.
- * Serves as a helper to manage current selection
- * The object cannot be reused, if the selection changes some of its properties may contain information related to previous selection
- *
- * @param {Window} win window in which text selection is processed
+ * Subclass of MessageSource that allows to connect Messenger to another Messenger using it as external source.
*/
-function TextSelection(win) {
- if (! this instanceof TextSelection)
- return new TextSelection(win);
- this.window = win || window;
- this.init();
-}
+var MessengerMessageSource = _.createSubclass(MessageSource, 'MessengerMessageSource');
+
+module.exports = MessengerMessageSource;
/**
- * TextSelection instance method
- * Returns selection start element
- *
- * @return {Element|null}
+ * ####MessengerMessageSource instance methods####
*/
-var TextSelection$startElement =
- _.partial(_getElement, '_startElement', 'startContainer');
-
+_.extendProto(MessengerMessageSource, {
+ init: init,
+ addSourceSubscriber: addSourceSubscriber,
+ removeSourceSubscriber: removeSourceSubscriber,
+ postMessage: MessengerMessageSource$postMessage
+});
/**
- * TextSelection instance method
- * Returns selection end element
+ * Initializes MessengerMessageSource
+ * Defines one parameter in addition to [MessageSource](./m_source.js.html) parameters
*
- * @return {Element|null}
+ * @param {Messenger} sourceMessenger messenger this message source connects to
*/
-var TextSelection$endElement =
- _.partial(_getElement, '_endElement', 'endContainer');
+function init(hostObject, proxyMethods, messengerAPI, sourceMessenger) {
+ MessageSource.prototype.init.apply(this, arguments);
+ this.sourceMessenger = sourceMessenger;
+}
/**
- * TextSelection instance method
- * Returns selection end element
+ * Subscribes to source message. See [MessageSource](./m_source.js.html) docs.
*
- * @return {Element|null}
+ * @param {String|Regex} sourceMessage source message to subscribe to
*/
-var TextSelection$containingElement =
- _.partial(_getElement, '_containingElement', 'commonAncestorContainer');
+function addSourceSubscriber(sourceMessage) {
+ this.sourceMessenger.onSync(sourceMessage, { context: this, subscriber: this.dispatchMessage });
+}
/**
- * TextSelection instance method
- * Returns selection start Component
+ * Unsubscribes from source message. See [MessageSource](./m_source.js.html) docs.
*
- * @return {Component}
+ * @param {String|Regex} sourceMessage source message to unsubscribe from
*/
-var TextSelection$startComponent =
- _.partial(_getComponent, '_startComponent', 'startElement');
+function removeSourceSubscriber(sourceMessage) {
+ this.sourceMessenger.off(sourceMessage, { context: this, subscriber: this.dispatchMessage });
+}
/**
- * TextSelection instance method
- * Returns selection end Component
- *
- * @return {Component}
- */
-var TextSelection$endComponent =
- _.partial(_getComponent, '_endComponent', 'endElement');
+ * Overrides defalut message source to dispatch messages synchronously
+ *
+ * @param {String} message
+ * @param {Object} data
+ */
+function MessengerMessageSource$postMessage(message, data) {
+ this.messenger.postMessageSync(message, data);
+}
+
+},{"../util/check":116,"./m_source":103,"mol-proto":122}],105:[function(require,module,exports){
+'use strict';
+
+var _ = require('mol-proto');
/**
- * TextSelection instance method
- * Returns selection end Component
+ * ####Milo packages####
*
- * @return {Component}
+ * - [minder](./minder.js.html) - data reactivity, one or two way, shallow or deep, as you like it
+ * - [config](./config.js.html) - milo configuration
+ * - [util](./util/index.js.html) - logger, request, dom, check, error, etc.
+ * - [classes](./classes.js.html) - abstract and base classes
+ * - [Messenger](./messenger/index.js.html) - generic Messenger used in most other milo classes, can be mixed into app classes too.
+ * - [Model](./model/index.js.html) - Model class that emits messages on changes to any depth without timer based watching
*/
-var TextSelection$containingComponent =
- _.partial(_getComponent, '_containingComponent', 'containingElement');
+var milo = {
+ minder: require('./minder'),
+ config: require('./config'),
+ util: require('./util'),
+ classes: require('./classes'),
+ Messenger: require('./messenger'),
+ Model: require('./model'),
+ destroy: destroy,
+ proto: _
+};
-_.extendProto(TextSelection, {
- init: TextSelection$init,
- text: TextSelection$text,
- textNodes: TextSelection$textNodes,
- clear: TextSelection$clear,
+// export for node/browserify
+if (typeof module == 'object' && module.exports)
+ module.exports = milo;
- startElement: TextSelection$startElement,
- endElement: TextSelection$endElement,
- containingElement: TextSelection$containingElement,
+// global milo for browser
+if (typeof window == 'object')
+ window.milo = milo;
- startComponent: TextSelection$startComponent,
- endComponent: TextSelection$endComponent,
- containingComponent: TextSelection$containingComponent,
- containedComponents: TextSelection$containedComponents,
- eachContainedComponent: TextSelection$eachContainedComponent,
- del: TextSelection$del,
- _getPostDeleteSelectionPoint: _getPostDeleteSelectionPoint,
- _selectAfterDelete: _selectAfterDelete,
+function destroy() {
+ milo.minder.destroy();
+}
- getRange: TextSelection$getRange,
- getState: TextSelection$getState,
- getNormalizedRange: TextSelection$$getNormalizedRange,
- getDirection: TextSelection$$getDirection
-});
+},{"./classes":98,"./config":99,"./messenger":100,"./minder":106,"./model":109,"./util":117,"mol-proto":122}],106:[function(require,module,exports){
+'use strict';
+var Connector = require('./model/connector')
+ , Messenger = require('./messenger')
+ , _ = require('mol-proto')
+ , logger = require('./util/logger');
-_.extend(TextSelection, {
- createFromRange: TextSelection$$createFromRange,
- createFromState: TextSelection$$createFromState,
- createStateObject: TextSelection$$createStateObject
-});
+
+module.exports = minder;
/**
- * TextSelection instance method
- * Initializes TextSelection from the current selection
+ * This function creates one or many Connector objects that
+ * create live reactive connection between objects implementing
+ * dataSource interface:
+ * Objects should emit messages when any part of their data changes,
+ * methods `on` and `off` should be implemented to subscribe/unsubscribe
+ * to change notification messages, methods `set` and `get` should be implemented to get/set data
+ * on path objects, pointing to particular parts of the object, method `path`
+ * should return path object for a given path string (see path utils for path string syntax).
+ * Both Model and Data facet are such data sources, they can be linked by Connector object.
+ *
+ * @param {Object} ds1 the first data source. Instead of the first data source an array can be passed with arrays of Connection objects parameters in each array element.
+ * @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
+ * @param {Object} ds2 the second data source
+ * @param {Object} options not implemented yet
*/
-function TextSelection$init() {
- this.selection = this.window.getSelection();
- if (this.selection.rangeCount)
- this.range = this.selection.getRangeAt(0);
- this.isCollapsed = this.selection.isCollapsed;
+function minder(ds1, mode, ds2, options) {
+ if (Array.isArray(ds1)) {
+ var connDescriptions = ds1;
+ var connectors = connDescriptions.map(function(descr) {
+ return new Connector(descr[0], descr[1], descr[2], descr[3]);
+ });
+ connectors.forEach(_addConnector);
+ return connectors;
+ } else {
+ var cnct = new Connector(ds1, mode, ds2, options);
+ _addConnector(cnct);
+ return cnct;
+ }
}
/**
- * TextSelection instance method
- * Retrieves and returns selection text
- *
- * @return {String}
+ * messenger of minder where it emits events related to all connectors
+ * @type {Messenger}
*/
-function TextSelection$text() {
- if (! this.range) return undefined;
-
- if (! this._text)
- this._text = this.range.toString();
+var _messenger = new Messenger(minder, Messenger.defaultMethods);
- return this._text;
-}
+var _connectors = []
+ , _receivedMessages = []
+ , _isPropagating = false;
-/**
- * TextSelection instance method
- * Retrieves and returns selection text nodes
- *
- * @return {Array[Node]}
- */
-function TextSelection$textNodes() {
- if (! this.range) return undefined;
- if (! this._textNodes)
- this._textNodes = _getTextNodes.call(this);
- return this._textNodes;
-}
+_.extend(minder, {
+ getConnectors: minder_getConnectors,
+ getExpandedConnections: minder_getExpandedConnections,
+ isPropagating: minder_isPropagating,
+ whenPropagationCompleted: minder_whenPropagationCompleted,
+ destroyConnector: minder_destroyConnector,
+ destroy: minder_destroy
+});
-function TextSelection$clear() {
- this.selection.removeAllRanges();
+function _addConnector(cnct) {
+ cnct.___minder_id = _connectors.push(cnct) - 1;
+ cnct.on(/.*/, onConnectorMessage);
+ minder.postMessage('added', { connector: cnct });
+ minder.postMessage('turnedon', { connector: cnct });
}
-/**
- * Retrieves text and text nodes from selection saving them on properties of object
- *
- * @private
- * @param {TextSelection} this
- */
-function _getTextNodes() {
- // list of selected text nodes
- var textNodes = [];
-
- if (this.isCollapsed)
- return textNodes;
+function onConnectorMessage(msg, data) {
+ var data = data ? _.clone(data) : {};
+ _.extend(data, {
+ id: this.___minder_id,
+ connector: this
+ });
+ minder.postMessage(msg, data);
+ if (! _receivedMessages.length && ! _isPropagating) {
+ _.defer(_idleCheck);
+ _isPropagating = true;
+ }
- // create TreeWalker to traverse the tree to select all text nodes
- var selStart = this.range.startContainer
- , selEnd = this.range.endContainer
- , rangeContainer = this.range.commonAncestorContainer;
+ _receivedMessages.push({ msg: msg, data: data });
+}
- var treeWalker = this.window.document.createTreeWalker(rangeContainer, NodeFilter.SHOW_TEXT);
- var node = treeWalker.currentNode = selStart;
- // traverse DOM tree to collect all selected text nodes
- while (node && (! inEnd || selEnd.contains(node))) {
- textNodes.push(node);
- var inEnd = inEnd || selEnd.contains(node);
- node = treeWalker.nextNode();
+function _idleCheck() {
+ if (_receivedMessages.length) {
+ _receivedMessages.length = 0;
+ _.defer(_idleCheck);
+ minder.postMessage('propagationticked');
+ } else {
+ _isPropagating = false;
+ minder.postMessage('propagationcompleted');
}
- return textNodes;
}
-/**
- * Retrieves and returns start/end element from selection saving them on properties of object
- *
- * @private
- * @param {TextSelection} this
- * @return {Element|null}
- */
-function _getElement(thisPropName, rangePropName) {
- if (! this.range) return undefined;
-
- if (typeof this[thisPropName] == 'undefined')
- this[thisPropName] = containingElement(this.range[rangePropName]);
- return this[thisPropName];
+function minder_isPropagating() {
+ return _isPropagating;
}
-/**
- * Retrieves and returns start/end component from selection saving them on properties of object
- *
- * @private
- * @param {TextSelection} this
- * @return {Component}
- */
-function _getComponent(thisPropName, elMethodName) {
- if (! this.range) return undefined;
+function minder_whenPropagationCompleted(callback) {
+ if (_isPropagating)
+ minder.once('propagationcompleted', executeCallback);
+ else
+ _.defer(executeCallback);
- if (typeof this[thisPropName] == 'undefined')
- this[thisPropName] = Component.getContainingComponent(this[elMethodName]());
- return this[thisPropName];
+ function executeCallback() {
+ if (_isPropagating)
+ minder.once('propagationcompleted', executeCallback);
+ else
+ callback();
+ }
}
-function TextSelection$containedComponents() {
- if (this._containedComponents)
- return this._containedComponents;
+function minder_getConnectors(onOff) {
+ if (typeof onOff == 'undefined')
+ return _connectors;
- var components = this._containedComponents = [];
+ return _connectors.filter(function(cnct) {
+ return cnct.isOn === onOff;
+ });
+}
- if (this.isCollapsed || ! this.range) return components;
- return getComponentsFromRange(this.range);
+function minder_destroyConnector(cnct) {
+ cnct.destroy();
+ var index = _connectors.indexOf(cnct);
+ if (index >= 0)
+ delete _connectors[index];
+ else
+ logger.warn('minder: connector destroyed that is not registered in minder');
}
-function TextSelection$eachContainedComponent(callback, thisArg) {
- if (this.isCollapsed || ! this.range) return;
+function minder_getExpandedConnections(onOff, searchStr) {
+ var connectors = minder.getConnectors(onOff);
+ var connections = connectors.map(function(cnct) {
+ var connection = {
+ leftSource: _getExpandedSource(cnct.ds1),
+ rightSource: _getExpandedSource(cnct.ds2),
+ mode: cnct.mode,
+ isOn: cnct.isOn
+ };
+
+ if (cnct.options)
+ connection.options = cnct.options;
- var components = this.containedComponents();
+ return connection;
+ });
- components.forEach(callback, thisArg);
+ if (searchStr)
+ connections = connections.filter(function(cnctn) {
+ return _sourceMatchesString(cnctn.leftSource, searchStr)
+ || _sourceMatchesString(cnctn.rightSource, searchStr);
+ });
+
+ return connections;
}
-/**
- * TextSelection instance method
- * Deletes the current selection and all components in it
- *
- * @param {Boolean} selectEndContainer set to true if the end container should be selected after deletion
- */
-function TextSelection$del(selectEndContainer) {
- if (this.isCollapsed || ! this.range) return;
+function _getExpandedSource(ds) {
+ var source = [];
+ if (typeof ds == 'function') {
+ if (ds._model && ds._accessPath) {
+ source.unshift(ds._accessPath);
+ ds = ds._model;
+ }
- var selPoint = this._getPostDeleteSelectionPoint(selectEndContainer);
+ source.unshift(ds);
+ ds = ds._hostObject;
+ }
- deleteRangeWithComponents(this.range);
+ if (typeof ds == 'object') {
+ source.unshift(ds);
- this._selectAfterDelete(selPoint);
- selPoint.node.parentNode.normalize();
+ if (ds.owner)
+ source.unshift(ds.owner);
+ }
+
+ return source;
}
-function _getPostDeleteSelectionPoint(selectEndContainer) {
- var selNode = this.range.startContainer;
- var selOffset = this.range.startOffset;
- if (selectEndContainer && this.range.startContainer != this.range.endContainer) {
- selNode = this.range.endContainer;
- selOffset = 0;
- }
- return { node: selNode, offset: selOffset };
+function _sourceMatchesString(source, matchStr) {
+ return source.some(function(srcNode) {
+ var className = srcNode.constructor && srcNode.constructor.name;
+ return _stringMatch(className, matchStr)
+ || _stringMatch(srcNode.name, matchStr)
+ || _stringMatch(srcNode, matchStr);
+ });
}
-function _selectAfterDelete(selPoint) {
- var selNode = selPoint.node
- , selOffset = selPoint.offset;
+function _stringMatch(str, substr) {
+ return str && typeof str == 'string' && str.indexOf(substr) >= 0;
+}
- if (!selNode) return;
- if (selNode.nodeType == Node.TEXT_NODE)
- selNode.textContent = selNode.textContent.trimRight();
- if (!selNode.nodeValue)
- selNode.nodeValue = '\u00A0'; //non-breaking space, \u200B for zero width space;
- var position = selOffset > selNode.length ? selNode.length : selOffset;
- setCaretPosition(selNode, position);
+function minder_destroy() {
+ _connectors.forEach(function(cnct) {
+ destroyDS(cnct.ds1);
+ destroyDS(cnct.ds2);
+ cnct.destroy();
+ });
+ _messenger.destroy();
+ minder._destroyed = true;
+
+ function destroyDS(ds) {
+ if (ds && !ds._destroyed) ds.destroy();
+ }
}
+},{"./messenger":100,"./model/connector":108,"./util/logger":118,"mol-proto":122}],107:[function(require,module,exports){
+'use strict';
+
+
+var logger = require('../util/logger')
+ , config = require('../config')
+ , pathUtils = require('./path_utils')
+ , _ = require('mol-proto');
/**
- * Returns selection range
- *
- * @return {Range}
+ * Utility function to process "changedata" messages emitted by Connector object.
*/
-function TextSelection$getRange() {
- return this.range;
-}
+module.exports = changeDataHandler;
+
+
+_.extend(changeDataHandler, {
+ setTransactionFlag: setTransactionFlag,
+ getTransactionFlag: getTransactionFlag,
+ passTransactionFlag: passTransactionFlag,
+ postTransactionFinished: postTransactionFinished
+});
/**
- * Stores selection window, nodes and offsets in object
+ * Change data uses hidden property on accessor methods to pass flag that the accessor is executed as a part of change transaction.
+ * Accessor methods are supposed to store this flag in a local variable and to clear it (because another accessor can be executed in or out of transaction) using `getTransactionFlag`
+ *
+ * @private
+ * @param {Function} func accessor method reference
+ * @param {Boolean} flag a flag to be set
*/
-function TextSelection$getState(rootEl) {
- var r = this.range;
- var doc = rootEl.ownerDocument
- , win = doc.defaultView || doc.parentWindow;
- if (!r) return { window: win };
- return TextSelection.createStateObject(rootEl, r.startContainer, r.startOffset, r.endContainer, r.endOffset);
+function setTransactionFlag(func, flag) {
+ _.defineProperty(func, '__inChangeTransaction', flag, _.CONF | _.WRIT);
}
-function TextSelection$$createStateObject(rootEl, startContainer, startOffset, endContainer, endOffset) {
- endContainer = endContainer || startContainer;
- endOffset = endOffset || startOffset;
- var doc = rootEl.ownerDocument
- , win = doc.defaultView || doc.parentWindow;
- return {
- window: win,
- rootEl: rootEl,
- start: _getSelectionPointState(rootEl, startContainer, startOffset),
- end: _getSelectionPointState(rootEl, endContainer, endOffset)
- };
+/**
+ * Retrieves and clears transaction flag from accessor method
+ *
+ * @private
+ * @param {Function} func accessor method reference
+ * @return {Boolean}
+ */
+function getTransactionFlag(func) {
+ var inTransaction = func.__inChangeTransaction;
+ delete func.__inChangeTransaction;
+ return inTransaction;
}
-function _getSelectionPointState(rootEl, node, offset) {
- var treePath = domUtils.treePathOf(rootEl, node);
- if (! treePath) logger.error('Selection point is outside of root element');
- return {
- treePath: treePath,
- offset: offset
- };
+function passTransactionFlag(fromFunc, toFunc) {
+ var inTransaction = getTransactionFlag(fromFunc);
+ setTransactionFlag(toFunc, inTransaction);
+ return inTransaction;
}
/**
- * Restores actual selection to the stored range
+ * Posts message on this to indicate the end of transaction unless `inChangeTransaction` is `true`.
*/
-function TextSelection$$createFromState(state) {
- var domUtils = state.window.milo.util.dom;
+function postTransactionFinished() {
+ this.postMessageSync('datachanges', { transaction: false, changes: [] });
+}
- if (state.rootEl && state.start && state.end) {
- var startNode = _selectionNodeFromState(state.rootEl, state.start)
- , endNode = _selectionNodeFromState(state.rootEl, state.end);
- try {
- domUtils.setSelection(startNode, state.start.offset, endNode, state.end.offset);
- return new TextSelection(state.window);
- } catch(e) {
- logger.error('Text selection: can\'t create selection', e, e.message);
- }
- } else {
- domUtils.clearSelection(state.window);
- return new TextSelection(state.window);
- }
+/**
+ * subscriber to "changedata" event emitted by [Connector](./connector.js.html) object to enable reactive connections
+ * Used by Data facet, Model and ModelPath. Can be used by any object that implements get/set/del/splice api and sets data deeply to the whole tree.
+ * Object should call `changeDataHandler.initialize.call(this)` in its constructor.
+ * TODO: optimize messages list to avoid setting duplicate values down the tree
+ *
+ * @param {String} msg should be "changedata" here
+ * @param {Object} data batch of data change desciption objects
+ * @param {Function} callback callback to call before and after the data is processed
+ */
+function changeDataHandler(message, data, callback) {
+ processChanges.call(this, data.changes, callback);
}
-function _selectionNodeFromState(rootEl, pointState) {
- var node = domUtils.getNodeAtTreePath(rootEl, pointState.treePath);
- if (! node) logger.error('TextSelection createFromState: no node at treePath');
- return node;
-}
+// map of message types to methods
+var CHANGE_TYPE_TO_METHOD_MAP = {
+ 'added': 'set',
+ 'changed': 'set',
+ 'deleted': 'del',
+ 'removed': 'del'
+};
/**
- * Creates selection from passed range
- *
- * @param {Range} range
- * @param {Boolean} backward
+ * Processes queued "changedata" messages.
+ * Posts "changestarted" and "changecompleted" messages and calls callback
*
- * @return {TextSelection}
+ * @param {[Function]} callback optional callback that is called with `(null, false)` parameters before change processing starts and `(null, true)` after it's finished.
*/
-function TextSelection$$createFromRange(range, backward) {
- var win = range.startContainer.ownerDocument.defaultView
- , sel = win.getSelection()
- , endRange;
-
- sel.removeAllRanges();
-
- if (backward){
- endRange = range.cloneRange();
- endRange.collapse(false);
+function processChanges(transaction, callback) {
+ notify.call(this, callback, false);
+ processTransaction.call(this,
+ prepareTransaction(
+ validateTransaction(transaction)));
+ notify.call(this, callback, true);
+}
- sel.addRange(endRange);
- sel.extend(range.startContainer, range.startOffset)
- }
- else {
- sel.addRange(range);
- }
- return new TextSelection(win);
+function notify(callback, changeFinished) {
+ callback && callback(null, changeFinished);
+ this.postMessage(changeFinished ? 'changecompleted' : 'changestarted');
}
+
/**
- * Returns a normalized copy of the range
- * If you triple click an item, the end of the range is positioned at the beginning of the NEXT node.
- * this function returns a range with the end positioned at the end of the last textnode contained
- * inside a component with the "editable" facet
+ * Checks that all messages from the transaction come from the same source.
+ * Hack: reverses the transaction if it comes from the Data facet
+ * Returns the reference to the transaction (for chaining)
*
- * @return {range}
+ * @param {Array} transaction transaction of data changes
+ * @return {Array}
*/
-function TextSelection$$getNormalizedRange(){
- var doc = this.range.commonAncestorContainer.ownerDocument
- , tw, previousNode
- , newRange = this.range.cloneRange();
+function validateTransaction(transaction) {
+ var source = transaction[0].source
+ , sameSource = true;
- if (newRange.endContainer.nodeType !== Node.TEXT_NODE) {
- tw = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT);
- tw.currentNode = newRange.endContainer;
- previousNode = tw.previousNode();
- newRange.setEnd(previousNode, previousNode.length);
+ if (transaction.length > 1) {
+ for (var i = 1, len = transaction.length; i < len; i++)
+ if (transaction[i].source != source) {
+ logger.error('changedata: changes from different sources in the same transaction, sources:', transaction[i].source.name, source.name);
+ sameSource = false;
+ source = transaction[i].source;
+ }
}
- return newRange;
-}
-
-/**
- * get the direction of a selection
- *
- * 1 forward, -1 backward, 0 no direction, undefined one of the node is detached or in a different frame
- *
- * @return {-1|0|1|undefined}
- */
-function TextSelection$$getDirection(){
- return domUtils.getSelectionDirection(this.selection);
+ return transaction;
}
-},{"../../components/c_class":16,"../dom":94,"../logger":102,"mol-proto":150}],106:[function(require,module,exports){
-'use strict';
+function prepareTransaction(transaction) {
+ var todo = []
+ , pathsToSplice = []
+ , pathsToChange = []
+ , hadSplice
+ , exitLoop = {};
-var DOMStorageError = require('../error').createClass('DomStorageError')
- , Messenger = require('../../messenger')
- , StorageMessageSource = require('./msg_src')
- , config = require('../../config')
- , jsonParse = require('../json_parse')
- , _ = require('mol-proto')
- , check = require('../check')
- , Match = check.Match;
+ try { transaction.forEach(checkChange); }
+ catch (e) { if (e != exitLoop) throw e; }
-require('./model')
+ return todo;
-module.exports = DOMStorage;
+ function checkChange(data) {
+ (data.type == 'splice' ? checkSplice : checkMethod)(data);
+ }
-// shared keys stored by all instances, include key prefixes
-var _storedKeys = {
- true: {}, // session storage
- false: {} // local storage
-};
+ function checkSplice(data) {
+ var parsedPath = pathUtils.parseAccessPath(data.path);
+ var parentPathChanged = pathsToChange.some(function(parentPath) {
+ if (parsedPath.length < parentPath.length) return;
+ return _pathIsParentOf(parentPath, parsedPath);
+ });
-/**
- * DOMStorage class to simplify storage and retrieval of multiple items with types preservation to DOM storage (localStorage and sessionStorage).
- * Types will be stored in the key created from value keys with appended `milo.config.domStorage.typeSuffix`
- *
- * @param {String} keyPrefix prefix that will be added to all keys followed by `milo.config.domStorage.prefixSeparator` ("/" by default).
- * @param {Boolean} sessionOnly true to use sessionStorage. localStorage will be used by default.
- * @param {Window} win window to work in
- */
-function DOMStorage(keyPrefix, sessionOnly, win) {
- if (typeof window == 'undefined') return;
- win = win || window;
+ if (parentPathChanged) return;
- keyPrefix = config.domStorage.root +
- (keyPrefix
- ? keyPrefix + config.domStorage.prefixSeparator
- : '');
+ todo.push(data);
- _.defineProperties(this, {
- keyPrefix: keyPrefix,
- sessionOnly: !! sessionOnly,
- window: win,
- _storage: sessionOnly ? win.sessionStorage : win.localStorage,
- _typeSuffix: config.domStorage.typeSuffix,
- _keys: {}
- }, _.WRIT);
-}
+ if (! config.debug) throw exitLoop;
+ pathsToSplice.push(parsedPath);
+ hadSplice = true;
+ }
-_.extendProto(DOMStorage, {
- get: DOMStorage$get,
- set: DOMStorage$set,
- remove: DOMStorage$remove,
- hasItem: DOMStorage$hasItem,
- getItem: DOMStorage$getItem,
- setItem: DOMStorage$setItem,
- removeItem: DOMStorage$removeItem,
- _storageKey: DOMStorage$_storageKey,
- _domStorageKey: DOMStorage$_domStorageKey,
- getAllKeys: DOMStorage$getAllKeys,
- getAllItems: DOMStorage$getAllItems,
- createMessenger: DOMStorage$createMessenger,
- destroy: DOMStorage$destroy
-});
+ function checkMethod(data) {
+ var parsedPath = pathUtils.parseAccessPath(data.path);
+ var parentPathSpliced = pathsToSplice && pathsToSplice.some(function(parentPath) {
+ if (parsedPath.length <= parentPath.length
+ || parsedPath[parentPath.length].syntax != 'array') return;
+ return _pathIsParentOf(parentPath, parsedPath);
+ });
+ if (parentPathSpliced) return;
+ if (hadSplice) logger.error('changedata: child change is executed after splice; probably data source did not emit message with data.type=="finished"');
-/**
- * Expose Mesenger and MessageSource methods on DOMStorage
- */
-Messenger.useWith(DOMStorage, '_messenger', Messenger.defaultMethods);
-StorageMessageSource.useWith(DOMStorage, '_messageSource', ['trigger']);
+ var parentPathChanged = pathsToChange.some(function(parentPath) {
+ if (parsedPath.length <= parentPath.length) return;
+ return _pathIsParentOf(parentPath, parsedPath);
+ });
+ if (parentPathChanged) return;
-var _sessionStorage = new DOMStorage('', true)
- , _localStorage = new DOMStorage('', false);
+ pathsToChange.push(parsedPath);
-var _domStorage = {
- true: _sessionStorage,
- false: _localStorage
- };
+ todo.push(data);
+ }
-_.extend(DOMStorage, {
- registerDataType: DOMStorage$$registerDataType,
- local: _localStorage,
- session: _sessionStorage,
- storage: _domStorage,
- _storedKeys: _storedKeys // exposed for testing
-});
+ function _pathIsParentOf(parentPath, childPath) {
+ return parentPath.every(function(pathNode, index) {
+ return pathNode.property == childPath[index].property;
+ });
+ }
+}
-/**
- * Sets data to DOM storage. `this.keyPrefix` is prepended to keys.
- *
- * @param {Object} data single object can be passed in which case keys will be used as keys in local storage.
- * @param {List} arguments alternatively just the list of arguments can be passed where arguments can be sequentially used as keys and values.
- */
-function DOMStorage$set(data) { // or arguments
- if (typeof data == 'object')
- _.eachKey(data, function(value, key) {
- this.setItem(key, value);
- }, this);
- else {
- var argsLen = arguments.length;
- if (argsLen % 2)
- throw new DomStorageError('DOMStorage: set should have even number of arguments or object');
- for (var i = 0; i < argsLen; i++) {
- var key = arguments[i]
- , value = arguments[++i];
+function processTransaction(transaction) {
+ transaction.forEach(processChange, this);
+ postTransactionFinished.call(this, false);
- this.setItem(key, value);
- }
+ function processChange(data) {
+ var modelPath = this.path(data.path, data.type != 'removed' && data.type != 'deleted');
+ if (! modelPath) return;
+ (data.type == 'splice' ? executeSplice : executeMethod)(modelPath, data);
}
}
-/**
- * Gets data from DOM storage. `this.keyPrefix` is prepended to passed keys, but returned object will have keys without root keys.
- *
- * @param {List} arguments keys can be passed as strings or arrays of strings
- * @returns {Object}
- */
-function DOMStorage$get() { // , ... arguments
- var data = {};
- _.deepForEach(arguments, function(key) {
- data[key] = this.getItem(key);
- }, this);
- return data;
+function executeSplice(modelPath, data) {
+ var index = data.index
+ , howMany = data.removed.length
+ , spliceArgs = [index, howMany];
+
+ spliceArgs = spliceArgs.concat(data.newValue.slice(index, index + data.addedCount));
+ setTransactionFlag(modelPath.splice, true);
+ modelPath.splice.apply(modelPath, spliceArgs);
}
-/**
- * Removes keys from DOM storage. `this.keyPrefix` is prepended to passed keys.
- *
- * @param {List} arguments keys can be passed as strings or arrays of strings
- */
-function DOMStorage$remove() { //, ... arguments
- _.deepForEach(arguments, function(key) {
- this.removeItem(key);
- }, this);
+function executeMethod(modelPath, data) {
+ var methodName = CHANGE_TYPE_TO_METHOD_MAP[data.type];
+ if (methodName) {
+ setTransactionFlag(modelPath[methodName], true);
+ modelPath[methodName](data.newValue);
+ } else
+ logger.error('unknown data change type');
}
+},{"../config":99,"../util/logger":118,"./path_utils":114,"mol-proto":122}],108:[function(require,module,exports){
+'use strict';
-/**
- * Check for presence of single item in DOM storage. `this.keyPrefix` is prepended to passed key.
- *
- * @param {String} key
- * @return {Boolean}
- */
-function DOMStorage$hasItem(key) {
- var pKey = this._storageKey(key);
- return this._storage.getItem(pKey) != null;
-}
+var Messenger = require('../messenger')
+ , pathUtils = require('./path_utils')
+ , _ = require('mol-proto')
+ , logger = require('../util/logger');
-/**
- * Gets single item from DOM storage prepending `this.keyPrefix` to passed key.
- * Reads type of the originally stored value from `key + this._typeSuffix` and converts data to the original type.
- *
- * @param {String} key
- * @return {Any}
- */
-function DOMStorage$getItem(key) {
- var pKey = this._storageKey(key);
- var dataType = _getKeyDataType.call(this, pKey);
- var valueStr = this._storage.getItem(pKey);
- var value = _parseData(valueStr, dataType);
- return value;
-}
+module.exports = Connector;
+
+
+var modePattern = /^(\<*)\-+(\>*)$/;
/**
- * Sets single item to DOM storage prepending `this.keyPrefix` to passed key.
- * Stores type of the stored value to `key + this._typeSuffix`.
+ * Connector
+ * Class that creates connector object for data connection between
+ * two data-sources
+ * Data-sources should implement the following API:
+ * get() - get value from datasource or its path
+ * set(value) - set value to datasource or to its path
+ * on(path, subscriber) - subscription to data changes with "*" support
+ * off(path, subscriber)
+ * path(accessPath) - to return the object that gives reference to some part of datasource
+ * and complies with that api too.
*
- * @param {String} key
- * @return {Any}
+ * ####Events####
+ *
+ * - 'turnedon' - connector was turned on
+ * - 'turnedoff' - connector was turned off
+ * - 'changestarted' - change on connected datasource is started
+ * - 'changecompleted' - change on connected datasource is completed
+ * - 'destroyed' - connector was destroyed
+ *
+ * @param {Object} ds1 the first data source.
+ * @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
+ * @param {Object} ds2 the second data source
+ * @param {Object} options not implemented yet
+ * @return {Connector} when called with `new`, creates a Connector object.
*/
-function DOMStorage$setItem(key, value) {
- var pKey = this._storageKey(key);
- var dataType = _setKeyDataType.call(this, pKey, value);
- var valueStr = _serializeData(value, dataType);
- try {
- this._storage.setItem(pKey, valueStr);
- } catch(e) {
- if (e.name == 'QuotaExceededError') {
- var cfg = config.domStorage.quotaExceeded;
- if (cfg.message)
- milo.mail.postMessage('quotaexceedederror', value);
- if (cfg.throwError)
- throw e;
- } else
- throw e;
+function Connector(ds1, mode, ds2, options) {
+ setupMode.call(this, mode);
+
+ _.extend(this, {
+ ds1: ds1,
+ ds2: ds2,
+ isOn: false,
+ _changesQueue1: [],
+ _changesQueue2: [],
+ _messenger: new Messenger(this, Messenger.defaultMethods)
+ });
+
+ if (options) {
+ this.options = options;
+
+ var pathTranslation = options.pathTranslation;
+ if (pathTranslation) {
+ pathTranslation = _.clone(pathTranslation);
+ var patternTranslation = getPatternTranslations(pathTranslation);
+ _.extend(this, {
+ pathTranslation1: reverseTranslationRules(pathTranslation),
+ pathTranslation2: pathTranslation,
+ patternTranslation1: reversePatternTranslationRules(patternTranslation),
+ patternTranslation2: patternTranslation
+ });
+ }
+
+ var dataTranslation = options.dataTranslation;
+ if (dataTranslation) {
+ _.extend(this, {
+ dataTranslation1: dataTranslation['<-'],
+ dataTranslation2: dataTranslation['->']
+ });
+ }
+
+ var dataValidation = options.dataValidation;
+ if (dataValidation) {
+ _.extend(this, {
+ dataValidation1: dataValidation['<-'],
+ dataValidation2: dataValidation['->']
+ });
+ }
}
- this._keys[key] = true;
- _domStorage[this.sessionOnly]._keys[pKey] = true;
+
+ this.turnOn();
}
-/**
- * Removes single item from DOM storage prepending `this.keyPrefix` to passed key.
- * Type of the stored value (in `key + this._typeSuffix` key) is also removed.
- *
- * @param {String} key
- * @return {Any}
- */
-function DOMStorage$removeItem(key) {
- var pKey = this._storageKey(key);
- this._storage.removeItem(pKey);
- _removeKeyDataType.call(this, pKey)
- delete this._keys[key];
- delete _domStorage[this.sessionOnly]._keys[pKey];
-}
+function setupMode(mode){
+ var parsedMode = mode.match(modePattern);
+ if (! parsedMode)
+ modeParseError();
-/**
- * Returns the array of all keys stored by this instance of DOMStorage
- *
- * @return {Array}
- */
-function DOMStorage$getAllKeys() {
- var storedKeys = Object.keys(this._keys);
- var keysInStorage = storedKeys.filter(function(key) {
- if (this.hasItem(key)) return true;
- else delete this._keys[key];
- }, this);
- return keysInStorage;
-}
+ var depth1 = parsedMode[1].length
+ , depth2 = parsedMode[2].length;
+ if (depth1 && depth2 && depth1 != depth2)
+ modeParseError();
-/**
- * Returns the map with all keys and values (deserialized) stored using this instance of DOMStorage
- *
- * @return {Object}
- */
-function DOMStorage$getAllItems() {
- return this.get(this.getAllKeys());
-}
+ if (! depth1 && ! depth2)
+ modeParseError();
+ _.extend(this, {
+ mode: mode,
+ depth1: depth1,
+ depth2: depth2,
+ });
-/**
- * Returns prefixed key for DOM storage for given unprefixed key.
- *
- * @param {String} key
- * @return {String}
- */
-function DOMStorage$_storageKey(key) {
- return this.keyPrefix + key;
+ function modeParseError() {
+ throw new Error('invalid Connector mode: ' + mode);
+ }
}
+_.extendProto(Connector, {
+ turnOn: Connector$turnOn,
+ turnOff: Connector$turnOff,
+ destroy: Connector$destroy,
+ changeMode: Connector$changeMode,
+ deferChangeMode: Connector$deferChangeMode
+});
+
/**
- * Returns unprefixed key to be used with this instance of DOMStorage fir given actual key in storage
- * If key has different prefix from the keyPrefix returns undefined
+ * Function change the mode of the connection
*
- * @param {String} storageKey actual key in local/session storage
- * @return {String}
+ * @param @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
+ * @return {Object[String]}
*/
-function DOMStorage$_domStorageKey(storageKey) {
- if (storageKey.indexOf(this._typeSuffix) >= 0) return;
- return _.unPrefix(storageKey, this.keyPrefix);
+function Connector$changeMode(mode) {
+ this.turnOff();
+ setupMode.call(this, mode);
+ this.turnOn();
+ return this;
}
/**
- * Gets originally stored data type for given (prefixed) `key`.
+ * Function change the mode of the connection
*
- * @param {String} pKey prefixed key of stored value
- * @return {String}
+ * @param @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
+ * @return {Object[String]}
*/
-function _getKeyDataType(pKey) {
- pKey = _dataTypeKey.call(this, pKey);
- return this._storage.getItem(pKey);
+function Connector$deferChangeMode(mode) {
+ _.deferMethod(this, 'changeMode', mode);
+ return this;
}
/**
- * Stores data type for given (prefixed) `key` and `value`.
- * Returns data type for `value`.
+ * Function that reverses translation rules for paths of connected odata sources
*
- * @param {String} pKey prefixed key of stored value
- * @param {Any} value
- * @return {String}
+ * @param {Object[String]} rules map of paths defining the translation rules
+ * @return {Object[String]}
*/
-function _setKeyDataType(pKey, value) {
- var dataType = _getValueType(value);
- pKey = _dataTypeKey.call(this, pKey);
- this._storage.setItem(pKey, dataType);
- return dataType;
+function reverseTranslationRules(rules) {
+ var reverseRules = {};
+ _.eachKey(rules, function(path2_value, path1_key) {
+ reverseRules[path2_value] = path1_key;
+ });
+ return reverseRules;
}
-/**
- * Removes stored data type for given (prefixed) `key`.
- *
- * @param {String} pKey prefixed key of stored value
- */
-function _removeKeyDataType(pKey) {
- pKey = _dataTypeKey.call(this, pKey);
- this._storage.removeItem(pKey);
+function getPatternTranslations(pathTranslation) {
+ var patternTranslation = [];
+ _.eachKey(pathTranslation, function(path2_value, path1_key) {
+ var starIndex1 = path1_key.indexOf('*')
+ , starIndex2 = path2_value.indexOf('*');
+ if (starIndex1 >= 0 && starIndex2 >= 0) { // pattern translation
+ if (path1_key.slice(starIndex1) != path2_value.slice(starIndex2))
+ _throwInvalidTranslation(path1_key, path2_value);
+ delete pathTranslation[path1_key];
+
+ patternTranslation.push({
+ fromPattern: pathUtils.createRegexPath(path1_key),
+ fromStaticPath: _getStaticPath(path1_key, starIndex1),
+ toPattern: pathUtils.createRegexPath(path2_value),
+ toStaticPath: _getStaticPath(path2_value, starIndex2)
+ });
+ } else if (starIndex1 >= 0 || starIndex2 >= 0) // pattern only on one side of translation
+ _throwInvalidTranslation(path1_key, path2_value);
+ });
+
+ return patternTranslation;
+
+
+ function _throwInvalidTranslation(path1, path2) {
+ throw new Error('Invalid pattern translation: ' + path1 + ', ' + path2);
+ }
+
+
+ function _getStaticPath(path, starIndex) {
+ return path.replace(/[\.\[]?\*.*$/, '');
+ }
}
-/**
- * Returns the key to store data type for given (prefixed) `key`.
- *
- * @param {String} pKey prefixed key of stored value
- * @return {String}
- */
-function _dataTypeKey(pKey) {
- return pKey + this._typeSuffix;
+function reversePatternTranslationRules(patternTranslation) {
+ return patternTranslation.map(function(pt) {
+ return {
+ fromPattern: pt.toPattern,
+ fromStaticPath: pt.toStaticPath,
+ toPattern: pt.fromPattern,
+ toStaticPath: pt.fromStaticPath
+ };
+ });
}
/**
- * Returns type of value as string. Class name returned for objects ('null' for null).
- * @param {Any} value
- * @return {String}
+ * turnOn
+ * Method of Connector that enables connection (if it was previously disabled)
*/
-function _getValueType(value) {
- var valueType = typeof value
- , className = value && value.constructor.name
- , dataType = valuesDataTypes[className];
- return dataType || (
- valueType != 'object'
- ? valueType
- : value == null
- ? 'null'
- : value.constructor.name);
-}
-var valuesDataTypes = {
- // can be registered with `registerDataType`
-}
-
+function Connector$turnOn() {
+ if (this.isOn)
+ return logger.warn('data sources are already connected');
-/**
- * Serializes value to be stored in DOM storage.
- *
- * @param {Any} value value to be serialized
- * @param {String} valueType optional data type to define serializer, _getValueType is used if not passed.
- * @return {String}
- */
-function _serializeData(value, valueType) {
- valueType = valueType || _getValueType(value);
- var serializer = dataSerializers[valueType];
- return serializer
- ? serializer(value, valueType)
- : value && value.toString == Object.prototype.toString
- ? JSON.stringify(value)
- : '' + value;
-}
-var dataSerializers = {
- 'Array': JSON.stringify
-}
+ var subscriptionPath = this._subscriptionPath =
+ new Array(this.depth1 || this.depth2).join('*');
+ var subscriptionPattern = pathUtils.createRegexPath(subscriptionPath);
-/**
- * Parses string retrieved from DOM storage.
- *
- * @param {String} valueStr
- * @param {String} valueType data type that defines parser. Original sring will be returned if parser is not defined.
- * @return {Any}
- */
-function _parseData(valueStr, valueType) {
- var parser = dataParsers[valueType];
- return parser
- ? parser(valueStr, valueType)
- : valueStr;
-}
-var dataParsers = {
- Object: jsonParse,
- Array: jsonParse,
- Date: function(valStr) { return new Date(valStr); },
- boolean: function(valStr) { return valStr == 'true'; },
- number: function(valStr) { return Number(valStr); },
- function: function(valStr) { return _.toFunction(valStr); },
- RegExp: function(valStr) { return _.toRegExp(valStr); }
-};
+ var self = this;
+ if (this.depth1)
+ this._link1 = linkDataSource('_link2', this.ds2, this.ds1, this._changesQueue1, this.pathTranslation1, this.patternTranslation1, this.dataTranslation1, this.dataValidation1);
+ if (this.depth2)
+ this._link2 = linkDataSource('_link1', this.ds1, this.ds2, this._changesQueue2, this.pathTranslation2, this.patternTranslation2, this.dataTranslation2, this.dataValidation2);
+ this.isOn = true;
+ this.postMessage('turnedon');
-/**
- * Registers data type to be saved in DOM storage. Class name can be used or result of `typeof` operator for non-objects to override default conversions.
- *
- * @param {String} valueType class (constructor) name or the string returned by typeof.
- * @param {Function} serializer optional serializer for this type
- * @param {Function} parser optional parser for this type
- * @param {[String]} storeAsDataType optional name of stored data type if different from valueType
- */
-function DOMStorage$$registerDataType(valueType, serializer, parser, storeAsDataType) {
- if (serializer) dataSerializers[valueType] = serializer;
- if (parser) dataParsers[valueType] = parser;
- valuesDataTypes[valueType] = storeAsDataType || valueType;
-}
+ function linkDataSource(reverseLink, fromDS, toDS, changesQueue, pathTranslation, patternTranslation, dataTranslation, dataValidation) {
+ fromDS.onSync('datachanges', onData);
+ return onData;
-function DOMStorage$createMessenger() {
- var storageMessageSource = new StorageMessageSource(this);
- var messenger = new Messenger(this, undefined, storageMessageSource);
- _.defineProperties(this, {
- _messenger: messenger,
- _messageSource: storageMessageSource
- }, _.WRIT);
-}
+ function onData(message, batch) {
+ var sendData = {
+ changes: [],
+ transaction: batch.transaction
+ }
+ batch.changes.forEach(function(change) {
+ var sourcePath = change.path
+ , targetPath = translatePath(sourcePath);
-function DOMStorage$destroy() {
- this._storage = undefined;
- this.window = undefined;
- if (this._messenger) this._messenger.destroy();
- this._destroyed = true;
-}
+ if (typeof targetPath == 'undefined') return;
-},{"../../config":65,"../../messenger":67,"../check":90,"../error":98,"../json_parse":101,"./model":107,"./msg_src":108,"mol-proto":150}],107:[function(require,module,exports){
-'use strict';
+ var change = _.clone(change);
+ _.extend(change, {
+ source: fromDS,
+ path: targetPath
+ });
-var Model = require('milo-core').Model
+ translateData(sourcePath, change);
+ validateData(sourcePath, change);
+ });
-Model.registerWithDOMStorage = Model$$registerWithDOMStorage;
+ if (! changesQueue.length)
+ _.defer(postChangeData);
+ changesQueue.push(sendData);
-function Model$$registerWithDOMStorage() {
- var DOMStorage = require('./index');
- DOMStorage.registerDataType('Model', Model_domStorageSerializer, Model_domStorageParser);
- DOMStorage.registerDataType('ModelPath', Model_domStorageSerializer, Model_domStorageParser, 'Model');
-}
+ function translatePath(sourcePath) {
+ if (pathTranslation) {
+ var translatedPath = pathTranslation[sourcePath];
+ if (translatedPath) return translatedPath;
+ if (!patternTranslation.length) return;
+ var pt = _.find(patternTranslation, function(pTranslation) {
+ return pTranslation.fromPattern.test(sourcePath);
+ });
+ if (!pt) return;
+ var translatedPath = sourcePath.replace(pt.fromStaticPath, pt.toStaticPath);
+ } else if (! ((subscriptionPattern instanceof RegExp
+ && subscriptionPattern.test(sourcePath))
+ || subscriptionPattern == sourcePath)) return;
-function Model_domStorageSerializer(value) {
- var data = value.get();
- return JSON.stringify(data);
-}
+ return translatedPath || sourcePath;
+ }
-function Model_domStorageParser(valueStr) {
- var data = _.jsonParse(valueStr);
- return new Model(data);
-}
+ function translateData(sourcePath, change) {
+ if (dataTranslation) {
+ var translate = dataTranslation[sourcePath];
+ if (translate && typeof translate == 'function') {
+ change.oldValue = translate(change.oldValue);
+ change.newValue = translate(change.newValue);
+ }
+ }
+ }
-},{"./index":106,"milo-core":124}],108:[function(require,module,exports){
-'use strict';
+
+ function validateData(sourcePath, change) {
+ propagateData(change);
+ if (dataValidation) {
+ var validators = dataValidation[sourcePath]
+ , passedCount = 0
+ , alreadyFailed = false;
-var MessageSource = require('../../messenger/m_source')
- , _ = require('mol-proto')
- , config = require('../../config')
- , miloCount = require('../../util/count')
- , StorageMessageSourceError = require('../../util/error').StorageMessageSource;
+ if (validators)
+ validators.forEach(callValidator);
+ }
-var StorageMessageSource = _.createSubclass(MessageSource, 'StorageMessageSource', true);
+ function callValidator(validator) {
+ validator(change.newValue, function(err, response) {
+ response.path = sourcePath;
+ if (! alreadyFailed && (err || response.valid) && ++passedCount == validators.length) {
+ fromDS.postMessage('validated', response);
+ } else if (! response.valid) {
+ alreadyFailed = true;
+ fromDS.postMessage('validated', response);
+ }
+ });
+ }
+ }
-_.extendProto(StorageMessageSource, {
- // implementing MessageSource interface
- init: init,
- addSourceSubscriber: StorageMessageSource$addSourceSubscriber,
- removeSourceSubscriber: StorageMessageSource$removeSourceSubscriber,
- postMessage: StorageMessageSource$postMessage,
- trigger: StorageMessageSource$trigger,
- //class specific methods
- handleEvent: handleEvent // event dispatcher - as defined by Event DOM API
-});
+ function propagateData(change) {
+ sendData.changes.push(change);
+ }
-module.exports = StorageMessageSource;
+ function postChangeData() {
+ // prevent endless loop of updates for 2-way connection
+ if (self[reverseLink]) var callback = subscriptionSwitch;
-function init(hostObject, proxyMethods, messengerAPIOrClass) {
- if (hostObject.constructor.name != 'DOMStorage')
- throw new StorageMessageSourceError('hostObject should be an instance of DOMStorage');
- this.storage = hostObject;
- this.messageKey = config.domStorage.messageKey;
- this.window = hostObject.window;
- MessageSource.prototype.init.apply(this, arguments);
-}
+ var transactions = mergeTransactions(changesQueue);
+ changesQueue.length = 0;
+ transactions.forEach(function(transaction) {
+ // send data change instruction as message
+ toDS.postMessageSync('changedata', { changes: transaction }, callback);
+ });
+ }
-function StorageMessageSource$addSourceSubscriber(sourceMessage) {
- this.window.addEventListener('storage', this, false);
-}
+ function subscriptionSwitch(err, changeFinished) {
+ if (err) return;
+ var onOff = changeFinished ? 'onSync' : 'off';
+ toDS[onOff]('datachanges', self[reverseLink]);
+ var message = changeFinished ? 'changecompleted' : 'changestarted';
+ self.postMessage(message, { source: fromDS, target: toDS });
+ }
-function StorageMessageSource$removeSourceSubscriber(sourceMessage) {
- this.window.removeEventListener('storage', this, false);
-}
+ function mergeTransactions(batches) {
+ var transactions = []
+ , currentTransaction;
-function StorageMessageSource$postMessage(message, data) {
- this.messenger.postMessageSync(message, data);
-}
+ batches.forEach(function(batch) {
+ if (! batch.transaction) currentTransaction = undefined;
+ if (! batch.changes.length) return;
+ if (batch.transaction) {
+ if (currentTransaction)
+ _.appendArray(currentTransaction, batch.changes);
+ else {
+ currentTransaction = _.clone(batch.changes);
+ transactions.push(currentTransaction);
+ }
+ } else
+ transactions.push(batch.changes);
+ });
-function StorageMessageSource$trigger(msgType, data) {
- var key = this.messageKey + msgType;
- data = data || {};
- data[config.domStorage.messageTimestamp] = miloCount();
- _.deferMethod(this.storage, 'setItem', key, data);
+ return transactions;
+ }
+ }
+ }
}
-function handleEvent(event) {
- if (event.storageArea != this.storage._storage) return;
- var key = this.storage._domStorageKey(event.key); if (! key) return;
- var msgType = _.unPrefix(key, this.messageKey); if (! msgType) return;
- var data = this.storage.getItem(key); if (! data) return;
- this.dispatchMessage(msgType, data);
-}
-
-},{"../../config":65,"../../messenger/m_source":70,"../../util/count":92,"../../util/error":98,"mol-proto":150}],109:[function(require,module,exports){
-'use strict';
-
/**
- * `milo.util.websocket`
-**/
+ * turnOff
+ * Method of Connector that disables connection (if it was previously enabled)
+ */
+function Connector$turnOff() {
+ if (! this.isOn)
+ return logger.warn('data sources are already disconnected');
+ var self = this;
+ unlinkDataSource(this.ds1, '_link2', this.pathTranslation2);
+ unlinkDataSource(this.ds2, '_link1', this.pathTranslation1);
-var Messenger = require('../../messenger')
- , WSMessageSource = require('./msg_src')
- , WSMsgAPI = require('./msg_api');
+ this.isOn = false;
+ this.postMessage('turnedoff');
-function websocket() {
- var wsMessenger = new Messenger;
- var wsMsgSource = new WSMessageSource(wsMessenger, { send: 'trigger', connect: 'connect' }, new WSMsgAPI);
- wsMessenger._setMessageSource(wsMsgSource);
- return wsMessenger;
+ function unlinkDataSource(fromDS, linkName, pathTranslation) {
+ if (self[linkName]) {
+ fromDS.off('datachanges', self[linkName]);
+ delete self[linkName];
+ }
+ }
}
-module.exports = websocket;
+/**
+ * Destroys connector object by turning it off and removing references to connected sources
+ */
+function Connector$destroy() {
+ this.turnOff();
+ this.postMessage('destroyed');
+ this._messenger.destroy();
+ delete this.ds1;
+ delete this.ds2;
+ this._destroyed = true;
+}
-},{"../../messenger":67,"./msg_api":110,"./msg_src":111}],110:[function(require,module,exports){
+},{"../messenger":100,"../util/logger":118,"./path_utils":114,"mol-proto":122}],109:[function(require,module,exports){
'use strict';
-var MessengerAPI = require('../../messenger/m_api')
+var ModelPath = require('./m_path')
+ , synthesize = require('./synthesize')
+ , pathUtils = require('./path_utils')
+ , modelUtils = require('./model_utils')
+ , changeDataHandler = require('./change_data')
+ , Messenger = require('../messenger')
+ , MessengerMessageSource = require('../messenger/msngr_source')
+ , ModelMsgAPI = require('./m_msg_api')
+ , Mixin = require('../abstract/mixin')
, _ = require('mol-proto')
- , check = require('../../util/check')
- , Match = check.Match;
+ , check = require('../util/check')
+ , Match = check.Match
+ , logger = require('../util/logger');
-var WSMsgAPI = _.createSubclass(MessengerAPI, 'WSMsgAPI', true);
+module.exports = Model;
-_.extendProto(WSMsgAPI, {
- translateToSourceMessage: translateToSourceMessage,
- filterSourceMessage: filterSourceMessage,
- createInternalData: createInternalData
-});
+/**
+ * `milo.Model`
+ * Model class instantiates objects that allow deep data access with __safe getters__ that return undefined (rather than throwing exception) when properties/items of unexisting objects/arrays are requested and __safe setters__ that create object trees when properties/items of unexisting objects/arrays are set and also post messages to allow subscription on changes and enable data reactivity.
+ * Reactivity is implememnted via [Connector](./connector.js.html) that can be instantiated either directly or with more convenient interface of [milo.minder](../minder.js.html). At the moment model can be connected to [Data facet](../components/c_facets/Data.js.html) or to another model or [ModelPath](./m_path.js.html).
+ * Model constructor returns objects that are functions at the same time; when called they return ModelPath objects that allow get/set access to any point in model data. See [ModelData](#ModelData) below.
+ *
+ * You can subscribe to model changes with `on` method by passing model access path in place of message, pattern or string with any number of stars to subscribe to a certain depth in model (e.g., `'***'` to subscribe to three levels).
+ *
+ * @constructor
+ * @param {Object|Array} data optional initial array data. If it is planned to connect model to view it is usually better to instantiate an empty Model (`var m = new Model`), connect it to [Component](../components/c_class.js.html)'s [Data facet](../components/c_facets/Data.js.html) (e.g., `milo.minder(m, '<<->>', c.data);`) and then set the model with `m.set(data)` - the view will be automatically updated.
+ * @param {Object} hostObject optional object that hosts model on one of its properties. Can be used when model itself is the context of the message subscriber and you need to travers to this object (although it is possible to set any context). Can also be used to proxy model's methods to the host like [Model facet](../components/c_facets/ModelFacet.js.html) is doing.
+ * @param {Object} options pass { reactive: false } to use model without messaging when it is not needed - it makes it much faster
+ * @return {Model}
+ */
+function Model(data, hostObject, options) {
+ // `model` will be returned by constructor instead of `this`. `model`
+ // (`modelPath` function) should return a ModelPath object with "synthesized" methods
+ // to get/set model properties, to subscribe to property changes, etc.
+ // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.
+ var model = function modelPath(accessPath) { // , ... arguments that will be interpolated
+ return Model$path.apply(model, arguments);
+ };
+ model.__proto__ = Model.prototype;
-module.exports = WSMsgAPI;
+ model._hostObject = hostObject;
+ model._options = options || {};
+ if (model._options.reactive !== false) {
+ model._prepareMessengers();
+ // subscribe to "changedata" message to enable reactive connections
+ model.onSync('changedata', changeDataHandler);
+ }
-var SOCKET_MESSAGES = ['open', 'close', 'error', 'message'];
+ if (data) model._data = data;
-function translateToSourceMessage(message) {
- return SOCKET_MESSAGES.indexOf(message) >= 0
- ? message
- : 'message';
+ return model;
}
-
-function filterSourceMessage(sourceMessage, message, msgData) {
- if (SOCKET_MESSAGES.indexOf(message) >= 0) return true; // internal message is one of external messages
- if (sourceMessage == 'message') {
- var msgType = msgData && msgData.type;
- return msgType == message; // type equals internal message
- }
-};
+Model.prototype.__proto__ = Model.__proto__;
-function createInternalData(sourceMessage, message, event) {
- var internalData = sourceMessage == 'message'
- ? _.jsonParse(event.data) || event.data
- : event;
- return internalData;
-}
+/**
+ * ####Model instance methods####
+ *
+ * - [path](#path) - returns ModelPath object that allows access to any point in Model
+ * - [get](#Model$get) - get model data
+ * - set - set model data, synthesized
+ * - splice - splice model data (as array or pseudo-array), synthesized
+ * - [len](./m_path.js.html#ModelPath$len) - returns length of array (or pseudo-array) in model in safe way, 0 if no length is set
+ * - [push](./m_path.js.html#ModelPath$push) - add items to the end of array (or pseudo-array) in model
+ * - [pop](./m_path.js.html#ModelPath$pop) - remove item from the end of array (or pseudo-array) in model
+ * - [unshift](./m_path.js.html#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in model
+ * - [shift](./m_path.js.html#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in model
+ * - [proxyMessenger](#proxyMessenger) - proxy model's Messenger methods to host object
+ * - [proxyMethods](#proxyMethods) - proxy model methods to host object
+ */
+_.extendProto(Model, {
+ path: Model$path,
+ get: Model$get,
+ proxyMessenger: proxyMessenger, // deprecated, should not be used
+ proxyMethods: proxyMethods,
+ _prepareMessengers: _prepareMessengers,
+ _getHostObject: _getHostObject,
+ destroy: Model$destroy
+});
-},{"../../messenger/m_api":68,"../../util/check":90,"mol-proto":150}],111:[function(require,module,exports){
-'use strict';
+// set, del, splice are added to model
+_.extendProto(Model, synthesize.modelMethods);
-var MessageSource = require('../../messenger/m_source')
- , _ = require('mol-proto')
- , logger = require('../../util/logger')
- , uniqueId = require('../../util/count')
- , config = require('../../config')
- , check = require('../../util/check')
- , Match = check.Match;
+/**
+ * - Path: ModelPath class as `milo.Model.Path`
+ */
+_.extend(Model, {
+ Path: ModelPath,
+ useWith: Model$$useWith,
+ _utils: {
+ path: pathUtils,
+ model: modelUtils,
+ changeDataHandler: changeDataHandler
+ }
+});
-var WSMessageSource = _.createSubclass(MessageSource, 'WSMessageSource', true);
+/**
+ * Expose Messenger methods on Facet prototype
+ */
+var MESSENGER_PROPERTY = '_messenger';
+Messenger.useWith(Model, MESSENGER_PROPERTY, Messenger.defaultMethods);
-_.extendProto(WSMessageSource, {
- // implementing MessageSource interface
- addSourceSubscriber: addSourceSubscriber,
- removeSourceSubscriber: removeSourceSubscriber,
-
- // class specific methods
- handleEvent: WSMessageSource$handleEvent,
- connect: WSMessageSource$connect,
- trigger: WSMessageSource$trigger
+/**
+ * ModelPath methods added to Model prototype
+ */
+['len', 'push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {
+ var method = ModelPath.prototype[methodName];
+ _.defineProperty(Model.prototype, methodName, method);
});
-module.exports = WSMessageSource;
-
+/**
+ * Model instance method.
+ * Get model data.
+ *
+ * @return {Any}
+ */
+function Model$get() {
+ return this._data;
+}
-function WSMessageSource$connect(options) {
- this._options = options = options || {};
- var host = options.host || window.location.host.replace(/:.*/, '')
- , port = options.port || '8080';
+/**
+ * Model instance method.
+ * Returns ModelPath object that implements the same API as model but allows access to any point inside model as defined by `accessPath`.
+ * See [ModelPath](./m_path.js.html) class for more information.
+ *
+ * @param {String} accessPath string that defines path to access model.
+ * Path string consists of parts to define either property access (`".name"` to access property name) or array item access (`"[1]"` to access item with index 1).
+ * Access path can contain as many parts as necessary (e.g. `".list[0].name"` to access property `name` in the first element of array stored in property `list`.
+ * @param {List} arguments additional arguments of this method can be used to create interpolated paths.
+ * E.g. `m.path("[$1].$2", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m("[" + id + "]." + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.
+ * @return {ModelPath}
+ */
+function Model$path(accessPath) { // , ... arguments that will be interpolated
+ if (! accessPath) return this;
- var self = this;
+ // "null" is context to pass to ModelPath, first parameter of bind
+ // "this" (model) is added in front of all arguments
+ _.splice(arguments, 0, 0, null, this);
- if (this._ws) {
- // TODO should unsubscribe differently
- this._ws.onopen = this.ws.onmessage = this.ws.onclose = this.ws.onerror = undefined;
- this._ws.close();
- }
+ // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...
+ return new (Function.prototype.bind.apply(ModelPath, arguments));
+}
- this._ws = new WebSocket('ws://' + host + ':' + port);
- // TODO reconnect
+/**
+ * Model instance method.
+ * Proxy model's Messenger methods to host object.
+ *
+ * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.
+ */
+function proxyMessenger(modelHostObject) {
+ modelHostObject = modelHostObject || this._hostObject;
+ Mixin.prototype._createProxyMethods.call(this[MESSENGER_PROPERTY], Messenger.defaultMethods, modelHostObject);
}
-
-function addSourceSubscriber (sourceMessage) {
- _wsSubscriberMethod.call(this, 'addEventListener', sourceMessage);
-}
+var modelMethodsToProxy = ['path', 'get', 'set', 'del', 'splice', 'len', 'push', 'pop', 'unshift', 'shift'];
-function removeSourceSubscriber (sourceMessage) {
- _wsSubscriberMethod.call(this, 'removeEventListener', sourceMessage);
+/**
+ * Expose model methods on
+ * See same method in Mixin class for parameters meaning
+ *
+ * @param {Function} hostClass
+ * @param {[type]} instanceKey
+ * @param {[type]} mixinMethods optional
+ */
+function Model$$useWith(hostClass, instanceKey, mixinMethods) {
+ mixinMethods = mixinMethods || modelMethodsToProxy;
+ Mixin.useWith.call(Model, hostClass, instanceKey, mixinMethods);
}
-function _wsSubscriberMethod (method, sourceMessage) {
- if (!this._ws) return logger.error('websocket is not created');
- this._ws[method](sourceMessage, this);
+/**
+ * Model instance method.
+ * Proxy model methods to host object.
+ *
+ * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.
+ */
+function proxyMethods(modelHostObject) {
+ modelHostObject = modelHostObject || this._hostObject;
+ Mixin.prototype._createProxyMethods.call(this, modelMethodsToProxy, modelHostObject);
}
-// event dispatcher - as defined by Event DOM API
-function WSMessageSource$handleEvent (event) {
- this.dispatchMessage(event.type, event);
-}
-
-
-function WSMessageSource$trigger (msg, data, callback) {
- if (!this._ws) return logger.error('websocket is not created');
+/**
+ * Model instance method.
+ * Create and connect internal and external model's messengers.
+ * External messenger's methods are proxied on the model and they allows "*" subscriptions.
+ */
+function _prepareMessengers() {
+ // model will post all its changes on internal messenger
+ var internalMessenger = new Messenger(this, undefined, undefined);
- data = data || {};
- data.type = msg;
+ // message source to connect internal messenger to external
+ var internalMessengerSource = new MessengerMessageSource(this, undefined, new ModelMsgAPI, internalMessenger);
- var self = this;
-
- if (callback) {
- data.callbackCorrId = uniqueId();
- var interval = _.delay(onTimeout, config.websocket.rpc.timeout);
- toggleRpcSubscription('once', data.callbackCorrId);
- }
+ // external messenger to which all model users will subscribe,
+ // that will allow "*" subscriptions and support "changedata" message api.
+ var externalMessenger = new Messenger(this, undefined, internalMessengerSource);
- this._ws.send(JSON.stringify(data));
+ _.defineProperty(this, MESSENGER_PROPERTY, externalMessenger);
+ _.defineProperty(this, '_internalMessenger', internalMessenger);
+}
- function onTimeout() {
- toggleRpcSubscription('off', data.callbackCorrId);
- callback(new Error('websocket rpc: timeout'));
- }
+function _getHostObject() {
+ return this._hostObject;
+}
- function onResponse(msg, msgData) {
- clearInterval(interval);
- if (typeof msgData == 'object') {
- var err = msgData.error ? new Error(msgData.error) : null;
- callback(err, msgData.data)
- } else
- callback(new Error('websocket rpc: invalid response data'), msgData);
- }
- function toggleRpcSubscription(onOff, corrId) {
- self.messenger[onOff](config.websocket.rpc.responsePrefix + corrId, onResponse);
- }
+function Model$destroy() {
+ this[MESSENGER_PROPERTY].destroy();
+ this._internalMessenger.destroy();
+ this._destroyed = true;
}
-},{"../../config":65,"../../messenger/m_source":70,"../../util/check":90,"../../util/count":92,"../../util/logger":102,"mol-proto":150}],112:[function(require,module,exports){
-;(function(){
+},{"../abstract/mixin":97,"../messenger":100,"../messenger/msngr_source":104,"../util/check":116,"../util/logger":118,"./change_data":107,"./m_msg_api":110,"./m_path":111,"./model_utils":112,"./path_utils":114,"./synthesize":115,"mol-proto":122}],110:[function(require,module,exports){
+'use strict';
-// This would be the place to edit if you want a different
-// Base32 implementation
+var MessengerRegexpAPI = require('../messenger/m_api_rx')
+ , pathUtils = require('./path_utils')
+ , _ = require('mol-proto');
-var alphabet = '0123456789abcdefghjkmnpqrtuvwxyz'
-var alias = { o:0, i:1, l:1, s:5 }
/**
- * Build a lookup table and memoize it
- *
- * Return an object that maps a character to its
- * byte value.
+ * Subclass of MessengerRegexpAPI that is used to translate messages of external messenger of Model to internal messenger of Model.
*/
+var ModelMsgAPI = _.createSubclass(MessengerRegexpAPI, 'ModelMsgAPI');
+
+module.exports = ModelMsgAPI;
-var lookup = function() {
- var table = {}
- // Invert 'alphabet'
- for (var i = 0; i < alphabet.length; i++) {
- table[alphabet[i]] = i
- }
- // Splice in 'alias'
- for (var key in alias) {
- if (!alias.hasOwnProperty(key)) continue
- table[key] = table['' + alias[key]]
- }
- lookup = function() { return table }
- return table
-}
/**
- * A streaming encoder
+ * ####ModelMsgAPI instance methods####
*
- * var encoder = new base32.Encoder()
- * var output1 = encoder.update(input1)
- * var output2 = encoder.update(input2)
- * var lastoutput = encode.update(lastinput, true)
+ * - [translateToSourceMessage](#translateToSourceMessage) - translates subscription paths with "*"s to regex, leaving other strings untouched
*/
+_.extendProto(ModelMsgAPI, {
+ translateToSourceMessage: translateToSourceMessage,
+});
-function Encoder() {
- var skip = 0 // how many bits we will skip from the first byte
- var bits = 0 // 5 high bits, carry from one byte to the next
- this.output = ''
+/**
+ * ModelMsgAPI instance method
+ * Translates subscription paths with "*"s to regex, leaving other strings untouched.
+ *
+ * @param {String} accessPath relative access path to be translated
+ * @return {RegExp|String}
+ */
+function translateToSourceMessage(accessPath) {
+ if (accessPath instanceof RegExp) return accessPath;
- // Read one byte of input
- // Should not really be used except by "update"
- this.readByte = function(byte) {
- // coerce the byte to an int
- if (typeof byte == 'string') byte = byte.charCodeAt(0)
+ return pathUtils.createRegexPath(accessPath);
+}
- if (skip < 0) { // we have a carry from the previous byte
- bits |= (byte >> (-skip))
- } else { // no carry
- bits = (byte << skip) & 248
- }
+},{"../messenger/m_api_rx":102,"./path_utils":114,"mol-proto":122}],111:[function(require,module,exports){
+'use strict';
- if (skip > 3) {
- // not enough data to produce a character, get us another one
- skip -= 8
- return 1
- }
+var synthesize = require('./synthesize')
+ , pathUtils = require('./path_utils')
+ , changeDataHandler = require('./change_data')
+ , Messenger = require('../messenger')
+ , ModelPathMsgAPI = require('./path_msg_api')
+ , MessengerMessageSource = require('../messenger/msngr_source')
+ , _ = require('mol-proto')
+ , check = require('../util/check')
+ , Match = check.Match;
- if (skip < 4) {
- // produce a character
- this.output += alphabet[bits >> 3]
- skip += 5
- }
- return 0
- }
+module.exports = ModelPath;
- // Flush any remaining bits left in the stream
- this.finish = function(check) {
- var output = this.output + (skip < 0 ? alphabet[bits >> 3] : '') + (check ? '$' : '')
- this.output = ''
- return output
- }
-}
/**
- * Process additional input
+ * `milo.Model.Path`
+ * ModelPath object that allows access to any point inside [Model](./index.js.html) as defined by `accessPath`
*
- * input: string of bytes to convert
- * flush: boolean, should we flush any trailing bits left
- * in the stream
- * returns: a string of characters representing 'input' in base32
+ * @constructor
+ * @param {Model} model Model instance that ModelPath gives access to.
+ * @param {String} accessPath string that defines path to access model.
+ * Path string consists of parts to define either property access (`".name"` to access property name) or array item access (`"[1]"` to access item with index 1).
+ * Access path can contain as many parts as necessary (e.g. `".list[0].name"` to access property `name` in the first element of array stored in property `list`.
+ * @param {List} arguments additional arguments of this method can be used to create interpolated paths.
+ * E.g. `m.path("[$1].$2", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m("[" + id + "]." + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.
+ * @return {ModelPath}
*/
+function ModelPath(model, path) { // ,... - additional arguments for interpolation
+ // check(model, Model);
+ check(path, String);
-Encoder.prototype.update = function(input, flush) {
- for (var i = 0; i < input.length; ) {
- i += this.readByte(input[i])
- }
- // consume all output
- var output = this.output
- this.output = ''
- if (flush) {
- output += this.finish()
- }
- return output
-}
+ // `modelPath` will be returned by constructor instead of `this`. `modelPath`
+ // (`modelPath_path` function) should also return a ModelPath object with "synthesized" methods
+ // to get/set model properties, to subscribe to property changes, etc.
+ // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.
+ var modelPath = function modelPath_path(accessPath) { // , ... arguments that will be interpolated
+ return ModelPath$path.apply(modelPath, arguments);
+ };
+ modelPath.__proto__ = ModelPath.prototype;
-// Functions analogously to Encoder
-function Decoder() {
- var skip = 0 // how many bits we have from the previous character
- var byte = 0 // current byte we're producing
+ _.defineProperties(modelPath, {
+ _model: model,
+ _path: path,
+ _args: _.slice(arguments, 1), // path will be the first element of this array
+ _options: model._options
+ });
- this.output = ''
+ // parse access path
+ var parsedPath = pathUtils.parseAccessPath(path);
- // Consume a character from the stream, store
- // the output in this.output. As before, better
- // to use update().
- this.readChar = function(char) {
- if (typeof char != 'string'){
- if (typeof char == 'number') {
- char = String.fromCharCode(char)
- }
- }
- char = char.toLowerCase()
- var val = lookup()[char]
- if (typeof val == 'undefined') {
- // character does not exist in our lookup table
- return // skip silently. An alternative would be:
- // throw Error('Could not find character "' + char + '" in lookup table.')
- }
- val <<= 3 // move to the high bits
- byte |= val >>> skip
- skip += 5
- if (skip >= 8) {
- // we have enough to preduce output
- this.output += String.fromCharCode(byte)
- skip -= 8
- if (skip > 0) byte = (val << (5 - skip)) & 255
- else byte = 0
- }
+ // compute access path string
+ _.defineProperty(modelPath, '_accessPath', interpolateAccessPath(parsedPath, modelPath._args));
+ if (modelPath._options.reactive !== false) {
+ // messenger fails on "*" subscriptions
+ modelPath._prepareMessenger();
+ // subscribe to "changedata" message to enable reactive connections
+ modelPath.onSync('changedata', changeDataHandler);
}
- this.finish = function(check) {
- var output = this.output + (skip < 0 ? alphabet[bits >> 3] : '') + (check ? '$' : '')
- this.output = ''
- return output
- }
-}
+ // compiling getter and setter
+ var methods = synthesize(path, parsedPath);
-Decoder.prototype.update = function(input, flush) {
- for (var i = 0; i < input.length; i++) {
- this.readChar(input[i])
- }
- var output = this.output
- this.output = ''
- if (flush) {
- output += this.finish()
- }
- return output
-}
+ // adding methods to model path
+ _.defineProperties(modelPath, methods);
-/** Convenience functions
- *
- * These are the ones to use if you just have a string and
- * want to convert it without dealing with streams and whatnot.
- */
+ Object.freeze(modelPath);
-// String of data goes in, Base32-encoded string comes out.
-function encode(input) {
- var encoder = new Encoder()
- var output = encoder.update(input, true)
- return output
+ return modelPath;
}
-// Base32-encoded string goes in, decoded data comes out.
-function decode(input) {
- var decoder = new Decoder()
- var output = decoder.update(input, true)
- return output
-}
+ModelPath.prototype.__proto__ = ModelPath.__proto__;
-var base32 = {
- Decoder: Decoder,
- Encoder: Encoder,
- encode: encode,
- decode: decode
-}
-if (typeof window !== 'undefined') {
- // we're in a browser - OMG!
- window.base32 = base32
+/**
+ * Interpolates path elements to compute real path
+ *
+ * @param {Array} parsedPath parsed path - array of path nodes
+ * @param {Array} args path interpolation arguments, args[0] is path itself
+ * @return {String}
+ */
+function interpolateAccessPath(parsedPath, args) {
+ return parsedPath.reduce(function(accessPathStr, currNode, index) {
+ var interpolate = currNode.interpolate;
+ return accessPathStr +
+ (interpolate
+ ? (currNode.syntax == 'array'
+ ? '[' + args[interpolate] + ']'
+ : '.' + args[interpolate])
+ : currNode.property);
+ }, '');
}
-if (typeof module !== 'undefined' && module.exports) {
- // nodejs/browserify
- module.exports = base32
-}
-})();
-},{}],113:[function(require,module,exports){
+/**
+ * ####ModelPath instance methods####
+ *
+ * - [path](#ModelPath$path) - gives access to path inside ModelPath
+ * - get - synthesized
+ * - set - synthesized
+ * - splice - splice model data (as array or pseudo-array), synthesized
+ * - [len](#ModelPath$len) - returns length of array (or pseudo-array) in safe way, 0 if no length is set
+ * - [push](#ModelPath$push) - add items to the end of array (or pseudo-array) in ModelPath
+ * - [pop](#ModelPath$pop) - remove item from the end of array (or pseudo-array) in ModelPath
+ * - [unshift](#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in ModelPath
+ * - [shift](#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in ModelPath
+ */
+_.extendProto(ModelPath, {
+ path: ModelPath$path,
+ len: ModelPath$len,
+ push: ModelPath$push,
+ pop: ModelPath$pop,
+ unshift: ModelPath$unshift,
+ shift: ModelPath$shift,
+ _prepareMessenger: _prepareMessenger,
+ _getDefinition: _getDefinition,
+ destroy: ModelPath$destroy
+});
-// not implemented
-// The reason for having an empty file and not throwing is to allow
-// untraditional implementation of this module.
-},{}],114:[function(require,module,exports){
-// doT.js
-// 2011-2014, Laura Doktorova, https://github.com/olado/doT
-// Licensed under the MIT license.
+_.extend(ModelPath, {
+ _createFromDefinition: _createFromDefinition
+})
-(function() {
- "use strict";
- var doT = {
- version: "1.0.3",
- templateSettings: {
- evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g,
- interpolate: /\{\{=([\s\S]+?)\}\}/g,
- encode: /\{\{!([\s\S]+?)\}\}/g,
- use: /\{\{#([\s\S]+?)\}\}/g,
- useParams: /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
- define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
- defineParams:/^\s*([\w$]+):([\s\S]+)/,
- conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
- iterate: /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
- varname: "it",
- strip: true,
- append: true,
- selfcontained: false,
- doNotSkipEncoded: false
- },
- template: undefined, //fn, compile template
- compile: undefined //fn, for express
- }, _globals;
+/**
+ * Expose Messenger methods on Facet prototype
+ */
+var MESSENGER_PROPERTY = '_messenger';
+Messenger.useWith(ModelPath, MESSENGER_PROPERTY, Messenger.defaultMethods);
- doT.encodeHTMLSource = function(doNotSkipEncoded) {
- var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'", "/": "/" },
- matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g;
- return function(code) {
- return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : "";
- };
- };
- _globals = (function(){ return this || (0,eval)("this"); }());
+/**
+ * ModelPath instance method
+ * Gives access to path inside ModelPath. Method works similarly to [path method](#Model$path) of model, using relative paths.
+ *
+ * @param {String} accessPath string that defines path to access model.
+ * Path string consists of parts to define either property access (`".name"` to access property name) or array item access (`"[1]"` to access item with index 1).
+ * Access path can contain as many parts as necessary (e.g. `".list[0].name"` to access property `name` in the first element of array stored in property `list`.
+ * @param {List} arguments additional arguments of this method can be used to create interpolated paths.
+ * E.g. `m.path("[$1].$2", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m("[" + id + "]." + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.
+ * @return {ModelPath}
+ */
+function ModelPath$path(accessPath) { // , ... arguments that will be interpolated
+ if (! accessPath) return this;
- if (typeof module !== "undefined" && module.exports) {
- module.exports = doT;
- } else if (typeof define === "function" && define.amd) {
- define(function(){return doT;});
- } else {
- _globals.doT = doT;
- }
+ var thisPathArgsCount = this._args.length - 1;
- var startend = {
- append: { start: "'+(", end: ")+'", startencode: "'+encodeHTML(" },
- split: { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML(" }
- }, skip = /$^/;
+ if (thisPathArgsCount > 0) {// this path has interpolated arguments too
+ accessPath = accessPath.replace(/\$[1-9][0-9]*/g, function(str) {
+ return '$' + (+str.slice(1) + thisPathArgsCount);
+ });
+ }
- function resolveDefs(c, block, def) {
- return ((typeof block === "string") ? block : block.toString())
- .replace(c.define || skip, function(m, code, assign, value) {
- if (code.indexOf("def.") === 0) {
- code = code.substring(4);
- }
- if (!(code in def)) {
- if (assign === ":") {
- if (c.defineParams) value.replace(c.defineParams, function(m, param, v) {
- def[code] = {arg: param, text: v};
- });
- if (!(code in def)) def[code]= value;
- } else {
- new Function("def", "def['"+code+"']=" + value)(def);
- }
- }
- return "";
- })
- .replace(c.use || skip, function(m, code) {
- if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {
- if (def[d] && def[d].arg && param) {
- var rw = (d+":"+param).replace(/'|\\/g, "_");
- def.__exp = def.__exp || {};
- def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2");
- return s + "def.__exp['"+rw+"']";
- }
- });
- var v = new Function("def", "return " + code)(def);
- return v ? resolveDefs(c, v, def) : v;
- });
- }
+ var newPath = this._path + accessPath;
- function unescape(code) {
- return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " ");
- }
+ // this._model is added in front of all arguments as the first parameter
+ // of ModelPath constructor
+ var args = [this._model, newPath]
+ .concat(this._args.slice(1)) // remove old path from _args, as it is 1 based
+ .concat(_.slice(arguments, 1)); // add new interpolation arguments
- doT.template = function(tmpl, c, def) {
- c = c || doT.templateSettings;
- var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,
- str = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;
+ // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...
+ return _.newApply(ModelPath, args);
+}
- str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ")
- .replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""): str)
- .replace(/'|\\/g, "\\$&")
- .replace(c.interpolate || skip, function(m, code) {
- return cse.start + unescape(code) + cse.end;
- })
- .replace(c.encode || skip, function(m, code) {
- needhtmlencode = true;
- return cse.startencode + unescape(code) + cse.end;
- })
- .replace(c.conditional || skip, function(m, elsecase, code) {
- return elsecase ?
- (code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
- (code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
- })
- .replace(c.iterate || skip, function(m, iterate, vname, iname) {
- if (!iterate) return "';} } out+='";
- sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
- return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+" length
+ ? length
+ : spliceIndex >= 0
+ ? spliceIndex
+ : spliceIndex + length > 0
+ ? spliceIndex + length
+ : 0;
}
+},{}],113:[function(require,module,exports){
+'use strict';
-/**
- * Sets mixin instance property name on the host class
- * Can be called only once
- *
- * @private
- * @param {Function} this Mixin subclass (not instance)
- * @param {Function} hostClass
- * @param {String} instanceKey
- */
-function Mixin_setInstanceKey(hostClass, method, instanceKey) {
- check(hostClass, Function);
- check(instanceKey, Match.IdentifierString);
+var MessengerAPI = require('../messenger/m_api')
+ , pathUtils = require('./path_utils')
+ , logger = require('../util/logger')
+ , _ = require('mol-proto');
- var prop = config.mixin.instancePropertiesMap
- , instanceKeys = hostClass[prop] = hostClass[prop] || {};
- if (instanceKeys[method.name])
- throw new Error('Mixin: instance property for method with name '
- + method.name + ' is already set');
+/**
+ * Subclass of MessengerAPI that is used to translate messages of Messenger on ModelPath to Messenger on Model.
+ */
+var ModelPathMsgAPI = _.createSubclass(MessengerAPI, 'ModelPathMsgAPI');
- instanceKeys[method.name] = instanceKey;
-}
+module.exports = ModelPathMsgAPI;
/**
- * Adds method of Mixin subclass to host class prototype.
+ * ####ModelPathMsgAPI instance methods####
*
- * @private
- * @param {Function} this Mixin subclass (not instance)
- * @param {String} mixinMethodName name of method in Mixin subclass
- * @param {String} hostMethodName (optional) name of created proxy method on host object, same if not specified
- * @param {Object} hostObject object class, must be specified as the last parameter (2nd or 3rd)
+ * - [init](#init) - initializes ModelPathMsgAPI
+ * - [translateToSourceMessage](#translateToSourceMessage) - translates relative access paths of ModelPath to full path of Model
+ * - [createInternalData](#createInternalData) - changes path in message on model to relative path and adds `fullPath` property to message data
*/
-function Mixin_addMethod(hostClass, instanceKey, mixinMethodName, hostMethodName) {
- var method = this.prototype[mixinMethodName];
- check(method, Function);
-
- var wrappedMethod = _wrapMixinMethod.call(this, method);
+_.extendProto(ModelPathMsgAPI, {
+ init: init,
+ translateToSourceMessage: translateToSourceMessage,
+ createInternalData: createInternalData,
+});
- _.defineProperty(hostClass.prototype, hostMethodName, wrappedMethod, _.WRIT);
- Mixin_setInstanceKey(hostClass, method, instanceKey)
+/**
+ * ModelPathMsgAPI instance method
+ * Called by MessengerAPI constructor.
+ *
+ * @param {String} rootPath root path of model path
+ */
+function init(rootPath) {
+ MessengerAPI.prototype.init.apply(this, arguments);
+ this.rootPath = rootPath;
}
-
/**
- * Returns method that will be exposed on the host class prototype
+ * ModelPathMsgAPI instance method
+ * Translates relative access paths of ModelPath to full path of Model.
*
- * @private
- * @param {Function} this Mixin subclass (not instance)
- * @return {Function}
+ * @param {String} accessPath relative access path to be translated
+ * @return {String}
*/
-function _wrapMixinMethod(method) {
- return function() { // ,... arguments
- var mixinInstance = _getMixinInstance.call(this, method.name);
- return method.apply(mixinInstance, arguments);
- }
+function translateToSourceMessage(message) {
+ // TODO should prepend RegExes
+ // TODO should not prepend changedata too???
+ if (message instanceof RegExp)
+ return message;
+ if (message == 'datachanges')
+ return message;
+
+ return this.rootPath + message;
}
/**
- * Returns the reference to the instance of mixin subclass.
- * This method is used when methods are exposed on the host class prototype (using addMehtods) rather than on host instance.
- * Subclasses should not use this methods - whenever subclass method is exposed on the prototype it will be wrapped to set correct context for the subclass method.
+ * ModelPathMsgAPI instance method
+ * Changes path in message on model to relative path and adds `fullPath` property to message data.
*
- * @private
+ * @param {String} sourceMessage full access path on Model
+ * @param {String} message relative access path on ModelPath
+ * @param {Object} sourceData data received from Model, will be translated as described to be dispatched to ModelPath
* @return {Object}
*/
-function _getMixinInstance(methodName) {
- if (this instanceof Mixin) return this;
- var instanceKeys = this.constructor[config.mixin.instancePropertiesMap]
- return this[instanceKeys[methodName]];
+function createInternalData(sourceMessage, message, sourceData) {
+ // TODO return on changedata too???
+ if (message == 'datachanges') {
+ var internalChanges = sourceData.changes
+ .map(truncateChangePath, this)
+ .filter(function(change) { return change; });
+ var internalData = {
+ changes: internalChanges,
+ transaction: sourceData.transaction
+ };
+
+ return internalData
+ }
+
+ var internalData = truncateChangePath.call(this, sourceData);
+ return internalData;
}
-/**
- * Adds methods of Mixin subclass to host class prototype.
- *
- * @param {Function} this Mixin subclass (not instance)
- * @param {Object} hostClass host object class; must be specified.
- * @param {String} instanceKey the name of the property the host class instance will store mixin instance on
- * @param {Hash[String]|Array[String]} mixinMethods map of names of methods, key - host method name, value - mixin method name. Can be array.
- */
-function Mixin$$useWith(hostClass, instanceKey, mixinMethods) {
- check(mixinMethods, Match.Optional(Match.OneOf([String], Match.ObjectHash(String))));
+function truncateChangePath(change) {
+ var fullPath = change.path
+ , path = _.unPrefix(fullPath, this.rootPath);
- if (Array.isArray(mixinMethods))
- mixinMethods.forEach(function(methodName) {
- Mixin_addMethod.call(this, hostClass, instanceKey, methodName, methodName);
- }, this);
- else
- _.eachKey(mixinMethods, function(mixinMethodName, hostMethodName) {
- Mixin_addMethod.call(this, hostClass, instanceKey, mixinMethodName, hostMethodName);
- }, this);
+ if (typeof path == 'string') {
+ var change = _.clone(change);
+ change.fullPath = fullPath;
+ change.path = path;
+ return change;
+ }
}
-},{"../config":118,"../util/check":135,"mol-proto":141}],117:[function(require,module,exports){
+},{"../messenger/m_api":101,"../util/logger":118,"./path_utils":114,"mol-proto":122}],114:[function(require,module,exports){
'use strict';
-//
-// milo.classes
-// -----------
+//
+// ### model path utils
-// This module contains foundation classes
+var check = require('../util/check')
+ , Match = check.Match
+ , _ = require('mol-proto');
-var classes = {
- Mixin: require('./abstract/mixin'),
- MessageSource: require('./messenger/m_source'),
- MessengerMessageSource: require('./messenger/msngr_source'),
- MessengerAPI: require('./messenger/m_api'),
- MessengerRegexpAPI: require('./messenger/m_api_rx')
+var pathUtils = {
+ parseAccessPath: parseAccessPath,
+ createRegexPath: createRegexPath,
+ getPathNodeKey: getPathNodeKey,
+ wrapMessengerMethods: wrapMessengerMethods
};
-module.exports = classes;
+module.exports = pathUtils;
-},{"./abstract/mixin":116,"./messenger/m_api":120,"./messenger/m_api_rx":121,"./messenger/m_source":122,"./messenger/msngr_source":123}],118:[function(require,module,exports){
-'use strict';
+var propertyPathSyntax = '\\.[A-Za-z_-][A-Za-z0-9_-]*'
+ , arrayPathSyntax = '\\[[0-9]+\\]'
+ , interpolationSyntax = '\\$[1-9][0-9]*'
+ , propertyInterpolateSyntax = '\\.' + interpolationSyntax
+ , arrayInterpolateSyntax = '\\[' + interpolationSyntax + '\\]'
-var _ = require('mol-proto');
+ , propertyStarSyntax = '\\.\\*'
+ , arrayStarSyntax = '\\[\\*\\]'
+ , starSyntax = '\\*'
+ , pathParseSyntax = [
+ propertyPathSyntax,
+ arrayPathSyntax,
+ propertyInterpolateSyntax,
+ arrayInterpolateSyntax
+ ].join('|')
+ , pathParsePattern = new RegExp(pathParseSyntax, 'g')
-module.exports = config;
+ , patternPathParseSyntax = [
+ pathParseSyntax,
+ propertyStarSyntax,
+ arrayStarSyntax,
+ starSyntax
+ ].join('|')
+ , patternPathParsePattern = new RegExp(patternPathParseSyntax, 'g')
-function config(options) {
- _.deepExtend(config, options);
-}
+ //, targetPathParsePattern = /\.[A-Za-z][A-Za-z0-9_]*|\[[0-9]+\]|\.\$[1-9][0-9]*|\[\$[1-9][0-9]*\]|\$[1-9][0-9]/g
+ , pathNodeTypes = {
+ '.': { syntax: 'object', empty: '{}' },
+ '[': { syntax: 'array', empty: '[]'},
+ '*': { syntax: 'match', empty: '{}'},
+ };
-config({
- mixin: {
- instancePropertiesMap: '___mixin_instances'
- },
- check: true,
- debug: false
-});
+function parseAccessPath(path, nodeParsePattern) {
+ nodeParsePattern = nodeParsePattern || pathParsePattern;
-},{"mol-proto":141}],119:[function(require,module,exports){
-'use strict';
+ var parsedPath = [];
-var Mixin = require('../abstract/mixin')
- , MessageSource = require('./m_source')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match;
-
-
-/**
- * `milo.Messenger`
- * A generic Messenger class that is used for all kinds of messaging in milo. It is subclassed from [Mixin](../abstract/mixin.js.html) and it proxies its methods to the host object for convenience.
- * All facets and components have messenger attached to them. Messenger class interoperates with [MessageSource](./m_source.js.html) class that connects the messenger to some external source of messages (e.g., DOM events) and [MessengerAPI](./m_api.js.html) class that allows to define higher level messages than messages that exist on the source.
- * Messenger class is used internally in milo and can be used together with any objects/classes in the application.
- * milo also defines a global messenger [milo.mail](../mail/index.js.html) that dispatches `domready` event and can be used for any application wide messaging.
- * To initialize your app after DOM is ready use:
- * ```
- * milo.mail.on('domready', function() {
- * // application starts
- * });
- * ```
- * or the following shorter form of the same:
- * ```
- * milo(function() {
- * // application starts
- * });
- * ```
- */
-var Messenger = _.createSubclass(Mixin, 'Messenger');
+ if (! path)
+ return parsedPath;
-var messagesSplitRegExp = Messenger.messagesSplitRegExp = /\s*(?:\,|\s)\s*/;
+ var unparsed = path.replace(nodeParsePattern, function(nodeStr) {
+ var pathNode = { property: nodeStr };
+ _.extend(pathNode, pathNodeTypes[nodeStr[0]]);
+ if (nodeStr[1] == '$')
+ pathNode.interpolate = getPathNodeKey(pathNode, true);
+ parsedPath.push(pathNode);
+ return '';
+ });
+ if (unparsed)
+ throw new Error('incorrect model path: ' + path);
-/**
- * ####Messenger instance methods####
- *
- * - [init](#init)
- * - [on](#Messenger$on) (alias - onMessage, deprecated)
- * - [off](#Messenger$off) (alias - offMessage, deprecated)
- * - [onMessages](#onMessages)
- * - [offMessages](#offMessages)
- * - [once](#once)
- * - [onceSync](#onceSync)
- * - [postMessage](#postMessage)
- * - [getSubscribers](#getSubscribers)
- *
- * "Private" methods
- *
- * - [_chooseSubscribersHash](#_chooseSubscribersHash)
- * - [_registerSubscriber](#_registerSubscriber)
- * - [_removeSubscriber](#_removeSubscriber)
- * - [_removeAllSubscribers](#_removeAllSubscribers)
- * - [_callPatternSubscribers](#_callPatternSubscribers)
- * - [_callSubscribers](#_callSubscribers)
- * - [_setMessageSource](#_setMessageSource)
- * - [getMessageSource](#getMessageSource)
- */
-_.extendProto(Messenger, {
- init: init, // called by Mixin (superclass)
- destroy: Messenger$destroy,
- on: Messenger$on,
- once: Messenger$once,
- onceSync: Messenger$onceSync,
- onSync: Messenger$onSync,
- onAsync: Messenger$onAsync,
- onMessage: Messenger$on, // deprecated
- off: Messenger$off,
- offMessage: Messenger$off, // deprecated
- onMessages: onMessages,
- offMessages: offMessages,
- offAll: Messenger$offAll,
- postMessage: postMessage,
- postMessageSync: postMessageSync,
- getSubscribers: getSubscribers,
- getMessageSource: getMessageSource,
- _chooseSubscribersHash: _chooseSubscribersHash,
- _registerSubscriber: _registerSubscriber,
- _removeSubscriber: _removeSubscriber,
- _removeAllSubscribers: _removeAllSubscribers,
- _callPatternSubscribers: _callPatternSubscribers,
- _callSubscribers: _callSubscribers,
- _callSubscriber: _callSubscriber,
- _setMessageSource: _setMessageSource
-});
+ return parsedPath;
+}
-/**
- * A default map of proxy methods used by ComponentFacet and Component classes to pass to Messenger when it is instantiated.
- * This map is for convenience only, it is NOT used internally by Messenger, a host class should pass it for methods to be proxied this way.
- */
-Messenger.defaultMethods = {
- on: 'on',
- onSync: 'onSync',
- once: 'once',
- onceSync: 'onceSync',
- off: 'off',
- onMessages: 'onMessages',
- offMessages: 'offMessages',
- postMessage: 'postMessage',
- postMessageSync: 'postMessageSync',
- getSubscribers: 'getSubscribers'
+var nodeRegex = {
+ '.*': propertyPathSyntax,
+ '[*]': arrayPathSyntax
};
+nodeRegex['*'] = nodeRegex['.*'] + '|' + nodeRegex['[*]'];
+function createRegexPath(path) {
+ check(path, Match.OneOf(String, RegExp));
-module.exports = Messenger;
-
+ if (path instanceof RegExp || path.indexOf('*') == -1)
+ return path;
-Messenger.subscriptions = [];
+ var parsedPath = pathUtils.parseAccessPath(path, patternPathParsePattern)
+ , regexStr = '^'
+ // , regexStrEnd = ''
+ , patternsStarted = false;
+ parsedPath.forEach(function(pathNode) {
+ var prop = pathNode.property
+ , regex = nodeRegex[prop];
+
+ if (regex) {
+ // regexStr += '(' + regex;
+ // regexStrEnd += '|)';
+ regexStr += '(' + regex + '|)';
+ // regexStrEnd += '|)';
+ patternsStarted = true;
+ } else {
+ // if (patternsStarted)
+ // throw new Error('"*" path segment cannot be in the middle of the path: ' + path);
+ regexStr += prop.replace(/(\.|\[|\])/g, '\\$1'); // add slash in front of symbols that have special meaning in regex
+ }
+ });
-/**
- * Messenger instance method
- * Initializes Messenger. Method is called by Mixin class constructor.
- * See [on](#Messenger$on) method, [Messenger](#Messenger) class above and [MessageSource](./m_source.js.html) class.
- *
- * @param {Object} hostObject Optional object that stores the messenger on one of its properties. It is used to proxy methods of messenger and also as a context for subscribers when they are called by the Messenger. See `on` method.
- * @param {Object} proxyMethods Optional map of method names; key - proxy method name, value - messenger's method name.
- * @param {MessageSource} messageSource Optional messageSource linked to the messenger. If messageSource is supplied, the reference to the messenger will stored on its 'messenger' property
- */
-function init(hostObject, proxyMethods, messageSource) {
- // hostObject and proxyMethods are used in Mixin and checked there
- if (messageSource)
- this._setMessageSource(messageSource);
+ regexStr += /* regexStrEnd + */ '$';
- _initializeSubscribers.call(this);
+ try {
+ return new RegExp(regexStr);
+ } catch (e) {
+ throw new Error('can\'t construct regex for path pattern: ' + path);
+ }
}
-function _initializeSubscribers() {
- _.defineProperties(this, {
- _messageSubscribers: {},
- _patternMessageSubscribers: {},
- }, _.CONF);
+function getPathNodeKey(pathNode, interpolated) {
+ var prop = pathNode.property
+ , startIndex = interpolated ? 2 : 1;
+ return pathNode.syntax == 'array'
+ ? prop.slice(startIndex, prop.length - 1)
+ : prop.slice(startIndex);
}
-/**
- * Destroys messenger. Maybe needs to unsubscribe all subscribers
- */
-function Messenger$destroy() {
- this.offAll();
- var messageSource = this.getMessageSource();
- if (messageSource)
- messageSource.destroy();
+// TODO allow for multiple messages in a string
+function wrapMessengerMethods(methodsNames) {
+ methodsNames = methodsNames || ['on', 'off'];
+ var wrappedMethods = _.mapToObject(methodsNames, function(methodName) {
+ var origMethod = this[methodName];
+ // replacing message subsribe/unsubscribe/etc. to convert "*" message patterns to regexps
+ return function(path, subscriber) {
+ var regexPath = createRegexPath(path);
+ origMethod.call(this, regexPath, subscriber);
+ };
+ }, this);
+ _.defineProperties(this, wrappedMethods);
}
+},{"../util/check":116,"mol-proto":122}],115:[function(require,module,exports){
+'use strict';
+
+var pathUtils = require('../path_utils')
+ , modelUtils = require('../model_utils')
+ , logger = require('../../util/logger')
+ , fs = require('fs')
+ , doT = require('dot')
+ , _ = require('mol-proto')
+ , changeDataHandler = require('../change_data')
+ , getTransactionFlag = changeDataHandler.getTransactionFlag
+ , postTransactionFinished = changeDataHandler.postTransactionFinished;
+
/**
- * Messenger instance method.
- * Registers a subscriber function for a certain message(s).
- * This method returns `true` if the subscription was successful. It can be unsuccessful if the passed subscriber has already been subscribed to this message type - double subscription never happens and it is safe to subscribe again - no error or warning is thrown or logged.
- * Subscriber is passed two parameters: `message` (string) and `data` (object). Data object is supplied when message is dispatched, Messenger itself adds nothing to it. For example, [events facet](../components/c_facets/Events.js.html) sends actual DOM event when it posts message.
- * Usage:
- * ```
- * // subscribes onMouseUpDown to two DOM events on component via events facet.
- * myComp.events.on('mousedown mouseup', onMouseUpDown);
- * function onMouseUpDown(eventType, event) {
- * // ...
- * }
- *
- * myComp.data.on(/.+/, function(msg, data) {
- * logger.debug(msg, data);
- * }); // subscribes anonymous function to all non-empty messages on data facet
- * // it will not be possible to unsubscribe anonymous subscriber separately,
- * // but myComp.data.off(/.+/) will unsubscribe it
- * ```
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added, so it can subscribe to the source.
- * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `on` when they proxy it.
- * See [postMessage](#postMessage).
- *
- * @param {String|Array[String]|RegExp} messages Message types that should envoke the subscriber.
- * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.
- * If an array of strings is passed, each string is a message type to subscribe for.
- * If a RegExp is passed, the subscriber will be envoked when the message dispatched on the messenger matches the pattern (or IS the RegExp with identical pattern).
- * Pattern subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.
- * @param {Function|Object} subscriber Message subscriber - a function that will be called when the message is dispatched on the messenger (usually via proxied postMessage method of host object).
- * If hostObject was supplied to Messenger constructor, hostObject will be the context (the value of this) for the subscriber envocation.
- * Subscriber can also be an object with properties `subscriber` (function) and `context` ("this" value when subscriber is called)
- * @return {Boolean}
+ * Templates to synthesize model getters and setters
*/
-function Messenger$on(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber);
-}
+var templates = {
+ get: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\nmethod = function get() {\n var m = {{# def.modelAccessPrefix }};\n return m {{~ it.parsedPath :pathNode }}\n {{? pathNode.interpolate}}\n && (m = m[this._args[ {{= pathNode.interpolate }} ]])\n {{??}}\n && (m = m{{= pathNode.property }})\n {{?}} {{~}};\n};\n",
+ set: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n{{# def.include_defines }}\n{{# def.include_create_tree }}\n\n\n/**\n * Template that synthesizes setter for Model and for ModelPath\n */\nmethod = function set(value) {\n {{# def.initVars:'set' }}\n\n {{# def.createTree:'set' }}\n\n {{\n currNode = nextNode;\n currProp = currNode && currNode.property;\n }}\n\n {{ /* assign value to the last property */ }}\n {{? currProp }}\n wasDef = {{# def.wasDefined}};\n {{# def.changeAccessPath }}\n\n var old = m{{# def.currProp }};\n\n {{ /* clone value to prevent same reference in linked models */ }}\n m{{# def.currProp }} = cloneTree(value);\n {{?}}\n\n {{ /* add message related to the last property change */ }}\n if (this._options.reactive !== false) {\n if (! wasDef)\n {{# def.addMsg }} accessPath, type: 'added',\n newValue: value });\n else if (old != value)\n {{# def.addMsg }} accessPath, type: 'changed',\n oldValue: old, newValue: value });\n\n {{ /* add message related to changes in (sub)properties inside removed and assigned value */ }}\n if (! wasDef || old != value)\n addTreeChangesMessages(messages, messagesHash,\n accessPath, old, value); /* defined in the function that synthesizes ModelPath setter */\n\n {{ /* post all stored messages */ }}\n {{# def.postMessages }}\n }\n};\n",
+ del: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n{{# def.include_defines }}\n{{# def.include_traverse_tree }}\n\nmethod = function del() {\n {{# def.initVars:'del' }}\n\n {{? it.parsedPath.length }}\n {{# def.traverseTree }}\n\n {{\n var currNode = it.parsedPath[count];\n var currProp = currNode.property; \n }}\n\n if (! treeDoesNotExist && m && m.hasOwnProperty && {{# def.wasDefined}}) {\n var old = m{{# def.currProp }};\n delete m{{# def.currProp }};\n {{# def.changeAccessPath }}\n var didDelete = true;\n }\n {{??}}\n if (typeof m != 'undefined') {\n var old = m;\n {{# def.modelAccessPrefix }} = undefined;\n var didDelete = true;\n }\n {{?}}\n\n if (didDelete && this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'deleted', oldValue: old });\n\n addTreeChangesMessages(messages, messagesHash,\n accessPath, old, undefined); /* defined in the function that synthesizes ModelPath setter */\n\n {{ /* post all stored messages */ }}\n {{# def.postMessages }}\n }\n};\n",
+ splice: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n{{# def.include_defines }}\n{{# def.include_create_tree }}\n{{# def.include_traverse_tree }}\n\nmethod = function splice(spliceIndex, spliceHowMany) { /* ,... - extra arguments to splice into array */\n {{# def.initVars:'splice' }}\n\n var argsLen = arguments.length;\n var addItems = argsLen > 2;\n\n if (addItems) {\n {{ /* only create model tree if items are inserted in array */ }}\n\n {{ /* if model is undefined it will be set to an empty array */ }} \n var value = [];\n {{# def.createTree:'splice' }}\n\n {{? nextNode }}\n {{\n var currNode = nextNode;\n var currProp = currNode.property;\n var emptyProp = '[]';\n }}\n\n {{# def.createTreeStep }}\n {{?}}\n\n } else if (spliceHowMany > 0) {\n {{ /* if items are not inserted, only traverse model tree if items are deleted from array */ }}\n {{? it.parsedPath.length }}\n {{# def.traverseTree }}\n\n {{\n var currNode = it.parsedPath[count];\n var currProp = currNode.property; \n }}\n\n {{ /* extra brace closes 'else' in def.traverseTreeStep */ }}\n {{# def.traverseTreeStep }} }\n {{?}}\n }\n\n {{ /* splice items */ }}\n if (addItems || (! treeDoesNotExist && m\n && m.length > spliceIndex ) ) {\n var oldLength = m.length = m.length || 0;\n\n arguments[0] = spliceIndex = normalizeSpliceIndex(spliceIndex, m.length);\n\n {{ /* clone added arguments to prevent same references in linked models */ }}\n if (addItems)\n for (var i = 2; i < argsLen; i++)\n arguments[i] = cloneTree(arguments[i]);\n\n {{ /* actual splice call */ }}\n var removed = Array.prototype.splice.apply(m, arguments);\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'splice',\n index: spliceIndex, removed: removed, addedCount: addItems ? argsLen - 2 : 0,\n newValue: m });\n\n if (removed && removed.length)\n removed.forEach(function(item, index) {\n var itemPath = accessPath + '[' + (spliceIndex + index) + ']';\n {{# def.addMsg }} itemPath, type: 'removed', oldValue: item });\n\n if (valueIsTree(item))\n addMessages(messages, messagesHash, itemPath, item, 'removed', 'oldValue');\n });\n\n if (addItems)\n for (var i = 2; i < argsLen; i++) {\n var item = arguments[i];\n var itemPath = accessPath + '[' + (spliceIndex + i - 2) + ']';\n {{# def.addMsg }} itemPath, type: 'added', newValue: item });\n\n if (valueIsTree(item))\n addMessages(messages, messagesHash, itemPath, item, 'added', 'newValue');\n }\n\n {{ /* post all stored messages */ }}\n {{# def.postMessages }}\n }\n }\n\n return removed || [];\n}\n"
+};
+var include_defines = "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n/**\n * Inserts initialization code\n */\n {{## def.initVars:method:\n var m = {{# def.modelAccessPrefix }};\n var messages = [], messagesHash = {};\n var accessPath = '';\n var treeDoesNotExist;\n /* hack to prevent sending finished events to allow for propagation of batches without splitting them */\n var inChangeTransaction = getTransactionFlag( {{= method }} );\n #}}\n\n/**\n * Inserts the beginning of function call to add message to list\n */\n{{## def.addMsg: addChangeMessage(messages, messagesHash, { path: #}}\n\n/**\n * Inserts current property/index for both normal and interpolated properties/indexes\n */\n{{## def.currProp:{{? currNode.interpolate }}[this._args[ {{= currNode.interpolate }} ]]{{??}}{{= currProp }}{{?}} #}}\n\n/**\n * Inserts condition to test whether normal/interpolated property/index exists\n */\n{{## def.wasDefined: m.hasOwnProperty(\n {{? currNode.interpolate }}\n this._args[ {{= currNode.interpolate }} ]\n {{??}}\n '{{= it.getPathNodeKey(currNode) }}'\n {{?}}\n) #}}\n\n\n/**\n * Inserts code to update access path for current property\n * Because of the possibility of interpolated properties, it can't be calculated in template, it can only be calculated during accessor call.\n */\n{{## def.changeAccessPath:\n accessPath += {{? currNode.interpolate }}\n {{? currNode.syntax == 'array' }}\n '[' + this._args[ {{= currNode.interpolate }} ] + ']';\n {{??}}\n '.' + this._args[ {{= currNode.interpolate }} ];\n {{?}}\n {{??}}\n '{{= currProp }}';\n {{?}}\n#}}\n\n\n/**\n * Inserts code to post stored messages\n */\n{{## def.postMessages:\n if (messages.length) {\n {{# def.modelPostBatchCode }}('datachanges', {\n changes: messages,\n transaction: inChangeTransaction\n });\n\n messages.forEach(function(msg) {\n {{# def.modelPostMessageCode }}(msg.path, msg);\n }, this);\n }\n#}}\n"
+ , include_create_tree = "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n/**\n * Inserts code to create model tree as neccessary for `set` and `splice` accessors and to add messages to send list if the tree changes.\n */\n{{## def.createTree:method:\n var wasDef = true;\n var old = m;\n\n {{ var emptyProp = it.parsedPath[0] && it.parsedPath[0].empty; }}\n {{? emptyProp }}\n {{ /* create top level model if it was not previously defined */ }}\n if (! m) {\n m = {{# def.modelAccessPrefix }} = {{= emptyProp }};\n wasDef = false;\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} '', type: 'added',\n newValue: m });\n }\n }\n {{??}}\n {{? method == 'splice' }}\n if (! m) {\n {{?}}\n m = {{# def.modelAccessPrefix }} = cloneTree(value);\n wasDef = typeof old != 'undefined';\n {{? method == 'splice' }}\n }\n {{?}} \n {{?}}\n\n\n {{ /* create model tree if it doesn't exist */ }}\n {{ var modelDataProperty = '';\n var nextNode = it.parsedPath[0];\n var count = it.parsedPath.length - 1;\n\n for (var i = 0; i < count; i++) {\n var currNode = nextNode;\n var currProp = currNode.property;\n nextNode = it.parsedPath[i + 1];\n var emptyProp = nextNode && nextNode.empty;\n }}\n\n {{# def.createTreeStep }}\n\n {{ } /* for loop */ }}\n#}}\n\n\n/**\n * Inserts code to create one step in the model tree\n */\n{{## def.createTreeStep:\n {{# def.changeAccessPath }}\n\n if (! {{# def.wasDefined }}) { \n {{ /* property does not exist */ }}\n m = m{{# def.currProp }} = {{= emptyProp }};\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'added', \n newValue: m });\n }\n\n } else if (typeof m{{# def.currProp }} != 'object') {\n {{ /* property is not object */ }}\n var old = m{{# def.currProp }};\n m = m{{# def.currProp }} = {{= emptyProp }};\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'changed', \n oldValue: old, newValue: m });\n }\n\n } else {\n {{ /* property exists, just traverse down the model tree */ }}\n m = m{{# def.currProp }};\n }\n#}}\n"
+ , include_traverse_tree = "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n/**\n * Inserts code to traverse model tree for `delete` and `splice` accessors.\n */\n{{## def.traverseTree:\n {{ \n var count = it.parsedPath.length-1;\n\n for (var i = 0; i < count; i++) { \n var currNode = it.parsedPath[i];\n var currProp = currNode.property;\n }}\n {{# def.traverseTreeStep }}\n\n {{ } /* for loop */\n\n var i = count;\n while (i--) { /* closing braces for else's above */\n }}\n }\n {{ } /* while loop */ }}\n#}}\n\n\n/**\n * Inserts code to traverse one step in the model tree\n */\n{{## def.traverseTreeStep:\n if (! (m && m.hasOwnProperty && {{# def.wasDefined}} ) )\n treeDoesNotExist = true;\n else {\n m = m{{# def.currProp }};\n {{# def.changeAccessPath }}\n {{ /* brace from else is not closed on purpose - all braces are closed in while loop */ }}\n#}}\n";
-function Messenger$once(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1 });
-}
-
-function Messenger$onceSync(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1, sync: true });
-}
+var dotDef = {
+ include_defines: include_defines,
+ include_create_tree: include_create_tree,
+ include_traverse_tree: include_traverse_tree,
+ getPathNodeKey: pathUtils.getPathNodeKey,
+ modelAccessPrefix: 'this._model._data',
+ modelPostMessageCode: 'this._model._internalMessenger.postMessage',
+ modelPostBatchCode: 'this._model.postMessageSync',
+ internalMessenger: 'this._model._internalMessenger'
+};
+var modelDotDef = _(dotDef).clone().extend({
+ modelAccessPrefix: 'this._data',
+ modelPostMessageCode: 'this._internalMessenger.postMessage',
+ modelPostBatchCode: 'this.postMessageSync',
+ internalMessenger: 'this._internalMessenger'
+})._();
-function Messenger$onSync(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: true });
-}
+var dotSettings = _.clone(doT.templateSettings);
+dotSettings.strip = false;
-function Messenger$onAsync(messages, subscriber) {
- return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: false });
-}
+var synthesizers = _.mapKeys(templates, function(tmpl) {
+ return doT.template(tmpl, dotSettings, dotDef);
+});
-function _Messenger_onWithOptions(messages, subscriber, options) {
- check(messages, Match.OneOf(String, [String], RegExp));
- check(subscriber, Match.OneOf(Function, {
- subscriber: Function,
- context: Match.Any,
- options: Match.Optional(Object),
- }));
+var modelSynthesizers = _.mapToObject(['set', 'del', 'splice'], function(methodName) {
+ return doT.template(templates[methodName], dotSettings, modelDotDef);
+});
- if (typeof subscriber == 'function') {
- subscriber = {
- subscriber: subscriber,
- context: this._hostObject,
- };
- }
- if (options) {
- subscriber.options = subscriber.options || {};
- _.extend(subscriber.options, options);
- }
+/**
+ * Function that synthesizes accessor methods.
+ * Function is memoized so accessors are cached (up to 1000).
+ *
+ * @param {String} path Model/ModelPath access path
+ * @param {Array} parsedPath array of path nodes
+ * @return {Object[Function]}
+ */
+var synthesizePathMethods = _.memoize(_synthesizePathMethods, undefined, 1000);
- return _Messenger_on.call(this, messages, subscriber);
+function _synthesizePathMethods(path, parsedPath) {
+ var methods = _.mapKeys(synthesizers, function(synthszr) {
+ return _synthesize(synthszr, path, parsedPath);
+ });
+ return methods;
}
-function _Messenger_on(messages, subscriber) {
- _.defineProperty(subscriber, '__messages', messages);
- return _eachMessage.call(this, '_registerSubscriber', messages, subscriber);
-}
+var normalizeSpliceIndex = modelUtils.normalizeSpliceIndex; // used in splice.dot.js
-function _eachMessage(methodName, messages, subscriber) {
- if (typeof messages == 'string')
- messages = messages.split(messagesSplitRegExp);
+function _synthesize(synthesizer, path, parsedPath) {
+ var method
+ , methodCode = synthesizer({
+ parsedPath: parsedPath,
+ getPathNodeKey: pathUtils.getPathNodeKey
+ });
- var subscribersHash = this._chooseSubscribersHash(messages);
+ try {
+ eval(methodCode);
+ } catch (e) {
+ throw ModelError('ModelPath method compilation error; path: ' + path + ', code: ' + methodCode);
+ }
- if (messages instanceof RegExp)
- return this[methodName](subscribersHash, messages, subscriber);
+ return method;
- else {
- var changed = false;
- messages.forEach(function(message) {
- var subscriptionChanged = this[methodName](subscribersHash, message, subscriber);
- changed = changed || subscriptionChanged;
- }, this);
+ // functions used by methods `set`, `delete` and `splice` (synthesized by template)
+ function addChangeMessage(messages, messagesHash, msg) {
+ messages.push(msg);
+ messagesHash[msg.path] = msg;
+ }
- return changed;
+ function addTreeChangesMessages(messages, messagesHash, rootPath, oldValue, newValue) {
+ var oldIsTree = valueIsTree(oldValue)
+ , newIsTree = valueIsTree(newValue);
+
+ if (newIsTree)
+ addMessages(messages, messagesHash, rootPath, newValue, 'added', 'newValue');
+
+ if (oldIsTree)
+ addMessages(messages, messagesHash, rootPath, oldValue, 'removed', 'oldValue');
}
-}
+ function addMessages(messages, messagesHash, rootPath, obj, msgType, valueProp) {
+ _addMessages(rootPath, obj);
-/**
- * "Private" Messenger instance method
- * It is called by [on](#Messenger$on) to register subscriber for one message type.
- * Returns `true` if this subscriber is not yet registered for this type of message.
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added.
- *
- * @private
- * @param {Object} subscribersHash The map of subscribers determined by [on](#Messenger$on) based on Message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
- * @param {String} message Message type
- * @param {Function|Object} subscriber Subscriber function to be added or object with properties `subscriber` (function) and `context` (value of "this" when subscriber is called)
- * @return {Boolean}
- */
-function _registerSubscriber(subscribersHash, message, subscriber) {
- if (! (subscribersHash[message] && subscribersHash[message].length)) {
- subscribersHash[message] = [];
- if (message instanceof RegExp)
- subscribersHash[message].pattern = message;
- if (this._messageSource)
- this._messageSource.onSubscriberAdded(message);
- var noSubscribers = true;
+
+ function _addMessages(rootPath, obj) {
+ if (Array.isArray(obj)) {
+ var pathSyntax = rootPath + '[$$]';
+ obj.forEach(function(value, index) {
+ addMessage(value, index, pathSyntax);
+ });
+ } else {
+ var pathSyntax = rootPath + '.$$';
+ _.eachKey(obj, function(value, key) {
+ addMessage(value, key, pathSyntax);
+ });
+ }
+ }
+
+ function addMessage(value, key, pathSyntax) {
+ var path = pathSyntax.replace('$$', key)
+ , existingMsg = messagesHash[path];
+
+ if (existingMsg) {
+ if (existingMsg.type == msgType)
+ logger.error('setter error: same message type posted on the same path');
+ else {
+ existingMsg.type = 'changed';
+ existingMsg[valueProp] = value;
+ }
+ } else {
+ var msg = { path: path, type: msgType };
+ msg[valueProp] = value;
+ addChangeMessage(messages, messagesHash, msg);
+ }
+
+ if (valueIsTree(value))
+ _addMessages(path, value);
+ }
}
- var msgSubscribers = subscribersHash[message];
- var notYetRegistered = noSubscribers || _indexOfSubscriber.call(this, msgSubscribers, subscriber) == -1;
+ function cloneTree(value) {
+ return valueIsNormalObject(value)
+ ? _.deepClone(value)
+ : value;
+ }
- if (notYetRegistered)
- msgSubscribers.push(subscriber);
+ function protectValue(value) {
+ return ! valueIsNormalObject(value)
+ ? value
+ : Array.isArray(value)
+ ? value.slice()
+ : Object.create(value);
+ }
- return notYetRegistered;
-}
+ function valueIsTree(value) {
+ return valueIsNormalObject(value)
+ && Object.keys(value).length;
+ }
+ function valueIsNormalObject(value) {
+ return value != null
+ && typeof value == "object"
+ && ! (value instanceof Date)
+ && ! (value instanceof RegExp);
+ }
-/**
- * Finds subscriber index in the list
- *
- * @param {Array[Function|Object]} list list of subscribers
- * @param {Function|Object} subscriber subscriber function or object with properties `subscriber` (function) and `context` ("this" object)
- */
-function _indexOfSubscriber(list, subscriber) {
- var self = this;
- return _.findIndex(list, function(subscr){
- return subscriber.subscriber == subscr.subscriber
- && subscriber.context == subscr.context
- });
+ function addBatchIdsToMessage(msg, batchId, msgId) {
+ _.defineProperties(msg, {
+ __batch_id: batchId,
+ __msg_id: msgId
+ });
+ }
}
/**
- * Messenger instance method.
- * Subscribes to multiple messages passed as map together with subscribers.
- * Usage:
- * ```
- * myComp.events.onMessages({
- * 'mousedown': onMouseDown,
- * 'mouseup': onMouseUp
- * });
- * function onMouseDown(eventType, event) {}
- * function onMouseUp(eventType, event) {}
- * ```
- * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was added.
- * It is NOT possible to add pattern subscriber using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.
+ * Exports `synthesize` function with the following:
*
- * @param {Object[Function]} messageSubscribers Map of message subscribers to be added
- * @return {Object[Boolean]}
+ * - .modelMethods.set - `set` method for Model
+ * - .modelMethods.del - `del` method for Model
+ * - .modelMethods.splice - `splice` method for Model
*/
-function onMessages(messageSubscribers) {
- check(messageSubscribers, Match.ObjectHash(Match.OneOf(Function, { subscriber: Function, context: Match.Any })));
+module.exports = synthesizePathMethods;
- var notYetRegisteredMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {
- return this.on(messages, subscriber);
- }, this);
+var modelMethods = _.mapKeys(modelSynthesizers, function(synthesizer) {
+ return _synthesize(synthesizer, '', []);
+});
- return notYetRegisteredMap;
-}
+synthesizePathMethods.modelMethods = modelMethods;
+},{"../../util/logger":118,"../change_data":107,"../model_utils":112,"../path_utils":114,"dot":121,"fs":96,"mol-proto":122}],116:[function(require,module,exports){
+'use strict';
/**
- * Messenger instance method.
- * Removes a subscriber for message(s). Removes all subscribers for the message if subscriber isn't passed.
- * This method returns `true` if the subscriber was registered. No error or warning is thrown or logged if you remove subscriber that was not registered.
- * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `off` when they proxy it.
- * Usage:
- * ```
- * // unsubscribes onMouseUpDown from two DOM events.
- * myComp.events.off('mousedown mouseup', onMouseUpDown);
- * ```
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.
+ * `milo.utils.check`
*
- * @param {String|Array[String]|RegExp} messages Message types that a subscriber should be removed for.
- * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.
- * If an array of strings is passed, each string is a message type to remove a subscriber for.
- * If a RegExp is passed, the pattern subscriber will be removed.
- * RegExp subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.
- * @param {Function} subscriber Message subscriber - Optional function that will be removed from the list of subscribers for the message(s). If subscriber is not supplied, all subscribers will be removed from this message(s).
- * @return {Boolean}
- */
-function Messenger$off(messages, subscriber) {
- check(messages, Match.OneOf(String, [String], RegExp));
- check(subscriber, Match.Optional(Match.OneOf(Function, {
- subscriber: Function,
- context: Match.Any,
- options: Match.Optional(Object),
- // __messages: Match.Optional(Match.OneOf(String, [String], RegExp))
- })));
-
- return _Messenger_off.call(this, messages, subscriber);
-}
-
-
-function _Messenger_off(messages, subscriber) {
- return _eachMessage.call(this, '_removeSubscriber', messages, subscriber);
-}
+ * Check is a module for parameters checking extracted from [Meteor](http://docs.meteor.com/) framework.
+ *
+ * It allows to both document and to check parameter types in your function
+ * making code both readable and stable.
+ *
+ *
+ * ### Usage
+ *```
+ * var check = milo.check
+ * , Match = check.Match;
+ *
+ * function My(name, obj, cb) {
+ * // if any of checks fail an error will be thrown
+ * check(name, String);
+ * check(obj, Match.ObjectIncluding({ options: Object }));
+ * check(cb, Function);
+ *
+ * // ... your code
+ * }
+ *```
+ * See [Meteor docs](http://docs.meteor.com/#match) to see how it works
+ *
+ *
+ * ### Patterns
+ *
+ * All patterns and functions described in Meteor docs work.
+ *
+ * Unlike in Meteor, Object pattern matches instance of any class,
+ * not only plain object.
+ *
+ * In addition to patterns described in Meteor docs the following patterns are implemented
+ *
+ * * Match.__ObjectHash__(_pattern_)
+ *
+ * Matches an object where all properties match a given pattern
+ *
+ * * Match.__Subclass__(_constructor_ [, _matchThisClassToo_])
+ *
+ * Matches a class that is a subclass of a given class. If the second parameter
+ * is true, it will also match the class itself.
+ *
+ * Without this pattern to check if _MySubclass_ is a subclass of _MyClass_
+ * you would have to use
+ *
+ * check(MySubclass, Match.Where(function() {
+ * return MySubclass.prototype instanceof MyClass;
+ * });
+ *
+ *
+ * Things we explicitly do NOT support:
+ * - heterogenous arrays
+**/
+var _ = require('mol-proto')
+ , config = require('../config');
-/**
- * "Private" Messenger instance method
- * It is called by [off](#Messenger$off) to remove subscriber for one message type.
- * Returns `true` if this subscriber was registered for this type of message.
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.
- *
- * @private
- * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
- * @param {String} message Message type
- * @param {Function} subscriber Subscriber function to be removed
- * @return {Boolean}
- */
-function _removeSubscriber(subscribersHash, message, subscriber) {
- var msgSubscribers = subscribersHash[message];
- if (! msgSubscribers || ! msgSubscribers.length)
- return false; // nothing removed
+var check = function (value, pattern) {
+ if (config.check === false)
+ return;
- if (subscriber) {
- if (typeof subscriber == 'function')
- subscriber = { subscriber: subscriber, context: this._hostObject };
+ // Record that check got called, if somebody cared.
+ try {
+ checkSubtree(value, pattern);
+ } catch (err) {
+ if ((err instanceof Match.Error) && err.path)
+ err.message += " in field " + err.path;
+ throw err;
+ }
+};
- var subscriberIndex = _indexOfSubscriber.call(this, msgSubscribers, subscriber);
- if (subscriberIndex == -1)
- return false; // nothing removed
- msgSubscribers.splice(subscriberIndex, 1);
- if (! msgSubscribers.length)
- this._removeAllSubscribers(subscribersHash, message);
+module.exports = check;
- } else
- this._removeAllSubscribers(subscribersHash, message);
+var Match = check.Match = {
+ Optional: function (pattern) {
+ return new Optional(pattern);
+ },
+ OneOf: function (/* arguments */) {
+ return new OneOf(arguments);
+ },
+ Any: ['__any__'],
+ Where: function (condition) {
+ return new Where(condition);
+ },
+ ObjectIncluding: function (pattern) {
+ return new ObjectIncluding(pattern);
+ },
+ // Matches only signed 32-bit integers
+ Integer: ['__integer__'],
- return true; // subscriber(s) removed
-}
+ // Matches string that is a valid identifier, will not allow javascript reserved words
+ IdentifierString: /^[a-z_$][0-9a-z_$]*$/i,
+ // Matches hash (object) with values matching pattern
+ ObjectHash: function(pattern) {
+ return new ObjectHash(pattern);
+ },
-/**
- * "Private" Messenger instance method
- * It is called by [_removeSubscriber](#_removeSubscriber) to remove all subscribers for one message type.
- * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified that all message subscribers were removed so it can unsubscribe from the source.
- *
- * @private
- * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`
- * @param {String} message Message type
- */
-function _removeAllSubscribers(subscribersHash, message) {
- delete subscribersHash[message];
- if (this._messageSource && typeof message == 'string')
- this._messageSource.onSubscriberRemoved(message);
-}
+ Subclass: function(Superclass, matchSuperclassToo) {
+ return new Subclass(Superclass, matchSuperclassToo);
+ },
+ // XXX matchers should know how to describe themselves for errors
+ Error: TypeError,
-/**
- * Messenger instance method.
- * Unsubscribes from multiple messages passed as map together with subscribers.
- * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was removed.
- * If a subscriber for one of the messages is not supplied, all subscribers for this message will be removed.
- * Usage:
- * ```
- * myComp.events.offMessages({
- * 'mousedown': onMouseDown,
- * 'mouseup': onMouseUp,
- * 'click': undefined // all subscribers to this message will be removed
- * });
- * ```
- * It is NOT possible to remove pattern subscriber(s) using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.
- *
- * @param {Object[Function]} messageSubscribers Map of message subscribers to be removed
- * @return {Object[Boolean]}
- */
-function offMessages(messageSubscribers) {
- check(messageSubscribers, Match.ObjectHash(Match.Optional(Match.OneOf(Function, { subscriber: Function, context: Match.Any }))));
+ // Meteor.makeErrorType("Match.Error", function (msg) {
+ // this.message = "Match error: " + msg;
+ // The path of the value that failed to match. Initially empty, this gets
+ // populated by catching and rethrowing the exception as it goes back up the
+ // stack.
+ // E.g.: "vals[3].entity.created"
+ // this.path = "";
+ // If this gets sent over DDP, don't give full internal details but at least
+ // provide something better than 500 Internal server error.
+ // this.sanitizedError = new Meteor.Error(400, "Match failed");
+ // }),
- var subscriberRemovedMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {
- return this.off(messages, subscriber);
- }, this);
+ // Tests to see if value matches pattern. Unlike check, it merely returns true
+ // or false (unless an error other than Match.Error was thrown).
+ test: function (value, pattern) {
+ try {
+ checkSubtree(value, pattern);
+ return true;
+ } catch (e) {
+ if (e instanceof Match.Error)
+ return false;
+ // Rethrow other errors.
+ throw e;
+ }
+ }
+};
- return subscriberRemovedMap;
-}
+function Optional(pattern) {
+ this.pattern = pattern;
+};
+function OneOf(choices) {
+ if (choices.length == 0)
+ throw new Error("Must provide at least one choice to Match.OneOf");
+ this.choices = choices;
+};
-/**
- * Unsubscribes all subscribers
- */
-function Messenger$offAll() {
- _offAllSubscribers.call(this, this._patternMessageSubscribers);
- _offAllSubscribers.call(this, this._messageSubscribers);
-}
+function Where(condition) {
+ this.condition = condition;
+};
+function ObjectIncluding(pattern) {
+ this.pattern = pattern;
+};
-function _offAllSubscribers(subscribersHash) {
- _.eachKey(subscribersHash, function(subscribers, message) {
- this._removeAllSubscribers(subscribersHash, message);
- }, this);
-}
+function ObjectHash(pattern) {
+ this.pattern = pattern;
+};
+function Subclass(Superclass, matchSuperclassToo) {
+ this.Superclass = Superclass;
+ this.matchSuperclass = matchSuperclassToo;
+};
-// TODO - send event to messageSource
+var typeofChecks = [
+ [String, "string"],
+ [Number, "number"],
+ [Boolean, "boolean"],
+ [Function, "function"],
+ // While we don't allow undefined in JSON, this is good for optional
+ // arguments with OneOf.
+ [undefined, "undefined"]
+];
+function checkSubtree(value, pattern) {
+ // Match anything!
+ if (pattern === Match.Any)
+ return;
-/**
- * Messenger instance method.
- * Dispatches the message calling all subscribers registered for this message and, if the message is a string, calling all pattern subscribers when message matches the pattern.
- * Each subscriber is passed the same parameters that are passed to theis method.
- * The context of the subscriber envocation is set to the host object (`this._hostObject`) that was passed to the messenger constructor.
- * Subscribers are called in the next tick ("asynchronously") apart from those that were subscribed with `onSync` (or that have `options.sync == true`).
- *
- * @param {String|RegExp} message message to be dispatched
- * If the message is a string, the subscribers registered with exactly this message will be called and also pattern subscribers registered with the pattern that matches the dispatched message.
- * If the message is RegExp, only the subscribers registered with exactly this pattern will be called.
- * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
- * @param {Function} callback optional callback to pass to subscriber
- * @param {Boolean} _synchronous if true passed, subscribers will be envoked synchronously apart from those that have `options.sync == false`. This parameter should not be used, instead postMessageSync should be used.
- */
-function postMessage(message, data, callback, _synchronous) {
- check(message, Match.OneOf(String, RegExp));
- check(callback, Match.Optional(Function));
-
- var subscribersHash = this._chooseSubscribersHash(message);
- var msgSubscribers = subscribersHash[message];
-
- this._callSubscribers(message, data, callback, msgSubscribers, _synchronous);
+ // Basic atomic types.
+ // Do not match boxed objects (e.g. String, Boolean)
+ for (var i = 0; i < typeofChecks.length; ++i) {
+ if (pattern === typeofChecks[i][0]) {
+ if (typeof value === typeofChecks[i][1])
+ return;
+ throw new Match.Error("Expected " + typeofChecks[i][1] + ", got " +
+ typeof value);
+ }
+ }
+ if (pattern === null) {
+ if (value === null)
+ return;
+ throw new Match.Error("Expected null, got " + JSON.stringify(value));
+ }
- if (typeof message == 'string')
- this._callPatternSubscribers(message, data, callback, msgSubscribers, _synchronous);
-}
+ // Match.Integer is special type encoded with array
+ if (pattern === Match.Integer) {
+ // There is no consistent and reliable way to check if variable is a 64-bit
+ // integer. One of the popular solutions is to get reminder of division by 1
+ // but this method fails on really large floats with big precision.
+ // E.g.: 1.348192308491824e+23 % 1 === 0 in V8
+ // Bitwise operators work consistantly but always cast variable to 32-bit
+ // signed integer according to JavaScript specs.
+ if (typeof value === 'number' && (value | 0) === value)
+ return
+ throw new Match.Error('Expected Integer, got '
+ + (value instanceof Object ? JSON.stringify(value) : value));
+ }
+ if (pattern === Match.IdentifierString) {
+ if (typeof value === 'string' && Match.IdentifierString.test(value)
+ && _jsKeywords.indexOf(key) == -1)
+ return;
+ throw new Match.Error('Expected identifier string, got '
+ + (value instanceof Object ? JSON.stringify(value) : value));
+ }
-/**
- * Same as postMessage apart from envoking subscribers synchronously, apart from those subscribed with `onAsync` (or with `options.sync == false`).
- *
- * @param {String|RegExp} message
- * @param {Any} data
- * @param {Function} callback
- */
-function postMessageSync(message, data, callback) {
- this.postMessage(message, data, callback, true);
-}
+ // "Object" is shorthand for Match.ObjectIncluding({});
+ if (pattern === Object)
+ pattern = Match.ObjectIncluding({});
+ // Array (checked AFTER Any, which is implemented as an Array).
+ if (pattern instanceof Array) {
+ if (pattern.length !== 1)
+ throw Error("Bad pattern: arrays must have one type element" +
+ JSON.stringify(pattern));
+ if (!Array.isArray(value)) {
+ throw new Match.Error("Expected array, got " + JSON.stringify(value));
+ }
-/**
- * "Private" Messenger instance method
- * Envokes pattern subscribers with the pattern that matches the message.
- * The method is called by [postMessage](#postMessage) - see more information there.
- *
- * @private
- * @param {String} message message to be dispatched. Pattern subscribers registered with the pattern that matches the dispatched message will be called.
- * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
- * @param {Function} callback optional callback to pass to subscriber
- * @param {Array[Function|Object]} calledMsgSubscribers array of subscribers already called, they won't be called again if they are among pattern subscribers.
- */
-function _callPatternSubscribers(message, data, callback, calledMsgSubscribers, _synchronous) {
- _.eachKey(this._patternMessageSubscribers,
- function(patternSubscribers) {
- var pattern = patternSubscribers.pattern;
- if (pattern.test(message)) {
- if (calledMsgSubscribers) {
- var patternSubscribers = patternSubscribers.filter(function(subscriber) {
- var index = _indexOfSubscriber.call(this, calledMsgSubscribers, subscriber);
- return index == -1;
- });
+ value.forEach(function (valueElement, index) {
+ try {
+ checkSubtree(valueElement, pattern[0]);
+ } catch (err) {
+ if (err instanceof Match.Error) {
+ err.path = _prependPath(index, err.path);
}
- this._callSubscribers(message, data, callback, patternSubscribers, _synchronous);
+ throw err;
}
- }
- , this);
-}
-
-
-/**
- * "Private" Messenger instance method
- * Envokes subscribers from the passed list.
- * The method is called by [postMessage](#postMessage) and [_callPatternSubscribers](#_callPatternSubscribers).
- *
- * @private
- * @param {String} message message to be dispatched, passed to subscribers as the first parameter.
- * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.
- * @param {Array[Function|Object]} msgSubscribers the array of message subscribers to be called. Each subscriber is called with the host object (see Messenger constructor) as the context.
- * @param {Function} callback optional callback to pass to subscriber
- */
-function _callSubscribers(message, data, callback, msgSubscribers, _synchronous) {
- if (msgSubscribers && msgSubscribers.length) {
- // cloning is necessary as some of the subscribers
- // can be unsubscribed during the dispatch
- // so this array would change in the process
- msgSubscribers = msgSubscribers.slice();
+ });
+ return;
+ }
- msgSubscribers.forEach(function(subscriber) {
- this._callSubscriber(subscriber, message, data, callback, _synchronous);
- }, this);
+ // Arbitrary validation checks. The condition can return false or throw a
+ // Match.Error (ie, it can internally use check()) to fail.
+ if (pattern instanceof Where) {
+ if (pattern.condition(value))
+ return;
+ // XXX this error is terrible
+ throw new Match.Error("Failed Match.Where validation");
}
-}
-function _callSubscriber(subscriber, message, data, callback, _synchronous) {
- var syncSubscriber = subscriber.options && subscriber.options.sync
- , synchro = (_synchronous && syncSubscriber !== false)
- || syncSubscriber;
+ if (pattern instanceof Optional)
+ pattern = Match.OneOf(undefined, pattern.pattern);
- var dispatchTimes = subscriber.options && subscriber.options.dispatchTimes;
- if (dispatchTimes) {
- if (dispatchTimes <= 1) {
- var messages = subscriber.__messages;
- this.off(messages, subscriber);
- } else if (dispatchTimes > 1)
- subscriber.options.dispatchTimes--;
+ if (pattern instanceof OneOf) {
+ for (var i = 0; i < pattern.choices.length; ++i) {
+ try {
+ checkSubtree(value, pattern.choices[i]);
+ // No error? Yay, return.
+ return;
+ } catch (err) {
+ // Other errors should be thrown. Match errors just mean try another
+ // choice.
+ if (!(err instanceof Match.Error))
+ throw err;
+ }
+ }
+ // XXX this error is terrible
+ throw new Match.Error("Failed Match.OneOf or Match.Optional validation");
}
- if (synchro)
- subscriber.subscriber.call(subscriber.context, message, data, callback);
- else
- _.deferMethod(subscriber.subscriber, 'call', subscriber.context, message, data, callback);
-}
-
+ // A function that isn't something we special-case is assumed to be a
+ // constructor.
+ if (pattern instanceof Function) {
+ if (value instanceof pattern)
+ return;
+ // XXX what if .name isn't defined
+ throw new Match.Error("Expected " + pattern.constructor.name);
+ }
-/**
- * Messenger instance method.
- * Returns the array of subscribers that would be called if the message were dispatched.
- * If `includePatternSubscribers === false`, pattern subscribers with matching patters will not be included (by default they are included).
- * If there are no subscribers to the message, `undefined` will be returned, not an empty array, so it is safe to use the result in boolean tests.
- *
- * @param {String|RegExp} message Message to get subscribers for.
- * If the message is RegExp, only pattern subscribers registered with exactly this pattern will be returned.
- * If the message is String, subscribers registered with the string messages and pattern subscribers registered with matching pattern will be returned (unless the second parameter is false).
- * @param {Boolean} includePatternSubscribers Optional false to prevent inclusion of patter subscribers, by default they are included.
- * @return {Array|undefined}
- */
-function getSubscribers(message, includePatternSubscribers) {
- check(message, Match.OneOf(String, RegExp));
+ var unknownKeysAllowed = false;
+ if (pattern instanceof ObjectIncluding) {
+ unknownKeysAllowed = true;
+ pattern = pattern.pattern;
+ }
- var subscribersHash = this._chooseSubscribersHash(message);
- var msgSubscribers = subscribersHash[message]
- ? [].concat(subscribersHash[message])
- : [];
+ if (pattern instanceof ObjectHash) {
+ var keyPattern = pattern.pattern;
+ var emptyHash = true;
+ for (var key in value) {
+ emptyHash = false;
+ check(value[key], keyPattern);
+ }
+ if (emptyHash)
+ throw new Match.Error("Expected " + pattern.constructor.name);
+ return;
+ }
- // pattern subscribers are incuded by default
- if (includePatternSubscribers !== false && typeof message == 'string') {
- _.eachKey(this._patternMessageSubscribers,
- function(patternSubscribers) {
- var pattern = patternSubscribers.pattern;
- if (patternSubscribers && patternSubscribers.length
- && pattern.test(message))
- _.appendArray(msgSubscribers, patternSubscribers);
- }
- );
+ if (pattern instanceof Subclass) {
+ var Superclass = pattern.Superclass;
+ if (pattern.matchSuperclass && value == Superclass)
+ return;
+ if (! (value.prototype instanceof Superclass))
+ throw new Match.Error("Expected " + pattern.constructor.name + " of " + Superclass.name);
+ return;
}
- // return undefined if there are no subscribers
- return msgSubscribers.length
- ? msgSubscribers
- : undefined;
-}
+ if (typeof pattern !== "object")
+ throw Error("Bad pattern: unknown pattern type");
+ // An object, with required and optional keys. Note that this does NOT do
+ // structural matches against objects of special types that happen to match
+ // the pattern: this really needs to be a plain old {Object}!
+ if (typeof value !== 'object')
+ throw new Match.Error("Expected object, got " + typeof value);
+ if (value === null)
+ throw new Match.Error("Expected object, got null");
-/**
- * "Private" Messenger instance method
- * Returns the map of subscribers for a given message type.
- *
- * @private
- * @param {String|RegExp} message Message to choose the map of subscribers for
- * @return {Object[Function]}
- */
-function _chooseSubscribersHash(message) {
- return message instanceof RegExp
- ? this._patternMessageSubscribers
- : this._messageSubscribers;
-}
+ var requiredPatterns = {};
+ var optionalPatterns = {};
+ _.eachKey(pattern, function(subPattern, key) {
+ if (pattern[key] instanceof Optional)
+ optionalPatterns[key] = pattern[key].pattern;
+ else
+ requiredPatterns[key] = pattern[key];
+ }, this, true);
-/**
- * Messenger instance method
- * Sets [MessageSource](./m_source.js.html) for the messenger also setting the reference to the messenger in the MessageSource.
- * MessageSource can be passed to message constructor; this method allows to set it at a later time. For example, the subclasses of [ComponentFacet](../components/c_facet.js.html) use this method to set different MessageSource'es in the messenger that is created by ComponentFacet.
- * Currently the method is implemented in such way that it can be called only once - MessageSource cannot be changed after this method is called.
- *
- * @param {MessageSource} messageSource an instance of MessageSource class to attach to this messenger (and to have this messenger attached to it too)
- */
-function _setMessageSource(messageSource) {
- check(messageSource, MessageSource);
+ _.eachKey(value, function(subValue, key) {
+ var subValue = value[key];
+ try {
+ if (requiredPatterns.hasOwnProperty(key)) {
+ checkSubtree(subValue, requiredPatterns[key]);
+ delete requiredPatterns[key];
+ } else if (optionalPatterns.hasOwnProperty(key)) {
+ checkSubtree(subValue, optionalPatterns[key]);
+ } else {
+ if (!unknownKeysAllowed)
+ throw new Match.Error("Unknown key");
+ }
+ } catch (err) {
+ if (err instanceof Match.Error)
+ err.path = _prependPath(key, err.path);
+ throw err;
+ }
+ }, this, true);
- _.defineProperty(this, '_messageSource', messageSource);
- messageSource.messenger = this;
-}
+ _.eachKey(requiredPatterns, function(value, key) {
+ throw new Match.Error("Missing key '" + key + "'");
+ }, this, true);
+};
+
+
+var _jsKeywords = ["do", "if", "in", "for", "let", "new", "try", "var", "case",
+ "else", "enum", "eval", "false", "null", "this", "true", "void", "with",
+ "break", "catch", "class", "const", "super", "throw", "while", "yield",
+ "delete", "export", "import", "public", "return", "static", "switch",
+ "typeof", "default", "extends", "finally", "package", "private", "continue",
+ "debugger", "function", "arguments", "interface", "protected", "implements",
+ "instanceof"];
+
+// Assumes the base of path is already escaped properly
+// returns key + base
+function _prependPath(key, base) {
+ if ((typeof key) === "number" || key.match(/^[0-9]+$/))
+ key = "[" + key + "]";
+ else if (!key.match(Match.IdentifierString) || _jsKeywords.indexOf(key) != -1)
+ key = JSON.stringify([key]);
+
+ if (base && base[0] !== "[")
+ return key + '.' + base;
+ return key + base;
+};
+},{"../config":99,"mol-proto":122}],117:[function(require,module,exports){
+'use strict';
/**
- * Messenger instance method
- * Returns messenger MessageSource
- *
- * @return {MessageSource}
+ * `milo.util`
*/
-function getMessageSource() {
- return this._messageSource
-}
+var util = {
+ logger: require('./logger'),
+ check: require('./check'),
+ doT: require('dot')
+};
+
+module.exports = util;
-},{"../abstract/mixin":116,"../util/check":135,"./m_source":122,"mol-proto":141}],120:[function(require,module,exports){
-arguments[4][68][0].apply(exports,arguments)
-},{"../util/logger":137,"mol-proto":141}],121:[function(require,module,exports){
-arguments[4][69][0].apply(exports,arguments)
-},{"./m_api":120,"mol-proto":141}],122:[function(require,module,exports){
+},{"./check":116,"./logger":118,"dot":121}],118:[function(require,module,exports){
'use strict';
-var Mixin = require('../abstract/mixin')
- , MessengerAPI = require('./m_api')
- , logger = require('../util/logger')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match;
+//
+// milo.utils.logger
+// -----------
+// Application logger that has error, warn, info and debug
+// methods, that can be suppressed by setting log level.
-/**
- * `milo.classes.MessageSource`
- * An abstract class (subclass of [Mixin](../abstract/mixin.js.html)) for connecting [Messenger](./index.js.html) to external sources of messages (like DOM events) and defining higher level messages.
- * An instance of MessageSource can either be passed to Messenger constructor or later using `_setMessageSource` method of Messenger. Once set, MessageSource of Messenger cannot be changed.
- */
-var MessageSource = _.createSubclass(Mixin, 'MessageSource', true);
+// Properties:
-module.exports = MessageSource;
+// - level
+// - 0 - error
+// - 1 - warn
+// - 2 - info
+// - 3 - debug (default)
-/**
- * ####MessageSource instance methods####
- *
- * - [init](#init) - initializes messageSource - called by Mixin superclass
- * - [setMessenger](#setMessenger) - connects Messenger to MessageSource, is called from `init` or `_setMessageSource` methods of [Messenger](./index.js.html).
- * - [onSubscriberAdded](#onSubscriberAdded) - called by Messenger to notify when the first subscriber for an internal message was added, so MessageSource can subscribe to source
- * - [onSubscriberRemoved](#onSubscriberRemoved) - called by Messenger to notify when the last subscriber for an internal message was removed, so MessageSource can unsubscribe from source
- * - [dispatchMessage](#dispatchMessage) - dispatches source message. MessageSource subclass should implement mechanism when on actual source message this method is called.
- *
- * Methods below should be implemented in subclass:
- *
- * - [trigger](#trigger) - triggers messages on the source (an optional method)
- * - [addSourceSubscriber](#addSourceSubscriber) - adds listener/subscriber to external message
- * - [removeSourceSubscriber](#removeSourceSubscriber) - removes listener/subscriber from external message
- */
-_.extendProto(MessageSource, {
- init: init,
- destroy: MessageSource$destroy,
- setMessenger: setMessenger,
- onSubscriberAdded: onSubscriberAdded,
- onSubscriberRemoved: onSubscriberRemoved,
- dispatchMessage: dispatchMessage,
- postMessage: postMessage,
- _prepareMessengerAPI: _prepareMessengerAPI,
+// - enabled
- // Methods below must be implemented in subclass
- trigger: toBeImplemented,
- addSourceSubscriber: toBeImplemented,
- removeSourceSubscriber: toBeImplemented
-});
+// true by default. Set to false to disable all logging in browser console.
-/**
- * MessageSource instance method.
- * Called by Mixin constructor.
- * MessageSource constructor should be passed the same parameters as this method signature.
- * If an instance of [MessengerAPI](./m_api.js.html) is passed as the third parameter, it extends MessageSource functionality to allow it to define new messages, to filter messages based on their data and to change message data. See [MessengerAPI](./m_api.js.html).
- *
- * @param {Object} hostObject Optional object that stores the MessageSource on one of its properties. It is used to proxy methods of MessageSource.
- * @param {Object[String]} proxyMethods Optional map of method names; key - proxy method name, value - MessageSource's method name.
- * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI.
- */
-function init(hostObject, proxyMethods, messengerAPI) {
- this._prepareMessengerAPI(messengerAPI);
-}
+var Logger = require('./logger_class');
+
+var logger = new Logger({ level: 3 });
+
+module.exports = logger;
+
+},{"./logger_class":119}],119:[function(require,module,exports){
+'use strict';
+
+// ### Logger Class
+
+// Properties:
+
+// - level
+
+// - 0 - error
+// - 1 - warn
+// - 2 - info
+// - 3 - debug (default)
+
+// - enabled
+
+// true by default. Set to false to disable all logging in browser console.
+
+
+var _ = require('mol-proto');
/**
- * Destroys message source
+ * Log levels.
*/
-function MessageSource$destroy() {
- if (this.messengerAPI)
- this.messengerAPI.destroy();
-}
+var levels = [
+ 'error',
+ 'warn',
+ 'info',
+ 'debug'
+];
+
+var maxLevelLength = Math.max.apply(Math, levels.map(function(level) { return level.length; }));
/**
- * MessageSource instance method.
- * Sets reference to Messenger instance.
- *
- * @param {Messenger} messenger reference to Messenger instance linked to this MessageSource
+ * Colors for log levels.
*/
-function setMessenger(messenger) {
- _.defineProperty(this, 'messenger', messenger);
-}
+var colors = [
+ 31,
+ 33,
+ 36,
+ 90
+];
/**
- * MessageSource instance method.
- * Prepares [MessengerAPI](./m_api.js.html) passed to constructor by proxying its methods to itself or if MessengerAPI wasn't passed defines two methods to avoid checking their availability every time the message is dispatched.
- *
- * @private
- * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI
+ * Pads the nice output to the longest log level.
*/
-function _prepareMessengerAPI(messengerAPI) {
- check(messengerAPI, Match.Optional(MessengerAPI));
+function pad(str) {
+ if (str.length < maxLevelLength)
+ return str + new Array(maxLevelLength - str.length + 1).join(' ');
- if (! messengerAPI)
- messengerAPI = new MessengerAPI;
+ return str;
+};
- _.defineProperty(this, 'messengerAPI', messengerAPI);
+
+function colored(str, color) {
+ return '\x1B[' + color + 'm' + str + ' -\x1B[39m';
}
-/**
- * MessageSource instance method.
- * Subscribes to external source using `addSourceSubscriber` method that should be implemented in subclass.
- * This method is called by [Messenger](./index.js.html) when the first subscriber to the `message` is added.
- * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.addInternalMessage` will return undefined if this `sourceMessage` was already subscribed to to prevent duplicate subscription.
- *
- * @param {String} message internal Messenger message that has to be subscribed to at the external source of messages.
- */
-function onSubscriberAdded(message) {
- var newSourceMessage = this.messengerAPI.addInternalMessage(message);
- if (typeof newSourceMessage != 'undefined')
- this.addSourceSubscriber(newSourceMessage);
+var DEFAULT_OPTIONS = {
+ level: 3,
+ throwLevel: -1, // never throw
+ enabled: true,
+ logPrefix: ''
}
/**
- * MessageSource instance method.
- * Unsubscribes from external source using `removeSourceSubscriber` method that should be implemented in subclass.
- * This method is called by [Messenger](./index.js.html) when the last subscriber to the `message` is removed.
- * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.removeInternalMessage` will return undefined if this `sourceMessage` was not yet subscribed to to prevent unsubscription without previous subscription.
+ * Logger (console).
*
- * @param {String} message internal Messenger message that has to be unsubscribed from at the external source of messages.
+ * @api public
*/
-function onSubscriberRemoved(message) {
- var removedSourceMessage = this.messengerAPI.removeInternalMessage(message);
- if (typeof removedSourceMessage != 'undefined')
- this.removeSourceSubscriber(removedSourceMessage);
-}
+var Logger = function (opts) {
+ _.extend(this, DEFAULT_OPTIONS);
+ _.extend(this, opts || {});
+};
/**
- * MessageSource instance method.
- * Dispatches sourceMessage to Messenger.
- * Mechanism that calls this method when the source message is received should be implemented by subclass (see [DOMEventsSource](../components/msg_src/dom_events.js.html) for example).
- * Delegates to supplied or default [MessengerAPI](./m_api.js.html) to create internal message data (`createInternalData`) and to filter the message based on its data and/or message (`filterSourceMessage`).
- * Base MessengerAPI class implements these two methods in a trivial way (`createInternalData` simply returns external data, `filterSourceMessage` returns `true`), they are meant to be implemented by subclass.
+ * Log method.
*
- * @param {String} sourceMessage source message received from external source
- * @param {Object} sourceData data received from external source
+ * @api public
*/
-function dispatchMessage(sourceMessage, sourceData) {
- var api = this.messengerAPI
- , internalMessages = api.getInternalMessages(sourceMessage);
-
- if (internalMessages)
- internalMessages.forEach(function (message) {
- var internalData = api.createInternalData(sourceMessage, message, sourceData);
-
- var shouldDispatch = api.filterSourceMessage(sourceMessage, message, internalData);
- if (shouldDispatch)
- this.postMessage(message, internalData);
-
- }, this);
-}
-
-/**
- * Posts message on the messenger. This method is separated so specific message sources can make message dispatch synchronous by using `postMessageSync`
- *
- * @param {String} message
- * @param {Object} data
- */
-function postMessage(message, data) {
- this.messenger.postMessage(message, data);
-}
+Logger.prototype.log = function (type) {
+ var index = levels.indexOf(type);
+ if (! this.enabled || index > this.level)
+ return this;
-function toBeImplemented() {
- throw new Error('calling the method of an absctract class');
-}
+ var args = _.slice(arguments, 1);
-},{"../abstract/mixin":116,"../util/check":135,"../util/logger":137,"./m_api":120,"mol-proto":141}],123:[function(require,module,exports){
-arguments[4][71][0].apply(exports,arguments)
-},{"../util/check":135,"./m_source":122,"mol-proto":141}],124:[function(require,module,exports){
-'use strict';
+ if (index <= this.throwLevel)
+ throw new Error([this.logPrefix, type + ':'].concat(args).join(' '));
-var _ = require('mol-proto');
+ console.log.apply(
+ console
+ , [ this.logPrefixColor
+ ? ' ' + colored(this.logPrefix, this.logPrefixColor)
+ : this.logPrefix,
+ (this.colors
+ ? ' ' + colored(pad(type), colors[index])
+ : type) + ':'
+ ].concat(args)
+ );
+ return this;
+};
/**
- * ####Milo packages####
- *
- * - [minder](./minder.js.html) - data reactivity, one or two way, shallow or deep, as you like it
- * - [config](./config.js.html) - milo configuration
- * - [util](./util/index.js.html) - logger, request, dom, check, error, etc.
- * - [classes](./classes.js.html) - abstract and base classes
- * - [Messenger](./messenger/index.js.html) - generic Messenger used in most other milo classes, can be mixed into app classes too.
- * - [Model](./model/index.js.html) - Model class that emits messages on changes to any depth without timer based watching
+ * Generate methods.
*/
-var milo = {
- minder: require('./minder'),
- config: require('./config'),
- util: require('./util'),
- classes: require('./classes'),
- Messenger: require('./messenger'),
- Model: require('./model'),
- destroy: destroy
-};
+levels.forEach(function (name) {
+ Logger.prototype[name] = function () {
+ this.log.apply(this, [name].concat(_.toArray(arguments)));
+ };
+});
-// export for node/browserify
-if (typeof module == 'object' && module.exports)
- module.exports = milo;
-// global milo for browser
-if (typeof window == 'object')
- window.milo = milo;
+module.exports = Logger;
+},{"mol-proto":122}],120:[function(require,module,exports){
+// doT.js
+// 2011-2014, Laura Doktorova, https://github.com/olado/doT
+// Licensed under the MIT license.
-function destroy() {
- milo.minder.destroy();
-}
+(function() {
+ "use strict";
-},{"./classes":117,"./config":118,"./messenger":119,"./minder":125,"./model":128,"./util":136,"mol-proto":141}],125:[function(require,module,exports){
-'use strict';
+ var doT = {
+ version: "1.0.3",
+ templateSettings: {
+ evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g,
+ interpolate: /\{\{=([\s\S]+?)\}\}/g,
+ encode: /\{\{!([\s\S]+?)\}\}/g,
+ use: /\{\{#([\s\S]+?)\}\}/g,
+ useParams: /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
+ define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
+ defineParams:/^\s*([\w$]+):([\s\S]+)/,
+ conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
+ iterate: /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
+ varname: "it",
+ strip: true,
+ append: true,
+ selfcontained: false,
+ doNotSkipEncoded: false
+ },
+ template: undefined, //fn, compile template
+ compile: undefined //fn, for express
+ }, _globals;
-var Connector = require('./model/connector')
- , Messenger = require('./messenger')
- , _ = require('mol-proto')
- , logger = require('./util/logger');
+ doT.encodeHTMLSource = function(doNotSkipEncoded) {
+ var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'", "/": "/" },
+ matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g;
+ return function(code) {
+ return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : "";
+ };
+ };
+ _globals = (function(){ return this || (0,eval)("this"); }());
-module.exports = minder;
+ if (typeof module !== "undefined" && module.exports) {
+ module.exports = doT;
+ } else if (typeof define === "function" && define.amd) {
+ define(function(){return doT;});
+ } else {
+ _globals.doT = doT;
+ }
+ var startend = {
+ append: { start: "'+(", end: ")+'", startencode: "'+encodeHTML(" },
+ split: { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML(" }
+ }, skip = /$^/;
-/**
- * This function creates one or many Connector objects that
- * create live reactive connection between objects implementing
- * dataSource interface:
- * Objects should emit messages when any part of their data changes,
- * methods `on` and `off` should be implemented to subscribe/unsubscribe
- * to change notification messages, methods `set` and `get` should be implemented to get/set data
- * on path objects, pointing to particular parts of the object, method `path`
- * should return path object for a given path string (see path utils for path string syntax).
- * Both Model and Data facet are such data sources, they can be linked by Connector object.
- *
- * @param {Object} ds1 the first data source. Instead of the first data source an array can be passed with arrays of Connection objects parameters in each array element.
- * @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
- * @param {Object} ds2 the second data source
- * @param {Object} options not implemented yet
- */
-function minder(ds1, mode, ds2, options) {
- if (Array.isArray(ds1)) {
- var connDescriptions = ds1;
- var connectors = connDescriptions.map(function(descr) {
- return new Connector(descr[0], descr[1], descr[2], descr[3]);
- });
- connectors.forEach(_addConnector);
- return connectors;
- } else {
- var cnct = new Connector(ds1, mode, ds2, options);
- _addConnector(cnct);
- return cnct;
- }
-}
+ function resolveDefs(c, block, def) {
+ return ((typeof block === "string") ? block : block.toString())
+ .replace(c.define || skip, function(m, code, assign, value) {
+ if (code.indexOf("def.") === 0) {
+ code = code.substring(4);
+ }
+ if (!(code in def)) {
+ if (assign === ":") {
+ if (c.defineParams) value.replace(c.defineParams, function(m, param, v) {
+ def[code] = {arg: param, text: v};
+ });
+ if (!(code in def)) def[code]= value;
+ } else {
+ new Function("def", "def['"+code+"']=" + value)(def);
+ }
+ }
+ return "";
+ })
+ .replace(c.use || skip, function(m, code) {
+ if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {
+ if (def[d] && def[d].arg && param) {
+ var rw = (d+":"+param).replace(/'|\\/g, "_");
+ def.__exp = def.__exp || {};
+ def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2");
+ return s + "def.__exp['"+rw+"']";
+ }
+ });
+ var v = new Function("def", "return " + code)(def);
+ return v ? resolveDefs(c, v, def) : v;
+ });
+ }
+ function unescape(code) {
+ return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " ");
+ }
-/**
- * messenger of minder where it emits events related to all connectors
- * @type {Messenger}
- */
-var _messenger = new Messenger(minder, Messenger.defaultMethods);
+ doT.template = function(tmpl, c, def) {
+ c = c || doT.templateSettings;
+ var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,
+ str = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;
+ str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ")
+ .replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""): str)
+ .replace(/'|\\/g, "\\$&")
+ .replace(c.interpolate || skip, function(m, code) {
+ return cse.start + unescape(code) + cse.end;
+ })
+ .replace(c.encode || skip, function(m, code) {
+ needhtmlencode = true;
+ return cse.startencode + unescape(code) + cse.end;
+ })
+ .replace(c.conditional || skip, function(m, elsecase, code) {
+ return elsecase ?
+ (code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
+ (code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
+ })
+ .replace(c.iterate || skip, function(m, iterate, vname, iname) {
+ if (!iterate) return "';} } out+='";
+ sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
+ return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"= 0)
- delete _connectors[index];
- else
- logger.warn('minder: connector destroyed that is not registered in minder');
+function addexports(exports) {
+ for (var ret ='', i=0; i< exports.length; i++) {
+ ret += "itself." + exports[i]+ "=" + exports[i]+";";
+ }
+ return ret;
}
-
-function minder_getExpandedConnections(onOff, searchStr) {
- var connectors = minder.getConnectors(onOff);
- var connections = connectors.map(function(cnct) {
- var connection = {
- leftSource: _getExpandedSource(cnct.ds1),
- rightSource: _getExpandedSource(cnct.ds2),
- mode: cnct.mode,
- isOn: cnct.isOn
- };
-
- if (cnct.options)
- connection.options = cnct.options;
-
- return connection;
- });
-
- if (searchStr)
- connections = connections.filter(function(cnctn) {
- return _sourceMatchesString(cnctn.leftSource, searchStr)
- || _sourceMatchesString(cnctn.rightSource, searchStr);
- });
-
- return connections;
+function copy(o, to) {
+ to = to || {};
+ for (var property in o) {
+ to[property] = o[property];
+ }
+ return to;
}
-
-function _getExpandedSource(ds) {
- var source = [];
- if (typeof ds == 'function') {
- if (ds._model && ds._accessPath) {
- source.unshift(ds._accessPath);
- ds = ds._model;
- }
-
- source.unshift(ds);
- ds = ds._hostObject;
- }
-
- if (typeof ds == 'object') {
- source.unshift(ds);
-
- if (ds.owner)
- source.unshift(ds.owner);
- }
-
- return source;
+function readdata(path) {
+ var data = fs.readFileSync(path);
+ if (data) return data.toString();
+ console.log("problems with " + path);
}
+InstallDots.prototype.compilePath = function(path) {
+ var data = readdata(path);
+ if (data) {
+ return doT.template(data,
+ this.__settings || doT.templateSettings,
+ copy(this.__includes));
+ }
+};
-function _sourceMatchesString(source, matchStr) {
- return source.some(function(srcNode) {
- var className = srcNode.constructor && srcNode.constructor.name;
- return _stringMatch(className, matchStr)
- || _stringMatch(srcNode.name, matchStr)
- || _stringMatch(srcNode, matchStr);
- });
-}
-
+InstallDots.prototype.compileAll = function() {
+ console.log("Compiling all doT templates...");
-function _stringMatch(str, substr) {
- return str && typeof str == 'string' && str.indexOf(substr) >= 0;
-}
+ var defFolder = this.__path,
+ sources = fs.readdirSync(defFolder),
+ k, l, name;
+ for( k = 0, l = sources.length; k < l; k++) {
+ name = sources[k];
+ if (/\.def(\.dot|\.jst)?$/.test(name)) {
+ console.log("Loaded def " + name);
+ this.__includes[name.substring(0, name.indexOf('.'))] = readdata(defFolder + name);
+ }
+ }
-function minder_destroy() {
- _connectors.forEach(function(cnct) {
- destroyDS(cnct.ds1);
- destroyDS(cnct.ds2);
- cnct.destroy();
- });
- _messenger.destroy();
- minder._destroyed = true;
-
- function destroyDS(ds) {
- if (ds && !ds._destroyed) ds.destroy();
- }
-}
-
-},{"./messenger":119,"./model/connector":127,"./util/logger":137,"mol-proto":141}],126:[function(require,module,exports){
-'use strict';
-
-
-var logger = require('../util/logger')
- , config = require('../config')
- , pathUtils = require('./path_utils')
- , _ = require('mol-proto');
-
-/**
- * Utility function to process "changedata" messages emitted by Connector object.
- */
-module.exports = changeDataHandler;
-
-
-_.extend(changeDataHandler, {
- setTransactionFlag: setTransactionFlag,
- getTransactionFlag: getTransactionFlag,
- passTransactionFlag: passTransactionFlag,
- postTransactionFinished: postTransactionFinished
-});
-
-
-/**
- * Change data uses hidden property on accessor methods to pass flag that the accessor is executed as a part of change transaction.
- * Accessor methods are supposed to store this flag in a local variable and to clear it (because another accessor can be executed in or out of transaction) using `getTransactionFlag`
- *
- * @private
- * @param {Function} func accessor method reference
- * @param {Boolean} flag a flag to be set
- */
-function setTransactionFlag(func, flag) {
- _.defineProperty(func, '__inChangeTransaction', flag, _.CONF | _.WRIT);
-}
-
-
-/**
- * Retrieves and clears transaction flag from accessor method
- *
- * @private
- * @param {Function} func accessor method reference
- * @return {Boolean}
- */
-function getTransactionFlag(func) {
- var inTransaction = func.__inChangeTransaction;
- delete func.__inChangeTransaction;
- return inTransaction;
-}
-
-
-function passTransactionFlag(fromFunc, toFunc) {
- var inTransaction = getTransactionFlag(fromFunc);
- setTransactionFlag(toFunc, inTransaction);
- return inTransaction;
-}
-
-
-/**
- * Posts message on this to indicate the end of transaction unless `inChangeTransaction` is `true`.
- */
-function postTransactionFinished() {
- this.postMessageSync('datachanges', { transaction: false, changes: [] });
-}
-
-
-/**
- * subscriber to "changedata" event emitted by [Connector](./connector.js.html) object to enable reactive connections
- * Used by Data facet, Model and ModelPath. Can be used by any object that implements get/set/del/splice api and sets data deeply to the whole tree.
- * Object should call `changeDataHandler.initialize.call(this)` in its constructor.
- * TODO: optimize messages list to avoid setting duplicate values down the tree
- *
- * @param {String} msg should be "changedata" here
- * @param {Object} data batch of data change desciption objects
- * @param {Function} callback callback to call before and after the data is processed
- */
-function changeDataHandler(message, data, callback) {
- processChanges.call(this, data.changes, callback);
-}
-
-
-// map of message types to methods
-var CHANGE_TYPE_TO_METHOD_MAP = {
- 'added': 'set',
- 'changed': 'set',
- 'deleted': 'del',
- 'removed': 'del'
-};
-
-
-/**
- * Processes queued "changedata" messages.
- * Posts "changestarted" and "changecompleted" messages and calls callback
- *
- * @param {[Function]} callback optional callback that is called with `(null, false)` parameters before change processing starts and `(null, true)` after it's finished.
- */
-function processChanges(transaction, callback) {
- notify.call(this, callback, false);
- processTransaction.call(this,
- prepareTransaction(
- validateTransaction(transaction)));
- notify.call(this, callback, true);
-}
-
-
-function notify(callback, changeFinished) {
- callback && callback(null, changeFinished);
- this.postMessage(changeFinished ? 'changecompleted' : 'changestarted');
-}
-
-
-/**
- * Checks that all messages from the transaction come from the same source.
- * Hack: reverses the transaction if it comes from the Data facet
- * Returns the reference to the transaction (for chaining)
- *
- * @param {Array} transaction transaction of data changes
- * @return {Array}
- */
-function validateTransaction(transaction) {
- var source = transaction[0].source
- , sameSource = true;
-
- if (transaction.length > 1) {
- for (var i = 1, len = transaction.length; i < len; i++)
- if (transaction[i].source != source) {
- logger.error('changedata: changes from different sources in the same transaction, sources:', transaction[i].source.name, source.name);
- sameSource = false;
- source = transaction[i].source;
- }
- }
-
- return transaction;
-}
-
-
-function prepareTransaction(transaction) {
- var todo = []
- , pathsToSplice = []
- , pathsToChange = []
- , hadSplice
- , exitLoop = {};
-
-
- try { transaction.forEach(checkChange); }
- catch (e) { if (e != exitLoop) throw e; }
-
- return todo;
-
-
- function checkChange(data) {
- (data.type == 'splice' ? checkSplice : checkMethod)(data);
- }
-
-
- function checkSplice(data) {
- var parsedPath = pathUtils.parseAccessPath(data.path);
- var parentPathChanged = pathsToChange.some(function(parentPath) {
- if (parsedPath.length < parentPath.length) return;
- return _pathIsParentOf(parentPath, parsedPath);
- });
-
- if (parentPathChanged) return;
-
- todo.push(data);
-
- if (! config.debug) throw exitLoop;
- pathsToSplice.push(parsedPath);
- hadSplice = true;
- }
-
-
- function checkMethod(data) {
- var parsedPath = pathUtils.parseAccessPath(data.path);
- var parentPathSpliced = pathsToSplice && pathsToSplice.some(function(parentPath) {
- if (parsedPath.length <= parentPath.length
- || parsedPath[parentPath.length].syntax != 'array') return;
- return _pathIsParentOf(parentPath, parsedPath);
- });
-
- if (parentPathSpliced) return;
- if (hadSplice) logger.error('changedata: child change is executed after splice; probably data source did not emit message with data.type=="finished"');
-
- var parentPathChanged = pathsToChange.some(function(parentPath) {
- if (parsedPath.length <= parentPath.length) return;
- return _pathIsParentOf(parentPath, parsedPath);
- });
-
- if (parentPathChanged) return;
-
- pathsToChange.push(parsedPath);
-
- todo.push(data);
- }
-
-
- function _pathIsParentOf(parentPath, childPath) {
- return parentPath.every(function(pathNode, index) {
- return pathNode.property == childPath[index].property;
- });
- }
-}
-
-
-function processTransaction(transaction) {
- transaction.forEach(processChange, this);
- postTransactionFinished.call(this, false);
-
- function processChange(data) {
- var modelPath = this.path(data.path, data.type != 'removed' && data.type != 'deleted');
- if (! modelPath) return;
- (data.type == 'splice' ? executeSplice : executeMethod)(modelPath, data);
- }
-}
-
-
-function executeSplice(modelPath, data) {
- var index = data.index
- , howMany = data.removed.length
- , spliceArgs = [index, howMany];
-
- spliceArgs = spliceArgs.concat(data.newValue.slice(index, index + data.addedCount));
- setTransactionFlag(modelPath.splice, true);
- modelPath.splice.apply(modelPath, spliceArgs);
-}
-
-
-function executeMethod(modelPath, data) {
- var methodName = CHANGE_TYPE_TO_METHOD_MAP[data.type];
- if (methodName) {
- setTransactionFlag(modelPath[methodName], true);
- modelPath[methodName](data.newValue);
- } else
- logger.error('unknown data change type');
-}
-
-},{"../config":118,"../util/logger":137,"./path_utils":133,"mol-proto":141}],127:[function(require,module,exports){
-'use strict';
-
-var Messenger = require('../messenger')
- , pathUtils = require('./path_utils')
- , _ = require('mol-proto')
- , logger = require('../util/logger');
-
-
-module.exports = Connector;
-
-
-var modePattern = /^(\<*)\-+(\>*)$/;
-
-
-/**
- * Connector
- * Class that creates connector object for data connection between
- * two data-sources
- * Data-sources should implement the following API:
- * get() - get value from datasource or its path
- * set(value) - set value to datasource or to its path
- * on(path, subscriber) - subscription to data changes with "*" support
- * off(path, subscriber)
- * path(accessPath) - to return the object that gives reference to some part of datasource
- * and complies with that api too.
- *
- * ####Events####
- *
- * - 'turnedon' - connector was turned on
- * - 'turnedoff' - connector was turned off
- * - 'changestarted' - change on connected datasource is started
- * - 'changecompleted' - change on connected datasource is completed
- * - 'destroyed' - connector was destroyed
- *
- * @param {Object} ds1 the first data source.
- * @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
- * @param {Object} ds2 the second data source
- * @param {Object} options not implemented yet
- * @return {Connector} when called with `new`, creates a Connector object.
- */
-function Connector(ds1, mode, ds2, options) {
- setupMode.call(this, mode);
-
- _.extend(this, {
- ds1: ds1,
- ds2: ds2,
- isOn: false,
- _changesQueue1: [],
- _changesQueue2: [],
- _messenger: new Messenger(this, Messenger.defaultMethods)
- });
-
- if (options) {
- this.options = options;
-
- var pathTranslation = options.pathTranslation;
- if (pathTranslation) {
- pathTranslation = _.clone(pathTranslation);
- var patternTranslation = getPatternTranslations(pathTranslation);
- _.extend(this, {
- pathTranslation1: reverseTranslationRules(pathTranslation),
- pathTranslation2: pathTranslation,
- patternTranslation1: reversePatternTranslationRules(patternTranslation),
- patternTranslation2: patternTranslation
- });
- }
-
- var dataTranslation = options.dataTranslation;
- if (dataTranslation) {
- _.extend(this, {
- dataTranslation1: dataTranslation['<-'],
- dataTranslation2: dataTranslation['->']
- });
- }
-
- var dataValidation = options.dataValidation;
- if (dataValidation) {
- _.extend(this, {
- dataValidation1: dataValidation['<-'],
- dataValidation2: dataValidation['->']
- });
- }
- }
-
- this.turnOn();
-}
-
-
-function setupMode(mode){
- var parsedMode = mode.match(modePattern);
-
- if (! parsedMode)
- modeParseError();
-
- var depth1 = parsedMode[1].length
- , depth2 = parsedMode[2].length;
-
- if (depth1 && depth2 && depth1 != depth2)
- modeParseError();
-
- if (! depth1 && ! depth2)
- modeParseError();
-
- _.extend(this, {
- mode: mode,
- depth1: depth1,
- depth2: depth2,
- });
-
- function modeParseError() {
- throw new Error('invalid Connector mode: ' + mode);
- }
-}
-
-
-_.extendProto(Connector, {
- turnOn: Connector$turnOn,
- turnOff: Connector$turnOff,
- destroy: Connector$destroy,
- changeMode: Connector$changeMode,
- deferChangeMode: Connector$deferChangeMode
-});
-
-/**
- * Function change the mode of the connection
- *
- * @param @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
- * @return {Object[String]}
- */
-function Connector$changeMode(mode) {
- this.turnOff();
- setupMode.call(this, mode);
- this.turnOn();
- return this;
-}
-
-
-/**
- * Function change the mode of the connection
- *
- * @param @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.
- * @return {Object[String]}
- */
-function Connector$deferChangeMode(mode) {
- _.deferMethod(this, 'changeMode', mode);
- return this;
-}
-
-
-/**
- * Function that reverses translation rules for paths of connected odata sources
- *
- * @param {Object[String]} rules map of paths defining the translation rules
- * @return {Object[String]}
- */
-function reverseTranslationRules(rules) {
- var reverseRules = {};
- _.eachKey(rules, function(path2_value, path1_key) {
- reverseRules[path2_value] = path1_key;
- });
- return reverseRules;
-}
-
-
-function getPatternTranslations(pathTranslation) {
- var patternTranslation = [];
- _.eachKey(pathTranslation, function(path2_value, path1_key) {
- var starIndex1 = path1_key.indexOf('*')
- , starIndex2 = path2_value.indexOf('*');
- if (starIndex1 >= 0 && starIndex2 >= 0) { // pattern translation
- if (path1_key.slice(starIndex1) != path2_value.slice(starIndex2))
- _throwInvalidTranslation(path1_key, path2_value);
- delete pathTranslation[path1_key];
-
- patternTranslation.push({
- fromPattern: pathUtils.createRegexPath(path1_key),
- fromStaticPath: _getStaticPath(path1_key, starIndex1),
- toPattern: pathUtils.createRegexPath(path2_value),
- toStaticPath: _getStaticPath(path2_value, starIndex2)
- });
- } else if (starIndex1 >= 0 || starIndex2 >= 0) // pattern only on one side of translation
- _throwInvalidTranslation(path1_key, path2_value);
- });
-
- return patternTranslation;
-
-
- function _throwInvalidTranslation(path1, path2) {
- throw new Error('Invalid pattern translation: ' + path1 + ', ' + path2);
- }
-
-
- function _getStaticPath(path, starIndex) {
- return path.replace(/[\.\[]?\*.*$/, '');
- }
-}
-
-
-function reversePatternTranslationRules(patternTranslation) {
- return patternTranslation.map(function(pt) {
- return {
- fromPattern: pt.toPattern,
- fromStaticPath: pt.toStaticPath,
- toPattern: pt.fromPattern,
- toStaticPath: pt.fromStaticPath
- };
- });
-}
-
-
-/**
- * turnOn
- * Method of Connector that enables connection (if it was previously disabled)
- */
-function Connector$turnOn() {
- if (this.isOn)
- return logger.warn('data sources are already connected');
-
- var subscriptionPath = this._subscriptionPath =
- new Array(this.depth1 || this.depth2).join('*');
-
- var subscriptionPattern = pathUtils.createRegexPath(subscriptionPath);
-
- var self = this;
- if (this.depth1)
- this._link1 = linkDataSource('_link2', this.ds2, this.ds1, this._changesQueue1, this.pathTranslation1, this.patternTranslation1, this.dataTranslation1, this.dataValidation1);
- if (this.depth2)
- this._link2 = linkDataSource('_link1', this.ds1, this.ds2, this._changesQueue2, this.pathTranslation2, this.patternTranslation2, this.dataTranslation2, this.dataValidation2);
-
- this.isOn = true;
- this.postMessage('turnedon');
-
-
- function linkDataSource(reverseLink, fromDS, toDS, changesQueue, pathTranslation, patternTranslation, dataTranslation, dataValidation) {
- fromDS.onSync('datachanges', onData);
- return onData;
-
- function onData(message, batch) {
- var sendData = {
- changes: [],
- transaction: batch.transaction
- }
-
- batch.changes.forEach(function(change) {
- var sourcePath = change.path
- , targetPath = translatePath(sourcePath);
-
- if (typeof targetPath == 'undefined') return;
-
- var change = _.clone(change);
- _.extend(change, {
- source: fromDS,
- path: targetPath
- });
-
- translateData(sourcePath, change);
- validateData(sourcePath, change);
- });
-
- if (! changesQueue.length)
- _.defer(postChangeData);
-
- changesQueue.push(sendData);
-
-
- function translatePath(sourcePath) {
- if (pathTranslation) {
- var translatedPath = pathTranslation[sourcePath];
- if (translatedPath) return translatedPath;
- if (!patternTranslation.length) return;
- var pt = _.find(patternTranslation, function(pTranslation) {
- return pTranslation.fromPattern.test(sourcePath);
- });
- if (!pt) return;
- var translatedPath = sourcePath.replace(pt.fromStaticPath, pt.toStaticPath);
- } else if (! ((subscriptionPattern instanceof RegExp
- && subscriptionPattern.test(sourcePath))
- || subscriptionPattern == sourcePath)) return;
-
- return translatedPath || sourcePath;
- }
-
-
- function translateData(sourcePath, change) {
- if (dataTranslation) {
- var translate = dataTranslation[sourcePath];
- if (translate && typeof translate == 'function') {
- change.oldValue = translate(change.oldValue);
- change.newValue = translate(change.newValue);
- }
- }
- }
-
-
- function validateData(sourcePath, change) {
- propagateData(change);
-
- if (dataValidation) {
- var validators = dataValidation[sourcePath]
- , passedCount = 0
- , alreadyFailed = false;
-
- if (validators)
- validators.forEach(callValidator);
- }
-
-
- function callValidator(validator) {
- validator(change.newValue, function(err, response) {
- response.path = sourcePath;
- if (! alreadyFailed && (err || response.valid) && ++passedCount == validators.length) {
- fromDS.postMessage('validated', response);
- } else if (! response.valid) {
- alreadyFailed = true;
- fromDS.postMessage('validated', response);
- }
- });
- }
- }
-
-
- function propagateData(change) {
- sendData.changes.push(change);
- }
-
-
- function postChangeData() {
- // prevent endless loop of updates for 2-way connection
- if (self[reverseLink]) var callback = subscriptionSwitch;
-
- var transactions = mergeTransactions(changesQueue);
- changesQueue.length = 0;
- transactions.forEach(function(transaction) {
- // send data change instruction as message
- toDS.postMessageSync('changedata', { changes: transaction }, callback);
- });
- }
-
-
- function subscriptionSwitch(err, changeFinished) {
- if (err) return;
- var onOff = changeFinished ? 'onSync' : 'off';
- toDS[onOff]('datachanges', self[reverseLink]);
-
- var message = changeFinished ? 'changecompleted' : 'changestarted';
- self.postMessage(message, { source: fromDS, target: toDS });
- }
-
-
- function mergeTransactions(batches) {
- var transactions = []
- , currentTransaction;
-
- batches.forEach(function(batch) {
- if (! batch.transaction) currentTransaction = undefined;
- if (! batch.changes.length) return;
-
- if (batch.transaction) {
- if (currentTransaction)
- _.appendArray(currentTransaction, batch.changes);
- else {
- currentTransaction = _.clone(batch.changes);
- transactions.push(currentTransaction);
- }
- } else
- transactions.push(batch.changes);
- });
-
- return transactions;
- }
- }
- }
-}
-
-
-/**
- * turnOff
- * Method of Connector that disables connection (if it was previously enabled)
- */
-function Connector$turnOff() {
- if (! this.isOn)
- return logger.warn('data sources are already disconnected');
-
- var self = this;
- unlinkDataSource(this.ds1, '_link2', this.pathTranslation2);
- unlinkDataSource(this.ds2, '_link1', this.pathTranslation1);
-
- this.isOn = false;
- this.postMessage('turnedoff');
-
-
- function unlinkDataSource(fromDS, linkName, pathTranslation) {
- if (self[linkName]) {
- fromDS.off('datachanges', self[linkName]);
- delete self[linkName];
- }
- }
-}
-
-
-/**
- * Destroys connector object by turning it off and removing references to connected sources
- */
-function Connector$destroy() {
- this.turnOff();
- this.postMessage('destroyed');
- this._messenger.destroy();
- delete this.ds1;
- delete this.ds2;
- this._destroyed = true;
-}
-
-},{"../messenger":119,"../util/logger":137,"./path_utils":133,"mol-proto":141}],128:[function(require,module,exports){
-'use strict';
-
-var ModelPath = require('./m_path')
- , synthesize = require('./synthesize')
- , pathUtils = require('./path_utils')
- , changeDataHandler = require('./change_data')
- , Messenger = require('../messenger')
- , MessengerMessageSource = require('../messenger/msngr_source')
- , ModelMsgAPI = require('./m_msg_api')
- , Mixin = require('../abstract/mixin')
- , _ = require('mol-proto')
- , check = require('../util/check')
- , Match = check.Match
- , logger = require('../util/logger');
-
-
-module.exports = Model;
-
-
-/**
- * `milo.Model`
- * Model class instantiates objects that allow deep data access with __safe getters__ that return undefined (rather than throwing exception) when properties/items of unexisting objects/arrays are requested and __safe setters__ that create object trees when properties/items of unexisting objects/arrays are set and also post messages to allow subscription on changes and enable data reactivity.
- * Reactivity is implememnted via [Connector](./connector.js.html) that can be instantiated either directly or with more convenient interface of [milo.minder](../minder.js.html). At the moment model can be connected to [Data facet](../components/c_facets/Data.js.html) or to another model or [ModelPath](./m_path.js.html).
- * Model constructor returns objects that are functions at the same time; when called they return ModelPath objects that allow get/set access to any point in model data. See [ModelData](#ModelData) below.
- *
- * You can subscribe to model changes with `on` method by passing model access path in place of message, pattern or string with any number of stars to subscribe to a certain depth in model (e.g., `'***'` to subscribe to three levels).
- *
- * @constructor
- * @param {Object|Array} data optional initial array data. If it is planned to connect model to view it is usually better to instantiate an empty Model (`var m = new Model`), connect it to [Component](../components/c_class.js.html)'s [Data facet](../components/c_facets/Data.js.html) (e.g., `milo.minder(m, '<<->>', c.data);`) and then set the model with `m.set(data)` - the view will be automatically updated.
- * @param {Object} hostObject optional object that hosts model on one of its properties. Can be used when model itself is the context of the message subscriber and you need to travers to this object (although it is possible to set any context). Can also be used to proxy model's methods to the host like [Model facet](../components/c_facets/ModelFacet.js.html) is doing.
- * @param {Object} options pass { reactive: false } to use model without messaging when it is not needed - it makes it much faster
- * @return {Model}
- */
-function Model(data, hostObject, options) {
- // `model` will be returned by constructor instead of `this`. `model`
- // (`modelPath` function) should return a ModelPath object with "synthesized" methods
- // to get/set model properties, to subscribe to property changes, etc.
- // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.
- var model = function modelPath(accessPath) { // , ... arguments that will be interpolated
- return Model$path.apply(model, arguments);
- };
- model.__proto__ = Model.prototype;
-
- model._hostObject = hostObject;
- model._options = options || {};
-
- if (model._options.reactive !== false) {
- model._prepareMessengers();
- // subscribe to "changedata" message to enable reactive connections
- model.onSync('changedata', changeDataHandler);
- }
-
- if (data) model._data = data;
-
- return model;
-}
-
-Model.prototype.__proto__ = Model.__proto__;
-
-
-/**
- * ####Model instance methods####
- *
- * - [path](#path) - returns ModelPath object that allows access to any point in Model
- * - [get](#Model$get) - get model data
- * - set - set model data, synthesized
- * - splice - splice model data (as array or pseudo-array), synthesized
- * - [len](./m_path.js.html#ModelPath$len) - returns length of array (or pseudo-array) in model in safe way, 0 if no length is set
- * - [push](./m_path.js.html#ModelPath$push) - add items to the end of array (or pseudo-array) in model
- * - [pop](./m_path.js.html#ModelPath$pop) - remove item from the end of array (or pseudo-array) in model
- * - [unshift](./m_path.js.html#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in model
- * - [shift](./m_path.js.html#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in model
- * - [proxyMessenger](#proxyMessenger) - proxy model's Messenger methods to host object
- * - [proxyMethods](#proxyMethods) - proxy model methods to host object
- */
-_.extendProto(Model, {
- path: Model$path,
- get: Model$get,
- proxyMessenger: proxyMessenger, // deprecated, should not be used
- proxyMethods: proxyMethods,
- _prepareMessengers: _prepareMessengers,
- _getHostObject: _getHostObject,
- destroy: Model$destroy
-});
-
-// set, del, splice are added to model
-_.extendProto(Model, synthesize.modelMethods);
-
-
-/**
- * - Path: ModelPath class as `milo.Model.Path`
- */
-_.extend(Model, {
- Path: ModelPath,
- useWith: Model$$useWith
-});
-
-
-/**
- * Expose Messenger methods on Facet prototype
- */
-var MESSENGER_PROPERTY = '_messenger';
-Messenger.useWith(Model, MESSENGER_PROPERTY, Messenger.defaultMethods);
-
-
-/**
- * ModelPath methods added to Model prototype
- */
-['len', 'push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {
- var method = ModelPath.prototype[methodName];
- _.defineProperty(Model.prototype, methodName, method);
-});
-
-
-/**
- * Model instance method.
- * Get model data.
- *
- * @return {Any}
- */
-function Model$get() {
- return this._data;
-}
-
-
-/**
- * Model instance method.
- * Returns ModelPath object that implements the same API as model but allows access to any point inside model as defined by `accessPath`.
- * See [ModelPath](./m_path.js.html) class for more information.
- *
- * @param {String} accessPath string that defines path to access model.
- * Path string consists of parts to define either property access (`".name"` to access property name) or array item access (`"[1]"` to access item with index 1).
- * Access path can contain as many parts as necessary (e.g. `".list[0].name"` to access property `name` in the first element of array stored in property `list`.
- * @param {List} arguments additional arguments of this method can be used to create interpolated paths.
- * E.g. `m.path("[$1].$2", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m("[" + id + "]." + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.
- * @return {ModelPath}
- */
-function Model$path(accessPath) { // , ... arguments that will be interpolated
- if (! accessPath) return this;
-
- // "null" is context to pass to ModelPath, first parameter of bind
- // "this" (model) is added in front of all arguments
- _.splice(arguments, 0, 0, null, this);
-
- // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...
- return new (Function.prototype.bind.apply(ModelPath, arguments));
-}
-
-
-/**
- * Model instance method.
- * Proxy model's Messenger methods to host object.
- *
- * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.
- */
-function proxyMessenger(modelHostObject) {
- modelHostObject = modelHostObject || this._hostObject;
- Mixin.prototype._createProxyMethods.call(this[MESSENGER_PROPERTY], Messenger.defaultMethods, modelHostObject);
-}
-
-
-var modelMethodsToProxy = ['path', 'get', 'set', 'del', 'splice', 'len', 'push', 'pop', 'unshift', 'shift'];
-
-
-/**
- * Expose model methods on
- * See same method in Mixin class for parameters meaning
- *
- * @param {Function} hostClass
- * @param {[type]} instanceKey
- * @param {[type]} mixinMethods optional
- */
-function Model$$useWith(hostClass, instanceKey, mixinMethods) {
- mixinMethods = mixinMethods || modelMethodsToProxy;
- Mixin.useWith.call(Model, hostClass, instanceKey, mixinMethods);
-}
-
-
-/**
- * Model instance method.
- * Proxy model methods to host object.
- *
- * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.
- */
-function proxyMethods(modelHostObject) {
- modelHostObject = modelHostObject || this._hostObject;
- Mixin.prototype._createProxyMethods.call(this, modelMethodsToProxy, modelHostObject);
-}
-
-
-/**
- * Model instance method.
- * Create and connect internal and external model's messengers.
- * External messenger's methods are proxied on the model and they allows "*" subscriptions.
- */
-function _prepareMessengers() {
- // model will post all its changes on internal messenger
- var internalMessenger = new Messenger(this, undefined, undefined);
-
- // message source to connect internal messenger to external
- var internalMessengerSource = new MessengerMessageSource(this, undefined, new ModelMsgAPI, internalMessenger);
-
- // external messenger to which all model users will subscribe,
- // that will allow "*" subscriptions and support "changedata" message api.
- var externalMessenger = new Messenger(this, undefined, internalMessengerSource);
-
- _.defineProperty(this, MESSENGER_PROPERTY, externalMessenger);
- _.defineProperty(this, '_internalMessenger', internalMessenger);
-}
-
-
-function _getHostObject() {
- return this._hostObject;
-}
-
-
-function Model$destroy() {
- this[MESSENGER_PROPERTY].destroy();
- this._internalMessenger.destroy();
- this._destroyed = true;
-}
-
-},{"../abstract/mixin":116,"../messenger":119,"../messenger/msngr_source":123,"../util/check":135,"../util/logger":137,"./change_data":126,"./m_msg_api":129,"./m_path":130,"./path_utils":133,"./synthesize":134,"mol-proto":141}],129:[function(require,module,exports){
-arguments[4][75][0].apply(exports,arguments)
-},{"../messenger/m_api_rx":121,"./path_utils":133,"mol-proto":141}],130:[function(require,module,exports){
-arguments[4][76][0].apply(exports,arguments)
-},{"../messenger":119,"../messenger/msngr_source":123,"../util/check":135,"./change_data":126,"./path_msg_api":132,"./path_utils":133,"./synthesize":134,"mol-proto":141}],131:[function(require,module,exports){
-module.exports=require(77)
-},{}],132:[function(require,module,exports){
-arguments[4][78][0].apply(exports,arguments)
-},{"../messenger/m_api":120,"../util/logger":137,"./path_utils":133,"mol-proto":141}],133:[function(require,module,exports){
-'use strict';
-
-//
-// ### model path utils
-
-var check = require('../util/check')
- , Match = check.Match
- , _ = require('mol-proto');
-
-var pathUtils = {
- parseAccessPath: parseAccessPath,
- createRegexPath: createRegexPath,
- getPathNodeKey: getPathNodeKey,
- wrapMessengerMethods: wrapMessengerMethods
-};
-
-module.exports = pathUtils;
-
-
-var propertyPathSyntax = '\\.[A-Za-z_-][A-Za-z0-9_-]*'
- , arrayPathSyntax = '\\[[0-9]+\\]'
- , interpolationSyntax = '\\$[1-9][0-9]*'
- , propertyInterpolateSyntax = '\\.' + interpolationSyntax
- , arrayInterpolateSyntax = '\\[' + interpolationSyntax + '\\]'
-
- , propertyStarSyntax = '\\.\\*'
- , arrayStarSyntax = '\\[\\*\\]'
- , starSyntax = '\\*'
-
- , pathParseSyntax = [
- propertyPathSyntax,
- arrayPathSyntax,
- propertyInterpolateSyntax,
- arrayInterpolateSyntax
- ].join('|')
- , pathParsePattern = new RegExp(pathParseSyntax, 'g')
-
- , patternPathParseSyntax = [
- pathParseSyntax,
- propertyStarSyntax,
- arrayStarSyntax,
- starSyntax
- ].join('|')
- , patternPathParsePattern = new RegExp(patternPathParseSyntax, 'g')
-
- //, targetPathParsePattern = /\.[A-Za-z][A-Za-z0-9_]*|\[[0-9]+\]|\.\$[1-9][0-9]*|\[\$[1-9][0-9]*\]|\$[1-9][0-9]/g
- , pathNodeTypes = {
- '.': { syntax: 'object', empty: '{}' },
- '[': { syntax: 'array', empty: '[]'},
- '*': { syntax: 'match', empty: '{}'},
- };
-
-function parseAccessPath(path, nodeParsePattern) {
- nodeParsePattern = nodeParsePattern || pathParsePattern;
-
- var parsedPath = [];
-
- if (! path)
- return parsedPath;
-
- var unparsed = path.replace(nodeParsePattern, function(nodeStr) {
- var pathNode = { property: nodeStr };
- _.extend(pathNode, pathNodeTypes[nodeStr[0]]);
- if (nodeStr[1] == '$')
- pathNode.interpolate = getPathNodeKey(pathNode, true);
-
- parsedPath.push(pathNode);
- return '';
- });
- if (unparsed)
- throw new Error('incorrect model path: ' + path);
-
- return parsedPath;
-}
-
-
-var nodeRegex = {
- '.*': propertyPathSyntax,
- '[*]': arrayPathSyntax
-};
-nodeRegex['*'] = nodeRegex['.*'] + '|' + nodeRegex['[*]'];
-
-function createRegexPath(path) {
- check(path, Match.OneOf(String, RegExp));
-
- if (path instanceof RegExp || path.indexOf('*') == -1)
- return path;
-
- var parsedPath = pathUtils.parseAccessPath(path, patternPathParsePattern)
- , regexStr = '^'
- // , regexStrEnd = ''
- , patternsStarted = false;
-
- parsedPath.forEach(function(pathNode) {
- var prop = pathNode.property
- , regex = nodeRegex[prop];
-
- if (regex) {
- // regexStr += '(' + regex;
- // regexStrEnd += '|)';
- regexStr += '(' + regex + '|)';
- // regexStrEnd += '|)';
- patternsStarted = true;
- } else {
- // if (patternsStarted)
- // throw new Error('"*" path segment cannot be in the middle of the path: ' + path);
- regexStr += prop.replace(/(\.|\[|\])/g, '\\$1'); // add slash in front of symbols that have special meaning in regex
- }
- });
-
- regexStr += /* regexStrEnd + */ '$';
-
- try {
- return new RegExp(regexStr);
- } catch (e) {
- throw new Error('can\'t construct regex for path pattern: ' + path);
- }
-}
-
-
-function getPathNodeKey(pathNode, interpolated) {
- var prop = pathNode.property
- , startIndex = interpolated ? 2 : 1;
- return pathNode.syntax == 'array'
- ? prop.slice(startIndex, prop.length - 1)
- : prop.slice(startIndex);
-}
-
-
-// TODO allow for multiple messages in a string
-function wrapMessengerMethods(methodsNames) {
- methodsNames = methodsNames || ['on', 'off'];
- var wrappedMethods = _.mapToObject(methodsNames, function(methodName) {
- var origMethod = this[methodName];
- // replacing message subsribe/unsubscribe/etc. to convert "*" message patterns to regexps
- return function(path, subscriber) {
- var regexPath = createRegexPath(path);
- origMethod.call(this, regexPath, subscriber);
- };
- }, this);
- _.defineProperties(this, wrappedMethods);
-}
-
-},{"../util/check":135,"mol-proto":141}],134:[function(require,module,exports){
-'use strict';
-
-var pathUtils = require('../path_utils')
- , modelUtils = require('../model_utils')
- , logger = require('../../util/logger')
- , fs = require('fs')
- , doT = require('dot')
- , _ = require('mol-proto')
- , changeDataHandler = require('../change_data')
- , getTransactionFlag = changeDataHandler.getTransactionFlag
- , postTransactionFinished = changeDataHandler.postTransactionFinished;
-
-
-/**
- * Templates to synthesize model getters and setters
- */
-var templates = {
- get: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\nmethod = function get() {\n var m = {{# def.modelAccessPrefix }};\n return m {{~ it.parsedPath :pathNode }}\n {{? pathNode.interpolate}}\n && (m = m[this._args[ {{= pathNode.interpolate }} ]])\n {{??}}\n && (m = m{{= pathNode.property }})\n {{?}} {{~}};\n};\n",
- set: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n{{# def.include_defines }}\n{{# def.include_create_tree }}\n\n\n/**\n * Template that synthesizes setter for Model and for ModelPath\n */\nmethod = function set(value) {\n {{# def.initVars:'set' }}\n\n {{# def.createTree:'set' }}\n\n {{\n currNode = nextNode;\n currProp = currNode && currNode.property;\n }}\n\n {{ /* assign value to the last property */ }}\n {{? currProp }}\n wasDef = {{# def.wasDefined}};\n {{# def.changeAccessPath }}\n\n var old = m{{# def.currProp }};\n\n {{ /* clone value to prevent same reference in linked models */ }}\n m{{# def.currProp }} = cloneTree(value);\n {{?}}\n\n {{ /* add message related to the last property change */ }}\n if (this._options.reactive !== false) {\n if (! wasDef)\n {{# def.addMsg }} accessPath, type: 'added',\n newValue: value });\n else if (old != value)\n {{# def.addMsg }} accessPath, type: 'changed',\n oldValue: old, newValue: value });\n\n {{ /* add message related to changes in (sub)properties inside removed and assigned value */ }}\n if (! wasDef || old != value)\n addTreeChangesMessages(messages, messagesHash,\n accessPath, old, value); /* defined in the function that synthesizes ModelPath setter */\n\n {{ /* post all stored messages */ }}\n {{# def.postMessages }}\n }\n};\n",
- del: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n{{# def.include_defines }}\n{{# def.include_traverse_tree }}\n\nmethod = function del() {\n {{# def.initVars:'del' }}\n\n {{? it.parsedPath.length }}\n {{# def.traverseTree }}\n\n {{\n var currNode = it.parsedPath[count];\n var currProp = currNode.property; \n }}\n\n if (! treeDoesNotExist && m && m.hasOwnProperty && {{# def.wasDefined}}) {\n var old = m{{# def.currProp }};\n delete m{{# def.currProp }};\n {{# def.changeAccessPath }}\n var didDelete = true;\n }\n {{??}}\n if (typeof m != 'undefined') {\n var old = m;\n {{# def.modelAccessPrefix }} = undefined;\n var didDelete = true;\n }\n {{?}}\n\n if (didDelete && this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'deleted', oldValue: old });\n\n addTreeChangesMessages(messages, messagesHash,\n accessPath, old, undefined); /* defined in the function that synthesizes ModelPath setter */\n\n {{ /* post all stored messages */ }}\n {{# def.postMessages }}\n }\n};\n",
- splice: "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n{{# def.include_defines }}\n{{# def.include_create_tree }}\n{{# def.include_traverse_tree }}\n\nmethod = function splice(spliceIndex, spliceHowMany) { /* ,... - extra arguments to splice into array */\n {{# def.initVars:'splice' }}\n\n var argsLen = arguments.length;\n var addItems = argsLen > 2;\n\n if (addItems) {\n {{ /* only create model tree if items are inserted in array */ }}\n\n {{ /* if model is undefined it will be set to an empty array */ }} \n var value = [];\n {{# def.createTree:'splice' }}\n\n {{? nextNode }}\n {{\n var currNode = nextNode;\n var currProp = currNode.property;\n var emptyProp = '[]';\n }}\n\n {{# def.createTreeStep }}\n {{?}}\n\n } else if (spliceHowMany > 0) {\n {{ /* if items are not inserted, only traverse model tree if items are deleted from array */ }}\n {{? it.parsedPath.length }}\n {{# def.traverseTree }}\n\n {{\n var currNode = it.parsedPath[count];\n var currProp = currNode.property; \n }}\n\n {{ /* extra brace closes 'else' in def.traverseTreeStep */ }}\n {{# def.traverseTreeStep }} }\n {{?}}\n }\n\n {{ /* splice items */ }}\n if (addItems || (! treeDoesNotExist && m\n && m.length > spliceIndex ) ) {\n var oldLength = m.length = m.length || 0;\n\n arguments[0] = spliceIndex = normalizeSpliceIndex(spliceIndex, m.length);\n\n {{ /* clone added arguments to prevent same references in linked models */ }}\n if (addItems)\n for (var i = 2; i < argsLen; i++)\n arguments[i] = cloneTree(arguments[i]);\n\n {{ /* actual splice call */ }}\n var removed = Array.prototype.splice.apply(m, arguments);\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'splice',\n index: spliceIndex, removed: removed, addedCount: addItems ? argsLen - 2 : 0,\n newValue: m });\n\n if (removed && removed.length)\n removed.forEach(function(item, index) {\n var itemPath = accessPath + '[' + (spliceIndex + index) + ']';\n {{# def.addMsg }} itemPath, type: 'removed', oldValue: item });\n\n if (valueIsTree(item))\n addMessages(messages, messagesHash, itemPath, item, 'removed', 'oldValue');\n });\n\n if (addItems)\n for (var i = 2; i < argsLen; i++) {\n var item = arguments[i];\n var itemPath = accessPath + '[' + (spliceIndex + i - 2) + ']';\n {{# def.addMsg }} itemPath, type: 'added', newValue: item });\n\n if (valueIsTree(item))\n addMessages(messages, messagesHash, itemPath, item, 'added', 'newValue');\n }\n\n {{ /* post all stored messages */ }}\n {{# def.postMessages }}\n }\n }\n\n return removed || [];\n}\n"
-};
-
-var include_defines = "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n/**\n * Inserts initialization code\n */\n {{## def.initVars:method:\n var m = {{# def.modelAccessPrefix }};\n var messages = [], messagesHash = {};\n var accessPath = '';\n var treeDoesNotExist;\n /* hack to prevent sending finished events to allow for propagation of batches without splitting them */\n var inChangeTransaction = getTransactionFlag( {{= method }} );\n #}}\n\n/**\n * Inserts the beginning of function call to add message to list\n */\n{{## def.addMsg: addChangeMessage(messages, messagesHash, { path: #}}\n\n/**\n * Inserts current property/index for both normal and interpolated properties/indexes\n */\n{{## def.currProp:{{? currNode.interpolate }}[this._args[ {{= currNode.interpolate }} ]]{{??}}{{= currProp }}{{?}} #}}\n\n/**\n * Inserts condition to test whether normal/interpolated property/index exists\n */\n{{## def.wasDefined: m.hasOwnProperty(\n {{? currNode.interpolate }}\n this._args[ {{= currNode.interpolate }} ]\n {{??}}\n '{{= it.getPathNodeKey(currNode) }}'\n {{?}}\n) #}}\n\n\n/**\n * Inserts code to update access path for current property\n * Because of the possibility of interpolated properties, it can't be calculated in template, it can only be calculated during accessor call.\n */\n{{## def.changeAccessPath:\n accessPath += {{? currNode.interpolate }}\n {{? currNode.syntax == 'array' }}\n '[' + this._args[ {{= currNode.interpolate }} ] + ']';\n {{??}}\n '.' + this._args[ {{= currNode.interpolate }} ];\n {{?}}\n {{??}}\n '{{= currProp }}';\n {{?}}\n#}}\n\n\n/**\n * Inserts code to post stored messages\n */\n{{## def.postMessages:\n if (messages.length) {\n {{# def.modelPostBatchCode }}('datachanges', {\n changes: messages,\n transaction: inChangeTransaction\n });\n\n messages.forEach(function(msg) {\n {{# def.modelPostMessageCode }}(msg.path, msg);\n }, this);\n }\n#}}\n"
- , include_create_tree = "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n/**\n * Inserts code to create model tree as neccessary for `set` and `splice` accessors and to add messages to send list if the tree changes.\n */\n{{## def.createTree:method:\n var wasDef = true;\n var old = m;\n\n {{ var emptyProp = it.parsedPath[0] && it.parsedPath[0].empty; }}\n {{? emptyProp }}\n {{ /* create top level model if it was not previously defined */ }}\n if (! m) {\n m = {{# def.modelAccessPrefix }} = {{= emptyProp }};\n wasDef = false;\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} '', type: 'added',\n newValue: m });\n }\n }\n {{??}}\n {{? method == 'splice' }}\n if (! m) {\n {{?}}\n m = {{# def.modelAccessPrefix }} = cloneTree(value);\n wasDef = typeof old != 'undefined';\n {{? method == 'splice' }}\n }\n {{?}} \n {{?}}\n\n\n {{ /* create model tree if it doesn't exist */ }}\n {{ var modelDataProperty = '';\n var nextNode = it.parsedPath[0];\n var count = it.parsedPath.length - 1;\n\n for (var i = 0; i < count; i++) {\n var currNode = nextNode;\n var currProp = currNode.property;\n nextNode = it.parsedPath[i + 1];\n var emptyProp = nextNode && nextNode.empty;\n }}\n\n {{# def.createTreeStep }}\n\n {{ } /* for loop */ }}\n#}}\n\n\n/**\n * Inserts code to create one step in the model tree\n */\n{{## def.createTreeStep:\n {{# def.changeAccessPath }}\n\n if (! {{# def.wasDefined }}) { \n {{ /* property does not exist */ }}\n m = m{{# def.currProp }} = {{= emptyProp }};\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'added', \n newValue: m });\n }\n\n } else if (typeof m{{# def.currProp }} != 'object') {\n {{ /* property is not object */ }}\n var old = m{{# def.currProp }};\n m = m{{# def.currProp }} = {{= emptyProp }};\n\n if (this._options.reactive !== false) {\n {{# def.addMsg }} accessPath, type: 'changed', \n oldValue: old, newValue: m });\n }\n\n } else {\n {{ /* property exists, just traverse down the model tree */ }}\n m = m{{# def.currProp }};\n }\n#}}\n"
- , include_traverse_tree = "'use strict';\n/* Only use this style of comments, not \"//\" */\n\n/**\n * Inserts code to traverse model tree for `delete` and `splice` accessors.\n */\n{{## def.traverseTree:\n {{ \n var count = it.parsedPath.length-1;\n\n for (var i = 0; i < count; i++) { \n var currNode = it.parsedPath[i];\n var currProp = currNode.property;\n }}\n {{# def.traverseTreeStep }}\n\n {{ } /* for loop */\n\n var i = count;\n while (i--) { /* closing braces for else's above */\n }}\n }\n {{ } /* while loop */ }}\n#}}\n\n\n/**\n * Inserts code to traverse one step in the model tree\n */\n{{## def.traverseTreeStep:\n if (! (m && m.hasOwnProperty && {{# def.wasDefined}} ) )\n treeDoesNotExist = true;\n else {\n m = m{{# def.currProp }};\n {{# def.changeAccessPath }}\n {{ /* brace from else is not closed on purpose - all braces are closed in while loop */ }}\n#}}\n";
-
-var dotDef = {
- include_defines: include_defines,
- include_create_tree: include_create_tree,
- include_traverse_tree: include_traverse_tree,
- getPathNodeKey: pathUtils.getPathNodeKey,
- modelAccessPrefix: 'this._model._data',
- modelPostMessageCode: 'this._model._internalMessenger.postMessage',
- modelPostBatchCode: 'this._model.postMessageSync',
- internalMessenger: 'this._model._internalMessenger'
-};
-
-var modelDotDef = _(dotDef).clone().extend({
- modelAccessPrefix: 'this._data',
- modelPostMessageCode: 'this._internalMessenger.postMessage',
- modelPostBatchCode: 'this.postMessageSync',
- internalMessenger: 'this._internalMessenger'
-})._();
-
-
-var dotSettings = _.clone(doT.templateSettings);
-dotSettings.strip = false;
-
-var synthesizers = _.mapKeys(templates, function(tmpl) {
- return doT.template(tmpl, dotSettings, dotDef);
-});
-
-
-var modelSynthesizers = _.mapToObject(['set', 'del', 'splice'], function(methodName) {
- return doT.template(templates[methodName], dotSettings, modelDotDef);
-});
-
-
-/**
- * Function that synthesizes accessor methods.
- * Function is memoized so accessors are cached (up to 1000).
- *
- * @param {String} path Model/ModelPath access path
- * @param {Array} parsedPath array of path nodes
- * @return {Object[Function]}
- */
-var synthesizePathMethods = _.memoize(_synthesizePathMethods, undefined, 1000);
-
-function _synthesizePathMethods(path, parsedPath) {
- var methods = _.mapKeys(synthesizers, function(synthszr) {
- return _synthesize(synthszr, path, parsedPath);
- });
- return methods;
-}
-
-
-var normalizeSpliceIndex = modelUtils.normalizeSpliceIndex; // used in splice.dot.js
-
-
-function _synthesize(synthesizer, path, parsedPath) {
- var method
- , methodCode = synthesizer({
- parsedPath: parsedPath,
- getPathNodeKey: pathUtils.getPathNodeKey
- });
-
- try {
- eval(methodCode);
- } catch (e) {
- throw ModelError('ModelPath method compilation error; path: ' + path + ', code: ' + methodCode);
- }
-
- return method;
-
-
- // functions used by methods `set`, `delete` and `splice` (synthesized by template)
- function addChangeMessage(messages, messagesHash, msg) {
- messages.push(msg);
- messagesHash[msg.path] = msg;
- }
-
- function addTreeChangesMessages(messages, messagesHash, rootPath, oldValue, newValue) {
- var oldIsTree = valueIsTree(oldValue)
- , newIsTree = valueIsTree(newValue);
-
- if (newIsTree)
- addMessages(messages, messagesHash, rootPath, newValue, 'added', 'newValue');
-
- if (oldIsTree)
- addMessages(messages, messagesHash, rootPath, oldValue, 'removed', 'oldValue');
- }
-
- function addMessages(messages, messagesHash, rootPath, obj, msgType, valueProp) {
- _addMessages(rootPath, obj);
-
-
- function _addMessages(rootPath, obj) {
- if (Array.isArray(obj)) {
- var pathSyntax = rootPath + '[$$]';
- obj.forEach(function(value, index) {
- addMessage(value, index, pathSyntax);
- });
- } else {
- var pathSyntax = rootPath + '.$$';
- _.eachKey(obj, function(value, key) {
- addMessage(value, key, pathSyntax);
- });
- }
- }
-
- function addMessage(value, key, pathSyntax) {
- var path = pathSyntax.replace('$$', key)
- , existingMsg = messagesHash[path];
-
- if (existingMsg) {
- if (existingMsg.type == msgType)
- logger.error('setter error: same message type posted on the same path');
- else {
- existingMsg.type = 'changed';
- existingMsg[valueProp] = value;
- }
- } else {
- var msg = { path: path, type: msgType };
- msg[valueProp] = value;
- addChangeMessage(messages, messagesHash, msg);
- }
-
- if (valueIsTree(value))
- _addMessages(path, value);
- }
- }
-
- function cloneTree(value) {
- return valueIsNormalObject(value)
- ? _.deepClone(value)
- : value;
- }
-
- function protectValue(value) {
- return ! valueIsNormalObject(value)
- ? value
- : Array.isArray(value)
- ? value.slice()
- : Object.create(value);
- }
-
- function valueIsTree(value) {
- return valueIsNormalObject(value)
- && Object.keys(value).length;
- }
-
- function valueIsNormalObject(value) {
- return value != null
- && typeof value == "object"
- && ! (value instanceof Date)
- && ! (value instanceof RegExp);
- }
-
- function addBatchIdsToMessage(msg, batchId, msgId) {
- _.defineProperties(msg, {
- __batch_id: batchId,
- __msg_id: msgId
- });
- }
-}
-
-
-/**
- * Exports `synthesize` function with the following:
- *
- * - .modelMethods.set - `set` method for Model
- * - .modelMethods.del - `del` method for Model
- * - .modelMethods.splice - `splice` method for Model
- */
-module.exports = synthesizePathMethods;
-
-var modelMethods = _.mapKeys(modelSynthesizers, function(synthesizer) {
- return _synthesize(synthesizer, '', []);
-});
-
-synthesizePathMethods.modelMethods = modelMethods;
-
-},{"../../util/logger":137,"../change_data":126,"../model_utils":131,"../path_utils":133,"dot":140,"fs":113,"mol-proto":141}],135:[function(require,module,exports){
-arguments[4][90][0].apply(exports,arguments)
-},{"../config":118,"mol-proto":141}],136:[function(require,module,exports){
-'use strict';
-
-/**
- * `milo.util`
- */
-var util = {
- logger: require('./logger'),
- check: require('./check'),
+ for( k = 0, l = sources.length; k < l; k++) {
+ name = sources[k];
+ if (/\.dot(\.def|\.jst)?$/.test(name)) {
+ console.log("Compiling " + name + " to function");
+ this.__rendermodule[name.substring(0, name.indexOf('.'))] = this.compilePath(defFolder + name);
+ }
+ if (/\.jst(\.dot|\.def)?$/.test(name)) {
+ console.log("Compiling " + name + " to file");
+ this.compileToFile(this.__destination + name.substring(0, name.indexOf('.')) + '.js',
+ readdata(defFolder + name));
+ }
+ }
+ return this.__rendermodule;
};
-module.exports = util;
-
-},{"./check":135,"./logger":137}],137:[function(require,module,exports){
-arguments[4][102][0].apply(exports,arguments)
-},{"./logger_class":138}],138:[function(require,module,exports){
-arguments[4][103][0].apply(exports,arguments)
-},{"mol-proto":141}],139:[function(require,module,exports){
-module.exports=require(114)
-},{}],140:[function(require,module,exports){
-module.exports=require(115)
-},{"./doT":139,"fs":113}],141:[function(require,module,exports){
+},{"./doT":120,"fs":96}],122:[function(require,module,exports){
'use strict';
var utils = require('./utils');
@@ -19032,7 +17168,7 @@ if (typeof module == 'object' && module.exports)
// export for node/browserify
module.exports = Proto;
-},{"./proto_array":142,"./proto_function":143,"./proto_number":144,"./proto_object":145,"./proto_prototype":146,"./proto_string":147,"./proto_util":148,"./utils":149}],142:[function(require,module,exports){
+},{"./proto_array":123,"./proto_function":124,"./proto_number":125,"./proto_object":126,"./proto_prototype":127,"./proto_string":128,"./proto_util":129,"./utils":130}],123:[function(require,module,exports){
'use strict';
var __ = require('./proto_object')
@@ -19266,7 +17402,7 @@ function deepForEach(callback, thisArg) {
}
}
-},{"./proto_object":145,"./utils":149}],143:[function(require,module,exports){
+},{"./proto_object":126,"./utils":130}],124:[function(require,module,exports){
'use strict';
@@ -19659,7 +17795,7 @@ function not() {
};
}
-},{"./proto_util":148,"./utils":149}],144:[function(require,module,exports){
+},{"./proto_util":129,"./utils":130}],125:[function(require,module,exports){
'use strict';
/**
@@ -19680,7 +17816,7 @@ function isNumeric() {
return !isNaN(parseFloat(this)) && isFinite(this);
};
-},{}],145:[function(require,module,exports){
+},{}],126:[function(require,module,exports){
'use strict';
@@ -20315,7 +18451,7 @@ function isNot(obj) {
return !isEqual.call(this, obj);
}
-},{"./utils":149}],146:[function(require,module,exports){
+},{"./utils":130}],127:[function(require,module,exports){
'use strict';
/**
@@ -20446,7 +18582,7 @@ function newApply(args) {
return new (Function.prototype.bind.apply(this, args));
}
-},{"./proto_function":143,"./proto_object":145}],147:[function(require,module,exports){
+},{"./proto_function":124,"./proto_object":126}],128:[function(require,module,exports){
'use strict';
@@ -20633,7 +18769,7 @@ function unPrefix(str) {
return this.replace(str, '');
}
-},{"./proto_object":145}],148:[function(require,module,exports){
+},{"./proto_object":126}],129:[function(require,module,exports){
'use strict';
/**
@@ -20765,7 +18901,7 @@ function compareProperty() {
*/
function noop() {}
-},{}],149:[function(require,module,exports){
+},{}],130:[function(require,module,exports){
'use strict';
var utils = module.exports = {
@@ -20830,24 +18966,6 @@ function makeFindMethod(eachMethod, findWhat) {
}
}
-},{}],150:[function(require,module,exports){
-arguments[4][141][0].apply(exports,arguments)
-},{"./proto_array":151,"./proto_function":152,"./proto_number":153,"./proto_object":154,"./proto_prototype":155,"./proto_string":156,"./proto_util":157,"./utils":158}],151:[function(require,module,exports){
-arguments[4][142][0].apply(exports,arguments)
-},{"./proto_object":154,"./utils":158}],152:[function(require,module,exports){
-module.exports=require(143)
-},{"./proto_util":157,"./utils":158}],153:[function(require,module,exports){
-module.exports=require(144)
-},{}],154:[function(require,module,exports){
-module.exports=require(145)
-},{"./utils":158}],155:[function(require,module,exports){
-arguments[4][146][0].apply(exports,arguments)
-},{"./proto_function":152,"./proto_object":154}],156:[function(require,module,exports){
-arguments[4][147][0].apply(exports,arguments)
-},{"./proto_object":154}],157:[function(require,module,exports){
-module.exports=require(148)
-},{}],158:[function(require,module,exports){
-module.exports=require(149)
-},{}]},{},[72])
-//@ sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvYWJzdHJhY3QvZmFjZXQuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2Fic3RyYWN0L2ZhY2V0ZWRfb2JqZWN0LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9hYnN0cmFjdC9taXhpbi5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvYWJzdHJhY3QvcmVnaXN0cnkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2F0dHJpYnV0ZXMvYV9iaW5kLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9hdHRyaWJ1dGVzL2FfY2xhc3MuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2F0dHJpYnV0ZXMvYV9sb2FkLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9hdHRyaWJ1dGVzL2luZGV4LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9iaW5kZXIuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NsYXNzZXMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbW1hbmQvYWN0aW9uc19oaXN0b3J5LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21tYW5kL2NtZF9yZWdpc3RyeS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tbWFuZC9pbmRleC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tbWFuZC90cmFuc2FjdGlvbi5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tbWFuZC90cmFuc2FjdGlvbl9oaXN0b3J5LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfY2xhc3MuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19mYWNldC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX2ZhY2V0cy9Db250YWluZXIuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19mYWNldHMvRGF0YS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX2ZhY2V0cy9Eb20uanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19mYWNldHMvRHJhZy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX2ZhY2V0cy9Ecm9wLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL0V2ZW50cy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX2ZhY2V0cy9GcmFtZS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX2ZhY2V0cy9JdGVtLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL0xpc3QuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19mYWNldHMvTW9kZWxGYWNldC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX2ZhY2V0cy9PcHRpb25zLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL1RlbXBsYXRlLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL1RyYW5zZmVyLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL2NmX3JlZ2lzdHJ5LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfaW5mby5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX3JlZ2lzdHJ5LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfdXRpbHMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY2xhc3Nlcy9WaWV3LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL21zZ19hcGkvZGF0YS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9tc2dfYXBpL2RlX2RhdGEuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvbXNnX2FwaS9kcm9wLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL21zZ19zcmMvZG9tX2V2ZW50cy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9tc2dfc3JjL2ZyYW1lLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3Njb3BlLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0J1dHRvbi5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9Db21iby5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9Db21ib0xpc3QuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvRGF0ZS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9Ecm9wVGFyZ2V0LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0ZvbGRUcmVlLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0dyb3VwLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0h5cGVybGluay5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9JbWFnZS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9JbnB1dC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9JbnB1dExpc3QuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvTGlzdC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9MaXN0SXRlbS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9SYWRpb0dyb3VwLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL1NlbGVjdC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9TdXBlckNvbWJvLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL1RleHQuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvVGV4dGFyZWEuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvVGltZS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9XcmFwcGVyLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL2Jvb3RzdHJhcC9BbGVydC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9ib290c3RyYXAvRGlhbG9nLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL2Jvb3RzdHJhcC9Ecm9wZG93bi5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29uZmlnLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9sb2FkZXIuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL21lc3Nlbmdlci9pbmRleC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvbWVzc2VuZ2VyL21fYXBpLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9tZXNzZW5nZXIvbV9hcGlfcnguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL21lc3Nlbmdlci9tX3NvdXJjZS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvbWVzc2VuZ2VyL21zbmdyX3NvdXJjZS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvbWlsby5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvbW9kZWwvY2hhbmdlX2RhdGEuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL21vZGVsL2luZGV4LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9tb2RlbC9tX21zZ19hcGkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL21vZGVsL21fcGF0aC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvbW9kZWwvbW9kZWxfdXRpbHMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL21vZGVsL3BhdGhfbXNnX2FwaS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvbW9kZWwvcGF0aF91dGlscy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvbW9kZWwvc3ludGhlc2l6ZS9pbmRleC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvcmVnaXN0cnkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL2RlX2NvbnN0cnMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL2RvbV9zb3VyY2UuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL21haWwvaW5kZXguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL21haWwvbWFpbF9hcGkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL21haWwvbWFpbF9zb3VyY2UuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL3dpbmRvdy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXNlX2NvbXBvbmVudHMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3VzZV9mYWNldHMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvY2hlY2suanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvY29tcG9uZW50X25hbWUuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvY291bnQuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvY3JlYXRlX2NvbXBvbmVudF9jbGFzcy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9kb20uanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvZG9tX2xpc3RlbmVycy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9kb21yZWFkeS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9kcmFnZHJvcC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9lcnJvci5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9mcmFnbWVudC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9pbmRleC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9qc29uX3BhcnNlLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi91dGlsL2xvZ2dlci5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9sb2dnZXJfY2xhc3MuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvcmVxdWVzdC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9zZWxlY3Rpb24vaW5kZXguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvc3RvcmFnZS9pbmRleC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9zdG9yYWdlL21vZGVsLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi91dGlsL3N0b3JhZ2UvbXNnX3NyYy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC93ZWJzb2NrZXQvaW5kZXguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvd2Vic29ja2V0L21zZ19hcGkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvd2Vic29ja2V0L21zZ19zcmMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL2Jhc2UzMi9saWIvYmFzZTMyLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLWJ1aWx0aW5zL2J1aWx0aW4vZnMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL2RvdC9kb1QuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL2RvdC9pbmRleC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9hYnN0cmFjdC9taXhpbi5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9jbGFzc2VzLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL2NvbmZpZy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9tZXNzZW5nZXIvaW5kZXguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvbWVzc2VuZ2VyL21fYXBpLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21lc3Nlbmdlci9tX2FwaV9yeC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9tZXNzZW5nZXIvbV9zb3VyY2UuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvbWVzc2VuZ2VyL21zbmdyX3NvdXJjZS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9taWxvLWNvcmUuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvbWluZGVyLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21vZGVsL2NoYW5nZV9kYXRhLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21vZGVsL2Nvbm5lY3Rvci5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9tb2RlbC9pbmRleC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9tb2RlbC9tX21zZ19hcGkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvbW9kZWwvbV9wYXRoLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21vZGVsL3BhdGhfbXNnX2FwaS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9tb2RlbC9wYXRoX3V0aWxzLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21vZGVsL3N5bnRoZXNpemUvaW5kZXguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvdXRpbC9jaGVjay5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi91dGlsL2luZGV4LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL3V0aWwvbG9nZ2VyLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL3V0aWwvbG9nZ2VyX2NsYXNzLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbm9kZV9tb2R1bGVzL21vbC1wcm90by9saWIvcHJvdG8uanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9ub2RlX21vZHVsZXMvbW9sLXByb3RvL2xpYi9wcm90b19hcnJheS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL25vZGVfbW9kdWxlcy9tb2wtcHJvdG8vbGliL3Byb3RvX2Z1bmN0aW9uLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbm9kZV9tb2R1bGVzL21vbC1wcm90by9saWIvcHJvdG9fbnVtYmVyLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbm9kZV9tb2R1bGVzL21vbC1wcm90by9saWIvcHJvdG9fb2JqZWN0LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbm9kZV9tb2R1bGVzL21vbC1wcm90by9saWIvcHJvdG9fcHJvdG90eXBlLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbm9kZV9tb2R1bGVzL21vbC1wcm90by9saWIvcHJvdG9fc3RyaW5nLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbm9kZV9tb2R1bGVzL21vbC1wcm90by9saWIvcHJvdG9fdXRpbC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL25vZGVfbW9kdWxlcy9tb2wtcHJvdG8vbGliL3V0aWxzLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9tb2wtcHJvdG8vbGliL3Byb3RvLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9tb2wtcHJvdG8vbGliL3Byb3RvX2FycmF5LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9tb2wtcHJvdG8vbGliL3Byb3RvX3Byb3RvdHlwZS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbW9sLXByb3RvL2xpYi9wcm90b19zdHJpbmcuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL01BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbk5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25KQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDck1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3o1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pwQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2TkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25GQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4UUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9JQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOW1CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pwQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9MQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZTQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9JQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM01BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0WEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeHFCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMU1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdmJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25NQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1SUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9JQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2cEJBOztBQ0FBOztBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlLQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdOQTs7QUNBQTs7OztBQ0FBOztBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMU1BOztBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNYQTs7QUNBQTs7Ozs7O0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL01BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeE9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdllBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3puQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0RBOztBQ0FBOzs7Ozs7OztBQ0FBOztBQ0FBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cblxudmFyIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxubW9kdWxlLmV4cG9ydHMgPSBGYWNldDtcblxuXG4vKipcbiAqIGBtaWxvLmNsYXNzZXMuRmFjZXRgXG4gKiBCYXNlIEZhY2V0IGNsYXNzIGlzIGFuIGFuY2VzdG9yIG9mIFtDb21wb25lbnRGYWNldF0oLi4vY29tcG9uZW50cy9jX2ZhY2V0LmpzLmh0bWwpIGNsYXNzLCB0aGUgbWFpbiBidWlsZGluZyBibG9jayBpbiBtaWxvLlxuICogXG4gKiBAcGFyYW0ge0ZhY2V0ZWRPYmplY3R9IG93bmVyIGFuIGluc3RhbmNlIG9mIEZhY2V0ZWRPYmplY3Qgc3ViY2xhc3MgdGhhdCBzdG9yZXMgdGhlIGZhY2V0IG9uIGl0cyBwcm9wZXJ0eSAgd2l0aCB0aGUgc2FtZSBuYW1lIGFzIGBuYW1lYCBwcm9wZXJ0eSBvZiBmYWNldFxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyBvcHRpb25hbCBmYWNldCBjb25maWd1cmF0aW9uLCB1c2VkIGluIHN1YmNsYXNzZXNcbiAqL1xuZnVuY3Rpb24gRmFjZXQob3duZXIsIGNvbmZpZykge1xuICAgIHRoaXMubmFtZSA9IF8uZmlyc3RMb3dlckNhc2UodGhpcy5jb25zdHJ1Y3Rvci5uYW1lKTtcbiAgICB0aGlzLm93bmVyID0gb3duZXI7XG4gICAgdGhpcy5jb25maWcgPSBjb25maWcgfHwge307XG4gICAgdGhpcy5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuLyoqXG4gKiBgaW5pdGAgbWV0aG9kIG9mIHN1YmNsYXNzIHdpbGwgYmUgY2FsbGVkIGJ5IEZhY2V0IGNvbnN0cnVjdG9yLlxuICovXG5fLmV4dGVuZFByb3RvKEZhY2V0LCB7XG4gICAgaW5pdDogZnVuY3Rpb24oKSB7fVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEZhY2V0ID0gcmVxdWlyZSgnLi9mYWNldCcpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBGYWNldEVycm9yID0gcmVxdWlyZSgnLi4vdXRpbC9lcnJvcicpLkZhY2V0O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZhY2V0ZWRPYmplY3Q7XG5cblxuLyoqXG4gKiBgbWlsby5jbGFzc2VzLkZhY2V0ZWRPYmplY3RgXG4gKiBDb21wb25lbnQgY2xhc3MgaXMgYmFzZWQgb24gYW4gYWJzdHJhY3QgYGBgRmFjZXRlZE9iamVjdGBgYCBjbGFzcy4gVGhpcyBjbGFzcyBjYW4gYmUgdXNlZCBpbiBhbnkgc2l0dWF0aW9uIHdoZXJlIG9iamVjdHMgY2FuIGJlIHJlcHJlc2VudGVkIHZpYSBjb2xsZWN0aW9uIG9mIGZhY2V0cyAoYSBmYWNldCBpcyBhbiBvYmplY3Qgb2YgYSBjZXJ0YWluIGNsYXNzLCBpdCBob2xkcyBpdHMgb3duIGNvbmZpZ3VyYXRpb24sIGRhdGEgYW5kIG1ldGhvZHMpLlxuICogSW4gYSB3YXksIFwiZmFjZXRzIHBhdHRlcm5cIiBpcyBhbiBpbnZlcnNpb24gb2YgXCJhZGFwdGVyIHBhdHRlcm5cIiAtIHdoaWxlIHRoZSBsYXR0ZXIgYWxsb3dzIGZpbmRpbmcgYSBjbGFzcy9tZXRob2RzIHRoYXQgaGFzIHNwZWNpZmljIGZ1bmN0aW9uYWxpdHksIGZhY2V0ZWQgb2JqZWN0IGlzIHNpbXBseSBjb25zdHJ1Y3RlZCB0byBoYXZlIHRoZXNlIGZ1bmN0aW9uYWxpdGllcy5cbiAqIFdpdGggdGhpcyBhcmNoaXRlY3R1cmUgaXQgaXMgcG9zc2libGUgdG8gY3JlYXRlIGEgdmlydHVhbGx5IHVubGltaXRlZCBudW1iZXIgb2YgY29tcG9uZW50IGNsYXNzZXMgd2l0aCBhIHZlcnkgbGltaXRlZCBudW1iZXIgb2YgYnVpbGRpbmcgYmxvY2tzIHdpdGhvdXQgaGF2aW5nIGFueSBoaWVyYXJjaHkgb2YgY2xhc3NlcyAtIGFsbCBjb21wb25lbnRzIGluaGVyaXQgZGlyZWN0bHkgZnJvbSBDb21wb25lbnQgY2xhc3MuXG4gKlxuICogVGhpcyBjb25zdHJ1Y3RvciBzaG91bGQgYmUgY2FsbGVkIGJ5IGFsbCBzdWJjbGFzc2VzIGNvbnN0cnVjdG9yIChpdCB3aWxsIGhhcHBlbiBhdXRvbWF0aWNhbGx5IGlmIGEgc3ViY2xhc3MgaXMgY3JlYXRlZCB3aXRoIGBfLmNyZWF0ZVN1YmNsYXNzYCkuXG4gKlxuICogQHJldHVybiB7RmFjZXRlZE9iamVjdH1cbiAqL1xuZnVuY3Rpb24gRmFjZXRlZE9iamVjdCgpIHtcbiAgICAvLyB0aGlzLmZhY2V0c0NvbmZpZyBhbmQgdGhpcy5mYWNldHNDbGFzc2VzIHdlcmUgc3RvcmVkIG9uIGEgc3BlY2lmaWMgY2xhc3MgcHJvdG90eXBlXG4gICAgLy8gd2hlbiB0aGUgY2xhc3Mgd2FzIGNyZWF0ZWQgYnkgRmFjZXRlZE9iamVjdC5jcmVhdGVGYWNldGVkQ2xhc3NcbiAgICB2YXIgZmFjZXRzQ29uZmlnID0gdGhpcy5mYWNldHNDb25maWcgfHwge307XG5cbiAgICB2YXIgZmFjZXRzRGVzY3JpcHRvcnMgPSB7fVxuICAgICAgICAsIGZhY2V0cyA9IHt9O1xuXG4gICAgLy8gRmFjZXRlZE9iamVjdCBjbGFzcyBpdHNlbGYgaXMgbm90IG1lYW50IHRvIGJlIGluc3RhbnRpYXRlZCAtIGl0IGhhcyBubyBmYWNldHNcbiAgICAvLyBJdCBtYXkgY2hhbmdlLCBhcyBhZGRpbmcgZmFjZXRzIGlzIHBvc3NpYmxlIHRvIGluc3RhbmNlc1xuICAgIGlmICh0aGlzLmNvbnN0cnVjdG9yID09IEZhY2V0ZWRPYmplY3QpICAgICAgXG4gICAgICAgIHRocm93IG5ldyBGYWNldEVycm9yKCdGYWNldGVkT2JqZWN0IGlzIGFuIGFic3RyYWN0IGNsYXNzLCBjYW5cXCd0IGJlIGluc3RhbnRpYXRlZCcpO1xuXG4gICAgLy8gaW5zdGFudGlhdGUgY2xhc3MgZmFjZXRzXG4gICAgaWYgKHRoaXMuZmFjZXRzQ2xhc3NlcylcbiAgICAgICAgXy5lYWNoS2V5KHRoaXMuZmFjZXRzQ2xhc3NlcywgaW5zdGFudGlhdGVGYWNldCwgdGhpcywgdHJ1ZSk7XG5cbiAgICAvLyBhZGQgZmFjZXRzIHRvIHRoZSBjbGFzcyBhcyBwcm9wZXJ0aWVzIHVuZGVyIHRoZWlyIG93biBuYW1lXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXModGhpcywgZmFjZXRzRGVzY3JpcHRvcnMpO1xuXG4gICAgLy8gc3RvcmUgYWxsIGZhY2V0cyBvbiBgZmFjZXRzYCBwcm9wZXJ0eSBzbyB0aGF0IHRoZXkgY2FuIGJlIGVudW1lcmF0ZWRcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdmYWNldHMnLCBmYWNldHMpOyAgIFxuXG4gICAgLy8gY2FsbCBgaW5pdGBtZXRob2QgaWYgaXQgaXMgZGVmaW5lZCBpbiBzdWJjbGFzc1xuICAgIGlmICh0aGlzLmluaXQpXG4gICAgICAgIHRoaXMuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXG4gICAgLy8gaW5zdGFudGlhdGUgZmFjZXQgd2l0aCBhIGdpdmVuIGNsYXNzIChGYWNldENsYXNzKSBhbmQgbmFtZSAoZmFjZXROYW1lKVxuICAgIGZ1bmN0aW9uIGluc3RhbnRpYXRlRmFjZXQoRmFjZXRDbGFzcywgZmFjZXROYW1lKSB7XG4gICAgICAgIC8vIGdldCBmYWNldCBjb25maWd1cmF0aW9uXG4gICAgICAgIHZhciBmY3RDb25maWcgPSBmYWNldHNDb25maWdbZmFjZXROYW1lXTtcblxuICAgICAgICAvLyBpbnN0YXRpYXRlIGZhY2V0c1xuICAgICAgICBmYWNldHNbZmFjZXROYW1lXSA9IG5ldyBGYWNldENsYXNzKHRoaXMsIGZjdENvbmZpZyk7XG5cbiAgICAgICAgLy8gYWRkIGZhY2V0IHRvIHByb3BlcnR5IGRlc2NyaXB0b3JzXG4gICAgICAgIGZhY2V0c0Rlc2NyaXB0b3JzW2ZhY2V0TmFtZV0gPSB7XG4gICAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IGZhY2V0c1tmYWNldE5hbWVdXG4gICAgICAgIH07XG4gICAgfVxufVxuXG5cbi8qKlxuICogIyMjI0ZhY2V0ZWRPYmplY3QgY2xhc3MgbWV0aG9kcyMjIyNcbiAqXG4gKiAtIFtjcmVhdGVGYWNldGVkQ2xhc3NdKCNGYWNldGVkT2JqZWN0JCRjcmVhdGVGYWNldGVkQ2xhc3MpXG4gKiAtIFtoYXNGYWNldF0oI0ZhY2V0ZWRPYmplY3QkJGhhc0ZhY2V0KVxuICovXG5fLmV4dGVuZChGYWNldGVkT2JqZWN0LCB7XG4gICAgY3JlYXRlRmFjZXRlZENsYXNzOiBGYWNldGVkT2JqZWN0JCRjcmVhdGVGYWNldGVkQ2xhc3MsXG4gICAgaGFzRmFjZXQ6IEZhY2V0ZWRPYmplY3QkJGhhc0ZhY2V0LFxuICAgIGdldEZhY2V0Q29uZmlnOiBGYWNldGVkT2JqZWN0JCRnZXRGYWNldENvbmZpZ1xufSk7XG5cblxuLyoqXG4gKiAjIyMjRmFjZXRlZE9iamVjdCBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2FkZEZhY2V0XSgjRmFjZXRlZE9iamVjdCRhZGRGYWNldClcbiAqL1xuXy5leHRlbmRQcm90byhGYWNldGVkT2JqZWN0LCB7XG4gICAgYWRkRmFjZXQ6IEZhY2V0ZWRPYmplY3QkYWRkRmFjZXRcbn0pO1xuXG5cbi8qKlxuICogRmFjZXRlZE9iamVjdCBpbnN0YW5jZSBtZXRob2QuXG4gKiBBZGRzIGEgZmFjZXQgdG8gdGhlIGluc3RhbmNlIG9mIEZhY2V0ZWRPYmplY3Qgc3ViY2xhc3MuXG4gKiBSZXR1cm5zIGFuIGluc3RhbmNlIG9mIHRoZSBmYWNldCB0aGF0IHdhcyBjcmVhdGVkLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IEZhY2V0Q2xhc3MgZmFjZXQgY2xhc3MgY29uc3RydWN0b3JcbiAqIEBwYXJhbSB7T2JqZWN0fSBmYWNldENvbmZpZyBvcHRpb25hbCBmYWNldCBjb25maWd1cmF0aW9uXG4gKiBAcGFyYW0ge1N0cmluZ30gZmFjZXROYW1lIG9wdGlvbmFsIGZhY2V0IG5hbWUsIEZhY2V0Q2xhc3MubmFtZSB3aWxsIGJlIHVzZWQgaWYgZmFjZXROYW1lIGlzIG5vdCBwYXNzZWQuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHRocm93T25FcnJvcnMgSWYgc2V0IHRvIGZhbHNlLCB0aGVuIGVycm9ycyB3aWxsIG9ubHkgYmUgbG9nZ2VkIHRvIGNvbnNvbGUuIFRydWUgYnkgZGVmYXVsdC5cbiAqIEByZXR1cm4ge0ZhY2V0fVxuICovXG5mdW5jdGlvbiBGYWNldGVkT2JqZWN0JGFkZEZhY2V0KEZhY2V0Q2xhc3MsIGZhY2V0Q29uZmlnLCBmYWNldE5hbWUsIHRocm93T25FcnJvcnMpIHtcbiAgICBjaGVjayhGYWNldENsYXNzLCBGdW5jdGlvbik7XG4gICAgY2hlY2soZmFjZXROYW1lLCBNYXRjaC5PcHRpb25hbChTdHJpbmcpKTtcblxuICAgIC8vIGZpcnN0IGxldHRlciBvZiBmYWNldCBuYW1lIHNob3VsZCBiZSBsb3dlcmNhc2VcbiAgICBmYWNldE5hbWUgPSBfLmZpcnN0TG93ZXJDYXNlKGZhY2V0TmFtZSB8fCBGYWNldENsYXNzLm5hbWUpO1xuXG4gICAgLy8gZ2V0IGZhY2V0cyBkZWZpbmVkIGluIGNsYXNzXG4gICAgdmFyIHByb3RvRmFjZXRzID0gdGhpcy5jb25zdHJ1Y3Rvci5wcm90b3R5cGUuZmFjZXRzQ2xhc3NlcztcblxuICAgIC8vIGNoZWNrIHRoYXQgdGhpcyBmYWNldE5hbWUgd2FzIG5vdCBhbHJlYWR5IHVzZWQgaW4gdGhlIGNsYXNzXG4gICAgaWYgKHByb3RvRmFjZXRzICYmIHByb3RvRmFjZXRzW2ZhY2V0TmFtZV0pXG4gICAgICAgIHRocm93IG5ldyBGYWNldEVycm9yKCdmYWNldCAnICsgZmFjZXROYW1lICsgJyBpcyBhbHJlYWR5IHBhcnQgb2YgdGhlIGNsYXNzICcgKyB0aGlzLmNvbnN0cnVjdG9yLm5hbWUpO1xuXG4gICAgLy8gY2hlY2sgdGhhdCB0aGlzIGZhY2VOYW1lIGRvZXMgbm90IGFscmVhZHkgZXhpc3Qgb24gdGhlIGZhY2V0ZWQgb2JqZWN0XG4gICAgaWYgKHRoaXNbZmFjZXROYW1lXSkge1xuICAgICAgICB2YXIgbWVzc2FnZSA9ICdmYWNldCAnICsgZmFjZXROYW1lICsgJyBpcyBhbHJlYWR5IHByZXNlbnQgaW4gb2JqZWN0JztcbiAgICAgICAgaWYgKHRocm93T25FcnJvcnMgPT09IGZhbHNlKVxuICAgICAgICAgICAgcmV0dXJuIGxvZ2dlci5lcnJvcignRmFjZXRlZE9iamVjdCBhZGRGYWNldDogJywgbWVzc2FnZSk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHRocm93IG5ldyBGYWNldEVycm9yKG1lc3NhZ2UpO1xuICAgIH1cblxuICAgIC8vIGluc3RhbnRpYXRlIHRoZSBmYWNldFxuICAgIHZhciBuZXdGYWNldCA9IHRoaXMuZmFjZXRzW2ZhY2V0TmFtZV0gPSBuZXcgRmFjZXRDbGFzcyh0aGlzLCBmYWNldENvbmZpZyk7XG5cbiAgICAvLyBhZGQgZmFjZXQgdG8gZmFjZXRlZCBvYmplY3RcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsIGZhY2V0TmFtZSwgbmV3RmFjZXQsIF8uRU5VTSk7XG5cbiAgICByZXR1cm4gbmV3RmFjZXQ7XG59XG5cblxuLyoqXG4gKiBGYWNldGVkT2JqZWN0IGNsYXNzIG1ldGhvZFxuICogUmV0dXJucyByZWZlcmVuY2UgdG8gdGhlIGZhY2V0IGNsYXNzIGlmIHRoZSBmYWNldCB3aXRoIGBmYWNldE5hbWVgIGlzIHBhcnQgb2YgdGhlIGNsYXNzLCBgdW5kZWZpbmVkYCBvdGhlcndpc2UuIElmIHN1YmNsYXNzIGlzIGNyZWF0ZWQgdXNpbmcgXy5jcmVhdGVTdWJjbGFzcyAoYXMgaXQgc2hvdWxkIGJlKSBpdCB3aWxsIGFsc28gaGF2ZSB0aGlzIG1ldGhvZC5cbiAqIFxuICogQHBhcmFtIHtTdWJjbGFzcyhGYWNldGVkT2JqZWN0KX0gdGhpcyB0aGlzIGluIHRoaXMgbWV0aG9kIHJlZmVycyB0byBGYWNldGVkT2JqZWN0IChvciBpdHMgc3ViY2xhc3MpIHRoYXQgY2FsbHMgdGhpcyBtZXRob2RcbiAqIEBwYXJhbSB7U3RyaW5nfSBmYWNldE5hbWVcbiAqIEByZXR1cm4ge1N1YmNsYXNzKEZhY2V0KXx1bmRlZmluZWR9IFxuICovXG5mdW5jdGlvbiBGYWNldGVkT2JqZWN0JCRoYXNGYWNldChmYWNldE5hbWUpIHtcbiAgICAvLyB0aGlzIHJlZmVycyB0byB0aGUgRmFjZXRlZE9iamVjdCBjbGFzcyAob3Igc3ViY2xhc3MpLCBub3QgaW5zdGFuY2VcbiAgICB2YXIgcHJvdG9GYWNldHMgPSB0aGlzLnByb3RvdHlwZS5mYWNldHNDbGFzc2VzO1xuICAgIHJldHVybiBwcm90b0ZhY2V0cyAmJiBwcm90b0ZhY2V0c1tmYWNldE5hbWVdO1xufVxuXG4vKipcbiAqIEZhY2V0ZWRPYmplY3QgY2xhc3MgbWV0aG9kXG4gKiBSZXR1cm4gdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBmYWNldFxuICogQHBhcmFtIHtTdHJpbmd9IGZhY2V0TmFtZSB0aGUgZmFjZXQgd2hpY2ggY29uZmlnIHNob3VsZCBiZSByZXRyaWV2ZWRcbiAqIEByZXR1cm4ge09iamVjdH0gdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRoYXQgd2FzIHBhc3NlZCB0byB0aGUgZmFjZXRcbiAqL1xuZnVuY3Rpb24gRmFjZXRlZE9iamVjdCQkZ2V0RmFjZXRDb25maWcoZmFjZXROYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMuaGFzRmFjZXQoZmFjZXROYW1lKSA/IHRoaXMucHJvdG90eXBlLmZhY2V0c0NvbmZpZ1tmYWNldE5hbWVdIDogbnVsbDtcbn1cblxuXG4vKipcbiAqIEZhY2V0ZWRPYmplY3QgY2xhc3MgbWV0aG9kXG4gKiBDbGFzcyBmYWN0b3J5IHRoYXQgY3JlYXRlcyBjbGFzc2VzIChjb25zdHJ1Y3RvciBmdW5jdGlvbnMpIGZyb20gdGhlIG1hcHMgb2YgZmFjZXRzIGFuZCB0aGVpciBjb25maWd1cmF0aW9ucy5cbiAqIENyZWF0ZWQgY2xhc3Mgd2lsbCBiZSBzdWJjbGFzcyBvZiBgRmFjZXRlZE9iamVjdGAuXG4gKlxuICogQHBhcmFtIHtTdWJjbGFzcyhGYWNldGVkT2JqZWN0KX0gdGhpcyB0aGlzIGluIHRoaXMgbWV0aG9kIHJlZmVycyB0byBGYWNldGVkT2JqZWN0IChvciBpdHMgc3ViY2xhc3MpIHRoYXQgY2FsbHMgdGhpcyBtZXRob2RcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIGNsYXNzIG5hbWUgKHdpbGwgYmUgZnVuY3Rpb24gbmFtZSBvZiBjbGFzcyBjb25zdHJ1Y3RvciBmdW5jdGlvbilcbiAqIEBwYXJhbSB7T2JqZWN0W1N1YmNsYXNzKEZhY2V0KV19IGZhY2V0c0NsYXNzZXMgbWFwIG9mIGNsYXNzZXMgb2YgZmFjZXRzIHRoYXQgd2lsbCBjb25zdGl0dXRlIHRoZSBjcmVhdGVkIGNsYXNzXG4gKiBAcGFyYW0ge09iamVjdFtPYmplY3RdfSBmYWNldHNDb25maWcgbWFwIG9mIGZhY2V0cyBjb25maWd1cmF0aW9uLCBzaG91bGQgaGF2ZSB0aGUgc2FtZSBrZXlzIGFzIHRoZSBtYXAgb2YgY2xhc3Nlcy4gU29tZSBmYWNldHMgbWF5IG5vdCBoYXZlIGNvbmZpZ3VyYXRpb24sIGJ1dCB0aGUgY29uZmlndXJhdGlvbiBmb3IgYSBmYWNldCB0aGF0IGlzIG5vdCBpbmNsdWRlZCBpbiBmYWNldHNDbGFzc2VzIHdpbGwgdGhyb3cgYW4gZXhjZXB0aW9uXG4gKiBAcmV0dXJuIHtTdWJjbGFzcyhGYWNldGVkT2JqZWN0KX1cbiAqL1xuZnVuY3Rpb24gRmFjZXRlZE9iamVjdCQkY3JlYXRlRmFjZXRlZENsYXNzKG5hbWUsIGZhY2V0c0NsYXNzZXMsIGZhY2V0c0NvbmZpZykge1xuICAgIGNoZWNrKG5hbWUsIFN0cmluZyk7XG4gICAgY2hlY2soZmFjZXRzQ2xhc3NlcywgTWF0Y2guT3B0aW9uYWwoTWF0Y2guT2JqZWN0SGFzaChNYXRjaC5TdWJjbGFzcyhGYWNldCwgdHJ1ZSkpKSk7XG4gICAgY2hlY2soZmFjZXRzQ29uZmlnLCBNYXRjaC5PcHRpb25hbChPYmplY3QpKTtcblxuICAgIC8vIHRocm93IGV4Y2VwdGlvbiBpZiBjb25maWcgcGFzc2VkIGZvciBmYWNldCBmb3Igd2hpY2ggdGhlcmUgaXMgbm8gY2xhc3NcbiAgICBpZiAoZmFjZXRzQ29uZmlnKVxuICAgICAgICBfLmVhY2hLZXkoZmFjZXRzQ29uZmlnLCBmdW5jdGlvbihmY3RDb25maWcsIGZjdE5hbWUpIHtcbiAgICAgICAgICAgIGlmICghIGZhY2V0c0NsYXNzZXMuaGFzT3duUHJvcGVydHkoZmN0TmFtZSkpXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEZhY2V0RXJyb3IoJ2NvbmZpZ3VyYXRpb24gZm9yIGZhY2V0ICgnICsgZmN0TmFtZSArICcpIHBhc3NlZCB0aGF0IGlzIG5vdCBpbiBjbGFzcycpO1xuICAgICAgICB9KTtcblxuICAgIC8vIGNyZWF0ZSBzdWJjbGFzcyBvZiB0aGUgY3VycmVudCBjbGFzcyAodGhpcyByZWZlcnMgdG8gdGhlIGNsYXNzIHRoYXQgY2FsbHMgdGhpcyBtZXRob2QpXG4gICAgdmFyIEZhY2V0ZWRDbGFzcyA9IF8uY3JlYXRlU3ViY2xhc3ModGhpcywgbmFtZSwgdHJ1ZSk7XG5cbiAgICAvLyBnZXQgZmFjZXRzIGNsYXNzZXMgYW5kIGNvbmZpZ3VyYXRpb25zIGZyb20gcGFyZW50IGNsYXNzXG4gICAgZmFjZXRzQ2xhc3NlcyA9IGFkZEluaGVyaXRlZEZhY2V0cyh0aGlzLCBmYWNldHNDbGFzc2VzLCAnZmFjZXRzQ2xhc3NlcycpO1xuICAgIGZhY2V0c0NvbmZpZyA9IGFkZEluaGVyaXRlZEZhY2V0cyh0aGlzLCBmYWNldHNDb25maWcsICdmYWNldHNDb25maWcnKTtcblxuICAgIC8vIHN0b3JlIGZhY2V0cyBjbGFzc2VzIGFuZCBjb25maWd1cmF0aW9ucyBvZiBjbGFzcyBwcm90b3R5cGVcbiAgICBfLmV4dGVuZFByb3RvKEZhY2V0ZWRDbGFzcywge1xuICAgICAgICBmYWNldHNDbGFzc2VzOiBmYWNldHNDbGFzc2VzLFxuICAgICAgICBmYWNldHNDb25maWc6IGZhY2V0c0NvbmZpZ1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIEZhY2V0ZWRDbGFzcztcblxuXG4gICAgZnVuY3Rpb24gYWRkSW5oZXJpdGVkRmFjZXRzKHN1cGVyQ2xhc3MsIGZhY2V0c0luZm8sIGZhY2V0c0luZm9OYW1lKSB7XG4gICAgICAgIHZhciBpbmhlcml0ZWRGYWNldHNJbmZvID0gc3VwZXJDbGFzcy5wcm90b3R5cGVbZmFjZXRzSW5mb05hbWVdO1xuICAgICAgICBpZiAoaW5oZXJpdGVkRmFjZXRzSW5mbylcbiAgICAgICAgICAgIHJldHVybiBfKGluaGVyaXRlZEZhY2V0c0luZm8pXG4gICAgICAgICAgICAgICAgICAgIC5jbG9uZSgpXG4gICAgICAgICAgICAgICAgICAgIC5leHRlbmQoZmFjZXRzSW5mbyB8fCB7fSkuXygpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICByZXR1cm4gZmFjZXRzSW5mbztcbiAgICB9XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgTWl4aW5FcnJvciA9IHJlcXVpcmUoJy4uL3V0aWwvZXJyb3InKS5NaXhpblxuICAgICwgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJyk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBNaXhpbjtcblxuLyoqXG4gKiBgbWlsby5jbGFzc2VzLk1peGluYCAtIGFuIGFic3RyYWN0IE1peGluIGNsYXNzLlxuICogQ2FuIGJlIHN1YmNsYXNzZWQgdXNpbmc6XG4gKiBgYGBcbiAqIHZhciBNeU1peGluID0gXy5jcmVhdGVTdWJjbGFzcyhtaWxvLmNsYXNzZXMuTWl4aW4sICdNeU1peGluJyk7XG4gKiBgYGBcbiAqXG4gKiBNaXhpbiBwYXR0ZXJuIGlzIGFsc28gdXNlZCwgYnV0IE1peGluIGluIG1pbG8gaXMgaW1wbGVtZW50ZWQgYXMgYSBzZXBhcmF0ZSBvYmplY3QgdGhhdCBpcyBzdG9yZWQgb24gdGhlIHByb3BlcnR5IG9mIHRoZSBob3N0IG9iamVjdCBhbmQgY2FuIGNyZWF0ZSBwcm94eSBtZXRob2RzIG9uIHRoZSBob3N0IG9iamVjdCBpZiByZXF1aXJlZC5cbiAqIENsYXNzZXMgW01lc3Nlbmdlcl0oLi4vbWVzc2VuZ2VyL2luZGV4LmpzLmh0bWwpIGFuZCBbTWVzc2FnZVNvdXJjZV0oLi4vbWVzc2VuZ2VyL21fc291cmNlLmpzLmh0bWwpIGFyZSBzdWJjbGFzc2VzIG9mIE1peGluIGFic3RyYWN0IGNsYXNzLiBgdGhpc2AgaW4gcHJveHkgbWV0aG9kcyByZWZlcnMgdG8gTWl4aW4gaW5zdGFuY2UsIHRoZSByZWZlcmVuY2UgdG8gdGhlIGhvc3Qgb2JqZWN0IGlzIGB0aGlzLl9ob3N0T2JqZWN0YC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBPcHRpb25hbCBvYmplY3Qgd2hlcmUgYSBNaXhpbiBpbnN0YW5jZSB3aWxsIGJlIHN0b3JlZCBvbi4gSXQgaXMgdXNlZCB0byBwcm94eSBtZXRob2RzIGFuZCBhbHNvIHRvIGZpbmQgdGhlIHJlZmVyZW5jZSB3aGVuIGl0IGlzIG5lZWRlZCBmb3IgaG9zdCBvYmplY3QgaW1wbGVtZW50YXRpb24uXG4gKiBAcGFyYW0ge09iamVjdH0gcHJveHlNZXRob2RzIE9wdGlvbmFsIG1hcCBvZiBwcm94eSBtZXRob2QgbmFtZXMgYXMga2V5cyBhbmQgTWl4aW4gbWV0aG9kcyBuYW1lcyBhcyB2YWx1ZXMsIHNvIHByb3hpZWQgbWV0aG9kcyBjYW4gYmUgcmVuYW1lZCB0byBhdm9pZCBuYW1lLXNwYWNlIGNvbmZsaWN0cyBpZiB0d28gZGlmZmVyZW50IE1peGluIGluc3RhbmNlcyB3aXRoIHRoZSBzYW1lIG1ldGhvZCBuYW1lcyBhcmUgcHV0IG9uIHRoZSBvYmplY3RcbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIGFsbCBjb25zdHJ1Y3RvciBhcmd1bWVudHMgd2lsbCBiZSBwYXNzZWQgdG8gaW5pdCBtZXRob2Qgb2YgTWl4aW4gc3ViY2xhc3MgdG9nZXRoZXIgd2l0aCBob3N0T2JqZWN0IGFuZCBwcm94eU1ldGhvZHNcbiAqIEByZXR1cm4ge01peGlufVxuICovXG5mdW5jdGlvbiBNaXhpbihob3N0T2JqZWN0LCBwcm94eU1ldGhvZHMpIHsgLy8gLCBvdGhlciBhcmdzIC0gcGFzc2VkIHRvIGluaXQgbWV0aG9kXG4gICAgY2hlY2soaG9zdE9iamVjdCwgTWF0Y2guT3B0aW9uYWwoTWF0Y2guT25lT2YoT2JqZWN0LCBGdW5jdGlvbikpKTtcblxuICAgIC8vIHN0b3JlIGhvc3RPYmplY3RcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdfaG9zdE9iamVjdCcsIGhvc3RPYmplY3QpO1xuXG4gICAgLy8gcHJveHkgbWV0aG9kcyB0byBob3N0T2JqZWN0XG4gICAgaWYgKHByb3h5TWV0aG9kcylcbiAgICAgICAgdGhpcy5fY3JlYXRlUHJveHlNZXRob2RzKHByb3h5TWV0aG9kcyk7XG5cbiAgICAvLyBjYWxsaW5nIGluaXQgaWYgaXQgaXMgZGVmaW5lZCBpbiB0aGUgY2xhc3NcbiAgICBpZiAodGhpcy5pbml0KVxuICAgICAgICB0aGlzLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuXG4vKipcbiAqICMjIyNNaXhpbiBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICogVGhlc2UgbWV0aG9kcyBhcmUgY2FsbGVkIGJ5IGNvbnN0cnVjdG9yLCB0aGV5IGFyZSBub3QgdG8gYmUgY2FsbGVkIGZyb20gc3ViY2xhc3Nlcy5cbiAqXG4gKiAtIFtfY3JlYXRlUHJveHlNZXRob2RdKCNfY3JlYXRlUHJveHlNZXRob2QpXG4gKiAtIFtfY3JlYXRlUHJveHlNZXRob2RzXSgjX2NyZWF0ZVByb3h5TWV0aG9kcylcbiAqL1xuXy5leHRlbmRQcm90byhNaXhpbiwge1xuICAgIF9jcmVhdGVQcm94eU1ldGhvZDogX2NyZWF0ZVByb3h5TWV0aG9kLCAgLy8gZGVwcmVjYXRlZCwgc2hvdWxkIG5vdCBiZSB1c2VkXG4gICAgX2NyZWF0ZVByb3h5TWV0aG9kczogX2NyZWF0ZVByb3h5TWV0aG9kcyAgLy8gZGVwcmVjYXRlZCwgc2hvdWxkIG5vdCBiZSB1c2VkXG59KTtcblxuXG4vKipcbiAqICMjIyNNaXhpbiBjbGFzcyBtZXRob2RzIyMjI1xuICogVGhlc2UgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgaW4gaG9zdCBjbGFzcyBkZWNsYXJhdGlvbi5cbiAqXG4gKiAtIFt1c2VXaXRoXSgjTWl4aW4kJHVzZVdpdGgpXG4gKi9cbl8uZXh0ZW5kKE1peGluLCB7XG4gICAgdXNlV2l0aDogTWl4aW4kJHVzZVdpdGhcbn0pO1xuXG5cbi8qKlxuICogQ3JlYXRlcyBhIHByb3hpZWQgbWV0aG9kIG9mIE1peGluIHN1YmNsYXNzIG9uIGhvc3Qgb2JqZWN0LlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtaXhpbk1ldGhvZE5hbWUgbmFtZSBvZiBtZXRob2QgaW4gTWl4aW4gc3ViY2xhc3NcbiAqIEBwYXJhbSB7U3RyaW5nfSBwcm94eU1ldGhvZE5hbWUgbmFtZSBvZiBjcmVhdGVkIHByb3h5IG1ldGhvZCBvbiBob3N0IG9iamVjdFxuICogQHBhcmFtIHtPYmplY3R9IGhvc3RPYmplY3QgT3B0aW9uYWwgcmVmZXJlbmNlIHRvIHRoZSBob3N0IG9iamVjdDsgaWYgbm90IHNwZWNpZmllZCB0aGUgaG9zdCBvYmplY3QgcGFzc2VkIHRvIGNvbnN0cnVjdG9yIHdpbCBiZSB1c2VkLiBJdCBhbGxvd3MgdG8gdXNlIHRoZSBzYW1lIGluc3RhbmNlIG9mIE1peGluIG9uIHR3byBob3N0IG9iamVjdHMuXG4gKi9cbmZ1bmN0aW9uIF9jcmVhdGVQcm94eU1ldGhvZChwcm94eU1ldGhvZE5hbWUsIG1peGluTWV0aG9kTmFtZSwgaG9zdE9iamVjdCkge1xuICAgIGhvc3RPYmplY3QgPSBob3N0T2JqZWN0IHx8IHRoaXMuX2hvc3RPYmplY3Q7XG5cbiAgICAvLyBNaXhpbiBjbGFzcyBkb2VzIG5vdCBhbGxvdyBzaGFkb3dpbmcgbWV0aG9kcyB0aGF0IGV4aXN0IG9uIHRoZSBob3N0IG9iamVjdFxuICAgIGlmIChob3N0T2JqZWN0W3Byb3h5TWV0aG9kTmFtZV0pXG4gICAgICAgIHRocm93IG5ldyBNaXhpbkVycm9yKCdtZXRob2QgJyArIHByb3h5TWV0aG9kTmFtZSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnIGFscmVhZHkgZGVmaW5lZCBpbiBob3N0IG9iamVjdCcpO1xuXG4gICAgdmFyIG1ldGhvZCA9IHRoaXNbbWl4aW5NZXRob2ROYW1lXVxuICAgIGNoZWNrKG1ldGhvZCwgRnVuY3Rpb24pO1xuXG4gICAgLy8gQmluZCBwcm94aWVkIE1peGluJ3MgbWV0aG9kIHRvIE1peGluIGluc3RhbmNlXG4gICAgdmFyIGJvdW5kTWV0aG9kID0gbWV0aG9kLmJpbmQodGhpcyk7XG5cbiAgICBfLmRlZmluZVByb3BlcnR5KGhvc3RPYmplY3QsIHByb3h5TWV0aG9kTmFtZSwgYm91bmRNZXRob2QsIF8uV1JJVCk7XG59XG5cblxuLyoqXG4gKiBDcmVhdGVzIHByb3hpZWQgbWV0aG9kcyBvZiBNaXhpbiBzdWJjbGFzcyBvbiBob3N0IG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge0hhc2hbU3RyaW5nXXxBcnJheVtTdHJpbmddfSBwcm94eU1ldGhvZHMgbWFwIG9mIG5hbWVzIG9mIG1ldGhvZHMsIGtleSAtIHByb3h5IG1ldGhvZCBuYW1lLCB2YWx1ZSAtIG1peGluIG1ldGhvZCBuYW1lLiBDYW4gYmUgYXJyYXkuXG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBhbiBvcHRpb25hbCByZWZlcmVuY2UgdG8gdGhlIGhvc3Qgb2JqZWN0OyBpZiBub3Qgc3BlY2lmaWVkIHRoZSBob3N0IG9iamVjdCBwYXNzZWQgdG8gY29uc3RydWN0b3Igd2lsIGJlIHVzZWQuIEl0IGFsbG93cyB0byB1c2UgdGhlIHNhbWUgaW5zdGFuY2Ugb2YgTWl4aW4gb24gdHdvIGhvc3Qgb2JqZWN0cy5cbiAqL1xuZnVuY3Rpb24gX2NyZWF0ZVByb3h5TWV0aG9kcyhwcm94eU1ldGhvZHMsIGhvc3RPYmplY3QpIHtcbiAgICBjaGVjayhwcm94eU1ldGhvZHMsIE1hdGNoLk9wdGlvbmFsKE1hdGNoLk9uZU9mKFtTdHJpbmddLCBNYXRjaC5PYmplY3RIYXNoKFN0cmluZykpKSk7XG5cbiAgICAvLyBjcmVhdGluZyBhbmQgYmluZGluZyBwcm94eSBtZXRob2RzIG9uIHRoZSBob3N0IG9iamVjdFxuICAgIGlmIChBcnJheS5pc0FycmF5KHByb3h5TWV0aG9kcykpXG4gICAgICAgIHByb3h5TWV0aG9kcy5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICAgICAgICAgIC8vIG1ldGhvZCBjYWxsZWQgdGhpcyB3YXkgdG8gYWxsb3cgdXNpbmcgX2NyZWF0ZVByb3h5TWV0aG9kcyB3aXRoIG9iamVjdHNcbiAgICAgICAgICAgIC8vIHRoYXQgYXJlIG5vdCBpbmhlcml0aW5nIGZyb20gTWl4aW5cbiAgICAgICAgICAgIF9jcmVhdGVQcm94eU1ldGhvZC5jYWxsKHRoaXMsIG1ldGhvZE5hbWUsIG1ldGhvZE5hbWUsIGhvc3RPYmplY3QpO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICBlbHNlXG4gICAgICAgIF8uZWFjaEtleShwcm94eU1ldGhvZHMsIGZ1bmN0aW9uKG1peGluTWV0aG9kTmFtZSwgcHJveHlNZXRob2ROYW1lKSB7XG4gICAgICAgICAgICAvLyBtZXRob2QgY2FsbGVkIHRoaXMgd2F5IHRvIGFsbG93IHVzaW5nIF9jcmVhdGVQcm94eU1ldGhvZHMgd2l0aCBvYmplY3RzXG4gICAgICAgICAgICAvLyB0aGF0IGFyZSBub3QgaW5oZXJpdGluZyBmcm9tIE1peGluXG4gICAgICAgICAgICBfY3JlYXRlUHJveHlNZXRob2QuY2FsbCh0aGlzLCBwcm94eU1ldGhvZE5hbWUsIG1peGluTWV0aG9kTmFtZSwgaG9zdE9iamVjdCk7XG4gICAgICAgIH0sIHRoaXMpO1xufVxuXG5cbi8qKlxuICogU2V0cyBtaXhpbiBpbnN0YW5jZSBwcm9wZXJ0eSBuYW1lIG9uIHRoZSBob3N0IGNsYXNzXG4gKiBDYW4gYmUgY2FsbGVkIG9ubHkgb25jZVxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzIE1peGluIHN1YmNsYXNzIChub3QgaW5zdGFuY2UpXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBob3N0Q2xhc3NcbiAqIEBwYXJhbSB7U3RyaW5nfSBpbnN0YW5jZUtleVxuICovXG5mdW5jdGlvbiBNaXhpbl9zZXRJbnN0YW5jZUtleShob3N0Q2xhc3MsIG1ldGhvZCwgaW5zdGFuY2VLZXkpIHtcbiAgICBjaGVjayhob3N0Q2xhc3MsIEZ1bmN0aW9uKTtcbiAgICBjaGVjayhpbnN0YW5jZUtleSwgTWF0Y2guSWRlbnRpZmllclN0cmluZyk7XG5cbiAgICB2YXIgcHJvcCA9IGNvbmZpZy5taXhpbi5pbnN0YW5jZVByb3BlcnRpZXNNYXBcbiAgICAgICAgLCBpbnN0YW5jZUtleXMgPSBob3N0Q2xhc3NbcHJvcF0gPSBob3N0Q2xhc3NbcHJvcF0gfHwge307XG5cbiAgICBpZiAoaW5zdGFuY2VLZXlzW21ldGhvZC5uYW1lXSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXhpbjogaW5zdGFuY2UgcHJvcGVydHkgZm9yIG1ldGhvZCB3aXRoIG5hbWUgJ1xuICAgICAgICAgICAgKyBtZXRob2QubmFtZSArICcgaXMgYWxyZWFkeSBzZXQnKTtcblxuICAgIGluc3RhbmNlS2V5c1ttZXRob2QubmFtZV0gPSBpbnN0YW5jZUtleTtcbn1cblxuXG4vKipcbiAqIEFkZHMgbWV0aG9kIG9mIE1peGluIHN1YmNsYXNzIHRvIGhvc3QgY2xhc3MgcHJvdG90eXBlLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzIE1peGluIHN1YmNsYXNzIChub3QgaW5zdGFuY2UpXG4gKiBAcGFyYW0ge1N0cmluZ30gbWl4aW5NZXRob2ROYW1lIG5hbWUgb2YgbWV0aG9kIGluIE1peGluIHN1YmNsYXNzXG4gKiBAcGFyYW0ge1N0cmluZ30gaG9zdE1ldGhvZE5hbWUgKG9wdGlvbmFsKSBuYW1lIG9mIGNyZWF0ZWQgcHJveHkgbWV0aG9kIG9uIGhvc3Qgb2JqZWN0LCBzYW1lIGlmIG5vdCBzcGVjaWZpZWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0T2JqZWN0IG9iamVjdCBjbGFzcywgbXVzdCBiZSBzcGVjaWZpZWQgYXMgdGhlIGxhc3QgcGFyYW1ldGVyICgybmQgb3IgM3JkKVxuICovXG5mdW5jdGlvbiBNaXhpbl9hZGRNZXRob2QoaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2ROYW1lLCBob3N0TWV0aG9kTmFtZSkge1xuICAgIHZhciBtZXRob2QgPSB0aGlzLnByb3RvdHlwZVttaXhpbk1ldGhvZE5hbWVdO1xuICAgIGNoZWNrKG1ldGhvZCwgRnVuY3Rpb24pO1xuXG4gICAgdmFyIHdyYXBwZWRNZXRob2QgPSBfd3JhcE1peGluTWV0aG9kLmNhbGwodGhpcywgbWV0aG9kKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydHkoaG9zdENsYXNzLnByb3RvdHlwZSwgaG9zdE1ldGhvZE5hbWUsIHdyYXBwZWRNZXRob2QsIF8uV1JJVCk7XG5cbiAgICBNaXhpbl9zZXRJbnN0YW5jZUtleShob3N0Q2xhc3MsIG1ldGhvZCwgaW5zdGFuY2VLZXkpXG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIG1ldGhvZCB0aGF0IHdpbGwgYmUgZXhwb3NlZCBvbiB0aGUgaG9zdCBjbGFzcyBwcm90b3R5cGVcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gdGhpcyBNaXhpbiBzdWJjbGFzcyAobm90IGluc3RhbmNlKVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIF93cmFwTWl4aW5NZXRob2QobWV0aG9kKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkgeyAvLyAsLi4uIGFyZ3VtZW50c1xuICAgICAgICB2YXIgbWl4aW5JbnN0YW5jZSA9IF9nZXRNaXhpbkluc3RhbmNlLmNhbGwodGhpcywgbWV0aG9kLm5hbWUpO1xuICAgICAgICByZXR1cm4gbWV0aG9kLmFwcGx5KG1peGluSW5zdGFuY2UsIGFyZ3VtZW50cyk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgcmVmZXJlbmNlIHRvIHRoZSBpbnN0YW5jZSBvZiBtaXhpbiBzdWJjbGFzcy5cbiAqIFRoaXMgbWV0aG9kIGlzIHVzZWQgd2hlbiBtZXRob2RzIGFyZSBleHBvc2VkIG9uIHRoZSBob3N0IGNsYXNzIHByb3RvdHlwZSAodXNpbmcgYWRkTWVodG9kcykgcmF0aGVyIHRoYW4gb24gaG9zdCBpbnN0YW5jZS5cbiAqIFN1YmNsYXNzZXMgc2hvdWxkIG5vdCB1c2UgdGhpcyBtZXRob2RzIC0gd2hlbmV2ZXIgc3ViY2xhc3MgbWV0aG9kIGlzIGV4cG9zZWQgb24gdGhlIHByb3RvdHlwZSBpdCB3aWxsIGJlIHdyYXBwZWQgdG8gc2V0IGNvcnJlY3QgY29udGV4dCBmb3IgdGhlIHN1YmNsYXNzIG1ldGhvZC5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBfZ2V0TWl4aW5JbnN0YW5jZShtZXRob2ROYW1lKSB7XG4gICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBNaXhpbikgcmV0dXJuIHRoaXM7XG4gICAgdmFyIGluc3RhbmNlS2V5cyA9IHRoaXMuY29uc3RydWN0b3JbY29uZmlnLm1peGluLmluc3RhbmNlUHJvcGVydGllc01hcF1cbiAgICByZXR1cm4gdGhpc1tpbnN0YW5jZUtleXNbbWV0aG9kTmFtZV1dO1xufVxuXG5cbi8qKlxuICogQWRkcyBtZXRob2RzIG9mIE1peGluIHN1YmNsYXNzIHRvIGhvc3QgY2xhc3MgcHJvdG90eXBlLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHRoaXMgTWl4aW4gc3ViY2xhc3MgKG5vdCBpbnN0YW5jZSlcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0Q2xhc3MgaG9zdCBvYmplY3QgY2xhc3M7IG11c3QgYmUgc3BlY2lmaWVkLlxuICogQHBhcmFtIHtTdHJpbmd9IGluc3RhbmNlS2V5IHRoZSBuYW1lIG9mIHRoZSBwcm9wZXJ0eSB0aGUgaG9zdCBjbGFzcyBpbnN0YW5jZSB3aWxsIHN0b3JlIG1peGluIGluc3RhbmNlIG9uXG4gKiBAcGFyYW0ge0hhc2hbU3RyaW5nXXxBcnJheVtTdHJpbmddfSBtaXhpbk1ldGhvZHMgbWFwIG9mIG5hbWVzIG9mIG1ldGhvZHMsIGtleSAtIGhvc3QgbWV0aG9kIG5hbWUsIHZhbHVlIC0gbWl4aW4gbWV0aG9kIG5hbWUuIENhbiBiZSBhcnJheS5cbiAqL1xuZnVuY3Rpb24gTWl4aW4kJHVzZVdpdGgoaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2RzKSB7XG4gICAgY2hlY2sobWl4aW5NZXRob2RzLCBNYXRjaC5PcHRpb25hbChNYXRjaC5PbmVPZihbU3RyaW5nXSwgTWF0Y2guT2JqZWN0SGFzaChTdHJpbmcpKSkpO1xuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkobWl4aW5NZXRob2RzKSlcbiAgICAgICAgbWl4aW5NZXRob2RzLmZvckVhY2goZnVuY3Rpb24obWV0aG9kTmFtZSkge1xuICAgICAgICAgICAgTWl4aW5fYWRkTWV0aG9kLmNhbGwodGhpcywgaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWV0aG9kTmFtZSwgbWV0aG9kTmFtZSk7XG4gICAgICAgIH0sIHRoaXMpO1xuICAgIGVsc2VcbiAgICAgICAgXy5lYWNoS2V5KG1peGluTWV0aG9kcywgZnVuY3Rpb24obWl4aW5NZXRob2ROYW1lLCBob3N0TWV0aG9kTmFtZSkge1xuICAgICAgICAgICAgTWl4aW5fYWRkTWV0aG9kLmNhbGwodGhpcywgaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2ROYW1lLCBob3N0TWV0aG9kTmFtZSk7XG4gICAgICAgIH0sIHRoaXMpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBSZWdpc3RyeUVycm9yID0gcmVxdWlyZSgnLi4vdXRpbC9lcnJvcicpLlJlZ2lzdHJ5XG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaDtcblxubW9kdWxlLmV4cG9ydHMgPSBDbGFzc1JlZ2lzdHJ5O1xuXG5cbi8qKlxuICogYG1pbG8uY2xhc3Nlcy5DbGFzc1JlZ2lzdHJ5YCAtIHRoZSByZWdpc3RyeSBvZiBjbGFzc2VzIGNsYXNzLlxuICogQ29tcG9uZW50cyBhbmQgRmFjZXRzIHJlZ2lzdGVyIHRoZW1zZWx2ZXMgaW4gcmVnaXN0cmllcy4gSXQgYWxsb3dzIHRvIGF2b2lkIHJlcXVpcmluZyB0aGVtIGZyb20gb25lIG1vZHVsZSBhbmQgcHJldmVudHMgY2lyY3VsYXIgZGVwZW5kZW5jaWVzIGJldHdlZW4gbW9kdWxlcy5cbiAqIFxuICogQHBhcmFtIHtGdW5jdGlvbn0gRm91bmRhdGlvbkNsYXNzIEFsbCBjbGFzc2VzIHRoYXQgYXJlIHJlZ2lzdGVyZWQgaW4gdGhlIHJlZ2lzdHJ5IHNob3VsZCBiZSBzdWJjbGFzc2VzIG9mIHRoZSBGb3VuZGF0aW9uQ2xhc3NcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gQ2xhc3NSZWdpc3RyeSAoRm91bmRhdGlvbkNsYXNzKSB7XG4gICAgaWYgKEZvdW5kYXRpb25DbGFzcylcbiAgICAgICAgdGhpcy5zZXRDbGFzcyhGb3VuZGF0aW9uQ2xhc3MpO1xuXG4gICAgdGhpcy5fX3JlZ2lzdGVyZWRDbGFzc2VzID0ge307XG59XG5cblxuLyoqXG4gKiAjIyMjQ2xhc3NSZWdpc3RyeSBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2FkZF0oI2FkZClcbiAqIC0gW2dldF0oI2dldClcbiAqIC0gW3JlbW92ZV0oI3JlbW92ZSlcbiAqIC0gW2NsZWFuXSgjY2xlYW4pXG4gKiAtIFtzZXRDbGFzc10oI3NldENsYXNzKVxuICovXG5fLmV4dGVuZFByb3RvKENsYXNzUmVnaXN0cnksIHtcbiAgICBhZGQ6IGFkZCxcbiAgICBnZXQ6IGdldCxcbiAgICByZW1vdmU6IHJlbW92ZSxcbiAgICBjbGVhbjogY2xlYW4sXG4gICAgc2V0Q2xhc3M6IHNldENsYXNzXG59KTtcblxuXG4vKipcbiAqIENsYXNzUmVnaXN0cnkgaW5zdGFuY2UgbWV0aG9kIHRoYXQgcmVnaXN0ZXJzIGEgY2xhc3MgaW4gdGhlIHJlZ2lzdHJ5LlxuICogVGhlIG1ldGhvZCB3aWxsIHRocm93IGFuIGV4Y2VwdGlvbiBpZiBhIGNsYXNzIGlzIHJlZ2lzdGVyZWQgdW5kZXIgdGhlIHNhbWUgbmFtZSBhcyBwcmV2aW91c2x5IHJlZ2lzdGVyZWQgY2xhc3MuXG4gKiBUaGUgbWV0aG9kIGFsbG93cyByZWdpc3RlcmluZyB0aGUgc2FtZSBjbGFzcyB1bmRlciBhIGRpZmZlcmVudCBuYW1lLCBzbyBjbGFzcyBhbGlhc2VzIGNhbiBiZSBjcmVhdGVkLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGFDbGFzcyBjbGFzcyB0byByZWdpc3RlciBpbiB0aGUgcmVnaXN0cnkuIFNob3VsZCBiZSBzdWJjbGFzcyBvZiBgdGhpcy5Gb3VuZGF0aW9uQ2xhc3NgLlxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWUgT3B0aW9uYWwgY2xhc3MgbmFtZS4gSWYgY2xhc3MgbmFtZSBpcyBub3Qgc3BlY2lmaWVkLCBpdCB3aWxsIGJlIHRha2VuIGZyb20gY29uc3RydWN0b3IgZnVuY3Rpb24gbmFtZS4gQ2xhc3MgbmFtZSBzaG91bGQgYmUgYSB2YWxpZCBpZGVudGlmaWVyIGFuZCBjYW5ub3QgYmUgYW4gZW1wdHkgc3RyaW5nLlxuICovXG5mdW5jdGlvbiBhZGQoYUNsYXNzLCBuYW1lKSB7XG4gICAgbmFtZSA9IG5hbWUgfHwgYUNsYXNzLm5hbWU7XG5cbiAgICBjaGVjayhuYW1lLCBNYXRjaC5JZGVudGlmaWVyU3RyaW5nLCAnY2xhc3MgbmFtZSBtdXN0IGJlIGlkZW50aWZpZXIgc3RyaW5nJyk7XG5cbiAgICBpZiAodGhpcy5Gb3VuZGF0aW9uQ2xhc3MpIHtcbiAgICAgICAgaWYgKGFDbGFzcyAhPSB0aGlzLkZvdW5kYXRpb25DbGFzcylcbiAgICAgICAgICAgIGNoZWNrKGFDbGFzcywgTWF0Y2guU3ViY2xhc3ModGhpcy5Gb3VuZGF0aW9uQ2xhc3MpLCAnY2xhc3MgbXVzdCBiZSBhIHN1YihjbGFzcykgb2YgYSBmb3VuZGF0aW9uIGNsYXNzJyk7XG4gICAgfSBlbHNlXG4gICAgICAgIHRocm93IG5ldyBSZWdpc3RyeUVycm9yKCdmb3VuZGF0aW9uIGNsYXNzIG11c3QgYmUgc2V0IGJlZm9yZSBhZGRpbmcgY2xhc3NlcyB0byByZWdpc3RyeScpO1xuXG4gICAgaWYgKHRoaXMuX19yZWdpc3RlcmVkQ2xhc3Nlc1tuYW1lXSlcbiAgICAgICAgdGhyb3cgbmV3IFJlZ2lzdHJ5RXJyb3IoJ2NsYXNzIFwiJyArIG5hbWUgKyAnXCIgaXMgYWxyZWFkeSByZWdpc3RlcmVkJyk7XG5cbiAgICB0aGlzLl9fcmVnaXN0ZXJlZENsYXNzZXNbbmFtZV0gPSBhQ2xhc3M7XG59O1xuXG5cbi8qKlxuICogR2V0cyBjbGFzcyBmcm9tIHJlZ2lzdHJ5IGJ5IG5hbWVcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBDbGFzcyBuYW1lXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gZ2V0KG5hbWUpIHtcbiAgICBjaGVjayhuYW1lLCBTdHJpbmcsICdjbGFzcyBuYW1lIG11c3QgYmUgc3RyaW5nJyk7XG4gICAgcmV0dXJuIHRoaXMuX19yZWdpc3RlcmVkQ2xhc3Nlc1tuYW1lXTtcbn07XG5cblxuLyoqXG4gKiBSZW1vdmUgY2xhc3MgZnJvbSByZWdpc3RyeSBieSBpdHMgbmFtZS5cbiAqIElmIGNsYXNzIGlzIG5vdCByZWdpc3RlcmVkLCB0aGlzIG1ldGhvZCB3aWxsIHRocm93IGFuIGV4Y2VwdGlvbi5cbiAqIFxuICogQHBhcmFtIHtTdHJpbmd8RnVuY3Rpb259IG5hbWVPckNsYXNzIENsYXNzIG5hbWUuIElmIGNsYXNzIGNvbnN0cnVjdG9yIGlzIHN1cHBsaWVkLCBpdHMgbmFtZSB3aWxsIGJlIHVzZWQuXG4gKi9cbmZ1bmN0aW9uIHJlbW92ZShuYW1lT3JDbGFzcykge1xuICAgIGNoZWNrKG5hbWVPckNsYXNzLCBNYXRjaC5PbmVPZihTdHJpbmcsIEZ1bmN0aW9uKSwgJ2NsYXNzIG9yIG5hbWUgbXVzdCBiZSBzdXBwbGllZCcpO1xuXG4gICAgdmFyIG5hbWUgPSB0eXBlb2YgbmFtZU9yQ2xhc3MgPT0gJ3N0cmluZydcbiAgICAgICAgICAgICAgICAgICAgICAgID8gbmFtZU9yQ2xhc3NcbiAgICAgICAgICAgICAgICAgICAgICAgIDogbmFtZU9yQ2xhc3MubmFtZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIFxuICAgIGlmICghIHRoaXMuX19yZWdpc3RlcmVkQ2xhc3Nlc1tuYW1lXSlcbiAgICAgICAgdGhyb3cgbmV3IFJlZ2lzdHJ5RXJyb3IoJ2NsYXNzIGlzIG5vdCByZWdpc3RlcmVkJyk7XG5cbiAgICBkZWxldGUgdGhpcy5fX3JlZ2lzdGVyZWRDbGFzc2VzW25hbWVdO1xufTtcblxuXG4vKipcbiAqIFJlbW92ZXMgYWxsIGNsYXNzZXMgZnJvbSByZWdpc3RyeS5cbiAqL1xuZnVuY3Rpb24gY2xlYW4oKSB7XG4gICAgdGhpcy5fX3JlZ2lzdGVyZWRDbGFzc2VzID0ge307XG59O1xuXG5cbi8qKlxuICogU2V0cyBgRm91bmRhdGlvbkNsYXNzYCBvZiB0aGUgcmVnaXN0cnkuIEl0IHNob3VsZCBiZSBzZXQgYmVmb3JlIGFueSBjbGFzcyBjYW4gYmUgYWRkZWQuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gRm91bmRhdGlvbkNsYXNzIEFueSBjbGFzcyB0aGF0IHdpbGwgYmUgYWRkZWQgdG8gdGhlIHJlZ2lzdHJ5IHNob3VsZCBiZSBhIHN1YmNsYXNzIG9mIHRoaXMgY2xhc3MuIEZvdW5kYXRpb25DbGFzcyBpdHNlbGYgY2FuIGJlIGFkZGVkIHRvIHRoZSByZWdpc3RyeSB0b28uXG4gKi9cbmZ1bmN0aW9uIHNldENsYXNzKEZvdW5kYXRpb25DbGFzcykge1xuICAgIGNoZWNrKEZvdW5kYXRpb25DbGFzcywgRnVuY3Rpb24pO1xuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgJ0ZvdW5kYXRpb25DbGFzcycsIEZvdW5kYXRpb25DbGFzcywgXy5FTlVNKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIEF0dHJpYnV0ZSA9IHJlcXVpcmUoJy4vYV9jbGFzcycpXG4gICAgLCBBdHRyaWJ1dGVFcnJvciA9IHJlcXVpcmUoJy4uL3V0aWwvZXJyb3InKS5BdHRyaWJ1dGVcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4uL2NvbmZpZycpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5cbnZhciBBVFRSSUJVVEVfUkVHRVhQPSAvXihbXlxcOlxcW1xcXV0qKSg/OlxcWyhbXlxcOlxcW1xcXV0qKVxcXSk/XFw6PyhbXjpdKikkL1xuICAgICwgRkFDRVRTX1NQTElUX1JFR0VYUCA9IC9cXHMqKD86XFwsfFxccylcXHMqL1xuICAgICwgQVRUUklCVVRFX1RFTVBMQVRFID0gJyVjb21wQ2xhc3MlY29tcEZhY2V0czolY29tcE5hbWUnO1xuXG5cbi8qKlxuICogYG1pbG8uYXR0cmlidXRlcy5iaW5kYFxuICogQmluZEF0dHJpYnV0ZSBjbGFzcyBwYXJzZXMvdmFsaWRhdGVzL2V0Yy4gYW4gYXR0cmlidXRlIHRoYXQgYmluZHMgRE9NIGVsZW1lbnRzIHRvIG1pbG8gY29tcG9uZW50cy5cbiAqIFBvc3NpYmxlIGF0dHJpYnV0ZSB2YWx1ZXMgYXJlOlxuICpcbiAqIC0gYDpteVZpZXdgIC0gb25seSBjb21wb25lbnQgbmFtZVxuICogLSBgVmlldzpteVZpZXdgIC0gY2xhc3MgYW5kIGNvbXBvbmVudCBuYW1lXG4gKiAtIGBbRXZlbnRzLCBEYXRhXTpteVZpZXdgIC0gZmFjZXRzIGFuZCBjb21wb25lbnQgbmFtZVxuICogLSBgVmlld1tFdmVudHNdOm15Vmlld2AgLSBjbGFzcywgZmFjZXQocykgYW5kIGNvbXBvbmVudCBuYW1lXG4gKlxuICogU2VlIFtiaW5kZXJdKC4uL2JpbmRlci5qcy5odG1sKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi5cbiAqL1xudmFyIEJpbmRBdHRyaWJ1dGUgPSBfLmNyZWF0ZVN1YmNsYXNzKEF0dHJpYnV0ZSwgJ0JpbmRBdHRyaWJ1dGUnLCB0cnVlKTtcblxuXG4vKipcbiAqICMjIyNCaW5kQXR0cmlidXRlIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbYXR0ck5hbWVdKCNhdHRyTmFtZSlcbiAqIC0gW3BhcnNlXSgjcGFyc2UpXG4gKiAtIFt2YWxpZGF0ZV0oI3ZhbGlkYXRlKVxuICogLSBbcmVuZGVyXSgjcmVuZGVyKVxuICovXG5fLmV4dGVuZFByb3RvKEJpbmRBdHRyaWJ1dGUsIHtcbiAgICBhdHRyTmFtZTogYXR0ck5hbWUsXG4gICAgcGFyc2U6IHBhcnNlLFxuICAgIHZhbGlkYXRlOiB2YWxpZGF0ZSxcbiAgICByZW5kZXI6IHJlbmRlclxufSk7XG5cblxuLyoqXG4gKiBCaW5kQXR0cmlidXRlIGNsYXNzIG1ldGhvZHNcbiAqXG4gKiAtIFtzZXRJbmZvXSgjQmluZEF0dHJpYnV0ZSQkc2V0SW5mbylcbiAqL1xuXy5leHRlbmQoQmluZEF0dHJpYnV0ZSwge1xuICAgIHNldEluZm86IEJpbmRBdHRyaWJ1dGUkJHNldEluZm9cbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQmluZEF0dHJpYnV0ZTtcblxuXG4vKipcbiAqIEJpbmRBdHRyaWJ1dGUgaW5zdGFuY2UgbWV0aG9kIHRoYXQgcmV0dXJucyBhdHRyaWJ1dGUgbmFtZSwgYnkgZGVmYXVsdCAtIGAnbWwtYmluZCdgLlxuICogVG8gY29uZmlndXJlIGJpbmQgYXR0cmlidXRlIG5hbWUgdXNlOlxuICogYGBgXG4gKiBtaWxvLmNvbmZpZyh7IGF0dHJzOiB7IGJpbmQ6ICdjYy1iaW5kJyB9IH0pOyAvLyB3aWxsIHNldCBiaW5kIGF0dHJpYnV0ZSB0byAnY2MtYmluZCdcbiAqIGBgYFxuICpcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gYXR0ck5hbWUoKSB7XG4gICAgcmV0dXJuIGNvbmZpZy5hdHRycy5iaW5kO1xufVxuXG5cbi8qKlxuICogQmluZEF0dHJpYnV0ZSBpbnN0YW5jZSBtZXRob2QgdGhhdCBwYXJzZXMgYmluZCBhdHRyaWJ1dGUgaWYgaXQgaXMgcHJlc2VudCBvbiB0aGUgZWxlbWVudC5cbiAqIEl0IGRlZmluZXMgcHJvcGVydGllcyBgY29tcENsYXNzYCwgYGNvbXBGYWNldHNgIGFuZCBgY29tcE5hbWVgIG9uIEJpbmRBdHRyaWJ1dGUgaW5zdGFuY2UuXG4gKiBSZXR1cm5zIHRoZSBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICpcbiAqIEByZXR1cm4ge0JpbmRBdHRyaWJ1dGV9XG4gKi9cbiBmdW5jdGlvbiBwYXJzZSgpIHtcbiAgICBpZiAoISB0aGlzLm5vZGUpIHJldHVybjtcblxuICAgIHZhciB2YWx1ZSA9IHRoaXMuZ2V0KCk7XG5cbiAgICBpZiAodmFsdWUpXG4gICAgICAgIHZhciBiaW5kVG8gPSB2YWx1ZS5tYXRjaChBVFRSSUJVVEVfUkVHRVhQKTtcblxuICAgIGlmICghIGJpbmRUbylcbiAgICAgICAgdGhyb3cgbmV3IEF0dHJpYnV0ZUVycm9yKCdpbnZhbGlkIGJpbmQgYXR0cmlidXRlICcgKyB2YWx1ZSk7XG5cbiAgICB0aGlzLmNvbXBDbGFzcyA9IGJpbmRUb1sxXSB8fCAnQ29tcG9uZW50JztcbiAgICB0aGlzLmNvbXBGYWNldHMgPSAoYmluZFRvWzJdICYmIGJpbmRUb1syXS5zcGxpdChGQUNFVFNfU1BMSVRfUkVHRVhQKSkgfHwgdW5kZWZpbmVkO1xuICAgIHRoaXMuY29tcE5hbWUgPSBiaW5kVG9bM10gfHwgdW5kZWZpbmVkOyAvLyB1bmRlZmluZWQgaXMgbm90IHNhbWUgYXMgJydcblxuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogQmluZEF0dHJpYnV0ZSBpbnN0YW5jZSBtZXRob2QgdGhhdCB2YWxpZGF0ZXMgYmluZCBhdHRyaWJ1dGUsIHRocm93cyBpZiBpdCBoYXMgYW4gaW52YWxpZCB2YWx1ZS5cbiAqIFJldHVybnMgdGhlIGluc3RhbmNlIGZvciBtZXRob2QgY2hhaW5pbmcuXG4gKlxuICogQHJldHVybiB7QmluZEF0dHJpYnV0ZX1cbiAqL1xuZnVuY3Rpb24gdmFsaWRhdGUoKSB7XG4gICAgY2hlY2sodGhpcy5jb21wTmFtZSwgTWF0Y2guSWRlbnRpZmllclN0cmluZyk7XG5cbiAgICBpZiAoISB0aGlzLmNvbXBDbGFzcylcbiAgICAgICAgdGhyb3cgbmV3IEF0dHJpYnV0ZUVycm9yKCdlbXB0eSBjb21wb25lbnQgY2xhc3MgbmFtZSAnICsgdGhpcy5jb21wQ2xhc3MpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBCaW5kQXR0cmlidXRlIGluc3RhbmNlIG1ldGhvZCB0aGF0IHJldHVybnMgdGhlIGF0dHJpYnV0ZSB2YWx1ZSBmb3IgZ2l2ZW4gdmFsdWVzIG9mIHByb3BlcnRpZXMgYGNvbXBDbGFzc2AsIGBjb21wTmFtZWAgYW5kIGBjb21wRmFjZXRzYC5cbiAqIElmIGB0aGlzLmNvbXBOYW1lYCBpcyBub3Qgc2V0IGl0IHdpbGwgYmUgZ2VuZXJhdGVkIGF1dG9tYXRpY2FsbHkuXG4gKlxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiByZW5kZXIoKSB7XG4gICAgdGhpcy5jb21wTmFtZSA9IHRoaXMuY29tcE5hbWUgfHwgbWlsby51dGlsLmNvbXBvbmVudE5hbWUoKTtcbiAgICByZXR1cm4gQVRUUklCVVRFX1RFTVBMQVRFXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJyVjb21wQ2xhc3MnLCB0aGlzLmNvbXBDbGFzcyB8fCAnJylcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgnJWNvbXBGYWNldHMnLCB0aGlzLmNvbXBGYWNldHMgJiYgdGhpcy5jb21wRmFjZXRzLmxlbmd0aFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/ICdbJyArIHRoaXMuY29tcEZhY2V0cy5qb2luKCcsICcpICsgJ10nXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogJycpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJyVjb21wTmFtZScsIHRoaXMuY29tcE5hbWUpO1xufVxuXG5cbi8qKlxuICogQmluZEF0dHJpYnV0ZSBjbGFzcyBtZXRob2RcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWxcbiAqIEBwYXJhbSB7U3RyaW5nfSBjb21wb25lbnRDbGFzcyBvcHRpb25hbCBjbGFzcyBuYW1lXG4gKiBAcGFyYW0ge1N0cmluZ30gY29tcG9uZW50TmFtZSBvcHRpb25hbFxuICogQHBhcmFtIHtBcnJheTxTdHJpbmc+fSBjb21wb25lbnRGYWNldHMgb3B0aW9uYWwgZXh0cmEgZmFjZXQgdG8gYWRkIHRvIHRoZSBjbGFzc1xuICovXG5mdW5jdGlvbiBCaW5kQXR0cmlidXRlJCRzZXRJbmZvKGVsLCBjb21wb25lbnRDbGFzcywgY29tcG9uZW50TmFtZSwgY29tcG9uZW50RmFjZXRzKSB7XG4gICAgdmFyIGF0dHIgPSBuZXcgQmluZEF0dHJpYnV0ZShlbCk7XG4gICAgXy5leHRlbmQoYXR0ciwge1xuICAgICAgICBjb21wQ2xhc3M6IGNvbXBvbmVudENsYXNzLFxuICAgICAgICBjb21wTmFtZTogY29tcG9uZW50TmFtZSxcbiAgICAgICAgY29tcEZhY2V0czogY29tcG9uZW50RmFjZXRzXG4gICAgfSk7XG4gICAgYXR0ci5kZWNvcmF0ZSgpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgdG9CZUltcGxlbWVudGVkID0gcmVxdWlyZSgnLi4vdXRpbC9lcnJvcicpLnRvQmVJbXBsZW1lbnRlZDtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IEF0dHJpYnV0ZTtcblxuXG4vKipcbiAqIEFuIGFic2N0cmFjdCBjbGFzcyBmb3IgcGFyc2luZyBhbmQgdmFsaWRhdGlvbiBvZiBlbGVtZW50IGF0dHJpYnV0ZXMuXG4gKiBTdWJjbGFzc2VzIHNob3VsZCBkZWZpbmUgbWV0aG9kcyBgYXR0ck5hbWVgLCBgcGFyc2VgLCBgdmFsaWRhdGVgIGFuZCBgcmVuZGVyYC5cbiAqXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsIERPTSBlbGVtZW50IHdoZXJlIGF0dHJpYnV0ZSBpcyBhdHRhY2hlZFxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWUgT3B0aW9uYWwgbmFtZSBvZiB0aGUgYXR0cmlidXRlLCB1c3VhbGx5IHN1cHBsaWVkIGJ5IHN1YmNsYXNzIHZpYSBgYXR0ck5hbWVgIG1ldGhvZFxuICovXG5mdW5jdGlvbiBBdHRyaWJ1dGUoZWwsIG5hbWUpIHtcbiAgICB0aGlzLm5hbWUgPSBuYW1lIHx8IHRoaXMuYXR0ck5hbWUoKTtcbiAgICB0aGlzLmVsID0gZWw7XG5cbiAgICAvLyBhdHRyaWJ1dGUgbm9kZVxuICAgIHRoaXMubm9kZSA9IGVsLmF0dHJpYnV0ZXNbdGhpcy5uYW1lXTtcbn1cblxuXG5fLmV4dGVuZChBdHRyaWJ1dGUsIHtcbiAgICByZW1vdmU6IEF0dHJpYnV0ZSQkcmVtb3ZlXG59KTtcblxuXG4vKipcbiAqICMjIyNBdHRyaWJ1dGUgaW5zdGFuY2UgbWV0aG9kcyMjIyNcbiAqXG4gKiAtIFtnZXRdKCNBdHRyaWJ1dGUkZ2V0KVxuICogLSBbc2V0XSgjQXR0cmlidXRlJHNldClcbiAqIC0gW2RlY29yYXRlXSgjQXR0cmlidXRlJGRlY29yYXRlKVxuICpcbiAqIFRoZSBmb2xsb3dpbmcgaW5zdGFuY2UgbWV0aG9kcyBzaG91bGQgYmUgZGVmaW5lZCBieSBzdWJjbGFzc1xuICpcbiAqIC0gYXR0ck5hbWUgLSBzaG91bGQgcmV0dXJuIGF0dHJpYnV0ZSBuYW1lXG4gKiAtIHBhcnNlIC0gc2hvdWxkIHBhcnNlIGF0dHJpYnV0ZSB2YWx1ZVxuICogLSB2YWxpZGF0ZSAtIHNob3VsZCB2YWxpZGF0ZSBhdHRyaWJ1dGUgdmFsdWUsIHRocm93aW5nIGV4Y2VwdGlvbiBpZiBpdCBpcyBpbmNvcnJlY3QgXG4gKiAtIHJlbmRlciAtIHNob3VsZCByZXR1cm4gYXR0cmlidXRlIHZhbHVlIGZvciBhIGdpdmVuIGF0dHJpYnV0ZSBzdGF0ZSAob3RoZXIgcHJvcGVydGllcywgYXMgZGVmaW5lZCBpbiBzdWJjbGFzcylcbiAqL1xuXy5leHRlbmRQcm90byhBdHRyaWJ1dGUsIHtcbiAgICBnZXQ6IEF0dHJpYnV0ZSRnZXQsXG4gICAgc2V0OiBBdHRyaWJ1dGUkc2V0LFxuICAgIHJlbW92ZTogQXR0cmlidXRlJHJlbW92ZSxcbiAgICBkZWNvcmF0ZTogQXR0cmlidXRlJGRlY29yYXRlLFxuXG4gICAgZGVzdHJveTogQXR0cmlidXRlJGRlc3Ryb3ksXG5cbiAgICAvLyBzaG91bGQgYmUgZGVmaW5lZCBpbiBzdWJjbGFzc1xuICAgIGF0dHJOYW1lOiB0b0JlSW1wbGVtZW50ZWQsXG4gICAgcGFyc2U6IHRvQmVJbXBsZW1lbnRlZCxcbiAgICB2YWxpZGF0ZTogdG9CZUltcGxlbWVudGVkLFxuICAgIHJlbmRlcjogdG9CZUltcGxlbWVudGVkXG59KTtcblxuXG5mdW5jdGlvbiBBdHRyaWJ1dGUkJHJlbW92ZShlbCwgZGVlcCkge1xuICAgIHZhciBuYW1lID0gdGhpcy5wcm90b3R5cGUuYXR0ck5hbWUoKTtcbiAgICBlbC5yZW1vdmVBdHRyaWJ1dGUobmFtZSk7XG5cbiAgICBpZiAoZGVlcCkge1xuICAgICAgICB2YXIgc2VsZWN0b3IgPSAnWycgKyBuYW1lICsgJ10nO1xuICAgICAgICB2YXIgY2hpbGRyZW4gPSBlbC5xdWVyeVNlbGVjdG9yQWxsKHNlbGVjdG9yKTtcbiAgICAgICAgXy5mb3JFYWNoKGNoaWxkcmVuLCBmdW5jdGlvbihjaGlsZEVsKSB7XG4gICAgICAgICAgICBjaGlsZEVsLnJlbW92ZUF0dHJpYnV0ZShuYW1lKTtcbiAgICAgICAgfSlcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gQXR0cmlidXRlJHJlbW92ZSgpIHtcbiAgICBkZWxldGUgdGhpcy5ub2RlO1xufVxuXG5cbmZ1bmN0aW9uIEF0dHJpYnV0ZSRkZXN0cm95KCkge1xuICAgIGRlbGV0ZSB0aGlzLmVsO1xuICAgIGRlbGV0ZSB0aGlzLm5vZGU7XG59XG5cbi8qKlxuICogQXR0cmlidXRlIGluc3RhbmNlIG1ldGhvZCB0aGF0IHJldHVybnMgYXR0cmlidXRlIHZhbHVlIGFzIHN0cmluZy5cbiAqXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIEF0dHJpYnV0ZSRnZXQoKSB7XG4gICAgcmV0dXJuIHRoaXMuZWwuZ2V0QXR0cmlidXRlKHRoaXMubmFtZSk7XG59XG5cblxuLyoqXG4gKiBBdHRyaWJ1dGUgaW5zdGFuY2UgbWV0aG9kIHRoYXQgc2V0cyBhdHRyaWJ1dGUgdmFsdWUuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHZhbHVlXG4gKi9cbmZ1bmN0aW9uIEF0dHJpYnV0ZSRzZXQodmFsdWUpIHtcbiAgICB0aGlzLmVsLnNldEF0dHJpYnV0ZSh0aGlzLm5hbWUsIHZhbHVlKTtcbn1cblxuXG4vKipcbiAqIEF0dHJpYnV0ZSBpbnN0YW5jZSBtZXRob2QgdGhhdCBkZWNvcmF0ZXMgZWxlbWVudCB3aXRoIGl0cyByZW5kZXJlZCB2YWx1ZS5cbiAqIFVzZXMgYHJlbmRlcmAgbWV0aG9kIHRoYXQgc2hvdWxkIGJlIGRlZmllbmQgaW4gc3ViY2xhc3MuXG4gKi9cbmZ1bmN0aW9uIEF0dHJpYnV0ZSRkZWNvcmF0ZSgpIHtcbiAgICB0aGlzLnNldCh0aGlzLnJlbmRlcigpKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIEF0dHJpYnV0ZSA9IHJlcXVpcmUoJy4vYV9jbGFzcycpXG4gICAgLCBBdHRyaWJ1dGVFcnJvciA9IHJlcXVpcmUoJy4uL3V0aWwvZXJyb3InKS5BdHRyaWJ1dGVcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4uL2NvbmZpZycpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cblxuLyoqXG4gKiBgbWlsby5hdHRyaWJ1dGVzLmxvYWRgXG4gKiBMb2FkQXR0cmlidXRlIGNsYXNzIHBhcnNlcy92YWxpZGF0ZXMvZXRjLiBhbiBhdHRyaWJ1dGUgdGhhdCBsb2FkcyBzdWItdmlld3MgaW50byB0aGUgcGFnZS5cbiAqIEF0dHJpYnV0ZSB2YWx1ZSBzaG91bGQgYmUgVVJMIG9mIHRoZSBmaWxlIHRvIGxvYWQgc3VidmlldyBmcm9tLlxuICogU2VlIFtsb2FkZXJdKC4uL2xvYWRlci5qcy5odG1sKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi5cbiAqL1xudmFyIExvYWRBdHRyaWJ1dGUgPSBfLmNyZWF0ZVN1YmNsYXNzKEF0dHJpYnV0ZSwgJ0xvYWRBdHRyaWJ1dGUnLCB0cnVlKTtcblxuXG4vKipcbiAqICMjIyNMb2FkQXR0cmlidXRlIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbYXR0ck5hbWVdKCNhdHRyTmFtZSlcbiAqIC0gW3BhcnNlXSgjcGFyc2UpXG4gKiAtIFt2YWxpZGF0ZV0oI3ZhbGlkYXRlKVxuICogLSBbcmVuZGVyXSgjcmVuZGVyKVxuICovXG5fLmV4dGVuZFByb3RvKExvYWRBdHRyaWJ1dGUsIHtcbiAgICBhdHRyTmFtZTogYXR0ck5hbWUsXG4gICAgcGFyc2U6IHBhcnNlLFxuICAgIHZhbGlkYXRlOiB2YWxpZGF0ZSxcbiAgICByZW5kZXI6IHJlbmRlclxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gTG9hZEF0dHJpYnV0ZTtcblxuXG4vKipcbiAqIEJpbmRBdHRyaWJ1dGUgaW5zdGFuY2UgbWV0aG9kIHRoYXQgcmV0dXJucyBhdHRyaWJ1dGUgbmFtZSwgYnkgZGVmYXVsdCAtIGAnbWwtbG9hZCdgLlxuICogVG8gY29uZmlndXJlIGxvYWQgYXR0cmlidXRlIG5hbWUgdXNlOlxuICogYGBgXG4gKiBtaWxvLmNvbmZpZyh7IGF0dHJzOiB7IGxvYWQ6ICdjYy1sb2FkJyB9IH0pOyAvLyB3aWxsIHNldCBiaW5kIGF0dHJpYnV0ZSB0byAnY2MtbG9hZCdcbiAqIGBgYFxuICpcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gYXR0ck5hbWUoKSB7XG4gICAgcmV0dXJuIGNvbmZpZy5hdHRycy5sb2FkO1xufVxuXG5cbi8qKlxuICogTG9hZEF0dHJpYnV0ZSBpbnN0YW5jZSBtZXRob2QgdGhhdCBwYXJzZXMgbG9hZCBhdHRyaWJ1dGUgaWYgaXQgaXMgcHJlc2VudCBvbiB0aGUgZWxlbWVudC5cbiAqIEl0IGRlZmluZXMgcHJvcGVydHkgYGxvYWRVcmxgIG9uIExvYWRBdHRyaWJ1dGUgaW5zdGFuY2UuXG4gKiBSZXR1cm5zIHRoZSBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICpcbiAqIEByZXR1cm4ge0xvYWRBdHRyaWJ1dGV9XG4gKi9cbmZ1bmN0aW9uIHBhcnNlKCkge1xuICAgIGlmICghIHRoaXMubm9kZSkgcmV0dXJuO1xuXG4gICAgdGhpcy5sb2FkVXJsID0gdGhpcy5nZXQoKTtcbiAgICByZXR1cm4gdGhpcztcbn1cblxuXG4vKipcbiAqIExvYWRBdHRyaWJ1dGUgaW5zdGFuY2UgbWV0aG9kIHRoYXQgc2hvdWxkIHZhbGlkYXRlIGxvYWQgYXR0cmlidXRlIGFuZCB0aHJvdyBpZiBpdCBoYXMgYW4gaW52YWxpZCB2YWx1ZS5cbiAqIFRPRE8gLSBpbXBsZW1lbnQgdXJsIHZhbGlkYXRpb24uXG4gKiBSZXR1cm5zIHRoZSBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICpcbiAqIEByZXR1cm4ge0xvYWRBdHRyaWJ1dGV9XG4gKi9cbmZ1bmN0aW9uIHZhbGlkYXRlKCkge1xuICAgIC8vIFRPRE8gdXJsIHZhbGlkYXRpb25cbiAgICByZXR1cm4gdGhpcztcbn1cblxuXG4vKipcbiAqIExvYWRBdHRyaWJ1dGUgaW5zdGFuY2UgbWV0aG9kIC0gcmV0dXJucyBVUkxcbiAqXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIHJlbmRlcigpIHtcbiAgICByZXR1cm4gdGhpcy5sb2FkVXJsO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIFN1YmNsYXNzZXMgb2YgW0F0dHJpYnV0ZV0oLi9hX2NsYXNzLmpzLmh0bWwpIGNsYXNzXG4gKlxuICogLSBbQmluZEF0dHJpYnV0ZV0oLi9hX2JpbmQuanMuaHRtbClcbiAqIC0gW0xvYWRBdHRyaWJ1dGVdKC4vYV9sb2FkLmpzLmh0bWwpXG4gKi9cbnZhciBhdHRyaWJ1dGVzID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgYmluZDogcmVxdWlyZSgnLi9hX2JpbmQnKSxcbiAgICBsb2FkOiByZXF1aXJlKCcuL2FfbG9hZCcpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgbWlsb01haWwgPSByZXF1aXJlKCcuL3NlcnZpY2VzL21haWwnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jb21wb25lbnRzL2NfcmVnaXN0cnknKVxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvY2ZfcmVnaXN0cnknKVxuICAgICwgQ29tcG9uZW50ID0gY29tcG9uZW50c1JlZ2lzdHJ5LmdldCgnQ29tcG9uZW50JylcbiAgICAsIENvbXBvbmVudEluZm8gPSByZXF1aXJlKCcuL2NvbXBvbmVudHMvY19pbmZvJylcbiAgICAsIFNjb3BlID0gcmVxdWlyZSgnLi9jb21wb25lbnRzL3Njb3BlJylcbiAgICAsIEJpbmRBdHRyaWJ1dGUgPSByZXF1aXJlKCcuL2F0dHJpYnV0ZXMvYV9iaW5kJylcbiAgICAsIEJpbmRlckVycm9yID0gcmVxdWlyZSgnLi91dGlsL2Vycm9yJykuQmluZGVyXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi91dGlsL2NoZWNrJylcbiAgICAsIHV0aWxEb20gPSByZXF1aXJlKCcuL3V0aWwvZG9tJylcbiAgICAsIE1hdGNoID0gIGNoZWNrLk1hdGNoO1xuXG5cbmJpbmRlci5zY2FuID0gc2NhbjtcbmJpbmRlci5jcmVhdGUgPSBjcmVhdGU7XG5iaW5kZXIudHdvUGFzcyA9IHR3b1Bhc3M7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBiaW5kZXI7XG5cblxuLyoqXG4gKiBgbWlsby5iaW5kZXJgXG4gKlxuICogUmVjdXJzaXZlbHkgc2NhbnMgdGhlIGRvY3VtZW50IHRyZWUgaW5zaWRlIGBzY29wZUVsYCAoZG9jdW1lbnQuYm9keSBieSBkZWZhdWx0KSBsb29raW5nIGZvciBfX21sLWJpbmRfXyBhdHRyaWJ1dGUgdGhhdCBzaG91bGQgY29udGFpbiB0aGUgY2xhc3MsIGFkZGl0aW9uYWwgZmFjZXRzIGFuZCB0aGUgbmFtZSBvZiB0aGUgY29tcG9uZW50IHRoYXQgc2hvdWxkIGJlIGNyZWF0ZWQgYW5kIGJvdW5kIHRvIHRoZSBlbGVtZW50LlxuICpcbiAqIFBvc3NpYmxlIHZhbHVlcyBvZiBfX21sLWJpbmRfXyBhdHRyaWJ1dGU6XG4gKlxuICogLSBgOm15Vmlld2AgLSBvbmx5IGNvbXBvbmVudCBuYW1lLiBBbiBpbnN0YW5jZSBvZiBDb21wb25lbnQgY2xhc3Mgd2lsbCBiZSBjcmVhdGVkIHdpdGhvdXQgYW55IGZhY2V0cy5cbiAqIC0gYFZpZXc6bXlWaWV3YCAtIGNsYXNzIGFuZCBjb21wb25lbnQgbmFtZS4gQW4gaW5zdGFuY2Ugb2YgVmlldyBjbGFzcyB3aWxsIGJlIGNyZWF0ZWQuXG4gKiAtIGBbRXZlbnRzLCBEYXRhXTpteVZpZXdgIC0gZmFjZXRzIGFuZCBjb21wb25lbnQgbmFtZS4gQW4gaW5zdGFuY2Ugb2YgQ29tcG9uZW50IGNsYXNzIHdpbGwgYmUgY3JlYXRlZCB3aXRoIHRoZSBhZGRpdGlvbiBvZiBmYWNldHMgRXZlbnRzIGFuZCBEYXRhLlxuICogLSBgVmlld1tFdmVudHMsIERhdGFdOm15Vmlld2AgLSBjbGFzcywgZmFjZXQocykgYW5kIGNvbXBvbmVudCBuYW1lLiBBbiBpbnN0YW5jZSBvZiBWaWV3IGNsYXNzIHdpbGwgYmUgY3JlYXRlZCB3aXRoIHRoZSBhZGRpdGlvbiBvZiBmYWNldHMgRXZlbnRzIGFuZCBEYXRhLlxuICpcbiAqIEZ1bmN0aW9uIHJldHVybnMgYW4gaW5zdGFuY2Ugb2YgW2BTY29wZWBdKC4vY29tcG9uZW50cy9zY29wZS5qcy5odG1sKSBjbGFzcyBjb250YWluaW5nIGFsbCBjb21wb25lbnRzIGNyZWF0ZWQgYXMgYSByZXN1bHQgb2Ygc2Nhbm5pbmcgRE9NLlxuICpcbiAqIElmIHRoZSBjb21wb25lbnQgaGFzIFtgQ29udGFpbmVyYF0oLi9jb21wb25lbnRzL2NfZmFjZXRzL0NvbnRhaW5lci5qcykgZmFjZXQsIGNoaWxkcmVuIG9mIHRoaXMgZWxlbWVudCB3aWxsIGJlIHN0b3JlZCBpbiB0aGUgYHNjb3BlYCBvYmplY3QsIGF2YWlsYWJsZSBhcyBzY29wZSBwcm9wZXJ0eSBvbiB0aGUgQ29udGFpbmVyIGZhY2V0IG9mIHRoaXMgY29tcG9uZW50LiBOYW1lcyBvZiBjb21wb25lbnRzIHdpdGhpbiB0aGUgc2NvcGUgc2hvdWxkIGJlIHVuaXF1ZSwgYnV0IHRoZXkgY2FuIGJlIHRoZSBzYW1lIGFzIHRoZSBuYW1lcyBvZiBjb21wb25lbnRzIGluIG91dGVyIHNjb3BlIChvciBzb21lIG90aGVyIHNjb3BlKS5cbiAqXG4gKiBAcGFyYW0ge0VsZW1lbnR9IHNjb3BlRWwgcm9vdCBlbGVtZW50IGluc2lkZSB3aGljaCBET00gd2lsbCBiZSBzY2FubmVkIGFuZCBib3VuZFxuICogQHBhcmFtIHtTY29wZX0gcm9vdFNjb3BlIE9wdGlvbmFsIFJvb3Qgc2NvcGUgb2JqZWN0IHdoZXJlIHRvcCBsZXZlbCBjb21wb25lbnRzIHdpbGwgYmUgc2F2ZWQuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGJpbmRSb290RWxlbWVudCBJZiBzZXQgdG8gZmFsc2UsIHRoZW4gdGhlIHJvb3QgZWxlbWVudCB3aWxsIG5vdCBiZSBib3VuZC4gVHJ1ZSBieSBkZWZhdWx0LlxuICogQHBhcmFtIHtCb29sZWFufSB0aHJvd09uRXJyb3JzIElmIHNldCB0byBmYWxzZSwgdGhlbiBlcnJvcnMgd2lsbCBvbmx5IGJlIGxvZ2dlZCB0byBjb25zb2xlLiBUcnVlIGJ5IGRlZmF1bHQuXG4gKiBAcmV0dXJuIHtTY29wZX1cbiAqL1xuZnVuY3Rpb24gYmluZGVyKHNjb3BlRWwsIHJvb3RTY29wZSwgYmluZFJvb3RFbGVtZW50LCB0aHJvd09uRXJyb3JzKSB7XG4gICAgcmV0dXJuIGNyZWF0ZUJpbmRlclNjb3BlKHNjb3BlRWwsIGZ1bmN0aW9uKHNjb3BlLCBlbCwgYXR0ciwgdGhyb3dPbkVycm9ycykge1xuICAgICAgICB2YXIgaW5mbyA9IG5ldyBDb21wb25lbnRJbmZvKHNjb3BlLCBlbCwgYXR0ciwgdGhyb3dPbkVycm9ycyk7XG4gICAgICAgIHJldHVybiBDb21wb25lbnQuY3JlYXRlKGluZm8sIHRocm93T25FcnJvcnMpO1xuICAgIH0sIHJvb3RTY29wZSwgYmluZFJvb3RFbGVtZW50LCB0aHJvd09uRXJyb3JzKTtcbn1cblxuXG4vLyBiaW5kIGluIHR3byBwYXNzZXNcbmZ1bmN0aW9uIHR3b1Bhc3Moc2NvcGVFbCwgcm9vdFNjb3BlLCBiaW5kUm9vdEVsZW1lbnQsIHRocm93T25FcnJvcnMpIHtcbiAgICB2YXIgc2NhblNjb3BlID0gYmluZGVyLnNjYW4oc2NvcGVFbCwgcm9vdFNjb3BlLCBiaW5kUm9vdEVsZW1lbnQsIHRocm93T25FcnJvcnMpO1xuICAgIHJldHVybiBiaW5kZXIuY3JlYXRlKHNjYW5TY29wZSwgdW5kZWZpbmVkLCB0aHJvd09uRXJyb3JzKTtcbn1cblxuXG4vLyBzY2FuIERPTSBmb3IgQmluZEF0dHJpYnV0ZVxuZnVuY3Rpb24gc2NhbihzY29wZUVsLCByb290U2NvcGUsIGJpbmRSb290RWxlbWVudCwgdGhyb3dPbkVycm9ycykge1xuICAgIHJldHVybiBjcmVhdGVCaW5kZXJTY29wZShzY29wZUVsLCBmdW5jdGlvbihzY29wZSwgZWwsIGF0dHIsIHRocm93T25FcnJvcnMpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBDb21wb25lbnRJbmZvKHNjb3BlLCBlbCwgYXR0ciwgdGhyb3dPbkVycm9ycyk7XG4gICAgfSwgcm9vdFNjb3BlLCBiaW5kUm9vdEVsZW1lbnQsIHRocm93T25FcnJvcnMpO1xufVxuXG5cbi8vIGNyZWF0ZSBib3VuZCBjb21wb25lbnRzXG5mdW5jdGlvbiBjcmVhdGUoc2NhblNjb3BlLCBob3N0T2JqZWN0LCB0aHJvd09uRXJyb3JzKSB7XG4gICAgdmFyIHNjb3BlID0gbmV3IFNjb3BlKHNjYW5TY29wZS5fcm9vdEVsLCBob3N0T2JqZWN0KVxuICAgICAgICAsIGFkZE1ldGhvZCA9IHRocm93T25FcnJvcnMgPT09IGZhbHNlID8gJ19zYWZlQWRkJyA6ICdfYWRkJztcblxuICAgIHNjYW5TY29wZS5fZWFjaChmdW5jdGlvbihjb21wSW5mbykge1xuICAgICAgICAvLyBzZXQgY29ycmVjdCBjb21wb25lbnQncyBzY29wZVxuICAgICAgICB2YXIgaW5mbyA9IF8uY2xvbmUoY29tcEluZm8pXG4gICAgICAgIGluZm8uc2NvcGUgPSBzY29wZTtcblxuICAgICAgICAvLyBjcmVhdGUgY29tcG9uZW50XG4gICAgICAgIHZhciBhQ29tcG9uZW50ID0gQ29tcG9uZW50LmNyZWF0ZShpbmZvLCB0aHJvd09uRXJyb3JzKTtcblxuICAgICAgICBzY29wZVthZGRNZXRob2RdKGFDb21wb25lbnQsIGFDb21wb25lbnQubmFtZSk7XG4gICAgICAgIGlmIChhQ29tcG9uZW50LmNvbnRhaW5lcilcbiAgICAgICAgICAgIGFDb21wb25lbnQuY29udGFpbmVyLnNjb3BlID0gY3JlYXRlKGNvbXBJbmZvLmNvbnRhaW5lci5zY29wZSwgYUNvbXBvbmVudC5jb250YWluZXIsIHRocm93T25FcnJvcnMpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHNjb3BlO1xufVxuXG4vKipcbiAqIGBjcmVhdGVCaW5kZXJTY29wZWBcbiAqIEBwYXJhbSAge0VsZW1lbnR9IHNjb3BlRWwgICAgICAgICAgICAgc2NvcGVFbCByb290IGVsZW1lbnQgaW5zaWRlIHdoaWNoIERPTSB3aWxsIGJlIHNjYW5uZWQgYW5kIGJvdW5kIChkb2N1bWVudC5ib2R5IGJ5IGRlZmF1bHQpLlxuICogQHBhcmFtICB7RnVuY3Rpb259IHNjb3BlT2JqZWN0RmFjdG9yeSBTZWUgW2JpbmRlcl0oI21pbG8uYmluZGVyKVxuICogQHBhcmFtICB7U2NvcGV9IHJvb3RTY29wZSAgICAgICAgICAgICBPcHRpb25hbCBSb290IHNjb3BlIG9iamVjdCB3aGVyZSB0b3AgbGV2ZWwgY29tcG9uZW50cyB3aWxsIGJlIHNhdmVkLlxuICogQHBhcmFtICB7Qm9vbGVhbn0gYmluZFJvb3RFbGVtZW50ICAgICBJZiBzZXQgdG8gZmFsc2UsIHRoZW4gdGhlIHJvb3QgZWxlbWVudCB3aWxsIG5vdCBiZSBib3VuZC4gVHJ1ZSBieSBkZWZhdWx0LlxuICogQHBhcmFtICB7Qm9vbGVhbn0gdGhyb3dPbkVycm9ycyAgICAgICBJZiBzZXQgdG8gZmFsc2UsIHRoZW4gZXJyb3JzIHdpbGwgb25seSBiZSBsb2dnZWQgdG8gY29uc29sZS4gVHJ1ZSBieSBkZWZhdWx0LlxuICogQHJldHVybiB7U2NvcGV9ICAgICAgICAgICAgICAgICAgICAgICBbZGVzY3JpcHRpb25dXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUJpbmRlclNjb3BlKHNjb3BlRWwsIHNjb3BlT2JqZWN0RmFjdG9yeSwgcm9vdFNjb3BlLCBiaW5kUm9vdEVsZW1lbnQsIHRocm93T25FcnJvcnMpIHtcbiAgICB2YXIgc2NvcGVFbCA9IHNjb3BlRWwgfHwgZG9jdW1lbnQuYm9keVxuICAgICAgICAsIHNjb3BlID0gcm9vdFNjb3BlIHx8IG5ldyBTY29wZShzY29wZUVsKVxuICAgICAgICAsIGFkZE1ldGhvZCA9IHRocm93T25FcnJvcnMgPT09IGZhbHNlID8gJ19zYWZlQWRkJyA6ICdfYWRkJztcblxuICAgIGNyZWF0ZVNjb3BlRm9yRWxlbWVudChzY29wZSwgc2NvcGVFbCwgYmluZFJvb3RFbGVtZW50KTtcblxuICAgIHJldHVybiBzY29wZTtcblxuXG4gICAgZnVuY3Rpb24gY3JlYXRlU2NvcGVGb3JFbGVtZW50KHNjb3BlLCBlbCwgYmluZFJvb3RFbGVtZW50KSB7XG4gICAgICAgIC8vIGdldCBlbGVtZW50J3MgYmluZGluZyBhdHRyaWJ1dGUgKG1sLWJpbmQgYnkgZGVmYXVsdClcbiAgICAgICAgdmFyIGF0dHIgPSBuZXcgQmluZEF0dHJpYnV0ZShlbCk7XG5cbiAgICAgICAgLy8gaWYgZWxlbWVudCBoYXMgYmluZCBhdHRyaWJ1dGUgY3JhdGUgc2NvcGUgb2JqZWN0IChDb21wb25lbnQgb3IgQ29tcG9uZW50SW5mbylcbiAgICAgICAgaWYgKGF0dHIubm9kZSAmJiBiaW5kUm9vdEVsZW1lbnQgIT09IGZhbHNlKSB7XG4gICAgICAgICAgICB2YXIgc2NvcGVkT2JqZWN0ID0gc2NvcGVPYmplY3RGYWN0b3J5KHNjb3BlLCBlbCwgYXR0ciwgdGhyb3dPbkVycm9ycylcbiAgICAgICAgICAgICAgICAsIGlzQ29udGFpbmVyID0gdHlwZW9mIHNjb3BlZE9iamVjdCAhPSAndW5kZWZpbmVkJyAmJiBzY29wZWRPYmplY3QuY29udGFpbmVyO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gaWYgdGhlcmUgYXJlIGNoaWxkTm9kZXMgYWRkIGNoaWxkcmVuIHRvIG5ldyBzY29wZSBpZiB0aGlzIGVsZW1lbnQgaGFzIGNvbXBvbmVudCB3aXRoIENvbnRhaW5lciBmYWNldFxuICAgICAgICAvLyBvdGhlcndpc2UgY3JlYXRlIGEgbmV3IHNjb3BlXG4gICAgICAgIGlmIChlbC5jaGlsZE5vZGVzICYmIGVsLmNoaWxkTm9kZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICBpZiAoaXNDb250YWluZXIpIHtcbiAgICAgICAgICAgICAgICB2YXIgaW5uZXJTY29wZSA9IG5ldyBTY29wZShlbCk7XG4gICAgICAgICAgICAgICAgc2NvcGVkT2JqZWN0LmNvbnRhaW5lci5zY29wZSA9IGlubmVyU2NvcGU7XG4gICAgICAgICAgICAgICAgaW5uZXJTY29wZS5faG9zdE9iamVjdCA9IHNjb3BlZE9iamVjdC5jb250YWluZXI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNyZWF0ZVNjb3BlRm9yQ2hpbGRyZW4oZWwsIGlzQ29udGFpbmVyID8gaW5uZXJTY29wZSA6IHNjb3BlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGlmIHNjb3BlIHdhc24ndCBwcmV2aW91c2x5IGNyZWF0ZWQgb24gY29udGFpbmVyIGZhY2V0LCBjcmVhdGUgZW1wdHkgc2NvcGUgYW55d2F5XG4gICAgICAgIGlmIChpc0NvbnRhaW5lciAmJiAhIHNjb3BlZE9iamVjdC5jb250YWluZXIuc2NvcGUpXG4gICAgICAgICAgICBzY29wZWRPYmplY3QuY29udGFpbmVyLnNjb3BlID0gbmV3IFNjb3BlKGVsKTtcblxuXG4gICAgICAgIC8vIFRPRE8gY29uZGl0aW9uIGFmdGVyICYmIGlzIGEgaGFjaywgc2hvdWxkIG5vdCBiZSB1c2VkIVxuICAgICAgICBpZiAoc2NvcGVkT2JqZWN0KSAvLyAmJiAhIHNjb3BlW2F0dHIuY29tcE5hbWVdKVxuICAgICAgICAgICAgc2NvcGVbYWRkTWV0aG9kXShzY29wZWRPYmplY3QsIGF0dHIuY29tcE5hbWUpO1xuXG4gICAgICAgIC8vIF8uZGVmZXIocG9zdENoaWxkcmVuQm91bmRNZXNzYWdlLCBlbCk7XG4gICAgICAgIHBvc3RDaGlsZHJlbkJvdW5kTWVzc2FnZShlbCk7XG5cbiAgICAgICAgcmV0dXJuIHNjb3BlZE9iamVjdDtcblxuXG4gICAgICAgIGZ1bmN0aW9uIHBvc3RDaGlsZHJlbkJvdW5kTWVzc2FnZShlbCkge1xuICAgICAgICAgICAgdmFyIGVsQ29tcCA9IENvbXBvbmVudC5nZXRDb21wb25lbnQoZWwpO1xuXG4gICAgICAgICAgICBpZiAoZWxDb21wKVxuICAgICAgICAgICAgICAgIGVsQ29tcC5wb3N0TWVzc2FnZVN5bmMoJ2NoaWxkcmVuYm91bmQnKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgZnVuY3Rpb24gY3JlYXRlU2NvcGVGb3JDaGlsZHJlbihjb250YWluZXJFbCwgc2NvcGUpIHtcbiAgICAgICAgdmFyIGNoaWxkcmVuID0gdXRpbERvbS5jaGlsZHJlbihjb250YWluZXJFbCk7XG5cbiAgICAgICAgXy5mb3JFYWNoKGNoaWxkcmVuLCBmdW5jdGlvbihub2RlKSB7XG4gICAgICAgICAgICBjcmVhdGVTY29wZUZvckVsZW1lbnQoc2NvcGUsIG5vZGUsIHRydWUpO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHNjb3BlO1xuICAgIH1cbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gPGEgbmFtZT1cImNsYXNzZXNcIj48L2E+XG4vLyBtaWxvLmNsYXNzZXNcbi8vIC0tLS0tLS0tLS0tXG5cbi8vIFRoaXMgbW9kdWxlIGNvbnRhaW5zIGZvdW5kYXRpb24gY2xhc3NlcyBhbmQgY2xhc3MgcmVnaXN0cmllcy5cblxudmFyIGNsYXNzZXMgPSB7XG4gICAgRmFjZXQ6IHJlcXVpcmUoJy4vYWJzdHJhY3QvZmFjZXQnKSxcbiAgICBGYWNldGVkT2JqZWN0OiByZXF1aXJlKCcuL2Fic3RyYWN0L2ZhY2V0ZWRfb2JqZWN0JyksXG4gICAgU2NvcGU6IHJlcXVpcmUoJy4vY29tcG9uZW50cy9zY29wZScpLFxuICAgIENsYXNzUmVnaXN0cnk6IHJlcXVpcmUoJy4vYWJzdHJhY3QvcmVnaXN0cnknKSxcbiAgICBNaXhpbjogcmVxdWlyZSgnLi9hYnN0cmFjdC9taXhpbicpLFxuICAgIE1lc3NhZ2VTb3VyY2U6IHJlcXVpcmUoJy4vbWVzc2VuZ2VyL21fc291cmNlJyksXG4gICAgTWVzc2VuZ2VyTWVzc2FnZVNvdXJjZTogcmVxdWlyZSgnLi9tZXNzZW5nZXIvbXNuZ3Jfc291cmNlJyksXG4gICAgTWVzc2VuZ2VyQVBJOiByZXF1aXJlKCcuL21lc3Nlbmdlci9tX2FwaScpLFxuICAgIERPTUV2ZW50c1NvdXJjZTogcmVxdWlyZSgnLi9jb21wb25lbnRzL21zZ19zcmMvZG9tX2V2ZW50cycpLFxuICAgIFRyYW5zYWN0aW9uOiByZXF1aXJlKCcuL2NvbW1hbmQvdHJhbnNhY3Rpb24nKSxcbiAgICBUcmFuc2FjdGlvbkhpc3Rvcnk6IHJlcXVpcmUoJy4vY29tbWFuZC90cmFuc2FjdGlvbl9oaXN0b3J5Jylcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3NlcztcbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBsb2dnZXIgPSByZXF1aXJlKCcuLi91dGlsL2xvZ2dlcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWN0aW9uc0hpc3Rvcnk7XG5cblxuLyoqXG4gKiBTdG9yZXMgbGlzdCBvZiBjb21tYW5kcyBvciB0cmFuc2FjdGlvbnNcbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqIEBwYXJhbSB7TnVtYmVyfSBtYXhMZW5ndGhcbiAqL1xuZnVuY3Rpb24gQWN0aW9uc0hpc3RvcnkobWF4TGVuZ3RoKSB7XG4gICAgdGhpcy5fbWF4TGVuZ3RoID0gbWF4TGVuZ3RoIHx8IEluZmluaXR5O1xuICAgIHRoaXMuYWN0aW9ucyA9IFtdO1xuICAgIHRoaXMucG9zaXRpb24gPSAwO1xufVxuXG5cbl8uZXh0ZW5kUHJvdG8oQWN0aW9uc0hpc3RvcnksIHtcbiAgICBzdG9yZTogQWN0aW9uc0hpc3Rvcnkkc3RvcmUsXG4gICAgZGVsZXRlTGFzdDogQWN0aW9uc0hpc3RvcnkkZGVsZXRlTGFzdCxcbiAgICB1bmRvOiBBY3Rpb25zSGlzdG9yeSR1bmRvLFxuICAgIHJlZG86IEFjdGlvbnNIaXN0b3J5JHJlZG8sXG4gICAgdW5kb0FsbDogQWN0aW9uc0hpc3RvcnkkdW5kb0FsbCxcbiAgICByZWRvQWxsOiBBY3Rpb25zSGlzdG9yeSRyZWRvQWxsLFxuICAgIHVuZG9BbGxBc3luYzogQWN0aW9uc0hpc3RvcnkkdW5kb0FsbEFzeW5jLFxuICAgIHJlZG9BbGxBc3luYzogQWN0aW9uc0hpc3RvcnkkcmVkb0FsbEFzeW5jLFxuICAgIGVhY2g6IEFjdGlvbnNIaXN0b3J5JGVhY2gsXG4gICAgZWFjaFJldmVyc2U6IEFjdGlvbnNIaXN0b3J5JGVhY2hSZXZlcnNlLFxuICAgIGdldExhc3RBY3Rpb246IEFjdGlvbnNIaXN0b3J5JGdldExhc3RBY3Rpb24sXG5cbiAgICBnZXREZXNjcmlwdGlvbjogQWN0aW9uc0hpc3RvcnkkZ2V0RGVzY3JpcHRpb25cbn0pO1xuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JHN0b3JlKGNvbW1hbmQpIHtcbiAgICBfdHJ1bmNhdGVUb0N1cnJlbnRQb3NpdGlvbi5jYWxsKHRoaXMpO1xuICAgIHRoaXMuYWN0aW9ucy5wdXNoKGNvbW1hbmQpO1xuXG4gICAgaWYgKHRoaXMuYWN0aW9ucy5sZW5ndGggPiB0aGlzLl9tYXhMZW5ndGgpIHtcbiAgICAgICAgdmFyIGFjdCA9IHRoaXMuYWN0aW9ucy5zaGlmdCgpO1xuICAgICAgICBhY3QuZGVzdHJveSgpO1xuICAgIH1cblxuICAgIHRoaXMucG9zaXRpb24gPSB0aGlzLmFjdGlvbnMubGVuZ3RoO1xuICAgIHJldHVybiB0aGlzLnBvc2l0aW9uIC0gMVxufVxuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JGRlbGV0ZUxhc3QoKSB7XG4gICAgaWYgKCF0aGlzLmFjdGlvbnMubGVuZ3RoKSByZXR1cm47XG4gICAgdGhpcy5wb3NpdGlvbi0tO1xuICAgIHRoaXMuYWN0aW9ucy5sZW5ndGgtLTtcbn1cblxuXG5mdW5jdGlvbiBfdHJ1bmNhdGVUb0N1cnJlbnRQb3NpdGlvbigpIHtcbiAgICBmb3IgKHZhciBpID0gdGhpcy5wb3NpdGlvbjsgaSA8IHRoaXMuYWN0aW9ucy5sZW5ndGg7IGkrKylcbiAgICAgICAgdGhpcy5hY3Rpb25zW2ldLmRlc3Ryb3koKTtcbiAgICB0aGlzLmFjdGlvbnMubGVuZ3RoID0gdGhpcy5wb3NpdGlvbjtcbn1cblxuXG5mdW5jdGlvbiBBY3Rpb25zSGlzdG9yeSR1bmRvKGNiKSB7XG4gICAgaWYgKHRoaXMucG9zaXRpb24gPT0gMCkgcmV0dXJuOyAvLyBub3RoaW5nIHRvIHVuZG9cbiAgICB2YXIgYWN0ID0gdGhpcy5hY3Rpb25zWy0tdGhpcy5wb3NpdGlvbl07XG4gICAgYWN0LnVuZG8oY2IpO1xuICAgIHJldHVybiBhY3Q7XG59XG5cblxuZnVuY3Rpb24gQWN0aW9uc0hpc3RvcnkkcmVkbyhjYikge1xuICAgIGlmICh0aGlzLnBvc2l0aW9uID09IHRoaXMuYWN0aW9ucy5sZW5ndGgpIHJldHVybjsgLy8gbm90aGluZyB0byByZWRvXG4gICAgdmFyIGFjdCA9IHRoaXMuYWN0aW9uc1t0aGlzLnBvc2l0aW9uKytdO1xuICAgIGFjdC5yZWRvKGNiKTtcbiAgICByZXR1cm4gYWN0O1xufVxuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JHVuZG9BbGwoKSB7XG4gICAgd2hpbGUgKHRoaXMucG9zaXRpb24pIHRoaXMudW5kbygpO1xufVxuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JHJlZG9BbGwoKSB7XG4gICAgd2hpbGUgKHRoaXMucG9zaXRpb24gPCB0aGlzLmFjdGlvbnMubGVuZ3RoKSB0aGlzLnJlZG8oKTtcbn1cblxuXG5mdW5jdGlvbiBBY3Rpb25zSGlzdG9yeSR1bmRvQWxsQXN5bmMoY2IpIHtcbiAgICBpZiAodGhpcy5wb3NpdGlvbikge1xuICAgICAgICB0aGlzLnVuZG8oKTtcbiAgICAgICAgaWYgKHRoaXMucG9zaXRpb24pXG4gICAgICAgICAgICBfLmRlZmVyTWV0aG9kKHRoaXMsICd1bmRvQWxsQXN5bmMnLCBjYik7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGlmIChjYikgXy5kZWZlcihjYik7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JHJlZG9BbGxBc3luYyhjYikge1xuICAgIGlmICh0aGlzLnBvc2l0aW9uIDwgdGhpcy5hY3Rpb25zLmxlbmd0aCkge1xuICAgICAgICB0aGlzLnJlZG8oKTtcbiAgICAgICAgaWYgKHRoaXMucG9zaXRpb24gPCB0aGlzLmFjdGlvbnMubGVuZ3RoKSBcbiAgICAgICAgICAgIF8uZGVmZXJNZXRob2QodGhpcywgJ3JlZG9BbGxBc3luYycsIGNiKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgaWYgKGNiKSBfLmRlZmVyKGNiKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gQWN0aW9uc0hpc3RvcnkkZWFjaChmdW5jT3JNZXRob2QsIHRoaXNBcmcpIHtcbiAgICB2YXIgZnVuYyA9IHR5cGVvZiBmdW5jT3JNZXRob2QgPT0gJ3N0cmluZydcbiAgICAgICAgICAgICAgICA/IGZ1bmN0aW9uKGFjdCkgeyBhY3RbZnVuY09yTWV0aG9kXSgpOyB9XG4gICAgICAgICAgICAgICAgOiBmdW5jT3JNZXRob2Q7XG5cbiAgICB0aGlzLmFjdGlvbnMuZm9yRWFjaChmdW5jLCB0aGlzQXJnIHx8IHRoaXMpO1xufVxuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JGVhY2hSZXZlcnNlKGZ1bmNPck1ldGhvZCwgdGhpc0FyZykge1xuICAgIHRoaXMuYWN0aW9ucy5yZXZlcnNlKCk7XG4gICAgdGhpcy5lYWNoKGZ1bmNPck1ldGhvZCwgdGhpc0FyZyk7XG4gICAgdGhpcy5hY3Rpb25zLnJldmVyc2UoKTtcbn1cblxuXG5mdW5jdGlvbiBBY3Rpb25zSGlzdG9yeSRnZXRMYXN0QWN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLnBvc2l0aW9uICYmIHRoaXMuYWN0aW9uc1t0aGlzLnBvc2l0aW9uIC0gMV07XG59XG5cblxuZnVuY3Rpb24gQWN0aW9uc0hpc3RvcnkkZ2V0RGVzY3JpcHRpb24oKSB7XG4gICAgdmFyIGFjdGlvbnMgPSB0aGlzLmFjdGlvbnMubWFwKGZ1bmN0aW9uKGFjdCkge1xuICAgICAgICByZXR1cm4gYWN0LmdldERlc2NyaXB0aW9uKCk7XG4gICAgfSk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgYWN0aW9uczogYWN0aW9ucyxcbiAgICAgICAgcG9zaXRpb246IHRoaXMucG9zaXRpb24sXG4gICAgICAgIGxlbmd0aDogYWN0aW9ucy5sZW5ndGhcbiAgICB9O1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2xhc3NSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2Fic3RyYWN0L3JlZ2lzdHJ5JylcbiAgICAsIENvbW1hbmQgPSByZXF1aXJlKCcuL2luZGV4Jyk7XG5cbi8qKlxuICogYG1pbG8ucmVnaXN0cnkuY29tcG9uZW50c2BcbiAqIEFuIGluc3RhbmNlIG9mIFtDbGFzc1JlZ2lzdHJ5XSguLi9hYnN0cmFjdC9yZWdpc3RyeS5qcy5odG1sKSBjbGFzcyB0aGF0IGlzIHVzZWQgYnkgbWlsbyB0byByZWdpc3RlciBhbmQgZmluZCBjb21wb25lbnRzLlxuICovXG52YXIgY29tbWFuZHNSZWdpc3RyeSA9IG5ldyBDbGFzc1JlZ2lzdHJ5KENvbW1hbmQpO1xuXG4vLyBhZGQgY29tbW9uIGFuY2VzdG9yIHRvIGFsbCBjb21wb25lbnRzIHRvIHRoZSByZWdpc3RyeS5cbmNvbW1hbmRzUmVnaXN0cnkuYWRkKENvbW1hbmQpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbW1hbmRzUmVnaXN0cnk7XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgY2hlY2sgPSByZXF1aXJlKCcuLi91dGlsL2NoZWNrJylcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2hcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uL3V0aWwvbG9nZ2VyJyk7XG5cblxudmFyIFVORE9fQ09NTUFORCA9ICdfdW5kb0NvbW1hbmQnO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQ29tbWFuZDtcblxuXG4vKipcbiAqIENvbW1hbmQgY2xhc3MgdG8gaW1wbGVtZW50IFwiY29tbWFuZCBwYXR0ZXJuXCIgLSBwYWNrYWdpbmcgbGwgaW5mb3JtYXRpb24gbmVjZXNzYXJ5IGZvciBkZWxheWVkIG1ldGhvZCBleGVjdXRpb25cbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgbWV0aG9kIG5hbWUgb3IgZnVuY3Rpb24gdG8gYmUgZXhlY3V0ZWRcbiAqIEBwYXJhbSB7TGlzdH0gKmFyZ3VtZW50cyBwYXJhbWV0ZXJzIHRvIGJlIHBhc3NlZCB0byBtZXRob2Qgb3IgZnVuY3Rpb25cbiAqL1xuZnVuY3Rpb24gQ29tbWFuZChmdW5jKSB7IC8vICwgLi4uIGFyZ3VtZW50c1xuICAgIHRoaXMuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbi8qKlxuICogQ29tbWFuZCBpbnN0YW5jZSBtZXRob2RzXG4gKiBcbiAqIC0gW2luaXRdKCNDb21tYW5kJGV4ZWN1dGUpIC0gaW5pdGlhbGl6ZSBjb21tYW5kLCBzaG91bGQgYmUgb3ZlcndyaXR0ZW4gYnkgc3ViY2xhc3Nlc1xuICogLSBbZXhlY3V0ZV0oI0NvbW1hbmQkZXhlY3V0ZSkgLSBleGVjdXRlIGNvbW1hbmRcbiAqIC0gW3NldFVuZG9dKCNDb21tYW5kJHNldFVuZG8pIC0gc2V0IHVuZG8gY29tbWFuZCBmb3IgdGhpcyBjb21tYW5kXG4gKiAtIFtnZXRVbmRvXSgjQ29tbWFuZCRnZXRVbmRvKSAtIGdldCB1bmRvIGNvbW1hbmQgb2YgdGhpcyBjb21tYW5kXG4gKiAtIFtzZXRBcmd1bWVudHNdKCNDb21tYW5kJHNldEFyZ3VtZW50cykgLSBzZXQgY29tbWFuZHMgYXJndW1lbnRzXG4gKiAtIFthZGRBcmd1bWVudHNdKCNDb21tYW5kJGFkZEFyZ3VtZW50cykgLSBhZGQgYXJndW1lbnRzIHRvIGNvbW1hbmRcbiAqIC0gW2Rlc3Ryb3ldKCNDb21tYW5kJGRlc3Ryb3kpXG4gKi9cbl8uZXh0ZW5kUHJvdG8oQ29tbWFuZCwge1xuICAgIGluaXQ6IENvbW1hbmQkaW5pdCxcbiAgICBleGVjdXRlOiBDb21tYW5kJGV4ZWN1dGUsXG4gICAgc2V0VW5kbzogQ29tbWFuZCRzZXRVbmRvLFxuICAgIGdldFVuZG86IENvbW1hbmQkZ2V0VW5kbyxcbiAgICB1bmRvOiBDb21tYW5kJHVuZG8sXG4gICAgcmVkbzogQ29tbWFuZCRleGVjdXRlLCAvLyBzYW1lIGZvciBjb21tYW5kLCBkaWZmZXJlbnQgZm9yIHRyYW5zYWN0aW9uXG4gICAgc2V0QXJndW1lbnRzOiBDb21tYW5kJHNldEFyZ3VtZW50cyxcbiAgICBhZGRBcmd1bWVudHM6IENvbW1hbmQkYWRkQXJndW1lbnRzLFxuICAgIGdldEFyZ3VtZW50czogQ29tbWFuZCRnZXRBcmd1bWVudHMsXG4gICAgY2hhbmdlQXJndW1lbnRzOiBDb21tYW5kJGNoYW5nZUFyZ3VtZW50cyxcbiAgICBkZXN0cm95OiBDb21tYW5kJGRlc3Ryb3ksXG5cbiAgICBzZXRDb21tZW50OiBDb21tYW5kJHNldENvbW1lbnQsXG4gICAgZ2V0RGVzY3JpcHRpb246IENvbW1hbmQkZ2V0RGVzY3JpcHRpb25cbn0pO1xuXG5cbi8qKlxuICogQ29tbWFuZCBjbGFzcyBtZXRob2RzXG4gKlxuICogLSBbY3JlYXRlXSgjQ29tbWFuZCQkY3JlYXRlKSAtIGNvbW1hbmRzIGZhY3RvcnlcbiAqL1xuXy5leHRlbmQoQ29tbWFuZCwge1xuICAgIGNyZWF0ZTogQ29tbWFuZCQkY3JlYXRlLFxuICAgIGNyZWF0ZVdpdGhVbmRvOiBDb21tYW5kJCRjcmVhdGVXaXRoVW5kb1xufSk7XG5cblxuZnVuY3Rpb24gQ29tbWFuZCRpbml0KGZ1bmMpIHsgLy8gLCAuLi4gYXJndW1lbnRzXG4gICAgY2hlY2soZnVuYywgTWF0Y2guT3B0aW9uYWwoRnVuY3Rpb24pKTtcbiAgICB0aGlzLmZ1bmMgPSBmdW5jIHx8IGZ1bmN0aW9uKCl7fTtcbiAgICB0aGlzLmFyZ3MgPSBfLnNsaWNlKGFyZ3VtZW50cywgMSk7ICAgIFxufVxuXG5cbi8qKlxuICogRXhlY3V0ZSBjb21tYW5kIG1ha2luZyBjb21tYW5kIG9iamVjdCBhdmFpbGFibGUgdmlhIGZ1bmN0aW9uIHByb3BlcnR5LiBcbiAqL1xuZnVuY3Rpb24gQ29tbWFuZCRleGVjdXRlKGNiKSB7XG4gICAgdmFyIHJlc3VsdCA9IHRoaXMuZnVuYy5hcHBseSh0aGlzLCB0aGlzLmFyZ3MpO1xuICAgIGlmIChjYikgXy5kZWZlcihjYik7XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cblxuXG4vKipcbiAqIFNldCB1bmRvIGNvbW1hbmQgZm9yIHRoaXMgY29tbWFuZC4gVGhpcyBjb21tYW5kIGJlY29tZXMgdW5kbyBjb21tYW5kIGZvciB1bmRvIGNvbW1hbmQgKHNvIHVuZG8gY29tbWFuZCBjYW4gY2hhbmdlIHRoaXMgY29tbWFuZCBkdXJpbmcgaXRzIGV4ZWN1dGlvbikuXG4gKiBcbiAqIEBwYXJhbSB7Q29tbWFuZH0gdW5kb0NvbW1hbmRcbiAqL1xuZnVuY3Rpb24gQ29tbWFuZCRzZXRVbmRvKHVuZG9Db21tYW5kKSB7XG4gICAgaWYgKHRoaXNbVU5ET19DT01NQU5EXSlcbiAgICAgICAgbG9nZ2VyLndhcm4oJ0NvbW1hbmQgc2V0VW5kbzogdW5kbyBjb21tYW5kIGlzIGFscmVhZHkgc2V0Jyk7XG5cbiAgICB0aGlzW1VORE9fQ09NTUFORF0gPSB1bmRvQ29tbWFuZDtcbiAgICB1bmRvQ29tbWFuZFtVTkRPX0NPTU1BTkRdID0gdGhpcztcbn1cblxuXG4vKipcbiAqIFJldHVybnMgdW5kbyBjb21tYW5kIG9mIGEgZ2l2ZW4gY29tbWFuZFxuICpcbiAqIEByZXR1cm4ge0NvbW1hbmR9XG4gKi9cbmZ1bmN0aW9uIENvbW1hbmQkZ2V0VW5kbygpIHtcbiAgICByZXR1cm4gdGhpc1tVTkRPX0NPTU1BTkRdO1xufVxuXG5cbi8qKlxuICogRXhlY3V0ZXMgdW5kbyBjb21tYW5kIG9mIGN1cnJlbnQgY29tbWFuZFxuICovXG5mdW5jdGlvbiBDb21tYW5kJHVuZG8oY2IpIHtcbiAgICB2YXIgdW5kb0NtZCA9IHRoaXMuZ2V0VW5kbygpO1xuICAgIGlmICghIHVuZG9DbWQpIHJldHVybiBsb2dnZXIuZXJyb3IoJ0NvbW1hbmQgdW5kbyBjYWxsZWQgd2l0aG91dCB1bmRvIGNvbW1hbmQgcHJlc2VudCcpO1xuICAgIHZhciByZXN1bHQgPSB1bmRvQ21kLmV4ZWN1dGUoKTtcbiAgICBpZiAoY2IpIF8uZGVmZXIoY2IpO1xuICAgIHJldHVybiByZXN1bHQ7XG59XG5cblxuLyoqXG4gKiBTZXQgY29tbWFuZCdzIGFyZ3VtZW50cy4gSWYgYXJndW1lbnRzIHdlcmUgc2V0IGR1cmluZyBjb21tYW5kJ3MgY3JlYXRpb24sIHRoaXMgbWV0aG9kIHdpbGwgb3ZlcndyaXRlIGFyZ3VtZW50cyBhbmQgbG9nIHdhcm5pbmcuXG4gKlxuICogQHBhcmFtIHtMaXN0fSAqYXJndW1lbnRzXG4gKi9cbmZ1bmN0aW9uIENvbW1hbmQkc2V0QXJndW1lbnRzKCkgeyAvLywgLi4uIGFyZ3VtZW50c1xuICAgIGlmICh0aGlzLmFyZ3MgJiYgdGhpcy5hcmdzLmxlbmd0aClcbiAgICAgICAgbG9nZ2VyLndhcm4oJ0NvbW1hbmQgc2V0QXJndW1lbnRzOiBjb21tYW5kIGFyZ3VtZW50cyBhcmUgYWxyZWFkeSBzZXQnKTtcbiAgICB0aGlzLmFyZ3MgPSBfLnRvQXJyYXkoYXJndW1lbnRzKTtcbn1cblxuXG5mdW5jdGlvbiBDb21tYW5kJGdldEFyZ3VtZW50cygpIHtcbiAgICByZXR1cm4gdGhpcy5hcmdzO1xufVxuXG5cbmZ1bmN0aW9uIENvbW1hbmQkY2hhbmdlQXJndW1lbnRzKCkgeyAvLywgLi4uIGFyZ3VtZW50c1xuICAgIHRoaXMuYXJncyA9IF8udG9BcnJheShhcmd1bWVudHMpO1xufVxuXG5cbi8qKlxuICogQWRkIChhcHBlbmQpIGFyZ3VtZW50cyB0byBjb21tYW5kXG4gKlxuICogQHBhcmFtIHtMaXN0fSAqYXJndW1lbnRzIGFyZ3VtZW50cyBsaXN0IHRvIGJlIGFwcGVuZGVkIHRvIGNvbW1hbmRcbiAqL1xuZnVuY3Rpb24gQ29tbWFuZCRhZGRBcmd1bWVudHMoKSB7IC8vLCAuLi4gYXJndW1lbnRzXG4gICAgaWYgKCEgdGhpcy5hcmdzKSB0aGlzLmFyZ3MgPSBbXTtcbiAgICBfLmFwcGVuZEFycmF5KHRoaXMuYXJncywgYXJndW1lbnRzKTtcbn1cblxuXG4vKipcbiAqIENvbW1hbmRzIGZhY3RvcnkuIExpa2VseSBvdCBiZSBvdmVycmlkZGVuIGJ5IHN1YmNsYXNzZXMgdG8gaW1wbGVtZW50IGN1c3RvbSBsb2dpYyBvZiBjb21tYW5kIGNvbnN0cnVjdGlvblxuICogXG4gKiBAdGhpcyB7RnVuY3Rpb259IENsYXNzIG9mIGNvbW1hbmRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgbWV0aG9kIG5hbWUgb3IgZnVuY3Rpb24gdG8gYmUgZXhlY3V0ZWRcbiAqIEBwYXJhbSB7TGlzdH0gKmFyZ3VtZW50cyBwYXJhbWV0ZXJzIHRvIGJlIHBhc3NlZCB0byBtZXRob2Qgb3IgZnVuY3Rpb25cbiAqIEByZXR1cm4ge0NvbW1hbmR9XG4gKi9cbmZ1bmN0aW9uIENvbW1hbmQkJGNyZWF0ZShmdW5jKSB7IC8vICwgLi4uIGFyZ3VtZW50c1xuICAgIHJldHVybiBfLm5ld0FwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuZnVuY3Rpb24gQ29tbWFuZCQkY3JlYXRlV2l0aFVuZG8oKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjcmVhdGVXaXRoVW5kbyBzaG91bGQgYmUgaW1wbGVtZW50ZWQgYnkgc3Vic2NsYXNzJyk7XG59XG5cblxuLyoqXG4gKiBEZXN0cm95IGN1cnJlbnQgY29tbWFuZCAodG8gcHJldmVudCBwb3RlbnRpYWwgbWVtb3J5IGxlYWtzIHdoZW4gY29tbWFuZHMgcG9pbnQgdG8gRE9NIGVsZW1lbnRzKVxuICovXG5mdW5jdGlvbiBDb21tYW5kJGRlc3Ryb3koKSB7XG4gICAgZGVsZXRlIHRoaXMuZnVuYztcbiAgICBkZWxldGUgdGhpcy5hcmdzO1xuICAgIHZhciB1bmRvQ21kID0gdGhpc1tVTkRPX0NPTU1BTkRdO1xuICAgIGlmICh1bmRvQ21kKSB7XG4gICAgICAgIGRlbGV0ZSB0aGlzW1VORE9fQ09NTUFORF1bVU5ET19DT01NQU5EXTtcbiAgICAgICAgZGVsZXRlIHRoaXNbVU5ET19DT01NQU5EXTtcbiAgICAgICAgdW5kb0NtZC5kZXN0cm95KCk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIENvbW1hbmQkc2V0Q29tbWVudChjb21tZW50KSB7XG4gICAgdGhpcy5jb21tZW50ID0gY29tbWVudDtcbn1cblxuXG5mdW5jdGlvbiBDb21tYW5kJGdldERlc2NyaXB0aW9uKCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIGZ1bmM6IHRoaXMuZnVuYy5uYW1lLFxuICAgICAgICBjb21tZW50OiB0aGlzLmNvbW1lbnRcbiAgICB9O1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBBY3Rpb25zSGlzdG9yeSA9IHJlcXVpcmUoJy4vYWN0aW9uc19oaXN0b3J5JylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IFRyYW5zYWN0aW9uO1xuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uKCkge1xuICAgIHRoaXMuY29tbWFuZHMgPSBuZXcgQWN0aW9uc0hpc3Rvcnk7XG59XG5cblxuXy5leHRlbmRQcm90byhUcmFuc2FjdGlvbiwge1xuICAgIGV4ZWN1dGU6IFRyYW5zYWN0aW9uJGV4ZWN1dGUsXG4gICAgdW5kbzogVHJhbnNhY3Rpb24kdW5kbyxcbiAgICByZWRvOiBUcmFuc2FjdGlvbiRyZWRvLFxuICAgIGRlc3Ryb3k6IFRyYW5zYWN0aW9uJGRlc3Ryb3ksXG4gICAgc3RvcmVDb21tYW5kOiBUcmFuc2FjdGlvbiRzdG9yZUNvbW1hbmQsXG4gICAgbWVyZ2U6IFRyYW5zYWN0aW9uJG1lcmdlLFxuXG4gICAgc2V0Q29tbWVudDogVHJhbnNhY3Rpb24kc2V0Q29tbWVudCxcbiAgICBnZXREZXNjcmlwdGlvbjogVHJhbnNhY3Rpb24kZ2V0RGVzY3JpcHRpb25cbn0pO1xuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uJGV4ZWN1dGUoKSB7XG4gICAgdGhpcy5jb21tYW5kcy5lYWNoKCdleGVjdXRlJyk7XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb24kdW5kbyhjYikge1xuICAgIHRoaXMuY29tbWFuZHMudW5kb0FsbEFzeW5jKGNiKTtcbn1cblxuXG5mdW5jdGlvbiBUcmFuc2FjdGlvbiRyZWRvKGNiKSB7XG4gICAgdGhpcy5jb21tYW5kcy5yZWRvQWxsQXN5bmMoY2IpO1xufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uJGRlc3Ryb3koKSB7XG4gICAgdGhpcy5jb21tYW5kcy5lYWNoKCdkZXN0cm95Jyk7XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb24kc3RvcmVDb21tYW5kKGNvbW1hbmQpIHtcbiAgICB0aGlzLmNvbW1hbmRzLnN0b3JlKGNvbW1hbmQpO1xufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uJG1lcmdlKHRyYW5zYWN0aW9uKSB7XG4gICAgdHJhbnNhY3Rpb24uY29tbWFuZHMuZWFjaChmdW5jdGlvbihjbWQpIHtcbiAgICAgICAgdGhpcy5jb21tYW5kcy5zdG9yZShjbWQpO1xuICAgIH0sIHRoaXMpO1xufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uJHNldENvbW1lbnQoY29tbWVudCkge1xuICAgIHRoaXMuY29tbWVudCA9IGNvbW1lbnRcbn1cblxuXG5mdW5jdGlvbiBUcmFuc2FjdGlvbiRnZXREZXNjcmlwdGlvbigpIHtcbiAgICB2YXIgY29tbWFuZHMgPSB0aGlzLmNvbW1hbmRzLmdldERlc2NyaXB0aW9uKCk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgY29tbWFuZHM6IGNvbW1hbmRzLmFjdGlvbnMsXG4gICAgICAgIGNvbW1lbnQ6IHRoaXMuY29tbWVudFxuICAgIH1cbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgQWN0aW9uc0hpc3RvcnkgPSByZXF1aXJlKCcuL2FjdGlvbnNfaGlzdG9yeScpXG4gICAgLCBUcmFuc2FjdGlvbiA9IHJlcXVpcmUoJy4vdHJhbnNhY3Rpb24nKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vdXRpbC9sb2dnZXInKVxuICAgICwgTWVzc2VuZ2VyID0gcmVxdWlyZSgnLi4vbWVzc2VuZ2VyJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IFRyYW5zYWN0aW9uSGlzdG9yeTtcblxuXG52YXIgU0NIRURVTEVEID0gJ19zY2hlZHVsZWQnO1xuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uSGlzdG9yeShtYXhMZW5ndGgpIHtcbiAgICB0aGlzLnRyYW5zYWN0aW9ucyA9IG5ldyBBY3Rpb25zSGlzdG9yeShtYXhMZW5ndGgpO1xuICAgIHRoaXMuY3VycmVudEJhdGNoID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuY3VycmVudFRyYW5zYWN0aW9uID0gdW5kZWZpbmVkO1xuICAgIHRoaXNbU0NIRURVTEVEXSA9IGZhbHNlO1xufVxuXG5cbl8uZXh0ZW5kUHJvdG8oVHJhbnNhY3Rpb25IaXN0b3J5LCB7XG4gICAgc3RvcmVDb21tYW5kOiBUcmFuc2FjdGlvbkhpc3Rvcnkkc3RvcmVDb21tYW5kLFxuICAgIGVuZFRyYW5zYWN0aW9uOiBUcmFuc2FjdGlvbkhpc3RvcnkkZW5kVHJhbnNhY3Rpb24sXG4gICAgc3RvcmVUcmFuc2FjdGlvbjogVHJhbnNhY3Rpb25IaXN0b3J5JHN0b3JlVHJhbnNhY3Rpb24sXG4gICAgZGVsZXRlTGFzdFRyYW5zYWN0aW9uOiBUcmFuc2FjdGlvbkhpc3RvcnkkZGVsZXRlTGFzdFRyYW5zYWN0aW9uLFxuICAgIHVuZG86IFRyYW5zYWN0aW9uSGlzdG9yeSR1bmRvLFxuICAgIHJlZG86IFRyYW5zYWN0aW9uSGlzdG9yeSRyZWRvLFxuICAgIGluVHJhbnNhY3Rpb246IFRyYW5zYWN0aW9uSGlzdG9yeSRpblRyYW5zYWN0aW9uLFxuXG4gICAgZ2V0RGVzY3JpcHRpb246IFRyYW5zYWN0aW9uSGlzdG9yeSRnZXREZXNjcmlwdGlvbixcbiAgICB1c2VNZXNzZW5nZXI6IFRyYW5zYWN0aW9uSGlzdG9yeSR1c2VNZXNzZW5nZXIsXG4gICAgZGVzdHJveTogVHJhbnNhY3Rpb25IaXN0b3J5JGRlc3Ryb3lcbn0pO1xuXG5cbi8qKlxuICogU3RvcmVzIGNvbW1hbmQgaW4gdGhlIGhpc3RvcnkuIFxuICogQHBhcmFtIHtDb21tYW5kfSBjb21tYW5kICAgICAgICAgICBcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gYXBwZW5kVHJhbnNhY3Rpb24gSWYgYHRydWVgLCBhcHBlbmRzIHRvIHRoZSBjdXJyZW50IG9yIHByZXZpb3VzIHRyYW5zYWN0aW9uIGlmIHRoZXJlIGlzIG5vIGN1cnJlbnQgdHJhbnNhY3Rpb24uXG4gKi9cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uSGlzdG9yeSRzdG9yZUNvbW1hbmQoY29tbWFuZCwgYXBwZW5kVHJhbnNhY3Rpb24pIHtcbiAgICBpZiAoYXBwZW5kVHJhbnNhY3Rpb24gJiYgISh0aGlzLmN1cnJlbnRUcmFuc2FjdGlvbiB8fCB0aGlzLmN1cnJlbnRCYXRjaCkpIHtcbiAgICAgICAgdmFyIHRyYW5zYWN0aW9uID0gdGhpcy50cmFuc2FjdGlvbnMuZ2V0TGFzdEFjdGlvbigpO1xuICAgICAgICB0cmFuc2FjdGlvbi5zdG9yZUNvbW1hbmQoY29tbWFuZCk7XG4gICAgICAgIF9wb3N0VHJhbnNhY3Rpb25NZXNzYWdlLmNhbGwodGhpcywgJ2FwcGVuZGVkJywgdHJhbnNhY3Rpb24pO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCEgdGhpcy5jdXJyZW50QmF0Y2gpIHRoaXMuY3VycmVudEJhdGNoID0gbmV3IFRyYW5zYWN0aW9uO1xuICAgIHRoaXMuY3VycmVudEJhdGNoLnN0b3JlQ29tbWFuZChjb21tYW5kKTtcbiAgICBpZiAoISB0aGlzW1NDSEVEVUxFRF0pIHtcbiAgICAgICAgdGhpc1tTQ0hFRFVMRURdID0gdHJ1ZTtcbiAgICAgICAgXy5kZWZlck1ldGhvZCh0aGlzLCBfc3RvcmVUcmFuc2FjdGlvbik7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uSGlzdG9yeSRkZWxldGVMYXN0VHJhbnNhY3Rpb24oKSB7XG4gICAgaWYgKHRoaXMuY3VycmVudEJhdGNoIHx8IHRoaXMuY3VycmVudFRyYW5zYWN0aW9uKSB7XG4gICAgICAgIHRoaXMuY3VycmVudEJhdGNoID0gdW5kZWZpbmVkO1xuICAgICAgICB0aGlzLmN1cnJlbnRUcmFuc2FjdGlvbiA9IHVuZGVmaW5lZDtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnRyYW5zYWN0aW9ucy5kZWxldGVMYXN0KCk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIF9zdG9yZVRyYW5zYWN0aW9uKCkge1xuICAgIGlmICh0aGlzLmN1cnJlbnRCYXRjaCkge1xuICAgICAgICBfYWRkQmF0Y2hUb1RyYW5zYWN0aW9uLmNhbGwodGhpcyk7XG4gICAgICAgIF8uZGVmZXJNZXRob2QodGhpcywgX3N0b3JlVHJhbnNhY3Rpb24pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIF9zdG9yZUN1cnJlbnRUcmFuc2FjdGlvbi5jYWxsKHRoaXMpO1xuICAgICAgICB0aGlzW1NDSEVEVUxFRF0gPSBmYWxzZTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb25IaXN0b3J5JGVuZFRyYW5zYWN0aW9uKCkge1xuICAgIF9hZGRCYXRjaFRvVHJhbnNhY3Rpb24uY2FsbCh0aGlzKTtcbiAgICBfc3RvcmVDdXJyZW50VHJhbnNhY3Rpb24uY2FsbCh0aGlzKTtcbn1cblxuXG5mdW5jdGlvbiBfYWRkQmF0Y2hUb1RyYW5zYWN0aW9uKCkge1xuICAgIGlmICh0aGlzLmN1cnJlbnRCYXRjaCkge1xuICAgICAgICBpZiAoISB0aGlzLmN1cnJlbnRUcmFuc2FjdGlvbikgdGhpcy5jdXJyZW50VHJhbnNhY3Rpb24gPSBuZXcgVHJhbnNhY3Rpb247XG4gICAgICAgIHRoaXMuY3VycmVudFRyYW5zYWN0aW9uLm1lcmdlKHRoaXMuY3VycmVudEJhdGNoKTtcbiAgICAgICAgdGhpcy5jdXJyZW50QmF0Y2ggPSB1bmRlZmluZWQ7XG4gICAgfSBcbn1cblxuXG5mdW5jdGlvbiBfc3RvcmVDdXJyZW50VHJhbnNhY3Rpb24oKSB7XG4gICAgaWYgKHRoaXMuY3VycmVudFRyYW5zYWN0aW9uKSB7XG4gICAgICAgIHZhciB0ID0gdGhpcy5jdXJyZW50VHJhbnNhY3Rpb247XG4gICAgICAgIHRoaXMudHJhbnNhY3Rpb25zLnN0b3JlKHQpO1xuICAgICAgICBfcG9zdFRyYW5zYWN0aW9uTWVzc2FnZS5jYWxsKHRoaXMsICdzdG9yZWQnLCB0KTtcblxuICAgICAgICB0aGlzLmN1cnJlbnRUcmFuc2FjdGlvbiA9IHVuZGVmaW5lZDtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb25IaXN0b3J5JHN0b3JlVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pIHtcbiAgICB0aGlzLmVuZFRyYW5zYWN0aW9uKCk7XG5cbiAgICB0aGlzLnRyYW5zYWN0aW9ucy5zdG9yZSh0cmFuc2FjdGlvbik7XG4gICAgX3Bvc3RUcmFuc2FjdGlvbk1lc3NhZ2UuY2FsbCh0aGlzLCAnc3RvcmVkJywgdHJhbnNhY3Rpb24pO1xufVxuXG5cbmZ1bmN0aW9uIF9wb3N0VHJhbnNhY3Rpb25NZXNzYWdlKG1zZywgdHJhbnNhY3Rpb24pIHtcbiAgICBpZiAodGhpcy5fbWVzc2VuZ2VyKVxuICAgICAgICB0aGlzLl9tZXNzZW5nZXIucG9zdE1lc3NhZ2UobXNnLCB7IHRyYW5zYWN0aW9uOiB0cmFuc2FjdGlvbiB9KTtcbn1cblxuXG5mdW5jdGlvbiBUcmFuc2FjdGlvbkhpc3RvcnkkdW5kbyhjYikge1xuICAgIHZhciB0ID0gdGhpcy50cmFuc2FjdGlvbnMudW5kbyhjYik7XG4gICAgaWYgKHQpIF9wb3N0VHJhbnNhY3Rpb25NZXNzYWdlLmNhbGwodGhpcywgJ3VuZG9uZScsIHQpO1xuICAgIHJldHVybiB0O1xufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uSGlzdG9yeSRyZWRvKGNiKSB7XG4gICAgdmFyIHQgPSB0aGlzLnRyYW5zYWN0aW9ucy5yZWRvKGNiKTtcbiAgICBpZiAodCkgX3Bvc3RUcmFuc2FjdGlvbk1lc3NhZ2UuY2FsbCh0aGlzLCAncmVkb25lJywgdCk7XG4gICAgcmV0dXJuIHQ7XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb25IaXN0b3J5JGluVHJhbnNhY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXNbU0NIRURVTEVEXTtcbn1cblxuXG5mdW5jdGlvbiBUcmFuc2FjdGlvbkhpc3RvcnkkZ2V0RGVzY3JpcHRpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNhY3Rpb25zLmdldERlc2NyaXB0aW9uKCk7XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb25IaXN0b3J5JHVzZU1lc3NlbmdlcigpIHtcbiAgICByZXR1cm4gdGhpcy5fbWVzc2VuZ2VyID0gbmV3IE1lc3Nlbmdlcih0aGlzLCBNZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMpO1xufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uSGlzdG9yeSRkZXN0cm95KCkge1xuICAgIGlmICh0aGlzLl9tZXNzZW5nZXIpIHRoaXMuX21lc3Nlbmdlci5kZXN0cm95KCk7XG4gICAgZGVsZXRlIHRoaXMudHJhbnNhY3Rpb25zO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBGYWNldGVkT2JqZWN0ID0gcmVxdWlyZSgnLi4vYWJzdHJhY3QvZmFjZXRlZF9vYmplY3QnKVxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NfZmFjZXRzL2NmX3JlZ2lzdHJ5JylcbiAgICAsIENvbXBvbmVudEZhY2V0ID0gZmFjZXRzUmVnaXN0cnkuZ2V0KCdDb21wb25lbnRGYWNldCcpXG4gICAgLCBjb21wb25lbnRVdGlscyA9IHJlcXVpcmUoJy4vY191dGlscycpXG4gICAgLCBNZXNzZW5nZXIgPSByZXF1aXJlKCcuLi9tZXNzZW5nZXInKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJylcbiAgICAsIG1pbG9Db21wb25lbnROYW1lID0gcmVxdWlyZSgnLi4vdXRpbC9jb21wb25lbnRfbmFtZScpXG4gICAgLCBsb2dnZXIgPSByZXF1aXJlKCcuLi91dGlsL2xvZ2dlcicpXG4gICAgLCBkb21VdGlscyA9IHJlcXVpcmUoJy4uL3V0aWwvZG9tJylcbiAgICAsIENvbXBvbmVudEVycm9yID0gcmVxdWlyZSgnLi4vdXRpbC9lcnJvcicpLkNvbXBvbmVudFxuICAgICwgQmluZEF0dHJpYnV0ZSA9IHJlcXVpcmUoJy4uL2F0dHJpYnV0ZXMvYV9iaW5kJylcbiAgICAsIFNjb3BlID0gcmVxdWlyZSgnLi9zY29wZScpXG4gICAgLCBET01TdG9yYWdlID0gcmVxdWlyZSgnLi4vdXRpbC9zdG9yYWdlJylcbiAgICAsIGpzb25QYXJzZSA9IHJlcXVpcmUoJy4uL3V0aWwvanNvbl9wYXJzZScpO1xuXG52YXIgX21ha2VDb21wb25lbnRDb25kaXRpb25GdW5jID0gY29tcG9uZW50VXRpbHMuX21ha2VDb21wb25lbnRDb25kaXRpb25GdW5jO1xuXG5cbi8qKlxuICogYG1pbG8uQ29tcG9uZW50YFxuICogQmFzZSBDb21wb25lbnQgY2xhc3MuIFN1YmNsYXNzIG9mIFtGYWNldGVkT2JqZWN0XSguLi9hYnN0cmFjdC9mYWNldGVkX29iamVjdC5qcy5odG1sKSwgYnV0IG5vbmUgb2YgdGhpcyBjbGFzcyBtZXRob2RzIHNob3VsZCBiZSBkaXJlY3RseSB1c2VkIHdpdGggY29tcG9uZW50LlxuICogSXRzIGNvbnN0cnVjdG9yIHBhc3NlcyBpdHMgcGFyYW1ldGVycywgaW5jbHVkaW5nIGl0cyBbc2NvcGVdKC4vc2NvcGUuanMuaHRtbCksIERPTSBlbGVtZW50IGFuZCBuYW1lIHRvIFtgaW5pdGBdKCNpbml0KSBtZXRob2QuXG4gKiBUaGUgY29uc3RydWN0b3Igb2YgQ29tcG9uZW50IGNsYXNzIHJhcmVseSBuZWVkcyB0byBiZSB1c2VkIGRpcmVjdGx5LCBhcyBbbWlsby5iaW5kZXJdKC4uL2JpbmRlci5qcy5odG1sKSBjcmVhdGVzIGNvbXBvbmVudHMgd2hlbiBpdCBzY2FucyBET00gdHJlZS5cbiAqIFtgQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzYF0oI2NyZWF0ZUNvbXBvbmVudENsYXNzKSBzaG91bGQgYmUgdXNlZCB0byBjcmVhdGUgYSBzdWJjbGFzcyBvZiBDb21wb25lbnQgY2xhc3Mgd2l0aCBjb25maWd1cmVkIGZhY2V0cy5cbiAqXG4gKlxuICogIyMjI0NvbXBvbmVudCBpbnN0YW5jZSBwcm9wZXJ0aWVzIyMjI1xuICpcbiAqIC0gZWwgLSBET00gZWxlbWVudCB0aGF0IGNvbXBvbmVudCBpcyBhdHRhY2hlZCB0by4gSWYgdGhlIHNlY29uZCBjb21wb25lbnQgaXMgYXR0YWNoZWQgdG8gdGhlIHNhbWUgRE9NIGVsZW1lbnQsIHRoZSB3YXJuaW5nIHdpbGwgYmUgbG9nZ2VkIHRvIGNvbnNvbGUuIFRvIGdldCBjb21wb25lbnQgcmVmZXJlbmNlIGZyb20gRE9NIGVsZW1lbnQgdXNlIFtDb21wb25lbnQuZ2V0Q29tcG9uZW50XSguL2NfdXRpbHMuanMuaHRtbCNnZXRDb21wb25lbnQpIGNsYXNzIG1ldGhvZC4gVG8gaW5zcGVjdCBjb21wb25lbnQgdmlhIGVsZW1lbnQgaW4gYnJvd3NlciBjaGVjayBgX19fbWlsb19jb21wb25lbnRgIHByb3BlcnR5IG9mIGVsZW1lbnQgKHByb3BlcnR5IG5hbWUgYmUgY2hhbmdlZCB1c2luZyBgbWlsby5jb25maWdgKS5cbiAqIC0gc2NvcGUgLSBwYXJlbnQgc2NvcGUgb2JqZWN0LCBhbiBpbnN0YW5jZSBvZiBbU2NvcGVdKC4vc2NvcGUuanMuaHRtbCkgY2xhc3MuIFRvIGdldCBwYXJlbnQgY29tcG9uZW50IHVzZSBbZ2V0U2NvcGVQYXJlbnRdKCNDb21wb25lbnQkZ2V0U2NvcGVQYXJlbnQpIGluc3RhbmNlIG1ldGhvZCBvZiBjb21wb25lbnQuIFRoZSBhY3R1YWwgcGF0aCB0byBnZXQgcGFyZW50IG9mIGNvbnBvbmVudCBpcyBgY29tcG9uZW50LnNjb3BlLl9ob3N0T2JqZWN0Lm93bmVyYCwgd2hlcmUgYF9ob3N0T2JqZWN0YCByZWZlcnMgdG8gW0NvbnRhaW5lcl0oY19mYWNldHMvQ29udGFpbmVyLmpzLmh0bWwpIGZhY2V0IG9mIHBhcmVudCBjb21wb25lbnQgYW5kIGBvd25lcmAgdG8gdGhlIHBhcmVudCBpdHNlbGYuIFRoZSBjaGlsZHJlbiBvZiBjb21wb25lbnQgYXJlIGFjY2Vzc2libGUgdmlhIHRoZSBzY29wZSBvZiBpdHMgY29udGFpbmVyIGZhY2V0OiBgY29tcG9uZW50LmNvbnRhaW5lci5zY29wZWAuIFRoZSBzY29wZSBoaWVyYXJjaHkgY2FuIGJlIHRoZSBzYW1lIG9yIGRpZmZlcmVudCBhcyB0aGUgRE9NIGhpZXJhcmNoeSAtIERPTSBjaGlsZHJlbiBvZiB0aGUgY29tcG9uZW50IHdpbGwgYmUgb24gdGhlIHNhbWUgc2NvcGUgYXMgY29tcG9uZW50IGlmIGl0IGRvZXMgbm90IGhhdmUgYENvbnRhaW5lcmAgZmFjZXQgYW5kIGluIHRoZSBzY29wZSBvZiBpdHMgQ29udGFpbmVyIGZhY2V0IGlmIGl0IGhhcyBpdC4gU2VlIFtTY29wZV0oLi9zY29wZS5qcy5odG1sKS5cbiAqIC0gbmFtZSAtIHRoZSBuYW1lIG9mIGNvbXBvbmVudCwgc2hvdWxkIGJlIHVuaXF1ZSBmb3IgdGhlIHNjb3BlIHdoZXJlIGNvbXBvbmVudCBiZWxvbmdzLiBUbyBmaW5kIGNvbXBvbmVudCBpbiBzY29wZSB0aGUgY29tcG9uZW50J3MgbmFtZSBzaG91bGQgYmUgdXNlZCBhcyBwcm9wZXJ0eSBvZiBzY29wZSBvYmplY3QuIFNlZSBbU2NvcGVdKC4vc2NvcGUuanMuaHRtbCkuXG4gKiAtIGZhY2V0cyAtIG1hcCBvZiByZWZlcmVuY2VzIG9mIGFsbCBjb21wb25lbnQncyBmYWNldHMgKGZhY2V0IG5hbWVzIGFyZSBsb3dlcmNhc2UgaW4gdGhpcyBtYXApLiBBbGwgZmFjZXRzIGNhbiBiZSBhY2Nlc3NlZCBkaXJlY3RseSBhcyBwcm9wZXJ0aWVzIG9mIGNvbXBvbmVudCwgdGhpcyBwcm9wZXJ0eSBjYW4gYmUgdXNlZCB0byBpdGVyYXRlIGZhY2V0cyAoaXQgaXMgdXNlZCBpbiB0aGlzIHdheSBpbiBbYWxsRmFjZXRzXSgjQ29tcG9uZW50JGFsbEZhY2V0cykgY29tcG9uZW50J3MgaW5zdGFuY2UgbWV0aG9kIHRoYXQgYWxsb3dzIHRvIGNhbGwgbWV0aG9kIHdpdGggdGhlIHNhbWUgbmFtZSBvbiBhbGwgZmFjZXRzKS5cbiAqIC0gZXh0cmFGYWNldHMgLSBhbiBhcnJheSBvZiBuYW1lcyBvZiBmYWNldHMgdGhhdCBhcmUgYWRkZWQgdG8gY29tcG9uZW50IGFuZCBkbyBub3QgZm9ybSB0aGUgcGFydCBvZiBjb21wb25lbnQncyBjbGFzcy5cbiAqIC0gX21lc3NlbmdlciAtIHRoZSByZWZlcmVuY2UgdG8gY29tcG9uZW50J3MgW21lc3Nlbmdlcl0oLi4vbWVzc2VuZ2VyL2luZGV4LmpzLmh0bWwpLiBSYXJlbHkgbmVlZHMgdG8gYmUgdXNlZCBkaXJlY3RseSBhcyBhbGwgY29tbW9ubHkgdXNlZCBtZXRob2RzIG9mIG1lc2VuZ2VyIGFyZSBhdmFpbGFibGUgZGlyZWN0bHkgb24gY29tcG9uZW50LlxuICpcbiAqXG4gKiAjIyMjQ29tcG9uZW50IGV2ZW50cyMjIyNcbiAqXG4gKiAtICdjaGlsZHJlbmJvdW5kJyAtIHN5bmNocm9ub3VzbHkgZGlzcGF0Y2hlZCB3aGVuIGNoaWxkcmVuIG9mIERPTSBlbGVtZW50IHdoaWNoIGNvbXBuZW50IGlzIGNvbm5lY3RlZCB0byBhcmUgY29ubmVjdGVkIHRvIGNvbXBvbmVudHMuIFRoZSBldmVudCBpcyBkaXNwYXRjaGVkIHdoZW4gY29tcG9uZW50IGlzIGNyZWF0ZWQgd2l0aCBgbWlsby5iaW5kZXJgIChhcyBpcyBhbG1vc3QgYWx3YXlzIHRoZSBjYXNlLCBhcyBhbGwgQ29tcG9uZW50IGNsYXNzIG1ldGhvZHMgdGhhdCBjcmVhdGUvY29weSBjb21wb25lbnRzIHVzZSBgbWlsby5iaW5kZXJgIGludGVybmFsbHkgLSBjb21wb25lbnQgY29uc3RydWN0b3IgYW5kIENvbXBvbmVudC5jcmVhdGUgbWV0aG9kcyBhcmUgbm90IHVzZWQgaW4gZnJhbWV3b3JrIG91dHNpZGUgb2YgYG1pbG8uYmluZGVyYCBhbmQgcmFyZWx5IGlmIGV2ZXIgbmVlZCB0byBiZSB1c2VkIGluIGFwbGljYXRpb24pLlxuICogLSAnYWRkZWR0b3Njb3BlJyAtIHN5bmNocm9ub3VzbHkgZGlzcGF0Y2hlZCB3aGVuIGNvbXBvbmVudCBpcyBhZGRlZCB0byBzY29wZS5cbiAqIC0gJ3N0YXRlcmVhZHknIC0gYXluY2hyb25vdXNseSBkaXNwYXRjaGVkIHdoZW4gY29tcG9uZW50ICh0b2dldGhlciB3aXRoIGl0cyBzY29wZSBjaGlsZHJlbikgaXMgY3JlYXRlZCB3aXRoIFtDb21wb25lbnQuY3JlYXRlRnJvbVN0YXRlXSgjQ29tcG9uZW50JCRjcmVhdGVGcm9tU3RhdGUpIChvciBgY3JlYXRlRnJvbURhdGFUcmFuc2ZlcmApIG1ldGhvZC4gQ2FuIGJlIGRpc3BhdGNoZWQgYnkgYXBwbGljYXRpb24gaWYgdGhlIGNvbXBvbmVudCdzIHN0YXRlIGlzIHNldCB3aXRoIHNvbWUgb3RoZXIgbWVjaGFuaXNtLiBUaGlzIGV2ZW50IGlzIG5vdCB1c2VkIGluIGBtaWxvYCwgaXQgY2FuIGJlIHVzZWQgaW4gYXBwbGljYXRpb24gaW4gcGFydGljdWxhciBzdWJjbGFzc2VzIG9mIGNvbXBvbmVudC5cbiAqIC0gJ2dldHN0YXRlc3RhcnRlZCcgLSBlbWl0dGVkIHN5bmNocm9ub3VzbHkganVzdCBiZWZvcmUgZ2V0U3RhdGUgZXhlY3V0ZXMgc28gY29tcG9uZW50cyBhbmQgZmFjZXRzIGNhbiBjbGVhbiB1cCB0aGVpciBzdGF0ZSBmb3Igc2VyaWFsaXphdGlvbi4gXG4gKiAtICdnZXRzdGF0ZWNvbXBsZXRlZCcgLSBlbWl0dGVkIGFzeW5jaHJvbm91c2x5IGFmdGVyIGdldFN0YXRlIGV4ZWN1dGVzIHNvIGNvbXBvbmVudHMgYW5kIGZhY2V0cyBjYW4gcmVzdG9yZSB0aGVpciBzdGF0ZSBhZnRlciBzZXJpYWxpemF0aW9uLlxuICpcbiAqXG4gKiAjIyMjQ29tcG9uZW50IFwibGlmZWN5Y2xlXCIjIyMjXG4gKlxuICogMS4gQ29tcG9uZW50IGNvbnN0cnVjdG9yIGlzIGNhbGxlZC4gQ29tcG9uZW50J3MgY29uc3RydWN0b3Igc2ltcGx5IGNhbGxzIGNvbnN0cnVjdG9yIG9mIFtGYWNldGVkT2JqZWN0XSguLi9hYnN0cmFjdC9mYWNldGVkX29iamVjdC5qcy5odG1sKSB0aGF0IGlzIGEgc3VwZXJjbGFzcyBvZiBDb21wb25lbnQuIFN1YmNsYXNzZXMgb2YgQ29tcG9uZW50IHNob3VsZCBub3QgaW1wbGVtZW50IHRoZWlyIG93biBjb25zdHJ1Y3RvciwgdGhleSBjYW4gb3B0aW9uYWxseSBpbXBsZW1lbnQgYGluaXRgIG1ldGhvZCwgYnV0IG1vc3QgY29tcG9uZW50cyBkbyBub3QgbmVlZCB0byBkbyBpdC5cbiAqIDIuIGNvbnN0cnVjdG9ycyBhbmQgYGluaXRgIG1ldGhvZHMgb2YgYWxsIGZhY2V0cyBhcmUgY2FsbGVkIGluIHNlcXVlbmNlLiBTYW1lIGFzIGNvbXBvbmVudHMsIGZhY2V0IGRvIG5vdCBpbXBsZW1lbnQgdGhlaXIgY29uc3RydWN0b3JzLCB0aGV5IGNhbiBvcHRpb25hbGx5IGltcGxlbWVudCBgaW5pdGAgYW5kIGBzdGFydGAgbWV0aG9kcyAoc2VlIGJlbG93KS4gSW5zaWRlIGBpbml0YCBtZXRob2QgdGhlcmUgc2hvdWxkIGJlIG9ubHkgZ2VuZXJhbCBpbml0aWFsaXphdGlvbiBjb2RlIHdpdGhvdXQgYW55IGRlcGVuZGVuY3kgb24gY29tcG9uZW50IGl0c2VsZiAoaXQgaXMgbm90IHJlYWR5IHlldCkgYW5kIG90aGVyIGZhY2V0cyAoYXMgdGhlcmUgaXMgbm8gc3BlY2lmaWMgZmFjZXRzIGNyZWF0aW9uIG9yZGVyKS4gSWYgZmFjZXQgaW1wbGVtZW50cyBgaW5pdGAgbWV0aG9kIGl0IE1VU1QgY2FsbCBpbmhlcml0ZWQgaW5pdCB3aXRoIGBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpYC5cbiAqIDMuIGBpbml0YCBtZXRob2Qgb2YgY29tcG9uZW50IGlzIGNhbGxlZC4gQXQgdGhpcyBwb2ludCBhbGwgZmFjZXRzIGFyZSBjcmVhdGVkIGJ1dCBmYWNldHMgc3RpbGwgY2FuIGJlIG5vdCByZWFkeSBhcyB0aGV5IGNhbiBoYXZlIGluaXRpYWxpemF0aW9uIGNvZGUgaW4gYHN0YXJ0YCBtZXRob2QuIElmIGNvbXBvbmVudCBzdWJjbGFzcyBpbXBsZW1lbnRzIGBpbml0YCBtZXRob2QgaXQgTVVTVCBjYWxsIGluaGVyaXRlZCBtZXRob2Qgd2l0aCBgPFN1cGVyY2xhc3M+LnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cylgLCB3aGVyZSA8U3VwZXJjbGFzcz4gaXMgQ29tcG9uZW50IG9yIGFub3RoZXIgc3VwZXJjbGFzcyB0aGUgY29tcG9uZW50IGlzIGEgc3ViY2xhc3Mgb2YuXG4gKiA0LiBgY2hlY2tgIG1ldGhvZCBvZiBhbGwgZmFjZXRzIGlzIGNhbGxlZC4gVGhpcyBtZXRob2QgYWRkcyBmYWNldHMgdGhhdCBhcmUgbm90IHBhcnQgb2YgdGhlIGNvbXBvbmVudCBkZWNsYXJhdGlvbiAoYmVpbmcgcGFydCBvZiB0aGUgY2xhc3Mgb3IgZXhwbGljaXRlbHkgbGlzdGVkIGluIGJpbmQgYXR0cmlidXRlKSBidXQgYXJlIHJlcXVpcmVkIGJ5IGZhY2V0cyB0aGF0IHRoZSBjb21wbmVudCBhbHJlYWR5IGhhcy4gU3ViY2xhc3NlcyBvZiBbQ29tcG9uZW50RmFjZXRdKC4vY19mYWNldC5qcy5odG1sKSBkbyBub3QgbmVlZCB0byBpbXBsZW1lbnQgdGhpcyBtZXRob2QuXG4gKiA1LiBgc3RhcnRgIG1ldGhvZCBvZiBhbGwgZmFjZXRzIGlzIGNhbGxlZC4gVGhpcyBtZXRob2QgaXMgdXN1YWxseSBpbXBsZW1lbnRlZCBieSBDb21wb25lbnRGYWNldCBzdWJjbGFzc2VzIGFuZCBpdCBjYW4gaGF2ZSBhbnkgaW5pdGlhbGl6YXRpb24gY29kZSB0aGF0IGRlcGVuZHMgb24gY29tcG9uZW50IG9yIG9uIG90aGVyIGZhY2V0cyB0aGF0IGFyZSB0aGUgZGVwZW5kZW5jaWVzIG9mIGEgZmFjZXQuIEluaGVyaXRlZCBgc3RhcnRgIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIGludCBoZSBzYW1lIHdheSBhcyB3cml0dGVuIGFib3ZlLlxuICogNi4gYHN0YXJ0YCBtZXRob2Qgb2YgY29tcG9uZW50IGlzIGNhbGxlZC4gVGhpcyBjb21wb25lbnQgbWV0aG9kIGNhbiBiZSBpbXBsZW1lbnRlZCBieSBzdWJjbGFzc2VzIGlmIHRoZXkgbmVlZCB0byBoYXZlIHNvbWUgaW5pdGlhbGl6YXRpb24gY29kZSB0aGF0IGRlcGVuZHMgb24gc29tZSBmYWNldHMgYW5kIHJlcXVpcmVzIHRoYXQgdGhlc2UgZmFjZXRzIGFyZSBmdWxseSBpbmlhbGl6ZWQuIE9mdGVuIHN1Y2ggY29kZSBhbHNvIGRlcGVuZHMgb24gY29tcG9uZW50J3Mgc2NvcGUgY2hpbGRyZW4gYXMgd2VsbCBzbyB0aGlzIGNvZGUgc2hvdWxkIGJlIGluc2lkZSBgJ2NoaWxkcmVuYm91bmQnYCBldmVudCBzdWJzY3JpYmVyLlxuICogNy4gJ2FkZGVkdG9zY29wZScgZXZlbnQgaXMgZGlzcGF0Y2hlZCB3aGVuIGNvbXBvbmVudCBpcyBhZGRlZCB0byBpdHMgcGFyZW50J3Mgc2NvcGUgb3IgdG8gdG9wIGxldmVsIHNjb3BlIGNyZWF0ZWQgYnkgYG1pbG8uYmluZGVyYC5cbiAqIDguIGNvbXBvbmVudCdzIGNoaWxkcmVuIGFyZSBjcmVhdGVkIChzdGVwcyAxLTYgYWJvdmUgYXJlIGZvbGxvd2VkIGZvciBlYWNoIGNoaWxkKS5cbiAqIDkuICdjaGlsZHJlbmJvdW5kJyBldmVudCBpcyBkaXNwYXRjaGVkIHdoZW4gYWxsIGNvbXBvbmVudCdzIGNoaWxkcmVuIGFyZSBjcmVhdGVkIGFuZCBhZGRlZCB0byB0aGVpciBzY29wZSAoc2VlIGV2ZW50IGRlc2NyaXB0aW9uIGJlbG93KS5cbiAqIDEwLiAnc3RhdGVyZWFkeScgZXZlbnQgaXMgZGlzcGF0Y2hlZCBmb3IgY29tcG9uZW50IGFuZCBhbGwgaXRzIGNoaWxkcmVuIHdoZW4gY29tcG9uZW50IGlzIGNyZWF0ZSBmcm9tIHN0YXRlIChzZWUgZXZlbnQgZGVzY3JpcHRpb24gYmVsb3cpLlxuICogMTEuIGF0IHRoaXMgcG9pbnQgY29tcG9uZW50IGlzIGluIHRoZSBcImludGVyYWN0aXZlXCIgc3RhdGUgd2hlbiBpdCBhbmQgaXRzIGZhY2V0cyB3aWxsIG9ubHkgcmVzcG9uZCB0byBtZXNzYWdlcy9ldmVudHMgdGhhdCB0aGV5IHN1YnNjcmliZWQgdG8gZHVyaW5nIGluaXRpYWxpemF0aW9uLlxuICpcbiAqXG4gKiBAcGFyYW0ge1Njb3BlfSBzY29wZSBzY29wZSB0byB3aGljaCBjb21wb25lbnQgd2lsbCBiZWxvbmcuIEl0IGlzIHVzdWFsbHkgYSB0b3AgbGV2ZWwgc2NvcGUgb2JqZWN0IHJldHVybmVkIGJ5IGBtaWxvLmJpbmRlcmAgb3IgYHNjb3BlYCBwcm9wZXJ0eSBvZiBDb250YWluZXIgZmFjZXQuXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsZW1lbnQgRE9NIGVsZW1lbnQgdGhhdCBjb21wb25lbnQgaXMgYXR0YWNoZWQgdG9cbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIGNvbXBvbmVudCBuYW1lLCBzaG91bGQgYmUgdW5pcXVlIGluIHRoZSBzY29wZSBvZiBjb21wb25lbnRcbiAqIEBwYXJhbSB7Q29tcG9uZW50SW5mb30gY29tcG9uZW50SW5mbyBpbnN0YW5jZSBvZiBDb21wb25lbnRJbmZvIGNsYXNzIHRoYXQgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGEgY29weSBvZiBjb21wb25lbnRcbiAqICBUT0RPIHRyeSByZW1vdmluZyBpdFxuICogQHJldHVybiB7Q29tcG9uZW50fVxuICovXG52YXIgQ29tcG9uZW50ID0gXy5jcmVhdGVTdWJjbGFzcyhGYWNldGVkT2JqZWN0LCAnQ29tcG9uZW50JywgdHJ1ZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ29tcG9uZW50O1xuXG5fcmVnaXN0ZXJXaXRoRG9tU3RvcmFnZSgnQ29tcG9uZW50Jyk7XG5cblxuLyoqXG4gKiAjIyMjQ29tcG9uZW50IGNsYXNzIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbY3JlYXRlQ29tcG9uZW50Q2xhc3NdKCNDb21wb25lbnQkJGNyZWF0ZUNvbXBvbmVudENsYXNzKVxuICogLSBbY3JlYXRlXSgjQ29tcG9uZW50JCRjcmVhdGUpXG4gKiAtIFtjb3B5XSgjQ29tcG9uZW50JCRjb3B5KVxuICogLSBbY3JlYXRlT25FbGVtZW50XSgjQ29tcG9uZW50JCRjcmVhdGVPbkVsZW1lbnQpXG4gKiAtIFtpc0NvbXBvbmVudF0oY191dGlscy5qcy5odG1sI2lzQ29tcG9uZW50KVxuICogLSBbZ2V0Q29tcG9uZW50XShjX3V0aWxzLmpzLmh0bWwjZ2V0Q29tcG9uZW50KVxuICogLSBbZ2V0Q29udGFpbmluZ0NvbXBvbmVudF0oY191dGlscy5qcy5odG1sI2dldENvbnRhaW5pbmdDb21wb25lbnQpXG4gKiAtIFtjcmVhdGVGcm9tU3RhdGVdKCNDb21wb25lbnQkJGNyZWF0ZUZyb21TdGF0ZSlcbiAqIC0gW2NyZWF0ZUZyb21EYXRhVHJhbnNmZXJdKCNDb21wb25lbnQkJGNyZWF0ZUZyb21EYXRhVHJhbnNmZXIpXG4gKi9cbl8uZXh0ZW5kKENvbXBvbmVudCwge1xuICAgIGNyZWF0ZUNvbXBvbmVudENsYXNzOiBDb21wb25lbnQkJGNyZWF0ZUNvbXBvbmVudENsYXNzLFxuICAgIGNyZWF0ZTogQ29tcG9uZW50JCRjcmVhdGUsXG4gICAgY29weTogQ29tcG9uZW50JCRjb3B5LFxuICAgIGNyZWF0ZU9uRWxlbWVudDogQ29tcG9uZW50JCRjcmVhdGVPbkVsZW1lbnQsXG4gICAgaXNDb21wb25lbnQ6IGNvbXBvbmVudFV0aWxzLmlzQ29tcG9uZW50LFxuICAgIGdldENvbXBvbmVudDogY29tcG9uZW50VXRpbHMuZ2V0Q29tcG9uZW50LFxuICAgIGdldENvbnRhaW5pbmdDb21wb25lbnQ6IGNvbXBvbmVudFV0aWxzLmdldENvbnRhaW5pbmdDb21wb25lbnQsXG4gICAgY3JlYXRlRnJvbVN0YXRlOiBDb21wb25lbnQkJGNyZWF0ZUZyb21TdGF0ZSxcbiAgICBjcmVhdGVGcm9tRGF0YVRyYW5zZmVyOiBDb21wb25lbnQkJGNyZWF0ZUZyb21EYXRhVHJhbnNmZXJcbn0pO1xuZGVsZXRlIENvbXBvbmVudC5jcmVhdGVGYWNldGVkQ2xhc3M7XG5cblxuLyoqXG4gKiAjIyMjQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbaW5pdF0oI0NvbXBvbmVudCRpbml0KVxuICogLSBbY3JlYXRlRWxlbWVudF0oI0NvbXBvbmVudCRjcmVhdGVFbGVtZW50KVxuICogLSBbaGFzRmFjZXRdKCNDb21wb25lbnQkaGFzRmFjZXQpXG4gKiAtIFthZGRGYWNldF0oI0NvbXBvbmVudCRhZGRGYWNldClcbiAqIC0gW2FsbEZhY2V0c10oI0NvbXBvbmVudCRhbGxGYWNldHMpXG4gKiAtIFtyZW5hbWVdKCNDb21wb25lbnQkcmVuYW1lKVxuICogLSBbcmVtb3ZlXSgjQ29tcG9uZW50JHJlbW92ZSlcbiAqIC0gW2dldFN0YXRlXSgjQ29tcG9uZW50JGdldFN0YXRlKVxuICogLSBbZ2V0VHJhbnNmZXJTdGF0ZV0oI0NvbXBvbmVudCRnZXRUcmFuc2ZlclN0YXRlKVxuICogLSBbc2V0U3RhdGVdKCNDb21wb25lbnQkc2V0U3RhdGUpXG4gKiAtIFtnZXRTY29wZVBhcmVudF0oI0NvbXBvbmVudCRnZXRTY29wZVBhcmVudClcbiAqIC0gW2dldFRvcFNjb3BlUGFyZW50XSgjQ29tcG9uZW50JGdldFRvcFNjb3BlUGFyZW50KVxuICogLSBbZ2V0U2NvcGVQYXJlbnRXaXRoQ2xhc3NdKCNDb21wb25lbnQkZ2V0U2NvcGVQYXJlbnRXaXRoQ2xhc3MpXG4gKiAtIFtnZXRUb3BTY29wZVBhcmVudFdpdGhDbGFzc10oI0NvbXBvbmVudCRnZXRUb3BTY29wZVBhcmVudFdpdGhDbGFzcylcbiAqIC0gW3dhbGtTY29wZVRyZWVdKCNDb21wb25lbnQkd2Fsa1Njb3BlVHJlZSlcbiAqIC0gW2Jyb2FkY2FzdF0oI0NvbXBvbmVudCRicm9hZGNhc3QpXG4gKiAtIFtkZXN0cm95XSgjQ29tcG9uZW50JGRlc3Ryb3kpXG4gKiAtIFtpc0Rlc3Ryb3llZF0oI0NvbXBvbmVudCRpc0Rlc3Ryb3llZClcbiAqXG4gKlxuICogIyMjIyNbTWVzc2VuZ2VyXSguLi9tZXNzZW5nZXIvaW5kZXguanMuaHRtbCkgbWV0aG9kcyBhdmFpbGFibGUgb24gY29tcG9uZW50IyMjIyNcbiAqXG4gKiAtIFtvbl0oLi4vbWVzc2VuZ2VyL2luZGV4LmpzLmh0bWwjTWVzc2VuZ2VyJG9uKSAtIHNpbmdsZSBzdWJzY3JpYmVcbiAqIC0gW29mZl0oLi4vbWVzc2VuZ2VyL2luZGV4LmpzLmh0bWwjTWVzc2VuZ2VyJG9mZikgLSBzaW5nbGUgdW5zdWJzY3JpYmVcbiAqIC0gW29uTWVzc2FnZXNdKC4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sI01lc3NlbmdlciRvbk1lc3NhZ2VzKSAtIG11bHRpcGxlIHN1YnNjcmliZVxuICogLSBbb2ZmTWVzc2FnZXNdKC4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sI01lc3NlbmdlciRvZmZNZXNzYWdlcykgLSBtdWx0aXBsZSB1bnN1YnNjcmliZVxuICogLSBbcG9zdE1lc3NhZ2VdKC4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sI01lc3NlbmdlciRwb3N0TWVzc2FnZSkgLSBwb3N0IG1lc3NhZ2Ugb24gY29tcG9uZW50XG4gKiAtIFtnZXRTdWJzY3JpYmVyc10oLi4vbWVzc2VuZ2VyL2luZGV4LmpzLmh0bWwjTWVzc2VuZ2VyJGdldFN1YnNjcmliZXJzKSAtIGdldCBzdWJzY3JpYmVycyBmb3IgYSBnaXZlbiBtZXNzYWdlXG4gKi9cbl8uZXh0ZW5kUHJvdG8oQ29tcG9uZW50LCB7XG4gICAgaW5pdDogQ29tcG9uZW50JGluaXQsXG4gICAgc3RhcnQ6IENvbXBvbmVudCRzdGFydCxcbiAgICBjcmVhdGVFbGVtZW50OiBDb21wb25lbnQkY3JlYXRlRWxlbWVudCxcbiAgICBoYXNGYWNldDogQ29tcG9uZW50JGhhc0ZhY2V0LFxuICAgIGFkZEZhY2V0OiBDb21wb25lbnQkYWRkRmFjZXQsXG4gICAgYWxsRmFjZXRzOiBDb21wb25lbnQkYWxsRmFjZXRzLFxuICAgIHJlbmFtZTogQ29tcG9uZW50JHJlbmFtZSxcbiAgICByZW1vdmU6IENvbXBvbmVudCRyZW1vdmUsXG4gICAgaW5zZXJ0SW50bzogQ29tcG9uZW50JGluc2VydEludG8sXG5cbiAgICBnZXRTdGF0ZTogQ29tcG9uZW50JGdldFN0YXRlLFxuICAgIGdldFRyYW5zZmVyU3RhdGU6IENvbXBvbmVudCRnZXRUcmFuc2ZlclN0YXRlLFxuICAgIF9nZXRTdGF0ZTogQ29tcG9uZW50JF9nZXRTdGF0ZSxcbiAgICBzZXRTdGF0ZTogQ29tcG9uZW50JHNldFN0YXRlLFxuICAgIFxuICAgIGdldFNjb3BlUGFyZW50OiBDb21wb25lbnQkZ2V0U2NvcGVQYXJlbnQsXG4gICAgZ2V0VG9wU2NvcGVQYXJlbnQ6IENvbXBvbmVudCRnZXRUb3BTY29wZVBhcmVudCxcbiAgICBnZXRTY29wZVBhcmVudFdpdGhDbGFzczogQ29tcG9uZW50JGdldFNjb3BlUGFyZW50V2l0aENsYXNzLFxuICAgIGdldFRvcFNjb3BlUGFyZW50V2l0aENsYXNzOiBDb21wb25lbnQkZ2V0VG9wU2NvcGVQYXJlbnRXaXRoQ2xhc3MsXG5cbiAgICBzZXRTY29wZVBhcmVudEZyb21ET006IENvbXBvbmVudCRzZXRTY29wZVBhcmVudEZyb21ET00sXG5cbiAgICB3YWxrU2NvcGVUcmVlOiBDb21wb25lbnQkd2Fsa1Njb3BlVHJlZSxcblxuICAgIHRyZWVQYXRoT2Y6IENvbXBvbmVudCR0cmVlUGF0aE9mLFxuICAgIGdldENvbXBvbmVudEF0VHJlZVBhdGg6IENvbXBvbmVudCRnZXRDb21wb25lbnRBdFRyZWVQYXRoLFxuICAgIGluc2VydEF0VHJlZVBhdGg6IENvbXBvbmVudCRpbnNlcnRBdFRyZWVQYXRoLFxuXG4gICAgYnJvYWRjYXN0OiBDb21wb25lbnQkYnJvYWRjYXN0LFxuICAgIGRlc3Ryb3k6IENvbXBvbmVudCRkZXN0cm95LFxuICAgIGlzRGVzdHJveWVkOiBDb21wb25lbnQkaXNEZXN0cm95ZWRcbn0pO1xuXG5cbi8qKlxuICogRXhwb3NlIE1lc3NlbmdlciBtZXRob2RzIG9uIENvbXBvbmVudCBwcm90b3R5cGVcbiAqL1xudmFyIE1FU1NFTkdFUl9QUk9QRVJUWSA9ICdfbWVzc2VuZ2VyJztcbk1lc3Nlbmdlci51c2VXaXRoKENvbXBvbmVudCwgTUVTU0VOR0VSX1BST1BFUlRZLCBNZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMpO1xuXG5cbnZhciBDT01QT05FTlRfREFUQV9UWVBFX1BSRUZJWCA9ICd4LWFwcGxpY2F0aW9uL21pbG8tY29tcG9uZW50JztcbnZhciBDT01QT05FTlRfREFUQV9UWVBFX1JFR0VYID0gL3gtYXBwbGljYXRpb25cXC9taWxvLWNvbXBvbmVudFxcLyhbYS16XyRdWzAtOWEtel8kXSopKD86XFwvKCkpL2k7XG5cbi8qKlxuICogQ29tcG9uZW50IGNsYXNzIG1ldGhvZFxuICogQ3JlYXRlcyBhIHN1YmNsYXNzIG9mIGNvbXBvbmVudCBmcm9tIHRoZSBtYXAgb2YgY29uZmlndXJlZCBmYWNldHMuXG4gKiBUaGlzIG1ldGhvZCB3cmFwcyBhbmQgcmVwbGFjZXMgW2BjcmVhdGVGYWNldGVkQ2xhc3NgXSguLi9hYnN0cmFjdC9mYWNldGVkX29iamVjdC5qcy5odG1sI2NyZWF0ZUZhY2V0ZWRDbGFzcykgY2xhc3MgbWV0aG9kIG9mIEZhY2V0ZWRPYmplY3QuXG4gKiBVbmxpa2UgY3JlYXRlRmFjZXRlZENsYXNzLCB0aGlzIG1ldGhvZCB0YWtlIGZhY2V0IGNsYXNzZXMgZnJvbSByZWdpc3RyeSBieSB0aGVpciBuYW1lLCBzbyBvbmx5IG1hcCBvZiBmYWNldHMgY29uZmlndXJhdGlvbiBuZWVkcyB0byBiZSBwYXNzZWQuIEFsbCBmYWNldHMgY2xhc3NlcyBzaG91bGQgYmUgc3ViY2xhc3NlcyBvZiBbQ29tcG9uZW50RmFjZXRdKC4vY19mYWNldC5qcy5odG1sKVxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIGNsYXNzIG5hbWVcbiAqIEBwYXJhbSB7T2JqZWN0W09iamVjdF0gfCBBcnJheVtTdHJpbmddfSBmYWNldHNDb25maWcgbWFwIG9mIGZhY2V0cyBjb25maWd1cmF0aW9uLlxuICogIElmIHNvbWUgZmFjZXQgZG9lcyBub3QgcmVxdWlyZSBjb25maWd1cmF0aW9uLCBgdW5kZWZpbmVkYCBzaG91bGQgYmUgcGFzc2VkIGFzIHRoZSBjb25maWd1cmF0aW9uIGZvciB0aGUgZmFjZXQuXG4gKiAgSWYgbm8gZmFjZXQgcmVxdWlyZXMgY29uZmlndXJhdGlvbiwgdGhlIGFycmF5IG9mIGZhY2V0cyBuYW1lcyBjYW4gYmUgcGFzc2VkLlxuICogQHJldHVybiB7U3ViY2xhc3MoQ29tcG9uZW50KX1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JCRjcmVhdGVDb21wb25lbnRDbGFzcyhuYW1lLCBmYWNldHNDb25maWcpIHtcbiAgICAvLyBjb252ZXJ0IGFycmF5IG9mIGZhY2V0IG5hbWVzIHRvIG1hcCBvZiBlbXB0eSBmYWNldHMgY29uZmlndXJhdGlvbnNcbiAgICBpZiAoQXJyYXkuaXNBcnJheShmYWNldHNDb25maWcpKSB7XG4gICAgICAgIHZhciBjb25maWdNYXAgPSB7fTtcbiAgICAgICAgZmFjZXRzQ29uZmlnLmZvckVhY2goZnVuY3Rpb24oZmN0KSB7XG4gICAgICAgICAgICB2YXIgZmN0TmFtZSA9IF8uZmlyc3RMb3dlckNhc2UoZmN0KTtcbiAgICAgICAgICAgIGNvbmZpZ01hcFtmY3ROYW1lXSA9IHt9O1xuICAgICAgICB9KTtcbiAgICAgICAgZmFjZXRzQ29uZmlnID0gY29uZmlnTWFwO1xuICAgIH1cblxuICAgIC8vIGNvbnN0cnVjdCBtYXAgb2YgZmFjZXRzIGNsYXNzZXMgZnJvbSBmYWNldFJlZ2lzdHJ5XG4gICAgdmFyIGZhY2V0c0NsYXNzZXM7XG4gICAgaWYgKHR5cGVvZiBmYWNldHNDb25maWcgPT0gJ29iamVjdCcgJiYgXy5rZXlzKGZhY2V0c0NvbmZpZykubGVuZ3RoKSB7XG4gICAgICAgIGZhY2V0c0NsYXNzZXMgPSB7fTtcbiAgICAgICAgXy5lYWNoS2V5KGZhY2V0c0NvbmZpZywgZnVuY3Rpb24oZmN0Q29uZmlnLCBmY3QpIHtcbiAgICAgICAgICAgIHZhciBmY3ROYW1lID0gXy5maXJzdExvd2VyQ2FzZShmY3QpO1xuICAgICAgICAgICAgdmFyIGZjdENsYXNzTmFtZSA9IF8uZmlyc3RVcHBlckNhc2UoZmN0KTtcbiAgICAgICAgICAgIGZhY2V0c0NsYXNzZXNbZmN0TmFtZV0gPSBmYWNldHNSZWdpc3RyeS5nZXQoZmN0Q2xhc3NOYW1lKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gY3JlYXRlIHN1YmNsYXNzIG9mIENvbXBvbmVudCB1c2luZyBtZXRob2Qgb2YgRmFjZXRlZE9iamVjdFxuICAgIHZhciBDb21wb25lbnRDbGFzcyA9IEZhY2V0ZWRPYmplY3QuY3JlYXRlRmFjZXRlZENsYXNzLmNhbGwodGhpcywgbmFtZSwgZmFjZXRzQ2xhc3NlcywgZmFjZXRzQ29uZmlnKTtcbiAgICBcbiAgICBfcmVnaXN0ZXJXaXRoRG9tU3RvcmFnZShuYW1lKTtcblxuICAgIHJldHVybiBDb21wb25lbnRDbGFzcztcbn1cblxuXG5mdW5jdGlvbiBfcmVnaXN0ZXJXaXRoRG9tU3RvcmFnZShjbGFzc05hbWUpIHtcbiAgICBET01TdG9yYWdlLnJlZ2lzdGVyRGF0YVR5cGUoY2xhc3NOYW1lLCBDb21wb25lbnRfZG9tU3RvcmFnZVNlcmlhbGl6ZXIsIENvbXBvbmVudF9kb21TdG9yYWdlUGFyc2VyKTtcbn1cblxuXG5mdW5jdGlvbiBDb21wb25lbnRfZG9tU3RvcmFnZVNlcmlhbGl6ZXIoY29tcG9uZW50KSB7XG4gICAgdmFyIHN0YXRlID0gY29tcG9uZW50LmdldFN0YXRlKCk7XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHN0YXRlKTsgICBcbn1cblxuXG5mdW5jdGlvbiBDb21wb25lbnRfZG9tU3RvcmFnZVBhcnNlcihjb21wU3RyLCBjb21wQ2xhc3NOYW1lKSB7XG4gICAgdmFyIHN0YXRlID0ganNvblBhcnNlKGNvbXBTdHIpO1xuICAgIGlmIChzdGF0ZSlcbiAgICAgICAgcmV0dXJuIENvbXBvbmVudC5jcmVhdGVGcm9tU3RhdGUoc3RhdGUpO1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGNsYXNzIG1ldGhvZFxuICogQ3JlYXRlcyBjb21wb25lbnQgZnJvbSBbQ29tcG9uZW50SW5mb10oLi9jX2luZm8uanMuaHRtbCkgKHVzZWQgYnkgW21pbG8uYmluZGVyXSguLi9iaW5kZXIuanMuaHRtbCkgYW5kIHRvIGNvcHkgY29tcG9uZW50KVxuICogQ29tcG9uZW50IG9mIGFueSByZWdpc3RlcmVkIGNsYXNzIChzZWUgW2NvbXBvbmVudHNSZWdpc3RyeV0oLi9jX3JlZ2lzdHJ5LmpzLmh0bWwpKSB3aXRoIGFueSBhZGRpdGlvbmFsIHJlZ2lzdGVyZWQgZmFjZXRzIChzZWUgW2ZhY2V0c1JlZ2lzdHJ5XSguL2NfZmFjZXRzL2NmX3JlZ2lzdHJ5LmpzLmh0bWwpKSBjYW4gYmUgY3JlYXRlZCB1c2luZyB0aGlzIG1ldGhvZC5cbiAqXG4gKiBAcGFyYW0ge0NvbXBvbmVudEluZm99IGluZm9cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gdGhyb3dPbkVycm9ycyBJZiBzZXQgdG8gZmFsc2UsIHRoZW4gZXJyb3JzIHdpbGwgb25seSBiZSBsb2dnZWQgdG8gY29uc29sZS4gVHJ1ZSBieSBkZWZhdWx0LlxuIEAgQHJldHVybiB7Q29tcG9uZW50fVxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkJGNyZWF0ZShpbmZvLCB0aHJvd09uRXJyb3JzKSB7XG4gICAgdmFyIENvbXBvbmVudENsYXNzID0gaW5mby5Db21wb25lbnRDbGFzcztcblxuICAgIGlmICh0eXBlb2YgQ29tcG9uZW50Q2xhc3MgIT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICB2YXIgbWVzc2FnZSA9ICdjcmVhdGU6IGNvbXBvbmVudCBjbGFzcyBzaG91bGQgYmUgZnVuY3Rpb24sIFwiJyArIHR5cGVvZiBDb21wb25lbnRDbGFzcyArICdcIiBwYXNzZWQnOyBcbiAgICAgICAgaWYgKHRocm93T25FcnJvcnMgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ0NvbXBvbmVudCcsIG1lc3NhZ2UsICc7dXNpbmcgYmFzZSBDb21wb25lbnQgY2xhc3MgaW5zdGVhZCcpO1xuICAgICAgICAgICAgQ29tcG9uZW50Q2xhc3MgPSBDb21wb25lbnQ7XG4gICAgICAgIH0gZWxzZVxuICAgICAgICAgICAgdGhyb3cgbmV3IENvbXBvbmVudEVycm9yKG1lc3NhZ2UpO1xuICAgIH1cblxuICAgIHZhciBhQ29tcG9uZW50ID0gbmV3IENvbXBvbmVudENsYXNzKGluZm8uc2NvcGUsIGluZm8uZWwsIGluZm8ubmFtZSwgaW5mbyk7XG5cbiAgICBpZiAoaW5mby5leHRyYUZhY2V0c0NsYXNzZXMpXG4gICAgICAgIF8uZWFjaEtleShpbmZvLmV4dHJhRmFjZXRzQ2xhc3NlcywgZnVuY3Rpb24oRmFjZXRDbGFzcykge1xuICAgICAgICAgICAgaWYgKCEgYUNvbXBvbmVudC5oYXNGYWNldChGYWNldENsYXNzKSlcbiAgICAgICAgICAgICAgICBhQ29tcG9uZW50LmFkZEZhY2V0KEZhY2V0Q2xhc3MsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB0aHJvd09uRXJyb3JzKTtcbiAgICAgICAgfSk7XG5cbiAgICByZXR1cm4gYUNvbXBvbmVudDtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBjbGFzcyBtZXRob2RcbiAqIENyZWF0ZSBhIGNvcHkgb2YgY29tcG9uZW50LCBpbmNsdWRpbmcgYSBjb3B5IG9mIERPTSBlbGVtZW50LiBSZXR1cm5zIGEgY29weSBvZiBgY29tcG9uZW50YCAob2YgdGhlIHNhbWUgY2xhc3MpIHdpdGggbmV3IERPTSBlbGVtZW50IChub3QgaW5zZXJ0ZWQgaW50byBwYWdlKS5cbiAqIENvbXBvbmVudCBpcyBhZGRlZCB0byB0aGUgc2FtZSBzY29wZSBhcyB0aGUgb3JpZ2luYWwgY29tcG9uZW50LlxuICpcbiAqIEBwYXJhbSB7Q29tcG9uZW50fSBjb21wb25lbnQgYW4gaW5zdGFuY2Ugb2YgQ29tcG9uZW50IGNsYXNzIG9yIHN1YmNsYXNzXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGRlZXBDb3B5IG9wdGlvbmFsIGB0cnVlYCB0byBtYWtlIGRlZXAgY29weSBvZiBET00gZWxlbWVudCwgb3RoZXJ3aXNlIG9ubHkgZWxlbWVudCB3aXRob3V0IGNoaWxkcmVuIGlzIGNvcGllZFxuICogQHJldHVybiB7Q29tcG9uZW50fVxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkJGNvcHkoY29tcG9uZW50LCBkZWVwQ29weSkge1xuICAgIGNoZWNrKGNvbXBvbmVudCwgQ29tcG9uZW50KTtcbiAgICBjaGVjayhkZWVwQ29weSwgTWF0Y2guT3B0aW9uYWwoQm9vbGVhbikpO1xuXG4gICAgaWYgKGRlZXBDb3B5ICYmICFjb21wb25lbnQuY29udGFpbmVyKSBcbiAgICAgICAgdGhyb3cgbmV3IENvbXBvbmVudEVycm9yKCdDYW5ub3QgZGVlcCBjb3B5IGNvbXBvbmVudCB3aXRob3V0IGNvbnRhaW5lciBmYWNldCcpO1xuXG4gICAgLy8gY29weSBET00gZWxlbWVudCwgdXNpbmcgRG9tIGZhY2V0IGlmIGl0IGlzIGF2YWlsYWJsZVxuICAgIHZhciBuZXdFbCA9IGNvbXBvbmVudC5kb20gXG4gICAgICAgICAgICAgICAgICAgID8gY29tcG9uZW50LmRvbS5jb3B5KGRlZXBDb3B5KVxuICAgICAgICAgICAgICAgICAgICA6IGNvbXBvbmVudC5lbC5jbG9uZU5vZGUoZGVlcENvcHkpO1xuXG4gICAgdmFyIENvbXBvbmVudENsYXNzID0gY29tcG9uZW50LmNvbnN0cnVjdG9yO1xuXG4gICAgLy8gY3JlYXRlIGNvbXBvbmVudCBvZiB0aGUgc2FtZSBjbGFzcyBvbiB0aGUgZWxlbWVudFxuICAgIHZhciBhQ29tcG9uZW50ID0gQ29tcG9uZW50Q2xhc3MuY3JlYXRlT25FbGVtZW50KG5ld0VsLCB1bmRlZmluZWQsIGNvbXBvbmVudC5zY29wZSwgY29tcG9uZW50LmV4dHJhRmFjZXRzKTtcbiAgICB2YXIgc3RhdGUgPSBjb21wb25lbnQuX2dldFN0YXRlKGRlZXBDb3B5IHx8IGZhbHNlKTtcbiAgICBhQ29tcG9uZW50LnNldFN0YXRlKHN0YXRlKTtcbiAgICBfLmRlZmVyTWV0aG9kKGFDb21wb25lbnQsICdicm9hZGNhc3QnLCAnc3RhdGVyZWFkeScpO1xuICAgIHJldHVybiBhQ29tcG9uZW50O1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGNsYXNzIG1ldGhvZFxuICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBjb21wb25lbnQgYXRhY2hlZCB0byBlbGVtZW50LiBBbGwgc3ViY2xhc3NlcyBvZiBjb21wb25lbnQgaW5oZXJpdCB0aGlzIG1ldGhvZC5cbiAqIFJldHVybnMgdGhlIGNvbXBvbmVudCBvZiB0aGUgY2xhc3MgdGhpcyBtZXRob2QgaXMgdXNlZCB3aXRoICh0aGVjb250ZXh0IG9mIHRoZSBtZXRob2QgY2FsbCkuXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBlbCBvcHRpb25hbCBlbGVtZW50IHRvIGF0dGFjaCBjb21wb25lbnQgdG8uIElmIGVsZW1lbnQgaXMgbm90IHBhc3NlZCwgaXQgd2lsbCBiZSBjcmVhdGVkXG4gKiBAcGFyYW0ge1N0cmluZ30gaW5uZXJIVE1MIG9wdGlvbmFsIGlubmVyIGh0bWwgdG8gaW5zZXJ0IGluIGVsZW1lbnQgYmVmb3JlIGJpbmRpbmcuXG4gKiBAcGFyYW0ge1Njb3BlfSByb290U2NvcGUgb3B0aW9uYWwgc2NvcGUgdG8gcHV0IGNvbXBvbmVudCBpbi4gSWYgbm90IHBhc3NlZCwgY29tcG9uZW50IHdpbGwgYmUgYXR0YWNoZWQgdG8gdGhlIHNjb3BlIHRoYXQgY29udGFpbnMgdGhlIGVsZW1lbnQuIElmIHN1Y2ggc2NvcGUgZG9lcyBub3QgZXhpc3QsIG5ldyBzY29wZSB3aWxsIGJlIGNyZWF0ZWQuXG4gKiBAcGFyYW0ge0FycmF5W1N0cmluZ119IGV4dHJhRmFjZXRzIGxpc3Qgb2YgZXh0cmEgZmFjZXQgdG8gYWRkIHRvIGNvbXBvbmVudFxuICogQHJldHVybiB7U3ViY2xhc3MoQ29tcG9uZW50KX1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JCRjcmVhdGVPbkVsZW1lbnQoZWwsIGlubmVySFRNTCwgcm9vdFNjb3BlLCBleHRyYUZhY2V0cykge1xuICAgIGNoZWNrKGlubmVySFRNTCwgTWF0Y2guT3B0aW9uYWwoU3RyaW5nKSk7XG4gICAgY2hlY2socm9vdFNjb3BlLCBNYXRjaC5PcHRpb25hbChTY29wZSkpO1xuICAgIGNoZWNrKGV4dHJhRmFjZXRzLCBNYXRjaC5PcHRpb25hbChbU3RyaW5nXSkpO1xuXG4gICAgLy8gXCJ0aGlzXCIgcmVmZXJzIHRvIHRoZSBjbGFzcyBvZiBjb21wb25lbnQgaGVyZSwgYXMgdGhpcyBpcyBhIGNsYXNzIG1ldGhvZFxuICAgIGlmIChlbCAmJiBpbm5lckhUTUwpIGVsLmlubmVySFRNTCA9IGlubmVySFRNTDtcbiAgICBlbCA9IGVsIHx8IF9jcmVhdGVDb21wb25lbnRFbGVtZW50LmNhbGwodGhpcywgaW5uZXJIVE1MKTtcbiAgICByb290U2NvcGUgPSByb290U2NvcGUgfHwgX2ZpbmRPckNyZWF0ZUNvbXBvbmVudFJvb3RTY29wZShlbCk7XG4gICAgdmFyIGFDb21wb25lbnQgPSBfYWRkQXR0cmlidXRlQW5kQmluZENvbXBvbmVudC5jYWxsKHRoaXMsIGVsLCByb290U2NvcGUsIGV4dHJhRmFjZXRzKTtcbiAgICBhQ29tcG9uZW50LmJyb2FkY2FzdCgnc3RhdGVyZWFkeScpO1xuICAgIHJldHVybiBhQ29tcG9uZW50O1xufVxuXG5mdW5jdGlvbiBfY3JlYXRlQ29tcG9uZW50RWxlbWVudChpbm5lckhUTUwpIHtcbiAgICAvLyBcInRoaXNcIiByZWZlcnMgdG8gdGhlIGNsYXNzIG9mIGNvbXBvbmVudCBoZXJlLCBhcyB0aGlzIGlzIGEgY2xhc3MgbWV0aG9kXG4gICAgdmFyIERvbSA9IGZhY2V0c1JlZ2lzdHJ5LmdldCgnRG9tJylcbiAgICAgICAgLCBkb21GYWNldENvbmZpZyA9IHRoaXMuZ2V0RmFjZXRDb25maWcoJ2RvbScpXG4gICAgICAgICwgdGVtcGxhdGVGYWNldENvbmZpZyA9IHRoaXMuZ2V0RmFjZXRDb25maWcoJ3RlbXBsYXRlJylcbiAgICAgICAgLCB0ZW1wbGF0ZSA9IHRlbXBsYXRlRmFjZXRDb25maWcgJiYgdGVtcGxhdGVGYWNldENvbmZpZy50ZW1wbGF0ZTtcblxuICAgIHZhciBlbENvbmZpZyA9IHtcbiAgICAgICAgZG9tQ29uZmlnOiBkb21GYWNldENvbmZpZyxcbiAgICAgICAgdGVtcGxhdGU6IHRlbXBsYXRlLFxuICAgICAgICBjb250ZW50OiBpbm5lckhUTUxcbiAgICB9O1xuXG4gICAgcmV0dXJuIERvbS5jcmVhdGVFbGVtZW50KGVsQ29uZmlnKTtcbn1cblxuZnVuY3Rpb24gX2ZpbmRPckNyZWF0ZUNvbXBvbmVudFJvb3RTY29wZShlbCkge1xuICAgIHZhciBwYXJlbnQgPSBDb21wb25lbnQuZ2V0Q29udGFpbmluZ0NvbXBvbmVudChlbCwgZmFsc2UsICdDb250YWluZXInKTtcbiAgICByZXR1cm4gcGFyZW50ID8gcGFyZW50LmNvbnRhaW5lci5zY29wZSA6IG5ldyBTY29wZShlbCk7XG59XG5cbmZ1bmN0aW9uIF9hZGRBdHRyaWJ1dGVBbmRCaW5kQ29tcG9uZW50KGVsLCByb290U2NvcGUsIGV4dHJhRmFjZXRzKSB7XG4gICAgLy8gYWRkIGJpbmQgYXR0cmlidXRlIHRvIGVsZW1lbnRcbiAgICB2YXIgYXR0ciA9IG5ldyBCaW5kQXR0cmlidXRlKGVsKTtcbiAgICAvLyBcInRoaXNcIiByZWZlcnMgdG8gdGhlIGNsYXNzIG9mIGNvbXBvbmVudCBoZXJlLCBhcyB0aGlzIGlzIGEgY2xhc3MgbWV0aG9kXG4gICAgYXR0ci5jb21wQ2xhc3MgPSB0aGlzLm5hbWU7XG4gICAgYXR0ci5jb21wRmFjZXRzID0gZXh0cmFGYWNldHM7XG4gICAgYXR0ci5kZWNvcmF0ZSgpO1xuXG4gICAgLy8gc2hvdWxkIGJlIHJlcXVpcmVkIGhlcmUgdG8gcmVzb2x2ZSBjaXJjdWxhciBkZXBlbmRlbmN5XG4gICAgdmFyIG1pbG9CaW5kZXIgPSByZXF1aXJlKCcuLi9iaW5kZXInKTtcbiAgICBtaWxvQmluZGVyKGVsLCByb290U2NvcGUpO1xuXG4gICAgcmV0dXJuIHJvb3RTY29wZVthdHRyLmNvbXBOYW1lXTtcbn1cblxuLyoqXG4gKiBDb21wb25lbnQgY2xhc3MgbWV0aG9kXG4gKiBDcmVhdGVzIGNvbXBvbmVudCBmcm9tIGNvbXBvbmVudCBzdGF0ZSwgdGhhdCBpbmNsdWRlcyBpbmZvcm1hdGlvbiBhYm91dCBpdHMgY2xhc3MsIGV4dHJhIGZhY2V0cywgZmFjZXRzIGRhdGEgYW5kIGFsbCBzY29wZSBjaGlsZHJlbi5cbiAqIFRoaXMgaXMgdXNlZCB0byBzYXZlL2xvYWQsIGNvcHkvcGFzdGUgYW5kIGRyYWcvZHJvcCBjb21wb25lbnRcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc3RhdGUgc3RhdGUgZnJvbSB3aGljaCBjb21wb25lbnQgd2lsbCBiZSBjcmVhdGVkXG4gKiBAcGFyYW0ge1Njb3BlfSByb290U2NvcGUgc2NvcGUgdG8gd2hpY2ggY29tcG9uZW50IHdpbGwgYmUgYWRkZWRcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gbmV3VW5pcXVlTmFtZSBvcHRpb25hbCBgdHJ1ZWAgdG8gY3JlYXRlIGNvbXBvbmVudCB3aXRoIHRoZSBuYW1lIGRpZmZlcmVudCBmcm9tIHRoZSBvcmlnaW5hbCBvbmUuIGBGYWxzZWAgYnkgZGVmYXVsdC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gdGhyb3dPbkVycm9ycyBJZiBzZXQgdG8gZmFsc2UsIHRoZW4gZXJyb3JzIHdpbGwgb25seSBiZSBsb2dnZWQgdG8gY29uc29sZS4gVHJ1ZSBieSBkZWZhdWx0LlxuICogQHJldHVybiB7Q29tcG9uZW50fSBjb21wb25lbnRcbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JCRjcmVhdGVGcm9tU3RhdGUoc3RhdGUsIHJvb3RTY29wZSwgbmV3VW5pcXVlTmFtZSwgdGhyb3dPbkVycm9ycykge1xuICAgIGNoZWNrKHN0YXRlLCBNYXRjaC5PYmplY3RJbmNsdWRpbmcoe1xuICAgICAgICBjb21wTmFtZTogTWF0Y2guT3B0aW9uYWwoU3RyaW5nKSxcbiAgICAgICAgY29tcENsYXNzOiBNYXRjaC5PcHRpb25hbChTdHJpbmcpLFxuICAgICAgICBleHRyYUZhY2V0czogTWF0Y2guT3B0aW9uYWwoW1N0cmluZ10pLFxuICAgICAgICBmYWNldHNTdGF0ZXM6IE1hdGNoLk9wdGlvbmFsKE9iamVjdCksXG4gICAgICAgIG91dGVySFRNTDogU3RyaW5nXG4gICAgfSkpO1xuXG4gICAgdmFyIG1pbG9CaW5kZXIgPSByZXF1aXJlKCcuLi9iaW5kZXInKTtcblxuICAgIC8vIGNyZWF0ZSB3cmFwcGVyIGVsZW1lbnQgb3B0aW9uYWxseSByZW5hbWluZyBjb21wb25lbnRcbiAgICB2YXIgd3JhcEVsID0gX2NyZWF0ZUNvbXBvbmVudFdyYXBFbGVtZW50KHN0YXRlLCBuZXdVbmlxdWVOYW1lKTtcblxuICAgIC8vIGluc3RhbnRpYXRlIGFsbCBjb21wb25lbnRzIGZyb20gSFRNTFxuICAgIHZhciBzY29wZSA9IG1pbG9CaW5kZXIod3JhcEVsLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdGhyb3dPbkVycm9ycyk7XG5cbiAgICAvLyBhcyB0aGVyZSBzaG91bGQgb25seSBiZSBvbmUgY29tcG9uZW50LCBjYWxsIHRvIF9hbnkgd2lsbCByZXR1cm4gaXRcbiAgICB2YXIgY29tcG9uZW50ID0gc2NvcGUuX2FueSgpO1xuXG4gICAgLy8gc2V0IGNvbXBvbmVudCdzIHNjb3BlXG4gICAgaWYgKHJvb3RTY29wZSkge1xuICAgICAgICBjb21wb25lbnQuc2NvcGUgPSByb290U2NvcGU7XG4gICAgICAgIHJvb3RTY29wZS5fYWRkKGNvbXBvbmVudCk7XG4gICAgfVxuXG4gICAgLy8gcmVzdG9yZSBjb21wb25lbnQgc3RhdGVcbiAgICBjb21wb25lbnQuc2V0U3RhdGUoc3RhdGUpO1xuICAgIF8uZGVmZXJNZXRob2QoY29tcG9uZW50LCAnYnJvYWRjYXN0JywgJ3N0YXRlcmVhZHknKTtcblxuICAgIHJldHVybiBjb21wb25lbnQ7ICAgXG59XG5cblxuLy8gdXNlZCBieSBDb21wb25lbnQkJGNyZWF0ZUZyb21TdGF0ZVxuZnVuY3Rpb24gX2NyZWF0ZUNvbXBvbmVudFdyYXBFbGVtZW50KHN0YXRlLCBuZXdVbmlxdWVOYW1lKSB7XG4gICAgdmFyIHdyYXBFbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgIHdyYXBFbC5pbm5lckhUTUwgPSBzdGF0ZS5vdXRlckhUTUw7XG5cbiAgICB2YXIgY2hpbGRyZW4gPSBkb21VdGlscy5jaGlsZHJlbih3cmFwRWwpO1xuICAgIGlmIChjaGlsZHJlbi5sZW5ndGggIT0gMSlcbiAgICAgICAgdGhyb3cgbmV3IENvbXBvbmVudEVycm9yKCdjYW5ub3QgY3JlYXRlIGNvbXBvbmVudDogaW5jb3JyZWN0IEhUTUwsIGVsZW1lbnRzIG51bWJlcjogJyArIGNoaWxkcmVuLmxlbmd0aCArICcgKHNob3VsZCBiZSAxKScpO1xuICAgIHZhciBjb21wRWwgPSBjaGlsZHJlblswXTtcbiAgICB2YXIgYXR0ciA9IG5ldyBCaW5kQXR0cmlidXRlKGNvbXBFbCk7XG4gICAgYXR0ci5jb21wTmFtZSA9IG5ld1VuaXF1ZU5hbWUgPyBtaWxvQ29tcG9uZW50TmFtZSgpIDogc3RhdGUuY29tcE5hbWU7XG4gICAgYXR0ci5jb21wQ2xhc3MgPSBzdGF0ZS5jb21wQ2xhc3M7XG4gICAgYXR0ci5jb21wRmFjZXRzID0gc3RhdGUuZXh0cmFGYWNldHM7XG4gICAgYXR0ci5kZWNvcmF0ZSgpO1xuXG4gICAgcmV0dXJuIHdyYXBFbDtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgY29tcG9uZW50IGZyb20gYSBEYXRhVHJhbnNmZXIgb2JqZWN0IChpZiBwb3NzaWJsZSlcbiAqXG4gKiBAc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9EYXRhVHJhbnNmZXJcbiAqIEBwYXJhbSB7RGF0YVRyYW5zZmVyfSBkYXRhVHJhbnNmZXIgRGF0YSB0cmFuc2ZlclxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkJGNyZWF0ZUZyb21EYXRhVHJhbnNmZXIoZGF0YVRyYW5zZmVyKSB7XG4gICAgdmFyIGRhdGFUeXBlID0gXy5maW5kKGRhdGFUcmFuc2Zlci50eXBlcywgZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgcmV0dXJuIENPTVBPTkVOVF9EQVRBX1RZUEVfUkVHRVgudGVzdCh0eXBlKTtcbiAgICB9KTtcbiAgICBpZiAoIWRhdGFUeXBlKSByZXR1cm47XG5cbiAgICB2YXIgc3RhdGUgPSBfLmpzb25QYXJzZShkYXRhVHJhbnNmZXIuZ2V0RGF0YShkYXRhVHlwZSkpO1xuICAgIGlmICghc3RhdGUpIHJldHVybjtcblxuICAgIHJldHVybiBDb21wb25lbnQuY3JlYXRlRnJvbVN0YXRlKHN0YXRlLCB1bmRlZmluZWQsIHRydWUpO1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZC5cbiAqIEluaXRpYWxpemVzIGNvbXBvbmVudC4gQXV0b21hdGljYWxseSBjYWxsZWQgYnkgaW5oZXJpdGVkIGNvbnN0cnVjdG9yIG9mIEZhY2V0ZWRPYmplY3QuXG4gKiBTdWJjbGFzc2VzIHNob3VsZCBjYWxsIGluaGVyaXRlZCBpbml0IG1ldGhvZHM6XG4gKiBgYGBcbiAqIENvbXBvbmVudC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpXG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge1Njb3BlfSBzY29wZSBzY29wZSB0byB3aGljaCBjb21wb25lbnQgd2lsbCBiZWxvbmcuIEl0IGlzIHVzdWFsbHkgYSB0b3AgbGV2ZWwgc2NvcGUgb2JqZWN0IHJldHVybmVkIGJ5IGBtaWxvLmJpbmRlcmAgb3IgYHNjb3BlYCBwcm9wZXJ0eSBvZiBDb250YWluZXIgZmFjZXQuXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsZW1lbnQgRE9NIGVsZW1lbnQgdGhhdCBjb21wb25lbnQgaXMgYXR0YWNoZWQgdG9cbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIGNvbXBvbmVudCBuYW1lLCBzaG91bGQgYmUgdW5pcXVlIGluIHRoZSBzY29wZSBvZiBjb21wb25lbnRcbiAqIEBwYXJhbSB7Q29tcG9uZW50SW5mb30gY29tcG9uZW50SW5mbyBpbnN0YW5jZSBvZiBDb21wb25lbnRJbmZvIGNsYXNzIHRoYXQgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGEgY29weSBvZiBjb21wb25lbnRcbiAqICBUT0RPIHRyeSByZW1vdmluZyBpdFxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkaW5pdChzY29wZSwgZWxlbWVudCwgbmFtZSwgY29tcG9uZW50SW5mbykge1xuICAgIC8vIGNyZWF0ZSBET00gZWxlbWVudCBpZiBpdCB3YXNuJ3QgcGFzc2VkIHRvIENvbnN0cnVjdG9yXG4gICAgdGhpcy5lbCA9IGVsZW1lbnQgfHwgdGhpcy5jcmVhdGVFbGVtZW50KCk7XG5cbiAgICAvLyBzdG9yZSByZWZlcmVuY2UgdG8gY29tcG9uZW50IG9uIERPTSBlbGVtZW50XG4gICAgaWYgKHRoaXMuZWwpIHtcbiAgICAgICAgLy8gY2hlY2sgdGhhdCBlbGVtZW50IGRvZXMgbm90IGhhdmUgYSBjb21wb25lbnQgYWxyZWFkeSBhdGFjaGVkXG4gICAgICAgIHZhciBlbENvbXAgPSB0aGlzLmVsW2NvbmZpZy5jb21wb25lbnRSZWZdO1xuICAgICAgICBpZiAoZWxDb21wKVxuICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ2NvbXBvbmVudCAnICsgbmFtZSArICcgYXR0YWNoZWQgdG8gZWxlbWVudCB0aGF0IGFscmVhZHkgaGFzIGNvbXBvbmVudCAnICsgZWxDb21wLm5hbWUpO1xuXG4gICAgICAgIHRoaXMuZWxbY29uZmlnLmNvbXBvbmVudFJlZl0gPSB0aGlzO1xuICAgIH1cblxuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgIGNvbXBvbmVudEluZm86IGNvbXBvbmVudEluZm8sXG4gICAgICAgIGV4dHJhRmFjZXRzOiBbXVxuICAgIH0sIF8uRU5VTSk7XG5cbiAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgIHRoaXMuc2NvcGUgPSBzY29wZTtcblxuICAgIC8vIGNyZWF0ZSBjb21wb25lbnQgbWVzc2VuZ2VyXG4gICAgdmFyIG1lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXIodGhpcyk7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBNRVNTRU5HRVJfUFJPUEVSVFksIG1lc3Nlbmdlcik7XG5cbiAgICAvLyBjaGVjayBhbGwgZmFjZXRzIGRlcGVuZGVuY2llcyAocmVxdWlyZWQgZmFjZXRzKVxuICAgIHRoaXMuYWxsRmFjZXRzKCdjaGVjaycpO1xuXG4gICAgLy8gc3RhcnQgYWxsIGZhY2V0c1xuICAgIHRoaXMuYWxsRmFjZXRzKCdzdGFydCcpO1xuXG4gICAgLy8gY2FsbCBzdGFydCBtZXRob2QgaWYgaXQncyBkZWZpbmVkIGluIHN1YmNsYXNzXG4gICAgaWYgKHRoaXMuc3RhcnQpIHRoaXMuc3RhcnQoKTtcbn1cblxuXG4vKipcbiAqIFRoaXMgaXMgYSBzdHViIHRvIGF2b2lkIGNvbmZ1c2lvbiB3aGV0aGVyIHRoZSBtZXRob2Qgb2Ygc3VwZXJjbGFzcyBzaG91bGQgYmUgY2FsbGVkIGluIHN1YmNsYXNzZXNcbiAqIFRoZSBzdGFydCBtZXRob2Qgb2Ygc3ViY2xhc3MgaW5zdGFuY2UgaXMgY2FsbGVkIG9uY2UgYWxsIHRoZSBmYWNldHMgYXJlIGNyZWF0ZWQsIGluaXRpYWxpemVkIGFuZCBzdGFydGVkIChzZWUgYWJvdmUpXG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRzdGFydCgpIHt9XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kLlxuICogSW5pdGlhbGl6ZXMgdGhlIGVsZW1lbnQgd2hpY2ggdGhpcyBjb21wb25lbnQgaXMgYm91bmQgdG9cbiAqXG4gKiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgd2hlbiBhIGNvbXBvbmVudCBpcyBpbnN0YW50aWF0ZWQgb3V0c2lkZSB0aGUgRE9NIGFuZFxuICogd2lsbCBnZW5lcmF0ZSBhIG5ldyBlbGVtZW50IGZvciB0aGUgY29tcG9uZW50LlxuICogXG4gKiBAcmV0dXJuIHtFbGVtZW50fVxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkY3JlYXRlRWxlbWVudCgpIHtcbiAgICBpZiAodHlwZW9mIGRvY3VtZW50ID09ICd1bmRlZmluZWQnKVxuICAgICAgICByZXR1cm47XG5cbiAgICB0aGlzLmVsID0gdGhpcy5kb21cbiAgICAgICAgICAgICAgICA/IHRoaXMuZG9tLmNyZWF0ZUVsZW1lbnQoKVxuICAgICAgICAgICAgICAgIDogZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnRElWJyk7XG5cbiAgICByZXR1cm4gdGhpcy5lbDtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgdHJ1ZSBpZiBjb21wb25lbnQgaGFzIGZhY2V0XG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbnxTdHJpbmd9IGZhY2V0TmFtZU9yQ2xhc3NcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRoYXNGYWNldChmYWNldE5hbWVPckNsYXNzKSB7XG4gICAgdmFyIGZhY2V0TmFtZSA9IF8uZmlyc3RMb3dlckNhc2UodHlwZW9mIGZhY2V0TmFtZU9yQ2xhc3MgPT0gJ2Z1bmN0aW9uJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gZmFjZXROYW1lT3JDbGFzcy5uYW1lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiBmYWNldE5hbWVPckNsYXNzKTtcblxuICAgIHZhciBmYWNldCA9IHRoaXNbZmFjZXROYW1lXTtcbiAgICBpZiAoISBmYWNldCBpbnN0YW5jZW9mIENvbXBvbmVudEZhY2V0KVxuICAgICAgICBsb2dnZXIud2FybignZXhwZWN0ZWQgZmFjZXQnLCBmYWNldE5hbWUsICdidXQgdGhpcyBwcm9wZXJ0eSBuYW1lIGlzIHVzZWQgZm9yIHNvbWV0aGluZyBlbHNlJyk7XG5cbiAgICByZXR1cm4gISEgZmFjZXQ7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kLlxuICogQWRkcyBmYWNldCB3aXRoIGdpdmVuIG5hbWUgb3IgY2xhc3MgdG8gdGhlIGluc3RhbmNlIG9mIENvbXBvbmVudCAob3IgaXRzIHN1YmNsYXNzKS5cbiAqIFxuICogQHBhcmFtIHtTdHJpbmd8U3ViY2xhc3MoQ29tcG9uZW50KX0gZmFjZXROYW1lT3JDbGFzcyBuYW1lIG9mIGZhY2V0IGNsYXNzIG9yIHRoZSBjbGFzcyBpdHNlbGYuIElmIG5hbWUgaXMgcGFzc2VkLCB0aGUgY2xhc3Mgd2lsbCBiZSByZXRpcmV2ZWQgZnJvbSBmYWNldHNSZWdpc3RyeVxuICogQHBhcmFtIHtPYmplY3R9IGZhY2V0Q29uZmlnIG9wdGlvbmFsIGZhY2V0IGNvbmZpZ3VyYXRpb25cbiAqIEBwYXJhbSB7U3RyaW5nfSBmYWNldE5hbWUgb3B0aW9uYWwgZmFjZXQgbmFtZS4gQWxsb3dzIHRvIGFkZCBmYWNldCB1bmRlciBhIG5hbWUgZGlmZmVyZW50IGZyb20gdGhlIGNsYXNzIG5hbWUgc3VwcGxpZWQuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHRocm93T25FcnJvcnMgSWYgc2V0IHRvIGZhbHNlLCB0aGVuIGVycm9ycyB3aWxsIG9ubHkgYmUgbG9nZ2VkIHRvIGNvbnNvbGUuIFRydWUgYnkgZGVmYXVsdC5cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JGFkZEZhY2V0KGZhY2V0TmFtZU9yQ2xhc3MsIGZhY2V0Q29uZmlnLCBmYWNldE5hbWUsIHRocm93T25FcnJvcnMpIHtcbiAgICBjaGVjayhmYWNldE5hbWVPckNsYXNzLCBNYXRjaC5PbmVPZihTdHJpbmcsIE1hdGNoLlN1YmNsYXNzKENvbXBvbmVudEZhY2V0KSkpO1xuICAgIGNoZWNrKGZhY2V0Q29uZmlnLCBNYXRjaC5PcHRpb25hbChPYmplY3QpKTtcbiAgICBjaGVjayhmYWNldE5hbWUsIE1hdGNoLk9wdGlvbmFsKFN0cmluZykpO1xuXG4gICAgdmFyIEZhY2V0Q2xhc3M7XG4gICAgLy8gaWYgb25seSBuYW1lIHBhc3NlZCwgcmV0cmlldmUgZmFjZXQgY2xhc3MgZnJvbSByZWdpc3RyeVxuICAgIGlmICh0eXBlb2YgZmFjZXROYW1lT3JDbGFzcyA9PSAnc3RyaW5nJykge1xuICAgICAgICB2YXIgZmFjZXRDbGFzc05hbWUgPSBfLmZpcnN0VXBwZXJDYXNlKGZhY2V0TmFtZU9yQ2xhc3MpO1xuICAgICAgICBGYWNldENsYXNzID0gZmFjZXRzUmVnaXN0cnkuZ2V0KGZhY2V0Q2xhc3NOYW1lKTtcbiAgICB9IGVsc2UgXG4gICAgICAgIEZhY2V0Q2xhc3MgPSBmYWNldE5hbWVPckNsYXNzO1xuXG4gICAgaWYgKCFmYWNldE5hbWUpXG4gICAgICAgIGZhY2V0TmFtZSA9IF8uZmlyc3RMb3dlckNhc2UoRmFjZXRDbGFzcy5uYW1lKTtcblxuICAgIHRoaXMuZXh0cmFGYWNldHMucHVzaChmYWNldE5hbWUpO1xuXG4gICAgLy8gYWRkIGZhY2V0IHVzaW5nIG1ldGhvZCBvZiBGYWNldGVkT2JqZWN0XG4gICAgdmFyIG5ld0ZhY2V0ID0gRmFjZXRlZE9iamVjdC5wcm90b3R5cGUuYWRkRmFjZXQuY2FsbCh0aGlzLCBGYWNldENsYXNzLCBmYWNldENvbmZpZywgZmFjZXROYW1lLCB0aHJvd09uRXJyb3JzKTtcblxuICAgIC8vIGNoZWNrIGRlcGVuZWRlbmNpZXMgYW5kIHN0YXJ0IGZhY2V0XG4gICAgaWYgKG5ld0ZhY2V0LmNoZWNrKSBuZXdGYWNldC5jaGVjaygpO1xuICAgIGlmIChuZXdGYWNldC5zdGFydCkgbmV3RmFjZXQuc3RhcnQoKTtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2QuXG4gKiBFbnZva2UgZ2l2ZW4gbWV0aG9kIHdpdGggb3B0aW9uYWwgcGFyYW1ldGVycyBvbiBhbGwgZmFjZXRzLlxuICogUmV0dXJucyB0aGUgbWFwIG9mIHZhbHVlcyByZXR1cm5lZCBieSBhbGwgZmFjZXRzLiBJZiB0aGUgZmFjZXQgZG9lc24ndCBoYXZlIHRoZSBtZXRob2QgaXQgaXMgc2ltcGx5IG5vdCBjYWxsZWQgYW5kIHRoZSB2YWx1ZSBpbiB0aGUgbWFwIHdpbGwgYmUgdW5kZWZpbmVkLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXRob2QgbWV0aG9kIG5hbWUgdG8gZW52b2tlIG9uIHRoZSBmYWNldFxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkYWxsRmFjZXRzKG1ldGhvZCkgeyAvLyAsLi4uIGFyZ3VtZW50c1xuICAgIHZhciBhcmdzID0gXy5zbGljZShhcmd1bWVudHMsIDEpO1xuXG4gICAgcmV0dXJuIF8ubWFwS2V5cyh0aGlzLmZhY2V0cywgZnVuY3Rpb24oZmFjZXQsIGZjdE5hbWUpIHtcbiAgICAgICAgaWYgKGZhY2V0ICYmIHR5cGVvZiBmYWNldFttZXRob2RdID09ICdmdW5jdGlvbicpXG4gICAgICAgICAgICByZXR1cm4gZmFjZXRbbWV0aG9kXS5hcHBseShmYWNldCwgYXJncyk7XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kLlxuICogXG4gKiBAcGFyYW0ge1tTdHJpbmddfSBuYW1lIG9wdGlvbmFsIG5ldyBuYW1lIG9mIGNvbXBvbmVudCwgXG4gKiBAcGFyYW0ge1tCb29sZWFuXX0gcmVuYW1lSW5TY29wZSBvcHRpb25hbCBmYWxzZSB0byBub3QgcmVuYW1lIENvbXBvbmVudEluZm8gb2JqZWN0IGluIGl0cyBzY29wZSwgdHJ1ZSBieSBkZWZhdWx0XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRyZW5hbWUobmFtZSwgcmVuYW1lSW5TY29wZSkge1xuICAgIG5hbWUgPSBuYW1lIHx8IG1pbG9Db21wb25lbnROYW1lKCk7XG4gICAgdGhpcy5jb21wb25lbnRJbmZvLnJlbmFtZShuYW1lLCBmYWxzZSk7XG4gICAgU2NvcGUucmVuYW1lKHRoaXMsIG5hbWUsIHJlbmFtZUluU2NvcGUpO1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZC5cbiAqIFJlbW92ZXMgY29tcG9uZW50IGZyb20gaXRzIHNjb3BlLlxuICpcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gcHJlc2VydmVTY29wZVByb3BlcnR5IHRydWUgbm90IHRvIGRlbGV0ZSBzY29wZSBwcm9wZXJ0eSBvZiBjb21wb25lbnRcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gcXVpZXQgb3B0aW9uYWwgdHJ1ZSB0byBzdXBwcmVzcyB0aGUgd2FybmluZyBtZXNzYWdlIGlmIHRoZSBjb21wb25lbnQgaXMgbm90IGluIHNjb3BlXG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRyZW1vdmUocHJlc2VydmVTY29wZVByb3BlcnR5LCBxdWlldCkge1xuICAgIGlmICh0aGlzLnNjb3BlKSB7XG4gICAgICAgIHRoaXMuc2NvcGUuX3JlbW92ZSh0aGlzLm5hbWUsIHF1aWV0KTtcbiAgICAgICAgaWYgKCEgcHJlc2VydmVTY29wZVByb3BlcnR5KVxuICAgICAgICAgICAgZGVsZXRlIHRoaXMuc2NvcGU7XG4gICAgfVxufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZC5cbiAqIEluc2VydHMgdGhlIGNvbXBvbmVudCBpbnRvIHRoZSBET00gYW5kIGF0dGVtcHRzIHRvIGFkanVzdCB0aGUgc2NvcGUgdHJlZSBhY2NvcmRpbmdseS5cbiAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IHBhcmVudEVsICAgIFRoZSBlbGVtZW50IGludG8gd2hpY2ggdGhlIGNvbXBvbmVudCBzaG91bGQgYmUgaW5zZXJ0ZWQuXG4gKiBAcGFyYW0ge0hUTUxFbGVtZW50fSByZWZlcmVuY2VFbCAob3B0aW9uYWwpIFRoZSByZWZlcmVuY2UgZWxlbWVudCBpdCBzaG91bGQgYmUgaW5zZXJ0ZWQgYmVmb3JlLlxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkaW5zZXJ0SW50byhwYXJlbnRFbCwgcmVmZXJlbmNlRWwpIHtcbiAgICBwYXJlbnRFbC5pbnNlcnRCZWZvcmUodGhpcy5lbCwgcmVmZXJlbmNlRWwpO1xuICAgIHRoaXMuc2V0U2NvcGVQYXJlbnRGcm9tRE9NKCk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXRyaWV2ZXMgYWxsIGNvbXBvbmVudCBzdGF0ZSwgaW5jbHVkaW5nIGluZm9ybWF0aW9uIGFib3V0IGl0cyBjbGFzcywgZXh0cmEgZmFjZXRzLCBmYWNldHMgZGF0YSBhbmQgYWxsIHNjb3BlIGNoaWxkcmVuLlxuICogVGhpcyBpbmZvcm1hdGlvbiBpcyB1c2VkIHRvIHNhdmUvbG9hZCwgY29weS9wYXN0ZSBhbmQgZHJhZy9kcm9wIGNvbXBvbmVudCBcbiAqIFJldHVybnMgY29tcG9uZW50IHN0YXRlXG4gKlxuICogQHRoaXMge0NvbXBvbmVudH0gY29tcG9uZW50IHdoaWNoIHN0YXRlIHdpbGwgYmUgc2F2ZWRcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JGdldFN0YXRlKCkge1xuICAgIHRoaXMuYnJvYWRjYXN0KCdnZXRzdGF0ZXN0YXJ0ZWQnLCB7IHJvb3RDb21wb25lbnQ6IHRoaXMgfSwgdW5kZWZpbmVkLCB0cnVlKTtcbiAgICB2YXIgc3RhdGUgPSB0aGlzLl9nZXRTdGF0ZSh0cnVlKTtcbiAgICBzdGF0ZS5vdXRlckhUTUwgPSB0aGlzLmVsLm91dGVySFRNTDtcbiAgICBfLmRlZmVyTWV0aG9kKHRoaXMsICdicm9hZGNhc3QnLCAnZ2V0c3RhdGVjb21wbGV0ZWQnLCB7IHJvb3RDb21wb25lbnQ6IHRoaXMgfSwgdW5kZWZpbmVkLCB0cnVlKTtcbiAgICByZXR1cm4gc3RhdGU7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXRyaWV2ZXMgYWxsIGNvbXBvbmVudCBzdGF0ZSwgaW5jbHVkaW5nIGluZm9ybWF0aW9uIGFib3V0IGl0cyBjbGFzcywgZXh0cmEgZmFjZXRzLCBmYWNldHMgZGF0YSBhbmQgYWxsIHNjb3BlIGNoaWxkcmVuLlxuICogVGhpcyBpbmZvcm1hdGlvbiBpcyB1c2VkIHRvIHNhdmUvbG9hZCwgY29weS9wYXN0ZSBhbmQgZHJhZy9kcm9wIGNvbXBvbmVudCBcbiAqIElmIGNvbXBvbmVudCBoYXMgW1RyYW5zZmVyXSguL2NfZmFjZXRzL1RyYW5zZmVyLmpzLmh0bWwpIGZhY2V0IG9uIGl0LCB0aGlzIG1ldGhvZCByZXRyaWV2ZXMgc3RhdGUgZnJvbSB0aGlzIGZhY2V0XG4gKiBSZXR1cm5zIGNvbXBvbmVudCBzdGF0ZVxuICpcbiAqIEB0aGlzIHtDb21wb25lbnR9IGNvbXBvbmVudCB3aGljaCBzdGF0ZSB3aWxsIGJlIHNhdmVkXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBjYW4gYmUgdXNlZCBieSBzdWJjbGFzc2VzLiBcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JGdldFRyYW5zZmVyU3RhdGUob3B0aW9ucykge1xuICAgIHJldHVybiB0aGlzLnRyYW5zZmVyXG4gICAgICAgICAgICA/IHRoaXMudHJhbnNmZXIuZ2V0U3RhdGUob3B0aW9ucylcbiAgICAgICAgICAgIDogdGhpcy5nZXRTdGF0ZShvcHRpb25zKTtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgdGhlIHN0YXRlIG9mIGNvbXBvbmVudFxuICogVXNlZCBieSBjbGFzcyBtZXRob2QgYENvbXBvbmVudC5nZXRTdGF0ZWAgYW5kIGJ5IFtDb250YWluZXJdKC4vY19mYWNldHMvQ29udGFpbmVyLmpzLmh0bWwpIGZhY2V0LlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGRlZXBTdGF0ZSBmYWxzZSB0byBnZXQgc2hhbGxvdyBzdGF0ZSBmcm9tIGFsbCBmYWNldHMgKHRydWUgYnkgZGVmYXVsdClcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JF9nZXRTdGF0ZShkZWVwU3RhdGUpe1xuXG4gICAgdmFyIGZhY2V0c1N0YXRlcyA9IHRoaXMuYWxsRmFjZXRzKCdnZXRTdGF0ZScsIGRlZXBTdGF0ZSA9PT0gZmFsc2UgPyBmYWxzZSA6IHRydWUpO1xuICAgIGZhY2V0c1N0YXRlcyA9IF8uZmlsdGVyS2V5cyhmYWNldHNTdGF0ZXMsIGZ1bmN0aW9uKGZjdFN0YXRlKSB7XG4gICAgICAgIHJldHVybiAhISBmY3RTdGF0ZTtcbiAgICB9KTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIGNvbXBOYW1lOiB0aGlzLm5hbWUsXG4gICAgICAgIGNvbXBDbGFzczogdGhpcy5jb25zdHJ1Y3Rvci5uYW1lLFxuICAgICAgICBleHRyYUZhY2V0czogdGhpcy5leHRyYUZhY2V0cyxcbiAgICAgICAgZmFjZXRzU3RhdGVzOiBmYWNldHNTdGF0ZXNcbiAgICB9O1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZFxuICogU2V0cyB0aGUgc3RhdGUgb2YgY29tcG9uZW50LlxuICogVXNlZCBieSBjbGFzcyBtZXRob2QgYENvbXBvbmVudC5jcmVhdGVGcm9tU3RhdGVgIGFuZCBieSBbQ29udGFpbmVyXSguL2NfZmFjZXRzL0NvbnRhaW5lci5qcy5odG1sKSBmYWNldC5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtPYmplY3R9IHN0YXRlIHN0YXRlIHRvIHNldCB0aGUgY29tcG9uZW50XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRzZXRTdGF0ZShzdGF0ZSkge1xuICAgIGlmIChzdGF0ZS5mYWNldHNTdGF0ZXMpXG4gICAgICAgIF8uZWFjaEtleShzdGF0ZS5mYWNldHNTdGF0ZXMsIGZ1bmN0aW9uKGZjdFN0YXRlLCBmY3ROYW1lKSB7XG4gICAgICAgICAgICB2YXIgZmFjZXQgPSB0aGlzW2ZjdE5hbWVdO1xuICAgICAgICAgICAgaWYgKGZhY2V0ICYmIHR5cGVvZiBmYWNldC5zZXRTdGF0ZSA9PSAnZnVuY3Rpb24nKVxuICAgICAgICAgICAgICAgIGZhY2V0LnNldFN0YXRlKGZjdFN0YXRlKTtcbiAgICAgICAgfSwgdGhpcyk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kLlxuICogUmV0dXJucyB0aGUgc2NvcGUgcGFyZW50IG9mIGEgY29tcG9uZW50LlxuICogSWYgYGNvbmRpdGlvbk9yRmFjZXRgIHBhcmFtZXRlciBpcyBub3Qgc3BlY2lmaWVkLCBhbiBpbW1lZGlhdGUgcGFyZW50IHdpbGwgYmUgcmV0dXJuZWQsIG90aGVyd2lzZSB0aGUgY2xvc2VzdCBhbmNlc3RvciB3aXRoIGEgc3BlY2lmaWVkIGZhY2V0IG9yIHBhc3NpbmcgY29uZGl0aW9uIHRlc3QuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbnxTdHJpbmd9IGNvbmRpdGlvbk9yRmFjZXQgb3B0aW9uYWwgY29uZGl0aW9uIHRoYXQgY29tcG9uZW50IHNob3VsZCBwYXNzIChvciBmYWNldCBuYW1lIGl0IHNob3VsZCBjb250YWluKVxuICogQHJldHVybiB7Q29tcG9uZW50fHVuZGVmaW5lZH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JGdldFNjb3BlUGFyZW50KGNvbmRpdGlvbk9yRmFjZXQpIHtcbiAgICByZXR1cm4gX2NhbGxHZXRTY29wZVBhcmVudC5jYWxsKHRoaXMsIF9nZXRTY29wZVBhcmVudCwgY29uZGl0aW9uT3JGYWNldCk7XG59XG5cbmZ1bmN0aW9uIF9jYWxsR2V0U2NvcGVQYXJlbnQoX2dldFNjb3BlUGFyZW50RnVuYywgY29uZGl0aW9uT3JGYWNldCkge1xuICAgIGNoZWNrKGNvbmRpdGlvbk9yRmFjZXQsIE1hdGNoLk9wdGlvbmFsKE1hdGNoLk9uZU9mKEZ1bmN0aW9uLCBTdHJpbmcpKSk7XG4gICAgdmFyIGNvbmRpdGlvbkZ1bmMgPSBjb21wb25lbnRVdGlscy5fbWFrZUNvbXBvbmVudENvbmRpdGlvbkZ1bmMoY29uZGl0aW9uT3JGYWNldCk7XG4gICAgcmV0dXJuIF9nZXRTY29wZVBhcmVudEZ1bmMuY2FsbCh0aGlzLCBjb25kaXRpb25GdW5jKTsgICBcbn1cblxuZnVuY3Rpb24gX2dldFNjb3BlUGFyZW50KGNvbmRpdGlvbkZ1bmMpIHtcbiAgICB2YXIgcGFyZW50O1xuICAgIHRyeSB7IHBhcmVudCA9IHRoaXMuc2NvcGUuX2hvc3RPYmplY3Qub3duZXI7IH0gY2F0Y2goZSkge31cblxuICAgIC8vIFdoZXJlIHRoZXJlIGlzIG5vIHBhcmVudCwgdGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiB1bmRlZmluZWRcbiAgICAvLyBUaGUgcGFyZW50IGNvbXBvbmVudCBpcyBjaGVja2VkIHJlY3Vyc2l2ZWx5XG4gICAgaWYgKHBhcmVudCkge1xuICAgICAgICBpZiAoISBjb25kaXRpb25GdW5jIHx8IGNvbmRpdGlvbkZ1bmMocGFyZW50KSApXG4gICAgICAgICAgICByZXR1cm4gcGFyZW50O1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICByZXR1cm4gX2dldFNjb3BlUGFyZW50LmNhbGwocGFyZW50LCBjb25kaXRpb25GdW5jKTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHNjb3BlIHBhcmVudCB3aXRoIGEgZ2l2ZW4gY2xhc3MsIHdpdGggc2FtZSBjbGFzcyBpZiBub3Qgc3BlY2lmaWVkXG4gKlxuICogQHBhcmFtIHtbRnVuY3Rpb25dfSBDb21wb25lbnRDbGFzcyBjb21wb25lbnQgY2xhc3MgdGhhdCB0aGUgcGFyZW50IHNob3VsZCBoYXZlLCBzYW1lIGNsYXNzIGJ5IGRlZmF1bHRcbiAqIEByZXR1cm4ge0NvbXBvbmVudH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JGdldFNjb3BlUGFyZW50V2l0aENsYXNzKENvbXBvbmVudENsYXNzKSB7XG4gICAgQ29tcG9uZW50Q2xhc3MgPSBDb21wb25lbnRDbGFzcyB8fCB0aGlzLmNvbnN0cnVjdG9yO1xuICAgIHJldHVybiBfZ2V0U2NvcGVQYXJlbnQuY2FsbCh0aGlzLCBmdW5jdGlvbihjb21wKSB7XG4gICAgICAgIHJldHVybiBjb21wIGluc3RhbmNlb2YgQ29tcG9uZW50Q2xhc3M7XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kLlxuICogUmV0dXJucyB0aGUgdG9wbW9zdCBzY29wZSBwYXJlbnQgb2YgYSBjb21wb25lbnQuXG4gKiBJZiBgY29uZGl0aW9uT3JGYWNldGAgcGFyYW1ldGVyIGlzIG5vdCBzcGVjaWZpZWQsIHRoZSB0b3Btb3N0IHNjb3BlIHBhcmVudCB3aWxsIGJlIHJldHVybmVkLCBvdGhlcndpc2UgdGhlIHRvcG1vc3QgYW5jZXN0b3Igd2l0aCBhIHNwZWNpZmllZCBmYWNldCBvciBwYXNzaW5nIGNvbmRpdGlvbiB0ZXN0LlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb258U3RyaW5nfSBjb25kaXRpb25PckZhY2V0IG9wdGlvbmFsIGNvbmRpdGlvbiB0aGF0IGNvbXBvbmVudCBzaG91bGQgcGFzcyAob3IgZmFjZXQgbmFtZSBpdCBzaG91bGQgY29udGFpbilcbiAqIEByZXR1cm4ge0NvbXBvbmVudHx1bmRlZmluZWR9XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRnZXRUb3BTY29wZVBhcmVudChjb25kaXRpb25PckZhY2V0KSB7XG4gICAgcmV0dXJuIF9jYWxsR2V0U2NvcGVQYXJlbnQuY2FsbCh0aGlzLCBfZ2V0VG9wU2NvcGVQYXJlbnQsIGNvbmRpdGlvbk9yRmFjZXQpO1xufVxuXG5mdW5jdGlvbiBfZ2V0VG9wU2NvcGVQYXJlbnQoY29uZGl0aW9uRnVuYykge1xuICAgIHZhciB0b3BQYXJlbnRcbiAgICAgICAgLCBwYXJlbnQgPSB0aGlzO1xuICAgIGRvIHtcbiAgICAgICAgcGFyZW50ID0gX2dldFNjb3BlUGFyZW50LmNhbGwocGFyZW50LCBjb25kaXRpb25GdW5jKTtcbiAgICAgICAgaWYgKHBhcmVudClcbiAgICAgICAgICAgIHRvcFBhcmVudCA9IHBhcmVudDtcbiAgICB9IHdoaWxlIChwYXJlbnQpO1xuXG4gICAgcmV0dXJuIHRvcFBhcmVudDtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgc2NvcGUgcGFyZW50IHdpdGggYSBnaXZlbiBjbGFzcywgd2l0aCBzYW1lIGNsYXNzIGlmIG5vdCBzcGVjaWZpZWRcbiAqXG4gKiBAcGFyYW0ge1tGdW5jdGlvbl19IENvbXBvbmVudENsYXNzIGNvbXBvbmVudCBjbGFzcyB0aGF0IHRoZSBwYXJlbnQgc2hvdWxkIGhhdmUsIHNhbWUgY2xhc3MgYnkgZGVmYXVsdFxuICogQHJldHVybiB7Q29tcG9uZW50fVxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkZ2V0VG9wU2NvcGVQYXJlbnRXaXRoQ2xhc3MoQ29tcG9uZW50Q2xhc3MpIHtcbiAgICBDb21wb25lbnRDbGFzcyA9IENvbXBvbmVudENsYXNzIHx8IHRoaXMuY29uc3RydWN0b3I7XG4gICAgcmV0dXJuIF9nZXRUb3BTY29wZVBhcmVudC5jYWxsKHRoaXMsIGZ1bmN0aW9uKGNvbXApIHtcbiAgICAgICAgcmV0dXJuIGNvbXAgaW5zdGFuY2VvZiBDb21wb25lbnRDbGFzcztcbiAgICB9KTtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIEZpbmRzIHNjb3BlIHBhcmVudCBvZiBjb21wb25lbnQgdXNpbmcgRE9NIHRyZWUgKHVubGlrZSBnZXRTY29wZVBhcmVudCB0aGF0IHNpbXBseSBnb2VzIHVwIHRoZSBzY29wZSB0cmVlKS5cbiAqIFdoaWxlIGdldFNjb3BlUGFyZW50IGlzIGZhc3RlciBpdCBtYXkgZmFpbCBpZiBzY29wZSBjaGFpbiBpcyBub3Qgc2V0dXAgeWV0IChlLmcuLCB3aGVuIGNvbXBvbmVudCBoYXMgYmVlbiBqdXN0IGluc2VydGVkKS5cbiAqIFRoZSBzY29wZSBwcm9wZXJ0eSBvZiBjb21wb25lbnQgd2lsbCBiZSBjaGFuZ2VkIHRvIHBvaW50IHRvIHNjb3BlIG9iamVjdCBvZiBjb250YWluZXIgZmFjZXQgb2YgdGhhdCBwYXJlbnQuXG4gKiBSZXR1cm5lZCBzY29wZSBwYXJlbnQgb2YgdGhlIGNvbXBvbmVudCB3aWxsIGJlIHVuZGVmaW5lZCAoYXMgd2VsbCBhcyBjb21wb25lbnQncyBzY29wZSBwcm9wZXJ0eSkgaWYgbm8gcGFyZW50IGluIHRoZSBET00gdHJlZSBoYXMgY29udGFpbmVyIGZhY2V0LlxuICogVE9ETyBNZXRob2Qgd2lsbCBub3QgYmluZCBET00gY2hpbGRyZW4gY29ycmVjdGx5IGlmIGNvbXBvbmVudCBoYXMgbm8gY29udGFpbmVyIGZhY2V0LlxuICpcbiAqIEByZXR1cm4ge0NvbXBvbmVudH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JHNldFNjb3BlUGFyZW50RnJvbURPTSgpIHtcbiAgICB2YXIgcGFyZW50RWwgPSB0aGlzLmVsLnBhcmVudE5vZGU7XG5cbiAgICB2YXIgcGFyZW50LCBmb3VuZFBhcmVudDtcbiAgICB3aGlsZSAocGFyZW50RWwgJiYgISBmb3VuZFBhcmVudCkge1xuICAgICAgICBwYXJlbnQgPSBDb21wb25lbnQuZ2V0Q29tcG9uZW50KHBhcmVudEVsKTtcbiAgICAgICAgZm91bmRQYXJlbnQgPSBwYXJlbnQgJiYgcGFyZW50LmNvbnRhaW5lcjtcbiAgICAgICAgcGFyZW50RWwgPSBwYXJlbnRFbC5wYXJlbnROb2RlO1xuICAgIH1cblxuICAgIHRoaXMucmVtb3ZlKCk7IC8vIHJlbW92ZSBjb21wb25lbnQgZnJvbSBpdHMgY3VycmVudCBzY29wZSAoaWYgaXQgaXMgZGVmaW5lZClcbiAgICBpZiAoZm91bmRQYXJlbnQpIHtcbiAgICAgICAgdGhpcy5yZW5hbWUodW5kZWZpbmVkLCBmYWxzZSk7XG4gICAgICAgIHBhcmVudC5jb250YWluZXIuc2NvcGUuX2FkZCh0aGlzKTtcbiAgICAgICAgcmV0dXJuIHBhcmVudDtcbiAgICB9ICAgICAgICBcbn1cblxuXG4vKipcbiAqIFdhbGtzIGNvbXBvbmVudCB0cmVlLCBjYWxsaW5nIHByb3ZpZGVkIGNhbGxiYWNrIG9uIGVhY2ggY29tcG9uZW50XG4gKlxuICogQHBhcmFtIGNhbGxiYWNrXG4gKiBAcGFyYW0gdGhpc0FyZ1xuICovXG5mdW5jdGlvbiBDb21wb25lbnQkd2Fsa1Njb3BlVHJlZShjYWxsYmFjaywgdGhpc0FyZykge1xuICAgIGNhbGxiYWNrLmNhbGwodGhpc0FyZywgdGhpcyk7XG4gICAgaWYgKCF0aGlzLmNvbnRhaW5lcikgcmV0dXJuO1xuICAgIHRoaXMuY29udGFpbmVyLnNjb3BlLl9lYWNoKGZ1bmN0aW9uKGNvbXBvbmVudCkge1xuICAgICAgICBjb21wb25lbnQud2Fsa1Njb3BlVHJlZShjYWxsYmFjaywgdGhpc0FyZyk7XG4gICAgfSk7XG59XG5cblxuZnVuY3Rpb24gQ29tcG9uZW50JHRyZWVQYXRoT2YoY29tcG9uZW50KSB7XG4gICAgcmV0dXJuIGRvbVV0aWxzLnRyZWVQYXRoT2YodGhpcy5lbCwgY29tcG9uZW50LmVsKTtcbn1cblxuXG5mdW5jdGlvbiBDb21wb25lbnQkZ2V0Q29tcG9uZW50QXRUcmVlUGF0aCh0cmVlUGF0aCwgbmVhcmVzdCkge1xuICAgIHZhciBub2RlID0gZG9tVXRpbHMuZ2V0Tm9kZUF0VHJlZVBhdGgodGhpcy5lbCwgdHJlZVBhdGgsIG5lYXJlc3QpO1xuICAgIHJldHVybiBDb21wb25lbnQuZ2V0Q29tcG9uZW50KG5vZGUpO1xufVxuXG5cbmZ1bmN0aW9uIENvbXBvbmVudCRpbnNlcnRBdFRyZWVQYXRoKHRyZWVQYXRoLCBjb21wb25lbnQsIG5lYXJlc3QpIHtcbiAgICB2YXIgd2FzSW5zZXJ0ZWQgPSBkb21VdGlscy5pbnNlcnRBdFRyZWVQYXRoKHRoaXMuZWwsIHRyZWVQYXRoLCBjb21wb25lbnQuZWwpO1xuICAgIGlmICh3YXNJbnNlcnRlZCkgY29tcG9uZW50LnNldFNjb3BlUGFyZW50RnJvbURPTSgpO1xuICAgIHJldHVybiB3YXNJbnNlcnRlZDtcbn1cblxuXG4vKipcbiAqIEJyb2FkY2FzdCBtZXNzYWdlIHRvIGNvbXBvbmVudCBhbmQgdG8gYWxsIGl0cyBzY29wZSBjaGlsZHJlblxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gbXNnIG1lc3NhZ2UgdG8gYmUgc2VudFxuICogQHBhcmFtIHtbQW55XX0gZGF0YSBvcHRpb25hbCBtZXNzYWdlIGRhdGFcbiAqIEBwYXJhbSB7W0Z1bmN0aW9uXX0gY2FsbGJhY2sgb3B0aW9uYWwgY2FsbGJhY2tcbiAqIEBwYXJhbSB7W0Jvb2xlYW5dfSBzeW5jaHJvbm91c2x5IGlmIGl0IHNob3VsZCB1c2UgcG9zdE1lc3NhZ2VTeW5jXG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRicm9hZGNhc3QobXNnLCBkYXRhLCBjYWxsYmFjaywgc3luY2hyb25vdXNseSkge1xuICAgIHZhciBwb3N0TWV0aG9kID0gc3luY2hyb25vdXNseSA/ICdwb3N0TWVzc2FnZVN5bmMnIDogJ3Bvc3RNZXNzYWdlJztcbiAgICB0aGlzLndhbGtTY29wZVRyZWUoZnVuY3Rpb24oY29tcG9uZW50KSB7XG4gICAgICAgIGNvbXBvbmVudFtwb3N0TWV0aG9kXShtc2csIGRhdGEsIGNhbGxiYWNrKTtcbiAgICB9KTtcbn1cblxuXG4vKipcbiAqIERlc3Ryb3kgY29tcG9uZW50OiByZW1vdmVzIGNvbXBvbmVudCBmcm9tIERPTSwgcmVtb3ZlcyBpdCBmcm9tIHNjb3BlLCBkZWxldGVzIGFsbCByZWZlcmVuY2VzIHRvIERPTSBub2RlcyBhbmQgdW5zdWJzY3JpYmVzIGZyb20gYWxsIG1lc3NhZ2VzIGJvdGggY29tcG9uZW50IGFuZCBhbGwgZmFjZXRzXG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRkZXN0cm95KHF1aWV0KSB7XG4gICAgaWYgKHRoaXMuX2Rlc3Ryb3llZCkge1xuICAgICAgICBpZiAoIXF1aWV0KSBsb2dnZXIud2FybignQ29tcG9uZW50IGRlc3Ryb3k6IGNvbXBvbmVudCBpcyBhbHJlYWR5IGRlc3Ryb3llZCcpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMucmVtb3ZlKGZhbHNlLCBxdWlldCk7XG4gICAgdGhpcy5hbGxGYWNldHMoJ2Rlc3Ryb3knKTtcbiAgICB0aGlzW01FU1NFTkdFUl9QUk9QRVJUWV0uZGVzdHJveSgpO1xuICAgIGlmICh0aGlzLmVsKSB7XG4gICAgICAgIGRvbVV0aWxzLmRldGFjaENvbXBvbmVudCh0aGlzLmVsKTtcbiAgICAgICAgZG9tVXRpbHMucmVtb3ZlRWxlbWVudCh0aGlzLmVsKTtcbiAgICAgICAgZGVsZXRlIHRoaXMuZWw7XG4gICAgfVxuICAgIHRoaXMuY29tcG9uZW50SW5mby5kZXN0cm95KCk7XG4gICAgdGhpcy5fZGVzdHJveWVkID0gdHJ1ZTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiBjb21wb25lbnQgd2FzIGRlc3Ryb3llZFxuICpcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRpc0Rlc3Ryb3llZCgpIHtcbiAgICByZXR1cm4gdGhpcy5fZGVzdHJveWVkO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIGBtaWxvLkNvbXBvbmVudC5GYWNldGBcbiAqXG4gKiBUaGUgY2xhc3MgZm90IHRoZSBmYWNldCBvZiBjb21wb25lbnQuIFdoZW4gYSBjb21wb25lbnQgaXMgY3JlYXRlZCwgaXRcbiAqIGNyZWF0ZXMgYWxsIGl0cyBmYWNldHMuXG4gKlxuICogU2VlIEZhY2V0cyBzZWN0aW9uIG9uIGluZm9ybWF0aW9uIGFib3V0IGF2YWlsYWJsZSBmYWNldHMgYW5kIG9uXG4gKiBob3cgdG8gY3JlYXRlIG5ldyBmYWNldHMgY2xhc3Nlcy5cbiAqXG4gKiAtIENvbXBvbmVudCAtIGJhc2ljIGNvbXBwb25lbnQgY2xhc3NcbiAqIC0gQ29tcG9uZW50RmFjZXQgLSBiYXNpY1xuICovXG5cbnZhciBGYWNldCA9IHJlcXVpcmUoJy4uL2Fic3RyYWN0L2ZhY2V0JylcbiAgICAsIE1lc3NlbmdlciA9IHJlcXVpcmUoJy4uL21lc3NlbmdlcicpXG4gICAgLCBGYWNldEVycm9yID0gcmVxdWlyZSgnLi4vdXRpbC9lcnJvcicpLkZhY2V0XG4gICAgLCBjb21wb25lbnRVdGlscyA9IHJlcXVpcmUoJy4vY191dGlscycpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cbnZhciBDb21wb25lbnRGYWNldCA9IF8uY3JlYXRlU3ViY2xhc3MoRmFjZXQsICdDb21wb25lbnRGYWNldCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENvbXBvbmVudEZhY2V0O1xuXG5cbi8qKlxuICogcG9zdERvbVBhcmVudFxuICpcbiAqIElmIGZhY2V0IGhhcyBET00gcGFyZW50IGZhY2V0IChzZWUgYGRvbVBhcmVudGAgbWV0aG9kKSwgcG9zdHMgdGhlIG1lc3NhZ2UgdG8gdGhpcyBmYWNldC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVR5cGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBtZXNzYWdlRGF0YVxuICovXG52YXIgcG9zdERvbVBhcmVudCA9IF8ucGFydGlhbChfcG9zdFBhcmVudCwgZG9tUGFyZW50KTtcblxuLyoqXG4gKiBwb3N0U2NvcGVQYXJlbnRcbiAqXG4gKiBJZiBmYWNldCBoYXMgc2NvcGUgcGFyZW50IGZhY2V0IChzZWUgYHNjb3BlUGFyZW50YCBtZXRob2QpLCBwb3N0cyB0aGUgbWVzc2FnZSB0byB0aGlzIGZhY2V0LlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlVHlwZVxuICogQHBhcmFtIHtPYmplY3R9IG1lc3NhZ2VEYXRhXG4gKi9cbnZhciBwb3N0U2NvcGVQYXJlbnQgPSBfLnBhcnRpYWwoX3Bvc3RQYXJlbnQsIHNjb3BlUGFyZW50KTtcblxuXG5fLmV4dGVuZFByb3RvKENvbXBvbmVudEZhY2V0LCB7XG4gICAgaW5pdDogQ29tcG9uZW50RmFjZXQkaW5pdCxcbiAgICBzdGFydDogQ29tcG9uZW50RmFjZXQkc3RhcnQsXG4gICAgY2hlY2s6IENvbXBvbmVudEZhY2V0JGNoZWNrLFxuICAgIGRlc3Ryb3k6IENvbXBvbmVudEZhY2V0JGRlc3Ryb3ksXG4gICAgb25Db25maWdNZXNzYWdlczogQ29tcG9uZW50RmFjZXQkb25Db25maWdNZXNzYWdlcyxcbiAgICBkb21QYXJlbnQ6IGRvbVBhcmVudCxcbiAgICBwb3N0RG9tUGFyZW50OiBwb3N0RG9tUGFyZW50LFxuICAgIHNjb3BlUGFyZW50OiBzY29wZVBhcmVudCxcbiAgICBwb3N0U2NvcGVQYXJlbnQ6IHBvc3RTY29wZVBhcmVudCxcbiAgICBnZXRNZXNzYWdlU291cmNlOiBnZXRNZXNzYWdlU291cmNlLFxuICAgIGRpc3BhdGNoU291cmNlTWVzc2FnZTogZGlzcGF0Y2hTb3VyY2VNZXNzYWdlLFxuICAgIF9jcmVhdGVNZXNzZW5nZXI6IF9jcmVhdGVNZXNzZW5nZXIsXG4gICAgX3NldE1lc3NhZ2VTb3VyY2U6IF9zZXRNZXNzYWdlU291cmNlLFxuICAgIF9jcmVhdGVNZXNzYWdlU291cmNlOiBfY3JlYXRlTWVzc2FnZVNvdXJjZSxcbiAgICBfY3JlYXRlTWVzc2FnZVNvdXJjZVdpdGhBUEk6IF9jcmVhdGVNZXNzYWdlU291cmNlV2l0aEFQSVxufSk7XG5cbl8uZXh0ZW5kKENvbXBvbmVudEZhY2V0LCB7XG4gICAgcmVxdWlyZXNGYWNldDogcmVxdWlyZXNGYWNldFxufSk7XG5cblxuLyoqXG4gKiBFeHBvc2UgTWVzc2VuZ2VyIG1ldGhvZHMgb24gRmFjZXQgcHJvdG90eXBlXG4gKi9cbnZhciBNRVNTRU5HRVJfUFJPUEVSVFkgPSAnX21lc3Nlbmdlcic7XG5NZXNzZW5nZXIudXNlV2l0aChDb21wb25lbnRGYWNldCwgTUVTU0VOR0VSX1BST1BFUlRZLCBNZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMpO1xuXG5cbi8vIGluaXRDb21wb25lbnRGYWNldFxuZnVuY3Rpb24gQ29tcG9uZW50RmFjZXQkaW5pdCgpIHtcbiAgICB0aGlzLl9jcmVhdGVNZXNzZW5nZXIoKTtcbn1cblxuXG4vLyBzb21lIHN1YmNsYXNzZXMgKGUuZy4gTW9kZWxGYWNldCkgb3ZlcnJyaWRlIHRoaXMgbWV0aG9kIGFuZCBkbyBub3QgY3JlYXRlIHRoZWlyIG93biBtZXNzZW5nZXJcbmZ1bmN0aW9uIF9jcmVhdGVNZXNzZW5nZXIoKXtcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsIE1FU1NFTkdFUl9QUk9QRVJUWSwgbmV3IE1lc3Nlbmdlcih0aGlzKSk7XG59XG5cblxuLy8gc3RhcnRDb21wb25lbnRGYWNldFxuZnVuY3Rpb24gQ29tcG9uZW50RmFjZXQkc3RhcnQoKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLm1lc3NhZ2VzKVxuICAgICAgICB0aGlzLm9uQ29uZmlnTWVzc2FnZXModGhpcy5jb25maWcubWVzc2FnZXMpO1xufVxuXG5cbmZ1bmN0aW9uIENvbXBvbmVudEZhY2V0JG9uQ29uZmlnTWVzc2FnZXMobWVzc2FnZVN1YnNjcmliZXJzKSB7XG4gICAgdmFyIG5vdFlldFJlZ2lzdGVyZWRNYXAgPSBfLm1hcEtleXMobWVzc2FnZVN1YnNjcmliZXJzLCBmdW5jdGlvbihzdWJzY3JpYmVyLCBtZXNzYWdlcykge1xuICAgICAgICB2YXIgc3Vic2NyaWJlclR5cGUgPSB0eXBlb2Ygc3Vic2NyaWJlcjtcbiAgICAgICAgaWYgKHN1YnNjcmliZXJUeXBlID09ICdmdW5jdGlvbicpXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5vbihtZXNzYWdlcywgc3Vic2NyaWJlcik7XG5cbiAgICAgICAgaWYgKHN1YnNjcmliZXJUeXBlID09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICB2YXIgY29udGV4dFR5cGUgPSB0eXBlb2Ygc3Vic2NyaWJlci5jb250ZXh0O1xuICAgICAgICAgICAgaWYgKGNvbnRleHRUeXBlID09ICdvYmplY3QnKVxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm9uKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKTtcblxuICAgICAgICAgICAgaWYgKGNvbnRleHRUeXBlID09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgaWYgKHN1YnNjcmliZXIuY29udGV4dCA9PSB0aGlzLm5hbWUgfHwgc3Vic2NyaWJlci5jb250ZXh0ID09ICdmYWNldCcpXG4gICAgICAgICAgICAgICAgICAgIHN1YnNjcmliZXIgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzdWJzY3JpYmVyOiBzdWJzY3JpYmVyLnN1YnNjcmliZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0OiB0aGlzXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoc3Vic2NyaWJlci5jb250ZXh0ID09ICdvd25lcicpXG4gICAgICAgICAgICAgICAgICAgIHN1YnNjcmliZXIgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzdWJzY3JpYmVyOiBzdWJzY3JpYmVyLnN1YnNjcmliZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0OiB0aGlzLm93bmVyXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRmFjZXRFcnJvcigndW5rbm93biBzdWJzY3JpYmVyIGNvbnRleHQgaW4gY29uZmlndXJhdGlvbjogJyArIHN1YnNjcmliZXIuY29udGV4dCk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5vbihtZXNzYWdlcywgc3Vic2NyaWJlcik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRocm93IG5ldyBGYWNldEVycm9yKCd1bmtub3duIHN1YnNjcmliZXIgY29udGV4dCB0eXBlIGluIGNvbmZpZ3VyYXRpb246ICcgKyBjb250ZXh0VHlwZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRmFjZXRFcnJvcigndW5rbm93biBzdWJzY3JpYmVyIHR5cGUgaW4gY29uZmlndXJhdGlvbjogJyArIHN1YnNjcmliZXJUeXBlKTtcbiAgICB9LCB0aGlzKTtcblxuICAgIHJldHVybiBub3RZZXRSZWdpc3RlcmVkTWFwO1xufVxuXG5cbi8vIGNoZWNrRGVwZW5kZW5jaWVzXG5mdW5jdGlvbiBDb21wb25lbnRGYWNldCRjaGVjaygpIHtcbiAgICBpZiAodGhpcy5yZXF1aXJlKSB7XG4gICAgICAgIHRoaXMucmVxdWlyZS5mb3JFYWNoKGZ1bmN0aW9uKHJlcUZhY2V0KSB7XG4gICAgICAgICAgICBpZiAoISB0aGlzLm93bmVyLmhhc0ZhY2V0KHJlcUZhY2V0KSlcbiAgICAgICAgICAgICAgICB0aGlzLm93bmVyLmFkZEZhY2V0KHJlcUZhY2V0KTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfVxufVxuXG5cbi8vIGRlc3Ryb3lzIGZhY2V0XG5mdW5jdGlvbiBDb21wb25lbnRGYWNldCRkZXN0cm95KCkge1xuICAgIGlmICh0aGlzW01FU1NFTkdFUl9QUk9QRVJUWV0pIHRoaXNbTUVTU0VOR0VSX1BST1BFUlRZXS5kZXN0cm95KCk7XG4gICAgdGhpcy5fZGVzdHJveWVkID0gdHJ1ZTtcbn1cblxuXG4vKipcbiAqIGRvbVBhcmVudFxuICpcbiAqIEByZXR1cm4ge0NvbXBvbmVudEZhY2V0fSByZWZlcmVuY2UgdG8gdGhlIGZhY2V0IG9mIHRoZSBzYW1lIGNsYXNzIG9mIHRoZSBjbG9zZXN0IHBhcmVudCBET00gZWxlbWVudCwgdGhhdCBoYXMgYSBjb21wb25lbnQgd2l0aCB0aGUgc2FtZSBmYWNldCBjbGFzcyBhdHRhY2hlZCB0byBpdC4gSWYgc3VjaCBlbGVtZW50IGRvZXNuJ3QgZXhpc3QgbWV0aG9kIHdpbGwgcmV0dXJuIHVuZGVmaW5lZC5cbiAqL1xuZnVuY3Rpb24gZG9tUGFyZW50KCkge1xuICAgIHZhciBwYXJlbnRDb21wb25lbnQgPSBjb21wb25lbnRVdGlscy5nZXRDb250YWluaW5nQ29tcG9uZW50KHRoaXMub3duZXIuZWwsIGZhbHNlLCB0aGlzLm5hbWUpO1xuICAgIHJldHVybiBwYXJlbnRDb21wb25lbnQgJiYgcGFyZW50Q29tcG9uZW50W3RoaXMubmFtZV07XG59XG5cblxuLyoqXG4gKiBzY29wZVBhcmVudFxuICpcbiAqIEByZXR1cm4ge0NvbXBvbmVudEZhY2V0fSByZWZlcmVuY2UgdG8gdGhlIGZhY2V0IG9mIHRoZSBzYW1lIGNsYXNzIGFzIGB0aGlzYCBmYWNldCBvZiB0aGUgY2xvc2VzdCBzY29wZSBwYXJlbnQgKGkuZS4sIHRoZSBjb21wb25lbnQgdGhhdCBoYXMgdGhlIHNjb3BlIG9mIHRoZSBjdXJyZW50IGNvbXBvbmVudCBpbiBpdHMgY29udGFpbmVyIGZhY2V0KS5cbiAqL1xuZnVuY3Rpb24gc2NvcGVQYXJlbnQoKSB7XG4gICAgdmFyIHBhcmVudENvbXBvbmVudCA9IHRoaXMub3duZXIuZ2V0U2NvcGVQYXJlbnQodGhpcy5uYW1lKTtcbiAgICByZXR1cm4gcGFyZW50Q29tcG9uZW50ICYmIHBhcmVudENvbXBvbmVudFt0aGlzLm5hbWVdO1xufVxuXG5cbmZ1bmN0aW9uIF9wb3N0UGFyZW50KGdldFBhcmVudE1ldGhvZCwgbWVzc2FnZVR5cGUsIG1lc3NhZ2VEYXRhKSB7XG4gICAgdmFyIHBhcmVudEZhY2V0ID0gZ2V0UGFyZW50TWV0aG9kLmNhbGwodGhpcyk7XG4gICAgaWYgKHBhcmVudEZhY2V0KVxuICAgICAgICBwYXJlbnRGYWNldC5wb3N0TWVzc2FnZShtZXNzYWdlVHlwZSwgbWVzc2FnZURhdGEpO1xufVxuXG5cbmZ1bmN0aW9uIF9zZXRNZXNzYWdlU291cmNlKG1lc3NhZ2VTb3VyY2UpIHtcbiAgICB0aGlzW01FU1NFTkdFUl9QUk9QRVJUWV0uX3NldE1lc3NhZ2VTb3VyY2UobWVzc2FnZVNvdXJjZSk7XG59XG5cblxuZnVuY3Rpb24gZ2V0TWVzc2FnZVNvdXJjZSgpIHtcbiAgICByZXR1cm4gdGhpc1tNRVNTRU5HRVJfUFJPUEVSVFldLmdldE1lc3NhZ2VTb3VyY2UoKTtcbn1cblxuXG5mdW5jdGlvbiBkaXNwYXRjaFNvdXJjZU1lc3NhZ2UobWVzc2FnZSwgZGF0YSkge1xuICAgIHJldHVybiB0aGlzLmdldE1lc3NhZ2VTb3VyY2UoKS5kaXNwYXRjaE1lc3NhZ2UobWVzc2FnZSwgZGF0YSk7XG59XG5cblxuZnVuY3Rpb24gX2NyZWF0ZU1lc3NhZ2VTb3VyY2UoTWVzc2FnZVNvdXJjZUNsYXNzLCBvcHRpb25zKSB7XG4gICAgdmFyIG1lc3NhZ2VTb3VyY2UgPSBuZXcgTWVzc2FnZVNvdXJjZUNsYXNzKHRoaXMsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB0aGlzLm93bmVyLCBvcHRpb25zKTtcbiAgICB0aGlzLl9zZXRNZXNzYWdlU291cmNlKG1lc3NhZ2VTb3VyY2UpXG5cbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdfbWVzc2FnZVNvdXJjZScsIG1lc3NhZ2VTb3VyY2UpO1xufVxuXG5cbmZ1bmN0aW9uIF9jcmVhdGVNZXNzYWdlU291cmNlV2l0aEFQSShNZXNzYWdlU291cmNlQ2xhc3MsIG1lc3NlbmdlckFQSU9yQ2xhc3MsIG9wdGlvbnMpIHtcbiAgICB2YXIgbWVzc2FnZVNvdXJjZSA9IG5ldyBNZXNzYWdlU291cmNlQ2xhc3ModGhpcywgdW5kZWZpbmVkLCBtZXNzZW5nZXJBUElPckNsYXNzLCB0aGlzLm93bmVyLCBvcHRpb25zKTtcbiAgICB0aGlzLl9zZXRNZXNzYWdlU291cmNlKG1lc3NhZ2VTb3VyY2UpXG5cbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdfbWVzc2FnZVNvdXJjZScsIG1lc3NhZ2VTb3VyY2UpO1xufVxuXG5cbmZ1bmN0aW9uIHJlcXVpcmVzRmFjZXQoZmFjZXROYW1lKSB7XG4gICAgLy8gJ3RoaXMnIHJlZmVycyB0byB0aGUgRmFjZXQgQ2xhc3NcbiAgICB2YXIgZmFjZXRSZXF1aXJlID0gdGhpcy5wcm90b3R5cGUucmVxdWlyZTtcblxuICAgIHJldHVybiBmYWNldFJlcXVpcmUgJiYgKGZhY2V0UmVxdWlyZS5pbmRleE9mKF8uZmlyc3RVcHBlckNhc2UoZmFjZXROYW1lKSkgPj0gMFxuICAgICAgICAgICAgICAgICAgICAgICAgfHwgZmFjZXRSZXF1aXJlLmluZGV4T2YoXy5maXJzdExvd2VyQ2FzZShmYWNldE5hbWUpKSA+PSAwKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgQ29tcG9uZW50RmFjZXQgPSByZXF1aXJlKCcuLi9jX2ZhY2V0JylcbiAgICAsIG1pbG9CaW5kZXIgPSByZXF1aXJlKCcuLi8uLi9iaW5kZXInKVxuICAgICwgU2NvcGUgPSByZXF1aXJlKCcuLi9zY29wZScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jZl9yZWdpc3RyeScpXG4gICAgLCBkb21VdGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvZG9tJylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvbG9nZ2VyJyk7XG5cblxuLyoqXG4gKiBgbWlsby5yZWdpc3RyeS5mYWNldHMuZ2V0KCdDb250YWluZXInKWBcbiAqIEEgc3BlY2lhbCBjb21wb25lbnQgZmFjZXQgdGhhdCBtYWtlcyBjb21wb25lbnQgY3JlYXRlIGl0cyBvd24gaW5uZXIgc2NvcGUuXG4gKiBXaGVuIFttaWxvLmJpbmRlcl0oLi4vLi4vYmluZGVyLmpzLmh0bWwpIGJpbmRzIERPTSB0cmVlIGFuZCBjcmVhdGVzIGNvbXBvbmVudHMsIGlmIGNvbXBvbmVudHMgYXJlIGluc2lkZSBjb21wb25lbnQgV0lUSCBDb250YWluZXIgZmFjZXQsIHRoZXkgYXJlIHB1dCBvbiB0aGUgYHNjb3BlYCBvZiBpdCAoY29tcG9uZW50LmNvbnRhaW5lci5zY29wZSAtIHNlZSBbU2NvcGVdKC4uL3Njb3BlLmpzLmh0bWwpKSwgb3RoZXJ3aXNlIHRoZXkgYXJlIHB1dCBvbiB0aGUgc2FtZSBzY29wZSBldmVuIHRob3VnaCB0aGV5IG1heSBiZSBkZWVwZXIgaW4gRE9NIHRyZWUuXG4gKiBJdCBhbGxvd3MgY3JlYXRpbmcgbmFtZXNwYWNlcyBhdm9pZGluZyBjb21wb25lbnRzIG5hbWVzIGNvbmZsaWN0cywgYXQgdGhlIHNhbWUgdGltZSBjcmVhdGluZyBtb3JlIHNoYWxsb3cgY29tcG9uZW50cyB0cmVlIHRoYW4gdGhlIERPTSB0cmVlLlxuICogVG8gY3JlYXRlIGNvbXBvbmVudHMgZm9yIGVsZW1lbnRzIGluc2lkZSB0aGUgY3VycmVudCBjb21wb25lbnQgdXNlOlxuICogYGBgXG4gKiBjb21wb25lbnQuY29udGFpbmVyLmJpbmRlcigpO1xuICogYGBgXG4gKiBTZWUgW21pbG8uYmluZGVyXSguLi8uLi9iaW5kZXIuanMuaHRtbClcbiAqL1xudmFyIENvbnRhaW5lciA9IF8uY3JlYXRlU3ViY2xhc3MoQ29tcG9uZW50RmFjZXQsICdDb250YWluZXInKTtcblxuXG4vKipcbiAqICMjIyNDb250YWluZXIgZmFjZXQgaW5zdGFuY2UgbWV0aG9kcyMjIyNcbiAqXG4gKiAtIFtiaW5kZXJdKCNDb250YWluZXIkYmluZGVyKSAtIGNyZWF0ZSBjb21wb25lbnRzIGZyb20gRE9NIGluc2lkZSB0aGUgY3VycmVudCBvbmVcbiAqL1xuXy5leHRlbmRQcm90byhDb250YWluZXIsIHtcbiAgICBzdGFydDogQ29udGFpbmVyJHN0YXJ0LFxuICAgIHBhdGg6IENvbnRhaW5lciRwYXRoLFxuICAgIGdldFN0YXRlOiBDb250YWluZXIkZ2V0U3RhdGUsXG4gICAgc2V0U3RhdGU6IENvbnRhaW5lciRzZXRTdGF0ZSxcbiAgICBiaW5kZXI6IENvbnRhaW5lciRiaW5kZXIsXG4gICAgZGVzdHJveTogQ29udGFpbmVyJGRlc3Ryb3ksXG4gICAgdW53cmFwOiBDb250YWluZXIkdW53cmFwLFxuXG4gICAgYXBwZW5kOiBDb250YWluZXIkYXBwZW5kLFxuICAgIGluc2VydEJlZm9yZTogQ29udGFpbmVyJGluc2VydEJlZm9yZSxcbiAgICByZW1vdmU6IENvbnRhaW5lciRyZW1vdmVcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoQ29udGFpbmVyKTtcblxubW9kdWxlLmV4cG9ydHMgPSBDb250YWluZXI7XG5cblxuLyoqXG4gKiBDb250YWluZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogU2NhbnMgRE9NLCBjcmVhdGVzIGNvbXBvbmVudHMgYW5kIGFkZHMgdG8gc2NvcGUgY2hpbGRyZW4gb2YgY29tcG9uZW50IGVsZW1lbnQuXG4gKi9cbmZ1bmN0aW9uIENvbnRhaW5lciRiaW5kZXIoKSB7XG4gICAgcmV0dXJuIG1pbG9CaW5kZXIodGhpcy5vd25lci5lbCwgdGhpcy5zY29wZSwgZmFsc2UpO1xufVxuXG5cbi8qKlxuICogQ29udGFpbmVyIGluc3RhbmNlIG1ldGhvZC5cbiAqIFNldHVwIGVtcHR5IHNjb3BlIG9iamVjdCBvbiBzdGFydFxuICovXG5mdW5jdGlvbiBDb250YWluZXIkc3RhcnQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLnN0YXJ0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgdGhpcy5zY29wZSA9IG5ldyBTY29wZSh0aGlzLm93bmVyLmVsLCB0aGlzKTtcbn1cblxuXG52YXIgYWxsb3dlZE5hbWVQYXR0ZXJuID0gL15bQS1aYS16XVtBLVphLXowLTlcXF9cXCRdKiQvO1xuLyoqXG4gKiBDb250YWluZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogU2FmZWx5IHRyYXZlcnNlcyBjb21wb25lbnQgc2NvcGVcbiAqIFJldHVybnMgY29tcG9uZW50IGluIHNjb3BlIGZvciBhIGdpdmVuIHBhdGhcbiAqIElmIHBhdGggaXMgaW52YWxpZCB0aGUgbWV0aG9kIHdpbGwgdGhyb3csIGlmIHRoZXJlIGlzIG5vIGNvbXBvbmVudCBhdCBhIGdpdmVuIHBhdGggb3Igc29tZSBvZiB0aGUgY29tcG9uZW50cyBhbG9uZyB0aGUgcGF0aCBkb2VzIG5vdCBoYXZlIENvbnRhaW5lciBmYWNldCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIHVuZGVmaW5lZCwgXG4gKiBcbiAqIEBwYXJhbSB7U3RyaW5nfSBwYXRoIHBhdGggb2YgY2hpbGQgY29tcG9uZW50IGluIHNjb3BlLCBlYWNoIG5hbWUgc2hvdWxkIGJlIHByZWZpeGVkIHdpdGggJy4nLCBlLmcuOiAnLmNoaWxkLnN1YmNoaWxkJ1xuICogQHJldHVybiB7Q29tcG9uZW50fVxuICovXG5mdW5jdGlvbiBDb250YWluZXIkcGF0aChwYXRoKSB7XG4gICAgcGF0aCA9IHBhdGguc3BsaXQoJy4nKTtcbiAgICB2YXIgbGVuID0gcGF0aC5sZW5ndGg7XG4gICAgaWYgKHBhdGhbMF0gfHwgbGVuIDwgMikgdGhyb3dJbnZhbGlkUGF0aCgpO1xuICAgIHZhciBjb21wID0gdGhpcy5vd25lcjtcbiAgICBmb3IgKHZhciBpID0gMTsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIHZhciBuYW1lID0gcGF0aFtpXTtcbiAgICAgICAgaWYgKCFhbGxvd2VkTmFtZVBhdHRlcm4udGVzdChuYW1lKSkgdGhyb3dJbnZhbGlkUGF0aCgpO1xuICAgICAgICBpZiAoIWNvbXAuY29udGFpbmVyKSByZXR1cm47XG4gICAgICAgIGNvbXAgPSBjb21wLmNvbnRhaW5lci5zY29wZVtuYW1lXTtcbiAgICAgICAgaWYgKCFjb21wKSByZXR1cm47XG4gICAgfVxuICAgIHJldHVybiBjb21wO1xuXG4gICAgZnVuY3Rpb24gdGhyb3dJbnZhbGlkUGF0aCgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdwYXRoICcgKyBwYXRoICsgJyBpcyBpbnZhbGlkJyk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogQ29udGFpbmVyIGluc3RhbmNlIG1ldGhvZFxuICogQ2FsbGVkIGJ5IGBDb21wb25lbnQucHJvdG90eXBlLmdldFN0YXRlYCB0byBnZXQgZmFjZXQncyBzdGF0ZVxuICogUmV0dXJucyB0aGUgc3RhdGUgb2YgY29tcG9uZW50cyBpbiB0aGUgc2NvcGVcbiAqXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGRlZXBDb3B5IHRydWUgYnkgZGVmYXVsdFxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBDb250YWluZXIkZ2V0U3RhdGUoZGVlcENvcHkpIHtcbiAgICB2YXIgc3RhdGUgPSB7IHNjb3BlOiB7fSB9O1xuICAgIGlmIChkZWVwQ29weSAhPT0gZmFsc2UpXG4gICAgICAgIHRoaXMuc2NvcGUuX2VhY2goZnVuY3Rpb24oY29tcG9uZW50LCBjb21wTmFtZSkge1xuICAgICAgICAgICAgc3RhdGUuc2NvcGVbY29tcE5hbWVdID0gY29tcG9uZW50Ll9nZXRTdGF0ZSgpO1xuICAgICAgICB9KTtcbiAgICByZXR1cm4gc3RhdGU7XG59XG5cblxuLyoqXG4gKiBDb250YWluZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBDYWxsZWQgYnkgYENvbXBvbmVudC5wcm90b3R5cGUuc2V0U3RhdGVgIHRvIHNldCBmYWNldCdzIHN0YXRlXG4gKiBTZXRzIHRoZSBzdGF0ZSBvZiBjb21wb25lbnRzIGluIHRoZSBzY29wZVxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIGRhdGEgdG8gc2V0IG9uIGZhY2V0J3MgbW9kZWxcbiAqL1xuZnVuY3Rpb24gQ29udGFpbmVyJHNldFN0YXRlKHN0YXRlKSB7XG4gICAgXy5lYWNoS2V5KHN0YXRlLnNjb3BlLCBmdW5jdGlvbihjb21wRGF0YSwgY29tcE5hbWUpIHtcbiAgICAgICAgdmFyIGNvbXBvbmVudCA9IHRoaXMuc2NvcGVbY29tcE5hbWVdO1xuICAgICAgICBpZiAoY29tcG9uZW50KVxuICAgICAgICAgICAgY29tcG9uZW50LnNldFN0YXRlKGNvbXBEYXRhKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ2NvbXBvbmVudCBcIicgKyBjb21wTmFtZSArICdcIiBkb2VzIG5vdCBleGlzdCBvbiBzY29wZScpO1xuICAgIH0sIHRoaXMpO1xufVxuXG5mdW5jdGlvbiBDb250YWluZXIkZGVzdHJveSgpIHtcbiAgICB0aGlzLnNjb3BlLl9lYWNoKGZ1bmN0aW9uKGNvbXBvbmVudCkge1xuICAgICAgICBjb21wb25lbnQuZGVzdHJveSgpO1xuICAgIH0pO1xuICAgIHRoaXMuc2NvcGUuX2RldGFjaEVsZW1lbnQoKTtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuZGVzdHJveS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbi8qKlxuICogQ29udGFpbmVyIGluc3RhbmNlIG1ldGhvZFxuICogTW92ZXMgYWxsIG9mIHRoZSBjb250ZW50cyBvZiB0aGUgb3duZXIgaW50byB0aGUgcGFyZW50IHNjb3BlXG4gKiBcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gcmVuYW1lQ2hpbGRyZW4gcGFzcyBmYWxzZSB0byBub3QgcmVuYW1lIHNjb3BlIGNoaWxkcmVuIChkZWZhdWx0IGlzIHRydWUpXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGRlc3Ryb3kgSWYgbm90IGZhbHNlLCB0aGUgY29tcG9uZW50IHdpbGwgYmUgZGVzdHJveWVkIGF0IHRoZSBlbmQgKGRlZmF1bHQgaXMgdHJ1ZSkuXG4gKi9cbmZ1bmN0aW9uIENvbnRhaW5lciR1bndyYXAocmVuYW1lQ2hpbGRyZW4sIGRlc3Ryb3kpIHtcbiAgICBkb21VdGlscy51bndyYXBFbGVtZW50KHRoaXMub3duZXIuZWwpO1xuICAgIHRoaXMuc2NvcGUgJiYgdGhpcy5zY29wZS5fZWFjaChmdW5jdGlvbiAoY2hpbGQpIHtcbiAgICAgICAgY2hpbGQucmVtb3ZlKCk7XG4gICAgICAgIGlmIChyZW5hbWVDaGlsZHJlbiAhPT0gZmFsc2UpIGNoaWxkLnJlbmFtZSh1bmRlZmluZWQsIGZhbHNlKTtcbiAgICAgICAgdGhpcy5vd25lci5zY29wZSAmJiB0aGlzLm93bmVyLnNjb3BlLl9hZGQoY2hpbGQpO1xuICAgIH0sIHRoaXMpO1xuICAgIGlmIChkZXN0cm95ICE9PSBmYWxzZSkgdGhpcy5vd25lci5kZXN0cm95KCk7XG59XG5cblxuLyoqXG4gKiBDb250YWluZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBBcHBlbmQgY29tcG9uZW50IHRvIERPTSBhbmQgdG8gc2NvcGVcbiAqIEBwYXJhbSB7Q29tcG9uZW50fSBjb21wIGNvbXBvbmVudCB0aGF0IHdpbGwgYmUgYXBwZW5kZWRcbiAqL1xuZnVuY3Rpb24gQ29udGFpbmVyJGFwcGVuZChjb21wKSB7XG4gICAgdGhpcy5zY29wZS5fYWRkKGNvbXApO1xuICAgIHRoaXMub3duZXIuZWwuYXBwZW5kQ2hpbGQoY29tcC5lbCk7XG59XG5cblxuLyoqXG4gKiBDb250YWluZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbnNlcnQgY29tcG9uZW50IHRvIERPTSBhbmQgdG8gc2NvcGUgYmVmb3JlIGFub3RoZXIgY29tcG9uZW50XG4gKiBAcGFyYW0ge0NvbXBvbmVudH0gY29tcCBjb21wb25lbnQgdGhhdCB3aWxsIGJlIGluc2VydGVkXG4gKiBAcGFyYW0ge0NvbXBvbmVudH0gc2libGluZyBjb21wb25lbnQgYmVmb3JlIHdoaWNoIGNvbXBvbmVudCB3aWxsIGJlIGFwcGVuZGVkXG4gKi9cbmZ1bmN0aW9uIENvbnRhaW5lciRpbnNlcnRCZWZvcmUoY29tcCwgc2libGluZykge1xuICAgIHRoaXMuc2NvcGUuX2FkZChjb21wKTtcbiAgICB0aGlzLmVsLmluc2VydEJlZm9yZShjb21wLmVsLCBzaWJsaW5nICYmIHNpYmxpbmcuZWwpO1xufVxuXG5mdW5jdGlvbiBDb250YWluZXIkcmVtb3ZlKGNvbXApIHtcbiAgICB0aGlzLnNjb3BlLl9yZW1vdmUoY29tcCk7XG4gICAgdGhpcy5vd25lci5lbC5yZW1vdmVDaGlsZChjb21wLmVsKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIE1peGluID0gcmVxdWlyZSgnLi4vLi4vYWJzdHJhY3QvbWl4aW4nKVxuICAgICwgQ29tcG9uZW50RmFjZXQgPSByZXF1aXJlKCcuLi9jX2ZhY2V0JylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jZl9yZWdpc3RyeScpXG5cbiAgICAsIE1lc3NlbmdlciA9IHJlcXVpcmUoJy4uLy4uL21lc3NlbmdlcicpXG4gICAgLCBET01FdmVudHNTb3VyY2UgPSByZXF1aXJlKCcuLi9tc2dfc3JjL2RvbV9ldmVudHMnKVxuICAgICwgRGF0YU1zZ0FQSSA9IHJlcXVpcmUoJy4uL21zZ19hcGkvZGF0YScpXG4gICAgLCBnZXRFbGVtZW50RGF0YUFjY2VzcyA9IHJlcXVpcmUoJy4uL21zZ19hcGkvZGVfZGF0YScpXG4gICAgLCBwYXRoVXRpbHMgPSByZXF1aXJlKCcuLi8uLi9tb2RlbC9wYXRoX3V0aWxzJylcbiAgICAsIE1vZGVsUGF0aCA9IHJlcXVpcmUoJy4uLy4uL21vZGVsL21fcGF0aCcpXG4gICAgLCBtb2RlbFV0aWxzID0gcmVxdWlyZSgnLi4vLi4vbW9kZWwvbW9kZWxfdXRpbHMnKVxuICAgICwgY2hhbmdlRGF0YUhhbmRsZXIgPSByZXF1aXJlKCcuLi8uLi9tb2RlbC9jaGFuZ2VfZGF0YScpXG4gICAgLCBnZXRUcmFuc2FjdGlvbkZsYWcgPSBjaGFuZ2VEYXRhSGFuZGxlci5nZXRUcmFuc2FjdGlvbkZsYWdcbiAgICAsIHNldFRyYW5zYWN0aW9uRmxhZyA9IGNoYW5nZURhdGFIYW5kbGVyLnNldFRyYW5zYWN0aW9uRmxhZ1xuICAgICwgcG9zdFRyYW5zYWN0aW9uRmluaXNoZWQgPSBjaGFuZ2VEYXRhSGFuZGxlci5wb3N0VHJhbnNhY3Rpb25GaW5pc2hlZFxuXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvbG9nZ2VyJyk7XG5cblxuLyoqXG4gKiBgbWlsby5yZWdpc3RyeS5mYWNldHMuZ2V0KCdEYXRhJylgXG4gKiBGYWNldCB0byBnaXZlIGFjY2VzcyB0byBET00gZGF0YVxuICovXG52YXIgRGF0YSA9IF8uY3JlYXRlU3ViY2xhc3MoQ29tcG9uZW50RmFjZXQsICdEYXRhJyk7XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZHNcbiAqXG4gKiAtIFtzdGFydF0oI0RhdGEkc3RhcnQpIC0gc3RhcnQgRGF0YSBmYWNldFxuICogLSBbZ2V0XSgjRGF0YSRnZXQpIC0gZ2V0IERPTSBkYXRhIGZyb20gRE9NIHRyZWVcbiAqIC0gW3NldF0oI0RhdGEkc2V0KSAtIHNldCBET00gZGF0YSB0byBET00gdHJlZVxuICogLSBbcGF0aF0oI0RhdGEkcGF0aCkgLSBnZXQgcmVmZXJlbmNlIHRvIERhdGEgZmFjZXQgYnkgcGF0aFxuICovXG5fLmV4dGVuZFByb3RvKERhdGEsIHtcbiAgICBzdGFydDogRGF0YSRzdGFydCxcbiAgICBnZXRTdGF0ZTogRGF0YSRnZXRTdGF0ZSxcbiAgICBzZXRTdGF0ZTogRGF0YSRzZXRTdGF0ZSxcblxuICAgIGdldDogRGF0YSRnZXQsXG4gICAgc2V0OiBEYXRhJHNldCxcbiAgICBkZWw6IERhdGEkZGVsLFxuICAgIHNwbGljZTogRGF0YSRzcGxpY2UsXG4gICAgbGVuOiBEYXRhJGxlbixcbiAgICBwYXRoOiBEYXRhJHBhdGgsXG4gICAgZ2V0UGF0aDogRGF0YSRnZXRQYXRoLFxuICAgIGdldEtleTogRGF0YSRnZXRLZXksXG5cbiAgICBfZ2V0OiBEYXRhJF9nZXQsXG4gICAgX3NldDogRGF0YSRfc2V0LFxuICAgIF9kZWw6IERhdGEkX2RlbCxcbiAgICBfc3BsaWNlOiBEYXRhJF9zcGxpY2UsXG4gICAgX2xlbjogRGF0YSRfbGVuLFxuXG4gICAgX3NldFNjYWxhclZhbHVlOiBEYXRhJF9zZXRTY2FsYXJWYWx1ZSxcbiAgICBfZ2V0U2NhbGFyVmFsdWU6IERhdGEkX2dldFNjYWxhclZhbHVlLFxuICAgIF9idWJibGVVcERhdGFDaGFuZ2U6IERhdGEkX2J1YmJsZVVwRGF0YUNoYW5nZSxcbiAgICBfcXVldWVEYXRhQ2hhbmdlOiBEYXRhJF9xdWV1ZURhdGFDaGFuZ2UsXG4gICAgX3Bvc3REYXRhQ2hhbmdlczogRGF0YSRfcG9zdERhdGFDaGFuZ2VzLFxuICAgIF9wcmVwYXJlTWVzc2FnZVNvdXJjZTogX3ByZXBhcmVNZXNzYWdlU291cmNlXG59KTtcblxuZmFjZXRzUmVnaXN0cnkuYWRkKERhdGEpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IERhdGE7XG5cblxuLyoqXG4gKiBNb2RlbFBhdGggbWV0aG9kcyBhZGRlZCB0byBEYXRhIHByb3RvdHlwZVxuICovXG5bJ3B1c2gnLCAncG9wJywgJ3Vuc2hpZnQnLCAnc2hpZnQnXS5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICB2YXIgbWV0aG9kID0gTW9kZWxQYXRoLnByb3RvdHlwZVttZXRob2ROYW1lXTtcbiAgICBfLmRlZmluZVByb3BlcnR5KERhdGEucHJvdG90eXBlLCBtZXRob2ROYW1lLCBtZXRob2QpO1xufSk7XG5cblxuXG4vLyB0aGVzZSBtZXRob2RzIHdpbGwgYmUgd3JhcHBlZCB0byBzdXBwb3J0IFwiKlwiIHBhdHRlcm4gc3Vic2NyaXB0aW9uc1xudmFyIHByb3h5RGF0YVNvdXJjZU1ldGhvZHMgPSB7XG4gICAgICAgIC8vIHZhbHVlOiAndmFsdWUnLFxuICAgICAgICB0cmlnZ2VyOiAndHJpZ2dlcidcbiAgICB9O1xuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFN0YXJ0cyBEYXRhIGZhY2V0XG4gKiBDYWxsZWQgYnkgY29tcG9uZW50IGFmdGVyIGNvbXBvbmVudCBpcyBpbml0aWFsaXplZC5cbiAqL1xuZnVuY3Rpb24gRGF0YSRzdGFydCgpIHtcbiAgICAvLyBjaGFuZ2UgbWVzc2VuZ2VyIG1ldGhvZHMgdG8gd29yayB3aXRoIFwiKlwiIHN1YnNjcmlwdGlvbnMgKGxpa2UgTW9kZWwgY2xhc3MpXG4gICAgcGF0aFV0aWxzLndyYXBNZXNzZW5nZXJNZXRob2RzLmNhbGwodGhpcyk7XG5cbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuc3RhcnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIC8vIGdldC9zZXQgbWV0aG9kcyB0byBzZXQgZGF0YSBvZiBlbGVtZW50XG4gICAgdGhpcy5lbERhdGEgPSBnZXRFbGVtZW50RGF0YUFjY2Vzcyh0aGlzLm93bmVyLmVsKTtcblxuICAgIHRoaXMuX2RhdGFDaGFuZ2VzUXVldWUgPSBbXTtcblxuICAgIHRoaXMuX3ByZXBhcmVNZXNzYWdlU291cmNlKCk7XG5cbiAgICAvLyBzdG9yZSBmYWNldCBkYXRhIHBhdGhcbiAgICB0aGlzLl9wYXRoID0gJy4nICsgdGhpcy5vd25lci5uYW1lO1xuXG4gICAgLy8gY3VycmVudCB2YWx1ZVxuICAgIHRoaXMuX3ZhbHVlID0gdGhpcy5nZXQoKTtcblxuICAgIC8vIHByZXBhcmUgaW50ZXJuYWwgYW5kIGV4dGVybmFsIG1lc3NlbmdlcnNcbiAgICAvLyB0aGlzLl9wcmVwYXJlTWVzc2VuZ2VycygpO1xuXG4gICAgLy8gc3Vic2NyaWJlIHRvIERPTSBldmVudCBhbmQgYWNjZXNzb3JzJyBtZXNzYWdlc1xuICAgIHRoaXMub25TeW5jKCcnLCBvbk93bkRhdGFDaGFuZ2UpO1xuXG4gICAgLy8gbWVzc2FnZSB0byBtYXJrIHRoZSBlbmQgb2YgYmF0Y2ggb24gdGhlIGN1cnJlbnQgbGV2ZWxcbiAgICB0aGlzLm9uU3luYygnZGF0YWNoYW5nZXNmaW5pc2hlZCcsIG9uRGF0YUNoYW5nZXNGaW5pc2hlZCk7XG5cbiAgICAvLyBjaGFuZ2VzIGluIHNjb3BlIGNoaWxkcmVuIHdpdGggRGF0YSBmYWNldFxuICAgIHRoaXMub25TeW5jKCdjaGlsZGRhdGEnLCBvbkNoaWxkRGF0YSk7XG5cbiAgICAvLyB0byBlbmFibGUgcmVhY3RpdmUgY29ubmVjdGlvbnNcbiAgICB0aGlzLm9uU3luYygnY2hhbmdlZGF0YScsIGNoYW5nZURhdGFIYW5kbGVyKTtcbn1cblxuXG4vKipcbiAqIERhdGEgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBDcmVhdGUgYW5kIGNvbm5lY3QgaW50ZXJuYWwgYW5kIGV4dGVybmFsIG1lc3NlbmdlcnMgb2YgRGF0YSBmYWNldC5cbiAqIEV4dGVybmFsIG1lc3NlbmdlcidzIG1ldGhvZHMgYXJlIHByb3hpZWQgb24gdGhlIERhdGEgZmFjZXQgYW5kIHRoZXkgYWxsb3dzIFwiKlwiIHN1YnNjcmlwdGlvbnMuXG4gKi9cbi8vIGZ1bmN0aW9uIF9wcmVwYXJlTWVzc2VuZ2VycygpIHtcbiAgICAvLyBEYXRhIGZhY2V0IHdpbGwgcG9zdCBhbGwgaXRzIGNoYW5nZXMgb24gaW50ZXJuYWwgbWVzc2VuZ2VyXG4gICAgLy8gdmFyIGludGVybmFsTWVzc2VuZ2VyID0gbmV3IE1lc3Nlbmdlcih0aGlzKTtcblxuICAgIC8vIG1lc3NhZ2Ugc291cmNlIHRvIGNvbm5lY3QgaW50ZXJuYWwgbWVzc2VuZ2VyIHRvIGV4dGVybmFsXG4gICAgLy8gdmFyIGludGVybmFsTWVzc2VuZ2VyU291cmNlID0gbmV3IE1lc3Nlbmdlck1lc3NhZ2VTb3VyY2UodGhpcywgdW5kZWZpbmVkLCBuZXcgTW9kZWxNc2dBUEksIGludGVybmFsTWVzc2VuZ2VyKTtcblxuICAgIC8vIGV4dGVybmFsIG1lc3NlbmdlciB0byB3aGljaCBhbGwgbW9kZWwgdXNlcnMgd2lsbCBzdWJzY3JpYmUsXG4gICAgLy8gdGhhdCB3aWxsIGFsbG93IFwiKlwiIHN1YnNjcmlwdGlvbnMgYW5kIHN1cHBvcnQgXCJjaGFuZ2VkYXRhXCIgbWVzc2FnZSBhcGkuXG4gICAgLy8gdmFyIGV4dGVybmFsTWVzc2VuZ2VyID0gbmV3IE1lc3Nlbmdlcih0aGlzLCBNZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMsIGludGVybmFsTWVzc2VuZ2VyU291cmNlKTtcblxuLy8gICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4vLyAgICAgICAgIF9tZXNzZW5nZXI6IGV4dGVybmFsTWVzc2VuZ2VyLFxuLy8gICAgICAgICBfaW50ZXJuYWxNZXNzZW5nZXI6IGludGVybmFsTWVzc2VuZ2VyXG4vLyAgICAgfSk7XG4vLyB9XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogSW5pdGlhbGl6ZXMgRE9NRXZlbnRzU291cmNlIGFuZCBjb25uZWN0cyBpdCB0byBEYXRhIGZhY2V0IG1lc3NlbmdlclxuICpcbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIF9wcmVwYXJlTWVzc2FnZVNvdXJjZSgpIHtcbiAgICB2YXIgZGF0YUFQSSA9IG5ldyBEYXRhTXNnQVBJKHRoaXMub3duZXIpXG4gICAgICAgICwgZGF0YUV2ZW50c1NvdXJjZSA9IG5ldyBET01FdmVudHNTb3VyY2UodGhpcywgcHJveHlEYXRhU291cmNlTWV0aG9kcywgZGF0YUFQSSwgdGhpcy5vd25lcik7XG4gICAgdGhpcy5fc2V0TWVzc2FnZVNvdXJjZShkYXRhRXZlbnRzU291cmNlKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgJ19kYXRhRXZlbnRzU291cmNlJywgZGF0YUV2ZW50c1NvdXJjZSk7XG5cbiAgICAvLyBtYWtlIHZhbHVlIG1ldGhvZCBvZiBEYXRhTXNnQVBJIGF2YWlsYWJsZSBvbiBEYXRhIGZhY2V0XG4gICAgLy8gdGhpcyBpcyBhIHByaXZhdGUgbWV0aG9kLCBnZXQoKSBzaG91bGQgYmUgdXNlZCB0byBnZXQgZGF0YS5cbiAgICBNaXhpbi5wcm90b3R5cGUuX2NyZWF0ZVByb3h5TWV0aG9kLmNhbGwoZGF0YUFQSSwgJ3ZhbHVlJywgJ3ZhbHVlJywgdGhpcyk7XG59XG5cblxuLyoqXG4gKiBTdWJzY3JpYmVyIHRvIGRhdGEgY2hhbmdlIGV2ZW50XG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBtc2dUeXBlIGluIHRoaXMgaW5zdGFuY2Ugd2lsbCBiZSAnJ1xuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgZGF0YSBjaGFuZ2UgaW5mb3JtYXRpb25cbiAqL1xuZnVuY3Rpb24gb25Pd25EYXRhQ2hhbmdlKG1zZ1R5cGUsIGRhdGEpIHtcbiAgICB0aGlzLl9idWJibGVVcERhdGFDaGFuZ2UoZGF0YSk7XG4gICAgdGhpcy5fcXVldWVEYXRhQ2hhbmdlKGRhdGEpO1xuICAgIGlmIChkYXRhLnBhdGggPT09ICcnKSB7XG4gICAgICAgIHZhciBpblRyYW5zYWN0aW9uID0gZ2V0VHJhbnNhY3Rpb25GbGFnKGRhdGEpO1xuICAgICAgICB0aGlzLnBvc3RNZXNzYWdlKCdkYXRhY2hhbmdlc2ZpbmlzaGVkJywgeyB0cmFuc2FjdGlvbjogaW5UcmFuc2FjdGlvbiB9KTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogU2VuZHMgZGF0YSBgbWVzc2FnZWAgdG8gRE9NIHBhcmVudFxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge09iamVjdH0gbXNnRGF0YSBkYXRhIGNoYW5nZSBtZXNzYWdlXG4gKi9cbmZ1bmN0aW9uIERhdGEkX2J1YmJsZVVwRGF0YUNoYW5nZShtc2dEYXRhKSB7XG4gICAgdmFyIHBhcmVudERhdGEgPSB0aGlzLnNjb3BlUGFyZW50KCk7XG5cbiAgICBpZiAocGFyZW50RGF0YSkge1xuICAgICAgICB2YXIgcGFyZW50TXNnID0gXy5jbG9uZShtc2dEYXRhKTtcbiAgICAgICAgcGFyZW50TXNnLnBhdGggPSAodGhpcy5fcGF0aCB8fCAoJy4nICsgdGhpcy5vd25lci5uYW1lKSkgICsgcGFyZW50TXNnLnBhdGg7XG4gICAgICAgIHBhcmVudERhdGEucG9zdE1lc3NhZ2UoJ2NoaWxkZGF0YScsIHBhcmVudE1zZyB8fCBtc2dEYXRhKTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogUXVldWVzIGRhdGEgbWVzc2FnZXMgdG8gYmUgZGlzcGF0Y2hlZCB0byBjb25uZWN0b3JcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtPYmplY3R9IGNoYW5nZSBkYXRhIGNoYW5nZSBkZXNjcmlwdGlvblxuICovXG5mdW5jdGlvbiBEYXRhJF9xdWV1ZURhdGFDaGFuZ2UoY2hhbmdlKSB7XG4gICAgdGhpcy5fZGF0YUNoYW5nZXNRdWV1ZS5wdXNoKGNoYW5nZSk7XG59XG5cblxuLyoqXG4gKiBTdWJzY3JpYmVyIHRvIGRhdGFjaGFuZ2VzZmluaXNoZWQgZXZlbnQuXG4gKiBDYWxscyB0aGUgbWV0aG9kIHRvIHBvc3QgY2hhbmdlcyBiYXRjaCBhbmQgYnViYmxlcyB1cCB0aGUgbWVzc2FnZVxuICpcbiAqIEBwYXJhbSAge1t0eXBlXX0gbXNnICBbZGVzY3JpcHRpb25dXG4gKiBAcGFyYW0gIHtbdHlwZV19IGRhdGEgW2Rlc2NyaXB0aW9uXVxuICovXG5mdW5jdGlvbiBvbkRhdGFDaGFuZ2VzRmluaXNoZWQobXNnLCBkYXRhKSB7XG4gICAgdGhpcy5fcG9zdERhdGFDaGFuZ2VzKGRhdGEuaW5UcmFuc2FjdGlvbik7XG4gICAgdmFyIHBhcmVudERhdGEgPSB0aGlzLnNjb3BlUGFyZW50KCk7XG4gICAgaWYgKHBhcmVudERhdGEpIHBhcmVudERhdGEucG9zdE1lc3NhZ2UoJ2RhdGFjaGFuZ2VzZmluaXNoZWQnLCBkYXRhKTtcbn1cblxuXG4vKipcbiAqIERpc3BhdGNoZXMgYWxsIGNoYW5nZXMgY29sbGVjdGVkIGluIHRoZSBiYXRjaFxuICogVXNlZCBmb3IgZGF0YSBwcm9wYWdhdGlvbiAtIGNvbm5lY3RvciBzdWJzY3JpYmVzIHRvIHRoaXMgbWVzc2FnZVxuICpcbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIERhdGEkX3Bvc3REYXRhQ2hhbmdlcyhpblRyYW5zYWN0aW9uKSB7XG4gICAgdmFyIHF1ZXVlID0gdGhpcy5fZGF0YUNoYW5nZXNRdWV1ZS5yZXZlcnNlKCk7XG4gICAgdGhpcy5wb3N0TWVzc2FnZVN5bmMoJ2RhdGFjaGFuZ2VzJywge1xuICAgICAgICBjaGFuZ2VzOiBxdWV1ZSxcbiAgICAgICAgdHJhbnNhY3Rpb246IGluVHJhbnNhY3Rpb25cbiAgICB9KTtcbiAgICB0aGlzLl9kYXRhQ2hhbmdlc1F1ZXVlID0gW107IC8vIGl0IGNhbid0IGJlIC5sZW5ndGggPSAwLCBhcyB0aGUgYWN0dWFsIGFycmF5IG1heSBzdGlsbCBiZSB1c2VkXG59XG5cblxuLyoqXG4gKiBTdWJzY3JpYmVyIHRvIGRhdGEgY2hhbmdlIGV2ZW50IGluIGNoaWxkIERhdGEgZmFjZXRcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtTdHJpbmd9IG1zZ1R5cGVcbiAqIEBwYXJhbSB7T2JlamN0fSBkYXRhIGRhdGEgY2hhbmdlIGluZm9ybWF0aW9uXG4gKi9cbmZ1bmN0aW9uIG9uQ2hpbGREYXRhKG1zZ1R5cGUsIGRhdGEpIHtcbiAgICB0aGlzLnBvc3RNZXNzYWdlKGRhdGEucGF0aCwgZGF0YSk7XG4gICAgdGhpcy5fYnViYmxlVXBEYXRhQ2hhbmdlKGRhdGEpO1xuICAgIHRoaXMuX3F1ZXVlRGF0YUNoYW5nZShkYXRhKTtcbn1cblxuXG4vKipcbiAqIERhdGEgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTZXRzIGRhdGEgaW4gRE9NIGhpZXJhcmNoeSByZWN1cnNpdmVseS5cbiAqIFJldHVybnMgdGhlIG9iamVjdCB3aXRoIHRoZSBkYXRhIGFjdHVhbGx5IHNldCAoY2FuIGJlIGRpZmZlcmVudCwgaWYgY29tcG9uZW50cyBtYXRjaGluZyBzb21lIHByb3BlcnRpZXMgYXJlIG1pc3NpbmcpLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ3xOdW1iZXJ9IHZhbHVlIHZhbHVlIHRvIGJlIHNldC4gSWYgdGhlIHZhbHVlIGlmIHNjYWxhciwgaXQgd2lsbCBiZSBzZXQgb24gY29tcG9uZW50J3MgZWxlbWVudCwgaWYgdGhlIHZhbHVlIGlzIG9iamVjdCAtIG9uIERPTSB0cmVlIGluc2lkZSBjb21wb25lbnRcbiAqIEByZXR1cm4ge09iamVjdHxTdHJpbmd8TnVtYmVyfVxuICovXG5mdW5jdGlvbiBEYXRhJHNldCh2YWx1ZSkge1xuICAgIHZhciBpblRyYW5zYWN0aW9uID0gZ2V0VHJhbnNhY3Rpb25GbGFnKERhdGEkc2V0KTtcblxuICAgIHZhciBjb21wb25lbnRTZXR0ZXIgPSB0aGlzLmNvbmZpZy5zZXQ7XG4gICAgaWYgKHR5cGVvZiBjb21wb25lbnRTZXR0ZXIgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICB2YXIgcmVzdWx0ID0gY29tcG9uZW50U2V0dGVyLmNhbGwodGhpcy5vd25lciwgdmFsdWUpO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIHNldFRyYW5zYWN0aW9uRmxhZyh0aGlzLl9zZXQsIGluVHJhbnNhY3Rpb24pO1xuXG4gICAgdmFyIG9sZFZhbHVlID0gdGhpcy5fdmFsdWVcbiAgICAgICAgLCBuZXdWYWx1ZSA9IHRoaXMuX3NldCh2YWx1ZSk7XG5cbiAgICAvLyB0aGlzIG1lc3NhZ2UgdHJpZ2dlcnMgb25Pd25EYXRhQ2hhbmdlLCBhcyB3ZWxsIGFzIGFjdHVhbGwgRE9NIGNoYW5nZVxuICAgIC8vIHNvIHRoZSBwYXJlbnQgZ2V0cyBub3RpZmllZFxuICAgIHZhciBtc2cgPSB7IHBhdGg6ICcnLCB0eXBlOiAnY2hhbmdlZCcsXG4gICAgICAgICAgICAgICAgbmV3VmFsdWU6IG5ld1ZhbHVlLCBvbGRWYWx1ZTogb2xkVmFsdWUgfTtcbiAgICBzZXRUcmFuc2FjdGlvbkZsYWcobXNnLCBpblRyYW5zYWN0aW9uKTtcbiAgICB0aGlzLnBvc3RNZXNzYWdlKCcnLCBtc2cpO1xuXG4gICAgcmV0dXJuIG5ld1ZhbHVlO1xufVxuXG5cbmZ1bmN0aW9uIERhdGEkX3NldCh2YWx1ZSkge1xuICAgIHZhciBpblRyYW5zYWN0aW9uID0gZ2V0VHJhbnNhY3Rpb25GbGFnKERhdGEkX3NldCk7XG5cbiAgICB2YXIgdmFsdWVTZXQ7XG4gICAgaWYgKHZhbHVlICE9IG51bGwgJiYgdHlwZW9mIHZhbHVlID09ICdvYmplY3QnKSB7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgdmFsdWVTZXQgPSBbXTtcblxuICAgICAgICAgICAgdmFyIGxpc3RGYWNldCA9IHRoaXMub3duZXIubGlzdDtcbiAgICAgICAgICAgIGlmIChsaXN0RmFjZXQpe1xuICAgICAgICAgICAgICAgIHZhciBsaXN0TGVuZ3RoID0gbGlzdEZhY2V0LmNvdW50KClcbiAgICAgICAgICAgICAgICAgICAgLCBuZXdJdGVtc0NvdW50ID0gdmFsdWUubGVuZ3RoIC0gbGlzdExlbmd0aDtcbiAgICAgICAgICAgICAgICBpZiAobmV3SXRlbXNDb3VudCA+PSAzKSB7XG4gICAgICAgICAgICAgICAgICAgIGxpc3RGYWNldC5fYWRkSXRlbXMobmV3SXRlbXNDb3VudCk7XG4gICAgICAgICAgICAgICAgICAgIGxpc3RGYWNldC5fdXBkYXRlRGF0YVBhdGhzKGxpc3RMZW5ndGgsIGxpc3RGYWNldC5jb3VudCgpKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YWx1ZS5mb3JFYWNoKGZ1bmN0aW9uKGNoaWxkVmFsdWUsIGluZGV4KSB7XG4gICAgICAgICAgICAgICAgICAgIHNldENoaWxkRGF0YS5jYWxsKHRoaXMsIHZhbHVlU2V0LCBjaGlsZFZhbHVlLCBpbmRleCwgJ1skJF0nKTtcbiAgICAgICAgICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICAgICAgICAgIHZhciBsaXN0Q291bnQgPSBsaXN0RmFjZXQuY291bnQoKVxuICAgICAgICAgICAgICAgICAgICAsIHJlbW92ZUNvdW50ID0gbGlzdENvdW50IC0gdmFsdWUubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgd2hpbGUgKHJlbW92ZUNvdW50LS0gPiAwKVxuICAgICAgICAgICAgICAgICAgICBsaXN0RmFjZXQuX3JlbW92ZUl0ZW0odmFsdWUubGVuZ3RoKTtcbiAgICAgICAgICAgIH0gZWxzZVxuICAgICAgICAgICAgICAgIGxvZ2dlci53YXJuKCdEYXRhOiBzZXR0aW5nIGFycmF5IGRhdGEgd2l0aG91dCBMaXN0IGZhY2V0Jyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YWx1ZVNldCA9IHt9O1xuICAgICAgICAgICAgXy5lYWNoS2V5KHZhbHVlLCBmdW5jdGlvbihjaGlsZFZhbHVlLCBrZXkpIHtcbiAgICAgICAgICAgICAgICBzZXRDaGlsZERhdGEuY2FsbCh0aGlzLCB2YWx1ZVNldCwgY2hpbGRWYWx1ZSwga2V5LCAnLiQkJyk7XG4gICAgICAgICAgICB9LCB0aGlzKTtcbiAgICAgICAgfVxuICAgIH0gZWxzZVxuICAgICAgICB2YWx1ZVNldCA9IHRoaXMuX3NldFNjYWxhclZhbHVlKHZhbHVlKTtcblxuICAgIHRoaXMuX3ZhbHVlID0gdmFsdWVTZXQ7XG5cbiAgICByZXR1cm4gdmFsdWVTZXQ7XG5cblxuICAgIGZ1bmN0aW9uIHNldENoaWxkRGF0YSh2YWx1ZVNldCwgY2hpbGRWYWx1ZSwga2V5LCBwYXRoU3ludGF4KSB7XG4gICAgICAgIHZhciBjaGlsZFBhdGggPSBwYXRoU3ludGF4LnJlcGxhY2UoJyQkJywga2V5KTtcbiAgICAgICAgdmFyIGNoaWxkRGF0YUZhY2V0ID0gdGhpcy5wYXRoKGNoaWxkUGF0aCwgdHlwZW9mIGNoaWxkVmFsdWUgIT0gJ3VuZGVmaW5lZCcpO1xuICAgICAgICBpZiAoY2hpbGREYXRhRmFjZXQpIHtcbiAgICAgICAgICAgIHNldFRyYW5zYWN0aW9uRmxhZyhjaGlsZERhdGFGYWNldC5zZXQsIGluVHJhbnNhY3Rpb24pO1xuICAgICAgICAgICAgdmFsdWVTZXRba2V5XSA9IGNoaWxkRGF0YUZhY2V0LnNldChjaGlsZFZhbHVlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuXG4vKipcbiAqIERhdGEgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBEZWxldGVzIGNvbXBvbmVudCBmcm9tIHZpZXcgYW5kIHNjb3BlLCBvbmx5IGluIGNhc2UgaXQgaGFzIEl0ZW0gZmFjZXQgb24gaXRcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ3xOdW1iZXJ9IHZhbHVlIHZhbHVlIHRvIHNldCB0byBET00gZWxlbWVudFxuICovXG5mdW5jdGlvbiBEYXRhJGRlbCgpIHtcbiAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGdldFRyYW5zYWN0aW9uRmxhZyhEYXRhJGRlbCk7XG5cbiAgICB2YXIgY29tcG9uZW50RGVsZXRlID0gdGhpcy5jb25maWcuZGVsO1xuICAgIGlmICh0eXBlb2YgY29tcG9uZW50RGVsZXRlID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IGNvbXBvbmVudERlbGV0ZS5jYWxsKHRoaXMub3duZXIpO1xuICAgICAgICBwb3N0VHJhbnNhY3Rpb25GaW5pc2hlZC5jYWxsKHRoaXMsIGluVHJhbnNhY3Rpb24pO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIHZhciBvbGRWYWx1ZSA9IHRoaXMuX3ZhbHVlO1xuXG4gICAgc2V0VHJhbnNhY3Rpb25GbGFnKHRoaXMuX2RlbCwgaW5UcmFuc2FjdGlvbik7XG4gICAgdGhpcy5fZGVsKCk7XG5cbiAgICAvLyB0aGlzIG1lc3NhZ2UgdHJpZ2dlcnMgb25Pd25EYXRhQ2hhbmdlLCBhcyB3ZWxsIGFzIGFjdHVhbGwgRE9NIGNoYW5nZVxuICAgIC8vIHNvIHRoZSBwYXJlbnQgZ2V0cyBub3RpZmllZFxuICAgIHZhciBtc2cgPSB7IHBhdGg6ICcnLCB0eXBlOiAnZGVsZXRlZCcsIG9sZFZhbHVlOiBvbGRWYWx1ZSB9O1xuICAgIHNldFRyYW5zYWN0aW9uRmxhZyhtc2csIGluVHJhbnNhY3Rpb24pO1xuICAgIHRoaXMucG9zdE1lc3NhZ2UoJycsIG1zZyk7XG59XG5cblxuZnVuY3Rpb24gRGF0YSRfZGVsKCkge1xuICAgIHZhciBpblRyYW5zYWN0aW9uID0gZ2V0VHJhbnNhY3Rpb25GbGFnKERhdGEkX2RlbCk7XG4gICAgc2V0VHJhbnNhY3Rpb25GbGFnKHRoaXMuX3NldCwgaW5UcmFuc2FjdGlvbik7XG4gICAgdGhpcy5fc2V0KCk7XG59XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogU2V0cyBzY2FsYXIgdmFsdWUgdG8gRE9NIGVsZW1lbnRcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfSB2YWx1ZSB2YWx1ZSB0byBzZXQgdG8gRE9NIGVsZW1lbnRcbiAqL1xuZnVuY3Rpb24gRGF0YSRfc2V0U2NhbGFyVmFsdWUodmFsdWUpIHtcbiAgICByZXR1cm4gdGhpcy5lbERhdGEuc2V0KHRoaXMub3duZXIuZWwsIHZhbHVlKTtcbn1cblxuXG4vKipcbiAqIERhdGEgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBHZXQgc3RydWN0dXJlZCBkYXRhIGZyb20gRE9NIGhpZXJhcmNoeSByZWN1cnNpdmVseVxuICogUmV0dXJucyBET00gZGF0YVxuICpcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gZGVlcEdldCB0cnVlIGJ5IGRlZmF1bHRcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gRGF0YSRnZXQoZGVlcEdldCkge1xuICAgIHZhciBjb21wb25lbnRHZXR0ZXIgPSB0aGlzLmNvbmZpZy5nZXQ7XG4gICAgaWYgKHR5cGVvZiBjb21wb25lbnRHZXR0ZXIgPT0gJ2Z1bmN0aW9uJylcbiAgICAgICAgcmV0dXJuIGNvbXBvbmVudEdldHRlci5jYWxsKHRoaXMub3duZXIsIGRlZXBHZXQpO1xuXG4gICAgcmV0dXJuIHRoaXMuX2dldChkZWVwR2V0KTtcbn1cblxuZnVuY3Rpb24gRGF0YSRfZ2V0KGRlZXBHZXQpIHtcbiAgICBpZiAoZGVlcEdldCA9PT0gZmFsc2UpIC8vIGEgaGFjayB0byBlbmFibGUgZ2V0dGluZyBzaGFsbG93IHN0YXRlXG4gICAgICAgIHJldHVybjtcblxuICAgIHZhciBjb21wID0gdGhpcy5vd25lclxuICAgICAgICAsIHNjb3BlRGF0YTtcblxuICAgIGlmIChjb21wLmxpc3QpIHtcbiAgICAgICAgc2NvcGVEYXRhID0gW107XG4gICAgICAgIGNvbXAubGlzdC5lYWNoKGZ1bmN0aW9uKGxpc3RJdGVtLCBpbmRleCkge1xuICAgICAgICAgICAgc2NvcGVEYXRhW2luZGV4XSA9IGxpc3RJdGVtLmRhdGEuZ2V0KCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChjb21wLmNvbnRhaW5lcilcbiAgICAgICAgICAgIGNvbXAuY29udGFpbmVyLnNjb3BlLl9lYWNoKGZ1bmN0aW9uKHNjb3BlSXRlbSwgbmFtZSkge1xuICAgICAgICAgICAgICAgIGlmICghIGNvbXAubGlzdC5jb250YWlucyhzY29wZUl0ZW0pICYmIHNjb3BlSXRlbS5kYXRhKVxuICAgICAgICAgICAgICAgICAgICBzY29wZURhdGFbbmFtZV0gPSBzY29wZUl0ZW0uZGF0YS5nZXQoKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAoY29tcC5jb250YWluZXIpIHtcbiAgICAgICAgc2NvcGVEYXRhID0ge307XG4gICAgICAgIGNvbXAuY29udGFpbmVyLnNjb3BlLl9lYWNoKGZ1bmN0aW9uKHNjb3BlSXRlbSwgbmFtZSkge1xuICAgICAgICAgICAgaWYgKHNjb3BlSXRlbS5kYXRhKVxuICAgICAgICAgICAgICAgIHNjb3BlRGF0YVtuYW1lXSA9IHNjb3BlSXRlbS5kYXRhLmdldCgpO1xuICAgICAgICB9KTtcbiAgICB9IGVsc2VcbiAgICAgICAgc2NvcGVEYXRhID0gdGhpcy5fZ2V0U2NhbGFyVmFsdWUoKTtcblxuICAgIHRoaXMuX3ZhbHVlID0gc2NvcGVEYXRhO1xuXG4gICAgcmV0dXJuIHNjb3BlRGF0YTtcbn1cblxuXG4vKipcbiAqIERhdGEgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBHZXRzIHNjYWxhciBkYXRhIGZyb20gRE9NIGVsZW1lbnRcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBEYXRhJF9nZXRTY2FsYXJWYWx1ZSgpIHtcbiAgICByZXR1cm4gdGhpcy5lbERhdGEuZ2V0KHRoaXMub3duZXIuZWwpO1xufVxuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFNwbGljZXMgTGlzdCBpdGVtcy4gUmVxdWlyZXMgTGlzdCBmYWNldCB0byBiZSBwcmVzZW50IG9uIGNvbXBvbmVudC4gV29ya3MgaW4gdGhlIHNhbWUgd2F5IGFzIGFycmF5IHNwbGljZS5cbiAqIFJldHVybnMgZGF0YSByZXRyaWV2ZWQgZnJvbSByZW1vdmVkIGl0ZW1zXG4gKlxuICogQHBhcmFtIHtJbnRlZ2VyfSBzcGxpY2VJbmRleCBpbmRleCB0byBkZWxldGUvaW5zZXJ0IGF0XG4gKiBAcGFyYW0ge0ludGVnZXJ9IHNwbGljZUhvd01hbnkgbnVtYmVyIG9mIGl0ZW1zIHRvIGRlbGV0ZVxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgb3B0aW9uYWwgaXRlbXMgdG8gaW5zZXJ0XG4gKiBAcmV0dXJuIHtBcnJheX1cbiAqL1xuZnVuY3Rpb24gRGF0YSRzcGxpY2Uoc3BsaWNlSW5kZXgsIHNwbGljZUhvd01hbnkpIHsgLy8sIC4uLiBhcmd1bWVudHNcbiAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGdldFRyYW5zYWN0aW9uRmxhZyhEYXRhJHNwbGljZSk7XG4gICAgdmFyIHJlc3VsdDtcblxuICAgIHZhciBjb21wb25lbnRTcGxpY2UgPSB0aGlzLmNvbmZpZy5zcGxpY2U7XG4gICAgaWYgKHR5cGVvZiBjb21wb25lbnRTcGxpY2UgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICByZXN1bHQgPSBjb21wb25lbnRTcGxpY2UuYXBwbHkodGhpcy5vd25lciwgYXJndW1lbnRzKTtcbiAgICAgICAgcG9zdFRyYW5zYWN0aW9uRmluaXNoZWQuY2FsbCh0aGlzLCBpblRyYW5zYWN0aW9uKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBzZXRUcmFuc2FjdGlvbkZsYWcodGhpcy5fc3BsaWNlLCBpblRyYW5zYWN0aW9uKTtcbiAgICByZXN1bHQgPSB0aGlzLl9zcGxpY2UuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIGlmICghcmVzdWx0KSByZXR1cm47XG5cbiAgICB2YXIgbXNnID0geyBwYXRoOiAnJywgdHlwZTogJ3NwbGljZScsXG4gICAgICAgICAgICAgICAgaW5kZXg6IHJlc3VsdC5zcGxpY2VJbmRleCxcbiAgICAgICAgICAgICAgICByZW1vdmVkOiByZXN1bHQucmVtb3ZlZCxcbiAgICAgICAgICAgICAgICBhZGRlZENvdW50OiByZXN1bHQuYWRkZWRDb3VudCxcbiAgICAgICAgICAgICAgICBuZXdWYWx1ZTogdGhpcy5fdmFsdWUgfTtcbiAgICBzZXRUcmFuc2FjdGlvbkZsYWcobXNnLCBpblRyYW5zYWN0aW9uKTtcbiAgICB0aGlzLnBvc3RNZXNzYWdlKCcnLCBtc2cpO1xuXG4gICAgcmV0dXJuIHJlc3VsdC5yZW1vdmVkO1xufVxuXG5cbmZ1bmN0aW9uIERhdGEkX3NwbGljZShzcGxpY2VJbmRleCwgc3BsaWNlSG93TWFueSkgeyAvLywgLi4uIGFyZ3VtZW50c1xuICAgIHZhciBpblRyYW5zYWN0aW9uID0gZ2V0VHJhbnNhY3Rpb25GbGFnKERhdGEkX3NwbGljZSk7XG5cbiAgICB2YXIgbGlzdEZhY2V0ID0gdGhpcy5vd25lci5saXN0O1xuICAgIGlmICghIGxpc3RGYWNldClcbiAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdEYXRhOiBjYW5ub3QgdXNlIHNwbGljZSBtZXRob2Qgd2l0aG91dCBMaXN0IGZhY2V0Jyk7XG5cbiAgICB2YXIgcmVtb3ZlZCA9IFtdO1xuXG4gICAgdmFyIGxpc3RMZW5ndGggPSBsaXN0RmFjZXQuY291bnQoKTtcbiAgICBhcmd1bWVudHNbMF0gPSBzcGxpY2VJbmRleCA9XG4gICAgICAgIG1vZGVsVXRpbHMubm9ybWFsaXplU3BsaWNlSW5kZXgoc3BsaWNlSW5kZXgsIGxpc3RMZW5ndGgpO1xuXG4gICAgaWYgKHNwbGljZUhvd01hbnkgPiAwICYmIGxpc3RMZW5ndGggPiAwKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSBzcGxpY2VJbmRleDsgaSA8IHNwbGljZUluZGV4ICsgc3BsaWNlSG93TWFueTsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgaXRlbSA9IGxpc3RGYWNldC5pdGVtKHNwbGljZUluZGV4KTtcbiAgICAgICAgICAgIGlmIChpdGVtKSB7XG4gICAgICAgICAgICAgICAgdmFyIGl0ZW1EYXRhID0gaXRlbS5kYXRhLmdldCgpO1xuICAgICAgICAgICAgICAgIGxpc3RGYWNldC5fcmVtb3ZlSXRlbShzcGxpY2VJbmRleCk7XG4gICAgICAgICAgICB9IGVsc2VcbiAgICAgICAgICAgICAgICBsb2dnZXIud2FybignRGF0YTogbm8gaXRlbSBmb3IgaW5kZXgnLCBpKTtcblxuICAgICAgICAgICAgcmVtb3ZlZC5wdXNoKGl0ZW1EYXRhKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxpc3RGYWNldC5fdXBkYXRlRGF0YVBhdGhzKHNwbGljZUluZGV4LCBsaXN0RmFjZXQuY291bnQoKSk7XG4gICAgfVxuXG4gICAgdmFyIGFkZGVkID0gW107XG5cbiAgICB2YXIgYXJnc0xlbiA9IGFyZ3VtZW50cy5sZW5ndGhcbiAgICAgICAgLCBhZGRJdGVtcyA9IGFyZ3NMZW4gPiAyXG4gICAgICAgICwgYWRkZWRDb3VudCA9IGFyZ3NMZW4gLSAyO1xuICAgIGlmIChhZGRJdGVtcykge1xuICAgICAgICBsaXN0RmFjZXQuX2FkZEl0ZW1zKGFkZGVkQ291bnQsIHNwbGljZUluZGV4KTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDIsIGogPSBzcGxpY2VJbmRleDsgaSA8IGFyZ3NMZW47IGkrKywgaisrKSB7XG4gICAgICAgICAgICB2YXIgaXRlbSA9IGxpc3RGYWNldC5pdGVtKGopO1xuICAgICAgICAgICAgaWYgKGl0ZW0pIHtcbiAgICAgICAgICAgICAgICBzZXRUcmFuc2FjdGlvbkZsYWcoaXRlbS5kYXRhLnNldCwgaW5UcmFuc2FjdGlvbik7XG4gICAgICAgICAgICAgICAgdmFyIGl0ZW1EYXRhID0gaXRlbS5kYXRhLnNldChhcmd1bWVudHNbaV0pO1xuICAgICAgICAgICAgfSBlbHNlXG4gICAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ0RhdGE6IG5vIGl0ZW0gZm9yIGluZGV4Jywgaik7XG5cbiAgICAgICAgICAgIGFkZGVkLnB1c2goaXRlbURhdGEpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gY2hhbmdlIHBhdGhzIG9mIGl0ZW1zIHRoYXQgd2VyZSBhZGRlZCBhbmQgaXRlbXMgYWZ0ZXIgdGhlbVxuICAgICAgICBsaXN0RmFjZXQuX3VwZGF0ZURhdGFQYXRocyhzcGxpY2VJbmRleCwgbGlzdEZhY2V0LmNvdW50KCkpO1xuICAgIH1cblxuICAgIC8vIGlmIChBcnJheS5pc0FycmF5KHRoaXMuX3ZhbHVlKSkge1xuICAgIC8vICAgICBfLnByZXBlbmRBcnJheShhZGRlZCwgW3NwbGljZUluZGV4LCBzcGxpY2VIb3dNYW55XSk7XG4gICAgLy8gICAgIEFycmF5LnByb3RvdHlwZS5zcGxpY2UuYXBwbHkodGhpcy5fdmFsdWUsIGFkZGVkKTtcbiAgICAvLyB9IGVsc2VcbiAgICAgICAgdGhpcy5fdmFsdWUgPSB0aGlzLmdldCgpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgc3BsaWNlSW5kZXg6IHNwbGljZUluZGV4LFxuICAgICAgICByZW1vdmVkOiByZW1vdmVkLFxuICAgICAgICBhZGRlZENvdW50OiBhZGRJdGVtcyA/IGFkZGVkQ291bnQgOiAwXG4gICAgfTtcbn1cblxuXG5mdW5jdGlvbiBEYXRhJGxlbigpIHtcbiAgICB2YXIgY29tcG9uZW50TGVuID0gdGhpcy5jb25maWcubGVuO1xuICAgIGlmICh0eXBlb2YgY29tcG9uZW50TGVuID09ICdmdW5jdGlvbicpXG4gICAgICAgIHJldHVybiBjb21wb25lbnRMZW4uY2FsbCh0aGlzLm93bmVyKTtcbiAgICBlbHNlXG4gICAgICAgIHJldHVybiB0aGlzLl9sZW4oKTtcbn1cblxuXG5mdW5jdGlvbiBEYXRhJF9sZW4oKSB7XG4gICAgaWYgKHRoaXMub3duZXIubGlzdCkgcmV0dXJuIHRoaXMub3duZXIubGlzdC5jb3VudCgpO1xuICAgIGVsc2UgbG9nZ2VyLmVycm9yKCdEYXRhOiBsZW4gY2FsbGVkIHdpdGhvdXQgbGlzdCBmYWNldCcpO1xufVxuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgZGF0YSBmYWNldCBvZiBhIGNoaWxkIGNvbXBvbmVudCAoYnkgc2NvcGVzKSBjb3JyZXNwb25kaW5nIHRvIHRoZSBwYXRoXG4gKiBAcGFyYW0ge1N0cmluZ30gYWNjZXNzUGF0aCBkYXRhIGFjY2VzcyBwYXRoXG4gKi9cbmZ1bmN0aW9uIERhdGEkcGF0aChhY2Nlc3NQYXRoLCBjcmVhdGVJdGVtKSB7XG4gICAgLy8gY3JlYXRlSXRlbSA9IHRydWU7IC8vIHRoaXMgaGFjayBzZWVtcyB0byBiZSBubyBsb25nZXIgbmVlZGVkLi4uXG5cbiAgICBpZiAoISBhY2Nlc3NQYXRoKVxuICAgICAgICByZXR1cm4gdGhpcztcblxuICAgIHZhciBwYXJzZWRQYXRoID0gcGF0aFV0aWxzLnBhcnNlQWNjZXNzUGF0aChhY2Nlc3NQYXRoKTtcbiAgICB2YXIgY3VycmVudENvbXBvbmVudCA9IHRoaXMub3duZXI7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gcGFyc2VkUGF0aC5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgICAgICB2YXIgcGF0aE5vZGUgPSBwYXJzZWRQYXRoW2ldXG4gICAgICAgICAgICAsIG5vZGVLZXkgPSBwYXRoVXRpbHMuZ2V0UGF0aE5vZGVLZXkocGF0aE5vZGUpO1xuICAgICAgICBpZiAocGF0aE5vZGUuc3ludGF4ID09ICdhcnJheScgJiYgY3VycmVudENvbXBvbmVudC5saXN0KSB7XG4gICAgICAgICAgICB2YXIgaXRlbUNvbXBvbmVudCA9IGN1cnJlbnRDb21wb25lbnQubGlzdC5pdGVtKG5vZGVLZXkpO1xuICAgICAgICAgICAgaWYgKCEgaXRlbUNvbXBvbmVudCAmJiBjcmVhdGVJdGVtICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgIGl0ZW1Db21wb25lbnQgPSBjdXJyZW50Q29tcG9uZW50Lmxpc3QuX2FkZEl0ZW0obm9kZUtleSk7XG4gICAgICAgICAgICAgICAgaXRlbUNvbXBvbmVudC5kYXRhLl9wYXRoID0gcGF0aE5vZGUucHJvcGVydHk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjdXJyZW50Q29tcG9uZW50ID0gaXRlbUNvbXBvbmVudDtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJyZW50Q29tcG9uZW50LmNvbnRhaW5lcilcbiAgICAgICAgICAgIGN1cnJlbnRDb21wb25lbnQgPSBjdXJyZW50Q29tcG9uZW50LmNvbnRhaW5lci5zY29wZVtub2RlS2V5XTtcblxuICAgICAgICB2YXIgY3VycmVudERhdGFGYWNldCA9IGN1cnJlbnRDb21wb25lbnQgJiYgY3VycmVudENvbXBvbmVudC5kYXRhO1xuICAgICAgICBpZiAoISBjdXJyZW50RGF0YUZhY2V0KVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgcmV0dXJuIGN1cnJlbnREYXRhRmFjZXQ7XG59XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyBwYXRoIHRvIGFjY2VzcyB0aGlzIGRhdGEgZmFjZXQgZnJvbSBwYXJlbnQgKHVzaW5nIHBhdGggbWV0aG9kKVxuICpcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gRGF0YSRnZXRQYXRoKCkge1xuICAgIHJldHVybiB0aGlzLl9wYXRoO1xufVxuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMga2V5IHRvIGFjY2VzcyB0aGUgdmFsdWUgcmVsYXRlZCB0byB0aGlzIGRhdGEgZmFjZXQgb24gdGhlIHZhbHVlIHJlbGF0ZWQgdG8gcGFyZW50IGRhdGEgZmFjZXQuXG4gKiBJZiBjb21wb25lbnQgaGFzIExpc3QgZmFjZXQsIHJldHVybnMgaW5kZXhcbiAqXG4gKiBAcmV0dXJuIHtTdHJpbmd8SW50ZWdlcn1cbiAqL1xuZnVuY3Rpb24gRGF0YSRnZXRLZXkoKSB7XG4gICAgdmFyIHBhdGggPSB0aGlzLl9wYXRoO1xuICAgIHJldHVybiBwYXRoWzBdID09ICdbJ1xuICAgICAgICAgICAgPyArcGF0aC5zbGljZSgxLCAtMSkgLy8gcmVtb3ZlIFwiW1wiIGFuZCBcIl1cIlxuICAgICAgICAgICAgOiBwYXRoLnNsaWNlKDEpIC8vIHJlbW92ZSBsZWFkaW5nIFwiLlwiXG59XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogQ2FsbGVkIGJ5IGBDb21wb25lbnQucHJvdG90eXBlLmdldFN0YXRlYCB0byBnZXQgZmFjZXQncyBzdGF0ZVxuICogUmV0dXJucyBET00gZGF0YVxuICpcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gZGVlcFN0YXRlLCB0cnVlIGJ5IGRlZmF1bHRcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gRGF0YSRnZXRTdGF0ZShkZWVwU3RhdGUpIHtcbiAgICByZXR1cm4geyBzdGF0ZTogdGhpcy5nZXQoZGVlcFN0YXRlKSB9O1xufVxuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIENhbGxlZCBieSBgQ29tcG9uZW50LnByb3RvdHlwZS5zZXRTdGF0ZWAgdG8gc2V0IGZhY2V0J3Mgc3RhdGVcbiAqIFNpbXBseSBzZXRzIG1vZGVsIGRhdGFcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc3RhdGUgZGF0YSB0byBzZXQgb24gZmFjZXQncyBtb2RlbFxuICovXG5mdW5jdGlvbiBEYXRhJHNldFN0YXRlKHN0YXRlKSB7XG4gICAgcmV0dXJuIHRoaXMuc2V0KHN0YXRlLnN0YXRlKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgQ29tcG9uZW50RmFjZXQgPSByZXF1aXJlKCcuLi9jX2ZhY2V0JylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jZl9yZWdpc3RyeScpIFxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgYmluZGVyID0gcmVxdWlyZSgnLi4vLi4vYmluZGVyJylcbiAgICAsIEJpbmRBdHRyaWJ1dGUgPSByZXF1aXJlKCcuLi8uLi9hdHRyaWJ1dGVzL2FfYmluZCcpXG4gICAgLCBEb21GYWNldEVycm9yID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9lcnJvcicpLkRvbUZhY2V0XG4gICAgLCBkb21VdGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvZG9tJylcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4uLy4uL2NvbmZpZycpXG4gICAgLCBkb1QgPSByZXF1aXJlKCdkb3QnKTtcblxuXG4vKipcbiAqIGBtaWxvLnJlZ2lzdHJ5LmZhY2V0cy5nZXQoJ0RvbScpYFxuICogRmFjZXQgd2l0aCBjb21wb25lbnQgcmVsYXRlZCBkb20gdXRpbHNcbiAqL1xudmFyIERvbSA9IF8uY3JlYXRlU3ViY2xhc3MoQ29tcG9uZW50RmFjZXQsICdEb20nKTtcblxuXy5leHRlbmQoRG9tLCB7XG4gICAgY3JlYXRlRWxlbWVudDogRG9tJCRjcmVhdGVFbGVtZW50XG59KTtcblxuXG4vKipcbiAqIEZhY2V0IGNsYXNzIG1ldGhvZFxuICogQ3JlYXRlcyBhbiBlbGVtZW50IGZyb20gYSBwYXNzZWQgY29uZmlndWF0aW9uIG9iamVjdFxuICogXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIHdpdGggdGhlIHByb3BlcnRpZXMgYGRvbUNvbmZpZ2AsIGBjb250ZW50YCwgYHRlbXBsYXRlYFxuICogQHJldHVybiB7RWxlbWVudH0gYW4gaHRtbCBlbGVtZW50IFxuICovXG5mdW5jdGlvbiBEb20kJGNyZWF0ZUVsZW1lbnQoY29uZmlnKSB7XG4gICAgdmFyIGRvbUNvbmZpZyA9IGNvbmZpZy5kb21Db25maWcgfHwge31cbiAgICAgICAgLCB0YWdOYW1lID0gZG9tQ29uZmlnLnRhZ05hbWUgfHwgJ2RpdidcbiAgICAgICAgLCBuZXdFbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodGFnTmFtZSlcbiAgICAgICAgLCBjb250ZW50ID0gY29uZmlnLmNvbnRlbnRcbiAgICAgICAgLCB0ZW1wbGF0ZSA9IGNvbmZpZy50ZW1wbGF0ZTtcblxuICAgIC8vIFRPRE8gaXQgd2lsbCBiZSBjYWxsZWQgYWdhaW4gd2hlbi9pZiBjb21wb25lbnQgaXMgaW5zdGFudGlhdGVkXG4gICAgLy8gU2hvdWxkIGJlIHNvbWVwcm9wZXJ0eSBvbiBlbGVtZW50IHRvIGluZGljYXRlIGl0J3MgYmVlbiBjYWxsZWQ/XG4gICAgX2FwcGx5Q29uZmlnVG9FbGVtZW50KG5ld0VsLCBkb21Db25maWcpO1xuXG4gICAgaWYgKHR5cGVvZiBjb250ZW50ID09ICdzdHJpbmcnKSB7XG4gICAgICAgIGlmICh0ZW1wbGF0ZSlcbiAgICAgICAgICAgIG5ld0VsLmlubmVySFRNTCA9IGRvVC50ZW1wbGF0ZSh0ZW1wbGF0ZSkoe2NvbnRlbnQ6IGNvbnRlbnR9KTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgbmV3RWwuaW5uZXJIVE1MID0gY29udGVudDtcbiAgICB9XG4gICAgcmV0dXJuIG5ld0VsO1xufVxuXG5cbmZ1bmN0aW9uIF9hcHBseUNvbmZpZ1RvRWxlbWVudChlbCwgY29uZmlnKSB7XG4gICAgdmFyIGNzc0NsYXNzZXMgPSBjb25maWcgJiYgY29uZmlnLmNsc1xuICAgICAgICAsIGNvbmZpZ0F0dHJpYnV0ZXMgPSBjb25maWcgJiYgY29uZmlnLmF0dHJpYnV0ZXM7XG5cbiAgICBpZiAoY29uZmlnQXR0cmlidXRlcylcbiAgICAgICAgXy5lYWNoS2V5KGNvbmZpZ0F0dHJpYnV0ZXMsIGZ1bmN0aW9uKGF0dHJWYWx1ZSwgYXR0ck5hbWUpIHtcbiAgICAgICAgICAgIGVsLnNldEF0dHJpYnV0ZShhdHRyTmFtZSwgYXR0clZhbHVlKTtcbiAgICAgICAgfSk7XG5cbiAgICBpZiAoY3NzQ2xhc3NlcylcbiAgICAgICAgX2F0dGFjaENzc0NsYXNzZXMoZWwsICdhZGQnLCBjc3NDbGFzc2VzKTtcbn1cblxuXG5fLmV4dGVuZFByb3RvKERvbSwge1xuICAgIHN0YXJ0OiBzdGFydCxcblxuICAgIHNob3c6IHNob3csXG4gICAgaGlkZTogaGlkZSxcbiAgICB0b2dnbGU6IHRvZ2dsZSxcbiAgICBkZXRhY2g6IGRldGFjaCxcbiAgICByZW1vdmU6IHJlbW92ZSxcbiAgICBhcHBlbmQ6IGFwcGVuZCxcbiAgICBwcmVwZW5kOiBwcmVwZW5kLFxuICAgIGFwcGVuZENoaWxkcmVuOiBhcHBlbmRDaGlsZHJlbixcbiAgICBwcmVwZW5kQ2hpbGRyZW46IHByZXBlbmRDaGlsZHJlbixcbiAgICBpbnNlcnRBZnRlcjogaW5zZXJ0QWZ0ZXIsXG4gICAgaW5zZXJ0QmVmb3JlOiBpbnNlcnRCZWZvcmUsXG4gICAgYXBwZW5kVG9TY29wZVBhcmVudDogYXBwZW5kVG9TY29wZVBhcmVudCxcbiAgICBjaGlsZHJlbjogRG9tJGNoaWxkcmVuLFxuICAgIHNldFN0eWxlOiBzZXRTdHlsZSxcbiAgICBzZXRTdHlsZXM6IHNldFN0eWxlcyxcbiAgICBjb3B5OiBjb3B5LFxuICAgIGNyZWF0ZUVsZW1lbnQ6IGNyZWF0ZUVsZW1lbnQsXG5cbiAgICBhZGRDc3NDbGFzc2VzOiBfLnBhcnRpYWwoX21hbmFnZUNzc0NsYXNzZXMsICdhZGQnKSxcbiAgICByZW1vdmVDc3NDbGFzc2VzOiBfLnBhcnRpYWwoX21hbmFnZUNzc0NsYXNzZXMsICdyZW1vdmUnKSxcbiAgICB0b2dnbGVDc3NDbGFzc2VzOiBfLnBhcnRpYWwoX21hbmFnZUNzc0NsYXNzZXMsICd0b2dnbGUnKSxcblxuICAgIGZpbmQ6IGZpbmQsXG4gICAgaGFzVGV4dEJlZm9yZVNlbGVjdGlvbjogaGFzVGV4dEJlZm9yZVNlbGVjdGlvbixcbiAgICBoYXNUZXh0QWZ0ZXJTZWxlY3Rpb246IGhhc1RleHRBZnRlclNlbGVjdGlvbixcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoRG9tKTtcblxubW9kdWxlLmV4cG9ydHMgPSBEb207XG5cblxuLy8gc3RhcnQgRG9tIGZhY2V0XG5mdW5jdGlvbiBzdGFydCgpIHtcbiAgICB2YXIgZWwgPSB0aGlzLm93bmVyLmVsO1xuICAgIF9hcHBseUNvbmZpZ1RvRWxlbWVudChlbCwgdGhpcy5jb25maWcpO1xuICAgIHZhciBjdXJyZW50U3R5bGUgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlbClcbiAgICB0aGlzLl92aXNpYmxlID0gY3VycmVudFN0eWxlICYmIGN1cnJlbnRTdHlsZS5kaXNwbGF5ICE9ICdub25lJztcbn1cblxuLy8gc2hvdyBIVE1MIGVsZW1lbnQgb2YgY29tcG9uZW50XG5mdW5jdGlvbiBzaG93KCkge1xuICAgIHRoaXMudG9nZ2xlKHRydWUpO1xufVxuXG4vLyBoaWRlIEhUTUwgZWxlbWVudCBvZiBjb21wb25lbnRcbmZ1bmN0aW9uIGhpZGUoKSB7XG4gICAgdGhpcy50b2dnbGUoZmFsc2UpO1xufVxuXG4vLyBzaG93L2hpZGVcbmZ1bmN0aW9uIHRvZ2dsZShkb1Nob3cpIHtcbiAgICBkb1Nob3cgPSB0eXBlb2YgZG9TaG93ID09ICd1bmRlZmluZWQnXG4gICAgICAgICAgICAgICAgPyAhIHRoaXMuX3Zpc2libGVcbiAgICAgICAgICAgICAgICA6ICEhIGRvU2hvdztcblxuICAgIHRoaXMuX3Zpc2libGUgPSBkb1Nob3c7XG4gICAgdmFyIGVsID0gdGhpcy5vd25lci5lbDtcblxuICAgIGVsLnN0eWxlLmRpc3BsYXkgPSBkb1Nob3cgPyAnYmxvY2snIDogJ25vbmUnO1xuXG4gICAgcmV0dXJuIGRvU2hvdztcbn1cblxuXG5mdW5jdGlvbiBfbWFuYWdlQ3NzQ2xhc3NlcyhtZXRob2ROYW1lLCBjc3NDbGFzc2VzLCBlbmZvcmNlKSB7XG4gICAgX2F0dGFjaENzc0NsYXNzZXModGhpcy5vd25lci5lbCwgbWV0aG9kTmFtZSwgY3NzQ2xhc3NlcywgZW5mb3JjZSk7XG59XG5cblxuZnVuY3Rpb24gX2F0dGFjaENzc0NsYXNzZXMoZWwsIG1ldGhvZE5hbWUsIGNzc0NsYXNzZXMsIGVuZm9yY2UpIHtcbiAgICB2YXIgY2xhc3NMaXN0ID0gZWwuY2xhc3NMaXN0XG4gICAgICAgICwgZG9Ub2dnbGUgPSBtZXRob2ROYW1lID09ICd0b2dnbGUnO1xuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoY3NzQ2xhc3NlcykpXG4gICAgICAgIGNzc0NsYXNzZXMuZm9yRWFjaChjYWxsTWV0aG9kKTtcbiAgICBlbHNlIGlmICh0eXBlb2YgY3NzQ2xhc3NlcyA9PSAnc3RyaW5nJylcbiAgICAgICAgY2FsbE1ldGhvZChjc3NDbGFzc2VzKTtcbiAgICBlbHNlXG4gICAgICAgIHRocm93IG5ldyBEb21GYWNldEVycm9yKCd1bmtub3duIHR5cGUgb2YgQ1NTIGNsYXNzZXMgcGFyYW1ldGVyJyk7XG5cbiAgICBmdW5jdGlvbiBjYWxsTWV0aG9kKGNzc0Nscykge1xuICAgICAgICBkb1RvZ2dsZVxuICAgICAgICAgICAgLy8gT25seSBwYXNzICdlbmZvcmNlJyBpZiBhIHZhbHVlIGhhcyBiZWVuIHByb3ZpZGVkIChUaGUgJ3RvZ2dsZScgZnVuY3Rpb24gb2YgdGhlIGNsYXNzTGlzdCB3aWxsIHRyZWF0IHVuZGVmaW5lZCA9PT0gZmFsc2UgcmVzdWx0aW5nIGluIG9ubHkgYWxsb3dpbmcgY2xhc3NlcyB0byBiZSByZW1vdmVkKVxuICAgICAgICAgICAgPyBlbmZvcmNlID09PSB1bmRlZmluZWQgPyBjbGFzc0xpc3RbbWV0aG9kTmFtZV0oY3NzQ2xzKSA6IGNsYXNzTGlzdFttZXRob2ROYW1lXShjc3NDbHMsIGVuZm9yY2UpXG4gICAgICAgICAgICA6IGNsYXNzTGlzdFttZXRob2ROYW1lXShjc3NDbHMpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBkZXRhY2goKSB7XG4gICAgaWYgKHRoaXMub3duZXIuZWwpICBcbiAgICAgICAgZG9tVXRpbHMuZGV0YWNoQ29tcG9uZW50KHRoaXMub3duZXIuZWwpO1xufVxuXG5cbmZ1bmN0aW9uIHNldFN0eWxlKHByb3BlcnR5LCB2YWx1ZSkge1xuICAgIGlmICghdGhpcy5vd25lci5lbCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY2FsbCBzZXRTdHlsZSBvbiBvd25lciB3aXRoIG5vIGVsZW1lbnQ6IFwiICsgdGhpcy5vd25lci5jb25zdHJ1Y3Rvci5uYW1lKTtcbiAgICB9XG4gICAgdGhpcy5vd25lci5lbC5zdHlsZVtwcm9wZXJ0eV0gPSB2YWx1ZTtcbn1cblxuZnVuY3Rpb24gc2V0U3R5bGVzKHByb3BlcnRpZXMpIHtcbiAgICBmb3IgKHZhciBwcm9wZXJ0eSBpbiBwcm9wZXJ0aWVzKVxuICAgICAgICB0aGlzLm93bmVyLmVsLnN0eWxlW3Byb3BlcnR5XSA9IHByb3BlcnRpZXNbcHJvcGVydHldO1xufVxuXG5cbi8vIGNyZWF0ZSBhIGNvcHkgb2YgRE9NIGVsZW1lbnQgdXNpbmcgZmFjZXQgY29uZmlnIGlmIHNldFxuZnVuY3Rpb24gY29weShpc0RlZXApIHtcbiAgICByZXR1cm4gdGhpcy5vd25lci5lbCAmJiB0aGlzLm93bmVyLmVsLmNsb25lTm9kZShpc0RlZXApO1xufVxuXG5cbmZ1bmN0aW9uIGNyZWF0ZUVsZW1lbnQoKSB7XG4gICAgdmFyIG5ld0VsID0gRG9tLmNyZWF0ZUVsZW1lbnQodGhpcy5jb25maWcpO1xuICAgIHJldHVybiBuZXdFbDtcbn1cblxuXG4vLyByZW1vdmUgSFRNTCBlbGVtZW50IG9mIGNvbXBvbmVudFxuZnVuY3Rpb24gcmVtb3ZlKCkge1xuICAgIGRvbVV0aWxzLnJlbW92ZUVsZW1lbnQodGhpcy5vd25lci5lbCk7XG59XG5cbi8vIGFwcGVuZCBpbnNpZGUgSFRNTCBlbGVtZW50IG9mIGNvbXBvbmVudFxuZnVuY3Rpb24gYXBwZW5kKGVsKSB7XG4gICAgdGhpcy5vd25lci5lbC5hcHBlbmRDaGlsZChlbCk7XG59XG5cbi8vIHByZXBlbmQgaW5zaWRlIEhUTUwgZWxlbWVudCBvZiBjb21wb25lbnRcbmZ1bmN0aW9uIHByZXBlbmQoZWwpIHtcbiAgICB2YXIgdGhpc0VsID0gdGhpcy5vd25lci5lbFxuICAgICAgICAsIGZpcnN0Q2hpbGQgPSB0aGlzRWwuZmlyc3RDaGlsZDtcbiAgICBpZiAoZmlyc3RDaGlsZClcbiAgICAgICAgdGhpc0VsLmluc2VydEJlZm9yZShlbCwgZmlyc3RDaGlsZCk7XG4gICAgZWxzZVxuICAgICAgICB0aGlzRWwuYXBwZW5kQ2hpbGQoZWwpO1xufVxuXG4vLyBhcHBlbmRzIGNoaWxkcmVuIG9mIGVsZW1lbnQgaW5zaWRlIHRoaXMgY29tcG9uZW50J3MgZWxlbWVudFxuZnVuY3Rpb24gYXBwZW5kQ2hpbGRyZW4oZWwpIHtcbiAgICB3aGlsZShlbC5jaGlsZE5vZGVzLmxlbmd0aClcbiAgICAgICAgdGhpcy5hcHBlbmQoZWwuY2hpbGROb2Rlc1swXSk7XG59XG5cbi8vIHByZXBlbmRzIGNoaWxkcmVuIG9mIGVsZW1lbnQgaW5zaWRlIHRoaXMgY29tcG9uZW50J3MgZWxlbWVudFxuZnVuY3Rpb24gcHJlcGVuZENoaWxkcmVuKGVsKSB7XG4gICAgd2hpbGUoZWwuY2hpbGROb2Rlcy5sZW5ndGgpXG4gICAgICAgIHRoaXMucHJlcGVuZChlbC5jaGlsZE5vZGVzW2VsLmNoaWxkTm9kZXMubGVuZ3RoIC0gMV0pO1xufVxuXG5mdW5jdGlvbiBpbnNlcnRBZnRlcihlbCkge1xuICAgIHZhciB0aGlzRWwgPSB0aGlzLm93bmVyLmVsXG4gICAgICAgICwgcGFyZW50ID0gdGhpc0VsLnBhcmVudE5vZGU7ICAgIFxuICAgIHBhcmVudC5pbnNlcnRCZWZvcmUoZWwsIHRoaXNFbC5uZXh0U2libGluZyk7XG59XG5cbmZ1bmN0aW9uIGluc2VydEJlZm9yZShlbCkge1xuICAgIHZhciB0aGlzRWwgPSB0aGlzLm93bmVyLmVsXG4gICAgICAgICwgcGFyZW50ID0gdGhpc0VsLnBhcmVudE5vZGU7XG4gICAgcGFyZW50Lmluc2VydEJlZm9yZShlbCwgdGhpc0VsKTtcbn1cblxuXG4vLyBhcHBlbmRzIGNvbXBvbmVudCdzIGVsZW1lbnQgdG8gc2NvcGUgcGFyZW50LiBJZiBpdCB3YXMgYWxyZWR5IGluIERPTSBpdCB3aWxsIGJlIG1vdmVkXG5mdW5jdGlvbiBhcHBlbmRUb1Njb3BlUGFyZW50KCkge1xuICAgIHZhciBwYXJlbnQgPSB0aGlzLm93bmVyLmdldFNjb3BlUGFyZW50KCk7XG4gICAgaWYgKHBhcmVudCkgcGFyZW50LmVsLmFwcGVuZENoaWxkKHRoaXMub3duZXIuZWwpO1xufVxuXG5cbi8qKlxuICogRG9tIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyB0aGUgbGlzdCBvZiBjaGlsZCBlbGVtZW50cyBvZiB0aGUgY29tcG9uZW50IGVsZW1lbnRcbiAqXG4gKiBAcmV0dXJuIHtBcnJheVtFbGVtZW50XX1cbiAqL1xuZnVuY3Rpb24gRG9tJGNoaWxkcmVuKCkge1xuICAgIHJldHVybiBkb21VdGlscy5jaGlsZHJlbih0aGlzLm93bmVyLmVsKTtcbn1cblxuXG52YXIgZmluZERpcmVjdGlvbnMgPSB7XG4gICAgJ3VwJzogJ3ByZXZpb3VzTm9kZScsXG4gICAgJ2Rvd24nOiAnbmV4dE5vZGUnXG59O1xuXG4vLyBGaW5kcyBjb21wb25lbnQgcGFzc2luZyBvcHRpb25hbCBpdGVyYXRvcidzIHRlc3Rcbi8vIGluIHRoZSBzYW1lIHNjb3BlIGFzIHRoZSBjdXJyZW50IGNvbXBvbmVudCAodGhpcylcbi8vIGJ5IHRyYXZlcnNpbmcgRE9NIHRyZWUgdXB3YXJkcyAoZGlyZWN0aW9uID0gXCJ1cFwiKVxuLy8gb3IgZG93bndhcmRzIChkaXJlY3Rpb24gPSBcImRvd25cIilcbmZ1bmN0aW9uIGZpbmQoZGlyZWN0aW9uLCBpdGVyYXRvcikge1xuICAgIGlmICghIGZpbmREaXJlY3Rpb25zLmhhc093blByb3BlcnR5KGRpcmVjdGlvbikpXG4gICAgICAgIHRocm93IG5ldyBEb21GYWNldEVycm9yKCdpbmNvcnJlY3QgZmluZCBkaXJlY3Rpb246ICcgKyBkaXJlY3Rpb24pO1xuXG4gICAgdmFyIGVsID0gdGhpcy5vd25lci5lbFxuICAgICAgICAsIHNjb3BlID0gdGhpcy5vd25lci5zY29wZVxuICAgICAgICAsIHRyZWVXYWxrZXIgPSBkb2N1bWVudC5jcmVhdGVUcmVlV2Fsa2VyKHNjb3BlLl9yb290RWwsIE5vZGVGaWx0ZXIuU0hPV19FTEVNRU5UKTtcblxuICAgIHRyZWVXYWxrZXIuY3VycmVudE5vZGUgPSBlbDtcbiAgICB2YXIgbmV4dE5vZGUgPSB0cmVlV2Fsa2VyW2ZpbmREaXJlY3Rpb25zW2RpcmVjdGlvbl1dKClcbiAgICAgICAgLCBjb21wb25lbnRzTmFtZXMgPSBPYmplY3Qua2V5cyhzY29wZSlcbiAgICAgICAgLCBmb3VuZCA9IGZhbHNlO1xuXG4gICAgd2hpbGUgKG5leHROb2RlKSB7XG4gICAgICAgIHZhciBhdHRyID0gbmV3IEJpbmRBdHRyaWJ1dGUobmV4dE5vZGUpO1xuICAgICAgICBpZiAoYXR0ci5ub2RlKSB7XG4gICAgICAgICAgICBhdHRyLnBhcnNlKCkudmFsaWRhdGUoKTtcbiAgICAgICAgICAgIGlmIChzY29wZS5oYXNPd25Qcm9wZXJ0eShhdHRyLmNvbXBOYW1lKSkge1xuICAgICAgICAgICAgICAgIHZhciBjb21wb25lbnQgPSBzY29wZVthdHRyLmNvbXBOYW1lXTtcbiAgICAgICAgICAgICAgICBpZiAoISBpdGVyYXRvciB8fCBpdGVyYXRvcihjb21wb25lbnQpKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvdW5kID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRyZWVXYWxrZXIuY3VycmVudE5vZGUgPSBuZXh0Tm9kZTtcbiAgICAgICAgbmV4dE5vZGUgPSB0cmVlV2Fsa2VyW2ZpbmREaXJlY3Rpb25zW2RpcmVjdGlvbl1dKCk7XG4gICAgfVxuXG4gICAgaWYgKGZvdW5kKSByZXR1cm4gY29tcG9uZW50O1xufVxuXG5cbi8vIHJldHVybnMgdHJ1ZSBpZiB0aGUgZWxlbWVudCBoYXMgdGV4dCBiZWZvcmUgc2VsZWN0aW9uXG5mdW5jdGlvbiBoYXNUZXh0QmVmb3JlU2VsZWN0aW9uKCkge1xuICAgIHZhciBzZWxlY3Rpb24gPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XG4gICAgaWYgKCEgc2VsZWN0aW9uLmlzQ29sbGFwc2VkKSByZXR1cm4gdHJ1ZTtcbiAgICBcbiAgICB2YXIgdGV4dCA9IHNlbGVjdGlvbi5mb2N1c05vZGUgJiYgc2VsZWN0aW9uLmZvY3VzTm9kZS50ZXh0Q29udGVudDtcbiAgICB2YXIgc3RhcnRQb3MgPSB0ZXh0ICYmIHRleHQuY2hhckF0KDApID09ICcgJyA/IDEgOiAwO1xuICAgIGlmIChzZWxlY3Rpb24uYW5jaG9yT2Zmc2V0ICE9IHN0YXJ0UG9zKSByZXR1cm4gdHJ1ZTtcblxuICAgIC8vIHdhbGsgdXAgdGhlIERPTSB0cmVlIHRvIGNoZWNrIGlmIHRoZXJlIGFyZSB0ZXh0IG5vZGVzIGJlZm9yZSBjdXJzb3JcbiAgICB2YXIgdHJlZVdhbGtlciA9IGRvY3VtZW50LmNyZWF0ZVRyZWVXYWxrZXIodGhpcy5vd25lci5lbCwgTm9kZUZpbHRlci5TSE9XX1RFWFQpO1xuICAgIHRyZWVXYWxrZXIuY3VycmVudE5vZGUgPSBzZWxlY3Rpb24uYW5jaG9yTm9kZTtcbiAgICB2YXIgcHJldk5vZGUgPSB0cmVlV2Fsa2VyLnByZXZpb3VzTm9kZSgpO1xuXG4gICAgdmFyIGlzVGV4dCA9IHByZXZOb2RlID8gIXByZXZOb2RlLm5vZGVWYWx1ZS50cmltKCkgPT0gJycgOiBmYWxzZTtcblxuICAgIHJldHVybiBpc1RleHQ7XG59XG5cblxuZnVuY3Rpb24gaGFzVGV4dEFmdGVyU2VsZWN0aW9uKCkge1xuICAgIHZhciBzZWxlY3Rpb24gPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XG4gICAgaWYgKCEgc2VsZWN0aW9uLmlzQ29sbGFwc2VkKSByZXR1cm4gdHJ1ZTtcblxuICAgIHZhciB0ZXh0ID0gc2VsZWN0aW9uLmZvY3VzTm9kZSAmJiBzZWxlY3Rpb24uZm9jdXNOb2RlLnRleHRDb250ZW50O1xuICAgIHZhciBzdGFydFBvcyA9IHRleHQgJiYgdGV4dC5jaGFyQXQodGV4dC5sZW5ndGgtMSkgPT0gJyAnID8gc2VsZWN0aW9uLmFuY2hvck5vZGUubGVuZ3RoLTEgOiBzZWxlY3Rpb24uYW5jaG9yTm9kZS5sZW5ndGg7XG4gICAgaWYgKHNlbGVjdGlvbi5hbmNob3JPZmZzZXQgPCBzdGFydFBvcykgcmV0dXJuIHRydWU7XG5cbiAgICAvLyB3YWxrIHVwIHRoZSBET00gdHJlZSB0byBjaGVjayBpZiB0aGVyZSBhcmUgdGV4dCBub2RlcyBhZnRlciBjdXJzb3JcbiAgICB2YXIgdHJlZVdhbGtlciA9IGRvY3VtZW50LmNyZWF0ZVRyZWVXYWxrZXIodGhpcy5vd25lci5lbCwgTm9kZUZpbHRlci5TSE9XX1RFWFQpO1xuICAgIHRyZWVXYWxrZXIuY3VycmVudE5vZGUgPSBzZWxlY3Rpb24uYW5jaG9yTm9kZTtcbiAgICB2YXIgbmV4dE5vZGUgPSB0cmVlV2Fsa2VyLm5leHROb2RlKCk7XG4gICAgXG4gICAgLy9UbyBjYXB0dXJlIHdoZW4gdHJlZXdhbGtlciBnaXZlcyB1cyBhbiBlbXB0eSB0ZXh0IG5vZGUgKHVua25vd24gcmVhc29uKVxuICAgIHZhciBpc1RleHQgPSBuZXh0Tm9kZSA/ICFuZXh0Tm9kZS5ub2RlVmFsdWUudHJpbSgpID09ICcnIDogZmFsc2U7XG5cbiAgICByZXR1cm4gaXNUZXh0O1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyA8YSBuYW1lPVwiY29tcG9uZW50cy1mYWNldHMtZHJhZ1wiPjwvYT5cbi8vICMjI2RyYWcgZmFjZXRcblxudmFyIENvbXBvbmVudEZhY2V0ID0gcmVxdWlyZSgnLi4vY19mYWNldCcpXG4gICAgLCBmYWNldHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY2ZfcmVnaXN0cnknKVxuICAgICwgRE9NRXZlbnRzU291cmNlID0gcmVxdWlyZSgnLi4vbXNnX3NyYy9kb21fZXZlbnRzJylcbiAgICAsIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgRHJhZ0Ryb3AgPSByZXF1aXJlKCcuLi8uLi91dGlsL2RyYWdkcm9wJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9sb2dnZXInKTtcblxuXG4vKipcbiAqIGBtaWxvLnJlZ2lzdHJ5LmZhY2V0cy5nZXQoJ0RyYWcnKWBcbiAqIEZhY2V0IGZvciBjb21wb25lbnRzIHRoYXQgY2FuIGJlIGRyYWdnZWRcbiAqIERyYWcgZmFjZXQgc3VwcG9ydHMgdGhlIGZvbGxvd2luZyBjb25maWd1cmF0aW9uIHBhcmFtZXRlcnM6XG4gKlxuICogIC0gbWV0YTogb2JqZWN0IHdpdGggcHJvcGVydGllc1xuICogICAgICAtIHBhcmFtczogb2JqZWN0IG9mIGtleS12YWx1ZSBwYWlycyB0aGF0IHdpbGwgYmUgY29udmVydGVkIGluIHVybC1saWtlIHF1ZXJ5IHN0cmluZyBpbiB0aGUgZW5kIG9mIGRhdGEgdHlwZSBmb3IgbWV0YWRhdGEgZGF0YSB0eXBlIChvciBmdW5jdGlvbiB0aGF0IHJldHVybnMgdGhpcyBvYmplY3QpLiBTZWUgY29uZmlnLmRyYWdEcm9wLmRhdGFUeXBlcy5jb21wb25lbnRNZXRhVGVtcGxhdGVcbiAqICAgICAgICAgIGFsbCB2YWx1ZXMgd2lsbCBjb252ZXJ0ZWQgdG8gbG93ZXJjYXNlIGFzIGRhdGF0eXBlIGNhbm5vdCBzdG9yZSB1cHBlcmNhc2UgbGV0dGVycy5cbiAqICAgICAgLSBkYXRhOiBkYXRhIHRoYXQgd2lsbCBiZSBzdG9yZWQgaW4gdGhlIGFib3ZlIG1ldGEgZGF0YSB0eXBlIChvciBmdW5jdGlvbilcbiAqICAtIGFsbG93ZWRFZmZlY3RzOiBzdHJpbmcgKG9yIGZ1bmN0aW9uKSBhcyBzcGVjaWZpZWQgaGVyZTogaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9EcmFnRHJvcC9EcmFnX09wZXJhdGlvbnMjZHJhZ3N0YXJ0XG4gKiAgLSBkYXRhVHlwZXM6IG1hcCBvZiBhZGRpdGlvbmFsIGRhdGEgdHlwZXMgdGhlIGNvbXBvbmVudCB3aWxsIHN1cHBseSB0byBkYXRhIHRyYW5zZmVyIG9iamVjdCwga2V5IGlzIGRhdGEgdHlwZSwgdmFsdWUgaXMgYSBmdW5jdGlvbiB0aGF0IHJldHVybnMgaXQsIGNvbXBvbmVudCB3aWxsIGJlIHBhc3NlZCBhcyB0aGUgY29udGV4dCB0byB0aGlzIGZ1bmN0aW9uXG4gKlxuICogSWYgZnVuY3Rpb24gaXMgc3BlY2lmaWVkIGluIGFueSBwYXJhbWV0ZXIgaXQgd2lsbCBiZSBjYWxsZWQgd2l0aCB0aGUgY29tcG9uZW50IGFzIHRoZSBjb250ZXh0XG4gKi9cbnZhciBEcmFnID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ0RyYWcnKTtcblxuXy5leHRlbmRQcm90byhEcmFnLCB7XG4gICAgaW5pdDogRHJhZyRpbml0LFxuICAgIHN0YXJ0OiBEcmFnJHN0YXJ0LFxuICAgIHNldEhhbmRsZTogRHJhZyRzZXRIYW5kbGVcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoRHJhZyk7XG5cbm1vZHVsZS5leHBvcnRzID0gRHJhZztcblxuXG5mdW5jdGlvbiBEcmFnJGluaXQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTsgICBcblxuICAgIHRoaXMuX2NyZWF0ZU1lc3NhZ2VTb3VyY2VXaXRoQVBJKERPTUV2ZW50c1NvdXJjZSk7XG4gICAgdGhpcy5fZHJhZ0RhdGEgPSB7fTtcblxuICAgIHZhciBkYXRhVHlwZUluZm8gPSB0aGlzLmNvbmZpZy5fZGF0YVR5cGVJbmZvIHx8ICcnO1xuICAgIHRoaXMuX2RhdGFUeXBlSW5mbyA9IHR5cGVvZiBkYXRhVHlwZUluZm8gPT0gJ2Z1bmN0aW9uJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gZGF0YVR5cGVJbmZvXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgOiBmdW5jdGlvbigpIHsgcmV0dXJuIGRhdGFUeXBlSW5mbzsgfTtcbn1cblxuXG4vKipcbiAqIERyYWcgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTZXRzIHRoZSBkcmFnIGhhbmRsZSBlbGVtZW50IG9mIGNvbXBvbmVudC4gVGhpcyBlbGVtZW50IGhhcyB0byBiZSBkcmFnZ2VkIGZvciB0aGUgY29tcG9uZW50IHRvIGJlIGRyYWdnZWQuXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBoYW5kbGVFbFxuICovXG5mdW5jdGlvbiBEcmFnJHNldEhhbmRsZShoYW5kbGVFbCkge1xuICAgIGlmICghIHRoaXMub3duZXIuZWwuY29udGFpbnMoaGFuZGxlRWwpKVxuICAgICAgICByZXR1cm4gbG9nZ2VyLndhcm4oJ2RyYWcgaGFuZGxlIHNob3VsZCBiZSBpbnNpZGUgZWxlbWVudCB0byBiZSBkcmFnZ2VkJylcbiAgICB0aGlzLl9kcmFnSGFuZGxlID0gaGFuZGxlRWw7XG59XG5cblxuZnVuY3Rpb24gRHJhZyRzdGFydCgpIHtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuc3RhcnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICBfYWRkRHJhZ0F0dHJpYnV0ZS5jYWxsKHRoaXMpO1xuXG4gICAgdGhpcy5vbk1lc3NhZ2VzKHtcbiAgICAgICAgJ21vdXNlZG93bic6IG9uTW91c2VEb3duLFxuICAgICAgICAnbW91c2VlbnRlciBtb3VzZWxlYXZlIG1vdXNlbW92ZSc6IG9uTW91c2VNb3ZlbWVudCxcbiAgICAgICAgJ2RyYWdzdGFydCc6IG9uRHJhZ1N0YXJ0LFxuICAgICAgICAnZHJhZyc6IG9uRHJhZ2dpbmcsXG4gICAgICAgICdkcmFnZW5kJzogb25EcmFnRW5kXG4gICAgfSk7XG5cbiAgICB0aGlzLm93bmVyLm9uTWVzc2FnZXMoe1xuICAgICAgICAnZ2V0c3RhdGVzdGFydGVkJzpcbiAgICAgICAgICAgIHsgc3Vic2NyaWJlcjogX3JlbW92ZURyYWdBdHRyaWJ1dGUsIGNvbnRleHQ6IHRoaXMgfSxcbiAgICAgICAgJ2dldHN0YXRlY29tcGxldGVkJzpcbiAgICAgICAgICAgIHsgc3Vic2NyaWJlcjogX2FkZERyYWdBdHRyaWJ1dGUsIGNvbnRleHQ6IHRoaXMgfVxuICAgIH0pO1xufVxuXG5cbi8qKlxuICogQWRkcyBkcmFnZ2FibGUgYXR0cmlidXRlIHRvIGNvbXBvbmVudCdzIGVsZW1lbnRcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBfYWRkRHJhZ0F0dHJpYnV0ZSgpIHtcbiAgICBpZiAodGhpcy5vd25lci5lbClcbiAgICAgICAgdGhpcy5vd25lci5lbC5zZXRBdHRyaWJ1dGUoJ2RyYWdnYWJsZScsIHRydWUpO1xufVxuXG5cbmZ1bmN0aW9uIF9yZW1vdmVEcmFnQXR0cmlidXRlKCkge1xuICAgIGlmICh0aGlzLm93bmVyLmVsKVxuICAgICAgICB0aGlzLm93bmVyLmVsLnJlbW92ZUF0dHJpYnV0ZSgnZHJhZ2dhYmxlJyk7XG59XG5cblxuZnVuY3Rpb24gb25Nb3VzZURvd24oZXZlbnRUeXBlLCBldmVudCkge1xuICAgIHRoaXMuX19tb3VzZURvd25UYXJnZXQgPSBldmVudC50YXJnZXQ7XG4gICAgaWYgKHRhcmdldEluRHJhZ0hhbmRsZS5jYWxsKHRoaXMpKSB7XG4gICAgICAgIHdpbmRvdy5nZXRTZWxlY3Rpb24oKS5lbXB0eSgpO1xuICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gb25Nb3VzZU1vdmVtZW50KGV2ZW50VHlwZSwgZXZlbnQpIHtcbiAgICB2YXIgc2hvdWxkQmVEcmFnZ2FibGUgPSB0YXJnZXRJbkRyYWdIYW5kbGUuY2FsbCh0aGlzKTtcbiAgICB0aGlzLm93bmVyLmVsLnNldEF0dHJpYnV0ZSgnZHJhZ2dhYmxlJywgc2hvdWxkQmVEcmFnZ2FibGUpO1xuICAgIGlmIChkb2N1bWVudC5ib2R5LmdldEF0dHJpYnV0ZSgnZGF0YS1kcmFnRW5hYmxlRXZlbnQnKSAhPSAnZmFsc2UnKVxuICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbn1cblxuXG5mdW5jdGlvbiBvbkRyYWdTdGFydChldmVudFR5cGUsIGV2ZW50KSB7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgaWYgKHRoaXMuY29uZmlnLm9mZiB8fCAhIHRhcmdldEluRHJhZ0hhbmRsZS5jYWxsKHRoaXMpKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgb3duZXIgPSB0aGlzLm93bmVyO1xuICAgIHZhciBkdCA9IG5ldyBEcmFnRHJvcChldmVudCk7XG5cbiAgICB0aGlzLl9kcmFnRGF0YSA9IGR0LnNldENvbXBvbmVudFN0YXRlKG93bmVyKTtcbiAgICBzZXRNZXRhLmNhbGwodGhpcyk7XG4gICAgc2V0QWRkaXRpb25hbERhdGFUeXBlcy5jYWxsKHRoaXMpO1xuICAgIF9zZXRBbGxvd2VkRWZmZWN0cy5jYWxsKHRoaXMsIGR0KTtcblxuICAgIERyYWdEcm9wLnNlcnZpY2UucG9zdE1lc3NhZ2VTeW5jKCdkcmFnZHJvcHN0YXJ0ZWQnLCB7XG4gICAgICAgIGV2ZW50VHlwZTogJ2RyYWdzdGFydCcsXG4gICAgICAgIGRyYWdEcm9wOiBkdCxcbiAgICAgICAgZHJhZ0ZhY2V0OiB0aGlzXG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiBzZXRNZXRhKCkge1xuICAgICAgICB2YXIgbWV0YUNvbmZpZyA9IHRoaXMuY29uZmlnLm1ldGFcbiAgICAgICAgICAgICwgcGFyYW1zQ29uZmlnID0gbWV0YUNvbmZpZyAmJiBtZXRhQ29uZmlnLnBhcmFtc1xuICAgICAgICAgICAgLCBtZXRhRGF0YUNvbmZpZyA9IG1ldGFDb25maWcgJiYgbWV0YUNvbmZpZy5kYXRhO1xuXG4gICAgICAgIHZhciBwYXJhbXMgPSBfLnJlc3VsdChwYXJhbXNDb25maWcsIG93bmVyKVxuICAgICAgICAgICAgLCBkYXRhID0gXy5yZXN1bHQobWV0YURhdGFDb25maWcsIG93bmVyKTtcblxuICAgICAgICB0aGlzLl9kcmFnTWV0YURhdGFUeXBlID0gZHQuc2V0Q29tcG9uZW50TWV0YShvd25lciwgcGFyYW1zLCBkYXRhKTtcbiAgICAgICAgdGhpcy5fZHJhZ01ldGFEYXRhID0gZGF0YTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzZXRBZGRpdGlvbmFsRGF0YVR5cGVzKCkge1xuICAgICAgICBpZiAodGhpcy5jb25maWcuZGF0YVR5cGVzKSB7XG4gICAgICAgICAgICB0aGlzLl9kYXRhVHlwZXNEYXRhID0gXy5tYXBLZXlzKHRoaXMuY29uZmlnLmRhdGFUeXBlcywgZnVuY3Rpb24gKGdldERhdGFGdW5jLCBkYXRhVHlwZSkge1xuICAgICAgICAgICAgICAgIHZhciBkYXRhID0gZ2V0RGF0YUZ1bmMuY2FsbCh0aGlzLm93bmVyLCBkYXRhVHlwZSk7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBkYXRhID09ICdvYmplY3QnKSBkYXRhID0gSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGEpIGR0LnNldERhdGEoZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICAgICAgICAgIHJldHVybiBkYXRhO1xuICAgICAgICAgICAgfSwgdGhpcyk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cblxuZnVuY3Rpb24gb25EcmFnZ2luZyhldmVudFR5cGUsIGV2ZW50KSB7XG4gICAgaWYgKF9kcmFnSXNEaXNhYmxlZC5jYWxsKHRoaXMsIGV2ZW50KSkgcmV0dXJuO1xuXG4gICAgdmFyIGR0ID0gbmV3IERyYWdEcm9wKGV2ZW50KTtcbiAgICBkdC5zZXRDb21wb25lbnRTdGF0ZSh0aGlzLm93bmVyLCB0aGlzLl9kcmFnRGF0YSk7XG4gICAgZHQuc2V0RGF0YSh0aGlzLl9kcmFnTWV0YURhdGFUeXBlLCB0aGlzLl9kcmFnTWV0YURhdGEpO1xuICAgIGlmICh0aGlzLl9kYXRhVHlwZXNEYXRhKSB7XG4gICAgICAgIF8uZWFjaEtleSh0aGlzLl9kYXRhVHlwZXNEYXRhLCBmdW5jdGlvbihkYXRhLCBkYXRhVHlwZSkge1xuICAgICAgICAgICAgaWYgKGRhdGEpIGR0LnNldERhdGEoZGF0YVR5cGUsIGRhdGEpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBfc2V0QWxsb3dlZEVmZmVjdHMuY2FsbCh0aGlzLCBkdCk7XG59XG5cblxuZnVuY3Rpb24gb25EcmFnRW5kKGV2ZW50VHlwZSwgZXZlbnQpIHtcbiAgICBpZiAoX2RyYWdJc0Rpc2FibGVkLmNhbGwodGhpcywgZXZlbnQpKSByZXR1cm47XG5cbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB2YXIgZHQgPSBuZXcgRHJhZ0Ryb3AoZXZlbnQpO1xuICAgIERyYWdEcm9wLnNlcnZpY2UucG9zdE1lc3NhZ2VTeW5jKCdjb21wbGV0ZWRyYWdkcm9wJywge1xuICAgICAgICBldmVudFR5cGU6ICdkcmFnZW5kJyxcbiAgICAgICAgZHJhZ0Ryb3A6IGR0LFxuICAgICAgICBkcmFnRmFjZXQ6IHRoaXNcbiAgICB9KTtcbn1cblxuXG5mdW5jdGlvbiBfc2V0QWxsb3dlZEVmZmVjdHMoRHJhZ0Ryb3ApIHtcbiAgICB2YXIgZWZmZWN0cyA9IF8ucmVzdWx0KHRoaXMuY29uZmlnLmFsbG93ZWRFZmZlY3RzLCB0aGlzLm93bmVyKTtcbiAgICBEcmFnRHJvcC5zZXRBbGxvd2VkRWZmZWN0cyhlZmZlY3RzKTtcbn1cblxuXG5mdW5jdGlvbiB0YXJnZXRJbkRyYWdIYW5kbGUoKSB7XG4gICAgcmV0dXJuICEgdGhpcy5fZHJhZ0hhbmRsZSB8fCB0aGlzLl9kcmFnSGFuZGxlLmNvbnRhaW5zKHRoaXMuX19tb3VzZURvd25UYXJnZXQpO1xufVxuXG5cbmZ1bmN0aW9uIF9kcmFnSXNEaXNhYmxlZChldmVudCkge1xuICAgIGlmICh0aGlzLmNvbmZpZy5vZmYpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gPGEgbmFtZT1cImNvbXBvbmVudHMtZmFjZXRzLWRyb3BcIj48L2E+XG4vLyAjIyNkcm9wIGZhY2V0XG5cbnZhciBDb21wb25lbnRGYWNldCA9IHJlcXVpcmUoJy4uL2NfZmFjZXQnKVxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NmX3JlZ2lzdHJ5JylcbiAgICAsIERPTUV2ZW50c1NvdXJjZSA9IHJlcXVpcmUoJy4uL21zZ19zcmMvZG9tX2V2ZW50cycpXG4gICAgLCBEcm9wTXNnQVBJID0gcmVxdWlyZSgnLi4vbXNnX2FwaS9kcm9wJylcbiAgICAsIERyYWdEcm9wID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9kcmFnZHJvcCcpXG4gICAgLCBEcm9wRXJyb3IgPSByZXF1aXJlKCcuLi8uLi91dGlsL2Vycm9yJykuRHJvcFxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBfaGFuZGxlRHJvcERlcGVuZGVuY3k7XG5cbi8qKlxuICogYG1pbG8ucmVnaXN0cnkuZmFjZXRzLmdldCgnRHJvcCcpYFxuICogRmFjZXQgZm9yIGNvbXBvbmVudHMgdGhhdCBjYW4gYWNjZXB0IGRyb3BzXG4gKiBEcm9wIGZhY2V0IHN1cHBvcnRzIHRoZSBmb2xsb3dpbmcgY29uZmlndXJhdGlvbiBwYXJhbWV0ZXJzOlxuICpcbiAqICAtIGFsbG93IC0gYW4gb2JqZWN0IHRoYXQgd2lsbCBkZWZpbmUgYWxsb3dlZCBkYXRhIHR5cGVzIGR1cmluZyBkcmFnIChgZHJhZ2VudGVyYCBhbmQgYGRyYWdvdmVyYCBldmVudHMpIHdpdGggdGhlc2UgcHJvcGVydGllczpcbiAqICAgICAgLSBjb21wb25lbnRzOiBgdHJ1ZWAgYnkgZGVmYXVsdCAoYWxsIGNvbXBvbmVudHMgd2lsbCBiZSBhY2NlcHRlZClcbiAqICAgICAgICAgICAgICAgICAgICAgICAgT1Igc3RyaW5nIHdpdGggYWxsb3dlZCBjb21wb25lbnQgY2xhc3NcbiAqICAgICAgICAgICAgICAgICAgICAgICAgT1IgbGlzdCBvZiBhbGxvd2VkIGNvbXBvbmVudHMgY2xhc3NlcyAoc3RyaW5ncylcbiAqICAgICAgICAgICAgICAgICAgICAgICAgT1IgbWFwIHdpdGggYWxsb3dlZCBjbGFzc2VzIGluIGtleXMgYW5kIGB0cnVlYC90ZXN0IGZ1bmN0aW9ucyBpbiB2YWx1ZXNcbiAqICAgICAgICAgICAgICAgICAgICAgICAgT1IgdGVzdCBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgcGFzc2VkIG9iamVjdCBkZWZpbmVkIGJlbG93XG4gKiAgICAgICAgICAgICAgICAgICAgICAgIE9SIGBmYWxzZWAgdG8gTk9UIGFjY2VwdCBjb21wb25lbnRzXG4gKiAgICAgIC0gZGF0YVR5cGVzOiAgYGZhbHNlYCBieSBkZWZhdWx0IChubyBvdGhlciBkYXRhIHR5cGVzIHdpbGwgYmUgYWNjZXB0ZWQpXG4gKiAgICAgICAgICAgICAgICAgICAgICAgIE9SIHN0cmluZyB3aXRoIGFsbG93ZWQgZGF0YSB0eXBlXG4gKiAgICAgICAgICAgICAgICAgICAgICAgIE9SIGxpc3Qgb2YgYWRkaXRpb25hbCBkYXRhIHR5cGVzIHRoYXQgYSBkcm9wIHRhcmdldCB3b3VsZCBhY2NlcHRcbiAqICAgICAgICAgICAgICAgICAgICAgICAgT1IgdGVzdCBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgcGFzc2VkIERyYWdEcm9wIG9iamVjdFxuICogICAgICAgICAgICAgICAgICAgICAgICBPUiBgdHJ1ZWAgdG8gYWNjZXB0IGFsbCBkYXRhIHR5cGVzXG4gKiAgICAgIC0gY2hlY2tQYXJlbnQ6IGBmYWxzZWAgYnkgZGVmYXVsdFxuICogICAgICAgICAgICAgICAgICAgICAgICBPUiBgdHJ1ZWAgd2lsbCBjYWxsIHBhcmVudCBjb21wb25lbnQgZHJvcCBhbGxvdyB0byBjaGVjayBpZiBwYXJlbnQgY29tcG9uZW50IHdpbGwgYWNjZXB0IHRoZSBjb21wb25lbnRcbiAqICAgICAgSWYgdGVzdCBmdW5jdGlvbnMgYXJlIHVzZWQsIHRoZXkgc2hvdWxkIHJldHVybiBib29sZWFuLiBFYWNoIHRlc3QgZnVuY3Rpb24gY2FuIGFsc28gc2V0IGRyb3AgZWZmZWN0IGFzIGRlZmluZWQgaGVyZTpcbiAqICAgICAgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0RhdGFUcmFuc2ZlciNkcm9wRWZmZWN0LjI4LjI5XG4gKiAgICAgIFNldHRpbmcgZHJvcCBlZmZlY3QgdGhhdCBpcyBub3QgYWxsb3dlZCBieSBkcmFnZ2VkIG9iamVjdCB3aWxsIHByZXZlbnQgZHJvcC5cbiAqICAgICAgVGVzdCBmdW5jdGlvbnMgZm9yIGNvbXBvbmVudHMgd2lsbCBiZSBwYXNzZWQgdGhlIG93bmVyIG9mIERyb3AgZmFjZXQgYXMgY29udGV4dCwgdGhlIG9iamVjdCB3aXRoIHRoZSBmb2xsb3dpbmcgcG9zc2libGUgcHJvcGVydGllcyBhcyB0aGUgZmlyc3QgcGFyYW1ldGVyOlxuICogICAgICAgICAgY29tcENsYXNzIC0gbmFtZSBvZiBjb21wb25lbnQgY2xhc3MgYXMgc3RvcmVkIGluIHJlZ2lzdHJ5XG4gKiAgICAgICAgICBjb21wTmFtZSAtIG5hbWUgb2YgY29tcG9uZW50IChhbGwgbG93ZXJjYXNlKVxuICogICAgICAgICAgcGFyYW1zIC0gcGFyYW1ldGVycyBhcyBlbmNvZGVkIGluIGRhdGFUeXBlLCBwYXNzZWQgdG8gYG1pbG8udXRpbC5kcmFnRHJvcC5zZXRDb21wb25lbnRNZXRhYCBieSBEcmFnIGZhY2V0XG4gKiAgICAgICAgICBtZXRhRGF0YVR5cGUgLSBkYXRhIHR5cGUgb2YgdGhlIGRhdGEgdGhhdCBoYXMgY29tcENsYXNzLCBjb21wTmFtZSBhbmQgcGFyYW1zIGVuY29kZWRcbiAqXG4gKiAgICAgIC4uLiBhbmQgRHJhZ0Ryb3AgaW5zdGFuY2UgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXJcbiAqXG4gKiAgICAgIFRlc3QgZnVuY3Rpb24gZm9yIG90aGVyIGRhdGEgdHlwZXMgd2lsbCBiZSBwYXNzZWQgdGhlIG93bmVyIG9mIERyb3AgZmFjZXQgYXMgY29udGV4dCBhbmQgRHJhZ0Ryb3AgaW5zdGFuY2UgYXMgdGhlIGZpcnN0IHBhcmFtZXRlclxuICpcbiAqICMjIyNFdmVudHMjIyMjXG4gKlxuICogSW4gYWRkaXRpb24gdG8gY29uZmlndXJpbmcgYWxsb3dlZCBjb21wb25lbnRzIGFuZCBkYXRhIHR5cGVzLCBjb21wb25lbnRzIGNsYXNzZXMgc2hvdWxkIHN1YnNjcmliZSB0byBldmVudHMuXG4gKiBBdCB0aGUgdmVyeSBsZWFzdCwgdGhleSBzaG91bGQgc3Vic2NyaWJlIHRvIGBkcm9wYCBldmVudC5cbiAqXG4gKiBEcm9wIGZhY2V0IGVtaXRzIGRyYWdpbi9kcmFnb3V0IG1lc3NhZ2VzIHRoYXQgYXJlIGVtaXR0ZWQgd2hlbmV2ZXIgYWN0dWFsIGNvbXBvbmVudCBlbGVtZW50IGlzIGVudGVyZWQgb3IgbGVmdFxuICogKHdoaWNoIGlzIGRpZmZlcmVudCBmcm9tIGRyYWdlbnRlciBhbmQgZHJhZ2xlYXZlIG1lc3NhZ2VzIHRoYXQgYXJlIGVtaXR0ZWQgd2hlbmV2ZXIgYW55IGNoaWxkIGVsZW1lbnQgaXMgZW50ZXJlZCBvciBsZWZ0LCBhcyBsb25nIGFzIGV2ZW50IGJ1YmJsZXMgdXApXG4gKiBJZiBjaGlsZCBjb21wb25lbnQgaGFzIGRyb3AgZmFjZXQgYXR0YWNoZWQsIGRyYWdvdXQgd2lsbCBiZSBlbWl0dGVkIG9uIHRoZSBjdXJyZW50IGNvbXBvbmVudCB3aGVuIHRoZSBjaGlsZCBpcyBlbnRlcmVkLlxuICpcbiAqIFlvdSBjYW4gc2VlIHRoZSBkZW1vbnN0cmF0aW9uIG9mIHdoZW4gbWVzc2FnZXMgYXJlIGVtaXR0ZWQgW2hlcmVdKGh0dHA6Ly9qc2Jpbi5jb20vYnVxb3YvNilcbiAqIFxuICovXG52YXIgRHJvcCA9IF8uY3JlYXRlU3ViY2xhc3MoQ29tcG9uZW50RmFjZXQsICdEcm9wJyk7XG5cblxuXy5leHRlbmRQcm90byhEcm9wLCB7XG4gICAgaW5pdDogRHJvcCRpbml0LFxuICAgIHN0YXJ0OiBEcm9wJHN0YXJ0XG4gICAgLy8gX3JlYXR0YWNoOiBfcmVhdHRhY2hFdmVudHNPbkVsZW1lbnRDaGFuZ2Vcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoRHJvcCk7XG5cbm1vZHVsZS5leHBvcnRzID0gRHJvcDtcblxuXG5mdW5jdGlvbiBEcm9wJGluaXQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB0aGlzLl9jcmVhdGVNZXNzYWdlU291cmNlV2l0aEFQSShET01FdmVudHNTb3VyY2UsIG5ldyBEcm9wTXNnQVBJKTtcbn1cblxuXG5mdW5jdGlvbiBEcm9wJHN0YXJ0KCkge1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5zdGFydC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMub3duZXIuZWwuY2xhc3NMaXN0LmFkZCgnY2MtbW9kdWxlLXJlbGF0aXZlJyk7XG4gICAgdGhpcy5vbk1lc3NhZ2VzKHtcbiAgICAgICAgJ2RyYWdlbnRlciBkcmFnb3Zlcic6IG9uRHJhZ2dpbmcsXG4gICAgICAgICdkcm9wJzogb25Ecm9wLFxuICAgICAgICAnZHJhZ2VudGVyIGRyYWdvdmVyIGRyYWdsZWF2ZSBkcm9wIGRyYWdpbiBkcmFnb3V0JzogcG9zdFRvU2VydmljZVxuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIG9uRHJhZ2dpbmcoZXZlbnRUeXBlLCBldmVudCkge1xuICAgIHZhciBkdCA9IG5ldyBEcmFnRHJvcChldmVudCk7XG5cbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgaWYgKCEgX2hhbmRsZURyb3BEZXBlbmRlbmN5LmNhbGwodGhpcywgZHQpKVxuICAgICAgICBkdC5zZXREcm9wRWZmZWN0KCdub25lJyk7XG59XG5cblxuZnVuY3Rpb24gb25Ecm9wKGV2ZW50VHlwZSwgZXZlbnQpIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB2YXIgZHQgPSBuZXcgRHJhZ0Ryb3AoZXZlbnQpO1xuICAgIERyYWdEcm9wLnNlcnZpY2UucG9zdE1lc3NhZ2VTeW5jKCdkcmFnZHJvcGNvbXBsZXRlZCcsIHtcbiAgICAgICAgZXZlbnRUeXBlOiAnZHJvcCcsXG4gICAgICAgIGRyYWdEcm9wOiBkdCxcbiAgICAgICAgZHJvcEZhY2V0OiB0aGlzLFxuICAgICAgICBjb21wb25lbnQ6IHRoaXMub3duZXJcbiAgICB9KTtcbn1cblxuXG5mdW5jdGlvbiBwb3N0VG9TZXJ2aWNlKGV2ZW50VHlwZSwgZXZlbnQpIHtcbiAgICBEcmFnRHJvcC5zZXJ2aWNlLnBvc3RNZXNzYWdlU3luYyhldmVudFR5cGUsIHtcbiAgICAgICAgZXZlbnQ6IGV2ZW50LFxuICAgICAgICBkcm9wRmFjZXQ6IHRoaXMsXG4gICAgICAgIGNvbXBvbmVudDogdGhpcy5vd25lclxuICAgIH0pO1xufVxuXG5cbl9oYW5kbGVEcm9wRGVwZW5kZW5jeSA9IF8udGhyb3R0bGUoX2hhbmRsZURyb3BEZXBlbmRlbmN5Tm90aHJvdHRsZSwgNTApO1xuZnVuY3Rpb24gX2hhbmRsZURyb3BEZXBlbmRlbmN5Tm90aHJvdHRsZShkdCwgb3JpZ2luYWxEcm9wQ29tcG9uZW50KSB7XG4gICAgdmFyIGFsbG93ID0gdGhpcy5jb25maWcuYWxsb3dcbiAgICAgICAgLCBwYXJlbnRBbGxvd2VkID0gdHJ1ZTtcblxuICAgIG9yaWdpbmFsRHJvcENvbXBvbmVudCA9IG9yaWdpbmFsRHJvcENvbXBvbmVudCB8fCB0aGlzLm93bmVyO1xuXG4gICAgaWYgKGFsbG93ICYmIGFsbG93LmNoZWNrUGFyZW50KSB7XG4gICAgICAgIHZhciBwYXJlbnQgPSB0aGlzLm93bmVyLmdldFNjb3BlUGFyZW50KCdEcm9wJyk7XG4gICAgICAgIGlmIChwYXJlbnQpXG4gICAgICAgICAgICBwYXJlbnRBbGxvd2VkID0gX2hhbmRsZURyb3BEZXBlbmRlbmN5Tm90aHJvdHRsZS5jYWxsKHBhcmVudC5kcm9wLCBkdCwgb3JpZ2luYWxEcm9wQ29tcG9uZW50KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcGFyZW50QWxsb3dlZCAmJiBfaXNEcm9wQWxsb3dlZC5jYWxsKHRoaXMsIGR0LCBvcmlnaW5hbERyb3BDb21wb25lbnQpO1xufVxuXG5cbi8qKlxuICogQ2hlY2tzIGlmIGRyb3AgaXMgYWxsb3dlZCBiYXNlZCBvbiBmYWNldCBjb25maWd1cmF0aW9uIChzZWUgYWJvdmUpXG4gKiBcbiAqIEBwYXJhbSB7RHJhZ0Ryb3B9IGR0XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBfaXNEcm9wQWxsb3dlZChkdCwgb3JpZ2luYWxEcm9wQ29tcG9uZW50KSB7XG4gICAgdmFyIGFsbG93ID0gdGhpcy5jb25maWcuYWxsb3c7XG5cbiAgICBpZiAoZHQuaXNDb21wb25lbnQoKSkge1xuICAgICAgICB2YXIgYWxsb3dDb21wcyA9IGFsbG93ICYmIGFsbG93LmNvbXBvbmVudHNcbiAgICAgICAgICAgICwgbWV0YSA9IGR0LmdldENvbXBvbmVudE1ldGEoKTtcblxuICAgICAgICBzd2l0Y2ggKHR5cGVvZiBhbGxvd0NvbXBzKSB7XG4gICAgICAgICAgICBjYXNlICd1bmRlZmluZWQnOlxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgY2FzZSAnYm9vbGVhbic6XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFsbG93Q29tcHM7XG4gICAgICAgICAgICAvLyBjb21wb25lbnQgY2xhc3NcbiAgICAgICAgICAgIGNhc2UgJ3N0cmluZyc6XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1ldGEgJiYgbWV0YS5jb21wQ2xhc3MgPT0gYWxsb3dDb21wcztcbiAgICAgICAgICAgIC8vIHRlc3QgZnVuY3Rpb25cbiAgICAgICAgICAgIGNhc2UgJ2Z1bmN0aW9uJzpcbiAgICAgICAgICAgICAgICByZXR1cm4gYWxsb3dDb21wcy5jYWxsKHRoaXMub3duZXIsIG1ldGEsIGR0LCBvcmlnaW5hbERyb3BDb21wb25lbnQpO1xuICAgICAgICAgICAgY2FzZSAnb2JqZWN0JzpcbiAgICAgICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShhbGxvd0NvbXBzKSlcbiAgICAgICAgICAgICAgICAgICAgLy8gbGlzdCBvZiBhbGxvd2VkIGNsYXNzZXNcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGFsbG93Q29tcHMuaW5kZXhPZihtZXRhICYmIG1ldGEuY29tcENsYXNzKSA+PSAwO1xuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBtYXAgb2YgY2xhc3M6IGJvb2xlYW58dGVzdCBmdW5jdGlvblxuICAgICAgICAgICAgICAgICAgICB2YXIgdGVzdCA9IGFsbG93Q29tcHNbbWV0YSAmJiBtZXRhLmNvbXBDbGFzc107XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAhISBfLnJlc3VsdCh0ZXN0LCB0aGlzLm93bmVyLCBtZXRhLCBkdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRHJvcEVycm9yKCdJbmNvcnJlY3QgYWxsb3dlZCBjb21wb25lbnRzIGluIGNvbmZpZycpO1xuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIGRhdGFUeXBlcyA9IGFsbG93ICYmIGFsbG93LmRhdGFUeXBlc1xuICAgICAgICBzd2l0Y2ggKHR5cGVvZiBkYXRhVHlwZXMpIHtcbiAgICAgICAgICAgIGNhc2UgJ3VuZGVmaW5lZCc6XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgY2FzZSAnc3RyaW5nJzpcbiAgICAgICAgICAgICAgICByZXR1cm4gZHQudHlwZXMuaW5kZXhPZihkYXRhVHlwZXMpID49IDA7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUT0RPIHRlc3QgZm9yIG90aGVyIGRhdGEgdHlwZXNcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudEZhY2V0ID0gcmVxdWlyZSgnLi4vY19mYWNldCcpXG4gICAgLCBmYWNldHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY2ZfcmVnaXN0cnknKVxuICAgICwgTWVzc2VuZ2VyID0gcmVxdWlyZSgnLi4vLi4vbWVzc2VuZ2VyJylcbiAgICAsIERPTUV2ZW50c1NvdXJjZSA9IHJlcXVpcmUoJy4uL21zZ19zcmMvZG9tX2V2ZW50cycpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cblxuLyoqXG4gKiBgbWlsby5yZWdpc3RyeS5mYWNldHMuZ2V0KCdFdmVudHMnKWBcbiAqIENvbXBvbmVudCBmYWNldCB0aGF0IG1hbmFnZXMgc3Vic2NyaXB0aW9ucyB0byBET00gZXZlbnRzIHVzaW5nIFtNZXNzZW5nZXJdKC4uLy4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sKSB3aXRoIFtET01FdmVudHNTb3VyY2VdKC4uL21zZ19zcmMvZG9tX2V2ZW50cy5qcy5odG1sKS5cbiAqIEFsbCBwdWJsaWMgbWV0aG9kcyBvZiBNZXNzZW5nZXIgYW5kIGB0cmlnZ2VyYCBtZXRob2Qgb2YgW0RPTUV2ZW50c1NvdXJjZV0oLi4vbXNnX3NyYy9kb21fZXZlbnRzLmpzLmh0bWwpIGFyZSBwcm94aWVkIGRpcmVjdGx5IHRvIHRoaXMgZmFjZXQuXG4gKiBGb3IgZXhhbXBsZSwgdG8gc3Vic2NyaWJlIHRvIGBjbGlja2AgZXZlbnQgdXNlOlxuICogYGBgXG4gKiBjb21wb25lbnQuZnJhbWUub24oJ2NsaWNrJywgZnVuY3Rpb24oKSB7XG4gKiAgICAgLy8gLi4uXG4gKiB9KTtcbiAqIGBgYFxuICogU2VlIFtNZXNzZW5nZXJdKC4uLy4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sKVxuICovXG52YXIgRXZlbnRzID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ0V2ZW50cycpO1xuXG5cbi8qKlxuICogIyMjI0V2ZW50cyBmYWNldCBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2luaXRdKCNFdmVudHMkaW5pdCkgLSBjYWxsZWQgYnkgY29uc3RydWN0b3IgYXV0b21hdGljYWxseVxuICovXG5fLmV4dGVuZFByb3RvKEV2ZW50cywge1xuICAgIGluaXQ6IEV2ZW50cyRpbml0XG4gICAgLy8gX3JlYXR0YWNoOiBfcmVhdHRhY2hFdmVudHNPbkVsZW1lbnRDaGFuZ2Vcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoRXZlbnRzKTtcblxubW9kdWxlLmV4cG9ydHMgPSBFdmVudHM7XG5cblxuLyoqXG4gKiBFeHBvc2UgRE9NRXZlbnRzU291cmNlIHRyaWdnZXIgbWV0aG9kIG9uIEV2ZW50cyBwcm90b3R5cGVcbiAqL1xudmFyIE1TR19TT1VSQ0VfS0VZID0gJ19kb21FdmVudHNTb3VyY2UnXG5ET01FdmVudHNTb3VyY2UudXNlV2l0aChFdmVudHMsIE1TR19TT1VSQ0VfS0VZLCBbJ3RyaWdnZXInXSk7XG5cblxuLyoqXG4gKiBFdmVudHMgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsemVzIGZhY2V0LCBjb25uZWN0cyBET01FdmVudHNTb3VyY2UgdG8gZmFjZXQncyBtZXNzZW5nZXJcbiAqL1xuZnVuY3Rpb24gRXZlbnRzJGluaXQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIHZhciBkb21FdmVudHNTb3VyY2UgPSBuZXcgRE9NRXZlbnRzU291cmNlKHRoaXMsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB0aGlzLm93bmVyKTtcbiAgICB0aGlzLl9zZXRNZXNzYWdlU291cmNlKGRvbUV2ZW50c1NvdXJjZSk7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBNU0dfU09VUkNFX0tFWSwgZG9tRXZlbnRzU291cmNlKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgQ29tcG9uZW50RmFjZXQgPSByZXF1aXJlKCcuLi9jX2ZhY2V0JylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jZl9yZWdpc3RyeScpXG4gICAgLCBNZXNzZW5nZXIgPSByZXF1aXJlKCcuLi8uLi9tZXNzZW5nZXInKVxuICAgICwgRnJhbWVNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi4vbXNnX3NyYy9mcmFtZScpXG4gICAgLCBkb21FdmVudHNDb25zdHJ1Y3RvcnMgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlcy9kZV9jb25zdHJzJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG4vKipcbiAqIGBtaWxvLnJlZ2lzdHJ5LmZhY2V0cy5nZXQoJ0ZyYW1lJylgXG4gKiBDb21wb25lbnQgZmFjZXQgdGhhdCBzaW1wbGlmaWVzIHNlbmRpbmcgd2luZG93IG1lc3NhZ2VzIHRvIGlmcmFtZSBhbmQgc3Vic2NyaWJpbmcgdG8gbWVzc2FnZXMgb24gaW5uZXIgd2luZG93IG9mIGlmcmFtZS5cbiAqIEFsbCBwdWJsaWMgbWV0aG9kcyBvZiBNZXNzZW5nZXIgYW5kIGB0cmlnZ2VyYCBtZXRob2Qgb2YgW0ZyYW1lTWVzc2FnZVNvdXJjZV0oLi4vbXNnX3NyYy9mcmFtZS5qcy5odG1sKSBhcmUgcHJveGllZCBkaXJlY3RseSB0byB0aGlzIGZhY2V0LlxuICogRm9yIGV4YW1wbGUsIHRvIHNlbmQgY3VzdG9tIG1lc3NhZ2UgdG8gaWZyYW1lIHdpbmRvdyB1c2U6XG4gKiBgYGBcbiAqIGlmcmFtZUNvbXBvbmVudC5mcmFtZS50cmlnZ2VyKCdteW1lc3NhZ2UnLCBteURhdGEpO1xuICogYGBgXG4gKiBUbyBzdWJzY3JpYmUgdG8gdGhpcyBtZXNzYWdlcyBpbnNpZGUgZnJhbWUgdXNlICh3aXRoIG1pbG8gLSBzZWUgW21pbG8ubWFpbF0oLi4vLi4vbWFpbC9pbmRleC5qcy5odG1sKSk6XG4gKiBgYGBcbiAqIG1pbG8ubWFpbC5vbignbWVzc2FnZTpteW1lc3NhZ2UnLCBmdW5jdGlvbihtc2dUeXBlLCBtc2dEYXRhKSB7XG4gKiAgICAgLy8gZGF0YSBpcyBpbnNpZGUgb2Ygd2luZG93IG1lc3NhZ2UgZGF0YVxuICogICAgIC8vIG1zZ1R5cGUgPT0gJ21lc3NhZ2U6bXltZXNzYWdlJ1xuICogICAgIHZhciBteURhdGEgPSBtc2dEYXRhLmRhdGE7XG4gKiAgICAgLy8gLi4uIGFwcCBsb2dpYyBoZXJlXG4gKiB9KTtcbiAqIGBgYFxuICogb3Igd2l0aG91dCBtaWxvOlxuICogYGBgXG4gKiB3aW5kb3cuYXR0YWNoRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIGZ1bmN0aW9uKG1lc3NhZ2UpIHtcbiAqICAgICB2YXIgbXNnVHlwZSA9IG1lc3NhZ2UudHlwZTsgLy8gZS5nLiwgJ215bWVzc2FnZSdcbiAqICAgICB2YXIgbXlEYXRhID0gbWVzc2FnZS5kYXRhO1xuICogICAgIC8vIC4uLiBtZXNzYWdlIHJvdXRpbmcgYW5kIGNvZGUgaGVyZVxuICogfSk7XG4gKiBgYGBcbiAqIE1pbG8gZG9lcyByb3V0aW5nIGJhc2VkIG9uIHNlbnQgbWVzc2FnZSB0eXBlIGF1dG9tYXRpY2FsbHkuXG4gKiBTZWUgW01lc3Nlbmdlcl0oLi4vLi4vbWVzc2VuZ2VyL2luZGV4LmpzLmh0bWwpIGFuZCBbbWlsby5tYWlsXSguLi8uLi9tYWlsL2luZGV4LmpzLmh0bWwpLlxuICovXG4gdmFyIEZyYW1lID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ0ZyYW1lJyk7XG5cblxuLyoqXG4gKiBDYWxscyBwYXNzZWQgZnVuY3Rpb24gd2hlbiBmcmFtZSBET00gYmVjb21lcyByZWFkeS4gSWYgYWxyZWFkeSByZWFkeSBjYWxscyBpbW1lZGlhdGVseVxuICovXG52YXIgRnJhbWUkd2hlblJlYWR5ID0gX21ha2VXaGVuUmVhZHlGdW5jKEZyYW1lJGlzUmVhZHksICdkb21yZWFkeScpO1xuXG4vKipcbiAqIENhbGxzIHBhc3NlZCBmdW5jdGlvbiB3aGVuIGZyYW1lIG1pbG8gYmVjb21lcyByZWFkeS4gSWYgYWxyZWFkeSByZWFkeSBjYWxscyBpbW1lZGlhdGVseVxuICovXG52YXIgRnJhbWUkd2hlbk1pbG9SZWFkeSA9IF9tYWtlV2hlblJlYWR5RnVuYyhGcmFtZSRpc01pbG9SZWFkeSwgJ21lc3NhZ2U6bWlsb3JlYWR5Jyk7XG5cblxuLyoqXG4gKiAjIyMjRXZlbnRzIGZhY2V0IGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbaW5pdF0oI0ZyYW1lJGluaXQpIC0gY2FsbGVkIGJ5IGNvbnN0cnVjdG9yIGF1dG9tYXRpY2FsbHlcbiAqL1xuXy5leHRlbmRQcm90byhGcmFtZSwge1xuICAgIGluaXQ6IEZyYW1lJGluaXQsXG4gICAgc3RhcnQ6IEZyYW1lJHN0YXJ0LFxuICAgIGRlc3Ryb3k6IEZyYW1lJGRlc3Ryb3ksXG4gICAgZ2V0V2luZG93OiBGcmFtZSRnZXRXaW5kb3csXG4gICAgaXNSZWFkeTogRnJhbWUkaXNSZWFkeSxcbiAgICB3aGVuUmVhZHk6IEZyYW1lJHdoZW5SZWFkeSxcbiAgICBpc01pbG9SZWFkeTogRnJhbWUkaXNNaWxvUmVhZHksXG4gICAgd2hlbk1pbG9SZWFkeTogRnJhbWUkd2hlbk1pbG9SZWFkeSxcbiAgICBtaWxvOiBGcmFtZSRtaWxvXG4gICAgLy8gX3JlYXR0YWNoOiBfcmVhdHRhY2hFdmVudHNPbkVsZW1lbnRDaGFuZ2Vcbn0pO1xuXG5cbmZhY2V0c1JlZ2lzdHJ5LmFkZChGcmFtZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRnJhbWU7XG5cblxuLyoqXG4gKiBFeHBvc2UgRnJhbWVNZXNzYWdlU291cmNlIHRyaWdnZXIgbWV0aG9kIG9uIEV2ZW50cyBwcm90b3R5cGVcbiAqL1xudmFyIE1TR19TT1VSQ0VfS0VZID0gJ19tZXNzYWdlU291cmNlJztcbkZyYW1lTWVzc2FnZVNvdXJjZS51c2VXaXRoKEZyYW1lLCBNU0dfU09VUkNFX0tFWSwgWyd0cmlnZ2VyJ10pO1xuXG5cbi8qKlxuICogRnJhbWUgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsemVzIGZhY2V0LCBjb25uZWN0cyBGcmFtZU1lc3NhZ2VTb3VyY2UgdG8gZmFjZXQncyBtZXNzZW5nZXJcbiAqL1xuZnVuY3Rpb24gRnJhbWUkaW5pdCgpIHtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIFxuICAgIHZhciBtZXNzYWdlU291cmNlID0gbmV3IEZyYW1lTWVzc2FnZVNvdXJjZSh0aGlzLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdGhpcy5vd25lcik7XG4gICAgdGhpcy5fc2V0TWVzc2FnZVNvdXJjZShtZXNzYWdlU291cmNlKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgTVNHX1NPVVJDRV9LRVksIG1lc3NhZ2VTb3VyY2UpO1xufVxuXG5cbi8qKlxuICogRnJhbWUgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBFbWl0cyBmcmFtZWxvYWRlZCBldmVudCB3aGVuIHJlYWR5LlxuICovXG5mdW5jdGlvbiBGcmFtZSRzdGFydCgpIHtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuc3RhcnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgbWlsbyhwb3N0RG9tUmVhZHkpO1xuXG4gICAgZnVuY3Rpb24gcG9zdERvbVJlYWR5KGV2ZW50KSB7XG4gICAgICAgIHNlbGYucG9zdE1lc3NhZ2UoJ2RvbXJlYWR5JywgZXZlbnQpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBGcmFtZSRkZXN0cm95KCkge1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuLyoqXG4gKiBGcmFtZSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHJpZXZlcyB0aGUgaW50ZXJuYWwgd2luZG93IG9mIHRoZSBmcmFtZSBcbiAqXG4gKiBAcGFyYW0ge1dpbmRvd31cbiAqL1xuZnVuY3Rpb24gRnJhbWUkZ2V0V2luZG93KCkge1xuICAgIHJldHVybiB0aGlzLm93bmVyLmVsLmNvbnRlbnRXaW5kb3c7XG59XG5cblxuLyoqXG4gKiBGcmFtZSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgZG9jdW1lbnQucmVhZHlTdGF0ZSBpZiBmcmFtZSBkb3VtZW50IHN0YXRlIGlzICdpbnRlcmFjdGl2ZScgb3IgJ2NvbXBsZXRlJywgZmFsc2Ugb3RoZXJ3aXNlXG4gKlxuICogQHJldHVybiB7U3RyaW5nfEJvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIEZyYW1lJGlzUmVhZHkoKSB7XG4gICAgdmFyIHJlYWR5U3RhdGUgPSB0aGlzLmdldFdpbmRvdygpLmRvY3VtZW50LnJlYWR5U3RhdGU7XG4gICAgcmV0dXJuICByZWFkeVN0YXRlICE9ICdsb2FkaW5nJyA/IHJlYWR5U3RhdGUgOiBmYWxzZTtcbn1cblxuXG4vKipcbiAqIEZyYW1lIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyB0cnVlIGlmIG1pbG8gaXMgbG9hZGVkIGFuZCBoYXMgZmluaXNoZWQgaW5pdGlhbGl6aW5nIGluc2lkZSB0aGUgZnJhbWVcbiAqXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBGcmFtZSRpc01pbG9SZWFkeSgpIHtcbiAgICB2YXIgZnJhbWVNaWxvID0gdGhpcy5nZXRXaW5kb3coKS5taWxvO1xuICAgIHJldHVybiB0aGlzLmlzUmVhZHkoKSAmJiBmcmFtZU1pbG8gJiYgZnJhbWVNaWxvLm1pbG9fdmVyc2lvbjtcbn1cblxuXG4vKipcbiAqIEdpdmVzIGFjY2VzcyB0byBtaWxvIGluIHRoZSBmcmFtZSAoYXNzdW1pbmcgaXQgaXMgbG9hZGVkIHRoZXJlKVxuICogQ2FsbHMgZnVuY3Rpb24gd2hlbiBib3RoIG1pbG8gYW5kIERPTSBhcmUgcmVhZHkgaWYgZnVuY3Rpb24gaXMgcGFzc2VkLlxuICogUmV0dXJucyB0aGUgcmVmZXJlbmNlIHRvIG1pbG8gaW5zaWRlIHRoZSBmcmFtZSBpZiB0aGUgd2luZG93IGlzIGFscmVhZHkgYXZhaWxhYmxlLlxuICogXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB3aGVuIG1pbG8gYW5kIERPTSBhcmUgcmVhZHkgaW4gdGhlIGZyYW1lXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn0gcmVmZXJlbmNlIHRvIG1pbG8gaW4gdGhlIGZyYW1lIFxuICovXG5mdW5jdGlvbiBGcmFtZSRtaWxvKGZ1bmMpIHtcbiAgICBpZiAodHlwZW9mIGZ1bmMgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHRoaXMud2hlbk1pbG9SZWFkeShmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHNlbGYuZ2V0V2luZG93KCkubWlsbyhmdW5jKVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgdmFyIHdpbiA9IHRoaXMuZ2V0V2luZG93KCk7XG4gICAgcmV0dXJuIHdpbiAmJiB3aW4ubWlsbztcbn1cblxuXG5mdW5jdGlvbiBfbWFrZVdoZW5SZWFkeUZ1bmMoaXNSZWFkeUZ1bmMsIGV2ZW50KSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIEZyYW1lX3doZW5SZWFkeUZ1bmMoZnVuYykgeyAvLyAsIGFyZ3VtZW50c1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXNcbiAgICAgICAgICAgICwgYXJncyA9IF8uc2xpY2UoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgaWYgKGlzUmVhZHlGdW5jLmNhbGwodGhpcykpXG4gICAgICAgICAgICBjYWxsRnVuYygpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICB0aGlzLm9uKGV2ZW50LCBjYWxsRnVuYyk7XG5cbiAgICAgICAgZnVuY3Rpb24gY2FsbEZ1bmMoKSB7XG4gICAgICAgICAgICBmdW5jLmFwcGx5KHNlbGYsIGFyZ3MpO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBDb21wb25lbnRGYWNldCA9IHJlcXVpcmUoJy4uL2NfZmFjZXQnKVxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NmX3JlZ2lzdHJ5JylcbiAgICAsIE1vZGVsID0gcmVxdWlyZSgnLi4vLi4vbW9kZWwnKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBtaWxvTWFpbCA9IHJlcXVpcmUoJy4uLy4uL3NlcnZpY2VzL21haWwnKTtcblxuXG52YXIgSXRlbUZhY2V0ID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ0l0ZW0nKTtcblxuXy5leHRlbmRQcm90byhJdGVtRmFjZXQsIHtcbiAgICBnZXRTdGF0ZTogSXRlbUZhY2V0JGdldFN0YXRlLFxuICAgIHNldFN0YXRlOiBJdGVtRmFjZXQkc2V0U3RhdGUsXG4gICAgZ2V0SW5kZXg6IEl0ZW1GYWNldCRnZXRJbmRleCxcbiAgICBzZXRJbmRleDogSXRlbUZhY2V0JHNldEluZGV4LFxuICAgIHJlbW92ZUl0ZW06IEl0ZW1GYWNldCRyZW1vdmVJdGVtLFxuICAgIGV4dHJhY3RJdGVtOiBJdGVtRmFjZXQkZXh0cmFjdEl0ZW0sXG4gICAgcmVxdWlyZTogWydDb250YWluZXInLCAnRG9tJywgJ0RhdGEnXVxufSk7XG5cbmZhY2V0c1JlZ2lzdHJ5LmFkZChJdGVtRmFjZXQpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEl0ZW1GYWNldDtcblxuXG5mdW5jdGlvbiBJdGVtRmFjZXQkZ2V0U3RhdGUoKSB7XG4gICAgcmV0dXJuIHsgc3RhdGU6IHtcbiAgICAgICAgaW5kZXg6IHRoaXMuZ2V0SW5kZXgoKVxuICAgIH19O1xufVxuXG5cbmZ1bmN0aW9uIEl0ZW1GYWNldCRzZXRTdGF0ZShzdGF0ZSkge1xuICAgIHRoaXMuc2V0SW5kZXgoc3RhdGUuc3RhdGUuaW5kZXgpO1xufVxuXG5cbi8qKlxuICogRmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHRoZSBpbmRleCBvZiB0aGUgb3duZXIgY29tcG9uZW50IGluIGl0J3MgcGFyZW50IGxpc3QgY29tcG9uZW50XG4gKiBAcmV0dXJuIHtJbnRlZ2VyfSBUaGUgaW5kZXhcbiAqL1xuZnVuY3Rpb24gSXRlbUZhY2V0JGdldEluZGV4KCkge1xuICAgIHJldHVybiB0aGlzLmluZGV4O1xufVxuXG5cbi8qKlxuICogRmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTZXRzIHRoZSBpbmRleCBvZiB0aGlzIGNvbXBvbmVudFxuICogQHBhcmFtIHtJbnRlZ2VyfSBpbmRleCBUaGUgaW5kZXggdG8gYmUgc2V0XG4gKi9cbmZ1bmN0aW9uIEl0ZW1GYWNldCRzZXRJbmRleChpbmRleCkge1xuICAgIHRoaXMuaW5kZXggPSBpbmRleDtcbn1cblxuXG4vKipcbiAqIEl0ZW1GYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJlbW92ZXMgY29tcG9uZW50IGZyb20gdGhlIGxpc3QsIGNvbXBvbmVudCBnZXRzIGRlc3Ryb3llZFxuICovXG5mdW5jdGlvbiBJdGVtRmFjZXQkcmVtb3ZlSXRlbSgpIHtcbiAgICAvLyB0aGlzLmxpc3QgYW5kIHRoaXMuaW5kZXggYXJlIHNldCBieSB0aGUgbGlzdCB3aGVuIHRoZSBpdGVtIGlzIGFkZGVkXG4gICAgdGhpcy5saXN0LnJlbW92ZUl0ZW0odGhpcy5pbmRleCk7XG59XG5cblxuLyoqXG4gKiBJdGVtRmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZW1vdmVzIGNvbXBvbmVudCBmcm9tIHRoZSBsaXN0LCBjb21wb25lbnQgaXMgTk9UIGRlc3Ryb3llZFxuICovXG5mdW5jdGlvbiBJdGVtRmFjZXQkZXh0cmFjdEl0ZW0oKSB7XG4gICAgdGhpcy5saXN0LmV4dHJhY3RJdGVtKHRoaXMuaW5kZXgpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50RmFjZXQgPSByZXF1aXJlKCcuLi9jX2ZhY2V0JylcbiAgICAsIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NmX3JlZ2lzdHJ5JylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgbWlsb01haWwgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlcy9tYWlsJylcbiAgICAsIG1pbG9CaW5kZXIgPSByZXF1aXJlKCcuLi8uLi9iaW5kZXInKVxuICAgICwgbWlsb1V0aWwgPSByZXF1aXJlKCcuLi8uLi91dGlsJylcbiAgICAsIExpc3RFcnJvciA9IG1pbG9VdGlsLmVycm9yLkxpc3RcbiAgICAsIGxvZ2dlciA9IG1pbG9VdGlsLmxvZ2dlclxuICAgICwgZG9UID0gcmVxdWlyZSgnZG90JylcbiAgICAsIGNoZWNrID0gbWlsb1V0aWwuY2hlY2tcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2hcbiAgICAsIGRvbVV0aWxzID0gbWlsb1V0aWwuZG9tXG4gICAgLCBtaWxvQ29uZmlnID0gcmVxdWlyZSgnLi4vLi4vY29uZmlnJyk7XG5cblxudmFyIExJU1RfU0FNUExFX0NTU19DTEFTUyA9ICdtbC1saXN0LWl0ZW0tc2FtcGxlJztcblxuLyoqXG4gKiBgbWlsby5yZWdpc3RyeS5mYWNldHMuZ2V0KCdMaXN0JylgXG4gKiBGYWNldCBlbmFibGluZyBsaXN0IGZ1bmN0aW9uYWxpdHlcbiAqL1xudmFyIExpc3QgPSBfLmNyZWF0ZVN1YmNsYXNzKENvbXBvbmVudEZhY2V0LCAnTGlzdCcpO1xuXG5fLmV4dGVuZFByb3RvKExpc3QsIHtcbiAgICBpbml0OiBMaXN0JGluaXQsXG4gICAgc3RhcnQ6IExpc3Qkc3RhcnQsXG4gICAgZGVzdHJveTogTGlzdCRkZXN0cm95LFxuXG4gICAgcmVxdWlyZTogWydDb250YWluZXInLCAnRG9tJywgJ0RhdGEnXSxcbiAgICBfaXRlbVByZXZpb3VzQ29tcG9uZW50OiBfaXRlbVByZXZpb3VzQ29tcG9uZW50LFxuXG4gICAgaXRlbTogTGlzdCRpdGVtLFxuICAgIGNvdW50OiBMaXN0JGNvdW50LFxuICAgIGNvbnRhaW5zOiBMaXN0JGNvbnRhaW5zLFxuICAgIGFkZEl0ZW06IExpc3QkYWRkSXRlbSxcbiAgICBhZGRJdGVtczogTGlzdCRhZGRJdGVtcyxcbiAgICByZXBsYWNlSXRlbTogTGlzdCRyZXBsYWNlSXRlbSxcbiAgICByZW1vdmVJdGVtOiBMaXN0JHJlbW92ZUl0ZW0sXG4gICAgZXh0cmFjdEl0ZW06IExpc3QkZXh0cmFjdEl0ZW0sXG4gICAgZWFjaDogTGlzdCRlYWNoLFxuICAgIF9zZXRJdGVtOiBMaXN0JF9zZXRJdGVtLFxuICAgIF9yZW1vdmVJdGVtOiBMaXN0JF9yZW1vdmVJdGVtLFxuICAgIF9hZGRJdGVtOiBMaXN0JF9hZGRJdGVtLFxuICAgIF9hZGRJdGVtczogTGlzdCRfYWRkSXRlbXMsXG4gICAgX2NyZWF0ZUNhY2hlVGVtcGxhdGU6IExpc3QkX2NyZWF0ZUNhY2hlVGVtcGxhdGUsXG4gICAgX3VwZGF0ZURhdGFQYXRoczogTGlzdCRfdXBkYXRlRGF0YVBhdGhzXG59KTtcblxuZmFjZXRzUmVnaXN0cnkuYWRkKExpc3QpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IExpc3Q7XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIEluaXRpYWxpemVkIExpc3QgZmFjZXQgaW5zdGFuY2UgYW5kIHNldHMgdXAgaXRlbSBwcm9wZXJ0aWVzLlxuICovXG5mdW5jdGlvbiBMaXN0JGluaXQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICBfbGlzdEl0ZW1zOiBbXSxcbiAgICAgICAgX2xpc3RJdGVtc0hhc2g6IHt9XG4gICAgfSk7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnaXRlbVNhbXBsZScsIG51bGwsIF8uV1JJVCk7XG59XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFN0YXJ0cyB0aGUgTGlzdCBmYWNldCBpbnN0YW5jZSwgZmluZHMgY2hpbGQgd2l0aCBJdGVtIGZhY2V0LlxuICovXG5mdW5jdGlvbiBMaXN0JHN0YXJ0KCkge1xuICAgIC8vIEZpcmVkIGJ5IF9fYmluZGVyX18gd2hlbiBhbGwgY2hpbGRyZW4gb2YgY29tcG9uZW50IGFyZSBib3VuZFxuICAgIHRoaXMub3duZXIub24oJ2NoaWxkcmVuYm91bmQnLCBvbkNoaWxkcmVuQm91bmQpO1xufVxuXG5cbmZ1bmN0aW9uIG9uQ2hpbGRyZW5Cb3VuZCgpIHtcbiAgICAvLyBnZXQgaXRlbXMgYWxyZWFkeSBpbiB0aGUgbGlzdFxuICAgIHZhciBjaGlsZHJlbiA9IHRoaXMuZG9tLmNoaWxkcmVuKClcbiAgICAgICAgLCBpdGVtcyA9IHRoaXMubGlzdC5fbGlzdEl0ZW1zXG4gICAgICAgICwgaXRlbXNIYXNoID0gdGhpcy5saXN0Ll9saXN0SXRlbXNIYXNoO1xuXG4gICAgY2hpbGRyZW4gJiYgY2hpbGRyZW4uZm9yRWFjaChmdW5jdGlvbihjaGlsZEVsKSB7XG4gICAgICAgIHZhciBjb21wID0gQ29tcG9uZW50LmdldENvbXBvbmVudChjaGlsZEVsKTtcbiAgICAgICAgaWYgKGNvbXAgJiYgY29tcC5pdGVtKSB7XG4gICAgICAgICAgICBpdGVtcy5wdXNoKGNvbXApO1xuICAgICAgICAgICAgaXRlbXNIYXNoW2NvbXAubmFtZV0gPSBjb21wO1xuICAgICAgICAgICAgY29tcC5pdGVtLmxpc3QgPSB0aGlzLmxpc3Q7XG4gICAgICAgIH1cbiAgICB9LCB0aGlzKTtcblxuICAgIGlmIChpdGVtcy5sZW5ndGgpIHtcbiAgICAgICAgdmFyIGZvdW5kSXRlbSA9IGl0ZW1zWzBdO1xuICAgICAgICBpdGVtcy5zcGxpY2UoMCwgMSk7XG4gICAgICAgIGRlbGV0ZSBpdGVtc0hhc2hbZm91bmRJdGVtLm5hbWVdO1xuICAgICAgICBpdGVtcy5mb3JFYWNoKGZ1bmN0aW9uKGl0ZW0sIGluZGV4KSB7XG4gICAgICAgICAgICBpdGVtLml0ZW0uc2V0SW5kZXgoaW5kZXgpO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgLy8gQ29tcG9uZW50IG11c3QgaGF2ZSBvbmUgY2hpbGQgd2l0aCBhbiBJdGVtIGZhY2V0IFxuICAgIGlmICghIGZvdW5kSXRlbSkgdGhyb3cgbmV3IExpc3RFcnJvcignTm8gY2hpbGQgY29tcG9uZW50IGhhcyBJdGVtIGZhY2V0Jyk7XG5cbiAgICB0aGlzLmxpc3QuaXRlbVNhbXBsZSA9IGZvdW5kSXRlbTtcblxuICAgIC8vIEFmdGVyIGtlZXBpbmcgYSByZWZlcmVuY2UgdG8gdGhlIGl0ZW0gc2FtcGxlLCBpdCBtdXN0IGJlIGhpZGRlbiBhbmQgcmVtb3ZlZCBmcm9tIHNjb3BlXG4gICAgZm91bmRJdGVtLmRvbS5oaWRlKCk7XG4gICAgZm91bmRJdGVtLnJlbW92ZSh0cnVlKTtcbiAgICBmb3VuZEl0ZW0uZG9tLnJlbW92ZUNzc0NsYXNzZXMoTElTVF9TQU1QTEVfQ1NTX0NMQVNTKTtcblxuICAgIC8vIHJlbW92ZSByZWZlcmVuY2VzIHRvIGNvbXBvbmVudHMgZnJvbSBzYW1wbGUgaXRlbVxuICAgIGZvdW5kSXRlbS53YWxrU2NvcGVUcmVlKGZ1bmN0aW9uKGNvbXApIHtcbiAgICAgICAgZGVsZXRlIGNvbXAuZWxbbWlsb0NvbmZpZy5jb21wb25lbnRSZWZdO1xuICAgIH0pO1xuXG4gICAgdGhpcy5saXN0Ll9jcmVhdGVDYWNoZVRlbXBsYXRlKCk7XG59XG5cblxuZnVuY3Rpb24gTGlzdCRfY3JlYXRlQ2FjaGVUZW1wbGF0ZSgpIHtcbiAgICBpZiAoIXRoaXMuaXRlbVNhbXBsZSkgcmV0dXJuIGZhbHNlO1xuICAgIFxuICAgIHZhciBpdGVtU2FtcGxlID0gdGhpcy5pdGVtU2FtcGxlO1xuXG4gICAgLy8gY3JlYXRlIGl0ZW0gdGVtcGxhdGUgdG8gaW5zZXJ0IG1hbnkgaXRlbXMgYXQgb25jZVxuICAgIHZhciBpdGVtRWxDb3B5ID0gaXRlbVNhbXBsZS5lbC5jbG9uZU5vZGUodHJ1ZSk7XG4gICAgdmFyIGF0dHIgPSBpdGVtU2FtcGxlLmNvbXBvbmVudEluZm8uYXR0cjtcbiAgICB2YXIgYXR0ckNvcHkgPSBfLmNsb25lKGF0dHIpO1xuICAgIGF0dHIuY29tcE5hbWUgPSAne3s9IGl0LmNvbXBvbmVudE5hbWUoKSB9fSc7XG4gICAgYXR0ci5lbCA9IGl0ZW1FbENvcHk7XG4gICAgYXR0ci5kZWNvcmF0ZSgpO1xuXG4gICAgdmFyIGl0ZW1zVGVtcGxhdGVTdHIgPSBcbiAgICAgICAgICAne3sgdmFyIGkgPSBpdC5jb3VudDsgd2hpbGUoaS0tKSB7IH19J1xuICAgICAgICArIGl0ZW1FbENvcHkub3V0ZXJIVE1MXG4gICAgICAgICsgJ3t7IH0gfX0nO1xuXG4gICAgdGhpcy5pdGVtc1RlbXBsYXRlID0gZG9ULmNvbXBpbGUoaXRlbXNUZW1wbGF0ZVN0cik7XG59XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHJpZXZlIGEgcGFydGljdWxhciBjaGlsZCBpdGVtIGJ5IGluZGV4XG4gKiBAcGFyYW0ge0ludGVnZXJ9IGluZGV4IFRoZSBpbmRleCBvZiB0aGUgY2hpbGQgaXRlbSB0byBnZXQuXG4gKiBAcmV0dXJuIHtDb21wb25lbnR9IFRoZSBjb21wb25lbnQgZm91bmRcbiAqL1xuZnVuY3Rpb24gTGlzdCRpdGVtKGluZGV4KSB7XG4gICAgcmV0dXJuIHRoaXMuX2xpc3RJdGVtc1tpbmRleF07XG59XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIEdldHMgdGhlIHRvdGFsIG51bWJlciBvZiBjaGlsZCBpdGVtc1xuICogQHJldHVybiB7SW50ZWdlcn0gVGhlIHRvdGFsXG4gKi9cbmZ1bmN0aW9uIExpc3QkY291bnQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2xpc3RJdGVtcy5sZW5ndGg7XG59XG5cblxuZnVuY3Rpb24gTGlzdCRfc2V0SXRlbShpbmRleCwgY29tcG9uZW50KSB7XG4gICAgdGhpcy5fbGlzdEl0ZW1zLnNwbGljZShpbmRleCwgMCwgY29tcG9uZW50KTtcbiAgICB0aGlzLl9saXN0SXRlbXNIYXNoW2NvbXBvbmVudC5uYW1lXSA9IGNvbXBvbmVudDtcbiAgICBjb21wb25lbnQuaXRlbS5saXN0ID0gdGhpcztcbiAgICBjb21wb25lbnQuaXRlbS5zZXRJbmRleCgraW5kZXgpO1xufVxuXG5cbi8qKlxuICogRmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHRydWUgaWYgYSBwYXJ0aWN1bGFyIGNoaWxkIGl0ZW0gZXhpc3RzIGluIHRoZSBsaXN0XG4gKiBAcGFyYW0ge0NvbXBvbmVudH0gY29tcG9uZW50IFRoZSBjb21wb25lbnQgdG8gbG9vayBmb3IuXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBMaXN0JGNvbnRhaW5zKGNvbXBvbmVudCkge1xuICAgIHJldHVybiB0aGlzLl9saXN0SXRlbXNIYXNoW2NvbXBvbmVudC5uYW1lXSA9PSBjb21wb25lbnQ7XG59XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIEFkZHMgYSBuZXcgY2hpbGQgY29tcG9uZW50IGF0IGEgcGFydGljdWxhciBpbmRleCBhbmQgcmV0dXJucyB0aGUgbmV3IGNvbXBvbmVudC5cbiAqIFRoaXMgbWV0aG9kIHVzZXMgZGF0YSBmYWNldCwgc28gbm90aWZpY2F0aW9uIHdpbGwgYmUgZW1pdHRlZCBvbiBkYXRhIGZhY2V0LlxuICogQHBhcmFtIHtJbnRlZ2VyfSBpbmRleCBUaGUgaW5kZXggdG8gYWRkIGF0XG4gKiBAcmV0dXJuIHtDb21wb25lbnR9IFRoZSBuZXdseSBjcmVhdGVkIGNvbXBvbmVudFxuICovXG5mdW5jdGlvbiBMaXN0JGFkZEl0ZW0oaW5kZXgsIGl0ZW1EYXRhKSB7XG4gICAgaW5kZXggPSBpbmRleCB8fCB0aGlzLmNvdW50KCk7XG4gICAgdGhpcy5vd25lci5kYXRhLnNwbGljZShpbmRleCwgMCwgaXRlbURhdGEgfHwge30pO1xuICAgIHJldHVybiB0aGlzLml0ZW0oaW5kZXgpO1xufVxuXG5cbi8qKlxuICogRmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBBZGRzIGEgbmV3IGNoaWxkIGNvbXBvbmVudCBhdCBhIHBhcnRpY3VsYXIgaW5kZXggYW5kIHJldHVybnMgdGhlIG5ldyBjb21wb25lbnRcbiAqIEBwYXJhbSB7SW50ZWdlcn0gaW5kZXggVGhlIGluZGV4IHRvIGFkZCBhdFxuICogQHJldHVybiB7Q29tcG9uZW50fSBUaGUgbmV3bHkgY3JlYXRlZCBjb21wb25lbnRcbiAqL1xuZnVuY3Rpb24gTGlzdCRfYWRkSXRlbShpbmRleCkge1xuICAgIGluZGV4ID0gaW5kZXggfHwgdGhpcy5jb3VudCgpO1xuICAgIGlmICh0aGlzLml0ZW0oaW5kZXgpKVxuICAgICAgICB0aHJvdyBMaXN0RXJyb3IoJ2F0dGVtcHQgdG8gY3JlYXRlIGl0ZW0gd2l0aCBJRCBvZiBleGlzdGluZyBpdGVtJyk7XG5cbiAgICAvLyBDb3B5IGNvbXBvbmVudFxuICAgIHZhciBjb21wb25lbnQgPSBDb21wb25lbnQuY29weSh0aGlzLml0ZW1TYW1wbGUsIHRydWUpO1xuICAgIHZhciBwcmV2Q29tcG9uZW50ID0gdGhpcy5faXRlbVByZXZpb3VzQ29tcG9uZW50KGluZGV4KTtcblxuICAgIGlmICghcHJldkNvbXBvbmVudC5lbC5wYXJlbnROb2RlKVxuICAgICAgICByZXR1cm4gbG9nZ2VyLndhcm4oJ2xpc3QgaXRlbSBzYW1wbGUgd2FzIHJlbW92ZWQgZnJvbSBET00sIHByb2JhYmx5IGNhdXNlZCBieSB3cm9uZyBkYXRhLiBSZXNldCBsaXN0IGRhdGEgd2l0aCBhcnJheScpO1xuXG4gICAgLy8gQWRkIGl0IHRvIHRoZSBET01cbiAgICBwcmV2Q29tcG9uZW50LmRvbS5pbnNlcnRBZnRlcihjb21wb25lbnQuZWwpO1xuXG4gICAgLy8gQWRkIHRvIGxpc3QgaXRlbXNcbiAgICB0aGlzLl9zZXRJdGVtKGluZGV4LCBjb21wb25lbnQpO1xuXG4gICAgLy8gU2hvdyB0aGUgbGlzdCBpdGVtIGNvbXBvbmVudFxuICAgIGNvbXBvbmVudC5lbC5zdHlsZS5kaXNwbGF5ID0gJyc7XG5cbiAgICBfdXBkYXRlSXRlbXNJbmRleGVzLmNhbGwodGhpcywgaW5kZXggKyAxKTtcblxuICAgIHJldHVybiBjb21wb25lbnQ7XG59XG5cblxuZnVuY3Rpb24gX3VwZGF0ZUl0ZW1zSW5kZXhlcyhmcm9tSW5kZXgsIHRvSW5kZXgpIHtcbiAgICBmcm9tSW5kZXggPSBmcm9tSW5kZXggfHwgMDtcbiAgICB0b0luZGV4ID0gdG9JbmRleCB8fCB0aGlzLmNvdW50KCk7XG4gICAgZm9yICh2YXIgaSA9IGZyb21JbmRleDsgaSA8IHRvSW5kZXg7IGkrKykge1xuICAgICAgICB2YXIgY29tcG9uZW50ID0gdGhpcy5fbGlzdEl0ZW1zW2ldO1xuICAgICAgICBpZiAoY29tcG9uZW50KVxuICAgICAgICAgICAgY29tcG9uZW50Lml0ZW0uc2V0SW5kZXgoaSk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKCdMaXN0OiBubyBpdGVtIGF0IHBvc2l0aW9uJywgaSk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIExpc3QkYWRkSXRlbXMoY291bnQsIGluZGV4KSB7IC8vICwuLi4gaXRlbXMgZGF0YVxuICAgIHZhciBpdGVtc0RhdGEgPSBfLnNsaWNlKGFyZ3VtZW50cywgMik7XG4gICAgaWYgKGl0ZW1zRGF0YS5sZW5ndGggPCBjb3VudCkgXG4gICAgICAgIGl0ZW1zRGF0YS5jb25jYXQoXy5yZXBlYXQoY291bnQgLSBpdGVtc0RhdGEubGVuZ3RoLCB7fSkpO1xuICAgIHZhciBzcGxpY2VBcmdzID0gW2luZGV4LCAwXS5jb25jYXQoaXRlbXNEYXRhKTtcbiAgICB2YXIgZGF0YUZhY2V0ID0gdGhpcy5vd25lci5kYXRhO1xuICAgIGRhdGFGYWNldC5zcGxpY2UuYXBwbHkoZGF0YUZhY2V0LCBzcGxpY2VBcmdzKTtcbn1cblxuXG4vKipcbiAqIExpc3QgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBBZGRzIGEgZ2l2ZW4gbnVtYmVyIG9mIGl0ZW1zIHVzaW5nIHRlbXBsYXRlIHJlbmRlcmluZyByYXRoZXIgdGhhbiBhZGRpbmcgZWxlbWVudHMgb25lIGJ5IG9uZVxuICpcbiAqIEBwYXJhbSB7SW50ZWdlcn0gY291bnQgbnVtYmVyIG9mIGl0ZW1zIHRvIGFkZFxuICogQHBhcmFtIHtbSW50ZWdlcl19IGluZGV4IG9wdGlvbmFsIGluZGV4IG9mIGl0ZW0gYWZ0ZXIgd2hpY2ggdG8gYWRkXG4gKi9cbmZ1bmN0aW9uIExpc3QkX2FkZEl0ZW1zKGNvdW50LCBpbmRleCkge1xuICAgIGNoZWNrKGNvdW50LCBNYXRjaC5JbnRlZ2VyKTtcbiAgICBpZiAoY291bnQgPCAwKVxuICAgICAgICB0aHJvdyBuZXcgTGlzdEVycm9yKCdjYW5cXCd0IGFkZCBuZWdhdGl2ZSBudW1iZXIgb2YgaXRlbXMnKTtcblxuICAgIGlmIChjb3VudCA9PSAwKSByZXR1cm47XG5cbiAgICB2YXIgaXRlbXNIVE1MID0gdGhpcy5pdGVtc1RlbXBsYXRlKHtcbiAgICAgICAgY29tcG9uZW50TmFtZTogbWlsb1V0aWwuY29tcG9uZW50TmFtZSxcbiAgICAgICAgY291bnQ6IGNvdW50XG4gICAgfSk7XG5cbiAgICB2YXIgd3JhcEVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgd3JhcEVsLmlubmVySFRNTCA9IGl0ZW1zSFRNTDtcblxuICAgIG1pbG9CaW5kZXIod3JhcEVsLCB0aGlzLm93bmVyLmNvbnRhaW5lci5zY29wZSk7XG4gICAgdmFyIGNoaWxkcmVuID0gZG9tVXRpbHMuY2hpbGRyZW4od3JhcEVsKTtcblxuICAgIGlmIChjb3VudCAhPSBjaGlsZHJlbi5sZW5ndGgpXG4gICAgICAgIGxvZ2dlci5lcnJvcignbnVtYmVyIG9mIGl0ZW1zIGFkZGVkIGlzIGRpZmZlcmVudCBmcm9tIHJlcXVlc3RlZCcpO1xuXG4gICAgaWYgKGNoaWxkcmVuICYmIGNoaWxkcmVuLmxlbmd0aCkge1xuICAgICAgICB2YXIgbGlzdExlbmd0aCA9IHRoaXMuY291bnQoKTtcbiAgICAgICAgdmFyIHNwbGljZUluZGV4ID0gaW5kZXggPCAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgOiB0eXBlb2YgaW5kZXggPT0gJ3VuZGVmaW5lZCcgfHwgaW5kZXggPiBsaXN0TGVuZ3RoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gbGlzdExlbmd0aFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IGluZGV4O1xuXG4gICAgICAgIHZhciBwcmV2Q29tcG9uZW50ID0gc3BsaWNlSW5kZXggPT0gMFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IHRoaXMuaXRlbVNhbXBsZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHRoaXMuX2xpc3RJdGVtc1tzcGxpY2VJbmRleCAtIDFdO1xuXG4gICAgICAgIHZhciBmcmFnID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpXG4gICAgICAgICAgICAsIG5ld0NvbXBvbmVudHMgPSBbXTtcblxuICAgICAgICBjaGlsZHJlbi5mb3JFYWNoKGZ1bmN0aW9uKGVsLCBpKSB7XG4gICAgICAgICAgICB2YXIgY29tcG9uZW50ID0gQ29tcG9uZW50LmdldENvbXBvbmVudChlbCk7XG4gICAgICAgICAgICBpZiAoISBjb21wb25lbnQpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGxvZ2dlci5lcnJvcignTGlzdDogZWxlbWVudCBpbiBuZXcgaXRlbXMgaXMgbm90IGEgY29tcG9uZW50Jyk7XG4gICAgICAgICAgICBuZXdDb21wb25lbnRzLnB1c2goY29tcG9uZW50KTtcbiAgICAgICAgICAgIHRoaXMuX3NldEl0ZW0oc3BsaWNlSW5kZXgrKywgY29tcG9uZW50KTtcbiAgICAgICAgICAgIGZyYWcuYXBwZW5kQ2hpbGQoZWwpO1xuICAgICAgICAgICAgZWwuc3R5bGUuZGlzcGxheSA9ICcnO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBfdXBkYXRlSXRlbXNJbmRleGVzLmNhbGwodGhpcywgc3BsaWNlSW5kZXgpO1xuXG4gICAgICAgIGlmICghcHJldkNvbXBvbmVudC5lbC5wYXJlbnROb2RlKVxuICAgICAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdsaXN0IGl0ZW0gc2FtcGxlIHdhcyByZW1vdmVkIGZyb20gRE9NLCBwcm9iYWJseSBjYXVzZWQgYnkgd3JvbmcgZGF0YS4gUmVzZXQgbGlzdCBkYXRhIHdpdGggYXJyYXknKTtcblxuICAgICAgICAvLyBBZGQgaXQgdG8gdGhlIERPTVxuICAgICAgICBwcmV2Q29tcG9uZW50LmRvbS5pbnNlcnRBZnRlcihmcmFnKTtcblxuICAgICAgICBfLmRlZmVyTWV0aG9kKG5ld0NvbXBvbmVudHMsICdmb3JFYWNoJywgZnVuY3Rpb24oY29tcCkge1xuICAgICAgICAgICAgY29tcC5icm9hZGNhc3QoJ3N0YXRlcmVhZHknKTtcbiAgICAgICAgfSk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogTGlzdCBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIEBwYXJhbSB7SW50ZWdlcn0gaW5kZXggVGhlIGluZGV4IG9mIHRoZSBpdGVtIHRvIHJlbW92ZVxuICogQHJldHVybiB7QXJyYXlbT2JqZWN0XX0gVGhlIHNwbGljZWQgZGF0YVxuICovXG5mdW5jdGlvbiBMaXN0JHJlbW92ZUl0ZW0oaW5kZXgpIHtcbiAgICByZXR1cm4gdGhpcy5vd25lci5kYXRhLnNwbGljZShpbmRleCwgMSk7XG59XG5cblxuLyoqXG4gKiBMaXN0IGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogQHBhcmFtIHtJbnRlZ2VyfSBpbmRleCBUaGUgaW5kZXggb2YgdGhlIGl0ZW0gdG8gZXh0cmFjdFxuICogQHJldHVybiB7Q29tcG9uZW50fSBUaGUgZXh0cmFjdGVkIGl0ZW1cbiAqL1xuZnVuY3Rpb24gTGlzdCRleHRyYWN0SXRlbShpbmRleCkge1xuICAgIHZhciBpdGVtQ29tcCA9IHRoaXMuX3JlbW92ZUl0ZW0oaW5kZXgsIGZhbHNlKTtcbiAgICB0aGlzLl91cGRhdGVEYXRhUGF0aHMoaW5kZXgsIHRoaXMuY291bnQoKSk7XG4gICAgcmV0dXJuIGl0ZW1Db21wO1xufVxuXG5cbi8qKlxuICogTGlzdCBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJlbW92ZXMgaXRlbSwgcmV0dXJucyB0aGUgcmVtb3ZlZCBpdGVtIHRoYXQgaXMgZGVzdHJveWVkIGJ5IGRlZmF1bHQuXG4gKiBcbiAqIEBwYXJhbSAge051bWJlcn0gaW5kZXggaXRlbSBpbmRleFxuICogQHBhcmFtICB7Qm9vbGVhbn0gZG9EZXN0cm95SXRlbSBvcHRpb25hbCBmYWxzZSB0byBwcmV2ZW50IGl0ZW0gZGVzdHJ1Y3Rpb24sIHRydWUgYnkgZGVmYXVsdFxuICogQHJldHVybiB7Q29tcG9uZW50fVxuICovXG5mdW5jdGlvbiBMaXN0JF9yZW1vdmVJdGVtKGluZGV4LCBkb0Rlc3Ryb3lJdGVtKSB7XG4gICAgdmFyIGNvbXAgPSB0aGlzLml0ZW0oaW5kZXgpO1xuXG4gICAgaWYgKCEgY29tcClcbiAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdhdHRlbXB0IHRvIHJlbW92ZSBsaXN0IGl0ZW0gd2l0aCBpZCB0aGF0IGRvZXMgbm90IGV4aXN0Jyk7XG5cbiAgICB0aGlzLl9saXN0SXRlbXNbaW5kZXhdID0gdW5kZWZpbmVkO1xuICAgIGRlbGV0ZSB0aGlzLl9saXN0SXRlbXNIYXNoW2NvbXAubmFtZV07XG4gICAgaWYgKGRvRGVzdHJveUl0ZW0gIT09IGZhbHNlKSBjb21wLmRlc3Ryb3koKTtcbiAgICBlbHNlIHtcbiAgICAgICAgY29tcC5yZW1vdmUoKTtcbiAgICAgICAgY29tcC5kb20ucmVtb3ZlKCk7XG4gICAgfVxuXG4gICAgdGhpcy5fbGlzdEl0ZW1zLnNwbGljZShpbmRleCwgMSk7XG4gICAgX3VwZGF0ZUl0ZW1zSW5kZXhlcy5jYWxsKHRoaXMsIGluZGV4KTtcblxuICAgIHJldHVybiBjb21wO1xufVxuXG5cbmZ1bmN0aW9uIExpc3QkcmVwbGFjZUl0ZW0oaW5kZXgsIG5ld0l0ZW0pe1xuICAgIHZhciBvbGRJdGVtID0gdGhpcy5pdGVtKGluZGV4KTtcbiAgICBvbGRJdGVtLmRvbS5pbnNlcnRBZnRlcihuZXdJdGVtLmVsKTtcbiAgICB0aGlzLl9yZW1vdmVJdGVtKGluZGV4KTtcbiAgICB0aGlzLl9zZXRJdGVtKGluZGV4LCBuZXdJdGVtKTtcbn1cblxuXG4vLyBSZXR1cm5zIHRoZSBwcmV2aW91cyBpdGVtIGNvbXBvbmVudCBnaXZlbiBhbiBpbmRleFxuZnVuY3Rpb24gX2l0ZW1QcmV2aW91c0NvbXBvbmVudChpbmRleCkge1xuICAgIHdoaWxlIChpbmRleCA+PSAwICYmICEgdGhpcy5fbGlzdEl0ZW1zW2luZGV4XSlcbiAgICAgICAgaW5kZXgtLTtcblxuICAgIHJldHVybiBpbmRleCA+PSAwXG4gICAgICAgICAgICAgICAgPyB0aGlzLl9saXN0SXRlbXNbaW5kZXhdXG4gICAgICAgICAgICAgICAgOiB0aGlzLml0ZW1TYW1wbGU7XG59XG5cblxuLy8gdG9JbmRleCBpcyBub3QgaW5jbHVkZWRcbi8vIG5vIHJhbmdlIGNoZWNraW5nIGlzIG1hZGVcbmZ1bmN0aW9uIExpc3QkX3VwZGF0ZURhdGFQYXRocyhmcm9tSW5kZXgsIHRvSW5kZXgpIHtcbiAgICBmb3IgKHZhciBpID0gZnJvbUluZGV4OyBpIDwgdG9JbmRleDsgaSsrKSB7XG4gICAgICAgIHZhciBpdGVtID0gdGhpcy5pdGVtKGkpO1xuICAgICAgICBpZiAoaXRlbSlcbiAgICAgICAgICAgIGl0ZW0uZGF0YS5fcGF0aCA9ICdbJyArIGkgKyAnXSc7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKCdEYXRhOiBubyBpdGVtIGZvciBpbmRleCcsIGopO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIEZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogU2ltaWxhciB0byBmb3JFYWNoIG1ldGhvZCBvZiBBcnJheSwgaXRlcmF0ZXMgZWFjaCBvZiB0aGUgY2hpbGQgaXRlbXMuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBBbiBpdGVyYXRvciBmdW5jdGlvbiB0byBiZSBjYWxsZWQgb24gZWFjaCBjaGlsZCBpdGVtLlxuICogQHBhcmFtIHtbdHlwZV19ICAgdGhpc0FyZyAgQ29udGV4dCB0byBzZXQgYHRoaXNgLlxuICovXG5mdW5jdGlvbiBMaXN0JGVhY2goY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICB0aGlzLl9saXN0SXRlbXMuZm9yRWFjaChmdW5jdGlvbihpdGVtLCBpbmRleCkge1xuICAgICAgICBpZiAoaXRlbSkgY2FsbGJhY2suYXBwbHkodGhpcywgYXJndW1lbnRzKTsgLy8gcGFzc2VzIGl0ZW0sIGluZGV4IHRvIGNhbGxiYWNrXG4gICAgICAgIGVsc2UgbG9nZ2VyLndhcm4oJ0xpc3QkZWFjaDogaXRlbScsIGluZGV4LCAnaXMgdW5kZWZpbmVkJyk7XG4gICAgfSwgdGhpc0FyZyB8fCB0aGlzKTtcbn1cblxuXG4vKipcbiAqIEZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogRGVzdHJveXMgdGhlIGxpc3RcbiAqL1xuZnVuY3Rpb24gTGlzdCRkZXN0cm95KCkge1xuICAgIGlmICh0aGlzLml0ZW1TYW1wbGUpIHRoaXMuaXRlbVNhbXBsZS5kZXN0cm95KHRydWUpO1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnRGYWNldCA9IHJlcXVpcmUoJy4uL2NfZmFjZXQnKVxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NmX3JlZ2lzdHJ5JylcbiAgICAsIE1vZGVsID0gcmVxdWlyZSgnLi4vLi4vbW9kZWwnKVxuICAgICwgTWl4aW4gPSByZXF1aXJlKCcuLi8uLi9hYnN0cmFjdC9taXhpbicpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cblxuLy8gZ2VuZXJpYyBkcmFnIGhhbmRsZXIsIHNob3VsZCBiZSBvdmVycmlkZGVuXG52YXIgTW9kZWxGYWNldCA9IF8uY3JlYXRlU3ViY2xhc3MoQ29tcG9uZW50RmFjZXQsICdNb2RlbCcpO1xuXG5fLmV4dGVuZFByb3RvKE1vZGVsRmFjZXQsIHtcbiAgICBpbml0OiBNb2RlbEZhY2V0JGluaXQsXG4gICAgZ2V0U3RhdGU6IE1vZGVsRmFjZXQkZ2V0U3RhdGUsXG4gICAgc2V0U3RhdGU6IE1vZGVsRmFjZXQkc2V0U3RhdGUsXG4gICAgX2NyZWF0ZU1lc3NlbmdlcjogTW9kZWxGYWNldCRfY3JlYXRlTWVzc2VuZ2VyLFxuICAgIGRlc3Ryb3k6IE1vZGVsRmFjZXQkZGVzdHJveVxufSk7XG5cbmZhY2V0c1JlZ2lzdHJ5LmFkZChNb2RlbEZhY2V0KTtcblxubW9kdWxlLmV4cG9ydHMgPSBNb2RlbEZhY2V0O1xuXG5cbi8qKlxuICogRXhwb3NlIE1vZGVsIGNsYXNzIG1ldGhvZHMgb24gTW9kZWxGYWNldFxuICovXG5Nb2RlbC51c2VXaXRoKE1vZGVsRmFjZXQsICdtJyk7XG5cblxuZnVuY3Rpb24gTW9kZWxGYWNldCRpbml0KCkge1xuICAgIHRoaXMubSA9IG5ldyBNb2RlbCh0aGlzLmNvbmZpZy5kYXRhLCB0aGlzKTtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIC8vIHRoaXMubS5wcm94eU1ldGhvZHModGhpcyk7IC8vIENyZWF0ZXMgbW9kZWwncyBtZXRob2RzIGRpcmVjdGx5IG9uIGZhY2V0XG59XG5cblxuLyoqXG4gKiBNb2RlbEZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogQ2FsbGVkIGJ5IGBDb21wb25lbnQucHJvdG90eXBlLmdldFN0YXRlYCB0byBnZXQgZmFjZXQncyBzdGF0ZVxuICogU2ltcGx5IHJldHVybnMgbW9kZWwgZGF0YVxuICpcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gTW9kZWxGYWNldCRnZXRTdGF0ZSgpIHtcbiAgICB2YXIgbW9kZWxWYWx1ZSA9IHRoaXMubS5nZXQoKTtcbiAgICBpZiAodHlwZW9mIG1vZGVsVmFsdWUgPT0gJ29iamVjdCcpXG4gICAgICAgIG1vZGVsVmFsdWUgPSBfLmRlZXBDbG9uZShtb2RlbFZhbHVlKTtcbiAgICByZXR1cm4geyBzdGF0ZTogbW9kZWxWYWx1ZSB9O1xufVxuXG5cbi8qKlxuICogTW9kZWxGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIENhbGxlZCBieSBgQ29tcG9uZW50LnByb3RvdHlwZS5zZXRTdGF0ZWAgdG8gc2V0IGZhY2V0J3Mgc3RhdGVcbiAqIFNpbXBseSBzZXRzIG1vZGVsIGRhdGFcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc3RhdGUgZGF0YSB0byBzZXQgb24gZmFjZXQncyBtb2RlbFxuICovXG5mdW5jdGlvbiBNb2RlbEZhY2V0JHNldFN0YXRlKHN0YXRlKSB7XG4gICAgcmV0dXJuIHRoaXMubS5zZXQoc3RhdGUuc3RhdGUpO1xufVxuXG5cbmZ1bmN0aW9uIE1vZGVsRmFjZXQkX2NyZWF0ZU1lc3NlbmdlcigpIHsgLy8gQ2FsbGVkIGJ5IGluaGVyaXRlZCBpbml0XG4gICAgdGhpcy5fbWVzc2VuZ2VyID0gdGhpcy5tLl9tZXNzZW5nZXI7XG59XG5cblxuZnVuY3Rpb24gTW9kZWxGYWNldCRkZXN0cm95KCkge1xuICAgIHRoaXMubS5kZXN0cm95KCk7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmRlc3Ryb3kuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudEZhY2V0ID0gcmVxdWlyZSgnLi4vY19mYWNldCcpXG4gICAgLCBmYWNldHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY2ZfcmVnaXN0cnknKVxuICAgICwgTW9kZWwgPSByZXF1aXJlKCcuLi8uLi9tb2RlbCcpXG5cbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG4vLyBnZW5lcmljIGRyYWcgaGFuZGxlciwgc2hvdWxkIGJlIG92ZXJyaWRkZW5cbnZhciBPcHRpb25zID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ09wdGlvbnMnKTtcblxuXy5leHRlbmRQcm90byhPcHRpb25zLCB7XG4gICAgaW5pdDogT3B0aW9ucyRpbml0LFxuICAgIGRlc3Ryb3k6IE9wdGlvbnMkZGVzdHJveSxcbiAgICBfY3JlYXRlTWVzc2VuZ2VyOiBPcHRpb25zJF9jcmVhdGVNZXNzZW5nZXJcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoT3B0aW9ucyk7XG5cbm1vZHVsZS5leHBvcnRzID0gT3B0aW9ucztcblxuXG5mdW5jdGlvbiBPcHRpb25zJGluaXQoKSB7XG4gICAgdGhpcy5tID0gbmV3IE1vZGVsKHRoaXMuY29uZmlnLm9wdGlvbnMsIHRoaXMpO1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgdGhpcy5tLnByb3h5TWV0aG9kcyh0aGlzKTsgLy8gQ3JlYXRlcyBtb2RlbCdzIG1ldGhvZHMgZGlyZWN0bHkgb24gZmFjZXRcbn1cblxuXG5mdW5jdGlvbiBPcHRpb25zJF9jcmVhdGVNZXNzZW5nZXIoKSB7IC8vIENhbGxlZCBieSBpbmhlcml0ZWQgaW5pdFxuICAgIHRoaXMuX21lc3NlbmdlciA9IHRoaXMubS5fbWVzc2VuZ2VyO1xufVxuXG5cbmZ1bmN0aW9uIE9wdGlvbnMkZGVzdHJveSgpIHtcbiAgICB0aGlzLm0uZGVzdHJveSgpO1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vIDxhIG5hbWU9XCJjb21wb25lbnRzLWZhY2V0cy10ZW1wbGF0ZVwiPjwvYT5cbi8vICMjI3RlbXBsYXRlIGZhY2V0XG5cbi8vIHNpbXBsaWZpZXMgcmVuZGVyaW5nIG9mIGNvbXBvbmVudCBlbGVtZW50IGZyb20gdGVtcGxhdGUuXG4vLyAgIEFueSB0ZW1wbGF0aW5nIGVuZ2luZyBjYW4gYmUgdXNlZCB0aGF0IHN1cHBvcnRzIHRlbXBsYXRlIGNvbXBpbGF0aW9uXG4vLyAgIChvciB5b3UgY2FuIG1vY2sgdGhpcyBjb21waWxhdGlvbiBlYXNpbHkgYnkgY3JlYXRpbmcgY2xvc3VyZSBzdG9yaW5nXG4vLyAgIHRlbXBsYXRlIHN0cmluZyBpbiBjYXNlIHlvdXIgZW5naW5lIGRvZXNuJ3Qgc3VwcG9ydCBjb21waWxhdGlvbikuXG4vLyAgIEJ5IGRlZmF1bHQgbWlsbyB1c2VzIFtkb1RdKCksIHRoZSBtb3N0IHZlcnNhdGlsZSwgY29uc2Npc2UgYW5kIGF0IHRoZVxuLy8gICBzYW1lIHRpbWUgdGhlIGZhc3Rlc3QgdGVtcGxhdGluZyBlbmdpbmUuXG4vLyAgIElmIHlvdSB1c2UgbWlsbyBpbiBicm93c2VyLCBpdCBpcyB0aGUgcGFydCBvZiBtaWxvIGJ1bmRsZSBhbmQgYXZhaWxhYmxlXG4vLyAgIGFzIGdsb2JhbCB2YXJpYWJsZSBgZG9UYC5cblxudmFyIENvbXBvbmVudEZhY2V0ID0gcmVxdWlyZSgnLi4vY19mYWNldCcpXG4gICAgLCBmYWNldHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY2ZfcmVnaXN0cnknKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvY2hlY2snKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9sb2dnZXInKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgYmluZGVyID0gcmVxdWlyZSgnLi4vLi4vYmluZGVyJyk7XG5cblxuLy8gZGF0YSBtb2RlbCBjb25uZWN0aW9uIGZhY2V0XG52YXIgVGVtcGxhdGUgPSBfLmNyZWF0ZVN1YmNsYXNzKENvbXBvbmVudEZhY2V0LCAnVGVtcGxhdGUnKTtcblxuXy5leHRlbmRQcm90byhUZW1wbGF0ZSwge1xuICAgIGluaXQ6IFRlbXBsYXRlJGluaXQsXG4gICAgc3RhcnQ6IFRlbXBsYXRlJHN0YXJ0LFxuICAgIHNldDogVGVtcGxhdGUkc2V0LFxuICAgIGdldENvbXBpbGVkOiBUZW1wbGF0ZSRnZXRDb21waWxlZCxcbiAgICByZW5kZXI6IFRlbXBsYXRlJHJlbmRlcixcbiAgICBiaW5kZXI6IFRlbXBsYXRlJGJpbmRlclxuXG4gICAgLy8gX3JlYXR0YWNoOiBfcmVhdHRhY2hFdmVudHNPbkVsZW1lbnRDaGFuZ2Vcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoVGVtcGxhdGUpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFRlbXBsYXRlO1xuXG5cbmZ1bmN0aW9uIFRlbXBsYXRlJGluaXQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIC8vIHRlbXBsYXRlcyBhcmUgaW50ZXJwb2xhdGVkIHdpdGggZGVmYXVsdCAoZG9UKSBvciBjb25maWd1cmVkIGVuZ2luZSAodGhpcy5jb25maWcuY29tcGlsZSlcbiAgICAvLyB1bmxlc3MgdGhpcy5jb25maWcuaW50ZXJwb2xhdGUgaXMgZmFsc2VcbiAgICB2YXIgY29tcGlsZSA9IHRoaXMuY29uZmlnLmludGVycG9sYXRlID09PSBmYWxzZVxuICAgICAgICAgICAgICAgICAgICA/IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICA6IHRoaXMuY29uZmlnLmNvbXBpbGUgfHwgbWlsby5jb25maWcudGVtcGxhdGUuY29tcGlsZTtcblxuICAgIHRoaXMuc2V0KHRoaXMuY29uZmlnLnRlbXBsYXRlIHx8ICcnLCBjb21waWxlLCB0aGlzLmNvbmZpZy5jb21waWxlT3B0aW9ucyk7XG59XG5cblxuZnVuY3Rpb24gVGVtcGxhdGUkc3RhcnQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLnN0YXJ0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgaWYgKHRoaXMuY29uZmlnLmF1dG9SZW5kZXIpIHtcbiAgICAgICAgdGhpcy5yZW5kZXIoKTtcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmF1dG9CaW5kZXIpXG4gICAgICAgICAgICB0aGlzLmJpbmRlcigpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBUZW1wbGF0ZSRnZXRDb21waWxlZCgpIHtcbiAgICByZXR1cm4gdGhpcy5fdGVtcGxhdGU7XG59XG5cblxuZnVuY3Rpb24gVGVtcGxhdGUkc2V0KHRlbXBsYXRlU3RyLCBjb21waWxlLCBjb21waWxlT3B0aW9ucykge1xuICAgIGNoZWNrKHRlbXBsYXRlU3RyLCBNYXRjaC5PbmVPZihTdHJpbmcsIEZ1bmN0aW9uKSk7XG4gICAgY2hlY2soY29tcGlsZSwgTWF0Y2guT3B0aW9uYWwoRnVuY3Rpb24pKTtcblxuICAgIGlmICh0eXBlb2YgdGVtcGxhdGVTdHIgPT0gJ2Z1bmN0aW9uJylcbiAgICAgICAgdGhpcy5fdGVtcGxhdGUgPSB0ZW1wbGF0ZVN0cjtcbiAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5fdGVtcGxhdGVTdHIgPSB0ZW1wbGF0ZVN0cjtcbiAgICAgICAgaWYgKGNvbXBpbGUpXG4gICAgICAgICAgICB0aGlzLl9jb21waWxlID0gY29tcGlsZTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgY29tcGlsZSA9IHRoaXMuX2NvbXBpbGU7XG5cbiAgICAgICAgaWYgKGNvbXBpbGUpXG4gICAgICAgICAgICB0aGlzLl90ZW1wbGF0ZSA9IGNvbXBpbGUodGVtcGxhdGVTdHIsIGNvbXBpbGVPcHRpb25zKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcztcbn1cblxuXG5mdW5jdGlvbiBUZW1wbGF0ZSRyZW5kZXIoZGF0YSkgeyAvLyB3ZSBuZWVkIGRhdGEgb25seSBpZiB1c2UgdGVtcGxhdGluZyBlbmdpbmVcbiAgICB0aGlzLm93bmVyLmVsLmlubmVySFRNTCA9IHRoaXMuX3RlbXBsYXRlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gdGhpcy5fdGVtcGxhdGUoZGF0YSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiB0aGlzLl90ZW1wbGF0ZVN0cjtcblxuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbmZ1bmN0aW9uIFRlbXBsYXRlJGJpbmRlcigpIHtcbiAgICBpZiAodGhpcy5vd25lci5jb250YWluZXIpXG4gICAgICAgIHJldHVybiB0aGlzLm93bmVyLmNvbnRhaW5lci5iaW5kZXIoKTtcbiAgICBlbHNlXG4gICAgICAgIGxvZ2dlci5lcnJvcignVGVtcGxhdGVGYWNldDogQmluZGVyIGNhbGxlZCB3aXRob3V0IGNvbnRhaW5lciBmYWNldC4nKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudEZhY2V0ID0gcmVxdWlyZSgnLi4vY19mYWNldCcpXG4gICAgLCBmYWNldHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY2ZfcmVnaXN0cnknKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbi8qKlxuICogVHJhbnNmZXIgZmFjZXQgaXMgZGVzaWduZWQgZm9yIGNvbXBvbmVudHMgdG8gYmUgYWJsZSB0byByZXByZXNlbnQgb3RoZXIgY29tcG9uZW50c1xuICogSWYgYSBbQ29tcG9uZW50XSguLi9jX2NsYXNzLmpzLmh0bWwpIGhhcyBUcmFuc2ZlciBmYWNldCwgd2hlbiBgQ29tcG9uZW50LmdldFN0YXRlYCBpcyBjYWxsZWQgZm9yIHRoaXMgY29tcG9uZXQgaXQgcmV0dXJucyBwcmV2aW91c2x5IHNhdmVkIGRhdGEsIHBvc3NpYmx5IGZyb20gYW5vdGhlciBjb21wb25lbnQuXG4gKiBGb3IgZXhhbXBsZSwgYSBsaXN0IG9mIGRvY3VtZW50cyBjYW4gdXNlIHRoaXMgZmFjZXQgc28gdGhhdCBlYWNoIGl0ZW0gaW4gdGhlIGxpc3QgY2FuIHN0b3JlIGFjdHVhbCBkb2N1bWVudCBjb21wb25lbnQgb24gaXQuXG4gKi9cbnZhciBUcmFuc2ZlciA9IF8uY3JlYXRlU3ViY2xhc3MoQ29tcG9uZW50RmFjZXQsICdUcmFuc2ZlcicpO1xuXG5fLmV4dGVuZFByb3RvKFRyYW5zZmVyLCB7XG4gICAgaW5pdDogVHJhbnNmZXIkaW5pdCxcbiAgICBnZXRTdGF0ZTogVHJhbnNmZXIkZ2V0U3RhdGUsXG4gICAgc2V0U3RhdGU6IFRyYW5zZmVyJHNldFN0YXRlLFxuICAgIHNldEFjdGl2ZVN0YXRlOiBUcmFuc2ZlciRzZXRBY3RpdmVTdGF0ZSxcbiAgICBzZXRTdGF0ZVdpdGhLZXk6IFRyYW5zZmVyJHNldFN0YXRlV2l0aEtleSxcbiAgICBnZXRTdGF0ZVdpdGhLZXk6IFRyYW5zZmVyJGdldFN0YXRlV2l0aEtleSxcbiAgICBnZXRDb21wb25lbnRNZXRhOiBUcmFuc2ZlciRnZXRDb21wb25lbnRNZXRhXG59KTtcblxuZmFjZXRzUmVnaXN0cnkuYWRkKFRyYW5zZmVyKTtcblxubW9kdWxlLmV4cG9ydHMgPSBUcmFuc2ZlcjtcblxuXG5mdW5jdGlvbiBUcmFuc2ZlciRpbml0KCkge1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgdGhpcy5fYWN0aXZlU3RhdGUgPSAnJztcbiAgICB0aGlzLl9kZWZhdWx0S2V5ID0gJyc7XG4gICAgdGhpcy5fc3RhdGUgPSB7fTtcbn1cblxuXG4vKipcbiAqIFRyYW5zZmVyIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyB0cmFuc2ZlciBzdGF0ZSBmb3IgY29tcG9uZW50LiBDYW4gYmUgb2J0YWluZWQgZnJvbSBhbm90aGVyIGNvbXBvbmVudCBieSB1c2luZyBgQ29tcG9uZW50LmdldFN0YXRlYFxuICpcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gVHJhbnNmZXIkZ2V0U3RhdGUoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3N0YXRlW3RoaXMuX2FjdGl2ZVN0YXRlXSB8fCB0aGlzLl9zdGF0ZVt0aGlzLl9kZWZhdWx0S2V5XTtcbn1cblxuXG4vKipcbiAqIFRyYW5zZmVyIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogU2V0cyB0cmFuc2ZlciBzdGF0ZSBmb3IgY29tcG9uZW50LiBDYW4gYmUgb2J0YWluZWQgZnJvbSBhbm90aGVyIGNvbXBvbmVudCBieSB1c2luZyBgQ29tcG9uZW50LmdldFN0YXRlYFxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzdGF0ZVxuICovXG5mdW5jdGlvbiBUcmFuc2ZlciRzZXRTdGF0ZShzdGF0ZSkge1xuICAgIHRoaXMuX3N0YXRlWycnXSA9IHN0YXRlO1xuICAgIHRoaXMuc2V0QWN0aXZlU3RhdGUoJycpO1xufVxuXG4vKipcbiAqIFRyYW5zZmVyIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogU2V0cyB0aGUgYWN0aXZlIHN0YXRlICh1c2VkIGJ5IGdldFN0YXRlKVxuICogQHBhcmFtIHtbdHlwZV19IGtleSBbZGVzY3JpcHRpb25dXG4gKi9cbmZ1bmN0aW9uIFRyYW5zZmVyJHNldEFjdGl2ZVN0YXRlKGtleSkge1xuICAgIHRoaXMuX2FjdGl2ZVN0YXRlID0ga2V5O1xufVxuXG4vKipcbiAqIFRyYW5zZmVyIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogU2V0cyB0cmFuc2ZlciBzdGF0ZSBmb3IgY29tcG9uZW50IHdpdGhvdXQgZGVmYXVsdCBrZXkuIENhbiBiZSBvYnRhaW5lZCBmcm9tIGFub3RoZXIgY29tcG9uZW50IGJ5IHVzaW5nIGBDb21wb25lbnQuZ2V0U3RhdGVgXG4gKiBXaGVuIHRoZSBhY3RpdmUgc3RhdGUgaXMgc2V0IHRvIHRoZSBleHBlY3RlZCBrZXlcbiAqIEBwYXJhbSB7W3R5cGVdfSBrZXkgICBbZGVzY3JpcHRpb25dXG4gKiBAcGFyYW0ge1t0eXBlXX0gc3RhdGUgW2Rlc2NyaXB0aW9uXVxuICogQHBhcmFtIHtCb29sZWFufSBpc0RlZmF1bHRLZXkgKE9wdGlvbmFsKVxuICovXG5mdW5jdGlvbiBUcmFuc2ZlciRzZXRTdGF0ZVdpdGhLZXkoa2V5LCBzdGF0ZSwgaXNEZWZhdWx0S2V5KSB7XG4gICAgaWYgKCFrZXkpIHRocm93IG5ldyBFcnJvcignVHJhbnNmZXIkc2V0U3RhdGVXaXRoS2V5OiBubyBrZXknKTtcblxuICAgIGlmIChpc0RlZmF1bHRLZXkpXG4gICAgICAgIHRoaXMuX2RlZmF1bHRLZXkgPSBrZXk7XG4gICAgZWxzZVxuICAgICAgICB0aGlzLl9kZWZhdWx0S2V5ID0gdGhpcy5fZGVmYXVsdEtleSB8fCBrZXk7XG5cbiAgICB0aGlzLl9zdGF0ZVtrZXldID0gc3RhdGU7XG4gICAgdGhpcy5zZXRBY3RpdmVTdGF0ZShrZXkpO1xufVxuXG5cbmZ1bmN0aW9uIFRyYW5zZmVyJGdldFN0YXRlV2l0aEtleShrZXkpIHtcbiAgICByZXR1cm4gdHlwZW9mIGtleSA9PSAnc3RyaW5nJyAmJiB0aGlzLl9zdGF0ZVtrZXldO1xufVxuXG5cbmZ1bmN0aW9uIFRyYW5zZmVyJGdldENvbXBvbmVudE1ldGEoKSB7XG4gICAgdmFyIHN0YXRlID0gdGhpcy5nZXRTdGF0ZSgpO1xuICAgIHJldHVybiB7XG4gICAgICAgIGNvbXBOYW1lOiBzdGF0ZSAmJiBzdGF0ZS5jb21wTmFtZSxcbiAgICAgICAgY29tcENsYXNzOiBzdGF0ZSAmJiBzdGF0ZS5jb21wQ2xhc3NcbiAgICB9O1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2xhc3NSZWdpc3RyeSA9IHJlcXVpcmUoJy4uLy4uL2Fic3RyYWN0L3JlZ2lzdHJ5JylcbiAgICAsIENvbXBvbmVudEZhY2V0ID0gcmVxdWlyZSgnLi4vY19mYWNldCcpO1xuXG5cbi8qKlxuICogYG1pbG8ucmVnaXN0cnkuZmFjZXRzYFxuICogQ29tcG9uZW50IGZhY2V0cyByZWdpc3RyeS4gQW4gaW5zdGFuY2Ugb2YgW0NsYXNzUmVnaXN0cnldKC4uLy4uL2Fic3RyYWN0L3JlZ2lzdHJ5LmpzLmh0bWwpIGNsYXNzIHRoYXQgaXMgdXNlZCBieSBtaWxvIHRvIHJlZ2lzdGVyIGFuZCBmaW5kIGZhY2V0cy5cbiAqL1xuIHZhciBmYWNldHNSZWdpc3RyeSA9IG5ldyBDbGFzc1JlZ2lzdHJ5KENvbXBvbmVudEZhY2V0KTtcblxuXG4vLyBBZGRzIGNvbW1vbiBhbmNlc3RvciB0byBhbGwgZmFjZXRzIG9mIGNvbXBvbmVudHMgdG8gdGhlIHJlZ2lzdHJ5LlxuZmFjZXRzUmVnaXN0cnkuYWRkKENvbXBvbmVudEZhY2V0KTtcblxubW9kdWxlLmV4cG9ydHMgPSBmYWNldHNSZWdpc3RyeTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY19yZWdpc3RyeScpXG4gICAgLCBmYWNldHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY19mYWNldHMvY2ZfcmVnaXN0cnknKVxuICAgICwgY29tcG9uZW50TmFtZSA9IHJlcXVpcmUoJy4uL3V0aWwvY29tcG9uZW50X25hbWUnKVxuICAgICwgU2NvcGUgPSByZXF1aXJlKCcuL3Njb3BlJylcbiAgICAsIEJpbmRlckVycm9yID0gcmVxdWlyZSgnLi4vdXRpbC9lcnJvcicpLkJpbmRlclxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vdXRpbC9sb2dnZXInKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQ29tcG9uZW50SW5mbztcblxuXG4vKipcbiAqIFNpbXBsZSBjbGFzcyB0byBob2xkIGluZm9ybWF0aW9uIGFsbG93aW5nIHRvIGNyZWF0ZS9jb3B5IGNvbXBvbmVudCB1c2luZyBbYENvbXBvbmVudC5jcmVhdGVgXSguL2NfY2xhc3MuanMuaHRtbCNjcmVhdGUpIGFuZCBbYENvbXBvbmVudC5jb3B5YF0oLi9jX2NsYXNzLmpzLmh0bWwjY29weSkuXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAcGFyYW0ge1Njb3BlfSBzY29wZSBzY29wZSBvYmplY3QgdGhlIGNvbXBvbmVudCBiZWxvZ3MgdG8sIHVzdWFsbHkgZWl0aGVyIHRvcCBsZXZlbCBzY29wZSB0aGF0IHdpbGwgYmUgcmV0dXJuZWQgYnkgW21pbG8uYmluZGVyXSguLi9iaW5kZXIuanMuaHRtbCkgb3IgYHNjb3BlYCBwcm9wZXJ0eSBvZiBbQ29udGFpbmVyXSguL2NfZmFjZXRzL0NvbnRhaW5lci5qcy5odG1sKSBmYWNldCBvZiBjb250YWluaW5nIGNvbXBvbmVudFxuICogQHBhcmFtIHtFbGVtZW50fSBlbCBET00gZWxlbWVudCB0aGUgY29tcG9uZW50IGlzIGF0dGFjaGVkIHRvXG4gKiBAcGFyYW0ge0JpbmRBdHRyaWJ1dGV9IGF0dHIgQmluZEF0dHJpYnV0ZSBpbnN0YW5jZSB0aGF0IHRoZSBjb21wb25lbnQgd2FzIGNyZWF0ZWQgd2l0aFxuICogQHBhcmFtIHtCb29sZWFufSB0aHJvd09uRXJyb3JzIElmIHNldCB0byBmYWxzZSwgdGhlbiBlcnJvcnMgd2lsbCBvbmx5IGJlIGxvZ2dlZCB0byBjb25zb2xlLiBUcnVlIGJ5IGRlZmF1bHQuXG4gKiBAcmV0dXJuIHtDb21wb25lbnRJbmZvfVxuICovXG5mdW5jdGlvbiBDb21wb25lbnRJbmZvKHNjb3BlLCBlbCwgYXR0ciwgdGhyb3dPbkVycm9ycykge1xuICAgIGF0dHIucGFyc2UoKS52YWxpZGF0ZSgpO1xuXG4gICAgdGhpcy5zY29wZSA9IHNjb3BlO1xuICAgIHRoaXMuZWwgPSBlbDtcbiAgICB0aGlzLmF0dHIgPSBhdHRyO1xuICAgIHRoaXMubmFtZSA9IGF0dHIuY29tcE5hbWU7XG4gICAgdGhpcy5Db21wb25lbnRDbGFzcyA9IGdldENvbXBvbmVudENsYXNzKGF0dHIsIHRocm93T25FcnJvcnMpO1xuICAgIHRoaXMuZXh0cmFGYWNldHNDbGFzc2VzID0gZ2V0Q29tcG9uZW50RXh0cmFGYWNldHModGhpcy5Db21wb25lbnRDbGFzcywgYXR0ciwgdGhyb3dPbkVycm9ycyk7XG5cbiAgICBpZiAodGhpcy5Db21wb25lbnRDbGFzc1xuICAgICAgICAgICAgJiYgaGFzQ29udGFpbmVyRmFjZXQodGhpcy5Db21wb25lbnRDbGFzcywgdGhpcy5leHRyYUZhY2V0c0NsYXNzZXMpKSB7XG4gICAgICAgIHRoaXMuY29udGFpbmVyID0ge307XG4gICAgfVxufVxuXG5cbi8qKlxuICogIyMjI0NvbXBvbmVudEluZm8gaW5zdGFuY2UgbWV0aG9kcyMjIyNcbiAqIFxuICogLSBbZGVzdHJveV0oI0NvbXBvbmVudEluZm8kZGVzdHJveSlcbiAqIC0gW3JlbmFtZV0oI0NvbXBvbmVudEluZm8kcmVuYW1lKVxuICovXG5fLmV4dGVuZFByb3RvKENvbXBvbmVudEluZm8sIHtcbiAgICBkZXN0cm95OiBDb21wb25lbnRJbmZvJGRlc3Ryb3ksXG4gICAgcmVuYW1lOiBDb21wb25lbnRJbmZvJHJlbmFtZVxufSk7XG5cblxuLyoqXG4gKiBDb21wb25lbnRJbmZvIGluc3RhbmNlIG1ldGhvZFxuICogRGVzdHJveXMgQ29tcG9uZW50SW5mbyBieSByZW1vdmluZyB0aGUgcmVmZXJlbmNlcyB0byBET00gZWxlbWVudFxuICovXG5mdW5jdGlvbiBDb21wb25lbnRJbmZvJGRlc3Ryb3koKSB7XG4gICAgZGVsZXRlIHRoaXMuZWw7XG4gICAgdGhpcy5hdHRyLmRlc3Ryb3koKTtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudEluZm8gaW5zdGFuY2UgbWV0aG9kXG4gKiBSZW5hbWVzIENvbXBvbmVudEluZm8gb2JqZWN0XG4gKlxuICogQHBhcmFtIHtbU3RyaW5nXX0gbmFtZSBvcHRpb25hbCBuZXcgY29tcG9uZW50IG5hbWUsIGdlbmVyYXRlZCBmcm9tIHRpbWVzdGFtcCBieSBkZWZhdWx0XG4gKiBAcGFyYW0ge1tCb29sZWFuXX0gcmVuYW1lSW5TY29wZSBvcHRpb25hbCBmYWxzZSB0byBub3QgcmVuYW1lIENvbXBvbmVudEluZm8gb2JqZWN0IGluIGl0cyBzY29wZSwgdHJ1ZSBieSBkZWZhdWx0XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudEluZm8kcmVuYW1lKG5hbWUsIHJlbmFtZUluU2NvcGUpIHtcbiAgICBuYW1lID0gbmFtZSB8fCBjb21wb25lbnROYW1lKCk7XG4gICAgU2NvcGUucmVuYW1lKHRoaXMsIG5hbWUsIHJlbmFtZUluU2NvcGUpO1xuICAgIHRoaXMuYXR0ci5jb21wTmFtZSA9IG5hbWU7XG4gICAgdGhpcy5hdHRyLmRlY29yYXRlKCk7XG59XG5cblxuZnVuY3Rpb24gZ2V0Q29tcG9uZW50Q2xhc3MoYXR0ciwgdGhyb3dPbkVycm9ycykge1xuICAgIHZhciBDb21wb25lbnRDbGFzcyA9IGNvbXBvbmVudHNSZWdpc3RyeS5nZXQoYXR0ci5jb21wQ2xhc3MpO1xuICAgIGlmICghIENvbXBvbmVudENsYXNzKVxuICAgICAgICByZXBvcnRCaW5kZXJFcnJvcih0aHJvd09uRXJyb3JzLCAnY2xhc3MgJyArIGF0dHIuY29tcENsYXNzICsgJyBpcyBub3QgcmVnaXN0ZXJlZCcpO1xuICAgIHJldHVybiBDb21wb25lbnRDbGFzcztcbn1cblxuXG5mdW5jdGlvbiBnZXRDb21wb25lbnRFeHRyYUZhY2V0cyhDb21wb25lbnRDbGFzcywgYXR0ciwgdGhyb3dPbkVycm9ycykge1xuICAgIHZhciBmYWNldHMgPSBhdHRyLmNvbXBGYWNldHNcbiAgICAgICAgLCBleHRyYUZhY2V0c0NsYXNzZXMgPSB7fTtcblxuICAgIGlmIChBcnJheS5pc0FycmF5KGZhY2V0cykpXG4gICAgICAgIGZhY2V0cy5mb3JFYWNoKGZ1bmN0aW9uKGZjdE5hbWUpIHtcbiAgICAgICAgICAgIGZjdE5hbWUgPSBfLmZpcnN0VXBwZXJDYXNlKGZjdE5hbWUpO1xuICAgICAgICAgICAgaWYgKENvbXBvbmVudENsYXNzLmhhc0ZhY2V0KGZjdE5hbWUpKVxuICAgICAgICAgICAgICAgIHJlcG9ydEJpbmRlckVycm9yKHRocm93T25FcnJvcnMsICdjbGFzcyAnICsgQ29tcG9uZW50Q2xhc3MubmFtZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICArICcgYWxyZWFkeSBoYXMgZmFjZXQgJyArIGZjdE5hbWUpO1xuICAgICAgICAgICAgaWYgKGV4dHJhRmFjZXRzQ2xhc3Nlc1tmY3ROYW1lXSlcbiAgICAgICAgICAgICAgICByZXBvcnRCaW5kZXJFcnJvcih0aHJvd09uRXJyb3JzLCAnY29tcG9uZW50ICcgKyBhdHRyLmNvbXBOYW1lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICsgJyBhbHJlYWR5IGhhcyBmYWNldCAnICsgZmN0TmFtZSk7XG4gICAgICAgICAgICB2YXIgRmFjZXRDbGFzcyA9IGZhY2V0c1JlZ2lzdHJ5LmdldChmY3ROYW1lKTtcbiAgICAgICAgICAgIGV4dHJhRmFjZXRzQ2xhc3Nlc1tmY3ROYW1lXSA9IEZhY2V0Q2xhc3M7XG4gICAgICAgIH0pO1xuXG4gICAgcmV0dXJuIGV4dHJhRmFjZXRzQ2xhc3Nlcztcbn1cblxuXG5mdW5jdGlvbiByZXBvcnRCaW5kZXJFcnJvcih0aHJvd09uRXJyb3JzLCBtZXNzYWdlKSB7XG4gICAgaWYgKHRocm93T25FcnJvcnMgPT09IGZhbHNlKVxuICAgICAgICBsb2dnZXIuZXJyb3IoJ0NvbXBvbmVudEluZm8gYmluZGVyIGVycm9yOicsIG1lc3NhZ2UpO1xuICAgIGVsc2VcbiAgICAgICAgdGhyb3cgbmV3IEJpbmRlckVycm9yKG1lc3NhZ2UpO1xufTtcblxuXG5mdW5jdGlvbiBoYXNDb250YWluZXJGYWNldChDb21wb25lbnRDbGFzcywgZXh0cmFGYWNldHNDbGFzc2VzKSB7XG4gICAgcmV0dXJuIChDb21wb25lbnRDbGFzcy5oYXNGYWNldCgnY29udGFpbmVyJylcbiAgICAgICAgfHwgJ0NvbnRhaW5lcicgaW4gZXh0cmFGYWNldHNDbGFzc2VzXG4gICAgICAgIHx8IF8uc29tZUtleShleHRyYUZhY2V0c0NsYXNzZXMsIGZhY2V0UmVxdWlyZXNDb250YWluZXIpXG4gICAgICAgIHx8IGNsYXNzSGFzRmFjZXRUaGF0UmVxdWlyZXNDb250YWluZXIoKSk7XG5cbiAgICBmdW5jdGlvbiBjbGFzc0hhc0ZhY2V0VGhhdFJlcXVpcmVzQ29udGFpbmVyKCkge1xuICAgICAgICByZXR1cm4gKENvbXBvbmVudENsYXNzLnByb3RvdHlwZS5mYWNldHNDbGFzc2VzXG4gICAgICAgICAgICAmJiBfLnNvbWVLZXkoQ29tcG9uZW50Q2xhc3MucHJvdG90eXBlLmZhY2V0c0NsYXNzZXMsIGZhY2V0UmVxdWlyZXNDb250YWluZXIpKVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGZhY2V0UmVxdWlyZXNDb250YWluZXIoRmFjZXRDbGFzcykge1xuICAgICAgICByZXR1cm4gRmFjZXRDbGFzcy5yZXF1aXJlc0ZhY2V0KCdjb250YWluZXInKTtcbiAgICB9XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDbGFzc1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vYWJzdHJhY3QvcmVnaXN0cnknKVxuICAgICwgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi9jX2NsYXNzJyk7XG5cbi8qKlxuICogYG1pbG8ucmVnaXN0cnkuY29tcG9uZW50c2BcbiAqIEFuIGluc3RhbmNlIG9mIFtDbGFzc1JlZ2lzdHJ5XSguLi9hYnN0cmFjdC9yZWdpc3RyeS5qcy5odG1sKSBjbGFzcyB0aGF0IGlzIHVzZWQgYnkgbWlsbyB0byByZWdpc3RlciBhbmQgZmluZCBjb21wb25lbnRzLlxuICovXG52YXIgY29tcG9uZW50c1JlZ2lzdHJ5ID0gbmV3IENsYXNzUmVnaXN0cnkoQ29tcG9uZW50KTtcblxuLy8gYWRkIGNvbW1vbiBhbmNlc3RvciB0byBhbGwgY29tcG9uZW50cyB0byB0aGUgcmVnaXN0cnkuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKENvbXBvbmVudCk7XG5cbm1vZHVsZS5leHBvcnRzID0gY29tcG9uZW50c1JlZ2lzdHJ5O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5cbnZhciBjb21wb25lbnRVdGlscyA9IG1vZHVsZS5leHBvcnRzID0ge1xuICAgIGlzQ29tcG9uZW50OiBpc0NvbXBvbmVudCxcbiAgICBnZXRDb21wb25lbnQ6IGdldENvbXBvbmVudCxcbiAgICBnZXRDb250YWluaW5nQ29tcG9uZW50OiBnZXRDb250YWluaW5nQ29tcG9uZW50LFxuICAgIF9tYWtlQ29tcG9uZW50Q29uZGl0aW9uRnVuYzogX21ha2VDb21wb25lbnRDb25kaXRpb25GdW5jXG59O1xuXG5cbi8qKlxuICogaXNDb21wb25lbnRcbiAqXG4gKiBDaGVja3MgaWYgZWxlbWVudCBoYXMgYSBjb21wb25lbnQgYXR0YWNoZWQgdG8gaXQgYnlcbiAqIGNoZWNraW5nIHRoZSBwcmVzZW5jZSBvZiBwcm9wZXJ0eSBkaWZpbmVkIGluIG1pbG8uY29uZmlnXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBlbCBET00gZWxlbWVudFxuICogQHJldHVybiB7Qm9vbGVhbn0gdHJ1ZSwgaWYgaXQgaGFzIG1pbG8gY29tcG9uZW50IGF0dGFjaGVkIHRvIGl0XG4gKi9cbmZ1bmN0aW9uIGlzQ29tcG9uZW50KGVsKSB7XG4gICAgcmV0dXJuIGVsLmhhc093blByb3BlcnR5KGNvbmZpZy5jb21wb25lbnRSZWYpO1xufVxuXG5cbi8qKlxuICogZ2V0Q29tcG9uZW50XG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBlbCBET00gZWxlbWVudFxuICogQHJldHVybiB7Q29tcG9uZW50fSBjb21wb25lbnQgYXR0YWNoZWQgdG8gZWxlbWVudFxuICovXG5mdW5jdGlvbiBnZXRDb21wb25lbnQoZWwpIHtcbiAgICByZXR1cm4gZWwgJiYgZWxbY29uZmlnLmNvbXBvbmVudFJlZl07XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBjbG9zZXN0IGNvbXBvbmVudCB3aGljaCBjb250YWlucyB0aGUgc3BlY2lmaWVkIGVsZW1lbnQsXG4gKiBvcHRpb25hbGx5LCBvbmx5IGNvbXBvbmVudCB0aGF0IHBhc3NlcyBgY29uZGl0aW9uYCB0ZXN0IG9yIGNvbnRhaW5zIHNwZWNpZmllZCBmYWNldFxuICpcbiAqIFVubGVzcyBgcmV0dXJuQ3VycmVudGAgcGFyYW1ldGVyIGlzIGZhbHNlLCB0aGUgZnVuY3Rpb24gd2lsbCByZXR1cm5cbiAqIHRoZSBjdXJyZW50IGNvbXBvbmVudCBvZiB0aGUgZWxlbWVudCAodHJ1ZSBieSBkZWZhdWx0KS5cbiAqXG4gKiBAcGFyYW0ge05vZGV9IG5vZGUgRE9NIEVsZW1lbnQgb3IgdGV4dCBOb2RlXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHJldHVybkN1cnJlbnQgb3B0aW9uYWwgYm9vbGVhbiB2YWx1ZSBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIGNvbXBvbmVudCBvZiB0aGUgZWxlbWVudCBjYW4gYmUgcmV0dXJuZWQuIFRydWUgYnkgZGVmYXVsdCwgc2hvdWxkIGJlIGZhbHNlIHRvIHJldHVybiBvbmx5IGFuY2VzdG9ycy5cbiAqIEBwYXJhbSB7RnVuY3Rpb258U3RyaW5nfSBjb25kaXRpb25PckZhY2V0IG9wdGlvbmFsIGNvbmRpdGlvbiB0aGF0IGNvbXBvbmVudCBzaG91bGQgcGFzcyAob3IgZmFjZXQgbmFtZSBpdCBzaG91bGQgY29udGFpbilcbiAqIEByZXR1cm4ge0NvbXBvbmVudH0gXG4gKi9cbmZ1bmN0aW9uIGdldENvbnRhaW5pbmdDb21wb25lbnQobm9kZSwgcmV0dXJuQ3VycmVudCwgY29uZGl0aW9uT3JGYWNldCkge1xuICAgIC8vIGNoZWNrKG5vZGUsIE5vZGUpOyAtIGNhbid0IGNoZWNrIHRpeXBlIGhlcmUgYXMgaXQgaXMgbW9zdCBsaWtlbHkgY29taW5nIGZyb20gYW5vdGhlciBmcmFtZVxuICAgIGNoZWNrKHJldHVybkN1cnJlbnQsIE1hdGNoLk9wdGlvbmFsKEJvb2xlYW4pKTtcbiAgICBjaGVjayhjb25kaXRpb25PckZhY2V0LCBNYXRjaC5PcHRpb25hbChNYXRjaC5PbmVPZihGdW5jdGlvbiwgU3RyaW5nKSkpO1xuXG4gICAgdmFyIGNvbmRpdGlvbkZ1bmMgPSBfbWFrZUNvbXBvbmVudENvbmRpdGlvbkZ1bmMoY29uZGl0aW9uT3JGYWNldCk7XG5cbiAgICByZXR1cm4gX2dldENvbnRhaW5pbmdDb21wb25lbnQobm9kZSwgcmV0dXJuQ3VycmVudCwgY29uZGl0aW9uRnVuYyk7XG59XG5cblxuZnVuY3Rpb24gX21ha2VDb21wb25lbnRDb25kaXRpb25GdW5jKGNvbmRpdGlvbk9yRmFjZXQpIHtcbiAgICBpZiAodHlwZW9mIGNvbmRpdGlvbk9yRmFjZXQgPT0gJ2Z1bmN0aW9uJylcbiAgICAgICAgcmV0dXJuIGNvbmRpdGlvbk9yRmFjZXQ7XG4gICAgZWxzZSBpZiAodHlwZW9mIGNvbmRpdGlvbk9yRmFjZXQgPT0gJ3N0cmluZycpIHtcbiAgICAgICAgdmFyIGZhY2V0TmFtZSA9IF8uZmlyc3RMb3dlckNhc2UoY29uZGl0aW9uT3JGYWNldCk7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoY29tcCkge1xuICAgICAgICAgICByZXR1cm4gY29tcC5oYXNGYWNldChmYWNldE5hbWUpO1xuICAgICAgICB9O1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBfZ2V0Q29udGFpbmluZ0NvbXBvbmVudChlbCwgcmV0dXJuQ3VycmVudCwgY29uZGl0aW9uRnVuYykge1xuICAgIC8vIFdoZXJlIHRoZSBjdXJyZW50IGVsZW1lbnQgaXMgYSBjb21wb25lbnQgaXQgc2hvdWxkIGJlIHJldHVybmVkXG4gICAgLy8gaWYgcmV0dXJuQ3VycmVudCBpcyB0cnVlIG9yIHVuZGVmaW5lZFxuICAgIGlmIChyZXR1cm5DdXJyZW50ICE9PSBmYWxzZSkge1xuICAgICAgICB2YXIgY29tcCA9IGdldENvbXBvbmVudChlbCk7XG4gICAgICAgIGlmIChjb21wICYmICghIGNvbmRpdGlvbkZ1bmMgfHwgY29uZGl0aW9uRnVuYyhjb21wKSkpXG4gICAgICAgICAgICByZXR1cm4gY29tcDtcbiAgICB9XG5cbiAgICAvLyBXaGVyZSB0aGVyZSBpcyBubyBwYXJlbnQgZWxlbWVudCwgdGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiB1bmRlZmluZWRcbiAgICAvLyBUaGUgcGFyZW50IGVsZW1lbnQgaXMgY2hlY2tlZCByZWN1cnNpdmVseVxuICAgIGlmIChlbC5wYXJlbnROb2RlKVxuICAgICAgICByZXR1cm4gX2dldENvbnRhaW5pbmdDb21wb25lbnQoZWwucGFyZW50Tm9kZSwgdHJ1ZSwgY29uZGl0aW9uRnVuYyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jX2NsYXNzJylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2NfcmVnaXN0cnknKTtcblxuXG52YXIgVmlldyA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnVmlldycsIFsnY29udGFpbmVyJ10pO1xuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKFZpZXcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFZpZXc7XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIE1lc3NlbmdlckFQSSA9IHJlcXVpcmUoJy4uLy4uL21lc3Nlbmdlci9tX2FwaScpXG4gICAgLCBnZXRFbGVtZW50RGF0YUFjY2VzcyA9IHJlcXVpcmUoJy4vZGVfZGF0YScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5cbi8vIGNsYXNzIHRvIGhhbmRsZSBzdWJzY3JpYnRpb25zIHRvIGNoYW5nZXMgaW4gRE9NIGZvciBVSSAobWF5YmUgYWxzbyBjb250ZW50IGVkaXRhYmxlKSBlbGVtZW50c1xuXG4vKipcbiAqIEEgY2xhc3NcbiAqL1xudmFyIERhdGFNc2dBUEkgPSBfLmNyZWF0ZVN1YmNsYXNzKE1lc3NlbmdlckFQSSwgJ0RhdGFNc2dBUEknLCB0cnVlKTtcblxuXG5fLmV4dGVuZFByb3RvKERhdGFNc2dBUEksIHtcbiAgICAvLyBpbXBsZW1lbnRpbmcgTWVzc2FnZVNvdXJjZSBpbnRlcmZhY2VcbiAgICBpbml0OiBEYXRhTXNnQVBJJGluaXQsXG4gICAgdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlOiB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UsXG4gICAgZmlsdGVyU291cmNlTWVzc2FnZTogZmlsdGVyU291cmNlTWVzc2FnZSxcbiAgICBjcmVhdGVJbnRlcm5hbERhdGE6IGNyZWF0ZUludGVybmFsRGF0YSxcblxuICAgIC8vIGNsYXNzIHNwZWNpZmljIG1ldGhvZHNcbiAgICB2YWx1ZTogRGF0YU1zZ0FQSSR2YWx1ZVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRGF0YU1zZ0FQSTtcblxuXG5mdW5jdGlvbiBEYXRhTXNnQVBJJGluaXQoY29tcG9uZW50KSB7XG4gICAgTWVzc2VuZ2VyQVBJLnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICB0aGlzLmNvbXBvbmVudCA9IGNvbXBvbmVudDtcbiAgICB0aGlzLmVsRGF0YSA9IGdldEVsZW1lbnREYXRhQWNjZXNzKGNvbXBvbmVudC5lbCk7XG59XG5cblxuLy8gZ2V0RG9tRWxlbWVudERhdGFWYWx1ZVxuZnVuY3Rpb24gRGF0YU1zZ0FQSSR2YWx1ZSgpIHsgLy8gdmFsdWUgbWV0aG9kXG4gICAgdmFyIGNvbXBvbmVudEdldHRlciA9IHRoaXMuY29tcG9uZW50LmRhdGEuY29uZmlnLmdldDtcbiAgICB2YXIgbmV3VmFsdWUgPSB0eXBlb2YgY29tcG9uZW50R2V0dGVyID09ICdmdW5jdGlvbidcbiAgICAgICAgICAgICAgICAgICAgPyBjb21wb25lbnRHZXR0ZXIuY2FsbCh0aGlzLmNvbXBvbmVudClcbiAgICAgICAgICAgICAgICAgICAgOiB0aGlzLmVsRGF0YS5nZXQodGhpcy5jb21wb25lbnQuZWwpO1xuXG4gICAgdGhpcy5jb21wb25lbnQuZGF0YS5fdmFsdWUgPSBuZXdWYWx1ZTtcblxuICAgIHJldHVybiBuZXdWYWx1ZTtcbn1cblxuXG4vLyBUT0RPOiB0aGlzIGZ1bmN0aW9uIHNob3VsZCByZXR1cm4gcmVsZXZhbnQgRE9NIGV2ZW50IGRlcGVuZGVudCBvbiBlbGVtZW50IHRhZ1xuLy8gQ2FuIGFsc28gaW1wbGVtZW50IGJlZm9yZWRhdGFjaGFuZ2VkIGV2ZW50IHRvIGFsbG93IHByZXZlbnRpbmcgdGhlIGNoYW5nZVxuLy8gdHJhbnNsYXRlVG9Eb21FdmVudFxuZnVuY3Rpb24gdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgICB2YXIgY29tcG9uZW50RXZlbnQgPSB0aGlzLmNvbXBvbmVudC5kYXRhLmNvbmZpZy5ldmVudDtcbiAgICB2YXIgZXZlbnQgPSBjb21wb25lbnRFdmVudCB8fCB0aGlzLmVsRGF0YS5ldmVudCh0aGlzLmNvbXBvbmVudC5lbCk7XG5cbiAgICBpZiAobWVzc2FnZSA9PSAnJyAmJiBldmVudClcbiAgICAgICAgcmV0dXJuIGV2ZW50OyAgLy8gdGhpcy50YWdFdmVudDtcbn1cblxuXG4vLyBmaWx0ZXJEYXRhTWVzc2FnZVxuZnVuY3Rpb24gZmlsdGVyU291cmNlTWVzc2FnZShzb3VyY2VNZXNzYWdlLCBtZXNzYWdlLCBkYXRhKSB7XG4gICAgcmV0dXJuIGRhdGEubmV3VmFsdWUgIT0gZGF0YS5vbGRWYWx1ZTtcbn1cblxuXG5mdW5jdGlvbiBjcmVhdGVJbnRlcm5hbERhdGEoc291cmNlTWVzc2FnZSwgbWVzc2FnZSwgZGF0YSkge1xuICAgIHZhciBvbGRWYWx1ZSA9IHRoaXMuY29tcG9uZW50LmRhdGEuX3ZhbHVlXG4gICAgICAgICwgbmV3VmFsdWUgPSB0aGlzLnZhbHVlKCk7XG5cbiAgICB2YXIgaW50ZXJuYWxEYXRhID0geyBcbiAgICAgICAgcGF0aDogJycsXG4gICAgICAgIHR5cGU6ICdjaGFuZ2VkJyxcbiAgICAgICAgb2xkVmFsdWU6IG9sZFZhbHVlLFxuICAgICAgICBuZXdWYWx1ZTogbmV3VmFsdWVcbiAgICB9O1xuICAgIHJldHVybiBpbnRlcm5hbERhdGE7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG4vKipcbiAqIFJldHVybnMgZGF0YSBhY2Nlc3MgbWV0aG9kcyBhbmQgZXZlbnRzIGZvciBnaXZlbiBET00gZWxlbWVudC5cbiAqIFVzZWQgYnkgW0RhdGFdKC4uL2NfZmFjZXRzL0RhdGEuanMuaHRtbCkgZmFjZXQgYW5kIGJ5IFtEYXRhTXNnQVBJXSguL2RhdGEuanMuaHRtbClcbiAqXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbnZhciBnZXRFbGVtZW50RGF0YUFjY2VzcyA9IGZ1bmN0aW9uKGVsKSB7XG4gICAgdmFyIHRhZ05hbWUgPSBlbC50YWdOYW1lLnRvTG93ZXJDYXNlKClcbiAgICAgICAgLCBlbERhdGEgPSBkb21FbGVtZW50c0RhdGFBY2Nlc3NbdGFnTmFtZV07XG4gICAgcmV0dXJuIGVsRGF0YSB8fCBkb21FbGVtZW50c0RhdGFBY2Nlc3MuYnlEZWZhdWx0O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGdldEVsZW1lbnREYXRhQWNjZXNzO1xuXG5cbi8qKlxuICogRGF0YSBhY2Nlc3MgbWV0aG9kcyBhbmQgZXZlbnRzIGZvciBET00gZWxlbWVudHMuXG4gKi9cbnZhciBkb21FbGVtZW50c0RhdGFBY2Nlc3MgPSB7XG4gICAgYnlEZWZhdWx0OiB7XG4gICAgICAgIHByb3BlcnR5OiAnaW5uZXJIVE1MJyxcbiAgICB9LFxuICAgICdkaXYnOiB7XG4gICAgICAgIHByb3BlcnR5OiAnaW5uZXJIVE1MJywgLy8gaGFjaywgc2hvdWxkIGJlIGlubmVySFRNTD8gdG8gbWFrZSB3b3JrIHdpdGggRWRpdGFibGUgZmFjZXRcbiAgICAgICAgLy8gZXZlbnQ6ICdpbnB1dCdcbiAgICB9LFxuICAgICdzcGFuJzoge1xuICAgICAgICBwcm9wZXJ0eTogJ2lubmVySFRNTCcsXG4gICAgICAgIGV2ZW50OiAnaW5wdXQnXG4gICAgfSxcbiAgICAncCc6IHtcbiAgICAgICAgcHJvcGVydHk6ICdpbm5lckhUTUwnLFxuICAgICAgICBldmVudDogJ2lucHV0J1xuICAgIH0sXG4gICAgJ2lucHV0Jzoge1xuICAgICAgICBwcm9wZXJ0eTogaW5wdXREYXRhUHJvcGVydHksXG4gICAgICAgIGV2ZW50OiBpbnB1dENoYW5nZUV2ZW50XG4gICAgfSxcbiAgICAndGV4dGFyZWEnOiB7XG4gICAgICAgIHByb3BlcnR5OiAndmFsdWUnLFxuICAgICAgICBldmVudDogJ2lucHV0J1xuICAgIH0sXG4gICAgJ3NlbGVjdCc6IHtcbiAgICAgICAgcHJvcGVydHk6ICd2YWx1ZScsXG4gICAgICAgIGV2ZW50OiAnY2hhbmdlJ1xuICAgIH0sXG4gICAgJ2ltZyc6IHtcbiAgICAgICAgcHJvcGVydHk6ICdzcmMnXG4gICAgfSxcbiAgICAnY2FwdGlvbic6IHtcbiAgICAgICAgcHJvcGVydHk6ICdpbm5lckhUTUwnLFxuICAgICAgICBldmVudDogJ2lucHV0J1xuICAgIH0sXG4gICAgJ3RoZWFkJzoge1xuICAgICAgICBwcm9wZXJ0eTogJ2lubmVySFRNTCcsXG4gICAgICAgIGV2ZW50OiAnaW5wdXQnXG4gICAgfSxcbiAgICAndGJvZHknOiB7XG4gICAgICAgIHByb3BlcnR5OiAnaW5uZXJIVE1MJyxcbiAgICAgICAgZXZlbnQ6ICdpbnB1dCdcbiAgICB9LFxuICAgICd0Zm9vdCc6IHtcbiAgICAgICAgcHJvcGVydHk6ICdpbm5lckhUTUwnLFxuICAgICAgICBldmVudDogJ2lucHV0J1xuICAgIH1cbn07XG5cblxuLy8gY29udmVydCBzdHJpbmdzIHRvIGZ1bmN0aW9ucyBhbmQgY3JlYXRlIGdldHNldCBtZXRob2RzXG5fLmVhY2hLZXkoZG9tRWxlbWVudHNEYXRhQWNjZXNzLCBmdW5jdGlvbih0YWdJbmZvKSB7XG4gICAgdmFyIHByb3BlcnR5ID0gdGFnSW5mby5wcm9wZXJ0eVxuICAgICAgICAsIGV2ZW50ID0gdGFnSW5mby5ldmVudDtcbiAgICBpZiAodHlwZW9mIHByb3BlcnR5ICE9ICdmdW5jdGlvbicpXG4gICAgICAgIHRhZ0luZm8ucHJvcGVydHkgPSBmdW5jdGlvbigpIHsgcmV0dXJuIHByb3BlcnR5OyB9O1xuICAgIHZhciBwcm9wRnVuYyA9IHRhZ0luZm8ucHJvcGVydHk7XG4gICAgaWYgKHR5cGVvZiBldmVudCAhPSAnZnVuY3Rpb24nKVxuICAgICAgICB0YWdJbmZvLmV2ZW50ID0gZnVuY3Rpb24oKSB7IHJldHVybiBldmVudDsgfTtcbiAgICBpZiAoISB0YWdJbmZvLmdldClcbiAgICAgICAgdGFnSW5mby5nZXQgPSBmdW5jdGlvbihlbCkgeyByZXR1cm4gZWxbcHJvcEZ1bmMoZWwpXTsgfVxuICAgIGlmICghIHRhZ0luZm8uc2V0KVxuICAgICAgICB0YWdJbmZvLnNldCA9IGZ1bmN0aW9uKGVsLCB2YWx1ZSkge1xuICAgICAgICAgICAgcmV0dXJuIChlbFtwcm9wRnVuYyhlbCldID0gdHlwZW9mIHZhbHVlID09ICd1bmRlZmluZWQnID8gJycgOiB2YWx1ZSk7XG4gICAgICAgIH1cbn0pO1xuXG5cbi8qKlxuICogVHlwZXMgb2YgaW5wdXQgZWxlbWVudHNcbiAqL1xudmFyIGlucHV0RWxlbWVudFR5cGVzID0ge1xuICAgIGJ5RGVmYXVsdDoge1xuICAgICAgICBwcm9wZXJ0eTogJ3ZhbHVlJyxcbiAgICAgICAgZXZlbnQ6ICdpbnB1dCdcbiAgICB9LFxuICAgICdjaGVja2JveCc6IHtcbiAgICAgICAgcHJvcGVydHk6ICdjaGVja2VkJyxcbiAgICAgICAgZXZlbnQ6ICdjaGFuZ2UnXG4gICAgfSxcbiAgICAncmFkaW8nOiB7XG4gICAgICAgIHByb3BlcnR5OiAnY2hlY2tlZCcsXG4gICAgICAgIGV2ZW50OiAnY2hhbmdlJ1xuICAgIH0sXG4gICAgJ3RleHQnOiB7XG4gICAgICAgIHByb3BlcnR5OiAndmFsdWUnLFxuICAgICAgICBldmVudDogJ2lucHV0J1xuICAgIH1cbn1cblxuXG4vKipcbiAqIFJldHVybiBwcm9wZXJ0eSBvZiBpbnB1dCBlbGVtZW50IHRvIGdldC9zZXQgaXRzIGRhdGFcbiAqXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGlucHV0RGF0YVByb3BlcnR5KGVsKSB7XG4gICAgdmFyIGlucHV0VHlwZSA9IGlucHV0RWxlbWVudFR5cGVzW2VsLnR5cGVdO1xuICAgIHJldHVybiBpbnB1dFR5cGVcbiAgICAgICAgICAgID8gaW5wdXRUeXBlLnByb3BlcnR5XG4gICAgICAgICAgICA6IGlucHV0RWxlbWVudFR5cGVzLmJ5RGVmYXVsdC5wcm9wZXJ0eTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgRE9NIGV2ZW50IHR5cGUgdG8gbGlzdGVuIHRvIHRvIHJlYWN0IHRvIGlucHV0IGVsZW1lbnQgY2hhbmdlXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBlbFxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBpbnB1dENoYW5nZUV2ZW50KGVsKSB7XG4gICAgdmFyIGlucHV0VHlwZSA9IGlucHV0RWxlbWVudFR5cGVzW2VsLnR5cGVdO1xuICAgIHJldHVybiBpbnB1dFR5cGVcbiAgICAgICAgICAgID8gaW5wdXRUeXBlLmV2ZW50XG4gICAgICAgICAgICA6IGlucHV0RWxlbWVudFR5cGVzLmJ5RGVmYXVsdC5ldmVudDtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgTWVzc2VuZ2VyQVBJID0gcmVxdWlyZSgnLi4vLi4vbWVzc2VuZ2VyL21fYXBpJylcblxuXG52YXIgRHJvcE1zZ0FQSSA9IF8uY3JlYXRlU3ViY2xhc3MoTWVzc2VuZ2VyQVBJLCAnRHJvcE1zZ0FQSScsIHRydWUpO1xuXG5cbl8uZXh0ZW5kUHJvdG8oRHJvcE1zZ0FQSSwge1xuICAgIC8vIGltcGxlbWVudGluZyBNZXNzYWdlU291cmNlIGludGVyZmFjZVxuICAgIHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZTogdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlLFxuICAgIGZpbHRlclNvdXJjZU1lc3NhZ2U6IGZpbHRlclNvdXJjZU1lc3NhZ2UsXG59KTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IERyb3BNc2dBUEk7XG5cblxudmFyIGRyb3BFdmVudHNNYXAgPSB7XG4gICAgJ2RyYWdpbic6ICdkcmFnZW50ZXInLFxuICAgICdkcmFnb3V0JzogJ2RyYWdsZWF2ZSdcbn07XG5cblxuZnVuY3Rpb24gdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgICByZXR1cm4gZHJvcEV2ZW50c01hcC5oYXNPd25Qcm9wZXJ0eShtZXNzYWdlKVxuICAgICAgICAgICAgPyBkcm9wRXZlbnRzTWFwW21lc3NhZ2VdXG4gICAgICAgICAgICA6IG1lc3NhZ2U7XG59XG5cbmZ1bmN0aW9uIHJlc2V0RmlsdGVyVmFycygpIHtcbiAgICBkZWxldGUgdGhpcy5fY3VycmVudFRhcmdldDtcbiAgICBkZWxldGUgdGhpcy5faW5zaWRlO1xufVxuXG5mdW5jdGlvbiBmaWx0ZXJTb3VyY2VNZXNzYWdlKHNvdXJjZU1lc3NhZ2UsIG1lc3NhZ2UsIGRhdGEpIHsgLy8gZGF0YSBpcyBET00gZXZlbnQgb2JqZWN0XG4gICAgdmFyIG9rID0gdHJ1ZTtcblxuICAgIGlmIChzb3VyY2VNZXNzYWdlID09ICdkcmFnZW50ZXInICYmIG1lc3NhZ2UgPT0gJ2RyYWdpbicpIHtcbiAgICAgICAgdGhpcy5fY3VycmVudFRhcmdldCA9IGRhdGEudGFyZ2V0O1xuICAgICAgICBvayA9ICF0aGlzLl9pbnNpZGU7XG4gICAgICAgIHRoaXMuX2luc2lkZSA9IHRydWU7XG4gICAgfSBlbHNlIGlmIChzb3VyY2VNZXNzYWdlID09ICdkcmFnbGVhdmUnICYmIG1lc3NhZ2UgPT0gJ2RyYWdvdXQnKSB7XG4gICAgICAgIG9rID0gdGhpcy5fY3VycmVudFRhcmdldCA9PSBkYXRhLnRhcmdldDtcbiAgICAgICAgaWYgKG9rKSByZXNldEZpbHRlclZhcnMuY2FsbCh0aGlzKTtcbiAgICB9IGVsc2UgaWYgKHNvdXJjZU1lc3NhZ2UgPT0gJ2Ryb3AnKSByZXNldEZpbHRlclZhcnMuY2FsbCh0aGlzKTtcblxuICAgIHJldHVybiBvaztcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgRE9NRW1pdHRlclNvdXJjZSA9IHJlcXVpcmUoJy4uLy4uL3NlcnZpY2VzL2RvbV9zb3VyY2UnKVxuICAgICwgTWVzc2FnZVNvdXJjZSA9IHJlcXVpcmUoJy4uLy4uL21lc3Nlbmdlci9tX3NvdXJjZScpXG4gICAgLCBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jX2NsYXNzJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgY2hlY2sgPSByZXF1aXJlKCcuLi8uLi91dGlsL2NoZWNrJylcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2g7XG5cbnZhciBET01FdmVudHNTb3VyY2UgPSBfLmNyZWF0ZVN1YmNsYXNzKERPTUVtaXR0ZXJTb3VyY2UsICdET01FdmVudHNTb3VyY2UnLCB0cnVlKTtcblxuXG5fLmV4dGVuZFByb3RvKERPTUV2ZW50c1NvdXJjZSwge1xuICAgIGluaXQ6IGluaXQsXG4gICAgZGVzdHJveTogRE9NRXZlbnRzU291cmNlJGRlc3Ryb3ksXG4gICAgZW1pdHRlcjogZW1pdHRlclxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRE9NRXZlbnRzU291cmNlO1xuXG5cbnZhciB1c2VDYXB0dXJlUGF0dGVybiA9IC9fX2NhcHR1cmUkL1xuICAgICwgdXNlQ2FwdHVyZVBvc3RmaXggPSAnX19jYXB0dXJlJztcblxuXG4vLyBpbml0IERPTSBldmVudCBzb3VyY2VcbmZ1bmN0aW9uIGluaXQoaG9zdE9iamVjdCwgcHJveHlNZXRob2RzLCBtZXNzZW5nZXJBUElPckNsYXNzLCBjb21wb25lbnQpIHtcbiAgICBjaGVjayhjb21wb25lbnQsIENvbXBvbmVudCk7XG4gICAgdGhpcy5jb21wb25lbnQgPSBjb21wb25lbnQ7XG4gICAgTWVzc2FnZVNvdXJjZS5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbmZ1bmN0aW9uIERPTUV2ZW50c1NvdXJjZSRkZXN0cm95KCkge1xuICAgIE1lc3NhZ2VTb3VyY2UucHJvdG90eXBlLmRlc3Ryb3kuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICBkZWxldGUgdGhpcy5jb21wb25lbnQ7XG59XG5cblxuLy8gZ2V0IERPTSBlbGVtZW50IG9mIGNvbXBvbmVudFxuZnVuY3Rpb24gZW1pdHRlcigpIHtcbiAgICByZXR1cm4gdGhpcy5jb21wb25lbnQuZWw7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vICMjI2NvbXBvbmVudCBpZnJhbWUgc291cmNlXG5cbnZhciBNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi4vLi4vbWVzc2VuZ2VyL21fc291cmNlJylcbiAgICAsIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvY2hlY2snKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9sb2dnZXInKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgRnJhbWVNZXNzYWdlU291cmNlRXJyb3IgPSByZXF1aXJlKCcuLi8uLi91dGlsL2Vycm9yJykuRnJhbWVNZXNzYWdlU291cmNlO1xuXG52YXIgRnJhbWVNZXNzYWdlU291cmNlID0gXy5jcmVhdGVTdWJjbGFzcyhNZXNzYWdlU291cmNlLCAnRnJhbWVNZXNzYWdlU291cmNlJywgdHJ1ZSk7XG5cblxuXy5leHRlbmRQcm90byhGcmFtZU1lc3NhZ2VTb3VyY2UsIHtcbiAgICAvLyBpbXBsZW1lbnRpbmcgTWVzc2FnZVNvdXJjZSBpbnRlcmZhY2VcbiAgICBpbml0OiBpbml0LFxuICAgIGFkZFNvdXJjZVN1YnNjcmliZXI6IGFkZFNvdXJjZVN1YnNjcmliZXIsXG4gICAgcmVtb3ZlU291cmNlU3Vic2NyaWJlcjogcmVtb3ZlU291cmNlU3Vic2NyaWJlcixcbiAgICB0cmlnZ2VyOiB0cmlnZ2VyLFxuXG4gICAgLy9jbGFzcyBzcGVjaWZpYyBtZXRob2RzXG4gICAgZnJhbWVXaW5kb3c6IGZyYW1lV2luZG93LFxuICAgIGhhbmRsZUV2ZW50OiBoYW5kbGVFdmVudCAgLy8gZXZlbnQgZGlzcGF0Y2hlciAtIGFzIGRlZmluZWQgYnkgRXZlbnQgRE9NIEFQSVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRnJhbWVNZXNzYWdlU291cmNlO1xuXG5cbmZ1bmN0aW9uIGluaXQoaG9zdE9iamVjdCwgcHJveHlNZXRob2RzLCBtZXNzZW5nZXJBUElPckNsYXNzLCBjb21wb25lbnQpIHtcbiAgICBjaGVjayhjb21wb25lbnQsIENvbXBvbmVudCk7XG4gICAgdGhpcy5jb21wb25lbnQgPSBjb21wb25lbnQ7XG5cbiAgICBpZiAoY29tcG9uZW50LmVsLnRhZ05hbWUudG9Mb3dlckNhc2UoKSAhPSAnaWZyYW1lJylcbiAgICAgICAgdGhyb3cgbmV3IEZyYW1lTWVzc2FnZVNvdXJjZUVycm9yKCdjb21wb25lbnQgZm9yIEZyYW1lTWVzc2FnZVNvdXJjZSBjYW4gb25seSBiZSBhdHRhY2hlZCB0byBpZnJhbWUgZWxlbWVudCcpO1xuXG4gICAgTWVzc2FnZVNvdXJjZS5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbmZ1bmN0aW9uIGZyYW1lV2luZG93KCkge1xuICAgIHJldHVybiB0aGlzLmNvbXBvbmVudC5lbC5jb250ZW50V2luZG93O1xufVxuXG5cbi8vIGFkZElGcmFtZU1lc3NhZ2VMaXN0ZW5lclxuZnVuY3Rpb24gYWRkU291cmNlU3Vic2NyaWJlcihzb3VyY2VNZXNzYWdlKSB7XG4gICAgdmFyIHdpbiA9IHRoaXMuZnJhbWVXaW5kb3coKTtcbiAgICBpZiAod2luKSB3aW4uYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIHRoaXMsIGZhbHNlKTtcbiAgICBlbHNlIGxvZ2dlci53YXJuKCdGcmFtZU1lc3NhZ2VTb3VyY2U6IGZyYW1lIHdpbmRvdyBpcyB1bmRlZmluZWQnKTtcbn1cblxuXG4vLyByZW1vdmVJRnJhbWVNZXNzYWdlTGlzdGVuZXJcbmZ1bmN0aW9uIHJlbW92ZVNvdXJjZVN1YnNjcmliZXIoc291cmNlTWVzc2FnZSkge1xuICAgIHZhciB3aW4gPSB0aGlzLmZyYW1lV2luZG93KCk7XG4gICAgaWYgKHdpbikgd2luLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCB0aGlzLCBmYWxzZSk7XG4gICAgZWxzZSBsb2dnZXIud2FybignRnJhbWVNZXNzYWdlU291cmNlOiBmcmFtZSB3aW5kb3cgaXMgdW5kZWZpbmVkJyk7XG59XG5cblxuZnVuY3Rpb24gdHJpZ2dlcihtc2dUeXBlLCBkYXRhKSB7XG4gICAgZGF0YSA9IGRhdGEgfHwge307XG4gICAgZGF0YS50eXBlID0gbXNnVHlwZTtcblxuICAgIHRoaXMuZnJhbWVXaW5kb3coKS5wb3N0TWVzc2FnZShkYXRhLCAnKicpO1xufVxuXG5cbi8vIFRPRE8gbWF5YmUgcmVmYWN0b3IgdG8gRnJhbWVNc2dBUEk/XG5mdW5jdGlvbiBoYW5kbGVFdmVudChldmVudCkge1xuICAgIHRoaXMuZGlzcGF0Y2hNZXNzYWdlKGV2ZW50LmRhdGEudHlwZSwgZXZlbnQpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjb21wb25lbnROYW1lID0gcmVxdWlyZSgnLi4vdXRpbC9jb21wb25lbnRfbmFtZScpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgU2NvcGVFcnJvciA9IHJlcXVpcmUoJy4uL3V0aWwvZXJyb3InKS5TY29wZVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vdXRpbC9sb2dnZXInKTtcblxuXG4vKipcbiAqIFNjb3BlIGNsYXNzLlxuICogQHBhcmFtIHtFbGVtZW50fSByb290RWwgdGhlIHJvb3QgZWxlbWVudCBvZiB0aGlzIHNjb3BlXG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCB0aGUgaG9zdCBcbiAqIEByZXR1cm4ge1Njb3BlfVxuICovXG5mdW5jdGlvbiBTY29wZShyb290RWwsIGhvc3RPYmplY3QpIHtcbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICBfcm9vdEVsOiByb290RWwsXG4gICAgICAgIF9ob3N0T2JqZWN0OiBob3N0T2JqZWN0XG4gICAgfSwgXy5XUklUKTsgLy8gd3JpdGFibGVcbn07XG5cbl8uZXh0ZW5kUHJvdG8oU2NvcGUsIHtcbiAgICBfYWRkOiBTY29wZSRfYWRkLFxuICAgIF9zYWZlQWRkOiBTY29wZSRfc2FmZUFkZCxcbiAgICBfY29weTogU2NvcGUkX2NvcHksXG4gICAgX2VhY2g6IFNjb3BlJF9lYWNoLFxuICAgIF9tb3ZlOiBTY29wZSRfbW92ZSxcbiAgICBfbWVyZ2U6IFNjb3BlJF9tZXJnZSxcbiAgICBfbGVuZ3RoOiBTY29wZSRfbGVuZ3RoLFxuICAgIF9hbnk6IFNjb3BlJF9hbnksXG4gICAgX3JlbW92ZTogU2NvcGUkX3JlbW92ZSxcbiAgICBfY2xlYW46IFNjb3BlJF9jbGVhbixcbiAgICBfZGV0YWNoRWxlbWVudDogU2NvcGUkX2RldGFjaEVsZW1lbnQsXG4gICAgX2hhczogU2NvcGUkX2hhcyxcbiAgICBfZmlsdGVyOiBTY29wZSRfZmlsdGVyXG59KTtcblxuXG5fLmV4dGVuZChTY29wZSwge1xuICAgIHJlbmFtZTogU2NvcGUkJHJlbmFtZVxufSk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBTY29wZTtcblxuXG52YXIgYWxsb3dlZE5hbWVQYXR0ZXJuID0gL15bQS1aYS16XVtBLVphLXowLTlcXF9cXCRdKiQvO1xuXG5cbi8qKlxuICogU2NvcGUgaW5zdGFuY2UgbWV0aG9kLlxuICogQWRkcyBvYmplY3QgdG8gdGhlIHNjb3BlLCB0aHJvd2luZyBpZiBuYW1lIGlzIG5vdCB1bmlxdWVcbiAqIEBwYXJhbSB7Q29tcG9uZW50fENvbXBvbmVudEluZm99IG9iamVjdCBjb21wb25lbnQgb3IgY29tcG9uZW50IGluZm8gdG8gYWRkIHRvIHRoZSBzY29wZVxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWUgdGhlIG5hbWUgb2YgdGhlIGNvbXBvbmVudCB0byBhZGRcbiAqL1xuZnVuY3Rpb24gU2NvcGUkX2FkZChvYmplY3QsIG5hbWUpIHtcbiAgICBpZiAodHlwZW9mIG5hbWUgPT0gJ3N0cmluZycpXG4gICAgICAgIG9iamVjdC5uYW1lID0gbmFtZTtcbiAgICBlbHNlXG4gICAgICAgIG5hbWUgPSBvYmplY3QubmFtZTtcbiAgICBcbiAgICBpZiAodGhpcy5oYXNPd25Qcm9wZXJ0eShuYW1lKSlcbiAgICAgICAgdGhyb3cgbmV3IFNjb3BlRXJyb3IoJ2R1cGxpY2F0ZSBvYmplY3QgbmFtZTogJyArIG5hbWUpO1xuXG4gICAgY2hlY2tOYW1lKG5hbWUpO1xuICAgIF9fYWRkLmNhbGwodGhpcywgb2JqZWN0LCBuYW1lKTtcbn1cblxuXG4vKipcbiAqIFNjb3BlIGluc3RhbmNlIG1ldGhvZFxuICogQWRkcyBvYmplY3QgdG8gc2NvcGUgcmVuYW1pbmcgaXQgaWYgbmFtZSBpcyBub3QgdW5pcXVlXG4gKiBAcGFyYW0ge0NvbXBvbmVudHxDb21wb25lbnRJbmZvfSBvYmplY3QgY29tcG9uZW50IG9yIGNvbXBvbmVudCBpbmZvIHRvIGFkZCB0byB0aGUgc2NvcGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIHRoZSBuYW1lIG9mIHRoZSBjb21wb25lbnQgdG8gYWRkXG4gKi9cbmZ1bmN0aW9uIFNjb3BlJF9zYWZlQWRkKG9iamVjdCwgbmFtZSkge1xuICAgIGlmICh0eXBlb2YgbmFtZSA9PSAnc3RyaW5nJylcbiAgICAgICAgb2JqZWN0Lm5hbWUgPSBuYW1lO1xuICAgIGVsc2VcbiAgICAgICAgbmFtZSA9IG9iamVjdC5uYW1lO1xuXG4gICAgdmFyIHNob3VsZFJlbmFtZSA9IHRoaXMuaGFzT3duUHJvcGVydHkobmFtZSk7XG4gICAgaWYgKHNob3VsZFJlbmFtZSlcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdTY29wZTogZHVwbGljYXRlIG9iamVjdCBuYW1lOiAnICsgbmFtZSk7XG4gICAgZWxzZSB7XG4gICAgICAgIHNob3VsZFJlbmFtZSA9ICEgYWxsb3dlZE5hbWVQYXR0ZXJuLnRlc3QobmFtZSk7XG4gICAgICAgIGlmIChzaG91bGRSZW5hbWUpXG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ1Njb3BlOiBuYW1lIHNob3VsZCBzdGFydCBmcm9tIGxldHRlciwgdGhpcyBuYW1lIGlzIG5vdCBhbGxvd2VkOiAnICsgbmFtZSk7XG4gICAgfVxuXG4gICAgaWYgKHNob3VsZFJlbmFtZSkge1xuICAgICAgICBuYW1lID0gY29tcG9uZW50TmFtZSgpO1xuICAgICAgICBvYmplY3QubmFtZSA9IG5hbWU7XG4gICAgfVxuXG4gICAgX19hZGQuY2FsbCh0aGlzLCBvYmplY3QsIG5hbWUpO1xufVxuXG5cbmZ1bmN0aW9uIF9fYWRkKG9iamVjdCwgbmFtZSkge1xuICAgIHRoaXNbbmFtZV0gPSBvYmplY3Q7XG4gICAgb2JqZWN0LnNjb3BlID0gdGhpcztcblxuICAgIGlmICh0eXBlb2Ygb2JqZWN0LnBvc3RNZXNzYWdlID09PSAnZnVuY3Rpb24nKVxuICAgICAgICBvYmplY3QucG9zdE1lc3NhZ2UoJ2FkZGVkdG9zY29wZScpOyBcbn1cblxuXG4vKipcbiAqIEluc3RhbmNlIG1ldGhvZC5cbiAqIGNvcGllcyBhbGwgb2JqZWN0cyBmcm9tIG9uZSBzY29wZSB0byBhbm90aGVyLFxuICogdGhyb3dpbmcgaWYgc29tZSBvYmplY3QgaXMgbm90IHVuaXF1ZVxuICogQHBhcmFtIHtTY29wZX0gYVNjb3BlIHRoZSBzY29wZSB0byBjb3B5XG4gKi9cbmZ1bmN0aW9uIFNjb3BlJF9jb3B5KGFTY29wZSkge1xuICAgIGNoZWNrKGFTY29wZSwgU2NvcGUpO1xuXG4gICAgYVNjb3BlLl9lYWNoKFNjb3BlJF9hZGQsIHRoaXMpO1xufVxuXG5cbi8qKlxuICogSW5zdGFuY2UgbWV0aG9kLlxuICogTW92ZXMgYSBjb21wb25lbnQgZnJvbSB0aGlzIHNjb3BlIHRvIGFub3RoZXIgc2NvcGUuXG4gKiBAcGFyYW0ge0NvbXBvbmVudH0gY29tcG9uZW50IHRoZSBjb21wb25lbnQgdG8gYmUgbW92ZWRcbiAqIEBwYXJhbSB7U2NvcGV9IG90aGVyU2NvcGUgdGhlIHNjb3BlIHRvIGNvcHkgdGhlIGNvbXBvbmVudCB0b1xuICovXG5mdW5jdGlvbiBTY29wZSRfbW92ZShjb21wb25lbnQsIG90aGVyU2NvcGUpIHtcbiAgICBvdGhlclNjb3BlLl9hZGQoY29tcG9uZW50KTtcbiAgICB0aGlzLl9yZW1vdmUoY29tcG9uZW50Lm5hbWUpO1xuICAgIGNvbXBvbmVudC5zY29wZSA9IG90aGVyU2NvcGU7XG59XG5cblxuLyoqXG4gKiBJbnN0YW5jZSBtZXRob2QuXG4gKiBNZXJnZXMgb25lIHNjb3BlIGludG8gdGhpcyBzY29wZVxuICogQHBhcmFtIHtTY29wZX0gc2NvcGUgdGhlIHNjb3BlIHRvIGFic29yYlxuICovXG5mdW5jdGlvbiBTY29wZSRfbWVyZ2Uoc2NvcGUpIHtcbiAgICBzY29wZS5fZWFjaChmdW5jdGlvbiAoY29tcCkge1xuICAgICAgICB0aGlzLl9hZGQoY29tcCwgY29tcC5uYW1lKTtcbiAgICAgICAgc2NvcGUuX3JlbW92ZShjb21wLm5hbWUpO1xuICAgIH0sIHRoaXMpO1xufVxuXG5cbi8qKlxuICogSW5zdGFuY2UgbWV0aG9kLlxuICogRW51bWVyYXRlcyBlYWNoIGNvbXBvbmVudCBpbiB0aGUgc2NvcGVcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIHRoZSBmdW5jdGlvbiB0byBleGVjdXRlIGZvciBlYWNoIGNvbXBvbmVudFxuICogQHBhcmFtIHtPYmplY3R9IHRoaXNBcmcgdGhlIGNvbnRleHRcbiAqL1xuZnVuY3Rpb24gU2NvcGUkX2VhY2goY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICBfLmVhY2hLZXkodGhpcywgY2FsbGJhY2ssIHRoaXNBcmcgfHwgdGhpcywgdHJ1ZSk7IC8vIGVudW1lcmF0ZXMgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9ubHlcbn1cblxuXG4vKipcbiAqIEluc3RhbmNlIG1ldGhvZC5cbiAqIFJldHVybnMgYSBmaWx0ZXJlZCBsaXN0IG9mIGNvbXBvbmVudHMgYmFzZWQgb24gYSBjYWxsYmFja1xuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgdGhlIGZ1bmN0aW9uIHRvIGV4ZWN1dGUgZm9yIGVhY2ggY29tcG9uZW50XG4gKiBAcGFyYW0ge09iamVjdH0gdGhpc0FyZyB0aGUgY29udGV4dFxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIFNjb3BlJF9maWx0ZXIoY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICByZXR1cm4gXy5maWx0ZXJLZXlzKHRoaXMsIGNhbGxiYWNrLCB0aGlzQXJnIHx8IHRoaXMsIHRydWUpO1xufVxuXG5cbi8qKlxuICogQ2hlY2tzIHRoZSB2YWxpZGl0eSBvZiBhIG5hbWUuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayB0aGUgZnVuY3Rpb24gdG8gZXhlY3V0ZSBmb3IgZWFjaCBjb21wb25lbnRcbiAqL1xuZnVuY3Rpb24gY2hlY2tOYW1lKG5hbWUpIHtcbiAgICBpZiAoISBhbGxvd2VkTmFtZVBhdHRlcm4udGVzdChuYW1lKSlcbiAgICAgICAgdGhyb3cgbmV3IFNjb3BlRXJyb3IoJ25hbWUgc2hvdWxkIHN0YXJ0IGZyb20gbGV0dGVyLCB0aGlzIG5hbWUgaXMgbm90IGFsbG93ZWQ6ICcgKyBuYW1lKTtcbn1cblxuXG4vKipcbiAqIEluc3RhbmNlIG1ldGhvZC5cbiAqIFJldHVybnMgdGhlIG51bWJlciBvZiBvYmplY3RzIGluIHRoZSBzY29wZVxuICogQHJldHVybiB7TnVtYmVyfVxuICovXG5mdW5jdGlvbiBTY29wZSRfbGVuZ3RoKCkge1xuICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzKS5sZW5ndGg7XG59XG5cblxuLyoqXG4gKiBJbnN0YW5jZSBtZXRob2QuXG4gKiBSZXR1cm5zIGEgY29tcG9uZW50IGZyb20gdGhlIHNjb3BlLiBJdCBtYXkgbG9vayBsaWtlIGl0IHJldHVybnMgdGhlIGZpcnN0IGNvbXBvbmVudFxuICogYnV0IGluIHJlYWxpdHkgZ2l2ZW4gdGhhdCBzY29wZXMgYXJlIGhhc2hlcywgdGhlcmUgaXMgbm8gc3VjaCB0aGluZy5cbiAqIEByZXR1cm4ge0NvbXBvbmVudH1cbiAqL1xuZnVuY3Rpb24gU2NvcGUkX2FueSgpIHtcbiAgICB2YXIga2V5ID0gT2JqZWN0LmtleXModGhpcylbMF07XG4gICAgcmV0dXJuIGtleSAmJiB0aGlzW2tleV07XG59XG5cblxuLyoqXG4gKiBJbnN0YW5jZSBtZXRob2QuXG4gKiBSZW1vdmVzIGEgY29tcG9uZW50IGZyb20gdGhlIHNjb3BlIGJ5IGl0J3MgbmFtZS5cbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIHRoZSBuYW1lIG9mIHRoZSBjb21wb25lbnQgdG8gcmVtb3ZlXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHF1aWV0IG9wdGlvbmFsIHRydWUgdG8gc3VwcHJlc3MgdGhlIHdhcm5pbmcgbWVzc2FnZSBpZiB0aGUgY29tcG9uZW50IGlzIG5vdCBpbiBzY29wZVxuICovXG5mdW5jdGlvbiBTY29wZSRfcmVtb3ZlKG5hbWUsIHF1aWV0KSB7XG4gICAgaWYgKCEgKG5hbWUgaW4gdGhpcykpIHtcbiAgICAgICAgaWYgKCFxdWlldCkgbG9nZ2VyLndhcm4oJ3JlbW92aW5nIG9iamVjdCB0aGF0IGlzIG5vdCBpbiBzY29wZScpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIG9iamVjdCA9IHRoaXNbbmFtZV07XG5cbiAgICBkZWxldGUgdGhpc1tuYW1lXTtcblxuICAgIGlmICh0eXBlb2Ygb2JqZWN0LnBvc3RNZXNzYWdlID09PSAnZnVuY3Rpb24nKVxuICAgICAgICBvYmplY3QucG9zdE1lc3NhZ2UoJ3JlbW92ZWRmcm9tc2NvcGUnKTtcbn1cblxuXG4vKipcbiAqIEluc3RhbmNlIG1ldGhvZC5cbiAqIFJlbW92ZXMgYWxsIGNvbXBvbmVudHMgZnJvbSB0aGUgc2NvcGUuXG4gKi9cbmZ1bmN0aW9uIFNjb3BlJF9jbGVhbigpIHtcbiAgICB0aGlzLl9lYWNoKGZ1bmN0aW9uKG9iamVjdCwgbmFtZSkge1xuICAgICAgICBkZWxldGUgdGhpc1tuYW1lXS5zY29wZTtcbiAgICAgICAgZGVsZXRlIHRoaXNbbmFtZV07XG4gICAgfSwgdGhpcyk7XG59XG5cbmZ1bmN0aW9uIFNjb3BlJF9kZXRhY2hFbGVtZW50KCkge1xuICAgIHRoaXMuX3Jvb3RFbCA9IG51bGw7XG59XG5cblxuLyoqXG4gKiBDaGVja3MgaWYgc2NvcGUgaGFzIG9iamVjdCBieSBvYmplY3QgbmFtZVxuICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gU2NvcGUkX2hhcyhvYmplY3QpIHtcbiAgICByZXR1cm4gdGhpcy5oYXNPd25Qcm9wZXJ0eShvYmplY3QubmFtZSk7XG59XG5cblxuLyoqXG4gKiBDaGFuZ2Ugb2JqZWN0IG5hbWUsIHJlbmFtaW5nIGl0IGluIHNjb3BlIHVubGVzcyByZW5hbWVJblNjb3BlIGlzIGZhbHNlXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBuZXcgbmFtZVxuICogQHBhcmFtIHtCb29sZWFufSByZW5hbWVJblNjb3BlIHRydWUgYnkgZGVmYXVsdFxuICovXG5mdW5jdGlvbiBTY29wZSQkcmVuYW1lKG9iaiwgbmFtZSwgcmVuYW1lSW5TY29wZSkge1xuICAgIGlmIChvYmouc2NvcGUgJiYgcmVuYW1lSW5TY29wZSAhPT0gZmFsc2UpIHtcbiAgICAgICAgb2JqLnNjb3BlLl9yZW1vdmUob2JqLm5hbWUpO1xuICAgICAgICBvYmouc2NvcGUuX2FkZChvYmosIG5hbWUpO1xuICAgIH0gZWxzZVxuICAgICAgICBvYmoubmFtZSA9IG5hbWU7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jX2NsYXNzJylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2NfcmVnaXN0cnknKTtcblxuXG52YXIgTUxCdXR0b24gPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MQnV0dG9uJywge1xuICAgIGV2ZW50czogdW5kZWZpbmVkLFxuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS1idXR0b24nXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxCdXR0b24pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MQnV0dG9uO1xuXG5fLmV4dGVuZFByb3RvKE1MQnV0dG9uLCB7XG4gICAgZGlzYWJsZTogTUxCdXR0b24kZGlzYWJsZSxcbiAgICBpc0Rpc2FibGVkOiBNTEJ1dHRvbiRpc0Rpc2FibGVkXG59KTtcblxuXG5mdW5jdGlvbiBNTEJ1dHRvbiRkaXNhYmxlKGRpc2FibGUpIHtcbiAgICB0aGlzLmVsLmRpc2FibGVkID0gZGlzYWJsZTtcbn1cblxuZnVuY3Rpb24gTUxCdXR0b24kaXNEaXNhYmxlZCgpIHtcbiAgICByZXR1cm4gISF0aGlzLmVsLmRpc2FibGVkO1xufVxuXG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jX2NsYXNzJylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2NfcmVnaXN0cnknKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbnZhciBDT01CT19DSEFOR0VfTUVTU0FHRSA9ICdtbGNvbWJvY2hhbmdlJztcblxudmFyIERBVEFMSVNUX1RFTVBMQVRFID0gJ3t7fiBpdC5jb21ib09wdGlvbnMgOm9wdGlvbiB9fSBcXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJ7ez0gb3B0aW9uLmxhYmVsIH19XCI+PC9vcHRpb24+IFxcXG4gICAgICAgICAgICAgICAgICAgICAgICAge3t+fX0nO1xuXG52YXIgTUxDb21ibyA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxDb21ibycsIHtcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBkYXRhOiB7XG4gICAgICAgIGdldDogTUxDb21ib19nZXQsXG4gICAgICAgIHNldDogTUxDb21ib19zZXQsXG4gICAgICAgIGRlbDogTUxDb21ib19kZWwsXG4gICAgICAgIHNwbGljZTogdW5kZWZpbmVkLFxuICAgICAgICBldmVudDogQ09NQk9fQ0hBTkdFX01FU1NBR0VcbiAgICB9LFxuICAgIG1vZGVsOiB7XG4gICAgICAgIG1lc3NhZ2VzOiB7XG4gICAgICAgICAgICAnKioqJzogeyBzdWJzY3JpYmVyOiBvbk9wdGlvbnNDaGFuZ2UsIGNvbnRleHQ6ICdvd25lcicgfVxuICAgICAgICB9XG4gICAgfSxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktZGF0YWxpc3QnXG4gICAgfSxcbiAgICBjb250YWluZXI6IHVuZGVmaW5lZFxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxDb21ibyk7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxDb21ibztcblxuXG5fLmV4dGVuZFByb3RvKE1MQ29tYm8sIHtcbiAgICBpbml0OiBNTENvbWJvJGluaXRcbn0pO1xuXG5cbmZ1bmN0aW9uIE1MQ29tYm8kaW5pdCgpIHtcbiAgICBDb21wb25lbnQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB0aGlzLm9uKCdjaGlsZHJlbmJvdW5kJywgb25DaGlsZHJlbkJvdW5kKTtcbn1cblxuZnVuY3Rpb24gb25DaGlsZHJlbkJvdW5kKCkge1xuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgICdfY29tYm9JbnB1dCc6IHRoaXMuY29udGFpbmVyLnNjb3BlLmlucHV0LFxuICAgICAgICAnX2NvbWJvTGlzdCc6IHRoaXMuY29udGFpbmVyLnNjb3BlLmRhdGFsaXN0XG4gICAgfSk7XG5cbiAgICB0aGlzLl9jb21ib0xpc3QudGVtcGxhdGUuc2V0KERBVEFMSVNUX1RFTVBMQVRFKTtcblxuICAgIHRoaXMuX2NvbWJvSW5wdXQuZGF0YS5vbignaW5wdXQnLFxuICAgICAgICB7IHN1YnNjcmliZXI6IGRpc3BhdGNoQ2hhbmdlTWVzc2FnZSwgY29udGV4dDogdGhpcyB9KTtcbn1cblxuZnVuY3Rpb24gTUxDb21ib19nZXQoKSB7XG4gICAgaWYgKCEgdGhpcy5fY29tYm9JbnB1dCkgcmV0dXJuO1xuICAgIHJldHVybiB0aGlzLl9jb21ib0lucHV0LmRhdGEuZ2V0KCk7XG59XG5cbmZ1bmN0aW9uIE1MQ29tYm9fc2V0KHZhbHVlKSB7XG4gICAgcmV0dXJuIGNoYW5nZUNvbWJvRGF0YS5jYWxsKHRoaXMsICdzZXQnLCB2YWx1ZSk7XG59XG5cbmZ1bmN0aW9uIE1MQ29tYm9fZGVsKCkge1xuICAgIHJldHVybiBjaGFuZ2VDb21ib0RhdGEuY2FsbCh0aGlzLCAnZGVsJywgdmFsdWUpO1xufVxuXG5mdW5jdGlvbiBjaGFuZ2VDb21ib0RhdGEobWV0aG9kLCB2YWx1ZSkge1xuICAgIGlmICghIHRoaXMuX2NvbWJvSW5wdXQpIHJldHVybjtcbiAgICB2YXIgcmVzdWx0ID0gdGhpcy5fY29tYm9JbnB1dC5kYXRhW21ldGhvZF0odmFsdWUpO1xuICAgIGRpc3BhdGNoQ2hhbmdlTWVzc2FnZS5jYWxsKHRoaXMpO1xuICAgIHJldHVybiByZXN1bHQ7XG59XG5cblxuLy8gUG9zdCB0aGUgZGF0YSBjaGFuZ2VcbmZ1bmN0aW9uIGRpc3BhdGNoQ2hhbmdlTWVzc2FnZSgpIHtcbiAgICB0aGlzLmRhdGEuZGlzcGF0Y2hTb3VyY2VNZXNzYWdlKENPTUJPX0NIQU5HRV9NRVNTQUdFKTtcbn1cblxuZnVuY3Rpb24gb25PcHRpb25zQ2hhbmdlKG1zZywgZGF0YSkge1xuICAgIHRoaXMuX2NvbWJvTGlzdC50ZW1wbGF0ZS5yZW5kZXIoe1xuICAgICAgICBjb21ib09wdGlvbnM6IHRoaXMubW9kZWwuZ2V0KClcbiAgICB9KTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cbnZhciBDT01CT19MSVNUX0NIQU5HRV9NRVNTQUdFID0gJ21sY29tYm9saXN0Y2hhbmdlJztcblxuXG52YXIgTUxDb21ib0xpc3QgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MQ29tYm9MaXN0Jywge1xuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS1jb21iby1saXN0J1xuICAgIH0sXG4gICAgZGF0YToge1xuICAgICAgICBnZXQ6IE1MQ29tYm9MaXN0X2dldCxcbiAgICAgICAgc2V0OiBNTENvbWJvTGlzdF9zZXQsXG4gICAgICAgIGRlbDogTUxDb21ib0xpc3RfZGVsLFxuICAgICAgICBldmVudDogQ09NQk9fTElTVF9DSEFOR0VfTUVTU0FHRVxuICAgIH0sXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgY29udGFpbmVyOiB1bmRlZmluZWQsXG4gICAgbW9kZWw6IHtcbiAgICAgICAgbWVzc2FnZXM6IHtcbiAgICAgICAgICAgICcqKionOiB7IHN1YnNjcmliZXI6IG9uSXRlbXNDaGFuZ2UsIGNvbnRleHQ6ICdvd25lcid9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICAgIHRlbXBsYXRlOiAnPGRpdiBtbC1iaW5kPVwiTUxTdXBlckNvbWJvOmNvbWJvXCI+PC9kaXY+XFxcbiAgICAgICAgICAgICAgICAgICA8ZGl2IG1sLWJpbmQ9XCJNTExpc3Q6bGlzdFwiPlxcXG4gICAgICAgICAgICAgICAgICAgICAgIDxkaXYgbWwtYmluZD1cIk1MTGlzdEl0ZW06aXRlbVwiIGNsYXNzPVwibGlzdC1pdGVtXCI+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIG1sLWJpbmQ9XCJbZGF0YV06bGFiZWxcIj48L3NwYW4+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIG1sLWJpbmQ9XCJbZXZlbnRzXTpkZWxldGVCdG5cIiBjbGFzcz1cImdseXBoaWNvbiBnbHlwaGljb24tcmVtb3ZlXCI+PC9zcGFuPlxcXG4gICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxcXG4gICAgICAgICAgICAgICAgICAgPC9kaXY+J1xuICAgIH1cbn0pO1xuXG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxDb21ib0xpc3QpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MQ29tYm9MaXN0O1xuXG5cbl8uZXh0ZW5kUHJvdG8oTUxDb21ib0xpc3QsIHtcbiAgICBpbml0OiBNTENvbWJvTGlzdCRpbml0LFxuICAgIHNldE9wdGlvbnM6IE1MQ29tYm9MaXN0JHNldE9wdGlvbnMsXG4gICAgc2V0RGF0YVZhbGlkYXRpb246IE1MQ29tYm9MaXN0JHNldERhdGFWYWxpZGF0aW9uLFxuICAgIHRvZ2dsZUFkZEJ1dHRvbjogTUxDb21ib0xpc3QkdG9nZ2xlQWRkQnV0dG9uLFxuICAgIGRlc3Ryb3k6IE1MQ29tYm9MaXN0JGRlc3Ryb3ksXG4gICAgc2V0QWRkSXRlbVByb21wdDogTUxDb21ib0xpc3Qkc2V0QWRkSXRlbVByb21wdCxcbiAgICBjbGVhckNvbWJvSW5wdXQgOiBNTENvbWJvTGlzdCRjbGVhckNvbWJvSW5wdXRcbn0pO1xuXG5cbmZ1bmN0aW9uIE1MQ29tYm9MaXN0JGluaXQoKSB7XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgdGhpcy5fZGF0YVZhbGlkYXRpb24gPSBmdW5jdGlvbiAoKSB7fTtcbiAgICB0aGlzLm1vZGVsLnNldChbXSk7XG4gICAgdGhpcy5vbmNlKCdjaGlsZHJlbmJvdW5kJywgb25DaGlsZHJlbkJvdW5kKTtcbn1cblxuXG5mdW5jdGlvbiBNTENvbWJvTGlzdCRzZXREYXRhVmFsaWRhdGlvbihkYXRhVmFsaWRhdGlvbikge1xuICAgIGlmICh0eXBlb2YgZGF0YVZhbGlkYXRpb24gPT0gJ2Z1bmN0aW9uJylcbiAgICAgICAgdGhpcy5fZGF0YVZhbGlkYXRpb24gPSBkYXRhVmFsaWRhdGlvbjtcbn1cblxuZnVuY3Rpb24gTUxDb21ib0xpc3Qkc2V0T3B0aW9ucyhhcnIpIHtcbiAgICB0aGlzLl9jb21iby5zZXRPcHRpb25zKGFycik7XG59XG5cblxuZnVuY3Rpb24gTUxDb21ib0xpc3QkY2xlYXJDb21ib0lucHV0ICgpIHtcbiAgICB0aGlzLl9jb21iby5jbGVhckNvbWJvSW5wdXQoKTtcbn1cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBIaWRlcyBhZGQgYnV0dG9uXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHNob3dcbiAqL1xuZnVuY3Rpb24gTUxDb21ib0xpc3QkdG9nZ2xlQWRkQnV0dG9uKHNob3cpIHtcbiAgICB0aGlzLl9jb21iby50b2dnbGVBZGRCdXR0b24oc2hvdyk7XG59XG5cblxuZnVuY3Rpb24gTUxDb21ib0xpc3Qkc2V0QWRkSXRlbVByb21wdChwcm9tcHQpIHtcbiAgIHRoaXMuX2NvbWJvLnNldEFkZEl0ZW1Qcm9tcHQocHJvbXB0KTtcbn1cblxuXG5mdW5jdGlvbiBNTENvbWJvTGlzdCRkZXN0cm95KCkge1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuZGVzdHJveS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMuX2Nvbm5lY3RvciAmJiBtaWxvLm1pbmRlci5kZXN0cm95Q29ubmVjdG9yKHRoaXMuX2Nvbm5lY3Rvcik7XG4gICAgdGhpcy5fY29ubmVjdG9yID0gbnVsbDtcbn1cblxuXG5mdW5jdGlvbiBvbkNoaWxkcmVuQm91bmQoKSB7XG4gICAgdGhpcy50ZW1wbGF0ZS5yZW5kZXIoKS5iaW5kZXIoKTtcbiAgICBjb21wb25lbnRTZXR1cC5jYWxsKHRoaXMpO1xufVxuXG5mdW5jdGlvbiBjb21wb25lbnRTZXR1cCgpIHtcbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICAnX2NvbWJvJzogdGhpcy5jb250YWluZXIuc2NvcGUuY29tYm8sXG4gICAgICAgICdfbGlzdCc6IHRoaXMuY29udGFpbmVyLnNjb3BlLmxpc3RcbiAgICB9KTtcblxuICAgIHRoaXMuX2Nvbm5lY3RvciA9IG1pbG8ubWluZGVyKHRoaXMuX2xpc3QubW9kZWwsICc8PDwtPj4+JywgdGhpcy5tb2RlbCk7XG4gICAgdGhpcy5fY29tYm8uZGF0YS5vbignJywgeyBzdWJzY3JpYmVyOiBvbkNvbWJvQ2hhbmdlLCBjb250ZXh0OiB0aGlzIH0pO1xuICAgIHRoaXMuX2NvbWJvLm9uKCdhZGRpdGVtJywgeyBzdWJzY3JpYmVyOiBvbkFkZEl0ZW0sIGNvbnRleHQ6IHRoaXMgfSk7XG59XG5cbmZ1bmN0aW9uIG9uQ29tYm9DaGFuZ2UobXNnLCBkYXRhKSB7XG4gICAgaWYgKGRhdGEubmV3VmFsdWUgJiYgdGhpcy5fZGF0YVZhbGlkYXRpb24obXNnLCBkYXRhLCB0aGlzLl9saXN0Lm1vZGVsLmdldCgpKSlcbiAgICAgICAgdGhpcy5fbGlzdC5tb2RlbC5wdXNoKGRhdGEubmV3VmFsdWUpO1xuICAgIHRoaXMuX2NvbWJvLmRhdGEuZGVsKCk7XG4gICAgLy8gYmVjYXVzZSBvZiBzdXBlcmNvbWJvIGxpc3RlbmVycyBvZmYgeW91IGhhdmUgdG8gc2V0IF92YWx1ZSBleHBsaWNpdGx5XG4gICAgdGhpcy5fY29tYm8uZGF0YS5fdmFsdWUgPSAnJztcbn1cblxuZnVuY3Rpb24gb25JdGVtc0NoYW5nZShtc2csIGRhdGEpIHtcbiAgICB0aGlzLmRhdGEuZGlzcGF0Y2hTb3VyY2VNZXNzYWdlKENPTUJPX0xJU1RfQ0hBTkdFX01FU1NBR0UpO1xufVxuXG5mdW5jdGlvbiBNTENvbWJvTGlzdF9nZXQoKSB7XG4gICAgdmFyIHZhbHVlID0gdGhpcy5tb2RlbC5nZXQoKTtcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdvYmplY3QnID8gXy5jbG9uZSh2YWx1ZSkgOiB2YWx1ZTtcbn1cblxuZnVuY3Rpb24gTUxDb21ib0xpc3Rfc2V0KHZhbHVlKSB7XG4gICAgdGhpcy5tb2RlbC5zZXQodmFsdWUpO1xufVxuXG5mdW5jdGlvbiBNTENvbWJvTGlzdF9kZWwoKSB7XG4gICAgcmV0dXJuIHRoaXMubW9kZWwuc2V0KFtdKTtcbn1cblxuXG5mdW5jdGlvbiBvbkFkZEl0ZW0obXNnLCBkYXRhKSB7XG4gICAgdGhpcy5wb3N0TWVzc2FnZSgnYWRkaXRlbScsIGRhdGEpO1xuICAgIHRoaXMuZXZlbnRzLnBvc3RNZXNzYWdlKCdtaWxvX2NvbWJvbGlzdGFkZGl0ZW0nLCBkYXRhKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cbnZhciBNTERhdGUgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MRGF0ZScsIHtcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBkYXRhOiB7XG4gICAgICAgIGdldDogTUxEYXRlX2dldCxcbiAgICAgICAgc2V0OiBNTERhdGVfc2V0LFxuICAgICAgICBkZWw6IE1MRGF0ZV9kZWwsXG4gICAgfSxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktZGF0ZSdcbiAgICB9XG59KTtcblxuXy5leHRlbmRQcm90byhNTERhdGUsIHtcbiAgICBnZXRNaW46IE1MRGF0ZSRnZXRNaW4sXG4gICAgc2V0TWluOiBNTERhdGUkc2V0TWluLFxuICAgIGdldE1heDogTUxEYXRlJGdldE1heCxcbiAgICBzZXRNYXg6IE1MRGF0ZSRzZXRNYXhcbn0pO1xuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MRGF0ZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxEYXRlO1xuXG5cbmZ1bmN0aW9uIE1MRGF0ZSRnZXRNaW4oKSB7XG4gICAgcmV0dXJuIF8uZGF0ZSh0aGlzLmVsLm1pbik7XG59XG5cblxuZnVuY3Rpb24gTUxEYXRlJHNldE1pbih2YWx1ZSkge1xuICAgIHZhciBkYXRlID0gXy50b0RhdGUodmFsdWUpO1xuXG4gICAgdGhpcy5lbC5taW4gPSBkYXRlID8gdG9JU084NjAxRm9ybWF0KGRhdGUpIDogJyc7XG59XG5cblxuZnVuY3Rpb24gTUxEYXRlJGdldE1heCgpIHtcbiAgICByZXR1cm4gXy5kYXRlKHRoaXMuZWwubWF4KTtcbn1cblxuXG5mdW5jdGlvbiBNTERhdGUkc2V0TWF4KHZhbHVlKSB7XG4gICAgdmFyIGRhdGUgPSBfLnRvRGF0ZSh2YWx1ZSk7XG5cbiAgICB0aGlzLmVsLm1heCA9IGRhdGUgPyB0b0lTTzg2MDFGb3JtYXQoZGF0ZSkgOiAnJztcbn1cblxuXG5mdW5jdGlvbiBNTERhdGVfZ2V0KCkge1xuICAgIHJldHVybiBfLnRvRGF0ZSh0aGlzLmVsLnZhbHVlKTtcbn1cblxuXG5mdW5jdGlvbiBNTERhdGVfc2V0KHZhbHVlKSB7XG4gICAgdmFyIGRhdGUgPSBfLnRvRGF0ZSh2YWx1ZSk7XG5cbiAgICB0aGlzLmVsLnZhbHVlID0gZGF0ZSA/IHRvSVNPODYwMUZvcm1hdChkYXRlKSA6ICcnO1xuXG4gICAgZGlzcGF0Y2hJbnB1dE1lc3NhZ2UuY2FsbCh0aGlzKTtcbn1cblxuZnVuY3Rpb24gTUxEYXRlX2RlbCgpIHtcbiAgICB0aGlzLmVsLnZhbHVlID0gJyc7XG5cbiAgICBkaXNwYXRjaElucHV0TWVzc2FnZS5jYWxsKHRoaXMpO1xufVxuXG5cbmZ1bmN0aW9uIGRpc3BhdGNoSW5wdXRNZXNzYWdlKCkge1xuICAgIHRoaXMuZGF0YS5kaXNwYXRjaFNvdXJjZU1lc3NhZ2UoJ2lucHV0Jyk7IC8vIERpc3BhdGNoIHRoZSAnaW5wdXQnICh1c3VhbGx5IGRpc3BhdGNoZWQgYnkgdGhlIHVuZGVybHlpbmcgPGlucHV0PiBlbGVtZW50KSBldmVudCBzbyB0aGF0IHRoZSBkYXRhIGNoYW5nZSBjYW4gYmUgbGlzdGVuZWQgdG9cbn1cblxuXG5mdW5jdGlvbiB0b0lTTzg2MDFGb3JtYXQoZGF0ZSkge1xuICAgIHZhciBkYXRlQXJyID0gW1xuICAgICAgICBkYXRlLmdldEZ1bGxZZWFyKCksXG4gICAgICAgIHBhZChkYXRlLmdldE1vbnRoKCkgKyAxKSxcbiAgICAgICAgcGFkKGRhdGUuZ2V0RGF0ZSgpKVxuICAgIF07XG5cbiAgICB2YXIgZGF0ZVN0ciA9IGRhdGVBcnIuam9pbignLScpO1xuXG4gICAgcmV0dXJuIGRhdGVTdHI7XG5cbiAgICBmdW5jdGlvbiBwYWQobikgeyByZXR1cm4gbiA8IDEwID8gJzAnICsgbiA6IG47IH1cbn0iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpO1xuXG5cbnZhciBNTERyb3BUYXJnZXQgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MRHJvcFRhcmdldCcsIFsnZHJvcCddKTtcblxuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MRHJvcFRhcmdldCk7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxEcm9wVGFyZ2V0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZG9UID0gcmVxdWlyZSgnZG90JylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2NfcmVnaXN0cnknKVxuICAgICwgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBtaWxvQ291bnQgPSByZXF1aXJlKCcuLi8uLi91dGlsL2NvdW50Jyk7XG5cbnZhciBUUkVFX1RFTVBMQVRFID0gJzx1bCBjbGFzcz1cIm1sLXVpLWZvbGR0cmVlLWxpc3RcIj5cXFxuICAgICAgICAgICAgICAgICAgICAgICAge3t+IGl0LmRhdGEuaXRlbXMgOml0ZW06aW5kZXggfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7IHZhciBoYXNTdWJUcmVlID0gaXRlbS5pdGVtcyAmJiBpdGVtLml0ZW1zLmxlbmd0aDsgfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxsaSB7ez8gaGFzU3ViVHJlZSB9fWNsYXNzPVwibWwtdWktZm9sZHRyZWUtLWhhcy1tdWx0aXBsZVwie3s/fX0+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm1sLXVpLWZvbGR0cmVlLWl0ZW1cIj5cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3s/IGhhc1N1YlRyZWUgfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtbC11aS1mb2xkdHJlZS1idXR0b25cIj48L2Rpdj5cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3s/fX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3s9IGl0Lml0ZW1UZW1wbGF0ZSh7IGl0ZW06IGl0ZW0sIGlkOiBpdC5pdGVtSURzW2luZGV4XSB9KSB9fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7PyBoYXNTdWJUcmVlIH19XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7PSBpdC50cmVlVGVtcGxhdGUoaXRlbSkgfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7ez99fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9saT5cXFxuICAgICAgICAgICAgICAgICAgICAgICAge3t+fX1cXFxuICAgICAgICAgICAgICAgICAgICA8L3VsPic7XG5cbnZhciBERUZBVUxUX0NPTVBJTEVEX0lURU1fVEVNUExBVEUgPSBkb1QuY29tcGlsZSgnXFxcbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibWwtdWktZm9sZHRyZWUtbGFiZWxcIiBkYXRhLWl0ZW0taWQ9XCJ7ez0gaXQuaWQgfX1cIj5cXFxuICAgICAgICAgICAgICAgIHt7PSBpdC5pdGVtLmxhYmVsIH19XFxcbiAgICAgICAgICAgIDwvc3Bhbj4nKVxuICAgICwgQ09NUElMRURfVFJFRV9URU1QTEFURSA9IGRvVC5jb21waWxlKFRSRUVfVEVNUExBVEUpO1xuXG5cbnZhciBNTEZvbGRUcmVlID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTEZvbGRUcmVlJywge1xuICAgIGNvbnRhaW5lcjogdW5kZWZpbmVkLFxuICAgIGV2ZW50czoge1xuICAgICAgICBtZXNzYWdlczoge1xuICAgICAgICAgICAgJ2NsaWNrIGRibGNsaWNrJzogeyBzdWJzY3JpYmVyOiBvbkl0ZW1FdmVudCwgY29udGV4dDogJ293bmVyJyB9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS1mb2xkdHJlZS1tYWluJ1xuICAgIH1cbn0pO1xuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MRm9sZFRyZWUpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MRm9sZFRyZWU7XG5cbl8uZXh0ZW5kUHJvdG8oTUxGb2xkVHJlZSwge1xuICAgIHNldEl0ZW1UZW1wbGF0ZTogTUxGb2xkVHJlZSRzZXRJdGVtVGVtcGxhdGUsXG4gICAgcmVuZGVyVHJlZTogTUxGb2xkVHJlZSRyZW5kZXJUcmVlXG59KTtcblxuZnVuY3Rpb24gZm9sZFVuZm9sZChlbCkge1xuICAgIGVsLmNsYXNzTGlzdC50b2dnbGUoJ21sLXVpLWZvbGR0cmVlLS11bmZvbGQnKTtcbn1cblxuZnVuY3Rpb24gaXRlbU1lc3NhZ2UobXNnLCBlbCkge1xuICAgIHZhciBpZCA9IGVsLmdldEF0dHJpYnV0ZSgnZGF0YS1pdGVtLWlkJylcbiAgICAgICAgLCBpdGVtID0gdGhpcy5faXRlbXNNYXBbaWRdO1xuXG4gICAgdGhpcy5wb3N0TWVzc2FnZSgnbWxmb2xkdHJlZV8nICsgbXNnLCB7XG4gICAgICAgIGl0ZW06IGl0ZW0sXG4gICAgICAgIGVsOiBlbFxuICAgIH0pO1xufVxuXG5mdW5jdGlvbiBvbkl0ZW1FdmVudChtc2csIGUpIHtcbiAgICB2YXIgZWwgPSBlLnRhcmdldDtcbiAgICBpZiAoZWwuY2xhc3NMaXN0LmNvbnRhaW5zKCdtbC11aS1mb2xkdHJlZS1idXR0b24nKSlcbiAgICAgICAgZm9sZFVuZm9sZChlbC5wYXJlbnROb2RlLnBhcmVudE5vZGUpO1xuICAgIGVsc2UgaWYgKGVsLmNsYXNzTGlzdC5jb250YWlucygnbWwtdWktZm9sZHRyZWUtbGFiZWwnKSlcbiAgICAgICAgaXRlbU1lc3NhZ2UuY2FsbCh0aGlzLCBtc2csIGVsKTtcbiAgICBlbHNlIHJldHVybjtcbiAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xufVxuXG5mdW5jdGlvbiBNTEZvbGRUcmVlJHNldEl0ZW1UZW1wbGF0ZSAodGVtcGxhdGVTdHIpIHtcbiAgICB0aGlzLl9pdGVtVGVtcGxhdGUgPSBkb1QuY29tcGlsZSh0ZW1wbGF0ZVN0cik7XG59XG5cbmZ1bmN0aW9uIE1MRm9sZFRyZWUkcmVuZGVyVHJlZSAoZGF0YSkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLl9kYXRhID0gZGF0YTtcbiAgICBzZWxmLl9pdGVtc01hcCA9IHt9O1xuICAgIHRoaXMuZWwuaW5uZXJIVE1MID0gX3JlbmRlclRyZWUoZGF0YSk7XG5cbiAgICBmdW5jdGlvbiBfcmVuZGVyVHJlZSAoZGF0YSkge1xuICAgICAgICBpZiAoZGF0YS5pdGVtcylcbiAgICAgICAgICAgIHZhciBpdGVtc0lEcyA9IF8ubWFwKGRhdGEuaXRlbXMsIGZ1bmN0aW9uKGl0ZW0pIHtcbiAgICAgICAgICAgICAgICB2YXIgaWQgPSBtaWxvQ291bnQoKTtcbiAgICAgICAgICAgICAgICBzZWxmLl9pdGVtc01hcFtpZF0gPSBpdGVtO1xuICAgICAgICAgICAgICAgIHJldHVybiBpZDsgXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gQ09NUElMRURfVFJFRV9URU1QTEFURSh7XG4gICAgICAgICAgICBpdGVtSURzOiBpdGVtc0lEcyxcbiAgICAgICAgICAgIGRhdGE6IGRhdGEsXG4gICAgICAgICAgICBpdGVtVGVtcGxhdGU6IHNlbGYuX2l0ZW1UZW1wbGF0ZSB8fCBERUZBVUxUX0NPTVBJTEVEX0lURU1fVEVNUExBVEUsXG4gICAgICAgICAgICB0cmVlVGVtcGxhdGU6IF9yZW5kZXJUcmVlXG4gICAgICAgIH0pO1xuICAgIH1cbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpO1xuXG5cbnZhciBNTEdyb3VwID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTEdyb3VwJywge1xuICAgIGNvbnRhaW5lcjogdW5kZWZpbmVkLFxuICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktZ3JvdXAnXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxHcm91cCk7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxHcm91cDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpO1xuXG5cbnZhciBNTEh5cGVybGluayA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxIeXBlcmxpbmsnLCB7XG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZGF0YTogdW5kZWZpbmVkLFxuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS1oeXBlcmxpbmsnXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxIeXBlcmxpbmspO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MSHlwZXJsaW5rO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5JylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG52YXIgSU1BR0VfQ0hBTkdFX01FU1NBR0UgPSAnbWxpbWFnZWNoYW5nZSc7XG5cbnZhciBNTEltYWdlID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTEltYWdlJywge1xuICAgIGRhdGE6IHtcbiAgICAgICAgc2V0OiBNTEltYWdlX3NldCxcbiAgICAgICAgZ2V0OiBNTEltYWdlX2dldCxcbiAgICAgICAgZGVsOiBNTEltYWdlX2RlbCxcbiAgICAgICAgc3BsaWNlOiB1bmRlZmluZWQsXG4gICAgICAgIGV2ZW50OiBJTUFHRV9DSEFOR0VfTUVTU0FHRVxuICAgIH0sXG4gICAgbW9kZWw6IHtcbiAgICAgICAgbWVzc2FnZXM6IHtcbiAgICAgICAgICAgICcuc3JjJzogeyBzdWJzY3JpYmVyOiBvbk1vZGVsQ2hhbmdlLCBjb250ZXh0OiAnb3duZXInIH1cbiAgICAgICAgfVxuICAgIH0sXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgY29udGFpbmVyOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIHRhZ05hbWU6ICdpbWcnLFxuICAgICAgICBjbHM6ICdtbC11aS1pbWFnZSdcbiAgICB9XG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTEltYWdlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBNTEltYWdlO1xuXG5cbl8uZXh0ZW5kUHJvdG8oTUxJbWFnZSwge1xuICAgIGluaXQ6IE1MSW1hZ2UkaW5pdFxufSk7XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsaXplIHJhZGlvIGdyb3VwIGFuZCBzZXR1cFxuICovXG5mdW5jdGlvbiBNTEltYWdlJGluaXQoKSB7XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuLyoqXG4gKiBTZXRzIGltYWdlIHZhbHVlXG4gKiBSZXBsYWNlcyB0aGUgZGF0YSBzZXQgb3BlcmF0aW9uIHRvIGRlYWwgd2l0aCByYWRpbyBidXR0b25zXG4gKlxuICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIGJlIHNldFxuICovXG5mdW5jdGlvbiBNTEltYWdlX3NldCh2YWx1ZSkge1xuICAgIHRoaXMubW9kZWwuc2V0KHZhbHVlKTtcbiAgICByZXR1cm4gdmFsdWU7XG59XG5cblxuLyoqXG4gKiBHZXRzIGdyb3VwIHZhbHVlXG4gKiBSZXRyaWV2ZXMgdGhlIHNlbGVjdGVkIHZhbHVlIG9mIHRoZSBncm91cFxuICpcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gTUxJbWFnZV9nZXQoKSB7XG4gICAgdmFyIHZhbHVlID0gdGhpcy5tb2RlbC5nZXQoKTtcbiAgICByZXR1cm4gdmFsdWUgJiYgdHlwZW9mIHZhbHVlID09ICdvYmplY3QnID8gXy5jbG9uZSh2YWx1ZSkgOiB2YWx1ZTtcbn1cblxuXG4vKipcbiAqIERlbGV0ZWQgZ3JvdXAgdmFsdWVcbiAqIERlbGV0ZXMgdGhlIHZhbHVlIG9mIHRoZSBncm91cCwgc2V0dGluZyBpdCB0byBlbXB0eVxuICovXG5mdW5jdGlvbiBNTEltYWdlX2RlbCgpIHtcbiAgICB0aGlzLm1vZGVsLmRlbCgpO1xufVxuXG5cbi8vIFBvc3QgdGhlIGRhdGEgY2hhbmdlXG5mdW5jdGlvbiBkaXNwYXRjaENoYW5nZU1lc3NhZ2UoKSB7XG4gICAgdGhpcy5kYXRhLmRpc3BhdGNoU291cmNlTWVzc2FnZShJTUFHRV9DSEFOR0VfTUVTU0FHRSk7XG59XG5cblxuZnVuY3Rpb24gb25Nb2RlbENoYW5nZShwYXRoLCBkYXRhKSB7XG4gICAgdGhpcy5lbC5zcmMgPSBkYXRhLm5ld1ZhbHVlO1xuICAgIGRpc3BhdGNoQ2hhbmdlTWVzc2FnZS5jYWxsKHRoaXMpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5JylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG52YXIgTUxJbnB1dCA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxJbnB1dCcsIHtcbiAgICBkYXRhOiB1bmRlZmluZWQsXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogJ21sLXVpLWlucHV0J1xuICAgIH1cbn0pO1xuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MSW5wdXQpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MSW5wdXQ7XG5cbl8uZXh0ZW5kUHJvdG8oTUxJbnB1dCwge1xuICAgIGRpc2FibGU6IE1MSW5wdXQkZGlzYWJsZSxcbiAgICBpc0Rpc2FibGVkOiBNTElucHV0JGlzRGlzYWJsZWQsXG4gICAgc2V0TWF4TGVuZ3RoOiBNTElucHV0JHNldE1heExlbmd0aFxufSk7XG5cbmZ1bmN0aW9uIE1MSW5wdXQkZGlzYWJsZShkaXNhYmxlKSB7XG4gICAgdGhpcy5lbC5kaXNhYmxlZCA9IGRpc2FibGU7XG59XG5cbmZ1bmN0aW9uIE1MSW5wdXQkaXNEaXNhYmxlZCgpIHtcbiAgICByZXR1cm4gISF0aGlzLmVsLmRpc2FibGVkO1xufVxuXG5mdW5jdGlvbiBNTElucHV0JHNldE1heExlbmd0aChsZW5ndGgpIHtcbiAgICB0aGlzLmVsLnNldEF0dHJpYnV0ZSgnbWF4bGVuZ3RoJywgbGVuZ3RoKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cbnZhciBJTlBVVF9MSVNUX0NIQU5HRV9NRVNTQUdFID0gJ21saW5wdXRsaXN0Y2hhbmdlJztcblxudmFyIGFzeW5jSGFuZGxlciA9IGZ1bmN0aW9uICh2YWx1ZSwgY2FsbGJhY2spIHtjYWxsYmFjayh2YWx1ZSk7fTtcblxudmFyIE1MSW5wdXRMaXN0ID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTElucHV0TGlzdCcsIHtcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktaW5wdXQtbGlzdCdcbiAgICB9LFxuICAgIGRhdGE6IHtcbiAgICAgICAgZ2V0OiBNTElucHV0TGlzdF9nZXQsXG4gICAgICAgIHNldDogTUxJbnB1dExpc3Rfc2V0LFxuICAgICAgICBkZWw6IE1MSW5wdXRMaXN0X2RlbCxcbiAgICAgICAgc3BsaWNlOiBNTElucHV0TGlzdF9zcGxpY2UsXG4gICAgICAgIGV2ZW50OiBJTlBVVF9MSVNUX0NIQU5HRV9NRVNTQUdFXG4gICAgfSxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBjb250YWluZXI6IHVuZGVmaW5lZCxcbiAgICBtb2RlbDoge1xuICAgICAgICBtZXNzYWdlczoge1xuICAgICAgICAgICAgJyoqKic6IHsgc3Vic2NyaWJlcjogb25JdGVtc0NoYW5nZSwgY29udGV4dDogJ293bmVyJyB9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICAgIHRlbXBsYXRlOiAnXFxcbiAgICAgICAgICAgIDxkaXYgbWwtYmluZD1cIk1MTGlzdDpsaXN0XCI+XFxcbiAgICAgICAgICAgICAgICA8ZGl2IG1sLWJpbmQ9XCJNTExpc3RJdGVtOml0ZW1cIiBjbGFzcz1cImxpc3QtaXRlbVwiPlxcXG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIG1sLWJpbmQ9XCJbZGF0YV06bGFiZWxcIj48L3NwYW4+XFxcbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gbWwtYmluZD1cIltldmVudHNdOmRlbGV0ZUJ0blwiIGNsYXNzPVwiZ2x5cGhpY29uIGdseXBoaWNvbi1yZW1vdmVcIj48L3NwYW4+XFxcbiAgICAgICAgICAgICAgICA8L2Rpdj5cXFxuICAgICAgICAgICAgPC9kaXY+XFxcbiAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIG1sLWJpbmQ9XCJNTElucHV0OmlucHV0XCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIj5cXFxuICAgICAgICAgICAgPGJ1dHRvbiBtbC1iaW5kPVwiTUxCdXR0b246YnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHRcIj5cXFxuICAgICAgICAgICAgICAgIEFkZFxcXG4gICAgICAgICAgICA8L2J1dHRvbj4nXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxJbnB1dExpc3QpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MSW5wdXRMaXN0O1xuXG5fLmV4dGVuZFByb3RvKE1MSW5wdXRMaXN0LCB7XG4gICAgaW5pdDogTUxJbnB1dExpc3QkaW5pdCxcbiAgICBzZXRBc3luYzogTUxJbnB1dExpc3Qkc2V0QXN5bmMsXG4gICAgc2V0UGxhY2VIb2xkZXI6IE1MSW5wdXRMaXN0JHNldFBsYWNlSG9sZGVyLFxuICAgIGRlc3Ryb3k6IE1MSW5wdXRMaXN0JGRlc3Ryb3lcbn0pO1xuXG5mdW5jdGlvbiBNTElucHV0TGlzdCRpbml0KCkge1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMub25jZSgnY2hpbGRyZW5ib3VuZCcsIG9uQ2hpbGRyZW5Cb3VuZCk7XG4gICAgdGhpcy5tb2RlbC5zZXQoW10pO1xufVxuXG5mdW5jdGlvbiBvbkNoaWxkcmVuQm91bmQoKSB7XG4gICAgcmVuZGVyLmNhbGwodGhpcyk7XG59XG5cbmZ1bmN0aW9uIE1MSW5wdXRMaXN0JHNldFBsYWNlSG9sZGVyKHBsYWNlSG9sZGVyKSB7XG4gICAgdGhpcy5faW5wdXQuZWwuc2V0QXR0cmlidXRlKCdwbGFjZUhvbGRlcicsIHBsYWNlSG9sZGVyKTtcbn1cblxuZnVuY3Rpb24gTUxJbnB1dExpc3Qkc2V0QXN5bmMobmV3SGFuZGxlcikge1xuICAgIGFzeW5jSGFuZGxlciA9IG5ld0hhbmRsZXIgfHwgYXN5bmNIYW5kbGVyO1xufVxuXG5mdW5jdGlvbiBNTElucHV0TGlzdCRkZXN0cm95KCkge1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuZGVzdHJveS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMuX2Nvbm5lY3RvciAmJiBtaWxvLm1pbmRlci5kZXN0cm95Q29ubmVjdG9yKHRoaXMuX2Nvbm5lY3Rvcik7XG4gICAgdGhpcy5fY29ubmVjdG9yID0gbnVsbDtcbn1cblxuZnVuY3Rpb24gcmVuZGVyKCkge1xuICAgIHRoaXMudGVtcGxhdGUucmVuZGVyKCkuYmluZGVyKCk7XG4gICAgY29tcG9uZW50U2V0dXAuY2FsbCh0aGlzKTtcbn1cblxuZnVuY3Rpb24gY29tcG9uZW50U2V0dXAoKSB7XG4gICAgXy5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIHtcbiAgICAgICAgJ19pbnB1dCc6IHRoaXMuY29udGFpbmVyLnNjb3BlLmlucHV0LFxuICAgICAgICAnX2J1dHRvbic6IHRoaXMuY29udGFpbmVyLnNjb3BlLmJ1dHRvbixcbiAgICAgICAgJ19saXN0JzogdGhpcy5jb250YWluZXIuc2NvcGUubGlzdFxuICAgIH0pO1xuICAgIHRoaXMuX2Nvbm5lY3RvciA9IG1pbG8ubWluZGVyKHRoaXMuX2xpc3QubW9kZWwsICc8PDwtPj4+JywgdGhpcy5tb2RlbCk7XG4gICAgdGhpcy5fYnV0dG9uLmV2ZW50cy5vbignY2xpY2snLCB7c3Vic2NyaWJlcjogb25DbGljaywgY29udGV4dDogdGhpcyB9KTsgICBcbn1cblxuZnVuY3Rpb24gb25DbGljayhtc2cpIHtcbiAgICB2YXIgdmFsdWUgPSB0aGlzLl9pbnB1dC5kYXRhLmdldCgwKTtcbiAgICBpZiAodGhpcy5faW5wdXQuZGF0YSlcbiAgICAgICAgYXN5bmNIYW5kbGVyKHZhbHVlLCBmdW5jdGlvbiAobGFiZWwsIHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLl9saXN0Lm1vZGVsLnB1c2goeyBsYWJlbDogbGFiZWwsIHZhbHVlOiB2YWx1ZSB9KTtcbiAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB0aGlzLl9pbnB1dC5kYXRhLmRlbCgpO1xufVxuXG5mdW5jdGlvbiBvbkl0ZW1zQ2hhbmdlKG1zZywgZGF0YSkge1xuICAgIHRoaXMuZGF0YS5kaXNwYXRjaFNvdXJjZU1lc3NhZ2UoSU5QVVRfTElTVF9DSEFOR0VfTUVTU0FHRSk7XG59XG5cbmZ1bmN0aW9uIE1MSW5wdXRMaXN0X2dldCgpIHtcbiAgICB2YXIgbW9kZWwgPSB0aGlzLm1vZGVsLmdldCgpO1xuICAgIHJldHVybiBtb2RlbCA/IF8uY2xvbmUobW9kZWwpIDogdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiBNTElucHV0TGlzdF9zZXQodmFsdWUpIHtcbiAgICB0aGlzLm1vZGVsLnNldCh2YWx1ZSk7XG59XG5cbmZ1bmN0aW9uIE1MSW5wdXRMaXN0X2RlbCgpIHtcbiAgICByZXR1cm4gdGhpcy5tb2RlbC5zZXQoW10pO1xufVxuXG5mdW5jdGlvbiBNTElucHV0TGlzdF9zcGxpY2UoKSB7IC8vIC4uLiBhcmd1bWVudHNcbiAgICB0aGlzLm1vZGVsLnNwbGljZS5hcHBseSh0aGlzLm1vZGVsLCBhcmd1bWVudHMpO1xufSIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cbnZhciBMSVNUX0NIQU5HRV9NRVNTQUdFID0gJ21sbGlzdGNoYW5nZSdcbiAgICAsIERFTEVURV9CVVRUT05fTkFNRSA9ICdkZWxldGVCdG4nO1xuXG5cbnZhciBNTExpc3QgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MTGlzdCcsIHtcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktbGlzdCdcbiAgICB9LFxuICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBtb2RlbDogdW5kZWZpbmVkLFxuICAgIGxpc3Q6IHVuZGVmaW5lZFxufSk7XG5cblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTExpc3QpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MTGlzdDtcblxuXG5fLmV4dGVuZFByb3RvKE1MTGlzdCwge1xuICAgIGluaXQ6IE1MTGlzdCRpbml0LFxuICAgIGRlc3Ryb3k6IE1MTGlzdCRkZXN0cm95LFxuICAgIHJlbW92ZUl0ZW06IE1MTGlzdCRyZW1vdmVJdGVtLFxuICAgIG1vdmVJdGVtOiBNTExpc3QkbW92ZUl0ZW1cbn0pO1xuXG5cbmZ1bmN0aW9uIE1MTGlzdCRpbml0KCkge1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMub24oJ2NoaWxkcmVuYm91bmQnLCBvbkNoaWxkcmVuQm91bmQpO1xufVxuXG5cbmZ1bmN0aW9uIE1MTGlzdCRkZXN0cm95KCkge1xuICAgIHRoaXMuX2Nvbm5lY3RvciAmJiBtaWxvLm1pbmRlci5kZXN0cm95Q29ubmVjdG9yKHRoaXMuX2Nvbm5lY3Rvcik7XG4gICAgdGhpcy5fY29ubmVjdG9yID0gbnVsbDtcbiAgICBDb21wb25lbnQucHJvdG90eXBlLmRlc3Ryb3kuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuXG5mdW5jdGlvbiBNTExpc3QkcmVtb3ZlSXRlbShpbmRleCl7XG4gICAgdGhpcy5tb2RlbC5zcGxpY2UoaW5kZXgsIDEpO1xufVxuXG5cbmZ1bmN0aW9uIE1MTGlzdCRtb3ZlSXRlbShmcm9tLCB0bykge1xuICAgIHZhciBzcGxpY2VkRGF0YSA9IHRoaXMubW9kZWwuc3BsaWNlKGZyb20sIDEpO1xuICAgIHJldHVybiB0aGlzLm1vZGVsLnNwbGljZSh0bywgMCwgc3BsaWNlZERhdGFbMF0pO1xufVxuXG5cbmZ1bmN0aW9uIG9uQ2hpbGRyZW5Cb3VuZCgpIHtcbiAgICB0aGlzLm1vZGVsLnNldChbXSk7XG4gICAgdGhpcy5fY29ubmVjdG9yID0gbWlsby5taW5kZXIodGhpcy5tb2RlbCwgJzw8PC0nLCB0aGlzLmRhdGEpLmRlZmVyQ2hhbmdlTW9kZSgnPDw8LT4+PicpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBEcmFnRHJvcCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvZHJhZ2Ryb3AnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cblxudmFyIExJU1RJVEVNX0NIQU5HRV9NRVNTQUdFID0gJ21sbGlzdGl0ZW1jaGFuZ2UnXG5cbnZhciBNTExpc3RJdGVtID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTExpc3RJdGVtJywge1xuICAgIGNvbnRhaW5lcjogdW5kZWZpbmVkLFxuICAgIGRvbTogdW5kZWZpbmVkLFxuICAgIGRyYWc6IHtcbiAgICAgICAgbWV0YToge1xuICAgICAgICAgICAgcGFyYW1zOiBnZXRNZXRhRGF0YVxuICAgICAgICB9XG4gICAgfSxcbiAgICBkcm9wOiB7XG4gICAgICAgIG1lc3NhZ2VzOiB7XG4gICAgICAgICAgICAnZHJhZ2VudGVyJzogeyBzdWJzY3JpYmVyOiBvbkRyYWdIb3ZlciwgY29udGV4dDogJ293bmVyJyB9LFxuICAgICAgICAgICAgJ2RyYWdvdmVyJzogeyBzdWJzY3JpYmVyOiBvbkRyYWdIb3ZlciwgY29udGV4dDogJ293bmVyJyB9LFxuICAgICAgICAgICAgJ2RyYWdsZWF2ZSc6IHsgc3Vic2NyaWJlcjogb25EcmFnT3V0LCBjb250ZXh0OiAnb3duZXInIH0sXG4gICAgICAgICAgICAnZHJvcCc6IHsgc3Vic2NyaWJlcjogb25JdGVtRHJvcCwgY29udGV4dDogJ293bmVyJyB9XG4gICAgICAgIH0sXG4gICAgICAgIGFsbG93OiB7XG4gICAgICAgICAgICBjb21wb25lbnRzOiBpc0NvbXBvbmVudEFsbG93ZWRcbiAgICAgICAgfVxuICAgIH0sXG4gICAgZGF0YToge1xuICAgICAgICBnZXQ6IE1MTGlzdEl0ZW1fZ2V0LFxuICAgICAgICBzZXQ6IE1MTGlzdEl0ZW1fc2V0LFxuICAgICAgICBkZWw6IE1MTGlzdEl0ZW1fZGVsLFxuICAgICAgICBldmVudDogTElTVElURU1fQ0hBTkdFX01FU1NBR0VcbiAgICB9LFxuICAgIG1vZGVsOiB1bmRlZmluZWQsXG4gICAgaXRlbTogdW5kZWZpbmVkXG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTExpc3RJdGVtKTtcblxudmFyIE1MTGlzdEl0ZW0gPSBtb2R1bGUuZXhwb3J0cyA9IE1MTGlzdEl0ZW07XG5cblxuXy5leHRlbmRQcm90byhNTExpc3RJdGVtLCB7XG4gICAgaW5pdDogTUxMaXN0SXRlbSRpbml0LFxuICAgIG1vdmVJdGVtOiBNTExpc3RJdGVtJG1vdmVJdGVtLFxuICAgIHJlbW92ZUl0ZW06IE1MTGlzdEl0ZW0kcmVtb3ZlSXRlbSxcbiAgICBpc0Ryb3BBbGxvd2VkOiBNTExpc3RJdGVtJGlzRHJvcEFsbG93ZWRcbn0pO1xuXG5cbmZ1bmN0aW9uIE1MTGlzdEl0ZW0kaW5pdCgpIHtcbiAgICBDb21wb25lbnQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB0aGlzLm9uKCdjaGlsZHJlbmJvdW5kJywgb25DaGlsZHJlbkJvdW5kKTtcbn1cblxuXG5mdW5jdGlvbiBvbkNoaWxkcmVuQm91bmQoKSB7XG4gICAgdmFyIGRlbGV0ZUJ0biA9IHRoaXMuY29udGFpbmVyLnNjb3BlLmRlbGV0ZUJ0bjtcbiAgICBkZWxldGVCdG4gJiYgZGVsZXRlQnRuLmV2ZW50cy5vbignY2xpY2snLCB7IHN1YnNjcmliZXI6IHRoaXMucmVtb3ZlSXRlbSwgY29udGV4dDogdGhpcyB9KTtcbn1cblxuXG5mdW5jdGlvbiBNTExpc3RJdGVtJHJlbW92ZUl0ZW0oKSB7XG4gICAgdHJ5IHsgdmFyIGxpc3RPd25lciA9IHRoaXMuaXRlbS5saXN0Lm93bmVyOyB9IGNhdGNoKGUpIHt9XG4gICAgbGlzdE93bmVyICYmIGxpc3RPd25lci5yZW1vdmVJdGVtKHRoaXMuaXRlbS5pbmRleCk7XG59XG5cblxuZnVuY3Rpb24gTUxMaXN0SXRlbSRtb3ZlSXRlbShpbmRleCkge1xuICAgIHZhciBsaXN0T3duZXIgPSB0aGlzLml0ZW0ubGlzdC5vd25lcjtcbiAgICBsaXN0T3duZXIgJiYgbGlzdE93bmVyLm1vdmVJdGVtKHRoaXMuaXRlbS5pbmRleCwgaW5kZXgpO1xufVxuXG5cbmZ1bmN0aW9uIE1MTGlzdEl0ZW0kaXNEcm9wQWxsb3dlZChtZXRhLCBkcmFnRHJvcCl7XG4gICAgcmV0dXJuIG1ldGEucGFyYW1zICYmIG1ldGEucGFyYW1zLmluZGV4ICYmIG1ldGEuY29tcENsYXNzID09ICdNTExpc3RJdGVtJztcbn1cblxuXG5mdW5jdGlvbiBpc0NvbXBvbmVudEFsbG93ZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNEcm9wQWxsb3dlZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbmZ1bmN0aW9uIG9uSXRlbURyb3AoZXZlbnRUeXBlLCBldmVudCkge1xuICAgIG9uRHJhZ091dC5jYWxsKHRoaXMpO1xuICAgIHZhciBkdCA9IG5ldyBEcmFnRHJvcChldmVudCk7XG4gICAgdmFyIG1ldGEgPSBkdC5nZXRDb21wb25lbnRNZXRhKCk7XG4gICAgdmFyIHN0YXRlID0gZHQuZ2V0Q29tcG9uZW50U3RhdGUoKTtcbiAgICB2YXIgbGlzdE93bmVyID0gdGhpcy5pdGVtLmxpc3Qub3duZXI7XG4gICAgdmFyIGluZGV4ID0gbWV0YS5wYXJhbXMgJiYgbWV0YS5wYXJhbXMuaW5kZXg7XG5cbiAgICBsaXN0T3duZXIubW92ZUl0ZW0oK2luZGV4LCB0aGlzLml0ZW0uaW5kZXgsIHN0YXRlKTtcbn1cblxuXG5mdW5jdGlvbiBvbkRyYWdIb3ZlcihldmVudFR5cGUsIGV2ZW50KSB7XG4gICAgdGhpcy5kb20uYWRkQ3NzQ2xhc3NlcygnbWwtZHJhZy1vdmVyJyk7XG59XG5cblxuZnVuY3Rpb24gb25EcmFnT3V0KGV2ZW50VHlwZSwgZXZlbnQpIHtcbiAgICB0aGlzLmRvbS5yZW1vdmVDc3NDbGFzc2VzKCdtbC1kcmFnLW92ZXInKTtcbn1cblxuXG5mdW5jdGlvbiBnZXRNZXRhRGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBpbmRleDogdGhpcy5pdGVtLmluZGV4XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIE1MTGlzdEl0ZW1fZ2V0KCkge1xuICAgIHZhciB2YWx1ZSA9IHRoaXMubW9kZWwuZ2V0KCk7XG4gICAgcmV0dXJuIHZhbHVlICE9PSBudWxsICYmIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0JyA/IF8uY2xvbmUodmFsdWUpIDogdmFsdWU7XG59XG5cblxuZnVuY3Rpb24gTUxMaXN0SXRlbV9zZXQodmFsdWUpIHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09ICdvYmplY3QnKVxuICAgICAgICB0aGlzLmRhdGEuX3NldCh2YWx1ZSk7XG4gICAgdGhpcy5tb2RlbC5zZXQodmFsdWUpO1xuICAgIF9zZW5kQ2hhbmdlTWVzc2FnZS5jYWxsKHRoaXMpO1xuICAgIHJldHVybiB2YWx1ZTtcbn1cblxuXG5mdW5jdGlvbiBNTExpc3RJdGVtX2RlbCgpIHtcbiAgICB0aGlzLmRhdGEuX2RlbCgpO1xuICAgIHRoaXMubW9kZWwuZGVsKCk7XG4gICAgX3NlbmRDaGFuZ2VNZXNzYWdlLmNhbGwodGhpcyk7ICAgIFxufVxuXG5cbmZ1bmN0aW9uIF9zZW5kQ2hhbmdlTWVzc2FnZSgpIHtcbiAgICB0aGlzLmRhdGEuZGlzcGF0Y2hTb3VyY2VNZXNzYWdlKExJU1RJVEVNX0NIQU5HRV9NRVNTQUdFKTtcbn1cblxuXG5cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBtaWxvQ291bnQgPSByZXF1aXJlKCcuLi8uLi91dGlsL2NvdW50JylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG52YXIgUkFESU9fQ0hBTkdFX01FU1NBR0UgPSAnbWxyYWRpb2dyb3VwY2hhbmdlJ1xuICAgICwgRUxFTUVOVF9OQU1FX1BST1BFUlRZID0gJ19tbFJhZGlvR3JvdXBFbGVtZW50SUQnXG4gICAgLCBFTEVNRU5UX05BTUVfUFJFRklYID0gJ21sLXJhZGlvLWdyb3VwLSc7XG5cbnZhciBNTFJhZGlvR3JvdXAgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MUmFkaW9Hcm91cCcsIHtcbiAgICBkYXRhOiB7XG4gICAgICAgIHNldDogTUxSYWRpb0dyb3VwX3NldCxcbiAgICAgICAgZ2V0OiBNTFJhZGlvR3JvdXBfZ2V0LFxuICAgICAgICBkZWw6IE1MUmFkaW9Hcm91cF9kZWwsXG4gICAgICAgIHNwbGljZTogdW5kZWZpbmVkLFxuICAgICAgICBldmVudDogUkFESU9fQ0hBTkdFX01FU1NBR0VcbiAgICB9LFxuICAgIG1vZGVsOiB7XG4gICAgICAgIG1lc3NhZ2VzOiB7XG4gICAgICAgICAgICAnKioqJzogeyBzdWJzY3JpYmVyOiBvbk9wdGlvbnNDaGFuZ2UsIGNvbnRleHQ6ICdvd25lcicgfVxuICAgICAgICB9XG4gICAgfSxcbiAgICBldmVudHM6IHtcbiAgICAgICAgbWVzc2FnZXM6IHtcbiAgICAgICAgICAgICdjbGljayc6IHsgc3Vic2NyaWJlcjogb25Hcm91cENsaWNrLCBjb250ZXh0OiAnb3duZXInIH1cbiAgICAgICAgfVxuICAgIH0sXG4gICAgY29udGFpbmVyOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogJ21sLXVpLXJhZGlvLWdyb3VwJ1xuICAgIH0sXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgICAgdGVtcGxhdGU6ICd7e34gaXQucmFkaW9PcHRpb25zIDpvcHRpb24gfX0gXFxcbiAgICAgICAgICAgICAgICAgICAgICAgIHt7IyNkZWYuZWxJRDp7ez0gaXQuZWxlbWVudE5hbWUgfX0te3s9IG9wdGlvbi52YWx1ZSB9fSN9fSBcXFxuICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ7ez0gaXQuX3JlbmRlck9wdGlvbnMub3B0aW9uQ3NzQ2xhc3MgfHwgXCInICsgRUxFTUVOVF9OQU1FX1BSRUZJWCArICdvcHRpb25cIiB9fVwiPiBcXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpbnB1dCBpZD1cInt7IyBkZWYuZWxJRCB9fVwiIHR5cGU9XCJyYWRpb1wiIHZhbHVlPVwie3s9IG9wdGlvbi52YWx1ZSB9fVwiIG5hbWU9XCJ7ez0gaXQuZWxlbWVudE5hbWUgfX1cIj4gXFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8bGFiZWwgZm9yPVwie3sjIGRlZi5lbElEIH19XCI+e3s9IG9wdGlvbi5sYWJlbCB9fTwvbGFiZWw+IFxcXG4gICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4+IFxcXG4gICAgICAgICAgICAgICAgICAge3t+fX0nXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxSYWRpb0dyb3VwKTtcblxubW9kdWxlLmV4cG9ydHMgPSBNTFJhZGlvR3JvdXA7XG5cblxuXy5leHRlbmRQcm90byhNTFJhZGlvR3JvdXAsIHtcbiAgICBpbml0OiBNTFJhZGlvR3JvdXAkaW5pdCxcbiAgICBkZXN0cm95OiBNTFJhZGlvR3JvdXAkZGVzdHJveSxcbiAgICBzZXRSZW5kZXJPcHRpb25zOiBNTFJhZGlvR3JvdXAkc2V0UmVuZGVyT3B0aW9uc1xufSk7XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsaXplIHJhZGlvIGdyb3VwIGFuZCBzZXR1cFxuICovXG5mdW5jdGlvbiBNTFJhZGlvR3JvdXAkaW5pdCgpIHtcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdfcmFkaW9MaXN0JywgW10sIF8uQ09ORik7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBFTEVNRU5UX05BTUVfUFJPUEVSVFksIEVMRU1FTlRfTkFNRV9QUkVGSVggKyBtaWxvQ291bnQoKSk7XG4gICAgdGhpcy5fcmVuZGVyT3B0aW9ucyA9IHt9O1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbmZ1bmN0aW9uIE1MUmFkaW9Hcm91cCRzZXRSZW5kZXJPcHRpb25zKG9wdGlvbnMpIHtcbiAgICB0aGlzLl9yZW5kZXJPcHRpb25zID0gb3B0aW9ucztcbn1cblxuXG4vKipcbiAqIFNldHMgZ3JvdXAgdmFsdWVcbiAqIFJlcGxhY2VzIHRoZSBkYXRhIHNldCBvcGVyYXRpb24gdG8gZGVhbCB3aXRoIHJhZGlvIGJ1dHRvbnNcbiAqXG4gKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gYmUgc2V0XG4gKi9cbmZ1bmN0aW9uIE1MUmFkaW9Hcm91cF9zZXQodmFsdWUpIHtcbiAgICB2YXIgb3B0aW9ucyA9IHRoaXMuX3JhZGlvTGlzdFxuICAgICAgICAsIHNldFJlc3VsdDtcbiAgICBpZiAob3B0aW9ucy5sZW5ndGgpIHtcbiAgICAgICAgb3B0aW9ucy5mb3JFYWNoKGZ1bmN0aW9uKHJhZGlvKSB7XG4gICAgICAgICAgICByYWRpby5jaGVja2VkID0gcmFkaW8udmFsdWUgPT0gdmFsdWU7XG4gICAgICAgICAgICBpZiAocmFkaW8uY2hlY2tlZClcbiAgICAgICAgICAgICAgICBzZXRSZXN1bHQgPSB2YWx1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZGlzcGF0Y2hDaGFuZ2VNZXNzYWdlLmNhbGwodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIHNldFJlc3VsdDtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBHZXRzIGdyb3VwIHZhbHVlXG4gKiBSZXRyaWV2ZXMgdGhlIHNlbGVjdGVkIHZhbHVlIG9mIHRoZSBncm91cFxuICpcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gTUxSYWRpb0dyb3VwX2dldCgpIHtcbiAgICB2YXIgY2hlY2tlZCA9IF8uZmluZCh0aGlzLl9yYWRpb0xpc3QsIGZ1bmN0aW9uKHJhZGlvKSB7XG4gICAgICAgIHJldHVybiByYWRpby5jaGVja2VkO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGNoZWNrZWQgJiYgY2hlY2tlZC52YWx1ZSB8fCB1bmRlZmluZWQ7XG59XG5cblxuLyoqXG4gKiBEZWxldGVkIGdyb3VwIHZhbHVlXG4gKiBEZWxldGVzIHRoZSB2YWx1ZSBvZiB0aGUgZ3JvdXAsIHNldHRpbmcgaXQgdG8gZW1wdHlcbiAqL1xuZnVuY3Rpb24gTUxSYWRpb0dyb3VwX2RlbCgpIHtcbiAgICB2YXIgb3B0aW9ucyA9IHRoaXMuX3JhZGlvTGlzdDtcbiAgICBpZiAob3B0aW9ucy5sZW5ndGgpXG4gICAgICAgIG9wdGlvbnMuZm9yRWFjaChmdW5jdGlvbihyYWRpbykge1xuICAgICAgICAgICAgcmFkaW8uY2hlY2tlZCA9IGZhbHNlO1xuICAgICAgICB9KTtcblxuICAgIGRpc3BhdGNoQ2hhbmdlTWVzc2FnZS5jYWxsKHRoaXMpO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG59XG5cblxuLyoqXG4gKiBNYW5hZ2UgcmFkaW8gY2hpbGRyZW4gY2xpY2tzXG4gKi9cbmZ1bmN0aW9uIG9uR3JvdXBDbGljayhldmVudFR5cGUsIGV2ZW50KSB7XG4gICAgaWYgKGV2ZW50LnRhcmdldC50eXBlID09ICdyYWRpbycpXG4gICAgICAgIGRpc3BhdGNoQ2hhbmdlTWVzc2FnZS5jYWxsKHRoaXMpO1xufVxuXG4vLyBQb3N0IHRoZSBkYXRhIGNoYW5nZVxuZnVuY3Rpb24gZGlzcGF0Y2hDaGFuZ2VNZXNzYWdlKCkge1xuICAgIHRoaXMuZGF0YS5kaXNwYXRjaFNvdXJjZU1lc3NhZ2UoUkFESU9fQ0hBTkdFX01FU1NBR0UpO1xufVxuXG5cbi8vIFNldCByYWRpbyBidXR0b24gY2hpbGRyZW4gb24gbW9kZWwgY2hhbmdlXG5mdW5jdGlvbiBvbk9wdGlvbnNDaGFuZ2UocGF0aCwgZGF0YSkge1xuICAgIHRoaXMudGVtcGxhdGUucmVuZGVyKHtcbiAgICAgICAgcmFkaW9PcHRpb25zOiB0aGlzLm1vZGVsLmdldCgpLFxuICAgICAgICBlbGVtZW50TmFtZTogdGhpc1tFTEVNRU5UX05BTUVfUFJPUEVSVFldLFxuICAgICAgICBfcmVuZGVyT3B0aW9uczogdGhpcy5fcmVuZGVyT3B0aW9uc1xuICAgIH0pO1xuXG4gICAgdmFyIHJhZGlvRWxzID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCdpbnB1dFt0eXBlPVwicmFkaW9cIl0nKVxuICAgICAgICAsIG9wdGlvbnMgPSBfLnRvQXJyYXkocmFkaW9FbHMpO1xuXG4gICAgdGhpcy5fcmFkaW9MaXN0Lmxlbmd0aCA9IDA7XG4gICAgdGhpcy5fcmFkaW9MaXN0LnNwbGljZS5hcHBseSh0aGlzLl9yYWRpb0xpc3QsIFswLCAwXS5jb25jYXQob3B0aW9ucykpO1xufVxuXG5cbmZ1bmN0aW9uIE1MUmFkaW9Hcm91cCRkZXN0cm95KCkge1xuICAgIGRlbGV0ZSB0aGlzLl9yYWRpb0xpc3Q7XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jX2NsYXNzJylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2NfcmVnaXN0cnknKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbnZhciBNTFNlbGVjdCA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxTZWxlY3QnLCB7XG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogJ21sLXVpLXNlbGVjdCdcbiAgICB9LFxuICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBtb2RlbDoge1xuICAgICAgICBtZXNzYWdlczoge1xuICAgICAgICAgICAgJyoqJzogeyBzdWJzY3JpYmVyOiBvbk9wdGlvbnNDaGFuZ2UsIGNvbnRleHQ6ICdvd25lcicgfVxuICAgICAgICB9XG4gICAgfSxcbiAgICB0ZW1wbGF0ZToge1xuICAgICAgICB0ZW1wbGF0ZTogJ3t7fiBpdC5zZWxlY3RPcHRpb25zIDpvcHRpb24gfX0gXFxcbiAgICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJ7ez0gb3B0aW9uLnZhbHVlIH19XCIge3s/IG9wdGlvbi5zZWxlY3RlZCB9fXNlbGVjdGVke3s/fX0+e3s9IG9wdGlvbi5sYWJlbCB9fTwvb3B0aW9uPiBcXFxuICAgICAgICAgICAgICAgICAgIHt7fn19J1xuICAgIH1cbn0pO1xuXG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxTZWxlY3QpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MU2VsZWN0O1xuXG5cbl8uZXh0ZW5kUHJvdG8oTUxTZWxlY3QsIHtcbiAgICBzZXRPcHRpb25zOiBNTFNlbGVjdCRzZXRPcHRpb25zLFxuICAgIGRpc2FibGU6IE1MU2VsZWN0JGRpc2FibGVcbn0pO1xuXG5cbmZ1bmN0aW9uIE1MU2VsZWN0JHNldE9wdGlvbnMob3B0aW9ucykge1xuICAgIC8vIFNldCBvcHRpb25zIHRlbXBvcmFyaWx5IGRpc2FibGVzIG1vZGVsIHN1YnNjcmlwdGlvbnMgKEFzIGEgd29ya2Fyb3VuZCBmb3IgcGVyZm9ybWFuY2UgaXNzdWVzIHJlbGF0aW5nIHRvIG1vZGVsIHVwZGF0ZXMgLyB0ZW1wbGF0ZSByZS1yZW5kZXJpbmcpXG4gICAgdmFyIG1vZGVsQ2hhbmdlTGlzdGVuZXIgPSB7IGNvbnRleHQ6IHRoaXMsIHN1YnNjcmliZXI6IG9uT3B0aW9uc0NoYW5nZSB9O1xuXG4gICAgdGhpcy5tb2RlbC5vZmYoJyoqJywgbW9kZWxDaGFuZ2VMaXN0ZW5lcik7XG4gICAgdGhpcy5tb2RlbC5zZXQob3B0aW9ucyk7XG4gICAgdGhpcy5tb2RlbC5vbignKionLCBtb2RlbENoYW5nZUxpc3RlbmVyKTtcblxuICAgIG9uT3B0aW9uc0NoYW5nZS5jYWxsKHRoaXMpO1xufVxuXG5cbmZ1bmN0aW9uIE1MU2VsZWN0JGRpc2FibGUoZGlzYWJsZSkge1xuICAgIHRoaXMuZWwuZGlzYWJsZWQgPSBkaXNhYmxlO1xufVxuXG5cbmZ1bmN0aW9uIG9uT3B0aW9uc0NoYW5nZShwYXRoLCBkYXRhKSB7XG4gICAgdGhpcy50ZW1wbGF0ZS5yZW5kZXIoeyBzZWxlY3RPcHRpb25zOiB0aGlzLm1vZGVsLmdldCgpIH0pO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIE1MU3VwZXJDb21ib1xuICogQSBjb21ibyBzZWxlY3QgbGlzdCB3aXRoIGludGVsbGlnZW50IHNjcm9sbGluZyBvZiBzdXBlciBsYXJnZSBsaXN0cy5cbiAqL1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5JylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgZG9UID0gcmVxdWlyZSgnZG90JylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvbG9nZ2VyJyk7XG5cbnZhciBDT01CT19PUEVOID0gJ21sLXVpLXN1cGVyY29tYm8tb3Blbic7XG52YXIgQ09NQk9fQ0hBTkdFX01FU1NBR0UgPSAnbWxzdXBlcmNvbWJvY2hhbmdlJztcblxudmFyIE9QVElPTlNfVEVNUExBVEUgPSAne3t+IGl0LmNvbWJvT3B0aW9ucyA6b3B0aW9uOmluZGV4IH19XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHt7PyBvcHRpb24uc2VsZWN0ZWR9fWNsYXNzPVwic2VsZWN0ZWRcIiB7ez99fWRhdGEtdmFsdWU9XCJ7ez0gaW5kZXggfX1cIj57ez0gb3B0aW9uLmxhYmVsIH19PC9kaXY+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgIHt7fn19JztcblxudmFyIE1BWF9SRU5ERVJFRCA9IDEwMDtcbnZhciBCVUZGRVIgPSAyNTtcbnZhciBERUZBVUxUX0VMRU1FTlRfSEVJR0hUID0gMjA7XG5cbnZhciBNTFN1cGVyQ29tYm8gPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MU3VwZXJDb21ibycsIHtcbiAgICBldmVudHM6IHtcbiAgICAgICAgbWVzc2FnZXM6IHtcbiAgICAgICAgICAgICdtb3VzZWxlYXZlJzoge3N1YnNjcmliZXI6IG9uTW91c2VMZWF2ZSwgY29udGV4dDogJ293bmVyJ30sXG4gICAgICAgICAgICAnbW91c2VvdmVyJzoge3N1YnNjcmliZXI6IG9uTW91c2VPdmVyLCBjb250ZXh0OiAnb3duZXInfVxuICAgICAgICB9XG4gICAgfSxcbiAgICBkYXRhOiB7XG4gICAgICAgIGdldDogTUxTdXBlckNvbWJvX2dldCxcbiAgICAgICAgc2V0OiBNTFN1cGVyQ29tYm9fc2V0LFxuICAgICAgICBkZWw6IE1MU3VwZXJDb21ib19kZWwsXG4gICAgICAgIHNwbGljZTogdW5kZWZpbmVkLFxuICAgICAgICBldmVudDogQ09NQk9fQ0hBTkdFX01FU1NBR0VcbiAgICB9LFxuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS1zdXBlcmNvbWJvJ1xuICAgIH0sXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgICAgdGVtcGxhdGU6ICc8aW5wdXQgbWwtYmluZD1cIltkYXRhLCBldmVudHNdOmlucHV0XCIgY2xhc3M9XCJmb3JtLWNvbnRyb2wgbWwtdWktaW5wdXRcIj5cXFxuICAgICAgICAgICAgICAgICAgIDxkaXYgbWwtYmluZD1cIltkb21dOmFkZEl0ZW1EaXZcIiBjbGFzcz1cIm1sLXVpLXN1cGVyY29tYm8tYWRkXCI+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIG1sLWJpbmQ9XCI6YWRkUHJvbXB0XCI+PC9zcGFuPlxcXG4gICAgICAgICAgICAgICAgICAgICAgICA8YnV0dG9uIG1sLWJpbmQ9XCJbZXZlbnRzLCBkb21dOmFkZEJ0blwiIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0IG1sLXVpLWJ1dHRvblwiPkFkZDwvYnV0dG9uPlxcXG4gICAgICAgICAgICAgICAgICAgPC9kaXY+XFxcbiAgICAgICAgICAgICAgICAgICA8ZGl2IG1sLWJpbmQ9XCJbZG9tLCBldmVudHNdOmxpc3RcIiBjbGFzcz1cIm1sLXVpLXN1cGVyY29tYm8tZHJvcGRvd25cIj5cXFxuICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IG1sLWJpbmQ9XCJbZG9tXTpiZWZvcmVcIj48L2Rpdj5cXFxuICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IG1sLWJpbmQ9XCJbdGVtcGxhdGUsIGRvbSwgZXZlbnRzXTpvcHRpb25zXCIgY2xhc3M9XCJtbC11aS1zdXBlcmNvbWJvLW9wdGlvbnNcIj48L2Rpdj5cXFxuICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IG1sLWJpbmQ9XCJbZG9tXTphZnRlclwiPjwvZGl2PlxcXG4gICAgICAgICAgICAgICAgICAgPC9kaXY+J1xuICAgIH0sXG4gICAgY29udGFpbmVyOiB1bmRlZmluZWRcbn0pO1xuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MU3VwZXJDb21ibyk7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxTdXBlckNvbWJvO1xuXG4vKipcbiAqIFB1YmxpYyBBcGlcbiAqL1xuXy5leHRlbmRQcm90byhNTFN1cGVyQ29tYm8sIHtcbiAgICBpbml0OiBNTFN1cGVyQ29tYm8kaW5pdCxcbiAgICBzaG93T3B0aW9uczogTUxTdXBlckNvbWJvJHNob3dPcHRpb25zLFxuICAgIGhpZGVPcHRpb25zOiBNTFN1cGVyQ29tYm8kaGlkZU9wdGlvbnMsXG4gICAgdG9nZ2xlT3B0aW9uczogTUxTdXBlckNvbWJvJHRvZ2dsZU9wdGlvbnMsXG4gICAgc2V0T3B0aW9uczogTUxTdXBlckNvbWJvJHNldE9wdGlvbnMsXG4gICAgaW5pdE9wdGlvbnNVUkw6IE1MU3VwZXJDb21ibyRpbml0T3B0aW9uc1VSTCxcbiAgICBzZXRGaWx0ZXJlZE9wdGlvbnM6IE1MU3VwZXJDb21ibyRzZXRGaWx0ZXJlZE9wdGlvbnMsXG4gICAgdXBkYXRlOiBNTFN1cGVyQ29tYm8kdXBkYXRlLFxuICAgIHRvZ2dsZUFkZEJ1dHRvbjogTUxTdXBlckNvbWJvJHRvZ2dsZUFkZEJ1dHRvbixcbiAgICBzZXRBZGRJdGVtUHJvbXB0OiBNTFN1cGVyQ29tYm8kc2V0QWRkSXRlbVByb21wdCxcbiAgICBjbGVhckNvbWJvSW5wdXQ6IE1MU3VwZXJDb21ib19kZWxcbn0pO1xuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZFxuICogSW5pdGlhbGlzZSB0aGUgY29tcG9uZW50LCB3YWl0IGZvciBjaGlsZHJlbmJvdW5kLCBzZXR1cCBlbXB0eSBvcHRpb25zIGFycmF5cy5cbiAqL1xuZnVuY3Rpb24gTUxTdXBlckNvbWJvJGluaXQoKSB7XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICB0aGlzLm9uY2UoJ2NoaWxkcmVuYm91bmQnLCBvbkNoaWxkcmVuQm91bmQpO1xuXG4gICAgXy5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIHtcbiAgICAgICAgX29wdGlvbnNEYXRhOiBbXSxcbiAgICAgICAgX2ZpbHRlcmVkT3B0aW9uc0RhdGE6IFtdXG4gICAgfSwgXy5XUklUKTtcbn1cblxuLyoqXG4gKiBIYW5kbGVyIGZvciBpbml0IGNoaWxkcmVuYm91bmQgbGlzdGVuZXIuIFJlbmRlcnMgdGVtcGxhdGUuXG4gKi9cbmZ1bmN0aW9uIG9uQ2hpbGRyZW5Cb3VuZCgpIHtcbiAgICB0aGlzLnRlbXBsYXRlLnJlbmRlcigpLmJpbmRlcigpO1xuICAgIGNvbXBvbmVudFNldHVwLmNhbGwodGhpcyk7XG59XG5cblxuLyoqXG4gKiBEZWZpbmUgaW5zdGFuY2UgcHJvcGVydGllcywgZ2V0IHN1YmNvbXBvbmVudHMsIGNhbGwgc2V0dXAgc3ViLXRhc2tzXG4gKi9cbmZ1bmN0aW9uIGNvbXBvbmVudFNldHVwKCkge1xuICAgIHZhciBzY29wZSA9IHRoaXMuY29udGFpbmVyLnNjb3BlO1xuXG4gICAgXy5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIHtcbiAgICAgICAgX2NvbWJvSW5wdXQ6IHNjb3BlLmlucHV0LFxuICAgICAgICBfY29tYm9MaXN0OiBzY29wZS5saXN0LFxuICAgICAgICBfY29tYm9PcHRpb25zOiBzY29wZS5vcHRpb25zLFxuICAgICAgICBfY29tYm9CZWZvcmU6IHNjb3BlLmJlZm9yZSxcbiAgICAgICAgX2NvbWJvQWZ0ZXI6IHNjb3BlLmFmdGVyLFxuICAgICAgICBfY29tYm9BZGRJdGVtRGl2OiBzY29wZS5hZGRJdGVtRGl2LFxuICAgICAgICBfY29tYm9BZGRQcm9tcHQ6IHNjb3BlLmFkZFByb21wdCxcbiAgICAgICAgX2NvbWJvQWRkQnRuOiBzY29wZS5hZGRCdG4sXG4gICAgICAgIF9vcHRpb25UZW1wbGF0ZTogZG9ULmNvbXBpbGUoT1BUSU9OU19URU1QTEFURSlcbiAgICB9KTtcblxuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgIF9zdGFydEluZGV4OiAwLFxuICAgICAgICBfZW5kSW5kZXg6IE1BWF9SRU5ERVJFRCxcbiAgICAgICAgX2hpZGRlbjogZmFsc2UsXG4gICAgICAgIF9lbGVtZW50SGVpZ2h0OiBERUZBVUxUX0VMRU1FTlRfSEVJR0hULFxuICAgICAgICBfdG90YWw6IDAsXG4gICAgICAgIF9vcHRpb25zSGVpZ2h0OiAyMDAsXG4gICAgICAgIF9sYXN0U2Nyb2xsUG9zOiAwLFxuICAgICAgICBfY3VycmVudFZhbHVlOiBudWxsLFxuICAgICAgICBfc2VsZWN0ZWQ6IG51bGwsXG4gICAgICAgIF9pc0FkZEJ1dHRvblNob3duOiBmYWxzZVxuICAgIH0sIF8uV1JJVCk7XG5cbiAgICAvLyBDb21wb25lbnQgU2V0dXBcbiAgICB0aGlzLmRvbS5zZXRTdHlsZXMoeyBwb3NpdGlvbjogJ3JlbGF0aXZlJyB9KTtcbiAgICBzZXR1cENvbWJvTGlzdCh0aGlzLl9jb21ib0xpc3QsIHRoaXMuX2NvbWJvT3B0aW9ucywgdGhpcyk7XG4gICAgc2V0dXBDb21ib0lucHV0KHRoaXMuX2NvbWJvSW5wdXQsIHRoaXMpO1xuICAgIHNldHVwQ29tYm9CdG4odGhpcy5fY29tYm9BZGRCdG4sIHRoaXMpO1xuXG4gICAgdGhpcy5ldmVudHMub24oJ2tleWRvd24nLCB7IHN1YnNjcmliZXI6IGNoYW5nZVNlbGVjdGVkLCBjb250ZXh0OiB0aGlzIH0pO1xuICAgIC8vdGhpcy5ldmVudHMub24oJ21vdXNlbGVhdmUnLCB7IHN1YnNjcmliZXI6IE1MU3VwZXJDb21ibyRoaWRlT3B0aW9ucywgY29udGV4dDogdGhpcyB9KTtcbn1cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTaG93cyBvciBoaWRlcyBvcHRpb24gbGlzdC5cbiAqXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHNob3cgdHJ1ZSB0byBzaG93LCBmYWxzZSB0byBoaWRlXG4gKi9cbmZ1bmN0aW9uIE1MU3VwZXJDb21ibyR0b2dnbGVPcHRpb25zKHNob3cpIHtcbiAgICB0aGlzLl9oaWRkZW4gPSAhc2hvdztcbiAgICB0aGlzLl9jb21ib0xpc3QuZG9tLnRvZ2dsZShzaG93KTtcbn1cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTaG93cyBvcHRpb25zIGxpc3RcbiAqL1xuZnVuY3Rpb24gTUxTdXBlckNvbWJvJHNob3dPcHRpb25zKCkge1xuICAgIHRoaXMuX2hpZGRlbiA9IGZhbHNlO1xuICAgIHRoaXMuZWwuY2xhc3NMaXN0LmFkZChDT01CT19PUEVOKTtcbiAgICB0aGlzLl9jb21ib0xpc3QuZG9tLnRvZ2dsZSh0cnVlKTtcbn1cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBIaWRlcyBvcHRpb25zIGxpc3RcbiAqL1xuZnVuY3Rpb24gTUxTdXBlckNvbWJvJGhpZGVPcHRpb25zKCkge1xuICAgIHRoaXMuX2hpZGRlbiA9IHRydWU7XG4gICAgdGhpcy5lbC5jbGFzc0xpc3QucmVtb3ZlKENPTUJPX09QRU4pO1xuICAgIHRoaXMuX2NvbWJvTGlzdC5kb20udG9nZ2xlKGZhbHNlKTtcbn1cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBIaWRlcyBhZGQgYnV0dG9uXG4gKi9cbmZ1bmN0aW9uIE1MU3VwZXJDb21ibyR0b2dnbGVBZGRCdXR0b24oc2hvdywgb3B0aW9ucykge1xuICAgIHRoaXMuX2NvbWJvQWRkSXRlbURpdi5kb20udG9nZ2xlKHNob3cpO1xuICAgIGlmIChvcHRpb25zICYmIG9wdGlvbnMucHJlc2VydmVTdGF0ZSkgdGhpcy5fX3Nob3dBZGRPbkNsaWNrID0gdGhpcy5faXNBZGRCdXR0b25TaG93bjtcbiAgICB0aGlzLl9pc0FkZEJ1dHRvblNob3duID0gc2hvdztcbn1cblxuXG5mdW5jdGlvbiBNTFN1cGVyQ29tYm8kc2V0QWRkSXRlbVByb21wdChwcm9tcHQpIHtcbiAgICB0aGlzLl9hZGRJdGVtUHJvbXB0ID0gcHJvbXB0O1xuICAgIHRoaXMuX2NvbWJvQWRkUHJvbXB0LmVsLmlubmVySFRNTCA9IHByb21wdDtcbiAgICB0aGlzLnRvZ2dsZUFkZEJ1dHRvbihmYWxzZSk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTZXRzIHRoZSBvcHRpb25zIG9mIHRoZSBkcm9wZG93blxuICpcbiAqIEBwYXJhbSB7QXJyYXlbT2JqZWN0XX0gYXJyIHRoZSBvcHRpb25zIHRvIHNldCB3aXRoIGxhYmVsIGFuZCB2YWx1ZSBwYWlycy4gVmFsdWUgY2FuIGJlIGFuIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gTUxTdXBlckNvbWJvJHNldE9wdGlvbnMoYXJyKSB7XG4gICAgdGhpcy5fb3B0aW9uc0RhdGEgPSBhcnI7XG4gICAgdGhpcy5zZXRGaWx0ZXJlZE9wdGlvbnMoYXJyKTtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIEluaXRpYWxpc2UgdGhlIHJlbW90ZSBvcHRpb25zIG9mIHRoZSBkcm9wZG93blxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIHRoZSBvcHRpb25zIHRvIGluaXRpYWxpc2UuXG4gKi9cbmZ1bmN0aW9uIE1MU3VwZXJDb21ibyRpbml0T3B0aW9uc1VSTChvcHRpb25zKSB7XG4gICAgdGhpcy5fb3B0aW9uc1VSTCA9IG9wdGlvbnMudXJsO1xuICAgIHRoaXMuX2Zvcm1hdE9wdGlvbnNVUkwgPSBvcHRpb25zLmZvcm1hdE9wdGlvbnMgfHwgZnVuY3Rpb24oZSl7cmV0dXJuIGU7fTtcbn1cblxuXG4vKipcbiAqIFByaXZhdGUgbWV0aG9kXG4gKiBTZXRzIHRoZSBvcHRpb25zIG9mIHRoZSBkcm9wZG93biBiYXNlZCBvbiBhIHJlcXVlc3RcbiAqL1xuZnVuY3Rpb24gX2dldE9wdGlvbnNVUkwoY2IpIHtcbiAgICB2YXIgdXJsID0gdGhpcy5fb3B0aW9uc1VSTCxcbiAgICAgICAgcXVlcnlTdHJpbmcgPSB0aGlzLl9jb21ib0lucHV0LmRhdGEuZ2V0KCk7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGNiID0gY2IgfHwgXy5ub29wO1xuICAgIG1pbG8udXRpbC5yZXF1ZXN0LnBvc3QodXJsLCB7IG5hbWU6IHF1ZXJ5U3RyaW5nIH0sIGZ1bmN0aW9uIChlcnIsIHJlc3BvbnNlKSB7XG4gICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcignQ2FuIG5vdCBzZWFyY2ggZm9yIFwiJyArIHF1ZXJ5U3RyaW5nICsgJ1wiJyk7XG4gICAgICAgICAgICByZXR1cm4gY2IobmV3IEVycm9yKCdSZXF1ZXN0IGVycm9yJykpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHJlc3BvbnNlRGF0YSA9IF8uanNvblBhcnNlKHJlc3BvbnNlKTtcbiAgICAgICAgaWYgKHJlc3BvbnNlRGF0YSkgY2IobnVsbCwgcmVzcG9uc2VEYXRhKTtcbiAgICAgICAgZWxzZSBjYihuZXcgRXJyb3IoJ0RhdGEgZXJyb3InKSk7XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTZXRzIHRoZSBmaWx0ZXJlZCBvcHRpb25zLCB3aGljaCBpcyBhIHN1YnNldCBvZiBub3JtYWwgb3B0aW9uc1xuICpcbiAqIEBwYXJhbSB7W3R5cGVdfSBhcnIgVGhlIG9wdGlvbnMgdG8gc2V0XG4gKi9cbmZ1bmN0aW9uIE1MU3VwZXJDb21ibyRzZXRGaWx0ZXJlZE9wdGlvbnMoYXJyKSB7XG4gICAgaWYgKCEgYXJyKSByZXR1cm4gbG9nZ2VyLmVycm9yKCdzZXRGaWx0ZXJlZE9wdGlvbnM6IHBhcmFtZXRlciBpcyB1bmRlZmluZWQnKTtcbiAgICB0aGlzLl9maWx0ZXJlZE9wdGlvbnNEYXRhID0gYXJyO1xuICAgIHRoaXMuX3RvdGFsID0gYXJyLmxlbmd0aDtcbiAgICB0aGlzLnVwZGF0ZSgpO1xufVxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIFVwZGF0ZXMgdGhlIGxpc3QuIFRoaXMgaXMgdXNlZCBvbiBzY3JvbGwsIGFuZCBtYWtlcyB1c2Ugb2YgdGhlIGZpbHRlcmVkT3B0aW9ucyB0b1xuICogaW50ZWxsaWdlbnRseSBzaG93IGEgc3Vic2V0IG9mIHRoZSBmaWx0ZXJlZCBsaXN0IGF0IGEgdGltZS5cbiAqL1xuZnVuY3Rpb24gTUxTdXBlckNvbWJvJHVwZGF0ZSgpIHtcbiAgICB2YXIgd2FzSGlkZGVuID0gdGhpcy5faGlkZGVuO1xuXG4gICAgdmFyIGFyclRvU2hvdyA9IHRoaXMuX2ZpbHRlcmVkT3B0aW9uc0RhdGEuc2xpY2UodGhpcy5fc3RhcnRJbmRleCwgdGhpcy5fZW5kSW5kZXgpO1xuXG4gICAgdGhpcy5fY29tYm9PcHRpb25zLnRlbXBsYXRlLnJlbmRlcih7XG4gICAgICAgIGNvbWJvT3B0aW9uczogYXJyVG9TaG93XG4gICAgfSk7XG5cbiAgICB0aGlzLl9lbGVtZW50SGVpZ2h0ID0gdGhpcy5fZWxlbWVudEhlaWdodCB8fCBERUZBVUxUX0VMRU1FTlRfSEVJR0hUO1xuXG4gICAgaWYgKHdhc0hpZGRlbilcbiAgICAgICAgdGhpcy5oaWRlT3B0aW9ucygpO1xuXG4gICAgdmFyIGJlZm9yZUhlaWdodCA9IHRoaXMuX3N0YXJ0SW5kZXggKiB0aGlzLl9lbGVtZW50SGVpZ2h0O1xuICAgIHZhciBhZnRlckhlaWdodCA9ICh0aGlzLl90b3RhbCAtIHRoaXMuX2VuZEluZGV4KSAqIHRoaXMuX2VsZW1lbnRIZWlnaHQ7XG4gICAgdGhpcy5fY29tYm9CZWZvcmUuZWwuc3R5bGUuaGVpZ2h0ID0gYmVmb3JlSGVpZ2h0ICsgJ3B4JztcbiAgICB0aGlzLl9jb21ib0FmdGVyLmVsLnN0eWxlLmhlaWdodCA9IGFmdGVySGVpZ2h0ID4gMCA/IGFmdGVySGVpZ2h0ICsgJ3B4JyA6ICcwcHgnO1xufVxuXG4vKipcbiAqIFNldHVwIHRoZSBjb21ibyBsaXN0XG4gKlxuICogQHBhcmFtICB7Q29tcG9uZW50fSBsaXN0XG4gKiBAcGFyYW0gIHtBcnJheX0gb3B0aW9uc1xuICogQHBhcmFtICB7Q29tcG9uZW50fSBzZWxmXG4gKi9cbmZ1bmN0aW9uIHNldHVwQ29tYm9MaXN0KGxpc3QsIG9wdGlvbnMsIHNlbGYpIHtcbiAgICBzZWxmLnRvZ2dsZUFkZEJ1dHRvbihmYWxzZSk7XG4gICAgb3B0aW9ucy50ZW1wbGF0ZS5zZXQoT1BUSU9OU19URU1QTEFURSk7XG5cbiAgICBsaXN0LmRvbS5zZXRTdHlsZXMoe1xuICAgICAgICBvdmVyZmxvdzogJ3Njcm9sbCcsXG4gICAgICAgIGhlaWdodDogc2VsZi5fb3B0aW9uc0hlaWdodCArICdweCcsXG4gICAgICAgIHdpZHRoOiAnMTAwJScsXG4gICAgICAgIHBvc2l0aW9uOiAnYWJzb2x1dGUnLFxuICAgICAgICB6SW5kZXg6IDEwXG4gICAgICAgIC8vIHRvcDogeVBvcyArICdweCcsXG4gICAgICAgIC8vIGxlZnQ6IHhQb3MgKyAncHgnLFxuICAgIH0pO1xuXG4gICAgc2VsZi5oaWRlT3B0aW9ucygpO1xuICAgIGxpc3QuZXZlbnRzLm9uTWVzc2FnZXMoe1xuICAgICAgICAnY2xpY2snOiB7c3Vic2NyaWJlcjogb25MaXN0Q2xpY2ssIGNvbnRleHQ6IHNlbGZ9LFxuICAgICAgICAnc2Nyb2xsJzoge3N1YnNjcmliZXI6IG9uTGlzdFNjcm9sbCwgY29udGV4dDogc2VsZn1cbiAgICB9KTtcbn1cblxuLyoqXG4gKiBTZXR1cCB0aGUgaW5wdXQgY29tcG9uZW50XG4gKlxuICogQHBhcmFtICB7Q29tcG9uZW50fSBpbnB1dFxuICogQHBhcmFtICB7Q29tcG9uZW50fSBzZWxmXG4gKi9cbmZ1bmN0aW9uIHNldHVwQ29tYm9JbnB1dChpbnB1dCwgc2VsZikge1xuICAgIGlucHV0LmV2ZW50cy5vbmNlKCdmb2N1cycsIGZ1bmN0aW9uKCl7XG4gICAgICAgIGlucHV0LmRhdGEub24oJycsIHsgc3Vic2NyaWJlcjogb25EYXRhQ2hhbmdlLCBjb250ZXh0OiBzZWxmIH0pO1xuICAgICAgICBpbnB1dC5ldmVudHMub24oJ2NsaWNrJywge3N1YnNjcmliZXI6IG9uSW5wdXRDbGljaywgY29udGV4dDogc2VsZiB9KTtcbiAgICAgICAgaW5wdXQuZXZlbnRzLm9uKCdrZXlkb3duJywge3N1YnNjcmliZXI6IG9uRW50ZXJLZXksIGNvbnRleHQ6IHNlbGYgfSk7XG4gICAgfSk7XG59XG5cbi8qKlxuICogU2V0dXAgdGhlIGJ1dHRvblxuICogQHBhcmFtICB7Q29tcG9uZW50fSBidG5cbiAqIEBwYXJhbSAge0NvbXBvbmVudH0gc2VsZlxuICovXG5mdW5jdGlvbiBzZXR1cENvbWJvQnRuKGJ0biwgc2VsZikge1xuICAgIGJ0bi5ldmVudHMub24oJ2NsaWNrJywgeyBzdWJzY3JpYmVyOiBvbkFkZEJ0biwgY29udGV4dDogc2VsZiB9KTtcbn1cblxuXG4vKipcbiAqIEN1c3RvbSBkYXRhIGZhY2V0IGdldCBtZXRob2RcbiAqL1xuZnVuY3Rpb24gTUxTdXBlckNvbWJvX2dldCgpIHtcbiAgICByZXR1cm4gdGhpcy5fY3VycmVudFZhbHVlO1xufVxuXG4vKipcbiAqIEN1c3RvbSBkYXRhIGZhY2V0IHNldCBtZXRob2RcbiAqIEBwYXJhbSB7VmFyaWFibGV9IG9ialxuICovXG5mdW5jdGlvbiBNTFN1cGVyQ29tYm9fc2V0KG9iaikge1xuICAgIHRoaXMuX2N1cnJlbnRWYWx1ZSA9IG9iajtcbiAgICB0aGlzLl9jb21ib0lucHV0LmRhdGEuc2V0KG9iaiAmJiBvYmoubGFiZWwpO1xuICAgIF8uZGVmZXJNZXRob2QodGhpcywgJ2hpZGVPcHRpb25zJyk7XG59XG5cbi8qKlxuICogQ3VzdG9tIGRhdGEgZmFjZXQgZGVsIG1ldGhvZFxuICovXG5mdW5jdGlvbiBNTFN1cGVyQ29tYm9fZGVsKCkge1xuICAgIHRoaXMuX2N1cnJlbnRWYWx1ZSA9IG51bGw7XG4gICAgdGhpcy5fY29tYm9JbnB1dC5kYXRhLnNldCgnJyk7XG59XG5cblxuLyoqXG4gKiBJbnB1dCBkYXRhIGNoYW5nZSBoYW5kbGVyXG4gKiBXaGVuIHRoZSBpbnB1dCBkYXRhIGNoYW5nZXMsIHRoaXMgbWV0aG9kIGZpbHRlcnMgdGhlIG9wdGlvbnNEYXRhLCBhbmQgc2V0cyB0aGUgZmlyc3QgZWxlbWVudFxuICogdG8gYmUgc2VsZWN0ZWQuXG4gKiBAcGFyYW0gIHtTdHJpbmd9IG1zZ1xuICogQHBhcmFtICB7T2JqZXh0fSBkYXRhXG4gKi9cbmZ1bmN0aW9uIG9uRGF0YUNoYW5nZShtc2csIGRhdGEpIHtcbiAgICB2YXIgdGV4dCA9IGRhdGEubmV3VmFsdWUgJiYgZGF0YS5uZXdWYWx1ZS50cmltKCk7XG4gICAgaWYgKHRoaXMuX29wdGlvbnNVUkwpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICBfZ2V0T3B0aW9uc1VSTC5jYWxsKHRoaXMsIGZ1bmN0aW9uKGVyciwgcmVzcG9uc2VEYXRhKXtcbiAgICAgICAgICAgIGlmIChlcnIgfHwgIXJlc3BvbnNlRGF0YSkgcmV0dXJuO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB2YXIgb3B0aW9ucyA9IHJlc3BvbnNlRGF0YS5kYXRhLm1hcChzZWxmLl9mb3JtYXRPcHRpb25zVVJMKTtcbiAgICAgICAgICAgICAgICBzZWxmLnNldE9wdGlvbnMob3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgX3VwZGF0ZU9wdGlvbnNBbmRBZGRCdXR0b24uY2FsbChzZWxmLCB0ZXh0LCBzZWxmLl9vcHRpb25zRGF0YSk7XG4gICAgICAgICAgICB9IGNhdGNoKGUpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ0RhdGEgZXJyb3InLCBlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIGZpbHRlcmVkRGF0YSA9IF9maWx0ZXJEYXRhLmNhbGwodGhpcywgdGV4dCk7XG4gICAgICAgIF91cGRhdGVPcHRpb25zQW5kQWRkQnV0dG9uLmNhbGwodGhpcywgdGV4dCwgZmlsdGVyZWREYXRhKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gX2ZpbHRlckRhdGEodGV4dCkge1xuICAgIHJldHVybiB0aGlzLl9vcHRpb25zRGF0YS5maWx0ZXIoZnVuY3Rpb24ob3B0aW9uKSB7XG4gICAgICAgIGRlbGV0ZSBvcHRpb24uc2VsZWN0ZWQ7XG4gICAgICAgIGlmIChvcHRpb24ubGFiZWwpIHtcbiAgICAgICAgICAgIHZhciBsYWJlbCA9IG9wdGlvbi5sYWJlbC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICAgICAgcmV0dXJuIGxhYmVsLnRyaW0oKS50b0xvd2VyQ2FzZSgpLmluZGV4T2YodGV4dC50b0xvd2VyQ2FzZSgpKSA9PSAwO1xuICAgICAgICB9XG4gICAgfSk7XG59XG5cblxuZnVuY3Rpb24gX3VwZGF0ZU9wdGlvbnNBbmRBZGRCdXR0b24odGV4dCwgZmlsdGVyZWRBcnIpIHtcbiAgICBpZiAoIXRleHQpIHtcbiAgICAgICAgdGhpcy50b2dnbGVBZGRCdXR0b24oZmFsc2UsIHsgcHJlc2VydmVTdGF0ZTogdHJ1ZSB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoZmlsdGVyZWRBcnIubGVuZ3RoICYmIF8uZmluZChmaWx0ZXJlZEFyciwgaXNFeGFjdE1hdGNoKSkge1xuICAgICAgICAgICAgdGhpcy50b2dnbGVBZGRCdXR0b24oZmFsc2UsIHsgcHJlc2VydmVTdGF0ZTogdHJ1ZSB9KTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLl9hZGRJdGVtUHJvbXB0KSB7XG4gICAgICAgICAgICB0aGlzLnRvZ2dsZUFkZEJ1dHRvbih0aGlzLl9vcHRpb25zRGF0YS5sZW5ndGggPiAxIHx8IHRoaXMuX29wdGlvbnNVUkwpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGZpbHRlcmVkQXJyLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhpcy5zaG93T3B0aW9ucygpO1xuICAgICAgICAgICAgZmlsdGVyZWRBcnJbMF0uc2VsZWN0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy5fc2VsZWN0ZWQgPSBmaWx0ZXJlZEFyclswXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuaGlkZU9wdGlvbnMoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuc2V0RmlsdGVyZWRPcHRpb25zKGZpbHRlcmVkQXJyKTtcbiAgICB0aGlzLl9jb21ib0xpc3QuZWwuc2Nyb2xsVG9wID0gMDtcblxuICAgIGZ1bmN0aW9uIGlzRXhhY3RNYXRjaChpdGVtKSB7XG4gICAgICAgIHJldHVybiBpdGVtLmxhYmVsLnRvTG93ZXJDYXNlKCkgPT09IHRleHQudG9Mb3dlckNhc2UoKTtcbiAgICB9XG59XG5cbi8qKlxuICogQSBtYXAgb2Yga2V5Q29kZXMgdG8gZGlyZWN0aW9uc1xuICogQHR5cGUge09iamVjdH1cbiAqL1xudmFyIGRpcmVjdGlvbk1hcCA9IHsgJzQwJzogMSwgJzM4JzogLTEgfTtcblxuLyoqXG4gKiBMaXN0IGtleWRvd24gaGFuZGxlclxuICogQ2hhbmdlcyB0aGUgc2VsZWN0ZWQgbGlzdCBpdGVtIGJ5IGZpbmRpbmcgdGhlIGFkamFjZW50IGl0ZW0gYW5kIHNldHRpbmcgaXQgdG8gc2VsZWN0ZWQuXG4gKlxuICogQHBhcmFtICB7c3RyaW5nfSB0eXBlXG4gKiBAcGFyYW0gIHtFdmVudH0gZXZlbnRcbiAqL1xuZnVuY3Rpb24gY2hhbmdlU2VsZWN0ZWQodHlwZSwgZXZlbnQpIHtcbiAgICAvL1RPRE8gdGVzdCBtb2NoYVxuICAgIHZhciBkaXJlY3Rpb24gPSBkaXJlY3Rpb25NYXBbZXZlbnQua2V5Q29kZV07XG5cbiAgICBpZihkaXJlY3Rpb24pXG4gICAgICAgIF9jaGFuZ2VTZWxlY3RlZC5jYWxsKHRoaXMsIGRpcmVjdGlvbik7XG59XG5cbmZ1bmN0aW9uIF9jaGFuZ2VTZWxlY3RlZChkaXJlY3Rpb24pIHtcbiAgICAvLyBUT0RPOiByZWZhY3RvciBhbmQgdGlkeSB1cCwgbG9va3MgbGlrZSBzb21lIGNvZGUgZHVwbGljYXRpb24uXG4gICAgdmFyIHNlbGVjdGVkID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCcuc2VsZWN0ZWQnKVswXVxuICAgICAgICAsIHNjcm9sbFBvcyA9IHRoaXMuX2NvbWJvTGlzdC5lbC5zY3JvbGxUb3BcbiAgICAgICAgLCBzZWxlY3RlZFBvcyA9IHNlbGVjdGVkID8gc2VsZWN0ZWQub2Zmc2V0VG9wIDogMFxuICAgICAgICAsIHJlbGF0aXZlUG9zID0gc2VsZWN0ZWRQb3MgLSBzY3JvbGxQb3M7XG5cbiAgICBpZiAoc2VsZWN0ZWQpIHtcbiAgICAgICAgdmFyIGluZGV4ID0gX2dldERhdGFWYWx1ZUZyb21FbGVtZW50LmNhbGwodGhpcywgc2VsZWN0ZWQpXG4gICAgICAgICAgICAsIHRoaXNJdGVtID0gdGhpcy5fZmlsdGVyZWRPcHRpb25zRGF0YVtpbmRleF1cbiAgICAgICAgICAgICwgYWRqSXRlbSA9IHRoaXMuX2ZpbHRlcmVkT3B0aW9uc0RhdGFbaW5kZXggKyBkaXJlY3Rpb25dO1xuXG4gICAgICAgIGlmIChhZGpJdGVtKSB7XG4gICAgICAgICAgICBkZWxldGUgdGhpc0l0ZW0uc2VsZWN0ZWQ7XG4gICAgICAgICAgICBhZGpJdGVtLnNlbGVjdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuX3NlbGVjdGVkID0gYWRqSXRlbTtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlKCk7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICBpZiAodGhpcy5fZmlsdGVyZWRPcHRpb25zRGF0YVswXSkge1xuICAgICAgICAgICAgdGhpcy5fZmlsdGVyZWRPcHRpb25zRGF0YVswXS5zZWxlY3RlZCA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZSgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHJlbGF0aXZlUG9zID4gdGhpcy5fb3B0aW9uc0hlaWdodCAtIHRoaXMuX2VsZW1lbnRIZWlnaHQqMiAmJiBkaXJlY3Rpb24gPT09IDEpXG4gICAgICAgIHRoaXMuX2NvbWJvTGlzdC5lbC5zY3JvbGxUb3AgKz0gdGhpcy5fZWxlbWVudEhlaWdodCpkaXJlY3Rpb24qNTtcblxuICAgIGlmIChyZWxhdGl2ZVBvcyA8IHRoaXMuX2VsZW1lbnRIZWlnaHQgJiYgZGlyZWN0aW9uID09PSAtMSlcbiAgICAgICAgdGhpcy5fY29tYm9MaXN0LmVsLnNjcm9sbFRvcCArPSB0aGlzLl9lbGVtZW50SGVpZ2h0KmRpcmVjdGlvbio1O1xufVxuXG5cbi8qKlxuICogTW91c2Ugb3ZlciBoYW5kbGVyXG4gKlxuICogQHBhcmFtICB7U3RyaW5nfSB0eXBlXG4gKiBAcGFyYW0gIHtFdmVudH0gZXZlbnRcbiAqL1xuZnVuY3Rpb24gb25Nb3VzZU92ZXIodHlwZSwgZXZlbnQpIHtcbiAgICB0aGlzLl9tb3VzZUlzT3ZlciA9IHRydWU7XG59XG5cblxuLyoqXG4gKiBNb3VzZSBsZWF2ZSBoYW5kbGVyXG4gKlxuICogQHBhcmFtICB7U3RyaW5nfSB0eXBlXG4gKiBAcGFyYW0gIHtFdmVudH0gZXZlbnRcbiAqL1xuZnVuY3Rpb24gb25Nb3VzZUxlYXZlKHR5cGUsIGV2ZW50KSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMuX21vdXNlSXNPdmVyID0gZmFsc2U7XG4gICAgaWYgKHRoaXMuX21vdXNlT3V0VGltZXIpIGNsZWFySW50ZXJ2YWwodGhpcy5fbW91c2VPdXRUaW1lcik7XG4gICAgdGhpcy5fbW91c2VPdXRUaW1lciA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKXtcbiAgICAgICAgaWYgKCFzZWxmLl9tb3VzZUlzT3ZlcilcbiAgICAgICAgICAgIF9vbk1vdXNlTGVhdmUuY2FsbChzZWxmKTtcbiAgICB9LCA3NTApO1xufVxuXG5mdW5jdGlvbiBfb25Nb3VzZUxlYXZlKCkge1xuICAgIHRoaXMuaGlkZU9wdGlvbnMoKTtcbiAgICB0aGlzLnRvZ2dsZUFkZEJ1dHRvbihmYWxzZSwgeyBwcmVzZXJ2ZVN0YXRlOiB0cnVlIH0pO1xufVxuXG5cbi8qKlxuICogSW5wdXQgY2xpY2sgaGFuZGxlclxuICpcbiAqIEBwYXJhbSAge1N0cmluZ30gdHlwZVxuICogQHBhcmFtICB7RXZlbnR9IGV2ZW50XG4gKi9cbmZ1bmN0aW9uIG9uSW5wdXRDbGljayh0eXBlLCBldmVudCkge1xuICAgIHRoaXMuc2hvd09wdGlvbnMoKTtcbiAgICBpZiAodGhpcy5fX3Nob3dBZGRPbkNsaWNrKSB0aGlzLnRvZ2dsZUFkZEJ1dHRvbih0cnVlKTtcbn1cblxuXG4vKipcbiAqIEVudGVyIGtleSBoYW5kbGVyXG4gKlxuICogQHBhcmFtICB7U3RyaW5nfSB0eXBlXG4gKiBAcGFyYW0gIHtFdmVudH0gZXZlbnRcbiAqL1xuZnVuY3Rpb24gb25FbnRlcktleSh0eXBlLCBldmVudCkge1xuICAgIGlmIChldmVudC5rZXlDb2RlID09IDEzKSB7XG4gICAgICAgIGlmICh0aGlzLl9zZWxlY3RlZClcbiAgICAgICAgICAgIF9zZXREYXRhLmNhbGwodGhpcyk7XG4gICAgfVxufVxuXG4vKipcbiAqIEFkZCBidXR0b24gaGFuZGxlclxuICpcbiAqIEBwYXJhbSAge1N0cmluZ30gdHlwZVxuICogQHBhcmFtICB7RXZlbnR9IGV2ZW50XG4gKi9cbmZ1bmN0aW9uIG9uQWRkQnRuICh0eXBlLCBldmVudCkge1xuICAgIHZhciBkYXRhID0geyBsYWJlbDogdGhpcy5fY29tYm9JbnB1dC5lbC52YWx1ZSB9O1xuICAgIHRoaXMucG9zdE1lc3NhZ2UoJ2FkZGl0ZW0nLCBkYXRhKTtcbiAgICB0aGlzLmV2ZW50cy5wb3N0TWVzc2FnZSgnbWlsb19zdXBlcmNvbWJvYWRkaXRlbScsIGRhdGEpO1xuICAgIHRoaXMudG9nZ2xlQWRkQnV0dG9uKGZhbHNlLCB7IHByZXNlcnZlU3RhdGU6IHRydWUgfSk7XG5cbn1cblxuLyoqXG4gKiBMaXN0IGNsaWNrIGhhbmRsZXJcbiAqXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHR5cGVcbiAqIEBwYXJhbSAge0V2ZW50fSBldmVudFxuICovXG5mdW5jdGlvbiBvbkxpc3RDbGljayAodHlwZSwgZXZlbnQpIHtcbiAgICB2YXIgaW5kZXggPSBfZ2V0RGF0YVZhbHVlRnJvbUVsZW1lbnQuY2FsbCh0aGlzLCBldmVudC50YXJnZXQpO1xuICAgIHZhciBkYXRhID0gdGhpcy5fZmlsdGVyZWRPcHRpb25zRGF0YVtpbmRleF07XG5cbiAgICB0aGlzLl9zZWxlY3RlZCA9IGRhdGE7XG4gICAgX3NldERhdGEuY2FsbCh0aGlzKTtcbiAgICB0aGlzLnVwZGF0ZSgpO1xufVxuXG5cbi8qKlxuICogTGlzdCBzY3JvbGwgaGFuZGxlclxuICpcbiAqIEBwYXJhbSAge1N0cmluZ30gdHlwZVxuICogQHBhcmFtICB7RXZlbnR9IGV2ZW50XG4gKi9cbmZ1bmN0aW9uIG9uTGlzdFNjcm9sbCAodHlwZSwgZXZlbnQpIHtcbiAgICB2YXIgc2Nyb2xsUG9zID0gZXZlbnQudGFyZ2V0LnNjcm9sbFRvcFxuICAgICAgICAsIGRpcmVjdGlvbiA9IHNjcm9sbFBvcyA+IHRoaXMuX2xhc3RTY3JvbGxQb3MgPyAnZG93bicgOiAndXAnXG4gICAgICAgICwgZmlyc3RDaGlsZCA9IHRoaXMuX2NvbWJvT3B0aW9ucy5lbC5sYXN0RWxlbWVudENoaWxkXG4gICAgICAgICwgbGFzdENoaWxkID0gdGhpcy5fY29tYm9PcHRpb25zLmVsLmZpcnN0RWxlbWVudENoaWxkXG4gICAgICAgICwgbGFzdEVsUG9zaXRpb24gPSBmaXJzdENoaWxkID8gZmlyc3RDaGlsZC5vZmZzZXRUb3AgOiAwXG4gICAgICAgICwgZmlyc3RFbFBvc2l0aW9uID0gbGFzdENoaWxkID8gbGFzdENoaWxkLm9mZnNldFRvcCA6IDBcbiAgICAgICAgLCBkaXN0RnJvbUxhc3RFbCA9IGxhc3RFbFBvc2l0aW9uIC0gc2Nyb2xsUG9zIC0gdGhpcy5fb3B0aW9uc0hlaWdodCArIHRoaXMuX2VsZW1lbnRIZWlnaHRcbiAgICAgICAgLCBkaXN0RnJvbUZpcnN0RWwgPSBzY3JvbGxQb3MgLSBmaXJzdEVsUG9zaXRpb25cbiAgICAgICAgLCBlbHNGcm9tU3RhcnQgPSBNYXRoLmZsb29yKGRpc3RGcm9tRmlyc3RFbCAvIHRoaXMuX2VsZW1lbnRIZWlnaHQpXG4gICAgICAgICwgZWxzVG9UaGVFbmQgPSBNYXRoLmZsb29yKGRpc3RGcm9tTGFzdEVsIC8gdGhpcy5fZWxlbWVudEhlaWdodClcbiAgICAgICAgLCB0b3RhbEVsZW1lbnRzQmVmb3JlID0gTWF0aC5mbG9vcihzY3JvbGxQb3MgLyB0aGlzLl9lbGVtZW50SGVpZ2h0KSAtIEJVRkZFUjtcblxuICAgIGlmICgoZGlyZWN0aW9uID09ICdkb3duJyAmJiBlbHNUb1RoZUVuZCA8IEJVRkZFUilcbiAgICAgICAgfHwgKGRpcmVjdGlvbiA9PSAndXAnICYmIGVsc0Zyb21TdGFydCA8IEJVRkZFUikpIHtcbiAgICAgICAgdGhpcy5fc3RhcnRJbmRleCA9IHRvdGFsRWxlbWVudHNCZWZvcmUgPiAwID8gdG90YWxFbGVtZW50c0JlZm9yZSA6IDA7XG4gICAgICAgIHRoaXMuX2VuZEluZGV4ID0gdG90YWxFbGVtZW50c0JlZm9yZSArIE1BWF9SRU5ERVJFRDtcbiAgICAgICAgdGhpcy5fZWxlbWVudEhlaWdodCA9IGZpcnN0Q2hpbGQuc3R5bGUuaGVpZ2h0O1xuICAgICAgICB0aGlzLnVwZGF0ZSgpO1xuICAgIH1cbiAgICB0aGlzLl9sYXN0U2Nyb2xsUG9zID0gc2Nyb2xsUG9zO1xufVxuXG5cbi8qKlxuICogUHJpdmF0ZSBtZXRob2RcbiAqIFJldHJpZXZlcyB0aGUgZGF0YS12YWx1ZSBhdHRyaWJ1dGUgdmFsdWUgZnJvbSB0aGUgZWxlbWVudCBhbmQgcmV0dXJucyBpdCBhcyBhbiBpbmRleCBvZlxuICogdGhlIGZpbHRlcmVkT3B0aW9uc1xuICpcbiAqIEBwYXJhbSAge0VsZW1lbnR9IGVsXG4gKiBAcmV0dXJuIHtOdW1iZXJ9XG4gKi9cbmZ1bmN0aW9uIF9nZXREYXRhVmFsdWVGcm9tRWxlbWVudChlbCkge1xuICAgIHJldHVybiBOdW1iZXIoZWwuZ2V0QXR0cmlidXRlKCdkYXRhLXZhbHVlJykpICsgdGhpcy5fc3RhcnRJbmRleDtcbn1cblxuLyoqXG4gKiBQcml2YXRlIG1ldGhvZFxuICogU2V0cyB0aGUgZGF0YSBvZiB0aGUgU3VwZXJDb21ibywgdGFraW5nIGNhcmUgdG8gcmVzZXQgc29tZSB0aGluZ3MgYW5kIHRlbXBvcmFyaWx5XG4gKiB1bnN1YnNjcmliZSBkYXRhIGxpc3RlbmVycy5cbiAqL1xuZnVuY3Rpb24gX3NldERhdGEoKSB7XG4gICAgZGVsZXRlIHRoaXMuX3NlbGVjdGVkLnNlbGVjdGVkO1xuICAgIHRoaXMuaGlkZU9wdGlvbnMoKTtcbiAgICB0aGlzLnRvZ2dsZUFkZEJ1dHRvbihmYWxzZSk7XG4gICAgdGhpcy5fY29tYm9JbnB1dC5kYXRhLm9mZignJywgeyBzdWJzY3JpYmVyOiBvbkRhdGFDaGFuZ2UsIGNvbnRleHQ6IHRoaXMgfSk7XG4gICAgLy9zdXBlcmNvbWJvIGxpc3RlbmVycyBvZmZcbiAgICB0aGlzLmRhdGEuc2V0KHRoaXMuX3NlbGVjdGVkKTtcbiAgICB0aGlzLmRhdGEuZGlzcGF0Y2hTb3VyY2VNZXNzYWdlKENPTUJPX0NIQU5HRV9NRVNTQUdFKTtcbiAgICB0aGlzLl9jb21ib0lucHV0LmRhdGEub24oJycsIHsgc3Vic2NyaWJlcjogb25EYXRhQ2hhbmdlLCBjb250ZXh0OiB0aGlzIH0pO1xuICAgIC8vc3VwZXJjb21ibyBsaXN0ZW5lcnMgb25cbiAgICB0aGlzLl9zZWxlY3RlZCA9IG51bGw7XG4gICAgdGhpcy5zZXRGaWx0ZXJlZE9wdGlvbnModGhpcy5fb3B0aW9uc0RhdGEpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5Jyk7XG5cblxudmFyIE1MVGV4dCA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxUZXh0Jywge1xuICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktdGV4dCdcbiAgICB9XG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTFRleHQpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MVGV4dDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvbG9nZ2VyJyk7XG5cblxudmFyIE1MVGV4dGFyZWEgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MVGV4dGFyZWEnLCB7XG4gICAgZGF0YTogdW5kZWZpbmVkLFxuICAgIGV2ZW50czogdW5kZWZpbmVkLFxuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS10ZXh0YXJlYSdcbiAgICB9XG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTFRleHRhcmVhKTtcblxubW9kdWxlLmV4cG9ydHMgPSBNTFRleHRhcmVhO1xuXG5cbnZhciBTQU1QTEVfQVVUT1JFU0laRV9URVhUID0gJ0xvcmVtIGlwc3VtIGRvbG9yIHNpdCBhbWV0LCBjb25zZWN0ZXR1ZXIgYWRpcGlzY2luZyBlbGl0LCc7XG5cblxuXy5leHRlbmRQcm90byhNTFRleHRhcmVhLCB7XG4gICAgc3RhcnRBdXRvcmVzaXplOiBNTFRleHRhcmVhJHN0YXJ0QXV0b3Jlc2l6ZSxcbiAgICBzdG9wQXV0b3Jlc2l6ZTogTUxUZXh0YXJlYSRzdG9wQXV0b3Jlc2l6ZSxcbiAgICBpc0F1dG9yZXNpemVkOiBNTFRleHRhcmVhJGlzQXV0b3Jlc2l6ZWQsXG4gICAgZGlzYWJsZTogTUxUZXh0YXJlYSRkaXNhYmxlXG59KTtcblxuXG5mdW5jdGlvbiBNTFRleHRhcmVhJHN0YXJ0QXV0b3Jlc2l6ZShvcHRpb25zKSB7XG4gICAgaWYgKHRoaXMuX2F1dG9yZXNpemUpXG4gICAgICAgIHJldHVybiBsb2dnZXIud2FybignTUxUZXh0YXJlYSBzdGFydEF1dG9yZXNpemU6IGF1dG9yZXNpemUgaXMgYWxyZWFkeSBvbicpO1xuICAgIHRoaXMuX2F1dG9yZXNpemUgPSB0cnVlO1xuICAgIHRoaXMuX2F1dG9yZXNpemVPcHRpb25zID0gb3B0aW9ucztcblxuICAgIF9hZGp1c3RBcmVhSGVpZ2h0LmNhbGwodGhpcyk7XG4gICAgX21hbmFnZVN1YnNjcmlwdGlvbnMuY2FsbCh0aGlzLCAnb24nKTtcbn1cblxuXG5mdW5jdGlvbiBfbWFuYWdlU3Vic2NyaXB0aW9ucyhvbk9mZikge1xuICAgIHRoaXMuZXZlbnRzW29uT2ZmXSgnY2xpY2snLCB7IHN1YnNjcmliZXI6IF9hZGp1c3RBcmVhSGVpZ2h0LCBjb250ZXh0OiB0aGlzIH0pO1xuICAgIHRoaXMuZGF0YVtvbk9mZl0oJycsIHsgc3Vic2NyaWJlcjogX2FkanVzdEFyZWFIZWlnaHQsIGNvbnRleHQ6IHRoaXMgfSk7XG59XG5cblxuZnVuY3Rpb24gX2FkanVzdEFyZWFIZWlnaHQoKSB7XG4gICAgdGhpcy5lbC5zdHlsZS5oZWlnaHQgPSAwO1xuXG4gICAgdmFyIG5ld0hlaWdodCA9IHRoaXMuZWwuc2Nyb2xsSGVpZ2h0XG4gICAgICAgICwgbWluSGVpZ2h0ID0gdGhpcy5fYXV0b3Jlc2l6ZU9wdGlvbnMubWluSGVpZ2h0XG4gICAgICAgICwgbWF4SGVpZ2h0ID0gdGhpcy5fYXV0b3Jlc2l6ZU9wdGlvbnMubWF4SGVpZ2h0O1xuXG4gICAgbmV3SGVpZ2h0ID0gbmV3SGVpZ2h0ID49IG1heEhlaWdodFxuICAgICAgICAgICAgICAgID8gbWF4SGVpZ2h0XG4gICAgICAgICAgICAgICAgOiBuZXdIZWlnaHQgPD0gbWluSGVpZ2h0XG4gICAgICAgICAgICAgICAgPyBtaW5IZWlnaHRcbiAgICAgICAgICAgICAgICA6IG5ld0hlaWdodDtcblxuICAgIHRoaXMuZWwuc3R5bGUuaGVpZ2h0ID0gbmV3SGVpZ2h0ICsgJ3B4Jztcbn1cblxuXG5mdW5jdGlvbiBNTFRleHRhcmVhJHN0b3BBdXRvcmVzaXplKCkge1xuICAgIGlmICghIHRoaXMuX2F1dG9yZXNpemUpXG4gICAgICAgIHJldHVybiBsb2dnZXIud2FybignTUxUZXh0YXJlYSBzdG9wQXV0b3Jlc2l6ZTogYXV0b3Jlc2l6ZSBpcyBub3Qgb24nKTtcbiAgICB0aGlzLl9hdXRvcmVzaXplID0gZmFsc2U7XG4gICAgX21hbmFnZVN1YnNjcmlwdGlvbnMuY2FsbCh0aGlzLCAnb2ZmJyk7XG59XG5cblxuZnVuY3Rpb24gTUxUZXh0YXJlYSRpc0F1dG9yZXNpemVkKCkge1xuICAgIHJldHVybiB0aGlzLl9hdXRvcmVzaXplO1xufVxuXG5cbmZ1bmN0aW9uIE1MVGV4dGFyZWEkZGVzdHJveSgpIHtcbiAgICBpZiAodGhpcy5fYXV0b3Jlc2l6ZSlcbiAgICAgICAgdGhpcy5zdG9wQXV0b3Jlc2l6ZSgpO1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuZGVzdHJveS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5mdW5jdGlvbiBNTFRleHRhcmVhJGRpc2FibGUoZGlzYWJsZSkge1xuICAgIHRoaXMuZWwuZGlzYWJsZWQgPSBkaXNhYmxlO1xufSIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpO1xuXG5cbnZhciBNTFRpbWUgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MVGltZScsIHtcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBkYXRhOiB7XG4gICAgICAgIGdldDogTUxUaW1lX2dldCxcbiAgICAgICAgc2V0OiBNTFRpbWVfc2V0LFxuICAgICAgICBkZWw6IE1MVGltZV9kZWwsXG4gICAgfSxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktdGltZSdcbiAgICB9XG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTFRpbWUpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MVGltZTtcblxuXG52YXIgVElNRV9SRUdFWCA9IC9eKFswLTldezEsMn0pKD86XFw6fFxcLikoWzAtOV17MSwyfSkkL1xuICAgICwgVElNRV9URU1QTEFURSA9ICdoaDptbSc7XG5cbmZ1bmN0aW9uIE1MVGltZV9nZXQoKSB7XG4gICAgdmFyIHRpbWVTdHIgPSB0aGlzLmVsLnZhbHVlO1xuICAgIHZhciBtYXRjaCA9IHRpbWVTdHIubWF0Y2goVElNRV9SRUdFWCk7XG4gICAgaWYgKCEgbWF0Y2gpIHJldHVybjtcbiAgICB2YXIgaG91cnMgPSBtYXRjaFsxXVxuICAgICAgICAsIG1pbnMgPSBtYXRjaFsyXTtcbiAgICBpZiAoaG91cnMgPiAyMyB8fCBtaW5zID4gNTkpIHJldHVybjtcbiAgICB2YXIgdGltZSA9IG5ldyBEYXRlKDE5NzAsIDAsIDEsIGhvdXJzLCBtaW5zKTtcblxuICAgIHJldHVybiBfLnRvRGF0ZSh0aW1lKTtcbn1cblxuXG5mdW5jdGlvbiBNTFRpbWVfc2V0KHZhbHVlKSB7XG4gICAgdmFyIHRpbWUgPSBfLnRvRGF0ZSh2YWx1ZSk7XG4gICAgaWYgKCEgdGltZSkge1xuICAgICAgICB0aGlzLmVsLnZhbHVlID0gJyc7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgdGltZVN0ciA9IFRJTUVfVEVNUExBVEVcbiAgICAgICAgICAgIC5yZXBsYWNlKCdoaCcsIHBhZCh0aW1lLmdldEhvdXJzKCkpKVxuICAgICAgICAgICAgLnJlcGxhY2UoJ21tJywgcGFkKHRpbWUuZ2V0TWludXRlcygpKSk7XG5cbiAgICB0aGlzLmVsLnZhbHVlID0gdGltZVN0cjtcbiAgICByZXR1cm4gdGltZVN0cjtcblxuICAgIGZ1bmN0aW9uIHBhZChuKSB7cmV0dXJuIG4gPCAxMCA/ICcwJyArIG4gOiBuOyB9XG59XG5cblxuZnVuY3Rpb24gTUxUaW1lX2RlbCgpIHtcbiAgICB0aGlzLmVsLnZhbHVlID0gJyc7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jX2NsYXNzJylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2NfcmVnaXN0cnknKTtcblxuXG52YXIgTUxXcmFwcGVyID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTFdyYXBwZXInLCB7XG4gICAgY29udGFpbmVyOiB1bmRlZmluZWQsXG4gICAgZGF0YTogdW5kZWZpbmVkLFxuICAgIGV2ZW50czogdW5kZWZpbmVkLFxuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS13cmFwcGVyJ1xuICAgIH1cbn0pO1xuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MV3JhcHBlcik7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxXcmFwcGVyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi8uLi9jX3JlZ2lzdHJ5JylcbiAgICAsIGNvbXBvbmVudE5hbWUgPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2NvbXBvbmVudF9uYW1lJylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvbG9nZ2VyJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cblxudmFyIEFMRVJUX0NTU19DTEFTU0VTID0ge1xuICAgIHN1Y2Nlc3M6ICdhbGVydC1zdWNjZXNzJyxcbiAgICB3YXJuaW5nOiAnYWxlcnQtd2FybmluZycsXG4gICAgaW5mbzogJ2FsZXJ0LWluZm8nLFxuICAgIGRhbmdlcjogJ2FsZXJ0LWRhbmdlcicsXG4gICAgZml4ZWQ6ICdhbGVydC1maXhlZCdcbn07XG5cblxudmFyIE1MQWxlcnQgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MQWxlcnQnLCB7XG4gICAgY29udGFpbmVyOiB1bmRlZmluZWQsXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogWydtbC1icy1hbGVydCcsICdhbGVydCcsICdmYWRlJ10sXG4gICAgICAgIGF0dHJpYnV0ZXM6IHtcbiAgICAgICAgICAgICdyb2xlJzogJ2FsZXJ0JyxcbiAgICAgICAgICAgICdhcmlhLWhpZGRlbic6ICd0cnVlJ1xuICAgICAgICB9XG4gICAgfSxcbiAgICB0ZW1wbGF0ZToge1xuICAgICAgICB0ZW1wbGF0ZTogJ1xcXG4gICAgICAgICAgICB7ez8gaXQuY2xvc2UgfX1cXFxuICAgICAgICAgICAgICAgIDxidXR0b24gbWwtYmluZD1cIltldmVudHNdOmNsb3NlQnRuXCIgdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiY2xvc2VcIiBkYXRhLWRpc21pc3M9XCJhbGVydFwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPiZ0aW1lczs8L2J1dHRvbj5cXFxuICAgICAgICAgICAge3s/fX1cXFxuICAgICAgICAgICAge3s9IGl0Lm1lc3NhZ2V9fSdcbiAgICB9XG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTEFsZXJ0KTtcblxubW9kdWxlLmV4cG9ydHMgPSBNTEFsZXJ0O1xuXG5cbl8uZXh0ZW5kKE1MQWxlcnQsIHtcbiAgICBjcmVhdGVBbGVydDogTUxBbGVydCQkY3JlYXRlQWxlcnQsXG4gICAgb3BlbkFsZXJ0OiBNTEFsZXJ0JCRvcGVuQWxlcnQsXG59KTtcblxuXG5fLmV4dGVuZFByb3RvKE1MQWxlcnQsIHtcbiAgICBvcGVuQWxlcnQ6IE1MQWxlcnQkb3BlbkFsZXJ0LFxuICAgIGNsb3NlQWxlcnQ6IE1MQWxlcnQkY2xvc2VBbGVydFxufSk7XG5cblxuLyoqXG4gKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgbmV3IGFsZXJ0IGluc3RhbmNlLiBUbyBjcmVhdGUgYW5kIG9wZW4gYXQgdGhlIHNhbWUgdGltZSB1c2UgW29wZW5BbGVydF0oI01MQWxlcnQkJG9wZW5BbGVydClcbiAqIGBvcHRpb25zYCBpcyBhbiBvYmplY3Qgd2l0aCB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6XG4gKlxuICogICAgICBtZXNzYWdlOiBzdHJpbmcgYWxlcnQgbWVzc2FnZVxuICogICAgICB0eXBlOiAgICBvcHRpb25hbCBzdHJpbmcgdGhlIHR5cGUgb2YgYWxlcnQgbWVzc2FnZSwgb25lIG9mIHN1Y2Nlc3MsIHdhcm5pbmcsIGluZm8sIGRhbmdlciwgZml4ZWRcbiAqICAgICAgICAgICAgICAgZGVmYXVsdCAnaW5mbydcbiAqICAgICAgY2xvc2U6ICAgb3B0aW9uYWwgZmFsc2UgdG8gcHJldmVudCB1c2VyIGZyb20gY2xvc2luZ1xuICogICAgICAgICAgICAgICBvciB0cnVlIChkZWZhdWx0KSB0byBlbmFibGUgY2xvc2luZyBhbmQgcmVuZGVyIGEgY2xvc2UgYnV0dG9uXG4gKiAgICAgIHRpbWVvdXQ6IG9wdGlvbmFsIHRpbWVyLCBpbiBtaWxsaXNlY29uZHMgdG8gYXV0b21hdGljYWxseSBjbG9zZSB0aGUgYWxlcnRcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBhbGVydCBjb25maWd1cmF0aW9uXG4gKi9cbmZ1bmN0aW9uIE1MQWxlcnQkJGNyZWF0ZUFsZXJ0KG9wdGlvbnMpIHtcbiAgICBjaGVjayhvcHRpb25zLCB7XG4gICAgICAgIG1lc3NhZ2U6IFN0cmluZyxcbiAgICAgICAgdHlwZTogTWF0Y2guT3B0aW9uYWwoU3RyaW5nKSxcbiAgICAgICAgY2xvc2U6IE1hdGNoLk9wdGlvbmFsKEJvb2xlYW4pLFxuICAgICAgICB0aW1lb3V0OiBNYXRjaC5PcHRpb25hbChOdW1iZXIpXG4gICAgfSk7XG5cbiAgICB2YXIgYWxlcnQgPSBNTEFsZXJ0LmNyZWF0ZU9uRWxlbWVudCgpO1xuXG4gICAgb3B0aW9ucyA9IF9wcmVwYXJlT3B0aW9ucyhvcHRpb25zKTtcblxuICAgIHZhciBhbGVydENscyA9IEFMRVJUX0NTU19DTEFTU0VTW29wdGlvbnMudHlwZV07XG4gICAgYWxlcnQuZG9tLmFkZENzc0NsYXNzZXMoYWxlcnRDbHMpO1xuXG4gICAgYWxlcnQuX2FsZXJ0ID0ge1xuICAgICAgICBvcHRpb25zOiBvcHRpb25zLFxuICAgICAgICB2aXNpYmxlOiBmYWxzZVxuICAgIH07XG5cbiAgICBhbGVydC50ZW1wbGF0ZS5yZW5kZXIob3B0aW9ucykuYmluZGVyKCk7XG5cbiAgICB2YXIgYWxlcnRTY29wZSA9IGFsZXJ0LmNvbnRhaW5lci5zY29wZTtcblxuICAgIGlmIChvcHRpb25zLmNsb3NlKVxuICAgICAgICBhbGVydFNjb3BlLmNsb3NlQnRuLmV2ZW50cy5vbignY2xpY2snLFxuICAgICAgICAgICAgeyBzdWJzY3JpYmVyOiBfb25DbG9zZUJ0bkNsaWNrLCBjb250ZXh0OiBhbGVydCB9KTtcblxuICAgIGlmIChvcHRpb25zLnRpbWVvdXQpXG4gICAgICAgIHZhciB0aW1lciA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKXtcbiAgICAgICAgICAgIGlmKGFsZXJ0Ll9hbGVydC52aXNpYmxlKVxuICAgICAgICAgICAgICAgIGFsZXJ0LmNsb3NlQWxlcnQoKTtcbiAgICAgICAgfSwgb3B0aW9ucy50aW1lb3V0KTtcblxuICAgIHJldHVybiBhbGVydDtcbn1cblxuXG4vKipcbiAqIENyZWF0ZSBhbmQgc2hvdyBhbGVydCBwb3B1cFxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIG9iamVjdCB3aXRoIG1lc3NhZ2UsIHR5cGUsIGNsb3NlIGFuZCB0aW1lb3V0XG4gKiBAcmV0dXJuIHtNTEFsZXJ0fSB0aGUgYWxlcnQgaW5zdGFuY2VcbiAqL1xuZnVuY3Rpb24gTUxBbGVydCQkb3BlbkFsZXJ0KG9wdGlvbnMpIHtcbiAgICB2YXIgYWxlcnQgPSBNTEFsZXJ0LmNyZWF0ZUFsZXJ0KG9wdGlvbnMpO1xuICAgIGFsZXJ0Lm9wZW5BbGVydCgpO1xuICAgIHJldHVybiBhbGVydDtcbn1cblxuXG5mdW5jdGlvbiBfb25DbG9zZUJ0bkNsaWNrKHR5cGUsIGV2ZW50KSB7XG4gICAgdGhpcy5jbG9zZUFsZXJ0KCk7XG59XG5cblxuZnVuY3Rpb24gX3ByZXBhcmVPcHRpb25zKG9wdGlvbnMpIHtcbiAgICBvcHRpb25zID0gXy5jbG9uZShvcHRpb25zKTtcbiAgICBvcHRpb25zLmNsb3NlID0gdHlwZW9mIG9wdGlvbnMuY2xvc2UgPT0gJ3VuZGVmaW5lZCcgfHwgb3B0aW9ucy5jbG9zZSA9PT0gdHJ1ZTtcbiAgICBvcHRpb25zLnRpbWVvdXQgPSBNYXRoLmZsb29yKG9wdGlvbnMudGltZW91dCk7XG4gICAgb3B0aW9ucy50eXBlID0gb3B0aW9ucy50eXBlIHx8ICdpbmZvJztcblxuICAgIHJldHVybiBvcHRpb25zO1xufVxuXG5cbi8qKlxuICogT3BlbiB0aGUgYWxlcnRcbiAqL1xuZnVuY3Rpb24gTUxBbGVydCRvcGVuQWxlcnQoKSB7XG4gICAgX3RvZ2dsZUFsZXJ0LmNhbGwodGhpcywgdHJ1ZSk7XG59XG5cblxuLyoqXG4gKiBDbG9zZSB0aGUgYWxlcnRcbiAqL1xuZnVuY3Rpb24gTUxBbGVydCRjbG9zZUFsZXJ0KCkge1xuICAgIF90b2dnbGVBbGVydC5jYWxsKHRoaXMsIGZhbHNlKTtcbiAgICB0aGlzLmRlc3Ryb3koKTtcbn1cblxuXG5mdW5jdGlvbiBfdG9nZ2xlQWxlcnQoZG9TaG93KSB7XG4gICAgZG9TaG93ID0gdHlwZW9mIGRvU2hvdyA9PSAndW5kZWZpbmVkJ1xuICAgICAgICAgICAgICAgID8gISB0aGlzLl9hbGVydC52aXNpYmxlXG4gICAgICAgICAgICAgICAgOiAhISBkb1Nob3c7XG5cbiAgICB2YXIgYWRkUmVtb3ZlID0gZG9TaG93ID8gJ2FkZCcgOiAncmVtb3ZlJ1xuICAgICAgICAsIGFwcGVuZFJlbW92ZSA9IGRvU2hvdyA/ICdhcHBlbmRDaGlsZCcgOiAncmVtb3ZlQ2hpbGQnO1xuXG4gICAgdGhpcy5fYWxlcnQudmlzaWJsZSA9IGRvU2hvdztcblxuICAgIGRvY3VtZW50LmJvZHlbYXBwZW5kUmVtb3ZlXSh0aGlzLmVsKTtcbiAgICB0aGlzLmRvbS50b2dnbGUoZG9TaG93KTtcbiAgICB0aGlzLmVsLnNldEF0dHJpYnV0ZSgnYXJpYS1oaWRkZW4nLCAhZG9TaG93KTtcbiAgICB0aGlzLmVsLmNsYXNzTGlzdFthZGRSZW1vdmVdKCdpbicpO1xuICAgIHRoaXMuZWxbZG9TaG93ID8gJ2ZvY3VzJyA6ICdibHVyJ10oKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uLy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vLi4vY19yZWdpc3RyeScpXG4gICAgLCBjb21wb25lbnROYW1lID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9jb21wb25lbnRfbmFtZScpXG4gICAgLCBsb2dnZXIgPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2xvZ2dlcicpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbnZhciBERUZBVUxUX0JVVFRPTlMgPSBbIHsgdHlwZTogJ2RlZmF1bHQnLCBsYWJlbDogJ09LJywgcmVzdWx0OiAnT0snIH0gXTtcblxudmFyIENMT1NFX09QVElPTlMgPSBbJ2JhY2tkcm9wJywgJ2tleWJvYXJkJywgJ2J1dHRvbiddO1xuXG52YXIgQlVUVE9OX0NTU19DTEFTU0VTID0geyAvLyBUT0RPIC0gdXNlIGluIHRlbXBsYXRlXG4gICAgZGVmYXVsdDogJ2J0bi1kZWZhdWx0JyxcbiAgICBwcmltYXJ5OiAnYnRuLXByaW1hcnknLFxuICAgIHN1Y2Nlc3M6ICdidG4tc3VjY2VzcycsXG4gICAgaW5mbzogJ2J0bi1pbmZvJyxcbiAgICB3YXJuaW5nOiAnYnRuLXdhcm5pbmcnLFxuICAgIGRhbmdlcjogJ2J0bi1kYW5nZXInLFxuICAgIGxpbms6ICdidG4tbGluaydcbn07XG5cblxuLyoqXG4gKiBEaWFsb2cgY2xhc3MgdG8gc2hvdyBjdXN0b20gZGlhbG9nIGJveGVzIGJhc2VkIG9uIGNvbmZpZ3VyYXRpb24gLSBzZWUgW2NyZWF0ZURpYWxvZ10oI01MRGlhbG9nJCRjcmVhdGVEaWFsb2cpIG1ldGhvZC5cbiAqIE9ubHkgb25lIGRpYWxvZyBjYW4gYmUgb3BlbmVkIGF0IGEgdGltZSAtIHRyeWluZyB0byBvcGVuIGFub3RoZXIgd2lsbCBsb2cgZXJyb3IgdG8gY29uc29sZS4gQ3VycmVudGx5IG9wZW5lZCBkaWFsb2cgY2FuIGJlIHJldHJpZXZlZCB1c2luZyBbZ2V0Q3VycmVudERpYWxvZ10oI01MRGlhbG9nJCRnZXRDdXJyZW50RGlhbG9nKSBjbGFzcyBtZXRob2QuXG4gKi9cbnZhciBNTERpYWxvZyA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxEaWFsb2cnLCB7XG4gICAgY29udGFpbmVyOiB1bmRlZmluZWQsXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogWydtbC1icy1kaWFsb2cnLCAnbW9kYWwnLCAnZmFkZSddLFxuICAgICAgICBhdHRyaWJ1dGVzOiB7XG4gICAgICAgICAgICAncm9sZSc6ICdkaWFsb2cnLFxuICAgICAgICAgICAgJ2FyaWEtaGlkZGVuJzogJ3RydWUnXG4gICAgICAgIH1cbiAgICB9LFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICAgIHRlbXBsYXRlOiAnXFxcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1kaWFsb2dcIj5cXFxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1jb250ZW50XCI+XFxcbiAgICAgICAgICAgICAgICAgICAge3s/IGl0LnRpdGxlIH19XFxcbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1oZWFkZXJcIj5cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7PyBpdC5jbG9zZS5idXR0b24gfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8YnV0dG9uIG1sLWJpbmQ9XCJbZXZlbnRzXTpjbG9zZUJ0blwiIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImNsb3NlXCI+JnRpbWVzOzwvYnV0dG9uPlxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge3s/fX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxoNCBjbGFzcz1cIm1vZGFsLXRpdGxlXCI+e3s9IGl0LnRpdGxlIH19PC9oND5cXFxuICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XFxcbiAgICAgICAgICAgICAgICAgICAge3s/fX1cXFxuICAgICAgICAgICAgICAgICAgICB7ez8gaXQuaHRtbCB8fCBpdC50ZXh0IH19XFxcbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1ib2R5XCIgbWwtYmluZD1cIltjb250YWluZXJdOmRpYWxvZ0JvZHlcIj5cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7PyBpdC5odG1sIH19XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3s9IGl0Lmh0bWwgfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7Pz99fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwPnt7PSBpdC50ZXh0IH19PC9wPlxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge3s/fX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XFxcbiAgICAgICAgICAgICAgICAgICAge3s/fX1cXFxuICAgICAgICAgICAgICAgICAgICB7ez8gaXQuYnV0dG9ucyAmJiBpdC5idXR0b25zLmxlbmd0aCB9fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibW9kYWwtZm9vdGVyXCI+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7e34gaXQuYnV0dG9ucyA6YnRuIH19XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCJcXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXt7PSBidG4udHlwZSB9fXt7PyBidG4uY2xzIH19IHt7PSBidG4uY2xzIH19e3s/fX1cIlxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtbC1iaW5kPVwiW2V2ZW50c106e3s9IGJ0bi5uYW1lIH19XCI+e3s9IGJ0bi5sYWJlbCB9fTwvYnV0dG9uPlxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge3t+fX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XFxcbiAgICAgICAgICAgICAgICAgICAge3s/fX1cXFxuICAgICAgICAgICAgICAgIDwvZGl2PlxcXG4gICAgICAgICAgICA8L2Rpdj4nXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxEaWFsb2cpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MRGlhbG9nO1xuXG5cbl8uZXh0ZW5kKE1MRGlhbG9nLCB7XG4gICAgY3JlYXRlRGlhbG9nOiBNTERpYWxvZyQkY3JlYXRlRGlhbG9nLFxuICAgIG9wZW5EaWFsb2c6IE1MRGlhbG9nJCRvcGVuRGlhbG9nLFxuICAgIGdldE9wZW5lZERpYWxvZzogTUxEaWFsb2ckJGdldE9wZW5lZERpYWxvZ1xufSk7XG5cblxuXy5leHRlbmRQcm90byhNTERpYWxvZywge1xuICAgIG9wZW5EaWFsb2c6IE1MRGlhbG9nJG9wZW5EaWFsb2csXG4gICAgY2xvc2VEaWFsb2c6IE1MRGlhbG9nJGNsb3NlRGlhbG9nLFxuICAgIGRlc3Ryb3k6IE1MRGlhbG9nJGRlc3Ryb3lcbn0pO1xuXG5cbi8qKlxuICogQ3JlYXRlcyBhbmQgcmV0dXJucyBkaWFsb2cgaW5zdGFuY2UuIFRvIGNyZWF0ZSBhbmQgb3BlbiBhdCB0aGUgc2FtZSB0aW1lIFtvcGVuRGlhbG9nXSgjTUxEaWFsb2ckJG9wZW5EaWFsb2cpXG4gKiBgb3B0aW9uc2AgaXMgYW4gb2JqZWN0IHdpdGggdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOlxuICpcbiAqICAgICB0aXRsZTogb3B0aW9uYWwgZGlhbG9nIHRpdGxlXG4gKiAgICAgaHRtbDogb3B0aW9uYWwgZGlhbG9nIHRleHQgYXMgaHRtbCAod2lsbCB0YWtlIHByZWNlZGVuY2Ugb3ZlciB0ZXh0IGlmIGJvdGggdGV4dCBuZCBodG1sIGFyZSBwYXNzZWQpXG4gKiAgICAgICBvclxuICogICAgIHRleHQ6IG9wdGlvbmFsIGRpYWxvZyB0ZXh0XG4gKiAgICAgY2xvc2U6IG9wdGlvbmFsIGZhbHNlIHRvIHByZXZlbnQgYmFja2Ryb3AgYW5kIGVzYyBrZXkgZnJvbSBjbG9zaW5nIHRoZSBkaWFsb2cgYW5kIHJlbW92aW5nIGNsb3NlIGJ1dHRvbiBpbiB0b3AgcmlnaHQgY29ybmVyXG4gKiAgICAgICAgICAgIG9yIHRydWUgKGRlZmF1bHQpIHRvIGVuYWJsZSBhbGwgY2xvc2Ugb3B0aW9uc1xuICogICAgICAgICAgICBvciBvYmplY3Qgd2l0aCBwcm9wZXJ0aWVzXG4gKiAgICAgICAgIGJhY2tkcm9wOiBmYWxzZSBvciB0cnVlIChkZWZhdWx0KSwgY2xvc2UgZGlhbG9nIHdoZW4gYmFja2Ryb3AgY2xpY2tlZFxuICogICAgICAgICBrZXlib2FyZDogZmFsc2Ugb3IgdHJ1ZSAoZGVmYXVsdCksIGNsb3NlIGRpYWxvZyB3aGVuIGVzYyBrZXkgaXMgcHJlc3NlZFxuICogICAgICAgICBidXR0b246IGZhbHNlIG9yIHRydWUgKGRlZmF1bHQpLCBzaG93IGNsb3NlIGJ1dHRvbiBpbiB0aGUgaGVhZGVyICh3b24ndCBiZSBzaG93biBpZiB0aGVyZSBpcyBubyBoZWFkZXIgd2hlbiB0aXRsZSBpcyBub3QgcGFzc2VkKVxuICogICAgIGJ1dHRvbnM6IG9wdGlvbmFsIGFycmF5IG9mIGJ1dHRvbnMgY29uZmlndXJhdGlvbnMsIHdoZXJlIGVhY2ggYnV0dG9uIGNvbmZpZyBpcyBhbiBvYmplY3RcbiAqICAgICAgICAgbmFtZTogICBvcHRpb25hbCBuYW1lIG9mIGNvbXBvbmVudCwgc2hvdWxkIGJlIHVuaXF1ZSBhbmQgc2hvdWxkIG5vdCBiZSBgY2xvc2VCdG5gLCBpZiBub3QgcGFzc2VkIGEgdGltZXN0YW1wIGJhc2VkIG5hbWUgd2lsbCBiZSB1c2VkXG4gKiAgICAgICAgIHR5cGU6ICAgYnV0dG9uIHR5cGUsIHdpbGwgZGV0ZXJtaW5lIGJ1dHRvbiBDU1Mgc3R5bGUuIFBvc3NpYmxlIHR5cGVzIGFyZTogZGVmdWx0LCBwcmltYXJ5LCBzdWNjZXNzLCBpbmZvLCB3YXJuaW5nLCBkYW5nZXIsIGxpbmsgKG1hcCB0byByZWxhdGVkIGJvb3RzdHJhcCBidXR0b24gc3R5bGVzKVxuICogICAgICAgICBsYWJlbDogIGJ1dHRvbiBsYWJlbFxuICogICAgICAgICBjbG9zZTogIG9wdGlvbmFsIGZhbHNlIHRvIHByZXZlbnQgdGhpcyBidXR0b24gZnJvbSBjbG9zaW5nIGRpYWxvZ1xuICogICAgICAgICByZXN1bHQ6IHN0cmluZyB3aXRoIGRpYWxvZyBjbG9zZSByZXN1bHQgdGhhdCB3aWxsIGJlIHBhc3NlZCB0byBkaWFsb2cgc3Vic2NyaWJlciBhcyB0aGUgZmlyc3QgcGFyYW1ldGVyXG4gKiAgICAgICAgIGRhdGE6ICAgYW55IHZhbHVlL29iamVjdCBvciBmdW5jdGlvbiB0byBjcmVhdGUgZGF0YSB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIGRpYWxvZyBzdWJzY3JpYmVyIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyLlxuICogICAgICAgICAgICAgICAgIElmIGZ1bmN0aW9uIGlzIHBhc3NlZCBpdCB3aWxsIGJlIGNhbGxlZCB3aXRoIGRpYWxvZyBhcyBjb250ZXh0IGFuZCBidXR0b24gb3B0aW9ucyBhcyBwYXJhbWV0ZXIuXG4gKlxuICogICAgIElmIGB0aXRsZWAgaXMgbm90IHBhc3NlZCwgZGlhbG9nIHdpbGwgbm90IGhhdmUgdGl0bGUgc2VjdGlvbiAgIFxuICogICAgIElmIG5laXRoZXIgYHRleHRgIG5vciBgaHRtbGAgaXMgcGFzc2VkLCBkaWFsb2cgd2lsbCBub3QgaGF2ZSBib2R5IHNlY3Rpb24uXG4gKiAgICAgSWYgYGJ1dHRvbnNgIGFyZSBub3QgcGFzc2VkLCB0aGVyZSB3aWxsIG9ubHkgYmUgT0sgYnV0dG9uLlxuICpcbiAqIFdoZW4gZGlhbG9nIGlzIGNsb3NlZCwgdGhlIHN1YnNjcmliZXIgaXMgY2FsbGVkIHdpdGggcmVhdWx0IGFuZCBvcHRpb25hbCBkYXRhIGFzIGRlZmluZWQgaW4gYnV0dG9ucyBjb25maWd1cmF0aW9ucy5cbiAqIElmIGJhY2tkcm9wIGlzIGNsaWNrZWQgb3IgRVNDIGtleSBpcyBwcmVzc2VkIHRoZSByZXN1bHQgd2lsbCBiZSAnZGlzbWlzc2VkJ1xuICogSWYgY2xvc2UgYnV0dG9uIGluIHRoZSB0b3AgcmlnaHQgY29ybmVyIGlzIGNsaWNrZWQsIHRoZSByZXN1bHQgd2lsbCBiZSAnY2xvc2VkJyAoZGVmYXVsdCByZXN1bHQpXG4gKiBcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIGRpYWxvZyBjb25maWd1cmF0aW9uXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBpbml0aWFsaXplIGZ1bmN0aW9uIHRoYXQgaXMgY2FsbGVkIHRvIGluaXRpYWxpemUgdGhlIGRpYWxvZ1xuICovXG5mdW5jdGlvbiBNTERpYWxvZyQkY3JlYXRlRGlhbG9nKG9wdGlvbnMsIGluaXRpYWxpemUpIHtcbiAgICBjaGVjayhvcHRpb25zLCB7XG4gICAgICAgIHRpdGxlOiBNYXRjaC5PcHRpb25hbChTdHJpbmcpLFxuICAgICAgICBodG1sOiBNYXRjaC5PcHRpb25hbChTdHJpbmcpLFxuICAgICAgICB0ZXh0OiBNYXRjaC5PcHRpb25hbChTdHJpbmcpLFxuICAgICAgICBjbG9zZTogTWF0Y2guT3B0aW9uYWwoTWF0Y2guT25lT2YoQm9vbGVhbiwge1xuICAgICAgICAgICAgYmFja2Ryb3A6IE1hdGNoLk9wdGlvbmFsKEJvb2xlYW4pLFxuICAgICAgICAgICAga2V5Ym9hcmQ6IE1hdGNoLk9wdGlvbmFsKEJvb2xlYW4pLFxuICAgICAgICAgICAgYnV0dG9uOiBNYXRjaC5PcHRpb25hbChCb29sZWFuKVxuICAgICAgICB9KSksXG4gICAgICAgIGJ1dHRvbnM6IE1hdGNoLk9wdGlvbmFsKFsge1xuICAgICAgICAgICAgbmFtZTogTWF0Y2guT3B0aW9uYWwoU3RyaW5nKSxcbiAgICAgICAgICAgIHR5cGU6IFN0cmluZyxcbiAgICAgICAgICAgIGxhYmVsOiBTdHJpbmcsXG4gICAgICAgICAgICBjbG9zZTogTWF0Y2guT3B0aW9uYWwoQm9vbGVhbiksXG4gICAgICAgICAgICByZXN1bHQ6IE1hdGNoLk9wdGlvbmFsKFN0cmluZyksXG4gICAgICAgICAgICBkYXRhOiBNYXRjaC5PcHRpb25hbChNYXRjaC5BbnkpLFxuICAgICAgICAgICAgY2xzOiBNYXRjaC5PcHRpb25hbChTdHJpbmcpXG4gICAgICAgIH0gXSlcbiAgICB9KTtcblxuICAgIHZhciBkaWFsb2cgPSBNTERpYWxvZy5jcmVhdGVPbkVsZW1lbnQoKTtcblxuICAgIG9wdGlvbnMgPSBfcHJlcGFyZU9wdGlvbnMob3B0aW9ucyk7XG4gICAgZGlhbG9nLl9kaWFsb2cgPSB7XG4gICAgICAgIG9wdGlvbnM6IG9wdGlvbnMsXG4gICAgICAgIHZpc2libGU6IGZhbHNlXG4gICAgfTtcblxuICAgIGRpYWxvZy50ZW1wbGF0ZVxuICAgICAgICAucmVuZGVyKG9wdGlvbnMpXG4gICAgICAgIC5iaW5kZXIoKTtcblxuICAgIHZhciBkaWFsb2dTY29wZSA9IGRpYWxvZy5jb250YWluZXIuc2NvcGU7XG5cbiAgICBpZiAob3B0aW9ucy5jbG9zZS5iYWNrZHJvcClcbiAgICAgICAgZGlhbG9nLmV2ZW50cy5vbignY2xpY2snLFxuICAgICAgICAgICAgeyBzdWJzY3JpYmVyOiBfb25CYWNrZHJvcENsaWNrLCBjb250ZXh0OiBkaWFsb2cgfSk7XG5cbiAgICBpZiAob3B0aW9ucy50aXRsZSAmJiBvcHRpb25zLmNsb3NlLmJ1dHRvbilcbiAgICAgICAgZGlhbG9nU2NvcGUuY2xvc2VCdG4uZXZlbnRzLm9uKCdjbGljaycsXG4gICAgICAgICAgICB7IHN1YnNjcmliZXI6IF9vbkNsb3NlQnRuQ2xpY2ssIGNvbnRleHQ6IGRpYWxvZyB9KTtcblxuICAgIG9wdGlvbnMuYnV0dG9ucy5mb3JFYWNoKGZ1bmN0aW9uKGJ0bikge1xuICAgICAgICB2YXIgYnV0dG9uU3Vic2NyaWJlciA9IHtcbiAgICAgICAgICAgIHN1YnNjcmliZXI6IF8ucGFydGlhbChfZGlhbG9nQnV0dG9uQ2xpY2ssIGJ0biksXG4gICAgICAgICAgICBjb250ZXh0OiBkaWFsb2dcbiAgICAgICAgfTtcbiAgICAgICAgZGlhbG9nU2NvcGVbYnRuLm5hbWVdLmV2ZW50cy5vbignY2xpY2snLCBidXR0b25TdWJzY3JpYmVyKTtcbiAgICB9KTtcblxuICAgIGlmIChpbml0aWFsaXplKSBpbml0aWFsaXplKGRpYWxvZyk7XG4gICAgcmV0dXJuIGRpYWxvZztcbn1cblxuXG5mdW5jdGlvbiBfZGlhbG9nQnV0dG9uQ2xpY2soYnV0dG9uKSB7XG4gICAgaWYgKGJ1dHRvbi5jbG9zZSAhPT0gZmFsc2UpXG4gICAgICAgIF90b2dnbGVEaWFsb2cuY2FsbCh0aGlzLCBmYWxzZSk7XG5cbiAgICB2YXIgZGF0YSA9IF8ucmVzdWx0KGJ1dHRvbi5kYXRhLCB0aGlzLCBidXR0b24pO1xuICAgIF9kaXNwYXRjaFJlc3VsdC5jYWxsKHRoaXMsIGJ1dHRvbi5yZXN1bHQsIGRhdGEpO1xufVxuXG5cbmZ1bmN0aW9uIF9kaXNwYXRjaFJlc3VsdChyZXN1bHQsIGRhdGEpIHtcbiAgICB2YXIgc3Vic2NyaWJlciA9IHRoaXMuX2RpYWxvZy5zdWJzY3JpYmVyO1xuICAgIGlmICh0eXBlb2Ygc3Vic2NyaWJlciA9PSAnZnVuY3Rpb24nKVxuICAgICAgICBzdWJzY3JpYmVyLmNhbGwodGhpcywgcmVzdWx0LCBkYXRhKTtcbiAgICBlbHNlXG4gICAgICAgIHN1YnNjcmliZXIuc3Vic2NyaWJlci5jYWxsKHN1YnNjcmliZXIuY29udGV4dCwgcmVzdWx0LCBkYXRhKTtcbn1cblxuXG5mdW5jdGlvbiBfb25CYWNrZHJvcENsaWNrKGV2ZW50VHlwZSwgZXZlbnQpIHtcbiAgICBpZiAoZXZlbnQudGFyZ2V0ID09IHRoaXMuZWwpXG4gICAgICAgIHRoaXMuY2xvc2VEaWFsb2coJ2Rpc21pc3NlZCcpO1xufVxuXG5cbmZ1bmN0aW9uIF9vbkNsb3NlQnRuQ2xpY2soKSB7XG4gICAgdGhpcy5jbG9zZURpYWxvZygnY2xvc2VkJyk7XG59XG5cblxuZnVuY3Rpb24gX29uS2V5RG93bihldmVudCkge1xuICAgIGlmIChvcGVuZWREaWFsb2dcbiAgICAgICAgICAgICYmIG9wZW5lZERpYWxvZy5fZGlhbG9nLm9wdGlvbnMuY2xvc2Uua2V5Ym9hcmRcbiAgICAgICAgICAgICYmIGV2ZW50LmtleUNvZGUgPT0gMjcpIC8vIGVzYyBrZXlcbiAgICAgICAgb3BlbmVkRGlhbG9nLmNsb3NlRGlhbG9nKCdkaXNtaXNzZWQnKTtcbn1cblxuXG5mdW5jdGlvbiBfcHJlcGFyZU9wdGlvbnMob3B0aW9ucykge1xuICAgIG9wdGlvbnMgPSBfLmNsb25lKG9wdGlvbnMpO1xuICAgIG9wdGlvbnMuYnV0dG9ucyA9IF8uY2xvbmUob3B0aW9ucy5idXR0b25zIHx8IERFRkFVTFRfQlVUVE9OUyk7XG4gICAgb3B0aW9ucy5idXR0b25zLmZvckVhY2goZnVuY3Rpb24oYnRuKSB7XG4gICAgICAgIGJ0bi5uYW1lID0gYnRuLm5hbWUgfHwgY29tcG9uZW50TmFtZSgpO1xuICAgIH0pO1xuXG4gICAgb3B0aW9ucy5jbG9zZSA9IHR5cGVvZiBvcHRpb25zLmNsb3NlID09ICd1bmRlZmluZWQnIHx8IG9wdGlvbnMuY2xvc2UgPT09IHRydWVcbiAgICAgICAgICAgICAgICAgICAgICAgID8gXy5vYmplY3QoQ0xPU0VfT1BUSU9OUywgdHJ1ZSlcbiAgICAgICAgICAgICAgICAgICAgICAgIDogdHlwZW9mIG9wdGlvbnMuY2xvc2UgPT0gJ29iamVjdCdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IF8ubWFwVG9PYmplY3QoQ0xPU0VfT1BUSU9OUyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24ob3B0KSB7IHJldHVybiBvcHRpb25zLmNsb3NlW29wdF0gIT09IGZhbHNlOyB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogXy5vYmplY3QoQ0xPU0VfT1BUSU9OUywgZmFsc2UpO1xuXG4gICAgcmV0dXJuIG9wdGlvbnM7XG59XG5cblxuLyoqXG4gKiBDcmVhdGUgYW5kIHNob3cgZGlhbG9nIHBvcHVwXG4gKiBcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIG9iamVjdCB3aXRoIHRpdGxlLCB0ZXh0IGFuZCBidXR0b25zLiBTZWUgW2NyZWF0ZURpYWxvZ10oI01MRGlhbG9nJCRjcmVhdGVEaWFsb2cpIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R9IHN1YnNjcmliZXIgb3B0aW9uYWwgc3Vic2NyaWJlciBmdW5jdGlvbiBvciBvYmplY3QgdGhhdCBpcyBwYXNzZWQgcmVzdWx0IGFuZCBvcHRpb25hbCBkYXRhLiBVbmxlc3MgY29udGV4dCBpcyBkZWZpbmVkLCBkaWFsb2cgd2lsbCBiZSB0aGUgY29udGV4dC5cbiAqL1xuZnVuY3Rpb24gTUxEaWFsb2ckJG9wZW5EaWFsb2cob3B0aW9ucywgc3Vic2NyaWJlciwgaW5pdGlhbGl6ZSkge1xuICAgIHZhciBkaWFsb2cgPSBNTERpYWxvZy5jcmVhdGVEaWFsb2cob3B0aW9ucywgaW5pdGlhbGl6ZSk7XG4gICAgZGlhbG9nLm9wZW5EaWFsb2coc3Vic2NyaWJlcik7XG4gICAgcmV0dXJuIGRpYWxvZztcbn1cblxuXG5cbmZ1bmN0aW9uIF90b2dnbGVEaWFsb2coZG9TaG93KSB7XG4gICAgZG9TaG93ID0gdHlwZW9mIGRvU2hvdyA9PSAndW5kZWZpbmVkJ1xuICAgICAgICAgICAgICAgID8gISB0aGlzLl9kaWFsb2cudmlzaWJsZVxuICAgICAgICAgICAgICAgIDogISEgZG9TaG93O1xuXG4gICAgdmFyIGFkZFJlbW92ZSA9IGRvU2hvdyA/ICdhZGQnIDogJ3JlbW92ZSdcbiAgICAgICAgLCBhcHBlbmRSZW1vdmUgPSBkb1Nob3cgPyAnYXBwZW5kQ2hpbGQnIDogJ3JlbW92ZUNoaWxkJztcblxuICAgIHRoaXMuX2RpYWxvZy52aXNpYmxlID0gZG9TaG93O1xuXG4gICAgaWYgKGRvU2hvdyAmJiAhIGRpYWxvZ3NJbml0aWFsaXplZClcbiAgICAgICAgX2luaXRpYWxpemVEaWFsb2dzKCk7XG5cbiAgICBkb2N1bWVudC5ib2R5W2FwcGVuZFJlbW92ZV0odGhpcy5lbCk7XG4gICAgaWYgKGJhY2tkcm9wRWwpXG4gICAgICAgIGRvY3VtZW50LmJvZHlbYXBwZW5kUmVtb3ZlXShiYWNrZHJvcEVsKTtcbiAgICB0aGlzLmRvbS50b2dnbGUoZG9TaG93KTtcbiAgICB0aGlzLmVsLnNldEF0dHJpYnV0ZSgnYXJpYS1oaWRkZW4nLCAhZG9TaG93KTtcbiAgICBkb2N1bWVudC5ib2R5LmNsYXNzTGlzdFthZGRSZW1vdmVdKCdtb2RhbC1vcGVuJyk7XG4gICAgdGhpcy5lbC5jbGFzc0xpc3RbYWRkUmVtb3ZlXSgnaW4nKTtcblxuICAgIG9wZW5lZERpYWxvZyA9IGRvU2hvdyA/IHRoaXMgOiB1bmRlZmluZWQ7XG4gICAgdGhpcy5lbFtkb1Nob3cgPyAnZm9jdXMnIDogJ2JsdXInXSgpO1xufVxuXG5cbnZhciBkaWFsb2dzSW5pdGlhbGl6ZWQsIGJhY2tkcm9wRWw7XG5cbmZ1bmN0aW9uIF9pbml0aWFsaXplRGlhbG9ncygpIHtcbiAgICBiYWNrZHJvcEVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgYmFja2Ryb3BFbC5jbGFzc05hbWUgPSAnbW9kYWwtYmFja2Ryb3AgZmFkZSBpbic7XG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIF9vbktleURvd24pO1xuICAgIGRpYWxvZ3NJbml0aWFsaXplZCA9IHRydWU7XG59XG5cblxudmFyIG9wZW5lZERpYWxvZztcblxuLyoqXG4gKiBPcGVucyBkaWFsb2cgaW5zdGFuY2UuXG4gKiBTdWJzY3JpYmVyIG9iamVjdCBzaG91bGQgaGF2ZSB0aGUgc2FtZSBmb3JtYXQgYXMgdGhlIHN1YnNjcmliZXIgZm9yIHRoZSBNZXNzZW5nZXIgKGFsdGhvdWdoIE1lc3NlbmdlciBpcyBub3QgdXNlZCkgLSBlaXRoZXIgZnVuY3Rpb24gb3Igb2JqZWN0IHdpdGggc3Vic2NyaWJlciBhbmQgY29udGV4dCBwcm9wZXJ0aWVzLlxuICogXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdH0gc3Vic2NyaWJlciBzdWJzY3JpYmVyIG9iamVjdFxuICovXG5mdW5jdGlvbiBNTERpYWxvZyRvcGVuRGlhbG9nKHN1YnNjcmliZXIpIHtcbiAgICBjaGVjayhzdWJzY3JpYmVyLCBNYXRjaC5PbmVPZihGdW5jdGlvbiwgeyBzdWJzY3JpYmVyOiBGdW5jdGlvbiwgY29udGV4dDogTWF0Y2guQW55IH0pKTtcblxuICAgIGlmIChvcGVuZWREaWFsb2cpXG4gICAgICAgIHJldHVybiBsb2dnZXIud2FybignTUxEaWFsb2cgb3BlbkRpYWxvZzogY2FuXFwndCBvcGVuIGRpYWxvZywgYW5vdGhlciBkaWFsb2cgaXMgYWxyZWFkeSBvcGVuJyk7XG5cbiAgICB0aGlzLl9kaWFsb2cuc3Vic2NyaWJlciA9IHN1YnNjcmliZXI7XG4gICAgX3RvZ2dsZURpYWxvZy5jYWxsKHRoaXMsIHRydWUpO1xufVxuXG5cbi8qKlxuICogQ2xvc2VzIGRpYWxvZyBpbnN0YW5jZSwgb3B0aW9uYWxseSBwYXNzaW5nIHJlc3VsdCBhbmQgZGF0YSB0byBkaWFsb2cgc3Vic2NyaWJlci5cbiAqIElmIG5vIHJlc3VsdCBpcyBwYXNzZWQsICdjbG9zZWQnIHdpbGwgYmUgcGFzc2VkIHRvIHN1YnNjcmliZXIuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHJlc3VsdCBkaWFsb2cgcmVzdWx0LCBwYXNzZWQgYXMgdGhlIGZpcnN0IHBhcmFtZXRlciB0byBzdWJjc3JpYmVyXG4gKiBAcGFyYW0ge0FueX0gZGF0YSBvcHRpb25hbCBkaWFsb2cgZGF0YSwgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyIHRvIHN1YnNjcmliZXJcbiAqL1xuZnVuY3Rpb24gTUxEaWFsb2ckY2xvc2VEaWFsb2cocmVzdWx0LCBkYXRhKSB7XG4gICAgaWYgKCEgb3BlbmVkRGlhbG9nKVxuICAgICAgICByZXR1cm4gbG9nZ2VyLndhcm4oJ01MRGlhbG9nIGNsb3NlRGlhbG9nOiBjYW5cXCd0IGNsb3NlIGRpYWxvZywgbm8gZGlhbG9nIG9wZW4nKTtcblxuICAgIHJlc3VsdCA9IHJlc3VsdCB8fCAnY2xvc2VkJztcblxuICAgIF90b2dnbGVEaWFsb2cuY2FsbCh0aGlzLCBmYWxzZSk7XG4gICAgX2Rpc3BhdGNoUmVzdWx0LmNhbGwodGhpcywgcmVzdWx0LCBkYXRhKTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgY3VycmVudGx5IG9wZW5lZCBkaWFsb2dcbiAqXG4gKiBAcmV0dXJuIHtNTERpYWxvZ31cbiAqL1xuZnVuY3Rpb24gTUxEaWFsb2ckJGdldE9wZW5lZERpYWxvZygpIHtcbiAgICByZXR1cm4gb3BlbmVkRGlhbG9nO1xufVxuXG5cbmZ1bmN0aW9uIE1MRGlhbG9nJGRlc3Ryb3koKSB7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIF9vbktleURvd24pO1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuZGVzdHJveS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi8uLi9jX3JlZ2lzdHJ5JylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9sb2dnZXInKVxuICAgICwgRE9NTGlzdGVuZXJzID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9kb21fbGlzdGVuZXJzJyk7XG5cblxudmFyIFRPR0dMRV9DU1NfQ0xBU1MgPSAnZHJvcGRvd24tdG9nZ2xlJ1xuICAgICwgTUVOVV9DU1NfQ0xBU1MgPSAnZHJvcGRvd24tbWVudSc7XG5cblxudmFyIE1MRHJvcGRvd24gPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MRHJvcGRvd24nLCB7XG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogWydtbC1icy1kcm9wZG93bicsICdkcm9wZG93biddXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxEcm9wZG93bik7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxEcm9wZG93bjtcblxuXG5fLmV4dGVuZFByb3RvKE1MRHJvcGRvd24sIHtcbiAgICBzdGFydDogTUxEcm9wZG93biRzdGFydCxcbiAgICBkZXN0cm95OiBNTERyb3Bkb3duJGRlc3Ryb3ksXG4gICAgdG9nZ2xlTWVudTogTUxEcm9wZG93biR0b2dnbGVNZW51LFxuICAgIHNob3dNZW51OiBNTERyb3Bkb3duJHNob3dNZW51LFxuICAgIGhpZGVNZW51OiBNTERyb3Bkb3duJGhpZGVNZW51XG59KTtcblxuXG5mdW5jdGlvbiBNTERyb3Bkb3duJHN0YXJ0KCkge1xuICAgIHZhciB0b2dnbGVFbCA9IHRoaXMuZWwucXVlcnlTZWxlY3RvcignLicgKyBUT0dHTEVfQ1NTX0NMQVNTKVxuICAgICAgICAsIG1lbnVFbCA9IHRoaXMuZWwucXVlcnlTZWxlY3RvcignLicgKyBNRU5VX0NTU19DTEFTUyk7XG5cbiAgICBpZiAoISAodG9nZ2xlRWwgJiYgbWVudUVsKSlcbiAgICAgICAgcmV0dXJuIGxvZ2dlci5lcnJvcignTUxEcm9wZG93bjonLCBUT0dHTEVfQ1NTX0NMQVNTLCAnb3InLCBNRU5VX0NTU19DTEFTUywgJ2lzblxcJ3QgZm91bmQnKTtcblxuICAgIHZhciBkb2MgPSB3aW5kb3cuZG9jdW1lbnRcbiAgICAgICAgLCBjbGlja0hhbmRsZXIgPSB0aGlzLnRvZ2dsZU1lbnUuYmluZCh0aGlzLCB1bmRlZmluZWQpO1xuXG4gICAgdmFyIGxpc3RlbmVycyA9IG5ldyBET01MaXN0ZW5lcnM7XG4gICAgdGhpcy5fZHJvcGRvd24gPSB7XG4gICAgICAgIG1lbnU6IG1lbnVFbCxcbiAgICAgICAgdmlzaWJsZTogZmFsc2UsXG4gICAgICAgIGxpc3RlbmVyczogbGlzdGVuZXJzXG4gICAgfTtcbiAgICB0aGlzLmhpZGVNZW51KCk7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgbGlzdGVuZXJzLmFkZCh0b2dnbGVFbCwgJ2NsaWNrJywgY2xpY2tIYW5kbGVyKTtcbiAgICAvL21heWJlIG9ubHkgYWRkIHRoaXMgZXZlbnRzIGlmIGlzIG9wZW4/XG4gICAgbGlzdGVuZXJzLmFkZChkb2MsICdtb3VzZW91dCcsIG9uRG9jT3V0KTtcbiAgICBsaXN0ZW5lcnMuYWRkKGRvYywgJ2NsaWNrJywgb25DbGljayk7XG5cblxuICAgIGZ1bmN0aW9uIG9uRG9jT3V0KGV2ZW50KSB7XG4gICAgICAgIHZhciB0YXJnZXQgPSBldmVudC50YXJnZXRcbiAgICAgICAgICAgICwgcmVsYXRlZFRhcmdldCA9IGV2ZW50LnJlbGF0ZWRUYXJnZXRcbiAgICAgICAgICAgICwgbGlzdGVuZXJzID0gc2VsZi5fZHJvcGRvd24ubGlzdGVuZXJzO1xuXG4gICAgICAgIGlmIChpc0lmcmFtZSh0YXJnZXQpKVxuICAgICAgICAgICAgbGlzdGVuZXJzLnJlbW92ZSh0YXJnZXQuY29udGVudFdpbmRvdy5kb2N1bWVudCwgJ2NsaWNrJywgb25DbGljayk7XG5cbiAgICAgICAgaWYgKGlzSWZyYW1lKHJlbGF0ZWRUYXJnZXQpKVxuICAgICAgICAgICAgbGlzdGVuZXJzLmFkZChyZWxhdGVkVGFyZ2V0LmNvbnRlbnRXaW5kb3cuZG9jdW1lbnQsICdjbGljaycsIG9uQ2xpY2spO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG9uQ2xpY2soZXZlbnQpIHtcbiAgICAgICAgaWYgKCFzZWxmLmVsLmNvbnRhaW5zKGV2ZW50LnRhcmdldCkpXG4gICAgICAgICAgICBzZWxmLmhpZGVNZW51KCk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIGlzSWZyYW1lKGVsKSB7XG4gICAgcmV0dXJuIGVsICYmIGVsLnRhZ05hbWUgPT0gJ0lGUkFNRSc7XG59XG5cblxuZnVuY3Rpb24gTUxEcm9wZG93biRkZXN0cm95KCkge1xuICAgIHRoaXMuX2Ryb3Bkb3duLmxpc3RlbmVycy5yZW1vdmVBbGwoKTtcbiAgICBkZWxldGUgdGhpcy5fZHJvcGRvd247XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuZnVuY3Rpb24gTUxEcm9wZG93biRzaG93TWVudSgpIHtcbiAgICB0aGlzLnRvZ2dsZU1lbnUodHJ1ZSk7XG59XG5cblxuZnVuY3Rpb24gTUxEcm9wZG93biRoaWRlTWVudSgpIHtcbiAgICB0aGlzLnRvZ2dsZU1lbnUoZmFsc2UpO1xufVxuXG5cbmZ1bmN0aW9uIE1MRHJvcGRvd24kdG9nZ2xlTWVudShkb1Nob3cpIHtcbiAgICBkb1Nob3cgPSB0eXBlb2YgZG9TaG93ID09ICd1bmRlZmluZWQnXG4gICAgICAgICAgICAgICAgPyAhIHRoaXMuX2Ryb3Bkb3duLnZpc2libGVcbiAgICAgICAgICAgICAgICA6ICEhIGRvU2hvdztcblxuICAgIHRoaXMuX2Ryb3Bkb3duLnZpc2libGUgPSBkb1Nob3c7XG5cbiAgICB2YXIgbWVudSA9IHRoaXMuX2Ryb3Bkb3duLm1lbnU7XG4gICAgbWVudS5zdHlsZS5kaXNwbGF5ID0gZG9TaG93XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyAnYmxvY2snXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgOiAnbm9uZSc7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxuLy8gPGEgbmFtZT1cImNvbmZpZ1wiPjwvYT5cbi8vIG1pbG8uY29uZmlnXG4vLyAtLS0tLS0tLS0tLVxuXG4vLyBJdCBpcyB0aGUgZnVuY3Rpb24gdGhhdCBhbGxvd3MgdG8gY2hhbmdlIG1pbG8gY29uZmlndXJhdGlvbnMgYW5kIGFsc29cbi8vIGFjY2VzcyB0aGVtIG9uIGNvbmZpZydzIHByb3BlcnRpZXMuXG5cbi8vIGBgYGphdmFzY3JpcHRcbi8vIG1pbG8uY29uZmlnKHtcbi8vICAgICBhdHRyczoge1xuLy8gICAgICAgICBiaW5kOiAnbWwtYmluZCcsXG4vLyAgICAgICAgIGxvYWQ6ICdtbC1sb2FkJ1xuLy8gICAgIH1cbi8vIH0pO1xuLy8gYGBgXG5cblxudmFyIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgZG9UID0gcmVxdWlyZSgnZG90Jyk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBjb25maWc7XG5cbmZ1bmN0aW9uIGNvbmZpZyhvcHRpb25zKSB7XG4gICAgXy5kZWVwRXh0ZW5kKGNvbmZpZywgb3B0aW9ucyk7XG59XG5cbmNvbmZpZyh7XG4gICAgYXR0cnM6IHtcbiAgICAgICAgYmluZDogJ21sLWJpbmQnLFxuICAgICAgICBsb2FkOiAnbWwtbG9hZCdcbiAgICB9LFxuICAgIGNvbXBvbmVudFJlZjogJ19fX21pbG9fY29tcG9uZW50JyxcbiAgICBjb21wb25lbnRQcmVmaXg6ICdtaWxvXycsXG4gICAgbWl4aW46IHtcbiAgICAgICAgaW5zdGFuY2VQcm9wZXJ0aWVzTWFwOiAnX19fbWl4aW5faW5zdGFuY2VzJ1xuICAgIH0sXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgICAgY29tcGlsZTogZG9ULmNvbXBpbGVcbiAgICB9LFxuICAgIGRvbVN0b3JhZ2U6IHtcbiAgICAgICAgdHlwZVN1ZmZpeDogJzpfX19taWxvX2RhdGFfdHlwZScsXG4gICAgICAgIHByZWZpeFNlcGFyYXRvcjogJy8nLFxuICAgICAgICByb290OiAnJyxcbiAgICAgICAgbWVzc2FnZUtleTogJ19fX21pbG9fbWVzc2FnZS8nLFxuICAgICAgICBtZXNzYWdlVGltZXN0YW1wOiAnX19fbWlsb190aW1lc3RhbXAnLFxuICAgICAgICBxdW90YUV4Y2VlZGVkOiB7XG4gICAgICAgICAgICB0aHJvd0Vycm9yOiB0cnVlLFxuICAgICAgICAgICAgbWVzc2FnZTogZmFsc2VcbiAgICAgICAgfVxuICAgIH0sXG4gICAgZHJhZ0Ryb3A6IHtcbiAgICAgICAgZGF0YVR5cGVzOiB7XG4gICAgICAgICAgICBjb21wb25lbnQ6ICd4LWFwcGxpY2F0aW9uL21pbG8vY29tcG9uZW50JyxcbiAgICAgICAgICAgIGNvbXBvbmVudE1ldGFUZW1wbGF0ZTogJ3gtYXBwbGljYXRpb24vbWlsby9jb21wb25lbnQtbWV0YS8lY2xhc3MvJW5hbWUvJXBhcmFtcycsXG4gICAgICAgICAgICBjb21wb25lbnRNZXRhUmVnZXg6IC9eeFxcLWFwcGxpY2F0aW9uXFwvbWlsb1xcL2NvbXBvbmVudFxcLW1ldGFcXC8oW2EtejAtOV0rKVxcLyhbYS16MC05XSspXFwvKFthLXowLTldKikkLyxcbiAgICAgICAgfVxuICAgIH0sXG4gICAgcmVxdWVzdDoge1xuICAgICAgICBqc29ucFRpbWVvdXQ6IDYwMDAwLFxuICAgICAgICBqc29ucENhbGxiYWNrUHJlZml4OiAnX19fbWlsb19jYWxsYmFja18nLFxuICAgICAgICBvcHRpb25zS2V5OiAnX19fbWlsb19vcHRpb25zJyxcbiAgICAgICAgZGVmYXVsdHM6IHtcbiAgICAgICAgICAgIHRpbWVvdXQ6IDYwMDAwXG4gICAgICAgIH1cbiAgICB9LFxuICAgIHdlYnNvY2tldDoge1xuICAgICAgICBycGM6IHtcbiAgICAgICAgICAgIHRpbWVvdXQ6IDE1MDAwLFxuICAgICAgICAgICAgcmVzcG9uc2VQcmVmaXg6ICdyZXNwb25zZV8nXG4gICAgICAgIH1cbiAgICB9LFxuICAgIGNoZWNrOiB0cnVlLFxuICAgIGRlYnVnOiBmYWxzZVxufSk7XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIG1pbG9NYWlsID0gcmVxdWlyZSgnLi9zZXJ2aWNlcy9tYWlsJylcbiAgICAsIHJlcXVlc3QgPSByZXF1aXJlKCcuL3V0aWwvcmVxdWVzdCcpXG4gICAgLCBsb2dnZXIgPSByZXF1aXJlKCcuL3V0aWwvbG9nZ2VyJylcbiAgICAsIHV0aWxEb20gPSByZXF1aXJlKCcuL3V0aWwvZG9tJylcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4vY29uZmlnJylcbiAgICAsIExvYWRBdHRyaWJ1dGUgPSByZXF1aXJlKCcuL2F0dHJpYnV0ZXMvYV9sb2FkJylcbiAgICAsIExvYWRlckVycm9yID0gcmVxdWlyZSgnLi91dGlsL2Vycm9yJykuTG9hZGVyO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gbG9hZGVyO1xuXG4vKipcbiAqIGBtaWxvLmxvYWRlcmBcbiAqIFxuICogUmVjdXJzaXZlbHkgc2NhbnMgdGhlIGRvY3VtZW50IHRyZWUgaW5zaWRlIGByb290RWxgIChkb2N1bWVudC5ib2R5IGJ5IGRlZmF1bHQpIGxvb2tpbmcgZm9yIF9fbWwtbG9hZF9fIEBhdHRyaWJ1dGUuXG4gKiBPbmUgbGV2ZWwgbG9hZCBpcyBleGVjdXRlZC4gTm8gYWRkaXRpb25hbCBsb2FkZXIgZ2V0IGNhbGxlZCBvbiBpbnNpZGUgX19tbC1sb2FkX18gYXR0cmlidXRlcy4gXG4gKlxuICogUG9zc2libGUgdXNhZ2VzOlxuICogLSBtaWxvLmxvYWRlcihbbXlSb290RWwsXVtteVJlbW92ZUF0dHJpYnV0ZSxdbXlDYWxsYmFjaylcbiAqIFxuICogQHBhcmFtICB7RWxlbWVudH0gIHJvb3RFbCAgICAgICAgICBSb290IGVsZW1lbnQgaW5zaWRlIHdoaWNoIERPTSB3aWxsIGJlIHNjYW5uZWQgKGRvY3VtZW50LmJvZHkgYnkgZGVmYXVsdCkuXG4gKiBAcGFyYW0gIHtCb29sZWFufSAgcmVtb3ZlQXR0cmlidXRlIElmIHNldCB0byB0cnVlLCB0aGVuIHRoZSBfX21sLWxvYWRfXyBhdHRyaWJ1dGUgd2lsbCBiZSByZW1vdmVkIG9uY2UgbG9hZGVyIGhhcyBiZWVuIGV4ZWN1dGVkIChGYWxzZSBieSBkZWZhdWx0KS5cbiAqIEBwYXJhbSAge0Z1bmN0aW9ufSBjYWxsYmFjayAgICAgICAgQ2FsbGJhY2sgdG8gY2FsbCBhZnRlciBhbGwgZWxlbWVudHMgZ2V0IGxvYWRlZCAoUmVxdWlyZWQpLlxuICovXG5mdW5jdGlvbiBsb2FkZXIocm9vdEVsLCByZW1vdmVBdHRyaWJ1dGUsIGNhbGxiYWNrKSB7XG4gICAgbWlsbyhmdW5jdGlvbigpIHtcbiAgICAgICAgX2xvYWRlcihyb290RWwsIHJlbW92ZUF0dHJpYnV0ZSwgY2FsbGJhY2spO1xuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIF9sb2FkZXIocm9vdEVsLCByZW1vdmVBdHRyaWJ1dGUsIGNhbGxiYWNrKSB7XG4gICAgaWYgKHR5cGVvZiByb290RWwgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBjYWxsYmFjayA9IHJvb3RFbDtcbiAgICAgICAgcm9vdEVsID0gdW5kZWZpbmVkO1xuICAgICAgICByZW1vdmVBdHRyaWJ1dGUgPSBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHJlbW92ZUF0dHJpYnV0ZSA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIGNhbGxiYWNrID0gcmVtb3ZlQXR0cmlidXRlO1xuICAgICAgICByZW1vdmVBdHRyaWJ1dGUgPSBmYWxzZTtcbiAgICB9XG5cbiAgICByb290RWwgPSByb290RWwgfHwgZG9jdW1lbnQuYm9keTtcblxuICAgIG1pbG9NYWlsLnBvc3RNZXNzYWdlKCdsb2FkZXInLCB7IHN0YXRlOiAnc3RhcnRlZCcgfSk7XG4gICAgX2xvYWRWaWV3c0luRWxlbWVudChyb290RWwsIHJlbW92ZUF0dHJpYnV0ZSwgZnVuY3Rpb24odmlld3MpIHtcbiAgICAgICAgbWlsb01haWwucG9zdE1lc3NhZ2UoJ2xvYWRlcicsIHsgXG4gICAgICAgICAgICBzdGF0ZTogJ2ZpbmlzaGVkJyxcbiAgICAgICAgICAgIHZpZXdzOiB2aWV3c1xuICAgICAgICB9KTtcbiAgICAgICAgY2FsbGJhY2sodmlld3MpO1xuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIF9sb2FkVmlld3NJbkVsZW1lbnQocm9vdEVsLCByZW1vdmVBdHRyaWJ1dGUsIGNhbGxiYWNrKSB7XG4gICAgdmFyIGxvYWRFbGVtZW50cyA9IHJvb3RFbC5nZXRBdHRyaWJ1dGUoY29uZmlnLmF0dHJzLmxvYWQpXG4gICAgICAgICAgICAgICAgICAgICAgICA/IFtyb290RWxdXG4gICAgICAgICAgICAgICAgICAgICAgICA6IHJvb3RFbC5xdWVyeVNlbGVjdG9yQWxsKCdbJyArIGNvbmZpZy5hdHRycy5sb2FkICsgJ10nKTtcblxuICAgIHZhciB2aWV3cyA9IHt9XG4gICAgICAgICwgdG90YWxDb3VudCA9IGxvYWRFbGVtZW50cy5sZW5ndGhcbiAgICAgICAgLCBsb2FkZWRDb3VudCA9IDA7XG5cbiAgICBfLmZvckVhY2gobG9hZEVsZW1lbnRzLCBmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgbG9hZFZpZXcoZWwsIHJlbW92ZUF0dHJpYnV0ZSwgZnVuY3Rpb24oZXJyKSB7XG4gICAgICAgICAgICB2aWV3c1tlbC5pZF0gPSBlcnIgfHwgZWw7XG4gICAgICAgICAgICBsb2FkZWRDb3VudCsrO1xuICAgICAgICAgICAgaWYgKGxvYWRlZENvdW50ID09IHRvdGFsQ291bnQpXG4gICAgICAgICAgICAgICAgY2FsbGJhY2sodmlld3MpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn07XG5cblxuZnVuY3Rpb24gbG9hZFZpZXcoZWwsIHJlbW92ZUF0dHJpYnV0ZSwgY2FsbGJhY2spIHtcbiAgICBpZiAodXRpbERvbS5jaGlsZHJlbihlbCkubGVuZ3RoKVxuICAgICAgICB0aHJvdyBuZXcgTG9hZGVyRXJyb3IoJ2NhblxcJ3QgbG9hZCBodG1sIGludG8gZWxlbWVudCB0aGF0IGlzIG5vdCBlbXB0eScpO1xuXG4gICAgdmFyIGF0dHIgPSBuZXcgTG9hZEF0dHJpYnV0ZShlbCk7XG5cbiAgICBhdHRyLnBhcnNlKCkudmFsaWRhdGUoKTtcblxuICAgIHJlcXVlc3QuZ2V0KGF0dHIubG9hZFVybCwgZnVuY3Rpb24oZXJyLCBodG1sKSB7XG4gICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIGVyci5tZXNzYWdlID0gZXJyLm1lc3NhZ2UgfHwgJ2NhblxcJ3QgbG9hZCBmaWxlICcgKyBhdHRyLmxvYWRVcmw7XG4gICAgICAgICAgICAvLyBsb2dnZXIuZXJyb3IoZXJyLm1lc3NhZ2UpO1xuICAgICAgICAgICAgY2FsbGJhY2soZXJyKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGVsLmlubmVySFRNTCA9IGh0bWw7XG4gICAgICAgIGlmIChyZW1vdmVBdHRyaWJ1dGUpIExvYWRBdHRyaWJ1dGUucmVtb3ZlKGVsKTtcbiAgICAgICAgY2FsbGJhY2sobnVsbCk7XG4gICAgfSk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBNaXhpbiA9IHJlcXVpcmUoJy4uL2Fic3RyYWN0L21peGluJylcbiAgICAvLyAsIE1lc3NhZ2VTb3VyY2UgPSByZXF1aXJlKCcuL21lc3NhZ2Vfc291cmNlJylcbiAgICAsIE1lc3NhZ2VTb3VyY2UgPSByZXF1aXJlKCcuL21fc291cmNlJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgY2hlY2sgPSByZXF1aXJlKCcuLi91dGlsL2NoZWNrJylcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2hcbiAgICAsIE1lc3NlbmdlckVycm9yID0gcmVxdWlyZSgnLi4vdXRpbC9lcnJvcicpLk1lc3NlbmdlcjtcblxuXG4vKipcbiAqIGBtaWxvLk1lc3NlbmdlcmBcbiAqIEEgZ2VuZXJpYyBNZXNzZW5nZXIgY2xhc3MgdGhhdCBpcyB1c2VkIGZvciBhbGwga2luZHMgb2YgbWVzc2FnaW5nIGluIG1pbG8uIEl0IGlzIHN1YmNsYXNzZWQgZnJvbSBbTWl4aW5dKC4uL2Fic3RyYWN0L21peGluLmpzLmh0bWwpIGFuZCBpdCBwcm94aWVzIGl0cyBtZXRob2RzIHRvIHRoZSBob3N0IG9iamVjdCBmb3IgY29udmVuaWVuY2UuXG4gKiBBbGwgZmFjZXRzIGFuZCBjb21wb25lbnRzIGhhdmUgbWVzc2VuZ2VyIGF0dGFjaGVkIHRvIHRoZW0uIE1lc3NlbmdlciBjbGFzcyBpbnRlcm9wZXJhdGVzIHdpdGggW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgY2xhc3MgdGhhdCBjb25uZWN0cyB0aGUgbWVzc2VuZ2VyIHRvIHNvbWUgZXh0ZXJuYWwgc291cmNlIG9mIG1lc3NhZ2VzIChlLmcuLCBET00gZXZlbnRzKSBhbmQgW01lc3NlbmdlckFQSV0oLi9tX2FwaS5qcy5odG1sKSBjbGFzcyB0aGF0IGFsbG93cyB0byBkZWZpbmUgaGlnaGVyIGxldmVsIG1lc3NhZ2VzIHRoYW4gbWVzc2FnZXMgdGhhdCBleGlzdCBvbiB0aGUgc291cmNlLlxuICogTWVzc2VuZ2VyIGNsYXNzIGlzIHVzZWQgaW50ZXJuYWxseSBpbiBtaWxvIGFuZCBjYW4gYmUgdXNlZCB0b2dldGhlciB3aXRoIGFueSBvYmplY3RzL2NsYXNzZXMgaW4gdGhlIGFwcGxpY2F0aW9uLlxuICogbWlsbyBhbHNvIGRlZmluZXMgYSBnbG9iYWwgbWVzc2VuZ2VyIFttaWxvLm1haWxdKC4uL21haWwvaW5kZXguanMuaHRtbCkgdGhhdCBkaXNwYXRjaGVzIGBkb21yZWFkeWAgZXZlbnQgYW5kIGNhbiBiZSB1c2VkIGZvciBhbnkgYXBwbGljYXRpb24gd2lkZSBtZXNzYWdpbmcuXG4gKiBUbyBpbml0aWFsaXplIHlvdXIgYXBwIGFmdGVyIERPTSBpcyByZWFkeSB1c2U6XG4gKiBgYGBcbiAqIG1pbG8ubWFpbC5vbignZG9tcmVhZHknLCBmdW5jdGlvbigpIHtcbiAqICAgICAvLyBhcHBsaWNhdGlvbiBzdGFydHNcbiAqIH0pO1xuICogYGBgXG4gKiBvciB0aGUgZm9sbG93aW5nIHNob3J0ZXIgZm9ybSBvZiB0aGUgc2FtZTpcbiAqIGBgYFxuICogbWlsbyhmdW5jdGlvbigpIHtcbiAqICAgICAvLyBhcHBsaWNhdGlvbiBzdGFydHNcbiAqIH0pO1xuICogYGBgXG4gKi9cbnZhciBNZXNzZW5nZXIgPSBfLmNyZWF0ZVN1YmNsYXNzKE1peGluLCAnTWVzc2VuZ2VyJyk7XG5cbnZhciBtZXNzYWdlc1NwbGl0UmVnRXhwID0gTWVzc2VuZ2VyLm1lc3NhZ2VzU3BsaXRSZWdFeHAgPSAvXFxzKig/OlxcLHxcXHMpXFxzKi87XG5cblxuLyoqXG4gKiAjIyMjTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbaW5pdF0oI2luaXQpXG4gKiAtIFtvbl0oI01lc3NlbmdlciRvbikgKGFsaWFzIC0gb25NZXNzYWdlLCBkZXByZWNhdGVkKVxuICogLSBbb2ZmXSgjTWVzc2VuZ2VyJG9mZikgKGFsaWFzIC0gb2ZmTWVzc2FnZSwgZGVwcmVjYXRlZClcbiAqIC0gW29uTWVzc2FnZXNdKCNvbk1lc3NhZ2VzKVxuICogLSBbb2ZmTWVzc2FnZXNdKCNvZmZNZXNzYWdlcylcbiAqIC0gW29uY2VdKCNvbmNlKVxuICogLSBbb25jZVN5bmNdKCNvbmNlU3luYylcbiAqIC0gW3Bvc3RNZXNzYWdlXSgjcG9zdE1lc3NhZ2UpXG4gKiAtIFtnZXRTdWJzY3JpYmVyc10oI2dldFN1YnNjcmliZXJzKVxuICpcbiAqIFwiUHJpdmF0ZVwiIG1ldGhvZHNcbiAqXG4gKiAtIFtfY2hvb3NlU3Vic2NyaWJlcnNIYXNoXSgjX2Nob29zZVN1YnNjcmliZXJzSGFzaClcbiAqIC0gW19yZWdpc3RlclN1YnNjcmliZXJdKCNfcmVnaXN0ZXJTdWJzY3JpYmVyKVxuICogLSBbX3JlbW92ZVN1YnNjcmliZXJdKCNfcmVtb3ZlU3Vic2NyaWJlcilcbiAqIC0gW19yZW1vdmVBbGxTdWJzY3JpYmVyc10oI19yZW1vdmVBbGxTdWJzY3JpYmVycylcbiAqIC0gW19jYWxsUGF0dGVyblN1YnNjcmliZXJzXSgjX2NhbGxQYXR0ZXJuU3Vic2NyaWJlcnMpXG4gKiAtIFtfY2FsbFN1YnNjcmliZXJzXSgjX2NhbGxTdWJzY3JpYmVycylcbiAqIC0gW19zZXRNZXNzYWdlU291cmNlXSgjX3NldE1lc3NhZ2VTb3VyY2UpXG4gKiAtIFtnZXRNZXNzYWdlU291cmNlXSgjZ2V0TWVzc2FnZVNvdXJjZSlcbiAqL1xuXy5leHRlbmRQcm90byhNZXNzZW5nZXIsIHtcbiAgICBpbml0OiBpbml0LCAvLyBjYWxsZWQgYnkgTWl4aW4gKHN1cGVyY2xhc3MpXG4gICAgZGVzdHJveTogTWVzc2VuZ2VyJGRlc3Ryb3ksXG4gICAgb246IE1lc3NlbmdlciRvbixcbiAgICBvbmNlOiBNZXNzZW5nZXIkb25jZSxcbiAgICBvbmNlU3luYzogTWVzc2VuZ2VyJG9uY2VTeW5jLFxuICAgIG9uU3luYzogTWVzc2VuZ2VyJG9uU3luYyxcbiAgICBvbkFzeW5jOiBNZXNzZW5nZXIkb25Bc3luYyxcbiAgICBvbk1lc3NhZ2U6IE1lc3NlbmdlciRvbiwgLy8gZGVwcmVjYXRlZFxuICAgIG9mZjogTWVzc2VuZ2VyJG9mZixcbiAgICBvZmZNZXNzYWdlOiBNZXNzZW5nZXIkb2ZmLCAvLyBkZXByZWNhdGVkXG4gICAgb25NZXNzYWdlczogb25NZXNzYWdlcyxcbiAgICBvZmZNZXNzYWdlczogb2ZmTWVzc2FnZXMsXG4gICAgb2ZmQWxsOiBNZXNzZW5nZXIkb2ZmQWxsLFxuICAgIHBvc3RNZXNzYWdlOiBwb3N0TWVzc2FnZSxcbiAgICBwb3N0TWVzc2FnZVN5bmM6IHBvc3RNZXNzYWdlU3luYyxcbiAgICBnZXRTdWJzY3JpYmVyczogZ2V0U3Vic2NyaWJlcnMsXG4gICAgZ2V0TWVzc2FnZVNvdXJjZTogZ2V0TWVzc2FnZVNvdXJjZSxcbiAgICBfY2hvb3NlU3Vic2NyaWJlcnNIYXNoOiBfY2hvb3NlU3Vic2NyaWJlcnNIYXNoLFxuICAgIF9yZWdpc3RlclN1YnNjcmliZXI6IF9yZWdpc3RlclN1YnNjcmliZXIsXG4gICAgX3JlbW92ZVN1YnNjcmliZXI6IF9yZW1vdmVTdWJzY3JpYmVyLFxuICAgIF9yZW1vdmVBbGxTdWJzY3JpYmVyczogX3JlbW92ZUFsbFN1YnNjcmliZXJzLFxuICAgIF9jYWxsUGF0dGVyblN1YnNjcmliZXJzOiBfY2FsbFBhdHRlcm5TdWJzY3JpYmVycyxcbiAgICBfY2FsbFN1YnNjcmliZXJzOiBfY2FsbFN1YnNjcmliZXJzLFxuICAgIF9jYWxsU3Vic2NyaWJlcjogX2NhbGxTdWJzY3JpYmVyLFxuICAgIF9zZXRNZXNzYWdlU291cmNlOiBfc2V0TWVzc2FnZVNvdXJjZVxufSk7XG5cblxuLyoqXG4gKiBBIGRlZmF1bHQgbWFwIG9mIHByb3h5IG1ldGhvZHMgdXNlZCBieSBDb21wb25lbnRGYWNldCBhbmQgQ29tcG9uZW50IGNsYXNzZXMgdG8gcGFzcyB0byBNZXNzZW5nZXIgd2hlbiBpdCBpcyBpbnN0YW50aWF0ZWQuXG4gKiBUaGlzIG1hcCBpcyBmb3IgY29udmVuaWVuY2Ugb25seSwgaXQgaXMgTk9UIHVzZWQgaW50ZXJuYWxseSBieSBNZXNzZW5nZXIsIGEgaG9zdCBjbGFzcyBzaG91bGQgcGFzcyBpdCBmb3IgbWV0aG9kcyB0byBiZSBwcm94aWVkIHRoaXMgd2F5LlxuICovXG5NZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMgPSB7XG4gICAgb246ICdvbicsXG4gICAgb25TeW5jOiAnb25TeW5jJyxcbiAgICBvbmNlOiAnb25jZScsXG4gICAgb25jZVN5bmM6ICdvbmNlU3luYycsXG4gICAgb2ZmOiAnb2ZmJyxcbiAgICBvbk1lc3NhZ2VzOiAnb25NZXNzYWdlcycsXG4gICAgb2ZmTWVzc2FnZXM6ICdvZmZNZXNzYWdlcycsXG4gICAgcG9zdE1lc3NhZ2U6ICdwb3N0TWVzc2FnZScsXG4gICAgcG9zdE1lc3NhZ2VTeW5jOiAncG9zdE1lc3NhZ2VTeW5jJyxcbiAgICBnZXRTdWJzY3JpYmVyczogJ2dldFN1YnNjcmliZXJzJ1xufTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1lc3NlbmdlcjtcblxuXG5NZXNzZW5nZXIuc3Vic2NyaXB0aW9ucyA9IFtdO1xuXG5cbi8qKlxuICogTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZFxuICogSW5pdGlhbGl6ZXMgTWVzc2VuZ2VyLiBNZXRob2QgaXMgY2FsbGVkIGJ5IE1peGluIGNsYXNzIGNvbnN0cnVjdG9yLlxuICogU2VlIFtvbl0oI01lc3NlbmdlciRvbikgbWV0aG9kLCBbTWVzc2VuZ2VyXSgjTWVzc2VuZ2VyKSBjbGFzcyBhYm92ZSBhbmQgW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgY2xhc3MuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGhvc3RPYmplY3QgT3B0aW9uYWwgb2JqZWN0IHRoYXQgc3RvcmVzIHRoZSBtZXNzZW5nZXIgb24gb25lIG9mIGl0cyBwcm9wZXJ0aWVzLiBJdCBpcyB1c2VkIHRvIHByb3h5IG1ldGhvZHMgb2YgbWVzc2VuZ2VyIGFuZCBhbHNvIGFzIGEgY29udGV4dCBmb3Igc3Vic2NyaWJlcnMgd2hlbiB0aGV5IGFyZSBjYWxsZWQgYnkgdGhlIE1lc3Nlbmdlci4gU2VlIGBvbmAgbWV0aG9kLlxuICogQHBhcmFtIHtPYmplY3R9IHByb3h5TWV0aG9kcyBPcHRpb25hbCBtYXAgb2YgbWV0aG9kIG5hbWVzOyBrZXkgLSBwcm94eSBtZXRob2QgbmFtZSwgdmFsdWUgLSBtZXNzZW5nZXIncyBtZXRob2QgbmFtZS5cbiAqIEBwYXJhbSB7TWVzc2FnZVNvdXJjZX0gbWVzc2FnZVNvdXJjZSBPcHRpb25hbCBtZXNzYWdlU291cmNlIGxpbmtlZCB0byB0aGUgbWVzc2VuZ2VyLiBJZiBtZXNzYWdlU291cmNlIGlzIHN1cHBsaWVkLCB0aGUgcmVmZXJlbmNlIHRvIHRoZSBtZXNzZW5nZXIgd2lsbCBzdG9yZWQgb24gaXRzICdtZXNzZW5nZXInIHByb3BlcnR5XG4gKi9cbmZ1bmN0aW9uIGluaXQoaG9zdE9iamVjdCwgcHJveHlNZXRob2RzLCBtZXNzYWdlU291cmNlKSB7XG4gICAgLy8gaG9zdE9iamVjdCBhbmQgcHJveHlNZXRob2RzIGFyZSB1c2VkIGluIE1peGluIGFuZCBjaGVja2VkIHRoZXJlXG4gICAgaWYgKG1lc3NhZ2VTb3VyY2UpXG4gICAgICAgIHRoaXMuX3NldE1lc3NhZ2VTb3VyY2UobWVzc2FnZVNvdXJjZSk7XG5cbiAgICBfaW5pdGlhbGl6ZVN1YnNjcmliZXJzLmNhbGwodGhpcyk7XG59XG5cblxuZnVuY3Rpb24gX2luaXRpYWxpemVTdWJzY3JpYmVycygpIHtcbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICBfbWVzc2FnZVN1YnNjcmliZXJzOiB7fSxcbiAgICAgICAgX3BhdHRlcm5NZXNzYWdlU3Vic2NyaWJlcnM6IHt9LFxuICAgIH0sIF8uQ09ORik7XG59XG5cblxuLyoqXG4gKiBEZXN0cm95cyBtZXNzZW5nZXIuIE1heWJlIG5lZWRzIHRvIHVuc3Vic2NyaWJlIGFsbCBzdWJzY3JpYmVyc1xuICovXG5mdW5jdGlvbiBNZXNzZW5nZXIkZGVzdHJveSgpIHtcbiAgICB0aGlzLm9mZkFsbCgpO1xuICAgIHZhciBtZXNzYWdlU291cmNlID0gdGhpcy5nZXRNZXNzYWdlU291cmNlKCk7XG4gICAgaWYgKG1lc3NhZ2VTb3VyY2UpXG4gICAgICAgIG1lc3NhZ2VTb3VyY2UuZGVzdHJveSgpO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZC5cbiAqIFJlZ2lzdGVycyBhIHN1YnNjcmliZXIgZnVuY3Rpb24gZm9yIGEgY2VydGFpbiBtZXNzYWdlKHMpLlxuICogVGhpcyBtZXRob2QgcmV0dXJucyBgdHJ1ZWAgaWYgdGhlIHN1YnNjcmlwdGlvbiB3YXMgc3VjY2Vzc2Z1bC4gSXQgY2FuIGJlIHVuc3VjY2Vzc2Z1bCBpZiB0aGUgcGFzc2VkIHN1YnNjcmliZXIgaGFzIGFscmVhZHkgYmVlbiBzdWJzY3JpYmVkIHRvIHRoaXMgbWVzc2FnZSB0eXBlIC0gZG91YmxlIHN1YnNjcmlwdGlvbiBuZXZlciBoYXBwZW5zIGFuZCBpdCBpcyBzYWZlIHRvIHN1YnNjcmliZSBhZ2FpbiAtIG5vIGVycm9yIG9yIHdhcm5pbmcgaXMgdGhyb3duIG9yIGxvZ2dlZC5cbiAqIFN1YnNjcmliZXIgaXMgcGFzc2VkIHR3byBwYXJhbWV0ZXJzOiBgbWVzc2FnZWAgKHN0cmluZykgYW5kIGBkYXRhYCAob2JqZWN0KS4gRGF0YSBvYmplY3QgaXMgc3VwcGxpZWQgd2hlbiBtZXNzYWdlIGlzIGRpc3BhdGNoZWQsIE1lc3NlbmdlciBpdHNlbGYgYWRkcyBub3RoaW5nIHRvIGl0LiBGb3IgZXhhbXBsZSwgW2V2ZW50cyBmYWNldF0oLi4vY29tcG9uZW50cy9jX2ZhY2V0cy9FdmVudHMuanMuaHRtbCkgc2VuZHMgYWN0dWFsIERPTSBldmVudCB3aGVuIGl0IHBvc3RzIG1lc3NhZ2UuXG4gKiBVc2FnZTpcbiAqIGBgYFxuICogLy8gc3Vic2NyaWJlcyBvbk1vdXNlVXBEb3duIHRvIHR3byBET00gZXZlbnRzIG9uIGNvbXBvbmVudCB2aWEgZXZlbnRzIGZhY2V0LlxuICogbXlDb21wLmV2ZW50cy5vbignbW91c2Vkb3duIG1vdXNldXAnLCBvbk1vdXNlVXBEb3duKTtcbiAqIGZ1bmN0aW9uIG9uTW91c2VVcERvd24oZXZlbnRUeXBlLCBldmVudCkge1xuICogICAgIC8vIC4uLlxuICogfVxuICpcbiAqIG15Q29tcC5kYXRhLm9uKC8uKy8sIGZ1bmN0aW9uKG1zZywgZGF0YSkge1xuICogICAgIGxvZ2dlci5kZWJ1Zyhtc2csIGRhdGEpO1xuICogfSk7IC8vIHN1YnNjcmliZXMgYW5vbnltb3VzIGZ1bmN0aW9uIHRvIGFsbCBub24tZW1wdHkgbWVzc2FnZXMgb24gZGF0YSBmYWNldFxuICogLy8gaXQgd2lsbCBub3QgYmUgcG9zc2libGUgdG8gdW5zdWJzY3JpYmUgYW5vbnltb3VzIHN1YnNjcmliZXIgc2VwYXJhdGVseSxcbiAqIC8vIGJ1dCBteUNvbXAuZGF0YS5vZmYoLy4rLykgd2lsbCB1bnN1YnNjcmliZSBpdFxuICogYGBgXG4gKiBJZiBtZXNzZW5nZXIgaGFzIFtNZXNzYWdlU291cmNlXSguL21fc291cmNlLmpzLmh0bWwpIGF0dGFjaGVkIHRvIGl0LCBNZXNzYWdlU291cmNlIHdpbGwgYmUgbm90aWZpZWQgd2hlbiB0aGUgZmlyc3Qgc3Vic2NyaWJlciBmb3IgYSBnaXZlbiBtZXNzYWdlIGlzIGFkZGVkLCBzbyBpdCBjYW4gc3Vic2NyaWJlIHRvIHRoZSBzb3VyY2UuXG4gKiBbQ29tcG9uZW50c10oLi4vY29tcG9uZW50cy9jX2NsYXNzLmpzLmh0bWwpIGFuZCBbZmFjZXRzXSguLi9jb21wb25lbnRzL2NfZmFjZXQuanMuaHRtbCkgY2hhbmdlIHRoaXMgbWV0aG9kIG5hbWUgdG8gYG9uYCB3aGVuIHRoZXkgcHJveHkgaXQuXG4gKiBTZWUgW3Bvc3RNZXNzYWdlXSgjcG9zdE1lc3NhZ2UpLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfEFycmF5W1N0cmluZ118UmVnRXhwfSBtZXNzYWdlcyBNZXNzYWdlIHR5cGVzIHRoYXQgc2hvdWxkIGVudm9rZSB0aGUgc3Vic2NyaWJlci5cbiAqICBJZiBzdHJpbmcgaXMgcGFzc2VkLCBpdCBjYW4gYmUgYSBzaWdsZSBtZXNzYWdlIG9yIG11bHRpcGxlIG1lc3NhZ2UgdHlwZXMgc2VwYXJhdGVkIGJ5IHdoaXRlc3BhY2Ugd2l0aCBvcHRpb25hbCBjb21tYXMuXG4gKiAgSWYgYW4gYXJyYXkgb2Ygc3RyaW5ncyBpcyBwYXNzZWQsIGVhY2ggc3RyaW5nIGlzIGEgbWVzc2FnZSB0eXBlIHRvIHN1YnNjcmliZSBmb3IuXG4gKiAgSWYgYSBSZWdFeHAgaXMgcGFzc2VkLCB0aGUgc3Vic2NyaWJlciB3aWxsIGJlIGVudm9rZWQgd2hlbiB0aGUgbWVzc2FnZSBkaXNwYXRjaGVkIG9uIHRoZSBtZXNzZW5nZXIgbWF0Y2hlcyB0aGUgcGF0dGVybiAob3IgSVMgdGhlIFJlZ0V4cCB3aXRoIGlkZW50aWNhbCBwYXR0ZXJuKS5cbiAqICBQYXR0ZXJuIHN1YnNjcmliZXIgZG9lcyBOT1QgY2F1c2UgYW55IHN1YnNjcmlwdGlvbiB0byBNZXNzYWdlU291cmNlLCBpdCBvbmx5IGNhcHR1cmVzIG1lc3NhZ2VzIHRoYXQgYXJlIGFscmVhZHkgc3Vic2NyaWJlZCB0byB3aXRoIHByZWNpc2UgbWVzc2FnZSB0eXBlcy5cbiAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fSBzdWJzY3JpYmVyIE1lc3NhZ2Ugc3Vic2NyaWJlciAtIGEgZnVuY3Rpb24gdGhhdCB3aWxsIGJlIGNhbGxlZCB3aGVuIHRoZSBtZXNzYWdlIGlzIGRpc3BhdGNoZWQgb24gdGhlIG1lc3NlbmdlciAodXN1YWxseSB2aWEgcHJveGllZCBwb3N0TWVzc2FnZSBtZXRob2Qgb2YgaG9zdCBvYmplY3QpLlxuICogIElmIGhvc3RPYmplY3Qgd2FzIHN1cHBsaWVkIHRvIE1lc3NlbmdlciBjb25zdHJ1Y3RvciwgaG9zdE9iamVjdCB3aWxsIGJlIHRoZSBjb250ZXh0ICh0aGUgdmFsdWUgb2YgdGhpcykgZm9yIHRoZSBzdWJzY3JpYmVyIGVudm9jYXRpb24uXG4gKiAgU3Vic2NyaWJlciBjYW4gYWxzbyBiZSBhbiBvYmplY3Qgd2l0aCBwcm9wZXJ0aWVzIGBzdWJzY3JpYmVyYCAoZnVuY3Rpb24pIGFuZCBgY29udGV4dGAgKFwidGhpc1wiIHZhbHVlIHdoZW4gc3Vic2NyaWJlciBpcyBjYWxsZWQpXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBNZXNzZW5nZXIkb24obWVzc2FnZXMsIHN1YnNjcmliZXIpIHtcbiAgICByZXR1cm4gX01lc3Nlbmdlcl9vbldpdGhPcHRpb25zLmNhbGwodGhpcywgbWVzc2FnZXMsIHN1YnNjcmliZXIpO1xufVxuXG5cbmZ1bmN0aW9uIE1lc3NlbmdlciRvbmNlKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKSB7XG4gICAgcmV0dXJuIF9NZXNzZW5nZXJfb25XaXRoT3B0aW9ucy5jYWxsKHRoaXMsIG1lc3NhZ2VzLCBzdWJzY3JpYmVyLCB7IGRpc3BhdGNoVGltZXM6IDEgfSk7XG59XG5cbmZ1bmN0aW9uIE1lc3NlbmdlciRvbmNlU3luYyhtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIHJldHVybiBfTWVzc2VuZ2VyX29uV2l0aE9wdGlvbnMuY2FsbCh0aGlzLCBtZXNzYWdlcywgc3Vic2NyaWJlciwgeyBkaXNwYXRjaFRpbWVzOiAxLCBzeW5jOiB0cnVlIH0pO1xufVxuXG5cbmZ1bmN0aW9uIE1lc3NlbmdlciRvblN5bmMobWVzc2FnZXMsIHN1YnNjcmliZXIpIHtcbiAgICByZXR1cm4gX01lc3Nlbmdlcl9vbldpdGhPcHRpb25zLmNhbGwodGhpcywgbWVzc2FnZXMsIHN1YnNjcmliZXIsIHsgc3luYzogdHJ1ZSB9KTtcbn1cblxuXG5mdW5jdGlvbiBNZXNzZW5nZXIkb25Bc3luYyhtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIHJldHVybiBfTWVzc2VuZ2VyX29uV2l0aE9wdGlvbnMuY2FsbCh0aGlzLCBtZXNzYWdlcywgc3Vic2NyaWJlciwgeyBzeW5jOiBmYWxzZSB9KTtcbn1cblxuXG5mdW5jdGlvbiBfTWVzc2VuZ2VyX29uV2l0aE9wdGlvbnMobWVzc2FnZXMsIHN1YnNjcmliZXIsIG9wdGlvbnMpIHtcbiAgICBjaGVjayhtZXNzYWdlcywgTWF0Y2guT25lT2YoU3RyaW5nLCBbU3RyaW5nXSwgUmVnRXhwKSk7XG4gICAgY2hlY2soc3Vic2NyaWJlciwgTWF0Y2guT25lT2YoRnVuY3Rpb24sIHtcbiAgICAgICAgc3Vic2NyaWJlcjogRnVuY3Rpb24sXG4gICAgICAgIGNvbnRleHQ6IE1hdGNoLkFueSxcbiAgICAgICAgb3B0aW9uczogTWF0Y2guT3B0aW9uYWwoT2JqZWN0KSxcbiAgICB9KSk7XG5cbiAgICBpZiAodHlwZW9mIHN1YnNjcmliZXIgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBzdWJzY3JpYmVyID0ge1xuICAgICAgICAgICAgc3Vic2NyaWJlcjogc3Vic2NyaWJlcixcbiAgICAgICAgICAgIGNvbnRleHQ6IHRoaXMuX2hvc3RPYmplY3QsXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgICAgc3Vic2NyaWJlci5vcHRpb25zID0gc3Vic2NyaWJlci5vcHRpb25zIHx8IHt9O1xuICAgICAgICBfLmV4dGVuZChzdWJzY3JpYmVyLm9wdGlvbnMsIG9wdGlvbnMpO1xuICAgIH1cblxuICAgIHJldHVybiBfTWVzc2VuZ2VyX29uLmNhbGwodGhpcywgbWVzc2FnZXMsIHN1YnNjcmliZXIpO1xufVxuXG5cbmZ1bmN0aW9uIF9NZXNzZW5nZXJfb24obWVzc2FnZXMsIHN1YnNjcmliZXIpIHtcbiAgICBfLmRlZmluZVByb3BlcnR5KHN1YnNjcmliZXIsICdfX21lc3NhZ2VzJywgbWVzc2FnZXMpO1xuICAgIHJldHVybiBfZWFjaE1lc3NhZ2UuY2FsbCh0aGlzLCAnX3JlZ2lzdGVyU3Vic2NyaWJlcicsIG1lc3NhZ2VzLCBzdWJzY3JpYmVyKTtcbn1cblxuXG5mdW5jdGlvbiBfZWFjaE1lc3NhZ2UobWV0aG9kTmFtZSwgbWVzc2FnZXMsIHN1YnNjcmliZXIpIHtcbiAgICBpZiAodHlwZW9mIG1lc3NhZ2VzID09ICdzdHJpbmcnKVxuICAgICAgICBtZXNzYWdlcyA9IG1lc3NhZ2VzLnNwbGl0KG1lc3NhZ2VzU3BsaXRSZWdFeHApO1xuXG4gICAgdmFyIHN1YnNjcmliZXJzSGFzaCA9IHRoaXMuX2Nob29zZVN1YnNjcmliZXJzSGFzaChtZXNzYWdlcyk7XG5cbiAgICBpZiAobWVzc2FnZXMgaW5zdGFuY2VvZiBSZWdFeHApXG4gICAgICAgIHJldHVybiB0aGlzW21ldGhvZE5hbWVdKHN1YnNjcmliZXJzSGFzaCwgbWVzc2FnZXMsIHN1YnNjcmliZXIpO1xuXG4gICAgZWxzZSB7XG4gICAgICAgIHZhciBjaGFuZ2VkID0gZmFsc2U7XG5cbiAgICAgICAgbWVzc2FnZXMuZm9yRWFjaChmdW5jdGlvbihtZXNzYWdlKSB7XG4gICAgICAgICAgICB2YXIgc3Vic2NyaXB0aW9uQ2hhbmdlZCA9IHRoaXNbbWV0aG9kTmFtZV0oc3Vic2NyaWJlcnNIYXNoLCBtZXNzYWdlLCBzdWJzY3JpYmVyKTtcbiAgICAgICAgICAgIGNoYW5nZWQgPSBjaGFuZ2VkIHx8IHN1YnNjcmlwdGlvbkNoYW5nZWQ7XG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHJldHVybiBjaGFuZ2VkO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIFwiUHJpdmF0ZVwiIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2RcbiAqIEl0IGlzIGNhbGxlZCBieSBbb25dKCNNZXNzZW5nZXIkb24pIHRvIHJlZ2lzdGVyIHN1YnNjcmliZXIgZm9yIG9uZSBtZXNzYWdlIHR5cGUuXG4gKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGlzIHN1YnNjcmliZXIgaXMgbm90IHlldCByZWdpc3RlcmVkIGZvciB0aGlzIHR5cGUgb2YgbWVzc2FnZS5cbiAqIElmIG1lc3NlbmdlciBoYXMgW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgYXR0YWNoZWQgdG8gaXQsIE1lc3NhZ2VTb3VyY2Ugd2lsbCBiZSBub3RpZmllZCB3aGVuIHRoZSBmaXJzdCBzdWJzY3JpYmVyIGZvciBhIGdpdmVuIG1lc3NhZ2UgaXMgYWRkZWQuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBzdWJzY3JpYmVyc0hhc2ggVGhlIG1hcCBvZiBzdWJzY3JpYmVycyBkZXRlcm1pbmVkIGJ5IFtvbl0oI01lc3NlbmdlciRvbikgYmFzZWQgb24gTWVzc2FnZSB0eXBlLCBjYW4gYmUgYHRoaXMuX3BhdHRlcm5NZXNzYWdlU3Vic2NyaWJlcnNgIG9yIGB0aGlzLl9tZXNzYWdlU3Vic2NyaWJlcnNgXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBNZXNzYWdlIHR5cGVcbiAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fSBzdWJzY3JpYmVyIFN1YnNjcmliZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQgb3Igb2JqZWN0IHdpdGggcHJvcGVydGllcyBgc3Vic2NyaWJlcmAgKGZ1bmN0aW9uKSBhbmQgYGNvbnRleHRgICh2YWx1ZSBvZiBcInRoaXNcIiB3aGVuIHN1YnNjcmliZXIgaXMgY2FsbGVkKVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gX3JlZ2lzdGVyU3Vic2NyaWJlcihzdWJzY3JpYmVyc0hhc2gsIG1lc3NhZ2UsIHN1YnNjcmliZXIpIHtcbiAgICBpZiAoISAoc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdICYmIHN1YnNjcmliZXJzSGFzaFttZXNzYWdlXS5sZW5ndGgpKSB7XG4gICAgICAgIHN1YnNjcmliZXJzSGFzaFttZXNzYWdlXSA9IFtdO1xuICAgICAgICBpZiAobWVzc2FnZSBpbnN0YW5jZW9mIFJlZ0V4cClcbiAgICAgICAgICAgIHN1YnNjcmliZXJzSGFzaFttZXNzYWdlXS5wYXR0ZXJuID0gbWVzc2FnZTtcbiAgICAgICAgaWYgKHRoaXMuX21lc3NhZ2VTb3VyY2UpXG4gICAgICAgICAgICB0aGlzLl9tZXNzYWdlU291cmNlLm9uU3Vic2NyaWJlckFkZGVkKG1lc3NhZ2UpO1xuICAgICAgICB2YXIgbm9TdWJzY3JpYmVycyA9IHRydWU7XG4gICAgfVxuXG4gICAgdmFyIG1zZ1N1YnNjcmliZXJzID0gc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdO1xuICAgIHZhciBub3RZZXRSZWdpc3RlcmVkID0gbm9TdWJzY3JpYmVycyB8fCBfaW5kZXhPZlN1YnNjcmliZXIuY2FsbCh0aGlzLCBtc2dTdWJzY3JpYmVycywgc3Vic2NyaWJlcikgPT0gLTE7XG5cbiAgICBpZiAobm90WWV0UmVnaXN0ZXJlZClcbiAgICAgICAgbXNnU3Vic2NyaWJlcnMucHVzaChzdWJzY3JpYmVyKTtcblxuICAgIHJldHVybiBub3RZZXRSZWdpc3RlcmVkO1xufVxuXG5cbi8qKlxuICogRmluZHMgc3Vic2NyaWJlciBpbmRleCBpbiB0aGUgbGlzdFxuICpcbiAqIEBwYXJhbSB7QXJyYXlbRnVuY3Rpb258T2JqZWN0XX0gbGlzdCBsaXN0IG9mIHN1YnNjcmliZXJzXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdH0gc3Vic2NyaWJlciBzdWJzY3JpYmVyIGZ1bmN0aW9uIG9yIG9iamVjdCB3aXRoIHByb3BlcnRpZXMgYHN1YnNjcmliZXJgIChmdW5jdGlvbikgYW5kIGBjb250ZXh0YCAoXCJ0aGlzXCIgb2JqZWN0KVxuICovXG5mdW5jdGlvbiBfaW5kZXhPZlN1YnNjcmliZXIobGlzdCwgc3Vic2NyaWJlcikge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICByZXR1cm4gXy5maW5kSW5kZXgobGlzdCwgZnVuY3Rpb24oc3Vic2NyKXtcbiAgICAgICAgcmV0dXJuIHN1YnNjcmliZXIuc3Vic2NyaWJlciA9PSBzdWJzY3Iuc3Vic2NyaWJlclxuICAgICAgICAgICAgICAgICYmIHN1YnNjcmliZXIuY29udGV4dCA9PSBzdWJzY3IuY29udGV4dFxuICAgIH0pO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZC5cbiAqIFN1YnNjcmliZXMgdG8gbXVsdGlwbGUgbWVzc2FnZXMgcGFzc2VkIGFzIG1hcCB0b2dldGhlciB3aXRoIHN1YnNjcmliZXJzLlxuICogVXNhZ2U6XG4gKiBgYGBcbiAqIG15Q29tcC5ldmVudHMub25NZXNzYWdlcyh7XG4gKiAgICAgJ21vdXNlZG93bic6IG9uTW91c2VEb3duLFxuICogICAgICdtb3VzZXVwJzogb25Nb3VzZVVwXG4gKiB9KTtcbiAqIGZ1bmN0aW9uIG9uTW91c2VEb3duKGV2ZW50VHlwZSwgZXZlbnQpIHt9XG4gKiBmdW5jdGlvbiBvbk1vdXNlVXAoZXZlbnRUeXBlLCBldmVudCkge31cbiAqIGBgYFxuICogUmV0dXJucyBtYXAgd2l0aCB0aGUgc2FtZSBrZXlzIChtZXNzYWdlIHR5cGVzKSBhbmQgYm9vbGVhbiB2YWx1ZXMgaW5kaWNhdGluZyB3aGV0aGVyIHBhcnRpY3VsYXIgc3Vic2NyaWJlciB3YXMgYWRkZWQuXG4gKiBJdCBpcyBOT1QgcG9zc2libGUgdG8gYWRkIHBhdHRlcm4gc3Vic2NyaWJlciB1c2luZyB0aGlzIG1ldGhvZCwgYXMgYWx0aG91Z2ggeW91IGNhbiB1c2UgUmVnRXhwIGFzIHRoZSBrZXksIEphdmFTY3JpcHQgd2lsbCBhdXRvbWF0aWNhbGx5IGNvbnZlcnQgaXQgdG8gc3RyaW5nLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0W0Z1bmN0aW9uXX0gbWVzc2FnZVN1YnNjcmliZXJzIE1hcCBvZiBtZXNzYWdlIHN1YnNjcmliZXJzIHRvIGJlIGFkZGVkXG4gKiBAcmV0dXJuIHtPYmplY3RbQm9vbGVhbl19XG4gKi9cbmZ1bmN0aW9uIG9uTWVzc2FnZXMobWVzc2FnZVN1YnNjcmliZXJzKSB7XG4gICAgY2hlY2sobWVzc2FnZVN1YnNjcmliZXJzLCBNYXRjaC5PYmplY3RIYXNoKE1hdGNoLk9uZU9mKEZ1bmN0aW9uLCB7IHN1YnNjcmliZXI6IEZ1bmN0aW9uLCBjb250ZXh0OiBNYXRjaC5BbnkgfSkpKTtcblxuICAgIHZhciBub3RZZXRSZWdpc3RlcmVkTWFwID0gXy5tYXBLZXlzKG1lc3NhZ2VTdWJzY3JpYmVycywgZnVuY3Rpb24oc3Vic2NyaWJlciwgbWVzc2FnZXMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub24obWVzc2FnZXMsIHN1YnNjcmliZXIpO1xuICAgIH0sIHRoaXMpO1xuXG4gICAgcmV0dXJuIG5vdFlldFJlZ2lzdGVyZWRNYXA7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogUmVtb3ZlcyBhIHN1YnNjcmliZXIgZm9yIG1lc3NhZ2UocykuIFJlbW92ZXMgYWxsIHN1YnNjcmliZXJzIGZvciB0aGUgbWVzc2FnZSBpZiBzdWJzY3JpYmVyIGlzbid0IHBhc3NlZC5cbiAqIFRoaXMgbWV0aG9kIHJldHVybnMgYHRydWVgIGlmIHRoZSBzdWJzY3JpYmVyIHdhcyByZWdpc3RlcmVkLiBObyBlcnJvciBvciB3YXJuaW5nIGlzIHRocm93biBvciBsb2dnZWQgaWYgeW91IHJlbW92ZSBzdWJzY3JpYmVyIHRoYXQgd2FzIG5vdCByZWdpc3RlcmVkLlxuICogW0NvbXBvbmVudHNdKC4uL2NvbXBvbmVudHMvY19jbGFzcy5qcy5odG1sKSBhbmQgW2ZhY2V0c10oLi4vY29tcG9uZW50cy9jX2ZhY2V0LmpzLmh0bWwpIGNoYW5nZSB0aGlzIG1ldGhvZCBuYW1lIHRvIGBvZmZgIHdoZW4gdGhleSBwcm94eSBpdC5cbiAqIFVzYWdlOlxuICogYGBgXG4gKiAvLyB1bnN1YnNjcmliZXMgb25Nb3VzZVVwRG93biBmcm9tIHR3byBET00gZXZlbnRzLlxuICogbXlDb21wLmV2ZW50cy5vZmYoJ21vdXNlZG93biBtb3VzZXVwJywgb25Nb3VzZVVwRG93bik7XG4gKiBgYGBcbiAqIElmIG1lc3NlbmdlciBoYXMgW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgYXR0YWNoZWQgdG8gaXQsIE1lc3NhZ2VTb3VyY2Ugd2lsbCBiZSBub3RpZmllZCB3aGVuIHRoZSBsYXN0IHN1YnNjcmliZXIgZm9yIGEgZ2l2ZW4gbWVzc2FnZSBpcyByZW1vdmVkIGFuZCB0aGVyZSBpcyBubyBtb3JlIHN1YnNjcmliZXJzIGZvciB0aGlzIG1lc3NhZ2UuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8QXJyYXlbU3RyaW5nXXxSZWdFeHB9IG1lc3NhZ2VzIE1lc3NhZ2UgdHlwZXMgdGhhdCBhIHN1YnNjcmliZXIgc2hvdWxkIGJlIHJlbW92ZWQgZm9yLlxuICogIElmIHN0cmluZyBpcyBwYXNzZWQsIGl0IGNhbiBiZSBhIHNpZ2xlIG1lc3NhZ2Ugb3IgbXVsdGlwbGUgbWVzc2FnZSB0eXBlcyBzZXBhcmF0ZWQgYnkgd2hpdGVzcGFjZSB3aXRoIG9wdGlvbmFsIGNvbW1hcy5cbiAqICBJZiBhbiBhcnJheSBvZiBzdHJpbmdzIGlzIHBhc3NlZCwgZWFjaCBzdHJpbmcgaXMgYSBtZXNzYWdlIHR5cGUgdG8gcmVtb3ZlIGEgc3Vic2NyaWJlciBmb3IuXG4gKiAgSWYgYSBSZWdFeHAgaXMgcGFzc2VkLCB0aGUgcGF0dGVybiBzdWJzY3JpYmVyIHdpbGwgYmUgcmVtb3ZlZC5cbiAqICBSZWdFeHAgc3Vic2NyaWJlciBkb2VzIE5PVCBjYXVzZSBhbnkgc3Vic2NyaXB0aW9uIHRvIE1lc3NhZ2VTb3VyY2UsIGl0IG9ubHkgY2FwdHVyZXMgbWVzc2FnZXMgdGhhdCBhcmUgYWxyZWFkeSBzdWJzY3JpYmVkIHRvIHdpdGggcHJlY2lzZSBtZXNzYWdlIHR5cGVzLlxuICogQHBhcmFtIHtGdW5jdGlvbn0gc3Vic2NyaWJlciBNZXNzYWdlIHN1YnNjcmliZXIgLSBPcHRpb25hbCBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgcmVtb3ZlZCBmcm9tIHRoZSBsaXN0IG9mIHN1YnNjcmliZXJzIGZvciB0aGUgbWVzc2FnZShzKS4gSWYgc3Vic2NyaWJlciBpcyBub3Qgc3VwcGxpZWQsIGFsbCBzdWJzY3JpYmVycyB3aWxsIGJlIHJlbW92ZWQgZnJvbSB0aGlzIG1lc3NhZ2UocykuXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBNZXNzZW5nZXIkb2ZmKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKSB7XG4gICAgY2hlY2sobWVzc2FnZXMsIE1hdGNoLk9uZU9mKFN0cmluZywgW1N0cmluZ10sIFJlZ0V4cCkpO1xuICAgIGNoZWNrKHN1YnNjcmliZXIsIE1hdGNoLk9wdGlvbmFsKE1hdGNoLk9uZU9mKEZ1bmN0aW9uLCB7XG4gICAgICAgIHN1YnNjcmliZXI6IEZ1bmN0aW9uLFxuICAgICAgICBjb250ZXh0OiBNYXRjaC5BbnksXG4gICAgICAgIG9wdGlvbnM6IE1hdGNoLk9wdGlvbmFsKE9iamVjdCksXG4gICAgICAgIC8vIF9fbWVzc2FnZXM6IE1hdGNoLk9wdGlvbmFsKE1hdGNoLk9uZU9mKFN0cmluZywgW1N0cmluZ10sIFJlZ0V4cCkpXG4gICAgfSkpKTtcblxuICAgIHJldHVybiBfTWVzc2VuZ2VyX29mZi5jYWxsKHRoaXMsIG1lc3NhZ2VzLCBzdWJzY3JpYmVyKTtcbn1cblxuXG5mdW5jdGlvbiBfTWVzc2VuZ2VyX29mZihtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIHJldHVybiBfZWFjaE1lc3NhZ2UuY2FsbCh0aGlzLCAnX3JlbW92ZVN1YnNjcmliZXInLCBtZXNzYWdlcywgc3Vic2NyaWJlcik7XG59XG5cblxuLyoqXG4gKiBcIlByaXZhdGVcIiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBJdCBpcyBjYWxsZWQgYnkgW29mZl0oI01lc3NlbmdlciRvZmYpIHRvIHJlbW92ZSBzdWJzY3JpYmVyIGZvciBvbmUgbWVzc2FnZSB0eXBlLlxuICogUmV0dXJucyBgdHJ1ZWAgaWYgdGhpcyBzdWJzY3JpYmVyIHdhcyByZWdpc3RlcmVkIGZvciB0aGlzIHR5cGUgb2YgbWVzc2FnZS5cbiAqIElmIG1lc3NlbmdlciBoYXMgW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgYXR0YWNoZWQgdG8gaXQsIE1lc3NhZ2VTb3VyY2Ugd2lsbCBiZSBub3RpZmllZCB3aGVuIHRoZSBsYXN0IHN1YnNjcmliZXIgZm9yIGEgZ2l2ZW4gbWVzc2FnZSBpcyByZW1vdmVkIGFuZCB0aGVyZSBpcyBubyBtb3JlIHN1YnNjcmliZXJzIGZvciB0aGlzIG1lc3NhZ2UuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBzdWJzY3JpYmVyc0hhc2ggVGhlIG1hcCBvZiBzdWJzY3JpYmVycyBkZXRlcm1pbmVkIGJ5IFtvZmZdKCNNZXNzZW5nZXIkb2ZmKSBiYXNlZCBvbiBtZXNzYWdlIHR5cGUsIGNhbiBiZSBgdGhpcy5fcGF0dGVybk1lc3NhZ2VTdWJzY3JpYmVyc2Agb3IgYHRoaXMuX21lc3NhZ2VTdWJzY3JpYmVyc2BcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIE1lc3NhZ2UgdHlwZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gc3Vic2NyaWJlciBTdWJzY3JpYmVyIGZ1bmN0aW9uIHRvIGJlIHJlbW92ZWRcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIF9yZW1vdmVTdWJzY3JpYmVyKHN1YnNjcmliZXJzSGFzaCwgbWVzc2FnZSwgc3Vic2NyaWJlcikge1xuICAgIHZhciBtc2dTdWJzY3JpYmVycyA9IHN1YnNjcmliZXJzSGFzaFttZXNzYWdlXTtcbiAgICBpZiAoISBtc2dTdWJzY3JpYmVycyB8fCAhIG1zZ1N1YnNjcmliZXJzLmxlbmd0aClcbiAgICAgICAgcmV0dXJuIGZhbHNlOyAvLyBub3RoaW5nIHJlbW92ZWRcblxuICAgIGlmIChzdWJzY3JpYmVyKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygc3Vic2NyaWJlciA9PSAnZnVuY3Rpb24nKVxuICAgICAgICAgICAgc3Vic2NyaWJlciA9IHsgc3Vic2NyaWJlcjogc3Vic2NyaWJlciwgY29udGV4dDogdGhpcy5faG9zdE9iamVjdCB9O1xuXG4gICAgICAgIHZhciBzdWJzY3JpYmVySW5kZXggPSBfaW5kZXhPZlN1YnNjcmliZXIuY2FsbCh0aGlzLCBtc2dTdWJzY3JpYmVycywgc3Vic2NyaWJlcik7XG4gICAgICAgIGlmIChzdWJzY3JpYmVySW5kZXggPT0gLTEpXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7IC8vIG5vdGhpbmcgcmVtb3ZlZFxuICAgICAgICBtc2dTdWJzY3JpYmVycy5zcGxpY2Uoc3Vic2NyaWJlckluZGV4LCAxKTtcbiAgICAgICAgaWYgKCEgbXNnU3Vic2NyaWJlcnMubGVuZ3RoKVxuICAgICAgICAgICAgdGhpcy5fcmVtb3ZlQWxsU3Vic2NyaWJlcnMoc3Vic2NyaWJlcnNIYXNoLCBtZXNzYWdlKTtcblxuICAgIH0gZWxzZVxuICAgICAgICB0aGlzLl9yZW1vdmVBbGxTdWJzY3JpYmVycyhzdWJzY3JpYmVyc0hhc2gsIG1lc3NhZ2UpO1xuXG4gICAgcmV0dXJuIHRydWU7IC8vIHN1YnNjcmliZXIocykgcmVtb3ZlZFxufVxuXG5cbi8qKlxuICogXCJQcml2YXRlXCIgTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZFxuICogSXQgaXMgY2FsbGVkIGJ5IFtfcmVtb3ZlU3Vic2NyaWJlcl0oI19yZW1vdmVTdWJzY3JpYmVyKSB0byByZW1vdmUgYWxsIHN1YnNjcmliZXJzIGZvciBvbmUgbWVzc2FnZSB0eXBlLlxuICogSWYgbWVzc2VuZ2VyIGhhcyBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBhdHRhY2hlZCB0byBpdCwgTWVzc2FnZVNvdXJjZSB3aWxsIGJlIG5vdGlmaWVkIHRoYXQgYWxsIG1lc3NhZ2Ugc3Vic2NyaWJlcnMgd2VyZSByZW1vdmVkIHNvIGl0IGNhbiB1bnN1YnNjcmliZSBmcm9tIHRoZSBzb3VyY2UuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBzdWJzY3JpYmVyc0hhc2ggVGhlIG1hcCBvZiBzdWJzY3JpYmVycyBkZXRlcm1pbmVkIGJ5IFtvZmZdKCNNZXNzZW5nZXIkb2ZmKSBiYXNlZCBvbiBtZXNzYWdlIHR5cGUsIGNhbiBiZSBgdGhpcy5fcGF0dGVybk1lc3NhZ2VTdWJzY3JpYmVyc2Agb3IgYHRoaXMuX21lc3NhZ2VTdWJzY3JpYmVyc2BcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIE1lc3NhZ2UgdHlwZVxuICovXG5mdW5jdGlvbiBfcmVtb3ZlQWxsU3Vic2NyaWJlcnMoc3Vic2NyaWJlcnNIYXNoLCBtZXNzYWdlKSB7XG4gICAgZGVsZXRlIHN1YnNjcmliZXJzSGFzaFttZXNzYWdlXTtcbiAgICBpZiAodGhpcy5fbWVzc2FnZVNvdXJjZSAmJiB0eXBlb2YgbWVzc2FnZSA9PSAnc3RyaW5nJylcbiAgICAgICAgdGhpcy5fbWVzc2FnZVNvdXJjZS5vblN1YnNjcmliZXJSZW1vdmVkKG1lc3NhZ2UpO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZC5cbiAqIFVuc3Vic2NyaWJlcyBmcm9tIG11bHRpcGxlIG1lc3NhZ2VzIHBhc3NlZCBhcyBtYXAgdG9nZXRoZXIgd2l0aCBzdWJzY3JpYmVycy5cbiAqIFJldHVybnMgbWFwIHdpdGggdGhlIHNhbWUga2V5cyAobWVzc2FnZSB0eXBlcykgYW5kIGJvb2xlYW4gdmFsdWVzIGluZGljYXRpbmcgd2hldGhlciBwYXJ0aWN1bGFyIHN1YnNjcmliZXIgd2FzIHJlbW92ZWQuXG4gKiBJZiBhIHN1YnNjcmliZXIgZm9yIG9uZSBvZiB0aGUgbWVzc2FnZXMgaXMgbm90IHN1cHBsaWVkLCBhbGwgc3Vic2NyaWJlcnMgZm9yIHRoaXMgbWVzc2FnZSB3aWxsIGJlIHJlbW92ZWQuXG4gKiBVc2FnZTpcbiAqIGBgYFxuICogbXlDb21wLmV2ZW50cy5vZmZNZXNzYWdlcyh7XG4gKiAgICAgJ21vdXNlZG93bic6IG9uTW91c2VEb3duLFxuICogICAgICdtb3VzZXVwJzogb25Nb3VzZVVwLFxuICogICAgICdjbGljayc6IHVuZGVmaW5lZCAvLyBhbGwgc3Vic2NyaWJlcnMgdG8gdGhpcyBtZXNzYWdlIHdpbGwgYmUgcmVtb3ZlZFxuICogfSk7XG4gKiBgYGBcbiAqIEl0IGlzIE5PVCBwb3NzaWJsZSB0byByZW1vdmUgcGF0dGVybiBzdWJzY3JpYmVyKHMpIHVzaW5nIHRoaXMgbWV0aG9kLCBhcyBhbHRob3VnaCB5b3UgY2FuIHVzZSBSZWdFeHAgYXMgdGhlIGtleSwgSmF2YVNjcmlwdCB3aWxsIGF1dG9tYXRpY2FsbHkgY29udmVydCBpdCB0byBzdHJpbmcuXG4gKlxuICogQHBhcmFtIHtPYmplY3RbRnVuY3Rpb25dfSBtZXNzYWdlU3Vic2NyaWJlcnMgTWFwIG9mIG1lc3NhZ2Ugc3Vic2NyaWJlcnMgdG8gYmUgcmVtb3ZlZFxuICogQHJldHVybiB7T2JqZWN0W0Jvb2xlYW5dfVxuICovXG5mdW5jdGlvbiBvZmZNZXNzYWdlcyhtZXNzYWdlU3Vic2NyaWJlcnMpIHtcbiAgICBjaGVjayhtZXNzYWdlU3Vic2NyaWJlcnMsIE1hdGNoLk9iamVjdEhhc2goTWF0Y2guT3B0aW9uYWwoTWF0Y2guT25lT2YoRnVuY3Rpb24sIHsgc3Vic2NyaWJlcjogRnVuY3Rpb24sIGNvbnRleHQ6IE1hdGNoLkFueSB9KSkpKTtcblxuICAgIHZhciBzdWJzY3JpYmVyUmVtb3ZlZE1hcCA9IF8ubWFwS2V5cyhtZXNzYWdlU3Vic2NyaWJlcnMsIGZ1bmN0aW9uKHN1YnNjcmliZXIsIG1lc3NhZ2VzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9mZihtZXNzYWdlcywgc3Vic2NyaWJlcik7XG4gICAgfSwgdGhpcyk7XG5cbiAgICByZXR1cm4gc3Vic2NyaWJlclJlbW92ZWRNYXA7XG59XG5cblxuLyoqXG4gKiBVbnN1YnNjcmliZXMgYWxsIHN1YnNjcmliZXJzXG4gKi9cbmZ1bmN0aW9uIE1lc3NlbmdlciRvZmZBbGwoKSB7XG4gICAgX29mZkFsbFN1YnNjcmliZXJzLmNhbGwodGhpcywgdGhpcy5fcGF0dGVybk1lc3NhZ2VTdWJzY3JpYmVycyk7XG4gICAgX29mZkFsbFN1YnNjcmliZXJzLmNhbGwodGhpcywgdGhpcy5fbWVzc2FnZVN1YnNjcmliZXJzKTtcbn1cblxuXG5mdW5jdGlvbiBfb2ZmQWxsU3Vic2NyaWJlcnMoc3Vic2NyaWJlcnNIYXNoKSB7XG4gICAgXy5lYWNoS2V5KHN1YnNjcmliZXJzSGFzaCwgZnVuY3Rpb24oc3Vic2NyaWJlcnMsIG1lc3NhZ2UpIHtcbiAgICAgICAgdGhpcy5fcmVtb3ZlQWxsU3Vic2NyaWJlcnMoc3Vic2NyaWJlcnNIYXNoLCBtZXNzYWdlKTtcbiAgICB9LCB0aGlzKTtcbn1cblxuXG4vLyBUT0RPIC0gc2VuZCBldmVudCB0byBtZXNzYWdlU291cmNlXG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogRGlzcGF0Y2hlcyB0aGUgbWVzc2FnZSBjYWxsaW5nIGFsbCBzdWJzY3JpYmVycyByZWdpc3RlcmVkIGZvciB0aGlzIG1lc3NhZ2UgYW5kLCBpZiB0aGUgbWVzc2FnZSBpcyBhIHN0cmluZywgY2FsbGluZyBhbGwgcGF0dGVybiBzdWJzY3JpYmVycyB3aGVuIG1lc3NhZ2UgbWF0Y2hlcyB0aGUgcGF0dGVybi5cbiAqIEVhY2ggc3Vic2NyaWJlciBpcyBwYXNzZWQgdGhlIHNhbWUgcGFyYW1ldGVycyB0aGF0IGFyZSBwYXNzZWQgdG8gdGhlaXMgbWV0aG9kLlxuICogVGhlIGNvbnRleHQgb2YgdGhlIHN1YnNjcmliZXIgZW52b2NhdGlvbiBpcyBzZXQgdG8gdGhlIGhvc3Qgb2JqZWN0IChgdGhpcy5faG9zdE9iamVjdGApIHRoYXQgd2FzIHBhc3NlZCB0byB0aGUgbWVzc2VuZ2VyIGNvbnN0cnVjdG9yLlxuICogU3Vic2NyaWJlcnMgYXJlIGNhbGxlZCBpbiB0aGUgbmV4dCB0aWNrIChcImFzeW5jaHJvbm91c2x5XCIpIGFwYXJ0IGZyb20gdGhvc2UgdGhhdCB3ZXJlIHN1YnNjcmliZWQgd2l0aCBgb25TeW5jYCAob3IgdGhhdCBoYXZlIGBvcHRpb25zLnN5bmMgPT0gdHJ1ZWApLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gbWVzc2FnZSBtZXNzYWdlIHRvIGJlIGRpc3BhdGNoZWRcbiAqICBJZiB0aGUgbWVzc2FnZSBpcyBhIHN0cmluZywgdGhlIHN1YnNjcmliZXJzIHJlZ2lzdGVyZWQgd2l0aCBleGFjdGx5IHRoaXMgbWVzc2FnZSB3aWxsIGJlIGNhbGxlZCBhbmQgYWxzbyBwYXR0ZXJuIHN1YnNjcmliZXJzIHJlZ2lzdGVyZWQgd2l0aCB0aGUgcGF0dGVybiB0aGF0IG1hdGNoZXMgdGhlIGRpc3BhdGNoZWQgbWVzc2FnZS5cbiAqICBJZiB0aGUgbWVzc2FnZSBpcyBSZWdFeHAsIG9ubHkgdGhlIHN1YnNjcmliZXJzIHJlZ2lzdGVyZWQgd2l0aCBleGFjdGx5IHRoaXMgcGF0dGVybiB3aWxsIGJlIGNhbGxlZC5cbiAqIEBwYXJhbSB7QW55fSBkYXRhIGRhdGEgdGhhdCB3aWxsIGJlIHBhc3NlZCB0byB0aGUgc3Vic2NyaWJlciBhcyB0aGUgc2Vjb25kIHBhcmFtZXRlci4gTWVzc2VuZ2VyIGRvZXMgbm90IG1vZGlmeSB0aGlzIGRhdGEgaW4gYW55IHdheS5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIG9wdGlvbmFsIGNhbGxiYWNrIHRvIHBhc3MgdG8gc3Vic2NyaWJlclxuICogQHBhcmFtIHtCb29sZWFufSBfc3luY2hyb25vdXMgaWYgdHJ1ZSBwYXNzZWQsIHN1YnNjcmliZXJzIHdpbGwgYmUgZW52b2tlZCBzeW5jaHJvbm91c2x5IGFwYXJ0IGZyb20gdGhvc2UgdGhhdCBoYXZlIGBvcHRpb25zLnN5bmMgPT0gZmFsc2VgLiBUaGlzIHBhcmFtZXRlciBzaG91bGQgbm90IGJlIHVzZWQsIGluc3RlYWQgcG9zdE1lc3NhZ2VTeW5jIHNob3VsZCBiZSB1c2VkLlxuICovXG5mdW5jdGlvbiBwb3N0TWVzc2FnZShtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaywgX3N5bmNocm9ub3VzKSB7XG4gICAgY2hlY2sobWVzc2FnZSwgTWF0Y2guT25lT2YoU3RyaW5nLCBSZWdFeHApKTtcbiAgICBjaGVjayhjYWxsYmFjaywgTWF0Y2guT3B0aW9uYWwoRnVuY3Rpb24pKTtcblxuICAgIHZhciBzdWJzY3JpYmVyc0hhc2ggPSB0aGlzLl9jaG9vc2VTdWJzY3JpYmVyc0hhc2gobWVzc2FnZSk7XG4gICAgdmFyIG1zZ1N1YnNjcmliZXJzID0gc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdO1xuXG4gICAgdGhpcy5fY2FsbFN1YnNjcmliZXJzKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCBtc2dTdWJzY3JpYmVycywgX3N5bmNocm9ub3VzKTtcblxuICAgIGlmICh0eXBlb2YgbWVzc2FnZSA9PSAnc3RyaW5nJylcbiAgICAgICAgdGhpcy5fY2FsbFBhdHRlcm5TdWJzY3JpYmVycyhtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaywgbXNnU3Vic2NyaWJlcnMsIF9zeW5jaHJvbm91cyk7XG59XG5cblxuLyoqXG4gKiBTYW1lIGFzIHBvc3RNZXNzYWdlIGFwYXJ0IGZyb20gZW52b2tpbmcgc3Vic2NyaWJlcnMgc3luY2hyb25vdXNseSwgYXBhcnQgZnJvbSB0aG9zZSBzdWJzY3JpYmVkIHdpdGggYG9uQXN5bmNgIChvciB3aXRoIGBvcHRpb25zLnN5bmMgPT0gZmFsc2VgKS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ3xSZWdFeHB9IG1lc3NhZ2VcbiAqIEBwYXJhbSB7QW55fSBkYXRhXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICovXG5mdW5jdGlvbiBwb3N0TWVzc2FnZVN5bmMobWVzc2FnZSwgZGF0YSwgY2FsbGJhY2spIHtcbiAgICB0aGlzLnBvc3RNZXNzYWdlKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCB0cnVlKTtcbn1cblxuXG4vKipcbiAqIFwiUHJpdmF0ZVwiIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2RcbiAqIEVudm9rZXMgcGF0dGVybiBzdWJzY3JpYmVycyB3aXRoIHRoZSBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyB0aGUgbWVzc2FnZS5cbiAqIFRoZSBtZXRob2QgaXMgY2FsbGVkIGJ5IFtwb3N0TWVzc2FnZV0oI3Bvc3RNZXNzYWdlKSAtIHNlZSBtb3JlIGluZm9ybWF0aW9uIHRoZXJlLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBtZXNzYWdlIHRvIGJlIGRpc3BhdGNoZWQuIFBhdHRlcm4gc3Vic2NyaWJlcnMgcmVnaXN0ZXJlZCB3aXRoIHRoZSBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyB0aGUgZGlzcGF0Y2hlZCBtZXNzYWdlIHdpbGwgYmUgY2FsbGVkLlxuICogQHBhcmFtIHtBbnl9IGRhdGEgZGF0YSB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBzdWJzY3JpYmVyIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyLiBNZXNzZW5nZXIgZG9lcyBub3QgbW9kaWZ5IHRoaXMgZGF0YSBpbiBhbnkgd2F5LlxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgb3B0aW9uYWwgY2FsbGJhY2sgdG8gcGFzcyB0byBzdWJzY3JpYmVyXG4gKiBAcGFyYW0ge0FycmF5W0Z1bmN0aW9ufE9iamVjdF19IGNhbGxlZE1zZ1N1YnNjcmliZXJzIGFycmF5IG9mIHN1YnNjcmliZXJzIGFscmVhZHkgY2FsbGVkLCB0aGV5IHdvbid0IGJlIGNhbGxlZCBhZ2FpbiBpZiB0aGV5IGFyZSBhbW9uZyBwYXR0ZXJuIHN1YnNjcmliZXJzLlxuICovXG5mdW5jdGlvbiBfY2FsbFBhdHRlcm5TdWJzY3JpYmVycyhtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaywgY2FsbGVkTXNnU3Vic2NyaWJlcnMsIF9zeW5jaHJvbm91cykge1xuICAgIF8uZWFjaEtleSh0aGlzLl9wYXR0ZXJuTWVzc2FnZVN1YnNjcmliZXJzLFxuICAgICAgICBmdW5jdGlvbihwYXR0ZXJuU3Vic2NyaWJlcnMpIHtcbiAgICAgICAgICAgIHZhciBwYXR0ZXJuID0gcGF0dGVyblN1YnNjcmliZXJzLnBhdHRlcm47XG4gICAgICAgICAgICBpZiAocGF0dGVybi50ZXN0KG1lc3NhZ2UpKSB7XG4gICAgICAgICAgICAgICAgaWYgKGNhbGxlZE1zZ1N1YnNjcmliZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBwYXR0ZXJuU3Vic2NyaWJlcnMgPSBwYXR0ZXJuU3Vic2NyaWJlcnMuZmlsdGVyKGZ1bmN0aW9uKHN1YnNjcmliZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpbmRleCA9IF9pbmRleE9mU3Vic2NyaWJlci5jYWxsKHRoaXMsIGNhbGxlZE1zZ1N1YnNjcmliZXJzLCBzdWJzY3JpYmVyKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBpbmRleCA9PSAtMTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMuX2NhbGxTdWJzY3JpYmVycyhtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaywgcGF0dGVyblN1YnNjcmliZXJzLCBfc3luY2hyb25vdXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgLCB0aGlzKTtcbn1cblxuXG4vKipcbiAqIFwiUHJpdmF0ZVwiIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2RcbiAqIEVudm9rZXMgc3Vic2NyaWJlcnMgZnJvbSB0aGUgcGFzc2VkIGxpc3QuXG4gKiBUaGUgbWV0aG9kIGlzIGNhbGxlZCBieSBbcG9zdE1lc3NhZ2VdKCNwb3N0TWVzc2FnZSkgYW5kIFtfY2FsbFBhdHRlcm5TdWJzY3JpYmVyc10oI19jYWxsUGF0dGVyblN1YnNjcmliZXJzKS5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgbWVzc2FnZSB0byBiZSBkaXNwYXRjaGVkLCBwYXNzZWQgdG8gc3Vic2NyaWJlcnMgYXMgdGhlIGZpcnN0IHBhcmFtZXRlci5cbiAqIEBwYXJhbSB7QW55fSBkYXRhIGRhdGEgdGhhdCB3aWxsIGJlIHBhc3NlZCB0byB0aGUgc3Vic2NyaWJlciBhcyB0aGUgc2Vjb25kIHBhcmFtZXRlci4gTWVzc2VuZ2VyIGRvZXMgbm90IG1vZGlmeSB0aGlzIGRhdGEgaW4gYW55IHdheS5cbiAqIEBwYXJhbSB7QXJyYXlbRnVuY3Rpb258T2JqZWN0XX0gbXNnU3Vic2NyaWJlcnMgdGhlIGFycmF5IG9mIG1lc3NhZ2Ugc3Vic2NyaWJlcnMgdG8gYmUgY2FsbGVkLiBFYWNoIHN1YnNjcmliZXIgaXMgY2FsbGVkIHdpdGggdGhlIGhvc3Qgb2JqZWN0IChzZWUgTWVzc2VuZ2VyIGNvbnN0cnVjdG9yKSBhcyB0aGUgY29udGV4dC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIG9wdGlvbmFsIGNhbGxiYWNrIHRvIHBhc3MgdG8gc3Vic2NyaWJlclxuICovXG5mdW5jdGlvbiBfY2FsbFN1YnNjcmliZXJzKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCBtc2dTdWJzY3JpYmVycywgX3N5bmNocm9ub3VzKSB7XG4gICAgaWYgKG1zZ1N1YnNjcmliZXJzICYmIG1zZ1N1YnNjcmliZXJzLmxlbmd0aCkge1xuICAgICAgICAvLyBjbG9uaW5nIGlzIG5lY2Vzc2FyeSBhcyBzb21lIG9mIHRoZSBzdWJzY3JpYmVyc1xuICAgICAgICAvLyBjYW4gYmUgdW5zdWJzY3JpYmVkIGR1cmluZyB0aGUgZGlzcGF0Y2hcbiAgICAgICAgLy8gc28gdGhpcyBhcnJheSB3b3VsZCBjaGFuZ2UgaW4gdGhlIHByb2Nlc3NcbiAgICAgICAgbXNnU3Vic2NyaWJlcnMgPSBtc2dTdWJzY3JpYmVycy5zbGljZSgpO1xuXG4gICAgICAgIG1zZ1N1YnNjcmliZXJzLmZvckVhY2goZnVuY3Rpb24oc3Vic2NyaWJlcikge1xuICAgICAgICAgICAgdGhpcy5fY2FsbFN1YnNjcmliZXIoc3Vic2NyaWJlciwgbWVzc2FnZSwgZGF0YSwgY2FsbGJhY2ssIF9zeW5jaHJvbm91cyk7XG4gICAgICAgIH0sIHRoaXMpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBfY2FsbFN1YnNjcmliZXIoc3Vic2NyaWJlciwgbWVzc2FnZSwgZGF0YSwgY2FsbGJhY2ssIF9zeW5jaHJvbm91cykge1xuICAgIHZhciBzeW5jU3Vic2NyaWJlciA9IHN1YnNjcmliZXIub3B0aW9ucyAmJiBzdWJzY3JpYmVyLm9wdGlvbnMuc3luY1xuICAgICAgICAsIHN5bmNocm8gPSAoX3N5bmNocm9ub3VzICYmIHN5bmNTdWJzY3JpYmVyICE9PSBmYWxzZSlcbiAgICAgICAgICAgICAgICAgIHx8IHN5bmNTdWJzY3JpYmVyO1xuXG4gICAgdmFyIGRpc3BhdGNoVGltZXMgPSBzdWJzY3JpYmVyLm9wdGlvbnMgJiYgc3Vic2NyaWJlci5vcHRpb25zLmRpc3BhdGNoVGltZXM7XG4gICAgaWYgKGRpc3BhdGNoVGltZXMpIHtcbiAgICAgICAgaWYgKGRpc3BhdGNoVGltZXMgPD0gMSkge1xuICAgICAgICAgICAgdmFyIG1lc3NhZ2VzID0gc3Vic2NyaWJlci5fX21lc3NhZ2VzO1xuICAgICAgICAgICAgdGhpcy5vZmYobWVzc2FnZXMsIHN1YnNjcmliZXIpO1xuICAgICAgICB9IGVsc2UgaWYgKGRpc3BhdGNoVGltZXMgPiAxKVxuICAgICAgICAgICAgc3Vic2NyaWJlci5vcHRpb25zLmRpc3BhdGNoVGltZXMtLTtcbiAgICB9XG5cbiAgICBpZiAoc3luY2hybylcbiAgICAgICAgc3Vic2NyaWJlci5zdWJzY3JpYmVyLmNhbGwoc3Vic2NyaWJlci5jb250ZXh0LCBtZXNzYWdlLCBkYXRhLCBjYWxsYmFjayk7XG4gICAgZWxzZVxuICAgICAgICBfLmRlZmVyTWV0aG9kKHN1YnNjcmliZXIuc3Vic2NyaWJlciwgJ2NhbGwnLCBzdWJzY3JpYmVyLmNvbnRleHQsIG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrKTtcbn1cblxuXG4vKipcbiAqIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2QuXG4gKiBSZXR1cm5zIHRoZSBhcnJheSBvZiBzdWJzY3JpYmVycyB0aGF0IHdvdWxkIGJlIGNhbGxlZCBpZiB0aGUgbWVzc2FnZSB3ZXJlIGRpc3BhdGNoZWQuXG4gKiBJZiBgaW5jbHVkZVBhdHRlcm5TdWJzY3JpYmVycyA9PT0gZmFsc2VgLCBwYXR0ZXJuIHN1YnNjcmliZXJzIHdpdGggbWF0Y2hpbmcgcGF0dGVycyB3aWxsIG5vdCBiZSBpbmNsdWRlZCAoYnkgZGVmYXVsdCB0aGV5IGFyZSBpbmNsdWRlZCkuXG4gKiBJZiB0aGVyZSBhcmUgbm8gc3Vic2NyaWJlcnMgdG8gdGhlIG1lc3NhZ2UsIGB1bmRlZmluZWRgIHdpbGwgYmUgcmV0dXJuZWQsIG5vdCBhbiBlbXB0eSBhcnJheSwgc28gaXQgaXMgc2FmZSB0byB1c2UgdGhlIHJlc3VsdCBpbiBib29sZWFuIHRlc3RzLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gbWVzc2FnZSBNZXNzYWdlIHRvIGdldCBzdWJzY3JpYmVycyBmb3IuXG4gKiAgSWYgdGhlIG1lc3NhZ2UgaXMgUmVnRXhwLCBvbmx5IHBhdHRlcm4gc3Vic2NyaWJlcnMgcmVnaXN0ZXJlZCB3aXRoIGV4YWN0bHkgdGhpcyBwYXR0ZXJuIHdpbGwgYmUgcmV0dXJuZWQuXG4gKiAgSWYgdGhlIG1lc3NhZ2UgaXMgU3RyaW5nLCBzdWJzY3JpYmVycyByZWdpc3RlcmVkIHdpdGggdGhlIHN0cmluZyBtZXNzYWdlcyBhbmQgcGF0dGVybiBzdWJzY3JpYmVycyByZWdpc3RlcmVkIHdpdGggbWF0Y2hpbmcgcGF0dGVybiB3aWxsIGJlIHJldHVybmVkICh1bmxlc3MgdGhlIHNlY29uZCBwYXJhbWV0ZXIgaXMgZmFsc2UpLlxuICogQHBhcmFtIHtCb29sZWFufSBpbmNsdWRlUGF0dGVyblN1YnNjcmliZXJzIE9wdGlvbmFsIGZhbHNlIHRvIHByZXZlbnQgaW5jbHVzaW9uIG9mIHBhdHRlciBzdWJzY3JpYmVycywgYnkgZGVmYXVsdCB0aGV5IGFyZSBpbmNsdWRlZC5cbiAqIEByZXR1cm4ge0FycmF5fHVuZGVmaW5lZH1cbiAqL1xuZnVuY3Rpb24gZ2V0U3Vic2NyaWJlcnMobWVzc2FnZSwgaW5jbHVkZVBhdHRlcm5TdWJzY3JpYmVycykge1xuICAgIGNoZWNrKG1lc3NhZ2UsIE1hdGNoLk9uZU9mKFN0cmluZywgUmVnRXhwKSk7XG5cbiAgICB2YXIgc3Vic2NyaWJlcnNIYXNoID0gdGhpcy5fY2hvb3NlU3Vic2NyaWJlcnNIYXNoKG1lc3NhZ2UpO1xuICAgIHZhciBtc2dTdWJzY3JpYmVycyA9IHN1YnNjcmliZXJzSGFzaFttZXNzYWdlXVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gW10uY29uY2F0KHN1YnNjcmliZXJzSGFzaFttZXNzYWdlXSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IFtdO1xuXG4gICAgLy8gcGF0dGVybiBzdWJzY3JpYmVycyBhcmUgaW5jdWRlZCBieSBkZWZhdWx0XG4gICAgaWYgKGluY2x1ZGVQYXR0ZXJuU3Vic2NyaWJlcnMgIT09IGZhbHNlICYmIHR5cGVvZiBtZXNzYWdlID09ICdzdHJpbmcnKSB7XG4gICAgICAgIF8uZWFjaEtleSh0aGlzLl9wYXR0ZXJuTWVzc2FnZVN1YnNjcmliZXJzLFxuICAgICAgICAgICAgZnVuY3Rpb24ocGF0dGVyblN1YnNjcmliZXJzKSB7XG4gICAgICAgICAgICAgICAgdmFyIHBhdHRlcm4gPSBwYXR0ZXJuU3Vic2NyaWJlcnMucGF0dGVybjtcbiAgICAgICAgICAgICAgICBpZiAocGF0dGVyblN1YnNjcmliZXJzICYmIHBhdHRlcm5TdWJzY3JpYmVycy5sZW5ndGhcbiAgICAgICAgICAgICAgICAgICAgICAgICYmIHBhdHRlcm4udGVzdChtZXNzYWdlKSlcbiAgICAgICAgICAgICAgICAgICAgXy5hcHBlbmRBcnJheShtc2dTdWJzY3JpYmVycywgcGF0dGVyblN1YnNjcmliZXJzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyByZXR1cm4gdW5kZWZpbmVkIGlmIHRoZXJlIGFyZSBubyBzdWJzY3JpYmVyc1xuICAgIHJldHVybiBtc2dTdWJzY3JpYmVycy5sZW5ndGhcbiAgICAgICAgICAgICAgICA/IG1zZ1N1YnNjcmliZXJzXG4gICAgICAgICAgICAgICAgOiB1bmRlZmluZWQ7XG59XG5cblxuLyoqXG4gKiBcIlByaXZhdGVcIiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHRoZSBtYXAgb2Ygc3Vic2NyaWJlcnMgZm9yIGEgZ2l2ZW4gbWVzc2FnZSB0eXBlLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge1N0cmluZ3xSZWdFeHB9IG1lc3NhZ2UgTWVzc2FnZSB0byBjaG9vc2UgdGhlIG1hcCBvZiBzdWJzY3JpYmVycyBmb3JcbiAqIEByZXR1cm4ge09iamVjdFtGdW5jdGlvbl19XG4gKi9cbmZ1bmN0aW9uIF9jaG9vc2VTdWJzY3JpYmVyc0hhc2gobWVzc2FnZSkge1xuICAgIHJldHVybiBtZXNzYWdlIGluc3RhbmNlb2YgUmVnRXhwXG4gICAgICAgICAgICAgICAgPyB0aGlzLl9wYXR0ZXJuTWVzc2FnZVN1YnNjcmliZXJzXG4gICAgICAgICAgICAgICAgOiB0aGlzLl9tZXNzYWdlU3Vic2NyaWJlcnM7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBTZXRzIFtNZXNzYWdlU291cmNlXSguL21fc291cmNlLmpzLmh0bWwpIGZvciB0aGUgbWVzc2VuZ2VyIGFsc28gc2V0dGluZyB0aGUgcmVmZXJlbmNlIHRvIHRoZSBtZXNzZW5nZXIgaW4gdGhlIE1lc3NhZ2VTb3VyY2UuXG4gKiBNZXNzYWdlU291cmNlIGNhbiBiZSBwYXNzZWQgdG8gbWVzc2FnZSBjb25zdHJ1Y3RvcjsgdGhpcyBtZXRob2QgYWxsb3dzIHRvIHNldCBpdCBhdCBhIGxhdGVyIHRpbWUuIEZvciBleGFtcGxlLCB0aGUgc3ViY2xhc3NlcyBvZiBbQ29tcG9uZW50RmFjZXRdKC4uL2NvbXBvbmVudHMvY19mYWNldC5qcy5odG1sKSB1c2UgdGhpcyBtZXRob2QgdG8gc2V0IGRpZmZlcmVudCBNZXNzYWdlU291cmNlJ2VzIGluIHRoZSBtZXNzZW5nZXIgdGhhdCBpcyBjcmVhdGVkIGJ5IENvbXBvbmVudEZhY2V0LlxuICogQ3VycmVudGx5IHRoZSBtZXRob2QgaXMgaW1wbGVtZW50ZWQgaW4gc3VjaCB3YXkgdGhhdCBpdCBjYW4gYmUgY2FsbGVkIG9ubHkgb25jZSAtIE1lc3NhZ2VTb3VyY2UgY2Fubm90IGJlIGNoYW5nZWQgYWZ0ZXIgdGhpcyBtZXRob2QgaXMgY2FsbGVkLlxuICpcbiAqIEBwYXJhbSB7TWVzc2FnZVNvdXJjZX0gbWVzc2FnZVNvdXJjZSBhbiBpbnN0YW5jZSBvZiBNZXNzYWdlU291cmNlIGNsYXNzIHRvIGF0dGFjaCB0byB0aGlzIG1lc3NlbmdlciAoYW5kIHRvIGhhdmUgdGhpcyBtZXNzZW5nZXIgYXR0YWNoZWQgdG8gaXQgdG9vKVxuICovXG5mdW5jdGlvbiBfc2V0TWVzc2FnZVNvdXJjZShtZXNzYWdlU291cmNlKSB7XG4gICAgY2hlY2sobWVzc2FnZVNvdXJjZSwgTWVzc2FnZVNvdXJjZSk7XG5cbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdfbWVzc2FnZVNvdXJjZScsIG1lc3NhZ2VTb3VyY2UpO1xuICAgIG1lc3NhZ2VTb3VyY2UubWVzc2VuZ2VyID0gdGhpcztcbn1cblxuXG4vKipcbiAqIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgbWVzc2VuZ2VyIE1lc3NhZ2VTb3VyY2VcbiAqXG4gKiBAcmV0dXJuIHtNZXNzYWdlU291cmNlfVxuICovXG5mdW5jdGlvbiBnZXRNZXNzYWdlU291cmNlKCkge1xuICAgIHJldHVybiB0aGlzLl9tZXNzYWdlU291cmNlXG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uL3V0aWwvbG9nZ2VyJyk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBNZXNzZW5nZXJBUEk7XG5cblxuLyoqXG4gKiBgbWlsby5jbGFzc2VzLk1lc3NlbmdlckFQSWBcbiAqIEJhc2UgY2xhc3MsIHN1YmNsYXNzZXMgb2Ygd2hpY2ggY2FuIHN1cHBsZW1lbnQgdGhlIGZ1bmN0aW9uYWxpdHkgb2YgW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgYnkgaW1wbGVtZW50aW5nIHRocmVlIG1ldGhvZHM6XG4gKlxuICogLSBgdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlYCB0byB0cmFuc2xhdGUgc291cmNlIG1lc3NhZ2VzIChyZWNpZXZlZCBmcm9tIGV4dGVybmFsIHNvdXJjZSB2aWEgYE1lc3NhZ2VTT3VyY2VgKSB0byBpbnRlcm5hbCBtZXNzYWdlcyAodGhhdCBhcmUgZGlzcGF0Y2hlZCBvbiBNZXNzZW5nZXIpLCBhbGxvd2luZyB0byBtYWtlIGludGVybmFsIG1lc3NhZ2VzIG1vcmUgZGV0YWlsZWQgdGhhbiBzb3VyY2UgbWVzc2FnZXMuIEZvciBleGFtcGxlLCBbRGF0YSBmYWNldF0oLi4vY29tcG9uZW50cy9jX2ZhY2V0cy9EYXRhLmpzLmh0bWwpIHVzZXMgW0RhdGFNc2dBUEldKC4uL2NvbXBvbmVudHMvbXNnX2FwaS9kYXRhLmpzLmh0bWwpIHRvIGRlZmluZSBzZXZlcmFsIGludGVybmFsIG1lc3NhZ2VzIHJlbGF0ZWQgdG8gdGhlIGNoYW5nZSBvZiBzdGF0ZSBpbiBjb250ZW50ZWRpdGFibGUgRE9NIGVsZW1lbnQuXG4gKiAtIGBjcmVhdGVJbnRlcm5hbERhdGFgIHRvIG1vZGlmeSBtZXNzYWdlIGRhdGEgcmVjZWl2ZWQgZnJvbSBzb3VyY2UgdG8gc29tZSBtb3JlIG1lYW5pbmdmdWwgb3IgbW9yZSBkZXRhaWxlZCBtZXNzYWdlIGRhdGEgdGhhdCB3aWxsIGJlIGRpc3BhdGNoZWQgb24gTWVzc2VuZ2VyLiBGb3IgZXhhbXBsZSwgW0RhdGEgZmFjZXRdKC4uL2NvbXBvbmVudHMvY19mYWNldHMvRGF0YS5qcy5odG1sKSB1c2VzIFtEYXRhTXNnQVBJXSguLi9jb21wb25lbnRzL21zZ19hcGkvZGF0YS5qcy5odG1sKSAoc3ViY2xhc3Mgb2YgTWVzc2VuZ2VyQVBJKSB0byB0cmFuc2xhdGUgRE9NIG1lc3NhZ2VzIHRvIGRhdGEgY2hhbmdlIG1lc3NhZ2VzLlxuICogLSBgZmlsdGVyU291cmNlTWVzc2FnZWAgdG8gZW5hYmxlL2Rpc2FibGUgbWVzc2FnZSBkaXNwYXRjaCBiYXNlZCBvbiBzb21lIGNvbmRpdGlvbnMgaW4gZGF0YS5cbiAqXG4gKiBJZiBgTWVzc2FnZVNvdXJjZWAgY29uc3RydWN0b3IgaXMgbm90IHBhc3NlZCBhbiBpbnN0YW5jZSBvZiBzb21lIHN1YmNsYXNzIG9mIGBNZXNzZW5nZXJBUElgLCBpdCBhdXRvbWF0aWNhbGx5IGNyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgTWVzc2VuZ2VyQVBJIHRoYXQgZGVmaW5lcyBhbGwgMyBvZiB0aG9zZSBtZXRob2RzIGluIGEgdHJpdmlhbCB3YXkuIFNlZSB0aGVzZSBtZXRob2RzIGJlbG93IGZvciB0aGVpciBzaWduYXR1cmVzLlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQHRoaXMge01lc3NlbmdlckFQSX1cbiAqIEByZXR1cm4ge01lc3NlbmdlckFQSX1cbiAqL1xuZnVuY3Rpb24gTWVzc2VuZ2VyQVBJKCkge1xuICAgIGlmICh0aGlzLmluaXQpXG4gICAgICAgIHRoaXMuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbi8qKlxuICogIyMjI01lc3NlbmdlckFQSSBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2luaXRdKCNpbml0KSAtIGluaXRpYWxpemVzIE1lc3NlbmdlckFQSVxuICogLSBbYWRkSW50ZXJuYWxNZXNzYWdlXSgjYWRkSW50ZXJuYWxNZXNzYWdlKSAtIGFkZHMgaW50ZXJuYWwgbWVzc2FnZVxuICogLSBbcmVtb3ZlSW50ZXJuYWxNZXNzYWdlXSgjcmVtb3ZlSW50ZXJuYWxNZXNzYWdlKSAtIHJlbW92ZXMgaW50ZXJuYWwgbWVzc2FnZVxuICogLSBbZ2V0SW50ZXJuYWxNZXNzYWdlc10oI2dldEludGVybmFsTWVzc2FnZXMpIC0gcmV0dXJucyB0aGUgbGlzdCBvZiBpbnRlcm5hbCBtZXNzYWdlcyBmb3IgZ2l2ZW4gc291cmNlIG1lc3NhZ2VcbiAqXG4gKiBUaGVzZSBtZXRob2RzIHNob3VsZCBiZSByZWRlZmluZWQgYnkgc3ViY2xhc3M6XG4gKlxuICogLSBbdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlXSgjdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKSAtIGNvbnZlcnRzIGludGVybmFsIG1lc3NhZ2UgdHlwZSB0byBzb3VyY2UgKGV4dGVybmFsKSBtZXNzYWdlIHR5cGVcbiAqIC0gW2NyZWF0ZUludGVybmFsRGF0YV0oI2NyZWF0ZUludGVybmFsRGF0YSkgLSBjb252ZXJ0cyBzb3VyY2UgbWVzc2FnZSBkYXRhIHJlY2VpdmVkIHZpYSBNZXNzYWdlU291cmNlIHRvIGludGVybmFsIG1lc3NhZ2UgZGF0YVxuICogLSBbZmlsdGVyU291cmNlTWVzc2FnZV0oI2ZpbHRlclNvdXJjZU1lc3NhZ2UpIC0gZmlsdGVycyBzb3VyY2UgbWVzc2FnZSBiYXNlZCBvbiB0aGUgZGF0YSBvZiB0aGUgbWVzc2FnZSBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgaW50ZXJuYWwgbWVzc2FnZSB0aGF0IGlzIGFib3V0IHRvIGJlIHNlbnQgb24gTWVzc2VuZ2VyXG4gKi9cbl8uZXh0ZW5kUHJvdG8oTWVzc2VuZ2VyQVBJLCB7XG4gICAgaW5pdDogaW5pdCxcbiAgICBkZXN0cm95OiBNZXNzZW5nZXJBUEkkZGVzdHJveSxcbiAgICBhZGRJbnRlcm5hbE1lc3NhZ2U6IGFkZEludGVybmFsTWVzc2FnZSxcbiAgICByZW1vdmVJbnRlcm5hbE1lc3NhZ2U6IHJlbW92ZUludGVybmFsTWVzc2FnZSxcbiAgICBnZXRJbnRlcm5hbE1lc3NhZ2VzOiBnZXRJbnRlcm5hbE1lc3NhZ2VzLFxuXG4gICAgLy8gc2hvdWxkIGJlIHJlZGVmaW5lZCBieSBzdWJjbGFzc1xuICAgIHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZTogdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlLFxuICAgIGNyZWF0ZUludGVybmFsRGF0YTogY3JlYXRlSW50ZXJuYWxEYXRhLFxuICAgIGZpbHRlclNvdXJjZU1lc3NhZ2U6IGZpbHRlclNvdXJjZU1lc3NhZ2Vcbn0pO1xuXG5cbi8qKlxuICogTWVzc2VuZ2VyQVBJIGluc3RhbmNlIG1ldGhvZFxuICogQ2FsbGVkIGJ5IE1lc3NlbmdlckFQSSBjb25zdHJ1Y3Rvci4gU3ViY2xhc3NlcyB0aGF0IHJlLWltcGxlbWVudCBgaW5pdGAgbWV0aG9kIHNob3VsZCBjYWxsIHRoaXMgbWV0aG9kIHVzaW5nOiBgTWVzc2VuZ2VyQVBJLnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cylgXG4gKi9cbmZ1bmN0aW9uIGluaXQoKSB7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnX2ludGVybmFsTWVzc2FnZXMnLCB7fSk7XG59XG5cblxuLyoqXG4gKiBEZXN0cm95cyBtZXNzZW5nZXIgQVBJXG4gKi9cbmZ1bmN0aW9uIE1lc3NlbmdlckFQSSRkZXN0cm95KCkge1xuXG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXJBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBUcmFuc2xhdGVzIGludGVybmFsIGBtZXNzYWdlYCB0byBzb3VyY2UgbWVzc2FnZSwgYWRkcyBpbnRlcm5hbCBgbWVzc2FnZWAgdG8gdGhlIGxpc3QsIG1ha2luZyBzdXJlIHRoZSBzYW1lIGBtZXNzYWdlYCB3YXNuJ3QgcGFzc2VkIGJlZm9yZSAoaXQgd291bGQgaW5kaWNhdGUgTWVzc2VuZ2VyIGVycm9yKS5cbiAqIFJldHVybnMgc291cmNlIG1lc3NhZ2UgaWYgaXQgaXMgdXNlZCBmaXJzdCB0aW1lIChzbyB0aGF0IGBNZXNzYWdlU291cmNlYCBzdWJjcmliZXMgdG8gdGhpcyBzb3VyY2UgbWVzc2FnZSkgb3IgYHVuZGVmaW5lZGAuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgaW50ZXJuYWwgbWVzc2FnZSB0byBiZSB0cmFuc2xhdGVkIGFuZCBhZGRlZFxuICogQHJldHVybiB7U3RyaW5nfHVuZGVmaW5lZH1cbiAqL1xuZnVuY3Rpb24gYWRkSW50ZXJuYWxNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgICB2YXIgaW50ZXJuYWxNc2dzXG4gICAgICAgICwgc291cmNlTWVzc2FnZSA9IHRoaXMudHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKG1lc3NhZ2UpO1xuXG4gICAgaWYgKHR5cGVvZiBzb3VyY2VNZXNzYWdlID09ICd1bmRlZmluZWQnKSByZXR1cm47XG5cbiAgICBpZiAodGhpcy5faW50ZXJuYWxNZXNzYWdlcy5oYXNPd25Qcm9wZXJ0eShzb3VyY2VNZXNzYWdlKSkge1xuICAgICAgICBpbnRlcm5hbE1zZ3MgPSB0aGlzLl9pbnRlcm5hbE1lc3NhZ2VzW3NvdXJjZU1lc3NhZ2VdO1xuICAgICAgICBpZiAoaW50ZXJuYWxNc2dzLmluZGV4T2YobWVzc2FnZSkgPT0gLTEpXG4gICAgICAgICAgICBpbnRlcm5hbE1zZ3MucHVzaChtZXNzYWdlKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ0R1cGxpY2F0ZSBhZGRJbnRlcm5hbE1lc3NhZ2UgY2FsbCBmb3IgaW50ZXJuYWwgbWVzc2FnZSAnICsgbWVzc2FnZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgaW50ZXJuYWxNc2dzID0gdGhpcy5faW50ZXJuYWxNZXNzYWdlc1tzb3VyY2VNZXNzYWdlXSA9IFtdO1xuICAgICAgICBpbnRlcm5hbE1zZ3MucHVzaChtZXNzYWdlKTtcbiAgICAgICAgcmV0dXJuIHNvdXJjZU1lc3NhZ2U7XG4gICAgfVxufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyQVBJIGluc3RhbmNlIG1ldGhvZFxuICogUmVtb3ZlcyBpbnRlcm5hbCBgbWVzc2FnZWAgZnJvbSB0aGUgbGlzdCBjb25uZWN0ZWQgdG8gY29ycmVzcG9uZGluZyBzb3VyY2UgbWVzc2FnZSAoYHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZWAgaXMgdXNlZCBmb3IgdHJhbnNsYXRpb24pLlxuICogUmV0dXJucyBzb3VyY2UgbWVzc2FnZSwgaWYgdGhlIGxhc3QgaW50ZXJuYWwgbWVzc2FnZSB3YXMgcmVtb3ZlZCAoc28gdGhhdCBgTWVzc2FnZVNvdXJjZWAgY2FuIHVuc3Vic2NyaWJlIGZyb20gdGhpcyBzb3VyY2UgbWVzc2FnZSksIG9yIGB1bmRlZmluZWRgLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGludGVybmFsIG1lc3NhZ2UgdG8gYmUgdHJhbnNsYXRlZCBhbmQgcmVtb3ZlZFxuICogQHJldHVybiB7U3RyaW5nfHVuZGVmaW5lZH1cbiAqL1xuZnVuY3Rpb24gcmVtb3ZlSW50ZXJuYWxNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgICB2YXIgc291cmNlTWVzc2FnZSA9IHRoaXMudHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKG1lc3NhZ2UpO1xuXG4gICAgaWYgKHR5cGVvZiBzb3VyY2VNZXNzYWdlID09ICd1bmRlZmluZWQnKSByZXR1cm47XG5cbiAgICB2YXIgaW50ZXJuYWxNc2dzID0gdGhpcy5faW50ZXJuYWxNZXNzYWdlc1tzb3VyY2VNZXNzYWdlXTtcblxuICAgIGlmIChpbnRlcm5hbE1zZ3MgJiYgaW50ZXJuYWxNc2dzLmxlbmd0aCkge1xuICAgICAgICB2YXIgbWVzc2FnZUluZGV4ID0gaW50ZXJuYWxNc2dzLmluZGV4T2YobWVzc2FnZSk7XG4gICAgICAgIGlmIChtZXNzYWdlSW5kZXggPj0gMCkge1xuICAgICAgICAgICAgaW50ZXJuYWxNc2dzLnNwbGljZShtZXNzYWdlSW5kZXgsIDEpO1xuICAgICAgICAgICAgaWYgKGludGVybmFsTXNncy5sZW5ndGggPT0gMCkge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl9pbnRlcm5hbE1lc3NhZ2VzW3NvdXJjZU1lc3NhZ2VdO1xuICAgICAgICAgICAgICAgIHJldHVybiBzb3VyY2VNZXNzYWdlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2VcbiAgICAgICAgICAgIHVuZXhwZWN0ZWROb3RpZmljYXRpb25XYXJuaW5nKCk7XG4gICAgfSBlbHNlXG4gICAgICAgIHVuZXhwZWN0ZWROb3RpZmljYXRpb25XYXJuaW5nKCk7XG5cblxuICAgIGZ1bmN0aW9uIHVuZXhwZWN0ZWROb3RpZmljYXRpb25XYXJuaW5nKCkge1xuICAgICAgICBsb2dnZXIud2Fybignbm90aWZpY2F0aW9uIHJlY2VpdmVkOiB1bi1zdWJzY3JpYmUgZnJvbSBpbnRlcm5hbCBtZXNzYWdlICcgKyBtZXNzYWdlXG4gICAgICAgICAgICAgICAgICAgICArICcgd2l0aG91dCBwcmV2aW91cyBzdWJzY3JpcHRpb24gbm90aWZpY2F0aW9uJyk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyQVBJIGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyB0aGUgYXJyYXkgb2YgaW50ZXJuYWwgbWVzc2FnZXMgdGhhdCB3ZXJlIHRyYW5zbGF0ZWQgdG8gZ2l2ZW4gYHNvdXJjZU1lc3NhZ2VgLlxuICogVGhpcyBtZXRob2QgaXMgdXNlZCBieSBgTWVzc2FnZVNvdXJjZWAgdG8gZGlzcGF0Y2ggc291cmNlIG1lc3NhZ2Ugb24gdGhlIGBNZXNlbmdlcmAuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHNvdXJjZU1lc3NhZ2Ugc291cmNlIG1lc3NhZ2VcbiAqIEByZXR1cm4ge0FycmF5W1N0cmluZ119XG4gKi9cbmZ1bmN0aW9uIGdldEludGVybmFsTWVzc2FnZXMoc291cmNlTWVzc2FnZSkge1xuICAgIHJldHVybiB0aGlzLl9pbnRlcm5hbE1lc3NhZ2VzW3NvdXJjZU1lc3NhZ2VdO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyQVBJIGluc3RhbmNlIG1ldGhvZFxuICogU3ViY2xhc3NlcyBzaG91bGQgcmUtaW1wbGVtZW50IHRoaXMgbWV0aG9kIHRvIGRlZmluZSB0aGUgcnVsZSBmb3IgdHJhbnNsYXRpb24gb2YgaW50ZXJuYWwgYG1lc3NhZ2VgIHRvIHNvdXJjZSBtZXNzYWdlLiBUaGlzIGNsYXNzIHNpbXBseSByZXR1cm5zIHRoZSBzYW1lIGBtZXNzYWdlYC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBpbnRlcm5hbCBtZXNzYWdlIHRvIGJlIHRyYW5zbGF0ZWRcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgICByZXR1cm4gbWVzc2FnZVxufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyQVBJIGluc3RhbmNlIG1ldGhvZFxuICogU3ViY2xhc3NlcyBzaG91bGQgcmUtaW1wbGVtZW50IHRoaXMgbWV0aG9kIHRvIGRlZmluZSB0aGUgcnVsZSBmb3IgdHJhbnNsYXRpb24gb2Ygc291cmNlIG1lc3NhZ2UgZGF0YSB0byBpbnRlcm5hbCBtZXNzYWdlIGRhdGEuIFRoaXMgY2xhc3Mgc2ltcGx5IHJldHVybnMgdGhlIHNhbWUgYHNvdXJjZURhdGFgLlxuICogVGhpcyBtZXRob2QgaXMgdXNlZCBpbiBbZGlzcGF0Y2hNZXNzYWdlXSguL21fc291cmNlLmpzLmh0bWwjZGlzcGF0Y2hNZXNzYWdlKSBtZXRob2Qgb2YgYE1lc3NhZ2VTb3VyY2VgLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzb3VyY2VNZXNzYWdlIHNvdXJjZSBtZXNzYWdlLCBjYW4gYmUgdXNlZCBpbiB0cmFuc2xhdGlvbiBydWxlXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBpbnRlcm5hbCBtZXNzYWdlLCBjYW4gYmUgdXNlZCBpbiB0cmFuc2xhdGlvbiBydWxlXG4gKiBAcGFyYW0ge09iamVjdH0gc291cmNlRGF0YSBkYXRhIHJlY2VpdmVkIGZyb20gc291cmNlIHRoYXQgaGFzIHRvIGJlIHRyYW5zbGF0ZWQgdG8gZGF0YSB0aGF0IHdpbGwgYmUgc2VudCB0byBpbnRlcm5hbCBNZXNzZW5nZXIgc3Vic2NyaWJlclxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBjcmVhdGVJbnRlcm5hbERhdGEoc291cmNlTWVzc2FnZSwgbWVzc2FnZSwgc291cmNlRGF0YSkge1xuICAgIHJldHVybiBzb3VyY2VEYXRhO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyQVBJIGluc3RhbmNlIG1ldGhvZFxuICogU3ViY2xhc3NlcyBzaG91bGQgcmUtaW1wbGVtZW50IHRoaXMgbWV0aG9kIHRvIGRlZmluZSB0aGUgZGlzcGF0Y2ggZmlsdGVyIGZvciBpbnRlcm5hbCBtZXNzYWdlcy4gVGhpcyBtZXRob2Qgc2hvdWxkIHJldHVybiBgdHJ1ZWAgdG8gYWxsb3cgYW5kIGBmYWxzZWAgdG8gcHJldmVudCBpbnRlcm5hbCBtZXNzYWdlIGRpc3BhdGNoLiBUaGlzIGNsYXNzIGFsd2F5cyByZXR1cm5zIGB0cnVlYC5cbiAqIFRoaXMgbWV0aG9kIGlzIHVzZWQgaW4gW2Rpc3BhdGNoTWVzc2FnZV0oLi9tX3NvdXJjZS5qcy5odG1sI2Rpc3BhdGNoTWVzc2FnZSkgbWV0aG9kIG9mIGBNZXNzYWdlU291cmNlYC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gc291cmNlTWVzc2FnZSBzb3VyY2UgbWVzc2FnZSwgY2FuIGJlIHVzZWQgaW4gZmlsdGVyIHJ1bGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGludGVybmFsIG1lc3NhZ2UsIGNhbiBiZSB1c2VkIGluIGZpbHRlciBydWxlXG4gKiBAcGFyYW0ge09iamVjdH0gaW50ZXJuYWxEYXRhIGRhdGEgdHJhbnNsYXRlZCBieSBgY3JlYXRlSW50ZXJuYWxEYXRhYCBtZXRob2QgZnJvbSBzb3VyY2UgZGF0YSwgY2FuIGJlIHVzZWQgaW4gZmlsdGVyIHJ1bGVcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIGZpbHRlclNvdXJjZU1lc3NhZ2Uoc291cmNlTWVzc2FnZSwgbWVzc2FnZSwgaW50ZXJuYWxEYXRhKSB7XG4gICAgcmV0dXJuIHRydWU7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBNZXNzZW5nZXJBUEkgPSByZXF1aXJlKCcuL21fYXBpJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG4vKipcbiAqIEEgZ2VuZXJpYyBzdWJzY2xhc3Mgb2YgW01lc3NlbmdlckFQSV0oLi9tX2FwaS5qcy5odG1sKSB0aGF0IHN1cHBvcnRzIHBhdHRlcm4gc3Vic2NyaXB0aW9ucyB0byBzb3VyY2UuXG4gKiBDYW4gYmUgdXNlZnVsIGlmIHRoZSBzb3VyY2UgaXMgYW5vdGhlciBNZXNzZW5nZXIuXG4gKi9cbiB2YXIgTWVzc2VuZ2VyUmVnZXhwQVBJID0gXy5jcmVhdGVTdWJjbGFzcyhNZXNzZW5nZXJBUEksICdNZXNzZW5nZXJSZWdleHBBUEknKTtcblxuIG1vZHVsZS5leHBvcnRzID0gTWVzc2VuZ2VyUmVnZXhwQVBJO1xuXG5cbl8uZXh0ZW5kUHJvdG8oTWVzc2VuZ2VyUmVnZXhwQVBJLCB7XG4gICAgaW5pdDogaW5pdCxcbiAgICBhZGRJbnRlcm5hbE1lc3NhZ2U6IGFkZEludGVybmFsTWVzc2FnZSxcbiAgICByZW1vdmVJbnRlcm5hbE1lc3NhZ2U6IHJlbW92ZUludGVybmFsTWVzc2FnZSxcbiAgICBnZXRJbnRlcm5hbE1lc3NhZ2VzOiBnZXRJbnRlcm5hbE1lc3NhZ2VzXG59KTtcblxuXG4vKipcbiAqIE1lc3NlbmdlclJlZ2V4cEFQSSBpbnN0YW5jZSBtZXRob2RcbiAqIENhbGxlZCBieSBNZXNzZW5nZXJSZWdleHBBUEkgY29uc3RydWN0b3IuXG4gKi9cbmZ1bmN0aW9uIGluaXQoKSB7XG4gICAgTWVzc2VuZ2VyQVBJLnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgXy5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIHtcbiAgICAgICAgX3BhdHRlcm5JbnRlcm5hbE1lc3NhZ2VzOiB7fVxuICAgIH0pO1xuICAgIHRoaXMuX2NhdGNoQWxsU3Vic2NyaWJlZCA9IGZhbHNlO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyUmVnZXhwQVBJIGluc3RhbmNlIG1ldGhvZFxuICogQXVnbWVudHMgTWVzc2VuZ2VyQVBJIG1ldGhvZCBieSBzdG9yaW5nIHJlZ2V4cFxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGludGVybmFsIG1lc3NhZ2UgdG8gYmUgdHJhbnNsYXRlZCBhbmQgYWRkZWRcbiAqIEByZXR1cm4ge1N0cmluZ3xSZWdFeHB8dW5kZWZpbmVkfVxuICovXG5mdW5jdGlvbiBhZGRJbnRlcm5hbE1lc3NhZ2UobWVzc2FnZSkge1xuICAgIHZhciBzb3VyY2VNZXNzYWdlID0gTWVzc2VuZ2VyQVBJLnByb3RvdHlwZS5hZGRJbnRlcm5hbE1lc3NhZ2UuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICBcbiAgICAvLyBzdG9yZSByZWdleHAgaXRzZWxmIGlmIHNvdXJjZU1lc3NhZ2UgaXMgcmVnZXhwXG4gICAgaWYgKHNvdXJjZU1lc3NhZ2UgJiYgc291cmNlTWVzc2FnZSBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICB0aGlzLl9pbnRlcm5hbE1lc3NhZ2VzW3NvdXJjZU1lc3NhZ2VdLnBhdHRlcm4gPSBzb3VyY2VNZXNzYWdlO1xuICAgICAgICB0aGlzLl9wYXR0ZXJuSW50ZXJuYWxNZXNzYWdlc1tzb3VyY2VNZXNzYWdlXSA9IHRoaXMuX2ludGVybmFsTWVzc2FnZXNbc291cmNlTWVzc2FnZV07XG4gICAgICAgIGlmICh0aGlzLl9jYXRjaEFsbFN1YnNjcmliZWQpIHJldHVybjtcbiAgICAgICAgICAgIHRoaXMuX2NhdGNoQWxsU3Vic2NyaWJlZCA9IHRydWU7XG4gICAgICAgIHJldHVybiAvLiovO1xuICAgIH1cblxuICAgIHJldHVybiBzb3VyY2VNZXNzYWdlO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyUmVnZXhwQVBJIGluc3RhbmNlIG1ldGhvZFxuICogQXVnbWVudHMgTWVzc2VuZ2VyQVBJIG1ldGhvZCBieSByZW1vdmluZyByZWdleHAgc3Vic2NpcnB0aW9uXG4gKiBcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGludGVybmFsIG1lc3NhZ2UgdG8gYmUgdHJhbnNsYXRlZCBhbmQgYWRkZWRcbiAqIEByZXR1cm4ge1N0cmluZ3xSZWdFeHB8dW5kZWZpbmVkfVxuICovXG5mdW5jdGlvbiByZW1vdmVJbnRlcm5hbE1lc3NhZ2UobWVzc2FnZSkge1xuICAgIHZhciBzb3VyY2VNZXNzYWdlID0gTWVzc2VuZ2VyQVBJLnByb3RvdHlwZS5yZW1vdmVJbnRlcm5hbE1lc3NhZ2UuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIGlmIChzb3VyY2VNZXNzYWdlICYmIHNvdXJjZU1lc3NhZ2UgaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgICAgZGVsZXRlIHRoaXMuX3BhdHRlcm5JbnRlcm5hbE1lc3NhZ2VzW3NvdXJjZU1lc3NhZ2VdO1xuICAgICAgICB2YXIgbm9QYXR0ZXJuSW50ZXJuYWxNZXNzYWdlcyA9ICEgT2JqZWN0LmtleXModGhpcy5fcGF0dGVybkludGVybmFsTWVzc2FnZXMpLmxlbmd0aDtcbiAgICAgICAgaWYgKG5vUGF0dGVybkludGVybmFsTWVzc2FnZXMpIHtcbiAgICAgICAgICAgIHRoaXMuX2NhdGNoQWxsU3Vic2NyaWJlZCA9IGZhbHNlO1xuICAgICAgICAgICAgcmV0dXJuIC8uKi87XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gc291cmNlTWVzc2FnZTtcbn1cblxuXG4vKipcbiAqIE1lc3NlbmdlckFQSSBpbnN0YW5jZSBtZXRob2RcbiAqIEF1Z21lbnRzIE1lc3NlbmdlckFQSSBtZXRob2QgYnkgcmV0dXJuaW5nIG1lc3NhZ2VzIHN1YnNjcmliZWQgd2l0aCByZWdleHBcbiAqIFRoaXMgbWV0aG9kIGlzIHVzZWQgYnkgYE1lc3NhZ2VTb3VyY2VgIHRvIGRpc3BhdGNoIHNvdXJjZSBtZXNzYWdlIG9uIHRoZSBgTWVzZW5nZXJgLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gc291cmNlTWVzc2FnZSBzb3VyY2UgbWVzc2FnZVxuICogQHJldHVybiB7QXJyYXlbU3RyaW5nXX1cbiAqL1xuZnVuY3Rpb24gZ2V0SW50ZXJuYWxNZXNzYWdlcyhzb3VyY2VNZXNzYWdlKSB7XG4gICAgdmFyIGludGVybmFsTWVzc2FnZXMgPSBNZXNzZW5nZXJBUEkucHJvdG90eXBlLmdldEludGVybmFsTWVzc2FnZXMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIC8vIGFkZCBpbnRlcm5hbCBtZXNzYWdlcyBmb3IgcmVnZXhwIHNvdXJjZSBzdWJzY3JpcHRpb25zXG4gICAgaWYgKHR5cGVvZiBzb3VyY2VNZXNzYWdlID09ICdzdHJpbmcnKSB7XG4gICAgICAgIGludGVybmFsTWVzc2FnZXMgPSBpbnRlcm5hbE1lc3NhZ2VzIHx8IFtdO1xuICAgICAgICB2YXIgaW50ZXJuYWxNZXNzYWdlc0hhc2ggPSBfLm9iamVjdChpbnRlcm5hbE1lc3NhZ2VzLCB0cnVlKTtcblxuICAgICAgICBfLmVhY2hLZXkodGhpcy5fcGF0dGVybkludGVybmFsTWVzc2FnZXMsIGZ1bmN0aW9uKHBhdHRlcm5NZXNzYWdlcykge1xuICAgICAgICAgICAgdmFyIHNvdXJjZVBhdHRlcm4gPSBwYXR0ZXJuTWVzc2FnZXMucGF0dGVybjtcblxuICAgICAgICAgICAgaWYgKHNvdXJjZVBhdHRlcm4udGVzdChzb3VyY2VNZXNzYWdlKSlcbiAgICAgICAgICAgICAgICBwYXR0ZXJuTWVzc2FnZXMuZm9yRWFjaChmdW5jdGlvbihtZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpbnRlcm5hbE1lc3NhZ2VzSGFzaFttZXNzYWdlXSkgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICBpbnRlcm5hbE1lc3NhZ2VzLnB1c2gobWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgICAgIGludGVybmFsTWVzc2FnZXNIYXNoW21lc3NhZ2VdID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfSBcblxuICAgIHJldHVybiBpbnRlcm5hbE1lc3NhZ2VzO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgTWl4aW4gPSByZXF1aXJlKCcuLi9hYnN0cmFjdC9taXhpbicpXG4gICAgLCBNZXNzZW5nZXJBUEkgPSByZXF1aXJlKCcuL21fYXBpJylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uL3V0aWwvbG9nZ2VyJylcbiAgICAsIHRvQmVJbXBsZW1lbnRlZCA9IHJlcXVpcmUoJy4uL3V0aWwvZXJyb3InKS50b0JlSW1wbGVtZW50ZWRcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgY2hlY2sgPSByZXF1aXJlKCcuLi91dGlsL2NoZWNrJylcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2g7XG5cblxuLyoqXG4gKiBgbWlsby5jbGFzc2VzLk1lc3NhZ2VTb3VyY2VgXG4gKiBBbiBhYnN0cmFjdCBjbGFzcyAoc3ViY2xhc3Mgb2YgW01peGluXSguLi9hYnN0cmFjdC9taXhpbi5qcy5odG1sKSkgZm9yIGNvbm5lY3RpbmcgW01lc3Nlbmdlcl0oLi9pbmRleC5qcy5odG1sKSB0byBleHRlcm5hbCBzb3VyY2VzIG9mIG1lc3NhZ2VzIChsaWtlIERPTSBldmVudHMpIGFuZCBkZWZpbmluZyBoaWdoZXIgbGV2ZWwgbWVzc2FnZXMuXG4gKiBBbiBpbnN0YW5jZSBvZiBNZXNzYWdlU291cmNlIGNhbiBlaXRoZXIgYmUgcGFzc2VkIHRvIE1lc3NlbmdlciBjb25zdHJ1Y3RvciBvciBsYXRlciB1c2luZyBgX3NldE1lc3NhZ2VTb3VyY2VgIG1ldGhvZCBvZiBNZXNzZW5nZXIuIE9uY2Ugc2V0LCBNZXNzYWdlU291cmNlIG9mIE1lc3NlbmdlciBjYW5ub3QgYmUgY2hhbmdlZC5cbiAqL1xudmFyIE1lc3NhZ2VTb3VyY2UgPSBfLmNyZWF0ZVN1YmNsYXNzKE1peGluLCAnTWVzc2FnZVNvdXJjZScsIHRydWUpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1lc3NhZ2VTb3VyY2U7XG5cblxuLyoqXG4gKiAjIyMjTWVzc2FnZVNvdXJjZSBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2luaXRdKCNpbml0KSAtIGluaXRpYWxpemVzIG1lc3NhZ2VTb3VyY2UgLSBjYWxsZWQgYnkgTWl4aW4gc3VwZXJjbGFzc1xuICogLSBbc2V0TWVzc2VuZ2VyXSgjc2V0TWVzc2VuZ2VyKSAtIGNvbm5lY3RzIE1lc3NlbmdlciB0byBNZXNzYWdlU291cmNlLCBpcyBjYWxsZWQgZnJvbSBgaW5pdGAgb3IgYF9zZXRNZXNzYWdlU291cmNlYCBtZXRob2RzIG9mIFtNZXNzZW5nZXJdKC4vaW5kZXguanMuaHRtbCkuXG4gKiAtIFtvblN1YnNjcmliZXJBZGRlZF0oI29uU3Vic2NyaWJlckFkZGVkKSAtIGNhbGxlZCBieSBNZXNzZW5nZXIgdG8gbm90aWZ5IHdoZW4gdGhlIGZpcnN0IHN1YnNjcmliZXIgZm9yIGFuIGludGVybmFsIG1lc3NhZ2Ugd2FzIGFkZGVkLCBzbyBNZXNzYWdlU291cmNlIGNhbiBzdWJzY3JpYmUgdG8gc291cmNlXG4gKiAtIFtvblN1YnNjcmliZXJSZW1vdmVkXSgjb25TdWJzY3JpYmVyUmVtb3ZlZCkgLSBjYWxsZWQgYnkgTWVzc2VuZ2VyIHRvIG5vdGlmeSB3aGVuIHRoZSBsYXN0IHN1YnNjcmliZXIgZm9yIGFuIGludGVybmFsIG1lc3NhZ2Ugd2FzIHJlbW92ZWQsIHNvIE1lc3NhZ2VTb3VyY2UgY2FuIHVuc3Vic2NyaWJlIGZyb20gc291cmNlXG4gKiAtIFtkaXNwYXRjaE1lc3NhZ2VdKCNkaXNwYXRjaE1lc3NhZ2UpIC0gZGlzcGF0Y2hlcyBzb3VyY2UgbWVzc2FnZS4gTWVzc2FnZVNvdXJjZSBzdWJjbGFzcyBzaG91bGQgaW1wbGVtZW50IG1lY2hhbmlzbSB3aGVuIG9uIGFjdHVhbCBzb3VyY2UgbWVzc2FnZSB0aGlzIG1ldGhvZCBpcyBjYWxsZWQuXG4gKlxuICogTWV0aG9kcyBiZWxvdyBzaG91bGQgYmUgaW1wbGVtZW50ZWQgaW4gc3ViY2xhc3M6XG4gKlxuICogLSBbdHJpZ2dlcl0oI3RyaWdnZXIpIC0gdHJpZ2dlcnMgbWVzc2FnZXMgb24gdGhlIHNvdXJjZSAoYW4gb3B0aW9uYWwgbWV0aG9kKVxuICogLSBbYWRkU291cmNlU3Vic2NyaWJlcl0oI2FkZFNvdXJjZVN1YnNjcmliZXIpIC0gYWRkcyBsaXN0ZW5lci9zdWJzY3JpYmVyIHRvIGV4dGVybmFsIG1lc3NhZ2VcbiAqIC0gW3JlbW92ZVNvdXJjZVN1YnNjcmliZXJdKCNyZW1vdmVTb3VyY2VTdWJzY3JpYmVyKSAtIHJlbW92ZXMgbGlzdGVuZXIvc3Vic2NyaWJlciBmcm9tIGV4dGVybmFsIG1lc3NhZ2VcbiAqL1xuXy5leHRlbmRQcm90byhNZXNzYWdlU291cmNlLCB7XG4gICAgaW5pdDogaW5pdCxcbiAgICBkZXN0cm95OiBNZXNzYWdlU291cmNlJGRlc3Ryb3ksXG4gICAgc2V0TWVzc2VuZ2VyOiBzZXRNZXNzZW5nZXIsXG4gICAgb25TdWJzY3JpYmVyQWRkZWQ6IG9uU3Vic2NyaWJlckFkZGVkLFxuICAgIG9uU3Vic2NyaWJlclJlbW92ZWQ6IG9uU3Vic2NyaWJlclJlbW92ZWQsIFxuICAgIGRpc3BhdGNoTWVzc2FnZTogZGlzcGF0Y2hNZXNzYWdlLFxuICAgIHBvc3RNZXNzYWdlOiBwb3N0TWVzc2FnZSxcbiAgICBfcHJlcGFyZU1lc3NlbmdlckFQSTogX3ByZXBhcmVNZXNzZW5nZXJBUEksXG5cbiAgICAvLyBNZXRob2RzIGJlbG93IG11c3QgYmUgaW1wbGVtZW50ZWQgaW4gc3ViY2xhc3NcbiAgICB0cmlnZ2VyOiB0b0JlSW1wbGVtZW50ZWQsXG4gICAgYWRkU291cmNlU3Vic2NyaWJlcjogdG9CZUltcGxlbWVudGVkLFxuICAgIHJlbW92ZVNvdXJjZVN1YnNjcmliZXI6IHRvQmVJbXBsZW1lbnRlZFxufSk7XG5cblxuLyoqXG4gKiBNZXNzYWdlU291cmNlIGluc3RhbmNlIG1ldGhvZC5cbiAqIENhbGxlZCBieSBNaXhpbiBjb25zdHJ1Y3Rvci5cbiAqIE1lc3NhZ2VTb3VyY2UgY29uc3RydWN0b3Igc2hvdWxkIGJlIHBhc3NlZCB0aGUgc2FtZSBwYXJhbWV0ZXJzIGFzIHRoaXMgbWV0aG9kIHNpZ25hdHVyZS5cbiAqIElmIGFuIGluc3RhbmNlIG9mIFtNZXNzZW5nZXJBUEldKC4vbV9hcGkuanMuaHRtbCkgaXMgcGFzc2VkIGFzIHRoZSB0aGlyZCBwYXJhbWV0ZXIsIGl0IGV4dGVuZHMgTWVzc2FnZVNvdXJjZSBmdW5jdGlvbmFsaXR5IHRvIGFsbG93IGl0IHRvIGRlZmluZSBuZXcgbWVzc2FnZXMsIHRvIGZpbHRlciBtZXNzYWdlcyBiYXNlZCBvbiB0aGVpciBkYXRhIGFuZCB0byBjaGFuZ2UgbWVzc2FnZSBkYXRhLiBTZWUgW01lc3NlbmdlckFQSV0oLi9tX2FwaS5qcy5odG1sKS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBPcHRpb25hbCBvYmplY3QgdGhhdCBzdG9yZXMgdGhlIE1lc3NhZ2VTb3VyY2Ugb24gb25lIG9mIGl0cyBwcm9wZXJ0aWVzLiBJdCBpcyB1c2VkIHRvIHByb3h5IG1ldGhvZHMgb2YgTWVzc2FnZVNvdXJjZS5cbiAqIEBwYXJhbSB7T2JqZWN0W1N0cmluZ119IHByb3h5TWV0aG9kcyBPcHRpb25hbCBtYXAgb2YgbWV0aG9kIG5hbWVzOyBrZXkgLSBwcm94eSBtZXRob2QgbmFtZSwgdmFsdWUgLSBNZXNzYWdlU291cmNlJ3MgbWV0aG9kIG5hbWUuXG4gKiBAcGFyYW0ge01lc3NlbmdlckFQSX0gbWVzc2VuZ2VyQVBJIE9wdGlvbmFsIGluc3RhbmNlIG9mIE1lc3NlbmdlckFQSS5cbiAqL1xuZnVuY3Rpb24gaW5pdChob3N0T2JqZWN0LCBwcm94eU1ldGhvZHMsIG1lc3NlbmdlckFQSSkge1xuICAgIHRoaXMuX3ByZXBhcmVNZXNzZW5nZXJBUEkobWVzc2VuZ2VyQVBJKTtcbn1cblxuXG4vKipcbiAqIERlc3Ryb3lzIG1lc3NhZ2Ugc291cmNlXG4gKi9cbmZ1bmN0aW9uIE1lc3NhZ2VTb3VyY2UkZGVzdHJveSgpIHtcbiAgICBpZiAodGhpcy5tZXNzZW5nZXJBUEkpXG4gICAgICAgIHRoaXMubWVzc2VuZ2VyQVBJLmRlc3Ryb3koKTtcbn1cblxuXG4vKipcbiAqIE1lc3NhZ2VTb3VyY2UgaW5zdGFuY2UgbWV0aG9kLlxuICogU2V0cyByZWZlcmVuY2UgdG8gTWVzc2VuZ2VyIGluc3RhbmNlLlxuICpcbiAqIEBwYXJhbSB7TWVzc2VuZ2VyfSBtZXNzZW5nZXIgcmVmZXJlbmNlIHRvIE1lc3NlbmdlciBpbnN0YW5jZSBsaW5rZWQgdG8gdGhpcyBNZXNzYWdlU291cmNlXG4gKi9cbmZ1bmN0aW9uIHNldE1lc3NlbmdlcihtZXNzZW5nZXIpIHtcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdtZXNzZW5nZXInLCBtZXNzZW5nZXIpO1xufVxuXG5cbi8qKlxuICogTWVzc2FnZVNvdXJjZSBpbnN0YW5jZSBtZXRob2QuXG4gKiBQcmVwYXJlcyBbTWVzc2VuZ2VyQVBJXSguL21fYXBpLmpzLmh0bWwpIHBhc3NlZCB0byBjb25zdHJ1Y3RvciBieSBwcm94eWluZyBpdHMgbWV0aG9kcyB0byBpdHNlbGYgb3IgaWYgTWVzc2VuZ2VyQVBJIHdhc24ndCBwYXNzZWQgZGVmaW5lcyB0d28gbWV0aG9kcyB0byBhdm9pZCBjaGVja2luZyB0aGVpciBhdmFpbGFiaWxpdHkgZXZlcnkgdGltZSB0aGUgbWVzc2FnZSBpcyBkaXNwYXRjaGVkLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge01lc3NlbmdlckFQSX0gbWVzc2VuZ2VyQVBJIE9wdGlvbmFsIGluc3RhbmNlIG9mIE1lc3NlbmdlckFQSVxuICovXG5mdW5jdGlvbiBfcHJlcGFyZU1lc3NlbmdlckFQSShtZXNzZW5nZXJBUEkpIHtcbiAgICBjaGVjayhtZXNzZW5nZXJBUEksIE1hdGNoLk9wdGlvbmFsKE1lc3NlbmdlckFQSSkpO1xuXG4gICAgaWYgKCEgbWVzc2VuZ2VyQVBJKVxuICAgICAgICBtZXNzZW5nZXJBUEkgPSBuZXcgTWVzc2VuZ2VyQVBJO1xuXG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnbWVzc2VuZ2VyQVBJJywgbWVzc2VuZ2VyQVBJKTtcbn1cblxuXG4vKipcbiAqIE1lc3NhZ2VTb3VyY2UgaW5zdGFuY2UgbWV0aG9kLlxuICogU3Vic2NyaWJlcyB0byBleHRlcm5hbCBzb3VyY2UgdXNpbmcgYGFkZFNvdXJjZVN1YnNjcmliZXJgIG1ldGhvZCB0aGF0IHNob3VsZCBiZSBpbXBsZW1lbnRlZCBpbiBzdWJjbGFzcy5cbiAqIFRoaXMgbWV0aG9kIGlzIGNhbGxlZCBieSBbTWVzc2VuZ2VyXSguL2luZGV4LmpzLmh0bWwpIHdoZW4gdGhlIGZpcnN0IHN1YnNjcmliZXIgdG8gdGhlIGBtZXNzYWdlYCBpcyBhZGRlZC5cbiAqIERlbGVnYXRlcyB0byBzdXBwbGllZCBvciBkZWZhdWx0IFtNZXNzZW5nZXJBUEldKC4vbV9hcGkuanMuaHRtbCkgZm9yIHRyYW5zbGF0aW9uIG9mIGBtZXNzYWdlYCB0byBgc291cmNlTWVzc2FnZWAuIGBNZXNzYWdlQVBJLnByb3RvdHlwZS5hZGRJbnRlcm5hbE1lc3NhZ2VgIHdpbGwgcmV0dXJuIHVuZGVmaW5lZCBpZiB0aGlzIGBzb3VyY2VNZXNzYWdlYCB3YXMgYWxyZWFkeSBzdWJzY3JpYmVkIHRvIHRvIHByZXZlbnQgZHVwbGljYXRlIHN1YnNjcmlwdGlvbi5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBpbnRlcm5hbCBNZXNzZW5nZXIgbWVzc2FnZSB0aGF0IGhhcyB0byBiZSBzdWJzY3JpYmVkIHRvIGF0IHRoZSBleHRlcm5hbCBzb3VyY2Ugb2YgbWVzc2FnZXMuXG4gKi9cbmZ1bmN0aW9uIG9uU3Vic2NyaWJlckFkZGVkKG1lc3NhZ2UpIHtcbiAgICB2YXIgbmV3U291cmNlTWVzc2FnZSA9IHRoaXMubWVzc2VuZ2VyQVBJLmFkZEludGVybmFsTWVzc2FnZShtZXNzYWdlKTtcbiAgICBpZiAodHlwZW9mIG5ld1NvdXJjZU1lc3NhZ2UgIT0gJ3VuZGVmaW5lZCcpXG4gICAgICAgIHRoaXMuYWRkU291cmNlU3Vic2NyaWJlcihuZXdTb3VyY2VNZXNzYWdlKTtcbn1cblxuXG4vKipcbiAqIE1lc3NhZ2VTb3VyY2UgaW5zdGFuY2UgbWV0aG9kLlxuICogVW5zdWJzY3JpYmVzIGZyb20gZXh0ZXJuYWwgc291cmNlIHVzaW5nIGByZW1vdmVTb3VyY2VTdWJzY3JpYmVyYCBtZXRob2QgdGhhdCBzaG91bGQgYmUgaW1wbGVtZW50ZWQgaW4gc3ViY2xhc3MuXG4gKiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgYnkgW01lc3Nlbmdlcl0oLi9pbmRleC5qcy5odG1sKSB3aGVuIHRoZSBsYXN0IHN1YnNjcmliZXIgdG8gdGhlIGBtZXNzYWdlYCBpcyByZW1vdmVkLlxuICogRGVsZWdhdGVzIHRvIHN1cHBsaWVkIG9yIGRlZmF1bHQgW01lc3NlbmdlckFQSV0oLi9tX2FwaS5qcy5odG1sKSBmb3IgdHJhbnNsYXRpb24gb2YgYG1lc3NhZ2VgIHRvIGBzb3VyY2VNZXNzYWdlYC4gYE1lc3NhZ2VBUEkucHJvdG90eXBlLnJlbW92ZUludGVybmFsTWVzc2FnZWAgd2lsbCByZXR1cm4gdW5kZWZpbmVkIGlmIHRoaXMgYHNvdXJjZU1lc3NhZ2VgIHdhcyBub3QgeWV0IHN1YnNjcmliZWQgdG8gdG8gcHJldmVudCB1bnN1YnNjcmlwdGlvbiB3aXRob3V0IHByZXZpb3VzIHN1YnNjcmlwdGlvbi5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBpbnRlcm5hbCBNZXNzZW5nZXIgbWVzc2FnZSB0aGF0IGhhcyB0byBiZSB1bnN1YnNjcmliZWQgZnJvbSBhdCB0aGUgZXh0ZXJuYWwgc291cmNlIG9mIG1lc3NhZ2VzLlxuICovXG5mdW5jdGlvbiBvblN1YnNjcmliZXJSZW1vdmVkKG1lc3NhZ2UpIHtcbiAgICB2YXIgcmVtb3ZlZFNvdXJjZU1lc3NhZ2UgPSB0aGlzLm1lc3NlbmdlckFQSS5yZW1vdmVJbnRlcm5hbE1lc3NhZ2UobWVzc2FnZSk7XG4gICAgaWYgKHR5cGVvZiByZW1vdmVkU291cmNlTWVzc2FnZSAhPSAndW5kZWZpbmVkJylcbiAgICAgICAgdGhpcy5yZW1vdmVTb3VyY2VTdWJzY3JpYmVyKHJlbW92ZWRTb3VyY2VNZXNzYWdlKTtcbn1cblxuXG4vKipcbiAqIE1lc3NhZ2VTb3VyY2UgaW5zdGFuY2UgbWV0aG9kLlxuICogRGlzcGF0Y2hlcyBzb3VyY2VNZXNzYWdlIHRvIE1lc3Nlbmdlci5cbiAqIE1lY2hhbmlzbSB0aGF0IGNhbGxzIHRoaXMgbWV0aG9kIHdoZW4gdGhlIHNvdXJjZSBtZXNzYWdlIGlzIHJlY2VpdmVkIHNob3VsZCBiZSBpbXBsZW1lbnRlZCBieSBzdWJjbGFzcyAoc2VlIFtET01FdmVudHNTb3VyY2VdKC4uL2NvbXBvbmVudHMvbXNnX3NyYy9kb21fZXZlbnRzLmpzLmh0bWwpIGZvciBleGFtcGxlKS5cbiAqIERlbGVnYXRlcyB0byBzdXBwbGllZCBvciBkZWZhdWx0IFtNZXNzZW5nZXJBUEldKC4vbV9hcGkuanMuaHRtbCkgdG8gY3JlYXRlIGludGVybmFsIG1lc3NhZ2UgZGF0YSAoYGNyZWF0ZUludGVybmFsRGF0YWApIGFuZCB0byBmaWx0ZXIgdGhlIG1lc3NhZ2UgYmFzZWQgb24gaXRzIGRhdGEgYW5kL29yIG1lc3NhZ2UgKGBmaWx0ZXJTb3VyY2VNZXNzYWdlYCkuXG4gKiBCYXNlIE1lc3NlbmdlckFQSSBjbGFzcyBpbXBsZW1lbnRzIHRoZXNlIHR3byBtZXRob2RzIGluIGEgdHJpdmlhbCB3YXkgKGBjcmVhdGVJbnRlcm5hbERhdGFgIHNpbXBseSByZXR1cm5zIGV4dGVybmFsIGRhdGEsIGBmaWx0ZXJTb3VyY2VNZXNzYWdlYCByZXR1cm5zIGB0cnVlYCksIHRoZXkgYXJlIG1lYW50IHRvIGJlIGltcGxlbWVudGVkIGJ5IHN1YmNsYXNzLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzb3VyY2VNZXNzYWdlIHNvdXJjZSBtZXNzYWdlIHJlY2VpdmVkIGZyb20gZXh0ZXJuYWwgc291cmNlXG4gKiBAcGFyYW0ge09iamVjdH0gc291cmNlRGF0YSBkYXRhIHJlY2VpdmVkIGZyb20gZXh0ZXJuYWwgc291cmNlXG4gKi9cbmZ1bmN0aW9uIGRpc3BhdGNoTWVzc2FnZShzb3VyY2VNZXNzYWdlLCBzb3VyY2VEYXRhKSB7XG4gICAgdmFyIGFwaSA9IHRoaXMubWVzc2VuZ2VyQVBJXG4gICAgICAgICwgaW50ZXJuYWxNZXNzYWdlcyA9IGFwaS5nZXRJbnRlcm5hbE1lc3NhZ2VzKHNvdXJjZU1lc3NhZ2UpO1xuXG4gICAgaWYgKGludGVybmFsTWVzc2FnZXMpIFxuICAgICAgICBpbnRlcm5hbE1lc3NhZ2VzLmZvckVhY2goZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgICAgIHZhciBpbnRlcm5hbERhdGEgPSBhcGkuY3JlYXRlSW50ZXJuYWxEYXRhKHNvdXJjZU1lc3NhZ2UsIG1lc3NhZ2UsIHNvdXJjZURhdGEpO1xuXG4gICAgICAgICAgICB2YXIgc2hvdWxkRGlzcGF0Y2ggPSBhcGkuZmlsdGVyU291cmNlTWVzc2FnZShzb3VyY2VNZXNzYWdlLCBtZXNzYWdlLCBpbnRlcm5hbERhdGEpO1xuICAgICAgICAgICAgaWYgKHNob3VsZERpc3BhdGNoKSBcbiAgICAgICAgICAgICAgICB0aGlzLnBvc3RNZXNzYWdlKG1lc3NhZ2UsIGludGVybmFsRGF0YSk7ICAgICAgXG4gICAgICAgICAgICBcbiAgICAgICAgfSwgdGhpcyk7XG59XG5cblxuLyoqXG4gKiBQb3N0cyBtZXNzYWdlIG9uIHRoZSBtZXNzZW5nZXIuIFRoaXMgbWV0aG9kIGlzIHNlcGFyYXRlZCBzbyBzcGVjaWZpYyBtZXNzYWdlIHNvdXJjZXMgY2FuIG1ha2UgbWVzc2FnZSBkaXNwYXRjaCBzeW5jaHJvbm91cyBieSB1c2luZyBgcG9zdE1lc3NhZ2VTeW5jYFxuICogXG4gKiBAcGFyYW0gIHtTdHJpbmd9IG1lc3NhZ2VcbiAqIEBwYXJhbSAge09iamVjdH0gZGF0YVxuICovXG5mdW5jdGlvbiBwb3N0TWVzc2FnZShtZXNzYWdlLCBkYXRhKSB7XG4gICAgdGhpcy5tZXNzZW5nZXIucG9zdE1lc3NhZ2UobWVzc2FnZSwgZGF0YSk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIE1lc3NhZ2VTb3VyY2UgPSByZXF1aXJlKCcuL21fc291cmNlJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgY2hlY2sgPSByZXF1aXJlKCcuLi91dGlsL2NoZWNrJyk7XG5cblxuLyoqXG4gKiBTdWJjbGFzcyBvZiBNZXNzYWdlU291cmNlIHRoYXQgYWxsb3dzIHRvIGNvbm5lY3QgTWVzc2VuZ2VyIHRvIGFub3RoZXIgTWVzc2VuZ2VyIHVzaW5nIGl0IGFzIGV4dGVybmFsIHNvdXJjZS5cbiAqL1xudmFyIE1lc3Nlbmdlck1lc3NhZ2VTb3VyY2UgPSBfLmNyZWF0ZVN1YmNsYXNzKE1lc3NhZ2VTb3VyY2UsICdNZXNzZW5nZXJNZXNzYWdlU291cmNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gTWVzc2VuZ2VyTWVzc2FnZVNvdXJjZTtcblxuXG4vKipcbiAqICMjIyNNZXNzZW5nZXJNZXNzYWdlU291cmNlIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKi9cbl8uZXh0ZW5kUHJvdG8oTWVzc2VuZ2VyTWVzc2FnZVNvdXJjZSwge1xuICAgIGluaXQ6IGluaXQsXG4gICAgYWRkU291cmNlU3Vic2NyaWJlcjogYWRkU291cmNlU3Vic2NyaWJlcixcbiAgICByZW1vdmVTb3VyY2VTdWJzY3JpYmVyOiByZW1vdmVTb3VyY2VTdWJzY3JpYmVyLFxuICAgIHBvc3RNZXNzYWdlOiBNZXNzZW5nZXJNZXNzYWdlU291cmNlJHBvc3RNZXNzYWdlXG59KTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyBNZXNzZW5nZXJNZXNzYWdlU291cmNlXG4gKiBEZWZpbmVzIG9uZSBwYXJhbWV0ZXIgaW4gYWRkaXRpb24gdG8gW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgcGFyYW1ldGVyc1xuICpcbiAqIEBwYXJhbSB7TWVzc2VuZ2VyfSBzb3VyY2VNZXNzZW5nZXIgbWVzc2VuZ2VyIHRoaXMgbWVzc2FnZSBzb3VyY2UgY29ubmVjdHMgdG9cbiAqL1xuZnVuY3Rpb24gaW5pdChob3N0T2JqZWN0LCBwcm94eU1ldGhvZHMsIG1lc3NlbmdlckFQSSwgc291cmNlTWVzc2VuZ2VyKSB7XG4gICAgTWVzc2FnZVNvdXJjZS5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMuc291cmNlTWVzc2VuZ2VyID0gc291cmNlTWVzc2VuZ2VyO1xufVxuXG5cbi8qKlxuICogU3Vic2NyaWJlcyB0byBzb3VyY2UgbWVzc2FnZS4gU2VlIFtNZXNzYWdlU291cmNlXSguL21fc291cmNlLmpzLmh0bWwpIGRvY3MuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8UmVnZXh9IHNvdXJjZU1lc3NhZ2Ugc291cmNlIG1lc3NhZ2UgdG8gc3Vic2NyaWJlIHRvXG4gKi9cbmZ1bmN0aW9uIGFkZFNvdXJjZVN1YnNjcmliZXIoc291cmNlTWVzc2FnZSkge1xuICAgIHRoaXMuc291cmNlTWVzc2VuZ2VyLm9uU3luYyhzb3VyY2VNZXNzYWdlLCB7IGNvbnRleHQ6IHRoaXMsIHN1YnNjcmliZXI6IHRoaXMuZGlzcGF0Y2hNZXNzYWdlIH0pO1xufVxuXG5cbi8qKlxuICogVW5zdWJzY3JpYmVzIGZyb20gc291cmNlIG1lc3NhZ2UuIFNlZSBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBkb2NzLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ2V4fSBzb3VyY2VNZXNzYWdlIHNvdXJjZSBtZXNzYWdlIHRvIHVuc3Vic2NyaWJlIGZyb21cbiAqL1xuZnVuY3Rpb24gcmVtb3ZlU291cmNlU3Vic2NyaWJlcihzb3VyY2VNZXNzYWdlKSB7XG4gICAgdGhpcy5zb3VyY2VNZXNzZW5nZXIub2ZmKHNvdXJjZU1lc3NhZ2UsIHsgY29udGV4dDogdGhpcywgc3Vic2NyaWJlcjogdGhpcy5kaXNwYXRjaE1lc3NhZ2UgfSk7XG59XG5cblxuLyoqXG4gKiBPdmVycmlkZXMgZGVmYWx1dCBtZXNzYWdlIHNvdXJjZSB0byBkaXNwYXRjaCBtZXNzYWdlcyBzeW5jaHJvbm91c2x5XG4gKiBcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICovXG5mdW5jdGlvbiBNZXNzZW5nZXJNZXNzYWdlU291cmNlJHBvc3RNZXNzYWdlKG1lc3NhZ2UsIGRhdGEpIHtcbiAgICB0aGlzLm1lc3Nlbmdlci5wb3N0TWVzc2FnZVN5bmMobWVzc2FnZSwgZGF0YSk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjb3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJyk7XG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbi8vIHJlZ2lzdGVyIGluY2x1ZGVkIGZhY2V0c1xucmVxdWlyZSgnLi91c2VfZmFjZXRzJyk7XG5cbi8vIHJlZ2lzdGVyIGluY2x1ZGVkIGNvbXBvbmVudHNcbnJlcXVpcmUoJy4vdXNlX2NvbXBvbmVudHMnKTtcblxuXG4vKipcbiAqIGBtaWxvYFxuICpcbiAqIEEgbWluaW1hbGlzdCBicm93c2VyIGZyYW1ld29yayB0aGF0IGJpbmRzIERPTSBlbGVtZW50cyB0byBKUyBjb21wb25lbnRzIGFuZCBjb21wb25lbnRzIHRvIG1vZGVscy5cbiAqXG4gKiBgbWlsb2AgaXMgYXZhaWxhYmxlIGFzIGdsb2JhbCBvYmplY3QgaW4gdGhlIGJyb3dzZXIuXG4gKiBBdCB0aGUgbW9tZW50IGl0IGlzIG5vdCBwb3NzaWlibGUgdG8gcmVxdWlyZSBpdCB3aXRoIGJyb3dzZXJpZnkgdG8gaGF2ZSBpdCBidW5kbGVkIHdpdGggdGhlIGFwcCBiZWNhdXNlIG9mIHRoZSB3YXkgW2JyZnNdKGh0dHBzOi8vZ2l0aHViLmNvbS9zdWJzdGFjay9icmZzKSBicm93c2VyaWZ5IHBsdWdpbiBpcyBpbXBsZW1lbnRlZC5cbiAqIEl0IGlzIHBvc3NpYmxlIHRob3VnaCB0byByZXF1aXJlIGBtaWxvYCB3aXRoIG5vZGUgdG8gdXNlIHVuaXZlcnNhbCBwYXJ0cyBvZiB0aGUgZnJhbWV3b3JrIChhYnN0cmFjdCBjbGFzc2VzLCBNZXNzZW5nZXIsIE1vZGVsLCBldGMuKTpcbiAqIGBgYFxuICogdmFyIG1pbG8gPSByZXF1aXJlKCdtb2wtbWlsbycpO1xuICogYGBgXG4gKiBcbiAqIGBtaWxvYCBpdHNlbGYgaXMgYSBmdW5jdGlvbiB0aGF0IGluIHRoZSBicm93c2VyIGNhbiBiZSB1c2VkIHRvIGRlbGF5IGV4ZWN1dGlvbiB1bnRpbCBET00gaXMgcmVhZHkuXG4gKi9cbmZ1bmN0aW9uIG1pbG8oZnVuYykge1xuICAgIG1pbG8udXRpbC5kb21SZWFkeShmdW5jKTtcbn1cblxuXG4vKipcbiAqICMjIyNNaWxvIHBhY2thZ2VzIyMjI1xuICpcbiAqIC0gW2xvYWRlcl0oLi9sb2FkZXIuanMuaHRtbCkgLSBsb2FkaW5nIHN1YnZpZXdzIGludG8gcGFnZVxuICogLSBbYmluZGVyXSguL2JpbmRlci5qcy5odG1sKSAtIGNvbXBvbmVudHMgaW5zdGFudGlhdGlvbiBhbmQgYmluZGluZyBvZiBET00gZWxlbWVudHMgdG8gdGhlbVxuICogLSBbbWluZGVyXSguL21pbmRlci5qcy5odG1sKSAtIGRhdGEgcmVhY3Rpdml0eSwgb25lIG9yIHR3byB3YXksIHNoYWxsb3cgb3IgZGVlcCwgYXMgeW91IGxpa2UgaXRcbiAqIC0gW21haWxdKC4vbWFpbC9pbmRleC5qcy5odG1sKSAtIGFwcGxpY2FpdG9uIGxldmVsIG1lc3NlbmdlciwgYWxzbyBjb25uZWN0cyB0byBtZXNzYWdlcyBmcm9tIG90aGVyIHdpbmRvd3MgZGlzcGF0Y2hlZCB3aXRoIGB3aW5kb3cucG9zdE1lc3NhZ2VgLlxuICogLSBbY29uZmlnXSguL2NvbmZpZy5qcy5odG1sKSAtIG1pbG8gY29uZmlndXJhdGlvblxuICogLSBbdXRpbF0oLi91dGlsL2luZGV4LmpzLmh0bWwpIC0gbG9nZ2VyLCByZXF1ZXN0LCBkb20sIGNoZWNrLCBlcnJvciwgZXRjLlxuICogLSBbY2xhc3Nlc10oLi9jbGFzc2VzLmpzLmh0bWwpIC0gYWJzdHJhY3QgYW5kIGJhc2UgY2xhc3Nlc1xuICogLSBbYXR0cmlidXRlc10oLi9hdHRyaWJ1dGVzL2luZGV4LmpzLmh0bWwpIC0gY2xhc3NlcyB0aGF0IHdyYXAgRE9NIGVsZW1lbnRzIGF0dHJpYnV0ZXMgcmVjb2duaXplZCBieSBtaWxvXG4gKiAtIFtDb21wb25lbnRGYWNldF0oLi9jb21wb25lbnRzL2NfZmFjZXQuanMuaHRtbCkgLSBiYXNlIGNsYXNzIG9mIENvbXBvbmVudCBmYWNldFxuICogLSBbQ29tcG9uZW50XSguL2NvbXBvbmVudHMvY19jbGFzcy5qcy5odG1sKSAtIGJhc2UgQ29tcG9uZW50IGNsYXNzXG4gKiAtIFtNZXNzZW5nZXJdKC4vbWVzc2VuZ2VyL2luZGV4LmpzLmh0bWwpIC0gZ2VuZXJpYyBNZXNzZW5nZXIgdXNlZCBpbiBtb3N0IG90aGVyIG1pbG8gY2xhc3NlcywgY2FuIGJlIG1peGVkIGludG8gYXBwIGNsYXNzZXMgdG9vLlxuICogLSBbTW9kZWxdKC4vbW9kZWwvaW5kZXguanMuaHRtbCkgLSBNb2RlbCBjbGFzcyB0aGF0IGVtaXRzIG1lc3NhZ2VzIG9uIGNoYW5nZXMgdG8gYW55IGRlcHRoIHdpdGhvdXQgdGltZXIgYmFzZWQgd2F0Y2hpbmdcbiAqIC0gW3JlZ2lzdHJ5XSguL3JlZ2lzdHJ5LmpzLmh0bWwpIC0gcmVnaXN0cmllcyBvZiBmYXNldHMgYW5kIGNvbXBvbmVudHMgY2xhc3Nlc1xuICovXG5fLmV4dGVuZChtaWxvLCB7XG4gICAgTWVzc2VuZ2VyOiBjb3JlLk1lc3NlbmdlcixcbiAgICBNb2RlbDogY29yZS5Nb2RlbCxcbiAgICBtaW5kZXI6IGNvcmUubWluZGVyLFxuICAgIGxvYWRlcjogcmVxdWlyZSgnLi9sb2FkZXInKSxcbiAgICBiaW5kZXI6IHJlcXVpcmUoJy4vYmluZGVyJyksXG4gICAgbWFpbDogcmVxdWlyZSgnLi9zZXJ2aWNlcy9tYWlsJyksXG4gICAgd2luZG93OiByZXF1aXJlKCcuL3NlcnZpY2VzL3dpbmRvdycpLFxuICAgIGNvbmZpZzogcmVxdWlyZSgnLi9jb25maWcnKSxcbiAgICB1dGlsOiByZXF1aXJlKCcuL3V0aWwnKSxcbiAgICBjbGFzc2VzOiByZXF1aXJlKCcuL2NsYXNzZXMnKSxcbiAgICBhdHRyaWJ1dGVzOiByZXF1aXJlKCcuL2F0dHJpYnV0ZXMnKSxcbiAgICBDb21wb25lbnRGYWNldDogcmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXQnKSxcbiAgICBDb21wb25lbnQ6IHJlcXVpcmUoJy4vY29tcG9uZW50cy9jX2NsYXNzJyksXG4gICAgQ29tbWFuZDogcmVxdWlyZSgnLi9jb21tYW5kJyksXG4gICAgcmVnaXN0cnk6IHJlcXVpcmUoJy4vcmVnaXN0cnknKSxcbiAgICBtaWxvX3ZlcnNpb246ICcwLjEuNCcsXG4gICAgY3JlYXRlQ29tcG9uZW50Q2xhc3M6IHJlcXVpcmUoJy4vdXRpbC9jcmVhdGVfY29tcG9uZW50X2NsYXNzJyksXG4gICAgZGVzdHJveTogZGVzdHJveVxufSk7XG5cblxuLy8gZXhwb3J0IGZvciBub2RlL2Jyb3dzZXJpZnlcbmlmICh0eXBlb2YgbW9kdWxlID09ICdvYmplY3QnICYmIG1vZHVsZS5leHBvcnRzKSAgICBcbiAgICBtb2R1bGUuZXhwb3J0cyA9IG1pbG87XG5cbi8vIGdsb2JhbCBtaWxvIGZvciBicm93c2VyXG5pZiAodHlwZW9mIHdpbmRvdyA9PSAnb2JqZWN0Jykge1xuICAgIHdpbmRvdy5taWxvID0gbWlsbztcbiAgICBtaWxvLm1haWwudHJpZ2dlcignbWlsb3JlYWR5Jyk7XG59XG5cblxuZnVuY3Rpb24gZGVzdHJveSgpIHtcbiAgICBtaWxvLm1haWwuZGVzdHJveSgpO1xuICAgIG1pbG8ud2luZG93LmRlc3Ryb3koKTtcbiAgICBtaWxvLm1pbmRlci5kZXN0cm95KCk7XG4gICAgbWlsby51dGlsLmRlc3Ryb3koKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jb21wb25lbnRzL2NfZmFjZXRzL2NmX3JlZ2lzdHJ5JylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uL3V0aWwvbG9nZ2VyJylcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4uL2NvbmZpZycpXG4gICAgLCBwYXRoVXRpbHMgPSByZXF1aXJlKCcuL3BhdGhfdXRpbHMnKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG4vKipcbiAqIFV0aWxpdHkgZnVuY3Rpb24gdG8gcHJvY2VzcyBcImNoYW5nZWRhdGFcIiBtZXNzYWdlcyBlbWl0dGVkIGJ5IENvbm5lY3RvciBvYmplY3QuXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gY2hhbmdlRGF0YUhhbmRsZXI7XG5cblxuXy5leHRlbmQoY2hhbmdlRGF0YUhhbmRsZXIsIHtcbiAgICBzZXRUcmFuc2FjdGlvbkZsYWc6IHNldFRyYW5zYWN0aW9uRmxhZyxcbiAgICBnZXRUcmFuc2FjdGlvbkZsYWc6IGdldFRyYW5zYWN0aW9uRmxhZyxcbiAgICBwYXNzVHJhbnNhY3Rpb25GbGFnOiBwYXNzVHJhbnNhY3Rpb25GbGFnLFxuICAgIHBvc3RUcmFuc2FjdGlvbkZpbmlzaGVkOiBwb3N0VHJhbnNhY3Rpb25GaW5pc2hlZFxufSk7XG5cblxuLyoqXG4gKiBDaGFuZ2UgZGF0YSB1c2VzIGhpZGRlbiBwcm9wZXJ0eSBvbiBhY2Nlc3NvciBtZXRob2RzIHRvIHBhc3MgZmxhZyB0aGF0IHRoZSBhY2Nlc3NvciBpcyBleGVjdXRlZCBhcyBhIHBhcnQgb2YgY2hhbmdlIHRyYW5zYWN0aW9uLlxuICogQWNjZXNzb3IgbWV0aG9kcyBhcmUgc3VwcG9zZWQgdG8gc3RvcmUgdGhpcyBmbGFnIGluIGEgbG9jYWwgdmFyaWFibGUgYW5kIHRvIGNsZWFyIGl0IChiZWNhdXNlIGFub3RoZXIgYWNjZXNzb3IgY2FuIGJlIGV4ZWN1dGVkIGluIG9yIG91dCBvZiB0cmFuc2FjdGlvbikgdXNpbmcgYGdldFRyYW5zYWN0aW9uRmxhZ2BcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBhY2Nlc3NvciBtZXRob2QgcmVmZXJlbmNlXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGZsYWcgYSBmbGFnIHRvIGJlIHNldFxuICovXG5mdW5jdGlvbiBzZXRUcmFuc2FjdGlvbkZsYWcoZnVuYywgZmxhZykge1xuICAgIF8uZGVmaW5lUHJvcGVydHkoZnVuYywgJ19faW5DaGFuZ2VUcmFuc2FjdGlvbicsIGZsYWcsIF8uQ09ORiB8IF8uV1JJVCk7XG59XG5cblxuLyoqXG4gKiBSZXRyaWV2ZXMgYW5kIGNsZWFycyB0cmFuc2FjdGlvbiBmbGFnIGZyb20gYWNjZXNzb3IgbWV0aG9kXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgYWNjZXNzb3IgbWV0aG9kIHJlZmVyZW5jZVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25GbGFnKGZ1bmMpIHtcbiAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGZ1bmMuX19pbkNoYW5nZVRyYW5zYWN0aW9uO1xuICAgIGRlbGV0ZSBmdW5jLl9faW5DaGFuZ2VUcmFuc2FjdGlvbjtcbiAgICByZXR1cm4gaW5UcmFuc2FjdGlvbjtcbn1cblxuXG5mdW5jdGlvbiBwYXNzVHJhbnNhY3Rpb25GbGFnKGZyb21GdW5jLCB0b0Z1bmMpIHtcbiAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGdldFRyYW5zYWN0aW9uRmxhZyhmcm9tRnVuYyk7XG4gICAgc2V0VHJhbnNhY3Rpb25GbGFnKHRvRnVuYywgaW5UcmFuc2FjdGlvbik7XG4gICAgcmV0dXJuIGluVHJhbnNhY3Rpb247XG59XG5cblxuLyoqXG4gKiBQb3N0cyBtZXNzYWdlIG9uIHRoaXMgdG8gaW5kaWNhdGUgdGhlIGVuZCBvZiB0cmFuc2FjdGlvbiB1bmxlc3MgYGluQ2hhbmdlVHJhbnNhY3Rpb25gIGlzIGB0cnVlYC5cbiAqL1xuZnVuY3Rpb24gcG9zdFRyYW5zYWN0aW9uRmluaXNoZWQoKSB7XG4gICAgdGhpcy5wb3N0TWVzc2FnZVN5bmMoJ2RhdGFjaGFuZ2VzJywgeyB0cmFuc2FjdGlvbjogZmFsc2UsIGNoYW5nZXM6IFtdIH0pO1xufVxuXG5cbi8qKlxuICogc3Vic2NyaWJlciB0byBcImNoYW5nZWRhdGFcIiBldmVudCBlbWl0dGVkIGJ5IFtDb25uZWN0b3JdKC4vY29ubmVjdG9yLmpzLmh0bWwpIG9iamVjdCB0byBlbmFibGUgcmVhY3RpdmUgY29ubmVjdGlvbnNcbiAqIFVzZWQgYnkgRGF0YSBmYWNldCwgTW9kZWwgYW5kIE1vZGVsUGF0aC4gQ2FuIGJlIHVzZWQgYnkgYW55IG9iamVjdCB0aGF0IGltcGxlbWVudHMgZ2V0L3NldC9kZWwvc3BsaWNlIGFwaSBhbmQgc2V0cyBkYXRhIGRlZXBseSB0byB0aGUgd2hvbGUgdHJlZS5cbiAqIE9iamVjdCBzaG91bGQgY2FsbCBgY2hhbmdlRGF0YUhhbmRsZXIuaW5pdGlhbGl6ZS5jYWxsKHRoaXMpYCBpbiBpdHMgY29uc3RydWN0b3IuXG4gKiBUT0RPOiBvcHRpbWl6ZSBtZXNzYWdlcyBsaXN0IHRvIGF2b2lkIHNldHRpbmcgZHVwbGljYXRlIHZhbHVlcyBkb3duIHRoZSB0cmVlXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1zZyBzaG91bGQgYmUgXCJjaGFuZ2VkYXRhXCIgaGVyZVxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgYmF0Y2ggb2YgZGF0YSBjaGFuZ2UgZGVzY2lwdGlvbiBvYmplY3RzXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBjYWxsYmFjayB0byBjYWxsIGJlZm9yZSBhbmQgYWZ0ZXIgdGhlIGRhdGEgaXMgcHJvY2Vzc2VkXG4gKi9cbmZ1bmN0aW9uIGNoYW5nZURhdGFIYW5kbGVyKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrKSB7XG4gICAgcHJvY2Vzc0NoYW5nZXMuY2FsbCh0aGlzLCBkYXRhLmNoYW5nZXMsIGNhbGxiYWNrKTtcbn1cblxuXG4vLyBtYXAgb2YgbWVzc2FnZSB0eXBlcyB0byBtZXRob2RzXG52YXIgQ0hBTkdFX1RZUEVfVE9fTUVUSE9EX01BUCA9IHtcbiAgICAnYWRkZWQnOiAgICdzZXQnLFxuICAgICdjaGFuZ2VkJzogJ3NldCcsXG4gICAgJ2RlbGV0ZWQnOiAnZGVsJyxcbiAgICAncmVtb3ZlZCc6ICdkZWwnXG59O1xuXG5cbi8qKlxuICogUHJvY2Vzc2VzIHF1ZXVlZCBcImNoYW5nZWRhdGFcIiBtZXNzYWdlcy5cbiAqIFBvc3RzIFwiY2hhbmdlc3RhcnRlZFwiIGFuZCBcImNoYW5nZWNvbXBsZXRlZFwiIG1lc3NhZ2VzIGFuZCBjYWxscyBjYWxsYmFja1xuICpcbiAqIEBwYXJhbSB7W0Z1bmN0aW9uXX0gY2FsbGJhY2sgb3B0aW9uYWwgY2FsbGJhY2sgdGhhdCBpcyBjYWxsZWQgd2l0aCBgKG51bGwsIGZhbHNlKWAgcGFyYW1ldGVycyBiZWZvcmUgY2hhbmdlIHByb2Nlc3Npbmcgc3RhcnRzIGFuZCBgKG51bGwsIHRydWUpYCBhZnRlciBpdCdzIGZpbmlzaGVkLlxuICovXG5mdW5jdGlvbiBwcm9jZXNzQ2hhbmdlcyh0cmFuc2FjdGlvbiwgY2FsbGJhY2spIHtcbiAgICBub3RpZnkuY2FsbCh0aGlzLCBjYWxsYmFjaywgZmFsc2UpO1xuICAgIHByb2Nlc3NUcmFuc2FjdGlvbi5jYWxsKHRoaXMsXG4gICAgICAgIHByZXBhcmVUcmFuc2FjdGlvbihcbiAgICAgICAgICAgIHZhbGlkYXRlVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pKSk7XG4gICAgbm90aWZ5LmNhbGwodGhpcywgY2FsbGJhY2ssIHRydWUpO1xufVxuXG5cbmZ1bmN0aW9uIG5vdGlmeShjYWxsYmFjaywgY2hhbmdlRmluaXNoZWQpIHtcbiAgICBjYWxsYmFjayAmJiBjYWxsYmFjayhudWxsLCBjaGFuZ2VGaW5pc2hlZCk7XG4gICAgdGhpcy5wb3N0TWVzc2FnZShjaGFuZ2VGaW5pc2hlZCA/ICdjaGFuZ2Vjb21wbGV0ZWQnIDogJ2NoYW5nZXN0YXJ0ZWQnKTtcbn1cblxuXG4vKipcbiAqIENoZWNrcyB0aGF0IGFsbCBtZXNzYWdlcyBmcm9tIHRoZSB0cmFuc2FjdGlvbiBjb21lIGZyb20gdGhlIHNhbWUgc291cmNlLlxuICogSGFjazogcmV2ZXJzZXMgdGhlIHRyYW5zYWN0aW9uIGlmIGl0IGNvbWVzIGZyb20gdGhlIERhdGEgZmFjZXRcbiAqIFJldHVybnMgdGhlIHJlZmVyZW5jZSB0byB0aGUgdHJhbnNhY3Rpb24gKGZvciBjaGFpbmluZylcbiAqIFxuICogQHBhcmFtICB7QXJyYXl9IHRyYW5zYWN0aW9uIHRyYW5zYWN0aW9uIG9mIGRhdGEgY2hhbmdlc1xuICogQHJldHVybiB7QXJyYXl9IFxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZVRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKSB7XG4gICAgdmFyIHNvdXJjZSA9IHRyYW5zYWN0aW9uWzBdLnNvdXJjZVxuICAgICAgICAsIHNhbWVTb3VyY2UgPSB0cnVlO1xuXG4gICAgaWYgKHRyYW5zYWN0aW9uLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDEsIGxlbiA9IHRyYW5zYWN0aW9uLmxlbmd0aDsgaSA8IGxlbjsgaSsrKVxuICAgICAgICAgICAgaWYgKHRyYW5zYWN0aW9uW2ldLnNvdXJjZSAhPSBzb3VyY2UpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ2NoYW5nZWRhdGE6IGNoYW5nZXMgZnJvbSBkaWZmZXJlbnQgc291cmNlcyBpbiB0aGUgc2FtZSB0cmFuc2FjdGlvbiwgc291cmNlczonLCB0cmFuc2FjdGlvbltpXS5zb3VyY2UubmFtZSwgc291cmNlLm5hbWUpO1xuICAgICAgICAgICAgICAgIHNhbWVTb3VyY2UgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBzb3VyY2UgPSB0cmFuc2FjdGlvbltpXS5zb3VyY2U7XG4gICAgICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRyYW5zYWN0aW9uO1xufVxuXG5cbmZ1bmN0aW9uIHByZXBhcmVUcmFuc2FjdGlvbih0cmFuc2FjdGlvbikge1xuICAgIHZhciB0b2RvID0gW11cbiAgICAgICAgLCBwYXRoc1RvU3BsaWNlID0gW11cbiAgICAgICAgLCBwYXRoc1RvQ2hhbmdlID0gW11cbiAgICAgICAgLCBoYWRTcGxpY2VcbiAgICAgICAgLCBleGl0TG9vcCA9IHt9O1xuXG5cbiAgICB0cnkgeyB0cmFuc2FjdGlvbi5mb3JFYWNoKGNoZWNrQ2hhbmdlKTsgfVxuICAgIGNhdGNoIChlKSB7IGlmIChlICE9IGV4aXRMb29wKSB0aHJvdyBlOyB9XG5cbiAgICByZXR1cm4gdG9kbztcblxuXG4gICAgZnVuY3Rpb24gY2hlY2tDaGFuZ2UoZGF0YSkge1xuICAgICAgICAoZGF0YS50eXBlID09ICdzcGxpY2UnID8gY2hlY2tTcGxpY2UgOiBjaGVja01ldGhvZCkoZGF0YSk7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBjaGVja1NwbGljZShkYXRhKSB7XG4gICAgICAgIHZhciBwYXJzZWRQYXRoID0gcGF0aFV0aWxzLnBhcnNlQWNjZXNzUGF0aChkYXRhLnBhdGgpO1xuICAgICAgICB2YXIgcGFyZW50UGF0aENoYW5nZWQgPSBwYXRoc1RvQ2hhbmdlLnNvbWUoZnVuY3Rpb24ocGFyZW50UGF0aCkge1xuICAgICAgICAgICAgaWYgKHBhcnNlZFBhdGgubGVuZ3RoIDwgcGFyZW50UGF0aC5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgICAgIHJldHVybiBfcGF0aElzUGFyZW50T2YocGFyZW50UGF0aCwgcGFyc2VkUGF0aCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChwYXJlbnRQYXRoQ2hhbmdlZCkgcmV0dXJuO1xuXG4gICAgICAgIHRvZG8ucHVzaChkYXRhKTtcblxuICAgICAgICBpZiAoISBjb25maWcuZGVidWcpIHRocm93IGV4aXRMb29wO1xuICAgICAgICBwYXRoc1RvU3BsaWNlLnB1c2gocGFyc2VkUGF0aCk7XG4gICAgICAgIGhhZFNwbGljZSA9IHRydWU7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBjaGVja01ldGhvZChkYXRhKSB7XG4gICAgICAgIHZhciBwYXJzZWRQYXRoID0gcGF0aFV0aWxzLnBhcnNlQWNjZXNzUGF0aChkYXRhLnBhdGgpO1xuICAgICAgICB2YXIgcGFyZW50UGF0aFNwbGljZWQgPSBwYXRoc1RvU3BsaWNlICYmIHBhdGhzVG9TcGxpY2Uuc29tZShmdW5jdGlvbihwYXJlbnRQYXRoKSB7XG4gICAgICAgICAgICBpZiAocGFyc2VkUGF0aC5sZW5ndGggPD0gcGFyZW50UGF0aC5sZW5ndGhcbiAgICAgICAgICAgICAgICB8fCBwYXJzZWRQYXRoW3BhcmVudFBhdGgubGVuZ3RoXS5zeW50YXggIT0gJ2FycmF5JykgcmV0dXJuO1xuICAgICAgICAgICAgcmV0dXJuIF9wYXRoSXNQYXJlbnRPZihwYXJlbnRQYXRoLCBwYXJzZWRQYXRoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHBhcmVudFBhdGhTcGxpY2VkKSByZXR1cm47XG4gICAgICAgIGlmIChoYWRTcGxpY2UpIGxvZ2dlci5lcnJvcignY2hhbmdlZGF0YTogY2hpbGQgY2hhbmdlIGlzIGV4ZWN1dGVkIGFmdGVyIHNwbGljZTsgcHJvYmFibHkgZGF0YSBzb3VyY2UgZGlkIG5vdCBlbWl0IG1lc3NhZ2Ugd2l0aCBkYXRhLnR5cGU9PVwiZmluaXNoZWRcIicpO1xuXG4gICAgICAgIHZhciBwYXJlbnRQYXRoQ2hhbmdlZCA9IHBhdGhzVG9DaGFuZ2Uuc29tZShmdW5jdGlvbihwYXJlbnRQYXRoKSB7XG4gICAgICAgICAgICBpZiAocGFyc2VkUGF0aC5sZW5ndGggPD0gcGFyZW50UGF0aC5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgICAgIHJldHVybiBfcGF0aElzUGFyZW50T2YocGFyZW50UGF0aCwgcGFyc2VkUGF0aCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChwYXJlbnRQYXRoQ2hhbmdlZCkgcmV0dXJuO1xuXG4gICAgICAgIHBhdGhzVG9DaGFuZ2UucHVzaChwYXJzZWRQYXRoKTtcblxuICAgICAgICB0b2RvLnB1c2goZGF0YSk7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBfcGF0aElzUGFyZW50T2YocGFyZW50UGF0aCwgY2hpbGRQYXRoKSB7XG4gICAgICAgIHJldHVybiBwYXJlbnRQYXRoLmV2ZXJ5KGZ1bmN0aW9uKHBhdGhOb2RlLCBpbmRleCkge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGhOb2RlLnByb3BlcnR5ID09IGNoaWxkUGF0aFtpbmRleF0ucHJvcGVydHk7XG4gICAgICAgIH0pO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBwcm9jZXNzVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pIHtcbiAgICB0cmFuc2FjdGlvbi5mb3JFYWNoKHByb2Nlc3NDaGFuZ2UsIHRoaXMpO1xuICAgIHBvc3RUcmFuc2FjdGlvbkZpbmlzaGVkLmNhbGwodGhpcywgZmFsc2UpO1xuXG4gICAgZnVuY3Rpb24gcHJvY2Vzc0NoYW5nZShkYXRhKSB7XG4gICAgICAgIHZhciBtb2RlbFBhdGggPSB0aGlzLnBhdGgoZGF0YS5wYXRoLCBkYXRhLnR5cGUgIT0gJ3JlbW92ZWQnICYmIGRhdGEudHlwZSAhPSAnZGVsZXRlZCcpO1xuICAgICAgICBpZiAoISBtb2RlbFBhdGgpIHJldHVybjtcbiAgICAgICAgKGRhdGEudHlwZSA9PSAnc3BsaWNlJyA/IGV4ZWN1dGVTcGxpY2UgOiBleGVjdXRlTWV0aG9kKShtb2RlbFBhdGgsIGRhdGEpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBleGVjdXRlU3BsaWNlKG1vZGVsUGF0aCwgZGF0YSkge1xuICAgIHZhciBpbmRleCA9IGRhdGEuaW5kZXhcbiAgICAgICAgLCBob3dNYW55ID0gZGF0YS5yZW1vdmVkLmxlbmd0aFxuICAgICAgICAsIHNwbGljZUFyZ3MgPSBbaW5kZXgsIGhvd01hbnldO1xuXG4gICAgc3BsaWNlQXJncyA9IHNwbGljZUFyZ3MuY29uY2F0KGRhdGEubmV3VmFsdWUuc2xpY2UoaW5kZXgsIGluZGV4ICsgZGF0YS5hZGRlZENvdW50KSk7XG4gICAgc2V0VHJhbnNhY3Rpb25GbGFnKG1vZGVsUGF0aC5zcGxpY2UsIHRydWUpO1xuICAgIG1vZGVsUGF0aC5zcGxpY2UuYXBwbHkobW9kZWxQYXRoLCBzcGxpY2VBcmdzKTtcbn1cblxuXG5mdW5jdGlvbiBleGVjdXRlTWV0aG9kKG1vZGVsUGF0aCwgZGF0YSkge1xuICAgIHZhciBtZXRob2ROYW1lID0gQ0hBTkdFX1RZUEVfVE9fTUVUSE9EX01BUFtkYXRhLnR5cGVdO1xuICAgIGlmIChtZXRob2ROYW1lKSB7XG4gICAgICAgIHNldFRyYW5zYWN0aW9uRmxhZyhtb2RlbFBhdGhbbWV0aG9kTmFtZV0sIHRydWUpO1xuICAgICAgICBtb2RlbFBhdGhbbWV0aG9kTmFtZV0oZGF0YS5uZXdWYWx1ZSk7XG4gICAgfSBlbHNlXG4gICAgICAgIGxvZ2dlci5lcnJvcigndW5rbm93biBkYXRhIGNoYW5nZSB0eXBlJyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBNb2RlbFBhdGggPSByZXF1aXJlKCcuL21fcGF0aCcpXG4gICAgLCBzeW50aGVzaXplID0gcmVxdWlyZSgnLi9zeW50aGVzaXplJylcbiAgICAsIHBhdGhVdGlscyA9IHJlcXVpcmUoJy4vcGF0aF91dGlscycpXG4gICAgLCBjaGFuZ2VEYXRhSGFuZGxlciA9IHJlcXVpcmUoJy4vY2hhbmdlX2RhdGEnKVxuICAgICwgTWVzc2VuZ2VyID0gcmVxdWlyZSgnLi4vbWVzc2VuZ2VyJylcbiAgICAsIE1lc3Nlbmdlck1lc3NhZ2VTb3VyY2UgPSByZXF1aXJlKCcuLi9tZXNzZW5nZXIvbXNuZ3Jfc291cmNlJylcbiAgICAsIE1vZGVsTXNnQVBJID0gcmVxdWlyZSgnLi9tX21zZ19hcGknKVxuICAgICwgTW9kZWxFcnJvciA9IHJlcXVpcmUoJy4uL3V0aWwvZXJyb3InKS5Nb2RlbFxuICAgICwgTWl4aW4gPSByZXF1aXJlKCcuLi9hYnN0cmFjdC9taXhpbicpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBsb2dnZXIgPSByZXF1aXJlKCcuLi91dGlsL2xvZ2dlcicpXG4gICAgLCBqc29uUGFyc2UgPSByZXF1aXJlKCcuLi91dGlsL2pzb25fcGFyc2UnKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1vZGVsO1xuXG5cbi8qKlxuICogYG1pbG8uTW9kZWxgXG4gKiBNb2RlbCBjbGFzcyBpbnN0YW50aWF0ZXMgb2JqZWN0cyB0aGF0IGFsbG93IGRlZXAgZGF0YSBhY2Nlc3Mgd2l0aCBfX3NhZmUgZ2V0dGVyc19fIHRoYXQgcmV0dXJuIHVuZGVmaW5lZCAocmF0aGVyIHRoYW4gdGhyb3dpbmcgZXhjZXB0aW9uKSB3aGVuIHByb3BlcnRpZXMvaXRlbXMgb2YgdW5leGlzdGluZyBvYmplY3RzL2FycmF5cyBhcmUgcmVxdWVzdGVkIGFuZCBfX3NhZmUgc2V0dGVyc19fIHRoYXQgY3JlYXRlIG9iamVjdCB0cmVlcyB3aGVuIHByb3BlcnRpZXMvaXRlbXMgb2YgdW5leGlzdGluZyBvYmplY3RzL2FycmF5cyBhcmUgc2V0IGFuZCBhbHNvIHBvc3QgbWVzc2FnZXMgdG8gYWxsb3cgc3Vic2NyaXB0aW9uIG9uIGNoYW5nZXMgYW5kIGVuYWJsZSBkYXRhIHJlYWN0aXZpdHkuXG4gKiBSZWFjdGl2aXR5IGlzIGltcGxlbWVtbnRlZCB2aWEgW0Nvbm5lY3Rvcl0oLi9jb25uZWN0b3IuanMuaHRtbCkgdGhhdCBjYW4gYmUgaW5zdGFudGlhdGVkIGVpdGhlciBkaXJlY3RseSBvciB3aXRoIG1vcmUgY29udmVuaWVudCBpbnRlcmZhY2Ugb2YgW21pbG8ubWluZGVyXSguLi9taW5kZXIuanMuaHRtbCkuIEF0IHRoZSBtb21lbnQgbW9kZWwgY2FuIGJlIGNvbm5lY3RlZCB0byBbRGF0YSBmYWNldF0oLi4vY29tcG9uZW50cy9jX2ZhY2V0cy9EYXRhLmpzLmh0bWwpIG9yIHRvIGFub3RoZXIgbW9kZWwgb3IgW01vZGVsUGF0aF0oLi9tX3BhdGguanMuaHRtbCkuXG4gKiBNb2RlbCBjb25zdHJ1Y3RvciByZXR1cm5zIG9iamVjdHMgdGhhdCBhcmUgZnVuY3Rpb25zIGF0IHRoZSBzYW1lIHRpbWU7IHdoZW4gY2FsbGVkIHRoZXkgcmV0dXJuIE1vZGVsUGF0aCBvYmplY3RzIHRoYXQgYWxsb3cgZ2V0L3NldCBhY2Nlc3MgdG8gYW55IHBvaW50IGluIG1vZGVsIGRhdGEuIFNlZSBbTW9kZWxEYXRhXSgjTW9kZWxEYXRhKSBiZWxvdy5cbiAqXG4gKiBZb3UgY2FuIHN1YnNjcmliZSB0byBtb2RlbCBjaGFuZ2VzIHdpdGggYG9uYCBtZXRob2QgYnkgcGFzc2luZyBtb2RlbCBhY2Nlc3MgcGF0aCBpbiBwbGFjZSBvZiBtZXNzYWdlLCBwYXR0ZXJuIG9yIHN0cmluZyB3aXRoIGFueSBudW1iZXIgb2Ygc3RhcnMgdG8gc3Vic2NyaWJlIHRvIGEgY2VydGFpbiBkZXB0aCBpbiBtb2RlbCAoZS5nLiwgYCcqKionYCB0byBzdWJzY3JpYmUgdG8gdGhyZWUgbGV2ZWxzKS5cbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBkYXRhIG9wdGlvbmFsIGluaXRpYWwgYXJyYXkgZGF0YS4gSWYgaXQgaXMgcGxhbm5lZCB0byBjb25uZWN0IG1vZGVsIHRvIHZpZXcgaXQgaXMgdXN1YWxseSBiZXR0ZXIgdG8gaW5zdGFudGlhdGUgYW4gZW1wdHkgTW9kZWwgKGB2YXIgbSA9IG5ldyBNb2RlbGApLCBjb25uZWN0IGl0IHRvIFtDb21wb25lbnRdKC4uL2NvbXBvbmVudHMvY19jbGFzcy5qcy5odG1sKSdzIFtEYXRhIGZhY2V0XSguLi9jb21wb25lbnRzL2NfZmFjZXRzL0RhdGEuanMuaHRtbCkgKGUuZy4sIGBtaWxvLm1pbmRlcihtLCAnPDwtPj4nLCBjLmRhdGEpO2ApIGFuZCB0aGVuIHNldCB0aGUgbW9kZWwgd2l0aCBgbS5zZXQoZGF0YSlgIC0gdGhlIHZpZXcgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQuXG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBvcHRpb25hbCBvYmplY3QgdGhhdCBob3N0cyBtb2RlbCBvbiBvbmUgb2YgaXRzIHByb3BlcnRpZXMuIENhbiBiZSB1c2VkIHdoZW4gbW9kZWwgaXRzZWxmIGlzIHRoZSBjb250ZXh0IG9mIHRoZSBtZXNzYWdlIHN1YnNjcmliZXIgYW5kIHlvdSBuZWVkIHRvIHRyYXZlcnMgdG8gdGhpcyBvYmplY3QgKGFsdGhvdWdoIGl0IGlzIHBvc3NpYmxlIHRvIHNldCBhbnkgY29udGV4dCkuIENhbiBhbHNvIGJlIHVzZWQgdG8gcHJveHkgbW9kZWwncyBtZXRob2RzIHRvIHRoZSBob3N0IGxpa2UgW01vZGVsIGZhY2V0XSguLi9jb21wb25lbnRzL2NfZmFjZXRzL01vZGVsRmFjZXQuanMuaHRtbCkgaXMgZG9pbmcuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBwYXNzIHsgcmVhY3RpdmU6IGZhbHNlIH0gdG8gdXNlIG1vZGVsIHdpdGhvdXQgbWVzc2FnaW5nIHdoZW4gaXQgaXMgbm90IG5lZWRlZCAtIGl0IG1ha2VzIGl0IG11Y2ggZmFzdGVyXG4gKiBAcmV0dXJuIHtNb2RlbH1cbiAqL1xuZnVuY3Rpb24gTW9kZWwoZGF0YSwgaG9zdE9iamVjdCwgb3B0aW9ucykge1xuICAgIC8vIGBtb2RlbGAgd2lsbCBiZSByZXR1cm5lZCBieSBjb25zdHJ1Y3RvciBpbnN0ZWFkIG9mIGB0aGlzYC4gYG1vZGVsYFxuICAgIC8vIChgbW9kZWxQYXRoYCBmdW5jdGlvbikgc2hvdWxkIHJldHVybiBhIE1vZGVsUGF0aCBvYmplY3Qgd2l0aCBcInN5bnRoZXNpemVkXCIgbWV0aG9kc1xuICAgIC8vIHRvIGdldC9zZXQgbW9kZWwgcHJvcGVydGllcywgdG8gc3Vic2NyaWJlIHRvIHByb3BlcnR5IGNoYW5nZXMsIGV0Yy5cbiAgICAvLyBBZGRpdGlvbmFsIGFyZ3VtZW50cyBvZiBtb2RlbFBhdGggY2FuIGJlIHVzZWQgaW4gdGhlIHBhdGggdXNpbmcgaW50ZXJwb2xhdGlvbiAtIHNlZSBNb2RlbFBhdGggYmVsb3cuXG4gICAgdmFyIG1vZGVsID0gZnVuY3Rpb24gbW9kZWxQYXRoKGFjY2Vzc1BhdGgpIHsgLy8gLCAuLi4gYXJndW1lbnRzIHRoYXQgd2lsbCBiZSBpbnRlcnBvbGF0ZWRcbiAgICAgICAgcmV0dXJuIE1vZGVsJHBhdGguYXBwbHkobW9kZWwsIGFyZ3VtZW50cyk7XG4gICAgfTtcbiAgICBtb2RlbC5fX3Byb3RvX18gPSBNb2RlbC5wcm90b3R5cGU7XG5cbiAgICBtb2RlbC5faG9zdE9iamVjdCA9IGhvc3RPYmplY3Q7XG4gICAgbW9kZWwuX29wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgaWYgKG1vZGVsLl9vcHRpb25zLnJlYWN0aXZlICE9PSBmYWxzZSkge1xuICAgICAgICBtb2RlbC5fcHJlcGFyZU1lc3NlbmdlcnMoKTtcbiAgICAgICAgLy8gc3Vic2NyaWJlIHRvIFwiY2hhbmdlZGF0YVwiIG1lc3NhZ2UgdG8gZW5hYmxlIHJlYWN0aXZlIGNvbm5lY3Rpb25zXG4gICAgICAgIG1vZGVsLm9uU3luYygnY2hhbmdlZGF0YScsIGNoYW5nZURhdGFIYW5kbGVyKTtcbiAgICB9XG5cbiAgICBpZiAoZGF0YSkgbW9kZWwuX2RhdGEgPSBkYXRhO1xuXG4gICAgcmV0dXJuIG1vZGVsO1xufVxuXG5Nb2RlbC5wcm90b3R5cGUuX19wcm90b19fID0gTW9kZWwuX19wcm90b19fO1xuXG5cbi8qKlxuICogIyMjI01vZGVsIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbcGF0aF0oI3BhdGgpIC0gcmV0dXJucyBNb2RlbFBhdGggb2JqZWN0IHRoYXQgYWxsb3dzIGFjY2VzcyB0byBhbnkgcG9pbnQgaW4gTW9kZWxcbiAqIC0gW2dldF0oI01vZGVsJGdldCkgLSBnZXQgbW9kZWwgZGF0YVxuICogLSBzZXQgLSBzZXQgbW9kZWwgZGF0YSwgc3ludGhlc2l6ZWRcbiAqIC0gc3BsaWNlIC0gc3BsaWNlIG1vZGVsIGRhdGEgKGFzIGFycmF5IG9yIHBzZXVkby1hcnJheSksIHN5bnRoZXNpemVkXG4gKiAtIFtsZW5dKC4vbV9wYXRoLmpzLmh0bWwjTW9kZWxQYXRoJGxlbikgLSByZXR1cm5zIGxlbmd0aCBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KSBpbiBtb2RlbCBpbiBzYWZlIHdheSwgMCBpZiBubyBsZW5ndGggaXMgc2V0XG4gKiAtIFtwdXNoXSguL21fcGF0aC5qcy5odG1sI01vZGVsUGF0aCRwdXNoKSAtIGFkZCBpdGVtcyB0byB0aGUgZW5kIG9mIGFycmF5IChvciBwc2V1ZG8tYXJyYXkpIGluIG1vZGVsXG4gKiAtIFtwb3BdKC4vbV9wYXRoLmpzLmh0bWwjTW9kZWxQYXRoJHBvcCkgLSByZW1vdmUgaXRlbSBmcm9tIHRoZSBlbmQgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gbW9kZWxcbiAqIC0gW3Vuc2hpZnRdKC4vbV9wYXRoLmpzLmh0bWwjTW9kZWxQYXRoJHVuc2hpZnQpIC0gYWRkIGl0ZW1zIHRvIHRoZSBiZWdpbm5pbmcgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gbW9kZWxcbiAqIC0gW3NoaWZ0XSguL21fcGF0aC5qcy5odG1sI01vZGVsUGF0aCRzaGlmdCkgLSByZW1vdmUgaXRlbSBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gbW9kZWxcbiAqIC0gW3Byb3h5TWVzc2VuZ2VyXSgjcHJveHlNZXNzZW5nZXIpIC0gcHJveHkgbW9kZWwncyBNZXNzZW5nZXIgbWV0aG9kcyB0byBob3N0IG9iamVjdFxuICogLSBbcHJveHlNZXRob2RzXSgjcHJveHlNZXRob2RzKSAtIHByb3h5IG1vZGVsIG1ldGhvZHMgdG8gaG9zdCBvYmplY3RcbiAqL1xuXy5leHRlbmRQcm90byhNb2RlbCwge1xuICAgIHBhdGg6IE1vZGVsJHBhdGgsXG4gICAgZ2V0OiBNb2RlbCRnZXQsXG4gICAgcHJveHlNZXNzZW5nZXI6IHByb3h5TWVzc2VuZ2VyLCAvLyBkZXByZWNhdGVkLCBzaG91bGQgbm90IGJlIHVzZWRcbiAgICBwcm94eU1ldGhvZHM6IHByb3h5TWV0aG9kcyxcbiAgICBfcHJlcGFyZU1lc3NlbmdlcnM6IF9wcmVwYXJlTWVzc2VuZ2VycyxcbiAgICBfZ2V0SG9zdE9iamVjdDogX2dldEhvc3RPYmplY3QsXG4gICAgZGVzdHJveTogTW9kZWwkZGVzdHJveVxufSk7XG5cbi8vIHNldCwgZGVsLCBzcGxpY2UgYXJlIGFkZGVkIHRvIG1vZGVsXG5fLmV4dGVuZFByb3RvKE1vZGVsLCBzeW50aGVzaXplLm1vZGVsTWV0aG9kcyk7XG5cblxuLyoqXG4gKiAtIFBhdGg6IE1vZGVsUGF0aCBjbGFzcyBhcyBgbWlsby5Nb2RlbC5QYXRoYFxuICogLSBbcmVnaXN0ZXJXaXRoRE9NU3RvcmFnZV0oI01vZGVsJCRyZWdpc3RlcldpdGhET01TdG9yYWdlKVxuICovXG5fLmV4dGVuZChNb2RlbCwge1xuICAgIFBhdGg6IE1vZGVsUGF0aCxcbiAgICByZWdpc3RlcldpdGhET01TdG9yYWdlOiBNb2RlbCQkcmVnaXN0ZXJXaXRoRE9NU3RvcmFnZSxcbiAgICB1c2VXaXRoOiBNb2RlbCQkdXNlV2l0aFxufSk7XG5cblxuLyoqXG4gKiBFeHBvc2UgTWVzc2VuZ2VyIG1ldGhvZHMgb24gRmFjZXQgcHJvdG90eXBlXG4gKi9cbnZhciBNRVNTRU5HRVJfUFJPUEVSVFkgPSAnX21lc3Nlbmdlcic7XG5NZXNzZW5nZXIudXNlV2l0aChNb2RlbCwgTUVTU0VOR0VSX1BST1BFUlRZLCBNZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMpO1xuXG5cbi8qKlxuICogTW9kZWxQYXRoIG1ldGhvZHMgYWRkZWQgdG8gTW9kZWwgcHJvdG90eXBlXG4gKi9cblsnbGVuJywgJ3B1c2gnLCAncG9wJywgJ3Vuc2hpZnQnLCAnc2hpZnQnXS5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICB2YXIgbWV0aG9kID0gTW9kZWxQYXRoLnByb3RvdHlwZVttZXRob2ROYW1lXTtcbiAgICBfLmRlZmluZVByb3BlcnR5KE1vZGVsLnByb3RvdHlwZSwgbWV0aG9kTmFtZSwgbWV0aG9kKTtcbn0pO1xuXG5cbi8qKlxuICogTW9kZWwgaW5zdGFuY2UgbWV0aG9kLlxuICogR2V0IG1vZGVsIGRhdGEuXG4gKlxuICogQHJldHVybiB7QW55fVxuICovXG5mdW5jdGlvbiBNb2RlbCRnZXQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGE7XG59XG5cblxuLyoqXG4gKiBNb2RlbCBpbnN0YW5jZSBtZXRob2QuXG4gKiBSZXR1cm5zIE1vZGVsUGF0aCBvYmplY3QgdGhhdCBpbXBsZW1lbnRzIHRoZSBzYW1lIEFQSSBhcyBtb2RlbCBidXQgYWxsb3dzIGFjY2VzcyB0byBhbnkgcG9pbnQgaW5zaWRlIG1vZGVsIGFzIGRlZmluZWQgYnkgYGFjY2Vzc1BhdGhgLlxuICogU2VlIFtNb2RlbFBhdGhdKC4vbV9wYXRoLmpzLmh0bWwpIGNsYXNzIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBhY2Nlc3NQYXRoIHN0cmluZyB0aGF0IGRlZmluZXMgcGF0aCB0byBhY2Nlc3MgbW9kZWwuXG4gKiAgUGF0aCBzdHJpbmcgY29uc2lzdHMgb2YgcGFydHMgdG8gZGVmaW5lIGVpdGhlciBwcm9wZXJ0eSBhY2Nlc3MgKGBcIi5uYW1lXCJgIHRvIGFjY2VzcyBwcm9wZXJ0eSBuYW1lKSBvciBhcnJheSBpdGVtIGFjY2VzcyAoYFwiWzFdXCJgIHRvIGFjY2VzcyBpdGVtIHdpdGggaW5kZXggMSkuXG4gKiAgQWNjZXNzIHBhdGggY2FuIGNvbnRhaW4gYXMgbWFueSBwYXJ0cyBhcyBuZWNlc3NhcnkgKGUuZy4gYFwiLmxpc3RbMF0ubmFtZVwiYCB0byBhY2Nlc3MgcHJvcGVydHkgYG5hbWVgIGluIHRoZSBmaXJzdCBlbGVtZW50IG9mIGFycmF5IHN0b3JlZCBpbiBwcm9wZXJ0eSBgbGlzdGAuXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBhZGRpdGlvbmFsIGFyZ3VtZW50cyBvZiB0aGlzIG1ldGhvZCBjYW4gYmUgdXNlZCB0byBjcmVhdGUgaW50ZXJwb2xhdGVkIHBhdGhzLlxuICogIEUuZy4gYG0ucGF0aChcIlskMV0uJDJcIiwgaWQsIHByb3ApYCByZXR1cm5zIE1vZGVsUGF0aCB0byBhY2Nlc3MgcHJvcGVydHkgd2l0aCBuYW1lIGBwcm9wYCBpbiBhcnJheSBpdGVtIHdpdGggaW5kZXggYGlkYC4gQWx0aG91Z2ggdGhpcyBNb2RlbFBhdGggb2JqZWN0IHdpbGwgd29yayBleGFjdGx5IGFzIGBtKFwiW1wiICsgaWQgKyBcIl0uXCIgKyBwcm9wKWAsIHRoZSBpbnRlcnBvbGF0ZWQgaXMgbXVjaCBtb3JlIGVmZmljaWVudCBhcyBNb2RlbFBhdGggd2l0aCBpbnRlcnBvbGF0aW9uIHdpbGwgbm90IHN5bnRoZXNpemUgbmV3IGdldHRlcnMgYW5kIHNldHRlcnMsIHdoaWxlIE1vZGVsUGF0aCB3aXRoIGNvbXB1dGVkIGFjY2VzcyBwYXRoIHdpbGwgc3ludGhlc2l6ZSBuZXcgZ2V0dGVycyBhbmQgc2V0dGVycyBmb3IgZWFjaCBwYWlyIG9mIHZhbHVlcyBvZiBgaWRgIGFuZCBgcHJvcGAuXG4gKiBAcmV0dXJuIHtNb2RlbFBhdGh9XG4gKi9cbmZ1bmN0aW9uIE1vZGVsJHBhdGgoYWNjZXNzUGF0aCkgeyAgLy8gLCAuLi4gYXJndW1lbnRzIHRoYXQgd2lsbCBiZSBpbnRlcnBvbGF0ZWRcbiAgICBpZiAoISBhY2Nlc3NQYXRoKSByZXR1cm4gdGhpcztcblxuICAgIC8vIFwibnVsbFwiIGlzIGNvbnRleHQgdG8gcGFzcyB0byBNb2RlbFBhdGgsIGZpcnN0IHBhcmFtZXRlciBvZiBiaW5kXG4gICAgLy8gXCJ0aGlzXCIgKG1vZGVsKSBpcyBhZGRlZCBpbiBmcm9udCBvZiBhbGwgYXJndW1lbnRzXG4gICAgXy5zcGxpY2UoYXJndW1lbnRzLCAwLCAwLCBudWxsLCB0aGlzKTtcblxuICAgIC8vIGNhbGxpbmcgTW9kZWxQYXRoIGNvbnN0cnVjdG9yIHdpdGggbmV3IGFuZCB0aGUgbGlzdCBvZiBhcmd1bWVudHM6IHRoaXMgKG1vZGVsKSwgYWNjZXNzUGF0aCwgLi4uXG4gICAgcmV0dXJuIG5ldyAoRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQuYXBwbHkoTW9kZWxQYXRoLCBhcmd1bWVudHMpKTtcbn1cblxuXG4vKipcbiAqIE1vZGVsIGluc3RhbmNlIG1ldGhvZC5cbiAqIFByb3h5IG1vZGVsJ3MgTWVzc2VuZ2VyIG1ldGhvZHMgdG8gaG9zdCBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG1vZGVsSG9zdE9iamVjdCBvcHRpb25hbCBob3N0IG9iamVjdC4gSWYgbm90IHBhc3NlZCwgaG9zdE9iamVjdCBwYXNzZWQgdG8gTW9kZWwgY29uc3RydWN0b3Igd2lsbCBiZSB1c2VkLlxuICovXG5mdW5jdGlvbiBwcm94eU1lc3Nlbmdlcihtb2RlbEhvc3RPYmplY3QpIHtcbiAgICBtb2RlbEhvc3RPYmplY3QgPSBtb2RlbEhvc3RPYmplY3QgfHwgdGhpcy5faG9zdE9iamVjdDtcbiAgICBNaXhpbi5wcm90b3R5cGUuX2NyZWF0ZVByb3h5TWV0aG9kcy5jYWxsKHRoaXNbTUVTU0VOR0VSX1BST1BFUlRZXSwgTWVzc2VuZ2VyLmRlZmF1bHRNZXRob2RzLCBtb2RlbEhvc3RPYmplY3QpO1xufVxuXG5cbnZhciBtb2RlbE1ldGhvZHNUb1Byb3h5ID0gWydwYXRoJywgJ2dldCcsICdzZXQnLCAnZGVsJywgJ3NwbGljZScsICdsZW4nLCAncHVzaCcsICdwb3AnLCAndW5zaGlmdCcsICdzaGlmdCddO1xuXG5cbi8qKlxuICogRXhwb3NlIG1vZGVsIG1ldGhvZHMgb25cbiAqIFNlZSBzYW1lIG1ldGhvZCBpbiBNaXhpbiBjbGFzcyBmb3IgcGFyYW1ldGVycyBtZWFuaW5nXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gaG9zdENsYXNzXG4gKiBAcGFyYW0ge1t0eXBlXX0gaW5zdGFuY2VLZXlcbiAqIEBwYXJhbSB7W3R5cGVdfSBtaXhpbk1ldGhvZHMgb3B0aW9uYWxcbiAqL1xuZnVuY3Rpb24gTW9kZWwkJHVzZVdpdGgoaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2RzKSB7XG4gICAgbWl4aW5NZXRob2RzID0gbWl4aW5NZXRob2RzIHx8IG1vZGVsTWV0aG9kc1RvUHJveHk7XG4gICAgTWl4aW4udXNlV2l0aC5jYWxsKE1vZGVsLCBob3N0Q2xhc3MsIGluc3RhbmNlS2V5LCBtaXhpbk1ldGhvZHMpO1xufVxuXG5cbi8qKlxuICogTW9kZWwgaW5zdGFuY2UgbWV0aG9kLlxuICogUHJveHkgbW9kZWwgbWV0aG9kcyB0byBob3N0IG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gbW9kZWxIb3N0T2JqZWN0IG9wdGlvbmFsIGhvc3Qgb2JqZWN0LiBJZiBub3QgcGFzc2VkLCBob3N0T2JqZWN0IHBhc3NlZCB0byBNb2RlbCBjb25zdHJ1Y3RvciB3aWxsIGJlIHVzZWQuXG4gKi9cbmZ1bmN0aW9uIHByb3h5TWV0aG9kcyhtb2RlbEhvc3RPYmplY3QpIHtcbiAgICBtb2RlbEhvc3RPYmplY3QgPSBtb2RlbEhvc3RPYmplY3QgfHwgdGhpcy5faG9zdE9iamVjdDtcbiAgICBNaXhpbi5wcm90b3R5cGUuX2NyZWF0ZVByb3h5TWV0aG9kcy5jYWxsKHRoaXMsIG1vZGVsTWV0aG9kc1RvUHJveHksIG1vZGVsSG9zdE9iamVjdCk7XG59XG5cblxuLyoqXG4gKiBNb2RlbCBpbnN0YW5jZSBtZXRob2QuXG4gKiBDcmVhdGUgYW5kIGNvbm5lY3QgaW50ZXJuYWwgYW5kIGV4dGVybmFsIG1vZGVsJ3MgbWVzc2VuZ2Vycy5cbiAqIEV4dGVybmFsIG1lc3NlbmdlcidzIG1ldGhvZHMgYXJlIHByb3hpZWQgb24gdGhlIG1vZGVsIGFuZCB0aGV5IGFsbG93cyBcIipcIiBzdWJzY3JpcHRpb25zLlxuICovXG5mdW5jdGlvbiBfcHJlcGFyZU1lc3NlbmdlcnMoKSB7XG4gICAgLy8gbW9kZWwgd2lsbCBwb3N0IGFsbCBpdHMgY2hhbmdlcyBvbiBpbnRlcm5hbCBtZXNzZW5nZXJcbiAgICB2YXIgaW50ZXJuYWxNZXNzZW5nZXIgPSBuZXcgTWVzc2VuZ2VyKHRoaXMsIHVuZGVmaW5lZCwgdW5kZWZpbmVkKTtcblxuICAgIC8vIG1lc3NhZ2Ugc291cmNlIHRvIGNvbm5lY3QgaW50ZXJuYWwgbWVzc2VuZ2VyIHRvIGV4dGVybmFsXG4gICAgdmFyIGludGVybmFsTWVzc2VuZ2VyU291cmNlID0gbmV3IE1lc3Nlbmdlck1lc3NhZ2VTb3VyY2UodGhpcywgdW5kZWZpbmVkLCBuZXcgTW9kZWxNc2dBUEksIGludGVybmFsTWVzc2VuZ2VyKTtcblxuICAgIC8vIGV4dGVybmFsIG1lc3NlbmdlciB0byB3aGljaCBhbGwgbW9kZWwgdXNlcnMgd2lsbCBzdWJzY3JpYmUsXG4gICAgLy8gdGhhdCB3aWxsIGFsbG93IFwiKlwiIHN1YnNjcmlwdGlvbnMgYW5kIHN1cHBvcnQgXCJjaGFuZ2VkYXRhXCIgbWVzc2FnZSBhcGkuXG4gICAgdmFyIGV4dGVybmFsTWVzc2VuZ2VyID0gbmV3IE1lc3Nlbmdlcih0aGlzLCB1bmRlZmluZWQsIGludGVybmFsTWVzc2VuZ2VyU291cmNlKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgTUVTU0VOR0VSX1BST1BFUlRZLCBleHRlcm5hbE1lc3Nlbmdlcik7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnX2ludGVybmFsTWVzc2VuZ2VyJywgaW50ZXJuYWxNZXNzZW5nZXIpO1xufVxuXG5cbmZ1bmN0aW9uIF9nZXRIb3N0T2JqZWN0KCkge1xuICAgIHJldHVybiB0aGlzLl9ob3N0T2JqZWN0O1xufVxuXG5cbmZ1bmN0aW9uIE1vZGVsJCRyZWdpc3RlcldpdGhET01TdG9yYWdlKCkge1xuICAgIHZhciBET01TdG9yYWdlID0gcmVxdWlyZSgnLi4vdXRpbC9zdG9yYWdlJyk7XG4gICAgRE9NU3RvcmFnZS5yZWdpc3RlckRhdGFUeXBlKCdNb2RlbCcsIE1vZGVsX2RvbVN0b3JhZ2VTZXJpYWxpemVyLCBNb2RlbF9kb21TdG9yYWdlUGFyc2VyKTtcbiAgICBET01TdG9yYWdlLnJlZ2lzdGVyRGF0YVR5cGUoJ01vZGVsUGF0aCcsIE1vZGVsX2RvbVN0b3JhZ2VTZXJpYWxpemVyLCBNb2RlbF9kb21TdG9yYWdlUGFyc2VyLCAnTW9kZWwnKTtcbn1cblxuXG5mdW5jdGlvbiBNb2RlbF9kb21TdG9yYWdlU2VyaWFsaXplcih2YWx1ZSkge1xuICAgIHZhciBkYXRhID0gdmFsdWUuZ2V0KCk7XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGRhdGEpO1xufVxuXG5cbmZ1bmN0aW9uIE1vZGVsX2RvbVN0b3JhZ2VQYXJzZXIodmFsdWVTdHIpIHtcbiAgICB2YXIgZGF0YSA9IGpzb25QYXJzZSh2YWx1ZVN0cik7XG4gICAgcmV0dXJuIG5ldyBNb2RlbChkYXRhKTtcbn1cblxuXG5mdW5jdGlvbiBNb2RlbCRkZXN0cm95KCkge1xuICAgIHRoaXNbTUVTU0VOR0VSX1BST1BFUlRZXS5kZXN0cm95KCk7XG4gICAgdGhpcy5faW50ZXJuYWxNZXNzZW5nZXIuZGVzdHJveSgpO1xuICAgIHRoaXMuX2Rlc3Ryb3llZCA9IHRydWU7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBNZXNzZW5nZXJSZWdleHBBUEkgPSByZXF1aXJlKCcuLi9tZXNzZW5nZXIvbV9hcGlfcngnKVxuICAgICwgcGF0aFV0aWxzID0gcmVxdWlyZSgnLi9wYXRoX3V0aWxzJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG4vKipcbiAqIFN1YmNsYXNzIG9mIE1lc3NlbmdlclJlZ2V4cEFQSSB0aGF0IGlzIHVzZWQgdG8gdHJhbnNsYXRlIG1lc3NhZ2VzIG9mIGV4dGVybmFsIG1lc3NlbmdlciBvZiBNb2RlbCB0byBpbnRlcm5hbCBtZXNzZW5nZXIgb2YgTW9kZWwuXG4gKi9cbnZhciBNb2RlbE1zZ0FQSSA9IF8uY3JlYXRlU3ViY2xhc3MoTWVzc2VuZ2VyUmVnZXhwQVBJLCAnTW9kZWxNc2dBUEknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBNb2RlbE1zZ0FQSTtcblxuXG4vKipcbiAqICMjIyNNb2RlbE1zZ0FQSSBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW3RyYW5zbGF0ZVRvU291cmNlTWVzc2FnZV0oI3RyYW5zbGF0ZVRvU291cmNlTWVzc2FnZSkgLSB0cmFuc2xhdGVzIHN1YnNjcmlwdGlvbiBwYXRocyB3aXRoIFwiKlwicyB0byByZWdleCwgbGVhdmluZyBvdGhlciBzdHJpbmdzIHVudG91Y2hlZFxuICovXG5fLmV4dGVuZFByb3RvKE1vZGVsTXNnQVBJLCB7XG4gICAgdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlOiB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UsXG59KTtcblxuXG4vKipcbiAqIE1vZGVsTXNnQVBJIGluc3RhbmNlIG1ldGhvZFxuICogVHJhbnNsYXRlcyBzdWJzY3JpcHRpb24gcGF0aHMgd2l0aCBcIipcInMgdG8gcmVnZXgsIGxlYXZpbmcgb3RoZXIgc3RyaW5ncyB1bnRvdWNoZWQuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IGFjY2Vzc1BhdGggcmVsYXRpdmUgYWNjZXNzIHBhdGggdG8gYmUgdHJhbnNsYXRlZFxuICogQHJldHVybiB7UmVnRXhwfFN0cmluZ31cbiAqL1xuZnVuY3Rpb24gdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKGFjY2Vzc1BhdGgpIHtcbiAgICBpZiAoYWNjZXNzUGF0aCBpbnN0YW5jZW9mIFJlZ0V4cCkgcmV0dXJuIGFjY2Vzc1BhdGg7XG5cbiAgICByZXR1cm4gcGF0aFV0aWxzLmNyZWF0ZVJlZ2V4UGF0aChhY2Nlc3NQYXRoKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHN5bnRoZXNpemUgPSByZXF1aXJlKCcuL3N5bnRoZXNpemUnKVxuICAgICwgcGF0aFV0aWxzID0gcmVxdWlyZSgnLi9wYXRoX3V0aWxzJylcbiAgICAsIGNoYW5nZURhdGFIYW5kbGVyID0gcmVxdWlyZSgnLi9jaGFuZ2VfZGF0YScpXG4gICAgLCBNZXNzZW5nZXIgPSByZXF1aXJlKCcuLi9tZXNzZW5nZXInKVxuICAgICwgTW9kZWxQYXRoTXNnQVBJID0gcmVxdWlyZSgnLi9wYXRoX21zZ19hcGknKVxuICAgICwgTWVzc2VuZ2VyTWVzc2FnZVNvdXJjZSA9IHJlcXVpcmUoJy4uL21lc3Nlbmdlci9tc25ncl9zb3VyY2UnKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaDtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1vZGVsUGF0aDtcblxuXG4vKipcbiAqIGBtaWxvLk1vZGVsLlBhdGhgXG4gKiBNb2RlbFBhdGggb2JqZWN0IHRoYXQgYWxsb3dzIGFjY2VzcyB0byBhbnkgcG9pbnQgaW5zaWRlIFtNb2RlbF0oLi9pbmRleC5qcy5odG1sKSBhcyBkZWZpbmVkIGJ5IGBhY2Nlc3NQYXRoYFxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQHBhcmFtIHtNb2RlbH0gbW9kZWwgTW9kZWwgaW5zdGFuY2UgdGhhdCBNb2RlbFBhdGggZ2l2ZXMgYWNjZXNzIHRvLlxuICogQHBhcmFtIHtTdHJpbmd9IGFjY2Vzc1BhdGggc3RyaW5nIHRoYXQgZGVmaW5lcyBwYXRoIHRvIGFjY2VzcyBtb2RlbC5cbiAqICBQYXRoIHN0cmluZyBjb25zaXN0cyBvZiBwYXJ0cyB0byBkZWZpbmUgZWl0aGVyIHByb3BlcnR5IGFjY2VzcyAoYFwiLm5hbWVcImAgdG8gYWNjZXNzIHByb3BlcnR5IG5hbWUpIG9yIGFycmF5IGl0ZW0gYWNjZXNzIChgXCJbMV1cImAgdG8gYWNjZXNzIGl0ZW0gd2l0aCBpbmRleCAxKS5cbiAqICBBY2Nlc3MgcGF0aCBjYW4gY29udGFpbiBhcyBtYW55IHBhcnRzIGFzIG5lY2Vzc2FyeSAoZS5nLiBgXCIubGlzdFswXS5uYW1lXCJgIHRvIGFjY2VzcyBwcm9wZXJ0eSBgbmFtZWAgaW4gdGhlIGZpcnN0IGVsZW1lbnQgb2YgYXJyYXkgc3RvcmVkIGluIHByb3BlcnR5IGBsaXN0YC5cbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIGFkZGl0aW9uYWwgYXJndW1lbnRzIG9mIHRoaXMgbWV0aG9kIGNhbiBiZSB1c2VkIHRvIGNyZWF0ZSBpbnRlcnBvbGF0ZWQgcGF0aHMuXG4gKiAgRS5nLiBgbS5wYXRoKFwiWyQxXS4kMlwiLCBpZCwgcHJvcClgIHJldHVybnMgTW9kZWxQYXRoIHRvIGFjY2VzcyBwcm9wZXJ0eSB3aXRoIG5hbWUgYHByb3BgIGluIGFycmF5IGl0ZW0gd2l0aCBpbmRleCBgaWRgLiBBbHRob3VnaCB0aGlzIE1vZGVsUGF0aCBvYmplY3Qgd2lsbCB3b3JrIGV4YWN0bHkgYXMgYG0oXCJbXCIgKyBpZCArIFwiXS5cIiArIHByb3ApYCwgdGhlIGludGVycG9sYXRlZCBpcyBtdWNoIG1vcmUgZWZmaWNpZW50IGFzIE1vZGVsUGF0aCB3aXRoIGludGVycG9sYXRpb24gd2lsbCBub3Qgc3ludGhlc2l6ZSBuZXcgZ2V0dGVycyBhbmQgc2V0dGVycywgd2hpbGUgTW9kZWxQYXRoIHdpdGggY29tcHV0ZWQgYWNjZXNzIHBhdGggd2lsbCBzeW50aGVzaXplIG5ldyBnZXR0ZXJzIGFuZCBzZXR0ZXJzIGZvciBlYWNoIHBhaXIgb2YgdmFsdWVzIG9mIGBpZGAgYW5kIGBwcm9wYC5cbiAqIEByZXR1cm4ge01vZGVsUGF0aH1cbiAqL1xuZnVuY3Rpb24gTW9kZWxQYXRoKG1vZGVsLCBwYXRoKSB7IC8vICwuLi4gLSBhZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgaW50ZXJwb2xhdGlvblxuICAgIC8vIGNoZWNrKG1vZGVsLCBNb2RlbCk7XG4gICAgY2hlY2socGF0aCwgU3RyaW5nKTtcblxuICAgIC8vIGBtb2RlbFBhdGhgIHdpbGwgYmUgcmV0dXJuZWQgYnkgY29uc3RydWN0b3IgaW5zdGVhZCBvZiBgdGhpc2AuIGBtb2RlbFBhdGhgXG4gICAgLy8gKGBtb2RlbFBhdGhfcGF0aGAgZnVuY3Rpb24pIHNob3VsZCBhbHNvIHJldHVybiBhIE1vZGVsUGF0aCBvYmplY3Qgd2l0aCBcInN5bnRoZXNpemVkXCIgbWV0aG9kc1xuICAgIC8vIHRvIGdldC9zZXQgbW9kZWwgcHJvcGVydGllcywgdG8gc3Vic2NyaWJlIHRvIHByb3BlcnR5IGNoYW5nZXMsIGV0Yy5cbiAgICAvLyBBZGRpdGlvbmFsIGFyZ3VtZW50cyBvZiBtb2RlbFBhdGggY2FuIGJlIHVzZWQgaW4gdGhlIHBhdGggdXNpbmcgaW50ZXJwb2xhdGlvbiAtIHNlZSBNb2RlbFBhdGggYmVsb3cuXG4gICAgdmFyIG1vZGVsUGF0aCA9IGZ1bmN0aW9uIG1vZGVsUGF0aF9wYXRoKGFjY2Vzc1BhdGgpIHsgLy8gLCAuLi4gYXJndW1lbnRzIHRoYXQgd2lsbCBiZSBpbnRlcnBvbGF0ZWRcbiAgICAgICAgcmV0dXJuIE1vZGVsUGF0aCRwYXRoLmFwcGx5KG1vZGVsUGF0aCwgYXJndW1lbnRzKTtcbiAgICB9O1xuICAgIG1vZGVsUGF0aC5fX3Byb3RvX18gPSBNb2RlbFBhdGgucHJvdG90eXBlO1xuXG5cbiAgICBfLmRlZmluZVByb3BlcnRpZXMobW9kZWxQYXRoLCB7XG4gICAgICAgIF9tb2RlbDogbW9kZWwsXG4gICAgICAgIF9wYXRoOiBwYXRoLFxuICAgICAgICBfYXJnczogXy5zbGljZShhcmd1bWVudHMsIDEpLCAvLyBwYXRoIHdpbGwgYmUgdGhlIGZpcnN0IGVsZW1lbnQgb2YgdGhpcyBhcnJheVxuICAgICAgICBfb3B0aW9uczogbW9kZWwuX29wdGlvbnNcbiAgICB9KTtcblxuICAgIC8vIHBhcnNlIGFjY2VzcyBwYXRoXG4gICAgdmFyIHBhcnNlZFBhdGggPSBwYXRoVXRpbHMucGFyc2VBY2Nlc3NQYXRoKHBhdGgpO1xuXG4gICAgLy8gY29tcHV0ZSBhY2Nlc3MgcGF0aCBzdHJpbmdcbiAgICBfLmRlZmluZVByb3BlcnR5KG1vZGVsUGF0aCwgJ19hY2Nlc3NQYXRoJywgaW50ZXJwb2xhdGVBY2Nlc3NQYXRoKHBhcnNlZFBhdGgsIG1vZGVsUGF0aC5fYXJncykpO1xuXG4gICAgaWYgKG1vZGVsUGF0aC5fb3B0aW9ucy5yZWFjdGl2ZSAhPT0gZmFsc2UpIHtcbiAgICAgICAgLy8gbWVzc2VuZ2VyIGZhaWxzIG9uIFwiKlwiIHN1YnNjcmlwdGlvbnNcbiAgICAgICAgbW9kZWxQYXRoLl9wcmVwYXJlTWVzc2VuZ2VyKCk7XG4gICAgICAgIC8vIHN1YnNjcmliZSB0byBcImNoYW5nZWRhdGFcIiBtZXNzYWdlIHRvIGVuYWJsZSByZWFjdGl2ZSBjb25uZWN0aW9uc1xuICAgICAgICBtb2RlbFBhdGgub25TeW5jKCdjaGFuZ2VkYXRhJywgY2hhbmdlRGF0YUhhbmRsZXIpO1xuICAgIH1cblxuICAgIC8vIGNvbXBpbGluZyBnZXR0ZXIgYW5kIHNldHRlclxuICAgIHZhciBtZXRob2RzID0gc3ludGhlc2l6ZShwYXRoLCBwYXJzZWRQYXRoKTtcblxuICAgIC8vIGFkZGluZyBtZXRob2RzIHRvIG1vZGVsIHBhdGhcbiAgICBfLmRlZmluZVByb3BlcnRpZXMobW9kZWxQYXRoLCBtZXRob2RzKTtcblxuICAgIE9iamVjdC5mcmVlemUobW9kZWxQYXRoKTtcblxuICAgIHJldHVybiBtb2RlbFBhdGg7XG59XG5cbk1vZGVsUGF0aC5wcm90b3R5cGUuX19wcm90b19fID0gTW9kZWxQYXRoLl9fcHJvdG9fXztcblxuXG4vKipcbiAqIEludGVycG9sYXRlcyBwYXRoIGVsZW1lbnRzIHRvIGNvbXB1dGUgcmVhbCBwYXRoXG4gKlxuICogQHBhcmFtIHtBcnJheX0gcGFyc2VkUGF0aCBwYXJzZWQgcGF0aCAtIGFycmF5IG9mIHBhdGggbm9kZXNcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgcGF0aCBpbnRlcnBvbGF0aW9uIGFyZ3VtZW50cywgYXJnc1swXSBpcyBwYXRoIGl0c2VsZlxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBpbnRlcnBvbGF0ZUFjY2Vzc1BhdGgocGFyc2VkUGF0aCwgYXJncykge1xuICAgIHJldHVybiBwYXJzZWRQYXRoLnJlZHVjZShmdW5jdGlvbihhY2Nlc3NQYXRoU3RyLCBjdXJyTm9kZSwgaW5kZXgpIHtcbiAgICAgICAgdmFyIGludGVycG9sYXRlID0gY3Vyck5vZGUuaW50ZXJwb2xhdGU7XG4gICAgICAgIHJldHVybiBhY2Nlc3NQYXRoU3RyICtcbiAgICAgICAgICAgICAgICAoaW50ZXJwb2xhdGVcbiAgICAgICAgICAgICAgICAgICAgPyAoY3Vyck5vZGUuc3ludGF4ID09ICdhcnJheSdcbiAgICAgICAgICAgICAgICAgICAgICAgID8gJ1snICsgYXJnc1tpbnRlcnBvbGF0ZV0gKyAnXSdcbiAgICAgICAgICAgICAgICAgICAgICAgIDogJy4nICsgYXJnc1tpbnRlcnBvbGF0ZV0pXG4gICAgICAgICAgICAgICAgICAgIDogY3Vyck5vZGUucHJvcGVydHkpO1xuICAgIH0sICcnKTtcbn1cblxuXG4vKipcbiAqICMjIyNNb2RlbFBhdGggaW5zdGFuY2UgbWV0aG9kcyMjIyNcbiAqXG4gKiAtIFtwYXRoXSgjTW9kZWxQYXRoJHBhdGgpIC0gZ2l2ZXMgYWNjZXNzIHRvIHBhdGggaW5zaWRlIE1vZGVsUGF0aFxuICogLSBnZXQgLSBzeW50aGVzaXplZFxuICogLSBzZXQgLSBzeW50aGVzaXplZFxuICogLSBzcGxpY2UgLSBzcGxpY2UgbW9kZWwgZGF0YSAoYXMgYXJyYXkgb3IgcHNldWRvLWFycmF5KSwgc3ludGhlc2l6ZWRcbiAqIC0gW2xlbl0oI01vZGVsUGF0aCRsZW4pIC0gcmV0dXJucyBsZW5ndGggb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gc2FmZSB3YXksIDAgaWYgbm8gbGVuZ3RoIGlzIHNldFxuICogLSBbcHVzaF0oI01vZGVsUGF0aCRwdXNoKSAtIGFkZCBpdGVtcyB0byB0aGUgZW5kIG9mIGFycmF5IChvciBwc2V1ZG8tYXJyYXkpIGluIE1vZGVsUGF0aFxuICogLSBbcG9wXSgjTW9kZWxQYXRoJHBvcCkgLSByZW1vdmUgaXRlbSBmcm9tIHRoZSBlbmQgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gTW9kZWxQYXRoXG4gKiAtIFt1bnNoaWZ0XSgjTW9kZWxQYXRoJHVuc2hpZnQpIC0gYWRkIGl0ZW1zIHRvIHRoZSBiZWdpbm5pbmcgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gTW9kZWxQYXRoXG4gKiAtIFtzaGlmdF0oI01vZGVsUGF0aCRzaGlmdCkgLSByZW1vdmUgaXRlbSBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gTW9kZWxQYXRoXG4gKi9cbl8uZXh0ZW5kUHJvdG8oTW9kZWxQYXRoLCB7XG4gICAgcGF0aDogTW9kZWxQYXRoJHBhdGgsXG4gICAgbGVuOiBNb2RlbFBhdGgkbGVuLFxuICAgIHB1c2g6IE1vZGVsUGF0aCRwdXNoLFxuICAgIHBvcDogTW9kZWxQYXRoJHBvcCxcbiAgICB1bnNoaWZ0OiBNb2RlbFBhdGgkdW5zaGlmdCxcbiAgICBzaGlmdDogTW9kZWxQYXRoJHNoaWZ0LFxuICAgIF9wcmVwYXJlTWVzc2VuZ2VyOiBfcHJlcGFyZU1lc3NlbmdlcixcbiAgICBfZ2V0RGVmaW5pdGlvbjogX2dldERlZmluaXRpb24sXG4gICAgZGVzdHJveTogTW9kZWxQYXRoJGRlc3Ryb3lcbn0pO1xuXG5cbl8uZXh0ZW5kKE1vZGVsUGF0aCwge1xuICAgIF9jcmVhdGVGcm9tRGVmaW5pdGlvbjogX2NyZWF0ZUZyb21EZWZpbml0aW9uXG59KVxuXG5cbi8qKlxuICogRXhwb3NlIE1lc3NlbmdlciBtZXRob2RzIG9uIEZhY2V0IHByb3RvdHlwZVxuICovXG52YXIgTUVTU0VOR0VSX1BST1BFUlRZID0gJ19tZXNzZW5nZXInO1xuTWVzc2VuZ2VyLnVzZVdpdGgoTW9kZWxQYXRoLCBNRVNTRU5HRVJfUFJPUEVSVFksIE1lc3Nlbmdlci5kZWZhdWx0TWV0aG9kcyk7XG5cblxuLyoqXG4gKiBNb2RlbFBhdGggaW5zdGFuY2UgbWV0aG9kXG4gKiBHaXZlcyBhY2Nlc3MgdG8gcGF0aCBpbnNpZGUgTW9kZWxQYXRoLiBNZXRob2Qgd29ya3Mgc2ltaWxhcmx5IHRvIFtwYXRoIG1ldGhvZF0oI01vZGVsJHBhdGgpIG9mIG1vZGVsLCB1c2luZyByZWxhdGl2ZSBwYXRocy5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gYWNjZXNzUGF0aCBzdHJpbmcgdGhhdCBkZWZpbmVzIHBhdGggdG8gYWNjZXNzIG1vZGVsLlxuICogIFBhdGggc3RyaW5nIGNvbnNpc3RzIG9mIHBhcnRzIHRvIGRlZmluZSBlaXRoZXIgcHJvcGVydHkgYWNjZXNzIChgXCIubmFtZVwiYCB0byBhY2Nlc3MgcHJvcGVydHkgbmFtZSkgb3IgYXJyYXkgaXRlbSBhY2Nlc3MgKGBcIlsxXVwiYCB0byBhY2Nlc3MgaXRlbSB3aXRoIGluZGV4IDEpLlxuICogIEFjY2VzcyBwYXRoIGNhbiBjb250YWluIGFzIG1hbnkgcGFydHMgYXMgbmVjZXNzYXJ5IChlLmcuIGBcIi5saXN0WzBdLm5hbWVcImAgdG8gYWNjZXNzIHByb3BlcnR5IGBuYW1lYCBpbiB0aGUgZmlyc3QgZWxlbWVudCBvZiBhcnJheSBzdG9yZWQgaW4gcHJvcGVydHkgYGxpc3RgLlxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgYWRkaXRpb25hbCBhcmd1bWVudHMgb2YgdGhpcyBtZXRob2QgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGludGVycG9sYXRlZCBwYXRocy5cbiAqICBFLmcuIGBtLnBhdGgoXCJbJDFdLiQyXCIsIGlkLCBwcm9wKWAgcmV0dXJucyBNb2RlbFBhdGggdG8gYWNjZXNzIHByb3BlcnR5IHdpdGggbmFtZSBgcHJvcGAgaW4gYXJyYXkgaXRlbSB3aXRoIGluZGV4IGBpZGAuIEFsdGhvdWdoIHRoaXMgTW9kZWxQYXRoIG9iamVjdCB3aWxsIHdvcmsgZXhhY3RseSBhcyBgbShcIltcIiArIGlkICsgXCJdLlwiICsgcHJvcClgLCB0aGUgaW50ZXJwb2xhdGVkIGlzIG11Y2ggbW9yZSBlZmZpY2llbnQgYXMgTW9kZWxQYXRoIHdpdGggaW50ZXJwb2xhdGlvbiB3aWxsIG5vdCBzeW50aGVzaXplIG5ldyBnZXR0ZXJzIGFuZCBzZXR0ZXJzLCB3aGlsZSBNb2RlbFBhdGggd2l0aCBjb21wdXRlZCBhY2Nlc3MgcGF0aCB3aWxsIHN5bnRoZXNpemUgbmV3IGdldHRlcnMgYW5kIHNldHRlcnMgZm9yIGVhY2ggcGFpciBvZiB2YWx1ZXMgb2YgYGlkYCBhbmQgYHByb3BgLlxuICogQHJldHVybiB7TW9kZWxQYXRofVxuICovXG5mdW5jdGlvbiBNb2RlbFBhdGgkcGF0aChhY2Nlc3NQYXRoKSB7ICAvLyAsIC4uLiBhcmd1bWVudHMgdGhhdCB3aWxsIGJlIGludGVycG9sYXRlZFxuICAgIGlmICghIGFjY2Vzc1BhdGgpIHJldHVybiB0aGlzO1xuXG4gICAgdmFyIHRoaXNQYXRoQXJnc0NvdW50ID0gdGhpcy5fYXJncy5sZW5ndGggLSAxO1xuXG4gICAgaWYgKHRoaXNQYXRoQXJnc0NvdW50ID4gMCkgey8vIHRoaXMgcGF0aCBoYXMgaW50ZXJwb2xhdGVkIGFyZ3VtZW50cyB0b29cbiAgICAgICAgYWNjZXNzUGF0aCA9IGFjY2Vzc1BhdGgucmVwbGFjZSgvXFwkWzEtOV1bMC05XSovZywgZnVuY3Rpb24oc3RyKSB7XG4gICAgICAgICAgICByZXR1cm4gJyQnICsgKCtzdHIuc2xpY2UoMSkgKyB0aGlzUGF0aEFyZ3NDb3VudCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHZhciBuZXdQYXRoID0gdGhpcy5fcGF0aCArIGFjY2Vzc1BhdGg7XG5cbiAgICAvLyB0aGlzLl9tb2RlbCBpcyBhZGRlZCBpbiBmcm9udCBvZiBhbGwgYXJndW1lbnRzIGFzIHRoZSBmaXJzdCBwYXJhbWV0ZXJcbiAgICAvLyBvZiBNb2RlbFBhdGggY29uc3RydWN0b3JcbiAgICB2YXIgYXJncyA9IFt0aGlzLl9tb2RlbCwgbmV3UGF0aF1cbiAgICAgICAgICAgICAgICAuY29uY2F0KHRoaXMuX2FyZ3Muc2xpY2UoMSkpIC8vIHJlbW92ZSBvbGQgcGF0aCBmcm9tIF9hcmdzLCBhcyBpdCBpcyAxIGJhc2VkXG4gICAgICAgICAgICAgICAgLmNvbmNhdChfLnNsaWNlKGFyZ3VtZW50cywgMSkpOyAvLyBhZGQgbmV3IGludGVycG9sYXRpb24gYXJndW1lbnRzXG5cbiAgICAvLyBjYWxsaW5nIE1vZGVsUGF0aCBjb25zdHJ1Y3RvciB3aXRoIG5ldyBhbmQgdGhlIGxpc3Qgb2YgYXJndW1lbnRzOiB0aGlzIChtb2RlbCksIGFjY2Vzc1BhdGgsIC4uLlxuICAgIHJldHVybiBfLm5ld0FwcGx5KE1vZGVsUGF0aCwgYXJncyk7XG59XG5cblxuLyoqXG4gKiBNb2RlbFBhdGggYW5kIE1vZGVsIGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyBsZW5ndGggcHJvcGVydHkgYW5kIHNldHMgaXQgdG8gMCBpZiBpdCB3YXNuJ3Qgc2V0LlxuICpcbiAqIEByZXR1cm4ge0FueX1cbiAqL1xuZnVuY3Rpb24gTW9kZWxQYXRoJGxlbigpIHtcbiAgICByZXR1cm4gdGhpcy5wYXRoKCcubGVuZ3RoJykuZ2V0KCkgfHwgMDtcbn1cblxuXG4vKipcbiAqIE1vZGVsUGF0aCBhbmQgTW9kZWwgaW5zdGFuY2UgbWV0aG9kXG4gKiBBZGRzIGl0ZW1zIHRvIHRoZSBlbmQgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkuIFJldHVybnMgbmV3IGxlbmd0aC5cbiAqXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBsaXN0IG9mIGl0ZW1zIHRoYXQgd2lsbCBiZSBhZGRlZCB0byBhcnJheSAocHNldWRvIGFycmF5KVxuICogQHJldHVybiB7SW50ZWdlcn1cbiAqL1xuZnVuY3Rpb24gTW9kZWxQYXRoJHB1c2goKSB7IC8vIGFyZ3VtZW50c1xuICAgIHZhciBsZW5ndGggPSB0aGlzLmxlbigpO1xuICAgIHZhciBuZXdMZW5ndGggPSBsZW5ndGggKyBhcmd1bWVudHMubGVuZ3RoO1xuXG4gICAgXy5zcGxpY2UoYXJndW1lbnRzLCAwLCAwLCBsZW5ndGgsIDApO1xuICAgIHRoaXMuc3BsaWNlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICByZXR1cm4gbmV3TGVuZ3RoO1xufVxuXG5cbi8qKlxuICogTW9kZWxQYXRoIGFuZCBNb2RlbCBpbnN0YW5jZSBtZXRob2RcbiAqIFJlbW92ZXMgaXRlbSBmcm9tIHRoZSBlbmQgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkuIFJldHVybnMgdGhpcyBpdGVtLlxuICpcbiAqIEByZXR1cm4ge0FueX1cbiAqL1xuZnVuY3Rpb24gTW9kZWxQYXRoJHBvcCgpIHtcbiAgICByZXR1cm4gdGhpcy5zcGxpY2UodGhpcy5sZW4oKSAtIDEsIDEpWzBdO1xufVxuXG5cbi8qKlxuICogTW9kZWxQYXRoIGFuZCBNb2RlbCBpbnN0YW5jZSBtZXRob2RcbiAqIEluc2VydHMgaXRlbXMgdG8gdGhlIGJlZ2lubmluZyBvZiB0aGUgYXJyYXkuIFJldHVybnMgbmV3IGxlbmd0aC5cbiAqXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBpdGVtcyB0byBiZSBpbnNlcnRlZCBpbiB0aGUgYmVnaW5uaW5nIG9mIGFycmF5XG4gKiBAcmV0dXJuIHtJbnRlZ2VyfVxuICovXG5mdW5jdGlvbiBNb2RlbFBhdGgkdW5zaGlmdCgpIHsgLy8gYXJndW1lbnRzXG4gICAgdmFyIGxlbmd0aCA9IHRoaXMubGVuKCk7XG4gICAgbGVuZ3RoICs9IGFyZ3VtZW50cy5sZW5ndGg7XG5cbiAgICBfLnNwbGljZShhcmd1bWVudHMsIDAsIDAsIDAsIDApO1xuICAgIHRoaXMuc3BsaWNlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICByZXR1cm4gbGVuZ3RoO1xufVxuXG5cbi8qKlxuICogTW9kZWxQYXRoIGFuZCBNb2RlbCBpbnN0YW5jZSBtZXRob2RcbiAqIFJlbW92ZXMgdGhlIGl0ZW0gZnJvbSB0aGUgYmVnaW5uaW5nIG9mIGFycmF5IChvciBwc2V1ZG8tYXJyYXkpLiBSZXR1cm5zIHRoaXMgaXRlbS5cbiAqXG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmZ1bmN0aW9uIE1vZGVsUGF0aCRzaGlmdCgpIHsgLy8gYXJndW1lbnRzXG4gICAgcmV0dXJuIHRoaXMuc3BsaWNlKDAsIDEpWzBdO1xufVxuXG5cbi8qKlxuICogTW9kZWxQYXRoIGluc3RhbmNlIG1ldGhvZFxuICogSW5pdGlhbGl6ZXMgTW9kZWxQYXRoIG1lc2VuZ2VyIHdpdGggTW9kZWwncyBtZXNzZW5nZXIgYXMgaXRzIHNvdXJjZSAoW01lc3Nlbmdlck1lc3NhZ2VTb3VyY2VdKC4uL21lc3Nlbmdlci9tc25ncl9zb3VyY2UuanMuaHRtbCkpIGFuZCBbTW9kZWxQYXRoTXNnQVBJXSguL3BhdGhfbXNnX2FwaS5qcy5odG1sKSBhcyBbTWVzc2VuZ2VyQVBJXSguLi9tZXNzZW5nZXIvbV9hcGkuanMuaHRtbClcbiAqL1xuZnVuY3Rpb24gX3ByZXBhcmVNZXNzZW5nZXIoKSB7XG4gICAgdmFyIG1QYXRoQVBJID0gbmV3IE1vZGVsUGF0aE1zZ0FQSSh0aGlzLl9hY2Nlc3NQYXRoKTtcblxuICAgIC8vIGNyZWF0ZSBNZXNzZW5nZXJNZXNzYWdlU291cmNlIGNvbm5lY3RlZCB0byBNb2RlbCdzIG1lc3NlbmdlclxuICAgIHZhciBtb2RlbE1lc3NhZ2VTb3VyY2UgPSBuZXcgTWVzc2VuZ2VyTWVzc2FnZVNvdXJjZSh0aGlzLCB1bmRlZmluZWQsIG1QYXRoQVBJLCB0aGlzLl9tb2RlbCk7XG5cbiAgICAvLyBjcmVhdGUgbWVzc2VuZ2VyIHdpdGggbW9kZWwgcGFzc2VkIGFzIGhvc3RPYmplY3QgKGRlZmF1bHQgbWVzc2FnZSBkaXNwYXRjaCBjb250ZXh0KVxuICAgIC8vIGFuZCB3aXRob3V0IHByb3h5aW5nIG1ldGhvZHMgKHdlIGRvbid0IHdhbnQgdG8gcHJveHkgdGhlbSB0byBNb2RlbClcbiAgICB2YXIgbVBhdGhNZXNzZW5nZXIgPSBuZXcgTWVzc2VuZ2VyKHRoaXMsIHVuZGVmaW5lZCwgbW9kZWxNZXNzYWdlU291cmNlKTtcblxuICAgIC8vIHN0b3JlIG1lc3NlbmdlciBvbiBNb2RlbFBhdGggaW5zdGFuY2VcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsIE1FU1NFTkdFUl9QUk9QRVJUWSwgbVBhdGhNZXNzZW5nZXIpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgb2JqZWN0IGFsbG93aW5nIHRvIHJlY3JlYXRlIG1vZGVsIHBhdGhcbiAqXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIF9nZXREZWZpbml0aW9uKCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIG1vZGVsOiB0aGlzLl9tb2RlbCxcbiAgICAgICAgcGF0aDogdGhpcy5fcGF0aCxcbiAgICAgICAgYXJnczogdGhpcy5fYXJnc1xuICAgIH07XG59XG5cblxuLyoqXG4gKiBDbGFzcyBtZXRob2RcbiAqIENyZWF0ZXMgbW9kZWxQYXRoIG9iamVjdCBmcm9tIGRlZmluaXRpb24gY3JlYXRlZCBieSBfZ2V0RGVmaW5pdGlvblxuICpcbiAqIEBwYXJhbSAge09iamVjdH0gZGVmaW5pdGlvblxuICogQHJldHVybiB7TW9kZWxQYXRofVxuICovXG5mdW5jdGlvbiBfY3JlYXRlRnJvbURlZmluaXRpb24oZGVmaW5pdGlvbikge1xuICAgIGNoZWNrKGRlZmluaXRpb24sIHtcbiAgICAgICAgbW9kZWw6IEZ1bmN0aW9uLCAvLyBNb2RlbFxuICAgICAgICBwYXRoOiBTdHJpbmcsXG4gICAgICAgIGFyZ3M6IEFycmF5XG4gICAgfSk7XG5cbiAgICB2YXIgbSA9IGRlZmluaXRpb24ubW9kZWw7XG5cbiAgICByZXR1cm4gbS5hcHBseShtLCBkZWZpbml0aW9uLmFyZ3MpO1xufVxuXG5cbmZ1bmN0aW9uIE1vZGVsUGF0aCRkZXN0cm95KCkge1xuICAgIHRoaXNbTUVTU0VOR0VSX1BST1BFUlRZXS5kZXN0cm95KCk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIG1vZGVsVXRpbHMgPSB7XG4gICAgbm9ybWFsaXplU3BsaWNlSW5kZXg6IG5vcm1hbGl6ZVNwbGljZUluZGV4XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IG1vZGVsVXRpbHM7XG5cblxuZnVuY3Rpb24gbm9ybWFsaXplU3BsaWNlSW5kZXgoc3BsaWNlSW5kZXgsIGxlbmd0aCkge1xuICAgIHJldHVybiBzcGxpY2VJbmRleCA+IGxlbmd0aFxuICAgICAgICAgICAgPyBsZW5ndGhcbiAgICAgICAgICAgIDogc3BsaWNlSW5kZXggPj0gMFxuICAgICAgICAgICAgICAgID8gc3BsaWNlSW5kZXhcbiAgICAgICAgICAgICAgICA6IHNwbGljZUluZGV4ICsgbGVuZ3RoID4gMFxuICAgICAgICAgICAgICAgICAgICA/IHNwbGljZUluZGV4ICsgbGVuZ3RoXG4gICAgICAgICAgICAgICAgICAgIDogMDtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIE1lc3NlbmdlckFQSSA9IHJlcXVpcmUoJy4uL21lc3Nlbmdlci9tX2FwaScpXG4gICAgLCBwYXRoVXRpbHMgPSByZXF1aXJlKCcuL3BhdGhfdXRpbHMnKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vdXRpbC9sb2dnZXInKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbi8qKlxuICogU3ViY2xhc3Mgb2YgTWVzc2VuZ2VyQVBJIHRoYXQgaXMgdXNlZCB0byB0cmFuc2xhdGUgbWVzc2FnZXMgb2YgTWVzc2VuZ2VyIG9uIE1vZGVsUGF0aCB0byBNZXNzZW5nZXIgb24gTW9kZWwuXG4gKi9cbnZhciBNb2RlbFBhdGhNc2dBUEkgPSBfLmNyZWF0ZVN1YmNsYXNzKE1lc3NlbmdlckFQSSwgJ01vZGVsUGF0aE1zZ0FQSScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1vZGVsUGF0aE1zZ0FQSTtcblxuXG4vKipcbiAqICMjIyNNb2RlbFBhdGhNc2dBUEkgaW5zdGFuY2UgbWV0aG9kcyMjIyNcbiAqXG4gKiAtIFtpbml0XSgjaW5pdCkgLSBpbml0aWFsaXplcyBNb2RlbFBhdGhNc2dBUElcbiAqIC0gW3RyYW5zbGF0ZVRvU291cmNlTWVzc2FnZV0oI3RyYW5zbGF0ZVRvU291cmNlTWVzc2FnZSkgLSB0cmFuc2xhdGVzIHJlbGF0aXZlIGFjY2VzcyBwYXRocyBvZiBNb2RlbFBhdGggdG8gZnVsbCBwYXRoIG9mIE1vZGVsXG4gKiAtIFtjcmVhdGVJbnRlcm5hbERhdGFdKCNjcmVhdGVJbnRlcm5hbERhdGEpIC0gY2hhbmdlcyBwYXRoIGluIG1lc3NhZ2Ugb24gbW9kZWwgdG8gcmVsYXRpdmUgcGF0aCBhbmQgYWRkcyBgZnVsbFBhdGhgIHByb3BlcnR5IHRvIG1lc3NhZ2UgZGF0YVxuICovXG5fLmV4dGVuZFByb3RvKE1vZGVsUGF0aE1zZ0FQSSwge1xuICAgIGluaXQ6IGluaXQsXG4gICAgdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlOiB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UsXG4gICAgY3JlYXRlSW50ZXJuYWxEYXRhOiBjcmVhdGVJbnRlcm5hbERhdGEsXG59KTtcblxuXG4vKipcbiAqIE1vZGVsUGF0aE1zZ0FQSSBpbnN0YW5jZSBtZXRob2RcbiAqIENhbGxlZCBieSBNZXNzZW5nZXJBUEkgY29uc3RydWN0b3IuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHJvb3RQYXRoIHJvb3QgcGF0aCBvZiBtb2RlbCBwYXRoXG4gKi9cbmZ1bmN0aW9uIGluaXQocm9vdFBhdGgpIHtcbiAgICBNZXNzZW5nZXJBUEkucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB0aGlzLnJvb3RQYXRoID0gcm9vdFBhdGg7XG59XG5cbi8qKlxuICogTW9kZWxQYXRoTXNnQVBJIGluc3RhbmNlIG1ldGhvZFxuICogVHJhbnNsYXRlcyByZWxhdGl2ZSBhY2Nlc3MgcGF0aHMgb2YgTW9kZWxQYXRoIHRvIGZ1bGwgcGF0aCBvZiBNb2RlbC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gYWNjZXNzUGF0aCByZWxhdGl2ZSBhY2Nlc3MgcGF0aCB0byBiZSB0cmFuc2xhdGVkXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZShtZXNzYWdlKSB7XG4gICAgLy8gVE9ETyBzaG91bGQgcHJlcGVuZCBSZWdFeGVzXG4gICAgLy8gVE9ETyBzaG91bGQgbm90IHByZXBlbmQgY2hhbmdlZGF0YSB0b28/Pz9cbiAgICBpZiAobWVzc2FnZSBpbnN0YW5jZW9mIFJlZ0V4cClcbiAgICAgICAgcmV0dXJuIG1lc3NhZ2U7XG4gICAgaWYgKG1lc3NhZ2UgPT0gJ2RhdGFjaGFuZ2VzJylcbiAgICAgICAgcmV0dXJuIG1lc3NhZ2U7XG4gICAgXG4gICAgcmV0dXJuIHRoaXMucm9vdFBhdGggKyBtZXNzYWdlO1xufVxuXG5cbi8qKlxuICogTW9kZWxQYXRoTXNnQVBJIGluc3RhbmNlIG1ldGhvZFxuICogQ2hhbmdlcyBwYXRoIGluIG1lc3NhZ2Ugb24gbW9kZWwgdG8gcmVsYXRpdmUgcGF0aCBhbmQgYWRkcyBgZnVsbFBhdGhgIHByb3BlcnR5IHRvIG1lc3NhZ2UgZGF0YS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gc291cmNlTWVzc2FnZSBmdWxsIGFjY2VzcyBwYXRoIG9uIE1vZGVsXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSByZWxhdGl2ZSBhY2Nlc3MgcGF0aCBvbiBNb2RlbFBhdGhcbiAqIEBwYXJhbSB7T2JqZWN0fSBzb3VyY2VEYXRhIGRhdGEgcmVjZWl2ZWQgZnJvbSBNb2RlbCwgd2lsbCBiZSB0cmFuc2xhdGVkIGFzIGRlc2NyaWJlZCB0byBiZSBkaXNwYXRjaGVkIHRvIE1vZGVsUGF0aFxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBjcmVhdGVJbnRlcm5hbERhdGEoc291cmNlTWVzc2FnZSwgbWVzc2FnZSwgc291cmNlRGF0YSkge1xuICAgIC8vIFRPRE8gcmV0dXJuIG9uIGNoYW5nZWRhdGEgdG9vPz8/XG4gICAgaWYgKG1lc3NhZ2UgPT0gJ2RhdGFjaGFuZ2VzJykge1xuICAgICAgICB2YXIgaW50ZXJuYWxDaGFuZ2VzID0gc291cmNlRGF0YS5jaGFuZ2VzXG4gICAgICAgICAgICAubWFwKHRydW5jYXRlQ2hhbmdlUGF0aCwgdGhpcylcbiAgICAgICAgICAgIC5maWx0ZXIoZnVuY3Rpb24oY2hhbmdlKSB7IHJldHVybiBjaGFuZ2U7IH0pO1xuICAgICAgICB2YXIgaW50ZXJuYWxEYXRhID0ge1xuICAgICAgICAgICAgY2hhbmdlczogaW50ZXJuYWxDaGFuZ2VzLFxuICAgICAgICAgICAgdHJhbnNhY3Rpb246IHNvdXJjZURhdGEudHJhbnNhY3Rpb25cbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gaW50ZXJuYWxEYXRhXG4gICAgfVxuXG4gICAgdmFyIGludGVybmFsRGF0YSA9IHRydW5jYXRlQ2hhbmdlUGF0aC5jYWxsKHRoaXMsIHNvdXJjZURhdGEpO1xuICAgIHJldHVybiBpbnRlcm5hbERhdGE7XG59XG5cblxuZnVuY3Rpb24gdHJ1bmNhdGVDaGFuZ2VQYXRoKGNoYW5nZSkge1xuICAgIHZhciBmdWxsUGF0aCA9IGNoYW5nZS5wYXRoXG4gICAgICAgICwgcGF0aCA9IF8udW5QcmVmaXgoZnVsbFBhdGgsIHRoaXMucm9vdFBhdGgpO1xuXG4gICAgaWYgKHR5cGVvZiBwYXRoID09ICdzdHJpbmcnKSB7XG4gICAgICAgIHZhciBjaGFuZ2UgPSBfLmNsb25lKGNoYW5nZSk7XG4gICAgICAgIGNoYW5nZS5mdWxsUGF0aCA9IGZ1bGxQYXRoO1xuICAgICAgICBjaGFuZ2UucGF0aCA9IHBhdGg7XG4gICAgICAgIHJldHVybiBjaGFuZ2U7XG4gICAgfVxufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyA8YSBuYW1lPVwibW9kZWwtcGF0aFwiPjwvYT5cbi8vICMjIyBtb2RlbCBwYXRoIHV0aWxzXG5cbnZhciBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBNb2RlbEVycm9yID0gcmVxdWlyZSgnLi4vdXRpbC9lcnJvcicpLk1vZGVsO1xuXG52YXIgcGF0aFV0aWxzID0ge1xuICAgIHBhcnNlQWNjZXNzUGF0aDogcGFyc2VBY2Nlc3NQYXRoLFxuICAgIGNyZWF0ZVJlZ2V4UGF0aDogY3JlYXRlUmVnZXhQYXRoLFxuICAgIGdldFBhdGhOb2RlS2V5OiBnZXRQYXRoTm9kZUtleSxcbiAgICB3cmFwTWVzc2VuZ2VyTWV0aG9kczogd3JhcE1lc3Nlbmdlck1ldGhvZHNcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gcGF0aFV0aWxzO1xuXG5cbnZhciBwcm9wZXJ0eVBhdGhTeW50YXggPSAnXFxcXC5bQS1aYS16Xy1dW0EtWmEtejAtOV8tXSonXG4gICAgLCBhcnJheVBhdGhTeW50YXggPSAnXFxcXFtbMC05XStcXFxcXSdcbiAgICAsIGludGVycG9sYXRpb25TeW50YXggPSAnXFxcXCRbMS05XVswLTldKidcbiAgICAsIHByb3BlcnR5SW50ZXJwb2xhdGVTeW50YXggPSAnXFxcXC4nICsgaW50ZXJwb2xhdGlvblN5bnRheFxuICAgICwgYXJyYXlJbnRlcnBvbGF0ZVN5bnRheCA9ICdcXFxcWycgKyBpbnRlcnBvbGF0aW9uU3ludGF4ICsgJ1xcXFxdJ1xuXG4gICAgLCBwcm9wZXJ0eVN0YXJTeW50YXggPSAnXFxcXC5cXFxcKidcbiAgICAsIGFycmF5U3RhclN5bnRheCA9ICdcXFxcW1xcXFwqXFxcXF0nXG4gICAgLCBzdGFyU3ludGF4ID0gJ1xcXFwqJ1xuXG4gICAgLCBwYXRoUGFyc2VTeW50YXggPSBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcGVydHlQYXRoU3ludGF4LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmF5UGF0aFN5bnRheCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9wZXJ0eUludGVycG9sYXRlU3ludGF4LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmF5SW50ZXJwb2xhdGVTeW50YXhcbiAgICAgICAgICAgICAgICAgICAgICAgIF0uam9pbignfCcpXG4gICAgLCBwYXRoUGFyc2VQYXR0ZXJuID0gbmV3IFJlZ0V4cChwYXRoUGFyc2VTeW50YXgsICdnJylcblxuICAgICwgcGF0dGVyblBhdGhQYXJzZVN5bnRheCA9ICBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXRoUGFyc2VTeW50YXgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9wZXJ0eVN0YXJTeW50YXgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcnJheVN0YXJTeW50YXgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFyU3ludGF4XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0uam9pbignfCcpXG4gICAgLCBwYXR0ZXJuUGF0aFBhcnNlUGF0dGVybiA9IG5ldyBSZWdFeHAocGF0dGVyblBhdGhQYXJzZVN5bnRheCwgJ2cnKVxuXG4gICAgLy8sIHRhcmdldFBhdGhQYXJzZVBhdHRlcm4gPSAvXFwuW0EtWmEtel1bQS1aYS16MC05X10qfFxcW1swLTldK1xcXXxcXC5cXCRbMS05XVswLTldKnxcXFtcXCRbMS05XVswLTldKlxcXXxcXCRbMS05XVswLTldL2dcbiAgICAsIHBhdGhOb2RlVHlwZXMgPSB7XG4gICAgICAgICcuJzogeyBzeW50YXg6ICdvYmplY3QnLCBlbXB0eTogJ3t9JyB9LFxuICAgICAgICAnWyc6IHsgc3ludGF4OiAnYXJyYXknLCBlbXB0eTogJ1tdJ30sXG4gICAgICAgICcqJzogeyBzeW50YXg6ICdtYXRjaCcsIGVtcHR5OiAne30nfSxcbiAgICB9O1xuXG5mdW5jdGlvbiBwYXJzZUFjY2Vzc1BhdGgocGF0aCwgbm9kZVBhcnNlUGF0dGVybikge1xuICAgIG5vZGVQYXJzZVBhdHRlcm4gPSBub2RlUGFyc2VQYXR0ZXJuIHx8IHBhdGhQYXJzZVBhdHRlcm47XG5cbiAgICB2YXIgcGFyc2VkUGF0aCA9IFtdO1xuXG4gICAgaWYgKCEgcGF0aClcbiAgICAgICAgcmV0dXJuIHBhcnNlZFBhdGg7XG5cbiAgICB2YXIgdW5wYXJzZWQgPSBwYXRoLnJlcGxhY2Uobm9kZVBhcnNlUGF0dGVybiwgZnVuY3Rpb24obm9kZVN0cikge1xuICAgICAgICB2YXIgcGF0aE5vZGUgPSB7IHByb3BlcnR5OiBub2RlU3RyIH07XG4gICAgICAgIF8uZXh0ZW5kKHBhdGhOb2RlLCBwYXRoTm9kZVR5cGVzW25vZGVTdHJbMF1dKTtcbiAgICAgICAgaWYgKG5vZGVTdHJbMV0gPT0gJyQnKVxuICAgICAgICAgICAgcGF0aE5vZGUuaW50ZXJwb2xhdGUgPSBnZXRQYXRoTm9kZUtleShwYXRoTm9kZSwgdHJ1ZSk7XG5cbiAgICAgICAgcGFyc2VkUGF0aC5wdXNoKHBhdGhOb2RlKTtcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH0pO1xuICAgIGlmICh1bnBhcnNlZClcbiAgICAgICAgdGhyb3cgbmV3IE1vZGVsRXJyb3IoJ2luY29ycmVjdCBtb2RlbCBwYXRoOiAnICsgcGF0aCk7XG5cbiAgICByZXR1cm4gcGFyc2VkUGF0aDtcbn1cblxuXG52YXIgbm9kZVJlZ2V4ID0ge1xuICAgICcuKic6IHByb3BlcnR5UGF0aFN5bnRheCxcbiAgICAnWypdJzogYXJyYXlQYXRoU3ludGF4XG59O1xubm9kZVJlZ2V4WycqJ10gPSBub2RlUmVnZXhbJy4qJ10gKyAnfCcgKyBub2RlUmVnZXhbJ1sqXSddO1xuXG5mdW5jdGlvbiBjcmVhdGVSZWdleFBhdGgocGF0aCkge1xuICAgIGNoZWNrKHBhdGgsIE1hdGNoLk9uZU9mKFN0cmluZywgUmVnRXhwKSk7XG5cbiAgICBpZiAocGF0aCBpbnN0YW5jZW9mIFJlZ0V4cCB8fCBwYXRoLmluZGV4T2YoJyonKSA9PSAtMSlcbiAgICAgICAgcmV0dXJuIHBhdGg7XG5cbiAgICB2YXIgcGFyc2VkUGF0aCA9IHBhdGhVdGlscy5wYXJzZUFjY2Vzc1BhdGgocGF0aCwgcGF0dGVyblBhdGhQYXJzZVBhdHRlcm4pXG4gICAgICAgICwgcmVnZXhTdHIgPSAnXidcbiAgICAgICAgLy8gLCByZWdleFN0ckVuZCA9ICcnXG4gICAgICAgICwgcGF0dGVybnNTdGFydGVkID0gZmFsc2U7XG5cbiAgICBwYXJzZWRQYXRoLmZvckVhY2goZnVuY3Rpb24ocGF0aE5vZGUpIHtcbiAgICAgICAgdmFyIHByb3AgPSBwYXRoTm9kZS5wcm9wZXJ0eVxuICAgICAgICAgICAgLCByZWdleCA9IG5vZGVSZWdleFtwcm9wXTtcbiAgICAgICAgXG4gICAgICAgIGlmIChyZWdleCkge1xuICAgICAgICAgICAgLy8gcmVnZXhTdHIgKz0gJygnICsgcmVnZXg7XG4gICAgICAgICAgICAvLyByZWdleFN0ckVuZCArPSAnfCknO1xuICAgICAgICAgICAgcmVnZXhTdHIgKz0gJygnICsgcmVnZXggKyAnfCknO1xuICAgICAgICAgICAgLy8gcmVnZXhTdHJFbmQgKz0gJ3wpJztcbiAgICAgICAgICAgIHBhdHRlcm5zU3RhcnRlZCA9IHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBpZiAocGF0dGVybnNTdGFydGVkKVxuICAgICAgICAgICAgLy8gIHRocm93IG5ldyBNb2RlbEVycm9yKCdcIipcIiBwYXRoIHNlZ21lbnQgY2Fubm90IGJlIGluIHRoZSBtaWRkbGUgb2YgdGhlIHBhdGg6ICcgKyBwYXRoKTtcbiAgICAgICAgICAgIHJlZ2V4U3RyICs9IHByb3AucmVwbGFjZSgvKFxcLnxcXFt8XFxdKS9nLCAnXFxcXCQxJyk7IC8vIGFkZCBzbGFzaCBpbiBmcm9udCBvZiBzeW1ib2xzIHRoYXQgaGF2ZSBzcGVjaWFsIG1lYW5pbmcgaW4gcmVnZXhcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmVnZXhTdHIgKz0gLyogcmVnZXhTdHJFbmQgKyAqLyAnJCc7XG5cbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gbmV3IFJlZ0V4cChyZWdleFN0cik7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBuZXcgTW9kZWxFcnJvcignY2FuXFwndCBjb25zdHJ1Y3QgcmVnZXggZm9yIHBhdGggcGF0dGVybjogJyArIHBhdGgpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBnZXRQYXRoTm9kZUtleShwYXRoTm9kZSwgaW50ZXJwb2xhdGVkKSB7XG4gICAgdmFyIHByb3AgPSBwYXRoTm9kZS5wcm9wZXJ0eVxuICAgICAgICAsIHN0YXJ0SW5kZXggPSBpbnRlcnBvbGF0ZWQgPyAyIDogMTtcbiAgICByZXR1cm4gcGF0aE5vZGUuc3ludGF4ID09ICdhcnJheSdcbiAgICAgICAgPyBwcm9wLnNsaWNlKHN0YXJ0SW5kZXgsIHByb3AubGVuZ3RoIC0gMSlcbiAgICAgICAgOiBwcm9wLnNsaWNlKHN0YXJ0SW5kZXgpO1xufVxuXG5cbi8vIFRPRE8gYWxsb3cgZm9yIG11bHRpcGxlIG1lc3NhZ2VzIGluIGEgc3RyaW5nXG5mdW5jdGlvbiB3cmFwTWVzc2VuZ2VyTWV0aG9kcyhtZXRob2RzTmFtZXMpIHtcbiAgICBtZXRob2RzTmFtZXMgPSBtZXRob2RzTmFtZXMgfHwgWydvbicsICdvZmYnXTtcbiAgICB2YXIgd3JhcHBlZE1ldGhvZHMgPSBfLm1hcFRvT2JqZWN0KG1ldGhvZHNOYW1lcywgZnVuY3Rpb24obWV0aG9kTmFtZSkge1xuICAgICAgICB2YXIgb3JpZ01ldGhvZCA9IHRoaXNbbWV0aG9kTmFtZV07XG4gICAgICAgIC8vIHJlcGxhY2luZyBtZXNzYWdlIHN1YnNyaWJlL3Vuc3Vic2NyaWJlL2V0Yy4gdG8gY29udmVydCBcIipcIiBtZXNzYWdlIHBhdHRlcm5zIHRvIHJlZ2V4cHNcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKHBhdGgsIHN1YnNjcmliZXIpIHtcbiAgICAgICAgICAgIHZhciByZWdleFBhdGggPSBjcmVhdGVSZWdleFBhdGgocGF0aCk7XG4gICAgICAgICAgICBvcmlnTWV0aG9kLmNhbGwodGhpcywgcmVnZXhQYXRoLCBzdWJzY3JpYmVyKTtcbiAgICAgICAgfTtcbiAgICB9LCB0aGlzKTtcbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywgd3JhcHBlZE1ldGhvZHMpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcGF0aFV0aWxzID0gcmVxdWlyZSgnLi4vcGF0aF91dGlscycpXG4gICAgLCBtb2RlbFV0aWxzID0gcmVxdWlyZSgnLi4vbW9kZWxfdXRpbHMnKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9sb2dnZXInKVxuICAgICwgbWlsb0NvdW50ID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9jb3VudCcpXG4gICAgLCBmcyA9IHJlcXVpcmUoJ2ZzJylcbiAgICAsIGRvVCA9IHJlcXVpcmUoJ2RvdCcpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoYW5nZURhdGFIYW5kbGVyID0gcmVxdWlyZSgnLi4vY2hhbmdlX2RhdGEnKVxuICAgICwgZ2V0VHJhbnNhY3Rpb25GbGFnID0gY2hhbmdlRGF0YUhhbmRsZXIuZ2V0VHJhbnNhY3Rpb25GbGFnXG4gICAgLCBwb3N0VHJhbnNhY3Rpb25GaW5pc2hlZCA9IGNoYW5nZURhdGFIYW5kbGVyLnBvc3RUcmFuc2FjdGlvbkZpbmlzaGVkO1xuXG5cbi8qKlxuICogVGVtcGxhdGVzIHRvIHN5bnRoZXNpemUgbW9kZWwgZ2V0dGVycyBhbmQgc2V0dGVyc1xuICovXG52YXIgdGVtcGxhdGVzID0ge1xuICAgIGdldDogXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG5tZXRob2QgPSBmdW5jdGlvbiBnZXQoKSB7XFxuICAgIHZhciBtID0ge3sjIGRlZi5tb2RlbEFjY2Vzc1ByZWZpeCB9fTtcXG4gICAgcmV0dXJuIG0ge3t+IGl0LnBhcnNlZFBhdGggOnBhdGhOb2RlIH19XFxuICAgICAgICB7ez8gcGF0aE5vZGUuaW50ZXJwb2xhdGV9fVxcbiAgICAgICAgICAgICYmIChtID0gbVt0aGlzLl9hcmdzWyB7ez0gcGF0aE5vZGUuaW50ZXJwb2xhdGUgfX0gXV0pXFxuICAgICAgICB7ez8/fX1cXG4gICAgICAgICAgICAmJiAobSA9IG17ez0gcGF0aE5vZGUucHJvcGVydHkgfX0pXFxuICAgICAgICB7ez99fSB7e359fTtcXG59O1xcblwiLFxuICAgIHNldDogXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG57eyMgZGVmLmluY2x1ZGVfZGVmaW5lcyB9fVxcbnt7IyBkZWYuaW5jbHVkZV9jcmVhdGVfdHJlZSB9fVxcblxcblxcbi8qKlxcbiAqIFRlbXBsYXRlIHRoYXQgc3ludGhlc2l6ZXMgc2V0dGVyIGZvciBNb2RlbCBhbmQgZm9yIE1vZGVsUGF0aFxcbiAqL1xcbm1ldGhvZCA9IGZ1bmN0aW9uIHNldCh2YWx1ZSkge1xcbiAgICB7eyMgZGVmLmluaXRWYXJzOidzZXQnIH19XFxuXFxuICAgIHt7IyBkZWYuY3JlYXRlVHJlZTonc2V0JyB9fVxcblxcbiAgICB7e1xcbiAgICAgICAgY3Vyck5vZGUgPSBuZXh0Tm9kZTtcXG4gICAgICAgIGN1cnJQcm9wID0gY3Vyck5vZGUgJiYgY3Vyck5vZGUucHJvcGVydHk7XFxuICAgIH19XFxuXFxuICAgIHt7IC8qIGFzc2lnbiB2YWx1ZSB0byB0aGUgbGFzdCBwcm9wZXJ0eSAqLyB9fVxcbiAgICB7ez8gY3VyclByb3AgfX1cXG4gICAgICAgIHdhc0RlZiA9IHt7IyBkZWYud2FzRGVmaW5lZH19O1xcbiAgICAgICAge3sjIGRlZi5jaGFuZ2VBY2Nlc3NQYXRoIH19XFxuXFxuICAgICAgICB2YXIgb2xkID0gbXt7IyBkZWYuY3VyclByb3AgfX07XFxuXFxuICAgICAgICB7eyAvKiBjbG9uZSB2YWx1ZSB0byBwcmV2ZW50IHNhbWUgcmVmZXJlbmNlIGluIGxpbmtlZCBtb2RlbHMgKi8gfX1cXG4gICAgICAgIG17eyMgZGVmLmN1cnJQcm9wIH19ID0gY2xvbmVUcmVlKHZhbHVlKTtcXG4gICAge3s/fX1cXG5cXG4gICAge3sgLyogYWRkIG1lc3NhZ2UgcmVsYXRlZCB0byB0aGUgbGFzdCBwcm9wZXJ0eSBjaGFuZ2UgKi8gfX1cXG4gICAgaWYgKHRoaXMuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XFxuICAgICAgICBpZiAoISB3YXNEZWYpXFxuICAgICAgICAgICAge3sjIGRlZi5hZGRNc2cgfX0gYWNjZXNzUGF0aCwgdHlwZTogJ2FkZGVkJyxcXG4gICAgICAgICAgICAgICAgbmV3VmFsdWU6IHZhbHVlIH0pO1xcbiAgICAgICAgZWxzZSBpZiAob2xkICE9IHZhbHVlKVxcbiAgICAgICAgICAgIHt7IyBkZWYuYWRkTXNnIH19IGFjY2Vzc1BhdGgsIHR5cGU6ICdjaGFuZ2VkJyxcXG4gICAgICAgICAgICAgICAgb2xkVmFsdWU6IG9sZCwgbmV3VmFsdWU6IHZhbHVlIH0pO1xcblxcbiAgICAgICAge3sgLyogYWRkIG1lc3NhZ2UgcmVsYXRlZCB0byBjaGFuZ2VzIGluIChzdWIpcHJvcGVydGllcyBpbnNpZGUgcmVtb3ZlZCBhbmQgYXNzaWduZWQgdmFsdWUgKi8gfX1cXG4gICAgICAgIGlmICghIHdhc0RlZiB8fCBvbGQgIT0gdmFsdWUpXFxuICAgICAgICAgICAgYWRkVHJlZUNoYW5nZXNNZXNzYWdlcyhtZXNzYWdlcywgbWVzc2FnZXNIYXNoLFxcbiAgICAgICAgICAgICAgICBhY2Nlc3NQYXRoLCBvbGQsIHZhbHVlKTsgLyogZGVmaW5lZCBpbiB0aGUgZnVuY3Rpb24gdGhhdCBzeW50aGVzaXplcyBNb2RlbFBhdGggc2V0dGVyICovXFxuXFxuICAgICAgICB7eyAvKiBwb3N0IGFsbCBzdG9yZWQgbWVzc2FnZXMgKi8gfX1cXG4gICAgICAgIHt7IyBkZWYucG9zdE1lc3NhZ2VzIH19XFxuICAgIH1cXG59O1xcblwiLFxuICAgIGRlbDogXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG57eyMgZGVmLmluY2x1ZGVfZGVmaW5lcyB9fVxcbnt7IyBkZWYuaW5jbHVkZV90cmF2ZXJzZV90cmVlIH19XFxuXFxubWV0aG9kID0gZnVuY3Rpb24gZGVsKCkge1xcbiAgICB7eyMgZGVmLmluaXRWYXJzOidkZWwnIH19XFxuXFxuICAgIHt7PyBpdC5wYXJzZWRQYXRoLmxlbmd0aCB9fVxcbiAgICAgICAge3sjIGRlZi50cmF2ZXJzZVRyZWUgfX1cXG5cXG4gICAgICAgIHt7XFxuICAgICAgICAgICAgdmFyIGN1cnJOb2RlID0gaXQucGFyc2VkUGF0aFtjb3VudF07XFxuICAgICAgICAgICAgdmFyIGN1cnJQcm9wID0gY3Vyck5vZGUucHJvcGVydHk7ICAgICAgIFxcbiAgICAgICAgfX1cXG5cXG4gICAgICAgIGlmICghIHRyZWVEb2VzTm90RXhpc3QgJiYgbSAmJiBtLmhhc093blByb3BlcnR5ICYmIHt7IyBkZWYud2FzRGVmaW5lZH19KSB7XFxuICAgICAgICAgICAgdmFyIG9sZCA9IG17eyMgZGVmLmN1cnJQcm9wIH19O1xcbiAgICAgICAgICAgIGRlbGV0ZSBte3sjIGRlZi5jdXJyUHJvcCB9fTtcXG4gICAgICAgICAgICB7eyMgZGVmLmNoYW5nZUFjY2Vzc1BhdGggfX1cXG4gICAgICAgICAgICB2YXIgZGlkRGVsZXRlID0gdHJ1ZTtcXG4gICAgICAgIH1cXG4gICAge3s/P319XFxuICAgICAgICBpZiAodHlwZW9mIG0gIT0gJ3VuZGVmaW5lZCcpIHtcXG4gICAgICAgICAgICB2YXIgb2xkID0gbTtcXG4gICAgICAgICAgICB7eyMgZGVmLm1vZGVsQWNjZXNzUHJlZml4IH19ID0gdW5kZWZpbmVkO1xcbiAgICAgICAgICAgIHZhciBkaWREZWxldGUgPSB0cnVlO1xcbiAgICAgICAgfVxcbiAgICB7ez99fVxcblxcbiAgICBpZiAoZGlkRGVsZXRlICYmIHRoaXMuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XFxuICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSBhY2Nlc3NQYXRoLCB0eXBlOiAnZGVsZXRlZCcsIG9sZFZhbHVlOiBvbGQgfSk7XFxuXFxuICAgICAgICBhZGRUcmVlQ2hhbmdlc01lc3NhZ2VzKG1lc3NhZ2VzLCBtZXNzYWdlc0hhc2gsXFxuICAgICAgICAgICAgYWNjZXNzUGF0aCwgb2xkLCB1bmRlZmluZWQpOyAvKiBkZWZpbmVkIGluIHRoZSBmdW5jdGlvbiB0aGF0IHN5bnRoZXNpemVzIE1vZGVsUGF0aCBzZXR0ZXIgKi9cXG5cXG4gICAgICAgIHt7IC8qIHBvc3QgYWxsIHN0b3JlZCBtZXNzYWdlcyAqLyB9fVxcbiAgICAgICAge3sjIGRlZi5wb3N0TWVzc2FnZXMgfX1cXG4gICAgfVxcbn07XFxuXCIsXG4gICAgc3BsaWNlOiBcIid1c2Ugc3RyaWN0JztcXG4vKiBPbmx5IHVzZSB0aGlzIHN0eWxlIG9mIGNvbW1lbnRzLCBub3QgXFxcIi8vXFxcIiAqL1xcblxcbnt7IyBkZWYuaW5jbHVkZV9kZWZpbmVzIH19XFxue3sjIGRlZi5pbmNsdWRlX2NyZWF0ZV90cmVlIH19XFxue3sjIGRlZi5pbmNsdWRlX3RyYXZlcnNlX3RyZWUgfX1cXG5cXG5tZXRob2QgPSBmdW5jdGlvbiBzcGxpY2Uoc3BsaWNlSW5kZXgsIHNwbGljZUhvd01hbnkpIHsgLyogLC4uLiAtIGV4dHJhIGFyZ3VtZW50cyB0byBzcGxpY2UgaW50byBhcnJheSAqL1xcbiAgICB7eyMgZGVmLmluaXRWYXJzOidzcGxpY2UnIH19XFxuXFxuICAgIHZhciBhcmdzTGVuID0gYXJndW1lbnRzLmxlbmd0aDtcXG4gICAgdmFyIGFkZEl0ZW1zID0gYXJnc0xlbiA+IDI7XFxuXFxuICAgIGlmIChhZGRJdGVtcykge1xcbiAgICAgICAge3sgLyogb25seSBjcmVhdGUgbW9kZWwgdHJlZSBpZiBpdGVtcyBhcmUgaW5zZXJ0ZWQgaW4gYXJyYXkgKi8gfX1cXG5cXG4gICAgICAgIHt7IC8qIGlmIG1vZGVsIGlzIHVuZGVmaW5lZCBpdCB3aWxsIGJlIHNldCB0byBhbiBlbXB0eSBhcnJheSAqLyB9fSAgXFxuICAgICAgICB2YXIgdmFsdWUgPSBbXTtcXG4gICAgICAgIHt7IyBkZWYuY3JlYXRlVHJlZTonc3BsaWNlJyB9fVxcblxcbiAgICAgICAge3s/IG5leHROb2RlIH19XFxuICAgICAgICAgICAge3tcXG4gICAgICAgICAgICAgICAgdmFyIGN1cnJOb2RlID0gbmV4dE5vZGU7XFxuICAgICAgICAgICAgICAgIHZhciBjdXJyUHJvcCA9IGN1cnJOb2RlLnByb3BlcnR5O1xcbiAgICAgICAgICAgICAgICB2YXIgZW1wdHlQcm9wID0gJ1tdJztcXG4gICAgICAgICAgICB9fVxcblxcbiAgICAgICAgICAgIHt7IyBkZWYuY3JlYXRlVHJlZVN0ZXAgfX1cXG4gICAgICAgIHt7P319XFxuXFxuICAgIH0gZWxzZSBpZiAoc3BsaWNlSG93TWFueSA+IDApIHtcXG4gICAgICAgIHt7IC8qIGlmIGl0ZW1zIGFyZSBub3QgaW5zZXJ0ZWQsIG9ubHkgdHJhdmVyc2UgbW9kZWwgdHJlZSBpZiBpdGVtcyBhcmUgZGVsZXRlZCBmcm9tIGFycmF5ICovIH19XFxuICAgICAgICB7ez8gaXQucGFyc2VkUGF0aC5sZW5ndGggfX1cXG4gICAgICAgICAgICB7eyMgZGVmLnRyYXZlcnNlVHJlZSB9fVxcblxcbiAgICAgICAgICAgIHt7XFxuICAgICAgICAgICAgICAgIHZhciBjdXJyTm9kZSA9IGl0LnBhcnNlZFBhdGhbY291bnRdO1xcbiAgICAgICAgICAgICAgICB2YXIgY3VyclByb3AgPSBjdXJyTm9kZS5wcm9wZXJ0eTsgICAgICAgXFxuICAgICAgICAgICAgfX1cXG5cXG4gICAgICAgICAgICB7eyAvKiBleHRyYSBicmFjZSBjbG9zZXMgJ2Vsc2UnIGluIGRlZi50cmF2ZXJzZVRyZWVTdGVwICovIH19XFxuICAgICAgICAgICAge3sjIGRlZi50cmF2ZXJzZVRyZWVTdGVwIH19IH1cXG4gICAgICAgIHt7P319XFxuICAgIH1cXG5cXG4gICAge3sgLyogc3BsaWNlIGl0ZW1zICovIH19XFxuICAgIGlmIChhZGRJdGVtcyB8fCAoISB0cmVlRG9lc05vdEV4aXN0ICYmIG1cXG4gICAgICAgICAgICAmJiBtLmxlbmd0aCA+IHNwbGljZUluZGV4ICkgKSB7XFxuICAgICAgICB2YXIgb2xkTGVuZ3RoID0gbS5sZW5ndGggPSBtLmxlbmd0aCB8fCAwO1xcblxcbiAgICAgICAgYXJndW1lbnRzWzBdID0gc3BsaWNlSW5kZXggPSBub3JtYWxpemVTcGxpY2VJbmRleChzcGxpY2VJbmRleCwgbS5sZW5ndGgpO1xcblxcbiAgICAgICAge3sgLyogY2xvbmUgYWRkZWQgYXJndW1lbnRzIHRvIHByZXZlbnQgc2FtZSByZWZlcmVuY2VzIGluIGxpbmtlZCBtb2RlbHMgKi8gfX1cXG4gICAgICAgIGlmIChhZGRJdGVtcylcXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMjsgaSA8IGFyZ3NMZW47IGkrKylcXG4gICAgICAgICAgICAgICAgYXJndW1lbnRzW2ldID0gY2xvbmVUcmVlKGFyZ3VtZW50c1tpXSk7XFxuXFxuICAgICAgICB7eyAvKiBhY3R1YWwgc3BsaWNlIGNhbGwgKi8gfX1cXG4gICAgICAgIHZhciByZW1vdmVkID0gQXJyYXkucHJvdG90eXBlLnNwbGljZS5hcHBseShtLCBhcmd1bWVudHMpO1xcblxcbiAgICAgICAgaWYgKHRoaXMuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XFxuICAgICAgICAgICAge3sjIGRlZi5hZGRNc2cgfX0gYWNjZXNzUGF0aCwgdHlwZTogJ3NwbGljZScsXFxuICAgICAgICAgICAgICAgICAgICBpbmRleDogc3BsaWNlSW5kZXgsIHJlbW92ZWQ6IHJlbW92ZWQsIGFkZGVkQ291bnQ6IGFkZEl0ZW1zID8gYXJnc0xlbiAtIDIgOiAwLFxcbiAgICAgICAgICAgICAgICAgICAgbmV3VmFsdWU6IG0gfSk7XFxuXFxuICAgICAgICAgICAgaWYgKHJlbW92ZWQgJiYgcmVtb3ZlZC5sZW5ndGgpXFxuICAgICAgICAgICAgICAgIHJlbW92ZWQuZm9yRWFjaChmdW5jdGlvbihpdGVtLCBpbmRleCkge1xcbiAgICAgICAgICAgICAgICAgICAgdmFyIGl0ZW1QYXRoID0gYWNjZXNzUGF0aCArICdbJyArIChzcGxpY2VJbmRleCArIGluZGV4KSArICddJztcXG4gICAgICAgICAgICAgICAgICAgIHt7IyBkZWYuYWRkTXNnIH19IGl0ZW1QYXRoLCB0eXBlOiAncmVtb3ZlZCcsIG9sZFZhbHVlOiBpdGVtIH0pO1xcblxcbiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlSXNUcmVlKGl0ZW0pKVxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFkZE1lc3NhZ2VzKG1lc3NhZ2VzLCBtZXNzYWdlc0hhc2gsIGl0ZW1QYXRoLCBpdGVtLCAncmVtb3ZlZCcsICdvbGRWYWx1ZScpO1xcbiAgICAgICAgICAgICAgICB9KTtcXG5cXG4gICAgICAgICAgICBpZiAoYWRkSXRlbXMpXFxuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAyOyBpIDwgYXJnc0xlbjsgaSsrKSB7XFxuICAgICAgICAgICAgICAgICAgICB2YXIgaXRlbSA9IGFyZ3VtZW50c1tpXTtcXG4gICAgICAgICAgICAgICAgICAgIHZhciBpdGVtUGF0aCA9IGFjY2Vzc1BhdGggKyAnWycgKyAoc3BsaWNlSW5kZXggKyBpIC0gMikgKyAnXSc7XFxuICAgICAgICAgICAgICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSBpdGVtUGF0aCwgdHlwZTogJ2FkZGVkJywgbmV3VmFsdWU6IGl0ZW0gfSk7XFxuXFxuICAgICAgICAgICAgICAgICAgICBpZiAodmFsdWVJc1RyZWUoaXRlbSkpXFxuICAgICAgICAgICAgICAgICAgICAgICAgYWRkTWVzc2FnZXMobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgaXRlbVBhdGgsIGl0ZW0sICdhZGRlZCcsICduZXdWYWx1ZScpO1xcbiAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAge3sgLyogcG9zdCBhbGwgc3RvcmVkIG1lc3NhZ2VzICovIH19XFxuICAgICAgICAgICAge3sjIGRlZi5wb3N0TWVzc2FnZXMgfX1cXG4gICAgICAgIH1cXG4gICAgfVxcblxcbiAgICByZXR1cm4gcmVtb3ZlZCB8fCBbXTtcXG59XFxuXCJcbn07XG5cbnZhciBpbmNsdWRlX2RlZmluZXMgPSBcIid1c2Ugc3RyaWN0JztcXG4vKiBPbmx5IHVzZSB0aGlzIHN0eWxlIG9mIGNvbW1lbnRzLCBub3QgXFxcIi8vXFxcIiAqL1xcblxcbi8qKlxcbiAqIEluc2VydHMgaW5pdGlhbGl6YXRpb24gY29kZVxcbiAqL1xcbiB7eyMjIGRlZi5pbml0VmFyczptZXRob2Q6XFxuICAgIHZhciBtID0ge3sjIGRlZi5tb2RlbEFjY2Vzc1ByZWZpeCB9fTtcXG4gICAgdmFyIG1lc3NhZ2VzID0gW10sIG1lc3NhZ2VzSGFzaCA9IHt9O1xcbiAgICB2YXIgYWNjZXNzUGF0aCA9ICcnO1xcbiAgICB2YXIgdHJlZURvZXNOb3RFeGlzdDtcXG4gICAgLyogaGFjayB0byBwcmV2ZW50IHNlbmRpbmcgZmluaXNoZWQgZXZlbnRzIHRvIGFsbG93IGZvciBwcm9wYWdhdGlvbiBvZiBiYXRjaGVzIHdpdGhvdXQgc3BsaXR0aW5nIHRoZW0gKi9cXG4gICAgdmFyIGluQ2hhbmdlVHJhbnNhY3Rpb24gPSBnZXRUcmFuc2FjdGlvbkZsYWcoIHt7PSBtZXRob2QgfX0gKTtcXG4gI319XFxuXFxuLyoqXFxuICogSW5zZXJ0cyB0aGUgYmVnaW5uaW5nIG9mIGZ1bmN0aW9uIGNhbGwgdG8gYWRkIG1lc3NhZ2UgdG8gbGlzdFxcbiAqL1xcbnt7IyMgZGVmLmFkZE1zZzogYWRkQ2hhbmdlTWVzc2FnZShtZXNzYWdlcywgbWVzc2FnZXNIYXNoLCB7IHBhdGg6ICN9fVxcblxcbi8qKlxcbiAqIEluc2VydHMgY3VycmVudCBwcm9wZXJ0eS9pbmRleCBmb3IgYm90aCBub3JtYWwgYW5kIGludGVycG9sYXRlZCBwcm9wZXJ0aWVzL2luZGV4ZXNcXG4gKi9cXG57eyMjIGRlZi5jdXJyUHJvcDp7ez8gY3Vyck5vZGUuaW50ZXJwb2xhdGUgfX1bdGhpcy5fYXJnc1sge3s9IGN1cnJOb2RlLmludGVycG9sYXRlIH19IF1de3s/P319e3s9IGN1cnJQcm9wIH19e3s/fX0gI319XFxuXFxuLyoqXFxuICogSW5zZXJ0cyBjb25kaXRpb24gdG8gdGVzdCB3aGV0aGVyIG5vcm1hbC9pbnRlcnBvbGF0ZWQgcHJvcGVydHkvaW5kZXggZXhpc3RzXFxuICovXFxue3sjIyBkZWYud2FzRGVmaW5lZDogbS5oYXNPd25Qcm9wZXJ0eShcXG4gICAge3s/IGN1cnJOb2RlLmludGVycG9sYXRlIH19XFxuICAgICAgICB0aGlzLl9hcmdzWyB7ez0gY3Vyck5vZGUuaW50ZXJwb2xhdGUgfX0gXVxcbiAgICB7ez8/fX1cXG4gICAgICAgICd7ez0gaXQuZ2V0UGF0aE5vZGVLZXkoY3Vyck5vZGUpIH19J1xcbiAgICB7ez99fVxcbikgI319XFxuXFxuXFxuLyoqXFxuICogSW5zZXJ0cyBjb2RlIHRvIHVwZGF0ZSBhY2Nlc3MgcGF0aCBmb3IgY3VycmVudCBwcm9wZXJ0eVxcbiAqIEJlY2F1c2Ugb2YgdGhlIHBvc3NpYmlsaXR5IG9mIGludGVycG9sYXRlZCBwcm9wZXJ0aWVzLCBpdCBjYW4ndCBiZSBjYWxjdWxhdGVkIGluIHRlbXBsYXRlLCBpdCBjYW4gb25seSBiZSBjYWxjdWxhdGVkIGR1cmluZyBhY2Nlc3NvciBjYWxsLlxcbiAqL1xcbnt7IyMgZGVmLmNoYW5nZUFjY2Vzc1BhdGg6XFxuICAgIGFjY2Vzc1BhdGggKz0ge3s/IGN1cnJOb2RlLmludGVycG9sYXRlIH19XFxuICAgICAgICB7ez8gY3Vyck5vZGUuc3ludGF4ID09ICdhcnJheScgfX1cXG4gICAgICAgICAgICAnWycgKyB0aGlzLl9hcmdzWyB7ez0gY3Vyck5vZGUuaW50ZXJwb2xhdGUgfX0gXSArICddJztcXG4gICAgICAgIHt7Pz99fVxcbiAgICAgICAgICAgICcuJyArIHRoaXMuX2FyZ3NbIHt7PSBjdXJyTm9kZS5pbnRlcnBvbGF0ZSB9fSBdO1xcbiAgICAgICAge3s/fX1cXG4gICAge3s/P319XFxuICAgICAgICAne3s9IGN1cnJQcm9wIH19JztcXG4gICAge3s/fX1cXG4jfX1cXG5cXG5cXG4vKipcXG4gKiBJbnNlcnRzIGNvZGUgdG8gcG9zdCBzdG9yZWQgbWVzc2FnZXNcXG4gKi9cXG57eyMjIGRlZi5wb3N0TWVzc2FnZXM6XFxuICAgIGlmIChtZXNzYWdlcy5sZW5ndGgpIHtcXG4gICAgICAgIHt7IyBkZWYubW9kZWxQb3N0QmF0Y2hDb2RlIH19KCdkYXRhY2hhbmdlcycsIHtcXG4gICAgICAgICAgICBjaGFuZ2VzOiBtZXNzYWdlcyxcXG4gICAgICAgICAgICB0cmFuc2FjdGlvbjogaW5DaGFuZ2VUcmFuc2FjdGlvblxcbiAgICAgICAgfSk7XFxuXFxuICAgICAgICBtZXNzYWdlcy5mb3JFYWNoKGZ1bmN0aW9uKG1zZykge1xcbiAgICAgICAgICAgIHt7IyBkZWYubW9kZWxQb3N0TWVzc2FnZUNvZGUgfX0obXNnLnBhdGgsIG1zZyk7XFxuICAgICAgICB9LCB0aGlzKTtcXG4gICAgfVxcbiN9fVxcblwiXG4gICAgLCBpbmNsdWRlX2NyZWF0ZV90cmVlID0gXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG4vKipcXG4gKiBJbnNlcnRzIGNvZGUgdG8gY3JlYXRlIG1vZGVsIHRyZWUgYXMgbmVjY2Vzc2FyeSBmb3IgYHNldGAgYW5kIGBzcGxpY2VgIGFjY2Vzc29ycyBhbmQgdG8gYWRkIG1lc3NhZ2VzIHRvIHNlbmQgbGlzdCBpZiB0aGUgdHJlZSBjaGFuZ2VzLlxcbiAqL1xcbnt7IyMgZGVmLmNyZWF0ZVRyZWU6bWV0aG9kOlxcbiAgICB2YXIgd2FzRGVmID0gdHJ1ZTtcXG4gICAgdmFyIG9sZCA9IG07XFxuXFxuICAgIHt7IHZhciBlbXB0eVByb3AgPSBpdC5wYXJzZWRQYXRoWzBdICYmIGl0LnBhcnNlZFBhdGhbMF0uZW1wdHk7IH19XFxuICAgIHt7PyBlbXB0eVByb3AgfX1cXG4gICAgICAgIHt7IC8qIGNyZWF0ZSB0b3AgbGV2ZWwgbW9kZWwgaWYgaXQgd2FzIG5vdCBwcmV2aW91c2x5IGRlZmluZWQgKi8gfX1cXG4gICAgICAgIGlmICghIG0pIHtcXG4gICAgICAgICAgICBtID0ge3sjIGRlZi5tb2RlbEFjY2Vzc1ByZWZpeCB9fSA9IHt7PSBlbXB0eVByb3AgfX07XFxuICAgICAgICAgICAgd2FzRGVmID0gZmFsc2U7XFxuXFxuICAgICAgICAgICAgaWYgKHRoaXMuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XFxuICAgICAgICAgICAgICAgIHt7IyBkZWYuYWRkTXNnIH19ICcnLCB0eXBlOiAnYWRkZWQnLFxcbiAgICAgICAgICAgICAgICAgICAgICBuZXdWYWx1ZTogbSB9KTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgIHt7Pz99fVxcbiAgICAgICAge3s/IG1ldGhvZCA9PSAnc3BsaWNlJyB9fVxcbiAgICAgICAgICAgIGlmICghIG0pIHtcXG4gICAgICAgIHt7P319XFxuICAgICAgICAgICAgICAgIG0gPSB7eyMgZGVmLm1vZGVsQWNjZXNzUHJlZml4IH19ID0gY2xvbmVUcmVlKHZhbHVlKTtcXG4gICAgICAgICAgICAgICAgd2FzRGVmID0gdHlwZW9mIG9sZCAhPSAndW5kZWZpbmVkJztcXG4gICAgICAgIHt7PyBtZXRob2QgPT0gJ3NwbGljZScgfX1cXG4gICAgICAgICAgICB9XFxuICAgICAgICB7ez99fSAgICAgICBcXG4gICAge3s/fX1cXG5cXG5cXG4gICAge3sgLyogY3JlYXRlIG1vZGVsIHRyZWUgaWYgaXQgZG9lc24ndCBleGlzdCAqLyB9fVxcbiAgICB7eyAgdmFyIG1vZGVsRGF0YVByb3BlcnR5ID0gJyc7XFxuICAgICAgICB2YXIgbmV4dE5vZGUgPSBpdC5wYXJzZWRQYXRoWzBdO1xcbiAgICAgICAgdmFyIGNvdW50ID0gaXQucGFyc2VkUGF0aC5sZW5ndGggLSAxO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb3VudDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIGN1cnJOb2RlID0gbmV4dE5vZGU7XFxuICAgICAgICAgICAgdmFyIGN1cnJQcm9wID0gY3Vyck5vZGUucHJvcGVydHk7XFxuICAgICAgICAgICAgbmV4dE5vZGUgPSBpdC5wYXJzZWRQYXRoW2kgKyAxXTtcXG4gICAgICAgICAgICB2YXIgZW1wdHlQcm9wID0gbmV4dE5vZGUgJiYgbmV4dE5vZGUuZW1wdHk7XFxuICAgIH19XFxuXFxuICAgICAgICB7eyMgZGVmLmNyZWF0ZVRyZWVTdGVwIH19XFxuXFxuICAgIHt7ICB9IC8qIGZvciBsb29wICovIH19XFxuI319XFxuXFxuXFxuLyoqXFxuICogSW5zZXJ0cyBjb2RlIHRvIGNyZWF0ZSBvbmUgc3RlcCBpbiB0aGUgbW9kZWwgdHJlZVxcbiAqL1xcbnt7IyMgZGVmLmNyZWF0ZVRyZWVTdGVwOlxcbiAgICB7eyMgZGVmLmNoYW5nZUFjY2Vzc1BhdGggfX1cXG5cXG4gICAgaWYgKCEge3sjIGRlZi53YXNEZWZpbmVkIH19KSB7IFxcbiAgICAgICAge3sgLyogcHJvcGVydHkgZG9lcyBub3QgZXhpc3QgKi8gfX1cXG4gICAgICAgIG0gPSBte3sjIGRlZi5jdXJyUHJvcCB9fSA9IHt7PSBlbXB0eVByb3AgfX07XFxuXFxuICAgICAgICBpZiAodGhpcy5fb3B0aW9ucy5yZWFjdGl2ZSAhPT0gZmFsc2UpIHtcXG4gICAgICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSBhY2Nlc3NQYXRoLCB0eXBlOiAnYWRkZWQnLCBcXG4gICAgICAgICAgICAgICAgICBuZXdWYWx1ZTogbSB9KTtcXG4gICAgICAgIH1cXG5cXG4gICAgfSBlbHNlIGlmICh0eXBlb2YgbXt7IyBkZWYuY3VyclByb3AgfX0gIT0gJ29iamVjdCcpIHtcXG4gICAgICAgIHt7IC8qIHByb3BlcnR5IGlzIG5vdCBvYmplY3QgKi8gfX1cXG4gICAgICAgIHZhciBvbGQgPSBte3sjIGRlZi5jdXJyUHJvcCB9fTtcXG4gICAgICAgIG0gPSBte3sjIGRlZi5jdXJyUHJvcCB9fSA9IHt7PSBlbXB0eVByb3AgfX07XFxuXFxuICAgICAgICBpZiAodGhpcy5fb3B0aW9ucy5yZWFjdGl2ZSAhPT0gZmFsc2UpIHtcXG4gICAgICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSBhY2Nlc3NQYXRoLCB0eXBlOiAnY2hhbmdlZCcsIFxcbiAgICAgICAgICAgICAgICAgIG9sZFZhbHVlOiBvbGQsIG5ld1ZhbHVlOiBtIH0pO1xcbiAgICAgICAgfVxcblxcbiAgICB9IGVsc2Uge1xcbiAgICAgICAge3sgLyogcHJvcGVydHkgZXhpc3RzLCBqdXN0IHRyYXZlcnNlIGRvd24gdGhlIG1vZGVsIHRyZWUgKi8gfX1cXG4gICAgICAgIG0gPSBte3sjIGRlZi5jdXJyUHJvcCB9fTtcXG4gICAgfVxcbiN9fVxcblwiXG4gICAgLCBpbmNsdWRlX3RyYXZlcnNlX3RyZWUgPSBcIid1c2Ugc3RyaWN0JztcXG4vKiBPbmx5IHVzZSB0aGlzIHN0eWxlIG9mIGNvbW1lbnRzLCBub3QgXFxcIi8vXFxcIiAqL1xcblxcbi8qKlxcbiAqIEluc2VydHMgY29kZSB0byB0cmF2ZXJzZSBtb2RlbCB0cmVlIGZvciBgZGVsZXRlYCBhbmQgYHNwbGljZWAgYWNjZXNzb3JzLlxcbiAqL1xcbnt7IyMgZGVmLnRyYXZlcnNlVHJlZTpcXG4gICAge3sgXFxuICAgICAgICB2YXIgY291bnQgPSBpdC5wYXJzZWRQYXRoLmxlbmd0aC0xO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb3VudDsgaSsrKSB7IFxcbiAgICAgICAgICAgIHZhciBjdXJyTm9kZSA9IGl0LnBhcnNlZFBhdGhbaV07XFxuICAgICAgICAgICAgdmFyIGN1cnJQcm9wID0gY3Vyck5vZGUucHJvcGVydHk7XFxuICAgIH19XFxuICAgICAgICAgICAge3sjIGRlZi50cmF2ZXJzZVRyZWVTdGVwIH19XFxuXFxuICAgIHt7IH0gLyogZm9yIGxvb3AgKi9cXG5cXG4gICAgICAgIHZhciBpID0gY291bnQ7XFxuICAgICAgICB3aGlsZSAoaS0tKSB7IC8qIGNsb3NpbmcgYnJhY2VzIGZvciBlbHNlJ3MgYWJvdmUgKi9cXG4gICAgfX1cXG4gICAgICAgICAgICB9XFxuICAgIHt7IH0gLyogd2hpbGUgbG9vcCAqLyB9fVxcbiN9fVxcblxcblxcbi8qKlxcbiAqIEluc2VydHMgY29kZSB0byB0cmF2ZXJzZSBvbmUgc3RlcCBpbiB0aGUgbW9kZWwgdHJlZVxcbiAqL1xcbnt7IyMgZGVmLnRyYXZlcnNlVHJlZVN0ZXA6XFxuICAgIGlmICghIChtICYmIG0uaGFzT3duUHJvcGVydHkgJiYge3sjIGRlZi53YXNEZWZpbmVkfX0gKSApXFxuICAgICAgICB0cmVlRG9lc05vdEV4aXN0ID0gdHJ1ZTtcXG4gICAgZWxzZSB7XFxuICAgICAgICBtID0gbXt7IyBkZWYuY3VyclByb3AgfX07XFxuICAgICAgICB7eyMgZGVmLmNoYW5nZUFjY2Vzc1BhdGggfX1cXG4gICAge3sgLyogYnJhY2UgZnJvbSBlbHNlIGlzIG5vdCBjbG9zZWQgb24gcHVycG9zZSAtIGFsbCBicmFjZXMgYXJlIGNsb3NlZCBpbiB3aGlsZSBsb29wICovIH19XFxuI319XFxuXCI7XG5cbnZhciBkb3REZWYgPSB7XG4gICAgaW5jbHVkZV9kZWZpbmVzOiBpbmNsdWRlX2RlZmluZXMsXG4gICAgaW5jbHVkZV9jcmVhdGVfdHJlZTogaW5jbHVkZV9jcmVhdGVfdHJlZSxcbiAgICBpbmNsdWRlX3RyYXZlcnNlX3RyZWU6IGluY2x1ZGVfdHJhdmVyc2VfdHJlZSxcbiAgICBnZXRQYXRoTm9kZUtleTogcGF0aFV0aWxzLmdldFBhdGhOb2RlS2V5LFxuICAgIG1vZGVsQWNjZXNzUHJlZml4OiAndGhpcy5fbW9kZWwuX2RhdGEnLFxuICAgIG1vZGVsUG9zdE1lc3NhZ2VDb2RlOiAndGhpcy5fbW9kZWwuX2ludGVybmFsTWVzc2VuZ2VyLnBvc3RNZXNzYWdlJyxcbiAgICBtb2RlbFBvc3RCYXRjaENvZGU6ICd0aGlzLl9tb2RlbC5wb3N0TWVzc2FnZVN5bmMnLFxuICAgIGludGVybmFsTWVzc2VuZ2VyOiAndGhpcy5fbW9kZWwuX2ludGVybmFsTWVzc2VuZ2VyJ1xufTtcblxudmFyIG1vZGVsRG90RGVmID0gXyhkb3REZWYpLmNsb25lKCkuZXh0ZW5kKHtcbiAgICBtb2RlbEFjY2Vzc1ByZWZpeDogJ3RoaXMuX2RhdGEnLFxuICAgIG1vZGVsUG9zdE1lc3NhZ2VDb2RlOiAndGhpcy5faW50ZXJuYWxNZXNzZW5nZXIucG9zdE1lc3NhZ2UnLFxuICAgIG1vZGVsUG9zdEJhdGNoQ29kZTogJ3RoaXMucG9zdE1lc3NhZ2VTeW5jJyxcbiAgICBpbnRlcm5hbE1lc3NlbmdlcjogJ3RoaXMuX2ludGVybmFsTWVzc2VuZ2VyJ1xufSkuXygpO1xuXG5cbnZhciBkb3RTZXR0aW5ncyA9IF8uY2xvbmUoZG9ULnRlbXBsYXRlU2V0dGluZ3MpO1xuZG90U2V0dGluZ3Muc3RyaXAgPSBmYWxzZTtcblxudmFyIHN5bnRoZXNpemVycyA9IF8ubWFwS2V5cyh0ZW1wbGF0ZXMsIGZ1bmN0aW9uKHRtcGwpIHtcbiAgICByZXR1cm4gZG9ULnRlbXBsYXRlKHRtcGwsIGRvdFNldHRpbmdzLCBkb3REZWYpOyBcbn0pO1xuXG5cbnZhciBtb2RlbFN5bnRoZXNpemVycyA9IF8ubWFwVG9PYmplY3QoWydzZXQnLCAnZGVsJywgJ3NwbGljZSddLCBmdW5jdGlvbihtZXRob2ROYW1lKSB7XG4gICAgcmV0dXJuIGRvVC50ZW1wbGF0ZSh0ZW1wbGF0ZXNbbWV0aG9kTmFtZV0sIGRvdFNldHRpbmdzLCBtb2RlbERvdERlZik7XG59KTtcblxuXG4vKipcbiAqIEZ1bmN0aW9uIHRoYXQgc3ludGhlc2l6ZXMgYWNjZXNzb3IgbWV0aG9kcy5cbiAqIEZ1bmN0aW9uIGlzIG1lbW9pemVkIHNvIGFjY2Vzc29ycyBhcmUgY2FjaGVkICh1cCB0byAxMDAwKS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gcGF0aCBNb2RlbC9Nb2RlbFBhdGggYWNjZXNzIHBhdGhcbiAqIEBwYXJhbSB7QXJyYXl9IHBhcnNlZFBhdGggYXJyYXkgb2YgcGF0aCBub2Rlc1xuICogQHJldHVybiB7T2JqZWN0W0Z1bmN0aW9uXX1cbiAqL1xudmFyIHN5bnRoZXNpemVQYXRoTWV0aG9kcyA9IF8ubWVtb2l6ZShfc3ludGhlc2l6ZVBhdGhNZXRob2RzLCB1bmRlZmluZWQsIDEwMDApO1xuXG5mdW5jdGlvbiBfc3ludGhlc2l6ZVBhdGhNZXRob2RzKHBhdGgsIHBhcnNlZFBhdGgpIHtcbiAgICB2YXIgbWV0aG9kcyA9IF8ubWFwS2V5cyhzeW50aGVzaXplcnMsIGZ1bmN0aW9uKHN5bnRoc3pyKSB7XG4gICAgICAgIHJldHVybiBfc3ludGhlc2l6ZShzeW50aHN6ciwgcGF0aCwgcGFyc2VkUGF0aCk7XG4gICAgfSk7XG4gICAgcmV0dXJuIG1ldGhvZHM7XG59XG5cblxudmFyIG5vcm1hbGl6ZVNwbGljZUluZGV4ID0gbW9kZWxVdGlscy5ub3JtYWxpemVTcGxpY2VJbmRleDsgLy8gdXNlZCBpbiBzcGxpY2UuZG90LmpzXG5cblxuZnVuY3Rpb24gX3N5bnRoZXNpemUoc3ludGhlc2l6ZXIsIHBhdGgsIHBhcnNlZFBhdGgpIHtcbiAgICB2YXIgbWV0aG9kXG4gICAgICAgICwgbWV0aG9kQ29kZSA9IHN5bnRoZXNpemVyKHtcbiAgICAgICAgICAgIHBhcnNlZFBhdGg6IHBhcnNlZFBhdGgsXG4gICAgICAgICAgICBnZXRQYXRoTm9kZUtleTogcGF0aFV0aWxzLmdldFBhdGhOb2RlS2V5XG4gICAgICAgIH0pO1xuXG4gICAgdHJ5IHtcbiAgICAgICAgZXZhbChtZXRob2RDb2RlKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IE1vZGVsRXJyb3IoJ01vZGVsUGF0aCBtZXRob2QgY29tcGlsYXRpb24gZXJyb3I7IHBhdGg6ICcgKyBwYXRoICsgJywgY29kZTogJyArIG1ldGhvZENvZGUpO1xuICAgIH1cblxuICAgIHJldHVybiBtZXRob2Q7XG5cblxuICAgIC8vIGZ1bmN0aW9ucyB1c2VkIGJ5IG1ldGhvZHMgYHNldGAsIGBkZWxldGVgIGFuZCBgc3BsaWNlYCAoc3ludGhlc2l6ZWQgYnkgdGVtcGxhdGUpXG4gICAgZnVuY3Rpb24gYWRkQ2hhbmdlTWVzc2FnZShtZXNzYWdlcywgbWVzc2FnZXNIYXNoLCBtc2cpIHtcbiAgICAgICAgbWVzc2FnZXMucHVzaChtc2cpO1xuICAgICAgICBtZXNzYWdlc0hhc2hbbXNnLnBhdGhdID0gbXNnO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFkZFRyZWVDaGFuZ2VzTWVzc2FnZXMobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgcm9vdFBhdGgsIG9sZFZhbHVlLCBuZXdWYWx1ZSkge1xuICAgICAgICB2YXIgb2xkSXNUcmVlID0gdmFsdWVJc1RyZWUob2xkVmFsdWUpXG4gICAgICAgICAgICAsIG5ld0lzVHJlZSA9IHZhbHVlSXNUcmVlKG5ld1ZhbHVlKTtcblxuICAgICAgICBpZiAobmV3SXNUcmVlKVxuICAgICAgICAgICAgYWRkTWVzc2FnZXMobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgcm9vdFBhdGgsIG5ld1ZhbHVlLCAnYWRkZWQnLCAnbmV3VmFsdWUnKTtcbiAgICAgICAgXG4gICAgICAgIGlmIChvbGRJc1RyZWUpXG4gICAgICAgICAgICBhZGRNZXNzYWdlcyhtZXNzYWdlcywgbWVzc2FnZXNIYXNoLCByb290UGF0aCwgb2xkVmFsdWUsICdyZW1vdmVkJywgJ29sZFZhbHVlJyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYWRkTWVzc2FnZXMobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgcm9vdFBhdGgsIG9iaiwgbXNnVHlwZSwgdmFsdWVQcm9wKSB7XG4gICAgICAgIF9hZGRNZXNzYWdlcyhyb290UGF0aCwgb2JqKTtcblxuXG4gICAgICAgIGZ1bmN0aW9uIF9hZGRNZXNzYWdlcyhyb290UGF0aCwgb2JqKSB7XG4gICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvYmopKSB7XG4gICAgICAgICAgICAgICAgdmFyIHBhdGhTeW50YXggPSByb290UGF0aCArICdbJCRdJztcbiAgICAgICAgICAgICAgICBvYmouZm9yRWFjaChmdW5jdGlvbih2YWx1ZSwgaW5kZXgpIHtcbiAgICAgICAgICAgICAgICAgICAgYWRkTWVzc2FnZSh2YWx1ZSwgaW5kZXgsIHBhdGhTeW50YXgpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YXIgcGF0aFN5bnRheCA9IHJvb3RQYXRoICsgJy4kJCc7XG4gICAgICAgICAgICAgICAgXy5lYWNoS2V5KG9iaiwgZnVuY3Rpb24odmFsdWUsIGtleSkge1xuICAgICAgICAgICAgICAgICAgICBhZGRNZXNzYWdlKHZhbHVlLCBrZXksIHBhdGhTeW50YXgpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gYWRkTWVzc2FnZSh2YWx1ZSwga2V5LCBwYXRoU3ludGF4KSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHBhdGhTeW50YXgucmVwbGFjZSgnJCQnLCBrZXkpXG4gICAgICAgICAgICAgICAgLCBleGlzdGluZ01zZyA9IG1lc3NhZ2VzSGFzaFtwYXRoXTtcblxuICAgICAgICAgICAgaWYgKGV4aXN0aW5nTXNnKSB7XG4gICAgICAgICAgICAgICAgaWYgKGV4aXN0aW5nTXNnLnR5cGUgPT0gbXNnVHlwZSlcbiAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCdzZXR0ZXIgZXJyb3I6IHNhbWUgbWVzc2FnZSB0eXBlIHBvc3RlZCBvbiB0aGUgc2FtZSBwYXRoJyk7XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGV4aXN0aW5nTXNnLnR5cGUgPSAnY2hhbmdlZCc7XG4gICAgICAgICAgICAgICAgICAgIGV4aXN0aW5nTXNnW3ZhbHVlUHJvcF0gPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHZhciBtc2cgPSB7IHBhdGg6IHBhdGgsIHR5cGU6IG1zZ1R5cGUgfTtcbiAgICAgICAgICAgICAgICBtc2dbdmFsdWVQcm9wXSA9IHZhbHVlO1xuICAgICAgICAgICAgICAgIGFkZENoYW5nZU1lc3NhZ2UobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgbXNnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHZhbHVlSXNUcmVlKHZhbHVlKSlcbiAgICAgICAgICAgICAgICBfYWRkTWVzc2FnZXMocGF0aCwgdmFsdWUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY2xvbmVUcmVlKHZhbHVlKSB7XG4gICAgICAgIHJldHVybiB2YWx1ZUlzTm9ybWFsT2JqZWN0KHZhbHVlKVxuICAgICAgICAgICAgICAgID8gXy5kZWVwQ2xvbmUodmFsdWUpXG4gICAgICAgICAgICAgICAgOiB2YWx1ZTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwcm90ZWN0VmFsdWUodmFsdWUpIHtcbiAgICAgICAgcmV0dXJuICEgdmFsdWVJc05vcm1hbE9iamVjdCh2YWx1ZSlcbiAgICAgICAgICAgICAgICA/IHZhbHVlXG4gICAgICAgICAgICAgICAgOiBBcnJheS5pc0FycmF5KHZhbHVlKVxuICAgICAgICAgICAgICAgICAgICA/IHZhbHVlLnNsaWNlKClcbiAgICAgICAgICAgICAgICAgICAgOiBPYmplY3QuY3JlYXRlKHZhbHVlKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB2YWx1ZUlzVHJlZSh2YWx1ZSkge1xuICAgICAgICByZXR1cm4gdmFsdWVJc05vcm1hbE9iamVjdCh2YWx1ZSlcbiAgICAgICAgICAgICAgICAmJiBPYmplY3Qua2V5cyh2YWx1ZSkubGVuZ3RoO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHZhbHVlSXNOb3JtYWxPYmplY3QodmFsdWUpIHtcbiAgICAgICAgcmV0dXJuIHZhbHVlICE9IG51bGxcbiAgICAgICAgICAgICAgICAmJiB0eXBlb2YgdmFsdWUgPT0gXCJvYmplY3RcIlxuICAgICAgICAgICAgICAgICYmICEgKHZhbHVlIGluc3RhbmNlb2YgRGF0ZSlcbiAgICAgICAgICAgICAgICAmJiAhICh2YWx1ZSBpbnN0YW5jZW9mIFJlZ0V4cCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYWRkQmF0Y2hJZHNUb01lc3NhZ2UobXNnLCBiYXRjaElkLCBtc2dJZCkge1xuICAgICAgICBfLmRlZmluZVByb3BlcnRpZXMobXNnLCB7XG4gICAgICAgICAgICBfX2JhdGNoX2lkOiBiYXRjaElkLFxuICAgICAgICAgICAgX19tc2dfaWQ6IG1zZ0lkXG4gICAgICAgIH0pO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIEV4cG9ydHMgYHN5bnRoZXNpemVgIGZ1bmN0aW9uIHdpdGggdGhlIGZvbGxvd2luZzpcbiAqXG4gKiAtIC5tb2RlbE1ldGhvZHMuc2V0IC0gYHNldGAgbWV0aG9kIGZvciBNb2RlbFxuICogLSAubW9kZWxNZXRob2RzLmRlbCAtIGBkZWxgIG1ldGhvZCBmb3IgTW9kZWxcbiAqIC0gLm1vZGVsTWV0aG9kcy5zcGxpY2UgLSBgc3BsaWNlYCBtZXRob2QgZm9yIE1vZGVsXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gc3ludGhlc2l6ZVBhdGhNZXRob2RzO1xuXG52YXIgbW9kZWxNZXRob2RzID0gXy5tYXBLZXlzKG1vZGVsU3ludGhlc2l6ZXJzLCBmdW5jdGlvbihzeW50aGVzaXplcikge1xuICAgIHJldHVybiBfc3ludGhlc2l6ZShzeW50aGVzaXplciwgJycsIFtdKTtcbn0pO1xuXG5zeW50aGVzaXplUGF0aE1ldGhvZHMubW9kZWxNZXRob2RzID0gbW9kZWxNZXRob2RzO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIFJlZ2lzdHJpZXMgb2YgZmFjZXRzIGFuZCBvZiBjb21wb25lbnRzXG4gKlxuICogLSBbZmFjZXRzXSguL2NvbXBvbmVudHMvY19mYWNldHMvY2ZfcmVnaXN0cnkuanMuaHRtbClcbiAqIC0gW2NvbXBvbmVudHNdKC4vY29tcG9uZW50cy9jX3JlZ2lzdHJ5LmpzLmh0bWwpXG4gKi9cbnZhciByZWdpc3RyeSA9IG1vZHVsZS5leHBvcnRzID0ge1xuICAgIGZhY2V0czogcmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL2NmX3JlZ2lzdHJ5JyksXG4gICAgY29tcG9uZW50czogcmVxdWlyZSgnLi9jb21wb25lbnRzL2NfcmVnaXN0cnknKSxcbiAgICBjb21tYW5kczogcmVxdWlyZSgnLi9jb21tYW5kL2NtZF9yZWdpc3RyeScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyA8YSBuYW1lPVwiY29tcG9uZW50cy1kb20tY29uc3RydWN0b3JzXCI+PC9hPlxuLy8gIyMjZG9tIGV2ZW50cyBjb25zdHJ1Y3RvcnNcblxuXG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbi8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL1JlZmVyZW5jZS9FdmVudHNcblxudmFyIGV2ZW50VHlwZXMgPSB7XG4gICAgQ2xpcGJvYXJkRXZlbnQ6IFsnY29weScsICdjdXQnLCAncGFzdGUnLCAnYmVmb3JlY29weScsICdiZWZvcmVjdXQnLCAnYmVmb3JlcGFzdGUnXSxcbiAgICBFdmVudDogWydpbnB1dCcsICdyZWFkeXN0YXRlY2hhbmdlJ10sXG4gICAgRm9jdXNFdmVudDogWydmb2N1cycsICdibHVyJywgJ2ZvY3VzaW4nLCAnZm9jdXNvdXQnXSxcbiAgICBLZXlib2FyZEV2ZW50OiBbJ2tleWRvd24nLCAna2V5cHJlc3MnLCAgJ2tleXVwJ10sXG4gICAgTW91c2VFdmVudDogWydjbGljaycsICdjb250ZXh0bWVudScsICdkYmxjbGljaycsICdtb3VzZWRvd24nLCAnbW91c2V1cCcsXG4gICAgICAgICAgICAgICAgICdtb3VzZWVudGVyJywgJ21vdXNlbGVhdmUnLCAnbW91c2Vtb3ZlJywgJ21vdXNlb3V0JywgJ21vdXNlb3ZlcicsXG4gICAgICAgICAgICAgICAgICdzaG93JyAvKiBjb250ZXh0IG1lbnUgKi9dLFxuICAgIFRvdWNoRXZlbnQ6IFsndG91Y2hzdGFydCcsICd0b3VjaGVuZCcsICd0b3VjaG1vdmUnLCAndG91Y2hlbnRlcicsICd0b3VjaGxlYXZlJywgJ3RvdWNoY2FuY2VsJ10sXG59O1xuXG5cbi8vIG1vY2sgd2luZG93IGFuZCBldmVudCBjb25zdHJ1Y3RvcnMgZm9yIHRlc3RpbmdcbmlmICh0eXBlb2Ygd2luZG93ICE9ICd1bmRlZmluZWQnKVxuICAgIHZhciBnbG9iYWwgPSB3aW5kb3c7XG5lbHNlIHtcbiAgICBnbG9iYWwgPSB7fTtcbiAgICBfLmVhY2hLZXkoZXZlbnRUeXBlcywgZnVuY3Rpb24oZVR5cGVzLCBldmVudENvbnN0cnVjdG9yTmFtZSkge1xuICAgICAgICB2YXIgZXZlbnRDb25zdHJ1Y3RvciA9IF8ubWFrZUZ1bmN0aW9uKGV2ZW50Q29uc3RydWN0b3JOYW1lLCAndHlwZScsICdwcm9wZXJ0aWVzJyxcbiAgICAgICAgICAgICd0aGlzLnR5cGUgPSB0eXBlOyBfLmV4dGVuZCh0aGlzLCBwcm9wZXJ0aWVzKTsnKTtcbiAgICAgICAgZ2xvYmFsW2V2ZW50Q29uc3RydWN0b3JOYW1lXSA9IGV2ZW50Q29uc3RydWN0b3I7XG4gICAgfSk7XG59XG5cblxudmFyIGRvbUV2ZW50c0NvbnN0cnVjdG9ycyA9IHt9O1xuXG5fLmVhY2hLZXkoZXZlbnRUeXBlcywgZnVuY3Rpb24oZVR5cGVzLCBldmVudENvbnN0cnVjdG9yTmFtZSkge1xuICAgIGVUeXBlcy5mb3JFYWNoKGZ1bmN0aW9uKHR5cGUpIHtcbiAgICAgICAgaWYgKE9iamVjdC5oYXNPd25Qcm9wZXJ0eShkb21FdmVudHNDb25zdHJ1Y3RvcnMsIHR5cGUpKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdkdXBsaWNhdGUgZXZlbnQgdHlwZSAnICsgdHlwZSk7XG5cbiAgICAgICAgZG9tRXZlbnRzQ29uc3RydWN0b3JzW3R5cGVdID0gZ2xvYmFsW2V2ZW50Q29uc3RydWN0b3JOYW1lXTtcbiAgICB9KTtcbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gZG9tRXZlbnRzQ29uc3RydWN0b3JzO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi4vbWVzc2VuZ2VyL21fc291cmNlJylcbiAgICAsIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NvbXBvbmVudHMvY19jbGFzcycpXG4gICAgLCBkb21FdmVudHNDb25zdHJ1Y3RvcnMgPSByZXF1aXJlKCcuL2RlX2NvbnN0cnMnKSAvLyBUT0RPIG1lcmdlIHdpdGggRE9NRXZlbnRTb3VyY2UgPz9cbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgY2hlY2sgPSByZXF1aXJlKCcuLi91dGlsL2NoZWNrJylcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2g7XG5cbnZhciBET01FbWl0dGVyU291cmNlID0gXy5jcmVhdGVTdWJjbGFzcyhNZXNzYWdlU291cmNlLCAnRE9NRW1pdHRlclNvdXJjZScsIHRydWUpO1xuXG5cbl8uZXh0ZW5kUHJvdG8oRE9NRW1pdHRlclNvdXJjZSwge1xuICAgIC8vIGltcGxlbWVudGluZyBNZXNzYWdlU291cmNlIGludGVyZmFjZVxuICAgIGluaXQ6IGluaXQsXG4gICAgZGVzdHJveTogRE9NRW1pdHRlclNvdXJjZSRkZXN0cm95LFxuICAgIGFkZFNvdXJjZVN1YnNjcmliZXI6IF8ucGFydGlhbChzb3VyY2VTdWJzY3JpYmVyTWV0aG9kLCAnYWRkRXZlbnRMaXN0ZW5lcicpLFxuICAgIHJlbW92ZVNvdXJjZVN1YnNjcmliZXI6IF8ucGFydGlhbChzb3VyY2VTdWJzY3JpYmVyTWV0aG9kLCAncmVtb3ZlRXZlbnRMaXN0ZW5lcicpLFxuICAgIHBvc3RNZXNzYWdlOiBET01FbWl0dGVyU291cmNlJHBvc3RNZXNzYWdlLFxuICAgIHRyaWdnZXI6IHRyaWdnZXIsXG5cbiAgICAvLyBjbGFzcyBzcGVjaWZpYyBtZXRob2RzXG4gICAgZW1pdHRlcjogZW1pdHRlcixcbiAgICBoYW5kbGVFdmVudDogaGFuZGxlRXZlbnQsICAvLyBldmVudCBkaXNwYXRjaGVyIC0gYXMgZGVmaW5lZCBieSBFdmVudCBET00gQVBJXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBET01FbWl0dGVyU291cmNlO1xuXG5cbnZhciB1c2VDYXB0dXJlUGF0dGVybiA9IC9fX2NhcHR1cmUkL1xuICAgICwgdXNlQ2FwdHVyZVBvc3RmaXggPSAnX19jYXB0dXJlJztcblxuXG4vLyBpbml0IERPTSBldmVudCBzb3VyY2VcbmZ1bmN0aW9uIGluaXQoaG9zdE9iamVjdCwgcHJveHlNZXRob2RzLCBtZXNzZW5nZXJBUElPckNsYXNzLCBldmVudEVtaXR0ZXIpIHtcbiAgICB0aGlzLmV2ZW50RW1pdHRlciA9IGV2ZW50RW1pdHRlcjtcbiAgICBNZXNzYWdlU291cmNlLnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuZnVuY3Rpb24gRE9NRW1pdHRlclNvdXJjZSRkZXN0cm95KCkge1xuICAgIE1lc3NhZ2VTb3VyY2UucHJvdG90eXBlLmRlc3Ryb3kuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICBkZWxldGUgdGhpcy5ldmVudEVtaXR0ZXI7XG59XG5cblxuLy8gZ2V0IERPTSBlbGVtZW50IG9mIGNvbXBvbmVudFxuZnVuY3Rpb24gZW1pdHRlcigpIHtcbiAgICByZXR1cm4gdGhpcy5ldmVudEVtaXR0ZXI7XG59XG5cblxuZnVuY3Rpb24gc291cmNlU3Vic2NyaWJlck1ldGhvZChtZXRob2QsIGV2ZW50VHlwZSkge1xuICAgIGlmICghIChldmVudFR5cGUgJiYgdHlwZW9mIGV2ZW50VHlwZSA9PSAnc3RyaW5nJykpIHJldHVybjtcbiAgICB2YXIgY2FwdHVyZSA9IHVzZUNhcHR1cmVQYXR0ZXJuLnRlc3QoZXZlbnRUeXBlKTtcbiAgICBldmVudFR5cGUgPSBldmVudFR5cGUucmVwbGFjZSh1c2VDYXB0dXJlUGF0dGVybiwgJycpO1xuICAgIHRoaXMuZW1pdHRlcigpW21ldGhvZF0oZXZlbnRUeXBlLCB0aGlzLCBjYXB0dXJlKTtcbn1cblxuXG4vLyBldmVudCBkaXNwYXRjaGVyIC0gYXMgZGVmaW5lZCBieSBFdmVudCBET00gQVBJXG5mdW5jdGlvbiBoYW5kbGVFdmVudChldmVudCkge1xuICAgIHZhciBpc0NhcHR1cmVQaGFzZTtcbiAgICBpZiAodHlwZW9mIHdpbmRvdyAhPSAndW5kZWZpbmVkJylcbiAgICAgICAgaXNDYXB0dXJlUGhhc2UgPSBldmVudC5ldmVudFBoYXNlID09IHdpbmRvdy5FdmVudC5DQVBUVVJJTkdfUEhBU0U7XG5cbiAgICBpZiAoaXNDYXB0dXJlUGhhc2UpXG4gICAgICAgIGV2ZW50ICs9IHVzZUNhcHR1cmVQb3N0Zml4O1xuXG4gICAgdGhpcy5kaXNwYXRjaE1lc3NhZ2UoZXZlbnQudHlwZSwgZXZlbnQpO1xufVxuXG5cbmZ1bmN0aW9uIERPTUVtaXR0ZXJTb3VyY2UkcG9zdE1lc3NhZ2UobWVzc2FnZSwgZGF0YSkge1xuICAgIHRoaXMubWVzc2VuZ2VyLnBvc3RNZXNzYWdlU3luYyhtZXNzYWdlLCBkYXRhKTtcbn1cblxuXG5mdW5jdGlvbiB0cmlnZ2VyKGV2ZW50VHlwZSwgcHJvcGVydGllcykge1xuICAgIGNoZWNrKGV2ZW50VHlwZSwgU3RyaW5nKTtcbiAgICBjaGVjayhwcm9wZXJ0aWVzLCBNYXRjaC5PcHRpb25hbChPYmplY3QpKTtcblxuICAgIGV2ZW50VHlwZSA9IGV2ZW50VHlwZS5yZXBsYWNlKHVzZUNhcHR1cmVQYXR0ZXJuLCAnJyk7XG4gICAgdmFyIEV2ZW50Q29uc3RydWN0b3IgPSBkb21FdmVudHNDb25zdHJ1Y3RvcnNbZXZlbnRUeXBlXTtcblxuICAgIGlmICh0eXBlb2YgRXZlbnRDb25zdHJ1Y3RvciAhPSAnZnVuY3Rpb24nKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Vuc3VwcG9ydGVkIGV2ZW50IHR5cGUnKTtcblxuICAgIC8vIGNoZWNrIGlmIGl0IGlzIGNvcnJlY3RcbiAgICBpZiAodHlwZW9mIHByb3BlcnRpZXMgIT0gJ3VuZGVmaW5lZCcpXG4gICAgICAgIHByb3BlcnRpZXMudHlwZSA9IGV2ZW50VHlwZTtcblxuICAgIHZhciBkb21FdmVudCA9IG5ldyBFdmVudENvbnN0cnVjdG9yKGV2ZW50VHlwZSwgcHJvcGVydGllcyk7XG4gICAgdmFyIG5vdENhbmNlbGxlZCA9IHRoaXMuZW1pdHRlcigpLmRpc3BhdGNoRXZlbnQoZG9tRXZlbnQpO1xuICAgIHJldHVybiBub3RDYW5jZWxsZWQ7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogYG1pbG8ubWFpbGBcbiAqIEl0IGlzIGFuIGFwcGxpY2F0aW9uIGxldmVsIG1lc3NlbmdlciB0aGF0IGlzIGFuIGluc3RhbmNlIG9mIE1lc3NlbmdlciBjbGFzcy5cbiAqXG4gKiBBdCB0aGUgbW9tZW50LCBpbiBhZGRpdGlvbiB0byBhcHBsaWNhdGlvbiBtZXNzYWdlcyB0aGF0IHlvdSBkZWZpbmUsIHlvdSBjYW4gc3Vic2NyaWJlIHRvIF9fZG9tcmVhZHlfXyBtZXNzYWdlIHRoYXQgaXMgZ3VhcmFudGVlZCB0byBmaXJlIG9uY2UsXG4gKiBldmVuIGlmIERPTSB3YXMgcmVhZHkgYXQgdGhlIHRpbWUgb2YgdGhlIHN1YnNjcmlwdGlvbi5cbiAqXG4gKiBNZXNzYWdpbmcgYmV0d2VlbiBmcmFtZXMgaXMgYXZhaWxhYmxlIHZpYSBtaWxvLm1haWwuIFNlZSBbRnJhbWUgZmFjZXRdKC4uL2NvbXBvbmVudHMvY19mYWNldHMvRnJhbWUuanMuaHRtbCkuXG4gKlxuICogU2VlIFtNZXNzZW5nZXJdKC4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sKS5cbiAqIFxuKiovXG5cblxudmFyIE1lc3NlbmdlciA9IHJlcXVpcmUoJy4uLy4uL21lc3NlbmdlcicpXG4gICAgLCBNYWlsTXNnQVBJID0gcmVxdWlyZSgnLi9tYWlsX2FwaScpXG4gICAgLCBNYWlsTWVzc2FnZVNvdXJjZSA9IHJlcXVpcmUoJy4vbWFpbF9zb3VyY2UnKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbnZhciBtaWxvTWFpbCA9IG5ldyBNZXNzZW5nZXI7XG5cbnZhciBtYWlsTXNnU291cmNlID0gbmV3IE1haWxNZXNzYWdlU291cmNlKG1pbG9NYWlsLCB7IHRyaWdnZXI6ICd0cmlnZ2VyJyB9LCBuZXcgTWFpbE1zZ0FQSSk7XG5cbm1pbG9NYWlsLl9zZXRNZXNzYWdlU291cmNlKG1haWxNc2dTb3VyY2UpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gbWlsb01haWw7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBNZXNzZW5nZXJBUEkgPSByZXF1aXJlKCcuLi8uLi9tZXNzZW5nZXIvbV9hcGknKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaDtcblxuXG52YXIgTWFpbE1zZ0FQSSA9IF8uY3JlYXRlU3ViY2xhc3MoTWVzc2VuZ2VyQVBJLCAnTWFpbE1zZ0FQSScsIHRydWUpO1xuXG5cbl8uZXh0ZW5kUHJvdG8oTWFpbE1zZ0FQSSwge1xuICAgIHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZTogdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlLFxuICAgIGZpbHRlclNvdXJjZU1lc3NhZ2U6IGZpbHRlclNvdXJjZU1lc3NhZ2Vcbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1haWxNc2dBUEk7XG5cblxuLy8gVE9ETzogdGhpcyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIHJlbGV2YW50IERPTSBldmVudCBkZXBlbmRlbnQgb24gZWxlbWVudCB0YWdcbi8vIENhbiBhbHNvIGltcGxlbWVudCBiZWZvcmVkYXRhY2hhbmdlZCBldmVudCB0byBhbGxvdyBwcmV2ZW50aW5nIHRoZSBjaGFuZ2Vcbi8vIHRyYW5zbGF0ZVRvRG9tRXZlbnRcbnZhciB3aW5kb3dNZXNzYWdlUmVnRXhwID0gL15tZXNzYWdlXFw6L1xuICAgICwgd2luZG93TWVzc2FnZVByZWZpeCA9ICdtZXNzYWdlOic7XG5cbmZ1bmN0aW9uIHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZShtZXNzYWdlKSB7XG4gICAgaWYgKG1lc3NhZ2UgPT0gJ2RvbXJlYWR5JylcbiAgICAgICAgcmV0dXJuICdyZWFkeXN0YXRlY2hhbmdlJztcbiAgICBlbHNlIGlmICh3aW5kb3dNZXNzYWdlUmVnRXhwLnRlc3QobWVzc2FnZSkpXG4gICAgICAgIHJldHVybiAnbWVzc2FnZSc7XG59XG5cblxuLy8gZmlsdGVyRGF0YU1lc3NhZ2VcbmZ1bmN0aW9uIGZpbHRlclNvdXJjZU1lc3NhZ2Uoc291cmNlTWVzc2FnZSwgbXNnVHlwZSwgbXNnRGF0YSkge1xuICAgIGlmIChzb3VyY2VNZXNzYWdlID09ICdyZWFkeXN0YXRlY2hhbmdlJykge1xuICAgICAgICAvL3JldHVybiBkb2N1bWVudC5yZWFkeVN0YXRlID09ICdpbnRlcmFjdGl2ZSc7XG4gICAgICAgIC8vICByZXR1cm4gZmFsc2U7XG4gICAgICAgIC8vIF8uZGVmaW5lUHJvcGVydHkodGhpcywgJ19kb21SZWFkeUZpcmVkJywgdHJ1ZSwgXy5XUklUKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIGlmIChzb3VyY2VNZXNzYWdlID09ICdtZXNzYWdlJylcbiAgICAgICAgcmV0dXJuIHdpbmRvd01lc3NhZ2VQcmVmaXggKyBtc2dEYXRhLmRhdGEudHlwZSA9PSBtc2dUeXBlO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIE1lc3NhZ2VTb3VyY2UgPSByZXF1aXJlKCcuLi8uLi9tZXNzZW5nZXIvbV9zb3VyY2UnKVxuICAgICwgZG9tRXZlbnRzQ29uc3RydWN0b3JzID0gcmVxdWlyZSgnLi4vZGVfY29uc3RycycpXG4gICAgLCBNYWlsTWVzc2FnZVNvdXJjZUVycm9yID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9lcnJvcicpLk1haWxNZXNzYWdlU291cmNlXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5cbnZhciBNYWlsTWVzc2FnZVNvdXJjZSA9IF8uY3JlYXRlU3ViY2xhc3MoTWVzc2FnZVNvdXJjZSwgJ01haWxNZXNzYWdlU291cmNlJywgdHJ1ZSk7XG5cblxuXy5leHRlbmRQcm90byhNYWlsTWVzc2FnZVNvdXJjZSwge1xuICAgIC8vIGltcGxlbWVudGluZyBNZXNzYWdlU291cmNlIGludGVyZmFjZVxuICAgIGFkZFNvdXJjZVN1YnNjcmliZXI6IGFkZFNvdXJjZVN1YnNjcmliZXIsXG4gICAgcmVtb3ZlU291cmNlU3Vic2NyaWJlcjogcmVtb3ZlU291cmNlU3Vic2NyaWJlcixcbiAgICB0cmlnZ2VyOiB0cmlnZ2VyLFxuXG4gICAgLy8gY2xhc3Mgc3BlY2lmaWMgbWV0aG9kc1xuICAgIF93aW5kb3dTdWJzY3JpYmVyTWV0aG9kOiBfd2luZG93U3Vic2NyaWJlck1ldGhvZCxcbiAgICBoYW5kbGVFdmVudDogaGFuZGxlRXZlbnQsICAvLyBldmVudCBkaXNwYXRjaGVyIC0gYXMgZGVmaW5lZCBieSBFdmVudCBET00gQVBJXG59KTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1haWxNZXNzYWdlU291cmNlO1xuXG5cbmZ1bmN0aW9uIGFkZFNvdXJjZVN1YnNjcmliZXIoc291cmNlTWVzc2FnZSkge1xuICAgIGlmIChpc1JlYWR5U3RhdGVDaGFuZ2Uoc291cmNlTWVzc2FnZSkpIHtcbiAgICAgICAgaWYgKGRvY3VtZW50LnJlYWR5U3RhdGUgPT0gJ2xvYWRpbmcnKVxuICAgICAgICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigncmVhZHlzdGF0ZWNoYW5nZScsIHRoaXMsIGZhbHNlKTtcbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB2YXIgRXZlbnRDb25zdHJ1Y3RvciA9IGRvbUV2ZW50c0NvbnN0cnVjdG9ycy5yZWFkeXN0YXRlY2hhbmdlO1xuICAgICAgICAgICAgdmFyIGRvbUV2ZW50ID0gbmV3IEV2ZW50Q29uc3RydWN0b3IoJ3JlYWR5c3RhdGVjaGFuZ2UnLCB7IHRhcmdldDogZG9jdW1lbnQgfSk7XG4gICAgICAgICAgICB0aGlzLmRpc3BhdGNoTWVzc2FnZSgncmVhZHlzdGF0ZWNoYW5nZScsIGRvbUV2ZW50KTtcbiAgICAgICAgfVxuICAgIH0gZWxzZVxuICAgICAgICB0aGlzLl93aW5kb3dTdWJzY3JpYmVyTWV0aG9kKCdhZGRFdmVudExpc3RlbmVyJywgc291cmNlTWVzc2FnZSk7XG59XG5cblxuZnVuY3Rpb24gcmVtb3ZlU291cmNlU3Vic2NyaWJlcihzb3VyY2VNZXNzYWdlKSB7XG4gICAgaWYgKGlzUmVhZHlTdGF0ZUNoYW5nZShzb3VyY2VNZXNzYWdlKSlcbiAgICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigncmVhZHlzdGF0ZWNoYW5nZScsIHRoaXMsIGZhbHNlKTtcbiAgICBlbHNlIFxuICAgICAgICB0aGlzLl93aW5kb3dTdWJzY3JpYmVyTWV0aG9kKCdyZW1vdmVFdmVudExpc3RlbmVyJywgc291cmNlTWVzc2FnZSk7XG59XG5cblxuZnVuY3Rpb24gaXNSZWFkeVN0YXRlQ2hhbmdlKHNvdXJjZU1lc3NhZ2UpIHtcbiAgICByZXR1cm4gc291cmNlTWVzc2FnZSA9PSAncmVhZHlzdGF0ZWNoYW5nZScgJiYgdHlwZW9mIGRvY3VtZW50ID09ICdvYmplY3QnO1xufVxuXG5mdW5jdGlvbiBpc1dpbmRvd01lc3NhZ2Uoc291cmNlTWVzc2FnZSkge1xuICAgIHJldHVybiBzb3VyY2VNZXNzYWdlID09ICdtZXNzYWdlJyAmJiB0eXBlb2Ygd2luZG93ID09ICdvYmplY3QnO1xufVxuXG5mdW5jdGlvbiBfd2luZG93U3Vic2NyaWJlck1ldGhvZChtZXRob2QsIHNvdXJjZU1lc3NhZ2UpIHtcbiAgICBpZiAoaXNXaW5kb3dNZXNzYWdlKHNvdXJjZU1lc3NhZ2UpKVxuICAgICAgICB3aW5kb3dbbWV0aG9kXSgnbWVzc2FnZScsIHRoaXMsIGZhbHNlKTtcbn1cblxuXG4vLyBldmVudCBkaXNwYXRjaGVyIC0gYXMgZGVmaW5lZCBieSBFdmVudCBET00gQVBJXG5mdW5jdGlvbiBoYW5kbGVFdmVudChldmVudCkge1xuICAgIHRoaXMuZGlzcGF0Y2hNZXNzYWdlKGV2ZW50LnR5cGUsIGV2ZW50KTtcbn1cblxuXG5mdW5jdGlvbiB0cmlnZ2VyKG1zZ1R5cGUsIGRhdGEpIHtcbiAgICBkYXRhID0gZGF0YSB8fCB7fTtcbiAgICBkYXRhLnR5cGUgPSAnbWVzc2FnZTonICsgbXNnVHlwZTtcbiAgICBcbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PSAnb2JqZWN0JylcbiAgICAgICAgd2luZG93LnBvc3RNZXNzYWdlKGRhdGEsICcqJylcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgTWVzc2VuZ2VyID0gcmVxdWlyZSgnLi4vbWVzc2VuZ2VyJylcbiAgICAsIERPTUVtaXR0ZXJTb3VyY2UgPSByZXF1aXJlKCcuL2RvbV9zb3VyY2UnKTtcblxuXG52YXIgd2luZG93U2VydmljZSA9IG5ldyBNZXNzZW5nZXI7XG52YXIgZG9tRW1pdHRlclNvdXJjZSA9IG5ldyBET01FbWl0dGVyU291cmNlKHdpbmRvd1NlcnZpY2UsIHsgdHJpZ2dlcjogJ3RyaWdnZXInIH0sIHVuZGVmaW5lZCwgd2luZG93KTtcbndpbmRvd1NlcnZpY2UuX3NldE1lc3NhZ2VTb3VyY2UoZG9tRW1pdHRlclNvdXJjZSk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSB3aW5kb3dTZXJ2aWNlO1xuXG5cbl8uZXh0ZW5kKHdpbmRvd1NlcnZpY2UsIHtcbiAgICBpc1RvcDogd2luZG93U2VydmljZV9pc1RvcFxufSk7XG5cblxuZnVuY3Rpb24gd2luZG93U2VydmljZV9pc1RvcCgpIHtcbiAgICByZXR1cm4gd2luZG93LnRvcCA9PSB3aW5kb3cuc2VsZiB8fCB3aW5kb3cuX19rYXJtYV9fO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY2xhc3Nlcy9WaWV3Jyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvR3JvdXAnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9XcmFwcGVyJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvVGV4dCcpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL1NlbGVjdCcpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL0lucHV0Jyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvSW5wdXRMaXN0Jyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvVGV4dGFyZWEnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9SYWRpb0dyb3VwJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvQnV0dG9uJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvSHlwZXJsaW5rJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvTGlzdCcpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL0xpc3RJdGVtJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvVGltZScpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL0RhdGUnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9Db21ibycpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL1N1cGVyQ29tYm8nKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9Db21ib0xpc3QnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9JbWFnZScpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL0Ryb3BUYXJnZXQnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9Gb2xkVHJlZScpO1xuXG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvYm9vdHN0cmFwL0Ryb3Bkb3duJyk7XG4vLyByZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvYm9vdHN0cmFwL0RpYWxvZycpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvRG9tJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvRGF0YScpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL0ZyYW1lJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvRXZlbnRzJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvT3B0aW9ucycpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL1RlbXBsYXRlJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvQ29udGFpbmVyJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvTW9kZWxGYWNldCcpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL0RyYWcnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy9jX2ZhY2V0cy9Ecm9wJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvTGlzdCcpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL0l0ZW0nKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy9jX2ZhY2V0cy9UcmFuc2ZlcicpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIGBtaWxvLnV0aWxzLmNoZWNrYFxuICpcbiAqIENoZWNrIGlzIGEgbW9kdWxlIGZvciBwYXJhbWV0ZXJzIGNoZWNraW5nIGV4dHJhY3RlZCBmcm9tIFtNZXRlb3JdKGh0dHA6Ly9kb2NzLm1ldGVvci5jb20vKSBmcmFtZXdvcmsuXG4gKlxuICogSXQgYWxsb3dzIHRvIGJvdGggZG9jdW1lbnQgYW5kIHRvIGNoZWNrIHBhcmFtZXRlciB0eXBlcyBpbiB5b3VyIGZ1bmN0aW9uXG4gKiBtYWtpbmcgY29kZSBib3RoIHJlYWRhYmxlIGFuZCBzdGFibGUuXG4gKlxuICpcbiAqICMjIyBVc2FnZVxuICpgYGBcbiAqIHZhciBjaGVjayA9IG1pbG8uY2hlY2tcbiAqICAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2g7XG4gKlxuICogZnVuY3Rpb24gTXkobmFtZSwgb2JqLCBjYikge1xuICogICAgIC8vIGlmIGFueSBvZiBjaGVja3MgZmFpbCBhbiBlcnJvciB3aWxsIGJlIHRocm93blxuICogICAgIGNoZWNrKG5hbWUsIFN0cmluZyk7XG4gKiAgICAgY2hlY2sob2JqLCBNYXRjaC5PYmplY3RJbmNsdWRpbmcoeyBvcHRpb25zOiBPYmplY3QgfSkpO1xuICogICAgIGNoZWNrKGNiLCBGdW5jdGlvbik7XG4gKlxuICogICAgIC8vIC4uLiB5b3VyIGNvZGVcbiAqIH1cbiAqYGBgXG4gKiBTZWUgW01ldGVvciBkb2NzXShodHRwOi8vZG9jcy5tZXRlb3IuY29tLyNtYXRjaCkgdG8gc2VlIGhvdyBpdCB3b3Jrc1xuICpcbiAqXG4gKiAjIyMgUGF0dGVybnNcbiAqXG4gKiBBbGwgcGF0dGVybnMgYW5kIGZ1bmN0aW9ucyBkZXNjcmliZWQgaW4gTWV0ZW9yIGRvY3Mgd29yay5cbiAqXG4gKiBVbmxpa2UgaW4gTWV0ZW9yLCBPYmplY3QgcGF0dGVybiBtYXRjaGVzIGluc3RhbmNlIG9mIGFueSBjbGFzcyxcbiAqIG5vdCBvbmx5IHBsYWluIG9iamVjdC5cbiAqXG4gKiBJbiBhZGRpdGlvbiB0byBwYXR0ZXJucyBkZXNjcmliZWQgaW4gTWV0ZW9yIGRvY3MgdGhlIGZvbGxvd2luZyBwYXR0ZXJucyBhcmUgaW1wbGVtZW50ZWRcbiAqXG4gKiAqIE1hdGNoLl9fT2JqZWN0SGFzaF9fKF9wYXR0ZXJuXylcbiAqXG4gKiAgIE1hdGNoZXMgYW4gb2JqZWN0IHdoZXJlIGFsbCBwcm9wZXJ0aWVzIG1hdGNoIGEgZ2l2ZW4gcGF0dGVyblxuICpcbiAqICogTWF0Y2guX19TdWJjbGFzc19fKF9jb25zdHJ1Y3Rvcl8gWywgX21hdGNoVGhpc0NsYXNzVG9vX10pXG4gKlxuICogICBNYXRjaGVzIGEgY2xhc3MgdGhhdCBpcyBhIHN1YmNsYXNzIG9mIGEgZ2l2ZW4gY2xhc3MuIElmIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gKiAgIGlzIHRydWUsIGl0IHdpbGwgYWxzbyBtYXRjaCB0aGUgY2xhc3MgaXRzZWxmLlxuICpcbiAqICAgV2l0aG91dCB0aGlzIHBhdHRlcm4gdG8gY2hlY2sgaWYgX015U3ViY2xhc3NfIGlzIGEgc3ViY2xhc3Mgb2YgX015Q2xhc3NfXG4gKiAgIHlvdSB3b3VsZCBoYXZlIHRvIHVzZVxuICpcbiAqICAgICAgIGNoZWNrKE15U3ViY2xhc3MsIE1hdGNoLldoZXJlKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgIHJldHVybiBNeVN1YmNsYXNzLnByb3RvdHlwZSBpbnN0YW5jZW9mIE15Q2xhc3M7XG4gKiAgICAgICB9KTtcbiAqXG4gKlxuICogVGhpbmdzIHdlIGV4cGxpY2l0bHkgZG8gTk9UIHN1cHBvcnQ6XG4gKiAgICAtIGhldGVyb2dlbm91cyBhcnJheXNcbioqL1xuXG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjb25maWcgPSByZXF1aXJlKCcuLi9jb25maWcnKTtcblxudmFyIGNoZWNrID0gZnVuY3Rpb24gKHZhbHVlLCBwYXR0ZXJuKSB7XG4gICAgaWYgKGNvbmZpZy5jaGVjayA9PT0gZmFsc2UpXG4gICAgICAgIHJldHVybjtcblxuICAgIC8vIFJlY29yZCB0aGF0IGNoZWNrIGdvdCBjYWxsZWQsIGlmIHNvbWVib2R5IGNhcmVkLlxuICAgIHRyeSB7XG4gICAgICAgIGNoZWNrU3VidHJlZSh2YWx1ZSwgcGF0dGVybik7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGlmICgoZXJyIGluc3RhbmNlb2YgTWF0Y2guRXJyb3IpICYmIGVyci5wYXRoKVxuICAgICAgICAgICAgZXJyLm1lc3NhZ2UgKz0gXCIgaW4gZmllbGQgXCIgKyBlcnIucGF0aDtcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gY2hlY2s7XG5cbnZhciBNYXRjaCA9IGNoZWNrLk1hdGNoID0ge1xuICAgIE9wdGlvbmFsOiBmdW5jdGlvbiAocGF0dGVybikge1xuICAgICAgICByZXR1cm4gbmV3IE9wdGlvbmFsKHBhdHRlcm4pO1xuICAgIH0sXG4gICAgT25lT2Y6IGZ1bmN0aW9uICgvKiBhcmd1bWVudHMgKi8pIHtcbiAgICAgICAgcmV0dXJuIG5ldyBPbmVPZihhcmd1bWVudHMpO1xuICAgIH0sXG4gICAgQW55OiBbJ19fYW55X18nXSxcbiAgICBXaGVyZTogZnVuY3Rpb24gKGNvbmRpdGlvbikge1xuICAgICAgICByZXR1cm4gbmV3IFdoZXJlKGNvbmRpdGlvbik7XG4gICAgfSxcbiAgICBPYmplY3RJbmNsdWRpbmc6IGZ1bmN0aW9uIChwYXR0ZXJuKSB7XG4gICAgICAgIHJldHVybiBuZXcgT2JqZWN0SW5jbHVkaW5nKHBhdHRlcm4pO1xuICAgIH0sXG4gICAgLy8gTWF0Y2hlcyBvbmx5IHNpZ25lZCAzMi1iaXQgaW50ZWdlcnNcbiAgICBJbnRlZ2VyOiBbJ19faW50ZWdlcl9fJ10sXG5cbiAgICAvLyBNYXRjaGVzIHN0cmluZyB0aGF0IGlzIGEgdmFsaWQgaWRlbnRpZmllciwgd2lsbCBub3QgYWxsb3cgamF2YXNjcmlwdCByZXNlcnZlZCB3b3Jkc1xuICAgIElkZW50aWZpZXJTdHJpbmc6IC9eW2Etel8kXVswLTlhLXpfJF0qJC9pLFxuXG4gICAgLy8gTWF0Y2hlcyBoYXNoIChvYmplY3QpIHdpdGggdmFsdWVzIG1hdGNoaW5nIHBhdHRlcm5cbiAgICBPYmplY3RIYXNoOiBmdW5jdGlvbihwYXR0ZXJuKSB7XG4gICAgICAgIHJldHVybiBuZXcgT2JqZWN0SGFzaChwYXR0ZXJuKTtcbiAgICB9LFxuXG4gICAgU3ViY2xhc3M6IGZ1bmN0aW9uKFN1cGVyY2xhc3MsIG1hdGNoU3VwZXJjbGFzc1Rvbykge1xuICAgICAgICByZXR1cm4gbmV3IFN1YmNsYXNzKFN1cGVyY2xhc3MsIG1hdGNoU3VwZXJjbGFzc1Rvbyk7XG4gICAgfSxcblxuICAgIC8vIFhYWCBtYXRjaGVycyBzaG91bGQga25vdyBob3cgdG8gZGVzY3JpYmUgdGhlbXNlbHZlcyBmb3IgZXJyb3JzXG4gICAgRXJyb3I6IFR5cGVFcnJvcixcblxuICAgIC8vIE1ldGVvci5tYWtlRXJyb3JUeXBlKFwiTWF0Y2guRXJyb3JcIiwgZnVuY3Rpb24gKG1zZykge1xuICAgICAgICAvLyB0aGlzLm1lc3NhZ2UgPSBcIk1hdGNoIGVycm9yOiBcIiArIG1zZztcbiAgICAgICAgLy8gVGhlIHBhdGggb2YgdGhlIHZhbHVlIHRoYXQgZmFpbGVkIHRvIG1hdGNoLiBJbml0aWFsbHkgZW1wdHksIHRoaXMgZ2V0c1xuICAgICAgICAvLyBwb3B1bGF0ZWQgYnkgY2F0Y2hpbmcgYW5kIHJldGhyb3dpbmcgdGhlIGV4Y2VwdGlvbiBhcyBpdCBnb2VzIGJhY2sgdXAgdGhlXG4gICAgICAgIC8vIHN0YWNrLlxuICAgICAgICAvLyBFLmcuOiBcInZhbHNbM10uZW50aXR5LmNyZWF0ZWRcIlxuICAgICAgICAvLyB0aGlzLnBhdGggPSBcIlwiO1xuICAgICAgICAvLyBJZiB0aGlzIGdldHMgc2VudCBvdmVyIEREUCwgZG9uJ3QgZ2l2ZSBmdWxsIGludGVybmFsIGRldGFpbHMgYnV0IGF0IGxlYXN0XG4gICAgICAgIC8vIHByb3ZpZGUgc29tZXRoaW5nIGJldHRlciB0aGFuIDUwMCBJbnRlcm5hbCBzZXJ2ZXIgZXJyb3IuXG4gICAgLy8gICAgIHRoaXMuc2FuaXRpemVkRXJyb3IgPSBuZXcgTWV0ZW9yLkVycm9yKDQwMCwgXCJNYXRjaCBmYWlsZWRcIik7XG4gICAgLy8gfSksXG5cbiAgICAvLyBUZXN0cyB0byBzZWUgaWYgdmFsdWUgbWF0Y2hlcyBwYXR0ZXJuLiBVbmxpa2UgY2hlY2ssIGl0IG1lcmVseSByZXR1cm5zIHRydWVcbiAgICAvLyBvciBmYWxzZSAodW5sZXNzIGFuIGVycm9yIG90aGVyIHRoYW4gTWF0Y2guRXJyb3Igd2FzIHRocm93bikuXG4gICAgdGVzdDogZnVuY3Rpb24gKHZhbHVlLCBwYXR0ZXJuKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjaGVja1N1YnRyZWUodmFsdWUsIHBhdHRlcm4pO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGlmIChlIGluc3RhbmNlb2YgTWF0Y2guRXJyb3IpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgLy8gUmV0aHJvdyBvdGhlciBlcnJvcnMuXG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuZnVuY3Rpb24gT3B0aW9uYWwocGF0dGVybikge1xuICAgIHRoaXMucGF0dGVybiA9IHBhdHRlcm47XG59O1xuXG5mdW5jdGlvbiBPbmVPZihjaG9pY2VzKSB7XG4gICAgaWYgKGNob2ljZXMubGVuZ3RoID09IDApXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIk11c3QgcHJvdmlkZSBhdCBsZWFzdCBvbmUgY2hvaWNlIHRvIE1hdGNoLk9uZU9mXCIpO1xuICAgIHRoaXMuY2hvaWNlcyA9IGNob2ljZXM7XG59O1xuXG5mdW5jdGlvbiBXaGVyZShjb25kaXRpb24pIHtcbiAgICB0aGlzLmNvbmRpdGlvbiA9IGNvbmRpdGlvbjtcbn07XG5cbmZ1bmN0aW9uIE9iamVjdEluY2x1ZGluZyhwYXR0ZXJuKSB7XG4gICAgdGhpcy5wYXR0ZXJuID0gcGF0dGVybjtcbn07XG5cbmZ1bmN0aW9uIE9iamVjdEhhc2gocGF0dGVybikge1xuICAgIHRoaXMucGF0dGVybiA9IHBhdHRlcm47XG59O1xuXG5mdW5jdGlvbiBTdWJjbGFzcyhTdXBlcmNsYXNzLCBtYXRjaFN1cGVyY2xhc3NUb28pIHtcbiAgICB0aGlzLlN1cGVyY2xhc3MgPSBTdXBlcmNsYXNzO1xuICAgIHRoaXMubWF0Y2hTdXBlcmNsYXNzID0gbWF0Y2hTdXBlcmNsYXNzVG9vO1xufTtcblxudmFyIHR5cGVvZkNoZWNrcyA9IFtcbiAgICBbU3RyaW5nLCBcInN0cmluZ1wiXSxcbiAgICBbTnVtYmVyLCBcIm51bWJlclwiXSxcbiAgICBbQm9vbGVhbiwgXCJib29sZWFuXCJdLFxuICAgIFtGdW5jdGlvbiwgXCJmdW5jdGlvblwiXSxcbiAgICAvLyBXaGlsZSB3ZSBkb24ndCBhbGxvdyB1bmRlZmluZWQgaW4gSlNPTiwgdGhpcyBpcyBnb29kIGZvciBvcHRpb25hbFxuICAgIC8vIGFyZ3VtZW50cyB3aXRoIE9uZU9mLlxuICAgIFt1bmRlZmluZWQsIFwidW5kZWZpbmVkXCJdXG5dO1xuXG5mdW5jdGlvbiBjaGVja1N1YnRyZWUodmFsdWUsIHBhdHRlcm4pIHtcbiAgICAvLyBNYXRjaCBhbnl0aGluZyFcbiAgICBpZiAocGF0dGVybiA9PT0gTWF0Y2guQW55KVxuICAgICAgICByZXR1cm47XG5cbiAgICAvLyBCYXNpYyBhdG9taWMgdHlwZXMuXG4gICAgLy8gRG8gbm90IG1hdGNoIGJveGVkIG9iamVjdHMgKGUuZy4gU3RyaW5nLCBCb29sZWFuKVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdHlwZW9mQ2hlY2tzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIGlmIChwYXR0ZXJuID09PSB0eXBlb2ZDaGVja3NbaV1bMF0pIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IHR5cGVvZkNoZWNrc1tpXVsxXSlcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB0aHJvdyBuZXcgTWF0Y2guRXJyb3IoXCJFeHBlY3RlZCBcIiArIHR5cGVvZkNoZWNrc1tpXVsxXSArIFwiLCBnb3QgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlb2YgdmFsdWUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChwYXR0ZXJuID09PSBudWxsKSB7XG4gICAgICAgIGlmICh2YWx1ZSA9PT0gbnVsbClcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgdGhyb3cgbmV3IE1hdGNoLkVycm9yKFwiRXhwZWN0ZWQgbnVsbCwgZ290IFwiICsgSlNPTi5zdHJpbmdpZnkodmFsdWUpKTtcbiAgICB9XG5cbiAgICAvLyBNYXRjaC5JbnRlZ2VyIGlzIHNwZWNpYWwgdHlwZSBlbmNvZGVkIHdpdGggYXJyYXlcbiAgICBpZiAocGF0dGVybiA9PT0gTWF0Y2guSW50ZWdlcikge1xuICAgICAgICAvLyBUaGVyZSBpcyBubyBjb25zaXN0ZW50IGFuZCByZWxpYWJsZSB3YXkgdG8gY2hlY2sgaWYgdmFyaWFibGUgaXMgYSA2NC1iaXRcbiAgICAgICAgLy8gaW50ZWdlci4gT25lIG9mIHRoZSBwb3B1bGFyIHNvbHV0aW9ucyBpcyB0byBnZXQgcmVtaW5kZXIgb2YgZGl2aXNpb24gYnkgMVxuICAgICAgICAvLyBidXQgdGhpcyBtZXRob2QgZmFpbHMgb24gcmVhbGx5IGxhcmdlIGZsb2F0cyB3aXRoIGJpZyBwcmVjaXNpb24uXG4gICAgICAgIC8vIEUuZy46IDEuMzQ4MTkyMzA4NDkxODI0ZSsyMyAlIDEgPT09IDAgaW4gVjhcbiAgICAgICAgLy8gQml0d2lzZSBvcGVyYXRvcnMgd29yayBjb25zaXN0YW50bHkgYnV0IGFsd2F5cyBjYXN0IHZhcmlhYmxlIHRvIDMyLWJpdFxuICAgICAgICAvLyBzaWduZWQgaW50ZWdlciBhY2NvcmRpbmcgdG8gSmF2YVNjcmlwdCBzcGVjcy5cbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgJiYgKHZhbHVlIHwgMCkgPT09IHZhbHVlKVxuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIHRocm93IG5ldyBNYXRjaC5FcnJvcignRXhwZWN0ZWQgSW50ZWdlciwgZ290ICdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKyAodmFsdWUgaW5zdGFuY2VvZiBPYmplY3QgPyBKU09OLnN0cmluZ2lmeSh2YWx1ZSkgOiB2YWx1ZSkpO1xuICAgIH1cblxuICAgIGlmIChwYXR0ZXJuID09PSBNYXRjaC5JZGVudGlmaWVyU3RyaW5nKSB7XG4gICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIE1hdGNoLklkZW50aWZpZXJTdHJpbmcudGVzdCh2YWx1ZSlcbiAgICAgICAgICAgICAgICAmJiBfanNLZXl3b3Jkcy5pbmRleE9mKGtleSkgPT0gLTEpXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIHRocm93IG5ldyBNYXRjaC5FcnJvcignRXhwZWN0ZWQgaWRlbnRpZmllciBzdHJpbmcsIGdvdCAnXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICsgKHZhbHVlIGluc3RhbmNlb2YgT2JqZWN0ID8gSlNPTi5zdHJpbmdpZnkodmFsdWUpIDogdmFsdWUpKTtcbiAgICB9XG5cbiAgICAvLyBcIk9iamVjdFwiIGlzIHNob3J0aGFuZCBmb3IgTWF0Y2guT2JqZWN0SW5jbHVkaW5nKHt9KTtcbiAgICBpZiAocGF0dGVybiA9PT0gT2JqZWN0KVxuICAgICAgICBwYXR0ZXJuID0gTWF0Y2guT2JqZWN0SW5jbHVkaW5nKHt9KTtcblxuICAgIC8vIEFycmF5IChjaGVja2VkIEFGVEVSIEFueSwgd2hpY2ggaXMgaW1wbGVtZW50ZWQgYXMgYW4gQXJyYXkpLlxuICAgIGlmIChwYXR0ZXJuIGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICAgICAgaWYgKHBhdHRlcm4ubGVuZ3RoICE9PSAxKVxuICAgICAgICAgICAgdGhyb3cgRXJyb3IoXCJCYWQgcGF0dGVybjogYXJyYXlzIG11c3QgaGF2ZSBvbmUgdHlwZSBlbGVtZW50XCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkocGF0dGVybikpO1xuICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgTWF0Y2guRXJyb3IoXCJFeHBlY3RlZCBhcnJheSwgZ290IFwiICsgSlNPTi5zdHJpbmdpZnkodmFsdWUpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhbHVlLmZvckVhY2goZnVuY3Rpb24gKHZhbHVlRWxlbWVudCwgaW5kZXgpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgY2hlY2tTdWJ0cmVlKHZhbHVlRWxlbWVudCwgcGF0dGVyblswXSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyIGluc3RhbmNlb2YgTWF0Y2guRXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgZXJyLnBhdGggPSBfcHJlcGVuZFBhdGgoaW5kZXgsIGVyci5wYXRoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEFyYml0cmFyeSB2YWxpZGF0aW9uIGNoZWNrcy4gVGhlIGNvbmRpdGlvbiBjYW4gcmV0dXJuIGZhbHNlIG9yIHRocm93IGFcbiAgICAvLyBNYXRjaC5FcnJvciAoaWUsIGl0IGNhbiBpbnRlcm5hbGx5IHVzZSBjaGVjaygpKSB0byBmYWlsLlxuICAgIGlmIChwYXR0ZXJuIGluc3RhbmNlb2YgV2hlcmUpIHtcbiAgICAgICAgaWYgKHBhdHRlcm4uY29uZGl0aW9uKHZhbHVlKSlcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgLy8gWFhYIHRoaXMgZXJyb3IgaXMgdGVycmlibGVcbiAgICAgICAgdGhyb3cgbmV3IE1hdGNoLkVycm9yKFwiRmFpbGVkIE1hdGNoLldoZXJlIHZhbGlkYXRpb25cIik7XG4gICAgfVxuXG5cbiAgICBpZiAocGF0dGVybiBpbnN0YW5jZW9mIE9wdGlvbmFsKVxuICAgICAgICBwYXR0ZXJuID0gTWF0Y2guT25lT2YodW5kZWZpbmVkLCBwYXR0ZXJuLnBhdHRlcm4pO1xuXG4gICAgaWYgKHBhdHRlcm4gaW5zdGFuY2VvZiBPbmVPZikge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBhdHRlcm4uY2hvaWNlcy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjaGVja1N1YnRyZWUodmFsdWUsIHBhdHRlcm4uY2hvaWNlc1tpXSk7XG4gICAgICAgICAgICAgICAgLy8gTm8gZXJyb3I/IFlheSwgcmV0dXJuLlxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIC8vIE90aGVyIGVycm9ycyBzaG91bGQgYmUgdGhyb3duLiBNYXRjaCBlcnJvcnMganVzdCBtZWFuIHRyeSBhbm90aGVyXG4gICAgICAgICAgICAgICAgLy8gY2hvaWNlLlxuICAgICAgICAgICAgICAgIGlmICghKGVyciBpbnN0YW5jZW9mIE1hdGNoLkVycm9yKSlcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIFhYWCB0aGlzIGVycm9yIGlzIHRlcnJpYmxlXG4gICAgICAgIHRocm93IG5ldyBNYXRjaC5FcnJvcihcIkZhaWxlZCBNYXRjaC5PbmVPZiBvciBNYXRjaC5PcHRpb25hbCB2YWxpZGF0aW9uXCIpO1xuICAgIH1cblxuICAgIC8vIEEgZnVuY3Rpb24gdGhhdCBpc24ndCBzb21ldGhpbmcgd2Ugc3BlY2lhbC1jYXNlIGlzIGFzc3VtZWQgdG8gYmUgYVxuICAgIC8vIGNvbnN0cnVjdG9yLlxuICAgIGlmIChwYXR0ZXJuIGluc3RhbmNlb2YgRnVuY3Rpb24pIHtcbiAgICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgcGF0dGVybilcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgLy8gWFhYIHdoYXQgaWYgLm5hbWUgaXNuJ3QgZGVmaW5lZFxuICAgICAgICB0aHJvdyBuZXcgTWF0Y2guRXJyb3IoXCJFeHBlY3RlZCBcIiArIHBhdHRlcm4uY29uc3RydWN0b3IubmFtZSk7XG4gICAgfVxuXG4gICAgdmFyIHVua25vd25LZXlzQWxsb3dlZCA9IGZhbHNlO1xuICAgIGlmIChwYXR0ZXJuIGluc3RhbmNlb2YgT2JqZWN0SW5jbHVkaW5nKSB7XG4gICAgICAgIHVua25vd25LZXlzQWxsb3dlZCA9IHRydWU7XG4gICAgICAgIHBhdHRlcm4gPSBwYXR0ZXJuLnBhdHRlcm47XG4gICAgfVxuXG4gICAgaWYgKHBhdHRlcm4gaW5zdGFuY2VvZiBPYmplY3RIYXNoKSB7XG4gICAgICAgIHZhciBrZXlQYXR0ZXJuID0gcGF0dGVybi5wYXR0ZXJuO1xuICAgICAgICB2YXIgZW1wdHlIYXNoID0gdHJ1ZTtcbiAgICAgICAgZm9yICh2YXIga2V5IGluIHZhbHVlKSB7XG4gICAgICAgICAgICBlbXB0eUhhc2ggPSBmYWxzZTtcbiAgICAgICAgICAgIGNoZWNrKHZhbHVlW2tleV0sIGtleVBhdHRlcm4pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChlbXB0eUhhc2gpXG4gICAgICAgICAgICB0aHJvdyBuZXcgTWF0Y2guRXJyb3IoXCJFeHBlY3RlZCBcIiArIHBhdHRlcm4uY29uc3RydWN0b3IubmFtZSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAocGF0dGVybiBpbnN0YW5jZW9mIFN1YmNsYXNzKSB7XG4gICAgICAgIHZhciBTdXBlcmNsYXNzID0gcGF0dGVybi5TdXBlcmNsYXNzO1xuICAgICAgICBpZiAocGF0dGVybi5tYXRjaFN1cGVyY2xhc3MgJiYgdmFsdWUgPT0gU3VwZXJjbGFzcylcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgaWYgKCEgKHZhbHVlLnByb3RvdHlwZSBpbnN0YW5jZW9mIFN1cGVyY2xhc3MpKVxuICAgICAgICAgICAgdGhyb3cgbmV3IE1hdGNoLkVycm9yKFwiRXhwZWN0ZWQgXCIgKyBwYXR0ZXJuLmNvbnN0cnVjdG9yLm5hbWUgKyBcIiBvZiBcIiArIFN1cGVyY2xhc3MubmFtZSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHBhdHRlcm4gIT09IFwib2JqZWN0XCIpXG4gICAgICAgIHRocm93IEVycm9yKFwiQmFkIHBhdHRlcm46IHVua25vd24gcGF0dGVybiB0eXBlXCIpO1xuXG4gICAgLy8gQW4gb2JqZWN0LCB3aXRoIHJlcXVpcmVkIGFuZCBvcHRpb25hbCBrZXlzLiBOb3RlIHRoYXQgdGhpcyBkb2VzIE5PVCBkb1xuICAgIC8vIHN0cnVjdHVyYWwgbWF0Y2hlcyBhZ2FpbnN0IG9iamVjdHMgb2Ygc3BlY2lhbCB0eXBlcyB0aGF0IGhhcHBlbiB0byBtYXRjaFxuICAgIC8vIHRoZSBwYXR0ZXJuOiB0aGlzIHJlYWxseSBuZWVkcyB0byBiZSBhIHBsYWluIG9sZCB7T2JqZWN0fSFcbiAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnb2JqZWN0JylcbiAgICAgICAgdGhyb3cgbmV3IE1hdGNoLkVycm9yKFwiRXhwZWN0ZWQgb2JqZWN0LCBnb3QgXCIgKyB0eXBlb2YgdmFsdWUpO1xuICAgIGlmICh2YWx1ZSA9PT0gbnVsbClcbiAgICAgICAgdGhyb3cgbmV3IE1hdGNoLkVycm9yKFwiRXhwZWN0ZWQgb2JqZWN0LCBnb3QgbnVsbFwiKTtcblxuICAgIHZhciByZXF1aXJlZFBhdHRlcm5zID0ge307XG4gICAgdmFyIG9wdGlvbmFsUGF0dGVybnMgPSB7fTtcblxuICAgIF8uZWFjaEtleShwYXR0ZXJuLCBmdW5jdGlvbihzdWJQYXR0ZXJuLCBrZXkpIHtcbiAgICAgICAgaWYgKHBhdHRlcm5ba2V5XSBpbnN0YW5jZW9mIE9wdGlvbmFsKVxuICAgICAgICAgICAgb3B0aW9uYWxQYXR0ZXJuc1trZXldID0gcGF0dGVybltrZXldLnBhdHRlcm47XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHJlcXVpcmVkUGF0dGVybnNba2V5XSA9IHBhdHRlcm5ba2V5XTtcbiAgICB9LCB0aGlzLCB0cnVlKTtcblxuICAgIF8uZWFjaEtleSh2YWx1ZSwgZnVuY3Rpb24oc3ViVmFsdWUsIGtleSkge1xuICAgICAgICB2YXIgc3ViVmFsdWUgPSB2YWx1ZVtrZXldO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKHJlcXVpcmVkUGF0dGVybnMuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICAgICAgICAgIGNoZWNrU3VidHJlZShzdWJWYWx1ZSwgcmVxdWlyZWRQYXR0ZXJuc1trZXldKTtcbiAgICAgICAgICAgICAgICBkZWxldGUgcmVxdWlyZWRQYXR0ZXJuc1trZXldO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25hbFBhdHRlcm5zLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICBjaGVja1N1YnRyZWUoc3ViVmFsdWUsIG9wdGlvbmFsUGF0dGVybnNba2V5XSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmICghdW5rbm93bktleXNBbGxvd2VkKVxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgTWF0Y2guRXJyb3IoXCJVbmtub3duIGtleVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBpZiAoZXJyIGluc3RhbmNlb2YgTWF0Y2guRXJyb3IpXG4gICAgICAgICAgICAgICAgZXJyLnBhdGggPSBfcHJlcGVuZFBhdGgoa2V5LCBlcnIucGF0aCk7XG4gICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH1cbiAgICB9LCB0aGlzLCB0cnVlKTtcblxuICAgIF8uZWFjaEtleShyZXF1aXJlZFBhdHRlcm5zLCBmdW5jdGlvbih2YWx1ZSwga2V5KSB7XG4gICAgICAgIHRocm93IG5ldyBNYXRjaC5FcnJvcihcIk1pc3Npbmcga2V5ICdcIiArIGtleSArIFwiJ1wiKTtcbiAgICB9LCB0aGlzLCB0cnVlKTtcbn07XG5cblxudmFyIF9qc0tleXdvcmRzID0gW1wiZG9cIiwgXCJpZlwiLCBcImluXCIsIFwiZm9yXCIsIFwibGV0XCIsIFwibmV3XCIsIFwidHJ5XCIsIFwidmFyXCIsIFwiY2FzZVwiLFxuICAgIFwiZWxzZVwiLCBcImVudW1cIiwgXCJldmFsXCIsIFwiZmFsc2VcIiwgXCJudWxsXCIsIFwidGhpc1wiLCBcInRydWVcIiwgXCJ2b2lkXCIsIFwid2l0aFwiLFxuICAgIFwiYnJlYWtcIiwgXCJjYXRjaFwiLCBcImNsYXNzXCIsIFwiY29uc3RcIiwgXCJzdXBlclwiLCBcInRocm93XCIsIFwid2hpbGVcIiwgXCJ5aWVsZFwiLFxuICAgIFwiZGVsZXRlXCIsIFwiZXhwb3J0XCIsIFwiaW1wb3J0XCIsIFwicHVibGljXCIsIFwicmV0dXJuXCIsIFwic3RhdGljXCIsIFwic3dpdGNoXCIsXG4gICAgXCJ0eXBlb2ZcIiwgXCJkZWZhdWx0XCIsIFwiZXh0ZW5kc1wiLCBcImZpbmFsbHlcIiwgXCJwYWNrYWdlXCIsIFwicHJpdmF0ZVwiLCBcImNvbnRpbnVlXCIsXG4gICAgXCJkZWJ1Z2dlclwiLCBcImZ1bmN0aW9uXCIsIFwiYXJndW1lbnRzXCIsIFwiaW50ZXJmYWNlXCIsIFwicHJvdGVjdGVkXCIsIFwiaW1wbGVtZW50c1wiLFxuICAgIFwiaW5zdGFuY2VvZlwiXTtcblxuLy8gQXNzdW1lcyB0aGUgYmFzZSBvZiBwYXRoIGlzIGFscmVhZHkgZXNjYXBlZCBwcm9wZXJseVxuLy8gcmV0dXJucyBrZXkgKyBiYXNlXG5mdW5jdGlvbiBfcHJlcGVuZFBhdGgoa2V5LCBiYXNlKSB7XG4gICAgaWYgKCh0eXBlb2Yga2V5KSA9PT0gXCJudW1iZXJcIiB8fCBrZXkubWF0Y2goL15bMC05XSskLykpXG4gICAgICAgIGtleSA9IFwiW1wiICsga2V5ICsgXCJdXCI7XG4gICAgZWxzZSBpZiAoIWtleS5tYXRjaChNYXRjaC5JZGVudGlmaWVyU3RyaW5nKSB8fCBfanNLZXl3b3Jkcy5pbmRleE9mKGtleSkgIT0gLTEpXG4gICAgICAgIGtleSA9IEpTT04uc3RyaW5naWZ5KFtrZXldKTtcblxuICAgIGlmIChiYXNlICYmIGJhc2VbMF0gIT09IFwiW1wiKVxuICAgICAgICByZXR1cm4ga2V5ICsgJy4nICsgYmFzZTtcbiAgICByZXR1cm4ga2V5ICsgYmFzZTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjb3VudCA9IHJlcXVpcmUoJy4vY291bnQnKVxuICAgICwgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJylcbiAgICAsIHByZWZpeCA9IGNvbmZpZy5jb21wb25lbnRQcmVmaXg7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBjb21wb25lbnROYW1lO1xuXG5cbmZ1bmN0aW9uIGNvbXBvbmVudE5hbWUoKSB7XG4gICAgcmV0dXJuIHByZWZpeCArIGNvdW50KCk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciB0aW1lc3RhbXAgPSBEYXRlLm5vdygpXG4gICAgLCBjb3VudCA9ICcnXG4gICAgLCB1bmlxdWVJRCA9ICcnICsgdGltZXN0YW1wO1xuXG5mdW5jdGlvbiB1bmlxdWVDb3VudCgpIHtcbiAgICB2YXIgbmV3VGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICB1bmlxdWVJRCA9ICcnICsgbmV3VGltZXN0YW1wO1xuICAgIGlmICh0aW1lc3RhbXAgPT0gbmV3VGltZXN0YW1wKSB7XG4gICAgICAgIGNvdW50ID0gY291bnQgPT09ICcnID8gMCA6IGNvdW50ICsgMTtcbiAgICAgICAgdW5pcXVlSUQgKz0gJ18nICsgY291bnQ7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGltZXN0YW1wID0gbmV3VGltZXN0YW1wO1xuICAgICAgICBjb3VudCA9ICcnO1xuICAgIH1cblxuICAgIHJldHVybiB1bmlxdWVJRDtcbn1cblxudW5pcXVlQ291bnQuZ2V0ID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHVuaXF1ZUlEO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHVuaXF1ZUNvdW50O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNyZWF0ZUNvbXBvbmVudENsYXNzO1xuXG4vKipcbiAqIFV0aWxpdHkgZnVuY3Rpb24gd2hpY2ggY3JlYXRlcyBhbmQgcmVnaXN0ZXJzIG5ldyBtaWxvIGNvbXBvbmVudC4gIFRoZSBjb21wb25lbnQgY3JlYXRlZCB3aWxsIGhhdmVcbiAqIGEgcmVmZXJlbmNlIHRvIHRoZSBzdXBlciBjbGFzcyB1c2VkIGluIGl0cyBjcmVhdGlvbiAoQWNjZXNzYWJsZSB1c2luZyA8Q29tcG9uZW50Q2xhc3M+LnN1cGVyKS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnLmNsYXNzTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBuZXcgY29tcG9uZW50XG4gKiBAcGFyYW0ge3N0cmluZ30gWydDb21wb25lbnQnXSBjb25maWcuc3VwZXJDbGFzc05hbWUgLSBUaGUgbmFtZSBvZiBhbiBleGlzdGluZyBjb21wb25lbnQgdG8gYmUgdXNlZCBhcyB0aGUgbmV3IGNvbXBvbmVudCdzIHN1cGVyIGNsYXNzXG4gKiBAcGFyYW0ge29iamVjdD19IGNvbmZpZy5mYWNldHMgLSBGYWNldCBjb25maWd1cmF0aW9uIChIYXNoIG9mIGZhY2V0IG5hbWUge3N0cmluZ30gdG8gY29uZmlnIHtvYmplY3R9KVxuICogQHBhcmFtIHtvYmplY3Q9fSBjb25maWcubWV0aG9kcyAtIE1ldGhvZHMgb2YgdGhlIG5ldyBjb21wb25lbnQgKEhhc2ggb2YgZnVuY3Rpb24gbmFtZSB7c3RyaW5nfSB0byBmdW5jdGlvbiB7ZnVuY3Rpb259KVxuICogQHBhcmFtIHtvYmplY3Q9fSBjb25maWcuc3RhdGljTWV0aG9kcyAtIFN0YXRpYyBtZXRob2RzIG9mIHRoZSBuZXcgY29tcG9uZW50IChIYXNoIG9mIGZ1bmN0aW9uIG5hbWUge3N0cmluZ30gdG8gZnVuY3Rpb24ge2Z1bmN0aW9ufSlcbiAqL1xuZnVuY3Rpb24gY3JlYXRlQ29tcG9uZW50Q2xhc3MoY29uZmlnKSB7XG4gICAgdmFyIGNvbXBvbmVudFJlZ2lzdHJ5ID0gbWlsby5yZWdpc3RyeS5jb21wb25lbnRzO1xuICAgIHZhciBTdXBlckNsYXNzID0gY29tcG9uZW50UmVnaXN0cnkuZ2V0KGNvbmZpZy5zdXBlckNsYXNzTmFtZSB8fCAnQ29tcG9uZW50Jyk7XG4gICAgdmFyIENvbXBvbmVudENsYXNzID0gU3VwZXJDbGFzcy5jcmVhdGVDb21wb25lbnRDbGFzcyhjb25maWcuY2xhc3NOYW1lLCBjb25maWcuZmFjZXRzKTtcblxuICAgIGlmKGNvbmZpZy5tZXRob2RzKSB7XG4gICAgICAgIF8uZXh0ZW5kUHJvdG8oQ29tcG9uZW50Q2xhc3MsIGNvbmZpZy5tZXRob2RzKTtcbiAgICB9XG5cbiAgICBpZihjb25maWcuc3RhdGljTWV0aG9kcykge1xuICAgICAgICBpZihjb25maWcuc3RhdGljTWV0aG9kcy5zdXBlciAhPT0gdW5kZWZpbmVkKSB0aHJvdyAnXFwnc3VwZXJcXCcgaXMgYSByZXNlcnZlZCBrZXl3b3JkJztcblxuICAgICAgICBfLmV4dGVuZChDb21wb25lbnRDbGFzcywgY29uZmlnLnN0YXRpY01ldGhvZHMpO1xuICAgIH1cblxuICAgIENvbXBvbmVudENsYXNzLnN1cGVyID0gU3VwZXJDbGFzcy5wcm90b3R5cGU7XG4gICAgXG4gICAgY29tcG9uZW50UmVnaXN0cnkuYWRkKENvbXBvbmVudENsYXNzKTtcblxuICAgIHJldHVybiBDb21wb25lbnRDbGFzcztcbn0iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIGNvbmZpZyA9IHJlcXVpcmUoJy4uL2NvbmZpZycpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4vbG9nZ2VyJyk7XG5cbnZhciBkb21VdGlscyA9IHtcbiAgICBjaGlsZHJlbjogY2hpbGRyZW4sXG4gICAgZmlsdGVyTm9kZUxpc3RCeVR5cGU6IGZpbHRlck5vZGVMaXN0QnlUeXBlLFxuICAgIGNvbnRhaW5pbmdFbGVtZW50OiBjb250YWluaW5nRWxlbWVudCxcbiAgICBzZWxlY3RFbGVtZW50Q29udGVudHM6IHNlbGVjdEVsZW1lbnRDb250ZW50cyxcbiAgICBzZWxlY3RFbGVtZW50VGV4dDogc2VsZWN0RWxlbWVudFRleHQsXG4gICAgZ2V0RWxlbWVudE9mZnNldDogZ2V0RWxlbWVudE9mZnNldCxcbiAgICBzZXRDYXJldFBvc2l0aW9uOiBzZXRDYXJldFBvc2l0aW9uLFxuICAgIGdldFNlbGVjdGlvbkRpcmVjdGlvbjogZ2V0U2VsZWN0aW9uRGlyZWN0aW9uLFxuICAgIHNldFNlbGVjdGlvbjogc2V0U2VsZWN0aW9uLFxuICAgIGNsZWFyU2VsZWN0aW9uOiBjbGVhclNlbGVjdGlvbixcbiAgICByZW1vdmVFbGVtZW50OiByZW1vdmVFbGVtZW50LFxuICAgIHVud3JhcEVsZW1lbnQ6IHVud3JhcEVsZW1lbnQsXG4gICAgd3JhcEluRWxlbWVudDogd3JhcEluRWxlbWVudCxcbiAgICBkZXRhY2hDb21wb25lbnQ6IGRldGFjaENvbXBvbmVudCxcbiAgICBmaXJzdFRleHROb2RlOiBmaXJzdFRleHROb2RlLFxuICAgIGxhc3RUZXh0Tm9kZTogbGFzdFRleHROb2RlLFxuICAgIHRyaW1Ob2RlUmlnaHQ6IHRyaW1Ob2RlUmlnaHQsXG4gICAgdHJpbU5vZGVMZWZ0OiB0cmltTm9kZUxlZnQsXG4gICAgc3RyaXBIdG1sOiBzdHJpcEh0bWwsXG4gICAgaHRtbEVudGl0aWVzOiBodG1sRW50aXRpZXMsXG4gICAgd2Fsa1RyZWU6IHdhbGtUcmVlLFxuICAgIGNyZWF0ZVRyZWVXYWxrZXI6IGNyZWF0ZVRyZWVXYWxrZXIsXG5cbiAgICB0cmVlUGF0aE9mOiB0cmVlUGF0aE9mLFxuICAgIGdldE5vZGVBdFRyZWVQYXRoOiBnZXROb2RlQXRUcmVlUGF0aCxcbiAgICBpbnNlcnRBdFRyZWVQYXRoOiBpbnNlcnRBdFRyZWVQYXRoLFxuICAgIGlzVHJlZVBhdGhCZWZvcmU6IGlzVHJlZVBhdGhCZWZvcmUsXG5cbiAgICBnZXROb2RlV2luZG93OiBnZXROb2RlV2luZG93LFxuXG4gICAgZ2V0Q29tcG9uZW50c0Zyb21SYW5nZTogZ2V0Q29tcG9uZW50c0Zyb21SYW5nZSxcbiAgICBkZWxldGVSYW5nZVdpdGhDb21wb25lbnRzOiBkZWxldGVSYW5nZVdpdGhDb21wb25lbnRzLFxuICAgIGZvckVhY2hOb2Rlc0luUmFuZ2U6IGZvckVhY2hOb2Rlc0luUmFuZ2UsXG4gICAgYXJlUmFuZ2VzRXF1YWw6IGFyZVJhbmdlc0VxdWFsLFxuXG4gICAgYWRkRGVidWdQb2ludDogYWRkRGVidWdQb2ludFxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBkb21VdGlscztcblxuXG4vKipcbiAqIFJldHVybnMgdGhlIGxpc3Qgb2YgZWxlbWVudCBjaGlsZHJlbiBvZiBET00gZWxlbWVudFxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgZWxlbWVudCB0byByZXR1cm4gdGhlIGNoaWxkcmVuIG9mIChvbmx5IERPTSBlbGVtZW50cylcbiAqIEByZXR1cm4ge0FycmF5W0VsZW1lbnRdfVxuICovXG4gZnVuY3Rpb24gY2hpbGRyZW4oZWwpIHtcbiAgICByZXR1cm4gZmlsdGVyTm9kZUxpc3RCeVR5cGUoZWwuY2hpbGROb2RlcywgTm9kZS5FTEVNRU5UX05PREUpO1xuIH1cblxuXG4vKipcbiAqIEZpbHRlcnMgdGhlIGxpc3Qgb2Ygbm9kZXMgYnkgdHlwZVxuICpcbiAqIEBwYXJhbSB7Tm9kZUxpc3R9IG5vZGVMaXN0IHRoZSBsaXN0IG9mIG5vZGVzLCBmb3IgZXhhbXBsZSBjaGlsZE5vZGVzIHByb3BlcnR5IG9mIERPTSBlbGVtZW50XG4gKiBAcGFyYW0ge0ludGVnZXJ9IG5vZGVUeXBlIGFuIGludGVnZXIgY29uc3RhbnQgW2RlZmluZWQgYnkgRE9NIEFQSV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL05vZGUubm9kZVR5cGUpLCBlLmcuIGBOb2RlLkVMRU1FTlRfTk9ERWAgb3IgYE5vZGUuVEVYVF9OT0RFYFxuICogQHJldHVybiB7QXJyYXlbTm9kZV19XG4gKi9cbmZ1bmN0aW9uIGZpbHRlck5vZGVMaXN0QnlUeXBlKG5vZGVMaXN0LCBub2RlVHlwZSkge1xuICAgIHJldHVybiBfLmZpbHRlcihub2RlTGlzdCwgZnVuY3Rpb24gKG5vZGUpIHtcbiAgICAgICAgcmV0dXJuIG5vZGUubm9kZVR5cGUgPT0gbm9kZVR5cGU7XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBGaW5kIG5lYXJlc3QgcGFyZW50IGVsZW1lbnQgZm9yIG5vZGUuXG4gKiBJZiBub2RlIGlzIGFuIGVsZW1lbnQsIGl0IHdpbGwgYmUgcmV0dXJuZWQuXG4gKlxuICogQHBhcmFtIHtOb2RlfSBub2RlXG4gKiBAcmV0dXJuIHtFbGVtZW50fG51bGx9XG4gKi9cbmZ1bmN0aW9uIGNvbnRhaW5pbmdFbGVtZW50KG5vZGUpIHtcbiAgICB3aGlsZSAobm9kZSkge1xuICAgICAgICBpZiAobm9kZS5ub2RlVHlwZSA9PSBOb2RlLkVMRU1FTlRfTk9ERSlcbiAgICAgICAgICAgIHJldHVybiBub2RlO1xuICAgICAgICBub2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cblxuXG4vKipcbiAqIFNlbGVjdHMgaW5uZXIgY29udGVudHMgb2YgRE9NIGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsIERPTSBlbGVtZW50XG4gKi9cbmZ1bmN0aW9uIHNlbGVjdEVsZW1lbnRDb250ZW50cyhlbCkge1xuICAgIHZhciBkb2MgPSBlbC5vd25lckRvY3VtZW50O1xuICAgIGlmICghIGRvYykgcmV0dXJuIGxvZ2dlci5lcnJvcignc2VsZWN0RWxlbWVudENvbnRlbnRzOiBlbGVtZW50IGhhcyBubyBkb2N1bWVudCcpO1xuICAgIHZhciByYW5nZSA9IGRvYy5jcmVhdGVSYW5nZSgpO1xuICAgIHJhbmdlLnNlbGVjdE5vZGVDb250ZW50cyhlbCk7XG4gICAgdmFyIHdpbiA9IGdldE5vZGVXaW5kb3coZWwpXG4gICAgICAgICwgc2VsID0gd2luLmdldFNlbGVjdGlvbigpO1xuICAgIHNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICBzZWwuYWRkUmFuZ2UocmFuZ2UpO1xufVxuXG5cbi8qKlxuICogU2VsZWN0cyB0ZXh0IGluc2lkZSBlbGVtZW50XG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsXG4gKi9cbmZ1bmN0aW9uIHNlbGVjdEVsZW1lbnRUZXh0KGVsKSB7XG4gICAgdmFyIGZyb21Ob2RlID0gZmlyc3RUZXh0Tm9kZShlbClcbiAgICAgICAgLCB0b05vZGUgPSBsYXN0VGV4dE5vZGUoZWwpO1xuXG4gICAgaWYgKGZyb21Ob2RlICYmIHRvTm9kZSlcbiAgICAgICAgc2V0U2VsZWN0aW9uKGZyb21Ob2RlLCAwLCB0b05vZGUsIHRvTm9kZS50ZXh0Q29udGVudC5sZW5ndGgpO1xufVxuXG5cbi8qKlxuICogU2V0cyB0aGUgY2FyZXQgcG9zaXRpb24gdG8gdGhlIHBvc2l0aW9uIGluIHRoZSBub2RlXG4gKlxuICogQHBhcmFtIHtOb2RlfSBub2RlIERPTSBub2RlXG4gKiBAcGFyYW0ge051bWJlcn0gcG9zIGNhcmV0IHBvc2l0aW9uXG4gKi9cbmZ1bmN0aW9uIHNldENhcmV0UG9zaXRpb24obm9kZSwgcG9zKSB7XG4gICAgdmFyIGRvYyA9IG5vZGUub3duZXJEb2N1bWVudDtcbiAgICBpZiAoISBkb2MpIHJldHVybiBsb2dnZXIuZXJyb3IoJ3NldENhcmV0UG9zaXRpb246IGVsZW1lbnQgaGFzIG5vIGRvY3VtZW50Jyk7XG4gICAgdmFyIHJhbmdlID0gZG9jLmNyZWF0ZVJhbmdlKCk7XG4gICAgcmFuZ2Uuc2V0U3RhcnQobm9kZSwgcG9zKTtcbiAgICB2YXIgd2luID0gZ2V0Tm9kZVdpbmRvdyhub2RlKVxuICAgICAgICAsIHNlbCA9IHdpbi5nZXRTZWxlY3Rpb24oKTtcbiAgICBzZWwucmVtb3ZlQWxsUmFuZ2VzKCk7XG4gICAgc2VsLmFkZFJhbmdlKHJhbmdlKTtcbn1cblxuLyoqXG4gKiBnZXQgdGhlIGRpcmVjdGlvbiBvZiBhIHNlbGVjdGlvblxuICpcbiAqIDEgZm9yd2FyZCwgLTEgYmFja3dhcmQsIDAgbm8gZGlyZWN0aW9uLCB1bmRlZmluZWQgb25lIG9mIHRoZSBub2RlIGlzIGRldGFjaGVkIG9yIGluIGEgZGlmZmVyZW50IGZyYW1lXG4gKlxuICogQHBhcmFtIHtzZWx9IGEgc2VsZWN0aW9uIG9iamVjdFxuICogQHJldHVybiB7LTF8MHwxfHVuZGVmaW5lZH1cbiAqL1xuZnVuY3Rpb24gZ2V0U2VsZWN0aW9uRGlyZWN0aW9uKHNlbCl7XG4gICAgcmV0dXJuIF9nZXREaXJlY3Rpb24oc2VsLmFuY2hvck5vZGUsIHNlbC5hbmNob3JPZmZzZXQsIHNlbC5mb2N1c05vZGUsIHNlbC5mb2N1c09mZnNldCk7XG59XG5cbmZ1bmN0aW9uIF9nZXREaXJlY3Rpb24oZnJvbU5vZGUsIHN0YXJ0T2Zmc2V0LCB0b05vZGUsIGVuZE9mZnNldCl7XG4gICAgdmFyIGRvY1Bvc2l0aW9uID0gZnJvbU5vZGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24odG9Ob2RlKTtcbiAgICBpZiAoZG9jUG9zaXRpb24gJiBOb2RlLkRPQ1VNRU5UX1BPU0lUSU9OX0ZPTExPV0lORyl7XG4gICAgICAgIHJldHVybiAxO1xuICAgIH1cbiAgICBlbHNlIGlmIChkb2NQb3NpdGlvbiAmIE5vZGUuRE9DVU1FTlRfUE9TSVRJT05fUFJFQ0VESU5HKXtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cbiAgICBlbHNlIGlmIChmcm9tTm9kZSA9PSB0b05vZGUpe1xuICAgICAgICBpZiAoc3RhcnRPZmZzZXQgPCBlbmRPZmZzZXQpe1xuICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoc3RhcnRPZmZzZXQgPiBlbmRPZmZzZXQpe1xuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogU2VsZWN0cyBhIHJhbmdlIGluIGEgZG9jdW1lbnRcbiAqXG4gKiBAcGFyYW0ge05vZGV9IGZyb21Ob2RlIERPTSBub2RlIHRvIHN0YXJ0IHNlbGVjdGlvbiBpblxuICogQHBhcmFtIHtOdW1iZXJ9IHN0YXJ0T2Zmc2V0XG4gKiBAcGFyYW0ge05vZGV9IHRvTm9kZSBET00gbm9kZSB0byBlbmQgc2VsZWN0aW9uIGluXG4gKiBAcGFyYW0ge051bWJlcn0gZW5kT2Zmc2V0XG4gKi9cbmZ1bmN0aW9uIHNldFNlbGVjdGlvbihmcm9tTm9kZSwgc3RhcnRPZmZzZXQsIHRvTm9kZSwgZW5kT2Zmc2V0KSB7XG4gICAgdmFyIGRvYyA9IGZyb21Ob2RlLm93bmVyRG9jdW1lbnQ7XG4gICAgaWYgKCEgZG9jKSByZXR1cm4gbG9nZ2VyKCdzZXRDYXJldFBvc2l0aW9uOiBlbGVtZW50IGhhcyBubyBkb2N1bWVudCcpO1xuICAgIHZhciBiYWNrd2FyZCA9IF9nZXREaXJlY3Rpb24oZnJvbU5vZGUsIHN0YXJ0T2Zmc2V0LCB0b05vZGUsIGVuZE9mZnNldCkgPT0gLTE7XG4gICAgdmFyIHJhbmdlID0gZG9jLmNyZWF0ZVJhbmdlKCk7XG4gICAgdmFyIGNvbnRhaW5lciwgb3JpZ2luYWxDb250ZW50RWRpdGFibGU7XG4gICAgLy8gZG9lcyBub3Qgd29yayBpbiBub24gY29udGVudEVkaXRhYmxlIGl0ZW1zXG5cbiAgICB2YXIgd2luID0gZ2V0Tm9kZVdpbmRvdyhmcm9tTm9kZSlcbiAgICAgICAgLCBzZWwgPSB3aW4uZ2V0U2VsZWN0aW9uKCk7XG5cblxuICAgIGlmIChiYWNrd2FyZCl7XG4gICAgICAgIHJhbmdlLnNldFN0YXJ0KHRvTm9kZSwgZW5kT2Zmc2V0KTtcbiAgICAgICAgcmFuZ2Uuc2V0RW5kKGZyb21Ob2RlLCBzdGFydE9mZnNldCk7XG4gICAgICAgIHJhbmdlLmNvbGxhcHNlKGZhbHNlKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJhbmdlLnNldFN0YXJ0KGZyb21Ob2RlLCBzdGFydE9mZnNldCk7XG4gICAgICAgIHJhbmdlLnNldEVuZCh0b05vZGUsIGVuZE9mZnNldCk7XG4gICAgfVxuXG4gICAgY29udGFpbmVyID0gcmFuZ2UuY29tbW9uQW5jZXN0b3JDb250YWluZXIgPT0gTm9kZS5FTEVNRU5UX05PREUgP1xuICAgICAgICByYW5nZS5jb21tb25BbmNlc3RvckNvbnRhaW5lciA6XG4gICAgICAgIHJhbmdlLmNvbW1vbkFuY2VzdG9yQ29udGFpbmVyLnBhcmVudEVsZW1lbnQ7XG5cbiAgICBpZiAoIWNvbnRhaW5lci5pc0NvbnRlbnRFZGl0YWJsZSl7XG4gICAgICAgIG9yaWdpbmFsQ29udGVudEVkaXRhYmxlID0gY29udGFpbmVyLmNvbnRlbnRFZGl0YWJsZTsgLy8gZmFsc2Ugb3IgaW5oZXJpdFxuICAgICAgICBjb250YWluZXIuY29udGVudEVkaXRhYmxlID0gXCJ0cnVlXCI7XG4gICAgfVxuXG4gICAgc2VsLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgIHNlbC5hZGRSYW5nZShyYW5nZSk7XG5cbiAgICBpZiAoYmFja3dhcmQpe1xuICAgICAgICBzZWwuZXh0ZW5kKHRvTm9kZSwgZW5kT2Zmc2V0KTtcbiAgICB9XG5cbiAgICBpZiAob3JpZ2luYWxDb250ZW50RWRpdGFibGUpe1xuICAgICAgICAvLyByZXN0b3JpbmcgY29udGVudEVkaXRhYmxlXG4gICAgICAgIGNvbnRhaW5lci5jb250ZW50RWRpdGFibGUgPSBvcmlnaW5hbENvbnRlbnRFZGl0YWJsZTtcbiAgICB9XG59XG5cbi8qKlxuICogQ2xlYXJzIHNlbGVjdGlvbiBpbiBhIGdpdmVuIHdpbmRvd1xuICogQHBhcmFtIHtXaW5kb3d9IHdpblxuICovXG5mdW5jdGlvbiBjbGVhclNlbGVjdGlvbih3aW4pIHtcbiAgICB3aW4gPSB3aW4gfHwgd2luZG93O1xuICAgIHZhciBzZWwgPSB3aW4uZ2V0U2VsZWN0aW9uKCk7XG4gICAgc2VsLnJlbW92ZUFsbFJhbmdlcygpO1xufVxuXG5cbi8qKlxuICogQ2FsY3VsYXRlcyBhbiBlbGVtZW50J3MgdG90YWwgdG9wIGFuZCBsZWZ0IG9mZnNldCBmcm9tIHRoZSBkb2N1bWVudCBlZGdlLlxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgdGhlIGVsZW1lbnQgZm9yIHdoaWNoIHBvc2l0aW9uIG5lZWRzIHRvIGJlIHJldHVybmVkXG4gKiBAcGFyYW0ge2luY2x1ZGVCb3JkZXJ9IGlmIGlzIHRvIGluY2x1ZGUgdGhlIGJvcmRlciB3aWR0aFxuICogQHJldHVybiB7T2JqZWN0fSB2ZWN0b3Igb2JqZWN0IHdpdGggcHJvcGVydGllcyB0b3BPZmZzZXQgYW5kIGxlZnRPZmZzZXRcbiAqL1xuZnVuY3Rpb24gZ2V0RWxlbWVudE9mZnNldChlbCwgaW5jbHVkZUJvcmRlcikge1xuICAgIHZhciB5UG9zLCB4UG9zO1xuXG4gICAgeVBvcyA9IGVsLm9mZnNldFRvcDtcbiAgICB4UG9zID0gZWwub2Zmc2V0TGVmdDtcbiAgICBlbCA9IGVsLm9mZnNldFBhcmVudDtcblxuICAgIHdoaWxlIChlbCkge1xuICAgICAgICB5UG9zICs9IGVsLm9mZnNldFRvcCArIGdldEJvcmRlcihlbCwgJ0hlaWdodCcsIGluY2x1ZGVCb3JkZXIpO1xuICAgICAgICB4UG9zICs9IGVsLm9mZnNldExlZnQgKyBnZXRCb3JkZXIoZWwsICdXaWR0aCcsIGluY2x1ZGVCb3JkZXIpO1xuICAgICAgICBlbCA9IGVsLm9mZnNldFBhcmVudDtcbiAgICB9XG5cbiAgICByZXR1cm4geyB0b3BPZmZzZXQ6IHlQb3MsIGxlZnRPZmZzZXQ6IHhQb3MgfTtcbn1cblxuXG5mdW5jdGlvbiBnZXRCb3JkZXIoZWwsIHR5cGUsIGluY2x1ZGVCb3JkZXIpIHtcbiAgICBpZiAoaW5jbHVkZUJvcmRlcikge1xuICAgICAgICB2YXIgc2lkZSA9ICh0eXBlID09ICdIZWlnaHQnKSA/ICd0b3AnIDogJ2xlZnQnLFxuICAgICAgICAgICAgc3R5bGVzID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoZWwpLFxuICAgICAgICAgICAgc2lkZVZhbHVlID0gcGFyc2VJbnQoc3R5bGVzLmdldFByb3BlcnR5VmFsdWUoJ2JvcmRlci0nICsgc2lkZSArICctd2lkdGgnKSwgMTApO1xuXG4gICAgICAgIGlmIChzaWRlVmFsdWUpIHJldHVybiBzaWRlVmFsdWU7XG4gICAgfVxuICAgIHJldHVybiAwO1xufVxuXG5cbi8qKlxuICogUmVtb3ZlcyBlbGVtZW50IGZyb20gdGhlIGRvY3VtZW50XG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBlbCB0aGUgZWxlbWVudCB0byBiZSByZW1vdmVkXG4gKi9cbmZ1bmN0aW9uIHJlbW92ZUVsZW1lbnQoZWwpIHtcbiAgICB2YXIgcGFyZW50ID0gZWwucGFyZW50Tm9kZTtcbiAgICBpZiAocGFyZW50KXtcbiAgICAgICAgcGFyZW50LnJlbW92ZUNoaWxkKGVsKTtcbiAgICAgICAgcGFyZW50Lm5vcm1hbGl6ZSgpO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIFJldHVybnMgdGhlIGZpcnN0IGNoaWxkIHRleHQgbm9kZSBvZiBhbiBlbGVtZW50XG4gKlxuICogQHBhcmFtIHtFbGVtZW50fE5vZGV9IG5vZGUgdGhlIG5vZGUgdG8gYmUgc2VhcmNoZWQsIGlmIHRoZSBub2RlIGlzIHRleHQgbm9kZSB3ZSByZXR1cm4gdGhlIG5vZGUuXG4gKiBAcmV0dXJuIHtUZXh0Tm9kZX1cbiAqL1xuZnVuY3Rpb24gZmlyc3RUZXh0Tm9kZShub2RlKSB7XG4gICAgaWYgKG5vZGUubm9kZVR5cGUgPT0gTm9kZS5URVhUX05PREUpIHJldHVybiBub2RlO1xuICAgIHZhciB0cmVlV2Fsa2VyID0gY3JlYXRlVHJlZVdhbGtlcihub2RlLCBOb2RlRmlsdGVyLlNIT1dfVEVYVCk7XG4gICAgcmV0dXJuIHRyZWVXYWxrZXIuZmlyc3RDaGlsZCgpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgbGFzdCBjaGlsZCB0ZXh0IG5vZGUgb2YgYW4gZWxlbWVudFxuICpcbiAqIEBwYXJhbSB7RWxlbWVudHxOb2RlfSBub2RlIHRoZSBub2RlIHRvIGJlIHNlYXJjaGVkLCBpZiB0aGUgbm9kZSBpcyB0ZXh0IG5vZGUgd2UgcmV0dXJuIHRoZSBub2RlLlxuICogQHJldHVybiB7VGV4dE5vZGV9XG4gKi9cbmZ1bmN0aW9uIGxhc3RUZXh0Tm9kZShub2RlKSB7XG4gICAgaWYgKG5vZGUubm9kZVR5cGUgPT0gTm9kZS5URVhUX05PREUpIHJldHVybiBub2RlO1xuICAgIHZhciB0cmVlV2Fsa2VyID0gY3JlYXRlVHJlZVdhbGtlcihub2RlLCBOb2RlRmlsdGVyLlNIT1dfVEVYVCk7XG4gICAgcmV0dXJuIHRyZWVXYWxrZXIubGFzdENoaWxkKCk7XG59XG5cblxuLyoqXG4gKiBSZW1vdmVzIGVsZW1lbnQgZnJvbSB0aGUgZG9jdW1lbnQgcHV0dGluZyBpdHMgY2hpbGRyZW4gaW4gaXRzIHBsYWNlXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBlbCB0aGUgZWxlbWVudCB0byBiZSBcInVud3JhcHBlZFwiXG4gKi9cbmZ1bmN0aW9uIHVud3JhcEVsZW1lbnQoZWwpIHtcbiAgICB2YXIgcGFyZW50ID0gZWwucGFyZW50Tm9kZTtcblxuICAgIGlmIChwYXJlbnQpIHtcbiAgICAgICAgdmFyIGZyYWcgPSBkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7XG4gICAgICAgIC8vIG11c3QgYmUgY29waWVkIHRvIGF2b2lkIGl0ZXJhdGluZyBhIG11dGF0aW5nIGxpc3Qgb2YgY2hpbGROb2Rlc1xuICAgICAgICB2YXIgY2hpbGRyZW4gPSBfLnNsaWNlKGVsLmNoaWxkTm9kZXMpO1xuICAgICAgICBjaGlsZHJlbi5mb3JFYWNoKGZyYWcuYXBwZW5kQ2hpbGQsIGZyYWcpO1xuICAgICAgICBwYXJlbnQucmVwbGFjZUNoaWxkKGZyYWcsIGVsKTtcbiAgICAgICAgcGFyZW50Lm5vcm1hbGl6ZSgpO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIFdyYXBzIGFuIGVsZW1lbnQgaW4gYW5vdGhlciBlbGVtZW50XG4gKlxuICogQHBhcmFtICB7RWxlbWVudH0gd3JhcEludG9FbFxuICogQHBhcmFtICB7RWxlbWVudH0gZWxcbiAqL1xuZnVuY3Rpb24gd3JhcEluRWxlbWVudCh3cmFwSW50b0VsLCBlbCkge1xuICAgIHZhciBwYXJlbnQgPSBlbC5wYXJlbnROb2RlO1xuXG4gICAgaWYgKHBhcmVudCkge1xuICAgICAgICBwYXJlbnQuaW5zZXJ0QmVmb3JlKHdyYXBJbnRvRWwsIGVsKTtcbiAgICAgICAgd3JhcEludG9FbC5hcHBlbmRDaGlsZChlbCk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogVHJpbXMgYSB0ZXh0IG5vZGUgb2YgdHJhaWxpbmcgc3BhY2VzLCBhbmQgcmV0dXJucyB0cnVlIGlmIGEgdHJpbSB3YXMgcGVyZm9ybWVkLlxuICpcbiAqIEBwYXJhbSAge1RleHROb2RlfSBub2RlXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiB0cmltTm9kZVJpZ2h0KG5vZGUpIHtcbiAgICByZXR1cm4gX3RyaW1Ob2RlKG5vZGUsICd0cmltUmlnaHQnKTtcbn1cblxuXG4vKipcbiAqIFRyaW1zIGEgdGV4dCBub2RlIG9mIGxlYWRpbmcgc3BhY2VzLCBhbmQgcmV0dXJucyB0cnVlIGlmIGEgdHJpbSB3YXMgcGVyZm9ybWVkLlxuICpcbiAqIEBwYXJhbSAge1RleHROb2RlfSBub2RlXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiB0cmltTm9kZUxlZnQobm9kZSkge1xuICAgIHJldHVybiBfdHJpbU5vZGUobm9kZSwgJ3RyaW1MZWZ0Jyk7XG59XG5cblxuZnVuY3Rpb24gX3RyaW1Ob2RlKG5vZGUsIG1ldGhvZE5hbWUpIHtcbiAgICB2YXIgbGVuID0gbm9kZS5sZW5ndGg7XG4gICAgbm9kZS50ZXh0Q29udGVudCA9IG5vZGUudGV4dENvbnRlbnRbbWV0aG9kTmFtZV0oKTtcbiAgICByZXR1cm4gbGVuICE9PSBub2RlLmxlbmd0aDtcbn1cblxuXG4vKipcbiAqIFJlbW92ZXMgdGhlIHJlZmVyZW5jZSB0byBjb21wb25lbnQgZnJvbSBlbGVtZW50XG4gKlxuICogQHBhcmFtICB7RWxlbWVudH0gZWxcbiAqL1xuZnVuY3Rpb24gZGV0YWNoQ29tcG9uZW50KGVsKSB7XG4gICAgZGVsZXRlIGVsW2NvbmZpZy5jb21wb25lbnRSZWZdO1xufVxuXG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBjb250ZW50IG9mIGEgaHRtbCBzdHJpbmdcbiAqIEBwYXJhbSAge1N0cmluZ30gc3RyIEFueSBzdHJpbmdcbiAqIEByZXR1cm4ge1N0cmluZ30gcmV0dXJucyB0aGUgc3RyaW5nIGNsZWFuZWQgb2YgYW55IGh0bWwgY29udGVudC5cbiAqL1xuZnVuY3Rpb24gc3RyaXBIdG1sKHN0cikge1xuICAgIHZhciBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdESVYnKTtcbiAgICBkaXYuaW5uZXJIVE1MID0gc3RyO1xuICAgIHJldHVybiBkaXYudGV4dENvbnRlbnQgfHwgJyc7XG59XG5cblxuLyoqXG4gKiBDb252ZW5pZW5jZSB3cmFwcGVyIGZvciBuYXRpdmUgVHJlZVdhbGtlciB0aGF0IGF1dG9tYXRpY2FsbHkgd2Fsa3MgdGhlIHRyZWUgYW5kIGNhbGxzIGFuIGl0ZXJhdG9yIGZ1bmN0aW9uLlxuICogVGhpcyB3aWxsIG5vdCBpdGVyYXRlIHRoZSByb290IGVsZW1lbnQuXG4gKiBAcGFyYW0gIHtIVE1MRWxlbWVudH0gcm9vdCBUaGUgY29udGFpbmluZyByb290IGVsZW1lbnQgdG8gYmUgd2Fsa2VkLiBXaWxsIG5vdCBiZSBpdGVyYXRlZC5cbiAqIEBwYXJhbSAge05vZGVGaWxlcn0gZmlsdGVyIEEgTm9kZUZpbHRlciBjb25zdGFudCwgc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuL2RvY3MvV2ViL0FQSS9UcmVlV2Fsa2VyXG4gKiBAcGFyYW0gIHtGdW5jdGlvbn0gaXRlcmF0b3IgQSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgb24gZWFjaCBub2RlLiBSZXR1cm5pbmcgJ2ZhbHNlJyB3aWxsIGJyZWFrLlxuICogQHBhcmFtICB7T2JqZWN0fSBjb250ZXh0IEFuIG9wdGlvbmFsIGNvbnRleHQgdG8gcGFzc2VkLCBkZWZhdWx0cyB0byByb290LlxuICovXG5mdW5jdGlvbiB3YWxrVHJlZShyb290LCBmaWx0ZXIsIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgdmFyIHR3ID0gZG9jdW1lbnQuY3JlYXRlVHJlZVdhbGtlcihyb290LCBmaWx0ZXIpO1xuICAgIHdoaWxlKHR3Lm5leHROb2RlKCkpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IGl0ZXJhdG9yLmNhbGwoY29udGV4dCB8fCByb290LCB0dy5jdXJyZW50Tm9kZSk7XG4gICAgICAgIGlmIChyZXN1bHQgPT09IGZhbHNlKSBicmVhaztcbiAgICB9XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGFycmF5IG9mIGNoaWxkIGluZGV4ZXMgb2YgZWxlbWVudCBwYXRoIGluc2lkZSByb290IGVsZW1lbnQgaW4gRE9NIHRyZWUgdXNpbmcgYnJlYWR0aCBmaXJzdCB0cmVlIHRyYXZlcnNhbC5cbiAqIFJldHVybnMgdW5kZWZpbmVkIGlmIHRoZSBlbGVtZW50IGlzIG5vdCBpbnNpZGUgcm9vdCBlbGVtZW50LCAwIGlmIHRoZSByb290IGVsZW1lbnQgaXRzZWxmIGlzIHBhc3NlZC5cbiAqXG4gKiBAcGFyYW0gIHtFbGVtZW50fSByb290RWwgZWxlbWVudCB0byBzZWFyY2hcbiAqIEBwYXJhbSAge0VsZW1lbnR9IGVsIGVsZW1lbnQgdG8gZmluZCB0aGUgaW5kZXggb2ZcbiAqIEByZXR1cm4ge0FycmF5W051bWJlcl19XG4gKi9cbmZ1bmN0aW9uIHRyZWVQYXRoT2Yocm9vdEVsLCBlbCkge1xuICAgIGlmICghIChyb290RWwgJiYgcm9vdEVsLmNvbnRhaW5zKGVsKSkpIHJldHVybjtcblxuICAgIHZhciB0cmVlUGF0aCA9IFtdXG4gICAgICAgICwgbm9kZSA9IHJvb3RFbDtcblxuICAgIHdoaWxlIChub2RlICE9IGVsKSB7XG4gICAgICAgIHZhciBub2RlSW5kZXggPSBfLmZpbmRJbmRleChub2RlLmNoaWxkTm9kZXMsIGNvbnRhaW5zRWwpO1xuICAgICAgICB0cmVlUGF0aC5wdXNoKG5vZGVJbmRleCk7XG4gICAgICAgIG5vZGUgPSBub2RlLmNoaWxkTm9kZXNbbm9kZUluZGV4XTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJlZVBhdGg7XG5cbiAgICBmdW5jdGlvbiBjb250YWluc0VsKGNoaWxkKSB7XG4gICAgICAgIHJldHVybiBjaGlsZC5jb250YWlucyhlbCk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogUmV0dXJucyBlbGVtZW50IGF0IGdpdmVuIHRyZWUgcGF0aFxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gcm9vdEVsXG4gKiBAcGFyYW0ge0FycmF5W051bWJlcl19IHRyZWVQYXRoXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG5lYXJlc3QgcmV0dXJuIG5lYXJlc3QgcG9zc2libGUgbm9kZSBpZiBleGFjdCBub2RlIGRvZXMgbm90IGV4aXN0XG4gKiBAcmV0dXJuIHtOb2RlfVxuICovXG5mdW5jdGlvbiBnZXROb2RlQXRUcmVlUGF0aChyb290RWwsIHRyZWVQYXRoLCBuZWFyZXN0KSB7XG4gICAgaWYgKCF0cmVlUGF0aCkgcmV0dXJuO1xuXG4gICAgdmFyIGxlbiA9IHRyZWVQYXRoLmxlbmd0aDtcbiAgICBpZiAobGVuID09PSAwKSByZXR1cm4gcm9vdEVsO1xuXG4gICAgdmFyIG5vZGUgPSByb290RWw7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIHZhciBjaGlsZHJlbiA9IG5vZGUuY2hpbGROb2RlcztcbiAgICAgICAgaWYgKCEgY2hpbGRyZW4pIHtcbiAgICAgICAgICAgIGlmICghIG5lYXJlc3QpIG5vZGUgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICB2YXIgY2hpbGRJbmRleCA9IHRyZWVQYXRoW2ldXG4gICAgICAgICAgICAsIGNoaWxkID0gY2hpbGRyZW5bY2hpbGRJbmRleF07XG4gICAgICAgIGlmICghIGNoaWxkKSB7XG4gICAgICAgICAgICBub2RlID0gbmVhcmVzdFxuICAgICAgICAgICAgICAgICAgICA/IGNoaWxkcmVuW2NoaWxkcmVuLmxlbmd0aCAtIDFdXG4gICAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgbm9kZSA9IGNoaWxkO1xuICAgIH1cblxuICAgIHJldHVybiBub2RlO1xufVxuXG5cbi8qKlxuICogSW5zZXJ0cyBhbiBlbGVtZW50IGluc2lkZSByb290IGF0IGEgZ2l2ZW4gcGF0aCBpbiB0cmVlICh0aGF0IGhhcyB0aGUgc2FtZSBtZWFuaW5nIGFzIHRoZSBpbmRleCByZXR1cm5lZCBieSBgdHJlZVBhdGhPZmAgZnVuY3Rpb24pLiBJZiBlbGVtZW50IGlzIGFscmVhZHkgaW4gdGhlIHJvb3QncyB0cmVlLCBpdCB3aWxsIGJlIHJlbW92ZWQgZmlyc3QgYW5kIHRoZW4gbW92ZWQgdG8gdGhlIHBhc3NlZCB0cmVlSW5kZXhcbiAqIEluc2VydGlvbiBhdCBpbmRleCAwIGlzIG5vdCBwb3NzaWJsZSBhbmQgd2lsbCByZXR1cm4gdW5kZWZpbmVkIGFzIGl0IHdvdWxkIG1lYW4gcmVwbGFjaW5nIHRoZSByb290IGVsZW1lbnQuXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSByb290RWwgZWxlbWVudCBpbnRvIHdoaWNoIHRvIGluc2VydFxuICogQHBhcmFtIHtOdW1iZXJ9IHRyZWVJbmRleCBpbmRleCBpbiBET00gdHJlZSBpbnNpZGUgcm9vdCBlbGVtZW50IChzZWUgdHJlZVBhdGhPZilcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgZWxlbWVudCB0byBiZSBpbnNlcnRlZFxuICogQHJldHVybiB7Qm9vbGVhbn0gdHJ1ZSBpZiB3YXMgc3VjY2Vzc2Z1bGx5IGluc2VydGVkXG4gKi9cbmZ1bmN0aW9uIGluc2VydEF0VHJlZVBhdGgocm9vdEVsLCB0cmVlUGF0aCwgZWwsIG5lYXJlc3QpIHtcbiAgICB2YXIgdG9Ob3JtYWxpemUgPSBlbC5ub2RlVHlwZSA9PSBOb2RlLlRFWFRfTk9ERTtcbiAgICBpZiAocm9vdEVsLmNvbnRhaW5zKGVsKSlcbiAgICAgICAgcmVtb3ZlRWxlbWVudChlbCk7IC8vIGNhbid0IHVzZSByZW1vdmVDaGlsZCBhcyByb290RWwgaGVyZSBpcyBub3QgYW4gaW1tZWRpYXRlIHBhcmVudFxuXG4gICAgaWYgKHRyZWVQYXRoLmxlbmd0aCA9PSAwKSByZXR1cm47XG5cbiAgICB2YXIgcGFyZW50ID0gZ2V0Tm9kZUF0VHJlZVBhdGgocm9vdEVsLCB0cmVlUGF0aC5zbGljZSgwLCAtMSksIG5lYXJlc3QpXG4gICAgICAgICwgY2hpbGRyZW4gPSBwYXJlbnQuY2hpbGROb2RlcztcblxuICAgIGlmICghIGNoaWxkcmVuKSB7XG4gICAgICAgIGlmIChuZWFyZXN0KSB7XG4gICAgICAgICAgICBwYXJlbnQgPSBwYXJlbnQucGFyZW50Tm9kZTtcbiAgICAgICAgICAgIGNoaWxkcmVuID0gcGFyZW50LmNoaWxkTm9kZXM7XG4gICAgICAgIH0gZWxzZSByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGNoaWxkSW5kZXggPSB0cmVlUGF0aFt0cmVlUGF0aC5sZW5ndGggLSAxXVxuICAgICAgICAsIGNoaWxkID0gY2hpbGRyZW5bY2hpbGRJbmRleF07XG5cbiAgICBpZiAoY2hpbGQpIHtcbiAgICAgICAgcGFyZW50Lmluc2VydEJlZm9yZShlbCwgY2hpbGQpO1xuICAgICAgICBpZiAodG9Ob3JtYWxpemUpIHBhcmVudC5ub3JtYWxpemUoKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIGlmIChjaGlsZHJlbi5sZW5ndGggPT09IDAgJiYgKGNoaWxkSW5kZXggPT09IDAgfHwgbmVhcmVzdCkpIHtcbiAgICAgICAgcGFyZW50LmFwcGVuZENoaWxkKGVsKTtcbiAgICAgICAgaWYgKHRvTm9ybWFsaXplKSBwYXJlbnQubm9ybWFsaXplKCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGNoaWxkID0gY2hpbGRyZW5bY2hpbGRJbmRleCAtIDFdO1xuICAgICAgICBpZiAoY2hpbGQgfHwgbmVhcmVzdCkge1xuICAgICAgICAgICAgcGFyZW50LmFwcGVuZENoaWxkKGVsKTtcbiAgICAgICAgICAgIGlmICh0b05vcm1hbGl6ZSkgcGFyZW50Lm5vcm1hbGl6ZSgpO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgZmlyc3QgdHJlZSBwYXRoIHBvaW50cyB0byBhIG5vZGUgd2hpY2ggaXMgYmVmb3JlIHRoZSBvdGhlciBpbiB0aGUgZG9jdW1lbnQgb3JkZXIuXG4gKiBAcGFyYW0gIHtBcnJheX0gIHBhdGgxICAgQSB0cmVlcGF0aCBhcnJheVxuICogQHBhcmFtICB7QXJyYXl9ICBwYXRoMiAgIEEgdHJlZXBhdGggYXJyYXlcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIGlzVHJlZVBhdGhCZWZvcmUocGF0aDEsIHBhdGgyKSB7XG4gICAgdmFyIGkgPSAwXG4gICAgICAgICwgaXNCZWZvcmU7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHBhdGgxKSAmJiBBcnJheS5pc0FycmF5KHBhdGgyKSlcbiAgICAgICAgcmV0dXJuIGxvZ2dlci5lcnJvcignaXNUcmVlUGF0aEJlZm9yZTogT25lIG9yIGJvdGggcGF0aHMgYXJlIG5vdCB2YWxpZCB0cmVlcGF0aCBhcnJheXMuJyk7XG5cbiAgICBmb3IgKGk7IGkgPCBwYXRoMS5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAocGF0aDFbaV0gPCBwYXRoMltpXSkge1xuICAgICAgICAgICAgaXNCZWZvcmUgPSB0cnVlO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gZWxzZSBpZiAocGF0aDFbaV0gPiBwYXRoMltpXSkge1xuICAgICAgICAgICAgaXNCZWZvcmUgPSBmYWxzZTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBpc0JlZm9yZSA9PSAndW5kZWZpbmVkJylcbiAgICAgICAgaWYgKHBhdGgxLmxlbmd0aCA8IHBhdGgyLmxlbmd0aClcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKCdpc1RyZWVQYXRoQmVmb3JlOiBPbmUgbm9kZSBpcyBpbnNpZGUgYW5vdGhlcicpO1xuXG4gICAgcmV0dXJuIGlzQmVmb3JlIHx8IGZhbHNlO1xufVxuXG5cbi8qKlxuICogQ29udmVydHMgbm9uIGxhdGluIGNoYXJhY3RlcnMgdG8gSFRNTCBlbnRpdHkgY29kZXMuXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHN0ciB0aGUgc3RyaW5nIHRvIGNvbnZlcnRcbiAqIEByZXR1cm4ge1N0cmluZ30gICAgIHRoZSBzdHJpbmcgd2l0aCBodG1sIGVudGl0aWVzXG4gKi9cbmZ1bmN0aW9uIGh0bWxFbnRpdGllcyhzdHIpIHtcbiAgICByZXR1cm4gc3RyLnJlcGxhY2UoL1tcXHUwMEEwLVxcdTk5OTk5PD5cXCZdL2dpbSwgZnVuY3Rpb24oaSkge1xuICAgICAgICByZXR1cm4gJyYjJytpLmNoYXJDb2RlQXQoMCkrJzsnO1xuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIGNyZWF0ZVRyZWVXYWxrZXIoZWwsIHdoYXRUb1Nob3cpIHtcbiAgICB3aGF0VG9TaG93ID0gd2hhdFRvU2hvdyB8fCAoTm9kZUZpbHRlci5TSE9XX1RFWFQgfCBOb2RlRmlsdGVyLlNIT1dfRUxFTUVOVCk7XG4gICAgcmV0dXJuIGRvY3VtZW50LmNyZWF0ZVRyZWVXYWxrZXIoZWwsIHdoYXRUb1Nob3cpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgcmVmZXJlbmNlIHRvIHRoZSB3aW5kb3cgdGhlIG5vZGUgaXMgaW5cbiAqXG4gKiBAcGFyYW0ge05vZGV9IG5vZGVcbiAqIEByZXR1cm4ge1dpbmRvd31cbiAqL1xuZnVuY3Rpb24gZ2V0Tm9kZVdpbmRvdyhub2RlKSB7XG4gICAgdmFyIGRvYyA9IG5vZGUub3duZXJEb2N1bWVudDtcbiAgICByZXR1cm4gZG9jICYmIChkb2MuZGVmYXVsdFZpZXcgfHwgZG9jLnBhcmVudFdpbmRvdyk7XG59XG5cblxuXG4vKipcbiAqIGRvIHNvbWV0aGluZyBmb3IgZWFjaCBub2RlcyBjb250YWluZWQgaW4gYSByYW5nZVxuICpcbiAqIEBwYXJhbSB7cmFuZ2V9IGEgcmFuZ2VcbiAqIEBwYXJhbSB7Y2J9IGEgZnVuY3Rpb24gdGFraW5nIGEgbm9kZSBhcyBhcmd1bWVudFxuXG4gKi9cbmZ1bmN0aW9uIGZvckVhY2hOb2Rlc0luUmFuZ2UocmFuZ2UsIGNiKXtcbiAgICB2YXIgcmFuZ2VDb250YWluZXIgPSByYW5nZS5jb21tb25BbmNlc3RvckNvbnRhaW5lclxuICAgICAgICAsIGRvYyA9IHJhbmdlQ29udGFpbmVyLm93bmVyRG9jdW1lbnQ7XG5cbiAgICBmdW5jdGlvbiBpc05vZGVJbnNpZGVSYW5nZShub2RlKXtcbiAgICAgICAgdmFyIG5vZGVSYW5nZSA9IGRvY3VtZW50LmNyZWF0ZVJhbmdlKCk7XG4gICAgICAgIHZhciBpc0luc2lkZSA9IGZhbHNlO1xuICAgICAgICBub2RlUmFuZ2Uuc2VsZWN0Tm9kZShub2RlKTtcblxuICAgICAgICBpZiAobm9kZVJhbmdlLmNvbXBhcmVCb3VuZGFyeVBvaW50cyh3aW5kb3cuUmFuZ2UuU1RBUlRfVE9fU1RBUlQsIHJhbmdlKSAhPSAtMVxuICAgICAgICAgICAgJiYgbm9kZVJhbmdlLmNvbXBhcmVCb3VuZGFyeVBvaW50cyh3aW5kb3cuUmFuZ2UuRU5EX1RPX0VORCwgcmFuZ2UpICE9IDEpe1xuICAgICAgICAgICAgaXNJbnNpZGUgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIG5vZGVSYW5nZS5kZXRhY2goKTtcbiAgICAgICAgcmV0dXJuIGlzSW5zaWRlO1xuICAgIH1cblxuICAgIHZhciB0cmVlV2Fsa2VyID0gZG9jLmNyZWF0ZVRyZWVXYWxrZXIocmFuZ2VDb250YWluZXIsXG4gICAgICAgICAgICBOb2RlRmlsdGVyLlNIT1dfRUxFTUVOVCB8IE5vZGVGaWx0ZXIuU0hPV19URVhUKTtcblxuICAgIHZhciBjdXJyZW50Tm9kZTtcbiAgICB3aGlsZSAoY3VycmVudE5vZGUgPSB0cmVlV2Fsa2VyLm5leHROb2RlKCkpeyAvLyBzaG91bGQgYmUgYXNzaWdubWVudFxuICAgICAgICBpZiAoaXNOb2RlSW5zaWRlUmFuZ2UoY3VycmVudE5vZGUpKXtcbiAgICAgICAgICAgIGNiKGN1cnJlbnROb2RlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuLyoqXG4gKiBnZXQgYWxsIGNvbXBvbmVudHMgY29udGFpbmVkIGluIGEgcmFuZ2VcbiAqXG4gKiBAcGFyYW0ge3JhbmdlfSBhIERPTSByYW5nZS5cbiAqL1xuZnVuY3Rpb24gZ2V0Q29tcG9uZW50c0Zyb21SYW5nZShyYW5nZSkge1xuICAgIHZhciB3aW4gPSBnZXROb2RlV2luZG93KHJhbmdlLnN0YXJ0Q29udGFpbmVyKVxuICAgICAgICAsIENvbXBvbmVudCA9IHdpbi5taWxvLkNvbXBvbmVudDtcblxuICAgIHZhciBjb21wb25lbnRzID0gW107XG4gICAgZm9yRWFjaE5vZGVzSW5SYW5nZShyYW5nZSwgZnVuY3Rpb24gKG5vZGUpe1xuICAgICAgICBpZiAobm9kZS5ub2RlVHlwZSAhPSBOb2RlLlRFWFRfTk9ERSkge1xuICAgICAgICAgICAgdmFyIGNvbXAgPSBDb21wb25lbnQuZ2V0Q29tcG9uZW50KG5vZGUpO1xuICAgICAgICAgICAgaWYgKGNvbXApXG4gICAgICAgICAgICAgICAgY29tcG9uZW50cy5wdXNoKGNvbXApO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gY29tcG9uZW50cztcbn1cblxuLyoqXG4gKiBkZWxldGUgYSByYW5nZVxuICpcbiAqIEBwYXJhbSB7cmFuZ2V9IGRlbGV0ZSBhIERPTSByYW5nZSBhbmQgYWxsIHRoZSBjb21wb25lbnRzIGluc2lkZVxuICovXG5mdW5jdGlvbiBkZWxldGVSYW5nZVdpdGhDb21wb25lbnRzKHJhbmdlKSB7XG4gICAgdmFyIGNvbXBvbmVudHMgPSBnZXRDb21wb25lbnRzRnJvbVJhbmdlKHJhbmdlKTtcblxuICAgIGNvbXBvbmVudHMuZm9yRWFjaChmdW5jdGlvbihjb21wKSB7XG4gICAgICAgIGNvbXAuZGVzdHJveSh0cnVlKTtcbiAgICB9KTtcblxuICAgIHJhbmdlLmRlbGV0ZUNvbnRlbnRzKCk7XG59XG5cbi8qKlxuICogY2hlY2sgaWYgdHdvIHJhbmdlcyBhcmUgZXF1aXZhbGVudFxuICpcbiAqIEBwYXJhbSB7cmFuZ2V9IHJhbmdlMVxuICogQHBhcmFtIHtyYW5nZX0gcmFuZ2UyXG4gKiBAcmV0dXJuIHtCb29sZWFufSBhcmUgdGhlIHR3byByYW5nZXMgZXF1aXZhbGVudFxuICovXG5mdW5jdGlvbiBhcmVSYW5nZXNFcXVhbChyYW5nZTEsIHJhbmdlMil7XG4gICAgcmV0dXJuIHJhbmdlMS5jb21wYXJlQm91bmRhcnlQb2ludHMod2luZG93LlJhbmdlLlNUQVJUX1RPX1NUQVJULCByYW5nZTIpID09IDAgJiYgcmFuZ2UxLmNvbXBhcmVCb3VuZGFyeVBvaW50cyh3aW5kb3cuUmFuZ2UuRU5EX1RPX0VORCwgcmFuZ2UyKSA9PSAwO1xufVxuXG5cbi8qKlxuICogQWRkcyBhIHNpbmdsZSBwaXhlbCBkaXYgdG8gdGhlIGJvZHkgYXQgYSBnaXZlbiB4IGFuZCB5IHBvc2l0aW9uLiBVc2VmdWwgZm9yIGRlYnVnZ2luZyBwb3NpdGlvbiBzcGVjaWZpYyBjb2RlLlxuICogQHBhcmFtIHtOdW1iZXJ9IHhcbiAqIEBwYXJhbSB7TnVtYmVyfSB5XG4gKi9cbmZ1bmN0aW9uIGFkZERlYnVnUG9pbnQoeCwgeSkge1xuICAgIHZhciBkYkVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgZGJFbC5zZXRBdHRyaWJ1dGUoJ3N0eWxlJywgJ3dpZHRoOiAxcHg7IGhlaWdodDogMXB4OyBwb3NpdGlvbjpmaXhlZDsgbGVmdDonK3grJ3B4OyB0b3A6Jyt5KydweDsgYmFja2dyb3VuZC1jb2xvcjpyZWQ7IHotaW5kZXg6IDEwMCcpO1xuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChkYkVsKTt9LCAyMDApO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi9jaGVjaycpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gRE9NTGlzdGVuZXJzO1xuXG5cbmZ1bmN0aW9uIERPTUxpc3RlbmVycygpIHtcbiAgICB0aGlzLmxpc3RlbmVycyA9IFtdO1xufVxuXG5cbl8uZXh0ZW5kUHJvdG8oRE9NTGlzdGVuZXJzLCB7XG4gICAgYWRkOiBET01MaXN0ZW5lcnMkYWRkLFxuICAgIHJlbW92ZTogRE9NTGlzdGVuZXJzJHJlbW92ZSxcbiAgICByZW1vdmVBbGw6IERPTUxpc3RlbmVycyRyZW1vdmVBbGxcbn0pO1xuXG5cbmZ1bmN0aW9uIERPTUxpc3RlbmVycyRhZGQodGFyZ2V0LCBldmVudFR5cGUsIGhhbmRsZXIpIHtcbiAgICB0aGlzLmxpc3RlbmVycy5wdXNoKHtcbiAgICAgICAgdGFyZ2V0OiB0YXJnZXQsXG4gICAgICAgIGV2ZW50VHlwZTogZXZlbnRUeXBlLFxuICAgICAgICBoYW5kbGVyOiBoYW5kbGVyXG4gICAgfSk7XG4gICAgdGFyZ2V0LmFkZEV2ZW50TGlzdGVuZXIoZXZlbnRUeXBlLCBoYW5kbGVyKTtcbn1cblxuXG5mdW5jdGlvbiBET01MaXN0ZW5lcnMkcmVtb3ZlKHRhcmdldCwgZXZlbnRUeXBlLCBoYW5kbGVyKSB7XG4gICAgdmFyIGxpc3RlbmVyID0ge1xuICAgICAgICB0YXJnZXQ6IHRhcmdldCxcbiAgICAgICAgZXZlbnRUeXBlOiBldmVudFR5cGUsXG4gICAgICAgIGhhbmRsZXI6IGhhbmRsZXJcbiAgICB9O1xuICAgIHZhciBpZHggPSBfLmZpbmRJbmRleCh0aGlzLmxpc3RlbmVycywgXy5wYXJ0aWFsKF8uaXNFcXVhbCwgbGlzdGVuZXIpKTtcblxuICAgIGlmIChpZHggPiAtMSkge1xuICAgICAgICB0aGlzLmxpc3RlbmVycy5zcGxpY2UoaWR4LCAxKTtcbiAgICAgICAgX3JlbW92ZUxpc3RlbmVyKGxpc3RlbmVyKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gRE9NTGlzdGVuZXJzJHJlbW92ZUFsbCgpIHtcbiAgICB0aGlzLmxpc3RlbmVycy5mb3JFYWNoKF9yZW1vdmVMaXN0ZW5lcik7XG4gICAgdGhpcy5saXN0ZW5lcnMgPSBbXTtcbn1cblxuXG5mdW5jdGlvbiBfcmVtb3ZlTGlzdGVuZXIobCkge1xuICAgIGwudGFyZ2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIobC5ldmVudFR5cGUsIGwuaGFuZGxlcik7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGRvbVJlYWR5O1xuXG5cbnZhciBkb21SZWFkeUZ1bmNzID0gW11cbiAgICAsIGRvbVJlYWR5U3Vic2NyaWJlZCA9IGZhbHNlO1xuXG5cbmZ1bmN0aW9uIGRvbVJlYWR5KGZ1bmMpIHsgLy8gLCBhcmd1bWVudHNcbiAgICB2YXIgc2VsZiA9IHRoaXNcbiAgICAgICAgLCBhcmdzID0gXy5zbGljZShhcmd1bWVudHMsIDEpO1xuICAgIGlmIChpc1JlYWR5LmNhbGwodGhpcykpXG4gICAgICAgIGNhbGxGdW5jKCk7XG4gICAgZWxzZSB7XG4gICAgICAgIGlmICghZG9tUmVhZHlTdWJzY3JpYmVkKSB7XG4gICAgICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdyZWFkeXN0YXRlY2hhbmdlJywgb25Eb21SZWFkeSk7XG4gICAgICAgICAgICBkb21SZWFkeVN1YnNjcmliZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGRvbVJlYWR5RnVuY3MucHVzaChjYWxsRnVuYyk7IC8vIGNsb3N1cmUgaXMgYWRkZWQsIHNvIGV2ZXJ5IHRpbWUgZGlmZmVyZW50IGZ1bmN0aW9uIHdpbGwgYmUgY2FsbGVkXG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY2FsbEZ1bmMoKSB7XG4gICAgICAgIGZ1bmMuYXBwbHkoc2VsZiwgYXJncyk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIG9uRG9tUmVhZHkoKSB7XG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigncmVhZHlzdGF0ZWNoYW5nZScsIG9uRG9tUmVhZHkpO1xuICAgIGRvbVJlYWR5RnVuY3MuZm9yRWFjaChmdW5jdGlvbihmdW5jKSB7IGZ1bmMoKTsgfSk7XG59XG5cblxuXy5leHRlbmQoZG9tUmVhZHksIHtcbiAgICBpc1JlYWR5OiBpc1JlYWR5XG59KTtcblxuXG5mdW5jdGlvbiBpc1JlYWR5KCkge1xuICAgIHZhciByZWFkeVN0YXRlID0gZG9jdW1lbnQucmVhZHlTdGF0ZTtcbiAgICByZXR1cm4gcmVhZHlTdGF0ZSA9PSAnbG9hZGluZycgPyBmYWxzZSA6IHJlYWR5U3RhdGU7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jb21wb25lbnRzL2NfY2xhc3MnKVxuICAgICwgTWVzc2VuZ2VyID0gcmVxdWlyZSgnLi4vbWVzc2VuZ2VyJylcbiAgICAsIGRyYWdEcm9wQ29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJykuZHJhZ0Ryb3BcbiAgICAsIGNvbXBvbmVudE1ldGFSZWdleCA9IGRyYWdEcm9wQ29uZmlnLmRhdGFUeXBlcy5jb21wb25lbnRNZXRhUmVnZXhcbiAgICAsIGpzb25QYXJzZSA9IHJlcXVpcmUoJy4vanNvbl9wYXJzZScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGJhc2UzMiA9IHJlcXVpcmUoJ2Jhc2UzMicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gRHJhZ0Ryb3A7XG5cblxuLyoqXG4gKiBXcmFwcGVyIGZvciBldmVudC5kYXRhVHJhbnNmZXIgb2YgZHJhZy1kcm9wIEhUTUwgQVBJXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAcGFyYW0ge2V2ZW50fSBET00gZXZlbnRcbiAqIEByZXR1cm4ge0RyYWdEcm9wfVxuICovXG5mdW5jdGlvbiBEcmFnRHJvcChldmVudCkge1xuICAgIHRoaXMuZXZlbnQgPSBldmVudDtcbiAgICB0aGlzLmRhdGFUcmFuc2ZlciA9IGV2ZW50LmRhdGFUcmFuc2ZlcjtcbiAgICB0aGlzLnR5cGVzID0gZXZlbnQuZGF0YVRyYW5zZmVyLnR5cGVzO1xufVxuXG4vKipcbiAqIFVzYWdlOlxuICogdmFyIHRlc3REVCA9IG5ldyBEcmFnRHJvcChldmVudCk7XG4gKiB0ZXN0RFQuc2V0Q29tcG9uZW50TWV0YShuZXdDb21wb25lbnQsIHt0ZXN0OiAndGVzdCcsIHRlc3QyOiAndGVzdDInfSk7XG4gKiB0ZXN0RFQuZ2V0Q29tcG9uZW50TWV0YSgpO1xuICovXG5cbl8uZXh0ZW5kKERyYWdEcm9wLCB7XG4gICAgY29tcG9uZW50RGF0YVR5cGU6IERyYWdEcm9wJCRjb21wb25lbnREYXRhVHlwZVxufSk7XG5cbl8uZXh0ZW5kUHJvdG8oRHJhZ0Ryb3AsIHtcbiAgICBpc0NvbXBvbmVudDogRHJhZ0Ryb3AkaXNDb21wb25lbnQsXG4gICAgZ2V0Q29tcG9uZW50U3RhdGU6IERyYWdEcm9wJGdldENvbXBvbmVudFN0YXRlLFxuICAgIHNldENvbXBvbmVudFN0YXRlOiBEcmFnRHJvcCRzZXRDb21wb25lbnRTdGF0ZSxcbiAgICBnZXRDb21wb25lbnRNZXRhOiBEcmFnRHJvcCRnZXRDb21wb25lbnRNZXRhLFxuICAgIHNldENvbXBvbmVudE1ldGE6IERyYWdEcm9wJHNldENvbXBvbmVudE1ldGEsXG4gICAgZ2V0QWxsb3dlZEVmZmVjdHM6IERyYWdEcm9wJGdldEFsbG93ZWRFZmZlY3RzLFxuICAgIHNldEFsbG93ZWRFZmZlY3RzOiBEcmFnRHJvcCRzZXRBbGxvd2VkRWZmZWN0cyxcbiAgICBnZXREcm9wRWZmZWN0OiBEcmFnRHJvcCRnZXREcm9wRWZmZWN0LFxuICAgIHNldERyb3BFZmZlY3Q6IERyYWdEcm9wJHNldERyb3BFZmZlY3QsXG4gICAgaXNFZmZlY3RBbGxvd2VkOiBEcmFnRHJvcCRpc0VmZmVjdEFsbG93ZWQsXG4gICAgZ2V0RGF0YTogRHJhZ0Ryb3AkZ2V0RGF0YSxcbiAgICBzZXREYXRhOiBEcmFnRHJvcCRzZXREYXRhLFxuICAgIGNsZWFyRGF0YTogRHJhZ0Ryb3AkY2xlYXJEYXRhXG59KTtcblxuXG5mdW5jdGlvbiBEcmFnRHJvcCQkY29tcG9uZW50RGF0YVR5cGUoKSB7XG4gICAgcmV0dXJuIGRyYWdEcm9wQ29uZmlnLmRhdGFUeXBlcy5jb21wb25lbnQ7XG59XG5cblxuZnVuY3Rpb24gRHJhZ0Ryb3AkaXNDb21wb25lbnQoKSB7XG4gICAgcmV0dXJuIF8uaW5kZXhPZih0aGlzLnR5cGVzLCBEcmFnRHJvcC5jb21wb25lbnREYXRhVHlwZSgpKSA+PSAwO1xufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJGdldENvbXBvbmVudFN0YXRlKCkge1xuICAgIHZhciBkYXRhVHlwZSA9IERyYWdEcm9wLmNvbXBvbmVudERhdGFUeXBlKClcbiAgICAgICAgLCBzdGF0ZVN0ciA9IHRoaXMuZGF0YVRyYW5zZmVyLmdldERhdGEoZGF0YVR5cGUpXG4gICAgICAgICwgc3RhdGUgPSBqc29uUGFyc2Uoc3RhdGVTdHIpO1xuXG4gICAgcmV0dXJuIHN0YXRlO1xufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJHNldENvbXBvbmVudFN0YXRlKGNvbXBvbmVudCwgc3RhdGVTdHIpe1xuICAgIGlmICghIHN0YXRlU3RyKSB7XG4gICAgICAgIHZhciBzdGF0ZSA9IGNvbXBvbmVudC5nZXRUcmFuc2ZlclN0YXRlKHsgcmVxdWVzdGVkQnk6ICdkcmFnJyB9KTtcbiAgICAgICAgc3RhdGVTdHIgPSBKU09OLnN0cmluZ2lmeShzdGF0ZSk7XG4gICAgfVxuICAgIHZhciBkYXRhVHlwZSA9IERyYWdEcm9wLmNvbXBvbmVudERhdGFUeXBlKCk7XG5cbiAgICBzdGF0ZVN0ciAmJiB0aGlzLmRhdGFUcmFuc2Zlci5zZXREYXRhKGRhdGFUeXBlLCBzdGF0ZVN0cik7XG4gICAgdGhpcy5kYXRhVHJhbnNmZXIuc2V0RGF0YSgndGV4dC9odG1sJywgY29tcG9uZW50LmVsLm91dGVySFRNTCk7XG4gICAgcmV0dXJuIHN0YXRlU3RyO1xufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJHNldENvbXBvbmVudE1ldGEoY29tcG9uZW50LCBwYXJhbXMsIGRhdGEpIHtcbiAgICB2YXIgbWV0YSA9IF9jb21wb25lbnRNZXRhKGNvbXBvbmVudCk7XG5cbiAgICB2YXIgcGFyYW1zU3RyID0gXy50b1F1ZXJ5U3RyaW5nKHBhcmFtcyk7XG4gICAgdmFyIGRhdGFUeXBlID0gZHJhZ0Ryb3BDb25maWcuZGF0YVR5cGVzLmNvbXBvbmVudE1ldGFUZW1wbGF0ZVxuICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgnJWNsYXNzJywgX2VuY29kZShtZXRhLmNvbXBDbGFzcyB8fCAnJykpXG4gICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKCclbmFtZScsIF9lbmNvZGUobWV0YS5jb21wTmFtZSB8fCAnJykpXG4gICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKCclcGFyYW1zJywgX2VuY29kZShwYXJhbXNTdHIgfHwgJycpKTtcblxuICAgIGlmIChkYXRhICYmIHR5cGVvZiBkYXRhID09ICdvYmplY3QnKSBkYXRhID0gSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG5cbiAgICB0aGlzLmRhdGFUcmFuc2Zlci5zZXREYXRhKGRhdGFUeXBlLCBkYXRhIHx8ICcnKTtcblxuICAgIHJldHVybiBkYXRhVHlwZTtcbn1cblxuXG5mdW5jdGlvbiBfZW5jb2RlKHN0cikge1xuICAgIHJldHVybiBiYXNlMzIuZW5jb2RlKHN0cikudG9Mb3dlckNhc2UoKTtcbn1cblxuXG5mdW5jdGlvbiBfY29tcG9uZW50TWV0YShjb21wb25lbnQpIHtcbiAgICByZXR1cm4gY29tcG9uZW50LnRyYW5zZmVyXG4gICAgICAgICAgICA/IGNvbXBvbmVudC50cmFuc2Zlci5nZXRDb21wb25lbnRNZXRhKClcbiAgICAgICAgICAgIDogeyBcbiAgICAgICAgICAgICAgICBjb21wQ2xhc3M6IGNvbXBvbmVudC5jb25zdHJ1Y3Rvci5uYW1lLFxuICAgICAgICAgICAgICAgIGNvbXBOYW1lOiBjb21wb25lbnQubmFtZVxuICAgICAgICAgICAgfTtcbn1cblxuXG5mdW5jdGlvbiBEcmFnRHJvcCRnZXRDb21wb25lbnRNZXRhKCkge1xuICAgIHZhciBtYXRjaDtcbiAgICB2YXIgbWV0YURhdGFUeXBlID0gXy5maW5kKHRoaXMudHlwZXMsIGZ1bmN0aW9uIChkVHlwZSkge1xuICAgICAgICBtYXRjaCA9IGRUeXBlLm1hdGNoKGNvbXBvbmVudE1ldGFSZWdleCk7XG4gICAgICAgIHJldHVybiAhIW1hdGNoO1xuICAgIH0pO1xuICAgIGlmICghbWV0YURhdGFUeXBlKSByZXR1cm47XG5cbiAgICBmb3IgKHZhciBpPTE7IGk8NDsgaSsrKVxuICAgICAgICBtYXRjaFtpXSA9IGJhc2UzMi5kZWNvZGUobWF0Y2hbaV0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgY29tcENsYXNzOiBtYXRjaFsxXSxcbiAgICAgICAgY29tcE5hbWU6IG1hdGNoWzJdLFxuICAgICAgICBwYXJhbXM6IF8uZnJvbVF1ZXJ5U3RyaW5nKG1hdGNoWzNdKSxcbiAgICAgICAgbWV0YURhdGFUeXBlOiBtZXRhRGF0YVR5cGUsXG4gICAgICAgIG1ldGFEYXRhOiBfLmpzb25QYXJzZSh0aGlzLmRhdGFUcmFuc2Zlci5nZXREYXRhKG1ldGFEYXRhVHlwZSkpIFxuICAgICAgICAgICAgICAgICAgICA/IF8uanNvblBhcnNlKHRoaXMuZGF0YVRyYW5zZmVyLmdldERhdGEobWV0YURhdGFUeXBlKSkgXG4gICAgICAgICAgICAgICAgICAgIDogdGhpcy5kYXRhVHJhbnNmZXIuZ2V0RGF0YShtZXRhRGF0YVR5cGUpXG4gICAgfTtcbn1cblxuXG4vLyBhcyBkZWZpbmVkIGhlcmU6IGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvRHJhZ0Ryb3AvRHJhZ19PcGVyYXRpb25zI2RyYWdzdGFydFxuZnVuY3Rpb24gRHJhZ0Ryb3AkZ2V0QWxsb3dlZEVmZmVjdHMoKSB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YVRyYW5zZmVyLmVmZmVjdEFsbG93ZWQ7XG59XG5cblxuZnVuY3Rpb24gRHJhZ0Ryb3Akc2V0QWxsb3dlZEVmZmVjdHMoZWZmZWN0cykge1xuICAgIHRoaXMuZGF0YVRyYW5zZmVyLmVmZmVjdEFsbG93ZWQgPSBlZmZlY3RzO1xufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJGdldERyb3BFZmZlY3QoKSB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YVRyYW5zZmVyLmRyb3BFZmZlY3Q7XG59XG5cblxuZnVuY3Rpb24gRHJhZ0Ryb3Akc2V0RHJvcEVmZmVjdChlZmZlY3QpIHtcbiAgICB0aGlzLmRhdGFUcmFuc2Zlci5kcm9wRWZmZWN0ID0gZWZmZWN0O1xufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJGlzRWZmZWN0QWxsb3dlZChlZmZlY3QpIHtcbiAgICB2YXIgYWxsb3dlZEVmZmVjdHMgPSB0aGlzLmdldEFsbG93ZWRFZmZlY3RzKClcbiAgICAgICAgLCBpc0NvcHkgPSBlZmZlY3QgPT0gJ2NvcHknXG4gICAgICAgICwgaXNNb3ZlID0gZWZmZWN0ID09ICdtb3ZlJ1xuICAgICAgICAsIGlzTGluayA9IGVmZmVjdCA9PSAnbGluaydcbiAgICAgICAgLCBpc0FsbG93ZWQgPSBpc0NvcHkgfHwgaXNMaW5rIHx8IGlzTW92ZTtcblxuICAgIHN3aXRjaCAoYWxsb3dlZEVmZmVjdHMpIHtcbiAgICAgICAgY2FzZSAnY29weSc6XG4gICAgICAgIGNhc2UgJ21vdmUnOlxuICAgICAgICBjYXNlICdsaW5rJzpcbiAgICAgICAgICAgIHJldHVybiBhbGxvd2VkRWZmZWN0cyA9PSBlZmZlY3Q7XG4gICAgICAgIGNhc2UgJ2NvcHlMaW5rJzpcbiAgICAgICAgICAgIHJldHVybiBpc0NvcHkgfHwgaXNMaW5rO1xuICAgICAgICBjYXNlICdjb3B5TW92ZSc6XG4gICAgICAgICAgICByZXR1cm4gaXNDb3B5IHx8IGlzTW92ZTtcbiAgICAgICAgY2FzZSAnbGlua01vdmUnOlxuICAgICAgICAgICAgcmV0dXJuIGlzTGluayB8fCBpc01vdmU7XG4gICAgICAgIGNhc2UgJ2FsbCc6XG4gICAgICAgIGNhc2UgJ3VuaW5pdGlhbGl6ZWQnOlxuICAgICAgICAgICAgcmV0dXJuIGlzQWxsb3dlZDtcbiAgICAgICAgY2FzZSAnbm9uZSc6XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJGdldERhdGEoZGF0YVR5cGUpIHtcbiAgICByZXR1cm4gdGhpcy5kYXRhVHJhbnNmZXIuZ2V0RGF0YShkYXRhVHlwZSk7XG59XG5cblxuZnVuY3Rpb24gRHJhZ0Ryb3Akc2V0RGF0YShkYXRhVHlwZSwgZGF0YVN0cikge1xuICAgIHRoaXMuZGF0YVRyYW5zZmVyLnNldERhdGEoZGF0YVR5cGUsIGRhdGFTdHIpO1xufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJGNsZWFyRGF0YShkYXRhVHlwZSkge1xuICAgIHRoaXMuZGF0YVRyYW5zZmVyLmNsZWFyRGF0YShkYXRhVHlwZSk7XG59XG5cblxuLyoqXG4gKiBEcmFnIGRyb3Agc2VydmljZSBjb21wZW5zYXRpbmcgZm9yIHRoZSBsYWNrIG9mIGNvbW11bmljYXRpb24gZnJvbSBkcm9wIHRhcmdldCB0byBkcmFnIHNvdXJjZSBpbiBET00gQVBJXG4gKi9cbnZhciBkcmFnRHJvcFNlcnZpY2UgPSBuZXcgTWVzc2VuZ2VyO1xuXG52YXIgX2N1cnJlbnREcmFnRHJvcCwgX2N1cnJlbnREcmFnRmFjZXQ7XG5cbl8uZXh0ZW5kKERyYWdEcm9wLCB7XG4gICAgc2VydmljZTogZHJhZ0Ryb3BTZXJ2aWNlLFxuICAgIGRlc3Ryb3k6IERyYWdEcm9wX2Rlc3Ryb3lcbn0pO1xuXG5cbmRyYWdEcm9wU2VydmljZS5vbk1lc3NhZ2VzKHtcbiAgICAvLyBkYXRhIGlzIERyYWdEcm9wRGF0YVRyYW5zZmVyIGluc3RhbmNlXG4gICAgLy8gZmlyZWQgYnkgRHJhZyBmYWNldCBvbiBcImRyYWdzdGFydFwiIGV2ZW50XG4gICAgJ2RyYWdkcm9wc3RhcnRlZCc6IG9uRHJhZ0Ryb3BTdGFydGVkLCBcbiAgICAvLyBkYXRhIGlzIG9iamVjdCB3aXRoIGF0IGxlYXN0IGRyb3BFZmZlY3QgcHJvcGVydHlcbiAgICAvLyBmaXJlZCBieSBEcm9wIGZhY2V0IG9uIFwiZHJvcFwiIGV2ZW50XG4gICAgJ2RyYWdkcm9wY29tcGxldGVkJzogb25EcmFnRHJvcENvbXBsZXRlZCwgXG4gICAgLy8gZmlyZWQgYnkgRHJhZyBmYWNldCBvbiBcImRyYWdlbmRcIiBldmVudCB0byBjb21wbGV0ZSBkcmFnXG4gICAgLy8gaWYgZHJvcCBoYXBwZW5kZWQgaW4gYW5vdGhlciB3aW5kb3cgb3IgaWYgaXQgd2FzIGNhbmNlbGxlZFxuICAgICdjb21wbGV0ZWRyYWdkcm9wJzogb25Db21wbGV0ZURyYWdEcm9wXG59KTtcblxuXG5fLmV4dGVuZChkcmFnRHJvcFNlcnZpY2UsIHtcbiAgICBnZXRDdXJyZW50RHJhZ0Ryb3A6IGdldEN1cnJlbnREcmFnRHJvcFxufSk7XG5cblxuZnVuY3Rpb24gb25EcmFnRHJvcFN0YXJ0ZWQobXNnLCBkYXRhKSB7XG4gICAgX2N1cnJlbnREcmFnRHJvcCA9IGRhdGEuZHJhZ0Ryb3A7XG4gICAgX2N1cnJlbnREcmFnRmFjZXQgPSBkYXRhLmRyYWdGYWNldDtcbn1cblxuXG5mdW5jdGlvbiBvbkRyYWdEcm9wQ29tcGxldGVkKG1zZywgZGF0YSkge1xuICAgIF9jdXJyZW50RHJhZ0ZhY2V0ICYmIF9jdXJyZW50RHJhZ0ZhY2V0LnBvc3RNZXNzYWdlU3luYygnZHJhZ2Ryb3Bjb21wbGV0ZWQnLCBkYXRhKTtcbiAgICBfY3VycmVudERyYWdEcm9wID0gdW5kZWZpbmVkO1xuICAgIF9jdXJyZW50RHJhZ0ZhY2V0ID0gdW5kZWZpbmVkO1xufVxuXG5cbmZ1bmN0aW9uIG9uQ29tcGxldGVEcmFnRHJvcChtc2csIGRhdGEpIHtcbiAgICBpZiAoX2N1cnJlbnREcmFnRHJvcClcbiAgICAgICAgZHJhZ0Ryb3BTZXJ2aWNlLnBvc3RNZXNzYWdlU3luYygnZHJhZ2Ryb3Bjb21wbGV0ZWQnLCBkYXRhKTtcbn1cblxuXG5mdW5jdGlvbiBnZXRDdXJyZW50RHJhZ0Ryb3AoKSB7XG4gICAgcmV0dXJuIF9jdXJyZW50RHJhZ0Ryb3A7XG59XG5cblxuZnVuY3Rpb24gRHJhZ0Ryb3BfZGVzdHJveSgpIHtcbiAgICBkcmFnRHJvcFNlcnZpY2Uub2ZmQWxsKCk7XG59XG4iLCIvLyA8YSBuYW1lPVwidXRpbHMtZXJyb3JcIj48L2E+XG4vLyBtaWxvLnV0aWxzLmVycm9yXG4vLyAtLS0tLS0tLS0tLVxuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cblxuLy8gbW9kdWxlIGV4cG9ydHMgZXJyb3IgY2xhc3NlcyBmb3IgYWxsIG5hbWVzIGRlZmluZWQgaW4gdGhpcyBhcnJheVxudmFyIGVycm9yQ2xhc3NOYW1lcyA9IFsnQWJzdHJhY3RDbGFzcycsICdNaXhpbicsICdNZXNzZW5nZXInLCAnQ29tcG9uZW50JyxcbiAgICAgICAgICAgICAgICAgICAgICAgJ0F0dHJpYnV0ZScsICdCaW5kZXInLCAnTG9hZGVyJywgJ01haWxNZXNzYWdlU291cmNlJywgJ0ZhY2V0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgJ1Njb3BlJywgJ01vZGVsJywgJ0RvbUZhY2V0JywgJ0VkaXRhYmxlRmFjZXQnLFxuICAgICAgICAgICAgICAgICAgICAgICAnTGlzdCcsICdDb25uZWN0b3InLCAnUmVnaXN0cnknLCAnRnJhbWVNZXNzYWdlU291cmNlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgJ0Ryb3AnLCAnQW5ndWxhcicsICdTdG9yYWdlTWVzc2FnZVNvdXJjZSddO1xuXG52YXIgZXJyb3IgPSB7XG4gICAgdG9CZUltcGxlbWVudGVkOiBlcnJvciR0b0JlSW1wbGVtZW50ZWQsXG4gICAgY3JlYXRlQ2xhc3M6IGVycm9yJGNyZWF0ZUNsYXNzXG59O1xuXG5lcnJvckNsYXNzTmFtZXMuZm9yRWFjaChmdW5jdGlvbihuYW1lKSB7XG4gICAgZXJyb3JbbmFtZV0gPSBlcnJvciRjcmVhdGVDbGFzcyhuYW1lICsgJ0Vycm9yJyk7XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBlcnJvcjtcblxuXG5mdW5jdGlvbiBlcnJvciRjcmVhdGVDbGFzcyhlcnJvckNsYXNzTmFtZSkge1xuICAgIHZhciBFcnJvckNsYXNzID0gXy5tYWtlRnVuY3Rpb24oZXJyb3JDbGFzc05hbWUsICdtZXNzYWdlJyxcbiAgICAgICAgICAgICd0aGlzLm5hbWUgPSBcIicgKyBlcnJvckNsYXNzTmFtZSArICdcIjsgXFxcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2UgfHwgXCJUaGVyZSB3YXMgYW4gIGVycm9yXCI7Jyk7XG4gICAgXy5tYWtlU3ViY2xhc3MoRXJyb3JDbGFzcywgRXJyb3IpO1xuXG4gICAgcmV0dXJuIEVycm9yQ2xhc3M7XG59XG5cblxuZnVuY3Rpb24gZXJyb3IkdG9CZUltcGxlbWVudGVkKCkge1xuICAgIHRocm93IG5ldyBlcnJvci5BYnN0cmFjdENsYXNzKCdjYWxsaW5nIHRoZSBtZXRob2Qgb2YgYW4gYWJzY3RyYWN0IGNsYXNzJyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NvbXBvbmVudHMvY19jbGFzcycpXG4gICAgLCBCaW5kQXR0cmlidXRlID0gcmVxdWlyZSgnLi4vYXR0cmlidXRlcy9hX2JpbmQnKVxuICAgICwgYmluZGVyID0gcmVxdWlyZSgnLi4vYmluZGVyJylcbiAgICAsIGRvbVV0aWxzID0gcmVxdWlyZSgnLi9kb20nKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi9sb2dnZXInKVxuICAgICwgY2hlY2sgPSByZXF1aXJlKCcuL2NoZWNrJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG52YXIgY3JlYXRlUmFuZ2VQYXRocyA9IF9jcmVhdGVOb2Rlc0FuZFBhdGhzRnVuYyhkb21VdGlscy50cmVlUGF0aE9mKTtcbnZhciBjcmVhdGVSYW5nZU5vZGVzID0gX2NyZWF0ZU5vZGVzQW5kUGF0aHNGdW5jKGRvbVV0aWxzLmdldE5vZGVBdFRyZWVQYXRoKTtcblxuXG52YXIgZnJhZ21lbnRVdGlscyA9IG1vZHVsZS5leHBvcnRzID0ge1xuICAgIGdldFN0YXRlOiBmcmFnbWVudF9nZXRTdGF0ZSxcbiAgICBnZXRTdGF0ZUFzeW5jOiBmcmFnbWVudF9nZXRTdGF0ZUFzeW5jLFxuXG4gICAgZXhwYW5kUmFuZ2VUb1NpYmxpbmdzOiBleHBhbmRSYW5nZVRvU2libGluZ3MsXG4gICAgZ2V0UmFuZ2VTaWJsaW5nczogZ2V0UmFuZ2VTaWJsaW5ncyxcbiAgICBjcmVhdGVSYW5nZUZyb21TaWJsaW5nczogY3JlYXRlUmFuZ2VGcm9tU2libGluZ3MsXG4gICAgY3JlYXRlUmFuZ2VGcm9tTm9kZXM6IGNyZWF0ZVJhbmdlRnJvbVNpYmxpbmdzLCAvLyBhbGlhc1xuICAgIGNyZWF0ZVJhbmdlUGF0aHM6IGNyZWF0ZVJhbmdlUGF0aHMsXG4gICAgY3JlYXRlUmFuZ2VOb2RlczogY3JlYXRlUmFuZ2VOb2Rlc1xufTtcblxuXG4vKipcbiAqIENyZWF0ZXMgYW4gb2JqZWN0IHdpdGggdGhlIHN0YXRlIG9mIHdyYXBwZWQgcmFuZ2Ugd2l0aCBjb21wb25lbnRzLCBpbmNsdWRpbmcgcGFydGlhbGx5IHNlbGVjdGVkLiBUaGUgcmFuZ2Ugd2lsbCBiZSBjbG9uZWQgYW5kIHdyYXBwZWQgaW4gY29tcG9uZW50IHdpdGggY29udGFpbmVyIGZhY2V0IGJlZm9yZSBnZXR0aW5nIGl0cyBzdGF0ZS5cbiAqIFRoaXMgZnVuY3Rpb24gd2lsbCBsb2cgZXJyb3IgYW5kIHJldHVybiB1bmRlZmluZWQgaWYgcmFuZ2UgaGFzIG5vIGNvbW1vbiBhbmNlc3RvciB0aGF0IGhhcyBjb21wb25lbnQgd2l0aCBjb250YWluZXIgZmFjZXRcbiAqIFxuICogQHBhcmFtIHtSYW5nZX0gcmFuZ2UgRE9NIFJhbmdlIGluc3RhbmNlXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHJlbmFtZUNoaWxkcmVuIG9wdGlvbmFsIHBhcmFtZXRlciwgYHRydWVgIHRvIHJlbmFtZSBmcmFnbWVudCBjaGlsZCBjb21wb25lbnRzXG4gKiBAcGFyYW0ge1N0cmluZ30gd3JhcHBlckNsYXNzTmFtZSBvcHRpb25hbCBwYXJhbWV0ZXIgdG8gd3JhcCBpbiBhIGN1c3RvbSBjb21wb25lbnQgY2xhc3NcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZnJhZ21lbnRfZ2V0U3RhdGUocmFuZ2UsIHJlbmFtZUNoaWxkcmVuLCB3cmFwcGVyQ2xhc3NOYW1lKSB7XG4gICAgdmFyIHJhbmdlQ29udGFpbmVyID0gX2dldFJhbmdlQ29udGFpbmVyKHJhbmdlKTtcbiAgICBpZiAoISByYW5nZUNvbnRhaW5lcikge1xuICAgICAgICBsb2dnZXIuZXJyb3IoJ2ZyYWdtZW50LmdldFN0YXRlOiByYW5nZSBoYXMgbm8gY29tbW9uIGNvbnRhaW5lcicpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGZyYWcgPSByYW5nZS5jbG9uZUNvbnRlbnRzKClcbiAgICAgICAgLCB3cmFwcGVyID0gX3dyYXBGcmFnbWVudEluQ29udGFpbmVyKGZyYWcsIHdyYXBwZXJDbGFzc05hbWUpO1xuXG4gICAgX3RyYW5zZmVyU3RhdGVzKHJhbmdlQ29udGFpbmVyLCB3cmFwcGVyKTtcbiAgICBpZiAocmVuYW1lQ2hpbGRyZW4pIF9yZW5hbWVDaGlsZHJlbih3cmFwcGVyKTtcbiAgICB2YXIgd3JhcHBlclN0YXRlID0gd3JhcHBlci5nZXRTdGF0ZSgpO1xuICAgIF8uZGVmZXJNZXRob2Qod3JhcHBlciwgJ2Rlc3Ryb3knKTtcbiAgICByZXR1cm4gd3JhcHBlclN0YXRlO1xufVxuXG5cbi8qKlxuICogQ3JlYXRlcyBhbiBvYmplY3Qgd2l0aCB0aGUgc3RhdGUgb2Ygd3JhcHBlZCByYW5nZSB3aXRoIGNvbXBvbmVudHMsIGluY2x1ZGluZyBwYXJ0aWFsbHkgc2VsZWN0ZWQuIFRoZSByYW5nZSB3aWxsIGJlIGNsb25lZCBhbmQgd3JhcHBlZCBpbiBjb21wb25lbnQgd2l0aCBjb250YWluZXIgZmFjZXQgYmVmb3JlIGdldHRpbmcgaXRzIHN0YXRlLlxuICogVGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiByZXN1bHQgYW5kIGFueSBlcnJvciB2aWEgY2FsbGJhY2suXG4gKiBcbiAqIEBwYXJhbSB7UmFuZ2V9IHJhbmdlIERPTSBSYW5nZSBpbnN0YW5jZVxuICogQHBhcmFtIHtCb29sZWFufSByZW5hbWVDaGlsZHJlbiBvcHRpb25hbCBwYXJhbWV0ZXIsIGB0cnVlYCB0byByZW5hbWUgZnJhZ21lbnQgY2hpbGQgY29tcG9uZW50c1xuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgYWx3YXlzIHRoZSBsYXN0IHBhcmFtZXRlciwgb3B0aW9uYWwgcGFyYW1ldGVycyBjYW4gYmUgZHJvcHBlZDsgcmVzdWx0IGlzIHBhc3NlZCB2aWEgY2FsbGJhY2sgd2l0aCBhbnkgZXJyb3IgYXMgZmlyc3QgcGFyYW1ldGVyXG4gKi9cbmZ1bmN0aW9uIGZyYWdtZW50X2dldFN0YXRlQXN5bmMocmFuZ2UsIHJlbmFtZUNoaWxkcmVuLCBjYWxsYmFjaykge1xuICAgIHRyeSB7XG4gICAgICAgIHZhciByYW5nZUNvbnRhaW5lciA9IF9nZXRSYW5nZUNvbnRhaW5lcihyYW5nZSk7XG4gICAgICAgIGlmICghIHJhbmdlQ29udGFpbmVyKSB7XG4gICAgICAgICAgICBjYWxsYmFjayhuZXcgRXJyb3IoJ2ZyYWdtZW50LmdldFN0YXRlOiByYW5nZSBoYXMgbm8gY29tbW9uIGNvbnRhaW5lcicpKTtcbiAgICAgICAgICAgIHJldHVybjsgLy8gZG8gTk9UIGNvbm5lY3QgcmV0dXJuIHRvIHByZXZpb3VzIGNhbGxiYWNrLCBnZXRTdGF0ZSBzaG91bGQgcmV0dXJuIHVuZGVmaW5lZFxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiByZW5hbWVDaGlsZHJlbiA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYWxsYmFjayA9IHJlbmFtZUNoaWxkcmVuO1xuICAgICAgICAgICAgcmVuYW1lQ2hpbGRyZW4gPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBmcmFnID0gcmFuZ2UuY2xvbmVDb250ZW50cygpXG4gICAgICAgICAgICAsIHdyYXBwZXIgPSBfd3JhcEZyYWdtZW50SW5Db250YWluZXIoZnJhZyk7XG5cbiAgICAgICAgX3RyYW5zZmVyU3RhdGVzKHJhbmdlQ29udGFpbmVyLCB3cmFwcGVyKTtcbiAgICAgICAgXy5kZWZlcihmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHdyYXBwZXIuYnJvYWRjYXN0KCdzdGF0ZXJlYWR5Jyk7XG4gICAgICAgICAgICBfLmRlZmVyKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgIGlmIChyZW5hbWVDaGlsZHJlbikgX3JlbmFtZUNoaWxkcmVuKHdyYXBwZXIpO1xuICAgICAgICAgICAgICAgIHZhciB3cmFwcGVyU3RhdGUgPSB3cmFwcGVyLmdldFN0YXRlKCk7XG4gICAgICAgICAgICAgICAgd3JhcHBlci5kZXN0cm95KCk7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwgd3JhcHBlclN0YXRlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY2FsbGJhY2soZXJyKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gX3dyYXBGcmFnbWVudEluQ29udGFpbmVyKGZyYWcsIHdyYXBwZXJDbGFzc05hbWUpIHtcbiAgICB2YXIgd3JhcEVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2JylcbiAgICAgICAgLCBhdHRyID0gbmV3IEJpbmRBdHRyaWJ1dGUod3JhcEVsKTtcblxuICAgIF8uZXh0ZW5kKGF0dHIsIHtcbiAgICAgICAgY29tcENsYXNzOiB3cmFwcGVyQ2xhc3NOYW1lIHx8ICdDb21wb25lbnQnLFxuICAgICAgICBjb21wRmFjZXRzOiB3cmFwcGVyQ2xhc3NOYW1lID8gW10gOiBbJ2NvbnRhaW5lciddLFxuICAgICAgICBjb21wTmFtZTogJ3dyYXBwZXInXG4gICAgfSk7XG5cbiAgICBhdHRyLmRlY29yYXRlKCk7XG5cbiAgICB3cmFwRWwuYXBwZW5kQ2hpbGQoZnJhZyk7XG4gICAgdmFyIHNjb3BlID0gYmluZGVyKHdyYXBFbCk7XG4gICAgcmV0dXJuIHNjb3BlLndyYXBwZXI7XG59XG5cblxuZnVuY3Rpb24gX2dldFJhbmdlQ29udGFpbmVyKHJhbmdlKSB7XG4gICAgdmFyIGVsID0gZG9tVXRpbHMuY29udGFpbmluZ0VsZW1lbnQocmFuZ2UuY29tbW9uQW5jZXN0b3JDb250YWluZXIpO1xuICAgIHJldHVybiBDb21wb25lbnQuZ2V0Q29udGFpbmluZ0NvbXBvbmVudChlbCwgdHJ1ZSwgJ2NvbnRhaW5lcicpO1xufVxuXG5cbmZ1bmN0aW9uIF90cmFuc2ZlclN0YXRlcyhmcm9tQ29tcCwgdG9Db21wKSB7XG4gICAgdmFyIGZyb21TY29wZSA9IGZyb21Db21wLmNvbnRhaW5lci5zY29wZTtcbiAgICB0b0NvbXAuY29udGFpbmVyLnNjb3BlLl9lYWNoKGZ1bmN0aW9uKHRvQ2hpbGRDb21wLCBuYW1lKSB7XG4gICAgICAgIHZhciBmcm9tQ2hpbGRDb21wID0gZnJvbVNjb3BlW25hbWVdO1xuICAgICAgICBpZiAoISBmcm9tQ2hpbGRDb21wKSByZXR1cm4gbG9nZ2VyLmVycm9yKCdmcmFnbWVudC5nZXRTdGF0ZTogY29ucG9uZW50JywgbmFtZSwgJ25vdCBmb3VuZCBpbiByYW5nZScpO1xuICAgICAgICB2YXIgc3RhdGUgPSBmcm9tQ2hpbGRDb21wLl9nZXRTdGF0ZSh0cnVlKTtcbiAgICAgICAgdG9DaGlsZENvbXAuc2V0U3RhdGUoc3RhdGUpO1xuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIF9yZW5hbWVDaGlsZHJlbihjb21wKSB7XG4gICAgY29tcC5jb250YWluZXIuc2NvcGUuX2VhY2goZnVuY3Rpb24oY2hpbGQpIHtcbiAgICAgICAgY2hpbGQucmVuYW1lKCk7XG4gICAgfSk7XG59XG5cblxuZnVuY3Rpb24gZXhwYW5kUmFuZ2VUb1NpYmxpbmdzKHJhbmdlKSB7XG4gICAgdmFyIHNpYmxpbmdzID0gZ2V0UmFuZ2VTaWJsaW5ncyhyYW5nZSk7XG4gICAgcmFuZ2UgPSBjcmVhdGVSYW5nZUZyb21TaWJsaW5ncyhzaWJsaW5ncyk7XG4gICAgcmV0dXJuIHJhbmdlO1xufVxuXG5cbmZ1bmN0aW9uIGNyZWF0ZVJhbmdlRnJvbVNpYmxpbmdzKG5vZGVzKSB7XG4gICAgdmFyIHJhbmdlID0gZG9jdW1lbnQuY3JlYXRlUmFuZ2UoKTtcbiAgICBpZiAobm9kZXMuc2libGluZ3MpIHtcbiAgICAgICAgcmFuZ2Uuc2V0U3RhcnRCZWZvcmUobm9kZXMuc3RhcnQpO1xuICAgICAgICByYW5nZS5zZXRFbmRBZnRlcihub2Rlcy5lbmQpO1xuICAgIH0gZWxzZVxuICAgICAgICByYW5nZS5zZWxlY3ROb2RlKG5vZGVzLnN0YXJ0KTtcbiAgICByZXR1cm4gcmFuZ2U7XG59XG5cblxuZnVuY3Rpb24gZ2V0UmFuZ2VTaWJsaW5ncyhyYW5nZSkge1xuICAgIHZhciBjb250YWluZXJOb2RlID0gcmFuZ2UuY29tbW9uQW5jZXN0b3JDb250YWluZXJcbiAgICAgICAgLCBzdGFydE5vZGUgPSByYW5nZS5zdGFydENvbnRhaW5lclxuICAgICAgICAsIGVuZE5vZGUgPSByYW5nZS5lbmRDb250YWluZXI7XG5cbiAgICBpZiAoc3RhcnROb2RlID09IGVuZE5vZGUpIHtcbiAgICAgICAgaWYgKHN0YXJ0Tm9kZSAhPSBjb250YWluZXJOb2RlKSBsb2dnZXIuZXJyb3IoJ2RlbGV0ZVNlbGVjdGlvbkNvbW1hbmQgbG9naWNhbCBlcnJvcjogc3RhcnQ9PWVuZCwgYnV0IGNvbnRhaW5lciBpcyBkaWZmZXJlbnQnKTtcbiAgICAgICAgcmV0dXJuIHsgc2libGluZ3M6IGZhbHNlLCBzdGFydDogc3RhcnROb2RlIH07XG4gICAgfVxuXG4gICAgaWYgKHN0YXJ0Tm9kZSA9PSBjb250YWluZXJOb2RlIHx8IGVuZE5vZGUgPT0gY29udGFpbmVyTm9kZSlcbiAgICAgICAgcmV0dXJuIHsgc2libGluZ3M6IGZhbHNlLCBzdGFydDogY29udGFpbmVyTm9kZSB9O1xuXG4gICAgdmFyIHN0YXJ0U2libGluZyA9IF9maW5kQ29udGFpbmluZ0NoaWxkKGNvbnRhaW5lck5vZGUsIHN0YXJ0Tm9kZSk7XG4gICAgdmFyIGVuZFNpYmxpbmcgPSBfZmluZENvbnRhaW5pbmdDaGlsZChjb250YWluZXJOb2RlLCBlbmROb2RlKTtcblxuICAgIGlmIChzdGFydFNpYmxpbmcgJiYgZW5kU2libGluZykge1xuICAgICAgICBpZiAoc3RhcnRTaWJsaW5nID09IGVuZFNpYmxpbmcpIHtcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcignZGVsZXRlU2VsZWN0aW9uQ29tbWFuZCBsb2dpY2FsIGVycm9yOiBzYW1lIHNpYmxpbmdzJyk7XG4gICAgICAgICAgICByZXR1cm4geyBzaWJsaW5nczogZmFsc2UsIHN0YXJ0OiBzdGFydFNpYmxpbmcgfTtcbiAgICAgICAgfSBlbHNlXG4gICAgICAgICAgICByZXR1cm4geyBzaWJsaW5nczogdHJ1ZSwgc3RhcnQ6IHN0YXJ0U2libGluZywgZW5kOiBlbmRTaWJsaW5nIH07XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIF9maW5kQ29udGFpbmluZ0NoaWxkKGNvbnRhaW5lck5vZGUsIHNlbE5vZGUpIHtcbiAgICByZXR1cm4gXy5maW5kKGNvbnRhaW5lck5vZGUuY2hpbGROb2RlcywgZnVuY3Rpb24obm9kZSkge1xuICAgICAgICByZXR1cm4gbm9kZS5jb250YWlucyhzZWxOb2RlKTtcbiAgICB9KTtcbn1cblxuXG5mdW5jdGlvbiBfY3JlYXRlTm9kZXNBbmRQYXRoc0Z1bmMoZnVuYykge1xuICAgIHJldHVybiBmdW5jdGlvbihyb290RWwsIGZyb21PYmopIHtcbiAgICAgICAgdmFyIHRvT2JqID0ge1xuICAgICAgICAgICAgc2libGluZ3M6IGZyb21PYmouc2libGluZ3MsXG4gICAgICAgICAgICBzdGFydDogZnVuYyhyb290RWwsIGZyb21PYmouc3RhcnQpXG4gICAgICAgIH07XG4gICAgICAgIGlmICh0b09iai5zaWJsaW5ncylcbiAgICAgICAgICAgIHRvT2JqLmVuZCA9IGZ1bmMocm9vdEVsLCBmcm9tT2JqLmVuZCk7XG4gICAgICAgIHJldHVybiB0b09iajtcbiAgICB9O1xufVxuXG5cbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiBgbWlsby51dGlsYFxuICovXG52YXIgdXRpbCA9IHtcbiAgICBsb2dnZXI6IHJlcXVpcmUoJy4vbG9nZ2VyJyksXG4gICAgcmVxdWVzdDogcmVxdWlyZSgnLi9yZXF1ZXN0JyksXG4gICAgd2Vic29ja2V0OiByZXF1aXJlKCcuL3dlYnNvY2tldCcpLFxuICAgIGNoZWNrOiByZXF1aXJlKCcuL2NoZWNrJyksXG4gICAgZXJyb3I6IHJlcXVpcmUoJy4vZXJyb3InKSxcbiAgICBjb3VudDogcmVxdWlyZSgnLi9jb3VudCcpLCAvLyBkZXByZWNhdGVkXG4gICAgdW5pcXVlSWQ6IHJlcXVpcmUoJy4vY291bnQnKSxcbiAgICBjb21wb25lbnROYW1lOiByZXF1aXJlKCcuL2NvbXBvbmVudF9uYW1lJyksXG4gICAgZG9tOiByZXF1aXJlKCcuL2RvbScpLFxuICAgIGRvbUxpc3RlbmVyczogcmVxdWlyZSgnLi9kb21fbGlzdGVuZXJzJyksXG4gICAgc2VsZWN0aW9uOiByZXF1aXJlKCcuL3NlbGVjdGlvbicpLFxuICAgIGZyYWdtZW50OiByZXF1aXJlKCcuL2ZyYWdtZW50JyksXG4gICAganNvblBhcnNlOiByZXF1aXJlKCcuL2pzb25fcGFyc2UnKSxcbiAgICBzdG9yYWdlOiByZXF1aXJlKCcuL3N0b3JhZ2UnKSxcbiAgICBkb21SZWFkeTogcmVxdWlyZSgnLi9kb21yZWFkeScpLFxuICAgIGRyYWdEcm9wOiByZXF1aXJlKCcuL2RyYWdkcm9wJyksXG4gICAgZGlhbG9nOiByZXF1aXJlKCcuLi9jb21wb25lbnRzL3VpL2Jvb3RzdHJhcC9EaWFsb2cnKSxcbiAgICBhbGVydDogcmVxdWlyZSgnLi4vY29tcG9uZW50cy91aS9ib290c3RyYXAvQWxlcnQnKSxcbiAgICBkb1Q6IHJlcXVpcmUoJ2RvdCcpLFxuICAgIGRlc3Ryb3k6IHV0aWxfZGVzdHJveVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSB1dGlsO1xuXG5cbmZ1bmN0aW9uIHV0aWxfZGVzdHJveSgpIHtcbiAgICB1dGlsLnJlcXVlc3QuZGVzdHJveSgpO1xuICAgIHV0aWwuZHJhZ0Ryb3AuZGVzdHJveSgpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbm1vZHVsZS5leHBvcnRzID0ganNvblBhcnNlO1xuXG5cbi8qKlxuICogYG1pbG8udXRpbC5qc29uUGFyc2VgXG4gKiBTYWZlIEpTT04ucGFyc2UsIHJldHVybnMgdW5kZWZpbmVkIGlmIEpTT04ucGFyc2UgdGhyb3dzIGFuIGV4Y2VwdGlvblxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgLSBKU09OIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBvYmplY3RcbiAqIEByZXR1cm4ge09iamVjdHx1bmRlZmluZWR9XG4gKi9cbmZ1bmN0aW9uIGpzb25QYXJzZShzdHIpIHtcbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShzdHIpO1xuICAgIH0gY2F0Y2ggKGUpIHt9XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vIDxhIG5hbWU9XCJ1dGlscy1sb2dnZXJcIj48L2E+XG4vLyBtaWxvLnV0aWxzLmxvZ2dlclxuLy8gLS0tLS0tLS0tLS1cblxuLy8gQXBwbGljYXRpb24gbG9nZ2VyIHRoYXQgaGFzIGVycm9yLCB3YXJuLCBpbmZvIGFuZCBkZWJ1Z1xuLy8gbWV0aG9kcywgdGhhdCBjYW4gYmUgc3VwcHJlc3NlZCBieSBzZXR0aW5nIGxvZyBsZXZlbC5cblxuLy8gUHJvcGVydGllczpcblxuLy8gLSBsZXZlbFxuXG4vLyAgIC0gMCAtIGVycm9yXG4vLyAgIC0gMSAtIHdhcm5cbi8vICAgLSAyIC0gaW5mb1xuLy8gICAtIDMgLSBkZWJ1ZyAoZGVmYXVsdClcblxuLy8gLSBlbmFibGVkXG5cbi8vICAgdHJ1ZSBieSBkZWZhdWx0LiBTZXQgdG8gZmFsc2UgdG8gZGlzYWJsZSBhbGwgbG9nZ2luZyBpbiBicm93c2VyIGNvbnNvbGUuXG5cblxudmFyIExvZ2dlciA9IHJlcXVpcmUoJy4vbG9nZ2VyX2NsYXNzJyk7XG5cbnZhciBsb2dnZXIgPSBuZXcgTG9nZ2VyKHsgbGV2ZWw6IDMgfSk7XG5cbm1vZHVsZS5leHBvcnRzID0gbG9nZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyAjIyMgTG9nZ2VyIENsYXNzXG5cbi8vIFByb3BlcnRpZXM6XG5cbi8vIC0gbGV2ZWxcblxuLy8gICAtIDAgLSBlcnJvclxuLy8gICAtIDEgLSB3YXJuXG4vLyAgIC0gMiAtIGluZm9cbi8vICAgLSAzIC0gZGVidWcgKGRlZmF1bHQpXG5cbi8vIC0gZW5hYmxlZFxuXG4vLyAgIHRydWUgYnkgZGVmYXVsdC4gU2V0IHRvIGZhbHNlIHRvIGRpc2FibGUgYWxsIGxvZ2dpbmcgaW4gYnJvd3NlciBjb25zb2xlLlxuXG5cbnZhciBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cblxuLyoqXG4gKiBMb2cgbGV2ZWxzLlxuICovXG5cbnZhciBsZXZlbHMgPSBbXG4gICAgJ2Vycm9yJyxcbiAgICAnd2FybicsXG4gICAgJ2luZm8nLFxuICAgICdkZWJ1Zydcbl07XG5cbnZhciBtYXhMZXZlbExlbmd0aCA9IE1hdGgubWF4LmFwcGx5KE1hdGgsIGxldmVscy5tYXAoZnVuY3Rpb24obGV2ZWwpIHsgcmV0dXJuIGxldmVsLmxlbmd0aDsgfSkpO1xuXG4vKipcbiAqIENvbG9ycyBmb3IgbG9nIGxldmVscy5cbiAqL1xuXG52YXIgY29sb3JzID0gW1xuICAgIDMxLFxuICAgIDMzLFxuICAgIDM2LFxuICAgIDkwXG5dO1xuXG4vKipcbiAqIFBhZHMgdGhlIG5pY2Ugb3V0cHV0IHRvIHRoZSBsb25nZXN0IGxvZyBsZXZlbC5cbiAqL1xuZnVuY3Rpb24gcGFkKHN0cikge1xuICAgIGlmIChzdHIubGVuZ3RoIDwgbWF4TGV2ZWxMZW5ndGgpXG4gICAgICAgIHJldHVybiBzdHIgKyBuZXcgQXJyYXkobWF4TGV2ZWxMZW5ndGggLSBzdHIubGVuZ3RoICsgMSkuam9pbignICcpO1xuXG4gICAgcmV0dXJuIHN0cjtcbn07XG5cblxuZnVuY3Rpb24gY29sb3JlZChzdHIsIGNvbG9yKSB7XG4gICAgcmV0dXJuICdcXHgxQlsnICsgY29sb3IgKyAnbScgKyBzdHIgKyAnIC1cXHgxQlszOW0nO1xufVxuXG5cbnZhciBERUZBVUxUX09QVElPTlMgPSB7XG4gICAgbGV2ZWw6IDMsXG4gICAgdGhyb3dMZXZlbDogLTEsIC8vIG5ldmVyIHRocm93XG4gICAgZW5hYmxlZDogdHJ1ZSxcbiAgICBsb2dQcmVmaXg6ICcnXG59XG5cblxuLyoqXG4gKiBMb2dnZXIgKGNvbnNvbGUpLlxuICpcbiAqIEBhcGkgcHVibGljXG4gKi9cbnZhciBMb2dnZXIgPSBmdW5jdGlvbiAob3B0cykge1xuICAgIF8uZXh0ZW5kKHRoaXMsIERFRkFVTFRfT1BUSU9OUyk7XG4gICAgXy5leHRlbmQodGhpcywgb3B0cyB8fCB7fSk7XG59O1xuXG5cbi8qKlxuICogTG9nIG1ldGhvZC5cbiAqXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbkxvZ2dlci5wcm90b3R5cGUubG9nID0gZnVuY3Rpb24gKHR5cGUpIHtcbiAgICB2YXIgaW5kZXggPSBsZXZlbHMuaW5kZXhPZih0eXBlKTtcblxuICAgIGlmICghIHRoaXMuZW5hYmxlZCB8fCBpbmRleCA+IHRoaXMubGV2ZWwpXG4gICAgICAgIHJldHVybiB0aGlzO1xuXG4gICAgdmFyIGFyZ3MgPSBfLnNsaWNlKGFyZ3VtZW50cywgMSk7XG5cbiAgICBpZiAoaW5kZXggPD0gdGhpcy50aHJvd0xldmVsKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoW3RoaXMubG9nUHJlZml4LCB0eXBlICsgJzonXS5jb25jYXQoYXJncykuam9pbignICcpKTtcblxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxuICAgICAgICAgIGNvbnNvbGVcbiAgICAgICAgLCBbIHRoaXMubG9nUHJlZml4Q29sb3JcbiAgICAgICAgICAgICAgPyAnICAgJyArIGNvbG9yZWQodGhpcy5sb2dQcmVmaXgsIHRoaXMubG9nUHJlZml4Q29sb3IpXG4gICAgICAgICAgICAgIDogdGhpcy5sb2dQcmVmaXgsXG4gICAgICAgICAgICAodGhpcy5jb2xvcnNcbiAgICAgICAgICAgICAgPyAnICcgKyBjb2xvcmVkKHBhZCh0eXBlKSwgY29sb3JzW2luZGV4XSlcbiAgICAgICAgICAgICAgOiB0eXBlKSArICc6J1xuICAgICAgICAgIF0uY29uY2F0KGFyZ3MpXG4gICAgKTtcblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKiBHZW5lcmF0ZSBtZXRob2RzLlxuICovXG5cbmxldmVscy5mb3JFYWNoKGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgTG9nZ2VyLnByb3RvdHlwZVtuYW1lXSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5sb2cuYXBwbHkodGhpcywgW25hbWVdLmNvbmNhdChfLnRvQXJyYXkoYXJndW1lbnRzKSkpO1xuICAgIH07XG59KTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IExvZ2dlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gbWlsby51dGlscy5yZXF1ZXN0XG4vLyAtLS0tLS0tLS0tLVxuXG4vLyBDb252ZW5pZW5jZSBmdW5jdGlvbnMgd3JhcHBpbmcgWE1MSFRUUFJlcXVlc3QgZnVuY3Rpb25hbGl0eS5cblxuLy8gYGBgXG4vLyB2YXIgcmVxdWVzdCA9IG1pbG8udXRpbHMucmVxdWVzdFxuLy8gICAgICwgb3B0czogeyBtZXRob2Q6ICdHRVQnIH07XG5cbi8vIHJlcXVlc3QodXJsLCBvcHRzLCBmdW5jdGlvbihlcnIsIGRhdGEpIHtcbi8vICAgICBsb2dnZXIuZGVidWcoZGF0YSk7XG4vLyB9KTtcblxuLy8gcmVxdWVzdC5nZXQodXJsLCBmdW5jdGlvbihlcnIsIGRhdGEpIHtcbi8vICAgICBsb2dnZXIuZGVidWcoZGF0YSk7XG4vLyB9KTtcbi8vIGBgYFxuXG4vLyBPbmx5IGdlbmVyaWMgcmVxdWVzdCBhbmQgZ2V0LCBqc29uLCBwb3N0IGNvbnZlbmllbmNlIG1ldGhvZHMgYXJlIGN1cnJlbnRseSBpbXBsZW1lbnRlZC5cblxuXG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjb3VudCA9IHJlcXVpcmUoJy4vY291bnQnKVxuICAgICwgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4vbG9nZ2VyJylcbiAgICAsIE1lc3NlbmdlciA9IHJlcXVpcmUoJy4uL21lc3NlbmdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHJlcXVlc3Q7XG5cblxudmFyIF9wZW5kaW5nUmVxdWVzdHMgPSBbXTtcblxudmFyIHByb21pc2VUaGVuID0gY3JlYXRlUHJvbWlzZU92ZXJyaWRlKCd0aGVuJyk7XG52YXIgcHJvbWlzZUNhdGNoID0gY3JlYXRlUHJvbWlzZU92ZXJyaWRlKCdjYXRjaCcpO1xuXG4vKipcbiAqIENyZWF0ZXMgYSBmdW5jdGlvbiB3aGljaCBpcyB1c2VkIHRvIG92ZXJyaWRlIHN0YW5kYXJkIHByb21pc2UgYmVoYXZpb3VyIGFuZCBhbGxvdyBwcm9taXNlIGluc3RhbmNlcyBcbiAqIGNyZWF0ZWQgdG8gbWFpbnRhaW4gYSByZWZlcmVuY2UgdG8gdGhlIHJlcXVlc3Qgb2JqZWN0IG5vIG1hdHRlciBpZiAudGhlbigpIG9yIC5jYXRjaCgpIGlzIGNhbGxlZC5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlUHJvbWlzZU92ZXJyaWRlKGZ1bmN0aW9uTmFtZSkge1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHByb21pc2UgPSBQcm9taXNlLnByb3RvdHlwZVtmdW5jdGlvbk5hbWVdLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIGtlZXBSZXF1ZXN0T2JqZWN0KHByb21pc2UsIHRoaXMuX3JlcXVlc3QpO1xuICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gcmVxdWVzdCh1cmwsIG9wdHMsIGNhbGxiYWNrKSB7XG4gICAgb3B0cy51cmwgPSB1cmw7XG4gICAgb3B0cy5jb250ZW50VHlwZSA9IG9wdHMuY29udGVudFR5cGUgfHwgJ2FwcGxpY2F0aW9uL2pzb247Y2hhcnNldD1VVEYtOCc7XG4gICAgaWYgKF9tZXNzZW5nZXIpIHJlcXVlc3QucG9zdE1lc3NhZ2VTeW5jKCdyZXF1ZXN0JywgeyBvcHRpb25zOiBvcHRzIH0pO1xuXG4gICAgdmFyIHJlcSA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpO1xuICAgIHJlcS5vcGVuKG9wdHMubWV0aG9kLCBvcHRzLnVybCwgdHJ1ZSk7XG4gICAgcmVxLnNldFJlcXVlc3RIZWFkZXIoJ0NvbnRlbnQtVHlwZScsIG9wdHMuY29udGVudFR5cGUpO1xuICAgIHNldFJlcXVlc3RIZWFkZXJzKHJlcSwgb3B0cy5oZWFkZXJzKTtcblxuICAgIHJlcS50aW1lb3V0ID0gb3B0cy50aW1lb3V0IHx8IGNvbmZpZy5yZXF1ZXN0LmRlZmF1bHRzLnRpbWVvdXQ7XG4gICAgcmVxLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IHJlcS5vbnRpbWVvdXQgPSByZXEub25hYm9ydCA9IG9uUmVhZHk7XG5cbiAgICB2YXIgeFByb21pc2UgPSBfY3JlYXRlWFByb21pc2UocmVxKTtcblxuICAgIHJlcS5zZW5kKEpTT04uc3RyaW5naWZ5KG9wdHMuZGF0YSkpO1xuICAgIHJlcVtjb25maWcucmVxdWVzdC5vcHRpb25zS2V5XSA9IG9wdHM7XG5cbiAgICBfcGVuZGluZ1JlcXVlc3RzLnB1c2gocmVxKTtcblxuICAgIHJldHVybiB4UHJvbWlzZS5wcm9taXNlO1xuXG4gICAgZnVuY3Rpb24gb25SZWFkeShlKSB7XG4gICAgICAgIF9vblJlYWR5KHJlcSwgY2FsbGJhY2ssIHhQcm9taXNlLCBlLnR5cGUpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBfY3JlYXRlWFByb21pc2UocmVxdWVzdCkge1xuICAgIHZhciByZXNvbHZlUHJvbWlzZSwgcmVqZWN0UHJvbWlzZTtcbiAgICB2YXIgcHJvbWlzZSA9IG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgICByZXNvbHZlUHJvbWlzZSA9IHJlc29sdmU7XG4gICAgICAgIHJlamVjdFByb21pc2UgPSByZWplY3Q7XG4gICAgfSk7XG5cbiAgICBrZWVwUmVxdWVzdE9iamVjdChwcm9taXNlLCByZXF1ZXN0KTtcbiAgICBwcm9taXNlLmNhdGNoKF8ubm9vcCk7IC8vIFNvbWV0aW1lcyBlcnJvcnMgYXJlIGhhbmRsZWQgd2l0aGluIGNhbGxiYWNrcywgc28gdW5jYXVnaHQgcHJvbWlzZSBlcnJvciBtZXNzYWdlIHNob3VsZCBiZSBzdXBwcmVzc2VkLlxuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgcHJvbWlzZTogcHJvbWlzZSxcbiAgICAgICAgcmVzb2x2ZTogcmVzb2x2ZVByb21pc2UsXG4gICAgICAgIHJlamVjdDogcmVqZWN0UHJvbWlzZVxuICAgIH1cbn1cblxuLy8gRW5zdXJlcyB0aGF0IHRoZSBwcm9taXNlIChhbmQgYW55IHByb21pc2VzIGNyZWF0ZWQgd2hlbiBjYWxsaW5nIC50aGVuLy5jYXRjaCkgaGFzIGEgcmVmZXJlbmNlIHRvIHRoZSBvcmlnaW5hbCByZXF1ZXN0IG9iamVjdFxuZnVuY3Rpb24ga2VlcFJlcXVlc3RPYmplY3QocHJvbWlzZSwgcmVxdWVzdCkge1xuICAgIHByb21pc2UuX3JlcXVlc3QgPSByZXF1ZXN0O1xuICAgIHByb21pc2UudGhlbiA9IHByb21pc2VUaGVuO1xuICAgIHByb21pc2UuY2F0Y2ggPSBwcm9taXNlQ2F0Y2g7XG5cbiAgICByZXR1cm4gcHJvbWlzZTtcbn1cblxuXG5mdW5jdGlvbiBzZXRSZXF1ZXN0SGVhZGVycyhyZXEsIGhlYWRlcnMpIHtcbiAgICBpZiAoaGVhZGVycylcbiAgICAgICAgXy5lYWNoS2V5KGhlYWRlcnMsIGZ1bmN0aW9uKHZhbHVlLCBrZXkpIHtcbiAgICAgICAgICAgIHJlcS5zZXRSZXF1ZXN0SGVhZGVyKGtleSwgdmFsdWUpO1xuICAgICAgICB9KTtcbn1cblxuZnVuY3Rpb24gX29uUmVhZHkocmVxLCBjYWxsYmFjaywgeFByb21pc2UsIGV2ZW50VHlwZSkge1xuICAgIGlmIChyZXEucmVhZHlTdGF0ZSAhPSA0KSByZXR1cm47XG4gICAgaWYgKCFyZXEuc3RhdHVzICYmIGV2ZW50VHlwZSA9PSAncmVhZHlzdGF0ZWNoYW5nZScpIHJldHVybjtcblxuICAgIF8uc3BsaWNlSXRlbShfcGVuZGluZ1JlcXVlc3RzLCByZXEpO1xuXG4gICAgdmFyIGVycm9yO1xuICAgIHRyeSB7XG4gICAgICAgIGlmICggcmVxLnN0YXR1cyA+PSAyMDAgJiYgcmVxLnN0YXR1cyA8IDQwMCApIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgcG9zdE1lc3NhZ2UoJ3N1Y2Nlc3MnKTtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayAmJiBjYWxsYmFjayhudWxsLCByZXEucmVzcG9uc2VUZXh0LCByZXEpO1xuICAgICAgICAgICAgfSBjYXRjaChlKSB7IGVycm9yID0gZTsgfVxuICAgICAgICAgICAgeFByb21pc2UucmVzb2x2ZShyZXEucmVzcG9uc2VUZXh0KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHZhciBlcnJvclJlYXNvbiA9IHJlcS5zdGF0dXMgfHwgZXZlbnRUeXBlO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBwb3N0TWVzc2FnZSgnZXJyb3InKTtcbiAgICAgICAgICAgICAgICBwb3N0TWVzc2FnZSgnZXJyb3InICsgZXJyb3JSZWFzb24pO1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrICYmIGNhbGxiYWNrKGVycm9yUmVhc29uLCByZXEucmVzcG9uc2VUZXh0LCByZXEpO1xuICAgICAgICAgICAgfSBjYXRjaChlKSB7IGVycm9yID0gZTsgfVxuICAgICAgICAgICAgeFByb21pc2UucmVqZWN0KHsgcmVhc29uOiBlcnJvclJlYXNvbiwgcmVzcG9uc2U6IHJlcS5yZXNwb25zZVRleHQgfSk7XG4gICAgICAgIH1cbiAgICB9IGNhdGNoKGUpIHtcbiAgICAgICAgZXJyb3IgPSBlcnJvciB8fCBlO1xuICAgIH1cblxuICAgIC8vIG5vdCByZW1vdmluZyBzdWJzY3JpcHRpb24gY3JlYXRlcyBtZW1vcnkgbGVhaywgZGVsZXRpbmcgcHJvcGVydHkgd291bGQgbm90IHJlbW92ZSBzdWJzY3JpcHRpb25cbiAgICByZXEub25yZWFkeXN0YXRlY2hhbmdlID0gcmVxLm9udGltZW91dCA9IHJlcS5vbmFib3J0ID0gdW5kZWZpbmVkO1xuXG4gICAgaWYgKCFfcGVuZGluZ1JlcXVlc3RzLmxlbmd0aClcbiAgICAgICAgcG9zdE1lc3NhZ2UoJ3JlcXVlc3RzY29tcGxldGVkJyk7XG5cbiAgICBpZiAoZXJyb3IpIHRocm93IG5ldyBFcnJvcignRXhjZXB0aW9uOiAnICsgZXJyb3IpO1xuXG4gICAgZnVuY3Rpb24gcG9zdE1lc3NhZ2UobXNnKSB7XG4gICAgICAgIGlmIChfbWVzc2VuZ2VyKSByZXF1ZXN0LnBvc3RNZXNzYWdlKG1zZyxcbiAgICAgICAgICAgIHsgc3RhdHVzOiBzdGF0dXMsIHJlc3BvbnNlOiByZXEucmVzcG9uc2VUZXh0IH0pO1xuICAgIH1cbn1cblxuXG5fLmV4dGVuZChyZXF1ZXN0LCB7XG4gICAgZ2V0OiByZXF1ZXN0JGdldCxcbiAgICBwb3N0OiByZXF1ZXN0JHBvc3QsXG4gICAganNvbjogcmVxdWVzdCRqc29uLFxuICAgIGpzb25wOiByZXF1ZXN0JGpzb25wLFxuICAgIGZpbGU6IHJlcXVlc3QkZmlsZSxcbiAgICB1c2VNZXNzZW5nZXI6IHJlcXVlc3QkdXNlTWVzc2VuZ2VyLFxuICAgIGRlc3Ryb3k6IHJlcXVlc3QkZGVzdHJveSxcbiAgICB3aGVuUmVxdWVzdHNDb21wbGV0ZWQ6IHdoZW5SZXF1ZXN0c0NvbXBsZXRlZFxufSk7XG5cblxudmFyIF9tZXNzZW5nZXI7XG5cblxuZnVuY3Rpb24gcmVxdWVzdCR1c2VNZXNzZW5nZXIoKSB7XG4gICAgX21lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXIocmVxdWVzdCwgWydvbicsICdvbmNlJywgJ29uU3luYycsICdvZmYnLCAnb25NZXNzYWdlcycsICdvZmZNZXNzYWdlcycsICdwb3N0TWVzc2FnZScsICdwb3N0TWVzc2FnZVN5bmMnXSk7XG59XG5cblxuZnVuY3Rpb24gcmVxdWVzdCRnZXQodXJsLCBjYWxsYmFjaykge1xuICAgIHJldHVybiByZXF1ZXN0KHVybCwgeyBtZXRob2Q6ICdHRVQnIH0sIGNhbGxiYWNrKTtcbn1cblxuXG5mdW5jdGlvbiByZXF1ZXN0JHBvc3QodXJsLCBkYXRhLCBjYWxsYmFjaykge1xuICAgIHJldHVybiByZXF1ZXN0KHVybCwgeyBtZXRob2Q6ICdQT1NUJywgZGF0YTogZGF0YSB9LCBjYWxsYmFjayk7XG59XG5cblxuZnVuY3Rpb24gcmVxdWVzdCRqc29uKHVybCwgY2FsbGJhY2spIHtcbiAgICB2YXIgcHJvbWlzZSA9IHJlcXVlc3QodXJsLCB7IG1ldGhvZDogJ0dFVCcgfSk7XG5cbiAgICB2YXIganNvblByb21pc2UgPSBwcm9taXNlLnRoZW4oSlNPTi5wYXJzZSk7XG5cbiAgICBpZiAoY2FsbGJhY2spXG4gICAgICAgIGpzb25Qcm9taXNlXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uKGRhdGEpIHsgY2FsbGJhY2sobnVsbCwgZGF0YSk7IH0pXG4gICAgICAgIC5jYXRjaChmdW5jdGlvbihlcnJEYXRhKSB7IGNhbGxiYWNrKGVyckRhdGEucmVhc29uLCBlcnJEYXRhLnJlc3BvbnNlKTsgfSk7XG5cbiAgICByZXR1cm4ganNvblByb21pc2U7XG59XG5cblxudmFyIGpzb25wT3B0aW9ucyA9IHsgbWV0aG9kOiAnR0VUJywganNvbnA6IHRydWUgfTtcbmZ1bmN0aW9uIHJlcXVlc3QkanNvbnAodXJsLCBjYWxsYmFjaykge1xuICAgIHZhciBzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKSxcbiAgICAgICAgeFByb21pc2UgPSBfY3JlYXRlWFByb21pc2Uoc2NyaXB0KSxcbiAgICAgICAgaGVhZCA9IHdpbmRvdy5kb2N1bWVudC5oZWFkLFxuICAgICAgICB1bmlxdWVDYWxsYmFjayA9IGNvbmZpZy5yZXF1ZXN0Lmpzb25wQ2FsbGJhY2tQcmVmaXggKyBjb3VudCgpO1xuXG4gICAgdmFyIG9wdHMgPSBfLmV4dGVuZCh7IHVybDogdXJsIH0sIGpzb25wT3B0aW9ucyk7XG4gICAgaWYgKF9tZXNzZW5nZXIpIHJlcXVlc3QucG9zdE1lc3NhZ2VTeW5jKCdyZXF1ZXN0JywgeyBvcHRpb25zOiBvcHRzIH0pO1xuXG4gICAgaWYgKCEgXy5pc0VxdWFsKF8ub21pdEtleXMob3B0cywgJ3VybCcpLCBqc29ucE9wdGlvbnMpKVxuICAgICAgICBsb2dnZXIud2FybignSWdub3JlZCBub3QgYWxsb3dlZCByZXF1ZXN0IG9wdGlvbnMgY2hhbmdlIGluIEpTT05QIHJlcXVlc3QgLSBvbmx5IFVSTCBjYW4gYmUgY2hhbmdlZCcpO1xuXG4gICAgdmFyIHRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgZXJyID0gbmV3IEVycm9yKCdObyBKU09OUCByZXNwb25zZSBvciBubyBjYWxsYmFjayBpbiByZXNwb25zZScpO1xuICAgICAgICBfb25SZXN1bHQoZXJyKTtcbiAgICB9LCBjb25maWcucmVxdWVzdC5qc29ucFRpbWVvdXQpO1xuXG4gICAgd2luZG93W3VuaXF1ZUNhbGxiYWNrXSA9IF8ucGFydGlhbChfb25SZXN1bHQsIG51bGwpO1xuXG4gICAgX3BlbmRpbmdSZXF1ZXN0cy5wdXNoKHdpbmRvd1t1bmlxdWVDYWxsYmFja10pO1xuXG4gICAgc2NyaXB0LnR5cGUgPSAndGV4dC9qYXZhc2NyaXB0JztcbiAgICBzY3JpcHQuc3JjID0gb3B0cy51cmwgKyAob3B0cy51cmwuaW5kZXhPZignPycpID09IC0xID8gJz8nIDogJyYnKSArICdjYWxsYmFjaz0nICsgdW5pcXVlQ2FsbGJhY2s7XG5cbiAgICBoZWFkLmFwcGVuZENoaWxkKHNjcmlwdCk7XG5cbiAgICByZXR1cm4geFByb21pc2UucHJvbWlzZTtcblxuXG4gICAgZnVuY3Rpb24gX29uUmVzdWx0KGVyciwgcmVzdWx0KSB7XG4gICAgICAgIF8uc3BsaWNlSXRlbShfcGVuZGluZ1JlcXVlc3RzLCB3aW5kb3dbdW5pcXVlQ2FsbGJhY2tdKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHBvc3RNZXNzYWdlKGVyciA/ICdlcnJvcicgOiAnc3VjY2VzcycsIGVyciwgcmVzdWx0KTtcbiAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ05vIEpTT05QIHJlc3BvbnNlIG9yIHRpbWVvdXQnKTtcbiAgICAgICAgICAgICAgICBwb3N0TWVzc2FnZSgnZXJyb3Jqc29ucHRpbWVvdXQnLCBlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbGJhY2sgJiYgY2FsbGJhY2soZXJyLCByZXN1bHQpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoKGUpIHsgdmFyIGVycm9yID0gZTsgfVxuICAgICAgICBpZiAoZXJyKSB4UHJvbWlzZS5yZWplY3QoZXJyKTtcbiAgICAgICAgZWxzZSB4UHJvbWlzZS5yZXNvbHZlKHJlc3VsdCk7XG5cbiAgICAgICAgY2xlYW5VcCgpO1xuICAgICAgICBpZiAoIV9wZW5kaW5nUmVxdWVzdHMubGVuZ3RoKVxuICAgICAgICAgICAgcG9zdE1lc3NhZ2UoJ3JlcXVlc3RzY29tcGxldGVkJyk7XG5cbiAgICAgICAgaWYgKGVycm9yKSB0aHJvdyBlcnJvcjtcbiAgICB9XG5cblxuICAgIGZ1bmN0aW9uIGNsZWFuVXAoKSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgaGVhZC5yZW1vdmVDaGlsZChzY3JpcHQpO1xuICAgICAgICBkZWxldGUgd2luZG93W3VuaXF1ZUNhbGxiYWNrXTtcbiAgICB9XG5cblxuICAgIGZ1bmN0aW9uIHBvc3RNZXNzYWdlKG1zZywgc3RhdHVzLCByZXN1bHQpIHtcbiAgICAgICAgaWYgKF9tZXNzZW5nZXIpIHJlcXVlc3QucG9zdE1lc3NhZ2UobXNnLFxuICAgICAgICAgICAgeyBzdGF0dXM6IHN0YXR1cywgcmVzcG9uc2U6IHJlc3VsdCB9KTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gcmVxdWVzdCRmaWxlKG9wdHMsIGZpbGVEYXRhLCBjYWxsYmFjaywgcHJvZ3Jlc3MpIHtcbiAgICBpZiAodHlwZW9mIG9wdHMgPT0gJ3N0cmluZycpXG4gICAgICAgIG9wdHMgPSB7IG1ldGhvZDogJ1BPU1QnLCB1cmw6IG9wdHMgfTtcblxuICAgIG9wdHMubWV0aG9kID0gb3B0cy5tZXRob2QgfHwgJ1BPU1QnO1xuICAgIG9wdHMuZmlsZSA9IHRydWU7XG5cbiAgICBpZiAoX21lc3NlbmdlcikgcmVxdWVzdC5wb3N0TWVzc2FnZVN5bmMoJ3JlcXVlc3QnLCB7IG9wdGlvbnM6IG9wdHMgfSk7XG5cbiAgICB2YXIgcmVxID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7XG4gICAgaWYgKHByb2dyZXNzKSByZXEudXBsb2FkLm9ucHJvZ3Jlc3MgPSBwcm9ncmVzcztcblxuICAgIHJlcS5vcGVuKG9wdHMubWV0aG9kLCBvcHRzLnVybCwgdHJ1ZSk7XG4gICAgc2V0UmVxdWVzdEhlYWRlcnMocmVxLCBvcHRzLmhlYWRlcnMpO1xuXG4gICAgcmVxLnRpbWVvdXQgPSBvcHRzLnRpbWVvdXQgfHwgY29uZmlnLnJlcXVlc3QuZGVmYXVsdHMudGltZW91dDtcbiAgICByZXEub25yZWFkeXN0YXRlY2hhbmdlID0gcmVxLm9udGltZW91dCA9IHJlcS5vbmFib3J0ID0gb25SZWFkeTtcblxuICAgIHZhciB4UHJvbWlzZSA9IF9jcmVhdGVYUHJvbWlzZShyZXEpO1xuXG4gICAgaWYgKG9wdHMuYmluYXJ5KVxuICAgICAgICByZXEuc2VuZChmaWxlRGF0YSk7XG4gICAgZWxzZSB7XG4gICAgICAgIHZhciBmb3JtRGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICBmb3JtRGF0YS5hcHBlbmQoJ2ZpbGUnLCBmaWxlRGF0YSk7XG4gICAgICAgIHJlcS5zZW5kKGZvcm1EYXRhKTtcbiAgICB9XG5cbiAgICBfcGVuZGluZ1JlcXVlc3RzLnB1c2gocmVxKTtcblxuICAgIHJldHVybiB4UHJvbWlzZS5wcm9taXNlO1xuXG4gICAgZnVuY3Rpb24gb25SZWFkeShlKSB7XG4gICAgICAgIGlmIChwcm9ncmVzcykgcmVxLnVwbG9hZC5vbnByb2dyZXNzID0gdW5kZWZpbmVkO1xuICAgICAgICBfb25SZWFkeShyZXEsIGNhbGxiYWNrLCB4UHJvbWlzZSwgZS50eXBlKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gcmVxdWVzdCRkZXN0cm95KCkge1xuICAgIGlmIChfbWVzc2VuZ2VyKSBfbWVzc2VuZ2VyLmRlc3Ryb3koKTtcbiAgICByZXF1ZXN0Ll9kZXN0cm95ZWQgPSB0cnVlO1xufVxuXG5cbmZ1bmN0aW9uIHdoZW5SZXF1ZXN0c0NvbXBsZXRlZChjYWxsYmFjaywgdGltZW91dCkge1xuICAgIGNhbGxiYWNrID0gXy5vbmNlKGNhbGxiYWNrKTtcbiAgICBpZiAodGltZW91dClcbiAgICAgICAgXy5kZWxheShjYWxsYmFjaywgdGltZW91dCwgJ3RpbWVvdXQnKTtcblxuICAgIGlmIChfcGVuZGluZ1JlcXVlc3RzLmxlbmd0aClcbiAgICAgICAgX21lc3Nlbmdlci5vbmNlKCdyZXF1ZXN0c2NvbXBsZXRlZCcsIGNhbGxiYWNrKTtcbiAgICBlbHNlXG4gICAgICAgIF8uZGVmZXIoY2FsbGJhY2spO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBkb21VdGlscyA9IHJlcXVpcmUoJy4uL2RvbScpXG4gICAgLCBjb250YWluaW5nRWxlbWVudCA9IGRvbVV0aWxzLmNvbnRhaW5pbmdFbGVtZW50XG4gICAgLCBzZXRDYXJldFBvc2l0aW9uID0gZG9tVXRpbHMuc2V0Q2FyZXRQb3NpdGlvblxuICAgICwgZ2V0Q29tcG9uZW50c0Zyb21SYW5nZSA9IGRvbVV0aWxzLmdldENvbXBvbmVudHNGcm9tUmFuZ2VcbiAgICAsIGRlbGV0ZVJhbmdlV2l0aENvbXBvbmVudHMgPSBkb21VdGlscy5kZWxldGVSYW5nZVdpdGhDb21wb25lbnRzXG4gICAgLCBsb2dnZXIgPSByZXF1aXJlKCcuLi9sb2dnZXInKVxuICAgICwgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vLi4vY29tcG9uZW50cy9jX2NsYXNzJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxubW9kdWxlLmV4cG9ydHMgPSBUZXh0U2VsZWN0aW9uO1xuXG5cbi8qKlxuICogVGV4dCBzZWxlY3Rpb24gY2xhc3MuXG4gKiBTZXJ2ZXMgYXMgYSBoZWxwZXIgdG8gbWFuYWdlIGN1cnJlbnQgc2VsZWN0aW9uXG4gKiBUaGUgb2JqZWN0IGNhbm5vdCBiZSByZXVzZWQsIGlmIHRoZSBzZWxlY3Rpb24gY2hhbmdlcyBzb21lIG9mIGl0cyBwcm9wZXJ0aWVzIG1heSBjb250YWluIGluZm9ybWF0aW9uIHJlbGF0ZWQgdG8gcHJldmlvdXMgc2VsZWN0aW9uXG4gKlxuICogQHBhcmFtIHtXaW5kb3d9IHdpbiB3aW5kb3cgaW4gd2hpY2ggdGV4dCBzZWxlY3Rpb24gaXMgcHJvY2Vzc2VkXG4gKi9cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24od2luKSB7XG4gICAgaWYgKCEgdGhpcyBpbnN0YW5jZW9mIFRleHRTZWxlY3Rpb24pXG4gICAgICAgIHJldHVybiBuZXcgVGV4dFNlbGVjdGlvbih3aW4pO1xuICAgIHRoaXMud2luZG93ID0gd2luIHx8IHdpbmRvdztcbiAgICB0aGlzLmluaXQoKTtcbn1cblxuXG4vKipcbiAqIFRleHRTZWxlY3Rpb24gaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHNlbGVjdGlvbiBzdGFydCBlbGVtZW50XG4gKlxuICogQHJldHVybiB7RWxlbWVudHxudWxsfVxuICovXG52YXIgVGV4dFNlbGVjdGlvbiRzdGFydEVsZW1lbnQgPSBcbiAgICBfLnBhcnRpYWwoX2dldEVsZW1lbnQsICdfc3RhcnRFbGVtZW50JywgJ3N0YXJ0Q29udGFpbmVyJyk7XG5cblxuLyoqXG4gKiBUZXh0U2VsZWN0aW9uIGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyBzZWxlY3Rpb24gZW5kIGVsZW1lbnRcbiAqXG4gKiBAcmV0dXJuIHtFbGVtZW50fG51bGx9XG4gKi9cbnZhciBUZXh0U2VsZWN0aW9uJGVuZEVsZW1lbnQgPSBcbiAgICBfLnBhcnRpYWwoX2dldEVsZW1lbnQsICdfZW5kRWxlbWVudCcsICdlbmRDb250YWluZXInKTtcblxuXG4vKipcbiAqIFRleHRTZWxlY3Rpb24gaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHNlbGVjdGlvbiBlbmQgZWxlbWVudFxuICpcbiAqIEByZXR1cm4ge0VsZW1lbnR8bnVsbH1cbiAqL1xudmFyIFRleHRTZWxlY3Rpb24kY29udGFpbmluZ0VsZW1lbnQgPSBcbiAgICBfLnBhcnRpYWwoX2dldEVsZW1lbnQsICdfY29udGFpbmluZ0VsZW1lbnQnLCAnY29tbW9uQW5jZXN0b3JDb250YWluZXInKTtcblxuXG4vKipcbiAqIFRleHRTZWxlY3Rpb24gaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHNlbGVjdGlvbiBzdGFydCBDb21wb25lbnRcbiAqXG4gKiBAcmV0dXJuIHtDb21wb25lbnR9XG4gKi9cbnZhciBUZXh0U2VsZWN0aW9uJHN0YXJ0Q29tcG9uZW50ID0gXG4gICAgXy5wYXJ0aWFsKF9nZXRDb21wb25lbnQsICdfc3RhcnRDb21wb25lbnQnLCAnc3RhcnRFbGVtZW50Jyk7XG5cblxuLyoqXG4gKiBUZXh0U2VsZWN0aW9uIGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyBzZWxlY3Rpb24gZW5kIENvbXBvbmVudFxuICpcbiAqIEByZXR1cm4ge0NvbXBvbmVudH1cbiAqL1xudmFyIFRleHRTZWxlY3Rpb24kZW5kQ29tcG9uZW50ID0gXG4gICAgXy5wYXJ0aWFsKF9nZXRDb21wb25lbnQsICdfZW5kQ29tcG9uZW50JywgJ2VuZEVsZW1lbnQnKTtcblxuXG4vKipcbiAqIFRleHRTZWxlY3Rpb24gaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHNlbGVjdGlvbiBlbmQgQ29tcG9uZW50XG4gKlxuICogQHJldHVybiB7Q29tcG9uZW50fVxuICovXG52YXIgVGV4dFNlbGVjdGlvbiRjb250YWluaW5nQ29tcG9uZW50ID0gXG4gICAgXy5wYXJ0aWFsKF9nZXRDb21wb25lbnQsICdfY29udGFpbmluZ0NvbXBvbmVudCcsICdjb250YWluaW5nRWxlbWVudCcpO1xuXG5cbl8uZXh0ZW5kUHJvdG8oVGV4dFNlbGVjdGlvbiwge1xuICAgIGluaXQ6IFRleHRTZWxlY3Rpb24kaW5pdCxcbiAgICB0ZXh0OiBUZXh0U2VsZWN0aW9uJHRleHQsXG4gICAgdGV4dE5vZGVzOiBUZXh0U2VsZWN0aW9uJHRleHROb2RlcyxcbiAgICBjbGVhcjogVGV4dFNlbGVjdGlvbiRjbGVhcixcblxuICAgIHN0YXJ0RWxlbWVudDogVGV4dFNlbGVjdGlvbiRzdGFydEVsZW1lbnQsXG4gICAgZW5kRWxlbWVudDogVGV4dFNlbGVjdGlvbiRlbmRFbGVtZW50LFxuICAgIGNvbnRhaW5pbmdFbGVtZW50OiBUZXh0U2VsZWN0aW9uJGNvbnRhaW5pbmdFbGVtZW50LFxuXG4gICAgc3RhcnRDb21wb25lbnQ6IFRleHRTZWxlY3Rpb24kc3RhcnRDb21wb25lbnQsXG4gICAgZW5kQ29tcG9uZW50OiBUZXh0U2VsZWN0aW9uJGVuZENvbXBvbmVudCxcbiAgICBjb250YWluaW5nQ29tcG9uZW50OiBUZXh0U2VsZWN0aW9uJGNvbnRhaW5pbmdDb21wb25lbnQsXG5cbiAgICBjb250YWluZWRDb21wb25lbnRzOiBUZXh0U2VsZWN0aW9uJGNvbnRhaW5lZENvbXBvbmVudHMsXG4gICAgZWFjaENvbnRhaW5lZENvbXBvbmVudDogVGV4dFNlbGVjdGlvbiRlYWNoQ29udGFpbmVkQ29tcG9uZW50LFxuICAgIGRlbDogVGV4dFNlbGVjdGlvbiRkZWwsXG4gICAgX2dldFBvc3REZWxldGVTZWxlY3Rpb25Qb2ludDogX2dldFBvc3REZWxldGVTZWxlY3Rpb25Qb2ludCxcbiAgICBfc2VsZWN0QWZ0ZXJEZWxldGU6IF9zZWxlY3RBZnRlckRlbGV0ZSxcblxuICAgIGdldFJhbmdlOiBUZXh0U2VsZWN0aW9uJGdldFJhbmdlLFxuICAgIGdldFN0YXRlOiBUZXh0U2VsZWN0aW9uJGdldFN0YXRlLFxuICAgIGdldE5vcm1hbGl6ZWRSYW5nZTogVGV4dFNlbGVjdGlvbiQkZ2V0Tm9ybWFsaXplZFJhbmdlLFxuICAgIGdldERpcmVjdGlvbjogVGV4dFNlbGVjdGlvbiQkZ2V0RGlyZWN0aW9uXG59KTtcblxuXG5fLmV4dGVuZChUZXh0U2VsZWN0aW9uLCB7XG4gICAgY3JlYXRlRnJvbVJhbmdlOiBUZXh0U2VsZWN0aW9uJCRjcmVhdGVGcm9tUmFuZ2UsXG4gICAgY3JlYXRlRnJvbVN0YXRlOiBUZXh0U2VsZWN0aW9uJCRjcmVhdGVGcm9tU3RhdGUsXG4gICAgY3JlYXRlU3RhdGVPYmplY3Q6IFRleHRTZWxlY3Rpb24kJGNyZWF0ZVN0YXRlT2JqZWN0XG59KTtcblxuXG4vKipcbiAqIFRleHRTZWxlY3Rpb24gaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsaXplcyBUZXh0U2VsZWN0aW9uIGZyb20gdGhlIGN1cnJlbnQgc2VsZWN0aW9uXG4gKi9cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kaW5pdCgpIHtcbiAgICB0aGlzLnNlbGVjdGlvbiA9IHRoaXMud2luZG93LmdldFNlbGVjdGlvbigpO1xuICAgIGlmICh0aGlzLnNlbGVjdGlvbi5yYW5nZUNvdW50KVxuICAgICAgICB0aGlzLnJhbmdlID0gdGhpcy5zZWxlY3Rpb24uZ2V0UmFuZ2VBdCgwKTtcbiAgICB0aGlzLmlzQ29sbGFwc2VkID0gdGhpcy5zZWxlY3Rpb24uaXNDb2xsYXBzZWQ7XG59XG5cblxuLyoqXG4gKiBUZXh0U2VsZWN0aW9uIGluc3RhbmNlIG1ldGhvZFxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHNlbGVjdGlvbiB0ZXh0XG4gKlxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBUZXh0U2VsZWN0aW9uJHRleHQoKSB7XG4gICAgaWYgKCEgdGhpcy5yYW5nZSkgcmV0dXJuIHVuZGVmaW5lZDtcblxuICAgIGlmICghIHRoaXMuX3RleHQpXG4gICAgICAgIHRoaXMuX3RleHQgPSB0aGlzLnJhbmdlLnRvU3RyaW5nKCk7XG5cbiAgICByZXR1cm4gdGhpcy5fdGV4dDtcbn1cblxuXG4vKipcbiAqIFRleHRTZWxlY3Rpb24gaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgc2VsZWN0aW9uIHRleHQgbm9kZXNcbiAqXG4gKiBAcmV0dXJuIHtBcnJheVtOb2RlXX1cbiAqL1xuZnVuY3Rpb24gVGV4dFNlbGVjdGlvbiR0ZXh0Tm9kZXMoKSB7XG4gICAgaWYgKCEgdGhpcy5yYW5nZSkgcmV0dXJuIHVuZGVmaW5lZDtcblxuICAgIGlmICghIHRoaXMuX3RleHROb2RlcylcbiAgICAgICAgdGhpcy5fdGV4dE5vZGVzID0gX2dldFRleHROb2Rlcy5jYWxsKHRoaXMpO1xuICAgIHJldHVybiB0aGlzLl90ZXh0Tm9kZXM7XG59XG5cblxuZnVuY3Rpb24gVGV4dFNlbGVjdGlvbiRjbGVhcigpIHtcbiAgICB0aGlzLnNlbGVjdGlvbi5yZW1vdmVBbGxSYW5nZXMoKTtcbn1cblxuXG4vKipcbiAqIFJldHJpZXZlcyB0ZXh0IGFuZCB0ZXh0IG5vZGVzIGZyb20gc2VsZWN0aW9uIHNhdmluZyB0aGVtIG9uIHByb3BlcnRpZXMgb2Ygb2JqZWN0XG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7VGV4dFNlbGVjdGlvbn0gdGhpc1xuICovXG5mdW5jdGlvbiBfZ2V0VGV4dE5vZGVzKCkge1xuICAgIC8vIGxpc3Qgb2Ygc2VsZWN0ZWQgdGV4dCBub2Rlc1xuICAgIHZhciB0ZXh0Tm9kZXMgPSBbXTtcblxuICAgIGlmICh0aGlzLmlzQ29sbGFwc2VkKVxuICAgICAgICByZXR1cm4gdGV4dE5vZGVzO1xuXG4gICAgLy8gY3JlYXRlIFRyZWVXYWxrZXIgdG8gdHJhdmVyc2UgdGhlIHRyZWUgdG8gc2VsZWN0IGFsbCB0ZXh0IG5vZGVzXG4gICAgdmFyIHNlbFN0YXJ0ID0gdGhpcy5yYW5nZS5zdGFydENvbnRhaW5lclxuICAgICAgICAsIHNlbEVuZCA9IHRoaXMucmFuZ2UuZW5kQ29udGFpbmVyXG4gICAgICAgICwgcmFuZ2VDb250YWluZXIgPSB0aGlzLnJhbmdlLmNvbW1vbkFuY2VzdG9yQ29udGFpbmVyO1xuXG4gICAgdmFyIHRyZWVXYWxrZXIgPSB0aGlzLndpbmRvdy5kb2N1bWVudC5jcmVhdGVUcmVlV2Fsa2VyKHJhbmdlQ29udGFpbmVyLCBOb2RlRmlsdGVyLlNIT1dfVEVYVCk7XG4gICAgdmFyIG5vZGUgPSB0cmVlV2Fsa2VyLmN1cnJlbnROb2RlID0gc2VsU3RhcnQ7XG5cbiAgICAvLyB0cmF2ZXJzZSBET00gdHJlZSB0byBjb2xsZWN0IGFsbCBzZWxlY3RlZCB0ZXh0IG5vZGVzXG4gICAgd2hpbGUgKG5vZGUgJiYgKCEgaW5FbmQgfHwgc2VsRW5kLmNvbnRhaW5zKG5vZGUpKSkge1xuICAgICAgICB0ZXh0Tm9kZXMucHVzaChub2RlKTtcbiAgICAgICAgdmFyIGluRW5kID0gaW5FbmQgfHwgc2VsRW5kLmNvbnRhaW5zKG5vZGUpO1xuICAgICAgICBub2RlID0gdHJlZVdhbGtlci5uZXh0Tm9kZSgpO1xuICAgIH1cbiAgICByZXR1cm4gdGV4dE5vZGVzO1xufVxuXG5cbi8qKlxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHN0YXJ0L2VuZCBlbGVtZW50IGZyb20gc2VsZWN0aW9uIHNhdmluZyB0aGVtIG9uIHByb3BlcnRpZXMgb2Ygb2JqZWN0XG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7VGV4dFNlbGVjdGlvbn0gdGhpc1xuICogQHJldHVybiB7RWxlbWVudHxudWxsfVxuICovXG5mdW5jdGlvbiBfZ2V0RWxlbWVudCh0aGlzUHJvcE5hbWUsIHJhbmdlUHJvcE5hbWUpIHtcbiAgICBpZiAoISB0aGlzLnJhbmdlKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gICAgaWYgKHR5cGVvZiB0aGlzW3RoaXNQcm9wTmFtZV0gPT0gJ3VuZGVmaW5lZCcpXG4gICAgICAgIHRoaXNbdGhpc1Byb3BOYW1lXSA9IGNvbnRhaW5pbmdFbGVtZW50KHRoaXMucmFuZ2VbcmFuZ2VQcm9wTmFtZV0pO1xuICAgIHJldHVybiB0aGlzW3RoaXNQcm9wTmFtZV07XG59XG5cblxuLyoqXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgc3RhcnQvZW5kIGNvbXBvbmVudCBmcm9tIHNlbGVjdGlvbiBzYXZpbmcgdGhlbSBvbiBwcm9wZXJ0aWVzIG9mIG9iamVjdFxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge1RleHRTZWxlY3Rpb259IHRoaXNcbiAqIEByZXR1cm4ge0NvbXBvbmVudH1cbiAqL1xuZnVuY3Rpb24gX2dldENvbXBvbmVudCh0aGlzUHJvcE5hbWUsIGVsTWV0aG9kTmFtZSkge1xuICAgIGlmICghIHRoaXMucmFuZ2UpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICBpZiAodHlwZW9mIHRoaXNbdGhpc1Byb3BOYW1lXSA9PSAndW5kZWZpbmVkJylcbiAgICAgICAgdGhpc1t0aGlzUHJvcE5hbWVdID0gQ29tcG9uZW50LmdldENvbnRhaW5pbmdDb21wb25lbnQodGhpc1tlbE1ldGhvZE5hbWVdKCkpO1xuICAgIHJldHVybiB0aGlzW3RoaXNQcm9wTmFtZV07XG59XG5cblxuZnVuY3Rpb24gVGV4dFNlbGVjdGlvbiRjb250YWluZWRDb21wb25lbnRzKCkge1xuICAgIGlmICh0aGlzLl9jb250YWluZWRDb21wb25lbnRzKVxuICAgICAgICByZXR1cm4gdGhpcy5fY29udGFpbmVkQ29tcG9uZW50cztcblxuICAgIHZhciBjb21wb25lbnRzID0gdGhpcy5fY29udGFpbmVkQ29tcG9uZW50cyA9IFtdO1xuXG4gICAgaWYgKHRoaXMuaXNDb2xsYXBzZWQgfHwgISB0aGlzLnJhbmdlKSByZXR1cm4gY29tcG9uZW50cztcblxuICAgIHJldHVybiBnZXRDb21wb25lbnRzRnJvbVJhbmdlKHRoaXMucmFuZ2UpO1xufVxuXG5cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kZWFjaENvbnRhaW5lZENvbXBvbmVudChjYWxsYmFjaywgdGhpc0FyZykge1xuICAgIGlmICh0aGlzLmlzQ29sbGFwc2VkIHx8ICEgdGhpcy5yYW5nZSkgcmV0dXJuO1xuXG4gICAgdmFyIGNvbXBvbmVudHMgPSB0aGlzLmNvbnRhaW5lZENvbXBvbmVudHMoKTtcblxuICAgIGNvbXBvbmVudHMuZm9yRWFjaChjYWxsYmFjaywgdGhpc0FyZyk7XG59XG5cblxuLyoqXG4gKiBUZXh0U2VsZWN0aW9uIGluc3RhbmNlIG1ldGhvZFxuICogRGVsZXRlcyB0aGUgY3VycmVudCBzZWxlY3Rpb24gYW5kIGFsbCBjb21wb25lbnRzIGluIGl0XG4gKiBcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gc2VsZWN0RW5kQ29udGFpbmVyIHNldCB0byB0cnVlIGlmIHRoZSBlbmQgY29udGFpbmVyIHNob3VsZCBiZSBzZWxlY3RlZCBhZnRlciBkZWxldGlvblxuICovXG5mdW5jdGlvbiBUZXh0U2VsZWN0aW9uJGRlbChzZWxlY3RFbmRDb250YWluZXIpIHtcbiAgICBpZiAodGhpcy5pc0NvbGxhcHNlZCB8fCAhIHRoaXMucmFuZ2UpIHJldHVybjtcblxuICAgIHZhciBzZWxQb2ludCA9IHRoaXMuX2dldFBvc3REZWxldGVTZWxlY3Rpb25Qb2ludChzZWxlY3RFbmRDb250YWluZXIpO1xuXG4gICAgZGVsZXRlUmFuZ2VXaXRoQ29tcG9uZW50cyh0aGlzLnJhbmdlKTtcblxuICAgIHRoaXMuX3NlbGVjdEFmdGVyRGVsZXRlKHNlbFBvaW50KTtcbiAgICBzZWxQb2ludC5ub2RlLnBhcmVudE5vZGUubm9ybWFsaXplKCk7XG59XG5cblxuZnVuY3Rpb24gX2dldFBvc3REZWxldGVTZWxlY3Rpb25Qb2ludChzZWxlY3RFbmRDb250YWluZXIpIHtcbiAgICB2YXIgc2VsTm9kZSA9IHRoaXMucmFuZ2Uuc3RhcnRDb250YWluZXI7XG4gICAgdmFyIHNlbE9mZnNldCA9IHRoaXMucmFuZ2Uuc3RhcnRPZmZzZXQ7XG4gICAgaWYgKHNlbGVjdEVuZENvbnRhaW5lciAmJiB0aGlzLnJhbmdlLnN0YXJ0Q29udGFpbmVyICE9IHRoaXMucmFuZ2UuZW5kQ29udGFpbmVyKSB7XG4gICAgICAgIHNlbE5vZGUgPSB0aGlzLnJhbmdlLmVuZENvbnRhaW5lcjtcbiAgICAgICAgc2VsT2Zmc2V0ID0gMDtcbiAgICB9XG4gICAgcmV0dXJuIHsgbm9kZTogc2VsTm9kZSwgb2Zmc2V0OiBzZWxPZmZzZXQgfTtcbn1cblxuXG5mdW5jdGlvbiBfc2VsZWN0QWZ0ZXJEZWxldGUoc2VsUG9pbnQpIHtcbiAgICB2YXIgc2VsTm9kZSA9IHNlbFBvaW50Lm5vZGVcbiAgICAgICAgLCBzZWxPZmZzZXQgPSBzZWxQb2ludC5vZmZzZXQ7XG5cbiAgICBpZiAoIXNlbE5vZGUpIHJldHVybjtcbiAgICBpZiAoc2VsTm9kZS5ub2RlVHlwZSA9PSBOb2RlLlRFWFRfTk9ERSlcbiAgICAgICAgc2VsTm9kZS50ZXh0Q29udGVudCA9IHNlbE5vZGUudGV4dENvbnRlbnQudHJpbVJpZ2h0KCk7XG4gICAgaWYgKCFzZWxOb2RlLm5vZGVWYWx1ZSlcbiAgICAgICAgc2VsTm9kZS5ub2RlVmFsdWUgPSAnXFx1MDBBMCc7IC8vbm9uLWJyZWFraW5nIHNwYWNlLCBcXHUyMDBCIGZvciB6ZXJvIHdpZHRoIHNwYWNlO1xuXG4gICAgdmFyIHBvc2l0aW9uID0gc2VsT2Zmc2V0ID4gc2VsTm9kZS5sZW5ndGggPyBzZWxOb2RlLmxlbmd0aCA6IHNlbE9mZnNldDtcbiAgICBzZXRDYXJldFBvc2l0aW9uKHNlbE5vZGUsIHBvc2l0aW9uKTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgc2VsZWN0aW9uIHJhbmdlXG4gKlxuICogQHJldHVybiB7UmFuZ2V9XG4gKi9cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kZ2V0UmFuZ2UoKSB7XG4gICAgcmV0dXJuIHRoaXMucmFuZ2U7XG59XG5cblxuLyoqXG4gKiBTdG9yZXMgc2VsZWN0aW9uIHdpbmRvdywgbm9kZXMgYW5kIG9mZnNldHMgaW4gb2JqZWN0XG4gKi9cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kZ2V0U3RhdGUocm9vdEVsKSB7XG4gICAgdmFyIHIgPSB0aGlzLnJhbmdlO1xuICAgIHZhciBkb2MgPSByb290RWwub3duZXJEb2N1bWVudFxuICAgICAgICAsIHdpbiA9IGRvYy5kZWZhdWx0VmlldyB8fCBkb2MucGFyZW50V2luZG93O1xuICAgIGlmICghcikgcmV0dXJuIHsgd2luZG93OiB3aW4gfTtcbiAgICByZXR1cm4gVGV4dFNlbGVjdGlvbi5jcmVhdGVTdGF0ZU9iamVjdChyb290RWwsIHIuc3RhcnRDb250YWluZXIsIHIuc3RhcnRPZmZzZXQsIHIuZW5kQ29udGFpbmVyLCByLmVuZE9mZnNldCk7XG59XG5cblxuZnVuY3Rpb24gVGV4dFNlbGVjdGlvbiQkY3JlYXRlU3RhdGVPYmplY3Qocm9vdEVsLCBzdGFydENvbnRhaW5lciwgc3RhcnRPZmZzZXQsIGVuZENvbnRhaW5lciwgZW5kT2Zmc2V0KSB7XG4gICAgZW5kQ29udGFpbmVyID0gZW5kQ29udGFpbmVyIHx8IHN0YXJ0Q29udGFpbmVyO1xuICAgIGVuZE9mZnNldCA9IGVuZE9mZnNldCB8fCBzdGFydE9mZnNldDtcbiAgICB2YXIgZG9jID0gcm9vdEVsLm93bmVyRG9jdW1lbnRcbiAgICAgICAgLCB3aW4gPSBkb2MuZGVmYXVsdFZpZXcgfHwgZG9jLnBhcmVudFdpbmRvdztcbiAgICByZXR1cm4ge1xuICAgICAgICB3aW5kb3c6IHdpbixcbiAgICAgICAgcm9vdEVsOiByb290RWwsXG4gICAgICAgIHN0YXJ0OiBfZ2V0U2VsZWN0aW9uUG9pbnRTdGF0ZShyb290RWwsIHN0YXJ0Q29udGFpbmVyLCBzdGFydE9mZnNldCksXG4gICAgICAgIGVuZDogX2dldFNlbGVjdGlvblBvaW50U3RhdGUocm9vdEVsLCBlbmRDb250YWluZXIsIGVuZE9mZnNldClcbiAgICB9O1xufVxuXG5cbmZ1bmN0aW9uIF9nZXRTZWxlY3Rpb25Qb2ludFN0YXRlKHJvb3RFbCwgbm9kZSwgb2Zmc2V0KSB7XG4gICAgdmFyIHRyZWVQYXRoID0gZG9tVXRpbHMudHJlZVBhdGhPZihyb290RWwsIG5vZGUpO1xuICAgIGlmICghIHRyZWVQYXRoKSBsb2dnZXIuZXJyb3IoJ1NlbGVjdGlvbiBwb2ludCBpcyBvdXRzaWRlIG9mIHJvb3QgZWxlbWVudCcpO1xuICAgIHJldHVybiB7XG4gICAgICAgIHRyZWVQYXRoOiB0cmVlUGF0aCxcbiAgICAgICAgb2Zmc2V0OiBvZmZzZXRcbiAgICB9O1xufVxuXG5cbi8qKlxuICogUmVzdG9yZXMgYWN0dWFsIHNlbGVjdGlvbiB0byB0aGUgc3RvcmVkIHJhbmdlXG4gKi9cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kJGNyZWF0ZUZyb21TdGF0ZShzdGF0ZSkge1xuICAgIHZhciBkb21VdGlscyA9IHN0YXRlLndpbmRvdy5taWxvLnV0aWwuZG9tO1xuXG4gICAgaWYgKHN0YXRlLnJvb3RFbCAmJiBzdGF0ZS5zdGFydCAmJiBzdGF0ZS5lbmQpIHtcbiAgICAgICAgdmFyIHN0YXJ0Tm9kZSA9IF9zZWxlY3Rpb25Ob2RlRnJvbVN0YXRlKHN0YXRlLnJvb3RFbCwgc3RhdGUuc3RhcnQpXG4gICAgICAgICAgICAsIGVuZE5vZGUgPSBfc2VsZWN0aW9uTm9kZUZyb21TdGF0ZShzdGF0ZS5yb290RWwsIHN0YXRlLmVuZCk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGRvbVV0aWxzLnNldFNlbGVjdGlvbihzdGFydE5vZGUsIHN0YXRlLnN0YXJ0Lm9mZnNldCwgZW5kTm9kZSwgc3RhdGUuZW5kLm9mZnNldCk7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFRleHRTZWxlY3Rpb24oc3RhdGUud2luZG93KTtcbiAgICAgICAgfSBjYXRjaChlKSB7XG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ1RleHQgc2VsZWN0aW9uOiBjYW5cXCd0IGNyZWF0ZSBzZWxlY3Rpb24nLCBlLCBlLm1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgZG9tVXRpbHMuY2xlYXJTZWxlY3Rpb24oc3RhdGUud2luZG93KTtcbiAgICAgICAgcmV0dXJuIG5ldyBUZXh0U2VsZWN0aW9uKHN0YXRlLndpbmRvdyk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIF9zZWxlY3Rpb25Ob2RlRnJvbVN0YXRlKHJvb3RFbCwgcG9pbnRTdGF0ZSkge1xuICAgIHZhciBub2RlID0gZG9tVXRpbHMuZ2V0Tm9kZUF0VHJlZVBhdGgocm9vdEVsLCBwb2ludFN0YXRlLnRyZWVQYXRoKTtcbiAgICBpZiAoISBub2RlKSBsb2dnZXIuZXJyb3IoJ1RleHRTZWxlY3Rpb24gY3JlYXRlRnJvbVN0YXRlOiBubyBub2RlIGF0IHRyZWVQYXRoJyk7XG4gICAgcmV0dXJuIG5vZGU7XG59XG5cblxuLyoqXG4gKiBDcmVhdGVzIHNlbGVjdGlvbiBmcm9tIHBhc3NlZCByYW5nZVxuICogXG4gKiBAcGFyYW0ge1JhbmdlfSByYW5nZVxuICogQHBhcmFtIHtCb29sZWFufSBiYWNrd2FyZFxuICpcbiAqIEByZXR1cm4ge1RleHRTZWxlY3Rpb259XG4gKi9cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kJGNyZWF0ZUZyb21SYW5nZShyYW5nZSwgYmFja3dhcmQpIHtcbiAgICB2YXIgd2luID0gcmFuZ2Uuc3RhcnRDb250YWluZXIub3duZXJEb2N1bWVudC5kZWZhdWx0Vmlld1xuICAgICAgICAsIHNlbCA9IHdpbi5nZXRTZWxlY3Rpb24oKVxuICAgICAgICAsIGVuZFJhbmdlO1xuXG4gICAgc2VsLnJlbW92ZUFsbFJhbmdlcygpO1xuXG4gICAgaWYgKGJhY2t3YXJkKXtcbiAgICAgICAgZW5kUmFuZ2UgPSByYW5nZS5jbG9uZVJhbmdlKCk7XG4gICAgICAgIGVuZFJhbmdlLmNvbGxhcHNlKGZhbHNlKTtcblxuICAgICAgICBzZWwuYWRkUmFuZ2UoZW5kUmFuZ2UpO1xuICAgICAgICBzZWwuZXh0ZW5kKHJhbmdlLnN0YXJ0Q29udGFpbmVyLCByYW5nZS5zdGFydE9mZnNldCkgICAgICAgIFxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgc2VsLmFkZFJhbmdlKHJhbmdlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IFRleHRTZWxlY3Rpb24od2luKTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgbm9ybWFsaXplZCBjb3B5IG9mIHRoZSByYW5nZVxuICogSWYgeW91IHRyaXBsZSBjbGljayBhbiBpdGVtLCB0aGUgZW5kIG9mIHRoZSByYW5nZSBpcyBwb3NpdGlvbmVkIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIE5FWFQgbm9kZS5cbiAqIHRoaXMgZnVuY3Rpb24gcmV0dXJucyBhIHJhbmdlIHdpdGggdGhlIGVuZCBwb3NpdGlvbmVkIGF0IHRoZSBlbmQgb2YgdGhlIGxhc3QgdGV4dG5vZGUgY29udGFpbmVkIFxuICogaW5zaWRlIGEgY29tcG9uZW50IHdpdGggdGhlIFwiZWRpdGFibGVcIiBmYWNldFxuICogXG4gKiBAcmV0dXJuIHtyYW5nZX1cbiAqL1xuZnVuY3Rpb24gVGV4dFNlbGVjdGlvbiQkZ2V0Tm9ybWFsaXplZFJhbmdlKCl7XG4gICAgdmFyIGRvYyA9IHRoaXMucmFuZ2UuY29tbW9uQW5jZXN0b3JDb250YWluZXIub3duZXJEb2N1bWVudFxuICAgICAgICAsIHR3LCBwcmV2aW91c05vZGVcbiAgICAgICAgLCBuZXdSYW5nZSA9IHRoaXMucmFuZ2UuY2xvbmVSYW5nZSgpO1xuXG4gICAgaWYgKG5ld1JhbmdlLmVuZENvbnRhaW5lci5ub2RlVHlwZSAhPT0gTm9kZS5URVhUX05PREUpIHtcbiAgICAgICAgdHcgPSBkb2MuY3JlYXRlVHJlZVdhbGtlcihkb2MuYm9keSwgTm9kZUZpbHRlci5TSE9XX1RFWFQpO1xuICAgICAgICB0dy5jdXJyZW50Tm9kZSA9IG5ld1JhbmdlLmVuZENvbnRhaW5lcjtcbiAgICAgICAgcHJldmlvdXNOb2RlID0gdHcucHJldmlvdXNOb2RlKCk7XG4gICAgICAgIG5ld1JhbmdlLnNldEVuZChwcmV2aW91c05vZGUsIHByZXZpb3VzTm9kZS5sZW5ndGgpO1xuICAgIH1cblxuICAgIHJldHVybiBuZXdSYW5nZTtcbn1cblxuLyoqXG4gKiBnZXQgdGhlIGRpcmVjdGlvbiBvZiBhIHNlbGVjdGlvblxuICpcbiAqIDEgZm9yd2FyZCwgLTEgYmFja3dhcmQsIDAgbm8gZGlyZWN0aW9uLCB1bmRlZmluZWQgb25lIG9mIHRoZSBub2RlIGlzIGRldGFjaGVkIG9yIGluIGEgZGlmZmVyZW50IGZyYW1lXG4gKlxuICogQHJldHVybiB7LTF8MHwxfHVuZGVmaW5lZH1cbiAqL1xuZnVuY3Rpb24gVGV4dFNlbGVjdGlvbiQkZ2V0RGlyZWN0aW9uKCl7XG4gICAgcmV0dXJuIGRvbVV0aWxzLmdldFNlbGVjdGlvbkRpcmVjdGlvbih0aGlzLnNlbGVjdGlvbik7ICAgIFxufVxuXG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIERPTVN0b3JhZ2VFcnJvciA9IHJlcXVpcmUoJy4uL2Vycm9yJykuY3JlYXRlQ2xhc3MoJ0RvbVN0b3JhZ2VFcnJvcicpXG4gICAgLCBNZXNzZW5nZXIgPSByZXF1aXJlKCcuLi8uLi9tZXNzZW5nZXInKVxuICAgICwgU3RvcmFnZU1lc3NhZ2VTb3VyY2UgPSByZXF1aXJlKCcuL21zZ19zcmMnKVxuICAgICwgY29uZmlnID0gcmVxdWlyZSgnLi4vLi4vY29uZmlnJylcbiAgICAsIGpzb25QYXJzZSA9IHJlcXVpcmUoJy4uL2pzb25fcGFyc2UnKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uL2NoZWNrJylcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2g7XG5cbnJlcXVpcmUoJy4vbW9kZWwnKVxuXG5tb2R1bGUuZXhwb3J0cyA9IERPTVN0b3JhZ2U7XG5cblxuLy8gc2hhcmVkIGtleXMgc3RvcmVkIGJ5IGFsbCBpbnN0YW5jZXMsIGluY2x1ZGUga2V5IHByZWZpeGVzXG52YXIgX3N0b3JlZEtleXMgPSB7XG4gICAgdHJ1ZToge30sIC8vIHNlc3Npb24gc3RvcmFnZVxuICAgIGZhbHNlOiB7fSAvLyBsb2NhbCBzdG9yYWdlXG59O1xuXG5cbi8qKlxuICogRE9NU3RvcmFnZSBjbGFzcyB0byBzaW1wbGlmeSBzdG9yYWdlIGFuZCByZXRyaWV2YWwgb2YgbXVsdGlwbGUgaXRlbXMgd2l0aCB0eXBlcyBwcmVzZXJ2YXRpb24gdG8gRE9NIHN0b3JhZ2UgKGxvY2FsU3RvcmFnZSBhbmQgc2Vzc2lvblN0b3JhZ2UpLlxuICogVHlwZXMgd2lsbCBiZSBzdG9yZWQgaW4gdGhlIGtleSBjcmVhdGVkIGZyb20gdmFsdWUga2V5cyB3aXRoIGFwcGVuZGVkIGBtaWxvLmNvbmZpZy5kb21TdG9yYWdlLnR5cGVTdWZmaXhgXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IGtleVByZWZpeCBwcmVmaXggdGhhdCB3aWxsIGJlIGFkZGVkIHRvIGFsbCBrZXlzIGZvbGxvd2VkIGJ5IGBtaWxvLmNvbmZpZy5kb21TdG9yYWdlLnByZWZpeFNlcGFyYXRvcmAgKFwiL1wiIGJ5IGRlZmF1bHQpLlxuICogQHBhcmFtIHtCb29sZWFufSBzZXNzaW9uT25seSB0cnVlIHRvIHVzZSBzZXNzaW9uU3RvcmFnZS4gbG9jYWxTdG9yYWdlIHdpbGwgYmUgdXNlZCBieSBkZWZhdWx0LlxuICogQHBhcmFtIHtXaW5kb3d9IHdpbiB3aW5kb3cgdG8gd29yayBpblxuICovXG5mdW5jdGlvbiBET01TdG9yYWdlKGtleVByZWZpeCwgc2Vzc2lvbk9ubHksIHdpbikge1xuICAgIGlmICh0eXBlb2Ygd2luZG93ID09ICd1bmRlZmluZWQnKSByZXR1cm47XG4gICAgd2luID0gd2luIHx8IHdpbmRvdztcblxuICAgIGtleVByZWZpeCA9IGNvbmZpZy5kb21TdG9yYWdlLnJvb3QgK1xuICAgICAgICAgICAgICAgIChrZXlQcmVmaXhcbiAgICAgICAgICAgICAgICAgICAgPyBrZXlQcmVmaXggKyBjb25maWcuZG9tU3RvcmFnZS5wcmVmaXhTZXBhcmF0b3JcbiAgICAgICAgICAgICAgICAgICAgOiAnJyk7XG5cbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICBrZXlQcmVmaXg6IGtleVByZWZpeCxcbiAgICAgICAgc2Vzc2lvbk9ubHk6ICEhIHNlc3Npb25Pbmx5LFxuICAgICAgICB3aW5kb3c6IHdpbixcbiAgICAgICAgX3N0b3JhZ2U6IHNlc3Npb25Pbmx5ID8gd2luLnNlc3Npb25TdG9yYWdlIDogd2luLmxvY2FsU3RvcmFnZSxcbiAgICAgICAgX3R5cGVTdWZmaXg6IGNvbmZpZy5kb21TdG9yYWdlLnR5cGVTdWZmaXgsXG4gICAgICAgIF9rZXlzOiB7fVxuICAgIH0sIF8uV1JJVCk7XG59XG5cblxuXy5leHRlbmRQcm90byhET01TdG9yYWdlLCB7XG4gICAgZ2V0OiBET01TdG9yYWdlJGdldCxcbiAgICBzZXQ6IERPTVN0b3JhZ2Ukc2V0LFxuICAgIHJlbW92ZTogRE9NU3RvcmFnZSRyZW1vdmUsXG4gICAgaGFzSXRlbTogRE9NU3RvcmFnZSRoYXNJdGVtLFxuICAgIGdldEl0ZW06IERPTVN0b3JhZ2UkZ2V0SXRlbSxcbiAgICBzZXRJdGVtOiBET01TdG9yYWdlJHNldEl0ZW0sXG4gICAgcmVtb3ZlSXRlbTogRE9NU3RvcmFnZSRyZW1vdmVJdGVtLFxuICAgIF9zdG9yYWdlS2V5OiBET01TdG9yYWdlJF9zdG9yYWdlS2V5LFxuICAgIF9kb21TdG9yYWdlS2V5OiBET01TdG9yYWdlJF9kb21TdG9yYWdlS2V5LFxuICAgIGdldEFsbEtleXM6IERPTVN0b3JhZ2UkZ2V0QWxsS2V5cyxcbiAgICBnZXRBbGxJdGVtczogRE9NU3RvcmFnZSRnZXRBbGxJdGVtcyxcbiAgICBjcmVhdGVNZXNzZW5nZXI6IERPTVN0b3JhZ2UkY3JlYXRlTWVzc2VuZ2VyLFxuICAgIGRlc3Ryb3k6IERPTVN0b3JhZ2UkZGVzdHJveVxufSk7XG5cblxuLyoqXG4gKiBFeHBvc2UgTWVzZW5nZXIgYW5kIE1lc3NhZ2VTb3VyY2UgbWV0aG9kcyBvbiBET01TdG9yYWdlXG4gKi9cbk1lc3Nlbmdlci51c2VXaXRoKERPTVN0b3JhZ2UsICdfbWVzc2VuZ2VyJywgTWVzc2VuZ2VyLmRlZmF1bHRNZXRob2RzKTtcblN0b3JhZ2VNZXNzYWdlU291cmNlLnVzZVdpdGgoRE9NU3RvcmFnZSwgJ19tZXNzYWdlU291cmNlJywgWyd0cmlnZ2VyJ10pO1xuXG5cbnZhciBfc2Vzc2lvblN0b3JhZ2UgPSBuZXcgRE9NU3RvcmFnZSgnJywgdHJ1ZSlcbiAgICAsIF9sb2NhbFN0b3JhZ2UgPSBuZXcgRE9NU3RvcmFnZSgnJywgZmFsc2UpO1xuXG52YXIgX2RvbVN0b3JhZ2UgPSB7XG4gICAgICAgIHRydWU6IF9zZXNzaW9uU3RvcmFnZSxcbiAgICAgICAgZmFsc2U6IF9sb2NhbFN0b3JhZ2VcbiAgICB9O1xuXG5fLmV4dGVuZChET01TdG9yYWdlLCB7XG4gICAgcmVnaXN0ZXJEYXRhVHlwZTogRE9NU3RvcmFnZSQkcmVnaXN0ZXJEYXRhVHlwZSxcbiAgICBsb2NhbDogX2xvY2FsU3RvcmFnZSxcbiAgICBzZXNzaW9uOiBfc2Vzc2lvblN0b3JhZ2UsXG4gICAgc3RvcmFnZTogX2RvbVN0b3JhZ2UsXG4gICAgX3N0b3JlZEtleXM6IF9zdG9yZWRLZXlzIC8vIGV4cG9zZWQgZm9yIHRlc3Rpbmdcbn0pO1xuXG5cbi8qKlxuICogU2V0cyBkYXRhIHRvIERPTSBzdG9yYWdlLiBgdGhpcy5rZXlQcmVmaXhgIGlzIHByZXBlbmRlZCB0byBrZXlzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIHNpbmdsZSBvYmplY3QgY2FuIGJlIHBhc3NlZCBpbiB3aGljaCBjYXNlIGtleXMgd2lsbCBiZSB1c2VkIGFzIGtleXMgaW4gbG9jYWwgc3RvcmFnZS5cbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIGFsdGVybmF0aXZlbHkganVzdCB0aGUgbGlzdCBvZiBhcmd1bWVudHMgY2FuIGJlIHBhc3NlZCB3aGVyZSBhcmd1bWVudHMgY2FuIGJlIHNlcXVlbnRpYWxseSB1c2VkIGFzIGtleXMgYW5kIHZhbHVlcy5cbiAqL1xuZnVuY3Rpb24gRE9NU3RvcmFnZSRzZXQoZGF0YSkgeyAvLyBvciBhcmd1bWVudHNcbiAgICBpZiAodHlwZW9mIGRhdGEgPT0gJ29iamVjdCcpXG4gICAgICAgIF8uZWFjaEtleShkYXRhLCBmdW5jdGlvbih2YWx1ZSwga2V5KSB7XG4gICAgICAgICAgICB0aGlzLnNldEl0ZW0oa2V5LCB2YWx1ZSk7XG4gICAgICAgIH0sIHRoaXMpO1xuICAgIGVsc2Uge1xuICAgICAgICB2YXIgYXJnc0xlbiA9IGFyZ3VtZW50cy5sZW5ndGg7XG4gICAgICAgIGlmIChhcmdzTGVuICUgMilcbiAgICAgICAgICAgIHRocm93IG5ldyBEb21TdG9yYWdlRXJyb3IoJ0RPTVN0b3JhZ2U6IHNldCBzaG91bGQgaGF2ZSBldmVuIG51bWJlciBvZiBhcmd1bWVudHMgb3Igb2JqZWN0Jyk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcmdzTGVuOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBrZXkgPSBhcmd1bWVudHNbaV1cbiAgICAgICAgICAgICAgICAsIHZhbHVlID0gYXJndW1lbnRzWysraV07XG5cbiAgICAgICAgICAgIHRoaXMuc2V0SXRlbShrZXksIHZhbHVlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuXG4vKipcbiAqIEdldHMgZGF0YSBmcm9tIERPTSBzdG9yYWdlLiBgdGhpcy5rZXlQcmVmaXhgIGlzIHByZXBlbmRlZCB0byBwYXNzZWQga2V5cywgYnV0IHJldHVybmVkIG9iamVjdCB3aWxsIGhhdmUga2V5cyB3aXRob3V0IHJvb3Qga2V5cy5cbiAqXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBrZXlzIGNhbiBiZSBwYXNzZWQgYXMgc3RyaW5ncyBvciBhcnJheXMgb2Ygc3RyaW5nc1xuICogQHJldHVybnMge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gRE9NU3RvcmFnZSRnZXQoKSB7IC8vICwgLi4uIGFyZ3VtZW50c1xuICAgIHZhciBkYXRhID0ge307XG4gICAgXy5kZWVwRm9yRWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uKGtleSkge1xuICAgICAgICBkYXRhW2tleV0gPSB0aGlzLmdldEl0ZW0oa2V5KTtcbiAgICB9LCB0aGlzKTtcbiAgICByZXR1cm4gZGF0YTtcbn1cblxuXG4vKipcbiAqIFJlbW92ZXMga2V5cyBmcm9tIERPTSBzdG9yYWdlLiBgdGhpcy5rZXlQcmVmaXhgIGlzIHByZXBlbmRlZCB0byBwYXNzZWQga2V5cy5cbiAqXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBrZXlzIGNhbiBiZSBwYXNzZWQgYXMgc3RyaW5ncyBvciBhcnJheXMgb2Ygc3RyaW5nc1xuICovXG5mdW5jdGlvbiBET01TdG9yYWdlJHJlbW92ZSgpIHsgLy8sIC4uLiBhcmd1bWVudHNcbiAgICBfLmRlZXBGb3JFYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24oa2V5KSB7XG4gICAgICAgIHRoaXMucmVtb3ZlSXRlbShrZXkpO1xuICAgIH0sIHRoaXMpO1xufVxuXG5cbi8qKlxuICogQ2hlY2sgZm9yIHByZXNlbmNlIG9mIHNpbmdsZSBpdGVtIGluIERPTSBzdG9yYWdlLiBgdGhpcy5rZXlQcmVmaXhgIGlzIHByZXBlbmRlZCB0byBwYXNzZWQga2V5LlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBrZXlcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIERPTVN0b3JhZ2UkaGFzSXRlbShrZXkpIHtcbiAgICB2YXIgcEtleSA9IHRoaXMuX3N0b3JhZ2VLZXkoa2V5KTtcbiAgICByZXR1cm4gdGhpcy5fc3RvcmFnZS5nZXRJdGVtKHBLZXkpICE9IG51bGw7XG59XG5cblxuLyoqXG4gKiBHZXRzIHNpbmdsZSBpdGVtIGZyb20gRE9NIHN0b3JhZ2UgcHJlcGVuZGluZyBgdGhpcy5rZXlQcmVmaXhgIHRvIHBhc3NlZCBrZXkuXG4gKiBSZWFkcyB0eXBlIG9mIHRoZSBvcmlnaW5hbGx5IHN0b3JlZCB2YWx1ZSBmcm9tIGBrZXkgKyB0aGlzLl90eXBlU3VmZml4YCBhbmQgY29udmVydHMgZGF0YSB0byB0aGUgb3JpZ2luYWwgdHlwZS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30ga2V5XG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmZ1bmN0aW9uIERPTVN0b3JhZ2UkZ2V0SXRlbShrZXkpIHtcbiAgICB2YXIgcEtleSA9IHRoaXMuX3N0b3JhZ2VLZXkoa2V5KTtcbiAgICB2YXIgZGF0YVR5cGUgPSBfZ2V0S2V5RGF0YVR5cGUuY2FsbCh0aGlzLCBwS2V5KTtcbiAgICB2YXIgdmFsdWVTdHIgPSB0aGlzLl9zdG9yYWdlLmdldEl0ZW0ocEtleSk7XG4gICAgdmFyIHZhbHVlID0gX3BhcnNlRGF0YSh2YWx1ZVN0ciwgZGF0YVR5cGUpO1xuICAgIHJldHVybiB2YWx1ZTtcbn1cblxuXG4vKipcbiAqIFNldHMgc2luZ2xlIGl0ZW0gdG8gRE9NIHN0b3JhZ2UgcHJlcGVuZGluZyBgdGhpcy5rZXlQcmVmaXhgIHRvIHBhc3NlZCBrZXkuXG4gKiBTdG9yZXMgdHlwZSBvZiB0aGUgc3RvcmVkIHZhbHVlIHRvIGBrZXkgKyB0aGlzLl90eXBlU3VmZml4YC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30ga2V5XG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmZ1bmN0aW9uIERPTVN0b3JhZ2Ukc2V0SXRlbShrZXksIHZhbHVlKSB7XG4gICAgdmFyIHBLZXkgPSB0aGlzLl9zdG9yYWdlS2V5KGtleSk7XG4gICAgdmFyIGRhdGFUeXBlID0gX3NldEtleURhdGFUeXBlLmNhbGwodGhpcywgcEtleSwgdmFsdWUpO1xuICAgIHZhciB2YWx1ZVN0ciA9IF9zZXJpYWxpemVEYXRhKHZhbHVlLCBkYXRhVHlwZSk7XG4gICAgdHJ5IHtcbiAgICAgICAgdGhpcy5fc3RvcmFnZS5zZXRJdGVtKHBLZXksIHZhbHVlU3RyKTtcbiAgICB9IGNhdGNoKGUpIHtcbiAgICAgICAgaWYgKGUubmFtZSA9PSAnUXVvdGFFeGNlZWRlZEVycm9yJykge1xuICAgICAgICAgICAgdmFyIGNmZyA9IGNvbmZpZy5kb21TdG9yYWdlLnF1b3RhRXhjZWVkZWQ7XG4gICAgICAgICAgICBpZiAoY2ZnLm1lc3NhZ2UpXG4gICAgICAgICAgICAgICAgbWlsby5tYWlsLnBvc3RNZXNzYWdlKCdxdW90YWV4Y2VlZGVkZXJyb3InLCB2YWx1ZSk7XG4gICAgICAgICAgICBpZiAoY2ZnLnRocm93RXJyb3IpXG4gICAgICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgfSBlbHNlXG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgIH1cbiAgICB0aGlzLl9rZXlzW2tleV0gPSB0cnVlO1xuICAgIF9kb21TdG9yYWdlW3RoaXMuc2Vzc2lvbk9ubHldLl9rZXlzW3BLZXldID0gdHJ1ZTtcbn1cblxuXG4vKipcbiAqIFJlbW92ZXMgc2luZ2xlIGl0ZW0gZnJvbSBET00gc3RvcmFnZSBwcmVwZW5kaW5nIGB0aGlzLmtleVByZWZpeGAgdG8gcGFzc2VkIGtleS5cbiAqIFR5cGUgb2YgdGhlIHN0b3JlZCB2YWx1ZSAoaW4gYGtleSArIHRoaXMuX3R5cGVTdWZmaXhgIGtleSkgaXMgYWxzbyByZW1vdmVkLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBrZXlcbiAqIEByZXR1cm4ge0FueX1cbiAqL1xuZnVuY3Rpb24gRE9NU3RvcmFnZSRyZW1vdmVJdGVtKGtleSkge1xuICAgIHZhciBwS2V5ID0gdGhpcy5fc3RvcmFnZUtleShrZXkpO1xuICAgIHRoaXMuX3N0b3JhZ2UucmVtb3ZlSXRlbShwS2V5KTtcbiAgICBfcmVtb3ZlS2V5RGF0YVR5cGUuY2FsbCh0aGlzLCBwS2V5KVxuICAgIGRlbGV0ZSB0aGlzLl9rZXlzW2tleV07XG4gICAgZGVsZXRlIF9kb21TdG9yYWdlW3RoaXMuc2Vzc2lvbk9ubHldLl9rZXlzW3BLZXldO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgYXJyYXkgb2YgYWxsIGtleXMgc3RvcmVkIGJ5IHRoaXMgaW5zdGFuY2Ugb2YgRE9NU3RvcmFnZVxuICpcbiAqIEByZXR1cm4ge0FycmF5fVxuICovXG5mdW5jdGlvbiBET01TdG9yYWdlJGdldEFsbEtleXMoKSB7XG4gICAgdmFyIHN0b3JlZEtleXMgPSBPYmplY3Qua2V5cyh0aGlzLl9rZXlzKTtcbiAgICB2YXIga2V5c0luU3RvcmFnZSA9IHN0b3JlZEtleXMuZmlsdGVyKGZ1bmN0aW9uKGtleSkge1xuICAgICAgICBpZiAodGhpcy5oYXNJdGVtKGtleSkpIHJldHVybiB0cnVlO1xuICAgICAgICBlbHNlIGRlbGV0ZSB0aGlzLl9rZXlzW2tleV07XG4gICAgfSwgdGhpcyk7XG4gICAgcmV0dXJuIGtleXNJblN0b3JhZ2U7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBtYXAgd2l0aCBhbGwga2V5cyBhbmQgdmFsdWVzIChkZXNlcmlhbGl6ZWQpIHN0b3JlZCB1c2luZyB0aGlzIGluc3RhbmNlIG9mIERPTVN0b3JhZ2VcbiAqXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIERPTVN0b3JhZ2UkZ2V0QWxsSXRlbXMoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0KHRoaXMuZ2V0QWxsS2V5cygpKTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgcHJlZml4ZWQga2V5IGZvciBET00gc3RvcmFnZSBmb3IgZ2l2ZW4gdW5wcmVmaXhlZCBrZXkuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IGtleVxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBET01TdG9yYWdlJF9zdG9yYWdlS2V5KGtleSkge1xuICAgIHJldHVybiB0aGlzLmtleVByZWZpeCArIGtleTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgdW5wcmVmaXhlZCBrZXkgdG8gYmUgdXNlZCB3aXRoIHRoaXMgaW5zdGFuY2Ugb2YgRE9NU3RvcmFnZSBmaXIgZ2l2ZW4gYWN0dWFsIGtleSBpbiBzdG9yYWdlXG4gKiBJZiBrZXkgaGFzIGRpZmZlcmVudCBwcmVmaXggZnJvbSB0aGUga2V5UHJlZml4IHJldHVybnMgdW5kZWZpbmVkXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHN0b3JhZ2VLZXkgYWN0dWFsIGtleSBpbiBsb2NhbC9zZXNzaW9uIHN0b3JhZ2VcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gRE9NU3RvcmFnZSRfZG9tU3RvcmFnZUtleShzdG9yYWdlS2V5KSB7XG4gICAgaWYgKHN0b3JhZ2VLZXkuaW5kZXhPZih0aGlzLl90eXBlU3VmZml4KSA+PSAwKSByZXR1cm47XG4gICAgcmV0dXJuIF8udW5QcmVmaXgoc3RvcmFnZUtleSwgdGhpcy5rZXlQcmVmaXgpO1xufVxuXG5cbi8qKlxuICogR2V0cyBvcmlnaW5hbGx5IHN0b3JlZCBkYXRhIHR5cGUgZm9yIGdpdmVuIChwcmVmaXhlZCkgYGtleWAuXG4gKlxuICogQHBhcmFtICB7U3RyaW5nfSBwS2V5IHByZWZpeGVkIGtleSBvZiBzdG9yZWQgdmFsdWVcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gX2dldEtleURhdGFUeXBlKHBLZXkpIHtcbiAgICBwS2V5ID0gX2RhdGFUeXBlS2V5LmNhbGwodGhpcywgcEtleSk7XG4gICAgcmV0dXJuIHRoaXMuX3N0b3JhZ2UuZ2V0SXRlbShwS2V5KTtcbn1cblxuXG4vKipcbiAqIFN0b3JlcyBkYXRhIHR5cGUgZm9yIGdpdmVuIChwcmVmaXhlZCkgYGtleWAgYW5kIGB2YWx1ZWAuXG4gKiBSZXR1cm5zIGRhdGEgdHlwZSBmb3IgYHZhbHVlYC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gcEtleSBwcmVmaXhlZCBrZXkgb2Ygc3RvcmVkIHZhbHVlXG4gKiBAcGFyYW0ge0FueX0gdmFsdWVcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gX3NldEtleURhdGFUeXBlKHBLZXksIHZhbHVlKSB7XG4gICAgdmFyIGRhdGFUeXBlID0gX2dldFZhbHVlVHlwZSh2YWx1ZSk7XG4gICAgcEtleSA9IF9kYXRhVHlwZUtleS5jYWxsKHRoaXMsIHBLZXkpO1xuICAgIHRoaXMuX3N0b3JhZ2Uuc2V0SXRlbShwS2V5LCBkYXRhVHlwZSk7XG4gICAgcmV0dXJuIGRhdGFUeXBlO1xufVxuXG5cbi8qKlxuICogUmVtb3ZlcyBzdG9yZWQgZGF0YSB0eXBlIGZvciBnaXZlbiAocHJlZml4ZWQpIGBrZXlgLlxuICpcbiAqIEBwYXJhbSAge1N0cmluZ30gcEtleSBwcmVmaXhlZCBrZXkgb2Ygc3RvcmVkIHZhbHVlXG4gKi9cbmZ1bmN0aW9uIF9yZW1vdmVLZXlEYXRhVHlwZShwS2V5KSB7XG4gICAgcEtleSA9IF9kYXRhVHlwZUtleS5jYWxsKHRoaXMsIHBLZXkpO1xuICAgIHRoaXMuX3N0b3JhZ2UucmVtb3ZlSXRlbShwS2V5KTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgdGhlIGtleSB0byBzdG9yZSBkYXRhIHR5cGUgZm9yIGdpdmVuIChwcmVmaXhlZCkgYGtleWAuXG4gKlxuICogQHBhcmFtICB7U3RyaW5nfSBwS2V5IHByZWZpeGVkIGtleSBvZiBzdG9yZWQgdmFsdWVcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gX2RhdGFUeXBlS2V5KHBLZXkpIHtcbiAgICByZXR1cm4gcEtleSArIHRoaXMuX3R5cGVTdWZmaXg7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIHR5cGUgb2YgdmFsdWUgYXMgc3RyaW5nLiBDbGFzcyBuYW1lIHJldHVybmVkIGZvciBvYmplY3RzICgnbnVsbCcgZm9yIG51bGwpLlxuICogQHBhcmFtICB7QW55fSB2YWx1ZVxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBfZ2V0VmFsdWVUeXBlKHZhbHVlKSB7XG4gICAgdmFyIHZhbHVlVHlwZSA9IHR5cGVvZiB2YWx1ZVxuICAgICAgICAsIGNsYXNzTmFtZSA9IHZhbHVlICYmIHZhbHVlLmNvbnN0cnVjdG9yLm5hbWVcbiAgICAgICAgLCBkYXRhVHlwZSA9IHZhbHVlc0RhdGFUeXBlc1tjbGFzc05hbWVdO1xuICAgIHJldHVybiBkYXRhVHlwZSB8fCAoXG4gICAgICAgICAgICB2YWx1ZVR5cGUgIT0gJ29iamVjdCdcbiAgICAgICAgICAgICAgICA/IHZhbHVlVHlwZVxuICAgICAgICAgICAgICAgIDogdmFsdWUgPT0gbnVsbFxuICAgICAgICAgICAgICAgICAgICA/ICdudWxsJ1xuICAgICAgICAgICAgICAgICAgICA6IHZhbHVlLmNvbnN0cnVjdG9yLm5hbWUpO1xufVxudmFyIHZhbHVlc0RhdGFUeXBlcyA9IHtcbiAgICAvLyBjYW4gYmUgcmVnaXN0ZXJlZCB3aXRoIGByZWdpc3RlckRhdGFUeXBlYFxufVxuXG5cbi8qKlxuICogU2VyaWFsaXplcyB2YWx1ZSB0byBiZSBzdG9yZWQgaW4gRE9NIHN0b3JhZ2UuXG4gKlxuICogQHBhcmFtICB7QW55fSB2YWx1ZSB2YWx1ZSB0byBiZSBzZXJpYWxpemVkXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHZhbHVlVHlwZSBvcHRpb25hbCBkYXRhIHR5cGUgdG8gZGVmaW5lIHNlcmlhbGl6ZXIsIF9nZXRWYWx1ZVR5cGUgaXMgdXNlZCBpZiBub3QgcGFzc2VkLlxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBfc2VyaWFsaXplRGF0YSh2YWx1ZSwgdmFsdWVUeXBlKSB7XG4gICAgdmFsdWVUeXBlID0gdmFsdWVUeXBlIHx8IF9nZXRWYWx1ZVR5cGUodmFsdWUpO1xuICAgIHZhciBzZXJpYWxpemVyID0gZGF0YVNlcmlhbGl6ZXJzW3ZhbHVlVHlwZV07XG4gICAgcmV0dXJuIHNlcmlhbGl6ZXJcbiAgICAgICAgICAgID8gc2VyaWFsaXplcih2YWx1ZSwgdmFsdWVUeXBlKVxuICAgICAgICAgICAgOiB2YWx1ZSAmJiB2YWx1ZS50b1N0cmluZyA9PSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nXG4gICAgICAgICAgICAgICAgPyBKU09OLnN0cmluZ2lmeSh2YWx1ZSlcbiAgICAgICAgICAgICAgICA6ICcnICsgdmFsdWU7XG59XG52YXIgZGF0YVNlcmlhbGl6ZXJzID0ge1xuICAgICdBcnJheSc6IEpTT04uc3RyaW5naWZ5XG59XG5cblxuLyoqXG4gKiBQYXJzZXMgc3RyaW5nIHJldHJpZXZlZCBmcm9tIERPTSBzdG9yYWdlLlxuICpcbiAqIEBwYXJhbSAge1N0cmluZ30gdmFsdWVTdHJcbiAqIEBwYXJhbSAge1N0cmluZ30gdmFsdWVUeXBlIGRhdGEgdHlwZSB0aGF0IGRlZmluZXMgcGFyc2VyLiBPcmlnaW5hbCBzcmluZyB3aWxsIGJlIHJldHVybmVkIGlmIHBhcnNlciBpcyBub3QgZGVmaW5lZC5cbiAqIEByZXR1cm4ge0FueX1cbiAqL1xuZnVuY3Rpb24gX3BhcnNlRGF0YSh2YWx1ZVN0ciwgdmFsdWVUeXBlKSB7XG4gICAgdmFyIHBhcnNlciA9IGRhdGFQYXJzZXJzW3ZhbHVlVHlwZV07XG4gICAgcmV0dXJuIHBhcnNlclxuICAgICAgICAgICAgPyBwYXJzZXIodmFsdWVTdHIsIHZhbHVlVHlwZSlcbiAgICAgICAgICAgIDogdmFsdWVTdHI7XG59XG52YXIgZGF0YVBhcnNlcnMgPSB7XG4gICAgT2JqZWN0OiBqc29uUGFyc2UsXG4gICAgQXJyYXk6IGpzb25QYXJzZSxcbiAgICBEYXRlOiBmdW5jdGlvbih2YWxTdHIpIHsgcmV0dXJuIG5ldyBEYXRlKHZhbFN0cik7IH0sXG4gICAgYm9vbGVhbjogZnVuY3Rpb24odmFsU3RyKSB7IHJldHVybiB2YWxTdHIgPT0gJ3RydWUnOyB9LFxuICAgIG51bWJlcjogZnVuY3Rpb24odmFsU3RyKSB7IHJldHVybiBOdW1iZXIodmFsU3RyKTsgfSxcbiAgICBmdW5jdGlvbjogZnVuY3Rpb24odmFsU3RyKSB7IHJldHVybiBfLnRvRnVuY3Rpb24odmFsU3RyKTsgfSxcbiAgICBSZWdFeHA6IGZ1bmN0aW9uKHZhbFN0cikgeyByZXR1cm4gXy50b1JlZ0V4cCh2YWxTdHIpOyB9XG59O1xuXG5cbi8qKlxuICogUmVnaXN0ZXJzIGRhdGEgdHlwZSB0byBiZSBzYXZlZCBpbiBET00gc3RvcmFnZS4gQ2xhc3MgbmFtZSBjYW4gYmUgdXNlZCBvciByZXN1bHQgb2YgYHR5cGVvZmAgb3BlcmF0b3IgZm9yIG5vbi1vYmplY3RzIHRvIG92ZXJyaWRlIGRlZmF1bHQgY29udmVyc2lvbnMuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHZhbHVlVHlwZSBjbGFzcyAoY29uc3RydWN0b3IpIG5hbWUgb3IgdGhlIHN0cmluZyByZXR1cm5lZCBieSB0eXBlb2YuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzZXJpYWxpemVyIG9wdGlvbmFsIHNlcmlhbGl6ZXIgZm9yIHRoaXMgdHlwZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gcGFyc2VyIG9wdGlvbmFsIHBhcnNlciBmb3IgdGhpcyB0eXBlXG4gKiBAcGFyYW0ge1tTdHJpbmddfSBzdG9yZUFzRGF0YVR5cGUgb3B0aW9uYWwgbmFtZSBvZiBzdG9yZWQgZGF0YSB0eXBlIGlmIGRpZmZlcmVudCBmcm9tIHZhbHVlVHlwZVxuICovXG5mdW5jdGlvbiBET01TdG9yYWdlJCRyZWdpc3RlckRhdGFUeXBlKHZhbHVlVHlwZSwgc2VyaWFsaXplciwgcGFyc2VyLCBzdG9yZUFzRGF0YVR5cGUpIHtcbiAgICBpZiAoc2VyaWFsaXplcikgZGF0YVNlcmlhbGl6ZXJzW3ZhbHVlVHlwZV0gPSBzZXJpYWxpemVyO1xuICAgIGlmIChwYXJzZXIpIGRhdGFQYXJzZXJzW3ZhbHVlVHlwZV0gPSBwYXJzZXI7XG4gICAgdmFsdWVzRGF0YVR5cGVzW3ZhbHVlVHlwZV0gPSBzdG9yZUFzRGF0YVR5cGUgfHwgdmFsdWVUeXBlO1xufVxuXG5cbmZ1bmN0aW9uIERPTVN0b3JhZ2UkY3JlYXRlTWVzc2VuZ2VyKCkge1xuICAgIHZhciBzdG9yYWdlTWVzc2FnZVNvdXJjZSA9IG5ldyBTdG9yYWdlTWVzc2FnZVNvdXJjZSh0aGlzKTtcbiAgICB2YXIgbWVzc2VuZ2VyID0gbmV3IE1lc3Nlbmdlcih0aGlzLCB1bmRlZmluZWQsIHN0b3JhZ2VNZXNzYWdlU291cmNlKTtcbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICBfbWVzc2VuZ2VyOiBtZXNzZW5nZXIsXG4gICAgICAgIF9tZXNzYWdlU291cmNlOiBzdG9yYWdlTWVzc2FnZVNvdXJjZVxuICAgIH0sIF8uV1JJVCk7XG59XG5cblxuZnVuY3Rpb24gRE9NU3RvcmFnZSRkZXN0cm95KCkge1xuICAgIHRoaXMuX3N0b3JhZ2UgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy53aW5kb3cgPSB1bmRlZmluZWQ7XG4gICAgaWYgKHRoaXMuX21lc3NlbmdlcikgdGhpcy5fbWVzc2VuZ2VyLmRlc3Ryb3koKTtcbiAgICB0aGlzLl9kZXN0cm95ZWQgPSB0cnVlO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgTW9kZWwgPSByZXF1aXJlKCdtaWxvLWNvcmUnKS5Nb2RlbFxuXG5Nb2RlbC5yZWdpc3RlcldpdGhET01TdG9yYWdlID0gTW9kZWwkJHJlZ2lzdGVyV2l0aERPTVN0b3JhZ2U7XG5cblxuZnVuY3Rpb24gTW9kZWwkJHJlZ2lzdGVyV2l0aERPTVN0b3JhZ2UoKSB7XG4gICAgdmFyIERPTVN0b3JhZ2UgPSByZXF1aXJlKCcuL2luZGV4Jyk7XG4gICAgRE9NU3RvcmFnZS5yZWdpc3RlckRhdGFUeXBlKCdNb2RlbCcsIE1vZGVsX2RvbVN0b3JhZ2VTZXJpYWxpemVyLCBNb2RlbF9kb21TdG9yYWdlUGFyc2VyKTtcbiAgICBET01TdG9yYWdlLnJlZ2lzdGVyRGF0YVR5cGUoJ01vZGVsUGF0aCcsIE1vZGVsX2RvbVN0b3JhZ2VTZXJpYWxpemVyLCBNb2RlbF9kb21TdG9yYWdlUGFyc2VyLCAnTW9kZWwnKTtcbn1cblxuXG5mdW5jdGlvbiBNb2RlbF9kb21TdG9yYWdlU2VyaWFsaXplcih2YWx1ZSkge1xuICAgIHZhciBkYXRhID0gdmFsdWUuZ2V0KCk7XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGRhdGEpO1xufVxuXG5cbmZ1bmN0aW9uIE1vZGVsX2RvbVN0b3JhZ2VQYXJzZXIodmFsdWVTdHIpIHtcbiAgICB2YXIgZGF0YSA9IF8uanNvblBhcnNlKHZhbHVlU3RyKTtcbiAgICByZXR1cm4gbmV3IE1vZGVsKGRhdGEpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi4vLi4vbWVzc2VuZ2VyL21fc291cmNlJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgY29uZmlnID0gcmVxdWlyZSgnLi4vLi4vY29uZmlnJylcbiAgICAsIG1pbG9Db3VudCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvY291bnQnKVxuICAgICwgU3RvcmFnZU1lc3NhZ2VTb3VyY2VFcnJvciA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvZXJyb3InKS5TdG9yYWdlTWVzc2FnZVNvdXJjZTtcblxudmFyIFN0b3JhZ2VNZXNzYWdlU291cmNlID0gXy5jcmVhdGVTdWJjbGFzcyhNZXNzYWdlU291cmNlLCAnU3RvcmFnZU1lc3NhZ2VTb3VyY2UnLCB0cnVlKTtcblxuXG5fLmV4dGVuZFByb3RvKFN0b3JhZ2VNZXNzYWdlU291cmNlLCB7XG4gICAgLy8gaW1wbGVtZW50aW5nIE1lc3NhZ2VTb3VyY2UgaW50ZXJmYWNlXG4gICAgaW5pdDogaW5pdCxcbiAgICBhZGRTb3VyY2VTdWJzY3JpYmVyOiBTdG9yYWdlTWVzc2FnZVNvdXJjZSRhZGRTb3VyY2VTdWJzY3JpYmVyLFxuICAgIHJlbW92ZVNvdXJjZVN1YnNjcmliZXI6IFN0b3JhZ2VNZXNzYWdlU291cmNlJHJlbW92ZVNvdXJjZVN1YnNjcmliZXIsXG4gICAgcG9zdE1lc3NhZ2U6IFN0b3JhZ2VNZXNzYWdlU291cmNlJHBvc3RNZXNzYWdlLFxuICAgIHRyaWdnZXI6IFN0b3JhZ2VNZXNzYWdlU291cmNlJHRyaWdnZXIsXG5cbiAgICAvL2NsYXNzIHNwZWNpZmljIG1ldGhvZHNcbiAgICBoYW5kbGVFdmVudDogaGFuZGxlRXZlbnQgIC8vIGV2ZW50IGRpc3BhdGNoZXIgLSBhcyBkZWZpbmVkIGJ5IEV2ZW50IERPTSBBUElcbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0b3JhZ2VNZXNzYWdlU291cmNlO1xuXG5cbmZ1bmN0aW9uIGluaXQoaG9zdE9iamVjdCwgcHJveHlNZXRob2RzLCBtZXNzZW5nZXJBUElPckNsYXNzKSB7XG4gICAgaWYgKGhvc3RPYmplY3QuY29uc3RydWN0b3IubmFtZSAhPSAnRE9NU3RvcmFnZScpXG4gICAgICAgIHRocm93IG5ldyBTdG9yYWdlTWVzc2FnZVNvdXJjZUVycm9yKCdob3N0T2JqZWN0IHNob3VsZCBiZSBhbiBpbnN0YW5jZSBvZiBET01TdG9yYWdlJyk7XG4gICAgdGhpcy5zdG9yYWdlID0gaG9zdE9iamVjdDtcbiAgICB0aGlzLm1lc3NhZ2VLZXkgPSBjb25maWcuZG9tU3RvcmFnZS5tZXNzYWdlS2V5O1xuICAgIHRoaXMud2luZG93ID0gaG9zdE9iamVjdC53aW5kb3c7XG4gICAgTWVzc2FnZVNvdXJjZS5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbmZ1bmN0aW9uIFN0b3JhZ2VNZXNzYWdlU291cmNlJGFkZFNvdXJjZVN1YnNjcmliZXIoc291cmNlTWVzc2FnZSkge1xuICAgIHRoaXMud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3N0b3JhZ2UnLCB0aGlzLCBmYWxzZSk7XG59XG5cblxuZnVuY3Rpb24gU3RvcmFnZU1lc3NhZ2VTb3VyY2UkcmVtb3ZlU291cmNlU3Vic2NyaWJlcihzb3VyY2VNZXNzYWdlKSB7XG4gICAgdGhpcy53aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignc3RvcmFnZScsIHRoaXMsIGZhbHNlKTtcbn1cblxuXG5mdW5jdGlvbiBTdG9yYWdlTWVzc2FnZVNvdXJjZSRwb3N0TWVzc2FnZShtZXNzYWdlLCBkYXRhKSB7XG4gICAgdGhpcy5tZXNzZW5nZXIucG9zdE1lc3NhZ2VTeW5jKG1lc3NhZ2UsIGRhdGEpO1xufVxuXG5cbmZ1bmN0aW9uIFN0b3JhZ2VNZXNzYWdlU291cmNlJHRyaWdnZXIobXNnVHlwZSwgZGF0YSkge1xuICAgIHZhciBrZXkgPSB0aGlzLm1lc3NhZ2VLZXkgKyBtc2dUeXBlO1xuICAgIGRhdGEgPSBkYXRhIHx8IHt9O1xuICAgIGRhdGFbY29uZmlnLmRvbVN0b3JhZ2UubWVzc2FnZVRpbWVzdGFtcF0gPSBtaWxvQ291bnQoKTtcbiAgICBfLmRlZmVyTWV0aG9kKHRoaXMuc3RvcmFnZSwgJ3NldEl0ZW0nLCBrZXksIGRhdGEpO1xufVxuXG5cbmZ1bmN0aW9uIGhhbmRsZUV2ZW50KGV2ZW50KSB7XG4gICAgaWYgKGV2ZW50LnN0b3JhZ2VBcmVhICE9IHRoaXMuc3RvcmFnZS5fc3RvcmFnZSkgcmV0dXJuO1xuICAgIHZhciBrZXkgPSB0aGlzLnN0b3JhZ2UuX2RvbVN0b3JhZ2VLZXkoZXZlbnQua2V5KTsgaWYgKCEga2V5KSByZXR1cm47XG4gICAgdmFyIG1zZ1R5cGUgPSBfLnVuUHJlZml4KGtleSwgdGhpcy5tZXNzYWdlS2V5KTsgaWYgKCEgbXNnVHlwZSkgcmV0dXJuO1xuICAgIHZhciBkYXRhID0gdGhpcy5zdG9yYWdlLmdldEl0ZW0oa2V5KTsgaWYgKCEgZGF0YSkgcmV0dXJuO1xuICAgIHRoaXMuZGlzcGF0Y2hNZXNzYWdlKG1zZ1R5cGUsIGRhdGEpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIGBtaWxvLnV0aWwud2Vic29ja2V0YCBcbioqL1xuXG5cbnZhciBNZXNzZW5nZXIgPSByZXF1aXJlKCcuLi8uLi9tZXNzZW5nZXInKVxuICAgICwgV1NNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi9tc2dfc3JjJylcbiAgICAsIFdTTXNnQVBJID0gcmVxdWlyZSgnLi9tc2dfYXBpJyk7XG5cblxuZnVuY3Rpb24gd2Vic29ja2V0KCkge1xuICAgIHZhciB3c01lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXI7XG4gICAgdmFyIHdzTXNnU291cmNlID0gbmV3IFdTTWVzc2FnZVNvdXJjZSh3c01lc3NlbmdlciwgeyBzZW5kOiAndHJpZ2dlcicsIGNvbm5lY3Q6ICdjb25uZWN0JyB9LCBuZXcgV1NNc2dBUEkpO1xuICAgIHdzTWVzc2VuZ2VyLl9zZXRNZXNzYWdlU291cmNlKHdzTXNnU291cmNlKTtcbiAgICByZXR1cm4gd3NNZXNzZW5nZXI7XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSB3ZWJzb2NrZXQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBNZXNzZW5nZXJBUEkgPSByZXF1aXJlKCcuLi8uLi9tZXNzZW5nZXIvbV9hcGknKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaDtcblxuXG52YXIgV1NNc2dBUEkgPSBfLmNyZWF0ZVN1YmNsYXNzKE1lc3NlbmdlckFQSSwgJ1dTTXNnQVBJJywgdHJ1ZSk7XG5cblxuXy5leHRlbmRQcm90byhXU01zZ0FQSSwge1xuICAgIHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZTogdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlLFxuICAgIGZpbHRlclNvdXJjZU1lc3NhZ2U6IGZpbHRlclNvdXJjZU1lc3NhZ2UsXG4gICAgY3JlYXRlSW50ZXJuYWxEYXRhOiBjcmVhdGVJbnRlcm5hbERhdGFcbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFdTTXNnQVBJO1xuXG5cbnZhciBTT0NLRVRfTUVTU0FHRVMgPSBbJ29wZW4nLCAnY2xvc2UnLCAnZXJyb3InLCAnbWVzc2FnZSddO1xuXG5mdW5jdGlvbiB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UobWVzc2FnZSkge1xuICAgIHJldHVybiBTT0NLRVRfTUVTU0FHRVMuaW5kZXhPZihtZXNzYWdlKSA+PSAwXG4gICAgICAgICAgICA/IG1lc3NhZ2VcbiAgICAgICAgICAgIDogJ21lc3NhZ2UnO1xufVxuXG5cbmZ1bmN0aW9uIGZpbHRlclNvdXJjZU1lc3NhZ2Uoc291cmNlTWVzc2FnZSwgbWVzc2FnZSwgbXNnRGF0YSkge1xuICAgIGlmIChTT0NLRVRfTUVTU0FHRVMuaW5kZXhPZihtZXNzYWdlKSA+PSAwKSByZXR1cm4gdHJ1ZTsgLy8gaW50ZXJuYWwgbWVzc2FnZSBpcyBvbmUgb2YgZXh0ZXJuYWwgbWVzc2FnZXNcbiAgICBpZiAoc291cmNlTWVzc2FnZSA9PSAnbWVzc2FnZScpIHtcbiAgICAgICAgdmFyIG1zZ1R5cGUgPSBtc2dEYXRhICYmIG1zZ0RhdGEudHlwZTtcbiAgICAgICAgcmV0dXJuIG1zZ1R5cGUgPT0gbWVzc2FnZTsgLy8gdHlwZSBlcXVhbHMgaW50ZXJuYWwgbWVzc2FnZVxuICAgIH1cbn07XG5cblxuZnVuY3Rpb24gY3JlYXRlSW50ZXJuYWxEYXRhKHNvdXJjZU1lc3NhZ2UsIG1lc3NhZ2UsIGV2ZW50KSB7XG4gICAgdmFyIGludGVybmFsRGF0YSA9IHNvdXJjZU1lc3NhZ2UgPT0gJ21lc3NhZ2UnXG4gICAgICAgICAgICAgICAgICAgICAgICA/IF8uanNvblBhcnNlKGV2ZW50LmRhdGEpIHx8IGV2ZW50LmRhdGFcbiAgICAgICAgICAgICAgICAgICAgICAgIDogZXZlbnQ7XG4gICAgcmV0dXJuIGludGVybmFsRGF0YTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgTWVzc2FnZVNvdXJjZSA9IHJlcXVpcmUoJy4uLy4uL21lc3Nlbmdlci9tX3NvdXJjZScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvbG9nZ2VyJylcbiAgICAsIHVuaXF1ZUlkID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9jb3VudCcpXG4gICAgLCBjb25maWcgPSByZXF1aXJlKCcuLi8uLi9jb25maWcnKVxuICAgICwgY2hlY2sgPSByZXF1aXJlKCcuLi8uLi91dGlsL2NoZWNrJylcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2g7XG5cblxudmFyIFdTTWVzc2FnZVNvdXJjZSA9IF8uY3JlYXRlU3ViY2xhc3MoTWVzc2FnZVNvdXJjZSwgJ1dTTWVzc2FnZVNvdXJjZScsIHRydWUpO1xuXG5cbl8uZXh0ZW5kUHJvdG8oV1NNZXNzYWdlU291cmNlLCB7XG4gICAgLy8gaW1wbGVtZW50aW5nIE1lc3NhZ2VTb3VyY2UgaW50ZXJmYWNlXG4gICAgYWRkU291cmNlU3Vic2NyaWJlcjogYWRkU291cmNlU3Vic2NyaWJlcixcbiAgICByZW1vdmVTb3VyY2VTdWJzY3JpYmVyOiByZW1vdmVTb3VyY2VTdWJzY3JpYmVyLFxuICAgIFxuICAgIC8vIGNsYXNzIHNwZWNpZmljIG1ldGhvZHNcbiAgICBoYW5kbGVFdmVudDogV1NNZXNzYWdlU291cmNlJGhhbmRsZUV2ZW50LFxuICAgIGNvbm5lY3Q6IFdTTWVzc2FnZVNvdXJjZSRjb25uZWN0LFxuICAgIHRyaWdnZXI6IFdTTWVzc2FnZVNvdXJjZSR0cmlnZ2VyXG59KTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IFdTTWVzc2FnZVNvdXJjZTtcblxuXG5mdW5jdGlvbiBXU01lc3NhZ2VTb3VyY2UkY29ubmVjdChvcHRpb25zKSB7XG4gICAgdGhpcy5fb3B0aW9ucyA9IG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgdmFyIGhvc3QgPSBvcHRpb25zLmhvc3QgfHwgd2luZG93LmxvY2F0aW9uLmhvc3QucmVwbGFjZSgvOi4qLywgJycpXG4gICAgICAgICwgcG9ydCA9IG9wdGlvbnMucG9ydCB8fCAnODA4MCc7XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICBpZiAodGhpcy5fd3MpIHtcbiAgICAgICAgLy8gVE9ETyBzaG91bGQgdW5zdWJzY3JpYmUgZGlmZmVyZW50bHlcbiAgICAgICAgdGhpcy5fd3Mub25vcGVuID0gdGhpcy53cy5vbm1lc3NhZ2UgPSB0aGlzLndzLm9uY2xvc2UgPSB0aGlzLndzLm9uZXJyb3IgPSB1bmRlZmluZWQ7XG4gICAgICAgIHRoaXMuX3dzLmNsb3NlKCk7XG4gICAgfVxuXG4gICAgdGhpcy5fd3MgPSBuZXcgV2ViU29ja2V0KCd3czovLycgKyBob3N0ICsgJzonICsgcG9ydCk7XG5cbiAgICAvLyBUT0RPIHJlY29ubmVjdFxufVxuXG5cblxuZnVuY3Rpb24gYWRkU291cmNlU3Vic2NyaWJlciAoc291cmNlTWVzc2FnZSkge1xuICAgIF93c1N1YnNjcmliZXJNZXRob2QuY2FsbCh0aGlzLCAnYWRkRXZlbnRMaXN0ZW5lcicsIHNvdXJjZU1lc3NhZ2UpO1xufVxuXG5cbmZ1bmN0aW9uIHJlbW92ZVNvdXJjZVN1YnNjcmliZXIgKHNvdXJjZU1lc3NhZ2UpIHtcbiAgICBfd3NTdWJzY3JpYmVyTWV0aG9kLmNhbGwodGhpcywgJ3JlbW92ZUV2ZW50TGlzdGVuZXInLCBzb3VyY2VNZXNzYWdlKTtcbn1cblxuXG5mdW5jdGlvbiBfd3NTdWJzY3JpYmVyTWV0aG9kIChtZXRob2QsIHNvdXJjZU1lc3NhZ2UpIHsgICAgXG4gICAgaWYgKCF0aGlzLl93cykgcmV0dXJuIGxvZ2dlci5lcnJvcignd2Vic29ja2V0IGlzIG5vdCBjcmVhdGVkJyk7XG4gICAgdGhpcy5fd3NbbWV0aG9kXShzb3VyY2VNZXNzYWdlLCB0aGlzKTtcbn1cblxuXG4vLyBldmVudCBkaXNwYXRjaGVyIC0gYXMgZGVmaW5lZCBieSBFdmVudCBET00gQVBJXG5mdW5jdGlvbiBXU01lc3NhZ2VTb3VyY2UkaGFuZGxlRXZlbnQgKGV2ZW50KSB7XG4gICAgdGhpcy5kaXNwYXRjaE1lc3NhZ2UoZXZlbnQudHlwZSwgZXZlbnQpO1xufVxuXG5cbmZ1bmN0aW9uIFdTTWVzc2FnZVNvdXJjZSR0cmlnZ2VyIChtc2csIGRhdGEsIGNhbGxiYWNrKSB7XG4gICAgaWYgKCF0aGlzLl93cykgcmV0dXJuIGxvZ2dlci5lcnJvcignd2Vic29ja2V0IGlzIG5vdCBjcmVhdGVkJyk7XG5cbiAgICBkYXRhID0gZGF0YSB8fCB7fTtcbiAgICBkYXRhLnR5cGUgPSBtc2c7XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgXG4gICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgIGRhdGEuY2FsbGJhY2tDb3JySWQgPSB1bmlxdWVJZCgpO1xuICAgICAgICB2YXIgaW50ZXJ2YWwgPSBfLmRlbGF5KG9uVGltZW91dCwgY29uZmlnLndlYnNvY2tldC5ycGMudGltZW91dCk7XG4gICAgICAgIHRvZ2dsZVJwY1N1YnNjcmlwdGlvbignb25jZScsIGRhdGEuY2FsbGJhY2tDb3JySWQpO1xuICAgIH0gICAgXG5cbiAgICB0aGlzLl93cy5zZW5kKEpTT04uc3RyaW5naWZ5KGRhdGEpKTtcblxuXG4gICAgZnVuY3Rpb24gb25UaW1lb3V0KCkge1xuICAgICAgICB0b2dnbGVScGNTdWJzY3JpcHRpb24oJ29mZicsIGRhdGEuY2FsbGJhY2tDb3JySWQpO1xuICAgICAgICBjYWxsYmFjayhuZXcgRXJyb3IoJ3dlYnNvY2tldCBycGM6IHRpbWVvdXQnKSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gb25SZXNwb25zZShtc2csIG1zZ0RhdGEpIHtcbiAgICAgICAgY2xlYXJJbnRlcnZhbChpbnRlcnZhbCk7XG4gICAgICAgIGlmICh0eXBlb2YgbXNnRGF0YSA9PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgdmFyIGVyciA9IG1zZ0RhdGEuZXJyb3IgPyBuZXcgRXJyb3IobXNnRGF0YS5lcnJvcikgOiBudWxsO1xuICAgICAgICAgICAgY2FsbGJhY2soZXJyLCBtc2dEYXRhLmRhdGEpXG4gICAgICAgIH0gZWxzZVxuICAgICAgICAgICAgY2FsbGJhY2sobmV3IEVycm9yKCd3ZWJzb2NrZXQgcnBjOiBpbnZhbGlkIHJlc3BvbnNlIGRhdGEnKSwgbXNnRGF0YSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdG9nZ2xlUnBjU3Vic2NyaXB0aW9uKG9uT2ZmLCBjb3JySWQpIHtcbiAgICAgICAgc2VsZi5tZXNzZW5nZXJbb25PZmZdKGNvbmZpZy53ZWJzb2NrZXQucnBjLnJlc3BvbnNlUHJlZml4ICsgY29ycklkLCBvblJlc3BvbnNlKTtcbiAgICB9XG59XG4iLCI7KGZ1bmN0aW9uKCl7XG5cbi8vIFRoaXMgd291bGQgYmUgdGhlIHBsYWNlIHRvIGVkaXQgaWYgeW91IHdhbnQgYSBkaWZmZXJlbnRcbi8vIEJhc2UzMiBpbXBsZW1lbnRhdGlvblxuXG52YXIgYWxwaGFiZXQgPSAnMDEyMzQ1Njc4OWFiY2RlZmdoamttbnBxcnR1dnd4eXonXG52YXIgYWxpYXMgPSB7IG86MCwgaToxLCBsOjEsIHM6NSB9XG5cbi8qKlxuICogQnVpbGQgYSBsb29rdXAgdGFibGUgYW5kIG1lbW9pemUgaXRcbiAqXG4gKiBSZXR1cm4gYW4gb2JqZWN0IHRoYXQgbWFwcyBhIGNoYXJhY3RlciB0byBpdHNcbiAqIGJ5dGUgdmFsdWUuXG4gKi9cblxudmFyIGxvb2t1cCA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciB0YWJsZSA9IHt9XG4gICAgLy8gSW52ZXJ0ICdhbHBoYWJldCdcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFscGhhYmV0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRhYmxlW2FscGhhYmV0W2ldXSA9IGlcbiAgICB9XG4gICAgLy8gU3BsaWNlIGluICdhbGlhcydcbiAgICBmb3IgKHZhciBrZXkgaW4gYWxpYXMpIHtcbiAgICAgICAgaWYgKCFhbGlhcy5oYXNPd25Qcm9wZXJ0eShrZXkpKSBjb250aW51ZVxuICAgICAgICB0YWJsZVtrZXldID0gdGFibGVbJycgKyBhbGlhc1trZXldXVxuICAgIH1cbiAgICBsb29rdXAgPSBmdW5jdGlvbigpIHsgcmV0dXJuIHRhYmxlIH1cbiAgICByZXR1cm4gdGFibGVcbn1cblxuLyoqXG4gKiBBIHN0cmVhbWluZyBlbmNvZGVyXG4gKlxuICogICAgIHZhciBlbmNvZGVyID0gbmV3IGJhc2UzMi5FbmNvZGVyKClcbiAqICAgICB2YXIgb3V0cHV0MSA9IGVuY29kZXIudXBkYXRlKGlucHV0MSlcbiAqICAgICB2YXIgb3V0cHV0MiA9IGVuY29kZXIudXBkYXRlKGlucHV0MilcbiAqICAgICB2YXIgbGFzdG91dHB1dCA9IGVuY29kZS51cGRhdGUobGFzdGlucHV0LCB0cnVlKVxuICovXG5cbmZ1bmN0aW9uIEVuY29kZXIoKSB7XG4gICAgdmFyIHNraXAgPSAwIC8vIGhvdyBtYW55IGJpdHMgd2Ugd2lsbCBza2lwIGZyb20gdGhlIGZpcnN0IGJ5dGVcbiAgICB2YXIgYml0cyA9IDAgLy8gNSBoaWdoIGJpdHMsIGNhcnJ5IGZyb20gb25lIGJ5dGUgdG8gdGhlIG5leHRcblxuICAgIHRoaXMub3V0cHV0ID0gJydcblxuICAgIC8vIFJlYWQgb25lIGJ5dGUgb2YgaW5wdXRcbiAgICAvLyBTaG91bGQgbm90IHJlYWxseSBiZSB1c2VkIGV4Y2VwdCBieSBcInVwZGF0ZVwiXG4gICAgdGhpcy5yZWFkQnl0ZSA9IGZ1bmN0aW9uKGJ5dGUpIHtcbiAgICAgICAgLy8gY29lcmNlIHRoZSBieXRlIHRvIGFuIGludFxuICAgICAgICBpZiAodHlwZW9mIGJ5dGUgPT0gJ3N0cmluZycpIGJ5dGUgPSBieXRlLmNoYXJDb2RlQXQoMClcblxuICAgICAgICBpZiAoc2tpcCA8IDApIHsgLy8gd2UgaGF2ZSBhIGNhcnJ5IGZyb20gdGhlIHByZXZpb3VzIGJ5dGVcbiAgICAgICAgICAgIGJpdHMgfD0gKGJ5dGUgPj4gKC1za2lwKSlcbiAgICAgICAgfSBlbHNlIHsgLy8gbm8gY2FycnlcbiAgICAgICAgICAgIGJpdHMgPSAoYnl0ZSA8PCBza2lwKSAmIDI0OFxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHNraXAgPiAzKSB7XG4gICAgICAgICAgICAvLyBub3QgZW5vdWdoIGRhdGEgdG8gcHJvZHVjZSBhIGNoYXJhY3RlciwgZ2V0IHVzIGFub3RoZXIgb25lXG4gICAgICAgICAgICBza2lwIC09IDhcbiAgICAgICAgICAgIHJldHVybiAxXG4gICAgICAgIH1cblxuICAgICAgICBpZiAoc2tpcCA8IDQpIHtcbiAgICAgICAgICAgIC8vIHByb2R1Y2UgYSBjaGFyYWN0ZXJcbiAgICAgICAgICAgIHRoaXMub3V0cHV0ICs9IGFscGhhYmV0W2JpdHMgPj4gM11cbiAgICAgICAgICAgIHNraXAgKz0gNVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIDBcbiAgICB9XG5cbiAgICAvLyBGbHVzaCBhbnkgcmVtYWluaW5nIGJpdHMgbGVmdCBpbiB0aGUgc3RyZWFtXG4gICAgdGhpcy5maW5pc2ggPSBmdW5jdGlvbihjaGVjaykge1xuICAgICAgICB2YXIgb3V0cHV0ID0gdGhpcy5vdXRwdXQgKyAoc2tpcCA8IDAgPyBhbHBoYWJldFtiaXRzID4+IDNdIDogJycpICsgKGNoZWNrID8gJyQnIDogJycpXG4gICAgICAgIHRoaXMub3V0cHV0ID0gJydcbiAgICAgICAgcmV0dXJuIG91dHB1dFxuICAgIH1cbn1cblxuLyoqXG4gKiBQcm9jZXNzIGFkZGl0aW9uYWwgaW5wdXRcbiAqXG4gKiBpbnB1dDogc3RyaW5nIG9mIGJ5dGVzIHRvIGNvbnZlcnRcbiAqIGZsdXNoOiBib29sZWFuLCBzaG91bGQgd2UgZmx1c2ggYW55IHRyYWlsaW5nIGJpdHMgbGVmdFxuICogICAgICAgIGluIHRoZSBzdHJlYW1cbiAqIHJldHVybnM6IGEgc3RyaW5nIG9mIGNoYXJhY3RlcnMgcmVwcmVzZW50aW5nICdpbnB1dCcgaW4gYmFzZTMyXG4gKi9cblxuRW5jb2Rlci5wcm90b3R5cGUudXBkYXRlID0gZnVuY3Rpb24oaW5wdXQsIGZsdXNoKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBpbnB1dC5sZW5ndGg7ICkge1xuICAgICAgICBpICs9IHRoaXMucmVhZEJ5dGUoaW5wdXRbaV0pXG4gICAgfVxuICAgIC8vIGNvbnN1bWUgYWxsIG91dHB1dFxuICAgIHZhciBvdXRwdXQgPSB0aGlzLm91dHB1dFxuICAgIHRoaXMub3V0cHV0ID0gJydcbiAgICBpZiAoZmx1c2gpIHtcbiAgICAgIG91dHB1dCArPSB0aGlzLmZpbmlzaCgpXG4gICAgfVxuICAgIHJldHVybiBvdXRwdXRcbn1cblxuLy8gRnVuY3Rpb25zIGFuYWxvZ291c2x5IHRvIEVuY29kZXJcblxuZnVuY3Rpb24gRGVjb2RlcigpIHtcbiAgICB2YXIgc2tpcCA9IDAgLy8gaG93IG1hbnkgYml0cyB3ZSBoYXZlIGZyb20gdGhlIHByZXZpb3VzIGNoYXJhY3RlclxuICAgIHZhciBieXRlID0gMCAvLyBjdXJyZW50IGJ5dGUgd2UncmUgcHJvZHVjaW5nXG5cbiAgICB0aGlzLm91dHB1dCA9ICcnXG5cbiAgICAvLyBDb25zdW1lIGEgY2hhcmFjdGVyIGZyb20gdGhlIHN0cmVhbSwgc3RvcmVcbiAgICAvLyB0aGUgb3V0cHV0IGluIHRoaXMub3V0cHV0LiBBcyBiZWZvcmUsIGJldHRlclxuICAgIC8vIHRvIHVzZSB1cGRhdGUoKS5cbiAgICB0aGlzLnJlYWRDaGFyID0gZnVuY3Rpb24oY2hhcikge1xuICAgICAgICBpZiAodHlwZW9mIGNoYXIgIT0gJ3N0cmluZycpe1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBjaGFyID09ICdudW1iZXInKSB7XG4gICAgICAgICAgICAgICAgY2hhciA9IFN0cmluZy5mcm9tQ2hhckNvZGUoY2hhcilcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjaGFyID0gY2hhci50b0xvd2VyQ2FzZSgpXG4gICAgICAgIHZhciB2YWwgPSBsb29rdXAoKVtjaGFyXVxuICAgICAgICBpZiAodHlwZW9mIHZhbCA9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgLy8gY2hhcmFjdGVyIGRvZXMgbm90IGV4aXN0IGluIG91ciBsb29rdXAgdGFibGVcbiAgICAgICAgICAgIHJldHVybiAvLyBza2lwIHNpbGVudGx5LiBBbiBhbHRlcm5hdGl2ZSB3b3VsZCBiZTpcbiAgICAgICAgICAgIC8vIHRocm93IEVycm9yKCdDb3VsZCBub3QgZmluZCBjaGFyYWN0ZXIgXCInICsgY2hhciArICdcIiBpbiBsb29rdXAgdGFibGUuJylcbiAgICAgICAgfVxuICAgICAgICB2YWwgPDw9IDMgLy8gbW92ZSB0byB0aGUgaGlnaCBiaXRzXG4gICAgICAgIGJ5dGUgfD0gdmFsID4+PiBza2lwXG4gICAgICAgIHNraXAgKz0gNVxuICAgICAgICBpZiAoc2tpcCA+PSA4KSB7XG4gICAgICAgICAgICAvLyB3ZSBoYXZlIGVub3VnaCB0byBwcmVkdWNlIG91dHB1dFxuICAgICAgICAgICAgdGhpcy5vdXRwdXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlKVxuICAgICAgICAgICAgc2tpcCAtPSA4XG4gICAgICAgICAgICBpZiAoc2tpcCA+IDApIGJ5dGUgPSAodmFsIDw8ICg1IC0gc2tpcCkpICYgMjU1XG4gICAgICAgICAgICBlbHNlIGJ5dGUgPSAwXG4gICAgICAgIH1cblxuICAgIH1cblxuICAgIHRoaXMuZmluaXNoID0gZnVuY3Rpb24oY2hlY2spIHtcbiAgICAgICAgdmFyIG91dHB1dCA9IHRoaXMub3V0cHV0ICsgKHNraXAgPCAwID8gYWxwaGFiZXRbYml0cyA+PiAzXSA6ICcnKSArIChjaGVjayA/ICckJyA6ICcnKVxuICAgICAgICB0aGlzLm91dHB1dCA9ICcnXG4gICAgICAgIHJldHVybiBvdXRwdXRcbiAgICB9XG59XG5cbkRlY29kZXIucHJvdG90eXBlLnVwZGF0ZSA9IGZ1bmN0aW9uKGlucHV0LCBmbHVzaCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaW5wdXQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpcy5yZWFkQ2hhcihpbnB1dFtpXSlcbiAgICB9XG4gICAgdmFyIG91dHB1dCA9IHRoaXMub3V0cHV0XG4gICAgdGhpcy5vdXRwdXQgPSAnJ1xuICAgIGlmIChmbHVzaCkge1xuICAgICAgb3V0cHV0ICs9IHRoaXMuZmluaXNoKClcbiAgICB9XG4gICAgcmV0dXJuIG91dHB1dFxufVxuXG4vKiogQ29udmVuaWVuY2UgZnVuY3Rpb25zXG4gKlxuICogVGhlc2UgYXJlIHRoZSBvbmVzIHRvIHVzZSBpZiB5b3UganVzdCBoYXZlIGEgc3RyaW5nIGFuZFxuICogd2FudCB0byBjb252ZXJ0IGl0IHdpdGhvdXQgZGVhbGluZyB3aXRoIHN0cmVhbXMgYW5kIHdoYXRub3QuXG4gKi9cblxuLy8gU3RyaW5nIG9mIGRhdGEgZ29lcyBpbiwgQmFzZTMyLWVuY29kZWQgc3RyaW5nIGNvbWVzIG91dC5cbmZ1bmN0aW9uIGVuY29kZShpbnB1dCkge1xuICB2YXIgZW5jb2RlciA9IG5ldyBFbmNvZGVyKClcbiAgdmFyIG91dHB1dCA9IGVuY29kZXIudXBkYXRlKGlucHV0LCB0cnVlKVxuICByZXR1cm4gb3V0cHV0XG59XG5cbi8vIEJhc2UzMi1lbmNvZGVkIHN0cmluZyBnb2VzIGluLCBkZWNvZGVkIGRhdGEgY29tZXMgb3V0LlxuZnVuY3Rpb24gZGVjb2RlKGlucHV0KSB7XG4gICAgdmFyIGRlY29kZXIgPSBuZXcgRGVjb2RlcigpXG4gICAgdmFyIG91dHB1dCA9IGRlY29kZXIudXBkYXRlKGlucHV0LCB0cnVlKVxuICAgIHJldHVybiBvdXRwdXRcbn1cblxudmFyIGJhc2UzMiA9IHtcbiAgICBEZWNvZGVyOiBEZWNvZGVyLFxuICAgIEVuY29kZXI6IEVuY29kZXIsXG4gICAgZW5jb2RlOiBlbmNvZGUsXG4gICAgZGVjb2RlOiBkZWNvZGVcbn1cblxuaWYgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnKSB7XG4gIC8vIHdlJ3JlIGluIGEgYnJvd3NlciAtIE9NRyFcbiAgd2luZG93LmJhc2UzMiA9IGJhc2UzMlxufVxuXG5pZiAodHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcgJiYgbW9kdWxlLmV4cG9ydHMpIHtcbiAgLy8gbm9kZWpzL2Jyb3dzZXJpZnlcbiAgbW9kdWxlLmV4cG9ydHMgPSBiYXNlMzJcbn1cbn0pKCk7XG4iLCJcbi8vIG5vdCBpbXBsZW1lbnRlZFxuLy8gVGhlIHJlYXNvbiBmb3IgaGF2aW5nIGFuIGVtcHR5IGZpbGUgYW5kIG5vdCB0aHJvd2luZyBpcyB0byBhbGxvd1xuLy8gdW50cmFkaXRpb25hbCBpbXBsZW1lbnRhdGlvbiBvZiB0aGlzIG1vZHVsZS5cbiIsIi8vIGRvVC5qc1xuLy8gMjAxMS0yMDE0LCBMYXVyYSBEb2t0b3JvdmEsIGh0dHBzOi8vZ2l0aHViLmNvbS9vbGFkby9kb1Rcbi8vIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cblxuKGZ1bmN0aW9uKCkge1xuXHRcInVzZSBzdHJpY3RcIjtcblxuXHR2YXIgZG9UID0ge1xuXHRcdHZlcnNpb246IFwiMS4wLjNcIixcblx0XHR0ZW1wbGF0ZVNldHRpbmdzOiB7XG5cdFx0XHRldmFsdWF0ZTogICAgL1xce1xceyhbXFxzXFxTXSs/KFxcfT8pKylcXH1cXH0vZyxcblx0XHRcdGludGVycG9sYXRlOiAvXFx7XFx7PShbXFxzXFxTXSs/KVxcfVxcfS9nLFxuXHRcdFx0ZW5jb2RlOiAgICAgIC9cXHtcXHshKFtcXHNcXFNdKz8pXFx9XFx9L2csXG5cdFx0XHR1c2U6ICAgICAgICAgL1xce1xceyMoW1xcc1xcU10rPylcXH1cXH0vZyxcblx0XHRcdHVzZVBhcmFtczogICAvKF58W15cXHckXSlkZWYoPzpcXC58XFxbW1xcJ1xcXCJdKShbXFx3JFxcLl0rKSg/OltcXCdcXFwiXVxcXSk/XFxzKlxcOlxccyooW1xcdyRcXC5dK3xcXFwiW15cXFwiXStcXFwifFxcJ1teXFwnXStcXCd8XFx7W15cXH1dK1xcfSkvZyxcblx0XHRcdGRlZmluZTogICAgICAvXFx7XFx7IyNcXHMqKFtcXHdcXC4kXSspXFxzKihcXDp8PSkoW1xcc1xcU10rPykjXFx9XFx9L2csXG5cdFx0XHRkZWZpbmVQYXJhbXM6L15cXHMqKFtcXHckXSspOihbXFxzXFxTXSspLyxcblx0XHRcdGNvbmRpdGlvbmFsOiAvXFx7XFx7XFw/KFxcPyk/XFxzKihbXFxzXFxTXSo/KVxccypcXH1cXH0vZyxcblx0XHRcdGl0ZXJhdGU6ICAgICAvXFx7XFx7flxccyooPzpcXH1cXH18KFtcXHNcXFNdKz8pXFxzKlxcOlxccyooW1xcdyRdKylcXHMqKD86XFw6XFxzKihbXFx3JF0rKSk/XFxzKlxcfVxcfSkvZyxcblx0XHRcdHZhcm5hbWU6XHRcIml0XCIsXG5cdFx0XHRzdHJpcDpcdFx0dHJ1ZSxcblx0XHRcdGFwcGVuZDpcdFx0dHJ1ZSxcblx0XHRcdHNlbGZjb250YWluZWQ6IGZhbHNlLFxuXHRcdFx0ZG9Ob3RTa2lwRW5jb2RlZDogZmFsc2Vcblx0XHR9LFxuXHRcdHRlbXBsYXRlOiB1bmRlZmluZWQsIC8vZm4sIGNvbXBpbGUgdGVtcGxhdGVcblx0XHRjb21waWxlOiAgdW5kZWZpbmVkICAvL2ZuLCBmb3IgZXhwcmVzc1xuXHR9LCBfZ2xvYmFscztcblxuXHRkb1QuZW5jb2RlSFRNTFNvdXJjZSA9IGZ1bmN0aW9uKGRvTm90U2tpcEVuY29kZWQpIHtcblx0XHR2YXIgZW5jb2RlSFRNTFJ1bGVzID0geyBcIiZcIjogXCImIzM4O1wiLCBcIjxcIjogXCImIzYwO1wiLCBcIj5cIjogXCImIzYyO1wiLCAnXCInOiBcIiYjMzQ7XCIsIFwiJ1wiOiBcIiYjMzk7XCIsIFwiL1wiOiBcIiYjNDc7XCIgfSxcblx0XHRcdG1hdGNoSFRNTCA9IGRvTm90U2tpcEVuY29kZWQgPyAvWyY8PlwiJ1xcL10vZyA6IC8mKD8hIz9cXHcrOyl8PHw+fFwifCd8XFwvL2c7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKGNvZGUpIHtcblx0XHRcdHJldHVybiBjb2RlID8gY29kZS50b1N0cmluZygpLnJlcGxhY2UobWF0Y2hIVE1MLCBmdW5jdGlvbihtKSB7cmV0dXJuIGVuY29kZUhUTUxSdWxlc1ttXSB8fCBtO30pIDogXCJcIjtcblx0XHR9O1xuXHR9O1xuXG5cdF9nbG9iYWxzID0gKGZ1bmN0aW9uKCl7IHJldHVybiB0aGlzIHx8ICgwLGV2YWwpKFwidGhpc1wiKTsgfSgpKTtcblxuXHRpZiAodHlwZW9mIG1vZHVsZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBtb2R1bGUuZXhwb3J0cykge1xuXHRcdG1vZHVsZS5leHBvcnRzID0gZG9UO1xuXHR9IGVsc2UgaWYgKHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kKSB7XG5cdFx0ZGVmaW5lKGZ1bmN0aW9uKCl7cmV0dXJuIGRvVDt9KTtcblx0fSBlbHNlIHtcblx0XHRfZ2xvYmFscy5kb1QgPSBkb1Q7XG5cdH1cblxuXHR2YXIgc3RhcnRlbmQgPSB7XG5cdFx0YXBwZW5kOiB7IHN0YXJ0OiBcIicrKFwiLCAgICAgIGVuZDogXCIpKydcIiwgICAgICBzdGFydGVuY29kZTogXCInK2VuY29kZUhUTUwoXCIgfSxcblx0XHRzcGxpdDogIHsgc3RhcnQ6IFwiJztvdXQrPShcIiwgZW5kOiBcIik7b3V0Kz0nXCIsIHN0YXJ0ZW5jb2RlOiBcIic7b3V0Kz1lbmNvZGVIVE1MKFwiIH1cblx0fSwgc2tpcCA9IC8kXi87XG5cblx0ZnVuY3Rpb24gcmVzb2x2ZURlZnMoYywgYmxvY2ssIGRlZikge1xuXHRcdHJldHVybiAoKHR5cGVvZiBibG9jayA9PT0gXCJzdHJpbmdcIikgPyBibG9jayA6IGJsb2NrLnRvU3RyaW5nKCkpXG5cdFx0LnJlcGxhY2UoYy5kZWZpbmUgfHwgc2tpcCwgZnVuY3Rpb24obSwgY29kZSwgYXNzaWduLCB2YWx1ZSkge1xuXHRcdFx0aWYgKGNvZGUuaW5kZXhPZihcImRlZi5cIikgPT09IDApIHtcblx0XHRcdFx0Y29kZSA9IGNvZGUuc3Vic3RyaW5nKDQpO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCEoY29kZSBpbiBkZWYpKSB7XG5cdFx0XHRcdGlmIChhc3NpZ24gPT09IFwiOlwiKSB7XG5cdFx0XHRcdFx0aWYgKGMuZGVmaW5lUGFyYW1zKSB2YWx1ZS5yZXBsYWNlKGMuZGVmaW5lUGFyYW1zLCBmdW5jdGlvbihtLCBwYXJhbSwgdikge1xuXHRcdFx0XHRcdFx0ZGVmW2NvZGVdID0ge2FyZzogcGFyYW0sIHRleHQ6IHZ9O1xuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdGlmICghKGNvZGUgaW4gZGVmKSkgZGVmW2NvZGVdPSB2YWx1ZTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRuZXcgRnVuY3Rpb24oXCJkZWZcIiwgXCJkZWZbJ1wiK2NvZGUrXCInXT1cIiArIHZhbHVlKShkZWYpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gXCJcIjtcblx0XHR9KVxuXHRcdC5yZXBsYWNlKGMudXNlIHx8IHNraXAsIGZ1bmN0aW9uKG0sIGNvZGUpIHtcblx0XHRcdGlmIChjLnVzZVBhcmFtcykgY29kZSA9IGNvZGUucmVwbGFjZShjLnVzZVBhcmFtcywgZnVuY3Rpb24obSwgcywgZCwgcGFyYW0pIHtcblx0XHRcdFx0aWYgKGRlZltkXSAmJiBkZWZbZF0uYXJnICYmIHBhcmFtKSB7XG5cdFx0XHRcdFx0dmFyIHJ3ID0gKGQrXCI6XCIrcGFyYW0pLnJlcGxhY2UoLyd8XFxcXC9nLCBcIl9cIik7XG5cdFx0XHRcdFx0ZGVmLl9fZXhwID0gZGVmLl9fZXhwIHx8IHt9O1xuXHRcdFx0XHRcdGRlZi5fX2V4cFtyd10gPSBkZWZbZF0udGV4dC5yZXBsYWNlKG5ldyBSZWdFeHAoXCIoXnxbXlxcXFx3JF0pXCIgKyBkZWZbZF0uYXJnICsgXCIoW15cXFxcdyRdKVwiLCBcImdcIiksIFwiJDFcIiArIHBhcmFtICsgXCIkMlwiKTtcblx0XHRcdFx0XHRyZXR1cm4gcyArIFwiZGVmLl9fZXhwWydcIitydytcIiddXCI7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdFx0dmFyIHYgPSBuZXcgRnVuY3Rpb24oXCJkZWZcIiwgXCJyZXR1cm4gXCIgKyBjb2RlKShkZWYpO1xuXHRcdFx0cmV0dXJuIHYgPyByZXNvbHZlRGVmcyhjLCB2LCBkZWYpIDogdjtcblx0XHR9KTtcblx0fVxuXG5cdGZ1bmN0aW9uIHVuZXNjYXBlKGNvZGUpIHtcblx0XHRyZXR1cm4gY29kZS5yZXBsYWNlKC9cXFxcKCd8XFxcXCkvZywgXCIkMVwiKS5yZXBsYWNlKC9bXFxyXFx0XFxuXS9nLCBcIiBcIik7XG5cdH1cblxuXHRkb1QudGVtcGxhdGUgPSBmdW5jdGlvbih0bXBsLCBjLCBkZWYpIHtcblx0XHRjID0gYyB8fCBkb1QudGVtcGxhdGVTZXR0aW5ncztcblx0XHR2YXIgY3NlID0gYy5hcHBlbmQgPyBzdGFydGVuZC5hcHBlbmQgOiBzdGFydGVuZC5zcGxpdCwgbmVlZGh0bWxlbmNvZGUsIHNpZCA9IDAsIGluZHYsXG5cdFx0XHRzdHIgID0gKGMudXNlIHx8IGMuZGVmaW5lKSA/IHJlc29sdmVEZWZzKGMsIHRtcGwsIGRlZiB8fCB7fSkgOiB0bXBsO1xuXG5cdFx0c3RyID0gKFwidmFyIG91dD0nXCIgKyAoYy5zdHJpcCA/IHN0ci5yZXBsYWNlKC8oXnxcXHJ8XFxuKVxcdCogK3wgK1xcdCooXFxyfFxcbnwkKS9nLFwiIFwiKVxuXHRcdFx0XHRcdC5yZXBsYWNlKC9cXHJ8XFxufFxcdHxcXC9cXCpbXFxzXFxTXSo/XFwqXFwvL2csXCJcIik6IHN0cilcblx0XHRcdC5yZXBsYWNlKC8nfFxcXFwvZywgXCJcXFxcJCZcIilcblx0XHRcdC5yZXBsYWNlKGMuaW50ZXJwb2xhdGUgfHwgc2tpcCwgZnVuY3Rpb24obSwgY29kZSkge1xuXHRcdFx0XHRyZXR1cm4gY3NlLnN0YXJ0ICsgdW5lc2NhcGUoY29kZSkgKyBjc2UuZW5kO1xuXHRcdFx0fSlcblx0XHRcdC5yZXBsYWNlKGMuZW5jb2RlIHx8IHNraXAsIGZ1bmN0aW9uKG0sIGNvZGUpIHtcblx0XHRcdFx0bmVlZGh0bWxlbmNvZGUgPSB0cnVlO1xuXHRcdFx0XHRyZXR1cm4gY3NlLnN0YXJ0ZW5jb2RlICsgdW5lc2NhcGUoY29kZSkgKyBjc2UuZW5kO1xuXHRcdFx0fSlcblx0XHRcdC5yZXBsYWNlKGMuY29uZGl0aW9uYWwgfHwgc2tpcCwgZnVuY3Rpb24obSwgZWxzZWNhc2UsIGNvZGUpIHtcblx0XHRcdFx0cmV0dXJuIGVsc2VjYXNlID9cblx0XHRcdFx0XHQoY29kZSA/IFwiJzt9ZWxzZSBpZihcIiArIHVuZXNjYXBlKGNvZGUpICsgXCIpe291dCs9J1wiIDogXCInO31lbHNle291dCs9J1wiKSA6XG5cdFx0XHRcdFx0KGNvZGUgPyBcIic7aWYoXCIgKyB1bmVzY2FwZShjb2RlKSArIFwiKXtvdXQrPSdcIiA6IFwiJzt9b3V0Kz0nXCIpO1xuXHRcdFx0fSlcblx0XHRcdC5yZXBsYWNlKGMuaXRlcmF0ZSB8fCBza2lwLCBmdW5jdGlvbihtLCBpdGVyYXRlLCB2bmFtZSwgaW5hbWUpIHtcblx0XHRcdFx0aWYgKCFpdGVyYXRlKSByZXR1cm4gXCInO30gfSBvdXQrPSdcIjtcblx0XHRcdFx0c2lkKz0xOyBpbmR2PWluYW1lIHx8IFwiaVwiK3NpZDsgaXRlcmF0ZT11bmVzY2FwZShpdGVyYXRlKTtcblx0XHRcdFx0cmV0dXJuIFwiJzt2YXIgYXJyXCIrc2lkK1wiPVwiK2l0ZXJhdGUrXCI7aWYoYXJyXCIrc2lkK1wiKXt2YXIgXCIrdm5hbWUrXCIsXCIraW5kditcIj0tMSxsXCIrc2lkK1wiPWFyclwiK3NpZCtcIi5sZW5ndGgtMTt3aGlsZShcIitpbmR2K1wiPGxcIitzaWQrXCIpe1wiXG5cdFx0XHRcdFx0K3ZuYW1lK1wiPWFyclwiK3NpZCtcIltcIitpbmR2K1wiKz0xXTtvdXQrPSdcIjtcblx0XHRcdH0pXG5cdFx0XHQucmVwbGFjZShjLmV2YWx1YXRlIHx8IHNraXAsIGZ1bmN0aW9uKG0sIGNvZGUpIHtcblx0XHRcdFx0cmV0dXJuIFwiJztcIiArIHVuZXNjYXBlKGNvZGUpICsgXCJvdXQrPSdcIjtcblx0XHRcdH0pXG5cdFx0XHQrIFwiJztyZXR1cm4gb3V0O1wiKVxuXHRcdFx0LnJlcGxhY2UoL1xcbi9nLCBcIlxcXFxuXCIpLnJlcGxhY2UoL1xcdC9nLCAnXFxcXHQnKS5yZXBsYWNlKC9cXHIvZywgXCJcXFxcclwiKVxuXHRcdFx0LnJlcGxhY2UoLyhcXHN8O3xcXH18XnxcXHspb3V0XFwrPScnOy9nLCAnJDEnKS5yZXBsYWNlKC9cXCsnJy9nLCBcIlwiKTtcblx0XHRcdC8vLnJlcGxhY2UoLyhcXHN8O3xcXH18XnxcXHspb3V0XFwrPScnXFwrL2csJyQxb3V0Kz0nKTtcblxuXHRcdGlmIChuZWVkaHRtbGVuY29kZSkge1xuXHRcdFx0aWYgKCFjLnNlbGZjb250YWluZWQgJiYgX2dsb2JhbHMgJiYgIV9nbG9iYWxzLl9lbmNvZGVIVE1MKSBfZ2xvYmFscy5fZW5jb2RlSFRNTCA9IGRvVC5lbmNvZGVIVE1MU291cmNlKGMuZG9Ob3RTa2lwRW5jb2RlZCk7XG5cdFx0XHRzdHIgPSBcInZhciBlbmNvZGVIVE1MID0gdHlwZW9mIF9lbmNvZGVIVE1MICE9PSAndW5kZWZpbmVkJyA/IF9lbmNvZGVIVE1MIDogKFwiXG5cdFx0XHRcdCsgZG9ULmVuY29kZUhUTUxTb3VyY2UudG9TdHJpbmcoKSArIFwiKFwiICsgKGMuZG9Ob3RTa2lwRW5jb2RlZCB8fCAnJykgKyBcIikpO1wiXG5cdFx0XHRcdCsgc3RyO1xuXHRcdH1cblx0XHR0cnkge1xuXHRcdFx0cmV0dXJuIG5ldyBGdW5jdGlvbihjLnZhcm5hbWUsIHN0cik7XG5cdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0aWYgKHR5cGVvZiBjb25zb2xlICE9PSBcInVuZGVmaW5lZFwiKSBjb25zb2xlLmxvZyhcIkNvdWxkIG5vdCBjcmVhdGUgYSB0ZW1wbGF0ZSBmdW5jdGlvbjogXCIgKyBzdHIpO1xuXHRcdFx0dGhyb3cgZTtcblx0XHR9XG5cdH07XG5cblx0ZG9ULmNvbXBpbGUgPSBmdW5jdGlvbih0bXBsLCBkZWYpIHtcblx0XHRyZXR1cm4gZG9ULnRlbXBsYXRlKHRtcGwsIG51bGwsIGRlZik7XG5cdH07XG59KCkpO1xuIiwiLyogZG9UICsgYXV0by1jb21waWxhdGlvbiBvZiBkb1QgdGVtcGxhdGVzXG4gKlxuICogMjAxMiwgTGF1cmEgRG9rdG9yb3ZhLCBodHRwczovL2dpdGh1Yi5jb20vb2xhZG8vZG9UXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2VcbiAqXG4gKiBDb21waWxlcyAuZGVmLCAuZG90LCAuanN0IGZpbGVzIGZvdW5kIHVuZGVyIHRoZSBzcGVjaWZpZWQgcGF0aC5cbiAqIEl0IGlnbm9yZXMgc3ViLWRpcmVjdG9yaWVzLlxuICogVGVtcGxhdGUgZmlsZXMgY2FuIGhhdmUgbXVsdGlwbGUgZXh0ZW5zaW9ucyBhdCB0aGUgc2FtZSB0aW1lLlxuICogRmlsZXMgd2l0aCAuZGVmIGV4dGVuc2lvbiBjYW4gYmUgaW5jbHVkZWQgaW4gb3RoZXIgZmlsZXMgdmlhIHt7I2RlZi5uYW1lfX1cbiAqIEZpbGVzIHdpdGggLmRvdCBleHRlbnNpb24gYXJlIGNvbXBpbGVkIGludG8gZnVuY3Rpb25zIHdpdGggdGhlIHNhbWUgbmFtZSBhbmRcbiAqIGNhbiBiZSBhY2Nlc3NlZCBhcyByZW5kZXJlci5maWxlbmFtZVxuICogRmlsZXMgd2l0aCAuanN0IGV4dGVuc2lvbiBhcmUgY29tcGlsZWQgaW50byAuanMgZmlsZXMuIFByb2R1Y2VkIC5qcyBmaWxlIGNhbiBiZVxuICogbG9hZGVkIGFzIGEgY29tbW9uSlMsIEFNRCBtb2R1bGUsIG9yIGp1c3QgaW5zdGFsbGVkIGludG8gYSBnbG9iYWwgdmFyaWFibGVcbiAqIChkZWZhdWx0IGlzIHNldCB0byB3aW5kb3cucmVuZGVyKS5cbiAqIEFsbCBpbmxpbmUgZGVmaW5lcyBkZWZpbmVkIGluIHRoZSAuanN0IGZpbGUgYXJlXG4gKiBjb21waWxlZCBpbnRvIHNlcGFyYXRlIGZ1bmN0aW9ucyBhbmQgYXJlIGF2YWlsYWJsZSB2aWEgX3JlbmRlci5maWxlbmFtZS5kZWZpbmVuYW1lXG4gKlxuICogQmFzaWMgdXNhZ2U6XG4gKiB2YXIgZG90cyA9IHJlcXVpcmUoXCJkb3RcIikucHJvY2Vzcyh7cGF0aDogXCIuL3ZpZXdzXCJ9KTtcbiAqIGRvdHMubXl0ZW1wbGF0ZSh7Zm9vOlwiaGVsbG8gd29ybGRcIn0pO1xuICpcbiAqIFRoZSBhYm92ZSBzbmlwcGV0IHdpbGw6XG4gKiAxLiBDb21waWxlIGFsbCB0ZW1wbGF0ZXMgaW4gdmlld3MgZm9sZGVyICguZG90LCAuZGVmLCAuanN0KVxuICogMi4gUGxhY2UgLmpzIGZpbGVzIGNvbXBpbGVkIGZyb20gLmpzdCB0ZW1wbGF0ZXMgaW50byB0aGUgc2FtZSBmb2xkZXIuXG4gKiAgICBUaGVzZSBmaWxlcyBjYW4gYmUgdXNlZCB3aXRoIHJlcXVpcmUsIGkuZS4gcmVxdWlyZShcIi4vdmlld3MvbXl0ZW1wbGF0ZVwiKS5cbiAqIDMuIFJldHVybiBhbiBvYmplY3Qgd2l0aCBmdW5jdGlvbnMgY29tcGlsZWQgZnJvbSAuZG90IHRlbXBsYXRlcyBhcyBpdHMgcHJvcGVydGllcy5cbiAqIDQuIFJlbmRlciBteXRlbXBsYXRlIHRlbXBsYXRlLlxuICovXG5cbnZhciBmcyA9IHJlcXVpcmUoXCJmc1wiKSxcblx0ZG9UID0gbW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwiLi9kb1RcIik7XG5cbmRvVC5wcm9jZXNzID0gZnVuY3Rpb24ob3B0aW9ucykge1xuXHQvL3BhdGgsIGRlc3RpbmF0aW9uLCBnbG9iYWwsIHJlbmRlcm1vZHVsZSwgdGVtcGxhdGVTZXR0aW5nc1xuXHRyZXR1cm4gbmV3IEluc3RhbGxEb3RzKG9wdGlvbnMpLmNvbXBpbGVBbGwoKTtcbn07XG5cbmZ1bmN0aW9uIEluc3RhbGxEb3RzKG8pIHtcblx0dGhpcy5fX3BhdGggXHRcdD0gby5wYXRoIHx8IFwiLi9cIjtcblx0aWYgKHRoaXMuX19wYXRoW3RoaXMuX19wYXRoLmxlbmd0aC0xXSAhPT0gJy8nKSB0aGlzLl9fcGF0aCArPSAnLyc7XG5cdHRoaXMuX19kZXN0aW5hdGlvblx0PSBvLmRlc3RpbmF0aW9uIHx8IHRoaXMuX19wYXRoO1xuXHRpZiAodGhpcy5fX2Rlc3RpbmF0aW9uW3RoaXMuX19kZXN0aW5hdGlvbi5sZW5ndGgtMV0gIT09ICcvJykgdGhpcy5fX2Rlc3RpbmF0aW9uICs9ICcvJztcblx0dGhpcy5fX2dsb2JhbFx0XHQ9IG8uZ2xvYmFsIHx8IFwid2luZG93LnJlbmRlclwiO1xuXHR0aGlzLl9fcmVuZGVybW9kdWxlXHQ9IG8ucmVuZGVybW9kdWxlIHx8IHt9O1xuXHR0aGlzLl9fc2V0dGluZ3MgXHQ9IG8udGVtcGxhdGVTZXR0aW5ncyA/IGNvcHkoby50ZW1wbGF0ZVNldHRpbmdzLCBjb3B5KGRvVC50ZW1wbGF0ZVNldHRpbmdzKSkgOiB1bmRlZmluZWQ7XG5cdHRoaXMuX19pbmNsdWRlc1x0XHQ9IHt9O1xufVxuXG5JbnN0YWxsRG90cy5wcm90b3R5cGUuY29tcGlsZVRvRmlsZSA9IGZ1bmN0aW9uKHBhdGgsIHRlbXBsYXRlLCBkZWYpIHtcblx0ZGVmID0gZGVmIHx8IHt9O1xuXHR2YXIgbW9kdWxlbmFtZSA9IHBhdGguc3Vic3RyaW5nKHBhdGgubGFzdEluZGV4T2YoXCIvXCIpKzEsIHBhdGgubGFzdEluZGV4T2YoXCIuXCIpKVxuXHRcdCwgZGVmcyA9IGNvcHkodGhpcy5fX2luY2x1ZGVzLCBjb3B5KGRlZikpXG5cdFx0LCBzZXR0aW5ncyA9IHRoaXMuX19zZXR0aW5ncyB8fCBkb1QudGVtcGxhdGVTZXR0aW5nc1xuXHRcdCwgY29tcGlsZW9wdGlvbnMgPSBjb3B5KHNldHRpbmdzKVxuXHRcdCwgZGVmYXVsdGNvbXBpbGVkID0gZG9ULnRlbXBsYXRlKHRlbXBsYXRlLCBzZXR0aW5ncywgZGVmcylcblx0XHQsIGV4cG9ydHMgPSBbXVxuXHRcdCwgY29tcGlsZWQgPSBcIlwiXG5cdFx0LCBmbjtcblxuXHRmb3IgKHZhciBwcm9wZXJ0eSBpbiBkZWZzKSB7XG5cdFx0aWYgKGRlZnNbcHJvcGVydHldICE9PSBkZWZbcHJvcGVydHldICYmIGRlZnNbcHJvcGVydHldICE9PSB0aGlzLl9faW5jbHVkZXNbcHJvcGVydHldKSB7XG5cdFx0XHRmbiA9IHVuZGVmaW5lZDtcblx0XHRcdGlmICh0eXBlb2YgZGVmc1twcm9wZXJ0eV0gPT09ICdzdHJpbmcnKSB7XG5cdFx0XHRcdGZuID0gZG9ULnRlbXBsYXRlKGRlZnNbcHJvcGVydHldLCBzZXR0aW5ncywgZGVmcyk7XG5cdFx0XHR9IGVsc2UgaWYgKHR5cGVvZiBkZWZzW3Byb3BlcnR5XSA9PT0gJ2Z1bmN0aW9uJykge1xuXHRcdFx0XHRmbiA9IGRlZnNbcHJvcGVydHldO1xuXHRcdFx0fSBlbHNlIGlmIChkZWZzW3Byb3BlcnR5XS5hcmcpIHtcblx0XHRcdFx0Y29tcGlsZW9wdGlvbnMudmFybmFtZSA9IGRlZnNbcHJvcGVydHldLmFyZztcblx0XHRcdFx0Zm4gPSBkb1QudGVtcGxhdGUoZGVmc1twcm9wZXJ0eV0udGV4dCwgY29tcGlsZW9wdGlvbnMsIGRlZnMpO1xuXHRcdFx0fVxuXHRcdFx0aWYgKGZuKSB7XG5cdFx0XHRcdGNvbXBpbGVkICs9IGZuLnRvU3RyaW5nKCkucmVwbGFjZSgnYW5vbnltb3VzJywgcHJvcGVydHkpO1xuXHRcdFx0XHRleHBvcnRzLnB1c2gocHJvcGVydHkpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXHRjb21waWxlZCArPSBkZWZhdWx0Y29tcGlsZWQudG9TdHJpbmcoKS5yZXBsYWNlKCdhbm9ueW1vdXMnLCBtb2R1bGVuYW1lKTtcblx0ZnMud3JpdGVGaWxlU3luYyhwYXRoLCBcIihmdW5jdGlvbigpe1wiICsgY29tcGlsZWRcblx0XHQrIFwidmFyIGl0c2VsZj1cIiArIG1vZHVsZW5hbWUgKyBcIiwgX2VuY29kZUhUTUw9KFwiICsgZG9ULmVuY29kZUhUTUxTb3VyY2UudG9TdHJpbmcoKSArIFwiKFwiICsgKHNldHRpbmdzLmRvTm90U2tpcEVuY29kZWQgfHwgJycpICsgXCIpKTtcIlxuXHRcdCsgYWRkZXhwb3J0cyhleHBvcnRzKVxuXHRcdCsgXCJpZih0eXBlb2YgbW9kdWxlIT09J3VuZGVmaW5lZCcgJiYgbW9kdWxlLmV4cG9ydHMpIG1vZHVsZS5leHBvcnRzPWl0c2VsZjtlbHNlIGlmKHR5cGVvZiBkZWZpbmU9PT0nZnVuY3Rpb24nKWRlZmluZShmdW5jdGlvbigpe3JldHVybiBpdHNlbGY7fSk7ZWxzZSB7XCJcblx0XHQrIHRoaXMuX19nbG9iYWwgKyBcIj1cIiArIHRoaXMuX19nbG9iYWwgKyBcInx8e307XCIgKyB0aGlzLl9fZ2xvYmFsICsgXCJbJ1wiICsgbW9kdWxlbmFtZSArIFwiJ109aXRzZWxmO319KCkpO1wiKTtcbn07XG5cbmZ1bmN0aW9uIGFkZGV4cG9ydHMoZXhwb3J0cykge1xuXHRmb3IgKHZhciByZXQgPScnLCBpPTA7IGk8IGV4cG9ydHMubGVuZ3RoOyBpKyspIHtcblx0XHRyZXQgKz0gXCJpdHNlbGYuXCIgKyBleHBvcnRzW2ldKyBcIj1cIiArIGV4cG9ydHNbaV0rXCI7XCI7XG5cdH1cblx0cmV0dXJuIHJldDtcbn1cblxuZnVuY3Rpb24gY29weShvLCB0bykge1xuXHR0byA9IHRvIHx8IHt9O1xuXHRmb3IgKHZhciBwcm9wZXJ0eSBpbiBvKSB7XG5cdFx0dG9bcHJvcGVydHldID0gb1twcm9wZXJ0eV07XG5cdH1cblx0cmV0dXJuIHRvO1xufVxuXG5mdW5jdGlvbiByZWFkZGF0YShwYXRoKSB7XG5cdHZhciBkYXRhID0gZnMucmVhZEZpbGVTeW5jKHBhdGgpO1xuXHRpZiAoZGF0YSkgcmV0dXJuIGRhdGEudG9TdHJpbmcoKTtcblx0Y29uc29sZS5sb2coXCJwcm9ibGVtcyB3aXRoIFwiICsgcGF0aCk7XG59XG5cbkluc3RhbGxEb3RzLnByb3RvdHlwZS5jb21waWxlUGF0aCA9IGZ1bmN0aW9uKHBhdGgpIHtcblx0dmFyIGRhdGEgPSByZWFkZGF0YShwYXRoKTtcblx0aWYgKGRhdGEpIHtcblx0XHRyZXR1cm4gZG9ULnRlbXBsYXRlKGRhdGEsXG5cdFx0XHRcdFx0dGhpcy5fX3NldHRpbmdzIHx8IGRvVC50ZW1wbGF0ZVNldHRpbmdzLFxuXHRcdFx0XHRcdGNvcHkodGhpcy5fX2luY2x1ZGVzKSk7XG5cdH1cbn07XG5cbkluc3RhbGxEb3RzLnByb3RvdHlwZS5jb21waWxlQWxsID0gZnVuY3Rpb24oKSB7XG5cdGNvbnNvbGUubG9nKFwiQ29tcGlsaW5nIGFsbCBkb1QgdGVtcGxhdGVzLi4uXCIpO1xuXG5cdHZhciBkZWZGb2xkZXIgPSB0aGlzLl9fcGF0aCxcblx0XHRzb3VyY2VzID0gZnMucmVhZGRpclN5bmMoZGVmRm9sZGVyKSxcblx0XHRrLCBsLCBuYW1lO1xuXG5cdGZvciggayA9IDAsIGwgPSBzb3VyY2VzLmxlbmd0aDsgayA8IGw7IGsrKykge1xuXHRcdG5hbWUgPSBzb3VyY2VzW2tdO1xuXHRcdGlmICgvXFwuZGVmKFxcLmRvdHxcXC5qc3QpPyQvLnRlc3QobmFtZSkpIHtcblx0XHRcdGNvbnNvbGUubG9nKFwiTG9hZGVkIGRlZiBcIiArIG5hbWUpO1xuXHRcdFx0dGhpcy5fX2luY2x1ZGVzW25hbWUuc3Vic3RyaW5nKDAsIG5hbWUuaW5kZXhPZignLicpKV0gPSByZWFkZGF0YShkZWZGb2xkZXIgKyBuYW1lKTtcblx0XHR9XG5cdH1cblxuXHRmb3IoIGsgPSAwLCBsID0gc291cmNlcy5sZW5ndGg7IGsgPCBsOyBrKyspIHtcblx0XHRuYW1lID0gc291cmNlc1trXTtcblx0XHRpZiAoL1xcLmRvdChcXC5kZWZ8XFwuanN0KT8kLy50ZXN0KG5hbWUpKSB7XG5cdFx0XHRjb25zb2xlLmxvZyhcIkNvbXBpbGluZyBcIiArIG5hbWUgKyBcIiB0byBmdW5jdGlvblwiKTtcblx0XHRcdHRoaXMuX19yZW5kZXJtb2R1bGVbbmFtZS5zdWJzdHJpbmcoMCwgbmFtZS5pbmRleE9mKCcuJykpXSA9IHRoaXMuY29tcGlsZVBhdGgoZGVmRm9sZGVyICsgbmFtZSk7XG5cdFx0fVxuXHRcdGlmICgvXFwuanN0KFxcLmRvdHxcXC5kZWYpPyQvLnRlc3QobmFtZSkpIHtcblx0XHRcdGNvbnNvbGUubG9nKFwiQ29tcGlsaW5nIFwiICsgbmFtZSArIFwiIHRvIGZpbGVcIik7XG5cdFx0XHR0aGlzLmNvbXBpbGVUb0ZpbGUodGhpcy5fX2Rlc3RpbmF0aW9uICsgbmFtZS5zdWJzdHJpbmcoMCwgbmFtZS5pbmRleE9mKCcuJykpICsgJy5qcycsXG5cdFx0XHRcdFx0cmVhZGRhdGEoZGVmRm9sZGVyICsgbmFtZSkpO1xuXHRcdH1cblx0fVxuXHRyZXR1cm4gdGhpcy5fX3JlbmRlcm1vZHVsZTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBjb25maWcgPSByZXF1aXJlKCcuLi9jb25maWcnKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1peGluO1xuXG4vKipcbiAqIGBtaWxvLmNsYXNzZXMuTWl4aW5gIC0gYW4gYWJzdHJhY3QgTWl4aW4gY2xhc3MuXG4gKiBDYW4gYmUgc3ViY2xhc3NlZCB1c2luZzpcbiAqIGBgYFxuICogdmFyIE15TWl4aW4gPSBfLmNyZWF0ZVN1YmNsYXNzKG1pbG8uY2xhc3Nlcy5NaXhpbiwgJ015TWl4aW4nKTtcbiAqIGBgYFxuICpcbiAqIE1peGluIHBhdHRlcm4gaXMgYWxzbyB1c2VkLCBidXQgTWl4aW4gaW4gbWlsbyBpcyBpbXBsZW1lbnRlZCBhcyBhIHNlcGFyYXRlIG9iamVjdCB0aGF0IGlzIHN0b3JlZCBvbiB0aGUgcHJvcGVydHkgb2YgdGhlIGhvc3Qgb2JqZWN0IGFuZCBjYW4gY3JlYXRlIHByb3h5IG1ldGhvZHMgb24gdGhlIGhvc3Qgb2JqZWN0IGlmIHJlcXVpcmVkLlxuICogQ2xhc3NlcyBbTWVzc2VuZ2VyXSguLi9tZXNzZW5nZXIvaW5kZXguanMuaHRtbCkgYW5kIFtNZXNzYWdlU291cmNlXSguLi9tZXNzZW5nZXIvbV9zb3VyY2UuanMuaHRtbCkgYXJlIHN1YmNsYXNzZXMgb2YgTWl4aW4gYWJzdHJhY3QgY2xhc3MuIGB0aGlzYCBpbiBwcm94eSBtZXRob2RzIHJlZmVycyB0byBNaXhpbiBpbnN0YW5jZSwgdGhlIHJlZmVyZW5jZSB0byB0aGUgaG9zdCBvYmplY3QgaXMgYHRoaXMuX2hvc3RPYmplY3RgLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0T2JqZWN0IE9wdGlvbmFsIG9iamVjdCB3aGVyZSBhIE1peGluIGluc3RhbmNlIHdpbGwgYmUgc3RvcmVkIG9uLiBJdCBpcyB1c2VkIHRvIHByb3h5IG1ldGhvZHMgYW5kIGFsc28gdG8gZmluZCB0aGUgcmVmZXJlbmNlIHdoZW4gaXQgaXMgbmVlZGVkIGZvciBob3N0IG9iamVjdCBpbXBsZW1lbnRhdGlvbi5cbiAqIEBwYXJhbSB7T2JqZWN0fSBwcm94eU1ldGhvZHMgT3B0aW9uYWwgbWFwIG9mIHByb3h5IG1ldGhvZCBuYW1lcyBhcyBrZXlzIGFuZCBNaXhpbiBtZXRob2RzIG5hbWVzIGFzIHZhbHVlcywgc28gcHJveGllZCBtZXRob2RzIGNhbiBiZSByZW5hbWVkIHRvIGF2b2lkIG5hbWUtc3BhY2UgY29uZmxpY3RzIGlmIHR3byBkaWZmZXJlbnQgTWl4aW4gaW5zdGFuY2VzIHdpdGggdGhlIHNhbWUgbWV0aG9kIG5hbWVzIGFyZSBwdXQgb24gdGhlIG9iamVjdFxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgYWxsIGNvbnN0cnVjdG9yIGFyZ3VtZW50cyB3aWxsIGJlIHBhc3NlZCB0byBpbml0IG1ldGhvZCBvZiBNaXhpbiBzdWJjbGFzcyB0b2dldGhlciB3aXRoIGhvc3RPYmplY3QgYW5kIHByb3h5TWV0aG9kc1xuICogQHJldHVybiB7TWl4aW59XG4gKi9cbmZ1bmN0aW9uIE1peGluKGhvc3RPYmplY3QsIHByb3h5TWV0aG9kcykgeyAvLyAsIG90aGVyIGFyZ3MgLSBwYXNzZWQgdG8gaW5pdCBtZXRob2RcbiAgICBjaGVjayhob3N0T2JqZWN0LCBNYXRjaC5PcHRpb25hbChNYXRjaC5PbmVPZihPYmplY3QsIEZ1bmN0aW9uKSkpO1xuXG4gICAgLy8gc3RvcmUgaG9zdE9iamVjdFxuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgJ19ob3N0T2JqZWN0JywgaG9zdE9iamVjdCk7XG5cbiAgICAvLyBwcm94eSBtZXRob2RzIHRvIGhvc3RPYmplY3RcbiAgICBpZiAocHJveHlNZXRob2RzKVxuICAgICAgICB0aGlzLl9jcmVhdGVQcm94eU1ldGhvZHMocHJveHlNZXRob2RzKTtcblxuICAgIC8vIGNhbGxpbmcgaW5pdCBpZiBpdCBpcyBkZWZpbmVkIGluIHRoZSBjbGFzc1xuICAgIGlmICh0aGlzLmluaXQpXG4gICAgICAgIHRoaXMuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbi8qKlxuICogIyMjI01peGluIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKiBUaGVzZSBtZXRob2RzIGFyZSBjYWxsZWQgYnkgY29uc3RydWN0b3IsIHRoZXkgYXJlIG5vdCB0byBiZSBjYWxsZWQgZnJvbSBzdWJjbGFzc2VzLlxuICpcbiAqIC0gW19jcmVhdGVQcm94eU1ldGhvZF0oI19jcmVhdGVQcm94eU1ldGhvZClcbiAqIC0gW19jcmVhdGVQcm94eU1ldGhvZHNdKCNfY3JlYXRlUHJveHlNZXRob2RzKVxuICovXG5fLmV4dGVuZFByb3RvKE1peGluLCB7XG4gICAgX2NyZWF0ZVByb3h5TWV0aG9kOiBfY3JlYXRlUHJveHlNZXRob2QsICAvLyBkZXByZWNhdGVkLCBzaG91bGQgbm90IGJlIHVzZWRcbiAgICBfY3JlYXRlUHJveHlNZXRob2RzOiBfY3JlYXRlUHJveHlNZXRob2RzICAvLyBkZXByZWNhdGVkLCBzaG91bGQgbm90IGJlIHVzZWRcbn0pO1xuXG5cbi8qKlxuICogIyMjI01peGluIGNsYXNzIG1ldGhvZHMjIyMjXG4gKiBUaGVzZSBtZXRob2Qgc2hvdWxkIGJlIGNhbGxlZCBpbiBob3N0IGNsYXNzIGRlY2xhcmF0aW9uLlxuICpcbiAqIC0gW3VzZVdpdGhdKCNNaXhpbiQkdXNlV2l0aClcbiAqL1xuXy5leHRlbmQoTWl4aW4sIHtcbiAgICB1c2VXaXRoOiBNaXhpbiQkdXNlV2l0aFxufSk7XG5cblxuLyoqXG4gKiBDcmVhdGVzIGEgcHJveGllZCBtZXRob2Qgb2YgTWl4aW4gc3ViY2xhc3Mgb24gaG9zdCBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1peGluTWV0aG9kTmFtZSBuYW1lIG9mIG1ldGhvZCBpbiBNaXhpbiBzdWJjbGFzc1xuICogQHBhcmFtIHtTdHJpbmd9IHByb3h5TWV0aG9kTmFtZSBuYW1lIG9mIGNyZWF0ZWQgcHJveHkgbWV0aG9kIG9uIGhvc3Qgb2JqZWN0XG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBPcHRpb25hbCByZWZlcmVuY2UgdG8gdGhlIGhvc3Qgb2JqZWN0OyBpZiBub3Qgc3BlY2lmaWVkIHRoZSBob3N0IG9iamVjdCBwYXNzZWQgdG8gY29uc3RydWN0b3Igd2lsIGJlIHVzZWQuIEl0IGFsbG93cyB0byB1c2UgdGhlIHNhbWUgaW5zdGFuY2Ugb2YgTWl4aW4gb24gdHdvIGhvc3Qgb2JqZWN0cy5cbiAqL1xuZnVuY3Rpb24gX2NyZWF0ZVByb3h5TWV0aG9kKHByb3h5TWV0aG9kTmFtZSwgbWl4aW5NZXRob2ROYW1lLCBob3N0T2JqZWN0KSB7XG4gICAgaG9zdE9iamVjdCA9IGhvc3RPYmplY3QgfHwgdGhpcy5faG9zdE9iamVjdDtcblxuICAgIC8vIE1peGluIGNsYXNzIGRvZXMgbm90IGFsbG93IHNoYWRvd2luZyBtZXRob2RzIHRoYXQgZXhpc3Qgb24gdGhlIGhvc3Qgb2JqZWN0XG4gICAgaWYgKGhvc3RPYmplY3RbcHJveHlNZXRob2ROYW1lXSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdtZXRob2QgJyArIHByb3h5TWV0aG9kTmFtZSArXG4gICAgICAgICAgICAgICAgICAgICAgICAnIGFscmVhZHkgZGVmaW5lZCBpbiBob3N0IG9iamVjdCcpO1xuXG4gICAgdmFyIG1ldGhvZCA9IHRoaXNbbWl4aW5NZXRob2ROYW1lXVxuICAgIGNoZWNrKG1ldGhvZCwgRnVuY3Rpb24pO1xuXG4gICAgLy8gQmluZCBwcm94aWVkIE1peGluJ3MgbWV0aG9kIHRvIE1peGluIGluc3RhbmNlXG4gICAgdmFyIGJvdW5kTWV0aG9kID0gbWV0aG9kLmJpbmQodGhpcyk7XG5cbiAgICBfLmRlZmluZVByb3BlcnR5KGhvc3RPYmplY3QsIHByb3h5TWV0aG9kTmFtZSwgYm91bmRNZXRob2QsIF8uV1JJVCk7XG59XG5cblxuLyoqXG4gKiBDcmVhdGVzIHByb3hpZWQgbWV0aG9kcyBvZiBNaXhpbiBzdWJjbGFzcyBvbiBob3N0IG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge0hhc2hbU3RyaW5nXXxBcnJheVtTdHJpbmddfSBwcm94eU1ldGhvZHMgbWFwIG9mIG5hbWVzIG9mIG1ldGhvZHMsIGtleSAtIHByb3h5IG1ldGhvZCBuYW1lLCB2YWx1ZSAtIG1peGluIG1ldGhvZCBuYW1lLiBDYW4gYmUgYXJyYXkuXG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBhbiBvcHRpb25hbCByZWZlcmVuY2UgdG8gdGhlIGhvc3Qgb2JqZWN0OyBpZiBub3Qgc3BlY2lmaWVkIHRoZSBob3N0IG9iamVjdCBwYXNzZWQgdG8gY29uc3RydWN0b3Igd2lsIGJlIHVzZWQuIEl0IGFsbG93cyB0byB1c2UgdGhlIHNhbWUgaW5zdGFuY2Ugb2YgTWl4aW4gb24gdHdvIGhvc3Qgb2JqZWN0cy5cbiAqL1xuZnVuY3Rpb24gX2NyZWF0ZVByb3h5TWV0aG9kcyhwcm94eU1ldGhvZHMsIGhvc3RPYmplY3QpIHtcbiAgICBjaGVjayhwcm94eU1ldGhvZHMsIE1hdGNoLk9wdGlvbmFsKE1hdGNoLk9uZU9mKFtTdHJpbmddLCBNYXRjaC5PYmplY3RIYXNoKFN0cmluZykpKSk7XG5cbiAgICAvLyBjcmVhdGluZyBhbmQgYmluZGluZyBwcm94eSBtZXRob2RzIG9uIHRoZSBob3N0IG9iamVjdFxuICAgIGlmIChBcnJheS5pc0FycmF5KHByb3h5TWV0aG9kcykpXG4gICAgICAgIHByb3h5TWV0aG9kcy5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICAgICAgICAgIC8vIG1ldGhvZCBjYWxsZWQgdGhpcyB3YXkgdG8gYWxsb3cgdXNpbmcgX2NyZWF0ZVByb3h5TWV0aG9kcyB3aXRoIG9iamVjdHNcbiAgICAgICAgICAgIC8vIHRoYXQgYXJlIG5vdCBpbmhlcml0aW5nIGZyb20gTWl4aW5cbiAgICAgICAgICAgIF9jcmVhdGVQcm94eU1ldGhvZC5jYWxsKHRoaXMsIG1ldGhvZE5hbWUsIG1ldGhvZE5hbWUsIGhvc3RPYmplY3QpO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICBlbHNlXG4gICAgICAgIF8uZWFjaEtleShwcm94eU1ldGhvZHMsIGZ1bmN0aW9uKG1peGluTWV0aG9kTmFtZSwgcHJveHlNZXRob2ROYW1lKSB7XG4gICAgICAgICAgICAvLyBtZXRob2QgY2FsbGVkIHRoaXMgd2F5IHRvIGFsbG93IHVzaW5nIF9jcmVhdGVQcm94eU1ldGhvZHMgd2l0aCBvYmplY3RzXG4gICAgICAgICAgICAvLyB0aGF0IGFyZSBub3QgaW5oZXJpdGluZyBmcm9tIE1peGluXG4gICAgICAgICAgICBfY3JlYXRlUHJveHlNZXRob2QuY2FsbCh0aGlzLCBwcm94eU1ldGhvZE5hbWUsIG1peGluTWV0aG9kTmFtZSwgaG9zdE9iamVjdCk7XG4gICAgICAgIH0sIHRoaXMpO1xufVxuXG5cbi8qKlxuICogU2V0cyBtaXhpbiBpbnN0YW5jZSBwcm9wZXJ0eSBuYW1lIG9uIHRoZSBob3N0IGNsYXNzXG4gKiBDYW4gYmUgY2FsbGVkIG9ubHkgb25jZVxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzIE1peGluIHN1YmNsYXNzIChub3QgaW5zdGFuY2UpXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBob3N0Q2xhc3NcbiAqIEBwYXJhbSB7U3RyaW5nfSBpbnN0YW5jZUtleVxuICovXG5mdW5jdGlvbiBNaXhpbl9zZXRJbnN0YW5jZUtleShob3N0Q2xhc3MsIG1ldGhvZCwgaW5zdGFuY2VLZXkpIHtcbiAgICBjaGVjayhob3N0Q2xhc3MsIEZ1bmN0aW9uKTtcbiAgICBjaGVjayhpbnN0YW5jZUtleSwgTWF0Y2guSWRlbnRpZmllclN0cmluZyk7XG5cbiAgICB2YXIgcHJvcCA9IGNvbmZpZy5taXhpbi5pbnN0YW5jZVByb3BlcnRpZXNNYXBcbiAgICAgICAgLCBpbnN0YW5jZUtleXMgPSBob3N0Q2xhc3NbcHJvcF0gPSBob3N0Q2xhc3NbcHJvcF0gfHwge307XG5cbiAgICBpZiAoaW5zdGFuY2VLZXlzW21ldGhvZC5uYW1lXSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXhpbjogaW5zdGFuY2UgcHJvcGVydHkgZm9yIG1ldGhvZCB3aXRoIG5hbWUgJ1xuICAgICAgICAgICAgKyBtZXRob2QubmFtZSArICcgaXMgYWxyZWFkeSBzZXQnKTtcblxuICAgIGluc3RhbmNlS2V5c1ttZXRob2QubmFtZV0gPSBpbnN0YW5jZUtleTtcbn1cblxuXG4vKipcbiAqIEFkZHMgbWV0aG9kIG9mIE1peGluIHN1YmNsYXNzIHRvIGhvc3QgY2xhc3MgcHJvdG90eXBlLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzIE1peGluIHN1YmNsYXNzIChub3QgaW5zdGFuY2UpXG4gKiBAcGFyYW0ge1N0cmluZ30gbWl4aW5NZXRob2ROYW1lIG5hbWUgb2YgbWV0aG9kIGluIE1peGluIHN1YmNsYXNzXG4gKiBAcGFyYW0ge1N0cmluZ30gaG9zdE1ldGhvZE5hbWUgKG9wdGlvbmFsKSBuYW1lIG9mIGNyZWF0ZWQgcHJveHkgbWV0aG9kIG9uIGhvc3Qgb2JqZWN0LCBzYW1lIGlmIG5vdCBzcGVjaWZpZWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0T2JqZWN0IG9iamVjdCBjbGFzcywgbXVzdCBiZSBzcGVjaWZpZWQgYXMgdGhlIGxhc3QgcGFyYW1ldGVyICgybmQgb3IgM3JkKVxuICovXG5mdW5jdGlvbiBNaXhpbl9hZGRNZXRob2QoaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2ROYW1lLCBob3N0TWV0aG9kTmFtZSkge1xuICAgIHZhciBtZXRob2QgPSB0aGlzLnByb3RvdHlwZVttaXhpbk1ldGhvZE5hbWVdO1xuICAgIGNoZWNrKG1ldGhvZCwgRnVuY3Rpb24pO1xuXG4gICAgdmFyIHdyYXBwZWRNZXRob2QgPSBfd3JhcE1peGluTWV0aG9kLmNhbGwodGhpcywgbWV0aG9kKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydHkoaG9zdENsYXNzLnByb3RvdHlwZSwgaG9zdE1ldGhvZE5hbWUsIHdyYXBwZWRNZXRob2QsIF8uV1JJVCk7XG5cbiAgICBNaXhpbl9zZXRJbnN0YW5jZUtleShob3N0Q2xhc3MsIG1ldGhvZCwgaW5zdGFuY2VLZXkpXG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIG1ldGhvZCB0aGF0IHdpbGwgYmUgZXhwb3NlZCBvbiB0aGUgaG9zdCBjbGFzcyBwcm90b3R5cGVcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gdGhpcyBNaXhpbiBzdWJjbGFzcyAobm90IGluc3RhbmNlKVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIF93cmFwTWl4aW5NZXRob2QobWV0aG9kKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkgeyAvLyAsLi4uIGFyZ3VtZW50c1xuICAgICAgICB2YXIgbWl4aW5JbnN0YW5jZSA9IF9nZXRNaXhpbkluc3RhbmNlLmNhbGwodGhpcywgbWV0aG9kLm5hbWUpO1xuICAgICAgICByZXR1cm4gbWV0aG9kLmFwcGx5KG1peGluSW5zdGFuY2UsIGFyZ3VtZW50cyk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgcmVmZXJlbmNlIHRvIHRoZSBpbnN0YW5jZSBvZiBtaXhpbiBzdWJjbGFzcy5cbiAqIFRoaXMgbWV0aG9kIGlzIHVzZWQgd2hlbiBtZXRob2RzIGFyZSBleHBvc2VkIG9uIHRoZSBob3N0IGNsYXNzIHByb3RvdHlwZSAodXNpbmcgYWRkTWVodG9kcykgcmF0aGVyIHRoYW4gb24gaG9zdCBpbnN0YW5jZS5cbiAqIFN1YmNsYXNzZXMgc2hvdWxkIG5vdCB1c2UgdGhpcyBtZXRob2RzIC0gd2hlbmV2ZXIgc3ViY2xhc3MgbWV0aG9kIGlzIGV4cG9zZWQgb24gdGhlIHByb3RvdHlwZSBpdCB3aWxsIGJlIHdyYXBwZWQgdG8gc2V0IGNvcnJlY3QgY29udGV4dCBmb3IgdGhlIHN1YmNsYXNzIG1ldGhvZC5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBfZ2V0TWl4aW5JbnN0YW5jZShtZXRob2ROYW1lKSB7XG4gICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBNaXhpbikgcmV0dXJuIHRoaXM7XG4gICAgdmFyIGluc3RhbmNlS2V5cyA9IHRoaXMuY29uc3RydWN0b3JbY29uZmlnLm1peGluLmluc3RhbmNlUHJvcGVydGllc01hcF1cbiAgICByZXR1cm4gdGhpc1tpbnN0YW5jZUtleXNbbWV0aG9kTmFtZV1dO1xufVxuXG5cbi8qKlxuICogQWRkcyBtZXRob2RzIG9mIE1peGluIHN1YmNsYXNzIHRvIGhvc3QgY2xhc3MgcHJvdG90eXBlLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHRoaXMgTWl4aW4gc3ViY2xhc3MgKG5vdCBpbnN0YW5jZSlcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0Q2xhc3MgaG9zdCBvYmplY3QgY2xhc3M7IG11c3QgYmUgc3BlY2lmaWVkLlxuICogQHBhcmFtIHtTdHJpbmd9IGluc3RhbmNlS2V5IHRoZSBuYW1lIG9mIHRoZSBwcm9wZXJ0eSB0aGUgaG9zdCBjbGFzcyBpbnN0YW5jZSB3aWxsIHN0b3JlIG1peGluIGluc3RhbmNlIG9uXG4gKiBAcGFyYW0ge0hhc2hbU3RyaW5nXXxBcnJheVtTdHJpbmddfSBtaXhpbk1ldGhvZHMgbWFwIG9mIG5hbWVzIG9mIG1ldGhvZHMsIGtleSAtIGhvc3QgbWV0aG9kIG5hbWUsIHZhbHVlIC0gbWl4aW4gbWV0aG9kIG5hbWUuIENhbiBiZSBhcnJheS5cbiAqL1xuZnVuY3Rpb24gTWl4aW4kJHVzZVdpdGgoaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2RzKSB7XG4gICAgY2hlY2sobWl4aW5NZXRob2RzLCBNYXRjaC5PcHRpb25hbChNYXRjaC5PbmVPZihbU3RyaW5nXSwgTWF0Y2guT2JqZWN0SGFzaChTdHJpbmcpKSkpO1xuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkobWl4aW5NZXRob2RzKSlcbiAgICAgICAgbWl4aW5NZXRob2RzLmZvckVhY2goZnVuY3Rpb24obWV0aG9kTmFtZSkge1xuICAgICAgICAgICAgTWl4aW5fYWRkTWV0aG9kLmNhbGwodGhpcywgaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWV0aG9kTmFtZSwgbWV0aG9kTmFtZSk7XG4gICAgICAgIH0sIHRoaXMpO1xuICAgIGVsc2VcbiAgICAgICAgXy5lYWNoS2V5KG1peGluTWV0aG9kcywgZnVuY3Rpb24obWl4aW5NZXRob2ROYW1lLCBob3N0TWV0aG9kTmFtZSkge1xuICAgICAgICAgICAgTWl4aW5fYWRkTWV0aG9kLmNhbGwodGhpcywgaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2ROYW1lLCBob3N0TWV0aG9kTmFtZSk7XG4gICAgICAgIH0sIHRoaXMpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyA8YSBuYW1lPVwiY2xhc3Nlc1wiPjwvYT5cbi8vIG1pbG8uY2xhc3Nlc1xuLy8gLS0tLS0tLS0tLS1cblxuLy8gVGhpcyBtb2R1bGUgY29udGFpbnMgZm91bmRhdGlvbiBjbGFzc2VzXG5cbnZhciBjbGFzc2VzID0ge1xuICAgIE1peGluOiByZXF1aXJlKCcuL2Fic3RyYWN0L21peGluJyksXG4gICAgTWVzc2FnZVNvdXJjZTogcmVxdWlyZSgnLi9tZXNzZW5nZXIvbV9zb3VyY2UnKSxcbiAgICBNZXNzZW5nZXJNZXNzYWdlU291cmNlOiByZXF1aXJlKCcuL21lc3Nlbmdlci9tc25ncl9zb3VyY2UnKSxcbiAgICBNZXNzZW5nZXJBUEk6IHJlcXVpcmUoJy4vbWVzc2VuZ2VyL21fYXBpJyksXG4gICAgTWVzc2VuZ2VyUmVnZXhwQVBJOiByZXF1aXJlKCcuL21lc3Nlbmdlci9tX2FwaV9yeCcpXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzZXM7XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbmZpZztcblxuZnVuY3Rpb24gY29uZmlnKG9wdGlvbnMpIHtcbiAgICBfLmRlZXBFeHRlbmQoY29uZmlnLCBvcHRpb25zKTtcbn1cblxuY29uZmlnKHtcbiAgICBtaXhpbjoge1xuICAgICAgICBpbnN0YW5jZVByb3BlcnRpZXNNYXA6ICdfX19taXhpbl9pbnN0YW5jZXMnXG4gICAgfSxcbiAgICBjaGVjazogdHJ1ZSxcbiAgICBkZWJ1ZzogZmFsc2Vcbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgTWl4aW4gPSByZXF1aXJlKCcuLi9hYnN0cmFjdC9taXhpbicpXG4gICAgLCBNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi9tX3NvdXJjZScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5cbi8qKlxuICogYG1pbG8uTWVzc2VuZ2VyYFxuICogQSBnZW5lcmljIE1lc3NlbmdlciBjbGFzcyB0aGF0IGlzIHVzZWQgZm9yIGFsbCBraW5kcyBvZiBtZXNzYWdpbmcgaW4gbWlsby4gSXQgaXMgc3ViY2xhc3NlZCBmcm9tIFtNaXhpbl0oLi4vYWJzdHJhY3QvbWl4aW4uanMuaHRtbCkgYW5kIGl0IHByb3hpZXMgaXRzIG1ldGhvZHMgdG8gdGhlIGhvc3Qgb2JqZWN0IGZvciBjb252ZW5pZW5jZS5cbiAqIEFsbCBmYWNldHMgYW5kIGNvbXBvbmVudHMgaGF2ZSBtZXNzZW5nZXIgYXR0YWNoZWQgdG8gdGhlbS4gTWVzc2VuZ2VyIGNsYXNzIGludGVyb3BlcmF0ZXMgd2l0aCBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBjbGFzcyB0aGF0IGNvbm5lY3RzIHRoZSBtZXNzZW5nZXIgdG8gc29tZSBleHRlcm5hbCBzb3VyY2Ugb2YgbWVzc2FnZXMgKGUuZy4sIERPTSBldmVudHMpIGFuZCBbTWVzc2VuZ2VyQVBJXSguL21fYXBpLmpzLmh0bWwpIGNsYXNzIHRoYXQgYWxsb3dzIHRvIGRlZmluZSBoaWdoZXIgbGV2ZWwgbWVzc2FnZXMgdGhhbiBtZXNzYWdlcyB0aGF0IGV4aXN0IG9uIHRoZSBzb3VyY2UuXG4gKiBNZXNzZW5nZXIgY2xhc3MgaXMgdXNlZCBpbnRlcm5hbGx5IGluIG1pbG8gYW5kIGNhbiBiZSB1c2VkIHRvZ2V0aGVyIHdpdGggYW55IG9iamVjdHMvY2xhc3NlcyBpbiB0aGUgYXBwbGljYXRpb24uXG4gKiBtaWxvIGFsc28gZGVmaW5lcyBhIGdsb2JhbCBtZXNzZW5nZXIgW21pbG8ubWFpbF0oLi4vbWFpbC9pbmRleC5qcy5odG1sKSB0aGF0IGRpc3BhdGNoZXMgYGRvbXJlYWR5YCBldmVudCBhbmQgY2FuIGJlIHVzZWQgZm9yIGFueSBhcHBsaWNhdGlvbiB3aWRlIG1lc3NhZ2luZy5cbiAqIFRvIGluaXRpYWxpemUgeW91ciBhcHAgYWZ0ZXIgRE9NIGlzIHJlYWR5IHVzZTpcbiAqIGBgYFxuICogbWlsby5tYWlsLm9uKCdkb21yZWFkeScsIGZ1bmN0aW9uKCkge1xuICogICAgIC8vIGFwcGxpY2F0aW9uIHN0YXJ0c1xuICogfSk7XG4gKiBgYGBcbiAqIG9yIHRoZSBmb2xsb3dpbmcgc2hvcnRlciBmb3JtIG9mIHRoZSBzYW1lOlxuICogYGBgXG4gKiBtaWxvKGZ1bmN0aW9uKCkge1xuICogICAgIC8vIGFwcGxpY2F0aW9uIHN0YXJ0c1xuICogfSk7XG4gKiBgYGBcbiAqL1xudmFyIE1lc3NlbmdlciA9IF8uY3JlYXRlU3ViY2xhc3MoTWl4aW4sICdNZXNzZW5nZXInKTtcblxudmFyIG1lc3NhZ2VzU3BsaXRSZWdFeHAgPSBNZXNzZW5nZXIubWVzc2FnZXNTcGxpdFJlZ0V4cCA9IC9cXHMqKD86XFwsfFxccylcXHMqLztcblxuXG4vKipcbiAqICMjIyNNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kcyMjIyNcbiAqXG4gKiAtIFtpbml0XSgjaW5pdClcbiAqIC0gW29uXSgjTWVzc2VuZ2VyJG9uKSAoYWxpYXMgLSBvbk1lc3NhZ2UsIGRlcHJlY2F0ZWQpXG4gKiAtIFtvZmZdKCNNZXNzZW5nZXIkb2ZmKSAoYWxpYXMgLSBvZmZNZXNzYWdlLCBkZXByZWNhdGVkKVxuICogLSBbb25NZXNzYWdlc10oI29uTWVzc2FnZXMpXG4gKiAtIFtvZmZNZXNzYWdlc10oI29mZk1lc3NhZ2VzKVxuICogLSBbb25jZV0oI29uY2UpXG4gKiAtIFtvbmNlU3luY10oI29uY2VTeW5jKVxuICogLSBbcG9zdE1lc3NhZ2VdKCNwb3N0TWVzc2FnZSlcbiAqIC0gW2dldFN1YnNjcmliZXJzXSgjZ2V0U3Vic2NyaWJlcnMpXG4gKlxuICogXCJQcml2YXRlXCIgbWV0aG9kc1xuICpcbiAqIC0gW19jaG9vc2VTdWJzY3JpYmVyc0hhc2hdKCNfY2hvb3NlU3Vic2NyaWJlcnNIYXNoKVxuICogLSBbX3JlZ2lzdGVyU3Vic2NyaWJlcl0oI19yZWdpc3RlclN1YnNjcmliZXIpXG4gKiAtIFtfcmVtb3ZlU3Vic2NyaWJlcl0oI19yZW1vdmVTdWJzY3JpYmVyKVxuICogLSBbX3JlbW92ZUFsbFN1YnNjcmliZXJzXSgjX3JlbW92ZUFsbFN1YnNjcmliZXJzKVxuICogLSBbX2NhbGxQYXR0ZXJuU3Vic2NyaWJlcnNdKCNfY2FsbFBhdHRlcm5TdWJzY3JpYmVycylcbiAqIC0gW19jYWxsU3Vic2NyaWJlcnNdKCNfY2FsbFN1YnNjcmliZXJzKVxuICogLSBbX3NldE1lc3NhZ2VTb3VyY2VdKCNfc2V0TWVzc2FnZVNvdXJjZSlcbiAqIC0gW2dldE1lc3NhZ2VTb3VyY2VdKCNnZXRNZXNzYWdlU291cmNlKVxuICovXG5fLmV4dGVuZFByb3RvKE1lc3Nlbmdlciwge1xuICAgIGluaXQ6IGluaXQsIC8vIGNhbGxlZCBieSBNaXhpbiAoc3VwZXJjbGFzcylcbiAgICBkZXN0cm95OiBNZXNzZW5nZXIkZGVzdHJveSxcbiAgICBvbjogTWVzc2VuZ2VyJG9uLFxuICAgIG9uY2U6IE1lc3NlbmdlciRvbmNlLFxuICAgIG9uY2VTeW5jOiBNZXNzZW5nZXIkb25jZVN5bmMsXG4gICAgb25TeW5jOiBNZXNzZW5nZXIkb25TeW5jLFxuICAgIG9uQXN5bmM6IE1lc3NlbmdlciRvbkFzeW5jLFxuICAgIG9uTWVzc2FnZTogTWVzc2VuZ2VyJG9uLCAvLyBkZXByZWNhdGVkXG4gICAgb2ZmOiBNZXNzZW5nZXIkb2ZmLFxuICAgIG9mZk1lc3NhZ2U6IE1lc3NlbmdlciRvZmYsIC8vIGRlcHJlY2F0ZWRcbiAgICBvbk1lc3NhZ2VzOiBvbk1lc3NhZ2VzLFxuICAgIG9mZk1lc3NhZ2VzOiBvZmZNZXNzYWdlcyxcbiAgICBvZmZBbGw6IE1lc3NlbmdlciRvZmZBbGwsXG4gICAgcG9zdE1lc3NhZ2U6IHBvc3RNZXNzYWdlLFxuICAgIHBvc3RNZXNzYWdlU3luYzogcG9zdE1lc3NhZ2VTeW5jLFxuICAgIGdldFN1YnNjcmliZXJzOiBnZXRTdWJzY3JpYmVycyxcbiAgICBnZXRNZXNzYWdlU291cmNlOiBnZXRNZXNzYWdlU291cmNlLFxuICAgIF9jaG9vc2VTdWJzY3JpYmVyc0hhc2g6IF9jaG9vc2VTdWJzY3JpYmVyc0hhc2gsXG4gICAgX3JlZ2lzdGVyU3Vic2NyaWJlcjogX3JlZ2lzdGVyU3Vic2NyaWJlcixcbiAgICBfcmVtb3ZlU3Vic2NyaWJlcjogX3JlbW92ZVN1YnNjcmliZXIsXG4gICAgX3JlbW92ZUFsbFN1YnNjcmliZXJzOiBfcmVtb3ZlQWxsU3Vic2NyaWJlcnMsXG4gICAgX2NhbGxQYXR0ZXJuU3Vic2NyaWJlcnM6IF9jYWxsUGF0dGVyblN1YnNjcmliZXJzLFxuICAgIF9jYWxsU3Vic2NyaWJlcnM6IF9jYWxsU3Vic2NyaWJlcnMsXG4gICAgX2NhbGxTdWJzY3JpYmVyOiBfY2FsbFN1YnNjcmliZXIsXG4gICAgX3NldE1lc3NhZ2VTb3VyY2U6IF9zZXRNZXNzYWdlU291cmNlXG59KTtcblxuXG4vKipcbiAqIEEgZGVmYXVsdCBtYXAgb2YgcHJveHkgbWV0aG9kcyB1c2VkIGJ5IENvbXBvbmVudEZhY2V0IGFuZCBDb21wb25lbnQgY2xhc3NlcyB0byBwYXNzIHRvIE1lc3NlbmdlciB3aGVuIGl0IGlzIGluc3RhbnRpYXRlZC5cbiAqIFRoaXMgbWFwIGlzIGZvciBjb252ZW5pZW5jZSBvbmx5LCBpdCBpcyBOT1QgdXNlZCBpbnRlcm5hbGx5IGJ5IE1lc3NlbmdlciwgYSBob3N0IGNsYXNzIHNob3VsZCBwYXNzIGl0IGZvciBtZXRob2RzIHRvIGJlIHByb3hpZWQgdGhpcyB3YXkuXG4gKi9cbk1lc3Nlbmdlci5kZWZhdWx0TWV0aG9kcyA9IHtcbiAgICBvbjogJ29uJyxcbiAgICBvblN5bmM6ICdvblN5bmMnLFxuICAgIG9uY2U6ICdvbmNlJyxcbiAgICBvbmNlU3luYzogJ29uY2VTeW5jJyxcbiAgICBvZmY6ICdvZmYnLFxuICAgIG9uTWVzc2FnZXM6ICdvbk1lc3NhZ2VzJyxcbiAgICBvZmZNZXNzYWdlczogJ29mZk1lc3NhZ2VzJyxcbiAgICBwb3N0TWVzc2FnZTogJ3Bvc3RNZXNzYWdlJyxcbiAgICBwb3N0TWVzc2FnZVN5bmM6ICdwb3N0TWVzc2FnZVN5bmMnLFxuICAgIGdldFN1YnNjcmliZXJzOiAnZ2V0U3Vic2NyaWJlcnMnXG59O1xuXG5cbm1vZHVsZS5leHBvcnRzID0gTWVzc2VuZ2VyO1xuXG5cbk1lc3Nlbmdlci5zdWJzY3JpcHRpb25zID0gW107XG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsaXplcyBNZXNzZW5nZXIuIE1ldGhvZCBpcyBjYWxsZWQgYnkgTWl4aW4gY2xhc3MgY29uc3RydWN0b3IuXG4gKiBTZWUgW29uXSgjTWVzc2VuZ2VyJG9uKSBtZXRob2QsIFtNZXNzZW5nZXJdKCNNZXNzZW5nZXIpIGNsYXNzIGFib3ZlIGFuZCBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBjbGFzcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBPcHRpb25hbCBvYmplY3QgdGhhdCBzdG9yZXMgdGhlIG1lc3NlbmdlciBvbiBvbmUgb2YgaXRzIHByb3BlcnRpZXMuIEl0IGlzIHVzZWQgdG8gcHJveHkgbWV0aG9kcyBvZiBtZXNzZW5nZXIgYW5kIGFsc28gYXMgYSBjb250ZXh0IGZvciBzdWJzY3JpYmVycyB3aGVuIHRoZXkgYXJlIGNhbGxlZCBieSB0aGUgTWVzc2VuZ2VyLiBTZWUgYG9uYCBtZXRob2QuXG4gKiBAcGFyYW0ge09iamVjdH0gcHJveHlNZXRob2RzIE9wdGlvbmFsIG1hcCBvZiBtZXRob2QgbmFtZXM7IGtleSAtIHByb3h5IG1ldGhvZCBuYW1lLCB2YWx1ZSAtIG1lc3NlbmdlcidzIG1ldGhvZCBuYW1lLlxuICogQHBhcmFtIHtNZXNzYWdlU291cmNlfSBtZXNzYWdlU291cmNlIE9wdGlvbmFsIG1lc3NhZ2VTb3VyY2UgbGlua2VkIHRvIHRoZSBtZXNzZW5nZXIuIElmIG1lc3NhZ2VTb3VyY2UgaXMgc3VwcGxpZWQsIHRoZSByZWZlcmVuY2UgdG8gdGhlIG1lc3NlbmdlciB3aWxsIHN0b3JlZCBvbiBpdHMgJ21lc3NlbmdlcicgcHJvcGVydHlcbiAqL1xuZnVuY3Rpb24gaW5pdChob3N0T2JqZWN0LCBwcm94eU1ldGhvZHMsIG1lc3NhZ2VTb3VyY2UpIHtcbiAgICAvLyBob3N0T2JqZWN0IGFuZCBwcm94eU1ldGhvZHMgYXJlIHVzZWQgaW4gTWl4aW4gYW5kIGNoZWNrZWQgdGhlcmVcbiAgICBpZiAobWVzc2FnZVNvdXJjZSlcbiAgICAgICAgdGhpcy5fc2V0TWVzc2FnZVNvdXJjZShtZXNzYWdlU291cmNlKTtcblxuICAgIF9pbml0aWFsaXplU3Vic2NyaWJlcnMuY2FsbCh0aGlzKTtcbn1cblxuXG5mdW5jdGlvbiBfaW5pdGlhbGl6ZVN1YnNjcmliZXJzKCkge1xuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgIF9tZXNzYWdlU3Vic2NyaWJlcnM6IHt9LFxuICAgICAgICBfcGF0dGVybk1lc3NhZ2VTdWJzY3JpYmVyczoge30sXG4gICAgfSwgXy5DT05GKTtcbn1cblxuXG4vKipcbiAqIERlc3Ryb3lzIG1lc3Nlbmdlci4gTWF5YmUgbmVlZHMgdG8gdW5zdWJzY3JpYmUgYWxsIHN1YnNjcmliZXJzXG4gKi9cbmZ1bmN0aW9uIE1lc3NlbmdlciRkZXN0cm95KCkge1xuICAgIHRoaXMub2ZmQWxsKCk7XG4gICAgdmFyIG1lc3NhZ2VTb3VyY2UgPSB0aGlzLmdldE1lc3NhZ2VTb3VyY2UoKTtcbiAgICBpZiAobWVzc2FnZVNvdXJjZSlcbiAgICAgICAgbWVzc2FnZVNvdXJjZS5kZXN0cm95KCk7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogUmVnaXN0ZXJzIGEgc3Vic2NyaWJlciBmdW5jdGlvbiBmb3IgYSBjZXJ0YWluIG1lc3NhZ2UocykuXG4gKiBUaGlzIG1ldGhvZCByZXR1cm5zIGB0cnVlYCBpZiB0aGUgc3Vic2NyaXB0aW9uIHdhcyBzdWNjZXNzZnVsLiBJdCBjYW4gYmUgdW5zdWNjZXNzZnVsIGlmIHRoZSBwYXNzZWQgc3Vic2NyaWJlciBoYXMgYWxyZWFkeSBiZWVuIHN1YnNjcmliZWQgdG8gdGhpcyBtZXNzYWdlIHR5cGUgLSBkb3VibGUgc3Vic2NyaXB0aW9uIG5ldmVyIGhhcHBlbnMgYW5kIGl0IGlzIHNhZmUgdG8gc3Vic2NyaWJlIGFnYWluIC0gbm8gZXJyb3Igb3Igd2FybmluZyBpcyB0aHJvd24gb3IgbG9nZ2VkLlxuICogU3Vic2NyaWJlciBpcyBwYXNzZWQgdHdvIHBhcmFtZXRlcnM6IGBtZXNzYWdlYCAoc3RyaW5nKSBhbmQgYGRhdGFgIChvYmplY3QpLiBEYXRhIG9iamVjdCBpcyBzdXBwbGllZCB3aGVuIG1lc3NhZ2UgaXMgZGlzcGF0Y2hlZCwgTWVzc2VuZ2VyIGl0c2VsZiBhZGRzIG5vdGhpbmcgdG8gaXQuIEZvciBleGFtcGxlLCBbZXZlbnRzIGZhY2V0XSguLi9jb21wb25lbnRzL2NfZmFjZXRzL0V2ZW50cy5qcy5odG1sKSBzZW5kcyBhY3R1YWwgRE9NIGV2ZW50IHdoZW4gaXQgcG9zdHMgbWVzc2FnZS5cbiAqIFVzYWdlOlxuICogYGBgXG4gKiAvLyBzdWJzY3JpYmVzIG9uTW91c2VVcERvd24gdG8gdHdvIERPTSBldmVudHMgb24gY29tcG9uZW50IHZpYSBldmVudHMgZmFjZXQuXG4gKiBteUNvbXAuZXZlbnRzLm9uKCdtb3VzZWRvd24gbW91c2V1cCcsIG9uTW91c2VVcERvd24pO1xuICogZnVuY3Rpb24gb25Nb3VzZVVwRG93bihldmVudFR5cGUsIGV2ZW50KSB7XG4gKiAgICAgLy8gLi4uXG4gKiB9XG4gKlxuICogbXlDb21wLmRhdGEub24oLy4rLywgZnVuY3Rpb24obXNnLCBkYXRhKSB7XG4gKiAgICAgbG9nZ2VyLmRlYnVnKG1zZywgZGF0YSk7XG4gKiB9KTsgLy8gc3Vic2NyaWJlcyBhbm9ueW1vdXMgZnVuY3Rpb24gdG8gYWxsIG5vbi1lbXB0eSBtZXNzYWdlcyBvbiBkYXRhIGZhY2V0XG4gKiAvLyBpdCB3aWxsIG5vdCBiZSBwb3NzaWJsZSB0byB1bnN1YnNjcmliZSBhbm9ueW1vdXMgc3Vic2NyaWJlciBzZXBhcmF0ZWx5LFxuICogLy8gYnV0IG15Q29tcC5kYXRhLm9mZigvLisvKSB3aWxsIHVuc3Vic2NyaWJlIGl0XG4gKiBgYGBcbiAqIElmIG1lc3NlbmdlciBoYXMgW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgYXR0YWNoZWQgdG8gaXQsIE1lc3NhZ2VTb3VyY2Ugd2lsbCBiZSBub3RpZmllZCB3aGVuIHRoZSBmaXJzdCBzdWJzY3JpYmVyIGZvciBhIGdpdmVuIG1lc3NhZ2UgaXMgYWRkZWQsIHNvIGl0IGNhbiBzdWJzY3JpYmUgdG8gdGhlIHNvdXJjZS5cbiAqIFtDb21wb25lbnRzXSguLi9jb21wb25lbnRzL2NfY2xhc3MuanMuaHRtbCkgYW5kIFtmYWNldHNdKC4uL2NvbXBvbmVudHMvY19mYWNldC5qcy5odG1sKSBjaGFuZ2UgdGhpcyBtZXRob2QgbmFtZSB0byBgb25gIHdoZW4gdGhleSBwcm94eSBpdC5cbiAqIFNlZSBbcG9zdE1lc3NhZ2VdKCNwb3N0TWVzc2FnZSkuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8QXJyYXlbU3RyaW5nXXxSZWdFeHB9IG1lc3NhZ2VzIE1lc3NhZ2UgdHlwZXMgdGhhdCBzaG91bGQgZW52b2tlIHRoZSBzdWJzY3JpYmVyLlxuICogIElmIHN0cmluZyBpcyBwYXNzZWQsIGl0IGNhbiBiZSBhIHNpZ2xlIG1lc3NhZ2Ugb3IgbXVsdGlwbGUgbWVzc2FnZSB0eXBlcyBzZXBhcmF0ZWQgYnkgd2hpdGVzcGFjZSB3aXRoIG9wdGlvbmFsIGNvbW1hcy5cbiAqICBJZiBhbiBhcnJheSBvZiBzdHJpbmdzIGlzIHBhc3NlZCwgZWFjaCBzdHJpbmcgaXMgYSBtZXNzYWdlIHR5cGUgdG8gc3Vic2NyaWJlIGZvci5cbiAqICBJZiBhIFJlZ0V4cCBpcyBwYXNzZWQsIHRoZSBzdWJzY3JpYmVyIHdpbGwgYmUgZW52b2tlZCB3aGVuIHRoZSBtZXNzYWdlIGRpc3BhdGNoZWQgb24gdGhlIG1lc3NlbmdlciBtYXRjaGVzIHRoZSBwYXR0ZXJuIChvciBJUyB0aGUgUmVnRXhwIHdpdGggaWRlbnRpY2FsIHBhdHRlcm4pLlxuICogIFBhdHRlcm4gc3Vic2NyaWJlciBkb2VzIE5PVCBjYXVzZSBhbnkgc3Vic2NyaXB0aW9uIHRvIE1lc3NhZ2VTb3VyY2UsIGl0IG9ubHkgY2FwdHVyZXMgbWVzc2FnZXMgdGhhdCBhcmUgYWxyZWFkeSBzdWJzY3JpYmVkIHRvIHdpdGggcHJlY2lzZSBtZXNzYWdlIHR5cGVzLlxuICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R9IHN1YnNjcmliZXIgTWVzc2FnZSBzdWJzY3JpYmVyIC0gYSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgY2FsbGVkIHdoZW4gdGhlIG1lc3NhZ2UgaXMgZGlzcGF0Y2hlZCBvbiB0aGUgbWVzc2VuZ2VyICh1c3VhbGx5IHZpYSBwcm94aWVkIHBvc3RNZXNzYWdlIG1ldGhvZCBvZiBob3N0IG9iamVjdCkuXG4gKiAgSWYgaG9zdE9iamVjdCB3YXMgc3VwcGxpZWQgdG8gTWVzc2VuZ2VyIGNvbnN0cnVjdG9yLCBob3N0T2JqZWN0IHdpbGwgYmUgdGhlIGNvbnRleHQgKHRoZSB2YWx1ZSBvZiB0aGlzKSBmb3IgdGhlIHN1YnNjcmliZXIgZW52b2NhdGlvbi5cbiAqICBTdWJzY3JpYmVyIGNhbiBhbHNvIGJlIGFuIG9iamVjdCB3aXRoIHByb3BlcnRpZXMgYHN1YnNjcmliZXJgIChmdW5jdGlvbikgYW5kIGBjb250ZXh0YCAoXCJ0aGlzXCIgdmFsdWUgd2hlbiBzdWJzY3JpYmVyIGlzIGNhbGxlZClcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIE1lc3NlbmdlciRvbihtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIHJldHVybiBfTWVzc2VuZ2VyX29uV2l0aE9wdGlvbnMuY2FsbCh0aGlzLCBtZXNzYWdlcywgc3Vic2NyaWJlcik7XG59XG5cblxuZnVuY3Rpb24gTWVzc2VuZ2VyJG9uY2UobWVzc2FnZXMsIHN1YnNjcmliZXIpIHtcbiAgICByZXR1cm4gX01lc3Nlbmdlcl9vbldpdGhPcHRpb25zLmNhbGwodGhpcywgbWVzc2FnZXMsIHN1YnNjcmliZXIsIHsgZGlzcGF0Y2hUaW1lczogMSB9KTtcbn1cblxuZnVuY3Rpb24gTWVzc2VuZ2VyJG9uY2VTeW5jKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKSB7XG4gICAgcmV0dXJuIF9NZXNzZW5nZXJfb25XaXRoT3B0aW9ucy5jYWxsKHRoaXMsIG1lc3NhZ2VzLCBzdWJzY3JpYmVyLCB7IGRpc3BhdGNoVGltZXM6IDEsIHN5bmM6IHRydWUgfSk7XG59XG5cblxuZnVuY3Rpb24gTWVzc2VuZ2VyJG9uU3luYyhtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIHJldHVybiBfTWVzc2VuZ2VyX29uV2l0aE9wdGlvbnMuY2FsbCh0aGlzLCBtZXNzYWdlcywgc3Vic2NyaWJlciwgeyBzeW5jOiB0cnVlIH0pO1xufVxuXG5cbmZ1bmN0aW9uIE1lc3NlbmdlciRvbkFzeW5jKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKSB7XG4gICAgcmV0dXJuIF9NZXNzZW5nZXJfb25XaXRoT3B0aW9ucy5jYWxsKHRoaXMsIG1lc3NhZ2VzLCBzdWJzY3JpYmVyLCB7IHN5bmM6IGZhbHNlIH0pO1xufVxuXG5cbmZ1bmN0aW9uIF9NZXNzZW5nZXJfb25XaXRoT3B0aW9ucyhtZXNzYWdlcywgc3Vic2NyaWJlciwgb3B0aW9ucykge1xuICAgIGNoZWNrKG1lc3NhZ2VzLCBNYXRjaC5PbmVPZihTdHJpbmcsIFtTdHJpbmddLCBSZWdFeHApKTtcbiAgICBjaGVjayhzdWJzY3JpYmVyLCBNYXRjaC5PbmVPZihGdW5jdGlvbiwge1xuICAgICAgICBzdWJzY3JpYmVyOiBGdW5jdGlvbixcbiAgICAgICAgY29udGV4dDogTWF0Y2guQW55LFxuICAgICAgICBvcHRpb25zOiBNYXRjaC5PcHRpb25hbChPYmplY3QpLFxuICAgIH0pKTtcblxuICAgIGlmICh0eXBlb2Ygc3Vic2NyaWJlciA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHN1YnNjcmliZXIgPSB7XG4gICAgICAgICAgICBzdWJzY3JpYmVyOiBzdWJzY3JpYmVyLFxuICAgICAgICAgICAgY29udGV4dDogdGhpcy5faG9zdE9iamVjdCxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAob3B0aW9ucykge1xuICAgICAgICBzdWJzY3JpYmVyLm9wdGlvbnMgPSBzdWJzY3JpYmVyLm9wdGlvbnMgfHwge307XG4gICAgICAgIF8uZXh0ZW5kKHN1YnNjcmliZXIub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIF9NZXNzZW5nZXJfb24uY2FsbCh0aGlzLCBtZXNzYWdlcywgc3Vic2NyaWJlcik7XG59XG5cblxuZnVuY3Rpb24gX01lc3Nlbmdlcl9vbihtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIF8uZGVmaW5lUHJvcGVydHkoc3Vic2NyaWJlciwgJ19fbWVzc2FnZXMnLCBtZXNzYWdlcyk7XG4gICAgcmV0dXJuIF9lYWNoTWVzc2FnZS5jYWxsKHRoaXMsICdfcmVnaXN0ZXJTdWJzY3JpYmVyJywgbWVzc2FnZXMsIHN1YnNjcmliZXIpO1xufVxuXG5cbmZ1bmN0aW9uIF9lYWNoTWVzc2FnZShtZXRob2ROYW1lLCBtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIGlmICh0eXBlb2YgbWVzc2FnZXMgPT0gJ3N0cmluZycpXG4gICAgICAgIG1lc3NhZ2VzID0gbWVzc2FnZXMuc3BsaXQobWVzc2FnZXNTcGxpdFJlZ0V4cCk7XG5cbiAgICB2YXIgc3Vic2NyaWJlcnNIYXNoID0gdGhpcy5fY2hvb3NlU3Vic2NyaWJlcnNIYXNoKG1lc3NhZ2VzKTtcblxuICAgIGlmIChtZXNzYWdlcyBpbnN0YW5jZW9mIFJlZ0V4cClcbiAgICAgICAgcmV0dXJuIHRoaXNbbWV0aG9kTmFtZV0oc3Vic2NyaWJlcnNIYXNoLCBtZXNzYWdlcywgc3Vic2NyaWJlcik7XG5cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIGNoYW5nZWQgPSBmYWxzZTtcblxuICAgICAgICBtZXNzYWdlcy5mb3JFYWNoKGZ1bmN0aW9uKG1lc3NhZ2UpIHtcbiAgICAgICAgICAgIHZhciBzdWJzY3JpcHRpb25DaGFuZ2VkID0gdGhpc1ttZXRob2ROYW1lXShzdWJzY3JpYmVyc0hhc2gsIG1lc3NhZ2UsIHN1YnNjcmliZXIpO1xuICAgICAgICAgICAgY2hhbmdlZCA9IGNoYW5nZWQgfHwgc3Vic2NyaXB0aW9uQ2hhbmdlZDtcbiAgICAgICAgfSwgdGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5nZWQ7XG4gICAgfVxufVxuXG5cbi8qKlxuICogXCJQcml2YXRlXCIgTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZFxuICogSXQgaXMgY2FsbGVkIGJ5IFtvbl0oI01lc3NlbmdlciRvbikgdG8gcmVnaXN0ZXIgc3Vic2NyaWJlciBmb3Igb25lIG1lc3NhZ2UgdHlwZS5cbiAqIFJldHVybnMgYHRydWVgIGlmIHRoaXMgc3Vic2NyaWJlciBpcyBub3QgeWV0IHJlZ2lzdGVyZWQgZm9yIHRoaXMgdHlwZSBvZiBtZXNzYWdlLlxuICogSWYgbWVzc2VuZ2VyIGhhcyBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBhdHRhY2hlZCB0byBpdCwgTWVzc2FnZVNvdXJjZSB3aWxsIGJlIG5vdGlmaWVkIHdoZW4gdGhlIGZpcnN0IHN1YnNjcmliZXIgZm9yIGEgZ2l2ZW4gbWVzc2FnZSBpcyBhZGRlZC5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtPYmplY3R9IHN1YnNjcmliZXJzSGFzaCBUaGUgbWFwIG9mIHN1YnNjcmliZXJzIGRldGVybWluZWQgYnkgW29uXSgjTWVzc2VuZ2VyJG9uKSBiYXNlZCBvbiBNZXNzYWdlIHR5cGUsIGNhbiBiZSBgdGhpcy5fcGF0dGVybk1lc3NhZ2VTdWJzY3JpYmVyc2Agb3IgYHRoaXMuX21lc3NhZ2VTdWJzY3JpYmVyc2BcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIE1lc3NhZ2UgdHlwZVxuICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R9IHN1YnNjcmliZXIgU3Vic2NyaWJlciBmdW5jdGlvbiB0byBiZSBhZGRlZCBvciBvYmplY3Qgd2l0aCBwcm9wZXJ0aWVzIGBzdWJzY3JpYmVyYCAoZnVuY3Rpb24pIGFuZCBgY29udGV4dGAgKHZhbHVlIG9mIFwidGhpc1wiIHdoZW4gc3Vic2NyaWJlciBpcyBjYWxsZWQpXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBfcmVnaXN0ZXJTdWJzY3JpYmVyKHN1YnNjcmliZXJzSGFzaCwgbWVzc2FnZSwgc3Vic2NyaWJlcikge1xuICAgIGlmICghIChzdWJzY3JpYmVyc0hhc2hbbWVzc2FnZV0gJiYgc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdLmxlbmd0aCkpIHtcbiAgICAgICAgc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdID0gW107XG4gICAgICAgIGlmIChtZXNzYWdlIGluc3RhbmNlb2YgUmVnRXhwKVxuICAgICAgICAgICAgc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdLnBhdHRlcm4gPSBtZXNzYWdlO1xuICAgICAgICBpZiAodGhpcy5fbWVzc2FnZVNvdXJjZSlcbiAgICAgICAgICAgIHRoaXMuX21lc3NhZ2VTb3VyY2Uub25TdWJzY3JpYmVyQWRkZWQobWVzc2FnZSk7XG4gICAgICAgIHZhciBub1N1YnNjcmliZXJzID0gdHJ1ZTtcbiAgICB9XG5cbiAgICB2YXIgbXNnU3Vic2NyaWJlcnMgPSBzdWJzY3JpYmVyc0hhc2hbbWVzc2FnZV07XG4gICAgdmFyIG5vdFlldFJlZ2lzdGVyZWQgPSBub1N1YnNjcmliZXJzIHx8IF9pbmRleE9mU3Vic2NyaWJlci5jYWxsKHRoaXMsIG1zZ1N1YnNjcmliZXJzLCBzdWJzY3JpYmVyKSA9PSAtMTtcblxuICAgIGlmIChub3RZZXRSZWdpc3RlcmVkKVxuICAgICAgICBtc2dTdWJzY3JpYmVycy5wdXNoKHN1YnNjcmliZXIpO1xuXG4gICAgcmV0dXJuIG5vdFlldFJlZ2lzdGVyZWQ7XG59XG5cblxuLyoqXG4gKiBGaW5kcyBzdWJzY3JpYmVyIGluZGV4IGluIHRoZSBsaXN0XG4gKlxuICogQHBhcmFtIHtBcnJheVtGdW5jdGlvbnxPYmplY3RdfSBsaXN0IGxpc3Qgb2Ygc3Vic2NyaWJlcnNcbiAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fSBzdWJzY3JpYmVyIHN1YnNjcmliZXIgZnVuY3Rpb24gb3Igb2JqZWN0IHdpdGggcHJvcGVydGllcyBgc3Vic2NyaWJlcmAgKGZ1bmN0aW9uKSBhbmQgYGNvbnRleHRgIChcInRoaXNcIiBvYmplY3QpXG4gKi9cbmZ1bmN0aW9uIF9pbmRleE9mU3Vic2NyaWJlcihsaXN0LCBzdWJzY3JpYmVyKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHJldHVybiBfLmZpbmRJbmRleChsaXN0LCBmdW5jdGlvbihzdWJzY3Ipe1xuICAgICAgICByZXR1cm4gc3Vic2NyaWJlci5zdWJzY3JpYmVyID09IHN1YnNjci5zdWJzY3JpYmVyXG4gICAgICAgICAgICAgICAgJiYgc3Vic2NyaWJlci5jb250ZXh0ID09IHN1YnNjci5jb250ZXh0XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogU3Vic2NyaWJlcyB0byBtdWx0aXBsZSBtZXNzYWdlcyBwYXNzZWQgYXMgbWFwIHRvZ2V0aGVyIHdpdGggc3Vic2NyaWJlcnMuXG4gKiBVc2FnZTpcbiAqIGBgYFxuICogbXlDb21wLmV2ZW50cy5vbk1lc3NhZ2VzKHtcbiAqICAgICAnbW91c2Vkb3duJzogb25Nb3VzZURvd24sXG4gKiAgICAgJ21vdXNldXAnOiBvbk1vdXNlVXBcbiAqIH0pO1xuICogZnVuY3Rpb24gb25Nb3VzZURvd24oZXZlbnRUeXBlLCBldmVudCkge31cbiAqIGZ1bmN0aW9uIG9uTW91c2VVcChldmVudFR5cGUsIGV2ZW50KSB7fVxuICogYGBgXG4gKiBSZXR1cm5zIG1hcCB3aXRoIHRoZSBzYW1lIGtleXMgKG1lc3NhZ2UgdHlwZXMpIGFuZCBib29sZWFuIHZhbHVlcyBpbmRpY2F0aW5nIHdoZXRoZXIgcGFydGljdWxhciBzdWJzY3JpYmVyIHdhcyBhZGRlZC5cbiAqIEl0IGlzIE5PVCBwb3NzaWJsZSB0byBhZGQgcGF0dGVybiBzdWJzY3JpYmVyIHVzaW5nIHRoaXMgbWV0aG9kLCBhcyBhbHRob3VnaCB5b3UgY2FuIHVzZSBSZWdFeHAgYXMgdGhlIGtleSwgSmF2YVNjcmlwdCB3aWxsIGF1dG9tYXRpY2FsbHkgY29udmVydCBpdCB0byBzdHJpbmcuXG4gKlxuICogQHBhcmFtIHtPYmplY3RbRnVuY3Rpb25dfSBtZXNzYWdlU3Vic2NyaWJlcnMgTWFwIG9mIG1lc3NhZ2Ugc3Vic2NyaWJlcnMgdG8gYmUgYWRkZWRcbiAqIEByZXR1cm4ge09iamVjdFtCb29sZWFuXX1cbiAqL1xuZnVuY3Rpb24gb25NZXNzYWdlcyhtZXNzYWdlU3Vic2NyaWJlcnMpIHtcbiAgICBjaGVjayhtZXNzYWdlU3Vic2NyaWJlcnMsIE1hdGNoLk9iamVjdEhhc2goTWF0Y2guT25lT2YoRnVuY3Rpb24sIHsgc3Vic2NyaWJlcjogRnVuY3Rpb24sIGNvbnRleHQ6IE1hdGNoLkFueSB9KSkpO1xuXG4gICAgdmFyIG5vdFlldFJlZ2lzdGVyZWRNYXAgPSBfLm1hcEtleXMobWVzc2FnZVN1YnNjcmliZXJzLCBmdW5jdGlvbihzdWJzY3JpYmVyLCBtZXNzYWdlcykge1xuICAgICAgICByZXR1cm4gdGhpcy5vbihtZXNzYWdlcywgc3Vic2NyaWJlcik7XG4gICAgfSwgdGhpcyk7XG5cbiAgICByZXR1cm4gbm90WWV0UmVnaXN0ZXJlZE1hcDtcbn1cblxuXG4vKipcbiAqIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2QuXG4gKiBSZW1vdmVzIGEgc3Vic2NyaWJlciBmb3IgbWVzc2FnZShzKS4gUmVtb3ZlcyBhbGwgc3Vic2NyaWJlcnMgZm9yIHRoZSBtZXNzYWdlIGlmIHN1YnNjcmliZXIgaXNuJ3QgcGFzc2VkLlxuICogVGhpcyBtZXRob2QgcmV0dXJucyBgdHJ1ZWAgaWYgdGhlIHN1YnNjcmliZXIgd2FzIHJlZ2lzdGVyZWQuIE5vIGVycm9yIG9yIHdhcm5pbmcgaXMgdGhyb3duIG9yIGxvZ2dlZCBpZiB5b3UgcmVtb3ZlIHN1YnNjcmliZXIgdGhhdCB3YXMgbm90IHJlZ2lzdGVyZWQuXG4gKiBbQ29tcG9uZW50c10oLi4vY29tcG9uZW50cy9jX2NsYXNzLmpzLmh0bWwpIGFuZCBbZmFjZXRzXSguLi9jb21wb25lbnRzL2NfZmFjZXQuanMuaHRtbCkgY2hhbmdlIHRoaXMgbWV0aG9kIG5hbWUgdG8gYG9mZmAgd2hlbiB0aGV5IHByb3h5IGl0LlxuICogVXNhZ2U6XG4gKiBgYGBcbiAqIC8vIHVuc3Vic2NyaWJlcyBvbk1vdXNlVXBEb3duIGZyb20gdHdvIERPTSBldmVudHMuXG4gKiBteUNvbXAuZXZlbnRzLm9mZignbW91c2Vkb3duIG1vdXNldXAnLCBvbk1vdXNlVXBEb3duKTtcbiAqIGBgYFxuICogSWYgbWVzc2VuZ2VyIGhhcyBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBhdHRhY2hlZCB0byBpdCwgTWVzc2FnZVNvdXJjZSB3aWxsIGJlIG5vdGlmaWVkIHdoZW4gdGhlIGxhc3Qgc3Vic2NyaWJlciBmb3IgYSBnaXZlbiBtZXNzYWdlIGlzIHJlbW92ZWQgYW5kIHRoZXJlIGlzIG5vIG1vcmUgc3Vic2NyaWJlcnMgZm9yIHRoaXMgbWVzc2FnZS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ3xBcnJheVtTdHJpbmddfFJlZ0V4cH0gbWVzc2FnZXMgTWVzc2FnZSB0eXBlcyB0aGF0IGEgc3Vic2NyaWJlciBzaG91bGQgYmUgcmVtb3ZlZCBmb3IuXG4gKiAgSWYgc3RyaW5nIGlzIHBhc3NlZCwgaXQgY2FuIGJlIGEgc2lnbGUgbWVzc2FnZSBvciBtdWx0aXBsZSBtZXNzYWdlIHR5cGVzIHNlcGFyYXRlZCBieSB3aGl0ZXNwYWNlIHdpdGggb3B0aW9uYWwgY29tbWFzLlxuICogIElmIGFuIGFycmF5IG9mIHN0cmluZ3MgaXMgcGFzc2VkLCBlYWNoIHN0cmluZyBpcyBhIG1lc3NhZ2UgdHlwZSB0byByZW1vdmUgYSBzdWJzY3JpYmVyIGZvci5cbiAqICBJZiBhIFJlZ0V4cCBpcyBwYXNzZWQsIHRoZSBwYXR0ZXJuIHN1YnNjcmliZXIgd2lsbCBiZSByZW1vdmVkLlxuICogIFJlZ0V4cCBzdWJzY3JpYmVyIGRvZXMgTk9UIGNhdXNlIGFueSBzdWJzY3JpcHRpb24gdG8gTWVzc2FnZVNvdXJjZSwgaXQgb25seSBjYXB0dXJlcyBtZXNzYWdlcyB0aGF0IGFyZSBhbHJlYWR5IHN1YnNjcmliZWQgdG8gd2l0aCBwcmVjaXNlIG1lc3NhZ2UgdHlwZXMuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzdWJzY3JpYmVyIE1lc3NhZ2Ugc3Vic2NyaWJlciAtIE9wdGlvbmFsIGZ1bmN0aW9uIHRoYXQgd2lsbCBiZSByZW1vdmVkIGZyb20gdGhlIGxpc3Qgb2Ygc3Vic2NyaWJlcnMgZm9yIHRoZSBtZXNzYWdlKHMpLiBJZiBzdWJzY3JpYmVyIGlzIG5vdCBzdXBwbGllZCwgYWxsIHN1YnNjcmliZXJzIHdpbGwgYmUgcmVtb3ZlZCBmcm9tIHRoaXMgbWVzc2FnZShzKS5cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIE1lc3NlbmdlciRvZmYobWVzc2FnZXMsIHN1YnNjcmliZXIpIHtcbiAgICBjaGVjayhtZXNzYWdlcywgTWF0Y2guT25lT2YoU3RyaW5nLCBbU3RyaW5nXSwgUmVnRXhwKSk7XG4gICAgY2hlY2soc3Vic2NyaWJlciwgTWF0Y2guT3B0aW9uYWwoTWF0Y2guT25lT2YoRnVuY3Rpb24sIHtcbiAgICAgICAgc3Vic2NyaWJlcjogRnVuY3Rpb24sXG4gICAgICAgIGNvbnRleHQ6IE1hdGNoLkFueSxcbiAgICAgICAgb3B0aW9uczogTWF0Y2guT3B0aW9uYWwoT2JqZWN0KSxcbiAgICAgICAgLy8gX19tZXNzYWdlczogTWF0Y2guT3B0aW9uYWwoTWF0Y2guT25lT2YoU3RyaW5nLCBbU3RyaW5nXSwgUmVnRXhwKSlcbiAgICB9KSkpO1xuXG4gICAgcmV0dXJuIF9NZXNzZW5nZXJfb2ZmLmNhbGwodGhpcywgbWVzc2FnZXMsIHN1YnNjcmliZXIpO1xufVxuXG5cbmZ1bmN0aW9uIF9NZXNzZW5nZXJfb2ZmKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKSB7XG4gICAgcmV0dXJuIF9lYWNoTWVzc2FnZS5jYWxsKHRoaXMsICdfcmVtb3ZlU3Vic2NyaWJlcicsIG1lc3NhZ2VzLCBzdWJzY3JpYmVyKTtcbn1cblxuXG4vKipcbiAqIFwiUHJpdmF0ZVwiIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2RcbiAqIEl0IGlzIGNhbGxlZCBieSBbb2ZmXSgjTWVzc2VuZ2VyJG9mZikgdG8gcmVtb3ZlIHN1YnNjcmliZXIgZm9yIG9uZSBtZXNzYWdlIHR5cGUuXG4gKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGlzIHN1YnNjcmliZXIgd2FzIHJlZ2lzdGVyZWQgZm9yIHRoaXMgdHlwZSBvZiBtZXNzYWdlLlxuICogSWYgbWVzc2VuZ2VyIGhhcyBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBhdHRhY2hlZCB0byBpdCwgTWVzc2FnZVNvdXJjZSB3aWxsIGJlIG5vdGlmaWVkIHdoZW4gdGhlIGxhc3Qgc3Vic2NyaWJlciBmb3IgYSBnaXZlbiBtZXNzYWdlIGlzIHJlbW92ZWQgYW5kIHRoZXJlIGlzIG5vIG1vcmUgc3Vic2NyaWJlcnMgZm9yIHRoaXMgbWVzc2FnZS5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtPYmplY3R9IHN1YnNjcmliZXJzSGFzaCBUaGUgbWFwIG9mIHN1YnNjcmliZXJzIGRldGVybWluZWQgYnkgW29mZl0oI01lc3NlbmdlciRvZmYpIGJhc2VkIG9uIG1lc3NhZ2UgdHlwZSwgY2FuIGJlIGB0aGlzLl9wYXR0ZXJuTWVzc2FnZVN1YnNjcmliZXJzYCBvciBgdGhpcy5fbWVzc2FnZVN1YnNjcmliZXJzYFxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgTWVzc2FnZSB0eXBlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzdWJzY3JpYmVyIFN1YnNjcmliZXIgZnVuY3Rpb24gdG8gYmUgcmVtb3ZlZFxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gX3JlbW92ZVN1YnNjcmliZXIoc3Vic2NyaWJlcnNIYXNoLCBtZXNzYWdlLCBzdWJzY3JpYmVyKSB7XG4gICAgdmFyIG1zZ1N1YnNjcmliZXJzID0gc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdO1xuICAgIGlmICghIG1zZ1N1YnNjcmliZXJzIHx8ICEgbXNnU3Vic2NyaWJlcnMubGVuZ3RoKVxuICAgICAgICByZXR1cm4gZmFsc2U7IC8vIG5vdGhpbmcgcmVtb3ZlZFxuXG4gICAgaWYgKHN1YnNjcmliZXIpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBzdWJzY3JpYmVyID09ICdmdW5jdGlvbicpXG4gICAgICAgICAgICBzdWJzY3JpYmVyID0geyBzdWJzY3JpYmVyOiBzdWJzY3JpYmVyLCBjb250ZXh0OiB0aGlzLl9ob3N0T2JqZWN0IH07XG5cbiAgICAgICAgdmFyIHN1YnNjcmliZXJJbmRleCA9IF9pbmRleE9mU3Vic2NyaWJlci5jYWxsKHRoaXMsIG1zZ1N1YnNjcmliZXJzLCBzdWJzY3JpYmVyKTtcbiAgICAgICAgaWYgKHN1YnNjcmliZXJJbmRleCA9PSAtMSlcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTsgLy8gbm90aGluZyByZW1vdmVkXG4gICAgICAgIG1zZ1N1YnNjcmliZXJzLnNwbGljZShzdWJzY3JpYmVySW5kZXgsIDEpO1xuICAgICAgICBpZiAoISBtc2dTdWJzY3JpYmVycy5sZW5ndGgpXG4gICAgICAgICAgICB0aGlzLl9yZW1vdmVBbGxTdWJzY3JpYmVycyhzdWJzY3JpYmVyc0hhc2gsIG1lc3NhZ2UpO1xuXG4gICAgfSBlbHNlXG4gICAgICAgIHRoaXMuX3JlbW92ZUFsbFN1YnNjcmliZXJzKHN1YnNjcmliZXJzSGFzaCwgbWVzc2FnZSk7XG5cbiAgICByZXR1cm4gdHJ1ZTsgLy8gc3Vic2NyaWJlcihzKSByZW1vdmVkXG59XG5cblxuLyoqXG4gKiBcIlByaXZhdGVcIiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBJdCBpcyBjYWxsZWQgYnkgW19yZW1vdmVTdWJzY3JpYmVyXSgjX3JlbW92ZVN1YnNjcmliZXIpIHRvIHJlbW92ZSBhbGwgc3Vic2NyaWJlcnMgZm9yIG9uZSBtZXNzYWdlIHR5cGUuXG4gKiBJZiBtZXNzZW5nZXIgaGFzIFtNZXNzYWdlU291cmNlXSguL21fc291cmNlLmpzLmh0bWwpIGF0dGFjaGVkIHRvIGl0LCBNZXNzYWdlU291cmNlIHdpbGwgYmUgbm90aWZpZWQgdGhhdCBhbGwgbWVzc2FnZSBzdWJzY3JpYmVycyB3ZXJlIHJlbW92ZWQgc28gaXQgY2FuIHVuc3Vic2NyaWJlIGZyb20gdGhlIHNvdXJjZS5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtPYmplY3R9IHN1YnNjcmliZXJzSGFzaCBUaGUgbWFwIG9mIHN1YnNjcmliZXJzIGRldGVybWluZWQgYnkgW29mZl0oI01lc3NlbmdlciRvZmYpIGJhc2VkIG9uIG1lc3NhZ2UgdHlwZSwgY2FuIGJlIGB0aGlzLl9wYXR0ZXJuTWVzc2FnZVN1YnNjcmliZXJzYCBvciBgdGhpcy5fbWVzc2FnZVN1YnNjcmliZXJzYFxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgTWVzc2FnZSB0eXBlXG4gKi9cbmZ1bmN0aW9uIF9yZW1vdmVBbGxTdWJzY3JpYmVycyhzdWJzY3JpYmVyc0hhc2gsIG1lc3NhZ2UpIHtcbiAgICBkZWxldGUgc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdO1xuICAgIGlmICh0aGlzLl9tZXNzYWdlU291cmNlICYmIHR5cGVvZiBtZXNzYWdlID09ICdzdHJpbmcnKVxuICAgICAgICB0aGlzLl9tZXNzYWdlU291cmNlLm9uU3Vic2NyaWJlclJlbW92ZWQobWVzc2FnZSk7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogVW5zdWJzY3JpYmVzIGZyb20gbXVsdGlwbGUgbWVzc2FnZXMgcGFzc2VkIGFzIG1hcCB0b2dldGhlciB3aXRoIHN1YnNjcmliZXJzLlxuICogUmV0dXJucyBtYXAgd2l0aCB0aGUgc2FtZSBrZXlzIChtZXNzYWdlIHR5cGVzKSBhbmQgYm9vbGVhbiB2YWx1ZXMgaW5kaWNhdGluZyB3aGV0aGVyIHBhcnRpY3VsYXIgc3Vic2NyaWJlciB3YXMgcmVtb3ZlZC5cbiAqIElmIGEgc3Vic2NyaWJlciBmb3Igb25lIG9mIHRoZSBtZXNzYWdlcyBpcyBub3Qgc3VwcGxpZWQsIGFsbCBzdWJzY3JpYmVycyBmb3IgdGhpcyBtZXNzYWdlIHdpbGwgYmUgcmVtb3ZlZC5cbiAqIFVzYWdlOlxuICogYGBgXG4gKiBteUNvbXAuZXZlbnRzLm9mZk1lc3NhZ2VzKHtcbiAqICAgICAnbW91c2Vkb3duJzogb25Nb3VzZURvd24sXG4gKiAgICAgJ21vdXNldXAnOiBvbk1vdXNlVXAsXG4gKiAgICAgJ2NsaWNrJzogdW5kZWZpbmVkIC8vIGFsbCBzdWJzY3JpYmVycyB0byB0aGlzIG1lc3NhZ2Ugd2lsbCBiZSByZW1vdmVkXG4gKiB9KTtcbiAqIGBgYFxuICogSXQgaXMgTk9UIHBvc3NpYmxlIHRvIHJlbW92ZSBwYXR0ZXJuIHN1YnNjcmliZXIocykgdXNpbmcgdGhpcyBtZXRob2QsIGFzIGFsdGhvdWdoIHlvdSBjYW4gdXNlIFJlZ0V4cCBhcyB0aGUga2V5LCBKYXZhU2NyaXB0IHdpbGwgYXV0b21hdGljYWxseSBjb252ZXJ0IGl0IHRvIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdFtGdW5jdGlvbl19IG1lc3NhZ2VTdWJzY3JpYmVycyBNYXAgb2YgbWVzc2FnZSBzdWJzY3JpYmVycyB0byBiZSByZW1vdmVkXG4gKiBAcmV0dXJuIHtPYmplY3RbQm9vbGVhbl19XG4gKi9cbmZ1bmN0aW9uIG9mZk1lc3NhZ2VzKG1lc3NhZ2VTdWJzY3JpYmVycykge1xuICAgIGNoZWNrKG1lc3NhZ2VTdWJzY3JpYmVycywgTWF0Y2guT2JqZWN0SGFzaChNYXRjaC5PcHRpb25hbChNYXRjaC5PbmVPZihGdW5jdGlvbiwgeyBzdWJzY3JpYmVyOiBGdW5jdGlvbiwgY29udGV4dDogTWF0Y2guQW55IH0pKSkpO1xuXG4gICAgdmFyIHN1YnNjcmliZXJSZW1vdmVkTWFwID0gXy5tYXBLZXlzKG1lc3NhZ2VTdWJzY3JpYmVycywgZnVuY3Rpb24oc3Vic2NyaWJlciwgbWVzc2FnZXMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub2ZmKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKTtcbiAgICB9LCB0aGlzKTtcblxuICAgIHJldHVybiBzdWJzY3JpYmVyUmVtb3ZlZE1hcDtcbn1cblxuXG4vKipcbiAqIFVuc3Vic2NyaWJlcyBhbGwgc3Vic2NyaWJlcnNcbiAqL1xuZnVuY3Rpb24gTWVzc2VuZ2VyJG9mZkFsbCgpIHtcbiAgICBfb2ZmQWxsU3Vic2NyaWJlcnMuY2FsbCh0aGlzLCB0aGlzLl9wYXR0ZXJuTWVzc2FnZVN1YnNjcmliZXJzKTtcbiAgICBfb2ZmQWxsU3Vic2NyaWJlcnMuY2FsbCh0aGlzLCB0aGlzLl9tZXNzYWdlU3Vic2NyaWJlcnMpO1xufVxuXG5cbmZ1bmN0aW9uIF9vZmZBbGxTdWJzY3JpYmVycyhzdWJzY3JpYmVyc0hhc2gpIHtcbiAgICBfLmVhY2hLZXkoc3Vic2NyaWJlcnNIYXNoLCBmdW5jdGlvbihzdWJzY3JpYmVycywgbWVzc2FnZSkge1xuICAgICAgICB0aGlzLl9yZW1vdmVBbGxTdWJzY3JpYmVycyhzdWJzY3JpYmVyc0hhc2gsIG1lc3NhZ2UpO1xuICAgIH0sIHRoaXMpO1xufVxuXG5cbi8vIFRPRE8gLSBzZW5kIGV2ZW50IHRvIG1lc3NhZ2VTb3VyY2VcblxuXG4vKipcbiAqIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2QuXG4gKiBEaXNwYXRjaGVzIHRoZSBtZXNzYWdlIGNhbGxpbmcgYWxsIHN1YnNjcmliZXJzIHJlZ2lzdGVyZWQgZm9yIHRoaXMgbWVzc2FnZSBhbmQsIGlmIHRoZSBtZXNzYWdlIGlzIGEgc3RyaW5nLCBjYWxsaW5nIGFsbCBwYXR0ZXJuIHN1YnNjcmliZXJzIHdoZW4gbWVzc2FnZSBtYXRjaGVzIHRoZSBwYXR0ZXJuLlxuICogRWFjaCBzdWJzY3JpYmVyIGlzIHBhc3NlZCB0aGUgc2FtZSBwYXJhbWV0ZXJzIHRoYXQgYXJlIHBhc3NlZCB0byB0aGVpcyBtZXRob2QuXG4gKiBUaGUgY29udGV4dCBvZiB0aGUgc3Vic2NyaWJlciBlbnZvY2F0aW9uIGlzIHNldCB0byB0aGUgaG9zdCBvYmplY3QgKGB0aGlzLl9ob3N0T2JqZWN0YCkgdGhhdCB3YXMgcGFzc2VkIHRvIHRoZSBtZXNzZW5nZXIgY29uc3RydWN0b3IuXG4gKiBTdWJzY3JpYmVycyBhcmUgY2FsbGVkIGluIHRoZSBuZXh0IHRpY2sgKFwiYXN5bmNocm9ub3VzbHlcIikgYXBhcnQgZnJvbSB0aG9zZSB0aGF0IHdlcmUgc3Vic2NyaWJlZCB3aXRoIGBvblN5bmNgIChvciB0aGF0IGhhdmUgYG9wdGlvbnMuc3luYyA9PSB0cnVlYCkuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBtZXNzYWdlIG1lc3NhZ2UgdG8gYmUgZGlzcGF0Y2hlZFxuICogIElmIHRoZSBtZXNzYWdlIGlzIGEgc3RyaW5nLCB0aGUgc3Vic2NyaWJlcnMgcmVnaXN0ZXJlZCB3aXRoIGV4YWN0bHkgdGhpcyBtZXNzYWdlIHdpbGwgYmUgY2FsbGVkIGFuZCBhbHNvIHBhdHRlcm4gc3Vic2NyaWJlcnMgcmVnaXN0ZXJlZCB3aXRoIHRoZSBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyB0aGUgZGlzcGF0Y2hlZCBtZXNzYWdlLlxuICogIElmIHRoZSBtZXNzYWdlIGlzIFJlZ0V4cCwgb25seSB0aGUgc3Vic2NyaWJlcnMgcmVnaXN0ZXJlZCB3aXRoIGV4YWN0bHkgdGhpcyBwYXR0ZXJuIHdpbGwgYmUgY2FsbGVkLlxuICogQHBhcmFtIHtBbnl9IGRhdGEgZGF0YSB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBzdWJzY3JpYmVyIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyLiBNZXNzZW5nZXIgZG9lcyBub3QgbW9kaWZ5IHRoaXMgZGF0YSBpbiBhbnkgd2F5LlxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgb3B0aW9uYWwgY2FsbGJhY2sgdG8gcGFzcyB0byBzdWJzY3JpYmVyXG4gKiBAcGFyYW0ge0Jvb2xlYW59IF9zeW5jaHJvbm91cyBpZiB0cnVlIHBhc3NlZCwgc3Vic2NyaWJlcnMgd2lsbCBiZSBlbnZva2VkIHN5bmNocm9ub3VzbHkgYXBhcnQgZnJvbSB0aG9zZSB0aGF0IGhhdmUgYG9wdGlvbnMuc3luYyA9PSBmYWxzZWAuIFRoaXMgcGFyYW1ldGVyIHNob3VsZCBub3QgYmUgdXNlZCwgaW5zdGVhZCBwb3N0TWVzc2FnZVN5bmMgc2hvdWxkIGJlIHVzZWQuXG4gKi9cbmZ1bmN0aW9uIHBvc3RNZXNzYWdlKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCBfc3luY2hyb25vdXMpIHtcbiAgICBjaGVjayhtZXNzYWdlLCBNYXRjaC5PbmVPZihTdHJpbmcsIFJlZ0V4cCkpO1xuICAgIGNoZWNrKGNhbGxiYWNrLCBNYXRjaC5PcHRpb25hbChGdW5jdGlvbikpO1xuXG4gICAgdmFyIHN1YnNjcmliZXJzSGFzaCA9IHRoaXMuX2Nob29zZVN1YnNjcmliZXJzSGFzaChtZXNzYWdlKTtcbiAgICB2YXIgbXNnU3Vic2NyaWJlcnMgPSBzdWJzY3JpYmVyc0hhc2hbbWVzc2FnZV07XG5cbiAgICB0aGlzLl9jYWxsU3Vic2NyaWJlcnMobWVzc2FnZSwgZGF0YSwgY2FsbGJhY2ssIG1zZ1N1YnNjcmliZXJzLCBfc3luY2hyb25vdXMpO1xuXG4gICAgaWYgKHR5cGVvZiBtZXNzYWdlID09ICdzdHJpbmcnKVxuICAgICAgICB0aGlzLl9jYWxsUGF0dGVyblN1YnNjcmliZXJzKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCBtc2dTdWJzY3JpYmVycywgX3N5bmNocm9ub3VzKTtcbn1cblxuXG4vKipcbiAqIFNhbWUgYXMgcG9zdE1lc3NhZ2UgYXBhcnQgZnJvbSBlbnZva2luZyBzdWJzY3JpYmVycyBzeW5jaHJvbm91c2x5LCBhcGFydCBmcm9tIHRob3NlIHN1YnNjcmliZWQgd2l0aCBgb25Bc3luY2AgKG9yIHdpdGggYG9wdGlvbnMuc3luYyA9PSBmYWxzZWApLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gbWVzc2FnZVxuICogQHBhcmFtIHtBbnl9IGRhdGFcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gKi9cbmZ1bmN0aW9uIHBvc3RNZXNzYWdlU3luYyhtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaykge1xuICAgIHRoaXMucG9zdE1lc3NhZ2UobWVzc2FnZSwgZGF0YSwgY2FsbGJhY2ssIHRydWUpO1xufVxuXG5cbi8qKlxuICogXCJQcml2YXRlXCIgTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZFxuICogRW52b2tlcyBwYXR0ZXJuIHN1YnNjcmliZXJzIHdpdGggdGhlIHBhdHRlcm4gdGhhdCBtYXRjaGVzIHRoZSBtZXNzYWdlLlxuICogVGhlIG1ldGhvZCBpcyBjYWxsZWQgYnkgW3Bvc3RNZXNzYWdlXSgjcG9zdE1lc3NhZ2UpIC0gc2VlIG1vcmUgaW5mb3JtYXRpb24gdGhlcmUuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIG1lc3NhZ2UgdG8gYmUgZGlzcGF0Y2hlZC4gUGF0dGVybiBzdWJzY3JpYmVycyByZWdpc3RlcmVkIHdpdGggdGhlIHBhdHRlcm4gdGhhdCBtYXRjaGVzIHRoZSBkaXNwYXRjaGVkIG1lc3NhZ2Ugd2lsbCBiZSBjYWxsZWQuXG4gKiBAcGFyYW0ge0FueX0gZGF0YSBkYXRhIHRoYXQgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIHN1YnNjcmliZXIgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXIuIE1lc3NlbmdlciBkb2VzIG5vdCBtb2RpZnkgdGhpcyBkYXRhIGluIGFueSB3YXkuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBvcHRpb25hbCBjYWxsYmFjayB0byBwYXNzIHRvIHN1YnNjcmliZXJcbiAqIEBwYXJhbSB7QXJyYXlbRnVuY3Rpb258T2JqZWN0XX0gY2FsbGVkTXNnU3Vic2NyaWJlcnMgYXJyYXkgb2Ygc3Vic2NyaWJlcnMgYWxyZWFkeSBjYWxsZWQsIHRoZXkgd29uJ3QgYmUgY2FsbGVkIGFnYWluIGlmIHRoZXkgYXJlIGFtb25nIHBhdHRlcm4gc3Vic2NyaWJlcnMuXG4gKi9cbmZ1bmN0aW9uIF9jYWxsUGF0dGVyblN1YnNjcmliZXJzKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCBjYWxsZWRNc2dTdWJzY3JpYmVycywgX3N5bmNocm9ub3VzKSB7XG4gICAgXy5lYWNoS2V5KHRoaXMuX3BhdHRlcm5NZXNzYWdlU3Vic2NyaWJlcnMsXG4gICAgICAgIGZ1bmN0aW9uKHBhdHRlcm5TdWJzY3JpYmVycykge1xuICAgICAgICAgICAgdmFyIHBhdHRlcm4gPSBwYXR0ZXJuU3Vic2NyaWJlcnMucGF0dGVybjtcbiAgICAgICAgICAgIGlmIChwYXR0ZXJuLnRlc3QobWVzc2FnZSkpIHtcbiAgICAgICAgICAgICAgICBpZiAoY2FsbGVkTXNnU3Vic2NyaWJlcnMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhdHRlcm5TdWJzY3JpYmVycyA9IHBhdHRlcm5TdWJzY3JpYmVycy5maWx0ZXIoZnVuY3Rpb24oc3Vic2NyaWJlcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGluZGV4ID0gX2luZGV4T2ZTdWJzY3JpYmVyLmNhbGwodGhpcywgY2FsbGVkTXNnU3Vic2NyaWJlcnMsIHN1YnNjcmliZXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGluZGV4ID09IC0xO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5fY2FsbFN1YnNjcmliZXJzKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCBwYXR0ZXJuU3Vic2NyaWJlcnMsIF9zeW5jaHJvbm91cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAsIHRoaXMpO1xufVxuXG5cbi8qKlxuICogXCJQcml2YXRlXCIgTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZFxuICogRW52b2tlcyBzdWJzY3JpYmVycyBmcm9tIHRoZSBwYXNzZWQgbGlzdC5cbiAqIFRoZSBtZXRob2QgaXMgY2FsbGVkIGJ5IFtwb3N0TWVzc2FnZV0oI3Bvc3RNZXNzYWdlKSBhbmQgW19jYWxsUGF0dGVyblN1YnNjcmliZXJzXSgjX2NhbGxQYXR0ZXJuU3Vic2NyaWJlcnMpLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBtZXNzYWdlIHRvIGJlIGRpc3BhdGNoZWQsIHBhc3NlZCB0byBzdWJzY3JpYmVycyBhcyB0aGUgZmlyc3QgcGFyYW1ldGVyLlxuICogQHBhcmFtIHtBbnl9IGRhdGEgZGF0YSB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBzdWJzY3JpYmVyIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyLiBNZXNzZW5nZXIgZG9lcyBub3QgbW9kaWZ5IHRoaXMgZGF0YSBpbiBhbnkgd2F5LlxuICogQHBhcmFtIHtBcnJheVtGdW5jdGlvbnxPYmplY3RdfSBtc2dTdWJzY3JpYmVycyB0aGUgYXJyYXkgb2YgbWVzc2FnZSBzdWJzY3JpYmVycyB0byBiZSBjYWxsZWQuIEVhY2ggc3Vic2NyaWJlciBpcyBjYWxsZWQgd2l0aCB0aGUgaG9zdCBvYmplY3QgKHNlZSBNZXNzZW5nZXIgY29uc3RydWN0b3IpIGFzIHRoZSBjb250ZXh0LlxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgb3B0aW9uYWwgY2FsbGJhY2sgdG8gcGFzcyB0byBzdWJzY3JpYmVyXG4gKi9cbmZ1bmN0aW9uIF9jYWxsU3Vic2NyaWJlcnMobWVzc2FnZSwgZGF0YSwgY2FsbGJhY2ssIG1zZ1N1YnNjcmliZXJzLCBfc3luY2hyb25vdXMpIHtcbiAgICBpZiAobXNnU3Vic2NyaWJlcnMgJiYgbXNnU3Vic2NyaWJlcnMubGVuZ3RoKSB7XG4gICAgICAgIC8vIGNsb25pbmcgaXMgbmVjZXNzYXJ5IGFzIHNvbWUgb2YgdGhlIHN1YnNjcmliZXJzXG4gICAgICAgIC8vIGNhbiBiZSB1bnN1YnNjcmliZWQgZHVyaW5nIHRoZSBkaXNwYXRjaFxuICAgICAgICAvLyBzbyB0aGlzIGFycmF5IHdvdWxkIGNoYW5nZSBpbiB0aGUgcHJvY2Vzc1xuICAgICAgICBtc2dTdWJzY3JpYmVycyA9IG1zZ1N1YnNjcmliZXJzLnNsaWNlKCk7XG5cbiAgICAgICAgbXNnU3Vic2NyaWJlcnMuZm9yRWFjaChmdW5jdGlvbihzdWJzY3JpYmVyKSB7XG4gICAgICAgICAgICB0aGlzLl9jYWxsU3Vic2NyaWJlcihzdWJzY3JpYmVyLCBtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaywgX3N5bmNocm9ub3VzKTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIF9jYWxsU3Vic2NyaWJlcihzdWJzY3JpYmVyLCBtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaywgX3N5bmNocm9ub3VzKSB7XG4gICAgdmFyIHN5bmNTdWJzY3JpYmVyID0gc3Vic2NyaWJlci5vcHRpb25zICYmIHN1YnNjcmliZXIub3B0aW9ucy5zeW5jXG4gICAgICAgICwgc3luY2hybyA9IChfc3luY2hyb25vdXMgJiYgc3luY1N1YnNjcmliZXIgIT09IGZhbHNlKVxuICAgICAgICAgICAgICAgICAgfHwgc3luY1N1YnNjcmliZXI7XG5cbiAgICB2YXIgZGlzcGF0Y2hUaW1lcyA9IHN1YnNjcmliZXIub3B0aW9ucyAmJiBzdWJzY3JpYmVyLm9wdGlvbnMuZGlzcGF0Y2hUaW1lcztcbiAgICBpZiAoZGlzcGF0Y2hUaW1lcykge1xuICAgICAgICBpZiAoZGlzcGF0Y2hUaW1lcyA8PSAxKSB7XG4gICAgICAgICAgICB2YXIgbWVzc2FnZXMgPSBzdWJzY3JpYmVyLl9fbWVzc2FnZXM7XG4gICAgICAgICAgICB0aGlzLm9mZihtZXNzYWdlcywgc3Vic2NyaWJlcik7XG4gICAgICAgIH0gZWxzZSBpZiAoZGlzcGF0Y2hUaW1lcyA+IDEpXG4gICAgICAgICAgICBzdWJzY3JpYmVyLm9wdGlvbnMuZGlzcGF0Y2hUaW1lcy0tO1xuICAgIH1cblxuICAgIGlmIChzeW5jaHJvKVxuICAgICAgICBzdWJzY3JpYmVyLnN1YnNjcmliZXIuY2FsbChzdWJzY3JpYmVyLmNvbnRleHQsIG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrKTtcbiAgICBlbHNlXG4gICAgICAgIF8uZGVmZXJNZXRob2Qoc3Vic2NyaWJlci5zdWJzY3JpYmVyLCAnY2FsbCcsIHN1YnNjcmliZXIuY29udGV4dCwgbWVzc2FnZSwgZGF0YSwgY2FsbGJhY2spO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZC5cbiAqIFJldHVybnMgdGhlIGFycmF5IG9mIHN1YnNjcmliZXJzIHRoYXQgd291bGQgYmUgY2FsbGVkIGlmIHRoZSBtZXNzYWdlIHdlcmUgZGlzcGF0Y2hlZC5cbiAqIElmIGBpbmNsdWRlUGF0dGVyblN1YnNjcmliZXJzID09PSBmYWxzZWAsIHBhdHRlcm4gc3Vic2NyaWJlcnMgd2l0aCBtYXRjaGluZyBwYXR0ZXJzIHdpbGwgbm90IGJlIGluY2x1ZGVkIChieSBkZWZhdWx0IHRoZXkgYXJlIGluY2x1ZGVkKS5cbiAqIElmIHRoZXJlIGFyZSBubyBzdWJzY3JpYmVycyB0byB0aGUgbWVzc2FnZSwgYHVuZGVmaW5lZGAgd2lsbCBiZSByZXR1cm5lZCwgbm90IGFuIGVtcHR5IGFycmF5LCBzbyBpdCBpcyBzYWZlIHRvIHVzZSB0aGUgcmVzdWx0IGluIGJvb2xlYW4gdGVzdHMuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBtZXNzYWdlIE1lc3NhZ2UgdG8gZ2V0IHN1YnNjcmliZXJzIGZvci5cbiAqICBJZiB0aGUgbWVzc2FnZSBpcyBSZWdFeHAsIG9ubHkgcGF0dGVybiBzdWJzY3JpYmVycyByZWdpc3RlcmVkIHdpdGggZXhhY3RseSB0aGlzIHBhdHRlcm4gd2lsbCBiZSByZXR1cm5lZC5cbiAqICBJZiB0aGUgbWVzc2FnZSBpcyBTdHJpbmcsIHN1YnNjcmliZXJzIHJlZ2lzdGVyZWQgd2l0aCB0aGUgc3RyaW5nIG1lc3NhZ2VzIGFuZCBwYXR0ZXJuIHN1YnNjcmliZXJzIHJlZ2lzdGVyZWQgd2l0aCBtYXRjaGluZyBwYXR0ZXJuIHdpbGwgYmUgcmV0dXJuZWQgKHVubGVzcyB0aGUgc2Vjb25kIHBhcmFtZXRlciBpcyBmYWxzZSkuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGluY2x1ZGVQYXR0ZXJuU3Vic2NyaWJlcnMgT3B0aW9uYWwgZmFsc2UgdG8gcHJldmVudCBpbmNsdXNpb24gb2YgcGF0dGVyIHN1YnNjcmliZXJzLCBieSBkZWZhdWx0IHRoZXkgYXJlIGluY2x1ZGVkLlxuICogQHJldHVybiB7QXJyYXl8dW5kZWZpbmVkfVxuICovXG5mdW5jdGlvbiBnZXRTdWJzY3JpYmVycyhtZXNzYWdlLCBpbmNsdWRlUGF0dGVyblN1YnNjcmliZXJzKSB7XG4gICAgY2hlY2sobWVzc2FnZSwgTWF0Y2guT25lT2YoU3RyaW5nLCBSZWdFeHApKTtcblxuICAgIHZhciBzdWJzY3JpYmVyc0hhc2ggPSB0aGlzLl9jaG9vc2VTdWJzY3JpYmVyc0hhc2gobWVzc2FnZSk7XG4gICAgdmFyIG1zZ1N1YnNjcmliZXJzID0gc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyBbXS5jb25jYXQoc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogW107XG5cbiAgICAvLyBwYXR0ZXJuIHN1YnNjcmliZXJzIGFyZSBpbmN1ZGVkIGJ5IGRlZmF1bHRcbiAgICBpZiAoaW5jbHVkZVBhdHRlcm5TdWJzY3JpYmVycyAhPT0gZmFsc2UgJiYgdHlwZW9mIG1lc3NhZ2UgPT0gJ3N0cmluZycpIHtcbiAgICAgICAgXy5lYWNoS2V5KHRoaXMuX3BhdHRlcm5NZXNzYWdlU3Vic2NyaWJlcnMsXG4gICAgICAgICAgICBmdW5jdGlvbihwYXR0ZXJuU3Vic2NyaWJlcnMpIHtcbiAgICAgICAgICAgICAgICB2YXIgcGF0dGVybiA9IHBhdHRlcm5TdWJzY3JpYmVycy5wYXR0ZXJuO1xuICAgICAgICAgICAgICAgIGlmIChwYXR0ZXJuU3Vic2NyaWJlcnMgJiYgcGF0dGVyblN1YnNjcmliZXJzLmxlbmd0aFxuICAgICAgICAgICAgICAgICAgICAgICAgJiYgcGF0dGVybi50ZXN0KG1lc3NhZ2UpKVxuICAgICAgICAgICAgICAgICAgICBfLmFwcGVuZEFycmF5KG1zZ1N1YnNjcmliZXJzLCBwYXR0ZXJuU3Vic2NyaWJlcnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8vIHJldHVybiB1bmRlZmluZWQgaWYgdGhlcmUgYXJlIG5vIHN1YnNjcmliZXJzXG4gICAgcmV0dXJuIG1zZ1N1YnNjcmliZXJzLmxlbmd0aFxuICAgICAgICAgICAgICAgID8gbXNnU3Vic2NyaWJlcnNcbiAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZDtcbn1cblxuXG4vKipcbiAqIFwiUHJpdmF0ZVwiIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgdGhlIG1hcCBvZiBzdWJzY3JpYmVycyBmb3IgYSBnaXZlbiBtZXNzYWdlIHR5cGUuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gbWVzc2FnZSBNZXNzYWdlIHRvIGNob29zZSB0aGUgbWFwIG9mIHN1YnNjcmliZXJzIGZvclxuICogQHJldHVybiB7T2JqZWN0W0Z1bmN0aW9uXX1cbiAqL1xuZnVuY3Rpb24gX2Nob29zZVN1YnNjcmliZXJzSGFzaChtZXNzYWdlKSB7XG4gICAgcmV0dXJuIG1lc3NhZ2UgaW5zdGFuY2VvZiBSZWdFeHBcbiAgICAgICAgICAgICAgICA/IHRoaXMuX3BhdHRlcm5NZXNzYWdlU3Vic2NyaWJlcnNcbiAgICAgICAgICAgICAgICA6IHRoaXMuX21lc3NhZ2VTdWJzY3JpYmVycztcbn1cblxuXG4vKipcbiAqIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2RcbiAqIFNldHMgW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgZm9yIHRoZSBtZXNzZW5nZXIgYWxzbyBzZXR0aW5nIHRoZSByZWZlcmVuY2UgdG8gdGhlIG1lc3NlbmdlciBpbiB0aGUgTWVzc2FnZVNvdXJjZS5cbiAqIE1lc3NhZ2VTb3VyY2UgY2FuIGJlIHBhc3NlZCB0byBtZXNzYWdlIGNvbnN0cnVjdG9yOyB0aGlzIG1ldGhvZCBhbGxvd3MgdG8gc2V0IGl0IGF0IGEgbGF0ZXIgdGltZS4gRm9yIGV4YW1wbGUsIHRoZSBzdWJjbGFzc2VzIG9mIFtDb21wb25lbnRGYWNldF0oLi4vY29tcG9uZW50cy9jX2ZhY2V0LmpzLmh0bWwpIHVzZSB0aGlzIG1ldGhvZCB0byBzZXQgZGlmZmVyZW50IE1lc3NhZ2VTb3VyY2UnZXMgaW4gdGhlIG1lc3NlbmdlciB0aGF0IGlzIGNyZWF0ZWQgYnkgQ29tcG9uZW50RmFjZXQuXG4gKiBDdXJyZW50bHkgdGhlIG1ldGhvZCBpcyBpbXBsZW1lbnRlZCBpbiBzdWNoIHdheSB0aGF0IGl0IGNhbiBiZSBjYWxsZWQgb25seSBvbmNlIC0gTWVzc2FnZVNvdXJjZSBjYW5ub3QgYmUgY2hhbmdlZCBhZnRlciB0aGlzIG1ldGhvZCBpcyBjYWxsZWQuXG4gKlxuICogQHBhcmFtIHtNZXNzYWdlU291cmNlfSBtZXNzYWdlU291cmNlIGFuIGluc3RhbmNlIG9mIE1lc3NhZ2VTb3VyY2UgY2xhc3MgdG8gYXR0YWNoIHRvIHRoaXMgbWVzc2VuZ2VyIChhbmQgdG8gaGF2ZSB0aGlzIG1lc3NlbmdlciBhdHRhY2hlZCB0byBpdCB0b28pXG4gKi9cbmZ1bmN0aW9uIF9zZXRNZXNzYWdlU291cmNlKG1lc3NhZ2VTb3VyY2UpIHtcbiAgICBjaGVjayhtZXNzYWdlU291cmNlLCBNZXNzYWdlU291cmNlKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgJ19tZXNzYWdlU291cmNlJywgbWVzc2FnZVNvdXJjZSk7XG4gICAgbWVzc2FnZVNvdXJjZS5tZXNzZW5nZXIgPSB0aGlzO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyBtZXNzZW5nZXIgTWVzc2FnZVNvdXJjZVxuICpcbiAqIEByZXR1cm4ge01lc3NhZ2VTb3VyY2V9XG4gKi9cbmZ1bmN0aW9uIGdldE1lc3NhZ2VTb3VyY2UoKSB7XG4gICAgcmV0dXJuIHRoaXMuX21lc3NhZ2VTb3VyY2Vcbn1cbiIsImFyZ3VtZW50c1s0XVs2OF1bMF0uYXBwbHkoZXhwb3J0cyxhcmd1bWVudHMpIiwiYXJndW1lbnRzWzRdWzY5XVswXS5hcHBseShleHBvcnRzLGFyZ3VtZW50cykiLCIndXNlIHN0cmljdCc7XG5cbnZhciBNaXhpbiA9IHJlcXVpcmUoJy4uL2Fic3RyYWN0L21peGluJylcbiAgICAsIE1lc3NlbmdlckFQSSA9IHJlcXVpcmUoJy4vbV9hcGknKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vdXRpbC9sb2dnZXInKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaDtcblxuXG4vKipcbiAqIGBtaWxvLmNsYXNzZXMuTWVzc2FnZVNvdXJjZWBcbiAqIEFuIGFic3RyYWN0IGNsYXNzIChzdWJjbGFzcyBvZiBbTWl4aW5dKC4uL2Fic3RyYWN0L21peGluLmpzLmh0bWwpKSBmb3IgY29ubmVjdGluZyBbTWVzc2VuZ2VyXSguL2luZGV4LmpzLmh0bWwpIHRvIGV4dGVybmFsIHNvdXJjZXMgb2YgbWVzc2FnZXMgKGxpa2UgRE9NIGV2ZW50cykgYW5kIGRlZmluaW5nIGhpZ2hlciBsZXZlbCBtZXNzYWdlcy5cbiAqIEFuIGluc3RhbmNlIG9mIE1lc3NhZ2VTb3VyY2UgY2FuIGVpdGhlciBiZSBwYXNzZWQgdG8gTWVzc2VuZ2VyIGNvbnN0cnVjdG9yIG9yIGxhdGVyIHVzaW5nIGBfc2V0TWVzc2FnZVNvdXJjZWAgbWV0aG9kIG9mIE1lc3Nlbmdlci4gT25jZSBzZXQsIE1lc3NhZ2VTb3VyY2Ugb2YgTWVzc2VuZ2VyIGNhbm5vdCBiZSBjaGFuZ2VkLlxuICovXG52YXIgTWVzc2FnZVNvdXJjZSA9IF8uY3JlYXRlU3ViY2xhc3MoTWl4aW4sICdNZXNzYWdlU291cmNlJywgdHJ1ZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gTWVzc2FnZVNvdXJjZTtcblxuXG4vKipcbiAqICMjIyNNZXNzYWdlU291cmNlIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbaW5pdF0oI2luaXQpIC0gaW5pdGlhbGl6ZXMgbWVzc2FnZVNvdXJjZSAtIGNhbGxlZCBieSBNaXhpbiBzdXBlcmNsYXNzXG4gKiAtIFtzZXRNZXNzZW5nZXJdKCNzZXRNZXNzZW5nZXIpIC0gY29ubmVjdHMgTWVzc2VuZ2VyIHRvIE1lc3NhZ2VTb3VyY2UsIGlzIGNhbGxlZCBmcm9tIGBpbml0YCBvciBgX3NldE1lc3NhZ2VTb3VyY2VgIG1ldGhvZHMgb2YgW01lc3Nlbmdlcl0oLi9pbmRleC5qcy5odG1sKS5cbiAqIC0gW29uU3Vic2NyaWJlckFkZGVkXSgjb25TdWJzY3JpYmVyQWRkZWQpIC0gY2FsbGVkIGJ5IE1lc3NlbmdlciB0byBub3RpZnkgd2hlbiB0aGUgZmlyc3Qgc3Vic2NyaWJlciBmb3IgYW4gaW50ZXJuYWwgbWVzc2FnZSB3YXMgYWRkZWQsIHNvIE1lc3NhZ2VTb3VyY2UgY2FuIHN1YnNjcmliZSB0byBzb3VyY2VcbiAqIC0gW29uU3Vic2NyaWJlclJlbW92ZWRdKCNvblN1YnNjcmliZXJSZW1vdmVkKSAtIGNhbGxlZCBieSBNZXNzZW5nZXIgdG8gbm90aWZ5IHdoZW4gdGhlIGxhc3Qgc3Vic2NyaWJlciBmb3IgYW4gaW50ZXJuYWwgbWVzc2FnZSB3YXMgcmVtb3ZlZCwgc28gTWVzc2FnZVNvdXJjZSBjYW4gdW5zdWJzY3JpYmUgZnJvbSBzb3VyY2VcbiAqIC0gW2Rpc3BhdGNoTWVzc2FnZV0oI2Rpc3BhdGNoTWVzc2FnZSkgLSBkaXNwYXRjaGVzIHNvdXJjZSBtZXNzYWdlLiBNZXNzYWdlU291cmNlIHN1YmNsYXNzIHNob3VsZCBpbXBsZW1lbnQgbWVjaGFuaXNtIHdoZW4gb24gYWN0dWFsIHNvdXJjZSBtZXNzYWdlIHRoaXMgbWV0aG9kIGlzIGNhbGxlZC5cbiAqXG4gKiBNZXRob2RzIGJlbG93IHNob3VsZCBiZSBpbXBsZW1lbnRlZCBpbiBzdWJjbGFzczpcbiAqXG4gKiAtIFt0cmlnZ2VyXSgjdHJpZ2dlcikgLSB0cmlnZ2VycyBtZXNzYWdlcyBvbiB0aGUgc291cmNlIChhbiBvcHRpb25hbCBtZXRob2QpXG4gKiAtIFthZGRTb3VyY2VTdWJzY3JpYmVyXSgjYWRkU291cmNlU3Vic2NyaWJlcikgLSBhZGRzIGxpc3RlbmVyL3N1YnNjcmliZXIgdG8gZXh0ZXJuYWwgbWVzc2FnZVxuICogLSBbcmVtb3ZlU291cmNlU3Vic2NyaWJlcl0oI3JlbW92ZVNvdXJjZVN1YnNjcmliZXIpIC0gcmVtb3ZlcyBsaXN0ZW5lci9zdWJzY3JpYmVyIGZyb20gZXh0ZXJuYWwgbWVzc2FnZVxuICovXG5fLmV4dGVuZFByb3RvKE1lc3NhZ2VTb3VyY2UsIHtcbiAgICBpbml0OiBpbml0LFxuICAgIGRlc3Ryb3k6IE1lc3NhZ2VTb3VyY2UkZGVzdHJveSxcbiAgICBzZXRNZXNzZW5nZXI6IHNldE1lc3NlbmdlcixcbiAgICBvblN1YnNjcmliZXJBZGRlZDogb25TdWJzY3JpYmVyQWRkZWQsXG4gICAgb25TdWJzY3JpYmVyUmVtb3ZlZDogb25TdWJzY3JpYmVyUmVtb3ZlZCwgXG4gICAgZGlzcGF0Y2hNZXNzYWdlOiBkaXNwYXRjaE1lc3NhZ2UsXG4gICAgcG9zdE1lc3NhZ2U6IHBvc3RNZXNzYWdlLFxuICAgIF9wcmVwYXJlTWVzc2VuZ2VyQVBJOiBfcHJlcGFyZU1lc3NlbmdlckFQSSxcblxuICAgIC8vIE1ldGhvZHMgYmVsb3cgbXVzdCBiZSBpbXBsZW1lbnRlZCBpbiBzdWJjbGFzc1xuICAgIHRyaWdnZXI6IHRvQmVJbXBsZW1lbnRlZCxcbiAgICBhZGRTb3VyY2VTdWJzY3JpYmVyOiB0b0JlSW1wbGVtZW50ZWQsXG4gICAgcmVtb3ZlU291cmNlU3Vic2NyaWJlcjogdG9CZUltcGxlbWVudGVkXG59KTtcblxuXG4vKipcbiAqIE1lc3NhZ2VTb3VyY2UgaW5zdGFuY2UgbWV0aG9kLlxuICogQ2FsbGVkIGJ5IE1peGluIGNvbnN0cnVjdG9yLlxuICogTWVzc2FnZVNvdXJjZSBjb25zdHJ1Y3RvciBzaG91bGQgYmUgcGFzc2VkIHRoZSBzYW1lIHBhcmFtZXRlcnMgYXMgdGhpcyBtZXRob2Qgc2lnbmF0dXJlLlxuICogSWYgYW4gaW5zdGFuY2Ugb2YgW01lc3NlbmdlckFQSV0oLi9tX2FwaS5qcy5odG1sKSBpcyBwYXNzZWQgYXMgdGhlIHRoaXJkIHBhcmFtZXRlciwgaXQgZXh0ZW5kcyBNZXNzYWdlU291cmNlIGZ1bmN0aW9uYWxpdHkgdG8gYWxsb3cgaXQgdG8gZGVmaW5lIG5ldyBtZXNzYWdlcywgdG8gZmlsdGVyIG1lc3NhZ2VzIGJhc2VkIG9uIHRoZWlyIGRhdGEgYW5kIHRvIGNoYW5nZSBtZXNzYWdlIGRhdGEuIFNlZSBbTWVzc2VuZ2VyQVBJXSguL21fYXBpLmpzLmh0bWwpLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0T2JqZWN0IE9wdGlvbmFsIG9iamVjdCB0aGF0IHN0b3JlcyB0aGUgTWVzc2FnZVNvdXJjZSBvbiBvbmUgb2YgaXRzIHByb3BlcnRpZXMuIEl0IGlzIHVzZWQgdG8gcHJveHkgbWV0aG9kcyBvZiBNZXNzYWdlU291cmNlLlxuICogQHBhcmFtIHtPYmplY3RbU3RyaW5nXX0gcHJveHlNZXRob2RzIE9wdGlvbmFsIG1hcCBvZiBtZXRob2QgbmFtZXM7IGtleSAtIHByb3h5IG1ldGhvZCBuYW1lLCB2YWx1ZSAtIE1lc3NhZ2VTb3VyY2UncyBtZXRob2QgbmFtZS5cbiAqIEBwYXJhbSB7TWVzc2VuZ2VyQVBJfSBtZXNzZW5nZXJBUEkgT3B0aW9uYWwgaW5zdGFuY2Ugb2YgTWVzc2VuZ2VyQVBJLlxuICovXG5mdW5jdGlvbiBpbml0KGhvc3RPYmplY3QsIHByb3h5TWV0aG9kcywgbWVzc2VuZ2VyQVBJKSB7XG4gICAgdGhpcy5fcHJlcGFyZU1lc3NlbmdlckFQSShtZXNzZW5nZXJBUEkpO1xufVxuXG5cbi8qKlxuICogRGVzdHJveXMgbWVzc2FnZSBzb3VyY2VcbiAqL1xuZnVuY3Rpb24gTWVzc2FnZVNvdXJjZSRkZXN0cm95KCkge1xuICAgIGlmICh0aGlzLm1lc3NlbmdlckFQSSlcbiAgICAgICAgdGhpcy5tZXNzZW5nZXJBUEkuZGVzdHJveSgpO1xufVxuXG5cbi8qKlxuICogTWVzc2FnZVNvdXJjZSBpbnN0YW5jZSBtZXRob2QuXG4gKiBTZXRzIHJlZmVyZW5jZSB0byBNZXNzZW5nZXIgaW5zdGFuY2UuXG4gKlxuICogQHBhcmFtIHtNZXNzZW5nZXJ9IG1lc3NlbmdlciByZWZlcmVuY2UgdG8gTWVzc2VuZ2VyIGluc3RhbmNlIGxpbmtlZCB0byB0aGlzIE1lc3NhZ2VTb3VyY2VcbiAqL1xuZnVuY3Rpb24gc2V0TWVzc2VuZ2VyKG1lc3Nlbmdlcikge1xuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgJ21lc3NlbmdlcicsIG1lc3Nlbmdlcik7XG59XG5cblxuLyoqXG4gKiBNZXNzYWdlU291cmNlIGluc3RhbmNlIG1ldGhvZC5cbiAqIFByZXBhcmVzIFtNZXNzZW5nZXJBUEldKC4vbV9hcGkuanMuaHRtbCkgcGFzc2VkIHRvIGNvbnN0cnVjdG9yIGJ5IHByb3h5aW5nIGl0cyBtZXRob2RzIHRvIGl0c2VsZiBvciBpZiBNZXNzZW5nZXJBUEkgd2Fzbid0IHBhc3NlZCBkZWZpbmVzIHR3byBtZXRob2RzIHRvIGF2b2lkIGNoZWNraW5nIHRoZWlyIGF2YWlsYWJpbGl0eSBldmVyeSB0aW1lIHRoZSBtZXNzYWdlIGlzIGRpc3BhdGNoZWQuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7TWVzc2VuZ2VyQVBJfSBtZXNzZW5nZXJBUEkgT3B0aW9uYWwgaW5zdGFuY2Ugb2YgTWVzc2VuZ2VyQVBJXG4gKi9cbmZ1bmN0aW9uIF9wcmVwYXJlTWVzc2VuZ2VyQVBJKG1lc3NlbmdlckFQSSkge1xuICAgIGNoZWNrKG1lc3NlbmdlckFQSSwgTWF0Y2guT3B0aW9uYWwoTWVzc2VuZ2VyQVBJKSk7XG5cbiAgICBpZiAoISBtZXNzZW5nZXJBUEkpXG4gICAgICAgIG1lc3NlbmdlckFQSSA9IG5ldyBNZXNzZW5nZXJBUEk7XG5cbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdtZXNzZW5nZXJBUEknLCBtZXNzZW5nZXJBUEkpO1xufVxuXG5cbi8qKlxuICogTWVzc2FnZVNvdXJjZSBpbnN0YW5jZSBtZXRob2QuXG4gKiBTdWJzY3JpYmVzIHRvIGV4dGVybmFsIHNvdXJjZSB1c2luZyBgYWRkU291cmNlU3Vic2NyaWJlcmAgbWV0aG9kIHRoYXQgc2hvdWxkIGJlIGltcGxlbWVudGVkIGluIHN1YmNsYXNzLlxuICogVGhpcyBtZXRob2QgaXMgY2FsbGVkIGJ5IFtNZXNzZW5nZXJdKC4vaW5kZXguanMuaHRtbCkgd2hlbiB0aGUgZmlyc3Qgc3Vic2NyaWJlciB0byB0aGUgYG1lc3NhZ2VgIGlzIGFkZGVkLlxuICogRGVsZWdhdGVzIHRvIHN1cHBsaWVkIG9yIGRlZmF1bHQgW01lc3NlbmdlckFQSV0oLi9tX2FwaS5qcy5odG1sKSBmb3IgdHJhbnNsYXRpb24gb2YgYG1lc3NhZ2VgIHRvIGBzb3VyY2VNZXNzYWdlYC4gYE1lc3NhZ2VBUEkucHJvdG90eXBlLmFkZEludGVybmFsTWVzc2FnZWAgd2lsbCByZXR1cm4gdW5kZWZpbmVkIGlmIHRoaXMgYHNvdXJjZU1lc3NhZ2VgIHdhcyBhbHJlYWR5IHN1YnNjcmliZWQgdG8gdG8gcHJldmVudCBkdXBsaWNhdGUgc3Vic2NyaXB0aW9uLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGludGVybmFsIE1lc3NlbmdlciBtZXNzYWdlIHRoYXQgaGFzIHRvIGJlIHN1YnNjcmliZWQgdG8gYXQgdGhlIGV4dGVybmFsIHNvdXJjZSBvZiBtZXNzYWdlcy5cbiAqL1xuZnVuY3Rpb24gb25TdWJzY3JpYmVyQWRkZWQobWVzc2FnZSkge1xuICAgIHZhciBuZXdTb3VyY2VNZXNzYWdlID0gdGhpcy5tZXNzZW5nZXJBUEkuYWRkSW50ZXJuYWxNZXNzYWdlKG1lc3NhZ2UpO1xuICAgIGlmICh0eXBlb2YgbmV3U291cmNlTWVzc2FnZSAhPSAndW5kZWZpbmVkJylcbiAgICAgICAgdGhpcy5hZGRTb3VyY2VTdWJzY3JpYmVyKG5ld1NvdXJjZU1lc3NhZ2UpO1xufVxuXG5cbi8qKlxuICogTWVzc2FnZVNvdXJjZSBpbnN0YW5jZSBtZXRob2QuXG4gKiBVbnN1YnNjcmliZXMgZnJvbSBleHRlcm5hbCBzb3VyY2UgdXNpbmcgYHJlbW92ZVNvdXJjZVN1YnNjcmliZXJgIG1ldGhvZCB0aGF0IHNob3VsZCBiZSBpbXBsZW1lbnRlZCBpbiBzdWJjbGFzcy5cbiAqIFRoaXMgbWV0aG9kIGlzIGNhbGxlZCBieSBbTWVzc2VuZ2VyXSguL2luZGV4LmpzLmh0bWwpIHdoZW4gdGhlIGxhc3Qgc3Vic2NyaWJlciB0byB0aGUgYG1lc3NhZ2VgIGlzIHJlbW92ZWQuXG4gKiBEZWxlZ2F0ZXMgdG8gc3VwcGxpZWQgb3IgZGVmYXVsdCBbTWVzc2VuZ2VyQVBJXSguL21fYXBpLmpzLmh0bWwpIGZvciB0cmFuc2xhdGlvbiBvZiBgbWVzc2FnZWAgdG8gYHNvdXJjZU1lc3NhZ2VgLiBgTWVzc2FnZUFQSS5wcm90b3R5cGUucmVtb3ZlSW50ZXJuYWxNZXNzYWdlYCB3aWxsIHJldHVybiB1bmRlZmluZWQgaWYgdGhpcyBgc291cmNlTWVzc2FnZWAgd2FzIG5vdCB5ZXQgc3Vic2NyaWJlZCB0byB0byBwcmV2ZW50IHVuc3Vic2NyaXB0aW9uIHdpdGhvdXQgcHJldmlvdXMgc3Vic2NyaXB0aW9uLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGludGVybmFsIE1lc3NlbmdlciBtZXNzYWdlIHRoYXQgaGFzIHRvIGJlIHVuc3Vic2NyaWJlZCBmcm9tIGF0IHRoZSBleHRlcm5hbCBzb3VyY2Ugb2YgbWVzc2FnZXMuXG4gKi9cbmZ1bmN0aW9uIG9uU3Vic2NyaWJlclJlbW92ZWQobWVzc2FnZSkge1xuICAgIHZhciByZW1vdmVkU291cmNlTWVzc2FnZSA9IHRoaXMubWVzc2VuZ2VyQVBJLnJlbW92ZUludGVybmFsTWVzc2FnZShtZXNzYWdlKTtcbiAgICBpZiAodHlwZW9mIHJlbW92ZWRTb3VyY2VNZXNzYWdlICE9ICd1bmRlZmluZWQnKVxuICAgICAgICB0aGlzLnJlbW92ZVNvdXJjZVN1YnNjcmliZXIocmVtb3ZlZFNvdXJjZU1lc3NhZ2UpO1xufVxuXG5cbi8qKlxuICogTWVzc2FnZVNvdXJjZSBpbnN0YW5jZSBtZXRob2QuXG4gKiBEaXNwYXRjaGVzIHNvdXJjZU1lc3NhZ2UgdG8gTWVzc2VuZ2VyLlxuICogTWVjaGFuaXNtIHRoYXQgY2FsbHMgdGhpcyBtZXRob2Qgd2hlbiB0aGUgc291cmNlIG1lc3NhZ2UgaXMgcmVjZWl2ZWQgc2hvdWxkIGJlIGltcGxlbWVudGVkIGJ5IHN1YmNsYXNzIChzZWUgW0RPTUV2ZW50c1NvdXJjZV0oLi4vY29tcG9uZW50cy9tc2dfc3JjL2RvbV9ldmVudHMuanMuaHRtbCkgZm9yIGV4YW1wbGUpLlxuICogRGVsZWdhdGVzIHRvIHN1cHBsaWVkIG9yIGRlZmF1bHQgW01lc3NlbmdlckFQSV0oLi9tX2FwaS5qcy5odG1sKSB0byBjcmVhdGUgaW50ZXJuYWwgbWVzc2FnZSBkYXRhIChgY3JlYXRlSW50ZXJuYWxEYXRhYCkgYW5kIHRvIGZpbHRlciB0aGUgbWVzc2FnZSBiYXNlZCBvbiBpdHMgZGF0YSBhbmQvb3IgbWVzc2FnZSAoYGZpbHRlclNvdXJjZU1lc3NhZ2VgKS5cbiAqIEJhc2UgTWVzc2VuZ2VyQVBJIGNsYXNzIGltcGxlbWVudHMgdGhlc2UgdHdvIG1ldGhvZHMgaW4gYSB0cml2aWFsIHdheSAoYGNyZWF0ZUludGVybmFsRGF0YWAgc2ltcGx5IHJldHVybnMgZXh0ZXJuYWwgZGF0YSwgYGZpbHRlclNvdXJjZU1lc3NhZ2VgIHJldHVybnMgYHRydWVgKSwgdGhleSBhcmUgbWVhbnQgdG8gYmUgaW1wbGVtZW50ZWQgYnkgc3ViY2xhc3MuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHNvdXJjZU1lc3NhZ2Ugc291cmNlIG1lc3NhZ2UgcmVjZWl2ZWQgZnJvbSBleHRlcm5hbCBzb3VyY2VcbiAqIEBwYXJhbSB7T2JqZWN0fSBzb3VyY2VEYXRhIGRhdGEgcmVjZWl2ZWQgZnJvbSBleHRlcm5hbCBzb3VyY2VcbiAqL1xuZnVuY3Rpb24gZGlzcGF0Y2hNZXNzYWdlKHNvdXJjZU1lc3NhZ2UsIHNvdXJjZURhdGEpIHtcbiAgICB2YXIgYXBpID0gdGhpcy5tZXNzZW5nZXJBUElcbiAgICAgICAgLCBpbnRlcm5hbE1lc3NhZ2VzID0gYXBpLmdldEludGVybmFsTWVzc2FnZXMoc291cmNlTWVzc2FnZSk7XG5cbiAgICBpZiAoaW50ZXJuYWxNZXNzYWdlcykgXG4gICAgICAgIGludGVybmFsTWVzc2FnZXMuZm9yRWFjaChmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAgICAgdmFyIGludGVybmFsRGF0YSA9IGFwaS5jcmVhdGVJbnRlcm5hbERhdGEoc291cmNlTWVzc2FnZSwgbWVzc2FnZSwgc291cmNlRGF0YSk7XG5cbiAgICAgICAgICAgIHZhciBzaG91bGREaXNwYXRjaCA9IGFwaS5maWx0ZXJTb3VyY2VNZXNzYWdlKHNvdXJjZU1lc3NhZ2UsIG1lc3NhZ2UsIGludGVybmFsRGF0YSk7XG4gICAgICAgICAgICBpZiAoc2hvdWxkRGlzcGF0Y2gpIFxuICAgICAgICAgICAgICAgIHRoaXMucG9zdE1lc3NhZ2UobWVzc2FnZSwgaW50ZXJuYWxEYXRhKTsgICAgICBcbiAgICAgICAgICAgIFxuICAgICAgICB9LCB0aGlzKTtcbn1cblxuXG4vKipcbiAqIFBvc3RzIG1lc3NhZ2Ugb24gdGhlIG1lc3Nlbmdlci4gVGhpcyBtZXRob2QgaXMgc2VwYXJhdGVkIHNvIHNwZWNpZmljIG1lc3NhZ2Ugc291cmNlcyBjYW4gbWFrZSBtZXNzYWdlIGRpc3BhdGNoIHN5bmNocm9ub3VzIGJ5IHVzaW5nIGBwb3N0TWVzc2FnZVN5bmNgXG4gKiBcbiAqIEBwYXJhbSAge1N0cmluZ30gbWVzc2FnZVxuICogQHBhcmFtICB7T2JqZWN0fSBkYXRhXG4gKi9cbmZ1bmN0aW9uIHBvc3RNZXNzYWdlKG1lc3NhZ2UsIGRhdGEpIHtcbiAgICB0aGlzLm1lc3Nlbmdlci5wb3N0TWVzc2FnZShtZXNzYWdlLCBkYXRhKTtcbn1cblxuXG5mdW5jdGlvbiB0b0JlSW1wbGVtZW50ZWQoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjYWxsaW5nIHRoZSBtZXRob2Qgb2YgYW4gYWJzY3RyYWN0IGNsYXNzJyk7XG59XG4iLCJhcmd1bWVudHNbNF1bNzFdWzBdLmFwcGx5KGV4cG9ydHMsYXJndW1lbnRzKSIsIid1c2Ugc3RyaWN0JztcblxudmFyIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG4vKipcbiAqICMjIyNNaWxvIHBhY2thZ2VzIyMjI1xuICpcbiAqIC0gW21pbmRlcl0oLi9taW5kZXIuanMuaHRtbCkgLSBkYXRhIHJlYWN0aXZpdHksIG9uZSBvciB0d28gd2F5LCBzaGFsbG93IG9yIGRlZXAsIGFzIHlvdSBsaWtlIGl0XG4gKiAtIFtjb25maWddKC4vY29uZmlnLmpzLmh0bWwpIC0gbWlsbyBjb25maWd1cmF0aW9uXG4gKiAtIFt1dGlsXSguL3V0aWwvaW5kZXguanMuaHRtbCkgLSBsb2dnZXIsIHJlcXVlc3QsIGRvbSwgY2hlY2ssIGVycm9yLCBldGMuXG4gKiAtIFtjbGFzc2VzXSguL2NsYXNzZXMuanMuaHRtbCkgLSBhYnN0cmFjdCBhbmQgYmFzZSBjbGFzc2VzXG4gKiAtIFtNZXNzZW5nZXJdKC4vbWVzc2VuZ2VyL2luZGV4LmpzLmh0bWwpIC0gZ2VuZXJpYyBNZXNzZW5nZXIgdXNlZCBpbiBtb3N0IG90aGVyIG1pbG8gY2xhc3NlcywgY2FuIGJlIG1peGVkIGludG8gYXBwIGNsYXNzZXMgdG9vLlxuICogLSBbTW9kZWxdKC4vbW9kZWwvaW5kZXguanMuaHRtbCkgLSBNb2RlbCBjbGFzcyB0aGF0IGVtaXRzIG1lc3NhZ2VzIG9uIGNoYW5nZXMgdG8gYW55IGRlcHRoIHdpdGhvdXQgdGltZXIgYmFzZWQgd2F0Y2hpbmdcbiAqL1xudmFyIG1pbG8gPSB7XG4gICAgbWluZGVyOiByZXF1aXJlKCcuL21pbmRlcicpLFxuICAgIGNvbmZpZzogcmVxdWlyZSgnLi9jb25maWcnKSxcbiAgICB1dGlsOiByZXF1aXJlKCcuL3V0aWwnKSxcbiAgICBjbGFzc2VzOiByZXF1aXJlKCcuL2NsYXNzZXMnKSxcbiAgICBNZXNzZW5nZXI6IHJlcXVpcmUoJy4vbWVzc2VuZ2VyJyksXG4gICAgTW9kZWw6IHJlcXVpcmUoJy4vbW9kZWwnKSxcbiAgICBkZXN0cm95OiBkZXN0cm95XG59O1xuXG5cbi8vIGV4cG9ydCBmb3Igbm9kZS9icm93c2VyaWZ5XG5pZiAodHlwZW9mIG1vZHVsZSA9PSAnb2JqZWN0JyAmJiBtb2R1bGUuZXhwb3J0cykgICAgXG4gICAgbW9kdWxlLmV4cG9ydHMgPSBtaWxvO1xuXG4vLyBnbG9iYWwgbWlsbyBmb3IgYnJvd3NlclxuaWYgKHR5cGVvZiB3aW5kb3cgPT0gJ29iamVjdCcpXG4gICAgd2luZG93Lm1pbG8gPSBtaWxvO1xuXG5cbmZ1bmN0aW9uIGRlc3Ryb3koKSB7XG4gICAgbWlsby5taW5kZXIuZGVzdHJveSgpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29ubmVjdG9yID0gcmVxdWlyZSgnLi9tb2RlbC9jb25uZWN0b3InKVxuICAgICwgTWVzc2VuZ2VyID0gcmVxdWlyZSgnLi9tZXNzZW5nZXInKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBsb2dnZXIgPSByZXF1aXJlKCcuL3V0aWwvbG9nZ2VyJyk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBtaW5kZXI7XG5cblxuLyoqXG4gKiBUaGlzIGZ1bmN0aW9uIGNyZWF0ZXMgb25lIG9yIG1hbnkgQ29ubmVjdG9yIG9iamVjdHMgdGhhdFxuICogY3JlYXRlIGxpdmUgcmVhY3RpdmUgY29ubmVjdGlvbiBiZXR3ZWVuIG9iamVjdHMgaW1wbGVtZW50aW5nXG4gKiBkYXRhU291cmNlIGludGVyZmFjZTpcbiAqIE9iamVjdHMgc2hvdWxkIGVtaXQgbWVzc2FnZXMgd2hlbiBhbnkgcGFydCBvZiB0aGVpciBkYXRhIGNoYW5nZXMsXG4gKiBtZXRob2RzIGBvbmAgYW5kIGBvZmZgIHNob3VsZCBiZSBpbXBsZW1lbnRlZCB0byBzdWJzY3JpYmUvdW5zdWJzY3JpYmVcbiAqIHRvIGNoYW5nZSBub3RpZmljYXRpb24gbWVzc2FnZXMsIG1ldGhvZHMgYHNldGAgYW5kIGBnZXRgIHNob3VsZCBiZSBpbXBsZW1lbnRlZCB0byBnZXQvc2V0IGRhdGFcbiAqIG9uIHBhdGggb2JqZWN0cywgcG9pbnRpbmcgdG8gcGFydGljdWxhciBwYXJ0cyBvZiB0aGUgb2JqZWN0LCBtZXRob2QgYHBhdGhgXG4gKiBzaG91bGQgcmV0dXJuIHBhdGggb2JqZWN0IGZvciBhIGdpdmVuIHBhdGggc3RyaW5nIChzZWUgcGF0aCB1dGlscyBmb3IgcGF0aCBzdHJpbmcgc3ludGF4KS5cbiAqIEJvdGggTW9kZWwgYW5kIERhdGEgZmFjZXQgYXJlIHN1Y2ggZGF0YSBzb3VyY2VzLCB0aGV5IGNhbiBiZSBsaW5rZWQgYnkgQ29ubmVjdG9yIG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gZHMxIHRoZSBmaXJzdCBkYXRhIHNvdXJjZS4gSW5zdGVhZCBvZiB0aGUgZmlyc3QgZGF0YSBzb3VyY2UgYW4gYXJyYXkgY2FuIGJlIHBhc3NlZCB3aXRoIGFycmF5cyBvZiBDb25uZWN0aW9uIG9iamVjdHMgcGFyYW1ldGVycyBpbiBlYWNoIGFycmF5IGVsZW1lbnQuXG4gKiBAcGFyYW0ge1N0cmluZ30gbW9kZSB0aGUgY29ubmVjdGlvbiBtb2RlIHRoYXQgZGVmaW5lcyB0aGUgZGlyZWN0aW9uIGFuZCB0aGUgZGVwdGggb2YgY29ubmVjdGlvbi4gUG9zc2libGUgdmFsdWVzIGFyZSAnLT4nLCAnPDwtJywgJzw8PC0+Pj4nLCBldGMuXG4gKiBAcGFyYW0ge09iamVjdH0gZHMyIHRoZSBzZWNvbmQgZGF0YSBzb3VyY2VcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIG5vdCBpbXBsZW1lbnRlZCB5ZXRcbiAqL1xuZnVuY3Rpb24gbWluZGVyKGRzMSwgbW9kZSwgZHMyLCBvcHRpb25zKSB7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoZHMxKSkge1xuICAgICAgICB2YXIgY29ubkRlc2NyaXB0aW9ucyA9IGRzMTtcbiAgICAgICAgdmFyIGNvbm5lY3RvcnMgPSBjb25uRGVzY3JpcHRpb25zLm1hcChmdW5jdGlvbihkZXNjcikge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBDb25uZWN0b3IoZGVzY3JbMF0sIGRlc2NyWzFdLCBkZXNjclsyXSwgZGVzY3JbM10pO1xuICAgICAgICB9KTtcbiAgICAgICAgY29ubmVjdG9ycy5mb3JFYWNoKF9hZGRDb25uZWN0b3IpO1xuICAgICAgICByZXR1cm4gY29ubmVjdG9ycztcbiAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgY25jdCA9IG5ldyBDb25uZWN0b3IoZHMxLCBtb2RlLCBkczIsIG9wdGlvbnMpO1xuICAgICAgICBfYWRkQ29ubmVjdG9yKGNuY3QpO1xuICAgICAgICByZXR1cm4gY25jdDtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBtZXNzZW5nZXIgb2YgbWluZGVyIHdoZXJlIGl0IGVtaXRzIGV2ZW50cyByZWxhdGVkIHRvIGFsbCBjb25uZWN0b3JzXG4gKiBAdHlwZSB7TWVzc2VuZ2VyfVxuICovXG52YXIgX21lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXIobWluZGVyLCBNZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMpO1xuXG5cbnZhciBfY29ubmVjdG9ycyA9IFtdXG4gICAgLCBfcmVjZWl2ZWRNZXNzYWdlcyA9IFtdXG4gICAgLCBfaXNQcm9wYWdhdGluZyA9IGZhbHNlO1xuXG5cbl8uZXh0ZW5kKG1pbmRlciwge1xuICAgIGdldENvbm5lY3RvcnM6IG1pbmRlcl9nZXRDb25uZWN0b3JzLFxuICAgIGdldEV4cGFuZGVkQ29ubmVjdGlvbnM6IG1pbmRlcl9nZXRFeHBhbmRlZENvbm5lY3Rpb25zLFxuICAgIGlzUHJvcGFnYXRpbmc6IG1pbmRlcl9pc1Byb3BhZ2F0aW5nLFxuICAgIHdoZW5Qcm9wYWdhdGlvbkNvbXBsZXRlZDogbWluZGVyX3doZW5Qcm9wYWdhdGlvbkNvbXBsZXRlZCxcbiAgICBkZXN0cm95Q29ubmVjdG9yOiBtaW5kZXJfZGVzdHJveUNvbm5lY3RvcixcbiAgICBkZXN0cm95OiBtaW5kZXJfZGVzdHJveVxufSk7XG5cblxuZnVuY3Rpb24gX2FkZENvbm5lY3RvcihjbmN0KSB7XG4gICAgY25jdC5fX19taW5kZXJfaWQgPSBfY29ubmVjdG9ycy5wdXNoKGNuY3QpIC0gMTtcbiAgICBjbmN0Lm9uKC8uKi8sIG9uQ29ubmVjdG9yTWVzc2FnZSk7XG4gICAgbWluZGVyLnBvc3RNZXNzYWdlKCdhZGRlZCcsIHsgY29ubmVjdG9yOiBjbmN0IH0pO1xuICAgIG1pbmRlci5wb3N0TWVzc2FnZSgndHVybmVkb24nLCB7IGNvbm5lY3RvcjogY25jdCB9KTtcbn1cblxuXG5mdW5jdGlvbiBvbkNvbm5lY3Rvck1lc3NhZ2UobXNnLCBkYXRhKSB7XG4gICAgdmFyIGRhdGEgPSBkYXRhID8gXy5jbG9uZShkYXRhKSA6IHt9O1xuICAgIF8uZXh0ZW5kKGRhdGEsIHtcbiAgICAgICAgaWQ6IHRoaXMuX19fbWluZGVyX2lkLFxuICAgICAgICBjb25uZWN0b3I6IHRoaXNcbiAgICB9KTtcbiAgICBtaW5kZXIucG9zdE1lc3NhZ2UobXNnLCBkYXRhKTtcbiAgICBpZiAoISBfcmVjZWl2ZWRNZXNzYWdlcy5sZW5ndGggJiYgISBfaXNQcm9wYWdhdGluZykge1xuICAgICAgICBfLmRlZmVyKF9pZGxlQ2hlY2spO1xuICAgICAgICBfaXNQcm9wYWdhdGluZyA9IHRydWU7XG4gICAgfVxuXG4gICAgX3JlY2VpdmVkTWVzc2FnZXMucHVzaCh7IG1zZzogbXNnLCBkYXRhOiBkYXRhIH0pO1xufVxuXG5cbmZ1bmN0aW9uIF9pZGxlQ2hlY2soKSB7XG4gICAgaWYgKF9yZWNlaXZlZE1lc3NhZ2VzLmxlbmd0aCkge1xuICAgICAgICBfcmVjZWl2ZWRNZXNzYWdlcy5sZW5ndGggPSAwO1xuICAgICAgICBfLmRlZmVyKF9pZGxlQ2hlY2spO1xuICAgICAgICBtaW5kZXIucG9zdE1lc3NhZ2UoJ3Byb3BhZ2F0aW9udGlja2VkJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgX2lzUHJvcGFnYXRpbmcgPSBmYWxzZTtcbiAgICAgICAgbWluZGVyLnBvc3RNZXNzYWdlKCdwcm9wYWdhdGlvbmNvbXBsZXRlZCcpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBtaW5kZXJfaXNQcm9wYWdhdGluZygpIHtcbiAgICByZXR1cm4gX2lzUHJvcGFnYXRpbmc7XG59XG5cblxuZnVuY3Rpb24gbWluZGVyX3doZW5Qcm9wYWdhdGlvbkNvbXBsZXRlZChjYWxsYmFjaykge1xuICAgIGlmIChfaXNQcm9wYWdhdGluZylcbiAgICAgICAgbWluZGVyLm9uY2UoJ3Byb3BhZ2F0aW9uY29tcGxldGVkJywgZXhlY3V0ZUNhbGxiYWNrKTtcbiAgICBlbHNlXG4gICAgICAgIF8uZGVmZXIoZXhlY3V0ZUNhbGxiYWNrKTtcblxuICAgIGZ1bmN0aW9uIGV4ZWN1dGVDYWxsYmFjaygpIHtcbiAgICAgICAgaWYgKF9pc1Byb3BhZ2F0aW5nKVxuICAgICAgICAgICAgbWluZGVyLm9uY2UoJ3Byb3BhZ2F0aW9uY29tcGxldGVkJywgZXhlY3V0ZUNhbGxiYWNrKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgY2FsbGJhY2soKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gbWluZGVyX2dldENvbm5lY3RvcnMob25PZmYpIHtcbiAgICBpZiAodHlwZW9mIG9uT2ZmID09ICd1bmRlZmluZWQnKVxuICAgICAgICByZXR1cm4gX2Nvbm5lY3RvcnM7XG5cbiAgICByZXR1cm4gX2Nvbm5lY3RvcnMuZmlsdGVyKGZ1bmN0aW9uKGNuY3QpIHtcbiAgICAgICAgcmV0dXJuIGNuY3QuaXNPbiA9PT0gb25PZmY7XG4gICAgfSk7XG59XG5cblxuZnVuY3Rpb24gbWluZGVyX2Rlc3Ryb3lDb25uZWN0b3IoY25jdCkge1xuICAgIGNuY3QuZGVzdHJveSgpO1xuICAgIHZhciBpbmRleCA9IF9jb25uZWN0b3JzLmluZGV4T2YoY25jdCk7XG4gICAgaWYgKGluZGV4ID49IDApXG4gICAgICAgIGRlbGV0ZSBfY29ubmVjdG9yc1tpbmRleF07XG4gICAgZWxzZVxuICAgICAgICBsb2dnZXIud2FybignbWluZGVyOiBjb25uZWN0b3IgZGVzdHJveWVkIHRoYXQgaXMgbm90IHJlZ2lzdGVyZWQgaW4gbWluZGVyJyk7XG59XG5cblxuZnVuY3Rpb24gbWluZGVyX2dldEV4cGFuZGVkQ29ubmVjdGlvbnMob25PZmYsIHNlYXJjaFN0cikge1xuICAgIHZhciBjb25uZWN0b3JzID0gbWluZGVyLmdldENvbm5lY3RvcnMob25PZmYpO1xuICAgIHZhciBjb25uZWN0aW9ucyA9ICBjb25uZWN0b3JzLm1hcChmdW5jdGlvbihjbmN0KSB7XG4gICAgICAgIHZhciBjb25uZWN0aW9uID0ge1xuICAgICAgICAgICAgbGVmdFNvdXJjZTogX2dldEV4cGFuZGVkU291cmNlKGNuY3QuZHMxKSxcbiAgICAgICAgICAgIHJpZ2h0U291cmNlOiBfZ2V0RXhwYW5kZWRTb3VyY2UoY25jdC5kczIpLFxuICAgICAgICAgICAgbW9kZTogY25jdC5tb2RlLFxuICAgICAgICAgICAgaXNPbjogY25jdC5pc09uXG4gICAgICAgIH07XG4gICAgICAgIFxuICAgICAgICBpZiAoY25jdC5vcHRpb25zKVxuICAgICAgICAgICAgY29ubmVjdGlvbi5vcHRpb25zID0gY25jdC5vcHRpb25zO1xuXG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uO1xuICAgIH0pO1xuXG4gICAgaWYgKHNlYXJjaFN0cilcbiAgICAgICAgY29ubmVjdGlvbnMgPSBjb25uZWN0aW9ucy5maWx0ZXIoZnVuY3Rpb24oY25jdG4pIHtcbiAgICAgICAgICAgIHJldHVybiBfc291cmNlTWF0Y2hlc1N0cmluZyhjbmN0bi5sZWZ0U291cmNlLCBzZWFyY2hTdHIpXG4gICAgICAgICAgICAgICAgICAgIHx8IF9zb3VyY2VNYXRjaGVzU3RyaW5nKGNuY3RuLnJpZ2h0U291cmNlLCBzZWFyY2hTdHIpO1xuICAgICAgICB9KTtcblxuICAgIHJldHVybiBjb25uZWN0aW9ucztcbn1cblxuXG5mdW5jdGlvbiBfZ2V0RXhwYW5kZWRTb3VyY2UoZHMpIHtcbiAgICB2YXIgc291cmNlID0gW107XG4gICAgaWYgKHR5cGVvZiBkcyA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIGlmIChkcy5fbW9kZWwgJiYgZHMuX2FjY2Vzc1BhdGgpIHtcbiAgICAgICAgICAgIHNvdXJjZS51bnNoaWZ0KGRzLl9hY2Nlc3NQYXRoKTtcbiAgICAgICAgICAgIGRzID0gZHMuX21vZGVsO1xuICAgICAgICB9XG5cbiAgICAgICAgc291cmNlLnVuc2hpZnQoZHMpO1xuICAgICAgICBkcyA9IGRzLl9ob3N0T2JqZWN0O1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgZHMgPT0gJ29iamVjdCcpIHtcbiAgICAgICAgc291cmNlLnVuc2hpZnQoZHMpO1xuXG4gICAgICAgIGlmIChkcy5vd25lcilcbiAgICAgICAgICAgIHNvdXJjZS51bnNoaWZ0KGRzLm93bmVyKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc291cmNlO1xufVxuXG5cbmZ1bmN0aW9uIF9zb3VyY2VNYXRjaGVzU3RyaW5nKHNvdXJjZSwgbWF0Y2hTdHIpIHtcbiAgICByZXR1cm4gc291cmNlLnNvbWUoZnVuY3Rpb24oc3JjTm9kZSkge1xuICAgICAgICB2YXIgY2xhc3NOYW1lID0gc3JjTm9kZS5jb25zdHJ1Y3RvciAmJiBzcmNOb2RlLmNvbnN0cnVjdG9yLm5hbWU7XG4gICAgICAgIHJldHVybiBfc3RyaW5nTWF0Y2goY2xhc3NOYW1lLCBtYXRjaFN0cilcbiAgICAgICAgICAgICAgICB8fCBfc3RyaW5nTWF0Y2goc3JjTm9kZS5uYW1lLCBtYXRjaFN0cilcbiAgICAgICAgICAgICAgICB8fCBfc3RyaW5nTWF0Y2goc3JjTm9kZSwgbWF0Y2hTdHIpO1xuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIF9zdHJpbmdNYXRjaChzdHIsIHN1YnN0cikge1xuICAgIHJldHVybiBzdHIgJiYgdHlwZW9mIHN0ciA9PSAnc3RyaW5nJyAmJiBzdHIuaW5kZXhPZihzdWJzdHIpID49IDA7XG59XG5cblxuZnVuY3Rpb24gbWluZGVyX2Rlc3Ryb3koKSB7XG4gICAgX2Nvbm5lY3RvcnMuZm9yRWFjaChmdW5jdGlvbihjbmN0KSB7XG4gICAgICAgIGRlc3Ryb3lEUyhjbmN0LmRzMSk7XG4gICAgICAgIGRlc3Ryb3lEUyhjbmN0LmRzMik7XG4gICAgICAgIGNuY3QuZGVzdHJveSgpO1xuICAgIH0pO1xuICAgIF9tZXNzZW5nZXIuZGVzdHJveSgpO1xuICAgIG1pbmRlci5fZGVzdHJveWVkID0gdHJ1ZTtcblxuICAgIGZ1bmN0aW9uIGRlc3Ryb3lEUyhkcykge1xuICAgICAgICBpZiAoZHMgJiYgIWRzLl9kZXN0cm95ZWQpIGRzLmRlc3Ryb3koKTtcbiAgICB9XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIGxvZ2dlciA9IHJlcXVpcmUoJy4uL3V0aWwvbG9nZ2VyJylcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4uL2NvbmZpZycpXG4gICAgLCBwYXRoVXRpbHMgPSByZXF1aXJlKCcuL3BhdGhfdXRpbHMnKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG4vKipcbiAqIFV0aWxpdHkgZnVuY3Rpb24gdG8gcHJvY2VzcyBcImNoYW5nZWRhdGFcIiBtZXNzYWdlcyBlbWl0dGVkIGJ5IENvbm5lY3RvciBvYmplY3QuXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gY2hhbmdlRGF0YUhhbmRsZXI7XG5cblxuXy5leHRlbmQoY2hhbmdlRGF0YUhhbmRsZXIsIHtcbiAgICBzZXRUcmFuc2FjdGlvbkZsYWc6IHNldFRyYW5zYWN0aW9uRmxhZyxcbiAgICBnZXRUcmFuc2FjdGlvbkZsYWc6IGdldFRyYW5zYWN0aW9uRmxhZyxcbiAgICBwYXNzVHJhbnNhY3Rpb25GbGFnOiBwYXNzVHJhbnNhY3Rpb25GbGFnLFxuICAgIHBvc3RUcmFuc2FjdGlvbkZpbmlzaGVkOiBwb3N0VHJhbnNhY3Rpb25GaW5pc2hlZFxufSk7XG5cblxuLyoqXG4gKiBDaGFuZ2UgZGF0YSB1c2VzIGhpZGRlbiBwcm9wZXJ0eSBvbiBhY2Nlc3NvciBtZXRob2RzIHRvIHBhc3MgZmxhZyB0aGF0IHRoZSBhY2Nlc3NvciBpcyBleGVjdXRlZCBhcyBhIHBhcnQgb2YgY2hhbmdlIHRyYW5zYWN0aW9uLlxuICogQWNjZXNzb3IgbWV0aG9kcyBhcmUgc3VwcG9zZWQgdG8gc3RvcmUgdGhpcyBmbGFnIGluIGEgbG9jYWwgdmFyaWFibGUgYW5kIHRvIGNsZWFyIGl0IChiZWNhdXNlIGFub3RoZXIgYWNjZXNzb3IgY2FuIGJlIGV4ZWN1dGVkIGluIG9yIG91dCBvZiB0cmFuc2FjdGlvbikgdXNpbmcgYGdldFRyYW5zYWN0aW9uRmxhZ2BcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBhY2Nlc3NvciBtZXRob2QgcmVmZXJlbmNlXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGZsYWcgYSBmbGFnIHRvIGJlIHNldFxuICovXG5mdW5jdGlvbiBzZXRUcmFuc2FjdGlvbkZsYWcoZnVuYywgZmxhZykge1xuICAgIF8uZGVmaW5lUHJvcGVydHkoZnVuYywgJ19faW5DaGFuZ2VUcmFuc2FjdGlvbicsIGZsYWcsIF8uQ09ORiB8IF8uV1JJVCk7XG59XG5cblxuLyoqXG4gKiBSZXRyaWV2ZXMgYW5kIGNsZWFycyB0cmFuc2FjdGlvbiBmbGFnIGZyb20gYWNjZXNzb3IgbWV0aG9kXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgYWNjZXNzb3IgbWV0aG9kIHJlZmVyZW5jZVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25GbGFnKGZ1bmMpIHtcbiAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGZ1bmMuX19pbkNoYW5nZVRyYW5zYWN0aW9uO1xuICAgIGRlbGV0ZSBmdW5jLl9faW5DaGFuZ2VUcmFuc2FjdGlvbjtcbiAgICByZXR1cm4gaW5UcmFuc2FjdGlvbjtcbn1cblxuXG5mdW5jdGlvbiBwYXNzVHJhbnNhY3Rpb25GbGFnKGZyb21GdW5jLCB0b0Z1bmMpIHtcbiAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGdldFRyYW5zYWN0aW9uRmxhZyhmcm9tRnVuYyk7XG4gICAgc2V0VHJhbnNhY3Rpb25GbGFnKHRvRnVuYywgaW5UcmFuc2FjdGlvbik7XG4gICAgcmV0dXJuIGluVHJhbnNhY3Rpb247XG59XG5cblxuLyoqXG4gKiBQb3N0cyBtZXNzYWdlIG9uIHRoaXMgdG8gaW5kaWNhdGUgdGhlIGVuZCBvZiB0cmFuc2FjdGlvbiB1bmxlc3MgYGluQ2hhbmdlVHJhbnNhY3Rpb25gIGlzIGB0cnVlYC5cbiAqL1xuZnVuY3Rpb24gcG9zdFRyYW5zYWN0aW9uRmluaXNoZWQoKSB7XG4gICAgdGhpcy5wb3N0TWVzc2FnZVN5bmMoJ2RhdGFjaGFuZ2VzJywgeyB0cmFuc2FjdGlvbjogZmFsc2UsIGNoYW5nZXM6IFtdIH0pO1xufVxuXG5cbi8qKlxuICogc3Vic2NyaWJlciB0byBcImNoYW5nZWRhdGFcIiBldmVudCBlbWl0dGVkIGJ5IFtDb25uZWN0b3JdKC4vY29ubmVjdG9yLmpzLmh0bWwpIG9iamVjdCB0byBlbmFibGUgcmVhY3RpdmUgY29ubmVjdGlvbnNcbiAqIFVzZWQgYnkgRGF0YSBmYWNldCwgTW9kZWwgYW5kIE1vZGVsUGF0aC4gQ2FuIGJlIHVzZWQgYnkgYW55IG9iamVjdCB0aGF0IGltcGxlbWVudHMgZ2V0L3NldC9kZWwvc3BsaWNlIGFwaSBhbmQgc2V0cyBkYXRhIGRlZXBseSB0byB0aGUgd2hvbGUgdHJlZS5cbiAqIE9iamVjdCBzaG91bGQgY2FsbCBgY2hhbmdlRGF0YUhhbmRsZXIuaW5pdGlhbGl6ZS5jYWxsKHRoaXMpYCBpbiBpdHMgY29uc3RydWN0b3IuXG4gKiBUT0RPOiBvcHRpbWl6ZSBtZXNzYWdlcyBsaXN0IHRvIGF2b2lkIHNldHRpbmcgZHVwbGljYXRlIHZhbHVlcyBkb3duIHRoZSB0cmVlXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1zZyBzaG91bGQgYmUgXCJjaGFuZ2VkYXRhXCIgaGVyZVxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgYmF0Y2ggb2YgZGF0YSBjaGFuZ2UgZGVzY2lwdGlvbiBvYmplY3RzXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBjYWxsYmFjayB0byBjYWxsIGJlZm9yZSBhbmQgYWZ0ZXIgdGhlIGRhdGEgaXMgcHJvY2Vzc2VkXG4gKi9cbmZ1bmN0aW9uIGNoYW5nZURhdGFIYW5kbGVyKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrKSB7XG4gICAgcHJvY2Vzc0NoYW5nZXMuY2FsbCh0aGlzLCBkYXRhLmNoYW5nZXMsIGNhbGxiYWNrKTtcbn1cblxuXG4vLyBtYXAgb2YgbWVzc2FnZSB0eXBlcyB0byBtZXRob2RzXG52YXIgQ0hBTkdFX1RZUEVfVE9fTUVUSE9EX01BUCA9IHtcbiAgICAnYWRkZWQnOiAgICdzZXQnLFxuICAgICdjaGFuZ2VkJzogJ3NldCcsXG4gICAgJ2RlbGV0ZWQnOiAnZGVsJyxcbiAgICAncmVtb3ZlZCc6ICdkZWwnXG59O1xuXG5cbi8qKlxuICogUHJvY2Vzc2VzIHF1ZXVlZCBcImNoYW5nZWRhdGFcIiBtZXNzYWdlcy5cbiAqIFBvc3RzIFwiY2hhbmdlc3RhcnRlZFwiIGFuZCBcImNoYW5nZWNvbXBsZXRlZFwiIG1lc3NhZ2VzIGFuZCBjYWxscyBjYWxsYmFja1xuICpcbiAqIEBwYXJhbSB7W0Z1bmN0aW9uXX0gY2FsbGJhY2sgb3B0aW9uYWwgY2FsbGJhY2sgdGhhdCBpcyBjYWxsZWQgd2l0aCBgKG51bGwsIGZhbHNlKWAgcGFyYW1ldGVycyBiZWZvcmUgY2hhbmdlIHByb2Nlc3Npbmcgc3RhcnRzIGFuZCBgKG51bGwsIHRydWUpYCBhZnRlciBpdCdzIGZpbmlzaGVkLlxuICovXG5mdW5jdGlvbiBwcm9jZXNzQ2hhbmdlcyh0cmFuc2FjdGlvbiwgY2FsbGJhY2spIHtcbiAgICBub3RpZnkuY2FsbCh0aGlzLCBjYWxsYmFjaywgZmFsc2UpO1xuICAgIHByb2Nlc3NUcmFuc2FjdGlvbi5jYWxsKHRoaXMsXG4gICAgICAgIHByZXBhcmVUcmFuc2FjdGlvbihcbiAgICAgICAgICAgIHZhbGlkYXRlVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pKSk7XG4gICAgbm90aWZ5LmNhbGwodGhpcywgY2FsbGJhY2ssIHRydWUpO1xufVxuXG5cbmZ1bmN0aW9uIG5vdGlmeShjYWxsYmFjaywgY2hhbmdlRmluaXNoZWQpIHtcbiAgICBjYWxsYmFjayAmJiBjYWxsYmFjayhudWxsLCBjaGFuZ2VGaW5pc2hlZCk7XG4gICAgdGhpcy5wb3N0TWVzc2FnZShjaGFuZ2VGaW5pc2hlZCA/ICdjaGFuZ2Vjb21wbGV0ZWQnIDogJ2NoYW5nZXN0YXJ0ZWQnKTtcbn1cblxuXG4vKipcbiAqIENoZWNrcyB0aGF0IGFsbCBtZXNzYWdlcyBmcm9tIHRoZSB0cmFuc2FjdGlvbiBjb21lIGZyb20gdGhlIHNhbWUgc291cmNlLlxuICogSGFjazogcmV2ZXJzZXMgdGhlIHRyYW5zYWN0aW9uIGlmIGl0IGNvbWVzIGZyb20gdGhlIERhdGEgZmFjZXRcbiAqIFJldHVybnMgdGhlIHJlZmVyZW5jZSB0byB0aGUgdHJhbnNhY3Rpb24gKGZvciBjaGFpbmluZylcbiAqIFxuICogQHBhcmFtICB7QXJyYXl9IHRyYW5zYWN0aW9uIHRyYW5zYWN0aW9uIG9mIGRhdGEgY2hhbmdlc1xuICogQHJldHVybiB7QXJyYXl9IFxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZVRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKSB7XG4gICAgdmFyIHNvdXJjZSA9IHRyYW5zYWN0aW9uWzBdLnNvdXJjZVxuICAgICAgICAsIHNhbWVTb3VyY2UgPSB0cnVlO1xuXG4gICAgaWYgKHRyYW5zYWN0aW9uLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDEsIGxlbiA9IHRyYW5zYWN0aW9uLmxlbmd0aDsgaSA8IGxlbjsgaSsrKVxuICAgICAgICAgICAgaWYgKHRyYW5zYWN0aW9uW2ldLnNvdXJjZSAhPSBzb3VyY2UpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ2NoYW5nZWRhdGE6IGNoYW5nZXMgZnJvbSBkaWZmZXJlbnQgc291cmNlcyBpbiB0aGUgc2FtZSB0cmFuc2FjdGlvbiwgc291cmNlczonLCB0cmFuc2FjdGlvbltpXS5zb3VyY2UubmFtZSwgc291cmNlLm5hbWUpO1xuICAgICAgICAgICAgICAgIHNhbWVTb3VyY2UgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBzb3VyY2UgPSB0cmFuc2FjdGlvbltpXS5zb3VyY2U7XG4gICAgICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRyYW5zYWN0aW9uO1xufVxuXG5cbmZ1bmN0aW9uIHByZXBhcmVUcmFuc2FjdGlvbih0cmFuc2FjdGlvbikge1xuICAgIHZhciB0b2RvID0gW11cbiAgICAgICAgLCBwYXRoc1RvU3BsaWNlID0gW11cbiAgICAgICAgLCBwYXRoc1RvQ2hhbmdlID0gW11cbiAgICAgICAgLCBoYWRTcGxpY2VcbiAgICAgICAgLCBleGl0TG9vcCA9IHt9O1xuXG5cbiAgICB0cnkgeyB0cmFuc2FjdGlvbi5mb3JFYWNoKGNoZWNrQ2hhbmdlKTsgfVxuICAgIGNhdGNoIChlKSB7IGlmIChlICE9IGV4aXRMb29wKSB0aHJvdyBlOyB9XG5cbiAgICByZXR1cm4gdG9kbztcblxuXG4gICAgZnVuY3Rpb24gY2hlY2tDaGFuZ2UoZGF0YSkge1xuICAgICAgICAoZGF0YS50eXBlID09ICdzcGxpY2UnID8gY2hlY2tTcGxpY2UgOiBjaGVja01ldGhvZCkoZGF0YSk7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBjaGVja1NwbGljZShkYXRhKSB7XG4gICAgICAgIHZhciBwYXJzZWRQYXRoID0gcGF0aFV0aWxzLnBhcnNlQWNjZXNzUGF0aChkYXRhLnBhdGgpO1xuICAgICAgICB2YXIgcGFyZW50UGF0aENoYW5nZWQgPSBwYXRoc1RvQ2hhbmdlLnNvbWUoZnVuY3Rpb24ocGFyZW50UGF0aCkge1xuICAgICAgICAgICAgaWYgKHBhcnNlZFBhdGgubGVuZ3RoIDwgcGFyZW50UGF0aC5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgICAgIHJldHVybiBfcGF0aElzUGFyZW50T2YocGFyZW50UGF0aCwgcGFyc2VkUGF0aCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChwYXJlbnRQYXRoQ2hhbmdlZCkgcmV0dXJuO1xuXG4gICAgICAgIHRvZG8ucHVzaChkYXRhKTtcblxuICAgICAgICBpZiAoISBjb25maWcuZGVidWcpIHRocm93IGV4aXRMb29wO1xuICAgICAgICBwYXRoc1RvU3BsaWNlLnB1c2gocGFyc2VkUGF0aCk7XG4gICAgICAgIGhhZFNwbGljZSA9IHRydWU7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBjaGVja01ldGhvZChkYXRhKSB7XG4gICAgICAgIHZhciBwYXJzZWRQYXRoID0gcGF0aFV0aWxzLnBhcnNlQWNjZXNzUGF0aChkYXRhLnBhdGgpO1xuICAgICAgICB2YXIgcGFyZW50UGF0aFNwbGljZWQgPSBwYXRoc1RvU3BsaWNlICYmIHBhdGhzVG9TcGxpY2Uuc29tZShmdW5jdGlvbihwYXJlbnRQYXRoKSB7XG4gICAgICAgICAgICBpZiAocGFyc2VkUGF0aC5sZW5ndGggPD0gcGFyZW50UGF0aC5sZW5ndGhcbiAgICAgICAgICAgICAgICB8fCBwYXJzZWRQYXRoW3BhcmVudFBhdGgubGVuZ3RoXS5zeW50YXggIT0gJ2FycmF5JykgcmV0dXJuO1xuICAgICAgICAgICAgcmV0dXJuIF9wYXRoSXNQYXJlbnRPZihwYXJlbnRQYXRoLCBwYXJzZWRQYXRoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHBhcmVudFBhdGhTcGxpY2VkKSByZXR1cm47XG4gICAgICAgIGlmIChoYWRTcGxpY2UpIGxvZ2dlci5lcnJvcignY2hhbmdlZGF0YTogY2hpbGQgY2hhbmdlIGlzIGV4ZWN1dGVkIGFmdGVyIHNwbGljZTsgcHJvYmFibHkgZGF0YSBzb3VyY2UgZGlkIG5vdCBlbWl0IG1lc3NhZ2Ugd2l0aCBkYXRhLnR5cGU9PVwiZmluaXNoZWRcIicpO1xuXG4gICAgICAgIHZhciBwYXJlbnRQYXRoQ2hhbmdlZCA9IHBhdGhzVG9DaGFuZ2Uuc29tZShmdW5jdGlvbihwYXJlbnRQYXRoKSB7XG4gICAgICAgICAgICBpZiAocGFyc2VkUGF0aC5sZW5ndGggPD0gcGFyZW50UGF0aC5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgICAgIHJldHVybiBfcGF0aElzUGFyZW50T2YocGFyZW50UGF0aCwgcGFyc2VkUGF0aCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChwYXJlbnRQYXRoQ2hhbmdlZCkgcmV0dXJuO1xuXG4gICAgICAgIHBhdGhzVG9DaGFuZ2UucHVzaChwYXJzZWRQYXRoKTtcblxuICAgICAgICB0b2RvLnB1c2goZGF0YSk7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBfcGF0aElzUGFyZW50T2YocGFyZW50UGF0aCwgY2hpbGRQYXRoKSB7XG4gICAgICAgIHJldHVybiBwYXJlbnRQYXRoLmV2ZXJ5KGZ1bmN0aW9uKHBhdGhOb2RlLCBpbmRleCkge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGhOb2RlLnByb3BlcnR5ID09IGNoaWxkUGF0aFtpbmRleF0ucHJvcGVydHk7XG4gICAgICAgIH0pO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBwcm9jZXNzVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pIHtcbiAgICB0cmFuc2FjdGlvbi5mb3JFYWNoKHByb2Nlc3NDaGFuZ2UsIHRoaXMpO1xuICAgIHBvc3RUcmFuc2FjdGlvbkZpbmlzaGVkLmNhbGwodGhpcywgZmFsc2UpO1xuXG4gICAgZnVuY3Rpb24gcHJvY2Vzc0NoYW5nZShkYXRhKSB7XG4gICAgICAgIHZhciBtb2RlbFBhdGggPSB0aGlzLnBhdGgoZGF0YS5wYXRoLCBkYXRhLnR5cGUgIT0gJ3JlbW92ZWQnICYmIGRhdGEudHlwZSAhPSAnZGVsZXRlZCcpO1xuICAgICAgICBpZiAoISBtb2RlbFBhdGgpIHJldHVybjtcbiAgICAgICAgKGRhdGEudHlwZSA9PSAnc3BsaWNlJyA/IGV4ZWN1dGVTcGxpY2UgOiBleGVjdXRlTWV0aG9kKShtb2RlbFBhdGgsIGRhdGEpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBleGVjdXRlU3BsaWNlKG1vZGVsUGF0aCwgZGF0YSkge1xuICAgIHZhciBpbmRleCA9IGRhdGEuaW5kZXhcbiAgICAgICAgLCBob3dNYW55ID0gZGF0YS5yZW1vdmVkLmxlbmd0aFxuICAgICAgICAsIHNwbGljZUFyZ3MgPSBbaW5kZXgsIGhvd01hbnldO1xuXG4gICAgc3BsaWNlQXJncyA9IHNwbGljZUFyZ3MuY29uY2F0KGRhdGEubmV3VmFsdWUuc2xpY2UoaW5kZXgsIGluZGV4ICsgZGF0YS5hZGRlZENvdW50KSk7XG4gICAgc2V0VHJhbnNhY3Rpb25GbGFnKG1vZGVsUGF0aC5zcGxpY2UsIHRydWUpO1xuICAgIG1vZGVsUGF0aC5zcGxpY2UuYXBwbHkobW9kZWxQYXRoLCBzcGxpY2VBcmdzKTtcbn1cblxuXG5mdW5jdGlvbiBleGVjdXRlTWV0aG9kKG1vZGVsUGF0aCwgZGF0YSkge1xuICAgIHZhciBtZXRob2ROYW1lID0gQ0hBTkdFX1RZUEVfVE9fTUVUSE9EX01BUFtkYXRhLnR5cGVdO1xuICAgIGlmIChtZXRob2ROYW1lKSB7XG4gICAgICAgIHNldFRyYW5zYWN0aW9uRmxhZyhtb2RlbFBhdGhbbWV0aG9kTmFtZV0sIHRydWUpO1xuICAgICAgICBtb2RlbFBhdGhbbWV0aG9kTmFtZV0oZGF0YS5uZXdWYWx1ZSk7XG4gICAgfSBlbHNlXG4gICAgICAgIGxvZ2dlci5lcnJvcigndW5rbm93biBkYXRhIGNoYW5nZSB0eXBlJyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBNZXNzZW5nZXIgPSByZXF1aXJlKCcuLi9tZXNzZW5nZXInKVxuICAgICwgcGF0aFV0aWxzID0gcmVxdWlyZSgnLi9wYXRoX3V0aWxzJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vdXRpbC9sb2dnZXInKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IENvbm5lY3RvcjtcblxuXG52YXIgbW9kZVBhdHRlcm4gPSAvXihcXDwqKVxcLSsoXFw+KikkLztcblxuXG4vKipcbiAqIENvbm5lY3RvclxuICogQ2xhc3MgdGhhdCBjcmVhdGVzIGNvbm5lY3RvciBvYmplY3QgZm9yIGRhdGEgY29ubmVjdGlvbiBiZXR3ZWVuXG4gKiB0d28gZGF0YS1zb3VyY2VzXG4gKiBEYXRhLXNvdXJjZXMgc2hvdWxkIGltcGxlbWVudCB0aGUgZm9sbG93aW5nIEFQSTpcbiAqIGdldCgpIC0gZ2V0IHZhbHVlIGZyb20gZGF0YXNvdXJjZSBvciBpdHMgcGF0aFxuICogc2V0KHZhbHVlKSAtIHNldCB2YWx1ZSB0byBkYXRhc291cmNlIG9yIHRvIGl0cyBwYXRoXG4gKiBvbihwYXRoLCBzdWJzY3JpYmVyKSAtIHN1YnNjcmlwdGlvbiB0byBkYXRhIGNoYW5nZXMgd2l0aCBcIipcIiBzdXBwb3J0XG4gKiBvZmYocGF0aCwgc3Vic2NyaWJlcilcbiAqIHBhdGgoYWNjZXNzUGF0aCkgLSB0byByZXR1cm4gdGhlIG9iamVjdCB0aGF0IGdpdmVzIHJlZmVyZW5jZSB0byBzb21lIHBhcnQgb2YgZGF0YXNvdXJjZVxuICogYW5kIGNvbXBsaWVzIHdpdGggdGhhdCBhcGkgdG9vLlxuICpcbiAqICMjIyNFdmVudHMjIyMjXG4gKlxuICogLSAndHVybmVkb24nIC0gY29ubmVjdG9yIHdhcyB0dXJuZWQgb25cbiAqIC0gJ3R1cm5lZG9mZicgLSBjb25uZWN0b3Igd2FzIHR1cm5lZCBvZmZcbiAqIC0gJ2NoYW5nZXN0YXJ0ZWQnIC0gY2hhbmdlIG9uIGNvbm5lY3RlZCBkYXRhc291cmNlIGlzIHN0YXJ0ZWRcbiAqIC0gJ2NoYW5nZWNvbXBsZXRlZCcgLSBjaGFuZ2Ugb24gY29ubmVjdGVkIGRhdGFzb3VyY2UgaXMgY29tcGxldGVkXG4gKiAtICdkZXN0cm95ZWQnIC0gY29ubmVjdG9yIHdhcyBkZXN0cm95ZWRcbiAqIFxuICogQHBhcmFtIHtPYmplY3R9IGRzMSB0aGUgZmlyc3QgZGF0YSBzb3VyY2UuXG4gKiBAcGFyYW0ge1N0cmluZ30gbW9kZSB0aGUgY29ubmVjdGlvbiBtb2RlIHRoYXQgZGVmaW5lcyB0aGUgZGlyZWN0aW9uIGFuZCB0aGUgZGVwdGggb2YgY29ubmVjdGlvbi4gUG9zc2libGUgdmFsdWVzIGFyZSAnLT4nLCAnPDwtJywgJzw8PC0+Pj4nLCBldGMuXG4gKiBAcGFyYW0ge09iamVjdH0gZHMyIHRoZSBzZWNvbmQgZGF0YSBzb3VyY2VcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIG5vdCBpbXBsZW1lbnRlZCB5ZXRcbiAqIEByZXR1cm4ge0Nvbm5lY3Rvcn0gd2hlbiBjYWxsZWQgd2l0aCBgbmV3YCwgY3JlYXRlcyBhIENvbm5lY3RvciBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIENvbm5lY3RvcihkczEsIG1vZGUsIGRzMiwgb3B0aW9ucykge1xuICAgIHNldHVwTW9kZS5jYWxsKHRoaXMsIG1vZGUpO1xuXG4gICAgXy5leHRlbmQodGhpcywge1xuICAgICAgICBkczE6IGRzMSxcbiAgICAgICAgZHMyOiBkczIsXG4gICAgICAgIGlzT246IGZhbHNlLFxuICAgICAgICBfY2hhbmdlc1F1ZXVlMTogW10sXG4gICAgICAgIF9jaGFuZ2VzUXVldWUyOiBbXSxcbiAgICAgICAgX21lc3NlbmdlcjogbmV3IE1lc3Nlbmdlcih0aGlzLCBNZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMpXG4gICAgfSk7XG5cbiAgICBpZiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuXG4gICAgICAgIHZhciBwYXRoVHJhbnNsYXRpb24gPSBvcHRpb25zLnBhdGhUcmFuc2xhdGlvbjtcbiAgICAgICAgaWYgKHBhdGhUcmFuc2xhdGlvbikge1xuICAgICAgICAgICAgcGF0aFRyYW5zbGF0aW9uID0gXy5jbG9uZShwYXRoVHJhbnNsYXRpb24pO1xuICAgICAgICAgICAgdmFyIHBhdHRlcm5UcmFuc2xhdGlvbiA9IGdldFBhdHRlcm5UcmFuc2xhdGlvbnMocGF0aFRyYW5zbGF0aW9uKTtcbiAgICAgICAgICAgIF8uZXh0ZW5kKHRoaXMsIHtcbiAgICAgICAgICAgICAgICBwYXRoVHJhbnNsYXRpb24xOiByZXZlcnNlVHJhbnNsYXRpb25SdWxlcyhwYXRoVHJhbnNsYXRpb24pLFxuICAgICAgICAgICAgICAgIHBhdGhUcmFuc2xhdGlvbjI6IHBhdGhUcmFuc2xhdGlvbixcbiAgICAgICAgICAgICAgICBwYXR0ZXJuVHJhbnNsYXRpb24xOiByZXZlcnNlUGF0dGVyblRyYW5zbGF0aW9uUnVsZXMocGF0dGVyblRyYW5zbGF0aW9uKSxcbiAgICAgICAgICAgICAgICBwYXR0ZXJuVHJhbnNsYXRpb24yOiBwYXR0ZXJuVHJhbnNsYXRpb25cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGFUcmFuc2xhdGlvbiA9IG9wdGlvbnMuZGF0YVRyYW5zbGF0aW9uO1xuICAgICAgICBpZiAoZGF0YVRyYW5zbGF0aW9uKSB7XG4gICAgICAgICAgICBfLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICAgICAgZGF0YVRyYW5zbGF0aW9uMTogZGF0YVRyYW5zbGF0aW9uWyc8LSddLFxuICAgICAgICAgICAgICAgIGRhdGFUcmFuc2xhdGlvbjI6IGRhdGFUcmFuc2xhdGlvblsnLT4nXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZGF0YVZhbGlkYXRpb24gPSBvcHRpb25zLmRhdGFWYWxpZGF0aW9uO1xuICAgICAgICBpZiAoZGF0YVZhbGlkYXRpb24pIHtcbiAgICAgICAgICAgIF8uZXh0ZW5kKHRoaXMsIHtcbiAgICAgICAgICAgICAgICBkYXRhVmFsaWRhdGlvbjE6IGRhdGFWYWxpZGF0aW9uWyc8LSddLFxuICAgICAgICAgICAgICAgIGRhdGFWYWxpZGF0aW9uMjogZGF0YVZhbGlkYXRpb25bJy0+J11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy50dXJuT24oKTtcbn1cblxuXG5mdW5jdGlvbiBzZXR1cE1vZGUobW9kZSl7XG4gICAgdmFyIHBhcnNlZE1vZGUgPSBtb2RlLm1hdGNoKG1vZGVQYXR0ZXJuKTtcblxuICAgIGlmICghIHBhcnNlZE1vZGUpXG4gICAgICAgIG1vZGVQYXJzZUVycm9yKCk7XG5cbiAgICB2YXIgZGVwdGgxID0gcGFyc2VkTW9kZVsxXS5sZW5ndGhcbiAgICAgICAgLCBkZXB0aDIgPSBwYXJzZWRNb2RlWzJdLmxlbmd0aDtcblxuICAgIGlmIChkZXB0aDEgJiYgZGVwdGgyICYmIGRlcHRoMSAhPSBkZXB0aDIpXG4gICAgICAgIG1vZGVQYXJzZUVycm9yKCk7XG5cbiAgICBpZiAoISBkZXB0aDEgJiYgISBkZXB0aDIpXG4gICAgICAgIG1vZGVQYXJzZUVycm9yKCk7XG5cbiAgICBfLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgIG1vZGU6IG1vZGUsXG4gICAgICAgIGRlcHRoMTogZGVwdGgxLFxuICAgICAgICBkZXB0aDI6IGRlcHRoMixcbiAgICB9KTtcblxuICAgIGZ1bmN0aW9uIG1vZGVQYXJzZUVycm9yKCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgQ29ubmVjdG9yIG1vZGU6ICcgKyBtb2RlKTtcbiAgICB9XG59XG5cblxuXy5leHRlbmRQcm90byhDb25uZWN0b3IsIHtcbiAgICB0dXJuT246IENvbm5lY3RvciR0dXJuT24sXG4gICAgdHVybk9mZjogQ29ubmVjdG9yJHR1cm5PZmYsXG4gICAgZGVzdHJveTogQ29ubmVjdG9yJGRlc3Ryb3ksXG4gICAgY2hhbmdlTW9kZTogQ29ubmVjdG9yJGNoYW5nZU1vZGUsXG4gICAgZGVmZXJDaGFuZ2VNb2RlOiBDb25uZWN0b3IkZGVmZXJDaGFuZ2VNb2RlXG59KTtcblxuLyoqXG4gKiBGdW5jdGlvbiBjaGFuZ2UgdGhlIG1vZGUgb2YgdGhlIGNvbm5lY3Rpb25cbiAqXG4gKiBAcGFyYW0gQHBhcmFtIHtTdHJpbmd9IG1vZGUgdGhlIGNvbm5lY3Rpb24gbW9kZSB0aGF0IGRlZmluZXMgdGhlIGRpcmVjdGlvbiBhbmQgdGhlIGRlcHRoIG9mIGNvbm5lY3Rpb24uIFBvc3NpYmxlIHZhbHVlcyBhcmUgJy0+JywgJzw8LScsICc8PDwtPj4+JywgZXRjLlxuICogQHJldHVybiB7T2JqZWN0W1N0cmluZ119XG4gKi9cbmZ1bmN0aW9uIENvbm5lY3RvciRjaGFuZ2VNb2RlKG1vZGUpIHtcbiAgICB0aGlzLnR1cm5PZmYoKTtcbiAgICBzZXR1cE1vZGUuY2FsbCh0aGlzLCBtb2RlKTtcbiAgICB0aGlzLnR1cm5PbigpO1xuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogRnVuY3Rpb24gY2hhbmdlIHRoZSBtb2RlIG9mIHRoZSBjb25uZWN0aW9uXG4gKlxuICogQHBhcmFtIEBwYXJhbSB7U3RyaW5nfSBtb2RlIHRoZSBjb25uZWN0aW9uIG1vZGUgdGhhdCBkZWZpbmVzIHRoZSBkaXJlY3Rpb24gYW5kIHRoZSBkZXB0aCBvZiBjb25uZWN0aW9uLiBQb3NzaWJsZSB2YWx1ZXMgYXJlICctPicsICc8PC0nLCAnPDw8LT4+PicsIGV0Yy5cbiAqIEByZXR1cm4ge09iamVjdFtTdHJpbmddfVxuICovXG5mdW5jdGlvbiBDb25uZWN0b3IkZGVmZXJDaGFuZ2VNb2RlKG1vZGUpIHtcbiAgICBfLmRlZmVyTWV0aG9kKHRoaXMsICdjaGFuZ2VNb2RlJywgbW9kZSk7XG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBGdW5jdGlvbiB0aGF0IHJldmVyc2VzIHRyYW5zbGF0aW9uIHJ1bGVzIGZvciBwYXRocyBvZiBjb25uZWN0ZWQgb2RhdGEgc291cmNlc1xuICpcbiAqIEBwYXJhbSB7T2JqZWN0W1N0cmluZ119IHJ1bGVzIG1hcCBvZiBwYXRocyBkZWZpbmluZyB0aGUgdHJhbnNsYXRpb24gcnVsZXNcbiAqIEByZXR1cm4ge09iamVjdFtTdHJpbmddfVxuICovXG5mdW5jdGlvbiByZXZlcnNlVHJhbnNsYXRpb25SdWxlcyhydWxlcykge1xuICAgIHZhciByZXZlcnNlUnVsZXMgPSB7fTtcbiAgICBfLmVhY2hLZXkocnVsZXMsIGZ1bmN0aW9uKHBhdGgyX3ZhbHVlLCBwYXRoMV9rZXkpIHtcbiAgICAgICAgcmV2ZXJzZVJ1bGVzW3BhdGgyX3ZhbHVlXSA9IHBhdGgxX2tleTtcbiAgICB9KTtcbiAgICByZXR1cm4gcmV2ZXJzZVJ1bGVzO1xufVxuXG5cbmZ1bmN0aW9uIGdldFBhdHRlcm5UcmFuc2xhdGlvbnMocGF0aFRyYW5zbGF0aW9uKSB7XG4gICAgdmFyIHBhdHRlcm5UcmFuc2xhdGlvbiA9IFtdO1xuICAgIF8uZWFjaEtleShwYXRoVHJhbnNsYXRpb24sIGZ1bmN0aW9uKHBhdGgyX3ZhbHVlLCBwYXRoMV9rZXkpIHtcbiAgICAgICAgdmFyIHN0YXJJbmRleDEgPSBwYXRoMV9rZXkuaW5kZXhPZignKicpXG4gICAgICAgICAgICAsIHN0YXJJbmRleDIgPSBwYXRoMl92YWx1ZS5pbmRleE9mKCcqJyk7XG4gICAgICAgIGlmIChzdGFySW5kZXgxID49IDAgJiYgc3RhckluZGV4MiA+PSAwKSB7IC8vIHBhdHRlcm4gdHJhbnNsYXRpb25cbiAgICAgICAgICAgIGlmIChwYXRoMV9rZXkuc2xpY2Uoc3RhckluZGV4MSkgIT0gcGF0aDJfdmFsdWUuc2xpY2Uoc3RhckluZGV4MikpXG4gICAgICAgICAgICAgICAgX3Rocm93SW52YWxpZFRyYW5zbGF0aW9uKHBhdGgxX2tleSwgcGF0aDJfdmFsdWUpO1xuICAgICAgICAgICAgZGVsZXRlIHBhdGhUcmFuc2xhdGlvbltwYXRoMV9rZXldOyAgICAgICAgICAgIFxuXG4gICAgICAgICAgICBwYXR0ZXJuVHJhbnNsYXRpb24ucHVzaCh7XG4gICAgICAgICAgICAgICAgZnJvbVBhdHRlcm46IHBhdGhVdGlscy5jcmVhdGVSZWdleFBhdGgocGF0aDFfa2V5KSxcbiAgICAgICAgICAgICAgICBmcm9tU3RhdGljUGF0aDogX2dldFN0YXRpY1BhdGgocGF0aDFfa2V5LCBzdGFySW5kZXgxKSxcbiAgICAgICAgICAgICAgICB0b1BhdHRlcm46IHBhdGhVdGlscy5jcmVhdGVSZWdleFBhdGgocGF0aDJfdmFsdWUpLFxuICAgICAgICAgICAgICAgIHRvU3RhdGljUGF0aDogX2dldFN0YXRpY1BhdGgocGF0aDJfdmFsdWUsIHN0YXJJbmRleDIpXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChzdGFySW5kZXgxID49IDAgfHwgc3RhckluZGV4MiA+PSAwKSAvLyBwYXR0ZXJuIG9ubHkgb24gb25lIHNpZGUgb2YgdHJhbnNsYXRpb25cbiAgICAgICAgICAgIF90aHJvd0ludmFsaWRUcmFuc2xhdGlvbihwYXRoMV9rZXksIHBhdGgyX3ZhbHVlKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBwYXR0ZXJuVHJhbnNsYXRpb247XG5cblxuICAgIGZ1bmN0aW9uIF90aHJvd0ludmFsaWRUcmFuc2xhdGlvbihwYXRoMSwgcGF0aDIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHBhdHRlcm4gdHJhbnNsYXRpb246ICcgKyBwYXRoMSArICcsICcgKyBwYXRoMik7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBfZ2V0U3RhdGljUGF0aChwYXRoLCBzdGFySW5kZXgpIHtcbiAgICAgICAgcmV0dXJuIHBhdGgucmVwbGFjZSgvW1xcLlxcW10/XFwqLiokLywgJycpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiByZXZlcnNlUGF0dGVyblRyYW5zbGF0aW9uUnVsZXMocGF0dGVyblRyYW5zbGF0aW9uKSB7XG4gICAgcmV0dXJuIHBhdHRlcm5UcmFuc2xhdGlvbi5tYXAoZnVuY3Rpb24ocHQpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGZyb21QYXR0ZXJuOiBwdC50b1BhdHRlcm4sXG4gICAgICAgICAgICBmcm9tU3RhdGljUGF0aDogcHQudG9TdGF0aWNQYXRoLFxuICAgICAgICAgICAgdG9QYXR0ZXJuOiBwdC5mcm9tUGF0dGVybixcbiAgICAgICAgICAgIHRvU3RhdGljUGF0aDogcHQuZnJvbVN0YXRpY1BhdGhcbiAgICAgICAgfTtcbiAgICB9KTtcbn1cblxuXG4vKipcbiAqIHR1cm5PblxuICogTWV0aG9kIG9mIENvbm5lY3RvciB0aGF0IGVuYWJsZXMgY29ubmVjdGlvbiAoaWYgaXQgd2FzIHByZXZpb3VzbHkgZGlzYWJsZWQpXG4gKi9cbmZ1bmN0aW9uIENvbm5lY3RvciR0dXJuT24oKSB7XG4gICAgaWYgKHRoaXMuaXNPbilcbiAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdkYXRhIHNvdXJjZXMgYXJlIGFscmVhZHkgY29ubmVjdGVkJyk7XG5cbiAgICB2YXIgc3Vic2NyaXB0aW9uUGF0aCA9IHRoaXMuX3N1YnNjcmlwdGlvblBhdGggPVxuICAgICAgICBuZXcgQXJyYXkodGhpcy5kZXB0aDEgfHwgdGhpcy5kZXB0aDIpLmpvaW4oJyonKTtcblxuICAgIHZhciBzdWJzY3JpcHRpb25QYXR0ZXJuID0gcGF0aFV0aWxzLmNyZWF0ZVJlZ2V4UGF0aChzdWJzY3JpcHRpb25QYXRoKTtcblxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZiAodGhpcy5kZXB0aDEpXG4gICAgICAgIHRoaXMuX2xpbmsxID0gbGlua0RhdGFTb3VyY2UoJ19saW5rMicsIHRoaXMuZHMyLCB0aGlzLmRzMSwgdGhpcy5fY2hhbmdlc1F1ZXVlMSwgdGhpcy5wYXRoVHJhbnNsYXRpb24xLCB0aGlzLnBhdHRlcm5UcmFuc2xhdGlvbjEsIHRoaXMuZGF0YVRyYW5zbGF0aW9uMSwgdGhpcy5kYXRhVmFsaWRhdGlvbjEpO1xuICAgIGlmICh0aGlzLmRlcHRoMilcbiAgICAgICAgdGhpcy5fbGluazIgPSBsaW5rRGF0YVNvdXJjZSgnX2xpbmsxJywgdGhpcy5kczEsIHRoaXMuZHMyLCB0aGlzLl9jaGFuZ2VzUXVldWUyLCB0aGlzLnBhdGhUcmFuc2xhdGlvbjIsIHRoaXMucGF0dGVyblRyYW5zbGF0aW9uMiwgdGhpcy5kYXRhVHJhbnNsYXRpb24yLCB0aGlzLmRhdGFWYWxpZGF0aW9uMik7XG5cbiAgICB0aGlzLmlzT24gPSB0cnVlO1xuICAgIHRoaXMucG9zdE1lc3NhZ2UoJ3R1cm5lZG9uJyk7XG5cblxuICAgIGZ1bmN0aW9uIGxpbmtEYXRhU291cmNlKHJldmVyc2VMaW5rLCBmcm9tRFMsIHRvRFMsIGNoYW5nZXNRdWV1ZSwgcGF0aFRyYW5zbGF0aW9uLCBwYXR0ZXJuVHJhbnNsYXRpb24sIGRhdGFUcmFuc2xhdGlvbiwgZGF0YVZhbGlkYXRpb24pIHtcbiAgICAgICAgZnJvbURTLm9uU3luYygnZGF0YWNoYW5nZXMnLCBvbkRhdGEpO1xuICAgICAgICByZXR1cm4gb25EYXRhO1xuXG4gICAgICAgIGZ1bmN0aW9uIG9uRGF0YShtZXNzYWdlLCBiYXRjaCkge1xuICAgICAgICAgICAgdmFyIHNlbmREYXRhID0ge1xuICAgICAgICAgICAgICAgIGNoYW5nZXM6IFtdLFxuICAgICAgICAgICAgICAgIHRyYW5zYWN0aW9uOiBiYXRjaC50cmFuc2FjdGlvblxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBiYXRjaC5jaGFuZ2VzLmZvckVhY2goZnVuY3Rpb24oY2hhbmdlKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNvdXJjZVBhdGggPSBjaGFuZ2UucGF0aFxuICAgICAgICAgICAgICAgICAgICAsIHRhcmdldFBhdGggPSB0cmFuc2xhdGVQYXRoKHNvdXJjZVBhdGgpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB0YXJnZXRQYXRoID09ICd1bmRlZmluZWQnKSByZXR1cm47XG5cbiAgICAgICAgICAgICAgICB2YXIgY2hhbmdlID0gXy5jbG9uZShjaGFuZ2UpO1xuICAgICAgICAgICAgICAgIF8uZXh0ZW5kKGNoYW5nZSwge1xuICAgICAgICAgICAgICAgICAgICBzb3VyY2U6IGZyb21EUyxcbiAgICAgICAgICAgICAgICAgICAgcGF0aDogdGFyZ2V0UGF0aFxuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRlRGF0YShzb3VyY2VQYXRoLCBjaGFuZ2UpO1xuICAgICAgICAgICAgICAgIHZhbGlkYXRlRGF0YShzb3VyY2VQYXRoLCBjaGFuZ2UpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGlmICghIGNoYW5nZXNRdWV1ZS5sZW5ndGgpXG4gICAgICAgICAgICAgICAgXy5kZWZlcihwb3N0Q2hhbmdlRGF0YSk7XG5cbiAgICAgICAgICAgIGNoYW5nZXNRdWV1ZS5wdXNoKHNlbmREYXRhKTtcblxuXG4gICAgICAgICAgICBmdW5jdGlvbiB0cmFuc2xhdGVQYXRoKHNvdXJjZVBhdGgpIHtcbiAgICAgICAgICAgICAgICBpZiAocGF0aFRyYW5zbGF0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB0cmFuc2xhdGVkUGF0aCA9IHBhdGhUcmFuc2xhdGlvbltzb3VyY2VQYXRoXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRyYW5zbGF0ZWRQYXRoKSByZXR1cm4gdHJhbnNsYXRlZFBhdGg7XG4gICAgICAgICAgICAgICAgICAgIGlmICghcGF0dGVyblRyYW5zbGF0aW9uLmxlbmd0aCkgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcHQgPSBfLmZpbmQocGF0dGVyblRyYW5zbGF0aW9uLCBmdW5jdGlvbihwVHJhbnNsYXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBwVHJhbnNsYXRpb24uZnJvbVBhdHRlcm4udGVzdChzb3VyY2VQYXRoKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghcHQpIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRyYW5zbGF0ZWRQYXRoID0gc291cmNlUGF0aC5yZXBsYWNlKHB0LmZyb21TdGF0aWNQYXRoLCBwdC50b1N0YXRpY1BhdGgpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoISAoKHN1YnNjcmlwdGlvblBhdHRlcm4gaW5zdGFuY2VvZiBSZWdFeHBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIHN1YnNjcmlwdGlvblBhdHRlcm4udGVzdChzb3VyY2VQYXRoKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8IHN1YnNjcmlwdGlvblBhdHRlcm4gPT0gc291cmNlUGF0aCkpIHJldHVybjtcblxuICAgICAgICAgICAgICAgIHJldHVybiB0cmFuc2xhdGVkUGF0aCB8fCBzb3VyY2VQYXRoO1xuICAgICAgICAgICAgfVxuXG5cbiAgICAgICAgICAgIGZ1bmN0aW9uIHRyYW5zbGF0ZURhdGEoc291cmNlUGF0aCwgY2hhbmdlKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGFUcmFuc2xhdGlvbikge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdHJhbnNsYXRlID0gZGF0YVRyYW5zbGF0aW9uW3NvdXJjZVBhdGhdO1xuICAgICAgICAgICAgICAgICAgICBpZiAodHJhbnNsYXRlICYmIHR5cGVvZiB0cmFuc2xhdGUgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2hhbmdlLm9sZFZhbHVlID0gdHJhbnNsYXRlKGNoYW5nZS5vbGRWYWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjaGFuZ2UubmV3VmFsdWUgPSB0cmFuc2xhdGUoY2hhbmdlLm5ld1ZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgIFxuICAgICAgICAgICAgZnVuY3Rpb24gdmFsaWRhdGVEYXRhKHNvdXJjZVBhdGgsIGNoYW5nZSkge1xuICAgICAgICAgICAgICAgIHByb3BhZ2F0ZURhdGEoY2hhbmdlKTtcblxuICAgICAgICAgICAgICAgIGlmIChkYXRhVmFsaWRhdGlvbikge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFsaWRhdG9ycyA9IGRhdGFWYWxpZGF0aW9uW3NvdXJjZVBhdGhdXG4gICAgICAgICAgICAgICAgICAgICAgICAsIHBhc3NlZENvdW50ID0gMFxuICAgICAgICAgICAgICAgICAgICAgICAgLCBhbHJlYWR5RmFpbGVkID0gZmFsc2U7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbGlkYXRvcnMpXG4gICAgICAgICAgICAgICAgICAgICAgICB2YWxpZGF0b3JzLmZvckVhY2goY2FsbFZhbGlkYXRvcik7ICAgXG4gICAgICAgICAgICAgICAgfVxuXG5cbiAgICAgICAgICAgICAgICBmdW5jdGlvbiBjYWxsVmFsaWRhdG9yKHZhbGlkYXRvcikge1xuICAgICAgICAgICAgICAgICAgICB2YWxpZGF0b3IoY2hhbmdlLm5ld1ZhbHVlLCBmdW5jdGlvbihlcnIsIHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNwb25zZS5wYXRoID0gc291cmNlUGF0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghIGFscmVhZHlGYWlsZWQgJiYgKGVyciB8fCByZXNwb25zZS52YWxpZCkgJiYgKytwYXNzZWRDb3VudCA9PSB2YWxpZGF0b3JzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyb21EUy5wb3N0TWVzc2FnZSgndmFsaWRhdGVkJywgcmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICghIHJlc3BvbnNlLnZhbGlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxyZWFkeUZhaWxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJvbURTLnBvc3RNZXNzYWdlKCd2YWxpZGF0ZWQnLCByZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuXG4gICAgICAgICAgICBmdW5jdGlvbiBwcm9wYWdhdGVEYXRhKGNoYW5nZSkge1xuICAgICAgICAgICAgICAgIHNlbmREYXRhLmNoYW5nZXMucHVzaChjaGFuZ2UpO1xuICAgICAgICAgICAgfVxuXG5cbiAgICAgICAgICAgIGZ1bmN0aW9uIHBvc3RDaGFuZ2VEYXRhKCkge1xuICAgICAgICAgICAgICAgIC8vIHByZXZlbnQgZW5kbGVzcyBsb29wIG9mIHVwZGF0ZXMgZm9yIDItd2F5IGNvbm5lY3Rpb25cbiAgICAgICAgICAgICAgICBpZiAoc2VsZltyZXZlcnNlTGlua10pIHZhciBjYWxsYmFjayA9IHN1YnNjcmlwdGlvblN3aXRjaDtcblxuICAgICAgICAgICAgICAgIHZhciB0cmFuc2FjdGlvbnMgPSBtZXJnZVRyYW5zYWN0aW9ucyhjaGFuZ2VzUXVldWUpO1xuICAgICAgICAgICAgICAgIGNoYW5nZXNRdWV1ZS5sZW5ndGggPSAwO1xuICAgICAgICAgICAgICAgIHRyYW5zYWN0aW9ucy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zYWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHNlbmQgZGF0YSBjaGFuZ2UgaW5zdHJ1Y3Rpb24gYXMgbWVzc2FnZVxuICAgICAgICAgICAgICAgICAgICB0b0RTLnBvc3RNZXNzYWdlU3luYygnY2hhbmdlZGF0YScsIHsgY2hhbmdlczogdHJhbnNhY3Rpb24gfSwgY2FsbGJhY2spO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG5cbiAgICAgICAgICAgIGZ1bmN0aW9uIHN1YnNjcmlwdGlvblN3aXRjaChlcnIsIGNoYW5nZUZpbmlzaGVkKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycikgcmV0dXJuO1xuICAgICAgICAgICAgICAgIHZhciBvbk9mZiA9IGNoYW5nZUZpbmlzaGVkID8gJ29uU3luYycgOiAnb2ZmJztcbiAgICAgICAgICAgICAgICB0b0RTW29uT2ZmXSgnZGF0YWNoYW5nZXMnLCBzZWxmW3JldmVyc2VMaW5rXSk7XG5cbiAgICAgICAgICAgICAgICB2YXIgbWVzc2FnZSA9IGNoYW5nZUZpbmlzaGVkID8gJ2NoYW5nZWNvbXBsZXRlZCcgOiAnY2hhbmdlc3RhcnRlZCc7XG4gICAgICAgICAgICAgICAgc2VsZi5wb3N0TWVzc2FnZShtZXNzYWdlLCB7IHNvdXJjZTogZnJvbURTLCB0YXJnZXQ6IHRvRFMgfSk7XG4gICAgICAgICAgICB9XG5cblxuICAgICAgICAgICAgZnVuY3Rpb24gbWVyZ2VUcmFuc2FjdGlvbnMoYmF0Y2hlcykge1xuICAgICAgICAgICAgICAgIHZhciB0cmFuc2FjdGlvbnMgPSBbXVxuICAgICAgICAgICAgICAgICAgICAsIGN1cnJlbnRUcmFuc2FjdGlvbjtcblxuICAgICAgICAgICAgICAgIGJhdGNoZXMuZm9yRWFjaChmdW5jdGlvbihiYXRjaCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoISBiYXRjaC50cmFuc2FjdGlvbikgY3VycmVudFRyYW5zYWN0aW9uID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICBpZiAoISBiYXRjaC5jaGFuZ2VzLmxlbmd0aCkgcmV0dXJuO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChiYXRjaC50cmFuc2FjdGlvbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRUcmFuc2FjdGlvbilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBfLmFwcGVuZEFycmF5KGN1cnJlbnRUcmFuc2FjdGlvbiwgYmF0Y2guY2hhbmdlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50VHJhbnNhY3Rpb24gPSBfLmNsb25lKGJhdGNoLmNoYW5nZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zYWN0aW9ucy5wdXNoKGN1cnJlbnRUcmFuc2FjdGlvbik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNhY3Rpb25zLnB1c2goYmF0Y2guY2hhbmdlcyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdHJhbnNhY3Rpb25zO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG5cbi8qKlxuICogdHVybk9mZlxuICogTWV0aG9kIG9mIENvbm5lY3RvciB0aGF0IGRpc2FibGVzIGNvbm5lY3Rpb24gKGlmIGl0IHdhcyBwcmV2aW91c2x5IGVuYWJsZWQpXG4gKi9cbmZ1bmN0aW9uIENvbm5lY3RvciR0dXJuT2ZmKCkge1xuICAgIGlmICghIHRoaXMuaXNPbilcbiAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdkYXRhIHNvdXJjZXMgYXJlIGFscmVhZHkgZGlzY29ubmVjdGVkJyk7XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdW5saW5rRGF0YVNvdXJjZSh0aGlzLmRzMSwgJ19saW5rMicsIHRoaXMucGF0aFRyYW5zbGF0aW9uMik7XG4gICAgdW5saW5rRGF0YVNvdXJjZSh0aGlzLmRzMiwgJ19saW5rMScsIHRoaXMucGF0aFRyYW5zbGF0aW9uMSk7XG5cbiAgICB0aGlzLmlzT24gPSBmYWxzZTtcbiAgICB0aGlzLnBvc3RNZXNzYWdlKCd0dXJuZWRvZmYnKTtcblxuXG4gICAgZnVuY3Rpb24gdW5saW5rRGF0YVNvdXJjZShmcm9tRFMsIGxpbmtOYW1lLCBwYXRoVHJhbnNsYXRpb24pIHtcbiAgICAgICAgaWYgKHNlbGZbbGlua05hbWVdKSB7XG4gICAgICAgICAgICBmcm9tRFMub2ZmKCdkYXRhY2hhbmdlcycsIHNlbGZbbGlua05hbWVdKTtcbiAgICAgICAgICAgIGRlbGV0ZSBzZWxmW2xpbmtOYW1lXTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuXG4vKipcbiAqIERlc3Ryb3lzIGNvbm5lY3RvciBvYmplY3QgYnkgdHVybmluZyBpdCBvZmYgYW5kIHJlbW92aW5nIHJlZmVyZW5jZXMgdG8gY29ubmVjdGVkIHNvdXJjZXNcbiAqL1xuZnVuY3Rpb24gQ29ubmVjdG9yJGRlc3Ryb3koKSB7XG4gICAgdGhpcy50dXJuT2ZmKCk7XG4gICAgdGhpcy5wb3N0TWVzc2FnZSgnZGVzdHJveWVkJyk7XG4gICAgdGhpcy5fbWVzc2VuZ2VyLmRlc3Ryb3koKTtcbiAgICBkZWxldGUgdGhpcy5kczE7XG4gICAgZGVsZXRlIHRoaXMuZHMyO1xuICAgIHRoaXMuX2Rlc3Ryb3llZCA9IHRydWU7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBNb2RlbFBhdGggPSByZXF1aXJlKCcuL21fcGF0aCcpXG4gICAgLCBzeW50aGVzaXplID0gcmVxdWlyZSgnLi9zeW50aGVzaXplJylcbiAgICAsIHBhdGhVdGlscyA9IHJlcXVpcmUoJy4vcGF0aF91dGlscycpXG4gICAgLCBjaGFuZ2VEYXRhSGFuZGxlciA9IHJlcXVpcmUoJy4vY2hhbmdlX2RhdGEnKVxuICAgICwgTWVzc2VuZ2VyID0gcmVxdWlyZSgnLi4vbWVzc2VuZ2VyJylcbiAgICAsIE1lc3Nlbmdlck1lc3NhZ2VTb3VyY2UgPSByZXF1aXJlKCcuLi9tZXNzZW5nZXIvbXNuZ3Jfc291cmNlJylcbiAgICAsIE1vZGVsTXNnQVBJID0gcmVxdWlyZSgnLi9tX21zZ19hcGknKVxuICAgICwgTWl4aW4gPSByZXF1aXJlKCcuLi9hYnN0cmFjdC9taXhpbicpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBsb2dnZXIgPSByZXF1aXJlKCcuLi91dGlsL2xvZ2dlcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gTW9kZWw7XG5cblxuLyoqXG4gKiBgbWlsby5Nb2RlbGBcbiAqIE1vZGVsIGNsYXNzIGluc3RhbnRpYXRlcyBvYmplY3RzIHRoYXQgYWxsb3cgZGVlcCBkYXRhIGFjY2VzcyB3aXRoIF9fc2FmZSBnZXR0ZXJzX18gdGhhdCByZXR1cm4gdW5kZWZpbmVkIChyYXRoZXIgdGhhbiB0aHJvd2luZyBleGNlcHRpb24pIHdoZW4gcHJvcGVydGllcy9pdGVtcyBvZiB1bmV4aXN0aW5nIG9iamVjdHMvYXJyYXlzIGFyZSByZXF1ZXN0ZWQgYW5kIF9fc2FmZSBzZXR0ZXJzX18gdGhhdCBjcmVhdGUgb2JqZWN0IHRyZWVzIHdoZW4gcHJvcGVydGllcy9pdGVtcyBvZiB1bmV4aXN0aW5nIG9iamVjdHMvYXJyYXlzIGFyZSBzZXQgYW5kIGFsc28gcG9zdCBtZXNzYWdlcyB0byBhbGxvdyBzdWJzY3JpcHRpb24gb24gY2hhbmdlcyBhbmQgZW5hYmxlIGRhdGEgcmVhY3Rpdml0eS5cbiAqIFJlYWN0aXZpdHkgaXMgaW1wbGVtZW1udGVkIHZpYSBbQ29ubmVjdG9yXSguL2Nvbm5lY3Rvci5qcy5odG1sKSB0aGF0IGNhbiBiZSBpbnN0YW50aWF0ZWQgZWl0aGVyIGRpcmVjdGx5IG9yIHdpdGggbW9yZSBjb252ZW5pZW50IGludGVyZmFjZSBvZiBbbWlsby5taW5kZXJdKC4uL21pbmRlci5qcy5odG1sKS4gQXQgdGhlIG1vbWVudCBtb2RlbCBjYW4gYmUgY29ubmVjdGVkIHRvIFtEYXRhIGZhY2V0XSguLi9jb21wb25lbnRzL2NfZmFjZXRzL0RhdGEuanMuaHRtbCkgb3IgdG8gYW5vdGhlciBtb2RlbCBvciBbTW9kZWxQYXRoXSguL21fcGF0aC5qcy5odG1sKS5cbiAqIE1vZGVsIGNvbnN0cnVjdG9yIHJldHVybnMgb2JqZWN0cyB0aGF0IGFyZSBmdW5jdGlvbnMgYXQgdGhlIHNhbWUgdGltZTsgd2hlbiBjYWxsZWQgdGhleSByZXR1cm4gTW9kZWxQYXRoIG9iamVjdHMgdGhhdCBhbGxvdyBnZXQvc2V0IGFjY2VzcyB0byBhbnkgcG9pbnQgaW4gbW9kZWwgZGF0YS4gU2VlIFtNb2RlbERhdGFdKCNNb2RlbERhdGEpIGJlbG93LlxuICpcbiAqIFlvdSBjYW4gc3Vic2NyaWJlIHRvIG1vZGVsIGNoYW5nZXMgd2l0aCBgb25gIG1ldGhvZCBieSBwYXNzaW5nIG1vZGVsIGFjY2VzcyBwYXRoIGluIHBsYWNlIG9mIG1lc3NhZ2UsIHBhdHRlcm4gb3Igc3RyaW5nIHdpdGggYW55IG51bWJlciBvZiBzdGFycyB0byBzdWJzY3JpYmUgdG8gYSBjZXJ0YWluIGRlcHRoIGluIG1vZGVsIChlLmcuLCBgJyoqKidgIHRvIHN1YnNjcmliZSB0byB0aHJlZSBsZXZlbHMpLlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGRhdGEgb3B0aW9uYWwgaW5pdGlhbCBhcnJheSBkYXRhLiBJZiBpdCBpcyBwbGFubmVkIHRvIGNvbm5lY3QgbW9kZWwgdG8gdmlldyBpdCBpcyB1c3VhbGx5IGJldHRlciB0byBpbnN0YW50aWF0ZSBhbiBlbXB0eSBNb2RlbCAoYHZhciBtID0gbmV3IE1vZGVsYCksIGNvbm5lY3QgaXQgdG8gW0NvbXBvbmVudF0oLi4vY29tcG9uZW50cy9jX2NsYXNzLmpzLmh0bWwpJ3MgW0RhdGEgZmFjZXRdKC4uL2NvbXBvbmVudHMvY19mYWNldHMvRGF0YS5qcy5odG1sKSAoZS5nLiwgYG1pbG8ubWluZGVyKG0sICc8PC0+PicsIGMuZGF0YSk7YCkgYW5kIHRoZW4gc2V0IHRoZSBtb2RlbCB3aXRoIGBtLnNldChkYXRhKWAgLSB0aGUgdmlldyB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgdXBkYXRlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0T2JqZWN0IG9wdGlvbmFsIG9iamVjdCB0aGF0IGhvc3RzIG1vZGVsIG9uIG9uZSBvZiBpdHMgcHJvcGVydGllcy4gQ2FuIGJlIHVzZWQgd2hlbiBtb2RlbCBpdHNlbGYgaXMgdGhlIGNvbnRleHQgb2YgdGhlIG1lc3NhZ2Ugc3Vic2NyaWJlciBhbmQgeW91IG5lZWQgdG8gdHJhdmVycyB0byB0aGlzIG9iamVjdCAoYWx0aG91Z2ggaXQgaXMgcG9zc2libGUgdG8gc2V0IGFueSBjb250ZXh0KS4gQ2FuIGFsc28gYmUgdXNlZCB0byBwcm94eSBtb2RlbCdzIG1ldGhvZHMgdG8gdGhlIGhvc3QgbGlrZSBbTW9kZWwgZmFjZXRdKC4uL2NvbXBvbmVudHMvY19mYWNldHMvTW9kZWxGYWNldC5qcy5odG1sKSBpcyBkb2luZy5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIHBhc3MgeyByZWFjdGl2ZTogZmFsc2UgfSB0byB1c2UgbW9kZWwgd2l0aG91dCBtZXNzYWdpbmcgd2hlbiBpdCBpcyBub3QgbmVlZGVkIC0gaXQgbWFrZXMgaXQgbXVjaCBmYXN0ZXJcbiAqIEByZXR1cm4ge01vZGVsfVxuICovXG5mdW5jdGlvbiBNb2RlbChkYXRhLCBob3N0T2JqZWN0LCBvcHRpb25zKSB7XG4gICAgLy8gYG1vZGVsYCB3aWxsIGJlIHJldHVybmVkIGJ5IGNvbnN0cnVjdG9yIGluc3RlYWQgb2YgYHRoaXNgLiBgbW9kZWxgXG4gICAgLy8gKGBtb2RlbFBhdGhgIGZ1bmN0aW9uKSBzaG91bGQgcmV0dXJuIGEgTW9kZWxQYXRoIG9iamVjdCB3aXRoIFwic3ludGhlc2l6ZWRcIiBtZXRob2RzXG4gICAgLy8gdG8gZ2V0L3NldCBtb2RlbCBwcm9wZXJ0aWVzLCB0byBzdWJzY3JpYmUgdG8gcHJvcGVydHkgY2hhbmdlcywgZXRjLlxuICAgIC8vIEFkZGl0aW9uYWwgYXJndW1lbnRzIG9mIG1vZGVsUGF0aCBjYW4gYmUgdXNlZCBpbiB0aGUgcGF0aCB1c2luZyBpbnRlcnBvbGF0aW9uIC0gc2VlIE1vZGVsUGF0aCBiZWxvdy5cbiAgICB2YXIgbW9kZWwgPSBmdW5jdGlvbiBtb2RlbFBhdGgoYWNjZXNzUGF0aCkgeyAvLyAsIC4uLiBhcmd1bWVudHMgdGhhdCB3aWxsIGJlIGludGVycG9sYXRlZFxuICAgICAgICByZXR1cm4gTW9kZWwkcGF0aC5hcHBseShtb2RlbCwgYXJndW1lbnRzKTtcbiAgICB9O1xuICAgIG1vZGVsLl9fcHJvdG9fXyA9IE1vZGVsLnByb3RvdHlwZTtcblxuICAgIG1vZGVsLl9ob3N0T2JqZWN0ID0gaG9zdE9iamVjdDtcbiAgICBtb2RlbC5fb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICBpZiAobW9kZWwuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XG4gICAgICAgIG1vZGVsLl9wcmVwYXJlTWVzc2VuZ2VycygpO1xuICAgICAgICAvLyBzdWJzY3JpYmUgdG8gXCJjaGFuZ2VkYXRhXCIgbWVzc2FnZSB0byBlbmFibGUgcmVhY3RpdmUgY29ubmVjdGlvbnNcbiAgICAgICAgbW9kZWwub25TeW5jKCdjaGFuZ2VkYXRhJywgY2hhbmdlRGF0YUhhbmRsZXIpO1xuICAgIH1cblxuICAgIGlmIChkYXRhKSBtb2RlbC5fZGF0YSA9IGRhdGE7XG5cbiAgICByZXR1cm4gbW9kZWw7XG59XG5cbk1vZGVsLnByb3RvdHlwZS5fX3Byb3RvX18gPSBNb2RlbC5fX3Byb3RvX187XG5cblxuLyoqXG4gKiAjIyMjTW9kZWwgaW5zdGFuY2UgbWV0aG9kcyMjIyNcbiAqXG4gKiAtIFtwYXRoXSgjcGF0aCkgLSByZXR1cm5zIE1vZGVsUGF0aCBvYmplY3QgdGhhdCBhbGxvd3MgYWNjZXNzIHRvIGFueSBwb2ludCBpbiBNb2RlbFxuICogLSBbZ2V0XSgjTW9kZWwkZ2V0KSAtIGdldCBtb2RlbCBkYXRhXG4gKiAtIHNldCAtIHNldCBtb2RlbCBkYXRhLCBzeW50aGVzaXplZFxuICogLSBzcGxpY2UgLSBzcGxpY2UgbW9kZWwgZGF0YSAoYXMgYXJyYXkgb3IgcHNldWRvLWFycmF5KSwgc3ludGhlc2l6ZWRcbiAqIC0gW2xlbl0oLi9tX3BhdGguanMuaHRtbCNNb2RlbFBhdGgkbGVuKSAtIHJldHVybnMgbGVuZ3RoIG9mIGFycmF5IChvciBwc2V1ZG8tYXJyYXkpIGluIG1vZGVsIGluIHNhZmUgd2F5LCAwIGlmIG5vIGxlbmd0aCBpcyBzZXRcbiAqIC0gW3B1c2hdKC4vbV9wYXRoLmpzLmh0bWwjTW9kZWxQYXRoJHB1c2gpIC0gYWRkIGl0ZW1zIHRvIHRoZSBlbmQgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gbW9kZWxcbiAqIC0gW3BvcF0oLi9tX3BhdGguanMuaHRtbCNNb2RlbFBhdGgkcG9wKSAtIHJlbW92ZSBpdGVtIGZyb20gdGhlIGVuZCBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KSBpbiBtb2RlbFxuICogLSBbdW5zaGlmdF0oLi9tX3BhdGguanMuaHRtbCNNb2RlbFBhdGgkdW5zaGlmdCkgLSBhZGQgaXRlbXMgdG8gdGhlIGJlZ2lubmluZyBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KSBpbiBtb2RlbFxuICogLSBbc2hpZnRdKC4vbV9wYXRoLmpzLmh0bWwjTW9kZWxQYXRoJHNoaWZ0KSAtIHJlbW92ZSBpdGVtIGZyb20gdGhlIGJlZ2lubmluZyBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KSBpbiBtb2RlbFxuICogLSBbcHJveHlNZXNzZW5nZXJdKCNwcm94eU1lc3NlbmdlcikgLSBwcm94eSBtb2RlbCdzIE1lc3NlbmdlciBtZXRob2RzIHRvIGhvc3Qgb2JqZWN0XG4gKiAtIFtwcm94eU1ldGhvZHNdKCNwcm94eU1ldGhvZHMpIC0gcHJveHkgbW9kZWwgbWV0aG9kcyB0byBob3N0IG9iamVjdFxuICovXG5fLmV4dGVuZFByb3RvKE1vZGVsLCB7XG4gICAgcGF0aDogTW9kZWwkcGF0aCxcbiAgICBnZXQ6IE1vZGVsJGdldCxcbiAgICBwcm94eU1lc3NlbmdlcjogcHJveHlNZXNzZW5nZXIsIC8vIGRlcHJlY2F0ZWQsIHNob3VsZCBub3QgYmUgdXNlZFxuICAgIHByb3h5TWV0aG9kczogcHJveHlNZXRob2RzLFxuICAgIF9wcmVwYXJlTWVzc2VuZ2VyczogX3ByZXBhcmVNZXNzZW5nZXJzLFxuICAgIF9nZXRIb3N0T2JqZWN0OiBfZ2V0SG9zdE9iamVjdCxcbiAgICBkZXN0cm95OiBNb2RlbCRkZXN0cm95XG59KTtcblxuLy8gc2V0LCBkZWwsIHNwbGljZSBhcmUgYWRkZWQgdG8gbW9kZWxcbl8uZXh0ZW5kUHJvdG8oTW9kZWwsIHN5bnRoZXNpemUubW9kZWxNZXRob2RzKTtcblxuXG4vKipcbiAqIC0gUGF0aDogTW9kZWxQYXRoIGNsYXNzIGFzIGBtaWxvLk1vZGVsLlBhdGhgXG4gKi9cbl8uZXh0ZW5kKE1vZGVsLCB7XG4gICAgUGF0aDogTW9kZWxQYXRoLFxuICAgIHVzZVdpdGg6IE1vZGVsJCR1c2VXaXRoXG59KTtcblxuXG4vKipcbiAqIEV4cG9zZSBNZXNzZW5nZXIgbWV0aG9kcyBvbiBGYWNldCBwcm90b3R5cGVcbiAqL1xudmFyIE1FU1NFTkdFUl9QUk9QRVJUWSA9ICdfbWVzc2VuZ2VyJztcbk1lc3Nlbmdlci51c2VXaXRoKE1vZGVsLCBNRVNTRU5HRVJfUFJPUEVSVFksIE1lc3Nlbmdlci5kZWZhdWx0TWV0aG9kcyk7XG5cblxuLyoqXG4gKiBNb2RlbFBhdGggbWV0aG9kcyBhZGRlZCB0byBNb2RlbCBwcm90b3R5cGVcbiAqL1xuWydsZW4nLCAncHVzaCcsICdwb3AnLCAndW5zaGlmdCcsICdzaGlmdCddLmZvckVhY2goZnVuY3Rpb24obWV0aG9kTmFtZSkge1xuICAgIHZhciBtZXRob2QgPSBNb2RlbFBhdGgucHJvdG90eXBlW21ldGhvZE5hbWVdO1xuICAgIF8uZGVmaW5lUHJvcGVydHkoTW9kZWwucHJvdG90eXBlLCBtZXRob2ROYW1lLCBtZXRob2QpO1xufSk7XG5cblxuLyoqXG4gKiBNb2RlbCBpbnN0YW5jZSBtZXRob2QuXG4gKiBHZXQgbW9kZWwgZGF0YS5cbiAqXG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmZ1bmN0aW9uIE1vZGVsJGdldCgpIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YTtcbn1cblxuXG4vKipcbiAqIE1vZGVsIGluc3RhbmNlIG1ldGhvZC5cbiAqIFJldHVybnMgTW9kZWxQYXRoIG9iamVjdCB0aGF0IGltcGxlbWVudHMgdGhlIHNhbWUgQVBJIGFzIG1vZGVsIGJ1dCBhbGxvd3MgYWNjZXNzIHRvIGFueSBwb2ludCBpbnNpZGUgbW9kZWwgYXMgZGVmaW5lZCBieSBgYWNjZXNzUGF0aGAuXG4gKiBTZWUgW01vZGVsUGF0aF0oLi9tX3BhdGguanMuaHRtbCkgY2xhc3MgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IGFjY2Vzc1BhdGggc3RyaW5nIHRoYXQgZGVmaW5lcyBwYXRoIHRvIGFjY2VzcyBtb2RlbC5cbiAqICBQYXRoIHN0cmluZyBjb25zaXN0cyBvZiBwYXJ0cyB0byBkZWZpbmUgZWl0aGVyIHByb3BlcnR5IGFjY2VzcyAoYFwiLm5hbWVcImAgdG8gYWNjZXNzIHByb3BlcnR5IG5hbWUpIG9yIGFycmF5IGl0ZW0gYWNjZXNzIChgXCJbMV1cImAgdG8gYWNjZXNzIGl0ZW0gd2l0aCBpbmRleCAxKS5cbiAqICBBY2Nlc3MgcGF0aCBjYW4gY29udGFpbiBhcyBtYW55IHBhcnRzIGFzIG5lY2Vzc2FyeSAoZS5nLiBgXCIubGlzdFswXS5uYW1lXCJgIHRvIGFjY2VzcyBwcm9wZXJ0eSBgbmFtZWAgaW4gdGhlIGZpcnN0IGVsZW1lbnQgb2YgYXJyYXkgc3RvcmVkIGluIHByb3BlcnR5IGBsaXN0YC5cbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIGFkZGl0aW9uYWwgYXJndW1lbnRzIG9mIHRoaXMgbWV0aG9kIGNhbiBiZSB1c2VkIHRvIGNyZWF0ZSBpbnRlcnBvbGF0ZWQgcGF0aHMuXG4gKiAgRS5nLiBgbS5wYXRoKFwiWyQxXS4kMlwiLCBpZCwgcHJvcClgIHJldHVybnMgTW9kZWxQYXRoIHRvIGFjY2VzcyBwcm9wZXJ0eSB3aXRoIG5hbWUgYHByb3BgIGluIGFycmF5IGl0ZW0gd2l0aCBpbmRleCBgaWRgLiBBbHRob3VnaCB0aGlzIE1vZGVsUGF0aCBvYmplY3Qgd2lsbCB3b3JrIGV4YWN0bHkgYXMgYG0oXCJbXCIgKyBpZCArIFwiXS5cIiArIHByb3ApYCwgdGhlIGludGVycG9sYXRlZCBpcyBtdWNoIG1vcmUgZWZmaWNpZW50IGFzIE1vZGVsUGF0aCB3aXRoIGludGVycG9sYXRpb24gd2lsbCBub3Qgc3ludGhlc2l6ZSBuZXcgZ2V0dGVycyBhbmQgc2V0dGVycywgd2hpbGUgTW9kZWxQYXRoIHdpdGggY29tcHV0ZWQgYWNjZXNzIHBhdGggd2lsbCBzeW50aGVzaXplIG5ldyBnZXR0ZXJzIGFuZCBzZXR0ZXJzIGZvciBlYWNoIHBhaXIgb2YgdmFsdWVzIG9mIGBpZGAgYW5kIGBwcm9wYC5cbiAqIEByZXR1cm4ge01vZGVsUGF0aH1cbiAqL1xuZnVuY3Rpb24gTW9kZWwkcGF0aChhY2Nlc3NQYXRoKSB7ICAvLyAsIC4uLiBhcmd1bWVudHMgdGhhdCB3aWxsIGJlIGludGVycG9sYXRlZFxuICAgIGlmICghIGFjY2Vzc1BhdGgpIHJldHVybiB0aGlzO1xuXG4gICAgLy8gXCJudWxsXCIgaXMgY29udGV4dCB0byBwYXNzIHRvIE1vZGVsUGF0aCwgZmlyc3QgcGFyYW1ldGVyIG9mIGJpbmRcbiAgICAvLyBcInRoaXNcIiAobW9kZWwpIGlzIGFkZGVkIGluIGZyb250IG9mIGFsbCBhcmd1bWVudHNcbiAgICBfLnNwbGljZShhcmd1bWVudHMsIDAsIDAsIG51bGwsIHRoaXMpO1xuXG4gICAgLy8gY2FsbGluZyBNb2RlbFBhdGggY29uc3RydWN0b3Igd2l0aCBuZXcgYW5kIHRoZSBsaXN0IG9mIGFyZ3VtZW50czogdGhpcyAobW9kZWwpLCBhY2Nlc3NQYXRoLCAuLi5cbiAgICByZXR1cm4gbmV3IChGdW5jdGlvbi5wcm90b3R5cGUuYmluZC5hcHBseShNb2RlbFBhdGgsIGFyZ3VtZW50cykpO1xufVxuXG5cbi8qKlxuICogTW9kZWwgaW5zdGFuY2UgbWV0aG9kLlxuICogUHJveHkgbW9kZWwncyBNZXNzZW5nZXIgbWV0aG9kcyB0byBob3N0IG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gbW9kZWxIb3N0T2JqZWN0IG9wdGlvbmFsIGhvc3Qgb2JqZWN0LiBJZiBub3QgcGFzc2VkLCBob3N0T2JqZWN0IHBhc3NlZCB0byBNb2RlbCBjb25zdHJ1Y3RvciB3aWxsIGJlIHVzZWQuXG4gKi9cbmZ1bmN0aW9uIHByb3h5TWVzc2VuZ2VyKG1vZGVsSG9zdE9iamVjdCkge1xuICAgIG1vZGVsSG9zdE9iamVjdCA9IG1vZGVsSG9zdE9iamVjdCB8fCB0aGlzLl9ob3N0T2JqZWN0O1xuICAgIE1peGluLnByb3RvdHlwZS5fY3JlYXRlUHJveHlNZXRob2RzLmNhbGwodGhpc1tNRVNTRU5HRVJfUFJPUEVSVFldLCBNZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMsIG1vZGVsSG9zdE9iamVjdCk7XG59XG5cblxudmFyIG1vZGVsTWV0aG9kc1RvUHJveHkgPSBbJ3BhdGgnLCAnZ2V0JywgJ3NldCcsICdkZWwnLCAnc3BsaWNlJywgJ2xlbicsICdwdXNoJywgJ3BvcCcsICd1bnNoaWZ0JywgJ3NoaWZ0J107XG5cblxuLyoqXG4gKiBFeHBvc2UgbW9kZWwgbWV0aG9kcyBvblxuICogU2VlIHNhbWUgbWV0aG9kIGluIE1peGluIGNsYXNzIGZvciBwYXJhbWV0ZXJzIG1lYW5pbmdcbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBob3N0Q2xhc3NcbiAqIEBwYXJhbSB7W3R5cGVdfSBpbnN0YW5jZUtleVxuICogQHBhcmFtIHtbdHlwZV19IG1peGluTWV0aG9kcyBvcHRpb25hbFxuICovXG5mdW5jdGlvbiBNb2RlbCQkdXNlV2l0aChob3N0Q2xhc3MsIGluc3RhbmNlS2V5LCBtaXhpbk1ldGhvZHMpIHtcbiAgICBtaXhpbk1ldGhvZHMgPSBtaXhpbk1ldGhvZHMgfHwgbW9kZWxNZXRob2RzVG9Qcm94eTtcbiAgICBNaXhpbi51c2VXaXRoLmNhbGwoTW9kZWwsIGhvc3RDbGFzcywgaW5zdGFuY2VLZXksIG1peGluTWV0aG9kcyk7XG59XG5cblxuLyoqXG4gKiBNb2RlbCBpbnN0YW5jZSBtZXRob2QuXG4gKiBQcm94eSBtb2RlbCBtZXRob2RzIHRvIGhvc3Qgb2JqZWN0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBtb2RlbEhvc3RPYmplY3Qgb3B0aW9uYWwgaG9zdCBvYmplY3QuIElmIG5vdCBwYXNzZWQsIGhvc3RPYmplY3QgcGFzc2VkIHRvIE1vZGVsIGNvbnN0cnVjdG9yIHdpbGwgYmUgdXNlZC5cbiAqL1xuZnVuY3Rpb24gcHJveHlNZXRob2RzKG1vZGVsSG9zdE9iamVjdCkge1xuICAgIG1vZGVsSG9zdE9iamVjdCA9IG1vZGVsSG9zdE9iamVjdCB8fCB0aGlzLl9ob3N0T2JqZWN0O1xuICAgIE1peGluLnByb3RvdHlwZS5fY3JlYXRlUHJveHlNZXRob2RzLmNhbGwodGhpcywgbW9kZWxNZXRob2RzVG9Qcm94eSwgbW9kZWxIb3N0T2JqZWN0KTtcbn1cblxuXG4vKipcbiAqIE1vZGVsIGluc3RhbmNlIG1ldGhvZC5cbiAqIENyZWF0ZSBhbmQgY29ubmVjdCBpbnRlcm5hbCBhbmQgZXh0ZXJuYWwgbW9kZWwncyBtZXNzZW5nZXJzLlxuICogRXh0ZXJuYWwgbWVzc2VuZ2VyJ3MgbWV0aG9kcyBhcmUgcHJveGllZCBvbiB0aGUgbW9kZWwgYW5kIHRoZXkgYWxsb3dzIFwiKlwiIHN1YnNjcmlwdGlvbnMuXG4gKi9cbmZ1bmN0aW9uIF9wcmVwYXJlTWVzc2VuZ2VycygpIHtcbiAgICAvLyBtb2RlbCB3aWxsIHBvc3QgYWxsIGl0cyBjaGFuZ2VzIG9uIGludGVybmFsIG1lc3NlbmdlclxuICAgIHZhciBpbnRlcm5hbE1lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXIodGhpcywgdW5kZWZpbmVkLCB1bmRlZmluZWQpO1xuXG4gICAgLy8gbWVzc2FnZSBzb3VyY2UgdG8gY29ubmVjdCBpbnRlcm5hbCBtZXNzZW5nZXIgdG8gZXh0ZXJuYWxcbiAgICB2YXIgaW50ZXJuYWxNZXNzZW5nZXJTb3VyY2UgPSBuZXcgTWVzc2VuZ2VyTWVzc2FnZVNvdXJjZSh0aGlzLCB1bmRlZmluZWQsIG5ldyBNb2RlbE1zZ0FQSSwgaW50ZXJuYWxNZXNzZW5nZXIpO1xuXG4gICAgLy8gZXh0ZXJuYWwgbWVzc2VuZ2VyIHRvIHdoaWNoIGFsbCBtb2RlbCB1c2VycyB3aWxsIHN1YnNjcmliZSxcbiAgICAvLyB0aGF0IHdpbGwgYWxsb3cgXCIqXCIgc3Vic2NyaXB0aW9ucyBhbmQgc3VwcG9ydCBcImNoYW5nZWRhdGFcIiBtZXNzYWdlIGFwaS5cbiAgICB2YXIgZXh0ZXJuYWxNZXNzZW5nZXIgPSBuZXcgTWVzc2VuZ2VyKHRoaXMsIHVuZGVmaW5lZCwgaW50ZXJuYWxNZXNzZW5nZXJTb3VyY2UpO1xuXG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBNRVNTRU5HRVJfUFJPUEVSVFksIGV4dGVybmFsTWVzc2VuZ2VyKTtcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdfaW50ZXJuYWxNZXNzZW5nZXInLCBpbnRlcm5hbE1lc3Nlbmdlcik7XG59XG5cblxuZnVuY3Rpb24gX2dldEhvc3RPYmplY3QoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2hvc3RPYmplY3Q7XG59XG5cblxuZnVuY3Rpb24gTW9kZWwkZGVzdHJveSgpIHtcbiAgICB0aGlzW01FU1NFTkdFUl9QUk9QRVJUWV0uZGVzdHJveSgpO1xuICAgIHRoaXMuX2ludGVybmFsTWVzc2VuZ2VyLmRlc3Ryb3koKTtcbiAgICB0aGlzLl9kZXN0cm95ZWQgPSB0cnVlO1xufVxuIiwiYXJndW1lbnRzWzRdWzc1XVswXS5hcHBseShleHBvcnRzLGFyZ3VtZW50cykiLCJhcmd1bWVudHNbNF1bNzZdWzBdLmFwcGx5KGV4cG9ydHMsYXJndW1lbnRzKSIsImFyZ3VtZW50c1s0XVs3OF1bMF0uYXBwbHkoZXhwb3J0cyxhcmd1bWVudHMpIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyA8YSBuYW1lPVwibW9kZWwtcGF0aFwiPjwvYT5cbi8vICMjIyBtb2RlbCBwYXRoIHV0aWxzXG5cbnZhciBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG52YXIgcGF0aFV0aWxzID0ge1xuICAgIHBhcnNlQWNjZXNzUGF0aDogcGFyc2VBY2Nlc3NQYXRoLFxuICAgIGNyZWF0ZVJlZ2V4UGF0aDogY3JlYXRlUmVnZXhQYXRoLFxuICAgIGdldFBhdGhOb2RlS2V5OiBnZXRQYXRoTm9kZUtleSxcbiAgICB3cmFwTWVzc2VuZ2VyTWV0aG9kczogd3JhcE1lc3Nlbmdlck1ldGhvZHNcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gcGF0aFV0aWxzO1xuXG5cbnZhciBwcm9wZXJ0eVBhdGhTeW50YXggPSAnXFxcXC5bQS1aYS16Xy1dW0EtWmEtejAtOV8tXSonXG4gICAgLCBhcnJheVBhdGhTeW50YXggPSAnXFxcXFtbMC05XStcXFxcXSdcbiAgICAsIGludGVycG9sYXRpb25TeW50YXggPSAnXFxcXCRbMS05XVswLTldKidcbiAgICAsIHByb3BlcnR5SW50ZXJwb2xhdGVTeW50YXggPSAnXFxcXC4nICsgaW50ZXJwb2xhdGlvblN5bnRheFxuICAgICwgYXJyYXlJbnRlcnBvbGF0ZVN5bnRheCA9ICdcXFxcWycgKyBpbnRlcnBvbGF0aW9uU3ludGF4ICsgJ1xcXFxdJ1xuXG4gICAgLCBwcm9wZXJ0eVN0YXJTeW50YXggPSAnXFxcXC5cXFxcKidcbiAgICAsIGFycmF5U3RhclN5bnRheCA9ICdcXFxcW1xcXFwqXFxcXF0nXG4gICAgLCBzdGFyU3ludGF4ID0gJ1xcXFwqJ1xuXG4gICAgLCBwYXRoUGFyc2VTeW50YXggPSBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcGVydHlQYXRoU3ludGF4LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmF5UGF0aFN5bnRheCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9wZXJ0eUludGVycG9sYXRlU3ludGF4LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmF5SW50ZXJwb2xhdGVTeW50YXhcbiAgICAgICAgICAgICAgICAgICAgICAgIF0uam9pbignfCcpXG4gICAgLCBwYXRoUGFyc2VQYXR0ZXJuID0gbmV3IFJlZ0V4cChwYXRoUGFyc2VTeW50YXgsICdnJylcblxuICAgICwgcGF0dGVyblBhdGhQYXJzZVN5bnRheCA9ICBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXRoUGFyc2VTeW50YXgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9wZXJ0eVN0YXJTeW50YXgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcnJheVN0YXJTeW50YXgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFyU3ludGF4XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0uam9pbignfCcpXG4gICAgLCBwYXR0ZXJuUGF0aFBhcnNlUGF0dGVybiA9IG5ldyBSZWdFeHAocGF0dGVyblBhdGhQYXJzZVN5bnRheCwgJ2cnKVxuXG4gICAgLy8sIHRhcmdldFBhdGhQYXJzZVBhdHRlcm4gPSAvXFwuW0EtWmEtel1bQS1aYS16MC05X10qfFxcW1swLTldK1xcXXxcXC5cXCRbMS05XVswLTldKnxcXFtcXCRbMS05XVswLTldKlxcXXxcXCRbMS05XVswLTldL2dcbiAgICAsIHBhdGhOb2RlVHlwZXMgPSB7XG4gICAgICAgICcuJzogeyBzeW50YXg6ICdvYmplY3QnLCBlbXB0eTogJ3t9JyB9LFxuICAgICAgICAnWyc6IHsgc3ludGF4OiAnYXJyYXknLCBlbXB0eTogJ1tdJ30sXG4gICAgICAgICcqJzogeyBzeW50YXg6ICdtYXRjaCcsIGVtcHR5OiAne30nfSxcbiAgICB9O1xuXG5mdW5jdGlvbiBwYXJzZUFjY2Vzc1BhdGgocGF0aCwgbm9kZVBhcnNlUGF0dGVybikge1xuICAgIG5vZGVQYXJzZVBhdHRlcm4gPSBub2RlUGFyc2VQYXR0ZXJuIHx8IHBhdGhQYXJzZVBhdHRlcm47XG5cbiAgICB2YXIgcGFyc2VkUGF0aCA9IFtdO1xuXG4gICAgaWYgKCEgcGF0aClcbiAgICAgICAgcmV0dXJuIHBhcnNlZFBhdGg7XG5cbiAgICB2YXIgdW5wYXJzZWQgPSBwYXRoLnJlcGxhY2Uobm9kZVBhcnNlUGF0dGVybiwgZnVuY3Rpb24obm9kZVN0cikge1xuICAgICAgICB2YXIgcGF0aE5vZGUgPSB7IHByb3BlcnR5OiBub2RlU3RyIH07XG4gICAgICAgIF8uZXh0ZW5kKHBhdGhOb2RlLCBwYXRoTm9kZVR5cGVzW25vZGVTdHJbMF1dKTtcbiAgICAgICAgaWYgKG5vZGVTdHJbMV0gPT0gJyQnKVxuICAgICAgICAgICAgcGF0aE5vZGUuaW50ZXJwb2xhdGUgPSBnZXRQYXRoTm9kZUtleShwYXRoTm9kZSwgdHJ1ZSk7XG5cbiAgICAgICAgcGFyc2VkUGF0aC5wdXNoKHBhdGhOb2RlKTtcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH0pO1xuICAgIGlmICh1bnBhcnNlZClcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbmNvcnJlY3QgbW9kZWwgcGF0aDogJyArIHBhdGgpO1xuXG4gICAgcmV0dXJuIHBhcnNlZFBhdGg7XG59XG5cblxudmFyIG5vZGVSZWdleCA9IHtcbiAgICAnLionOiBwcm9wZXJ0eVBhdGhTeW50YXgsXG4gICAgJ1sqXSc6IGFycmF5UGF0aFN5bnRheFxufTtcbm5vZGVSZWdleFsnKiddID0gbm9kZVJlZ2V4WycuKiddICsgJ3wnICsgbm9kZVJlZ2V4WydbKl0nXTtcblxuZnVuY3Rpb24gY3JlYXRlUmVnZXhQYXRoKHBhdGgpIHtcbiAgICBjaGVjayhwYXRoLCBNYXRjaC5PbmVPZihTdHJpbmcsIFJlZ0V4cCkpO1xuXG4gICAgaWYgKHBhdGggaW5zdGFuY2VvZiBSZWdFeHAgfHwgcGF0aC5pbmRleE9mKCcqJykgPT0gLTEpXG4gICAgICAgIHJldHVybiBwYXRoO1xuXG4gICAgdmFyIHBhcnNlZFBhdGggPSBwYXRoVXRpbHMucGFyc2VBY2Nlc3NQYXRoKHBhdGgsIHBhdHRlcm5QYXRoUGFyc2VQYXR0ZXJuKVxuICAgICAgICAsIHJlZ2V4U3RyID0gJ14nXG4gICAgICAgIC8vICwgcmVnZXhTdHJFbmQgPSAnJ1xuICAgICAgICAsIHBhdHRlcm5zU3RhcnRlZCA9IGZhbHNlO1xuXG4gICAgcGFyc2VkUGF0aC5mb3JFYWNoKGZ1bmN0aW9uKHBhdGhOb2RlKSB7XG4gICAgICAgIHZhciBwcm9wID0gcGF0aE5vZGUucHJvcGVydHlcbiAgICAgICAgICAgICwgcmVnZXggPSBub2RlUmVnZXhbcHJvcF07XG4gICAgICAgIFxuICAgICAgICBpZiAocmVnZXgpIHtcbiAgICAgICAgICAgIC8vIHJlZ2V4U3RyICs9ICcoJyArIHJlZ2V4O1xuICAgICAgICAgICAgLy8gcmVnZXhTdHJFbmQgKz0gJ3wpJztcbiAgICAgICAgICAgIHJlZ2V4U3RyICs9ICcoJyArIHJlZ2V4ICsgJ3wpJztcbiAgICAgICAgICAgIC8vIHJlZ2V4U3RyRW5kICs9ICd8KSc7XG4gICAgICAgICAgICBwYXR0ZXJuc1N0YXJ0ZWQgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gaWYgKHBhdHRlcm5zU3RhcnRlZClcbiAgICAgICAgICAgIC8vICB0aHJvdyBuZXcgRXJyb3IoJ1wiKlwiIHBhdGggc2VnbWVudCBjYW5ub3QgYmUgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcGF0aDogJyArIHBhdGgpO1xuICAgICAgICAgICAgcmVnZXhTdHIgKz0gcHJvcC5yZXBsYWNlKC8oXFwufFxcW3xcXF0pL2csICdcXFxcJDEnKTsgLy8gYWRkIHNsYXNoIGluIGZyb250IG9mIHN5bWJvbHMgdGhhdCBoYXZlIHNwZWNpYWwgbWVhbmluZyBpbiByZWdleFxuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICByZWdleFN0ciArPSAvKiByZWdleFN0ckVuZCArICovICckJztcblxuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBuZXcgUmVnRXhwKHJlZ2V4U3RyKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignY2FuXFwndCBjb25zdHJ1Y3QgcmVnZXggZm9yIHBhdGggcGF0dGVybjogJyArIHBhdGgpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBnZXRQYXRoTm9kZUtleShwYXRoTm9kZSwgaW50ZXJwb2xhdGVkKSB7XG4gICAgdmFyIHByb3AgPSBwYXRoTm9kZS5wcm9wZXJ0eVxuICAgICAgICAsIHN0YXJ0SW5kZXggPSBpbnRlcnBvbGF0ZWQgPyAyIDogMTtcbiAgICByZXR1cm4gcGF0aE5vZGUuc3ludGF4ID09ICdhcnJheSdcbiAgICAgICAgPyBwcm9wLnNsaWNlKHN0YXJ0SW5kZXgsIHByb3AubGVuZ3RoIC0gMSlcbiAgICAgICAgOiBwcm9wLnNsaWNlKHN0YXJ0SW5kZXgpO1xufVxuXG5cbi8vIFRPRE8gYWxsb3cgZm9yIG11bHRpcGxlIG1lc3NhZ2VzIGluIGEgc3RyaW5nXG5mdW5jdGlvbiB3cmFwTWVzc2VuZ2VyTWV0aG9kcyhtZXRob2RzTmFtZXMpIHtcbiAgICBtZXRob2RzTmFtZXMgPSBtZXRob2RzTmFtZXMgfHwgWydvbicsICdvZmYnXTtcbiAgICB2YXIgd3JhcHBlZE1ldGhvZHMgPSBfLm1hcFRvT2JqZWN0KG1ldGhvZHNOYW1lcywgZnVuY3Rpb24obWV0aG9kTmFtZSkge1xuICAgICAgICB2YXIgb3JpZ01ldGhvZCA9IHRoaXNbbWV0aG9kTmFtZV07XG4gICAgICAgIC8vIHJlcGxhY2luZyBtZXNzYWdlIHN1YnNyaWJlL3Vuc3Vic2NyaWJlL2V0Yy4gdG8gY29udmVydCBcIipcIiBtZXNzYWdlIHBhdHRlcm5zIHRvIHJlZ2V4cHNcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKHBhdGgsIHN1YnNjcmliZXIpIHtcbiAgICAgICAgICAgIHZhciByZWdleFBhdGggPSBjcmVhdGVSZWdleFBhdGgocGF0aCk7XG4gICAgICAgICAgICBvcmlnTWV0aG9kLmNhbGwodGhpcywgcmVnZXhQYXRoLCBzdWJzY3JpYmVyKTtcbiAgICAgICAgfTtcbiAgICB9LCB0aGlzKTtcbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywgd3JhcHBlZE1ldGhvZHMpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcGF0aFV0aWxzID0gcmVxdWlyZSgnLi4vcGF0aF91dGlscycpXG4gICAgLCBtb2RlbFV0aWxzID0gcmVxdWlyZSgnLi4vbW9kZWxfdXRpbHMnKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9sb2dnZXInKVxuICAgICwgZnMgPSByZXF1aXJlKCdmcycpXG4gICAgLCBkb1QgPSByZXF1aXJlKCdkb3QnKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGFuZ2VEYXRhSGFuZGxlciA9IHJlcXVpcmUoJy4uL2NoYW5nZV9kYXRhJylcbiAgICAsIGdldFRyYW5zYWN0aW9uRmxhZyA9IGNoYW5nZURhdGFIYW5kbGVyLmdldFRyYW5zYWN0aW9uRmxhZ1xuICAgICwgcG9zdFRyYW5zYWN0aW9uRmluaXNoZWQgPSBjaGFuZ2VEYXRhSGFuZGxlci5wb3N0VHJhbnNhY3Rpb25GaW5pc2hlZDtcblxuXG4vKipcbiAqIFRlbXBsYXRlcyB0byBzeW50aGVzaXplIG1vZGVsIGdldHRlcnMgYW5kIHNldHRlcnNcbiAqL1xudmFyIHRlbXBsYXRlcyA9IHtcbiAgICBnZXQ6IFwiJ3VzZSBzdHJpY3QnO1xcbi8qIE9ubHkgdXNlIHRoaXMgc3R5bGUgb2YgY29tbWVudHMsIG5vdCBcXFwiLy9cXFwiICovXFxuXFxubWV0aG9kID0gZnVuY3Rpb24gZ2V0KCkge1xcbiAgICB2YXIgbSA9IHt7IyBkZWYubW9kZWxBY2Nlc3NQcmVmaXggfX07XFxuICAgIHJldHVybiBtIHt7fiBpdC5wYXJzZWRQYXRoIDpwYXRoTm9kZSB9fVxcbiAgICAgICAge3s/IHBhdGhOb2RlLmludGVycG9sYXRlfX1cXG4gICAgICAgICAgICAmJiAobSA9IG1bdGhpcy5fYXJnc1sge3s9IHBhdGhOb2RlLmludGVycG9sYXRlIH19IF1dKVxcbiAgICAgICAge3s/P319XFxuICAgICAgICAgICAgJiYgKG0gPSBte3s9IHBhdGhOb2RlLnByb3BlcnR5IH19KVxcbiAgICAgICAge3s/fX0ge3t+fX07XFxufTtcXG5cIixcbiAgICBzZXQ6IFwiJ3VzZSBzdHJpY3QnO1xcbi8qIE9ubHkgdXNlIHRoaXMgc3R5bGUgb2YgY29tbWVudHMsIG5vdCBcXFwiLy9cXFwiICovXFxuXFxue3sjIGRlZi5pbmNsdWRlX2RlZmluZXMgfX1cXG57eyMgZGVmLmluY2x1ZGVfY3JlYXRlX3RyZWUgfX1cXG5cXG5cXG4vKipcXG4gKiBUZW1wbGF0ZSB0aGF0IHN5bnRoZXNpemVzIHNldHRlciBmb3IgTW9kZWwgYW5kIGZvciBNb2RlbFBhdGhcXG4gKi9cXG5tZXRob2QgPSBmdW5jdGlvbiBzZXQodmFsdWUpIHtcXG4gICAge3sjIGRlZi5pbml0VmFyczonc2V0JyB9fVxcblxcbiAgICB7eyMgZGVmLmNyZWF0ZVRyZWU6J3NldCcgfX1cXG5cXG4gICAge3tcXG4gICAgICAgIGN1cnJOb2RlID0gbmV4dE5vZGU7XFxuICAgICAgICBjdXJyUHJvcCA9IGN1cnJOb2RlICYmIGN1cnJOb2RlLnByb3BlcnR5O1xcbiAgICB9fVxcblxcbiAgICB7eyAvKiBhc3NpZ24gdmFsdWUgdG8gdGhlIGxhc3QgcHJvcGVydHkgKi8gfX1cXG4gICAge3s/IGN1cnJQcm9wIH19XFxuICAgICAgICB3YXNEZWYgPSB7eyMgZGVmLndhc0RlZmluZWR9fTtcXG4gICAgICAgIHt7IyBkZWYuY2hhbmdlQWNjZXNzUGF0aCB9fVxcblxcbiAgICAgICAgdmFyIG9sZCA9IG17eyMgZGVmLmN1cnJQcm9wIH19O1xcblxcbiAgICAgICAge3sgLyogY2xvbmUgdmFsdWUgdG8gcHJldmVudCBzYW1lIHJlZmVyZW5jZSBpbiBsaW5rZWQgbW9kZWxzICovIH19XFxuICAgICAgICBte3sjIGRlZi5jdXJyUHJvcCB9fSA9IGNsb25lVHJlZSh2YWx1ZSk7XFxuICAgIHt7P319XFxuXFxuICAgIHt7IC8qIGFkZCBtZXNzYWdlIHJlbGF0ZWQgdG8gdGhlIGxhc3QgcHJvcGVydHkgY2hhbmdlICovIH19XFxuICAgIGlmICh0aGlzLl9vcHRpb25zLnJlYWN0aXZlICE9PSBmYWxzZSkge1xcbiAgICAgICAgaWYgKCEgd2FzRGVmKVxcbiAgICAgICAgICAgIHt7IyBkZWYuYWRkTXNnIH19IGFjY2Vzc1BhdGgsIHR5cGU6ICdhZGRlZCcsXFxuICAgICAgICAgICAgICAgIG5ld1ZhbHVlOiB2YWx1ZSB9KTtcXG4gICAgICAgIGVsc2UgaWYgKG9sZCAhPSB2YWx1ZSlcXG4gICAgICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSBhY2Nlc3NQYXRoLCB0eXBlOiAnY2hhbmdlZCcsXFxuICAgICAgICAgICAgICAgIG9sZFZhbHVlOiBvbGQsIG5ld1ZhbHVlOiB2YWx1ZSB9KTtcXG5cXG4gICAgICAgIHt7IC8qIGFkZCBtZXNzYWdlIHJlbGF0ZWQgdG8gY2hhbmdlcyBpbiAoc3ViKXByb3BlcnRpZXMgaW5zaWRlIHJlbW92ZWQgYW5kIGFzc2lnbmVkIHZhbHVlICovIH19XFxuICAgICAgICBpZiAoISB3YXNEZWYgfHwgb2xkICE9IHZhbHVlKVxcbiAgICAgICAgICAgIGFkZFRyZWVDaGFuZ2VzTWVzc2FnZXMobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCxcXG4gICAgICAgICAgICAgICAgYWNjZXNzUGF0aCwgb2xkLCB2YWx1ZSk7IC8qIGRlZmluZWQgaW4gdGhlIGZ1bmN0aW9uIHRoYXQgc3ludGhlc2l6ZXMgTW9kZWxQYXRoIHNldHRlciAqL1xcblxcbiAgICAgICAge3sgLyogcG9zdCBhbGwgc3RvcmVkIG1lc3NhZ2VzICovIH19XFxuICAgICAgICB7eyMgZGVmLnBvc3RNZXNzYWdlcyB9fVxcbiAgICB9XFxufTtcXG5cIixcbiAgICBkZWw6IFwiJ3VzZSBzdHJpY3QnO1xcbi8qIE9ubHkgdXNlIHRoaXMgc3R5bGUgb2YgY29tbWVudHMsIG5vdCBcXFwiLy9cXFwiICovXFxuXFxue3sjIGRlZi5pbmNsdWRlX2RlZmluZXMgfX1cXG57eyMgZGVmLmluY2x1ZGVfdHJhdmVyc2VfdHJlZSB9fVxcblxcbm1ldGhvZCA9IGZ1bmN0aW9uIGRlbCgpIHtcXG4gICAge3sjIGRlZi5pbml0VmFyczonZGVsJyB9fVxcblxcbiAgICB7ez8gaXQucGFyc2VkUGF0aC5sZW5ndGggfX1cXG4gICAgICAgIHt7IyBkZWYudHJhdmVyc2VUcmVlIH19XFxuXFxuICAgICAgICB7e1xcbiAgICAgICAgICAgIHZhciBjdXJyTm9kZSA9IGl0LnBhcnNlZFBhdGhbY291bnRdO1xcbiAgICAgICAgICAgIHZhciBjdXJyUHJvcCA9IGN1cnJOb2RlLnByb3BlcnR5OyAgICAgICBcXG4gICAgICAgIH19XFxuXFxuICAgICAgICBpZiAoISB0cmVlRG9lc05vdEV4aXN0ICYmIG0gJiYgbS5oYXNPd25Qcm9wZXJ0eSAmJiB7eyMgZGVmLndhc0RlZmluZWR9fSkge1xcbiAgICAgICAgICAgIHZhciBvbGQgPSBte3sjIGRlZi5jdXJyUHJvcCB9fTtcXG4gICAgICAgICAgICBkZWxldGUgbXt7IyBkZWYuY3VyclByb3AgfX07XFxuICAgICAgICAgICAge3sjIGRlZi5jaGFuZ2VBY2Nlc3NQYXRoIH19XFxuICAgICAgICAgICAgdmFyIGRpZERlbGV0ZSA9IHRydWU7XFxuICAgICAgICB9XFxuICAgIHt7Pz99fVxcbiAgICAgICAgaWYgKHR5cGVvZiBtICE9ICd1bmRlZmluZWQnKSB7XFxuICAgICAgICAgICAgdmFyIG9sZCA9IG07XFxuICAgICAgICAgICAge3sjIGRlZi5tb2RlbEFjY2Vzc1ByZWZpeCB9fSA9IHVuZGVmaW5lZDtcXG4gICAgICAgICAgICB2YXIgZGlkRGVsZXRlID0gdHJ1ZTtcXG4gICAgICAgIH1cXG4gICAge3s/fX1cXG5cXG4gICAgaWYgKGRpZERlbGV0ZSAmJiB0aGlzLl9vcHRpb25zLnJlYWN0aXZlICE9PSBmYWxzZSkge1xcbiAgICAgICAge3sjIGRlZi5hZGRNc2cgfX0gYWNjZXNzUGF0aCwgdHlwZTogJ2RlbGV0ZWQnLCBvbGRWYWx1ZTogb2xkIH0pO1xcblxcbiAgICAgICAgYWRkVHJlZUNoYW5nZXNNZXNzYWdlcyhtZXNzYWdlcywgbWVzc2FnZXNIYXNoLFxcbiAgICAgICAgICAgIGFjY2Vzc1BhdGgsIG9sZCwgdW5kZWZpbmVkKTsgLyogZGVmaW5lZCBpbiB0aGUgZnVuY3Rpb24gdGhhdCBzeW50aGVzaXplcyBNb2RlbFBhdGggc2V0dGVyICovXFxuXFxuICAgICAgICB7eyAvKiBwb3N0IGFsbCBzdG9yZWQgbWVzc2FnZXMgKi8gfX1cXG4gICAgICAgIHt7IyBkZWYucG9zdE1lc3NhZ2VzIH19XFxuICAgIH1cXG59O1xcblwiLFxuICAgIHNwbGljZTogXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG57eyMgZGVmLmluY2x1ZGVfZGVmaW5lcyB9fVxcbnt7IyBkZWYuaW5jbHVkZV9jcmVhdGVfdHJlZSB9fVxcbnt7IyBkZWYuaW5jbHVkZV90cmF2ZXJzZV90cmVlIH19XFxuXFxubWV0aG9kID0gZnVuY3Rpb24gc3BsaWNlKHNwbGljZUluZGV4LCBzcGxpY2VIb3dNYW55KSB7IC8qICwuLi4gLSBleHRyYSBhcmd1bWVudHMgdG8gc3BsaWNlIGludG8gYXJyYXkgKi9cXG4gICAge3sjIGRlZi5pbml0VmFyczonc3BsaWNlJyB9fVxcblxcbiAgICB2YXIgYXJnc0xlbiA9IGFyZ3VtZW50cy5sZW5ndGg7XFxuICAgIHZhciBhZGRJdGVtcyA9IGFyZ3NMZW4gPiAyO1xcblxcbiAgICBpZiAoYWRkSXRlbXMpIHtcXG4gICAgICAgIHt7IC8qIG9ubHkgY3JlYXRlIG1vZGVsIHRyZWUgaWYgaXRlbXMgYXJlIGluc2VydGVkIGluIGFycmF5ICovIH19XFxuXFxuICAgICAgICB7eyAvKiBpZiBtb2RlbCBpcyB1bmRlZmluZWQgaXQgd2lsbCBiZSBzZXQgdG8gYW4gZW1wdHkgYXJyYXkgKi8gfX0gIFxcbiAgICAgICAgdmFyIHZhbHVlID0gW107XFxuICAgICAgICB7eyMgZGVmLmNyZWF0ZVRyZWU6J3NwbGljZScgfX1cXG5cXG4gICAgICAgIHt7PyBuZXh0Tm9kZSB9fVxcbiAgICAgICAgICAgIHt7XFxuICAgICAgICAgICAgICAgIHZhciBjdXJyTm9kZSA9IG5leHROb2RlO1xcbiAgICAgICAgICAgICAgICB2YXIgY3VyclByb3AgPSBjdXJyTm9kZS5wcm9wZXJ0eTtcXG4gICAgICAgICAgICAgICAgdmFyIGVtcHR5UHJvcCA9ICdbXSc7XFxuICAgICAgICAgICAgfX1cXG5cXG4gICAgICAgICAgICB7eyMgZGVmLmNyZWF0ZVRyZWVTdGVwIH19XFxuICAgICAgICB7ez99fVxcblxcbiAgICB9IGVsc2UgaWYgKHNwbGljZUhvd01hbnkgPiAwKSB7XFxuICAgICAgICB7eyAvKiBpZiBpdGVtcyBhcmUgbm90IGluc2VydGVkLCBvbmx5IHRyYXZlcnNlIG1vZGVsIHRyZWUgaWYgaXRlbXMgYXJlIGRlbGV0ZWQgZnJvbSBhcnJheSAqLyB9fVxcbiAgICAgICAge3s/IGl0LnBhcnNlZFBhdGgubGVuZ3RoIH19XFxuICAgICAgICAgICAge3sjIGRlZi50cmF2ZXJzZVRyZWUgfX1cXG5cXG4gICAgICAgICAgICB7e1xcbiAgICAgICAgICAgICAgICB2YXIgY3Vyck5vZGUgPSBpdC5wYXJzZWRQYXRoW2NvdW50XTtcXG4gICAgICAgICAgICAgICAgdmFyIGN1cnJQcm9wID0gY3Vyck5vZGUucHJvcGVydHk7ICAgICAgIFxcbiAgICAgICAgICAgIH19XFxuXFxuICAgICAgICAgICAge3sgLyogZXh0cmEgYnJhY2UgY2xvc2VzICdlbHNlJyBpbiBkZWYudHJhdmVyc2VUcmVlU3RlcCAqLyB9fVxcbiAgICAgICAgICAgIHt7IyBkZWYudHJhdmVyc2VUcmVlU3RlcCB9fSB9XFxuICAgICAgICB7ez99fVxcbiAgICB9XFxuXFxuICAgIHt7IC8qIHNwbGljZSBpdGVtcyAqLyB9fVxcbiAgICBpZiAoYWRkSXRlbXMgfHwgKCEgdHJlZURvZXNOb3RFeGlzdCAmJiBtXFxuICAgICAgICAgICAgJiYgbS5sZW5ndGggPiBzcGxpY2VJbmRleCApICkge1xcbiAgICAgICAgdmFyIG9sZExlbmd0aCA9IG0ubGVuZ3RoID0gbS5sZW5ndGggfHwgMDtcXG5cXG4gICAgICAgIGFyZ3VtZW50c1swXSA9IHNwbGljZUluZGV4ID0gbm9ybWFsaXplU3BsaWNlSW5kZXgoc3BsaWNlSW5kZXgsIG0ubGVuZ3RoKTtcXG5cXG4gICAgICAgIHt7IC8qIGNsb25lIGFkZGVkIGFyZ3VtZW50cyB0byBwcmV2ZW50IHNhbWUgcmVmZXJlbmNlcyBpbiBsaW5rZWQgbW9kZWxzICovIH19XFxuICAgICAgICBpZiAoYWRkSXRlbXMpXFxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDI7IGkgPCBhcmdzTGVuOyBpKyspXFxuICAgICAgICAgICAgICAgIGFyZ3VtZW50c1tpXSA9IGNsb25lVHJlZShhcmd1bWVudHNbaV0pO1xcblxcbiAgICAgICAge3sgLyogYWN0dWFsIHNwbGljZSBjYWxsICovIH19XFxuICAgICAgICB2YXIgcmVtb3ZlZCA9IEFycmF5LnByb3RvdHlwZS5zcGxpY2UuYXBwbHkobSwgYXJndW1lbnRzKTtcXG5cXG4gICAgICAgIGlmICh0aGlzLl9vcHRpb25zLnJlYWN0aXZlICE9PSBmYWxzZSkge1xcbiAgICAgICAgICAgIHt7IyBkZWYuYWRkTXNnIH19IGFjY2Vzc1BhdGgsIHR5cGU6ICdzcGxpY2UnLFxcbiAgICAgICAgICAgICAgICAgICAgaW5kZXg6IHNwbGljZUluZGV4LCByZW1vdmVkOiByZW1vdmVkLCBhZGRlZENvdW50OiBhZGRJdGVtcyA/IGFyZ3NMZW4gLSAyIDogMCxcXG4gICAgICAgICAgICAgICAgICAgIG5ld1ZhbHVlOiBtIH0pO1xcblxcbiAgICAgICAgICAgIGlmIChyZW1vdmVkICYmIHJlbW92ZWQubGVuZ3RoKVxcbiAgICAgICAgICAgICAgICByZW1vdmVkLmZvckVhY2goZnVuY3Rpb24oaXRlbSwgaW5kZXgpIHtcXG4gICAgICAgICAgICAgICAgICAgIHZhciBpdGVtUGF0aCA9IGFjY2Vzc1BhdGggKyAnWycgKyAoc3BsaWNlSW5kZXggKyBpbmRleCkgKyAnXSc7XFxuICAgICAgICAgICAgICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSBpdGVtUGF0aCwgdHlwZTogJ3JlbW92ZWQnLCBvbGRWYWx1ZTogaXRlbSB9KTtcXG5cXG4gICAgICAgICAgICAgICAgICAgIGlmICh2YWx1ZUlzVHJlZShpdGVtKSlcXG4gICAgICAgICAgICAgICAgICAgICAgICBhZGRNZXNzYWdlcyhtZXNzYWdlcywgbWVzc2FnZXNIYXNoLCBpdGVtUGF0aCwgaXRlbSwgJ3JlbW92ZWQnLCAnb2xkVmFsdWUnKTtcXG4gICAgICAgICAgICAgICAgfSk7XFxuXFxuICAgICAgICAgICAgaWYgKGFkZEl0ZW1zKVxcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMjsgaSA8IGFyZ3NMZW47IGkrKykge1xcbiAgICAgICAgICAgICAgICAgICAgdmFyIGl0ZW0gPSBhcmd1bWVudHNbaV07XFxuICAgICAgICAgICAgICAgICAgICB2YXIgaXRlbVBhdGggPSBhY2Nlc3NQYXRoICsgJ1snICsgKHNwbGljZUluZGV4ICsgaSAtIDIpICsgJ10nO1xcbiAgICAgICAgICAgICAgICAgICAge3sjIGRlZi5hZGRNc2cgfX0gaXRlbVBhdGgsIHR5cGU6ICdhZGRlZCcsIG5ld1ZhbHVlOiBpdGVtIH0pO1xcblxcbiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlSXNUcmVlKGl0ZW0pKVxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFkZE1lc3NhZ2VzKG1lc3NhZ2VzLCBtZXNzYWdlc0hhc2gsIGl0ZW1QYXRoLCBpdGVtLCAnYWRkZWQnLCAnbmV3VmFsdWUnKTtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIHt7IC8qIHBvc3QgYWxsIHN0b3JlZCBtZXNzYWdlcyAqLyB9fVxcbiAgICAgICAgICAgIHt7IyBkZWYucG9zdE1lc3NhZ2VzIH19XFxuICAgICAgICB9XFxuICAgIH1cXG5cXG4gICAgcmV0dXJuIHJlbW92ZWQgfHwgW107XFxufVxcblwiXG59O1xuXG52YXIgaW5jbHVkZV9kZWZpbmVzID0gXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG4vKipcXG4gKiBJbnNlcnRzIGluaXRpYWxpemF0aW9uIGNvZGVcXG4gKi9cXG4ge3sjIyBkZWYuaW5pdFZhcnM6bWV0aG9kOlxcbiAgICB2YXIgbSA9IHt7IyBkZWYubW9kZWxBY2Nlc3NQcmVmaXggfX07XFxuICAgIHZhciBtZXNzYWdlcyA9IFtdLCBtZXNzYWdlc0hhc2ggPSB7fTtcXG4gICAgdmFyIGFjY2Vzc1BhdGggPSAnJztcXG4gICAgdmFyIHRyZWVEb2VzTm90RXhpc3Q7XFxuICAgIC8qIGhhY2sgdG8gcHJldmVudCBzZW5kaW5nIGZpbmlzaGVkIGV2ZW50cyB0byBhbGxvdyBmb3IgcHJvcGFnYXRpb24gb2YgYmF0Y2hlcyB3aXRob3V0IHNwbGl0dGluZyB0aGVtICovXFxuICAgIHZhciBpbkNoYW5nZVRyYW5zYWN0aW9uID0gZ2V0VHJhbnNhY3Rpb25GbGFnKCB7ez0gbWV0aG9kIH19ICk7XFxuICN9fVxcblxcbi8qKlxcbiAqIEluc2VydHMgdGhlIGJlZ2lubmluZyBvZiBmdW5jdGlvbiBjYWxsIHRvIGFkZCBtZXNzYWdlIHRvIGxpc3RcXG4gKi9cXG57eyMjIGRlZi5hZGRNc2c6IGFkZENoYW5nZU1lc3NhZ2UobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgeyBwYXRoOiAjfX1cXG5cXG4vKipcXG4gKiBJbnNlcnRzIGN1cnJlbnQgcHJvcGVydHkvaW5kZXggZm9yIGJvdGggbm9ybWFsIGFuZCBpbnRlcnBvbGF0ZWQgcHJvcGVydGllcy9pbmRleGVzXFxuICovXFxue3sjIyBkZWYuY3VyclByb3A6e3s/IGN1cnJOb2RlLmludGVycG9sYXRlIH19W3RoaXMuX2FyZ3NbIHt7PSBjdXJyTm9kZS5pbnRlcnBvbGF0ZSB9fSBdXXt7Pz99fXt7PSBjdXJyUHJvcCB9fXt7P319ICN9fVxcblxcbi8qKlxcbiAqIEluc2VydHMgY29uZGl0aW9uIHRvIHRlc3Qgd2hldGhlciBub3JtYWwvaW50ZXJwb2xhdGVkIHByb3BlcnR5L2luZGV4IGV4aXN0c1xcbiAqL1xcbnt7IyMgZGVmLndhc0RlZmluZWQ6IG0uaGFzT3duUHJvcGVydHkoXFxuICAgIHt7PyBjdXJyTm9kZS5pbnRlcnBvbGF0ZSB9fVxcbiAgICAgICAgdGhpcy5fYXJnc1sge3s9IGN1cnJOb2RlLmludGVycG9sYXRlIH19IF1cXG4gICAge3s/P319XFxuICAgICAgICAne3s9IGl0LmdldFBhdGhOb2RlS2V5KGN1cnJOb2RlKSB9fSdcXG4gICAge3s/fX1cXG4pICN9fVxcblxcblxcbi8qKlxcbiAqIEluc2VydHMgY29kZSB0byB1cGRhdGUgYWNjZXNzIHBhdGggZm9yIGN1cnJlbnQgcHJvcGVydHlcXG4gKiBCZWNhdXNlIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBpbnRlcnBvbGF0ZWQgcHJvcGVydGllcywgaXQgY2FuJ3QgYmUgY2FsY3VsYXRlZCBpbiB0ZW1wbGF0ZSwgaXQgY2FuIG9ubHkgYmUgY2FsY3VsYXRlZCBkdXJpbmcgYWNjZXNzb3IgY2FsbC5cXG4gKi9cXG57eyMjIGRlZi5jaGFuZ2VBY2Nlc3NQYXRoOlxcbiAgICBhY2Nlc3NQYXRoICs9IHt7PyBjdXJyTm9kZS5pbnRlcnBvbGF0ZSB9fVxcbiAgICAgICAge3s/IGN1cnJOb2RlLnN5bnRheCA9PSAnYXJyYXknIH19XFxuICAgICAgICAgICAgJ1snICsgdGhpcy5fYXJnc1sge3s9IGN1cnJOb2RlLmludGVycG9sYXRlIH19IF0gKyAnXSc7XFxuICAgICAgICB7ez8/fX1cXG4gICAgICAgICAgICAnLicgKyB0aGlzLl9hcmdzWyB7ez0gY3Vyck5vZGUuaW50ZXJwb2xhdGUgfX0gXTtcXG4gICAgICAgIHt7P319XFxuICAgIHt7Pz99fVxcbiAgICAgICAgJ3t7PSBjdXJyUHJvcCB9fSc7XFxuICAgIHt7P319XFxuI319XFxuXFxuXFxuLyoqXFxuICogSW5zZXJ0cyBjb2RlIHRvIHBvc3Qgc3RvcmVkIG1lc3NhZ2VzXFxuICovXFxue3sjIyBkZWYucG9zdE1lc3NhZ2VzOlxcbiAgICBpZiAobWVzc2FnZXMubGVuZ3RoKSB7XFxuICAgICAgICB7eyMgZGVmLm1vZGVsUG9zdEJhdGNoQ29kZSB9fSgnZGF0YWNoYW5nZXMnLCB7XFxuICAgICAgICAgICAgY2hhbmdlczogbWVzc2FnZXMsXFxuICAgICAgICAgICAgdHJhbnNhY3Rpb246IGluQ2hhbmdlVHJhbnNhY3Rpb25cXG4gICAgICAgIH0pO1xcblxcbiAgICAgICAgbWVzc2FnZXMuZm9yRWFjaChmdW5jdGlvbihtc2cpIHtcXG4gICAgICAgICAgICB7eyMgZGVmLm1vZGVsUG9zdE1lc3NhZ2VDb2RlIH19KG1zZy5wYXRoLCBtc2cpO1xcbiAgICAgICAgfSwgdGhpcyk7XFxuICAgIH1cXG4jfX1cXG5cIlxuICAgICwgaW5jbHVkZV9jcmVhdGVfdHJlZSA9IFwiJ3VzZSBzdHJpY3QnO1xcbi8qIE9ubHkgdXNlIHRoaXMgc3R5bGUgb2YgY29tbWVudHMsIG5vdCBcXFwiLy9cXFwiICovXFxuXFxuLyoqXFxuICogSW5zZXJ0cyBjb2RlIHRvIGNyZWF0ZSBtb2RlbCB0cmVlIGFzIG5lY2Nlc3NhcnkgZm9yIGBzZXRgIGFuZCBgc3BsaWNlYCBhY2Nlc3NvcnMgYW5kIHRvIGFkZCBtZXNzYWdlcyB0byBzZW5kIGxpc3QgaWYgdGhlIHRyZWUgY2hhbmdlcy5cXG4gKi9cXG57eyMjIGRlZi5jcmVhdGVUcmVlOm1ldGhvZDpcXG4gICAgdmFyIHdhc0RlZiA9IHRydWU7XFxuICAgIHZhciBvbGQgPSBtO1xcblxcbiAgICB7eyB2YXIgZW1wdHlQcm9wID0gaXQucGFyc2VkUGF0aFswXSAmJiBpdC5wYXJzZWRQYXRoWzBdLmVtcHR5OyB9fVxcbiAgICB7ez8gZW1wdHlQcm9wIH19XFxuICAgICAgICB7eyAvKiBjcmVhdGUgdG9wIGxldmVsIG1vZGVsIGlmIGl0IHdhcyBub3QgcHJldmlvdXNseSBkZWZpbmVkICovIH19XFxuICAgICAgICBpZiAoISBtKSB7XFxuICAgICAgICAgICAgbSA9IHt7IyBkZWYubW9kZWxBY2Nlc3NQcmVmaXggfX0gPSB7ez0gZW1wdHlQcm9wIH19O1xcbiAgICAgICAgICAgIHdhc0RlZiA9IGZhbHNlO1xcblxcbiAgICAgICAgICAgIGlmICh0aGlzLl9vcHRpb25zLnJlYWN0aXZlICE9PSBmYWxzZSkge1xcbiAgICAgICAgICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSAnJywgdHlwZTogJ2FkZGVkJyxcXG4gICAgICAgICAgICAgICAgICAgICAgbmV3VmFsdWU6IG0gfSk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB7ez8/fX1cXG4gICAgICAgIHt7PyBtZXRob2QgPT0gJ3NwbGljZScgfX1cXG4gICAgICAgICAgICBpZiAoISBtKSB7XFxuICAgICAgICB7ez99fVxcbiAgICAgICAgICAgICAgICBtID0ge3sjIGRlZi5tb2RlbEFjY2Vzc1ByZWZpeCB9fSA9IGNsb25lVHJlZSh2YWx1ZSk7XFxuICAgICAgICAgICAgICAgIHdhc0RlZiA9IHR5cGVvZiBvbGQgIT0gJ3VuZGVmaW5lZCc7XFxuICAgICAgICB7ez8gbWV0aG9kID09ICdzcGxpY2UnIH19XFxuICAgICAgICAgICAgfVxcbiAgICAgICAge3s/fX0gICAgICAgXFxuICAgIHt7P319XFxuXFxuXFxuICAgIHt7IC8qIGNyZWF0ZSBtb2RlbCB0cmVlIGlmIGl0IGRvZXNuJ3QgZXhpc3QgKi8gfX1cXG4gICAge3sgIHZhciBtb2RlbERhdGFQcm9wZXJ0eSA9ICcnO1xcbiAgICAgICAgdmFyIG5leHROb2RlID0gaXQucGFyc2VkUGF0aFswXTtcXG4gICAgICAgIHZhciBjb3VudCA9IGl0LnBhcnNlZFBhdGgubGVuZ3RoIC0gMTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY291bnQ7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBjdXJyTm9kZSA9IG5leHROb2RlO1xcbiAgICAgICAgICAgIHZhciBjdXJyUHJvcCA9IGN1cnJOb2RlLnByb3BlcnR5O1xcbiAgICAgICAgICAgIG5leHROb2RlID0gaXQucGFyc2VkUGF0aFtpICsgMV07XFxuICAgICAgICAgICAgdmFyIGVtcHR5UHJvcCA9IG5leHROb2RlICYmIG5leHROb2RlLmVtcHR5O1xcbiAgICB9fVxcblxcbiAgICAgICAge3sjIGRlZi5jcmVhdGVUcmVlU3RlcCB9fVxcblxcbiAgICB7eyAgfSAvKiBmb3IgbG9vcCAqLyB9fVxcbiN9fVxcblxcblxcbi8qKlxcbiAqIEluc2VydHMgY29kZSB0byBjcmVhdGUgb25lIHN0ZXAgaW4gdGhlIG1vZGVsIHRyZWVcXG4gKi9cXG57eyMjIGRlZi5jcmVhdGVUcmVlU3RlcDpcXG4gICAge3sjIGRlZi5jaGFuZ2VBY2Nlc3NQYXRoIH19XFxuXFxuICAgIGlmICghIHt7IyBkZWYud2FzRGVmaW5lZCB9fSkgeyBcXG4gICAgICAgIHt7IC8qIHByb3BlcnR5IGRvZXMgbm90IGV4aXN0ICovIH19XFxuICAgICAgICBtID0gbXt7IyBkZWYuY3VyclByb3AgfX0gPSB7ez0gZW1wdHlQcm9wIH19O1xcblxcbiAgICAgICAgaWYgKHRoaXMuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XFxuICAgICAgICAgICAge3sjIGRlZi5hZGRNc2cgfX0gYWNjZXNzUGF0aCwgdHlwZTogJ2FkZGVkJywgXFxuICAgICAgICAgICAgICAgICAgbmV3VmFsdWU6IG0gfSk7XFxuICAgICAgICB9XFxuXFxuICAgIH0gZWxzZSBpZiAodHlwZW9mIG17eyMgZGVmLmN1cnJQcm9wIH19ICE9ICdvYmplY3QnKSB7XFxuICAgICAgICB7eyAvKiBwcm9wZXJ0eSBpcyBub3Qgb2JqZWN0ICovIH19XFxuICAgICAgICB2YXIgb2xkID0gbXt7IyBkZWYuY3VyclByb3AgfX07XFxuICAgICAgICBtID0gbXt7IyBkZWYuY3VyclByb3AgfX0gPSB7ez0gZW1wdHlQcm9wIH19O1xcblxcbiAgICAgICAgaWYgKHRoaXMuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XFxuICAgICAgICAgICAge3sjIGRlZi5hZGRNc2cgfX0gYWNjZXNzUGF0aCwgdHlwZTogJ2NoYW5nZWQnLCBcXG4gICAgICAgICAgICAgICAgICBvbGRWYWx1ZTogb2xkLCBuZXdWYWx1ZTogbSB9KTtcXG4gICAgICAgIH1cXG5cXG4gICAgfSBlbHNlIHtcXG4gICAgICAgIHt7IC8qIHByb3BlcnR5IGV4aXN0cywganVzdCB0cmF2ZXJzZSBkb3duIHRoZSBtb2RlbCB0cmVlICovIH19XFxuICAgICAgICBtID0gbXt7IyBkZWYuY3VyclByb3AgfX07XFxuICAgIH1cXG4jfX1cXG5cIlxuICAgICwgaW5jbHVkZV90cmF2ZXJzZV90cmVlID0gXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG4vKipcXG4gKiBJbnNlcnRzIGNvZGUgdG8gdHJhdmVyc2UgbW9kZWwgdHJlZSBmb3IgYGRlbGV0ZWAgYW5kIGBzcGxpY2VgIGFjY2Vzc29ycy5cXG4gKi9cXG57eyMjIGRlZi50cmF2ZXJzZVRyZWU6XFxuICAgIHt7IFxcbiAgICAgICAgdmFyIGNvdW50ID0gaXQucGFyc2VkUGF0aC5sZW5ndGgtMTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY291bnQ7IGkrKykgeyBcXG4gICAgICAgICAgICB2YXIgY3Vyck5vZGUgPSBpdC5wYXJzZWRQYXRoW2ldO1xcbiAgICAgICAgICAgIHZhciBjdXJyUHJvcCA9IGN1cnJOb2RlLnByb3BlcnR5O1xcbiAgICB9fVxcbiAgICAgICAgICAgIHt7IyBkZWYudHJhdmVyc2VUcmVlU3RlcCB9fVxcblxcbiAgICB7eyB9IC8qIGZvciBsb29wICovXFxuXFxuICAgICAgICB2YXIgaSA9IGNvdW50O1xcbiAgICAgICAgd2hpbGUgKGktLSkgeyAvKiBjbG9zaW5nIGJyYWNlcyBmb3IgZWxzZSdzIGFib3ZlICovXFxuICAgIH19XFxuICAgICAgICAgICAgfVxcbiAgICB7eyB9IC8qIHdoaWxlIGxvb3AgKi8gfX1cXG4jfX1cXG5cXG5cXG4vKipcXG4gKiBJbnNlcnRzIGNvZGUgdG8gdHJhdmVyc2Ugb25lIHN0ZXAgaW4gdGhlIG1vZGVsIHRyZWVcXG4gKi9cXG57eyMjIGRlZi50cmF2ZXJzZVRyZWVTdGVwOlxcbiAgICBpZiAoISAobSAmJiBtLmhhc093blByb3BlcnR5ICYmIHt7IyBkZWYud2FzRGVmaW5lZH19ICkgKVxcbiAgICAgICAgdHJlZURvZXNOb3RFeGlzdCA9IHRydWU7XFxuICAgIGVsc2Uge1xcbiAgICAgICAgbSA9IG17eyMgZGVmLmN1cnJQcm9wIH19O1xcbiAgICAgICAge3sjIGRlZi5jaGFuZ2VBY2Nlc3NQYXRoIH19XFxuICAgIHt7IC8qIGJyYWNlIGZyb20gZWxzZSBpcyBub3QgY2xvc2VkIG9uIHB1cnBvc2UgLSBhbGwgYnJhY2VzIGFyZSBjbG9zZWQgaW4gd2hpbGUgbG9vcCAqLyB9fVxcbiN9fVxcblwiO1xuXG52YXIgZG90RGVmID0ge1xuICAgIGluY2x1ZGVfZGVmaW5lczogaW5jbHVkZV9kZWZpbmVzLFxuICAgIGluY2x1ZGVfY3JlYXRlX3RyZWU6IGluY2x1ZGVfY3JlYXRlX3RyZWUsXG4gICAgaW5jbHVkZV90cmF2ZXJzZV90cmVlOiBpbmNsdWRlX3RyYXZlcnNlX3RyZWUsXG4gICAgZ2V0UGF0aE5vZGVLZXk6IHBhdGhVdGlscy5nZXRQYXRoTm9kZUtleSxcbiAgICBtb2RlbEFjY2Vzc1ByZWZpeDogJ3RoaXMuX21vZGVsLl9kYXRhJyxcbiAgICBtb2RlbFBvc3RNZXNzYWdlQ29kZTogJ3RoaXMuX21vZGVsLl9pbnRlcm5hbE1lc3Nlbmdlci5wb3N0TWVzc2FnZScsXG4gICAgbW9kZWxQb3N0QmF0Y2hDb2RlOiAndGhpcy5fbW9kZWwucG9zdE1lc3NhZ2VTeW5jJyxcbiAgICBpbnRlcm5hbE1lc3NlbmdlcjogJ3RoaXMuX21vZGVsLl9pbnRlcm5hbE1lc3Nlbmdlcidcbn07XG5cbnZhciBtb2RlbERvdERlZiA9IF8oZG90RGVmKS5jbG9uZSgpLmV4dGVuZCh7XG4gICAgbW9kZWxBY2Nlc3NQcmVmaXg6ICd0aGlzLl9kYXRhJyxcbiAgICBtb2RlbFBvc3RNZXNzYWdlQ29kZTogJ3RoaXMuX2ludGVybmFsTWVzc2VuZ2VyLnBvc3RNZXNzYWdlJyxcbiAgICBtb2RlbFBvc3RCYXRjaENvZGU6ICd0aGlzLnBvc3RNZXNzYWdlU3luYycsXG4gICAgaW50ZXJuYWxNZXNzZW5nZXI6ICd0aGlzLl9pbnRlcm5hbE1lc3Nlbmdlcidcbn0pLl8oKTtcblxuXG52YXIgZG90U2V0dGluZ3MgPSBfLmNsb25lKGRvVC50ZW1wbGF0ZVNldHRpbmdzKTtcbmRvdFNldHRpbmdzLnN0cmlwID0gZmFsc2U7XG5cbnZhciBzeW50aGVzaXplcnMgPSBfLm1hcEtleXModGVtcGxhdGVzLCBmdW5jdGlvbih0bXBsKSB7XG4gICAgcmV0dXJuIGRvVC50ZW1wbGF0ZSh0bXBsLCBkb3RTZXR0aW5ncywgZG90RGVmKTsgXG59KTtcblxuXG52YXIgbW9kZWxTeW50aGVzaXplcnMgPSBfLm1hcFRvT2JqZWN0KFsnc2V0JywgJ2RlbCcsICdzcGxpY2UnXSwgZnVuY3Rpb24obWV0aG9kTmFtZSkge1xuICAgIHJldHVybiBkb1QudGVtcGxhdGUodGVtcGxhdGVzW21ldGhvZE5hbWVdLCBkb3RTZXR0aW5ncywgbW9kZWxEb3REZWYpO1xufSk7XG5cblxuLyoqXG4gKiBGdW5jdGlvbiB0aGF0IHN5bnRoZXNpemVzIGFjY2Vzc29yIG1ldGhvZHMuXG4gKiBGdW5jdGlvbiBpcyBtZW1vaXplZCBzbyBhY2Nlc3NvcnMgYXJlIGNhY2hlZCAodXAgdG8gMTAwMCkuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHBhdGggTW9kZWwvTW9kZWxQYXRoIGFjY2VzcyBwYXRoXG4gKiBAcGFyYW0ge0FycmF5fSBwYXJzZWRQYXRoIGFycmF5IG9mIHBhdGggbm9kZXNcbiAqIEByZXR1cm4ge09iamVjdFtGdW5jdGlvbl19XG4gKi9cbnZhciBzeW50aGVzaXplUGF0aE1ldGhvZHMgPSBfLm1lbW9pemUoX3N5bnRoZXNpemVQYXRoTWV0aG9kcywgdW5kZWZpbmVkLCAxMDAwKTtcblxuZnVuY3Rpb24gX3N5bnRoZXNpemVQYXRoTWV0aG9kcyhwYXRoLCBwYXJzZWRQYXRoKSB7XG4gICAgdmFyIG1ldGhvZHMgPSBfLm1hcEtleXMoc3ludGhlc2l6ZXJzLCBmdW5jdGlvbihzeW50aHN6cikge1xuICAgICAgICByZXR1cm4gX3N5bnRoZXNpemUoc3ludGhzenIsIHBhdGgsIHBhcnNlZFBhdGgpO1xuICAgIH0pO1xuICAgIHJldHVybiBtZXRob2RzO1xufVxuXG5cbnZhciBub3JtYWxpemVTcGxpY2VJbmRleCA9IG1vZGVsVXRpbHMubm9ybWFsaXplU3BsaWNlSW5kZXg7IC8vIHVzZWQgaW4gc3BsaWNlLmRvdC5qc1xuXG5cbmZ1bmN0aW9uIF9zeW50aGVzaXplKHN5bnRoZXNpemVyLCBwYXRoLCBwYXJzZWRQYXRoKSB7XG4gICAgdmFyIG1ldGhvZFxuICAgICAgICAsIG1ldGhvZENvZGUgPSBzeW50aGVzaXplcih7XG4gICAgICAgICAgICBwYXJzZWRQYXRoOiBwYXJzZWRQYXRoLFxuICAgICAgICAgICAgZ2V0UGF0aE5vZGVLZXk6IHBhdGhVdGlscy5nZXRQYXRoTm9kZUtleVxuICAgICAgICB9KTtcblxuICAgIHRyeSB7XG4gICAgICAgIGV2YWwobWV0aG9kQ29kZSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBNb2RlbEVycm9yKCdNb2RlbFBhdGggbWV0aG9kIGNvbXBpbGF0aW9uIGVycm9yOyBwYXRoOiAnICsgcGF0aCArICcsIGNvZGU6ICcgKyBtZXRob2RDb2RlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbWV0aG9kO1xuXG5cbiAgICAvLyBmdW5jdGlvbnMgdXNlZCBieSBtZXRob2RzIGBzZXRgLCBgZGVsZXRlYCBhbmQgYHNwbGljZWAgKHN5bnRoZXNpemVkIGJ5IHRlbXBsYXRlKVxuICAgIGZ1bmN0aW9uIGFkZENoYW5nZU1lc3NhZ2UobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgbXNnKSB7XG4gICAgICAgIG1lc3NhZ2VzLnB1c2gobXNnKTtcbiAgICAgICAgbWVzc2FnZXNIYXNoW21zZy5wYXRoXSA9IG1zZztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBhZGRUcmVlQ2hhbmdlc01lc3NhZ2VzKG1lc3NhZ2VzLCBtZXNzYWdlc0hhc2gsIHJvb3RQYXRoLCBvbGRWYWx1ZSwgbmV3VmFsdWUpIHtcbiAgICAgICAgdmFyIG9sZElzVHJlZSA9IHZhbHVlSXNUcmVlKG9sZFZhbHVlKVxuICAgICAgICAgICAgLCBuZXdJc1RyZWUgPSB2YWx1ZUlzVHJlZShuZXdWYWx1ZSk7XG5cbiAgICAgICAgaWYgKG5ld0lzVHJlZSlcbiAgICAgICAgICAgIGFkZE1lc3NhZ2VzKG1lc3NhZ2VzLCBtZXNzYWdlc0hhc2gsIHJvb3RQYXRoLCBuZXdWYWx1ZSwgJ2FkZGVkJywgJ25ld1ZhbHVlJyk7XG4gICAgICAgIFxuICAgICAgICBpZiAob2xkSXNUcmVlKVxuICAgICAgICAgICAgYWRkTWVzc2FnZXMobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgcm9vdFBhdGgsIG9sZFZhbHVlLCAncmVtb3ZlZCcsICdvbGRWYWx1ZScpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFkZE1lc3NhZ2VzKG1lc3NhZ2VzLCBtZXNzYWdlc0hhc2gsIHJvb3RQYXRoLCBvYmosIG1zZ1R5cGUsIHZhbHVlUHJvcCkge1xuICAgICAgICBfYWRkTWVzc2FnZXMocm9vdFBhdGgsIG9iaik7XG5cblxuICAgICAgICBmdW5jdGlvbiBfYWRkTWVzc2FnZXMocm9vdFBhdGgsIG9iaikge1xuICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2JqKSkge1xuICAgICAgICAgICAgICAgIHZhciBwYXRoU3ludGF4ID0gcm9vdFBhdGggKyAnWyQkXSc7XG4gICAgICAgICAgICAgICAgb2JqLmZvckVhY2goZnVuY3Rpb24odmFsdWUsIGluZGV4KSB7XG4gICAgICAgICAgICAgICAgICAgIGFkZE1lc3NhZ2UodmFsdWUsIGluZGV4LCBwYXRoU3ludGF4KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFyIHBhdGhTeW50YXggPSByb290UGF0aCArICcuJCQnO1xuICAgICAgICAgICAgICAgIF8uZWFjaEtleShvYmosIGZ1bmN0aW9uKHZhbHVlLCBrZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgYWRkTWVzc2FnZSh2YWx1ZSwga2V5LCBwYXRoU3ludGF4KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGFkZE1lc3NhZ2UodmFsdWUsIGtleSwgcGF0aFN5bnRheCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBwYXRoU3ludGF4LnJlcGxhY2UoJyQkJywga2V5KVxuICAgICAgICAgICAgICAgICwgZXhpc3RpbmdNc2cgPSBtZXNzYWdlc0hhc2hbcGF0aF07XG5cbiAgICAgICAgICAgIGlmIChleGlzdGluZ01zZykge1xuICAgICAgICAgICAgICAgIGlmIChleGlzdGluZ01zZy50eXBlID09IG1zZ1R5cGUpXG4gICAgICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcignc2V0dGVyIGVycm9yOiBzYW1lIG1lc3NhZ2UgdHlwZSBwb3N0ZWQgb24gdGhlIHNhbWUgcGF0aCcpO1xuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBleGlzdGluZ01zZy50eXBlID0gJ2NoYW5nZWQnO1xuICAgICAgICAgICAgICAgICAgICBleGlzdGluZ01zZ1t2YWx1ZVByb3BdID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YXIgbXNnID0geyBwYXRoOiBwYXRoLCB0eXBlOiBtc2dUeXBlIH07XG4gICAgICAgICAgICAgICAgbXNnW3ZhbHVlUHJvcF0gPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICBhZGRDaGFuZ2VNZXNzYWdlKG1lc3NhZ2VzLCBtZXNzYWdlc0hhc2gsIG1zZyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh2YWx1ZUlzVHJlZSh2YWx1ZSkpXG4gICAgICAgICAgICAgICAgX2FkZE1lc3NhZ2VzKHBhdGgsIHZhbHVlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNsb25lVHJlZSh2YWx1ZSkge1xuICAgICAgICByZXR1cm4gdmFsdWVJc05vcm1hbE9iamVjdCh2YWx1ZSlcbiAgICAgICAgICAgICAgICA/IF8uZGVlcENsb25lKHZhbHVlKVxuICAgICAgICAgICAgICAgIDogdmFsdWU7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcHJvdGVjdFZhbHVlKHZhbHVlKSB7XG4gICAgICAgIHJldHVybiAhIHZhbHVlSXNOb3JtYWxPYmplY3QodmFsdWUpXG4gICAgICAgICAgICAgICAgPyB2YWx1ZVxuICAgICAgICAgICAgICAgIDogQXJyYXkuaXNBcnJheSh2YWx1ZSlcbiAgICAgICAgICAgICAgICAgICAgPyB2YWx1ZS5zbGljZSgpXG4gICAgICAgICAgICAgICAgICAgIDogT2JqZWN0LmNyZWF0ZSh2YWx1ZSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdmFsdWVJc1RyZWUodmFsdWUpIHtcbiAgICAgICAgcmV0dXJuIHZhbHVlSXNOb3JtYWxPYmplY3QodmFsdWUpXG4gICAgICAgICAgICAgICAgJiYgT2JqZWN0LmtleXModmFsdWUpLmxlbmd0aDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB2YWx1ZUlzTm9ybWFsT2JqZWN0KHZhbHVlKSB7XG4gICAgICAgIHJldHVybiB2YWx1ZSAhPSBudWxsXG4gICAgICAgICAgICAgICAgJiYgdHlwZW9mIHZhbHVlID09IFwib2JqZWN0XCJcbiAgICAgICAgICAgICAgICAmJiAhICh2YWx1ZSBpbnN0YW5jZW9mIERhdGUpXG4gICAgICAgICAgICAgICAgJiYgISAodmFsdWUgaW5zdGFuY2VvZiBSZWdFeHApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFkZEJhdGNoSWRzVG9NZXNzYWdlKG1zZywgYmF0Y2hJZCwgbXNnSWQpIHtcbiAgICAgICAgXy5kZWZpbmVQcm9wZXJ0aWVzKG1zZywge1xuICAgICAgICAgICAgX19iYXRjaF9pZDogYmF0Y2hJZCxcbiAgICAgICAgICAgIF9fbXNnX2lkOiBtc2dJZFxuICAgICAgICB9KTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBFeHBvcnRzIGBzeW50aGVzaXplYCBmdW5jdGlvbiB3aXRoIHRoZSBmb2xsb3dpbmc6XG4gKlxuICogLSAubW9kZWxNZXRob2RzLnNldCAtIGBzZXRgIG1ldGhvZCBmb3IgTW9kZWxcbiAqIC0gLm1vZGVsTWV0aG9kcy5kZWwgLSBgZGVsYCBtZXRob2QgZm9yIE1vZGVsXG4gKiAtIC5tb2RlbE1ldGhvZHMuc3BsaWNlIC0gYHNwbGljZWAgbWV0aG9kIGZvciBNb2RlbFxuICovXG5tb2R1bGUuZXhwb3J0cyA9IHN5bnRoZXNpemVQYXRoTWV0aG9kcztcblxudmFyIG1vZGVsTWV0aG9kcyA9IF8ubWFwS2V5cyhtb2RlbFN5bnRoZXNpemVycywgZnVuY3Rpb24oc3ludGhlc2l6ZXIpIHtcbiAgICByZXR1cm4gX3N5bnRoZXNpemUoc3ludGhlc2l6ZXIsICcnLCBbXSk7XG59KTtcblxuc3ludGhlc2l6ZVBhdGhNZXRob2RzLm1vZGVsTWV0aG9kcyA9IG1vZGVsTWV0aG9kcztcbiIsImFyZ3VtZW50c1s0XVs5MF1bMF0uYXBwbHkoZXhwb3J0cyxhcmd1bWVudHMpIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIGBtaWxvLnV0aWxgXG4gKi9cbnZhciB1dGlsID0ge1xuICAgIGxvZ2dlcjogcmVxdWlyZSgnLi9sb2dnZXInKSxcbiAgICBjaGVjazogcmVxdWlyZSgnLi9jaGVjaycpLFxufTtcblxubW9kdWxlLmV4cG9ydHMgPSB1dGlsO1xuIiwiYXJndW1lbnRzWzRdWzEwMl1bMF0uYXBwbHkoZXhwb3J0cyxhcmd1bWVudHMpIiwiYXJndW1lbnRzWzRdWzEwM11bMF0uYXBwbHkoZXhwb3J0cyxhcmd1bWVudHMpIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzJyk7XG5cblxuLyoqXG4gKiBbX19Qcm90b3R5cGUgZnVuY3Rpb25zX19dKHByb3RvX3Byb3RvdHlwZS5qcy5odG1sKVxuICpcbiAqIC0gW2V4dGVuZFByb3RvXShwcm90b19wcm90b3R5cGUuanMuaHRtbCNleHRlbmRQcm90bylcbiAqIC0gW2NyZWF0ZVN1YmNsYXNzXShwcm90b19wcm90b3R5cGUuanMuaHRtbCNjcmVhdGVTdWJjbGFzcylcbiAqIC0gW21ha2VTdWJjbGFzc10ocHJvdG9fcHJvdG90eXBlLmpzLmh0bWwjbWFrZVN1YmNsYXNzKVxuICogLSBbbmV3QXBwbHldKHByb3RvX3Byb3RvdHlwZS5qcy5odG1sI25ld0FwcGx5KVxuICovXG52YXIgcHJvdG90eXBlTWV0aG9kcyA9IHJlcXVpcmUoJy4vcHJvdG9fcHJvdG90eXBlJyk7XG5cblxuLyoqXG4gKiBbX19PYmplY3QgZnVuY3Rpb25zX19dKHByb3RvX29iamVjdC5qcy5odG1sKVxuICpcbiAqIC0gW2V4dGVuZF0ocHJvdG9fb2JqZWN0LmpzLmh0bWwjZXh0ZW5kKVxuICogLSBbY2xvbmVdKHByb3RvX29iamVjdC5qcy5odG1sI2Nsb25lKVxuICogLSBbZGVmaW5lUHJvcGVydHldKHByb3RvX29iamVjdC5qcy5odG1sI2RlZmluZVByb3BlcnR5KVxuICogLSBbZGVmaW5lUHJvcGVydGllc10ocHJvdG9fb2JqZWN0LmpzLmh0bWwjZGVmaW5lUHJvcGVydGllcylcbiAqIC0gW2RlZXBFeHRlbmRdKHByb3RvX29iamVjdC5qcy5odG1sI2RlZXBFeHRlbmQpXG4gKiAtIFtkZWVwQ2xvbmVdKHByb3RvX29iamVjdC5qcy5odG1sI2RlZXBDbG9uZSlcbiAqIC0gW2tleXNdKHByb3RvX29iamVjdC5qcy5odG1sI2tleXMpXG4gKiAtIFthbGxLZXlzXShwcm90b19vYmplY3QuanMuaHRtbCNhbGxLZXlzKVxuICogLSBbdmFsdWVzXShwcm90b19vYmplY3QuanMuaHRtbCN2YWx1ZXMpXG4gKiAtIFtrZXlPZl0ocHJvdG9fb2JqZWN0LmpzLmh0bWwja2V5T2YpXG4gKiAtIFthbGxLZXlzT2ZdKHByb3RvX29iamVjdC5qcy5odG1sI2FsbEtleXNPZilcbiAqIC0gW2VhY2hLZXldKHByb3RvX29iamVjdC5qcy5odG1sI2VhY2hLZXkpXG4gKiAtIFttYXBLZXlzXShwcm90b19vYmplY3QuanMuaHRtbCNtYXBLZXlzKVxuICogLSBbcmVkdWNlS2V5c10ocHJvdG9fb2JqZWN0LmpzLmh0bWwjcmVkdWNlS2V5cylcbiAqIC0gW2ZpbHRlcktleXNdKHByb3RvX29iamVjdC5qcy5odG1sI2ZpbHRlcktleXMpXG4gKiAtIFtzb21lS2V5XShwcm90b19vYmplY3QuanMuaHRtbCNzb21lS2V5KVxuICogLSBbZXZlcnlLZXldKHByb3RvX29iamVjdC5qcy5odG1sI2V2ZXJ5S2V5KVxuICogLSBbZmluZFZhbHVlXShwcm90b19vYmplY3QuanMuaHRtbCNmaW5kVmFsdWUpXG4gKiAtIFtmaW5kS2V5XShwcm90b19vYmplY3QuanMuaHRtbCNmaW5kS2V5KVxuICogLSBbcGlja0tleXNdKHByb3RvX29iamVjdC5qcy5odG1sI3BpY2tLZXlzKVxuICogLSBbb21pdEtleXNdKHByb3RvX29iamVjdC5qcy5odG1sI29taXRLZXlzKVxuICogLSBbaXNFcXVhbF0ocHJvdG9fb2JqZWN0LmpzLmh0bWwjaXNFcXVhbClcbiAqIC0gW2lzTm90XShwcm90b19vYmplY3QuanMuaHRtbCNpc05vdClcbiAqL1xudmFyIG9iamVjdE1ldGhvZHMgPSByZXF1aXJlKCcuL3Byb3RvX29iamVjdCcpO1xuXG5cbi8qKlxuICogW19fQXJyYXkgZnVuY3Rpb25zX19dKHByb3RvX2FycmF5LmpzLmh0bWwpXG4gKlxuICogLSBbZmluZF0ocHJvdG9fYXJyYXkuanMuaHRtbCNmaW5kKVxuICogLSBbZmluZEluZGV4XShwcm90b19hcnJheS5qcy5odG1sI2ZpbmRJbmRleClcbiAqIC0gW2FwcGVuZEFycmF5XShwcm90b19hcnJheS5qcy5odG1sI2FwcGVuZEFycmF5KVxuICogLSBbcHJlcGVuZEFycmF5XShwcm90b19hcnJheS5qcy5odG1sI3ByZXBlbmRBcnJheSlcbiAqIC0gW3NwbGljZUl0ZW1dKHByb3RvX2FycmF5LmpzLmh0bWwjc3BsaWNlSXRlbSlcbiAqIC0gW3RvQXJyYXldKHByb3RvX2FycmF5LmpzLmh0bWwjdG9BcnJheSlcbiAqIC0gW29iamVjdF0ocHJvdG9fYXJyYXkuanMuaHRtbCNvYmplY3QpXG4gKiAtIFttYXBUb09iamVjdF0ocHJvdG9fYXJyYXkuanMuaHRtbCNtYXBUb09iamVjdClcbiAqIC0gW3VuaXF1ZV0ocHJvdG9fYXJyYXkuanMuaHRtbCN1bmlxdWUpXG4gKiAtIFtkZWVwRm9yRWFjaF0ocHJvdG9fYXJyYXkuanMuaHRtbCNkZWVwRm9yRWFjaClcbiAqXG4gKiBGdW5jdGlvbnMgdGhhdCBBcnJheSBbaW1wbGVtZW50cyBuYXRpdmVseV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvcHJvdG90eXBlI01ldGhvZHMpIGFyZSBhbHNvIGFkZGVkIC0gdGhleSBjYW4gYmUgdXNlZCB3aXRoIGFycmF5LWxpa2Ugb2JqZWN0cyBhbmQgZm9yIGNoYWluaW5nIChuYXRpdmUgZnVuY3Rpb25zIGFyZSBhbHdheXMgY2FsbGVkKS5cbiAqL1xudmFyIGFycmF5TWV0aG9kcyA9IHJlcXVpcmUoJy4vcHJvdG9fYXJyYXknKTtcblxuXG4vKipcbiAqIFtfX0Z1bmN0aW9uIGZ1bmN0aW9uc19fXShwcm90b19mdW5jdGlvbi5qcy5odG1sKVxuICpcbiAqIC0gW21ha2VGdW5jdGlvbl0ocHJvdG9fZnVuY3Rpb24uanMuaHRtbCNtYWtlRnVuY3Rpb24pXG4gKiAtIFtwYXJ0aWFsXShwcm90b19mdW5jdGlvbi5qcy5odG1sI3BhcnRpYWwpXG4gKiAtIFtwYXJ0aWFsUmlnaHRdKHByb3RvX2Z1bmN0aW9uLmpzLmh0bWwjcGFydGlhbFJpZ2h0KVxuICogLSBbbWVtb2l6ZV0ocHJvdG9fZnVuY3Rpb24uanMuaHRtbCNtZW1vaXplKVxuICogLSBbZGVsYXldKHByb3RvX2Z1bmN0aW9uLmpzLmh0bWwjZGVsYXkpXG4gKiAtIFtkZWZlcl0ocHJvdG9fZnVuY3Rpb24uanMuaHRtbCNkZWZlcilcbiAqIC0gW2RlbGF5ZWRdKHByb3RvX2Z1bmN0aW9uLmpzLmh0bWwjZGVsYXllZClcbiAqIC0gW2RlZmVycmVkXShwcm90b19mdW5jdGlvbi5qcy5odG1sI2RlZmVycmVkKVxuICogLSBbZGVmZXJUaWNrc10ocHJvdG9fZnVuY3Rpb24uanMuaHRtbCNkZWZlclRpY2tzKVxuICogLSBbZGVsYXlNZXRob2RdKHByb3RvX2Z1bmN0aW9uLmpzLmh0bWwjZGVsYXlNZXRob2QpXG4gKiAtIFtkZWZlck1ldGhvZF0ocHJvdG9fZnVuY3Rpb24uanMuaHRtbCNkZWZlck1ldGhvZClcbiAqIC0gW2RlYm91bmNlXShwcm90b19mdW5jdGlvbi5qcy5odG1sI2RlYm91bmNlKVxuICogLSBbdGhyb3R0bGVdKHByb3RvX2Z1bmN0aW9uLmpzLmh0bWwjdGhyb3R0bGUpXG4gKiAtIFtvbmNlXShwcm90b19mdW5jdGlvbi5qcy5odG1sI29uY2UpXG4gKiAtIFt3YWl0Rm9yXShwcm90b19mdW5jdGlvbi5qcy5odG1sI3dhaXRGb3IpXG4qL1xudmFyIGZ1bmN0aW9uTWV0aG9kcyA9IHJlcXVpcmUoJy4vcHJvdG9fZnVuY3Rpb24nKTtcblxuXG4vKipcbiAqIFtfX1N0cmluZyBmdW5jdGlvbnNfX10ocHJvdG9fc3RyaW5nLmpzLmh0bWwpXG4gKlxuICogLSBbZmlyc3RVcHBlckNhc2VdKHByb3RvX3N0cmluZy5qcy5odG1sI2ZpcnN0VXBwZXJDYXNlKVxuICogLSBbZmlyc3RMb3dlckNhc2VdKHByb3RvX3N0cmluZy5qcy5odG1sI2ZpcnN0TG93ZXJDYXNlKVxuICogLSBbdG9SZWdFeHBdKHByb3RvX3N0cmluZy5qcy5odG1sI3RvUmVnRXhwKVxuICogLSBbdG9GdW5jdGlvbl0ocHJvdG9fc3RyaW5nLmpzLmh0bWwjdG9GdW5jdGlvbilcbiAqIC0gW3RvRGF0ZV0ocHJvdG9fc3RyaW5nLmpzLmh0bWwjdG9EYXRlKVxuICogLSBbdG9RdWVyeVN0cmluZ10ocHJvdG9fc3RyaW5nLmpzLmh0bWwjdG9RdWVyeVN0cmluZylcbiAqIC0gW2Zyb21RdWVyeVN0cmluZ10ocHJvdG9fc3RyaW5nLmpzLmh0bWwjZnJvbVF1ZXJ5U3RyaW5nKVxuICogLSBbanNvblBhcnNlXShwcm90b19zdHJpbmcuanMuaHRtbCNqc29uUGFyc2UpXG4gKiAtIFtoYXNoQ29kZV0ocHJvdG9fc3RyaW5nLmpzLmh0bWwjaGFzaENvZGUpXG4gKiAtIFt1blByZWZpeF0ocHJvdG9fc3RyaW5nLmpzLmh0bWwjdW5QcmVmaXgpXG4gKi9cbnZhciBzdHJpbmdNZXRob2RzID0gcmVxdWlyZSgnLi9wcm90b19zdHJpbmcnKTtcblxuXG4vKipcbiAqIFtfX051bWJlciBmdW5jdGlvbnNfX10ocHJvdG9fbnVtYmVyLmpzLmh0bWwpXG4gKlxuICogLSBbaXNOdW1lcmljXShwcm90b19udW1iZXIuanMuaHRtbCNpc051bWVyaWMpXG4gKi9cbnZhciBudW1iZXJNZXRob2RzID0gcmVxdWlyZSgnLi9wcm90b19udW1iZXInKTtcblxuXG4vKipcbiAqIFtfX1V0aWxpdHkgZnVuY3Rpb25zX19dKHByb3RvX3V0aWwuanMuaHRtbClcbiAqXG4gKiAtIFt0aW1lc10ocHJvdG9fdXRpbC5qcy5odG1sI3RpbWVzKVxuICogLSBbcmVwZWF0XShwcm90b191dGlsLmpzLmh0bWwjcmVwZWF0KVxuICogLSBbdGFwXShwcm90b191dGlsLmpzLmh0bWwjdGFwKVxuICogLSBbcmVzdWx0XShwcm90b191dGlsLmpzLmh0bWwjcmVzdWx0KVxuICogLSBbaWRlbnRpdHldKHByb3RvX3V0aWwuanMuaHRtbCNpZGVudGl0eSlcbiAqIC0gW3Byb3BlcnR5XShwcm90b191dGlsLmpzLmh0bWwjcHJvcGVydHkpXG4gKiAtIFtjb21wYXJlUHJvcGVydHldKHByb3RvX3V0aWwuanMuaHRtbCNjb21wYXJlUHJvcGVydHkpXG4gKiAtIFtub29wXShwcm90b191dGlsLmpzLmh0bWwjbm9vcClcbiAqL1xudmFyIHV0aWxNZXRob2RzID0gcmVxdWlyZSgnLi9wcm90b191dGlsJyk7XG5cblxuLyoqXG4gKiBDaGFpbmluZ1xuICogPT09PT09PT1cbiAqXG4gKiBgX2AgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGEgd3JhcHBlZCB2YWx1ZSAob2JqZWN0LCBmdW5jdGlvbiwgYXJyYXksIGV0Yy4pIHRvIGFsbG93IGNoYWluaW5nIG9mIFByb3RvIGZ1bmN0aW9ucy5cbiAqIFRvIHVud3JhcCwgYF9gIG1ldGhvZCBvZiBhIHdyYXBwZWQgdmFsdWUgc2hvdWxkIGJlIHVzZWQuXG4gKiBVc2FnZTpcbiAqIGBgYFxuICogdmFyIGFyciA9IF8oeyAwOiAzLCAxOiA0LCAyOiA1LCBsZW5ndGg6IDN9KVxuICogICAgICAgICAgICAgIC50b0FycmF5KClcbiAqICAgICAgICAgICAgICAucHJlcGVuZEFycmF5KFsxLCAyXSlcbiAqICAgICAgICAgICAgICAuYXBwZW5kQXJyYXkoWzYsIDcsIDhdKVxuICogICAgICAgICAgICAgIC5fKCk7XG4gKiBgYGBcbiAqIEEgd3JhcHBlZCBvYmplY3QgaXMgYW4gaW5zdGFuY2Ugb2YgYF9gIChgUHJvdG9gIGNsYXNzKS5cbiAqXG4gKiBDaGFpbmluZyBpcyBpbXBsZW1lbnRlZCBmb3IgZGV2ZWxvcG1lbnQgY29udmVuaWVuY2UsIGJ1dCBpdCBoYXMgcGVyZm9ybWFuY2Ugb3ZlcmhlYWQsIG5vdCBvbmx5IHRvIHdyYXAgYW5kIHVud3JhcCB2YWx1ZXMgYnV0IGluIGVhY2ggZnVuY3Rpb24gY2FsbC5cbiAqIEFsdGhvdWdoIGFsbCBQcm90byBmdW5jdGlvbnMgYXJlIGltcGxlbWVudGVkIGFzIG1ldGhvZHMgb3BlcmF0aW5nIG9uIHRoaXMgYW5kIHRoZSBvdmVyaGVhZCB0byByZWRlZmluZSB0aGVtIGFzIGZ1bmN0aW9ucyBpcyB2ZXJ5IHNtYWxsLCB0aGUgb3ZlcmhlYWQgdG8gcmVkZWZpbmUgdGhlbSBhcyBtZXRob2RzIG9mIHdyYXBwZWQgdmFsdWUgaXMgc2xpZ2h0bHkgaGlnaGVyIC0gY2hhaW5pbmcgaXMgMTUtMjUlIHNsb3dlciB0aGFuIHVzaW5nIGZ1bmN0aW9ucyAocHJvcGVydGllcyBvZiBfIHRoYXQgdGFrZSB0aGUgZmlyc3QgcGFyYW1ldGVyKS5cbiAqIEluIGNhc2VzIHdoZW4gcGVyZm9ybWFuY2UgaXMgY3JpdGljYWwsIHlvdSBtYXkgd2FudCB0byBhdm9pZCB1c2luZyBjaGFpbmluZy5cbiAqXG4gKiBAcGFyYW0ge0FueX0gc2VsZiBBIHZhbHVlIHRvIGJlIHdyYXBwZWRcbiAqIEByZXR1cm4ge1Byb3RvfVxuICovXG5mdW5jdGlvbiBQcm90byhzZWxmKSB7XG4gICAgLy8gd3JhcCBwYXNzZWQgcGFyYW1ldGVyIGluIF8gb2JqZWN0XG4gICAgdmFyIHdyYXBwZWQgPSBPYmplY3QuY3JlYXRlKFByb3RvLnByb3RvdHlwZSk7XG4gICAgd3JhcHBlZC5zZWxmID0gc2VsZjtcbiAgICByZXR1cm4gd3JhcHBlZDtcbn07XG5cbnZhciBfID0gUHJvdG87XG5cblxuLy8gc3RvcmUgcmF3IG1ldGhvZHMgZnJvbSBkaWZmZXJlbnQgbW9kdWxlcyBpbiBfXyBvYmplY3QgKGRvdWJsZSBcIl9cIilcbnZhciBfXyA9IHt9O1xuXG5vYmplY3RNZXRob2RzLmV4dGVuZC5jYWxsKF9fLCBvYmplY3RNZXRob2RzKTtcbl9fLmV4dGVuZC5jYWxsKF9fLCBwcm90b3R5cGVNZXRob2RzKTtcbl9fLmV4dGVuZC5jYWxsKF9fLCBhcnJheU1ldGhvZHMpO1xuX18uZXh0ZW5kLmNhbGwoX18sIHN0cmluZ01ldGhvZHMpO1xuX18uZXh0ZW5kLmNhbGwoX18sIG51bWJlck1ldGhvZHMpO1xuX18uZXh0ZW5kLmNhbGwoX18sIGZ1bmN0aW9uTWV0aG9kcyk7XG5fXy5leHRlbmQuY2FsbChfXywgdXRpbE1ldGhvZHMpO1xuXG5cbi8vIGFkZCBfXyBhcyBwcm9wZXJ0eSBvZiBQcm90bywgc28gdGhleSBjYW4gYmUgdXNlZCBhcyBtaXhpbnMgaW4gb3RoZXIgY2xhc3Nlc1xuX18uZGVmaW5lUHJvcGVydHkoUHJvdG8sICdfXycsIF9fKTtcblxuXG4vLyBhZGQgXyBtZXRob2QgdG8gdW53cmFwIHdyYXBwZWQgdmFsdWUgKFByb3RvIGluc3RhbmNlKVxuZnVuY3Rpb24gdW53cmFwUHJvdG8oKSB7IHJldHVybiB0aGlzLnNlbGY7IH1cbl9fLmV4dGVuZFByb3RvLmNhbGwoUHJvdG8sIHsgXzogdW53cmFwUHJvdG8gfSk7XG5cbi8vIGFkZCBjb25zdGFudHMgKGZ1bmN0aW9ucyB3aWxsIGJlIG92ZXJ3cml0dGVuKVxuX18uZXh0ZW5kLmNhbGwoUHJvdG8sIG9iamVjdE1ldGhvZHMuX2NvbnN0YW50cyk7XG5cbi8vIGFkZCBmdW5jdGlvbnMgdGhhdCB0YWtlIGZpcnN0IHBhcmFtZXRlciBpbnN0ZWFkIG9mIFwidGhpc1wiIHRvIFByb3RvXG52YXIgcHJvdG9GdW5jcyA9IF9fLm1hcEtleXMuY2FsbChfXywgdXRpbHMubWFrZVByb3RvRnVuY3Rpb24sIHRydWUpO1xuX18uZXh0ZW5kLmNhbGwoUHJvdG8sIHByb3RvRnVuY3MpO1xuXG4vLyBhZGQgUHJvdG8gd3JhcHBlZCB2YWx1ZSBpbnN0YW5jZSBtZXRob2RzIHRvIFByb3RvIHByb3RvdHlwZVxudmFyIHByb3RvSW5zdGFuY2VNZXRob2RzID0gX18ubWFwS2V5cy5jYWxsKF9fLCB1dGlscy5tYWtlUHJvdG9JbnN0YW5jZU1ldGhvZCwgdHJ1ZSk7XG5fXy5leHRlbmRQcm90by5jYWxsKFByb3RvLCBwcm90b0luc3RhbmNlTWV0aG9kcyk7XG5cblxuLyoqXG4gKiBJbiB3aW5kb3dzIGVudmlyb25tZW50LCBhIGdsb2JhbCBgX2AgdmFsdWUgaXMgcHJlc2VydmVkIGluIGBfLnVuZGVyc2NvcmVgXG4gKi9cbmlmICh0eXBlb2Ygd2luZG93ID09ICdvYmplY3QnKSB7XG4gICAgLy8gcHJlc2VydmUgZXhpc3RpbmcgXyBvYmplY3RcbiAgICBpZiAod2luZG93Ll8pXG4gICAgICAgIFByb3RvLnVuZGVyc2NvcmUgPSB3aW5kb3cuX1xuXG4gICAgLy8gZXhwb3NlIGdsb2JhbCBfIGFuZCBQcm90b1xuICAgIHdpbmRvdy5fID0gUHJvdG87XG59XG5cbmlmICh0eXBlb2YgbW9kdWxlID09ICdvYmplY3QnICYmIG1vZHVsZS5leHBvcnRzKVxuICAgIC8vIGV4cG9ydCBmb3Igbm9kZS9icm93c2VyaWZ5XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBQcm90bztcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIF9fID0gcmVxdWlyZSgnLi9wcm90b19vYmplY3QnKVxuICAgICwgdXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzJyk7XG5cblxuLyoqXG4gKiAtIFtmaW5kXSgjZmluZClcbiAqIC0gW2ZpbmRJbmRleF0oI2ZpbmRJbmRleClcbiAqIC0gW2FwcGVuZEFycmF5XSgjYXBwZW5kQXJyYXkpXG4gKiAtIFtwcmVwZW5kQXJyYXldKCNwcmVwZW5kQXJyYXkpXG4gKiAtIFtzcGxpY2VJdGVtXSgjc3BsaWNlSXRlbSlcbiAqIC0gW3RvQXJyYXldKCN0b0FycmF5KVxuICogLSBbb2JqZWN0XSgjb2JqZWN0KVxuICogLSBbbWFwVG9PYmplY3RdKCNtYXBUb09iamVjdClcbiAqIC0gW3VuaXF1ZV0oI3VuaXF1ZSlcbiAqIC0gW2RlZXBGb3JFYWNoXSgjZGVlcEZvckVhY2gpXG4gKlxuICogVGhlc2UgbWV0aG9kcyBjYW4gYmUgW2NoYWluZWRdKHByb3RvLmpzLmh0bWwjUHJvdG8pLlxuICovXG52YXIgYXJyYXlNZXRob2RzID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgLy8gZmluZDogc2VlIGJlbG93XG4gICAgLy8gZmluZEluZGV4OiBzZWUgYmVsb3dcbiAgICBhcHBlbmRBcnJheTogYXBwZW5kQXJyYXksXG4gICAgcHJlcGVuZEFycmF5OiBwcmVwZW5kQXJyYXksXG4gICAgdG9BcnJheTogdG9BcnJheSxcbiAgICBvYmplY3Q6IG9iamVjdCxcbiAgICBtYXBUb09iamVjdDogbWFwVG9PYmplY3QsXG4gICAgdW5pcXVlOiB1bmlxdWUsXG4gICAgZGVlcEZvckVhY2g6IGRlZXBGb3JFYWNoLFxuICAgIHNwbGljZUl0ZW06IHNwbGljZUl0ZW1cbn07XG5cblxuLyoqXG4gKiBGdW5jdGlvbnMgdGhhdCBBcnJheSBbaW1wbGVtZW50cyBuYXRpdmVseV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvcHJvdG90eXBlI01ldGhvZHMpIGFyZSBhbHNvIGluY2x1ZGVkIGZvciBjb252ZW5pZW5jZSAtIHRoZXkgY2FuIGJlIHVzZWQgd2l0aCBhcnJheS1saWtlIG9iamVjdHMgYW5kIGZvciBjaGFpbmluZyAobmF0aXZlIGZ1bmN0aW9ucyBhcmUgYWx3YXlzIGNhbGxlZCkuXG4gKiBUaGVzZSBtZXRob2RzIGNhbiBiZSBbY2hhaW5lZF0ocHJvdG8uanMuaHRtbCNQcm90bykgdG9vLlxuICovXG52YXIgbmF0aXZlQXJyYXlNZXRob2RzTmFtZXMgPSBbICdqb2luJywgJ3BvcCcsICdwdXNoJywgJ2NvbmNhdCcsXG4gICAgJ3JldmVyc2UnLCAnc2hpZnQnLCAndW5zaGlmdCcsICdzbGljZScsICdzcGxpY2UnLFxuICAgICdzb3J0JywgJ2ZpbHRlcicsICdmb3JFYWNoJywgJ3NvbWUnLCAnZXZlcnknLFxuICAgICdtYXAnLCAnaW5kZXhPZicsICdsYXN0SW5kZXhPZicsICdyZWR1Y2UnLCAncmVkdWNlUmlnaHQnXTtcblxudmFyIG5hdGl2ZUFycmF5TWV0aG9kcyA9IG1hcFRvT2JqZWN0LmNhbGwobmF0aXZlQXJyYXlNZXRob2RzTmFtZXMsXG4gICAgICAgIGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybiBBcnJheS5wcm90b3R5cGVbbWV0aG9kTmFtZV07XG4gICAgICAgIH0pO1xuXG5fXy5leHRlbmQuY2FsbChhcnJheU1ldGhvZHMsIG5hdGl2ZUFycmF5TWV0aG9kcyk7XG5cblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiBFUzYgW0FycmF5IF9fZmluZF9fIG1ldGhvZF0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvZmluZCkgKG5hdGl2ZSBtZXRob2QgaXMgdXNlZCBpZiBhdmFpbGFibGUpLlxuICogUmV0dXJucyBhcnJheSBlbGVtZW50IHRoYXQgcGFzc2VzIGNhbGxiYWNrIHRlc3QuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gc2VsZiBhcnJheSB0byBzZWFyY2ggaW5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIHNob3VsZCByZXR1cm4gYHRydWVgIGZvciBpdGVtIHRvIHBhc3MgdGhlIHRlc3QsIHBhc3NlZCBgdmFsdWVgLCBgaW5kZXhgIGFuZCBgc2VsZmAgYXMgcGFyYW1ldGVyc1xuICogQHBhcmFtIHtPYmplY3R9IHRoaXNBcmcgb3B0aW9uYWwgY29udGV4dCAoYHRoaXNgKSBvZiBjYWxsYmFjayBjYWxsXG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmFycmF5TWV0aG9kcy5maW5kID0gQXJyYXkucHJvdG90eXBlLmZpbmRcbiAgICB8fCB1dGlscy5tYWtlRmluZE1ldGhvZChhcnJheU1ldGhvZHMuZm9yRWFjaCwgJ3ZhbHVlJyk7XG5cblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiBFUzYgW0FycmF5IF9fZmluZEluZGV4X18gbWV0aG9kXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9maW5kSW5kZXgpIChuYXRpdmUgbWV0aG9kIGlzIHVzZWQgaWYgYXZhaWxhYmxlKS5cbiAqIFJldHVybnMgdGhlIGluZGV4IG9mIGFycmF5IGVsZW1lbnQgdGhhdCBwYXNzZXMgY2FsbGJhY2sgdGVzdC4gUmV0dXJucyBgLTFgIGlmIG5vdCBmb3VuZC5cbiAqXG4gKiBAcGFyYW0ge0FycmF5fSBzZWxmIGFycmF5IHRvIHNlYXJjaCBpblxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgc2hvdWxkIHJldHVybiBgdHJ1ZWAgZm9yIGl0ZW0gdG8gcGFzcyB0aGUgdGVzdCwgcGFzc2VkIGB2YWx1ZWAsIGBpbmRleGAgYW5kIGBzZWxmYCBhcyBwYXJhbWV0ZXJzXG4gKiBAcGFyYW0ge09iamVjdH0gdGhpc0FyZyBvcHRpb25hbCBjb250ZXh0IChgdGhpc2ApIG9mIGNhbGxiYWNrIGNhbGxcbiAqIEByZXR1cm4ge0ludGVnZXJ9XG4gKi9cbmFycmF5TWV0aG9kcy5maW5kSW5kZXggPSBBcnJheS5wcm90b3R5cGUuZmluZEluZGV4XG4gICAgfHwgdXRpbHMubWFrZUZpbmRNZXRob2QoYXJyYXlNZXRob2RzLmZvckVhY2gsICdpbmRleCcpO1xuXG5cbi8qKlxuICogQXBwZW5kcyBgYXJyYXlUb0FwcGVuZGAgdG8gdGhlIGVuZCBvZiBhcnJheSBgc2VsZmAgaW4gcGxhY2UgKGNhbiBiZSBhbiBpbnN0YW5jZSBvZiBBcnJheSBvciBhcnJheS1saWtlIG9iamVjdCkuXG4gKiBDaGFuZ2VzIHRoZSB2YWx1ZSBvZiBgc2VsZmAgKGl0IHVzZXMgYEFycmF5LnByb3RvdHlwZS5zcGxpY2VgKSBhbmQgcmV0dXJucyBgc2VsZmAuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gc2VsZiBBbiBhcnJheSB0aGF0IHdpbGwgYmUgbW9kaWZpZWRcbiAqIEBwYXJhbSB7QXJyYXl8QXJyYXktbGlrZX0gYXJyYXlUb0FwcGVuZCBBbiBhcnJheSB0aGF0IHdpbGwgYmUgYXBwZW5kZWRcbiAqIEByZXR1cm4ge0FycmF5fVxuICovXG5mdW5jdGlvbiBhcHBlbmRBcnJheShhcnJheVRvQXBwZW5kKSB7XG4gICAgaWYgKCEgYXJyYXlUb0FwcGVuZC5sZW5ndGgpIHJldHVybiB0aGlzO1xuICAgIGlmICghIEFycmF5LmlzQXJyYXkoYXJyYXlUb0FwcGVuZCkpXG4gICAgICAgIGFycmF5VG9BcHBlbmQgPSB0b0FycmF5LmNhbGwoYXJyYXlUb0FwcGVuZCk7XG4gICAgXG4gICAgdmFyIGFyZ3MgPSBbdGhpcy5sZW5ndGgsIDBdLmNvbmNhdChhcnJheVRvQXBwZW5kKTtcbiAgICBhcnJheU1ldGhvZHMuc3BsaWNlLmFwcGx5KHRoaXMsIGFyZ3MpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBQcmVwZW5kcyBgYXJyYXlUb1ByZXBlbmRgIHRvIHRoZSBiZWdpbm5pZyBvZiBhcnJheSBgc2VsZmAgaW4gcGxhY2UgKGNhbiBiZSBhbiBpbnN0YW5jZSBvZiBBcnJheSBvciBhcnJheS1saWtlIG9iamVjdCkuXG4gKiBDaGFuZ2VzIHRoZSB2YWx1ZSBvZiBgc2VsZmAgKGl0IHVzZXMgYEFycmF5LnByb3RvdHlwZS5zcGxpY2VgKSBhbmQgcmV0dXJucyBgc2VsZmAuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gc2VsZiBBbiBhcnJheSB0aGF0IHdpbGwgYmUgbW9kaWZpZWRcbiAqIEBwYXJhbSB7QXJyYXl8QXJyYXktbGlrZX0gYXJyYXlUb0FwcGVuZCBBbiBhcnJheSB0aGF0IHdpbGwgYmUgcHJlcGVuZGVkXG4gKiBAcmV0dXJuIHtBcnJheX1cbiAqL1xuZnVuY3Rpb24gcHJlcGVuZEFycmF5KGFycmF5VG9QcmVwZW5kKSB7XG4gICAgaWYgKCEgYXJyYXlUb1ByZXBlbmQubGVuZ3RoKSByZXR1cm4gdGhpcztcbiAgICBpZiAoISBBcnJheS5pc0FycmF5KGFycmF5VG9QcmVwZW5kKSlcbiAgICAgICAgYXJyYXlUb1ByZXBlbmQgPSB0b0FycmF5LmNhbGwoYXJyYXlUb1ByZXBlbmQpO1xuXG4gICAgdmFyIGFyZ3MgPSBbMCwgMF0uY29uY2F0KGFycmF5VG9QcmVwZW5kKTtcbiAgICBhcnJheU1ldGhvZHMuc3BsaWNlLmFwcGx5KHRoaXMsIGFyZ3MpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBSZW1vdmVzIGl0ZW0gZnJvbSBhcnJheSB0aGF0IGlzIGZvdW5kIHVzaW5nIGluZGV4T2YgKGkuZS4gJz09PScpXG4gKiBNb2RpZmllcyBvcmlnaW5hbCBhcnJheSBhbmQgcmV0dXJucyB0aGUgcmVmZXJlbmNlIHRvIGl0LlxuICogXG4gKiBAcGFyYW0ge0FycmF5fSBzZWxmIEFuIGFycmF5IHRoYXQgd2lsbCBiZSBtb2RpZmllZFxuICogQHBhcmFtICB7QW55fSBpdGVtIGl0ZW0gdG8gYmUgcmVtb3ZlZFxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIHNwbGljZUl0ZW0oaXRlbSkge1xuICAgIHZhciBpbmRleCA9IHRoaXMuaW5kZXhPZihpdGVtKTtcbiAgICBpZiAoaW5kZXggPj0gMCkgdGhpcy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBuZXcgYXJyYXkgY3JlYXRlZCBmcm9tIGFycmF5LWxpa2Ugb2JqZWN0IChlLmcuLCBgYXJndW1lbnRzYCBwc2V1ZG8tYXJyYXkpLlxuICpcbiAqIEBwYXJhbSB7QXJyYXktbGlrZX0gc2VsZiBPYmplY3Qgd2l0aCBudW1lcmljIHByb3BlcnR5IGxlbmd0aFxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIHRvQXJyYXkoKSB7XG4gICAgcmV0dXJuIGFycmF5TWV0aG9kcy5zbGljZS5jYWxsKHRoaXMpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBhbiBvYmplY3QgY3JlYXRlZCBmcm9tIHRoZSBhcnJheSBvZiBga2V5c2AgYW5kIG9wdGlvbmFsIGFycmF5IG9mIGB2YWx1ZXNgLlxuICpcbiAqIEBwYXJhbSB7QXJyYXl9IHNlbGYgQXJyYXkgb2Yga2V5c1xuICogQHBhcmFtIHtBcnJheXxhbnl9IHZhbHVlcyBPcHRpb25hbCBhcnJheSBvZiB2YWx1ZXMgb3IgdGhlIHZhbHVlIHRvIGJlIGFzc2lnbmVkIHRvIGVhY2ggcHJvcGVydHkuXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIG9iamVjdCh2YWx1ZXMpIHtcbiAgICB2YXIgb2JqID0ge31cbiAgICAgICAgLCB2YWx1ZXNJc0FycmF5ID0gQXJyYXkuaXNBcnJheSh2YWx1ZXMpO1xuICAgIGFycmF5TWV0aG9kcy5mb3JFYWNoLmNhbGwodGhpcywgZnVuY3Rpb24oa2V5LCBpbmRleCkge1xuICAgICAgICBvYmpba2V5XSA9IHZhbHVlc0lzQXJyYXkgPyB2YWx1ZXNbaW5kZXhdIDogdmFsdWVzO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIG9iajtcbn1cblxuXG4vKipcbiAqIE1hcHMgYXJyYXkgdG8gb2JqZWN0LlxuICogQXJyYXkgZWxlbWVudHMgYmVjb21lIGtleXMsIHZhbHVlIGFyZSB0YWtlbiBmcm9tIGBjYWxsYmFja2AuXG4gKiBcbiAqIEBwYXJhbSB7QXJyYXl9IHNlbGYgQW4gYXJyYXkgd2hpY2ggdmFsdWVzIHdpbGwgYmVjb21lIGtleXMgb2YgdGhlIHJlc3VsdFxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGJhY2sgaXMgcGFzc2VkIGB2YWx1ZWAsIGBpbmRleGAgYW5kIGBzZWxmYCBhbmQgc2hvdWxkIHJldHVybiB2YWx1ZSB0aGF0IHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIHJlc3VsdC5cbiAqIEBwYXJhbSB7T2JqZWN0fSB0aGlzQXJnIEFuIG9wdGlvbmFsIGNvbnRleHQgb2YgaXRlcmF0aW9uICh0aGUgdmFsdWVvZiBgdGhpc2ApLCB3aWxsIGJlIHVuZGVmaW5lZCBpZiB0aGlzIHBhcmFtZXRlciBpcyBub3QgcGFzc2VkLlxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBtYXBUb09iamVjdChjYWxsYmFjaywgdGhpc0FyZykge1xuICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICBBcnJheS5wcm90b3R5cGUuZm9yRWFjaC5jYWxsKHRoaXMsIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCkge1xuICAgICAgICByZXN1bHRbdmFsdWVdID0gY2FsbGJhY2suY2FsbCh0aGlzQXJnLCB2YWx1ZSwgaW5kZXgsIHRoaXMpO1xuICAgIH0sIHRoaXMpO1xuICAgIHJldHVybiByZXN1bHQ7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGFycmF5IHdpdGhvdXQgZHVwbGljYXRlcy4gRG9lcyBub3QgbW9kaWZ5IG9yaWdpbmFsIGFycmF5LlxuICpcbiAqIEBwYXJhbSB7QXJyYXl9IHNlbGYgb3JpZ2luYWwgYXJyYXlcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIGNvbXBhcmlzb24gZnVuY3Rpb24sIHNob3VsZCByZXR1cm4gdHJ1ZSBmb3IgZXF1YWwgaXRlbXMsIFwiPT09XCIgaXMgdXNlZCBpZiBub3QgcGFzc2VkLlxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIHVuaXF1ZShjYWxsYmFjaykge1xuICAgIHZhciBmaWx0ZXJlZCA9IFtdO1xuICAgIGlmICghIGNhbGxiYWNrKVxuICAgICAgICBpdGVtSW5kZXggPSBpdGVtSW5kZXhPZjtcblxuICAgIHRoaXMuZm9yRWFjaChmdW5jdGlvbihpdGVtKSB7XG4gICAgICAgIHZhciBpbmRleCA9IGl0ZW1JbmRleChpdGVtKTtcbiAgICAgICAgaWYgKGluZGV4ID09IC0xKVxuICAgICAgICAgICAgZmlsdGVyZWQucHVzaChpdGVtKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBmaWx0ZXJlZDtcblxuXG4gICAgZnVuY3Rpb24gaXRlbUluZGV4KGl0ZW0pIHtcbiAgICAgICAgcmV0dXJuIGFycmF5TWV0aG9kcy5maW5kSW5kZXguY2FsbChmaWx0ZXJlZCwgZnVuY3Rpb24oaXQpIHtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhpdGVtLCBpdCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGl0ZW1JbmRleE9mKGl0ZW0pIHtcbiAgICAgICAgcmV0dXJuIGZpbHRlcmVkLmluZGV4T2YoaXRlbSk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogSXRlcmF0ZXMgYXJyYXkgYW5kIGVsZW1lbnRzIHRoYXQgYXJlIGFycmF5cyBjYWxsaW5nIGNhbGxiYWNrIHdpdGggZWFjaCBlbGVtZW50IHRoYXQgaXMgbm90IGFuIGFycmF5LiBDYW4gYmUgdXNlZCB0byBpdGVyYXRlIG92ZXIgYXJndW1lbnRzIGxpc3QgdG8gYXZvaWQgY2hlY2tpbmcgd2hldGhlciBhcnJheSBvciBsaXN0IG9mIHBhcmFtZXRlcnMgaXMgcGFzc2VkLlxuICpcbiAqIEBwYXJhbSB7QXJyYXl8QXJyYXktbGlrZX0gc2VsZiBhcnJheSBvZiBlbGVtZW50cyBhbmQgYXJyYXlzdG8gaXRlcmF0ZS5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIGNhbGxlZCBmb3IgZWFjaCBpdGVtIHRoYXQgaXMgbm90IGFuIGFycmF5LiBDYWxsYmFjayBpcyBwYXNzZWQgaXRlbSwgaW5kZXggYW5kIG9yaWdpbmFsIGFycmF5IGFzIHBhcmFtZXRlcnMuXG4gKiBAcGFyYW0ge0FueX0gdGhpc0FyZyBvcHRpb25hbCBjYWxsYmFjayBlbnZvY2F0aW9uIGNvbnRleHRcbiAqL1xuZnVuY3Rpb24gZGVlcEZvckVhY2goY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICB2YXIgaW5kZXggPSAwLCBhcnIgPSB0aGlzO1xuICAgIF9kZWVwRm9yRWFjaC5jYWxsKHRoaXMpO1xuXG4gICAgZnVuY3Rpb24gX2RlZXBGb3JFYWNoKCkge1xuICAgICAgICBhcnJheU1ldGhvZHMuZm9yRWFjaC5jYWxsKHRoaXMsIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpXG4gICAgICAgICAgICAgICAgX2RlZXBGb3JFYWNoLmNhbGwodmFsdWUpO1xuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwodGhpc0FyZywgdmFsdWUsIGluZGV4KyssIGFycik7XG4gICAgICAgIH0pO1xuICAgIH1cbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgbWFrZVByb3RvRnVuY3Rpb24gPSByZXF1aXJlKCcuL3V0aWxzJykubWFrZVByb3RvRnVuY3Rpb25cbiAgICAsIHJlcGVhdCA9IHJlcXVpcmUoJy4vcHJvdG9fdXRpbCcpLnJlcGVhdDtcblxuXG4vKipcbiAqIC0gW21ha2VGdW5jdGlvbl0oI21ha2VGdW5jdGlvbilcbiAqIC0gW3BhcnRpYWxdKCNwYXJ0aWFsKVxuICogLSBbcGFydGlhbFJpZ2h0XSgjcGFydGlhbFJpZ2h0KVxuICogLSBbbWVtb2l6ZV0oI21lbW9pemUpXG4gKiAtIFtkZWxheV0oI2RlbGF5KVxuICogLSBbZGVmZXJdKCNkZWZlcilcbiAqIC0gW2RlbGF5ZWRdKCNkZWxheWVkKVxuICogLSBbZGVmZXJyZWRdKCNkZWZlcnJlZClcbiAqIC0gW2RlZmVyVGlja3NdKCNkZWZlclRpY2tzKVxuICogLSBbZGVsYXlNZXRob2RdKCNkZWxheU1ldGhvZClcbiAqIC0gW2RlZmVyTWV0aG9kXSgjZGVmZXJNZXRob2QpXG4gKiAtIFtkZWJvdW5jZV0oI2RlYm91bmNlKVxuICogLSBbdGhyb3R0bGVdKCN0aHJvdHRsZSlcbiAqIC0gW29uY2VdKCNvbmNlKVxuICogLSBbd2FpdEZvcl0oI3dhaXRGb3IpXG4gKiAtIFtub3RdKCNub3QpXG4gKlxuICogVGhlc2UgbWV0aG9kcyBjYW4gYmUgW2NoYWluZWRdKHByb3RvLmpzLmh0bWwjUHJvdG8pXG4gKi9cbnZhciBmdW5jdGlvbk1ldGhvZHMgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBtYWtlRnVuY3Rpb246IG1ha2VGdW5jdGlvbixcbiAgICBwYXJ0aWFsOiBwYXJ0aWFsLFxuICAgIHBhcnRpYWxSaWdodDogcGFydGlhbFJpZ2h0LFxuICAgIG1lbW9pemU6IG1lbW9pemUsXG4gICAgZGVsYXk6IGRlbGF5LFxuICAgIGRlZmVyOiBkZWZlcixcbiAgICBkZWxheWVkOiBkZWxheWVkLFxuICAgIGRlZmVycmVkOiBkZWZlcnJlZCxcbiAgICBkZWZlclRpY2tzOiBkZWZlclRpY2tzLFxuICAgIGRlbGF5TWV0aG9kOiBkZWxheU1ldGhvZCxcbiAgICBkZWZlck1ldGhvZDogZGVmZXJNZXRob2QsXG4gICAgZGVib3VuY2U6IGRlYm91bmNlLFxuICAgIHRocm90dGxlOiB0aHJvdHRsZSxcbiAgICBvbmNlOiBvbmNlLFxuICAgIHdhaXRGb3I6IHdhaXRGb3IsXG4gICAgbm90OiBub3Rcbn07XG5cblxudmFyIHNsaWNlID0gQXJyYXkucHJvdG90eXBlLnNsaWNlO1xuXG5cbi8qKlxuICogU2ltaWxhcmx5IHRvIEZ1bmN0aW9uIGNvbnN0cnVjdG9yIGNyZWF0ZXMgYSBmdW5jdGlvbiBmcm9tIGNvZGUuXG4gKiBVbmxpa2UgRnVuY3Rpb24gY29uc3RydWN0b3IsIHRoZSBmaXJzdCBhcmd1bWVudCBpcyBhIGZ1bmN0aW9uIG5hbWVcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBuZXcgZnVuY3Rpb24gbmFtZVxuICogQHBhcmFtIHtTdHJpbmd9IGFyZzEsIGFyZzIsIC4uLiB0aGUgbmFtZXMgb2YgZnVuY3Rpb24gcGFyYW1ldGVyc1xuICogQHBhcmFtIHtTdHJpbmd9IGZ1bmNCb2R5IGZ1bmN0aW9uIGJvZHlcbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBtYWtlRnVuY3Rpb24oYXJnMSwgYXJnMiwgZnVuY0JvZHkpIHtcbiAgICB2YXIgbmFtZSA9IHRoaXNcbiAgICAgICAgLCBjb3VudCA9IGFyZ3VtZW50cy5sZW5ndGggLSAxXG4gICAgICAgICwgZnVuY0JvZHkgPSBhcmd1bWVudHNbY291bnRdXG4gICAgICAgICwgZnVuY1xuICAgICAgICAsIGNvZGUgPSAnJztcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvdW50OyBpKyspXG4gICAgICAgIGNvZGUgKz0gJywgJyArIGFyZ3VtZW50c1tpXTtcbiAgICBjb2RlID0gWydmdW5jID0gZnVuY3Rpb24gJywgbmFtZSwgJygnLCBjb2RlLnNsaWNlKDIpLCAnKSB7XFxuJ1xuICAgICAgICAgICAgICAgICwgZnVuY0JvZHksICdcXG59J10uam9pbignJyk7XG4gICAgZXZhbChjb2RlKTtcbiAgICByZXR1cm4gZnVuYztcbn1cblxuXG4vKipcbiAqIENyZWF0ZXMgYSBmdW5jdGlvbiBhcyBhIHJlc3VsdCBvZiBwYXJ0aWFsIGZ1bmN0aW9uIGFwcGxpY2F0aW9uIHdpdGggdGhlIHBhc3NlZCBwYXJhbWV0ZXJzLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgRnVuY3Rpb24gdG8gYmUgYXBwbGllZFxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgQXJndW1lbnRzIGFmdGVyIHNlbGYgd2lsbCBiZSBwcmVwZW5kZWQgdG8gdGhlIG9yaWdpbmFsIGZ1bmN0aW9uIGNhbGwgd2hlbiB0aGUgcGFydGlhbCBmdW5jdGlvbiBpcyBjYWxsZWQuXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gcGFydGlhbCgpIHsgLy8gLCAuLi4gYXJndW1lbnRzXG4gICAgdmFyIGZ1bmMgPSB0aGlzO1xuICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIGZ1bmMuYXBwbHkodGhpcywgYXJncy5jb25jYXQoc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgfTtcbn1cblxuXG4vKipcbiAqIENyZWF0ZXMgYSBmdW5jdGlvbiBhcyBhIHJlc3VsdCBvZiBwYXJ0aWFsIGZ1bmN0aW9uIGFwcGxpY2F0aW9uIHdpdGggdGhlIHBhc3NlZCBwYXJhbWV0ZXJzLCBidXQgcGFyYW1ldGVycyBhcmUgYXBwZW5kZWQgb24gdGhlIHJpZ2h0LlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgRnVuY3Rpb24gdG8gYmUgYXBwbGllZFxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgQXJndW1lbnRzIGFmdGVyIHNlbGYgd2lsbCBiZSBhcHBlbmRlZCBvbiB0aGUgcmlnaHQgdG8gdGhlIG9yaWdpbmFsIGZ1bmN0aW9uIGNhbGwgd2hlbiB0aGUgcGFydGlhbCBmdW5jdGlvbiBpcyBjYWxsZWQuXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gcGFydGlhbFJpZ2h0KCkgeyAvLyAsIC4uLiBhcmd1bWVudHNcbiAgICB2YXIgZnVuYyA9IHRoaXM7XG4gICAgdmFyIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gZnVuYy5hcHBseSh0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cykuY29uY2F0KGFyZ3MpKTtcbiAgICB9O1xufVxuXG5cbi8qKlxuICogQ3JlYXRlcyBhIG1lbW9pemVkIHZlcnNpb24gb2YgdGhlIGZ1bmN0aW9uIHVzaW5nIHN1cHBsaWVkIGhhc2ggZnVuY3Rpb24gYXMga2V5LiBJZiB0aGUgaGFzaCBpcyBub3Qgc3VwcGxpZWQsIHVzZXMgaXRzIGZpcnN0IHBhcmFtZXRlciBhcyB0aGUgaGFzaC5cbiAqIFxuICogQHBhcmFtIHtGdW5jdGlvbn0gc2VsZiBmdW5jdGlvbiB0byBiZSBtZW1vaXplZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gaGFzaEZ1bmMgb3B0aW9uYWwgaGFzaCBmdW5jdGlvbiB0aGF0IGlzIHBhc3NlZCBhbGwgZnVuY3Rpb24gYXJndW1lbnRzIGFuZCBzaG91bGQgcmV0dXJuIGNhY2hlIGtleS5cbiAqIEBwYXJhbSB7SW50ZWdlcn0gbGltaXQgb3B0aW9uYWwgbWF4aW11bSBudW1iZXIgb2YgcmVzdWx0cyB0byBiZSBzdG9yZWQgaW4gdGhlIGNhY2hlLiAxMDAwIGJ5IGRlZmF1bHQuXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn0gbWVtb2l6ZWQgZnVuY3Rpb25cbiAqL1xuZnVuY3Rpb24gbWVtb2l6ZShoYXNoRnVuYywgbGltaXQpIHtcbiAgICB2YXIgZnVuYyA9IHRoaXM7XG4gICAgdmFyIGNhY2hlID0ge30sIGtleXNMaXN0ID0gW107XG4gICAgbGltaXQgPSBsaW1pdCB8fCAxMDAwO1xuXG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIga2V5ID0gaGFzaEZ1bmMgPyBoYXNoRnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpIDogYXJndW1lbnRzWzBdO1xuICAgICAgICBpZiAoY2FjaGUuaGFzT3duUHJvcGVydHkoa2V5KSlcbiAgICAgICAgICAgIHJldHVybiBjYWNoZVtrZXldO1xuXG4gICAgICAgIHZhciByZXN1bHQgPSBjYWNoZVtrZXldID0gZnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICBrZXlzTGlzdC5wdXNoKGtleSk7XG5cbiAgICAgICAgaWYgKGtleXNMaXN0Lmxlbmd0aCA+IGxpbWl0KVxuICAgICAgICAgICAgZGVsZXRlIGNhY2hlW2tleXNMaXN0LnNoaWZ0KCldO1xuXG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbn1cblxuXG4vKipcbiAqIERlbGF5cyBmdW5jdGlvbiBleGVjdXRpb24gYnkgYSBnaXZlbiB0aW1lIGluIG1pbGxpc2Vjb25kcy5cbiAqIFRoZSBjb250ZXh0IGluIGZ1bmN0aW9uIHdoZW4gaXQgaXMgZXhlY3V0ZWQgaXMgc2V0IHRvIGBudWxsYC5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzZWxmIGZ1bmN0aW9uIHRoYXQgZXhlY3V0aW9uIGhhcyB0byBiZSBkZWxheWVkXG4gKiBAcGFyYW0ge051bWJlcn0gd2FpdCBhcHByb3hpbWF0ZSBkYWxheSB0aW1lIGluIG1pbGxpc2Vjb25kc1xuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgb3B0aW9uYWwgYXJndW1lbnRzIHRoYXQgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uXG4gKi9cbmZ1bmN0aW9uIGRlbGF5KHdhaXQpIHsgLy8gLCBhcmd1bWVudHNcbiAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICByZXR1cm4gX2RlbGF5KHRoaXMsIHdhaXQsIGFyZ3MpO1xufVxuIFxuXG4vKipcbiAqIERlZmVycyBmdW5jdGlvbiBleGVjdXRpb24gKGV4ZWN1dGVzIGFzIHNvb24gYXMgZXhlY3V0aW9uIGxvb3AgYmVjb21lcyBmcmVlKVxuICogVGhlIGNvbnRleHQgaW4gZnVuY3Rpb24gd2hlbiBpdCBpcyBleGVjdXRlZCBpcyBzZXQgdG8gYG51bGxgLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgZnVuY3Rpb24gdGhhdCBleGVjdXRpb24gaGFzIHRvIGJlIGRlbGF5ZWRcbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIG9wdGlvbmFsIGFyZ3VtZW50cyB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvblxuICovXG5mdW5jdGlvbiBkZWZlcigpIHsgLy8gLCBhcmd1bWVudHNcbiAgICByZXR1cm4gX2RlbGF5KHRoaXMsIDEsIGFyZ3VtZW50cyk7XG59XG5cbmZ1bmN0aW9uIF9kZWxheShmdW5jLCB3YWl0LCBhcmdzLCBjb250ZXh0KSB7XG4gICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuYy5hcHBseS5iaW5kKGZ1bmMsIGNvbnRleHQgfHwgbnVsbCwgYXJncyksIHdhaXQpO1xufVxuXG4vKipcbiAqIFNhbWUgYXMgXy5kZWZlciwgdGFrZXMgZmlyc3QgYXJndW1lbnQgYXMgdGhlIGZ1bmN0aW9uIHRvIGJlIGRlZmVycmVkXG4gKi9cbnZhciBkZWZlckZ1bmMgPSBtYWtlUHJvdG9GdW5jdGlvbihkZWZlcik7XG5cbi8qKlxuICogRGVmZXJzIGZ1bmN0aW9uIGV4ZWN1dGlvbiBmb3IgYHRpbWVzYCB0aWNrcyAoZXhlY3V0ZXMgYWZ0ZXIgZXhlY3V0aW9uIGxvb3AgYmVjb21lcyBmcmVlIGB0aW1lc2AgdGltZXMpXG4gKiBUaGUgY29udGV4dCBpbiBmdW5jdGlvbiB3aGVuIGl0IGlzIGV4ZWN1dGVkIGlzIHNldCB0byBgbnVsbGAuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gc2VsZiBmdW5jdGlvbiB0aGF0IGV4ZWN1dGlvbiBoYXMgdG8gYmUgZGVsYXllZFxuICogQHBhcmFtIHtJbnRlZ2VyfSB0aWNrcyBudW1iZXIgb2YgdGltZXMgdG8gZGVmZXIgZXhlY3V0aW9uXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBvcHRpb25hbCBhcmd1bWVudHMgdGhhdCB3aWxsIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb25cbiAqL1xuZnVuY3Rpb24gZGVmZXJUaWNrcyh0aWNrcykgeyAvLyAsIGFyZ3VtZW50c1xuICAgIGlmICh0aWNrcyA8IDIpIHJldHVybiBkZWZlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHZhciBhcmdzID0gcmVwZWF0LmNhbGwoZGVmZXJGdW5jLCB0aWNrcyAtIDEpO1xuICAgIGFyZ3MgPSBhcmdzLmNvbmNhdCh0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cywgMSkpOyBcbiAgICByZXR1cm4gZGVmZXJGdW5jLmFwcGx5KG51bGwsIGFyZ3MpO1xufVxuXG5cbi8qKlxuICogV29ya3MgbGlrZSBfLmRlbGF5IGJ1dCBhbGxvd3MgdG8gZGVmZXIgbWV0aG9kIGNhbGwgb2YgYHNlbGZgIHdoaWNoIHdpbGwgYmUgdGhlIGZpcnN0IF8uZGVsYXlNZXRob2QgcGFyYW1ldGVyXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgb2JqZWN0IHRvIGRlbGF5IG1ldGhvZCBjYWxsIG9mXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufFN0cmluZ30gZnVuY09yTWV0aG9kTmFtZSBmdW5jdGlvbiBvciBuYW1lIG9mIG1ldGhvZFxuICogQHBhcmFtIHtOdW1iZXJ9IHdhaXQgYXBwcm94aW1hdGUgZGFsYXkgdGltZSBpbiBtaWxsaXNlY29uZHNcbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIGFyZ3VtZW50cyB0byBwYXNzIHRvIG1ldGhvZFxuICovXG5mdW5jdGlvbiBkZWxheU1ldGhvZChmdW5jT3JNZXRob2ROYW1lLCB3YWl0KSB7IC8vICwgLi4uIGFyZ3VtZW50c1xuICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgIHJldHVybiBfZGVsYXlNZXRob2QodGhpcywgZnVuY09yTWV0aG9kTmFtZSwgd2FpdCwgYXJncyk7XG59XG5cblxuLyoqXG4gKiBXb3JrcyBsaWtlIF8uZGVmZXIgYnV0IGFsbG93cyB0byBkZWZlciBtZXRob2QgY2FsbCBvZiBgc2VsZmAgd2hpY2ggd2lsbCBiZSB0aGUgZmlyc3QgXy5kZWZlck1ldGhvZCBwYXJhbWV0ZXJcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBvYmplY3QgdG8gZGVmZXIgbWV0aG9kIGNhbGwgb2ZcbiAqIEBwYXJhbSB7RnVuY3Rpb258U3RyaW5nfSBmdW5jT3JNZXRob2ROYW1lIGZ1bmN0aW9uIG9yIG5hbWUgb2YgbWV0aG9kXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBhcmd1bWVudHMgdG8gcGFzcyB0byBtZXRob2RcbiAqL1xuZnVuY3Rpb24gZGVmZXJNZXRob2QoZnVuY09yTWV0aG9kTmFtZSkgeyAvLyAsIC4uLiBhcmd1bWVudHNcbiAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICByZXR1cm4gX2RlbGF5TWV0aG9kKHRoaXMsIGZ1bmNPck1ldGhvZE5hbWUsIDEsIGFyZ3MpO1xufVxuXG5mdW5jdGlvbiBfZGVsYXlNZXRob2Qob2JqZWN0LCBmdW5jT3JNZXRob2ROYW1lLCB3YWl0LCBhcmdzKSB7XG4gICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBmdW5jID0gdHlwZW9mIGZ1bmNPck1ldGhvZE5hbWUgPT0gJ3N0cmluZydcbiAgICAgICAgICAgICAgICAgICAgPyBvYmplY3RbZnVuY09yTWV0aG9kTmFtZV1cbiAgICAgICAgICAgICAgICAgICAgOiBmdW5jT3JNZXRob2ROYW1lO1xuICAgICAgICBmdW5jLmFwcGx5KG9iamVjdCwgYXJncyk7XG4gICAgfSwgd2FpdCk7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGZ1bmN0aW9uIHRoYXQgd2lsbCBleGVjdXRlIHRoZSBvcmlnaW5hbCBmdW5jdGlvbiBgd2FpdGAgbXMgYWZ0ZXIgaXQgaGFzIGJlZW4gY2FsbGVkXG4gKiBUaGUgY29udGV4dCBpbiBmdW5jdGlvbiB3aGVuIGl0IGlzIGV4ZWN1dGVkIGlzIHNldCB0byBgbnVsbGAuXG4gKiBBcmd1bWVudHMgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbiBhcmUgYXBwZW5kZWQgdG8gdGhlIGFyZ3VtZW50cyBwYXNzZWQgdG8gZGVsYXllZC5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzZWxmIGZ1bmN0aW9uIHdoaWNoIGV4ZWN1dGlvbiBoYXMgdG8gYmUgZGVmZXJyZWRcbiAqIEBwYXJhbSB7TnVtYmVyfSB3YWl0IGFwcHJveGltYXRlIGRhbGF5IHRpbWUgaW4gbWlsbGlzZWNvbmRzXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBvcHRpb25hbCBhcmd1bWVudHMgdGhhdCB3aWxsIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb25cbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBkZWxheWVkKHdhaXQpIHsgLy8sIC4uLiBhcmd1bWVudHNcbiAgICB2YXIgZnVuYyA9IHRoaXNcbiAgICAgICAgLCBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHJldHVybiBmdW5jdGlvbigpIHsgLy8gLi4uIGFyZ3VtZW50c1xuICAgICAgICB2YXIgcGFzc0FyZ3MgPSBhcmdzLmNvbmNhdChzbGljZS5jYWxsKGFyZ3VtZW50cykpO1xuICAgICAgICByZXR1cm4gX2RlbGF5KGZ1bmMsIHdhaXQsIHBhc3NBcmdzLCB0aGlzKTtcbiAgICB9O1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBmdW5jdGlvbiB0aGF0IHdpbGwgZXhlY3V0ZSB0aGUgb3JpZ2luYWwgZnVuY3Rpb24gb24gdGhlIG5leHQgdGljayBvbmNlIGl0IGhhcyBiZWVuIGNhbGxlZFxuICogVGhlIGNvbnRleHQgaW4gZnVuY3Rpb24gd2hlbiBpdCBpcyBleGVjdXRlZCBpcyBzZXQgdG8gYG51bGxgLlxuICogQXJndW1lbnRzIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24gYXJlIGFwcGVuZGVkIHRvIHRoZSBhcmd1bWVudHMgcGFzc2VkIHRvIGRlZmVycmVkLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgZnVuY3Rpb24gd2hpY2ggZXhlY3V0aW9uIGhhcyB0byBiZSBkZWZlcnJlZFxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgb3B0aW9uYWwgYXJndW1lbnRzIHRoYXQgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gZGVmZXJyZWQoKSB7IC8vLCAuLi4gYXJndW1lbnRzXG4gICAgdmFyIGZ1bmMgPSB0aGlzXG4gICAgICAgICwgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7IC8vIC4uLiBhcmd1bWVudHNcbiAgICAgICAgdmFyIHBhc3NBcmdzID0gYXJncy5jb25jYXQoc2xpY2UuY2FsbChhcmd1bWVudHMpKTtcbiAgICAgICAgcmV0dXJuIF9kZWxheShmdW5jLCAxLCBwYXNzQXJncywgdGhpcyk7XG4gICAgfTtcbn1cblxuXG4vKipcbiAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0IHdpbGwgY2FsbCBvcmlnaW5hbCBmdW5jdGlvbiBvbmNlIGl0IGhhcyBub3QgYmVlbiBjYWxsZWQgZm9yIGEgc3BlY2lmaWVkIHRpbWVcbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzZWxmIGZ1bmN0aW9uIHRoYXQgZXhlY3V0aW9uIGhhcyB0byBiZSBkZWxheWVkXG4gKiBAcGFyYW0ge051bWJlcn0gd2FpdCBhcHByb3hpbWF0ZSBkYWxheSB0aW1lIGluIG1pbGxpc2Vjb25kc1xuICogQHBhcmFtIHtCb29sZWFufSBpbW1lZGlhdGUgdHJ1ZSB0byBpbnZva2UgZnVuY2l0b24gaW1tZWRpYXRlbHkgYW5kIHRoZW4gaWdub3JlIGZvbGxvd2luZyBjYWxscyBmb3Igd2FpdCBtaWxsaXNlY29uZHNcbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBkZWJvdW5jZSh3YWl0LCBpbW1lZGlhdGUpIHtcbiAgICB2YXIgZnVuYyA9IHRoaXM7IC8vIGZpcnN0IHBhcmFtZXRlciBvZiBfLmRlYm91bmNlXG4gICAgdmFyIHRpbWVvdXQsIGFyZ3MsIGNvbnRleHQsIHRpbWVzdGFtcCwgcmVzdWx0O1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgY29udGV4dCA9IHRoaXM7IC8vIHN0b3JlIG9yaWdpbmFsIGNvbnRleHRcbiAgICAgICAgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgICAgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgICAgdmFyIGNhbGxOb3cgPSBpbW1lZGlhdGUgJiYgISB0aW1lb3V0O1xuICAgICAgICBpZiAoISB0aW1lb3V0KVxuICAgICAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQobGF0ZXIsIHdhaXQpO1xuICAgICAgICBpZiAoY2FsbE5vdylcbiAgICAgICAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG5cbiAgICAgICAgZnVuY3Rpb24gbGF0ZXIoKSB7XG4gICAgICAgICAgICB2YXIgbGFzdCA9IERhdGUubm93KCkgLSB0aW1lc3RhbXA7XG4gICAgICAgICAgICBpZiAobGFzdCA8IHdhaXQpXG4gICAgICAgICAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQobGF0ZXIsIHdhaXQgLSBsYXN0KTtcbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRpbWVvdXQgPSBudWxsO1xuICAgICAgICAgICAgICAgIGlmICghIGltbWVkaWF0ZSlcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGEgZnVuY3Rpb24sIHRoYXQsIHdoZW4gaW52b2tlZCwgd2lsbCBvbmx5IGJlIHRyaWdnZXJlZCBhdCBtb3N0IG9uY2UgZHVyaW5nIGEgZ2l2ZW4gd2luZG93IG9mIHRpbWUuIFxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgZnVuY3Rpb24gdGhhdCBleGVjdXRpb24gaGFzIHRvIGJlIGRlbGF5ZWRcbiAqIEBwYXJhbSB7TnVtYmVyfSB3YWl0IGFwcHJveGltYXRlIGRlbGF5IHRpbWUgaW4gbWlsbGlzZWNvbmRzXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBge2xlYWRpbmc6IGZhbHNlfWAgdG8gZGlzYWJsZSB0aGUgZXhlY3V0aW9uIG9uIHRoZSBsZWFkaW5nIGVkZ2VcbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiB0aHJvdHRsZSh3YWl0LCBvcHRpb25zKSB7XG4gICAgdmFyIGZ1bmMgPSB0aGlzOyAvLyBmaXJzdCBwYXJhbWV0ZXIgb2YgXy50aHJvdHRsZVxuICAgIHZhciBjb250ZXh0LCBhcmdzLCByZXN1bHQ7XG4gICAgdmFyIHRpbWVvdXQgPSBudWxsO1xuICAgIHZhciBwcmV2aW91cyA9IDA7XG4gICAgb3B0aW9ucyB8fCAob3B0aW9ucyA9IHt9KTtcblxuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIG5vdyA9IERhdGUubm93KCk7XG4gICAgICAgIGlmICghcHJldmlvdXMgJiYgb3B0aW9ucy5sZWFkaW5nID09PSBmYWxzZSkgcHJldmlvdXMgPSBub3c7XG4gICAgICAgIHZhciByZW1haW5pbmcgPSB3YWl0IC0gKG5vdyAtIHByZXZpb3VzKTtcbiAgICAgICAgY29udGV4dCA9IHRoaXM7XG4gICAgICAgIGFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICAgIGlmIChyZW1haW5pbmcgPD0gMCkge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICAgICAgdGltZW91dCA9IG51bGw7XG4gICAgICAgICAgICBwcmV2aW91cyA9IG5vdztcbiAgICAgICAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgICAgIH0gZWxzZSBpZiAoIXRpbWVvdXQgJiYgb3B0aW9ucy50cmFpbGluZyAhPT0gZmFsc2UpXG4gICAgICAgICAgICB0aW1lb3V0ID0gc2V0VGltZW91dChsYXRlciwgcmVtYWluaW5nKTtcblxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiBsYXRlcigpIHtcbiAgICAgICAgcHJldmlvdXMgPSBvcHRpb25zLmxlYWRpbmcgPT09IGZhbHNlID8gMCA6IERhdGUubm93KCk7XG4gICAgICAgIHRpbWVvdXQgPSBudWxsO1xuICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MpO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIENhbGwgcGFzc2VkIGZ1bmN0aW9uIG9ubHkgb25jZVxuICogQHJldHVybiB7RnVuY3Rpb259IHNlbGZcbiAqL1xuZnVuY3Rpb24gb25jZSgpIHtcbiAgICB2YXIgZnVuYyA9IHRoaXNcbiAgICAgICAgLCByYW4gPSBmYWxzZVxuICAgICAgICAsIG1lbW87XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAocmFuKSByZXR1cm4gbWVtbztcbiAgICAgICAgcmFuID0gdHJ1ZTtcbiAgICAgICAgbWVtbyA9IGZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgZnVuYyA9IG51bGw7XG4gICAgICAgIHJldHVybiBtZW1vO1xuICAgIH07XG59XG5cblxuLyoqXG4gKiBFeGVjdXRlIGEgZnVuY3Rpb24gd2hlbiB0aGUgY29uZGl0aW9uIGZ1bmN0aW9uIHJldHVybnMgYSB0cnV0aHkgdmFsdWVcbiAqIGl0IHJ1bnMgdGhlIGNvbmRpdGlvbiBmdW5jdGlvbiBldmVyeSBgY2hlY2tJbnRlcnZhbGAgbWlsbGlzZWNvbmRzIChkZWZhdWx0IDUwKVxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgZnVuY3Rpb246IGlmIGl0IHJldHVybnMgdHJ1ZSB0aGUgY2FsbGJhY2sgaXMgZXhlY3V0ZWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIHJ1bnMgd2hlbiB0aGUgY29uZGl0aW9uIGlzIHRydWVcbiAqIEBwYXJhbSB7TnVtYmVyfSBtYXhUaW1lb3V0IHRpbWVvdXQgYmVmb3JlIGdpdmluZyB1cCAodGltZSBpbiBtaWxsaXNlY29uZHMpXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aW1lZE91dEZ1bmMgYSBmdW5jdGlvbiBjYWxsZWQgaWYgdGltZW91dCBpcyByZWFjaGVkXG4gKiBAcGFyYW0ge051bWJlcn0gY2hlY2tJbnRlcnZhbCB0aW1lIGludGVydmFsIHdoZW4geW91IHJ1biB0aGUgY29uZGl0aW9uIGZ1bmN0aW9uICh0aW1lIGluIG1pbGxpc2Vjb25kcyksIGRlZmF1bHQgNTAgbXNcbiAqL1xuZnVuY3Rpb24gd2FpdEZvcihjYWxsYmFjaywgbWF4VGltZW91dCwgdGltZWRPdXRGdW5jLCBjaGVja0ludGVydmFsKXtcbiAgICB2YXIgc3RhcnQgPSBEYXRlLm5vdygpO1xuICAgIHZhciBjb25kaXRpb24gPSB0aGlzO1xuICAgIGNoZWNrSW50ZXJ2YWwgPSBjaGVja0ludGVydmFsIHx8IDUwO1xuICAgIHZhciBpbnRlcnZhbCA9IHNldEludGVydmFsKHRlc3RDb25kaXRpb24sIGNoZWNrSW50ZXJ2YWwpO1xuXG4gICAgZnVuY3Rpb24gdGVzdENvbmRpdGlvbigpIHtcbiAgICAgICAgaWYgKGNvbmRpdGlvbigpKSBjYWxsYmFjaygpO1xuICAgICAgICBlbHNlIGlmIChEYXRlLm5vdygpIC0gc3RhcnQgPj0gbWF4VGltZW91dClcbiAgICAgICAgICAgIHRpbWVkT3V0RnVuYyAmJiB0aW1lZE91dEZ1bmMoKTtcbiAgICAgICAgZWxzZSByZXR1cm47XG4gICAgICAgIGNsZWFySW50ZXJ2YWwoaW50ZXJ2YWwpO1xuICAgIH07XG59XG5cblxuLyoqXG4gKiByZXR1cm5zIHRoZSBmdW5jdGlvbiB0aGF0IG5lZ2F0ZXMgKCEgb3BlcmF0b3IpIHRoZSByZXN1bHQgb2YgdGhlIG9yaWdpbmFsIGZ1bmN0aW9uXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzZWxmIGZ1bmN0aW9uIHRvIG5lZ2F0ZVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIG5vdCgpIHtcbiAgICB2YXIgZnVuYyA9IHRoaXM7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gIWZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9O1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIC0gW2lzTnVtZXJpY10oI2lzTnVtZXJpYylcbiAqL1xudmFyIG51bWJlck1ldGhvZHMgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBpc051bWVyaWM6IGlzTnVtZXJpY1xufTtcblxuXG4vKipcbiAqIEZ1bmN0aW9uIHRvIHRlc3QgaWYgYSB2YWx1ZSBpcyBudW1lcmljXG4gKlxuICogQHBhcmFtIHtBbnl9IHNlbGYgdmFsdWUgdG8gYmUgdGVzdGVkXG4gKiBAcmV0dXJuIHtCb29sZWFufSB0cnVlIGlmIGl0IGlzIGEgbnVtZXJpYyB2YWx1ZVxuICovXG5mdW5jdGlvbiBpc051bWVyaWMoKSB7XG4gICAgcmV0dXJuICFpc05hTihwYXJzZUZsb2F0KHRoaXMpKSAmJiBpc0Zpbml0ZSh0aGlzKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi91dGlscycpO1xuXG5cbi8qKlxuICogLSBbZXh0ZW5kXSgjZXh0ZW5kKVxuICogLSBbY2xvbmVdKCNjbG9uZSlcbiAqIC0gW2RlZmluZVByb3BlcnR5XSgjZGVmaW5lUHJvcGVydHkpXG4gKiAtIFtkZWZpbmVQcm9wZXJ0aWVzXSgjZGVmaW5lUHJvcGVydGllcylcbiAqIC0gW2RlZXBFeHRlbmRdKCNkZWVwRXh0ZW5kKVxuICogLSBbZGVlcENsb25lXSgjZGVlcENsb25lKVxuICogLSBba2V5c10oI2tleXMpXG4gKiAtIFthbGxLZXlzXSgjYWxsS2V5cylcbiAqIC0gW3ZhbHVlc10oI3ZhbHVlcylcbiAqIC0gW2tleU9mXSgja2V5T2YpXG4gKiAtIFthbGxLZXlzT2ZdKCNhbGxLZXlzT2YpXG4gKiAtIFtlYWNoS2V5XSgjZWFjaEtleSlcbiAqIC0gW21hcEtleXNdKCNtYXBLZXlzKVxuICogLSBbcmVkdWNlS2V5c10oI3JlZHVjZUtleXMpXG4gKiAtIFtmaWx0ZXJLZXlzXSgjZmlsdGVyS2V5cylcbiAqIC0gW3NvbWVLZXldKCNzb21lS2V5KVxuICogLSBbZXZlcnlLZXldKCNldmVyeUtleSlcbiAqIC0gW2ZpbmRWYWx1ZV0oI2ZpbmRWYWx1ZSlcbiAqIC0gW2ZpbmRLZXldKCNmaW5kS2V5KVxuICogLSBbcGlja0tleXNdKCNwaWNrS2V5cylcbiAqIC0gW29taXRLZXlzXSgjb21pdEtleXMpXG4gKiAtIFtpc0VxdWFsXSgjaXNFcXVhbClcbiAqIC0gW2lzTm90XSgjaXNOb3QpXG4gKlxuICogQWxsIHRoZXNlIG1ldGhvZHMgY2FuIGJlIFtjaGFpbmVkXShwcm90by5qcy5odG1sI1Byb3RvKVxuICovXG52YXIgb2JqZWN0TWV0aG9kcyA9IG1vZHVsZS5leHBvcnRzID0ge1xuICAgIGV4dGVuZDogZXh0ZW5kLFxuICAgIGNsb25lOiBjbG9uZSxcbiAgICBkZWZpbmVQcm9wZXJ0eTogZGVmaW5lUHJvcGVydHksXG4gICAgZGVmaW5lUHJvcGVydGllczogZGVmaW5lUHJvcGVydGllcyxcbiAgICBkZWVwRXh0ZW5kOiBkZWVwRXh0ZW5kLFxuICAgIGRlZXBDbG9uZTogZGVlcENsb25lLFxuICAgIGtleXM6IGtleXMsXG4gICAgYWxsS2V5czogYWxsS2V5cyxcbiAgICB2YWx1ZXM6IHZhbHVlcyxcbiAgICBrZXlPZjoga2V5T2YsXG4gICAgYWxsS2V5c09mOiBhbGxLZXlzT2YsXG4gICAgZWFjaEtleTogZWFjaEtleSxcbiAgICBtYXBLZXlzOiBtYXBLZXlzLFxuICAgIHJlZHVjZUtleXM6IHJlZHVjZUtleXMsXG4gICAgZmlsdGVyS2V5czogZmlsdGVyS2V5cyxcbiAgICBzb21lS2V5OiBzb21lS2V5LFxuICAgIGV2ZXJ5S2V5OiBldmVyeUtleSxcbiAgICBwaWNrS2V5czogcGlja0tleXMsXG4gICAgb21pdEtleXM6IG9taXRLZXlzLFxuICAgIGlzRXF1YWw6IGlzRXF1YWwsXG4gICAgaXNOb3Q6IGlzTm90XG59O1xuXG5cbi8qKlxuICogIyMjI1Byb3BlcnR5IGRlc2NyaXB0b3IgY29uc3RhbnRzIyMjI1xuICogVGhlIHN1bSBvZiB0aGVzZSBjb25zdGFudHMgY2FuIGJlIHVzZWQgYXMgbGFzdCBwYXJhbWV0ZXIgb2YgZGVmaW5lUHJvcGVydHkgYW5kIGRlZmluZVByb3BlcnRpZXMgdG8gZGV0ZXJtaW5lIHR5cGVzIG9mIHByb3BlcnRpZXMuXG4gKi9cbnZhciBjb25zdGFudHMgPSB7XG4gICAgRU5VTUVSQUJMRTogMSxcbiAgICBFTlVNOiAxLFxuICAgIENPTkZJR1VSQUJMRTogMixcbiAgICBDT05GOiAyLFxuICAgIFdSSVRBQkxFOiA0LFxuICAgIFdSSVQ6IDRcbn07XG5cbmRlZmluZVByb3BlcnR5LmNhbGwob2JqZWN0TWV0aG9kcywgJ19jb25zdGFudHMnLCBjb25zdGFudHMpO1xuXG5cbi8qKlxuICogQW5hbG9ndWUgb2YgRVM2IFtBcnJheSBfX2ZpbmRfXyBtZXRob2RdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0FycmF5L2ZpbmQpLlxuICogUmV0dXJucyB0aGUgdmFsdWUgb2Ygb2JqZWN0IHByb3BlcnR5IHRoYXQgcGFzc2VzIGNhbGxiYWNrIHRlc3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgb2JqZWN0IHRvIHNlYXJjaCBpblxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgc2hvdWxkIHJldHVybiBgdHJ1ZWAgZm9yIGl0ZW0gdG8gcGFzcyB0aGUgdGVzdCwgcGFzc2VkIGB2YWx1ZWAsIGBrZXlgIGFuZCBgc2VsZmAgYXMgcGFyYW1ldGVyc1xuICogQHBhcmFtIHtPYmplY3R9IHRoaXNBcmcgb3B0aW9uYWwgY29udGV4dCAoYHRoaXNgKSBvZiBjYWxsYmFjayBjYWxsXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIEFuIG9wdGlvbmFsIGB0cnVlYCB0byBpdGVyYXRlIGVudW1lcmFibGUgcHJvcGVydGllcyBvbmx5LlxuICogQHJldHVybiB7QW55fVxuICovXG5vYmplY3RNZXRob2RzLmZpbmRWYWx1ZSA9IHV0aWxzLm1ha2VGaW5kTWV0aG9kKGVhY2hLZXksICd2YWx1ZScpO1xuXG5cbi8qKlxuICogQW5hbG9ndWUgb2YgRVM2IFtBcnJheSBfX2ZpbmRJbmRleF9fIG1ldGhvZF0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvZmluZEluZGV4KS5cbiAqIFJldHVybnMgdGhlIGtleSBvZiBvYmplY3QgcHJvcGVydHkgdGhhdCBwYXNzZXMgY2FsbGJhY2sgdGVzdC4gUmV0dXJucyBgdW5kZWZpbmVkYCBpZiBub3QgZm91bmQgKHVubGlrZSBgZmluZEluZGV4YCwgdGhhdCByZXR1cm5zIC0xIGluIHRoaXMgY2FzZSkuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgb2JqZWN0IHRvIHNlYXJjaCBpblxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgc2hvdWxkIHJldHVybiBgdHJ1ZWAgZm9yIGl0ZW0gdG8gcGFzcyB0aGUgdGVzdCwgcGFzc2VkIGB2YWx1ZWAsIGBrZXlgIGFuZCBgc2VsZmAgYXMgcGFyYW1ldGVyc1xuICogQHBhcmFtIHtPYmplY3R9IHRoaXNBcmcgb3B0aW9uYWwgY29udGV4dCAoYHRoaXNgKSBvZiBjYWxsYmFjayBjYWxsXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIEFuIG9wdGlvbmFsIGB0cnVlYCB0byBpdGVyYXRlIGVudW1lcmFibGUgcHJvcGVydGllcyBvbmx5LlxuICogQHJldHVybiB7SW50ZWdlcn1cbiAqL1xub2JqZWN0TWV0aG9kcy5maW5kS2V5ID0gdXRpbHMubWFrZUZpbmRNZXRob2QoZWFjaEtleSwgJ2tleScpO1xuXG5cbi8qKlxuICogRXh0ZW5kcyBvYmplY3QgYHNlbGZgIHdpdGggdGhlIHByb3BlcnRpZXMgb2YgdGhlIG9iamVjdCBgb2JqYCBjb3B5aW5nIGFsbCBvd24gcHJvcGVydGllcyAobm90IHRob3NlIGluaGVyaXRlZCB2aWEgcHJvdG90eXBlIGNoYWluKSwgaW5jbHVkaW5nIG5vbi1lbnVtZXJhYmxlIHByb3BlcnRpZXMgKHVubGVzcyBgb25seUVudW1lcmFibGVgIGlzIHRydXRoeSkuXG4gKiBDcmVhdGVkIHByb3BlcnRpZXMgd2lsbCBoYXZlIHRoZSBzYW1lIGRlc2NyaXB0b3JzIGFzIHRoZSBwcm9wZXJ0aXMgb2YgYG9iamAuXG4gKiBSZXR1cm5zIGBzZWxmYCB0byBhbGxvdyBjaGFpbmluZyB3aXRoIG90aGVyIGZ1bmN0aW9ucy5cbiAqIENhbiBiZSB1c2VkIHdpdGggZnVuY3Rpb25zLCB0byBjb3B5IGNsYXNzIG1ldGhvZHMsIGUuZy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3QgdG8gYmUgZXh0ZW5kZWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogQW4gb2JqZWN0IHdoaWNoIHByb3BlcnRpZXMgd2lsbCBiZSBjb3BpZWQgdG8gc2VsZlxuICogQHBhcmFtIHtCb29sZWFufSBvbmx5RW51bWVyYWJsZSBPcHRpb25hbCBmbGFnIHRvIHByZXZlbnQgY29weWluZyBub24tZW51bWVyYWJsZSBwcm9wZXJ0aWVzLCBgZmFsc2VgIGJ5IGRlZmF1bHRcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZXh0ZW5kKG9iaiwgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgZGVzY3JpcHRvcnMgPSB7fTtcblxuICAgIGVhY2hLZXkuY2FsbChvYmosIGZ1bmN0aW9uKHZhbHVlLCBwcm9wKSB7XG4gICAgICAgIGRlc2NyaXB0b3JzW3Byb3BdID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihvYmosIHByb3ApO1xuICAgIH0sIHRoaXMsIG9ubHlFbnVtZXJhYmxlKTtcblxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIGRlc2NyaXB0b3JzKTtcblxuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogTWFrZXMgYSBzaGFsbG93IGNsb25lIG9mIG9iamVjdCBgb2JqYCBjcmVhdGluZyBhbiBpbnN0YW5jZSBvZiB0aGUgc2FtZSBjbGFzczsgdGhlIHByb3BlcnRpZXMgd2lsbCBoYXZlIHRoZSBzYW1lIGRlc2NyaXB0b3JzLlxuICogVG8gY2xvbmUgYW4gYXJyYXkgdXNlXG4gKiBgYGBcbiAqIHZhciBjbG9uZWRBcnJheSA9IFtdLmNvbmNhdChhcnIpO1xuICogYGBgXG4gKiBUaGlzIGZ1bmN0aW9uIHNob3VsZCBub3QgYmUgdXNlZCB0byBjbG9uZSBhbiBhcnJheSwgYmVjYXVzZSBpdCBpcyBpbmVmZmljaWVudC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3QgdG8gYmUgY2xvbmVkXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIGNsb25lKCkge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMpKSByZXR1cm4gdGhpcy5zbGljZSgpO1xuICAgIGlmICh0aGlzIGluc3RhbmNlb2YgRGF0ZSkgcmV0dXJuIG5ldyBEYXRlKHRoaXMpO1xuICAgIGlmICh0aGlzIGluc3RhbmNlb2YgUmVnRXhwKSByZXR1cm4gbmV3IFJlZ0V4cCh0aGlzKTtcbiAgICB2YXIgY2xvbmVkT2JqZWN0ID0gT2JqZWN0LmNyZWF0ZSh0aGlzLmNvbnN0cnVjdG9yLnByb3RvdHlwZSk7XG4gICAgZXh0ZW5kLmNhbGwoY2xvbmVkT2JqZWN0LCB0aGlzKTtcbiAgICByZXR1cm4gY2xvbmVkT2JqZWN0O1xufVxuXG5cbi8qKlxuICogU3ludGF4IHN1Z2FyIHRvIHNob3J0ZW4gdXNhZ2Ugb2YgYE9iamVjdC5kZWZpbmVQcm9wZXJ0eWAuXG4gKiBUaGUgc2ltcGxlc3QgdXNhZ2UgKHRvIGFkZCBub24tZW51bWVyYWJsZSwgbm9uLWNvbmZpZ3VyYWJsZSwgbm9uLXdyaXRhYmxlIHByb3BlcnR5KTpcbiAqIGBgYFxuICogXy5kZWZpbmVQcm9wZXJ0eShvYmosICdrZXknLCB2YWx1ZSk7XG4gKiBgYGBcbiAqXG4gKiBUbyBkZWZpbmUgc29tZSBvdGhlciBwcm9wZXJ0aWVzIHVzZSBzdW0gb2YgdGhlIGZsYWdzIGBfLkVOVU1FUkFCTEVgIChvciBgXy5FTlVNYCksIGBfLkNPTkZJR1VSQUJMRWAgKG9yIGBfLkNPTkZgKSBhbmQgYF8uV1JJVEFCTEVgIChvciBgXy5XUklUYCk6XG4gKiBgYGBcbiAqIF8uZGVmaW5lUHJvcGVydHkob2JqLCAna2V5JywgdmFsdWUsIF8uRU5VTSArIF8uV1JJVCk7XG4gKiBgYGBcbiAqIFJldHVybnMgYHNlbGZgLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZWxmIEFuIG9iamVjdCB0byBhZGQgYSBwcm9wZXJ0eSB0b1xuICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5TmFtZSB0aGUgbmFtZSBvZiB0aGUgcHJvcGVydHkgdGhhdCB3aWxsIGJlIGFkZGVkXG4gKiBAcGFyYW0ge0FueX0gdmFsdWUgdGhlIHZhbHVlIG9mIGFkZGVkIHByb3BlcnR5XG4gKiBAcGFyYW0ge0ludGVnZXJ9IGRlY3JpcHRvckZsYWdzIGJpdCBtYXNrIG9mIHByb3BlcnR5IGRlc2NyaXB0b3IgcHJvcGVydGllcyBjb21wb3NlZCBmcm9tIGBfLkVOVU1FUkFCTEVgIChvciBgXy5FTlVNYCksIGBfLkNPTkZJR1VSQUJMRWAgKG9yIGBfLkNPTkZgKSBhbmQgYF8uV1JJVEFCTEVgIChvciBgXy5XUklUYClcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZGVmaW5lUHJvcGVydHkocHJvcGVydHlOYW1lLCB2YWx1ZSwgZGVjcmlwdG9yRmxhZ3MpIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgcHJvcGVydHlOYW1lLFxuICAgICAgICBfZ2V0RGVzY3JpcHRvcih2YWx1ZSwgZGVjcmlwdG9yRmxhZ3MpKTtcbiAgICByZXR1cm4gdGhpcztcbn1cblxuXG5mdW5jdGlvbiBfZ2V0RGVzY3JpcHRvcih2YWx1ZSwgZGVjcmlwdG9yRmxhZ3MpIHtcbiAgICB2YXIgZGVzY3JpcHRvciA9IHsgdmFsdWU6IHZhbHVlIH07XG4gICAgaWYgKGRlY3JpcHRvckZsYWdzKVxuICAgICAgICBleHRlbmQuY2FsbChkZXNjcmlwdG9yLCB7XG4gICAgICAgICAgICBlbnVtZXJhYmxlOiAhISAoZGVjcmlwdG9yRmxhZ3MgJiBjb25zdGFudHMuRU5VTUVSQUJMRSksXG4gICAgICAgICAgICBjb25maWd1cmFibGU6ICEhIChkZWNyaXB0b3JGbGFncyAmIGNvbnN0YW50cy5DT05GSUdVUkFCTEUpLFxuICAgICAgICAgICAgd3JpdGFibGU6ICEhIChkZWNyaXB0b3JGbGFncyAmIGNvbnN0YW50cy5XUklUQUJMRSlcbiAgICAgICAgfSk7XG5cbiAgICByZXR1cm4gZGVzY3JpcHRvcjtcbn1cblxuXG4vKipcbiAqIFN5bnRheCBzdWdhciB0byBzaG9ydGVuIHVzYWdlIG9mIGBPYmplY3QuZGVmaW5lUHJvcGVydGllc2AuXG4gKiBUaGUgc2ltcGxlc3QgdXNhZ2UgKHRvIGFkZCBub24tZW51bWVyYWJsZSwgbm9uLWNvbmZpZ3VyYWJsZSwgbm9uLXdyaXRhYmxlIHByb3BlcnRpZXMpOlxuICogYGBgXG4gKiBfLmRlZmluZVByb3BlcnRpZXMob2JqLCB7XG4gKiAgICAga2V5MTogdmFsdWUxLFxuICogICAgIGtleTI6IHZhbHVlMlxuICogfSk7XG4gKiBgYGBcbiAqIFRvIGRlZmluZSBzb21lIG90aGVyIHByb3BlcnRpZXMgdXNlIHN1bSBvZiB0aGUgZmxhZ3MgYF8uRU5VTUVSQUJMRWAgKG9yIGBfLkVOVU1gKSwgYF8uQ09ORklHVVJBQkxFYCAob3IgYF8uQ09ORmApIGFuZCBgXy5XUklUQUJMRWAgKG9yIGBfLldSSVRgKTpcbiAqIGBgYFxuICogXy5kZWZpbmVQcm9wZXJ0aWVzKG9iaiwge1xuICogICAgIGtleTE6IHZhbHVlMSxcbiAqICAgICBrZXkyOiB2YWx1ZTJcbiAqIH0sIF8uRU5VTSArIF8uV1JJVCk7XG4gKiBgYGBcbiAqIFJldHVybnMgYHNlbGZgLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZWxmIEFuIG9iamVjdCB0byBhZGQgYSBwcm9wZXJ0eSB0b1xuICogQHBhcmFtIHtPYmplY3R9IHByb3BlcnR5VmFsdWVzIEEgbWFwIG9mIGtleXMgYW5kIHZhbHVlcyBvZiBwcm9wZXJ0aWVzIHRoYXR3aWxsIGJlIGFkZGVkLiBUaGUgZGVzY3JpcHRvcnMgb2YgcHJvcGVydGllcyB3aWxsIGJlIGRlZmluZWQgYnkgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzLlxuICogQHBhcmFtIHtJbnRlZ2VyfSBkZWNyaXB0b3JGbGFncyBiaXQgbWFzayBvZiBwcm9wZXJ0eSBkZXNjcmlwdG9yIHByb3BlcnRpZXMgY29tcG9zZWQgZnJvbSBgXy5FTlVNRVJBQkxFYCAob3IgYF8uRU5VTWApLCBgXy5DT05GSUdVUkFCTEVgIChvciBgXy5DT05GYCkgYW5kIGBfLldSSVRBQkxFYCAob3IgYF8uV1JJVGApXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIGRlZmluZVByb3BlcnRpZXMocHJvcGVydHlWYWx1ZXMsIGRlY3JpcHRvckZsYWdzKSB7XG4gICAgdmFyIGRlc2NyaXB0b3JzID0gbWFwS2V5cy5jYWxsKHByb3BlcnR5VmFsdWVzLCBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICByZXR1cm4gX2dldERlc2NyaXB0b3IodmFsdWUsIGRlY3JpcHRvckZsYWdzKTtcbiAgICB9LCB0cnVlKTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh0aGlzLCBkZXNjcmlwdG9ycyk7XG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBFeHRlbmRzIG9iamVjdCBgc2VsZmAgd2l0aCBwcm9wZXJ0aWVzIG9mIGBvYmpgIHRvIGFueSBkZXB0aCwgd2l0aG91dCBvdmVyd3J0aXRpbmcgZXhpc3Rpbmcgb2JqZWN0IHByb3BlcnRpZXMgb2YgYHNlbGZgIHdpdGggb2JqZWN0IHByb3BlcnRpZXMgb2YgYG9iamAuXG4gKiBTY2FsYXIgcHJvcGVydGllcyBvZiBgb2JqYCB3aWxsIG92ZXJ3cml0ZSBwcm9wZXJ0aWVzIG9mIGBzZWxmYC4gU2NhbGFyIHBvcnBlcnRpZXMgb2YgYHNlbGZgIHdpbGwgYWxzbyBiZSBvdmVyd3JpdHRlbi5cbiAqIENvcnJlY3RseSB3b3JrcyB3aXRoIHJlY3Vyc2l2ZSBvYmplY3RzLlxuICogVXNhZ2U6XG4gKiBgYGBcbiAqIHZhciBvYmogPSB7XG4gKiAgICAgaW5uZXI6IHtcbiAqICAgICAgICAgYTogMVxuICogICAgIH1cbiAqIH07XG4gKlxuICogXy5kZWVwRXh0ZW5kKG9iaiwge1xuICogICAgIGlubmVyOiB7XG4gKiAgICAgICAgIGI6IDJcbiAqICAgICB9XG4gKiB9KTtcbiAqXG4gKiBhc3NlcnQuZGVlcEVxdWFsKG9iaiwge1xuICogICAgIGlubmVyOiB7XG4gKiAgICAgICAgIGE6IDEsXG4gKiAgICAgICAgIGI6IDJcbiAqICAgICB9XG4gKiB9KTsgLy8gYXNzZXJ0IHBhc3Nlc1xuICogYGBgXG4gKiBSZXR1cm5zIGBzZWxmYC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3QgdG8gYmUgZXh0ZW5kZWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogQW4gb2JqZWN0IHdpdGggcHJvcGVydGllcyB0byBjb3B5IHRvXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIE9wdGlvbmFsIGB0cnVlYCB0byB1c2Ugb25seSBlbnVtZXJhYmxlIHByb3BlcnRpZXNcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZGVlcEV4dGVuZChvYmosIG9ubHlFbnVtZXJhYmxlKSB7XG4gICAgcmV0dXJuIF9leHRlbmRUcmVlKHRoaXMsIG9iaiwgb25seUVudW1lcmFibGUsIFtdKTtcbn1cblxuXG5mdW5jdGlvbiBfZXh0ZW5kVHJlZShzZWxmTm9kZSwgb2JqTm9kZSwgb25seUVudW1lcmFibGUsIG9ialRyYXZlcnNlZCkge1xuICAgIGlmIChvYmpUcmF2ZXJzZWQuaW5kZXhPZihvYmpOb2RlKSA+PSAwKSByZXR1cm47IC8vIG5vZGUgYWxyZWFkeSB0cmF2ZXJzZWQsIG9iaiBoYXMgcmVjdXJzaW9uXG5cbiAgICAvLyBzdG9yZSBub2RlIHRvIHJlY29nbmlzZSByZWN1cnNpb25cbiAgICBvYmpUcmF2ZXJzZWQucHVzaChvYmpOb2RlKTtcblxuICAgIHZhciBsb29wID0gQXJyYXkuaXNBcnJheShvYmpOb2RlKSA/IEFycmF5LnByb3RvdHlwZS5mb3JFYWNoIDogZWFjaEtleTtcblxuICAgIGxvb3AuY2FsbChvYmpOb2RlLCBmdW5jdGlvbih2YWx1ZSwgcHJvcCkge1xuICAgICAgICB2YXIgZGVzY3JpcHRvciA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3Iob2JqTm9kZSwgcHJvcCk7XG4gICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCcgJiYgdmFsdWUgIT0gbnVsbFxuICAgICAgICAgICAgICAgICYmICEgKHZhbHVlIGluc3RhbmNlb2YgUmVnRXhwKSAmJiAhICh2YWx1ZSBpbnN0YW5jZW9mIERhdGUpKSB7XG4gICAgICAgICAgICBpZiAoISAoc2VsZk5vZGUuaGFzT3duUHJvcGVydHkocHJvcClcbiAgICAgICAgICAgICAgICAgICAgJiYgdHlwZW9mIHNlbGZOb2RlW3Byb3BdID09ICdvYmplY3QnICYmIHNlbGZOb2RlW3Byb3BdICE9IG51bGwpKVxuICAgICAgICAgICAgICAgIHNlbGZOb2RlW3Byb3BdID0gKEFycmF5LmlzQXJyYXkodmFsdWUpKSA/IFtdIDoge307XG4gICAgICAgICAgICBfZXh0ZW5kVHJlZShzZWxmTm9kZVtwcm9wXSwgdmFsdWUsIG9ubHlFbnVtZXJhYmxlLCBvYmpUcmF2ZXJzZWQpO1xuICAgICAgICB9IGVsc2VcbiAgICAgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShzZWxmTm9kZSwgcHJvcCwgZGVzY3JpcHRvcik7XG4gICAgfSwgdGhpcywgb25seUVudW1lcmFibGUpO1xuXG4gICAgcmV0dXJuIHNlbGZOb2RlO1xufVxuXG5cbi8qKlxuICogQ2xvbmVzIGFsbCBvYmplY3QgdHJlZS4gQ2xhc3Mgb2Ygb3JpZ2luYWwgb2JqZWN0IGlzIG5vdCBwcmVzZXJ2ZWQuIFJldHVybnMgYHNlbGZgXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgQW4gb2JqZWN0IHRvIGJlIGV4dGVuZGVkXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIE9wdGlvbmFsIGB0cnVlYCB0byB1c2Ugb25seSBlbnVtZXJhYmxlIHByb3BlcnRpZXNcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZGVlcENsb25lKG9ubHlFbnVtZXJhYmxlKSB7XG4gICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBEYXRlKSByZXR1cm4gbmV3IERhdGUodGhpcyk7XG4gICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBSZWdFeHApIHJldHVybiBuZXcgUmVnRXhwKHRoaXMpO1xuICAgIHZhciBjbG9uZWRPYmplY3QgPSBBcnJheS5pc0FycmF5KHRoaXMpID8gW10gOiB7fTtcbiAgICBkZWVwRXh0ZW5kLmNhbGwoY2xvbmVkT2JqZWN0LCB0aGlzLCBvbmx5RW51bWVyYWJsZSk7XG4gICAgcmV0dXJuIGNsb25lZE9iamVjdDtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgYXJyYXkgb2YgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9mIHRoZSBvYmplY3RcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBvYmplY3QgdG8gcmV0dXJuIGtleXMgb2ZcbiAqIEByZXR1cm4ge0FycmF5fVxuICovXG5mdW5jdGlvbiBrZXlzKCkge1xuICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzKTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgYXJyYXkgb2YgdmFsdWVzIG9mIHRoZSBvYmplY3QncyBrZXlzXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgb2JqZWN0IHRvIHJldHVybiB2YWx1ZXMgZnJvbVxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIHZhbHVlcyhvbmx5RW51bWVyYWJsZSkge1xuICAgIHZhciBwcm9wZXJ0aWVzID0gb25seUVudW1lcmFibGVcbiAgICAgICAgICAgICAgICA/IE9iamVjdC5rZXlzKHRoaXMpXG4gICAgICAgICAgICAgICAgOiBhbGxLZXlzLmNhbGwodGhpcyk7XG5cbiAgICByZXR1cm4gcHJvcGVydGllcy5tYXAoZnVuY3Rpb24ocHJvcCkge1xuICAgICAgICByZXR1cm4gdGhpc1twcm9wXTtcbiAgICB9LCB0aGlzKTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgYXJyYXkgb2YgYWxsIHByb3BlcnR5IG5hbWVzIG9mIGFuIG9iamVjdCBgc2VsZmAgKGluY2x1ZGluZyBub24tZW51bWVyYmFsZSkuXG4gKiBUbyBnZXQgb25seSBlbnVtZXJhYmxlIHByb3BlcnRpZXMsIHVzZSBgT2JqZWN0LmtleXMoKWAuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgQW4gb2JqZWN0IHRvIGdldCBhbGwgcHJvcGVydGllcyBvZi5cbiAqIEByZXR1cm4ge0FycmF5fVxuICovXG4gZnVuY3Rpb24gYWxsS2V5cygpIHtcbiAgICByZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModGhpcyk7XG4gfVxuXG5cbi8qKlxuICogQW4gYW5hbG9ndWUgb2YgYGluZGV4T2ZgIG1ldGhvZCBvZiBBcnJheSBwcm90b3R5cGUuXG4gKiBSZXR1cm5zIHRoZSBga2V5YCBvZiBgc2VhcmNoRWxlbWVudGAgaW4gdGhlIG9iamVjdCBgc2VsZmAuXG4gKiBBcyBvYmplY3Qga2V5cyBhcmUgdW5zb3J0ZWQsIGlmIHRoZXJlIGFyZSBzZXZlcmFsIGtleXMgdGhhdCBob2xkIGBzZWFyY2hFbGVtZW50YCBhbnkgb2YgdGhlbSBjYW4gYmUgcmV0dXJuZWQuIFVzZSBgYWxsS2V5c09mYCB0byByZXR1cm4gYWxsIGtleXMuXG4gKiBBbGwgb3duIHByb3BlcnRpZXMgYXJlIHNlYXJjaGVkIChub3QgdGhvc2UgaW5oZXJpdGVkIHZpYSBwcm90b3R5cGUgY2hhaW4pLCBpbmNsdWRpbmcgbm9uLWVudW1lcmFibGUgcHJvcGVydGllcyAodW5sZXNzIGBvbmx5RW51bWVyYWJsZWAgaXMgdHJ1dGh5KS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3QgdG8gc2VhcmNoIGEgdmFsdWUgaW5cbiAqIEBwYXJhbSB7QW55fSBzZWFyY2hFbGVtZW50IEFuIGVsZW1lbnQgdGhhdCB3aWxsIGJlIHNlYXJjaGVkLiBBbiBleGFjdCBlcXVhbGl0eSBpcyB0ZXN0ZWQsIHNvIGAwYCBpcyBub3QgdGhlIHNhbWUgYXMgYCcwJ2AuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIEFuIG9wdGlvbmFsIHRydWUgdG8gc2VhcmNoIGFtb25nIGVudW1lcmFibGUgcHJvcGVydGllcyBvbmx5LlxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBrZXlPZihzZWFyY2hFbGVtZW50LCBvbmx5RW51bWVyYWJsZSkge1xuICAgIHZhciBwcm9wZXJ0aWVzID0gb25seUVudW1lcmFibGVcbiAgICAgICAgICAgICAgICAgICAgICAgID8gT2JqZWN0LmtleXModGhpcylcbiAgICAgICAgICAgICAgICAgICAgICAgIDogYWxsS2V5cy5jYWxsKHRoaXMpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwcm9wZXJ0aWVzLmxlbmd0aDsgaSsrKVxuICAgICAgICBpZiAoc2VhcmNoRWxlbWVudCA9PT0gdGhpc1twcm9wZXJ0aWVzW2ldXSlcbiAgICAgICAgICAgIHJldHVybiBwcm9wZXJ0aWVzW2ldO1xuXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuXG4vKipcbiAqIFdvcmtzIHNpbWlsYXJseSB0byB0aGUgcHJldmlvdXMgZnVuY3Rpb24sIGJ1dCByZXR1cm5zIHRoZSBhcnJheSBvZiBrZXlzIGhvbGRpbmcgYHNlYXJjaEVsZW1lbnRgIGFzIHRoZWlyIHZhbHVlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZWxmIEFuIG9iamVjdCB0byBzZWFyY2ggYSB2YWx1ZSBpblxuICogQHBhcmFtIHtBbnl9IHNlYXJjaEVsZW1lbnQgQW4gZWxlbWVudCB0aGF0IHdpbGwgYmUgc2VhcmNoZWQuIEFuIGV4YWN0IGVxdWFsaXR5IGlzIHRlc3RlZCwgc28gYDBgIGlzIG5vdCB0aGUgc2FtZSBhcyBgJzAnYC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gb25seUVudW1lcmFibGUgQW4gb3B0aW9uYWwgdHJ1ZSB0byBzZWFyY2ggYW1vbmcgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9ubHkuXG4gKiBAcmV0dXJuIHtBcnJheVtTdHJpbmddfVxuICovXG5mdW5jdGlvbiBhbGxLZXlzT2Yoc2VhcmNoRWxlbWVudCwgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgcHJvcGVydGllcyA9IG9ubHlFbnVtZXJhYmxlXG4gICAgICAgICAgICAgICAgICAgICAgICA/IE9iamVjdC5rZXlzKHRoaXMpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGFsbEtleXMuY2FsbCh0aGlzKTtcblxuICAgIHZhciBrZXlzID0gcHJvcGVydGllcy5maWx0ZXIoZnVuY3Rpb24ocHJvcCkge1xuICAgICAgICByZXR1cm4gc2VhcmNoRWxlbWVudCA9PT0gdGhpc1twcm9wXTtcbiAgICB9LCB0aGlzKTtcblxuICAgIHJldHVybiBrZXlzO1xufVxuXG5cbi8qKlxuICogQW4gYW5hbG9ndWUgb2YgW2ZvckVhY2hdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0FycmF5L2ZvckVhY2gpIG1ldGhvZCBvZiBBcnJheSBwcm90b3R5cGUuXG4gKiBJdGVyYXRlcyBhbGwgb3duIHByb3BlcnRpZXMgb2YgYHNlbGZgIChvciBvbmx5IGVudW1lcmFibGUgb3duIHByb3BlcnRpZXMgaWYgYG9ubHlFbnVtZXJhYmxlYCBpcyB0cnV0aHkpIGNhbGxpbmcgY2FsbGJhY2sgZm9yIGVhY2gga2V5LlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIG5vdCBiZSB1c2VkIHdpdGggYXJyYXlzLCBpdCB3aWxsIGluY2x1ZGUgYGxlbmd0aGAgcHJvcGVydHkgaW4gaXRlcmF0aW9uLlxuICogVG8gaXRlcmF0ZSBhcnJheS1saWtlIG9iamVjdHMgKGUuZy4sIGBhcmd1bWVudHNgIHBzZXVkby1hcnJheSkgdXNlOlxuICogYGBgXG4gKiBfLmZvckVhY2goYXJndW1lbnRzLCBjYWxsYmFjaywgdGhpc0FyZyk7XG4gKiBgYGBcbiAqIEZ1bmN0aW9uIHJldHVybnMgYHNlbGZgIHRvIGFsbG93IFtjaGFpbmluZ10ocHJvdG8uanMuaHRtbClcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3Qgd2hpY2ggcHJvcGVydGllcyB3aWxsIGJlIGl0ZXJhdGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayBpcyBwYXNzZWQgYHZhbHVlYCwgYGtleWAgYW5kIGBzZWxmYCwgaXRzIHJldHVybiB2YWx1ZSBpcyBub3QgdXNlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSB0aGlzQXJnIEFuIG9wdGlvbmFsIGNvbnRleHQgb2YgaXRlcmF0aW9uICh0aGUgdmFsdWVvZiBgdGhpc2ApLCB3aWxsIGJlIHVuZGVmaW5lZCBpZiB0aGlzIHBhcmFtZXRlciBpcyBub3QgcGFzc2VkLlxuICogQHBhcmFtIHtCb29sZWFufSBvbmx5RW51bWVyYWJsZSBBbiBvcHRpb25hbCBgdHJ1ZWAgdG8gaXRlcmF0ZSBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb25seS5cbiAqL1xuZnVuY3Rpb24gZWFjaEtleShjYWxsYmFjaywgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgcHJvcGVydGllcyA9IG9ubHlFbnVtZXJhYmxlXG4gICAgICAgICAgICAgICAgICAgICAgICA/IE9iamVjdC5rZXlzKHRoaXMpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGFsbEtleXMuY2FsbCh0aGlzKTtcblxuICAgIHByb3BlcnRpZXMuZm9yRWFjaChmdW5jdGlvbihwcm9wKSB7XG4gICAgICAgIGNhbGxiYWNrLmNhbGwodGhpc0FyZywgdGhpc1twcm9wXSwgcHJvcCwgdGhpcyk7XG4gICAgfSwgdGhpcyk7XG5cbiAgICByZXR1cm4gdGhpcztcbn1cblxuXG4vKipcbiAqIEFuIGFuYWxvZ3VlIG9mIFttYXBdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0FycmF5L21hcCkgbWV0aG9kIG9mIEFycmF5IHByb3RvdHlwZS5cbiAqIFJldHVybnMgdGhlIG9iamVjdCB0aGF0IGlzIHRoZSByZXN1bHQgb2YgdGhlIGFwcGxpY2F0aW9uIG9mIGNhbGxiYWNrIHRvIHZhbHVlcyBpbiBhbGwgb3duIHByb3BlcnRpZXMgb2YgYHNlbGZgIChvciBvbmx5IGVudW1lcmFibGUgb3duIHByb3BlcnRpZXMgaWYgYG9ubHlFbnVtZXJhYmxlYCBpcyB0cnV0aHkpLlxuICogVGhlIHJldHVybmVkIG9iamVjdCB3aWxsIGJlIHRoZSBpbnN0YW5jZSBvZiB0aGUgc2FtZSBjbGFzcyBhcyBgc2VsZmAuXG4gKiBQcm9wZXJ0eSBkZXNjcmlwdG9ycyBvZiB0aGUgcmV0dXJuZWQgb2JqZWN0IHdpbGwgaGF2ZSB0aGUgc2FtZSBgZW51bWVyYWJsZWAsIGBjb25maWd1cmFibGVgIGFuZCBgd3JpdGFibGVgIHNldHRpbmdzIGFzIHRoZSBwcm9wZXJ0aWVzIG9mIGBzZWxmYC5cbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBub3QgYmUgdXNlZCB3aXRoIGFycmF5cywgaXQgd2lsbCBpbmNsdWRlIGBsZW5ndGhgIHByb3BlcnR5IGluIGl0ZXJhdGlvbi5cbiAqIFRvIG1hcCBhcnJheS1saWtlIG9iamVjdHMgdXNlOlxuICogYGBgXG4gKiB2YXIgcmVzdWx0ID0gXy5tYXAoYXJndW1lbnRzLCBjYWxsYmFjaywgdGhpc0FyZyk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3Qgd2hpY2ggcHJvcGVydGllcyB3aWxsIGJlIGl0ZXJhdGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayBpcyBwYXNzZWQgYHZhbHVlYCwgYGtleWAgYW5kIGBzZWxmYCBhbmQgc2hvdWxkIHJldHVybiB2YWx1ZSB0aGF0IHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG1hcC5cbiAqIEBwYXJhbSB7T2JqZWN0fSB0aGlzQXJnIEFuIG9wdGlvbmFsIGNvbnRleHQgb2YgaXRlcmF0aW9uICh0aGUgdmFsdWVvZiBgdGhpc2ApLCB3aWxsIGJlIHVuZGVmaW5lZCBpZiB0aGlzIHBhcmFtZXRlciBpcyBub3QgcGFzc2VkLlxuICogQHBhcmFtIHtCb29sZWFufSBvbmx5RW51bWVyYWJsZSBBbiBvcHRpb25hbCBgdHJ1ZWAgdG8gaXRlcmF0ZSBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb25seS5cbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gbWFwS2V5cyhjYWxsYmFjaywgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgZGVzY3JpcHRvcnMgPSB7fTtcbiAgICBlYWNoS2V5LmNhbGwodGhpcywgbWFwUHJvcGVydHksIHRoaXNBcmcsIG9ubHlFbnVtZXJhYmxlKTtcbiAgICByZXR1cm4gT2JqZWN0LmNyZWF0ZSh0aGlzLmNvbnN0cnVjdG9yLnByb3RvdHlwZSwgZGVzY3JpcHRvcnMpO1xuXG4gICAgZnVuY3Rpb24gbWFwUHJvcGVydHkodmFsdWUsIGtleSwgc2VsZikge1xuICAgICAgICBkZXNjcmlwdG9yc1trZXldID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihzZWxmLCBrZXkpO1xuICAgICAgICBkZXNjcmlwdG9yc1trZXldLnZhbHVlID0gY2FsbGJhY2suY2FsbCh0aGlzLCB2YWx1ZSwga2V5LCBzZWxmKTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBBbiBhbmFsb2d1ZSBvZiBbcmVkdWNlXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9SZWR1Y2UpIG1ldGhvZCBvZiBBcnJheSBwcm90b3R5cGUuXG4gKiBUaGlzIG1ldGhvZCByZWR1Y2VzIHRoZSBvYmplY3QgdG8gYSBzaW5nbGUgdmFsdWUuIEl0ZXJhdGlvbiBvcmRlciBpcyBpbXBvc3NpYmxlIHRvIGNvbnRyb2wgd2l0aCBvYmplY3QuXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgbm90IGJlIHVzZWQgd2l0aCBhcnJheXMsIGl0IHdpbGwgaW5jbHVkZSBgbGVuZ3RoYCBwcm9wZXJ0eSBpbiBpdGVyYXRpb24uXG4gKiBUbyByZWR1Y2UgYXJyYXktbGlrZSBvYmplY3RzIHVzZTpcbiAqIGBgYFxuICogdmFyIHJlc3VsdCA9IF8ucmVkdWNlKGFyZ3VtZW50cywgY2FsbGJhY2ssIGluaXRpYWxWYWx1ZSwgdGhpc0FyZyk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3Qgd2hpY2ggcHJvcGVydGllcyB3aWxsIGJlIGl0ZXJhdGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayBpcyBwYXNzZWQgYHByZXZpb3VzVmFsdWVgLCBgdmFsdWVgLCBga2V5YCBhbmQgYHNlbGZgIGFuZCBzaG91bGQgcmV0dXJuIHZhbHVlIHRoYXQgd2lsbCBiZSB1c2VkIGFzIHRoZSBgcHJldmlvdXNWYWx1ZWAgZm9yIHRoZSBuZXh0IGBjYWxsYmFja2AgY2FsbC5cbiAqIEBwYXJhbSB7QW55fSBpbml0aWFsVmFsdWUgVGhlIGluaXRpYWwgdmFsdWUgcGFzc2VkIHRvIGNhbGxiYWNrIGFzIHRoZSBmaXJzdCBwYXJhbWV0ZXIgb24gdGhlIGZpcnN0IGNhbGwuXG4gKiBAcGFyYW0ge09iamVjdH0gdGhpc0FyZyBBbiBvcHRpb25hbCBjb250ZXh0IG9mIGl0ZXJhdGlvbiAodGhlIHZhbHVlb2YgYHRoaXNgKSwgd2lsbCBiZSB1bmRlZmluZWQgaWYgdGhpcyBwYXJhbWV0ZXIgaXMgbm90IHBhc3NlZC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gb25seUVudW1lcmFibGUgQW4gb3B0aW9uYWwgYHRydWVgIHRvIGl0ZXJhdGUgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9ubHkuXG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmZ1bmN0aW9uIHJlZHVjZUtleXMoY2FsbGJhY2ssIGluaXRpYWxWYWx1ZSwgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgcHJvcGVydGllcyA9IG9ubHlFbnVtZXJhYmxlXG4gICAgICAgICAgICAgICAgICAgICAgICA/IE9iamVjdC5rZXlzKHRoaXMpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGFsbEtleXMuY2FsbCh0aGlzKTtcblxuICAgIHZhciBtZW1vID0gaW5pdGlhbFZhbHVlO1xuXG4gICAgcHJvcGVydGllcy5mb3JFYWNoKGZ1bmN0aW9uKHByb3ApIHtcbiAgICAgICAgbWVtbyA9IGNhbGxiYWNrLmNhbGwodGhpc0FyZywgbWVtbywgdGhpc1twcm9wXSwgcHJvcCwgdGhpcyk7XG4gICAgfSwgdGhpcyk7XG5cbiAgICByZXR1cm4gbWVtbztcbn1cblxuXG4vKipcbiAqIEFuIGFuYWxvZ3VlIG9mIFtmaWx0ZXJdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0FycmF5L2ZpbHRlcikgbWV0aG9kIG9mIEFycmF5IHByb3RvdHlwZS5cbiAqIFJldHVybnMgdGhlIG5ldyBvYmplY3Qgd2l0aCBrZXlzIGZvciB3aGljaCBjYWxsYmFjayByZXR1cm5zIHRydWUuXG4gKiBQcm9wZXJ0eSBkZXNjcmlwdG9ycyBvZiB0aGUgcmV0dXJuZWQgb2JqZWN0IHdpbGwgaGF2ZSB0aGUgc2FtZSBgZW51bWVyYWJsZWAsIGBjb25maWd1cmFibGVgIGFuZCBgd3JpdGFibGVgIHNldHRpbmdzIGFzIHRoZSBwcm9wZXJ0aWVzIG9mIGBzZWxmYC5cbiAqIFRvIGZpbHRlciBhcnJheS1saWtlIG9iamVjdHMgdXNlOlxuICogYGBgXG4gKiB2YXIgcmVzdWx0ID0gXy5maWx0ZXIoYXJndW1lbnRzLCBjYWxsYmFjaywgdGhpc0FyZyk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3Qgd2hpY2ggcHJvcGVydGllcyB3aWxsIGJlIGl0ZXJhdGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayBpcyBwYXNzZWQgYHZhbHVlYCwgYGtleWAgYW5kIGBzZWxmYC4gSWYgaXQgcmV0dXJucyB0cnV0aHkgdmFsdWUsIHRoZSBrZXkvdmFsdWUgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgcmVzdWx0aW5nIG9iamVjdC5cbiAqIEBwYXJhbSB7T2JqZWN0fSB0aGlzQXJnIEFuIG9wdGlvbmFsIGNvbnRleHQgb2YgaXRlcmF0aW9uICh0aGUgdmFsdWVvZiBgdGhpc2ApLCB3aWxsIGJlIHVuZGVmaW5lZCBpZiB0aGlzIHBhcmFtZXRlciBpcyBub3QgcGFzc2VkLlxuICogQHBhcmFtIHtCb29sZWFufSBvbmx5RW51bWVyYWJsZSBBbiBvcHRpb25hbCBgdHJ1ZWAgdG8gaXRlcmF0ZSBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb25seS5cbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZmlsdGVyS2V5cyhjYWxsYmFjaywgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgZGVzY3JpcHRvcnMgPSB7fTtcbiAgICBlYWNoS2V5LmNhbGwodGhpcywgZmlsdGVyUHJvcGVydHksIHRoaXNBcmcsIG9ubHlFbnVtZXJhYmxlKTtcbiAgICByZXR1cm4gT2JqZWN0LmNyZWF0ZSh0aGlzLmNvbnN0cnVjdG9yLnByb3RvdHlwZSwgZGVzY3JpcHRvcnMpOztcblxuICAgIGZ1bmN0aW9uIGZpbHRlclByb3BlcnR5KHZhbHVlLCBrZXksIHNlbGYpIHtcbiAgICAgICAgaWYgKGNhbGxiYWNrLmNhbGwodGhpcywgdmFsdWUsIGtleSwgc2VsZikpXG4gICAgICAgICAgICBkZXNjcmlwdG9yc1trZXldID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihzZWxmLCBrZXkpO1xuICAgIH1cbn1cblxuXG52YXIgX3Bhc3NlZCA9IHt9XG4gICAgLCBfZGlkTm90UGFzcyA9IHt9O1xuXG4vKipcbiAqIEFuIGFuYWxvZ3VlIG9mIFtzb21lXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9zb21lKSBtZXRob2Qgb2YgQXJyYXkgcHJvdG90eXBlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZWxmIEFuIG9iamVjdCB3aGljaCBwcm9wZXJ0aWVzIHdpbGwgYmUgaXRlcmF0ZWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIENhbGxiYWNrIGlzIHBhc3NlZCBgdmFsdWVgLCBga2V5YCBhbmQgYHNlbGZgLiBJZiBpdCByZXR1cm5zIHRydXRoeSB2YWx1ZSwgdGhlIGZ1bmN0aW9uIGltbWVhZGl0ZWx5IHJldHVybnMgYHRydWVgLlxuICogQHBhcmFtIHtPYmplY3R9IHRoaXNBcmcgQW4gb3B0aW9uYWwgY29udGV4dCBvZiBpdGVyYXRpb24gKHRoZSB2YWx1ZW9mIGB0aGlzYCksIHdpbGwgYmUgdW5kZWZpbmVkIGlmIHRoaXMgcGFyYW1ldGVyIGlzIG5vdCBwYXNzZWQuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIEFuIG9wdGlvbmFsIGB0cnVlYCB0byBpdGVyYXRlIGVudW1lcmFibGUgcHJvcGVydGllcyBvbmx5LlxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gc29tZUtleShjYWxsYmFjaywgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB0cnkge1xuICAgICAgICBlYWNoS2V5LmNhbGwodGhpcywgdGVzdFByb3BlcnR5LCB0aGlzQXJnLCBvbmx5RW51bWVyYWJsZSk7XG4gICAgfSBjYXRjaCAodGVzdCkge1xuICAgICAgICBpZiAodGVzdCA9PT0gX3Bhc3NlZCkgcmV0dXJuIHRydWU7XG4gICAgICAgIGVsc2UgdGhyb3cgdGVzdDtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuXG4gICAgZnVuY3Rpb24gdGVzdFByb3BlcnR5KHZhbHVlLCBrZXksIHNlbGYpIHtcbiAgICAgICAgaWYgKGNhbGxiYWNrLmNhbGwodGhpcywgdmFsdWUsIGtleSwgc2VsZikpXG4gICAgICAgICAgICB0aHJvdyBfcGFzc2VkO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIEFuIGFuYWxvZ3VlIG9mIFtldmVyeV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvZXZlcnkpIG1ldGhvZCBvZiBBcnJheSBwcm90b3R5cGUuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgQW4gb2JqZWN0IHdoaWNoIHByb3BlcnRpZXMgd2lsbCBiZSBpdGVyYXRlZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGJhY2sgaXMgcGFzc2VkIGB2YWx1ZWAsIGBrZXlgIGFuZCBgc2VsZmAuIElmIGl0IHJldHVybnMgZmFsc3kgdmFsdWUsIHRoZSBmdW5jdGlvbiBpbW1lYWRpdGVseSByZXR1cm5zIGBmYWxzZWAuXG4gKiBAcGFyYW0ge09iamVjdH0gdGhpc0FyZyBBbiBvcHRpb25hbCBjb250ZXh0IG9mIGl0ZXJhdGlvbiAodGhlIHZhbHVlb2YgYHRoaXNgKSwgd2lsbCBiZSB1bmRlZmluZWQgaWYgdGhpcyBwYXJhbWV0ZXIgaXMgbm90IHBhc3NlZC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gb25seUVudW1lcmFibGUgQW4gb3B0aW9uYWwgYHRydWVgIHRvIGl0ZXJhdGUgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9ubHkuXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBldmVyeUtleShjYWxsYmFjaywgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB0cnkge1xuICAgICAgICBlYWNoS2V5LmNhbGwodGhpcywgdGVzdFByb3BlcnR5LCB0aGlzQXJnLCBvbmx5RW51bWVyYWJsZSk7XG4gICAgfSBjYXRjaCAodGVzdCkge1xuICAgICAgICBpZiAodGVzdCA9PT0gX2RpZE5vdFBhc3MpIHJldHVybiBmYWxzZTtcbiAgICAgICAgZWxzZSB0aHJvdyB0ZXN0O1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcblxuICAgIGZ1bmN0aW9uIHRlc3RQcm9wZXJ0eSh2YWx1ZSwga2V5LCBzZWxmKSB7XG4gICAgICAgIGlmICghIGNhbGxiYWNrLmNhbGwodGhpcywgdmFsdWUsIGtleSwgc2VsZikpXG4gICAgICAgICAgICB0aHJvdyBfZGlkTm90UGFzcztcbiAgICB9XG59XG5cblxudmFyIEFycmF5UHJvdG8gPSBBcnJheS5wcm90b3R5cGVcbiAgICAsIGNvbmNhdCA9IEFycmF5UHJvdG8uY29uY2F0O1xuLyoqXG4gKiBSZXR1cm5zIG9iamVjdCBvZiB0aGUgc2FtZSBjbGFzcyB3aXRoIG9ubHkgc3BlY2lmaWVkIGtleXMsIHRoYXQgYXJlIHBhc3NlZCBhcyBzdHJpbmcgcGFyYW1ldGVycyBvciBhcnJheShzKSBvZiBrZXlzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZWxmIGFuIG9iamVjdCB0byBwaWNrIGtleXMgZnJvbVxuICogQHBhcmFtIHtMaXN0W1N0cmluZ3xBcnJheV19IGFyZ3VtZW50cyBsaXN0IG9mIGtleXMgKG9yIGFycmF5KHMpIG9mIGtleXMpXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIHBpY2tLZXlzKCkgeyAvLyAsIC4uLiBrZXlzXG4gICAgdmFyIGtleXMgPSBjb25jYXQuYXBwbHkoQXJyYXlQcm90bywgYXJndW1lbnRzKVxuICAgICAgICAsIG9iaiA9IE9iamVjdC5jcmVhdGUodGhpcy5jb25zdHJ1Y3Rvci5wcm90b3R5cGUpO1xuICAgIGtleXMuZm9yRWFjaChmdW5jdGlvbihrZXkpIHtcbiAgICAgICAgaWYgKHRoaXMuaGFzT3duUHJvcGVydHkoa2V5KSlcbiAgICAgICAgICAgIG9ialtrZXldID0gdGhpc1trZXldO1xuICAgIH0sIHRoaXMpO1xuICAgIHJldHVybiBvYmo7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIG9iamVjdCBvZiB0aGUgc2FtZSBjbGFzcyB3aXRob3V0IHNwZWNpZmllZCBrZXlzLCB0aGF0IGFyZSBwYXNzZWQgYXMgc3RyaW5nIHBhcmFtZXRlcnMgb3IgYXJyYXkocykgb2Yga2V5cy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBhbiBvYmplY3QgdG8gb21pdCBrZXlzIGluXG4gKiBAcGFyYW0ge0xpc3RbU3RyaW5nfEFycmF5XX0gYXJndW1lbnRzIGxpc3Qgb2Yga2V5cyAob3IgYXJyYXkocykgb2Yga2V5cylcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gb21pdEtleXMoKSB7IC8vICwgLi4uIGtleXNcbiAgICB2YXIga2V5cyA9IGNvbmNhdC5hcHBseShBcnJheVByb3RvLCBhcmd1bWVudHMpXG4gICAgICAgICwgb2JqID0gY2xvbmUuY2FsbCh0aGlzKTtcbiAgICBrZXlzLmZvckVhY2goZnVuY3Rpb24oa2V5KXtcbiAgICAgICAgZGVsZXRlIG9ialtrZXldO1xuICAgIH0sIHRoaXMpO1xuICAgIHJldHVybiBvYmo7XG59XG5cblxuLyoqXG4gKiBQZXJmb3JtcyBkZWVwIGVxdWFsaXR5IHRlc3Qgb2YgdGhlIG9iamVjdC4gRG9lcyBub3Qgd29yayB3aXRoIHJlY3Vyc2l2ZSBvYmplY3RzXG4gKiBAcGFyYW0gIHtBbnl9IHNlbGYgb2JqZWN0IHRvIGNvbXBhcmVcbiAqIEBwYXJhbSAge0FueX0gb2JqIG9iamVjdCB0byBjb21wYXJlXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBpc0VxdWFsKG9iaikge1xuICAgIGlmICh0aGlzID09PSBvYmopIHJldHVybiB0aGlzICE9PSAwIHx8IDEvdGhpcyA9PSAxL29iajsgLy8gMCBhbmQgLTAgYXJlIGNvbnNpZGVyZWQgbm90IGVxdWFsLCBhbHRob3VnaCAwID09PSAtMCBpcyB0cnVlXG4gICAgaWYgKHRoaXMgPT0gbnVsbCB8fCBvYmogPT0gbnVsbCkgcmV0dXJuIGZhbHNlO1xuICAgIHZhciBjbGFzc05hbWUgPSB0aGlzLmNvbnN0cnVjdG9yLm5hbWU7XG4gICAgaWYgKGNsYXNzTmFtZSAhPSBvYmouY29uc3RydWN0b3IubmFtZSkgcmV0dXJuIGZhbHNlO1xuICAgIHN3aXRjaCAoY2xhc3NOYW1lKSB7XG4gICAgICAgIGNhc2UgJ1N0cmluZyc6XG4gICAgICAgICAgICByZXR1cm4gdGhpcyA9PSBTdHJpbmcob2JqKTtcbiAgICAgICAgY2FzZSAnTnVtYmVyJzpcbiAgICAgICAgICAgIHJldHVybiB0aGlzICE9ICt0aGlzID8gb2JqICE9ICtvYmogOiAodGhpcyA9PSAwID8gMS90aGlzID09IDEvb2JqIDogdGhpcyA9PSArb2JqKTtcbiAgICAgICAgY2FzZSAnRGF0ZSc6XG4gICAgICAgIGNhc2UgJ0Jvb2xlYW4nOlxuICAgICAgICAgICAgcmV0dXJuICt0aGlzID09ICtvYmo7XG4gICAgICAgIGNhc2UgJ1JlZ0V4cCc6XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zb3VyY2UgPT0gb2JqLnNvdXJjZVxuICAgICAgICAgICAgICAgICAgICAmJiB0aGlzLmdsb2JhbCA9PSBvYmouZ2xvYmFsXG4gICAgICAgICAgICAgICAgICAgICYmIHRoaXMubXVsdGlsaW5lID09IG9iai5tdWx0aWxpbmVcbiAgICAgICAgICAgICAgICAgICAgJiYgdGhpcy5pZ25vcmVDYXNlID09IG9iai5pZ25vcmVDYXNlO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIHRoaXMgIT0gJ29iamVjdCcgfHwgdHlwZW9mIG9iaiAhPSAnb2JqZWN0JykgcmV0dXJuIGZhbHNlO1xuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkodGhpcykpXG4gICAgICAgIHJldHVybiB0aGlzLmxlbmd0aCA9PSBvYmoubGVuZ3RoXG4gICAgICAgICAgICAgICAgJiYgdGhpcy5ldmVyeShmdW5jdGlvbihpdGVtLCBpbmRleCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaXNFcXVhbC5jYWxsKGl0ZW0sIG9ialtpbmRleF0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgIGVsc2Uge1xuICAgICAgICByZXR1cm4gYWxsS2V5cy5jYWxsKHRoaXMpLmxlbmd0aCA9PSBhbGxLZXlzLmNhbGwob2JqKS5sZW5ndGhcbiAgICAgICAgICAgICAgICAmJiBldmVyeUtleS5jYWxsKHRoaXMsIGZ1bmN0aW9uKHZhbHVlLCBrZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGlzRXF1YWwuY2FsbCh2YWx1ZSwgb2JqW2tleV0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIFRoZSBvcHBvc2l0ZSBvZiBpc0VxdWFsXG4gKiBAcGFyYW0gIHtBbnl9IHNlbGYgb2JqZWN0IHRvIGNvbXBhcmVcbiAqIEBwYXJhbSAge0FueX0gb2JqIG9iamVjdCB0byBjb21wYXJlXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBpc05vdChvYmopIHtcbiAgICByZXR1cm4gIWlzRXF1YWwuY2FsbCh0aGlzLCBvYmopO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIC0gW2V4dGVuZFByb3RvXSgjZXh0ZW5kUHJvdG8pXG4gKiAtIFtjcmVhdGVTdWJjbGFzc10oI2NyZWF0ZVN1YmNsYXNzKVxuICogLSBbbWFrZVN1YmNsYXNzXSgjbWFrZVN1YmNsYXNzKVxuICogLSBbbmV3QXBwbHldKCNuZXdBcHBseSlcbiAqXG4gKiBUaGVzZSBtZXRob2RzIGNhbiBiZSBbY2hhaW5lZF0ocHJvdG8uanMuaHRtbCNQcm90bylcbiAqL1xudmFyIHByb3RvdHlwZU1ldGhvZHMgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBleHRlbmRQcm90bzogZXh0ZW5kUHJvdG8sXG4gICAgY3JlYXRlU3ViY2xhc3M6IGNyZWF0ZVN1YmNsYXNzLFxuICAgIG1ha2VTdWJjbGFzczogbWFrZVN1YmNsYXNzLFxuICAgIG5ld0FwcGx5OiBuZXdBcHBseVxufTtcblxuXG52YXIgX18gPSByZXF1aXJlKCcuL3Byb3RvX29iamVjdCcpO1xuXG5fXy5leHRlbmQuY2FsbChfXywgcmVxdWlyZSgnLi9wcm90b19mdW5jdGlvbicpKTtcblxuXG4vKipcbiAqIEFkZHMgbm9uLWVudW1lcmFibGUsIG5vbi1jb25maWd1cmFibGUgYW5kIG5vbi13cml0YWJsZSBwcm9wZXJ0aWVzIHRvIHRoZSBwcm90b3R5cGUgb2YgY29uc3RydWN0b3IgZnVuY3Rpb24uXG4gKiBVc2FnZTpcbiAqIGBgYFxuICogZnVuY3Rpb24gTXlDbGFzcygpIHt9XG4gKiBfLmV4dGVuZFByb3RvKE15Q2xhc3MsIHtcbiAqICAgICBtZXRob2QxOiBmdW5jdGlvbigpIHt9LFxuICogICAgIG1ldGhvZDI6IGZ1bmN0aW9uKCkge31cbiAqIH0pO1xuICogYGBgXG4gKiBUbyBleHRlbmQgY2xhc3MgdmlhIG9iamVjdDpcbiAqIGBgYFxuICogXy5leHRlbmRQcm90byhvYmouY29uc3RydWN0b3IsIG1ldGhvZHMpO1xuICogYGBgXG4gKiBSZXR1cm5zIHBhc3NlZCBjb25zdHJ1Y3Rvciwgc28gZnVuY3Rpb25zIF8uZXh0ZW5kUHJvdG8sIFtfLmV4dGVuZF0ob2JqZWN0LmpzLmh0bWwjZXh0ZW5kKSBhbmQgXy5tYWtlU3ViY2xhc3MgY2FuIGJlIFtjaGFpbmVkXShwcm90by5qcy5odG1sKS4gXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gc2VsZiBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICogQHBhcmFtIHtPYmplY3R9IG1ldGhvZHMgYSBtYXAgb2YgZnVuY3Rpb25zLCBrZXlzIHdpbGwgYmUgaW5zdGFuY2UgbWV0aG9kcyAocHJvcGVydGllcyBvZiB0aGUgY29uc3RydWN0b3IgcHJvdG90eXBlKVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIGV4dGVuZFByb3RvKG1ldGhvZHMpIHtcbiAgICB2YXIgcHJvcERlc2NyaXB0b3JzID0ge307XG5cbiAgICBfXy5lYWNoS2V5LmNhbGwobWV0aG9kcywgZnVuY3Rpb24obWV0aG9kLCBuYW1lKSB7XG4gICAgICAgIHByb3BEZXNjcmlwdG9yc1tuYW1lXSA9IHtcbiAgICAgICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICAgICAgY29uZmlndXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIHdyaXRhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIHZhbHVlOiBtZXRob2RcbiAgICAgICAgfTtcbiAgICB9KTtcblxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMucHJvdG90eXBlLCBwcm9wRGVzY3JpcHRvcnMpO1xuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogTWFrZXMgYSBzdWJjbGFzcyBvZiBjbGFzcyBgdGhpc0NsYXNzYC5cbiAqIFRoZSByZXR1cm5lZCBmdW5jdGlvbiB3aWxsIGhhdmUgc3BlY2lmaWVkIGBuYW1lYCBpZiBzdXBwbGllZC5cbiAqIFRoZSBjb25zdHJ1Y3RvciBvZiBzdXBlcmNsYXNzIHdpbGwgYmUgY2FsbGVkIGluIHN1YmNsYXNzIGNvbnN0cnVjdG9yIGJ5IGRlZmF1bHQgdW5sZXNzIGBhcHBseUNvbnN0cnVjdG9yID09PSBmYWxzZWAgKG5vdCBqdXN0IGZhbHN5KS5cbiAqIENvcGllcyBgdGhpc0NsYXNzYCBjbGFzcyBtZXRob2RzIHRvIGNyZWF0ZWQgc3ViY2xhc3MuIEZvciB0aGVtIHRvIHdvcmsgY29ycmVjdGx5IHRoZXkgc2hvdWxkIHVzZSBgdGhpc2AgdG8gcmVmZXIgdG8gdGhlIGNsYXNzIHJhdGhlciB0aGFuIGV4cGxpY2l0IHN1cGVyY2xhc3MgbmFtZS5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzQ2xhc3MgQSBjbGFzcyB0byBtYWtlIHN1YmNsYXNzIG9mXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBPcHRpb25hbCBuYW1lIG9mIHN1YmNsYXNzIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGFwcGx5Q29uc3RydWN0b3IgT3B0aW9uYWwgZmFsc2UgdmFsdWUgKG5vdCBmYWxzeSkgdG8gcHJldmVudCBjYWxsIG9mIGluaGVyaXRlZCBjb25zdHJ1Y3RvciBpbiB0aGUgY29uc3RydWN0b3Igb2Ygc3ViY2xhc3NcbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBjcmVhdGVTdWJjbGFzcyhuYW1lLCBhcHBseUNvbnN0cnVjdG9yKSB7XG4gICAgdmFyIHRoaXNDbGFzcyA9IHRoaXM7XG4gICAgdmFyIHN1YmNsYXNzO1xuXG4gICAgLy8gbmFtZSBpcyBvcHRpb25hbFxuICAgIG5hbWUgPSBuYW1lIHx8ICcnO1xuXG4gICAgLy8gYXBwbHkgc3VwZXJjbGFzcyBjb25zdHJ1Y3RvclxuICAgIHZhciBjb25zdHJ1Y3RvckNvZGUgPSBhcHBseUNvbnN0cnVjdG9yID09PSBmYWxzZVxuICAgICAgICAgICAgPyAnJ1xuICAgICAgICAgICAgOiAndGhpc0NsYXNzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7JztcblxuICAgIGV2YWwoJ3N1YmNsYXNzID0gZnVuY3Rpb24gJyArIG5hbWUgKyAnKCl7ICcgKyBjb25zdHJ1Y3RvckNvZGUgKyAnIH0nKTtcblxuICAgIG1ha2VTdWJjbGFzcy5jYWxsKHN1YmNsYXNzLCB0aGlzQ2xhc3MpO1xuXG4gICAgLy8gY29weSBjbGFzcyBtZXRob2RzXG4gICAgLy8gLSBmb3IgdGhlbSB0byB3b3JrIGNvcnJlY3RseSB0aGV5IHNob3VsZCBub3QgZXhwbGljdGx5IHVzZSBzdXBlcmNsYXNzIG5hbWVcbiAgICAvLyBhbmQgdXNlIFwidGhpc1wiIGluc3RlYWRcbiAgICBfXy5kZWVwRXh0ZW5kLmNhbGwoc3ViY2xhc3MsIHRoaXNDbGFzcywgdHJ1ZSk7XG5cbiAgICByZXR1cm4gc3ViY2xhc3M7XG59XG5cblxuLyoqXG4gKiBTZXRzIHVwIHByb3RvdHlwZSBjaGFpbiB0byBjaGFuZ2UgYHRoaXNDbGFzc2AgKGEgY29uc3RydWN0b3IgZnVuY3Rpb24pIHNvIHRoYXQgaXQgYmVjb21lcyBhIHN1YmNsYXNzIG9mIGBTdXBlcmNsYXNzYC5cbiAqIFJldHVybnMgYHRoaXNDbGFzc2Agc28gaXQgY2FuIGJlIFtjaGFpbmVkXShwcm90by5qcy5odG1sKSB3aXRoIF8uZXh0ZW5kUHJvdG8gYW5kIFtfLmV4dGVuZF0ob2JqZWN0LmpzLmh0bWwjZXh0ZW5kKS5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzQ2xhc3MgQSBjbGFzcyB0aGF0IHdpbGwgYmVjb21lIGEgc3ViY2xhc3Mgb2YgU3VwZXJjbGFzc1xuICogQHBhcmFtIHtGdW5jdGlvbn0gU3VwZXJjbGFzcyBBIGNsYXNzIHRoYXQgd2lsbCBiZWNvbWUgYSBzdXBlcmNsYXNzIG9mIHRoaXNDbGFzc1xuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIG1ha2VTdWJjbGFzcyhTdXBlcmNsYXNzKSB7XG4gICAgLy8gcHJvdG90eXBlIGNoYWluXG4gICAgdGhpcy5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKFN1cGVyY2xhc3MucHJvdG90eXBlKTtcbiAgICBcbiAgICAvLyBzdWJjbGFzcyBpZGVudGl0eVxuICAgIGV4dGVuZFByb3RvLmNhbGwodGhpcywge1xuICAgICAgICBjb25zdHJ1Y3RvcjogdGhpc1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogQ2FsbHMgY29uc3RydWN0b3IgYHRoaXNgIHdpdGggYXJndW1lbnRzIHBhc3NlZCBhcyBhcnJheVxuICogXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzQ2xhc3MgQSBjbGFzcyBjb25zdHJ1Y3RvciB0aGF0IHdpbGwgYmUgY2FsbGVkXG4gKiBAcmV0dXJuIHtBcnJheXxBcnJheS1saWtlfSBhcmdzIEFycmF5IG9mIGFyZ3VtZW50cyB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIGNvbnN0cnVjdG9yXG4gKi9cbmZ1bmN0aW9uIG5ld0FwcGx5KGFyZ3MpIHtcbiAgICBpZiAoISBBcnJheS5pc0FycmF5KGFyZ3MpKVxuICAgICAgICBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJncyk7XG4gICAgLy8gXCJudWxsXCIgaXMgY29udGV4dCB0byBwYXNzIHRvIGNsYXNzIGNvbnN0cnVjdG9yLCBmaXJzdCBwYXJhbWV0ZXIgb2YgYmluZFxuICAgIHZhciBhcmdzID0gW251bGxdLmNvbmNhdChhcmdzKTtcbiAgICByZXR1cm4gbmV3IChGdW5jdGlvbi5wcm90b3R5cGUuYmluZC5hcHBseSh0aGlzLCBhcmdzKSk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIF9fID0gcmVxdWlyZSgnLi9wcm90b19vYmplY3QnKTtcblxuXG4vKipcbiAqIC0gW2ZpcnN0VXBwZXJDYXNlXSgjZmlyc3RVcHBlckNhc2UpXG4gKiAtIFtmaXJzdExvd2VyQ2FzZV0oI2ZpcnN0TG93ZXJDYXNlKVxuICogLSBbdG9SZWdFeHBdKCN0b1JlZ0V4cClcbiAqIC0gW3RvRnVuY3Rpb25dKCN0b0Z1bmN0aW9uKVxuICogLSBbdG9EYXRlXSgjdG9EYXRlKVxuICogLSBbdG9RdWVyeVN0cmluZ10oI3RvUXVlcnlTdHJpbmcpXG4gKiAtIFtmcm9tUXVlcnlTdHJpbmddKCNmcm9tUXVlcnlTdHJpbmcpXG4gKiAtIFtqc29uUGFyc2VdKCNqc29uUGFyc2UpXG4gKiAtIFtoYXNoQ29kZV0oI2hhc2hDb2RlKVxuICogLSBbdW5QcmVmaXhdKCN1blByZWZpeClcbiAqL1xuIHZhciBzdHJpbmdNZXRob2RzID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgZmlyc3RVcHBlckNhc2U6IGZpcnN0VXBwZXJDYXNlLFxuICAgIGZpcnN0TG93ZXJDYXNlOiBmaXJzdExvd2VyQ2FzZSxcbiAgICB0b1JlZ0V4cDogdG9SZWdFeHAsXG4gICAgdG9GdW5jdGlvbjogdG9GdW5jdGlvbixcbiAgICB0b0RhdGU6IHRvRGF0ZSxcbiAgICB0b1F1ZXJ5U3RyaW5nOiB0b1F1ZXJ5U3RyaW5nLFxuICAgIGZyb21RdWVyeVN0cmluZzogZnJvbVF1ZXJ5U3RyaW5nLFxuICAgIGpzb25QYXJzZToganNvblBhcnNlLFxuICAgIGhhc2hDb2RlOiBoYXNoQ29kZSxcbiAgICB1blByZWZpeDogdW5QcmVmaXhcbn07XG5cblxuLyoqXG4gKiBSZXR1cm5zIHN0cmluZyB3aXRoIHRoZSBmaXJzdCBjaGFyYWN0ZXIgY2hhbmdlZCB0byB1cHBlciBjYXNlLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzZWxmIEEgc3RyaW5nIHRoYXQgd2lsbCBoYXZlIGl0cyBmaXJzdCBjaGFyYWN0ZXIgcmVwbGFjZWRcbiAqL1xuZnVuY3Rpb24gZmlyc3RVcHBlckNhc2UoKSB7XG4gICAgcmV0dXJuIHRoaXMgPyB0aGlzWzBdLnRvVXBwZXJDYXNlKCkgKyB0aGlzLnNsaWNlKDEpIDogdGhpcztcbn1cblxuXG4vKipcbiAqIFJldHVybnMgc3RyaW5nIHdpdGggdGhlIGZpcnN0IGNoYXJhY3RlciBjaGFuZ2VkIHRvIGxvd2VyIGNhc2UuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHNlbGYgQSBzdHJpbmcgdGhhdCB3aWxsIGhhdmUgaXRzIGZpcnN0IGNoYXJhY3RlciByZXBsYWNlZFxuICovXG5mdW5jdGlvbiBmaXJzdExvd2VyQ2FzZSgpIHtcbiAgICByZXR1cm4gdGhpcyA/IHRoaXNbMF0udG9Mb3dlckNhc2UoKSArIHRoaXMuc2xpY2UoMSkgOiB0aGlzO1xufVxuXG5cbi8qKlxuICogQ29udmVydHMgc3RyaW5nIGNyZWF0ZWQgYnkgYHRvU3RyaW5nYCBtZXRob2Qgb2YgUmVnRXhwIGJhY2sgdG8gUmVnRXhwXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHNlbGYgc3RyaW5nIGNvbnRhaW5pbmcgcmVndWxhciBleHByZXNzaW9uIGluY2x1ZGluZyBlbmNsb3NpbmcgXCIvXCIgc3ltYm9scyBhbmQgZmxhZ3NcbiAqIEByZXR1cm4ge1JlZ0V4cH1cbiAqL1xuZnVuY3Rpb24gdG9SZWdFeHAoKSB7XG4gICAgdmFyIHJ4ID0gdGhpcy5tYXRjaChyZWdleHBTdHJpbmdQYXR0ZXJuKTtcbiAgICBpZiAocngpIHJldHVybiBuZXcgUmVnRXhwKHJ4WzFdLCByeFsyXSk7XG59XG52YXIgcmVnZXhwU3RyaW5nUGF0dGVybiA9IC9eXFwvKC4qKVxcLyhbZ2lteV0qKSQvO1xuXG5cbi8qKlxuICogQ29udmVydHMgc3RyaW5nIGNyZWF0ZWQgYnkgYHRvU3RyaW5nYCBtZXRob2Qgb2YgZnVuY3Rpb24gYmFjayB0byBmdW5jdGlvblxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzZWxmIHN0cmluZyBjb250YWluaW5nIGZ1bGwgZnVuY3Rpb24gY29kZVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIHRvRnVuY3Rpb24oKSB7XG4gICAgdmFyIGZ1bmM7XG4gICAgdmFyIGNvZGUgPSAnZnVuYyA9ICcgKyB0aGlzICsgJzsnO1xuICAgIHRyeSB7XG4gICAgICAgIGV2YWwoY29kZSk7XG4gICAgICAgIHJldHVybiBmdW5jO1xuICAgIH0gY2F0Y2goZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxufVxuXG5cbi8qKlxuICogQ29udmVydHMgc3RyaW5nIHRvIGRhdGUgaW4gYSBzYWZlIHdheSBzbyB0aGF0IHRoZSByZXNpdWx0IGlzIHVuZGVmaW5lZCBpZiBkYXRlIGlzIGludmFsaWRcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ3xEYXRlfSBzZWxmIHN0cmluZyBvciBkYXRlIG9iamVjdCB0byBjb252ZXJ0IHRvIFZBTElEIGRhdGVcbiAqIEByZXR1cm4ge1t0eXBlXX0gW2Rlc2NyaXB0aW9uXVxuICovXG5mdW5jdGlvbiB0b0RhdGUoKSB7XG4gICAgaWYgKCEgdGhpcykgcmV0dXJuO1xuICAgIHRyeSB7XG4gICAgICAgIHZhciBkYXRlID0gbmV3IERhdGUodGhpcyk7XG4gICAgfSBjYXRjaCAoZSkge31cbiAgICBpZiAoZGF0ZSAmJiBkYXRlLmdldFRpbWUgJiYgIWlzTmFOKGRhdGUuZ2V0VGltZSgpKSlcbiAgICAgICAgcmV0dXJuIGRhdGU7XG59XG5cblxuLyoqXG4gKiBDb252ZXJ0IHBhcmFtcyBvYmplY3QgdG8gYSB1cmwgc3R5bGUgcXVlcnkgc3RyaW5nICh3aXRob3V0IFwiP1wiKVxuICogXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBUaGUgb2JqZWN0IGhhc2ggdG8gYmUgY29udmVydGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmNvZGUgb3B0aW9uYWwgZnVuY3Rpb24gdXNlZCB0byBlbmNvZGUgZGF0YSwgZW5jb2RlVVJJQ29tcG9uZW50IGlzIHVzZWQgaWYgbm90IHNwZWNpZmllZFxuICogQHJldHVybiB7U3RyaW5nfSB0aGUgcmVzdWx0aW5nIHF1ZXJ5IHN0cmluZ1xuICovXG5mdW5jdGlvbiB0b1F1ZXJ5U3RyaW5nKGVuY29kZSkge1xuICAgIHZhciBxcyA9ICcnXG4gICAgICAgICwgcGFyYW1zID0gdGhpcyB8fCB7fVxuICAgICAgICAsIGVuY29kZSA9IGVuY29kZSB8fCBlbmNvZGVVUklDb21wb25lbnQ7XG5cbiAgICBfXy5lYWNoS2V5LmNhbGwocGFyYW1zLCBmdW5jdGlvbih2YWx1ZSwga2V5KSB7XG4gICAgICAgIHFzICs9IGtleSArICc9JyArIGVuY29kZSh2YWx1ZSkgKyAnJic7XG4gICAgfSk7XG4gICAgXG4gICAgcmV0dXJuIHFzLnNsaWNlKDAsIC0xKTtcbn1cblxuXG4vKipcbiAqIENvbnZlcnQgdXJsIHN0eWxlIHF1ZXJ5IHN0cmluZyAod2l0aG91dCBcIj9cIikgaW50byBvYmplY3QgaGFzaFxuICogXG4gKiBAcGFyYW0ge1N0cmluZ30gc2VsZiBUaGUgc3RyaW5nIHRvIGJlIGNvbnZlcnRlZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gZGVjb2RlIG9wdGlvbmFsIGRlY29kZSBmdW5jdGlvbiwgZGVjb2RlVVJJQ29tcG9uZW50IHdpbGwgYmUgdXNlZCBpZiBub3Qgc3VwcGxpZWRcbiAqIEByZXR1cm4ge09iamVjdH0gVGhlIHJlc3VsdGluZyBvYmplY3QgaGFzaFxuICovXG5mdW5jdGlvbiBmcm9tUXVlcnlTdHJpbmcoZGVjb2RlKSB7XG4gICAgdmFyIHBhaXJzID0gdGhpcy5zcGxpdCgnJicpXG4gICAgICAgICwgcmVzdWx0cyA9IHt9XG4gICAgICAgICwgZGVjb2RlID0gZGVjb2RlIHx8IGRlY29kZVVSSUNvbXBvbmVudDtcblxuICAgIHBhaXJzLmZvckVhY2goZnVuY3Rpb24ocGFpcikge1xuICAgICAgICB2YXIgc3BsaXRQYWlyID0gcGFpci5zcGxpdCgnPScpO1xuICAgICAgICBpZiAoc3BsaXRQYWlyLmxlbmd0aCA8IDIpIHJldHVybjtcbiAgICAgICAgdmFyIGtleSA9IHNwbGl0UGFpclswXVxuICAgICAgICAgICAgLCB2YWx1ZSA9IGRlY29kZShzcGxpdFBhaXJbMV0gfHwgJycpO1xuICAgICAgICBpZiAoIWtleSkgcmV0dXJuO1xuICAgICAgICByZXN1bHRzW2tleV0gPSB2YWx1ZTtcbiAgICB9KTtcblxuICAgIHJldHVybiByZXN1bHRzO1xufVxuXG5cbi8qKlxuICogU2FmZSBKU09OLnBhcnNlLCByZXR1cm5zIHVuZGVmaW5lZCBpZiBKU09OLnBhcnNlIHRocm93cyBhbiBleGNlcHRpb25cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gc2VsZiBKU09OIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBvYmplY3RcbiAqIEByZXR1cm4ge09iamVjdHx1bmRlZmluZWR9XG4gKi9cbmZ1bmN0aW9uIGpzb25QYXJzZSgpIHtcbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZSh0aGlzKTtcbiAgICB9IGNhdGNoIChlKSB7fVxufVxuXG5cbi8qKlxuICogRGFuIEJlcm5zdGVpbidzIGFsZ29yeXRobSB0byBjcmVhdGUgaGFzaCBmcm9tIHN0cmluZ1xuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzZWxmIHN0cmluZyB0byBjb252ZXJ0IHRvIGhhc2hcbiAqIEByZXR1cm4ge051bWJlcn1cbiAqL1xuZnVuY3Rpb24gaGFzaENvZGUoKSB7XG4gICAgdmFyIGhhc2ggPSA1MzgxXG4gICAgICAgICwgc3RyID0gdGhpc1xuICAgICAgICAsIGxlbiA9IHN0ci5sZW5ndGg7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgICB2YXIgY2hhciA9IHN0ci5jaGFyQ29kZUF0KGkpO1xuICAgICAgICBoYXNoID0gKChoYXNoIDw8IDUpICsgaGFzaCkgKyBjaGFyOyAvKiBoYXNoICogMzMgKyBjICovXG4gICAgfVxuICAgIHJldHVybiBoYXNoO1xufVxuXG5cbi8qKlxuICogUmVtb3ZlcyBnaXZlbiBwcmVmaXggZnJvbSB0aGUgc3RyaW5nLiBJZiBzdHJpbmcgZG9lcyBub3QgYmVnaW4gZnJvbSB0aGUgcHJlZml4LCByZXR1cm5zIHVuZGVmaW5lZFxuICogXG4gKiBAcGFyYW0ge1N0cmluZ30gc2VsZlxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiB1blByZWZpeChzdHIpIHtcbiAgICBpZiAodGhpcy5pbmRleE9mKHN0cikgPT0gMClcbiAgICAgICAgcmV0dXJuIHRoaXMucmVwbGFjZShzdHIsICcnKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiAtIFt0aW1lc10oI3RpbWVzKVxuICogLSBbcmVwZWF0XSgjcmVwZWF0KVxuICogLSBbdGFwXSgjdGFwKVxuICogLSBbcmVzdWx0XSgjcmVzdWx0KVxuICogLSBbaWRlbnRpdHldKCNpZGVudGl0eSlcbiAqIC0gW3Byb3BlcnR5XSgjcHJvcGVydHkpXG4gKiAtIFtjb21wYXJlUHJvcGVydHldKCNjb21wYXJlUHJvcGVydHkpXG4gKiAtIFtub29wXSgjbm9vcClcbiAqL1xudmFyIHV0aWxNZXRob2RzID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgdGltZXM6IHRpbWVzLFxuICAgIHJlcGVhdDogcmVwZWF0LFxuICAgIHRhcDogdGFwLFxuICAgIHJlc3VsdDogcmVzdWx0LFxuICAgIGlkZW50aXR5OiBpZGVudGl0eSxcbiAgICBwcm9wZXJ0eTogcHJvcGVydHksXG4gICAgY29tcGFyZVByb3BlcnR5OiBjb21wYXJlUHJvcGVydHksXG4gICAgbm9vcDogbm9vcFxufTtcblxuXG4vKipcbiAqIENhbGxzIGBjYWxsYmFja2AgYHNlbGZgIHRpbWVzIHdpdGggYHRoaXNBcmdgIGFzIGNvbnRleHQuIENhbGxiYWNrIGlzIHBhc3NlZCBpdGVyYXRpb24gaW5kZXggZnJvbSAwIHRvIGBzZWxmLTFgXG4gKiBcbiAqIEBwYXJhbSB7SW50ZWdlcn0gc2VsZlxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7QW55fSB0aGlzQXJnXG4gKiBAcmV0dXJuIHtBcnJheX1cbiAqL1xuZnVuY3Rpb24gdGltZXMoY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICB2YXIgYXJyID0gQXJyYXkoTWF0aC5tYXgoMCwgdGhpcykpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpczsgaSsrKVxuICAgICAgICBhcnJbaV0gPSBjYWxsYmFjay5jYWxsKHRoaXNBcmcsIGkpO1xuICAgIHJldHVybiBhcnI7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGFycmF5IHdpdGggdGhlIGZpcnN0IGFyZ3VtZW50IHJlcGVhdGVkIGB0aW1lc2AgdGltZXNcbiAqIEBwYXJhbSAge0FueX0gc2VsZlxuICogQHBhcmFtICB7SW50ZWdlcn0gdGltZXNcbiAqIEByZXR1cm4ge0FycmF5W0FueV19XG4gKi9cbmZ1bmN0aW9uIHJlcGVhdCh0aW1lcykge1xuICAgIHZhciBhcnIgPSBBcnJheShNYXRoLm1heCgwLCB0aW1lcykpOztcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRpbWVzOyBpKyspXG4gICAgICAgIGFycltpXSA9IHRoaXM7XG4gICAgcmV0dXJuIGFycjtcbn1cblxuXG4vKipcbiAqIEZ1bmN0aW9uIHRvIHRhcCBpbnRvIGNoYWluZWQgbWV0aG9kcyBhbmQgdG8gaW5zcGVjdCBpbnRlcm1lZGlhcnkgcmVzdWx0XG4gKlxuICogQHBhcmFtIHtBbnl9IHNlbGYgdmFsdWUgdGhhdCdzIHBhc3NlZCBiZXR3ZWVuIGNoYWluZWQgbWV0aG9kc1xuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgY2FsbGVkIHdpdGggdGhlIHZhbHVlIChib3RoIGFzIGNvbnRleHQgYW5kIGFzIHRoZSBmaXJzdCBwYXJhbWV0ZXIpXG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmZ1bmN0aW9uIHRhcChmdW5jKSB7XG4gICAgZnVuYy5jYWxsKHRoaXMsIHRoaXMpO1xuICAgIHJldHVybiB0aGlzO1xufTtcblxuXG4vKipcbiAqIENhbGxzIGZ1bmN0aW9uIGBzZWxmYCAoZmlyc3QgcGFyYW1ldGVyIG9mIF8ucmVzdWx0KSB3aXRoIGdpdmVuIGNvbnRleHQgYW5kIGFyZ3VtZW50c1xuICogXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufEFueX0gc2VsZlxuICogQHBhcmFtIHtBbnl9IHRoaXNBcmcgY29udGV4dFxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgZXh0cmEgYXJndW1lbnRzXG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmZ1bmN0aW9uIHJlc3VsdCh0aGlzQXJnKSB7IC8vLCBhcmd1bWVudHNcbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgcmV0dXJuIHR5cGVvZiB0aGlzID09ICdmdW5jdGlvbidcbiAgICAgICAgICAgID8gdGhpcy5hcHBseSh0aGlzQXJnLCBhcmdzKVxuICAgICAgICAgICAgOiB0aGlzO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBzZWxmLiBVc2VmdWwgZm9yIHVzaW5nIGFzIGFuIGl0ZXJhdG9yIGlmIHRoZSBhY3R1YWwgdmFsdWUgbmVlZHMgdG8gYmUgcmV0dXJuZWQuIFVubGlrZSBpbiB1bmRlcnNjb3JlIGFuZCBsb2Rhc2gsIHRoaXMgZnVuY3Rpb24gaXMgTk9UIHVzZWQgYXMgZGVmYXVsdCBpdGVyYXRvci5cbiAqXG4gKiBAcGFyYW0ge0FueX0gc2VsZiBcbiAqIEByZXR1cm4ge0FueX1cbiAqL1xuZnVuY3Rpb24gaWRlbnRpdHkoKSB7XG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGZ1bmN0aW9uIHRoYXQgcGlja3MgdGhlIHByb3BlcnR5IGZyb20gdGhlIG9iamVjdFxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzZWxmXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gcHJvcGVydHkoKSB7XG4gICAgdmFyIGtleSA9IHRoaXM7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKG9iaikge1xuICAgICAgICByZXR1cm4gb2JqW2tleV07XG4gICAgfTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZCBpbiBhcnJheSBzb3J0IHRvIHNvcnQgYnkgYSBnaXZlbiBwcm9wZXJ0eVxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzZWxmXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gY29tcGFyZVByb3BlcnR5KCkge1xuICAgIHZhciBrZXkgPSB0aGlzO1xuICAgIHJldHVybiBmdW5jdGlvbihhLCBiKSB7XG4gICAgICAgIHJldHVybiBhW2tleV0gPCBiW2tleV1cbiAgICAgICAgICAgID8gLTFcbiAgICAgICAgICAgIDogYVtrZXldID4gYltrZXldXG4gICAgICAgICAgICAgICAgPyAxXG4gICAgICAgICAgICAgICAgOiAwO1xuICAgIH07XG59XG5cblxuLyoqXG4gKiBGdW5jdGlvbiB0aGF0IGRvZXMgbm90aGluZ1xuICovXG5mdW5jdGlvbiBub29wKCkge31cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHV0aWxzID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgbWFrZVByb3RvSW5zdGFuY2VNZXRob2Q6IG1ha2VQcm90b0luc3RhbmNlTWV0aG9kLFxuICAgIG1ha2VQcm90b0Z1bmN0aW9uOiBtYWtlUHJvdG9GdW5jdGlvbixcbiAgICBtYWtlRmluZE1ldGhvZDogbWFrZUZpbmRNZXRob2Rcbn1cblxuXG5mdW5jdGlvbiBtYWtlUHJvdG9JbnN0YW5jZU1ldGhvZChtZXRob2QpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIHRoaXMuc2VsZiA9IG1ldGhvZC5hcHBseSh0aGlzLnNlbGYsIGFyZ3VtZW50cyk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG59XG5cblxuZnVuY3Rpb24gbWFrZVByb3RvRnVuY3Rpb24obWV0aG9kKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICAvLyB3aGVuIHRoZSBtZXRob2QgaXMgZXhlY3V0ZWQsIHRoZSB2YWx1ZSBvZiBcInRoaXNcIiB3aWxsIGJlIGFyZ3VtZW50c1swXSxcbiAgICAgICAgLy8gb3RoZXIgYXJndW1lbnRzIHN0YXJ0aW5nIGZyb20gIzEgd2lsbCBwYXNzZWQgdG8gbWV0aG9kIGFzIHBhcmFtZXRlcnMuXG4gICAgICAgIHJldHVybiBtZXRob2QuY2FsbC5hcHBseShtZXRob2QsIGFyZ3VtZW50cyk7XG4gICAgfTtcbn1cblxuXG52YXIgX2Vycm9yID0gbmV3IEVycm9yO1xuXG4vKipcbiAqIFJldHVybnMgYGZpbmRgIG9yIGBmaW5kSW5kZXhgIG1ldGhvZCwgZGVwZW5kaW5nIG9uIHBhcmFtZXRlclxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVhY2hNZXRob2QgLSBtZXRob2QgdG8gdXNlIGZvciBpdGVyYXRpb24gKGZvckVhY2ggZm9yIGFycmF5IG9yIGVhY2hLZXkgZm9yIG9iamVjdClcbiAqIEBwYXJhbSB7U3RyaW5nfSBmaW5kV2hhdCAndmFsdWUnIC0gcmV0dXJucyBmaW5kIG1ldGhvZCBvZiBBcnJheSAoaW1wbGVtZW50ZWQgaW4gRVM2KSBvciBmaW5kVmFsdWUgbWV0aG9kIG9mIE9iamVjdCwgYW55dGhpbmcgZWxzZSA9IHJldHVybnMgZmluZEluZGV4L2ZpbmRLZXkgbWV0aG9kcy5cbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBtYWtlRmluZE1ldGhvZChlYWNoTWV0aG9kLCBmaW5kV2hhdCkge1xuICAgIHZhciBhcmdJbmRleCA9IGZpbmRXaGF0ID09ICd2YWx1ZScgPyAwIDogMTtcblxuICAgIHJldHVybiBmdW5jdGlvbiBmaW5kVmFsdWVPckluZGV4KGNhbGxiYWNrLCB0aGlzQXJnLCBvbmx5RW51bWVyYWJsZSkge1xuICAgICAgICB2YXIgY2F1Z2h0RXJyb3I7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBlYWNoTWV0aG9kLmNhbGwodGhpcywgdGVzdEl0ZW0sIHRoaXNBcmcsIG9ubHlFbnVtZXJhYmxlKTtcbiAgICAgICAgfSBjYXRjaCAoZm91bmQpIHtcbiAgICAgICAgICAgIGlmIChmb3VuZCA9PT0gX2Vycm9yKSB0aHJvdyBjYXVnaHRFcnJvcjtcbiAgICAgICAgICAgIGVsc2UgcmV0dXJuIGZvdW5kO1xuICAgICAgICB9XG4gICAgICAgIC8vIGlmIGxvb2tpbmcgZm9yIGluZGV4IGFuZCBub3QgZm91bmQsIHJldHVybiAtMVxuICAgICAgICBpZiAoYXJnSW5kZXggJiYgZWFjaE1ldGhvZCA9PSBBcnJheS5wcm90b3R5cGUuZm9yRWFjaClcbiAgICAgICAgICAgIHJldHVybiAtMTsgXG5cbiAgICAgICAgZnVuY3Rpb24gdGVzdEl0ZW0odmFsdWUsIGluZGV4LCBzZWxmKSB7XG4gICAgICAgICAgICB2YXIgdGVzdDtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdGVzdCA9IGNhbGxiYWNrLmNhbGwodGhpcywgdmFsdWUsIGluZGV4LCBzZWxmKTtcbiAgICAgICAgICAgIH0gY2F0Y2goZXJyKSB7XG4gICAgICAgICAgICAgICAgY2F1Z2h0RXJyb3IgPSBlcnI7XG4gICAgICAgICAgICAgICAgdGhyb3cgX2Vycm9yO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRlc3QpXG4gICAgICAgICAgICAgICAgdGhyb3cgYXJndW1lbnRzW2FyZ0luZGV4XTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsImFyZ3VtZW50c1s0XVsxNDFdWzBdLmFwcGx5KGV4cG9ydHMsYXJndW1lbnRzKSIsImFyZ3VtZW50c1s0XVsxNDJdWzBdLmFwcGx5KGV4cG9ydHMsYXJndW1lbnRzKSIsImFyZ3VtZW50c1s0XVsxNDZdWzBdLmFwcGx5KGV4cG9ydHMsYXJndW1lbnRzKSIsImFyZ3VtZW50c1s0XVsxNDddWzBdLmFwcGx5KGV4cG9ydHMsYXJndW1lbnRzKSJdfQ==
+},{}]},{},[66])
+//@ sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvYWJzdHJhY3QvZmFjZXQuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2Fic3RyYWN0L2ZhY2V0ZWRfb2JqZWN0LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9hYnN0cmFjdC9yZWdpc3RyeS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvYXR0cmlidXRlcy9hX2JpbmQuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2F0dHJpYnV0ZXMvYV9jbGFzcy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvYXR0cmlidXRlcy9hX2xvYWQuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2F0dHJpYnV0ZXMvaW5kZXguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2JpbmRlci5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY2xhc3Nlcy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tbWFuZC9hY3Rpb25zX2hpc3RvcnkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbW1hbmQvY21kX3JlZ2lzdHJ5LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21tYW5kL2luZGV4LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21tYW5kL3RyYW5zYWN0aW9uLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21tYW5kL3RyYW5zYWN0aW9uX2hpc3RvcnkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19jbGFzcy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX2ZhY2V0LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL0NvbnRhaW5lci5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX2ZhY2V0cy9EYXRhLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL0RvbS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX2ZhY2V0cy9EcmFnLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL0Ryb3AuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19mYWNldHMvRXZlbnRzLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL0ZyYW1lLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL0l0ZW0uanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19mYWNldHMvTGlzdC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jX2ZhY2V0cy9Nb2RlbEZhY2V0LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfZmFjZXRzL09wdGlvbnMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19mYWNldHMvVGVtcGxhdGUuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19mYWNldHMvVHJhbnNmZXIuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19mYWNldHMvY2ZfcmVnaXN0cnkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY19pbmZvLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL2NfcmVnaXN0cnkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvY191dGlscy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9jbGFzc2VzL1ZpZXcuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvbXNnX2FwaS9kYXRhLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL21zZ19hcGkvZGVfZGF0YS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy9tc2dfYXBpL2Ryb3AuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvbXNnX3NyYy9kb21fZXZlbnRzLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL21zZ19zcmMvZnJhbWUuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvc2NvcGUuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvQnV0dG9uLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0NvbWJvLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0NvbWJvTGlzdC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9EYXRlLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0Ryb3BUYXJnZXQuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvRm9sZFRyZWUuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvR3JvdXAuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvSHlwZXJsaW5rLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0ltYWdlLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0lucHV0LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0lucHV0TGlzdC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9MaXN0LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL0xpc3RJdGVtLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL1JhZGlvR3JvdXAuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvU2VsZWN0LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL1N1cGVyQ29tYm8uanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvVGV4dC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9UZXh0YXJlYS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvY29tcG9uZW50cy91aS9UaW1lLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL1dyYXBwZXIuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvYm9vdHN0cmFwL0FsZXJ0LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb21wb25lbnRzL3VpL2Jvb3RzdHJhcC9EaWFsb2cuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2NvbXBvbmVudHMvdWkvYm9vdHN0cmFwL0Ryb3Bkb3duLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi9jb25maWcuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL2xvYWRlci5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvbWlsby5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvcmVnaXN0cnkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL2RlX2NvbnN0cnMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL2RvbV9zb3VyY2UuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL21haWwvaW5kZXguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL21haWwvbWFpbF9hcGkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL21haWwvbWFpbF9zb3VyY2UuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3NlcnZpY2VzL3dpbmRvdy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXNlX2NvbXBvbmVudHMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3VzZV9mYWNldHMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvY29tcG9uZW50X25hbWUuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvY291bnQuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvY3JlYXRlX2NvbXBvbmVudF9jbGFzcy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9kb20uanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvZG9tX2xpc3RlbmVycy5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9kb21yZWFkeS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9kcmFnZHJvcC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9lcnJvci5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9mcmFnbWVudC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9pbmRleC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9qc29uX3BhcnNlLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi91dGlsL3JlcXVlc3QuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvc2VsZWN0aW9uL2luZGV4LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi91dGlsL3N0b3JhZ2UvaW5kZXguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvc3RvcmFnZS9tb2RlbC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9saWIvdXRpbC9zdG9yYWdlL21zZ19zcmMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbGliL3V0aWwvd2Vic29ja2V0L2luZGV4LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi91dGlsL3dlYnNvY2tldC9tc2dfYXBpLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL2xpYi91dGlsL3dlYnNvY2tldC9tc2dfc3JjLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9iYXNlMzIvbGliL2Jhc2UzMi5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3Nlci1idWlsdGlucy9idWlsdGluL2ZzLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL2Fic3RyYWN0L21peGluLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL2NsYXNzZXMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvY29uZmlnLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21lc3Nlbmdlci9pbmRleC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9tZXNzZW5nZXIvbV9hcGkuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvbWVzc2VuZ2VyL21fYXBpX3J4LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21lc3Nlbmdlci9tX3NvdXJjZS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9tZXNzZW5nZXIvbXNuZ3Jfc291cmNlLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21pbG8tY29yZS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9taW5kZXIuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvbW9kZWwvY2hhbmdlX2RhdGEuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvbW9kZWwvY29ubmVjdG9yLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21vZGVsL2luZGV4LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21vZGVsL21fbXNnX2FwaS5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi9tb2RlbC9tX3BhdGguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvbW9kZWwvbW9kZWxfdXRpbHMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvbW9kZWwvcGF0aF9tc2dfYXBpLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL21vZGVsL3BhdGhfdXRpbHMuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvbW9kZWwvc3ludGhlc2l6ZS9pbmRleC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL2xpYi91dGlsL2NoZWNrLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbGliL3V0aWwvaW5kZXguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvdXRpbC9sb2dnZXIuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9saWIvdXRpbC9sb2dnZXJfY2xhc3MuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9ub2RlX21vZHVsZXMvZG90L2RvVC5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL25vZGVfbW9kdWxlcy9kb3QvaW5kZXguanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9ub2RlX21vZHVsZXMvbW9sLXByb3RvL2xpYi9wcm90by5qcyIsIi9Vc2Vycy9ldmdlbnlwb2JlcmV6a2luL1dvcmsvQ0MvbWlsby9ub2RlX21vZHVsZXMvbWlsby1jb3JlL25vZGVfbW9kdWxlcy9tb2wtcHJvdG8vbGliL3Byb3RvX2FycmF5LmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbm9kZV9tb2R1bGVzL21vbC1wcm90by9saWIvcHJvdG9fZnVuY3Rpb24uanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9ub2RlX21vZHVsZXMvbW9sLXByb3RvL2xpYi9wcm90b19udW1iZXIuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9ub2RlX21vZHVsZXMvbW9sLXByb3RvL2xpYi9wcm90b19vYmplY3QuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9ub2RlX21vZHVsZXMvbW9sLXByb3RvL2xpYi9wcm90b19wcm90b3R5cGUuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9ub2RlX21vZHVsZXMvbW9sLXByb3RvL2xpYi9wcm90b19zdHJpbmcuanMiLCIvVXNlcnMvZXZnZW55cG9iZXJlemtpbi9Xb3JrL0NDL21pbG8vbm9kZV9tb2R1bGVzL21pbG8tY29yZS9ub2RlX21vZHVsZXMvbW9sLXByb3RvL2xpYi9wcm90b191dGlsLmpzIiwiL1VzZXJzL2V2Z2VueXBvYmVyZXpraW4vV29yay9DQy9taWxvL25vZGVfbW9kdWxlcy9taWxvLWNvcmUvbm9kZV9tb2R1bGVzL21vbC1wcm90by9saWIvdXRpbHMuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL01BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4NUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbHBCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeE5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbElBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5SUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4UUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0lBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9tQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9DQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdlFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDalVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4YkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbk1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbE5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdnBCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDek9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbk9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdlNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25HQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdFhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL01BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeE9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdllBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3puQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIid1c2Ugc3RyaWN0JztcblxuXG52YXIgXyA9IHJlcXVpcmUoJ21pbG8tY29yZScpLnByb3RvO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZhY2V0O1xuXG5cbi8qKlxuICogYG1pbG8uY2xhc3Nlcy5GYWNldGBcbiAqIEJhc2UgRmFjZXQgY2xhc3MgaXMgYW4gYW5jZXN0b3Igb2YgW0NvbXBvbmVudEZhY2V0XSguLi9jb21wb25lbnRzL2NfZmFjZXQuanMuaHRtbCkgY2xhc3MsIHRoZSBtYWluIGJ1aWxkaW5nIGJsb2NrIGluIG1pbG8uXG4gKiBcbiAqIEBwYXJhbSB7RmFjZXRlZE9iamVjdH0gb3duZXIgYW4gaW5zdGFuY2Ugb2YgRmFjZXRlZE9iamVjdCBzdWJjbGFzcyB0aGF0IHN0b3JlcyB0aGUgZmFjZXQgb24gaXRzIHByb3BlcnR5ICB3aXRoIHRoZSBzYW1lIG5hbWUgYXMgYG5hbWVgIHByb3BlcnR5IG9mIGZhY2V0XG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIG9wdGlvbmFsIGZhY2V0IGNvbmZpZ3VyYXRpb24sIHVzZWQgaW4gc3ViY2xhc3Nlc1xuICovXG5mdW5jdGlvbiBGYWNldChvd25lciwgY29uZmlnKSB7XG4gICAgdGhpcy5uYW1lID0gXy5maXJzdExvd2VyQ2FzZSh0aGlzLmNvbnN0cnVjdG9yLm5hbWUpO1xuICAgIHRoaXMub3duZXIgPSBvd25lcjtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZyB8fCB7fTtcbiAgICB0aGlzLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuXG4vKipcbiAqIGBpbml0YCBtZXRob2Qgb2Ygc3ViY2xhc3Mgd2lsbCBiZSBjYWxsZWQgYnkgRmFjZXQgY29uc3RydWN0b3IuXG4gKi9cbl8uZXh0ZW5kUHJvdG8oRmFjZXQsIHtcbiAgICBpbml0OiBmdW5jdGlvbigpIHt9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgRmFjZXQgPSByZXF1aXJlKCcuL2ZhY2V0JylcbiAgICAsIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgY2hlY2sgPSBtaWxvQ29yZS51dGlsLmNoZWNrXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZhY2V0ZWRPYmplY3Q7XG5cblxuLyoqXG4gKiBgbWlsby5jbGFzc2VzLkZhY2V0ZWRPYmplY3RgXG4gKiBDb21wb25lbnQgY2xhc3MgaXMgYmFzZWQgb24gYW4gYWJzdHJhY3QgYGBgRmFjZXRlZE9iamVjdGBgYCBjbGFzcy4gVGhpcyBjbGFzcyBjYW4gYmUgdXNlZCBpbiBhbnkgc2l0dWF0aW9uIHdoZXJlIG9iamVjdHMgY2FuIGJlIHJlcHJlc2VudGVkIHZpYSBjb2xsZWN0aW9uIG9mIGZhY2V0cyAoYSBmYWNldCBpcyBhbiBvYmplY3Qgb2YgYSBjZXJ0YWluIGNsYXNzLCBpdCBob2xkcyBpdHMgb3duIGNvbmZpZ3VyYXRpb24sIGRhdGEgYW5kIG1ldGhvZHMpLlxuICogSW4gYSB3YXksIFwiZmFjZXRzIHBhdHRlcm5cIiBpcyBhbiBpbnZlcnNpb24gb2YgXCJhZGFwdGVyIHBhdHRlcm5cIiAtIHdoaWxlIHRoZSBsYXR0ZXIgYWxsb3dzIGZpbmRpbmcgYSBjbGFzcy9tZXRob2RzIHRoYXQgaGFzIHNwZWNpZmljIGZ1bmN0aW9uYWxpdHksIGZhY2V0ZWQgb2JqZWN0IGlzIHNpbXBseSBjb25zdHJ1Y3RlZCB0byBoYXZlIHRoZXNlIGZ1bmN0aW9uYWxpdGllcy5cbiAqIFdpdGggdGhpcyBhcmNoaXRlY3R1cmUgaXQgaXMgcG9zc2libGUgdG8gY3JlYXRlIGEgdmlydHVhbGx5IHVubGltaXRlZCBudW1iZXIgb2YgY29tcG9uZW50IGNsYXNzZXMgd2l0aCBhIHZlcnkgbGltaXRlZCBudW1iZXIgb2YgYnVpbGRpbmcgYmxvY2tzIHdpdGhvdXQgaGF2aW5nIGFueSBoaWVyYXJjaHkgb2YgY2xhc3NlcyAtIGFsbCBjb21wb25lbnRzIGluaGVyaXQgZGlyZWN0bHkgZnJvbSBDb21wb25lbnQgY2xhc3MuXG4gKlxuICogVGhpcyBjb25zdHJ1Y3RvciBzaG91bGQgYmUgY2FsbGVkIGJ5IGFsbCBzdWJjbGFzc2VzIGNvbnN0cnVjdG9yIChpdCB3aWxsIGhhcHBlbiBhdXRvbWF0aWNhbGx5IGlmIGEgc3ViY2xhc3MgaXMgY3JlYXRlZCB3aXRoIGBfLmNyZWF0ZVN1YmNsYXNzYCkuXG4gKlxuICogQHJldHVybiB7RmFjZXRlZE9iamVjdH1cbiAqL1xuZnVuY3Rpb24gRmFjZXRlZE9iamVjdCgpIHtcbiAgICAvLyB0aGlzLmZhY2V0c0NvbmZpZyBhbmQgdGhpcy5mYWNldHNDbGFzc2VzIHdlcmUgc3RvcmVkIG9uIGEgc3BlY2lmaWMgY2xhc3MgcHJvdG90eXBlXG4gICAgLy8gd2hlbiB0aGUgY2xhc3Mgd2FzIGNyZWF0ZWQgYnkgRmFjZXRlZE9iamVjdC5jcmVhdGVGYWNldGVkQ2xhc3NcbiAgICB2YXIgZmFjZXRzQ29uZmlnID0gdGhpcy5mYWNldHNDb25maWcgfHwge307XG5cbiAgICB2YXIgZmFjZXRzRGVzY3JpcHRvcnMgPSB7fVxuICAgICAgICAsIGZhY2V0cyA9IHt9O1xuXG4gICAgLy8gRmFjZXRlZE9iamVjdCBjbGFzcyBpdHNlbGYgaXMgbm90IG1lYW50IHRvIGJlIGluc3RhbnRpYXRlZCAtIGl0IGhhcyBubyBmYWNldHNcbiAgICAvLyBJdCBtYXkgY2hhbmdlLCBhcyBhZGRpbmcgZmFjZXRzIGlzIHBvc3NpYmxlIHRvIGluc3RhbmNlc1xuICAgIGlmICh0aGlzLmNvbnN0cnVjdG9yID09IEZhY2V0ZWRPYmplY3QpICAgICAgXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignRmFjZXRlZE9iamVjdCBpcyBhbiBhYnN0cmFjdCBjbGFzcywgY2FuXFwndCBiZSBpbnN0YW50aWF0ZWQnKTtcblxuICAgIC8vIGluc3RhbnRpYXRlIGNsYXNzIGZhY2V0c1xuICAgIGlmICh0aGlzLmZhY2V0c0NsYXNzZXMpXG4gICAgICAgIF8uZWFjaEtleSh0aGlzLmZhY2V0c0NsYXNzZXMsIGluc3RhbnRpYXRlRmFjZXQsIHRoaXMsIHRydWUpO1xuXG4gICAgLy8gYWRkIGZhY2V0cyB0byB0aGUgY2xhc3MgYXMgcHJvcGVydGllcyB1bmRlciB0aGVpciBvd24gbmFtZVxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIGZhY2V0c0Rlc2NyaXB0b3JzKTtcblxuICAgIC8vIHN0b3JlIGFsbCBmYWNldHMgb24gYGZhY2V0c2AgcHJvcGVydHkgc28gdGhhdCB0aGV5IGNhbiBiZSBlbnVtZXJhdGVkXG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnZmFjZXRzJywgZmFjZXRzKTsgICBcblxuICAgIC8vIGNhbGwgYGluaXRgbWV0aG9kIGlmIGl0IGlzIGRlZmluZWQgaW4gc3ViY2xhc3NcbiAgICBpZiAodGhpcy5pbml0KVxuICAgICAgICB0aGlzLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIC8vIGluc3RhbnRpYXRlIGZhY2V0IHdpdGggYSBnaXZlbiBjbGFzcyAoRmFjZXRDbGFzcykgYW5kIG5hbWUgKGZhY2V0TmFtZSlcbiAgICBmdW5jdGlvbiBpbnN0YW50aWF0ZUZhY2V0KEZhY2V0Q2xhc3MsIGZhY2V0TmFtZSkge1xuICAgICAgICAvLyBnZXQgZmFjZXQgY29uZmlndXJhdGlvblxuICAgICAgICB2YXIgZmN0Q29uZmlnID0gZmFjZXRzQ29uZmlnW2ZhY2V0TmFtZV07XG5cbiAgICAgICAgLy8gaW5zdGF0aWF0ZSBmYWNldHNcbiAgICAgICAgZmFjZXRzW2ZhY2V0TmFtZV0gPSBuZXcgRmFjZXRDbGFzcyh0aGlzLCBmY3RDb25maWcpO1xuXG4gICAgICAgIC8vIGFkZCBmYWNldCB0byBwcm9wZXJ0eSBkZXNjcmlwdG9yc1xuICAgICAgICBmYWNldHNEZXNjcmlwdG9yc1tmYWNldE5hbWVdID0ge1xuICAgICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHZhbHVlOiBmYWNldHNbZmFjZXROYW1lXVxuICAgICAgICB9O1xuICAgIH1cbn1cblxuXG4vKipcbiAqICMjIyNGYWNldGVkT2JqZWN0IGNsYXNzIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbY3JlYXRlRmFjZXRlZENsYXNzXSgjRmFjZXRlZE9iamVjdCQkY3JlYXRlRmFjZXRlZENsYXNzKVxuICogLSBbaGFzRmFjZXRdKCNGYWNldGVkT2JqZWN0JCRoYXNGYWNldClcbiAqL1xuXy5leHRlbmQoRmFjZXRlZE9iamVjdCwge1xuICAgIGNyZWF0ZUZhY2V0ZWRDbGFzczogRmFjZXRlZE9iamVjdCQkY3JlYXRlRmFjZXRlZENsYXNzLFxuICAgIGhhc0ZhY2V0OiBGYWNldGVkT2JqZWN0JCRoYXNGYWNldCxcbiAgICBnZXRGYWNldENvbmZpZzogRmFjZXRlZE9iamVjdCQkZ2V0RmFjZXRDb25maWdcbn0pO1xuXG5cbi8qKlxuICogIyMjI0ZhY2V0ZWRPYmplY3QgaW5zdGFuY2UgbWV0aG9kcyMjIyNcbiAqXG4gKiAtIFthZGRGYWNldF0oI0ZhY2V0ZWRPYmplY3QkYWRkRmFjZXQpXG4gKi9cbl8uZXh0ZW5kUHJvdG8oRmFjZXRlZE9iamVjdCwge1xuICAgIGFkZEZhY2V0OiBGYWNldGVkT2JqZWN0JGFkZEZhY2V0XG59KTtcblxuXG4vKipcbiAqIEZhY2V0ZWRPYmplY3QgaW5zdGFuY2UgbWV0aG9kLlxuICogQWRkcyBhIGZhY2V0IHRvIHRoZSBpbnN0YW5jZSBvZiBGYWNldGVkT2JqZWN0IHN1YmNsYXNzLlxuICogUmV0dXJucyBhbiBpbnN0YW5jZSBvZiB0aGUgZmFjZXQgdGhhdCB3YXMgY3JlYXRlZC5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBGYWNldENsYXNzIGZhY2V0IGNsYXNzIGNvbnN0cnVjdG9yXG4gKiBAcGFyYW0ge09iamVjdH0gZmFjZXRDb25maWcgb3B0aW9uYWwgZmFjZXQgY29uZmlndXJhdGlvblxuICogQHBhcmFtIHtTdHJpbmd9IGZhY2V0TmFtZSBvcHRpb25hbCBmYWNldCBuYW1lLCBGYWNldENsYXNzLm5hbWUgd2lsbCBiZSB1c2VkIGlmIGZhY2V0TmFtZSBpcyBub3QgcGFzc2VkLlxuICogQHBhcmFtIHtCb29sZWFufSB0aHJvd09uRXJyb3JzIElmIHNldCB0byBmYWxzZSwgdGhlbiBlcnJvcnMgd2lsbCBvbmx5IGJlIGxvZ2dlZCB0byBjb25zb2xlLiBUcnVlIGJ5IGRlZmF1bHQuXG4gKiBAcmV0dXJuIHtGYWNldH1cbiAqL1xuZnVuY3Rpb24gRmFjZXRlZE9iamVjdCRhZGRGYWNldChGYWNldENsYXNzLCBmYWNldENvbmZpZywgZmFjZXROYW1lLCB0aHJvd09uRXJyb3JzKSB7XG4gICAgY2hlY2soRmFjZXRDbGFzcywgRnVuY3Rpb24pO1xuICAgIGNoZWNrKGZhY2V0TmFtZSwgTWF0Y2guT3B0aW9uYWwoU3RyaW5nKSk7XG5cbiAgICAvLyBmaXJzdCBsZXR0ZXIgb2YgZmFjZXQgbmFtZSBzaG91bGQgYmUgbG93ZXJjYXNlXG4gICAgZmFjZXROYW1lID0gXy5maXJzdExvd2VyQ2FzZShmYWNldE5hbWUgfHwgRmFjZXRDbGFzcy5uYW1lKTtcblxuICAgIC8vIGdldCBmYWNldHMgZGVmaW5lZCBpbiBjbGFzc1xuICAgIHZhciBwcm90b0ZhY2V0cyA9IHRoaXMuY29uc3RydWN0b3IucHJvdG90eXBlLmZhY2V0c0NsYXNzZXM7XG5cbiAgICAvLyBjaGVjayB0aGF0IHRoaXMgZmFjZXROYW1lIHdhcyBub3QgYWxyZWFkeSB1c2VkIGluIHRoZSBjbGFzc1xuICAgIGlmIChwcm90b0ZhY2V0cyAmJiBwcm90b0ZhY2V0c1tmYWNldE5hbWVdKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ZhY2V0ICcgKyBmYWNldE5hbWUgKyAnIGlzIGFscmVhZHkgcGFydCBvZiB0aGUgY2xhc3MgJyArIHRoaXMuY29uc3RydWN0b3IubmFtZSk7XG5cbiAgICAvLyBjaGVjayB0aGF0IHRoaXMgZmFjZU5hbWUgZG9lcyBub3QgYWxyZWFkeSBleGlzdCBvbiB0aGUgZmFjZXRlZCBvYmplY3RcbiAgICBpZiAodGhpc1tmYWNldE5hbWVdKSB7XG4gICAgICAgIHZhciBtZXNzYWdlID0gJ2ZhY2V0ICcgKyBmYWNldE5hbWUgKyAnIGlzIGFscmVhZHkgcHJlc2VudCBpbiBvYmplY3QnO1xuICAgICAgICBpZiAodGhyb3dPbkVycm9ycyA9PT0gZmFsc2UpXG4gICAgICAgICAgICByZXR1cm4gbG9nZ2VyLmVycm9yKCdGYWNldGVkT2JqZWN0IGFkZEZhY2V0OiAnLCBtZXNzYWdlKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKG1lc3NhZ2UpO1xuICAgIH1cblxuICAgIC8vIGluc3RhbnRpYXRlIHRoZSBmYWNldFxuICAgIHZhciBuZXdGYWNldCA9IHRoaXMuZmFjZXRzW2ZhY2V0TmFtZV0gPSBuZXcgRmFjZXRDbGFzcyh0aGlzLCBmYWNldENvbmZpZyk7XG5cbiAgICAvLyBhZGQgZmFjZXQgdG8gZmFjZXRlZCBvYmplY3RcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsIGZhY2V0TmFtZSwgbmV3RmFjZXQsIF8uRU5VTSk7XG5cbiAgICByZXR1cm4gbmV3RmFjZXQ7XG59XG5cblxuLyoqXG4gKiBGYWNldGVkT2JqZWN0IGNsYXNzIG1ldGhvZFxuICogUmV0dXJucyByZWZlcmVuY2UgdG8gdGhlIGZhY2V0IGNsYXNzIGlmIHRoZSBmYWNldCB3aXRoIGBmYWNldE5hbWVgIGlzIHBhcnQgb2YgdGhlIGNsYXNzLCBgdW5kZWZpbmVkYCBvdGhlcndpc2UuIElmIHN1YmNsYXNzIGlzIGNyZWF0ZWQgdXNpbmcgXy5jcmVhdGVTdWJjbGFzcyAoYXMgaXQgc2hvdWxkIGJlKSBpdCB3aWxsIGFsc28gaGF2ZSB0aGlzIG1ldGhvZC5cbiAqIFxuICogQHBhcmFtIHtTdWJjbGFzcyhGYWNldGVkT2JqZWN0KX0gdGhpcyB0aGlzIGluIHRoaXMgbWV0aG9kIHJlZmVycyB0byBGYWNldGVkT2JqZWN0IChvciBpdHMgc3ViY2xhc3MpIHRoYXQgY2FsbHMgdGhpcyBtZXRob2RcbiAqIEBwYXJhbSB7U3RyaW5nfSBmYWNldE5hbWVcbiAqIEByZXR1cm4ge1N1YmNsYXNzKEZhY2V0KXx1bmRlZmluZWR9IFxuICovXG5mdW5jdGlvbiBGYWNldGVkT2JqZWN0JCRoYXNGYWNldChmYWNldE5hbWUpIHtcbiAgICAvLyB0aGlzIHJlZmVycyB0byB0aGUgRmFjZXRlZE9iamVjdCBjbGFzcyAob3Igc3ViY2xhc3MpLCBub3QgaW5zdGFuY2VcbiAgICB2YXIgcHJvdG9GYWNldHMgPSB0aGlzLnByb3RvdHlwZS5mYWNldHNDbGFzc2VzO1xuICAgIHJldHVybiBwcm90b0ZhY2V0cyAmJiBwcm90b0ZhY2V0c1tmYWNldE5hbWVdO1xufVxuXG4vKipcbiAqIEZhY2V0ZWRPYmplY3QgY2xhc3MgbWV0aG9kXG4gKiBSZXR1cm4gdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBmYWNldFxuICogQHBhcmFtIHtTdHJpbmd9IGZhY2V0TmFtZSB0aGUgZmFjZXQgd2hpY2ggY29uZmlnIHNob3VsZCBiZSByZXRyaWV2ZWRcbiAqIEByZXR1cm4ge09iamVjdH0gdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRoYXQgd2FzIHBhc3NlZCB0byB0aGUgZmFjZXRcbiAqL1xuZnVuY3Rpb24gRmFjZXRlZE9iamVjdCQkZ2V0RmFjZXRDb25maWcoZmFjZXROYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMuaGFzRmFjZXQoZmFjZXROYW1lKSA/IHRoaXMucHJvdG90eXBlLmZhY2V0c0NvbmZpZ1tmYWNldE5hbWVdIDogbnVsbDtcbn1cblxuXG4vKipcbiAqIEZhY2V0ZWRPYmplY3QgY2xhc3MgbWV0aG9kXG4gKiBDbGFzcyBmYWN0b3J5IHRoYXQgY3JlYXRlcyBjbGFzc2VzIChjb25zdHJ1Y3RvciBmdW5jdGlvbnMpIGZyb20gdGhlIG1hcHMgb2YgZmFjZXRzIGFuZCB0aGVpciBjb25maWd1cmF0aW9ucy5cbiAqIENyZWF0ZWQgY2xhc3Mgd2lsbCBiZSBzdWJjbGFzcyBvZiBgRmFjZXRlZE9iamVjdGAuXG4gKlxuICogQHBhcmFtIHtTdWJjbGFzcyhGYWNldGVkT2JqZWN0KX0gdGhpcyB0aGlzIGluIHRoaXMgbWV0aG9kIHJlZmVycyB0byBGYWNldGVkT2JqZWN0IChvciBpdHMgc3ViY2xhc3MpIHRoYXQgY2FsbHMgdGhpcyBtZXRob2RcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIGNsYXNzIG5hbWUgKHdpbGwgYmUgZnVuY3Rpb24gbmFtZSBvZiBjbGFzcyBjb25zdHJ1Y3RvciBmdW5jdGlvbilcbiAqIEBwYXJhbSB7T2JqZWN0W1N1YmNsYXNzKEZhY2V0KV19IGZhY2V0c0NsYXNzZXMgbWFwIG9mIGNsYXNzZXMgb2YgZmFjZXRzIHRoYXQgd2lsbCBjb25zdGl0dXRlIHRoZSBjcmVhdGVkIGNsYXNzXG4gKiBAcGFyYW0ge09iamVjdFtPYmplY3RdfSBmYWNldHNDb25maWcgbWFwIG9mIGZhY2V0cyBjb25maWd1cmF0aW9uLCBzaG91bGQgaGF2ZSB0aGUgc2FtZSBrZXlzIGFzIHRoZSBtYXAgb2YgY2xhc3Nlcy4gU29tZSBmYWNldHMgbWF5IG5vdCBoYXZlIGNvbmZpZ3VyYXRpb24sIGJ1dCB0aGUgY29uZmlndXJhdGlvbiBmb3IgYSBmYWNldCB0aGF0IGlzIG5vdCBpbmNsdWRlZCBpbiBmYWNldHNDbGFzc2VzIHdpbGwgdGhyb3cgYW4gZXhjZXB0aW9uXG4gKiBAcmV0dXJuIHtTdWJjbGFzcyhGYWNldGVkT2JqZWN0KX1cbiAqL1xuZnVuY3Rpb24gRmFjZXRlZE9iamVjdCQkY3JlYXRlRmFjZXRlZENsYXNzKG5hbWUsIGZhY2V0c0NsYXNzZXMsIGZhY2V0c0NvbmZpZykge1xuICAgIGNoZWNrKG5hbWUsIFN0cmluZyk7XG4gICAgY2hlY2soZmFjZXRzQ2xhc3NlcywgTWF0Y2guT3B0aW9uYWwoTWF0Y2guT2JqZWN0SGFzaChNYXRjaC5TdWJjbGFzcyhGYWNldCwgdHJ1ZSkpKSk7XG4gICAgY2hlY2soZmFjZXRzQ29uZmlnLCBNYXRjaC5PcHRpb25hbChPYmplY3QpKTtcblxuICAgIC8vIHRocm93IGV4Y2VwdGlvbiBpZiBjb25maWcgcGFzc2VkIGZvciBmYWNldCBmb3Igd2hpY2ggdGhlcmUgaXMgbm8gY2xhc3NcbiAgICBpZiAoZmFjZXRzQ29uZmlnKVxuICAgICAgICBfLmVhY2hLZXkoZmFjZXRzQ29uZmlnLCBmdW5jdGlvbihmY3RDb25maWcsIGZjdE5hbWUpIHtcbiAgICAgICAgICAgIGlmICghIGZhY2V0c0NsYXNzZXMuaGFzT3duUHJvcGVydHkoZmN0TmFtZSkpXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjb25maWd1cmF0aW9uIGZvciBmYWNldCAoJyArIGZjdE5hbWUgKyAnKSBwYXNzZWQgdGhhdCBpcyBub3QgaW4gY2xhc3MnKTtcbiAgICAgICAgfSk7XG5cbiAgICAvLyBjcmVhdGUgc3ViY2xhc3Mgb2YgdGhlIGN1cnJlbnQgY2xhc3MgKHRoaXMgcmVmZXJzIHRvIHRoZSBjbGFzcyB0aGF0IGNhbGxzIHRoaXMgbWV0aG9kKVxuICAgIHZhciBGYWNldGVkQ2xhc3MgPSBfLmNyZWF0ZVN1YmNsYXNzKHRoaXMsIG5hbWUsIHRydWUpO1xuXG4gICAgLy8gZ2V0IGZhY2V0cyBjbGFzc2VzIGFuZCBjb25maWd1cmF0aW9ucyBmcm9tIHBhcmVudCBjbGFzc1xuICAgIGZhY2V0c0NsYXNzZXMgPSBhZGRJbmhlcml0ZWRGYWNldHModGhpcywgZmFjZXRzQ2xhc3NlcywgJ2ZhY2V0c0NsYXNzZXMnKTtcbiAgICBmYWNldHNDb25maWcgPSBhZGRJbmhlcml0ZWRGYWNldHModGhpcywgZmFjZXRzQ29uZmlnLCAnZmFjZXRzQ29uZmlnJyk7XG5cbiAgICAvLyBzdG9yZSBmYWNldHMgY2xhc3NlcyBhbmQgY29uZmlndXJhdGlvbnMgb2YgY2xhc3MgcHJvdG90eXBlXG4gICAgXy5leHRlbmRQcm90byhGYWNldGVkQ2xhc3MsIHtcbiAgICAgICAgZmFjZXRzQ2xhc3NlczogZmFjZXRzQ2xhc3NlcyxcbiAgICAgICAgZmFjZXRzQ29uZmlnOiBmYWNldHNDb25maWdcbiAgICB9KTtcblxuICAgIHJldHVybiBGYWNldGVkQ2xhc3M7XG5cblxuICAgIGZ1bmN0aW9uIGFkZEluaGVyaXRlZEZhY2V0cyhzdXBlckNsYXNzLCBmYWNldHNJbmZvLCBmYWNldHNJbmZvTmFtZSkge1xuICAgICAgICB2YXIgaW5oZXJpdGVkRmFjZXRzSW5mbyA9IHN1cGVyQ2xhc3MucHJvdG90eXBlW2ZhY2V0c0luZm9OYW1lXTtcbiAgICAgICAgaWYgKGluaGVyaXRlZEZhY2V0c0luZm8pXG4gICAgICAgICAgICByZXR1cm4gXyhpbmhlcml0ZWRGYWNldHNJbmZvKVxuICAgICAgICAgICAgICAgICAgICAuY2xvbmUoKVxuICAgICAgICAgICAgICAgICAgICAuZXh0ZW5kKGZhY2V0c0luZm8gfHwge30pLl8oKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmV0dXJuIGZhY2V0c0luZm87XG4gICAgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgY2hlY2sgPSBtaWxvQ29yZS51dGlsLmNoZWNrXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENsYXNzUmVnaXN0cnk7XG5cblxuLyoqXG4gKiBgbWlsby5jbGFzc2VzLkNsYXNzUmVnaXN0cnlgIC0gdGhlIHJlZ2lzdHJ5IG9mIGNsYXNzZXMgY2xhc3MuXG4gKiBDb21wb25lbnRzIGFuZCBGYWNldHMgcmVnaXN0ZXIgdGhlbXNlbHZlcyBpbiByZWdpc3RyaWVzLiBJdCBhbGxvd3MgdG8gYXZvaWQgcmVxdWlyaW5nIHRoZW0gZnJvbSBvbmUgbW9kdWxlIGFuZCBwcmV2ZW50cyBjaXJjdWxhciBkZXBlbmRlbmNpZXMgYmV0d2VlbiBtb2R1bGVzLlxuICogXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBGb3VuZGF0aW9uQ2xhc3MgQWxsIGNsYXNzZXMgdGhhdCBhcmUgcmVnaXN0ZXJlZCBpbiB0aGUgcmVnaXN0cnkgc2hvdWxkIGJlIHN1YmNsYXNzZXMgb2YgdGhlIEZvdW5kYXRpb25DbGFzc1xuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBDbGFzc1JlZ2lzdHJ5IChGb3VuZGF0aW9uQ2xhc3MpIHtcbiAgICBpZiAoRm91bmRhdGlvbkNsYXNzKVxuICAgICAgICB0aGlzLnNldENsYXNzKEZvdW5kYXRpb25DbGFzcyk7XG5cbiAgICB0aGlzLl9fcmVnaXN0ZXJlZENsYXNzZXMgPSB7fTtcbn1cblxuXG4vKipcbiAqICMjIyNDbGFzc1JlZ2lzdHJ5IGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbYWRkXSgjYWRkKVxuICogLSBbZ2V0XSgjZ2V0KVxuICogLSBbcmVtb3ZlXSgjcmVtb3ZlKVxuICogLSBbY2xlYW5dKCNjbGVhbilcbiAqIC0gW3NldENsYXNzXSgjc2V0Q2xhc3MpXG4gKi9cbl8uZXh0ZW5kUHJvdG8oQ2xhc3NSZWdpc3RyeSwge1xuICAgIGFkZDogYWRkLFxuICAgIGdldDogZ2V0LFxuICAgIHJlbW92ZTogcmVtb3ZlLFxuICAgIGNsZWFuOiBjbGVhbixcbiAgICBzZXRDbGFzczogc2V0Q2xhc3Ncbn0pO1xuXG5cbi8qKlxuICogQ2xhc3NSZWdpc3RyeSBpbnN0YW5jZSBtZXRob2QgdGhhdCByZWdpc3RlcnMgYSBjbGFzcyBpbiB0aGUgcmVnaXN0cnkuXG4gKiBUaGUgbWV0aG9kIHdpbGwgdGhyb3cgYW4gZXhjZXB0aW9uIGlmIGEgY2xhc3MgaXMgcmVnaXN0ZXJlZCB1bmRlciB0aGUgc2FtZSBuYW1lIGFzIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCBjbGFzcy5cbiAqIFRoZSBtZXRob2QgYWxsb3dzIHJlZ2lzdGVyaW5nIHRoZSBzYW1lIGNsYXNzIHVuZGVyIGEgZGlmZmVyZW50IG5hbWUsIHNvIGNsYXNzIGFsaWFzZXMgY2FuIGJlIGNyZWF0ZWQuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gYUNsYXNzIGNsYXNzIHRvIHJlZ2lzdGVyIGluIHRoZSByZWdpc3RyeS4gU2hvdWxkIGJlIHN1YmNsYXNzIG9mIGB0aGlzLkZvdW5kYXRpb25DbGFzc2AuXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBPcHRpb25hbCBjbGFzcyBuYW1lLiBJZiBjbGFzcyBuYW1lIGlzIG5vdCBzcGVjaWZpZWQsIGl0IHdpbGwgYmUgdGFrZW4gZnJvbSBjb25zdHJ1Y3RvciBmdW5jdGlvbiBuYW1lLiBDbGFzcyBuYW1lIHNob3VsZCBiZSBhIHZhbGlkIGlkZW50aWZpZXIgYW5kIGNhbm5vdCBiZSBhbiBlbXB0eSBzdHJpbmcuXG4gKi9cbmZ1bmN0aW9uIGFkZChhQ2xhc3MsIG5hbWUpIHtcbiAgICBuYW1lID0gbmFtZSB8fCBhQ2xhc3MubmFtZTtcblxuICAgIGNoZWNrKG5hbWUsIE1hdGNoLklkZW50aWZpZXJTdHJpbmcsICdjbGFzcyBuYW1lIG11c3QgYmUgaWRlbnRpZmllciBzdHJpbmcnKTtcblxuICAgIGlmICh0aGlzLkZvdW5kYXRpb25DbGFzcykge1xuICAgICAgICBpZiAoYUNsYXNzICE9IHRoaXMuRm91bmRhdGlvbkNsYXNzKVxuICAgICAgICAgICAgY2hlY2soYUNsYXNzLCBNYXRjaC5TdWJjbGFzcyh0aGlzLkZvdW5kYXRpb25DbGFzcyksICdjbGFzcyBtdXN0IGJlIGEgc3ViKGNsYXNzKSBvZiBhIGZvdW5kYXRpb24gY2xhc3MnKTtcbiAgICB9IGVsc2VcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdmb3VuZGF0aW9uIGNsYXNzIG11c3QgYmUgc2V0IGJlZm9yZSBhZGRpbmcgY2xhc3NlcyB0byByZWdpc3RyeScpO1xuXG4gICAgaWYgKHRoaXMuX19yZWdpc3RlcmVkQ2xhc3Nlc1tuYW1lXSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjbGFzcyBcIicgKyBuYW1lICsgJ1wiIGlzIGFscmVhZHkgcmVnaXN0ZXJlZCcpO1xuXG4gICAgdGhpcy5fX3JlZ2lzdGVyZWRDbGFzc2VzW25hbWVdID0gYUNsYXNzO1xufTtcblxuXG4vKipcbiAqIEdldHMgY2xhc3MgZnJvbSByZWdpc3RyeSBieSBuYW1lXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWUgQ2xhc3MgbmFtZVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIGdldChuYW1lKSB7XG4gICAgY2hlY2sobmFtZSwgU3RyaW5nLCAnY2xhc3MgbmFtZSBtdXN0IGJlIHN0cmluZycpO1xuICAgIHJldHVybiB0aGlzLl9fcmVnaXN0ZXJlZENsYXNzZXNbbmFtZV07XG59O1xuXG5cbi8qKlxuICogUmVtb3ZlIGNsYXNzIGZyb20gcmVnaXN0cnkgYnkgaXRzIG5hbWUuXG4gKiBJZiBjbGFzcyBpcyBub3QgcmVnaXN0ZXJlZCwgdGhpcyBtZXRob2Qgd2lsbCB0aHJvdyBhbiBleGNlcHRpb24uXG4gKiBcbiAqIEBwYXJhbSB7U3RyaW5nfEZ1bmN0aW9ufSBuYW1lT3JDbGFzcyBDbGFzcyBuYW1lLiBJZiBjbGFzcyBjb25zdHJ1Y3RvciBpcyBzdXBwbGllZCwgaXRzIG5hbWUgd2lsbCBiZSB1c2VkLlxuICovXG5mdW5jdGlvbiByZW1vdmUobmFtZU9yQ2xhc3MpIHtcbiAgICBjaGVjayhuYW1lT3JDbGFzcywgTWF0Y2guT25lT2YoU3RyaW5nLCBGdW5jdGlvbiksICdjbGFzcyBvciBuYW1lIG11c3QgYmUgc3VwcGxpZWQnKTtcblxuICAgIHZhciBuYW1lID0gdHlwZW9mIG5hbWVPckNsYXNzID09ICdzdHJpbmcnXG4gICAgICAgICAgICAgICAgICAgICAgICA/IG5hbWVPckNsYXNzXG4gICAgICAgICAgICAgICAgICAgICAgICA6IG5hbWVPckNsYXNzLm5hbWU7XG4gICAgICAgICAgICAgICAgICAgICAgICBcbiAgICBpZiAoISB0aGlzLl9fcmVnaXN0ZXJlZENsYXNzZXNbbmFtZV0pXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignY2xhc3MgaXMgbm90IHJlZ2lzdGVyZWQnKTtcblxuICAgIGRlbGV0ZSB0aGlzLl9fcmVnaXN0ZXJlZENsYXNzZXNbbmFtZV07XG59O1xuXG5cbi8qKlxuICogUmVtb3ZlcyBhbGwgY2xhc3NlcyBmcm9tIHJlZ2lzdHJ5LlxuICovXG5mdW5jdGlvbiBjbGVhbigpIHtcbiAgICB0aGlzLl9fcmVnaXN0ZXJlZENsYXNzZXMgPSB7fTtcbn07XG5cblxuLyoqXG4gKiBTZXRzIGBGb3VuZGF0aW9uQ2xhc3NgIG9mIHRoZSByZWdpc3RyeS4gSXQgc2hvdWxkIGJlIHNldCBiZWZvcmUgYW55IGNsYXNzIGNhbiBiZSBhZGRlZC5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBGb3VuZGF0aW9uQ2xhc3MgQW55IGNsYXNzIHRoYXQgd2lsbCBiZSBhZGRlZCB0byB0aGUgcmVnaXN0cnkgc2hvdWxkIGJlIGEgc3ViY2xhc3Mgb2YgdGhpcyBjbGFzcy4gRm91bmRhdGlvbkNsYXNzIGl0c2VsZiBjYW4gYmUgYWRkZWQgdG8gdGhlIHJlZ2lzdHJ5IHRvby5cbiAqL1xuZnVuY3Rpb24gc2V0Q2xhc3MoRm91bmRhdGlvbkNsYXNzKSB7XG4gICAgY2hlY2soRm91bmRhdGlvbkNsYXNzLCBGdW5jdGlvbik7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnRm91bmRhdGlvbkNsYXNzJywgRm91bmRhdGlvbkNsYXNzLCBfLkVOVU0pO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQXR0cmlidXRlID0gcmVxdWlyZSgnLi9hX2NsYXNzJylcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4uL2NvbmZpZycpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIGNoZWNrID0gbWlsb0NvcmUudXRpbC5jaGVja1xuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaDtcblxuXG52YXIgQVRUUklCVVRFX1JFR0VYUD0gL14oW15cXDpcXFtcXF1dKikoPzpcXFsoW15cXDpcXFtcXF1dKilcXF0pP1xcOj8oW146XSopJC9cbiAgICAsIEZBQ0VUU19TUExJVF9SRUdFWFAgPSAvXFxzKig/OlxcLHxcXHMpXFxzKi9cbiAgICAsIEFUVFJJQlVURV9URU1QTEFURSA9ICclY29tcENsYXNzJWNvbXBGYWNldHM6JWNvbXBOYW1lJztcblxuXG4vKipcbiAqIGBtaWxvLmF0dHJpYnV0ZXMuYmluZGBcbiAqIEJpbmRBdHRyaWJ1dGUgY2xhc3MgcGFyc2VzL3ZhbGlkYXRlcy9ldGMuIGFuIGF0dHJpYnV0ZSB0aGF0IGJpbmRzIERPTSBlbGVtZW50cyB0byBtaWxvIGNvbXBvbmVudHMuXG4gKiBQb3NzaWJsZSBhdHRyaWJ1dGUgdmFsdWVzIGFyZTpcbiAqXG4gKiAtIGA6bXlWaWV3YCAtIG9ubHkgY29tcG9uZW50IG5hbWVcbiAqIC0gYFZpZXc6bXlWaWV3YCAtIGNsYXNzIGFuZCBjb21wb25lbnQgbmFtZVxuICogLSBgW0V2ZW50cywgRGF0YV06bXlWaWV3YCAtIGZhY2V0cyBhbmQgY29tcG9uZW50IG5hbWVcbiAqIC0gYFZpZXdbRXZlbnRzXTpteVZpZXdgIC0gY2xhc3MsIGZhY2V0KHMpIGFuZCBjb21wb25lbnQgbmFtZVxuICpcbiAqIFNlZSBbYmluZGVyXSguLi9iaW5kZXIuanMuaHRtbCkgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gKi9cbnZhciBCaW5kQXR0cmlidXRlID0gXy5jcmVhdGVTdWJjbGFzcyhBdHRyaWJ1dGUsICdCaW5kQXR0cmlidXRlJywgdHJ1ZSk7XG5cblxuLyoqXG4gKiAjIyMjQmluZEF0dHJpYnV0ZSBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2F0dHJOYW1lXSgjYXR0ck5hbWUpXG4gKiAtIFtwYXJzZV0oI3BhcnNlKVxuICogLSBbdmFsaWRhdGVdKCN2YWxpZGF0ZSlcbiAqIC0gW3JlbmRlcl0oI3JlbmRlcilcbiAqL1xuXy5leHRlbmRQcm90byhCaW5kQXR0cmlidXRlLCB7XG4gICAgYXR0ck5hbWU6IGF0dHJOYW1lLFxuICAgIHBhcnNlOiBwYXJzZSxcbiAgICB2YWxpZGF0ZTogdmFsaWRhdGUsXG4gICAgcmVuZGVyOiByZW5kZXJcbn0pO1xuXG5cbi8qKlxuICogQmluZEF0dHJpYnV0ZSBjbGFzcyBtZXRob2RzXG4gKlxuICogLSBbc2V0SW5mb10oI0JpbmRBdHRyaWJ1dGUkJHNldEluZm8pXG4gKi9cbl8uZXh0ZW5kKEJpbmRBdHRyaWJ1dGUsIHtcbiAgICBzZXRJbmZvOiBCaW5kQXR0cmlidXRlJCRzZXRJbmZvXG59KTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IEJpbmRBdHRyaWJ1dGU7XG5cblxuLyoqXG4gKiBCaW5kQXR0cmlidXRlIGluc3RhbmNlIG1ldGhvZCB0aGF0IHJldHVybnMgYXR0cmlidXRlIG5hbWUsIGJ5IGRlZmF1bHQgLSBgJ21sLWJpbmQnYC5cbiAqIFRvIGNvbmZpZ3VyZSBiaW5kIGF0dHJpYnV0ZSBuYW1lIHVzZTpcbiAqIGBgYFxuICogbWlsby5jb25maWcoeyBhdHRyczogeyBiaW5kOiAnY2MtYmluZCcgfSB9KTsgLy8gd2lsbCBzZXQgYmluZCBhdHRyaWJ1dGUgdG8gJ2NjLWJpbmQnXG4gKiBgYGBcbiAqXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGF0dHJOYW1lKCkge1xuICAgIHJldHVybiBjb25maWcuYXR0cnMuYmluZDtcbn1cblxuXG4vKipcbiAqIEJpbmRBdHRyaWJ1dGUgaW5zdGFuY2UgbWV0aG9kIHRoYXQgcGFyc2VzIGJpbmQgYXR0cmlidXRlIGlmIGl0IGlzIHByZXNlbnQgb24gdGhlIGVsZW1lbnQuXG4gKiBJdCBkZWZpbmVzIHByb3BlcnRpZXMgYGNvbXBDbGFzc2AsIGBjb21wRmFjZXRzYCBhbmQgYGNvbXBOYW1lYCBvbiBCaW5kQXR0cmlidXRlIGluc3RhbmNlLlxuICogUmV0dXJucyB0aGUgaW5zdGFuY2UgZm9yIG1ldGhvZCBjaGFpbmluZy5cbiAqXG4gKiBAcmV0dXJuIHtCaW5kQXR0cmlidXRlfVxuICovXG4gZnVuY3Rpb24gcGFyc2UoKSB7XG4gICAgaWYgKCEgdGhpcy5ub2RlKSByZXR1cm47XG5cbiAgICB2YXIgdmFsdWUgPSB0aGlzLmdldCgpO1xuXG4gICAgaWYgKHZhbHVlKVxuICAgICAgICB2YXIgYmluZFRvID0gdmFsdWUubWF0Y2goQVRUUklCVVRFX1JFR0VYUCk7XG5cbiAgICBpZiAoISBiaW5kVG8pXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBiaW5kIGF0dHJpYnV0ZSAnICsgdmFsdWUpO1xuXG4gICAgdGhpcy5jb21wQ2xhc3MgPSBiaW5kVG9bMV0gfHwgJ0NvbXBvbmVudCc7XG4gICAgdGhpcy5jb21wRmFjZXRzID0gKGJpbmRUb1syXSAmJiBiaW5kVG9bMl0uc3BsaXQoRkFDRVRTX1NQTElUX1JFR0VYUCkpIHx8IHVuZGVmaW5lZDtcbiAgICB0aGlzLmNvbXBOYW1lID0gYmluZFRvWzNdIHx8IHVuZGVmaW5lZDsgLy8gdW5kZWZpbmVkIGlzIG5vdCBzYW1lIGFzICcnXG5cbiAgICByZXR1cm4gdGhpcztcbn1cblxuXG4vKipcbiAqIEJpbmRBdHRyaWJ1dGUgaW5zdGFuY2UgbWV0aG9kIHRoYXQgdmFsaWRhdGVzIGJpbmQgYXR0cmlidXRlLCB0aHJvd3MgaWYgaXQgaGFzIGFuIGludmFsaWQgdmFsdWUuXG4gKiBSZXR1cm5zIHRoZSBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nLlxuICpcbiAqIEByZXR1cm4ge0JpbmRBdHRyaWJ1dGV9XG4gKi9cbmZ1bmN0aW9uIHZhbGlkYXRlKCkge1xuICAgIGNoZWNrKHRoaXMuY29tcE5hbWUsIE1hdGNoLklkZW50aWZpZXJTdHJpbmcpO1xuXG4gICAgaWYgKCEgdGhpcy5jb21wQ2xhc3MpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignZW1wdHkgY29tcG9uZW50IGNsYXNzIG5hbWUgJyArIHRoaXMuY29tcENsYXNzKTtcblxuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogQmluZEF0dHJpYnV0ZSBpbnN0YW5jZSBtZXRob2QgdGhhdCByZXR1cm5zIHRoZSBhdHRyaWJ1dGUgdmFsdWUgZm9yIGdpdmVuIHZhbHVlcyBvZiBwcm9wZXJ0aWVzIGBjb21wQ2xhc3NgLCBgY29tcE5hbWVgIGFuZCBgY29tcEZhY2V0c2AuXG4gKiBJZiBgdGhpcy5jb21wTmFtZWAgaXMgbm90IHNldCBpdCB3aWxsIGJlIGdlbmVyYXRlZCBhdXRvbWF0aWNhbGx5LlxuICpcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gcmVuZGVyKCkge1xuICAgIHRoaXMuY29tcE5hbWUgPSB0aGlzLmNvbXBOYW1lIHx8IG1pbG8udXRpbC5jb21wb25lbnROYW1lKCk7XG4gICAgcmV0dXJuIEFUVFJJQlVURV9URU1QTEFURVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCclY29tcENsYXNzJywgdGhpcy5jb21wQ2xhc3MgfHwgJycpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJyVjb21wRmFjZXRzJywgdGhpcy5jb21wRmFjZXRzICYmIHRoaXMuY29tcEZhY2V0cy5sZW5ndGhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyAnWycgKyB0aGlzLmNvbXBGYWNldHMuam9pbignLCAnKSArICddJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6ICcnKVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCclY29tcE5hbWUnLCB0aGlzLmNvbXBOYW1lKTtcbn1cblxuXG4vKipcbiAqIEJpbmRBdHRyaWJ1dGUgY2xhc3MgbWV0aG9kXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsXG4gKiBAcGFyYW0ge1N0cmluZ30gY29tcG9uZW50Q2xhc3Mgb3B0aW9uYWwgY2xhc3MgbmFtZVxuICogQHBhcmFtIHtTdHJpbmd9IGNvbXBvbmVudE5hbWUgb3B0aW9uYWxcbiAqIEBwYXJhbSB7QXJyYXk8U3RyaW5nPn0gY29tcG9uZW50RmFjZXRzIG9wdGlvbmFsIGV4dHJhIGZhY2V0IHRvIGFkZCB0byB0aGUgY2xhc3NcbiAqL1xuZnVuY3Rpb24gQmluZEF0dHJpYnV0ZSQkc2V0SW5mbyhlbCwgY29tcG9uZW50Q2xhc3MsIGNvbXBvbmVudE5hbWUsIGNvbXBvbmVudEZhY2V0cykge1xuICAgIHZhciBhdHRyID0gbmV3IEJpbmRBdHRyaWJ1dGUoZWwpO1xuICAgIF8uZXh0ZW5kKGF0dHIsIHtcbiAgICAgICAgY29tcENsYXNzOiBjb21wb25lbnRDbGFzcyxcbiAgICAgICAgY29tcE5hbWU6IGNvbXBvbmVudE5hbWUsXG4gICAgICAgIGNvbXBGYWNldHM6IGNvbXBvbmVudEZhY2V0c1xuICAgIH0pO1xuICAgIGF0dHIuZGVjb3JhdGUoKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgY2hlY2sgPSBtaWxvQ29yZS51dGlsLmNoZWNrXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXR0cmlidXRlO1xuXG5cbi8qKlxuICogQW4gYWJzY3RyYWN0IGNsYXNzIGZvciBwYXJzaW5nIGFuZCB2YWxpZGF0aW9uIG9mIGVsZW1lbnQgYXR0cmlidXRlcy5cbiAqIFN1YmNsYXNzZXMgc2hvdWxkIGRlZmluZSBtZXRob2RzIGBhdHRyTmFtZWAsIGBwYXJzZWAsIGB2YWxpZGF0ZWAgYW5kIGByZW5kZXJgLlxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgRE9NIGVsZW1lbnQgd2hlcmUgYXR0cmlidXRlIGlzIGF0dGFjaGVkXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBPcHRpb25hbCBuYW1lIG9mIHRoZSBhdHRyaWJ1dGUsIHVzdWFsbHkgc3VwcGxpZWQgYnkgc3ViY2xhc3MgdmlhIGBhdHRyTmFtZWAgbWV0aG9kXG4gKi9cbmZ1bmN0aW9uIEF0dHJpYnV0ZShlbCwgbmFtZSkge1xuICAgIHRoaXMubmFtZSA9IG5hbWUgfHwgdGhpcy5hdHRyTmFtZSgpO1xuICAgIHRoaXMuZWwgPSBlbDtcblxuICAgIC8vIGF0dHJpYnV0ZSBub2RlXG4gICAgdGhpcy5ub2RlID0gZWwuYXR0cmlidXRlc1t0aGlzLm5hbWVdO1xufVxuXG5cbl8uZXh0ZW5kKEF0dHJpYnV0ZSwge1xuICAgIHJlbW92ZTogQXR0cmlidXRlJCRyZW1vdmVcbn0pO1xuXG5cbi8qKlxuICogIyMjI0F0dHJpYnV0ZSBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2dldF0oI0F0dHJpYnV0ZSRnZXQpXG4gKiAtIFtzZXRdKCNBdHRyaWJ1dGUkc2V0KVxuICogLSBbZGVjb3JhdGVdKCNBdHRyaWJ1dGUkZGVjb3JhdGUpXG4gKlxuICogVGhlIGZvbGxvd2luZyBpbnN0YW5jZSBtZXRob2RzIHNob3VsZCBiZSBkZWZpbmVkIGJ5IHN1YmNsYXNzXG4gKlxuICogLSBhdHRyTmFtZSAtIHNob3VsZCByZXR1cm4gYXR0cmlidXRlIG5hbWVcbiAqIC0gcGFyc2UgLSBzaG91bGQgcGFyc2UgYXR0cmlidXRlIHZhbHVlXG4gKiAtIHZhbGlkYXRlIC0gc2hvdWxkIHZhbGlkYXRlIGF0dHJpYnV0ZSB2YWx1ZSwgdGhyb3dpbmcgZXhjZXB0aW9uIGlmIGl0IGlzIGluY29ycmVjdCBcbiAqIC0gcmVuZGVyIC0gc2hvdWxkIHJldHVybiBhdHRyaWJ1dGUgdmFsdWUgZm9yIGEgZ2l2ZW4gYXR0cmlidXRlIHN0YXRlIChvdGhlciBwcm9wZXJ0aWVzLCBhcyBkZWZpbmVkIGluIHN1YmNsYXNzKVxuICovXG5fLmV4dGVuZFByb3RvKEF0dHJpYnV0ZSwge1xuICAgIGdldDogQXR0cmlidXRlJGdldCxcbiAgICBzZXQ6IEF0dHJpYnV0ZSRzZXQsXG4gICAgcmVtb3ZlOiBBdHRyaWJ1dGUkcmVtb3ZlLFxuICAgIGRlY29yYXRlOiBBdHRyaWJ1dGUkZGVjb3JhdGUsXG5cbiAgICBkZXN0cm95OiBBdHRyaWJ1dGUkZGVzdHJveSxcblxuICAgIC8vIHNob3VsZCBiZSBkZWZpbmVkIGluIHN1YmNsYXNzXG4gICAgYXR0ck5hbWU6IHRvQmVJbXBsZW1lbnRlZCxcbiAgICBwYXJzZTogdG9CZUltcGxlbWVudGVkLFxuICAgIHZhbGlkYXRlOiB0b0JlSW1wbGVtZW50ZWQsXG4gICAgcmVuZGVyOiB0b0JlSW1wbGVtZW50ZWRcbn0pO1xuXG5cbmZ1bmN0aW9uIEF0dHJpYnV0ZSQkcmVtb3ZlKGVsLCBkZWVwKSB7XG4gICAgdmFyIG5hbWUgPSB0aGlzLnByb3RvdHlwZS5hdHRyTmFtZSgpO1xuICAgIGVsLnJlbW92ZUF0dHJpYnV0ZShuYW1lKTtcblxuICAgIGlmIChkZWVwKSB7XG4gICAgICAgIHZhciBzZWxlY3RvciA9ICdbJyArIG5hbWUgKyAnXSc7XG4gICAgICAgIHZhciBjaGlsZHJlbiA9IGVsLnF1ZXJ5U2VsZWN0b3JBbGwoc2VsZWN0b3IpO1xuICAgICAgICBfLmZvckVhY2goY2hpbGRyZW4sIGZ1bmN0aW9uKGNoaWxkRWwpIHtcbiAgICAgICAgICAgIGNoaWxkRWwucmVtb3ZlQXR0cmlidXRlKG5hbWUpO1xuICAgICAgICB9KVxuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBBdHRyaWJ1dGUkcmVtb3ZlKCkge1xuICAgIGRlbGV0ZSB0aGlzLm5vZGU7XG59XG5cblxuZnVuY3Rpb24gQXR0cmlidXRlJGRlc3Ryb3koKSB7XG4gICAgZGVsZXRlIHRoaXMuZWw7XG4gICAgZGVsZXRlIHRoaXMubm9kZTtcbn1cblxuLyoqXG4gKiBBdHRyaWJ1dGUgaW5zdGFuY2UgbWV0aG9kIHRoYXQgcmV0dXJucyBhdHRyaWJ1dGUgdmFsdWUgYXMgc3RyaW5nLlxuICpcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gQXR0cmlidXRlJGdldCgpIHtcbiAgICByZXR1cm4gdGhpcy5lbC5nZXRBdHRyaWJ1dGUodGhpcy5uYW1lKTtcbn1cblxuXG4vKipcbiAqIEF0dHJpYnV0ZSBpbnN0YW5jZSBtZXRob2QgdGhhdCBzZXRzIGF0dHJpYnV0ZSB2YWx1ZS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gdmFsdWVcbiAqL1xuZnVuY3Rpb24gQXR0cmlidXRlJHNldCh2YWx1ZSkge1xuICAgIHRoaXMuZWwuc2V0QXR0cmlidXRlKHRoaXMubmFtZSwgdmFsdWUpO1xufVxuXG5cbi8qKlxuICogQXR0cmlidXRlIGluc3RhbmNlIG1ldGhvZCB0aGF0IGRlY29yYXRlcyBlbGVtZW50IHdpdGggaXRzIHJlbmRlcmVkIHZhbHVlLlxuICogVXNlcyBgcmVuZGVyYCBtZXRob2QgdGhhdCBzaG91bGQgYmUgZGVmaWVuZCBpbiBzdWJjbGFzcy5cbiAqL1xuZnVuY3Rpb24gQXR0cmlidXRlJGRlY29yYXRlKCkge1xuICAgIHRoaXMuc2V0KHRoaXMucmVuZGVyKCkpO1xufVxuXG5cbmZ1bmN0aW9uIHRvQmVJbXBsZW1lbnRlZCgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2NhbGxpbmcgdGhlIG1ldGhvZCBvZiBhbiBhYnNjdHJhY3QgY2xhc3MnKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIEF0dHJpYnV0ZSA9IHJlcXVpcmUoJy4vYV9jbGFzcycpXG4gICAgLCBjb25maWcgPSByZXF1aXJlKCcuLi9jb25maWcnKVxuICAgICwgXyA9IHJlcXVpcmUoJ21pbG8tY29yZScpLnByb3RvO1xuXG5cbi8qKlxuICogYG1pbG8uYXR0cmlidXRlcy5sb2FkYFxuICogTG9hZEF0dHJpYnV0ZSBjbGFzcyBwYXJzZXMvdmFsaWRhdGVzL2V0Yy4gYW4gYXR0cmlidXRlIHRoYXQgbG9hZHMgc3ViLXZpZXdzIGludG8gdGhlIHBhZ2UuXG4gKiBBdHRyaWJ1dGUgdmFsdWUgc2hvdWxkIGJlIFVSTCBvZiB0aGUgZmlsZSB0byBsb2FkIHN1YnZpZXcgZnJvbS5cbiAqIFNlZSBbbG9hZGVyXSguLi9sb2FkZXIuanMuaHRtbCkgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gKi9cbnZhciBMb2FkQXR0cmlidXRlID0gXy5jcmVhdGVTdWJjbGFzcyhBdHRyaWJ1dGUsICdMb2FkQXR0cmlidXRlJywgdHJ1ZSk7XG5cblxuLyoqXG4gKiAjIyMjTG9hZEF0dHJpYnV0ZSBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2F0dHJOYW1lXSgjYXR0ck5hbWUpXG4gKiAtIFtwYXJzZV0oI3BhcnNlKVxuICogLSBbdmFsaWRhdGVdKCN2YWxpZGF0ZSlcbiAqIC0gW3JlbmRlcl0oI3JlbmRlcilcbiAqL1xuXy5leHRlbmRQcm90byhMb2FkQXR0cmlidXRlLCB7XG4gICAgYXR0ck5hbWU6IGF0dHJOYW1lLFxuICAgIHBhcnNlOiBwYXJzZSxcbiAgICB2YWxpZGF0ZTogdmFsaWRhdGUsXG4gICAgcmVuZGVyOiByZW5kZXJcbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IExvYWRBdHRyaWJ1dGU7XG5cblxuLyoqXG4gKiBCaW5kQXR0cmlidXRlIGluc3RhbmNlIG1ldGhvZCB0aGF0IHJldHVybnMgYXR0cmlidXRlIG5hbWUsIGJ5IGRlZmF1bHQgLSBgJ21sLWxvYWQnYC5cbiAqIFRvIGNvbmZpZ3VyZSBsb2FkIGF0dHJpYnV0ZSBuYW1lIHVzZTpcbiAqIGBgYFxuICogbWlsby5jb25maWcoeyBhdHRyczogeyBsb2FkOiAnY2MtbG9hZCcgfSB9KTsgLy8gd2lsbCBzZXQgYmluZCBhdHRyaWJ1dGUgdG8gJ2NjLWxvYWQnXG4gKiBgYGBcbiAqXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGF0dHJOYW1lKCkge1xuICAgIHJldHVybiBjb25maWcuYXR0cnMubG9hZDtcbn1cblxuXG4vKipcbiAqIExvYWRBdHRyaWJ1dGUgaW5zdGFuY2UgbWV0aG9kIHRoYXQgcGFyc2VzIGxvYWQgYXR0cmlidXRlIGlmIGl0IGlzIHByZXNlbnQgb24gdGhlIGVsZW1lbnQuXG4gKiBJdCBkZWZpbmVzIHByb3BlcnR5IGBsb2FkVXJsYCBvbiBMb2FkQXR0cmlidXRlIGluc3RhbmNlLlxuICogUmV0dXJucyB0aGUgaW5zdGFuY2UgZm9yIG1ldGhvZCBjaGFpbmluZy5cbiAqXG4gKiBAcmV0dXJuIHtMb2FkQXR0cmlidXRlfVxuICovXG5mdW5jdGlvbiBwYXJzZSgpIHtcbiAgICBpZiAoISB0aGlzLm5vZGUpIHJldHVybjtcblxuICAgIHRoaXMubG9hZFVybCA9IHRoaXMuZ2V0KCk7XG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBMb2FkQXR0cmlidXRlIGluc3RhbmNlIG1ldGhvZCB0aGF0IHNob3VsZCB2YWxpZGF0ZSBsb2FkIGF0dHJpYnV0ZSBhbmQgdGhyb3cgaWYgaXQgaGFzIGFuIGludmFsaWQgdmFsdWUuXG4gKiBUT0RPIC0gaW1wbGVtZW50IHVybCB2YWxpZGF0aW9uLlxuICogUmV0dXJucyB0aGUgaW5zdGFuY2UgZm9yIG1ldGhvZCBjaGFpbmluZy5cbiAqXG4gKiBAcmV0dXJuIHtMb2FkQXR0cmlidXRlfVxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZSgpIHtcbiAgICAvLyBUT0RPIHVybCB2YWxpZGF0aW9uXG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBMb2FkQXR0cmlidXRlIGluc3RhbmNlIG1ldGhvZCAtIHJldHVybnMgVVJMXG4gKlxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiByZW5kZXIoKSB7XG4gICAgcmV0dXJuIHRoaXMubG9hZFVybDtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiBTdWJjbGFzc2VzIG9mIFtBdHRyaWJ1dGVdKC4vYV9jbGFzcy5qcy5odG1sKSBjbGFzc1xuICpcbiAqIC0gW0JpbmRBdHRyaWJ1dGVdKC4vYV9iaW5kLmpzLmh0bWwpXG4gKiAtIFtMb2FkQXR0cmlidXRlXSguL2FfbG9hZC5qcy5odG1sKVxuICovXG52YXIgYXR0cmlidXRlcyA9IG1vZHVsZS5leHBvcnRzID0ge1xuICAgIGJpbmQ6IHJlcXVpcmUoJy4vYV9iaW5kJyksXG4gICAgbG9hZDogcmVxdWlyZSgnLi9hX2xvYWQnKVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1pbG9NYWlsID0gcmVxdWlyZSgnLi9zZXJ2aWNlcy9tYWlsJylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY29tcG9uZW50cy9jX3JlZ2lzdHJ5JylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL2NmX3JlZ2lzdHJ5JylcbiAgICAsIENvbXBvbmVudCA9IGNvbXBvbmVudHNSZWdpc3RyeS5nZXQoJ0NvbXBvbmVudCcpXG4gICAgLCBDb21wb25lbnRJbmZvID0gcmVxdWlyZSgnLi9jb21wb25lbnRzL2NfaW5mbycpXG4gICAgLCBTY29wZSA9IHJlcXVpcmUoJy4vY29tcG9uZW50cy9zY29wZScpXG4gICAgLCBCaW5kQXR0cmlidXRlID0gcmVxdWlyZSgnLi9hdHRyaWJ1dGVzL2FfYmluZCcpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIGNoZWNrID0gbWlsb0NvcmUudXRpbC5jaGVja1xuICAgICwgdXRpbERvbSA9IHJlcXVpcmUoJy4vdXRpbC9kb20nKVxuICAgICwgTWF0Y2ggPSAgY2hlY2suTWF0Y2g7XG5cblxuYmluZGVyLnNjYW4gPSBzY2FuO1xuYmluZGVyLmNyZWF0ZSA9IGNyZWF0ZTtcbmJpbmRlci50d29QYXNzID0gdHdvUGFzcztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGJpbmRlcjtcblxuXG4vKipcbiAqIGBtaWxvLmJpbmRlcmBcbiAqXG4gKiBSZWN1cnNpdmVseSBzY2FucyB0aGUgZG9jdW1lbnQgdHJlZSBpbnNpZGUgYHNjb3BlRWxgIChkb2N1bWVudC5ib2R5IGJ5IGRlZmF1bHQpIGxvb2tpbmcgZm9yIF9fbWwtYmluZF9fIGF0dHJpYnV0ZSB0aGF0IHNob3VsZCBjb250YWluIHRoZSBjbGFzcywgYWRkaXRpb25hbCBmYWNldHMgYW5kIHRoZSBuYW1lIG9mIHRoZSBjb21wb25lbnQgdGhhdCBzaG91bGQgYmUgY3JlYXRlZCBhbmQgYm91bmQgdG8gdGhlIGVsZW1lbnQuXG4gKlxuICogUG9zc2libGUgdmFsdWVzIG9mIF9fbWwtYmluZF9fIGF0dHJpYnV0ZTpcbiAqXG4gKiAtIGA6bXlWaWV3YCAtIG9ubHkgY29tcG9uZW50IG5hbWUuIEFuIGluc3RhbmNlIG9mIENvbXBvbmVudCBjbGFzcyB3aWxsIGJlIGNyZWF0ZWQgd2l0aG91dCBhbnkgZmFjZXRzLlxuICogLSBgVmlldzpteVZpZXdgIC0gY2xhc3MgYW5kIGNvbXBvbmVudCBuYW1lLiBBbiBpbnN0YW5jZSBvZiBWaWV3IGNsYXNzIHdpbGwgYmUgY3JlYXRlZC5cbiAqIC0gYFtFdmVudHMsIERhdGFdOm15Vmlld2AgLSBmYWNldHMgYW5kIGNvbXBvbmVudCBuYW1lLiBBbiBpbnN0YW5jZSBvZiBDb21wb25lbnQgY2xhc3Mgd2lsbCBiZSBjcmVhdGVkIHdpdGggdGhlIGFkZGl0aW9uIG9mIGZhY2V0cyBFdmVudHMgYW5kIERhdGEuXG4gKiAtIGBWaWV3W0V2ZW50cywgRGF0YV06bXlWaWV3YCAtIGNsYXNzLCBmYWNldChzKSBhbmQgY29tcG9uZW50IG5hbWUuIEFuIGluc3RhbmNlIG9mIFZpZXcgY2xhc3Mgd2lsbCBiZSBjcmVhdGVkIHdpdGggdGhlIGFkZGl0aW9uIG9mIGZhY2V0cyBFdmVudHMgYW5kIERhdGEuXG4gKlxuICogRnVuY3Rpb24gcmV0dXJucyBhbiBpbnN0YW5jZSBvZiBbYFNjb3BlYF0oLi9jb21wb25lbnRzL3Njb3BlLmpzLmh0bWwpIGNsYXNzIGNvbnRhaW5pbmcgYWxsIGNvbXBvbmVudHMgY3JlYXRlZCBhcyBhIHJlc3VsdCBvZiBzY2FubmluZyBET00uXG4gKlxuICogSWYgdGhlIGNvbXBvbmVudCBoYXMgW2BDb250YWluZXJgXSguL2NvbXBvbmVudHMvY19mYWNldHMvQ29udGFpbmVyLmpzKSBmYWNldCwgY2hpbGRyZW4gb2YgdGhpcyBlbGVtZW50IHdpbGwgYmUgc3RvcmVkIGluIHRoZSBgc2NvcGVgIG9iamVjdCwgYXZhaWxhYmxlIGFzIHNjb3BlIHByb3BlcnR5IG9uIHRoZSBDb250YWluZXIgZmFjZXQgb2YgdGhpcyBjb21wb25lbnQuIE5hbWVzIG9mIGNvbXBvbmVudHMgd2l0aGluIHRoZSBzY29wZSBzaG91bGQgYmUgdW5pcXVlLCBidXQgdGhleSBjYW4gYmUgdGhlIHNhbWUgYXMgdGhlIG5hbWVzIG9mIGNvbXBvbmVudHMgaW4gb3V0ZXIgc2NvcGUgKG9yIHNvbWUgb3RoZXIgc2NvcGUpLlxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gc2NvcGVFbCByb290IGVsZW1lbnQgaW5zaWRlIHdoaWNoIERPTSB3aWxsIGJlIHNjYW5uZWQgYW5kIGJvdW5kXG4gKiBAcGFyYW0ge1Njb3BlfSByb290U2NvcGUgT3B0aW9uYWwgUm9vdCBzY29wZSBvYmplY3Qgd2hlcmUgdG9wIGxldmVsIGNvbXBvbmVudHMgd2lsbCBiZSBzYXZlZC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gYmluZFJvb3RFbGVtZW50IElmIHNldCB0byBmYWxzZSwgdGhlbiB0aGUgcm9vdCBlbGVtZW50IHdpbGwgbm90IGJlIGJvdW5kLiBUcnVlIGJ5IGRlZmF1bHQuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHRocm93T25FcnJvcnMgSWYgc2V0IHRvIGZhbHNlLCB0aGVuIGVycm9ycyB3aWxsIG9ubHkgYmUgbG9nZ2VkIHRvIGNvbnNvbGUuIFRydWUgYnkgZGVmYXVsdC5cbiAqIEByZXR1cm4ge1Njb3BlfVxuICovXG5mdW5jdGlvbiBiaW5kZXIoc2NvcGVFbCwgcm9vdFNjb3BlLCBiaW5kUm9vdEVsZW1lbnQsIHRocm93T25FcnJvcnMpIHtcbiAgICByZXR1cm4gY3JlYXRlQmluZGVyU2NvcGUoc2NvcGVFbCwgZnVuY3Rpb24oc2NvcGUsIGVsLCBhdHRyLCB0aHJvd09uRXJyb3JzKSB7XG4gICAgICAgIHZhciBpbmZvID0gbmV3IENvbXBvbmVudEluZm8oc2NvcGUsIGVsLCBhdHRyLCB0aHJvd09uRXJyb3JzKTtcbiAgICAgICAgcmV0dXJuIENvbXBvbmVudC5jcmVhdGUoaW5mbywgdGhyb3dPbkVycm9ycyk7XG4gICAgfSwgcm9vdFNjb3BlLCBiaW5kUm9vdEVsZW1lbnQsIHRocm93T25FcnJvcnMpO1xufVxuXG5cbi8vIGJpbmQgaW4gdHdvIHBhc3Nlc1xuZnVuY3Rpb24gdHdvUGFzcyhzY29wZUVsLCByb290U2NvcGUsIGJpbmRSb290RWxlbWVudCwgdGhyb3dPbkVycm9ycykge1xuICAgIHZhciBzY2FuU2NvcGUgPSBiaW5kZXIuc2NhbihzY29wZUVsLCByb290U2NvcGUsIGJpbmRSb290RWxlbWVudCwgdGhyb3dPbkVycm9ycyk7XG4gICAgcmV0dXJuIGJpbmRlci5jcmVhdGUoc2NhblNjb3BlLCB1bmRlZmluZWQsIHRocm93T25FcnJvcnMpO1xufVxuXG5cbi8vIHNjYW4gRE9NIGZvciBCaW5kQXR0cmlidXRlXG5mdW5jdGlvbiBzY2FuKHNjb3BlRWwsIHJvb3RTY29wZSwgYmluZFJvb3RFbGVtZW50LCB0aHJvd09uRXJyb3JzKSB7XG4gICAgcmV0dXJuIGNyZWF0ZUJpbmRlclNjb3BlKHNjb3BlRWwsIGZ1bmN0aW9uKHNjb3BlLCBlbCwgYXR0ciwgdGhyb3dPbkVycm9ycykge1xuICAgICAgICByZXR1cm4gbmV3IENvbXBvbmVudEluZm8oc2NvcGUsIGVsLCBhdHRyLCB0aHJvd09uRXJyb3JzKTtcbiAgICB9LCByb290U2NvcGUsIGJpbmRSb290RWxlbWVudCwgdGhyb3dPbkVycm9ycyk7XG59XG5cblxuLy8gY3JlYXRlIGJvdW5kIGNvbXBvbmVudHNcbmZ1bmN0aW9uIGNyZWF0ZShzY2FuU2NvcGUsIGhvc3RPYmplY3QsIHRocm93T25FcnJvcnMpIHtcbiAgICB2YXIgc2NvcGUgPSBuZXcgU2NvcGUoc2NhblNjb3BlLl9yb290RWwsIGhvc3RPYmplY3QpXG4gICAgICAgICwgYWRkTWV0aG9kID0gdGhyb3dPbkVycm9ycyA9PT0gZmFsc2UgPyAnX3NhZmVBZGQnIDogJ19hZGQnO1xuXG4gICAgc2NhblNjb3BlLl9lYWNoKGZ1bmN0aW9uKGNvbXBJbmZvKSB7XG4gICAgICAgIC8vIHNldCBjb3JyZWN0IGNvbXBvbmVudCdzIHNjb3BlXG4gICAgICAgIHZhciBpbmZvID0gXy5jbG9uZShjb21wSW5mbylcbiAgICAgICAgaW5mby5zY29wZSA9IHNjb3BlO1xuXG4gICAgICAgIC8vIGNyZWF0ZSBjb21wb25lbnRcbiAgICAgICAgdmFyIGFDb21wb25lbnQgPSBDb21wb25lbnQuY3JlYXRlKGluZm8sIHRocm93T25FcnJvcnMpO1xuXG4gICAgICAgIHNjb3BlW2FkZE1ldGhvZF0oYUNvbXBvbmVudCwgYUNvbXBvbmVudC5uYW1lKTtcbiAgICAgICAgaWYgKGFDb21wb25lbnQuY29udGFpbmVyKVxuICAgICAgICAgICAgYUNvbXBvbmVudC5jb250YWluZXIuc2NvcGUgPSBjcmVhdGUoY29tcEluZm8uY29udGFpbmVyLnNjb3BlLCBhQ29tcG9uZW50LmNvbnRhaW5lciwgdGhyb3dPbkVycm9ycyk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gc2NvcGU7XG59XG5cbi8qKlxuICogYGNyZWF0ZUJpbmRlclNjb3BlYFxuICogQHBhcmFtICB7RWxlbWVudH0gc2NvcGVFbCAgICAgICAgICAgICBzY29wZUVsIHJvb3QgZWxlbWVudCBpbnNpZGUgd2hpY2ggRE9NIHdpbGwgYmUgc2Nhbm5lZCBhbmQgYm91bmQgKGRvY3VtZW50LmJvZHkgYnkgZGVmYXVsdCkuXG4gKiBAcGFyYW0gIHtGdW5jdGlvbn0gc2NvcGVPYmplY3RGYWN0b3J5IFNlZSBbYmluZGVyXSgjbWlsby5iaW5kZXIpXG4gKiBAcGFyYW0gIHtTY29wZX0gcm9vdFNjb3BlICAgICAgICAgICAgIE9wdGlvbmFsIFJvb3Qgc2NvcGUgb2JqZWN0IHdoZXJlIHRvcCBsZXZlbCBjb21wb25lbnRzIHdpbGwgYmUgc2F2ZWQuXG4gKiBAcGFyYW0gIHtCb29sZWFufSBiaW5kUm9vdEVsZW1lbnQgICAgIElmIHNldCB0byBmYWxzZSwgdGhlbiB0aGUgcm9vdCBlbGVtZW50IHdpbGwgbm90IGJlIGJvdW5kLiBUcnVlIGJ5IGRlZmF1bHQuXG4gKiBAcGFyYW0gIHtCb29sZWFufSB0aHJvd09uRXJyb3JzICAgICAgIElmIHNldCB0byBmYWxzZSwgdGhlbiBlcnJvcnMgd2lsbCBvbmx5IGJlIGxvZ2dlZCB0byBjb25zb2xlLiBUcnVlIGJ5IGRlZmF1bHQuXG4gKiBAcmV0dXJuIHtTY29wZX0gICAgICAgICAgICAgICAgICAgICAgIFtkZXNjcmlwdGlvbl1cbiAqL1xuZnVuY3Rpb24gY3JlYXRlQmluZGVyU2NvcGUoc2NvcGVFbCwgc2NvcGVPYmplY3RGYWN0b3J5LCByb290U2NvcGUsIGJpbmRSb290RWxlbWVudCwgdGhyb3dPbkVycm9ycykge1xuICAgIHZhciBzY29wZUVsID0gc2NvcGVFbCB8fCBkb2N1bWVudC5ib2R5XG4gICAgICAgICwgc2NvcGUgPSByb290U2NvcGUgfHwgbmV3IFNjb3BlKHNjb3BlRWwpXG4gICAgICAgICwgYWRkTWV0aG9kID0gdGhyb3dPbkVycm9ycyA9PT0gZmFsc2UgPyAnX3NhZmVBZGQnIDogJ19hZGQnO1xuXG4gICAgY3JlYXRlU2NvcGVGb3JFbGVtZW50KHNjb3BlLCBzY29wZUVsLCBiaW5kUm9vdEVsZW1lbnQpO1xuXG4gICAgcmV0dXJuIHNjb3BlO1xuXG5cbiAgICBmdW5jdGlvbiBjcmVhdGVTY29wZUZvckVsZW1lbnQoc2NvcGUsIGVsLCBiaW5kUm9vdEVsZW1lbnQpIHtcbiAgICAgICAgLy8gZ2V0IGVsZW1lbnQncyBiaW5kaW5nIGF0dHJpYnV0ZSAobWwtYmluZCBieSBkZWZhdWx0KVxuICAgICAgICB2YXIgYXR0ciA9IG5ldyBCaW5kQXR0cmlidXRlKGVsKTtcblxuICAgICAgICAvLyBpZiBlbGVtZW50IGhhcyBiaW5kIGF0dHJpYnV0ZSBjcmF0ZSBzY29wZSBvYmplY3QgKENvbXBvbmVudCBvciBDb21wb25lbnRJbmZvKVxuICAgICAgICBpZiAoYXR0ci5ub2RlICYmIGJpbmRSb290RWxlbWVudCAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgIHZhciBzY29wZWRPYmplY3QgPSBzY29wZU9iamVjdEZhY3Rvcnkoc2NvcGUsIGVsLCBhdHRyLCB0aHJvd09uRXJyb3JzKVxuICAgICAgICAgICAgICAgICwgaXNDb250YWluZXIgPSB0eXBlb2Ygc2NvcGVkT2JqZWN0ICE9ICd1bmRlZmluZWQnICYmIHNjb3BlZE9iamVjdC5jb250YWluZXI7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBpZiB0aGVyZSBhcmUgY2hpbGROb2RlcyBhZGQgY2hpbGRyZW4gdG8gbmV3IHNjb3BlIGlmIHRoaXMgZWxlbWVudCBoYXMgY29tcG9uZW50IHdpdGggQ29udGFpbmVyIGZhY2V0XG4gICAgICAgIC8vIG90aGVyd2lzZSBjcmVhdGUgYSBuZXcgc2NvcGVcbiAgICAgICAgaWYgKGVsLmNoaWxkTm9kZXMgJiYgZWwuY2hpbGROb2Rlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGlmIChpc0NvbnRhaW5lcikge1xuICAgICAgICAgICAgICAgIHZhciBpbm5lclNjb3BlID0gbmV3IFNjb3BlKGVsKTtcbiAgICAgICAgICAgICAgICBzY29wZWRPYmplY3QuY29udGFpbmVyLnNjb3BlID0gaW5uZXJTY29wZTtcbiAgICAgICAgICAgICAgICBpbm5lclNjb3BlLl9ob3N0T2JqZWN0ID0gc2NvcGVkT2JqZWN0LmNvbnRhaW5lcjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY3JlYXRlU2NvcGVGb3JDaGlsZHJlbihlbCwgaXNDb250YWluZXIgPyBpbm5lclNjb3BlIDogc2NvcGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gaWYgc2NvcGUgd2Fzbid0IHByZXZpb3VzbHkgY3JlYXRlZCBvbiBjb250YWluZXIgZmFjZXQsIGNyZWF0ZSBlbXB0eSBzY29wZSBhbnl3YXlcbiAgICAgICAgaWYgKGlzQ29udGFpbmVyICYmICEgc2NvcGVkT2JqZWN0LmNvbnRhaW5lci5zY29wZSlcbiAgICAgICAgICAgIHNjb3BlZE9iamVjdC5jb250YWluZXIuc2NvcGUgPSBuZXcgU2NvcGUoZWwpO1xuXG5cbiAgICAgICAgLy8gVE9ETyBjb25kaXRpb24gYWZ0ZXIgJiYgaXMgYSBoYWNrLCBzaG91bGQgbm90IGJlIHVzZWQhXG4gICAgICAgIGlmIChzY29wZWRPYmplY3QpIC8vICYmICEgc2NvcGVbYXR0ci5jb21wTmFtZV0pXG4gICAgICAgICAgICBzY29wZVthZGRNZXRob2RdKHNjb3BlZE9iamVjdCwgYXR0ci5jb21wTmFtZSk7XG5cbiAgICAgICAgLy8gXy5kZWZlcihwb3N0Q2hpbGRyZW5Cb3VuZE1lc3NhZ2UsIGVsKTtcbiAgICAgICAgcG9zdENoaWxkcmVuQm91bmRNZXNzYWdlKGVsKTtcblxuICAgICAgICByZXR1cm4gc2NvcGVkT2JqZWN0O1xuXG5cbiAgICAgICAgZnVuY3Rpb24gcG9zdENoaWxkcmVuQm91bmRNZXNzYWdlKGVsKSB7XG4gICAgICAgICAgICB2YXIgZWxDb21wID0gQ29tcG9uZW50LmdldENvbXBvbmVudChlbCk7XG5cbiAgICAgICAgICAgIGlmIChlbENvbXApXG4gICAgICAgICAgICAgICAgZWxDb21wLnBvc3RNZXNzYWdlU3luYygnY2hpbGRyZW5ib3VuZCcpO1xuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBjcmVhdGVTY29wZUZvckNoaWxkcmVuKGNvbnRhaW5lckVsLCBzY29wZSkge1xuICAgICAgICB2YXIgY2hpbGRyZW4gPSB1dGlsRG9tLmNoaWxkcmVuKGNvbnRhaW5lckVsKTtcblxuICAgICAgICBfLmZvckVhY2goY2hpbGRyZW4sIGZ1bmN0aW9uKG5vZGUpIHtcbiAgICAgICAgICAgIGNyZWF0ZVNjb3BlRm9yRWxlbWVudChzY29wZSwgbm9kZSwgdHJ1ZSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gc2NvcGU7XG4gICAgfVxufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY29yZUNsYXNzZXMgPSByZXF1aXJlKCdtaWxvLWNvcmUnKS5jbGFzc2VzO1xuXG4vLyA8YSBuYW1lPVwiY2xhc3Nlc1wiPjwvYT5cbi8vIG1pbG8uY2xhc3Nlc1xuLy8gLS0tLS0tLS0tLS1cblxuLy8gVGhpcyBtb2R1bGUgY29udGFpbnMgZm91bmRhdGlvbiBjbGFzc2VzIGFuZCBjbGFzcyByZWdpc3RyaWVzLlxuXG52YXIgY2xhc3NlcyA9IHtcbiAgICBGYWNldDogcmVxdWlyZSgnLi9hYnN0cmFjdC9mYWNldCcpLFxuICAgIEZhY2V0ZWRPYmplY3Q6IHJlcXVpcmUoJy4vYWJzdHJhY3QvZmFjZXRlZF9vYmplY3QnKSxcbiAgICBTY29wZTogcmVxdWlyZSgnLi9jb21wb25lbnRzL3Njb3BlJyksXG4gICAgQ2xhc3NSZWdpc3RyeTogcmVxdWlyZSgnLi9hYnN0cmFjdC9yZWdpc3RyeScpLFxuICAgIE1peGluOiBjb3JlQ2xhc3Nlcy5NaXhpbixcbiAgICBNZXNzYWdlU291cmNlOiBjb3JlQ2xhc3Nlcy5NZXNzYWdlU291cmNlLFxuICAgIE1lc3Nlbmdlck1lc3NhZ2VTb3VyY2U6IGNvcmVDbGFzc2VzLk1lc3Nlbmdlck1lc3NhZ2VTb3VyY2UsXG4gICAgTWVzc2VuZ2VyQVBJOiBjb3JlQ2xhc3Nlcy5NZXNzZW5nZXJBUEksXG4gICAgRE9NRXZlbnRzU291cmNlOiByZXF1aXJlKCcuL2NvbXBvbmVudHMvbXNnX3NyYy9kb21fZXZlbnRzJyksXG4gICAgVHJhbnNhY3Rpb246IHJlcXVpcmUoJy4vY29tbWFuZC90cmFuc2FjdGlvbicpLFxuICAgIFRyYW5zYWN0aW9uSGlzdG9yeTogcmVxdWlyZSgnLi9jb21tYW5kL3RyYW5zYWN0aW9uX2hpc3RvcnknKVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBjbGFzc2VzO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIGxvZ2dlciA9IG1pbG9Db3JlLnV0aWwubG9nZ2VyO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQWN0aW9uc0hpc3Rvcnk7XG5cblxuLyoqXG4gKiBTdG9yZXMgbGlzdCBvZiBjb21tYW5kcyBvciB0cmFuc2FjdGlvbnNcbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqIEBwYXJhbSB7TnVtYmVyfSBtYXhMZW5ndGhcbiAqL1xuZnVuY3Rpb24gQWN0aW9uc0hpc3RvcnkobWF4TGVuZ3RoKSB7XG4gICAgdGhpcy5fbWF4TGVuZ3RoID0gbWF4TGVuZ3RoIHx8IEluZmluaXR5O1xuICAgIHRoaXMuYWN0aW9ucyA9IFtdO1xuICAgIHRoaXMucG9zaXRpb24gPSAwO1xufVxuXG5cbl8uZXh0ZW5kUHJvdG8oQWN0aW9uc0hpc3RvcnksIHtcbiAgICBzdG9yZTogQWN0aW9uc0hpc3Rvcnkkc3RvcmUsXG4gICAgZGVsZXRlTGFzdDogQWN0aW9uc0hpc3RvcnkkZGVsZXRlTGFzdCxcbiAgICB1bmRvOiBBY3Rpb25zSGlzdG9yeSR1bmRvLFxuICAgIHJlZG86IEFjdGlvbnNIaXN0b3J5JHJlZG8sXG4gICAgdW5kb0FsbDogQWN0aW9uc0hpc3RvcnkkdW5kb0FsbCxcbiAgICByZWRvQWxsOiBBY3Rpb25zSGlzdG9yeSRyZWRvQWxsLFxuICAgIHVuZG9BbGxBc3luYzogQWN0aW9uc0hpc3RvcnkkdW5kb0FsbEFzeW5jLFxuICAgIHJlZG9BbGxBc3luYzogQWN0aW9uc0hpc3RvcnkkcmVkb0FsbEFzeW5jLFxuICAgIGVhY2g6IEFjdGlvbnNIaXN0b3J5JGVhY2gsXG4gICAgZWFjaFJldmVyc2U6IEFjdGlvbnNIaXN0b3J5JGVhY2hSZXZlcnNlLFxuICAgIGdldExhc3RBY3Rpb246IEFjdGlvbnNIaXN0b3J5JGdldExhc3RBY3Rpb24sXG5cbiAgICBnZXREZXNjcmlwdGlvbjogQWN0aW9uc0hpc3RvcnkkZ2V0RGVzY3JpcHRpb25cbn0pO1xuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JHN0b3JlKGNvbW1hbmQpIHtcbiAgICBfdHJ1bmNhdGVUb0N1cnJlbnRQb3NpdGlvbi5jYWxsKHRoaXMpO1xuICAgIHRoaXMuYWN0aW9ucy5wdXNoKGNvbW1hbmQpO1xuXG4gICAgaWYgKHRoaXMuYWN0aW9ucy5sZW5ndGggPiB0aGlzLl9tYXhMZW5ndGgpIHtcbiAgICAgICAgdmFyIGFjdCA9IHRoaXMuYWN0aW9ucy5zaGlmdCgpO1xuICAgICAgICBhY3QuZGVzdHJveSgpO1xuICAgIH1cblxuICAgIHRoaXMucG9zaXRpb24gPSB0aGlzLmFjdGlvbnMubGVuZ3RoO1xuICAgIHJldHVybiB0aGlzLnBvc2l0aW9uIC0gMVxufVxuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JGRlbGV0ZUxhc3QoKSB7XG4gICAgaWYgKCF0aGlzLmFjdGlvbnMubGVuZ3RoKSByZXR1cm47XG4gICAgdGhpcy5wb3NpdGlvbi0tO1xuICAgIHRoaXMuYWN0aW9ucy5sZW5ndGgtLTtcbn1cblxuXG5mdW5jdGlvbiBfdHJ1bmNhdGVUb0N1cnJlbnRQb3NpdGlvbigpIHtcbiAgICBmb3IgKHZhciBpID0gdGhpcy5wb3NpdGlvbjsgaSA8IHRoaXMuYWN0aW9ucy5sZW5ndGg7IGkrKylcbiAgICAgICAgdGhpcy5hY3Rpb25zW2ldLmRlc3Ryb3koKTtcbiAgICB0aGlzLmFjdGlvbnMubGVuZ3RoID0gdGhpcy5wb3NpdGlvbjtcbn1cblxuXG5mdW5jdGlvbiBBY3Rpb25zSGlzdG9yeSR1bmRvKGNiKSB7XG4gICAgaWYgKHRoaXMucG9zaXRpb24gPT0gMCkgcmV0dXJuOyAvLyBub3RoaW5nIHRvIHVuZG9cbiAgICB2YXIgYWN0ID0gdGhpcy5hY3Rpb25zWy0tdGhpcy5wb3NpdGlvbl07XG4gICAgYWN0LnVuZG8oY2IpO1xuICAgIHJldHVybiBhY3Q7XG59XG5cblxuZnVuY3Rpb24gQWN0aW9uc0hpc3RvcnkkcmVkbyhjYikge1xuICAgIGlmICh0aGlzLnBvc2l0aW9uID09IHRoaXMuYWN0aW9ucy5sZW5ndGgpIHJldHVybjsgLy8gbm90aGluZyB0byByZWRvXG4gICAgdmFyIGFjdCA9IHRoaXMuYWN0aW9uc1t0aGlzLnBvc2l0aW9uKytdO1xuICAgIGFjdC5yZWRvKGNiKTtcbiAgICByZXR1cm4gYWN0O1xufVxuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JHVuZG9BbGwoKSB7XG4gICAgd2hpbGUgKHRoaXMucG9zaXRpb24pIHRoaXMudW5kbygpO1xufVxuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JHJlZG9BbGwoKSB7XG4gICAgd2hpbGUgKHRoaXMucG9zaXRpb24gPCB0aGlzLmFjdGlvbnMubGVuZ3RoKSB0aGlzLnJlZG8oKTtcbn1cblxuXG5mdW5jdGlvbiBBY3Rpb25zSGlzdG9yeSR1bmRvQWxsQXN5bmMoY2IpIHtcbiAgICBpZiAodGhpcy5wb3NpdGlvbikge1xuICAgICAgICB0aGlzLnVuZG8oKTtcbiAgICAgICAgaWYgKHRoaXMucG9zaXRpb24pXG4gICAgICAgICAgICBfLmRlZmVyTWV0aG9kKHRoaXMsICd1bmRvQWxsQXN5bmMnLCBjYik7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGlmIChjYikgXy5kZWZlcihjYik7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JHJlZG9BbGxBc3luYyhjYikge1xuICAgIGlmICh0aGlzLnBvc2l0aW9uIDwgdGhpcy5hY3Rpb25zLmxlbmd0aCkge1xuICAgICAgICB0aGlzLnJlZG8oKTtcbiAgICAgICAgaWYgKHRoaXMucG9zaXRpb24gPCB0aGlzLmFjdGlvbnMubGVuZ3RoKSBcbiAgICAgICAgICAgIF8uZGVmZXJNZXRob2QodGhpcywgJ3JlZG9BbGxBc3luYycsIGNiKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgaWYgKGNiKSBfLmRlZmVyKGNiKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gQWN0aW9uc0hpc3RvcnkkZWFjaChmdW5jT3JNZXRob2QsIHRoaXNBcmcpIHtcbiAgICB2YXIgZnVuYyA9IHR5cGVvZiBmdW5jT3JNZXRob2QgPT0gJ3N0cmluZydcbiAgICAgICAgICAgICAgICA/IGZ1bmN0aW9uKGFjdCkgeyBhY3RbZnVuY09yTWV0aG9kXSgpOyB9XG4gICAgICAgICAgICAgICAgOiBmdW5jT3JNZXRob2Q7XG5cbiAgICB0aGlzLmFjdGlvbnMuZm9yRWFjaChmdW5jLCB0aGlzQXJnIHx8IHRoaXMpO1xufVxuXG5cbmZ1bmN0aW9uIEFjdGlvbnNIaXN0b3J5JGVhY2hSZXZlcnNlKGZ1bmNPck1ldGhvZCwgdGhpc0FyZykge1xuICAgIHRoaXMuYWN0aW9ucy5yZXZlcnNlKCk7XG4gICAgdGhpcy5lYWNoKGZ1bmNPck1ldGhvZCwgdGhpc0FyZyk7XG4gICAgdGhpcy5hY3Rpb25zLnJldmVyc2UoKTtcbn1cblxuXG5mdW5jdGlvbiBBY3Rpb25zSGlzdG9yeSRnZXRMYXN0QWN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLnBvc2l0aW9uICYmIHRoaXMuYWN0aW9uc1t0aGlzLnBvc2l0aW9uIC0gMV07XG59XG5cblxuZnVuY3Rpb24gQWN0aW9uc0hpc3RvcnkkZ2V0RGVzY3JpcHRpb24oKSB7XG4gICAgdmFyIGFjdGlvbnMgPSB0aGlzLmFjdGlvbnMubWFwKGZ1bmN0aW9uKGFjdCkge1xuICAgICAgICByZXR1cm4gYWN0LmdldERlc2NyaXB0aW9uKCk7XG4gICAgfSk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgYWN0aW9uczogYWN0aW9ucyxcbiAgICAgICAgcG9zaXRpb246IHRoaXMucG9zaXRpb24sXG4gICAgICAgIGxlbmd0aDogYWN0aW9ucy5sZW5ndGhcbiAgICB9O1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2xhc3NSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2Fic3RyYWN0L3JlZ2lzdHJ5JylcbiAgICAsIENvbW1hbmQgPSByZXF1aXJlKCcuL2luZGV4Jyk7XG5cbi8qKlxuICogYG1pbG8ucmVnaXN0cnkuY29tcG9uZW50c2BcbiAqIEFuIGluc3RhbmNlIG9mIFtDbGFzc1JlZ2lzdHJ5XSguLi9hYnN0cmFjdC9yZWdpc3RyeS5qcy5odG1sKSBjbGFzcyB0aGF0IGlzIHVzZWQgYnkgbWlsbyB0byByZWdpc3RlciBhbmQgZmluZCBjb21wb25lbnRzLlxuICovXG52YXIgY29tbWFuZHNSZWdpc3RyeSA9IG5ldyBDbGFzc1JlZ2lzdHJ5KENvbW1hbmQpO1xuXG4vLyBhZGQgY29tbW9uIGFuY2VzdG9yIHRvIGFsbCBjb21wb25lbnRzIHRvIHRoZSByZWdpc3RyeS5cbmNvbW1hbmRzUmVnaXN0cnkuYWRkKENvbW1hbmQpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbW1hbmRzUmVnaXN0cnk7XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgY2hlY2sgPSBtaWxvQ29yZS51dGlsLmNoZWNrXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBsb2dnZXIgPSBtaWxvQ29yZS51dGlsLmxvZ2dlcjtcblxuXG52YXIgVU5ET19DT01NQU5EID0gJ191bmRvQ29tbWFuZCc7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBDb21tYW5kO1xuXG5cbi8qKlxuICogQ29tbWFuZCBjbGFzcyB0byBpbXBsZW1lbnQgXCJjb21tYW5kIHBhdHRlcm5cIiAtIHBhY2thZ2luZyBsbCBpbmZvcm1hdGlvbiBuZWNlc3NhcnkgZm9yIGRlbGF5ZWQgbWV0aG9kIGV4ZWN1dGlvblxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBtZXRob2QgbmFtZSBvciBmdW5jdGlvbiB0byBiZSBleGVjdXRlZFxuICogQHBhcmFtIHtMaXN0fSAqYXJndW1lbnRzIHBhcmFtZXRlcnMgdG8gYmUgcGFzc2VkIHRvIG1ldGhvZCBvciBmdW5jdGlvblxuICovXG5mdW5jdGlvbiBDb21tYW5kKGZ1bmMpIHsgLy8gLCAuLi4gYXJndW1lbnRzXG4gICAgdGhpcy5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuLyoqXG4gKiBDb21tYW5kIGluc3RhbmNlIG1ldGhvZHNcbiAqIFxuICogLSBbaW5pdF0oI0NvbW1hbmQkZXhlY3V0ZSkgLSBpbml0aWFsaXplIGNvbW1hbmQsIHNob3VsZCBiZSBvdmVyd3JpdHRlbiBieSBzdWJjbGFzc2VzXG4gKiAtIFtleGVjdXRlXSgjQ29tbWFuZCRleGVjdXRlKSAtIGV4ZWN1dGUgY29tbWFuZFxuICogLSBbc2V0VW5kb10oI0NvbW1hbmQkc2V0VW5kbykgLSBzZXQgdW5kbyBjb21tYW5kIGZvciB0aGlzIGNvbW1hbmRcbiAqIC0gW2dldFVuZG9dKCNDb21tYW5kJGdldFVuZG8pIC0gZ2V0IHVuZG8gY29tbWFuZCBvZiB0aGlzIGNvbW1hbmRcbiAqIC0gW3NldEFyZ3VtZW50c10oI0NvbW1hbmQkc2V0QXJndW1lbnRzKSAtIHNldCBjb21tYW5kcyBhcmd1bWVudHNcbiAqIC0gW2FkZEFyZ3VtZW50c10oI0NvbW1hbmQkYWRkQXJndW1lbnRzKSAtIGFkZCBhcmd1bWVudHMgdG8gY29tbWFuZFxuICogLSBbZGVzdHJveV0oI0NvbW1hbmQkZGVzdHJveSlcbiAqL1xuXy5leHRlbmRQcm90byhDb21tYW5kLCB7XG4gICAgaW5pdDogQ29tbWFuZCRpbml0LFxuICAgIGV4ZWN1dGU6IENvbW1hbmQkZXhlY3V0ZSxcbiAgICBzZXRVbmRvOiBDb21tYW5kJHNldFVuZG8sXG4gICAgZ2V0VW5kbzogQ29tbWFuZCRnZXRVbmRvLFxuICAgIHVuZG86IENvbW1hbmQkdW5kbyxcbiAgICByZWRvOiBDb21tYW5kJGV4ZWN1dGUsIC8vIHNhbWUgZm9yIGNvbW1hbmQsIGRpZmZlcmVudCBmb3IgdHJhbnNhY3Rpb25cbiAgICBzZXRBcmd1bWVudHM6IENvbW1hbmQkc2V0QXJndW1lbnRzLFxuICAgIGFkZEFyZ3VtZW50czogQ29tbWFuZCRhZGRBcmd1bWVudHMsXG4gICAgZ2V0QXJndW1lbnRzOiBDb21tYW5kJGdldEFyZ3VtZW50cyxcbiAgICBjaGFuZ2VBcmd1bWVudHM6IENvbW1hbmQkY2hhbmdlQXJndW1lbnRzLFxuICAgIGRlc3Ryb3k6IENvbW1hbmQkZGVzdHJveSxcblxuICAgIHNldENvbW1lbnQ6IENvbW1hbmQkc2V0Q29tbWVudCxcbiAgICBnZXREZXNjcmlwdGlvbjogQ29tbWFuZCRnZXREZXNjcmlwdGlvblxufSk7XG5cblxuLyoqXG4gKiBDb21tYW5kIGNsYXNzIG1ldGhvZHNcbiAqXG4gKiAtIFtjcmVhdGVdKCNDb21tYW5kJCRjcmVhdGUpIC0gY29tbWFuZHMgZmFjdG9yeVxuICovXG5fLmV4dGVuZChDb21tYW5kLCB7XG4gICAgY3JlYXRlOiBDb21tYW5kJCRjcmVhdGUsXG4gICAgY3JlYXRlV2l0aFVuZG86IENvbW1hbmQkJGNyZWF0ZVdpdGhVbmRvXG59KTtcblxuXG5mdW5jdGlvbiBDb21tYW5kJGluaXQoZnVuYykgeyAvLyAsIC4uLiBhcmd1bWVudHNcbiAgICBjaGVjayhmdW5jLCBNYXRjaC5PcHRpb25hbChGdW5jdGlvbikpO1xuICAgIHRoaXMuZnVuYyA9IGZ1bmMgfHwgZnVuY3Rpb24oKXt9O1xuICAgIHRoaXMuYXJncyA9IF8uc2xpY2UoYXJndW1lbnRzLCAxKTsgICAgXG59XG5cblxuLyoqXG4gKiBFeGVjdXRlIGNvbW1hbmQgbWFraW5nIGNvbW1hbmQgb2JqZWN0IGF2YWlsYWJsZSB2aWEgZnVuY3Rpb24gcHJvcGVydHkuIFxuICovXG5mdW5jdGlvbiBDb21tYW5kJGV4ZWN1dGUoY2IpIHtcbiAgICB2YXIgcmVzdWx0ID0gdGhpcy5mdW5jLmFwcGx5KHRoaXMsIHRoaXMuYXJncyk7XG4gICAgaWYgKGNiKSBfLmRlZmVyKGNiKTtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuXG5cbi8qKlxuICogU2V0IHVuZG8gY29tbWFuZCBmb3IgdGhpcyBjb21tYW5kLiBUaGlzIGNvbW1hbmQgYmVjb21lcyB1bmRvIGNvbW1hbmQgZm9yIHVuZG8gY29tbWFuZCAoc28gdW5kbyBjb21tYW5kIGNhbiBjaGFuZ2UgdGhpcyBjb21tYW5kIGR1cmluZyBpdHMgZXhlY3V0aW9uKS5cbiAqIFxuICogQHBhcmFtIHtDb21tYW5kfSB1bmRvQ29tbWFuZFxuICovXG5mdW5jdGlvbiBDb21tYW5kJHNldFVuZG8odW5kb0NvbW1hbmQpIHtcbiAgICBpZiAodGhpc1tVTkRPX0NPTU1BTkRdKVxuICAgICAgICBsb2dnZXIud2FybignQ29tbWFuZCBzZXRVbmRvOiB1bmRvIGNvbW1hbmQgaXMgYWxyZWFkeSBzZXQnKTtcblxuICAgIHRoaXNbVU5ET19DT01NQU5EXSA9IHVuZG9Db21tYW5kO1xuICAgIHVuZG9Db21tYW5kW1VORE9fQ09NTUFORF0gPSB0aGlzO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB1bmRvIGNvbW1hbmQgb2YgYSBnaXZlbiBjb21tYW5kXG4gKlxuICogQHJldHVybiB7Q29tbWFuZH1cbiAqL1xuZnVuY3Rpb24gQ29tbWFuZCRnZXRVbmRvKCkge1xuICAgIHJldHVybiB0aGlzW1VORE9fQ09NTUFORF07XG59XG5cblxuLyoqXG4gKiBFeGVjdXRlcyB1bmRvIGNvbW1hbmQgb2YgY3VycmVudCBjb21tYW5kXG4gKi9cbmZ1bmN0aW9uIENvbW1hbmQkdW5kbyhjYikge1xuICAgIHZhciB1bmRvQ21kID0gdGhpcy5nZXRVbmRvKCk7XG4gICAgaWYgKCEgdW5kb0NtZCkgcmV0dXJuIGxvZ2dlci5lcnJvcignQ29tbWFuZCB1bmRvIGNhbGxlZCB3aXRob3V0IHVuZG8gY29tbWFuZCBwcmVzZW50Jyk7XG4gICAgdmFyIHJlc3VsdCA9IHVuZG9DbWQuZXhlY3V0ZSgpO1xuICAgIGlmIChjYikgXy5kZWZlcihjYik7XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cblxuXG4vKipcbiAqIFNldCBjb21tYW5kJ3MgYXJndW1lbnRzLiBJZiBhcmd1bWVudHMgd2VyZSBzZXQgZHVyaW5nIGNvbW1hbmQncyBjcmVhdGlvbiwgdGhpcyBtZXRob2Qgd2lsbCBvdmVyd3JpdGUgYXJndW1lbnRzIGFuZCBsb2cgd2FybmluZy5cbiAqXG4gKiBAcGFyYW0ge0xpc3R9ICphcmd1bWVudHNcbiAqL1xuZnVuY3Rpb24gQ29tbWFuZCRzZXRBcmd1bWVudHMoKSB7IC8vLCAuLi4gYXJndW1lbnRzXG4gICAgaWYgKHRoaXMuYXJncyAmJiB0aGlzLmFyZ3MubGVuZ3RoKVxuICAgICAgICBsb2dnZXIud2FybignQ29tbWFuZCBzZXRBcmd1bWVudHM6IGNvbW1hbmQgYXJndW1lbnRzIGFyZSBhbHJlYWR5IHNldCcpO1xuICAgIHRoaXMuYXJncyA9IF8udG9BcnJheShhcmd1bWVudHMpO1xufVxuXG5cbmZ1bmN0aW9uIENvbW1hbmQkZ2V0QXJndW1lbnRzKCkge1xuICAgIHJldHVybiB0aGlzLmFyZ3M7XG59XG5cblxuZnVuY3Rpb24gQ29tbWFuZCRjaGFuZ2VBcmd1bWVudHMoKSB7IC8vLCAuLi4gYXJndW1lbnRzXG4gICAgdGhpcy5hcmdzID0gXy50b0FycmF5KGFyZ3VtZW50cyk7XG59XG5cblxuLyoqXG4gKiBBZGQgKGFwcGVuZCkgYXJndW1lbnRzIHRvIGNvbW1hbmRcbiAqXG4gKiBAcGFyYW0ge0xpc3R9ICphcmd1bWVudHMgYXJndW1lbnRzIGxpc3QgdG8gYmUgYXBwZW5kZWQgdG8gY29tbWFuZFxuICovXG5mdW5jdGlvbiBDb21tYW5kJGFkZEFyZ3VtZW50cygpIHsgLy8sIC4uLiBhcmd1bWVudHNcbiAgICBpZiAoISB0aGlzLmFyZ3MpIHRoaXMuYXJncyA9IFtdO1xuICAgIF8uYXBwZW5kQXJyYXkodGhpcy5hcmdzLCBhcmd1bWVudHMpO1xufVxuXG5cbi8qKlxuICogQ29tbWFuZHMgZmFjdG9yeS4gTGlrZWx5IG90IGJlIG92ZXJyaWRkZW4gYnkgc3ViY2xhc3NlcyB0byBpbXBsZW1lbnQgY3VzdG9tIGxvZ2ljIG9mIGNvbW1hbmQgY29uc3RydWN0aW9uXG4gKiBcbiAqIEB0aGlzIHtGdW5jdGlvbn0gQ2xhc3Mgb2YgY29tbWFuZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBtZXRob2QgbmFtZSBvciBmdW5jdGlvbiB0byBiZSBleGVjdXRlZFxuICogQHBhcmFtIHtMaXN0fSAqYXJndW1lbnRzIHBhcmFtZXRlcnMgdG8gYmUgcGFzc2VkIHRvIG1ldGhvZCBvciBmdW5jdGlvblxuICogQHJldHVybiB7Q29tbWFuZH1cbiAqL1xuZnVuY3Rpb24gQ29tbWFuZCQkY3JlYXRlKGZ1bmMpIHsgLy8gLCAuLi4gYXJndW1lbnRzXG4gICAgcmV0dXJuIF8ubmV3QXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuXG5mdW5jdGlvbiBDb21tYW5kJCRjcmVhdGVXaXRoVW5kbygpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2NyZWF0ZVdpdGhVbmRvIHNob3VsZCBiZSBpbXBsZW1lbnRlZCBieSBzdWJzY2xhc3MnKTtcbn1cblxuXG4vKipcbiAqIERlc3Ryb3kgY3VycmVudCBjb21tYW5kICh0byBwcmV2ZW50IHBvdGVudGlhbCBtZW1vcnkgbGVha3Mgd2hlbiBjb21tYW5kcyBwb2ludCB0byBET00gZWxlbWVudHMpXG4gKi9cbmZ1bmN0aW9uIENvbW1hbmQkZGVzdHJveSgpIHtcbiAgICBkZWxldGUgdGhpcy5mdW5jO1xuICAgIGRlbGV0ZSB0aGlzLmFyZ3M7XG4gICAgdmFyIHVuZG9DbWQgPSB0aGlzW1VORE9fQ09NTUFORF07XG4gICAgaWYgKHVuZG9DbWQpIHtcbiAgICAgICAgZGVsZXRlIHRoaXNbVU5ET19DT01NQU5EXVtVTkRPX0NPTU1BTkRdO1xuICAgICAgICBkZWxldGUgdGhpc1tVTkRPX0NPTU1BTkRdO1xuICAgICAgICB1bmRvQ21kLmRlc3Ryb3koKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gQ29tbWFuZCRzZXRDb21tZW50KGNvbW1lbnQpIHtcbiAgICB0aGlzLmNvbW1lbnQgPSBjb21tZW50O1xufVxuXG5cbmZ1bmN0aW9uIENvbW1hbmQkZ2V0RGVzY3JpcHRpb24oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgZnVuYzogdGhpcy5mdW5jLm5hbWUsXG4gICAgICAgIGNvbW1lbnQ6IHRoaXMuY29tbWVudFxuICAgIH07XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIEFjdGlvbnNIaXN0b3J5ID0gcmVxdWlyZSgnLi9hY3Rpb25zX2hpc3RvcnknKVxuICAgICwgXyA9IHJlcXVpcmUoJ21pbG8tY29yZScpLnByb3RvO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gVHJhbnNhY3Rpb247XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb24oKSB7XG4gICAgdGhpcy5jb21tYW5kcyA9IG5ldyBBY3Rpb25zSGlzdG9yeTtcbn1cblxuXG5fLmV4dGVuZFByb3RvKFRyYW5zYWN0aW9uLCB7XG4gICAgZXhlY3V0ZTogVHJhbnNhY3Rpb24kZXhlY3V0ZSxcbiAgICB1bmRvOiBUcmFuc2FjdGlvbiR1bmRvLFxuICAgIHJlZG86IFRyYW5zYWN0aW9uJHJlZG8sXG4gICAgZGVzdHJveTogVHJhbnNhY3Rpb24kZGVzdHJveSxcbiAgICBzdG9yZUNvbW1hbmQ6IFRyYW5zYWN0aW9uJHN0b3JlQ29tbWFuZCxcbiAgICBtZXJnZTogVHJhbnNhY3Rpb24kbWVyZ2UsXG5cbiAgICBzZXRDb21tZW50OiBUcmFuc2FjdGlvbiRzZXRDb21tZW50LFxuICAgIGdldERlc2NyaXB0aW9uOiBUcmFuc2FjdGlvbiRnZXREZXNjcmlwdGlvblxufSk7XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb24kZXhlY3V0ZSgpIHtcbiAgICB0aGlzLmNvbW1hbmRzLmVhY2goJ2V4ZWN1dGUnKTtcbn1cblxuXG5mdW5jdGlvbiBUcmFuc2FjdGlvbiR1bmRvKGNiKSB7XG4gICAgdGhpcy5jb21tYW5kcy51bmRvQWxsQXN5bmMoY2IpO1xufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uJHJlZG8oY2IpIHtcbiAgICB0aGlzLmNvbW1hbmRzLnJlZG9BbGxBc3luYyhjYik7XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb24kZGVzdHJveSgpIHtcbiAgICB0aGlzLmNvbW1hbmRzLmVhY2goJ2Rlc3Ryb3knKTtcbn1cblxuXG5mdW5jdGlvbiBUcmFuc2FjdGlvbiRzdG9yZUNvbW1hbmQoY29tbWFuZCkge1xuICAgIHRoaXMuY29tbWFuZHMuc3RvcmUoY29tbWFuZCk7XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb24kbWVyZ2UodHJhbnNhY3Rpb24pIHtcbiAgICB0cmFuc2FjdGlvbi5jb21tYW5kcy5lYWNoKGZ1bmN0aW9uKGNtZCkge1xuICAgICAgICB0aGlzLmNvbW1hbmRzLnN0b3JlKGNtZCk7XG4gICAgfSwgdGhpcyk7XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb24kc2V0Q29tbWVudChjb21tZW50KSB7XG4gICAgdGhpcy5jb21tZW50ID0gY29tbWVudFxufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uJGdldERlc2NyaXB0aW9uKCkge1xuICAgIHZhciBjb21tYW5kcyA9IHRoaXMuY29tbWFuZHMuZ2V0RGVzY3JpcHRpb24oKTtcbiAgICByZXR1cm4ge1xuICAgICAgICBjb21tYW5kczogY29tbWFuZHMuYWN0aW9ucyxcbiAgICAgICAgY29tbWVudDogdGhpcy5jb21tZW50XG4gICAgfVxufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBBY3Rpb25zSGlzdG9yeSA9IHJlcXVpcmUoJy4vYWN0aW9uc19oaXN0b3J5JylcbiAgICAsIFRyYW5zYWN0aW9uID0gcmVxdWlyZSgnLi90cmFuc2FjdGlvbicpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBsb2dnZXIgPSBtaWxvQ29yZS51dGlsLmxvZ2dlclxuICAgICwgTWVzc2VuZ2VyID0gbWlsb0NvcmUuTWVzc2VuZ2VyXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG87XG5cblxubW9kdWxlLmV4cG9ydHMgPSBUcmFuc2FjdGlvbkhpc3Rvcnk7XG5cblxudmFyIFNDSEVEVUxFRCA9ICdfc2NoZWR1bGVkJztcblxuXG5mdW5jdGlvbiBUcmFuc2FjdGlvbkhpc3RvcnkobWF4TGVuZ3RoKSB7XG4gICAgdGhpcy50cmFuc2FjdGlvbnMgPSBuZXcgQWN0aW9uc0hpc3RvcnkobWF4TGVuZ3RoKTtcbiAgICB0aGlzLmN1cnJlbnRCYXRjaCA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmN1cnJlbnRUcmFuc2FjdGlvbiA9IHVuZGVmaW5lZDtcbiAgICB0aGlzW1NDSEVEVUxFRF0gPSBmYWxzZTtcbn1cblxuXG5fLmV4dGVuZFByb3RvKFRyYW5zYWN0aW9uSGlzdG9yeSwge1xuICAgIHN0b3JlQ29tbWFuZDogVHJhbnNhY3Rpb25IaXN0b3J5JHN0b3JlQ29tbWFuZCxcbiAgICBlbmRUcmFuc2FjdGlvbjogVHJhbnNhY3Rpb25IaXN0b3J5JGVuZFRyYW5zYWN0aW9uLFxuICAgIHN0b3JlVHJhbnNhY3Rpb246IFRyYW5zYWN0aW9uSGlzdG9yeSRzdG9yZVRyYW5zYWN0aW9uLFxuICAgIGRlbGV0ZUxhc3RUcmFuc2FjdGlvbjogVHJhbnNhY3Rpb25IaXN0b3J5JGRlbGV0ZUxhc3RUcmFuc2FjdGlvbixcbiAgICB1bmRvOiBUcmFuc2FjdGlvbkhpc3RvcnkkdW5kbyxcbiAgICByZWRvOiBUcmFuc2FjdGlvbkhpc3RvcnkkcmVkbyxcbiAgICBpblRyYW5zYWN0aW9uOiBUcmFuc2FjdGlvbkhpc3RvcnkkaW5UcmFuc2FjdGlvbixcblxuICAgIGdldERlc2NyaXB0aW9uOiBUcmFuc2FjdGlvbkhpc3RvcnkkZ2V0RGVzY3JpcHRpb24sXG4gICAgdXNlTWVzc2VuZ2VyOiBUcmFuc2FjdGlvbkhpc3RvcnkkdXNlTWVzc2VuZ2VyLFxuICAgIGRlc3Ryb3k6IFRyYW5zYWN0aW9uSGlzdG9yeSRkZXN0cm95XG59KTtcblxuXG4vKipcbiAqIFN0b3JlcyBjb21tYW5kIGluIHRoZSBoaXN0b3J5LiBcbiAqIEBwYXJhbSB7Q29tbWFuZH0gY29tbWFuZCAgICAgICAgICAgXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGFwcGVuZFRyYW5zYWN0aW9uIElmIGB0cnVlYCwgYXBwZW5kcyB0byB0aGUgY3VycmVudCBvciBwcmV2aW91cyB0cmFuc2FjdGlvbiBpZiB0aGVyZSBpcyBubyBjdXJyZW50IHRyYW5zYWN0aW9uLlxuICovXG5mdW5jdGlvbiBUcmFuc2FjdGlvbkhpc3Rvcnkkc3RvcmVDb21tYW5kKGNvbW1hbmQsIGFwcGVuZFRyYW5zYWN0aW9uKSB7XG4gICAgaWYgKGFwcGVuZFRyYW5zYWN0aW9uICYmICEodGhpcy5jdXJyZW50VHJhbnNhY3Rpb24gfHwgdGhpcy5jdXJyZW50QmF0Y2gpKSB7XG4gICAgICAgIHZhciB0cmFuc2FjdGlvbiA9IHRoaXMudHJhbnNhY3Rpb25zLmdldExhc3RBY3Rpb24oKTtcbiAgICAgICAgdHJhbnNhY3Rpb24uc3RvcmVDb21tYW5kKGNvbW1hbmQpO1xuICAgICAgICBfcG9zdFRyYW5zYWN0aW9uTWVzc2FnZS5jYWxsKHRoaXMsICdhcHBlbmRlZCcsIHRyYW5zYWN0aW9uKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICghIHRoaXMuY3VycmVudEJhdGNoKSB0aGlzLmN1cnJlbnRCYXRjaCA9IG5ldyBUcmFuc2FjdGlvbjtcbiAgICB0aGlzLmN1cnJlbnRCYXRjaC5zdG9yZUNvbW1hbmQoY29tbWFuZCk7XG4gICAgaWYgKCEgdGhpc1tTQ0hFRFVMRURdKSB7XG4gICAgICAgIHRoaXNbU0NIRURVTEVEXSA9IHRydWU7XG4gICAgICAgIF8uZGVmZXJNZXRob2QodGhpcywgX3N0b3JlVHJhbnNhY3Rpb24pO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBUcmFuc2FjdGlvbkhpc3RvcnkkZGVsZXRlTGFzdFRyYW5zYWN0aW9uKCkge1xuICAgIGlmICh0aGlzLmN1cnJlbnRCYXRjaCB8fCB0aGlzLmN1cnJlbnRUcmFuc2FjdGlvbikge1xuICAgICAgICB0aGlzLmN1cnJlbnRCYXRjaCA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5jdXJyZW50VHJhbnNhY3Rpb24gPSB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy50cmFuc2FjdGlvbnMuZGVsZXRlTGFzdCgpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBfc3RvcmVUcmFuc2FjdGlvbigpIHtcbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2gpIHtcbiAgICAgICAgX2FkZEJhdGNoVG9UcmFuc2FjdGlvbi5jYWxsKHRoaXMpO1xuICAgICAgICBfLmRlZmVyTWV0aG9kKHRoaXMsIF9zdG9yZVRyYW5zYWN0aW9uKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBfc3RvcmVDdXJyZW50VHJhbnNhY3Rpb24uY2FsbCh0aGlzKTtcbiAgICAgICAgdGhpc1tTQ0hFRFVMRURdID0gZmFsc2U7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uSGlzdG9yeSRlbmRUcmFuc2FjdGlvbigpIHtcbiAgICBfYWRkQmF0Y2hUb1RyYW5zYWN0aW9uLmNhbGwodGhpcyk7XG4gICAgX3N0b3JlQ3VycmVudFRyYW5zYWN0aW9uLmNhbGwodGhpcyk7XG59XG5cblxuZnVuY3Rpb24gX2FkZEJhdGNoVG9UcmFuc2FjdGlvbigpIHtcbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2gpIHtcbiAgICAgICAgaWYgKCEgdGhpcy5jdXJyZW50VHJhbnNhY3Rpb24pIHRoaXMuY3VycmVudFRyYW5zYWN0aW9uID0gbmV3IFRyYW5zYWN0aW9uO1xuICAgICAgICB0aGlzLmN1cnJlbnRUcmFuc2FjdGlvbi5tZXJnZSh0aGlzLmN1cnJlbnRCYXRjaCk7XG4gICAgICAgIHRoaXMuY3VycmVudEJhdGNoID0gdW5kZWZpbmVkO1xuICAgIH0gXG59XG5cblxuZnVuY3Rpb24gX3N0b3JlQ3VycmVudFRyYW5zYWN0aW9uKCkge1xuICAgIGlmICh0aGlzLmN1cnJlbnRUcmFuc2FjdGlvbikge1xuICAgICAgICB2YXIgdCA9IHRoaXMuY3VycmVudFRyYW5zYWN0aW9uO1xuICAgICAgICB0aGlzLnRyYW5zYWN0aW9ucy5zdG9yZSh0KTtcbiAgICAgICAgX3Bvc3RUcmFuc2FjdGlvbk1lc3NhZ2UuY2FsbCh0aGlzLCAnc3RvcmVkJywgdCk7XG5cbiAgICAgICAgdGhpcy5jdXJyZW50VHJhbnNhY3Rpb24gPSB1bmRlZmluZWQ7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uSGlzdG9yeSRzdG9yZVRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKSB7XG4gICAgdGhpcy5lbmRUcmFuc2FjdGlvbigpO1xuXG4gICAgdGhpcy50cmFuc2FjdGlvbnMuc3RvcmUodHJhbnNhY3Rpb24pO1xuICAgIF9wb3N0VHJhbnNhY3Rpb25NZXNzYWdlLmNhbGwodGhpcywgJ3N0b3JlZCcsIHRyYW5zYWN0aW9uKTtcbn1cblxuXG5mdW5jdGlvbiBfcG9zdFRyYW5zYWN0aW9uTWVzc2FnZShtc2csIHRyYW5zYWN0aW9uKSB7XG4gICAgaWYgKHRoaXMuX21lc3NlbmdlcilcbiAgICAgICAgdGhpcy5fbWVzc2VuZ2VyLnBvc3RNZXNzYWdlKG1zZywgeyB0cmFuc2FjdGlvbjogdHJhbnNhY3Rpb24gfSk7XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb25IaXN0b3J5JHVuZG8oY2IpIHtcbiAgICB2YXIgdCA9IHRoaXMudHJhbnNhY3Rpb25zLnVuZG8oY2IpO1xuICAgIGlmICh0KSBfcG9zdFRyYW5zYWN0aW9uTWVzc2FnZS5jYWxsKHRoaXMsICd1bmRvbmUnLCB0KTtcbiAgICByZXR1cm4gdDtcbn1cblxuXG5mdW5jdGlvbiBUcmFuc2FjdGlvbkhpc3RvcnkkcmVkbyhjYikge1xuICAgIHZhciB0ID0gdGhpcy50cmFuc2FjdGlvbnMucmVkbyhjYik7XG4gICAgaWYgKHQpIF9wb3N0VHJhbnNhY3Rpb25NZXNzYWdlLmNhbGwodGhpcywgJ3JlZG9uZScsIHQpO1xuICAgIHJldHVybiB0O1xufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uSGlzdG9yeSRpblRyYW5zYWN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzW1NDSEVEVUxFRF07XG59XG5cblxuZnVuY3Rpb24gVHJhbnNhY3Rpb25IaXN0b3J5JGdldERlc2NyaXB0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLnRyYW5zYWN0aW9ucy5nZXREZXNjcmlwdGlvbigpO1xufVxuXG5cbmZ1bmN0aW9uIFRyYW5zYWN0aW9uSGlzdG9yeSR1c2VNZXNzZW5nZXIoKSB7XG4gICAgcmV0dXJuIHRoaXMuX21lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXIodGhpcywgTWVzc2VuZ2VyLmRlZmF1bHRNZXRob2RzKTtcbn1cblxuXG5mdW5jdGlvbiBUcmFuc2FjdGlvbkhpc3RvcnkkZGVzdHJveSgpIHtcbiAgICBpZiAodGhpcy5fbWVzc2VuZ2VyKSB0aGlzLl9tZXNzZW5nZXIuZGVzdHJveSgpO1xuICAgIGRlbGV0ZSB0aGlzLnRyYW5zYWN0aW9ucztcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgRmFjZXRlZE9iamVjdCA9IHJlcXVpcmUoJy4uL2Fic3RyYWN0L2ZhY2V0ZWRfb2JqZWN0JylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jX2ZhY2V0cy9jZl9yZWdpc3RyeScpXG4gICAgLCBDb21wb25lbnRGYWNldCA9IGZhY2V0c1JlZ2lzdHJ5LmdldCgnQ29tcG9uZW50RmFjZXQnKVxuICAgICwgY29tcG9uZW50VXRpbHMgPSByZXF1aXJlKCcuL2NfdXRpbHMnKVxuICAgICwgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgTWVzc2VuZ2VyID0gbWlsb0NvcmUuTWVzc2VuZ2VyXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIGNoZWNrID0gbWlsb0NvcmUudXRpbC5jaGVja1xuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJylcbiAgICAsIG1pbG9Db21wb25lbnROYW1lID0gcmVxdWlyZSgnLi4vdXRpbC9jb21wb25lbnRfbmFtZScpXG4gICAgLCBsb2dnZXIgPSBtaWxvQ29yZS51dGlsLmxvZ2dlclxuICAgICwgZG9tVXRpbHMgPSByZXF1aXJlKCcuLi91dGlsL2RvbScpXG4gICAgLCBCaW5kQXR0cmlidXRlID0gcmVxdWlyZSgnLi4vYXR0cmlidXRlcy9hX2JpbmQnKVxuICAgICwgU2NvcGUgPSByZXF1aXJlKCcuL3Njb3BlJylcbiAgICAsIERPTVN0b3JhZ2UgPSByZXF1aXJlKCcuLi91dGlsL3N0b3JhZ2UnKTtcblxudmFyIF9tYWtlQ29tcG9uZW50Q29uZGl0aW9uRnVuYyA9IGNvbXBvbmVudFV0aWxzLl9tYWtlQ29tcG9uZW50Q29uZGl0aW9uRnVuYztcblxuXG4vKipcbiAqIGBtaWxvLkNvbXBvbmVudGBcbiAqIEJhc2UgQ29tcG9uZW50IGNsYXNzLiBTdWJjbGFzcyBvZiBbRmFjZXRlZE9iamVjdF0oLi4vYWJzdHJhY3QvZmFjZXRlZF9vYmplY3QuanMuaHRtbCksIGJ1dCBub25lIG9mIHRoaXMgY2xhc3MgbWV0aG9kcyBzaG91bGQgYmUgZGlyZWN0bHkgdXNlZCB3aXRoIGNvbXBvbmVudC5cbiAqIEl0cyBjb25zdHJ1Y3RvciBwYXNzZXMgaXRzIHBhcmFtZXRlcnMsIGluY2x1ZGluZyBpdHMgW3Njb3BlXSguL3Njb3BlLmpzLmh0bWwpLCBET00gZWxlbWVudCBhbmQgbmFtZSB0byBbYGluaXRgXSgjaW5pdCkgbWV0aG9kLlxuICogVGhlIGNvbnN0cnVjdG9yIG9mIENvbXBvbmVudCBjbGFzcyByYXJlbHkgbmVlZHMgdG8gYmUgdXNlZCBkaXJlY3RseSwgYXMgW21pbG8uYmluZGVyXSguLi9iaW5kZXIuanMuaHRtbCkgY3JlYXRlcyBjb21wb25lbnRzIHdoZW4gaXQgc2NhbnMgRE9NIHRyZWUuXG4gKiBbYENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzc2BdKCNjcmVhdGVDb21wb25lbnRDbGFzcykgc2hvdWxkIGJlIHVzZWQgdG8gY3JlYXRlIGEgc3ViY2xhc3Mgb2YgQ29tcG9uZW50IGNsYXNzIHdpdGggY29uZmlndXJlZCBmYWNldHMuXG4gKlxuICpcbiAqICMjIyNDb21wb25lbnQgaW5zdGFuY2UgcHJvcGVydGllcyMjIyNcbiAqXG4gKiAtIGVsIC0gRE9NIGVsZW1lbnQgdGhhdCBjb21wb25lbnQgaXMgYXR0YWNoZWQgdG8uIElmIHRoZSBzZWNvbmQgY29tcG9uZW50IGlzIGF0dGFjaGVkIHRvIHRoZSBzYW1lIERPTSBlbGVtZW50LCB0aGUgd2FybmluZyB3aWxsIGJlIGxvZ2dlZCB0byBjb25zb2xlLiBUbyBnZXQgY29tcG9uZW50IHJlZmVyZW5jZSBmcm9tIERPTSBlbGVtZW50IHVzZSBbQ29tcG9uZW50LmdldENvbXBvbmVudF0oLi9jX3V0aWxzLmpzLmh0bWwjZ2V0Q29tcG9uZW50KSBjbGFzcyBtZXRob2QuIFRvIGluc3BlY3QgY29tcG9uZW50IHZpYSBlbGVtZW50IGluIGJyb3dzZXIgY2hlY2sgYF9fX21pbG9fY29tcG9uZW50YCBwcm9wZXJ0eSBvZiBlbGVtZW50IChwcm9wZXJ0eSBuYW1lIGJlIGNoYW5nZWQgdXNpbmcgYG1pbG8uY29uZmlnYCkuXG4gKiAtIHNjb3BlIC0gcGFyZW50IHNjb3BlIG9iamVjdCwgYW4gaW5zdGFuY2Ugb2YgW1Njb3BlXSguL3Njb3BlLmpzLmh0bWwpIGNsYXNzLiBUbyBnZXQgcGFyZW50IGNvbXBvbmVudCB1c2UgW2dldFNjb3BlUGFyZW50XSgjQ29tcG9uZW50JGdldFNjb3BlUGFyZW50KSBpbnN0YW5jZSBtZXRob2Qgb2YgY29tcG9uZW50LiBUaGUgYWN0dWFsIHBhdGggdG8gZ2V0IHBhcmVudCBvZiBjb25wb25lbnQgaXMgYGNvbXBvbmVudC5zY29wZS5faG9zdE9iamVjdC5vd25lcmAsIHdoZXJlIGBfaG9zdE9iamVjdGAgcmVmZXJzIHRvIFtDb250YWluZXJdKGNfZmFjZXRzL0NvbnRhaW5lci5qcy5odG1sKSBmYWNldCBvZiBwYXJlbnQgY29tcG9uZW50IGFuZCBgb3duZXJgIHRvIHRoZSBwYXJlbnQgaXRzZWxmLiBUaGUgY2hpbGRyZW4gb2YgY29tcG9uZW50IGFyZSBhY2Nlc3NpYmxlIHZpYSB0aGUgc2NvcGUgb2YgaXRzIGNvbnRhaW5lciBmYWNldDogYGNvbXBvbmVudC5jb250YWluZXIuc2NvcGVgLiBUaGUgc2NvcGUgaGllcmFyY2h5IGNhbiBiZSB0aGUgc2FtZSBvciBkaWZmZXJlbnQgYXMgdGhlIERPTSBoaWVyYXJjaHkgLSBET00gY2hpbGRyZW4gb2YgdGhlIGNvbXBvbmVudCB3aWxsIGJlIG9uIHRoZSBzYW1lIHNjb3BlIGFzIGNvbXBvbmVudCBpZiBpdCBkb2VzIG5vdCBoYXZlIGBDb250YWluZXJgIGZhY2V0IGFuZCBpbiB0aGUgc2NvcGUgb2YgaXRzIENvbnRhaW5lciBmYWNldCBpZiBpdCBoYXMgaXQuIFNlZSBbU2NvcGVdKC4vc2NvcGUuanMuaHRtbCkuXG4gKiAtIG5hbWUgLSB0aGUgbmFtZSBvZiBjb21wb25lbnQsIHNob3VsZCBiZSB1bmlxdWUgZm9yIHRoZSBzY29wZSB3aGVyZSBjb21wb25lbnQgYmVsb25ncy4gVG8gZmluZCBjb21wb25lbnQgaW4gc2NvcGUgdGhlIGNvbXBvbmVudCdzIG5hbWUgc2hvdWxkIGJlIHVzZWQgYXMgcHJvcGVydHkgb2Ygc2NvcGUgb2JqZWN0LiBTZWUgW1Njb3BlXSguL3Njb3BlLmpzLmh0bWwpLlxuICogLSBmYWNldHMgLSBtYXAgb2YgcmVmZXJlbmNlcyBvZiBhbGwgY29tcG9uZW50J3MgZmFjZXRzIChmYWNldCBuYW1lcyBhcmUgbG93ZXJjYXNlIGluIHRoaXMgbWFwKS4gQWxsIGZhY2V0cyBjYW4gYmUgYWNjZXNzZWQgZGlyZWN0bHkgYXMgcHJvcGVydGllcyBvZiBjb21wb25lbnQsIHRoaXMgcHJvcGVydHkgY2FuIGJlIHVzZWQgdG8gaXRlcmF0ZSBmYWNldHMgKGl0IGlzIHVzZWQgaW4gdGhpcyB3YXkgaW4gW2FsbEZhY2V0c10oI0NvbXBvbmVudCRhbGxGYWNldHMpIGNvbXBvbmVudCdzIGluc3RhbmNlIG1ldGhvZCB0aGF0IGFsbG93cyB0byBjYWxsIG1ldGhvZCB3aXRoIHRoZSBzYW1lIG5hbWUgb24gYWxsIGZhY2V0cykuXG4gKiAtIGV4dHJhRmFjZXRzIC0gYW4gYXJyYXkgb2YgbmFtZXMgb2YgZmFjZXRzIHRoYXQgYXJlIGFkZGVkIHRvIGNvbXBvbmVudCBhbmQgZG8gbm90IGZvcm0gdGhlIHBhcnQgb2YgY29tcG9uZW50J3MgY2xhc3MuXG4gKiAtIF9tZXNzZW5nZXIgLSB0aGUgcmVmZXJlbmNlIHRvIGNvbXBvbmVudCdzIFttZXNzZW5nZXJdKC4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sKS4gUmFyZWx5IG5lZWRzIHRvIGJlIHVzZWQgZGlyZWN0bHkgYXMgYWxsIGNvbW1vbmx5IHVzZWQgbWV0aG9kcyBvZiBtZXNlbmdlciBhcmUgYXZhaWxhYmxlIGRpcmVjdGx5IG9uIGNvbXBvbmVudC5cbiAqXG4gKlxuICogIyMjI0NvbXBvbmVudCBldmVudHMjIyMjXG4gKlxuICogLSAnY2hpbGRyZW5ib3VuZCcgLSBzeW5jaHJvbm91c2x5IGRpc3BhdGNoZWQgd2hlbiBjaGlsZHJlbiBvZiBET00gZWxlbWVudCB3aGljaCBjb21wbmVudCBpcyBjb25uZWN0ZWQgdG8gYXJlIGNvbm5lY3RlZCB0byBjb21wb25lbnRzLiBUaGUgZXZlbnQgaXMgZGlzcGF0Y2hlZCB3aGVuIGNvbXBvbmVudCBpcyBjcmVhdGVkIHdpdGggYG1pbG8uYmluZGVyYCAoYXMgaXMgYWxtb3N0IGFsd2F5cyB0aGUgY2FzZSwgYXMgYWxsIENvbXBvbmVudCBjbGFzcyBtZXRob2RzIHRoYXQgY3JlYXRlL2NvcHkgY29tcG9uZW50cyB1c2UgYG1pbG8uYmluZGVyYCBpbnRlcm5hbGx5IC0gY29tcG9uZW50IGNvbnN0cnVjdG9yIGFuZCBDb21wb25lbnQuY3JlYXRlIG1ldGhvZHMgYXJlIG5vdCB1c2VkIGluIGZyYW1ld29yayBvdXRzaWRlIG9mIGBtaWxvLmJpbmRlcmAgYW5kIHJhcmVseSBpZiBldmVyIG5lZWQgdG8gYmUgdXNlZCBpbiBhcGxpY2F0aW9uKS5cbiAqIC0gJ2FkZGVkdG9zY29wZScgLSBzeW5jaHJvbm91c2x5IGRpc3BhdGNoZWQgd2hlbiBjb21wb25lbnQgaXMgYWRkZWQgdG8gc2NvcGUuXG4gKiAtICdzdGF0ZXJlYWR5JyAtIGF5bmNocm9ub3VzbHkgZGlzcGF0Y2hlZCB3aGVuIGNvbXBvbmVudCAodG9nZXRoZXIgd2l0aCBpdHMgc2NvcGUgY2hpbGRyZW4pIGlzIGNyZWF0ZWQgd2l0aCBbQ29tcG9uZW50LmNyZWF0ZUZyb21TdGF0ZV0oI0NvbXBvbmVudCQkY3JlYXRlRnJvbVN0YXRlKSAob3IgYGNyZWF0ZUZyb21EYXRhVHJhbnNmZXJgKSBtZXRob2QuIENhbiBiZSBkaXNwYXRjaGVkIGJ5IGFwcGxpY2F0aW9uIGlmIHRoZSBjb21wb25lbnQncyBzdGF0ZSBpcyBzZXQgd2l0aCBzb21lIG90aGVyIG1lY2hhbmlzbS4gVGhpcyBldmVudCBpcyBub3QgdXNlZCBpbiBgbWlsb2AsIGl0IGNhbiBiZSB1c2VkIGluIGFwcGxpY2F0aW9uIGluIHBhcnRpY3VsYXIgc3ViY2xhc3NlcyBvZiBjb21wb25lbnQuXG4gKiAtICdnZXRzdGF0ZXN0YXJ0ZWQnIC0gZW1pdHRlZCBzeW5jaHJvbm91c2x5IGp1c3QgYmVmb3JlIGdldFN0YXRlIGV4ZWN1dGVzIHNvIGNvbXBvbmVudHMgYW5kIGZhY2V0cyBjYW4gY2xlYW4gdXAgdGhlaXIgc3RhdGUgZm9yIHNlcmlhbGl6YXRpb24uIFxuICogLSAnZ2V0c3RhdGVjb21wbGV0ZWQnIC0gZW1pdHRlZCBhc3luY2hyb25vdXNseSBhZnRlciBnZXRTdGF0ZSBleGVjdXRlcyBzbyBjb21wb25lbnRzIGFuZCBmYWNldHMgY2FuIHJlc3RvcmUgdGhlaXIgc3RhdGUgYWZ0ZXIgc2VyaWFsaXphdGlvbi5cbiAqXG4gKlxuICogIyMjI0NvbXBvbmVudCBcImxpZmVjeWNsZVwiIyMjI1xuICpcbiAqIDEuIENvbXBvbmVudCBjb25zdHJ1Y3RvciBpcyBjYWxsZWQuIENvbXBvbmVudCdzIGNvbnN0cnVjdG9yIHNpbXBseSBjYWxscyBjb25zdHJ1Y3RvciBvZiBbRmFjZXRlZE9iamVjdF0oLi4vYWJzdHJhY3QvZmFjZXRlZF9vYmplY3QuanMuaHRtbCkgdGhhdCBpcyBhIHN1cGVyY2xhc3Mgb2YgQ29tcG9uZW50LiBTdWJjbGFzc2VzIG9mIENvbXBvbmVudCBzaG91bGQgbm90IGltcGxlbWVudCB0aGVpciBvd24gY29uc3RydWN0b3IsIHRoZXkgY2FuIG9wdGlvbmFsbHkgaW1wbGVtZW50IGBpbml0YCBtZXRob2QsIGJ1dCBtb3N0IGNvbXBvbmVudHMgZG8gbm90IG5lZWQgdG8gZG8gaXQuXG4gKiAyLiBjb25zdHJ1Y3RvcnMgYW5kIGBpbml0YCBtZXRob2RzIG9mIGFsbCBmYWNldHMgYXJlIGNhbGxlZCBpbiBzZXF1ZW5jZS4gU2FtZSBhcyBjb21wb25lbnRzLCBmYWNldCBkbyBub3QgaW1wbGVtZW50IHRoZWlyIGNvbnN0cnVjdG9ycywgdGhleSBjYW4gb3B0aW9uYWxseSBpbXBsZW1lbnQgYGluaXRgIGFuZCBgc3RhcnRgIG1ldGhvZHMgKHNlZSBiZWxvdykuIEluc2lkZSBgaW5pdGAgbWV0aG9kIHRoZXJlIHNob3VsZCBiZSBvbmx5IGdlbmVyYWwgaW5pdGlhbGl6YXRpb24gY29kZSB3aXRob3V0IGFueSBkZXBlbmRlbmN5IG9uIGNvbXBvbmVudCBpdHNlbGYgKGl0IGlzIG5vdCByZWFkeSB5ZXQpIGFuZCBvdGhlciBmYWNldHMgKGFzIHRoZXJlIGlzIG5vIHNwZWNpZmljIGZhY2V0cyBjcmVhdGlvbiBvcmRlcikuIElmIGZhY2V0IGltcGxlbWVudHMgYGluaXRgIG1ldGhvZCBpdCBNVVNUIGNhbGwgaW5oZXJpdGVkIGluaXQgd2l0aCBgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKWAuXG4gKiAzLiBgaW5pdGAgbWV0aG9kIG9mIGNvbXBvbmVudCBpcyBjYWxsZWQuIEF0IHRoaXMgcG9pbnQgYWxsIGZhY2V0cyBhcmUgY3JlYXRlZCBidXQgZmFjZXRzIHN0aWxsIGNhbiBiZSBub3QgcmVhZHkgYXMgdGhleSBjYW4gaGF2ZSBpbml0aWFsaXphdGlvbiBjb2RlIGluIGBzdGFydGAgbWV0aG9kLiBJZiBjb21wb25lbnQgc3ViY2xhc3MgaW1wbGVtZW50cyBgaW5pdGAgbWV0aG9kIGl0IE1VU1QgY2FsbCBpbmhlcml0ZWQgbWV0aG9kIHdpdGggYDxTdXBlcmNsYXNzPi5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpYCwgd2hlcmUgPFN1cGVyY2xhc3M+IGlzIENvbXBvbmVudCBvciBhbm90aGVyIHN1cGVyY2xhc3MgdGhlIGNvbXBvbmVudCBpcyBhIHN1YmNsYXNzIG9mLlxuICogNC4gYGNoZWNrYCBtZXRob2Qgb2YgYWxsIGZhY2V0cyBpcyBjYWxsZWQuIFRoaXMgbWV0aG9kIGFkZHMgZmFjZXRzIHRoYXQgYXJlIG5vdCBwYXJ0IG9mIHRoZSBjb21wb25lbnQgZGVjbGFyYXRpb24gKGJlaW5nIHBhcnQgb2YgdGhlIGNsYXNzIG9yIGV4cGxpY2l0ZWx5IGxpc3RlZCBpbiBiaW5kIGF0dHJpYnV0ZSkgYnV0IGFyZSByZXF1aXJlZCBieSBmYWNldHMgdGhhdCB0aGUgY29tcG5lbnQgYWxyZWFkeSBoYXMuIFN1YmNsYXNzZXMgb2YgW0NvbXBvbmVudEZhY2V0XSguL2NfZmFjZXQuanMuaHRtbCkgZG8gbm90IG5lZWQgdG8gaW1wbGVtZW50IHRoaXMgbWV0aG9kLlxuICogNS4gYHN0YXJ0YCBtZXRob2Qgb2YgYWxsIGZhY2V0cyBpcyBjYWxsZWQuIFRoaXMgbWV0aG9kIGlzIHVzdWFsbHkgaW1wbGVtZW50ZWQgYnkgQ29tcG9uZW50RmFjZXQgc3ViY2xhc3NlcyBhbmQgaXQgY2FuIGhhdmUgYW55IGluaXRpYWxpemF0aW9uIGNvZGUgdGhhdCBkZXBlbmRzIG9uIGNvbXBvbmVudCBvciBvbiBvdGhlciBmYWNldHMgdGhhdCBhcmUgdGhlIGRlcGVuZGVuY2llcyBvZiBhIGZhY2V0LiBJbmhlcml0ZWQgYHN0YXJ0YCBtZXRob2Qgc2hvdWxkIGJlIGNhbGxlZCBpbnQgaGUgc2FtZSB3YXkgYXMgd3JpdHRlbiBhYm92ZS5cbiAqIDYuIGBzdGFydGAgbWV0aG9kIG9mIGNvbXBvbmVudCBpcyBjYWxsZWQuIFRoaXMgY29tcG9uZW50IG1ldGhvZCBjYW4gYmUgaW1wbGVtZW50ZWQgYnkgc3ViY2xhc3NlcyBpZiB0aGV5IG5lZWQgdG8gaGF2ZSBzb21lIGluaXRpYWxpemF0aW9uIGNvZGUgdGhhdCBkZXBlbmRzIG9uIHNvbWUgZmFjZXRzIGFuZCByZXF1aXJlcyB0aGF0IHRoZXNlIGZhY2V0cyBhcmUgZnVsbHkgaW5pYWxpemVkLiBPZnRlbiBzdWNoIGNvZGUgYWxzbyBkZXBlbmRzIG9uIGNvbXBvbmVudCdzIHNjb3BlIGNoaWxkcmVuIGFzIHdlbGwgc28gdGhpcyBjb2RlIHNob3VsZCBiZSBpbnNpZGUgYCdjaGlsZHJlbmJvdW5kJ2AgZXZlbnQgc3Vic2NyaWJlci5cbiAqIDcuICdhZGRlZHRvc2NvcGUnIGV2ZW50IGlzIGRpc3BhdGNoZWQgd2hlbiBjb21wb25lbnQgaXMgYWRkZWQgdG8gaXRzIHBhcmVudCdzIHNjb3BlIG9yIHRvIHRvcCBsZXZlbCBzY29wZSBjcmVhdGVkIGJ5IGBtaWxvLmJpbmRlcmAuXG4gKiA4LiBjb21wb25lbnQncyBjaGlsZHJlbiBhcmUgY3JlYXRlZCAoc3RlcHMgMS02IGFib3ZlIGFyZSBmb2xsb3dlZCBmb3IgZWFjaCBjaGlsZCkuXG4gKiA5LiAnY2hpbGRyZW5ib3VuZCcgZXZlbnQgaXMgZGlzcGF0Y2hlZCB3aGVuIGFsbCBjb21wb25lbnQncyBjaGlsZHJlbiBhcmUgY3JlYXRlZCBhbmQgYWRkZWQgdG8gdGhlaXIgc2NvcGUgKHNlZSBldmVudCBkZXNjcmlwdGlvbiBiZWxvdykuXG4gKiAxMC4gJ3N0YXRlcmVhZHknIGV2ZW50IGlzIGRpc3BhdGNoZWQgZm9yIGNvbXBvbmVudCBhbmQgYWxsIGl0cyBjaGlsZHJlbiB3aGVuIGNvbXBvbmVudCBpcyBjcmVhdGUgZnJvbSBzdGF0ZSAoc2VlIGV2ZW50IGRlc2NyaXB0aW9uIGJlbG93KS5cbiAqIDExLiBhdCB0aGlzIHBvaW50IGNvbXBvbmVudCBpcyBpbiB0aGUgXCJpbnRlcmFjdGl2ZVwiIHN0YXRlIHdoZW4gaXQgYW5kIGl0cyBmYWNldHMgd2lsbCBvbmx5IHJlc3BvbmQgdG8gbWVzc2FnZXMvZXZlbnRzIHRoYXQgdGhleSBzdWJzY3JpYmVkIHRvIGR1cmluZyBpbml0aWFsaXphdGlvbi5cbiAqXG4gKlxuICogQHBhcmFtIHtTY29wZX0gc2NvcGUgc2NvcGUgdG8gd2hpY2ggY29tcG9uZW50IHdpbGwgYmVsb25nLiBJdCBpcyB1c3VhbGx5IGEgdG9wIGxldmVsIHNjb3BlIG9iamVjdCByZXR1cm5lZCBieSBgbWlsby5iaW5kZXJgIG9yIGBzY29wZWAgcHJvcGVydHkgb2YgQ29udGFpbmVyIGZhY2V0LlxuICogQHBhcmFtIHtFbGVtZW50fSBlbGVtZW50IERPTSBlbGVtZW50IHRoYXQgY29tcG9uZW50IGlzIGF0dGFjaGVkIHRvXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBjb21wb25lbnQgbmFtZSwgc2hvdWxkIGJlIHVuaXF1ZSBpbiB0aGUgc2NvcGUgb2YgY29tcG9uZW50XG4gKiBAcGFyYW0ge0NvbXBvbmVudEluZm99IGNvbXBvbmVudEluZm8gaW5zdGFuY2Ugb2YgQ29tcG9uZW50SW5mbyBjbGFzcyB0aGF0IGNhbiBiZSB1c2VkIHRvIGNyZWF0ZSBhIGNvcHkgb2YgY29tcG9uZW50XG4gKiAgVE9ETyB0cnkgcmVtb3ZpbmcgaXRcbiAqIEByZXR1cm4ge0NvbXBvbmVudH1cbiAqL1xudmFyIENvbXBvbmVudCA9IF8uY3JlYXRlU3ViY2xhc3MoRmFjZXRlZE9iamVjdCwgJ0NvbXBvbmVudCcsIHRydWUpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENvbXBvbmVudDtcblxuX3JlZ2lzdGVyV2l0aERvbVN0b3JhZ2UoJ0NvbXBvbmVudCcpO1xuXG5cbi8qKlxuICogIyMjI0NvbXBvbmVudCBjbGFzcyBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2NyZWF0ZUNvbXBvbmVudENsYXNzXSgjQ29tcG9uZW50JCRjcmVhdGVDb21wb25lbnRDbGFzcylcbiAqIC0gW2NyZWF0ZV0oI0NvbXBvbmVudCQkY3JlYXRlKVxuICogLSBbY29weV0oI0NvbXBvbmVudCQkY29weSlcbiAqIC0gW2NyZWF0ZU9uRWxlbWVudF0oI0NvbXBvbmVudCQkY3JlYXRlT25FbGVtZW50KVxuICogLSBbaXNDb21wb25lbnRdKGNfdXRpbHMuanMuaHRtbCNpc0NvbXBvbmVudClcbiAqIC0gW2dldENvbXBvbmVudF0oY191dGlscy5qcy5odG1sI2dldENvbXBvbmVudClcbiAqIC0gW2dldENvbnRhaW5pbmdDb21wb25lbnRdKGNfdXRpbHMuanMuaHRtbCNnZXRDb250YWluaW5nQ29tcG9uZW50KVxuICogLSBbY3JlYXRlRnJvbVN0YXRlXSgjQ29tcG9uZW50JCRjcmVhdGVGcm9tU3RhdGUpXG4gKiAtIFtjcmVhdGVGcm9tRGF0YVRyYW5zZmVyXSgjQ29tcG9uZW50JCRjcmVhdGVGcm9tRGF0YVRyYW5zZmVyKVxuICovXG5fLmV4dGVuZChDb21wb25lbnQsIHtcbiAgICBjcmVhdGVDb21wb25lbnRDbGFzczogQ29tcG9uZW50JCRjcmVhdGVDb21wb25lbnRDbGFzcyxcbiAgICBjcmVhdGU6IENvbXBvbmVudCQkY3JlYXRlLFxuICAgIGNvcHk6IENvbXBvbmVudCQkY29weSxcbiAgICBjcmVhdGVPbkVsZW1lbnQ6IENvbXBvbmVudCQkY3JlYXRlT25FbGVtZW50LFxuICAgIGlzQ29tcG9uZW50OiBjb21wb25lbnRVdGlscy5pc0NvbXBvbmVudCxcbiAgICBnZXRDb21wb25lbnQ6IGNvbXBvbmVudFV0aWxzLmdldENvbXBvbmVudCxcbiAgICBnZXRDb250YWluaW5nQ29tcG9uZW50OiBjb21wb25lbnRVdGlscy5nZXRDb250YWluaW5nQ29tcG9uZW50LFxuICAgIGNyZWF0ZUZyb21TdGF0ZTogQ29tcG9uZW50JCRjcmVhdGVGcm9tU3RhdGUsXG4gICAgY3JlYXRlRnJvbURhdGFUcmFuc2ZlcjogQ29tcG9uZW50JCRjcmVhdGVGcm9tRGF0YVRyYW5zZmVyXG59KTtcbmRlbGV0ZSBDb21wb25lbnQuY3JlYXRlRmFjZXRlZENsYXNzO1xuXG5cbi8qKlxuICogIyMjI0NvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2luaXRdKCNDb21wb25lbnQkaW5pdClcbiAqIC0gW2NyZWF0ZUVsZW1lbnRdKCNDb21wb25lbnQkY3JlYXRlRWxlbWVudClcbiAqIC0gW2hhc0ZhY2V0XSgjQ29tcG9uZW50JGhhc0ZhY2V0KVxuICogLSBbYWRkRmFjZXRdKCNDb21wb25lbnQkYWRkRmFjZXQpXG4gKiAtIFthbGxGYWNldHNdKCNDb21wb25lbnQkYWxsRmFjZXRzKVxuICogLSBbcmVuYW1lXSgjQ29tcG9uZW50JHJlbmFtZSlcbiAqIC0gW3JlbW92ZV0oI0NvbXBvbmVudCRyZW1vdmUpXG4gKiAtIFtnZXRTdGF0ZV0oI0NvbXBvbmVudCRnZXRTdGF0ZSlcbiAqIC0gW2dldFRyYW5zZmVyU3RhdGVdKCNDb21wb25lbnQkZ2V0VHJhbnNmZXJTdGF0ZSlcbiAqIC0gW3NldFN0YXRlXSgjQ29tcG9uZW50JHNldFN0YXRlKVxuICogLSBbZ2V0U2NvcGVQYXJlbnRdKCNDb21wb25lbnQkZ2V0U2NvcGVQYXJlbnQpXG4gKiAtIFtnZXRUb3BTY29wZVBhcmVudF0oI0NvbXBvbmVudCRnZXRUb3BTY29wZVBhcmVudClcbiAqIC0gW2dldFNjb3BlUGFyZW50V2l0aENsYXNzXSgjQ29tcG9uZW50JGdldFNjb3BlUGFyZW50V2l0aENsYXNzKVxuICogLSBbZ2V0VG9wU2NvcGVQYXJlbnRXaXRoQ2xhc3NdKCNDb21wb25lbnQkZ2V0VG9wU2NvcGVQYXJlbnRXaXRoQ2xhc3MpXG4gKiAtIFt3YWxrU2NvcGVUcmVlXSgjQ29tcG9uZW50JHdhbGtTY29wZVRyZWUpXG4gKiAtIFticm9hZGNhc3RdKCNDb21wb25lbnQkYnJvYWRjYXN0KVxuICogLSBbZGVzdHJveV0oI0NvbXBvbmVudCRkZXN0cm95KVxuICogLSBbaXNEZXN0cm95ZWRdKCNDb21wb25lbnQkaXNEZXN0cm95ZWQpXG4gKlxuICpcbiAqICMjIyMjW01lc3Nlbmdlcl0oLi4vbWVzc2VuZ2VyL2luZGV4LmpzLmh0bWwpIG1ldGhvZHMgYXZhaWxhYmxlIG9uIGNvbXBvbmVudCMjIyMjXG4gKlxuICogLSBbb25dKC4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sI01lc3NlbmdlciRvbikgLSBzaW5nbGUgc3Vic2NyaWJlXG4gKiAtIFtvZmZdKC4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sI01lc3NlbmdlciRvZmYpIC0gc2luZ2xlIHVuc3Vic2NyaWJlXG4gKiAtIFtvbk1lc3NhZ2VzXSguLi9tZXNzZW5nZXIvaW5kZXguanMuaHRtbCNNZXNzZW5nZXIkb25NZXNzYWdlcykgLSBtdWx0aXBsZSBzdWJzY3JpYmVcbiAqIC0gW29mZk1lc3NhZ2VzXSguLi9tZXNzZW5nZXIvaW5kZXguanMuaHRtbCNNZXNzZW5nZXIkb2ZmTWVzc2FnZXMpIC0gbXVsdGlwbGUgdW5zdWJzY3JpYmVcbiAqIC0gW3Bvc3RNZXNzYWdlXSguLi9tZXNzZW5nZXIvaW5kZXguanMuaHRtbCNNZXNzZW5nZXIkcG9zdE1lc3NhZ2UpIC0gcG9zdCBtZXNzYWdlIG9uIGNvbXBvbmVudFxuICogLSBbZ2V0U3Vic2NyaWJlcnNdKC4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sI01lc3NlbmdlciRnZXRTdWJzY3JpYmVycykgLSBnZXQgc3Vic2NyaWJlcnMgZm9yIGEgZ2l2ZW4gbWVzc2FnZVxuICovXG5fLmV4dGVuZFByb3RvKENvbXBvbmVudCwge1xuICAgIGluaXQ6IENvbXBvbmVudCRpbml0LFxuICAgIHN0YXJ0OiBDb21wb25lbnQkc3RhcnQsXG4gICAgY3JlYXRlRWxlbWVudDogQ29tcG9uZW50JGNyZWF0ZUVsZW1lbnQsXG4gICAgaGFzRmFjZXQ6IENvbXBvbmVudCRoYXNGYWNldCxcbiAgICBhZGRGYWNldDogQ29tcG9uZW50JGFkZEZhY2V0LFxuICAgIGFsbEZhY2V0czogQ29tcG9uZW50JGFsbEZhY2V0cyxcbiAgICByZW5hbWU6IENvbXBvbmVudCRyZW5hbWUsXG4gICAgcmVtb3ZlOiBDb21wb25lbnQkcmVtb3ZlLFxuICAgIGluc2VydEludG86IENvbXBvbmVudCRpbnNlcnRJbnRvLFxuXG4gICAgZ2V0U3RhdGU6IENvbXBvbmVudCRnZXRTdGF0ZSxcbiAgICBnZXRUcmFuc2ZlclN0YXRlOiBDb21wb25lbnQkZ2V0VHJhbnNmZXJTdGF0ZSxcbiAgICBfZ2V0U3RhdGU6IENvbXBvbmVudCRfZ2V0U3RhdGUsXG4gICAgc2V0U3RhdGU6IENvbXBvbmVudCRzZXRTdGF0ZSxcbiAgICBcbiAgICBnZXRTY29wZVBhcmVudDogQ29tcG9uZW50JGdldFNjb3BlUGFyZW50LFxuICAgIGdldFRvcFNjb3BlUGFyZW50OiBDb21wb25lbnQkZ2V0VG9wU2NvcGVQYXJlbnQsXG4gICAgZ2V0U2NvcGVQYXJlbnRXaXRoQ2xhc3M6IENvbXBvbmVudCRnZXRTY29wZVBhcmVudFdpdGhDbGFzcyxcbiAgICBnZXRUb3BTY29wZVBhcmVudFdpdGhDbGFzczogQ29tcG9uZW50JGdldFRvcFNjb3BlUGFyZW50V2l0aENsYXNzLFxuXG4gICAgc2V0U2NvcGVQYXJlbnRGcm9tRE9NOiBDb21wb25lbnQkc2V0U2NvcGVQYXJlbnRGcm9tRE9NLFxuXG4gICAgd2Fsa1Njb3BlVHJlZTogQ29tcG9uZW50JHdhbGtTY29wZVRyZWUsXG5cbiAgICB0cmVlUGF0aE9mOiBDb21wb25lbnQkdHJlZVBhdGhPZixcbiAgICBnZXRDb21wb25lbnRBdFRyZWVQYXRoOiBDb21wb25lbnQkZ2V0Q29tcG9uZW50QXRUcmVlUGF0aCxcbiAgICBpbnNlcnRBdFRyZWVQYXRoOiBDb21wb25lbnQkaW5zZXJ0QXRUcmVlUGF0aCxcblxuICAgIGJyb2FkY2FzdDogQ29tcG9uZW50JGJyb2FkY2FzdCxcbiAgICBkZXN0cm95OiBDb21wb25lbnQkZGVzdHJveSxcbiAgICBpc0Rlc3Ryb3llZDogQ29tcG9uZW50JGlzRGVzdHJveWVkXG59KTtcblxuXG4vKipcbiAqIEV4cG9zZSBNZXNzZW5nZXIgbWV0aG9kcyBvbiBDb21wb25lbnQgcHJvdG90eXBlXG4gKi9cbnZhciBNRVNTRU5HRVJfUFJPUEVSVFkgPSAnX21lc3Nlbmdlcic7XG5NZXNzZW5nZXIudXNlV2l0aChDb21wb25lbnQsIE1FU1NFTkdFUl9QUk9QRVJUWSwgTWVzc2VuZ2VyLmRlZmF1bHRNZXRob2RzKTtcblxuXG52YXIgQ09NUE9ORU5UX0RBVEFfVFlQRV9QUkVGSVggPSAneC1hcHBsaWNhdGlvbi9taWxvLWNvbXBvbmVudCc7XG52YXIgQ09NUE9ORU5UX0RBVEFfVFlQRV9SRUdFWCA9IC94LWFwcGxpY2F0aW9uXFwvbWlsby1jb21wb25lbnRcXC8oW2Etel8kXVswLTlhLXpfJF0qKSg/OlxcLygpKS9pO1xuXG4vKipcbiAqIENvbXBvbmVudCBjbGFzcyBtZXRob2RcbiAqIENyZWF0ZXMgYSBzdWJjbGFzcyBvZiBjb21wb25lbnQgZnJvbSB0aGUgbWFwIG9mIGNvbmZpZ3VyZWQgZmFjZXRzLlxuICogVGhpcyBtZXRob2Qgd3JhcHMgYW5kIHJlcGxhY2VzIFtgY3JlYXRlRmFjZXRlZENsYXNzYF0oLi4vYWJzdHJhY3QvZmFjZXRlZF9vYmplY3QuanMuaHRtbCNjcmVhdGVGYWNldGVkQ2xhc3MpIGNsYXNzIG1ldGhvZCBvZiBGYWNldGVkT2JqZWN0LlxuICogVW5saWtlIGNyZWF0ZUZhY2V0ZWRDbGFzcywgdGhpcyBtZXRob2QgdGFrZSBmYWNldCBjbGFzc2VzIGZyb20gcmVnaXN0cnkgYnkgdGhlaXIgbmFtZSwgc28gb25seSBtYXAgb2YgZmFjZXRzIGNvbmZpZ3VyYXRpb24gbmVlZHMgdG8gYmUgcGFzc2VkLiBBbGwgZmFjZXRzIGNsYXNzZXMgc2hvdWxkIGJlIHN1YmNsYXNzZXMgb2YgW0NvbXBvbmVudEZhY2V0XSguL2NfZmFjZXQuanMuaHRtbClcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBjbGFzcyBuYW1lXG4gKiBAcGFyYW0ge09iamVjdFtPYmplY3RdIHwgQXJyYXlbU3RyaW5nXX0gZmFjZXRzQ29uZmlnIG1hcCBvZiBmYWNldHMgY29uZmlndXJhdGlvbi5cbiAqICBJZiBzb21lIGZhY2V0IGRvZXMgbm90IHJlcXVpcmUgY29uZmlndXJhdGlvbiwgYHVuZGVmaW5lZGAgc2hvdWxkIGJlIHBhc3NlZCBhcyB0aGUgY29uZmlndXJhdGlvbiBmb3IgdGhlIGZhY2V0LlxuICogIElmIG5vIGZhY2V0IHJlcXVpcmVzIGNvbmZpZ3VyYXRpb24sIHRoZSBhcnJheSBvZiBmYWNldHMgbmFtZXMgY2FuIGJlIHBhc3NlZC5cbiAqIEByZXR1cm4ge1N1YmNsYXNzKENvbXBvbmVudCl9XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCQkY3JlYXRlQ29tcG9uZW50Q2xhc3MobmFtZSwgZmFjZXRzQ29uZmlnKSB7XG4gICAgLy8gY29udmVydCBhcnJheSBvZiBmYWNldCBuYW1lcyB0byBtYXAgb2YgZW1wdHkgZmFjZXRzIGNvbmZpZ3VyYXRpb25zXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoZmFjZXRzQ29uZmlnKSkge1xuICAgICAgICB2YXIgY29uZmlnTWFwID0ge307XG4gICAgICAgIGZhY2V0c0NvbmZpZy5mb3JFYWNoKGZ1bmN0aW9uKGZjdCkge1xuICAgICAgICAgICAgdmFyIGZjdE5hbWUgPSBfLmZpcnN0TG93ZXJDYXNlKGZjdCk7XG4gICAgICAgICAgICBjb25maWdNYXBbZmN0TmFtZV0gPSB7fTtcbiAgICAgICAgfSk7XG4gICAgICAgIGZhY2V0c0NvbmZpZyA9IGNvbmZpZ01hcDtcbiAgICB9XG5cbiAgICAvLyBjb25zdHJ1Y3QgbWFwIG9mIGZhY2V0cyBjbGFzc2VzIGZyb20gZmFjZXRSZWdpc3RyeVxuICAgIHZhciBmYWNldHNDbGFzc2VzO1xuICAgIGlmICh0eXBlb2YgZmFjZXRzQ29uZmlnID09ICdvYmplY3QnICYmIF8ua2V5cyhmYWNldHNDb25maWcpLmxlbmd0aCkge1xuICAgICAgICBmYWNldHNDbGFzc2VzID0ge307XG4gICAgICAgIF8uZWFjaEtleShmYWNldHNDb25maWcsIGZ1bmN0aW9uKGZjdENvbmZpZywgZmN0KSB7XG4gICAgICAgICAgICB2YXIgZmN0TmFtZSA9IF8uZmlyc3RMb3dlckNhc2UoZmN0KTtcbiAgICAgICAgICAgIHZhciBmY3RDbGFzc05hbWUgPSBfLmZpcnN0VXBwZXJDYXNlKGZjdCk7XG4gICAgICAgICAgICBmYWNldHNDbGFzc2VzW2ZjdE5hbWVdID0gZmFjZXRzUmVnaXN0cnkuZ2V0KGZjdENsYXNzTmFtZSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIGNyZWF0ZSBzdWJjbGFzcyBvZiBDb21wb25lbnQgdXNpbmcgbWV0aG9kIG9mIEZhY2V0ZWRPYmplY3RcbiAgICB2YXIgQ29tcG9uZW50Q2xhc3MgPSBGYWNldGVkT2JqZWN0LmNyZWF0ZUZhY2V0ZWRDbGFzcy5jYWxsKHRoaXMsIG5hbWUsIGZhY2V0c0NsYXNzZXMsIGZhY2V0c0NvbmZpZyk7XG4gICAgXG4gICAgX3JlZ2lzdGVyV2l0aERvbVN0b3JhZ2UobmFtZSk7XG5cbiAgICByZXR1cm4gQ29tcG9uZW50Q2xhc3M7XG59XG5cblxuZnVuY3Rpb24gX3JlZ2lzdGVyV2l0aERvbVN0b3JhZ2UoY2xhc3NOYW1lKSB7XG4gICAgRE9NU3RvcmFnZS5yZWdpc3RlckRhdGFUeXBlKGNsYXNzTmFtZSwgQ29tcG9uZW50X2RvbVN0b3JhZ2VTZXJpYWxpemVyLCBDb21wb25lbnRfZG9tU3RvcmFnZVBhcnNlcik7XG59XG5cblxuZnVuY3Rpb24gQ29tcG9uZW50X2RvbVN0b3JhZ2VTZXJpYWxpemVyKGNvbXBvbmVudCkge1xuICAgIHZhciBzdGF0ZSA9IGNvbXBvbmVudC5nZXRTdGF0ZSgpO1xuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShzdGF0ZSk7ICAgXG59XG5cblxuZnVuY3Rpb24gQ29tcG9uZW50X2RvbVN0b3JhZ2VQYXJzZXIoY29tcFN0ciwgY29tcENsYXNzTmFtZSkge1xuICAgIHZhciBzdGF0ZSA9IF8uanNvblBhcnNlKGNvbXBTdHIpO1xuICAgIGlmIChzdGF0ZSlcbiAgICAgICAgcmV0dXJuIENvbXBvbmVudC5jcmVhdGVGcm9tU3RhdGUoc3RhdGUpO1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGNsYXNzIG1ldGhvZFxuICogQ3JlYXRlcyBjb21wb25lbnQgZnJvbSBbQ29tcG9uZW50SW5mb10oLi9jX2luZm8uanMuaHRtbCkgKHVzZWQgYnkgW21pbG8uYmluZGVyXSguLi9iaW5kZXIuanMuaHRtbCkgYW5kIHRvIGNvcHkgY29tcG9uZW50KVxuICogQ29tcG9uZW50IG9mIGFueSByZWdpc3RlcmVkIGNsYXNzIChzZWUgW2NvbXBvbmVudHNSZWdpc3RyeV0oLi9jX3JlZ2lzdHJ5LmpzLmh0bWwpKSB3aXRoIGFueSBhZGRpdGlvbmFsIHJlZ2lzdGVyZWQgZmFjZXRzIChzZWUgW2ZhY2V0c1JlZ2lzdHJ5XSguL2NfZmFjZXRzL2NmX3JlZ2lzdHJ5LmpzLmh0bWwpKSBjYW4gYmUgY3JlYXRlZCB1c2luZyB0aGlzIG1ldGhvZC5cbiAqXG4gKiBAcGFyYW0ge0NvbXBvbmVudEluZm99IGluZm9cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gdGhyb3dPbkVycm9ycyBJZiBzZXQgdG8gZmFsc2UsIHRoZW4gZXJyb3JzIHdpbGwgb25seSBiZSBsb2dnZWQgdG8gY29uc29sZS4gVHJ1ZSBieSBkZWZhdWx0LlxuIEAgQHJldHVybiB7Q29tcG9uZW50fVxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkJGNyZWF0ZShpbmZvLCB0aHJvd09uRXJyb3JzKSB7XG4gICAgdmFyIENvbXBvbmVudENsYXNzID0gaW5mby5Db21wb25lbnRDbGFzcztcblxuICAgIGlmICh0eXBlb2YgQ29tcG9uZW50Q2xhc3MgIT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICB2YXIgbWVzc2FnZSA9ICdjcmVhdGU6IGNvbXBvbmVudCBjbGFzcyBzaG91bGQgYmUgZnVuY3Rpb24sIFwiJyArIHR5cGVvZiBDb21wb25lbnRDbGFzcyArICdcIiBwYXNzZWQnOyBcbiAgICAgICAgaWYgKHRocm93T25FcnJvcnMgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ0NvbXBvbmVudCcsIG1lc3NhZ2UsICc7dXNpbmcgYmFzZSBDb21wb25lbnQgY2xhc3MgaW5zdGVhZCcpO1xuICAgICAgICAgICAgQ29tcG9uZW50Q2xhc3MgPSBDb21wb25lbnQ7XG4gICAgICAgIH0gZWxzZVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKG1lc3NhZ2UpO1xuICAgIH1cblxuICAgIHZhciBhQ29tcG9uZW50ID0gbmV3IENvbXBvbmVudENsYXNzKGluZm8uc2NvcGUsIGluZm8uZWwsIGluZm8ubmFtZSwgaW5mbyk7XG5cbiAgICBpZiAoaW5mby5leHRyYUZhY2V0c0NsYXNzZXMpXG4gICAgICAgIF8uZWFjaEtleShpbmZvLmV4dHJhRmFjZXRzQ2xhc3NlcywgZnVuY3Rpb24oRmFjZXRDbGFzcykge1xuICAgICAgICAgICAgaWYgKCEgYUNvbXBvbmVudC5oYXNGYWNldChGYWNldENsYXNzKSlcbiAgICAgICAgICAgICAgICBhQ29tcG9uZW50LmFkZEZhY2V0KEZhY2V0Q2xhc3MsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB0aHJvd09uRXJyb3JzKTtcbiAgICAgICAgfSk7XG5cbiAgICByZXR1cm4gYUNvbXBvbmVudDtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBjbGFzcyBtZXRob2RcbiAqIENyZWF0ZSBhIGNvcHkgb2YgY29tcG9uZW50LCBpbmNsdWRpbmcgYSBjb3B5IG9mIERPTSBlbGVtZW50LiBSZXR1cm5zIGEgY29weSBvZiBgY29tcG9uZW50YCAob2YgdGhlIHNhbWUgY2xhc3MpIHdpdGggbmV3IERPTSBlbGVtZW50IChub3QgaW5zZXJ0ZWQgaW50byBwYWdlKS5cbiAqIENvbXBvbmVudCBpcyBhZGRlZCB0byB0aGUgc2FtZSBzY29wZSBhcyB0aGUgb3JpZ2luYWwgY29tcG9uZW50LlxuICpcbiAqIEBwYXJhbSB7Q29tcG9uZW50fSBjb21wb25lbnQgYW4gaW5zdGFuY2Ugb2YgQ29tcG9uZW50IGNsYXNzIG9yIHN1YmNsYXNzXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGRlZXBDb3B5IG9wdGlvbmFsIGB0cnVlYCB0byBtYWtlIGRlZXAgY29weSBvZiBET00gZWxlbWVudCwgb3RoZXJ3aXNlIG9ubHkgZWxlbWVudCB3aXRob3V0IGNoaWxkcmVuIGlzIGNvcGllZFxuICogQHJldHVybiB7Q29tcG9uZW50fVxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkJGNvcHkoY29tcG9uZW50LCBkZWVwQ29weSkge1xuICAgIGNoZWNrKGNvbXBvbmVudCwgQ29tcG9uZW50KTtcbiAgICBjaGVjayhkZWVwQ29weSwgTWF0Y2guT3B0aW9uYWwoQm9vbGVhbikpO1xuXG4gICAgaWYgKGRlZXBDb3B5ICYmICFjb21wb25lbnQuY29udGFpbmVyKSBcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgZGVlcCBjb3B5IGNvbXBvbmVudCB3aXRob3V0IGNvbnRhaW5lciBmYWNldCcpO1xuXG4gICAgLy8gY29weSBET00gZWxlbWVudCwgdXNpbmcgRG9tIGZhY2V0IGlmIGl0IGlzIGF2YWlsYWJsZVxuICAgIHZhciBuZXdFbCA9IGNvbXBvbmVudC5kb20gXG4gICAgICAgICAgICAgICAgICAgID8gY29tcG9uZW50LmRvbS5jb3B5KGRlZXBDb3B5KVxuICAgICAgICAgICAgICAgICAgICA6IGNvbXBvbmVudC5lbC5jbG9uZU5vZGUoZGVlcENvcHkpO1xuXG4gICAgdmFyIENvbXBvbmVudENsYXNzID0gY29tcG9uZW50LmNvbnN0cnVjdG9yO1xuXG4gICAgLy8gY3JlYXRlIGNvbXBvbmVudCBvZiB0aGUgc2FtZSBjbGFzcyBvbiB0aGUgZWxlbWVudFxuICAgIHZhciBhQ29tcG9uZW50ID0gQ29tcG9uZW50Q2xhc3MuY3JlYXRlT25FbGVtZW50KG5ld0VsLCB1bmRlZmluZWQsIGNvbXBvbmVudC5zY29wZSwgY29tcG9uZW50LmV4dHJhRmFjZXRzKTtcbiAgICB2YXIgc3RhdGUgPSBjb21wb25lbnQuX2dldFN0YXRlKGRlZXBDb3B5IHx8IGZhbHNlKTtcbiAgICBhQ29tcG9uZW50LnNldFN0YXRlKHN0YXRlKTtcbiAgICBfLmRlZmVyTWV0aG9kKGFDb21wb25lbnQsICdicm9hZGNhc3QnLCAnc3RhdGVyZWFkeScpO1xuICAgIHJldHVybiBhQ29tcG9uZW50O1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGNsYXNzIG1ldGhvZFxuICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBjb21wb25lbnQgYXRhY2hlZCB0byBlbGVtZW50LiBBbGwgc3ViY2xhc3NlcyBvZiBjb21wb25lbnQgaW5oZXJpdCB0aGlzIG1ldGhvZC5cbiAqIFJldHVybnMgdGhlIGNvbXBvbmVudCBvZiB0aGUgY2xhc3MgdGhpcyBtZXRob2QgaXMgdXNlZCB3aXRoICh0aGVjb250ZXh0IG9mIHRoZSBtZXRob2QgY2FsbCkuXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBlbCBvcHRpb25hbCBlbGVtZW50IHRvIGF0dGFjaCBjb21wb25lbnQgdG8uIElmIGVsZW1lbnQgaXMgbm90IHBhc3NlZCwgaXQgd2lsbCBiZSBjcmVhdGVkXG4gKiBAcGFyYW0ge1N0cmluZ30gaW5uZXJIVE1MIG9wdGlvbmFsIGlubmVyIGh0bWwgdG8gaW5zZXJ0IGluIGVsZW1lbnQgYmVmb3JlIGJpbmRpbmcuXG4gKiBAcGFyYW0ge1Njb3BlfSByb290U2NvcGUgb3B0aW9uYWwgc2NvcGUgdG8gcHV0IGNvbXBvbmVudCBpbi4gSWYgbm90IHBhc3NlZCwgY29tcG9uZW50IHdpbGwgYmUgYXR0YWNoZWQgdG8gdGhlIHNjb3BlIHRoYXQgY29udGFpbnMgdGhlIGVsZW1lbnQuIElmIHN1Y2ggc2NvcGUgZG9lcyBub3QgZXhpc3QsIG5ldyBzY29wZSB3aWxsIGJlIGNyZWF0ZWQuXG4gKiBAcGFyYW0ge0FycmF5W1N0cmluZ119IGV4dHJhRmFjZXRzIGxpc3Qgb2YgZXh0cmEgZmFjZXQgdG8gYWRkIHRvIGNvbXBvbmVudFxuICogQHJldHVybiB7U3ViY2xhc3MoQ29tcG9uZW50KX1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JCRjcmVhdGVPbkVsZW1lbnQoZWwsIGlubmVySFRNTCwgcm9vdFNjb3BlLCBleHRyYUZhY2V0cykge1xuICAgIGNoZWNrKGlubmVySFRNTCwgTWF0Y2guT3B0aW9uYWwoU3RyaW5nKSk7XG4gICAgY2hlY2socm9vdFNjb3BlLCBNYXRjaC5PcHRpb25hbChTY29wZSkpO1xuICAgIGNoZWNrKGV4dHJhRmFjZXRzLCBNYXRjaC5PcHRpb25hbChbU3RyaW5nXSkpO1xuXG4gICAgLy8gXCJ0aGlzXCIgcmVmZXJzIHRvIHRoZSBjbGFzcyBvZiBjb21wb25lbnQgaGVyZSwgYXMgdGhpcyBpcyBhIGNsYXNzIG1ldGhvZFxuICAgIGlmIChlbCAmJiBpbm5lckhUTUwpIGVsLmlubmVySFRNTCA9IGlubmVySFRNTDtcbiAgICBlbCA9IGVsIHx8IF9jcmVhdGVDb21wb25lbnRFbGVtZW50LmNhbGwodGhpcywgaW5uZXJIVE1MKTtcbiAgICByb290U2NvcGUgPSByb290U2NvcGUgfHwgX2ZpbmRPckNyZWF0ZUNvbXBvbmVudFJvb3RTY29wZShlbCk7XG4gICAgdmFyIGFDb21wb25lbnQgPSBfYWRkQXR0cmlidXRlQW5kQmluZENvbXBvbmVudC5jYWxsKHRoaXMsIGVsLCByb290U2NvcGUsIGV4dHJhRmFjZXRzKTtcbiAgICBhQ29tcG9uZW50LmJyb2FkY2FzdCgnc3RhdGVyZWFkeScpO1xuICAgIHJldHVybiBhQ29tcG9uZW50O1xufVxuXG5mdW5jdGlvbiBfY3JlYXRlQ29tcG9uZW50RWxlbWVudChpbm5lckhUTUwpIHtcbiAgICAvLyBcInRoaXNcIiByZWZlcnMgdG8gdGhlIGNsYXNzIG9mIGNvbXBvbmVudCBoZXJlLCBhcyB0aGlzIGlzIGEgY2xhc3MgbWV0aG9kXG4gICAgdmFyIERvbSA9IGZhY2V0c1JlZ2lzdHJ5LmdldCgnRG9tJylcbiAgICAgICAgLCBkb21GYWNldENvbmZpZyA9IHRoaXMuZ2V0RmFjZXRDb25maWcoJ2RvbScpXG4gICAgICAgICwgdGVtcGxhdGVGYWNldENvbmZpZyA9IHRoaXMuZ2V0RmFjZXRDb25maWcoJ3RlbXBsYXRlJylcbiAgICAgICAgLCB0ZW1wbGF0ZSA9IHRlbXBsYXRlRmFjZXRDb25maWcgJiYgdGVtcGxhdGVGYWNldENvbmZpZy50ZW1wbGF0ZTtcblxuICAgIHZhciBlbENvbmZpZyA9IHtcbiAgICAgICAgZG9tQ29uZmlnOiBkb21GYWNldENvbmZpZyxcbiAgICAgICAgdGVtcGxhdGU6IHRlbXBsYXRlLFxuICAgICAgICBjb250ZW50OiBpbm5lckhUTUxcbiAgICB9O1xuXG4gICAgcmV0dXJuIERvbS5jcmVhdGVFbGVtZW50KGVsQ29uZmlnKTtcbn1cblxuZnVuY3Rpb24gX2ZpbmRPckNyZWF0ZUNvbXBvbmVudFJvb3RTY29wZShlbCkge1xuICAgIHZhciBwYXJlbnQgPSBDb21wb25lbnQuZ2V0Q29udGFpbmluZ0NvbXBvbmVudChlbCwgZmFsc2UsICdDb250YWluZXInKTtcbiAgICByZXR1cm4gcGFyZW50ID8gcGFyZW50LmNvbnRhaW5lci5zY29wZSA6IG5ldyBTY29wZShlbCk7XG59XG5cbmZ1bmN0aW9uIF9hZGRBdHRyaWJ1dGVBbmRCaW5kQ29tcG9uZW50KGVsLCByb290U2NvcGUsIGV4dHJhRmFjZXRzKSB7XG4gICAgLy8gYWRkIGJpbmQgYXR0cmlidXRlIHRvIGVsZW1lbnRcbiAgICB2YXIgYXR0ciA9IG5ldyBCaW5kQXR0cmlidXRlKGVsKTtcbiAgICAvLyBcInRoaXNcIiByZWZlcnMgdG8gdGhlIGNsYXNzIG9mIGNvbXBvbmVudCBoZXJlLCBhcyB0aGlzIGlzIGEgY2xhc3MgbWV0aG9kXG4gICAgYXR0ci5jb21wQ2xhc3MgPSB0aGlzLm5hbWU7XG4gICAgYXR0ci5jb21wRmFjZXRzID0gZXh0cmFGYWNldHM7XG4gICAgYXR0ci5kZWNvcmF0ZSgpO1xuXG4gICAgLy8gc2hvdWxkIGJlIHJlcXVpcmVkIGhlcmUgdG8gcmVzb2x2ZSBjaXJjdWxhciBkZXBlbmRlbmN5XG4gICAgdmFyIG1pbG9CaW5kZXIgPSByZXF1aXJlKCcuLi9iaW5kZXInKTtcbiAgICBtaWxvQmluZGVyKGVsLCByb290U2NvcGUpO1xuXG4gICAgcmV0dXJuIHJvb3RTY29wZVthdHRyLmNvbXBOYW1lXTtcbn1cblxuLyoqXG4gKiBDb21wb25lbnQgY2xhc3MgbWV0aG9kXG4gKiBDcmVhdGVzIGNvbXBvbmVudCBmcm9tIGNvbXBvbmVudCBzdGF0ZSwgdGhhdCBpbmNsdWRlcyBpbmZvcm1hdGlvbiBhYm91dCBpdHMgY2xhc3MsIGV4dHJhIGZhY2V0cywgZmFjZXRzIGRhdGEgYW5kIGFsbCBzY29wZSBjaGlsZHJlbi5cbiAqIFRoaXMgaXMgdXNlZCB0byBzYXZlL2xvYWQsIGNvcHkvcGFzdGUgYW5kIGRyYWcvZHJvcCBjb21wb25lbnRcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc3RhdGUgc3RhdGUgZnJvbSB3aGljaCBjb21wb25lbnQgd2lsbCBiZSBjcmVhdGVkXG4gKiBAcGFyYW0ge1Njb3BlfSByb290U2NvcGUgc2NvcGUgdG8gd2hpY2ggY29tcG9uZW50IHdpbGwgYmUgYWRkZWRcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gbmV3VW5pcXVlTmFtZSBvcHRpb25hbCBgdHJ1ZWAgdG8gY3JlYXRlIGNvbXBvbmVudCB3aXRoIHRoZSBuYW1lIGRpZmZlcmVudCBmcm9tIHRoZSBvcmlnaW5hbCBvbmUuIGBGYWxzZWAgYnkgZGVmYXVsdC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gdGhyb3dPbkVycm9ycyBJZiBzZXQgdG8gZmFsc2UsIHRoZW4gZXJyb3JzIHdpbGwgb25seSBiZSBsb2dnZWQgdG8gY29uc29sZS4gVHJ1ZSBieSBkZWZhdWx0LlxuICogQHJldHVybiB7Q29tcG9uZW50fSBjb21wb25lbnRcbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JCRjcmVhdGVGcm9tU3RhdGUoc3RhdGUsIHJvb3RTY29wZSwgbmV3VW5pcXVlTmFtZSwgdGhyb3dPbkVycm9ycykge1xuICAgIGNoZWNrKHN0YXRlLCBNYXRjaC5PYmplY3RJbmNsdWRpbmcoe1xuICAgICAgICBjb21wTmFtZTogTWF0Y2guT3B0aW9uYWwoU3RyaW5nKSxcbiAgICAgICAgY29tcENsYXNzOiBNYXRjaC5PcHRpb25hbChTdHJpbmcpLFxuICAgICAgICBleHRyYUZhY2V0czogTWF0Y2guT3B0aW9uYWwoW1N0cmluZ10pLFxuICAgICAgICBmYWNldHNTdGF0ZXM6IE1hdGNoLk9wdGlvbmFsKE9iamVjdCksXG4gICAgICAgIG91dGVySFRNTDogU3RyaW5nXG4gICAgfSkpO1xuXG4gICAgdmFyIG1pbG9CaW5kZXIgPSByZXF1aXJlKCcuLi9iaW5kZXInKTtcblxuICAgIC8vIGNyZWF0ZSB3cmFwcGVyIGVsZW1lbnQgb3B0aW9uYWxseSByZW5hbWluZyBjb21wb25lbnRcbiAgICB2YXIgd3JhcEVsID0gX2NyZWF0ZUNvbXBvbmVudFdyYXBFbGVtZW50KHN0YXRlLCBuZXdVbmlxdWVOYW1lKTtcblxuICAgIC8vIGluc3RhbnRpYXRlIGFsbCBjb21wb25lbnRzIGZyb20gSFRNTFxuICAgIHZhciBzY29wZSA9IG1pbG9CaW5kZXIod3JhcEVsLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdGhyb3dPbkVycm9ycyk7XG5cbiAgICAvLyBhcyB0aGVyZSBzaG91bGQgb25seSBiZSBvbmUgY29tcG9uZW50LCBjYWxsIHRvIF9hbnkgd2lsbCByZXR1cm4gaXRcbiAgICB2YXIgY29tcG9uZW50ID0gc2NvcGUuX2FueSgpO1xuXG4gICAgLy8gc2V0IGNvbXBvbmVudCdzIHNjb3BlXG4gICAgaWYgKHJvb3RTY29wZSkge1xuICAgICAgICBjb21wb25lbnQuc2NvcGUgPSByb290U2NvcGU7XG4gICAgICAgIHJvb3RTY29wZS5fYWRkKGNvbXBvbmVudCk7XG4gICAgfVxuXG4gICAgLy8gcmVzdG9yZSBjb21wb25lbnQgc3RhdGVcbiAgICBjb21wb25lbnQuc2V0U3RhdGUoc3RhdGUpO1xuICAgIF8uZGVmZXJNZXRob2QoY29tcG9uZW50LCAnYnJvYWRjYXN0JywgJ3N0YXRlcmVhZHknKTtcblxuICAgIHJldHVybiBjb21wb25lbnQ7ICAgXG59XG5cblxuLy8gdXNlZCBieSBDb21wb25lbnQkJGNyZWF0ZUZyb21TdGF0ZVxuZnVuY3Rpb24gX2NyZWF0ZUNvbXBvbmVudFdyYXBFbGVtZW50KHN0YXRlLCBuZXdVbmlxdWVOYW1lKSB7XG4gICAgdmFyIHdyYXBFbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgIHdyYXBFbC5pbm5lckhUTUwgPSBzdGF0ZS5vdXRlckhUTUw7XG5cbiAgICB2YXIgY2hpbGRyZW4gPSBkb21VdGlscy5jaGlsZHJlbih3cmFwRWwpO1xuICAgIGlmIChjaGlsZHJlbi5sZW5ndGggIT0gMSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3QgY3JlYXRlIGNvbXBvbmVudDogaW5jb3JyZWN0IEhUTUwsIGVsZW1lbnRzIG51bWJlcjogJyArIGNoaWxkcmVuLmxlbmd0aCArICcgKHNob3VsZCBiZSAxKScpO1xuICAgIHZhciBjb21wRWwgPSBjaGlsZHJlblswXTtcbiAgICB2YXIgYXR0ciA9IG5ldyBCaW5kQXR0cmlidXRlKGNvbXBFbCk7XG4gICAgYXR0ci5jb21wTmFtZSA9IG5ld1VuaXF1ZU5hbWUgPyBtaWxvQ29tcG9uZW50TmFtZSgpIDogc3RhdGUuY29tcE5hbWU7XG4gICAgYXR0ci5jb21wQ2xhc3MgPSBzdGF0ZS5jb21wQ2xhc3M7XG4gICAgYXR0ci5jb21wRmFjZXRzID0gc3RhdGUuZXh0cmFGYWNldHM7XG4gICAgYXR0ci5kZWNvcmF0ZSgpO1xuXG4gICAgcmV0dXJuIHdyYXBFbDtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgY29tcG9uZW50IGZyb20gYSBEYXRhVHJhbnNmZXIgb2JqZWN0IChpZiBwb3NzaWJsZSlcbiAqXG4gKiBAc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9EYXRhVHJhbnNmZXJcbiAqIEBwYXJhbSB7RGF0YVRyYW5zZmVyfSBkYXRhVHJhbnNmZXIgRGF0YSB0cmFuc2ZlclxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkJGNyZWF0ZUZyb21EYXRhVHJhbnNmZXIoZGF0YVRyYW5zZmVyKSB7XG4gICAgdmFyIGRhdGFUeXBlID0gXy5maW5kKGRhdGFUcmFuc2Zlci50eXBlcywgZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgcmV0dXJuIENPTVBPTkVOVF9EQVRBX1RZUEVfUkVHRVgudGVzdCh0eXBlKTtcbiAgICB9KTtcbiAgICBpZiAoIWRhdGFUeXBlKSByZXR1cm47XG5cbiAgICB2YXIgc3RhdGUgPSBfLmpzb25QYXJzZShkYXRhVHJhbnNmZXIuZ2V0RGF0YShkYXRhVHlwZSkpO1xuICAgIGlmICghc3RhdGUpIHJldHVybjtcblxuICAgIHJldHVybiBDb21wb25lbnQuY3JlYXRlRnJvbVN0YXRlKHN0YXRlLCB1bmRlZmluZWQsIHRydWUpO1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZC5cbiAqIEluaXRpYWxpemVzIGNvbXBvbmVudC4gQXV0b21hdGljYWxseSBjYWxsZWQgYnkgaW5oZXJpdGVkIGNvbnN0cnVjdG9yIG9mIEZhY2V0ZWRPYmplY3QuXG4gKiBTdWJjbGFzc2VzIHNob3VsZCBjYWxsIGluaGVyaXRlZCBpbml0IG1ldGhvZHM6XG4gKiBgYGBcbiAqIENvbXBvbmVudC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpXG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge1Njb3BlfSBzY29wZSBzY29wZSB0byB3aGljaCBjb21wb25lbnQgd2lsbCBiZWxvbmcuIEl0IGlzIHVzdWFsbHkgYSB0b3AgbGV2ZWwgc2NvcGUgb2JqZWN0IHJldHVybmVkIGJ5IGBtaWxvLmJpbmRlcmAgb3IgYHNjb3BlYCBwcm9wZXJ0eSBvZiBDb250YWluZXIgZmFjZXQuXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsZW1lbnQgRE9NIGVsZW1lbnQgdGhhdCBjb21wb25lbnQgaXMgYXR0YWNoZWQgdG9cbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIGNvbXBvbmVudCBuYW1lLCBzaG91bGQgYmUgdW5pcXVlIGluIHRoZSBzY29wZSBvZiBjb21wb25lbnRcbiAqIEBwYXJhbSB7Q29tcG9uZW50SW5mb30gY29tcG9uZW50SW5mbyBpbnN0YW5jZSBvZiBDb21wb25lbnRJbmZvIGNsYXNzIHRoYXQgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGEgY29weSBvZiBjb21wb25lbnRcbiAqICBUT0RPIHRyeSByZW1vdmluZyBpdFxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkaW5pdChzY29wZSwgZWxlbWVudCwgbmFtZSwgY29tcG9uZW50SW5mbykge1xuICAgIC8vIGNyZWF0ZSBET00gZWxlbWVudCBpZiBpdCB3YXNuJ3QgcGFzc2VkIHRvIENvbnN0cnVjdG9yXG4gICAgdGhpcy5lbCA9IGVsZW1lbnQgfHwgdGhpcy5jcmVhdGVFbGVtZW50KCk7XG5cbiAgICAvLyBzdG9yZSByZWZlcmVuY2UgdG8gY29tcG9uZW50IG9uIERPTSBlbGVtZW50XG4gICAgaWYgKHRoaXMuZWwpIHtcbiAgICAgICAgLy8gY2hlY2sgdGhhdCBlbGVtZW50IGRvZXMgbm90IGhhdmUgYSBjb21wb25lbnQgYWxyZWFkeSBhdGFjaGVkXG4gICAgICAgIHZhciBlbENvbXAgPSB0aGlzLmVsW2NvbmZpZy5jb21wb25lbnRSZWZdO1xuICAgICAgICBpZiAoZWxDb21wKVxuICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ2NvbXBvbmVudCAnICsgbmFtZSArICcgYXR0YWNoZWQgdG8gZWxlbWVudCB0aGF0IGFscmVhZHkgaGFzIGNvbXBvbmVudCAnICsgZWxDb21wLm5hbWUpO1xuXG4gICAgICAgIHRoaXMuZWxbY29uZmlnLmNvbXBvbmVudFJlZl0gPSB0aGlzO1xuICAgIH1cblxuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgIGNvbXBvbmVudEluZm86IGNvbXBvbmVudEluZm8sXG4gICAgICAgIGV4dHJhRmFjZXRzOiBbXVxuICAgIH0sIF8uRU5VTSk7XG5cbiAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgIHRoaXMuc2NvcGUgPSBzY29wZTtcblxuICAgIC8vIGNyZWF0ZSBjb21wb25lbnQgbWVzc2VuZ2VyXG4gICAgdmFyIG1lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXIodGhpcyk7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBNRVNTRU5HRVJfUFJPUEVSVFksIG1lc3Nlbmdlcik7XG5cbiAgICAvLyBjaGVjayBhbGwgZmFjZXRzIGRlcGVuZGVuY2llcyAocmVxdWlyZWQgZmFjZXRzKVxuICAgIHRoaXMuYWxsRmFjZXRzKCdjaGVjaycpO1xuXG4gICAgLy8gc3RhcnQgYWxsIGZhY2V0c1xuICAgIHRoaXMuYWxsRmFjZXRzKCdzdGFydCcpO1xuXG4gICAgLy8gY2FsbCBzdGFydCBtZXRob2QgaWYgaXQncyBkZWZpbmVkIGluIHN1YmNsYXNzXG4gICAgaWYgKHRoaXMuc3RhcnQpIHRoaXMuc3RhcnQoKTtcbn1cblxuXG4vKipcbiAqIFRoaXMgaXMgYSBzdHViIHRvIGF2b2lkIGNvbmZ1c2lvbiB3aGV0aGVyIHRoZSBtZXRob2Qgb2Ygc3VwZXJjbGFzcyBzaG91bGQgYmUgY2FsbGVkIGluIHN1YmNsYXNzZXNcbiAqIFRoZSBzdGFydCBtZXRob2Qgb2Ygc3ViY2xhc3MgaW5zdGFuY2UgaXMgY2FsbGVkIG9uY2UgYWxsIHRoZSBmYWNldHMgYXJlIGNyZWF0ZWQsIGluaXRpYWxpemVkIGFuZCBzdGFydGVkIChzZWUgYWJvdmUpXG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRzdGFydCgpIHt9XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kLlxuICogSW5pdGlhbGl6ZXMgdGhlIGVsZW1lbnQgd2hpY2ggdGhpcyBjb21wb25lbnQgaXMgYm91bmQgdG9cbiAqXG4gKiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgd2hlbiBhIGNvbXBvbmVudCBpcyBpbnN0YW50aWF0ZWQgb3V0c2lkZSB0aGUgRE9NIGFuZFxuICogd2lsbCBnZW5lcmF0ZSBhIG5ldyBlbGVtZW50IGZvciB0aGUgY29tcG9uZW50LlxuICogXG4gKiBAcmV0dXJuIHtFbGVtZW50fVxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkY3JlYXRlRWxlbWVudCgpIHtcbiAgICBpZiAodHlwZW9mIGRvY3VtZW50ID09ICd1bmRlZmluZWQnKVxuICAgICAgICByZXR1cm47XG5cbiAgICB0aGlzLmVsID0gdGhpcy5kb21cbiAgICAgICAgICAgICAgICA/IHRoaXMuZG9tLmNyZWF0ZUVsZW1lbnQoKVxuICAgICAgICAgICAgICAgIDogZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnRElWJyk7XG5cbiAgICByZXR1cm4gdGhpcy5lbDtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgdHJ1ZSBpZiBjb21wb25lbnQgaGFzIGZhY2V0XG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbnxTdHJpbmd9IGZhY2V0TmFtZU9yQ2xhc3NcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRoYXNGYWNldChmYWNldE5hbWVPckNsYXNzKSB7XG4gICAgdmFyIGZhY2V0TmFtZSA9IF8uZmlyc3RMb3dlckNhc2UodHlwZW9mIGZhY2V0TmFtZU9yQ2xhc3MgPT0gJ2Z1bmN0aW9uJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gZmFjZXROYW1lT3JDbGFzcy5uYW1lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiBmYWNldE5hbWVPckNsYXNzKTtcblxuICAgIHZhciBmYWNldCA9IHRoaXNbZmFjZXROYW1lXTtcbiAgICBpZiAoISBmYWNldCBpbnN0YW5jZW9mIENvbXBvbmVudEZhY2V0KVxuICAgICAgICBsb2dnZXIud2FybignZXhwZWN0ZWQgZmFjZXQnLCBmYWNldE5hbWUsICdidXQgdGhpcyBwcm9wZXJ0eSBuYW1lIGlzIHVzZWQgZm9yIHNvbWV0aGluZyBlbHNlJyk7XG5cbiAgICByZXR1cm4gISEgZmFjZXQ7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kLlxuICogQWRkcyBmYWNldCB3aXRoIGdpdmVuIG5hbWUgb3IgY2xhc3MgdG8gdGhlIGluc3RhbmNlIG9mIENvbXBvbmVudCAob3IgaXRzIHN1YmNsYXNzKS5cbiAqIFxuICogQHBhcmFtIHtTdHJpbmd8U3ViY2xhc3MoQ29tcG9uZW50KX0gZmFjZXROYW1lT3JDbGFzcyBuYW1lIG9mIGZhY2V0IGNsYXNzIG9yIHRoZSBjbGFzcyBpdHNlbGYuIElmIG5hbWUgaXMgcGFzc2VkLCB0aGUgY2xhc3Mgd2lsbCBiZSByZXRpcmV2ZWQgZnJvbSBmYWNldHNSZWdpc3RyeVxuICogQHBhcmFtIHtPYmplY3R9IGZhY2V0Q29uZmlnIG9wdGlvbmFsIGZhY2V0IGNvbmZpZ3VyYXRpb25cbiAqIEBwYXJhbSB7U3RyaW5nfSBmYWNldE5hbWUgb3B0aW9uYWwgZmFjZXQgbmFtZS4gQWxsb3dzIHRvIGFkZCBmYWNldCB1bmRlciBhIG5hbWUgZGlmZmVyZW50IGZyb20gdGhlIGNsYXNzIG5hbWUgc3VwcGxpZWQuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHRocm93T25FcnJvcnMgSWYgc2V0IHRvIGZhbHNlLCB0aGVuIGVycm9ycyB3aWxsIG9ubHkgYmUgbG9nZ2VkIHRvIGNvbnNvbGUuIFRydWUgYnkgZGVmYXVsdC5cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JGFkZEZhY2V0KGZhY2V0TmFtZU9yQ2xhc3MsIGZhY2V0Q29uZmlnLCBmYWNldE5hbWUsIHRocm93T25FcnJvcnMpIHtcbiAgICBjaGVjayhmYWNldE5hbWVPckNsYXNzLCBNYXRjaC5PbmVPZihTdHJpbmcsIE1hdGNoLlN1YmNsYXNzKENvbXBvbmVudEZhY2V0KSkpO1xuICAgIGNoZWNrKGZhY2V0Q29uZmlnLCBNYXRjaC5PcHRpb25hbChPYmplY3QpKTtcbiAgICBjaGVjayhmYWNldE5hbWUsIE1hdGNoLk9wdGlvbmFsKFN0cmluZykpO1xuXG4gICAgdmFyIEZhY2V0Q2xhc3M7XG4gICAgLy8gaWYgb25seSBuYW1lIHBhc3NlZCwgcmV0cmlldmUgZmFjZXQgY2xhc3MgZnJvbSByZWdpc3RyeVxuICAgIGlmICh0eXBlb2YgZmFjZXROYW1lT3JDbGFzcyA9PSAnc3RyaW5nJykge1xuICAgICAgICB2YXIgZmFjZXRDbGFzc05hbWUgPSBfLmZpcnN0VXBwZXJDYXNlKGZhY2V0TmFtZU9yQ2xhc3MpO1xuICAgICAgICBGYWNldENsYXNzID0gZmFjZXRzUmVnaXN0cnkuZ2V0KGZhY2V0Q2xhc3NOYW1lKTtcbiAgICB9IGVsc2UgXG4gICAgICAgIEZhY2V0Q2xhc3MgPSBmYWNldE5hbWVPckNsYXNzO1xuXG4gICAgaWYgKCFmYWNldE5hbWUpXG4gICAgICAgIGZhY2V0TmFtZSA9IF8uZmlyc3RMb3dlckNhc2UoRmFjZXRDbGFzcy5uYW1lKTtcblxuICAgIHRoaXMuZXh0cmFGYWNldHMucHVzaChmYWNldE5hbWUpO1xuXG4gICAgLy8gYWRkIGZhY2V0IHVzaW5nIG1ldGhvZCBvZiBGYWNldGVkT2JqZWN0XG4gICAgdmFyIG5ld0ZhY2V0ID0gRmFjZXRlZE9iamVjdC5wcm90b3R5cGUuYWRkRmFjZXQuY2FsbCh0aGlzLCBGYWNldENsYXNzLCBmYWNldENvbmZpZywgZmFjZXROYW1lLCB0aHJvd09uRXJyb3JzKTtcblxuICAgIC8vIGNoZWNrIGRlcGVuZWRlbmNpZXMgYW5kIHN0YXJ0IGZhY2V0XG4gICAgaWYgKG5ld0ZhY2V0LmNoZWNrKSBuZXdGYWNldC5jaGVjaygpO1xuICAgIGlmIChuZXdGYWNldC5zdGFydCkgbmV3RmFjZXQuc3RhcnQoKTtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2QuXG4gKiBFbnZva2UgZ2l2ZW4gbWV0aG9kIHdpdGggb3B0aW9uYWwgcGFyYW1ldGVycyBvbiBhbGwgZmFjZXRzLlxuICogUmV0dXJucyB0aGUgbWFwIG9mIHZhbHVlcyByZXR1cm5lZCBieSBhbGwgZmFjZXRzLiBJZiB0aGUgZmFjZXQgZG9lc24ndCBoYXZlIHRoZSBtZXRob2QgaXQgaXMgc2ltcGx5IG5vdCBjYWxsZWQgYW5kIHRoZSB2YWx1ZSBpbiB0aGUgbWFwIHdpbGwgYmUgdW5kZWZpbmVkLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXRob2QgbWV0aG9kIG5hbWUgdG8gZW52b2tlIG9uIHRoZSBmYWNldFxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkYWxsRmFjZXRzKG1ldGhvZCkgeyAvLyAsLi4uIGFyZ3VtZW50c1xuICAgIHZhciBhcmdzID0gXy5zbGljZShhcmd1bWVudHMsIDEpO1xuXG4gICAgcmV0dXJuIF8ubWFwS2V5cyh0aGlzLmZhY2V0cywgZnVuY3Rpb24oZmFjZXQsIGZjdE5hbWUpIHtcbiAgICAgICAgaWYgKGZhY2V0ICYmIHR5cGVvZiBmYWNldFttZXRob2RdID09ICdmdW5jdGlvbicpXG4gICAgICAgICAgICByZXR1cm4gZmFjZXRbbWV0aG9kXS5hcHBseShmYWNldCwgYXJncyk7XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kLlxuICogXG4gKiBAcGFyYW0ge1tTdHJpbmddfSBuYW1lIG9wdGlvbmFsIG5ldyBuYW1lIG9mIGNvbXBvbmVudCwgXG4gKiBAcGFyYW0ge1tCb29sZWFuXX0gcmVuYW1lSW5TY29wZSBvcHRpb25hbCBmYWxzZSB0byBub3QgcmVuYW1lIENvbXBvbmVudEluZm8gb2JqZWN0IGluIGl0cyBzY29wZSwgdHJ1ZSBieSBkZWZhdWx0XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRyZW5hbWUobmFtZSwgcmVuYW1lSW5TY29wZSkge1xuICAgIG5hbWUgPSBuYW1lIHx8IG1pbG9Db21wb25lbnROYW1lKCk7XG4gICAgdGhpcy5jb21wb25lbnRJbmZvLnJlbmFtZShuYW1lLCBmYWxzZSk7XG4gICAgU2NvcGUucmVuYW1lKHRoaXMsIG5hbWUsIHJlbmFtZUluU2NvcGUpO1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZC5cbiAqIFJlbW92ZXMgY29tcG9uZW50IGZyb20gaXRzIHNjb3BlLlxuICpcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gcHJlc2VydmVTY29wZVByb3BlcnR5IHRydWUgbm90IHRvIGRlbGV0ZSBzY29wZSBwcm9wZXJ0eSBvZiBjb21wb25lbnRcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gcXVpZXQgb3B0aW9uYWwgdHJ1ZSB0byBzdXBwcmVzcyB0aGUgd2FybmluZyBtZXNzYWdlIGlmIHRoZSBjb21wb25lbnQgaXMgbm90IGluIHNjb3BlXG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRyZW1vdmUocHJlc2VydmVTY29wZVByb3BlcnR5LCBxdWlldCkge1xuICAgIGlmICh0aGlzLnNjb3BlKSB7XG4gICAgICAgIHRoaXMuc2NvcGUuX3JlbW92ZSh0aGlzLm5hbWUsIHF1aWV0KTtcbiAgICAgICAgaWYgKCEgcHJlc2VydmVTY29wZVByb3BlcnR5KVxuICAgICAgICAgICAgZGVsZXRlIHRoaXMuc2NvcGU7XG4gICAgfVxufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZC5cbiAqIEluc2VydHMgdGhlIGNvbXBvbmVudCBpbnRvIHRoZSBET00gYW5kIGF0dGVtcHRzIHRvIGFkanVzdCB0aGUgc2NvcGUgdHJlZSBhY2NvcmRpbmdseS5cbiAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IHBhcmVudEVsICAgIFRoZSBlbGVtZW50IGludG8gd2hpY2ggdGhlIGNvbXBvbmVudCBzaG91bGQgYmUgaW5zZXJ0ZWQuXG4gKiBAcGFyYW0ge0hUTUxFbGVtZW50fSByZWZlcmVuY2VFbCAob3B0aW9uYWwpIFRoZSByZWZlcmVuY2UgZWxlbWVudCBpdCBzaG91bGQgYmUgaW5zZXJ0ZWQgYmVmb3JlLlxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkaW5zZXJ0SW50byhwYXJlbnRFbCwgcmVmZXJlbmNlRWwpIHtcbiAgICBwYXJlbnRFbC5pbnNlcnRCZWZvcmUodGhpcy5lbCwgcmVmZXJlbmNlRWwpO1xuICAgIHRoaXMuc2V0U2NvcGVQYXJlbnRGcm9tRE9NKCk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXRyaWV2ZXMgYWxsIGNvbXBvbmVudCBzdGF0ZSwgaW5jbHVkaW5nIGluZm9ybWF0aW9uIGFib3V0IGl0cyBjbGFzcywgZXh0cmEgZmFjZXRzLCBmYWNldHMgZGF0YSBhbmQgYWxsIHNjb3BlIGNoaWxkcmVuLlxuICogVGhpcyBpbmZvcm1hdGlvbiBpcyB1c2VkIHRvIHNhdmUvbG9hZCwgY29weS9wYXN0ZSBhbmQgZHJhZy9kcm9wIGNvbXBvbmVudCBcbiAqIFJldHVybnMgY29tcG9uZW50IHN0YXRlXG4gKlxuICogQHRoaXMge0NvbXBvbmVudH0gY29tcG9uZW50IHdoaWNoIHN0YXRlIHdpbGwgYmUgc2F2ZWRcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JGdldFN0YXRlKCkge1xuICAgIHRoaXMuYnJvYWRjYXN0KCdnZXRzdGF0ZXN0YXJ0ZWQnLCB7IHJvb3RDb21wb25lbnQ6IHRoaXMgfSwgdW5kZWZpbmVkLCB0cnVlKTtcbiAgICB2YXIgc3RhdGUgPSB0aGlzLl9nZXRTdGF0ZSh0cnVlKTtcbiAgICBzdGF0ZS5vdXRlckhUTUwgPSB0aGlzLmVsLm91dGVySFRNTDtcbiAgICBfLmRlZmVyTWV0aG9kKHRoaXMsICdicm9hZGNhc3QnLCAnZ2V0c3RhdGVjb21wbGV0ZWQnLCB7IHJvb3RDb21wb25lbnQ6IHRoaXMgfSwgdW5kZWZpbmVkLCB0cnVlKTtcbiAgICByZXR1cm4gc3RhdGU7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXRyaWV2ZXMgYWxsIGNvbXBvbmVudCBzdGF0ZSwgaW5jbHVkaW5nIGluZm9ybWF0aW9uIGFib3V0IGl0cyBjbGFzcywgZXh0cmEgZmFjZXRzLCBmYWNldHMgZGF0YSBhbmQgYWxsIHNjb3BlIGNoaWxkcmVuLlxuICogVGhpcyBpbmZvcm1hdGlvbiBpcyB1c2VkIHRvIHNhdmUvbG9hZCwgY29weS9wYXN0ZSBhbmQgZHJhZy9kcm9wIGNvbXBvbmVudCBcbiAqIElmIGNvbXBvbmVudCBoYXMgW1RyYW5zZmVyXSguL2NfZmFjZXRzL1RyYW5zZmVyLmpzLmh0bWwpIGZhY2V0IG9uIGl0LCB0aGlzIG1ldGhvZCByZXRyaWV2ZXMgc3RhdGUgZnJvbSB0aGlzIGZhY2V0XG4gKiBSZXR1cm5zIGNvbXBvbmVudCBzdGF0ZVxuICpcbiAqIEB0aGlzIHtDb21wb25lbnR9IGNvbXBvbmVudCB3aGljaCBzdGF0ZSB3aWxsIGJlIHNhdmVkXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBjYW4gYmUgdXNlZCBieSBzdWJjbGFzc2VzLiBcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JGdldFRyYW5zZmVyU3RhdGUob3B0aW9ucykge1xuICAgIHJldHVybiB0aGlzLnRyYW5zZmVyXG4gICAgICAgICAgICA/IHRoaXMudHJhbnNmZXIuZ2V0U3RhdGUob3B0aW9ucylcbiAgICAgICAgICAgIDogdGhpcy5nZXRTdGF0ZShvcHRpb25zKTtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgdGhlIHN0YXRlIG9mIGNvbXBvbmVudFxuICogVXNlZCBieSBjbGFzcyBtZXRob2QgYENvbXBvbmVudC5nZXRTdGF0ZWAgYW5kIGJ5IFtDb250YWluZXJdKC4vY19mYWNldHMvQ29udGFpbmVyLmpzLmh0bWwpIGZhY2V0LlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGRlZXBTdGF0ZSBmYWxzZSB0byBnZXQgc2hhbGxvdyBzdGF0ZSBmcm9tIGFsbCBmYWNldHMgKHRydWUgYnkgZGVmYXVsdClcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JF9nZXRTdGF0ZShkZWVwU3RhdGUpe1xuXG4gICAgdmFyIGZhY2V0c1N0YXRlcyA9IHRoaXMuYWxsRmFjZXRzKCdnZXRTdGF0ZScsIGRlZXBTdGF0ZSA9PT0gZmFsc2UgPyBmYWxzZSA6IHRydWUpO1xuICAgIGZhY2V0c1N0YXRlcyA9IF8uZmlsdGVyS2V5cyhmYWNldHNTdGF0ZXMsIGZ1bmN0aW9uKGZjdFN0YXRlKSB7XG4gICAgICAgIHJldHVybiAhISBmY3RTdGF0ZTtcbiAgICB9KTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIGNvbXBOYW1lOiB0aGlzLm5hbWUsXG4gICAgICAgIGNvbXBDbGFzczogdGhpcy5jb25zdHJ1Y3Rvci5uYW1lLFxuICAgICAgICBleHRyYUZhY2V0czogdGhpcy5leHRyYUZhY2V0cyxcbiAgICAgICAgZmFjZXRzU3RhdGVzOiBmYWNldHNTdGF0ZXNcbiAgICB9O1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZFxuICogU2V0cyB0aGUgc3RhdGUgb2YgY29tcG9uZW50LlxuICogVXNlZCBieSBjbGFzcyBtZXRob2QgYENvbXBvbmVudC5jcmVhdGVGcm9tU3RhdGVgIGFuZCBieSBbQ29udGFpbmVyXSguL2NfZmFjZXRzL0NvbnRhaW5lci5qcy5odG1sKSBmYWNldC5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtPYmplY3R9IHN0YXRlIHN0YXRlIHRvIHNldCB0aGUgY29tcG9uZW50XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRzZXRTdGF0ZShzdGF0ZSkge1xuICAgIGlmIChzdGF0ZS5mYWNldHNTdGF0ZXMpXG4gICAgICAgIF8uZWFjaEtleShzdGF0ZS5mYWNldHNTdGF0ZXMsIGZ1bmN0aW9uKGZjdFN0YXRlLCBmY3ROYW1lKSB7XG4gICAgICAgICAgICB2YXIgZmFjZXQgPSB0aGlzW2ZjdE5hbWVdO1xuICAgICAgICAgICAgaWYgKGZhY2V0ICYmIHR5cGVvZiBmYWNldC5zZXRTdGF0ZSA9PSAnZnVuY3Rpb24nKVxuICAgICAgICAgICAgICAgIGZhY2V0LnNldFN0YXRlKGZjdFN0YXRlKTtcbiAgICAgICAgfSwgdGhpcyk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kLlxuICogUmV0dXJucyB0aGUgc2NvcGUgcGFyZW50IG9mIGEgY29tcG9uZW50LlxuICogSWYgYGNvbmRpdGlvbk9yRmFjZXRgIHBhcmFtZXRlciBpcyBub3Qgc3BlY2lmaWVkLCBhbiBpbW1lZGlhdGUgcGFyZW50IHdpbGwgYmUgcmV0dXJuZWQsIG90aGVyd2lzZSB0aGUgY2xvc2VzdCBhbmNlc3RvciB3aXRoIGEgc3BlY2lmaWVkIGZhY2V0IG9yIHBhc3NpbmcgY29uZGl0aW9uIHRlc3QuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbnxTdHJpbmd9IGNvbmRpdGlvbk9yRmFjZXQgb3B0aW9uYWwgY29uZGl0aW9uIHRoYXQgY29tcG9uZW50IHNob3VsZCBwYXNzIChvciBmYWNldCBuYW1lIGl0IHNob3VsZCBjb250YWluKVxuICogQHJldHVybiB7Q29tcG9uZW50fHVuZGVmaW5lZH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JGdldFNjb3BlUGFyZW50KGNvbmRpdGlvbk9yRmFjZXQpIHtcbiAgICByZXR1cm4gX2NhbGxHZXRTY29wZVBhcmVudC5jYWxsKHRoaXMsIF9nZXRTY29wZVBhcmVudCwgY29uZGl0aW9uT3JGYWNldCk7XG59XG5cbmZ1bmN0aW9uIF9jYWxsR2V0U2NvcGVQYXJlbnQoX2dldFNjb3BlUGFyZW50RnVuYywgY29uZGl0aW9uT3JGYWNldCkge1xuICAgIGNoZWNrKGNvbmRpdGlvbk9yRmFjZXQsIE1hdGNoLk9wdGlvbmFsKE1hdGNoLk9uZU9mKEZ1bmN0aW9uLCBTdHJpbmcpKSk7XG4gICAgdmFyIGNvbmRpdGlvbkZ1bmMgPSBjb21wb25lbnRVdGlscy5fbWFrZUNvbXBvbmVudENvbmRpdGlvbkZ1bmMoY29uZGl0aW9uT3JGYWNldCk7XG4gICAgcmV0dXJuIF9nZXRTY29wZVBhcmVudEZ1bmMuY2FsbCh0aGlzLCBjb25kaXRpb25GdW5jKTsgICBcbn1cblxuZnVuY3Rpb24gX2dldFNjb3BlUGFyZW50KGNvbmRpdGlvbkZ1bmMpIHtcbiAgICB2YXIgcGFyZW50O1xuICAgIHRyeSB7IHBhcmVudCA9IHRoaXMuc2NvcGUuX2hvc3RPYmplY3Qub3duZXI7IH0gY2F0Y2goZSkge31cblxuICAgIC8vIFdoZXJlIHRoZXJlIGlzIG5vIHBhcmVudCwgdGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiB1bmRlZmluZWRcbiAgICAvLyBUaGUgcGFyZW50IGNvbXBvbmVudCBpcyBjaGVja2VkIHJlY3Vyc2l2ZWx5XG4gICAgaWYgKHBhcmVudCkge1xuICAgICAgICBpZiAoISBjb25kaXRpb25GdW5jIHx8IGNvbmRpdGlvbkZ1bmMocGFyZW50KSApXG4gICAgICAgICAgICByZXR1cm4gcGFyZW50O1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICByZXR1cm4gX2dldFNjb3BlUGFyZW50LmNhbGwocGFyZW50LCBjb25kaXRpb25GdW5jKTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHNjb3BlIHBhcmVudCB3aXRoIGEgZ2l2ZW4gY2xhc3MsIHdpdGggc2FtZSBjbGFzcyBpZiBub3Qgc3BlY2lmaWVkXG4gKlxuICogQHBhcmFtIHtbRnVuY3Rpb25dfSBDb21wb25lbnRDbGFzcyBjb21wb25lbnQgY2xhc3MgdGhhdCB0aGUgcGFyZW50IHNob3VsZCBoYXZlLCBzYW1lIGNsYXNzIGJ5IGRlZmF1bHRcbiAqIEByZXR1cm4ge0NvbXBvbmVudH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JGdldFNjb3BlUGFyZW50V2l0aENsYXNzKENvbXBvbmVudENsYXNzKSB7XG4gICAgQ29tcG9uZW50Q2xhc3MgPSBDb21wb25lbnRDbGFzcyB8fCB0aGlzLmNvbnN0cnVjdG9yO1xuICAgIHJldHVybiBfZ2V0U2NvcGVQYXJlbnQuY2FsbCh0aGlzLCBmdW5jdGlvbihjb21wKSB7XG4gICAgICAgIHJldHVybiBjb21wIGluc3RhbmNlb2YgQ29tcG9uZW50Q2xhc3M7XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kLlxuICogUmV0dXJucyB0aGUgdG9wbW9zdCBzY29wZSBwYXJlbnQgb2YgYSBjb21wb25lbnQuXG4gKiBJZiBgY29uZGl0aW9uT3JGYWNldGAgcGFyYW1ldGVyIGlzIG5vdCBzcGVjaWZpZWQsIHRoZSB0b3Btb3N0IHNjb3BlIHBhcmVudCB3aWxsIGJlIHJldHVybmVkLCBvdGhlcndpc2UgdGhlIHRvcG1vc3QgYW5jZXN0b3Igd2l0aCBhIHNwZWNpZmllZCBmYWNldCBvciBwYXNzaW5nIGNvbmRpdGlvbiB0ZXN0LlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb258U3RyaW5nfSBjb25kaXRpb25PckZhY2V0IG9wdGlvbmFsIGNvbmRpdGlvbiB0aGF0IGNvbXBvbmVudCBzaG91bGQgcGFzcyAob3IgZmFjZXQgbmFtZSBpdCBzaG91bGQgY29udGFpbilcbiAqIEByZXR1cm4ge0NvbXBvbmVudHx1bmRlZmluZWR9XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRnZXRUb3BTY29wZVBhcmVudChjb25kaXRpb25PckZhY2V0KSB7XG4gICAgcmV0dXJuIF9jYWxsR2V0U2NvcGVQYXJlbnQuY2FsbCh0aGlzLCBfZ2V0VG9wU2NvcGVQYXJlbnQsIGNvbmRpdGlvbk9yRmFjZXQpO1xufVxuXG5mdW5jdGlvbiBfZ2V0VG9wU2NvcGVQYXJlbnQoY29uZGl0aW9uRnVuYykge1xuICAgIHZhciB0b3BQYXJlbnRcbiAgICAgICAgLCBwYXJlbnQgPSB0aGlzO1xuICAgIGRvIHtcbiAgICAgICAgcGFyZW50ID0gX2dldFNjb3BlUGFyZW50LmNhbGwocGFyZW50LCBjb25kaXRpb25GdW5jKTtcbiAgICAgICAgaWYgKHBhcmVudClcbiAgICAgICAgICAgIHRvcFBhcmVudCA9IHBhcmVudDtcbiAgICB9IHdoaWxlIChwYXJlbnQpO1xuXG4gICAgcmV0dXJuIHRvcFBhcmVudDtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgc2NvcGUgcGFyZW50IHdpdGggYSBnaXZlbiBjbGFzcywgd2l0aCBzYW1lIGNsYXNzIGlmIG5vdCBzcGVjaWZpZWRcbiAqXG4gKiBAcGFyYW0ge1tGdW5jdGlvbl19IENvbXBvbmVudENsYXNzIGNvbXBvbmVudCBjbGFzcyB0aGF0IHRoZSBwYXJlbnQgc2hvdWxkIGhhdmUsIHNhbWUgY2xhc3MgYnkgZGVmYXVsdFxuICogQHJldHVybiB7Q29tcG9uZW50fVxuICovXG5mdW5jdGlvbiBDb21wb25lbnQkZ2V0VG9wU2NvcGVQYXJlbnRXaXRoQ2xhc3MoQ29tcG9uZW50Q2xhc3MpIHtcbiAgICBDb21wb25lbnRDbGFzcyA9IENvbXBvbmVudENsYXNzIHx8IHRoaXMuY29uc3RydWN0b3I7XG4gICAgcmV0dXJuIF9nZXRUb3BTY29wZVBhcmVudC5jYWxsKHRoaXMsIGZ1bmN0aW9uKGNvbXApIHtcbiAgICAgICAgcmV0dXJuIGNvbXAgaW5zdGFuY2VvZiBDb21wb25lbnRDbGFzcztcbiAgICB9KTtcbn1cblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIEZpbmRzIHNjb3BlIHBhcmVudCBvZiBjb21wb25lbnQgdXNpbmcgRE9NIHRyZWUgKHVubGlrZSBnZXRTY29wZVBhcmVudCB0aGF0IHNpbXBseSBnb2VzIHVwIHRoZSBzY29wZSB0cmVlKS5cbiAqIFdoaWxlIGdldFNjb3BlUGFyZW50IGlzIGZhc3RlciBpdCBtYXkgZmFpbCBpZiBzY29wZSBjaGFpbiBpcyBub3Qgc2V0dXAgeWV0IChlLmcuLCB3aGVuIGNvbXBvbmVudCBoYXMgYmVlbiBqdXN0IGluc2VydGVkKS5cbiAqIFRoZSBzY29wZSBwcm9wZXJ0eSBvZiBjb21wb25lbnQgd2lsbCBiZSBjaGFuZ2VkIHRvIHBvaW50IHRvIHNjb3BlIG9iamVjdCBvZiBjb250YWluZXIgZmFjZXQgb2YgdGhhdCBwYXJlbnQuXG4gKiBSZXR1cm5lZCBzY29wZSBwYXJlbnQgb2YgdGhlIGNvbXBvbmVudCB3aWxsIGJlIHVuZGVmaW5lZCAoYXMgd2VsbCBhcyBjb21wb25lbnQncyBzY29wZSBwcm9wZXJ0eSkgaWYgbm8gcGFyZW50IGluIHRoZSBET00gdHJlZSBoYXMgY29udGFpbmVyIGZhY2V0LlxuICogVE9ETyBNZXRob2Qgd2lsbCBub3QgYmluZCBET00gY2hpbGRyZW4gY29ycmVjdGx5IGlmIGNvbXBvbmVudCBoYXMgbm8gY29udGFpbmVyIGZhY2V0LlxuICpcbiAqIEByZXR1cm4ge0NvbXBvbmVudH1cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50JHNldFNjb3BlUGFyZW50RnJvbURPTSgpIHtcbiAgICB2YXIgcGFyZW50RWwgPSB0aGlzLmVsLnBhcmVudE5vZGU7XG5cbiAgICB2YXIgcGFyZW50LCBmb3VuZFBhcmVudDtcbiAgICB3aGlsZSAocGFyZW50RWwgJiYgISBmb3VuZFBhcmVudCkge1xuICAgICAgICBwYXJlbnQgPSBDb21wb25lbnQuZ2V0Q29tcG9uZW50KHBhcmVudEVsKTtcbiAgICAgICAgZm91bmRQYXJlbnQgPSBwYXJlbnQgJiYgcGFyZW50LmNvbnRhaW5lcjtcbiAgICAgICAgcGFyZW50RWwgPSBwYXJlbnRFbC5wYXJlbnROb2RlO1xuICAgIH1cblxuICAgIHRoaXMucmVtb3ZlKCk7IC8vIHJlbW92ZSBjb21wb25lbnQgZnJvbSBpdHMgY3VycmVudCBzY29wZSAoaWYgaXQgaXMgZGVmaW5lZClcbiAgICBpZiAoZm91bmRQYXJlbnQpIHtcbiAgICAgICAgdGhpcy5yZW5hbWUodW5kZWZpbmVkLCBmYWxzZSk7XG4gICAgICAgIHBhcmVudC5jb250YWluZXIuc2NvcGUuX2FkZCh0aGlzKTtcbiAgICAgICAgcmV0dXJuIHBhcmVudDtcbiAgICB9ICAgICAgICBcbn1cblxuXG4vKipcbiAqIFdhbGtzIGNvbXBvbmVudCB0cmVlLCBjYWxsaW5nIHByb3ZpZGVkIGNhbGxiYWNrIG9uIGVhY2ggY29tcG9uZW50XG4gKlxuICogQHBhcmFtIGNhbGxiYWNrXG4gKiBAcGFyYW0gdGhpc0FyZ1xuICovXG5mdW5jdGlvbiBDb21wb25lbnQkd2Fsa1Njb3BlVHJlZShjYWxsYmFjaywgdGhpc0FyZykge1xuICAgIGNhbGxiYWNrLmNhbGwodGhpc0FyZywgdGhpcyk7XG4gICAgaWYgKCF0aGlzLmNvbnRhaW5lcikgcmV0dXJuO1xuICAgIHRoaXMuY29udGFpbmVyLnNjb3BlLl9lYWNoKGZ1bmN0aW9uKGNvbXBvbmVudCkge1xuICAgICAgICBjb21wb25lbnQud2Fsa1Njb3BlVHJlZShjYWxsYmFjaywgdGhpc0FyZyk7XG4gICAgfSk7XG59XG5cblxuZnVuY3Rpb24gQ29tcG9uZW50JHRyZWVQYXRoT2YoY29tcG9uZW50KSB7XG4gICAgcmV0dXJuIGRvbVV0aWxzLnRyZWVQYXRoT2YodGhpcy5lbCwgY29tcG9uZW50LmVsKTtcbn1cblxuXG5mdW5jdGlvbiBDb21wb25lbnQkZ2V0Q29tcG9uZW50QXRUcmVlUGF0aCh0cmVlUGF0aCwgbmVhcmVzdCkge1xuICAgIHZhciBub2RlID0gZG9tVXRpbHMuZ2V0Tm9kZUF0VHJlZVBhdGgodGhpcy5lbCwgdHJlZVBhdGgsIG5lYXJlc3QpO1xuICAgIHJldHVybiBDb21wb25lbnQuZ2V0Q29tcG9uZW50KG5vZGUpO1xufVxuXG5cbmZ1bmN0aW9uIENvbXBvbmVudCRpbnNlcnRBdFRyZWVQYXRoKHRyZWVQYXRoLCBjb21wb25lbnQsIG5lYXJlc3QpIHtcbiAgICB2YXIgd2FzSW5zZXJ0ZWQgPSBkb21VdGlscy5pbnNlcnRBdFRyZWVQYXRoKHRoaXMuZWwsIHRyZWVQYXRoLCBjb21wb25lbnQuZWwpO1xuICAgIGlmICh3YXNJbnNlcnRlZCkgY29tcG9uZW50LnNldFNjb3BlUGFyZW50RnJvbURPTSgpO1xuICAgIHJldHVybiB3YXNJbnNlcnRlZDtcbn1cblxuXG4vKipcbiAqIEJyb2FkY2FzdCBtZXNzYWdlIHRvIGNvbXBvbmVudCBhbmQgdG8gYWxsIGl0cyBzY29wZSBjaGlsZHJlblxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gbXNnIG1lc3NhZ2UgdG8gYmUgc2VudFxuICogQHBhcmFtIHtbQW55XX0gZGF0YSBvcHRpb25hbCBtZXNzYWdlIGRhdGFcbiAqIEBwYXJhbSB7W0Z1bmN0aW9uXX0gY2FsbGJhY2sgb3B0aW9uYWwgY2FsbGJhY2tcbiAqIEBwYXJhbSB7W0Jvb2xlYW5dfSBzeW5jaHJvbm91c2x5IGlmIGl0IHNob3VsZCB1c2UgcG9zdE1lc3NhZ2VTeW5jXG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRicm9hZGNhc3QobXNnLCBkYXRhLCBjYWxsYmFjaywgc3luY2hyb25vdXNseSkge1xuICAgIHZhciBwb3N0TWV0aG9kID0gc3luY2hyb25vdXNseSA/ICdwb3N0TWVzc2FnZVN5bmMnIDogJ3Bvc3RNZXNzYWdlJztcbiAgICB0aGlzLndhbGtTY29wZVRyZWUoZnVuY3Rpb24oY29tcG9uZW50KSB7XG4gICAgICAgIGNvbXBvbmVudFtwb3N0TWV0aG9kXShtc2csIGRhdGEsIGNhbGxiYWNrKTtcbiAgICB9KTtcbn1cblxuXG4vKipcbiAqIERlc3Ryb3kgY29tcG9uZW50OiByZW1vdmVzIGNvbXBvbmVudCBmcm9tIERPTSwgcmVtb3ZlcyBpdCBmcm9tIHNjb3BlLCBkZWxldGVzIGFsbCByZWZlcmVuY2VzIHRvIERPTSBub2RlcyBhbmQgdW5zdWJzY3JpYmVzIGZyb20gYWxsIG1lc3NhZ2VzIGJvdGggY29tcG9uZW50IGFuZCBhbGwgZmFjZXRzXG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRkZXN0cm95KHF1aWV0KSB7XG4gICAgaWYgKHRoaXMuX2Rlc3Ryb3llZCkge1xuICAgICAgICBpZiAoIXF1aWV0KSBsb2dnZXIud2FybignQ29tcG9uZW50IGRlc3Ryb3k6IGNvbXBvbmVudCBpcyBhbHJlYWR5IGRlc3Ryb3llZCcpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMucmVtb3ZlKGZhbHNlLCBxdWlldCk7XG4gICAgdGhpcy5hbGxGYWNldHMoJ2Rlc3Ryb3knKTtcbiAgICB0aGlzW01FU1NFTkdFUl9QUk9QRVJUWV0uZGVzdHJveSgpO1xuICAgIGlmICh0aGlzLmVsKSB7XG4gICAgICAgIGRvbVV0aWxzLmRldGFjaENvbXBvbmVudCh0aGlzLmVsKTtcbiAgICAgICAgZG9tVXRpbHMucmVtb3ZlRWxlbWVudCh0aGlzLmVsKTtcbiAgICAgICAgZGVsZXRlIHRoaXMuZWw7XG4gICAgfVxuICAgIHRoaXMuY29tcG9uZW50SW5mby5kZXN0cm95KCk7XG4gICAgdGhpcy5fZGVzdHJveWVkID0gdHJ1ZTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiBjb21wb25lbnQgd2FzIGRlc3Ryb3llZFxuICpcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIENvbXBvbmVudCRpc0Rlc3Ryb3llZCgpIHtcbiAgICByZXR1cm4gdGhpcy5fZGVzdHJveWVkO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIGBtaWxvLkNvbXBvbmVudC5GYWNldGBcbiAqXG4gKiBUaGUgY2xhc3MgZm90IHRoZSBmYWNldCBvZiBjb21wb25lbnQuIFdoZW4gYSBjb21wb25lbnQgaXMgY3JlYXRlZCwgaXRcbiAqIGNyZWF0ZXMgYWxsIGl0cyBmYWNldHMuXG4gKlxuICogU2VlIEZhY2V0cyBzZWN0aW9uIG9uIGluZm9ybWF0aW9uIGFib3V0IGF2YWlsYWJsZSBmYWNldHMgYW5kIG9uXG4gKiBob3cgdG8gY3JlYXRlIG5ldyBmYWNldHMgY2xhc3Nlcy5cbiAqXG4gKiAtIENvbXBvbmVudCAtIGJhc2ljIGNvbXBwb25lbnQgY2xhc3NcbiAqIC0gQ29tcG9uZW50RmFjZXQgLSBiYXNpY1xuICovXG5cbnZhciBGYWNldCA9IHJlcXVpcmUoJy4uL2Fic3RyYWN0L2ZhY2V0JylcbiAgICAsIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIE1lc3NlbmdlciA9IG1pbG9Db3JlLk1lc3NlbmdlclxuICAgICwgY29tcG9uZW50VXRpbHMgPSByZXF1aXJlKCcuL2NfdXRpbHMnKVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvO1xuXG52YXIgQ29tcG9uZW50RmFjZXQgPSBfLmNyZWF0ZVN1YmNsYXNzKEZhY2V0LCAnQ29tcG9uZW50RmFjZXQnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBDb21wb25lbnRGYWNldDtcblxuXG4vKipcbiAqIHBvc3REb21QYXJlbnRcbiAqXG4gKiBJZiBmYWNldCBoYXMgRE9NIHBhcmVudCBmYWNldCAoc2VlIGBkb21QYXJlbnRgIG1ldGhvZCksIHBvc3RzIHRoZSBtZXNzYWdlIHRvIHRoaXMgZmFjZXQuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VUeXBlXG4gKiBAcGFyYW0ge09iamVjdH0gbWVzc2FnZURhdGFcbiAqL1xudmFyIHBvc3REb21QYXJlbnQgPSBfLnBhcnRpYWwoX3Bvc3RQYXJlbnQsIGRvbVBhcmVudCk7XG5cbi8qKlxuICogcG9zdFNjb3BlUGFyZW50XG4gKlxuICogSWYgZmFjZXQgaGFzIHNjb3BlIHBhcmVudCBmYWNldCAoc2VlIGBzY29wZVBhcmVudGAgbWV0aG9kKSwgcG9zdHMgdGhlIG1lc3NhZ2UgdG8gdGhpcyBmYWNldC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVR5cGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBtZXNzYWdlRGF0YVxuICovXG52YXIgcG9zdFNjb3BlUGFyZW50ID0gXy5wYXJ0aWFsKF9wb3N0UGFyZW50LCBzY29wZVBhcmVudCk7XG5cblxuXy5leHRlbmRQcm90byhDb21wb25lbnRGYWNldCwge1xuICAgIGluaXQ6IENvbXBvbmVudEZhY2V0JGluaXQsXG4gICAgc3RhcnQ6IENvbXBvbmVudEZhY2V0JHN0YXJ0LFxuICAgIGNoZWNrOiBDb21wb25lbnRGYWNldCRjaGVjayxcbiAgICBkZXN0cm95OiBDb21wb25lbnRGYWNldCRkZXN0cm95LFxuICAgIG9uQ29uZmlnTWVzc2FnZXM6IENvbXBvbmVudEZhY2V0JG9uQ29uZmlnTWVzc2FnZXMsXG4gICAgZG9tUGFyZW50OiBkb21QYXJlbnQsXG4gICAgcG9zdERvbVBhcmVudDogcG9zdERvbVBhcmVudCxcbiAgICBzY29wZVBhcmVudDogc2NvcGVQYXJlbnQsXG4gICAgcG9zdFNjb3BlUGFyZW50OiBwb3N0U2NvcGVQYXJlbnQsXG4gICAgZ2V0TWVzc2FnZVNvdXJjZTogZ2V0TWVzc2FnZVNvdXJjZSxcbiAgICBkaXNwYXRjaFNvdXJjZU1lc3NhZ2U6IGRpc3BhdGNoU291cmNlTWVzc2FnZSxcbiAgICBfY3JlYXRlTWVzc2VuZ2VyOiBfY3JlYXRlTWVzc2VuZ2VyLFxuICAgIF9zZXRNZXNzYWdlU291cmNlOiBfc2V0TWVzc2FnZVNvdXJjZSxcbiAgICBfY3JlYXRlTWVzc2FnZVNvdXJjZTogX2NyZWF0ZU1lc3NhZ2VTb3VyY2UsXG4gICAgX2NyZWF0ZU1lc3NhZ2VTb3VyY2VXaXRoQVBJOiBfY3JlYXRlTWVzc2FnZVNvdXJjZVdpdGhBUElcbn0pO1xuXG5fLmV4dGVuZChDb21wb25lbnRGYWNldCwge1xuICAgIHJlcXVpcmVzRmFjZXQ6IHJlcXVpcmVzRmFjZXRcbn0pO1xuXG5cbi8qKlxuICogRXhwb3NlIE1lc3NlbmdlciBtZXRob2RzIG9uIEZhY2V0IHByb3RvdHlwZVxuICovXG52YXIgTUVTU0VOR0VSX1BST1BFUlRZID0gJ19tZXNzZW5nZXInO1xuTWVzc2VuZ2VyLnVzZVdpdGgoQ29tcG9uZW50RmFjZXQsIE1FU1NFTkdFUl9QUk9QRVJUWSwgTWVzc2VuZ2VyLmRlZmF1bHRNZXRob2RzKTtcblxuXG4vLyBpbml0Q29tcG9uZW50RmFjZXRcbmZ1bmN0aW9uIENvbXBvbmVudEZhY2V0JGluaXQoKSB7XG4gICAgdGhpcy5fY3JlYXRlTWVzc2VuZ2VyKCk7XG59XG5cblxuLy8gc29tZSBzdWJjbGFzc2VzIChlLmcuIE1vZGVsRmFjZXQpIG92ZXJycmlkZSB0aGlzIG1ldGhvZCBhbmQgZG8gbm90IGNyZWF0ZSB0aGVpciBvd24gbWVzc2VuZ2VyXG5mdW5jdGlvbiBfY3JlYXRlTWVzc2VuZ2VyKCl7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBNRVNTRU5HRVJfUFJPUEVSVFksIG5ldyBNZXNzZW5nZXIodGhpcykpO1xufVxuXG5cbi8vIHN0YXJ0Q29tcG9uZW50RmFjZXRcbmZ1bmN0aW9uIENvbXBvbmVudEZhY2V0JHN0YXJ0KCkge1xuICAgIGlmICh0aGlzLmNvbmZpZy5tZXNzYWdlcylcbiAgICAgICAgdGhpcy5vbkNvbmZpZ01lc3NhZ2VzKHRoaXMuY29uZmlnLm1lc3NhZ2VzKTtcbn1cblxuXG5mdW5jdGlvbiBDb21wb25lbnRGYWNldCRvbkNvbmZpZ01lc3NhZ2VzKG1lc3NhZ2VTdWJzY3JpYmVycykge1xuICAgIHZhciBub3RZZXRSZWdpc3RlcmVkTWFwID0gXy5tYXBLZXlzKG1lc3NhZ2VTdWJzY3JpYmVycywgZnVuY3Rpb24oc3Vic2NyaWJlciwgbWVzc2FnZXMpIHtcbiAgICAgICAgdmFyIHN1YnNjcmliZXJUeXBlID0gdHlwZW9mIHN1YnNjcmliZXI7XG4gICAgICAgIGlmIChzdWJzY3JpYmVyVHlwZSA9PSAnZnVuY3Rpb24nKVxuICAgICAgICAgICAgcmV0dXJuIHRoaXMub24obWVzc2FnZXMsIHN1YnNjcmliZXIpO1xuXG4gICAgICAgIGlmIChzdWJzY3JpYmVyVHlwZSA9PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgdmFyIGNvbnRleHRUeXBlID0gdHlwZW9mIHN1YnNjcmliZXIuY29udGV4dDtcbiAgICAgICAgICAgIGlmIChjb250ZXh0VHlwZSA9PSAnb2JqZWN0JylcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5vbihtZXNzYWdlcywgc3Vic2NyaWJlcik7XG5cbiAgICAgICAgICAgIGlmIChjb250ZXh0VHlwZSA9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIGlmIChzdWJzY3JpYmVyLmNvbnRleHQgPT0gdGhpcy5uYW1lIHx8IHN1YnNjcmliZXIuY29udGV4dCA9PSAnZmFjZXQnKVxuICAgICAgICAgICAgICAgICAgICBzdWJzY3JpYmVyID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2NyaWJlcjogc3Vic2NyaWJlci5zdWJzY3JpYmVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dDogdGhpc1xuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGVsc2UgaWYgKHN1YnNjcmliZXIuY29udGV4dCA9PSAnb3duZXInKVxuICAgICAgICAgICAgICAgICAgICBzdWJzY3JpYmVyID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2NyaWJlcjogc3Vic2NyaWJlci5zdWJzY3JpYmVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dDogdGhpcy5vd25lclxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmtub3duIHN1YnNjcmliZXIgY29udGV4dCBpbiBjb25maWd1cmF0aW9uOiAnICsgc3Vic2NyaWJlci5jb250ZXh0KTtcblxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm9uKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmtub3duIHN1YnNjcmliZXIgY29udGV4dCB0eXBlIGluIGNvbmZpZ3VyYXRpb246ICcgKyBjb250ZXh0VHlwZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Vua25vd24gc3Vic2NyaWJlciB0eXBlIGluIGNvbmZpZ3VyYXRpb246ICcgKyBzdWJzY3JpYmVyVHlwZSk7XG4gICAgfSwgdGhpcyk7XG5cbiAgICByZXR1cm4gbm90WWV0UmVnaXN0ZXJlZE1hcDtcbn1cblxuXG4vLyBjaGVja0RlcGVuZGVuY2llc1xuZnVuY3Rpb24gQ29tcG9uZW50RmFjZXQkY2hlY2soKSB7XG4gICAgaWYgKHRoaXMucmVxdWlyZSkge1xuICAgICAgICB0aGlzLnJlcXVpcmUuZm9yRWFjaChmdW5jdGlvbihyZXFGYWNldCkge1xuICAgICAgICAgICAgaWYgKCEgdGhpcy5vd25lci5oYXNGYWNldChyZXFGYWNldCkpXG4gICAgICAgICAgICAgICAgdGhpcy5vd25lci5hZGRGYWNldChyZXFGYWNldCk7XG4gICAgICAgIH0sIHRoaXMpO1xuICAgIH1cbn1cblxuXG4vLyBkZXN0cm95cyBmYWNldFxuZnVuY3Rpb24gQ29tcG9uZW50RmFjZXQkZGVzdHJveSgpIHtcbiAgICBpZiAodGhpc1tNRVNTRU5HRVJfUFJPUEVSVFldKSB0aGlzW01FU1NFTkdFUl9QUk9QRVJUWV0uZGVzdHJveSgpO1xuICAgIHRoaXMuX2Rlc3Ryb3llZCA9IHRydWU7XG59XG5cblxuLyoqXG4gKiBkb21QYXJlbnRcbiAqXG4gKiBAcmV0dXJuIHtDb21wb25lbnRGYWNldH0gcmVmZXJlbmNlIHRvIHRoZSBmYWNldCBvZiB0aGUgc2FtZSBjbGFzcyBvZiB0aGUgY2xvc2VzdCBwYXJlbnQgRE9NIGVsZW1lbnQsIHRoYXQgaGFzIGEgY29tcG9uZW50IHdpdGggdGhlIHNhbWUgZmFjZXQgY2xhc3MgYXR0YWNoZWQgdG8gaXQuIElmIHN1Y2ggZWxlbWVudCBkb2Vzbid0IGV4aXN0IG1ldGhvZCB3aWxsIHJldHVybiB1bmRlZmluZWQuXG4gKi9cbmZ1bmN0aW9uIGRvbVBhcmVudCgpIHtcbiAgICB2YXIgcGFyZW50Q29tcG9uZW50ID0gY29tcG9uZW50VXRpbHMuZ2V0Q29udGFpbmluZ0NvbXBvbmVudCh0aGlzLm93bmVyLmVsLCBmYWxzZSwgdGhpcy5uYW1lKTtcbiAgICByZXR1cm4gcGFyZW50Q29tcG9uZW50ICYmIHBhcmVudENvbXBvbmVudFt0aGlzLm5hbWVdO1xufVxuXG5cbi8qKlxuICogc2NvcGVQYXJlbnRcbiAqXG4gKiBAcmV0dXJuIHtDb21wb25lbnRGYWNldH0gcmVmZXJlbmNlIHRvIHRoZSBmYWNldCBvZiB0aGUgc2FtZSBjbGFzcyBhcyBgdGhpc2AgZmFjZXQgb2YgdGhlIGNsb3Nlc3Qgc2NvcGUgcGFyZW50IChpLmUuLCB0aGUgY29tcG9uZW50IHRoYXQgaGFzIHRoZSBzY29wZSBvZiB0aGUgY3VycmVudCBjb21wb25lbnQgaW4gaXRzIGNvbnRhaW5lciBmYWNldCkuXG4gKi9cbmZ1bmN0aW9uIHNjb3BlUGFyZW50KCkge1xuICAgIHZhciBwYXJlbnRDb21wb25lbnQgPSB0aGlzLm93bmVyLmdldFNjb3BlUGFyZW50KHRoaXMubmFtZSk7XG4gICAgcmV0dXJuIHBhcmVudENvbXBvbmVudCAmJiBwYXJlbnRDb21wb25lbnRbdGhpcy5uYW1lXTtcbn1cblxuXG5mdW5jdGlvbiBfcG9zdFBhcmVudChnZXRQYXJlbnRNZXRob2QsIG1lc3NhZ2VUeXBlLCBtZXNzYWdlRGF0YSkge1xuICAgIHZhciBwYXJlbnRGYWNldCA9IGdldFBhcmVudE1ldGhvZC5jYWxsKHRoaXMpO1xuICAgIGlmIChwYXJlbnRGYWNldClcbiAgICAgICAgcGFyZW50RmFjZXQucG9zdE1lc3NhZ2UobWVzc2FnZVR5cGUsIG1lc3NhZ2VEYXRhKTtcbn1cblxuXG5mdW5jdGlvbiBfc2V0TWVzc2FnZVNvdXJjZShtZXNzYWdlU291cmNlKSB7XG4gICAgdGhpc1tNRVNTRU5HRVJfUFJPUEVSVFldLl9zZXRNZXNzYWdlU291cmNlKG1lc3NhZ2VTb3VyY2UpO1xufVxuXG5cbmZ1bmN0aW9uIGdldE1lc3NhZ2VTb3VyY2UoKSB7XG4gICAgcmV0dXJuIHRoaXNbTUVTU0VOR0VSX1BST1BFUlRZXS5nZXRNZXNzYWdlU291cmNlKCk7XG59XG5cblxuZnVuY3Rpb24gZGlzcGF0Y2hTb3VyY2VNZXNzYWdlKG1lc3NhZ2UsIGRhdGEpIHtcbiAgICByZXR1cm4gdGhpcy5nZXRNZXNzYWdlU291cmNlKCkuZGlzcGF0Y2hNZXNzYWdlKG1lc3NhZ2UsIGRhdGEpO1xufVxuXG5cbmZ1bmN0aW9uIF9jcmVhdGVNZXNzYWdlU291cmNlKE1lc3NhZ2VTb3VyY2VDbGFzcywgb3B0aW9ucykge1xuICAgIHZhciBtZXNzYWdlU291cmNlID0gbmV3IE1lc3NhZ2VTb3VyY2VDbGFzcyh0aGlzLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdGhpcy5vd25lciwgb3B0aW9ucyk7XG4gICAgdGhpcy5fc2V0TWVzc2FnZVNvdXJjZShtZXNzYWdlU291cmNlKVxuXG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnX21lc3NhZ2VTb3VyY2UnLCBtZXNzYWdlU291cmNlKTtcbn1cblxuXG5mdW5jdGlvbiBfY3JlYXRlTWVzc2FnZVNvdXJjZVdpdGhBUEkoTWVzc2FnZVNvdXJjZUNsYXNzLCBtZXNzZW5nZXJBUElPckNsYXNzLCBvcHRpb25zKSB7XG4gICAgdmFyIG1lc3NhZ2VTb3VyY2UgPSBuZXcgTWVzc2FnZVNvdXJjZUNsYXNzKHRoaXMsIHVuZGVmaW5lZCwgbWVzc2VuZ2VyQVBJT3JDbGFzcywgdGhpcy5vd25lciwgb3B0aW9ucyk7XG4gICAgdGhpcy5fc2V0TWVzc2FnZVNvdXJjZShtZXNzYWdlU291cmNlKVxuXG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnX21lc3NhZ2VTb3VyY2UnLCBtZXNzYWdlU291cmNlKTtcbn1cblxuXG5mdW5jdGlvbiByZXF1aXJlc0ZhY2V0KGZhY2V0TmFtZSkge1xuICAgIC8vICd0aGlzJyByZWZlcnMgdG8gdGhlIEZhY2V0IENsYXNzXG4gICAgdmFyIGZhY2V0UmVxdWlyZSA9IHRoaXMucHJvdG90eXBlLnJlcXVpcmU7XG5cbiAgICByZXR1cm4gZmFjZXRSZXF1aXJlICYmIChmYWNldFJlcXVpcmUuaW5kZXhPZihfLmZpcnN0VXBwZXJDYXNlKGZhY2V0TmFtZSkpID49IDBcbiAgICAgICAgICAgICAgICAgICAgICAgIHx8IGZhY2V0UmVxdWlyZS5pbmRleE9mKF8uZmlyc3RMb3dlckNhc2UoZmFjZXROYW1lKSkgPj0gMCk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIENvbXBvbmVudEZhY2V0ID0gcmVxdWlyZSgnLi4vY19mYWNldCcpXG4gICAgLCBtaWxvQmluZGVyID0gcmVxdWlyZSgnLi4vLi4vYmluZGVyJylcbiAgICAsIFNjb3BlID0gcmVxdWlyZSgnLi4vc2NvcGUnKVxuICAgICwgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvXG4gICAgLCBsb2dnZXIgPSBtaWxvQ29yZS51dGlsLmxvZ2dlclxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NmX3JlZ2lzdHJ5JylcbiAgICAsIGRvbVV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9kb20nKTtcblxuXG4vKipcbiAqIGBtaWxvLnJlZ2lzdHJ5LmZhY2V0cy5nZXQoJ0NvbnRhaW5lcicpYFxuICogQSBzcGVjaWFsIGNvbXBvbmVudCBmYWNldCB0aGF0IG1ha2VzIGNvbXBvbmVudCBjcmVhdGUgaXRzIG93biBpbm5lciBzY29wZS5cbiAqIFdoZW4gW21pbG8uYmluZGVyXSguLi8uLi9iaW5kZXIuanMuaHRtbCkgYmluZHMgRE9NIHRyZWUgYW5kIGNyZWF0ZXMgY29tcG9uZW50cywgaWYgY29tcG9uZW50cyBhcmUgaW5zaWRlIGNvbXBvbmVudCBXSVRIIENvbnRhaW5lciBmYWNldCwgdGhleSBhcmUgcHV0IG9uIHRoZSBgc2NvcGVgIG9mIGl0IChjb21wb25lbnQuY29udGFpbmVyLnNjb3BlIC0gc2VlIFtTY29wZV0oLi4vc2NvcGUuanMuaHRtbCkpLCBvdGhlcndpc2UgdGhleSBhcmUgcHV0IG9uIHRoZSBzYW1lIHNjb3BlIGV2ZW4gdGhvdWdoIHRoZXkgbWF5IGJlIGRlZXBlciBpbiBET00gdHJlZS5cbiAqIEl0IGFsbG93cyBjcmVhdGluZyBuYW1lc3BhY2VzIGF2b2lkaW5nIGNvbXBvbmVudHMgbmFtZXMgY29uZmxpY3RzLCBhdCB0aGUgc2FtZSB0aW1lIGNyZWF0aW5nIG1vcmUgc2hhbGxvdyBjb21wb25lbnRzIHRyZWUgdGhhbiB0aGUgRE9NIHRyZWUuXG4gKiBUbyBjcmVhdGUgY29tcG9uZW50cyBmb3IgZWxlbWVudHMgaW5zaWRlIHRoZSBjdXJyZW50IGNvbXBvbmVudCB1c2U6XG4gKiBgYGBcbiAqIGNvbXBvbmVudC5jb250YWluZXIuYmluZGVyKCk7XG4gKiBgYGBcbiAqIFNlZSBbbWlsby5iaW5kZXJdKC4uLy4uL2JpbmRlci5qcy5odG1sKVxuICovXG52YXIgQ29udGFpbmVyID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ0NvbnRhaW5lcicpO1xuXG5cbi8qKlxuICogIyMjI0NvbnRhaW5lciBmYWNldCBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2JpbmRlcl0oI0NvbnRhaW5lciRiaW5kZXIpIC0gY3JlYXRlIGNvbXBvbmVudHMgZnJvbSBET00gaW5zaWRlIHRoZSBjdXJyZW50IG9uZVxuICovXG5fLmV4dGVuZFByb3RvKENvbnRhaW5lciwge1xuICAgIHN0YXJ0OiBDb250YWluZXIkc3RhcnQsXG4gICAgcGF0aDogQ29udGFpbmVyJHBhdGgsXG4gICAgZ2V0U3RhdGU6IENvbnRhaW5lciRnZXRTdGF0ZSxcbiAgICBzZXRTdGF0ZTogQ29udGFpbmVyJHNldFN0YXRlLFxuICAgIGJpbmRlcjogQ29udGFpbmVyJGJpbmRlcixcbiAgICBkZXN0cm95OiBDb250YWluZXIkZGVzdHJveSxcbiAgICB1bndyYXA6IENvbnRhaW5lciR1bndyYXAsXG5cbiAgICBhcHBlbmQ6IENvbnRhaW5lciRhcHBlbmQsXG4gICAgaW5zZXJ0QmVmb3JlOiBDb250YWluZXIkaW5zZXJ0QmVmb3JlLFxuICAgIHJlbW92ZTogQ29udGFpbmVyJHJlbW92ZVxufSk7XG5cbmZhY2V0c1JlZ2lzdHJ5LmFkZChDb250YWluZXIpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENvbnRhaW5lcjtcblxuXG4vKipcbiAqIENvbnRhaW5lciBpbnN0YW5jZSBtZXRob2QuXG4gKiBTY2FucyBET00sIGNyZWF0ZXMgY29tcG9uZW50cyBhbmQgYWRkcyB0byBzY29wZSBjaGlsZHJlbiBvZiBjb21wb25lbnQgZWxlbWVudC5cbiAqL1xuZnVuY3Rpb24gQ29udGFpbmVyJGJpbmRlcigpIHtcbiAgICByZXR1cm4gbWlsb0JpbmRlcih0aGlzLm93bmVyLmVsLCB0aGlzLnNjb3BlLCBmYWxzZSk7XG59XG5cblxuLyoqXG4gKiBDb250YWluZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogU2V0dXAgZW1wdHkgc2NvcGUgb2JqZWN0IG9uIHN0YXJ0XG4gKi9cbmZ1bmN0aW9uIENvbnRhaW5lciRzdGFydCgpIHtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuc3RhcnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB0aGlzLnNjb3BlID0gbmV3IFNjb3BlKHRoaXMub3duZXIuZWwsIHRoaXMpO1xufVxuXG5cbnZhciBhbGxvd2VkTmFtZVBhdHRlcm4gPSAvXltBLVphLXpdW0EtWmEtejAtOVxcX1xcJF0qJC87XG4vKipcbiAqIENvbnRhaW5lciBpbnN0YW5jZSBtZXRob2QuXG4gKiBTYWZlbHkgdHJhdmVyc2VzIGNvbXBvbmVudCBzY29wZVxuICogUmV0dXJucyBjb21wb25lbnQgaW4gc2NvcGUgZm9yIGEgZ2l2ZW4gcGF0aFxuICogSWYgcGF0aCBpcyBpbnZhbGlkIHRoZSBtZXRob2Qgd2lsbCB0aHJvdywgaWYgdGhlcmUgaXMgbm8gY29tcG9uZW50IGF0IGEgZ2l2ZW4gcGF0aCBvciBzb21lIG9mIHRoZSBjb21wb25lbnRzIGFsb25nIHRoZSBwYXRoIGRvZXMgbm90IGhhdmUgQ29udGFpbmVyIGZhY2V0IHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gdW5kZWZpbmVkLCBcbiAqIFxuICogQHBhcmFtIHtTdHJpbmd9IHBhdGggcGF0aCBvZiBjaGlsZCBjb21wb25lbnQgaW4gc2NvcGUsIGVhY2ggbmFtZSBzaG91bGQgYmUgcHJlZml4ZWQgd2l0aCAnLicsIGUuZy46ICcuY2hpbGQuc3ViY2hpbGQnXG4gKiBAcmV0dXJuIHtDb21wb25lbnR9XG4gKi9cbmZ1bmN0aW9uIENvbnRhaW5lciRwYXRoKHBhdGgpIHtcbiAgICBwYXRoID0gcGF0aC5zcGxpdCgnLicpO1xuICAgIHZhciBsZW4gPSBwYXRoLmxlbmd0aDtcbiAgICBpZiAocGF0aFswXSB8fCBsZW4gPCAyKSB0aHJvd0ludmFsaWRQYXRoKCk7XG4gICAgdmFyIGNvbXAgPSB0aGlzLm93bmVyO1xuICAgIGZvciAodmFyIGkgPSAxOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgdmFyIG5hbWUgPSBwYXRoW2ldO1xuICAgICAgICBpZiAoIWFsbG93ZWROYW1lUGF0dGVybi50ZXN0KG5hbWUpKSB0aHJvd0ludmFsaWRQYXRoKCk7XG4gICAgICAgIGlmICghY29tcC5jb250YWluZXIpIHJldHVybjtcbiAgICAgICAgY29tcCA9IGNvbXAuY29udGFpbmVyLnNjb3BlW25hbWVdO1xuICAgICAgICBpZiAoIWNvbXApIHJldHVybjtcbiAgICB9XG4gICAgcmV0dXJuIGNvbXA7XG5cbiAgICBmdW5jdGlvbiB0aHJvd0ludmFsaWRQYXRoKCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3BhdGggJyArIHBhdGggKyAnIGlzIGludmFsaWQnKTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBDb250YWluZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBDYWxsZWQgYnkgYENvbXBvbmVudC5wcm90b3R5cGUuZ2V0U3RhdGVgIHRvIGdldCBmYWNldCdzIHN0YXRlXG4gKiBSZXR1cm5zIHRoZSBzdGF0ZSBvZiBjb21wb25lbnRzIGluIHRoZSBzY29wZVxuICpcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gZGVlcENvcHkgdHJ1ZSBieSBkZWZhdWx0XG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIENvbnRhaW5lciRnZXRTdGF0ZShkZWVwQ29weSkge1xuICAgIHZhciBzdGF0ZSA9IHsgc2NvcGU6IHt9IH07XG4gICAgaWYgKGRlZXBDb3B5ICE9PSBmYWxzZSlcbiAgICAgICAgdGhpcy5zY29wZS5fZWFjaChmdW5jdGlvbihjb21wb25lbnQsIGNvbXBOYW1lKSB7XG4gICAgICAgICAgICBzdGF0ZS5zY29wZVtjb21wTmFtZV0gPSBjb21wb25lbnQuX2dldFN0YXRlKCk7XG4gICAgICAgIH0pO1xuICAgIHJldHVybiBzdGF0ZTtcbn1cblxuXG4vKipcbiAqIENvbnRhaW5lciBpbnN0YW5jZSBtZXRob2RcbiAqIENhbGxlZCBieSBgQ29tcG9uZW50LnByb3RvdHlwZS5zZXRTdGF0ZWAgdG8gc2V0IGZhY2V0J3Mgc3RhdGVcbiAqIFNldHMgdGhlIHN0YXRlIG9mIGNvbXBvbmVudHMgaW4gdGhlIHNjb3BlXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgZGF0YSB0byBzZXQgb24gZmFjZXQncyBtb2RlbFxuICovXG5mdW5jdGlvbiBDb250YWluZXIkc2V0U3RhdGUoc3RhdGUpIHtcbiAgICBfLmVhY2hLZXkoc3RhdGUuc2NvcGUsIGZ1bmN0aW9uKGNvbXBEYXRhLCBjb21wTmFtZSkge1xuICAgICAgICB2YXIgY29tcG9uZW50ID0gdGhpcy5zY29wZVtjb21wTmFtZV07XG4gICAgICAgIGlmIChjb21wb25lbnQpXG4gICAgICAgICAgICBjb21wb25lbnQuc2V0U3RhdGUoY29tcERhdGEpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBsb2dnZXIud2FybignY29tcG9uZW50IFwiJyArIGNvbXBOYW1lICsgJ1wiIGRvZXMgbm90IGV4aXN0IG9uIHNjb3BlJyk7XG4gICAgfSwgdGhpcyk7XG59XG5cbmZ1bmN0aW9uIENvbnRhaW5lciRkZXN0cm95KCkge1xuICAgIHRoaXMuc2NvcGUuX2VhY2goZnVuY3Rpb24oY29tcG9uZW50KSB7XG4gICAgICAgIGNvbXBvbmVudC5kZXN0cm95KCk7XG4gICAgfSk7XG4gICAgdGhpcy5zY29wZS5fZGV0YWNoRWxlbWVudCgpO1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuLyoqXG4gKiBDb250YWluZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBNb3ZlcyBhbGwgb2YgdGhlIGNvbnRlbnRzIG9mIHRoZSBvd25lciBpbnRvIHRoZSBwYXJlbnQgc2NvcGVcbiAqIFxuICogQHBhcmFtIHtCb29sZWFufSByZW5hbWVDaGlsZHJlbiBwYXNzIGZhbHNlIHRvIG5vdCByZW5hbWUgc2NvcGUgY2hpbGRyZW4gKGRlZmF1bHQgaXMgdHJ1ZSlcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gZGVzdHJveSBJZiBub3QgZmFsc2UsIHRoZSBjb21wb25lbnQgd2lsbCBiZSBkZXN0cm95ZWQgYXQgdGhlIGVuZCAoZGVmYXVsdCBpcyB0cnVlKS5cbiAqL1xuZnVuY3Rpb24gQ29udGFpbmVyJHVud3JhcChyZW5hbWVDaGlsZHJlbiwgZGVzdHJveSkge1xuICAgIGRvbVV0aWxzLnVud3JhcEVsZW1lbnQodGhpcy5vd25lci5lbCk7XG4gICAgdGhpcy5zY29wZSAmJiB0aGlzLnNjb3BlLl9lYWNoKGZ1bmN0aW9uIChjaGlsZCkge1xuICAgICAgICBjaGlsZC5yZW1vdmUoKTtcbiAgICAgICAgaWYgKHJlbmFtZUNoaWxkcmVuICE9PSBmYWxzZSkgY2hpbGQucmVuYW1lKHVuZGVmaW5lZCwgZmFsc2UpO1xuICAgICAgICB0aGlzLm93bmVyLnNjb3BlICYmIHRoaXMub3duZXIuc2NvcGUuX2FkZChjaGlsZCk7XG4gICAgfSwgdGhpcyk7XG4gICAgaWYgKGRlc3Ryb3kgIT09IGZhbHNlKSB0aGlzLm93bmVyLmRlc3Ryb3koKTtcbn1cblxuXG4vKipcbiAqIENvbnRhaW5lciBpbnN0YW5jZSBtZXRob2RcbiAqIEFwcGVuZCBjb21wb25lbnQgdG8gRE9NIGFuZCB0byBzY29wZVxuICogQHBhcmFtIHtDb21wb25lbnR9IGNvbXAgY29tcG9uZW50IHRoYXQgd2lsbCBiZSBhcHBlbmRlZFxuICovXG5mdW5jdGlvbiBDb250YWluZXIkYXBwZW5kKGNvbXApIHtcbiAgICB0aGlzLnNjb3BlLl9hZGQoY29tcCk7XG4gICAgdGhpcy5vd25lci5lbC5hcHBlbmRDaGlsZChjb21wLmVsKTtcbn1cblxuXG4vKipcbiAqIENvbnRhaW5lciBpbnN0YW5jZSBtZXRob2RcbiAqIEluc2VydCBjb21wb25lbnQgdG8gRE9NIGFuZCB0byBzY29wZSBiZWZvcmUgYW5vdGhlciBjb21wb25lbnRcbiAqIEBwYXJhbSB7Q29tcG9uZW50fSBjb21wIGNvbXBvbmVudCB0aGF0IHdpbGwgYmUgaW5zZXJ0ZWRcbiAqIEBwYXJhbSB7Q29tcG9uZW50fSBzaWJsaW5nIGNvbXBvbmVudCBiZWZvcmUgd2hpY2ggY29tcG9uZW50IHdpbGwgYmUgYXBwZW5kZWRcbiAqL1xuZnVuY3Rpb24gQ29udGFpbmVyJGluc2VydEJlZm9yZShjb21wLCBzaWJsaW5nKSB7XG4gICAgdGhpcy5zY29wZS5fYWRkKGNvbXApO1xuICAgIHRoaXMuZWwuaW5zZXJ0QmVmb3JlKGNvbXAuZWwsIHNpYmxpbmcgJiYgc2libGluZy5lbCk7XG59XG5cbmZ1bmN0aW9uIENvbnRhaW5lciRyZW1vdmUoY29tcCkge1xuICAgIHRoaXMuc2NvcGUuX3JlbW92ZShjb21wKTtcbiAgICB0aGlzLm93bmVyLmVsLnJlbW92ZUNoaWxkKGNvbXAuZWwpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgTWl4aW4gPSBtaWxvQ29yZS5jbGFzc2VzLk1peGluXG4gICAgLCBDb21wb25lbnRGYWNldCA9IHJlcXVpcmUoJy4uL2NfZmFjZXQnKVxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NmX3JlZ2lzdHJ5JylcblxuICAgICwgTWVzc2VuZ2VyID0gbWlsb0NvcmUuTWVzc2VuZ2VyXG4gICAgLCBET01FdmVudHNTb3VyY2UgPSByZXF1aXJlKCcuLi9tc2dfc3JjL2RvbV9ldmVudHMnKVxuICAgICwgRGF0YU1zZ0FQSSA9IHJlcXVpcmUoJy4uL21zZ19hcGkvZGF0YScpXG4gICAgLCBnZXRFbGVtZW50RGF0YUFjY2VzcyA9IHJlcXVpcmUoJy4uL21zZ19hcGkvZGVfZGF0YScpXG4gICAgLCBNb2RlbCA9IG1pbG9Db3JlLk1vZGVsXG4gICAgLCBwYXRoVXRpbHMgPSBNb2RlbC5fdXRpbHMucGF0aFxuICAgICwgbW9kZWxVdGlscyA9IE1vZGVsLl91dGlscy5tb2RlbFxuICAgICwgY2hhbmdlRGF0YUhhbmRsZXIgPSBNb2RlbC5fdXRpbHMuY2hhbmdlRGF0YUhhbmRsZXJcbiAgICAsIGdldFRyYW5zYWN0aW9uRmxhZyA9IGNoYW5nZURhdGFIYW5kbGVyLmdldFRyYW5zYWN0aW9uRmxhZ1xuICAgICwgc2V0VHJhbnNhY3Rpb25GbGFnID0gY2hhbmdlRGF0YUhhbmRsZXIuc2V0VHJhbnNhY3Rpb25GbGFnXG4gICAgLCBwb3N0VHJhbnNhY3Rpb25GaW5pc2hlZCA9IGNoYW5nZURhdGFIYW5kbGVyLnBvc3RUcmFuc2FjdGlvbkZpbmlzaGVkXG5cbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgbG9nZ2VyID0gbWlsb0NvcmUudXRpbC5sb2dnZXI7XG5cblxuLyoqXG4gKiBgbWlsby5yZWdpc3RyeS5mYWNldHMuZ2V0KCdEYXRhJylgXG4gKiBGYWNldCB0byBnaXZlIGFjY2VzcyB0byBET00gZGF0YVxuICovXG52YXIgRGF0YSA9IF8uY3JlYXRlU3ViY2xhc3MoQ29tcG9uZW50RmFjZXQsICdEYXRhJyk7XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZHNcbiAqXG4gKiAtIFtzdGFydF0oI0RhdGEkc3RhcnQpIC0gc3RhcnQgRGF0YSBmYWNldFxuICogLSBbZ2V0XSgjRGF0YSRnZXQpIC0gZ2V0IERPTSBkYXRhIGZyb20gRE9NIHRyZWVcbiAqIC0gW3NldF0oI0RhdGEkc2V0KSAtIHNldCBET00gZGF0YSB0byBET00gdHJlZVxuICogLSBbcGF0aF0oI0RhdGEkcGF0aCkgLSBnZXQgcmVmZXJlbmNlIHRvIERhdGEgZmFjZXQgYnkgcGF0aFxuICovXG5fLmV4dGVuZFByb3RvKERhdGEsIHtcbiAgICBzdGFydDogRGF0YSRzdGFydCxcbiAgICBnZXRTdGF0ZTogRGF0YSRnZXRTdGF0ZSxcbiAgICBzZXRTdGF0ZTogRGF0YSRzZXRTdGF0ZSxcblxuICAgIGdldDogRGF0YSRnZXQsXG4gICAgc2V0OiBEYXRhJHNldCxcbiAgICBkZWw6IERhdGEkZGVsLFxuICAgIHNwbGljZTogRGF0YSRzcGxpY2UsXG4gICAgbGVuOiBEYXRhJGxlbixcbiAgICBwYXRoOiBEYXRhJHBhdGgsXG4gICAgZ2V0UGF0aDogRGF0YSRnZXRQYXRoLFxuICAgIGdldEtleTogRGF0YSRnZXRLZXksXG5cbiAgICBfZ2V0OiBEYXRhJF9nZXQsXG4gICAgX3NldDogRGF0YSRfc2V0LFxuICAgIF9kZWw6IERhdGEkX2RlbCxcbiAgICBfc3BsaWNlOiBEYXRhJF9zcGxpY2UsXG4gICAgX2xlbjogRGF0YSRfbGVuLFxuXG4gICAgX3NldFNjYWxhclZhbHVlOiBEYXRhJF9zZXRTY2FsYXJWYWx1ZSxcbiAgICBfZ2V0U2NhbGFyVmFsdWU6IERhdGEkX2dldFNjYWxhclZhbHVlLFxuICAgIF9idWJibGVVcERhdGFDaGFuZ2U6IERhdGEkX2J1YmJsZVVwRGF0YUNoYW5nZSxcbiAgICBfcXVldWVEYXRhQ2hhbmdlOiBEYXRhJF9xdWV1ZURhdGFDaGFuZ2UsXG4gICAgX3Bvc3REYXRhQ2hhbmdlczogRGF0YSRfcG9zdERhdGFDaGFuZ2VzLFxuICAgIF9wcmVwYXJlTWVzc2FnZVNvdXJjZTogX3ByZXBhcmVNZXNzYWdlU291cmNlXG59KTtcblxuZmFjZXRzUmVnaXN0cnkuYWRkKERhdGEpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IERhdGE7XG5cblxuLyoqXG4gKiBNb2RlbFBhdGggbWV0aG9kcyBhZGRlZCB0byBEYXRhIHByb3RvdHlwZVxuICovXG5bJ3B1c2gnLCAncG9wJywgJ3Vuc2hpZnQnLCAnc2hpZnQnXS5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICB2YXIgbWV0aG9kID0gTW9kZWwuUGF0aC5wcm90b3R5cGVbbWV0aG9kTmFtZV07XG4gICAgXy5kZWZpbmVQcm9wZXJ0eShEYXRhLnByb3RvdHlwZSwgbWV0aG9kTmFtZSwgbWV0aG9kKTtcbn0pO1xuXG5cblxuLy8gdGhlc2UgbWV0aG9kcyB3aWxsIGJlIHdyYXBwZWQgdG8gc3VwcG9ydCBcIipcIiBwYXR0ZXJuIHN1YnNjcmlwdGlvbnNcbnZhciBwcm94eURhdGFTb3VyY2VNZXRob2RzID0ge1xuICAgICAgICAvLyB2YWx1ZTogJ3ZhbHVlJyxcbiAgICAgICAgdHJpZ2dlcjogJ3RyaWdnZXInXG4gICAgfTtcblxuXG4vKipcbiAqIERhdGEgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTdGFydHMgRGF0YSBmYWNldFxuICogQ2FsbGVkIGJ5IGNvbXBvbmVudCBhZnRlciBjb21wb25lbnQgaXMgaW5pdGlhbGl6ZWQuXG4gKi9cbmZ1bmN0aW9uIERhdGEkc3RhcnQoKSB7XG4gICAgLy8gY2hhbmdlIG1lc3NlbmdlciBtZXRob2RzIHRvIHdvcmsgd2l0aCBcIipcIiBzdWJzY3JpcHRpb25zIChsaWtlIE1vZGVsIGNsYXNzKVxuICAgIHBhdGhVdGlscy53cmFwTWVzc2VuZ2VyTWV0aG9kcy5jYWxsKHRoaXMpO1xuXG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLnN0YXJ0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAvLyBnZXQvc2V0IG1ldGhvZHMgdG8gc2V0IGRhdGEgb2YgZWxlbWVudFxuICAgIHRoaXMuZWxEYXRhID0gZ2V0RWxlbWVudERhdGFBY2Nlc3ModGhpcy5vd25lci5lbCk7XG5cbiAgICB0aGlzLl9kYXRhQ2hhbmdlc1F1ZXVlID0gW107XG5cbiAgICB0aGlzLl9wcmVwYXJlTWVzc2FnZVNvdXJjZSgpO1xuXG4gICAgLy8gc3RvcmUgZmFjZXQgZGF0YSBwYXRoXG4gICAgdGhpcy5fcGF0aCA9ICcuJyArIHRoaXMub3duZXIubmFtZTtcblxuICAgIC8vIGN1cnJlbnQgdmFsdWVcbiAgICB0aGlzLl92YWx1ZSA9IHRoaXMuZ2V0KCk7XG5cbiAgICAvLyBwcmVwYXJlIGludGVybmFsIGFuZCBleHRlcm5hbCBtZXNzZW5nZXJzXG4gICAgLy8gdGhpcy5fcHJlcGFyZU1lc3NlbmdlcnMoKTtcblxuICAgIC8vIHN1YnNjcmliZSB0byBET00gZXZlbnQgYW5kIGFjY2Vzc29ycycgbWVzc2FnZXNcbiAgICB0aGlzLm9uU3luYygnJywgb25Pd25EYXRhQ2hhbmdlKTtcblxuICAgIC8vIG1lc3NhZ2UgdG8gbWFyayB0aGUgZW5kIG9mIGJhdGNoIG9uIHRoZSBjdXJyZW50IGxldmVsXG4gICAgdGhpcy5vblN5bmMoJ2RhdGFjaGFuZ2VzZmluaXNoZWQnLCBvbkRhdGFDaGFuZ2VzRmluaXNoZWQpO1xuXG4gICAgLy8gY2hhbmdlcyBpbiBzY29wZSBjaGlsZHJlbiB3aXRoIERhdGEgZmFjZXRcbiAgICB0aGlzLm9uU3luYygnY2hpbGRkYXRhJywgb25DaGlsZERhdGEpO1xuXG4gICAgLy8gdG8gZW5hYmxlIHJlYWN0aXZlIGNvbm5lY3Rpb25zXG4gICAgdGhpcy5vblN5bmMoJ2NoYW5nZWRhdGEnLCBjaGFuZ2VEYXRhSGFuZGxlcik7XG59XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogQ3JlYXRlIGFuZCBjb25uZWN0IGludGVybmFsIGFuZCBleHRlcm5hbCBtZXNzZW5nZXJzIG9mIERhdGEgZmFjZXQuXG4gKiBFeHRlcm5hbCBtZXNzZW5nZXIncyBtZXRob2RzIGFyZSBwcm94aWVkIG9uIHRoZSBEYXRhIGZhY2V0IGFuZCB0aGV5IGFsbG93cyBcIipcIiBzdWJzY3JpcHRpb25zLlxuICovXG4vLyBmdW5jdGlvbiBfcHJlcGFyZU1lc3NlbmdlcnMoKSB7XG4gICAgLy8gRGF0YSBmYWNldCB3aWxsIHBvc3QgYWxsIGl0cyBjaGFuZ2VzIG9uIGludGVybmFsIG1lc3NlbmdlclxuICAgIC8vIHZhciBpbnRlcm5hbE1lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXIodGhpcyk7XG5cbiAgICAvLyBtZXNzYWdlIHNvdXJjZSB0byBjb25uZWN0IGludGVybmFsIG1lc3NlbmdlciB0byBleHRlcm5hbFxuICAgIC8vIHZhciBpbnRlcm5hbE1lc3NlbmdlclNvdXJjZSA9IG5ldyBNZXNzZW5nZXJNZXNzYWdlU291cmNlKHRoaXMsIHVuZGVmaW5lZCwgbmV3IE1vZGVsTXNnQVBJLCBpbnRlcm5hbE1lc3Nlbmdlcik7XG5cbiAgICAvLyBleHRlcm5hbCBtZXNzZW5nZXIgdG8gd2hpY2ggYWxsIG1vZGVsIHVzZXJzIHdpbGwgc3Vic2NyaWJlLFxuICAgIC8vIHRoYXQgd2lsbCBhbGxvdyBcIipcIiBzdWJzY3JpcHRpb25zIGFuZCBzdXBwb3J0IFwiY2hhbmdlZGF0YVwiIG1lc3NhZ2UgYXBpLlxuICAgIC8vIHZhciBleHRlcm5hbE1lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXIodGhpcywgTWVzc2VuZ2VyLmRlZmF1bHRNZXRob2RzLCBpbnRlcm5hbE1lc3NlbmdlclNvdXJjZSk7XG5cbi8vICAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuLy8gICAgICAgICBfbWVzc2VuZ2VyOiBleHRlcm5hbE1lc3Nlbmdlcixcbi8vICAgICAgICAgX2ludGVybmFsTWVzc2VuZ2VyOiBpbnRlcm5hbE1lc3NlbmdlclxuLy8gICAgIH0pO1xuLy8gfVxuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIEluaXRpYWxpemVzIERPTUV2ZW50c1NvdXJjZSBhbmQgY29ubmVjdHMgaXQgdG8gRGF0YSBmYWNldCBtZXNzZW5nZXJcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBfcHJlcGFyZU1lc3NhZ2VTb3VyY2UoKSB7XG4gICAgdmFyIGRhdGFBUEkgPSBuZXcgRGF0YU1zZ0FQSSh0aGlzLm93bmVyKVxuICAgICAgICAsIGRhdGFFdmVudHNTb3VyY2UgPSBuZXcgRE9NRXZlbnRzU291cmNlKHRoaXMsIHByb3h5RGF0YVNvdXJjZU1ldGhvZHMsIGRhdGFBUEksIHRoaXMub3duZXIpO1xuICAgIHRoaXMuX3NldE1lc3NhZ2VTb3VyY2UoZGF0YUV2ZW50c1NvdXJjZSk7XG5cbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdfZGF0YUV2ZW50c1NvdXJjZScsIGRhdGFFdmVudHNTb3VyY2UpO1xuXG4gICAgLy8gbWFrZSB2YWx1ZSBtZXRob2Qgb2YgRGF0YU1zZ0FQSSBhdmFpbGFibGUgb24gRGF0YSBmYWNldFxuICAgIC8vIHRoaXMgaXMgYSBwcml2YXRlIG1ldGhvZCwgZ2V0KCkgc2hvdWxkIGJlIHVzZWQgdG8gZ2V0IGRhdGEuXG4gICAgTWl4aW4ucHJvdG90eXBlLl9jcmVhdGVQcm94eU1ldGhvZC5jYWxsKGRhdGFBUEksICd2YWx1ZScsICd2YWx1ZScsIHRoaXMpO1xufVxuXG5cbi8qKlxuICogU3Vic2NyaWJlciB0byBkYXRhIGNoYW5nZSBldmVudFxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge1N0cmluZ30gbXNnVHlwZSBpbiB0aGlzIGluc3RhbmNlIHdpbGwgYmUgJydcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIGRhdGEgY2hhbmdlIGluZm9ybWF0aW9uXG4gKi9cbmZ1bmN0aW9uIG9uT3duRGF0YUNoYW5nZShtc2dUeXBlLCBkYXRhKSB7XG4gICAgdGhpcy5fYnViYmxlVXBEYXRhQ2hhbmdlKGRhdGEpO1xuICAgIHRoaXMuX3F1ZXVlRGF0YUNoYW5nZShkYXRhKTtcbiAgICBpZiAoZGF0YS5wYXRoID09PSAnJykge1xuICAgICAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGdldFRyYW5zYWN0aW9uRmxhZyhkYXRhKTtcbiAgICAgICAgdGhpcy5wb3N0TWVzc2FnZSgnZGF0YWNoYW5nZXNmaW5pc2hlZCcsIHsgdHJhbnNhY3Rpb246IGluVHJhbnNhY3Rpb24gfSk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFNlbmRzIGRhdGEgYG1lc3NhZ2VgIHRvIERPTSBwYXJlbnRcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtPYmplY3R9IG1zZ0RhdGEgZGF0YSBjaGFuZ2UgbWVzc2FnZVxuICovXG5mdW5jdGlvbiBEYXRhJF9idWJibGVVcERhdGFDaGFuZ2UobXNnRGF0YSkge1xuICAgIHZhciBwYXJlbnREYXRhID0gdGhpcy5zY29wZVBhcmVudCgpO1xuXG4gICAgaWYgKHBhcmVudERhdGEpIHtcbiAgICAgICAgdmFyIHBhcmVudE1zZyA9IF8uY2xvbmUobXNnRGF0YSk7XG4gICAgICAgIHBhcmVudE1zZy5wYXRoID0gKHRoaXMuX3BhdGggfHwgKCcuJyArIHRoaXMub3duZXIubmFtZSkpICArIHBhcmVudE1zZy5wYXRoO1xuICAgICAgICBwYXJlbnREYXRhLnBvc3RNZXNzYWdlKCdjaGlsZGRhdGEnLCBwYXJlbnRNc2cgfHwgbXNnRGF0YSk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFF1ZXVlcyBkYXRhIG1lc3NhZ2VzIHRvIGJlIGRpc3BhdGNoZWQgdG8gY29ubmVjdG9yXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBjaGFuZ2UgZGF0YSBjaGFuZ2UgZGVzY3JpcHRpb25cbiAqL1xuZnVuY3Rpb24gRGF0YSRfcXVldWVEYXRhQ2hhbmdlKGNoYW5nZSkge1xuICAgIHRoaXMuX2RhdGFDaGFuZ2VzUXVldWUucHVzaChjaGFuZ2UpO1xufVxuXG5cbi8qKlxuICogU3Vic2NyaWJlciB0byBkYXRhY2hhbmdlc2ZpbmlzaGVkIGV2ZW50LlxuICogQ2FsbHMgdGhlIG1ldGhvZCB0byBwb3N0IGNoYW5nZXMgYmF0Y2ggYW5kIGJ1YmJsZXMgdXAgdGhlIG1lc3NhZ2VcbiAqXG4gKiBAcGFyYW0gIHtbdHlwZV19IG1zZyAgW2Rlc2NyaXB0aW9uXVxuICogQHBhcmFtICB7W3R5cGVdfSBkYXRhIFtkZXNjcmlwdGlvbl1cbiAqL1xuZnVuY3Rpb24gb25EYXRhQ2hhbmdlc0ZpbmlzaGVkKG1zZywgZGF0YSkge1xuICAgIHRoaXMuX3Bvc3REYXRhQ2hhbmdlcyhkYXRhLmluVHJhbnNhY3Rpb24pO1xuICAgIHZhciBwYXJlbnREYXRhID0gdGhpcy5zY29wZVBhcmVudCgpO1xuICAgIGlmIChwYXJlbnREYXRhKSBwYXJlbnREYXRhLnBvc3RNZXNzYWdlKCdkYXRhY2hhbmdlc2ZpbmlzaGVkJywgZGF0YSk7XG59XG5cblxuLyoqXG4gKiBEaXNwYXRjaGVzIGFsbCBjaGFuZ2VzIGNvbGxlY3RlZCBpbiB0aGUgYmF0Y2hcbiAqIFVzZWQgZm9yIGRhdGEgcHJvcGFnYXRpb24gLSBjb25uZWN0b3Igc3Vic2NyaWJlcyB0byB0aGlzIG1lc3NhZ2VcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBEYXRhJF9wb3N0RGF0YUNoYW5nZXMoaW5UcmFuc2FjdGlvbikge1xuICAgIHZhciBxdWV1ZSA9IHRoaXMuX2RhdGFDaGFuZ2VzUXVldWUucmV2ZXJzZSgpO1xuICAgIHRoaXMucG9zdE1lc3NhZ2VTeW5jKCdkYXRhY2hhbmdlcycsIHtcbiAgICAgICAgY2hhbmdlczogcXVldWUsXG4gICAgICAgIHRyYW5zYWN0aW9uOiBpblRyYW5zYWN0aW9uXG4gICAgfSk7XG4gICAgdGhpcy5fZGF0YUNoYW5nZXNRdWV1ZSA9IFtdOyAvLyBpdCBjYW4ndCBiZSAubGVuZ3RoID0gMCwgYXMgdGhlIGFjdHVhbCBhcnJheSBtYXkgc3RpbGwgYmUgdXNlZFxufVxuXG5cbi8qKlxuICogU3Vic2NyaWJlciB0byBkYXRhIGNoYW5nZSBldmVudCBpbiBjaGlsZCBEYXRhIGZhY2V0XG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBtc2dUeXBlXG4gKiBAcGFyYW0ge09iZWpjdH0gZGF0YSBkYXRhIGNoYW5nZSBpbmZvcm1hdGlvblxuICovXG5mdW5jdGlvbiBvbkNoaWxkRGF0YShtc2dUeXBlLCBkYXRhKSB7XG4gICAgdGhpcy5wb3N0TWVzc2FnZShkYXRhLnBhdGgsIGRhdGEpO1xuICAgIHRoaXMuX2J1YmJsZVVwRGF0YUNoYW5nZShkYXRhKTtcbiAgICB0aGlzLl9xdWV1ZURhdGFDaGFuZ2UoZGF0YSk7XG59XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogU2V0cyBkYXRhIGluIERPTSBoaWVyYXJjaHkgcmVjdXJzaXZlbHkuXG4gKiBSZXR1cm5zIHRoZSBvYmplY3Qgd2l0aCB0aGUgZGF0YSBhY3R1YWxseSBzZXQgKGNhbiBiZSBkaWZmZXJlbnQsIGlmIGNvbXBvbmVudHMgbWF0Y2hpbmcgc29tZSBwcm9wZXJ0aWVzIGFyZSBtaXNzaW5nKS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdHxTdHJpbmd8TnVtYmVyfSB2YWx1ZSB2YWx1ZSB0byBiZSBzZXQuIElmIHRoZSB2YWx1ZSBpZiBzY2FsYXIsIGl0IHdpbGwgYmUgc2V0IG9uIGNvbXBvbmVudCdzIGVsZW1lbnQsIGlmIHRoZSB2YWx1ZSBpcyBvYmplY3QgLSBvbiBET00gdHJlZSBpbnNpZGUgY29tcG9uZW50XG4gKiBAcmV0dXJuIHtPYmplY3R8U3RyaW5nfE51bWJlcn1cbiAqL1xuZnVuY3Rpb24gRGF0YSRzZXQodmFsdWUpIHtcbiAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGdldFRyYW5zYWN0aW9uRmxhZyhEYXRhJHNldCk7XG5cbiAgICB2YXIgY29tcG9uZW50U2V0dGVyID0gdGhpcy5jb25maWcuc2V0O1xuICAgIGlmICh0eXBlb2YgY29tcG9uZW50U2V0dGVyID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IGNvbXBvbmVudFNldHRlci5jYWxsKHRoaXMub3duZXIsIHZhbHVlKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBzZXRUcmFuc2FjdGlvbkZsYWcodGhpcy5fc2V0LCBpblRyYW5zYWN0aW9uKTtcblxuICAgIHZhciBvbGRWYWx1ZSA9IHRoaXMuX3ZhbHVlXG4gICAgICAgICwgbmV3VmFsdWUgPSB0aGlzLl9zZXQodmFsdWUpO1xuXG4gICAgLy8gdGhpcyBtZXNzYWdlIHRyaWdnZXJzIG9uT3duRGF0YUNoYW5nZSwgYXMgd2VsbCBhcyBhY3R1YWxsIERPTSBjaGFuZ2VcbiAgICAvLyBzbyB0aGUgcGFyZW50IGdldHMgbm90aWZpZWRcbiAgICB2YXIgbXNnID0geyBwYXRoOiAnJywgdHlwZTogJ2NoYW5nZWQnLFxuICAgICAgICAgICAgICAgIG5ld1ZhbHVlOiBuZXdWYWx1ZSwgb2xkVmFsdWU6IG9sZFZhbHVlIH07XG4gICAgc2V0VHJhbnNhY3Rpb25GbGFnKG1zZywgaW5UcmFuc2FjdGlvbik7XG4gICAgdGhpcy5wb3N0TWVzc2FnZSgnJywgbXNnKTtcblxuICAgIHJldHVybiBuZXdWYWx1ZTtcbn1cblxuXG5mdW5jdGlvbiBEYXRhJF9zZXQodmFsdWUpIHtcbiAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGdldFRyYW5zYWN0aW9uRmxhZyhEYXRhJF9zZXQpO1xuXG4gICAgdmFyIHZhbHVlU2V0O1xuICAgIGlmICh2YWx1ZSAhPSBudWxsICYmIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0Jykge1xuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgIHZhbHVlU2V0ID0gW107XG5cbiAgICAgICAgICAgIHZhciBsaXN0RmFjZXQgPSB0aGlzLm93bmVyLmxpc3Q7XG4gICAgICAgICAgICBpZiAobGlzdEZhY2V0KXtcbiAgICAgICAgICAgICAgICB2YXIgbGlzdExlbmd0aCA9IGxpc3RGYWNldC5jb3VudCgpXG4gICAgICAgICAgICAgICAgICAgICwgbmV3SXRlbXNDb3VudCA9IHZhbHVlLmxlbmd0aCAtIGxpc3RMZW5ndGg7XG4gICAgICAgICAgICAgICAgaWYgKG5ld0l0ZW1zQ291bnQgPj0gMykge1xuICAgICAgICAgICAgICAgICAgICBsaXN0RmFjZXQuX2FkZEl0ZW1zKG5ld0l0ZW1zQ291bnQpO1xuICAgICAgICAgICAgICAgICAgICBsaXN0RmFjZXQuX3VwZGF0ZURhdGFQYXRocyhsaXN0TGVuZ3RoLCBsaXN0RmFjZXQuY291bnQoKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFsdWUuZm9yRWFjaChmdW5jdGlvbihjaGlsZFZhbHVlLCBpbmRleCkge1xuICAgICAgICAgICAgICAgICAgICBzZXRDaGlsZERhdGEuY2FsbCh0aGlzLCB2YWx1ZVNldCwgY2hpbGRWYWx1ZSwgaW5kZXgsICdbJCRdJyk7XG4gICAgICAgICAgICAgICAgfSwgdGhpcyk7XG5cbiAgICAgICAgICAgICAgICB2YXIgbGlzdENvdW50ID0gbGlzdEZhY2V0LmNvdW50KClcbiAgICAgICAgICAgICAgICAgICAgLCByZW1vdmVDb3VudCA9IGxpc3RDb3VudCAtIHZhbHVlLmxlbmd0aDtcblxuICAgICAgICAgICAgICAgIHdoaWxlIChyZW1vdmVDb3VudC0tID4gMClcbiAgICAgICAgICAgICAgICAgICAgbGlzdEZhY2V0Ll9yZW1vdmVJdGVtKHZhbHVlLmxlbmd0aCk7XG4gICAgICAgICAgICB9IGVsc2VcbiAgICAgICAgICAgICAgICBsb2dnZXIud2FybignRGF0YTogc2V0dGluZyBhcnJheSBkYXRhIHdpdGhvdXQgTGlzdCBmYWNldCcpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdmFsdWVTZXQgPSB7fTtcbiAgICAgICAgICAgIF8uZWFjaEtleSh2YWx1ZSwgZnVuY3Rpb24oY2hpbGRWYWx1ZSwga2V5KSB7XG4gICAgICAgICAgICAgICAgc2V0Q2hpbGREYXRhLmNhbGwodGhpcywgdmFsdWVTZXQsIGNoaWxkVmFsdWUsIGtleSwgJy4kJCcpO1xuICAgICAgICAgICAgfSwgdGhpcyk7XG4gICAgICAgIH1cbiAgICB9IGVsc2VcbiAgICAgICAgdmFsdWVTZXQgPSB0aGlzLl9zZXRTY2FsYXJWYWx1ZSh2YWx1ZSk7XG5cbiAgICB0aGlzLl92YWx1ZSA9IHZhbHVlU2V0O1xuXG4gICAgcmV0dXJuIHZhbHVlU2V0O1xuXG5cbiAgICBmdW5jdGlvbiBzZXRDaGlsZERhdGEodmFsdWVTZXQsIGNoaWxkVmFsdWUsIGtleSwgcGF0aFN5bnRheCkge1xuICAgICAgICB2YXIgY2hpbGRQYXRoID0gcGF0aFN5bnRheC5yZXBsYWNlKCckJCcsIGtleSk7XG4gICAgICAgIHZhciBjaGlsZERhdGFGYWNldCA9IHRoaXMucGF0aChjaGlsZFBhdGgsIHR5cGVvZiBjaGlsZFZhbHVlICE9ICd1bmRlZmluZWQnKTtcbiAgICAgICAgaWYgKGNoaWxkRGF0YUZhY2V0KSB7XG4gICAgICAgICAgICBzZXRUcmFuc2FjdGlvbkZsYWcoY2hpbGREYXRhRmFjZXQuc2V0LCBpblRyYW5zYWN0aW9uKTtcbiAgICAgICAgICAgIHZhbHVlU2V0W2tleV0gPSBjaGlsZERhdGFGYWNldC5zZXQoY2hpbGRWYWx1ZSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogRGVsZXRlcyBjb21wb25lbnQgZnJvbSB2aWV3IGFuZCBzY29wZSwgb25seSBpbiBjYXNlIGl0IGhhcyBJdGVtIGZhY2V0IG9uIGl0XG4gKlxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfSB2YWx1ZSB2YWx1ZSB0byBzZXQgdG8gRE9NIGVsZW1lbnRcbiAqL1xuZnVuY3Rpb24gRGF0YSRkZWwoKSB7XG4gICAgdmFyIGluVHJhbnNhY3Rpb24gPSBnZXRUcmFuc2FjdGlvbkZsYWcoRGF0YSRkZWwpO1xuXG4gICAgdmFyIGNvbXBvbmVudERlbGV0ZSA9IHRoaXMuY29uZmlnLmRlbDtcbiAgICBpZiAodHlwZW9mIGNvbXBvbmVudERlbGV0ZSA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSBjb21wb25lbnREZWxldGUuY2FsbCh0aGlzLm93bmVyKTtcbiAgICAgICAgcG9zdFRyYW5zYWN0aW9uRmluaXNoZWQuY2FsbCh0aGlzLCBpblRyYW5zYWN0aW9uKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICB2YXIgb2xkVmFsdWUgPSB0aGlzLl92YWx1ZTtcblxuICAgIHNldFRyYW5zYWN0aW9uRmxhZyh0aGlzLl9kZWwsIGluVHJhbnNhY3Rpb24pO1xuICAgIHRoaXMuX2RlbCgpO1xuXG4gICAgLy8gdGhpcyBtZXNzYWdlIHRyaWdnZXJzIG9uT3duRGF0YUNoYW5nZSwgYXMgd2VsbCBhcyBhY3R1YWxsIERPTSBjaGFuZ2VcbiAgICAvLyBzbyB0aGUgcGFyZW50IGdldHMgbm90aWZpZWRcbiAgICB2YXIgbXNnID0geyBwYXRoOiAnJywgdHlwZTogJ2RlbGV0ZWQnLCBvbGRWYWx1ZTogb2xkVmFsdWUgfTtcbiAgICBzZXRUcmFuc2FjdGlvbkZsYWcobXNnLCBpblRyYW5zYWN0aW9uKTtcbiAgICB0aGlzLnBvc3RNZXNzYWdlKCcnLCBtc2cpO1xufVxuXG5cbmZ1bmN0aW9uIERhdGEkX2RlbCgpIHtcbiAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGdldFRyYW5zYWN0aW9uRmxhZyhEYXRhJF9kZWwpO1xuICAgIHNldFRyYW5zYWN0aW9uRmxhZyh0aGlzLl9zZXQsIGluVHJhbnNhY3Rpb24pO1xuICAgIHRoaXMuX3NldCgpO1xufVxuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFNldHMgc2NhbGFyIHZhbHVlIHRvIERPTSBlbGVtZW50XG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcn0gdmFsdWUgdmFsdWUgdG8gc2V0IHRvIERPTSBlbGVtZW50XG4gKi9cbmZ1bmN0aW9uIERhdGEkX3NldFNjYWxhclZhbHVlKHZhbHVlKSB7XG4gICAgcmV0dXJuIHRoaXMuZWxEYXRhLnNldCh0aGlzLm93bmVyLmVsLCB2YWx1ZSk7XG59XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogR2V0IHN0cnVjdHVyZWQgZGF0YSBmcm9tIERPTSBoaWVyYXJjaHkgcmVjdXJzaXZlbHlcbiAqIFJldHVybnMgRE9NIGRhdGFcbiAqXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGRlZXBHZXQgdHJ1ZSBieSBkZWZhdWx0XG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIERhdGEkZ2V0KGRlZXBHZXQpIHtcbiAgICB2YXIgY29tcG9uZW50R2V0dGVyID0gdGhpcy5jb25maWcuZ2V0O1xuICAgIGlmICh0eXBlb2YgY29tcG9uZW50R2V0dGVyID09ICdmdW5jdGlvbicpXG4gICAgICAgIHJldHVybiBjb21wb25lbnRHZXR0ZXIuY2FsbCh0aGlzLm93bmVyLCBkZWVwR2V0KTtcblxuICAgIHJldHVybiB0aGlzLl9nZXQoZGVlcEdldCk7XG59XG5cbmZ1bmN0aW9uIERhdGEkX2dldChkZWVwR2V0KSB7XG4gICAgaWYgKGRlZXBHZXQgPT09IGZhbHNlKSAvLyBhIGhhY2sgdG8gZW5hYmxlIGdldHRpbmcgc2hhbGxvdyBzdGF0ZVxuICAgICAgICByZXR1cm47XG5cbiAgICB2YXIgY29tcCA9IHRoaXMub3duZXJcbiAgICAgICAgLCBzY29wZURhdGE7XG5cbiAgICBpZiAoY29tcC5saXN0KSB7XG4gICAgICAgIHNjb3BlRGF0YSA9IFtdO1xuICAgICAgICBjb21wLmxpc3QuZWFjaChmdW5jdGlvbihsaXN0SXRlbSwgaW5kZXgpIHtcbiAgICAgICAgICAgIHNjb3BlRGF0YVtpbmRleF0gPSBsaXN0SXRlbS5kYXRhLmdldCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoY29tcC5jb250YWluZXIpXG4gICAgICAgICAgICBjb21wLmNvbnRhaW5lci5zY29wZS5fZWFjaChmdW5jdGlvbihzY29wZUl0ZW0sIG5hbWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoISBjb21wLmxpc3QuY29udGFpbnMoc2NvcGVJdGVtKSAmJiBzY29wZUl0ZW0uZGF0YSlcbiAgICAgICAgICAgICAgICAgICAgc2NvcGVEYXRhW25hbWVdID0gc2NvcGVJdGVtLmRhdGEuZ2V0KCk7XG4gICAgICAgICAgICB9KTtcbiAgICB9IGVsc2UgaWYgKGNvbXAuY29udGFpbmVyKSB7XG4gICAgICAgIHNjb3BlRGF0YSA9IHt9O1xuICAgICAgICBjb21wLmNvbnRhaW5lci5zY29wZS5fZWFjaChmdW5jdGlvbihzY29wZUl0ZW0sIG5hbWUpIHtcbiAgICAgICAgICAgIGlmIChzY29wZUl0ZW0uZGF0YSlcbiAgICAgICAgICAgICAgICBzY29wZURhdGFbbmFtZV0gPSBzY29wZUl0ZW0uZGF0YS5nZXQoKTtcbiAgICAgICAgfSk7XG4gICAgfSBlbHNlXG4gICAgICAgIHNjb3BlRGF0YSA9IHRoaXMuX2dldFNjYWxhclZhbHVlKCk7XG5cbiAgICB0aGlzLl92YWx1ZSA9IHNjb3BlRGF0YTtcblxuICAgIHJldHVybiBzY29wZURhdGE7XG59XG5cblxuLyoqXG4gKiBEYXRhIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogR2V0cyBzY2FsYXIgZGF0YSBmcm9tIERPTSBlbGVtZW50XG4gKlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gRGF0YSRfZ2V0U2NhbGFyVmFsdWUoKSB7XG4gICAgcmV0dXJuIHRoaXMuZWxEYXRhLmdldCh0aGlzLm93bmVyLmVsKTtcbn1cblxuXG4vKipcbiAqIERhdGEgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTcGxpY2VzIExpc3QgaXRlbXMuIFJlcXVpcmVzIExpc3QgZmFjZXQgdG8gYmUgcHJlc2VudCBvbiBjb21wb25lbnQuIFdvcmtzIGluIHRoZSBzYW1lIHdheSBhcyBhcnJheSBzcGxpY2UuXG4gKiBSZXR1cm5zIGRhdGEgcmV0cmlldmVkIGZyb20gcmVtb3ZlZCBpdGVtc1xuICpcbiAqIEBwYXJhbSB7SW50ZWdlcn0gc3BsaWNlSW5kZXggaW5kZXggdG8gZGVsZXRlL2luc2VydCBhdFxuICogQHBhcmFtIHtJbnRlZ2VyfSBzcGxpY2VIb3dNYW55IG51bWJlciBvZiBpdGVtcyB0byBkZWxldGVcbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIG9wdGlvbmFsIGl0ZW1zIHRvIGluc2VydFxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIERhdGEkc3BsaWNlKHNwbGljZUluZGV4LCBzcGxpY2VIb3dNYW55KSB7IC8vLCAuLi4gYXJndW1lbnRzXG4gICAgdmFyIGluVHJhbnNhY3Rpb24gPSBnZXRUcmFuc2FjdGlvbkZsYWcoRGF0YSRzcGxpY2UpO1xuICAgIHZhciByZXN1bHQ7XG5cbiAgICB2YXIgY29tcG9uZW50U3BsaWNlID0gdGhpcy5jb25maWcuc3BsaWNlO1xuICAgIGlmICh0eXBlb2YgY29tcG9uZW50U3BsaWNlID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgcmVzdWx0ID0gY29tcG9uZW50U3BsaWNlLmFwcGx5KHRoaXMub3duZXIsIGFyZ3VtZW50cyk7XG4gICAgICAgIHBvc3RUcmFuc2FjdGlvbkZpbmlzaGVkLmNhbGwodGhpcywgaW5UcmFuc2FjdGlvbik7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgc2V0VHJhbnNhY3Rpb25GbGFnKHRoaXMuX3NwbGljZSwgaW5UcmFuc2FjdGlvbik7XG4gICAgcmVzdWx0ID0gdGhpcy5fc3BsaWNlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICBpZiAoIXJlc3VsdCkgcmV0dXJuO1xuXG4gICAgdmFyIG1zZyA9IHsgcGF0aDogJycsIHR5cGU6ICdzcGxpY2UnLFxuICAgICAgICAgICAgICAgIGluZGV4OiByZXN1bHQuc3BsaWNlSW5kZXgsXG4gICAgICAgICAgICAgICAgcmVtb3ZlZDogcmVzdWx0LnJlbW92ZWQsXG4gICAgICAgICAgICAgICAgYWRkZWRDb3VudDogcmVzdWx0LmFkZGVkQ291bnQsXG4gICAgICAgICAgICAgICAgbmV3VmFsdWU6IHRoaXMuX3ZhbHVlIH07XG4gICAgc2V0VHJhbnNhY3Rpb25GbGFnKG1zZywgaW5UcmFuc2FjdGlvbik7XG4gICAgdGhpcy5wb3N0TWVzc2FnZSgnJywgbXNnKTtcblxuICAgIHJldHVybiByZXN1bHQucmVtb3ZlZDtcbn1cblxuXG5mdW5jdGlvbiBEYXRhJF9zcGxpY2Uoc3BsaWNlSW5kZXgsIHNwbGljZUhvd01hbnkpIHsgLy8sIC4uLiBhcmd1bWVudHNcbiAgICB2YXIgaW5UcmFuc2FjdGlvbiA9IGdldFRyYW5zYWN0aW9uRmxhZyhEYXRhJF9zcGxpY2UpO1xuXG4gICAgdmFyIGxpc3RGYWNldCA9IHRoaXMub3duZXIubGlzdDtcbiAgICBpZiAoISBsaXN0RmFjZXQpXG4gICAgICAgIHJldHVybiBsb2dnZXIud2FybignRGF0YTogY2Fubm90IHVzZSBzcGxpY2UgbWV0aG9kIHdpdGhvdXQgTGlzdCBmYWNldCcpO1xuXG4gICAgdmFyIHJlbW92ZWQgPSBbXTtcblxuICAgIHZhciBsaXN0TGVuZ3RoID0gbGlzdEZhY2V0LmNvdW50KCk7XG4gICAgYXJndW1lbnRzWzBdID0gc3BsaWNlSW5kZXggPVxuICAgICAgICBtb2RlbFV0aWxzLm5vcm1hbGl6ZVNwbGljZUluZGV4KHNwbGljZUluZGV4LCBsaXN0TGVuZ3RoKTtcblxuICAgIGlmIChzcGxpY2VIb3dNYW55ID4gMCAmJiBsaXN0TGVuZ3RoID4gMCkge1xuICAgICAgICBmb3IgKHZhciBpID0gc3BsaWNlSW5kZXg7IGkgPCBzcGxpY2VJbmRleCArIHNwbGljZUhvd01hbnk7IGkrKykge1xuICAgICAgICAgICAgdmFyIGl0ZW0gPSBsaXN0RmFjZXQuaXRlbShzcGxpY2VJbmRleCk7XG4gICAgICAgICAgICBpZiAoaXRlbSkge1xuICAgICAgICAgICAgICAgIHZhciBpdGVtRGF0YSA9IGl0ZW0uZGF0YS5nZXQoKTtcbiAgICAgICAgICAgICAgICBsaXN0RmFjZXQuX3JlbW92ZUl0ZW0oc3BsaWNlSW5kZXgpO1xuICAgICAgICAgICAgfSBlbHNlXG4gICAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ0RhdGE6IG5vIGl0ZW0gZm9yIGluZGV4JywgaSk7XG5cbiAgICAgICAgICAgIHJlbW92ZWQucHVzaChpdGVtRGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICBsaXN0RmFjZXQuX3VwZGF0ZURhdGFQYXRocyhzcGxpY2VJbmRleCwgbGlzdEZhY2V0LmNvdW50KCkpO1xuICAgIH1cblxuICAgIHZhciBhZGRlZCA9IFtdO1xuXG4gICAgdmFyIGFyZ3NMZW4gPSBhcmd1bWVudHMubGVuZ3RoXG4gICAgICAgICwgYWRkSXRlbXMgPSBhcmdzTGVuID4gMlxuICAgICAgICAsIGFkZGVkQ291bnQgPSBhcmdzTGVuIC0gMjtcbiAgICBpZiAoYWRkSXRlbXMpIHtcbiAgICAgICAgbGlzdEZhY2V0Ll9hZGRJdGVtcyhhZGRlZENvdW50LCBzcGxpY2VJbmRleCk7XG4gICAgICAgIGZvciAodmFyIGkgPSAyLCBqID0gc3BsaWNlSW5kZXg7IGkgPCBhcmdzTGVuOyBpKyssIGorKykge1xuICAgICAgICAgICAgdmFyIGl0ZW0gPSBsaXN0RmFjZXQuaXRlbShqKTtcbiAgICAgICAgICAgIGlmIChpdGVtKSB7XG4gICAgICAgICAgICAgICAgc2V0VHJhbnNhY3Rpb25GbGFnKGl0ZW0uZGF0YS5zZXQsIGluVHJhbnNhY3Rpb24pO1xuICAgICAgICAgICAgICAgIHZhciBpdGVtRGF0YSA9IGl0ZW0uZGF0YS5zZXQoYXJndW1lbnRzW2ldKTtcbiAgICAgICAgICAgIH0gZWxzZVxuICAgICAgICAgICAgICAgIGxvZ2dlci53YXJuKCdEYXRhOiBubyBpdGVtIGZvciBpbmRleCcsIGopO1xuXG4gICAgICAgICAgICBhZGRlZC5wdXNoKGl0ZW1EYXRhKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGNoYW5nZSBwYXRocyBvZiBpdGVtcyB0aGF0IHdlcmUgYWRkZWQgYW5kIGl0ZW1zIGFmdGVyIHRoZW1cbiAgICAgICAgbGlzdEZhY2V0Ll91cGRhdGVEYXRhUGF0aHMoc3BsaWNlSW5kZXgsIGxpc3RGYWNldC5jb3VudCgpKTtcbiAgICB9XG5cbiAgICAvLyBpZiAoQXJyYXkuaXNBcnJheSh0aGlzLl92YWx1ZSkpIHtcbiAgICAvLyAgICAgXy5wcmVwZW5kQXJyYXkoYWRkZWQsIFtzcGxpY2VJbmRleCwgc3BsaWNlSG93TWFueV0pO1xuICAgIC8vICAgICBBcnJheS5wcm90b3R5cGUuc3BsaWNlLmFwcGx5KHRoaXMuX3ZhbHVlLCBhZGRlZCk7XG4gICAgLy8gfSBlbHNlXG4gICAgICAgIHRoaXMuX3ZhbHVlID0gdGhpcy5nZXQoKTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIHNwbGljZUluZGV4OiBzcGxpY2VJbmRleCxcbiAgICAgICAgcmVtb3ZlZDogcmVtb3ZlZCxcbiAgICAgICAgYWRkZWRDb3VudDogYWRkSXRlbXMgPyBhZGRlZENvdW50IDogMFxuICAgIH07XG59XG5cblxuZnVuY3Rpb24gRGF0YSRsZW4oKSB7XG4gICAgdmFyIGNvbXBvbmVudExlbiA9IHRoaXMuY29uZmlnLmxlbjtcbiAgICBpZiAodHlwZW9mIGNvbXBvbmVudExlbiA9PSAnZnVuY3Rpb24nKVxuICAgICAgICByZXR1cm4gY29tcG9uZW50TGVuLmNhbGwodGhpcy5vd25lcik7XG4gICAgZWxzZVxuICAgICAgICByZXR1cm4gdGhpcy5fbGVuKCk7XG59XG5cblxuZnVuY3Rpb24gRGF0YSRfbGVuKCkge1xuICAgIGlmICh0aGlzLm93bmVyLmxpc3QpIHJldHVybiB0aGlzLm93bmVyLmxpc3QuY291bnQoKTtcbiAgICBlbHNlIGxvZ2dlci5lcnJvcignRGF0YTogbGVuIGNhbGxlZCB3aXRob3V0IGxpc3QgZmFjZXQnKTtcbn1cblxuXG4vKipcbiAqIERhdGEgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIGRhdGEgZmFjZXQgb2YgYSBjaGlsZCBjb21wb25lbnQgKGJ5IHNjb3BlcykgY29ycmVzcG9uZGluZyB0byB0aGUgcGF0aFxuICogQHBhcmFtIHtTdHJpbmd9IGFjY2Vzc1BhdGggZGF0YSBhY2Nlc3MgcGF0aFxuICovXG5mdW5jdGlvbiBEYXRhJHBhdGgoYWNjZXNzUGF0aCwgY3JlYXRlSXRlbSkge1xuICAgIC8vIGNyZWF0ZUl0ZW0gPSB0cnVlOyAvLyB0aGlzIGhhY2sgc2VlbXMgdG8gYmUgbm8gbG9uZ2VyIG5lZWRlZC4uLlxuXG4gICAgaWYgKCEgYWNjZXNzUGF0aClcbiAgICAgICAgcmV0dXJuIHRoaXM7XG5cbiAgICB2YXIgcGFyc2VkUGF0aCA9IHBhdGhVdGlscy5wYXJzZUFjY2Vzc1BhdGgoYWNjZXNzUGF0aCk7XG4gICAgdmFyIGN1cnJlbnRDb21wb25lbnQgPSB0aGlzLm93bmVyO1xuXG4gICAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IHBhcnNlZFBhdGgubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgdmFyIHBhdGhOb2RlID0gcGFyc2VkUGF0aFtpXVxuICAgICAgICAgICAgLCBub2RlS2V5ID0gcGF0aFV0aWxzLmdldFBhdGhOb2RlS2V5KHBhdGhOb2RlKTtcbiAgICAgICAgaWYgKHBhdGhOb2RlLnN5bnRheCA9PSAnYXJyYXknICYmIGN1cnJlbnRDb21wb25lbnQubGlzdCkge1xuICAgICAgICAgICAgdmFyIGl0ZW1Db21wb25lbnQgPSBjdXJyZW50Q29tcG9uZW50Lmxpc3QuaXRlbShub2RlS2V5KTtcbiAgICAgICAgICAgIGlmICghIGl0ZW1Db21wb25lbnQgJiYgY3JlYXRlSXRlbSAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICBpdGVtQ29tcG9uZW50ID0gY3VycmVudENvbXBvbmVudC5saXN0Ll9hZGRJdGVtKG5vZGVLZXkpO1xuICAgICAgICAgICAgICAgIGl0ZW1Db21wb25lbnQuZGF0YS5fcGF0aCA9IHBhdGhOb2RlLnByb3BlcnR5O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY3VycmVudENvbXBvbmVudCA9IGl0ZW1Db21wb25lbnQ7XG4gICAgICAgIH0gZWxzZSBpZiAoY3VycmVudENvbXBvbmVudC5jb250YWluZXIpXG4gICAgICAgICAgICBjdXJyZW50Q29tcG9uZW50ID0gY3VycmVudENvbXBvbmVudC5jb250YWluZXIuc2NvcGVbbm9kZUtleV07XG5cbiAgICAgICAgdmFyIGN1cnJlbnREYXRhRmFjZXQgPSBjdXJyZW50Q29tcG9uZW50ICYmIGN1cnJlbnRDb21wb25lbnQuZGF0YTtcbiAgICAgICAgaWYgKCEgY3VycmVudERhdGFGYWNldClcbiAgICAgICAgICAgIGJyZWFrO1xuICAgIH1cblxuICAgIHJldHVybiBjdXJyZW50RGF0YUZhY2V0O1xufVxuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgcGF0aCB0byBhY2Nlc3MgdGhpcyBkYXRhIGZhY2V0IGZyb20gcGFyZW50ICh1c2luZyBwYXRoIG1ldGhvZClcbiAqXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIERhdGEkZ2V0UGF0aCgpIHtcbiAgICByZXR1cm4gdGhpcy5fcGF0aDtcbn1cblxuXG4vKipcbiAqIERhdGEgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIGtleSB0byBhY2Nlc3MgdGhlIHZhbHVlIHJlbGF0ZWQgdG8gdGhpcyBkYXRhIGZhY2V0IG9uIHRoZSB2YWx1ZSByZWxhdGVkIHRvIHBhcmVudCBkYXRhIGZhY2V0LlxuICogSWYgY29tcG9uZW50IGhhcyBMaXN0IGZhY2V0LCByZXR1cm5zIGluZGV4XG4gKlxuICogQHJldHVybiB7U3RyaW5nfEludGVnZXJ9XG4gKi9cbmZ1bmN0aW9uIERhdGEkZ2V0S2V5KCkge1xuICAgIHZhciBwYXRoID0gdGhpcy5fcGF0aDtcbiAgICByZXR1cm4gcGF0aFswXSA9PSAnWydcbiAgICAgICAgICAgID8gK3BhdGguc2xpY2UoMSwgLTEpIC8vIHJlbW92ZSBcIltcIiBhbmQgXCJdXCJcbiAgICAgICAgICAgIDogcGF0aC5zbGljZSgxKSAvLyByZW1vdmUgbGVhZGluZyBcIi5cIlxufVxuXG5cbi8qKlxuICogRGF0YSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIENhbGxlZCBieSBgQ29tcG9uZW50LnByb3RvdHlwZS5nZXRTdGF0ZWAgdG8gZ2V0IGZhY2V0J3Mgc3RhdGVcbiAqIFJldHVybnMgRE9NIGRhdGFcbiAqXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGRlZXBTdGF0ZSwgdHJ1ZSBieSBkZWZhdWx0XG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIERhdGEkZ2V0U3RhdGUoZGVlcFN0YXRlKSB7XG4gICAgcmV0dXJuIHsgc3RhdGU6IHRoaXMuZ2V0KGRlZXBTdGF0ZSkgfTtcbn1cblxuXG4vKipcbiAqIERhdGEgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBDYWxsZWQgYnkgYENvbXBvbmVudC5wcm90b3R5cGUuc2V0U3RhdGVgIHRvIHNldCBmYWNldCdzIHN0YXRlXG4gKiBTaW1wbHkgc2V0cyBtb2RlbCBkYXRhXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHN0YXRlIGRhdGEgdG8gc2V0IG9uIGZhY2V0J3MgbW9kZWxcbiAqL1xuZnVuY3Rpb24gRGF0YSRzZXRTdGF0ZShzdGF0ZSkge1xuICAgIHJldHVybiB0aGlzLnNldChzdGF0ZS5zdGF0ZSk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIENvbXBvbmVudEZhY2V0ID0gcmVxdWlyZSgnLi4vY19mYWNldCcpXG4gICAgLCBmYWNldHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY2ZfcmVnaXN0cnknKSBcbiAgICAsIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgY2hlY2sgPSBtaWxvQ29yZS51dGlsLmNoZWNrXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBkb1QgPSBtaWxvQ29yZS51dGlsLmRvVFxuICAgICwgYmluZGVyID0gcmVxdWlyZSgnLi4vLi4vYmluZGVyJylcbiAgICAsIEJpbmRBdHRyaWJ1dGUgPSByZXF1aXJlKCcuLi8uLi9hdHRyaWJ1dGVzL2FfYmluZCcpXG4gICAgLCBkb21VdGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvZG9tJylcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4uLy4uL2NvbmZpZycpO1xuXG5cbi8qKlxuICogYG1pbG8ucmVnaXN0cnkuZmFjZXRzLmdldCgnRG9tJylgXG4gKiBGYWNldCB3aXRoIGNvbXBvbmVudCByZWxhdGVkIGRvbSB1dGlsc1xuICovXG52YXIgRG9tID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ0RvbScpO1xuXG5fLmV4dGVuZChEb20sIHtcbiAgICBjcmVhdGVFbGVtZW50OiBEb20kJGNyZWF0ZUVsZW1lbnRcbn0pO1xuXG5cbi8qKlxuICogRmFjZXQgY2xhc3MgbWV0aG9kXG4gKiBDcmVhdGVzIGFuIGVsZW1lbnQgZnJvbSBhIHBhc3NlZCBjb25maWd1YXRpb24gb2JqZWN0XG4gKiBcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgd2l0aCB0aGUgcHJvcGVydGllcyBgZG9tQ29uZmlnYCwgYGNvbnRlbnRgLCBgdGVtcGxhdGVgXG4gKiBAcmV0dXJuIHtFbGVtZW50fSBhbiBodG1sIGVsZW1lbnQgXG4gKi9cbmZ1bmN0aW9uIERvbSQkY3JlYXRlRWxlbWVudChjb25maWcpIHtcbiAgICB2YXIgZG9tQ29uZmlnID0gY29uZmlnLmRvbUNvbmZpZyB8fCB7fVxuICAgICAgICAsIHRhZ05hbWUgPSBkb21Db25maWcudGFnTmFtZSB8fCAnZGl2J1xuICAgICAgICAsIG5ld0VsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCh0YWdOYW1lKVxuICAgICAgICAsIGNvbnRlbnQgPSBjb25maWcuY29udGVudFxuICAgICAgICAsIHRlbXBsYXRlID0gY29uZmlnLnRlbXBsYXRlO1xuXG4gICAgLy8gVE9ETyBpdCB3aWxsIGJlIGNhbGxlZCBhZ2FpbiB3aGVuL2lmIGNvbXBvbmVudCBpcyBpbnN0YW50aWF0ZWRcbiAgICAvLyBTaG91bGQgYmUgc29tZXByb3BlcnR5IG9uIGVsZW1lbnQgdG8gaW5kaWNhdGUgaXQncyBiZWVuIGNhbGxlZD9cbiAgICBfYXBwbHlDb25maWdUb0VsZW1lbnQobmV3RWwsIGRvbUNvbmZpZyk7XG5cbiAgICBpZiAodHlwZW9mIGNvbnRlbnQgPT0gJ3N0cmluZycpIHtcbiAgICAgICAgaWYgKHRlbXBsYXRlKVxuICAgICAgICAgICAgbmV3RWwuaW5uZXJIVE1MID0gZG9ULnRlbXBsYXRlKHRlbXBsYXRlKSh7Y29udGVudDogY29udGVudH0pO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBuZXdFbC5pbm5lckhUTUwgPSBjb250ZW50O1xuICAgIH1cbiAgICByZXR1cm4gbmV3RWw7XG59XG5cblxuZnVuY3Rpb24gX2FwcGx5Q29uZmlnVG9FbGVtZW50KGVsLCBjb25maWcpIHtcbiAgICB2YXIgY3NzQ2xhc3NlcyA9IGNvbmZpZyAmJiBjb25maWcuY2xzXG4gICAgICAgICwgY29uZmlnQXR0cmlidXRlcyA9IGNvbmZpZyAmJiBjb25maWcuYXR0cmlidXRlcztcblxuICAgIGlmIChjb25maWdBdHRyaWJ1dGVzKVxuICAgICAgICBfLmVhY2hLZXkoY29uZmlnQXR0cmlidXRlcywgZnVuY3Rpb24oYXR0clZhbHVlLCBhdHRyTmFtZSkge1xuICAgICAgICAgICAgZWwuc2V0QXR0cmlidXRlKGF0dHJOYW1lLCBhdHRyVmFsdWUpO1xuICAgICAgICB9KTtcblxuICAgIGlmIChjc3NDbGFzc2VzKVxuICAgICAgICBfYXR0YWNoQ3NzQ2xhc3NlcyhlbCwgJ2FkZCcsIGNzc0NsYXNzZXMpO1xufVxuXG5cbl8uZXh0ZW5kUHJvdG8oRG9tLCB7XG4gICAgc3RhcnQ6IHN0YXJ0LFxuXG4gICAgc2hvdzogc2hvdyxcbiAgICBoaWRlOiBoaWRlLFxuICAgIHRvZ2dsZTogdG9nZ2xlLFxuICAgIGRldGFjaDogZGV0YWNoLFxuICAgIHJlbW92ZTogcmVtb3ZlLFxuICAgIGFwcGVuZDogYXBwZW5kLFxuICAgIHByZXBlbmQ6IHByZXBlbmQsXG4gICAgYXBwZW5kQ2hpbGRyZW46IGFwcGVuZENoaWxkcmVuLFxuICAgIHByZXBlbmRDaGlsZHJlbjogcHJlcGVuZENoaWxkcmVuLFxuICAgIGluc2VydEFmdGVyOiBpbnNlcnRBZnRlcixcbiAgICBpbnNlcnRCZWZvcmU6IGluc2VydEJlZm9yZSxcbiAgICBhcHBlbmRUb1Njb3BlUGFyZW50OiBhcHBlbmRUb1Njb3BlUGFyZW50LFxuICAgIGNoaWxkcmVuOiBEb20kY2hpbGRyZW4sXG4gICAgc2V0U3R5bGU6IHNldFN0eWxlLFxuICAgIHNldFN0eWxlczogc2V0U3R5bGVzLFxuICAgIGNvcHk6IGNvcHksXG4gICAgY3JlYXRlRWxlbWVudDogY3JlYXRlRWxlbWVudCxcblxuICAgIGFkZENzc0NsYXNzZXM6IF8ucGFydGlhbChfbWFuYWdlQ3NzQ2xhc3NlcywgJ2FkZCcpLFxuICAgIHJlbW92ZUNzc0NsYXNzZXM6IF8ucGFydGlhbChfbWFuYWdlQ3NzQ2xhc3NlcywgJ3JlbW92ZScpLFxuICAgIHRvZ2dsZUNzc0NsYXNzZXM6IF8ucGFydGlhbChfbWFuYWdlQ3NzQ2xhc3NlcywgJ3RvZ2dsZScpLFxuXG4gICAgZmluZDogZmluZCxcbiAgICBoYXNUZXh0QmVmb3JlU2VsZWN0aW9uOiBoYXNUZXh0QmVmb3JlU2VsZWN0aW9uLFxuICAgIGhhc1RleHRBZnRlclNlbGVjdGlvbjogaGFzVGV4dEFmdGVyU2VsZWN0aW9uLFxufSk7XG5cbmZhY2V0c1JlZ2lzdHJ5LmFkZChEb20pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IERvbTtcblxuXG4vLyBzdGFydCBEb20gZmFjZXRcbmZ1bmN0aW9uIHN0YXJ0KCkge1xuICAgIHZhciBlbCA9IHRoaXMub3duZXIuZWw7XG4gICAgX2FwcGx5Q29uZmlnVG9FbGVtZW50KGVsLCB0aGlzLmNvbmZpZyk7XG4gICAgdmFyIGN1cnJlbnRTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsKVxuICAgIHRoaXMuX3Zpc2libGUgPSBjdXJyZW50U3R5bGUgJiYgY3VycmVudFN0eWxlLmRpc3BsYXkgIT0gJ25vbmUnO1xufVxuXG4vLyBzaG93IEhUTUwgZWxlbWVudCBvZiBjb21wb25lbnRcbmZ1bmN0aW9uIHNob3coKSB7XG4gICAgdGhpcy50b2dnbGUodHJ1ZSk7XG59XG5cbi8vIGhpZGUgSFRNTCBlbGVtZW50IG9mIGNvbXBvbmVudFxuZnVuY3Rpb24gaGlkZSgpIHtcbiAgICB0aGlzLnRvZ2dsZShmYWxzZSk7XG59XG5cbi8vIHNob3cvaGlkZVxuZnVuY3Rpb24gdG9nZ2xlKGRvU2hvdykge1xuICAgIGRvU2hvdyA9IHR5cGVvZiBkb1Nob3cgPT0gJ3VuZGVmaW5lZCdcbiAgICAgICAgICAgICAgICA/ICEgdGhpcy5fdmlzaWJsZVxuICAgICAgICAgICAgICAgIDogISEgZG9TaG93O1xuXG4gICAgdGhpcy5fdmlzaWJsZSA9IGRvU2hvdztcbiAgICB2YXIgZWwgPSB0aGlzLm93bmVyLmVsO1xuXG4gICAgZWwuc3R5bGUuZGlzcGxheSA9IGRvU2hvdyA/ICdibG9jaycgOiAnbm9uZSc7XG5cbiAgICByZXR1cm4gZG9TaG93O1xufVxuXG5cbmZ1bmN0aW9uIF9tYW5hZ2VDc3NDbGFzc2VzKG1ldGhvZE5hbWUsIGNzc0NsYXNzZXMsIGVuZm9yY2UpIHtcbiAgICBfYXR0YWNoQ3NzQ2xhc3Nlcyh0aGlzLm93bmVyLmVsLCBtZXRob2ROYW1lLCBjc3NDbGFzc2VzLCBlbmZvcmNlKTtcbn1cblxuXG5mdW5jdGlvbiBfYXR0YWNoQ3NzQ2xhc3NlcyhlbCwgbWV0aG9kTmFtZSwgY3NzQ2xhc3NlcywgZW5mb3JjZSkge1xuICAgIHZhciBjbGFzc0xpc3QgPSBlbC5jbGFzc0xpc3RcbiAgICAgICAgLCBkb1RvZ2dsZSA9IG1ldGhvZE5hbWUgPT0gJ3RvZ2dsZSc7XG5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShjc3NDbGFzc2VzKSlcbiAgICAgICAgY3NzQ2xhc3Nlcy5mb3JFYWNoKGNhbGxNZXRob2QpO1xuICAgIGVsc2UgaWYgKHR5cGVvZiBjc3NDbGFzc2VzID09ICdzdHJpbmcnKVxuICAgICAgICBjYWxsTWV0aG9kKGNzc0NsYXNzZXMpO1xuICAgIGVsc2VcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmtub3duIHR5cGUgb2YgQ1NTIGNsYXNzZXMgcGFyYW1ldGVyJyk7XG5cbiAgICBmdW5jdGlvbiBjYWxsTWV0aG9kKGNzc0Nscykge1xuICAgICAgICBkb1RvZ2dsZVxuICAgICAgICAgICAgLy8gT25seSBwYXNzICdlbmZvcmNlJyBpZiBhIHZhbHVlIGhhcyBiZWVuIHByb3ZpZGVkIChUaGUgJ3RvZ2dsZScgZnVuY3Rpb24gb2YgdGhlIGNsYXNzTGlzdCB3aWxsIHRyZWF0IHVuZGVmaW5lZCA9PT0gZmFsc2UgcmVzdWx0aW5nIGluIG9ubHkgYWxsb3dpbmcgY2xhc3NlcyB0byBiZSByZW1vdmVkKVxuICAgICAgICAgICAgPyBlbmZvcmNlID09PSB1bmRlZmluZWQgPyBjbGFzc0xpc3RbbWV0aG9kTmFtZV0oY3NzQ2xzKSA6IGNsYXNzTGlzdFttZXRob2ROYW1lXShjc3NDbHMsIGVuZm9yY2UpXG4gICAgICAgICAgICA6IGNsYXNzTGlzdFttZXRob2ROYW1lXShjc3NDbHMpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBkZXRhY2goKSB7XG4gICAgaWYgKHRoaXMub3duZXIuZWwpICBcbiAgICAgICAgZG9tVXRpbHMuZGV0YWNoQ29tcG9uZW50KHRoaXMub3duZXIuZWwpO1xufVxuXG5cbmZ1bmN0aW9uIHNldFN0eWxlKHByb3BlcnR5LCB2YWx1ZSkge1xuICAgIGlmICghdGhpcy5vd25lci5lbCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY2FsbCBzZXRTdHlsZSBvbiBvd25lciB3aXRoIG5vIGVsZW1lbnQ6IFwiICsgdGhpcy5vd25lci5jb25zdHJ1Y3Rvci5uYW1lKTtcbiAgICB9XG4gICAgdGhpcy5vd25lci5lbC5zdHlsZVtwcm9wZXJ0eV0gPSB2YWx1ZTtcbn1cblxuZnVuY3Rpb24gc2V0U3R5bGVzKHByb3BlcnRpZXMpIHtcbiAgICBmb3IgKHZhciBwcm9wZXJ0eSBpbiBwcm9wZXJ0aWVzKVxuICAgICAgICB0aGlzLm93bmVyLmVsLnN0eWxlW3Byb3BlcnR5XSA9IHByb3BlcnRpZXNbcHJvcGVydHldO1xufVxuXG5cbi8vIGNyZWF0ZSBhIGNvcHkgb2YgRE9NIGVsZW1lbnQgdXNpbmcgZmFjZXQgY29uZmlnIGlmIHNldFxuZnVuY3Rpb24gY29weShpc0RlZXApIHtcbiAgICByZXR1cm4gdGhpcy5vd25lci5lbCAmJiB0aGlzLm93bmVyLmVsLmNsb25lTm9kZShpc0RlZXApO1xufVxuXG5cbmZ1bmN0aW9uIGNyZWF0ZUVsZW1lbnQoKSB7XG4gICAgdmFyIG5ld0VsID0gRG9tLmNyZWF0ZUVsZW1lbnQodGhpcy5jb25maWcpO1xuICAgIHJldHVybiBuZXdFbDtcbn1cblxuXG4vLyByZW1vdmUgSFRNTCBlbGVtZW50IG9mIGNvbXBvbmVudFxuZnVuY3Rpb24gcmVtb3ZlKCkge1xuICAgIGRvbVV0aWxzLnJlbW92ZUVsZW1lbnQodGhpcy5vd25lci5lbCk7XG59XG5cbi8vIGFwcGVuZCBpbnNpZGUgSFRNTCBlbGVtZW50IG9mIGNvbXBvbmVudFxuZnVuY3Rpb24gYXBwZW5kKGVsKSB7XG4gICAgdGhpcy5vd25lci5lbC5hcHBlbmRDaGlsZChlbCk7XG59XG5cbi8vIHByZXBlbmQgaW5zaWRlIEhUTUwgZWxlbWVudCBvZiBjb21wb25lbnRcbmZ1bmN0aW9uIHByZXBlbmQoZWwpIHtcbiAgICB2YXIgdGhpc0VsID0gdGhpcy5vd25lci5lbFxuICAgICAgICAsIGZpcnN0Q2hpbGQgPSB0aGlzRWwuZmlyc3RDaGlsZDtcbiAgICBpZiAoZmlyc3RDaGlsZClcbiAgICAgICAgdGhpc0VsLmluc2VydEJlZm9yZShlbCwgZmlyc3RDaGlsZCk7XG4gICAgZWxzZVxuICAgICAgICB0aGlzRWwuYXBwZW5kQ2hpbGQoZWwpO1xufVxuXG4vLyBhcHBlbmRzIGNoaWxkcmVuIG9mIGVsZW1lbnQgaW5zaWRlIHRoaXMgY29tcG9uZW50J3MgZWxlbWVudFxuZnVuY3Rpb24gYXBwZW5kQ2hpbGRyZW4oZWwpIHtcbiAgICB3aGlsZShlbC5jaGlsZE5vZGVzLmxlbmd0aClcbiAgICAgICAgdGhpcy5hcHBlbmQoZWwuY2hpbGROb2Rlc1swXSk7XG59XG5cbi8vIHByZXBlbmRzIGNoaWxkcmVuIG9mIGVsZW1lbnQgaW5zaWRlIHRoaXMgY29tcG9uZW50J3MgZWxlbWVudFxuZnVuY3Rpb24gcHJlcGVuZENoaWxkcmVuKGVsKSB7XG4gICAgd2hpbGUoZWwuY2hpbGROb2Rlcy5sZW5ndGgpXG4gICAgICAgIHRoaXMucHJlcGVuZChlbC5jaGlsZE5vZGVzW2VsLmNoaWxkTm9kZXMubGVuZ3RoIC0gMV0pO1xufVxuXG5mdW5jdGlvbiBpbnNlcnRBZnRlcihlbCkge1xuICAgIHZhciB0aGlzRWwgPSB0aGlzLm93bmVyLmVsXG4gICAgICAgICwgcGFyZW50ID0gdGhpc0VsLnBhcmVudE5vZGU7ICAgIFxuICAgIHBhcmVudC5pbnNlcnRCZWZvcmUoZWwsIHRoaXNFbC5uZXh0U2libGluZyk7XG59XG5cbmZ1bmN0aW9uIGluc2VydEJlZm9yZShlbCkge1xuICAgIHZhciB0aGlzRWwgPSB0aGlzLm93bmVyLmVsXG4gICAgICAgICwgcGFyZW50ID0gdGhpc0VsLnBhcmVudE5vZGU7XG4gICAgcGFyZW50Lmluc2VydEJlZm9yZShlbCwgdGhpc0VsKTtcbn1cblxuXG4vLyBhcHBlbmRzIGNvbXBvbmVudCdzIGVsZW1lbnQgdG8gc2NvcGUgcGFyZW50LiBJZiBpdCB3YXMgYWxyZWR5IGluIERPTSBpdCB3aWxsIGJlIG1vdmVkXG5mdW5jdGlvbiBhcHBlbmRUb1Njb3BlUGFyZW50KCkge1xuICAgIHZhciBwYXJlbnQgPSB0aGlzLm93bmVyLmdldFNjb3BlUGFyZW50KCk7XG4gICAgaWYgKHBhcmVudCkgcGFyZW50LmVsLmFwcGVuZENoaWxkKHRoaXMub3duZXIuZWwpO1xufVxuXG5cbi8qKlxuICogRG9tIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyB0aGUgbGlzdCBvZiBjaGlsZCBlbGVtZW50cyBvZiB0aGUgY29tcG9uZW50IGVsZW1lbnRcbiAqXG4gKiBAcmV0dXJuIHtBcnJheVtFbGVtZW50XX1cbiAqL1xuZnVuY3Rpb24gRG9tJGNoaWxkcmVuKCkge1xuICAgIHJldHVybiBkb21VdGlscy5jaGlsZHJlbih0aGlzLm93bmVyLmVsKTtcbn1cblxuXG52YXIgZmluZERpcmVjdGlvbnMgPSB7XG4gICAgJ3VwJzogJ3ByZXZpb3VzTm9kZScsXG4gICAgJ2Rvd24nOiAnbmV4dE5vZGUnXG59O1xuXG4vLyBGaW5kcyBjb21wb25lbnQgcGFzc2luZyBvcHRpb25hbCBpdGVyYXRvcidzIHRlc3Rcbi8vIGluIHRoZSBzYW1lIHNjb3BlIGFzIHRoZSBjdXJyZW50IGNvbXBvbmVudCAodGhpcylcbi8vIGJ5IHRyYXZlcnNpbmcgRE9NIHRyZWUgdXB3YXJkcyAoZGlyZWN0aW9uID0gXCJ1cFwiKVxuLy8gb3IgZG93bndhcmRzIChkaXJlY3Rpb24gPSBcImRvd25cIilcbmZ1bmN0aW9uIGZpbmQoZGlyZWN0aW9uLCBpdGVyYXRvcikge1xuICAgIGlmICghIGZpbmREaXJlY3Rpb25zLmhhc093blByb3BlcnR5KGRpcmVjdGlvbikpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignaW5jb3JyZWN0IGZpbmQgZGlyZWN0aW9uOiAnICsgZGlyZWN0aW9uKTtcblxuICAgIHZhciBlbCA9IHRoaXMub3duZXIuZWxcbiAgICAgICAgLCBzY29wZSA9IHRoaXMub3duZXIuc2NvcGVcbiAgICAgICAgLCB0cmVlV2Fsa2VyID0gZG9jdW1lbnQuY3JlYXRlVHJlZVdhbGtlcihzY29wZS5fcm9vdEVsLCBOb2RlRmlsdGVyLlNIT1dfRUxFTUVOVCk7XG5cbiAgICB0cmVlV2Fsa2VyLmN1cnJlbnROb2RlID0gZWw7XG4gICAgdmFyIG5leHROb2RlID0gdHJlZVdhbGtlcltmaW5kRGlyZWN0aW9uc1tkaXJlY3Rpb25dXSgpXG4gICAgICAgICwgY29tcG9uZW50c05hbWVzID0gT2JqZWN0LmtleXMoc2NvcGUpXG4gICAgICAgICwgZm91bmQgPSBmYWxzZTtcblxuICAgIHdoaWxlIChuZXh0Tm9kZSkge1xuICAgICAgICB2YXIgYXR0ciA9IG5ldyBCaW5kQXR0cmlidXRlKG5leHROb2RlKTtcbiAgICAgICAgaWYgKGF0dHIubm9kZSkge1xuICAgICAgICAgICAgYXR0ci5wYXJzZSgpLnZhbGlkYXRlKCk7XG4gICAgICAgICAgICBpZiAoc2NvcGUuaGFzT3duUHJvcGVydHkoYXR0ci5jb21wTmFtZSkpIHtcbiAgICAgICAgICAgICAgICB2YXIgY29tcG9uZW50ID0gc2NvcGVbYXR0ci5jb21wTmFtZV07XG4gICAgICAgICAgICAgICAgaWYgKCEgaXRlcmF0b3IgfHwgaXRlcmF0b3IoY29tcG9uZW50KSkge1xuICAgICAgICAgICAgICAgICAgICBmb3VuZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0cmVlV2Fsa2VyLmN1cnJlbnROb2RlID0gbmV4dE5vZGU7XG4gICAgICAgIG5leHROb2RlID0gdHJlZVdhbGtlcltmaW5kRGlyZWN0aW9uc1tkaXJlY3Rpb25dXSgpO1xuICAgIH1cblxuICAgIGlmIChmb3VuZCkgcmV0dXJuIGNvbXBvbmVudDtcbn1cblxuXG4vLyByZXR1cm5zIHRydWUgaWYgdGhlIGVsZW1lbnQgaGFzIHRleHQgYmVmb3JlIHNlbGVjdGlvblxuZnVuY3Rpb24gaGFzVGV4dEJlZm9yZVNlbGVjdGlvbigpIHtcbiAgICB2YXIgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xuICAgIGlmICghIHNlbGVjdGlvbi5pc0NvbGxhcHNlZCkgcmV0dXJuIHRydWU7XG4gICAgXG4gICAgdmFyIHRleHQgPSBzZWxlY3Rpb24uZm9jdXNOb2RlICYmIHNlbGVjdGlvbi5mb2N1c05vZGUudGV4dENvbnRlbnQ7XG4gICAgdmFyIHN0YXJ0UG9zID0gdGV4dCAmJiB0ZXh0LmNoYXJBdCgwKSA9PSAnICcgPyAxIDogMDtcbiAgICBpZiAoc2VsZWN0aW9uLmFuY2hvck9mZnNldCAhPSBzdGFydFBvcykgcmV0dXJuIHRydWU7XG5cbiAgICAvLyB3YWxrIHVwIHRoZSBET00gdHJlZSB0byBjaGVjayBpZiB0aGVyZSBhcmUgdGV4dCBub2RlcyBiZWZvcmUgY3Vyc29yXG4gICAgdmFyIHRyZWVXYWxrZXIgPSBkb2N1bWVudC5jcmVhdGVUcmVlV2Fsa2VyKHRoaXMub3duZXIuZWwsIE5vZGVGaWx0ZXIuU0hPV19URVhUKTtcbiAgICB0cmVlV2Fsa2VyLmN1cnJlbnROb2RlID0gc2VsZWN0aW9uLmFuY2hvck5vZGU7XG4gICAgdmFyIHByZXZOb2RlID0gdHJlZVdhbGtlci5wcmV2aW91c05vZGUoKTtcblxuICAgIHZhciBpc1RleHQgPSBwcmV2Tm9kZSA/ICFwcmV2Tm9kZS5ub2RlVmFsdWUudHJpbSgpID09ICcnIDogZmFsc2U7XG5cbiAgICByZXR1cm4gaXNUZXh0O1xufVxuXG5cbmZ1bmN0aW9uIGhhc1RleHRBZnRlclNlbGVjdGlvbigpIHtcbiAgICB2YXIgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xuICAgIGlmICghIHNlbGVjdGlvbi5pc0NvbGxhcHNlZCkgcmV0dXJuIHRydWU7XG5cbiAgICB2YXIgdGV4dCA9IHNlbGVjdGlvbi5mb2N1c05vZGUgJiYgc2VsZWN0aW9uLmZvY3VzTm9kZS50ZXh0Q29udGVudDtcbiAgICB2YXIgc3RhcnRQb3MgPSB0ZXh0ICYmIHRleHQuY2hhckF0KHRleHQubGVuZ3RoLTEpID09ICcgJyA/IHNlbGVjdGlvbi5hbmNob3JOb2RlLmxlbmd0aC0xIDogc2VsZWN0aW9uLmFuY2hvck5vZGUubGVuZ3RoO1xuICAgIGlmIChzZWxlY3Rpb24uYW5jaG9yT2Zmc2V0IDwgc3RhcnRQb3MpIHJldHVybiB0cnVlO1xuXG4gICAgLy8gd2FsayB1cCB0aGUgRE9NIHRyZWUgdG8gY2hlY2sgaWYgdGhlcmUgYXJlIHRleHQgbm9kZXMgYWZ0ZXIgY3Vyc29yXG4gICAgdmFyIHRyZWVXYWxrZXIgPSBkb2N1bWVudC5jcmVhdGVUcmVlV2Fsa2VyKHRoaXMub3duZXIuZWwsIE5vZGVGaWx0ZXIuU0hPV19URVhUKTtcbiAgICB0cmVlV2Fsa2VyLmN1cnJlbnROb2RlID0gc2VsZWN0aW9uLmFuY2hvck5vZGU7XG4gICAgdmFyIG5leHROb2RlID0gdHJlZVdhbGtlci5uZXh0Tm9kZSgpO1xuICAgIFxuICAgIC8vVG8gY2FwdHVyZSB3aGVuIHRyZWV3YWxrZXIgZ2l2ZXMgdXMgYW4gZW1wdHkgdGV4dCBub2RlICh1bmtub3duIHJlYXNvbilcbiAgICB2YXIgaXNUZXh0ID0gbmV4dE5vZGUgPyAhbmV4dE5vZGUubm9kZVZhbHVlLnRyaW0oKSA9PSAnJyA6IGZhbHNlO1xuXG4gICAgcmV0dXJuIGlzVGV4dDtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gPGEgbmFtZT1cImNvbXBvbmVudHMtZmFjZXRzLWRyYWdcIj48L2E+XG4vLyAjIyNkcmFnIGZhY2V0XG5cbnZhciBDb21wb25lbnRGYWNldCA9IHJlcXVpcmUoJy4uL2NfZmFjZXQnKVxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NmX3JlZ2lzdHJ5JylcbiAgICAsIERPTUV2ZW50c1NvdXJjZSA9IHJlcXVpcmUoJy4uL21zZ19zcmMvZG9tX2V2ZW50cycpXG4gICAgLCBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jX2NsYXNzJylcbiAgICAsIERyYWdEcm9wID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9kcmFnZHJvcCcpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIGxvZ2dlciA9IG1pbG9Db3JlLnV0aWwubG9nZ2VyO1xuXG5cbi8qKlxuICogYG1pbG8ucmVnaXN0cnkuZmFjZXRzLmdldCgnRHJhZycpYFxuICogRmFjZXQgZm9yIGNvbXBvbmVudHMgdGhhdCBjYW4gYmUgZHJhZ2dlZFxuICogRHJhZyBmYWNldCBzdXBwb3J0cyB0aGUgZm9sbG93aW5nIGNvbmZpZ3VyYXRpb24gcGFyYW1ldGVyczpcbiAqXG4gKiAgLSBtZXRhOiBvYmplY3Qgd2l0aCBwcm9wZXJ0aWVzXG4gKiAgICAgIC0gcGFyYW1zOiBvYmplY3Qgb2Yga2V5LXZhbHVlIHBhaXJzIHRoYXQgd2lsbCBiZSBjb252ZXJ0ZWQgaW4gdXJsLWxpa2UgcXVlcnkgc3RyaW5nIGluIHRoZSBlbmQgb2YgZGF0YSB0eXBlIGZvciBtZXRhZGF0YSBkYXRhIHR5cGUgKG9yIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyB0aGlzIG9iamVjdCkuIFNlZSBjb25maWcuZHJhZ0Ryb3AuZGF0YVR5cGVzLmNvbXBvbmVudE1ldGFUZW1wbGF0ZVxuICogICAgICAgICAgYWxsIHZhbHVlcyB3aWxsIGNvbnZlcnRlZCB0byBsb3dlcmNhc2UgYXMgZGF0YXR5cGUgY2Fubm90IHN0b3JlIHVwcGVyY2FzZSBsZXR0ZXJzLlxuICogICAgICAtIGRhdGE6IGRhdGEgdGhhdCB3aWxsIGJlIHN0b3JlZCBpbiB0aGUgYWJvdmUgbWV0YSBkYXRhIHR5cGUgKG9yIGZ1bmN0aW9uKVxuICogIC0gYWxsb3dlZEVmZmVjdHM6IHN0cmluZyAob3IgZnVuY3Rpb24pIGFzIHNwZWNpZmllZCBoZXJlOiBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL0RyYWdEcm9wL0RyYWdfT3BlcmF0aW9ucyNkcmFnc3RhcnRcbiAqICAtIGRhdGFUeXBlczogbWFwIG9mIGFkZGl0aW9uYWwgZGF0YSB0eXBlcyB0aGUgY29tcG9uZW50IHdpbGwgc3VwcGx5IHRvIGRhdGEgdHJhbnNmZXIgb2JqZWN0LCBrZXkgaXMgZGF0YSB0eXBlLCB2YWx1ZSBpcyBhIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBpdCwgY29tcG9uZW50IHdpbGwgYmUgcGFzc2VkIGFzIHRoZSBjb250ZXh0IHRvIHRoaXMgZnVuY3Rpb25cbiAqXG4gKiBJZiBmdW5jdGlvbiBpcyBzcGVjaWZpZWQgaW4gYW55IHBhcmFtZXRlciBpdCB3aWxsIGJlIGNhbGxlZCB3aXRoIHRoZSBjb21wb25lbnQgYXMgdGhlIGNvbnRleHRcbiAqL1xudmFyIERyYWcgPSBfLmNyZWF0ZVN1YmNsYXNzKENvbXBvbmVudEZhY2V0LCAnRHJhZycpO1xuXG5fLmV4dGVuZFByb3RvKERyYWcsIHtcbiAgICBpbml0OiBEcmFnJGluaXQsXG4gICAgc3RhcnQ6IERyYWckc3RhcnQsXG4gICAgc2V0SGFuZGxlOiBEcmFnJHNldEhhbmRsZVxufSk7XG5cbmZhY2V0c1JlZ2lzdHJ5LmFkZChEcmFnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBEcmFnO1xuXG5cbmZ1bmN0aW9uIERyYWckaW5pdCgpIHtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyAgIFxuXG4gICAgdGhpcy5fY3JlYXRlTWVzc2FnZVNvdXJjZVdpdGhBUEkoRE9NRXZlbnRzU291cmNlKTtcbiAgICB0aGlzLl9kcmFnRGF0YSA9IHt9O1xuXG4gICAgdmFyIGRhdGFUeXBlSW5mbyA9IHRoaXMuY29uZmlnLl9kYXRhVHlwZUluZm8gfHwgJyc7XG4gICAgdGhpcy5fZGF0YVR5cGVJbmZvID0gdHlwZW9mIGRhdGFUeXBlSW5mbyA9PSAnZnVuY3Rpb24nXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyBkYXRhVHlwZUluZm9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IGZ1bmN0aW9uKCkgeyByZXR1cm4gZGF0YVR5cGVJbmZvOyB9O1xufVxuXG5cbi8qKlxuICogRHJhZyBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFNldHMgdGhlIGRyYWcgaGFuZGxlIGVsZW1lbnQgb2YgY29tcG9uZW50LiBUaGlzIGVsZW1lbnQgaGFzIHRvIGJlIGRyYWdnZWQgZm9yIHRoZSBjb21wb25lbnQgdG8gYmUgZHJhZ2dlZC5cbiAqXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGhhbmRsZUVsXG4gKi9cbmZ1bmN0aW9uIERyYWckc2V0SGFuZGxlKGhhbmRsZUVsKSB7XG4gICAgaWYgKCEgdGhpcy5vd25lci5lbC5jb250YWlucyhoYW5kbGVFbCkpXG4gICAgICAgIHJldHVybiBsb2dnZXIud2FybignZHJhZyBoYW5kbGUgc2hvdWxkIGJlIGluc2lkZSBlbGVtZW50IHRvIGJlIGRyYWdnZWQnKVxuICAgIHRoaXMuX2RyYWdIYW5kbGUgPSBoYW5kbGVFbDtcbn1cblxuXG5mdW5jdGlvbiBEcmFnJHN0YXJ0KCkge1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5zdGFydC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIF9hZGREcmFnQXR0cmlidXRlLmNhbGwodGhpcyk7XG5cbiAgICB0aGlzLm9uTWVzc2FnZXMoe1xuICAgICAgICAnbW91c2Vkb3duJzogb25Nb3VzZURvd24sXG4gICAgICAgICdtb3VzZWVudGVyIG1vdXNlbGVhdmUgbW91c2Vtb3ZlJzogb25Nb3VzZU1vdmVtZW50LFxuICAgICAgICAnZHJhZ3N0YXJ0Jzogb25EcmFnU3RhcnQsXG4gICAgICAgICdkcmFnJzogb25EcmFnZ2luZyxcbiAgICAgICAgJ2RyYWdlbmQnOiBvbkRyYWdFbmRcbiAgICB9KTtcblxuICAgIHRoaXMub3duZXIub25NZXNzYWdlcyh7XG4gICAgICAgICdnZXRzdGF0ZXN0YXJ0ZWQnOlxuICAgICAgICAgICAgeyBzdWJzY3JpYmVyOiBfcmVtb3ZlRHJhZ0F0dHJpYnV0ZSwgY29udGV4dDogdGhpcyB9LFxuICAgICAgICAnZ2V0c3RhdGVjb21wbGV0ZWQnOlxuICAgICAgICAgICAgeyBzdWJzY3JpYmVyOiBfYWRkRHJhZ0F0dHJpYnV0ZSwgY29udGV4dDogdGhpcyB9XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBBZGRzIGRyYWdnYWJsZSBhdHRyaWJ1dGUgdG8gY29tcG9uZW50J3MgZWxlbWVudFxuICpcbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIF9hZGREcmFnQXR0cmlidXRlKCkge1xuICAgIGlmICh0aGlzLm93bmVyLmVsKVxuICAgICAgICB0aGlzLm93bmVyLmVsLnNldEF0dHJpYnV0ZSgnZHJhZ2dhYmxlJywgdHJ1ZSk7XG59XG5cblxuZnVuY3Rpb24gX3JlbW92ZURyYWdBdHRyaWJ1dGUoKSB7XG4gICAgaWYgKHRoaXMub3duZXIuZWwpXG4gICAgICAgIHRoaXMub3duZXIuZWwucmVtb3ZlQXR0cmlidXRlKCdkcmFnZ2FibGUnKTtcbn1cblxuXG5mdW5jdGlvbiBvbk1vdXNlRG93bihldmVudFR5cGUsIGV2ZW50KSB7XG4gICAgdGhpcy5fX21vdXNlRG93blRhcmdldCA9IGV2ZW50LnRhcmdldDtcbiAgICBpZiAodGFyZ2V0SW5EcmFnSGFuZGxlLmNhbGwodGhpcykpIHtcbiAgICAgICAgd2luZG93LmdldFNlbGVjdGlvbigpLmVtcHR5KCk7XG4gICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBvbk1vdXNlTW92ZW1lbnQoZXZlbnRUeXBlLCBldmVudCkge1xuICAgIHZhciBzaG91bGRCZURyYWdnYWJsZSA9IHRhcmdldEluRHJhZ0hhbmRsZS5jYWxsKHRoaXMpO1xuICAgIHRoaXMub3duZXIuZWwuc2V0QXR0cmlidXRlKCdkcmFnZ2FibGUnLCBzaG91bGRCZURyYWdnYWJsZSk7XG4gICAgaWYgKGRvY3VtZW50LmJvZHkuZ2V0QXR0cmlidXRlKCdkYXRhLWRyYWdFbmFibGVFdmVudCcpICE9ICdmYWxzZScpXG4gICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xufVxuXG5cbmZ1bmN0aW9uIG9uRHJhZ1N0YXJ0KGV2ZW50VHlwZSwgZXZlbnQpIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBpZiAodGhpcy5jb25maWcub2ZmIHx8ICEgdGFyZ2V0SW5EcmFnSGFuZGxlLmNhbGwodGhpcykpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBvd25lciA9IHRoaXMub3duZXI7XG4gICAgdmFyIGR0ID0gbmV3IERyYWdEcm9wKGV2ZW50KTtcblxuICAgIHRoaXMuX2RyYWdEYXRhID0gZHQuc2V0Q29tcG9uZW50U3RhdGUob3duZXIpO1xuICAgIHNldE1ldGEuY2FsbCh0aGlzKTtcbiAgICBzZXRBZGRpdGlvbmFsRGF0YVR5cGVzLmNhbGwodGhpcyk7XG4gICAgX3NldEFsbG93ZWRFZmZlY3RzLmNhbGwodGhpcywgZHQpO1xuXG4gICAgRHJhZ0Ryb3Auc2VydmljZS5wb3N0TWVzc2FnZVN5bmMoJ2RyYWdkcm9wc3RhcnRlZCcsIHtcbiAgICAgICAgZXZlbnRUeXBlOiAnZHJhZ3N0YXJ0JyxcbiAgICAgICAgZHJhZ0Ryb3A6IGR0LFxuICAgICAgICBkcmFnRmFjZXQ6IHRoaXNcbiAgICB9KTtcblxuICAgIGZ1bmN0aW9uIHNldE1ldGEoKSB7XG4gICAgICAgIHZhciBtZXRhQ29uZmlnID0gdGhpcy5jb25maWcubWV0YVxuICAgICAgICAgICAgLCBwYXJhbXNDb25maWcgPSBtZXRhQ29uZmlnICYmIG1ldGFDb25maWcucGFyYW1zXG4gICAgICAgICAgICAsIG1ldGFEYXRhQ29uZmlnID0gbWV0YUNvbmZpZyAmJiBtZXRhQ29uZmlnLmRhdGE7XG5cbiAgICAgICAgdmFyIHBhcmFtcyA9IF8ucmVzdWx0KHBhcmFtc0NvbmZpZywgb3duZXIpXG4gICAgICAgICAgICAsIGRhdGEgPSBfLnJlc3VsdChtZXRhRGF0YUNvbmZpZywgb3duZXIpO1xuXG4gICAgICAgIHRoaXMuX2RyYWdNZXRhRGF0YVR5cGUgPSBkdC5zZXRDb21wb25lbnRNZXRhKG93bmVyLCBwYXJhbXMsIGRhdGEpO1xuICAgICAgICB0aGlzLl9kcmFnTWV0YURhdGEgPSBkYXRhO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHNldEFkZGl0aW9uYWxEYXRhVHlwZXMoKSB7XG4gICAgICAgIGlmICh0aGlzLmNvbmZpZy5kYXRhVHlwZXMpIHtcbiAgICAgICAgICAgIHRoaXMuX2RhdGFUeXBlc0RhdGEgPSBfLm1hcEtleXModGhpcy5jb25maWcuZGF0YVR5cGVzLCBmdW5jdGlvbiAoZ2V0RGF0YUZ1bmMsIGRhdGFUeXBlKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBnZXREYXRhRnVuYy5jYWxsKHRoaXMub3duZXIsIGRhdGFUeXBlKTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGRhdGEgPT0gJ29iamVjdCcpIGRhdGEgPSBKU09OLnN0cmluZ2lmeShkYXRhKTtcbiAgICAgICAgICAgICAgICBpZiAoZGF0YSkgZHQuc2V0RGF0YShkYXRhVHlwZSwgZGF0YSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgICAgICAgICB9LCB0aGlzKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBvbkRyYWdnaW5nKGV2ZW50VHlwZSwgZXZlbnQpIHtcbiAgICBpZiAoX2RyYWdJc0Rpc2FibGVkLmNhbGwodGhpcywgZXZlbnQpKSByZXR1cm47XG5cbiAgICB2YXIgZHQgPSBuZXcgRHJhZ0Ryb3AoZXZlbnQpO1xuICAgIGR0LnNldENvbXBvbmVudFN0YXRlKHRoaXMub3duZXIsIHRoaXMuX2RyYWdEYXRhKTtcbiAgICBkdC5zZXREYXRhKHRoaXMuX2RyYWdNZXRhRGF0YVR5cGUsIHRoaXMuX2RyYWdNZXRhRGF0YSk7XG4gICAgaWYgKHRoaXMuX2RhdGFUeXBlc0RhdGEpIHtcbiAgICAgICAgXy5lYWNoS2V5KHRoaXMuX2RhdGFUeXBlc0RhdGEsIGZ1bmN0aW9uKGRhdGEsIGRhdGFUeXBlKSB7XG4gICAgICAgICAgICBpZiAoZGF0YSkgZHQuc2V0RGF0YShkYXRhVHlwZSwgZGF0YSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIF9zZXRBbGxvd2VkRWZmZWN0cy5jYWxsKHRoaXMsIGR0KTtcbn1cblxuXG5mdW5jdGlvbiBvbkRyYWdFbmQoZXZlbnRUeXBlLCBldmVudCkge1xuICAgIGlmIChfZHJhZ0lzRGlzYWJsZWQuY2FsbCh0aGlzLCBldmVudCkpIHJldHVybjtcblxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIHZhciBkdCA9IG5ldyBEcmFnRHJvcChldmVudCk7XG4gICAgRHJhZ0Ryb3Auc2VydmljZS5wb3N0TWVzc2FnZVN5bmMoJ2NvbXBsZXRlZHJhZ2Ryb3AnLCB7XG4gICAgICAgIGV2ZW50VHlwZTogJ2RyYWdlbmQnLFxuICAgICAgICBkcmFnRHJvcDogZHQsXG4gICAgICAgIGRyYWdGYWNldDogdGhpc1xuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIF9zZXRBbGxvd2VkRWZmZWN0cyhEcmFnRHJvcCkge1xuICAgIHZhciBlZmZlY3RzID0gXy5yZXN1bHQodGhpcy5jb25maWcuYWxsb3dlZEVmZmVjdHMsIHRoaXMub3duZXIpO1xuICAgIERyYWdEcm9wLnNldEFsbG93ZWRFZmZlY3RzKGVmZmVjdHMpO1xufVxuXG5cbmZ1bmN0aW9uIHRhcmdldEluRHJhZ0hhbmRsZSgpIHtcbiAgICByZXR1cm4gISB0aGlzLl9kcmFnSGFuZGxlIHx8IHRoaXMuX2RyYWdIYW5kbGUuY29udGFpbnModGhpcy5fX21vdXNlRG93blRhcmdldCk7XG59XG5cblxuZnVuY3Rpb24gX2RyYWdJc0Rpc2FibGVkKGV2ZW50KSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLm9mZikge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyA8YSBuYW1lPVwiY29tcG9uZW50cy1mYWNldHMtZHJvcFwiPjwvYT5cbi8vICMjI2Ryb3AgZmFjZXRcblxudmFyIENvbXBvbmVudEZhY2V0ID0gcmVxdWlyZSgnLi4vY19mYWNldCcpXG4gICAgLCBmYWNldHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY2ZfcmVnaXN0cnknKVxuICAgICwgRE9NRXZlbnRzU291cmNlID0gcmVxdWlyZSgnLi4vbXNnX3NyYy9kb21fZXZlbnRzJylcbiAgICAsIERyb3BNc2dBUEkgPSByZXF1aXJlKCcuLi9tc2dfYXBpL2Ryb3AnKVxuICAgICwgRHJhZ0Ryb3AgPSByZXF1aXJlKCcuLi8uLi91dGlsL2RyYWdkcm9wJylcbiAgICAsIF8gPSByZXF1aXJlKCdtaWxvLWNvcmUnKS5wcm90bztcblxuLyoqXG4gKiBgbWlsby5yZWdpc3RyeS5mYWNldHMuZ2V0KCdEcm9wJylgXG4gKiBGYWNldCBmb3IgY29tcG9uZW50cyB0aGF0IGNhbiBhY2NlcHQgZHJvcHNcbiAqIERyb3AgZmFjZXQgc3VwcG9ydHMgdGhlIGZvbGxvd2luZyBjb25maWd1cmF0aW9uIHBhcmFtZXRlcnM6XG4gKlxuICogIC0gYWxsb3cgLSBhbiBvYmplY3QgdGhhdCB3aWxsIGRlZmluZSBhbGxvd2VkIGRhdGEgdHlwZXMgZHVyaW5nIGRyYWcgKGBkcmFnZW50ZXJgIGFuZCBgZHJhZ292ZXJgIGV2ZW50cykgd2l0aCB0aGVzZSBwcm9wZXJ0aWVzOlxuICogICAgICAtIGNvbXBvbmVudHM6IGB0cnVlYCBieSBkZWZhdWx0IChhbGwgY29tcG9uZW50cyB3aWxsIGJlIGFjY2VwdGVkKVxuICogICAgICAgICAgICAgICAgICAgICAgICBPUiBzdHJpbmcgd2l0aCBhbGxvd2VkIGNvbXBvbmVudCBjbGFzc1xuICogICAgICAgICAgICAgICAgICAgICAgICBPUiBsaXN0IG9mIGFsbG93ZWQgY29tcG9uZW50cyBjbGFzc2VzIChzdHJpbmdzKVxuICogICAgICAgICAgICAgICAgICAgICAgICBPUiBtYXAgd2l0aCBhbGxvd2VkIGNsYXNzZXMgaW4ga2V5cyBhbmQgYHRydWVgL3Rlc3QgZnVuY3Rpb25zIGluIHZhbHVlc1xuICogICAgICAgICAgICAgICAgICAgICAgICBPUiB0ZXN0IGZ1bmN0aW9uIHRoYXQgd2lsbCBiZSBwYXNzZWQgb2JqZWN0IGRlZmluZWQgYmVsb3dcbiAqICAgICAgICAgICAgICAgICAgICAgICAgT1IgYGZhbHNlYCB0byBOT1QgYWNjZXB0IGNvbXBvbmVudHNcbiAqICAgICAgLSBkYXRhVHlwZXM6ICBgZmFsc2VgIGJ5IGRlZmF1bHQgKG5vIG90aGVyIGRhdGEgdHlwZXMgd2lsbCBiZSBhY2NlcHRlZClcbiAqICAgICAgICAgICAgICAgICAgICAgICAgT1Igc3RyaW5nIHdpdGggYWxsb3dlZCBkYXRhIHR5cGVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgT1IgbGlzdCBvZiBhZGRpdGlvbmFsIGRhdGEgdHlwZXMgdGhhdCBhIGRyb3AgdGFyZ2V0IHdvdWxkIGFjY2VwdFxuICogICAgICAgICAgICAgICAgICAgICAgICBPUiB0ZXN0IGZ1bmN0aW9uIHRoYXQgd2lsbCBiZSBwYXNzZWQgRHJhZ0Ryb3Agb2JqZWN0XG4gKiAgICAgICAgICAgICAgICAgICAgICAgIE9SIGB0cnVlYCB0byBhY2NlcHQgYWxsIGRhdGEgdHlwZXNcbiAqICAgICAgLSBjaGVja1BhcmVudDogYGZhbHNlYCBieSBkZWZhdWx0XG4gKiAgICAgICAgICAgICAgICAgICAgICAgIE9SIGB0cnVlYCB3aWxsIGNhbGwgcGFyZW50IGNvbXBvbmVudCBkcm9wIGFsbG93IHRvIGNoZWNrIGlmIHBhcmVudCBjb21wb25lbnQgd2lsbCBhY2NlcHQgdGhlIGNvbXBvbmVudFxuICogICAgICBJZiB0ZXN0IGZ1bmN0aW9ucyBhcmUgdXNlZCwgdGhleSBzaG91bGQgcmV0dXJuIGJvb2xlYW4uIEVhY2ggdGVzdCBmdW5jdGlvbiBjYW4gYWxzbyBzZXQgZHJvcCBlZmZlY3QgYXMgZGVmaW5lZCBoZXJlOlxuICogICAgICBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvRGF0YVRyYW5zZmVyI2Ryb3BFZmZlY3QuMjguMjlcbiAqICAgICAgU2V0dGluZyBkcm9wIGVmZmVjdCB0aGF0IGlzIG5vdCBhbGxvd2VkIGJ5IGRyYWdnZWQgb2JqZWN0IHdpbGwgcHJldmVudCBkcm9wLlxuICogICAgICBUZXN0IGZ1bmN0aW9ucyBmb3IgY29tcG9uZW50cyB3aWxsIGJlIHBhc3NlZCB0aGUgb3duZXIgb2YgRHJvcCBmYWNldCBhcyBjb250ZXh0LCB0aGUgb2JqZWN0IHdpdGggdGhlIGZvbGxvd2luZyBwb3NzaWJsZSBwcm9wZXJ0aWVzIGFzIHRoZSBmaXJzdCBwYXJhbWV0ZXI6XG4gKiAgICAgICAgICBjb21wQ2xhc3MgLSBuYW1lIG9mIGNvbXBvbmVudCBjbGFzcyBhcyBzdG9yZWQgaW4gcmVnaXN0cnlcbiAqICAgICAgICAgIGNvbXBOYW1lIC0gbmFtZSBvZiBjb21wb25lbnQgKGFsbCBsb3dlcmNhc2UpXG4gKiAgICAgICAgICBwYXJhbXMgLSBwYXJhbWV0ZXJzIGFzIGVuY29kZWQgaW4gZGF0YVR5cGUsIHBhc3NlZCB0byBgbWlsby51dGlsLmRyYWdEcm9wLnNldENvbXBvbmVudE1ldGFgIGJ5IERyYWcgZmFjZXRcbiAqICAgICAgICAgIG1ldGFEYXRhVHlwZSAtIGRhdGEgdHlwZSBvZiB0aGUgZGF0YSB0aGF0IGhhcyBjb21wQ2xhc3MsIGNvbXBOYW1lIGFuZCBwYXJhbXMgZW5jb2RlZFxuICpcbiAqICAgICAgLi4uIGFuZCBEcmFnRHJvcCBpbnN0YW5jZSBhcyB0aGUgc2Vjb25kIHBhcmFtZXRlclxuICpcbiAqICAgICAgVGVzdCBmdW5jdGlvbiBmb3Igb3RoZXIgZGF0YSB0eXBlcyB3aWxsIGJlIHBhc3NlZCB0aGUgb3duZXIgb2YgRHJvcCBmYWNldCBhcyBjb250ZXh0IGFuZCBEcmFnRHJvcCBpbnN0YW5jZSBhcyB0aGUgZmlyc3QgcGFyYW1ldGVyXG4gKlxuICogIyMjI0V2ZW50cyMjIyNcbiAqXG4gKiBJbiBhZGRpdGlvbiB0byBjb25maWd1cmluZyBhbGxvd2VkIGNvbXBvbmVudHMgYW5kIGRhdGEgdHlwZXMsIGNvbXBvbmVudHMgY2xhc3NlcyBzaG91bGQgc3Vic2NyaWJlIHRvIGV2ZW50cy5cbiAqIEF0IHRoZSB2ZXJ5IGxlYXN0LCB0aGV5IHNob3VsZCBzdWJzY3JpYmUgdG8gYGRyb3BgIGV2ZW50LlxuICpcbiAqIERyb3AgZmFjZXQgZW1pdHMgZHJhZ2luL2RyYWdvdXQgbWVzc2FnZXMgdGhhdCBhcmUgZW1pdHRlZCB3aGVuZXZlciBhY3R1YWwgY29tcG9uZW50IGVsZW1lbnQgaXMgZW50ZXJlZCBvciBsZWZ0XG4gKiAod2hpY2ggaXMgZGlmZmVyZW50IGZyb20gZHJhZ2VudGVyIGFuZCBkcmFnbGVhdmUgbWVzc2FnZXMgdGhhdCBhcmUgZW1pdHRlZCB3aGVuZXZlciBhbnkgY2hpbGQgZWxlbWVudCBpcyBlbnRlcmVkIG9yIGxlZnQsIGFzIGxvbmcgYXMgZXZlbnQgYnViYmxlcyB1cClcbiAqIElmIGNoaWxkIGNvbXBvbmVudCBoYXMgZHJvcCBmYWNldCBhdHRhY2hlZCwgZHJhZ291dCB3aWxsIGJlIGVtaXR0ZWQgb24gdGhlIGN1cnJlbnQgY29tcG9uZW50IHdoZW4gdGhlIGNoaWxkIGlzIGVudGVyZWQuXG4gKlxuICogWW91IGNhbiBzZWUgdGhlIGRlbW9uc3RyYXRpb24gb2Ygd2hlbiBtZXNzYWdlcyBhcmUgZW1pdHRlZCBbaGVyZV0oaHR0cDovL2pzYmluLmNvbS9idXFvdi82KVxuICogXG4gKi9cbnZhciBEcm9wID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ0Ryb3AnKTtcblxuXG5fLmV4dGVuZFByb3RvKERyb3AsIHtcbiAgICBpbml0OiBEcm9wJGluaXQsXG4gICAgc3RhcnQ6IERyb3Akc3RhcnRcbiAgICAvLyBfcmVhdHRhY2g6IF9yZWF0dGFjaEV2ZW50c09uRWxlbWVudENoYW5nZVxufSk7XG5cbmZhY2V0c1JlZ2lzdHJ5LmFkZChEcm9wKTtcblxubW9kdWxlLmV4cG9ydHMgPSBEcm9wO1xuXG5cbmZ1bmN0aW9uIERyb3AkaW5pdCgpIHtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMuX2NyZWF0ZU1lc3NhZ2VTb3VyY2VXaXRoQVBJKERPTUV2ZW50c1NvdXJjZSwgbmV3IERyb3BNc2dBUEkpO1xufVxuXG5cbmZ1bmN0aW9uIERyb3Akc3RhcnQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLnN0YXJ0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgdGhpcy5vd25lci5lbC5jbGFzc0xpc3QuYWRkKCdjYy1tb2R1bGUtcmVsYXRpdmUnKTtcbiAgICB0aGlzLm9uTWVzc2FnZXMoe1xuICAgICAgICAnZHJhZ2VudGVyIGRyYWdvdmVyJzogb25EcmFnZ2luZyxcbiAgICAgICAgJ2Ryb3AnOiBvbkRyb3AsXG4gICAgICAgICdkcmFnZW50ZXIgZHJhZ292ZXIgZHJhZ2xlYXZlIGRyb3AgZHJhZ2luIGRyYWdvdXQnOiBwb3N0VG9TZXJ2aWNlXG4gICAgfSk7XG59XG5cblxuZnVuY3Rpb24gb25EcmFnZ2luZyhldmVudFR5cGUsIGV2ZW50KSB7XG4gICAgdmFyIGR0ID0gbmV3IERyYWdEcm9wKGV2ZW50KTtcblxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICBpZiAoISBfaGFuZGxlRHJvcERlcGVuZGVuY3kuY2FsbCh0aGlzLCBkdCkpXG4gICAgICAgIGR0LnNldERyb3BFZmZlY3QoJ25vbmUnKTtcbn1cblxuXG5mdW5jdGlvbiBvbkRyb3AoZXZlbnRUeXBlLCBldmVudCkge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIHZhciBkdCA9IG5ldyBEcmFnRHJvcChldmVudCk7XG4gICAgRHJhZ0Ryb3Auc2VydmljZS5wb3N0TWVzc2FnZVN5bmMoJ2RyYWdkcm9wY29tcGxldGVkJywge1xuICAgICAgICBldmVudFR5cGU6ICdkcm9wJyxcbiAgICAgICAgZHJhZ0Ryb3A6IGR0LFxuICAgICAgICBkcm9wRmFjZXQ6IHRoaXMsXG4gICAgICAgIGNvbXBvbmVudDogdGhpcy5vd25lclxuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIHBvc3RUb1NlcnZpY2UoZXZlbnRUeXBlLCBldmVudCkge1xuICAgIERyYWdEcm9wLnNlcnZpY2UucG9zdE1lc3NhZ2VTeW5jKGV2ZW50VHlwZSwge1xuICAgICAgICBldmVudDogZXZlbnQsXG4gICAgICAgIGRyb3BGYWNldDogdGhpcyxcbiAgICAgICAgY29tcG9uZW50OiB0aGlzLm93bmVyXG4gICAgfSk7XG59XG5cblxudmFyIF9oYW5kbGVEcm9wRGVwZW5kZW5jeSA9IF8udGhyb3R0bGUoX2hhbmRsZURyb3BEZXBlbmRlbmN5Tm90aHJvdHRsZSwgNTApO1xuZnVuY3Rpb24gX2hhbmRsZURyb3BEZXBlbmRlbmN5Tm90aHJvdHRsZShkdCwgb3JpZ2luYWxEcm9wQ29tcG9uZW50KSB7XG4gICAgdmFyIGFsbG93ID0gdGhpcy5jb25maWcuYWxsb3dcbiAgICAgICAgLCBwYXJlbnRBbGxvd2VkID0gdHJ1ZTtcblxuICAgIG9yaWdpbmFsRHJvcENvbXBvbmVudCA9IG9yaWdpbmFsRHJvcENvbXBvbmVudCB8fCB0aGlzLm93bmVyO1xuXG4gICAgaWYgKGFsbG93ICYmIGFsbG93LmNoZWNrUGFyZW50KSB7XG4gICAgICAgIHZhciBwYXJlbnQgPSB0aGlzLm93bmVyLmdldFNjb3BlUGFyZW50KCdEcm9wJyk7XG4gICAgICAgIGlmIChwYXJlbnQpXG4gICAgICAgICAgICBwYXJlbnRBbGxvd2VkID0gX2hhbmRsZURyb3BEZXBlbmRlbmN5Tm90aHJvdHRsZS5jYWxsKHBhcmVudC5kcm9wLCBkdCwgb3JpZ2luYWxEcm9wQ29tcG9uZW50KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcGFyZW50QWxsb3dlZCAmJiBfaXNEcm9wQWxsb3dlZC5jYWxsKHRoaXMsIGR0LCBvcmlnaW5hbERyb3BDb21wb25lbnQpO1xufVxuXG5cbi8qKlxuICogQ2hlY2tzIGlmIGRyb3AgaXMgYWxsb3dlZCBiYXNlZCBvbiBmYWNldCBjb25maWd1cmF0aW9uIChzZWUgYWJvdmUpXG4gKiBcbiAqIEBwYXJhbSB7RHJhZ0Ryb3B9IGR0XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBfaXNEcm9wQWxsb3dlZChkdCwgb3JpZ2luYWxEcm9wQ29tcG9uZW50KSB7XG4gICAgdmFyIGFsbG93ID0gdGhpcy5jb25maWcuYWxsb3c7XG5cbiAgICBpZiAoZHQuaXNDb21wb25lbnQoKSkge1xuICAgICAgICB2YXIgYWxsb3dDb21wcyA9IGFsbG93ICYmIGFsbG93LmNvbXBvbmVudHNcbiAgICAgICAgICAgICwgbWV0YSA9IGR0LmdldENvbXBvbmVudE1ldGEoKTtcblxuICAgICAgICBzd2l0Y2ggKHR5cGVvZiBhbGxvd0NvbXBzKSB7XG4gICAgICAgICAgICBjYXNlICd1bmRlZmluZWQnOlxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgY2FzZSAnYm9vbGVhbic6XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFsbG93Q29tcHM7XG4gICAgICAgICAgICAvLyBjb21wb25lbnQgY2xhc3NcbiAgICAgICAgICAgIGNhc2UgJ3N0cmluZyc6XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1ldGEgJiYgbWV0YS5jb21wQ2xhc3MgPT0gYWxsb3dDb21wcztcbiAgICAgICAgICAgIC8vIHRlc3QgZnVuY3Rpb25cbiAgICAgICAgICAgIGNhc2UgJ2Z1bmN0aW9uJzpcbiAgICAgICAgICAgICAgICByZXR1cm4gYWxsb3dDb21wcy5jYWxsKHRoaXMub3duZXIsIG1ldGEsIGR0LCBvcmlnaW5hbERyb3BDb21wb25lbnQpO1xuICAgICAgICAgICAgY2FzZSAnb2JqZWN0JzpcbiAgICAgICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShhbGxvd0NvbXBzKSlcbiAgICAgICAgICAgICAgICAgICAgLy8gbGlzdCBvZiBhbGxvd2VkIGNsYXNzZXNcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGFsbG93Q29tcHMuaW5kZXhPZihtZXRhICYmIG1ldGEuY29tcENsYXNzKSA+PSAwO1xuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBtYXAgb2YgY2xhc3M6IGJvb2xlYW58dGVzdCBmdW5jdGlvblxuICAgICAgICAgICAgICAgICAgICB2YXIgdGVzdCA9IGFsbG93Q29tcHNbbWV0YSAmJiBtZXRhLmNvbXBDbGFzc107XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAhISBfLnJlc3VsdCh0ZXN0LCB0aGlzLm93bmVyLCBtZXRhLCBkdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0luY29ycmVjdCBhbGxvd2VkIGNvbXBvbmVudHMgaW4gY29uZmlnJyk7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgZGF0YVR5cGVzID0gYWxsb3cgJiYgYWxsb3cuZGF0YVR5cGVzXG4gICAgICAgIHN3aXRjaCAodHlwZW9mIGRhdGFUeXBlcykge1xuICAgICAgICAgICAgY2FzZSAndW5kZWZpbmVkJzpcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICBjYXNlICdzdHJpbmcnOlxuICAgICAgICAgICAgICAgIHJldHVybiBkdC50eXBlcy5pbmRleE9mKGRhdGFUeXBlcykgPj0gMDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRPRE8gdGVzdCBmb3Igb3RoZXIgZGF0YSB0eXBlc1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50RmFjZXQgPSByZXF1aXJlKCcuLi9jX2ZhY2V0JylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jZl9yZWdpc3RyeScpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNZXNzZW5nZXIgPSBtaWxvQ29yZS5NZXNzZW5nZXJcbiAgICAsIERPTUV2ZW50c1NvdXJjZSA9IHJlcXVpcmUoJy4uL21zZ19zcmMvZG9tX2V2ZW50cycpXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG87XG5cblxuLyoqXG4gKiBgbWlsby5yZWdpc3RyeS5mYWNldHMuZ2V0KCdFdmVudHMnKWBcbiAqIENvbXBvbmVudCBmYWNldCB0aGF0IG1hbmFnZXMgc3Vic2NyaXB0aW9ucyB0byBET00gZXZlbnRzIHVzaW5nIFtNZXNzZW5nZXJdKC4uLy4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sKSB3aXRoIFtET01FdmVudHNTb3VyY2VdKC4uL21zZ19zcmMvZG9tX2V2ZW50cy5qcy5odG1sKS5cbiAqIEFsbCBwdWJsaWMgbWV0aG9kcyBvZiBNZXNzZW5nZXIgYW5kIGB0cmlnZ2VyYCBtZXRob2Qgb2YgW0RPTUV2ZW50c1NvdXJjZV0oLi4vbXNnX3NyYy9kb21fZXZlbnRzLmpzLmh0bWwpIGFyZSBwcm94aWVkIGRpcmVjdGx5IHRvIHRoaXMgZmFjZXQuXG4gKiBGb3IgZXhhbXBsZSwgdG8gc3Vic2NyaWJlIHRvIGBjbGlja2AgZXZlbnQgdXNlOlxuICogYGBgXG4gKiBjb21wb25lbnQuZnJhbWUub24oJ2NsaWNrJywgZnVuY3Rpb24oKSB7XG4gKiAgICAgLy8gLi4uXG4gKiB9KTtcbiAqIGBgYFxuICogU2VlIFtNZXNzZW5nZXJdKC4uLy4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sKVxuICovXG52YXIgRXZlbnRzID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ0V2ZW50cycpO1xuXG5cbi8qKlxuICogIyMjI0V2ZW50cyBmYWNldCBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2luaXRdKCNFdmVudHMkaW5pdCkgLSBjYWxsZWQgYnkgY29uc3RydWN0b3IgYXV0b21hdGljYWxseVxuICovXG5fLmV4dGVuZFByb3RvKEV2ZW50cywge1xuICAgIGluaXQ6IEV2ZW50cyRpbml0XG4gICAgLy8gX3JlYXR0YWNoOiBfcmVhdHRhY2hFdmVudHNPbkVsZW1lbnRDaGFuZ2Vcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoRXZlbnRzKTtcblxubW9kdWxlLmV4cG9ydHMgPSBFdmVudHM7XG5cblxuLyoqXG4gKiBFeHBvc2UgRE9NRXZlbnRzU291cmNlIHRyaWdnZXIgbWV0aG9kIG9uIEV2ZW50cyBwcm90b3R5cGVcbiAqL1xudmFyIE1TR19TT1VSQ0VfS0VZID0gJ19kb21FdmVudHNTb3VyY2UnXG5ET01FdmVudHNTb3VyY2UudXNlV2l0aChFdmVudHMsIE1TR19TT1VSQ0VfS0VZLCBbJ3RyaWdnZXInXSk7XG5cblxuLyoqXG4gKiBFdmVudHMgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsemVzIGZhY2V0LCBjb25uZWN0cyBET01FdmVudHNTb3VyY2UgdG8gZmFjZXQncyBtZXNzZW5nZXJcbiAqL1xuZnVuY3Rpb24gRXZlbnRzJGluaXQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIHZhciBkb21FdmVudHNTb3VyY2UgPSBuZXcgRE9NRXZlbnRzU291cmNlKHRoaXMsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB0aGlzLm93bmVyKTtcbiAgICB0aGlzLl9zZXRNZXNzYWdlU291cmNlKGRvbUV2ZW50c1NvdXJjZSk7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBNU0dfU09VUkNFX0tFWSwgZG9tRXZlbnRzU291cmNlKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgQ29tcG9uZW50RmFjZXQgPSByZXF1aXJlKCcuLi9jX2ZhY2V0JylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jZl9yZWdpc3RyeScpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNZXNzZW5nZXIgPSBtaWxvQ29yZS5NZXNzZW5nZXJcbiAgICAsIEZyYW1lTWVzc2FnZVNvdXJjZSA9IHJlcXVpcmUoJy4uL21zZ19zcmMvZnJhbWUnKVxuICAgICwgZG9tRXZlbnRzQ29uc3RydWN0b3JzID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZXMvZGVfY29uc3RycycpXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG87XG5cblxuLyoqXG4gKiBgbWlsby5yZWdpc3RyeS5mYWNldHMuZ2V0KCdGcmFtZScpYFxuICogQ29tcG9uZW50IGZhY2V0IHRoYXQgc2ltcGxpZmllcyBzZW5kaW5nIHdpbmRvdyBtZXNzYWdlcyB0byBpZnJhbWUgYW5kIHN1YnNjcmliaW5nIHRvIG1lc3NhZ2VzIG9uIGlubmVyIHdpbmRvdyBvZiBpZnJhbWUuXG4gKiBBbGwgcHVibGljIG1ldGhvZHMgb2YgTWVzc2VuZ2VyIGFuZCBgdHJpZ2dlcmAgbWV0aG9kIG9mIFtGcmFtZU1lc3NhZ2VTb3VyY2VdKC4uL21zZ19zcmMvZnJhbWUuanMuaHRtbCkgYXJlIHByb3hpZWQgZGlyZWN0bHkgdG8gdGhpcyBmYWNldC5cbiAqIEZvciBleGFtcGxlLCB0byBzZW5kIGN1c3RvbSBtZXNzYWdlIHRvIGlmcmFtZSB3aW5kb3cgdXNlOlxuICogYGBgXG4gKiBpZnJhbWVDb21wb25lbnQuZnJhbWUudHJpZ2dlcignbXltZXNzYWdlJywgbXlEYXRhKTtcbiAqIGBgYFxuICogVG8gc3Vic2NyaWJlIHRvIHRoaXMgbWVzc2FnZXMgaW5zaWRlIGZyYW1lIHVzZSAod2l0aCBtaWxvIC0gc2VlIFttaWxvLm1haWxdKC4uLy4uL21haWwvaW5kZXguanMuaHRtbCkpOlxuICogYGBgXG4gKiBtaWxvLm1haWwub24oJ21lc3NhZ2U6bXltZXNzYWdlJywgZnVuY3Rpb24obXNnVHlwZSwgbXNnRGF0YSkge1xuICogICAgIC8vIGRhdGEgaXMgaW5zaWRlIG9mIHdpbmRvdyBtZXNzYWdlIGRhdGFcbiAqICAgICAvLyBtc2dUeXBlID09ICdtZXNzYWdlOm15bWVzc2FnZSdcbiAqICAgICB2YXIgbXlEYXRhID0gbXNnRGF0YS5kYXRhO1xuICogICAgIC8vIC4uLiBhcHAgbG9naWMgaGVyZVxuICogfSk7XG4gKiBgYGBcbiAqIG9yIHdpdGhvdXQgbWlsbzpcbiAqIGBgYFxuICogd2luZG93LmF0dGFjaEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBmdW5jdGlvbihtZXNzYWdlKSB7XG4gKiAgICAgdmFyIG1zZ1R5cGUgPSBtZXNzYWdlLnR5cGU7IC8vIGUuZy4sICdteW1lc3NhZ2UnXG4gKiAgICAgdmFyIG15RGF0YSA9IG1lc3NhZ2UuZGF0YTtcbiAqICAgICAvLyAuLi4gbWVzc2FnZSByb3V0aW5nIGFuZCBjb2RlIGhlcmVcbiAqIH0pO1xuICogYGBgXG4gKiBNaWxvIGRvZXMgcm91dGluZyBiYXNlZCBvbiBzZW50IG1lc3NhZ2UgdHlwZSBhdXRvbWF0aWNhbGx5LlxuICogU2VlIFtNZXNzZW5nZXJdKC4uLy4uL21lc3Nlbmdlci9pbmRleC5qcy5odG1sKSBhbmQgW21pbG8ubWFpbF0oLi4vLi4vbWFpbC9pbmRleC5qcy5odG1sKS5cbiAqL1xuIHZhciBGcmFtZSA9IF8uY3JlYXRlU3ViY2xhc3MoQ29tcG9uZW50RmFjZXQsICdGcmFtZScpO1xuXG5cbi8qKlxuICogQ2FsbHMgcGFzc2VkIGZ1bmN0aW9uIHdoZW4gZnJhbWUgRE9NIGJlY29tZXMgcmVhZHkuIElmIGFscmVhZHkgcmVhZHkgY2FsbHMgaW1tZWRpYXRlbHlcbiAqL1xudmFyIEZyYW1lJHdoZW5SZWFkeSA9IF9tYWtlV2hlblJlYWR5RnVuYyhGcmFtZSRpc1JlYWR5LCAnZG9tcmVhZHknKTtcblxuLyoqXG4gKiBDYWxscyBwYXNzZWQgZnVuY3Rpb24gd2hlbiBmcmFtZSBtaWxvIGJlY29tZXMgcmVhZHkuIElmIGFscmVhZHkgcmVhZHkgY2FsbHMgaW1tZWRpYXRlbHlcbiAqL1xudmFyIEZyYW1lJHdoZW5NaWxvUmVhZHkgPSBfbWFrZVdoZW5SZWFkeUZ1bmMoRnJhbWUkaXNNaWxvUmVhZHksICdtZXNzYWdlOm1pbG9yZWFkeScpO1xuXG5cbi8qKlxuICogIyMjI0V2ZW50cyBmYWNldCBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2luaXRdKCNGcmFtZSRpbml0KSAtIGNhbGxlZCBieSBjb25zdHJ1Y3RvciBhdXRvbWF0aWNhbGx5XG4gKi9cbl8uZXh0ZW5kUHJvdG8oRnJhbWUsIHtcbiAgICBpbml0OiBGcmFtZSRpbml0LFxuICAgIHN0YXJ0OiBGcmFtZSRzdGFydCxcbiAgICBkZXN0cm95OiBGcmFtZSRkZXN0cm95LFxuICAgIGdldFdpbmRvdzogRnJhbWUkZ2V0V2luZG93LFxuICAgIGlzUmVhZHk6IEZyYW1lJGlzUmVhZHksXG4gICAgd2hlblJlYWR5OiBGcmFtZSR3aGVuUmVhZHksXG4gICAgaXNNaWxvUmVhZHk6IEZyYW1lJGlzTWlsb1JlYWR5LFxuICAgIHdoZW5NaWxvUmVhZHk6IEZyYW1lJHdoZW5NaWxvUmVhZHksXG4gICAgbWlsbzogRnJhbWUkbWlsb1xuICAgIC8vIF9yZWF0dGFjaDogX3JlYXR0YWNoRXZlbnRzT25FbGVtZW50Q2hhbmdlXG59KTtcblxuXG5mYWNldHNSZWdpc3RyeS5hZGQoRnJhbWUpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZyYW1lO1xuXG5cbi8qKlxuICogRXhwb3NlIEZyYW1lTWVzc2FnZVNvdXJjZSB0cmlnZ2VyIG1ldGhvZCBvbiBFdmVudHMgcHJvdG90eXBlXG4gKi9cbnZhciBNU0dfU09VUkNFX0tFWSA9ICdfbWVzc2FnZVNvdXJjZSc7XG5GcmFtZU1lc3NhZ2VTb3VyY2UudXNlV2l0aChGcmFtZSwgTVNHX1NPVVJDRV9LRVksIFsndHJpZ2dlciddKTtcblxuXG4vKipcbiAqIEZyYW1lIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogSW5pdGlhbHplcyBmYWNldCwgY29ubmVjdHMgRnJhbWVNZXNzYWdlU291cmNlIHRvIGZhY2V0J3MgbWVzc2VuZ2VyXG4gKi9cbmZ1bmN0aW9uIEZyYW1lJGluaXQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICBcbiAgICB2YXIgbWVzc2FnZVNvdXJjZSA9IG5ldyBGcmFtZU1lc3NhZ2VTb3VyY2UodGhpcywgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHRoaXMub3duZXIpO1xuICAgIHRoaXMuX3NldE1lc3NhZ2VTb3VyY2UobWVzc2FnZVNvdXJjZSk7XG5cbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsIE1TR19TT1VSQ0VfS0VZLCBtZXNzYWdlU291cmNlKTtcbn1cblxuXG4vKipcbiAqIEZyYW1lIGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogRW1pdHMgZnJhbWVsb2FkZWQgZXZlbnQgd2hlbiByZWFkeS5cbiAqL1xuZnVuY3Rpb24gRnJhbWUkc3RhcnQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLnN0YXJ0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIG1pbG8ocG9zdERvbVJlYWR5KTtcblxuICAgIGZ1bmN0aW9uIHBvc3REb21SZWFkeShldmVudCkge1xuICAgICAgICBzZWxmLnBvc3RNZXNzYWdlKCdkb21yZWFkeScsIGV2ZW50KTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gRnJhbWUkZGVzdHJveSgpIHtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuZGVzdHJveS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbi8qKlxuICogRnJhbWUgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXRyaWV2ZXMgdGhlIGludGVybmFsIHdpbmRvdyBvZiB0aGUgZnJhbWUgXG4gKlxuICogQHBhcmFtIHtXaW5kb3d9XG4gKi9cbmZ1bmN0aW9uIEZyYW1lJGdldFdpbmRvdygpIHtcbiAgICByZXR1cm4gdGhpcy5vd25lci5lbC5jb250ZW50V2luZG93O1xufVxuXG5cbi8qKlxuICogRnJhbWUgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIGRvY3VtZW50LnJlYWR5U3RhdGUgaWYgZnJhbWUgZG91bWVudCBzdGF0ZSBpcyAnaW50ZXJhY3RpdmUnIG9yICdjb21wbGV0ZScsIGZhbHNlIG90aGVyd2lzZVxuICpcbiAqIEByZXR1cm4ge1N0cmluZ3xCb29sZWFufVxuICovXG5mdW5jdGlvbiBGcmFtZSRpc1JlYWR5KCkge1xuICAgIHZhciByZWFkeVN0YXRlID0gdGhpcy5nZXRXaW5kb3coKS5kb2N1bWVudC5yZWFkeVN0YXRlO1xuICAgIHJldHVybiAgcmVhZHlTdGF0ZSAhPSAnbG9hZGluZycgPyByZWFkeVN0YXRlIDogZmFsc2U7XG59XG5cblxuLyoqXG4gKiBGcmFtZSBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgdHJ1ZSBpZiBtaWxvIGlzIGxvYWRlZCBhbmQgaGFzIGZpbmlzaGVkIGluaXRpYWxpemluZyBpbnNpZGUgdGhlIGZyYW1lXG4gKlxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gRnJhbWUkaXNNaWxvUmVhZHkoKSB7XG4gICAgdmFyIGZyYW1lTWlsbyA9IHRoaXMuZ2V0V2luZG93KCkubWlsbztcbiAgICByZXR1cm4gdGhpcy5pc1JlYWR5KCkgJiYgZnJhbWVNaWxvICYmIGZyYW1lTWlsby5taWxvX3ZlcnNpb247XG59XG5cblxuLyoqXG4gKiBHaXZlcyBhY2Nlc3MgdG8gbWlsbyBpbiB0aGUgZnJhbWUgKGFzc3VtaW5nIGl0IGlzIGxvYWRlZCB0aGVyZSlcbiAqIENhbGxzIGZ1bmN0aW9uIHdoZW4gYm90aCBtaWxvIGFuZCBET00gYXJlIHJlYWR5IGlmIGZ1bmN0aW9uIGlzIHBhc3NlZC5cbiAqIFJldHVybnMgdGhlIHJlZmVyZW5jZSB0byBtaWxvIGluc2lkZSB0aGUgZnJhbWUgaWYgdGhlIHdpbmRvdyBpcyBhbHJlYWR5IGF2YWlsYWJsZS5cbiAqIFxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBmdW5jdGlvbiB0byBiZSBjYWxsZWQgd2hlbiBtaWxvIGFuZCBET00gYXJlIHJlYWR5IGluIHRoZSBmcmFtZVxuICogQHJldHVybiB7RnVuY3Rpb259IHJlZmVyZW5jZSB0byBtaWxvIGluIHRoZSBmcmFtZSBcbiAqL1xuZnVuY3Rpb24gRnJhbWUkbWlsbyhmdW5jKSB7XG4gICAgaWYgKHR5cGVvZiBmdW5jID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICB0aGlzLndoZW5NaWxvUmVhZHkoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBzZWxmLmdldFdpbmRvdygpLm1pbG8oZnVuYylcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHZhciB3aW4gPSB0aGlzLmdldFdpbmRvdygpO1xuICAgIHJldHVybiB3aW4gJiYgd2luLm1pbG87XG59XG5cblxuZnVuY3Rpb24gX21ha2VXaGVuUmVhZHlGdW5jKGlzUmVhZHlGdW5jLCBldmVudCkge1xuICAgIHJldHVybiBmdW5jdGlvbiBGcmFtZV93aGVuUmVhZHlGdW5jKGZ1bmMpIHsgLy8gLCBhcmd1bWVudHNcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzXG4gICAgICAgICAgICAsIGFyZ3MgPSBfLnNsaWNlKGFyZ3VtZW50cywgMSk7XG4gICAgICAgIGlmIChpc1JlYWR5RnVuYy5jYWxsKHRoaXMpKVxuICAgICAgICAgICAgY2FsbEZ1bmMoKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgdGhpcy5vbihldmVudCwgY2FsbEZ1bmMpO1xuXG4gICAgICAgIGZ1bmN0aW9uIGNhbGxGdW5jKCkge1xuICAgICAgICAgICAgZnVuYy5hcHBseShzZWxmLCBhcmdzKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgQ29tcG9uZW50RmFjZXQgPSByZXF1aXJlKCcuLi9jX2ZhY2V0JylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jZl9yZWdpc3RyeScpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNb2RlbCA9IG1pbG9Db3JlLk1vZGVsXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIG1pbG9NYWlsID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZXMvbWFpbCcpO1xuXG5cbnZhciBJdGVtRmFjZXQgPSBfLmNyZWF0ZVN1YmNsYXNzKENvbXBvbmVudEZhY2V0LCAnSXRlbScpO1xuXG5fLmV4dGVuZFByb3RvKEl0ZW1GYWNldCwge1xuICAgIGdldFN0YXRlOiBJdGVtRmFjZXQkZ2V0U3RhdGUsXG4gICAgc2V0U3RhdGU6IEl0ZW1GYWNldCRzZXRTdGF0ZSxcbiAgICBnZXRJbmRleDogSXRlbUZhY2V0JGdldEluZGV4LFxuICAgIHNldEluZGV4OiBJdGVtRmFjZXQkc2V0SW5kZXgsXG4gICAgcmVtb3ZlSXRlbTogSXRlbUZhY2V0JHJlbW92ZUl0ZW0sXG4gICAgZXh0cmFjdEl0ZW06IEl0ZW1GYWNldCRleHRyYWN0SXRlbSxcbiAgICByZXF1aXJlOiBbJ0NvbnRhaW5lcicsICdEb20nLCAnRGF0YSddXG59KTtcblxuZmFjZXRzUmVnaXN0cnkuYWRkKEl0ZW1GYWNldCk7XG5cbm1vZHVsZS5leHBvcnRzID0gSXRlbUZhY2V0O1xuXG5cbmZ1bmN0aW9uIEl0ZW1GYWNldCRnZXRTdGF0ZSgpIHtcbiAgICByZXR1cm4geyBzdGF0ZToge1xuICAgICAgICBpbmRleDogdGhpcy5nZXRJbmRleCgpXG4gICAgfX07XG59XG5cblxuZnVuY3Rpb24gSXRlbUZhY2V0JHNldFN0YXRlKHN0YXRlKSB7XG4gICAgdGhpcy5zZXRJbmRleChzdGF0ZS5zdGF0ZS5pbmRleCk7XG59XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgdGhlIGluZGV4IG9mIHRoZSBvd25lciBjb21wb25lbnQgaW4gaXQncyBwYXJlbnQgbGlzdCBjb21wb25lbnRcbiAqIEByZXR1cm4ge0ludGVnZXJ9IFRoZSBpbmRleFxuICovXG5mdW5jdGlvbiBJdGVtRmFjZXQkZ2V0SW5kZXgoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW5kZXg7XG59XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFNldHMgdGhlIGluZGV4IG9mIHRoaXMgY29tcG9uZW50XG4gKiBAcGFyYW0ge0ludGVnZXJ9IGluZGV4IFRoZSBpbmRleCB0byBiZSBzZXRcbiAqL1xuZnVuY3Rpb24gSXRlbUZhY2V0JHNldEluZGV4KGluZGV4KSB7XG4gICAgdGhpcy5pbmRleCA9IGluZGV4O1xufVxuXG5cbi8qKlxuICogSXRlbUZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogUmVtb3ZlcyBjb21wb25lbnQgZnJvbSB0aGUgbGlzdCwgY29tcG9uZW50IGdldHMgZGVzdHJveWVkXG4gKi9cbmZ1bmN0aW9uIEl0ZW1GYWNldCRyZW1vdmVJdGVtKCkge1xuICAgIC8vIHRoaXMubGlzdCBhbmQgdGhpcy5pbmRleCBhcmUgc2V0IGJ5IHRoZSBsaXN0IHdoZW4gdGhlIGl0ZW0gaXMgYWRkZWRcbiAgICB0aGlzLmxpc3QucmVtb3ZlSXRlbSh0aGlzLmluZGV4KTtcbn1cblxuXG4vKipcbiAqIEl0ZW1GYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJlbW92ZXMgY29tcG9uZW50IGZyb20gdGhlIGxpc3QsIGNvbXBvbmVudCBpcyBOT1QgZGVzdHJveWVkXG4gKi9cbmZ1bmN0aW9uIEl0ZW1GYWNldCRleHRyYWN0SXRlbSgpIHtcbiAgICB0aGlzLmxpc3QuZXh0cmFjdEl0ZW0odGhpcy5pbmRleCk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnRGYWNldCA9IHJlcXVpcmUoJy4uL2NfZmFjZXQnKVxuICAgICwgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBmYWNldHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY2ZfcmVnaXN0cnknKVxuICAgICwgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvXG4gICAgLCBtaWxvTWFpbCA9IHJlcXVpcmUoJy4uLy4uL3NlcnZpY2VzL21haWwnKVxuICAgICwgbWlsb0JpbmRlciA9IHJlcXVpcmUoJy4uLy4uL2JpbmRlcicpXG4gICAgLCBsb2dnZXIgPSBtaWxvQ29yZS51dGlsLmxvZ2dlclxuICAgICwgZG9UID0gbWlsb0NvcmUudXRpbC5kb1RcbiAgICAsIGNoZWNrID0gbWlsb0NvcmUudXRpbC5jaGVja1xuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgZG9tVXRpbHMgPSByZXF1aXJlKCcuLi8uLi91dGlsL2RvbScpXG4gICAgLCBjb21wb25lbnROYW1lID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9jb21wb25lbnRfbmFtZScpXG4gICAgLCBtaWxvQ29uZmlnID0gcmVxdWlyZSgnLi4vLi4vY29uZmlnJyk7XG5cblxudmFyIExJU1RfU0FNUExFX0NTU19DTEFTUyA9ICdtbC1saXN0LWl0ZW0tc2FtcGxlJztcblxuLyoqXG4gKiBgbWlsby5yZWdpc3RyeS5mYWNldHMuZ2V0KCdMaXN0JylgXG4gKiBGYWNldCBlbmFibGluZyBsaXN0IGZ1bmN0aW9uYWxpdHlcbiAqL1xudmFyIExpc3QgPSBfLmNyZWF0ZVN1YmNsYXNzKENvbXBvbmVudEZhY2V0LCAnTGlzdCcpO1xuXG5fLmV4dGVuZFByb3RvKExpc3QsIHtcbiAgICBpbml0OiBMaXN0JGluaXQsXG4gICAgc3RhcnQ6IExpc3Qkc3RhcnQsXG4gICAgZGVzdHJveTogTGlzdCRkZXN0cm95LFxuXG4gICAgcmVxdWlyZTogWydDb250YWluZXInLCAnRG9tJywgJ0RhdGEnXSxcbiAgICBfaXRlbVByZXZpb3VzQ29tcG9uZW50OiBfaXRlbVByZXZpb3VzQ29tcG9uZW50LFxuXG4gICAgaXRlbTogTGlzdCRpdGVtLFxuICAgIGNvdW50OiBMaXN0JGNvdW50LFxuICAgIGNvbnRhaW5zOiBMaXN0JGNvbnRhaW5zLFxuICAgIGFkZEl0ZW06IExpc3QkYWRkSXRlbSxcbiAgICBhZGRJdGVtczogTGlzdCRhZGRJdGVtcyxcbiAgICByZXBsYWNlSXRlbTogTGlzdCRyZXBsYWNlSXRlbSxcbiAgICByZW1vdmVJdGVtOiBMaXN0JHJlbW92ZUl0ZW0sXG4gICAgZXh0cmFjdEl0ZW06IExpc3QkZXh0cmFjdEl0ZW0sXG4gICAgZWFjaDogTGlzdCRlYWNoLFxuICAgIF9zZXRJdGVtOiBMaXN0JF9zZXRJdGVtLFxuICAgIF9yZW1vdmVJdGVtOiBMaXN0JF9yZW1vdmVJdGVtLFxuICAgIF9hZGRJdGVtOiBMaXN0JF9hZGRJdGVtLFxuICAgIF9hZGRJdGVtczogTGlzdCRfYWRkSXRlbXMsXG4gICAgX2NyZWF0ZUNhY2hlVGVtcGxhdGU6IExpc3QkX2NyZWF0ZUNhY2hlVGVtcGxhdGUsXG4gICAgX3VwZGF0ZURhdGFQYXRoczogTGlzdCRfdXBkYXRlRGF0YVBhdGhzXG59KTtcblxuZmFjZXRzUmVnaXN0cnkuYWRkKExpc3QpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IExpc3Q7XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIEluaXRpYWxpemVkIExpc3QgZmFjZXQgaW5zdGFuY2UgYW5kIHNldHMgdXAgaXRlbSBwcm9wZXJ0aWVzLlxuICovXG5mdW5jdGlvbiBMaXN0JGluaXQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICBfbGlzdEl0ZW1zOiBbXSxcbiAgICAgICAgX2xpc3RJdGVtc0hhc2g6IHt9XG4gICAgfSk7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnaXRlbVNhbXBsZScsIG51bGwsIF8uV1JJVCk7XG59XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFN0YXJ0cyB0aGUgTGlzdCBmYWNldCBpbnN0YW5jZSwgZmluZHMgY2hpbGQgd2l0aCBJdGVtIGZhY2V0LlxuICovXG5mdW5jdGlvbiBMaXN0JHN0YXJ0KCkge1xuICAgIC8vIEZpcmVkIGJ5IF9fYmluZGVyX18gd2hlbiBhbGwgY2hpbGRyZW4gb2YgY29tcG9uZW50IGFyZSBib3VuZFxuICAgIHRoaXMub3duZXIub24oJ2NoaWxkcmVuYm91bmQnLCBvbkNoaWxkcmVuQm91bmQpO1xufVxuXG5cbmZ1bmN0aW9uIG9uQ2hpbGRyZW5Cb3VuZCgpIHtcbiAgICAvLyBnZXQgaXRlbXMgYWxyZWFkeSBpbiB0aGUgbGlzdFxuICAgIHZhciBjaGlsZHJlbiA9IHRoaXMuZG9tLmNoaWxkcmVuKClcbiAgICAgICAgLCBpdGVtcyA9IHRoaXMubGlzdC5fbGlzdEl0ZW1zXG4gICAgICAgICwgaXRlbXNIYXNoID0gdGhpcy5saXN0Ll9saXN0SXRlbXNIYXNoO1xuXG4gICAgY2hpbGRyZW4gJiYgY2hpbGRyZW4uZm9yRWFjaChmdW5jdGlvbihjaGlsZEVsKSB7XG4gICAgICAgIHZhciBjb21wID0gQ29tcG9uZW50LmdldENvbXBvbmVudChjaGlsZEVsKTtcbiAgICAgICAgaWYgKGNvbXAgJiYgY29tcC5pdGVtKSB7XG4gICAgICAgICAgICBpdGVtcy5wdXNoKGNvbXApO1xuICAgICAgICAgICAgaXRlbXNIYXNoW2NvbXAubmFtZV0gPSBjb21wO1xuICAgICAgICAgICAgY29tcC5pdGVtLmxpc3QgPSB0aGlzLmxpc3Q7XG4gICAgICAgIH1cbiAgICB9LCB0aGlzKTtcblxuICAgIGlmIChpdGVtcy5sZW5ndGgpIHtcbiAgICAgICAgdmFyIGZvdW5kSXRlbSA9IGl0ZW1zWzBdO1xuICAgICAgICBpdGVtcy5zcGxpY2UoMCwgMSk7XG4gICAgICAgIGRlbGV0ZSBpdGVtc0hhc2hbZm91bmRJdGVtLm5hbWVdO1xuICAgICAgICBpdGVtcy5mb3JFYWNoKGZ1bmN0aW9uKGl0ZW0sIGluZGV4KSB7XG4gICAgICAgICAgICBpdGVtLml0ZW0uc2V0SW5kZXgoaW5kZXgpO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgLy8gQ29tcG9uZW50IG11c3QgaGF2ZSBvbmUgY2hpbGQgd2l0aCBhbiBJdGVtIGZhY2V0IFxuICAgIGlmICghIGZvdW5kSXRlbSkgdGhyb3cgbmV3IEVycm9yKCdObyBjaGlsZCBjb21wb25lbnQgaGFzIEl0ZW0gZmFjZXQnKTtcblxuICAgIHRoaXMubGlzdC5pdGVtU2FtcGxlID0gZm91bmRJdGVtO1xuXG4gICAgLy8gQWZ0ZXIga2VlcGluZyBhIHJlZmVyZW5jZSB0byB0aGUgaXRlbSBzYW1wbGUsIGl0IG11c3QgYmUgaGlkZGVuIGFuZCByZW1vdmVkIGZyb20gc2NvcGVcbiAgICBmb3VuZEl0ZW0uZG9tLmhpZGUoKTtcbiAgICBmb3VuZEl0ZW0ucmVtb3ZlKHRydWUpO1xuICAgIGZvdW5kSXRlbS5kb20ucmVtb3ZlQ3NzQ2xhc3NlcyhMSVNUX1NBTVBMRV9DU1NfQ0xBU1MpO1xuXG4gICAgLy8gcmVtb3ZlIHJlZmVyZW5jZXMgdG8gY29tcG9uZW50cyBmcm9tIHNhbXBsZSBpdGVtXG4gICAgZm91bmRJdGVtLndhbGtTY29wZVRyZWUoZnVuY3Rpb24oY29tcCkge1xuICAgICAgICBkZWxldGUgY29tcC5lbFttaWxvQ29uZmlnLmNvbXBvbmVudFJlZl07XG4gICAgfSk7XG5cbiAgICB0aGlzLmxpc3QuX2NyZWF0ZUNhY2hlVGVtcGxhdGUoKTtcbn1cblxuXG5mdW5jdGlvbiBMaXN0JF9jcmVhdGVDYWNoZVRlbXBsYXRlKCkge1xuICAgIGlmICghdGhpcy5pdGVtU2FtcGxlKSByZXR1cm4gZmFsc2U7XG4gICAgXG4gICAgdmFyIGl0ZW1TYW1wbGUgPSB0aGlzLml0ZW1TYW1wbGU7XG5cbiAgICAvLyBjcmVhdGUgaXRlbSB0ZW1wbGF0ZSB0byBpbnNlcnQgbWFueSBpdGVtcyBhdCBvbmNlXG4gICAgdmFyIGl0ZW1FbENvcHkgPSBpdGVtU2FtcGxlLmVsLmNsb25lTm9kZSh0cnVlKTtcbiAgICB2YXIgYXR0ciA9IGl0ZW1TYW1wbGUuY29tcG9uZW50SW5mby5hdHRyO1xuICAgIHZhciBhdHRyQ29weSA9IF8uY2xvbmUoYXR0cik7XG4gICAgYXR0ci5jb21wTmFtZSA9ICd7ez0gaXQuY29tcG9uZW50TmFtZSgpIH19JztcbiAgICBhdHRyLmVsID0gaXRlbUVsQ29weTtcbiAgICBhdHRyLmRlY29yYXRlKCk7XG5cbiAgICB2YXIgaXRlbXNUZW1wbGF0ZVN0ciA9IFxuICAgICAgICAgICd7eyB2YXIgaSA9IGl0LmNvdW50OyB3aGlsZShpLS0pIHsgfX0nXG4gICAgICAgICsgaXRlbUVsQ29weS5vdXRlckhUTUxcbiAgICAgICAgKyAne3sgfSB9fSc7XG5cbiAgICB0aGlzLml0ZW1zVGVtcGxhdGUgPSBkb1QuY29tcGlsZShpdGVtc1RlbXBsYXRlU3RyKTtcbn1cblxuXG4vKipcbiAqIEZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogUmV0cmlldmUgYSBwYXJ0aWN1bGFyIGNoaWxkIGl0ZW0gYnkgaW5kZXhcbiAqIEBwYXJhbSB7SW50ZWdlcn0gaW5kZXggVGhlIGluZGV4IG9mIHRoZSBjaGlsZCBpdGVtIHRvIGdldC5cbiAqIEByZXR1cm4ge0NvbXBvbmVudH0gVGhlIGNvbXBvbmVudCBmb3VuZFxuICovXG5mdW5jdGlvbiBMaXN0JGl0ZW0oaW5kZXgpIHtcbiAgICByZXR1cm4gdGhpcy5fbGlzdEl0ZW1zW2luZGV4XTtcbn1cblxuXG4vKipcbiAqIEZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogR2V0cyB0aGUgdG90YWwgbnVtYmVyIG9mIGNoaWxkIGl0ZW1zXG4gKiBAcmV0dXJuIHtJbnRlZ2VyfSBUaGUgdG90YWxcbiAqL1xuZnVuY3Rpb24gTGlzdCRjb3VudCgpIHtcbiAgICByZXR1cm4gdGhpcy5fbGlzdEl0ZW1zLmxlbmd0aDtcbn1cblxuXG5mdW5jdGlvbiBMaXN0JF9zZXRJdGVtKGluZGV4LCBjb21wb25lbnQpIHtcbiAgICB0aGlzLl9saXN0SXRlbXMuc3BsaWNlKGluZGV4LCAwLCBjb21wb25lbnQpO1xuICAgIHRoaXMuX2xpc3RJdGVtc0hhc2hbY29tcG9uZW50Lm5hbWVdID0gY29tcG9uZW50O1xuICAgIGNvbXBvbmVudC5pdGVtLmxpc3QgPSB0aGlzO1xuICAgIGNvbXBvbmVudC5pdGVtLnNldEluZGV4KCtpbmRleCk7XG59XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgdHJ1ZSBpZiBhIHBhcnRpY3VsYXIgY2hpbGQgaXRlbSBleGlzdHMgaW4gdGhlIGxpc3RcbiAqIEBwYXJhbSB7Q29tcG9uZW50fSBjb21wb25lbnQgVGhlIGNvbXBvbmVudCB0byBsb29rIGZvci5cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIExpc3QkY29udGFpbnMoY29tcG9uZW50KSB7XG4gICAgcmV0dXJuIHRoaXMuX2xpc3RJdGVtc0hhc2hbY29tcG9uZW50Lm5hbWVdID09IGNvbXBvbmVudDtcbn1cblxuXG4vKipcbiAqIEZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogQWRkcyBhIG5ldyBjaGlsZCBjb21wb25lbnQgYXQgYSBwYXJ0aWN1bGFyIGluZGV4IGFuZCByZXR1cm5zIHRoZSBuZXcgY29tcG9uZW50LlxuICogVGhpcyBtZXRob2QgdXNlcyBkYXRhIGZhY2V0LCBzbyBub3RpZmljYXRpb24gd2lsbCBiZSBlbWl0dGVkIG9uIGRhdGEgZmFjZXQuXG4gKiBAcGFyYW0ge0ludGVnZXJ9IGluZGV4IFRoZSBpbmRleCB0byBhZGQgYXRcbiAqIEByZXR1cm4ge0NvbXBvbmVudH0gVGhlIG5ld2x5IGNyZWF0ZWQgY29tcG9uZW50XG4gKi9cbmZ1bmN0aW9uIExpc3QkYWRkSXRlbShpbmRleCwgaXRlbURhdGEpIHtcbiAgICBpbmRleCA9IGluZGV4IHx8IHRoaXMuY291bnQoKTtcbiAgICB0aGlzLm93bmVyLmRhdGEuc3BsaWNlKGluZGV4LCAwLCBpdGVtRGF0YSB8fCB7fSk7XG4gICAgcmV0dXJuIHRoaXMuaXRlbShpbmRleCk7XG59XG5cblxuLyoqXG4gKiBGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIEFkZHMgYSBuZXcgY2hpbGQgY29tcG9uZW50IGF0IGEgcGFydGljdWxhciBpbmRleCBhbmQgcmV0dXJucyB0aGUgbmV3IGNvbXBvbmVudFxuICogQHBhcmFtIHtJbnRlZ2VyfSBpbmRleCBUaGUgaW5kZXggdG8gYWRkIGF0XG4gKiBAcmV0dXJuIHtDb21wb25lbnR9IFRoZSBuZXdseSBjcmVhdGVkIGNvbXBvbmVudFxuICovXG5mdW5jdGlvbiBMaXN0JF9hZGRJdGVtKGluZGV4KSB7XG4gICAgaW5kZXggPSBpbmRleCB8fCB0aGlzLmNvdW50KCk7XG4gICAgaWYgKHRoaXMuaXRlbShpbmRleCkpXG4gICAgICAgIHRocm93IEVycm9yKCdhdHRlbXB0IHRvIGNyZWF0ZSBpdGVtIHdpdGggSUQgb2YgZXhpc3RpbmcgaXRlbScpO1xuXG4gICAgLy8gQ29weSBjb21wb25lbnRcbiAgICB2YXIgY29tcG9uZW50ID0gQ29tcG9uZW50LmNvcHkodGhpcy5pdGVtU2FtcGxlLCB0cnVlKTtcbiAgICB2YXIgcHJldkNvbXBvbmVudCA9IHRoaXMuX2l0ZW1QcmV2aW91c0NvbXBvbmVudChpbmRleCk7XG5cbiAgICBpZiAoIXByZXZDb21wb25lbnQuZWwucGFyZW50Tm9kZSlcbiAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdsaXN0IGl0ZW0gc2FtcGxlIHdhcyByZW1vdmVkIGZyb20gRE9NLCBwcm9iYWJseSBjYXVzZWQgYnkgd3JvbmcgZGF0YS4gUmVzZXQgbGlzdCBkYXRhIHdpdGggYXJyYXknKTtcblxuICAgIC8vIEFkZCBpdCB0byB0aGUgRE9NXG4gICAgcHJldkNvbXBvbmVudC5kb20uaW5zZXJ0QWZ0ZXIoY29tcG9uZW50LmVsKTtcblxuICAgIC8vIEFkZCB0byBsaXN0IGl0ZW1zXG4gICAgdGhpcy5fc2V0SXRlbShpbmRleCwgY29tcG9uZW50KTtcblxuICAgIC8vIFNob3cgdGhlIGxpc3QgaXRlbSBjb21wb25lbnRcbiAgICBjb21wb25lbnQuZWwuc3R5bGUuZGlzcGxheSA9ICcnO1xuXG4gICAgX3VwZGF0ZUl0ZW1zSW5kZXhlcy5jYWxsKHRoaXMsIGluZGV4ICsgMSk7XG5cbiAgICByZXR1cm4gY29tcG9uZW50O1xufVxuXG5cbmZ1bmN0aW9uIF91cGRhdGVJdGVtc0luZGV4ZXMoZnJvbUluZGV4LCB0b0luZGV4KSB7XG4gICAgZnJvbUluZGV4ID0gZnJvbUluZGV4IHx8IDA7XG4gICAgdG9JbmRleCA9IHRvSW5kZXggfHwgdGhpcy5jb3VudCgpO1xuICAgIGZvciAodmFyIGkgPSBmcm9tSW5kZXg7IGkgPCB0b0luZGV4OyBpKyspIHtcbiAgICAgICAgdmFyIGNvbXBvbmVudCA9IHRoaXMuX2xpc3RJdGVtc1tpXTtcbiAgICAgICAgaWYgKGNvbXBvbmVudClcbiAgICAgICAgICAgIGNvbXBvbmVudC5pdGVtLnNldEluZGV4KGkpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBsb2dnZXIud2FybignTGlzdDogbm8gaXRlbSBhdCBwb3NpdGlvbicsIGkpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBMaXN0JGFkZEl0ZW1zKGNvdW50LCBpbmRleCkgeyAvLyAsLi4uIGl0ZW1zIGRhdGFcbiAgICB2YXIgaXRlbXNEYXRhID0gXy5zbGljZShhcmd1bWVudHMsIDIpO1xuICAgIGlmIChpdGVtc0RhdGEubGVuZ3RoIDwgY291bnQpIFxuICAgICAgICBpdGVtc0RhdGEuY29uY2F0KF8ucmVwZWF0KGNvdW50IC0gaXRlbXNEYXRhLmxlbmd0aCwge30pKTtcbiAgICB2YXIgc3BsaWNlQXJncyA9IFtpbmRleCwgMF0uY29uY2F0KGl0ZW1zRGF0YSk7XG4gICAgdmFyIGRhdGFGYWNldCA9IHRoaXMub3duZXIuZGF0YTtcbiAgICBkYXRhRmFjZXQuc3BsaWNlLmFwcGx5KGRhdGFGYWNldCwgc3BsaWNlQXJncyk7XG59XG5cblxuLyoqXG4gKiBMaXN0IGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogQWRkcyBhIGdpdmVuIG51bWJlciBvZiBpdGVtcyB1c2luZyB0ZW1wbGF0ZSByZW5kZXJpbmcgcmF0aGVyIHRoYW4gYWRkaW5nIGVsZW1lbnRzIG9uZSBieSBvbmVcbiAqXG4gKiBAcGFyYW0ge0ludGVnZXJ9IGNvdW50IG51bWJlciBvZiBpdGVtcyB0byBhZGRcbiAqIEBwYXJhbSB7W0ludGVnZXJdfSBpbmRleCBvcHRpb25hbCBpbmRleCBvZiBpdGVtIGFmdGVyIHdoaWNoIHRvIGFkZFxuICovXG5mdW5jdGlvbiBMaXN0JF9hZGRJdGVtcyhjb3VudCwgaW5kZXgpIHtcbiAgICBjaGVjayhjb3VudCwgTWF0Y2guSW50ZWdlcik7XG4gICAgaWYgKGNvdW50IDwgMClcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5cXCd0IGFkZCBuZWdhdGl2ZSBudW1iZXIgb2YgaXRlbXMnKTtcblxuICAgIGlmIChjb3VudCA9PSAwKSByZXR1cm47XG5cbiAgICB2YXIgaXRlbXNIVE1MID0gdGhpcy5pdGVtc1RlbXBsYXRlKHtcbiAgICAgICAgY29tcG9uZW50TmFtZTogY29tcG9uZW50TmFtZSxcbiAgICAgICAgY291bnQ6IGNvdW50XG4gICAgfSk7XG5cbiAgICB2YXIgd3JhcEVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgd3JhcEVsLmlubmVySFRNTCA9IGl0ZW1zSFRNTDtcblxuICAgIG1pbG9CaW5kZXIod3JhcEVsLCB0aGlzLm93bmVyLmNvbnRhaW5lci5zY29wZSk7XG4gICAgdmFyIGNoaWxkcmVuID0gZG9tVXRpbHMuY2hpbGRyZW4od3JhcEVsKTtcblxuICAgIGlmIChjb3VudCAhPSBjaGlsZHJlbi5sZW5ndGgpXG4gICAgICAgIGxvZ2dlci5lcnJvcignbnVtYmVyIG9mIGl0ZW1zIGFkZGVkIGlzIGRpZmZlcmVudCBmcm9tIHJlcXVlc3RlZCcpO1xuXG4gICAgaWYgKGNoaWxkcmVuICYmIGNoaWxkcmVuLmxlbmd0aCkge1xuICAgICAgICB2YXIgbGlzdExlbmd0aCA9IHRoaXMuY291bnQoKTtcbiAgICAgICAgdmFyIHNwbGljZUluZGV4ID0gaW5kZXggPCAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgOiB0eXBlb2YgaW5kZXggPT0gJ3VuZGVmaW5lZCcgfHwgaW5kZXggPiBsaXN0TGVuZ3RoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gbGlzdExlbmd0aFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IGluZGV4O1xuXG4gICAgICAgIHZhciBwcmV2Q29tcG9uZW50ID0gc3BsaWNlSW5kZXggPT0gMFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IHRoaXMuaXRlbVNhbXBsZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHRoaXMuX2xpc3RJdGVtc1tzcGxpY2VJbmRleCAtIDFdO1xuXG4gICAgICAgIHZhciBmcmFnID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpXG4gICAgICAgICAgICAsIG5ld0NvbXBvbmVudHMgPSBbXTtcblxuICAgICAgICBjaGlsZHJlbi5mb3JFYWNoKGZ1bmN0aW9uKGVsLCBpKSB7XG4gICAgICAgICAgICB2YXIgY29tcG9uZW50ID0gQ29tcG9uZW50LmdldENvbXBvbmVudChlbCk7XG4gICAgICAgICAgICBpZiAoISBjb21wb25lbnQpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGxvZ2dlci5lcnJvcignTGlzdDogZWxlbWVudCBpbiBuZXcgaXRlbXMgaXMgbm90IGEgY29tcG9uZW50Jyk7XG4gICAgICAgICAgICBuZXdDb21wb25lbnRzLnB1c2goY29tcG9uZW50KTtcbiAgICAgICAgICAgIHRoaXMuX3NldEl0ZW0oc3BsaWNlSW5kZXgrKywgY29tcG9uZW50KTtcbiAgICAgICAgICAgIGZyYWcuYXBwZW5kQ2hpbGQoZWwpO1xuICAgICAgICAgICAgZWwuc3R5bGUuZGlzcGxheSA9ICcnO1xuICAgICAgICB9LCB0aGlzKTtcblxuICAgICAgICBfdXBkYXRlSXRlbXNJbmRleGVzLmNhbGwodGhpcywgc3BsaWNlSW5kZXgpO1xuXG4gICAgICAgIGlmICghcHJldkNvbXBvbmVudC5lbC5wYXJlbnROb2RlKVxuICAgICAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdsaXN0IGl0ZW0gc2FtcGxlIHdhcyByZW1vdmVkIGZyb20gRE9NLCBwcm9iYWJseSBjYXVzZWQgYnkgd3JvbmcgZGF0YS4gUmVzZXQgbGlzdCBkYXRhIHdpdGggYXJyYXknKTtcblxuICAgICAgICAvLyBBZGQgaXQgdG8gdGhlIERPTVxuICAgICAgICBwcmV2Q29tcG9uZW50LmRvbS5pbnNlcnRBZnRlcihmcmFnKTtcblxuICAgICAgICBfLmRlZmVyTWV0aG9kKG5ld0NvbXBvbmVudHMsICdmb3JFYWNoJywgZnVuY3Rpb24oY29tcCkge1xuICAgICAgICAgICAgY29tcC5icm9hZGNhc3QoJ3N0YXRlcmVhZHknKTtcbiAgICAgICAgfSk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogTGlzdCBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIEBwYXJhbSB7SW50ZWdlcn0gaW5kZXggVGhlIGluZGV4IG9mIHRoZSBpdGVtIHRvIHJlbW92ZVxuICogQHJldHVybiB7QXJyYXlbT2JqZWN0XX0gVGhlIHNwbGljZWQgZGF0YVxuICovXG5mdW5jdGlvbiBMaXN0JHJlbW92ZUl0ZW0oaW5kZXgpIHtcbiAgICByZXR1cm4gdGhpcy5vd25lci5kYXRhLnNwbGljZShpbmRleCwgMSk7XG59XG5cblxuLyoqXG4gKiBMaXN0IGZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogQHBhcmFtIHtJbnRlZ2VyfSBpbmRleCBUaGUgaW5kZXggb2YgdGhlIGl0ZW0gdG8gZXh0cmFjdFxuICogQHJldHVybiB7Q29tcG9uZW50fSBUaGUgZXh0cmFjdGVkIGl0ZW1cbiAqL1xuZnVuY3Rpb24gTGlzdCRleHRyYWN0SXRlbShpbmRleCkge1xuICAgIHZhciBpdGVtQ29tcCA9IHRoaXMuX3JlbW92ZUl0ZW0oaW5kZXgsIGZhbHNlKTtcbiAgICB0aGlzLl91cGRhdGVEYXRhUGF0aHMoaW5kZXgsIHRoaXMuY291bnQoKSk7XG4gICAgcmV0dXJuIGl0ZW1Db21wO1xufVxuXG5cbi8qKlxuICogTGlzdCBmYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIFJlbW92ZXMgaXRlbSwgcmV0dXJucyB0aGUgcmVtb3ZlZCBpdGVtIHRoYXQgaXMgZGVzdHJveWVkIGJ5IGRlZmF1bHQuXG4gKiBcbiAqIEBwYXJhbSAge051bWJlcn0gaW5kZXggaXRlbSBpbmRleFxuICogQHBhcmFtICB7Qm9vbGVhbn0gZG9EZXN0cm95SXRlbSBvcHRpb25hbCBmYWxzZSB0byBwcmV2ZW50IGl0ZW0gZGVzdHJ1Y3Rpb24sIHRydWUgYnkgZGVmYXVsdFxuICogQHJldHVybiB7Q29tcG9uZW50fVxuICovXG5mdW5jdGlvbiBMaXN0JF9yZW1vdmVJdGVtKGluZGV4LCBkb0Rlc3Ryb3lJdGVtKSB7XG4gICAgdmFyIGNvbXAgPSB0aGlzLml0ZW0oaW5kZXgpO1xuXG4gICAgaWYgKCEgY29tcClcbiAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdhdHRlbXB0IHRvIHJlbW92ZSBsaXN0IGl0ZW0gd2l0aCBpZCB0aGF0IGRvZXMgbm90IGV4aXN0Jyk7XG5cbiAgICB0aGlzLl9saXN0SXRlbXNbaW5kZXhdID0gdW5kZWZpbmVkO1xuICAgIGRlbGV0ZSB0aGlzLl9saXN0SXRlbXNIYXNoW2NvbXAubmFtZV07XG4gICAgaWYgKGRvRGVzdHJveUl0ZW0gIT09IGZhbHNlKSBjb21wLmRlc3Ryb3koKTtcbiAgICBlbHNlIHtcbiAgICAgICAgY29tcC5yZW1vdmUoKTtcbiAgICAgICAgY29tcC5kb20ucmVtb3ZlKCk7XG4gICAgfVxuXG4gICAgdGhpcy5fbGlzdEl0ZW1zLnNwbGljZShpbmRleCwgMSk7XG4gICAgX3VwZGF0ZUl0ZW1zSW5kZXhlcy5jYWxsKHRoaXMsIGluZGV4KTtcblxuICAgIHJldHVybiBjb21wO1xufVxuXG5cbmZ1bmN0aW9uIExpc3QkcmVwbGFjZUl0ZW0oaW5kZXgsIG5ld0l0ZW0pe1xuICAgIHZhciBvbGRJdGVtID0gdGhpcy5pdGVtKGluZGV4KTtcbiAgICBvbGRJdGVtLmRvbS5pbnNlcnRBZnRlcihuZXdJdGVtLmVsKTtcbiAgICB0aGlzLl9yZW1vdmVJdGVtKGluZGV4KTtcbiAgICB0aGlzLl9zZXRJdGVtKGluZGV4LCBuZXdJdGVtKTtcbn1cblxuXG4vLyBSZXR1cm5zIHRoZSBwcmV2aW91cyBpdGVtIGNvbXBvbmVudCBnaXZlbiBhbiBpbmRleFxuZnVuY3Rpb24gX2l0ZW1QcmV2aW91c0NvbXBvbmVudChpbmRleCkge1xuICAgIHdoaWxlIChpbmRleCA+PSAwICYmICEgdGhpcy5fbGlzdEl0ZW1zW2luZGV4XSlcbiAgICAgICAgaW5kZXgtLTtcblxuICAgIHJldHVybiBpbmRleCA+PSAwXG4gICAgICAgICAgICAgICAgPyB0aGlzLl9saXN0SXRlbXNbaW5kZXhdXG4gICAgICAgICAgICAgICAgOiB0aGlzLml0ZW1TYW1wbGU7XG59XG5cblxuLy8gdG9JbmRleCBpcyBub3QgaW5jbHVkZWRcbi8vIG5vIHJhbmdlIGNoZWNraW5nIGlzIG1hZGVcbmZ1bmN0aW9uIExpc3QkX3VwZGF0ZURhdGFQYXRocyhmcm9tSW5kZXgsIHRvSW5kZXgpIHtcbiAgICBmb3IgKHZhciBpID0gZnJvbUluZGV4OyBpIDwgdG9JbmRleDsgaSsrKSB7XG4gICAgICAgIHZhciBpdGVtID0gdGhpcy5pdGVtKGkpO1xuICAgICAgICBpZiAoaXRlbSlcbiAgICAgICAgICAgIGl0ZW0uZGF0YS5fcGF0aCA9ICdbJyArIGkgKyAnXSc7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKCdEYXRhOiBubyBpdGVtIGZvciBpbmRleCcsIGopO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIEZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogU2ltaWxhciB0byBmb3JFYWNoIG1ldGhvZCBvZiBBcnJheSwgaXRlcmF0ZXMgZWFjaCBvZiB0aGUgY2hpbGQgaXRlbXMuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBBbiBpdGVyYXRvciBmdW5jdGlvbiB0byBiZSBjYWxsZWQgb24gZWFjaCBjaGlsZCBpdGVtLlxuICogQHBhcmFtIHtbdHlwZV19ICAgdGhpc0FyZyAgQ29udGV4dCB0byBzZXQgYHRoaXNgLlxuICovXG5mdW5jdGlvbiBMaXN0JGVhY2goY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICB0aGlzLl9saXN0SXRlbXMuZm9yRWFjaChmdW5jdGlvbihpdGVtLCBpbmRleCkge1xuICAgICAgICBpZiAoaXRlbSkgY2FsbGJhY2suYXBwbHkodGhpcywgYXJndW1lbnRzKTsgLy8gcGFzc2VzIGl0ZW0sIGluZGV4IHRvIGNhbGxiYWNrXG4gICAgICAgIGVsc2UgbG9nZ2VyLndhcm4oJ0xpc3QkZWFjaDogaXRlbScsIGluZGV4LCAnaXMgdW5kZWZpbmVkJyk7XG4gICAgfSwgdGhpc0FyZyB8fCB0aGlzKTtcbn1cblxuXG4vKipcbiAqIEZhY2V0IGluc3RhbmNlIG1ldGhvZFxuICogRGVzdHJveXMgdGhlIGxpc3RcbiAqL1xuZnVuY3Rpb24gTGlzdCRkZXN0cm95KCkge1xuICAgIGlmICh0aGlzLml0ZW1TYW1wbGUpIHRoaXMuaXRlbVNhbXBsZS5kZXN0cm95KHRydWUpO1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnRGYWNldCA9IHJlcXVpcmUoJy4uL2NfZmFjZXQnKVxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NmX3JlZ2lzdHJ5JylcbiAgICAsIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIE1vZGVsID0gbWlsb0NvcmUuTW9kZWxcbiAgICAsIE1peGluID0gbWlsb0NvcmUuY2xhc3Nlcy5NaXhpblxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvO1xuXG5cbi8vIGdlbmVyaWMgZHJhZyBoYW5kbGVyLCBzaG91bGQgYmUgb3ZlcnJpZGRlblxudmFyIE1vZGVsRmFjZXQgPSBfLmNyZWF0ZVN1YmNsYXNzKENvbXBvbmVudEZhY2V0LCAnTW9kZWwnKTtcblxuXy5leHRlbmRQcm90byhNb2RlbEZhY2V0LCB7XG4gICAgaW5pdDogTW9kZWxGYWNldCRpbml0LFxuICAgIGdldFN0YXRlOiBNb2RlbEZhY2V0JGdldFN0YXRlLFxuICAgIHNldFN0YXRlOiBNb2RlbEZhY2V0JHNldFN0YXRlLFxuICAgIF9jcmVhdGVNZXNzZW5nZXI6IE1vZGVsRmFjZXQkX2NyZWF0ZU1lc3NlbmdlcixcbiAgICBkZXN0cm95OiBNb2RlbEZhY2V0JGRlc3Ryb3lcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoTW9kZWxGYWNldCk7XG5cbm1vZHVsZS5leHBvcnRzID0gTW9kZWxGYWNldDtcblxuXG4vKipcbiAqIEV4cG9zZSBNb2RlbCBjbGFzcyBtZXRob2RzIG9uIE1vZGVsRmFjZXRcbiAqL1xuTW9kZWwudXNlV2l0aChNb2RlbEZhY2V0LCAnbScpO1xuXG5cbmZ1bmN0aW9uIE1vZGVsRmFjZXQkaW5pdCgpIHtcbiAgICB0aGlzLm0gPSBuZXcgTW9kZWwodGhpcy5jb25maWcuZGF0YSwgdGhpcyk7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAvLyB0aGlzLm0ucHJveHlNZXRob2RzKHRoaXMpOyAvLyBDcmVhdGVzIG1vZGVsJ3MgbWV0aG9kcyBkaXJlY3RseSBvbiBmYWNldFxufVxuXG5cbi8qKlxuICogTW9kZWxGYWNldCBpbnN0YW5jZSBtZXRob2RcbiAqIENhbGxlZCBieSBgQ29tcG9uZW50LnByb3RvdHlwZS5nZXRTdGF0ZWAgdG8gZ2V0IGZhY2V0J3Mgc3RhdGVcbiAqIFNpbXBseSByZXR1cm5zIG1vZGVsIGRhdGFcbiAqXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIE1vZGVsRmFjZXQkZ2V0U3RhdGUoKSB7XG4gICAgdmFyIG1vZGVsVmFsdWUgPSB0aGlzLm0uZ2V0KCk7XG4gICAgaWYgKHR5cGVvZiBtb2RlbFZhbHVlID09ICdvYmplY3QnKVxuICAgICAgICBtb2RlbFZhbHVlID0gXy5kZWVwQ2xvbmUobW9kZWxWYWx1ZSk7XG4gICAgcmV0dXJuIHsgc3RhdGU6IG1vZGVsVmFsdWUgfTtcbn1cblxuXG4vKipcbiAqIE1vZGVsRmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBDYWxsZWQgYnkgYENvbXBvbmVudC5wcm90b3R5cGUuc2V0U3RhdGVgIHRvIHNldCBmYWNldCdzIHN0YXRlXG4gKiBTaW1wbHkgc2V0cyBtb2RlbCBkYXRhXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHN0YXRlIGRhdGEgdG8gc2V0IG9uIGZhY2V0J3MgbW9kZWxcbiAqL1xuZnVuY3Rpb24gTW9kZWxGYWNldCRzZXRTdGF0ZShzdGF0ZSkge1xuICAgIHJldHVybiB0aGlzLm0uc2V0KHN0YXRlLnN0YXRlKTtcbn1cblxuXG5mdW5jdGlvbiBNb2RlbEZhY2V0JF9jcmVhdGVNZXNzZW5nZXIoKSB7IC8vIENhbGxlZCBieSBpbmhlcml0ZWQgaW5pdFxuICAgIHRoaXMuX21lc3NlbmdlciA9IHRoaXMubS5fbWVzc2VuZ2VyO1xufVxuXG5cbmZ1bmN0aW9uIE1vZGVsRmFjZXQkZGVzdHJveSgpIHtcbiAgICB0aGlzLm0uZGVzdHJveSgpO1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnRGYWNldCA9IHJlcXVpcmUoJy4uL2NfZmFjZXQnKVxuICAgICwgZmFjZXRzUmVnaXN0cnkgPSByZXF1aXJlKCcuL2NmX3JlZ2lzdHJ5JylcbiAgICAsIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIE1vZGVsID0gbWlsb0NvcmUuTW9kZWxcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90bztcblxuXG4vLyBnZW5lcmljIGRyYWcgaGFuZGxlciwgc2hvdWxkIGJlIG92ZXJyaWRkZW5cbnZhciBPcHRpb25zID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ09wdGlvbnMnKTtcblxuXy5leHRlbmRQcm90byhPcHRpb25zLCB7XG4gICAgaW5pdDogT3B0aW9ucyRpbml0LFxuICAgIGRlc3Ryb3k6IE9wdGlvbnMkZGVzdHJveSxcbiAgICBfY3JlYXRlTWVzc2VuZ2VyOiBPcHRpb25zJF9jcmVhdGVNZXNzZW5nZXJcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoT3B0aW9ucyk7XG5cbm1vZHVsZS5leHBvcnRzID0gT3B0aW9ucztcblxuXG5mdW5jdGlvbiBPcHRpb25zJGluaXQoKSB7XG4gICAgdGhpcy5tID0gbmV3IE1vZGVsKHRoaXMuY29uZmlnLm9wdGlvbnMsIHRoaXMpO1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgdGhpcy5tLnByb3h5TWV0aG9kcyh0aGlzKTsgLy8gQ3JlYXRlcyBtb2RlbCdzIG1ldGhvZHMgZGlyZWN0bHkgb24gZmFjZXRcbn1cblxuXG5mdW5jdGlvbiBPcHRpb25zJF9jcmVhdGVNZXNzZW5nZXIoKSB7IC8vIENhbGxlZCBieSBpbmhlcml0ZWQgaW5pdFxuICAgIHRoaXMuX21lc3NlbmdlciA9IHRoaXMubS5fbWVzc2VuZ2VyO1xufVxuXG5cbmZ1bmN0aW9uIE9wdGlvbnMkZGVzdHJveSgpIHtcbiAgICB0aGlzLm0uZGVzdHJveSgpO1xuICAgIENvbXBvbmVudEZhY2V0LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vIDxhIG5hbWU9XCJjb21wb25lbnRzLWZhY2V0cy10ZW1wbGF0ZVwiPjwvYT5cbi8vICMjI3RlbXBsYXRlIGZhY2V0XG5cbi8vIHNpbXBsaWZpZXMgcmVuZGVyaW5nIG9mIGNvbXBvbmVudCBlbGVtZW50IGZyb20gdGVtcGxhdGUuXG4vLyAgIEFueSB0ZW1wbGF0aW5nIGVuZ2luZyBjYW4gYmUgdXNlZCB0aGF0IHN1cHBvcnRzIHRlbXBsYXRlIGNvbXBpbGF0aW9uXG4vLyAgIChvciB5b3UgY2FuIG1vY2sgdGhpcyBjb21waWxhdGlvbiBlYXNpbHkgYnkgY3JlYXRpbmcgY2xvc3VyZSBzdG9yaW5nXG4vLyAgIHRlbXBsYXRlIHN0cmluZyBpbiBjYXNlIHlvdXIgZW5naW5lIGRvZXNuJ3Qgc3VwcG9ydCBjb21waWxhdGlvbikuXG4vLyAgIEJ5IGRlZmF1bHQgbWlsbyB1c2VzIFtkb1RdKCksIHRoZSBtb3N0IHZlcnNhdGlsZSwgY29uc2Npc2UgYW5kIGF0IHRoZVxuLy8gICBzYW1lIHRpbWUgdGhlIGZhc3Rlc3QgdGVtcGxhdGluZyBlbmdpbmUuXG4vLyAgIElmIHlvdSB1c2UgbWlsbyBpbiBicm93c2VyLCBpdCBpcyB0aGUgcGFydCBvZiBtaWxvIGJ1bmRsZSBhbmQgYXZhaWxhYmxlXG4vLyAgIGFzIGdsb2JhbCB2YXJpYWJsZSBgZG9UYC5cblxudmFyIENvbXBvbmVudEZhY2V0ID0gcmVxdWlyZSgnLi4vY19mYWNldCcpXG4gICAgLCBmYWNldHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4vY2ZfcmVnaXN0cnknKVxuICAgICwgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvXG4gICAgLCBjaGVjayA9IG1pbG9Db3JlLnV0aWwuY2hlY2tcbiAgICAsIGxvZ2dlciA9IG1pbG9Db3JlLnV0aWwubG9nZ2VyXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBiaW5kZXIgPSByZXF1aXJlKCcuLi8uLi9iaW5kZXInKTtcblxuXG4vLyBkYXRhIG1vZGVsIGNvbm5lY3Rpb24gZmFjZXRcbnZhciBUZW1wbGF0ZSA9IF8uY3JlYXRlU3ViY2xhc3MoQ29tcG9uZW50RmFjZXQsICdUZW1wbGF0ZScpO1xuXG5fLmV4dGVuZFByb3RvKFRlbXBsYXRlLCB7XG4gICAgaW5pdDogVGVtcGxhdGUkaW5pdCxcbiAgICBzdGFydDogVGVtcGxhdGUkc3RhcnQsXG4gICAgc2V0OiBUZW1wbGF0ZSRzZXQsXG4gICAgZ2V0Q29tcGlsZWQ6IFRlbXBsYXRlJGdldENvbXBpbGVkLFxuICAgIHJlbmRlcjogVGVtcGxhdGUkcmVuZGVyLFxuICAgIGJpbmRlcjogVGVtcGxhdGUkYmluZGVyXG5cbiAgICAvLyBfcmVhdHRhY2g6IF9yZWF0dGFjaEV2ZW50c09uRWxlbWVudENoYW5nZVxufSk7XG5cbmZhY2V0c1JlZ2lzdHJ5LmFkZChUZW1wbGF0ZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gVGVtcGxhdGU7XG5cblxuZnVuY3Rpb24gVGVtcGxhdGUkaW5pdCgpIHtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXG4gICAgLy8gdGVtcGxhdGVzIGFyZSBpbnRlcnBvbGF0ZWQgd2l0aCBkZWZhdWx0IChkb1QpIG9yIGNvbmZpZ3VyZWQgZW5naW5lICh0aGlzLmNvbmZpZy5jb21waWxlKVxuICAgIC8vIHVubGVzcyB0aGlzLmNvbmZpZy5pbnRlcnBvbGF0ZSBpcyBmYWxzZVxuICAgIHZhciBjb21waWxlID0gdGhpcy5jb25maWcuaW50ZXJwb2xhdGUgPT09IGZhbHNlXG4gICAgICAgICAgICAgICAgICAgID8gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgIDogdGhpcy5jb25maWcuY29tcGlsZSB8fCBtaWxvLmNvbmZpZy50ZW1wbGF0ZS5jb21waWxlO1xuXG4gICAgdGhpcy5zZXQodGhpcy5jb25maWcudGVtcGxhdGUgfHwgJycsIGNvbXBpbGUsIHRoaXMuY29uZmlnLmNvbXBpbGVPcHRpb25zKTtcbn1cblxuXG5mdW5jdGlvbiBUZW1wbGF0ZSRzdGFydCgpIHtcbiAgICBDb21wb25lbnRGYWNldC5wcm90b3R5cGUuc3RhcnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICBpZiAodGhpcy5jb25maWcuYXV0b1JlbmRlcikge1xuICAgICAgICB0aGlzLnJlbmRlcigpO1xuICAgICAgICBpZiAodGhpcy5jb25maWcuYXV0b0JpbmRlcilcbiAgICAgICAgICAgIHRoaXMuYmluZGVyKCk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIFRlbXBsYXRlJGdldENvbXBpbGVkKCkge1xuICAgIHJldHVybiB0aGlzLl90ZW1wbGF0ZTtcbn1cblxuXG5mdW5jdGlvbiBUZW1wbGF0ZSRzZXQodGVtcGxhdGVTdHIsIGNvbXBpbGUsIGNvbXBpbGVPcHRpb25zKSB7XG4gICAgY2hlY2sodGVtcGxhdGVTdHIsIE1hdGNoLk9uZU9mKFN0cmluZywgRnVuY3Rpb24pKTtcbiAgICBjaGVjayhjb21waWxlLCBNYXRjaC5PcHRpb25hbChGdW5jdGlvbikpO1xuXG4gICAgaWYgKHR5cGVvZiB0ZW1wbGF0ZVN0ciA9PSAnZnVuY3Rpb24nKVxuICAgICAgICB0aGlzLl90ZW1wbGF0ZSA9IHRlbXBsYXRlU3RyO1xuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLl90ZW1wbGF0ZVN0ciA9IHRlbXBsYXRlU3RyO1xuICAgICAgICBpZiAoY29tcGlsZSlcbiAgICAgICAgICAgIHRoaXMuX2NvbXBpbGUgPSBjb21waWxlO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBjb21waWxlID0gdGhpcy5fY29tcGlsZTtcblxuICAgICAgICBpZiAoY29tcGlsZSlcbiAgICAgICAgICAgIHRoaXMuX3RlbXBsYXRlID0gY29tcGlsZSh0ZW1wbGF0ZVN0ciwgY29tcGlsZU9wdGlvbnMpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbmZ1bmN0aW9uIFRlbXBsYXRlJHJlbmRlcihkYXRhKSB7IC8vIHdlIG5lZWQgZGF0YSBvbmx5IGlmIHVzZSB0ZW1wbGF0aW5nIGVuZ2luZVxuICAgIHRoaXMub3duZXIuZWwuaW5uZXJIVE1MID0gdGhpcy5fdGVtcGxhdGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyB0aGlzLl90ZW1wbGF0ZShkYXRhKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHRoaXMuX3RlbXBsYXRlU3RyO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuZnVuY3Rpb24gVGVtcGxhdGUkYmluZGVyKCkge1xuICAgIGlmICh0aGlzLm93bmVyLmNvbnRhaW5lcilcbiAgICAgICAgcmV0dXJuIHRoaXMub3duZXIuY29udGFpbmVyLmJpbmRlcigpO1xuICAgIGVsc2VcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdUZW1wbGF0ZUZhY2V0OiBCaW5kZXIgY2FsbGVkIHdpdGhvdXQgY29udGFpbmVyIGZhY2V0LicpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50RmFjZXQgPSByZXF1aXJlKCcuLi9jX2ZhY2V0JylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jZl9yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbWlsby1jb3JlJykucHJvdG87XG5cblxuLyoqXG4gKiBUcmFuc2ZlciBmYWNldCBpcyBkZXNpZ25lZCBmb3IgY29tcG9uZW50cyB0byBiZSBhYmxlIHRvIHJlcHJlc2VudCBvdGhlciBjb21wb25lbnRzXG4gKiBJZiBhIFtDb21wb25lbnRdKC4uL2NfY2xhc3MuanMuaHRtbCkgaGFzIFRyYW5zZmVyIGZhY2V0LCB3aGVuIGBDb21wb25lbnQuZ2V0U3RhdGVgIGlzIGNhbGxlZCBmb3IgdGhpcyBjb21wb25ldCBpdCByZXR1cm5zIHByZXZpb3VzbHkgc2F2ZWQgZGF0YSwgcG9zc2libHkgZnJvbSBhbm90aGVyIGNvbXBvbmVudC5cbiAqIEZvciBleGFtcGxlLCBhIGxpc3Qgb2YgZG9jdW1lbnRzIGNhbiB1c2UgdGhpcyBmYWNldCBzbyB0aGF0IGVhY2ggaXRlbSBpbiB0aGUgbGlzdCBjYW4gc3RvcmUgYWN0dWFsIGRvY3VtZW50IGNvbXBvbmVudCBvbiBpdC5cbiAqL1xudmFyIFRyYW5zZmVyID0gXy5jcmVhdGVTdWJjbGFzcyhDb21wb25lbnRGYWNldCwgJ1RyYW5zZmVyJyk7XG5cbl8uZXh0ZW5kUHJvdG8oVHJhbnNmZXIsIHtcbiAgICBpbml0OiBUcmFuc2ZlciRpbml0LFxuICAgIGdldFN0YXRlOiBUcmFuc2ZlciRnZXRTdGF0ZSxcbiAgICBzZXRTdGF0ZTogVHJhbnNmZXIkc2V0U3RhdGUsXG4gICAgc2V0QWN0aXZlU3RhdGU6IFRyYW5zZmVyJHNldEFjdGl2ZVN0YXRlLFxuICAgIHNldFN0YXRlV2l0aEtleTogVHJhbnNmZXIkc2V0U3RhdGVXaXRoS2V5LFxuICAgIGdldFN0YXRlV2l0aEtleTogVHJhbnNmZXIkZ2V0U3RhdGVXaXRoS2V5LFxuICAgIGdldENvbXBvbmVudE1ldGE6IFRyYW5zZmVyJGdldENvbXBvbmVudE1ldGFcbn0pO1xuXG5mYWNldHNSZWdpc3RyeS5hZGQoVHJhbnNmZXIpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFRyYW5zZmVyO1xuXG5cbmZ1bmN0aW9uIFRyYW5zZmVyJGluaXQoKSB7XG4gICAgQ29tcG9uZW50RmFjZXQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB0aGlzLl9hY3RpdmVTdGF0ZSA9ICcnO1xuICAgIHRoaXMuX2RlZmF1bHRLZXkgPSAnJztcbiAgICB0aGlzLl9zdGF0ZSA9IHt9O1xufVxuXG5cbi8qKlxuICogVHJhbnNmZXIgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHRyYW5zZmVyIHN0YXRlIGZvciBjb21wb25lbnQuIENhbiBiZSBvYnRhaW5lZCBmcm9tIGFub3RoZXIgY29tcG9uZW50IGJ5IHVzaW5nIGBDb21wb25lbnQuZ2V0U3RhdGVgXG4gKlxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBUcmFuc2ZlciRnZXRTdGF0ZSgpIHtcbiAgICByZXR1cm4gdGhpcy5fc3RhdGVbdGhpcy5fYWN0aXZlU3RhdGVdIHx8IHRoaXMuX3N0YXRlW3RoaXMuX2RlZmF1bHRLZXldO1xufVxuXG5cbi8qKlxuICogVHJhbnNmZXIgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTZXRzIHRyYW5zZmVyIHN0YXRlIGZvciBjb21wb25lbnQuIENhbiBiZSBvYnRhaW5lZCBmcm9tIGFub3RoZXIgY29tcG9uZW50IGJ5IHVzaW5nIGBDb21wb25lbnQuZ2V0U3RhdGVgXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHN0YXRlXG4gKi9cbmZ1bmN0aW9uIFRyYW5zZmVyJHNldFN0YXRlKHN0YXRlKSB7XG4gICAgdGhpcy5fc3RhdGVbJyddID0gc3RhdGU7XG4gICAgdGhpcy5zZXRBY3RpdmVTdGF0ZSgnJyk7XG59XG5cbi8qKlxuICogVHJhbnNmZXIgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTZXRzIHRoZSBhY3RpdmUgc3RhdGUgKHVzZWQgYnkgZ2V0U3RhdGUpXG4gKiBAcGFyYW0ge1t0eXBlXX0ga2V5IFtkZXNjcmlwdGlvbl1cbiAqL1xuZnVuY3Rpb24gVHJhbnNmZXIkc2V0QWN0aXZlU3RhdGUoa2V5KSB7XG4gICAgdGhpcy5fYWN0aXZlU3RhdGUgPSBrZXk7XG59XG5cbi8qKlxuICogVHJhbnNmZXIgZmFjZXQgaW5zdGFuY2UgbWV0aG9kXG4gKiBTZXRzIHRyYW5zZmVyIHN0YXRlIGZvciBjb21wb25lbnQgd2l0aG91dCBkZWZhdWx0IGtleS4gQ2FuIGJlIG9idGFpbmVkIGZyb20gYW5vdGhlciBjb21wb25lbnQgYnkgdXNpbmcgYENvbXBvbmVudC5nZXRTdGF0ZWBcbiAqIFdoZW4gdGhlIGFjdGl2ZSBzdGF0ZSBpcyBzZXQgdG8gdGhlIGV4cGVjdGVkIGtleVxuICogQHBhcmFtIHtbdHlwZV19IGtleSAgIFtkZXNjcmlwdGlvbl1cbiAqIEBwYXJhbSB7W3R5cGVdfSBzdGF0ZSBbZGVzY3JpcHRpb25dXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGlzRGVmYXVsdEtleSAoT3B0aW9uYWwpXG4gKi9cbmZ1bmN0aW9uIFRyYW5zZmVyJHNldFN0YXRlV2l0aEtleShrZXksIHN0YXRlLCBpc0RlZmF1bHRLZXkpIHtcbiAgICBpZiAoIWtleSkgdGhyb3cgbmV3IEVycm9yKCdUcmFuc2ZlciRzZXRTdGF0ZVdpdGhLZXk6IG5vIGtleScpO1xuXG4gICAgaWYgKGlzRGVmYXVsdEtleSlcbiAgICAgICAgdGhpcy5fZGVmYXVsdEtleSA9IGtleTtcbiAgICBlbHNlXG4gICAgICAgIHRoaXMuX2RlZmF1bHRLZXkgPSB0aGlzLl9kZWZhdWx0S2V5IHx8IGtleTtcblxuICAgIHRoaXMuX3N0YXRlW2tleV0gPSBzdGF0ZTtcbiAgICB0aGlzLnNldEFjdGl2ZVN0YXRlKGtleSk7XG59XG5cblxuZnVuY3Rpb24gVHJhbnNmZXIkZ2V0U3RhdGVXaXRoS2V5KGtleSkge1xuICAgIHJldHVybiB0eXBlb2Yga2V5ID09ICdzdHJpbmcnICYmIHRoaXMuX3N0YXRlW2tleV07XG59XG5cblxuZnVuY3Rpb24gVHJhbnNmZXIkZ2V0Q29tcG9uZW50TWV0YSgpIHtcbiAgICB2YXIgc3RhdGUgPSB0aGlzLmdldFN0YXRlKCk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgY29tcE5hbWU6IHN0YXRlICYmIHN0YXRlLmNvbXBOYW1lLFxuICAgICAgICBjb21wQ2xhc3M6IHN0YXRlICYmIHN0YXRlLmNvbXBDbGFzc1xuICAgIH07XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDbGFzc1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vLi4vYWJzdHJhY3QvcmVnaXN0cnknKVxuICAgICwgQ29tcG9uZW50RmFjZXQgPSByZXF1aXJlKCcuLi9jX2ZhY2V0Jyk7XG5cblxuLyoqXG4gKiBgbWlsby5yZWdpc3RyeS5mYWNldHNgXG4gKiBDb21wb25lbnQgZmFjZXRzIHJlZ2lzdHJ5LiBBbiBpbnN0YW5jZSBvZiBbQ2xhc3NSZWdpc3RyeV0oLi4vLi4vYWJzdHJhY3QvcmVnaXN0cnkuanMuaHRtbCkgY2xhc3MgdGhhdCBpcyB1c2VkIGJ5IG1pbG8gdG8gcmVnaXN0ZXIgYW5kIGZpbmQgZmFjZXRzLlxuICovXG4gdmFyIGZhY2V0c1JlZ2lzdHJ5ID0gbmV3IENsYXNzUmVnaXN0cnkoQ29tcG9uZW50RmFjZXQpO1xuXG5cbi8vIEFkZHMgY29tbW9uIGFuY2VzdG9yIHRvIGFsbCBmYWNldHMgb2YgY29tcG9uZW50cyB0byB0aGUgcmVnaXN0cnkuXG5mYWNldHNSZWdpc3RyeS5hZGQoQ29tcG9uZW50RmFjZXQpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZhY2V0c1JlZ2lzdHJ5O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jX3JlZ2lzdHJ5JylcbiAgICAsIGZhY2V0c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi9jX2ZhY2V0cy9jZl9yZWdpc3RyeScpXG4gICAgLCBjb21wb25lbnROYW1lID0gcmVxdWlyZSgnLi4vdXRpbC9jb21wb25lbnRfbmFtZScpXG4gICAgLCBTY29wZSA9IHJlcXVpcmUoJy4vc2NvcGUnKVxuICAgICwgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgbG9nZ2VyID0gbWlsb0NvcmUudXRpbC5sb2dnZXJcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90bztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IENvbXBvbmVudEluZm87XG5cblxuLyoqXG4gKiBTaW1wbGUgY2xhc3MgdG8gaG9sZCBpbmZvcm1hdGlvbiBhbGxvd2luZyB0byBjcmVhdGUvY29weSBjb21wb25lbnQgdXNpbmcgW2BDb21wb25lbnQuY3JlYXRlYF0oLi9jX2NsYXNzLmpzLmh0bWwjY3JlYXRlKSBhbmQgW2BDb21wb25lbnQuY29weWBdKC4vY19jbGFzcy5qcy5odG1sI2NvcHkpLlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQHBhcmFtIHtTY29wZX0gc2NvcGUgc2NvcGUgb2JqZWN0IHRoZSBjb21wb25lbnQgYmVsb2dzIHRvLCB1c3VhbGx5IGVpdGhlciB0b3AgbGV2ZWwgc2NvcGUgdGhhdCB3aWxsIGJlIHJldHVybmVkIGJ5IFttaWxvLmJpbmRlcl0oLi4vYmluZGVyLmpzLmh0bWwpIG9yIGBzY29wZWAgcHJvcGVydHkgb2YgW0NvbnRhaW5lcl0oLi9jX2ZhY2V0cy9Db250YWluZXIuanMuaHRtbCkgZmFjZXQgb2YgY29udGFpbmluZyBjb21wb25lbnRcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgRE9NIGVsZW1lbnQgdGhlIGNvbXBvbmVudCBpcyBhdHRhY2hlZCB0b1xuICogQHBhcmFtIHtCaW5kQXR0cmlidXRlfSBhdHRyIEJpbmRBdHRyaWJ1dGUgaW5zdGFuY2UgdGhhdCB0aGUgY29tcG9uZW50IHdhcyBjcmVhdGVkIHdpdGhcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gdGhyb3dPbkVycm9ycyBJZiBzZXQgdG8gZmFsc2UsIHRoZW4gZXJyb3JzIHdpbGwgb25seSBiZSBsb2dnZWQgdG8gY29uc29sZS4gVHJ1ZSBieSBkZWZhdWx0LlxuICogQHJldHVybiB7Q29tcG9uZW50SW5mb31cbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50SW5mbyhzY29wZSwgZWwsIGF0dHIsIHRocm93T25FcnJvcnMpIHtcbiAgICBhdHRyLnBhcnNlKCkudmFsaWRhdGUoKTtcblxuICAgIHRoaXMuc2NvcGUgPSBzY29wZTtcbiAgICB0aGlzLmVsID0gZWw7XG4gICAgdGhpcy5hdHRyID0gYXR0cjtcbiAgICB0aGlzLm5hbWUgPSBhdHRyLmNvbXBOYW1lO1xuICAgIHRoaXMuQ29tcG9uZW50Q2xhc3MgPSBnZXRDb21wb25lbnRDbGFzcyhhdHRyLCB0aHJvd09uRXJyb3JzKTtcbiAgICB0aGlzLmV4dHJhRmFjZXRzQ2xhc3NlcyA9IGdldENvbXBvbmVudEV4dHJhRmFjZXRzKHRoaXMuQ29tcG9uZW50Q2xhc3MsIGF0dHIsIHRocm93T25FcnJvcnMpO1xuXG4gICAgaWYgKHRoaXMuQ29tcG9uZW50Q2xhc3NcbiAgICAgICAgICAgICYmIGhhc0NvbnRhaW5lckZhY2V0KHRoaXMuQ29tcG9uZW50Q2xhc3MsIHRoaXMuZXh0cmFGYWNldHNDbGFzc2VzKSkge1xuICAgICAgICB0aGlzLmNvbnRhaW5lciA9IHt9O1xuICAgIH1cbn1cblxuXG4vKipcbiAqICMjIyNDb21wb25lbnRJbmZvIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKiBcbiAqIC0gW2Rlc3Ryb3ldKCNDb21wb25lbnRJbmZvJGRlc3Ryb3kpXG4gKiAtIFtyZW5hbWVdKCNDb21wb25lbnRJbmZvJHJlbmFtZSlcbiAqL1xuXy5leHRlbmRQcm90byhDb21wb25lbnRJbmZvLCB7XG4gICAgZGVzdHJveTogQ29tcG9uZW50SW5mbyRkZXN0cm95LFxuICAgIHJlbmFtZTogQ29tcG9uZW50SW5mbyRyZW5hbWVcbn0pO1xuXG5cbi8qKlxuICogQ29tcG9uZW50SW5mbyBpbnN0YW5jZSBtZXRob2RcbiAqIERlc3Ryb3lzIENvbXBvbmVudEluZm8gYnkgcmVtb3ZpbmcgdGhlIHJlZmVyZW5jZXMgdG8gRE9NIGVsZW1lbnRcbiAqL1xuZnVuY3Rpb24gQ29tcG9uZW50SW5mbyRkZXN0cm95KCkge1xuICAgIGRlbGV0ZSB0aGlzLmVsO1xuICAgIHRoaXMuYXR0ci5kZXN0cm95KCk7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnRJbmZvIGluc3RhbmNlIG1ldGhvZFxuICogUmVuYW1lcyBDb21wb25lbnRJbmZvIG9iamVjdFxuICpcbiAqIEBwYXJhbSB7W1N0cmluZ119IG5hbWUgb3B0aW9uYWwgbmV3IGNvbXBvbmVudCBuYW1lLCBnZW5lcmF0ZWQgZnJvbSB0aW1lc3RhbXAgYnkgZGVmYXVsdFxuICogQHBhcmFtIHtbQm9vbGVhbl19IHJlbmFtZUluU2NvcGUgb3B0aW9uYWwgZmFsc2UgdG8gbm90IHJlbmFtZSBDb21wb25lbnRJbmZvIG9iamVjdCBpbiBpdHMgc2NvcGUsIHRydWUgYnkgZGVmYXVsdFxuICovXG5mdW5jdGlvbiBDb21wb25lbnRJbmZvJHJlbmFtZShuYW1lLCByZW5hbWVJblNjb3BlKSB7XG4gICAgbmFtZSA9IG5hbWUgfHwgY29tcG9uZW50TmFtZSgpO1xuICAgIFNjb3BlLnJlbmFtZSh0aGlzLCBuYW1lLCByZW5hbWVJblNjb3BlKTtcbiAgICB0aGlzLmF0dHIuY29tcE5hbWUgPSBuYW1lO1xuICAgIHRoaXMuYXR0ci5kZWNvcmF0ZSgpO1xufVxuXG5cbmZ1bmN0aW9uIGdldENvbXBvbmVudENsYXNzKGF0dHIsIHRocm93T25FcnJvcnMpIHtcbiAgICB2YXIgQ29tcG9uZW50Q2xhc3MgPSBjb21wb25lbnRzUmVnaXN0cnkuZ2V0KGF0dHIuY29tcENsYXNzKTtcbiAgICBpZiAoISBDb21wb25lbnRDbGFzcylcbiAgICAgICAgcmVwb3J0QmluZGVyRXJyb3IodGhyb3dPbkVycm9ycywgJ2NsYXNzICcgKyBhdHRyLmNvbXBDbGFzcyArICcgaXMgbm90IHJlZ2lzdGVyZWQnKTtcbiAgICByZXR1cm4gQ29tcG9uZW50Q2xhc3M7XG59XG5cblxuZnVuY3Rpb24gZ2V0Q29tcG9uZW50RXh0cmFGYWNldHMoQ29tcG9uZW50Q2xhc3MsIGF0dHIsIHRocm93T25FcnJvcnMpIHtcbiAgICB2YXIgZmFjZXRzID0gYXR0ci5jb21wRmFjZXRzXG4gICAgICAgICwgZXh0cmFGYWNldHNDbGFzc2VzID0ge307XG5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShmYWNldHMpKVxuICAgICAgICBmYWNldHMuZm9yRWFjaChmdW5jdGlvbihmY3ROYW1lKSB7XG4gICAgICAgICAgICBmY3ROYW1lID0gXy5maXJzdFVwcGVyQ2FzZShmY3ROYW1lKTtcbiAgICAgICAgICAgIGlmIChDb21wb25lbnRDbGFzcy5oYXNGYWNldChmY3ROYW1lKSlcbiAgICAgICAgICAgICAgICByZXBvcnRCaW5kZXJFcnJvcih0aHJvd09uRXJyb3JzLCAnY2xhc3MgJyArIENvbXBvbmVudENsYXNzLm5hbWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKyAnIGFscmVhZHkgaGFzIGZhY2V0ICcgKyBmY3ROYW1lKTtcbiAgICAgICAgICAgIGlmIChleHRyYUZhY2V0c0NsYXNzZXNbZmN0TmFtZV0pXG4gICAgICAgICAgICAgICAgcmVwb3J0QmluZGVyRXJyb3IodGhyb3dPbkVycm9ycywgJ2NvbXBvbmVudCAnICsgYXR0ci5jb21wTmFtZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICArICcgYWxyZWFkeSBoYXMgZmFjZXQgJyArIGZjdE5hbWUpO1xuICAgICAgICAgICAgdmFyIEZhY2V0Q2xhc3MgPSBmYWNldHNSZWdpc3RyeS5nZXQoZmN0TmFtZSk7XG4gICAgICAgICAgICBleHRyYUZhY2V0c0NsYXNzZXNbZmN0TmFtZV0gPSBGYWNldENsYXNzO1xuICAgICAgICB9KTtcblxuICAgIHJldHVybiBleHRyYUZhY2V0c0NsYXNzZXM7XG59XG5cblxuZnVuY3Rpb24gcmVwb3J0QmluZGVyRXJyb3IodGhyb3dPbkVycm9ycywgbWVzc2FnZSkge1xuICAgIGlmICh0aHJvd09uRXJyb3JzID09PSBmYWxzZSlcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdDb21wb25lbnRJbmZvIGJpbmRlciBlcnJvcjonLCBtZXNzYWdlKTtcbiAgICBlbHNlXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihtZXNzYWdlKTtcbn07XG5cblxuZnVuY3Rpb24gaGFzQ29udGFpbmVyRmFjZXQoQ29tcG9uZW50Q2xhc3MsIGV4dHJhRmFjZXRzQ2xhc3Nlcykge1xuICAgIHJldHVybiAoQ29tcG9uZW50Q2xhc3MuaGFzRmFjZXQoJ2NvbnRhaW5lcicpXG4gICAgICAgIHx8ICdDb250YWluZXInIGluIGV4dHJhRmFjZXRzQ2xhc3Nlc1xuICAgICAgICB8fCBfLnNvbWVLZXkoZXh0cmFGYWNldHNDbGFzc2VzLCBmYWNldFJlcXVpcmVzQ29udGFpbmVyKVxuICAgICAgICB8fCBjbGFzc0hhc0ZhY2V0VGhhdFJlcXVpcmVzQ29udGFpbmVyKCkpO1xuXG4gICAgZnVuY3Rpb24gY2xhc3NIYXNGYWNldFRoYXRSZXF1aXJlc0NvbnRhaW5lcigpIHtcbiAgICAgICAgcmV0dXJuIChDb21wb25lbnRDbGFzcy5wcm90b3R5cGUuZmFjZXRzQ2xhc3Nlc1xuICAgICAgICAgICAgJiYgXy5zb21lS2V5KENvbXBvbmVudENsYXNzLnByb3RvdHlwZS5mYWNldHNDbGFzc2VzLCBmYWNldFJlcXVpcmVzQ29udGFpbmVyKSlcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBmYWNldFJlcXVpcmVzQ29udGFpbmVyKEZhY2V0Q2xhc3MpIHtcbiAgICAgICAgcmV0dXJuIEZhY2V0Q2xhc3MucmVxdWlyZXNGYWNldCgnY29udGFpbmVyJyk7XG4gICAgfVxufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2xhc3NSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2Fic3RyYWN0L3JlZ2lzdHJ5JylcbiAgICAsIENvbXBvbmVudCA9IHJlcXVpcmUoJy4vY19jbGFzcycpO1xuXG4vKipcbiAqIGBtaWxvLnJlZ2lzdHJ5LmNvbXBvbmVudHNgXG4gKiBBbiBpbnN0YW5jZSBvZiBbQ2xhc3NSZWdpc3RyeV0oLi4vYWJzdHJhY3QvcmVnaXN0cnkuanMuaHRtbCkgY2xhc3MgdGhhdCBpcyB1c2VkIGJ5IG1pbG8gdG8gcmVnaXN0ZXIgYW5kIGZpbmQgY29tcG9uZW50cy5cbiAqL1xudmFyIGNvbXBvbmVudHNSZWdpc3RyeSA9IG5ldyBDbGFzc1JlZ2lzdHJ5KENvbXBvbmVudCk7XG5cbi8vIGFkZCBjb21tb24gYW5jZXN0b3IgdG8gYWxsIGNvbXBvbmVudHMgdG8gdGhlIHJlZ2lzdHJ5LlxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChDb21wb25lbnQpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbXBvbmVudHNSZWdpc3RyeTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNvbmZpZyA9IHJlcXVpcmUoJy4uL2NvbmZpZycpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBjaGVjayA9IG1pbG9Db3JlLnV0aWwuY2hlY2tcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2hcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90bztcblxuXG52YXIgY29tcG9uZW50VXRpbHMgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBpc0NvbXBvbmVudDogaXNDb21wb25lbnQsXG4gICAgZ2V0Q29tcG9uZW50OiBnZXRDb21wb25lbnQsXG4gICAgZ2V0Q29udGFpbmluZ0NvbXBvbmVudDogZ2V0Q29udGFpbmluZ0NvbXBvbmVudCxcbiAgICBfbWFrZUNvbXBvbmVudENvbmRpdGlvbkZ1bmM6IF9tYWtlQ29tcG9uZW50Q29uZGl0aW9uRnVuY1xufTtcblxuXG4vKipcbiAqIGlzQ29tcG9uZW50XG4gKlxuICogQ2hlY2tzIGlmIGVsZW1lbnQgaGFzIGEgY29tcG9uZW50IGF0dGFjaGVkIHRvIGl0IGJ5XG4gKiBjaGVja2luZyB0aGUgcHJlc2VuY2Ugb2YgcHJvcGVydHkgZGlmaW5lZCBpbiBtaWxvLmNvbmZpZ1xuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgRE9NIGVsZW1lbnRcbiAqIEByZXR1cm4ge0Jvb2xlYW59IHRydWUsIGlmIGl0IGhhcyBtaWxvIGNvbXBvbmVudCBhdHRhY2hlZCB0byBpdFxuICovXG5mdW5jdGlvbiBpc0NvbXBvbmVudChlbCkge1xuICAgIHJldHVybiBlbC5oYXNPd25Qcm9wZXJ0eShjb25maWcuY29tcG9uZW50UmVmKTtcbn1cblxuXG4vKipcbiAqIGdldENvbXBvbmVudFxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgRE9NIGVsZW1lbnRcbiAqIEByZXR1cm4ge0NvbXBvbmVudH0gY29tcG9uZW50IGF0dGFjaGVkIHRvIGVsZW1lbnRcbiAqL1xuZnVuY3Rpb24gZ2V0Q29tcG9uZW50KGVsKSB7XG4gICAgcmV0dXJuIGVsICYmIGVsW2NvbmZpZy5jb21wb25lbnRSZWZdO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgY2xvc2VzdCBjb21wb25lbnQgd2hpY2ggY29udGFpbnMgdGhlIHNwZWNpZmllZCBlbGVtZW50LFxuICogb3B0aW9uYWxseSwgb25seSBjb21wb25lbnQgdGhhdCBwYXNzZXMgYGNvbmRpdGlvbmAgdGVzdCBvciBjb250YWlucyBzcGVjaWZpZWQgZmFjZXRcbiAqXG4gKiBVbmxlc3MgYHJldHVybkN1cnJlbnRgIHBhcmFtZXRlciBpcyBmYWxzZSwgdGhlIGZ1bmN0aW9uIHdpbGwgcmV0dXJuXG4gKiB0aGUgY3VycmVudCBjb21wb25lbnQgb2YgdGhlIGVsZW1lbnQgKHRydWUgYnkgZGVmYXVsdCkuXG4gKlxuICogQHBhcmFtIHtOb2RlfSBub2RlIERPTSBFbGVtZW50IG9yIHRleHQgTm9kZVxuICogQHBhcmFtIHtCb29sZWFufSByZXR1cm5DdXJyZW50IG9wdGlvbmFsIGJvb2xlYW4gdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBjb21wb25lbnQgb2YgdGhlIGVsZW1lbnQgY2FuIGJlIHJldHVybmVkLiBUcnVlIGJ5IGRlZmF1bHQsIHNob3VsZCBiZSBmYWxzZSB0byByZXR1cm4gb25seSBhbmNlc3RvcnMuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufFN0cmluZ30gY29uZGl0aW9uT3JGYWNldCBvcHRpb25hbCBjb25kaXRpb24gdGhhdCBjb21wb25lbnQgc2hvdWxkIHBhc3MgKG9yIGZhY2V0IG5hbWUgaXQgc2hvdWxkIGNvbnRhaW4pXG4gKiBAcmV0dXJuIHtDb21wb25lbnR9IFxuICovXG5mdW5jdGlvbiBnZXRDb250YWluaW5nQ29tcG9uZW50KG5vZGUsIHJldHVybkN1cnJlbnQsIGNvbmRpdGlvbk9yRmFjZXQpIHtcbiAgICAvLyBjaGVjayhub2RlLCBOb2RlKTsgLSBjYW4ndCBjaGVjayB0aXlwZSBoZXJlIGFzIGl0IGlzIG1vc3QgbGlrZWx5IGNvbWluZyBmcm9tIGFub3RoZXIgZnJhbWVcbiAgICBjaGVjayhyZXR1cm5DdXJyZW50LCBNYXRjaC5PcHRpb25hbChCb29sZWFuKSk7XG4gICAgY2hlY2soY29uZGl0aW9uT3JGYWNldCwgTWF0Y2guT3B0aW9uYWwoTWF0Y2guT25lT2YoRnVuY3Rpb24sIFN0cmluZykpKTtcblxuICAgIHZhciBjb25kaXRpb25GdW5jID0gX21ha2VDb21wb25lbnRDb25kaXRpb25GdW5jKGNvbmRpdGlvbk9yRmFjZXQpO1xuXG4gICAgcmV0dXJuIF9nZXRDb250YWluaW5nQ29tcG9uZW50KG5vZGUsIHJldHVybkN1cnJlbnQsIGNvbmRpdGlvbkZ1bmMpO1xufVxuXG5cbmZ1bmN0aW9uIF9tYWtlQ29tcG9uZW50Q29uZGl0aW9uRnVuYyhjb25kaXRpb25PckZhY2V0KSB7XG4gICAgaWYgKHR5cGVvZiBjb25kaXRpb25PckZhY2V0ID09ICdmdW5jdGlvbicpXG4gICAgICAgIHJldHVybiBjb25kaXRpb25PckZhY2V0O1xuICAgIGVsc2UgaWYgKHR5cGVvZiBjb25kaXRpb25PckZhY2V0ID09ICdzdHJpbmcnKSB7XG4gICAgICAgIHZhciBmYWNldE5hbWUgPSBfLmZpcnN0TG93ZXJDYXNlKGNvbmRpdGlvbk9yRmFjZXQpO1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKGNvbXApIHtcbiAgICAgICAgICAgcmV0dXJuIGNvbXAuaGFzRmFjZXQoZmFjZXROYW1lKTtcbiAgICAgICAgfTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gX2dldENvbnRhaW5pbmdDb21wb25lbnQoZWwsIHJldHVybkN1cnJlbnQsIGNvbmRpdGlvbkZ1bmMpIHtcbiAgICAvLyBXaGVyZSB0aGUgY3VycmVudCBlbGVtZW50IGlzIGEgY29tcG9uZW50IGl0IHNob3VsZCBiZSByZXR1cm5lZFxuICAgIC8vIGlmIHJldHVybkN1cnJlbnQgaXMgdHJ1ZSBvciB1bmRlZmluZWRcbiAgICBpZiAocmV0dXJuQ3VycmVudCAhPT0gZmFsc2UpIHtcbiAgICAgICAgdmFyIGNvbXAgPSBnZXRDb21wb25lbnQoZWwpO1xuICAgICAgICBpZiAoY29tcCAmJiAoISBjb25kaXRpb25GdW5jIHx8IGNvbmRpdGlvbkZ1bmMoY29tcCkpKVxuICAgICAgICAgICAgcmV0dXJuIGNvbXA7XG4gICAgfVxuXG4gICAgLy8gV2hlcmUgdGhlcmUgaXMgbm8gcGFyZW50IGVsZW1lbnQsIHRoaXMgZnVuY3Rpb24gd2lsbCByZXR1cm4gdW5kZWZpbmVkXG4gICAgLy8gVGhlIHBhcmVudCBlbGVtZW50IGlzIGNoZWNrZWQgcmVjdXJzaXZlbHlcbiAgICBpZiAoZWwucGFyZW50Tm9kZSlcbiAgICAgICAgcmV0dXJuIF9nZXRDb250YWluaW5nQ29tcG9uZW50KGVsLnBhcmVudE5vZGUsIHRydWUsIGNvbmRpdGlvbkZ1bmMpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5Jyk7XG5cblxudmFyIFZpZXcgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ1ZpZXcnLCBbJ2NvbnRhaW5lciddKTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChWaWV3KTtcblxubW9kdWxlLmV4cG9ydHMgPSBWaWV3O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBnZXRFbGVtZW50RGF0YUFjY2VzcyA9IHJlcXVpcmUoJy4vZGVfZGF0YScpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNZXNzZW5nZXJBUEkgPSBtaWxvQ29yZS5jbGFzc2VzLk1lc3NlbmdlckFQSVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvXG4gICAgLCBjaGVjayA9IG1pbG9Db3JlLnV0aWwuY2hlY2tcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2g7XG5cblxuLy8gY2xhc3MgdG8gaGFuZGxlIHN1YnNjcmlidGlvbnMgdG8gY2hhbmdlcyBpbiBET00gZm9yIFVJIChtYXliZSBhbHNvIGNvbnRlbnQgZWRpdGFibGUpIGVsZW1lbnRzXG5cbi8qKlxuICogQSBjbGFzc1xuICovXG52YXIgRGF0YU1zZ0FQSSA9IF8uY3JlYXRlU3ViY2xhc3MoTWVzc2VuZ2VyQVBJLCAnRGF0YU1zZ0FQSScsIHRydWUpO1xuXG5cbl8uZXh0ZW5kUHJvdG8oRGF0YU1zZ0FQSSwge1xuICAgIC8vIGltcGxlbWVudGluZyBNZXNzYWdlU291cmNlIGludGVyZmFjZVxuICAgIGluaXQ6IERhdGFNc2dBUEkkaW5pdCxcbiAgICB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2U6IHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZSxcbiAgICBmaWx0ZXJTb3VyY2VNZXNzYWdlOiBmaWx0ZXJTb3VyY2VNZXNzYWdlLFxuICAgIGNyZWF0ZUludGVybmFsRGF0YTogY3JlYXRlSW50ZXJuYWxEYXRhLFxuXG4gICAgLy8gY2xhc3Mgc3BlY2lmaWMgbWV0aG9kc1xuICAgIHZhbHVlOiBEYXRhTXNnQVBJJHZhbHVlXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBEYXRhTXNnQVBJO1xuXG5cbmZ1bmN0aW9uIERhdGFNc2dBUEkkaW5pdChjb21wb25lbnQpIHtcbiAgICBNZXNzZW5nZXJBUEkucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIHRoaXMuY29tcG9uZW50ID0gY29tcG9uZW50O1xuICAgIHRoaXMuZWxEYXRhID0gZ2V0RWxlbWVudERhdGFBY2Nlc3MoY29tcG9uZW50LmVsKTtcbn1cblxuXG4vLyBnZXREb21FbGVtZW50RGF0YVZhbHVlXG5mdW5jdGlvbiBEYXRhTXNnQVBJJHZhbHVlKCkgeyAvLyB2YWx1ZSBtZXRob2RcbiAgICB2YXIgY29tcG9uZW50R2V0dGVyID0gdGhpcy5jb21wb25lbnQuZGF0YS5jb25maWcuZ2V0O1xuICAgIHZhciBuZXdWYWx1ZSA9IHR5cGVvZiBjb21wb25lbnRHZXR0ZXIgPT0gJ2Z1bmN0aW9uJ1xuICAgICAgICAgICAgICAgICAgICA/IGNvbXBvbmVudEdldHRlci5jYWxsKHRoaXMuY29tcG9uZW50KVxuICAgICAgICAgICAgICAgICAgICA6IHRoaXMuZWxEYXRhLmdldCh0aGlzLmNvbXBvbmVudC5lbCk7XG5cbiAgICB0aGlzLmNvbXBvbmVudC5kYXRhLl92YWx1ZSA9IG5ld1ZhbHVlO1xuXG4gICAgcmV0dXJuIG5ld1ZhbHVlO1xufVxuXG5cbi8vIFRPRE86IHRoaXMgZnVuY3Rpb24gc2hvdWxkIHJldHVybiByZWxldmFudCBET00gZXZlbnQgZGVwZW5kZW50IG9uIGVsZW1lbnQgdGFnXG4vLyBDYW4gYWxzbyBpbXBsZW1lbnQgYmVmb3JlZGF0YWNoYW5nZWQgZXZlbnQgdG8gYWxsb3cgcHJldmVudGluZyB0aGUgY2hhbmdlXG4vLyB0cmFuc2xhdGVUb0RvbUV2ZW50XG5mdW5jdGlvbiB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UobWVzc2FnZSkge1xuICAgIHZhciBjb21wb25lbnRFdmVudCA9IHRoaXMuY29tcG9uZW50LmRhdGEuY29uZmlnLmV2ZW50O1xuICAgIHZhciBldmVudCA9IGNvbXBvbmVudEV2ZW50IHx8IHRoaXMuZWxEYXRhLmV2ZW50KHRoaXMuY29tcG9uZW50LmVsKTtcblxuICAgIGlmIChtZXNzYWdlID09ICcnICYmIGV2ZW50KVxuICAgICAgICByZXR1cm4gZXZlbnQ7ICAvLyB0aGlzLnRhZ0V2ZW50O1xufVxuXG5cbi8vIGZpbHRlckRhdGFNZXNzYWdlXG5mdW5jdGlvbiBmaWx0ZXJTb3VyY2VNZXNzYWdlKHNvdXJjZU1lc3NhZ2UsIG1lc3NhZ2UsIGRhdGEpIHtcbiAgICByZXR1cm4gZGF0YS5uZXdWYWx1ZSAhPSBkYXRhLm9sZFZhbHVlO1xufVxuXG5cbmZ1bmN0aW9uIGNyZWF0ZUludGVybmFsRGF0YShzb3VyY2VNZXNzYWdlLCBtZXNzYWdlLCBkYXRhKSB7XG4gICAgdmFyIG9sZFZhbHVlID0gdGhpcy5jb21wb25lbnQuZGF0YS5fdmFsdWVcbiAgICAgICAgLCBuZXdWYWx1ZSA9IHRoaXMudmFsdWUoKTtcblxuICAgIHZhciBpbnRlcm5hbERhdGEgPSB7IFxuICAgICAgICBwYXRoOiAnJyxcbiAgICAgICAgdHlwZTogJ2NoYW5nZWQnLFxuICAgICAgICBvbGRWYWx1ZTogb2xkVmFsdWUsXG4gICAgICAgIG5ld1ZhbHVlOiBuZXdWYWx1ZVxuICAgIH07XG4gICAgcmV0dXJuIGludGVybmFsRGF0YTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgXyA9IHJlcXVpcmUoJ21pbG8tY29yZScpLnByb3RvO1xuXG5cbi8qKlxuICogUmV0dXJucyBkYXRhIGFjY2VzcyBtZXRob2RzIGFuZCBldmVudHMgZm9yIGdpdmVuIERPTSBlbGVtZW50LlxuICogVXNlZCBieSBbRGF0YV0oLi4vY19mYWNldHMvRGF0YS5qcy5odG1sKSBmYWNldCBhbmQgYnkgW0RhdGFNc2dBUEldKC4vZGF0YS5qcy5odG1sKVxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWxcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xudmFyIGdldEVsZW1lbnREYXRhQWNjZXNzID0gZnVuY3Rpb24oZWwpIHtcbiAgICB2YXIgdGFnTmFtZSA9IGVsLnRhZ05hbWUudG9Mb3dlckNhc2UoKVxuICAgICAgICAsIGVsRGF0YSA9IGRvbUVsZW1lbnRzRGF0YUFjY2Vzc1t0YWdOYW1lXTtcbiAgICByZXR1cm4gZWxEYXRhIHx8IGRvbUVsZW1lbnRzRGF0YUFjY2Vzcy5ieURlZmF1bHQ7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0RWxlbWVudERhdGFBY2Nlc3M7XG5cblxuLyoqXG4gKiBEYXRhIGFjY2VzcyBtZXRob2RzIGFuZCBldmVudHMgZm9yIERPTSBlbGVtZW50cy5cbiAqL1xudmFyIGRvbUVsZW1lbnRzRGF0YUFjY2VzcyA9IHtcbiAgICBieURlZmF1bHQ6IHtcbiAgICAgICAgcHJvcGVydHk6ICdpbm5lckhUTUwnLFxuICAgIH0sXG4gICAgJ2Rpdic6IHtcbiAgICAgICAgcHJvcGVydHk6ICdpbm5lckhUTUwnLCAvLyBoYWNrLCBzaG91bGQgYmUgaW5uZXJIVE1MPyB0byBtYWtlIHdvcmsgd2l0aCBFZGl0YWJsZSBmYWNldFxuICAgICAgICAvLyBldmVudDogJ2lucHV0J1xuICAgIH0sXG4gICAgJ3NwYW4nOiB7XG4gICAgICAgIHByb3BlcnR5OiAnaW5uZXJIVE1MJyxcbiAgICAgICAgZXZlbnQ6ICdpbnB1dCdcbiAgICB9LFxuICAgICdwJzoge1xuICAgICAgICBwcm9wZXJ0eTogJ2lubmVySFRNTCcsXG4gICAgICAgIGV2ZW50OiAnaW5wdXQnXG4gICAgfSxcbiAgICAnaW5wdXQnOiB7XG4gICAgICAgIHByb3BlcnR5OiBpbnB1dERhdGFQcm9wZXJ0eSxcbiAgICAgICAgZXZlbnQ6IGlucHV0Q2hhbmdlRXZlbnRcbiAgICB9LFxuICAgICd0ZXh0YXJlYSc6IHtcbiAgICAgICAgcHJvcGVydHk6ICd2YWx1ZScsXG4gICAgICAgIGV2ZW50OiAnaW5wdXQnXG4gICAgfSxcbiAgICAnc2VsZWN0Jzoge1xuICAgICAgICBwcm9wZXJ0eTogJ3ZhbHVlJyxcbiAgICAgICAgZXZlbnQ6ICdjaGFuZ2UnXG4gICAgfSxcbiAgICAnaW1nJzoge1xuICAgICAgICBwcm9wZXJ0eTogJ3NyYydcbiAgICB9LFxuICAgICdjYXB0aW9uJzoge1xuICAgICAgICBwcm9wZXJ0eTogJ2lubmVySFRNTCcsXG4gICAgICAgIGV2ZW50OiAnaW5wdXQnXG4gICAgfSxcbiAgICAndGhlYWQnOiB7XG4gICAgICAgIHByb3BlcnR5OiAnaW5uZXJIVE1MJyxcbiAgICAgICAgZXZlbnQ6ICdpbnB1dCdcbiAgICB9LFxuICAgICd0Ym9keSc6IHtcbiAgICAgICAgcHJvcGVydHk6ICdpbm5lckhUTUwnLFxuICAgICAgICBldmVudDogJ2lucHV0J1xuICAgIH0sXG4gICAgJ3Rmb290Jzoge1xuICAgICAgICBwcm9wZXJ0eTogJ2lubmVySFRNTCcsXG4gICAgICAgIGV2ZW50OiAnaW5wdXQnXG4gICAgfVxufTtcblxuXG4vLyBjb252ZXJ0IHN0cmluZ3MgdG8gZnVuY3Rpb25zIGFuZCBjcmVhdGUgZ2V0c2V0IG1ldGhvZHNcbl8uZWFjaEtleShkb21FbGVtZW50c0RhdGFBY2Nlc3MsIGZ1bmN0aW9uKHRhZ0luZm8pIHtcbiAgICB2YXIgcHJvcGVydHkgPSB0YWdJbmZvLnByb3BlcnR5XG4gICAgICAgICwgZXZlbnQgPSB0YWdJbmZvLmV2ZW50O1xuICAgIGlmICh0eXBlb2YgcHJvcGVydHkgIT0gJ2Z1bmN0aW9uJylcbiAgICAgICAgdGFnSW5mby5wcm9wZXJ0eSA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gcHJvcGVydHk7IH07XG4gICAgdmFyIHByb3BGdW5jID0gdGFnSW5mby5wcm9wZXJ0eTtcbiAgICBpZiAodHlwZW9mIGV2ZW50ICE9ICdmdW5jdGlvbicpXG4gICAgICAgIHRhZ0luZm8uZXZlbnQgPSBmdW5jdGlvbigpIHsgcmV0dXJuIGV2ZW50OyB9O1xuICAgIGlmICghIHRhZ0luZm8uZ2V0KVxuICAgICAgICB0YWdJbmZvLmdldCA9IGZ1bmN0aW9uKGVsKSB7IHJldHVybiBlbFtwcm9wRnVuYyhlbCldOyB9XG4gICAgaWYgKCEgdGFnSW5mby5zZXQpXG4gICAgICAgIHRhZ0luZm8uc2V0ID0gZnVuY3Rpb24oZWwsIHZhbHVlKSB7XG4gICAgICAgICAgICByZXR1cm4gKGVsW3Byb3BGdW5jKGVsKV0gPSB0eXBlb2YgdmFsdWUgPT0gJ3VuZGVmaW5lZCcgPyAnJyA6IHZhbHVlKTtcbiAgICAgICAgfVxufSk7XG5cblxuLyoqXG4gKiBUeXBlcyBvZiBpbnB1dCBlbGVtZW50c1xuICovXG52YXIgaW5wdXRFbGVtZW50VHlwZXMgPSB7XG4gICAgYnlEZWZhdWx0OiB7XG4gICAgICAgIHByb3BlcnR5OiAndmFsdWUnLFxuICAgICAgICBldmVudDogJ2lucHV0J1xuICAgIH0sXG4gICAgJ2NoZWNrYm94Jzoge1xuICAgICAgICBwcm9wZXJ0eTogJ2NoZWNrZWQnLFxuICAgICAgICBldmVudDogJ2NoYW5nZSdcbiAgICB9LFxuICAgICdyYWRpbyc6IHtcbiAgICAgICAgcHJvcGVydHk6ICdjaGVja2VkJyxcbiAgICAgICAgZXZlbnQ6ICdjaGFuZ2UnXG4gICAgfSxcbiAgICAndGV4dCc6IHtcbiAgICAgICAgcHJvcGVydHk6ICd2YWx1ZScsXG4gICAgICAgIGV2ZW50OiAnaW5wdXQnXG4gICAgfVxufVxuXG5cbi8qKlxuICogUmV0dXJuIHByb3BlcnR5IG9mIGlucHV0IGVsZW1lbnQgdG8gZ2V0L3NldCBpdHMgZGF0YVxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWxcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gaW5wdXREYXRhUHJvcGVydHkoZWwpIHtcbiAgICB2YXIgaW5wdXRUeXBlID0gaW5wdXRFbGVtZW50VHlwZXNbZWwudHlwZV07XG4gICAgcmV0dXJuIGlucHV0VHlwZVxuICAgICAgICAgICAgPyBpbnB1dFR5cGUucHJvcGVydHlcbiAgICAgICAgICAgIDogaW5wdXRFbGVtZW50VHlwZXMuYnlEZWZhdWx0LnByb3BlcnR5O1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBET00gZXZlbnQgdHlwZSB0byBsaXN0ZW4gdG8gdG8gcmVhY3QgdG8gaW5wdXQgZWxlbWVudCBjaGFuZ2VcbiAqXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGlucHV0Q2hhbmdlRXZlbnQoZWwpIHtcbiAgICB2YXIgaW5wdXRUeXBlID0gaW5wdXRFbGVtZW50VHlwZXNbZWwudHlwZV07XG4gICAgcmV0dXJuIGlucHV0VHlwZVxuICAgICAgICAgICAgPyBpbnB1dFR5cGUuZXZlbnRcbiAgICAgICAgICAgIDogaW5wdXRFbGVtZW50VHlwZXMuYnlEZWZhdWx0LmV2ZW50O1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBNZXNzZW5nZXJBUEkgPSByZXF1aXJlKCdtaWxvLWNvcmUnKS5jbGFzc2VzLk1lc3NlbmdlckFQSTtcblxuXG52YXIgRHJvcE1zZ0FQSSA9IF8uY3JlYXRlU3ViY2xhc3MoTWVzc2VuZ2VyQVBJLCAnRHJvcE1zZ0FQSScsIHRydWUpO1xuXG5cbl8uZXh0ZW5kUHJvdG8oRHJvcE1zZ0FQSSwge1xuICAgIC8vIGltcGxlbWVudGluZyBNZXNzYWdlU291cmNlIGludGVyZmFjZVxuICAgIHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZTogdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlLFxuICAgIGZpbHRlclNvdXJjZU1lc3NhZ2U6IGZpbHRlclNvdXJjZU1lc3NhZ2UsXG59KTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IERyb3BNc2dBUEk7XG5cblxudmFyIGRyb3BFdmVudHNNYXAgPSB7XG4gICAgJ2RyYWdpbic6ICdkcmFnZW50ZXInLFxuICAgICdkcmFnb3V0JzogJ2RyYWdsZWF2ZSdcbn07XG5cblxuZnVuY3Rpb24gdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgICByZXR1cm4gZHJvcEV2ZW50c01hcC5oYXNPd25Qcm9wZXJ0eShtZXNzYWdlKVxuICAgICAgICAgICAgPyBkcm9wRXZlbnRzTWFwW21lc3NhZ2VdXG4gICAgICAgICAgICA6IG1lc3NhZ2U7XG59XG5cbmZ1bmN0aW9uIHJlc2V0RmlsdGVyVmFycygpIHtcbiAgICBkZWxldGUgdGhpcy5fY3VycmVudFRhcmdldDtcbiAgICBkZWxldGUgdGhpcy5faW5zaWRlO1xufVxuXG5mdW5jdGlvbiBmaWx0ZXJTb3VyY2VNZXNzYWdlKHNvdXJjZU1lc3NhZ2UsIG1lc3NhZ2UsIGRhdGEpIHsgLy8gZGF0YSBpcyBET00gZXZlbnQgb2JqZWN0XG4gICAgdmFyIG9rID0gdHJ1ZTtcblxuICAgIGlmIChzb3VyY2VNZXNzYWdlID09ICdkcmFnZW50ZXInICYmIG1lc3NhZ2UgPT0gJ2RyYWdpbicpIHtcbiAgICAgICAgdGhpcy5fY3VycmVudFRhcmdldCA9IGRhdGEudGFyZ2V0O1xuICAgICAgICBvayA9ICF0aGlzLl9pbnNpZGU7XG4gICAgICAgIHRoaXMuX2luc2lkZSA9IHRydWU7XG4gICAgfSBlbHNlIGlmIChzb3VyY2VNZXNzYWdlID09ICdkcmFnbGVhdmUnICYmIG1lc3NhZ2UgPT0gJ2RyYWdvdXQnKSB7XG4gICAgICAgIG9rID0gdGhpcy5fY3VycmVudFRhcmdldCA9PSBkYXRhLnRhcmdldDtcbiAgICAgICAgaWYgKG9rKSByZXNldEZpbHRlclZhcnMuY2FsbCh0aGlzKTtcbiAgICB9IGVsc2UgaWYgKHNvdXJjZU1lc3NhZ2UgPT0gJ2Ryb3AnKSByZXNldEZpbHRlclZhcnMuY2FsbCh0aGlzKTtcblxuICAgIHJldHVybiBvaztcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgRE9NRW1pdHRlclNvdXJjZSA9IHJlcXVpcmUoJy4uLy4uL3NlcnZpY2VzL2RvbV9zb3VyY2UnKVxuICAgICwgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgTWVzc2FnZVNvdXJjZSA9IG1pbG9Db3JlLmNsYXNzZXMuTWVzc2FnZVNvdXJjZVxuICAgICwgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIGNoZWNrID0gbWlsb0NvcmUudXRpbC5jaGVja1xuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaDtcblxudmFyIERPTUV2ZW50c1NvdXJjZSA9IF8uY3JlYXRlU3ViY2xhc3MoRE9NRW1pdHRlclNvdXJjZSwgJ0RPTUV2ZW50c1NvdXJjZScsIHRydWUpO1xuXG5cbl8uZXh0ZW5kUHJvdG8oRE9NRXZlbnRzU291cmNlLCB7XG4gICAgaW5pdDogaW5pdCxcbiAgICBkZXN0cm95OiBET01FdmVudHNTb3VyY2UkZGVzdHJveSxcbiAgICBlbWl0dGVyOiBlbWl0dGVyXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBET01FdmVudHNTb3VyY2U7XG5cblxudmFyIHVzZUNhcHR1cmVQYXR0ZXJuID0gL19fY2FwdHVyZSQvXG4gICAgLCB1c2VDYXB0dXJlUG9zdGZpeCA9ICdfX2NhcHR1cmUnO1xuXG5cbi8vIGluaXQgRE9NIGV2ZW50IHNvdXJjZVxuZnVuY3Rpb24gaW5pdChob3N0T2JqZWN0LCBwcm94eU1ldGhvZHMsIG1lc3NlbmdlckFQSU9yQ2xhc3MsIGNvbXBvbmVudCkge1xuICAgIGNoZWNrKGNvbXBvbmVudCwgQ29tcG9uZW50KTtcbiAgICB0aGlzLmNvbXBvbmVudCA9IGNvbXBvbmVudDtcbiAgICBNZXNzYWdlU291cmNlLnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuZnVuY3Rpb24gRE9NRXZlbnRzU291cmNlJGRlc3Ryb3koKSB7XG4gICAgTWVzc2FnZVNvdXJjZS5wcm90b3R5cGUuZGVzdHJveS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIGRlbGV0ZSB0aGlzLmNvbXBvbmVudDtcbn1cblxuXG4vLyBnZXQgRE9NIGVsZW1lbnQgb2YgY29tcG9uZW50XG5mdW5jdGlvbiBlbWl0dGVyKCkge1xuICAgIHJldHVybiB0aGlzLmNvbXBvbmVudC5lbDtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gIyMjY29tcG9uZW50IGlmcmFtZSBzb3VyY2VcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgTWVzc2FnZVNvdXJjZSA9IG1pbG9Db3JlLmNsYXNzZXMuTWVzc2FnZVNvdXJjZVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvXG4gICAgLCBjaGVjayA9IG1pbG9Db3JlLnV0aWwuY2hlY2tcbiAgICAsIGxvZ2dlciA9IG1pbG9Db3JlLnV0aWwubG9nZ2VyXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG52YXIgRnJhbWVNZXNzYWdlU291cmNlID0gXy5jcmVhdGVTdWJjbGFzcyhNZXNzYWdlU291cmNlLCAnRnJhbWVNZXNzYWdlU291cmNlJywgdHJ1ZSk7XG5cblxuXy5leHRlbmRQcm90byhGcmFtZU1lc3NhZ2VTb3VyY2UsIHtcbiAgICAvLyBpbXBsZW1lbnRpbmcgTWVzc2FnZVNvdXJjZSBpbnRlcmZhY2VcbiAgICBpbml0OiBpbml0LFxuICAgIGFkZFNvdXJjZVN1YnNjcmliZXI6IGFkZFNvdXJjZVN1YnNjcmliZXIsXG4gICAgcmVtb3ZlU291cmNlU3Vic2NyaWJlcjogcmVtb3ZlU291cmNlU3Vic2NyaWJlcixcbiAgICB0cmlnZ2VyOiB0cmlnZ2VyLFxuXG4gICAgLy9jbGFzcyBzcGVjaWZpYyBtZXRob2RzXG4gICAgZnJhbWVXaW5kb3c6IGZyYW1lV2luZG93LFxuICAgIGhhbmRsZUV2ZW50OiBoYW5kbGVFdmVudCAgLy8gZXZlbnQgZGlzcGF0Y2hlciAtIGFzIGRlZmluZWQgYnkgRXZlbnQgRE9NIEFQSVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRnJhbWVNZXNzYWdlU291cmNlO1xuXG5cbmZ1bmN0aW9uIGluaXQoaG9zdE9iamVjdCwgcHJveHlNZXRob2RzLCBtZXNzZW5nZXJBUElPckNsYXNzLCBjb21wb25lbnQpIHtcbiAgICBjaGVjayhjb21wb25lbnQsIENvbXBvbmVudCk7XG4gICAgdGhpcy5jb21wb25lbnQgPSBjb21wb25lbnQ7XG5cbiAgICBpZiAoY29tcG9uZW50LmVsLnRhZ05hbWUudG9Mb3dlckNhc2UoKSAhPSAnaWZyYW1lJylcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjb21wb25lbnQgZm9yIEZyYW1lTWVzc2FnZVNvdXJjZSBjYW4gb25seSBiZSBhdHRhY2hlZCB0byBpZnJhbWUgZWxlbWVudCcpO1xuXG4gICAgTWVzc2FnZVNvdXJjZS5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbmZ1bmN0aW9uIGZyYW1lV2luZG93KCkge1xuICAgIHJldHVybiB0aGlzLmNvbXBvbmVudC5lbC5jb250ZW50V2luZG93O1xufVxuXG5cbi8vIGFkZElGcmFtZU1lc3NhZ2VMaXN0ZW5lclxuZnVuY3Rpb24gYWRkU291cmNlU3Vic2NyaWJlcihzb3VyY2VNZXNzYWdlKSB7XG4gICAgdmFyIHdpbiA9IHRoaXMuZnJhbWVXaW5kb3coKTtcbiAgICBpZiAod2luKSB3aW4uYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIHRoaXMsIGZhbHNlKTtcbiAgICBlbHNlIGxvZ2dlci53YXJuKCdGcmFtZU1lc3NhZ2VTb3VyY2U6IGZyYW1lIHdpbmRvdyBpcyB1bmRlZmluZWQnKTtcbn1cblxuXG4vLyByZW1vdmVJRnJhbWVNZXNzYWdlTGlzdGVuZXJcbmZ1bmN0aW9uIHJlbW92ZVNvdXJjZVN1YnNjcmliZXIoc291cmNlTWVzc2FnZSkge1xuICAgIHZhciB3aW4gPSB0aGlzLmZyYW1lV2luZG93KCk7XG4gICAgaWYgKHdpbikgd2luLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCB0aGlzLCBmYWxzZSk7XG4gICAgZWxzZSBsb2dnZXIud2FybignRnJhbWVNZXNzYWdlU291cmNlOiBmcmFtZSB3aW5kb3cgaXMgdW5kZWZpbmVkJyk7XG59XG5cblxuZnVuY3Rpb24gdHJpZ2dlcihtc2dUeXBlLCBkYXRhKSB7XG4gICAgZGF0YSA9IGRhdGEgfHwge307XG4gICAgZGF0YS50eXBlID0gbXNnVHlwZTtcblxuICAgIHRoaXMuZnJhbWVXaW5kb3coKS5wb3N0TWVzc2FnZShkYXRhLCAnKicpO1xufVxuXG5cbi8vIFRPRE8gbWF5YmUgcmVmYWN0b3IgdG8gRnJhbWVNc2dBUEk/XG5mdW5jdGlvbiBoYW5kbGVFdmVudChldmVudCkge1xuICAgIHRoaXMuZGlzcGF0Y2hNZXNzYWdlKGV2ZW50LmRhdGEudHlwZSwgZXZlbnQpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvXG4gICAgLCBjb21wb25lbnROYW1lID0gcmVxdWlyZSgnLi4vdXRpbC9jb21wb25lbnRfbmFtZScpXG4gICAgLCBjaGVjayA9IG1pbG9Db3JlLnV0aWwuY2hlY2tcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2hcbiAgICAsIGxvZ2dlciA9IG1pbG9Db3JlLnV0aWwubG9nZ2VyO1xuXG5cbi8qKlxuICogU2NvcGUgY2xhc3MuXG4gKiBAcGFyYW0ge0VsZW1lbnR9IHJvb3RFbCB0aGUgcm9vdCBlbGVtZW50IG9mIHRoaXMgc2NvcGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0T2JqZWN0IHRoZSBob3N0IFxuICogQHJldHVybiB7U2NvcGV9XG4gKi9cbmZ1bmN0aW9uIFNjb3BlKHJvb3RFbCwgaG9zdE9iamVjdCkge1xuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgIF9yb290RWw6IHJvb3RFbCxcbiAgICAgICAgX2hvc3RPYmplY3Q6IGhvc3RPYmplY3RcbiAgICB9LCBfLldSSVQpOyAvLyB3cml0YWJsZVxufTtcblxuXy5leHRlbmRQcm90byhTY29wZSwge1xuICAgIF9hZGQ6IFNjb3BlJF9hZGQsXG4gICAgX3NhZmVBZGQ6IFNjb3BlJF9zYWZlQWRkLFxuICAgIF9jb3B5OiBTY29wZSRfY29weSxcbiAgICBfZWFjaDogU2NvcGUkX2VhY2gsXG4gICAgX21vdmU6IFNjb3BlJF9tb3ZlLFxuICAgIF9tZXJnZTogU2NvcGUkX21lcmdlLFxuICAgIF9sZW5ndGg6IFNjb3BlJF9sZW5ndGgsXG4gICAgX2FueTogU2NvcGUkX2FueSxcbiAgICBfcmVtb3ZlOiBTY29wZSRfcmVtb3ZlLFxuICAgIF9jbGVhbjogU2NvcGUkX2NsZWFuLFxuICAgIF9kZXRhY2hFbGVtZW50OiBTY29wZSRfZGV0YWNoRWxlbWVudCxcbiAgICBfaGFzOiBTY29wZSRfaGFzLFxuICAgIF9maWx0ZXI6IFNjb3BlJF9maWx0ZXJcbn0pO1xuXG5cbl8uZXh0ZW5kKFNjb3BlLCB7XG4gICAgcmVuYW1lOiBTY29wZSQkcmVuYW1lXG59KTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IFNjb3BlO1xuXG5cbnZhciBhbGxvd2VkTmFtZVBhdHRlcm4gPSAvXltBLVphLXpdW0EtWmEtejAtOVxcX1xcJF0qJC87XG5cblxuLyoqXG4gKiBTY29wZSBpbnN0YW5jZSBtZXRob2QuXG4gKiBBZGRzIG9iamVjdCB0byB0aGUgc2NvcGUsIHRocm93aW5nIGlmIG5hbWUgaXMgbm90IHVuaXF1ZVxuICogQHBhcmFtIHtDb21wb25lbnR8Q29tcG9uZW50SW5mb30gb2JqZWN0IGNvbXBvbmVudCBvciBjb21wb25lbnQgaW5mbyB0byBhZGQgdG8gdGhlIHNjb3BlXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSB0aGUgbmFtZSBvZiB0aGUgY29tcG9uZW50IHRvIGFkZFxuICovXG5mdW5jdGlvbiBTY29wZSRfYWRkKG9iamVjdCwgbmFtZSkge1xuICAgIGlmICh0eXBlb2YgbmFtZSA9PSAnc3RyaW5nJylcbiAgICAgICAgb2JqZWN0Lm5hbWUgPSBuYW1lO1xuICAgIGVsc2VcbiAgICAgICAgbmFtZSA9IG9iamVjdC5uYW1lO1xuICAgIFxuICAgIGlmICh0aGlzLmhhc093blByb3BlcnR5KG5hbWUpKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2R1cGxpY2F0ZSBvYmplY3QgbmFtZTogJyArIG5hbWUpO1xuXG4gICAgY2hlY2tOYW1lKG5hbWUpO1xuICAgIF9fYWRkLmNhbGwodGhpcywgb2JqZWN0LCBuYW1lKTtcbn1cblxuXG4vKipcbiAqIFNjb3BlIGluc3RhbmNlIG1ldGhvZFxuICogQWRkcyBvYmplY3QgdG8gc2NvcGUgcmVuYW1pbmcgaXQgaWYgbmFtZSBpcyBub3QgdW5pcXVlXG4gKiBAcGFyYW0ge0NvbXBvbmVudHxDb21wb25lbnRJbmZvfSBvYmplY3QgY29tcG9uZW50IG9yIGNvbXBvbmVudCBpbmZvIHRvIGFkZCB0byB0aGUgc2NvcGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIHRoZSBuYW1lIG9mIHRoZSBjb21wb25lbnQgdG8gYWRkXG4gKi9cbmZ1bmN0aW9uIFNjb3BlJF9zYWZlQWRkKG9iamVjdCwgbmFtZSkge1xuICAgIGlmICh0eXBlb2YgbmFtZSA9PSAnc3RyaW5nJylcbiAgICAgICAgb2JqZWN0Lm5hbWUgPSBuYW1lO1xuICAgIGVsc2VcbiAgICAgICAgbmFtZSA9IG9iamVjdC5uYW1lO1xuXG4gICAgdmFyIHNob3VsZFJlbmFtZSA9IHRoaXMuaGFzT3duUHJvcGVydHkobmFtZSk7XG4gICAgaWYgKHNob3VsZFJlbmFtZSlcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdTY29wZTogZHVwbGljYXRlIG9iamVjdCBuYW1lOiAnICsgbmFtZSk7XG4gICAgZWxzZSB7XG4gICAgICAgIHNob3VsZFJlbmFtZSA9ICEgYWxsb3dlZE5hbWVQYXR0ZXJuLnRlc3QobmFtZSk7XG4gICAgICAgIGlmIChzaG91bGRSZW5hbWUpXG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ1Njb3BlOiBuYW1lIHNob3VsZCBzdGFydCBmcm9tIGxldHRlciwgdGhpcyBuYW1lIGlzIG5vdCBhbGxvd2VkOiAnICsgbmFtZSk7XG4gICAgfVxuXG4gICAgaWYgKHNob3VsZFJlbmFtZSkge1xuICAgICAgICBuYW1lID0gY29tcG9uZW50TmFtZSgpO1xuICAgICAgICBvYmplY3QubmFtZSA9IG5hbWU7XG4gICAgfVxuXG4gICAgX19hZGQuY2FsbCh0aGlzLCBvYmplY3QsIG5hbWUpO1xufVxuXG5cbmZ1bmN0aW9uIF9fYWRkKG9iamVjdCwgbmFtZSkge1xuICAgIHRoaXNbbmFtZV0gPSBvYmplY3Q7XG4gICAgb2JqZWN0LnNjb3BlID0gdGhpcztcblxuICAgIGlmICh0eXBlb2Ygb2JqZWN0LnBvc3RNZXNzYWdlID09PSAnZnVuY3Rpb24nKVxuICAgICAgICBvYmplY3QucG9zdE1lc3NhZ2UoJ2FkZGVkdG9zY29wZScpOyBcbn1cblxuXG4vKipcbiAqIEluc3RhbmNlIG1ldGhvZC5cbiAqIGNvcGllcyBhbGwgb2JqZWN0cyBmcm9tIG9uZSBzY29wZSB0byBhbm90aGVyLFxuICogdGhyb3dpbmcgaWYgc29tZSBvYmplY3QgaXMgbm90IHVuaXF1ZVxuICogQHBhcmFtIHtTY29wZX0gYVNjb3BlIHRoZSBzY29wZSB0byBjb3B5XG4gKi9cbmZ1bmN0aW9uIFNjb3BlJF9jb3B5KGFTY29wZSkge1xuICAgIGNoZWNrKGFTY29wZSwgU2NvcGUpO1xuXG4gICAgYVNjb3BlLl9lYWNoKFNjb3BlJF9hZGQsIHRoaXMpO1xufVxuXG5cbi8qKlxuICogSW5zdGFuY2UgbWV0aG9kLlxuICogTW92ZXMgYSBjb21wb25lbnQgZnJvbSB0aGlzIHNjb3BlIHRvIGFub3RoZXIgc2NvcGUuXG4gKiBAcGFyYW0ge0NvbXBvbmVudH0gY29tcG9uZW50IHRoZSBjb21wb25lbnQgdG8gYmUgbW92ZWRcbiAqIEBwYXJhbSB7U2NvcGV9IG90aGVyU2NvcGUgdGhlIHNjb3BlIHRvIGNvcHkgdGhlIGNvbXBvbmVudCB0b1xuICovXG5mdW5jdGlvbiBTY29wZSRfbW92ZShjb21wb25lbnQsIG90aGVyU2NvcGUpIHtcbiAgICBvdGhlclNjb3BlLl9hZGQoY29tcG9uZW50KTtcbiAgICB0aGlzLl9yZW1vdmUoY29tcG9uZW50Lm5hbWUpO1xuICAgIGNvbXBvbmVudC5zY29wZSA9IG90aGVyU2NvcGU7XG59XG5cblxuLyoqXG4gKiBJbnN0YW5jZSBtZXRob2QuXG4gKiBNZXJnZXMgb25lIHNjb3BlIGludG8gdGhpcyBzY29wZVxuICogQHBhcmFtIHtTY29wZX0gc2NvcGUgdGhlIHNjb3BlIHRvIGFic29yYlxuICovXG5mdW5jdGlvbiBTY29wZSRfbWVyZ2Uoc2NvcGUpIHtcbiAgICBzY29wZS5fZWFjaChmdW5jdGlvbiAoY29tcCkge1xuICAgICAgICB0aGlzLl9hZGQoY29tcCwgY29tcC5uYW1lKTtcbiAgICAgICAgc2NvcGUuX3JlbW92ZShjb21wLm5hbWUpO1xuICAgIH0sIHRoaXMpO1xufVxuXG5cbi8qKlxuICogSW5zdGFuY2UgbWV0aG9kLlxuICogRW51bWVyYXRlcyBlYWNoIGNvbXBvbmVudCBpbiB0aGUgc2NvcGVcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIHRoZSBmdW5jdGlvbiB0byBleGVjdXRlIGZvciBlYWNoIGNvbXBvbmVudFxuICogQHBhcmFtIHtPYmplY3R9IHRoaXNBcmcgdGhlIGNvbnRleHRcbiAqL1xuZnVuY3Rpb24gU2NvcGUkX2VhY2goY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICBfLmVhY2hLZXkodGhpcywgY2FsbGJhY2ssIHRoaXNBcmcgfHwgdGhpcywgdHJ1ZSk7IC8vIGVudW1lcmF0ZXMgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9ubHlcbn1cblxuXG4vKipcbiAqIEluc3RhbmNlIG1ldGhvZC5cbiAqIFJldHVybnMgYSBmaWx0ZXJlZCBsaXN0IG9mIGNvbXBvbmVudHMgYmFzZWQgb24gYSBjYWxsYmFja1xuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgdGhlIGZ1bmN0aW9uIHRvIGV4ZWN1dGUgZm9yIGVhY2ggY29tcG9uZW50XG4gKiBAcGFyYW0ge09iamVjdH0gdGhpc0FyZyB0aGUgY29udGV4dFxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIFNjb3BlJF9maWx0ZXIoY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICByZXR1cm4gXy5maWx0ZXJLZXlzKHRoaXMsIGNhbGxiYWNrLCB0aGlzQXJnIHx8IHRoaXMsIHRydWUpO1xufVxuXG5cbi8qKlxuICogQ2hlY2tzIHRoZSB2YWxpZGl0eSBvZiBhIG5hbWUuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayB0aGUgZnVuY3Rpb24gdG8gZXhlY3V0ZSBmb3IgZWFjaCBjb21wb25lbnRcbiAqL1xuZnVuY3Rpb24gY2hlY2tOYW1lKG5hbWUpIHtcbiAgICBpZiAoISBhbGxvd2VkTmFtZVBhdHRlcm4udGVzdChuYW1lKSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCduYW1lIHNob3VsZCBzdGFydCBmcm9tIGxldHRlciwgdGhpcyBuYW1lIGlzIG5vdCBhbGxvd2VkOiAnICsgbmFtZSk7XG59XG5cblxuLyoqXG4gKiBJbnN0YW5jZSBtZXRob2QuXG4gKiBSZXR1cm5zIHRoZSBudW1iZXIgb2Ygb2JqZWN0cyBpbiB0aGUgc2NvcGVcbiAqIEByZXR1cm4ge051bWJlcn1cbiAqL1xuZnVuY3Rpb24gU2NvcGUkX2xlbmd0aCgpIHtcbiAgICByZXR1cm4gT2JqZWN0LmtleXModGhpcykubGVuZ3RoO1xufVxuXG5cbi8qKlxuICogSW5zdGFuY2UgbWV0aG9kLlxuICogUmV0dXJucyBhIGNvbXBvbmVudCBmcm9tIHRoZSBzY29wZS4gSXQgbWF5IGxvb2sgbGlrZSBpdCByZXR1cm5zIHRoZSBmaXJzdCBjb21wb25lbnRcbiAqIGJ1dCBpbiByZWFsaXR5IGdpdmVuIHRoYXQgc2NvcGVzIGFyZSBoYXNoZXMsIHRoZXJlIGlzIG5vIHN1Y2ggdGhpbmcuXG4gKiBAcmV0dXJuIHtDb21wb25lbnR9XG4gKi9cbmZ1bmN0aW9uIFNjb3BlJF9hbnkoKSB7XG4gICAgdmFyIGtleSA9IE9iamVjdC5rZXlzKHRoaXMpWzBdO1xuICAgIHJldHVybiBrZXkgJiYgdGhpc1trZXldO1xufVxuXG5cbi8qKlxuICogSW5zdGFuY2UgbWV0aG9kLlxuICogUmVtb3ZlcyBhIGNvbXBvbmVudCBmcm9tIHRoZSBzY29wZSBieSBpdCdzIG5hbWUuXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSB0aGUgbmFtZSBvZiB0aGUgY29tcG9uZW50IHRvIHJlbW92ZVxuICogQHBhcmFtIHtCb29sZWFufSBxdWlldCBvcHRpb25hbCB0cnVlIHRvIHN1cHByZXNzIHRoZSB3YXJuaW5nIG1lc3NhZ2UgaWYgdGhlIGNvbXBvbmVudCBpcyBub3QgaW4gc2NvcGVcbiAqL1xuZnVuY3Rpb24gU2NvcGUkX3JlbW92ZShuYW1lLCBxdWlldCkge1xuICAgIGlmICghIChuYW1lIGluIHRoaXMpKSB7XG4gICAgICAgIGlmICghcXVpZXQpIGxvZ2dlci53YXJuKCdyZW1vdmluZyBvYmplY3QgdGhhdCBpcyBub3QgaW4gc2NvcGUnKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBvYmplY3QgPSB0aGlzW25hbWVdO1xuXG4gICAgZGVsZXRlIHRoaXNbbmFtZV07XG5cbiAgICBpZiAodHlwZW9mIG9iamVjdC5wb3N0TWVzc2FnZSA9PT0gJ2Z1bmN0aW9uJylcbiAgICAgICAgb2JqZWN0LnBvc3RNZXNzYWdlKCdyZW1vdmVkZnJvbXNjb3BlJyk7XG59XG5cblxuLyoqXG4gKiBJbnN0YW5jZSBtZXRob2QuXG4gKiBSZW1vdmVzIGFsbCBjb21wb25lbnRzIGZyb20gdGhlIHNjb3BlLlxuICovXG5mdW5jdGlvbiBTY29wZSRfY2xlYW4oKSB7XG4gICAgdGhpcy5fZWFjaChmdW5jdGlvbihvYmplY3QsIG5hbWUpIHtcbiAgICAgICAgZGVsZXRlIHRoaXNbbmFtZV0uc2NvcGU7XG4gICAgICAgIGRlbGV0ZSB0aGlzW25hbWVdO1xuICAgIH0sIHRoaXMpO1xufVxuXG5mdW5jdGlvbiBTY29wZSRfZGV0YWNoRWxlbWVudCgpIHtcbiAgICB0aGlzLl9yb290RWwgPSBudWxsO1xufVxuXG5cbi8qKlxuICogQ2hlY2tzIGlmIHNjb3BlIGhhcyBvYmplY3QgYnkgb2JqZWN0IG5hbWVcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIFNjb3BlJF9oYXMob2JqZWN0KSB7XG4gICAgcmV0dXJuIHRoaXMuaGFzT3duUHJvcGVydHkob2JqZWN0Lm5hbWUpO1xufVxuXG5cbi8qKlxuICogQ2hhbmdlIG9iamVjdCBuYW1lLCByZW5hbWluZyBpdCBpbiBzY29wZSB1bmxlc3MgcmVuYW1lSW5TY29wZSBpcyBmYWxzZVxuICogQHBhcmFtIHtPYmplY3R9IG9ialxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWUgbmV3IG5hbWVcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gcmVuYW1lSW5TY29wZSB0cnVlIGJ5IGRlZmF1bHRcbiAqL1xuZnVuY3Rpb24gU2NvcGUkJHJlbmFtZShvYmosIG5hbWUsIHJlbmFtZUluU2NvcGUpIHtcbiAgICBpZiAob2JqLnNjb3BlICYmIHJlbmFtZUluU2NvcGUgIT09IGZhbHNlKSB7XG4gICAgICAgIG9iai5zY29wZS5fcmVtb3ZlKG9iai5uYW1lKTtcbiAgICAgICAgb2JqLnNjb3BlLl9hZGQob2JqLCBuYW1lKTtcbiAgICB9IGVsc2VcbiAgICAgICAgb2JqLm5hbWUgPSBuYW1lO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5JylcbiAgICAsIF8gPSByZXF1aXJlKCdtaWxvLWNvcmUnKS5wcm90bztcblxuXG52YXIgTUxCdXR0b24gPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MQnV0dG9uJywge1xuICAgIGV2ZW50czogdW5kZWZpbmVkLFxuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS1idXR0b24nXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxCdXR0b24pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MQnV0dG9uO1xuXG5fLmV4dGVuZFByb3RvKE1MQnV0dG9uLCB7XG4gICAgZGlzYWJsZTogTUxCdXR0b24kZGlzYWJsZSxcbiAgICBpc0Rpc2FibGVkOiBNTEJ1dHRvbiRpc0Rpc2FibGVkXG59KTtcblxuXG5mdW5jdGlvbiBNTEJ1dHRvbiRkaXNhYmxlKGRpc2FibGUpIHtcbiAgICB0aGlzLmVsLmRpc2FibGVkID0gZGlzYWJsZTtcbn1cblxuZnVuY3Rpb24gTUxCdXR0b24kaXNEaXNhYmxlZCgpIHtcbiAgICByZXR1cm4gISF0aGlzLmVsLmRpc2FibGVkO1xufVxuXG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jX2NsYXNzJylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2NfcmVnaXN0cnknKVxuICAgICwgXyA9IHJlcXVpcmUoJ21pbG8tY29yZScpLnByb3RvO1xuXG5cbnZhciBDT01CT19DSEFOR0VfTUVTU0FHRSA9ICdtbGNvbWJvY2hhbmdlJztcblxudmFyIERBVEFMSVNUX1RFTVBMQVRFID0gJ3t7fiBpdC5jb21ib09wdGlvbnMgOm9wdGlvbiB9fSBcXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJ7ez0gb3B0aW9uLmxhYmVsIH19XCI+PC9vcHRpb24+IFxcXG4gICAgICAgICAgICAgICAgICAgICAgICAge3t+fX0nO1xuXG52YXIgTUxDb21ibyA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxDb21ibycsIHtcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBkYXRhOiB7XG4gICAgICAgIGdldDogTUxDb21ib19nZXQsXG4gICAgICAgIHNldDogTUxDb21ib19zZXQsXG4gICAgICAgIGRlbDogTUxDb21ib19kZWwsXG4gICAgICAgIHNwbGljZTogdW5kZWZpbmVkLFxuICAgICAgICBldmVudDogQ09NQk9fQ0hBTkdFX01FU1NBR0VcbiAgICB9LFxuICAgIG1vZGVsOiB7XG4gICAgICAgIG1lc3NhZ2VzOiB7XG4gICAgICAgICAgICAnKioqJzogeyBzdWJzY3JpYmVyOiBvbk9wdGlvbnNDaGFuZ2UsIGNvbnRleHQ6ICdvd25lcicgfVxuICAgICAgICB9XG4gICAgfSxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktZGF0YWxpc3QnXG4gICAgfSxcbiAgICBjb250YWluZXI6IHVuZGVmaW5lZFxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxDb21ibyk7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxDb21ibztcblxuXG5fLmV4dGVuZFByb3RvKE1MQ29tYm8sIHtcbiAgICBpbml0OiBNTENvbWJvJGluaXRcbn0pO1xuXG5cbmZ1bmN0aW9uIE1MQ29tYm8kaW5pdCgpIHtcbiAgICBDb21wb25lbnQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB0aGlzLm9uKCdjaGlsZHJlbmJvdW5kJywgb25DaGlsZHJlbkJvdW5kKTtcbn1cblxuZnVuY3Rpb24gb25DaGlsZHJlbkJvdW5kKCkge1xuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgICdfY29tYm9JbnB1dCc6IHRoaXMuY29udGFpbmVyLnNjb3BlLmlucHV0LFxuICAgICAgICAnX2NvbWJvTGlzdCc6IHRoaXMuY29udGFpbmVyLnNjb3BlLmRhdGFsaXN0XG4gICAgfSk7XG5cbiAgICB0aGlzLl9jb21ib0xpc3QudGVtcGxhdGUuc2V0KERBVEFMSVNUX1RFTVBMQVRFKTtcblxuICAgIHRoaXMuX2NvbWJvSW5wdXQuZGF0YS5vbignaW5wdXQnLFxuICAgICAgICB7IHN1YnNjcmliZXI6IGRpc3BhdGNoQ2hhbmdlTWVzc2FnZSwgY29udGV4dDogdGhpcyB9KTtcbn1cblxuZnVuY3Rpb24gTUxDb21ib19nZXQoKSB7XG4gICAgaWYgKCEgdGhpcy5fY29tYm9JbnB1dCkgcmV0dXJuO1xuICAgIHJldHVybiB0aGlzLl9jb21ib0lucHV0LmRhdGEuZ2V0KCk7XG59XG5cbmZ1bmN0aW9uIE1MQ29tYm9fc2V0KHZhbHVlKSB7XG4gICAgcmV0dXJuIGNoYW5nZUNvbWJvRGF0YS5jYWxsKHRoaXMsICdzZXQnLCB2YWx1ZSk7XG59XG5cbmZ1bmN0aW9uIE1MQ29tYm9fZGVsKCkge1xuICAgIHJldHVybiBjaGFuZ2VDb21ib0RhdGEuY2FsbCh0aGlzLCAnZGVsJywgdmFsdWUpO1xufVxuXG5mdW5jdGlvbiBjaGFuZ2VDb21ib0RhdGEobWV0aG9kLCB2YWx1ZSkge1xuICAgIGlmICghIHRoaXMuX2NvbWJvSW5wdXQpIHJldHVybjtcbiAgICB2YXIgcmVzdWx0ID0gdGhpcy5fY29tYm9JbnB1dC5kYXRhW21ldGhvZF0odmFsdWUpO1xuICAgIGRpc3BhdGNoQ2hhbmdlTWVzc2FnZS5jYWxsKHRoaXMpO1xuICAgIHJldHVybiByZXN1bHQ7XG59XG5cblxuLy8gUG9zdCB0aGUgZGF0YSBjaGFuZ2VcbmZ1bmN0aW9uIGRpc3BhdGNoQ2hhbmdlTWVzc2FnZSgpIHtcbiAgICB0aGlzLmRhdGEuZGlzcGF0Y2hTb3VyY2VNZXNzYWdlKENPTUJPX0NIQU5HRV9NRVNTQUdFKTtcbn1cblxuZnVuY3Rpb24gb25PcHRpb25zQ2hhbmdlKG1zZywgZGF0YSkge1xuICAgIHRoaXMuX2NvbWJvTGlzdC50ZW1wbGF0ZS5yZW5kZXIoe1xuICAgICAgICBjb21ib09wdGlvbnM6IHRoaXMubW9kZWwuZ2V0KClcbiAgICB9KTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbWlsby1jb3JlJykucHJvdG87XG5cbnZhciBDT01CT19MSVNUX0NIQU5HRV9NRVNTQUdFID0gJ21sY29tYm9saXN0Y2hhbmdlJztcblxuXG52YXIgTUxDb21ib0xpc3QgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MQ29tYm9MaXN0Jywge1xuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS1jb21iby1saXN0J1xuICAgIH0sXG4gICAgZGF0YToge1xuICAgICAgICBnZXQ6IE1MQ29tYm9MaXN0X2dldCxcbiAgICAgICAgc2V0OiBNTENvbWJvTGlzdF9zZXQsXG4gICAgICAgIGRlbDogTUxDb21ib0xpc3RfZGVsLFxuICAgICAgICBldmVudDogQ09NQk9fTElTVF9DSEFOR0VfTUVTU0FHRVxuICAgIH0sXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgY29udGFpbmVyOiB1bmRlZmluZWQsXG4gICAgbW9kZWw6IHtcbiAgICAgICAgbWVzc2FnZXM6IHtcbiAgICAgICAgICAgICcqKionOiB7IHN1YnNjcmliZXI6IG9uSXRlbXNDaGFuZ2UsIGNvbnRleHQ6ICdvd25lcid9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICAgIHRlbXBsYXRlOiAnPGRpdiBtbC1iaW5kPVwiTUxTdXBlckNvbWJvOmNvbWJvXCI+PC9kaXY+XFxcbiAgICAgICAgICAgICAgICAgICA8ZGl2IG1sLWJpbmQ9XCJNTExpc3Q6bGlzdFwiPlxcXG4gICAgICAgICAgICAgICAgICAgICAgIDxkaXYgbWwtYmluZD1cIk1MTGlzdEl0ZW06aXRlbVwiIGNsYXNzPVwibGlzdC1pdGVtXCI+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIG1sLWJpbmQ9XCJbZGF0YV06bGFiZWxcIj48L3NwYW4+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIG1sLWJpbmQ9XCJbZXZlbnRzXTpkZWxldGVCdG5cIiBjbGFzcz1cImdseXBoaWNvbiBnbHlwaGljb24tcmVtb3ZlXCI+PC9zcGFuPlxcXG4gICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxcXG4gICAgICAgICAgICAgICAgICAgPC9kaXY+J1xuICAgIH1cbn0pO1xuXG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxDb21ib0xpc3QpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MQ29tYm9MaXN0O1xuXG5cbl8uZXh0ZW5kUHJvdG8oTUxDb21ib0xpc3QsIHtcbiAgICBpbml0OiBNTENvbWJvTGlzdCRpbml0LFxuICAgIHNldE9wdGlvbnM6IE1MQ29tYm9MaXN0JHNldE9wdGlvbnMsXG4gICAgc2V0RGF0YVZhbGlkYXRpb246IE1MQ29tYm9MaXN0JHNldERhdGFWYWxpZGF0aW9uLFxuICAgIHRvZ2dsZUFkZEJ1dHRvbjogTUxDb21ib0xpc3QkdG9nZ2xlQWRkQnV0dG9uLFxuICAgIGRlc3Ryb3k6IE1MQ29tYm9MaXN0JGRlc3Ryb3ksXG4gICAgc2V0QWRkSXRlbVByb21wdDogTUxDb21ib0xpc3Qkc2V0QWRkSXRlbVByb21wdCxcbiAgICBjbGVhckNvbWJvSW5wdXQgOiBNTENvbWJvTGlzdCRjbGVhckNvbWJvSW5wdXRcbn0pO1xuXG5cbmZ1bmN0aW9uIE1MQ29tYm9MaXN0JGluaXQoKSB7XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgdGhpcy5fZGF0YVZhbGlkYXRpb24gPSBmdW5jdGlvbiAoKSB7fTtcbiAgICB0aGlzLm1vZGVsLnNldChbXSk7XG4gICAgdGhpcy5vbmNlKCdjaGlsZHJlbmJvdW5kJywgb25DaGlsZHJlbkJvdW5kKTtcbn1cblxuXG5mdW5jdGlvbiBNTENvbWJvTGlzdCRzZXREYXRhVmFsaWRhdGlvbihkYXRhVmFsaWRhdGlvbikge1xuICAgIGlmICh0eXBlb2YgZGF0YVZhbGlkYXRpb24gPT0gJ2Z1bmN0aW9uJylcbiAgICAgICAgdGhpcy5fZGF0YVZhbGlkYXRpb24gPSBkYXRhVmFsaWRhdGlvbjtcbn1cblxuZnVuY3Rpb24gTUxDb21ib0xpc3Qkc2V0T3B0aW9ucyhhcnIpIHtcbiAgICB0aGlzLl9jb21iby5zZXRPcHRpb25zKGFycik7XG59XG5cblxuZnVuY3Rpb24gTUxDb21ib0xpc3QkY2xlYXJDb21ib0lucHV0ICgpIHtcbiAgICB0aGlzLl9jb21iby5jbGVhckNvbWJvSW5wdXQoKTtcbn1cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBIaWRlcyBhZGQgYnV0dG9uXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHNob3dcbiAqL1xuZnVuY3Rpb24gTUxDb21ib0xpc3QkdG9nZ2xlQWRkQnV0dG9uKHNob3cpIHtcbiAgICB0aGlzLl9jb21iby50b2dnbGVBZGRCdXR0b24oc2hvdyk7XG59XG5cblxuZnVuY3Rpb24gTUxDb21ib0xpc3Qkc2V0QWRkSXRlbVByb21wdChwcm9tcHQpIHtcbiAgIHRoaXMuX2NvbWJvLnNldEFkZEl0ZW1Qcm9tcHQocHJvbXB0KTtcbn1cblxuXG5mdW5jdGlvbiBNTENvbWJvTGlzdCRkZXN0cm95KCkge1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuZGVzdHJveS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMuX2Nvbm5lY3RvciAmJiBtaWxvLm1pbmRlci5kZXN0cm95Q29ubmVjdG9yKHRoaXMuX2Nvbm5lY3Rvcik7XG4gICAgdGhpcy5fY29ubmVjdG9yID0gbnVsbDtcbn1cblxuXG5mdW5jdGlvbiBvbkNoaWxkcmVuQm91bmQoKSB7XG4gICAgdGhpcy50ZW1wbGF0ZS5yZW5kZXIoKS5iaW5kZXIoKTtcbiAgICBjb21wb25lbnRTZXR1cC5jYWxsKHRoaXMpO1xufVxuXG5mdW5jdGlvbiBjb21wb25lbnRTZXR1cCgpIHtcbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICAnX2NvbWJvJzogdGhpcy5jb250YWluZXIuc2NvcGUuY29tYm8sXG4gICAgICAgICdfbGlzdCc6IHRoaXMuY29udGFpbmVyLnNjb3BlLmxpc3RcbiAgICB9KTtcblxuICAgIHRoaXMuX2Nvbm5lY3RvciA9IG1pbG8ubWluZGVyKHRoaXMuX2xpc3QubW9kZWwsICc8PDwtPj4+JywgdGhpcy5tb2RlbCk7XG4gICAgdGhpcy5fY29tYm8uZGF0YS5vbignJywgeyBzdWJzY3JpYmVyOiBvbkNvbWJvQ2hhbmdlLCBjb250ZXh0OiB0aGlzIH0pO1xuICAgIHRoaXMuX2NvbWJvLm9uKCdhZGRpdGVtJywgeyBzdWJzY3JpYmVyOiBvbkFkZEl0ZW0sIGNvbnRleHQ6IHRoaXMgfSk7XG59XG5cbmZ1bmN0aW9uIG9uQ29tYm9DaGFuZ2UobXNnLCBkYXRhKSB7XG4gICAgaWYgKGRhdGEubmV3VmFsdWUgJiYgdGhpcy5fZGF0YVZhbGlkYXRpb24obXNnLCBkYXRhLCB0aGlzLl9saXN0Lm1vZGVsLmdldCgpKSlcbiAgICAgICAgdGhpcy5fbGlzdC5tb2RlbC5wdXNoKGRhdGEubmV3VmFsdWUpO1xuICAgIHRoaXMuX2NvbWJvLmRhdGEuZGVsKCk7XG4gICAgLy8gYmVjYXVzZSBvZiBzdXBlcmNvbWJvIGxpc3RlbmVycyBvZmYgeW91IGhhdmUgdG8gc2V0IF92YWx1ZSBleHBsaWNpdGx5XG4gICAgdGhpcy5fY29tYm8uZGF0YS5fdmFsdWUgPSAnJztcbn1cblxuZnVuY3Rpb24gb25JdGVtc0NoYW5nZShtc2csIGRhdGEpIHtcbiAgICB0aGlzLmRhdGEuZGlzcGF0Y2hTb3VyY2VNZXNzYWdlKENPTUJPX0xJU1RfQ0hBTkdFX01FU1NBR0UpO1xufVxuXG5mdW5jdGlvbiBNTENvbWJvTGlzdF9nZXQoKSB7XG4gICAgdmFyIHZhbHVlID0gdGhpcy5tb2RlbC5nZXQoKTtcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdvYmplY3QnID8gXy5jbG9uZSh2YWx1ZSkgOiB2YWx1ZTtcbn1cblxuZnVuY3Rpb24gTUxDb21ib0xpc3Rfc2V0KHZhbHVlKSB7XG4gICAgdGhpcy5tb2RlbC5zZXQodmFsdWUpO1xufVxuXG5mdW5jdGlvbiBNTENvbWJvTGlzdF9kZWwoKSB7XG4gICAgcmV0dXJuIHRoaXMubW9kZWwuc2V0KFtdKTtcbn1cblxuXG5mdW5jdGlvbiBvbkFkZEl0ZW0obXNnLCBkYXRhKSB7XG4gICAgdGhpcy5wb3N0TWVzc2FnZSgnYWRkaXRlbScsIGRhdGEpO1xuICAgIHRoaXMuZXZlbnRzLnBvc3RNZXNzYWdlKCdtaWxvX2NvbWJvbGlzdGFkZGl0ZW0nLCBkYXRhKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbWlsby1jb3JlJykucHJvdG87XG5cbnZhciBNTERhdGUgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MRGF0ZScsIHtcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBkYXRhOiB7XG4gICAgICAgIGdldDogTUxEYXRlX2dldCxcbiAgICAgICAgc2V0OiBNTERhdGVfc2V0LFxuICAgICAgICBkZWw6IE1MRGF0ZV9kZWwsXG4gICAgfSxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktZGF0ZSdcbiAgICB9XG59KTtcblxuXy5leHRlbmRQcm90byhNTERhdGUsIHtcbiAgICBnZXRNaW46IE1MRGF0ZSRnZXRNaW4sXG4gICAgc2V0TWluOiBNTERhdGUkc2V0TWluLFxuICAgIGdldE1heDogTUxEYXRlJGdldE1heCxcbiAgICBzZXRNYXg6IE1MRGF0ZSRzZXRNYXhcbn0pO1xuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MRGF0ZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxEYXRlO1xuXG5cbmZ1bmN0aW9uIE1MRGF0ZSRnZXRNaW4oKSB7XG4gICAgcmV0dXJuIF8uZGF0ZSh0aGlzLmVsLm1pbik7XG59XG5cblxuZnVuY3Rpb24gTUxEYXRlJHNldE1pbih2YWx1ZSkge1xuICAgIHZhciBkYXRlID0gXy50b0RhdGUodmFsdWUpO1xuXG4gICAgdGhpcy5lbC5taW4gPSBkYXRlID8gdG9JU084NjAxRm9ybWF0KGRhdGUpIDogJyc7XG59XG5cblxuZnVuY3Rpb24gTUxEYXRlJGdldE1heCgpIHtcbiAgICByZXR1cm4gXy5kYXRlKHRoaXMuZWwubWF4KTtcbn1cblxuXG5mdW5jdGlvbiBNTERhdGUkc2V0TWF4KHZhbHVlKSB7XG4gICAgdmFyIGRhdGUgPSBfLnRvRGF0ZSh2YWx1ZSk7XG5cbiAgICB0aGlzLmVsLm1heCA9IGRhdGUgPyB0b0lTTzg2MDFGb3JtYXQoZGF0ZSkgOiAnJztcbn1cblxuXG5mdW5jdGlvbiBNTERhdGVfZ2V0KCkge1xuICAgIHJldHVybiBfLnRvRGF0ZSh0aGlzLmVsLnZhbHVlKTtcbn1cblxuXG5mdW5jdGlvbiBNTERhdGVfc2V0KHZhbHVlKSB7XG4gICAgdmFyIGRhdGUgPSBfLnRvRGF0ZSh2YWx1ZSk7XG5cbiAgICB0aGlzLmVsLnZhbHVlID0gZGF0ZSA/IHRvSVNPODYwMUZvcm1hdChkYXRlKSA6ICcnO1xuXG4gICAgZGlzcGF0Y2hJbnB1dE1lc3NhZ2UuY2FsbCh0aGlzKTtcbn1cblxuZnVuY3Rpb24gTUxEYXRlX2RlbCgpIHtcbiAgICB0aGlzLmVsLnZhbHVlID0gJyc7XG5cbiAgICBkaXNwYXRjaElucHV0TWVzc2FnZS5jYWxsKHRoaXMpO1xufVxuXG5cbmZ1bmN0aW9uIGRpc3BhdGNoSW5wdXRNZXNzYWdlKCkge1xuICAgIHRoaXMuZGF0YS5kaXNwYXRjaFNvdXJjZU1lc3NhZ2UoJ2lucHV0Jyk7IC8vIERpc3BhdGNoIHRoZSAnaW5wdXQnICh1c3VhbGx5IGRpc3BhdGNoZWQgYnkgdGhlIHVuZGVybHlpbmcgPGlucHV0PiBlbGVtZW50KSBldmVudCBzbyB0aGF0IHRoZSBkYXRhIGNoYW5nZSBjYW4gYmUgbGlzdGVuZWQgdG9cbn1cblxuXG5mdW5jdGlvbiB0b0lTTzg2MDFGb3JtYXQoZGF0ZSkge1xuICAgIHZhciBkYXRlQXJyID0gW1xuICAgICAgICBkYXRlLmdldEZ1bGxZZWFyKCksXG4gICAgICAgIHBhZChkYXRlLmdldE1vbnRoKCkgKyAxKSxcbiAgICAgICAgcGFkKGRhdGUuZ2V0RGF0ZSgpKVxuICAgIF07XG5cbiAgICB2YXIgZGF0ZVN0ciA9IGRhdGVBcnIuam9pbignLScpO1xuXG4gICAgcmV0dXJuIGRhdGVTdHI7XG5cbiAgICBmdW5jdGlvbiBwYWQobikgeyByZXR1cm4gbiA8IDEwID8gJzAnICsgbiA6IG47IH1cbn0iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpO1xuXG5cbnZhciBNTERyb3BUYXJnZXQgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MRHJvcFRhcmdldCcsIFsnZHJvcCddKTtcblxuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MRHJvcFRhcmdldCk7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxEcm9wVGFyZ2V0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZG9UID0gcmVxdWlyZSgnbWlsby1jb3JlJykudXRpbC5kb1RcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2NfcmVnaXN0cnknKVxuICAgICwgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBtaWxvQ291bnQgPSByZXF1aXJlKCcuLi8uLi91dGlsL2NvdW50Jyk7XG5cbnZhciBUUkVFX1RFTVBMQVRFID0gJzx1bCBjbGFzcz1cIm1sLXVpLWZvbGR0cmVlLWxpc3RcIj5cXFxuICAgICAgICAgICAgICAgICAgICAgICAge3t+IGl0LmRhdGEuaXRlbXMgOml0ZW06aW5kZXggfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7IHZhciBoYXNTdWJUcmVlID0gaXRlbS5pdGVtcyAmJiBpdGVtLml0ZW1zLmxlbmd0aDsgfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxsaSB7ez8gaGFzU3ViVHJlZSB9fWNsYXNzPVwibWwtdWktZm9sZHRyZWUtLWhhcy1tdWx0aXBsZVwie3s/fX0+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm1sLXVpLWZvbGR0cmVlLWl0ZW1cIj5cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3s/IGhhc1N1YlRyZWUgfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtbC11aS1mb2xkdHJlZS1idXR0b25cIj48L2Rpdj5cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3s/fX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3s9IGl0Lml0ZW1UZW1wbGF0ZSh7IGl0ZW06IGl0ZW0sIGlkOiBpdC5pdGVtSURzW2luZGV4XSB9KSB9fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7PyBoYXNTdWJUcmVlIH19XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7PSBpdC50cmVlVGVtcGxhdGUoaXRlbSkgfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7ez99fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9saT5cXFxuICAgICAgICAgICAgICAgICAgICAgICAge3t+fX1cXFxuICAgICAgICAgICAgICAgICAgICA8L3VsPic7XG5cbnZhciBERUZBVUxUX0NPTVBJTEVEX0lURU1fVEVNUExBVEUgPSBkb1QuY29tcGlsZSgnXFxcbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibWwtdWktZm9sZHRyZWUtbGFiZWxcIiBkYXRhLWl0ZW0taWQ9XCJ7ez0gaXQuaWQgfX1cIj5cXFxuICAgICAgICAgICAgICAgIHt7PSBpdC5pdGVtLmxhYmVsIH19XFxcbiAgICAgICAgICAgIDwvc3Bhbj4nKVxuICAgICwgQ09NUElMRURfVFJFRV9URU1QTEFURSA9IGRvVC5jb21waWxlKFRSRUVfVEVNUExBVEUpO1xuXG5cbnZhciBNTEZvbGRUcmVlID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTEZvbGRUcmVlJywge1xuICAgIGNvbnRhaW5lcjogdW5kZWZpbmVkLFxuICAgIGV2ZW50czoge1xuICAgICAgICBtZXNzYWdlczoge1xuICAgICAgICAgICAgJ2NsaWNrIGRibGNsaWNrJzogeyBzdWJzY3JpYmVyOiBvbkl0ZW1FdmVudCwgY29udGV4dDogJ293bmVyJyB9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS1mb2xkdHJlZS1tYWluJ1xuICAgIH1cbn0pO1xuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MRm9sZFRyZWUpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MRm9sZFRyZWU7XG5cbl8uZXh0ZW5kUHJvdG8oTUxGb2xkVHJlZSwge1xuICAgIHNldEl0ZW1UZW1wbGF0ZTogTUxGb2xkVHJlZSRzZXRJdGVtVGVtcGxhdGUsXG4gICAgcmVuZGVyVHJlZTogTUxGb2xkVHJlZSRyZW5kZXJUcmVlXG59KTtcblxuZnVuY3Rpb24gZm9sZFVuZm9sZChlbCkge1xuICAgIGVsLmNsYXNzTGlzdC50b2dnbGUoJ21sLXVpLWZvbGR0cmVlLS11bmZvbGQnKTtcbn1cblxuZnVuY3Rpb24gaXRlbU1lc3NhZ2UobXNnLCBlbCkge1xuICAgIHZhciBpZCA9IGVsLmdldEF0dHJpYnV0ZSgnZGF0YS1pdGVtLWlkJylcbiAgICAgICAgLCBpdGVtID0gdGhpcy5faXRlbXNNYXBbaWRdO1xuXG4gICAgdGhpcy5wb3N0TWVzc2FnZSgnbWxmb2xkdHJlZV8nICsgbXNnLCB7XG4gICAgICAgIGl0ZW06IGl0ZW0sXG4gICAgICAgIGVsOiBlbFxuICAgIH0pO1xufVxuXG5mdW5jdGlvbiBvbkl0ZW1FdmVudChtc2csIGUpIHtcbiAgICB2YXIgZWwgPSBlLnRhcmdldDtcbiAgICBpZiAoZWwuY2xhc3NMaXN0LmNvbnRhaW5zKCdtbC11aS1mb2xkdHJlZS1idXR0b24nKSlcbiAgICAgICAgZm9sZFVuZm9sZChlbC5wYXJlbnROb2RlLnBhcmVudE5vZGUpO1xuICAgIGVsc2UgaWYgKGVsLmNsYXNzTGlzdC5jb250YWlucygnbWwtdWktZm9sZHRyZWUtbGFiZWwnKSlcbiAgICAgICAgaXRlbU1lc3NhZ2UuY2FsbCh0aGlzLCBtc2csIGVsKTtcbiAgICBlbHNlIHJldHVybjtcbiAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xufVxuXG5mdW5jdGlvbiBNTEZvbGRUcmVlJHNldEl0ZW1UZW1wbGF0ZSAodGVtcGxhdGVTdHIpIHtcbiAgICB0aGlzLl9pdGVtVGVtcGxhdGUgPSBkb1QuY29tcGlsZSh0ZW1wbGF0ZVN0cik7XG59XG5cbmZ1bmN0aW9uIE1MRm9sZFRyZWUkcmVuZGVyVHJlZSAoZGF0YSkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLl9kYXRhID0gZGF0YTtcbiAgICBzZWxmLl9pdGVtc01hcCA9IHt9O1xuICAgIHRoaXMuZWwuaW5uZXJIVE1MID0gX3JlbmRlclRyZWUoZGF0YSk7XG5cbiAgICBmdW5jdGlvbiBfcmVuZGVyVHJlZSAoZGF0YSkge1xuICAgICAgICBpZiAoZGF0YS5pdGVtcylcbiAgICAgICAgICAgIHZhciBpdGVtc0lEcyA9IF8ubWFwKGRhdGEuaXRlbXMsIGZ1bmN0aW9uKGl0ZW0pIHtcbiAgICAgICAgICAgICAgICB2YXIgaWQgPSBtaWxvQ291bnQoKTtcbiAgICAgICAgICAgICAgICBzZWxmLl9pdGVtc01hcFtpZF0gPSBpdGVtO1xuICAgICAgICAgICAgICAgIHJldHVybiBpZDsgXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gQ09NUElMRURfVFJFRV9URU1QTEFURSh7XG4gICAgICAgICAgICBpdGVtSURzOiBpdGVtc0lEcyxcbiAgICAgICAgICAgIGRhdGE6IGRhdGEsXG4gICAgICAgICAgICBpdGVtVGVtcGxhdGU6IHNlbGYuX2l0ZW1UZW1wbGF0ZSB8fCBERUZBVUxUX0NPTVBJTEVEX0lURU1fVEVNUExBVEUsXG4gICAgICAgICAgICB0cmVlVGVtcGxhdGU6IF9yZW5kZXJUcmVlXG4gICAgICAgIH0pO1xuICAgIH1cbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpO1xuXG5cbnZhciBNTEdyb3VwID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTEdyb3VwJywge1xuICAgIGNvbnRhaW5lcjogdW5kZWZpbmVkLFxuICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktZ3JvdXAnXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxHcm91cCk7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxHcm91cDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpO1xuXG5cbnZhciBNTEh5cGVybGluayA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxIeXBlcmxpbmsnLCB7XG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZGF0YTogdW5kZWZpbmVkLFxuICAgIGRvbToge1xuICAgICAgICBjbHM6ICdtbC11aS1oeXBlcmxpbmsnXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxIeXBlcmxpbmspO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MSHlwZXJsaW5rO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5JylcbiAgICAsIF8gPSByZXF1aXJlKCdtaWxvLWNvcmUnKS5wcm90bztcblxuXG52YXIgSU1BR0VfQ0hBTkdFX01FU1NBR0UgPSAnbWxpbWFnZWNoYW5nZSc7XG5cbnZhciBNTEltYWdlID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTEltYWdlJywge1xuICAgIGRhdGE6IHtcbiAgICAgICAgc2V0OiBNTEltYWdlX3NldCxcbiAgICAgICAgZ2V0OiBNTEltYWdlX2dldCxcbiAgICAgICAgZGVsOiBNTEltYWdlX2RlbCxcbiAgICAgICAgc3BsaWNlOiB1bmRlZmluZWQsXG4gICAgICAgIGV2ZW50OiBJTUFHRV9DSEFOR0VfTUVTU0FHRVxuICAgIH0sXG4gICAgbW9kZWw6IHtcbiAgICAgICAgbWVzc2FnZXM6IHtcbiAgICAgICAgICAgICcuc3JjJzogeyBzdWJzY3JpYmVyOiBvbk1vZGVsQ2hhbmdlLCBjb250ZXh0OiAnb3duZXInIH1cbiAgICAgICAgfVxuICAgIH0sXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgY29udGFpbmVyOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIHRhZ05hbWU6ICdpbWcnLFxuICAgICAgICBjbHM6ICdtbC11aS1pbWFnZSdcbiAgICB9XG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTEltYWdlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBNTEltYWdlO1xuXG5cbl8uZXh0ZW5kUHJvdG8oTUxJbWFnZSwge1xuICAgIGluaXQ6IE1MSW1hZ2UkaW5pdFxufSk7XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsaXplIHJhZGlvIGdyb3VwIGFuZCBzZXR1cFxuICovXG5mdW5jdGlvbiBNTEltYWdlJGluaXQoKSB7XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuLyoqXG4gKiBTZXRzIGltYWdlIHZhbHVlXG4gKiBSZXBsYWNlcyB0aGUgZGF0YSBzZXQgb3BlcmF0aW9uIHRvIGRlYWwgd2l0aCByYWRpbyBidXR0b25zXG4gKlxuICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIGJlIHNldFxuICovXG5mdW5jdGlvbiBNTEltYWdlX3NldCh2YWx1ZSkge1xuICAgIHRoaXMubW9kZWwuc2V0KHZhbHVlKTtcbiAgICByZXR1cm4gdmFsdWU7XG59XG5cblxuLyoqXG4gKiBHZXRzIGdyb3VwIHZhbHVlXG4gKiBSZXRyaWV2ZXMgdGhlIHNlbGVjdGVkIHZhbHVlIG9mIHRoZSBncm91cFxuICpcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gTUxJbWFnZV9nZXQoKSB7XG4gICAgdmFyIHZhbHVlID0gdGhpcy5tb2RlbC5nZXQoKTtcbiAgICByZXR1cm4gdmFsdWUgJiYgdHlwZW9mIHZhbHVlID09ICdvYmplY3QnID8gXy5jbG9uZSh2YWx1ZSkgOiB2YWx1ZTtcbn1cblxuXG4vKipcbiAqIERlbGV0ZWQgZ3JvdXAgdmFsdWVcbiAqIERlbGV0ZXMgdGhlIHZhbHVlIG9mIHRoZSBncm91cCwgc2V0dGluZyBpdCB0byBlbXB0eVxuICovXG5mdW5jdGlvbiBNTEltYWdlX2RlbCgpIHtcbiAgICB0aGlzLm1vZGVsLmRlbCgpO1xufVxuXG5cbi8vIFBvc3QgdGhlIGRhdGEgY2hhbmdlXG5mdW5jdGlvbiBkaXNwYXRjaENoYW5nZU1lc3NhZ2UoKSB7XG4gICAgdGhpcy5kYXRhLmRpc3BhdGNoU291cmNlTWVzc2FnZShJTUFHRV9DSEFOR0VfTUVTU0FHRSk7XG59XG5cblxuZnVuY3Rpb24gb25Nb2RlbENoYW5nZShwYXRoLCBkYXRhKSB7XG4gICAgdGhpcy5lbC5zcmMgPSBkYXRhLm5ld1ZhbHVlO1xuICAgIGRpc3BhdGNoQ2hhbmdlTWVzc2FnZS5jYWxsKHRoaXMpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5JylcbiAgICAsIF8gPSByZXF1aXJlKCdtaWxvLWNvcmUnKS5wcm90bztcblxuXG52YXIgTUxJbnB1dCA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxJbnB1dCcsIHtcbiAgICBkYXRhOiB1bmRlZmluZWQsXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogJ21sLXVpLWlucHV0J1xuICAgIH1cbn0pO1xuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MSW5wdXQpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MSW5wdXQ7XG5cbl8uZXh0ZW5kUHJvdG8oTUxJbnB1dCwge1xuICAgIGRpc2FibGU6IE1MSW5wdXQkZGlzYWJsZSxcbiAgICBpc0Rpc2FibGVkOiBNTElucHV0JGlzRGlzYWJsZWQsXG4gICAgc2V0TWF4TGVuZ3RoOiBNTElucHV0JHNldE1heExlbmd0aFxufSk7XG5cbmZ1bmN0aW9uIE1MSW5wdXQkZGlzYWJsZShkaXNhYmxlKSB7XG4gICAgdGhpcy5lbC5kaXNhYmxlZCA9IGRpc2FibGU7XG59XG5cbmZ1bmN0aW9uIE1MSW5wdXQkaXNEaXNhYmxlZCgpIHtcbiAgICByZXR1cm4gISF0aGlzLmVsLmRpc2FibGVkO1xufVxuXG5mdW5jdGlvbiBNTElucHV0JHNldE1heExlbmd0aChsZW5ndGgpIHtcbiAgICB0aGlzLmVsLnNldEF0dHJpYnV0ZSgnbWF4bGVuZ3RoJywgbGVuZ3RoKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbWlsby1jb3JlJykucHJvdG87XG5cbnZhciBJTlBVVF9MSVNUX0NIQU5HRV9NRVNTQUdFID0gJ21saW5wdXRsaXN0Y2hhbmdlJztcblxudmFyIGFzeW5jSGFuZGxlciA9IGZ1bmN0aW9uICh2YWx1ZSwgY2FsbGJhY2spIHtjYWxsYmFjayh2YWx1ZSk7fTtcblxudmFyIE1MSW5wdXRMaXN0ID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTElucHV0TGlzdCcsIHtcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktaW5wdXQtbGlzdCdcbiAgICB9LFxuICAgIGRhdGE6IHtcbiAgICAgICAgZ2V0OiBNTElucHV0TGlzdF9nZXQsXG4gICAgICAgIHNldDogTUxJbnB1dExpc3Rfc2V0LFxuICAgICAgICBkZWw6IE1MSW5wdXRMaXN0X2RlbCxcbiAgICAgICAgc3BsaWNlOiBNTElucHV0TGlzdF9zcGxpY2UsXG4gICAgICAgIGV2ZW50OiBJTlBVVF9MSVNUX0NIQU5HRV9NRVNTQUdFXG4gICAgfSxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBjb250YWluZXI6IHVuZGVmaW5lZCxcbiAgICBtb2RlbDoge1xuICAgICAgICBtZXNzYWdlczoge1xuICAgICAgICAgICAgJyoqKic6IHsgc3Vic2NyaWJlcjogb25JdGVtc0NoYW5nZSwgY29udGV4dDogJ293bmVyJyB9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICAgIHRlbXBsYXRlOiAnXFxcbiAgICAgICAgICAgIDxkaXYgbWwtYmluZD1cIk1MTGlzdDpsaXN0XCI+XFxcbiAgICAgICAgICAgICAgICA8ZGl2IG1sLWJpbmQ9XCJNTExpc3RJdGVtOml0ZW1cIiBjbGFzcz1cImxpc3QtaXRlbVwiPlxcXG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIG1sLWJpbmQ9XCJbZGF0YV06bGFiZWxcIj48L3NwYW4+XFxcbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gbWwtYmluZD1cIltldmVudHNdOmRlbGV0ZUJ0blwiIGNsYXNzPVwiZ2x5cGhpY29uIGdseXBoaWNvbi1yZW1vdmVcIj48L3NwYW4+XFxcbiAgICAgICAgICAgICAgICA8L2Rpdj5cXFxuICAgICAgICAgICAgPC9kaXY+XFxcbiAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIG1sLWJpbmQ9XCJNTElucHV0OmlucHV0XCIgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIj5cXFxuICAgICAgICAgICAgPGJ1dHRvbiBtbC1iaW5kPVwiTUxCdXR0b246YnV0dG9uXCIgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHRcIj5cXFxuICAgICAgICAgICAgICAgIEFkZFxcXG4gICAgICAgICAgICA8L2J1dHRvbj4nXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxJbnB1dExpc3QpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MSW5wdXRMaXN0O1xuXG5fLmV4dGVuZFByb3RvKE1MSW5wdXRMaXN0LCB7XG4gICAgaW5pdDogTUxJbnB1dExpc3QkaW5pdCxcbiAgICBzZXRBc3luYzogTUxJbnB1dExpc3Qkc2V0QXN5bmMsXG4gICAgc2V0UGxhY2VIb2xkZXI6IE1MSW5wdXRMaXN0JHNldFBsYWNlSG9sZGVyLFxuICAgIGRlc3Ryb3k6IE1MSW5wdXRMaXN0JGRlc3Ryb3lcbn0pO1xuXG5mdW5jdGlvbiBNTElucHV0TGlzdCRpbml0KCkge1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMub25jZSgnY2hpbGRyZW5ib3VuZCcsIG9uQ2hpbGRyZW5Cb3VuZCk7XG4gICAgdGhpcy5tb2RlbC5zZXQoW10pO1xufVxuXG5mdW5jdGlvbiBvbkNoaWxkcmVuQm91bmQoKSB7XG4gICAgcmVuZGVyLmNhbGwodGhpcyk7XG59XG5cbmZ1bmN0aW9uIE1MSW5wdXRMaXN0JHNldFBsYWNlSG9sZGVyKHBsYWNlSG9sZGVyKSB7XG4gICAgdGhpcy5faW5wdXQuZWwuc2V0QXR0cmlidXRlKCdwbGFjZUhvbGRlcicsIHBsYWNlSG9sZGVyKTtcbn1cblxuZnVuY3Rpb24gTUxJbnB1dExpc3Qkc2V0QXN5bmMobmV3SGFuZGxlcikge1xuICAgIGFzeW5jSGFuZGxlciA9IG5ld0hhbmRsZXIgfHwgYXN5bmNIYW5kbGVyO1xufVxuXG5mdW5jdGlvbiBNTElucHV0TGlzdCRkZXN0cm95KCkge1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuZGVzdHJveS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMuX2Nvbm5lY3RvciAmJiBtaWxvLm1pbmRlci5kZXN0cm95Q29ubmVjdG9yKHRoaXMuX2Nvbm5lY3Rvcik7XG4gICAgdGhpcy5fY29ubmVjdG9yID0gbnVsbDtcbn1cblxuZnVuY3Rpb24gcmVuZGVyKCkge1xuICAgIHRoaXMudGVtcGxhdGUucmVuZGVyKCkuYmluZGVyKCk7XG4gICAgY29tcG9uZW50U2V0dXAuY2FsbCh0aGlzKTtcbn1cblxuZnVuY3Rpb24gY29tcG9uZW50U2V0dXAoKSB7XG4gICAgXy5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIHtcbiAgICAgICAgJ19pbnB1dCc6IHRoaXMuY29udGFpbmVyLnNjb3BlLmlucHV0LFxuICAgICAgICAnX2J1dHRvbic6IHRoaXMuY29udGFpbmVyLnNjb3BlLmJ1dHRvbixcbiAgICAgICAgJ19saXN0JzogdGhpcy5jb250YWluZXIuc2NvcGUubGlzdFxuICAgIH0pO1xuICAgIHRoaXMuX2Nvbm5lY3RvciA9IG1pbG8ubWluZGVyKHRoaXMuX2xpc3QubW9kZWwsICc8PDwtPj4+JywgdGhpcy5tb2RlbCk7XG4gICAgdGhpcy5fYnV0dG9uLmV2ZW50cy5vbignY2xpY2snLCB7c3Vic2NyaWJlcjogb25DbGljaywgY29udGV4dDogdGhpcyB9KTsgICBcbn1cblxuZnVuY3Rpb24gb25DbGljayhtc2cpIHtcbiAgICB2YXIgdmFsdWUgPSB0aGlzLl9pbnB1dC5kYXRhLmdldCgwKTtcbiAgICBpZiAodGhpcy5faW5wdXQuZGF0YSlcbiAgICAgICAgYXN5bmNIYW5kbGVyKHZhbHVlLCBmdW5jdGlvbiAobGFiZWwsIHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLl9saXN0Lm1vZGVsLnB1c2goeyBsYWJlbDogbGFiZWwsIHZhbHVlOiB2YWx1ZSB9KTtcbiAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB0aGlzLl9pbnB1dC5kYXRhLmRlbCgpO1xufVxuXG5mdW5jdGlvbiBvbkl0ZW1zQ2hhbmdlKG1zZywgZGF0YSkge1xuICAgIHRoaXMuZGF0YS5kaXNwYXRjaFNvdXJjZU1lc3NhZ2UoSU5QVVRfTElTVF9DSEFOR0VfTUVTU0FHRSk7XG59XG5cbmZ1bmN0aW9uIE1MSW5wdXRMaXN0X2dldCgpIHtcbiAgICB2YXIgbW9kZWwgPSB0aGlzLm1vZGVsLmdldCgpO1xuICAgIHJldHVybiBtb2RlbCA/IF8uY2xvbmUobW9kZWwpIDogdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiBNTElucHV0TGlzdF9zZXQodmFsdWUpIHtcbiAgICB0aGlzLm1vZGVsLnNldCh2YWx1ZSk7XG59XG5cbmZ1bmN0aW9uIE1MSW5wdXRMaXN0X2RlbCgpIHtcbiAgICByZXR1cm4gdGhpcy5tb2RlbC5zZXQoW10pO1xufVxuXG5mdW5jdGlvbiBNTElucHV0TGlzdF9zcGxpY2UoKSB7IC8vIC4uLiBhcmd1bWVudHNcbiAgICB0aGlzLm1vZGVsLnNwbGljZS5hcHBseSh0aGlzLm1vZGVsLCBhcmd1bWVudHMpO1xufSIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbWlsby1jb3JlJykucHJvdG87XG5cbnZhciBMSVNUX0NIQU5HRV9NRVNTQUdFID0gJ21sbGlzdGNoYW5nZSdcbiAgICAsIERFTEVURV9CVVRUT05fTkFNRSA9ICdkZWxldGVCdG4nO1xuXG5cbnZhciBNTExpc3QgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MTGlzdCcsIHtcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktbGlzdCdcbiAgICB9LFxuICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBtb2RlbDogdW5kZWZpbmVkLFxuICAgIGxpc3Q6IHVuZGVmaW5lZFxufSk7XG5cblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTExpc3QpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MTGlzdDtcblxuXG5fLmV4dGVuZFByb3RvKE1MTGlzdCwge1xuICAgIGluaXQ6IE1MTGlzdCRpbml0LFxuICAgIGRlc3Ryb3k6IE1MTGlzdCRkZXN0cm95LFxuICAgIHJlbW92ZUl0ZW06IE1MTGlzdCRyZW1vdmVJdGVtLFxuICAgIG1vdmVJdGVtOiBNTExpc3QkbW92ZUl0ZW1cbn0pO1xuXG5cbmZ1bmN0aW9uIE1MTGlzdCRpbml0KCkge1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMub24oJ2NoaWxkcmVuYm91bmQnLCBvbkNoaWxkcmVuQm91bmQpO1xufVxuXG5cbmZ1bmN0aW9uIE1MTGlzdCRkZXN0cm95KCkge1xuICAgIHRoaXMuX2Nvbm5lY3RvciAmJiBtaWxvLm1pbmRlci5kZXN0cm95Q29ubmVjdG9yKHRoaXMuX2Nvbm5lY3Rvcik7XG4gICAgdGhpcy5fY29ubmVjdG9yID0gbnVsbDtcbiAgICBDb21wb25lbnQucHJvdG90eXBlLmRlc3Ryb3kuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuXG5mdW5jdGlvbiBNTExpc3QkcmVtb3ZlSXRlbShpbmRleCl7XG4gICAgdGhpcy5tb2RlbC5zcGxpY2UoaW5kZXgsIDEpO1xufVxuXG5cbmZ1bmN0aW9uIE1MTGlzdCRtb3ZlSXRlbShmcm9tLCB0bykge1xuICAgIHZhciBzcGxpY2VkRGF0YSA9IHRoaXMubW9kZWwuc3BsaWNlKGZyb20sIDEpO1xuICAgIHJldHVybiB0aGlzLm1vZGVsLnNwbGljZSh0bywgMCwgc3BsaWNlZERhdGFbMF0pO1xufVxuXG5cbmZ1bmN0aW9uIG9uQ2hpbGRyZW5Cb3VuZCgpIHtcbiAgICB0aGlzLm1vZGVsLnNldChbXSk7XG4gICAgdGhpcy5fY29ubmVjdG9yID0gbWlsby5taW5kZXIodGhpcy5tb2RlbCwgJzw8PC0nLCB0aGlzLmRhdGEpLmRlZmVyQ2hhbmdlTW9kZSgnPDw8LT4+PicpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBEcmFnRHJvcCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvZHJhZ2Ryb3AnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBfID0gcmVxdWlyZSgnbWlsby1jb3JlJykucHJvdG87XG5cblxudmFyIExJU1RJVEVNX0NIQU5HRV9NRVNTQUdFID0gJ21sbGlzdGl0ZW1jaGFuZ2UnXG5cbnZhciBNTExpc3RJdGVtID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTExpc3RJdGVtJywge1xuICAgIGNvbnRhaW5lcjogdW5kZWZpbmVkLFxuICAgIGRvbTogdW5kZWZpbmVkLFxuICAgIGRyYWc6IHtcbiAgICAgICAgbWV0YToge1xuICAgICAgICAgICAgcGFyYW1zOiBnZXRNZXRhRGF0YVxuICAgICAgICB9XG4gICAgfSxcbiAgICBkcm9wOiB7XG4gICAgICAgIG1lc3NhZ2VzOiB7XG4gICAgICAgICAgICAnZHJhZ2VudGVyJzogeyBzdWJzY3JpYmVyOiBvbkRyYWdIb3ZlciwgY29udGV4dDogJ293bmVyJyB9LFxuICAgICAgICAgICAgJ2RyYWdvdmVyJzogeyBzdWJzY3JpYmVyOiBvbkRyYWdIb3ZlciwgY29udGV4dDogJ293bmVyJyB9LFxuICAgICAgICAgICAgJ2RyYWdsZWF2ZSc6IHsgc3Vic2NyaWJlcjogb25EcmFnT3V0LCBjb250ZXh0OiAnb3duZXInIH0sXG4gICAgICAgICAgICAnZHJvcCc6IHsgc3Vic2NyaWJlcjogb25JdGVtRHJvcCwgY29udGV4dDogJ293bmVyJyB9XG4gICAgICAgIH0sXG4gICAgICAgIGFsbG93OiB7XG4gICAgICAgICAgICBjb21wb25lbnRzOiBpc0NvbXBvbmVudEFsbG93ZWRcbiAgICAgICAgfVxuICAgIH0sXG4gICAgZGF0YToge1xuICAgICAgICBnZXQ6IE1MTGlzdEl0ZW1fZ2V0LFxuICAgICAgICBzZXQ6IE1MTGlzdEl0ZW1fc2V0LFxuICAgICAgICBkZWw6IE1MTGlzdEl0ZW1fZGVsLFxuICAgICAgICBldmVudDogTElTVElURU1fQ0hBTkdFX01FU1NBR0VcbiAgICB9LFxuICAgIG1vZGVsOiB1bmRlZmluZWQsXG4gICAgaXRlbTogdW5kZWZpbmVkXG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTExpc3RJdGVtKTtcblxudmFyIE1MTGlzdEl0ZW0gPSBtb2R1bGUuZXhwb3J0cyA9IE1MTGlzdEl0ZW07XG5cblxuXy5leHRlbmRQcm90byhNTExpc3RJdGVtLCB7XG4gICAgaW5pdDogTUxMaXN0SXRlbSRpbml0LFxuICAgIG1vdmVJdGVtOiBNTExpc3RJdGVtJG1vdmVJdGVtLFxuICAgIHJlbW92ZUl0ZW06IE1MTGlzdEl0ZW0kcmVtb3ZlSXRlbSxcbiAgICBpc0Ryb3BBbGxvd2VkOiBNTExpc3RJdGVtJGlzRHJvcEFsbG93ZWRcbn0pO1xuXG5cbmZ1bmN0aW9uIE1MTGlzdEl0ZW0kaW5pdCgpIHtcbiAgICBDb21wb25lbnQucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB0aGlzLm9uKCdjaGlsZHJlbmJvdW5kJywgb25DaGlsZHJlbkJvdW5kKTtcbn1cblxuXG5mdW5jdGlvbiBvbkNoaWxkcmVuQm91bmQoKSB7XG4gICAgdmFyIGRlbGV0ZUJ0biA9IHRoaXMuY29udGFpbmVyLnNjb3BlLmRlbGV0ZUJ0bjtcbiAgICBkZWxldGVCdG4gJiYgZGVsZXRlQnRuLmV2ZW50cy5vbignY2xpY2snLCB7IHN1YnNjcmliZXI6IHRoaXMucmVtb3ZlSXRlbSwgY29udGV4dDogdGhpcyB9KTtcbn1cblxuXG5mdW5jdGlvbiBNTExpc3RJdGVtJHJlbW92ZUl0ZW0oKSB7XG4gICAgdHJ5IHsgdmFyIGxpc3RPd25lciA9IHRoaXMuaXRlbS5saXN0Lm93bmVyOyB9IGNhdGNoKGUpIHt9XG4gICAgbGlzdE93bmVyICYmIGxpc3RPd25lci5yZW1vdmVJdGVtKHRoaXMuaXRlbS5pbmRleCk7XG59XG5cblxuZnVuY3Rpb24gTUxMaXN0SXRlbSRtb3ZlSXRlbShpbmRleCkge1xuICAgIHZhciBsaXN0T3duZXIgPSB0aGlzLml0ZW0ubGlzdC5vd25lcjtcbiAgICBsaXN0T3duZXIgJiYgbGlzdE93bmVyLm1vdmVJdGVtKHRoaXMuaXRlbS5pbmRleCwgaW5kZXgpO1xufVxuXG5cbmZ1bmN0aW9uIE1MTGlzdEl0ZW0kaXNEcm9wQWxsb3dlZChtZXRhLCBkcmFnRHJvcCl7XG4gICAgcmV0dXJuIG1ldGEucGFyYW1zICYmIG1ldGEucGFyYW1zLmluZGV4ICYmIG1ldGEuY29tcENsYXNzID09ICdNTExpc3RJdGVtJztcbn1cblxuXG5mdW5jdGlvbiBpc0NvbXBvbmVudEFsbG93ZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNEcm9wQWxsb3dlZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbmZ1bmN0aW9uIG9uSXRlbURyb3AoZXZlbnRUeXBlLCBldmVudCkge1xuICAgIG9uRHJhZ091dC5jYWxsKHRoaXMpO1xuICAgIHZhciBkdCA9IG5ldyBEcmFnRHJvcChldmVudCk7XG4gICAgdmFyIG1ldGEgPSBkdC5nZXRDb21wb25lbnRNZXRhKCk7XG4gICAgdmFyIHN0YXRlID0gZHQuZ2V0Q29tcG9uZW50U3RhdGUoKTtcbiAgICB2YXIgbGlzdE93bmVyID0gdGhpcy5pdGVtLmxpc3Qub3duZXI7XG4gICAgdmFyIGluZGV4ID0gbWV0YS5wYXJhbXMgJiYgbWV0YS5wYXJhbXMuaW5kZXg7XG5cbiAgICBsaXN0T3duZXIubW92ZUl0ZW0oK2luZGV4LCB0aGlzLml0ZW0uaW5kZXgsIHN0YXRlKTtcbn1cblxuXG5mdW5jdGlvbiBvbkRyYWdIb3ZlcihldmVudFR5cGUsIGV2ZW50KSB7XG4gICAgdGhpcy5kb20uYWRkQ3NzQ2xhc3NlcygnbWwtZHJhZy1vdmVyJyk7XG59XG5cblxuZnVuY3Rpb24gb25EcmFnT3V0KGV2ZW50VHlwZSwgZXZlbnQpIHtcbiAgICB0aGlzLmRvbS5yZW1vdmVDc3NDbGFzc2VzKCdtbC1kcmFnLW92ZXInKTtcbn1cblxuXG5mdW5jdGlvbiBnZXRNZXRhRGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBpbmRleDogdGhpcy5pdGVtLmluZGV4XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIE1MTGlzdEl0ZW1fZ2V0KCkge1xuICAgIHZhciB2YWx1ZSA9IHRoaXMubW9kZWwuZ2V0KCk7XG4gICAgcmV0dXJuIHZhbHVlICE9PSBudWxsICYmIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0JyA/IF8uY2xvbmUodmFsdWUpIDogdmFsdWU7XG59XG5cblxuZnVuY3Rpb24gTUxMaXN0SXRlbV9zZXQodmFsdWUpIHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09ICdvYmplY3QnKVxuICAgICAgICB0aGlzLmRhdGEuX3NldCh2YWx1ZSk7XG4gICAgdGhpcy5tb2RlbC5zZXQodmFsdWUpO1xuICAgIF9zZW5kQ2hhbmdlTWVzc2FnZS5jYWxsKHRoaXMpO1xuICAgIHJldHVybiB2YWx1ZTtcbn1cblxuXG5mdW5jdGlvbiBNTExpc3RJdGVtX2RlbCgpIHtcbiAgICB0aGlzLmRhdGEuX2RlbCgpO1xuICAgIHRoaXMubW9kZWwuZGVsKCk7XG4gICAgX3NlbmRDaGFuZ2VNZXNzYWdlLmNhbGwodGhpcyk7ICAgIFxufVxuXG5cbmZ1bmN0aW9uIF9zZW5kQ2hhbmdlTWVzc2FnZSgpIHtcbiAgICB0aGlzLmRhdGEuZGlzcGF0Y2hTb3VyY2VNZXNzYWdlKExJU1RJVEVNX0NIQU5HRV9NRVNTQUdFKTtcbn1cblxuXG5cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpXG4gICAgLCBtaWxvQ291bnQgPSByZXF1aXJlKCcuLi8uLi91dGlsL2NvdW50JylcbiAgICAsIF8gPSByZXF1aXJlKCdtaWxvLWNvcmUnKS5wcm90bztcblxuXG52YXIgUkFESU9fQ0hBTkdFX01FU1NBR0UgPSAnbWxyYWRpb2dyb3VwY2hhbmdlJ1xuICAgICwgRUxFTUVOVF9OQU1FX1BST1BFUlRZID0gJ19tbFJhZGlvR3JvdXBFbGVtZW50SUQnXG4gICAgLCBFTEVNRU5UX05BTUVfUFJFRklYID0gJ21sLXJhZGlvLWdyb3VwLSc7XG5cbnZhciBNTFJhZGlvR3JvdXAgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MUmFkaW9Hcm91cCcsIHtcbiAgICBkYXRhOiB7XG4gICAgICAgIHNldDogTUxSYWRpb0dyb3VwX3NldCxcbiAgICAgICAgZ2V0OiBNTFJhZGlvR3JvdXBfZ2V0LFxuICAgICAgICBkZWw6IE1MUmFkaW9Hcm91cF9kZWwsXG4gICAgICAgIHNwbGljZTogdW5kZWZpbmVkLFxuICAgICAgICBldmVudDogUkFESU9fQ0hBTkdFX01FU1NBR0VcbiAgICB9LFxuICAgIG1vZGVsOiB7XG4gICAgICAgIG1lc3NhZ2VzOiB7XG4gICAgICAgICAgICAnKioqJzogeyBzdWJzY3JpYmVyOiBvbk9wdGlvbnNDaGFuZ2UsIGNvbnRleHQ6ICdvd25lcicgfVxuICAgICAgICB9XG4gICAgfSxcbiAgICBldmVudHM6IHtcbiAgICAgICAgbWVzc2FnZXM6IHtcbiAgICAgICAgICAgICdjbGljayc6IHsgc3Vic2NyaWJlcjogb25Hcm91cENsaWNrLCBjb250ZXh0OiAnb3duZXInIH1cbiAgICAgICAgfVxuICAgIH0sXG4gICAgY29udGFpbmVyOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogJ21sLXVpLXJhZGlvLWdyb3VwJ1xuICAgIH0sXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgICAgdGVtcGxhdGU6ICd7e34gaXQucmFkaW9PcHRpb25zIDpvcHRpb24gfX0gXFxcbiAgICAgICAgICAgICAgICAgICAgICAgIHt7IyNkZWYuZWxJRDp7ez0gaXQuZWxlbWVudE5hbWUgfX0te3s9IG9wdGlvbi52YWx1ZSB9fSN9fSBcXFxuICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ7ez0gaXQuX3JlbmRlck9wdGlvbnMub3B0aW9uQ3NzQ2xhc3MgfHwgXCInICsgRUxFTUVOVF9OQU1FX1BSRUZJWCArICdvcHRpb25cIiB9fVwiPiBcXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpbnB1dCBpZD1cInt7IyBkZWYuZWxJRCB9fVwiIHR5cGU9XCJyYWRpb1wiIHZhbHVlPVwie3s9IG9wdGlvbi52YWx1ZSB9fVwiIG5hbWU9XCJ7ez0gaXQuZWxlbWVudE5hbWUgfX1cIj4gXFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8bGFiZWwgZm9yPVwie3sjIGRlZi5lbElEIH19XCI+e3s9IG9wdGlvbi5sYWJlbCB9fTwvbGFiZWw+IFxcXG4gICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4+IFxcXG4gICAgICAgICAgICAgICAgICAge3t+fX0nXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxSYWRpb0dyb3VwKTtcblxubW9kdWxlLmV4cG9ydHMgPSBNTFJhZGlvR3JvdXA7XG5cblxuXy5leHRlbmRQcm90byhNTFJhZGlvR3JvdXAsIHtcbiAgICBpbml0OiBNTFJhZGlvR3JvdXAkaW5pdCxcbiAgICBkZXN0cm95OiBNTFJhZGlvR3JvdXAkZGVzdHJveSxcbiAgICBzZXRSZW5kZXJPcHRpb25zOiBNTFJhZGlvR3JvdXAkc2V0UmVuZGVyT3B0aW9uc1xufSk7XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsaXplIHJhZGlvIGdyb3VwIGFuZCBzZXR1cFxuICovXG5mdW5jdGlvbiBNTFJhZGlvR3JvdXAkaW5pdCgpIHtcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdfcmFkaW9MaXN0JywgW10sIF8uQ09ORik7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBFTEVNRU5UX05BTUVfUFJPUEVSVFksIEVMRU1FTlRfTkFNRV9QUkVGSVggKyBtaWxvQ291bnQoKSk7XG4gICAgdGhpcy5fcmVuZGVyT3B0aW9ucyA9IHt9O1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbmZ1bmN0aW9uIE1MUmFkaW9Hcm91cCRzZXRSZW5kZXJPcHRpb25zKG9wdGlvbnMpIHtcbiAgICB0aGlzLl9yZW5kZXJPcHRpb25zID0gb3B0aW9ucztcbn1cblxuXG4vKipcbiAqIFNldHMgZ3JvdXAgdmFsdWVcbiAqIFJlcGxhY2VzIHRoZSBkYXRhIHNldCBvcGVyYXRpb24gdG8gZGVhbCB3aXRoIHJhZGlvIGJ1dHRvbnNcbiAqXG4gKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gYmUgc2V0XG4gKi9cbmZ1bmN0aW9uIE1MUmFkaW9Hcm91cF9zZXQodmFsdWUpIHtcbiAgICB2YXIgb3B0aW9ucyA9IHRoaXMuX3JhZGlvTGlzdFxuICAgICAgICAsIHNldFJlc3VsdDtcbiAgICBpZiAob3B0aW9ucy5sZW5ndGgpIHtcbiAgICAgICAgb3B0aW9ucy5mb3JFYWNoKGZ1bmN0aW9uKHJhZGlvKSB7XG4gICAgICAgICAgICByYWRpby5jaGVja2VkID0gcmFkaW8udmFsdWUgPT0gdmFsdWU7XG4gICAgICAgICAgICBpZiAocmFkaW8uY2hlY2tlZClcbiAgICAgICAgICAgICAgICBzZXRSZXN1bHQgPSB2YWx1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZGlzcGF0Y2hDaGFuZ2VNZXNzYWdlLmNhbGwodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIHNldFJlc3VsdDtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBHZXRzIGdyb3VwIHZhbHVlXG4gKiBSZXRyaWV2ZXMgdGhlIHNlbGVjdGVkIHZhbHVlIG9mIHRoZSBncm91cFxuICpcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gTUxSYWRpb0dyb3VwX2dldCgpIHtcbiAgICB2YXIgY2hlY2tlZCA9IF8uZmluZCh0aGlzLl9yYWRpb0xpc3QsIGZ1bmN0aW9uKHJhZGlvKSB7XG4gICAgICAgIHJldHVybiByYWRpby5jaGVja2VkO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGNoZWNrZWQgJiYgY2hlY2tlZC52YWx1ZSB8fCB1bmRlZmluZWQ7XG59XG5cblxuLyoqXG4gKiBEZWxldGVkIGdyb3VwIHZhbHVlXG4gKiBEZWxldGVzIHRoZSB2YWx1ZSBvZiB0aGUgZ3JvdXAsIHNldHRpbmcgaXQgdG8gZW1wdHlcbiAqL1xuZnVuY3Rpb24gTUxSYWRpb0dyb3VwX2RlbCgpIHtcbiAgICB2YXIgb3B0aW9ucyA9IHRoaXMuX3JhZGlvTGlzdDtcbiAgICBpZiAob3B0aW9ucy5sZW5ndGgpXG4gICAgICAgIG9wdGlvbnMuZm9yRWFjaChmdW5jdGlvbihyYWRpbykge1xuICAgICAgICAgICAgcmFkaW8uY2hlY2tlZCA9IGZhbHNlO1xuICAgICAgICB9KTtcblxuICAgIGRpc3BhdGNoQ2hhbmdlTWVzc2FnZS5jYWxsKHRoaXMpO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG59XG5cblxuLyoqXG4gKiBNYW5hZ2UgcmFkaW8gY2hpbGRyZW4gY2xpY2tzXG4gKi9cbmZ1bmN0aW9uIG9uR3JvdXBDbGljayhldmVudFR5cGUsIGV2ZW50KSB7XG4gICAgaWYgKGV2ZW50LnRhcmdldC50eXBlID09ICdyYWRpbycpXG4gICAgICAgIGRpc3BhdGNoQ2hhbmdlTWVzc2FnZS5jYWxsKHRoaXMpO1xufVxuXG4vLyBQb3N0IHRoZSBkYXRhIGNoYW5nZVxuZnVuY3Rpb24gZGlzcGF0Y2hDaGFuZ2VNZXNzYWdlKCkge1xuICAgIHRoaXMuZGF0YS5kaXNwYXRjaFNvdXJjZU1lc3NhZ2UoUkFESU9fQ0hBTkdFX01FU1NBR0UpO1xufVxuXG5cbi8vIFNldCByYWRpbyBidXR0b24gY2hpbGRyZW4gb24gbW9kZWwgY2hhbmdlXG5mdW5jdGlvbiBvbk9wdGlvbnNDaGFuZ2UocGF0aCwgZGF0YSkge1xuICAgIHRoaXMudGVtcGxhdGUucmVuZGVyKHtcbiAgICAgICAgcmFkaW9PcHRpb25zOiB0aGlzLm1vZGVsLmdldCgpLFxuICAgICAgICBlbGVtZW50TmFtZTogdGhpc1tFTEVNRU5UX05BTUVfUFJPUEVSVFldLFxuICAgICAgICBfcmVuZGVyT3B0aW9uczogdGhpcy5fcmVuZGVyT3B0aW9uc1xuICAgIH0pO1xuXG4gICAgdmFyIHJhZGlvRWxzID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yQWxsKCdpbnB1dFt0eXBlPVwicmFkaW9cIl0nKVxuICAgICAgICAsIG9wdGlvbnMgPSBfLnRvQXJyYXkocmFkaW9FbHMpO1xuXG4gICAgdGhpcy5fcmFkaW9MaXN0Lmxlbmd0aCA9IDA7XG4gICAgdGhpcy5fcmFkaW9MaXN0LnNwbGljZS5hcHBseSh0aGlzLl9yYWRpb0xpc3QsIFswLCAwXS5jb25jYXQob3B0aW9ucykpO1xufVxuXG5cbmZ1bmN0aW9uIE1MUmFkaW9Hcm91cCRkZXN0cm95KCkge1xuICAgIGRlbGV0ZSB0aGlzLl9yYWRpb0xpc3Q7XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jX2NsYXNzJylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2NfcmVnaXN0cnknKVxuICAgICwgXyA9IHJlcXVpcmUoJ21pbG8tY29yZScpLnByb3RvO1xuXG5cbnZhciBNTFNlbGVjdCA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxTZWxlY3QnLCB7XG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogJ21sLXVpLXNlbGVjdCdcbiAgICB9LFxuICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBtb2RlbDoge1xuICAgICAgICBtZXNzYWdlczoge1xuICAgICAgICAgICAgJyoqJzogeyBzdWJzY3JpYmVyOiBvbk9wdGlvbnNDaGFuZ2UsIGNvbnRleHQ6ICdvd25lcicgfVxuICAgICAgICB9XG4gICAgfSxcbiAgICB0ZW1wbGF0ZToge1xuICAgICAgICB0ZW1wbGF0ZTogJ3t7fiBpdC5zZWxlY3RPcHRpb25zIDpvcHRpb24gfX0gXFxcbiAgICAgICAgICAgICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJ7ez0gb3B0aW9uLnZhbHVlIH19XCIge3s/IG9wdGlvbi5zZWxlY3RlZCB9fXNlbGVjdGVke3s/fX0+e3s9IG9wdGlvbi5sYWJlbCB9fTwvb3B0aW9uPiBcXFxuICAgICAgICAgICAgICAgICAgIHt7fn19J1xuICAgIH1cbn0pO1xuXG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxTZWxlY3QpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MU2VsZWN0O1xuXG5cbl8uZXh0ZW5kUHJvdG8oTUxTZWxlY3QsIHtcbiAgICBzZXRPcHRpb25zOiBNTFNlbGVjdCRzZXRPcHRpb25zLFxuICAgIGRpc2FibGU6IE1MU2VsZWN0JGRpc2FibGVcbn0pO1xuXG5cbmZ1bmN0aW9uIE1MU2VsZWN0JHNldE9wdGlvbnMob3B0aW9ucykge1xuICAgIC8vIFNldCBvcHRpb25zIHRlbXBvcmFyaWx5IGRpc2FibGVzIG1vZGVsIHN1YnNjcmlwdGlvbnMgKEFzIGEgd29ya2Fyb3VuZCBmb3IgcGVyZm9ybWFuY2UgaXNzdWVzIHJlbGF0aW5nIHRvIG1vZGVsIHVwZGF0ZXMgLyB0ZW1wbGF0ZSByZS1yZW5kZXJpbmcpXG4gICAgdmFyIG1vZGVsQ2hhbmdlTGlzdGVuZXIgPSB7IGNvbnRleHQ6IHRoaXMsIHN1YnNjcmliZXI6IG9uT3B0aW9uc0NoYW5nZSB9O1xuXG4gICAgdGhpcy5tb2RlbC5vZmYoJyoqJywgbW9kZWxDaGFuZ2VMaXN0ZW5lcik7XG4gICAgdGhpcy5tb2RlbC5zZXQob3B0aW9ucyk7XG4gICAgdGhpcy5tb2RlbC5vbignKionLCBtb2RlbENoYW5nZUxpc3RlbmVyKTtcblxuICAgIG9uT3B0aW9uc0NoYW5nZS5jYWxsKHRoaXMpO1xufVxuXG5cbmZ1bmN0aW9uIE1MU2VsZWN0JGRpc2FibGUoZGlzYWJsZSkge1xuICAgIHRoaXMuZWwuZGlzYWJsZWQgPSBkaXNhYmxlO1xufVxuXG5cbmZ1bmN0aW9uIG9uT3B0aW9uc0NoYW5nZShwYXRoLCBkYXRhKSB7XG4gICAgdGhpcy50ZW1wbGF0ZS5yZW5kZXIoeyBzZWxlY3RPcHRpb25zOiB0aGlzLm1vZGVsLmdldCgpIH0pO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIE1MU3VwZXJDb21ib1xuICogQSBjb21ibyBzZWxlY3QgbGlzdCB3aXRoIGludGVsbGlnZW50IHNjcm9sbGluZyBvZiBzdXBlciBsYXJnZSBsaXN0cy5cbiAqL1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5JylcbiAgICAsIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgZG9UID0gbWlsb0NvcmUudXRpbC5kb1RcbiAgICAsIGxvZ2dlciA9IG1pbG9Db3JlLnV0aWwubG9nZ2VyO1xuXG52YXIgQ09NQk9fT1BFTiA9ICdtbC11aS1zdXBlcmNvbWJvLW9wZW4nO1xudmFyIENPTUJPX0NIQU5HRV9NRVNTQUdFID0gJ21sc3VwZXJjb21ib2NoYW5nZSc7XG5cbnZhciBPUFRJT05TX1RFTVBMQVRFID0gJ3t7fiBpdC5jb21ib09wdGlvbnMgOm9wdGlvbjppbmRleCB9fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiB7ez8gb3B0aW9uLnNlbGVjdGVkfX1jbGFzcz1cInNlbGVjdGVkXCIge3s/fX1kYXRhLXZhbHVlPVwie3s9IGluZGV4IH19XCI+e3s9IG9wdGlvbi5sYWJlbCB9fTwvZGl2PlxcXG4gICAgICAgICAgICAgICAgICAgICAgICB7e359fSc7XG5cbnZhciBNQVhfUkVOREVSRUQgPSAxMDA7XG52YXIgQlVGRkVSID0gMjU7XG52YXIgREVGQVVMVF9FTEVNRU5UX0hFSUdIVCA9IDIwO1xuXG52YXIgTUxTdXBlckNvbWJvID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTFN1cGVyQ29tYm8nLCB7XG4gICAgZXZlbnRzOiB7XG4gICAgICAgIG1lc3NhZ2VzOiB7XG4gICAgICAgICAgICAnbW91c2VsZWF2ZSc6IHtzdWJzY3JpYmVyOiBvbk1vdXNlTGVhdmUsIGNvbnRleHQ6ICdvd25lcid9LFxuICAgICAgICAgICAgJ21vdXNlb3Zlcic6IHtzdWJzY3JpYmVyOiBvbk1vdXNlT3ZlciwgY29udGV4dDogJ293bmVyJ31cbiAgICAgICAgfVxuICAgIH0sXG4gICAgZGF0YToge1xuICAgICAgICBnZXQ6IE1MU3VwZXJDb21ib19nZXQsXG4gICAgICAgIHNldDogTUxTdXBlckNvbWJvX3NldCxcbiAgICAgICAgZGVsOiBNTFN1cGVyQ29tYm9fZGVsLFxuICAgICAgICBzcGxpY2U6IHVuZGVmaW5lZCxcbiAgICAgICAgZXZlbnQ6IENPTUJPX0NIQU5HRV9NRVNTQUdFXG4gICAgfSxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktc3VwZXJjb21ibydcbiAgICB9LFxuICAgIHRlbXBsYXRlOiB7XG4gICAgICAgIHRlbXBsYXRlOiAnPGlucHV0IG1sLWJpbmQ9XCJbZGF0YSwgZXZlbnRzXTppbnB1dFwiIGNsYXNzPVwiZm9ybS1jb250cm9sIG1sLXVpLWlucHV0XCI+XFxcbiAgICAgICAgICAgICAgICAgICA8ZGl2IG1sLWJpbmQ9XCJbZG9tXTphZGRJdGVtRGl2XCIgY2xhc3M9XCJtbC11aS1zdXBlcmNvbWJvLWFkZFwiPlxcXG4gICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBtbC1iaW5kPVwiOmFkZFByb21wdFwiPjwvc3Bhbj5cXFxuICAgICAgICAgICAgICAgICAgICAgICAgPGJ1dHRvbiBtbC1iaW5kPVwiW2V2ZW50cywgZG9tXTphZGRCdG5cIiBjbGFzcz1cImJ0biBidG4tZGVmYXVsdCBtbC11aS1idXR0b25cIj5BZGQ8L2J1dHRvbj5cXFxuICAgICAgICAgICAgICAgICAgIDwvZGl2PlxcXG4gICAgICAgICAgICAgICAgICAgPGRpdiBtbC1iaW5kPVwiW2RvbSwgZXZlbnRzXTpsaXN0XCIgY2xhc3M9XCJtbC11aS1zdXBlcmNvbWJvLWRyb3Bkb3duXCI+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBtbC1iaW5kPVwiW2RvbV06YmVmb3JlXCI+PC9kaXY+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBtbC1iaW5kPVwiW3RlbXBsYXRlLCBkb20sIGV2ZW50c106b3B0aW9uc1wiIGNsYXNzPVwibWwtdWktc3VwZXJjb21iby1vcHRpb25zXCI+PC9kaXY+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBtbC1iaW5kPVwiW2RvbV06YWZ0ZXJcIj48L2Rpdj5cXFxuICAgICAgICAgICAgICAgICAgIDwvZGl2PidcbiAgICB9LFxuICAgIGNvbnRhaW5lcjogdW5kZWZpbmVkXG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTFN1cGVyQ29tYm8pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MU3VwZXJDb21ibztcblxuLyoqXG4gKiBQdWJsaWMgQXBpXG4gKi9cbl8uZXh0ZW5kUHJvdG8oTUxTdXBlckNvbWJvLCB7XG4gICAgaW5pdDogTUxTdXBlckNvbWJvJGluaXQsXG4gICAgc2hvd09wdGlvbnM6IE1MU3VwZXJDb21ibyRzaG93T3B0aW9ucyxcbiAgICBoaWRlT3B0aW9uczogTUxTdXBlckNvbWJvJGhpZGVPcHRpb25zLFxuICAgIHRvZ2dsZU9wdGlvbnM6IE1MU3VwZXJDb21ibyR0b2dnbGVPcHRpb25zLFxuICAgIHNldE9wdGlvbnM6IE1MU3VwZXJDb21ibyRzZXRPcHRpb25zLFxuICAgIGluaXRPcHRpb25zVVJMOiBNTFN1cGVyQ29tYm8kaW5pdE9wdGlvbnNVUkwsXG4gICAgc2V0RmlsdGVyZWRPcHRpb25zOiBNTFN1cGVyQ29tYm8kc2V0RmlsdGVyZWRPcHRpb25zLFxuICAgIHVwZGF0ZTogTUxTdXBlckNvbWJvJHVwZGF0ZSxcbiAgICB0b2dnbGVBZGRCdXR0b246IE1MU3VwZXJDb21ibyR0b2dnbGVBZGRCdXR0b24sXG4gICAgc2V0QWRkSXRlbVByb21wdDogTUxTdXBlckNvbWJvJHNldEFkZEl0ZW1Qcm9tcHQsXG4gICAgY2xlYXJDb21ib0lucHV0OiBNTFN1cGVyQ29tYm9fZGVsXG59KTtcblxuXG4vKipcbiAqIENvbXBvbmVudCBpbnN0YW5jZSBtZXRob2RcbiAqIEluaXRpYWxpc2UgdGhlIGNvbXBvbmVudCwgd2FpdCBmb3IgY2hpbGRyZW5ib3VuZCwgc2V0dXAgZW1wdHkgb3B0aW9ucyBhcnJheXMuXG4gKi9cbmZ1bmN0aW9uIE1MU3VwZXJDb21ibyRpbml0KCkge1xuICAgIENvbXBvbmVudC5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXG4gICAgdGhpcy5vbmNlKCdjaGlsZHJlbmJvdW5kJywgb25DaGlsZHJlbkJvdW5kKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgIF9vcHRpb25zRGF0YTogW10sXG4gICAgICAgIF9maWx0ZXJlZE9wdGlvbnNEYXRhOiBbXVxuICAgIH0sIF8uV1JJVCk7XG59XG5cbi8qKlxuICogSGFuZGxlciBmb3IgaW5pdCBjaGlsZHJlbmJvdW5kIGxpc3RlbmVyLiBSZW5kZXJzIHRlbXBsYXRlLlxuICovXG5mdW5jdGlvbiBvbkNoaWxkcmVuQm91bmQoKSB7XG4gICAgdGhpcy50ZW1wbGF0ZS5yZW5kZXIoKS5iaW5kZXIoKTtcbiAgICBjb21wb25lbnRTZXR1cC5jYWxsKHRoaXMpO1xufVxuXG5cbi8qKlxuICogRGVmaW5lIGluc3RhbmNlIHByb3BlcnRpZXMsIGdldCBzdWJjb21wb25lbnRzLCBjYWxsIHNldHVwIHN1Yi10YXNrc1xuICovXG5mdW5jdGlvbiBjb21wb25lbnRTZXR1cCgpIHtcbiAgICB2YXIgc2NvcGUgPSB0aGlzLmNvbnRhaW5lci5zY29wZTtcblxuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgIF9jb21ib0lucHV0OiBzY29wZS5pbnB1dCxcbiAgICAgICAgX2NvbWJvTGlzdDogc2NvcGUubGlzdCxcbiAgICAgICAgX2NvbWJvT3B0aW9uczogc2NvcGUub3B0aW9ucyxcbiAgICAgICAgX2NvbWJvQmVmb3JlOiBzY29wZS5iZWZvcmUsXG4gICAgICAgIF9jb21ib0FmdGVyOiBzY29wZS5hZnRlcixcbiAgICAgICAgX2NvbWJvQWRkSXRlbURpdjogc2NvcGUuYWRkSXRlbURpdixcbiAgICAgICAgX2NvbWJvQWRkUHJvbXB0OiBzY29wZS5hZGRQcm9tcHQsXG4gICAgICAgIF9jb21ib0FkZEJ0bjogc2NvcGUuYWRkQnRuLFxuICAgICAgICBfb3B0aW9uVGVtcGxhdGU6IGRvVC5jb21waWxlKE9QVElPTlNfVEVNUExBVEUpXG4gICAgfSk7XG5cbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICBfc3RhcnRJbmRleDogMCxcbiAgICAgICAgX2VuZEluZGV4OiBNQVhfUkVOREVSRUQsXG4gICAgICAgIF9oaWRkZW46IGZhbHNlLFxuICAgICAgICBfZWxlbWVudEhlaWdodDogREVGQVVMVF9FTEVNRU5UX0hFSUdIVCxcbiAgICAgICAgX3RvdGFsOiAwLFxuICAgICAgICBfb3B0aW9uc0hlaWdodDogMjAwLFxuICAgICAgICBfbGFzdFNjcm9sbFBvczogMCxcbiAgICAgICAgX2N1cnJlbnRWYWx1ZTogbnVsbCxcbiAgICAgICAgX3NlbGVjdGVkOiBudWxsLFxuICAgICAgICBfaXNBZGRCdXR0b25TaG93bjogZmFsc2VcbiAgICB9LCBfLldSSVQpO1xuXG4gICAgLy8gQ29tcG9uZW50IFNldHVwXG4gICAgdGhpcy5kb20uc2V0U3R5bGVzKHsgcG9zaXRpb246ICdyZWxhdGl2ZScgfSk7XG4gICAgc2V0dXBDb21ib0xpc3QodGhpcy5fY29tYm9MaXN0LCB0aGlzLl9jb21ib09wdGlvbnMsIHRoaXMpO1xuICAgIHNldHVwQ29tYm9JbnB1dCh0aGlzLl9jb21ib0lucHV0LCB0aGlzKTtcbiAgICBzZXR1cENvbWJvQnRuKHRoaXMuX2NvbWJvQWRkQnRuLCB0aGlzKTtcblxuICAgIHRoaXMuZXZlbnRzLm9uKCdrZXlkb3duJywgeyBzdWJzY3JpYmVyOiBjaGFuZ2VTZWxlY3RlZCwgY29udGV4dDogdGhpcyB9KTtcbiAgICAvL3RoaXMuZXZlbnRzLm9uKCdtb3VzZWxlYXZlJywgeyBzdWJzY3JpYmVyOiBNTFN1cGVyQ29tYm8kaGlkZU9wdGlvbnMsIGNvbnRleHQ6IHRoaXMgfSk7XG59XG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZFxuICogU2hvd3Mgb3IgaGlkZXMgb3B0aW9uIGxpc3QuXG4gKlxuICogQHBhcmFtIHtCb29sZWFufSBzaG93IHRydWUgdG8gc2hvdywgZmFsc2UgdG8gaGlkZVxuICovXG5mdW5jdGlvbiBNTFN1cGVyQ29tYm8kdG9nZ2xlT3B0aW9ucyhzaG93KSB7XG4gICAgdGhpcy5faGlkZGVuID0gIXNob3c7XG4gICAgdGhpcy5fY29tYm9MaXN0LmRvbS50b2dnbGUoc2hvdyk7XG59XG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZFxuICogU2hvd3Mgb3B0aW9ucyBsaXN0XG4gKi9cbmZ1bmN0aW9uIE1MU3VwZXJDb21ibyRzaG93T3B0aW9ucygpIHtcbiAgICB0aGlzLl9oaWRkZW4gPSBmYWxzZTtcbiAgICB0aGlzLmVsLmNsYXNzTGlzdC5hZGQoQ09NQk9fT1BFTik7XG4gICAgdGhpcy5fY29tYm9MaXN0LmRvbS50b2dnbGUodHJ1ZSk7XG59XG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZFxuICogSGlkZXMgb3B0aW9ucyBsaXN0XG4gKi9cbmZ1bmN0aW9uIE1MU3VwZXJDb21ibyRoaWRlT3B0aW9ucygpIHtcbiAgICB0aGlzLl9oaWRkZW4gPSB0cnVlO1xuICAgIHRoaXMuZWwuY2xhc3NMaXN0LnJlbW92ZShDT01CT19PUEVOKTtcbiAgICB0aGlzLl9jb21ib0xpc3QuZG9tLnRvZ2dsZShmYWxzZSk7XG59XG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZFxuICogSGlkZXMgYWRkIGJ1dHRvblxuICovXG5mdW5jdGlvbiBNTFN1cGVyQ29tYm8kdG9nZ2xlQWRkQnV0dG9uKHNob3csIG9wdGlvbnMpIHtcbiAgICB0aGlzLl9jb21ib0FkZEl0ZW1EaXYuZG9tLnRvZ2dsZShzaG93KTtcbiAgICBpZiAob3B0aW9ucyAmJiBvcHRpb25zLnByZXNlcnZlU3RhdGUpIHRoaXMuX19zaG93QWRkT25DbGljayA9IHRoaXMuX2lzQWRkQnV0dG9uU2hvd247XG4gICAgdGhpcy5faXNBZGRCdXR0b25TaG93biA9IHNob3c7XG59XG5cblxuZnVuY3Rpb24gTUxTdXBlckNvbWJvJHNldEFkZEl0ZW1Qcm9tcHQocHJvbXB0KSB7XG4gICAgdGhpcy5fYWRkSXRlbVByb21wdCA9IHByb21wdDtcbiAgICB0aGlzLl9jb21ib0FkZFByb21wdC5lbC5pbm5lckhUTUwgPSBwcm9tcHQ7XG4gICAgdGhpcy50b2dnbGVBZGRCdXR0b24oZmFsc2UpO1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZFxuICogU2V0cyB0aGUgb3B0aW9ucyBvZiB0aGUgZHJvcGRvd25cbiAqXG4gKiBAcGFyYW0ge0FycmF5W09iamVjdF19IGFyciB0aGUgb3B0aW9ucyB0byBzZXQgd2l0aCBsYWJlbCBhbmQgdmFsdWUgcGFpcnMuIFZhbHVlIGNhbiBiZSBhbiBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIE1MU3VwZXJDb21ibyRzZXRPcHRpb25zKGFycikge1xuICAgIHRoaXMuX29wdGlvbnNEYXRhID0gYXJyO1xuICAgIHRoaXMuc2V0RmlsdGVyZWRPcHRpb25zKGFycik7XG59XG5cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsaXNlIHRoZSByZW1vdGUgb3B0aW9ucyBvZiB0aGUgZHJvcGRvd25cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyB0aGUgb3B0aW9ucyB0byBpbml0aWFsaXNlLlxuICovXG5mdW5jdGlvbiBNTFN1cGVyQ29tYm8kaW5pdE9wdGlvbnNVUkwob3B0aW9ucykge1xuICAgIHRoaXMuX29wdGlvbnNVUkwgPSBvcHRpb25zLnVybDtcbiAgICB0aGlzLl9mb3JtYXRPcHRpb25zVVJMID0gb3B0aW9ucy5mb3JtYXRPcHRpb25zIHx8IGZ1bmN0aW9uKGUpe3JldHVybiBlO307XG59XG5cblxuLyoqXG4gKiBQcml2YXRlIG1ldGhvZFxuICogU2V0cyB0aGUgb3B0aW9ucyBvZiB0aGUgZHJvcGRvd24gYmFzZWQgb24gYSByZXF1ZXN0XG4gKi9cbmZ1bmN0aW9uIF9nZXRPcHRpb25zVVJMKGNiKSB7XG4gICAgdmFyIHVybCA9IHRoaXMuX29wdGlvbnNVUkwsXG4gICAgICAgIHF1ZXJ5U3RyaW5nID0gdGhpcy5fY29tYm9JbnB1dC5kYXRhLmdldCgpO1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBjYiA9IGNiIHx8IF8ubm9vcDtcbiAgICBtaWxvLnV0aWwucmVxdWVzdC5wb3N0KHVybCwgeyBuYW1lOiBxdWVyeVN0cmluZyB9LCBmdW5jdGlvbiAoZXJyLCByZXNwb25zZSkge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoJ0NhbiBub3Qgc2VhcmNoIGZvciBcIicgKyBxdWVyeVN0cmluZyArICdcIicpO1xuICAgICAgICAgICAgcmV0dXJuIGNiKG5ldyBFcnJvcignUmVxdWVzdCBlcnJvcicpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciByZXNwb25zZURhdGEgPSBfLmpzb25QYXJzZShyZXNwb25zZSk7XG4gICAgICAgIGlmIChyZXNwb25zZURhdGEpIGNiKG51bGwsIHJlc3BvbnNlRGF0YSk7XG4gICAgICAgIGVsc2UgY2IobmV3IEVycm9yKCdEYXRhIGVycm9yJykpO1xuICAgIH0pO1xufVxuXG5cbi8qKlxuICogQ29tcG9uZW50IGluc3RhbmNlIG1ldGhvZFxuICogU2V0cyB0aGUgZmlsdGVyZWQgb3B0aW9ucywgd2hpY2ggaXMgYSBzdWJzZXQgb2Ygbm9ybWFsIG9wdGlvbnNcbiAqXG4gKiBAcGFyYW0ge1t0eXBlXX0gYXJyIFRoZSBvcHRpb25zIHRvIHNldFxuICovXG5mdW5jdGlvbiBNTFN1cGVyQ29tYm8kc2V0RmlsdGVyZWRPcHRpb25zKGFycikge1xuICAgIGlmICghIGFycikgcmV0dXJuIGxvZ2dlci5lcnJvcignc2V0RmlsdGVyZWRPcHRpb25zOiBwYXJhbWV0ZXIgaXMgdW5kZWZpbmVkJyk7XG4gICAgdGhpcy5fZmlsdGVyZWRPcHRpb25zRGF0YSA9IGFycjtcbiAgICB0aGlzLl90b3RhbCA9IGFyci5sZW5ndGg7XG4gICAgdGhpcy51cGRhdGUoKTtcbn1cblxuLyoqXG4gKiBDb21wb25lbnQgaW5zdGFuY2UgbWV0aG9kXG4gKiBVcGRhdGVzIHRoZSBsaXN0LiBUaGlzIGlzIHVzZWQgb24gc2Nyb2xsLCBhbmQgbWFrZXMgdXNlIG9mIHRoZSBmaWx0ZXJlZE9wdGlvbnMgdG9cbiAqIGludGVsbGlnZW50bHkgc2hvdyBhIHN1YnNldCBvZiB0aGUgZmlsdGVyZWQgbGlzdCBhdCBhIHRpbWUuXG4gKi9cbmZ1bmN0aW9uIE1MU3VwZXJDb21ibyR1cGRhdGUoKSB7XG4gICAgdmFyIHdhc0hpZGRlbiA9IHRoaXMuX2hpZGRlbjtcblxuICAgIHZhciBhcnJUb1Nob3cgPSB0aGlzLl9maWx0ZXJlZE9wdGlvbnNEYXRhLnNsaWNlKHRoaXMuX3N0YXJ0SW5kZXgsIHRoaXMuX2VuZEluZGV4KTtcblxuICAgIHRoaXMuX2NvbWJvT3B0aW9ucy50ZW1wbGF0ZS5yZW5kZXIoe1xuICAgICAgICBjb21ib09wdGlvbnM6IGFyclRvU2hvd1xuICAgIH0pO1xuXG4gICAgdGhpcy5fZWxlbWVudEhlaWdodCA9IHRoaXMuX2VsZW1lbnRIZWlnaHQgfHwgREVGQVVMVF9FTEVNRU5UX0hFSUdIVDtcblxuICAgIGlmICh3YXNIaWRkZW4pXG4gICAgICAgIHRoaXMuaGlkZU9wdGlvbnMoKTtcblxuICAgIHZhciBiZWZvcmVIZWlnaHQgPSB0aGlzLl9zdGFydEluZGV4ICogdGhpcy5fZWxlbWVudEhlaWdodDtcbiAgICB2YXIgYWZ0ZXJIZWlnaHQgPSAodGhpcy5fdG90YWwgLSB0aGlzLl9lbmRJbmRleCkgKiB0aGlzLl9lbGVtZW50SGVpZ2h0O1xuICAgIHRoaXMuX2NvbWJvQmVmb3JlLmVsLnN0eWxlLmhlaWdodCA9IGJlZm9yZUhlaWdodCArICdweCc7XG4gICAgdGhpcy5fY29tYm9BZnRlci5lbC5zdHlsZS5oZWlnaHQgPSBhZnRlckhlaWdodCA+IDAgPyBhZnRlckhlaWdodCArICdweCcgOiAnMHB4Jztcbn1cblxuLyoqXG4gKiBTZXR1cCB0aGUgY29tYm8gbGlzdFxuICpcbiAqIEBwYXJhbSAge0NvbXBvbmVudH0gbGlzdFxuICogQHBhcmFtICB7QXJyYXl9IG9wdGlvbnNcbiAqIEBwYXJhbSAge0NvbXBvbmVudH0gc2VsZlxuICovXG5mdW5jdGlvbiBzZXR1cENvbWJvTGlzdChsaXN0LCBvcHRpb25zLCBzZWxmKSB7XG4gICAgc2VsZi50b2dnbGVBZGRCdXR0b24oZmFsc2UpO1xuICAgIG9wdGlvbnMudGVtcGxhdGUuc2V0KE9QVElPTlNfVEVNUExBVEUpO1xuXG4gICAgbGlzdC5kb20uc2V0U3R5bGVzKHtcbiAgICAgICAgb3ZlcmZsb3c6ICdzY3JvbGwnLFxuICAgICAgICBoZWlnaHQ6IHNlbGYuX29wdGlvbnNIZWlnaHQgKyAncHgnLFxuICAgICAgICB3aWR0aDogJzEwMCUnLFxuICAgICAgICBwb3NpdGlvbjogJ2Fic29sdXRlJyxcbiAgICAgICAgekluZGV4OiAxMFxuICAgICAgICAvLyB0b3A6IHlQb3MgKyAncHgnLFxuICAgICAgICAvLyBsZWZ0OiB4UG9zICsgJ3B4JyxcbiAgICB9KTtcblxuICAgIHNlbGYuaGlkZU9wdGlvbnMoKTtcbiAgICBsaXN0LmV2ZW50cy5vbk1lc3NhZ2VzKHtcbiAgICAgICAgJ2NsaWNrJzoge3N1YnNjcmliZXI6IG9uTGlzdENsaWNrLCBjb250ZXh0OiBzZWxmfSxcbiAgICAgICAgJ3Njcm9sbCc6IHtzdWJzY3JpYmVyOiBvbkxpc3RTY3JvbGwsIGNvbnRleHQ6IHNlbGZ9XG4gICAgfSk7XG59XG5cbi8qKlxuICogU2V0dXAgdGhlIGlucHV0IGNvbXBvbmVudFxuICpcbiAqIEBwYXJhbSAge0NvbXBvbmVudH0gaW5wdXRcbiAqIEBwYXJhbSAge0NvbXBvbmVudH0gc2VsZlxuICovXG5mdW5jdGlvbiBzZXR1cENvbWJvSW5wdXQoaW5wdXQsIHNlbGYpIHtcbiAgICBpbnB1dC5ldmVudHMub25jZSgnZm9jdXMnLCBmdW5jdGlvbigpe1xuICAgICAgICBpbnB1dC5kYXRhLm9uKCcnLCB7IHN1YnNjcmliZXI6IG9uRGF0YUNoYW5nZSwgY29udGV4dDogc2VsZiB9KTtcbiAgICAgICAgaW5wdXQuZXZlbnRzLm9uKCdjbGljaycsIHtzdWJzY3JpYmVyOiBvbklucHV0Q2xpY2ssIGNvbnRleHQ6IHNlbGYgfSk7XG4gICAgICAgIGlucHV0LmV2ZW50cy5vbigna2V5ZG93bicsIHtzdWJzY3JpYmVyOiBvbkVudGVyS2V5LCBjb250ZXh0OiBzZWxmIH0pO1xuICAgIH0pO1xufVxuXG4vKipcbiAqIFNldHVwIHRoZSBidXR0b25cbiAqIEBwYXJhbSAge0NvbXBvbmVudH0gYnRuXG4gKiBAcGFyYW0gIHtDb21wb25lbnR9IHNlbGZcbiAqL1xuZnVuY3Rpb24gc2V0dXBDb21ib0J0bihidG4sIHNlbGYpIHtcbiAgICBidG4uZXZlbnRzLm9uKCdjbGljaycsIHsgc3Vic2NyaWJlcjogb25BZGRCdG4sIGNvbnRleHQ6IHNlbGYgfSk7XG59XG5cblxuLyoqXG4gKiBDdXN0b20gZGF0YSBmYWNldCBnZXQgbWV0aG9kXG4gKi9cbmZ1bmN0aW9uIE1MU3VwZXJDb21ib19nZXQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2N1cnJlbnRWYWx1ZTtcbn1cblxuLyoqXG4gKiBDdXN0b20gZGF0YSBmYWNldCBzZXQgbWV0aG9kXG4gKiBAcGFyYW0ge1ZhcmlhYmxlfSBvYmpcbiAqL1xuZnVuY3Rpb24gTUxTdXBlckNvbWJvX3NldChvYmopIHtcbiAgICB0aGlzLl9jdXJyZW50VmFsdWUgPSBvYmo7XG4gICAgdGhpcy5fY29tYm9JbnB1dC5kYXRhLnNldChvYmogJiYgb2JqLmxhYmVsKTtcbiAgICBfLmRlZmVyTWV0aG9kKHRoaXMsICdoaWRlT3B0aW9ucycpO1xufVxuXG4vKipcbiAqIEN1c3RvbSBkYXRhIGZhY2V0IGRlbCBtZXRob2RcbiAqL1xuZnVuY3Rpb24gTUxTdXBlckNvbWJvX2RlbCgpIHtcbiAgICB0aGlzLl9jdXJyZW50VmFsdWUgPSBudWxsO1xuICAgIHRoaXMuX2NvbWJvSW5wdXQuZGF0YS5zZXQoJycpO1xufVxuXG5cbi8qKlxuICogSW5wdXQgZGF0YSBjaGFuZ2UgaGFuZGxlclxuICogV2hlbiB0aGUgaW5wdXQgZGF0YSBjaGFuZ2VzLCB0aGlzIG1ldGhvZCBmaWx0ZXJzIHRoZSBvcHRpb25zRGF0YSwgYW5kIHNldHMgdGhlIGZpcnN0IGVsZW1lbnRcbiAqIHRvIGJlIHNlbGVjdGVkLlxuICogQHBhcmFtICB7U3RyaW5nfSBtc2dcbiAqIEBwYXJhbSAge09iamV4dH0gZGF0YVxuICovXG5mdW5jdGlvbiBvbkRhdGFDaGFuZ2UobXNnLCBkYXRhKSB7XG4gICAgdmFyIHRleHQgPSBkYXRhLm5ld1ZhbHVlICYmIGRhdGEubmV3VmFsdWUudHJpbSgpO1xuICAgIGlmICh0aGlzLl9vcHRpb25zVVJMKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgX2dldE9wdGlvbnNVUkwuY2FsbCh0aGlzLCBmdW5jdGlvbihlcnIsIHJlc3BvbnNlRGF0YSl7XG4gICAgICAgICAgICBpZiAoZXJyIHx8ICFyZXNwb25zZURhdGEpIHJldHVybjtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSByZXNwb25zZURhdGEuZGF0YS5tYXAoc2VsZi5fZm9ybWF0T3B0aW9uc1VSTCk7XG4gICAgICAgICAgICAgICAgc2VsZi5zZXRPcHRpb25zKG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIF91cGRhdGVPcHRpb25zQW5kQWRkQnV0dG9uLmNhbGwoc2VsZiwgdGV4dCwgc2VsZi5fb3B0aW9uc0RhdGEpO1xuICAgICAgICAgICAgfSBjYXRjaChlKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCdEYXRhIGVycm9yJywgZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBmaWx0ZXJlZERhdGEgPSBfZmlsdGVyRGF0YS5jYWxsKHRoaXMsIHRleHQpO1xuICAgICAgICBfdXBkYXRlT3B0aW9uc0FuZEFkZEJ1dHRvbi5jYWxsKHRoaXMsIHRleHQsIGZpbHRlcmVkRGF0YSk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIF9maWx0ZXJEYXRhKHRleHQpIHtcbiAgICByZXR1cm4gdGhpcy5fb3B0aW9uc0RhdGEuZmlsdGVyKGZ1bmN0aW9uKG9wdGlvbikge1xuICAgICAgICBkZWxldGUgb3B0aW9uLnNlbGVjdGVkO1xuICAgICAgICBpZiAob3B0aW9uLmxhYmVsKSB7XG4gICAgICAgICAgICB2YXIgbGFiZWwgPSBvcHRpb24ubGFiZWwudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICAgIHJldHVybiBsYWJlbC50cmltKCkudG9Mb3dlckNhc2UoKS5pbmRleE9mKHRleHQudG9Mb3dlckNhc2UoKSkgPT0gMDtcbiAgICAgICAgfVxuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIF91cGRhdGVPcHRpb25zQW5kQWRkQnV0dG9uKHRleHQsIGZpbHRlcmVkQXJyKSB7XG4gICAgaWYgKCF0ZXh0KSB7XG4gICAgICAgIHRoaXMudG9nZ2xlQWRkQnV0dG9uKGZhbHNlLCB7IHByZXNlcnZlU3RhdGU6IHRydWUgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKGZpbHRlcmVkQXJyLmxlbmd0aCAmJiBfLmZpbmQoZmlsdGVyZWRBcnIsIGlzRXhhY3RNYXRjaCkpIHtcbiAgICAgICAgICAgIHRoaXMudG9nZ2xlQWRkQnV0dG9uKGZhbHNlLCB7IHByZXNlcnZlU3RhdGU6IHRydWUgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5fYWRkSXRlbVByb21wdCkge1xuICAgICAgICAgICAgdGhpcy50b2dnbGVBZGRCdXR0b24odGhpcy5fb3B0aW9uc0RhdGEubGVuZ3RoID4gMSB8fCB0aGlzLl9vcHRpb25zVVJMKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChmaWx0ZXJlZEFyci5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRoaXMuc2hvd09wdGlvbnMoKTtcbiAgICAgICAgICAgIGZpbHRlcmVkQXJyWzBdLnNlbGVjdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuX3NlbGVjdGVkID0gZmlsdGVyZWRBcnJbMF07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmhpZGVPcHRpb25zKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLnNldEZpbHRlcmVkT3B0aW9ucyhmaWx0ZXJlZEFycik7XG4gICAgdGhpcy5fY29tYm9MaXN0LmVsLnNjcm9sbFRvcCA9IDA7XG5cbiAgICBmdW5jdGlvbiBpc0V4YWN0TWF0Y2goaXRlbSkge1xuICAgICAgICByZXR1cm4gaXRlbS5sYWJlbC50b0xvd2VyQ2FzZSgpID09PSB0ZXh0LnRvTG93ZXJDYXNlKCk7XG4gICAgfVxufVxuXG4vKipcbiAqIEEgbWFwIG9mIGtleUNvZGVzIHRvIGRpcmVjdGlvbnNcbiAqIEB0eXBlIHtPYmplY3R9XG4gKi9cbnZhciBkaXJlY3Rpb25NYXAgPSB7ICc0MCc6IDEsICczOCc6IC0xIH07XG5cbi8qKlxuICogTGlzdCBrZXlkb3duIGhhbmRsZXJcbiAqIENoYW5nZXMgdGhlIHNlbGVjdGVkIGxpc3QgaXRlbSBieSBmaW5kaW5nIHRoZSBhZGphY2VudCBpdGVtIGFuZCBzZXR0aW5nIGl0IHRvIHNlbGVjdGVkLlxuICpcbiAqIEBwYXJhbSAge3N0cmluZ30gdHlwZVxuICogQHBhcmFtICB7RXZlbnR9IGV2ZW50XG4gKi9cbmZ1bmN0aW9uIGNoYW5nZVNlbGVjdGVkKHR5cGUsIGV2ZW50KSB7XG4gICAgLy9UT0RPIHRlc3QgbW9jaGFcbiAgICB2YXIgZGlyZWN0aW9uID0gZGlyZWN0aW9uTWFwW2V2ZW50LmtleUNvZGVdO1xuXG4gICAgaWYoZGlyZWN0aW9uKVxuICAgICAgICBfY2hhbmdlU2VsZWN0ZWQuY2FsbCh0aGlzLCBkaXJlY3Rpb24pO1xufVxuXG5mdW5jdGlvbiBfY2hhbmdlU2VsZWN0ZWQoZGlyZWN0aW9uKSB7XG4gICAgLy8gVE9ETzogcmVmYWN0b3IgYW5kIHRpZHkgdXAsIGxvb2tzIGxpa2Ugc29tZSBjb2RlIGR1cGxpY2F0aW9uLlxuICAgIHZhciBzZWxlY3RlZCA9IHRoaXMuZWwucXVlcnlTZWxlY3RvckFsbCgnLnNlbGVjdGVkJylbMF1cbiAgICAgICAgLCBzY3JvbGxQb3MgPSB0aGlzLl9jb21ib0xpc3QuZWwuc2Nyb2xsVG9wXG4gICAgICAgICwgc2VsZWN0ZWRQb3MgPSBzZWxlY3RlZCA/IHNlbGVjdGVkLm9mZnNldFRvcCA6IDBcbiAgICAgICAgLCByZWxhdGl2ZVBvcyA9IHNlbGVjdGVkUG9zIC0gc2Nyb2xsUG9zO1xuXG4gICAgaWYgKHNlbGVjdGVkKSB7XG4gICAgICAgIHZhciBpbmRleCA9IF9nZXREYXRhVmFsdWVGcm9tRWxlbWVudC5jYWxsKHRoaXMsIHNlbGVjdGVkKVxuICAgICAgICAgICAgLCB0aGlzSXRlbSA9IHRoaXMuX2ZpbHRlcmVkT3B0aW9uc0RhdGFbaW5kZXhdXG4gICAgICAgICAgICAsIGFkakl0ZW0gPSB0aGlzLl9maWx0ZXJlZE9wdGlvbnNEYXRhW2luZGV4ICsgZGlyZWN0aW9uXTtcblxuICAgICAgICBpZiAoYWRqSXRlbSkge1xuICAgICAgICAgICAgZGVsZXRlIHRoaXNJdGVtLnNlbGVjdGVkO1xuICAgICAgICAgICAgYWRqSXRlbS5zZWxlY3RlZCA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLl9zZWxlY3RlZCA9IGFkakl0ZW07XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZSgpO1xuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHRoaXMuX2ZpbHRlcmVkT3B0aW9uc0RhdGFbMF0pIHtcbiAgICAgICAgICAgIHRoaXMuX2ZpbHRlcmVkT3B0aW9uc0RhdGFbMF0uc2VsZWN0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy51cGRhdGUoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlmIChyZWxhdGl2ZVBvcyA+IHRoaXMuX29wdGlvbnNIZWlnaHQgLSB0aGlzLl9lbGVtZW50SGVpZ2h0KjIgJiYgZGlyZWN0aW9uID09PSAxKVxuICAgICAgICB0aGlzLl9jb21ib0xpc3QuZWwuc2Nyb2xsVG9wICs9IHRoaXMuX2VsZW1lbnRIZWlnaHQqZGlyZWN0aW9uKjU7XG5cbiAgICBpZiAocmVsYXRpdmVQb3MgPCB0aGlzLl9lbGVtZW50SGVpZ2h0ICYmIGRpcmVjdGlvbiA9PT0gLTEpXG4gICAgICAgIHRoaXMuX2NvbWJvTGlzdC5lbC5zY3JvbGxUb3AgKz0gdGhpcy5fZWxlbWVudEhlaWdodCpkaXJlY3Rpb24qNTtcbn1cblxuXG4vKipcbiAqIE1vdXNlIG92ZXIgaGFuZGxlclxuICpcbiAqIEBwYXJhbSAge1N0cmluZ30gdHlwZVxuICogQHBhcmFtICB7RXZlbnR9IGV2ZW50XG4gKi9cbmZ1bmN0aW9uIG9uTW91c2VPdmVyKHR5cGUsIGV2ZW50KSB7XG4gICAgdGhpcy5fbW91c2VJc092ZXIgPSB0cnVlO1xufVxuXG5cbi8qKlxuICogTW91c2UgbGVhdmUgaGFuZGxlclxuICpcbiAqIEBwYXJhbSAge1N0cmluZ30gdHlwZVxuICogQHBhcmFtICB7RXZlbnR9IGV2ZW50XG4gKi9cbmZ1bmN0aW9uIG9uTW91c2VMZWF2ZSh0eXBlLCBldmVudCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLl9tb3VzZUlzT3ZlciA9IGZhbHNlO1xuICAgIGlmICh0aGlzLl9tb3VzZU91dFRpbWVyKSBjbGVhckludGVydmFsKHRoaXMuX21vdXNlT3V0VGltZXIpO1xuICAgIHRoaXMuX21vdXNlT3V0VGltZXIgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7XG4gICAgICAgIGlmICghc2VsZi5fbW91c2VJc092ZXIpXG4gICAgICAgICAgICBfb25Nb3VzZUxlYXZlLmNhbGwoc2VsZik7XG4gICAgfSwgNzUwKTtcbn1cblxuZnVuY3Rpb24gX29uTW91c2VMZWF2ZSgpIHtcbiAgICB0aGlzLmhpZGVPcHRpb25zKCk7XG4gICAgdGhpcy50b2dnbGVBZGRCdXR0b24oZmFsc2UsIHsgcHJlc2VydmVTdGF0ZTogdHJ1ZSB9KTtcbn1cblxuXG4vKipcbiAqIElucHV0IGNsaWNrIGhhbmRsZXJcbiAqXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHR5cGVcbiAqIEBwYXJhbSAge0V2ZW50fSBldmVudFxuICovXG5mdW5jdGlvbiBvbklucHV0Q2xpY2sodHlwZSwgZXZlbnQpIHtcbiAgICB0aGlzLnNob3dPcHRpb25zKCk7XG4gICAgaWYgKHRoaXMuX19zaG93QWRkT25DbGljaykgdGhpcy50b2dnbGVBZGRCdXR0b24odHJ1ZSk7XG59XG5cblxuLyoqXG4gKiBFbnRlciBrZXkgaGFuZGxlclxuICpcbiAqIEBwYXJhbSAge1N0cmluZ30gdHlwZVxuICogQHBhcmFtICB7RXZlbnR9IGV2ZW50XG4gKi9cbmZ1bmN0aW9uIG9uRW50ZXJLZXkodHlwZSwgZXZlbnQpIHtcbiAgICBpZiAoZXZlbnQua2V5Q29kZSA9PSAxMykge1xuICAgICAgICBpZiAodGhpcy5fc2VsZWN0ZWQpXG4gICAgICAgICAgICBfc2V0RGF0YS5jYWxsKHRoaXMpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBBZGQgYnV0dG9uIGhhbmRsZXJcbiAqXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHR5cGVcbiAqIEBwYXJhbSAge0V2ZW50fSBldmVudFxuICovXG5mdW5jdGlvbiBvbkFkZEJ0biAodHlwZSwgZXZlbnQpIHtcbiAgICB2YXIgZGF0YSA9IHsgbGFiZWw6IHRoaXMuX2NvbWJvSW5wdXQuZWwudmFsdWUgfTtcbiAgICB0aGlzLnBvc3RNZXNzYWdlKCdhZGRpdGVtJywgZGF0YSk7XG4gICAgdGhpcy5ldmVudHMucG9zdE1lc3NhZ2UoJ21pbG9fc3VwZXJjb21ib2FkZGl0ZW0nLCBkYXRhKTtcbiAgICB0aGlzLnRvZ2dsZUFkZEJ1dHRvbihmYWxzZSwgeyBwcmVzZXJ2ZVN0YXRlOiB0cnVlIH0pO1xuXG59XG5cbi8qKlxuICogTGlzdCBjbGljayBoYW5kbGVyXG4gKlxuICogQHBhcmFtICB7U3RyaW5nfSB0eXBlXG4gKiBAcGFyYW0gIHtFdmVudH0gZXZlbnRcbiAqL1xuZnVuY3Rpb24gb25MaXN0Q2xpY2sgKHR5cGUsIGV2ZW50KSB7XG4gICAgdmFyIGluZGV4ID0gX2dldERhdGFWYWx1ZUZyb21FbGVtZW50LmNhbGwodGhpcywgZXZlbnQudGFyZ2V0KTtcbiAgICB2YXIgZGF0YSA9IHRoaXMuX2ZpbHRlcmVkT3B0aW9uc0RhdGFbaW5kZXhdO1xuXG4gICAgdGhpcy5fc2VsZWN0ZWQgPSBkYXRhO1xuICAgIF9zZXREYXRhLmNhbGwodGhpcyk7XG4gICAgdGhpcy51cGRhdGUoKTtcbn1cblxuXG4vKipcbiAqIExpc3Qgc2Nyb2xsIGhhbmRsZXJcbiAqXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHR5cGVcbiAqIEBwYXJhbSAge0V2ZW50fSBldmVudFxuICovXG5mdW5jdGlvbiBvbkxpc3RTY3JvbGwgKHR5cGUsIGV2ZW50KSB7XG4gICAgdmFyIHNjcm9sbFBvcyA9IGV2ZW50LnRhcmdldC5zY3JvbGxUb3BcbiAgICAgICAgLCBkaXJlY3Rpb24gPSBzY3JvbGxQb3MgPiB0aGlzLl9sYXN0U2Nyb2xsUG9zID8gJ2Rvd24nIDogJ3VwJ1xuICAgICAgICAsIGZpcnN0Q2hpbGQgPSB0aGlzLl9jb21ib09wdGlvbnMuZWwubGFzdEVsZW1lbnRDaGlsZFxuICAgICAgICAsIGxhc3RDaGlsZCA9IHRoaXMuX2NvbWJvT3B0aW9ucy5lbC5maXJzdEVsZW1lbnRDaGlsZFxuICAgICAgICAsIGxhc3RFbFBvc2l0aW9uID0gZmlyc3RDaGlsZCA/IGZpcnN0Q2hpbGQub2Zmc2V0VG9wIDogMFxuICAgICAgICAsIGZpcnN0RWxQb3NpdGlvbiA9IGxhc3RDaGlsZCA/IGxhc3RDaGlsZC5vZmZzZXRUb3AgOiAwXG4gICAgICAgICwgZGlzdEZyb21MYXN0RWwgPSBsYXN0RWxQb3NpdGlvbiAtIHNjcm9sbFBvcyAtIHRoaXMuX29wdGlvbnNIZWlnaHQgKyB0aGlzLl9lbGVtZW50SGVpZ2h0XG4gICAgICAgICwgZGlzdEZyb21GaXJzdEVsID0gc2Nyb2xsUG9zIC0gZmlyc3RFbFBvc2l0aW9uXG4gICAgICAgICwgZWxzRnJvbVN0YXJ0ID0gTWF0aC5mbG9vcihkaXN0RnJvbUZpcnN0RWwgLyB0aGlzLl9lbGVtZW50SGVpZ2h0KVxuICAgICAgICAsIGVsc1RvVGhlRW5kID0gTWF0aC5mbG9vcihkaXN0RnJvbUxhc3RFbCAvIHRoaXMuX2VsZW1lbnRIZWlnaHQpXG4gICAgICAgICwgdG90YWxFbGVtZW50c0JlZm9yZSA9IE1hdGguZmxvb3Ioc2Nyb2xsUG9zIC8gdGhpcy5fZWxlbWVudEhlaWdodCkgLSBCVUZGRVI7XG5cbiAgICBpZiAoKGRpcmVjdGlvbiA9PSAnZG93bicgJiYgZWxzVG9UaGVFbmQgPCBCVUZGRVIpXG4gICAgICAgIHx8IChkaXJlY3Rpb24gPT0gJ3VwJyAmJiBlbHNGcm9tU3RhcnQgPCBCVUZGRVIpKSB7XG4gICAgICAgIHRoaXMuX3N0YXJ0SW5kZXggPSB0b3RhbEVsZW1lbnRzQmVmb3JlID4gMCA/IHRvdGFsRWxlbWVudHNCZWZvcmUgOiAwO1xuICAgICAgICB0aGlzLl9lbmRJbmRleCA9IHRvdGFsRWxlbWVudHNCZWZvcmUgKyBNQVhfUkVOREVSRUQ7XG4gICAgICAgIHRoaXMuX2VsZW1lbnRIZWlnaHQgPSBmaXJzdENoaWxkLnN0eWxlLmhlaWdodDtcbiAgICAgICAgdGhpcy51cGRhdGUoKTtcbiAgICB9XG4gICAgdGhpcy5fbGFzdFNjcm9sbFBvcyA9IHNjcm9sbFBvcztcbn1cblxuXG4vKipcbiAqIFByaXZhdGUgbWV0aG9kXG4gKiBSZXRyaWV2ZXMgdGhlIGRhdGEtdmFsdWUgYXR0cmlidXRlIHZhbHVlIGZyb20gdGhlIGVsZW1lbnQgYW5kIHJldHVybnMgaXQgYXMgYW4gaW5kZXggb2ZcbiAqIHRoZSBmaWx0ZXJlZE9wdGlvbnNcbiAqXG4gKiBAcGFyYW0gIHtFbGVtZW50fSBlbFxuICogQHJldHVybiB7TnVtYmVyfVxuICovXG5mdW5jdGlvbiBfZ2V0RGF0YVZhbHVlRnJvbUVsZW1lbnQoZWwpIHtcbiAgICByZXR1cm4gTnVtYmVyKGVsLmdldEF0dHJpYnV0ZSgnZGF0YS12YWx1ZScpKSArIHRoaXMuX3N0YXJ0SW5kZXg7XG59XG5cbi8qKlxuICogUHJpdmF0ZSBtZXRob2RcbiAqIFNldHMgdGhlIGRhdGEgb2YgdGhlIFN1cGVyQ29tYm8sIHRha2luZyBjYXJlIHRvIHJlc2V0IHNvbWUgdGhpbmdzIGFuZCB0ZW1wb3JhcmlseVxuICogdW5zdWJzY3JpYmUgZGF0YSBsaXN0ZW5lcnMuXG4gKi9cbmZ1bmN0aW9uIF9zZXREYXRhKCkge1xuICAgIGRlbGV0ZSB0aGlzLl9zZWxlY3RlZC5zZWxlY3RlZDtcbiAgICB0aGlzLmhpZGVPcHRpb25zKCk7XG4gICAgdGhpcy50b2dnbGVBZGRCdXR0b24oZmFsc2UpO1xuICAgIHRoaXMuX2NvbWJvSW5wdXQuZGF0YS5vZmYoJycsIHsgc3Vic2NyaWJlcjogb25EYXRhQ2hhbmdlLCBjb250ZXh0OiB0aGlzIH0pO1xuICAgIC8vc3VwZXJjb21ibyBsaXN0ZW5lcnMgb2ZmXG4gICAgdGhpcy5kYXRhLnNldCh0aGlzLl9zZWxlY3RlZCk7XG4gICAgdGhpcy5kYXRhLmRpc3BhdGNoU291cmNlTWVzc2FnZShDT01CT19DSEFOR0VfTUVTU0FHRSk7XG4gICAgdGhpcy5fY29tYm9JbnB1dC5kYXRhLm9uKCcnLCB7IHN1YnNjcmliZXI6IG9uRGF0YUNoYW5nZSwgY29udGV4dDogdGhpcyB9KTtcbiAgICAvL3N1cGVyY29tYm8gbGlzdGVuZXJzIG9uXG4gICAgdGhpcy5fc2VsZWN0ZWQgPSBudWxsO1xuICAgIHRoaXMuc2V0RmlsdGVyZWRPcHRpb25zKHRoaXMuX29wdGlvbnNEYXRhKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vY19yZWdpc3RyeScpO1xuXG5cbnZhciBNTFRleHQgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MVGV4dCcsIHtcbiAgICBkYXRhOiB1bmRlZmluZWQsXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogJ21sLXVpLXRleHQnXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxUZXh0KTtcblxubW9kdWxlLmV4cG9ydHMgPSBNTFRleHQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jX2NsYXNzJylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uL2NfcmVnaXN0cnknKVxuICAgICwgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvXG4gICAgLCBsb2dnZXIgPSBtaWxvQ29yZS51dGlsLmxvZ2dlcjtcblxuXG52YXIgTUxUZXh0YXJlYSA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxUZXh0YXJlYScsIHtcbiAgICBkYXRhOiB1bmRlZmluZWQsXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogJ21sLXVpLXRleHRhcmVhJ1xuICAgIH1cbn0pO1xuXG5jb21wb25lbnRzUmVnaXN0cnkuYWRkKE1MVGV4dGFyZWEpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MVGV4dGFyZWE7XG5cblxudmFyIFNBTVBMRV9BVVRPUkVTSVpFX1RFWFQgPSAnTG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVlciBhZGlwaXNjaW5nIGVsaXQsJztcblxuXG5fLmV4dGVuZFByb3RvKE1MVGV4dGFyZWEsIHtcbiAgICBzdGFydEF1dG9yZXNpemU6IE1MVGV4dGFyZWEkc3RhcnRBdXRvcmVzaXplLFxuICAgIHN0b3BBdXRvcmVzaXplOiBNTFRleHRhcmVhJHN0b3BBdXRvcmVzaXplLFxuICAgIGlzQXV0b3Jlc2l6ZWQ6IE1MVGV4dGFyZWEkaXNBdXRvcmVzaXplZCxcbiAgICBkaXNhYmxlOiBNTFRleHRhcmVhJGRpc2FibGVcbn0pO1xuXG5cbmZ1bmN0aW9uIE1MVGV4dGFyZWEkc3RhcnRBdXRvcmVzaXplKG9wdGlvbnMpIHtcbiAgICBpZiAodGhpcy5fYXV0b3Jlc2l6ZSlcbiAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdNTFRleHRhcmVhIHN0YXJ0QXV0b3Jlc2l6ZTogYXV0b3Jlc2l6ZSBpcyBhbHJlYWR5IG9uJyk7XG4gICAgdGhpcy5fYXV0b3Jlc2l6ZSA9IHRydWU7XG4gICAgdGhpcy5fYXV0b3Jlc2l6ZU9wdGlvbnMgPSBvcHRpb25zO1xuXG4gICAgX2FkanVzdEFyZWFIZWlnaHQuY2FsbCh0aGlzKTtcbiAgICBfbWFuYWdlU3Vic2NyaXB0aW9ucy5jYWxsKHRoaXMsICdvbicpO1xufVxuXG5cbmZ1bmN0aW9uIF9tYW5hZ2VTdWJzY3JpcHRpb25zKG9uT2ZmKSB7XG4gICAgdGhpcy5ldmVudHNbb25PZmZdKCdjbGljaycsIHsgc3Vic2NyaWJlcjogX2FkanVzdEFyZWFIZWlnaHQsIGNvbnRleHQ6IHRoaXMgfSk7XG4gICAgdGhpcy5kYXRhW29uT2ZmXSgnJywgeyBzdWJzY3JpYmVyOiBfYWRqdXN0QXJlYUhlaWdodCwgY29udGV4dDogdGhpcyB9KTtcbn1cblxuXG5mdW5jdGlvbiBfYWRqdXN0QXJlYUhlaWdodCgpIHtcbiAgICB0aGlzLmVsLnN0eWxlLmhlaWdodCA9IDA7XG5cbiAgICB2YXIgbmV3SGVpZ2h0ID0gdGhpcy5lbC5zY3JvbGxIZWlnaHRcbiAgICAgICAgLCBtaW5IZWlnaHQgPSB0aGlzLl9hdXRvcmVzaXplT3B0aW9ucy5taW5IZWlnaHRcbiAgICAgICAgLCBtYXhIZWlnaHQgPSB0aGlzLl9hdXRvcmVzaXplT3B0aW9ucy5tYXhIZWlnaHQ7XG5cbiAgICBuZXdIZWlnaHQgPSBuZXdIZWlnaHQgPj0gbWF4SGVpZ2h0XG4gICAgICAgICAgICAgICAgPyBtYXhIZWlnaHRcbiAgICAgICAgICAgICAgICA6IG5ld0hlaWdodCA8PSBtaW5IZWlnaHRcbiAgICAgICAgICAgICAgICA/IG1pbkhlaWdodFxuICAgICAgICAgICAgICAgIDogbmV3SGVpZ2h0O1xuXG4gICAgdGhpcy5lbC5zdHlsZS5oZWlnaHQgPSBuZXdIZWlnaHQgKyAncHgnO1xufVxuXG5cbmZ1bmN0aW9uIE1MVGV4dGFyZWEkc3RvcEF1dG9yZXNpemUoKSB7XG4gICAgaWYgKCEgdGhpcy5fYXV0b3Jlc2l6ZSlcbiAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdNTFRleHRhcmVhIHN0b3BBdXRvcmVzaXplOiBhdXRvcmVzaXplIGlzIG5vdCBvbicpO1xuICAgIHRoaXMuX2F1dG9yZXNpemUgPSBmYWxzZTtcbiAgICBfbWFuYWdlU3Vic2NyaXB0aW9ucy5jYWxsKHRoaXMsICdvZmYnKTtcbn1cblxuXG5mdW5jdGlvbiBNTFRleHRhcmVhJGlzQXV0b3Jlc2l6ZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2F1dG9yZXNpemU7XG59XG5cblxuZnVuY3Rpb24gTUxUZXh0YXJlYSRkZXN0cm95KCkge1xuICAgIGlmICh0aGlzLl9hdXRvcmVzaXplKVxuICAgICAgICB0aGlzLnN0b3BBdXRvcmVzaXplKCk7XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cbmZ1bmN0aW9uIE1MVGV4dGFyZWEkZGlzYWJsZShkaXNhYmxlKSB7XG4gICAgdGhpcy5lbC5kaXNhYmxlZCA9IGRpc2FibGU7XG59IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5JylcbiAgICAsIF8gPSByZXF1aXJlKCdtaWxvLWNvcmUnKS5wcm90bztcblxuXG52YXIgTUxUaW1lID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTFRpbWUnLCB7XG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZGF0YToge1xuICAgICAgICBnZXQ6IE1MVGltZV9nZXQsXG4gICAgICAgIHNldDogTUxUaW1lX3NldCxcbiAgICAgICAgZGVsOiBNTFRpbWVfZGVsLFxuICAgIH0sXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogJ21sLXVpLXRpbWUnXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxUaW1lKTtcblxubW9kdWxlLmV4cG9ydHMgPSBNTFRpbWU7XG5cblxudmFyIFRJTUVfUkVHRVggPSAvXihbMC05XXsxLDJ9KSg/OlxcOnxcXC4pKFswLTldezEsMn0pJC9cbiAgICAsIFRJTUVfVEVNUExBVEUgPSAnaGg6bW0nO1xuXG5mdW5jdGlvbiBNTFRpbWVfZ2V0KCkge1xuICAgIHZhciB0aW1lU3RyID0gdGhpcy5lbC52YWx1ZTtcbiAgICB2YXIgbWF0Y2ggPSB0aW1lU3RyLm1hdGNoKFRJTUVfUkVHRVgpO1xuICAgIGlmICghIG1hdGNoKSByZXR1cm47XG4gICAgdmFyIGhvdXJzID0gbWF0Y2hbMV1cbiAgICAgICAgLCBtaW5zID0gbWF0Y2hbMl07XG4gICAgaWYgKGhvdXJzID4gMjMgfHwgbWlucyA+IDU5KSByZXR1cm47XG4gICAgdmFyIHRpbWUgPSBuZXcgRGF0ZSgxOTcwLCAwLCAxLCBob3VycywgbWlucyk7XG5cbiAgICByZXR1cm4gXy50b0RhdGUodGltZSk7XG59XG5cblxuZnVuY3Rpb24gTUxUaW1lX3NldCh2YWx1ZSkge1xuICAgIHZhciB0aW1lID0gXy50b0RhdGUodmFsdWUpO1xuICAgIGlmICghIHRpbWUpIHtcbiAgICAgICAgdGhpcy5lbC52YWx1ZSA9ICcnO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIHRpbWVTdHIgPSBUSU1FX1RFTVBMQVRFXG4gICAgICAgICAgICAucmVwbGFjZSgnaGgnLCBwYWQodGltZS5nZXRIb3VycygpKSlcbiAgICAgICAgICAgIC5yZXBsYWNlKCdtbScsIHBhZCh0aW1lLmdldE1pbnV0ZXMoKSkpO1xuXG4gICAgdGhpcy5lbC52YWx1ZSA9IHRpbWVTdHI7XG4gICAgcmV0dXJuIHRpbWVTdHI7XG5cbiAgICBmdW5jdGlvbiBwYWQobikge3JldHVybiBuIDwgMTAgPyAnMCcgKyBuIDogbjsgfVxufVxuXG5cbmZ1bmN0aW9uIE1MVGltZV9kZWwoKSB7XG4gICAgdGhpcy5lbC52YWx1ZSA9ICcnO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29tcG9uZW50ID0gcmVxdWlyZSgnLi4vY19jbGFzcycpXG4gICAgLCBjb21wb25lbnRzUmVnaXN0cnkgPSByZXF1aXJlKCcuLi9jX3JlZ2lzdHJ5Jyk7XG5cblxudmFyIE1MV3JhcHBlciA9IENvbXBvbmVudC5jcmVhdGVDb21wb25lbnRDbGFzcygnTUxXcmFwcGVyJywge1xuICAgIGNvbnRhaW5lcjogdW5kZWZpbmVkLFxuICAgIGRhdGE6IHVuZGVmaW5lZCxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiAnbWwtdWktd3JhcHBlcidcbiAgICB9XG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTFdyYXBwZXIpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1MV3JhcHBlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uLy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vLi4vY19yZWdpc3RyeScpXG4gICAgLCBjb21wb25lbnROYW1lID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9jb21wb25lbnRfbmFtZScpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBsb2dnZXIgPSBtaWxvQ29yZS51dGlsLmxvZ2dlclxuICAgICwgY2hlY2sgPSBtaWxvQ29yZS51dGlsLmNoZWNrXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG87XG5cblxudmFyIEFMRVJUX0NTU19DTEFTU0VTID0ge1xuICAgIHN1Y2Nlc3M6ICdhbGVydC1zdWNjZXNzJyxcbiAgICB3YXJuaW5nOiAnYWxlcnQtd2FybmluZycsXG4gICAgaW5mbzogJ2FsZXJ0LWluZm8nLFxuICAgIGRhbmdlcjogJ2FsZXJ0LWRhbmdlcicsXG4gICAgZml4ZWQ6ICdhbGVydC1maXhlZCdcbn07XG5cblxudmFyIE1MQWxlcnQgPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MQWxlcnQnLCB7XG4gICAgY29udGFpbmVyOiB1bmRlZmluZWQsXG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogWydtbC1icy1hbGVydCcsICdhbGVydCcsICdmYWRlJ10sXG4gICAgICAgIGF0dHJpYnV0ZXM6IHtcbiAgICAgICAgICAgICdyb2xlJzogJ2FsZXJ0JyxcbiAgICAgICAgICAgICdhcmlhLWhpZGRlbic6ICd0cnVlJ1xuICAgICAgICB9XG4gICAgfSxcbiAgICB0ZW1wbGF0ZToge1xuICAgICAgICB0ZW1wbGF0ZTogJ1xcXG4gICAgICAgICAgICB7ez8gaXQuY2xvc2UgfX1cXFxuICAgICAgICAgICAgICAgIDxidXR0b24gbWwtYmluZD1cIltldmVudHNdOmNsb3NlQnRuXCIgdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiY2xvc2VcIiBkYXRhLWRpc21pc3M9XCJhbGVydFwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPiZ0aW1lczs8L2J1dHRvbj5cXFxuICAgICAgICAgICAge3s/fX1cXFxuICAgICAgICAgICAge3s9IGl0Lm1lc3NhZ2V9fSdcbiAgICB9XG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTEFsZXJ0KTtcblxubW9kdWxlLmV4cG9ydHMgPSBNTEFsZXJ0O1xuXG5cbl8uZXh0ZW5kKE1MQWxlcnQsIHtcbiAgICBjcmVhdGVBbGVydDogTUxBbGVydCQkY3JlYXRlQWxlcnQsXG4gICAgb3BlbkFsZXJ0OiBNTEFsZXJ0JCRvcGVuQWxlcnQsXG59KTtcblxuXG5fLmV4dGVuZFByb3RvKE1MQWxlcnQsIHtcbiAgICBvcGVuQWxlcnQ6IE1MQWxlcnQkb3BlbkFsZXJ0LFxuICAgIGNsb3NlQWxlcnQ6IE1MQWxlcnQkY2xvc2VBbGVydFxufSk7XG5cblxuLyoqXG4gKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgbmV3IGFsZXJ0IGluc3RhbmNlLiBUbyBjcmVhdGUgYW5kIG9wZW4gYXQgdGhlIHNhbWUgdGltZSB1c2UgW29wZW5BbGVydF0oI01MQWxlcnQkJG9wZW5BbGVydClcbiAqIGBvcHRpb25zYCBpcyBhbiBvYmplY3Qgd2l0aCB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6XG4gKlxuICogICAgICBtZXNzYWdlOiBzdHJpbmcgYWxlcnQgbWVzc2FnZVxuICogICAgICB0eXBlOiAgICBvcHRpb25hbCBzdHJpbmcgdGhlIHR5cGUgb2YgYWxlcnQgbWVzc2FnZSwgb25lIG9mIHN1Y2Nlc3MsIHdhcm5pbmcsIGluZm8sIGRhbmdlciwgZml4ZWRcbiAqICAgICAgICAgICAgICAgZGVmYXVsdCAnaW5mbydcbiAqICAgICAgY2xvc2U6ICAgb3B0aW9uYWwgZmFsc2UgdG8gcHJldmVudCB1c2VyIGZyb20gY2xvc2luZ1xuICogICAgICAgICAgICAgICBvciB0cnVlIChkZWZhdWx0KSB0byBlbmFibGUgY2xvc2luZyBhbmQgcmVuZGVyIGEgY2xvc2UgYnV0dG9uXG4gKiAgICAgIHRpbWVvdXQ6IG9wdGlvbmFsIHRpbWVyLCBpbiBtaWxsaXNlY29uZHMgdG8gYXV0b21hdGljYWxseSBjbG9zZSB0aGUgYWxlcnRcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBhbGVydCBjb25maWd1cmF0aW9uXG4gKi9cbmZ1bmN0aW9uIE1MQWxlcnQkJGNyZWF0ZUFsZXJ0KG9wdGlvbnMpIHtcbiAgICBjaGVjayhvcHRpb25zLCB7XG4gICAgICAgIG1lc3NhZ2U6IFN0cmluZyxcbiAgICAgICAgdHlwZTogTWF0Y2guT3B0aW9uYWwoU3RyaW5nKSxcbiAgICAgICAgY2xvc2U6IE1hdGNoLk9wdGlvbmFsKEJvb2xlYW4pLFxuICAgICAgICB0aW1lb3V0OiBNYXRjaC5PcHRpb25hbChOdW1iZXIpXG4gICAgfSk7XG5cbiAgICB2YXIgYWxlcnQgPSBNTEFsZXJ0LmNyZWF0ZU9uRWxlbWVudCgpO1xuXG4gICAgb3B0aW9ucyA9IF9wcmVwYXJlT3B0aW9ucyhvcHRpb25zKTtcblxuICAgIHZhciBhbGVydENscyA9IEFMRVJUX0NTU19DTEFTU0VTW29wdGlvbnMudHlwZV07XG4gICAgYWxlcnQuZG9tLmFkZENzc0NsYXNzZXMoYWxlcnRDbHMpO1xuXG4gICAgYWxlcnQuX2FsZXJ0ID0ge1xuICAgICAgICBvcHRpb25zOiBvcHRpb25zLFxuICAgICAgICB2aXNpYmxlOiBmYWxzZVxuICAgIH07XG5cbiAgICBhbGVydC50ZW1wbGF0ZS5yZW5kZXIob3B0aW9ucykuYmluZGVyKCk7XG5cbiAgICB2YXIgYWxlcnRTY29wZSA9IGFsZXJ0LmNvbnRhaW5lci5zY29wZTtcblxuICAgIGlmIChvcHRpb25zLmNsb3NlKVxuICAgICAgICBhbGVydFNjb3BlLmNsb3NlQnRuLmV2ZW50cy5vbignY2xpY2snLFxuICAgICAgICAgICAgeyBzdWJzY3JpYmVyOiBfb25DbG9zZUJ0bkNsaWNrLCBjb250ZXh0OiBhbGVydCB9KTtcblxuICAgIGlmIChvcHRpb25zLnRpbWVvdXQpXG4gICAgICAgIHZhciB0aW1lciA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKXtcbiAgICAgICAgICAgIGlmKGFsZXJ0Ll9hbGVydC52aXNpYmxlKVxuICAgICAgICAgICAgICAgIGFsZXJ0LmNsb3NlQWxlcnQoKTtcbiAgICAgICAgfSwgb3B0aW9ucy50aW1lb3V0KTtcblxuICAgIHJldHVybiBhbGVydDtcbn1cblxuXG4vKipcbiAqIENyZWF0ZSBhbmQgc2hvdyBhbGVydCBwb3B1cFxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIG9iamVjdCB3aXRoIG1lc3NhZ2UsIHR5cGUsIGNsb3NlIGFuZCB0aW1lb3V0XG4gKiBAcmV0dXJuIHtNTEFsZXJ0fSB0aGUgYWxlcnQgaW5zdGFuY2VcbiAqL1xuZnVuY3Rpb24gTUxBbGVydCQkb3BlbkFsZXJ0KG9wdGlvbnMpIHtcbiAgICB2YXIgYWxlcnQgPSBNTEFsZXJ0LmNyZWF0ZUFsZXJ0KG9wdGlvbnMpO1xuICAgIGFsZXJ0Lm9wZW5BbGVydCgpO1xuICAgIHJldHVybiBhbGVydDtcbn1cblxuXG5mdW5jdGlvbiBfb25DbG9zZUJ0bkNsaWNrKHR5cGUsIGV2ZW50KSB7XG4gICAgdGhpcy5jbG9zZUFsZXJ0KCk7XG59XG5cblxuZnVuY3Rpb24gX3ByZXBhcmVPcHRpb25zKG9wdGlvbnMpIHtcbiAgICBvcHRpb25zID0gXy5jbG9uZShvcHRpb25zKTtcbiAgICBvcHRpb25zLmNsb3NlID0gdHlwZW9mIG9wdGlvbnMuY2xvc2UgPT0gJ3VuZGVmaW5lZCcgfHwgb3B0aW9ucy5jbG9zZSA9PT0gdHJ1ZTtcbiAgICBvcHRpb25zLnRpbWVvdXQgPSBNYXRoLmZsb29yKG9wdGlvbnMudGltZW91dCk7XG4gICAgb3B0aW9ucy50eXBlID0gb3B0aW9ucy50eXBlIHx8ICdpbmZvJztcblxuICAgIHJldHVybiBvcHRpb25zO1xufVxuXG5cbi8qKlxuICogT3BlbiB0aGUgYWxlcnRcbiAqL1xuZnVuY3Rpb24gTUxBbGVydCRvcGVuQWxlcnQoKSB7XG4gICAgX3RvZ2dsZUFsZXJ0LmNhbGwodGhpcywgdHJ1ZSk7XG59XG5cblxuLyoqXG4gKiBDbG9zZSB0aGUgYWxlcnRcbiAqL1xuZnVuY3Rpb24gTUxBbGVydCRjbG9zZUFsZXJ0KCkge1xuICAgIF90b2dnbGVBbGVydC5jYWxsKHRoaXMsIGZhbHNlKTtcbiAgICB0aGlzLmRlc3Ryb3koKTtcbn1cblxuXG5mdW5jdGlvbiBfdG9nZ2xlQWxlcnQoZG9TaG93KSB7XG4gICAgZG9TaG93ID0gdHlwZW9mIGRvU2hvdyA9PSAndW5kZWZpbmVkJ1xuICAgICAgICAgICAgICAgID8gISB0aGlzLl9hbGVydC52aXNpYmxlXG4gICAgICAgICAgICAgICAgOiAhISBkb1Nob3c7XG5cbiAgICB2YXIgYWRkUmVtb3ZlID0gZG9TaG93ID8gJ2FkZCcgOiAncmVtb3ZlJ1xuICAgICAgICAsIGFwcGVuZFJlbW92ZSA9IGRvU2hvdyA/ICdhcHBlbmRDaGlsZCcgOiAncmVtb3ZlQ2hpbGQnO1xuXG4gICAgdGhpcy5fYWxlcnQudmlzaWJsZSA9IGRvU2hvdztcblxuICAgIGRvY3VtZW50LmJvZHlbYXBwZW5kUmVtb3ZlXSh0aGlzLmVsKTtcbiAgICB0aGlzLmRvbS50b2dnbGUoZG9TaG93KTtcbiAgICB0aGlzLmVsLnNldEF0dHJpYnV0ZSgnYXJpYS1oaWRkZW4nLCAhZG9TaG93KTtcbiAgICB0aGlzLmVsLmNsYXNzTGlzdFthZGRSZW1vdmVdKCdpbicpO1xuICAgIHRoaXMuZWxbZG9TaG93ID8gJ2ZvY3VzJyA6ICdibHVyJ10oKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uLy4uL2NfY2xhc3MnKVxuICAgICwgY29tcG9uZW50c1JlZ2lzdHJ5ID0gcmVxdWlyZSgnLi4vLi4vY19yZWdpc3RyeScpXG4gICAgLCBjb21wb25lbnROYW1lID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9jb21wb25lbnRfbmFtZScpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBsb2dnZXIgPSBtaWxvQ29yZS51dGlsLmxvZ2dlclxuICAgICwgY2hlY2sgPSBtaWxvQ29yZS51dGlsLmNoZWNrXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG87XG5cblxudmFyIERFRkFVTFRfQlVUVE9OUyA9IFsgeyB0eXBlOiAnZGVmYXVsdCcsIGxhYmVsOiAnT0snLCByZXN1bHQ6ICdPSycgfSBdO1xuXG52YXIgQ0xPU0VfT1BUSU9OUyA9IFsnYmFja2Ryb3AnLCAna2V5Ym9hcmQnLCAnYnV0dG9uJ107XG5cbnZhciBCVVRUT05fQ1NTX0NMQVNTRVMgPSB7IC8vIFRPRE8gLSB1c2UgaW4gdGVtcGxhdGVcbiAgICBkZWZhdWx0OiAnYnRuLWRlZmF1bHQnLFxuICAgIHByaW1hcnk6ICdidG4tcHJpbWFyeScsXG4gICAgc3VjY2VzczogJ2J0bi1zdWNjZXNzJyxcbiAgICBpbmZvOiAnYnRuLWluZm8nLFxuICAgIHdhcm5pbmc6ICdidG4td2FybmluZycsXG4gICAgZGFuZ2VyOiAnYnRuLWRhbmdlcicsXG4gICAgbGluazogJ2J0bi1saW5rJ1xufTtcblxuXG4vKipcbiAqIERpYWxvZyBjbGFzcyB0byBzaG93IGN1c3RvbSBkaWFsb2cgYm94ZXMgYmFzZWQgb24gY29uZmlndXJhdGlvbiAtIHNlZSBbY3JlYXRlRGlhbG9nXSgjTUxEaWFsb2ckJGNyZWF0ZURpYWxvZykgbWV0aG9kLlxuICogT25seSBvbmUgZGlhbG9nIGNhbiBiZSBvcGVuZWQgYXQgYSB0aW1lIC0gdHJ5aW5nIHRvIG9wZW4gYW5vdGhlciB3aWxsIGxvZyBlcnJvciB0byBjb25zb2xlLiBDdXJyZW50bHkgb3BlbmVkIGRpYWxvZyBjYW4gYmUgcmV0cmlldmVkIHVzaW5nIFtnZXRDdXJyZW50RGlhbG9nXSgjTUxEaWFsb2ckJGdldEN1cnJlbnREaWFsb2cpIGNsYXNzIG1ldGhvZC5cbiAqL1xudmFyIE1MRGlhbG9nID0gQ29tcG9uZW50LmNyZWF0ZUNvbXBvbmVudENsYXNzKCdNTERpYWxvZycsIHtcbiAgICBjb250YWluZXI6IHVuZGVmaW5lZCxcbiAgICBldmVudHM6IHVuZGVmaW5lZCxcbiAgICBkb206IHtcbiAgICAgICAgY2xzOiBbJ21sLWJzLWRpYWxvZycsICdtb2RhbCcsICdmYWRlJ10sXG4gICAgICAgIGF0dHJpYnV0ZXM6IHtcbiAgICAgICAgICAgICdyb2xlJzogJ2RpYWxvZycsXG4gICAgICAgICAgICAnYXJpYS1oaWRkZW4nOiAndHJ1ZSdcbiAgICAgICAgfVxuICAgIH0sXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgICAgdGVtcGxhdGU6ICdcXFxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm1vZGFsLWRpYWxvZ1wiPlxcXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm1vZGFsLWNvbnRlbnRcIj5cXFxuICAgICAgICAgICAgICAgICAgICB7ez8gaXQudGl0bGUgfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm1vZGFsLWhlYWRlclwiPlxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge3s/IGl0LmNsb3NlLmJ1dHRvbiB9fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxidXR0b24gbWwtYmluZD1cIltldmVudHNdOmNsb3NlQnRuXCIgdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiY2xvc2VcIj4mdGltZXM7PC9idXR0b24+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7ez99fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGg0IGNsYXNzPVwibW9kYWwtdGl0bGVcIj57ez0gaXQudGl0bGUgfX08L2g0PlxcXG4gICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cXFxuICAgICAgICAgICAgICAgICAgICB7ez99fVxcXG4gICAgICAgICAgICAgICAgICAgIHt7PyBpdC5odG1sIHx8IGl0LnRleHQgfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm1vZGFsLWJvZHlcIiBtbC1iaW5kPVwiW2NvbnRhaW5lcl06ZGlhbG9nQm9keVwiPlxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge3s/IGl0Lmh0bWwgfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7ez0gaXQuaHRtbCB9fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge3s/P319XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHA+e3s9IGl0LnRleHQgfX08L3A+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7ez99fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cXFxuICAgICAgICAgICAgICAgICAgICB7ez99fVxcXG4gICAgICAgICAgICAgICAgICAgIHt7PyBpdC5idXR0b25zICYmIGl0LmJ1dHRvbnMubGVuZ3RoIH19XFxcbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1mb290ZXJcIj5cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7fiBpdC5idXR0b25zIDpidG4gfX1cXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIlxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImJ0biBidG4te3s9IGJ0bi50eXBlIH19e3s/IGJ0bi5jbHMgfX0ge3s9IGJ0bi5jbHMgfX17ez99fVwiXFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1sLWJpbmQ9XCJbZXZlbnRzXTp7ez0gYnRuLm5hbWUgfX1cIj57ez0gYnRuLmxhYmVsIH19PC9idXR0b24+XFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7e359fVxcXG4gICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cXFxuICAgICAgICAgICAgICAgICAgICB7ez99fVxcXG4gICAgICAgICAgICAgICAgPC9kaXY+XFxcbiAgICAgICAgICAgIDwvZGl2PidcbiAgICB9XG59KTtcblxuY29tcG9uZW50c1JlZ2lzdHJ5LmFkZChNTERpYWxvZyk7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxEaWFsb2c7XG5cblxuXy5leHRlbmQoTUxEaWFsb2csIHtcbiAgICBjcmVhdGVEaWFsb2c6IE1MRGlhbG9nJCRjcmVhdGVEaWFsb2csXG4gICAgb3BlbkRpYWxvZzogTUxEaWFsb2ckJG9wZW5EaWFsb2csXG4gICAgZ2V0T3BlbmVkRGlhbG9nOiBNTERpYWxvZyQkZ2V0T3BlbmVkRGlhbG9nXG59KTtcblxuXG5fLmV4dGVuZFByb3RvKE1MRGlhbG9nLCB7XG4gICAgb3BlbkRpYWxvZzogTUxEaWFsb2ckb3BlbkRpYWxvZyxcbiAgICBjbG9zZURpYWxvZzogTUxEaWFsb2ckY2xvc2VEaWFsb2csXG4gICAgZGVzdHJveTogTUxEaWFsb2ckZGVzdHJveVxufSk7XG5cblxuLyoqXG4gKiBDcmVhdGVzIGFuZCByZXR1cm5zIGRpYWxvZyBpbnN0YW5jZS4gVG8gY3JlYXRlIGFuZCBvcGVuIGF0IHRoZSBzYW1lIHRpbWUgW29wZW5EaWFsb2ddKCNNTERpYWxvZyQkb3BlbkRpYWxvZylcbiAqIGBvcHRpb25zYCBpcyBhbiBvYmplY3Qgd2l0aCB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6XG4gKlxuICogICAgIHRpdGxlOiBvcHRpb25hbCBkaWFsb2cgdGl0bGVcbiAqICAgICBodG1sOiBvcHRpb25hbCBkaWFsb2cgdGV4dCBhcyBodG1sICh3aWxsIHRha2UgcHJlY2VkZW5jZSBvdmVyIHRleHQgaWYgYm90aCB0ZXh0IG5kIGh0bWwgYXJlIHBhc3NlZClcbiAqICAgICAgIG9yXG4gKiAgICAgdGV4dDogb3B0aW9uYWwgZGlhbG9nIHRleHRcbiAqICAgICBjbG9zZTogb3B0aW9uYWwgZmFsc2UgdG8gcHJldmVudCBiYWNrZHJvcCBhbmQgZXNjIGtleSBmcm9tIGNsb3NpbmcgdGhlIGRpYWxvZyBhbmQgcmVtb3ZpbmcgY2xvc2UgYnV0dG9uIGluIHRvcCByaWdodCBjb3JuZXJcbiAqICAgICAgICAgICAgb3IgdHJ1ZSAoZGVmYXVsdCkgdG8gZW5hYmxlIGFsbCBjbG9zZSBvcHRpb25zXG4gKiAgICAgICAgICAgIG9yIG9iamVjdCB3aXRoIHByb3BlcnRpZXNcbiAqICAgICAgICAgYmFja2Ryb3A6IGZhbHNlIG9yIHRydWUgKGRlZmF1bHQpLCBjbG9zZSBkaWFsb2cgd2hlbiBiYWNrZHJvcCBjbGlja2VkXG4gKiAgICAgICAgIGtleWJvYXJkOiBmYWxzZSBvciB0cnVlIChkZWZhdWx0KSwgY2xvc2UgZGlhbG9nIHdoZW4gZXNjIGtleSBpcyBwcmVzc2VkXG4gKiAgICAgICAgIGJ1dHRvbjogZmFsc2Ugb3IgdHJ1ZSAoZGVmYXVsdCksIHNob3cgY2xvc2UgYnV0dG9uIGluIHRoZSBoZWFkZXIgKHdvbid0IGJlIHNob3duIGlmIHRoZXJlIGlzIG5vIGhlYWRlciB3aGVuIHRpdGxlIGlzIG5vdCBwYXNzZWQpXG4gKiAgICAgYnV0dG9uczogb3B0aW9uYWwgYXJyYXkgb2YgYnV0dG9ucyBjb25maWd1cmF0aW9ucywgd2hlcmUgZWFjaCBidXR0b24gY29uZmlnIGlzIGFuIG9iamVjdFxuICogICAgICAgICBuYW1lOiAgIG9wdGlvbmFsIG5hbWUgb2YgY29tcG9uZW50LCBzaG91bGQgYmUgdW5pcXVlIGFuZCBzaG91bGQgbm90IGJlIGBjbG9zZUJ0bmAsIGlmIG5vdCBwYXNzZWQgYSB0aW1lc3RhbXAgYmFzZWQgbmFtZSB3aWxsIGJlIHVzZWRcbiAqICAgICAgICAgdHlwZTogICBidXR0b24gdHlwZSwgd2lsbCBkZXRlcm1pbmUgYnV0dG9uIENTUyBzdHlsZS4gUG9zc2libGUgdHlwZXMgYXJlOiBkZWZ1bHQsIHByaW1hcnksIHN1Y2Nlc3MsIGluZm8sIHdhcm5pbmcsIGRhbmdlciwgbGluayAobWFwIHRvIHJlbGF0ZWQgYm9vdHN0cmFwIGJ1dHRvbiBzdHlsZXMpXG4gKiAgICAgICAgIGxhYmVsOiAgYnV0dG9uIGxhYmVsXG4gKiAgICAgICAgIGNsb3NlOiAgb3B0aW9uYWwgZmFsc2UgdG8gcHJldmVudCB0aGlzIGJ1dHRvbiBmcm9tIGNsb3NpbmcgZGlhbG9nXG4gKiAgICAgICAgIHJlc3VsdDogc3RyaW5nIHdpdGggZGlhbG9nIGNsb3NlIHJlc3VsdCB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIGRpYWxvZyBzdWJzY3JpYmVyIGFzIHRoZSBmaXJzdCBwYXJhbWV0ZXJcbiAqICAgICAgICAgZGF0YTogICBhbnkgdmFsdWUvb2JqZWN0IG9yIGZ1bmN0aW9uIHRvIGNyZWF0ZSBkYXRhIHRoYXQgd2lsbCBiZSBwYXNzZWQgdG8gZGlhbG9nIHN1YnNjcmliZXIgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXIuXG4gKiAgICAgICAgICAgICAgICAgSWYgZnVuY3Rpb24gaXMgcGFzc2VkIGl0IHdpbGwgYmUgY2FsbGVkIHdpdGggZGlhbG9nIGFzIGNvbnRleHQgYW5kIGJ1dHRvbiBvcHRpb25zIGFzIHBhcmFtZXRlci5cbiAqXG4gKiAgICAgSWYgYHRpdGxlYCBpcyBub3QgcGFzc2VkLCBkaWFsb2cgd2lsbCBub3QgaGF2ZSB0aXRsZSBzZWN0aW9uICAgXG4gKiAgICAgSWYgbmVpdGhlciBgdGV4dGAgbm9yIGBodG1sYCBpcyBwYXNzZWQsIGRpYWxvZyB3aWxsIG5vdCBoYXZlIGJvZHkgc2VjdGlvbi5cbiAqICAgICBJZiBgYnV0dG9uc2AgYXJlIG5vdCBwYXNzZWQsIHRoZXJlIHdpbGwgb25seSBiZSBPSyBidXR0b24uXG4gKlxuICogV2hlbiBkaWFsb2cgaXMgY2xvc2VkLCB0aGUgc3Vic2NyaWJlciBpcyBjYWxsZWQgd2l0aCByZWF1bHQgYW5kIG9wdGlvbmFsIGRhdGEgYXMgZGVmaW5lZCBpbiBidXR0b25zIGNvbmZpZ3VyYXRpb25zLlxuICogSWYgYmFja2Ryb3AgaXMgY2xpY2tlZCBvciBFU0Mga2V5IGlzIHByZXNzZWQgdGhlIHJlc3VsdCB3aWxsIGJlICdkaXNtaXNzZWQnXG4gKiBJZiBjbG9zZSBidXR0b24gaW4gdGhlIHRvcCByaWdodCBjb3JuZXIgaXMgY2xpY2tlZCwgdGhlIHJlc3VsdCB3aWxsIGJlICdjbG9zZWQnIChkZWZhdWx0IHJlc3VsdClcbiAqIFxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgZGlhbG9nIGNvbmZpZ3VyYXRpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGluaXRpYWxpemUgZnVuY3Rpb24gdGhhdCBpcyBjYWxsZWQgdG8gaW5pdGlhbGl6ZSB0aGUgZGlhbG9nXG4gKi9cbmZ1bmN0aW9uIE1MRGlhbG9nJCRjcmVhdGVEaWFsb2cob3B0aW9ucywgaW5pdGlhbGl6ZSkge1xuICAgIGNoZWNrKG9wdGlvbnMsIHtcbiAgICAgICAgdGl0bGU6IE1hdGNoLk9wdGlvbmFsKFN0cmluZyksXG4gICAgICAgIGh0bWw6IE1hdGNoLk9wdGlvbmFsKFN0cmluZyksXG4gICAgICAgIHRleHQ6IE1hdGNoLk9wdGlvbmFsKFN0cmluZyksXG4gICAgICAgIGNsb3NlOiBNYXRjaC5PcHRpb25hbChNYXRjaC5PbmVPZihCb29sZWFuLCB7XG4gICAgICAgICAgICBiYWNrZHJvcDogTWF0Y2guT3B0aW9uYWwoQm9vbGVhbiksXG4gICAgICAgICAgICBrZXlib2FyZDogTWF0Y2guT3B0aW9uYWwoQm9vbGVhbiksXG4gICAgICAgICAgICBidXR0b246IE1hdGNoLk9wdGlvbmFsKEJvb2xlYW4pXG4gICAgICAgIH0pKSxcbiAgICAgICAgYnV0dG9uczogTWF0Y2guT3B0aW9uYWwoWyB7XG4gICAgICAgICAgICBuYW1lOiBNYXRjaC5PcHRpb25hbChTdHJpbmcpLFxuICAgICAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgICAgICAgbGFiZWw6IFN0cmluZyxcbiAgICAgICAgICAgIGNsb3NlOiBNYXRjaC5PcHRpb25hbChCb29sZWFuKSxcbiAgICAgICAgICAgIHJlc3VsdDogTWF0Y2guT3B0aW9uYWwoU3RyaW5nKSxcbiAgICAgICAgICAgIGRhdGE6IE1hdGNoLk9wdGlvbmFsKE1hdGNoLkFueSksXG4gICAgICAgICAgICBjbHM6IE1hdGNoLk9wdGlvbmFsKFN0cmluZylcbiAgICAgICAgfSBdKVxuICAgIH0pO1xuXG4gICAgdmFyIGRpYWxvZyA9IE1MRGlhbG9nLmNyZWF0ZU9uRWxlbWVudCgpO1xuXG4gICAgb3B0aW9ucyA9IF9wcmVwYXJlT3B0aW9ucyhvcHRpb25zKTtcbiAgICBkaWFsb2cuX2RpYWxvZyA9IHtcbiAgICAgICAgb3B0aW9uczogb3B0aW9ucyxcbiAgICAgICAgdmlzaWJsZTogZmFsc2VcbiAgICB9O1xuXG4gICAgZGlhbG9nLnRlbXBsYXRlXG4gICAgICAgIC5yZW5kZXIob3B0aW9ucylcbiAgICAgICAgLmJpbmRlcigpO1xuXG4gICAgdmFyIGRpYWxvZ1Njb3BlID0gZGlhbG9nLmNvbnRhaW5lci5zY29wZTtcblxuICAgIGlmIChvcHRpb25zLmNsb3NlLmJhY2tkcm9wKVxuICAgICAgICBkaWFsb2cuZXZlbnRzLm9uKCdjbGljaycsXG4gICAgICAgICAgICB7IHN1YnNjcmliZXI6IF9vbkJhY2tkcm9wQ2xpY2ssIGNvbnRleHQ6IGRpYWxvZyB9KTtcblxuICAgIGlmIChvcHRpb25zLnRpdGxlICYmIG9wdGlvbnMuY2xvc2UuYnV0dG9uKVxuICAgICAgICBkaWFsb2dTY29wZS5jbG9zZUJ0bi5ldmVudHMub24oJ2NsaWNrJyxcbiAgICAgICAgICAgIHsgc3Vic2NyaWJlcjogX29uQ2xvc2VCdG5DbGljaywgY29udGV4dDogZGlhbG9nIH0pO1xuXG4gICAgb3B0aW9ucy5idXR0b25zLmZvckVhY2goZnVuY3Rpb24oYnRuKSB7XG4gICAgICAgIHZhciBidXR0b25TdWJzY3JpYmVyID0ge1xuICAgICAgICAgICAgc3Vic2NyaWJlcjogXy5wYXJ0aWFsKF9kaWFsb2dCdXR0b25DbGljaywgYnRuKSxcbiAgICAgICAgICAgIGNvbnRleHQ6IGRpYWxvZ1xuICAgICAgICB9O1xuICAgICAgICBkaWFsb2dTY29wZVtidG4ubmFtZV0uZXZlbnRzLm9uKCdjbGljaycsIGJ1dHRvblN1YnNjcmliZXIpO1xuICAgIH0pO1xuXG4gICAgaWYgKGluaXRpYWxpemUpIGluaXRpYWxpemUoZGlhbG9nKTtcbiAgICByZXR1cm4gZGlhbG9nO1xufVxuXG5cbmZ1bmN0aW9uIF9kaWFsb2dCdXR0b25DbGljayhidXR0b24pIHtcbiAgICBpZiAoYnV0dG9uLmNsb3NlICE9PSBmYWxzZSlcbiAgICAgICAgX3RvZ2dsZURpYWxvZy5jYWxsKHRoaXMsIGZhbHNlKTtcblxuICAgIHZhciBkYXRhID0gXy5yZXN1bHQoYnV0dG9uLmRhdGEsIHRoaXMsIGJ1dHRvbik7XG4gICAgX2Rpc3BhdGNoUmVzdWx0LmNhbGwodGhpcywgYnV0dG9uLnJlc3VsdCwgZGF0YSk7XG59XG5cblxuZnVuY3Rpb24gX2Rpc3BhdGNoUmVzdWx0KHJlc3VsdCwgZGF0YSkge1xuICAgIHZhciBzdWJzY3JpYmVyID0gdGhpcy5fZGlhbG9nLnN1YnNjcmliZXI7XG4gICAgaWYgKHR5cGVvZiBzdWJzY3JpYmVyID09ICdmdW5jdGlvbicpXG4gICAgICAgIHN1YnNjcmliZXIuY2FsbCh0aGlzLCByZXN1bHQsIGRhdGEpO1xuICAgIGVsc2VcbiAgICAgICAgc3Vic2NyaWJlci5zdWJzY3JpYmVyLmNhbGwoc3Vic2NyaWJlci5jb250ZXh0LCByZXN1bHQsIGRhdGEpO1xufVxuXG5cbmZ1bmN0aW9uIF9vbkJhY2tkcm9wQ2xpY2soZXZlbnRUeXBlLCBldmVudCkge1xuICAgIGlmIChldmVudC50YXJnZXQgPT0gdGhpcy5lbClcbiAgICAgICAgdGhpcy5jbG9zZURpYWxvZygnZGlzbWlzc2VkJyk7XG59XG5cblxuZnVuY3Rpb24gX29uQ2xvc2VCdG5DbGljaygpIHtcbiAgICB0aGlzLmNsb3NlRGlhbG9nKCdjbG9zZWQnKTtcbn1cblxuXG5mdW5jdGlvbiBfb25LZXlEb3duKGV2ZW50KSB7XG4gICAgaWYgKG9wZW5lZERpYWxvZ1xuICAgICAgICAgICAgJiYgb3BlbmVkRGlhbG9nLl9kaWFsb2cub3B0aW9ucy5jbG9zZS5rZXlib2FyZFxuICAgICAgICAgICAgJiYgZXZlbnQua2V5Q29kZSA9PSAyNykgLy8gZXNjIGtleVxuICAgICAgICBvcGVuZWREaWFsb2cuY2xvc2VEaWFsb2coJ2Rpc21pc3NlZCcpO1xufVxuXG5cbmZ1bmN0aW9uIF9wcmVwYXJlT3B0aW9ucyhvcHRpb25zKSB7XG4gICAgb3B0aW9ucyA9IF8uY2xvbmUob3B0aW9ucyk7XG4gICAgb3B0aW9ucy5idXR0b25zID0gXy5jbG9uZShvcHRpb25zLmJ1dHRvbnMgfHwgREVGQVVMVF9CVVRUT05TKTtcbiAgICBvcHRpb25zLmJ1dHRvbnMuZm9yRWFjaChmdW5jdGlvbihidG4pIHtcbiAgICAgICAgYnRuLm5hbWUgPSBidG4ubmFtZSB8fCBjb21wb25lbnROYW1lKCk7XG4gICAgfSk7XG5cbiAgICBvcHRpb25zLmNsb3NlID0gdHlwZW9mIG9wdGlvbnMuY2xvc2UgPT0gJ3VuZGVmaW5lZCcgfHwgb3B0aW9ucy5jbG9zZSA9PT0gdHJ1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBfLm9iamVjdChDTE9TRV9PUFRJT05TLCB0cnVlKVxuICAgICAgICAgICAgICAgICAgICAgICAgOiB0eXBlb2Ygb3B0aW9ucy5jbG9zZSA9PSAnb2JqZWN0J1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gXy5tYXBUb09iamVjdChDTE9TRV9PUFRJT05TLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihvcHQpIHsgcmV0dXJuIG9wdGlvbnMuY2xvc2Vbb3B0XSAhPT0gZmFsc2U7IH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgOiBfLm9iamVjdChDTE9TRV9PUFRJT05TLCBmYWxzZSk7XG5cbiAgICByZXR1cm4gb3B0aW9ucztcbn1cblxuXG4vKipcbiAqIENyZWF0ZSBhbmQgc2hvdyBkaWFsb2cgcG9wdXBcbiAqIFxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgb2JqZWN0IHdpdGggdGl0bGUsIHRleHQgYW5kIGJ1dHRvbnMuIFNlZSBbY3JlYXRlRGlhbG9nXSgjTUxEaWFsb2ckJGNyZWF0ZURpYWxvZykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdH0gc3Vic2NyaWJlciBvcHRpb25hbCBzdWJzY3JpYmVyIGZ1bmN0aW9uIG9yIG9iamVjdCB0aGF0IGlzIHBhc3NlZCByZXN1bHQgYW5kIG9wdGlvbmFsIGRhdGEuIFVubGVzcyBjb250ZXh0IGlzIGRlZmluZWQsIGRpYWxvZyB3aWxsIGJlIHRoZSBjb250ZXh0LlxuICovXG5mdW5jdGlvbiBNTERpYWxvZyQkb3BlbkRpYWxvZyhvcHRpb25zLCBzdWJzY3JpYmVyLCBpbml0aWFsaXplKSB7XG4gICAgdmFyIGRpYWxvZyA9IE1MRGlhbG9nLmNyZWF0ZURpYWxvZyhvcHRpb25zLCBpbml0aWFsaXplKTtcbiAgICBkaWFsb2cub3BlbkRpYWxvZyhzdWJzY3JpYmVyKTtcbiAgICByZXR1cm4gZGlhbG9nO1xufVxuXG5cblxuZnVuY3Rpb24gX3RvZ2dsZURpYWxvZyhkb1Nob3cpIHtcbiAgICBkb1Nob3cgPSB0eXBlb2YgZG9TaG93ID09ICd1bmRlZmluZWQnXG4gICAgICAgICAgICAgICAgPyAhIHRoaXMuX2RpYWxvZy52aXNpYmxlXG4gICAgICAgICAgICAgICAgOiAhISBkb1Nob3c7XG5cbiAgICB2YXIgYWRkUmVtb3ZlID0gZG9TaG93ID8gJ2FkZCcgOiAncmVtb3ZlJ1xuICAgICAgICAsIGFwcGVuZFJlbW92ZSA9IGRvU2hvdyA/ICdhcHBlbmRDaGlsZCcgOiAncmVtb3ZlQ2hpbGQnO1xuXG4gICAgdGhpcy5fZGlhbG9nLnZpc2libGUgPSBkb1Nob3c7XG5cbiAgICBpZiAoZG9TaG93ICYmICEgZGlhbG9nc0luaXRpYWxpemVkKVxuICAgICAgICBfaW5pdGlhbGl6ZURpYWxvZ3MoKTtcblxuICAgIGRvY3VtZW50LmJvZHlbYXBwZW5kUmVtb3ZlXSh0aGlzLmVsKTtcbiAgICBpZiAoYmFja2Ryb3BFbClcbiAgICAgICAgZG9jdW1lbnQuYm9keVthcHBlbmRSZW1vdmVdKGJhY2tkcm9wRWwpO1xuICAgIHRoaXMuZG9tLnRvZ2dsZShkb1Nob3cpO1xuICAgIHRoaXMuZWwuc2V0QXR0cmlidXRlKCdhcmlhLWhpZGRlbicsICFkb1Nob3cpO1xuICAgIGRvY3VtZW50LmJvZHkuY2xhc3NMaXN0W2FkZFJlbW92ZV0oJ21vZGFsLW9wZW4nKTtcbiAgICB0aGlzLmVsLmNsYXNzTGlzdFthZGRSZW1vdmVdKCdpbicpO1xuXG4gICAgb3BlbmVkRGlhbG9nID0gZG9TaG93ID8gdGhpcyA6IHVuZGVmaW5lZDtcbiAgICB0aGlzLmVsW2RvU2hvdyA/ICdmb2N1cycgOiAnYmx1ciddKCk7XG59XG5cblxudmFyIGRpYWxvZ3NJbml0aWFsaXplZCwgYmFja2Ryb3BFbDtcblxuZnVuY3Rpb24gX2luaXRpYWxpemVEaWFsb2dzKCkge1xuICAgIGJhY2tkcm9wRWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBiYWNrZHJvcEVsLmNsYXNzTmFtZSA9ICdtb2RhbC1iYWNrZHJvcCBmYWRlIGluJztcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgX29uS2V5RG93bik7XG4gICAgZGlhbG9nc0luaXRpYWxpemVkID0gdHJ1ZTtcbn1cblxuXG52YXIgb3BlbmVkRGlhbG9nO1xuXG4vKipcbiAqIE9wZW5zIGRpYWxvZyBpbnN0YW5jZS5cbiAqIFN1YnNjcmliZXIgb2JqZWN0IHNob3VsZCBoYXZlIHRoZSBzYW1lIGZvcm1hdCBhcyB0aGUgc3Vic2NyaWJlciBmb3IgdGhlIE1lc3NlbmdlciAoYWx0aG91Z2ggTWVzc2VuZ2VyIGlzIG5vdCB1c2VkKSAtIGVpdGhlciBmdW5jdGlvbiBvciBvYmplY3Qgd2l0aCBzdWJzY3JpYmVyIGFuZCBjb250ZXh0IHByb3BlcnRpZXMuXG4gKiBcbiAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fSBzdWJzY3JpYmVyIHN1YnNjcmliZXIgb2JqZWN0XG4gKi9cbmZ1bmN0aW9uIE1MRGlhbG9nJG9wZW5EaWFsb2coc3Vic2NyaWJlcikge1xuICAgIGNoZWNrKHN1YnNjcmliZXIsIE1hdGNoLk9uZU9mKEZ1bmN0aW9uLCB7IHN1YnNjcmliZXI6IEZ1bmN0aW9uLCBjb250ZXh0OiBNYXRjaC5BbnkgfSkpO1xuXG4gICAgaWYgKG9wZW5lZERpYWxvZylcbiAgICAgICAgcmV0dXJuIGxvZ2dlci53YXJuKCdNTERpYWxvZyBvcGVuRGlhbG9nOiBjYW5cXCd0IG9wZW4gZGlhbG9nLCBhbm90aGVyIGRpYWxvZyBpcyBhbHJlYWR5IG9wZW4nKTtcblxuICAgIHRoaXMuX2RpYWxvZy5zdWJzY3JpYmVyID0gc3Vic2NyaWJlcjtcbiAgICBfdG9nZ2xlRGlhbG9nLmNhbGwodGhpcywgdHJ1ZSk7XG59XG5cblxuLyoqXG4gKiBDbG9zZXMgZGlhbG9nIGluc3RhbmNlLCBvcHRpb25hbGx5IHBhc3NpbmcgcmVzdWx0IGFuZCBkYXRhIHRvIGRpYWxvZyBzdWJzY3JpYmVyLlxuICogSWYgbm8gcmVzdWx0IGlzIHBhc3NlZCwgJ2Nsb3NlZCcgd2lsbCBiZSBwYXNzZWQgdG8gc3Vic2NyaWJlci5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gcmVzdWx0IGRpYWxvZyByZXN1bHQsIHBhc3NlZCBhcyB0aGUgZmlyc3QgcGFyYW1ldGVyIHRvIHN1YmNzcmliZXJcbiAqIEBwYXJhbSB7QW55fSBkYXRhIG9wdGlvbmFsIGRpYWxvZyBkYXRhLCBwYXNzZWQgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXIgdG8gc3Vic2NyaWJlclxuICovXG5mdW5jdGlvbiBNTERpYWxvZyRjbG9zZURpYWxvZyhyZXN1bHQsIGRhdGEpIHtcbiAgICBpZiAoISBvcGVuZWREaWFsb2cpXG4gICAgICAgIHJldHVybiBsb2dnZXIud2FybignTUxEaWFsb2cgY2xvc2VEaWFsb2c6IGNhblxcJ3QgY2xvc2UgZGlhbG9nLCBubyBkaWFsb2cgb3BlbicpO1xuXG4gICAgcmVzdWx0ID0gcmVzdWx0IHx8ICdjbG9zZWQnO1xuXG4gICAgX3RvZ2dsZURpYWxvZy5jYWxsKHRoaXMsIGZhbHNlKTtcbiAgICBfZGlzcGF0Y2hSZXN1bHQuY2FsbCh0aGlzLCByZXN1bHQsIGRhdGEpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBjdXJyZW50bHkgb3BlbmVkIGRpYWxvZ1xuICpcbiAqIEByZXR1cm4ge01MRGlhbG9nfVxuICovXG5mdW5jdGlvbiBNTERpYWxvZyQkZ2V0T3BlbmVkRGlhbG9nKCkge1xuICAgIHJldHVybiBvcGVuZWREaWFsb2c7XG59XG5cblxuZnVuY3Rpb24gTUxEaWFsb2ckZGVzdHJveSgpIHtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdrZXlkb3duJywgX29uS2V5RG93bik7XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi8uLi9jX2NsYXNzJylcbiAgICAsIGNvbXBvbmVudHNSZWdpc3RyeSA9IHJlcXVpcmUoJy4uLy4uL2NfcmVnaXN0cnknKVxuICAgICwgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvXG4gICAgLCBsb2dnZXIgPSBtaWxvQ29yZS51dGlsLmxvZ2dlclxuICAgICwgRE9NTGlzdGVuZXJzID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbC9kb21fbGlzdGVuZXJzJyk7XG5cblxudmFyIFRPR0dMRV9DU1NfQ0xBU1MgPSAnZHJvcGRvd24tdG9nZ2xlJ1xuICAgICwgTUVOVV9DU1NfQ0xBU1MgPSAnZHJvcGRvd24tbWVudSc7XG5cblxudmFyIE1MRHJvcGRvd24gPSBDb21wb25lbnQuY3JlYXRlQ29tcG9uZW50Q2xhc3MoJ01MRHJvcGRvd24nLCB7XG4gICAgZXZlbnRzOiB1bmRlZmluZWQsXG4gICAgZG9tOiB7XG4gICAgICAgIGNsczogWydtbC1icy1kcm9wZG93bicsICdkcm9wZG93biddXG4gICAgfVxufSk7XG5cbmNvbXBvbmVudHNSZWdpc3RyeS5hZGQoTUxEcm9wZG93bik7XG5cbm1vZHVsZS5leHBvcnRzID0gTUxEcm9wZG93bjtcblxuXG5fLmV4dGVuZFByb3RvKE1MRHJvcGRvd24sIHtcbiAgICBzdGFydDogTUxEcm9wZG93biRzdGFydCxcbiAgICBkZXN0cm95OiBNTERyb3Bkb3duJGRlc3Ryb3ksXG4gICAgdG9nZ2xlTWVudTogTUxEcm9wZG93biR0b2dnbGVNZW51LFxuICAgIHNob3dNZW51OiBNTERyb3Bkb3duJHNob3dNZW51LFxuICAgIGhpZGVNZW51OiBNTERyb3Bkb3duJGhpZGVNZW51XG59KTtcblxuXG5mdW5jdGlvbiBNTERyb3Bkb3duJHN0YXJ0KCkge1xuICAgIHZhciB0b2dnbGVFbCA9IHRoaXMuZWwucXVlcnlTZWxlY3RvcignLicgKyBUT0dHTEVfQ1NTX0NMQVNTKVxuICAgICAgICAsIG1lbnVFbCA9IHRoaXMuZWwucXVlcnlTZWxlY3RvcignLicgKyBNRU5VX0NTU19DTEFTUyk7XG5cbiAgICBpZiAoISAodG9nZ2xlRWwgJiYgbWVudUVsKSlcbiAgICAgICAgcmV0dXJuIGxvZ2dlci5lcnJvcignTUxEcm9wZG93bjonLCBUT0dHTEVfQ1NTX0NMQVNTLCAnb3InLCBNRU5VX0NTU19DTEFTUywgJ2lzblxcJ3QgZm91bmQnKTtcblxuICAgIHZhciBkb2MgPSB3aW5kb3cuZG9jdW1lbnRcbiAgICAgICAgLCBjbGlja0hhbmRsZXIgPSB0aGlzLnRvZ2dsZU1lbnUuYmluZCh0aGlzLCB1bmRlZmluZWQpO1xuXG4gICAgdmFyIGxpc3RlbmVycyA9IG5ldyBET01MaXN0ZW5lcnM7XG4gICAgdGhpcy5fZHJvcGRvd24gPSB7XG4gICAgICAgIG1lbnU6IG1lbnVFbCxcbiAgICAgICAgdmlzaWJsZTogZmFsc2UsXG4gICAgICAgIGxpc3RlbmVyczogbGlzdGVuZXJzXG4gICAgfTtcbiAgICB0aGlzLmhpZGVNZW51KCk7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgbGlzdGVuZXJzLmFkZCh0b2dnbGVFbCwgJ2NsaWNrJywgY2xpY2tIYW5kbGVyKTtcbiAgICAvL21heWJlIG9ubHkgYWRkIHRoaXMgZXZlbnRzIGlmIGlzIG9wZW4/XG4gICAgbGlzdGVuZXJzLmFkZChkb2MsICdtb3VzZW91dCcsIG9uRG9jT3V0KTtcbiAgICBsaXN0ZW5lcnMuYWRkKGRvYywgJ2NsaWNrJywgb25DbGljayk7XG5cblxuICAgIGZ1bmN0aW9uIG9uRG9jT3V0KGV2ZW50KSB7XG4gICAgICAgIHZhciB0YXJnZXQgPSBldmVudC50YXJnZXRcbiAgICAgICAgICAgICwgcmVsYXRlZFRhcmdldCA9IGV2ZW50LnJlbGF0ZWRUYXJnZXRcbiAgICAgICAgICAgICwgbGlzdGVuZXJzID0gc2VsZi5fZHJvcGRvd24ubGlzdGVuZXJzO1xuXG4gICAgICAgIGlmIChpc0lmcmFtZSh0YXJnZXQpKVxuICAgICAgICAgICAgbGlzdGVuZXJzLnJlbW92ZSh0YXJnZXQuY29udGVudFdpbmRvdy5kb2N1bWVudCwgJ2NsaWNrJywgb25DbGljayk7XG5cbiAgICAgICAgaWYgKGlzSWZyYW1lKHJlbGF0ZWRUYXJnZXQpKVxuICAgICAgICAgICAgbGlzdGVuZXJzLmFkZChyZWxhdGVkVGFyZ2V0LmNvbnRlbnRXaW5kb3cuZG9jdW1lbnQsICdjbGljaycsIG9uQ2xpY2spO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG9uQ2xpY2soZXZlbnQpIHtcbiAgICAgICAgaWYgKCFzZWxmLmVsLmNvbnRhaW5zKGV2ZW50LnRhcmdldCkpXG4gICAgICAgICAgICBzZWxmLmhpZGVNZW51KCk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIGlzSWZyYW1lKGVsKSB7XG4gICAgcmV0dXJuIGVsICYmIGVsLnRhZ05hbWUgPT0gJ0lGUkFNRSc7XG59XG5cblxuZnVuY3Rpb24gTUxEcm9wZG93biRkZXN0cm95KCkge1xuICAgIHRoaXMuX2Ryb3Bkb3duLmxpc3RlbmVycy5yZW1vdmVBbGwoKTtcbiAgICBkZWxldGUgdGhpcy5fZHJvcGRvd247XG4gICAgQ29tcG9uZW50LnByb3RvdHlwZS5kZXN0cm95LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuZnVuY3Rpb24gTUxEcm9wZG93biRzaG93TWVudSgpIHtcbiAgICB0aGlzLnRvZ2dsZU1lbnUodHJ1ZSk7XG59XG5cblxuZnVuY3Rpb24gTUxEcm9wZG93biRoaWRlTWVudSgpIHtcbiAgICB0aGlzLnRvZ2dsZU1lbnUoZmFsc2UpO1xufVxuXG5cbmZ1bmN0aW9uIE1MRHJvcGRvd24kdG9nZ2xlTWVudShkb1Nob3cpIHtcbiAgICBkb1Nob3cgPSB0eXBlb2YgZG9TaG93ID09ICd1bmRlZmluZWQnXG4gICAgICAgICAgICAgICAgPyAhIHRoaXMuX2Ryb3Bkb3duLnZpc2libGVcbiAgICAgICAgICAgICAgICA6ICEhIGRvU2hvdztcblxuICAgIHRoaXMuX2Ryb3Bkb3duLnZpc2libGUgPSBkb1Nob3c7XG5cbiAgICB2YXIgbWVudSA9IHRoaXMuX2Ryb3Bkb3duLm1lbnU7XG4gICAgbWVudS5zdHlsZS5kaXNwbGF5ID0gZG9TaG93XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyAnYmxvY2snXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgOiAnbm9uZSc7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxuLy8gPGEgbmFtZT1cImNvbmZpZ1wiPjwvYT5cbi8vIG1pbG8uY29uZmlnXG4vLyAtLS0tLS0tLS0tLVxuXG4vLyBJdCBpcyB0aGUgZnVuY3Rpb24gdGhhdCBhbGxvd3MgdG8gY2hhbmdlIG1pbG8gY29uZmlndXJhdGlvbnMgYW5kIGFsc29cbi8vIGFjY2VzcyB0aGVtIG9uIGNvbmZpZydzIHByb3BlcnRpZXMuXG5cbi8vIGBgYGphdmFzY3JpcHRcbi8vIG1pbG8uY29uZmlnKHtcbi8vICAgICBhdHRyczoge1xuLy8gICAgICAgICBiaW5kOiAnbWwtYmluZCcsXG4vLyAgICAgICAgIGxvYWQ6ICdtbC1sb2FkJ1xuLy8gICAgIH1cbi8vIH0pO1xuLy8gYGBgXG5cblxudmFyIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgZG9UID0gbWlsb0NvcmUudXRpbC5kb1Q7XG5cblxudmFyIGNvbmZpZyA9IG1vZHVsZS5leHBvcnRzID0gbWlsb0NvcmUuY29uZmlnO1xuXG5cbmNvbmZpZyh7XG4gICAgYXR0cnM6IHtcbiAgICAgICAgYmluZDogJ21sLWJpbmQnLFxuICAgICAgICBsb2FkOiAnbWwtbG9hZCdcbiAgICB9LFxuICAgIGNvbXBvbmVudFJlZjogJ19fX21pbG9fY29tcG9uZW50JyxcbiAgICBjb21wb25lbnRQcmVmaXg6ICdtaWxvXycsXG4gICAgdGVtcGxhdGU6IHtcbiAgICAgICAgY29tcGlsZTogZG9ULmNvbXBpbGVcbiAgICB9LFxuICAgIGRvbVN0b3JhZ2U6IHtcbiAgICAgICAgdHlwZVN1ZmZpeDogJzpfX19taWxvX2RhdGFfdHlwZScsXG4gICAgICAgIHByZWZpeFNlcGFyYXRvcjogJy8nLFxuICAgICAgICByb290OiAnJyxcbiAgICAgICAgbWVzc2FnZUtleTogJ19fX21pbG9fbWVzc2FnZS8nLFxuICAgICAgICBtZXNzYWdlVGltZXN0YW1wOiAnX19fbWlsb190aW1lc3RhbXAnLFxuICAgICAgICBxdW90YUV4Y2VlZGVkOiB7XG4gICAgICAgICAgICB0aHJvd0Vycm9yOiB0cnVlLFxuICAgICAgICAgICAgbWVzc2FnZTogZmFsc2VcbiAgICAgICAgfVxuICAgIH0sXG4gICAgZHJhZ0Ryb3A6IHtcbiAgICAgICAgZGF0YVR5cGVzOiB7XG4gICAgICAgICAgICBjb21wb25lbnQ6ICd4LWFwcGxpY2F0aW9uL21pbG8vY29tcG9uZW50JyxcbiAgICAgICAgICAgIGNvbXBvbmVudE1ldGFUZW1wbGF0ZTogJ3gtYXBwbGljYXRpb24vbWlsby9jb21wb25lbnQtbWV0YS8lY2xhc3MvJW5hbWUvJXBhcmFtcycsXG4gICAgICAgICAgICBjb21wb25lbnRNZXRhUmVnZXg6IC9eeFxcLWFwcGxpY2F0aW9uXFwvbWlsb1xcL2NvbXBvbmVudFxcLW1ldGFcXC8oW2EtejAtOV0rKVxcLyhbYS16MC05XSspXFwvKFthLXowLTldKikkLyxcbiAgICAgICAgfVxuICAgIH0sXG4gICAgcmVxdWVzdDoge1xuICAgICAgICBqc29ucFRpbWVvdXQ6IDYwMDAwLFxuICAgICAgICBqc29ucENhbGxiYWNrUHJlZml4OiAnX19fbWlsb19jYWxsYmFja18nLFxuICAgICAgICBvcHRpb25zS2V5OiAnX19fbWlsb19vcHRpb25zJyxcbiAgICAgICAgZGVmYXVsdHM6IHtcbiAgICAgICAgICAgIHRpbWVvdXQ6IDYwMDAwXG4gICAgICAgIH1cbiAgICB9LFxuICAgIHdlYnNvY2tldDoge1xuICAgICAgICBycGM6IHtcbiAgICAgICAgICAgIHRpbWVvdXQ6IDE1MDAwLFxuICAgICAgICAgICAgcmVzcG9uc2VQcmVmaXg6ICdyZXNwb25zZV8nXG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgbWlsb01haWwgPSByZXF1aXJlKCcuL3NlcnZpY2VzL21haWwnKVxuICAgICwgcmVxdWVzdCA9IHJlcXVpcmUoJy4vdXRpbC9yZXF1ZXN0JylcbiAgICAsIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIGxvZ2dlciA9IG1pbG9Db3JlLnV0aWwubG9nZ2VyXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIHV0aWxEb20gPSByZXF1aXJlKCcuL3V0aWwvZG9tJylcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4vY29uZmlnJylcbiAgICAsIExvYWRBdHRyaWJ1dGUgPSByZXF1aXJlKCcuL2F0dHJpYnV0ZXMvYV9sb2FkJyk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBsb2FkZXI7XG5cbi8qKlxuICogYG1pbG8ubG9hZGVyYFxuICogXG4gKiBSZWN1cnNpdmVseSBzY2FucyB0aGUgZG9jdW1lbnQgdHJlZSBpbnNpZGUgYHJvb3RFbGAgKGRvY3VtZW50LmJvZHkgYnkgZGVmYXVsdCkgbG9va2luZyBmb3IgX19tbC1sb2FkX18gQGF0dHJpYnV0ZS5cbiAqIE9uZSBsZXZlbCBsb2FkIGlzIGV4ZWN1dGVkLiBObyBhZGRpdGlvbmFsIGxvYWRlciBnZXQgY2FsbGVkIG9uIGluc2lkZSBfX21sLWxvYWRfXyBhdHRyaWJ1dGVzLiBcbiAqXG4gKiBQb3NzaWJsZSB1c2FnZXM6XG4gKiAtIG1pbG8ubG9hZGVyKFtteVJvb3RFbCxdW215UmVtb3ZlQXR0cmlidXRlLF1teUNhbGxiYWNrKVxuICogXG4gKiBAcGFyYW0gIHtFbGVtZW50fSAgcm9vdEVsICAgICAgICAgIFJvb3QgZWxlbWVudCBpbnNpZGUgd2hpY2ggRE9NIHdpbGwgYmUgc2Nhbm5lZCAoZG9jdW1lbnQuYm9keSBieSBkZWZhdWx0KS5cbiAqIEBwYXJhbSAge0Jvb2xlYW59ICByZW1vdmVBdHRyaWJ1dGUgSWYgc2V0IHRvIHRydWUsIHRoZW4gdGhlIF9fbWwtbG9hZF9fIGF0dHJpYnV0ZSB3aWxsIGJlIHJlbW92ZWQgb25jZSBsb2FkZXIgaGFzIGJlZW4gZXhlY3V0ZWQgKEZhbHNlIGJ5IGRlZmF1bHQpLlxuICogQHBhcmFtICB7RnVuY3Rpb259IGNhbGxiYWNrICAgICAgICBDYWxsYmFjayB0byBjYWxsIGFmdGVyIGFsbCBlbGVtZW50cyBnZXQgbG9hZGVkIChSZXF1aXJlZCkuXG4gKi9cbmZ1bmN0aW9uIGxvYWRlcihyb290RWwsIHJlbW92ZUF0dHJpYnV0ZSwgY2FsbGJhY2spIHtcbiAgICBtaWxvKGZ1bmN0aW9uKCkge1xuICAgICAgICBfbG9hZGVyKHJvb3RFbCwgcmVtb3ZlQXR0cmlidXRlLCBjYWxsYmFjayk7XG4gICAgfSk7XG59XG5cblxuZnVuY3Rpb24gX2xvYWRlcihyb290RWwsIHJlbW92ZUF0dHJpYnV0ZSwgY2FsbGJhY2spIHtcbiAgICBpZiAodHlwZW9mIHJvb3RFbCA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIGNhbGxiYWNrID0gcm9vdEVsO1xuICAgICAgICByb290RWwgPSB1bmRlZmluZWQ7XG4gICAgICAgIHJlbW92ZUF0dHJpYnV0ZSA9IGZhbHNlO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgcmVtb3ZlQXR0cmlidXRlID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgY2FsbGJhY2sgPSByZW1vdmVBdHRyaWJ1dGU7XG4gICAgICAgIHJlbW92ZUF0dHJpYnV0ZSA9IGZhbHNlO1xuICAgIH1cblxuICAgIHJvb3RFbCA9IHJvb3RFbCB8fCBkb2N1bWVudC5ib2R5O1xuXG4gICAgbWlsb01haWwucG9zdE1lc3NhZ2UoJ2xvYWRlcicsIHsgc3RhdGU6ICdzdGFydGVkJyB9KTtcbiAgICBfbG9hZFZpZXdzSW5FbGVtZW50KHJvb3RFbCwgcmVtb3ZlQXR0cmlidXRlLCBmdW5jdGlvbih2aWV3cykge1xuICAgICAgICBtaWxvTWFpbC5wb3N0TWVzc2FnZSgnbG9hZGVyJywgeyBcbiAgICAgICAgICAgIHN0YXRlOiAnZmluaXNoZWQnLFxuICAgICAgICAgICAgdmlld3M6IHZpZXdzXG4gICAgICAgIH0pO1xuICAgICAgICBjYWxsYmFjayh2aWV3cyk7XG4gICAgfSk7XG59XG5cblxuZnVuY3Rpb24gX2xvYWRWaWV3c0luRWxlbWVudChyb290RWwsIHJlbW92ZUF0dHJpYnV0ZSwgY2FsbGJhY2spIHtcbiAgICB2YXIgbG9hZEVsZW1lbnRzID0gcm9vdEVsLmdldEF0dHJpYnV0ZShjb25maWcuYXR0cnMubG9hZClcbiAgICAgICAgICAgICAgICAgICAgICAgID8gW3Jvb3RFbF1cbiAgICAgICAgICAgICAgICAgICAgICAgIDogcm9vdEVsLnF1ZXJ5U2VsZWN0b3JBbGwoJ1snICsgY29uZmlnLmF0dHJzLmxvYWQgKyAnXScpO1xuXG4gICAgdmFyIHZpZXdzID0ge31cbiAgICAgICAgLCB0b3RhbENvdW50ID0gbG9hZEVsZW1lbnRzLmxlbmd0aFxuICAgICAgICAsIGxvYWRlZENvdW50ID0gMDtcblxuICAgIF8uZm9yRWFjaChsb2FkRWxlbWVudHMsIGZ1bmN0aW9uIChlbCkge1xuICAgICAgICBsb2FkVmlldyhlbCwgcmVtb3ZlQXR0cmlidXRlLCBmdW5jdGlvbihlcnIpIHtcbiAgICAgICAgICAgIHZpZXdzW2VsLmlkXSA9IGVyciB8fCBlbDtcbiAgICAgICAgICAgIGxvYWRlZENvdW50Kys7XG4gICAgICAgICAgICBpZiAobG9hZGVkQ291bnQgPT0gdG90YWxDb3VudClcbiAgICAgICAgICAgICAgICBjYWxsYmFjayh2aWV3cyk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xufTtcblxuXG5mdW5jdGlvbiBsb2FkVmlldyhlbCwgcmVtb3ZlQXR0cmlidXRlLCBjYWxsYmFjaykge1xuICAgIGlmICh1dGlsRG9tLmNoaWxkcmVuKGVsKS5sZW5ndGgpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignY2FuXFwndCBsb2FkIGh0bWwgaW50byBlbGVtZW50IHRoYXQgaXMgbm90IGVtcHR5Jyk7XG5cbiAgICB2YXIgYXR0ciA9IG5ldyBMb2FkQXR0cmlidXRlKGVsKTtcblxuICAgIGF0dHIucGFyc2UoKS52YWxpZGF0ZSgpO1xuXG4gICAgcmVxdWVzdC5nZXQoYXR0ci5sb2FkVXJsLCBmdW5jdGlvbihlcnIsIGh0bWwpIHtcbiAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgZXJyLm1lc3NhZ2UgPSBlcnIubWVzc2FnZSB8fCAnY2FuXFwndCBsb2FkIGZpbGUgJyArIGF0dHIubG9hZFVybDtcbiAgICAgICAgICAgIC8vIGxvZ2dlci5lcnJvcihlcnIubWVzc2FnZSk7XG4gICAgICAgICAgICBjYWxsYmFjayhlcnIpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgZWwuaW5uZXJIVE1MID0gaHRtbDtcbiAgICAgICAgaWYgKHJlbW92ZUF0dHJpYnV0ZSkgTG9hZEF0dHJpYnV0ZS5yZW1vdmUoZWwpO1xuICAgICAgICBjYWxsYmFjayhudWxsKTtcbiAgICB9KTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90bztcblxuXG4vLyByZWdpc3RlciBpbmNsdWRlZCBmYWNldHNcbnJlcXVpcmUoJy4vdXNlX2ZhY2V0cycpO1xuXG4vLyByZWdpc3RlciBpbmNsdWRlZCBjb21wb25lbnRzXG5yZXF1aXJlKCcuL3VzZV9jb21wb25lbnRzJyk7XG5cblxuLyoqXG4gKiBgbWlsb2BcbiAqXG4gKiBBIG1pbmltYWxpc3QgYnJvd3NlciBmcmFtZXdvcmsgdGhhdCBiaW5kcyBET00gZWxlbWVudHMgdG8gSlMgY29tcG9uZW50cyBhbmQgY29tcG9uZW50cyB0byBtb2RlbHMuXG4gKlxuICogYG1pbG9gIGlzIGF2YWlsYWJsZSBhcyBnbG9iYWwgb2JqZWN0IGluIHRoZSBicm93c2VyLlxuICogQXQgdGhlIG1vbWVudCBpdCBpcyBub3QgcG9zc2lpYmxlIHRvIHJlcXVpcmUgaXQgd2l0aCBicm93c2VyaWZ5IHRvIGhhdmUgaXQgYnVuZGxlZCB3aXRoIHRoZSBhcHAgYmVjYXVzZSBvZiB0aGUgd2F5IFticmZzXShodHRwczovL2dpdGh1Yi5jb20vc3Vic3RhY2svYnJmcykgYnJvd3NlcmlmeSBwbHVnaW4gaXMgaW1wbGVtZW50ZWQuXG4gKiBJdCBpcyBwb3NzaWJsZSB0aG91Z2ggdG8gcmVxdWlyZSBgbWlsb2Agd2l0aCBub2RlIHRvIHVzZSB1bml2ZXJzYWwgcGFydHMgb2YgdGhlIGZyYW1ld29yayAoYWJzdHJhY3QgY2xhc3NlcywgTWVzc2VuZ2VyLCBNb2RlbCwgZXRjLik6XG4gKiBgYGBcbiAqIHZhciBtaWxvID0gcmVxdWlyZSgnbW9sLW1pbG8nKTtcbiAqIGBgYFxuICogXG4gKiBgbWlsb2AgaXRzZWxmIGlzIGEgZnVuY3Rpb24gdGhhdCBpbiB0aGUgYnJvd3NlciBjYW4gYmUgdXNlZCB0byBkZWxheSBleGVjdXRpb24gdW50aWwgRE9NIGlzIHJlYWR5LlxuICovXG5mdW5jdGlvbiBtaWxvKGZ1bmMpIHtcbiAgICBtaWxvLnV0aWwuZG9tUmVhZHkoZnVuYyk7XG59XG5cblxuLyoqXG4gKiAjIyMjTWlsbyBwYWNrYWdlcyMjIyNcbiAqXG4gKiAtIFtsb2FkZXJdKC4vbG9hZGVyLmpzLmh0bWwpIC0gbG9hZGluZyBzdWJ2aWV3cyBpbnRvIHBhZ2VcbiAqIC0gW2JpbmRlcl0oLi9iaW5kZXIuanMuaHRtbCkgLSBjb21wb25lbnRzIGluc3RhbnRpYXRpb24gYW5kIGJpbmRpbmcgb2YgRE9NIGVsZW1lbnRzIHRvIHRoZW1cbiAqIC0gW21pbmRlcl0oLi9taW5kZXIuanMuaHRtbCkgLSBkYXRhIHJlYWN0aXZpdHksIG9uZSBvciB0d28gd2F5LCBzaGFsbG93IG9yIGRlZXAsIGFzIHlvdSBsaWtlIGl0XG4gKiAtIFttYWlsXSguL21haWwvaW5kZXguanMuaHRtbCkgLSBhcHBsaWNhaXRvbiBsZXZlbCBtZXNzZW5nZXIsIGFsc28gY29ubmVjdHMgdG8gbWVzc2FnZXMgZnJvbSBvdGhlciB3aW5kb3dzIGRpc3BhdGNoZWQgd2l0aCBgd2luZG93LnBvc3RNZXNzYWdlYC5cbiAqIC0gW2NvbmZpZ10oLi9jb25maWcuanMuaHRtbCkgLSBtaWxvIGNvbmZpZ3VyYXRpb25cbiAqIC0gW3V0aWxdKC4vdXRpbC9pbmRleC5qcy5odG1sKSAtIGxvZ2dlciwgcmVxdWVzdCwgZG9tLCBjaGVjaywgZXJyb3IsIGV0Yy5cbiAqIC0gW2NsYXNzZXNdKC4vY2xhc3Nlcy5qcy5odG1sKSAtIGFic3RyYWN0IGFuZCBiYXNlIGNsYXNzZXNcbiAqIC0gW2F0dHJpYnV0ZXNdKC4vYXR0cmlidXRlcy9pbmRleC5qcy5odG1sKSAtIGNsYXNzZXMgdGhhdCB3cmFwIERPTSBlbGVtZW50cyBhdHRyaWJ1dGVzIHJlY29nbml6ZWQgYnkgbWlsb1xuICogLSBbQ29tcG9uZW50RmFjZXRdKC4vY29tcG9uZW50cy9jX2ZhY2V0LmpzLmh0bWwpIC0gYmFzZSBjbGFzcyBvZiBDb21wb25lbnQgZmFjZXRcbiAqIC0gW0NvbXBvbmVudF0oLi9jb21wb25lbnRzL2NfY2xhc3MuanMuaHRtbCkgLSBiYXNlIENvbXBvbmVudCBjbGFzc1xuICogLSBbTWVzc2VuZ2VyXSguL21lc3Nlbmdlci9pbmRleC5qcy5odG1sKSAtIGdlbmVyaWMgTWVzc2VuZ2VyIHVzZWQgaW4gbW9zdCBvdGhlciBtaWxvIGNsYXNzZXMsIGNhbiBiZSBtaXhlZCBpbnRvIGFwcCBjbGFzc2VzIHRvby5cbiAqIC0gW01vZGVsXSguL21vZGVsL2luZGV4LmpzLmh0bWwpIC0gTW9kZWwgY2xhc3MgdGhhdCBlbWl0cyBtZXNzYWdlcyBvbiBjaGFuZ2VzIHRvIGFueSBkZXB0aCB3aXRob3V0IHRpbWVyIGJhc2VkIHdhdGNoaW5nXG4gKiAtIFtyZWdpc3RyeV0oLi9yZWdpc3RyeS5qcy5odG1sKSAtIHJlZ2lzdHJpZXMgb2YgZmFzZXRzIGFuZCBjb21wb25lbnRzIGNsYXNzZXNcbiAqL1xuXy5leHRlbmQobWlsbywge1xuICAgIE1lc3NlbmdlcjogbWlsb0NvcmUuTWVzc2VuZ2VyLFxuICAgIE1vZGVsOiBtaWxvQ29yZS5Nb2RlbCxcbiAgICBtaW5kZXI6IG1pbG9Db3JlLm1pbmRlcixcbiAgICBsb2FkZXI6IHJlcXVpcmUoJy4vbG9hZGVyJyksXG4gICAgYmluZGVyOiByZXF1aXJlKCcuL2JpbmRlcicpLFxuICAgIG1haWw6IHJlcXVpcmUoJy4vc2VydmljZXMvbWFpbCcpLFxuICAgIHdpbmRvdzogcmVxdWlyZSgnLi9zZXJ2aWNlcy93aW5kb3cnKSxcbiAgICBjb25maWc6IHJlcXVpcmUoJy4vY29uZmlnJyksXG4gICAgdXRpbDogcmVxdWlyZSgnLi91dGlsJyksXG4gICAgY2xhc3NlczogcmVxdWlyZSgnLi9jbGFzc2VzJyksXG4gICAgYXR0cmlidXRlczogcmVxdWlyZSgnLi9hdHRyaWJ1dGVzJyksXG4gICAgQ29tcG9uZW50RmFjZXQ6IHJlcXVpcmUoJy4vY29tcG9uZW50cy9jX2ZhY2V0JyksXG4gICAgQ29tcG9uZW50OiByZXF1aXJlKCcuL2NvbXBvbmVudHMvY19jbGFzcycpLFxuICAgIENvbW1hbmQ6IHJlcXVpcmUoJy4vY29tbWFuZCcpLFxuICAgIHJlZ2lzdHJ5OiByZXF1aXJlKCcuL3JlZ2lzdHJ5JyksXG4gICAgbWlsb192ZXJzaW9uOiAnMC4xLjEwJyxcbiAgICBjcmVhdGVDb21wb25lbnRDbGFzczogcmVxdWlyZSgnLi91dGlsL2NyZWF0ZV9jb21wb25lbnRfY2xhc3MnKSxcbiAgICBkZXN0cm95OiBkZXN0cm95XG59KTtcblxuXG4vLyBleHBvcnQgZm9yIG5vZGUvYnJvd3NlcmlmeVxuaWYgKHR5cGVvZiBtb2R1bGUgPT0gJ29iamVjdCcgJiYgbW9kdWxlLmV4cG9ydHMpICAgIFxuICAgIG1vZHVsZS5leHBvcnRzID0gbWlsbztcblxuLy8gZ2xvYmFsIG1pbG8gZm9yIGJyb3dzZXJcbmlmICh0eXBlb2Ygd2luZG93ID09ICdvYmplY3QnKSB7XG4gICAgd2luZG93Lm1pbG8gPSBtaWxvO1xuICAgIG1pbG8ubWFpbC50cmlnZ2VyKCdtaWxvcmVhZHknKTtcbn1cblxuXG5mdW5jdGlvbiBkZXN0cm95KCkge1xuICAgIG1pbG9Db3JlLmRlc3Ryb3koKTtcbiAgICBtaWxvLm1haWwuZGVzdHJveSgpO1xuICAgIG1pbG8ud2luZG93LmRlc3Ryb3koKTtcbiAgICBtaWxvLnV0aWwuZGVzdHJveSgpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIFJlZ2lzdHJpZXMgb2YgZmFjZXRzIGFuZCBvZiBjb21wb25lbnRzXG4gKlxuICogLSBbZmFjZXRzXSguL2NvbXBvbmVudHMvY19mYWNldHMvY2ZfcmVnaXN0cnkuanMuaHRtbClcbiAqIC0gW2NvbXBvbmVudHNdKC4vY29tcG9uZW50cy9jX3JlZ2lzdHJ5LmpzLmh0bWwpXG4gKi9cbnZhciByZWdpc3RyeSA9IG1vZHVsZS5leHBvcnRzID0ge1xuICAgIGZhY2V0czogcmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL2NmX3JlZ2lzdHJ5JyksXG4gICAgY29tcG9uZW50czogcmVxdWlyZSgnLi9jb21wb25lbnRzL2NfcmVnaXN0cnknKSxcbiAgICBjb21tYW5kczogcmVxdWlyZSgnLi9jb21tYW5kL2NtZF9yZWdpc3RyeScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyA8YSBuYW1lPVwiY29tcG9uZW50cy1kb20tY29uc3RydWN0b3JzXCI+PC9hPlxuLy8gIyMjZG9tIGV2ZW50cyBjb25zdHJ1Y3RvcnNcblxuXG52YXIgXyA9IHJlcXVpcmUoJ21pbG8tY29yZScpLnByb3RvO1xuXG5cbi8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL1JlZmVyZW5jZS9FdmVudHNcblxudmFyIGV2ZW50VHlwZXMgPSB7XG4gICAgQ2xpcGJvYXJkRXZlbnQ6IFsnY29weScsICdjdXQnLCAncGFzdGUnLCAnYmVmb3JlY29weScsICdiZWZvcmVjdXQnLCAnYmVmb3JlcGFzdGUnXSxcbiAgICBFdmVudDogWydpbnB1dCcsICdyZWFkeXN0YXRlY2hhbmdlJ10sXG4gICAgRm9jdXNFdmVudDogWydmb2N1cycsICdibHVyJywgJ2ZvY3VzaW4nLCAnZm9jdXNvdXQnXSxcbiAgICBLZXlib2FyZEV2ZW50OiBbJ2tleWRvd24nLCAna2V5cHJlc3MnLCAgJ2tleXVwJ10sXG4gICAgTW91c2VFdmVudDogWydjbGljaycsICdjb250ZXh0bWVudScsICdkYmxjbGljaycsICdtb3VzZWRvd24nLCAnbW91c2V1cCcsXG4gICAgICAgICAgICAgICAgICdtb3VzZWVudGVyJywgJ21vdXNlbGVhdmUnLCAnbW91c2Vtb3ZlJywgJ21vdXNlb3V0JywgJ21vdXNlb3ZlcicsXG4gICAgICAgICAgICAgICAgICdzaG93JyAvKiBjb250ZXh0IG1lbnUgKi9dLFxuICAgIFRvdWNoRXZlbnQ6IFsndG91Y2hzdGFydCcsICd0b3VjaGVuZCcsICd0b3VjaG1vdmUnLCAndG91Y2hlbnRlcicsICd0b3VjaGxlYXZlJywgJ3RvdWNoY2FuY2VsJ10sXG59O1xuXG5cbi8vIG1vY2sgd2luZG93IGFuZCBldmVudCBjb25zdHJ1Y3RvcnMgZm9yIHRlc3RpbmdcbmlmICh0eXBlb2Ygd2luZG93ICE9ICd1bmRlZmluZWQnKVxuICAgIHZhciBnbG9iYWwgPSB3aW5kb3c7XG5lbHNlIHtcbiAgICBnbG9iYWwgPSB7fTtcbiAgICBfLmVhY2hLZXkoZXZlbnRUeXBlcywgZnVuY3Rpb24oZVR5cGVzLCBldmVudENvbnN0cnVjdG9yTmFtZSkge1xuICAgICAgICB2YXIgZXZlbnRDb25zdHJ1Y3RvciA9IF8ubWFrZUZ1bmN0aW9uKGV2ZW50Q29uc3RydWN0b3JOYW1lLCAndHlwZScsICdwcm9wZXJ0aWVzJyxcbiAgICAgICAgICAgICd0aGlzLnR5cGUgPSB0eXBlOyBfLmV4dGVuZCh0aGlzLCBwcm9wZXJ0aWVzKTsnKTtcbiAgICAgICAgZ2xvYmFsW2V2ZW50Q29uc3RydWN0b3JOYW1lXSA9IGV2ZW50Q29uc3RydWN0b3I7XG4gICAgfSk7XG59XG5cblxudmFyIGRvbUV2ZW50c0NvbnN0cnVjdG9ycyA9IHt9O1xuXG5fLmVhY2hLZXkoZXZlbnRUeXBlcywgZnVuY3Rpb24oZVR5cGVzLCBldmVudENvbnN0cnVjdG9yTmFtZSkge1xuICAgIGVUeXBlcy5mb3JFYWNoKGZ1bmN0aW9uKHR5cGUpIHtcbiAgICAgICAgaWYgKE9iamVjdC5oYXNPd25Qcm9wZXJ0eShkb21FdmVudHNDb25zdHJ1Y3RvcnMsIHR5cGUpKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdkdXBsaWNhdGUgZXZlbnQgdHlwZSAnICsgdHlwZSk7XG5cbiAgICAgICAgZG9tRXZlbnRzQ29uc3RydWN0b3JzW3R5cGVdID0gZ2xvYmFsW2V2ZW50Q29uc3RydWN0b3JOYW1lXTtcbiAgICB9KTtcbn0pO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gZG9tRXZlbnRzQ29uc3RydWN0b3JzO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNZXNzYWdlU291cmNlID0gbWlsb0NvcmUuY2xhc3Nlcy5NZXNzYWdlU291cmNlXG4gICAgLCBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jb21wb25lbnRzL2NfY2xhc3MnKVxuICAgICwgZG9tRXZlbnRzQ29uc3RydWN0b3JzID0gcmVxdWlyZSgnLi9kZV9jb25zdHJzJykgLy8gVE9ETyBtZXJnZSB3aXRoIERPTUV2ZW50U291cmNlID8/XG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIGNoZWNrID0gbWlsb0NvcmUudXRpbC5jaGVja1xuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaDtcblxudmFyIERPTUVtaXR0ZXJTb3VyY2UgPSBfLmNyZWF0ZVN1YmNsYXNzKE1lc3NhZ2VTb3VyY2UsICdET01FbWl0dGVyU291cmNlJywgdHJ1ZSk7XG5cblxuXy5leHRlbmRQcm90byhET01FbWl0dGVyU291cmNlLCB7XG4gICAgLy8gaW1wbGVtZW50aW5nIE1lc3NhZ2VTb3VyY2UgaW50ZXJmYWNlXG4gICAgaW5pdDogaW5pdCxcbiAgICBkZXN0cm95OiBET01FbWl0dGVyU291cmNlJGRlc3Ryb3ksXG4gICAgYWRkU291cmNlU3Vic2NyaWJlcjogXy5wYXJ0aWFsKHNvdXJjZVN1YnNjcmliZXJNZXRob2QsICdhZGRFdmVudExpc3RlbmVyJyksXG4gICAgcmVtb3ZlU291cmNlU3Vic2NyaWJlcjogXy5wYXJ0aWFsKHNvdXJjZVN1YnNjcmliZXJNZXRob2QsICdyZW1vdmVFdmVudExpc3RlbmVyJyksXG4gICAgcG9zdE1lc3NhZ2U6IERPTUVtaXR0ZXJTb3VyY2UkcG9zdE1lc3NhZ2UsXG4gICAgdHJpZ2dlcjogdHJpZ2dlcixcblxuICAgIC8vIGNsYXNzIHNwZWNpZmljIG1ldGhvZHNcbiAgICBlbWl0dGVyOiBlbWl0dGVyLFxuICAgIGhhbmRsZUV2ZW50OiBoYW5kbGVFdmVudCwgIC8vIGV2ZW50IGRpc3BhdGNoZXIgLSBhcyBkZWZpbmVkIGJ5IEV2ZW50IERPTSBBUElcbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IERPTUVtaXR0ZXJTb3VyY2U7XG5cblxudmFyIHVzZUNhcHR1cmVQYXR0ZXJuID0gL19fY2FwdHVyZSQvXG4gICAgLCB1c2VDYXB0dXJlUG9zdGZpeCA9ICdfX2NhcHR1cmUnO1xuXG5cbi8vIGluaXQgRE9NIGV2ZW50IHNvdXJjZVxuZnVuY3Rpb24gaW5pdChob3N0T2JqZWN0LCBwcm94eU1ldGhvZHMsIG1lc3NlbmdlckFQSU9yQ2xhc3MsIGV2ZW50RW1pdHRlcikge1xuICAgIHRoaXMuZXZlbnRFbWl0dGVyID0gZXZlbnRFbWl0dGVyO1xuICAgIE1lc3NhZ2VTb3VyY2UucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuXG5mdW5jdGlvbiBET01FbWl0dGVyU291cmNlJGRlc3Ryb3koKSB7XG4gICAgTWVzc2FnZVNvdXJjZS5wcm90b3R5cGUuZGVzdHJveS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIGRlbGV0ZSB0aGlzLmV2ZW50RW1pdHRlcjtcbn1cblxuXG4vLyBnZXQgRE9NIGVsZW1lbnQgb2YgY29tcG9uZW50XG5mdW5jdGlvbiBlbWl0dGVyKCkge1xuICAgIHJldHVybiB0aGlzLmV2ZW50RW1pdHRlcjtcbn1cblxuXG5mdW5jdGlvbiBzb3VyY2VTdWJzY3JpYmVyTWV0aG9kKG1ldGhvZCwgZXZlbnRUeXBlKSB7XG4gICAgaWYgKCEgKGV2ZW50VHlwZSAmJiB0eXBlb2YgZXZlbnRUeXBlID09ICdzdHJpbmcnKSkgcmV0dXJuO1xuICAgIHZhciBjYXB0dXJlID0gdXNlQ2FwdHVyZVBhdHRlcm4udGVzdChldmVudFR5cGUpO1xuICAgIGV2ZW50VHlwZSA9IGV2ZW50VHlwZS5yZXBsYWNlKHVzZUNhcHR1cmVQYXR0ZXJuLCAnJyk7XG4gICAgdGhpcy5lbWl0dGVyKClbbWV0aG9kXShldmVudFR5cGUsIHRoaXMsIGNhcHR1cmUpO1xufVxuXG5cbi8vIGV2ZW50IGRpc3BhdGNoZXIgLSBhcyBkZWZpbmVkIGJ5IEV2ZW50IERPTSBBUElcbmZ1bmN0aW9uIGhhbmRsZUV2ZW50KGV2ZW50KSB7XG4gICAgdmFyIGlzQ2FwdHVyZVBoYXNlO1xuICAgIGlmICh0eXBlb2Ygd2luZG93ICE9ICd1bmRlZmluZWQnKVxuICAgICAgICBpc0NhcHR1cmVQaGFzZSA9IGV2ZW50LmV2ZW50UGhhc2UgPT0gd2luZG93LkV2ZW50LkNBUFRVUklOR19QSEFTRTtcblxuICAgIGlmIChpc0NhcHR1cmVQaGFzZSlcbiAgICAgICAgZXZlbnQgKz0gdXNlQ2FwdHVyZVBvc3RmaXg7XG5cbiAgICB0aGlzLmRpc3BhdGNoTWVzc2FnZShldmVudC50eXBlLCBldmVudCk7XG59XG5cblxuZnVuY3Rpb24gRE9NRW1pdHRlclNvdXJjZSRwb3N0TWVzc2FnZShtZXNzYWdlLCBkYXRhKSB7XG4gICAgdGhpcy5tZXNzZW5nZXIucG9zdE1lc3NhZ2VTeW5jKG1lc3NhZ2UsIGRhdGEpO1xufVxuXG5cbmZ1bmN0aW9uIHRyaWdnZXIoZXZlbnRUeXBlLCBwcm9wZXJ0aWVzKSB7XG4gICAgY2hlY2soZXZlbnRUeXBlLCBTdHJpbmcpO1xuICAgIGNoZWNrKHByb3BlcnRpZXMsIE1hdGNoLk9wdGlvbmFsKE9iamVjdCkpO1xuXG4gICAgZXZlbnRUeXBlID0gZXZlbnRUeXBlLnJlcGxhY2UodXNlQ2FwdHVyZVBhdHRlcm4sICcnKTtcbiAgICB2YXIgRXZlbnRDb25zdHJ1Y3RvciA9IGRvbUV2ZW50c0NvbnN0cnVjdG9yc1tldmVudFR5cGVdO1xuXG4gICAgaWYgKHR5cGVvZiBFdmVudENvbnN0cnVjdG9yICE9ICdmdW5jdGlvbicpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndW5zdXBwb3J0ZWQgZXZlbnQgdHlwZScpO1xuXG4gICAgLy8gY2hlY2sgaWYgaXQgaXMgY29ycmVjdFxuICAgIGlmICh0eXBlb2YgcHJvcGVydGllcyAhPSAndW5kZWZpbmVkJylcbiAgICAgICAgcHJvcGVydGllcy50eXBlID0gZXZlbnRUeXBlO1xuXG4gICAgdmFyIGRvbUV2ZW50ID0gbmV3IEV2ZW50Q29uc3RydWN0b3IoZXZlbnRUeXBlLCBwcm9wZXJ0aWVzKTtcbiAgICB2YXIgbm90Q2FuY2VsbGVkID0gdGhpcy5lbWl0dGVyKCkuZGlzcGF0Y2hFdmVudChkb21FdmVudCk7XG4gICAgcmV0dXJuIG5vdENhbmNlbGxlZDtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiBgbWlsby5tYWlsYFxuICogSXQgaXMgYW4gYXBwbGljYXRpb24gbGV2ZWwgbWVzc2VuZ2VyIHRoYXQgaXMgYW4gaW5zdGFuY2Ugb2YgTWVzc2VuZ2VyIGNsYXNzLlxuICpcbiAqIEF0IHRoZSBtb21lbnQsIGluIGFkZGl0aW9uIHRvIGFwcGxpY2F0aW9uIG1lc3NhZ2VzIHRoYXQgeW91IGRlZmluZSwgeW91IGNhbiBzdWJzY3JpYmUgdG8gX19kb21yZWFkeV9fIG1lc3NhZ2UgdGhhdCBpcyBndWFyYW50ZWVkIHRvIGZpcmUgb25jZSxcbiAqIGV2ZW4gaWYgRE9NIHdhcyByZWFkeSBhdCB0aGUgdGltZSBvZiB0aGUgc3Vic2NyaXB0aW9uLlxuICpcbiAqIE1lc3NhZ2luZyBiZXR3ZWVuIGZyYW1lcyBpcyBhdmFpbGFibGUgdmlhIG1pbG8ubWFpbC4gU2VlIFtGcmFtZSBmYWNldF0oLi4vY29tcG9uZW50cy9jX2ZhY2V0cy9GcmFtZS5qcy5odG1sKS5cbiAqXG4gKiBTZWUgW01lc3Nlbmdlcl0oLi4vbWVzc2VuZ2VyL2luZGV4LmpzLmh0bWwpLlxuICogXG4qKi9cblxuXG52YXIgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgTWVzc2VuZ2VyID0gbWlsb0NvcmUuTWVzc2VuZ2VyXG4gICAgLCBNYWlsTXNnQVBJID0gcmVxdWlyZSgnLi9tYWlsX2FwaScpXG4gICAgLCBNYWlsTWVzc2FnZVNvdXJjZSA9IHJlcXVpcmUoJy4vbWFpbF9zb3VyY2UnKVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvO1xuXG5cbnZhciBtaWxvTWFpbCA9IG5ldyBNZXNzZW5nZXI7XG5cbnZhciBtYWlsTXNnU291cmNlID0gbmV3IE1haWxNZXNzYWdlU291cmNlKG1pbG9NYWlsLCB7IHRyaWdnZXI6ICd0cmlnZ2VyJyB9LCBuZXcgTWFpbE1zZ0FQSSk7XG5cbm1pbG9NYWlsLl9zZXRNZXNzYWdlU291cmNlKG1haWxNc2dTb3VyY2UpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gbWlsb01haWw7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNZXNzZW5nZXJBUEkgPSBtaWxvQ29yZS5jbGFzc2VzLk1lc3NlbmdlckFQSVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvXG4gICAgLCBjaGVjayA9IG1pbG9Db3JlLnV0aWwuY2hlY2tcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2g7XG5cblxudmFyIE1haWxNc2dBUEkgPSBfLmNyZWF0ZVN1YmNsYXNzKE1lc3NlbmdlckFQSSwgJ01haWxNc2dBUEknLCB0cnVlKTtcblxuXG5fLmV4dGVuZFByb3RvKE1haWxNc2dBUEksIHtcbiAgICB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2U6IHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZSxcbiAgICBmaWx0ZXJTb3VyY2VNZXNzYWdlOiBmaWx0ZXJTb3VyY2VNZXNzYWdlXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBNYWlsTXNnQVBJO1xuXG5cbi8vIFRPRE86IHRoaXMgZnVuY3Rpb24gc2hvdWxkIHJldHVybiByZWxldmFudCBET00gZXZlbnQgZGVwZW5kZW50IG9uIGVsZW1lbnQgdGFnXG4vLyBDYW4gYWxzbyBpbXBsZW1lbnQgYmVmb3JlZGF0YWNoYW5nZWQgZXZlbnQgdG8gYWxsb3cgcHJldmVudGluZyB0aGUgY2hhbmdlXG4vLyB0cmFuc2xhdGVUb0RvbUV2ZW50XG52YXIgd2luZG93TWVzc2FnZVJlZ0V4cCA9IC9ebWVzc2FnZVxcOi9cbiAgICAsIHdpbmRvd01lc3NhZ2VQcmVmaXggPSAnbWVzc2FnZTonO1xuXG5mdW5jdGlvbiB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UobWVzc2FnZSkge1xuICAgIGlmIChtZXNzYWdlID09ICdkb21yZWFkeScpXG4gICAgICAgIHJldHVybiAncmVhZHlzdGF0ZWNoYW5nZSc7XG4gICAgZWxzZSBpZiAod2luZG93TWVzc2FnZVJlZ0V4cC50ZXN0KG1lc3NhZ2UpKVxuICAgICAgICByZXR1cm4gJ21lc3NhZ2UnO1xufVxuXG5cbi8vIGZpbHRlckRhdGFNZXNzYWdlXG5mdW5jdGlvbiBmaWx0ZXJTb3VyY2VNZXNzYWdlKHNvdXJjZU1lc3NhZ2UsIG1zZ1R5cGUsIG1zZ0RhdGEpIHtcbiAgICBpZiAoc291cmNlTWVzc2FnZSA9PSAncmVhZHlzdGF0ZWNoYW5nZScpIHtcbiAgICAgICAgLy9yZXR1cm4gZG9jdW1lbnQucmVhZHlTdGF0ZSA9PSAnaW50ZXJhY3RpdmUnO1xuICAgICAgICAvLyAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAvLyBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdfZG9tUmVhZHlGaXJlZCcsIHRydWUsIF8uV1JJVCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSBpZiAoc291cmNlTWVzc2FnZSA9PSAnbWVzc2FnZScpXG4gICAgICAgIHJldHVybiB3aW5kb3dNZXNzYWdlUHJlZml4ICsgbXNnRGF0YS5kYXRhLnR5cGUgPT0gbXNnVHlwZTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNZXNzYWdlU291cmNlID0gbWlsb0NvcmUuY2xhc3Nlcy5NZXNzYWdlU291cmNlXG4gICAgLCBkb21FdmVudHNDb25zdHJ1Y3RvcnMgPSByZXF1aXJlKCcuLi9kZV9jb25zdHJzJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgY2hlY2sgPSBtaWxvQ29yZS51dGlsLmNoZWNrXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5cbnZhciBNYWlsTWVzc2FnZVNvdXJjZSA9IF8uY3JlYXRlU3ViY2xhc3MoTWVzc2FnZVNvdXJjZSwgJ01haWxNZXNzYWdlU291cmNlJywgdHJ1ZSk7XG5cblxuXy5leHRlbmRQcm90byhNYWlsTWVzc2FnZVNvdXJjZSwge1xuICAgIC8vIGltcGxlbWVudGluZyBNZXNzYWdlU291cmNlIGludGVyZmFjZVxuICAgIGFkZFNvdXJjZVN1YnNjcmliZXI6IGFkZFNvdXJjZVN1YnNjcmliZXIsXG4gICAgcmVtb3ZlU291cmNlU3Vic2NyaWJlcjogcmVtb3ZlU291cmNlU3Vic2NyaWJlcixcbiAgICB0cmlnZ2VyOiB0cmlnZ2VyLFxuXG4gICAgLy8gY2xhc3Mgc3BlY2lmaWMgbWV0aG9kc1xuICAgIF93aW5kb3dTdWJzY3JpYmVyTWV0aG9kOiBfd2luZG93U3Vic2NyaWJlck1ldGhvZCxcbiAgICBoYW5kbGVFdmVudDogaGFuZGxlRXZlbnQsICAvLyBldmVudCBkaXNwYXRjaGVyIC0gYXMgZGVmaW5lZCBieSBFdmVudCBET00gQVBJXG59KTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1haWxNZXNzYWdlU291cmNlO1xuXG5cbmZ1bmN0aW9uIGFkZFNvdXJjZVN1YnNjcmliZXIoc291cmNlTWVzc2FnZSkge1xuICAgIGlmIChpc1JlYWR5U3RhdGVDaGFuZ2Uoc291cmNlTWVzc2FnZSkpIHtcbiAgICAgICAgaWYgKGRvY3VtZW50LnJlYWR5U3RhdGUgPT0gJ2xvYWRpbmcnKVxuICAgICAgICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigncmVhZHlzdGF0ZWNoYW5nZScsIHRoaXMsIGZhbHNlKTtcbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB2YXIgRXZlbnRDb25zdHJ1Y3RvciA9IGRvbUV2ZW50c0NvbnN0cnVjdG9ycy5yZWFkeXN0YXRlY2hhbmdlO1xuICAgICAgICAgICAgdmFyIGRvbUV2ZW50ID0gbmV3IEV2ZW50Q29uc3RydWN0b3IoJ3JlYWR5c3RhdGVjaGFuZ2UnLCB7IHRhcmdldDogZG9jdW1lbnQgfSk7XG4gICAgICAgICAgICB0aGlzLmRpc3BhdGNoTWVzc2FnZSgncmVhZHlzdGF0ZWNoYW5nZScsIGRvbUV2ZW50KTtcbiAgICAgICAgfVxuICAgIH0gZWxzZVxuICAgICAgICB0aGlzLl93aW5kb3dTdWJzY3JpYmVyTWV0aG9kKCdhZGRFdmVudExpc3RlbmVyJywgc291cmNlTWVzc2FnZSk7XG59XG5cblxuZnVuY3Rpb24gcmVtb3ZlU291cmNlU3Vic2NyaWJlcihzb3VyY2VNZXNzYWdlKSB7XG4gICAgaWYgKGlzUmVhZHlTdGF0ZUNoYW5nZShzb3VyY2VNZXNzYWdlKSlcbiAgICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigncmVhZHlzdGF0ZWNoYW5nZScsIHRoaXMsIGZhbHNlKTtcbiAgICBlbHNlIFxuICAgICAgICB0aGlzLl93aW5kb3dTdWJzY3JpYmVyTWV0aG9kKCdyZW1vdmVFdmVudExpc3RlbmVyJywgc291cmNlTWVzc2FnZSk7XG59XG5cblxuZnVuY3Rpb24gaXNSZWFkeVN0YXRlQ2hhbmdlKHNvdXJjZU1lc3NhZ2UpIHtcbiAgICByZXR1cm4gc291cmNlTWVzc2FnZSA9PSAncmVhZHlzdGF0ZWNoYW5nZScgJiYgdHlwZW9mIGRvY3VtZW50ID09ICdvYmplY3QnO1xufVxuXG5mdW5jdGlvbiBpc1dpbmRvd01lc3NhZ2Uoc291cmNlTWVzc2FnZSkge1xuICAgIHJldHVybiBzb3VyY2VNZXNzYWdlID09ICdtZXNzYWdlJyAmJiB0eXBlb2Ygd2luZG93ID09ICdvYmplY3QnO1xufVxuXG5mdW5jdGlvbiBfd2luZG93U3Vic2NyaWJlck1ldGhvZChtZXRob2QsIHNvdXJjZU1lc3NhZ2UpIHtcbiAgICBpZiAoaXNXaW5kb3dNZXNzYWdlKHNvdXJjZU1lc3NhZ2UpKVxuICAgICAgICB3aW5kb3dbbWV0aG9kXSgnbWVzc2FnZScsIHRoaXMsIGZhbHNlKTtcbn1cblxuXG4vLyBldmVudCBkaXNwYXRjaGVyIC0gYXMgZGVmaW5lZCBieSBFdmVudCBET00gQVBJXG5mdW5jdGlvbiBoYW5kbGVFdmVudChldmVudCkge1xuICAgIHRoaXMuZGlzcGF0Y2hNZXNzYWdlKGV2ZW50LnR5cGUsIGV2ZW50KTtcbn1cblxuXG5mdW5jdGlvbiB0cmlnZ2VyKG1zZ1R5cGUsIGRhdGEpIHtcbiAgICBkYXRhID0gZGF0YSB8fCB7fTtcbiAgICBkYXRhLnR5cGUgPSAnbWVzc2FnZTonICsgbXNnVHlwZTtcbiAgICBcbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PSAnb2JqZWN0JylcbiAgICAgICAgd2luZG93LnBvc3RNZXNzYWdlKGRhdGEsICcqJylcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgTWVzc2VuZ2VyID0gbWlsb0NvcmUuTWVzc2VuZ2VyXG4gICAgLCBET01FbWl0dGVyU291cmNlID0gcmVxdWlyZSgnLi9kb21fc291cmNlJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90bztcblxuXG52YXIgd2luZG93U2VydmljZSA9IG5ldyBNZXNzZW5nZXI7XG52YXIgZG9tRW1pdHRlclNvdXJjZSA9IG5ldyBET01FbWl0dGVyU291cmNlKHdpbmRvd1NlcnZpY2UsIHsgdHJpZ2dlcjogJ3RyaWdnZXInIH0sIHVuZGVmaW5lZCwgd2luZG93KTtcbndpbmRvd1NlcnZpY2UuX3NldE1lc3NhZ2VTb3VyY2UoZG9tRW1pdHRlclNvdXJjZSk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSB3aW5kb3dTZXJ2aWNlO1xuXG5cbl8uZXh0ZW5kKHdpbmRvd1NlcnZpY2UsIHtcbiAgICBpc1RvcDogd2luZG93U2VydmljZV9pc1RvcFxufSk7XG5cblxuZnVuY3Rpb24gd2luZG93U2VydmljZV9pc1RvcCgpIHtcbiAgICByZXR1cm4gd2luZG93LnRvcCA9PSB3aW5kb3cuc2VsZiB8fCB3aW5kb3cuX19rYXJtYV9fO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY2xhc3Nlcy9WaWV3Jyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvR3JvdXAnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9XcmFwcGVyJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvVGV4dCcpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL1NlbGVjdCcpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL0lucHV0Jyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvSW5wdXRMaXN0Jyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvVGV4dGFyZWEnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9SYWRpb0dyb3VwJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvQnV0dG9uJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvSHlwZXJsaW5rJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvTGlzdCcpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL0xpc3RJdGVtJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvVGltZScpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL0RhdGUnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9Db21ibycpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL1N1cGVyQ29tYm8nKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9Db21ib0xpc3QnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9JbWFnZScpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL3VpL0Ryb3BUYXJnZXQnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy91aS9Gb2xkVHJlZScpO1xuXG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvYm9vdHN0cmFwL0Ryb3Bkb3duJyk7XG4vLyByZXF1aXJlKCcuL2NvbXBvbmVudHMvdWkvYm9vdHN0cmFwL0RpYWxvZycpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvRG9tJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvRGF0YScpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL0ZyYW1lJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvRXZlbnRzJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvT3B0aW9ucycpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL1RlbXBsYXRlJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvQ29udGFpbmVyJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvTW9kZWxGYWNldCcpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL0RyYWcnKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy9jX2ZhY2V0cy9Ecm9wJyk7XG5yZXF1aXJlKCcuL2NvbXBvbmVudHMvY19mYWNldHMvTGlzdCcpO1xucmVxdWlyZSgnLi9jb21wb25lbnRzL2NfZmFjZXRzL0l0ZW0nKTtcbnJlcXVpcmUoJy4vY29tcG9uZW50cy9jX2ZhY2V0cy9UcmFuc2ZlcicpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY291bnQgPSByZXF1aXJlKCcuL2NvdW50JylcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4uL2NvbmZpZycpXG4gICAgLCBwcmVmaXggPSBjb25maWcuY29tcG9uZW50UHJlZml4O1xuXG5cbm1vZHVsZS5leHBvcnRzID0gY29tcG9uZW50TmFtZTtcblxuXG5mdW5jdGlvbiBjb21wb25lbnROYW1lKCkge1xuICAgIHJldHVybiBwcmVmaXggKyBjb3VudCgpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdGltZXN0YW1wID0gRGF0ZS5ub3coKVxuICAgICwgY291bnQgPSAnJ1xuICAgICwgdW5pcXVlSUQgPSAnJyArIHRpbWVzdGFtcDtcblxuZnVuY3Rpb24gdW5pcXVlQ291bnQoKSB7XG4gICAgdmFyIG5ld1RpbWVzdGFtcCA9IERhdGUubm93KCk7XG4gICAgdW5pcXVlSUQgPSAnJyArIG5ld1RpbWVzdGFtcDtcbiAgICBpZiAodGltZXN0YW1wID09IG5ld1RpbWVzdGFtcCkge1xuICAgICAgICBjb3VudCA9IGNvdW50ID09PSAnJyA/IDAgOiBjb3VudCArIDE7XG4gICAgICAgIHVuaXF1ZUlEICs9ICdfJyArIGNvdW50O1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRpbWVzdGFtcCA9IG5ld1RpbWVzdGFtcDtcbiAgICAgICAgY291bnQgPSAnJztcbiAgICB9XG5cbiAgICByZXR1cm4gdW5pcXVlSUQ7XG59XG5cbnVuaXF1ZUNvdW50LmdldCA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB1bmlxdWVJRDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB1bmlxdWVDb3VudDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIF8gPSByZXF1aXJlKCdtaWxvLWNvcmUnKS5wcm90bztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGNyZWF0ZUNvbXBvbmVudENsYXNzO1xuXG4vKipcbiAqIFV0aWxpdHkgZnVuY3Rpb24gd2hpY2ggY3JlYXRlcyBhbmQgcmVnaXN0ZXJzIG5ldyBtaWxvIGNvbXBvbmVudC4gIFRoZSBjb21wb25lbnQgY3JlYXRlZCB3aWxsIGhhdmVcbiAqIGEgcmVmZXJlbmNlIHRvIHRoZSBzdXBlciBjbGFzcyB1c2VkIGluIGl0cyBjcmVhdGlvbiAoQWNjZXNzYWJsZSB1c2luZyA8Q29tcG9uZW50Q2xhc3M+LnN1cGVyKS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnLmNsYXNzTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBuZXcgY29tcG9uZW50XG4gKiBAcGFyYW0ge3N0cmluZ30gWydDb21wb25lbnQnXSBjb25maWcuc3VwZXJDbGFzc05hbWUgLSBUaGUgbmFtZSBvZiBhbiBleGlzdGluZyBjb21wb25lbnQgdG8gYmUgdXNlZCBhcyB0aGUgbmV3IGNvbXBvbmVudCdzIHN1cGVyIGNsYXNzXG4gKiBAcGFyYW0ge29iamVjdD19IGNvbmZpZy5mYWNldHMgLSBGYWNldCBjb25maWd1cmF0aW9uIChIYXNoIG9mIGZhY2V0IG5hbWUge3N0cmluZ30gdG8gY29uZmlnIHtvYmplY3R9KVxuICogQHBhcmFtIHtvYmplY3Q9fSBjb25maWcubWV0aG9kcyAtIE1ldGhvZHMgb2YgdGhlIG5ldyBjb21wb25lbnQgKEhhc2ggb2YgZnVuY3Rpb24gbmFtZSB7c3RyaW5nfSB0byBmdW5jdGlvbiB7ZnVuY3Rpb259KVxuICogQHBhcmFtIHtvYmplY3Q9fSBjb25maWcuc3RhdGljTWV0aG9kcyAtIFN0YXRpYyBtZXRob2RzIG9mIHRoZSBuZXcgY29tcG9uZW50IChIYXNoIG9mIGZ1bmN0aW9uIG5hbWUge3N0cmluZ30gdG8gZnVuY3Rpb24ge2Z1bmN0aW9ufSlcbiAqL1xuZnVuY3Rpb24gY3JlYXRlQ29tcG9uZW50Q2xhc3MoY29uZmlnKSB7XG4gICAgdmFyIGNvbXBvbmVudFJlZ2lzdHJ5ID0gbWlsby5yZWdpc3RyeS5jb21wb25lbnRzO1xuICAgIHZhciBTdXBlckNsYXNzID0gY29tcG9uZW50UmVnaXN0cnkuZ2V0KGNvbmZpZy5zdXBlckNsYXNzTmFtZSB8fCAnQ29tcG9uZW50Jyk7XG4gICAgdmFyIENvbXBvbmVudENsYXNzID0gU3VwZXJDbGFzcy5jcmVhdGVDb21wb25lbnRDbGFzcyhjb25maWcuY2xhc3NOYW1lLCBjb25maWcuZmFjZXRzKTtcblxuICAgIGlmKGNvbmZpZy5tZXRob2RzKSB7XG4gICAgICAgIF8uZXh0ZW5kUHJvdG8oQ29tcG9uZW50Q2xhc3MsIGNvbmZpZy5tZXRob2RzKTtcbiAgICB9XG5cbiAgICBpZihjb25maWcuc3RhdGljTWV0aG9kcykge1xuICAgICAgICBpZihjb25maWcuc3RhdGljTWV0aG9kcy5zdXBlciAhPT0gdW5kZWZpbmVkKSB0aHJvdyAnXFwnc3VwZXJcXCcgaXMgYSByZXNlcnZlZCBrZXl3b3JkJztcblxuICAgICAgICBfLmV4dGVuZChDb21wb25lbnRDbGFzcywgY29uZmlnLnN0YXRpY01ldGhvZHMpO1xuICAgIH1cblxuICAgIENvbXBvbmVudENsYXNzLnN1cGVyID0gU3VwZXJDbGFzcy5wcm90b3R5cGU7XG4gICAgXG4gICAgY29tcG9uZW50UmVnaXN0cnkuYWRkKENvbXBvbmVudENsYXNzKTtcblxuICAgIHJldHVybiBDb21wb25lbnRDbGFzcztcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJylcbiAgICAsIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgbG9nZ2VyID0gbWlsb0NvcmUudXRpbC5sb2dnZXI7XG5cbnZhciBkb21VdGlscyA9IHtcbiAgICBjaGlsZHJlbjogY2hpbGRyZW4sXG4gICAgZmlsdGVyTm9kZUxpc3RCeVR5cGU6IGZpbHRlck5vZGVMaXN0QnlUeXBlLFxuICAgIGNvbnRhaW5pbmdFbGVtZW50OiBjb250YWluaW5nRWxlbWVudCxcbiAgICBzZWxlY3RFbGVtZW50Q29udGVudHM6IHNlbGVjdEVsZW1lbnRDb250ZW50cyxcbiAgICBzZWxlY3RFbGVtZW50VGV4dDogc2VsZWN0RWxlbWVudFRleHQsXG4gICAgZ2V0RWxlbWVudE9mZnNldDogZ2V0RWxlbWVudE9mZnNldCxcbiAgICBzZXRDYXJldFBvc2l0aW9uOiBzZXRDYXJldFBvc2l0aW9uLFxuICAgIGdldFNlbGVjdGlvbkRpcmVjdGlvbjogZ2V0U2VsZWN0aW9uRGlyZWN0aW9uLFxuICAgIHNldFNlbGVjdGlvbjogc2V0U2VsZWN0aW9uLFxuICAgIGNsZWFyU2VsZWN0aW9uOiBjbGVhclNlbGVjdGlvbixcbiAgICByZW1vdmVFbGVtZW50OiByZW1vdmVFbGVtZW50LFxuICAgIHVud3JhcEVsZW1lbnQ6IHVud3JhcEVsZW1lbnQsXG4gICAgd3JhcEluRWxlbWVudDogd3JhcEluRWxlbWVudCxcbiAgICBkZXRhY2hDb21wb25lbnQ6IGRldGFjaENvbXBvbmVudCxcbiAgICBmaXJzdFRleHROb2RlOiBmaXJzdFRleHROb2RlLFxuICAgIGxhc3RUZXh0Tm9kZTogbGFzdFRleHROb2RlLFxuICAgIHRyaW1Ob2RlUmlnaHQ6IHRyaW1Ob2RlUmlnaHQsXG4gICAgdHJpbU5vZGVMZWZ0OiB0cmltTm9kZUxlZnQsXG4gICAgc3RyaXBIdG1sOiBzdHJpcEh0bWwsXG4gICAgaHRtbEVudGl0aWVzOiBodG1sRW50aXRpZXMsXG4gICAgd2Fsa1RyZWU6IHdhbGtUcmVlLFxuICAgIGNyZWF0ZVRyZWVXYWxrZXI6IGNyZWF0ZVRyZWVXYWxrZXIsXG5cbiAgICB0cmVlUGF0aE9mOiB0cmVlUGF0aE9mLFxuICAgIGdldE5vZGVBdFRyZWVQYXRoOiBnZXROb2RlQXRUcmVlUGF0aCxcbiAgICBpbnNlcnRBdFRyZWVQYXRoOiBpbnNlcnRBdFRyZWVQYXRoLFxuICAgIGlzVHJlZVBhdGhCZWZvcmU6IGlzVHJlZVBhdGhCZWZvcmUsXG5cbiAgICBnZXROb2RlV2luZG93OiBnZXROb2RlV2luZG93LFxuXG4gICAgZ2V0Q29tcG9uZW50c0Zyb21SYW5nZTogZ2V0Q29tcG9uZW50c0Zyb21SYW5nZSxcbiAgICBkZWxldGVSYW5nZVdpdGhDb21wb25lbnRzOiBkZWxldGVSYW5nZVdpdGhDb21wb25lbnRzLFxuICAgIGZvckVhY2hOb2Rlc0luUmFuZ2U6IGZvckVhY2hOb2Rlc0luUmFuZ2UsXG4gICAgYXJlUmFuZ2VzRXF1YWw6IGFyZVJhbmdlc0VxdWFsLFxuXG4gICAgYWRkRGVidWdQb2ludDogYWRkRGVidWdQb2ludFxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBkb21VdGlscztcblxuXG4vKipcbiAqIFJldHVybnMgdGhlIGxpc3Qgb2YgZWxlbWVudCBjaGlsZHJlbiBvZiBET00gZWxlbWVudFxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgZWxlbWVudCB0byByZXR1cm4gdGhlIGNoaWxkcmVuIG9mIChvbmx5IERPTSBlbGVtZW50cylcbiAqIEByZXR1cm4ge0FycmF5W0VsZW1lbnRdfVxuICovXG4gZnVuY3Rpb24gY2hpbGRyZW4oZWwpIHtcbiAgICByZXR1cm4gZmlsdGVyTm9kZUxpc3RCeVR5cGUoZWwuY2hpbGROb2RlcywgTm9kZS5FTEVNRU5UX05PREUpO1xuIH1cblxuXG4vKipcbiAqIEZpbHRlcnMgdGhlIGxpc3Qgb2Ygbm9kZXMgYnkgdHlwZVxuICpcbiAqIEBwYXJhbSB7Tm9kZUxpc3R9IG5vZGVMaXN0IHRoZSBsaXN0IG9mIG5vZGVzLCBmb3IgZXhhbXBsZSBjaGlsZE5vZGVzIHByb3BlcnR5IG9mIERPTSBlbGVtZW50XG4gKiBAcGFyYW0ge0ludGVnZXJ9IG5vZGVUeXBlIGFuIGludGVnZXIgY29uc3RhbnQgW2RlZmluZWQgYnkgRE9NIEFQSV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL05vZGUubm9kZVR5cGUpLCBlLmcuIGBOb2RlLkVMRU1FTlRfTk9ERWAgb3IgYE5vZGUuVEVYVF9OT0RFYFxuICogQHJldHVybiB7QXJyYXlbTm9kZV19XG4gKi9cbmZ1bmN0aW9uIGZpbHRlck5vZGVMaXN0QnlUeXBlKG5vZGVMaXN0LCBub2RlVHlwZSkge1xuICAgIHJldHVybiBfLmZpbHRlcihub2RlTGlzdCwgZnVuY3Rpb24gKG5vZGUpIHtcbiAgICAgICAgcmV0dXJuIG5vZGUubm9kZVR5cGUgPT0gbm9kZVR5cGU7XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBGaW5kIG5lYXJlc3QgcGFyZW50IGVsZW1lbnQgZm9yIG5vZGUuXG4gKiBJZiBub2RlIGlzIGFuIGVsZW1lbnQsIGl0IHdpbGwgYmUgcmV0dXJuZWQuXG4gKlxuICogQHBhcmFtIHtOb2RlfSBub2RlXG4gKiBAcmV0dXJuIHtFbGVtZW50fG51bGx9XG4gKi9cbmZ1bmN0aW9uIGNvbnRhaW5pbmdFbGVtZW50KG5vZGUpIHtcbiAgICB3aGlsZSAobm9kZSkge1xuICAgICAgICBpZiAobm9kZS5ub2RlVHlwZSA9PSBOb2RlLkVMRU1FTlRfTk9ERSlcbiAgICAgICAgICAgIHJldHVybiBub2RlO1xuICAgICAgICBub2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cblxuXG4vKipcbiAqIFNlbGVjdHMgaW5uZXIgY29udGVudHMgb2YgRE9NIGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsIERPTSBlbGVtZW50XG4gKi9cbmZ1bmN0aW9uIHNlbGVjdEVsZW1lbnRDb250ZW50cyhlbCkge1xuICAgIHZhciBkb2MgPSBlbC5vd25lckRvY3VtZW50O1xuICAgIGlmICghIGRvYykgcmV0dXJuIGxvZ2dlci5lcnJvcignc2VsZWN0RWxlbWVudENvbnRlbnRzOiBlbGVtZW50IGhhcyBubyBkb2N1bWVudCcpO1xuICAgIHZhciByYW5nZSA9IGRvYy5jcmVhdGVSYW5nZSgpO1xuICAgIHJhbmdlLnNlbGVjdE5vZGVDb250ZW50cyhlbCk7XG4gICAgdmFyIHdpbiA9IGdldE5vZGVXaW5kb3coZWwpXG4gICAgICAgICwgc2VsID0gd2luLmdldFNlbGVjdGlvbigpO1xuICAgIHNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICBzZWwuYWRkUmFuZ2UocmFuZ2UpO1xufVxuXG5cbi8qKlxuICogU2VsZWN0cyB0ZXh0IGluc2lkZSBlbGVtZW50XG4gKiBAcGFyYW0ge0VsZW1lbnR9IGVsXG4gKi9cbmZ1bmN0aW9uIHNlbGVjdEVsZW1lbnRUZXh0KGVsKSB7XG4gICAgdmFyIGZyb21Ob2RlID0gZmlyc3RUZXh0Tm9kZShlbClcbiAgICAgICAgLCB0b05vZGUgPSBsYXN0VGV4dE5vZGUoZWwpO1xuXG4gICAgaWYgKGZyb21Ob2RlICYmIHRvTm9kZSlcbiAgICAgICAgc2V0U2VsZWN0aW9uKGZyb21Ob2RlLCAwLCB0b05vZGUsIHRvTm9kZS50ZXh0Q29udGVudC5sZW5ndGgpO1xufVxuXG5cbi8qKlxuICogU2V0cyB0aGUgY2FyZXQgcG9zaXRpb24gdG8gdGhlIHBvc2l0aW9uIGluIHRoZSBub2RlXG4gKlxuICogQHBhcmFtIHtOb2RlfSBub2RlIERPTSBub2RlXG4gKiBAcGFyYW0ge051bWJlcn0gcG9zIGNhcmV0IHBvc2l0aW9uXG4gKi9cbmZ1bmN0aW9uIHNldENhcmV0UG9zaXRpb24obm9kZSwgcG9zKSB7XG4gICAgdmFyIGRvYyA9IG5vZGUub3duZXJEb2N1bWVudDtcbiAgICBpZiAoISBkb2MpIHJldHVybiBsb2dnZXIuZXJyb3IoJ3NldENhcmV0UG9zaXRpb246IGVsZW1lbnQgaGFzIG5vIGRvY3VtZW50Jyk7XG4gICAgdmFyIHJhbmdlID0gZG9jLmNyZWF0ZVJhbmdlKCk7XG4gICAgcmFuZ2Uuc2V0U3RhcnQobm9kZSwgcG9zKTtcbiAgICB2YXIgd2luID0gZ2V0Tm9kZVdpbmRvdyhub2RlKVxuICAgICAgICAsIHNlbCA9IHdpbi5nZXRTZWxlY3Rpb24oKTtcbiAgICBzZWwucmVtb3ZlQWxsUmFuZ2VzKCk7XG4gICAgc2VsLmFkZFJhbmdlKHJhbmdlKTtcbn1cblxuLyoqXG4gKiBnZXQgdGhlIGRpcmVjdGlvbiBvZiBhIHNlbGVjdGlvblxuICpcbiAqIDEgZm9yd2FyZCwgLTEgYmFja3dhcmQsIDAgbm8gZGlyZWN0aW9uLCB1bmRlZmluZWQgb25lIG9mIHRoZSBub2RlIGlzIGRldGFjaGVkIG9yIGluIGEgZGlmZmVyZW50IGZyYW1lXG4gKlxuICogQHBhcmFtIHtzZWx9IGEgc2VsZWN0aW9uIG9iamVjdFxuICogQHJldHVybiB7LTF8MHwxfHVuZGVmaW5lZH1cbiAqL1xuZnVuY3Rpb24gZ2V0U2VsZWN0aW9uRGlyZWN0aW9uKHNlbCl7XG4gICAgcmV0dXJuIF9nZXREaXJlY3Rpb24oc2VsLmFuY2hvck5vZGUsIHNlbC5hbmNob3JPZmZzZXQsIHNlbC5mb2N1c05vZGUsIHNlbC5mb2N1c09mZnNldCk7XG59XG5cbmZ1bmN0aW9uIF9nZXREaXJlY3Rpb24oZnJvbU5vZGUsIHN0YXJ0T2Zmc2V0LCB0b05vZGUsIGVuZE9mZnNldCl7XG4gICAgdmFyIGRvY1Bvc2l0aW9uID0gZnJvbU5vZGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24odG9Ob2RlKTtcbiAgICBpZiAoZG9jUG9zaXRpb24gJiBOb2RlLkRPQ1VNRU5UX1BPU0lUSU9OX0ZPTExPV0lORyl7XG4gICAgICAgIHJldHVybiAxO1xuICAgIH1cbiAgICBlbHNlIGlmIChkb2NQb3NpdGlvbiAmIE5vZGUuRE9DVU1FTlRfUE9TSVRJT05fUFJFQ0VESU5HKXtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cbiAgICBlbHNlIGlmIChmcm9tTm9kZSA9PSB0b05vZGUpe1xuICAgICAgICBpZiAoc3RhcnRPZmZzZXQgPCBlbmRPZmZzZXQpe1xuICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoc3RhcnRPZmZzZXQgPiBlbmRPZmZzZXQpe1xuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogU2VsZWN0cyBhIHJhbmdlIGluIGEgZG9jdW1lbnRcbiAqXG4gKiBAcGFyYW0ge05vZGV9IGZyb21Ob2RlIERPTSBub2RlIHRvIHN0YXJ0IHNlbGVjdGlvbiBpblxuICogQHBhcmFtIHtOdW1iZXJ9IHN0YXJ0T2Zmc2V0XG4gKiBAcGFyYW0ge05vZGV9IHRvTm9kZSBET00gbm9kZSB0byBlbmQgc2VsZWN0aW9uIGluXG4gKiBAcGFyYW0ge051bWJlcn0gZW5kT2Zmc2V0XG4gKi9cbmZ1bmN0aW9uIHNldFNlbGVjdGlvbihmcm9tTm9kZSwgc3RhcnRPZmZzZXQsIHRvTm9kZSwgZW5kT2Zmc2V0KSB7XG4gICAgdmFyIGRvYyA9IGZyb21Ob2RlLm93bmVyRG9jdW1lbnQ7XG4gICAgaWYgKCEgZG9jKSByZXR1cm4gbG9nZ2VyKCdzZXRDYXJldFBvc2l0aW9uOiBlbGVtZW50IGhhcyBubyBkb2N1bWVudCcpO1xuICAgIHZhciBiYWNrd2FyZCA9IF9nZXREaXJlY3Rpb24oZnJvbU5vZGUsIHN0YXJ0T2Zmc2V0LCB0b05vZGUsIGVuZE9mZnNldCkgPT0gLTE7XG4gICAgdmFyIHJhbmdlID0gZG9jLmNyZWF0ZVJhbmdlKCk7XG4gICAgdmFyIGNvbnRhaW5lciwgb3JpZ2luYWxDb250ZW50RWRpdGFibGU7XG4gICAgLy8gZG9lcyBub3Qgd29yayBpbiBub24gY29udGVudEVkaXRhYmxlIGl0ZW1zXG5cbiAgICB2YXIgd2luID0gZ2V0Tm9kZVdpbmRvdyhmcm9tTm9kZSlcbiAgICAgICAgLCBzZWwgPSB3aW4uZ2V0U2VsZWN0aW9uKCk7XG5cblxuICAgIGlmIChiYWNrd2FyZCl7XG4gICAgICAgIHJhbmdlLnNldFN0YXJ0KHRvTm9kZSwgZW5kT2Zmc2V0KTtcbiAgICAgICAgcmFuZ2Uuc2V0RW5kKGZyb21Ob2RlLCBzdGFydE9mZnNldCk7XG4gICAgICAgIHJhbmdlLmNvbGxhcHNlKGZhbHNlKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJhbmdlLnNldFN0YXJ0KGZyb21Ob2RlLCBzdGFydE9mZnNldCk7XG4gICAgICAgIHJhbmdlLnNldEVuZCh0b05vZGUsIGVuZE9mZnNldCk7XG4gICAgfVxuXG4gICAgY29udGFpbmVyID0gcmFuZ2UuY29tbW9uQW5jZXN0b3JDb250YWluZXIgPT0gTm9kZS5FTEVNRU5UX05PREUgP1xuICAgICAgICByYW5nZS5jb21tb25BbmNlc3RvckNvbnRhaW5lciA6XG4gICAgICAgIHJhbmdlLmNvbW1vbkFuY2VzdG9yQ29udGFpbmVyLnBhcmVudEVsZW1lbnQ7XG5cbiAgICBpZiAoIWNvbnRhaW5lci5pc0NvbnRlbnRFZGl0YWJsZSl7XG4gICAgICAgIG9yaWdpbmFsQ29udGVudEVkaXRhYmxlID0gY29udGFpbmVyLmNvbnRlbnRFZGl0YWJsZTsgLy8gZmFsc2Ugb3IgaW5oZXJpdFxuICAgICAgICBjb250YWluZXIuY29udGVudEVkaXRhYmxlID0gXCJ0cnVlXCI7XG4gICAgfVxuXG4gICAgc2VsLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgIHNlbC5hZGRSYW5nZShyYW5nZSk7XG5cbiAgICBpZiAoYmFja3dhcmQpe1xuICAgICAgICBzZWwuZXh0ZW5kKHRvTm9kZSwgZW5kT2Zmc2V0KTtcbiAgICB9XG5cbiAgICBpZiAob3JpZ2luYWxDb250ZW50RWRpdGFibGUpe1xuICAgICAgICAvLyByZXN0b3JpbmcgY29udGVudEVkaXRhYmxlXG4gICAgICAgIGNvbnRhaW5lci5jb250ZW50RWRpdGFibGUgPSBvcmlnaW5hbENvbnRlbnRFZGl0YWJsZTtcbiAgICB9XG59XG5cbi8qKlxuICogQ2xlYXJzIHNlbGVjdGlvbiBpbiBhIGdpdmVuIHdpbmRvd1xuICogQHBhcmFtIHtXaW5kb3d9IHdpblxuICovXG5mdW5jdGlvbiBjbGVhclNlbGVjdGlvbih3aW4pIHtcbiAgICB3aW4gPSB3aW4gfHwgd2luZG93O1xuICAgIHZhciBzZWwgPSB3aW4uZ2V0U2VsZWN0aW9uKCk7XG4gICAgc2VsLnJlbW92ZUFsbFJhbmdlcygpO1xufVxuXG5cbi8qKlxuICogQ2FsY3VsYXRlcyBhbiBlbGVtZW50J3MgdG90YWwgdG9wIGFuZCBsZWZ0IG9mZnNldCBmcm9tIHRoZSBkb2N1bWVudCBlZGdlLlxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgdGhlIGVsZW1lbnQgZm9yIHdoaWNoIHBvc2l0aW9uIG5lZWRzIHRvIGJlIHJldHVybmVkXG4gKiBAcGFyYW0ge2luY2x1ZGVCb3JkZXJ9IGlmIGlzIHRvIGluY2x1ZGUgdGhlIGJvcmRlciB3aWR0aFxuICogQHJldHVybiB7T2JqZWN0fSB2ZWN0b3Igb2JqZWN0IHdpdGggcHJvcGVydGllcyB0b3BPZmZzZXQgYW5kIGxlZnRPZmZzZXRcbiAqL1xuZnVuY3Rpb24gZ2V0RWxlbWVudE9mZnNldChlbCwgaW5jbHVkZUJvcmRlcikge1xuICAgIHZhciB5UG9zLCB4UG9zO1xuXG4gICAgeVBvcyA9IGVsLm9mZnNldFRvcDtcbiAgICB4UG9zID0gZWwub2Zmc2V0TGVmdDtcbiAgICBlbCA9IGVsLm9mZnNldFBhcmVudDtcblxuICAgIHdoaWxlIChlbCkge1xuICAgICAgICB5UG9zICs9IGVsLm9mZnNldFRvcCArIGdldEJvcmRlcihlbCwgJ0hlaWdodCcsIGluY2x1ZGVCb3JkZXIpO1xuICAgICAgICB4UG9zICs9IGVsLm9mZnNldExlZnQgKyBnZXRCb3JkZXIoZWwsICdXaWR0aCcsIGluY2x1ZGVCb3JkZXIpO1xuICAgICAgICBlbCA9IGVsLm9mZnNldFBhcmVudDtcbiAgICB9XG5cbiAgICByZXR1cm4geyB0b3BPZmZzZXQ6IHlQb3MsIGxlZnRPZmZzZXQ6IHhQb3MgfTtcbn1cblxuXG5mdW5jdGlvbiBnZXRCb3JkZXIoZWwsIHR5cGUsIGluY2x1ZGVCb3JkZXIpIHtcbiAgICBpZiAoaW5jbHVkZUJvcmRlcikge1xuICAgICAgICB2YXIgc2lkZSA9ICh0eXBlID09ICdIZWlnaHQnKSA/ICd0b3AnIDogJ2xlZnQnLFxuICAgICAgICAgICAgc3R5bGVzID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoZWwpLFxuICAgICAgICAgICAgc2lkZVZhbHVlID0gcGFyc2VJbnQoc3R5bGVzLmdldFByb3BlcnR5VmFsdWUoJ2JvcmRlci0nICsgc2lkZSArICctd2lkdGgnKSwgMTApO1xuXG4gICAgICAgIGlmIChzaWRlVmFsdWUpIHJldHVybiBzaWRlVmFsdWU7XG4gICAgfVxuICAgIHJldHVybiAwO1xufVxuXG5cbi8qKlxuICogUmVtb3ZlcyBlbGVtZW50IGZyb20gdGhlIGRvY3VtZW50XG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBlbCB0aGUgZWxlbWVudCB0byBiZSByZW1vdmVkXG4gKi9cbmZ1bmN0aW9uIHJlbW92ZUVsZW1lbnQoZWwpIHtcbiAgICB2YXIgcGFyZW50ID0gZWwucGFyZW50Tm9kZTtcbiAgICBpZiAocGFyZW50KXtcbiAgICAgICAgcGFyZW50LnJlbW92ZUNoaWxkKGVsKTtcbiAgICAgICAgcGFyZW50Lm5vcm1hbGl6ZSgpO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIFJldHVybnMgdGhlIGZpcnN0IGNoaWxkIHRleHQgbm9kZSBvZiBhbiBlbGVtZW50XG4gKlxuICogQHBhcmFtIHtFbGVtZW50fE5vZGV9IG5vZGUgdGhlIG5vZGUgdG8gYmUgc2VhcmNoZWQsIGlmIHRoZSBub2RlIGlzIHRleHQgbm9kZSB3ZSByZXR1cm4gdGhlIG5vZGUuXG4gKiBAcmV0dXJuIHtUZXh0Tm9kZX1cbiAqL1xuZnVuY3Rpb24gZmlyc3RUZXh0Tm9kZShub2RlKSB7XG4gICAgaWYgKG5vZGUubm9kZVR5cGUgPT0gTm9kZS5URVhUX05PREUpIHJldHVybiBub2RlO1xuICAgIHZhciB0cmVlV2Fsa2VyID0gY3JlYXRlVHJlZVdhbGtlcihub2RlLCBOb2RlRmlsdGVyLlNIT1dfVEVYVCk7XG4gICAgcmV0dXJuIHRyZWVXYWxrZXIuZmlyc3RDaGlsZCgpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgbGFzdCBjaGlsZCB0ZXh0IG5vZGUgb2YgYW4gZWxlbWVudFxuICpcbiAqIEBwYXJhbSB7RWxlbWVudHxOb2RlfSBub2RlIHRoZSBub2RlIHRvIGJlIHNlYXJjaGVkLCBpZiB0aGUgbm9kZSBpcyB0ZXh0IG5vZGUgd2UgcmV0dXJuIHRoZSBub2RlLlxuICogQHJldHVybiB7VGV4dE5vZGV9XG4gKi9cbmZ1bmN0aW9uIGxhc3RUZXh0Tm9kZShub2RlKSB7XG4gICAgaWYgKG5vZGUubm9kZVR5cGUgPT0gTm9kZS5URVhUX05PREUpIHJldHVybiBub2RlO1xuICAgIHZhciB0cmVlV2Fsa2VyID0gY3JlYXRlVHJlZVdhbGtlcihub2RlLCBOb2RlRmlsdGVyLlNIT1dfVEVYVCk7XG4gICAgcmV0dXJuIHRyZWVXYWxrZXIubGFzdENoaWxkKCk7XG59XG5cblxuLyoqXG4gKiBSZW1vdmVzIGVsZW1lbnQgZnJvbSB0aGUgZG9jdW1lbnQgcHV0dGluZyBpdHMgY2hpbGRyZW4gaW4gaXRzIHBsYWNlXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSBlbCB0aGUgZWxlbWVudCB0byBiZSBcInVud3JhcHBlZFwiXG4gKi9cbmZ1bmN0aW9uIHVud3JhcEVsZW1lbnQoZWwpIHtcbiAgICB2YXIgcGFyZW50ID0gZWwucGFyZW50Tm9kZTtcblxuICAgIGlmIChwYXJlbnQpIHtcbiAgICAgICAgdmFyIGZyYWcgPSBkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7XG4gICAgICAgIC8vIG11c3QgYmUgY29waWVkIHRvIGF2b2lkIGl0ZXJhdGluZyBhIG11dGF0aW5nIGxpc3Qgb2YgY2hpbGROb2Rlc1xuICAgICAgICB2YXIgY2hpbGRyZW4gPSBfLnNsaWNlKGVsLmNoaWxkTm9kZXMpO1xuICAgICAgICBjaGlsZHJlbi5mb3JFYWNoKGZyYWcuYXBwZW5kQ2hpbGQsIGZyYWcpO1xuICAgICAgICBwYXJlbnQucmVwbGFjZUNoaWxkKGZyYWcsIGVsKTtcbiAgICAgICAgcGFyZW50Lm5vcm1hbGl6ZSgpO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIFdyYXBzIGFuIGVsZW1lbnQgaW4gYW5vdGhlciBlbGVtZW50XG4gKlxuICogQHBhcmFtICB7RWxlbWVudH0gd3JhcEludG9FbFxuICogQHBhcmFtICB7RWxlbWVudH0gZWxcbiAqL1xuZnVuY3Rpb24gd3JhcEluRWxlbWVudCh3cmFwSW50b0VsLCBlbCkge1xuICAgIHZhciBwYXJlbnQgPSBlbC5wYXJlbnROb2RlO1xuXG4gICAgaWYgKHBhcmVudCkge1xuICAgICAgICBwYXJlbnQuaW5zZXJ0QmVmb3JlKHdyYXBJbnRvRWwsIGVsKTtcbiAgICAgICAgd3JhcEludG9FbC5hcHBlbmRDaGlsZChlbCk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogVHJpbXMgYSB0ZXh0IG5vZGUgb2YgdHJhaWxpbmcgc3BhY2VzLCBhbmQgcmV0dXJucyB0cnVlIGlmIGEgdHJpbSB3YXMgcGVyZm9ybWVkLlxuICpcbiAqIEBwYXJhbSAge1RleHROb2RlfSBub2RlXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiB0cmltTm9kZVJpZ2h0KG5vZGUpIHtcbiAgICByZXR1cm4gX3RyaW1Ob2RlKG5vZGUsICd0cmltUmlnaHQnKTtcbn1cblxuXG4vKipcbiAqIFRyaW1zIGEgdGV4dCBub2RlIG9mIGxlYWRpbmcgc3BhY2VzLCBhbmQgcmV0dXJucyB0cnVlIGlmIGEgdHJpbSB3YXMgcGVyZm9ybWVkLlxuICpcbiAqIEBwYXJhbSAge1RleHROb2RlfSBub2RlXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiB0cmltTm9kZUxlZnQobm9kZSkge1xuICAgIHJldHVybiBfdHJpbU5vZGUobm9kZSwgJ3RyaW1MZWZ0Jyk7XG59XG5cblxuZnVuY3Rpb24gX3RyaW1Ob2RlKG5vZGUsIG1ldGhvZE5hbWUpIHtcbiAgICB2YXIgbGVuID0gbm9kZS5sZW5ndGg7XG4gICAgbm9kZS50ZXh0Q29udGVudCA9IG5vZGUudGV4dENvbnRlbnRbbWV0aG9kTmFtZV0oKTtcbiAgICByZXR1cm4gbGVuICE9PSBub2RlLmxlbmd0aDtcbn1cblxuXG4vKipcbiAqIFJlbW92ZXMgdGhlIHJlZmVyZW5jZSB0byBjb21wb25lbnQgZnJvbSBlbGVtZW50XG4gKlxuICogQHBhcmFtICB7RWxlbWVudH0gZWxcbiAqL1xuZnVuY3Rpb24gZGV0YWNoQ29tcG9uZW50KGVsKSB7XG4gICAgZGVsZXRlIGVsW2NvbmZpZy5jb21wb25lbnRSZWZdO1xufVxuXG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBjb250ZW50IG9mIGEgaHRtbCBzdHJpbmdcbiAqIEBwYXJhbSAge1N0cmluZ30gc3RyIEFueSBzdHJpbmdcbiAqIEByZXR1cm4ge1N0cmluZ30gcmV0dXJucyB0aGUgc3RyaW5nIGNsZWFuZWQgb2YgYW55IGh0bWwgY29udGVudC5cbiAqL1xuZnVuY3Rpb24gc3RyaXBIdG1sKHN0cikge1xuICAgIHZhciBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdESVYnKTtcbiAgICBkaXYuaW5uZXJIVE1MID0gc3RyO1xuICAgIHJldHVybiBkaXYudGV4dENvbnRlbnQgfHwgJyc7XG59XG5cblxuLyoqXG4gKiBDb252ZW5pZW5jZSB3cmFwcGVyIGZvciBuYXRpdmUgVHJlZVdhbGtlciB0aGF0IGF1dG9tYXRpY2FsbHkgd2Fsa3MgdGhlIHRyZWUgYW5kIGNhbGxzIGFuIGl0ZXJhdG9yIGZ1bmN0aW9uLlxuICogVGhpcyB3aWxsIG5vdCBpdGVyYXRlIHRoZSByb290IGVsZW1lbnQuXG4gKiBAcGFyYW0gIHtIVE1MRWxlbWVudH0gcm9vdCBUaGUgY29udGFpbmluZyByb290IGVsZW1lbnQgdG8gYmUgd2Fsa2VkLiBXaWxsIG5vdCBiZSBpdGVyYXRlZC5cbiAqIEBwYXJhbSAge05vZGVGaWxlcn0gZmlsdGVyIEEgTm9kZUZpbHRlciBjb25zdGFudCwgc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuL2RvY3MvV2ViL0FQSS9UcmVlV2Fsa2VyXG4gKiBAcGFyYW0gIHtGdW5jdGlvbn0gaXRlcmF0b3IgQSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgb24gZWFjaCBub2RlLiBSZXR1cm5pbmcgJ2ZhbHNlJyB3aWxsIGJyZWFrLlxuICogQHBhcmFtICB7T2JqZWN0fSBjb250ZXh0IEFuIG9wdGlvbmFsIGNvbnRleHQgdG8gcGFzc2VkLCBkZWZhdWx0cyB0byByb290LlxuICovXG5mdW5jdGlvbiB3YWxrVHJlZShyb290LCBmaWx0ZXIsIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgdmFyIHR3ID0gZG9jdW1lbnQuY3JlYXRlVHJlZVdhbGtlcihyb290LCBmaWx0ZXIpO1xuICAgIHdoaWxlKHR3Lm5leHROb2RlKCkpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IGl0ZXJhdG9yLmNhbGwoY29udGV4dCB8fCByb290LCB0dy5jdXJyZW50Tm9kZSk7XG4gICAgICAgIGlmIChyZXN1bHQgPT09IGZhbHNlKSBicmVhaztcbiAgICB9XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGFycmF5IG9mIGNoaWxkIGluZGV4ZXMgb2YgZWxlbWVudCBwYXRoIGluc2lkZSByb290IGVsZW1lbnQgaW4gRE9NIHRyZWUgdXNpbmcgYnJlYWR0aCBmaXJzdCB0cmVlIHRyYXZlcnNhbC5cbiAqIFJldHVybnMgdW5kZWZpbmVkIGlmIHRoZSBlbGVtZW50IGlzIG5vdCBpbnNpZGUgcm9vdCBlbGVtZW50LCAwIGlmIHRoZSByb290IGVsZW1lbnQgaXRzZWxmIGlzIHBhc3NlZC5cbiAqXG4gKiBAcGFyYW0gIHtFbGVtZW50fSByb290RWwgZWxlbWVudCB0byBzZWFyY2hcbiAqIEBwYXJhbSAge0VsZW1lbnR9IGVsIGVsZW1lbnQgdG8gZmluZCB0aGUgaW5kZXggb2ZcbiAqIEByZXR1cm4ge0FycmF5W051bWJlcl19XG4gKi9cbmZ1bmN0aW9uIHRyZWVQYXRoT2Yocm9vdEVsLCBlbCkge1xuICAgIGlmICghIChyb290RWwgJiYgcm9vdEVsLmNvbnRhaW5zKGVsKSkpIHJldHVybjtcblxuICAgIHZhciB0cmVlUGF0aCA9IFtdXG4gICAgICAgICwgbm9kZSA9IHJvb3RFbDtcblxuICAgIHdoaWxlIChub2RlICE9IGVsKSB7XG4gICAgICAgIHZhciBub2RlSW5kZXggPSBfLmZpbmRJbmRleChub2RlLmNoaWxkTm9kZXMsIGNvbnRhaW5zRWwpO1xuICAgICAgICB0cmVlUGF0aC5wdXNoKG5vZGVJbmRleCk7XG4gICAgICAgIG5vZGUgPSBub2RlLmNoaWxkTm9kZXNbbm9kZUluZGV4XTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJlZVBhdGg7XG5cbiAgICBmdW5jdGlvbiBjb250YWluc0VsKGNoaWxkKSB7XG4gICAgICAgIHJldHVybiBjaGlsZC5jb250YWlucyhlbCk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogUmV0dXJucyBlbGVtZW50IGF0IGdpdmVuIHRyZWUgcGF0aFxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gcm9vdEVsXG4gKiBAcGFyYW0ge0FycmF5W051bWJlcl19IHRyZWVQYXRoXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG5lYXJlc3QgcmV0dXJuIG5lYXJlc3QgcG9zc2libGUgbm9kZSBpZiBleGFjdCBub2RlIGRvZXMgbm90IGV4aXN0XG4gKiBAcmV0dXJuIHtOb2RlfVxuICovXG5mdW5jdGlvbiBnZXROb2RlQXRUcmVlUGF0aChyb290RWwsIHRyZWVQYXRoLCBuZWFyZXN0KSB7XG4gICAgaWYgKCF0cmVlUGF0aCkgcmV0dXJuO1xuXG4gICAgdmFyIGxlbiA9IHRyZWVQYXRoLmxlbmd0aDtcbiAgICBpZiAobGVuID09PSAwKSByZXR1cm4gcm9vdEVsO1xuXG4gICAgdmFyIG5vZGUgPSByb290RWw7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIHZhciBjaGlsZHJlbiA9IG5vZGUuY2hpbGROb2RlcztcbiAgICAgICAgaWYgKCEgY2hpbGRyZW4pIHtcbiAgICAgICAgICAgIGlmICghIG5lYXJlc3QpIG5vZGUgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICB2YXIgY2hpbGRJbmRleCA9IHRyZWVQYXRoW2ldXG4gICAgICAgICAgICAsIGNoaWxkID0gY2hpbGRyZW5bY2hpbGRJbmRleF07XG4gICAgICAgIGlmICghIGNoaWxkKSB7XG4gICAgICAgICAgICBub2RlID0gbmVhcmVzdFxuICAgICAgICAgICAgICAgICAgICA/IGNoaWxkcmVuW2NoaWxkcmVuLmxlbmd0aCAtIDFdXG4gICAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgbm9kZSA9IGNoaWxkO1xuICAgIH1cblxuICAgIHJldHVybiBub2RlO1xufVxuXG5cbi8qKlxuICogSW5zZXJ0cyBhbiBlbGVtZW50IGluc2lkZSByb290IGF0IGEgZ2l2ZW4gcGF0aCBpbiB0cmVlICh0aGF0IGhhcyB0aGUgc2FtZSBtZWFuaW5nIGFzIHRoZSBpbmRleCByZXR1cm5lZCBieSBgdHJlZVBhdGhPZmAgZnVuY3Rpb24pLiBJZiBlbGVtZW50IGlzIGFscmVhZHkgaW4gdGhlIHJvb3QncyB0cmVlLCBpdCB3aWxsIGJlIHJlbW92ZWQgZmlyc3QgYW5kIHRoZW4gbW92ZWQgdG8gdGhlIHBhc3NlZCB0cmVlSW5kZXhcbiAqIEluc2VydGlvbiBhdCBpbmRleCAwIGlzIG5vdCBwb3NzaWJsZSBhbmQgd2lsbCByZXR1cm4gdW5kZWZpbmVkIGFzIGl0IHdvdWxkIG1lYW4gcmVwbGFjaW5nIHRoZSByb290IGVsZW1lbnQuXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fSByb290RWwgZWxlbWVudCBpbnRvIHdoaWNoIHRvIGluc2VydFxuICogQHBhcmFtIHtOdW1iZXJ9IHRyZWVJbmRleCBpbmRleCBpbiBET00gdHJlZSBpbnNpZGUgcm9vdCBlbGVtZW50IChzZWUgdHJlZVBhdGhPZilcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgZWxlbWVudCB0byBiZSBpbnNlcnRlZFxuICogQHJldHVybiB7Qm9vbGVhbn0gdHJ1ZSBpZiB3YXMgc3VjY2Vzc2Z1bGx5IGluc2VydGVkXG4gKi9cbmZ1bmN0aW9uIGluc2VydEF0VHJlZVBhdGgocm9vdEVsLCB0cmVlUGF0aCwgZWwsIG5lYXJlc3QpIHtcbiAgICB2YXIgdG9Ob3JtYWxpemUgPSBlbC5ub2RlVHlwZSA9PSBOb2RlLlRFWFRfTk9ERTtcbiAgICBpZiAocm9vdEVsLmNvbnRhaW5zKGVsKSlcbiAgICAgICAgcmVtb3ZlRWxlbWVudChlbCk7IC8vIGNhbid0IHVzZSByZW1vdmVDaGlsZCBhcyByb290RWwgaGVyZSBpcyBub3QgYW4gaW1tZWRpYXRlIHBhcmVudFxuXG4gICAgaWYgKHRyZWVQYXRoLmxlbmd0aCA9PSAwKSByZXR1cm47XG5cbiAgICB2YXIgcGFyZW50ID0gZ2V0Tm9kZUF0VHJlZVBhdGgocm9vdEVsLCB0cmVlUGF0aC5zbGljZSgwLCAtMSksIG5lYXJlc3QpXG4gICAgICAgICwgY2hpbGRyZW4gPSBwYXJlbnQuY2hpbGROb2RlcztcblxuICAgIGlmICghIGNoaWxkcmVuKSB7XG4gICAgICAgIGlmIChuZWFyZXN0KSB7XG4gICAgICAgICAgICBwYXJlbnQgPSBwYXJlbnQucGFyZW50Tm9kZTtcbiAgICAgICAgICAgIGNoaWxkcmVuID0gcGFyZW50LmNoaWxkTm9kZXM7XG4gICAgICAgIH0gZWxzZSByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGNoaWxkSW5kZXggPSB0cmVlUGF0aFt0cmVlUGF0aC5sZW5ndGggLSAxXVxuICAgICAgICAsIGNoaWxkID0gY2hpbGRyZW5bY2hpbGRJbmRleF07XG5cbiAgICBpZiAoY2hpbGQpIHtcbiAgICAgICAgcGFyZW50Lmluc2VydEJlZm9yZShlbCwgY2hpbGQpO1xuICAgICAgICBpZiAodG9Ob3JtYWxpemUpIHBhcmVudC5ub3JtYWxpemUoKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIGlmIChjaGlsZHJlbi5sZW5ndGggPT09IDAgJiYgKGNoaWxkSW5kZXggPT09IDAgfHwgbmVhcmVzdCkpIHtcbiAgICAgICAgcGFyZW50LmFwcGVuZENoaWxkKGVsKTtcbiAgICAgICAgaWYgKHRvTm9ybWFsaXplKSBwYXJlbnQubm9ybWFsaXplKCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGNoaWxkID0gY2hpbGRyZW5bY2hpbGRJbmRleCAtIDFdO1xuICAgICAgICBpZiAoY2hpbGQgfHwgbmVhcmVzdCkge1xuICAgICAgICAgICAgcGFyZW50LmFwcGVuZENoaWxkKGVsKTtcbiAgICAgICAgICAgIGlmICh0b05vcm1hbGl6ZSkgcGFyZW50Lm5vcm1hbGl6ZSgpO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgZmlyc3QgdHJlZSBwYXRoIHBvaW50cyB0byBhIG5vZGUgd2hpY2ggaXMgYmVmb3JlIHRoZSBvdGhlciBpbiB0aGUgZG9jdW1lbnQgb3JkZXIuXG4gKiBAcGFyYW0gIHtBcnJheX0gIHBhdGgxICAgQSB0cmVlcGF0aCBhcnJheVxuICogQHBhcmFtICB7QXJyYXl9ICBwYXRoMiAgIEEgdHJlZXBhdGggYXJyYXlcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIGlzVHJlZVBhdGhCZWZvcmUocGF0aDEsIHBhdGgyKSB7XG4gICAgdmFyIGkgPSAwXG4gICAgICAgICwgaXNCZWZvcmU7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHBhdGgxKSAmJiBBcnJheS5pc0FycmF5KHBhdGgyKSlcbiAgICAgICAgcmV0dXJuIGxvZ2dlci5lcnJvcignaXNUcmVlUGF0aEJlZm9yZTogT25lIG9yIGJvdGggcGF0aHMgYXJlIG5vdCB2YWxpZCB0cmVlcGF0aCBhcnJheXMuJyk7XG5cbiAgICBmb3IgKGk7IGkgPCBwYXRoMS5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAocGF0aDFbaV0gPCBwYXRoMltpXSkge1xuICAgICAgICAgICAgaXNCZWZvcmUgPSB0cnVlO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gZWxzZSBpZiAocGF0aDFbaV0gPiBwYXRoMltpXSkge1xuICAgICAgICAgICAgaXNCZWZvcmUgPSBmYWxzZTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBpc0JlZm9yZSA9PSAndW5kZWZpbmVkJylcbiAgICAgICAgaWYgKHBhdGgxLmxlbmd0aCA8IHBhdGgyLmxlbmd0aClcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKCdpc1RyZWVQYXRoQmVmb3JlOiBPbmUgbm9kZSBpcyBpbnNpZGUgYW5vdGhlcicpO1xuXG4gICAgcmV0dXJuIGlzQmVmb3JlIHx8IGZhbHNlO1xufVxuXG5cbi8qKlxuICogQ29udmVydHMgbm9uIGxhdGluIGNoYXJhY3RlcnMgdG8gSFRNTCBlbnRpdHkgY29kZXMuXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHN0ciB0aGUgc3RyaW5nIHRvIGNvbnZlcnRcbiAqIEByZXR1cm4ge1N0cmluZ30gICAgIHRoZSBzdHJpbmcgd2l0aCBodG1sIGVudGl0aWVzXG4gKi9cbmZ1bmN0aW9uIGh0bWxFbnRpdGllcyhzdHIpIHtcbiAgICByZXR1cm4gc3RyLnJlcGxhY2UoL1tcXHUwMEEwLVxcdTk5OTk5PD5cXCZdL2dpbSwgZnVuY3Rpb24oaSkge1xuICAgICAgICByZXR1cm4gJyYjJytpLmNoYXJDb2RlQXQoMCkrJzsnO1xuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIGNyZWF0ZVRyZWVXYWxrZXIoZWwsIHdoYXRUb1Nob3cpIHtcbiAgICB3aGF0VG9TaG93ID0gd2hhdFRvU2hvdyB8fCAoTm9kZUZpbHRlci5TSE9XX1RFWFQgfCBOb2RlRmlsdGVyLlNIT1dfRUxFTUVOVCk7XG4gICAgcmV0dXJuIGRvY3VtZW50LmNyZWF0ZVRyZWVXYWxrZXIoZWwsIHdoYXRUb1Nob3cpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgcmVmZXJlbmNlIHRvIHRoZSB3aW5kb3cgdGhlIG5vZGUgaXMgaW5cbiAqXG4gKiBAcGFyYW0ge05vZGV9IG5vZGVcbiAqIEByZXR1cm4ge1dpbmRvd31cbiAqL1xuZnVuY3Rpb24gZ2V0Tm9kZVdpbmRvdyhub2RlKSB7XG4gICAgdmFyIGRvYyA9IG5vZGUub3duZXJEb2N1bWVudDtcbiAgICByZXR1cm4gZG9jICYmIChkb2MuZGVmYXVsdFZpZXcgfHwgZG9jLnBhcmVudFdpbmRvdyk7XG59XG5cblxuXG4vKipcbiAqIGRvIHNvbWV0aGluZyBmb3IgZWFjaCBub2RlcyBjb250YWluZWQgaW4gYSByYW5nZVxuICpcbiAqIEBwYXJhbSB7cmFuZ2V9IGEgcmFuZ2VcbiAqIEBwYXJhbSB7Y2J9IGEgZnVuY3Rpb24gdGFraW5nIGEgbm9kZSBhcyBhcmd1bWVudFxuXG4gKi9cbmZ1bmN0aW9uIGZvckVhY2hOb2Rlc0luUmFuZ2UocmFuZ2UsIGNiKXtcbiAgICB2YXIgcmFuZ2VDb250YWluZXIgPSByYW5nZS5jb21tb25BbmNlc3RvckNvbnRhaW5lclxuICAgICAgICAsIGRvYyA9IHJhbmdlQ29udGFpbmVyLm93bmVyRG9jdW1lbnQ7XG5cbiAgICBmdW5jdGlvbiBpc05vZGVJbnNpZGVSYW5nZShub2RlKXtcbiAgICAgICAgdmFyIG5vZGVSYW5nZSA9IGRvY3VtZW50LmNyZWF0ZVJhbmdlKCk7XG4gICAgICAgIHZhciBpc0luc2lkZSA9IGZhbHNlO1xuICAgICAgICBub2RlUmFuZ2Uuc2VsZWN0Tm9kZShub2RlKTtcblxuICAgICAgICBpZiAobm9kZVJhbmdlLmNvbXBhcmVCb3VuZGFyeVBvaW50cyh3aW5kb3cuUmFuZ2UuU1RBUlRfVE9fU1RBUlQsIHJhbmdlKSAhPSAtMVxuICAgICAgICAgICAgJiYgbm9kZVJhbmdlLmNvbXBhcmVCb3VuZGFyeVBvaW50cyh3aW5kb3cuUmFuZ2UuRU5EX1RPX0VORCwgcmFuZ2UpICE9IDEpe1xuICAgICAgICAgICAgaXNJbnNpZGUgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIG5vZGVSYW5nZS5kZXRhY2goKTtcbiAgICAgICAgcmV0dXJuIGlzSW5zaWRlO1xuICAgIH1cblxuICAgIHZhciB0cmVlV2Fsa2VyID0gZG9jLmNyZWF0ZVRyZWVXYWxrZXIocmFuZ2VDb250YWluZXIsXG4gICAgICAgICAgICBOb2RlRmlsdGVyLlNIT1dfRUxFTUVOVCB8IE5vZGVGaWx0ZXIuU0hPV19URVhUKTtcblxuICAgIHZhciBjdXJyZW50Tm9kZTtcbiAgICB3aGlsZSAoY3VycmVudE5vZGUgPSB0cmVlV2Fsa2VyLm5leHROb2RlKCkpeyAvLyBzaG91bGQgYmUgYXNzaWdubWVudFxuICAgICAgICBpZiAoaXNOb2RlSW5zaWRlUmFuZ2UoY3VycmVudE5vZGUpKXtcbiAgICAgICAgICAgIGNiKGN1cnJlbnROb2RlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuLyoqXG4gKiBnZXQgYWxsIGNvbXBvbmVudHMgY29udGFpbmVkIGluIGEgcmFuZ2VcbiAqXG4gKiBAcGFyYW0ge3JhbmdlfSBhIERPTSByYW5nZS5cbiAqL1xuZnVuY3Rpb24gZ2V0Q29tcG9uZW50c0Zyb21SYW5nZShyYW5nZSkge1xuICAgIHZhciB3aW4gPSBnZXROb2RlV2luZG93KHJhbmdlLnN0YXJ0Q29udGFpbmVyKVxuICAgICAgICAsIENvbXBvbmVudCA9IHdpbi5taWxvLkNvbXBvbmVudDtcblxuICAgIHZhciBjb21wb25lbnRzID0gW107XG4gICAgZm9yRWFjaE5vZGVzSW5SYW5nZShyYW5nZSwgZnVuY3Rpb24gKG5vZGUpe1xuICAgICAgICBpZiAobm9kZS5ub2RlVHlwZSAhPSBOb2RlLlRFWFRfTk9ERSkge1xuICAgICAgICAgICAgdmFyIGNvbXAgPSBDb21wb25lbnQuZ2V0Q29tcG9uZW50KG5vZGUpO1xuICAgICAgICAgICAgaWYgKGNvbXApXG4gICAgICAgICAgICAgICAgY29tcG9uZW50cy5wdXNoKGNvbXApO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gY29tcG9uZW50cztcbn1cblxuLyoqXG4gKiBkZWxldGUgYSByYW5nZVxuICpcbiAqIEBwYXJhbSB7cmFuZ2V9IGRlbGV0ZSBhIERPTSByYW5nZSBhbmQgYWxsIHRoZSBjb21wb25lbnRzIGluc2lkZVxuICovXG5mdW5jdGlvbiBkZWxldGVSYW5nZVdpdGhDb21wb25lbnRzKHJhbmdlKSB7XG4gICAgdmFyIGNvbXBvbmVudHMgPSBnZXRDb21wb25lbnRzRnJvbVJhbmdlKHJhbmdlKTtcblxuICAgIGNvbXBvbmVudHMuZm9yRWFjaChmdW5jdGlvbihjb21wKSB7XG4gICAgICAgIGNvbXAuZGVzdHJveSh0cnVlKTtcbiAgICB9KTtcblxuICAgIHJhbmdlLmRlbGV0ZUNvbnRlbnRzKCk7XG59XG5cbi8qKlxuICogY2hlY2sgaWYgdHdvIHJhbmdlcyBhcmUgZXF1aXZhbGVudFxuICpcbiAqIEBwYXJhbSB7cmFuZ2V9IHJhbmdlMVxuICogQHBhcmFtIHtyYW5nZX0gcmFuZ2UyXG4gKiBAcmV0dXJuIHtCb29sZWFufSBhcmUgdGhlIHR3byByYW5nZXMgZXF1aXZhbGVudFxuICovXG5mdW5jdGlvbiBhcmVSYW5nZXNFcXVhbChyYW5nZTEsIHJhbmdlMil7XG4gICAgcmV0dXJuIHJhbmdlMS5jb21wYXJlQm91bmRhcnlQb2ludHMod2luZG93LlJhbmdlLlNUQVJUX1RPX1NUQVJULCByYW5nZTIpID09IDAgJiYgcmFuZ2UxLmNvbXBhcmVCb3VuZGFyeVBvaW50cyh3aW5kb3cuUmFuZ2UuRU5EX1RPX0VORCwgcmFuZ2UyKSA9PSAwO1xufVxuXG5cbi8qKlxuICogQWRkcyBhIHNpbmdsZSBwaXhlbCBkaXYgdG8gdGhlIGJvZHkgYXQgYSBnaXZlbiB4IGFuZCB5IHBvc2l0aW9uLiBVc2VmdWwgZm9yIGRlYnVnZ2luZyBwb3NpdGlvbiBzcGVjaWZpYyBjb2RlLlxuICogQHBhcmFtIHtOdW1iZXJ9IHhcbiAqIEBwYXJhbSB7TnVtYmVyfSB5XG4gKi9cbmZ1bmN0aW9uIGFkZERlYnVnUG9pbnQoeCwgeSkge1xuICAgIHZhciBkYkVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgZGJFbC5zZXRBdHRyaWJ1dGUoJ3N0eWxlJywgJ3dpZHRoOiAxcHg7IGhlaWdodDogMXB4OyBwb3NpdGlvbjpmaXhlZDsgbGVmdDonK3grJ3B4OyB0b3A6Jyt5KydweDsgYmFja2dyb3VuZC1jb2xvcjpyZWQ7IHotaW5kZXg6IDEwMCcpO1xuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChkYkVsKTt9LCAyMDApO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBfID0gcmVxdWlyZSgnbWlsby1jb3JlJykucHJvdG87XG5cblxubW9kdWxlLmV4cG9ydHMgPSBET01MaXN0ZW5lcnM7XG5cblxuZnVuY3Rpb24gRE9NTGlzdGVuZXJzKCkge1xuICAgIHRoaXMubGlzdGVuZXJzID0gW107XG59XG5cblxuXy5leHRlbmRQcm90byhET01MaXN0ZW5lcnMsIHtcbiAgICBhZGQ6IERPTUxpc3RlbmVycyRhZGQsXG4gICAgcmVtb3ZlOiBET01MaXN0ZW5lcnMkcmVtb3ZlLFxuICAgIHJlbW92ZUFsbDogRE9NTGlzdGVuZXJzJHJlbW92ZUFsbFxufSk7XG5cblxuZnVuY3Rpb24gRE9NTGlzdGVuZXJzJGFkZCh0YXJnZXQsIGV2ZW50VHlwZSwgaGFuZGxlcikge1xuICAgIHRoaXMubGlzdGVuZXJzLnB1c2goe1xuICAgICAgICB0YXJnZXQ6IHRhcmdldCxcbiAgICAgICAgZXZlbnRUeXBlOiBldmVudFR5cGUsXG4gICAgICAgIGhhbmRsZXI6IGhhbmRsZXJcbiAgICB9KTtcbiAgICB0YXJnZXQuYWRkRXZlbnRMaXN0ZW5lcihldmVudFR5cGUsIGhhbmRsZXIpO1xufVxuXG5cbmZ1bmN0aW9uIERPTUxpc3RlbmVycyRyZW1vdmUodGFyZ2V0LCBldmVudFR5cGUsIGhhbmRsZXIpIHtcbiAgICB2YXIgbGlzdGVuZXIgPSB7XG4gICAgICAgIHRhcmdldDogdGFyZ2V0LFxuICAgICAgICBldmVudFR5cGU6IGV2ZW50VHlwZSxcbiAgICAgICAgaGFuZGxlcjogaGFuZGxlclxuICAgIH07XG4gICAgdmFyIGlkeCA9IF8uZmluZEluZGV4KHRoaXMubGlzdGVuZXJzLCBfLnBhcnRpYWwoXy5pc0VxdWFsLCBsaXN0ZW5lcikpO1xuXG4gICAgaWYgKGlkeCA+IC0xKSB7XG4gICAgICAgIHRoaXMubGlzdGVuZXJzLnNwbGljZShpZHgsIDEpO1xuICAgICAgICBfcmVtb3ZlTGlzdGVuZXIobGlzdGVuZXIpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBET01MaXN0ZW5lcnMkcmVtb3ZlQWxsKCkge1xuICAgIHRoaXMubGlzdGVuZXJzLmZvckVhY2goX3JlbW92ZUxpc3RlbmVyKTtcbiAgICB0aGlzLmxpc3RlbmVycyA9IFtdO1xufVxuXG5cbmZ1bmN0aW9uIF9yZW1vdmVMaXN0ZW5lcihsKSB7XG4gICAgbC50YXJnZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcihsLmV2ZW50VHlwZSwgbC5oYW5kbGVyKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgXyA9IHJlcXVpcmUoJ21pbG8tY29yZScpLnByb3RvO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gZG9tUmVhZHk7XG5cblxudmFyIGRvbVJlYWR5RnVuY3MgPSBbXVxuICAgICwgZG9tUmVhZHlTdWJzY3JpYmVkID0gZmFsc2U7XG5cblxuZnVuY3Rpb24gZG9tUmVhZHkoZnVuYykgeyAvLyAsIGFyZ3VtZW50c1xuICAgIHZhciBzZWxmID0gdGhpc1xuICAgICAgICAsIGFyZ3MgPSBfLnNsaWNlKGFyZ3VtZW50cywgMSk7XG4gICAgaWYgKGlzUmVhZHkuY2FsbCh0aGlzKSlcbiAgICAgICAgY2FsbEZ1bmMoKTtcbiAgICBlbHNlIHtcbiAgICAgICAgaWYgKCFkb21SZWFkeVN1YnNjcmliZWQpIHtcbiAgICAgICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3JlYWR5c3RhdGVjaGFuZ2UnLCBvbkRvbVJlYWR5KTtcbiAgICAgICAgICAgIGRvbVJlYWR5U3Vic2NyaWJlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgZG9tUmVhZHlGdW5jcy5wdXNoKGNhbGxGdW5jKTsgLy8gY2xvc3VyZSBpcyBhZGRlZCwgc28gZXZlcnkgdGltZSBkaWZmZXJlbnQgZnVuY3Rpb24gd2lsbCBiZSBjYWxsZWRcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjYWxsRnVuYygpIHtcbiAgICAgICAgZnVuYy5hcHBseShzZWxmLCBhcmdzKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gb25Eb21SZWFkeSgpIHtcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdyZWFkeXN0YXRlY2hhbmdlJywgb25Eb21SZWFkeSk7XG4gICAgZG9tUmVhZHlGdW5jcy5mb3JFYWNoKGZ1bmN0aW9uKGZ1bmMpIHsgZnVuYygpOyB9KTtcbn1cblxuXG5fLmV4dGVuZChkb21SZWFkeSwge1xuICAgIGlzUmVhZHk6IGlzUmVhZHlcbn0pO1xuXG5cbmZ1bmN0aW9uIGlzUmVhZHkoKSB7XG4gICAgdmFyIHJlYWR5U3RhdGUgPSBkb2N1bWVudC5yZWFkeVN0YXRlO1xuICAgIHJldHVybiByZWFkeVN0YXRlID09ICdsb2FkaW5nJyA/IGZhbHNlIDogcmVhZHlTdGF0ZTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uL2NvbXBvbmVudHMvY19jbGFzcycpXG4gICAgLCBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNZXNzZW5nZXIgPSBtaWxvQ29yZS5NZXNzZW5nZXJcbiAgICAsIGRyYWdEcm9wQ29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJykuZHJhZ0Ryb3BcbiAgICAsIGNvbXBvbmVudE1ldGFSZWdleCA9IGRyYWdEcm9wQ29uZmlnLmRhdGFUeXBlcy5jb21wb25lbnRNZXRhUmVnZXhcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgYmFzZTMyID0gcmVxdWlyZSgnYmFzZTMyJyk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBEcmFnRHJvcDtcblxuXG4vKipcbiAqIFdyYXBwZXIgZm9yIGV2ZW50LmRhdGFUcmFuc2ZlciBvZiBkcmFnLWRyb3AgSFRNTCBBUElcbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqIEBwYXJhbSB7ZXZlbnR9IERPTSBldmVudFxuICogQHJldHVybiB7RHJhZ0Ryb3B9XG4gKi9cbmZ1bmN0aW9uIERyYWdEcm9wKGV2ZW50KSB7XG4gICAgdGhpcy5ldmVudCA9IGV2ZW50O1xuICAgIHRoaXMuZGF0YVRyYW5zZmVyID0gZXZlbnQuZGF0YVRyYW5zZmVyO1xuICAgIHRoaXMudHlwZXMgPSBldmVudC5kYXRhVHJhbnNmZXIudHlwZXM7XG59XG5cbi8qKlxuICogVXNhZ2U6XG4gKiB2YXIgdGVzdERUID0gbmV3IERyYWdEcm9wKGV2ZW50KTtcbiAqIHRlc3REVC5zZXRDb21wb25lbnRNZXRhKG5ld0NvbXBvbmVudCwge3Rlc3Q6ICd0ZXN0JywgdGVzdDI6ICd0ZXN0Mid9KTtcbiAqIHRlc3REVC5nZXRDb21wb25lbnRNZXRhKCk7XG4gKi9cblxuXy5leHRlbmQoRHJhZ0Ryb3AsIHtcbiAgICBjb21wb25lbnREYXRhVHlwZTogRHJhZ0Ryb3AkJGNvbXBvbmVudERhdGFUeXBlXG59KTtcblxuXy5leHRlbmRQcm90byhEcmFnRHJvcCwge1xuICAgIGlzQ29tcG9uZW50OiBEcmFnRHJvcCRpc0NvbXBvbmVudCxcbiAgICBnZXRDb21wb25lbnRTdGF0ZTogRHJhZ0Ryb3AkZ2V0Q29tcG9uZW50U3RhdGUsXG4gICAgc2V0Q29tcG9uZW50U3RhdGU6IERyYWdEcm9wJHNldENvbXBvbmVudFN0YXRlLFxuICAgIGdldENvbXBvbmVudE1ldGE6IERyYWdEcm9wJGdldENvbXBvbmVudE1ldGEsXG4gICAgc2V0Q29tcG9uZW50TWV0YTogRHJhZ0Ryb3Akc2V0Q29tcG9uZW50TWV0YSxcbiAgICBnZXRBbGxvd2VkRWZmZWN0czogRHJhZ0Ryb3AkZ2V0QWxsb3dlZEVmZmVjdHMsXG4gICAgc2V0QWxsb3dlZEVmZmVjdHM6IERyYWdEcm9wJHNldEFsbG93ZWRFZmZlY3RzLFxuICAgIGdldERyb3BFZmZlY3Q6IERyYWdEcm9wJGdldERyb3BFZmZlY3QsXG4gICAgc2V0RHJvcEVmZmVjdDogRHJhZ0Ryb3Akc2V0RHJvcEVmZmVjdCxcbiAgICBpc0VmZmVjdEFsbG93ZWQ6IERyYWdEcm9wJGlzRWZmZWN0QWxsb3dlZCxcbiAgICBnZXREYXRhOiBEcmFnRHJvcCRnZXREYXRhLFxuICAgIHNldERhdGE6IERyYWdEcm9wJHNldERhdGEsXG4gICAgY2xlYXJEYXRhOiBEcmFnRHJvcCRjbGVhckRhdGFcbn0pO1xuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJCRjb21wb25lbnREYXRhVHlwZSgpIHtcbiAgICByZXR1cm4gZHJhZ0Ryb3BDb25maWcuZGF0YVR5cGVzLmNvbXBvbmVudDtcbn1cblxuXG5mdW5jdGlvbiBEcmFnRHJvcCRpc0NvbXBvbmVudCgpIHtcbiAgICByZXR1cm4gXy5pbmRleE9mKHRoaXMudHlwZXMsIERyYWdEcm9wLmNvbXBvbmVudERhdGFUeXBlKCkpID49IDA7XG59XG5cblxuZnVuY3Rpb24gRHJhZ0Ryb3AkZ2V0Q29tcG9uZW50U3RhdGUoKSB7XG4gICAgdmFyIGRhdGFUeXBlID0gRHJhZ0Ryb3AuY29tcG9uZW50RGF0YVR5cGUoKVxuICAgICAgICAsIHN0YXRlU3RyID0gdGhpcy5kYXRhVHJhbnNmZXIuZ2V0RGF0YShkYXRhVHlwZSlcbiAgICAgICAgLCBzdGF0ZSA9IF8uanNvblBhcnNlKHN0YXRlU3RyKTtcblxuICAgIHJldHVybiBzdGF0ZTtcbn1cblxuXG5mdW5jdGlvbiBEcmFnRHJvcCRzZXRDb21wb25lbnRTdGF0ZShjb21wb25lbnQsIHN0YXRlU3RyKXtcbiAgICBpZiAoISBzdGF0ZVN0cikge1xuICAgICAgICB2YXIgc3RhdGUgPSBjb21wb25lbnQuZ2V0VHJhbnNmZXJTdGF0ZSh7IHJlcXVlc3RlZEJ5OiAnZHJhZycgfSk7XG4gICAgICAgIHN0YXRlU3RyID0gSlNPTi5zdHJpbmdpZnkoc3RhdGUpO1xuICAgIH1cbiAgICB2YXIgZGF0YVR5cGUgPSBEcmFnRHJvcC5jb21wb25lbnREYXRhVHlwZSgpO1xuXG4gICAgc3RhdGVTdHIgJiYgdGhpcy5kYXRhVHJhbnNmZXIuc2V0RGF0YShkYXRhVHlwZSwgc3RhdGVTdHIpO1xuICAgIHRoaXMuZGF0YVRyYW5zZmVyLnNldERhdGEoJ3RleHQvaHRtbCcsIGNvbXBvbmVudC5lbC5vdXRlckhUTUwpO1xuICAgIHJldHVybiBzdGF0ZVN0cjtcbn1cblxuXG5mdW5jdGlvbiBEcmFnRHJvcCRzZXRDb21wb25lbnRNZXRhKGNvbXBvbmVudCwgcGFyYW1zLCBkYXRhKSB7XG4gICAgdmFyIG1ldGEgPSBfY29tcG9uZW50TWV0YShjb21wb25lbnQpO1xuXG4gICAgdmFyIHBhcmFtc1N0ciA9IF8udG9RdWVyeVN0cmluZyhwYXJhbXMpO1xuICAgIHZhciBkYXRhVHlwZSA9IGRyYWdEcm9wQ29uZmlnLmRhdGFUeXBlcy5jb21wb25lbnRNZXRhVGVtcGxhdGVcbiAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoJyVjbGFzcycsIF9lbmNvZGUobWV0YS5jb21wQ2xhc3MgfHwgJycpKVxuICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgnJW5hbWUnLCBfZW5jb2RlKG1ldGEuY29tcE5hbWUgfHwgJycpKVxuICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgnJXBhcmFtcycsIF9lbmNvZGUocGFyYW1zU3RyIHx8ICcnKSk7XG5cbiAgICBpZiAoZGF0YSAmJiB0eXBlb2YgZGF0YSA9PSAnb2JqZWN0JykgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGRhdGEpO1xuXG4gICAgdGhpcy5kYXRhVHJhbnNmZXIuc2V0RGF0YShkYXRhVHlwZSwgZGF0YSB8fCAnJyk7XG5cbiAgICByZXR1cm4gZGF0YVR5cGU7XG59XG5cblxuZnVuY3Rpb24gX2VuY29kZShzdHIpIHtcbiAgICByZXR1cm4gYmFzZTMyLmVuY29kZShzdHIpLnRvTG93ZXJDYXNlKCk7XG59XG5cblxuZnVuY3Rpb24gX2NvbXBvbmVudE1ldGEoY29tcG9uZW50KSB7XG4gICAgcmV0dXJuIGNvbXBvbmVudC50cmFuc2ZlclxuICAgICAgICAgICAgPyBjb21wb25lbnQudHJhbnNmZXIuZ2V0Q29tcG9uZW50TWV0YSgpXG4gICAgICAgICAgICA6IHsgXG4gICAgICAgICAgICAgICAgY29tcENsYXNzOiBjb21wb25lbnQuY29uc3RydWN0b3IubmFtZSxcbiAgICAgICAgICAgICAgICBjb21wTmFtZTogY29tcG9uZW50Lm5hbWVcbiAgICAgICAgICAgIH07XG59XG5cblxuZnVuY3Rpb24gRHJhZ0Ryb3AkZ2V0Q29tcG9uZW50TWV0YSgpIHtcbiAgICB2YXIgbWF0Y2g7XG4gICAgdmFyIG1ldGFEYXRhVHlwZSA9IF8uZmluZCh0aGlzLnR5cGVzLCBmdW5jdGlvbiAoZFR5cGUpIHtcbiAgICAgICAgbWF0Y2ggPSBkVHlwZS5tYXRjaChjb21wb25lbnRNZXRhUmVnZXgpO1xuICAgICAgICByZXR1cm4gISFtYXRjaDtcbiAgICB9KTtcbiAgICBpZiAoIW1ldGFEYXRhVHlwZSkgcmV0dXJuO1xuXG4gICAgZm9yICh2YXIgaT0xOyBpPDQ7IGkrKylcbiAgICAgICAgbWF0Y2hbaV0gPSBiYXNlMzIuZGVjb2RlKG1hdGNoW2ldKTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIGNvbXBDbGFzczogbWF0Y2hbMV0sXG4gICAgICAgIGNvbXBOYW1lOiBtYXRjaFsyXSxcbiAgICAgICAgcGFyYW1zOiBfLmZyb21RdWVyeVN0cmluZyhtYXRjaFszXSksXG4gICAgICAgIG1ldGFEYXRhVHlwZTogbWV0YURhdGFUeXBlLFxuICAgICAgICBtZXRhRGF0YTogXy5qc29uUGFyc2UodGhpcy5kYXRhVHJhbnNmZXIuZ2V0RGF0YShtZXRhRGF0YVR5cGUpKSBcbiAgICAgICAgICAgICAgICAgICAgPyBfLmpzb25QYXJzZSh0aGlzLmRhdGFUcmFuc2Zlci5nZXREYXRhKG1ldGFEYXRhVHlwZSkpIFxuICAgICAgICAgICAgICAgICAgICA6IHRoaXMuZGF0YVRyYW5zZmVyLmdldERhdGEobWV0YURhdGFUeXBlKVxuICAgIH07XG59XG5cblxuLy8gYXMgZGVmaW5lZCBoZXJlOiBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL0RyYWdEcm9wL0RyYWdfT3BlcmF0aW9ucyNkcmFnc3RhcnRcbmZ1bmN0aW9uIERyYWdEcm9wJGdldEFsbG93ZWRFZmZlY3RzKCkge1xuICAgIHJldHVybiB0aGlzLmRhdGFUcmFuc2Zlci5lZmZlY3RBbGxvd2VkO1xufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJHNldEFsbG93ZWRFZmZlY3RzKGVmZmVjdHMpIHtcbiAgICB0aGlzLmRhdGFUcmFuc2Zlci5lZmZlY3RBbGxvd2VkID0gZWZmZWN0cztcbn1cblxuXG5mdW5jdGlvbiBEcmFnRHJvcCRnZXREcm9wRWZmZWN0KCkge1xuICAgIHJldHVybiB0aGlzLmRhdGFUcmFuc2Zlci5kcm9wRWZmZWN0O1xufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJHNldERyb3BFZmZlY3QoZWZmZWN0KSB7XG4gICAgdGhpcy5kYXRhVHJhbnNmZXIuZHJvcEVmZmVjdCA9IGVmZmVjdDtcbn1cblxuXG5mdW5jdGlvbiBEcmFnRHJvcCRpc0VmZmVjdEFsbG93ZWQoZWZmZWN0KSB7XG4gICAgdmFyIGFsbG93ZWRFZmZlY3RzID0gdGhpcy5nZXRBbGxvd2VkRWZmZWN0cygpXG4gICAgICAgICwgaXNDb3B5ID0gZWZmZWN0ID09ICdjb3B5J1xuICAgICAgICAsIGlzTW92ZSA9IGVmZmVjdCA9PSAnbW92ZSdcbiAgICAgICAgLCBpc0xpbmsgPSBlZmZlY3QgPT0gJ2xpbmsnXG4gICAgICAgICwgaXNBbGxvd2VkID0gaXNDb3B5IHx8IGlzTGluayB8fCBpc01vdmU7XG5cbiAgICBzd2l0Y2ggKGFsbG93ZWRFZmZlY3RzKSB7XG4gICAgICAgIGNhc2UgJ2NvcHknOlxuICAgICAgICBjYXNlICdtb3ZlJzpcbiAgICAgICAgY2FzZSAnbGluayc6XG4gICAgICAgICAgICByZXR1cm4gYWxsb3dlZEVmZmVjdHMgPT0gZWZmZWN0O1xuICAgICAgICBjYXNlICdjb3B5TGluayc6XG4gICAgICAgICAgICByZXR1cm4gaXNDb3B5IHx8IGlzTGluaztcbiAgICAgICAgY2FzZSAnY29weU1vdmUnOlxuICAgICAgICAgICAgcmV0dXJuIGlzQ29weSB8fCBpc01vdmU7XG4gICAgICAgIGNhc2UgJ2xpbmtNb3ZlJzpcbiAgICAgICAgICAgIHJldHVybiBpc0xpbmsgfHwgaXNNb3ZlO1xuICAgICAgICBjYXNlICdhbGwnOlxuICAgICAgICBjYXNlICd1bmluaXRpYWxpemVkJzpcbiAgICAgICAgICAgIHJldHVybiBpc0FsbG93ZWQ7XG4gICAgICAgIGNhc2UgJ25vbmUnOlxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBEcmFnRHJvcCRnZXREYXRhKGRhdGFUeXBlKSB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YVRyYW5zZmVyLmdldERhdGEoZGF0YVR5cGUpO1xufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wJHNldERhdGEoZGF0YVR5cGUsIGRhdGFTdHIpIHtcbiAgICB0aGlzLmRhdGFUcmFuc2Zlci5zZXREYXRhKGRhdGFUeXBlLCBkYXRhU3RyKTtcbn1cblxuXG5mdW5jdGlvbiBEcmFnRHJvcCRjbGVhckRhdGEoZGF0YVR5cGUpIHtcbiAgICB0aGlzLmRhdGFUcmFuc2Zlci5jbGVhckRhdGEoZGF0YVR5cGUpO1xufVxuXG5cbi8qKlxuICogRHJhZyBkcm9wIHNlcnZpY2UgY29tcGVuc2F0aW5nIGZvciB0aGUgbGFjayBvZiBjb21tdW5pY2F0aW9uIGZyb20gZHJvcCB0YXJnZXQgdG8gZHJhZyBzb3VyY2UgaW4gRE9NIEFQSVxuICovXG52YXIgZHJhZ0Ryb3BTZXJ2aWNlID0gbmV3IE1lc3NlbmdlcjtcblxudmFyIF9jdXJyZW50RHJhZ0Ryb3AsIF9jdXJyZW50RHJhZ0ZhY2V0O1xuXG5fLmV4dGVuZChEcmFnRHJvcCwge1xuICAgIHNlcnZpY2U6IGRyYWdEcm9wU2VydmljZSxcbiAgICBkZXN0cm95OiBEcmFnRHJvcF9kZXN0cm95XG59KTtcblxuXG5kcmFnRHJvcFNlcnZpY2Uub25NZXNzYWdlcyh7XG4gICAgLy8gZGF0YSBpcyBEcmFnRHJvcERhdGFUcmFuc2ZlciBpbnN0YW5jZVxuICAgIC8vIGZpcmVkIGJ5IERyYWcgZmFjZXQgb24gXCJkcmFnc3RhcnRcIiBldmVudFxuICAgICdkcmFnZHJvcHN0YXJ0ZWQnOiBvbkRyYWdEcm9wU3RhcnRlZCwgXG4gICAgLy8gZGF0YSBpcyBvYmplY3Qgd2l0aCBhdCBsZWFzdCBkcm9wRWZmZWN0IHByb3BlcnR5XG4gICAgLy8gZmlyZWQgYnkgRHJvcCBmYWNldCBvbiBcImRyb3BcIiBldmVudFxuICAgICdkcmFnZHJvcGNvbXBsZXRlZCc6IG9uRHJhZ0Ryb3BDb21wbGV0ZWQsIFxuICAgIC8vIGZpcmVkIGJ5IERyYWcgZmFjZXQgb24gXCJkcmFnZW5kXCIgZXZlbnQgdG8gY29tcGxldGUgZHJhZ1xuICAgIC8vIGlmIGRyb3AgaGFwcGVuZGVkIGluIGFub3RoZXIgd2luZG93IG9yIGlmIGl0IHdhcyBjYW5jZWxsZWRcbiAgICAnY29tcGxldGVkcmFnZHJvcCc6IG9uQ29tcGxldGVEcmFnRHJvcFxufSk7XG5cblxuXy5leHRlbmQoZHJhZ0Ryb3BTZXJ2aWNlLCB7XG4gICAgZ2V0Q3VycmVudERyYWdEcm9wOiBnZXRDdXJyZW50RHJhZ0Ryb3Bcbn0pO1xuXG5cbmZ1bmN0aW9uIG9uRHJhZ0Ryb3BTdGFydGVkKG1zZywgZGF0YSkge1xuICAgIF9jdXJyZW50RHJhZ0Ryb3AgPSBkYXRhLmRyYWdEcm9wO1xuICAgIF9jdXJyZW50RHJhZ0ZhY2V0ID0gZGF0YS5kcmFnRmFjZXQ7XG59XG5cblxuZnVuY3Rpb24gb25EcmFnRHJvcENvbXBsZXRlZChtc2csIGRhdGEpIHtcbiAgICBfY3VycmVudERyYWdGYWNldCAmJiBfY3VycmVudERyYWdGYWNldC5wb3N0TWVzc2FnZVN5bmMoJ2RyYWdkcm9wY29tcGxldGVkJywgZGF0YSk7XG4gICAgX2N1cnJlbnREcmFnRHJvcCA9IHVuZGVmaW5lZDtcbiAgICBfY3VycmVudERyYWdGYWNldCA9IHVuZGVmaW5lZDtcbn1cblxuXG5mdW5jdGlvbiBvbkNvbXBsZXRlRHJhZ0Ryb3AobXNnLCBkYXRhKSB7XG4gICAgaWYgKF9jdXJyZW50RHJhZ0Ryb3ApXG4gICAgICAgIGRyYWdEcm9wU2VydmljZS5wb3N0TWVzc2FnZVN5bmMoJ2RyYWdkcm9wY29tcGxldGVkJywgZGF0YSk7XG59XG5cblxuZnVuY3Rpb24gZ2V0Q3VycmVudERyYWdEcm9wKCkge1xuICAgIHJldHVybiBfY3VycmVudERyYWdEcm9wO1xufVxuXG5cbmZ1bmN0aW9uIERyYWdEcm9wX2Rlc3Ryb3koKSB7XG4gICAgZHJhZ0Ryb3BTZXJ2aWNlLm9mZkFsbCgpO1xufVxuIiwiLy8gPGEgbmFtZT1cInV0aWxzLWVycm9yXCI+PC9hPlxuLy8gbWlsby51dGlscy5lcnJvclxuLy8gLS0tLS0tLS0tLS1cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgXyA9IHJlcXVpcmUoJ21pbG8tY29yZScpLnByb3RvO1xuXG5cbi8vIG1vZHVsZSBleHBvcnRzIGVycm9yIGNsYXNzZXMgZm9yIGFsbCBuYW1lcyBkZWZpbmVkIGluIHRoaXMgYXJyYXlcbnZhciBlcnJvckNsYXNzTmFtZXMgPSBbJ0Fic3RyYWN0Q2xhc3MnLCAnTWl4aW4nLCAnTWVzc2VuZ2VyJywgJ0NvbXBvbmVudCcsXG4gICAgICAgICAgICAgICAgICAgICAgICdBdHRyaWJ1dGUnLCAnQmluZGVyJywgJ0xvYWRlcicsICdNYWlsTWVzc2FnZVNvdXJjZScsICdGYWNldCcsXG4gICAgICAgICAgICAgICAgICAgICAgICdTY29wZScsICdNb2RlbCcsICdEb21GYWNldCcsICdFZGl0YWJsZUZhY2V0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgJ0xpc3QnLCAnQ29ubmVjdG9yJywgJ1JlZ2lzdHJ5JywgJ0ZyYW1lTWVzc2FnZVNvdXJjZScsXG4gICAgICAgICAgICAgICAgICAgICAgICdEcm9wJywgJ0FuZ3VsYXInLCAnU3RvcmFnZU1lc3NhZ2VTb3VyY2UnXTtcblxudmFyIGVycm9yID0ge1xuICAgIHRvQmVJbXBsZW1lbnRlZDogZXJyb3IkdG9CZUltcGxlbWVudGVkLFxuICAgIGNyZWF0ZUNsYXNzOiBlcnJvciRjcmVhdGVDbGFzc1xufTtcblxuZXJyb3JDbGFzc05hbWVzLmZvckVhY2goZnVuY3Rpb24obmFtZSkge1xuICAgIGVycm9yW25hbWVdID0gZXJyb3IkY3JlYXRlQ2xhc3MobmFtZSArICdFcnJvcicpO1xufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gZXJyb3I7XG5cblxuZnVuY3Rpb24gZXJyb3IkY3JlYXRlQ2xhc3MoZXJyb3JDbGFzc05hbWUpIHtcbiAgICB2YXIgRXJyb3JDbGFzcyA9IF8ubWFrZUZ1bmN0aW9uKGVycm9yQ2xhc3NOYW1lLCAnbWVzc2FnZScsXG4gICAgICAgICAgICAndGhpcy5uYW1lID0gXCInICsgZXJyb3JDbGFzc05hbWUgKyAnXCI7IFxcXG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlIHx8IFwiVGhlcmUgd2FzIGFuICBlcnJvclwiOycpO1xuICAgIF8ubWFrZVN1YmNsYXNzKEVycm9yQ2xhc3MsIEVycm9yKTtcblxuICAgIHJldHVybiBFcnJvckNsYXNzO1xufVxuXG5cbmZ1bmN0aW9uIGVycm9yJHRvQmVJbXBsZW1lbnRlZCgpIHtcbiAgICB0aHJvdyBuZXcgZXJyb3IuQWJzdHJhY3RDbGFzcygnY2FsbGluZyB0aGUgbWV0aG9kIG9mIGFuIGFic2N0cmFjdCBjbGFzcycpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBDb21wb25lbnQgPSByZXF1aXJlKCcuLi9jb21wb25lbnRzL2NfY2xhc3MnKVxuICAgICwgQmluZEF0dHJpYnV0ZSA9IHJlcXVpcmUoJy4uL2F0dHJpYnV0ZXMvYV9iaW5kJylcbiAgICAsIGJpbmRlciA9IHJlcXVpcmUoJy4uL2JpbmRlcicpXG4gICAgLCBkb21VdGlscyA9IHJlcXVpcmUoJy4vZG9tJylcbiAgICAsIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIGxvZ2dlciA9IG1pbG9Db3JlLnV0aWwubG9nZ2VyXG4gICAgLCBjaGVjayA9IG1pbG9Db3JlLnV0aWwuY2hlY2tcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90bztcblxuXG52YXIgY3JlYXRlUmFuZ2VQYXRocyA9IF9jcmVhdGVOb2Rlc0FuZFBhdGhzRnVuYyhkb21VdGlscy50cmVlUGF0aE9mKTtcbnZhciBjcmVhdGVSYW5nZU5vZGVzID0gX2NyZWF0ZU5vZGVzQW5kUGF0aHNGdW5jKGRvbVV0aWxzLmdldE5vZGVBdFRyZWVQYXRoKTtcblxuXG52YXIgZnJhZ21lbnRVdGlscyA9IG1vZHVsZS5leHBvcnRzID0ge1xuICAgIGdldFN0YXRlOiBmcmFnbWVudF9nZXRTdGF0ZSxcbiAgICBnZXRTdGF0ZUFzeW5jOiBmcmFnbWVudF9nZXRTdGF0ZUFzeW5jLFxuXG4gICAgZXhwYW5kUmFuZ2VUb1NpYmxpbmdzOiBleHBhbmRSYW5nZVRvU2libGluZ3MsXG4gICAgZ2V0UmFuZ2VTaWJsaW5nczogZ2V0UmFuZ2VTaWJsaW5ncyxcbiAgICBjcmVhdGVSYW5nZUZyb21TaWJsaW5nczogY3JlYXRlUmFuZ2VGcm9tU2libGluZ3MsXG4gICAgY3JlYXRlUmFuZ2VGcm9tTm9kZXM6IGNyZWF0ZVJhbmdlRnJvbVNpYmxpbmdzLCAvLyBhbGlhc1xuICAgIGNyZWF0ZVJhbmdlUGF0aHM6IGNyZWF0ZVJhbmdlUGF0aHMsXG4gICAgY3JlYXRlUmFuZ2VOb2RlczogY3JlYXRlUmFuZ2VOb2Rlc1xufTtcblxuXG4vKipcbiAqIENyZWF0ZXMgYW4gb2JqZWN0IHdpdGggdGhlIHN0YXRlIG9mIHdyYXBwZWQgcmFuZ2Ugd2l0aCBjb21wb25lbnRzLCBpbmNsdWRpbmcgcGFydGlhbGx5IHNlbGVjdGVkLiBUaGUgcmFuZ2Ugd2lsbCBiZSBjbG9uZWQgYW5kIHdyYXBwZWQgaW4gY29tcG9uZW50IHdpdGggY29udGFpbmVyIGZhY2V0IGJlZm9yZSBnZXR0aW5nIGl0cyBzdGF0ZS5cbiAqIFRoaXMgZnVuY3Rpb24gd2lsbCBsb2cgZXJyb3IgYW5kIHJldHVybiB1bmRlZmluZWQgaWYgcmFuZ2UgaGFzIG5vIGNvbW1vbiBhbmNlc3RvciB0aGF0IGhhcyBjb21wb25lbnQgd2l0aCBjb250YWluZXIgZmFjZXRcbiAqIFxuICogQHBhcmFtIHtSYW5nZX0gcmFuZ2UgRE9NIFJhbmdlIGluc3RhbmNlXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHJlbmFtZUNoaWxkcmVuIG9wdGlvbmFsIHBhcmFtZXRlciwgYHRydWVgIHRvIHJlbmFtZSBmcmFnbWVudCBjaGlsZCBjb21wb25lbnRzXG4gKiBAcGFyYW0ge1N0cmluZ30gd3JhcHBlckNsYXNzTmFtZSBvcHRpb25hbCBwYXJhbWV0ZXIgdG8gd3JhcCBpbiBhIGN1c3RvbSBjb21wb25lbnQgY2xhc3NcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZnJhZ21lbnRfZ2V0U3RhdGUocmFuZ2UsIHJlbmFtZUNoaWxkcmVuLCB3cmFwcGVyQ2xhc3NOYW1lKSB7XG4gICAgdmFyIHJhbmdlQ29udGFpbmVyID0gX2dldFJhbmdlQ29udGFpbmVyKHJhbmdlKTtcbiAgICBpZiAoISByYW5nZUNvbnRhaW5lcikge1xuICAgICAgICBsb2dnZXIuZXJyb3IoJ2ZyYWdtZW50LmdldFN0YXRlOiByYW5nZSBoYXMgbm8gY29tbW9uIGNvbnRhaW5lcicpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGZyYWcgPSByYW5nZS5jbG9uZUNvbnRlbnRzKClcbiAgICAgICAgLCB3cmFwcGVyID0gX3dyYXBGcmFnbWVudEluQ29udGFpbmVyKGZyYWcsIHdyYXBwZXJDbGFzc05hbWUpO1xuXG4gICAgX3RyYW5zZmVyU3RhdGVzKHJhbmdlQ29udGFpbmVyLCB3cmFwcGVyKTtcbiAgICBpZiAocmVuYW1lQ2hpbGRyZW4pIF9yZW5hbWVDaGlsZHJlbih3cmFwcGVyKTtcbiAgICB2YXIgd3JhcHBlclN0YXRlID0gd3JhcHBlci5nZXRTdGF0ZSgpO1xuICAgIF8uZGVmZXJNZXRob2Qod3JhcHBlciwgJ2Rlc3Ryb3knKTtcbiAgICByZXR1cm4gd3JhcHBlclN0YXRlO1xufVxuXG5cbi8qKlxuICogQ3JlYXRlcyBhbiBvYmplY3Qgd2l0aCB0aGUgc3RhdGUgb2Ygd3JhcHBlZCByYW5nZSB3aXRoIGNvbXBvbmVudHMsIGluY2x1ZGluZyBwYXJ0aWFsbHkgc2VsZWN0ZWQuIFRoZSByYW5nZSB3aWxsIGJlIGNsb25lZCBhbmQgd3JhcHBlZCBpbiBjb21wb25lbnQgd2l0aCBjb250YWluZXIgZmFjZXQgYmVmb3JlIGdldHRpbmcgaXRzIHN0YXRlLlxuICogVGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiByZXN1bHQgYW5kIGFueSBlcnJvciB2aWEgY2FsbGJhY2suXG4gKiBcbiAqIEBwYXJhbSB7UmFuZ2V9IHJhbmdlIERPTSBSYW5nZSBpbnN0YW5jZVxuICogQHBhcmFtIHtCb29sZWFufSByZW5hbWVDaGlsZHJlbiBvcHRpb25hbCBwYXJhbWV0ZXIsIGB0cnVlYCB0byByZW5hbWUgZnJhZ21lbnQgY2hpbGQgY29tcG9uZW50c1xuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgYWx3YXlzIHRoZSBsYXN0IHBhcmFtZXRlciwgb3B0aW9uYWwgcGFyYW1ldGVycyBjYW4gYmUgZHJvcHBlZDsgcmVzdWx0IGlzIHBhc3NlZCB2aWEgY2FsbGJhY2sgd2l0aCBhbnkgZXJyb3IgYXMgZmlyc3QgcGFyYW1ldGVyXG4gKi9cbmZ1bmN0aW9uIGZyYWdtZW50X2dldFN0YXRlQXN5bmMocmFuZ2UsIHJlbmFtZUNoaWxkcmVuLCBjYWxsYmFjaykge1xuICAgIHRyeSB7XG4gICAgICAgIHZhciByYW5nZUNvbnRhaW5lciA9IF9nZXRSYW5nZUNvbnRhaW5lcihyYW5nZSk7XG4gICAgICAgIGlmICghIHJhbmdlQ29udGFpbmVyKSB7XG4gICAgICAgICAgICBjYWxsYmFjayhuZXcgRXJyb3IoJ2ZyYWdtZW50LmdldFN0YXRlOiByYW5nZSBoYXMgbm8gY29tbW9uIGNvbnRhaW5lcicpKTtcbiAgICAgICAgICAgIHJldHVybjsgLy8gZG8gTk9UIGNvbm5lY3QgcmV0dXJuIHRvIHByZXZpb3VzIGNhbGxiYWNrLCBnZXRTdGF0ZSBzaG91bGQgcmV0dXJuIHVuZGVmaW5lZFxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiByZW5hbWVDaGlsZHJlbiA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYWxsYmFjayA9IHJlbmFtZUNoaWxkcmVuO1xuICAgICAgICAgICAgcmVuYW1lQ2hpbGRyZW4gPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBmcmFnID0gcmFuZ2UuY2xvbmVDb250ZW50cygpXG4gICAgICAgICAgICAsIHdyYXBwZXIgPSBfd3JhcEZyYWdtZW50SW5Db250YWluZXIoZnJhZyk7XG5cbiAgICAgICAgX3RyYW5zZmVyU3RhdGVzKHJhbmdlQ29udGFpbmVyLCB3cmFwcGVyKTtcbiAgICAgICAgXy5kZWZlcihmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHdyYXBwZXIuYnJvYWRjYXN0KCdzdGF0ZXJlYWR5Jyk7XG4gICAgICAgICAgICBfLmRlZmVyKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgIGlmIChyZW5hbWVDaGlsZHJlbikgX3JlbmFtZUNoaWxkcmVuKHdyYXBwZXIpO1xuICAgICAgICAgICAgICAgIHZhciB3cmFwcGVyU3RhdGUgPSB3cmFwcGVyLmdldFN0YXRlKCk7XG4gICAgICAgICAgICAgICAgd3JhcHBlci5kZXN0cm95KCk7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwgd3JhcHBlclN0YXRlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY2FsbGJhY2soZXJyKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gX3dyYXBGcmFnbWVudEluQ29udGFpbmVyKGZyYWcsIHdyYXBwZXJDbGFzc05hbWUpIHtcbiAgICB2YXIgd3JhcEVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2JylcbiAgICAgICAgLCBhdHRyID0gbmV3IEJpbmRBdHRyaWJ1dGUod3JhcEVsKTtcblxuICAgIF8uZXh0ZW5kKGF0dHIsIHtcbiAgICAgICAgY29tcENsYXNzOiB3cmFwcGVyQ2xhc3NOYW1lIHx8ICdDb21wb25lbnQnLFxuICAgICAgICBjb21wRmFjZXRzOiB3cmFwcGVyQ2xhc3NOYW1lID8gW10gOiBbJ2NvbnRhaW5lciddLFxuICAgICAgICBjb21wTmFtZTogJ3dyYXBwZXInXG4gICAgfSk7XG5cbiAgICBhdHRyLmRlY29yYXRlKCk7XG5cbiAgICB3cmFwRWwuYXBwZW5kQ2hpbGQoZnJhZyk7XG4gICAgdmFyIHNjb3BlID0gYmluZGVyKHdyYXBFbCk7XG4gICAgcmV0dXJuIHNjb3BlLndyYXBwZXI7XG59XG5cblxuZnVuY3Rpb24gX2dldFJhbmdlQ29udGFpbmVyKHJhbmdlKSB7XG4gICAgdmFyIGVsID0gZG9tVXRpbHMuY29udGFpbmluZ0VsZW1lbnQocmFuZ2UuY29tbW9uQW5jZXN0b3JDb250YWluZXIpO1xuICAgIHJldHVybiBDb21wb25lbnQuZ2V0Q29udGFpbmluZ0NvbXBvbmVudChlbCwgdHJ1ZSwgJ2NvbnRhaW5lcicpO1xufVxuXG5cbmZ1bmN0aW9uIF90cmFuc2ZlclN0YXRlcyhmcm9tQ29tcCwgdG9Db21wKSB7XG4gICAgdmFyIGZyb21TY29wZSA9IGZyb21Db21wLmNvbnRhaW5lci5zY29wZTtcbiAgICB0b0NvbXAuY29udGFpbmVyLnNjb3BlLl9lYWNoKGZ1bmN0aW9uKHRvQ2hpbGRDb21wLCBuYW1lKSB7XG4gICAgICAgIHZhciBmcm9tQ2hpbGRDb21wID0gZnJvbVNjb3BlW25hbWVdO1xuICAgICAgICBpZiAoISBmcm9tQ2hpbGRDb21wKSByZXR1cm4gbG9nZ2VyLmVycm9yKCdmcmFnbWVudC5nZXRTdGF0ZTogY29ucG9uZW50JywgbmFtZSwgJ25vdCBmb3VuZCBpbiByYW5nZScpO1xuICAgICAgICB2YXIgc3RhdGUgPSBmcm9tQ2hpbGRDb21wLl9nZXRTdGF0ZSh0cnVlKTtcbiAgICAgICAgdG9DaGlsZENvbXAuc2V0U3RhdGUoc3RhdGUpO1xuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIF9yZW5hbWVDaGlsZHJlbihjb21wKSB7XG4gICAgY29tcC5jb250YWluZXIuc2NvcGUuX2VhY2goZnVuY3Rpb24oY2hpbGQpIHtcbiAgICAgICAgY2hpbGQucmVuYW1lKCk7XG4gICAgfSk7XG59XG5cblxuZnVuY3Rpb24gZXhwYW5kUmFuZ2VUb1NpYmxpbmdzKHJhbmdlKSB7XG4gICAgdmFyIHNpYmxpbmdzID0gZ2V0UmFuZ2VTaWJsaW5ncyhyYW5nZSk7XG4gICAgcmFuZ2UgPSBjcmVhdGVSYW5nZUZyb21TaWJsaW5ncyhzaWJsaW5ncyk7XG4gICAgcmV0dXJuIHJhbmdlO1xufVxuXG5cbmZ1bmN0aW9uIGNyZWF0ZVJhbmdlRnJvbVNpYmxpbmdzKG5vZGVzKSB7XG4gICAgdmFyIHJhbmdlID0gZG9jdW1lbnQuY3JlYXRlUmFuZ2UoKTtcbiAgICBpZiAobm9kZXMuc2libGluZ3MpIHtcbiAgICAgICAgcmFuZ2Uuc2V0U3RhcnRCZWZvcmUobm9kZXMuc3RhcnQpO1xuICAgICAgICByYW5nZS5zZXRFbmRBZnRlcihub2Rlcy5lbmQpO1xuICAgIH0gZWxzZVxuICAgICAgICByYW5nZS5zZWxlY3ROb2RlKG5vZGVzLnN0YXJ0KTtcbiAgICByZXR1cm4gcmFuZ2U7XG59XG5cblxuZnVuY3Rpb24gZ2V0UmFuZ2VTaWJsaW5ncyhyYW5nZSkge1xuICAgIHZhciBjb250YWluZXJOb2RlID0gcmFuZ2UuY29tbW9uQW5jZXN0b3JDb250YWluZXJcbiAgICAgICAgLCBzdGFydE5vZGUgPSByYW5nZS5zdGFydENvbnRhaW5lclxuICAgICAgICAsIGVuZE5vZGUgPSByYW5nZS5lbmRDb250YWluZXI7XG5cbiAgICBpZiAoc3RhcnROb2RlID09IGVuZE5vZGUpIHtcbiAgICAgICAgaWYgKHN0YXJ0Tm9kZSAhPSBjb250YWluZXJOb2RlKSBsb2dnZXIuZXJyb3IoJ2RlbGV0ZVNlbGVjdGlvbkNvbW1hbmQgbG9naWNhbCBlcnJvcjogc3RhcnQ9PWVuZCwgYnV0IGNvbnRhaW5lciBpcyBkaWZmZXJlbnQnKTtcbiAgICAgICAgcmV0dXJuIHsgc2libGluZ3M6IGZhbHNlLCBzdGFydDogc3RhcnROb2RlIH07XG4gICAgfVxuXG4gICAgaWYgKHN0YXJ0Tm9kZSA9PSBjb250YWluZXJOb2RlIHx8IGVuZE5vZGUgPT0gY29udGFpbmVyTm9kZSlcbiAgICAgICAgcmV0dXJuIHsgc2libGluZ3M6IGZhbHNlLCBzdGFydDogY29udGFpbmVyTm9kZSB9O1xuXG4gICAgdmFyIHN0YXJ0U2libGluZyA9IF9maW5kQ29udGFpbmluZ0NoaWxkKGNvbnRhaW5lck5vZGUsIHN0YXJ0Tm9kZSk7XG4gICAgdmFyIGVuZFNpYmxpbmcgPSBfZmluZENvbnRhaW5pbmdDaGlsZChjb250YWluZXJOb2RlLCBlbmROb2RlKTtcblxuICAgIGlmIChzdGFydFNpYmxpbmcgJiYgZW5kU2libGluZykge1xuICAgICAgICBpZiAoc3RhcnRTaWJsaW5nID09IGVuZFNpYmxpbmcpIHtcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcignZGVsZXRlU2VsZWN0aW9uQ29tbWFuZCBsb2dpY2FsIGVycm9yOiBzYW1lIHNpYmxpbmdzJyk7XG4gICAgICAgICAgICByZXR1cm4geyBzaWJsaW5nczogZmFsc2UsIHN0YXJ0OiBzdGFydFNpYmxpbmcgfTtcbiAgICAgICAgfSBlbHNlXG4gICAgICAgICAgICByZXR1cm4geyBzaWJsaW5nczogdHJ1ZSwgc3RhcnQ6IHN0YXJ0U2libGluZywgZW5kOiBlbmRTaWJsaW5nIH07XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIF9maW5kQ29udGFpbmluZ0NoaWxkKGNvbnRhaW5lck5vZGUsIHNlbE5vZGUpIHtcbiAgICByZXR1cm4gXy5maW5kKGNvbnRhaW5lck5vZGUuY2hpbGROb2RlcywgZnVuY3Rpb24obm9kZSkge1xuICAgICAgICByZXR1cm4gbm9kZS5jb250YWlucyhzZWxOb2RlKTtcbiAgICB9KTtcbn1cblxuXG5mdW5jdGlvbiBfY3JlYXRlTm9kZXNBbmRQYXRoc0Z1bmMoZnVuYykge1xuICAgIHJldHVybiBmdW5jdGlvbihyb290RWwsIGZyb21PYmopIHtcbiAgICAgICAgdmFyIHRvT2JqID0ge1xuICAgICAgICAgICAgc2libGluZ3M6IGZyb21PYmouc2libGluZ3MsXG4gICAgICAgICAgICBzdGFydDogZnVuYyhyb290RWwsIGZyb21PYmouc3RhcnQpXG4gICAgICAgIH07XG4gICAgICAgIGlmICh0b09iai5zaWJsaW5ncylcbiAgICAgICAgICAgIHRvT2JqLmVuZCA9IGZ1bmMocm9vdEVsLCBmcm9tT2JqLmVuZCk7XG4gICAgICAgIHJldHVybiB0b09iajtcbiAgICB9O1xufVxuXG5cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJyk7XG5cbi8qKlxuICogYG1pbG8udXRpbGBcbiAqL1xudmFyIHV0aWwgPSB7XG4gICAgbG9nZ2VyOiBtaWxvQ29yZS51dGlsLmxvZ2dlcixcbiAgICByZXF1ZXN0OiByZXF1aXJlKCcuL3JlcXVlc3QnKSxcbiAgICB3ZWJzb2NrZXQ6IHJlcXVpcmUoJy4vd2Vic29ja2V0JyksXG4gICAgY2hlY2s6IG1pbG9Db3JlLnV0aWwuY2hlY2ssXG4gICAgZXJyb3I6IHJlcXVpcmUoJy4vZXJyb3InKSwgLy8gZGVwcmVjYXRlZFxuICAgIGNvdW50OiByZXF1aXJlKCcuL2NvdW50JyksIC8vIGRlcHJlY2F0ZWRcbiAgICB1bmlxdWVJZDogcmVxdWlyZSgnLi9jb3VudCcpLFxuICAgIGNvbXBvbmVudE5hbWU6IHJlcXVpcmUoJy4vY29tcG9uZW50X25hbWUnKSxcbiAgICBkb206IHJlcXVpcmUoJy4vZG9tJyksXG4gICAgZG9tTGlzdGVuZXJzOiByZXF1aXJlKCcuL2RvbV9saXN0ZW5lcnMnKSxcbiAgICBzZWxlY3Rpb246IHJlcXVpcmUoJy4vc2VsZWN0aW9uJyksXG4gICAgZnJhZ21lbnQ6IHJlcXVpcmUoJy4vZnJhZ21lbnQnKSxcbiAgICBqc29uUGFyc2U6IHJlcXVpcmUoJy4vanNvbl9wYXJzZScpLCAvLyBkZXByZWNhdGVkXG4gICAgc3RvcmFnZTogcmVxdWlyZSgnLi9zdG9yYWdlJyksXG4gICAgZG9tUmVhZHk6IHJlcXVpcmUoJy4vZG9tcmVhZHknKSxcbiAgICBkcmFnRHJvcDogcmVxdWlyZSgnLi9kcmFnZHJvcCcpLFxuICAgIGRpYWxvZzogcmVxdWlyZSgnLi4vY29tcG9uZW50cy91aS9ib290c3RyYXAvRGlhbG9nJyksIC8vIGRlcHJlY2F0ZWQgLSBzaG91bGQgYmUgdXNlZCBmcm9tIHJlZ2lzdHJ5XG4gICAgYWxlcnQ6IHJlcXVpcmUoJy4uL2NvbXBvbmVudHMvdWkvYm9vdHN0cmFwL0FsZXJ0JyksIC8vIGRlcHJlY2F0ZWQgLSBzaG91bGQgYmUgdXNlZCBmcm9tIHJlZ2lzdHJ5XG4gICAgZG9UOiBtaWxvQ29yZS51dGlsLmRvVCxcbiAgICBkZXN0cm95OiB1dGlsX2Rlc3Ryb3lcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gdXRpbDtcblxuXG5mdW5jdGlvbiB1dGlsX2Rlc3Ryb3koKSB7XG4gICAgdXRpbC5yZXF1ZXN0LmRlc3Ryb3koKTtcbiAgICB1dGlsLmRyYWdEcm9wLmRlc3Ryb3koKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGpzb25QYXJzZTtcblxuXG4vKipcbiAqIGBtaWxvLnV0aWwuanNvblBhcnNlYFxuICogU2FmZSBKU09OLnBhcnNlLCByZXR1cm5zIHVuZGVmaW5lZCBpZiBKU09OLnBhcnNlIHRocm93cyBhbiBleGNlcHRpb25cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gc3RyIC0gSlNPTiBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2Ygb2JqZWN0XG4gKiBAcmV0dXJuIHtPYmplY3R8dW5kZWZpbmVkfVxuICovXG5mdW5jdGlvbiBqc29uUGFyc2Uoc3RyKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2Uoc3RyKTtcbiAgICB9IGNhdGNoIChlKSB7fVxufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyBtaWxvLnV0aWxzLnJlcXVlc3Rcbi8vIC0tLS0tLS0tLS0tXG5cbi8vIENvbnZlbmllbmNlIGZ1bmN0aW9ucyB3cmFwcGluZyBYTUxIVFRQUmVxdWVzdCBmdW5jdGlvbmFsaXR5LlxuXG4vLyBgYGBcbi8vIHZhciByZXF1ZXN0ID0gbWlsby51dGlscy5yZXF1ZXN0XG4vLyAgICAgLCBvcHRzOiB7IG1ldGhvZDogJ0dFVCcgfTtcblxuLy8gcmVxdWVzdCh1cmwsIG9wdHMsIGZ1bmN0aW9uKGVyciwgZGF0YSkge1xuLy8gICAgIGxvZ2dlci5kZWJ1ZyhkYXRhKTtcbi8vIH0pO1xuXG4vLyByZXF1ZXN0LmdldCh1cmwsIGZ1bmN0aW9uKGVyciwgZGF0YSkge1xuLy8gICAgIGxvZ2dlci5kZWJ1ZyhkYXRhKTtcbi8vIH0pO1xuLy8gYGBgXG5cbi8vIE9ubHkgZ2VuZXJpYyByZXF1ZXN0IGFuZCBnZXQsIGpzb24sIHBvc3QgY29udmVuaWVuY2UgbWV0aG9kcyBhcmUgY3VycmVudGx5IGltcGxlbWVudGVkLlxuXG5cbnZhciBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIGNvdW50ID0gcmVxdWlyZSgnLi9jb3VudCcpXG4gICAgLCBjb25maWcgPSByZXF1aXJlKCcuLi9jb25maWcnKVxuICAgICwgbG9nZ2VyID0gbWlsb0NvcmUudXRpbC5sb2dnZXJcbiAgICAsIE1lc3NlbmdlciA9IG1pbG9Db3JlLk1lc3NlbmdlcjtcblxubW9kdWxlLmV4cG9ydHMgPSByZXF1ZXN0O1xuXG5cbnZhciBfcGVuZGluZ1JlcXVlc3RzID0gW107XG5cbnZhciBwcm9taXNlVGhlbiA9IGNyZWF0ZVByb21pc2VPdmVycmlkZSgndGhlbicpO1xudmFyIHByb21pc2VDYXRjaCA9IGNyZWF0ZVByb21pc2VPdmVycmlkZSgnY2F0Y2gnKTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgZnVuY3Rpb24gd2hpY2ggaXMgdXNlZCB0byBvdmVycmlkZSBzdGFuZGFyZCBwcm9taXNlIGJlaGF2aW91ciBhbmQgYWxsb3cgcHJvbWlzZSBpbnN0YW5jZXMgXG4gKiBjcmVhdGVkIHRvIG1haW50YWluIGEgcmVmZXJlbmNlIHRvIHRoZSByZXF1ZXN0IG9iamVjdCBubyBtYXR0ZXIgaWYgLnRoZW4oKSBvciAuY2F0Y2goKSBpcyBjYWxsZWQuXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZVByb21pc2VPdmVycmlkZShmdW5jdGlvbk5hbWUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBwcm9taXNlID0gUHJvbWlzZS5wcm90b3R5cGVbZnVuY3Rpb25OYW1lXS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICBrZWVwUmVxdWVzdE9iamVjdChwcm9taXNlLCB0aGlzLl9yZXF1ZXN0KTtcbiAgICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIHJlcXVlc3QodXJsLCBvcHRzLCBjYWxsYmFjaykge1xuICAgIG9wdHMudXJsID0gdXJsO1xuICAgIG9wdHMuY29udGVudFR5cGUgPSBvcHRzLmNvbnRlbnRUeXBlIHx8ICdhcHBsaWNhdGlvbi9qc29uO2NoYXJzZXQ9VVRGLTgnO1xuICAgIGlmIChfbWVzc2VuZ2VyKSByZXF1ZXN0LnBvc3RNZXNzYWdlU3luYygncmVxdWVzdCcsIHsgb3B0aW9uczogb3B0cyB9KTtcblxuICAgIHZhciByZXEgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcbiAgICByZXEub3BlbihvcHRzLm1ldGhvZCwgb3B0cy51cmwsIHRydWUpO1xuICAgIHJlcS5zZXRSZXF1ZXN0SGVhZGVyKCdDb250ZW50LVR5cGUnLCBvcHRzLmNvbnRlbnRUeXBlKTtcbiAgICBzZXRSZXF1ZXN0SGVhZGVycyhyZXEsIG9wdHMuaGVhZGVycyk7XG5cbiAgICByZXEudGltZW91dCA9IG9wdHMudGltZW91dCB8fCBjb25maWcucmVxdWVzdC5kZWZhdWx0cy50aW1lb3V0O1xuICAgIHJlcS5vbnJlYWR5c3RhdGVjaGFuZ2UgPSByZXEub250aW1lb3V0ID0gcmVxLm9uYWJvcnQgPSBvblJlYWR5O1xuXG4gICAgdmFyIHhQcm9taXNlID0gX2NyZWF0ZVhQcm9taXNlKHJlcSk7XG5cbiAgICByZXEuc2VuZChKU09OLnN0cmluZ2lmeShvcHRzLmRhdGEpKTtcbiAgICByZXFbY29uZmlnLnJlcXVlc3Qub3B0aW9uc0tleV0gPSBvcHRzO1xuXG4gICAgX3BlbmRpbmdSZXF1ZXN0cy5wdXNoKHJlcSk7XG5cbiAgICByZXR1cm4geFByb21pc2UucHJvbWlzZTtcblxuICAgIGZ1bmN0aW9uIG9uUmVhZHkoZSkge1xuICAgICAgICBfb25SZWFkeShyZXEsIGNhbGxiYWNrLCB4UHJvbWlzZSwgZS50eXBlKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gX2NyZWF0ZVhQcm9taXNlKHJlcXVlc3QpIHtcbiAgICB2YXIgcmVzb2x2ZVByb21pc2UsIHJlamVjdFByb21pc2U7XG4gICAgdmFyIHByb21pc2UgPSBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgICAgcmVzb2x2ZVByb21pc2UgPSByZXNvbHZlO1xuICAgICAgICByZWplY3RQcm9taXNlID0gcmVqZWN0O1xuICAgIH0pO1xuXG4gICAga2VlcFJlcXVlc3RPYmplY3QocHJvbWlzZSwgcmVxdWVzdCk7XG4gICAgcHJvbWlzZS5jYXRjaChfLm5vb3ApOyAvLyBTb21ldGltZXMgZXJyb3JzIGFyZSBoYW5kbGVkIHdpdGhpbiBjYWxsYmFja3MsIHNvIHVuY2F1Z2h0IHByb21pc2UgZXJyb3IgbWVzc2FnZSBzaG91bGQgYmUgc3VwcHJlc3NlZC5cblxuICAgIHJldHVybiB7XG4gICAgICAgIHByb21pc2U6IHByb21pc2UsXG4gICAgICAgIHJlc29sdmU6IHJlc29sdmVQcm9taXNlLFxuICAgICAgICByZWplY3Q6IHJlamVjdFByb21pc2VcbiAgICB9XG59XG5cbi8vIEVuc3VyZXMgdGhhdCB0aGUgcHJvbWlzZSAoYW5kIGFueSBwcm9taXNlcyBjcmVhdGVkIHdoZW4gY2FsbGluZyAudGhlbi8uY2F0Y2gpIGhhcyBhIHJlZmVyZW5jZSB0byB0aGUgb3JpZ2luYWwgcmVxdWVzdCBvYmplY3RcbmZ1bmN0aW9uIGtlZXBSZXF1ZXN0T2JqZWN0KHByb21pc2UsIHJlcXVlc3QpIHtcbiAgICBwcm9taXNlLl9yZXF1ZXN0ID0gcmVxdWVzdDtcbiAgICBwcm9taXNlLnRoZW4gPSBwcm9taXNlVGhlbjtcbiAgICBwcm9taXNlLmNhdGNoID0gcHJvbWlzZUNhdGNoO1xuXG4gICAgcmV0dXJuIHByb21pc2U7XG59XG5cblxuZnVuY3Rpb24gc2V0UmVxdWVzdEhlYWRlcnMocmVxLCBoZWFkZXJzKSB7XG4gICAgaWYgKGhlYWRlcnMpXG4gICAgICAgIF8uZWFjaEtleShoZWFkZXJzLCBmdW5jdGlvbih2YWx1ZSwga2V5KSB7XG4gICAgICAgICAgICByZXEuc2V0UmVxdWVzdEhlYWRlcihrZXksIHZhbHVlKTtcbiAgICAgICAgfSk7XG59XG5cbmZ1bmN0aW9uIF9vblJlYWR5KHJlcSwgY2FsbGJhY2ssIHhQcm9taXNlLCBldmVudFR5cGUpIHtcbiAgICBpZiAocmVxLnJlYWR5U3RhdGUgIT0gNCkgcmV0dXJuO1xuICAgIGlmICghcmVxLnN0YXR1cyAmJiBldmVudFR5cGUgPT0gJ3JlYWR5c3RhdGVjaGFuZ2UnKSByZXR1cm47XG5cbiAgICBfLnNwbGljZUl0ZW0oX3BlbmRpbmdSZXF1ZXN0cywgcmVxKTtcblxuICAgIHZhciBlcnJvcjtcbiAgICB0cnkge1xuICAgICAgICBpZiAoIHJlcS5zdGF0dXMgPj0gMjAwICYmIHJlcS5zdGF0dXMgPCA0MDAgKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHBvc3RNZXNzYWdlKCdzdWNjZXNzJyk7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2sgJiYgY2FsbGJhY2sobnVsbCwgcmVxLnJlc3BvbnNlVGV4dCwgcmVxKTtcbiAgICAgICAgICAgIH0gY2F0Y2goZSkgeyBlcnJvciA9IGU7IH1cbiAgICAgICAgICAgIHhQcm9taXNlLnJlc29sdmUocmVxLnJlc3BvbnNlVGV4dCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB2YXIgZXJyb3JSZWFzb24gPSByZXEuc3RhdHVzIHx8IGV2ZW50VHlwZTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgcG9zdE1lc3NhZ2UoJ2Vycm9yJyk7XG4gICAgICAgICAgICAgICAgcG9zdE1lc3NhZ2UoJ2Vycm9yJyArIGVycm9yUmVhc29uKTtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayAmJiBjYWxsYmFjayhlcnJvclJlYXNvbiwgcmVxLnJlc3BvbnNlVGV4dCwgcmVxKTtcbiAgICAgICAgICAgIH0gY2F0Y2goZSkgeyBlcnJvciA9IGU7IH1cbiAgICAgICAgICAgIHhQcm9taXNlLnJlamVjdCh7IHJlYXNvbjogZXJyb3JSZWFzb24sIHJlc3BvbnNlOiByZXEucmVzcG9uc2VUZXh0IH0pO1xuICAgICAgICB9XG4gICAgfSBjYXRjaChlKSB7XG4gICAgICAgIGVycm9yID0gZXJyb3IgfHwgZTtcbiAgICB9XG5cbiAgICAvLyBub3QgcmVtb3Zpbmcgc3Vic2NyaXB0aW9uIGNyZWF0ZXMgbWVtb3J5IGxlYWssIGRlbGV0aW5nIHByb3BlcnR5IHdvdWxkIG5vdCByZW1vdmUgc3Vic2NyaXB0aW9uXG4gICAgcmVxLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IHJlcS5vbnRpbWVvdXQgPSByZXEub25hYm9ydCA9IHVuZGVmaW5lZDtcblxuICAgIGlmICghX3BlbmRpbmdSZXF1ZXN0cy5sZW5ndGgpXG4gICAgICAgIHBvc3RNZXNzYWdlKCdyZXF1ZXN0c2NvbXBsZXRlZCcpO1xuXG4gICAgaWYgKGVycm9yKSB0aHJvdyBuZXcgRXJyb3IoJ0V4Y2VwdGlvbjogJyArIGVycm9yKTtcblxuICAgIGZ1bmN0aW9uIHBvc3RNZXNzYWdlKG1zZykge1xuICAgICAgICBpZiAoX21lc3NlbmdlcikgcmVxdWVzdC5wb3N0TWVzc2FnZShtc2csXG4gICAgICAgICAgICB7IHN0YXR1czogc3RhdHVzLCByZXNwb25zZTogcmVxLnJlc3BvbnNlVGV4dCB9KTtcbiAgICB9XG59XG5cblxuXy5leHRlbmQocmVxdWVzdCwge1xuICAgIGdldDogcmVxdWVzdCRnZXQsXG4gICAgcG9zdDogcmVxdWVzdCRwb3N0LFxuICAgIGpzb246IHJlcXVlc3QkanNvbixcbiAgICBqc29ucDogcmVxdWVzdCRqc29ucCxcbiAgICBmaWxlOiByZXF1ZXN0JGZpbGUsXG4gICAgdXNlTWVzc2VuZ2VyOiByZXF1ZXN0JHVzZU1lc3NlbmdlcixcbiAgICBkZXN0cm95OiByZXF1ZXN0JGRlc3Ryb3ksXG4gICAgd2hlblJlcXVlc3RzQ29tcGxldGVkOiB3aGVuUmVxdWVzdHNDb21wbGV0ZWRcbn0pO1xuXG5cbnZhciBfbWVzc2VuZ2VyO1xuXG5cbmZ1bmN0aW9uIHJlcXVlc3QkdXNlTWVzc2VuZ2VyKCkge1xuICAgIF9tZXNzZW5nZXIgPSBuZXcgTWVzc2VuZ2VyKHJlcXVlc3QsIFsnb24nLCAnb25jZScsICdvblN5bmMnLCAnb2ZmJywgJ29uTWVzc2FnZXMnLCAnb2ZmTWVzc2FnZXMnLCAncG9zdE1lc3NhZ2UnLCAncG9zdE1lc3NhZ2VTeW5jJ10pO1xufVxuXG5cbmZ1bmN0aW9uIHJlcXVlc3QkZ2V0KHVybCwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gcmVxdWVzdCh1cmwsIHsgbWV0aG9kOiAnR0VUJyB9LCBjYWxsYmFjayk7XG59XG5cblxuZnVuY3Rpb24gcmVxdWVzdCRwb3N0KHVybCwgZGF0YSwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gcmVxdWVzdCh1cmwsIHsgbWV0aG9kOiAnUE9TVCcsIGRhdGE6IGRhdGEgfSwgY2FsbGJhY2spO1xufVxuXG5cbmZ1bmN0aW9uIHJlcXVlc3QkanNvbih1cmwsIGNhbGxiYWNrKSB7XG4gICAgdmFyIHByb21pc2UgPSByZXF1ZXN0KHVybCwgeyBtZXRob2Q6ICdHRVQnIH0pO1xuXG4gICAgdmFyIGpzb25Qcm9taXNlID0gcHJvbWlzZS50aGVuKEpTT04ucGFyc2UpO1xuXG4gICAgaWYgKGNhbGxiYWNrKVxuICAgICAgICBqc29uUHJvbWlzZVxuICAgICAgICAudGhlbihmdW5jdGlvbihkYXRhKSB7IGNhbGxiYWNrKG51bGwsIGRhdGEpOyB9KVxuICAgICAgICAuY2F0Y2goZnVuY3Rpb24oZXJyRGF0YSkgeyBjYWxsYmFjayhlcnJEYXRhLnJlYXNvbiwgZXJyRGF0YS5yZXNwb25zZSk7IH0pO1xuXG4gICAgcmV0dXJuIGpzb25Qcm9taXNlO1xufVxuXG5cbnZhciBqc29ucE9wdGlvbnMgPSB7IG1ldGhvZDogJ0dFVCcsIGpzb25wOiB0cnVlIH07XG5mdW5jdGlvbiByZXF1ZXN0JGpzb25wKHVybCwgY2FsbGJhY2spIHtcbiAgICB2YXIgc2NyaXB0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0JyksXG4gICAgICAgIHhQcm9taXNlID0gX2NyZWF0ZVhQcm9taXNlKHNjcmlwdCksXG4gICAgICAgIGhlYWQgPSB3aW5kb3cuZG9jdW1lbnQuaGVhZCxcbiAgICAgICAgdW5pcXVlQ2FsbGJhY2sgPSBjb25maWcucmVxdWVzdC5qc29ucENhbGxiYWNrUHJlZml4ICsgY291bnQoKTtcblxuICAgIHZhciBvcHRzID0gXy5leHRlbmQoeyB1cmw6IHVybCB9LCBqc29ucE9wdGlvbnMpO1xuICAgIGlmIChfbWVzc2VuZ2VyKSByZXF1ZXN0LnBvc3RNZXNzYWdlU3luYygncmVxdWVzdCcsIHsgb3B0aW9uczogb3B0cyB9KTtcblxuICAgIGlmICghIF8uaXNFcXVhbChfLm9taXRLZXlzKG9wdHMsICd1cmwnKSwganNvbnBPcHRpb25zKSlcbiAgICAgICAgbG9nZ2VyLndhcm4oJ0lnbm9yZWQgbm90IGFsbG93ZWQgcmVxdWVzdCBvcHRpb25zIGNoYW5nZSBpbiBKU09OUCByZXF1ZXN0IC0gb25seSBVUkwgY2FuIGJlIGNoYW5nZWQnKTtcblxuICAgIHZhciB0aW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGVyciA9IG5ldyBFcnJvcignTm8gSlNPTlAgcmVzcG9uc2Ugb3Igbm8gY2FsbGJhY2sgaW4gcmVzcG9uc2UnKTtcbiAgICAgICAgX29uUmVzdWx0KGVycik7XG4gICAgfSwgY29uZmlnLnJlcXVlc3QuanNvbnBUaW1lb3V0KTtcblxuICAgIHdpbmRvd1t1bmlxdWVDYWxsYmFja10gPSBfLnBhcnRpYWwoX29uUmVzdWx0LCBudWxsKTtcblxuICAgIF9wZW5kaW5nUmVxdWVzdHMucHVzaCh3aW5kb3dbdW5pcXVlQ2FsbGJhY2tdKTtcblxuICAgIHNjcmlwdC50eXBlID0gJ3RleHQvamF2YXNjcmlwdCc7XG4gICAgc2NyaXB0LnNyYyA9IG9wdHMudXJsICsgKG9wdHMudXJsLmluZGV4T2YoJz8nKSA9PSAtMSA/ICc/JyA6ICcmJykgKyAnY2FsbGJhY2s9JyArIHVuaXF1ZUNhbGxiYWNrO1xuXG4gICAgaGVhZC5hcHBlbmRDaGlsZChzY3JpcHQpO1xuXG4gICAgcmV0dXJuIHhQcm9taXNlLnByb21pc2U7XG5cblxuICAgIGZ1bmN0aW9uIF9vblJlc3VsdChlcnIsIHJlc3VsdCkge1xuICAgICAgICBfLnNwbGljZUl0ZW0oX3BlbmRpbmdSZXF1ZXN0cywgd2luZG93W3VuaXF1ZUNhbGxiYWNrXSk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBwb3N0TWVzc2FnZShlcnIgPyAnZXJyb3InIDogJ3N1Y2Nlc3MnLCBlcnIsIHJlc3VsdCk7XG4gICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCdObyBKU09OUCByZXNwb25zZSBvciB0aW1lb3V0Jyk7XG4gICAgICAgICAgICAgICAgcG9zdE1lc3NhZ2UoJ2Vycm9yanNvbnB0aW1lb3V0JywgZXJyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbGxiYWNrICYmIGNhbGxiYWNrKGVyciwgcmVzdWx0KTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaChlKSB7IHZhciBlcnJvciA9IGU7IH1cbiAgICAgICAgaWYgKGVycikgeFByb21pc2UucmVqZWN0KGVycik7XG4gICAgICAgIGVsc2UgeFByb21pc2UucmVzb2x2ZShyZXN1bHQpO1xuXG4gICAgICAgIGNsZWFuVXAoKTtcbiAgICAgICAgaWYgKCFfcGVuZGluZ1JlcXVlc3RzLmxlbmd0aClcbiAgICAgICAgICAgIHBvc3RNZXNzYWdlKCdyZXF1ZXN0c2NvbXBsZXRlZCcpO1xuXG4gICAgICAgIGlmIChlcnJvcikgdGhyb3cgZXJyb3I7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBjbGVhblVwKCkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICAgIGhlYWQucmVtb3ZlQ2hpbGQoc2NyaXB0KTtcbiAgICAgICAgZGVsZXRlIHdpbmRvd1t1bmlxdWVDYWxsYmFja107XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBwb3N0TWVzc2FnZShtc2csIHN0YXR1cywgcmVzdWx0KSB7XG4gICAgICAgIGlmIChfbWVzc2VuZ2VyKSByZXF1ZXN0LnBvc3RNZXNzYWdlKG1zZyxcbiAgICAgICAgICAgIHsgc3RhdHVzOiBzdGF0dXMsIHJlc3BvbnNlOiByZXN1bHQgfSk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIHJlcXVlc3QkZmlsZShvcHRzLCBmaWxlRGF0YSwgY2FsbGJhY2ssIHByb2dyZXNzKSB7XG4gICAgaWYgKHR5cGVvZiBvcHRzID09ICdzdHJpbmcnKVxuICAgICAgICBvcHRzID0geyBtZXRob2Q6ICdQT1NUJywgdXJsOiBvcHRzIH07XG5cbiAgICBvcHRzLm1ldGhvZCA9IG9wdHMubWV0aG9kIHx8ICdQT1NUJztcbiAgICBvcHRzLmZpbGUgPSB0cnVlO1xuXG4gICAgaWYgKF9tZXNzZW5nZXIpIHJlcXVlc3QucG9zdE1lc3NhZ2VTeW5jKCdyZXF1ZXN0JywgeyBvcHRpb25zOiBvcHRzIH0pO1xuXG4gICAgdmFyIHJlcSA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpO1xuICAgIGlmIChwcm9ncmVzcykgcmVxLnVwbG9hZC5vbnByb2dyZXNzID0gcHJvZ3Jlc3M7XG5cbiAgICByZXEub3BlbihvcHRzLm1ldGhvZCwgb3B0cy51cmwsIHRydWUpO1xuICAgIHNldFJlcXVlc3RIZWFkZXJzKHJlcSwgb3B0cy5oZWFkZXJzKTtcblxuICAgIHJlcS50aW1lb3V0ID0gb3B0cy50aW1lb3V0IHx8IGNvbmZpZy5yZXF1ZXN0LmRlZmF1bHRzLnRpbWVvdXQ7XG4gICAgcmVxLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IHJlcS5vbnRpbWVvdXQgPSByZXEub25hYm9ydCA9IG9uUmVhZHk7XG5cbiAgICB2YXIgeFByb21pc2UgPSBfY3JlYXRlWFByb21pc2UocmVxKTtcblxuICAgIGlmIChvcHRzLmJpbmFyeSlcbiAgICAgICAgcmVxLnNlbmQoZmlsZURhdGEpO1xuICAgIGVsc2Uge1xuICAgICAgICB2YXIgZm9ybURhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgZm9ybURhdGEuYXBwZW5kKCdmaWxlJywgZmlsZURhdGEpO1xuICAgICAgICByZXEuc2VuZChmb3JtRGF0YSk7XG4gICAgfVxuXG4gICAgX3BlbmRpbmdSZXF1ZXN0cy5wdXNoKHJlcSk7XG5cbiAgICByZXR1cm4geFByb21pc2UucHJvbWlzZTtcblxuICAgIGZ1bmN0aW9uIG9uUmVhZHkoZSkge1xuICAgICAgICBpZiAocHJvZ3Jlc3MpIHJlcS51cGxvYWQub25wcm9ncmVzcyA9IHVuZGVmaW5lZDtcbiAgICAgICAgX29uUmVhZHkocmVxLCBjYWxsYmFjaywgeFByb21pc2UsIGUudHlwZSk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIHJlcXVlc3QkZGVzdHJveSgpIHtcbiAgICBpZiAoX21lc3NlbmdlcikgX21lc3Nlbmdlci5kZXN0cm95KCk7XG4gICAgcmVxdWVzdC5fZGVzdHJveWVkID0gdHJ1ZTtcbn1cblxuXG5mdW5jdGlvbiB3aGVuUmVxdWVzdHNDb21wbGV0ZWQoY2FsbGJhY2ssIHRpbWVvdXQpIHtcbiAgICBjYWxsYmFjayA9IF8ub25jZShjYWxsYmFjayk7XG4gICAgaWYgKHRpbWVvdXQpXG4gICAgICAgIF8uZGVsYXkoY2FsbGJhY2ssIHRpbWVvdXQsICd0aW1lb3V0Jyk7XG5cbiAgICBpZiAoX3BlbmRpbmdSZXF1ZXN0cy5sZW5ndGgpXG4gICAgICAgIF9tZXNzZW5nZXIub25jZSgncmVxdWVzdHNjb21wbGV0ZWQnLCBjYWxsYmFjayk7XG4gICAgZWxzZVxuICAgICAgICBfLmRlZmVyKGNhbGxiYWNrKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgZG9tVXRpbHMgPSByZXF1aXJlKCcuLi9kb20nKVxuICAgICwgY29udGFpbmluZ0VsZW1lbnQgPSBkb21VdGlscy5jb250YWluaW5nRWxlbWVudFxuICAgICwgc2V0Q2FyZXRQb3NpdGlvbiA9IGRvbVV0aWxzLnNldENhcmV0UG9zaXRpb25cbiAgICAsIGdldENvbXBvbmVudHNGcm9tUmFuZ2UgPSBkb21VdGlscy5nZXRDb21wb25lbnRzRnJvbVJhbmdlXG4gICAgLCBkZWxldGVSYW5nZVdpdGhDb21wb25lbnRzID0gZG9tVXRpbHMuZGVsZXRlUmFuZ2VXaXRoQ29tcG9uZW50c1xuICAgICwgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgbG9nZ2VyID0gbWlsb0NvcmUudXRpbC5sb2dnZXJcbiAgICAsIENvbXBvbmVudCA9IHJlcXVpcmUoJy4uLy4uL2NvbXBvbmVudHMvY19jbGFzcycpXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG87XG5cbm1vZHVsZS5leHBvcnRzID0gVGV4dFNlbGVjdGlvbjtcblxuXG4vKipcbiAqIFRleHQgc2VsZWN0aW9uIGNsYXNzLlxuICogU2VydmVzIGFzIGEgaGVscGVyIHRvIG1hbmFnZSBjdXJyZW50IHNlbGVjdGlvblxuICogVGhlIG9iamVjdCBjYW5ub3QgYmUgcmV1c2VkLCBpZiB0aGUgc2VsZWN0aW9uIGNoYW5nZXMgc29tZSBvZiBpdHMgcHJvcGVydGllcyBtYXkgY29udGFpbiBpbmZvcm1hdGlvbiByZWxhdGVkIHRvIHByZXZpb3VzIHNlbGVjdGlvblxuICpcbiAqIEBwYXJhbSB7V2luZG93fSB3aW4gd2luZG93IGluIHdoaWNoIHRleHQgc2VsZWN0aW9uIGlzIHByb2Nlc3NlZFxuICovXG5mdW5jdGlvbiBUZXh0U2VsZWN0aW9uKHdpbikge1xuICAgIGlmICghIHRoaXMgaW5zdGFuY2VvZiBUZXh0U2VsZWN0aW9uKVxuICAgICAgICByZXR1cm4gbmV3IFRleHRTZWxlY3Rpb24od2luKTtcbiAgICB0aGlzLndpbmRvdyA9IHdpbiB8fCB3aW5kb3c7XG4gICAgdGhpcy5pbml0KCk7XG59XG5cblxuLyoqXG4gKiBUZXh0U2VsZWN0aW9uIGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyBzZWxlY3Rpb24gc3RhcnQgZWxlbWVudFxuICpcbiAqIEByZXR1cm4ge0VsZW1lbnR8bnVsbH1cbiAqL1xudmFyIFRleHRTZWxlY3Rpb24kc3RhcnRFbGVtZW50ID0gXG4gICAgXy5wYXJ0aWFsKF9nZXRFbGVtZW50LCAnX3N0YXJ0RWxlbWVudCcsICdzdGFydENvbnRhaW5lcicpO1xuXG5cbi8qKlxuICogVGV4dFNlbGVjdGlvbiBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgc2VsZWN0aW9uIGVuZCBlbGVtZW50XG4gKlxuICogQHJldHVybiB7RWxlbWVudHxudWxsfVxuICovXG52YXIgVGV4dFNlbGVjdGlvbiRlbmRFbGVtZW50ID0gXG4gICAgXy5wYXJ0aWFsKF9nZXRFbGVtZW50LCAnX2VuZEVsZW1lbnQnLCAnZW5kQ29udGFpbmVyJyk7XG5cblxuLyoqXG4gKiBUZXh0U2VsZWN0aW9uIGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyBzZWxlY3Rpb24gZW5kIGVsZW1lbnRcbiAqXG4gKiBAcmV0dXJuIHtFbGVtZW50fG51bGx9XG4gKi9cbnZhciBUZXh0U2VsZWN0aW9uJGNvbnRhaW5pbmdFbGVtZW50ID0gXG4gICAgXy5wYXJ0aWFsKF9nZXRFbGVtZW50LCAnX2NvbnRhaW5pbmdFbGVtZW50JywgJ2NvbW1vbkFuY2VzdG9yQ29udGFpbmVyJyk7XG5cblxuLyoqXG4gKiBUZXh0U2VsZWN0aW9uIGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyBzZWxlY3Rpb24gc3RhcnQgQ29tcG9uZW50XG4gKlxuICogQHJldHVybiB7Q29tcG9uZW50fVxuICovXG52YXIgVGV4dFNlbGVjdGlvbiRzdGFydENvbXBvbmVudCA9IFxuICAgIF8ucGFydGlhbChfZ2V0Q29tcG9uZW50LCAnX3N0YXJ0Q29tcG9uZW50JywgJ3N0YXJ0RWxlbWVudCcpO1xuXG5cbi8qKlxuICogVGV4dFNlbGVjdGlvbiBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgc2VsZWN0aW9uIGVuZCBDb21wb25lbnRcbiAqXG4gKiBAcmV0dXJuIHtDb21wb25lbnR9XG4gKi9cbnZhciBUZXh0U2VsZWN0aW9uJGVuZENvbXBvbmVudCA9IFxuICAgIF8ucGFydGlhbChfZ2V0Q29tcG9uZW50LCAnX2VuZENvbXBvbmVudCcsICdlbmRFbGVtZW50Jyk7XG5cblxuLyoqXG4gKiBUZXh0U2VsZWN0aW9uIGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyBzZWxlY3Rpb24gZW5kIENvbXBvbmVudFxuICpcbiAqIEByZXR1cm4ge0NvbXBvbmVudH1cbiAqL1xudmFyIFRleHRTZWxlY3Rpb24kY29udGFpbmluZ0NvbXBvbmVudCA9IFxuICAgIF8ucGFydGlhbChfZ2V0Q29tcG9uZW50LCAnX2NvbnRhaW5pbmdDb21wb25lbnQnLCAnY29udGFpbmluZ0VsZW1lbnQnKTtcblxuXG5fLmV4dGVuZFByb3RvKFRleHRTZWxlY3Rpb24sIHtcbiAgICBpbml0OiBUZXh0U2VsZWN0aW9uJGluaXQsXG4gICAgdGV4dDogVGV4dFNlbGVjdGlvbiR0ZXh0LFxuICAgIHRleHROb2RlczogVGV4dFNlbGVjdGlvbiR0ZXh0Tm9kZXMsXG4gICAgY2xlYXI6IFRleHRTZWxlY3Rpb24kY2xlYXIsXG5cbiAgICBzdGFydEVsZW1lbnQ6IFRleHRTZWxlY3Rpb24kc3RhcnRFbGVtZW50LFxuICAgIGVuZEVsZW1lbnQ6IFRleHRTZWxlY3Rpb24kZW5kRWxlbWVudCxcbiAgICBjb250YWluaW5nRWxlbWVudDogVGV4dFNlbGVjdGlvbiRjb250YWluaW5nRWxlbWVudCxcblxuICAgIHN0YXJ0Q29tcG9uZW50OiBUZXh0U2VsZWN0aW9uJHN0YXJ0Q29tcG9uZW50LFxuICAgIGVuZENvbXBvbmVudDogVGV4dFNlbGVjdGlvbiRlbmRDb21wb25lbnQsXG4gICAgY29udGFpbmluZ0NvbXBvbmVudDogVGV4dFNlbGVjdGlvbiRjb250YWluaW5nQ29tcG9uZW50LFxuXG4gICAgY29udGFpbmVkQ29tcG9uZW50czogVGV4dFNlbGVjdGlvbiRjb250YWluZWRDb21wb25lbnRzLFxuICAgIGVhY2hDb250YWluZWRDb21wb25lbnQ6IFRleHRTZWxlY3Rpb24kZWFjaENvbnRhaW5lZENvbXBvbmVudCxcbiAgICBkZWw6IFRleHRTZWxlY3Rpb24kZGVsLFxuICAgIF9nZXRQb3N0RGVsZXRlU2VsZWN0aW9uUG9pbnQ6IF9nZXRQb3N0RGVsZXRlU2VsZWN0aW9uUG9pbnQsXG4gICAgX3NlbGVjdEFmdGVyRGVsZXRlOiBfc2VsZWN0QWZ0ZXJEZWxldGUsXG5cbiAgICBnZXRSYW5nZTogVGV4dFNlbGVjdGlvbiRnZXRSYW5nZSxcbiAgICBnZXRTdGF0ZTogVGV4dFNlbGVjdGlvbiRnZXRTdGF0ZSxcbiAgICBnZXROb3JtYWxpemVkUmFuZ2U6IFRleHRTZWxlY3Rpb24kJGdldE5vcm1hbGl6ZWRSYW5nZSxcbiAgICBnZXREaXJlY3Rpb246IFRleHRTZWxlY3Rpb24kJGdldERpcmVjdGlvblxufSk7XG5cblxuXy5leHRlbmQoVGV4dFNlbGVjdGlvbiwge1xuICAgIGNyZWF0ZUZyb21SYW5nZTogVGV4dFNlbGVjdGlvbiQkY3JlYXRlRnJvbVJhbmdlLFxuICAgIGNyZWF0ZUZyb21TdGF0ZTogVGV4dFNlbGVjdGlvbiQkY3JlYXRlRnJvbVN0YXRlLFxuICAgIGNyZWF0ZVN0YXRlT2JqZWN0OiBUZXh0U2VsZWN0aW9uJCRjcmVhdGVTdGF0ZU9iamVjdFxufSk7XG5cblxuLyoqXG4gKiBUZXh0U2VsZWN0aW9uIGluc3RhbmNlIG1ldGhvZFxuICogSW5pdGlhbGl6ZXMgVGV4dFNlbGVjdGlvbiBmcm9tIHRoZSBjdXJyZW50IHNlbGVjdGlvblxuICovXG5mdW5jdGlvbiBUZXh0U2VsZWN0aW9uJGluaXQoKSB7XG4gICAgdGhpcy5zZWxlY3Rpb24gPSB0aGlzLndpbmRvdy5nZXRTZWxlY3Rpb24oKTtcbiAgICBpZiAodGhpcy5zZWxlY3Rpb24ucmFuZ2VDb3VudClcbiAgICAgICAgdGhpcy5yYW5nZSA9IHRoaXMuc2VsZWN0aW9uLmdldFJhbmdlQXQoMCk7XG4gICAgdGhpcy5pc0NvbGxhcHNlZCA9IHRoaXMuc2VsZWN0aW9uLmlzQ29sbGFwc2VkO1xufVxuXG5cbi8qKlxuICogVGV4dFNlbGVjdGlvbiBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyBzZWxlY3Rpb24gdGV4dFxuICpcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gVGV4dFNlbGVjdGlvbiR0ZXh0KCkge1xuICAgIGlmICghIHRoaXMucmFuZ2UpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICBpZiAoISB0aGlzLl90ZXh0KVxuICAgICAgICB0aGlzLl90ZXh0ID0gdGhpcy5yYW5nZS50b1N0cmluZygpO1xuXG4gICAgcmV0dXJuIHRoaXMuX3RleHQ7XG59XG5cblxuLyoqXG4gKiBUZXh0U2VsZWN0aW9uIGluc3RhbmNlIG1ldGhvZFxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHNlbGVjdGlvbiB0ZXh0IG5vZGVzXG4gKlxuICogQHJldHVybiB7QXJyYXlbTm9kZV19XG4gKi9cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kdGV4dE5vZGVzKCkge1xuICAgIGlmICghIHRoaXMucmFuZ2UpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICBpZiAoISB0aGlzLl90ZXh0Tm9kZXMpXG4gICAgICAgIHRoaXMuX3RleHROb2RlcyA9IF9nZXRUZXh0Tm9kZXMuY2FsbCh0aGlzKTtcbiAgICByZXR1cm4gdGhpcy5fdGV4dE5vZGVzO1xufVxuXG5cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kY2xlYXIoKSB7XG4gICAgdGhpcy5zZWxlY3Rpb24ucmVtb3ZlQWxsUmFuZ2VzKCk7XG59XG5cblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGV4dCBhbmQgdGV4dCBub2RlcyBmcm9tIHNlbGVjdGlvbiBzYXZpbmcgdGhlbSBvbiBwcm9wZXJ0aWVzIG9mIG9iamVjdFxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge1RleHRTZWxlY3Rpb259IHRoaXNcbiAqL1xuZnVuY3Rpb24gX2dldFRleHROb2RlcygpIHtcbiAgICAvLyBsaXN0IG9mIHNlbGVjdGVkIHRleHQgbm9kZXNcbiAgICB2YXIgdGV4dE5vZGVzID0gW107XG5cbiAgICBpZiAodGhpcy5pc0NvbGxhcHNlZClcbiAgICAgICAgcmV0dXJuIHRleHROb2RlcztcblxuICAgIC8vIGNyZWF0ZSBUcmVlV2Fsa2VyIHRvIHRyYXZlcnNlIHRoZSB0cmVlIHRvIHNlbGVjdCBhbGwgdGV4dCBub2Rlc1xuICAgIHZhciBzZWxTdGFydCA9IHRoaXMucmFuZ2Uuc3RhcnRDb250YWluZXJcbiAgICAgICAgLCBzZWxFbmQgPSB0aGlzLnJhbmdlLmVuZENvbnRhaW5lclxuICAgICAgICAsIHJhbmdlQ29udGFpbmVyID0gdGhpcy5yYW5nZS5jb21tb25BbmNlc3RvckNvbnRhaW5lcjtcblxuICAgIHZhciB0cmVlV2Fsa2VyID0gdGhpcy53aW5kb3cuZG9jdW1lbnQuY3JlYXRlVHJlZVdhbGtlcihyYW5nZUNvbnRhaW5lciwgTm9kZUZpbHRlci5TSE9XX1RFWFQpO1xuICAgIHZhciBub2RlID0gdHJlZVdhbGtlci5jdXJyZW50Tm9kZSA9IHNlbFN0YXJ0O1xuXG4gICAgLy8gdHJhdmVyc2UgRE9NIHRyZWUgdG8gY29sbGVjdCBhbGwgc2VsZWN0ZWQgdGV4dCBub2Rlc1xuICAgIHdoaWxlIChub2RlICYmICghIGluRW5kIHx8IHNlbEVuZC5jb250YWlucyhub2RlKSkpIHtcbiAgICAgICAgdGV4dE5vZGVzLnB1c2gobm9kZSk7XG4gICAgICAgIHZhciBpbkVuZCA9IGluRW5kIHx8IHNlbEVuZC5jb250YWlucyhub2RlKTtcbiAgICAgICAgbm9kZSA9IHRyZWVXYWxrZXIubmV4dE5vZGUoKTtcbiAgICB9XG4gICAgcmV0dXJuIHRleHROb2Rlcztcbn1cblxuXG4vKipcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyBzdGFydC9lbmQgZWxlbWVudCBmcm9tIHNlbGVjdGlvbiBzYXZpbmcgdGhlbSBvbiBwcm9wZXJ0aWVzIG9mIG9iamVjdFxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge1RleHRTZWxlY3Rpb259IHRoaXNcbiAqIEByZXR1cm4ge0VsZW1lbnR8bnVsbH1cbiAqL1xuZnVuY3Rpb24gX2dldEVsZW1lbnQodGhpc1Byb3BOYW1lLCByYW5nZVByb3BOYW1lKSB7XG4gICAgaWYgKCEgdGhpcy5yYW5nZSkgcmV0dXJuIHVuZGVmaW5lZDtcblxuICAgIGlmICh0eXBlb2YgdGhpc1t0aGlzUHJvcE5hbWVdID09ICd1bmRlZmluZWQnKVxuICAgICAgICB0aGlzW3RoaXNQcm9wTmFtZV0gPSBjb250YWluaW5nRWxlbWVudCh0aGlzLnJhbmdlW3JhbmdlUHJvcE5hbWVdKTtcbiAgICByZXR1cm4gdGhpc1t0aGlzUHJvcE5hbWVdO1xufVxuXG5cbi8qKlxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHN0YXJ0L2VuZCBjb21wb25lbnQgZnJvbSBzZWxlY3Rpb24gc2F2aW5nIHRoZW0gb24gcHJvcGVydGllcyBvZiBvYmplY3RcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtUZXh0U2VsZWN0aW9ufSB0aGlzXG4gKiBAcmV0dXJuIHtDb21wb25lbnR9XG4gKi9cbmZ1bmN0aW9uIF9nZXRDb21wb25lbnQodGhpc1Byb3BOYW1lLCBlbE1ldGhvZE5hbWUpIHtcbiAgICBpZiAoISB0aGlzLnJhbmdlKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gICAgaWYgKHR5cGVvZiB0aGlzW3RoaXNQcm9wTmFtZV0gPT0gJ3VuZGVmaW5lZCcpXG4gICAgICAgIHRoaXNbdGhpc1Byb3BOYW1lXSA9IENvbXBvbmVudC5nZXRDb250YWluaW5nQ29tcG9uZW50KHRoaXNbZWxNZXRob2ROYW1lXSgpKTtcbiAgICByZXR1cm4gdGhpc1t0aGlzUHJvcE5hbWVdO1xufVxuXG5cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kY29udGFpbmVkQ29tcG9uZW50cygpIHtcbiAgICBpZiAodGhpcy5fY29udGFpbmVkQ29tcG9uZW50cylcbiAgICAgICAgcmV0dXJuIHRoaXMuX2NvbnRhaW5lZENvbXBvbmVudHM7XG5cbiAgICB2YXIgY29tcG9uZW50cyA9IHRoaXMuX2NvbnRhaW5lZENvbXBvbmVudHMgPSBbXTtcblxuICAgIGlmICh0aGlzLmlzQ29sbGFwc2VkIHx8ICEgdGhpcy5yYW5nZSkgcmV0dXJuIGNvbXBvbmVudHM7XG5cbiAgICByZXR1cm4gZ2V0Q29tcG9uZW50c0Zyb21SYW5nZSh0aGlzLnJhbmdlKTtcbn1cblxuXG5mdW5jdGlvbiBUZXh0U2VsZWN0aW9uJGVhY2hDb250YWluZWRDb21wb25lbnQoY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICBpZiAodGhpcy5pc0NvbGxhcHNlZCB8fCAhIHRoaXMucmFuZ2UpIHJldHVybjtcblxuICAgIHZhciBjb21wb25lbnRzID0gdGhpcy5jb250YWluZWRDb21wb25lbnRzKCk7XG5cbiAgICBjb21wb25lbnRzLmZvckVhY2goY2FsbGJhY2ssIHRoaXNBcmcpO1xufVxuXG5cbi8qKlxuICogVGV4dFNlbGVjdGlvbiBpbnN0YW5jZSBtZXRob2RcbiAqIERlbGV0ZXMgdGhlIGN1cnJlbnQgc2VsZWN0aW9uIGFuZCBhbGwgY29tcG9uZW50cyBpbiBpdFxuICogXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHNlbGVjdEVuZENvbnRhaW5lciBzZXQgdG8gdHJ1ZSBpZiB0aGUgZW5kIGNvbnRhaW5lciBzaG91bGQgYmUgc2VsZWN0ZWQgYWZ0ZXIgZGVsZXRpb25cbiAqL1xuZnVuY3Rpb24gVGV4dFNlbGVjdGlvbiRkZWwoc2VsZWN0RW5kQ29udGFpbmVyKSB7XG4gICAgaWYgKHRoaXMuaXNDb2xsYXBzZWQgfHwgISB0aGlzLnJhbmdlKSByZXR1cm47XG5cbiAgICB2YXIgc2VsUG9pbnQgPSB0aGlzLl9nZXRQb3N0RGVsZXRlU2VsZWN0aW9uUG9pbnQoc2VsZWN0RW5kQ29udGFpbmVyKTtcblxuICAgIGRlbGV0ZVJhbmdlV2l0aENvbXBvbmVudHModGhpcy5yYW5nZSk7XG5cbiAgICB0aGlzLl9zZWxlY3RBZnRlckRlbGV0ZShzZWxQb2ludCk7XG4gICAgc2VsUG9pbnQubm9kZS5wYXJlbnROb2RlLm5vcm1hbGl6ZSgpO1xufVxuXG5cbmZ1bmN0aW9uIF9nZXRQb3N0RGVsZXRlU2VsZWN0aW9uUG9pbnQoc2VsZWN0RW5kQ29udGFpbmVyKSB7XG4gICAgdmFyIHNlbE5vZGUgPSB0aGlzLnJhbmdlLnN0YXJ0Q29udGFpbmVyO1xuICAgIHZhciBzZWxPZmZzZXQgPSB0aGlzLnJhbmdlLnN0YXJ0T2Zmc2V0O1xuICAgIGlmIChzZWxlY3RFbmRDb250YWluZXIgJiYgdGhpcy5yYW5nZS5zdGFydENvbnRhaW5lciAhPSB0aGlzLnJhbmdlLmVuZENvbnRhaW5lcikge1xuICAgICAgICBzZWxOb2RlID0gdGhpcy5yYW5nZS5lbmRDb250YWluZXI7XG4gICAgICAgIHNlbE9mZnNldCA9IDA7XG4gICAgfVxuICAgIHJldHVybiB7IG5vZGU6IHNlbE5vZGUsIG9mZnNldDogc2VsT2Zmc2V0IH07XG59XG5cblxuZnVuY3Rpb24gX3NlbGVjdEFmdGVyRGVsZXRlKHNlbFBvaW50KSB7XG4gICAgdmFyIHNlbE5vZGUgPSBzZWxQb2ludC5ub2RlXG4gICAgICAgICwgc2VsT2Zmc2V0ID0gc2VsUG9pbnQub2Zmc2V0O1xuXG4gICAgaWYgKCFzZWxOb2RlKSByZXR1cm47XG4gICAgaWYgKHNlbE5vZGUubm9kZVR5cGUgPT0gTm9kZS5URVhUX05PREUpXG4gICAgICAgIHNlbE5vZGUudGV4dENvbnRlbnQgPSBzZWxOb2RlLnRleHRDb250ZW50LnRyaW1SaWdodCgpO1xuICAgIGlmICghc2VsTm9kZS5ub2RlVmFsdWUpXG4gICAgICAgIHNlbE5vZGUubm9kZVZhbHVlID0gJ1xcdTAwQTAnOyAvL25vbi1icmVha2luZyBzcGFjZSwgXFx1MjAwQiBmb3IgemVybyB3aWR0aCBzcGFjZTtcblxuICAgIHZhciBwb3NpdGlvbiA9IHNlbE9mZnNldCA+IHNlbE5vZGUubGVuZ3RoID8gc2VsTm9kZS5sZW5ndGggOiBzZWxPZmZzZXQ7XG4gICAgc2V0Q2FyZXRQb3NpdGlvbihzZWxOb2RlLCBwb3NpdGlvbik7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIHNlbGVjdGlvbiByYW5nZVxuICpcbiAqIEByZXR1cm4ge1JhbmdlfVxuICovXG5mdW5jdGlvbiBUZXh0U2VsZWN0aW9uJGdldFJhbmdlKCkge1xuICAgIHJldHVybiB0aGlzLnJhbmdlO1xufVxuXG5cbi8qKlxuICogU3RvcmVzIHNlbGVjdGlvbiB3aW5kb3csIG5vZGVzIGFuZCBvZmZzZXRzIGluIG9iamVjdFxuICovXG5mdW5jdGlvbiBUZXh0U2VsZWN0aW9uJGdldFN0YXRlKHJvb3RFbCkge1xuICAgIHZhciByID0gdGhpcy5yYW5nZTtcbiAgICB2YXIgZG9jID0gcm9vdEVsLm93bmVyRG9jdW1lbnRcbiAgICAgICAgLCB3aW4gPSBkb2MuZGVmYXVsdFZpZXcgfHwgZG9jLnBhcmVudFdpbmRvdztcbiAgICBpZiAoIXIpIHJldHVybiB7IHdpbmRvdzogd2luIH07XG4gICAgcmV0dXJuIFRleHRTZWxlY3Rpb24uY3JlYXRlU3RhdGVPYmplY3Qocm9vdEVsLCByLnN0YXJ0Q29udGFpbmVyLCByLnN0YXJ0T2Zmc2V0LCByLmVuZENvbnRhaW5lciwgci5lbmRPZmZzZXQpO1xufVxuXG5cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kJGNyZWF0ZVN0YXRlT2JqZWN0KHJvb3RFbCwgc3RhcnRDb250YWluZXIsIHN0YXJ0T2Zmc2V0LCBlbmRDb250YWluZXIsIGVuZE9mZnNldCkge1xuICAgIGVuZENvbnRhaW5lciA9IGVuZENvbnRhaW5lciB8fCBzdGFydENvbnRhaW5lcjtcbiAgICBlbmRPZmZzZXQgPSBlbmRPZmZzZXQgfHwgc3RhcnRPZmZzZXQ7XG4gICAgdmFyIGRvYyA9IHJvb3RFbC5vd25lckRvY3VtZW50XG4gICAgICAgICwgd2luID0gZG9jLmRlZmF1bHRWaWV3IHx8IGRvYy5wYXJlbnRXaW5kb3c7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgd2luZG93OiB3aW4sXG4gICAgICAgIHJvb3RFbDogcm9vdEVsLFxuICAgICAgICBzdGFydDogX2dldFNlbGVjdGlvblBvaW50U3RhdGUocm9vdEVsLCBzdGFydENvbnRhaW5lciwgc3RhcnRPZmZzZXQpLFxuICAgICAgICBlbmQ6IF9nZXRTZWxlY3Rpb25Qb2ludFN0YXRlKHJvb3RFbCwgZW5kQ29udGFpbmVyLCBlbmRPZmZzZXQpXG4gICAgfTtcbn1cblxuXG5mdW5jdGlvbiBfZ2V0U2VsZWN0aW9uUG9pbnRTdGF0ZShyb290RWwsIG5vZGUsIG9mZnNldCkge1xuICAgIHZhciB0cmVlUGF0aCA9IGRvbVV0aWxzLnRyZWVQYXRoT2Yocm9vdEVsLCBub2RlKTtcbiAgICBpZiAoISB0cmVlUGF0aCkgbG9nZ2VyLmVycm9yKCdTZWxlY3Rpb24gcG9pbnQgaXMgb3V0c2lkZSBvZiByb290IGVsZW1lbnQnKTtcbiAgICByZXR1cm4ge1xuICAgICAgICB0cmVlUGF0aDogdHJlZVBhdGgsXG4gICAgICAgIG9mZnNldDogb2Zmc2V0XG4gICAgfTtcbn1cblxuXG4vKipcbiAqIFJlc3RvcmVzIGFjdHVhbCBzZWxlY3Rpb24gdG8gdGhlIHN0b3JlZCByYW5nZVxuICovXG5mdW5jdGlvbiBUZXh0U2VsZWN0aW9uJCRjcmVhdGVGcm9tU3RhdGUoc3RhdGUpIHtcbiAgICB2YXIgZG9tVXRpbHMgPSBzdGF0ZS53aW5kb3cubWlsby51dGlsLmRvbTtcblxuICAgIGlmIChzdGF0ZS5yb290RWwgJiYgc3RhdGUuc3RhcnQgJiYgc3RhdGUuZW5kKSB7XG4gICAgICAgIHZhciBzdGFydE5vZGUgPSBfc2VsZWN0aW9uTm9kZUZyb21TdGF0ZShzdGF0ZS5yb290RWwsIHN0YXRlLnN0YXJ0KVxuICAgICAgICAgICAgLCBlbmROb2RlID0gX3NlbGVjdGlvbk5vZGVGcm9tU3RhdGUoc3RhdGUucm9vdEVsLCBzdGF0ZS5lbmQpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBkb21VdGlscy5zZXRTZWxlY3Rpb24oc3RhcnROb2RlLCBzdGF0ZS5zdGFydC5vZmZzZXQsIGVuZE5vZGUsIHN0YXRlLmVuZC5vZmZzZXQpO1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBUZXh0U2VsZWN0aW9uKHN0YXRlLndpbmRvdyk7XG4gICAgICAgIH0gY2F0Y2goZSkge1xuICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCdUZXh0IHNlbGVjdGlvbjogY2FuXFwndCBjcmVhdGUgc2VsZWN0aW9uJywgZSwgZS5tZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAgIGRvbVV0aWxzLmNsZWFyU2VsZWN0aW9uKHN0YXRlLndpbmRvdyk7XG4gICAgICAgIHJldHVybiBuZXcgVGV4dFNlbGVjdGlvbihzdGF0ZS53aW5kb3cpO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBfc2VsZWN0aW9uTm9kZUZyb21TdGF0ZShyb290RWwsIHBvaW50U3RhdGUpIHtcbiAgICB2YXIgbm9kZSA9IGRvbVV0aWxzLmdldE5vZGVBdFRyZWVQYXRoKHJvb3RFbCwgcG9pbnRTdGF0ZS50cmVlUGF0aCk7XG4gICAgaWYgKCEgbm9kZSkgbG9nZ2VyLmVycm9yKCdUZXh0U2VsZWN0aW9uIGNyZWF0ZUZyb21TdGF0ZTogbm8gbm9kZSBhdCB0cmVlUGF0aCcpO1xuICAgIHJldHVybiBub2RlO1xufVxuXG5cbi8qKlxuICogQ3JlYXRlcyBzZWxlY3Rpb24gZnJvbSBwYXNzZWQgcmFuZ2VcbiAqIFxuICogQHBhcmFtIHtSYW5nZX0gcmFuZ2VcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gYmFja3dhcmRcbiAqXG4gKiBAcmV0dXJuIHtUZXh0U2VsZWN0aW9ufVxuICovXG5mdW5jdGlvbiBUZXh0U2VsZWN0aW9uJCRjcmVhdGVGcm9tUmFuZ2UocmFuZ2UsIGJhY2t3YXJkKSB7XG4gICAgdmFyIHdpbiA9IHJhbmdlLnN0YXJ0Q29udGFpbmVyLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXdcbiAgICAgICAgLCBzZWwgPSB3aW4uZ2V0U2VsZWN0aW9uKClcbiAgICAgICAgLCBlbmRSYW5nZTtcblxuICAgIHNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcblxuICAgIGlmIChiYWNrd2FyZCl7XG4gICAgICAgIGVuZFJhbmdlID0gcmFuZ2UuY2xvbmVSYW5nZSgpO1xuICAgICAgICBlbmRSYW5nZS5jb2xsYXBzZShmYWxzZSk7XG5cbiAgICAgICAgc2VsLmFkZFJhbmdlKGVuZFJhbmdlKTtcbiAgICAgICAgc2VsLmV4dGVuZChyYW5nZS5zdGFydENvbnRhaW5lciwgcmFuZ2Uuc3RhcnRPZmZzZXQpICAgICAgICBcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHNlbC5hZGRSYW5nZShyYW5nZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBUZXh0U2VsZWN0aW9uKHdpbik7XG59XG5cbi8qKlxuICogUmV0dXJucyBhIG5vcm1hbGl6ZWQgY29weSBvZiB0aGUgcmFuZ2VcbiAqIElmIHlvdSB0cmlwbGUgY2xpY2sgYW4gaXRlbSwgdGhlIGVuZCBvZiB0aGUgcmFuZ2UgaXMgcG9zaXRpb25lZCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBORVhUIG5vZGUuXG4gKiB0aGlzIGZ1bmN0aW9uIHJldHVybnMgYSByYW5nZSB3aXRoIHRoZSBlbmQgcG9zaXRpb25lZCBhdCB0aGUgZW5kIG9mIHRoZSBsYXN0IHRleHRub2RlIGNvbnRhaW5lZCBcbiAqIGluc2lkZSBhIGNvbXBvbmVudCB3aXRoIHRoZSBcImVkaXRhYmxlXCIgZmFjZXRcbiAqIFxuICogQHJldHVybiB7cmFuZ2V9XG4gKi9cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kJGdldE5vcm1hbGl6ZWRSYW5nZSgpe1xuICAgIHZhciBkb2MgPSB0aGlzLnJhbmdlLmNvbW1vbkFuY2VzdG9yQ29udGFpbmVyLm93bmVyRG9jdW1lbnRcbiAgICAgICAgLCB0dywgcHJldmlvdXNOb2RlXG4gICAgICAgICwgbmV3UmFuZ2UgPSB0aGlzLnJhbmdlLmNsb25lUmFuZ2UoKTtcblxuICAgIGlmIChuZXdSYW5nZS5lbmRDb250YWluZXIubm9kZVR5cGUgIT09IE5vZGUuVEVYVF9OT0RFKSB7XG4gICAgICAgIHR3ID0gZG9jLmNyZWF0ZVRyZWVXYWxrZXIoZG9jLmJvZHksIE5vZGVGaWx0ZXIuU0hPV19URVhUKTtcbiAgICAgICAgdHcuY3VycmVudE5vZGUgPSBuZXdSYW5nZS5lbmRDb250YWluZXI7XG4gICAgICAgIHByZXZpb3VzTm9kZSA9IHR3LnByZXZpb3VzTm9kZSgpO1xuICAgICAgICBuZXdSYW5nZS5zZXRFbmQocHJldmlvdXNOb2RlLCBwcmV2aW91c05vZGUubGVuZ3RoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3UmFuZ2U7XG59XG5cbi8qKlxuICogZ2V0IHRoZSBkaXJlY3Rpb24gb2YgYSBzZWxlY3Rpb25cbiAqXG4gKiAxIGZvcndhcmQsIC0xIGJhY2t3YXJkLCAwIG5vIGRpcmVjdGlvbiwgdW5kZWZpbmVkIG9uZSBvZiB0aGUgbm9kZSBpcyBkZXRhY2hlZCBvciBpbiBhIGRpZmZlcmVudCBmcmFtZVxuICpcbiAqIEByZXR1cm4gey0xfDB8MXx1bmRlZmluZWR9XG4gKi9cbmZ1bmN0aW9uIFRleHRTZWxlY3Rpb24kJGdldERpcmVjdGlvbigpe1xuICAgIHJldHVybiBkb21VdGlscy5nZXRTZWxlY3Rpb25EaXJlY3Rpb24odGhpcy5zZWxlY3Rpb24pOyAgICBcbn1cblxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNZXNzZW5nZXIgPSBtaWxvQ29yZS5NZXNzZW5nZXJcbiAgICAsIFN0b3JhZ2VNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi9tc2dfc3JjJylcbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4uLy4uL2NvbmZpZycpXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIGNoZWNrID0gbWlsb0NvcmUudXRpbC5jaGVja1xuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaDtcblxucmVxdWlyZSgnLi9tb2RlbCcpXG5cbm1vZHVsZS5leHBvcnRzID0gRE9NU3RvcmFnZTtcblxuXG4vLyBzaGFyZWQga2V5cyBzdG9yZWQgYnkgYWxsIGluc3RhbmNlcywgaW5jbHVkZSBrZXkgcHJlZml4ZXNcbnZhciBfc3RvcmVkS2V5cyA9IHtcbiAgICB0cnVlOiB7fSwgLy8gc2Vzc2lvbiBzdG9yYWdlXG4gICAgZmFsc2U6IHt9IC8vIGxvY2FsIHN0b3JhZ2Vcbn07XG5cblxuLyoqXG4gKiBET01TdG9yYWdlIGNsYXNzIHRvIHNpbXBsaWZ5IHN0b3JhZ2UgYW5kIHJldHJpZXZhbCBvZiBtdWx0aXBsZSBpdGVtcyB3aXRoIHR5cGVzIHByZXNlcnZhdGlvbiB0byBET00gc3RvcmFnZSAobG9jYWxTdG9yYWdlIGFuZCBzZXNzaW9uU3RvcmFnZSkuXG4gKiBUeXBlcyB3aWxsIGJlIHN0b3JlZCBpbiB0aGUga2V5IGNyZWF0ZWQgZnJvbSB2YWx1ZSBrZXlzIHdpdGggYXBwZW5kZWQgYG1pbG8uY29uZmlnLmRvbVN0b3JhZ2UudHlwZVN1ZmZpeGBcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30ga2V5UHJlZml4IHByZWZpeCB0aGF0IHdpbGwgYmUgYWRkZWQgdG8gYWxsIGtleXMgZm9sbG93ZWQgYnkgYG1pbG8uY29uZmlnLmRvbVN0b3JhZ2UucHJlZml4U2VwYXJhdG9yYCAoXCIvXCIgYnkgZGVmYXVsdCkuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHNlc3Npb25Pbmx5IHRydWUgdG8gdXNlIHNlc3Npb25TdG9yYWdlLiBsb2NhbFN0b3JhZ2Ugd2lsbCBiZSB1c2VkIGJ5IGRlZmF1bHQuXG4gKiBAcGFyYW0ge1dpbmRvd30gd2luIHdpbmRvdyB0byB3b3JrIGluXG4gKi9cbmZ1bmN0aW9uIERPTVN0b3JhZ2Uoa2V5UHJlZml4LCBzZXNzaW9uT25seSwgd2luKSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT0gJ3VuZGVmaW5lZCcpIHJldHVybjtcbiAgICB3aW4gPSB3aW4gfHwgd2luZG93O1xuXG4gICAga2V5UHJlZml4ID0gY29uZmlnLmRvbVN0b3JhZ2Uucm9vdCArXG4gICAgICAgICAgICAgICAgKGtleVByZWZpeFxuICAgICAgICAgICAgICAgICAgICA/IGtleVByZWZpeCArIGNvbmZpZy5kb21TdG9yYWdlLnByZWZpeFNlcGFyYXRvclxuICAgICAgICAgICAgICAgICAgICA6ICcnKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgIGtleVByZWZpeDoga2V5UHJlZml4LFxuICAgICAgICBzZXNzaW9uT25seTogISEgc2Vzc2lvbk9ubHksXG4gICAgICAgIHdpbmRvdzogd2luLFxuICAgICAgICBfc3RvcmFnZTogc2Vzc2lvbk9ubHkgPyB3aW4uc2Vzc2lvblN0b3JhZ2UgOiB3aW4ubG9jYWxTdG9yYWdlLFxuICAgICAgICBfdHlwZVN1ZmZpeDogY29uZmlnLmRvbVN0b3JhZ2UudHlwZVN1ZmZpeCxcbiAgICAgICAgX2tleXM6IHt9XG4gICAgfSwgXy5XUklUKTtcbn1cblxuXG5fLmV4dGVuZFByb3RvKERPTVN0b3JhZ2UsIHtcbiAgICBnZXQ6IERPTVN0b3JhZ2UkZ2V0LFxuICAgIHNldDogRE9NU3RvcmFnZSRzZXQsXG4gICAgcmVtb3ZlOiBET01TdG9yYWdlJHJlbW92ZSxcbiAgICBoYXNJdGVtOiBET01TdG9yYWdlJGhhc0l0ZW0sXG4gICAgZ2V0SXRlbTogRE9NU3RvcmFnZSRnZXRJdGVtLFxuICAgIHNldEl0ZW06IERPTVN0b3JhZ2Ukc2V0SXRlbSxcbiAgICByZW1vdmVJdGVtOiBET01TdG9yYWdlJHJlbW92ZUl0ZW0sXG4gICAgX3N0b3JhZ2VLZXk6IERPTVN0b3JhZ2UkX3N0b3JhZ2VLZXksXG4gICAgX2RvbVN0b3JhZ2VLZXk6IERPTVN0b3JhZ2UkX2RvbVN0b3JhZ2VLZXksXG4gICAgZ2V0QWxsS2V5czogRE9NU3RvcmFnZSRnZXRBbGxLZXlzLFxuICAgIGdldEFsbEl0ZW1zOiBET01TdG9yYWdlJGdldEFsbEl0ZW1zLFxuICAgIGNyZWF0ZU1lc3NlbmdlcjogRE9NU3RvcmFnZSRjcmVhdGVNZXNzZW5nZXIsXG4gICAgZGVzdHJveTogRE9NU3RvcmFnZSRkZXN0cm95XG59KTtcblxuXG4vKipcbiAqIEV4cG9zZSBNZXNlbmdlciBhbmQgTWVzc2FnZVNvdXJjZSBtZXRob2RzIG9uIERPTVN0b3JhZ2VcbiAqL1xuTWVzc2VuZ2VyLnVzZVdpdGgoRE9NU3RvcmFnZSwgJ19tZXNzZW5nZXInLCBNZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMpO1xuU3RvcmFnZU1lc3NhZ2VTb3VyY2UudXNlV2l0aChET01TdG9yYWdlLCAnX21lc3NhZ2VTb3VyY2UnLCBbJ3RyaWdnZXInXSk7XG5cblxudmFyIF9zZXNzaW9uU3RvcmFnZSA9IG5ldyBET01TdG9yYWdlKCcnLCB0cnVlKVxuICAgICwgX2xvY2FsU3RvcmFnZSA9IG5ldyBET01TdG9yYWdlKCcnLCBmYWxzZSk7XG5cbnZhciBfZG9tU3RvcmFnZSA9IHtcbiAgICAgICAgdHJ1ZTogX3Nlc3Npb25TdG9yYWdlLFxuICAgICAgICBmYWxzZTogX2xvY2FsU3RvcmFnZVxuICAgIH07XG5cbl8uZXh0ZW5kKERPTVN0b3JhZ2UsIHtcbiAgICByZWdpc3RlckRhdGFUeXBlOiBET01TdG9yYWdlJCRyZWdpc3RlckRhdGFUeXBlLFxuICAgIGxvY2FsOiBfbG9jYWxTdG9yYWdlLFxuICAgIHNlc3Npb246IF9zZXNzaW9uU3RvcmFnZSxcbiAgICBzdG9yYWdlOiBfZG9tU3RvcmFnZSxcbiAgICBfc3RvcmVkS2V5czogX3N0b3JlZEtleXMgLy8gZXhwb3NlZCBmb3IgdGVzdGluZ1xufSk7XG5cblxuLyoqXG4gKiBTZXRzIGRhdGEgdG8gRE9NIHN0b3JhZ2UuIGB0aGlzLmtleVByZWZpeGAgaXMgcHJlcGVuZGVkIHRvIGtleXMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgc2luZ2xlIG9iamVjdCBjYW4gYmUgcGFzc2VkIGluIHdoaWNoIGNhc2Uga2V5cyB3aWxsIGJlIHVzZWQgYXMga2V5cyBpbiBsb2NhbCBzdG9yYWdlLlxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgYWx0ZXJuYXRpdmVseSBqdXN0IHRoZSBsaXN0IG9mIGFyZ3VtZW50cyBjYW4gYmUgcGFzc2VkIHdoZXJlIGFyZ3VtZW50cyBjYW4gYmUgc2VxdWVudGlhbGx5IHVzZWQgYXMga2V5cyBhbmQgdmFsdWVzLlxuICovXG5mdW5jdGlvbiBET01TdG9yYWdlJHNldChkYXRhKSB7IC8vIG9yIGFyZ3VtZW50c1xuICAgIGlmICh0eXBlb2YgZGF0YSA9PSAnb2JqZWN0JylcbiAgICAgICAgXy5lYWNoS2V5KGRhdGEsIGZ1bmN0aW9uKHZhbHVlLCBrZXkpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0SXRlbShrZXksIHZhbHVlKTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgZWxzZSB7XG4gICAgICAgIHZhciBhcmdzTGVuID0gYXJndW1lbnRzLmxlbmd0aDtcbiAgICAgICAgaWYgKGFyZ3NMZW4gJSAyKVxuICAgICAgICAgICAgdGhyb3cgbmV3IERvbVN0b3JhZ2VFcnJvcignRE9NU3RvcmFnZTogc2V0IHNob3VsZCBoYXZlIGV2ZW4gbnVtYmVyIG9mIGFyZ3VtZW50cyBvciBvYmplY3QnKTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyZ3NMZW47IGkrKykge1xuICAgICAgICAgICAgdmFyIGtleSA9IGFyZ3VtZW50c1tpXVxuICAgICAgICAgICAgICAgICwgdmFsdWUgPSBhcmd1bWVudHNbKytpXTtcblxuICAgICAgICAgICAgdGhpcy5zZXRJdGVtKGtleSwgdmFsdWUpO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5cbi8qKlxuICogR2V0cyBkYXRhIGZyb20gRE9NIHN0b3JhZ2UuIGB0aGlzLmtleVByZWZpeGAgaXMgcHJlcGVuZGVkIHRvIHBhc3NlZCBrZXlzLCBidXQgcmV0dXJuZWQgb2JqZWN0IHdpbGwgaGF2ZSBrZXlzIHdpdGhvdXQgcm9vdCBrZXlzLlxuICpcbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIGtleXMgY2FuIGJlIHBhc3NlZCBhcyBzdHJpbmdzIG9yIGFycmF5cyBvZiBzdHJpbmdzXG4gKiBAcmV0dXJucyB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBET01TdG9yYWdlJGdldCgpIHsgLy8gLCAuLi4gYXJndW1lbnRzXG4gICAgdmFyIGRhdGEgPSB7fTtcbiAgICBfLmRlZXBGb3JFYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24oa2V5KSB7XG4gICAgICAgIGRhdGFba2V5XSA9IHRoaXMuZ2V0SXRlbShrZXkpO1xuICAgIH0sIHRoaXMpO1xuICAgIHJldHVybiBkYXRhO1xufVxuXG5cbi8qKlxuICogUmVtb3ZlcyBrZXlzIGZyb20gRE9NIHN0b3JhZ2UuIGB0aGlzLmtleVByZWZpeGAgaXMgcHJlcGVuZGVkIHRvIHBhc3NlZCBrZXlzLlxuICpcbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIGtleXMgY2FuIGJlIHBhc3NlZCBhcyBzdHJpbmdzIG9yIGFycmF5cyBvZiBzdHJpbmdzXG4gKi9cbmZ1bmN0aW9uIERPTVN0b3JhZ2UkcmVtb3ZlKCkgeyAvLywgLi4uIGFyZ3VtZW50c1xuICAgIF8uZGVlcEZvckVhY2goYXJndW1lbnRzLCBmdW5jdGlvbihrZXkpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVJdGVtKGtleSk7XG4gICAgfSwgdGhpcyk7XG59XG5cblxuLyoqXG4gKiBDaGVjayBmb3IgcHJlc2VuY2Ugb2Ygc2luZ2xlIGl0ZW0gaW4gRE9NIHN0b3JhZ2UuIGB0aGlzLmtleVByZWZpeGAgaXMgcHJlcGVuZGVkIHRvIHBhc3NlZCBrZXkuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IGtleVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gRE9NU3RvcmFnZSRoYXNJdGVtKGtleSkge1xuICAgIHZhciBwS2V5ID0gdGhpcy5fc3RvcmFnZUtleShrZXkpO1xuICAgIHJldHVybiB0aGlzLl9zdG9yYWdlLmdldEl0ZW0ocEtleSkgIT0gbnVsbDtcbn1cblxuXG4vKipcbiAqIEdldHMgc2luZ2xlIGl0ZW0gZnJvbSBET00gc3RvcmFnZSBwcmVwZW5kaW5nIGB0aGlzLmtleVByZWZpeGAgdG8gcGFzc2VkIGtleS5cbiAqIFJlYWRzIHR5cGUgb2YgdGhlIG9yaWdpbmFsbHkgc3RvcmVkIHZhbHVlIGZyb20gYGtleSArIHRoaXMuX3R5cGVTdWZmaXhgIGFuZCBjb252ZXJ0cyBkYXRhIHRvIHRoZSBvcmlnaW5hbCB0eXBlLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBrZXlcbiAqIEByZXR1cm4ge0FueX1cbiAqL1xuZnVuY3Rpb24gRE9NU3RvcmFnZSRnZXRJdGVtKGtleSkge1xuICAgIHZhciBwS2V5ID0gdGhpcy5fc3RvcmFnZUtleShrZXkpO1xuICAgIHZhciBkYXRhVHlwZSA9IF9nZXRLZXlEYXRhVHlwZS5jYWxsKHRoaXMsIHBLZXkpO1xuICAgIHZhciB2YWx1ZVN0ciA9IHRoaXMuX3N0b3JhZ2UuZ2V0SXRlbShwS2V5KTtcbiAgICB2YXIgdmFsdWUgPSBfcGFyc2VEYXRhKHZhbHVlU3RyLCBkYXRhVHlwZSk7XG4gICAgcmV0dXJuIHZhbHVlO1xufVxuXG5cbi8qKlxuICogU2V0cyBzaW5nbGUgaXRlbSB0byBET00gc3RvcmFnZSBwcmVwZW5kaW5nIGB0aGlzLmtleVByZWZpeGAgdG8gcGFzc2VkIGtleS5cbiAqIFN0b3JlcyB0eXBlIG9mIHRoZSBzdG9yZWQgdmFsdWUgdG8gYGtleSArIHRoaXMuX3R5cGVTdWZmaXhgLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBrZXlcbiAqIEByZXR1cm4ge0FueX1cbiAqL1xuZnVuY3Rpb24gRE9NU3RvcmFnZSRzZXRJdGVtKGtleSwgdmFsdWUpIHtcbiAgICB2YXIgcEtleSA9IHRoaXMuX3N0b3JhZ2VLZXkoa2V5KTtcbiAgICB2YXIgZGF0YVR5cGUgPSBfc2V0S2V5RGF0YVR5cGUuY2FsbCh0aGlzLCBwS2V5LCB2YWx1ZSk7XG4gICAgdmFyIHZhbHVlU3RyID0gX3NlcmlhbGl6ZURhdGEodmFsdWUsIGRhdGFUeXBlKTtcbiAgICB0cnkge1xuICAgICAgICB0aGlzLl9zdG9yYWdlLnNldEl0ZW0ocEtleSwgdmFsdWVTdHIpO1xuICAgIH0gY2F0Y2goZSkge1xuICAgICAgICBpZiAoZS5uYW1lID09ICdRdW90YUV4Y2VlZGVkRXJyb3InKSB7XG4gICAgICAgICAgICB2YXIgY2ZnID0gY29uZmlnLmRvbVN0b3JhZ2UucXVvdGFFeGNlZWRlZDtcbiAgICAgICAgICAgIGlmIChjZmcubWVzc2FnZSlcbiAgICAgICAgICAgICAgICBtaWxvLm1haWwucG9zdE1lc3NhZ2UoJ3F1b3RhZXhjZWVkZWRlcnJvcicsIHZhbHVlKTtcbiAgICAgICAgICAgIGlmIChjZmcudGhyb3dFcnJvcilcbiAgICAgICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9IGVsc2VcbiAgICAgICAgICAgIHRocm93IGU7XG4gICAgfVxuICAgIHRoaXMuX2tleXNba2V5XSA9IHRydWU7XG4gICAgX2RvbVN0b3JhZ2VbdGhpcy5zZXNzaW9uT25seV0uX2tleXNbcEtleV0gPSB0cnVlO1xufVxuXG5cbi8qKlxuICogUmVtb3ZlcyBzaW5nbGUgaXRlbSBmcm9tIERPTSBzdG9yYWdlIHByZXBlbmRpbmcgYHRoaXMua2V5UHJlZml4YCB0byBwYXNzZWQga2V5LlxuICogVHlwZSBvZiB0aGUgc3RvcmVkIHZhbHVlIChpbiBga2V5ICsgdGhpcy5fdHlwZVN1ZmZpeGAga2V5KSBpcyBhbHNvIHJlbW92ZWQuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IGtleVxuICogQHJldHVybiB7QW55fVxuICovXG5mdW5jdGlvbiBET01TdG9yYWdlJHJlbW92ZUl0ZW0oa2V5KSB7XG4gICAgdmFyIHBLZXkgPSB0aGlzLl9zdG9yYWdlS2V5KGtleSk7XG4gICAgdGhpcy5fc3RvcmFnZS5yZW1vdmVJdGVtKHBLZXkpO1xuICAgIF9yZW1vdmVLZXlEYXRhVHlwZS5jYWxsKHRoaXMsIHBLZXkpXG4gICAgZGVsZXRlIHRoaXMuX2tleXNba2V5XTtcbiAgICBkZWxldGUgX2RvbVN0b3JhZ2VbdGhpcy5zZXNzaW9uT25seV0uX2tleXNbcEtleV07XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBhcnJheSBvZiBhbGwga2V5cyBzdG9yZWQgYnkgdGhpcyBpbnN0YW5jZSBvZiBET01TdG9yYWdlXG4gKlxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIERPTVN0b3JhZ2UkZ2V0QWxsS2V5cygpIHtcbiAgICB2YXIgc3RvcmVkS2V5cyA9IE9iamVjdC5rZXlzKHRoaXMuX2tleXMpO1xuICAgIHZhciBrZXlzSW5TdG9yYWdlID0gc3RvcmVkS2V5cy5maWx0ZXIoZnVuY3Rpb24oa2V5KSB7XG4gICAgICAgIGlmICh0aGlzLmhhc0l0ZW0oa2V5KSkgcmV0dXJuIHRydWU7XG4gICAgICAgIGVsc2UgZGVsZXRlIHRoaXMuX2tleXNba2V5XTtcbiAgICB9LCB0aGlzKTtcbiAgICByZXR1cm4ga2V5c0luU3RvcmFnZTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgdGhlIG1hcCB3aXRoIGFsbCBrZXlzIGFuZCB2YWx1ZXMgKGRlc2VyaWFsaXplZCkgc3RvcmVkIHVzaW5nIHRoaXMgaW5zdGFuY2Ugb2YgRE9NU3RvcmFnZVxuICpcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gRE9NU3RvcmFnZSRnZXRBbGxJdGVtcygpIHtcbiAgICByZXR1cm4gdGhpcy5nZXQodGhpcy5nZXRBbGxLZXlzKCkpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBwcmVmaXhlZCBrZXkgZm9yIERPTSBzdG9yYWdlIGZvciBnaXZlbiB1bnByZWZpeGVkIGtleS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30ga2V5XG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIERPTVN0b3JhZ2UkX3N0b3JhZ2VLZXkoa2V5KSB7XG4gICAgcmV0dXJuIHRoaXMua2V5UHJlZml4ICsga2V5O1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB1bnByZWZpeGVkIGtleSB0byBiZSB1c2VkIHdpdGggdGhpcyBpbnN0YW5jZSBvZiBET01TdG9yYWdlIGZpciBnaXZlbiBhY3R1YWwga2V5IGluIHN0b3JhZ2VcbiAqIElmIGtleSBoYXMgZGlmZmVyZW50IHByZWZpeCBmcm9tIHRoZSBrZXlQcmVmaXggcmV0dXJucyB1bmRlZmluZWRcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gc3RvcmFnZUtleSBhY3R1YWwga2V5IGluIGxvY2FsL3Nlc3Npb24gc3RvcmFnZVxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBET01TdG9yYWdlJF9kb21TdG9yYWdlS2V5KHN0b3JhZ2VLZXkpIHtcbiAgICBpZiAoc3RvcmFnZUtleS5pbmRleE9mKHRoaXMuX3R5cGVTdWZmaXgpID49IDApIHJldHVybjtcbiAgICByZXR1cm4gXy51blByZWZpeChzdG9yYWdlS2V5LCB0aGlzLmtleVByZWZpeCk7XG59XG5cblxuLyoqXG4gKiBHZXRzIG9yaWdpbmFsbHkgc3RvcmVkIGRhdGEgdHlwZSBmb3IgZ2l2ZW4gKHByZWZpeGVkKSBga2V5YC5cbiAqXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHBLZXkgcHJlZml4ZWQga2V5IG9mIHN0b3JlZCB2YWx1ZVxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBfZ2V0S2V5RGF0YVR5cGUocEtleSkge1xuICAgIHBLZXkgPSBfZGF0YVR5cGVLZXkuY2FsbCh0aGlzLCBwS2V5KTtcbiAgICByZXR1cm4gdGhpcy5fc3RvcmFnZS5nZXRJdGVtKHBLZXkpO1xufVxuXG5cbi8qKlxuICogU3RvcmVzIGRhdGEgdHlwZSBmb3IgZ2l2ZW4gKHByZWZpeGVkKSBga2V5YCBhbmQgYHZhbHVlYC5cbiAqIFJldHVybnMgZGF0YSB0eXBlIGZvciBgdmFsdWVgLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBwS2V5IHByZWZpeGVkIGtleSBvZiBzdG9yZWQgdmFsdWVcbiAqIEBwYXJhbSB7QW55fSB2YWx1ZVxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBfc2V0S2V5RGF0YVR5cGUocEtleSwgdmFsdWUpIHtcbiAgICB2YXIgZGF0YVR5cGUgPSBfZ2V0VmFsdWVUeXBlKHZhbHVlKTtcbiAgICBwS2V5ID0gX2RhdGFUeXBlS2V5LmNhbGwodGhpcywgcEtleSk7XG4gICAgdGhpcy5fc3RvcmFnZS5zZXRJdGVtKHBLZXksIGRhdGFUeXBlKTtcbiAgICByZXR1cm4gZGF0YVR5cGU7XG59XG5cblxuLyoqXG4gKiBSZW1vdmVzIHN0b3JlZCBkYXRhIHR5cGUgZm9yIGdpdmVuIChwcmVmaXhlZCkgYGtleWAuXG4gKlxuICogQHBhcmFtICB7U3RyaW5nfSBwS2V5IHByZWZpeGVkIGtleSBvZiBzdG9yZWQgdmFsdWVcbiAqL1xuZnVuY3Rpb24gX3JlbW92ZUtleURhdGFUeXBlKHBLZXkpIHtcbiAgICBwS2V5ID0gX2RhdGFUeXBlS2V5LmNhbGwodGhpcywgcEtleSk7XG4gICAgdGhpcy5fc3RvcmFnZS5yZW1vdmVJdGVtKHBLZXkpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUga2V5IHRvIHN0b3JlIGRhdGEgdHlwZSBmb3IgZ2l2ZW4gKHByZWZpeGVkKSBga2V5YC5cbiAqXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHBLZXkgcHJlZml4ZWQga2V5IG9mIHN0b3JlZCB2YWx1ZVxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBfZGF0YVR5cGVLZXkocEtleSkge1xuICAgIHJldHVybiBwS2V5ICsgdGhpcy5fdHlwZVN1ZmZpeDtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgdHlwZSBvZiB2YWx1ZSBhcyBzdHJpbmcuIENsYXNzIG5hbWUgcmV0dXJuZWQgZm9yIG9iamVjdHMgKCdudWxsJyBmb3IgbnVsbCkuXG4gKiBAcGFyYW0gIHtBbnl9IHZhbHVlXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIF9nZXRWYWx1ZVR5cGUodmFsdWUpIHtcbiAgICB2YXIgdmFsdWVUeXBlID0gdHlwZW9mIHZhbHVlXG4gICAgICAgICwgY2xhc3NOYW1lID0gdmFsdWUgJiYgdmFsdWUuY29uc3RydWN0b3IubmFtZVxuICAgICAgICAsIGRhdGFUeXBlID0gdmFsdWVzRGF0YVR5cGVzW2NsYXNzTmFtZV07XG4gICAgcmV0dXJuIGRhdGFUeXBlIHx8IChcbiAgICAgICAgICAgIHZhbHVlVHlwZSAhPSAnb2JqZWN0J1xuICAgICAgICAgICAgICAgID8gdmFsdWVUeXBlXG4gICAgICAgICAgICAgICAgOiB2YWx1ZSA9PSBudWxsXG4gICAgICAgICAgICAgICAgICAgID8gJ251bGwnXG4gICAgICAgICAgICAgICAgICAgIDogdmFsdWUuY29uc3RydWN0b3IubmFtZSk7XG59XG52YXIgdmFsdWVzRGF0YVR5cGVzID0ge1xuICAgIC8vIGNhbiBiZSByZWdpc3RlcmVkIHdpdGggYHJlZ2lzdGVyRGF0YVR5cGVgXG59XG5cblxuLyoqXG4gKiBTZXJpYWxpemVzIHZhbHVlIHRvIGJlIHN0b3JlZCBpbiBET00gc3RvcmFnZS5cbiAqXG4gKiBAcGFyYW0gIHtBbnl9IHZhbHVlIHZhbHVlIHRvIGJlIHNlcmlhbGl6ZWRcbiAqIEBwYXJhbSAge1N0cmluZ30gdmFsdWVUeXBlIG9wdGlvbmFsIGRhdGEgdHlwZSB0byBkZWZpbmUgc2VyaWFsaXplciwgX2dldFZhbHVlVHlwZSBpcyB1c2VkIGlmIG5vdCBwYXNzZWQuXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIF9zZXJpYWxpemVEYXRhKHZhbHVlLCB2YWx1ZVR5cGUpIHtcbiAgICB2YWx1ZVR5cGUgPSB2YWx1ZVR5cGUgfHwgX2dldFZhbHVlVHlwZSh2YWx1ZSk7XG4gICAgdmFyIHNlcmlhbGl6ZXIgPSBkYXRhU2VyaWFsaXplcnNbdmFsdWVUeXBlXTtcbiAgICByZXR1cm4gc2VyaWFsaXplclxuICAgICAgICAgICAgPyBzZXJpYWxpemVyKHZhbHVlLCB2YWx1ZVR5cGUpXG4gICAgICAgICAgICA6IHZhbHVlICYmIHZhbHVlLnRvU3RyaW5nID09IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmdcbiAgICAgICAgICAgICAgICA/IEpTT04uc3RyaW5naWZ5KHZhbHVlKVxuICAgICAgICAgICAgICAgIDogJycgKyB2YWx1ZTtcbn1cbnZhciBkYXRhU2VyaWFsaXplcnMgPSB7XG4gICAgJ0FycmF5JzogSlNPTi5zdHJpbmdpZnlcbn1cblxuXG4vKipcbiAqIFBhcnNlcyBzdHJpbmcgcmV0cmlldmVkIGZyb20gRE9NIHN0b3JhZ2UuXG4gKlxuICogQHBhcmFtICB7U3RyaW5nfSB2YWx1ZVN0clxuICogQHBhcmFtICB7U3RyaW5nfSB2YWx1ZVR5cGUgZGF0YSB0eXBlIHRoYXQgZGVmaW5lcyBwYXJzZXIuIE9yaWdpbmFsIHNyaW5nIHdpbGwgYmUgcmV0dXJuZWQgaWYgcGFyc2VyIGlzIG5vdCBkZWZpbmVkLlxuICogQHJldHVybiB7QW55fVxuICovXG5mdW5jdGlvbiBfcGFyc2VEYXRhKHZhbHVlU3RyLCB2YWx1ZVR5cGUpIHtcbiAgICB2YXIgcGFyc2VyID0gZGF0YVBhcnNlcnNbdmFsdWVUeXBlXTtcbiAgICByZXR1cm4gcGFyc2VyXG4gICAgICAgICAgICA/IHBhcnNlcih2YWx1ZVN0ciwgdmFsdWVUeXBlKVxuICAgICAgICAgICAgOiB2YWx1ZVN0cjtcbn1cbnZhciBkYXRhUGFyc2VycyA9IHtcbiAgICBPYmplY3Q6IF8uanNvblBhcnNlLFxuICAgIEFycmF5OiBfLmpzb25QYXJzZSxcbiAgICBEYXRlOiBmdW5jdGlvbih2YWxTdHIpIHsgcmV0dXJuIG5ldyBEYXRlKHZhbFN0cik7IH0sXG4gICAgYm9vbGVhbjogZnVuY3Rpb24odmFsU3RyKSB7IHJldHVybiB2YWxTdHIgPT0gJ3RydWUnOyB9LFxuICAgIG51bWJlcjogTnVtYmVyLFxuICAgIGZ1bmN0aW9uOiBfLnRvRnVuY3Rpb24sXG4gICAgUmVnRXhwOiBfLnRvUmVnRXhwXG59O1xuXG5cbi8qKlxuICogUmVnaXN0ZXJzIGRhdGEgdHlwZSB0byBiZSBzYXZlZCBpbiBET00gc3RvcmFnZS4gQ2xhc3MgbmFtZSBjYW4gYmUgdXNlZCBvciByZXN1bHQgb2YgYHR5cGVvZmAgb3BlcmF0b3IgZm9yIG5vbi1vYmplY3RzIHRvIG92ZXJyaWRlIGRlZmF1bHQgY29udmVyc2lvbnMuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHZhbHVlVHlwZSBjbGFzcyAoY29uc3RydWN0b3IpIG5hbWUgb3IgdGhlIHN0cmluZyByZXR1cm5lZCBieSB0eXBlb2YuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzZXJpYWxpemVyIG9wdGlvbmFsIHNlcmlhbGl6ZXIgZm9yIHRoaXMgdHlwZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gcGFyc2VyIG9wdGlvbmFsIHBhcnNlciBmb3IgdGhpcyB0eXBlXG4gKiBAcGFyYW0ge1tTdHJpbmddfSBzdG9yZUFzRGF0YVR5cGUgb3B0aW9uYWwgbmFtZSBvZiBzdG9yZWQgZGF0YSB0eXBlIGlmIGRpZmZlcmVudCBmcm9tIHZhbHVlVHlwZVxuICovXG5mdW5jdGlvbiBET01TdG9yYWdlJCRyZWdpc3RlckRhdGFUeXBlKHZhbHVlVHlwZSwgc2VyaWFsaXplciwgcGFyc2VyLCBzdG9yZUFzRGF0YVR5cGUpIHtcbiAgICBpZiAoc2VyaWFsaXplcikgZGF0YVNlcmlhbGl6ZXJzW3ZhbHVlVHlwZV0gPSBzZXJpYWxpemVyO1xuICAgIGlmIChwYXJzZXIpIGRhdGFQYXJzZXJzW3ZhbHVlVHlwZV0gPSBwYXJzZXI7XG4gICAgdmFsdWVzRGF0YVR5cGVzW3ZhbHVlVHlwZV0gPSBzdG9yZUFzRGF0YVR5cGUgfHwgdmFsdWVUeXBlO1xufVxuXG5cbmZ1bmN0aW9uIERPTVN0b3JhZ2UkY3JlYXRlTWVzc2VuZ2VyKCkge1xuICAgIHZhciBzdG9yYWdlTWVzc2FnZVNvdXJjZSA9IG5ldyBTdG9yYWdlTWVzc2FnZVNvdXJjZSh0aGlzKTtcbiAgICB2YXIgbWVzc2VuZ2VyID0gbmV3IE1lc3Nlbmdlcih0aGlzLCB1bmRlZmluZWQsIHN0b3JhZ2VNZXNzYWdlU291cmNlKTtcbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICBfbWVzc2VuZ2VyOiBtZXNzZW5nZXIsXG4gICAgICAgIF9tZXNzYWdlU291cmNlOiBzdG9yYWdlTWVzc2FnZVNvdXJjZVxuICAgIH0sIF8uV1JJVCk7XG59XG5cblxuZnVuY3Rpb24gRE9NU3RvcmFnZSRkZXN0cm95KCkge1xuICAgIHRoaXMuX3N0b3JhZ2UgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy53aW5kb3cgPSB1bmRlZmluZWQ7XG4gICAgaWYgKHRoaXMuX21lc3NlbmdlcikgdGhpcy5fbWVzc2VuZ2VyLmRlc3Ryb3koKTtcbiAgICB0aGlzLl9kZXN0cm95ZWQgPSB0cnVlO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgbWlsb0NvcmUgPSByZXF1aXJlKCdtaWxvLWNvcmUnKVxuICAgICwgTW9kZWwgPSBtaWxvQ29yZS5Nb2RlbFxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvO1xuXG5Nb2RlbC5yZWdpc3RlcldpdGhET01TdG9yYWdlID0gTW9kZWwkJHJlZ2lzdGVyV2l0aERPTVN0b3JhZ2U7XG5cblxuZnVuY3Rpb24gTW9kZWwkJHJlZ2lzdGVyV2l0aERPTVN0b3JhZ2UoKSB7XG4gICAgdmFyIERPTVN0b3JhZ2UgPSByZXF1aXJlKCcuL2luZGV4Jyk7XG4gICAgRE9NU3RvcmFnZS5yZWdpc3RlckRhdGFUeXBlKCdNb2RlbCcsIE1vZGVsX2RvbVN0b3JhZ2VTZXJpYWxpemVyLCBNb2RlbF9kb21TdG9yYWdlUGFyc2VyKTtcbiAgICBET01TdG9yYWdlLnJlZ2lzdGVyRGF0YVR5cGUoJ01vZGVsUGF0aCcsIE1vZGVsX2RvbVN0b3JhZ2VTZXJpYWxpemVyLCBNb2RlbF9kb21TdG9yYWdlUGFyc2VyLCAnTW9kZWwnKTtcbn1cblxuXG5mdW5jdGlvbiBNb2RlbF9kb21TdG9yYWdlU2VyaWFsaXplcih2YWx1ZSkge1xuICAgIHZhciBkYXRhID0gdmFsdWUuZ2V0KCk7XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGRhdGEpO1xufVxuXG5cbmZ1bmN0aW9uIE1vZGVsX2RvbVN0b3JhZ2VQYXJzZXIodmFsdWVTdHIpIHtcbiAgICB2YXIgZGF0YSA9IF8uanNvblBhcnNlKHZhbHVlU3RyKTtcbiAgICByZXR1cm4gbmV3IE1vZGVsKGRhdGEpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNZXNzYWdlU291cmNlID0gbWlsb0NvcmUuY2xhc3Nlcy5NZXNzYWdlU291cmNlXG4gICAgLCBfID0gbWlsb0NvcmUucHJvdG9cbiAgICAsIGNvbmZpZyA9IHJlcXVpcmUoJy4uLy4uL2NvbmZpZycpXG4gICAgLCBtaWxvQ291bnQgPSByZXF1aXJlKCcuLi8uLi91dGlsL2NvdW50Jyk7XG5cbnZhciBTdG9yYWdlTWVzc2FnZVNvdXJjZSA9IF8uY3JlYXRlU3ViY2xhc3MoTWVzc2FnZVNvdXJjZSwgJ1N0b3JhZ2VNZXNzYWdlU291cmNlJywgdHJ1ZSk7XG5cblxuXy5leHRlbmRQcm90byhTdG9yYWdlTWVzc2FnZVNvdXJjZSwge1xuICAgIC8vIGltcGxlbWVudGluZyBNZXNzYWdlU291cmNlIGludGVyZmFjZVxuICAgIGluaXQ6IGluaXQsXG4gICAgYWRkU291cmNlU3Vic2NyaWJlcjogU3RvcmFnZU1lc3NhZ2VTb3VyY2UkYWRkU291cmNlU3Vic2NyaWJlcixcbiAgICByZW1vdmVTb3VyY2VTdWJzY3JpYmVyOiBTdG9yYWdlTWVzc2FnZVNvdXJjZSRyZW1vdmVTb3VyY2VTdWJzY3JpYmVyLFxuICAgIHBvc3RNZXNzYWdlOiBTdG9yYWdlTWVzc2FnZVNvdXJjZSRwb3N0TWVzc2FnZSxcbiAgICB0cmlnZ2VyOiBTdG9yYWdlTWVzc2FnZVNvdXJjZSR0cmlnZ2VyLFxuXG4gICAgLy9jbGFzcyBzcGVjaWZpYyBtZXRob2RzXG4gICAgaGFuZGxlRXZlbnQ6IGhhbmRsZUV2ZW50ICAvLyBldmVudCBkaXNwYXRjaGVyIC0gYXMgZGVmaW5lZCBieSBFdmVudCBET00gQVBJXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdG9yYWdlTWVzc2FnZVNvdXJjZTtcblxuXG5mdW5jdGlvbiBpbml0KGhvc3RPYmplY3QsIHByb3h5TWV0aG9kcywgbWVzc2VuZ2VyQVBJT3JDbGFzcykge1xuICAgIGlmIChob3N0T2JqZWN0LmNvbnN0cnVjdG9yLm5hbWUgIT0gJ0RPTVN0b3JhZ2UnKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2hvc3RPYmplY3Qgc2hvdWxkIGJlIGFuIGluc3RhbmNlIG9mIERPTVN0b3JhZ2UnKTtcbiAgICB0aGlzLnN0b3JhZ2UgPSBob3N0T2JqZWN0O1xuICAgIHRoaXMubWVzc2FnZUtleSA9IGNvbmZpZy5kb21TdG9yYWdlLm1lc3NhZ2VLZXk7XG4gICAgdGhpcy53aW5kb3cgPSBob3N0T2JqZWN0LndpbmRvdztcbiAgICBNZXNzYWdlU291cmNlLnByb3RvdHlwZS5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuZnVuY3Rpb24gU3RvcmFnZU1lc3NhZ2VTb3VyY2UkYWRkU291cmNlU3Vic2NyaWJlcihzb3VyY2VNZXNzYWdlKSB7XG4gICAgdGhpcy53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignc3RvcmFnZScsIHRoaXMsIGZhbHNlKTtcbn1cblxuXG5mdW5jdGlvbiBTdG9yYWdlTWVzc2FnZVNvdXJjZSRyZW1vdmVTb3VyY2VTdWJzY3JpYmVyKHNvdXJjZU1lc3NhZ2UpIHtcbiAgICB0aGlzLndpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdzdG9yYWdlJywgdGhpcywgZmFsc2UpO1xufVxuXG5cbmZ1bmN0aW9uIFN0b3JhZ2VNZXNzYWdlU291cmNlJHBvc3RNZXNzYWdlKG1lc3NhZ2UsIGRhdGEpIHtcbiAgICB0aGlzLm1lc3Nlbmdlci5wb3N0TWVzc2FnZVN5bmMobWVzc2FnZSwgZGF0YSk7XG59XG5cblxuZnVuY3Rpb24gU3RvcmFnZU1lc3NhZ2VTb3VyY2UkdHJpZ2dlcihtc2dUeXBlLCBkYXRhKSB7XG4gICAgdmFyIGtleSA9IHRoaXMubWVzc2FnZUtleSArIG1zZ1R5cGU7XG4gICAgZGF0YSA9IGRhdGEgfHwge307XG4gICAgZGF0YVtjb25maWcuZG9tU3RvcmFnZS5tZXNzYWdlVGltZXN0YW1wXSA9IG1pbG9Db3VudCgpO1xuICAgIF8uZGVmZXJNZXRob2QodGhpcy5zdG9yYWdlLCAnc2V0SXRlbScsIGtleSwgZGF0YSk7XG59XG5cblxuZnVuY3Rpb24gaGFuZGxlRXZlbnQoZXZlbnQpIHtcbiAgICBpZiAoZXZlbnQuc3RvcmFnZUFyZWEgIT0gdGhpcy5zdG9yYWdlLl9zdG9yYWdlKSByZXR1cm47XG4gICAgdmFyIGtleSA9IHRoaXMuc3RvcmFnZS5fZG9tU3RvcmFnZUtleShldmVudC5rZXkpOyBpZiAoISBrZXkpIHJldHVybjtcbiAgICB2YXIgbXNnVHlwZSA9IF8udW5QcmVmaXgoa2V5LCB0aGlzLm1lc3NhZ2VLZXkpOyBpZiAoISBtc2dUeXBlKSByZXR1cm47XG4gICAgdmFyIGRhdGEgPSB0aGlzLnN0b3JhZ2UuZ2V0SXRlbShrZXkpOyBpZiAoISBkYXRhKSByZXR1cm47XG4gICAgdGhpcy5kaXNwYXRjaE1lc3NhZ2UobXNnVHlwZSwgZGF0YSk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogYG1pbG8udXRpbC53ZWJzb2NrZXRgIFxuKiovXG5cblxudmFyIE1lc3NlbmdlciA9IHJlcXVpcmUoJ21pbG8tY29yZScpLk1lc3NlbmdlclxuICAgICwgV1NNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi9tc2dfc3JjJylcbiAgICAsIFdTTXNnQVBJID0gcmVxdWlyZSgnLi9tc2dfYXBpJyk7XG5cblxuZnVuY3Rpb24gd2Vic29ja2V0KCkge1xuICAgIHZhciB3c01lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXI7XG4gICAgdmFyIHdzTXNnU291cmNlID0gbmV3IFdTTWVzc2FnZVNvdXJjZSh3c01lc3NlbmdlciwgeyBzZW5kOiAndHJpZ2dlcicsIGNvbm5lY3Q6ICdjb25uZWN0JyB9LCBuZXcgV1NNc2dBUEkpO1xuICAgIHdzTWVzc2VuZ2VyLl9zZXRNZXNzYWdlU291cmNlKHdzTXNnU291cmNlKTtcbiAgICByZXR1cm4gd3NNZXNzZW5nZXI7XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSB3ZWJzb2NrZXQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBtaWxvQ29yZSA9IHJlcXVpcmUoJ21pbG8tY29yZScpXG4gICAgLCBNZXNzZW5nZXJBUEkgPSBtaWxvQ29yZS5jbGFzc2VzLk1lc3NlbmdlckFQSVxuICAgICwgXyA9IG1pbG9Db3JlLnByb3RvXG4gICAgLCBjaGVjayA9IG1pbG9Db3JlLnV0aWwuY2hlY2tcbiAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2g7XG5cblxudmFyIFdTTXNnQVBJID0gXy5jcmVhdGVTdWJjbGFzcyhNZXNzZW5nZXJBUEksICdXU01zZ0FQSScsIHRydWUpO1xuXG5cbl8uZXh0ZW5kUHJvdG8oV1NNc2dBUEksIHtcbiAgICB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2U6IHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZSxcbiAgICBmaWx0ZXJTb3VyY2VNZXNzYWdlOiBmaWx0ZXJTb3VyY2VNZXNzYWdlLFxuICAgIGNyZWF0ZUludGVybmFsRGF0YTogY3JlYXRlSW50ZXJuYWxEYXRhXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBXU01zZ0FQSTtcblxuXG52YXIgU09DS0VUX01FU1NBR0VTID0gWydvcGVuJywgJ2Nsb3NlJywgJ2Vycm9yJywgJ21lc3NhZ2UnXTtcblxuZnVuY3Rpb24gdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgICByZXR1cm4gU09DS0VUX01FU1NBR0VTLmluZGV4T2YobWVzc2FnZSkgPj0gMFxuICAgICAgICAgICAgPyBtZXNzYWdlXG4gICAgICAgICAgICA6ICdtZXNzYWdlJztcbn1cblxuXG5mdW5jdGlvbiBmaWx0ZXJTb3VyY2VNZXNzYWdlKHNvdXJjZU1lc3NhZ2UsIG1lc3NhZ2UsIG1zZ0RhdGEpIHtcbiAgICBpZiAoU09DS0VUX01FU1NBR0VTLmluZGV4T2YobWVzc2FnZSkgPj0gMCkgcmV0dXJuIHRydWU7IC8vIGludGVybmFsIG1lc3NhZ2UgaXMgb25lIG9mIGV4dGVybmFsIG1lc3NhZ2VzXG4gICAgaWYgKHNvdXJjZU1lc3NhZ2UgPT0gJ21lc3NhZ2UnKSB7XG4gICAgICAgIHZhciBtc2dUeXBlID0gbXNnRGF0YSAmJiBtc2dEYXRhLnR5cGU7XG4gICAgICAgIHJldHVybiBtc2dUeXBlID09IG1lc3NhZ2U7IC8vIHR5cGUgZXF1YWxzIGludGVybmFsIG1lc3NhZ2VcbiAgICB9XG59O1xuXG5cbmZ1bmN0aW9uIGNyZWF0ZUludGVybmFsRGF0YShzb3VyY2VNZXNzYWdlLCBtZXNzYWdlLCBldmVudCkge1xuICAgIHZhciBpbnRlcm5hbERhdGEgPSBzb3VyY2VNZXNzYWdlID09ICdtZXNzYWdlJ1xuICAgICAgICAgICAgICAgICAgICAgICAgPyBfLmpzb25QYXJzZShldmVudC5kYXRhKSB8fCBldmVudC5kYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGV2ZW50O1xuICAgIHJldHVybiBpbnRlcm5hbERhdGE7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIG1pbG9Db3JlID0gcmVxdWlyZSgnbWlsby1jb3JlJylcbiAgICAsIE1lc3NhZ2VTb3VyY2UgPSBtaWxvQ29yZS5jbGFzc2VzLk1lc3NhZ2VTb3VyY2VcbiAgICAsIF8gPSBtaWxvQ29yZS5wcm90b1xuICAgICwgbG9nZ2VyID0gbWlsb0NvcmUudXRpbC5sb2dnZXJcbiAgICAsIHVuaXF1ZUlkID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9jb3VudCcpXG4gICAgLCBjb25maWcgPSByZXF1aXJlKCcuLi8uLi9jb25maWcnKVxuICAgICwgY2hlY2sgPSBtaWxvQ29yZS51dGlsLmNoZWNrXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5cbnZhciBXU01lc3NhZ2VTb3VyY2UgPSBfLmNyZWF0ZVN1YmNsYXNzKE1lc3NhZ2VTb3VyY2UsICdXU01lc3NhZ2VTb3VyY2UnLCB0cnVlKTtcblxuXG5fLmV4dGVuZFByb3RvKFdTTWVzc2FnZVNvdXJjZSwge1xuICAgIC8vIGltcGxlbWVudGluZyBNZXNzYWdlU291cmNlIGludGVyZmFjZVxuICAgIGFkZFNvdXJjZVN1YnNjcmliZXI6IGFkZFNvdXJjZVN1YnNjcmliZXIsXG4gICAgcmVtb3ZlU291cmNlU3Vic2NyaWJlcjogcmVtb3ZlU291cmNlU3Vic2NyaWJlcixcbiAgICBcbiAgICAvLyBjbGFzcyBzcGVjaWZpYyBtZXRob2RzXG4gICAgaGFuZGxlRXZlbnQ6IFdTTWVzc2FnZVNvdXJjZSRoYW5kbGVFdmVudCxcbiAgICBjb25uZWN0OiBXU01lc3NhZ2VTb3VyY2UkY29ubmVjdCxcbiAgICB0cmlnZ2VyOiBXU01lc3NhZ2VTb3VyY2UkdHJpZ2dlclxufSk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBXU01lc3NhZ2VTb3VyY2U7XG5cblxuZnVuY3Rpb24gV1NNZXNzYWdlU291cmNlJGNvbm5lY3Qob3B0aW9ucykge1xuICAgIHRoaXMuX29wdGlvbnMgPSBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgIHZhciBob3N0ID0gb3B0aW9ucy5ob3N0IHx8IHdpbmRvdy5sb2NhdGlvbi5ob3N0LnJlcGxhY2UoLzouKi8sICcnKVxuICAgICAgICAsIHBvcnQgPSBvcHRpb25zLnBvcnQgfHwgJzgwODAnO1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgaWYgKHRoaXMuX3dzKSB7XG4gICAgICAgIC8vIFRPRE8gc2hvdWxkIHVuc3Vic2NyaWJlIGRpZmZlcmVudGx5XG4gICAgICAgIHRoaXMuX3dzLm9ub3BlbiA9IHRoaXMud3Mub25tZXNzYWdlID0gdGhpcy53cy5vbmNsb3NlID0gdGhpcy53cy5vbmVycm9yID0gdW5kZWZpbmVkO1xuICAgICAgICB0aGlzLl93cy5jbG9zZSgpO1xuICAgIH1cblxuICAgIHRoaXMuX3dzID0gbmV3IFdlYlNvY2tldCgnd3M6Ly8nICsgaG9zdCArICc6JyArIHBvcnQpO1xuXG4gICAgLy8gVE9ETyByZWNvbm5lY3Rcbn1cblxuXG5cbmZ1bmN0aW9uIGFkZFNvdXJjZVN1YnNjcmliZXIgKHNvdXJjZU1lc3NhZ2UpIHtcbiAgICBfd3NTdWJzY3JpYmVyTWV0aG9kLmNhbGwodGhpcywgJ2FkZEV2ZW50TGlzdGVuZXInLCBzb3VyY2VNZXNzYWdlKTtcbn1cblxuXG5mdW5jdGlvbiByZW1vdmVTb3VyY2VTdWJzY3JpYmVyIChzb3VyY2VNZXNzYWdlKSB7XG4gICAgX3dzU3Vic2NyaWJlck1ldGhvZC5jYWxsKHRoaXMsICdyZW1vdmVFdmVudExpc3RlbmVyJywgc291cmNlTWVzc2FnZSk7XG59XG5cblxuZnVuY3Rpb24gX3dzU3Vic2NyaWJlck1ldGhvZCAobWV0aG9kLCBzb3VyY2VNZXNzYWdlKSB7ICAgIFxuICAgIGlmICghdGhpcy5fd3MpIHJldHVybiBsb2dnZXIuZXJyb3IoJ3dlYnNvY2tldCBpcyBub3QgY3JlYXRlZCcpO1xuICAgIHRoaXMuX3dzW21ldGhvZF0oc291cmNlTWVzc2FnZSwgdGhpcyk7XG59XG5cblxuLy8gZXZlbnQgZGlzcGF0Y2hlciAtIGFzIGRlZmluZWQgYnkgRXZlbnQgRE9NIEFQSVxuZnVuY3Rpb24gV1NNZXNzYWdlU291cmNlJGhhbmRsZUV2ZW50IChldmVudCkge1xuICAgIHRoaXMuZGlzcGF0Y2hNZXNzYWdlKGV2ZW50LnR5cGUsIGV2ZW50KTtcbn1cblxuXG5mdW5jdGlvbiBXU01lc3NhZ2VTb3VyY2UkdHJpZ2dlciAobXNnLCBkYXRhLCBjYWxsYmFjaykge1xuICAgIGlmICghdGhpcy5fd3MpIHJldHVybiBsb2dnZXIuZXJyb3IoJ3dlYnNvY2tldCBpcyBub3QgY3JlYXRlZCcpO1xuXG4gICAgZGF0YSA9IGRhdGEgfHwge307XG4gICAgZGF0YS50eXBlID0gbXNnO1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIFxuICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICBkYXRhLmNhbGxiYWNrQ29ycklkID0gdW5pcXVlSWQoKTtcbiAgICAgICAgdmFyIGludGVydmFsID0gXy5kZWxheShvblRpbWVvdXQsIGNvbmZpZy53ZWJzb2NrZXQucnBjLnRpbWVvdXQpO1xuICAgICAgICB0b2dnbGVScGNTdWJzY3JpcHRpb24oJ29uY2UnLCBkYXRhLmNhbGxiYWNrQ29ycklkKTtcbiAgICB9ICAgIFxuXG4gICAgdGhpcy5fd3Muc2VuZChKU09OLnN0cmluZ2lmeShkYXRhKSk7XG5cblxuICAgIGZ1bmN0aW9uIG9uVGltZW91dCgpIHtcbiAgICAgICAgdG9nZ2xlUnBjU3Vic2NyaXB0aW9uKCdvZmYnLCBkYXRhLmNhbGxiYWNrQ29ycklkKTtcbiAgICAgICAgY2FsbGJhY2sobmV3IEVycm9yKCd3ZWJzb2NrZXQgcnBjOiB0aW1lb3V0JykpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG9uUmVzcG9uc2UobXNnLCBtc2dEYXRhKSB7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwoaW50ZXJ2YWwpO1xuICAgICAgICBpZiAodHlwZW9mIG1zZ0RhdGEgPT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHZhciBlcnIgPSBtc2dEYXRhLmVycm9yID8gbmV3IEVycm9yKG1zZ0RhdGEuZXJyb3IpIDogbnVsbDtcbiAgICAgICAgICAgIGNhbGxiYWNrKGVyciwgbXNnRGF0YS5kYXRhKVxuICAgICAgICB9IGVsc2VcbiAgICAgICAgICAgIGNhbGxiYWNrKG5ldyBFcnJvcignd2Vic29ja2V0IHJwYzogaW52YWxpZCByZXNwb25zZSBkYXRhJyksIG1zZ0RhdGEpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHRvZ2dsZVJwY1N1YnNjcmlwdGlvbihvbk9mZiwgY29ycklkKSB7XG4gICAgICAgIHNlbGYubWVzc2VuZ2VyW29uT2ZmXShjb25maWcud2Vic29ja2V0LnJwYy5yZXNwb25zZVByZWZpeCArIGNvcnJJZCwgb25SZXNwb25zZSk7XG4gICAgfVxufVxuIiwiOyhmdW5jdGlvbigpe1xuXG4vLyBUaGlzIHdvdWxkIGJlIHRoZSBwbGFjZSB0byBlZGl0IGlmIHlvdSB3YW50IGEgZGlmZmVyZW50XG4vLyBCYXNlMzIgaW1wbGVtZW50YXRpb25cblxudmFyIGFscGhhYmV0ID0gJzAxMjM0NTY3ODlhYmNkZWZnaGprbW5wcXJ0dXZ3eHl6J1xudmFyIGFsaWFzID0geyBvOjAsIGk6MSwgbDoxLCBzOjUgfVxuXG4vKipcbiAqIEJ1aWxkIGEgbG9va3VwIHRhYmxlIGFuZCBtZW1vaXplIGl0XG4gKlxuICogUmV0dXJuIGFuIG9iamVjdCB0aGF0IG1hcHMgYSBjaGFyYWN0ZXIgdG8gaXRzXG4gKiBieXRlIHZhbHVlLlxuICovXG5cbnZhciBsb29rdXAgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgdGFibGUgPSB7fVxuICAgIC8vIEludmVydCAnYWxwaGFiZXQnXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhbHBoYWJldC5sZW5ndGg7IGkrKykge1xuICAgICAgICB0YWJsZVthbHBoYWJldFtpXV0gPSBpXG4gICAgfVxuICAgIC8vIFNwbGljZSBpbiAnYWxpYXMnXG4gICAgZm9yICh2YXIga2V5IGluIGFsaWFzKSB7XG4gICAgICAgIGlmICghYWxpYXMuaGFzT3duUHJvcGVydHkoa2V5KSkgY29udGludWVcbiAgICAgICAgdGFibGVba2V5XSA9IHRhYmxlWycnICsgYWxpYXNba2V5XV1cbiAgICB9XG4gICAgbG9va3VwID0gZnVuY3Rpb24oKSB7IHJldHVybiB0YWJsZSB9XG4gICAgcmV0dXJuIHRhYmxlXG59XG5cbi8qKlxuICogQSBzdHJlYW1pbmcgZW5jb2RlclxuICpcbiAqICAgICB2YXIgZW5jb2RlciA9IG5ldyBiYXNlMzIuRW5jb2RlcigpXG4gKiAgICAgdmFyIG91dHB1dDEgPSBlbmNvZGVyLnVwZGF0ZShpbnB1dDEpXG4gKiAgICAgdmFyIG91dHB1dDIgPSBlbmNvZGVyLnVwZGF0ZShpbnB1dDIpXG4gKiAgICAgdmFyIGxhc3RvdXRwdXQgPSBlbmNvZGUudXBkYXRlKGxhc3RpbnB1dCwgdHJ1ZSlcbiAqL1xuXG5mdW5jdGlvbiBFbmNvZGVyKCkge1xuICAgIHZhciBza2lwID0gMCAvLyBob3cgbWFueSBiaXRzIHdlIHdpbGwgc2tpcCBmcm9tIHRoZSBmaXJzdCBieXRlXG4gICAgdmFyIGJpdHMgPSAwIC8vIDUgaGlnaCBiaXRzLCBjYXJyeSBmcm9tIG9uZSBieXRlIHRvIHRoZSBuZXh0XG5cbiAgICB0aGlzLm91dHB1dCA9ICcnXG5cbiAgICAvLyBSZWFkIG9uZSBieXRlIG9mIGlucHV0XG4gICAgLy8gU2hvdWxkIG5vdCByZWFsbHkgYmUgdXNlZCBleGNlcHQgYnkgXCJ1cGRhdGVcIlxuICAgIHRoaXMucmVhZEJ5dGUgPSBmdW5jdGlvbihieXRlKSB7XG4gICAgICAgIC8vIGNvZXJjZSB0aGUgYnl0ZSB0byBhbiBpbnRcbiAgICAgICAgaWYgKHR5cGVvZiBieXRlID09ICdzdHJpbmcnKSBieXRlID0gYnl0ZS5jaGFyQ29kZUF0KDApXG5cbiAgICAgICAgaWYgKHNraXAgPCAwKSB7IC8vIHdlIGhhdmUgYSBjYXJyeSBmcm9tIHRoZSBwcmV2aW91cyBieXRlXG4gICAgICAgICAgICBiaXRzIHw9IChieXRlID4+ICgtc2tpcCkpXG4gICAgICAgIH0gZWxzZSB7IC8vIG5vIGNhcnJ5XG4gICAgICAgICAgICBiaXRzID0gKGJ5dGUgPDwgc2tpcCkgJiAyNDhcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChza2lwID4gMykge1xuICAgICAgICAgICAgLy8gbm90IGVub3VnaCBkYXRhIHRvIHByb2R1Y2UgYSBjaGFyYWN0ZXIsIGdldCB1cyBhbm90aGVyIG9uZVxuICAgICAgICAgICAgc2tpcCAtPSA4XG4gICAgICAgICAgICByZXR1cm4gMVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHNraXAgPCA0KSB7XG4gICAgICAgICAgICAvLyBwcm9kdWNlIGEgY2hhcmFjdGVyXG4gICAgICAgICAgICB0aGlzLm91dHB1dCArPSBhbHBoYWJldFtiaXRzID4+IDNdXG4gICAgICAgICAgICBza2lwICs9IDVcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAwXG4gICAgfVxuXG4gICAgLy8gRmx1c2ggYW55IHJlbWFpbmluZyBiaXRzIGxlZnQgaW4gdGhlIHN0cmVhbVxuICAgIHRoaXMuZmluaXNoID0gZnVuY3Rpb24oY2hlY2spIHtcbiAgICAgICAgdmFyIG91dHB1dCA9IHRoaXMub3V0cHV0ICsgKHNraXAgPCAwID8gYWxwaGFiZXRbYml0cyA+PiAzXSA6ICcnKSArIChjaGVjayA/ICckJyA6ICcnKVxuICAgICAgICB0aGlzLm91dHB1dCA9ICcnXG4gICAgICAgIHJldHVybiBvdXRwdXRcbiAgICB9XG59XG5cbi8qKlxuICogUHJvY2VzcyBhZGRpdGlvbmFsIGlucHV0XG4gKlxuICogaW5wdXQ6IHN0cmluZyBvZiBieXRlcyB0byBjb252ZXJ0XG4gKiBmbHVzaDogYm9vbGVhbiwgc2hvdWxkIHdlIGZsdXNoIGFueSB0cmFpbGluZyBiaXRzIGxlZnRcbiAqICAgICAgICBpbiB0aGUgc3RyZWFtXG4gKiByZXR1cm5zOiBhIHN0cmluZyBvZiBjaGFyYWN0ZXJzIHJlcHJlc2VudGluZyAnaW5wdXQnIGluIGJhc2UzMlxuICovXG5cbkVuY29kZXIucHJvdG90eXBlLnVwZGF0ZSA9IGZ1bmN0aW9uKGlucHV0LCBmbHVzaCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaW5wdXQubGVuZ3RoOyApIHtcbiAgICAgICAgaSArPSB0aGlzLnJlYWRCeXRlKGlucHV0W2ldKVxuICAgIH1cbiAgICAvLyBjb25zdW1lIGFsbCBvdXRwdXRcbiAgICB2YXIgb3V0cHV0ID0gdGhpcy5vdXRwdXRcbiAgICB0aGlzLm91dHB1dCA9ICcnXG4gICAgaWYgKGZsdXNoKSB7XG4gICAgICBvdXRwdXQgKz0gdGhpcy5maW5pc2goKVxuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0XG59XG5cbi8vIEZ1bmN0aW9ucyBhbmFsb2dvdXNseSB0byBFbmNvZGVyXG5cbmZ1bmN0aW9uIERlY29kZXIoKSB7XG4gICAgdmFyIHNraXAgPSAwIC8vIGhvdyBtYW55IGJpdHMgd2UgaGF2ZSBmcm9tIHRoZSBwcmV2aW91cyBjaGFyYWN0ZXJcbiAgICB2YXIgYnl0ZSA9IDAgLy8gY3VycmVudCBieXRlIHdlJ3JlIHByb2R1Y2luZ1xuXG4gICAgdGhpcy5vdXRwdXQgPSAnJ1xuXG4gICAgLy8gQ29uc3VtZSBhIGNoYXJhY3RlciBmcm9tIHRoZSBzdHJlYW0sIHN0b3JlXG4gICAgLy8gdGhlIG91dHB1dCBpbiB0aGlzLm91dHB1dC4gQXMgYmVmb3JlLCBiZXR0ZXJcbiAgICAvLyB0byB1c2UgdXBkYXRlKCkuXG4gICAgdGhpcy5yZWFkQ2hhciA9IGZ1bmN0aW9uKGNoYXIpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBjaGFyICE9ICdzdHJpbmcnKXtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgY2hhciA9PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgICAgIGNoYXIgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGNoYXIpXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY2hhciA9IGNoYXIudG9Mb3dlckNhc2UoKVxuICAgICAgICB2YXIgdmFsID0gbG9va3VwKClbY2hhcl1cbiAgICAgICAgaWYgKHR5cGVvZiB2YWwgPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIC8vIGNoYXJhY3RlciBkb2VzIG5vdCBleGlzdCBpbiBvdXIgbG9va3VwIHRhYmxlXG4gICAgICAgICAgICByZXR1cm4gLy8gc2tpcCBzaWxlbnRseS4gQW4gYWx0ZXJuYXRpdmUgd291bGQgYmU6XG4gICAgICAgICAgICAvLyB0aHJvdyBFcnJvcignQ291bGQgbm90IGZpbmQgY2hhcmFjdGVyIFwiJyArIGNoYXIgKyAnXCIgaW4gbG9va3VwIHRhYmxlLicpXG4gICAgICAgIH1cbiAgICAgICAgdmFsIDw8PSAzIC8vIG1vdmUgdG8gdGhlIGhpZ2ggYml0c1xuICAgICAgICBieXRlIHw9IHZhbCA+Pj4gc2tpcFxuICAgICAgICBza2lwICs9IDVcbiAgICAgICAgaWYgKHNraXAgPj0gOCkge1xuICAgICAgICAgICAgLy8gd2UgaGF2ZSBlbm91Z2ggdG8gcHJlZHVjZSBvdXRwdXRcbiAgICAgICAgICAgIHRoaXMub3V0cHV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnl0ZSlcbiAgICAgICAgICAgIHNraXAgLT0gOFxuICAgICAgICAgICAgaWYgKHNraXAgPiAwKSBieXRlID0gKHZhbCA8PCAoNSAtIHNraXApKSAmIDI1NVxuICAgICAgICAgICAgZWxzZSBieXRlID0gMFxuICAgICAgICB9XG5cbiAgICB9XG5cbiAgICB0aGlzLmZpbmlzaCA9IGZ1bmN0aW9uKGNoZWNrKSB7XG4gICAgICAgIHZhciBvdXRwdXQgPSB0aGlzLm91dHB1dCArIChza2lwIDwgMCA/IGFscGhhYmV0W2JpdHMgPj4gM10gOiAnJykgKyAoY2hlY2sgPyAnJCcgOiAnJylcbiAgICAgICAgdGhpcy5vdXRwdXQgPSAnJ1xuICAgICAgICByZXR1cm4gb3V0cHV0XG4gICAgfVxufVxuXG5EZWNvZGVyLnByb3RvdHlwZS51cGRhdGUgPSBmdW5jdGlvbihpbnB1dCwgZmx1c2gpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGlucHV0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMucmVhZENoYXIoaW5wdXRbaV0pXG4gICAgfVxuICAgIHZhciBvdXRwdXQgPSB0aGlzLm91dHB1dFxuICAgIHRoaXMub3V0cHV0ID0gJydcbiAgICBpZiAoZmx1c2gpIHtcbiAgICAgIG91dHB1dCArPSB0aGlzLmZpbmlzaCgpXG4gICAgfVxuICAgIHJldHVybiBvdXRwdXRcbn1cblxuLyoqIENvbnZlbmllbmNlIGZ1bmN0aW9uc1xuICpcbiAqIFRoZXNlIGFyZSB0aGUgb25lcyB0byB1c2UgaWYgeW91IGp1c3QgaGF2ZSBhIHN0cmluZyBhbmRcbiAqIHdhbnQgdG8gY29udmVydCBpdCB3aXRob3V0IGRlYWxpbmcgd2l0aCBzdHJlYW1zIGFuZCB3aGF0bm90LlxuICovXG5cbi8vIFN0cmluZyBvZiBkYXRhIGdvZXMgaW4sIEJhc2UzMi1lbmNvZGVkIHN0cmluZyBjb21lcyBvdXQuXG5mdW5jdGlvbiBlbmNvZGUoaW5wdXQpIHtcbiAgdmFyIGVuY29kZXIgPSBuZXcgRW5jb2RlcigpXG4gIHZhciBvdXRwdXQgPSBlbmNvZGVyLnVwZGF0ZShpbnB1dCwgdHJ1ZSlcbiAgcmV0dXJuIG91dHB1dFxufVxuXG4vLyBCYXNlMzItZW5jb2RlZCBzdHJpbmcgZ29lcyBpbiwgZGVjb2RlZCBkYXRhIGNvbWVzIG91dC5cbmZ1bmN0aW9uIGRlY29kZShpbnB1dCkge1xuICAgIHZhciBkZWNvZGVyID0gbmV3IERlY29kZXIoKVxuICAgIHZhciBvdXRwdXQgPSBkZWNvZGVyLnVwZGF0ZShpbnB1dCwgdHJ1ZSlcbiAgICByZXR1cm4gb3V0cHV0XG59XG5cbnZhciBiYXNlMzIgPSB7XG4gICAgRGVjb2RlcjogRGVjb2RlcixcbiAgICBFbmNvZGVyOiBFbmNvZGVyLFxuICAgIGVuY29kZTogZW5jb2RlLFxuICAgIGRlY29kZTogZGVjb2RlXG59XG5cbmlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJykge1xuICAvLyB3ZSdyZSBpbiBhIGJyb3dzZXIgLSBPTUchXG4gIHdpbmRvdy5iYXNlMzIgPSBiYXNlMzJcbn1cblxuaWYgKHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnICYmIG1vZHVsZS5leHBvcnRzKSB7XG4gIC8vIG5vZGVqcy9icm93c2VyaWZ5XG4gIG1vZHVsZS5leHBvcnRzID0gYmFzZTMyXG59XG59KSgpO1xuIiwiXG4vLyBub3QgaW1wbGVtZW50ZWRcbi8vIFRoZSByZWFzb24gZm9yIGhhdmluZyBhbiBlbXB0eSBmaWxlIGFuZCBub3QgdGhyb3dpbmcgaXMgdG8gYWxsb3dcbi8vIHVudHJhZGl0aW9uYWwgaW1wbGVtZW50YXRpb24gb2YgdGhpcyBtb2R1bGUuXG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBjb25maWcgPSByZXF1aXJlKCcuLi9jb25maWcnKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1peGluO1xuXG4vKipcbiAqIGBtaWxvLmNsYXNzZXMuTWl4aW5gIC0gYW4gYWJzdHJhY3QgTWl4aW4gY2xhc3MuXG4gKiBDYW4gYmUgc3ViY2xhc3NlZCB1c2luZzpcbiAqIGBgYFxuICogdmFyIE15TWl4aW4gPSBfLmNyZWF0ZVN1YmNsYXNzKG1pbG8uY2xhc3Nlcy5NaXhpbiwgJ015TWl4aW4nKTtcbiAqIGBgYFxuICpcbiAqIE1peGluIHBhdHRlcm4gaXMgYWxzbyB1c2VkLCBidXQgTWl4aW4gaW4gbWlsbyBpcyBpbXBsZW1lbnRlZCBhcyBhIHNlcGFyYXRlIG9iamVjdCB0aGF0IGlzIHN0b3JlZCBvbiB0aGUgcHJvcGVydHkgb2YgdGhlIGhvc3Qgb2JqZWN0IGFuZCBjYW4gY3JlYXRlIHByb3h5IG1ldGhvZHMgb24gdGhlIGhvc3Qgb2JqZWN0IGlmIHJlcXVpcmVkLlxuICogQ2xhc3NlcyBbTWVzc2VuZ2VyXSguLi9tZXNzZW5nZXIvaW5kZXguanMuaHRtbCkgYW5kIFtNZXNzYWdlU291cmNlXSguLi9tZXNzZW5nZXIvbV9zb3VyY2UuanMuaHRtbCkgYXJlIHN1YmNsYXNzZXMgb2YgTWl4aW4gYWJzdHJhY3QgY2xhc3MuIGB0aGlzYCBpbiBwcm94eSBtZXRob2RzIHJlZmVycyB0byBNaXhpbiBpbnN0YW5jZSwgdGhlIHJlZmVyZW5jZSB0byB0aGUgaG9zdCBvYmplY3QgaXMgYHRoaXMuX2hvc3RPYmplY3RgLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0T2JqZWN0IE9wdGlvbmFsIG9iamVjdCB3aGVyZSBhIE1peGluIGluc3RhbmNlIHdpbGwgYmUgc3RvcmVkIG9uLiBJdCBpcyB1c2VkIHRvIHByb3h5IG1ldGhvZHMgYW5kIGFsc28gdG8gZmluZCB0aGUgcmVmZXJlbmNlIHdoZW4gaXQgaXMgbmVlZGVkIGZvciBob3N0IG9iamVjdCBpbXBsZW1lbnRhdGlvbi5cbiAqIEBwYXJhbSB7T2JqZWN0fSBwcm94eU1ldGhvZHMgT3B0aW9uYWwgbWFwIG9mIHByb3h5IG1ldGhvZCBuYW1lcyBhcyBrZXlzIGFuZCBNaXhpbiBtZXRob2RzIG5hbWVzIGFzIHZhbHVlcywgc28gcHJveGllZCBtZXRob2RzIGNhbiBiZSByZW5hbWVkIHRvIGF2b2lkIG5hbWUtc3BhY2UgY29uZmxpY3RzIGlmIHR3byBkaWZmZXJlbnQgTWl4aW4gaW5zdGFuY2VzIHdpdGggdGhlIHNhbWUgbWV0aG9kIG5hbWVzIGFyZSBwdXQgb24gdGhlIG9iamVjdFxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgYWxsIGNvbnN0cnVjdG9yIGFyZ3VtZW50cyB3aWxsIGJlIHBhc3NlZCB0byBpbml0IG1ldGhvZCBvZiBNaXhpbiBzdWJjbGFzcyB0b2dldGhlciB3aXRoIGhvc3RPYmplY3QgYW5kIHByb3h5TWV0aG9kc1xuICogQHJldHVybiB7TWl4aW59XG4gKi9cbmZ1bmN0aW9uIE1peGluKGhvc3RPYmplY3QsIHByb3h5TWV0aG9kcykgeyAvLyAsIG90aGVyIGFyZ3MgLSBwYXNzZWQgdG8gaW5pdCBtZXRob2RcbiAgICBjaGVjayhob3N0T2JqZWN0LCBNYXRjaC5PcHRpb25hbChNYXRjaC5PbmVPZihPYmplY3QsIEZ1bmN0aW9uKSkpO1xuXG4gICAgLy8gc3RvcmUgaG9zdE9iamVjdFxuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgJ19ob3N0T2JqZWN0JywgaG9zdE9iamVjdCk7XG5cbiAgICAvLyBwcm94eSBtZXRob2RzIHRvIGhvc3RPYmplY3RcbiAgICBpZiAocHJveHlNZXRob2RzKVxuICAgICAgICB0aGlzLl9jcmVhdGVQcm94eU1ldGhvZHMocHJveHlNZXRob2RzKTtcblxuICAgIC8vIGNhbGxpbmcgaW5pdCBpZiBpdCBpcyBkZWZpbmVkIGluIHRoZSBjbGFzc1xuICAgIGlmICh0aGlzLmluaXQpXG4gICAgICAgIHRoaXMuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG5cbi8qKlxuICogIyMjI01peGluIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKiBUaGVzZSBtZXRob2RzIGFyZSBjYWxsZWQgYnkgY29uc3RydWN0b3IsIHRoZXkgYXJlIG5vdCB0byBiZSBjYWxsZWQgZnJvbSBzdWJjbGFzc2VzLlxuICpcbiAqIC0gW19jcmVhdGVQcm94eU1ldGhvZF0oI19jcmVhdGVQcm94eU1ldGhvZClcbiAqIC0gW19jcmVhdGVQcm94eU1ldGhvZHNdKCNfY3JlYXRlUHJveHlNZXRob2RzKVxuICovXG5fLmV4dGVuZFByb3RvKE1peGluLCB7XG4gICAgX2NyZWF0ZVByb3h5TWV0aG9kOiBfY3JlYXRlUHJveHlNZXRob2QsICAvLyBkZXByZWNhdGVkLCBzaG91bGQgbm90IGJlIHVzZWRcbiAgICBfY3JlYXRlUHJveHlNZXRob2RzOiBfY3JlYXRlUHJveHlNZXRob2RzICAvLyBkZXByZWNhdGVkLCBzaG91bGQgbm90IGJlIHVzZWRcbn0pO1xuXG5cbi8qKlxuICogIyMjI01peGluIGNsYXNzIG1ldGhvZHMjIyMjXG4gKiBUaGVzZSBtZXRob2Qgc2hvdWxkIGJlIGNhbGxlZCBpbiBob3N0IGNsYXNzIGRlY2xhcmF0aW9uLlxuICpcbiAqIC0gW3VzZVdpdGhdKCNNaXhpbiQkdXNlV2l0aClcbiAqL1xuXy5leHRlbmQoTWl4aW4sIHtcbiAgICB1c2VXaXRoOiBNaXhpbiQkdXNlV2l0aFxufSk7XG5cblxuLyoqXG4gKiBDcmVhdGVzIGEgcHJveGllZCBtZXRob2Qgb2YgTWl4aW4gc3ViY2xhc3Mgb24gaG9zdCBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1peGluTWV0aG9kTmFtZSBuYW1lIG9mIG1ldGhvZCBpbiBNaXhpbiBzdWJjbGFzc1xuICogQHBhcmFtIHtTdHJpbmd9IHByb3h5TWV0aG9kTmFtZSBuYW1lIG9mIGNyZWF0ZWQgcHJveHkgbWV0aG9kIG9uIGhvc3Qgb2JqZWN0XG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBPcHRpb25hbCByZWZlcmVuY2UgdG8gdGhlIGhvc3Qgb2JqZWN0OyBpZiBub3Qgc3BlY2lmaWVkIHRoZSBob3N0IG9iamVjdCBwYXNzZWQgdG8gY29uc3RydWN0b3Igd2lsIGJlIHVzZWQuIEl0IGFsbG93cyB0byB1c2UgdGhlIHNhbWUgaW5zdGFuY2Ugb2YgTWl4aW4gb24gdHdvIGhvc3Qgb2JqZWN0cy5cbiAqL1xuZnVuY3Rpb24gX2NyZWF0ZVByb3h5TWV0aG9kKHByb3h5TWV0aG9kTmFtZSwgbWl4aW5NZXRob2ROYW1lLCBob3N0T2JqZWN0KSB7XG4gICAgaG9zdE9iamVjdCA9IGhvc3RPYmplY3QgfHwgdGhpcy5faG9zdE9iamVjdDtcblxuICAgIC8vIE1peGluIGNsYXNzIGRvZXMgbm90IGFsbG93IHNoYWRvd2luZyBtZXRob2RzIHRoYXQgZXhpc3Qgb24gdGhlIGhvc3Qgb2JqZWN0XG4gICAgaWYgKGhvc3RPYmplY3RbcHJveHlNZXRob2ROYW1lXSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdtZXRob2QgJyArIHByb3h5TWV0aG9kTmFtZSArXG4gICAgICAgICAgICAgICAgICAgICAgICAnIGFscmVhZHkgZGVmaW5lZCBpbiBob3N0IG9iamVjdCcpO1xuXG4gICAgdmFyIG1ldGhvZCA9IHRoaXNbbWl4aW5NZXRob2ROYW1lXVxuICAgIGNoZWNrKG1ldGhvZCwgRnVuY3Rpb24pO1xuXG4gICAgLy8gQmluZCBwcm94aWVkIE1peGluJ3MgbWV0aG9kIHRvIE1peGluIGluc3RhbmNlXG4gICAgdmFyIGJvdW5kTWV0aG9kID0gbWV0aG9kLmJpbmQodGhpcyk7XG5cbiAgICBfLmRlZmluZVByb3BlcnR5KGhvc3RPYmplY3QsIHByb3h5TWV0aG9kTmFtZSwgYm91bmRNZXRob2QsIF8uV1JJVCk7XG59XG5cblxuLyoqXG4gKiBDcmVhdGVzIHByb3hpZWQgbWV0aG9kcyBvZiBNaXhpbiBzdWJjbGFzcyBvbiBob3N0IG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge0hhc2hbU3RyaW5nXXxBcnJheVtTdHJpbmddfSBwcm94eU1ldGhvZHMgbWFwIG9mIG5hbWVzIG9mIG1ldGhvZHMsIGtleSAtIHByb3h5IG1ldGhvZCBuYW1lLCB2YWx1ZSAtIG1peGluIG1ldGhvZCBuYW1lLiBDYW4gYmUgYXJyYXkuXG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBhbiBvcHRpb25hbCByZWZlcmVuY2UgdG8gdGhlIGhvc3Qgb2JqZWN0OyBpZiBub3Qgc3BlY2lmaWVkIHRoZSBob3N0IG9iamVjdCBwYXNzZWQgdG8gY29uc3RydWN0b3Igd2lsIGJlIHVzZWQuIEl0IGFsbG93cyB0byB1c2UgdGhlIHNhbWUgaW5zdGFuY2Ugb2YgTWl4aW4gb24gdHdvIGhvc3Qgb2JqZWN0cy5cbiAqL1xuZnVuY3Rpb24gX2NyZWF0ZVByb3h5TWV0aG9kcyhwcm94eU1ldGhvZHMsIGhvc3RPYmplY3QpIHtcbiAgICBjaGVjayhwcm94eU1ldGhvZHMsIE1hdGNoLk9wdGlvbmFsKE1hdGNoLk9uZU9mKFtTdHJpbmddLCBNYXRjaC5PYmplY3RIYXNoKFN0cmluZykpKSk7XG5cbiAgICAvLyBjcmVhdGluZyBhbmQgYmluZGluZyBwcm94eSBtZXRob2RzIG9uIHRoZSBob3N0IG9iamVjdFxuICAgIGlmIChBcnJheS5pc0FycmF5KHByb3h5TWV0aG9kcykpXG4gICAgICAgIHByb3h5TWV0aG9kcy5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICAgICAgICAgIC8vIG1ldGhvZCBjYWxsZWQgdGhpcyB3YXkgdG8gYWxsb3cgdXNpbmcgX2NyZWF0ZVByb3h5TWV0aG9kcyB3aXRoIG9iamVjdHNcbiAgICAgICAgICAgIC8vIHRoYXQgYXJlIG5vdCBpbmhlcml0aW5nIGZyb20gTWl4aW5cbiAgICAgICAgICAgIF9jcmVhdGVQcm94eU1ldGhvZC5jYWxsKHRoaXMsIG1ldGhvZE5hbWUsIG1ldGhvZE5hbWUsIGhvc3RPYmplY3QpO1xuICAgICAgICB9LCB0aGlzKTtcbiAgICBlbHNlXG4gICAgICAgIF8uZWFjaEtleShwcm94eU1ldGhvZHMsIGZ1bmN0aW9uKG1peGluTWV0aG9kTmFtZSwgcHJveHlNZXRob2ROYW1lKSB7XG4gICAgICAgICAgICAvLyBtZXRob2QgY2FsbGVkIHRoaXMgd2F5IHRvIGFsbG93IHVzaW5nIF9jcmVhdGVQcm94eU1ldGhvZHMgd2l0aCBvYmplY3RzXG4gICAgICAgICAgICAvLyB0aGF0IGFyZSBub3QgaW5oZXJpdGluZyBmcm9tIE1peGluXG4gICAgICAgICAgICBfY3JlYXRlUHJveHlNZXRob2QuY2FsbCh0aGlzLCBwcm94eU1ldGhvZE5hbWUsIG1peGluTWV0aG9kTmFtZSwgaG9zdE9iamVjdCk7XG4gICAgICAgIH0sIHRoaXMpO1xufVxuXG5cbi8qKlxuICogU2V0cyBtaXhpbiBpbnN0YW5jZSBwcm9wZXJ0eSBuYW1lIG9uIHRoZSBob3N0IGNsYXNzXG4gKiBDYW4gYmUgY2FsbGVkIG9ubHkgb25jZVxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzIE1peGluIHN1YmNsYXNzIChub3QgaW5zdGFuY2UpXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBob3N0Q2xhc3NcbiAqIEBwYXJhbSB7U3RyaW5nfSBpbnN0YW5jZUtleVxuICovXG5mdW5jdGlvbiBNaXhpbl9zZXRJbnN0YW5jZUtleShob3N0Q2xhc3MsIG1ldGhvZCwgaW5zdGFuY2VLZXkpIHtcbiAgICBjaGVjayhob3N0Q2xhc3MsIEZ1bmN0aW9uKTtcbiAgICBjaGVjayhpbnN0YW5jZUtleSwgTWF0Y2guSWRlbnRpZmllclN0cmluZyk7XG5cbiAgICB2YXIgcHJvcCA9IGNvbmZpZy5taXhpbi5pbnN0YW5jZVByb3BlcnRpZXNNYXBcbiAgICAgICAgLCBpbnN0YW5jZUtleXMgPSBob3N0Q2xhc3NbcHJvcF0gPSBob3N0Q2xhc3NbcHJvcF0gfHwge307XG5cbiAgICBpZiAoaW5zdGFuY2VLZXlzW21ldGhvZC5uYW1lXSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXhpbjogaW5zdGFuY2UgcHJvcGVydHkgZm9yIG1ldGhvZCB3aXRoIG5hbWUgJ1xuICAgICAgICAgICAgKyBtZXRob2QubmFtZSArICcgaXMgYWxyZWFkeSBzZXQnKTtcblxuICAgIGluc3RhbmNlS2V5c1ttZXRob2QubmFtZV0gPSBpbnN0YW5jZUtleTtcbn1cblxuXG4vKipcbiAqIEFkZHMgbWV0aG9kIG9mIE1peGluIHN1YmNsYXNzIHRvIGhvc3QgY2xhc3MgcHJvdG90eXBlLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzIE1peGluIHN1YmNsYXNzIChub3QgaW5zdGFuY2UpXG4gKiBAcGFyYW0ge1N0cmluZ30gbWl4aW5NZXRob2ROYW1lIG5hbWUgb2YgbWV0aG9kIGluIE1peGluIHN1YmNsYXNzXG4gKiBAcGFyYW0ge1N0cmluZ30gaG9zdE1ldGhvZE5hbWUgKG9wdGlvbmFsKSBuYW1lIG9mIGNyZWF0ZWQgcHJveHkgbWV0aG9kIG9uIGhvc3Qgb2JqZWN0LCBzYW1lIGlmIG5vdCBzcGVjaWZpZWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0T2JqZWN0IG9iamVjdCBjbGFzcywgbXVzdCBiZSBzcGVjaWZpZWQgYXMgdGhlIGxhc3QgcGFyYW1ldGVyICgybmQgb3IgM3JkKVxuICovXG5mdW5jdGlvbiBNaXhpbl9hZGRNZXRob2QoaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2ROYW1lLCBob3N0TWV0aG9kTmFtZSkge1xuICAgIHZhciBtZXRob2QgPSB0aGlzLnByb3RvdHlwZVttaXhpbk1ldGhvZE5hbWVdO1xuICAgIGNoZWNrKG1ldGhvZCwgRnVuY3Rpb24pO1xuXG4gICAgdmFyIHdyYXBwZWRNZXRob2QgPSBfd3JhcE1peGluTWV0aG9kLmNhbGwodGhpcywgbWV0aG9kKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydHkoaG9zdENsYXNzLnByb3RvdHlwZSwgaG9zdE1ldGhvZE5hbWUsIHdyYXBwZWRNZXRob2QsIF8uV1JJVCk7XG5cbiAgICBNaXhpbl9zZXRJbnN0YW5jZUtleShob3N0Q2xhc3MsIG1ldGhvZCwgaW5zdGFuY2VLZXkpXG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIG1ldGhvZCB0aGF0IHdpbGwgYmUgZXhwb3NlZCBvbiB0aGUgaG9zdCBjbGFzcyBwcm90b3R5cGVcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gdGhpcyBNaXhpbiBzdWJjbGFzcyAobm90IGluc3RhbmNlKVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIF93cmFwTWl4aW5NZXRob2QobWV0aG9kKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkgeyAvLyAsLi4uIGFyZ3VtZW50c1xuICAgICAgICB2YXIgbWl4aW5JbnN0YW5jZSA9IF9nZXRNaXhpbkluc3RhbmNlLmNhbGwodGhpcywgbWV0aG9kLm5hbWUpO1xuICAgICAgICByZXR1cm4gbWV0aG9kLmFwcGx5KG1peGluSW5zdGFuY2UsIGFyZ3VtZW50cyk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgcmVmZXJlbmNlIHRvIHRoZSBpbnN0YW5jZSBvZiBtaXhpbiBzdWJjbGFzcy5cbiAqIFRoaXMgbWV0aG9kIGlzIHVzZWQgd2hlbiBtZXRob2RzIGFyZSBleHBvc2VkIG9uIHRoZSBob3N0IGNsYXNzIHByb3RvdHlwZSAodXNpbmcgYWRkTWVodG9kcykgcmF0aGVyIHRoYW4gb24gaG9zdCBpbnN0YW5jZS5cbiAqIFN1YmNsYXNzZXMgc2hvdWxkIG5vdCB1c2UgdGhpcyBtZXRob2RzIC0gd2hlbmV2ZXIgc3ViY2xhc3MgbWV0aG9kIGlzIGV4cG9zZWQgb24gdGhlIHByb3RvdHlwZSBpdCB3aWxsIGJlIHdyYXBwZWQgdG8gc2V0IGNvcnJlY3QgY29udGV4dCBmb3IgdGhlIHN1YmNsYXNzIG1ldGhvZC5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBfZ2V0TWl4aW5JbnN0YW5jZShtZXRob2ROYW1lKSB7XG4gICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBNaXhpbikgcmV0dXJuIHRoaXM7XG4gICAgdmFyIGluc3RhbmNlS2V5cyA9IHRoaXMuY29uc3RydWN0b3JbY29uZmlnLm1peGluLmluc3RhbmNlUHJvcGVydGllc01hcF1cbiAgICByZXR1cm4gdGhpc1tpbnN0YW5jZUtleXNbbWV0aG9kTmFtZV1dO1xufVxuXG5cbi8qKlxuICogQWRkcyBtZXRob2RzIG9mIE1peGluIHN1YmNsYXNzIHRvIGhvc3QgY2xhc3MgcHJvdG90eXBlLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHRoaXMgTWl4aW4gc3ViY2xhc3MgKG5vdCBpbnN0YW5jZSlcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0Q2xhc3MgaG9zdCBvYmplY3QgY2xhc3M7IG11c3QgYmUgc3BlY2lmaWVkLlxuICogQHBhcmFtIHtTdHJpbmd9IGluc3RhbmNlS2V5IHRoZSBuYW1lIG9mIHRoZSBwcm9wZXJ0eSB0aGUgaG9zdCBjbGFzcyBpbnN0YW5jZSB3aWxsIHN0b3JlIG1peGluIGluc3RhbmNlIG9uXG4gKiBAcGFyYW0ge0hhc2hbU3RyaW5nXXxBcnJheVtTdHJpbmddfSBtaXhpbk1ldGhvZHMgbWFwIG9mIG5hbWVzIG9mIG1ldGhvZHMsIGtleSAtIGhvc3QgbWV0aG9kIG5hbWUsIHZhbHVlIC0gbWl4aW4gbWV0aG9kIG5hbWUuIENhbiBiZSBhcnJheS5cbiAqL1xuZnVuY3Rpb24gTWl4aW4kJHVzZVdpdGgoaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2RzKSB7XG4gICAgY2hlY2sobWl4aW5NZXRob2RzLCBNYXRjaC5PcHRpb25hbChNYXRjaC5PbmVPZihbU3RyaW5nXSwgTWF0Y2guT2JqZWN0SGFzaChTdHJpbmcpKSkpO1xuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkobWl4aW5NZXRob2RzKSlcbiAgICAgICAgbWl4aW5NZXRob2RzLmZvckVhY2goZnVuY3Rpb24obWV0aG9kTmFtZSkge1xuICAgICAgICAgICAgTWl4aW5fYWRkTWV0aG9kLmNhbGwodGhpcywgaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWV0aG9kTmFtZSwgbWV0aG9kTmFtZSk7XG4gICAgICAgIH0sIHRoaXMpO1xuICAgIGVsc2VcbiAgICAgICAgXy5lYWNoS2V5KG1peGluTWV0aG9kcywgZnVuY3Rpb24obWl4aW5NZXRob2ROYW1lLCBob3N0TWV0aG9kTmFtZSkge1xuICAgICAgICAgICAgTWl4aW5fYWRkTWV0aG9kLmNhbGwodGhpcywgaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2ROYW1lLCBob3N0TWV0aG9kTmFtZSk7XG4gICAgICAgIH0sIHRoaXMpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyA8YSBuYW1lPVwiY2xhc3Nlc1wiPjwvYT5cbi8vIG1pbG8uY2xhc3Nlc1xuLy8gLS0tLS0tLS0tLS1cblxuLy8gVGhpcyBtb2R1bGUgY29udGFpbnMgZm91bmRhdGlvbiBjbGFzc2VzXG5cbnZhciBjbGFzc2VzID0ge1xuICAgIE1peGluOiByZXF1aXJlKCcuL2Fic3RyYWN0L21peGluJyksXG4gICAgTWVzc2FnZVNvdXJjZTogcmVxdWlyZSgnLi9tZXNzZW5nZXIvbV9zb3VyY2UnKSxcbiAgICBNZXNzZW5nZXJNZXNzYWdlU291cmNlOiByZXF1aXJlKCcuL21lc3Nlbmdlci9tc25ncl9zb3VyY2UnKSxcbiAgICBNZXNzZW5nZXJBUEk6IHJlcXVpcmUoJy4vbWVzc2VuZ2VyL21fYXBpJyksXG4gICAgTWVzc2VuZ2VyUmVnZXhwQVBJOiByZXF1aXJlKCcuL21lc3Nlbmdlci9tX2FwaV9yeCcpXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzZXM7XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbmZpZztcblxuZnVuY3Rpb24gY29uZmlnKG9wdGlvbnMpIHtcbiAgICBfLmRlZXBFeHRlbmQoY29uZmlnLCBvcHRpb25zKTtcbn1cblxuY29uZmlnKHtcbiAgICBtaXhpbjoge1xuICAgICAgICBpbnN0YW5jZVByb3BlcnRpZXNNYXA6ICdfX19taXhpbl9pbnN0YW5jZXMnXG4gICAgfSxcbiAgICBjaGVjazogdHJ1ZSxcbiAgICBkZWJ1ZzogZmFsc2Vcbn0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgTWl4aW4gPSByZXF1aXJlKCcuLi9hYnN0cmFjdC9taXhpbicpXG4gICAgLCBNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi9tX3NvdXJjZScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5cbi8qKlxuICogYG1pbG8uTWVzc2VuZ2VyYFxuICogQSBnZW5lcmljIE1lc3NlbmdlciBjbGFzcyB0aGF0IGlzIHVzZWQgZm9yIGFsbCBraW5kcyBvZiBtZXNzYWdpbmcgaW4gbWlsby4gSXQgaXMgc3ViY2xhc3NlZCBmcm9tIFtNaXhpbl0oLi4vYWJzdHJhY3QvbWl4aW4uanMuaHRtbCkgYW5kIGl0IHByb3hpZXMgaXRzIG1ldGhvZHMgdG8gdGhlIGhvc3Qgb2JqZWN0IGZvciBjb252ZW5pZW5jZS5cbiAqIEFsbCBmYWNldHMgYW5kIGNvbXBvbmVudHMgaGF2ZSBtZXNzZW5nZXIgYXR0YWNoZWQgdG8gdGhlbS4gTWVzc2VuZ2VyIGNsYXNzIGludGVyb3BlcmF0ZXMgd2l0aCBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBjbGFzcyB0aGF0IGNvbm5lY3RzIHRoZSBtZXNzZW5nZXIgdG8gc29tZSBleHRlcm5hbCBzb3VyY2Ugb2YgbWVzc2FnZXMgKGUuZy4sIERPTSBldmVudHMpIGFuZCBbTWVzc2VuZ2VyQVBJXSguL21fYXBpLmpzLmh0bWwpIGNsYXNzIHRoYXQgYWxsb3dzIHRvIGRlZmluZSBoaWdoZXIgbGV2ZWwgbWVzc2FnZXMgdGhhbiBtZXNzYWdlcyB0aGF0IGV4aXN0IG9uIHRoZSBzb3VyY2UuXG4gKiBNZXNzZW5nZXIgY2xhc3MgaXMgdXNlZCBpbnRlcm5hbGx5IGluIG1pbG8gYW5kIGNhbiBiZSB1c2VkIHRvZ2V0aGVyIHdpdGggYW55IG9iamVjdHMvY2xhc3NlcyBpbiB0aGUgYXBwbGljYXRpb24uXG4gKiBtaWxvIGFsc28gZGVmaW5lcyBhIGdsb2JhbCBtZXNzZW5nZXIgW21pbG8ubWFpbF0oLi4vbWFpbC9pbmRleC5qcy5odG1sKSB0aGF0IGRpc3BhdGNoZXMgYGRvbXJlYWR5YCBldmVudCBhbmQgY2FuIGJlIHVzZWQgZm9yIGFueSBhcHBsaWNhdGlvbiB3aWRlIG1lc3NhZ2luZy5cbiAqIFRvIGluaXRpYWxpemUgeW91ciBhcHAgYWZ0ZXIgRE9NIGlzIHJlYWR5IHVzZTpcbiAqIGBgYFxuICogbWlsby5tYWlsLm9uKCdkb21yZWFkeScsIGZ1bmN0aW9uKCkge1xuICogICAgIC8vIGFwcGxpY2F0aW9uIHN0YXJ0c1xuICogfSk7XG4gKiBgYGBcbiAqIG9yIHRoZSBmb2xsb3dpbmcgc2hvcnRlciBmb3JtIG9mIHRoZSBzYW1lOlxuICogYGBgXG4gKiBtaWxvKGZ1bmN0aW9uKCkge1xuICogICAgIC8vIGFwcGxpY2F0aW9uIHN0YXJ0c1xuICogfSk7XG4gKiBgYGBcbiAqL1xudmFyIE1lc3NlbmdlciA9IF8uY3JlYXRlU3ViY2xhc3MoTWl4aW4sICdNZXNzZW5nZXInKTtcblxudmFyIG1lc3NhZ2VzU3BsaXRSZWdFeHAgPSBNZXNzZW5nZXIubWVzc2FnZXNTcGxpdFJlZ0V4cCA9IC9cXHMqKD86XFwsfFxccylcXHMqLztcblxuXG4vKipcbiAqICMjIyNNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kcyMjIyNcbiAqXG4gKiAtIFtpbml0XSgjaW5pdClcbiAqIC0gW29uXSgjTWVzc2VuZ2VyJG9uKSAoYWxpYXMgLSBvbk1lc3NhZ2UsIGRlcHJlY2F0ZWQpXG4gKiAtIFtvZmZdKCNNZXNzZW5nZXIkb2ZmKSAoYWxpYXMgLSBvZmZNZXNzYWdlLCBkZXByZWNhdGVkKVxuICogLSBbb25NZXNzYWdlc10oI29uTWVzc2FnZXMpXG4gKiAtIFtvZmZNZXNzYWdlc10oI29mZk1lc3NhZ2VzKVxuICogLSBbb25jZV0oI29uY2UpXG4gKiAtIFtvbmNlU3luY10oI29uY2VTeW5jKVxuICogLSBbcG9zdE1lc3NhZ2VdKCNwb3N0TWVzc2FnZSlcbiAqIC0gW2dldFN1YnNjcmliZXJzXSgjZ2V0U3Vic2NyaWJlcnMpXG4gKlxuICogXCJQcml2YXRlXCIgbWV0aG9kc1xuICpcbiAqIC0gW19jaG9vc2VTdWJzY3JpYmVyc0hhc2hdKCNfY2hvb3NlU3Vic2NyaWJlcnNIYXNoKVxuICogLSBbX3JlZ2lzdGVyU3Vic2NyaWJlcl0oI19yZWdpc3RlclN1YnNjcmliZXIpXG4gKiAtIFtfcmVtb3ZlU3Vic2NyaWJlcl0oI19yZW1vdmVTdWJzY3JpYmVyKVxuICogLSBbX3JlbW92ZUFsbFN1YnNjcmliZXJzXSgjX3JlbW92ZUFsbFN1YnNjcmliZXJzKVxuICogLSBbX2NhbGxQYXR0ZXJuU3Vic2NyaWJlcnNdKCNfY2FsbFBhdHRlcm5TdWJzY3JpYmVycylcbiAqIC0gW19jYWxsU3Vic2NyaWJlcnNdKCNfY2FsbFN1YnNjcmliZXJzKVxuICogLSBbX3NldE1lc3NhZ2VTb3VyY2VdKCNfc2V0TWVzc2FnZVNvdXJjZSlcbiAqIC0gW2dldE1lc3NhZ2VTb3VyY2VdKCNnZXRNZXNzYWdlU291cmNlKVxuICovXG5fLmV4dGVuZFByb3RvKE1lc3Nlbmdlciwge1xuICAgIGluaXQ6IGluaXQsIC8vIGNhbGxlZCBieSBNaXhpbiAoc3VwZXJjbGFzcylcbiAgICBkZXN0cm95OiBNZXNzZW5nZXIkZGVzdHJveSxcbiAgICBvbjogTWVzc2VuZ2VyJG9uLFxuICAgIG9uY2U6IE1lc3NlbmdlciRvbmNlLFxuICAgIG9uY2VTeW5jOiBNZXNzZW5nZXIkb25jZVN5bmMsXG4gICAgb25TeW5jOiBNZXNzZW5nZXIkb25TeW5jLFxuICAgIG9uQXN5bmM6IE1lc3NlbmdlciRvbkFzeW5jLFxuICAgIG9uTWVzc2FnZTogTWVzc2VuZ2VyJG9uLCAvLyBkZXByZWNhdGVkXG4gICAgb2ZmOiBNZXNzZW5nZXIkb2ZmLFxuICAgIG9mZk1lc3NhZ2U6IE1lc3NlbmdlciRvZmYsIC8vIGRlcHJlY2F0ZWRcbiAgICBvbk1lc3NhZ2VzOiBvbk1lc3NhZ2VzLFxuICAgIG9mZk1lc3NhZ2VzOiBvZmZNZXNzYWdlcyxcbiAgICBvZmZBbGw6IE1lc3NlbmdlciRvZmZBbGwsXG4gICAgcG9zdE1lc3NhZ2U6IHBvc3RNZXNzYWdlLFxuICAgIHBvc3RNZXNzYWdlU3luYzogcG9zdE1lc3NhZ2VTeW5jLFxuICAgIGdldFN1YnNjcmliZXJzOiBnZXRTdWJzY3JpYmVycyxcbiAgICBnZXRNZXNzYWdlU291cmNlOiBnZXRNZXNzYWdlU291cmNlLFxuICAgIF9jaG9vc2VTdWJzY3JpYmVyc0hhc2g6IF9jaG9vc2VTdWJzY3JpYmVyc0hhc2gsXG4gICAgX3JlZ2lzdGVyU3Vic2NyaWJlcjogX3JlZ2lzdGVyU3Vic2NyaWJlcixcbiAgICBfcmVtb3ZlU3Vic2NyaWJlcjogX3JlbW92ZVN1YnNjcmliZXIsXG4gICAgX3JlbW92ZUFsbFN1YnNjcmliZXJzOiBfcmVtb3ZlQWxsU3Vic2NyaWJlcnMsXG4gICAgX2NhbGxQYXR0ZXJuU3Vic2NyaWJlcnM6IF9jYWxsUGF0dGVyblN1YnNjcmliZXJzLFxuICAgIF9jYWxsU3Vic2NyaWJlcnM6IF9jYWxsU3Vic2NyaWJlcnMsXG4gICAgX2NhbGxTdWJzY3JpYmVyOiBfY2FsbFN1YnNjcmliZXIsXG4gICAgX3NldE1lc3NhZ2VTb3VyY2U6IF9zZXRNZXNzYWdlU291cmNlXG59KTtcblxuXG4vKipcbiAqIEEgZGVmYXVsdCBtYXAgb2YgcHJveHkgbWV0aG9kcyB1c2VkIGJ5IENvbXBvbmVudEZhY2V0IGFuZCBDb21wb25lbnQgY2xhc3NlcyB0byBwYXNzIHRvIE1lc3NlbmdlciB3aGVuIGl0IGlzIGluc3RhbnRpYXRlZC5cbiAqIFRoaXMgbWFwIGlzIGZvciBjb252ZW5pZW5jZSBvbmx5LCBpdCBpcyBOT1QgdXNlZCBpbnRlcm5hbGx5IGJ5IE1lc3NlbmdlciwgYSBob3N0IGNsYXNzIHNob3VsZCBwYXNzIGl0IGZvciBtZXRob2RzIHRvIGJlIHByb3hpZWQgdGhpcyB3YXkuXG4gKi9cbk1lc3Nlbmdlci5kZWZhdWx0TWV0aG9kcyA9IHtcbiAgICBvbjogJ29uJyxcbiAgICBvblN5bmM6ICdvblN5bmMnLFxuICAgIG9uY2U6ICdvbmNlJyxcbiAgICBvbmNlU3luYzogJ29uY2VTeW5jJyxcbiAgICBvZmY6ICdvZmYnLFxuICAgIG9uTWVzc2FnZXM6ICdvbk1lc3NhZ2VzJyxcbiAgICBvZmZNZXNzYWdlczogJ29mZk1lc3NhZ2VzJyxcbiAgICBwb3N0TWVzc2FnZTogJ3Bvc3RNZXNzYWdlJyxcbiAgICBwb3N0TWVzc2FnZVN5bmM6ICdwb3N0TWVzc2FnZVN5bmMnLFxuICAgIGdldFN1YnNjcmliZXJzOiAnZ2V0U3Vic2NyaWJlcnMnXG59O1xuXG5cbm1vZHVsZS5leHBvcnRzID0gTWVzc2VuZ2VyO1xuXG5cbk1lc3Nlbmdlci5zdWJzY3JpcHRpb25zID0gW107XG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsaXplcyBNZXNzZW5nZXIuIE1ldGhvZCBpcyBjYWxsZWQgYnkgTWl4aW4gY2xhc3MgY29uc3RydWN0b3IuXG4gKiBTZWUgW29uXSgjTWVzc2VuZ2VyJG9uKSBtZXRob2QsIFtNZXNzZW5nZXJdKCNNZXNzZW5nZXIpIGNsYXNzIGFib3ZlIGFuZCBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBjbGFzcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBPcHRpb25hbCBvYmplY3QgdGhhdCBzdG9yZXMgdGhlIG1lc3NlbmdlciBvbiBvbmUgb2YgaXRzIHByb3BlcnRpZXMuIEl0IGlzIHVzZWQgdG8gcHJveHkgbWV0aG9kcyBvZiBtZXNzZW5nZXIgYW5kIGFsc28gYXMgYSBjb250ZXh0IGZvciBzdWJzY3JpYmVycyB3aGVuIHRoZXkgYXJlIGNhbGxlZCBieSB0aGUgTWVzc2VuZ2VyLiBTZWUgYG9uYCBtZXRob2QuXG4gKiBAcGFyYW0ge09iamVjdH0gcHJveHlNZXRob2RzIE9wdGlvbmFsIG1hcCBvZiBtZXRob2QgbmFtZXM7IGtleSAtIHByb3h5IG1ldGhvZCBuYW1lLCB2YWx1ZSAtIG1lc3NlbmdlcidzIG1ldGhvZCBuYW1lLlxuICogQHBhcmFtIHtNZXNzYWdlU291cmNlfSBtZXNzYWdlU291cmNlIE9wdGlvbmFsIG1lc3NhZ2VTb3VyY2UgbGlua2VkIHRvIHRoZSBtZXNzZW5nZXIuIElmIG1lc3NhZ2VTb3VyY2UgaXMgc3VwcGxpZWQsIHRoZSByZWZlcmVuY2UgdG8gdGhlIG1lc3NlbmdlciB3aWxsIHN0b3JlZCBvbiBpdHMgJ21lc3NlbmdlcicgcHJvcGVydHlcbiAqL1xuZnVuY3Rpb24gaW5pdChob3N0T2JqZWN0LCBwcm94eU1ldGhvZHMsIG1lc3NhZ2VTb3VyY2UpIHtcbiAgICAvLyBob3N0T2JqZWN0IGFuZCBwcm94eU1ldGhvZHMgYXJlIHVzZWQgaW4gTWl4aW4gYW5kIGNoZWNrZWQgdGhlcmVcbiAgICBpZiAobWVzc2FnZVNvdXJjZSlcbiAgICAgICAgdGhpcy5fc2V0TWVzc2FnZVNvdXJjZShtZXNzYWdlU291cmNlKTtcblxuICAgIF9pbml0aWFsaXplU3Vic2NyaWJlcnMuY2FsbCh0aGlzKTtcbn1cblxuXG5mdW5jdGlvbiBfaW5pdGlhbGl6ZVN1YnNjcmliZXJzKCkge1xuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgIF9tZXNzYWdlU3Vic2NyaWJlcnM6IHt9LFxuICAgICAgICBfcGF0dGVybk1lc3NhZ2VTdWJzY3JpYmVyczoge30sXG4gICAgfSwgXy5DT05GKTtcbn1cblxuXG4vKipcbiAqIERlc3Ryb3lzIG1lc3Nlbmdlci4gTWF5YmUgbmVlZHMgdG8gdW5zdWJzY3JpYmUgYWxsIHN1YnNjcmliZXJzXG4gKi9cbmZ1bmN0aW9uIE1lc3NlbmdlciRkZXN0cm95KCkge1xuICAgIHRoaXMub2ZmQWxsKCk7XG4gICAgdmFyIG1lc3NhZ2VTb3VyY2UgPSB0aGlzLmdldE1lc3NhZ2VTb3VyY2UoKTtcbiAgICBpZiAobWVzc2FnZVNvdXJjZSlcbiAgICAgICAgbWVzc2FnZVNvdXJjZS5kZXN0cm95KCk7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogUmVnaXN0ZXJzIGEgc3Vic2NyaWJlciBmdW5jdGlvbiBmb3IgYSBjZXJ0YWluIG1lc3NhZ2UocykuXG4gKiBUaGlzIG1ldGhvZCByZXR1cm5zIGB0cnVlYCBpZiB0aGUgc3Vic2NyaXB0aW9uIHdhcyBzdWNjZXNzZnVsLiBJdCBjYW4gYmUgdW5zdWNjZXNzZnVsIGlmIHRoZSBwYXNzZWQgc3Vic2NyaWJlciBoYXMgYWxyZWFkeSBiZWVuIHN1YnNjcmliZWQgdG8gdGhpcyBtZXNzYWdlIHR5cGUgLSBkb3VibGUgc3Vic2NyaXB0aW9uIG5ldmVyIGhhcHBlbnMgYW5kIGl0IGlzIHNhZmUgdG8gc3Vic2NyaWJlIGFnYWluIC0gbm8gZXJyb3Igb3Igd2FybmluZyBpcyB0aHJvd24gb3IgbG9nZ2VkLlxuICogU3Vic2NyaWJlciBpcyBwYXNzZWQgdHdvIHBhcmFtZXRlcnM6IGBtZXNzYWdlYCAoc3RyaW5nKSBhbmQgYGRhdGFgIChvYmplY3QpLiBEYXRhIG9iamVjdCBpcyBzdXBwbGllZCB3aGVuIG1lc3NhZ2UgaXMgZGlzcGF0Y2hlZCwgTWVzc2VuZ2VyIGl0c2VsZiBhZGRzIG5vdGhpbmcgdG8gaXQuIEZvciBleGFtcGxlLCBbZXZlbnRzIGZhY2V0XSguLi9jb21wb25lbnRzL2NfZmFjZXRzL0V2ZW50cy5qcy5odG1sKSBzZW5kcyBhY3R1YWwgRE9NIGV2ZW50IHdoZW4gaXQgcG9zdHMgbWVzc2FnZS5cbiAqIFVzYWdlOlxuICogYGBgXG4gKiAvLyBzdWJzY3JpYmVzIG9uTW91c2VVcERvd24gdG8gdHdvIERPTSBldmVudHMgb24gY29tcG9uZW50IHZpYSBldmVudHMgZmFjZXQuXG4gKiBteUNvbXAuZXZlbnRzLm9uKCdtb3VzZWRvd24gbW91c2V1cCcsIG9uTW91c2VVcERvd24pO1xuICogZnVuY3Rpb24gb25Nb3VzZVVwRG93bihldmVudFR5cGUsIGV2ZW50KSB7XG4gKiAgICAgLy8gLi4uXG4gKiB9XG4gKlxuICogbXlDb21wLmRhdGEub24oLy4rLywgZnVuY3Rpb24obXNnLCBkYXRhKSB7XG4gKiAgICAgbG9nZ2VyLmRlYnVnKG1zZywgZGF0YSk7XG4gKiB9KTsgLy8gc3Vic2NyaWJlcyBhbm9ueW1vdXMgZnVuY3Rpb24gdG8gYWxsIG5vbi1lbXB0eSBtZXNzYWdlcyBvbiBkYXRhIGZhY2V0XG4gKiAvLyBpdCB3aWxsIG5vdCBiZSBwb3NzaWJsZSB0byB1bnN1YnNjcmliZSBhbm9ueW1vdXMgc3Vic2NyaWJlciBzZXBhcmF0ZWx5LFxuICogLy8gYnV0IG15Q29tcC5kYXRhLm9mZigvLisvKSB3aWxsIHVuc3Vic2NyaWJlIGl0XG4gKiBgYGBcbiAqIElmIG1lc3NlbmdlciBoYXMgW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgYXR0YWNoZWQgdG8gaXQsIE1lc3NhZ2VTb3VyY2Ugd2lsbCBiZSBub3RpZmllZCB3aGVuIHRoZSBmaXJzdCBzdWJzY3JpYmVyIGZvciBhIGdpdmVuIG1lc3NhZ2UgaXMgYWRkZWQsIHNvIGl0IGNhbiBzdWJzY3JpYmUgdG8gdGhlIHNvdXJjZS5cbiAqIFtDb21wb25lbnRzXSguLi9jb21wb25lbnRzL2NfY2xhc3MuanMuaHRtbCkgYW5kIFtmYWNldHNdKC4uL2NvbXBvbmVudHMvY19mYWNldC5qcy5odG1sKSBjaGFuZ2UgdGhpcyBtZXRob2QgbmFtZSB0byBgb25gIHdoZW4gdGhleSBwcm94eSBpdC5cbiAqIFNlZSBbcG9zdE1lc3NhZ2VdKCNwb3N0TWVzc2FnZSkuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8QXJyYXlbU3RyaW5nXXxSZWdFeHB9IG1lc3NhZ2VzIE1lc3NhZ2UgdHlwZXMgdGhhdCBzaG91bGQgZW52b2tlIHRoZSBzdWJzY3JpYmVyLlxuICogIElmIHN0cmluZyBpcyBwYXNzZWQsIGl0IGNhbiBiZSBhIHNpZ2xlIG1lc3NhZ2Ugb3IgbXVsdGlwbGUgbWVzc2FnZSB0eXBlcyBzZXBhcmF0ZWQgYnkgd2hpdGVzcGFjZSB3aXRoIG9wdGlvbmFsIGNvbW1hcy5cbiAqICBJZiBhbiBhcnJheSBvZiBzdHJpbmdzIGlzIHBhc3NlZCwgZWFjaCBzdHJpbmcgaXMgYSBtZXNzYWdlIHR5cGUgdG8gc3Vic2NyaWJlIGZvci5cbiAqICBJZiBhIFJlZ0V4cCBpcyBwYXNzZWQsIHRoZSBzdWJzY3JpYmVyIHdpbGwgYmUgZW52b2tlZCB3aGVuIHRoZSBtZXNzYWdlIGRpc3BhdGNoZWQgb24gdGhlIG1lc3NlbmdlciBtYXRjaGVzIHRoZSBwYXR0ZXJuIChvciBJUyB0aGUgUmVnRXhwIHdpdGggaWRlbnRpY2FsIHBhdHRlcm4pLlxuICogIFBhdHRlcm4gc3Vic2NyaWJlciBkb2VzIE5PVCBjYXVzZSBhbnkgc3Vic2NyaXB0aW9uIHRvIE1lc3NhZ2VTb3VyY2UsIGl0IG9ubHkgY2FwdHVyZXMgbWVzc2FnZXMgdGhhdCBhcmUgYWxyZWFkeSBzdWJzY3JpYmVkIHRvIHdpdGggcHJlY2lzZSBtZXNzYWdlIHR5cGVzLlxuICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R9IHN1YnNjcmliZXIgTWVzc2FnZSBzdWJzY3JpYmVyIC0gYSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgY2FsbGVkIHdoZW4gdGhlIG1lc3NhZ2UgaXMgZGlzcGF0Y2hlZCBvbiB0aGUgbWVzc2VuZ2VyICh1c3VhbGx5IHZpYSBwcm94aWVkIHBvc3RNZXNzYWdlIG1ldGhvZCBvZiBob3N0IG9iamVjdCkuXG4gKiAgSWYgaG9zdE9iamVjdCB3YXMgc3VwcGxpZWQgdG8gTWVzc2VuZ2VyIGNvbnN0cnVjdG9yLCBob3N0T2JqZWN0IHdpbGwgYmUgdGhlIGNvbnRleHQgKHRoZSB2YWx1ZSBvZiB0aGlzKSBmb3IgdGhlIHN1YnNjcmliZXIgZW52b2NhdGlvbi5cbiAqICBTdWJzY3JpYmVyIGNhbiBhbHNvIGJlIGFuIG9iamVjdCB3aXRoIHByb3BlcnRpZXMgYHN1YnNjcmliZXJgIChmdW5jdGlvbikgYW5kIGBjb250ZXh0YCAoXCJ0aGlzXCIgdmFsdWUgd2hlbiBzdWJzY3JpYmVyIGlzIGNhbGxlZClcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIE1lc3NlbmdlciRvbihtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIHJldHVybiBfTWVzc2VuZ2VyX29uV2l0aE9wdGlvbnMuY2FsbCh0aGlzLCBtZXNzYWdlcywgc3Vic2NyaWJlcik7XG59XG5cblxuZnVuY3Rpb24gTWVzc2VuZ2VyJG9uY2UobWVzc2FnZXMsIHN1YnNjcmliZXIpIHtcbiAgICByZXR1cm4gX01lc3Nlbmdlcl9vbldpdGhPcHRpb25zLmNhbGwodGhpcywgbWVzc2FnZXMsIHN1YnNjcmliZXIsIHsgZGlzcGF0Y2hUaW1lczogMSB9KTtcbn1cblxuZnVuY3Rpb24gTWVzc2VuZ2VyJG9uY2VTeW5jKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKSB7XG4gICAgcmV0dXJuIF9NZXNzZW5nZXJfb25XaXRoT3B0aW9ucy5jYWxsKHRoaXMsIG1lc3NhZ2VzLCBzdWJzY3JpYmVyLCB7IGRpc3BhdGNoVGltZXM6IDEsIHN5bmM6IHRydWUgfSk7XG59XG5cblxuZnVuY3Rpb24gTWVzc2VuZ2VyJG9uU3luYyhtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIHJldHVybiBfTWVzc2VuZ2VyX29uV2l0aE9wdGlvbnMuY2FsbCh0aGlzLCBtZXNzYWdlcywgc3Vic2NyaWJlciwgeyBzeW5jOiB0cnVlIH0pO1xufVxuXG5cbmZ1bmN0aW9uIE1lc3NlbmdlciRvbkFzeW5jKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKSB7XG4gICAgcmV0dXJuIF9NZXNzZW5nZXJfb25XaXRoT3B0aW9ucy5jYWxsKHRoaXMsIG1lc3NhZ2VzLCBzdWJzY3JpYmVyLCB7IHN5bmM6IGZhbHNlIH0pO1xufVxuXG5cbmZ1bmN0aW9uIF9NZXNzZW5nZXJfb25XaXRoT3B0aW9ucyhtZXNzYWdlcywgc3Vic2NyaWJlciwgb3B0aW9ucykge1xuICAgIGNoZWNrKG1lc3NhZ2VzLCBNYXRjaC5PbmVPZihTdHJpbmcsIFtTdHJpbmddLCBSZWdFeHApKTtcbiAgICBjaGVjayhzdWJzY3JpYmVyLCBNYXRjaC5PbmVPZihGdW5jdGlvbiwge1xuICAgICAgICBzdWJzY3JpYmVyOiBGdW5jdGlvbixcbiAgICAgICAgY29udGV4dDogTWF0Y2guQW55LFxuICAgICAgICBvcHRpb25zOiBNYXRjaC5PcHRpb25hbChPYmplY3QpLFxuICAgIH0pKTtcblxuICAgIGlmICh0eXBlb2Ygc3Vic2NyaWJlciA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHN1YnNjcmliZXIgPSB7XG4gICAgICAgICAgICBzdWJzY3JpYmVyOiBzdWJzY3JpYmVyLFxuICAgICAgICAgICAgY29udGV4dDogdGhpcy5faG9zdE9iamVjdCxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAob3B0aW9ucykge1xuICAgICAgICBzdWJzY3JpYmVyLm9wdGlvbnMgPSBzdWJzY3JpYmVyLm9wdGlvbnMgfHwge307XG4gICAgICAgIF8uZXh0ZW5kKHN1YnNjcmliZXIub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIF9NZXNzZW5nZXJfb24uY2FsbCh0aGlzLCBtZXNzYWdlcywgc3Vic2NyaWJlcik7XG59XG5cblxuZnVuY3Rpb24gX01lc3Nlbmdlcl9vbihtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIF8uZGVmaW5lUHJvcGVydHkoc3Vic2NyaWJlciwgJ19fbWVzc2FnZXMnLCBtZXNzYWdlcyk7XG4gICAgcmV0dXJuIF9lYWNoTWVzc2FnZS5jYWxsKHRoaXMsICdfcmVnaXN0ZXJTdWJzY3JpYmVyJywgbWVzc2FnZXMsIHN1YnNjcmliZXIpO1xufVxuXG5cbmZ1bmN0aW9uIF9lYWNoTWVzc2FnZShtZXRob2ROYW1lLCBtZXNzYWdlcywgc3Vic2NyaWJlcikge1xuICAgIGlmICh0eXBlb2YgbWVzc2FnZXMgPT0gJ3N0cmluZycpXG4gICAgICAgIG1lc3NhZ2VzID0gbWVzc2FnZXMuc3BsaXQobWVzc2FnZXNTcGxpdFJlZ0V4cCk7XG5cbiAgICB2YXIgc3Vic2NyaWJlcnNIYXNoID0gdGhpcy5fY2hvb3NlU3Vic2NyaWJlcnNIYXNoKG1lc3NhZ2VzKTtcblxuICAgIGlmIChtZXNzYWdlcyBpbnN0YW5jZW9mIFJlZ0V4cClcbiAgICAgICAgcmV0dXJuIHRoaXNbbWV0aG9kTmFtZV0oc3Vic2NyaWJlcnNIYXNoLCBtZXNzYWdlcywgc3Vic2NyaWJlcik7XG5cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIGNoYW5nZWQgPSBmYWxzZTtcblxuICAgICAgICBtZXNzYWdlcy5mb3JFYWNoKGZ1bmN0aW9uKG1lc3NhZ2UpIHtcbiAgICAgICAgICAgIHZhciBzdWJzY3JpcHRpb25DaGFuZ2VkID0gdGhpc1ttZXRob2ROYW1lXShzdWJzY3JpYmVyc0hhc2gsIG1lc3NhZ2UsIHN1YnNjcmliZXIpO1xuICAgICAgICAgICAgY2hhbmdlZCA9IGNoYW5nZWQgfHwgc3Vic2NyaXB0aW9uQ2hhbmdlZDtcbiAgICAgICAgfSwgdGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5nZWQ7XG4gICAgfVxufVxuXG5cbi8qKlxuICogXCJQcml2YXRlXCIgTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZFxuICogSXQgaXMgY2FsbGVkIGJ5IFtvbl0oI01lc3NlbmdlciRvbikgdG8gcmVnaXN0ZXIgc3Vic2NyaWJlciBmb3Igb25lIG1lc3NhZ2UgdHlwZS5cbiAqIFJldHVybnMgYHRydWVgIGlmIHRoaXMgc3Vic2NyaWJlciBpcyBub3QgeWV0IHJlZ2lzdGVyZWQgZm9yIHRoaXMgdHlwZSBvZiBtZXNzYWdlLlxuICogSWYgbWVzc2VuZ2VyIGhhcyBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBhdHRhY2hlZCB0byBpdCwgTWVzc2FnZVNvdXJjZSB3aWxsIGJlIG5vdGlmaWVkIHdoZW4gdGhlIGZpcnN0IHN1YnNjcmliZXIgZm9yIGEgZ2l2ZW4gbWVzc2FnZSBpcyBhZGRlZC5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtPYmplY3R9IHN1YnNjcmliZXJzSGFzaCBUaGUgbWFwIG9mIHN1YnNjcmliZXJzIGRldGVybWluZWQgYnkgW29uXSgjTWVzc2VuZ2VyJG9uKSBiYXNlZCBvbiBNZXNzYWdlIHR5cGUsIGNhbiBiZSBgdGhpcy5fcGF0dGVybk1lc3NhZ2VTdWJzY3JpYmVyc2Agb3IgYHRoaXMuX21lc3NhZ2VTdWJzY3JpYmVyc2BcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIE1lc3NhZ2UgdHlwZVxuICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R9IHN1YnNjcmliZXIgU3Vic2NyaWJlciBmdW5jdGlvbiB0byBiZSBhZGRlZCBvciBvYmplY3Qgd2l0aCBwcm9wZXJ0aWVzIGBzdWJzY3JpYmVyYCAoZnVuY3Rpb24pIGFuZCBgY29udGV4dGAgKHZhbHVlIG9mIFwidGhpc1wiIHdoZW4gc3Vic2NyaWJlciBpcyBjYWxsZWQpXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBfcmVnaXN0ZXJTdWJzY3JpYmVyKHN1YnNjcmliZXJzSGFzaCwgbWVzc2FnZSwgc3Vic2NyaWJlcikge1xuICAgIGlmICghIChzdWJzY3JpYmVyc0hhc2hbbWVzc2FnZV0gJiYgc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdLmxlbmd0aCkpIHtcbiAgICAgICAgc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdID0gW107XG4gICAgICAgIGlmIChtZXNzYWdlIGluc3RhbmNlb2YgUmVnRXhwKVxuICAgICAgICAgICAgc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdLnBhdHRlcm4gPSBtZXNzYWdlO1xuICAgICAgICBpZiAodGhpcy5fbWVzc2FnZVNvdXJjZSlcbiAgICAgICAgICAgIHRoaXMuX21lc3NhZ2VTb3VyY2Uub25TdWJzY3JpYmVyQWRkZWQobWVzc2FnZSk7XG4gICAgICAgIHZhciBub1N1YnNjcmliZXJzID0gdHJ1ZTtcbiAgICB9XG5cbiAgICB2YXIgbXNnU3Vic2NyaWJlcnMgPSBzdWJzY3JpYmVyc0hhc2hbbWVzc2FnZV07XG4gICAgdmFyIG5vdFlldFJlZ2lzdGVyZWQgPSBub1N1YnNjcmliZXJzIHx8IF9pbmRleE9mU3Vic2NyaWJlci5jYWxsKHRoaXMsIG1zZ1N1YnNjcmliZXJzLCBzdWJzY3JpYmVyKSA9PSAtMTtcblxuICAgIGlmIChub3RZZXRSZWdpc3RlcmVkKVxuICAgICAgICBtc2dTdWJzY3JpYmVycy5wdXNoKHN1YnNjcmliZXIpO1xuXG4gICAgcmV0dXJuIG5vdFlldFJlZ2lzdGVyZWQ7XG59XG5cblxuLyoqXG4gKiBGaW5kcyBzdWJzY3JpYmVyIGluZGV4IGluIHRoZSBsaXN0XG4gKlxuICogQHBhcmFtIHtBcnJheVtGdW5jdGlvbnxPYmplY3RdfSBsaXN0IGxpc3Qgb2Ygc3Vic2NyaWJlcnNcbiAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fSBzdWJzY3JpYmVyIHN1YnNjcmliZXIgZnVuY3Rpb24gb3Igb2JqZWN0IHdpdGggcHJvcGVydGllcyBgc3Vic2NyaWJlcmAgKGZ1bmN0aW9uKSBhbmQgYGNvbnRleHRgIChcInRoaXNcIiBvYmplY3QpXG4gKi9cbmZ1bmN0aW9uIF9pbmRleE9mU3Vic2NyaWJlcihsaXN0LCBzdWJzY3JpYmVyKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHJldHVybiBfLmZpbmRJbmRleChsaXN0LCBmdW5jdGlvbihzdWJzY3Ipe1xuICAgICAgICByZXR1cm4gc3Vic2NyaWJlci5zdWJzY3JpYmVyID09IHN1YnNjci5zdWJzY3JpYmVyXG4gICAgICAgICAgICAgICAgJiYgc3Vic2NyaWJlci5jb250ZXh0ID09IHN1YnNjci5jb250ZXh0XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogU3Vic2NyaWJlcyB0byBtdWx0aXBsZSBtZXNzYWdlcyBwYXNzZWQgYXMgbWFwIHRvZ2V0aGVyIHdpdGggc3Vic2NyaWJlcnMuXG4gKiBVc2FnZTpcbiAqIGBgYFxuICogbXlDb21wLmV2ZW50cy5vbk1lc3NhZ2VzKHtcbiAqICAgICAnbW91c2Vkb3duJzogb25Nb3VzZURvd24sXG4gKiAgICAgJ21vdXNldXAnOiBvbk1vdXNlVXBcbiAqIH0pO1xuICogZnVuY3Rpb24gb25Nb3VzZURvd24oZXZlbnRUeXBlLCBldmVudCkge31cbiAqIGZ1bmN0aW9uIG9uTW91c2VVcChldmVudFR5cGUsIGV2ZW50KSB7fVxuICogYGBgXG4gKiBSZXR1cm5zIG1hcCB3aXRoIHRoZSBzYW1lIGtleXMgKG1lc3NhZ2UgdHlwZXMpIGFuZCBib29sZWFuIHZhbHVlcyBpbmRpY2F0aW5nIHdoZXRoZXIgcGFydGljdWxhciBzdWJzY3JpYmVyIHdhcyBhZGRlZC5cbiAqIEl0IGlzIE5PVCBwb3NzaWJsZSB0byBhZGQgcGF0dGVybiBzdWJzY3JpYmVyIHVzaW5nIHRoaXMgbWV0aG9kLCBhcyBhbHRob3VnaCB5b3UgY2FuIHVzZSBSZWdFeHAgYXMgdGhlIGtleSwgSmF2YVNjcmlwdCB3aWxsIGF1dG9tYXRpY2FsbHkgY29udmVydCBpdCB0byBzdHJpbmcuXG4gKlxuICogQHBhcmFtIHtPYmplY3RbRnVuY3Rpb25dfSBtZXNzYWdlU3Vic2NyaWJlcnMgTWFwIG9mIG1lc3NhZ2Ugc3Vic2NyaWJlcnMgdG8gYmUgYWRkZWRcbiAqIEByZXR1cm4ge09iamVjdFtCb29sZWFuXX1cbiAqL1xuZnVuY3Rpb24gb25NZXNzYWdlcyhtZXNzYWdlU3Vic2NyaWJlcnMpIHtcbiAgICBjaGVjayhtZXNzYWdlU3Vic2NyaWJlcnMsIE1hdGNoLk9iamVjdEhhc2goTWF0Y2guT25lT2YoRnVuY3Rpb24sIHsgc3Vic2NyaWJlcjogRnVuY3Rpb24sIGNvbnRleHQ6IE1hdGNoLkFueSB9KSkpO1xuXG4gICAgdmFyIG5vdFlldFJlZ2lzdGVyZWRNYXAgPSBfLm1hcEtleXMobWVzc2FnZVN1YnNjcmliZXJzLCBmdW5jdGlvbihzdWJzY3JpYmVyLCBtZXNzYWdlcykge1xuICAgICAgICByZXR1cm4gdGhpcy5vbihtZXNzYWdlcywgc3Vic2NyaWJlcik7XG4gICAgfSwgdGhpcyk7XG5cbiAgICByZXR1cm4gbm90WWV0UmVnaXN0ZXJlZE1hcDtcbn1cblxuXG4vKipcbiAqIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2QuXG4gKiBSZW1vdmVzIGEgc3Vic2NyaWJlciBmb3IgbWVzc2FnZShzKS4gUmVtb3ZlcyBhbGwgc3Vic2NyaWJlcnMgZm9yIHRoZSBtZXNzYWdlIGlmIHN1YnNjcmliZXIgaXNuJ3QgcGFzc2VkLlxuICogVGhpcyBtZXRob2QgcmV0dXJucyBgdHJ1ZWAgaWYgdGhlIHN1YnNjcmliZXIgd2FzIHJlZ2lzdGVyZWQuIE5vIGVycm9yIG9yIHdhcm5pbmcgaXMgdGhyb3duIG9yIGxvZ2dlZCBpZiB5b3UgcmVtb3ZlIHN1YnNjcmliZXIgdGhhdCB3YXMgbm90IHJlZ2lzdGVyZWQuXG4gKiBbQ29tcG9uZW50c10oLi4vY29tcG9uZW50cy9jX2NsYXNzLmpzLmh0bWwpIGFuZCBbZmFjZXRzXSguLi9jb21wb25lbnRzL2NfZmFjZXQuanMuaHRtbCkgY2hhbmdlIHRoaXMgbWV0aG9kIG5hbWUgdG8gYG9mZmAgd2hlbiB0aGV5IHByb3h5IGl0LlxuICogVXNhZ2U6XG4gKiBgYGBcbiAqIC8vIHVuc3Vic2NyaWJlcyBvbk1vdXNlVXBEb3duIGZyb20gdHdvIERPTSBldmVudHMuXG4gKiBteUNvbXAuZXZlbnRzLm9mZignbW91c2Vkb3duIG1vdXNldXAnLCBvbk1vdXNlVXBEb3duKTtcbiAqIGBgYFxuICogSWYgbWVzc2VuZ2VyIGhhcyBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBhdHRhY2hlZCB0byBpdCwgTWVzc2FnZVNvdXJjZSB3aWxsIGJlIG5vdGlmaWVkIHdoZW4gdGhlIGxhc3Qgc3Vic2NyaWJlciBmb3IgYSBnaXZlbiBtZXNzYWdlIGlzIHJlbW92ZWQgYW5kIHRoZXJlIGlzIG5vIG1vcmUgc3Vic2NyaWJlcnMgZm9yIHRoaXMgbWVzc2FnZS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ3xBcnJheVtTdHJpbmddfFJlZ0V4cH0gbWVzc2FnZXMgTWVzc2FnZSB0eXBlcyB0aGF0IGEgc3Vic2NyaWJlciBzaG91bGQgYmUgcmVtb3ZlZCBmb3IuXG4gKiAgSWYgc3RyaW5nIGlzIHBhc3NlZCwgaXQgY2FuIGJlIGEgc2lnbGUgbWVzc2FnZSBvciBtdWx0aXBsZSBtZXNzYWdlIHR5cGVzIHNlcGFyYXRlZCBieSB3aGl0ZXNwYWNlIHdpdGggb3B0aW9uYWwgY29tbWFzLlxuICogIElmIGFuIGFycmF5IG9mIHN0cmluZ3MgaXMgcGFzc2VkLCBlYWNoIHN0cmluZyBpcyBhIG1lc3NhZ2UgdHlwZSB0byByZW1vdmUgYSBzdWJzY3JpYmVyIGZvci5cbiAqICBJZiBhIFJlZ0V4cCBpcyBwYXNzZWQsIHRoZSBwYXR0ZXJuIHN1YnNjcmliZXIgd2lsbCBiZSByZW1vdmVkLlxuICogIFJlZ0V4cCBzdWJzY3JpYmVyIGRvZXMgTk9UIGNhdXNlIGFueSBzdWJzY3JpcHRpb24gdG8gTWVzc2FnZVNvdXJjZSwgaXQgb25seSBjYXB0dXJlcyBtZXNzYWdlcyB0aGF0IGFyZSBhbHJlYWR5IHN1YnNjcmliZWQgdG8gd2l0aCBwcmVjaXNlIG1lc3NhZ2UgdHlwZXMuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzdWJzY3JpYmVyIE1lc3NhZ2Ugc3Vic2NyaWJlciAtIE9wdGlvbmFsIGZ1bmN0aW9uIHRoYXQgd2lsbCBiZSByZW1vdmVkIGZyb20gdGhlIGxpc3Qgb2Ygc3Vic2NyaWJlcnMgZm9yIHRoZSBtZXNzYWdlKHMpLiBJZiBzdWJzY3JpYmVyIGlzIG5vdCBzdXBwbGllZCwgYWxsIHN1YnNjcmliZXJzIHdpbGwgYmUgcmVtb3ZlZCBmcm9tIHRoaXMgbWVzc2FnZShzKS5cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIE1lc3NlbmdlciRvZmYobWVzc2FnZXMsIHN1YnNjcmliZXIpIHtcbiAgICBjaGVjayhtZXNzYWdlcywgTWF0Y2guT25lT2YoU3RyaW5nLCBbU3RyaW5nXSwgUmVnRXhwKSk7XG4gICAgY2hlY2soc3Vic2NyaWJlciwgTWF0Y2guT3B0aW9uYWwoTWF0Y2guT25lT2YoRnVuY3Rpb24sIHtcbiAgICAgICAgc3Vic2NyaWJlcjogRnVuY3Rpb24sXG4gICAgICAgIGNvbnRleHQ6IE1hdGNoLkFueSxcbiAgICAgICAgb3B0aW9uczogTWF0Y2guT3B0aW9uYWwoT2JqZWN0KSxcbiAgICAgICAgLy8gX19tZXNzYWdlczogTWF0Y2guT3B0aW9uYWwoTWF0Y2guT25lT2YoU3RyaW5nLCBbU3RyaW5nXSwgUmVnRXhwKSlcbiAgICB9KSkpO1xuXG4gICAgcmV0dXJuIF9NZXNzZW5nZXJfb2ZmLmNhbGwodGhpcywgbWVzc2FnZXMsIHN1YnNjcmliZXIpO1xufVxuXG5cbmZ1bmN0aW9uIF9NZXNzZW5nZXJfb2ZmKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKSB7XG4gICAgcmV0dXJuIF9lYWNoTWVzc2FnZS5jYWxsKHRoaXMsICdfcmVtb3ZlU3Vic2NyaWJlcicsIG1lc3NhZ2VzLCBzdWJzY3JpYmVyKTtcbn1cblxuXG4vKipcbiAqIFwiUHJpdmF0ZVwiIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2RcbiAqIEl0IGlzIGNhbGxlZCBieSBbb2ZmXSgjTWVzc2VuZ2VyJG9mZikgdG8gcmVtb3ZlIHN1YnNjcmliZXIgZm9yIG9uZSBtZXNzYWdlIHR5cGUuXG4gKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGlzIHN1YnNjcmliZXIgd2FzIHJlZ2lzdGVyZWQgZm9yIHRoaXMgdHlwZSBvZiBtZXNzYWdlLlxuICogSWYgbWVzc2VuZ2VyIGhhcyBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBhdHRhY2hlZCB0byBpdCwgTWVzc2FnZVNvdXJjZSB3aWxsIGJlIG5vdGlmaWVkIHdoZW4gdGhlIGxhc3Qgc3Vic2NyaWJlciBmb3IgYSBnaXZlbiBtZXNzYWdlIGlzIHJlbW92ZWQgYW5kIHRoZXJlIGlzIG5vIG1vcmUgc3Vic2NyaWJlcnMgZm9yIHRoaXMgbWVzc2FnZS5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtPYmplY3R9IHN1YnNjcmliZXJzSGFzaCBUaGUgbWFwIG9mIHN1YnNjcmliZXJzIGRldGVybWluZWQgYnkgW29mZl0oI01lc3NlbmdlciRvZmYpIGJhc2VkIG9uIG1lc3NhZ2UgdHlwZSwgY2FuIGJlIGB0aGlzLl9wYXR0ZXJuTWVzc2FnZVN1YnNjcmliZXJzYCBvciBgdGhpcy5fbWVzc2FnZVN1YnNjcmliZXJzYFxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgTWVzc2FnZSB0eXBlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzdWJzY3JpYmVyIFN1YnNjcmliZXIgZnVuY3Rpb24gdG8gYmUgcmVtb3ZlZFxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gX3JlbW92ZVN1YnNjcmliZXIoc3Vic2NyaWJlcnNIYXNoLCBtZXNzYWdlLCBzdWJzY3JpYmVyKSB7XG4gICAgdmFyIG1zZ1N1YnNjcmliZXJzID0gc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdO1xuICAgIGlmICghIG1zZ1N1YnNjcmliZXJzIHx8ICEgbXNnU3Vic2NyaWJlcnMubGVuZ3RoKVxuICAgICAgICByZXR1cm4gZmFsc2U7IC8vIG5vdGhpbmcgcmVtb3ZlZFxuXG4gICAgaWYgKHN1YnNjcmliZXIpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBzdWJzY3JpYmVyID09ICdmdW5jdGlvbicpXG4gICAgICAgICAgICBzdWJzY3JpYmVyID0geyBzdWJzY3JpYmVyOiBzdWJzY3JpYmVyLCBjb250ZXh0OiB0aGlzLl9ob3N0T2JqZWN0IH07XG5cbiAgICAgICAgdmFyIHN1YnNjcmliZXJJbmRleCA9IF9pbmRleE9mU3Vic2NyaWJlci5jYWxsKHRoaXMsIG1zZ1N1YnNjcmliZXJzLCBzdWJzY3JpYmVyKTtcbiAgICAgICAgaWYgKHN1YnNjcmliZXJJbmRleCA9PSAtMSlcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTsgLy8gbm90aGluZyByZW1vdmVkXG4gICAgICAgIG1zZ1N1YnNjcmliZXJzLnNwbGljZShzdWJzY3JpYmVySW5kZXgsIDEpO1xuICAgICAgICBpZiAoISBtc2dTdWJzY3JpYmVycy5sZW5ndGgpXG4gICAgICAgICAgICB0aGlzLl9yZW1vdmVBbGxTdWJzY3JpYmVycyhzdWJzY3JpYmVyc0hhc2gsIG1lc3NhZ2UpO1xuXG4gICAgfSBlbHNlXG4gICAgICAgIHRoaXMuX3JlbW92ZUFsbFN1YnNjcmliZXJzKHN1YnNjcmliZXJzSGFzaCwgbWVzc2FnZSk7XG5cbiAgICByZXR1cm4gdHJ1ZTsgLy8gc3Vic2NyaWJlcihzKSByZW1vdmVkXG59XG5cblxuLyoqXG4gKiBcIlByaXZhdGVcIiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kXG4gKiBJdCBpcyBjYWxsZWQgYnkgW19yZW1vdmVTdWJzY3JpYmVyXSgjX3JlbW92ZVN1YnNjcmliZXIpIHRvIHJlbW92ZSBhbGwgc3Vic2NyaWJlcnMgZm9yIG9uZSBtZXNzYWdlIHR5cGUuXG4gKiBJZiBtZXNzZW5nZXIgaGFzIFtNZXNzYWdlU291cmNlXSguL21fc291cmNlLmpzLmh0bWwpIGF0dGFjaGVkIHRvIGl0LCBNZXNzYWdlU291cmNlIHdpbGwgYmUgbm90aWZpZWQgdGhhdCBhbGwgbWVzc2FnZSBzdWJzY3JpYmVycyB3ZXJlIHJlbW92ZWQgc28gaXQgY2FuIHVuc3Vic2NyaWJlIGZyb20gdGhlIHNvdXJjZS5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIHtPYmplY3R9IHN1YnNjcmliZXJzSGFzaCBUaGUgbWFwIG9mIHN1YnNjcmliZXJzIGRldGVybWluZWQgYnkgW29mZl0oI01lc3NlbmdlciRvZmYpIGJhc2VkIG9uIG1lc3NhZ2UgdHlwZSwgY2FuIGJlIGB0aGlzLl9wYXR0ZXJuTWVzc2FnZVN1YnNjcmliZXJzYCBvciBgdGhpcy5fbWVzc2FnZVN1YnNjcmliZXJzYFxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgTWVzc2FnZSB0eXBlXG4gKi9cbmZ1bmN0aW9uIF9yZW1vdmVBbGxTdWJzY3JpYmVycyhzdWJzY3JpYmVyc0hhc2gsIG1lc3NhZ2UpIHtcbiAgICBkZWxldGUgc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdO1xuICAgIGlmICh0aGlzLl9tZXNzYWdlU291cmNlICYmIHR5cGVvZiBtZXNzYWdlID09ICdzdHJpbmcnKVxuICAgICAgICB0aGlzLl9tZXNzYWdlU291cmNlLm9uU3Vic2NyaWJlclJlbW92ZWQobWVzc2FnZSk7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXIgaW5zdGFuY2UgbWV0aG9kLlxuICogVW5zdWJzY3JpYmVzIGZyb20gbXVsdGlwbGUgbWVzc2FnZXMgcGFzc2VkIGFzIG1hcCB0b2dldGhlciB3aXRoIHN1YnNjcmliZXJzLlxuICogUmV0dXJucyBtYXAgd2l0aCB0aGUgc2FtZSBrZXlzIChtZXNzYWdlIHR5cGVzKSBhbmQgYm9vbGVhbiB2YWx1ZXMgaW5kaWNhdGluZyB3aGV0aGVyIHBhcnRpY3VsYXIgc3Vic2NyaWJlciB3YXMgcmVtb3ZlZC5cbiAqIElmIGEgc3Vic2NyaWJlciBmb3Igb25lIG9mIHRoZSBtZXNzYWdlcyBpcyBub3Qgc3VwcGxpZWQsIGFsbCBzdWJzY3JpYmVycyBmb3IgdGhpcyBtZXNzYWdlIHdpbGwgYmUgcmVtb3ZlZC5cbiAqIFVzYWdlOlxuICogYGBgXG4gKiBteUNvbXAuZXZlbnRzLm9mZk1lc3NhZ2VzKHtcbiAqICAgICAnbW91c2Vkb3duJzogb25Nb3VzZURvd24sXG4gKiAgICAgJ21vdXNldXAnOiBvbk1vdXNlVXAsXG4gKiAgICAgJ2NsaWNrJzogdW5kZWZpbmVkIC8vIGFsbCBzdWJzY3JpYmVycyB0byB0aGlzIG1lc3NhZ2Ugd2lsbCBiZSByZW1vdmVkXG4gKiB9KTtcbiAqIGBgYFxuICogSXQgaXMgTk9UIHBvc3NpYmxlIHRvIHJlbW92ZSBwYXR0ZXJuIHN1YnNjcmliZXIocykgdXNpbmcgdGhpcyBtZXRob2QsIGFzIGFsdGhvdWdoIHlvdSBjYW4gdXNlIFJlZ0V4cCBhcyB0aGUga2V5LCBKYXZhU2NyaXB0IHdpbGwgYXV0b21hdGljYWxseSBjb252ZXJ0IGl0IHRvIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdFtGdW5jdGlvbl19IG1lc3NhZ2VTdWJzY3JpYmVycyBNYXAgb2YgbWVzc2FnZSBzdWJzY3JpYmVycyB0byBiZSByZW1vdmVkXG4gKiBAcmV0dXJuIHtPYmplY3RbQm9vbGVhbl19XG4gKi9cbmZ1bmN0aW9uIG9mZk1lc3NhZ2VzKG1lc3NhZ2VTdWJzY3JpYmVycykge1xuICAgIGNoZWNrKG1lc3NhZ2VTdWJzY3JpYmVycywgTWF0Y2guT2JqZWN0SGFzaChNYXRjaC5PcHRpb25hbChNYXRjaC5PbmVPZihGdW5jdGlvbiwgeyBzdWJzY3JpYmVyOiBGdW5jdGlvbiwgY29udGV4dDogTWF0Y2guQW55IH0pKSkpO1xuXG4gICAgdmFyIHN1YnNjcmliZXJSZW1vdmVkTWFwID0gXy5tYXBLZXlzKG1lc3NhZ2VTdWJzY3JpYmVycywgZnVuY3Rpb24oc3Vic2NyaWJlciwgbWVzc2FnZXMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub2ZmKG1lc3NhZ2VzLCBzdWJzY3JpYmVyKTtcbiAgICB9LCB0aGlzKTtcblxuICAgIHJldHVybiBzdWJzY3JpYmVyUmVtb3ZlZE1hcDtcbn1cblxuXG4vKipcbiAqIFVuc3Vic2NyaWJlcyBhbGwgc3Vic2NyaWJlcnNcbiAqL1xuZnVuY3Rpb24gTWVzc2VuZ2VyJG9mZkFsbCgpIHtcbiAgICBfb2ZmQWxsU3Vic2NyaWJlcnMuY2FsbCh0aGlzLCB0aGlzLl9wYXR0ZXJuTWVzc2FnZVN1YnNjcmliZXJzKTtcbiAgICBfb2ZmQWxsU3Vic2NyaWJlcnMuY2FsbCh0aGlzLCB0aGlzLl9tZXNzYWdlU3Vic2NyaWJlcnMpO1xufVxuXG5cbmZ1bmN0aW9uIF9vZmZBbGxTdWJzY3JpYmVycyhzdWJzY3JpYmVyc0hhc2gpIHtcbiAgICBfLmVhY2hLZXkoc3Vic2NyaWJlcnNIYXNoLCBmdW5jdGlvbihzdWJzY3JpYmVycywgbWVzc2FnZSkge1xuICAgICAgICB0aGlzLl9yZW1vdmVBbGxTdWJzY3JpYmVycyhzdWJzY3JpYmVyc0hhc2gsIG1lc3NhZ2UpO1xuICAgIH0sIHRoaXMpO1xufVxuXG5cbi8vIFRPRE8gLSBzZW5kIGV2ZW50IHRvIG1lc3NhZ2VTb3VyY2VcblxuXG4vKipcbiAqIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2QuXG4gKiBEaXNwYXRjaGVzIHRoZSBtZXNzYWdlIGNhbGxpbmcgYWxsIHN1YnNjcmliZXJzIHJlZ2lzdGVyZWQgZm9yIHRoaXMgbWVzc2FnZSBhbmQsIGlmIHRoZSBtZXNzYWdlIGlzIGEgc3RyaW5nLCBjYWxsaW5nIGFsbCBwYXR0ZXJuIHN1YnNjcmliZXJzIHdoZW4gbWVzc2FnZSBtYXRjaGVzIHRoZSBwYXR0ZXJuLlxuICogRWFjaCBzdWJzY3JpYmVyIGlzIHBhc3NlZCB0aGUgc2FtZSBwYXJhbWV0ZXJzIHRoYXQgYXJlIHBhc3NlZCB0byB0aGVpcyBtZXRob2QuXG4gKiBUaGUgY29udGV4dCBvZiB0aGUgc3Vic2NyaWJlciBlbnZvY2F0aW9uIGlzIHNldCB0byB0aGUgaG9zdCBvYmplY3QgKGB0aGlzLl9ob3N0T2JqZWN0YCkgdGhhdCB3YXMgcGFzc2VkIHRvIHRoZSBtZXNzZW5nZXIgY29uc3RydWN0b3IuXG4gKiBTdWJzY3JpYmVycyBhcmUgY2FsbGVkIGluIHRoZSBuZXh0IHRpY2sgKFwiYXN5bmNocm9ub3VzbHlcIikgYXBhcnQgZnJvbSB0aG9zZSB0aGF0IHdlcmUgc3Vic2NyaWJlZCB3aXRoIGBvblN5bmNgIChvciB0aGF0IGhhdmUgYG9wdGlvbnMuc3luYyA9PSB0cnVlYCkuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBtZXNzYWdlIG1lc3NhZ2UgdG8gYmUgZGlzcGF0Y2hlZFxuICogIElmIHRoZSBtZXNzYWdlIGlzIGEgc3RyaW5nLCB0aGUgc3Vic2NyaWJlcnMgcmVnaXN0ZXJlZCB3aXRoIGV4YWN0bHkgdGhpcyBtZXNzYWdlIHdpbGwgYmUgY2FsbGVkIGFuZCBhbHNvIHBhdHRlcm4gc3Vic2NyaWJlcnMgcmVnaXN0ZXJlZCB3aXRoIHRoZSBwYXR0ZXJuIHRoYXQgbWF0Y2hlcyB0aGUgZGlzcGF0Y2hlZCBtZXNzYWdlLlxuICogIElmIHRoZSBtZXNzYWdlIGlzIFJlZ0V4cCwgb25seSB0aGUgc3Vic2NyaWJlcnMgcmVnaXN0ZXJlZCB3aXRoIGV4YWN0bHkgdGhpcyBwYXR0ZXJuIHdpbGwgYmUgY2FsbGVkLlxuICogQHBhcmFtIHtBbnl9IGRhdGEgZGF0YSB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBzdWJzY3JpYmVyIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyLiBNZXNzZW5nZXIgZG9lcyBub3QgbW9kaWZ5IHRoaXMgZGF0YSBpbiBhbnkgd2F5LlxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgb3B0aW9uYWwgY2FsbGJhY2sgdG8gcGFzcyB0byBzdWJzY3JpYmVyXG4gKiBAcGFyYW0ge0Jvb2xlYW59IF9zeW5jaHJvbm91cyBpZiB0cnVlIHBhc3NlZCwgc3Vic2NyaWJlcnMgd2lsbCBiZSBlbnZva2VkIHN5bmNocm9ub3VzbHkgYXBhcnQgZnJvbSB0aG9zZSB0aGF0IGhhdmUgYG9wdGlvbnMuc3luYyA9PSBmYWxzZWAuIFRoaXMgcGFyYW1ldGVyIHNob3VsZCBub3QgYmUgdXNlZCwgaW5zdGVhZCBwb3N0TWVzc2FnZVN5bmMgc2hvdWxkIGJlIHVzZWQuXG4gKi9cbmZ1bmN0aW9uIHBvc3RNZXNzYWdlKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCBfc3luY2hyb25vdXMpIHtcbiAgICBjaGVjayhtZXNzYWdlLCBNYXRjaC5PbmVPZihTdHJpbmcsIFJlZ0V4cCkpO1xuICAgIGNoZWNrKGNhbGxiYWNrLCBNYXRjaC5PcHRpb25hbChGdW5jdGlvbikpO1xuXG4gICAgdmFyIHN1YnNjcmliZXJzSGFzaCA9IHRoaXMuX2Nob29zZVN1YnNjcmliZXJzSGFzaChtZXNzYWdlKTtcbiAgICB2YXIgbXNnU3Vic2NyaWJlcnMgPSBzdWJzY3JpYmVyc0hhc2hbbWVzc2FnZV07XG5cbiAgICB0aGlzLl9jYWxsU3Vic2NyaWJlcnMobWVzc2FnZSwgZGF0YSwgY2FsbGJhY2ssIG1zZ1N1YnNjcmliZXJzLCBfc3luY2hyb25vdXMpO1xuXG4gICAgaWYgKHR5cGVvZiBtZXNzYWdlID09ICdzdHJpbmcnKVxuICAgICAgICB0aGlzLl9jYWxsUGF0dGVyblN1YnNjcmliZXJzKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCBtc2dTdWJzY3JpYmVycywgX3N5bmNocm9ub3VzKTtcbn1cblxuXG4vKipcbiAqIFNhbWUgYXMgcG9zdE1lc3NhZ2UgYXBhcnQgZnJvbSBlbnZva2luZyBzdWJzY3JpYmVycyBzeW5jaHJvbm91c2x5LCBhcGFydCBmcm9tIHRob3NlIHN1YnNjcmliZWQgd2l0aCBgb25Bc3luY2AgKG9yIHdpdGggYG9wdGlvbnMuc3luYyA9PSBmYWxzZWApLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gbWVzc2FnZVxuICogQHBhcmFtIHtBbnl9IGRhdGFcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gKi9cbmZ1bmN0aW9uIHBvc3RNZXNzYWdlU3luYyhtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaykge1xuICAgIHRoaXMucG9zdE1lc3NhZ2UobWVzc2FnZSwgZGF0YSwgY2FsbGJhY2ssIHRydWUpO1xufVxuXG5cbi8qKlxuICogXCJQcml2YXRlXCIgTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZFxuICogRW52b2tlcyBwYXR0ZXJuIHN1YnNjcmliZXJzIHdpdGggdGhlIHBhdHRlcm4gdGhhdCBtYXRjaGVzIHRoZSBtZXNzYWdlLlxuICogVGhlIG1ldGhvZCBpcyBjYWxsZWQgYnkgW3Bvc3RNZXNzYWdlXSgjcG9zdE1lc3NhZ2UpIC0gc2VlIG1vcmUgaW5mb3JtYXRpb24gdGhlcmUuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIG1lc3NhZ2UgdG8gYmUgZGlzcGF0Y2hlZC4gUGF0dGVybiBzdWJzY3JpYmVycyByZWdpc3RlcmVkIHdpdGggdGhlIHBhdHRlcm4gdGhhdCBtYXRjaGVzIHRoZSBkaXNwYXRjaGVkIG1lc3NhZ2Ugd2lsbCBiZSBjYWxsZWQuXG4gKiBAcGFyYW0ge0FueX0gZGF0YSBkYXRhIHRoYXQgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIHN1YnNjcmliZXIgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXIuIE1lc3NlbmdlciBkb2VzIG5vdCBtb2RpZnkgdGhpcyBkYXRhIGluIGFueSB3YXkuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBvcHRpb25hbCBjYWxsYmFjayB0byBwYXNzIHRvIHN1YnNjcmliZXJcbiAqIEBwYXJhbSB7QXJyYXlbRnVuY3Rpb258T2JqZWN0XX0gY2FsbGVkTXNnU3Vic2NyaWJlcnMgYXJyYXkgb2Ygc3Vic2NyaWJlcnMgYWxyZWFkeSBjYWxsZWQsIHRoZXkgd29uJ3QgYmUgY2FsbGVkIGFnYWluIGlmIHRoZXkgYXJlIGFtb25nIHBhdHRlcm4gc3Vic2NyaWJlcnMuXG4gKi9cbmZ1bmN0aW9uIF9jYWxsUGF0dGVyblN1YnNjcmliZXJzKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCBjYWxsZWRNc2dTdWJzY3JpYmVycywgX3N5bmNocm9ub3VzKSB7XG4gICAgXy5lYWNoS2V5KHRoaXMuX3BhdHRlcm5NZXNzYWdlU3Vic2NyaWJlcnMsXG4gICAgICAgIGZ1bmN0aW9uKHBhdHRlcm5TdWJzY3JpYmVycykge1xuICAgICAgICAgICAgdmFyIHBhdHRlcm4gPSBwYXR0ZXJuU3Vic2NyaWJlcnMucGF0dGVybjtcbiAgICAgICAgICAgIGlmIChwYXR0ZXJuLnRlc3QobWVzc2FnZSkpIHtcbiAgICAgICAgICAgICAgICBpZiAoY2FsbGVkTXNnU3Vic2NyaWJlcnMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhdHRlcm5TdWJzY3JpYmVycyA9IHBhdHRlcm5TdWJzY3JpYmVycy5maWx0ZXIoZnVuY3Rpb24oc3Vic2NyaWJlcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGluZGV4ID0gX2luZGV4T2ZTdWJzY3JpYmVyLmNhbGwodGhpcywgY2FsbGVkTXNnU3Vic2NyaWJlcnMsIHN1YnNjcmliZXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGluZGV4ID09IC0xO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5fY2FsbFN1YnNjcmliZXJzKG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrLCBwYXR0ZXJuU3Vic2NyaWJlcnMsIF9zeW5jaHJvbm91cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAsIHRoaXMpO1xufVxuXG5cbi8qKlxuICogXCJQcml2YXRlXCIgTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZFxuICogRW52b2tlcyBzdWJzY3JpYmVycyBmcm9tIHRoZSBwYXNzZWQgbGlzdC5cbiAqIFRoZSBtZXRob2QgaXMgY2FsbGVkIGJ5IFtwb3N0TWVzc2FnZV0oI3Bvc3RNZXNzYWdlKSBhbmQgW19jYWxsUGF0dGVyblN1YnNjcmliZXJzXSgjX2NhbGxQYXR0ZXJuU3Vic2NyaWJlcnMpLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBtZXNzYWdlIHRvIGJlIGRpc3BhdGNoZWQsIHBhc3NlZCB0byBzdWJzY3JpYmVycyBhcyB0aGUgZmlyc3QgcGFyYW1ldGVyLlxuICogQHBhcmFtIHtBbnl9IGRhdGEgZGF0YSB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBzdWJzY3JpYmVyIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyLiBNZXNzZW5nZXIgZG9lcyBub3QgbW9kaWZ5IHRoaXMgZGF0YSBpbiBhbnkgd2F5LlxuICogQHBhcmFtIHtBcnJheVtGdW5jdGlvbnxPYmplY3RdfSBtc2dTdWJzY3JpYmVycyB0aGUgYXJyYXkgb2YgbWVzc2FnZSBzdWJzY3JpYmVycyB0byBiZSBjYWxsZWQuIEVhY2ggc3Vic2NyaWJlciBpcyBjYWxsZWQgd2l0aCB0aGUgaG9zdCBvYmplY3QgKHNlZSBNZXNzZW5nZXIgY29uc3RydWN0b3IpIGFzIHRoZSBjb250ZXh0LlxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgb3B0aW9uYWwgY2FsbGJhY2sgdG8gcGFzcyB0byBzdWJzY3JpYmVyXG4gKi9cbmZ1bmN0aW9uIF9jYWxsU3Vic2NyaWJlcnMobWVzc2FnZSwgZGF0YSwgY2FsbGJhY2ssIG1zZ1N1YnNjcmliZXJzLCBfc3luY2hyb25vdXMpIHtcbiAgICBpZiAobXNnU3Vic2NyaWJlcnMgJiYgbXNnU3Vic2NyaWJlcnMubGVuZ3RoKSB7XG4gICAgICAgIC8vIGNsb25pbmcgaXMgbmVjZXNzYXJ5IGFzIHNvbWUgb2YgdGhlIHN1YnNjcmliZXJzXG4gICAgICAgIC8vIGNhbiBiZSB1bnN1YnNjcmliZWQgZHVyaW5nIHRoZSBkaXNwYXRjaFxuICAgICAgICAvLyBzbyB0aGlzIGFycmF5IHdvdWxkIGNoYW5nZSBpbiB0aGUgcHJvY2Vzc1xuICAgICAgICBtc2dTdWJzY3JpYmVycyA9IG1zZ1N1YnNjcmliZXJzLnNsaWNlKCk7XG5cbiAgICAgICAgbXNnU3Vic2NyaWJlcnMuZm9yRWFjaChmdW5jdGlvbihzdWJzY3JpYmVyKSB7XG4gICAgICAgICAgICB0aGlzLl9jYWxsU3Vic2NyaWJlcihzdWJzY3JpYmVyLCBtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaywgX3N5bmNocm9ub3VzKTtcbiAgICAgICAgfSwgdGhpcyk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIF9jYWxsU3Vic2NyaWJlcihzdWJzY3JpYmVyLCBtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaywgX3N5bmNocm9ub3VzKSB7XG4gICAgdmFyIHN5bmNTdWJzY3JpYmVyID0gc3Vic2NyaWJlci5vcHRpb25zICYmIHN1YnNjcmliZXIub3B0aW9ucy5zeW5jXG4gICAgICAgICwgc3luY2hybyA9IChfc3luY2hyb25vdXMgJiYgc3luY1N1YnNjcmliZXIgIT09IGZhbHNlKVxuICAgICAgICAgICAgICAgICAgfHwgc3luY1N1YnNjcmliZXI7XG5cbiAgICB2YXIgZGlzcGF0Y2hUaW1lcyA9IHN1YnNjcmliZXIub3B0aW9ucyAmJiBzdWJzY3JpYmVyLm9wdGlvbnMuZGlzcGF0Y2hUaW1lcztcbiAgICBpZiAoZGlzcGF0Y2hUaW1lcykge1xuICAgICAgICBpZiAoZGlzcGF0Y2hUaW1lcyA8PSAxKSB7XG4gICAgICAgICAgICB2YXIgbWVzc2FnZXMgPSBzdWJzY3JpYmVyLl9fbWVzc2FnZXM7XG4gICAgICAgICAgICB0aGlzLm9mZihtZXNzYWdlcywgc3Vic2NyaWJlcik7XG4gICAgICAgIH0gZWxzZSBpZiAoZGlzcGF0Y2hUaW1lcyA+IDEpXG4gICAgICAgICAgICBzdWJzY3JpYmVyLm9wdGlvbnMuZGlzcGF0Y2hUaW1lcy0tO1xuICAgIH1cblxuICAgIGlmIChzeW5jaHJvKVxuICAgICAgICBzdWJzY3JpYmVyLnN1YnNjcmliZXIuY2FsbChzdWJzY3JpYmVyLmNvbnRleHQsIG1lc3NhZ2UsIGRhdGEsIGNhbGxiYWNrKTtcbiAgICBlbHNlXG4gICAgICAgIF8uZGVmZXJNZXRob2Qoc3Vic2NyaWJlci5zdWJzY3JpYmVyLCAnY2FsbCcsIHN1YnNjcmliZXIuY29udGV4dCwgbWVzc2FnZSwgZGF0YSwgY2FsbGJhY2spO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZC5cbiAqIFJldHVybnMgdGhlIGFycmF5IG9mIHN1YnNjcmliZXJzIHRoYXQgd291bGQgYmUgY2FsbGVkIGlmIHRoZSBtZXNzYWdlIHdlcmUgZGlzcGF0Y2hlZC5cbiAqIElmIGBpbmNsdWRlUGF0dGVyblN1YnNjcmliZXJzID09PSBmYWxzZWAsIHBhdHRlcm4gc3Vic2NyaWJlcnMgd2l0aCBtYXRjaGluZyBwYXR0ZXJzIHdpbGwgbm90IGJlIGluY2x1ZGVkIChieSBkZWZhdWx0IHRoZXkgYXJlIGluY2x1ZGVkKS5cbiAqIElmIHRoZXJlIGFyZSBubyBzdWJzY3JpYmVycyB0byB0aGUgbWVzc2FnZSwgYHVuZGVmaW5lZGAgd2lsbCBiZSByZXR1cm5lZCwgbm90IGFuIGVtcHR5IGFycmF5LCBzbyBpdCBpcyBzYWZlIHRvIHVzZSB0aGUgcmVzdWx0IGluIGJvb2xlYW4gdGVzdHMuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBtZXNzYWdlIE1lc3NhZ2UgdG8gZ2V0IHN1YnNjcmliZXJzIGZvci5cbiAqICBJZiB0aGUgbWVzc2FnZSBpcyBSZWdFeHAsIG9ubHkgcGF0dGVybiBzdWJzY3JpYmVycyByZWdpc3RlcmVkIHdpdGggZXhhY3RseSB0aGlzIHBhdHRlcm4gd2lsbCBiZSByZXR1cm5lZC5cbiAqICBJZiB0aGUgbWVzc2FnZSBpcyBTdHJpbmcsIHN1YnNjcmliZXJzIHJlZ2lzdGVyZWQgd2l0aCB0aGUgc3RyaW5nIG1lc3NhZ2VzIGFuZCBwYXR0ZXJuIHN1YnNjcmliZXJzIHJlZ2lzdGVyZWQgd2l0aCBtYXRjaGluZyBwYXR0ZXJuIHdpbGwgYmUgcmV0dXJuZWQgKHVubGVzcyB0aGUgc2Vjb25kIHBhcmFtZXRlciBpcyBmYWxzZSkuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGluY2x1ZGVQYXR0ZXJuU3Vic2NyaWJlcnMgT3B0aW9uYWwgZmFsc2UgdG8gcHJldmVudCBpbmNsdXNpb24gb2YgcGF0dGVyIHN1YnNjcmliZXJzLCBieSBkZWZhdWx0IHRoZXkgYXJlIGluY2x1ZGVkLlxuICogQHJldHVybiB7QXJyYXl8dW5kZWZpbmVkfVxuICovXG5mdW5jdGlvbiBnZXRTdWJzY3JpYmVycyhtZXNzYWdlLCBpbmNsdWRlUGF0dGVyblN1YnNjcmliZXJzKSB7XG4gICAgY2hlY2sobWVzc2FnZSwgTWF0Y2guT25lT2YoU3RyaW5nLCBSZWdFeHApKTtcblxuICAgIHZhciBzdWJzY3JpYmVyc0hhc2ggPSB0aGlzLl9jaG9vc2VTdWJzY3JpYmVyc0hhc2gobWVzc2FnZSk7XG4gICAgdmFyIG1zZ1N1YnNjcmliZXJzID0gc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyBbXS5jb25jYXQoc3Vic2NyaWJlcnNIYXNoW21lc3NhZ2VdKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogW107XG5cbiAgICAvLyBwYXR0ZXJuIHN1YnNjcmliZXJzIGFyZSBpbmN1ZGVkIGJ5IGRlZmF1bHRcbiAgICBpZiAoaW5jbHVkZVBhdHRlcm5TdWJzY3JpYmVycyAhPT0gZmFsc2UgJiYgdHlwZW9mIG1lc3NhZ2UgPT0gJ3N0cmluZycpIHtcbiAgICAgICAgXy5lYWNoS2V5KHRoaXMuX3BhdHRlcm5NZXNzYWdlU3Vic2NyaWJlcnMsXG4gICAgICAgICAgICBmdW5jdGlvbihwYXR0ZXJuU3Vic2NyaWJlcnMpIHtcbiAgICAgICAgICAgICAgICB2YXIgcGF0dGVybiA9IHBhdHRlcm5TdWJzY3JpYmVycy5wYXR0ZXJuO1xuICAgICAgICAgICAgICAgIGlmIChwYXR0ZXJuU3Vic2NyaWJlcnMgJiYgcGF0dGVyblN1YnNjcmliZXJzLmxlbmd0aFxuICAgICAgICAgICAgICAgICAgICAgICAgJiYgcGF0dGVybi50ZXN0KG1lc3NhZ2UpKVxuICAgICAgICAgICAgICAgICAgICBfLmFwcGVuZEFycmF5KG1zZ1N1YnNjcmliZXJzLCBwYXR0ZXJuU3Vic2NyaWJlcnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8vIHJldHVybiB1bmRlZmluZWQgaWYgdGhlcmUgYXJlIG5vIHN1YnNjcmliZXJzXG4gICAgcmV0dXJuIG1zZ1N1YnNjcmliZXJzLmxlbmd0aFxuICAgICAgICAgICAgICAgID8gbXNnU3Vic2NyaWJlcnNcbiAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZDtcbn1cblxuXG4vKipcbiAqIFwiUHJpdmF0ZVwiIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2RcbiAqIFJldHVybnMgdGhlIG1hcCBvZiBzdWJzY3JpYmVycyBmb3IgYSBnaXZlbiBtZXNzYWdlIHR5cGUuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gbWVzc2FnZSBNZXNzYWdlIHRvIGNob29zZSB0aGUgbWFwIG9mIHN1YnNjcmliZXJzIGZvclxuICogQHJldHVybiB7T2JqZWN0W0Z1bmN0aW9uXX1cbiAqL1xuZnVuY3Rpb24gX2Nob29zZVN1YnNjcmliZXJzSGFzaChtZXNzYWdlKSB7XG4gICAgcmV0dXJuIG1lc3NhZ2UgaW5zdGFuY2VvZiBSZWdFeHBcbiAgICAgICAgICAgICAgICA/IHRoaXMuX3BhdHRlcm5NZXNzYWdlU3Vic2NyaWJlcnNcbiAgICAgICAgICAgICAgICA6IHRoaXMuX21lc3NhZ2VTdWJzY3JpYmVycztcbn1cblxuXG4vKipcbiAqIE1lc3NlbmdlciBpbnN0YW5jZSBtZXRob2RcbiAqIFNldHMgW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgZm9yIHRoZSBtZXNzZW5nZXIgYWxzbyBzZXR0aW5nIHRoZSByZWZlcmVuY2UgdG8gdGhlIG1lc3NlbmdlciBpbiB0aGUgTWVzc2FnZVNvdXJjZS5cbiAqIE1lc3NhZ2VTb3VyY2UgY2FuIGJlIHBhc3NlZCB0byBtZXNzYWdlIGNvbnN0cnVjdG9yOyB0aGlzIG1ldGhvZCBhbGxvd3MgdG8gc2V0IGl0IGF0IGEgbGF0ZXIgdGltZS4gRm9yIGV4YW1wbGUsIHRoZSBzdWJjbGFzc2VzIG9mIFtDb21wb25lbnRGYWNldF0oLi4vY29tcG9uZW50cy9jX2ZhY2V0LmpzLmh0bWwpIHVzZSB0aGlzIG1ldGhvZCB0byBzZXQgZGlmZmVyZW50IE1lc3NhZ2VTb3VyY2UnZXMgaW4gdGhlIG1lc3NlbmdlciB0aGF0IGlzIGNyZWF0ZWQgYnkgQ29tcG9uZW50RmFjZXQuXG4gKiBDdXJyZW50bHkgdGhlIG1ldGhvZCBpcyBpbXBsZW1lbnRlZCBpbiBzdWNoIHdheSB0aGF0IGl0IGNhbiBiZSBjYWxsZWQgb25seSBvbmNlIC0gTWVzc2FnZVNvdXJjZSBjYW5ub3QgYmUgY2hhbmdlZCBhZnRlciB0aGlzIG1ldGhvZCBpcyBjYWxsZWQuXG4gKlxuICogQHBhcmFtIHtNZXNzYWdlU291cmNlfSBtZXNzYWdlU291cmNlIGFuIGluc3RhbmNlIG9mIE1lc3NhZ2VTb3VyY2UgY2xhc3MgdG8gYXR0YWNoIHRvIHRoaXMgbWVzc2VuZ2VyIChhbmQgdG8gaGF2ZSB0aGlzIG1lc3NlbmdlciBhdHRhY2hlZCB0byBpdCB0b28pXG4gKi9cbmZ1bmN0aW9uIF9zZXRNZXNzYWdlU291cmNlKG1lc3NhZ2VTb3VyY2UpIHtcbiAgICBjaGVjayhtZXNzYWdlU291cmNlLCBNZXNzYWdlU291cmNlKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgJ19tZXNzYWdlU291cmNlJywgbWVzc2FnZVNvdXJjZSk7XG4gICAgbWVzc2FnZVNvdXJjZS5tZXNzZW5nZXIgPSB0aGlzO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyIGluc3RhbmNlIG1ldGhvZFxuICogUmV0dXJucyBtZXNzZW5nZXIgTWVzc2FnZVNvdXJjZVxuICpcbiAqIEByZXR1cm4ge01lc3NhZ2VTb3VyY2V9XG4gKi9cbmZ1bmN0aW9uIGdldE1lc3NhZ2VTb3VyY2UoKSB7XG4gICAgcmV0dXJuIHRoaXMuX21lc3NhZ2VTb3VyY2Vcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vdXRpbC9sb2dnZXInKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1lc3NlbmdlckFQSTtcblxuXG4vKipcbiAqIGBtaWxvLmNsYXNzZXMuTWVzc2VuZ2VyQVBJYFxuICogQmFzZSBjbGFzcywgc3ViY2xhc3NlcyBvZiB3aGljaCBjYW4gc3VwcGxlbWVudCB0aGUgZnVuY3Rpb25hbGl0eSBvZiBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBieSBpbXBsZW1lbnRpbmcgdGhyZWUgbWV0aG9kczpcbiAqXG4gKiAtIGB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2VgIHRvIHRyYW5zbGF0ZSBzb3VyY2UgbWVzc2FnZXMgKHJlY2lldmVkIGZyb20gZXh0ZXJuYWwgc291cmNlIHZpYSBgTWVzc2FnZVNPdXJjZWApIHRvIGludGVybmFsIG1lc3NhZ2VzICh0aGF0IGFyZSBkaXNwYXRjaGVkIG9uIE1lc3NlbmdlciksIGFsbG93aW5nIHRvIG1ha2UgaW50ZXJuYWwgbWVzc2FnZXMgbW9yZSBkZXRhaWxlZCB0aGFuIHNvdXJjZSBtZXNzYWdlcy4gRm9yIGV4YW1wbGUsIFtEYXRhIGZhY2V0XSguLi9jb21wb25lbnRzL2NfZmFjZXRzL0RhdGEuanMuaHRtbCkgdXNlcyBbRGF0YU1zZ0FQSV0oLi4vY29tcG9uZW50cy9tc2dfYXBpL2RhdGEuanMuaHRtbCkgdG8gZGVmaW5lIHNldmVyYWwgaW50ZXJuYWwgbWVzc2FnZXMgcmVsYXRlZCB0byB0aGUgY2hhbmdlIG9mIHN0YXRlIGluIGNvbnRlbnRlZGl0YWJsZSBET00gZWxlbWVudC5cbiAqIC0gYGNyZWF0ZUludGVybmFsRGF0YWAgdG8gbW9kaWZ5IG1lc3NhZ2UgZGF0YSByZWNlaXZlZCBmcm9tIHNvdXJjZSB0byBzb21lIG1vcmUgbWVhbmluZ2Z1bCBvciBtb3JlIGRldGFpbGVkIG1lc3NhZ2UgZGF0YSB0aGF0IHdpbGwgYmUgZGlzcGF0Y2hlZCBvbiBNZXNzZW5nZXIuIEZvciBleGFtcGxlLCBbRGF0YSBmYWNldF0oLi4vY29tcG9uZW50cy9jX2ZhY2V0cy9EYXRhLmpzLmh0bWwpIHVzZXMgW0RhdGFNc2dBUEldKC4uL2NvbXBvbmVudHMvbXNnX2FwaS9kYXRhLmpzLmh0bWwpIChzdWJjbGFzcyBvZiBNZXNzZW5nZXJBUEkpIHRvIHRyYW5zbGF0ZSBET00gbWVzc2FnZXMgdG8gZGF0YSBjaGFuZ2UgbWVzc2FnZXMuXG4gKiAtIGBmaWx0ZXJTb3VyY2VNZXNzYWdlYCB0byBlbmFibGUvZGlzYWJsZSBtZXNzYWdlIGRpc3BhdGNoIGJhc2VkIG9uIHNvbWUgY29uZGl0aW9ucyBpbiBkYXRhLlxuICpcbiAqIElmIGBNZXNzYWdlU291cmNlYCBjb25zdHJ1Y3RvciBpcyBub3QgcGFzc2VkIGFuIGluc3RhbmNlIG9mIHNvbWUgc3ViY2xhc3Mgb2YgYE1lc3NlbmdlckFQSWAsIGl0IGF1dG9tYXRpY2FsbHkgY3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBNZXNzZW5nZXJBUEkgdGhhdCBkZWZpbmVzIGFsbCAzIG9mIHRob3NlIG1ldGhvZHMgaW4gYSB0cml2aWFsIHdheS4gU2VlIHRoZXNlIG1ldGhvZHMgYmVsb3cgZm9yIHRoZWlyIHNpZ25hdHVyZXMuXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAdGhpcyB7TWVzc2VuZ2VyQVBJfVxuICogQHJldHVybiB7TWVzc2VuZ2VyQVBJfVxuICovXG5mdW5jdGlvbiBNZXNzZW5nZXJBUEkoKSB7XG4gICAgaWYgKHRoaXMuaW5pdClcbiAgICAgICAgdGhpcy5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59XG5cblxuLyoqXG4gKiAjIyMjTWVzc2VuZ2VyQVBJIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbaW5pdF0oI2luaXQpIC0gaW5pdGlhbGl6ZXMgTWVzc2VuZ2VyQVBJXG4gKiAtIFthZGRJbnRlcm5hbE1lc3NhZ2VdKCNhZGRJbnRlcm5hbE1lc3NhZ2UpIC0gYWRkcyBpbnRlcm5hbCBtZXNzYWdlXG4gKiAtIFtyZW1vdmVJbnRlcm5hbE1lc3NhZ2VdKCNyZW1vdmVJbnRlcm5hbE1lc3NhZ2UpIC0gcmVtb3ZlcyBpbnRlcm5hbCBtZXNzYWdlXG4gKiAtIFtnZXRJbnRlcm5hbE1lc3NhZ2VzXSgjZ2V0SW50ZXJuYWxNZXNzYWdlcykgLSByZXR1cm5zIHRoZSBsaXN0IG9mIGludGVybmFsIG1lc3NhZ2VzIGZvciBnaXZlbiBzb3VyY2UgbWVzc2FnZVxuICpcbiAqIFRoZXNlIG1ldGhvZHMgc2hvdWxkIGJlIHJlZGVmaW5lZCBieSBzdWJjbGFzczpcbiAqXG4gKiAtIFt0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2VdKCN0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UpIC0gY29udmVydHMgaW50ZXJuYWwgbWVzc2FnZSB0eXBlIHRvIHNvdXJjZSAoZXh0ZXJuYWwpIG1lc3NhZ2UgdHlwZVxuICogLSBbY3JlYXRlSW50ZXJuYWxEYXRhXSgjY3JlYXRlSW50ZXJuYWxEYXRhKSAtIGNvbnZlcnRzIHNvdXJjZSBtZXNzYWdlIGRhdGEgcmVjZWl2ZWQgdmlhIE1lc3NhZ2VTb3VyY2UgdG8gaW50ZXJuYWwgbWVzc2FnZSBkYXRhXG4gKiAtIFtmaWx0ZXJTb3VyY2VNZXNzYWdlXSgjZmlsdGVyU291cmNlTWVzc2FnZSkgLSBmaWx0ZXJzIHNvdXJjZSBtZXNzYWdlIGJhc2VkIG9uIHRoZSBkYXRhIG9mIHRoZSBtZXNzYWdlIGFuZCB0aGUgY29ycmVzcG9uZGluZyBpbnRlcm5hbCBtZXNzYWdlIHRoYXQgaXMgYWJvdXQgdG8gYmUgc2VudCBvbiBNZXNzZW5nZXJcbiAqL1xuXy5leHRlbmRQcm90byhNZXNzZW5nZXJBUEksIHtcbiAgICBpbml0OiBpbml0LFxuICAgIGRlc3Ryb3k6IE1lc3NlbmdlckFQSSRkZXN0cm95LFxuICAgIGFkZEludGVybmFsTWVzc2FnZTogYWRkSW50ZXJuYWxNZXNzYWdlLFxuICAgIHJlbW92ZUludGVybmFsTWVzc2FnZTogcmVtb3ZlSW50ZXJuYWxNZXNzYWdlLFxuICAgIGdldEludGVybmFsTWVzc2FnZXM6IGdldEludGVybmFsTWVzc2FnZXMsXG5cbiAgICAvLyBzaG91bGQgYmUgcmVkZWZpbmVkIGJ5IHN1YmNsYXNzXG4gICAgdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlOiB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UsXG4gICAgY3JlYXRlSW50ZXJuYWxEYXRhOiBjcmVhdGVJbnRlcm5hbERhdGEsXG4gICAgZmlsdGVyU291cmNlTWVzc2FnZTogZmlsdGVyU291cmNlTWVzc2FnZVxufSk7XG5cblxuLyoqXG4gKiBNZXNzZW5nZXJBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBDYWxsZWQgYnkgTWVzc2VuZ2VyQVBJIGNvbnN0cnVjdG9yLiBTdWJjbGFzc2VzIHRoYXQgcmUtaW1wbGVtZW50IGBpbml0YCBtZXRob2Qgc2hvdWxkIGNhbGwgdGhpcyBtZXRob2QgdXNpbmc6IGBNZXNzZW5nZXJBUEkucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKWBcbiAqL1xuZnVuY3Rpb24gaW5pdCgpIHtcbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdfaW50ZXJuYWxNZXNzYWdlcycsIHt9KTtcbn1cblxuXG4vKipcbiAqIERlc3Ryb3lzIG1lc3NlbmdlciBBUElcbiAqL1xuZnVuY3Rpb24gTWVzc2VuZ2VyQVBJJGRlc3Ryb3koKSB7XG5cbn1cblxuXG4vKipcbiAqIE1lc3NlbmdlckFQSSBpbnN0YW5jZSBtZXRob2RcbiAqIFRyYW5zbGF0ZXMgaW50ZXJuYWwgYG1lc3NhZ2VgIHRvIHNvdXJjZSBtZXNzYWdlLCBhZGRzIGludGVybmFsIGBtZXNzYWdlYCB0byB0aGUgbGlzdCwgbWFraW5nIHN1cmUgdGhlIHNhbWUgYG1lc3NhZ2VgIHdhc24ndCBwYXNzZWQgYmVmb3JlIChpdCB3b3VsZCBpbmRpY2F0ZSBNZXNzZW5nZXIgZXJyb3IpLlxuICogUmV0dXJucyBzb3VyY2UgbWVzc2FnZSBpZiBpdCBpcyB1c2VkIGZpcnN0IHRpbWUgKHNvIHRoYXQgYE1lc3NhZ2VTb3VyY2VgIHN1YmNyaWJlcyB0byB0aGlzIHNvdXJjZSBtZXNzYWdlKSBvciBgdW5kZWZpbmVkYC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBpbnRlcm5hbCBtZXNzYWdlIHRvIGJlIHRyYW5zbGF0ZWQgYW5kIGFkZGVkXG4gKiBAcmV0dXJuIHtTdHJpbmd8dW5kZWZpbmVkfVxuICovXG5mdW5jdGlvbiBhZGRJbnRlcm5hbE1lc3NhZ2UobWVzc2FnZSkge1xuICAgIHZhciBpbnRlcm5hbE1zZ3NcbiAgICAgICAgLCBzb3VyY2VNZXNzYWdlID0gdGhpcy50cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UobWVzc2FnZSk7XG5cbiAgICBpZiAodHlwZW9mIHNvdXJjZU1lc3NhZ2UgPT0gJ3VuZGVmaW5lZCcpIHJldHVybjtcblxuICAgIGlmICh0aGlzLl9pbnRlcm5hbE1lc3NhZ2VzLmhhc093blByb3BlcnR5KHNvdXJjZU1lc3NhZ2UpKSB7XG4gICAgICAgIGludGVybmFsTXNncyA9IHRoaXMuX2ludGVybmFsTWVzc2FnZXNbc291cmNlTWVzc2FnZV07XG4gICAgICAgIGlmIChpbnRlcm5hbE1zZ3MuaW5kZXhPZihtZXNzYWdlKSA9PSAtMSlcbiAgICAgICAgICAgIGludGVybmFsTXNncy5wdXNoKG1lc3NhZ2UpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBsb2dnZXIud2FybignRHVwbGljYXRlIGFkZEludGVybmFsTWVzc2FnZSBjYWxsIGZvciBpbnRlcm5hbCBtZXNzYWdlICcgKyBtZXNzYWdlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBpbnRlcm5hbE1zZ3MgPSB0aGlzLl9pbnRlcm5hbE1lc3NhZ2VzW3NvdXJjZU1lc3NhZ2VdID0gW107XG4gICAgICAgIGludGVybmFsTXNncy5wdXNoKG1lc3NhZ2UpO1xuICAgICAgICByZXR1cm4gc291cmNlTWVzc2FnZTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXJBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZW1vdmVzIGludGVybmFsIGBtZXNzYWdlYCBmcm9tIHRoZSBsaXN0IGNvbm5lY3RlZCB0byBjb3JyZXNwb25kaW5nIHNvdXJjZSBtZXNzYWdlIChgdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlYCBpcyB1c2VkIGZvciB0cmFuc2xhdGlvbikuXG4gKiBSZXR1cm5zIHNvdXJjZSBtZXNzYWdlLCBpZiB0aGUgbGFzdCBpbnRlcm5hbCBtZXNzYWdlIHdhcyByZW1vdmVkIChzbyB0aGF0IGBNZXNzYWdlU291cmNlYCBjYW4gdW5zdWJzY3JpYmUgZnJvbSB0aGlzIHNvdXJjZSBtZXNzYWdlKSwgb3IgYHVuZGVmaW5lZGAuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgaW50ZXJuYWwgbWVzc2FnZSB0byBiZSB0cmFuc2xhdGVkIGFuZCByZW1vdmVkXG4gKiBAcmV0dXJuIHtTdHJpbmd8dW5kZWZpbmVkfVxuICovXG5mdW5jdGlvbiByZW1vdmVJbnRlcm5hbE1lc3NhZ2UobWVzc2FnZSkge1xuICAgIHZhciBzb3VyY2VNZXNzYWdlID0gdGhpcy50cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UobWVzc2FnZSk7XG5cbiAgICBpZiAodHlwZW9mIHNvdXJjZU1lc3NhZ2UgPT0gJ3VuZGVmaW5lZCcpIHJldHVybjtcblxuICAgIHZhciBpbnRlcm5hbE1zZ3MgPSB0aGlzLl9pbnRlcm5hbE1lc3NhZ2VzW3NvdXJjZU1lc3NhZ2VdO1xuXG4gICAgaWYgKGludGVybmFsTXNncyAmJiBpbnRlcm5hbE1zZ3MubGVuZ3RoKSB7XG4gICAgICAgIHZhciBtZXNzYWdlSW5kZXggPSBpbnRlcm5hbE1zZ3MuaW5kZXhPZihtZXNzYWdlKTtcbiAgICAgICAgaWYgKG1lc3NhZ2VJbmRleCA+PSAwKSB7XG4gICAgICAgICAgICBpbnRlcm5hbE1zZ3Muc3BsaWNlKG1lc3NhZ2VJbmRleCwgMSk7XG4gICAgICAgICAgICBpZiAoaW50ZXJuYWxNc2dzLmxlbmd0aCA9PSAwKSB7XG4gICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuX2ludGVybmFsTWVzc2FnZXNbc291cmNlTWVzc2FnZV07XG4gICAgICAgICAgICAgICAgcmV0dXJuIHNvdXJjZU1lc3NhZ2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZVxuICAgICAgICAgICAgdW5leHBlY3RlZE5vdGlmaWNhdGlvbldhcm5pbmcoKTtcbiAgICB9IGVsc2VcbiAgICAgICAgdW5leHBlY3RlZE5vdGlmaWNhdGlvbldhcm5pbmcoKTtcblxuXG4gICAgZnVuY3Rpb24gdW5leHBlY3RlZE5vdGlmaWNhdGlvbldhcm5pbmcoKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKCdub3RpZmljYXRpb24gcmVjZWl2ZWQ6IHVuLXN1YnNjcmliZSBmcm9tIGludGVybmFsIG1lc3NhZ2UgJyArIG1lc3NhZ2VcbiAgICAgICAgICAgICAgICAgICAgICsgJyB3aXRob3V0IHByZXZpb3VzIHN1YnNjcmlwdGlvbiBub3RpZmljYXRpb24nKTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXJBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIHRoZSBhcnJheSBvZiBpbnRlcm5hbCBtZXNzYWdlcyB0aGF0IHdlcmUgdHJhbnNsYXRlZCB0byBnaXZlbiBgc291cmNlTWVzc2FnZWAuXG4gKiBUaGlzIG1ldGhvZCBpcyB1c2VkIGJ5IGBNZXNzYWdlU291cmNlYCB0byBkaXNwYXRjaCBzb3VyY2UgbWVzc2FnZSBvbiB0aGUgYE1lc2VuZ2VyYC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gc291cmNlTWVzc2FnZSBzb3VyY2UgbWVzc2FnZVxuICogQHJldHVybiB7QXJyYXlbU3RyaW5nXX1cbiAqL1xuZnVuY3Rpb24gZ2V0SW50ZXJuYWxNZXNzYWdlcyhzb3VyY2VNZXNzYWdlKSB7XG4gICAgcmV0dXJuIHRoaXMuX2ludGVybmFsTWVzc2FnZXNbc291cmNlTWVzc2FnZV07XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXJBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBTdWJjbGFzc2VzIHNob3VsZCByZS1pbXBsZW1lbnQgdGhpcyBtZXRob2QgdG8gZGVmaW5lIHRoZSBydWxlIGZvciB0cmFuc2xhdGlvbiBvZiBpbnRlcm5hbCBgbWVzc2FnZWAgdG8gc291cmNlIG1lc3NhZ2UuIFRoaXMgY2xhc3Mgc2ltcGx5IHJldHVybnMgdGhlIHNhbWUgYG1lc3NhZ2VgLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGludGVybmFsIG1lc3NhZ2UgdG8gYmUgdHJhbnNsYXRlZFxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UobWVzc2FnZSkge1xuICAgIHJldHVybiBtZXNzYWdlXG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXJBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBTdWJjbGFzc2VzIHNob3VsZCByZS1pbXBsZW1lbnQgdGhpcyBtZXRob2QgdG8gZGVmaW5lIHRoZSBydWxlIGZvciB0cmFuc2xhdGlvbiBvZiBzb3VyY2UgbWVzc2FnZSBkYXRhIHRvIGludGVybmFsIG1lc3NhZ2UgZGF0YS4gVGhpcyBjbGFzcyBzaW1wbHkgcmV0dXJucyB0aGUgc2FtZSBgc291cmNlRGF0YWAuXG4gKiBUaGlzIG1ldGhvZCBpcyB1c2VkIGluIFtkaXNwYXRjaE1lc3NhZ2VdKC4vbV9zb3VyY2UuanMuaHRtbCNkaXNwYXRjaE1lc3NhZ2UpIG1ldGhvZCBvZiBgTWVzc2FnZVNvdXJjZWAuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHNvdXJjZU1lc3NhZ2Ugc291cmNlIG1lc3NhZ2UsIGNhbiBiZSB1c2VkIGluIHRyYW5zbGF0aW9uIHJ1bGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGludGVybmFsIG1lc3NhZ2UsIGNhbiBiZSB1c2VkIGluIHRyYW5zbGF0aW9uIHJ1bGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBzb3VyY2VEYXRhIGRhdGEgcmVjZWl2ZWQgZnJvbSBzb3VyY2UgdGhhdCBoYXMgdG8gYmUgdHJhbnNsYXRlZCB0byBkYXRhIHRoYXQgd2lsbCBiZSBzZW50IHRvIGludGVybmFsIE1lc3NlbmdlciBzdWJzY3JpYmVyXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUludGVybmFsRGF0YShzb3VyY2VNZXNzYWdlLCBtZXNzYWdlLCBzb3VyY2VEYXRhKSB7XG4gICAgcmV0dXJuIHNvdXJjZURhdGE7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXJBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBTdWJjbGFzc2VzIHNob3VsZCByZS1pbXBsZW1lbnQgdGhpcyBtZXRob2QgdG8gZGVmaW5lIHRoZSBkaXNwYXRjaCBmaWx0ZXIgZm9yIGludGVybmFsIG1lc3NhZ2VzLiBUaGlzIG1ldGhvZCBzaG91bGQgcmV0dXJuIGB0cnVlYCB0byBhbGxvdyBhbmQgYGZhbHNlYCB0byBwcmV2ZW50IGludGVybmFsIG1lc3NhZ2UgZGlzcGF0Y2guIFRoaXMgY2xhc3MgYWx3YXlzIHJldHVybnMgYHRydWVgLlxuICogVGhpcyBtZXRob2QgaXMgdXNlZCBpbiBbZGlzcGF0Y2hNZXNzYWdlXSguL21fc291cmNlLmpzLmh0bWwjZGlzcGF0Y2hNZXNzYWdlKSBtZXRob2Qgb2YgYE1lc3NhZ2VTb3VyY2VgLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzb3VyY2VNZXNzYWdlIHNvdXJjZSBtZXNzYWdlLCBjYW4gYmUgdXNlZCBpbiBmaWx0ZXIgcnVsZVxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgaW50ZXJuYWwgbWVzc2FnZSwgY2FuIGJlIHVzZWQgaW4gZmlsdGVyIHJ1bGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBpbnRlcm5hbERhdGEgZGF0YSB0cmFuc2xhdGVkIGJ5IGBjcmVhdGVJbnRlcm5hbERhdGFgIG1ldGhvZCBmcm9tIHNvdXJjZSBkYXRhLCBjYW4gYmUgdXNlZCBpbiBmaWx0ZXIgcnVsZVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gZmlsdGVyU291cmNlTWVzc2FnZShzb3VyY2VNZXNzYWdlLCBtZXNzYWdlLCBpbnRlcm5hbERhdGEpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIE1lc3NlbmdlckFQSSA9IHJlcXVpcmUoJy4vbV9hcGknKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbi8qKlxuICogQSBnZW5lcmljIHN1YnNjbGFzcyBvZiBbTWVzc2VuZ2VyQVBJXSguL21fYXBpLmpzLmh0bWwpIHRoYXQgc3VwcG9ydHMgcGF0dGVybiBzdWJzY3JpcHRpb25zIHRvIHNvdXJjZS5cbiAqIENhbiBiZSB1c2VmdWwgaWYgdGhlIHNvdXJjZSBpcyBhbm90aGVyIE1lc3Nlbmdlci5cbiAqL1xuIHZhciBNZXNzZW5nZXJSZWdleHBBUEkgPSBfLmNyZWF0ZVN1YmNsYXNzKE1lc3NlbmdlckFQSSwgJ01lc3NlbmdlclJlZ2V4cEFQSScpO1xuXG4gbW9kdWxlLmV4cG9ydHMgPSBNZXNzZW5nZXJSZWdleHBBUEk7XG5cblxuXy5leHRlbmRQcm90byhNZXNzZW5nZXJSZWdleHBBUEksIHtcbiAgICBpbml0OiBpbml0LFxuICAgIGFkZEludGVybmFsTWVzc2FnZTogYWRkSW50ZXJuYWxNZXNzYWdlLFxuICAgIHJlbW92ZUludGVybmFsTWVzc2FnZTogcmVtb3ZlSW50ZXJuYWxNZXNzYWdlLFxuICAgIGdldEludGVybmFsTWVzc2FnZXM6IGdldEludGVybmFsTWVzc2FnZXNcbn0pO1xuXG5cbi8qKlxuICogTWVzc2VuZ2VyUmVnZXhwQVBJIGluc3RhbmNlIG1ldGhvZFxuICogQ2FsbGVkIGJ5IE1lc3NlbmdlclJlZ2V4cEFQSSBjb25zdHJ1Y3Rvci5cbiAqL1xuZnVuY3Rpb24gaW5pdCgpIHtcbiAgICBNZXNzZW5nZXJBUEkucHJvdG90eXBlLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICBfLmRlZmluZVByb3BlcnRpZXModGhpcywge1xuICAgICAgICBfcGF0dGVybkludGVybmFsTWVzc2FnZXM6IHt9XG4gICAgfSk7XG4gICAgdGhpcy5fY2F0Y2hBbGxTdWJzY3JpYmVkID0gZmFsc2U7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXJSZWdleHBBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBBdWdtZW50cyBNZXNzZW5nZXJBUEkgbWV0aG9kIGJ5IHN0b3JpbmcgcmVnZXhwXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgaW50ZXJuYWwgbWVzc2FnZSB0byBiZSB0cmFuc2xhdGVkIGFuZCBhZGRlZFxuICogQHJldHVybiB7U3RyaW5nfFJlZ0V4cHx1bmRlZmluZWR9XG4gKi9cbmZ1bmN0aW9uIGFkZEludGVybmFsTWVzc2FnZShtZXNzYWdlKSB7XG4gICAgdmFyIHNvdXJjZU1lc3NhZ2UgPSBNZXNzZW5nZXJBUEkucHJvdG90eXBlLmFkZEludGVybmFsTWVzc2FnZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIFxuICAgIC8vIHN0b3JlIHJlZ2V4cCBpdHNlbGYgaWYgc291cmNlTWVzc2FnZSBpcyByZWdleHBcbiAgICBpZiAoc291cmNlTWVzc2FnZSAmJiBzb3VyY2VNZXNzYWdlIGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgICAgIHRoaXMuX2ludGVybmFsTWVzc2FnZXNbc291cmNlTWVzc2FnZV0ucGF0dGVybiA9IHNvdXJjZU1lc3NhZ2U7XG4gICAgICAgIHRoaXMuX3BhdHRlcm5JbnRlcm5hbE1lc3NhZ2VzW3NvdXJjZU1lc3NhZ2VdID0gdGhpcy5faW50ZXJuYWxNZXNzYWdlc1tzb3VyY2VNZXNzYWdlXTtcbiAgICAgICAgaWYgKHRoaXMuX2NhdGNoQWxsU3Vic2NyaWJlZCkgcmV0dXJuO1xuICAgICAgICAgICAgdGhpcy5fY2F0Y2hBbGxTdWJzY3JpYmVkID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIC8uKi87XG4gICAgfVxuXG4gICAgcmV0dXJuIHNvdXJjZU1lc3NhZ2U7XG59XG5cblxuLyoqXG4gKiBNZXNzZW5nZXJSZWdleHBBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBBdWdtZW50cyBNZXNzZW5nZXJBUEkgbWV0aG9kIGJ5IHJlbW92aW5nIHJlZ2V4cCBzdWJzY2lycHRpb25cbiAqIFxuICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgaW50ZXJuYWwgbWVzc2FnZSB0byBiZSB0cmFuc2xhdGVkIGFuZCBhZGRlZFxuICogQHJldHVybiB7U3RyaW5nfFJlZ0V4cHx1bmRlZmluZWR9XG4gKi9cbmZ1bmN0aW9uIHJlbW92ZUludGVybmFsTWVzc2FnZShtZXNzYWdlKSB7XG4gICAgdmFyIHNvdXJjZU1lc3NhZ2UgPSBNZXNzZW5nZXJBUEkucHJvdG90eXBlLnJlbW92ZUludGVybmFsTWVzc2FnZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXG4gICAgaWYgKHNvdXJjZU1lc3NhZ2UgJiYgc291cmNlTWVzc2FnZSBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICBkZWxldGUgdGhpcy5fcGF0dGVybkludGVybmFsTWVzc2FnZXNbc291cmNlTWVzc2FnZV07XG4gICAgICAgIHZhciBub1BhdHRlcm5JbnRlcm5hbE1lc3NhZ2VzID0gISBPYmplY3Qua2V5cyh0aGlzLl9wYXR0ZXJuSW50ZXJuYWxNZXNzYWdlcykubGVuZ3RoO1xuICAgICAgICBpZiAobm9QYXR0ZXJuSW50ZXJuYWxNZXNzYWdlcykge1xuICAgICAgICAgICAgdGhpcy5fY2F0Y2hBbGxTdWJzY3JpYmVkID0gZmFsc2U7XG4gICAgICAgICAgICByZXR1cm4gLy4qLztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBzb3VyY2VNZXNzYWdlO1xufVxuXG5cbi8qKlxuICogTWVzc2VuZ2VyQVBJIGluc3RhbmNlIG1ldGhvZFxuICogQXVnbWVudHMgTWVzc2VuZ2VyQVBJIG1ldGhvZCBieSByZXR1cm5pbmcgbWVzc2FnZXMgc3Vic2NyaWJlZCB3aXRoIHJlZ2V4cFxuICogVGhpcyBtZXRob2QgaXMgdXNlZCBieSBgTWVzc2FnZVNvdXJjZWAgdG8gZGlzcGF0Y2ggc291cmNlIG1lc3NhZ2Ugb24gdGhlIGBNZXNlbmdlcmAuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBzb3VyY2VNZXNzYWdlIHNvdXJjZSBtZXNzYWdlXG4gKiBAcmV0dXJuIHtBcnJheVtTdHJpbmddfVxuICovXG5mdW5jdGlvbiBnZXRJbnRlcm5hbE1lc3NhZ2VzKHNvdXJjZU1lc3NhZ2UpIHtcbiAgICB2YXIgaW50ZXJuYWxNZXNzYWdlcyA9IE1lc3NlbmdlckFQSS5wcm90b3R5cGUuZ2V0SW50ZXJuYWxNZXNzYWdlcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXG4gICAgLy8gYWRkIGludGVybmFsIG1lc3NhZ2VzIGZvciByZWdleHAgc291cmNlIHN1YnNjcmlwdGlvbnNcbiAgICBpZiAodHlwZW9mIHNvdXJjZU1lc3NhZ2UgPT0gJ3N0cmluZycpIHtcbiAgICAgICAgaW50ZXJuYWxNZXNzYWdlcyA9IGludGVybmFsTWVzc2FnZXMgfHwgW107XG4gICAgICAgIHZhciBpbnRlcm5hbE1lc3NhZ2VzSGFzaCA9IF8ub2JqZWN0KGludGVybmFsTWVzc2FnZXMsIHRydWUpO1xuXG4gICAgICAgIF8uZWFjaEtleSh0aGlzLl9wYXR0ZXJuSW50ZXJuYWxNZXNzYWdlcywgZnVuY3Rpb24ocGF0dGVybk1lc3NhZ2VzKSB7XG4gICAgICAgICAgICB2YXIgc291cmNlUGF0dGVybiA9IHBhdHRlcm5NZXNzYWdlcy5wYXR0ZXJuO1xuXG4gICAgICAgICAgICBpZiAoc291cmNlUGF0dGVybi50ZXN0KHNvdXJjZU1lc3NhZ2UpKVxuICAgICAgICAgICAgICAgIHBhdHRlcm5NZXNzYWdlcy5mb3JFYWNoKGZ1bmN0aW9uKG1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGludGVybmFsTWVzc2FnZXNIYXNoW21lc3NhZ2VdKSByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIGludGVybmFsTWVzc2FnZXMucHVzaChtZXNzYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgaW50ZXJuYWxNZXNzYWdlc0hhc2hbbWVzc2FnZV0gPSB0cnVlO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9IFxuXG4gICAgcmV0dXJuIGludGVybmFsTWVzc2FnZXM7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBNaXhpbiA9IHJlcXVpcmUoJy4uL2Fic3RyYWN0L21peGluJylcbiAgICAsIE1lc3NlbmdlckFQSSA9IHJlcXVpcmUoJy4vbV9hcGknKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vdXRpbC9sb2dnZXInKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaDtcblxuXG4vKipcbiAqIGBtaWxvLmNsYXNzZXMuTWVzc2FnZVNvdXJjZWBcbiAqIEFuIGFic3RyYWN0IGNsYXNzIChzdWJjbGFzcyBvZiBbTWl4aW5dKC4uL2Fic3RyYWN0L21peGluLmpzLmh0bWwpKSBmb3IgY29ubmVjdGluZyBbTWVzc2VuZ2VyXSguL2luZGV4LmpzLmh0bWwpIHRvIGV4dGVybmFsIHNvdXJjZXMgb2YgbWVzc2FnZXMgKGxpa2UgRE9NIGV2ZW50cykgYW5kIGRlZmluaW5nIGhpZ2hlciBsZXZlbCBtZXNzYWdlcy5cbiAqIEFuIGluc3RhbmNlIG9mIE1lc3NhZ2VTb3VyY2UgY2FuIGVpdGhlciBiZSBwYXNzZWQgdG8gTWVzc2VuZ2VyIGNvbnN0cnVjdG9yIG9yIGxhdGVyIHVzaW5nIGBfc2V0TWVzc2FnZVNvdXJjZWAgbWV0aG9kIG9mIE1lc3Nlbmdlci4gT25jZSBzZXQsIE1lc3NhZ2VTb3VyY2Ugb2YgTWVzc2VuZ2VyIGNhbm5vdCBiZSBjaGFuZ2VkLlxuICovXG52YXIgTWVzc2FnZVNvdXJjZSA9IF8uY3JlYXRlU3ViY2xhc3MoTWl4aW4sICdNZXNzYWdlU291cmNlJywgdHJ1ZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gTWVzc2FnZVNvdXJjZTtcblxuXG4vKipcbiAqICMjIyNNZXNzYWdlU291cmNlIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbaW5pdF0oI2luaXQpIC0gaW5pdGlhbGl6ZXMgbWVzc2FnZVNvdXJjZSAtIGNhbGxlZCBieSBNaXhpbiBzdXBlcmNsYXNzXG4gKiAtIFtzZXRNZXNzZW5nZXJdKCNzZXRNZXNzZW5nZXIpIC0gY29ubmVjdHMgTWVzc2VuZ2VyIHRvIE1lc3NhZ2VTb3VyY2UsIGlzIGNhbGxlZCBmcm9tIGBpbml0YCBvciBgX3NldE1lc3NhZ2VTb3VyY2VgIG1ldGhvZHMgb2YgW01lc3Nlbmdlcl0oLi9pbmRleC5qcy5odG1sKS5cbiAqIC0gW29uU3Vic2NyaWJlckFkZGVkXSgjb25TdWJzY3JpYmVyQWRkZWQpIC0gY2FsbGVkIGJ5IE1lc3NlbmdlciB0byBub3RpZnkgd2hlbiB0aGUgZmlyc3Qgc3Vic2NyaWJlciBmb3IgYW4gaW50ZXJuYWwgbWVzc2FnZSB3YXMgYWRkZWQsIHNvIE1lc3NhZ2VTb3VyY2UgY2FuIHN1YnNjcmliZSB0byBzb3VyY2VcbiAqIC0gW29uU3Vic2NyaWJlclJlbW92ZWRdKCNvblN1YnNjcmliZXJSZW1vdmVkKSAtIGNhbGxlZCBieSBNZXNzZW5nZXIgdG8gbm90aWZ5IHdoZW4gdGhlIGxhc3Qgc3Vic2NyaWJlciBmb3IgYW4gaW50ZXJuYWwgbWVzc2FnZSB3YXMgcmVtb3ZlZCwgc28gTWVzc2FnZVNvdXJjZSBjYW4gdW5zdWJzY3JpYmUgZnJvbSBzb3VyY2VcbiAqIC0gW2Rpc3BhdGNoTWVzc2FnZV0oI2Rpc3BhdGNoTWVzc2FnZSkgLSBkaXNwYXRjaGVzIHNvdXJjZSBtZXNzYWdlLiBNZXNzYWdlU291cmNlIHN1YmNsYXNzIHNob3VsZCBpbXBsZW1lbnQgbWVjaGFuaXNtIHdoZW4gb24gYWN0dWFsIHNvdXJjZSBtZXNzYWdlIHRoaXMgbWV0aG9kIGlzIGNhbGxlZC5cbiAqXG4gKiBNZXRob2RzIGJlbG93IHNob3VsZCBiZSBpbXBsZW1lbnRlZCBpbiBzdWJjbGFzczpcbiAqXG4gKiAtIFt0cmlnZ2VyXSgjdHJpZ2dlcikgLSB0cmlnZ2VycyBtZXNzYWdlcyBvbiB0aGUgc291cmNlIChhbiBvcHRpb25hbCBtZXRob2QpXG4gKiAtIFthZGRTb3VyY2VTdWJzY3JpYmVyXSgjYWRkU291cmNlU3Vic2NyaWJlcikgLSBhZGRzIGxpc3RlbmVyL3N1YnNjcmliZXIgdG8gZXh0ZXJuYWwgbWVzc2FnZVxuICogLSBbcmVtb3ZlU291cmNlU3Vic2NyaWJlcl0oI3JlbW92ZVNvdXJjZVN1YnNjcmliZXIpIC0gcmVtb3ZlcyBsaXN0ZW5lci9zdWJzY3JpYmVyIGZyb20gZXh0ZXJuYWwgbWVzc2FnZVxuICovXG5fLmV4dGVuZFByb3RvKE1lc3NhZ2VTb3VyY2UsIHtcbiAgICBpbml0OiBpbml0LFxuICAgIGRlc3Ryb3k6IE1lc3NhZ2VTb3VyY2UkZGVzdHJveSxcbiAgICBzZXRNZXNzZW5nZXI6IHNldE1lc3NlbmdlcixcbiAgICBvblN1YnNjcmliZXJBZGRlZDogb25TdWJzY3JpYmVyQWRkZWQsXG4gICAgb25TdWJzY3JpYmVyUmVtb3ZlZDogb25TdWJzY3JpYmVyUmVtb3ZlZCwgXG4gICAgZGlzcGF0Y2hNZXNzYWdlOiBkaXNwYXRjaE1lc3NhZ2UsXG4gICAgcG9zdE1lc3NhZ2U6IHBvc3RNZXNzYWdlLFxuICAgIF9wcmVwYXJlTWVzc2VuZ2VyQVBJOiBfcHJlcGFyZU1lc3NlbmdlckFQSSxcblxuICAgIC8vIE1ldGhvZHMgYmVsb3cgbXVzdCBiZSBpbXBsZW1lbnRlZCBpbiBzdWJjbGFzc1xuICAgIHRyaWdnZXI6IHRvQmVJbXBsZW1lbnRlZCxcbiAgICBhZGRTb3VyY2VTdWJzY3JpYmVyOiB0b0JlSW1wbGVtZW50ZWQsXG4gICAgcmVtb3ZlU291cmNlU3Vic2NyaWJlcjogdG9CZUltcGxlbWVudGVkXG59KTtcblxuXG4vKipcbiAqIE1lc3NhZ2VTb3VyY2UgaW5zdGFuY2UgbWV0aG9kLlxuICogQ2FsbGVkIGJ5IE1peGluIGNvbnN0cnVjdG9yLlxuICogTWVzc2FnZVNvdXJjZSBjb25zdHJ1Y3RvciBzaG91bGQgYmUgcGFzc2VkIHRoZSBzYW1lIHBhcmFtZXRlcnMgYXMgdGhpcyBtZXRob2Qgc2lnbmF0dXJlLlxuICogSWYgYW4gaW5zdGFuY2Ugb2YgW01lc3NlbmdlckFQSV0oLi9tX2FwaS5qcy5odG1sKSBpcyBwYXNzZWQgYXMgdGhlIHRoaXJkIHBhcmFtZXRlciwgaXQgZXh0ZW5kcyBNZXNzYWdlU291cmNlIGZ1bmN0aW9uYWxpdHkgdG8gYWxsb3cgaXQgdG8gZGVmaW5lIG5ldyBtZXNzYWdlcywgdG8gZmlsdGVyIG1lc3NhZ2VzIGJhc2VkIG9uIHRoZWlyIGRhdGEgYW5kIHRvIGNoYW5nZSBtZXNzYWdlIGRhdGEuIFNlZSBbTWVzc2VuZ2VyQVBJXSguL21fYXBpLmpzLmh0bWwpLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBob3N0T2JqZWN0IE9wdGlvbmFsIG9iamVjdCB0aGF0IHN0b3JlcyB0aGUgTWVzc2FnZVNvdXJjZSBvbiBvbmUgb2YgaXRzIHByb3BlcnRpZXMuIEl0IGlzIHVzZWQgdG8gcHJveHkgbWV0aG9kcyBvZiBNZXNzYWdlU291cmNlLlxuICogQHBhcmFtIHtPYmplY3RbU3RyaW5nXX0gcHJveHlNZXRob2RzIE9wdGlvbmFsIG1hcCBvZiBtZXRob2QgbmFtZXM7IGtleSAtIHByb3h5IG1ldGhvZCBuYW1lLCB2YWx1ZSAtIE1lc3NhZ2VTb3VyY2UncyBtZXRob2QgbmFtZS5cbiAqIEBwYXJhbSB7TWVzc2VuZ2VyQVBJfSBtZXNzZW5nZXJBUEkgT3B0aW9uYWwgaW5zdGFuY2Ugb2YgTWVzc2VuZ2VyQVBJLlxuICovXG5mdW5jdGlvbiBpbml0KGhvc3RPYmplY3QsIHByb3h5TWV0aG9kcywgbWVzc2VuZ2VyQVBJKSB7XG4gICAgdGhpcy5fcHJlcGFyZU1lc3NlbmdlckFQSShtZXNzZW5nZXJBUEkpO1xufVxuXG5cbi8qKlxuICogRGVzdHJveXMgbWVzc2FnZSBzb3VyY2VcbiAqL1xuZnVuY3Rpb24gTWVzc2FnZVNvdXJjZSRkZXN0cm95KCkge1xuICAgIGlmICh0aGlzLm1lc3NlbmdlckFQSSlcbiAgICAgICAgdGhpcy5tZXNzZW5nZXJBUEkuZGVzdHJveSgpO1xufVxuXG5cbi8qKlxuICogTWVzc2FnZVNvdXJjZSBpbnN0YW5jZSBtZXRob2QuXG4gKiBTZXRzIHJlZmVyZW5jZSB0byBNZXNzZW5nZXIgaW5zdGFuY2UuXG4gKlxuICogQHBhcmFtIHtNZXNzZW5nZXJ9IG1lc3NlbmdlciByZWZlcmVuY2UgdG8gTWVzc2VuZ2VyIGluc3RhbmNlIGxpbmtlZCB0byB0aGlzIE1lc3NhZ2VTb3VyY2VcbiAqL1xuZnVuY3Rpb24gc2V0TWVzc2VuZ2VyKG1lc3Nlbmdlcikge1xuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgJ21lc3NlbmdlcicsIG1lc3Nlbmdlcik7XG59XG5cblxuLyoqXG4gKiBNZXNzYWdlU291cmNlIGluc3RhbmNlIG1ldGhvZC5cbiAqIFByZXBhcmVzIFtNZXNzZW5nZXJBUEldKC4vbV9hcGkuanMuaHRtbCkgcGFzc2VkIHRvIGNvbnN0cnVjdG9yIGJ5IHByb3h5aW5nIGl0cyBtZXRob2RzIHRvIGl0c2VsZiBvciBpZiBNZXNzZW5nZXJBUEkgd2Fzbid0IHBhc3NlZCBkZWZpbmVzIHR3byBtZXRob2RzIHRvIGF2b2lkIGNoZWNraW5nIHRoZWlyIGF2YWlsYWJpbGl0eSBldmVyeSB0aW1lIHRoZSBtZXNzYWdlIGlzIGRpc3BhdGNoZWQuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7TWVzc2VuZ2VyQVBJfSBtZXNzZW5nZXJBUEkgT3B0aW9uYWwgaW5zdGFuY2Ugb2YgTWVzc2VuZ2VyQVBJXG4gKi9cbmZ1bmN0aW9uIF9wcmVwYXJlTWVzc2VuZ2VyQVBJKG1lc3NlbmdlckFQSSkge1xuICAgIGNoZWNrKG1lc3NlbmdlckFQSSwgTWF0Y2guT3B0aW9uYWwoTWVzc2VuZ2VyQVBJKSk7XG5cbiAgICBpZiAoISBtZXNzZW5nZXJBUEkpXG4gICAgICAgIG1lc3NlbmdlckFQSSA9IG5ldyBNZXNzZW5nZXJBUEk7XG5cbiAgICBfLmRlZmluZVByb3BlcnR5KHRoaXMsICdtZXNzZW5nZXJBUEknLCBtZXNzZW5nZXJBUEkpO1xufVxuXG5cbi8qKlxuICogTWVzc2FnZVNvdXJjZSBpbnN0YW5jZSBtZXRob2QuXG4gKiBTdWJzY3JpYmVzIHRvIGV4dGVybmFsIHNvdXJjZSB1c2luZyBgYWRkU291cmNlU3Vic2NyaWJlcmAgbWV0aG9kIHRoYXQgc2hvdWxkIGJlIGltcGxlbWVudGVkIGluIHN1YmNsYXNzLlxuICogVGhpcyBtZXRob2QgaXMgY2FsbGVkIGJ5IFtNZXNzZW5nZXJdKC4vaW5kZXguanMuaHRtbCkgd2hlbiB0aGUgZmlyc3Qgc3Vic2NyaWJlciB0byB0aGUgYG1lc3NhZ2VgIGlzIGFkZGVkLlxuICogRGVsZWdhdGVzIHRvIHN1cHBsaWVkIG9yIGRlZmF1bHQgW01lc3NlbmdlckFQSV0oLi9tX2FwaS5qcy5odG1sKSBmb3IgdHJhbnNsYXRpb24gb2YgYG1lc3NhZ2VgIHRvIGBzb3VyY2VNZXNzYWdlYC4gYE1lc3NhZ2VBUEkucHJvdG90eXBlLmFkZEludGVybmFsTWVzc2FnZWAgd2lsbCByZXR1cm4gdW5kZWZpbmVkIGlmIHRoaXMgYHNvdXJjZU1lc3NhZ2VgIHdhcyBhbHJlYWR5IHN1YnNjcmliZWQgdG8gdG8gcHJldmVudCBkdXBsaWNhdGUgc3Vic2NyaXB0aW9uLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGludGVybmFsIE1lc3NlbmdlciBtZXNzYWdlIHRoYXQgaGFzIHRvIGJlIHN1YnNjcmliZWQgdG8gYXQgdGhlIGV4dGVybmFsIHNvdXJjZSBvZiBtZXNzYWdlcy5cbiAqL1xuZnVuY3Rpb24gb25TdWJzY3JpYmVyQWRkZWQobWVzc2FnZSkge1xuICAgIHZhciBuZXdTb3VyY2VNZXNzYWdlID0gdGhpcy5tZXNzZW5nZXJBUEkuYWRkSW50ZXJuYWxNZXNzYWdlKG1lc3NhZ2UpO1xuICAgIGlmICh0eXBlb2YgbmV3U291cmNlTWVzc2FnZSAhPSAndW5kZWZpbmVkJylcbiAgICAgICAgdGhpcy5hZGRTb3VyY2VTdWJzY3JpYmVyKG5ld1NvdXJjZU1lc3NhZ2UpO1xufVxuXG5cbi8qKlxuICogTWVzc2FnZVNvdXJjZSBpbnN0YW5jZSBtZXRob2QuXG4gKiBVbnN1YnNjcmliZXMgZnJvbSBleHRlcm5hbCBzb3VyY2UgdXNpbmcgYHJlbW92ZVNvdXJjZVN1YnNjcmliZXJgIG1ldGhvZCB0aGF0IHNob3VsZCBiZSBpbXBsZW1lbnRlZCBpbiBzdWJjbGFzcy5cbiAqIFRoaXMgbWV0aG9kIGlzIGNhbGxlZCBieSBbTWVzc2VuZ2VyXSguL2luZGV4LmpzLmh0bWwpIHdoZW4gdGhlIGxhc3Qgc3Vic2NyaWJlciB0byB0aGUgYG1lc3NhZ2VgIGlzIHJlbW92ZWQuXG4gKiBEZWxlZ2F0ZXMgdG8gc3VwcGxpZWQgb3IgZGVmYXVsdCBbTWVzc2VuZ2VyQVBJXSguL21fYXBpLmpzLmh0bWwpIGZvciB0cmFuc2xhdGlvbiBvZiBgbWVzc2FnZWAgdG8gYHNvdXJjZU1lc3NhZ2VgLiBgTWVzc2FnZUFQSS5wcm90b3R5cGUucmVtb3ZlSW50ZXJuYWxNZXNzYWdlYCB3aWxsIHJldHVybiB1bmRlZmluZWQgaWYgdGhpcyBgc291cmNlTWVzc2FnZWAgd2FzIG5vdCB5ZXQgc3Vic2NyaWJlZCB0byB0byBwcmV2ZW50IHVuc3Vic2NyaXB0aW9uIHdpdGhvdXQgcHJldmlvdXMgc3Vic2NyaXB0aW9uLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGludGVybmFsIE1lc3NlbmdlciBtZXNzYWdlIHRoYXQgaGFzIHRvIGJlIHVuc3Vic2NyaWJlZCBmcm9tIGF0IHRoZSBleHRlcm5hbCBzb3VyY2Ugb2YgbWVzc2FnZXMuXG4gKi9cbmZ1bmN0aW9uIG9uU3Vic2NyaWJlclJlbW92ZWQobWVzc2FnZSkge1xuICAgIHZhciByZW1vdmVkU291cmNlTWVzc2FnZSA9IHRoaXMubWVzc2VuZ2VyQVBJLnJlbW92ZUludGVybmFsTWVzc2FnZShtZXNzYWdlKTtcbiAgICBpZiAodHlwZW9mIHJlbW92ZWRTb3VyY2VNZXNzYWdlICE9ICd1bmRlZmluZWQnKVxuICAgICAgICB0aGlzLnJlbW92ZVNvdXJjZVN1YnNjcmliZXIocmVtb3ZlZFNvdXJjZU1lc3NhZ2UpO1xufVxuXG5cbi8qKlxuICogTWVzc2FnZVNvdXJjZSBpbnN0YW5jZSBtZXRob2QuXG4gKiBEaXNwYXRjaGVzIHNvdXJjZU1lc3NhZ2UgdG8gTWVzc2VuZ2VyLlxuICogTWVjaGFuaXNtIHRoYXQgY2FsbHMgdGhpcyBtZXRob2Qgd2hlbiB0aGUgc291cmNlIG1lc3NhZ2UgaXMgcmVjZWl2ZWQgc2hvdWxkIGJlIGltcGxlbWVudGVkIGJ5IHN1YmNsYXNzIChzZWUgW0RPTUV2ZW50c1NvdXJjZV0oLi4vY29tcG9uZW50cy9tc2dfc3JjL2RvbV9ldmVudHMuanMuaHRtbCkgZm9yIGV4YW1wbGUpLlxuICogRGVsZWdhdGVzIHRvIHN1cHBsaWVkIG9yIGRlZmF1bHQgW01lc3NlbmdlckFQSV0oLi9tX2FwaS5qcy5odG1sKSB0byBjcmVhdGUgaW50ZXJuYWwgbWVzc2FnZSBkYXRhIChgY3JlYXRlSW50ZXJuYWxEYXRhYCkgYW5kIHRvIGZpbHRlciB0aGUgbWVzc2FnZSBiYXNlZCBvbiBpdHMgZGF0YSBhbmQvb3IgbWVzc2FnZSAoYGZpbHRlclNvdXJjZU1lc3NhZ2VgKS5cbiAqIEJhc2UgTWVzc2VuZ2VyQVBJIGNsYXNzIGltcGxlbWVudHMgdGhlc2UgdHdvIG1ldGhvZHMgaW4gYSB0cml2aWFsIHdheSAoYGNyZWF0ZUludGVybmFsRGF0YWAgc2ltcGx5IHJldHVybnMgZXh0ZXJuYWwgZGF0YSwgYGZpbHRlclNvdXJjZU1lc3NhZ2VgIHJldHVybnMgYHRydWVgKSwgdGhleSBhcmUgbWVhbnQgdG8gYmUgaW1wbGVtZW50ZWQgYnkgc3ViY2xhc3MuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHNvdXJjZU1lc3NhZ2Ugc291cmNlIG1lc3NhZ2UgcmVjZWl2ZWQgZnJvbSBleHRlcm5hbCBzb3VyY2VcbiAqIEBwYXJhbSB7T2JqZWN0fSBzb3VyY2VEYXRhIGRhdGEgcmVjZWl2ZWQgZnJvbSBleHRlcm5hbCBzb3VyY2VcbiAqL1xuZnVuY3Rpb24gZGlzcGF0Y2hNZXNzYWdlKHNvdXJjZU1lc3NhZ2UsIHNvdXJjZURhdGEpIHtcbiAgICB2YXIgYXBpID0gdGhpcy5tZXNzZW5nZXJBUElcbiAgICAgICAgLCBpbnRlcm5hbE1lc3NhZ2VzID0gYXBpLmdldEludGVybmFsTWVzc2FnZXMoc291cmNlTWVzc2FnZSk7XG5cbiAgICBpZiAoaW50ZXJuYWxNZXNzYWdlcykgXG4gICAgICAgIGludGVybmFsTWVzc2FnZXMuZm9yRWFjaChmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAgICAgdmFyIGludGVybmFsRGF0YSA9IGFwaS5jcmVhdGVJbnRlcm5hbERhdGEoc291cmNlTWVzc2FnZSwgbWVzc2FnZSwgc291cmNlRGF0YSk7XG5cbiAgICAgICAgICAgIHZhciBzaG91bGREaXNwYXRjaCA9IGFwaS5maWx0ZXJTb3VyY2VNZXNzYWdlKHNvdXJjZU1lc3NhZ2UsIG1lc3NhZ2UsIGludGVybmFsRGF0YSk7XG4gICAgICAgICAgICBpZiAoc2hvdWxkRGlzcGF0Y2gpIFxuICAgICAgICAgICAgICAgIHRoaXMucG9zdE1lc3NhZ2UobWVzc2FnZSwgaW50ZXJuYWxEYXRhKTsgICAgICBcbiAgICAgICAgICAgIFxuICAgICAgICB9LCB0aGlzKTtcbn1cblxuXG4vKipcbiAqIFBvc3RzIG1lc3NhZ2Ugb24gdGhlIG1lc3Nlbmdlci4gVGhpcyBtZXRob2QgaXMgc2VwYXJhdGVkIHNvIHNwZWNpZmljIG1lc3NhZ2Ugc291cmNlcyBjYW4gbWFrZSBtZXNzYWdlIGRpc3BhdGNoIHN5bmNocm9ub3VzIGJ5IHVzaW5nIGBwb3N0TWVzc2FnZVN5bmNgXG4gKiBcbiAqIEBwYXJhbSAge1N0cmluZ30gbWVzc2FnZVxuICogQHBhcmFtICB7T2JqZWN0fSBkYXRhXG4gKi9cbmZ1bmN0aW9uIHBvc3RNZXNzYWdlKG1lc3NhZ2UsIGRhdGEpIHtcbiAgICB0aGlzLm1lc3Nlbmdlci5wb3N0TWVzc2FnZShtZXNzYWdlLCBkYXRhKTtcbn1cblxuXG5mdW5jdGlvbiB0b0JlSW1wbGVtZW50ZWQoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjYWxsaW5nIHRoZSBtZXRob2Qgb2YgYW4gYWJzY3RyYWN0IGNsYXNzJyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIE1lc3NhZ2VTb3VyY2UgPSByZXF1aXJlKCcuL21fc291cmNlJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgY2hlY2sgPSByZXF1aXJlKCcuLi91dGlsL2NoZWNrJyk7XG5cblxuLyoqXG4gKiBTdWJjbGFzcyBvZiBNZXNzYWdlU291cmNlIHRoYXQgYWxsb3dzIHRvIGNvbm5lY3QgTWVzc2VuZ2VyIHRvIGFub3RoZXIgTWVzc2VuZ2VyIHVzaW5nIGl0IGFzIGV4dGVybmFsIHNvdXJjZS5cbiAqL1xudmFyIE1lc3Nlbmdlck1lc3NhZ2VTb3VyY2UgPSBfLmNyZWF0ZVN1YmNsYXNzKE1lc3NhZ2VTb3VyY2UsICdNZXNzZW5nZXJNZXNzYWdlU291cmNlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gTWVzc2VuZ2VyTWVzc2FnZVNvdXJjZTtcblxuXG4vKipcbiAqICMjIyNNZXNzZW5nZXJNZXNzYWdlU291cmNlIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKi9cbl8uZXh0ZW5kUHJvdG8oTWVzc2VuZ2VyTWVzc2FnZVNvdXJjZSwge1xuICAgIGluaXQ6IGluaXQsXG4gICAgYWRkU291cmNlU3Vic2NyaWJlcjogYWRkU291cmNlU3Vic2NyaWJlcixcbiAgICByZW1vdmVTb3VyY2VTdWJzY3JpYmVyOiByZW1vdmVTb3VyY2VTdWJzY3JpYmVyLFxuICAgIHBvc3RNZXNzYWdlOiBNZXNzZW5nZXJNZXNzYWdlU291cmNlJHBvc3RNZXNzYWdlXG59KTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyBNZXNzZW5nZXJNZXNzYWdlU291cmNlXG4gKiBEZWZpbmVzIG9uZSBwYXJhbWV0ZXIgaW4gYWRkaXRpb24gdG8gW01lc3NhZ2VTb3VyY2VdKC4vbV9zb3VyY2UuanMuaHRtbCkgcGFyYW1ldGVyc1xuICpcbiAqIEBwYXJhbSB7TWVzc2VuZ2VyfSBzb3VyY2VNZXNzZW5nZXIgbWVzc2VuZ2VyIHRoaXMgbWVzc2FnZSBzb3VyY2UgY29ubmVjdHMgdG9cbiAqL1xuZnVuY3Rpb24gaW5pdChob3N0T2JqZWN0LCBwcm94eU1ldGhvZHMsIG1lc3NlbmdlckFQSSwgc291cmNlTWVzc2VuZ2VyKSB7XG4gICAgTWVzc2FnZVNvdXJjZS5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMuc291cmNlTWVzc2VuZ2VyID0gc291cmNlTWVzc2VuZ2VyO1xufVxuXG5cbi8qKlxuICogU3Vic2NyaWJlcyB0byBzb3VyY2UgbWVzc2FnZS4gU2VlIFtNZXNzYWdlU291cmNlXSguL21fc291cmNlLmpzLmh0bWwpIGRvY3MuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8UmVnZXh9IHNvdXJjZU1lc3NhZ2Ugc291cmNlIG1lc3NhZ2UgdG8gc3Vic2NyaWJlIHRvXG4gKi9cbmZ1bmN0aW9uIGFkZFNvdXJjZVN1YnNjcmliZXIoc291cmNlTWVzc2FnZSkge1xuICAgIHRoaXMuc291cmNlTWVzc2VuZ2VyLm9uU3luYyhzb3VyY2VNZXNzYWdlLCB7IGNvbnRleHQ6IHRoaXMsIHN1YnNjcmliZXI6IHRoaXMuZGlzcGF0Y2hNZXNzYWdlIH0pO1xufVxuXG5cbi8qKlxuICogVW5zdWJzY3JpYmVzIGZyb20gc291cmNlIG1lc3NhZ2UuIFNlZSBbTWVzc2FnZVNvdXJjZV0oLi9tX3NvdXJjZS5qcy5odG1sKSBkb2NzLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfFJlZ2V4fSBzb3VyY2VNZXNzYWdlIHNvdXJjZSBtZXNzYWdlIHRvIHVuc3Vic2NyaWJlIGZyb21cbiAqL1xuZnVuY3Rpb24gcmVtb3ZlU291cmNlU3Vic2NyaWJlcihzb3VyY2VNZXNzYWdlKSB7XG4gICAgdGhpcy5zb3VyY2VNZXNzZW5nZXIub2ZmKHNvdXJjZU1lc3NhZ2UsIHsgY29udGV4dDogdGhpcywgc3Vic2NyaWJlcjogdGhpcy5kaXNwYXRjaE1lc3NhZ2UgfSk7XG59XG5cblxuLyoqXG4gKiBPdmVycmlkZXMgZGVmYWx1dCBtZXNzYWdlIHNvdXJjZSB0byBkaXNwYXRjaCBtZXNzYWdlcyBzeW5jaHJvbm91c2x5XG4gKiBcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICovXG5mdW5jdGlvbiBNZXNzZW5nZXJNZXNzYWdlU291cmNlJHBvc3RNZXNzYWdlKG1lc3NhZ2UsIGRhdGEpIHtcbiAgICB0aGlzLm1lc3Nlbmdlci5wb3N0TWVzc2FnZVN5bmMobWVzc2FnZSwgZGF0YSk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cblxuLyoqXG4gKiAjIyMjTWlsbyBwYWNrYWdlcyMjIyNcbiAqXG4gKiAtIFttaW5kZXJdKC4vbWluZGVyLmpzLmh0bWwpIC0gZGF0YSByZWFjdGl2aXR5LCBvbmUgb3IgdHdvIHdheSwgc2hhbGxvdyBvciBkZWVwLCBhcyB5b3UgbGlrZSBpdFxuICogLSBbY29uZmlnXSguL2NvbmZpZy5qcy5odG1sKSAtIG1pbG8gY29uZmlndXJhdGlvblxuICogLSBbdXRpbF0oLi91dGlsL2luZGV4LmpzLmh0bWwpIC0gbG9nZ2VyLCByZXF1ZXN0LCBkb20sIGNoZWNrLCBlcnJvciwgZXRjLlxuICogLSBbY2xhc3Nlc10oLi9jbGFzc2VzLmpzLmh0bWwpIC0gYWJzdHJhY3QgYW5kIGJhc2UgY2xhc3Nlc1xuICogLSBbTWVzc2VuZ2VyXSguL21lc3Nlbmdlci9pbmRleC5qcy5odG1sKSAtIGdlbmVyaWMgTWVzc2VuZ2VyIHVzZWQgaW4gbW9zdCBvdGhlciBtaWxvIGNsYXNzZXMsIGNhbiBiZSBtaXhlZCBpbnRvIGFwcCBjbGFzc2VzIHRvby5cbiAqIC0gW01vZGVsXSguL21vZGVsL2luZGV4LmpzLmh0bWwpIC0gTW9kZWwgY2xhc3MgdGhhdCBlbWl0cyBtZXNzYWdlcyBvbiBjaGFuZ2VzIHRvIGFueSBkZXB0aCB3aXRob3V0IHRpbWVyIGJhc2VkIHdhdGNoaW5nXG4gKi9cbnZhciBtaWxvID0ge1xuICAgIG1pbmRlcjogcmVxdWlyZSgnLi9taW5kZXInKSxcbiAgICBjb25maWc6IHJlcXVpcmUoJy4vY29uZmlnJyksXG4gICAgdXRpbDogcmVxdWlyZSgnLi91dGlsJyksXG4gICAgY2xhc3NlczogcmVxdWlyZSgnLi9jbGFzc2VzJyksXG4gICAgTWVzc2VuZ2VyOiByZXF1aXJlKCcuL21lc3NlbmdlcicpLFxuICAgIE1vZGVsOiByZXF1aXJlKCcuL21vZGVsJyksXG4gICAgZGVzdHJveTogZGVzdHJveSxcbiAgICBwcm90bzogX1xufTtcblxuXG4vLyBleHBvcnQgZm9yIG5vZGUvYnJvd3NlcmlmeVxuaWYgKHR5cGVvZiBtb2R1bGUgPT0gJ29iamVjdCcgJiYgbW9kdWxlLmV4cG9ydHMpICAgIFxuICAgIG1vZHVsZS5leHBvcnRzID0gbWlsbztcblxuLy8gZ2xvYmFsIG1pbG8gZm9yIGJyb3dzZXJcbmlmICh0eXBlb2Ygd2luZG93ID09ICdvYmplY3QnKVxuICAgIHdpbmRvdy5taWxvID0gbWlsbztcblxuXG5mdW5jdGlvbiBkZXN0cm95KCkge1xuICAgIG1pbG8ubWluZGVyLmRlc3Ryb3koKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbm5lY3RvciA9IHJlcXVpcmUoJy4vbW9kZWwvY29ubmVjdG9yJylcbiAgICAsIE1lc3NlbmdlciA9IHJlcXVpcmUoJy4vbWVzc2VuZ2VyJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKVxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi91dGlsL2xvZ2dlcicpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gbWluZGVyO1xuXG5cbi8qKlxuICogVGhpcyBmdW5jdGlvbiBjcmVhdGVzIG9uZSBvciBtYW55IENvbm5lY3RvciBvYmplY3RzIHRoYXRcbiAqIGNyZWF0ZSBsaXZlIHJlYWN0aXZlIGNvbm5lY3Rpb24gYmV0d2VlbiBvYmplY3RzIGltcGxlbWVudGluZ1xuICogZGF0YVNvdXJjZSBpbnRlcmZhY2U6XG4gKiBPYmplY3RzIHNob3VsZCBlbWl0IG1lc3NhZ2VzIHdoZW4gYW55IHBhcnQgb2YgdGhlaXIgZGF0YSBjaGFuZ2VzLFxuICogbWV0aG9kcyBgb25gIGFuZCBgb2ZmYCBzaG91bGQgYmUgaW1wbGVtZW50ZWQgdG8gc3Vic2NyaWJlL3Vuc3Vic2NyaWJlXG4gKiB0byBjaGFuZ2Ugbm90aWZpY2F0aW9uIG1lc3NhZ2VzLCBtZXRob2RzIGBzZXRgIGFuZCBgZ2V0YCBzaG91bGQgYmUgaW1wbGVtZW50ZWQgdG8gZ2V0L3NldCBkYXRhXG4gKiBvbiBwYXRoIG9iamVjdHMsIHBvaW50aW5nIHRvIHBhcnRpY3VsYXIgcGFydHMgb2YgdGhlIG9iamVjdCwgbWV0aG9kIGBwYXRoYFxuICogc2hvdWxkIHJldHVybiBwYXRoIG9iamVjdCBmb3IgYSBnaXZlbiBwYXRoIHN0cmluZyAoc2VlIHBhdGggdXRpbHMgZm9yIHBhdGggc3RyaW5nIHN5bnRheCkuXG4gKiBCb3RoIE1vZGVsIGFuZCBEYXRhIGZhY2V0IGFyZSBzdWNoIGRhdGEgc291cmNlcywgdGhleSBjYW4gYmUgbGlua2VkIGJ5IENvbm5lY3RvciBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGRzMSB0aGUgZmlyc3QgZGF0YSBzb3VyY2UuIEluc3RlYWQgb2YgdGhlIGZpcnN0IGRhdGEgc291cmNlIGFuIGFycmF5IGNhbiBiZSBwYXNzZWQgd2l0aCBhcnJheXMgb2YgQ29ubmVjdGlvbiBvYmplY3RzIHBhcmFtZXRlcnMgaW4gZWFjaCBhcnJheSBlbGVtZW50LlxuICogQHBhcmFtIHtTdHJpbmd9IG1vZGUgdGhlIGNvbm5lY3Rpb24gbW9kZSB0aGF0IGRlZmluZXMgdGhlIGRpcmVjdGlvbiBhbmQgdGhlIGRlcHRoIG9mIGNvbm5lY3Rpb24uIFBvc3NpYmxlIHZhbHVlcyBhcmUgJy0+JywgJzw8LScsICc8PDwtPj4+JywgZXRjLlxuICogQHBhcmFtIHtPYmplY3R9IGRzMiB0aGUgc2Vjb25kIGRhdGEgc291cmNlXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBub3QgaW1wbGVtZW50ZWQgeWV0XG4gKi9cbmZ1bmN0aW9uIG1pbmRlcihkczEsIG1vZGUsIGRzMiwgb3B0aW9ucykge1xuICAgIGlmIChBcnJheS5pc0FycmF5KGRzMSkpIHtcbiAgICAgICAgdmFyIGNvbm5EZXNjcmlwdGlvbnMgPSBkczE7XG4gICAgICAgIHZhciBjb25uZWN0b3JzID0gY29ubkRlc2NyaXB0aW9ucy5tYXAoZnVuY3Rpb24oZGVzY3IpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgQ29ubmVjdG9yKGRlc2NyWzBdLCBkZXNjclsxXSwgZGVzY3JbMl0sIGRlc2NyWzNdKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbm5lY3RvcnMuZm9yRWFjaChfYWRkQ29ubmVjdG9yKTtcbiAgICAgICAgcmV0dXJuIGNvbm5lY3RvcnM7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIGNuY3QgPSBuZXcgQ29ubmVjdG9yKGRzMSwgbW9kZSwgZHMyLCBvcHRpb25zKTtcbiAgICAgICAgX2FkZENvbm5lY3RvcihjbmN0KTtcbiAgICAgICAgcmV0dXJuIGNuY3Q7XG4gICAgfVxufVxuXG5cbi8qKlxuICogbWVzc2VuZ2VyIG9mIG1pbmRlciB3aGVyZSBpdCBlbWl0cyBldmVudHMgcmVsYXRlZCB0byBhbGwgY29ubmVjdG9yc1xuICogQHR5cGUge01lc3Nlbmdlcn1cbiAqL1xudmFyIF9tZXNzZW5nZXIgPSBuZXcgTWVzc2VuZ2VyKG1pbmRlciwgTWVzc2VuZ2VyLmRlZmF1bHRNZXRob2RzKTtcblxuXG52YXIgX2Nvbm5lY3RvcnMgPSBbXVxuICAgICwgX3JlY2VpdmVkTWVzc2FnZXMgPSBbXVxuICAgICwgX2lzUHJvcGFnYXRpbmcgPSBmYWxzZTtcblxuXG5fLmV4dGVuZChtaW5kZXIsIHtcbiAgICBnZXRDb25uZWN0b3JzOiBtaW5kZXJfZ2V0Q29ubmVjdG9ycyxcbiAgICBnZXRFeHBhbmRlZENvbm5lY3Rpb25zOiBtaW5kZXJfZ2V0RXhwYW5kZWRDb25uZWN0aW9ucyxcbiAgICBpc1Byb3BhZ2F0aW5nOiBtaW5kZXJfaXNQcm9wYWdhdGluZyxcbiAgICB3aGVuUHJvcGFnYXRpb25Db21wbGV0ZWQ6IG1pbmRlcl93aGVuUHJvcGFnYXRpb25Db21wbGV0ZWQsXG4gICAgZGVzdHJveUNvbm5lY3RvcjogbWluZGVyX2Rlc3Ryb3lDb25uZWN0b3IsXG4gICAgZGVzdHJveTogbWluZGVyX2Rlc3Ryb3lcbn0pO1xuXG5cbmZ1bmN0aW9uIF9hZGRDb25uZWN0b3IoY25jdCkge1xuICAgIGNuY3QuX19fbWluZGVyX2lkID0gX2Nvbm5lY3RvcnMucHVzaChjbmN0KSAtIDE7XG4gICAgY25jdC5vbigvLiovLCBvbkNvbm5lY3Rvck1lc3NhZ2UpO1xuICAgIG1pbmRlci5wb3N0TWVzc2FnZSgnYWRkZWQnLCB7IGNvbm5lY3RvcjogY25jdCB9KTtcbiAgICBtaW5kZXIucG9zdE1lc3NhZ2UoJ3R1cm5lZG9uJywgeyBjb25uZWN0b3I6IGNuY3QgfSk7XG59XG5cblxuZnVuY3Rpb24gb25Db25uZWN0b3JNZXNzYWdlKG1zZywgZGF0YSkge1xuICAgIHZhciBkYXRhID0gZGF0YSA/IF8uY2xvbmUoZGF0YSkgOiB7fTtcbiAgICBfLmV4dGVuZChkYXRhLCB7XG4gICAgICAgIGlkOiB0aGlzLl9fX21pbmRlcl9pZCxcbiAgICAgICAgY29ubmVjdG9yOiB0aGlzXG4gICAgfSk7XG4gICAgbWluZGVyLnBvc3RNZXNzYWdlKG1zZywgZGF0YSk7XG4gICAgaWYgKCEgX3JlY2VpdmVkTWVzc2FnZXMubGVuZ3RoICYmICEgX2lzUHJvcGFnYXRpbmcpIHtcbiAgICAgICAgXy5kZWZlcihfaWRsZUNoZWNrKTtcbiAgICAgICAgX2lzUHJvcGFnYXRpbmcgPSB0cnVlO1xuICAgIH1cblxuICAgIF9yZWNlaXZlZE1lc3NhZ2VzLnB1c2goeyBtc2c6IG1zZywgZGF0YTogZGF0YSB9KTtcbn1cblxuXG5mdW5jdGlvbiBfaWRsZUNoZWNrKCkge1xuICAgIGlmIChfcmVjZWl2ZWRNZXNzYWdlcy5sZW5ndGgpIHtcbiAgICAgICAgX3JlY2VpdmVkTWVzc2FnZXMubGVuZ3RoID0gMDtcbiAgICAgICAgXy5kZWZlcihfaWRsZUNoZWNrKTtcbiAgICAgICAgbWluZGVyLnBvc3RNZXNzYWdlKCdwcm9wYWdhdGlvbnRpY2tlZCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIF9pc1Byb3BhZ2F0aW5nID0gZmFsc2U7XG4gICAgICAgIG1pbmRlci5wb3N0TWVzc2FnZSgncHJvcGFnYXRpb25jb21wbGV0ZWQnKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gbWluZGVyX2lzUHJvcGFnYXRpbmcoKSB7XG4gICAgcmV0dXJuIF9pc1Byb3BhZ2F0aW5nO1xufVxuXG5cbmZ1bmN0aW9uIG1pbmRlcl93aGVuUHJvcGFnYXRpb25Db21wbGV0ZWQoY2FsbGJhY2spIHtcbiAgICBpZiAoX2lzUHJvcGFnYXRpbmcpXG4gICAgICAgIG1pbmRlci5vbmNlKCdwcm9wYWdhdGlvbmNvbXBsZXRlZCcsIGV4ZWN1dGVDYWxsYmFjayk7XG4gICAgZWxzZVxuICAgICAgICBfLmRlZmVyKGV4ZWN1dGVDYWxsYmFjayk7XG5cbiAgICBmdW5jdGlvbiBleGVjdXRlQ2FsbGJhY2soKSB7XG4gICAgICAgIGlmIChfaXNQcm9wYWdhdGluZylcbiAgICAgICAgICAgIG1pbmRlci5vbmNlKCdwcm9wYWdhdGlvbmNvbXBsZXRlZCcsIGV4ZWN1dGVDYWxsYmFjayk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIG1pbmRlcl9nZXRDb25uZWN0b3JzKG9uT2ZmKSB7XG4gICAgaWYgKHR5cGVvZiBvbk9mZiA9PSAndW5kZWZpbmVkJylcbiAgICAgICAgcmV0dXJuIF9jb25uZWN0b3JzO1xuXG4gICAgcmV0dXJuIF9jb25uZWN0b3JzLmZpbHRlcihmdW5jdGlvbihjbmN0KSB7XG4gICAgICAgIHJldHVybiBjbmN0LmlzT24gPT09IG9uT2ZmO1xuICAgIH0pO1xufVxuXG5cbmZ1bmN0aW9uIG1pbmRlcl9kZXN0cm95Q29ubmVjdG9yKGNuY3QpIHtcbiAgICBjbmN0LmRlc3Ryb3koKTtcbiAgICB2YXIgaW5kZXggPSBfY29ubmVjdG9ycy5pbmRleE9mKGNuY3QpO1xuICAgIGlmIChpbmRleCA+PSAwKVxuICAgICAgICBkZWxldGUgX2Nvbm5lY3RvcnNbaW5kZXhdO1xuICAgIGVsc2VcbiAgICAgICAgbG9nZ2VyLndhcm4oJ21pbmRlcjogY29ubmVjdG9yIGRlc3Ryb3llZCB0aGF0IGlzIG5vdCByZWdpc3RlcmVkIGluIG1pbmRlcicpO1xufVxuXG5cbmZ1bmN0aW9uIG1pbmRlcl9nZXRFeHBhbmRlZENvbm5lY3Rpb25zKG9uT2ZmLCBzZWFyY2hTdHIpIHtcbiAgICB2YXIgY29ubmVjdG9ycyA9IG1pbmRlci5nZXRDb25uZWN0b3JzKG9uT2ZmKTtcbiAgICB2YXIgY29ubmVjdGlvbnMgPSAgY29ubmVjdG9ycy5tYXAoZnVuY3Rpb24oY25jdCkge1xuICAgICAgICB2YXIgY29ubmVjdGlvbiA9IHtcbiAgICAgICAgICAgIGxlZnRTb3VyY2U6IF9nZXRFeHBhbmRlZFNvdXJjZShjbmN0LmRzMSksXG4gICAgICAgICAgICByaWdodFNvdXJjZTogX2dldEV4cGFuZGVkU291cmNlKGNuY3QuZHMyKSxcbiAgICAgICAgICAgIG1vZGU6IGNuY3QubW9kZSxcbiAgICAgICAgICAgIGlzT246IGNuY3QuaXNPblxuICAgICAgICB9O1xuICAgICAgICBcbiAgICAgICAgaWYgKGNuY3Qub3B0aW9ucylcbiAgICAgICAgICAgIGNvbm5lY3Rpb24ub3B0aW9ucyA9IGNuY3Qub3B0aW9ucztcblxuICAgICAgICByZXR1cm4gY29ubmVjdGlvbjtcbiAgICB9KTtcblxuICAgIGlmIChzZWFyY2hTdHIpXG4gICAgICAgIGNvbm5lY3Rpb25zID0gY29ubmVjdGlvbnMuZmlsdGVyKGZ1bmN0aW9uKGNuY3RuKSB7XG4gICAgICAgICAgICByZXR1cm4gX3NvdXJjZU1hdGNoZXNTdHJpbmcoY25jdG4ubGVmdFNvdXJjZSwgc2VhcmNoU3RyKVxuICAgICAgICAgICAgICAgICAgICB8fCBfc291cmNlTWF0Y2hlc1N0cmluZyhjbmN0bi5yaWdodFNvdXJjZSwgc2VhcmNoU3RyKTtcbiAgICAgICAgfSk7XG5cbiAgICByZXR1cm4gY29ubmVjdGlvbnM7XG59XG5cblxuZnVuY3Rpb24gX2dldEV4cGFuZGVkU291cmNlKGRzKSB7XG4gICAgdmFyIHNvdXJjZSA9IFtdO1xuICAgIGlmICh0eXBlb2YgZHMgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBpZiAoZHMuX21vZGVsICYmIGRzLl9hY2Nlc3NQYXRoKSB7XG4gICAgICAgICAgICBzb3VyY2UudW5zaGlmdChkcy5fYWNjZXNzUGF0aCk7XG4gICAgICAgICAgICBkcyA9IGRzLl9tb2RlbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHNvdXJjZS51bnNoaWZ0KGRzKTtcbiAgICAgICAgZHMgPSBkcy5faG9zdE9iamVjdDtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGRzID09ICdvYmplY3QnKSB7XG4gICAgICAgIHNvdXJjZS51bnNoaWZ0KGRzKTtcblxuICAgICAgICBpZiAoZHMub3duZXIpXG4gICAgICAgICAgICBzb3VyY2UudW5zaGlmdChkcy5vd25lcik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNvdXJjZTtcbn1cblxuXG5mdW5jdGlvbiBfc291cmNlTWF0Y2hlc1N0cmluZyhzb3VyY2UsIG1hdGNoU3RyKSB7XG4gICAgcmV0dXJuIHNvdXJjZS5zb21lKGZ1bmN0aW9uKHNyY05vZGUpIHtcbiAgICAgICAgdmFyIGNsYXNzTmFtZSA9IHNyY05vZGUuY29uc3RydWN0b3IgJiYgc3JjTm9kZS5jb25zdHJ1Y3Rvci5uYW1lO1xuICAgICAgICByZXR1cm4gX3N0cmluZ01hdGNoKGNsYXNzTmFtZSwgbWF0Y2hTdHIpXG4gICAgICAgICAgICAgICAgfHwgX3N0cmluZ01hdGNoKHNyY05vZGUubmFtZSwgbWF0Y2hTdHIpXG4gICAgICAgICAgICAgICAgfHwgX3N0cmluZ01hdGNoKHNyY05vZGUsIG1hdGNoU3RyKTtcbiAgICB9KTtcbn1cblxuXG5mdW5jdGlvbiBfc3RyaW5nTWF0Y2goc3RyLCBzdWJzdHIpIHtcbiAgICByZXR1cm4gc3RyICYmIHR5cGVvZiBzdHIgPT0gJ3N0cmluZycgJiYgc3RyLmluZGV4T2Yoc3Vic3RyKSA+PSAwO1xufVxuXG5cbmZ1bmN0aW9uIG1pbmRlcl9kZXN0cm95KCkge1xuICAgIF9jb25uZWN0b3JzLmZvckVhY2goZnVuY3Rpb24oY25jdCkge1xuICAgICAgICBkZXN0cm95RFMoY25jdC5kczEpO1xuICAgICAgICBkZXN0cm95RFMoY25jdC5kczIpO1xuICAgICAgICBjbmN0LmRlc3Ryb3koKTtcbiAgICB9KTtcbiAgICBfbWVzc2VuZ2VyLmRlc3Ryb3koKTtcbiAgICBtaW5kZXIuX2Rlc3Ryb3llZCA9IHRydWU7XG5cbiAgICBmdW5jdGlvbiBkZXN0cm95RFMoZHMpIHtcbiAgICAgICAgaWYgKGRzICYmICFkcy5fZGVzdHJveWVkKSBkcy5kZXN0cm95KCk7XG4gICAgfVxufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciBsb2dnZXIgPSByZXF1aXJlKCcuLi91dGlsL2xvZ2dlcicpXG4gICAgLCBjb25maWcgPSByZXF1aXJlKCcuLi9jb25maWcnKVxuICAgICwgcGF0aFV0aWxzID0gcmVxdWlyZSgnLi9wYXRoX3V0aWxzJylcbiAgICAsIF8gPSByZXF1aXJlKCdtb2wtcHJvdG8nKTtcblxuLyoqXG4gKiBVdGlsaXR5IGZ1bmN0aW9uIHRvIHByb2Nlc3MgXCJjaGFuZ2VkYXRhXCIgbWVzc2FnZXMgZW1pdHRlZCBieSBDb25uZWN0b3Igb2JqZWN0LlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGNoYW5nZURhdGFIYW5kbGVyO1xuXG5cbl8uZXh0ZW5kKGNoYW5nZURhdGFIYW5kbGVyLCB7XG4gICAgc2V0VHJhbnNhY3Rpb25GbGFnOiBzZXRUcmFuc2FjdGlvbkZsYWcsXG4gICAgZ2V0VHJhbnNhY3Rpb25GbGFnOiBnZXRUcmFuc2FjdGlvbkZsYWcsXG4gICAgcGFzc1RyYW5zYWN0aW9uRmxhZzogcGFzc1RyYW5zYWN0aW9uRmxhZyxcbiAgICBwb3N0VHJhbnNhY3Rpb25GaW5pc2hlZDogcG9zdFRyYW5zYWN0aW9uRmluaXNoZWRcbn0pO1xuXG5cbi8qKlxuICogQ2hhbmdlIGRhdGEgdXNlcyBoaWRkZW4gcHJvcGVydHkgb24gYWNjZXNzb3IgbWV0aG9kcyB0byBwYXNzIGZsYWcgdGhhdCB0aGUgYWNjZXNzb3IgaXMgZXhlY3V0ZWQgYXMgYSBwYXJ0IG9mIGNoYW5nZSB0cmFuc2FjdGlvbi5cbiAqIEFjY2Vzc29yIG1ldGhvZHMgYXJlIHN1cHBvc2VkIHRvIHN0b3JlIHRoaXMgZmxhZyBpbiBhIGxvY2FsIHZhcmlhYmxlIGFuZCB0byBjbGVhciBpdCAoYmVjYXVzZSBhbm90aGVyIGFjY2Vzc29yIGNhbiBiZSBleGVjdXRlZCBpbiBvciBvdXQgb2YgdHJhbnNhY3Rpb24pIHVzaW5nIGBnZXRUcmFuc2FjdGlvbkZsYWdgXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgYWNjZXNzb3IgbWV0aG9kIHJlZmVyZW5jZVxuICogQHBhcmFtIHtCb29sZWFufSBmbGFnIGEgZmxhZyB0byBiZSBzZXRcbiAqL1xuZnVuY3Rpb24gc2V0VHJhbnNhY3Rpb25GbGFnKGZ1bmMsIGZsYWcpIHtcbiAgICBfLmRlZmluZVByb3BlcnR5KGZ1bmMsICdfX2luQ2hhbmdlVHJhbnNhY3Rpb24nLCBmbGFnLCBfLkNPTkYgfCBfLldSSVQpO1xufVxuXG5cbi8qKlxuICogUmV0cmlldmVzIGFuZCBjbGVhcnMgdHJhbnNhY3Rpb24gZmxhZyBmcm9tIGFjY2Vzc29yIG1ldGhvZFxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIGFjY2Vzc29yIG1ldGhvZCByZWZlcmVuY2VcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIGdldFRyYW5zYWN0aW9uRmxhZyhmdW5jKSB7XG4gICAgdmFyIGluVHJhbnNhY3Rpb24gPSBmdW5jLl9faW5DaGFuZ2VUcmFuc2FjdGlvbjtcbiAgICBkZWxldGUgZnVuYy5fX2luQ2hhbmdlVHJhbnNhY3Rpb247XG4gICAgcmV0dXJuIGluVHJhbnNhY3Rpb247XG59XG5cblxuZnVuY3Rpb24gcGFzc1RyYW5zYWN0aW9uRmxhZyhmcm9tRnVuYywgdG9GdW5jKSB7XG4gICAgdmFyIGluVHJhbnNhY3Rpb24gPSBnZXRUcmFuc2FjdGlvbkZsYWcoZnJvbUZ1bmMpO1xuICAgIHNldFRyYW5zYWN0aW9uRmxhZyh0b0Z1bmMsIGluVHJhbnNhY3Rpb24pO1xuICAgIHJldHVybiBpblRyYW5zYWN0aW9uO1xufVxuXG5cbi8qKlxuICogUG9zdHMgbWVzc2FnZSBvbiB0aGlzIHRvIGluZGljYXRlIHRoZSBlbmQgb2YgdHJhbnNhY3Rpb24gdW5sZXNzIGBpbkNoYW5nZVRyYW5zYWN0aW9uYCBpcyBgdHJ1ZWAuXG4gKi9cbmZ1bmN0aW9uIHBvc3RUcmFuc2FjdGlvbkZpbmlzaGVkKCkge1xuICAgIHRoaXMucG9zdE1lc3NhZ2VTeW5jKCdkYXRhY2hhbmdlcycsIHsgdHJhbnNhY3Rpb246IGZhbHNlLCBjaGFuZ2VzOiBbXSB9KTtcbn1cblxuXG4vKipcbiAqIHN1YnNjcmliZXIgdG8gXCJjaGFuZ2VkYXRhXCIgZXZlbnQgZW1pdHRlZCBieSBbQ29ubmVjdG9yXSguL2Nvbm5lY3Rvci5qcy5odG1sKSBvYmplY3QgdG8gZW5hYmxlIHJlYWN0aXZlIGNvbm5lY3Rpb25zXG4gKiBVc2VkIGJ5IERhdGEgZmFjZXQsIE1vZGVsIGFuZCBNb2RlbFBhdGguIENhbiBiZSB1c2VkIGJ5IGFueSBvYmplY3QgdGhhdCBpbXBsZW1lbnRzIGdldC9zZXQvZGVsL3NwbGljZSBhcGkgYW5kIHNldHMgZGF0YSBkZWVwbHkgdG8gdGhlIHdob2xlIHRyZWUuXG4gKiBPYmplY3Qgc2hvdWxkIGNhbGwgYGNoYW5nZURhdGFIYW5kbGVyLmluaXRpYWxpemUuY2FsbCh0aGlzKWAgaW4gaXRzIGNvbnN0cnVjdG9yLlxuICogVE9ETzogb3B0aW1pemUgbWVzc2FnZXMgbGlzdCB0byBhdm9pZCBzZXR0aW5nIGR1cGxpY2F0ZSB2YWx1ZXMgZG93biB0aGUgdHJlZVxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtc2cgc2hvdWxkIGJlIFwiY2hhbmdlZGF0YVwiIGhlcmVcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIGJhdGNoIG9mIGRhdGEgY2hhbmdlIGRlc2NpcHRpb24gb2JqZWN0c1xuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgY2FsbGJhY2sgdG8gY2FsbCBiZWZvcmUgYW5kIGFmdGVyIHRoZSBkYXRhIGlzIHByb2Nlc3NlZFxuICovXG5mdW5jdGlvbiBjaGFuZ2VEYXRhSGFuZGxlcihtZXNzYWdlLCBkYXRhLCBjYWxsYmFjaykge1xuICAgIHByb2Nlc3NDaGFuZ2VzLmNhbGwodGhpcywgZGF0YS5jaGFuZ2VzLCBjYWxsYmFjayk7XG59XG5cblxuLy8gbWFwIG9mIG1lc3NhZ2UgdHlwZXMgdG8gbWV0aG9kc1xudmFyIENIQU5HRV9UWVBFX1RPX01FVEhPRF9NQVAgPSB7XG4gICAgJ2FkZGVkJzogICAnc2V0JyxcbiAgICAnY2hhbmdlZCc6ICdzZXQnLFxuICAgICdkZWxldGVkJzogJ2RlbCcsXG4gICAgJ3JlbW92ZWQnOiAnZGVsJ1xufTtcblxuXG4vKipcbiAqIFByb2Nlc3NlcyBxdWV1ZWQgXCJjaGFuZ2VkYXRhXCIgbWVzc2FnZXMuXG4gKiBQb3N0cyBcImNoYW5nZXN0YXJ0ZWRcIiBhbmQgXCJjaGFuZ2Vjb21wbGV0ZWRcIiBtZXNzYWdlcyBhbmQgY2FsbHMgY2FsbGJhY2tcbiAqXG4gKiBAcGFyYW0ge1tGdW5jdGlvbl19IGNhbGxiYWNrIG9wdGlvbmFsIGNhbGxiYWNrIHRoYXQgaXMgY2FsbGVkIHdpdGggYChudWxsLCBmYWxzZSlgIHBhcmFtZXRlcnMgYmVmb3JlIGNoYW5nZSBwcm9jZXNzaW5nIHN0YXJ0cyBhbmQgYChudWxsLCB0cnVlKWAgYWZ0ZXIgaXQncyBmaW5pc2hlZC5cbiAqL1xuZnVuY3Rpb24gcHJvY2Vzc0NoYW5nZXModHJhbnNhY3Rpb24sIGNhbGxiYWNrKSB7XG4gICAgbm90aWZ5LmNhbGwodGhpcywgY2FsbGJhY2ssIGZhbHNlKTtcbiAgICBwcm9jZXNzVHJhbnNhY3Rpb24uY2FsbCh0aGlzLFxuICAgICAgICBwcmVwYXJlVHJhbnNhY3Rpb24oXG4gICAgICAgICAgICB2YWxpZGF0ZVRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKSkpO1xuICAgIG5vdGlmeS5jYWxsKHRoaXMsIGNhbGxiYWNrLCB0cnVlKTtcbn1cblxuXG5mdW5jdGlvbiBub3RpZnkoY2FsbGJhY2ssIGNoYW5nZUZpbmlzaGVkKSB7XG4gICAgY2FsbGJhY2sgJiYgY2FsbGJhY2sobnVsbCwgY2hhbmdlRmluaXNoZWQpO1xuICAgIHRoaXMucG9zdE1lc3NhZ2UoY2hhbmdlRmluaXNoZWQgPyAnY2hhbmdlY29tcGxldGVkJyA6ICdjaGFuZ2VzdGFydGVkJyk7XG59XG5cblxuLyoqXG4gKiBDaGVja3MgdGhhdCBhbGwgbWVzc2FnZXMgZnJvbSB0aGUgdHJhbnNhY3Rpb24gY29tZSBmcm9tIHRoZSBzYW1lIHNvdXJjZS5cbiAqIEhhY2s6IHJldmVyc2VzIHRoZSB0cmFuc2FjdGlvbiBpZiBpdCBjb21lcyBmcm9tIHRoZSBEYXRhIGZhY2V0XG4gKiBSZXR1cm5zIHRoZSByZWZlcmVuY2UgdG8gdGhlIHRyYW5zYWN0aW9uIChmb3IgY2hhaW5pbmcpXG4gKiBcbiAqIEBwYXJhbSAge0FycmF5fSB0cmFuc2FjdGlvbiB0cmFuc2FjdGlvbiBvZiBkYXRhIGNoYW5nZXNcbiAqIEByZXR1cm4ge0FycmF5fSBcbiAqL1xuZnVuY3Rpb24gdmFsaWRhdGVUcmFuc2FjdGlvbih0cmFuc2FjdGlvbikge1xuICAgIHZhciBzb3VyY2UgPSB0cmFuc2FjdGlvblswXS5zb3VyY2VcbiAgICAgICAgLCBzYW1lU291cmNlID0gdHJ1ZTtcblxuICAgIGlmICh0cmFuc2FjdGlvbi5sZW5ndGggPiAxKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAxLCBsZW4gPSB0cmFuc2FjdGlvbi5sZW5ndGg7IGkgPCBsZW47IGkrKylcbiAgICAgICAgICAgIGlmICh0cmFuc2FjdGlvbltpXS5zb3VyY2UgIT0gc291cmNlKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCdjaGFuZ2VkYXRhOiBjaGFuZ2VzIGZyb20gZGlmZmVyZW50IHNvdXJjZXMgaW4gdGhlIHNhbWUgdHJhbnNhY3Rpb24sIHNvdXJjZXM6JywgdHJhbnNhY3Rpb25baV0uc291cmNlLm5hbWUsIHNvdXJjZS5uYW1lKTtcbiAgICAgICAgICAgICAgICBzYW1lU291cmNlID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgc291cmNlID0gdHJhbnNhY3Rpb25baV0uc291cmNlO1xuICAgICAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0cmFuc2FjdGlvbjtcbn1cblxuXG5mdW5jdGlvbiBwcmVwYXJlVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pIHtcbiAgICB2YXIgdG9kbyA9IFtdXG4gICAgICAgICwgcGF0aHNUb1NwbGljZSA9IFtdXG4gICAgICAgICwgcGF0aHNUb0NoYW5nZSA9IFtdXG4gICAgICAgICwgaGFkU3BsaWNlXG4gICAgICAgICwgZXhpdExvb3AgPSB7fTtcblxuXG4gICAgdHJ5IHsgdHJhbnNhY3Rpb24uZm9yRWFjaChjaGVja0NoYW5nZSk7IH1cbiAgICBjYXRjaCAoZSkgeyBpZiAoZSAhPSBleGl0TG9vcCkgdGhyb3cgZTsgfVxuXG4gICAgcmV0dXJuIHRvZG87XG5cblxuICAgIGZ1bmN0aW9uIGNoZWNrQ2hhbmdlKGRhdGEpIHtcbiAgICAgICAgKGRhdGEudHlwZSA9PSAnc3BsaWNlJyA/IGNoZWNrU3BsaWNlIDogY2hlY2tNZXRob2QpKGRhdGEpO1xuICAgIH1cblxuXG4gICAgZnVuY3Rpb24gY2hlY2tTcGxpY2UoZGF0YSkge1xuICAgICAgICB2YXIgcGFyc2VkUGF0aCA9IHBhdGhVdGlscy5wYXJzZUFjY2Vzc1BhdGgoZGF0YS5wYXRoKTtcbiAgICAgICAgdmFyIHBhcmVudFBhdGhDaGFuZ2VkID0gcGF0aHNUb0NoYW5nZS5zb21lKGZ1bmN0aW9uKHBhcmVudFBhdGgpIHtcbiAgICAgICAgICAgIGlmIChwYXJzZWRQYXRoLmxlbmd0aCA8IHBhcmVudFBhdGgubGVuZ3RoKSByZXR1cm47XG4gICAgICAgICAgICByZXR1cm4gX3BhdGhJc1BhcmVudE9mKHBhcmVudFBhdGgsIHBhcnNlZFBhdGgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAocGFyZW50UGF0aENoYW5nZWQpIHJldHVybjtcblxuICAgICAgICB0b2RvLnB1c2goZGF0YSk7XG5cbiAgICAgICAgaWYgKCEgY29uZmlnLmRlYnVnKSB0aHJvdyBleGl0TG9vcDtcbiAgICAgICAgcGF0aHNUb1NwbGljZS5wdXNoKHBhcnNlZFBhdGgpO1xuICAgICAgICBoYWRTcGxpY2UgPSB0cnVlO1xuICAgIH1cblxuXG4gICAgZnVuY3Rpb24gY2hlY2tNZXRob2QoZGF0YSkge1xuICAgICAgICB2YXIgcGFyc2VkUGF0aCA9IHBhdGhVdGlscy5wYXJzZUFjY2Vzc1BhdGgoZGF0YS5wYXRoKTtcbiAgICAgICAgdmFyIHBhcmVudFBhdGhTcGxpY2VkID0gcGF0aHNUb1NwbGljZSAmJiBwYXRoc1RvU3BsaWNlLnNvbWUoZnVuY3Rpb24ocGFyZW50UGF0aCkge1xuICAgICAgICAgICAgaWYgKHBhcnNlZFBhdGgubGVuZ3RoIDw9IHBhcmVudFBhdGgubGVuZ3RoXG4gICAgICAgICAgICAgICAgfHwgcGFyc2VkUGF0aFtwYXJlbnRQYXRoLmxlbmd0aF0uc3ludGF4ICE9ICdhcnJheScpIHJldHVybjtcbiAgICAgICAgICAgIHJldHVybiBfcGF0aElzUGFyZW50T2YocGFyZW50UGF0aCwgcGFyc2VkUGF0aCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChwYXJlbnRQYXRoU3BsaWNlZCkgcmV0dXJuO1xuICAgICAgICBpZiAoaGFkU3BsaWNlKSBsb2dnZXIuZXJyb3IoJ2NoYW5nZWRhdGE6IGNoaWxkIGNoYW5nZSBpcyBleGVjdXRlZCBhZnRlciBzcGxpY2U7IHByb2JhYmx5IGRhdGEgc291cmNlIGRpZCBub3QgZW1pdCBtZXNzYWdlIHdpdGggZGF0YS50eXBlPT1cImZpbmlzaGVkXCInKTtcblxuICAgICAgICB2YXIgcGFyZW50UGF0aENoYW5nZWQgPSBwYXRoc1RvQ2hhbmdlLnNvbWUoZnVuY3Rpb24ocGFyZW50UGF0aCkge1xuICAgICAgICAgICAgaWYgKHBhcnNlZFBhdGgubGVuZ3RoIDw9IHBhcmVudFBhdGgubGVuZ3RoKSByZXR1cm47XG4gICAgICAgICAgICByZXR1cm4gX3BhdGhJc1BhcmVudE9mKHBhcmVudFBhdGgsIHBhcnNlZFBhdGgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAocGFyZW50UGF0aENoYW5nZWQpIHJldHVybjtcblxuICAgICAgICBwYXRoc1RvQ2hhbmdlLnB1c2gocGFyc2VkUGF0aCk7XG5cbiAgICAgICAgdG9kby5wdXNoKGRhdGEpO1xuICAgIH1cblxuXG4gICAgZnVuY3Rpb24gX3BhdGhJc1BhcmVudE9mKHBhcmVudFBhdGgsIGNoaWxkUGF0aCkge1xuICAgICAgICByZXR1cm4gcGFyZW50UGF0aC5ldmVyeShmdW5jdGlvbihwYXRoTm9kZSwgaW5kZXgpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXRoTm9kZS5wcm9wZXJ0eSA9PSBjaGlsZFBhdGhbaW5kZXhdLnByb3BlcnR5O1xuICAgICAgICB9KTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gcHJvY2Vzc1RyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKSB7XG4gICAgdHJhbnNhY3Rpb24uZm9yRWFjaChwcm9jZXNzQ2hhbmdlLCB0aGlzKTtcbiAgICBwb3N0VHJhbnNhY3Rpb25GaW5pc2hlZC5jYWxsKHRoaXMsIGZhbHNlKTtcblxuICAgIGZ1bmN0aW9uIHByb2Nlc3NDaGFuZ2UoZGF0YSkge1xuICAgICAgICB2YXIgbW9kZWxQYXRoID0gdGhpcy5wYXRoKGRhdGEucGF0aCwgZGF0YS50eXBlICE9ICdyZW1vdmVkJyAmJiBkYXRhLnR5cGUgIT0gJ2RlbGV0ZWQnKTtcbiAgICAgICAgaWYgKCEgbW9kZWxQYXRoKSByZXR1cm47XG4gICAgICAgIChkYXRhLnR5cGUgPT0gJ3NwbGljZScgPyBleGVjdXRlU3BsaWNlIDogZXhlY3V0ZU1ldGhvZCkobW9kZWxQYXRoLCBkYXRhKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gZXhlY3V0ZVNwbGljZShtb2RlbFBhdGgsIGRhdGEpIHtcbiAgICB2YXIgaW5kZXggPSBkYXRhLmluZGV4XG4gICAgICAgICwgaG93TWFueSA9IGRhdGEucmVtb3ZlZC5sZW5ndGhcbiAgICAgICAgLCBzcGxpY2VBcmdzID0gW2luZGV4LCBob3dNYW55XTtcblxuICAgIHNwbGljZUFyZ3MgPSBzcGxpY2VBcmdzLmNvbmNhdChkYXRhLm5ld1ZhbHVlLnNsaWNlKGluZGV4LCBpbmRleCArIGRhdGEuYWRkZWRDb3VudCkpO1xuICAgIHNldFRyYW5zYWN0aW9uRmxhZyhtb2RlbFBhdGguc3BsaWNlLCB0cnVlKTtcbiAgICBtb2RlbFBhdGguc3BsaWNlLmFwcGx5KG1vZGVsUGF0aCwgc3BsaWNlQXJncyk7XG59XG5cblxuZnVuY3Rpb24gZXhlY3V0ZU1ldGhvZChtb2RlbFBhdGgsIGRhdGEpIHtcbiAgICB2YXIgbWV0aG9kTmFtZSA9IENIQU5HRV9UWVBFX1RPX01FVEhPRF9NQVBbZGF0YS50eXBlXTtcbiAgICBpZiAobWV0aG9kTmFtZSkge1xuICAgICAgICBzZXRUcmFuc2FjdGlvbkZsYWcobW9kZWxQYXRoW21ldGhvZE5hbWVdLCB0cnVlKTtcbiAgICAgICAgbW9kZWxQYXRoW21ldGhvZE5hbWVdKGRhdGEubmV3VmFsdWUpO1xuICAgIH0gZWxzZVxuICAgICAgICBsb2dnZXIuZXJyb3IoJ3Vua25vd24gZGF0YSBjaGFuZ2UgdHlwZScpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgTWVzc2VuZ2VyID0gcmVxdWlyZSgnLi4vbWVzc2VuZ2VyJylcbiAgICAsIHBhdGhVdGlscyA9IHJlcXVpcmUoJy4vcGF0aF91dGlscycpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGxvZ2dlciA9IHJlcXVpcmUoJy4uL3V0aWwvbG9nZ2VyJyk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBDb25uZWN0b3I7XG5cblxudmFyIG1vZGVQYXR0ZXJuID0gL14oXFw8KilcXC0rKFxcPiopJC87XG5cblxuLyoqXG4gKiBDb25uZWN0b3JcbiAqIENsYXNzIHRoYXQgY3JlYXRlcyBjb25uZWN0b3Igb2JqZWN0IGZvciBkYXRhIGNvbm5lY3Rpb24gYmV0d2VlblxuICogdHdvIGRhdGEtc291cmNlc1xuICogRGF0YS1zb3VyY2VzIHNob3VsZCBpbXBsZW1lbnQgdGhlIGZvbGxvd2luZyBBUEk6XG4gKiBnZXQoKSAtIGdldCB2YWx1ZSBmcm9tIGRhdGFzb3VyY2Ugb3IgaXRzIHBhdGhcbiAqIHNldCh2YWx1ZSkgLSBzZXQgdmFsdWUgdG8gZGF0YXNvdXJjZSBvciB0byBpdHMgcGF0aFxuICogb24ocGF0aCwgc3Vic2NyaWJlcikgLSBzdWJzY3JpcHRpb24gdG8gZGF0YSBjaGFuZ2VzIHdpdGggXCIqXCIgc3VwcG9ydFxuICogb2ZmKHBhdGgsIHN1YnNjcmliZXIpXG4gKiBwYXRoKGFjY2Vzc1BhdGgpIC0gdG8gcmV0dXJuIHRoZSBvYmplY3QgdGhhdCBnaXZlcyByZWZlcmVuY2UgdG8gc29tZSBwYXJ0IG9mIGRhdGFzb3VyY2VcbiAqIGFuZCBjb21wbGllcyB3aXRoIHRoYXQgYXBpIHRvby5cbiAqXG4gKiAjIyMjRXZlbnRzIyMjI1xuICpcbiAqIC0gJ3R1cm5lZG9uJyAtIGNvbm5lY3RvciB3YXMgdHVybmVkIG9uXG4gKiAtICd0dXJuZWRvZmYnIC0gY29ubmVjdG9yIHdhcyB0dXJuZWQgb2ZmXG4gKiAtICdjaGFuZ2VzdGFydGVkJyAtIGNoYW5nZSBvbiBjb25uZWN0ZWQgZGF0YXNvdXJjZSBpcyBzdGFydGVkXG4gKiAtICdjaGFuZ2Vjb21wbGV0ZWQnIC0gY2hhbmdlIG9uIGNvbm5lY3RlZCBkYXRhc291cmNlIGlzIGNvbXBsZXRlZFxuICogLSAnZGVzdHJveWVkJyAtIGNvbm5lY3RvciB3YXMgZGVzdHJveWVkXG4gKiBcbiAqIEBwYXJhbSB7T2JqZWN0fSBkczEgdGhlIGZpcnN0IGRhdGEgc291cmNlLlxuICogQHBhcmFtIHtTdHJpbmd9IG1vZGUgdGhlIGNvbm5lY3Rpb24gbW9kZSB0aGF0IGRlZmluZXMgdGhlIGRpcmVjdGlvbiBhbmQgdGhlIGRlcHRoIG9mIGNvbm5lY3Rpb24uIFBvc3NpYmxlIHZhbHVlcyBhcmUgJy0+JywgJzw8LScsICc8PDwtPj4+JywgZXRjLlxuICogQHBhcmFtIHtPYmplY3R9IGRzMiB0aGUgc2Vjb25kIGRhdGEgc291cmNlXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBub3QgaW1wbGVtZW50ZWQgeWV0XG4gKiBAcmV0dXJuIHtDb25uZWN0b3J9IHdoZW4gY2FsbGVkIHdpdGggYG5ld2AsIGNyZWF0ZXMgYSBDb25uZWN0b3Igb2JqZWN0LlxuICovXG5mdW5jdGlvbiBDb25uZWN0b3IoZHMxLCBtb2RlLCBkczIsIG9wdGlvbnMpIHtcbiAgICBzZXR1cE1vZGUuY2FsbCh0aGlzLCBtb2RlKTtcblxuICAgIF8uZXh0ZW5kKHRoaXMsIHtcbiAgICAgICAgZHMxOiBkczEsXG4gICAgICAgIGRzMjogZHMyLFxuICAgICAgICBpc09uOiBmYWxzZSxcbiAgICAgICAgX2NoYW5nZXNRdWV1ZTE6IFtdLFxuICAgICAgICBfY2hhbmdlc1F1ZXVlMjogW10sXG4gICAgICAgIF9tZXNzZW5nZXI6IG5ldyBNZXNzZW5nZXIodGhpcywgTWVzc2VuZ2VyLmRlZmF1bHRNZXRob2RzKVxuICAgIH0pO1xuXG4gICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICB2YXIgcGF0aFRyYW5zbGF0aW9uID0gb3B0aW9ucy5wYXRoVHJhbnNsYXRpb247XG4gICAgICAgIGlmIChwYXRoVHJhbnNsYXRpb24pIHtcbiAgICAgICAgICAgIHBhdGhUcmFuc2xhdGlvbiA9IF8uY2xvbmUocGF0aFRyYW5zbGF0aW9uKTtcbiAgICAgICAgICAgIHZhciBwYXR0ZXJuVHJhbnNsYXRpb24gPSBnZXRQYXR0ZXJuVHJhbnNsYXRpb25zKHBhdGhUcmFuc2xhdGlvbik7XG4gICAgICAgICAgICBfLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICAgICAgcGF0aFRyYW5zbGF0aW9uMTogcmV2ZXJzZVRyYW5zbGF0aW9uUnVsZXMocGF0aFRyYW5zbGF0aW9uKSxcbiAgICAgICAgICAgICAgICBwYXRoVHJhbnNsYXRpb24yOiBwYXRoVHJhbnNsYXRpb24sXG4gICAgICAgICAgICAgICAgcGF0dGVyblRyYW5zbGF0aW9uMTogcmV2ZXJzZVBhdHRlcm5UcmFuc2xhdGlvblJ1bGVzKHBhdHRlcm5UcmFuc2xhdGlvbiksXG4gICAgICAgICAgICAgICAgcGF0dGVyblRyYW5zbGF0aW9uMjogcGF0dGVyblRyYW5zbGF0aW9uXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBkYXRhVHJhbnNsYXRpb24gPSBvcHRpb25zLmRhdGFUcmFuc2xhdGlvbjtcbiAgICAgICAgaWYgKGRhdGFUcmFuc2xhdGlvbikge1xuICAgICAgICAgICAgXy5leHRlbmQodGhpcywge1xuICAgICAgICAgICAgICAgIGRhdGFUcmFuc2xhdGlvbjE6IGRhdGFUcmFuc2xhdGlvblsnPC0nXSxcbiAgICAgICAgICAgICAgICBkYXRhVHJhbnNsYXRpb24yOiBkYXRhVHJhbnNsYXRpb25bJy0+J11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGFWYWxpZGF0aW9uID0gb3B0aW9ucy5kYXRhVmFsaWRhdGlvbjtcbiAgICAgICAgaWYgKGRhdGFWYWxpZGF0aW9uKSB7XG4gICAgICAgICAgICBfLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICAgICAgZGF0YVZhbGlkYXRpb24xOiBkYXRhVmFsaWRhdGlvblsnPC0nXSxcbiAgICAgICAgICAgICAgICBkYXRhVmFsaWRhdGlvbjI6IGRhdGFWYWxpZGF0aW9uWyctPiddXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMudHVybk9uKCk7XG59XG5cblxuZnVuY3Rpb24gc2V0dXBNb2RlKG1vZGUpe1xuICAgIHZhciBwYXJzZWRNb2RlID0gbW9kZS5tYXRjaChtb2RlUGF0dGVybik7XG5cbiAgICBpZiAoISBwYXJzZWRNb2RlKVxuICAgICAgICBtb2RlUGFyc2VFcnJvcigpO1xuXG4gICAgdmFyIGRlcHRoMSA9IHBhcnNlZE1vZGVbMV0ubGVuZ3RoXG4gICAgICAgICwgZGVwdGgyID0gcGFyc2VkTW9kZVsyXS5sZW5ndGg7XG5cbiAgICBpZiAoZGVwdGgxICYmIGRlcHRoMiAmJiBkZXB0aDEgIT0gZGVwdGgyKVxuICAgICAgICBtb2RlUGFyc2VFcnJvcigpO1xuXG4gICAgaWYgKCEgZGVwdGgxICYmICEgZGVwdGgyKVxuICAgICAgICBtb2RlUGFyc2VFcnJvcigpO1xuXG4gICAgXy5leHRlbmQodGhpcywge1xuICAgICAgICBtb2RlOiBtb2RlLFxuICAgICAgICBkZXB0aDE6IGRlcHRoMSxcbiAgICAgICAgZGVwdGgyOiBkZXB0aDIsXG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiBtb2RlUGFyc2VFcnJvcigpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIENvbm5lY3RvciBtb2RlOiAnICsgbW9kZSk7XG4gICAgfVxufVxuXG5cbl8uZXh0ZW5kUHJvdG8oQ29ubmVjdG9yLCB7XG4gICAgdHVybk9uOiBDb25uZWN0b3IkdHVybk9uLFxuICAgIHR1cm5PZmY6IENvbm5lY3RvciR0dXJuT2ZmLFxuICAgIGRlc3Ryb3k6IENvbm5lY3RvciRkZXN0cm95LFxuICAgIGNoYW5nZU1vZGU6IENvbm5lY3RvciRjaGFuZ2VNb2RlLFxuICAgIGRlZmVyQ2hhbmdlTW9kZTogQ29ubmVjdG9yJGRlZmVyQ2hhbmdlTW9kZVxufSk7XG5cbi8qKlxuICogRnVuY3Rpb24gY2hhbmdlIHRoZSBtb2RlIG9mIHRoZSBjb25uZWN0aW9uXG4gKlxuICogQHBhcmFtIEBwYXJhbSB7U3RyaW5nfSBtb2RlIHRoZSBjb25uZWN0aW9uIG1vZGUgdGhhdCBkZWZpbmVzIHRoZSBkaXJlY3Rpb24gYW5kIHRoZSBkZXB0aCBvZiBjb25uZWN0aW9uLiBQb3NzaWJsZSB2YWx1ZXMgYXJlICctPicsICc8PC0nLCAnPDw8LT4+PicsIGV0Yy5cbiAqIEByZXR1cm4ge09iamVjdFtTdHJpbmddfVxuICovXG5mdW5jdGlvbiBDb25uZWN0b3IkY2hhbmdlTW9kZShtb2RlKSB7XG4gICAgdGhpcy50dXJuT2ZmKCk7XG4gICAgc2V0dXBNb2RlLmNhbGwodGhpcywgbW9kZSk7XG4gICAgdGhpcy50dXJuT24oKTtcbiAgICByZXR1cm4gdGhpcztcbn1cblxuXG4vKipcbiAqIEZ1bmN0aW9uIGNoYW5nZSB0aGUgbW9kZSBvZiB0aGUgY29ubmVjdGlvblxuICpcbiAqIEBwYXJhbSBAcGFyYW0ge1N0cmluZ30gbW9kZSB0aGUgY29ubmVjdGlvbiBtb2RlIHRoYXQgZGVmaW5lcyB0aGUgZGlyZWN0aW9uIGFuZCB0aGUgZGVwdGggb2YgY29ubmVjdGlvbi4gUG9zc2libGUgdmFsdWVzIGFyZSAnLT4nLCAnPDwtJywgJzw8PC0+Pj4nLCBldGMuXG4gKiBAcmV0dXJuIHtPYmplY3RbU3RyaW5nXX1cbiAqL1xuZnVuY3Rpb24gQ29ubmVjdG9yJGRlZmVyQ2hhbmdlTW9kZShtb2RlKSB7XG4gICAgXy5kZWZlck1ldGhvZCh0aGlzLCAnY2hhbmdlTW9kZScsIG1vZGUpO1xuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogRnVuY3Rpb24gdGhhdCByZXZlcnNlcyB0cmFuc2xhdGlvbiBydWxlcyBmb3IgcGF0aHMgb2YgY29ubmVjdGVkIG9kYXRhIHNvdXJjZXNcbiAqXG4gKiBAcGFyYW0ge09iamVjdFtTdHJpbmddfSBydWxlcyBtYXAgb2YgcGF0aHMgZGVmaW5pbmcgdGhlIHRyYW5zbGF0aW9uIHJ1bGVzXG4gKiBAcmV0dXJuIHtPYmplY3RbU3RyaW5nXX1cbiAqL1xuZnVuY3Rpb24gcmV2ZXJzZVRyYW5zbGF0aW9uUnVsZXMocnVsZXMpIHtcbiAgICB2YXIgcmV2ZXJzZVJ1bGVzID0ge307XG4gICAgXy5lYWNoS2V5KHJ1bGVzLCBmdW5jdGlvbihwYXRoMl92YWx1ZSwgcGF0aDFfa2V5KSB7XG4gICAgICAgIHJldmVyc2VSdWxlc1twYXRoMl92YWx1ZV0gPSBwYXRoMV9rZXk7XG4gICAgfSk7XG4gICAgcmV0dXJuIHJldmVyc2VSdWxlcztcbn1cblxuXG5mdW5jdGlvbiBnZXRQYXR0ZXJuVHJhbnNsYXRpb25zKHBhdGhUcmFuc2xhdGlvbikge1xuICAgIHZhciBwYXR0ZXJuVHJhbnNsYXRpb24gPSBbXTtcbiAgICBfLmVhY2hLZXkocGF0aFRyYW5zbGF0aW9uLCBmdW5jdGlvbihwYXRoMl92YWx1ZSwgcGF0aDFfa2V5KSB7XG4gICAgICAgIHZhciBzdGFySW5kZXgxID0gcGF0aDFfa2V5LmluZGV4T2YoJyonKVxuICAgICAgICAgICAgLCBzdGFySW5kZXgyID0gcGF0aDJfdmFsdWUuaW5kZXhPZignKicpO1xuICAgICAgICBpZiAoc3RhckluZGV4MSA+PSAwICYmIHN0YXJJbmRleDIgPj0gMCkgeyAvLyBwYXR0ZXJuIHRyYW5zbGF0aW9uXG4gICAgICAgICAgICBpZiAocGF0aDFfa2V5LnNsaWNlKHN0YXJJbmRleDEpICE9IHBhdGgyX3ZhbHVlLnNsaWNlKHN0YXJJbmRleDIpKVxuICAgICAgICAgICAgICAgIF90aHJvd0ludmFsaWRUcmFuc2xhdGlvbihwYXRoMV9rZXksIHBhdGgyX3ZhbHVlKTtcbiAgICAgICAgICAgIGRlbGV0ZSBwYXRoVHJhbnNsYXRpb25bcGF0aDFfa2V5XTsgICAgICAgICAgICBcblxuICAgICAgICAgICAgcGF0dGVyblRyYW5zbGF0aW9uLnB1c2goe1xuICAgICAgICAgICAgICAgIGZyb21QYXR0ZXJuOiBwYXRoVXRpbHMuY3JlYXRlUmVnZXhQYXRoKHBhdGgxX2tleSksXG4gICAgICAgICAgICAgICAgZnJvbVN0YXRpY1BhdGg6IF9nZXRTdGF0aWNQYXRoKHBhdGgxX2tleSwgc3RhckluZGV4MSksXG4gICAgICAgICAgICAgICAgdG9QYXR0ZXJuOiBwYXRoVXRpbHMuY3JlYXRlUmVnZXhQYXRoKHBhdGgyX3ZhbHVlKSxcbiAgICAgICAgICAgICAgICB0b1N0YXRpY1BhdGg6IF9nZXRTdGF0aWNQYXRoKHBhdGgyX3ZhbHVlLCBzdGFySW5kZXgyKVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoc3RhckluZGV4MSA+PSAwIHx8IHN0YXJJbmRleDIgPj0gMCkgLy8gcGF0dGVybiBvbmx5IG9uIG9uZSBzaWRlIG9mIHRyYW5zbGF0aW9uXG4gICAgICAgICAgICBfdGhyb3dJbnZhbGlkVHJhbnNsYXRpb24ocGF0aDFfa2V5LCBwYXRoMl92YWx1ZSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gcGF0dGVyblRyYW5zbGF0aW9uO1xuXG5cbiAgICBmdW5jdGlvbiBfdGhyb3dJbnZhbGlkVHJhbnNsYXRpb24ocGF0aDEsIHBhdGgyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBwYXR0ZXJuIHRyYW5zbGF0aW9uOiAnICsgcGF0aDEgKyAnLCAnICsgcGF0aDIpO1xuICAgIH1cblxuXG4gICAgZnVuY3Rpb24gX2dldFN0YXRpY1BhdGgocGF0aCwgc3RhckluZGV4KSB7XG4gICAgICAgIHJldHVybiBwYXRoLnJlcGxhY2UoL1tcXC5cXFtdP1xcKi4qJC8sICcnKTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gcmV2ZXJzZVBhdHRlcm5UcmFuc2xhdGlvblJ1bGVzKHBhdHRlcm5UcmFuc2xhdGlvbikge1xuICAgIHJldHVybiBwYXR0ZXJuVHJhbnNsYXRpb24ubWFwKGZ1bmN0aW9uKHB0KSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBmcm9tUGF0dGVybjogcHQudG9QYXR0ZXJuLFxuICAgICAgICAgICAgZnJvbVN0YXRpY1BhdGg6IHB0LnRvU3RhdGljUGF0aCxcbiAgICAgICAgICAgIHRvUGF0dGVybjogcHQuZnJvbVBhdHRlcm4sXG4gICAgICAgICAgICB0b1N0YXRpY1BhdGg6IHB0LmZyb21TdGF0aWNQYXRoXG4gICAgICAgIH07XG4gICAgfSk7XG59XG5cblxuLyoqXG4gKiB0dXJuT25cbiAqIE1ldGhvZCBvZiBDb25uZWN0b3IgdGhhdCBlbmFibGVzIGNvbm5lY3Rpb24gKGlmIGl0IHdhcyBwcmV2aW91c2x5IGRpc2FibGVkKVxuICovXG5mdW5jdGlvbiBDb25uZWN0b3IkdHVybk9uKCkge1xuICAgIGlmICh0aGlzLmlzT24pXG4gICAgICAgIHJldHVybiBsb2dnZXIud2FybignZGF0YSBzb3VyY2VzIGFyZSBhbHJlYWR5IGNvbm5lY3RlZCcpO1xuXG4gICAgdmFyIHN1YnNjcmlwdGlvblBhdGggPSB0aGlzLl9zdWJzY3JpcHRpb25QYXRoID1cbiAgICAgICAgbmV3IEFycmF5KHRoaXMuZGVwdGgxIHx8IHRoaXMuZGVwdGgyKS5qb2luKCcqJyk7XG5cbiAgICB2YXIgc3Vic2NyaXB0aW9uUGF0dGVybiA9IHBhdGhVdGlscy5jcmVhdGVSZWdleFBhdGgoc3Vic2NyaXB0aW9uUGF0aCk7XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgaWYgKHRoaXMuZGVwdGgxKVxuICAgICAgICB0aGlzLl9saW5rMSA9IGxpbmtEYXRhU291cmNlKCdfbGluazInLCB0aGlzLmRzMiwgdGhpcy5kczEsIHRoaXMuX2NoYW5nZXNRdWV1ZTEsIHRoaXMucGF0aFRyYW5zbGF0aW9uMSwgdGhpcy5wYXR0ZXJuVHJhbnNsYXRpb24xLCB0aGlzLmRhdGFUcmFuc2xhdGlvbjEsIHRoaXMuZGF0YVZhbGlkYXRpb24xKTtcbiAgICBpZiAodGhpcy5kZXB0aDIpXG4gICAgICAgIHRoaXMuX2xpbmsyID0gbGlua0RhdGFTb3VyY2UoJ19saW5rMScsIHRoaXMuZHMxLCB0aGlzLmRzMiwgdGhpcy5fY2hhbmdlc1F1ZXVlMiwgdGhpcy5wYXRoVHJhbnNsYXRpb24yLCB0aGlzLnBhdHRlcm5UcmFuc2xhdGlvbjIsIHRoaXMuZGF0YVRyYW5zbGF0aW9uMiwgdGhpcy5kYXRhVmFsaWRhdGlvbjIpO1xuXG4gICAgdGhpcy5pc09uID0gdHJ1ZTtcbiAgICB0aGlzLnBvc3RNZXNzYWdlKCd0dXJuZWRvbicpO1xuXG5cbiAgICBmdW5jdGlvbiBsaW5rRGF0YVNvdXJjZShyZXZlcnNlTGluaywgZnJvbURTLCB0b0RTLCBjaGFuZ2VzUXVldWUsIHBhdGhUcmFuc2xhdGlvbiwgcGF0dGVyblRyYW5zbGF0aW9uLCBkYXRhVHJhbnNsYXRpb24sIGRhdGFWYWxpZGF0aW9uKSB7XG4gICAgICAgIGZyb21EUy5vblN5bmMoJ2RhdGFjaGFuZ2VzJywgb25EYXRhKTtcbiAgICAgICAgcmV0dXJuIG9uRGF0YTtcblxuICAgICAgICBmdW5jdGlvbiBvbkRhdGEobWVzc2FnZSwgYmF0Y2gpIHtcbiAgICAgICAgICAgIHZhciBzZW5kRGF0YSA9IHtcbiAgICAgICAgICAgICAgICBjaGFuZ2VzOiBbXSxcbiAgICAgICAgICAgICAgICB0cmFuc2FjdGlvbjogYmF0Y2gudHJhbnNhY3Rpb25cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgYmF0Y2guY2hhbmdlcy5mb3JFYWNoKGZ1bmN0aW9uKGNoYW5nZSkge1xuICAgICAgICAgICAgICAgIHZhciBzb3VyY2VQYXRoID0gY2hhbmdlLnBhdGhcbiAgICAgICAgICAgICAgICAgICAgLCB0YXJnZXRQYXRoID0gdHJhbnNsYXRlUGF0aChzb3VyY2VQYXRoKTtcblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdGFyZ2V0UGF0aCA9PSAndW5kZWZpbmVkJykgcmV0dXJuO1xuXG4gICAgICAgICAgICAgICAgdmFyIGNoYW5nZSA9IF8uY2xvbmUoY2hhbmdlKTtcbiAgICAgICAgICAgICAgICBfLmV4dGVuZChjaGFuZ2UsIHtcbiAgICAgICAgICAgICAgICAgICAgc291cmNlOiBmcm9tRFMsXG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHRhcmdldFBhdGhcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIHRyYW5zbGF0ZURhdGEoc291cmNlUGF0aCwgY2hhbmdlKTtcbiAgICAgICAgICAgICAgICB2YWxpZGF0ZURhdGEoc291cmNlUGF0aCwgY2hhbmdlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBpZiAoISBjaGFuZ2VzUXVldWUubGVuZ3RoKVxuICAgICAgICAgICAgICAgIF8uZGVmZXIocG9zdENoYW5nZURhdGEpO1xuXG4gICAgICAgICAgICBjaGFuZ2VzUXVldWUucHVzaChzZW5kRGF0YSk7XG5cblxuICAgICAgICAgICAgZnVuY3Rpb24gdHJhbnNsYXRlUGF0aChzb3VyY2VQYXRoKSB7XG4gICAgICAgICAgICAgICAgaWYgKHBhdGhUcmFuc2xhdGlvbikge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdHJhbnNsYXRlZFBhdGggPSBwYXRoVHJhbnNsYXRpb25bc291cmNlUGF0aF07XG4gICAgICAgICAgICAgICAgICAgIGlmICh0cmFuc2xhdGVkUGF0aCkgcmV0dXJuIHRyYW5zbGF0ZWRQYXRoO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXBhdHRlcm5UcmFuc2xhdGlvbi5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHB0ID0gXy5maW5kKHBhdHRlcm5UcmFuc2xhdGlvbiwgZnVuY3Rpb24ocFRyYW5zbGF0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcFRyYW5zbGF0aW9uLmZyb21QYXR0ZXJuLnRlc3Qoc291cmNlUGF0aCk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXB0KSByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIHZhciB0cmFuc2xhdGVkUGF0aCA9IHNvdXJjZVBhdGgucmVwbGFjZShwdC5mcm9tU3RhdGljUGF0aCwgcHQudG9TdGF0aWNQYXRoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCEgKChzdWJzY3JpcHRpb25QYXR0ZXJuIGluc3RhbmNlb2YgUmVnRXhwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmJiBzdWJzY3JpcHRpb25QYXR0ZXJuLnRlc3Qoc291cmNlUGF0aCkpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8fCBzdWJzY3JpcHRpb25QYXR0ZXJuID09IHNvdXJjZVBhdGgpKSByZXR1cm47XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdHJhbnNsYXRlZFBhdGggfHwgc291cmNlUGF0aDtcbiAgICAgICAgICAgIH1cblxuXG4gICAgICAgICAgICBmdW5jdGlvbiB0cmFuc2xhdGVEYXRhKHNvdXJjZVBhdGgsIGNoYW5nZSkge1xuICAgICAgICAgICAgICAgIGlmIChkYXRhVHJhbnNsYXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRyYW5zbGF0ZSA9IGRhdGFUcmFuc2xhdGlvbltzb3VyY2VQYXRoXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRyYW5zbGF0ZSAmJiB0eXBlb2YgdHJhbnNsYXRlID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNoYW5nZS5vbGRWYWx1ZSA9IHRyYW5zbGF0ZShjaGFuZ2Uub2xkVmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2hhbmdlLm5ld1ZhbHVlID0gdHJhbnNsYXRlKGNoYW5nZS5uZXdWYWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICBcbiAgICAgICAgICAgIGZ1bmN0aW9uIHZhbGlkYXRlRGF0YShzb3VyY2VQYXRoLCBjaGFuZ2UpIHtcbiAgICAgICAgICAgICAgICBwcm9wYWdhdGVEYXRhKGNoYW5nZSk7XG5cbiAgICAgICAgICAgICAgICBpZiAoZGF0YVZhbGlkYXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhbGlkYXRvcnMgPSBkYXRhVmFsaWRhdGlvbltzb3VyY2VQYXRoXVxuICAgICAgICAgICAgICAgICAgICAgICAgLCBwYXNzZWRDb3VudCA9IDBcbiAgICAgICAgICAgICAgICAgICAgICAgICwgYWxyZWFkeUZhaWxlZCA9IGZhbHNlO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICh2YWxpZGF0b3JzKVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFsaWRhdG9ycy5mb3JFYWNoKGNhbGxWYWxpZGF0b3IpOyAgIFxuICAgICAgICAgICAgICAgIH1cblxuXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gY2FsbFZhbGlkYXRvcih2YWxpZGF0b3IpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsaWRhdG9yKGNoYW5nZS5uZXdWYWx1ZSwgZnVuY3Rpb24oZXJyLCByZXNwb25zZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2UucGF0aCA9IHNvdXJjZVBhdGg7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoISBhbHJlYWR5RmFpbGVkICYmIChlcnIgfHwgcmVzcG9uc2UudmFsaWQpICYmICsrcGFzc2VkQ291bnQgPT0gdmFsaWRhdG9ycy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tRFMucG9zdE1lc3NhZ2UoJ3ZhbGlkYXRlZCcsIHJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoISByZXNwb25zZS52YWxpZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscmVhZHlGYWlsZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyb21EUy5wb3N0TWVzc2FnZSgndmFsaWRhdGVkJywgcmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cblxuICAgICAgICAgICAgZnVuY3Rpb24gcHJvcGFnYXRlRGF0YShjaGFuZ2UpIHtcbiAgICAgICAgICAgICAgICBzZW5kRGF0YS5jaGFuZ2VzLnB1c2goY2hhbmdlKTtcbiAgICAgICAgICAgIH1cblxuXG4gICAgICAgICAgICBmdW5jdGlvbiBwb3N0Q2hhbmdlRGF0YSgpIHtcbiAgICAgICAgICAgICAgICAvLyBwcmV2ZW50IGVuZGxlc3MgbG9vcCBvZiB1cGRhdGVzIGZvciAyLXdheSBjb25uZWN0aW9uXG4gICAgICAgICAgICAgICAgaWYgKHNlbGZbcmV2ZXJzZUxpbmtdKSB2YXIgY2FsbGJhY2sgPSBzdWJzY3JpcHRpb25Td2l0Y2g7XG5cbiAgICAgICAgICAgICAgICB2YXIgdHJhbnNhY3Rpb25zID0gbWVyZ2VUcmFuc2FjdGlvbnMoY2hhbmdlc1F1ZXVlKTtcbiAgICAgICAgICAgICAgICBjaGFuZ2VzUXVldWUubGVuZ3RoID0gMDtcbiAgICAgICAgICAgICAgICB0cmFuc2FjdGlvbnMuZm9yRWFjaChmdW5jdGlvbih0cmFuc2FjdGlvbikge1xuICAgICAgICAgICAgICAgICAgICAvLyBzZW5kIGRhdGEgY2hhbmdlIGluc3RydWN0aW9uIGFzIG1lc3NhZ2VcbiAgICAgICAgICAgICAgICAgICAgdG9EUy5wb3N0TWVzc2FnZVN5bmMoJ2NoYW5nZWRhdGEnLCB7IGNoYW5nZXM6IHRyYW5zYWN0aW9uIH0sIGNhbGxiYWNrKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuXG4gICAgICAgICAgICBmdW5jdGlvbiBzdWJzY3JpcHRpb25Td2l0Y2goZXJyLCBjaGFuZ2VGaW5pc2hlZCkge1xuICAgICAgICAgICAgICAgIGlmIChlcnIpIHJldHVybjtcbiAgICAgICAgICAgICAgICB2YXIgb25PZmYgPSBjaGFuZ2VGaW5pc2hlZCA/ICdvblN5bmMnIDogJ29mZic7XG4gICAgICAgICAgICAgICAgdG9EU1tvbk9mZl0oJ2RhdGFjaGFuZ2VzJywgc2VsZltyZXZlcnNlTGlua10pO1xuXG4gICAgICAgICAgICAgICAgdmFyIG1lc3NhZ2UgPSBjaGFuZ2VGaW5pc2hlZCA/ICdjaGFuZ2Vjb21wbGV0ZWQnIDogJ2NoYW5nZXN0YXJ0ZWQnO1xuICAgICAgICAgICAgICAgIHNlbGYucG9zdE1lc3NhZ2UobWVzc2FnZSwgeyBzb3VyY2U6IGZyb21EUywgdGFyZ2V0OiB0b0RTIH0pO1xuICAgICAgICAgICAgfVxuXG5cbiAgICAgICAgICAgIGZ1bmN0aW9uIG1lcmdlVHJhbnNhY3Rpb25zKGJhdGNoZXMpIHtcbiAgICAgICAgICAgICAgICB2YXIgdHJhbnNhY3Rpb25zID0gW11cbiAgICAgICAgICAgICAgICAgICAgLCBjdXJyZW50VHJhbnNhY3Rpb247XG5cbiAgICAgICAgICAgICAgICBiYXRjaGVzLmZvckVhY2goZnVuY3Rpb24oYmF0Y2gpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEgYmF0Y2gudHJhbnNhY3Rpb24pIGN1cnJlbnRUcmFuc2FjdGlvbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEgYmF0Y2guY2hhbmdlcy5sZW5ndGgpIHJldHVybjtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoYmF0Y2gudHJhbnNhY3Rpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50VHJhbnNhY3Rpb24pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXy5hcHBlbmRBcnJheShjdXJyZW50VHJhbnNhY3Rpb24sIGJhdGNoLmNoYW5nZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudFRyYW5zYWN0aW9uID0gXy5jbG9uZShiYXRjaC5jaGFuZ2VzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2FjdGlvbnMucHVzaChjdXJyZW50VHJhbnNhY3Rpb24pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9IGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zYWN0aW9ucy5wdXNoKGJhdGNoLmNoYW5nZXMpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRyYW5zYWN0aW9ucztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn1cblxuXG4vKipcbiAqIHR1cm5PZmZcbiAqIE1ldGhvZCBvZiBDb25uZWN0b3IgdGhhdCBkaXNhYmxlcyBjb25uZWN0aW9uIChpZiBpdCB3YXMgcHJldmlvdXNseSBlbmFibGVkKVxuICovXG5mdW5jdGlvbiBDb25uZWN0b3IkdHVybk9mZigpIHtcbiAgICBpZiAoISB0aGlzLmlzT24pXG4gICAgICAgIHJldHVybiBsb2dnZXIud2FybignZGF0YSBzb3VyY2VzIGFyZSBhbHJlYWR5IGRpc2Nvbm5lY3RlZCcpO1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHVubGlua0RhdGFTb3VyY2UodGhpcy5kczEsICdfbGluazInLCB0aGlzLnBhdGhUcmFuc2xhdGlvbjIpO1xuICAgIHVubGlua0RhdGFTb3VyY2UodGhpcy5kczIsICdfbGluazEnLCB0aGlzLnBhdGhUcmFuc2xhdGlvbjEpO1xuXG4gICAgdGhpcy5pc09uID0gZmFsc2U7XG4gICAgdGhpcy5wb3N0TWVzc2FnZSgndHVybmVkb2ZmJyk7XG5cblxuICAgIGZ1bmN0aW9uIHVubGlua0RhdGFTb3VyY2UoZnJvbURTLCBsaW5rTmFtZSwgcGF0aFRyYW5zbGF0aW9uKSB7XG4gICAgICAgIGlmIChzZWxmW2xpbmtOYW1lXSkge1xuICAgICAgICAgICAgZnJvbURTLm9mZignZGF0YWNoYW5nZXMnLCBzZWxmW2xpbmtOYW1lXSk7XG4gICAgICAgICAgICBkZWxldGUgc2VsZltsaW5rTmFtZV07XG4gICAgICAgIH1cbiAgICB9XG59XG5cblxuLyoqXG4gKiBEZXN0cm95cyBjb25uZWN0b3Igb2JqZWN0IGJ5IHR1cm5pbmcgaXQgb2ZmIGFuZCByZW1vdmluZyByZWZlcmVuY2VzIHRvIGNvbm5lY3RlZCBzb3VyY2VzXG4gKi9cbmZ1bmN0aW9uIENvbm5lY3RvciRkZXN0cm95KCkge1xuICAgIHRoaXMudHVybk9mZigpO1xuICAgIHRoaXMucG9zdE1lc3NhZ2UoJ2Rlc3Ryb3llZCcpO1xuICAgIHRoaXMuX21lc3Nlbmdlci5kZXN0cm95KCk7XG4gICAgZGVsZXRlIHRoaXMuZHMxO1xuICAgIGRlbGV0ZSB0aGlzLmRzMjtcbiAgICB0aGlzLl9kZXN0cm95ZWQgPSB0cnVlO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgTW9kZWxQYXRoID0gcmVxdWlyZSgnLi9tX3BhdGgnKVxuICAgICwgc3ludGhlc2l6ZSA9IHJlcXVpcmUoJy4vc3ludGhlc2l6ZScpXG4gICAgLCBwYXRoVXRpbHMgPSByZXF1aXJlKCcuL3BhdGhfdXRpbHMnKVxuICAgICwgbW9kZWxVdGlscyA9IHJlcXVpcmUoJy4vbW9kZWxfdXRpbHMnKVxuICAgICwgY2hhbmdlRGF0YUhhbmRsZXIgPSByZXF1aXJlKCcuL2NoYW5nZV9kYXRhJylcbiAgICAsIE1lc3NlbmdlciA9IHJlcXVpcmUoJy4uL21lc3NlbmdlcicpXG4gICAgLCBNZXNzZW5nZXJNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi4vbWVzc2VuZ2VyL21zbmdyX3NvdXJjZScpXG4gICAgLCBNb2RlbE1zZ0FQSSA9IHJlcXVpcmUoJy4vbV9tc2dfYXBpJylcbiAgICAsIE1peGluID0gcmVxdWlyZSgnLi4vYWJzdHJhY3QvbWl4aW4nKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjaGVjayA9IHJlcXVpcmUoJy4uL3V0aWwvY2hlY2snKVxuICAgICwgTWF0Y2ggPSBjaGVjay5NYXRjaFxuICAgICwgbG9nZ2VyID0gcmVxdWlyZSgnLi4vdXRpbC9sb2dnZXInKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1vZGVsO1xuXG5cbi8qKlxuICogYG1pbG8uTW9kZWxgXG4gKiBNb2RlbCBjbGFzcyBpbnN0YW50aWF0ZXMgb2JqZWN0cyB0aGF0IGFsbG93IGRlZXAgZGF0YSBhY2Nlc3Mgd2l0aCBfX3NhZmUgZ2V0dGVyc19fIHRoYXQgcmV0dXJuIHVuZGVmaW5lZCAocmF0aGVyIHRoYW4gdGhyb3dpbmcgZXhjZXB0aW9uKSB3aGVuIHByb3BlcnRpZXMvaXRlbXMgb2YgdW5leGlzdGluZyBvYmplY3RzL2FycmF5cyBhcmUgcmVxdWVzdGVkIGFuZCBfX3NhZmUgc2V0dGVyc19fIHRoYXQgY3JlYXRlIG9iamVjdCB0cmVlcyB3aGVuIHByb3BlcnRpZXMvaXRlbXMgb2YgdW5leGlzdGluZyBvYmplY3RzL2FycmF5cyBhcmUgc2V0IGFuZCBhbHNvIHBvc3QgbWVzc2FnZXMgdG8gYWxsb3cgc3Vic2NyaXB0aW9uIG9uIGNoYW5nZXMgYW5kIGVuYWJsZSBkYXRhIHJlYWN0aXZpdHkuXG4gKiBSZWFjdGl2aXR5IGlzIGltcGxlbWVtbnRlZCB2aWEgW0Nvbm5lY3Rvcl0oLi9jb25uZWN0b3IuanMuaHRtbCkgdGhhdCBjYW4gYmUgaW5zdGFudGlhdGVkIGVpdGhlciBkaXJlY3RseSBvciB3aXRoIG1vcmUgY29udmVuaWVudCBpbnRlcmZhY2Ugb2YgW21pbG8ubWluZGVyXSguLi9taW5kZXIuanMuaHRtbCkuIEF0IHRoZSBtb21lbnQgbW9kZWwgY2FuIGJlIGNvbm5lY3RlZCB0byBbRGF0YSBmYWNldF0oLi4vY29tcG9uZW50cy9jX2ZhY2V0cy9EYXRhLmpzLmh0bWwpIG9yIHRvIGFub3RoZXIgbW9kZWwgb3IgW01vZGVsUGF0aF0oLi9tX3BhdGguanMuaHRtbCkuXG4gKiBNb2RlbCBjb25zdHJ1Y3RvciByZXR1cm5zIG9iamVjdHMgdGhhdCBhcmUgZnVuY3Rpb25zIGF0IHRoZSBzYW1lIHRpbWU7IHdoZW4gY2FsbGVkIHRoZXkgcmV0dXJuIE1vZGVsUGF0aCBvYmplY3RzIHRoYXQgYWxsb3cgZ2V0L3NldCBhY2Nlc3MgdG8gYW55IHBvaW50IGluIG1vZGVsIGRhdGEuIFNlZSBbTW9kZWxEYXRhXSgjTW9kZWxEYXRhKSBiZWxvdy5cbiAqXG4gKiBZb3UgY2FuIHN1YnNjcmliZSB0byBtb2RlbCBjaGFuZ2VzIHdpdGggYG9uYCBtZXRob2QgYnkgcGFzc2luZyBtb2RlbCBhY2Nlc3MgcGF0aCBpbiBwbGFjZSBvZiBtZXNzYWdlLCBwYXR0ZXJuIG9yIHN0cmluZyB3aXRoIGFueSBudW1iZXIgb2Ygc3RhcnMgdG8gc3Vic2NyaWJlIHRvIGEgY2VydGFpbiBkZXB0aCBpbiBtb2RlbCAoZS5nLiwgYCcqKionYCB0byBzdWJzY3JpYmUgdG8gdGhyZWUgbGV2ZWxzKS5cbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBkYXRhIG9wdGlvbmFsIGluaXRpYWwgYXJyYXkgZGF0YS4gSWYgaXQgaXMgcGxhbm5lZCB0byBjb25uZWN0IG1vZGVsIHRvIHZpZXcgaXQgaXMgdXN1YWxseSBiZXR0ZXIgdG8gaW5zdGFudGlhdGUgYW4gZW1wdHkgTW9kZWwgKGB2YXIgbSA9IG5ldyBNb2RlbGApLCBjb25uZWN0IGl0IHRvIFtDb21wb25lbnRdKC4uL2NvbXBvbmVudHMvY19jbGFzcy5qcy5odG1sKSdzIFtEYXRhIGZhY2V0XSguLi9jb21wb25lbnRzL2NfZmFjZXRzL0RhdGEuanMuaHRtbCkgKGUuZy4sIGBtaWxvLm1pbmRlcihtLCAnPDwtPj4nLCBjLmRhdGEpO2ApIGFuZCB0aGVuIHNldCB0aGUgbW9kZWwgd2l0aCBgbS5zZXQoZGF0YSlgIC0gdGhlIHZpZXcgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQuXG4gKiBAcGFyYW0ge09iamVjdH0gaG9zdE9iamVjdCBvcHRpb25hbCBvYmplY3QgdGhhdCBob3N0cyBtb2RlbCBvbiBvbmUgb2YgaXRzIHByb3BlcnRpZXMuIENhbiBiZSB1c2VkIHdoZW4gbW9kZWwgaXRzZWxmIGlzIHRoZSBjb250ZXh0IG9mIHRoZSBtZXNzYWdlIHN1YnNjcmliZXIgYW5kIHlvdSBuZWVkIHRvIHRyYXZlcnMgdG8gdGhpcyBvYmplY3QgKGFsdGhvdWdoIGl0IGlzIHBvc3NpYmxlIHRvIHNldCBhbnkgY29udGV4dCkuIENhbiBhbHNvIGJlIHVzZWQgdG8gcHJveHkgbW9kZWwncyBtZXRob2RzIHRvIHRoZSBob3N0IGxpa2UgW01vZGVsIGZhY2V0XSguLi9jb21wb25lbnRzL2NfZmFjZXRzL01vZGVsRmFjZXQuanMuaHRtbCkgaXMgZG9pbmcuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBwYXNzIHsgcmVhY3RpdmU6IGZhbHNlIH0gdG8gdXNlIG1vZGVsIHdpdGhvdXQgbWVzc2FnaW5nIHdoZW4gaXQgaXMgbm90IG5lZWRlZCAtIGl0IG1ha2VzIGl0IG11Y2ggZmFzdGVyXG4gKiBAcmV0dXJuIHtNb2RlbH1cbiAqL1xuZnVuY3Rpb24gTW9kZWwoZGF0YSwgaG9zdE9iamVjdCwgb3B0aW9ucykge1xuICAgIC8vIGBtb2RlbGAgd2lsbCBiZSByZXR1cm5lZCBieSBjb25zdHJ1Y3RvciBpbnN0ZWFkIG9mIGB0aGlzYC4gYG1vZGVsYFxuICAgIC8vIChgbW9kZWxQYXRoYCBmdW5jdGlvbikgc2hvdWxkIHJldHVybiBhIE1vZGVsUGF0aCBvYmplY3Qgd2l0aCBcInN5bnRoZXNpemVkXCIgbWV0aG9kc1xuICAgIC8vIHRvIGdldC9zZXQgbW9kZWwgcHJvcGVydGllcywgdG8gc3Vic2NyaWJlIHRvIHByb3BlcnR5IGNoYW5nZXMsIGV0Yy5cbiAgICAvLyBBZGRpdGlvbmFsIGFyZ3VtZW50cyBvZiBtb2RlbFBhdGggY2FuIGJlIHVzZWQgaW4gdGhlIHBhdGggdXNpbmcgaW50ZXJwb2xhdGlvbiAtIHNlZSBNb2RlbFBhdGggYmVsb3cuXG4gICAgdmFyIG1vZGVsID0gZnVuY3Rpb24gbW9kZWxQYXRoKGFjY2Vzc1BhdGgpIHsgLy8gLCAuLi4gYXJndW1lbnRzIHRoYXQgd2lsbCBiZSBpbnRlcnBvbGF0ZWRcbiAgICAgICAgcmV0dXJuIE1vZGVsJHBhdGguYXBwbHkobW9kZWwsIGFyZ3VtZW50cyk7XG4gICAgfTtcbiAgICBtb2RlbC5fX3Byb3RvX18gPSBNb2RlbC5wcm90b3R5cGU7XG5cbiAgICBtb2RlbC5faG9zdE9iamVjdCA9IGhvc3RPYmplY3Q7XG4gICAgbW9kZWwuX29wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgaWYgKG1vZGVsLl9vcHRpb25zLnJlYWN0aXZlICE9PSBmYWxzZSkge1xuICAgICAgICBtb2RlbC5fcHJlcGFyZU1lc3NlbmdlcnMoKTtcbiAgICAgICAgLy8gc3Vic2NyaWJlIHRvIFwiY2hhbmdlZGF0YVwiIG1lc3NhZ2UgdG8gZW5hYmxlIHJlYWN0aXZlIGNvbm5lY3Rpb25zXG4gICAgICAgIG1vZGVsLm9uU3luYygnY2hhbmdlZGF0YScsIGNoYW5nZURhdGFIYW5kbGVyKTtcbiAgICB9XG5cbiAgICBpZiAoZGF0YSkgbW9kZWwuX2RhdGEgPSBkYXRhO1xuXG4gICAgcmV0dXJuIG1vZGVsO1xufVxuXG5Nb2RlbC5wcm90b3R5cGUuX19wcm90b19fID0gTW9kZWwuX19wcm90b19fO1xuXG5cbi8qKlxuICogIyMjI01vZGVsIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbcGF0aF0oI3BhdGgpIC0gcmV0dXJucyBNb2RlbFBhdGggb2JqZWN0IHRoYXQgYWxsb3dzIGFjY2VzcyB0byBhbnkgcG9pbnQgaW4gTW9kZWxcbiAqIC0gW2dldF0oI01vZGVsJGdldCkgLSBnZXQgbW9kZWwgZGF0YVxuICogLSBzZXQgLSBzZXQgbW9kZWwgZGF0YSwgc3ludGhlc2l6ZWRcbiAqIC0gc3BsaWNlIC0gc3BsaWNlIG1vZGVsIGRhdGEgKGFzIGFycmF5IG9yIHBzZXVkby1hcnJheSksIHN5bnRoZXNpemVkXG4gKiAtIFtsZW5dKC4vbV9wYXRoLmpzLmh0bWwjTW9kZWxQYXRoJGxlbikgLSByZXR1cm5zIGxlbmd0aCBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KSBpbiBtb2RlbCBpbiBzYWZlIHdheSwgMCBpZiBubyBsZW5ndGggaXMgc2V0XG4gKiAtIFtwdXNoXSguL21fcGF0aC5qcy5odG1sI01vZGVsUGF0aCRwdXNoKSAtIGFkZCBpdGVtcyB0byB0aGUgZW5kIG9mIGFycmF5IChvciBwc2V1ZG8tYXJyYXkpIGluIG1vZGVsXG4gKiAtIFtwb3BdKC4vbV9wYXRoLmpzLmh0bWwjTW9kZWxQYXRoJHBvcCkgLSByZW1vdmUgaXRlbSBmcm9tIHRoZSBlbmQgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gbW9kZWxcbiAqIC0gW3Vuc2hpZnRdKC4vbV9wYXRoLmpzLmh0bWwjTW9kZWxQYXRoJHVuc2hpZnQpIC0gYWRkIGl0ZW1zIHRvIHRoZSBiZWdpbm5pbmcgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gbW9kZWxcbiAqIC0gW3NoaWZ0XSguL21fcGF0aC5qcy5odG1sI01vZGVsUGF0aCRzaGlmdCkgLSByZW1vdmUgaXRlbSBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gbW9kZWxcbiAqIC0gW3Byb3h5TWVzc2VuZ2VyXSgjcHJveHlNZXNzZW5nZXIpIC0gcHJveHkgbW9kZWwncyBNZXNzZW5nZXIgbWV0aG9kcyB0byBob3N0IG9iamVjdFxuICogLSBbcHJveHlNZXRob2RzXSgjcHJveHlNZXRob2RzKSAtIHByb3h5IG1vZGVsIG1ldGhvZHMgdG8gaG9zdCBvYmplY3RcbiAqL1xuXy5leHRlbmRQcm90byhNb2RlbCwge1xuICAgIHBhdGg6IE1vZGVsJHBhdGgsXG4gICAgZ2V0OiBNb2RlbCRnZXQsXG4gICAgcHJveHlNZXNzZW5nZXI6IHByb3h5TWVzc2VuZ2VyLCAvLyBkZXByZWNhdGVkLCBzaG91bGQgbm90IGJlIHVzZWRcbiAgICBwcm94eU1ldGhvZHM6IHByb3h5TWV0aG9kcyxcbiAgICBfcHJlcGFyZU1lc3NlbmdlcnM6IF9wcmVwYXJlTWVzc2VuZ2VycyxcbiAgICBfZ2V0SG9zdE9iamVjdDogX2dldEhvc3RPYmplY3QsXG4gICAgZGVzdHJveTogTW9kZWwkZGVzdHJveVxufSk7XG5cbi8vIHNldCwgZGVsLCBzcGxpY2UgYXJlIGFkZGVkIHRvIG1vZGVsXG5fLmV4dGVuZFByb3RvKE1vZGVsLCBzeW50aGVzaXplLm1vZGVsTWV0aG9kcyk7XG5cblxuLyoqXG4gKiAtIFBhdGg6IE1vZGVsUGF0aCBjbGFzcyBhcyBgbWlsby5Nb2RlbC5QYXRoYFxuICovXG5fLmV4dGVuZChNb2RlbCwge1xuICAgIFBhdGg6IE1vZGVsUGF0aCxcbiAgICB1c2VXaXRoOiBNb2RlbCQkdXNlV2l0aCxcbiAgICBfdXRpbHM6IHtcbiAgICAgICAgcGF0aDogcGF0aFV0aWxzLFxuICAgICAgICBtb2RlbDogbW9kZWxVdGlscyxcbiAgICAgICAgY2hhbmdlRGF0YUhhbmRsZXI6IGNoYW5nZURhdGFIYW5kbGVyXG4gICAgfVxufSk7XG5cblxuLyoqXG4gKiBFeHBvc2UgTWVzc2VuZ2VyIG1ldGhvZHMgb24gRmFjZXQgcHJvdG90eXBlXG4gKi9cbnZhciBNRVNTRU5HRVJfUFJPUEVSVFkgPSAnX21lc3Nlbmdlcic7XG5NZXNzZW5nZXIudXNlV2l0aChNb2RlbCwgTUVTU0VOR0VSX1BST1BFUlRZLCBNZXNzZW5nZXIuZGVmYXVsdE1ldGhvZHMpO1xuXG5cbi8qKlxuICogTW9kZWxQYXRoIG1ldGhvZHMgYWRkZWQgdG8gTW9kZWwgcHJvdG90eXBlXG4gKi9cblsnbGVuJywgJ3B1c2gnLCAncG9wJywgJ3Vuc2hpZnQnLCAnc2hpZnQnXS5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICB2YXIgbWV0aG9kID0gTW9kZWxQYXRoLnByb3RvdHlwZVttZXRob2ROYW1lXTtcbiAgICBfLmRlZmluZVByb3BlcnR5KE1vZGVsLnByb3RvdHlwZSwgbWV0aG9kTmFtZSwgbWV0aG9kKTtcbn0pO1xuXG5cbi8qKlxuICogTW9kZWwgaW5zdGFuY2UgbWV0aG9kLlxuICogR2V0IG1vZGVsIGRhdGEuXG4gKlxuICogQHJldHVybiB7QW55fVxuICovXG5mdW5jdGlvbiBNb2RlbCRnZXQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGE7XG59XG5cblxuLyoqXG4gKiBNb2RlbCBpbnN0YW5jZSBtZXRob2QuXG4gKiBSZXR1cm5zIE1vZGVsUGF0aCBvYmplY3QgdGhhdCBpbXBsZW1lbnRzIHRoZSBzYW1lIEFQSSBhcyBtb2RlbCBidXQgYWxsb3dzIGFjY2VzcyB0byBhbnkgcG9pbnQgaW5zaWRlIG1vZGVsIGFzIGRlZmluZWQgYnkgYGFjY2Vzc1BhdGhgLlxuICogU2VlIFtNb2RlbFBhdGhdKC4vbV9wYXRoLmpzLmh0bWwpIGNsYXNzIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBhY2Nlc3NQYXRoIHN0cmluZyB0aGF0IGRlZmluZXMgcGF0aCB0byBhY2Nlc3MgbW9kZWwuXG4gKiAgUGF0aCBzdHJpbmcgY29uc2lzdHMgb2YgcGFydHMgdG8gZGVmaW5lIGVpdGhlciBwcm9wZXJ0eSBhY2Nlc3MgKGBcIi5uYW1lXCJgIHRvIGFjY2VzcyBwcm9wZXJ0eSBuYW1lKSBvciBhcnJheSBpdGVtIGFjY2VzcyAoYFwiWzFdXCJgIHRvIGFjY2VzcyBpdGVtIHdpdGggaW5kZXggMSkuXG4gKiAgQWNjZXNzIHBhdGggY2FuIGNvbnRhaW4gYXMgbWFueSBwYXJ0cyBhcyBuZWNlc3NhcnkgKGUuZy4gYFwiLmxpc3RbMF0ubmFtZVwiYCB0byBhY2Nlc3MgcHJvcGVydHkgYG5hbWVgIGluIHRoZSBmaXJzdCBlbGVtZW50IG9mIGFycmF5IHN0b3JlZCBpbiBwcm9wZXJ0eSBgbGlzdGAuXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBhZGRpdGlvbmFsIGFyZ3VtZW50cyBvZiB0aGlzIG1ldGhvZCBjYW4gYmUgdXNlZCB0byBjcmVhdGUgaW50ZXJwb2xhdGVkIHBhdGhzLlxuICogIEUuZy4gYG0ucGF0aChcIlskMV0uJDJcIiwgaWQsIHByb3ApYCByZXR1cm5zIE1vZGVsUGF0aCB0byBhY2Nlc3MgcHJvcGVydHkgd2l0aCBuYW1lIGBwcm9wYCBpbiBhcnJheSBpdGVtIHdpdGggaW5kZXggYGlkYC4gQWx0aG91Z2ggdGhpcyBNb2RlbFBhdGggb2JqZWN0IHdpbGwgd29yayBleGFjdGx5IGFzIGBtKFwiW1wiICsgaWQgKyBcIl0uXCIgKyBwcm9wKWAsIHRoZSBpbnRlcnBvbGF0ZWQgaXMgbXVjaCBtb3JlIGVmZmljaWVudCBhcyBNb2RlbFBhdGggd2l0aCBpbnRlcnBvbGF0aW9uIHdpbGwgbm90IHN5bnRoZXNpemUgbmV3IGdldHRlcnMgYW5kIHNldHRlcnMsIHdoaWxlIE1vZGVsUGF0aCB3aXRoIGNvbXB1dGVkIGFjY2VzcyBwYXRoIHdpbGwgc3ludGhlc2l6ZSBuZXcgZ2V0dGVycyBhbmQgc2V0dGVycyBmb3IgZWFjaCBwYWlyIG9mIHZhbHVlcyBvZiBgaWRgIGFuZCBgcHJvcGAuXG4gKiBAcmV0dXJuIHtNb2RlbFBhdGh9XG4gKi9cbmZ1bmN0aW9uIE1vZGVsJHBhdGgoYWNjZXNzUGF0aCkgeyAgLy8gLCAuLi4gYXJndW1lbnRzIHRoYXQgd2lsbCBiZSBpbnRlcnBvbGF0ZWRcbiAgICBpZiAoISBhY2Nlc3NQYXRoKSByZXR1cm4gdGhpcztcblxuICAgIC8vIFwibnVsbFwiIGlzIGNvbnRleHQgdG8gcGFzcyB0byBNb2RlbFBhdGgsIGZpcnN0IHBhcmFtZXRlciBvZiBiaW5kXG4gICAgLy8gXCJ0aGlzXCIgKG1vZGVsKSBpcyBhZGRlZCBpbiBmcm9udCBvZiBhbGwgYXJndW1lbnRzXG4gICAgXy5zcGxpY2UoYXJndW1lbnRzLCAwLCAwLCBudWxsLCB0aGlzKTtcblxuICAgIC8vIGNhbGxpbmcgTW9kZWxQYXRoIGNvbnN0cnVjdG9yIHdpdGggbmV3IGFuZCB0aGUgbGlzdCBvZiBhcmd1bWVudHM6IHRoaXMgKG1vZGVsKSwgYWNjZXNzUGF0aCwgLi4uXG4gICAgcmV0dXJuIG5ldyAoRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQuYXBwbHkoTW9kZWxQYXRoLCBhcmd1bWVudHMpKTtcbn1cblxuXG4vKipcbiAqIE1vZGVsIGluc3RhbmNlIG1ldGhvZC5cbiAqIFByb3h5IG1vZGVsJ3MgTWVzc2VuZ2VyIG1ldGhvZHMgdG8gaG9zdCBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG1vZGVsSG9zdE9iamVjdCBvcHRpb25hbCBob3N0IG9iamVjdC4gSWYgbm90IHBhc3NlZCwgaG9zdE9iamVjdCBwYXNzZWQgdG8gTW9kZWwgY29uc3RydWN0b3Igd2lsbCBiZSB1c2VkLlxuICovXG5mdW5jdGlvbiBwcm94eU1lc3Nlbmdlcihtb2RlbEhvc3RPYmplY3QpIHtcbiAgICBtb2RlbEhvc3RPYmplY3QgPSBtb2RlbEhvc3RPYmplY3QgfHwgdGhpcy5faG9zdE9iamVjdDtcbiAgICBNaXhpbi5wcm90b3R5cGUuX2NyZWF0ZVByb3h5TWV0aG9kcy5jYWxsKHRoaXNbTUVTU0VOR0VSX1BST1BFUlRZXSwgTWVzc2VuZ2VyLmRlZmF1bHRNZXRob2RzLCBtb2RlbEhvc3RPYmplY3QpO1xufVxuXG5cbnZhciBtb2RlbE1ldGhvZHNUb1Byb3h5ID0gWydwYXRoJywgJ2dldCcsICdzZXQnLCAnZGVsJywgJ3NwbGljZScsICdsZW4nLCAncHVzaCcsICdwb3AnLCAndW5zaGlmdCcsICdzaGlmdCddO1xuXG5cbi8qKlxuICogRXhwb3NlIG1vZGVsIG1ldGhvZHMgb25cbiAqIFNlZSBzYW1lIG1ldGhvZCBpbiBNaXhpbiBjbGFzcyBmb3IgcGFyYW1ldGVycyBtZWFuaW5nXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gaG9zdENsYXNzXG4gKiBAcGFyYW0ge1t0eXBlXX0gaW5zdGFuY2VLZXlcbiAqIEBwYXJhbSB7W3R5cGVdfSBtaXhpbk1ldGhvZHMgb3B0aW9uYWxcbiAqL1xuZnVuY3Rpb24gTW9kZWwkJHVzZVdpdGgoaG9zdENsYXNzLCBpbnN0YW5jZUtleSwgbWl4aW5NZXRob2RzKSB7XG4gICAgbWl4aW5NZXRob2RzID0gbWl4aW5NZXRob2RzIHx8IG1vZGVsTWV0aG9kc1RvUHJveHk7XG4gICAgTWl4aW4udXNlV2l0aC5jYWxsKE1vZGVsLCBob3N0Q2xhc3MsIGluc3RhbmNlS2V5LCBtaXhpbk1ldGhvZHMpO1xufVxuXG5cbi8qKlxuICogTW9kZWwgaW5zdGFuY2UgbWV0aG9kLlxuICogUHJveHkgbW9kZWwgbWV0aG9kcyB0byBob3N0IG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gbW9kZWxIb3N0T2JqZWN0IG9wdGlvbmFsIGhvc3Qgb2JqZWN0LiBJZiBub3QgcGFzc2VkLCBob3N0T2JqZWN0IHBhc3NlZCB0byBNb2RlbCBjb25zdHJ1Y3RvciB3aWxsIGJlIHVzZWQuXG4gKi9cbmZ1bmN0aW9uIHByb3h5TWV0aG9kcyhtb2RlbEhvc3RPYmplY3QpIHtcbiAgICBtb2RlbEhvc3RPYmplY3QgPSBtb2RlbEhvc3RPYmplY3QgfHwgdGhpcy5faG9zdE9iamVjdDtcbiAgICBNaXhpbi5wcm90b3R5cGUuX2NyZWF0ZVByb3h5TWV0aG9kcy5jYWxsKHRoaXMsIG1vZGVsTWV0aG9kc1RvUHJveHksIG1vZGVsSG9zdE9iamVjdCk7XG59XG5cblxuLyoqXG4gKiBNb2RlbCBpbnN0YW5jZSBtZXRob2QuXG4gKiBDcmVhdGUgYW5kIGNvbm5lY3QgaW50ZXJuYWwgYW5kIGV4dGVybmFsIG1vZGVsJ3MgbWVzc2VuZ2Vycy5cbiAqIEV4dGVybmFsIG1lc3NlbmdlcidzIG1ldGhvZHMgYXJlIHByb3hpZWQgb24gdGhlIG1vZGVsIGFuZCB0aGV5IGFsbG93cyBcIipcIiBzdWJzY3JpcHRpb25zLlxuICovXG5mdW5jdGlvbiBfcHJlcGFyZU1lc3NlbmdlcnMoKSB7XG4gICAgLy8gbW9kZWwgd2lsbCBwb3N0IGFsbCBpdHMgY2hhbmdlcyBvbiBpbnRlcm5hbCBtZXNzZW5nZXJcbiAgICB2YXIgaW50ZXJuYWxNZXNzZW5nZXIgPSBuZXcgTWVzc2VuZ2VyKHRoaXMsIHVuZGVmaW5lZCwgdW5kZWZpbmVkKTtcblxuICAgIC8vIG1lc3NhZ2Ugc291cmNlIHRvIGNvbm5lY3QgaW50ZXJuYWwgbWVzc2VuZ2VyIHRvIGV4dGVybmFsXG4gICAgdmFyIGludGVybmFsTWVzc2VuZ2VyU291cmNlID0gbmV3IE1lc3Nlbmdlck1lc3NhZ2VTb3VyY2UodGhpcywgdW5kZWZpbmVkLCBuZXcgTW9kZWxNc2dBUEksIGludGVybmFsTWVzc2VuZ2VyKTtcblxuICAgIC8vIGV4dGVybmFsIG1lc3NlbmdlciB0byB3aGljaCBhbGwgbW9kZWwgdXNlcnMgd2lsbCBzdWJzY3JpYmUsXG4gICAgLy8gdGhhdCB3aWxsIGFsbG93IFwiKlwiIHN1YnNjcmlwdGlvbnMgYW5kIHN1cHBvcnQgXCJjaGFuZ2VkYXRhXCIgbWVzc2FnZSBhcGkuXG4gICAgdmFyIGV4dGVybmFsTWVzc2VuZ2VyID0gbmV3IE1lc3Nlbmdlcih0aGlzLCB1bmRlZmluZWQsIGludGVybmFsTWVzc2VuZ2VyU291cmNlKTtcblxuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgTUVTU0VOR0VSX1BST1BFUlRZLCBleHRlcm5hbE1lc3Nlbmdlcik7XG4gICAgXy5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnX2ludGVybmFsTWVzc2VuZ2VyJywgaW50ZXJuYWxNZXNzZW5nZXIpO1xufVxuXG5cbmZ1bmN0aW9uIF9nZXRIb3N0T2JqZWN0KCkge1xuICAgIHJldHVybiB0aGlzLl9ob3N0T2JqZWN0O1xufVxuXG5cbmZ1bmN0aW9uIE1vZGVsJGRlc3Ryb3koKSB7XG4gICAgdGhpc1tNRVNTRU5HRVJfUFJPUEVSVFldLmRlc3Ryb3koKTtcbiAgICB0aGlzLl9pbnRlcm5hbE1lc3Nlbmdlci5kZXN0cm95KCk7XG4gICAgdGhpcy5fZGVzdHJveWVkID0gdHJ1ZTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIE1lc3NlbmdlclJlZ2V4cEFQSSA9IHJlcXVpcmUoJy4uL21lc3Nlbmdlci9tX2FwaV9yeCcpXG4gICAgLCBwYXRoVXRpbHMgPSByZXF1aXJlKCcuL3BhdGhfdXRpbHMnKVxuICAgICwgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbi8qKlxuICogU3ViY2xhc3Mgb2YgTWVzc2VuZ2VyUmVnZXhwQVBJIHRoYXQgaXMgdXNlZCB0byB0cmFuc2xhdGUgbWVzc2FnZXMgb2YgZXh0ZXJuYWwgbWVzc2VuZ2VyIG9mIE1vZGVsIHRvIGludGVybmFsIG1lc3NlbmdlciBvZiBNb2RlbC5cbiAqL1xudmFyIE1vZGVsTXNnQVBJID0gXy5jcmVhdGVTdWJjbGFzcyhNZXNzZW5nZXJSZWdleHBBUEksICdNb2RlbE1zZ0FQSScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1vZGVsTXNnQVBJO1xuXG5cbi8qKlxuICogIyMjI01vZGVsTXNnQVBJIGluc3RhbmNlIG1ldGhvZHMjIyMjXG4gKlxuICogLSBbdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlXSgjdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKSAtIHRyYW5zbGF0ZXMgc3Vic2NyaXB0aW9uIHBhdGhzIHdpdGggXCIqXCJzIHRvIHJlZ2V4LCBsZWF2aW5nIG90aGVyIHN0cmluZ3MgdW50b3VjaGVkXG4gKi9cbl8uZXh0ZW5kUHJvdG8oTW9kZWxNc2dBUEksIHtcbiAgICB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2U6IHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZSxcbn0pO1xuXG5cbi8qKlxuICogTW9kZWxNc2dBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBUcmFuc2xhdGVzIHN1YnNjcmlwdGlvbiBwYXRocyB3aXRoIFwiKlwicyB0byByZWdleCwgbGVhdmluZyBvdGhlciBzdHJpbmdzIHVudG91Y2hlZC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gYWNjZXNzUGF0aCByZWxhdGl2ZSBhY2Nlc3MgcGF0aCB0byBiZSB0cmFuc2xhdGVkXG4gKiBAcmV0dXJuIHtSZWdFeHB8U3RyaW5nfVxuICovXG5mdW5jdGlvbiB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2UoYWNjZXNzUGF0aCkge1xuICAgIGlmIChhY2Nlc3NQYXRoIGluc3RhbmNlb2YgUmVnRXhwKSByZXR1cm4gYWNjZXNzUGF0aDtcblxuICAgIHJldHVybiBwYXRoVXRpbHMuY3JlYXRlUmVnZXhQYXRoKGFjY2Vzc1BhdGgpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgc3ludGhlc2l6ZSA9IHJlcXVpcmUoJy4vc3ludGhlc2l6ZScpXG4gICAgLCBwYXRoVXRpbHMgPSByZXF1aXJlKCcuL3BhdGhfdXRpbHMnKVxuICAgICwgY2hhbmdlRGF0YUhhbmRsZXIgPSByZXF1aXJlKCcuL2NoYW5nZV9kYXRhJylcbiAgICAsIE1lc3NlbmdlciA9IHJlcXVpcmUoJy4uL21lc3NlbmdlcicpXG4gICAgLCBNb2RlbFBhdGhNc2dBUEkgPSByZXF1aXJlKCcuL3BhdGhfbXNnX2FwaScpXG4gICAgLCBNZXNzZW5nZXJNZXNzYWdlU291cmNlID0gcmVxdWlyZSgnLi4vbWVzc2VuZ2VyL21zbmdyX3NvdXJjZScpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gTW9kZWxQYXRoO1xuXG5cbi8qKlxuICogYG1pbG8uTW9kZWwuUGF0aGBcbiAqIE1vZGVsUGF0aCBvYmplY3QgdGhhdCBhbGxvd3MgYWNjZXNzIHRvIGFueSBwb2ludCBpbnNpZGUgW01vZGVsXSguL2luZGV4LmpzLmh0bWwpIGFzIGRlZmluZWQgYnkgYGFjY2Vzc1BhdGhgXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAcGFyYW0ge01vZGVsfSBtb2RlbCBNb2RlbCBpbnN0YW5jZSB0aGF0IE1vZGVsUGF0aCBnaXZlcyBhY2Nlc3MgdG8uXG4gKiBAcGFyYW0ge1N0cmluZ30gYWNjZXNzUGF0aCBzdHJpbmcgdGhhdCBkZWZpbmVzIHBhdGggdG8gYWNjZXNzIG1vZGVsLlxuICogIFBhdGggc3RyaW5nIGNvbnNpc3RzIG9mIHBhcnRzIHRvIGRlZmluZSBlaXRoZXIgcHJvcGVydHkgYWNjZXNzIChgXCIubmFtZVwiYCB0byBhY2Nlc3MgcHJvcGVydHkgbmFtZSkgb3IgYXJyYXkgaXRlbSBhY2Nlc3MgKGBcIlsxXVwiYCB0byBhY2Nlc3MgaXRlbSB3aXRoIGluZGV4IDEpLlxuICogIEFjY2VzcyBwYXRoIGNhbiBjb250YWluIGFzIG1hbnkgcGFydHMgYXMgbmVjZXNzYXJ5IChlLmcuIGBcIi5saXN0WzBdLm5hbWVcImAgdG8gYWNjZXNzIHByb3BlcnR5IGBuYW1lYCBpbiB0aGUgZmlyc3QgZWxlbWVudCBvZiBhcnJheSBzdG9yZWQgaW4gcHJvcGVydHkgYGxpc3RgLlxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgYWRkaXRpb25hbCBhcmd1bWVudHMgb2YgdGhpcyBtZXRob2QgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGludGVycG9sYXRlZCBwYXRocy5cbiAqICBFLmcuIGBtLnBhdGgoXCJbJDFdLiQyXCIsIGlkLCBwcm9wKWAgcmV0dXJucyBNb2RlbFBhdGggdG8gYWNjZXNzIHByb3BlcnR5IHdpdGggbmFtZSBgcHJvcGAgaW4gYXJyYXkgaXRlbSB3aXRoIGluZGV4IGBpZGAuIEFsdGhvdWdoIHRoaXMgTW9kZWxQYXRoIG9iamVjdCB3aWxsIHdvcmsgZXhhY3RseSBhcyBgbShcIltcIiArIGlkICsgXCJdLlwiICsgcHJvcClgLCB0aGUgaW50ZXJwb2xhdGVkIGlzIG11Y2ggbW9yZSBlZmZpY2llbnQgYXMgTW9kZWxQYXRoIHdpdGggaW50ZXJwb2xhdGlvbiB3aWxsIG5vdCBzeW50aGVzaXplIG5ldyBnZXR0ZXJzIGFuZCBzZXR0ZXJzLCB3aGlsZSBNb2RlbFBhdGggd2l0aCBjb21wdXRlZCBhY2Nlc3MgcGF0aCB3aWxsIHN5bnRoZXNpemUgbmV3IGdldHRlcnMgYW5kIHNldHRlcnMgZm9yIGVhY2ggcGFpciBvZiB2YWx1ZXMgb2YgYGlkYCBhbmQgYHByb3BgLlxuICogQHJldHVybiB7TW9kZWxQYXRofVxuICovXG5mdW5jdGlvbiBNb2RlbFBhdGgobW9kZWwsIHBhdGgpIHsgLy8gLC4uLiAtIGFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBpbnRlcnBvbGF0aW9uXG4gICAgLy8gY2hlY2sobW9kZWwsIE1vZGVsKTtcbiAgICBjaGVjayhwYXRoLCBTdHJpbmcpO1xuXG4gICAgLy8gYG1vZGVsUGF0aGAgd2lsbCBiZSByZXR1cm5lZCBieSBjb25zdHJ1Y3RvciBpbnN0ZWFkIG9mIGB0aGlzYC4gYG1vZGVsUGF0aGBcbiAgICAvLyAoYG1vZGVsUGF0aF9wYXRoYCBmdW5jdGlvbikgc2hvdWxkIGFsc28gcmV0dXJuIGEgTW9kZWxQYXRoIG9iamVjdCB3aXRoIFwic3ludGhlc2l6ZWRcIiBtZXRob2RzXG4gICAgLy8gdG8gZ2V0L3NldCBtb2RlbCBwcm9wZXJ0aWVzLCB0byBzdWJzY3JpYmUgdG8gcHJvcGVydHkgY2hhbmdlcywgZXRjLlxuICAgIC8vIEFkZGl0aW9uYWwgYXJndW1lbnRzIG9mIG1vZGVsUGF0aCBjYW4gYmUgdXNlZCBpbiB0aGUgcGF0aCB1c2luZyBpbnRlcnBvbGF0aW9uIC0gc2VlIE1vZGVsUGF0aCBiZWxvdy5cbiAgICB2YXIgbW9kZWxQYXRoID0gZnVuY3Rpb24gbW9kZWxQYXRoX3BhdGgoYWNjZXNzUGF0aCkgeyAvLyAsIC4uLiBhcmd1bWVudHMgdGhhdCB3aWxsIGJlIGludGVycG9sYXRlZFxuICAgICAgICByZXR1cm4gTW9kZWxQYXRoJHBhdGguYXBwbHkobW9kZWxQYXRoLCBhcmd1bWVudHMpO1xuICAgIH07XG4gICAgbW9kZWxQYXRoLl9fcHJvdG9fXyA9IE1vZGVsUGF0aC5wcm90b3R5cGU7XG5cblxuICAgIF8uZGVmaW5lUHJvcGVydGllcyhtb2RlbFBhdGgsIHtcbiAgICAgICAgX21vZGVsOiBtb2RlbCxcbiAgICAgICAgX3BhdGg6IHBhdGgsXG4gICAgICAgIF9hcmdzOiBfLnNsaWNlKGFyZ3VtZW50cywgMSksIC8vIHBhdGggd2lsbCBiZSB0aGUgZmlyc3QgZWxlbWVudCBvZiB0aGlzIGFycmF5XG4gICAgICAgIF9vcHRpb25zOiBtb2RlbC5fb3B0aW9uc1xuICAgIH0pO1xuXG4gICAgLy8gcGFyc2UgYWNjZXNzIHBhdGhcbiAgICB2YXIgcGFyc2VkUGF0aCA9IHBhdGhVdGlscy5wYXJzZUFjY2Vzc1BhdGgocGF0aCk7XG5cbiAgICAvLyBjb21wdXRlIGFjY2VzcyBwYXRoIHN0cmluZ1xuICAgIF8uZGVmaW5lUHJvcGVydHkobW9kZWxQYXRoLCAnX2FjY2Vzc1BhdGgnLCBpbnRlcnBvbGF0ZUFjY2Vzc1BhdGgocGFyc2VkUGF0aCwgbW9kZWxQYXRoLl9hcmdzKSk7XG5cbiAgICBpZiAobW9kZWxQYXRoLl9vcHRpb25zLnJlYWN0aXZlICE9PSBmYWxzZSkge1xuICAgICAgICAvLyBtZXNzZW5nZXIgZmFpbHMgb24gXCIqXCIgc3Vic2NyaXB0aW9uc1xuICAgICAgICBtb2RlbFBhdGguX3ByZXBhcmVNZXNzZW5nZXIoKTtcbiAgICAgICAgLy8gc3Vic2NyaWJlIHRvIFwiY2hhbmdlZGF0YVwiIG1lc3NhZ2UgdG8gZW5hYmxlIHJlYWN0aXZlIGNvbm5lY3Rpb25zXG4gICAgICAgIG1vZGVsUGF0aC5vblN5bmMoJ2NoYW5nZWRhdGEnLCBjaGFuZ2VEYXRhSGFuZGxlcik7XG4gICAgfVxuXG4gICAgLy8gY29tcGlsaW5nIGdldHRlciBhbmQgc2V0dGVyXG4gICAgdmFyIG1ldGhvZHMgPSBzeW50aGVzaXplKHBhdGgsIHBhcnNlZFBhdGgpO1xuXG4gICAgLy8gYWRkaW5nIG1ldGhvZHMgdG8gbW9kZWwgcGF0aFxuICAgIF8uZGVmaW5lUHJvcGVydGllcyhtb2RlbFBhdGgsIG1ldGhvZHMpO1xuXG4gICAgT2JqZWN0LmZyZWV6ZShtb2RlbFBhdGgpO1xuXG4gICAgcmV0dXJuIG1vZGVsUGF0aDtcbn1cblxuTW9kZWxQYXRoLnByb3RvdHlwZS5fX3Byb3RvX18gPSBNb2RlbFBhdGguX19wcm90b19fO1xuXG5cbi8qKlxuICogSW50ZXJwb2xhdGVzIHBhdGggZWxlbWVudHMgdG8gY29tcHV0ZSByZWFsIHBhdGhcbiAqXG4gKiBAcGFyYW0ge0FycmF5fSBwYXJzZWRQYXRoIHBhcnNlZCBwYXRoIC0gYXJyYXkgb2YgcGF0aCBub2Rlc1xuICogQHBhcmFtIHtBcnJheX0gYXJncyBwYXRoIGludGVycG9sYXRpb24gYXJndW1lbnRzLCBhcmdzWzBdIGlzIHBhdGggaXRzZWxmXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGludGVycG9sYXRlQWNjZXNzUGF0aChwYXJzZWRQYXRoLCBhcmdzKSB7XG4gICAgcmV0dXJuIHBhcnNlZFBhdGgucmVkdWNlKGZ1bmN0aW9uKGFjY2Vzc1BhdGhTdHIsIGN1cnJOb2RlLCBpbmRleCkge1xuICAgICAgICB2YXIgaW50ZXJwb2xhdGUgPSBjdXJyTm9kZS5pbnRlcnBvbGF0ZTtcbiAgICAgICAgcmV0dXJuIGFjY2Vzc1BhdGhTdHIgK1xuICAgICAgICAgICAgICAgIChpbnRlcnBvbGF0ZVxuICAgICAgICAgICAgICAgICAgICA/IChjdXJyTm9kZS5zeW50YXggPT0gJ2FycmF5J1xuICAgICAgICAgICAgICAgICAgICAgICAgPyAnWycgKyBhcmdzW2ludGVycG9sYXRlXSArICddJ1xuICAgICAgICAgICAgICAgICAgICAgICAgOiAnLicgKyBhcmdzW2ludGVycG9sYXRlXSlcbiAgICAgICAgICAgICAgICAgICAgOiBjdXJyTm9kZS5wcm9wZXJ0eSk7XG4gICAgfSwgJycpO1xufVxuXG5cbi8qKlxuICogIyMjI01vZGVsUGF0aCBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW3BhdGhdKCNNb2RlbFBhdGgkcGF0aCkgLSBnaXZlcyBhY2Nlc3MgdG8gcGF0aCBpbnNpZGUgTW9kZWxQYXRoXG4gKiAtIGdldCAtIHN5bnRoZXNpemVkXG4gKiAtIHNldCAtIHN5bnRoZXNpemVkXG4gKiAtIHNwbGljZSAtIHNwbGljZSBtb2RlbCBkYXRhIChhcyBhcnJheSBvciBwc2V1ZG8tYXJyYXkpLCBzeW50aGVzaXplZFxuICogLSBbbGVuXSgjTW9kZWxQYXRoJGxlbikgLSByZXR1cm5zIGxlbmd0aCBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KSBpbiBzYWZlIHdheSwgMCBpZiBubyBsZW5ndGggaXMgc2V0XG4gKiAtIFtwdXNoXSgjTW9kZWxQYXRoJHB1c2gpIC0gYWRkIGl0ZW1zIHRvIHRoZSBlbmQgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkgaW4gTW9kZWxQYXRoXG4gKiAtIFtwb3BdKCNNb2RlbFBhdGgkcG9wKSAtIHJlbW92ZSBpdGVtIGZyb20gdGhlIGVuZCBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KSBpbiBNb2RlbFBhdGhcbiAqIC0gW3Vuc2hpZnRdKCNNb2RlbFBhdGgkdW5zaGlmdCkgLSBhZGQgaXRlbXMgdG8gdGhlIGJlZ2lubmluZyBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KSBpbiBNb2RlbFBhdGhcbiAqIC0gW3NoaWZ0XSgjTW9kZWxQYXRoJHNoaWZ0KSAtIHJlbW92ZSBpdGVtIGZyb20gdGhlIGJlZ2lubmluZyBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KSBpbiBNb2RlbFBhdGhcbiAqL1xuXy5leHRlbmRQcm90byhNb2RlbFBhdGgsIHtcbiAgICBwYXRoOiBNb2RlbFBhdGgkcGF0aCxcbiAgICBsZW46IE1vZGVsUGF0aCRsZW4sXG4gICAgcHVzaDogTW9kZWxQYXRoJHB1c2gsXG4gICAgcG9wOiBNb2RlbFBhdGgkcG9wLFxuICAgIHVuc2hpZnQ6IE1vZGVsUGF0aCR1bnNoaWZ0LFxuICAgIHNoaWZ0OiBNb2RlbFBhdGgkc2hpZnQsXG4gICAgX3ByZXBhcmVNZXNzZW5nZXI6IF9wcmVwYXJlTWVzc2VuZ2VyLFxuICAgIF9nZXREZWZpbml0aW9uOiBfZ2V0RGVmaW5pdGlvbixcbiAgICBkZXN0cm95OiBNb2RlbFBhdGgkZGVzdHJveVxufSk7XG5cblxuXy5leHRlbmQoTW9kZWxQYXRoLCB7XG4gICAgX2NyZWF0ZUZyb21EZWZpbml0aW9uOiBfY3JlYXRlRnJvbURlZmluaXRpb25cbn0pXG5cblxuLyoqXG4gKiBFeHBvc2UgTWVzc2VuZ2VyIG1ldGhvZHMgb24gRmFjZXQgcHJvdG90eXBlXG4gKi9cbnZhciBNRVNTRU5HRVJfUFJPUEVSVFkgPSAnX21lc3Nlbmdlcic7XG5NZXNzZW5nZXIudXNlV2l0aChNb2RlbFBhdGgsIE1FU1NFTkdFUl9QUk9QRVJUWSwgTWVzc2VuZ2VyLmRlZmF1bHRNZXRob2RzKTtcblxuXG4vKipcbiAqIE1vZGVsUGF0aCBpbnN0YW5jZSBtZXRob2RcbiAqIEdpdmVzIGFjY2VzcyB0byBwYXRoIGluc2lkZSBNb2RlbFBhdGguIE1ldGhvZCB3b3JrcyBzaW1pbGFybHkgdG8gW3BhdGggbWV0aG9kXSgjTW9kZWwkcGF0aCkgb2YgbW9kZWwsIHVzaW5nIHJlbGF0aXZlIHBhdGhzLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBhY2Nlc3NQYXRoIHN0cmluZyB0aGF0IGRlZmluZXMgcGF0aCB0byBhY2Nlc3MgbW9kZWwuXG4gKiAgUGF0aCBzdHJpbmcgY29uc2lzdHMgb2YgcGFydHMgdG8gZGVmaW5lIGVpdGhlciBwcm9wZXJ0eSBhY2Nlc3MgKGBcIi5uYW1lXCJgIHRvIGFjY2VzcyBwcm9wZXJ0eSBuYW1lKSBvciBhcnJheSBpdGVtIGFjY2VzcyAoYFwiWzFdXCJgIHRvIGFjY2VzcyBpdGVtIHdpdGggaW5kZXggMSkuXG4gKiAgQWNjZXNzIHBhdGggY2FuIGNvbnRhaW4gYXMgbWFueSBwYXJ0cyBhcyBuZWNlc3NhcnkgKGUuZy4gYFwiLmxpc3RbMF0ubmFtZVwiYCB0byBhY2Nlc3MgcHJvcGVydHkgYG5hbWVgIGluIHRoZSBmaXJzdCBlbGVtZW50IG9mIGFycmF5IHN0b3JlZCBpbiBwcm9wZXJ0eSBgbGlzdGAuXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBhZGRpdGlvbmFsIGFyZ3VtZW50cyBvZiB0aGlzIG1ldGhvZCBjYW4gYmUgdXNlZCB0byBjcmVhdGUgaW50ZXJwb2xhdGVkIHBhdGhzLlxuICogIEUuZy4gYG0ucGF0aChcIlskMV0uJDJcIiwgaWQsIHByb3ApYCByZXR1cm5zIE1vZGVsUGF0aCB0byBhY2Nlc3MgcHJvcGVydHkgd2l0aCBuYW1lIGBwcm9wYCBpbiBhcnJheSBpdGVtIHdpdGggaW5kZXggYGlkYC4gQWx0aG91Z2ggdGhpcyBNb2RlbFBhdGggb2JqZWN0IHdpbGwgd29yayBleGFjdGx5IGFzIGBtKFwiW1wiICsgaWQgKyBcIl0uXCIgKyBwcm9wKWAsIHRoZSBpbnRlcnBvbGF0ZWQgaXMgbXVjaCBtb3JlIGVmZmljaWVudCBhcyBNb2RlbFBhdGggd2l0aCBpbnRlcnBvbGF0aW9uIHdpbGwgbm90IHN5bnRoZXNpemUgbmV3IGdldHRlcnMgYW5kIHNldHRlcnMsIHdoaWxlIE1vZGVsUGF0aCB3aXRoIGNvbXB1dGVkIGFjY2VzcyBwYXRoIHdpbGwgc3ludGhlc2l6ZSBuZXcgZ2V0dGVycyBhbmQgc2V0dGVycyBmb3IgZWFjaCBwYWlyIG9mIHZhbHVlcyBvZiBgaWRgIGFuZCBgcHJvcGAuXG4gKiBAcmV0dXJuIHtNb2RlbFBhdGh9XG4gKi9cbmZ1bmN0aW9uIE1vZGVsUGF0aCRwYXRoKGFjY2Vzc1BhdGgpIHsgIC8vICwgLi4uIGFyZ3VtZW50cyB0aGF0IHdpbGwgYmUgaW50ZXJwb2xhdGVkXG4gICAgaWYgKCEgYWNjZXNzUGF0aCkgcmV0dXJuIHRoaXM7XG5cbiAgICB2YXIgdGhpc1BhdGhBcmdzQ291bnQgPSB0aGlzLl9hcmdzLmxlbmd0aCAtIDE7XG5cbiAgICBpZiAodGhpc1BhdGhBcmdzQ291bnQgPiAwKSB7Ly8gdGhpcyBwYXRoIGhhcyBpbnRlcnBvbGF0ZWQgYXJndW1lbnRzIHRvb1xuICAgICAgICBhY2Nlc3NQYXRoID0gYWNjZXNzUGF0aC5yZXBsYWNlKC9cXCRbMS05XVswLTldKi9nLCBmdW5jdGlvbihzdHIpIHtcbiAgICAgICAgICAgIHJldHVybiAnJCcgKyAoK3N0ci5zbGljZSgxKSArIHRoaXNQYXRoQXJnc0NvdW50KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgdmFyIG5ld1BhdGggPSB0aGlzLl9wYXRoICsgYWNjZXNzUGF0aDtcblxuICAgIC8vIHRoaXMuX21vZGVsIGlzIGFkZGVkIGluIGZyb250IG9mIGFsbCBhcmd1bWVudHMgYXMgdGhlIGZpcnN0IHBhcmFtZXRlclxuICAgIC8vIG9mIE1vZGVsUGF0aCBjb25zdHJ1Y3RvclxuICAgIHZhciBhcmdzID0gW3RoaXMuX21vZGVsLCBuZXdQYXRoXVxuICAgICAgICAgICAgICAgIC5jb25jYXQodGhpcy5fYXJncy5zbGljZSgxKSkgLy8gcmVtb3ZlIG9sZCBwYXRoIGZyb20gX2FyZ3MsIGFzIGl0IGlzIDEgYmFzZWRcbiAgICAgICAgICAgICAgICAuY29uY2F0KF8uc2xpY2UoYXJndW1lbnRzLCAxKSk7IC8vIGFkZCBuZXcgaW50ZXJwb2xhdGlvbiBhcmd1bWVudHNcblxuICAgIC8vIGNhbGxpbmcgTW9kZWxQYXRoIGNvbnN0cnVjdG9yIHdpdGggbmV3IGFuZCB0aGUgbGlzdCBvZiBhcmd1bWVudHM6IHRoaXMgKG1vZGVsKSwgYWNjZXNzUGF0aCwgLi4uXG4gICAgcmV0dXJuIF8ubmV3QXBwbHkoTW9kZWxQYXRoLCBhcmdzKTtcbn1cblxuXG4vKipcbiAqIE1vZGVsUGF0aCBhbmQgTW9kZWwgaW5zdGFuY2UgbWV0aG9kXG4gKiBSZXR1cm5zIGxlbmd0aCBwcm9wZXJ0eSBhbmQgc2V0cyBpdCB0byAwIGlmIGl0IHdhc24ndCBzZXQuXG4gKlxuICogQHJldHVybiB7QW55fVxuICovXG5mdW5jdGlvbiBNb2RlbFBhdGgkbGVuKCkge1xuICAgIHJldHVybiB0aGlzLnBhdGgoJy5sZW5ndGgnKS5nZXQoKSB8fCAwO1xufVxuXG5cbi8qKlxuICogTW9kZWxQYXRoIGFuZCBNb2RlbCBpbnN0YW5jZSBtZXRob2RcbiAqIEFkZHMgaXRlbXMgdG8gdGhlIGVuZCBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KS4gUmV0dXJucyBuZXcgbGVuZ3RoLlxuICpcbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIGxpc3Qgb2YgaXRlbXMgdGhhdCB3aWxsIGJlIGFkZGVkIHRvIGFycmF5IChwc2V1ZG8gYXJyYXkpXG4gKiBAcmV0dXJuIHtJbnRlZ2VyfVxuICovXG5mdW5jdGlvbiBNb2RlbFBhdGgkcHVzaCgpIHsgLy8gYXJndW1lbnRzXG4gICAgdmFyIGxlbmd0aCA9IHRoaXMubGVuKCk7XG4gICAgdmFyIG5ld0xlbmd0aCA9IGxlbmd0aCArIGFyZ3VtZW50cy5sZW5ndGg7XG5cbiAgICBfLnNwbGljZShhcmd1bWVudHMsIDAsIDAsIGxlbmd0aCwgMCk7XG4gICAgdGhpcy5zcGxpY2UuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIHJldHVybiBuZXdMZW5ndGg7XG59XG5cblxuLyoqXG4gKiBNb2RlbFBhdGggYW5kIE1vZGVsIGluc3RhbmNlIG1ldGhvZFxuICogUmVtb3ZlcyBpdGVtIGZyb20gdGhlIGVuZCBvZiBhcnJheSAob3IgcHNldWRvLWFycmF5KS4gUmV0dXJucyB0aGlzIGl0ZW0uXG4gKlxuICogQHJldHVybiB7QW55fVxuICovXG5mdW5jdGlvbiBNb2RlbFBhdGgkcG9wKCkge1xuICAgIHJldHVybiB0aGlzLnNwbGljZSh0aGlzLmxlbigpIC0gMSwgMSlbMF07XG59XG5cblxuLyoqXG4gKiBNb2RlbFBhdGggYW5kIE1vZGVsIGluc3RhbmNlIG1ldGhvZFxuICogSW5zZXJ0cyBpdGVtcyB0byB0aGUgYmVnaW5uaW5nIG9mIHRoZSBhcnJheS4gUmV0dXJucyBuZXcgbGVuZ3RoLlxuICpcbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIGl0ZW1zIHRvIGJlIGluc2VydGVkIGluIHRoZSBiZWdpbm5pbmcgb2YgYXJyYXlcbiAqIEByZXR1cm4ge0ludGVnZXJ9XG4gKi9cbmZ1bmN0aW9uIE1vZGVsUGF0aCR1bnNoaWZ0KCkgeyAvLyBhcmd1bWVudHNcbiAgICB2YXIgbGVuZ3RoID0gdGhpcy5sZW4oKTtcbiAgICBsZW5ndGggKz0gYXJndW1lbnRzLmxlbmd0aDtcblxuICAgIF8uc3BsaWNlKGFyZ3VtZW50cywgMCwgMCwgMCwgMCk7XG4gICAgdGhpcy5zcGxpY2UuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIHJldHVybiBsZW5ndGg7XG59XG5cblxuLyoqXG4gKiBNb2RlbFBhdGggYW5kIE1vZGVsIGluc3RhbmNlIG1ldGhvZFxuICogUmVtb3ZlcyB0aGUgaXRlbSBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgYXJyYXkgKG9yIHBzZXVkby1hcnJheSkuIFJldHVybnMgdGhpcyBpdGVtLlxuICpcbiAqIEByZXR1cm4ge0FueX1cbiAqL1xuZnVuY3Rpb24gTW9kZWxQYXRoJHNoaWZ0KCkgeyAvLyBhcmd1bWVudHNcbiAgICByZXR1cm4gdGhpcy5zcGxpY2UoMCwgMSlbMF07XG59XG5cblxuLyoqXG4gKiBNb2RlbFBhdGggaW5zdGFuY2UgbWV0aG9kXG4gKiBJbml0aWFsaXplcyBNb2RlbFBhdGggbWVzZW5nZXIgd2l0aCBNb2RlbCdzIG1lc3NlbmdlciBhcyBpdHMgc291cmNlIChbTWVzc2VuZ2VyTWVzc2FnZVNvdXJjZV0oLi4vbWVzc2VuZ2VyL21zbmdyX3NvdXJjZS5qcy5odG1sKSkgYW5kIFtNb2RlbFBhdGhNc2dBUEldKC4vcGF0aF9tc2dfYXBpLmpzLmh0bWwpIGFzIFtNZXNzZW5nZXJBUEldKC4uL21lc3Nlbmdlci9tX2FwaS5qcy5odG1sKVxuICovXG5mdW5jdGlvbiBfcHJlcGFyZU1lc3NlbmdlcigpIHtcbiAgICB2YXIgbVBhdGhBUEkgPSBuZXcgTW9kZWxQYXRoTXNnQVBJKHRoaXMuX2FjY2Vzc1BhdGgpO1xuXG4gICAgLy8gY3JlYXRlIE1lc3Nlbmdlck1lc3NhZ2VTb3VyY2UgY29ubmVjdGVkIHRvIE1vZGVsJ3MgbWVzc2VuZ2VyXG4gICAgdmFyIG1vZGVsTWVzc2FnZVNvdXJjZSA9IG5ldyBNZXNzZW5nZXJNZXNzYWdlU291cmNlKHRoaXMsIHVuZGVmaW5lZCwgbVBhdGhBUEksIHRoaXMuX21vZGVsKTtcblxuICAgIC8vIGNyZWF0ZSBtZXNzZW5nZXIgd2l0aCBtb2RlbCBwYXNzZWQgYXMgaG9zdE9iamVjdCAoZGVmYXVsdCBtZXNzYWdlIGRpc3BhdGNoIGNvbnRleHQpXG4gICAgLy8gYW5kIHdpdGhvdXQgcHJveHlpbmcgbWV0aG9kcyAod2UgZG9uJ3Qgd2FudCB0byBwcm94eSB0aGVtIHRvIE1vZGVsKVxuICAgIHZhciBtUGF0aE1lc3NlbmdlciA9IG5ldyBNZXNzZW5nZXIodGhpcywgdW5kZWZpbmVkLCBtb2RlbE1lc3NhZ2VTb3VyY2UpO1xuXG4gICAgLy8gc3RvcmUgbWVzc2VuZ2VyIG9uIE1vZGVsUGF0aCBpbnN0YW5jZVxuICAgIF8uZGVmaW5lUHJvcGVydHkodGhpcywgTUVTU0VOR0VSX1BST1BFUlRZLCBtUGF0aE1lc3Nlbmdlcik7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBvYmplY3QgYWxsb3dpbmcgdG8gcmVjcmVhdGUgbW9kZWwgcGF0aFxuICpcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gX2dldERlZmluaXRpb24oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgbW9kZWw6IHRoaXMuX21vZGVsLFxuICAgICAgICBwYXRoOiB0aGlzLl9wYXRoLFxuICAgICAgICBhcmdzOiB0aGlzLl9hcmdzXG4gICAgfTtcbn1cblxuXG4vKipcbiAqIENsYXNzIG1ldGhvZFxuICogQ3JlYXRlcyBtb2RlbFBhdGggb2JqZWN0IGZyb20gZGVmaW5pdGlvbiBjcmVhdGVkIGJ5IF9nZXREZWZpbml0aW9uXG4gKlxuICogQHBhcmFtICB7T2JqZWN0fSBkZWZpbml0aW9uXG4gKiBAcmV0dXJuIHtNb2RlbFBhdGh9XG4gKi9cbmZ1bmN0aW9uIF9jcmVhdGVGcm9tRGVmaW5pdGlvbihkZWZpbml0aW9uKSB7XG4gICAgY2hlY2soZGVmaW5pdGlvbiwge1xuICAgICAgICBtb2RlbDogRnVuY3Rpb24sIC8vIE1vZGVsXG4gICAgICAgIHBhdGg6IFN0cmluZyxcbiAgICAgICAgYXJnczogQXJyYXlcbiAgICB9KTtcblxuICAgIHZhciBtID0gZGVmaW5pdGlvbi5tb2RlbDtcblxuICAgIHJldHVybiBtLmFwcGx5KG0sIGRlZmluaXRpb24uYXJncyk7XG59XG5cblxuZnVuY3Rpb24gTW9kZWxQYXRoJGRlc3Ryb3koKSB7XG4gICAgdGhpc1tNRVNTRU5HRVJfUFJPUEVSVFldLmRlc3Ryb3koKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgbW9kZWxVdGlscyA9IHtcbiAgICBub3JtYWxpemVTcGxpY2VJbmRleDogbm9ybWFsaXplU3BsaWNlSW5kZXhcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gbW9kZWxVdGlscztcblxuXG5mdW5jdGlvbiBub3JtYWxpemVTcGxpY2VJbmRleChzcGxpY2VJbmRleCwgbGVuZ3RoKSB7XG4gICAgcmV0dXJuIHNwbGljZUluZGV4ID4gbGVuZ3RoXG4gICAgICAgICAgICA/IGxlbmd0aFxuICAgICAgICAgICAgOiBzcGxpY2VJbmRleCA+PSAwXG4gICAgICAgICAgICAgICAgPyBzcGxpY2VJbmRleFxuICAgICAgICAgICAgICAgIDogc3BsaWNlSW5kZXggKyBsZW5ndGggPiAwXG4gICAgICAgICAgICAgICAgICAgID8gc3BsaWNlSW5kZXggKyBsZW5ndGhcbiAgICAgICAgICAgICAgICAgICAgOiAwO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgTWVzc2VuZ2VyQVBJID0gcmVxdWlyZSgnLi4vbWVzc2VuZ2VyL21fYXBpJylcbiAgICAsIHBhdGhVdGlscyA9IHJlcXVpcmUoJy4vcGF0aF91dGlscycpXG4gICAgLCBsb2dnZXIgPSByZXF1aXJlKCcuLi91dGlsL2xvZ2dlcicpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cblxuLyoqXG4gKiBTdWJjbGFzcyBvZiBNZXNzZW5nZXJBUEkgdGhhdCBpcyB1c2VkIHRvIHRyYW5zbGF0ZSBtZXNzYWdlcyBvZiBNZXNzZW5nZXIgb24gTW9kZWxQYXRoIHRvIE1lc3NlbmdlciBvbiBNb2RlbC5cbiAqL1xudmFyIE1vZGVsUGF0aE1zZ0FQSSA9IF8uY3JlYXRlU3ViY2xhc3MoTWVzc2VuZ2VyQVBJLCAnTW9kZWxQYXRoTXNnQVBJJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gTW9kZWxQYXRoTXNnQVBJO1xuXG5cbi8qKlxuICogIyMjI01vZGVsUGF0aE1zZ0FQSSBpbnN0YW5jZSBtZXRob2RzIyMjI1xuICpcbiAqIC0gW2luaXRdKCNpbml0KSAtIGluaXRpYWxpemVzIE1vZGVsUGF0aE1zZ0FQSVxuICogLSBbdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlXSgjdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKSAtIHRyYW5zbGF0ZXMgcmVsYXRpdmUgYWNjZXNzIHBhdGhzIG9mIE1vZGVsUGF0aCB0byBmdWxsIHBhdGggb2YgTW9kZWxcbiAqIC0gW2NyZWF0ZUludGVybmFsRGF0YV0oI2NyZWF0ZUludGVybmFsRGF0YSkgLSBjaGFuZ2VzIHBhdGggaW4gbWVzc2FnZSBvbiBtb2RlbCB0byByZWxhdGl2ZSBwYXRoIGFuZCBhZGRzIGBmdWxsUGF0aGAgcHJvcGVydHkgdG8gbWVzc2FnZSBkYXRhXG4gKi9cbl8uZXh0ZW5kUHJvdG8oTW9kZWxQYXRoTXNnQVBJLCB7XG4gICAgaW5pdDogaW5pdCxcbiAgICB0cmFuc2xhdGVUb1NvdXJjZU1lc3NhZ2U6IHRyYW5zbGF0ZVRvU291cmNlTWVzc2FnZSxcbiAgICBjcmVhdGVJbnRlcm5hbERhdGE6IGNyZWF0ZUludGVybmFsRGF0YSxcbn0pO1xuXG5cbi8qKlxuICogTW9kZWxQYXRoTXNnQVBJIGluc3RhbmNlIG1ldGhvZFxuICogQ2FsbGVkIGJ5IE1lc3NlbmdlckFQSSBjb25zdHJ1Y3Rvci5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gcm9vdFBhdGggcm9vdCBwYXRoIG9mIG1vZGVsIHBhdGhcbiAqL1xuZnVuY3Rpb24gaW5pdChyb290UGF0aCkge1xuICAgIE1lc3NlbmdlckFQSS5wcm90b3R5cGUuaW5pdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHRoaXMucm9vdFBhdGggPSByb290UGF0aDtcbn1cblxuLyoqXG4gKiBNb2RlbFBhdGhNc2dBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBUcmFuc2xhdGVzIHJlbGF0aXZlIGFjY2VzcyBwYXRocyBvZiBNb2RlbFBhdGggdG8gZnVsbCBwYXRoIG9mIE1vZGVsLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBhY2Nlc3NQYXRoIHJlbGF0aXZlIGFjY2VzcyBwYXRoIHRvIGJlIHRyYW5zbGF0ZWRcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuZnVuY3Rpb24gdHJhbnNsYXRlVG9Tb3VyY2VNZXNzYWdlKG1lc3NhZ2UpIHtcbiAgICAvLyBUT0RPIHNob3VsZCBwcmVwZW5kIFJlZ0V4ZXNcbiAgICAvLyBUT0RPIHNob3VsZCBub3QgcHJlcGVuZCBjaGFuZ2VkYXRhIHRvbz8/P1xuICAgIGlmIChtZXNzYWdlIGluc3RhbmNlb2YgUmVnRXhwKVxuICAgICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICBpZiAobWVzc2FnZSA9PSAnZGF0YWNoYW5nZXMnKVxuICAgICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICBcbiAgICByZXR1cm4gdGhpcy5yb290UGF0aCArIG1lc3NhZ2U7XG59XG5cblxuLyoqXG4gKiBNb2RlbFBhdGhNc2dBUEkgaW5zdGFuY2UgbWV0aG9kXG4gKiBDaGFuZ2VzIHBhdGggaW4gbWVzc2FnZSBvbiBtb2RlbCB0byByZWxhdGl2ZSBwYXRoIGFuZCBhZGRzIGBmdWxsUGF0aGAgcHJvcGVydHkgdG8gbWVzc2FnZSBkYXRhLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzb3VyY2VNZXNzYWdlIGZ1bGwgYWNjZXNzIHBhdGggb24gTW9kZWxcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIHJlbGF0aXZlIGFjY2VzcyBwYXRoIG9uIE1vZGVsUGF0aFxuICogQHBhcmFtIHtPYmplY3R9IHNvdXJjZURhdGEgZGF0YSByZWNlaXZlZCBmcm9tIE1vZGVsLCB3aWxsIGJlIHRyYW5zbGF0ZWQgYXMgZGVzY3JpYmVkIHRvIGJlIGRpc3BhdGNoZWQgdG8gTW9kZWxQYXRoXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUludGVybmFsRGF0YShzb3VyY2VNZXNzYWdlLCBtZXNzYWdlLCBzb3VyY2VEYXRhKSB7XG4gICAgLy8gVE9ETyByZXR1cm4gb24gY2hhbmdlZGF0YSB0b28/Pz9cbiAgICBpZiAobWVzc2FnZSA9PSAnZGF0YWNoYW5nZXMnKSB7XG4gICAgICAgIHZhciBpbnRlcm5hbENoYW5nZXMgPSBzb3VyY2VEYXRhLmNoYW5nZXNcbiAgICAgICAgICAgIC5tYXAodHJ1bmNhdGVDaGFuZ2VQYXRoLCB0aGlzKVxuICAgICAgICAgICAgLmZpbHRlcihmdW5jdGlvbihjaGFuZ2UpIHsgcmV0dXJuIGNoYW5nZTsgfSk7XG4gICAgICAgIHZhciBpbnRlcm5hbERhdGEgPSB7XG4gICAgICAgICAgICBjaGFuZ2VzOiBpbnRlcm5hbENoYW5nZXMsXG4gICAgICAgICAgICB0cmFuc2FjdGlvbjogc291cmNlRGF0YS50cmFuc2FjdGlvblxuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiBpbnRlcm5hbERhdGFcbiAgICB9XG5cbiAgICB2YXIgaW50ZXJuYWxEYXRhID0gdHJ1bmNhdGVDaGFuZ2VQYXRoLmNhbGwodGhpcywgc291cmNlRGF0YSk7XG4gICAgcmV0dXJuIGludGVybmFsRGF0YTtcbn1cblxuXG5mdW5jdGlvbiB0cnVuY2F0ZUNoYW5nZVBhdGgoY2hhbmdlKSB7XG4gICAgdmFyIGZ1bGxQYXRoID0gY2hhbmdlLnBhdGhcbiAgICAgICAgLCBwYXRoID0gXy51blByZWZpeChmdWxsUGF0aCwgdGhpcy5yb290UGF0aCk7XG5cbiAgICBpZiAodHlwZW9mIHBhdGggPT0gJ3N0cmluZycpIHtcbiAgICAgICAgdmFyIGNoYW5nZSA9IF8uY2xvbmUoY2hhbmdlKTtcbiAgICAgICAgY2hhbmdlLmZ1bGxQYXRoID0gZnVsbFBhdGg7XG4gICAgICAgIGNoYW5nZS5wYXRoID0gcGF0aDtcbiAgICAgICAgcmV0dXJuIGNoYW5nZTtcbiAgICB9XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vIDxhIG5hbWU9XCJtb2RlbC1wYXRoXCI+PC9hPlxuLy8gIyMjIG1vZGVsIHBhdGggdXRpbHNcblxudmFyIGNoZWNrID0gcmVxdWlyZSgnLi4vdXRpbC9jaGVjaycpXG4gICAgLCBNYXRjaCA9IGNoZWNrLk1hdGNoXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJyk7XG5cbnZhciBwYXRoVXRpbHMgPSB7XG4gICAgcGFyc2VBY2Nlc3NQYXRoOiBwYXJzZUFjY2Vzc1BhdGgsXG4gICAgY3JlYXRlUmVnZXhQYXRoOiBjcmVhdGVSZWdleFBhdGgsXG4gICAgZ2V0UGF0aE5vZGVLZXk6IGdldFBhdGhOb2RlS2V5LFxuICAgIHdyYXBNZXNzZW5nZXJNZXRob2RzOiB3cmFwTWVzc2VuZ2VyTWV0aG9kc1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBwYXRoVXRpbHM7XG5cblxudmFyIHByb3BlcnR5UGF0aFN5bnRheCA9ICdcXFxcLltBLVphLXpfLV1bQS1aYS16MC05Xy1dKidcbiAgICAsIGFycmF5UGF0aFN5bnRheCA9ICdcXFxcW1swLTldK1xcXFxdJ1xuICAgICwgaW50ZXJwb2xhdGlvblN5bnRheCA9ICdcXFxcJFsxLTldWzAtOV0qJ1xuICAgICwgcHJvcGVydHlJbnRlcnBvbGF0ZVN5bnRheCA9ICdcXFxcLicgKyBpbnRlcnBvbGF0aW9uU3ludGF4XG4gICAgLCBhcnJheUludGVycG9sYXRlU3ludGF4ID0gJ1xcXFxbJyArIGludGVycG9sYXRpb25TeW50YXggKyAnXFxcXF0nXG5cbiAgICAsIHByb3BlcnR5U3RhclN5bnRheCA9ICdcXFxcLlxcXFwqJ1xuICAgICwgYXJyYXlTdGFyU3ludGF4ID0gJ1xcXFxbXFxcXCpcXFxcXSdcbiAgICAsIHN0YXJTeW50YXggPSAnXFxcXConXG5cbiAgICAsIHBhdGhQYXJzZVN5bnRheCA9IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9wZXJ0eVBhdGhTeW50YXgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyYXlQYXRoU3ludGF4LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3BlcnR5SW50ZXJwb2xhdGVTeW50YXgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyYXlJbnRlcnBvbGF0ZVN5bnRheFxuICAgICAgICAgICAgICAgICAgICAgICAgXS5qb2luKCd8JylcbiAgICAsIHBhdGhQYXJzZVBhdHRlcm4gPSBuZXcgUmVnRXhwKHBhdGhQYXJzZVN5bnRheCwgJ2cnKVxuXG4gICAgLCBwYXR0ZXJuUGF0aFBhcnNlU3ludGF4ID0gIFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGhQYXJzZVN5bnRheCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3BlcnR5U3RhclN5bnRheCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmF5U3RhclN5bnRheCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJTeW50YXhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXS5qb2luKCd8JylcbiAgICAsIHBhdHRlcm5QYXRoUGFyc2VQYXR0ZXJuID0gbmV3IFJlZ0V4cChwYXR0ZXJuUGF0aFBhcnNlU3ludGF4LCAnZycpXG5cbiAgICAvLywgdGFyZ2V0UGF0aFBhcnNlUGF0dGVybiA9IC9cXC5bQS1aYS16XVtBLVphLXowLTlfXSp8XFxbWzAtOV0rXFxdfFxcLlxcJFsxLTldWzAtOV0qfFxcW1xcJFsxLTldWzAtOV0qXFxdfFxcJFsxLTldWzAtOV0vZ1xuICAgICwgcGF0aE5vZGVUeXBlcyA9IHtcbiAgICAgICAgJy4nOiB7IHN5bnRheDogJ29iamVjdCcsIGVtcHR5OiAne30nIH0sXG4gICAgICAgICdbJzogeyBzeW50YXg6ICdhcnJheScsIGVtcHR5OiAnW10nfSxcbiAgICAgICAgJyonOiB7IHN5bnRheDogJ21hdGNoJywgZW1wdHk6ICd7fSd9LFxuICAgIH07XG5cbmZ1bmN0aW9uIHBhcnNlQWNjZXNzUGF0aChwYXRoLCBub2RlUGFyc2VQYXR0ZXJuKSB7XG4gICAgbm9kZVBhcnNlUGF0dGVybiA9IG5vZGVQYXJzZVBhdHRlcm4gfHwgcGF0aFBhcnNlUGF0dGVybjtcblxuICAgIHZhciBwYXJzZWRQYXRoID0gW107XG5cbiAgICBpZiAoISBwYXRoKVxuICAgICAgICByZXR1cm4gcGFyc2VkUGF0aDtcblxuICAgIHZhciB1bnBhcnNlZCA9IHBhdGgucmVwbGFjZShub2RlUGFyc2VQYXR0ZXJuLCBmdW5jdGlvbihub2RlU3RyKSB7XG4gICAgICAgIHZhciBwYXRoTm9kZSA9IHsgcHJvcGVydHk6IG5vZGVTdHIgfTtcbiAgICAgICAgXy5leHRlbmQocGF0aE5vZGUsIHBhdGhOb2RlVHlwZXNbbm9kZVN0clswXV0pO1xuICAgICAgICBpZiAobm9kZVN0clsxXSA9PSAnJCcpXG4gICAgICAgICAgICBwYXRoTm9kZS5pbnRlcnBvbGF0ZSA9IGdldFBhdGhOb2RlS2V5KHBhdGhOb2RlLCB0cnVlKTtcblxuICAgICAgICBwYXJzZWRQYXRoLnB1c2gocGF0aE5vZGUpO1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgfSk7XG4gICAgaWYgKHVucGFyc2VkKVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2luY29ycmVjdCBtb2RlbCBwYXRoOiAnICsgcGF0aCk7XG5cbiAgICByZXR1cm4gcGFyc2VkUGF0aDtcbn1cblxuXG52YXIgbm9kZVJlZ2V4ID0ge1xuICAgICcuKic6IHByb3BlcnR5UGF0aFN5bnRheCxcbiAgICAnWypdJzogYXJyYXlQYXRoU3ludGF4XG59O1xubm9kZVJlZ2V4WycqJ10gPSBub2RlUmVnZXhbJy4qJ10gKyAnfCcgKyBub2RlUmVnZXhbJ1sqXSddO1xuXG5mdW5jdGlvbiBjcmVhdGVSZWdleFBhdGgocGF0aCkge1xuICAgIGNoZWNrKHBhdGgsIE1hdGNoLk9uZU9mKFN0cmluZywgUmVnRXhwKSk7XG5cbiAgICBpZiAocGF0aCBpbnN0YW5jZW9mIFJlZ0V4cCB8fCBwYXRoLmluZGV4T2YoJyonKSA9PSAtMSlcbiAgICAgICAgcmV0dXJuIHBhdGg7XG5cbiAgICB2YXIgcGFyc2VkUGF0aCA9IHBhdGhVdGlscy5wYXJzZUFjY2Vzc1BhdGgocGF0aCwgcGF0dGVyblBhdGhQYXJzZVBhdHRlcm4pXG4gICAgICAgICwgcmVnZXhTdHIgPSAnXidcbiAgICAgICAgLy8gLCByZWdleFN0ckVuZCA9ICcnXG4gICAgICAgICwgcGF0dGVybnNTdGFydGVkID0gZmFsc2U7XG5cbiAgICBwYXJzZWRQYXRoLmZvckVhY2goZnVuY3Rpb24ocGF0aE5vZGUpIHtcbiAgICAgICAgdmFyIHByb3AgPSBwYXRoTm9kZS5wcm9wZXJ0eVxuICAgICAgICAgICAgLCByZWdleCA9IG5vZGVSZWdleFtwcm9wXTtcbiAgICAgICAgXG4gICAgICAgIGlmIChyZWdleCkge1xuICAgICAgICAgICAgLy8gcmVnZXhTdHIgKz0gJygnICsgcmVnZXg7XG4gICAgICAgICAgICAvLyByZWdleFN0ckVuZCArPSAnfCknO1xuICAgICAgICAgICAgcmVnZXhTdHIgKz0gJygnICsgcmVnZXggKyAnfCknO1xuICAgICAgICAgICAgLy8gcmVnZXhTdHJFbmQgKz0gJ3wpJztcbiAgICAgICAgICAgIHBhdHRlcm5zU3RhcnRlZCA9IHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBpZiAocGF0dGVybnNTdGFydGVkKVxuICAgICAgICAgICAgLy8gIHRocm93IG5ldyBFcnJvcignXCIqXCIgcGF0aCBzZWdtZW50IGNhbm5vdCBiZSBpbiB0aGUgbWlkZGxlIG9mIHRoZSBwYXRoOiAnICsgcGF0aCk7XG4gICAgICAgICAgICByZWdleFN0ciArPSBwcm9wLnJlcGxhY2UoLyhcXC58XFxbfFxcXSkvZywgJ1xcXFwkMScpOyAvLyBhZGQgc2xhc2ggaW4gZnJvbnQgb2Ygc3ltYm9scyB0aGF0IGhhdmUgc3BlY2lhbCBtZWFuaW5nIGluIHJlZ2V4XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIHJlZ2V4U3RyICs9IC8qIHJlZ2V4U3RyRW5kICsgKi8gJyQnO1xuXG4gICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIG5ldyBSZWdFeHAocmVnZXhTdHIpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5cXCd0IGNvbnN0cnVjdCByZWdleCBmb3IgcGF0aCBwYXR0ZXJuOiAnICsgcGF0aCk7XG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIGdldFBhdGhOb2RlS2V5KHBhdGhOb2RlLCBpbnRlcnBvbGF0ZWQpIHtcbiAgICB2YXIgcHJvcCA9IHBhdGhOb2RlLnByb3BlcnR5XG4gICAgICAgICwgc3RhcnRJbmRleCA9IGludGVycG9sYXRlZCA/IDIgOiAxO1xuICAgIHJldHVybiBwYXRoTm9kZS5zeW50YXggPT0gJ2FycmF5J1xuICAgICAgICA/IHByb3Auc2xpY2Uoc3RhcnRJbmRleCwgcHJvcC5sZW5ndGggLSAxKVxuICAgICAgICA6IHByb3Auc2xpY2Uoc3RhcnRJbmRleCk7XG59XG5cblxuLy8gVE9ETyBhbGxvdyBmb3IgbXVsdGlwbGUgbWVzc2FnZXMgaW4gYSBzdHJpbmdcbmZ1bmN0aW9uIHdyYXBNZXNzZW5nZXJNZXRob2RzKG1ldGhvZHNOYW1lcykge1xuICAgIG1ldGhvZHNOYW1lcyA9IG1ldGhvZHNOYW1lcyB8fCBbJ29uJywgJ29mZiddO1xuICAgIHZhciB3cmFwcGVkTWV0aG9kcyA9IF8ubWFwVG9PYmplY3QobWV0aG9kc05hbWVzLCBmdW5jdGlvbihtZXRob2ROYW1lKSB7XG4gICAgICAgIHZhciBvcmlnTWV0aG9kID0gdGhpc1ttZXRob2ROYW1lXTtcbiAgICAgICAgLy8gcmVwbGFjaW5nIG1lc3NhZ2Ugc3Vic3JpYmUvdW5zdWJzY3JpYmUvZXRjLiB0byBjb252ZXJ0IFwiKlwiIG1lc3NhZ2UgcGF0dGVybnMgdG8gcmVnZXhwc1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24ocGF0aCwgc3Vic2NyaWJlcikge1xuICAgICAgICAgICAgdmFyIHJlZ2V4UGF0aCA9IGNyZWF0ZVJlZ2V4UGF0aChwYXRoKTtcbiAgICAgICAgICAgIG9yaWdNZXRob2QuY2FsbCh0aGlzLCByZWdleFBhdGgsIHN1YnNjcmliZXIpO1xuICAgICAgICB9O1xuICAgIH0sIHRoaXMpO1xuICAgIF8uZGVmaW5lUHJvcGVydGllcyh0aGlzLCB3cmFwcGVkTWV0aG9kcyk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBwYXRoVXRpbHMgPSByZXF1aXJlKCcuLi9wYXRoX3V0aWxzJylcbiAgICAsIG1vZGVsVXRpbHMgPSByZXF1aXJlKCcuLi9tb2RlbF91dGlscycpXG4gICAgLCBsb2dnZXIgPSByZXF1aXJlKCcuLi8uLi91dGlsL2xvZ2dlcicpXG4gICAgLCBmcyA9IHJlcXVpcmUoJ2ZzJylcbiAgICAsIGRvVCA9IHJlcXVpcmUoJ2RvdCcpXG4gICAgLCBfID0gcmVxdWlyZSgnbW9sLXByb3RvJylcbiAgICAsIGNoYW5nZURhdGFIYW5kbGVyID0gcmVxdWlyZSgnLi4vY2hhbmdlX2RhdGEnKVxuICAgICwgZ2V0VHJhbnNhY3Rpb25GbGFnID0gY2hhbmdlRGF0YUhhbmRsZXIuZ2V0VHJhbnNhY3Rpb25GbGFnXG4gICAgLCBwb3N0VHJhbnNhY3Rpb25GaW5pc2hlZCA9IGNoYW5nZURhdGFIYW5kbGVyLnBvc3RUcmFuc2FjdGlvbkZpbmlzaGVkO1xuXG5cbi8qKlxuICogVGVtcGxhdGVzIHRvIHN5bnRoZXNpemUgbW9kZWwgZ2V0dGVycyBhbmQgc2V0dGVyc1xuICovXG52YXIgdGVtcGxhdGVzID0ge1xuICAgIGdldDogXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG5tZXRob2QgPSBmdW5jdGlvbiBnZXQoKSB7XFxuICAgIHZhciBtID0ge3sjIGRlZi5tb2RlbEFjY2Vzc1ByZWZpeCB9fTtcXG4gICAgcmV0dXJuIG0ge3t+IGl0LnBhcnNlZFBhdGggOnBhdGhOb2RlIH19XFxuICAgICAgICB7ez8gcGF0aE5vZGUuaW50ZXJwb2xhdGV9fVxcbiAgICAgICAgICAgICYmIChtID0gbVt0aGlzLl9hcmdzWyB7ez0gcGF0aE5vZGUuaW50ZXJwb2xhdGUgfX0gXV0pXFxuICAgICAgICB7ez8/fX1cXG4gICAgICAgICAgICAmJiAobSA9IG17ez0gcGF0aE5vZGUucHJvcGVydHkgfX0pXFxuICAgICAgICB7ez99fSB7e359fTtcXG59O1xcblwiLFxuICAgIHNldDogXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG57eyMgZGVmLmluY2x1ZGVfZGVmaW5lcyB9fVxcbnt7IyBkZWYuaW5jbHVkZV9jcmVhdGVfdHJlZSB9fVxcblxcblxcbi8qKlxcbiAqIFRlbXBsYXRlIHRoYXQgc3ludGhlc2l6ZXMgc2V0dGVyIGZvciBNb2RlbCBhbmQgZm9yIE1vZGVsUGF0aFxcbiAqL1xcbm1ldGhvZCA9IGZ1bmN0aW9uIHNldCh2YWx1ZSkge1xcbiAgICB7eyMgZGVmLmluaXRWYXJzOidzZXQnIH19XFxuXFxuICAgIHt7IyBkZWYuY3JlYXRlVHJlZTonc2V0JyB9fVxcblxcbiAgICB7e1xcbiAgICAgICAgY3Vyck5vZGUgPSBuZXh0Tm9kZTtcXG4gICAgICAgIGN1cnJQcm9wID0gY3Vyck5vZGUgJiYgY3Vyck5vZGUucHJvcGVydHk7XFxuICAgIH19XFxuXFxuICAgIHt7IC8qIGFzc2lnbiB2YWx1ZSB0byB0aGUgbGFzdCBwcm9wZXJ0eSAqLyB9fVxcbiAgICB7ez8gY3VyclByb3AgfX1cXG4gICAgICAgIHdhc0RlZiA9IHt7IyBkZWYud2FzRGVmaW5lZH19O1xcbiAgICAgICAge3sjIGRlZi5jaGFuZ2VBY2Nlc3NQYXRoIH19XFxuXFxuICAgICAgICB2YXIgb2xkID0gbXt7IyBkZWYuY3VyclByb3AgfX07XFxuXFxuICAgICAgICB7eyAvKiBjbG9uZSB2YWx1ZSB0byBwcmV2ZW50IHNhbWUgcmVmZXJlbmNlIGluIGxpbmtlZCBtb2RlbHMgKi8gfX1cXG4gICAgICAgIG17eyMgZGVmLmN1cnJQcm9wIH19ID0gY2xvbmVUcmVlKHZhbHVlKTtcXG4gICAge3s/fX1cXG5cXG4gICAge3sgLyogYWRkIG1lc3NhZ2UgcmVsYXRlZCB0byB0aGUgbGFzdCBwcm9wZXJ0eSBjaGFuZ2UgKi8gfX1cXG4gICAgaWYgKHRoaXMuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XFxuICAgICAgICBpZiAoISB3YXNEZWYpXFxuICAgICAgICAgICAge3sjIGRlZi5hZGRNc2cgfX0gYWNjZXNzUGF0aCwgdHlwZTogJ2FkZGVkJyxcXG4gICAgICAgICAgICAgICAgbmV3VmFsdWU6IHZhbHVlIH0pO1xcbiAgICAgICAgZWxzZSBpZiAob2xkICE9IHZhbHVlKVxcbiAgICAgICAgICAgIHt7IyBkZWYuYWRkTXNnIH19IGFjY2Vzc1BhdGgsIHR5cGU6ICdjaGFuZ2VkJyxcXG4gICAgICAgICAgICAgICAgb2xkVmFsdWU6IG9sZCwgbmV3VmFsdWU6IHZhbHVlIH0pO1xcblxcbiAgICAgICAge3sgLyogYWRkIG1lc3NhZ2UgcmVsYXRlZCB0byBjaGFuZ2VzIGluIChzdWIpcHJvcGVydGllcyBpbnNpZGUgcmVtb3ZlZCBhbmQgYXNzaWduZWQgdmFsdWUgKi8gfX1cXG4gICAgICAgIGlmICghIHdhc0RlZiB8fCBvbGQgIT0gdmFsdWUpXFxuICAgICAgICAgICAgYWRkVHJlZUNoYW5nZXNNZXNzYWdlcyhtZXNzYWdlcywgbWVzc2FnZXNIYXNoLFxcbiAgICAgICAgICAgICAgICBhY2Nlc3NQYXRoLCBvbGQsIHZhbHVlKTsgLyogZGVmaW5lZCBpbiB0aGUgZnVuY3Rpb24gdGhhdCBzeW50aGVzaXplcyBNb2RlbFBhdGggc2V0dGVyICovXFxuXFxuICAgICAgICB7eyAvKiBwb3N0IGFsbCBzdG9yZWQgbWVzc2FnZXMgKi8gfX1cXG4gICAgICAgIHt7IyBkZWYucG9zdE1lc3NhZ2VzIH19XFxuICAgIH1cXG59O1xcblwiLFxuICAgIGRlbDogXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG57eyMgZGVmLmluY2x1ZGVfZGVmaW5lcyB9fVxcbnt7IyBkZWYuaW5jbHVkZV90cmF2ZXJzZV90cmVlIH19XFxuXFxubWV0aG9kID0gZnVuY3Rpb24gZGVsKCkge1xcbiAgICB7eyMgZGVmLmluaXRWYXJzOidkZWwnIH19XFxuXFxuICAgIHt7PyBpdC5wYXJzZWRQYXRoLmxlbmd0aCB9fVxcbiAgICAgICAge3sjIGRlZi50cmF2ZXJzZVRyZWUgfX1cXG5cXG4gICAgICAgIHt7XFxuICAgICAgICAgICAgdmFyIGN1cnJOb2RlID0gaXQucGFyc2VkUGF0aFtjb3VudF07XFxuICAgICAgICAgICAgdmFyIGN1cnJQcm9wID0gY3Vyck5vZGUucHJvcGVydHk7ICAgICAgIFxcbiAgICAgICAgfX1cXG5cXG4gICAgICAgIGlmICghIHRyZWVEb2VzTm90RXhpc3QgJiYgbSAmJiBtLmhhc093blByb3BlcnR5ICYmIHt7IyBkZWYud2FzRGVmaW5lZH19KSB7XFxuICAgICAgICAgICAgdmFyIG9sZCA9IG17eyMgZGVmLmN1cnJQcm9wIH19O1xcbiAgICAgICAgICAgIGRlbGV0ZSBte3sjIGRlZi5jdXJyUHJvcCB9fTtcXG4gICAgICAgICAgICB7eyMgZGVmLmNoYW5nZUFjY2Vzc1BhdGggfX1cXG4gICAgICAgICAgICB2YXIgZGlkRGVsZXRlID0gdHJ1ZTtcXG4gICAgICAgIH1cXG4gICAge3s/P319XFxuICAgICAgICBpZiAodHlwZW9mIG0gIT0gJ3VuZGVmaW5lZCcpIHtcXG4gICAgICAgICAgICB2YXIgb2xkID0gbTtcXG4gICAgICAgICAgICB7eyMgZGVmLm1vZGVsQWNjZXNzUHJlZml4IH19ID0gdW5kZWZpbmVkO1xcbiAgICAgICAgICAgIHZhciBkaWREZWxldGUgPSB0cnVlO1xcbiAgICAgICAgfVxcbiAgICB7ez99fVxcblxcbiAgICBpZiAoZGlkRGVsZXRlICYmIHRoaXMuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XFxuICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSBhY2Nlc3NQYXRoLCB0eXBlOiAnZGVsZXRlZCcsIG9sZFZhbHVlOiBvbGQgfSk7XFxuXFxuICAgICAgICBhZGRUcmVlQ2hhbmdlc01lc3NhZ2VzKG1lc3NhZ2VzLCBtZXNzYWdlc0hhc2gsXFxuICAgICAgICAgICAgYWNjZXNzUGF0aCwgb2xkLCB1bmRlZmluZWQpOyAvKiBkZWZpbmVkIGluIHRoZSBmdW5jdGlvbiB0aGF0IHN5bnRoZXNpemVzIE1vZGVsUGF0aCBzZXR0ZXIgKi9cXG5cXG4gICAgICAgIHt7IC8qIHBvc3QgYWxsIHN0b3JlZCBtZXNzYWdlcyAqLyB9fVxcbiAgICAgICAge3sjIGRlZi5wb3N0TWVzc2FnZXMgfX1cXG4gICAgfVxcbn07XFxuXCIsXG4gICAgc3BsaWNlOiBcIid1c2Ugc3RyaWN0JztcXG4vKiBPbmx5IHVzZSB0aGlzIHN0eWxlIG9mIGNvbW1lbnRzLCBub3QgXFxcIi8vXFxcIiAqL1xcblxcbnt7IyBkZWYuaW5jbHVkZV9kZWZpbmVzIH19XFxue3sjIGRlZi5pbmNsdWRlX2NyZWF0ZV90cmVlIH19XFxue3sjIGRlZi5pbmNsdWRlX3RyYXZlcnNlX3RyZWUgfX1cXG5cXG5tZXRob2QgPSBmdW5jdGlvbiBzcGxpY2Uoc3BsaWNlSW5kZXgsIHNwbGljZUhvd01hbnkpIHsgLyogLC4uLiAtIGV4dHJhIGFyZ3VtZW50cyB0byBzcGxpY2UgaW50byBhcnJheSAqL1xcbiAgICB7eyMgZGVmLmluaXRWYXJzOidzcGxpY2UnIH19XFxuXFxuICAgIHZhciBhcmdzTGVuID0gYXJndW1lbnRzLmxlbmd0aDtcXG4gICAgdmFyIGFkZEl0ZW1zID0gYXJnc0xlbiA+IDI7XFxuXFxuICAgIGlmIChhZGRJdGVtcykge1xcbiAgICAgICAge3sgLyogb25seSBjcmVhdGUgbW9kZWwgdHJlZSBpZiBpdGVtcyBhcmUgaW5zZXJ0ZWQgaW4gYXJyYXkgKi8gfX1cXG5cXG4gICAgICAgIHt7IC8qIGlmIG1vZGVsIGlzIHVuZGVmaW5lZCBpdCB3aWxsIGJlIHNldCB0byBhbiBlbXB0eSBhcnJheSAqLyB9fSAgXFxuICAgICAgICB2YXIgdmFsdWUgPSBbXTtcXG4gICAgICAgIHt7IyBkZWYuY3JlYXRlVHJlZTonc3BsaWNlJyB9fVxcblxcbiAgICAgICAge3s/IG5leHROb2RlIH19XFxuICAgICAgICAgICAge3tcXG4gICAgICAgICAgICAgICAgdmFyIGN1cnJOb2RlID0gbmV4dE5vZGU7XFxuICAgICAgICAgICAgICAgIHZhciBjdXJyUHJvcCA9IGN1cnJOb2RlLnByb3BlcnR5O1xcbiAgICAgICAgICAgICAgICB2YXIgZW1wdHlQcm9wID0gJ1tdJztcXG4gICAgICAgICAgICB9fVxcblxcbiAgICAgICAgICAgIHt7IyBkZWYuY3JlYXRlVHJlZVN0ZXAgfX1cXG4gICAgICAgIHt7P319XFxuXFxuICAgIH0gZWxzZSBpZiAoc3BsaWNlSG93TWFueSA+IDApIHtcXG4gICAgICAgIHt7IC8qIGlmIGl0ZW1zIGFyZSBub3QgaW5zZXJ0ZWQsIG9ubHkgdHJhdmVyc2UgbW9kZWwgdHJlZSBpZiBpdGVtcyBhcmUgZGVsZXRlZCBmcm9tIGFycmF5ICovIH19XFxuICAgICAgICB7ez8gaXQucGFyc2VkUGF0aC5sZW5ndGggfX1cXG4gICAgICAgICAgICB7eyMgZGVmLnRyYXZlcnNlVHJlZSB9fVxcblxcbiAgICAgICAgICAgIHt7XFxuICAgICAgICAgICAgICAgIHZhciBjdXJyTm9kZSA9IGl0LnBhcnNlZFBhdGhbY291bnRdO1xcbiAgICAgICAgICAgICAgICB2YXIgY3VyclByb3AgPSBjdXJyTm9kZS5wcm9wZXJ0eTsgICAgICAgXFxuICAgICAgICAgICAgfX1cXG5cXG4gICAgICAgICAgICB7eyAvKiBleHRyYSBicmFjZSBjbG9zZXMgJ2Vsc2UnIGluIGRlZi50cmF2ZXJzZVRyZWVTdGVwICovIH19XFxuICAgICAgICAgICAge3sjIGRlZi50cmF2ZXJzZVRyZWVTdGVwIH19IH1cXG4gICAgICAgIHt7P319XFxuICAgIH1cXG5cXG4gICAge3sgLyogc3BsaWNlIGl0ZW1zICovIH19XFxuICAgIGlmIChhZGRJdGVtcyB8fCAoISB0cmVlRG9lc05vdEV4aXN0ICYmIG1cXG4gICAgICAgICAgICAmJiBtLmxlbmd0aCA+IHNwbGljZUluZGV4ICkgKSB7XFxuICAgICAgICB2YXIgb2xkTGVuZ3RoID0gbS5sZW5ndGggPSBtLmxlbmd0aCB8fCAwO1xcblxcbiAgICAgICAgYXJndW1lbnRzWzBdID0gc3BsaWNlSW5kZXggPSBub3JtYWxpemVTcGxpY2VJbmRleChzcGxpY2VJbmRleCwgbS5sZW5ndGgpO1xcblxcbiAgICAgICAge3sgLyogY2xvbmUgYWRkZWQgYXJndW1lbnRzIHRvIHByZXZlbnQgc2FtZSByZWZlcmVuY2VzIGluIGxpbmtlZCBtb2RlbHMgKi8gfX1cXG4gICAgICAgIGlmIChhZGRJdGVtcylcXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMjsgaSA8IGFyZ3NMZW47IGkrKylcXG4gICAgICAgICAgICAgICAgYXJndW1lbnRzW2ldID0gY2xvbmVUcmVlKGFyZ3VtZW50c1tpXSk7XFxuXFxuICAgICAgICB7eyAvKiBhY3R1YWwgc3BsaWNlIGNhbGwgKi8gfX1cXG4gICAgICAgIHZhciByZW1vdmVkID0gQXJyYXkucHJvdG90eXBlLnNwbGljZS5hcHBseShtLCBhcmd1bWVudHMpO1xcblxcbiAgICAgICAgaWYgKHRoaXMuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XFxuICAgICAgICAgICAge3sjIGRlZi5hZGRNc2cgfX0gYWNjZXNzUGF0aCwgdHlwZTogJ3NwbGljZScsXFxuICAgICAgICAgICAgICAgICAgICBpbmRleDogc3BsaWNlSW5kZXgsIHJlbW92ZWQ6IHJlbW92ZWQsIGFkZGVkQ291bnQ6IGFkZEl0ZW1zID8gYXJnc0xlbiAtIDIgOiAwLFxcbiAgICAgICAgICAgICAgICAgICAgbmV3VmFsdWU6IG0gfSk7XFxuXFxuICAgICAgICAgICAgaWYgKHJlbW92ZWQgJiYgcmVtb3ZlZC5sZW5ndGgpXFxuICAgICAgICAgICAgICAgIHJlbW92ZWQuZm9yRWFjaChmdW5jdGlvbihpdGVtLCBpbmRleCkge1xcbiAgICAgICAgICAgICAgICAgICAgdmFyIGl0ZW1QYXRoID0gYWNjZXNzUGF0aCArICdbJyArIChzcGxpY2VJbmRleCArIGluZGV4KSArICddJztcXG4gICAgICAgICAgICAgICAgICAgIHt7IyBkZWYuYWRkTXNnIH19IGl0ZW1QYXRoLCB0eXBlOiAncmVtb3ZlZCcsIG9sZFZhbHVlOiBpdGVtIH0pO1xcblxcbiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlSXNUcmVlKGl0ZW0pKVxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFkZE1lc3NhZ2VzKG1lc3NhZ2VzLCBtZXNzYWdlc0hhc2gsIGl0ZW1QYXRoLCBpdGVtLCAncmVtb3ZlZCcsICdvbGRWYWx1ZScpO1xcbiAgICAgICAgICAgICAgICB9KTtcXG5cXG4gICAgICAgICAgICBpZiAoYWRkSXRlbXMpXFxuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAyOyBpIDwgYXJnc0xlbjsgaSsrKSB7XFxuICAgICAgICAgICAgICAgICAgICB2YXIgaXRlbSA9IGFyZ3VtZW50c1tpXTtcXG4gICAgICAgICAgICAgICAgICAgIHZhciBpdGVtUGF0aCA9IGFjY2Vzc1BhdGggKyAnWycgKyAoc3BsaWNlSW5kZXggKyBpIC0gMikgKyAnXSc7XFxuICAgICAgICAgICAgICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSBpdGVtUGF0aCwgdHlwZTogJ2FkZGVkJywgbmV3VmFsdWU6IGl0ZW0gfSk7XFxuXFxuICAgICAgICAgICAgICAgICAgICBpZiAodmFsdWVJc1RyZWUoaXRlbSkpXFxuICAgICAgICAgICAgICAgICAgICAgICAgYWRkTWVzc2FnZXMobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgaXRlbVBhdGgsIGl0ZW0sICdhZGRlZCcsICduZXdWYWx1ZScpO1xcbiAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAge3sgLyogcG9zdCBhbGwgc3RvcmVkIG1lc3NhZ2VzICovIH19XFxuICAgICAgICAgICAge3sjIGRlZi5wb3N0TWVzc2FnZXMgfX1cXG4gICAgICAgIH1cXG4gICAgfVxcblxcbiAgICByZXR1cm4gcmVtb3ZlZCB8fCBbXTtcXG59XFxuXCJcbn07XG5cbnZhciBpbmNsdWRlX2RlZmluZXMgPSBcIid1c2Ugc3RyaWN0JztcXG4vKiBPbmx5IHVzZSB0aGlzIHN0eWxlIG9mIGNvbW1lbnRzLCBub3QgXFxcIi8vXFxcIiAqL1xcblxcbi8qKlxcbiAqIEluc2VydHMgaW5pdGlhbGl6YXRpb24gY29kZVxcbiAqL1xcbiB7eyMjIGRlZi5pbml0VmFyczptZXRob2Q6XFxuICAgIHZhciBtID0ge3sjIGRlZi5tb2RlbEFjY2Vzc1ByZWZpeCB9fTtcXG4gICAgdmFyIG1lc3NhZ2VzID0gW10sIG1lc3NhZ2VzSGFzaCA9IHt9O1xcbiAgICB2YXIgYWNjZXNzUGF0aCA9ICcnO1xcbiAgICB2YXIgdHJlZURvZXNOb3RFeGlzdDtcXG4gICAgLyogaGFjayB0byBwcmV2ZW50IHNlbmRpbmcgZmluaXNoZWQgZXZlbnRzIHRvIGFsbG93IGZvciBwcm9wYWdhdGlvbiBvZiBiYXRjaGVzIHdpdGhvdXQgc3BsaXR0aW5nIHRoZW0gKi9cXG4gICAgdmFyIGluQ2hhbmdlVHJhbnNhY3Rpb24gPSBnZXRUcmFuc2FjdGlvbkZsYWcoIHt7PSBtZXRob2QgfX0gKTtcXG4gI319XFxuXFxuLyoqXFxuICogSW5zZXJ0cyB0aGUgYmVnaW5uaW5nIG9mIGZ1bmN0aW9uIGNhbGwgdG8gYWRkIG1lc3NhZ2UgdG8gbGlzdFxcbiAqL1xcbnt7IyMgZGVmLmFkZE1zZzogYWRkQ2hhbmdlTWVzc2FnZShtZXNzYWdlcywgbWVzc2FnZXNIYXNoLCB7IHBhdGg6ICN9fVxcblxcbi8qKlxcbiAqIEluc2VydHMgY3VycmVudCBwcm9wZXJ0eS9pbmRleCBmb3IgYm90aCBub3JtYWwgYW5kIGludGVycG9sYXRlZCBwcm9wZXJ0aWVzL2luZGV4ZXNcXG4gKi9cXG57eyMjIGRlZi5jdXJyUHJvcDp7ez8gY3Vyck5vZGUuaW50ZXJwb2xhdGUgfX1bdGhpcy5fYXJnc1sge3s9IGN1cnJOb2RlLmludGVycG9sYXRlIH19IF1de3s/P319e3s9IGN1cnJQcm9wIH19e3s/fX0gI319XFxuXFxuLyoqXFxuICogSW5zZXJ0cyBjb25kaXRpb24gdG8gdGVzdCB3aGV0aGVyIG5vcm1hbC9pbnRlcnBvbGF0ZWQgcHJvcGVydHkvaW5kZXggZXhpc3RzXFxuICovXFxue3sjIyBkZWYud2FzRGVmaW5lZDogbS5oYXNPd25Qcm9wZXJ0eShcXG4gICAge3s/IGN1cnJOb2RlLmludGVycG9sYXRlIH19XFxuICAgICAgICB0aGlzLl9hcmdzWyB7ez0gY3Vyck5vZGUuaW50ZXJwb2xhdGUgfX0gXVxcbiAgICB7ez8/fX1cXG4gICAgICAgICd7ez0gaXQuZ2V0UGF0aE5vZGVLZXkoY3Vyck5vZGUpIH19J1xcbiAgICB7ez99fVxcbikgI319XFxuXFxuXFxuLyoqXFxuICogSW5zZXJ0cyBjb2RlIHRvIHVwZGF0ZSBhY2Nlc3MgcGF0aCBmb3IgY3VycmVudCBwcm9wZXJ0eVxcbiAqIEJlY2F1c2Ugb2YgdGhlIHBvc3NpYmlsaXR5IG9mIGludGVycG9sYXRlZCBwcm9wZXJ0aWVzLCBpdCBjYW4ndCBiZSBjYWxjdWxhdGVkIGluIHRlbXBsYXRlLCBpdCBjYW4gb25seSBiZSBjYWxjdWxhdGVkIGR1cmluZyBhY2Nlc3NvciBjYWxsLlxcbiAqL1xcbnt7IyMgZGVmLmNoYW5nZUFjY2Vzc1BhdGg6XFxuICAgIGFjY2Vzc1BhdGggKz0ge3s/IGN1cnJOb2RlLmludGVycG9sYXRlIH19XFxuICAgICAgICB7ez8gY3Vyck5vZGUuc3ludGF4ID09ICdhcnJheScgfX1cXG4gICAgICAgICAgICAnWycgKyB0aGlzLl9hcmdzWyB7ez0gY3Vyck5vZGUuaW50ZXJwb2xhdGUgfX0gXSArICddJztcXG4gICAgICAgIHt7Pz99fVxcbiAgICAgICAgICAgICcuJyArIHRoaXMuX2FyZ3NbIHt7PSBjdXJyTm9kZS5pbnRlcnBvbGF0ZSB9fSBdO1xcbiAgICAgICAge3s/fX1cXG4gICAge3s/P319XFxuICAgICAgICAne3s9IGN1cnJQcm9wIH19JztcXG4gICAge3s/fX1cXG4jfX1cXG5cXG5cXG4vKipcXG4gKiBJbnNlcnRzIGNvZGUgdG8gcG9zdCBzdG9yZWQgbWVzc2FnZXNcXG4gKi9cXG57eyMjIGRlZi5wb3N0TWVzc2FnZXM6XFxuICAgIGlmIChtZXNzYWdlcy5sZW5ndGgpIHtcXG4gICAgICAgIHt7IyBkZWYubW9kZWxQb3N0QmF0Y2hDb2RlIH19KCdkYXRhY2hhbmdlcycsIHtcXG4gICAgICAgICAgICBjaGFuZ2VzOiBtZXNzYWdlcyxcXG4gICAgICAgICAgICB0cmFuc2FjdGlvbjogaW5DaGFuZ2VUcmFuc2FjdGlvblxcbiAgICAgICAgfSk7XFxuXFxuICAgICAgICBtZXNzYWdlcy5mb3JFYWNoKGZ1bmN0aW9uKG1zZykge1xcbiAgICAgICAgICAgIHt7IyBkZWYubW9kZWxQb3N0TWVzc2FnZUNvZGUgfX0obXNnLnBhdGgsIG1zZyk7XFxuICAgICAgICB9LCB0aGlzKTtcXG4gICAgfVxcbiN9fVxcblwiXG4gICAgLCBpbmNsdWRlX2NyZWF0ZV90cmVlID0gXCIndXNlIHN0cmljdCc7XFxuLyogT25seSB1c2UgdGhpcyBzdHlsZSBvZiBjb21tZW50cywgbm90IFxcXCIvL1xcXCIgKi9cXG5cXG4vKipcXG4gKiBJbnNlcnRzIGNvZGUgdG8gY3JlYXRlIG1vZGVsIHRyZWUgYXMgbmVjY2Vzc2FyeSBmb3IgYHNldGAgYW5kIGBzcGxpY2VgIGFjY2Vzc29ycyBhbmQgdG8gYWRkIG1lc3NhZ2VzIHRvIHNlbmQgbGlzdCBpZiB0aGUgdHJlZSBjaGFuZ2VzLlxcbiAqL1xcbnt7IyMgZGVmLmNyZWF0ZVRyZWU6bWV0aG9kOlxcbiAgICB2YXIgd2FzRGVmID0gdHJ1ZTtcXG4gICAgdmFyIG9sZCA9IG07XFxuXFxuICAgIHt7IHZhciBlbXB0eVByb3AgPSBpdC5wYXJzZWRQYXRoWzBdICYmIGl0LnBhcnNlZFBhdGhbMF0uZW1wdHk7IH19XFxuICAgIHt7PyBlbXB0eVByb3AgfX1cXG4gICAgICAgIHt7IC8qIGNyZWF0ZSB0b3AgbGV2ZWwgbW9kZWwgaWYgaXQgd2FzIG5vdCBwcmV2aW91c2x5IGRlZmluZWQgKi8gfX1cXG4gICAgICAgIGlmICghIG0pIHtcXG4gICAgICAgICAgICBtID0ge3sjIGRlZi5tb2RlbEFjY2Vzc1ByZWZpeCB9fSA9IHt7PSBlbXB0eVByb3AgfX07XFxuICAgICAgICAgICAgd2FzRGVmID0gZmFsc2U7XFxuXFxuICAgICAgICAgICAgaWYgKHRoaXMuX29wdGlvbnMucmVhY3RpdmUgIT09IGZhbHNlKSB7XFxuICAgICAgICAgICAgICAgIHt7IyBkZWYuYWRkTXNnIH19ICcnLCB0eXBlOiAnYWRkZWQnLFxcbiAgICAgICAgICAgICAgICAgICAgICBuZXdWYWx1ZTogbSB9KTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgIHt7Pz99fVxcbiAgICAgICAge3s/IG1ldGhvZCA9PSAnc3BsaWNlJyB9fVxcbiAgICAgICAgICAgIGlmICghIG0pIHtcXG4gICAgICAgIHt7P319XFxuICAgICAgICAgICAgICAgIG0gPSB7eyMgZGVmLm1vZGVsQWNjZXNzUHJlZml4IH19ID0gY2xvbmVUcmVlKHZhbHVlKTtcXG4gICAgICAgICAgICAgICAgd2FzRGVmID0gdHlwZW9mIG9sZCAhPSAndW5kZWZpbmVkJztcXG4gICAgICAgIHt7PyBtZXRob2QgPT0gJ3NwbGljZScgfX1cXG4gICAgICAgICAgICB9XFxuICAgICAgICB7ez99fSAgICAgICBcXG4gICAge3s/fX1cXG5cXG5cXG4gICAge3sgLyogY3JlYXRlIG1vZGVsIHRyZWUgaWYgaXQgZG9lc24ndCBleGlzdCAqLyB9fVxcbiAgICB7eyAgdmFyIG1vZGVsRGF0YVByb3BlcnR5ID0gJyc7XFxuICAgICAgICB2YXIgbmV4dE5vZGUgPSBpdC5wYXJzZWRQYXRoWzBdO1xcbiAgICAgICAgdmFyIGNvdW50ID0gaXQucGFyc2VkUGF0aC5sZW5ndGggLSAxO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb3VudDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIGN1cnJOb2RlID0gbmV4dE5vZGU7XFxuICAgICAgICAgICAgdmFyIGN1cnJQcm9wID0gY3Vyck5vZGUucHJvcGVydHk7XFxuICAgICAgICAgICAgbmV4dE5vZGUgPSBpdC5wYXJzZWRQYXRoW2kgKyAxXTtcXG4gICAgICAgICAgICB2YXIgZW1wdHlQcm9wID0gbmV4dE5vZGUgJiYgbmV4dE5vZGUuZW1wdHk7XFxuICAgIH19XFxuXFxuICAgICAgICB7eyMgZGVmLmNyZWF0ZVRyZWVTdGVwIH19XFxuXFxuICAgIHt7ICB9IC8qIGZvciBsb29wICovIH19XFxuI319XFxuXFxuXFxuLyoqXFxuICogSW5zZXJ0cyBjb2RlIHRvIGNyZWF0ZSBvbmUgc3RlcCBpbiB0aGUgbW9kZWwgdHJlZVxcbiAqL1xcbnt7IyMgZGVmLmNyZWF0ZVRyZWVTdGVwOlxcbiAgICB7eyMgZGVmLmNoYW5nZUFjY2Vzc1BhdGggfX1cXG5cXG4gICAgaWYgKCEge3sjIGRlZi53YXNEZWZpbmVkIH19KSB7IFxcbiAgICAgICAge3sgLyogcHJvcGVydHkgZG9lcyBub3QgZXhpc3QgKi8gfX1cXG4gICAgICAgIG0gPSBte3sjIGRlZi5jdXJyUHJvcCB9fSA9IHt7PSBlbXB0eVByb3AgfX07XFxuXFxuICAgICAgICBpZiAodGhpcy5fb3B0aW9ucy5yZWFjdGl2ZSAhPT0gZmFsc2UpIHtcXG4gICAgICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSBhY2Nlc3NQYXRoLCB0eXBlOiAnYWRkZWQnLCBcXG4gICAgICAgICAgICAgICAgICBuZXdWYWx1ZTogbSB9KTtcXG4gICAgICAgIH1cXG5cXG4gICAgfSBlbHNlIGlmICh0eXBlb2YgbXt7IyBkZWYuY3VyclByb3AgfX0gIT0gJ29iamVjdCcpIHtcXG4gICAgICAgIHt7IC8qIHByb3BlcnR5IGlzIG5vdCBvYmplY3QgKi8gfX1cXG4gICAgICAgIHZhciBvbGQgPSBte3sjIGRlZi5jdXJyUHJvcCB9fTtcXG4gICAgICAgIG0gPSBte3sjIGRlZi5jdXJyUHJvcCB9fSA9IHt7PSBlbXB0eVByb3AgfX07XFxuXFxuICAgICAgICBpZiAodGhpcy5fb3B0aW9ucy5yZWFjdGl2ZSAhPT0gZmFsc2UpIHtcXG4gICAgICAgICAgICB7eyMgZGVmLmFkZE1zZyB9fSBhY2Nlc3NQYXRoLCB0eXBlOiAnY2hhbmdlZCcsIFxcbiAgICAgICAgICAgICAgICAgIG9sZFZhbHVlOiBvbGQsIG5ld1ZhbHVlOiBtIH0pO1xcbiAgICAgICAgfVxcblxcbiAgICB9IGVsc2Uge1xcbiAgICAgICAge3sgLyogcHJvcGVydHkgZXhpc3RzLCBqdXN0IHRyYXZlcnNlIGRvd24gdGhlIG1vZGVsIHRyZWUgKi8gfX1cXG4gICAgICAgIG0gPSBte3sjIGRlZi5jdXJyUHJvcCB9fTtcXG4gICAgfVxcbiN9fVxcblwiXG4gICAgLCBpbmNsdWRlX3RyYXZlcnNlX3RyZWUgPSBcIid1c2Ugc3RyaWN0JztcXG4vKiBPbmx5IHVzZSB0aGlzIHN0eWxlIG9mIGNvbW1lbnRzLCBub3QgXFxcIi8vXFxcIiAqL1xcblxcbi8qKlxcbiAqIEluc2VydHMgY29kZSB0byB0cmF2ZXJzZSBtb2RlbCB0cmVlIGZvciBgZGVsZXRlYCBhbmQgYHNwbGljZWAgYWNjZXNzb3JzLlxcbiAqL1xcbnt7IyMgZGVmLnRyYXZlcnNlVHJlZTpcXG4gICAge3sgXFxuICAgICAgICB2YXIgY291bnQgPSBpdC5wYXJzZWRQYXRoLmxlbmd0aC0xO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb3VudDsgaSsrKSB7IFxcbiAgICAgICAgICAgIHZhciBjdXJyTm9kZSA9IGl0LnBhcnNlZFBhdGhbaV07XFxuICAgICAgICAgICAgdmFyIGN1cnJQcm9wID0gY3Vyck5vZGUucHJvcGVydHk7XFxuICAgIH19XFxuICAgICAgICAgICAge3sjIGRlZi50cmF2ZXJzZVRyZWVTdGVwIH19XFxuXFxuICAgIHt7IH0gLyogZm9yIGxvb3AgKi9cXG5cXG4gICAgICAgIHZhciBpID0gY291bnQ7XFxuICAgICAgICB3aGlsZSAoaS0tKSB7IC8qIGNsb3NpbmcgYnJhY2VzIGZvciBlbHNlJ3MgYWJvdmUgKi9cXG4gICAgfX1cXG4gICAgICAgICAgICB9XFxuICAgIHt7IH0gLyogd2hpbGUgbG9vcCAqLyB9fVxcbiN9fVxcblxcblxcbi8qKlxcbiAqIEluc2VydHMgY29kZSB0byB0cmF2ZXJzZSBvbmUgc3RlcCBpbiB0aGUgbW9kZWwgdHJlZVxcbiAqL1xcbnt7IyMgZGVmLnRyYXZlcnNlVHJlZVN0ZXA6XFxuICAgIGlmICghIChtICYmIG0uaGFzT3duUHJvcGVydHkgJiYge3sjIGRlZi53YXNEZWZpbmVkfX0gKSApXFxuICAgICAgICB0cmVlRG9lc05vdEV4aXN0ID0gdHJ1ZTtcXG4gICAgZWxzZSB7XFxuICAgICAgICBtID0gbXt7IyBkZWYuY3VyclByb3AgfX07XFxuICAgICAgICB7eyMgZGVmLmNoYW5nZUFjY2Vzc1BhdGggfX1cXG4gICAge3sgLyogYnJhY2UgZnJvbSBlbHNlIGlzIG5vdCBjbG9zZWQgb24gcHVycG9zZSAtIGFsbCBicmFjZXMgYXJlIGNsb3NlZCBpbiB3aGlsZSBsb29wICovIH19XFxuI319XFxuXCI7XG5cbnZhciBkb3REZWYgPSB7XG4gICAgaW5jbHVkZV9kZWZpbmVzOiBpbmNsdWRlX2RlZmluZXMsXG4gICAgaW5jbHVkZV9jcmVhdGVfdHJlZTogaW5jbHVkZV9jcmVhdGVfdHJlZSxcbiAgICBpbmNsdWRlX3RyYXZlcnNlX3RyZWU6IGluY2x1ZGVfdHJhdmVyc2VfdHJlZSxcbiAgICBnZXRQYXRoTm9kZUtleTogcGF0aFV0aWxzLmdldFBhdGhOb2RlS2V5LFxuICAgIG1vZGVsQWNjZXNzUHJlZml4OiAndGhpcy5fbW9kZWwuX2RhdGEnLFxuICAgIG1vZGVsUG9zdE1lc3NhZ2VDb2RlOiAndGhpcy5fbW9kZWwuX2ludGVybmFsTWVzc2VuZ2VyLnBvc3RNZXNzYWdlJyxcbiAgICBtb2RlbFBvc3RCYXRjaENvZGU6ICd0aGlzLl9tb2RlbC5wb3N0TWVzc2FnZVN5bmMnLFxuICAgIGludGVybmFsTWVzc2VuZ2VyOiAndGhpcy5fbW9kZWwuX2ludGVybmFsTWVzc2VuZ2VyJ1xufTtcblxudmFyIG1vZGVsRG90RGVmID0gXyhkb3REZWYpLmNsb25lKCkuZXh0ZW5kKHtcbiAgICBtb2RlbEFjY2Vzc1ByZWZpeDogJ3RoaXMuX2RhdGEnLFxuICAgIG1vZGVsUG9zdE1lc3NhZ2VDb2RlOiAndGhpcy5faW50ZXJuYWxNZXNzZW5nZXIucG9zdE1lc3NhZ2UnLFxuICAgIG1vZGVsUG9zdEJhdGNoQ29kZTogJ3RoaXMucG9zdE1lc3NhZ2VTeW5jJyxcbiAgICBpbnRlcm5hbE1lc3NlbmdlcjogJ3RoaXMuX2ludGVybmFsTWVzc2VuZ2VyJ1xufSkuXygpO1xuXG5cbnZhciBkb3RTZXR0aW5ncyA9IF8uY2xvbmUoZG9ULnRlbXBsYXRlU2V0dGluZ3MpO1xuZG90U2V0dGluZ3Muc3RyaXAgPSBmYWxzZTtcblxudmFyIHN5bnRoZXNpemVycyA9IF8ubWFwS2V5cyh0ZW1wbGF0ZXMsIGZ1bmN0aW9uKHRtcGwpIHtcbiAgICByZXR1cm4gZG9ULnRlbXBsYXRlKHRtcGwsIGRvdFNldHRpbmdzLCBkb3REZWYpOyBcbn0pO1xuXG5cbnZhciBtb2RlbFN5bnRoZXNpemVycyA9IF8ubWFwVG9PYmplY3QoWydzZXQnLCAnZGVsJywgJ3NwbGljZSddLCBmdW5jdGlvbihtZXRob2ROYW1lKSB7XG4gICAgcmV0dXJuIGRvVC50ZW1wbGF0ZSh0ZW1wbGF0ZXNbbWV0aG9kTmFtZV0sIGRvdFNldHRpbmdzLCBtb2RlbERvdERlZik7XG59KTtcblxuXG4vKipcbiAqIEZ1bmN0aW9uIHRoYXQgc3ludGhlc2l6ZXMgYWNjZXNzb3IgbWV0aG9kcy5cbiAqIEZ1bmN0aW9uIGlzIG1lbW9pemVkIHNvIGFjY2Vzc29ycyBhcmUgY2FjaGVkICh1cCB0byAxMDAwKS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gcGF0aCBNb2RlbC9Nb2RlbFBhdGggYWNjZXNzIHBhdGhcbiAqIEBwYXJhbSB7QXJyYXl9IHBhcnNlZFBhdGggYXJyYXkgb2YgcGF0aCBub2Rlc1xuICogQHJldHVybiB7T2JqZWN0W0Z1bmN0aW9uXX1cbiAqL1xudmFyIHN5bnRoZXNpemVQYXRoTWV0aG9kcyA9IF8ubWVtb2l6ZShfc3ludGhlc2l6ZVBhdGhNZXRob2RzLCB1bmRlZmluZWQsIDEwMDApO1xuXG5mdW5jdGlvbiBfc3ludGhlc2l6ZVBhdGhNZXRob2RzKHBhdGgsIHBhcnNlZFBhdGgpIHtcbiAgICB2YXIgbWV0aG9kcyA9IF8ubWFwS2V5cyhzeW50aGVzaXplcnMsIGZ1bmN0aW9uKHN5bnRoc3pyKSB7XG4gICAgICAgIHJldHVybiBfc3ludGhlc2l6ZShzeW50aHN6ciwgcGF0aCwgcGFyc2VkUGF0aCk7XG4gICAgfSk7XG4gICAgcmV0dXJuIG1ldGhvZHM7XG59XG5cblxudmFyIG5vcm1hbGl6ZVNwbGljZUluZGV4ID0gbW9kZWxVdGlscy5ub3JtYWxpemVTcGxpY2VJbmRleDsgLy8gdXNlZCBpbiBzcGxpY2UuZG90LmpzXG5cblxuZnVuY3Rpb24gX3N5bnRoZXNpemUoc3ludGhlc2l6ZXIsIHBhdGgsIHBhcnNlZFBhdGgpIHtcbiAgICB2YXIgbWV0aG9kXG4gICAgICAgICwgbWV0aG9kQ29kZSA9IHN5bnRoZXNpemVyKHtcbiAgICAgICAgICAgIHBhcnNlZFBhdGg6IHBhcnNlZFBhdGgsXG4gICAgICAgICAgICBnZXRQYXRoTm9kZUtleTogcGF0aFV0aWxzLmdldFBhdGhOb2RlS2V5XG4gICAgICAgIH0pO1xuXG4gICAgdHJ5IHtcbiAgICAgICAgZXZhbChtZXRob2RDb2RlKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IE1vZGVsRXJyb3IoJ01vZGVsUGF0aCBtZXRob2QgY29tcGlsYXRpb24gZXJyb3I7IHBhdGg6ICcgKyBwYXRoICsgJywgY29kZTogJyArIG1ldGhvZENvZGUpO1xuICAgIH1cblxuICAgIHJldHVybiBtZXRob2Q7XG5cblxuICAgIC8vIGZ1bmN0aW9ucyB1c2VkIGJ5IG1ldGhvZHMgYHNldGAsIGBkZWxldGVgIGFuZCBgc3BsaWNlYCAoc3ludGhlc2l6ZWQgYnkgdGVtcGxhdGUpXG4gICAgZnVuY3Rpb24gYWRkQ2hhbmdlTWVzc2FnZShtZXNzYWdlcywgbWVzc2FnZXNIYXNoLCBtc2cpIHtcbiAgICAgICAgbWVzc2FnZXMucHVzaChtc2cpO1xuICAgICAgICBtZXNzYWdlc0hhc2hbbXNnLnBhdGhdID0gbXNnO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFkZFRyZWVDaGFuZ2VzTWVzc2FnZXMobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgcm9vdFBhdGgsIG9sZFZhbHVlLCBuZXdWYWx1ZSkge1xuICAgICAgICB2YXIgb2xkSXNUcmVlID0gdmFsdWVJc1RyZWUob2xkVmFsdWUpXG4gICAgICAgICAgICAsIG5ld0lzVHJlZSA9IHZhbHVlSXNUcmVlKG5ld1ZhbHVlKTtcblxuICAgICAgICBpZiAobmV3SXNUcmVlKVxuICAgICAgICAgICAgYWRkTWVzc2FnZXMobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgcm9vdFBhdGgsIG5ld1ZhbHVlLCAnYWRkZWQnLCAnbmV3VmFsdWUnKTtcbiAgICAgICAgXG4gICAgICAgIGlmIChvbGRJc1RyZWUpXG4gICAgICAgICAgICBhZGRNZXNzYWdlcyhtZXNzYWdlcywgbWVzc2FnZXNIYXNoLCByb290UGF0aCwgb2xkVmFsdWUsICdyZW1vdmVkJywgJ29sZFZhbHVlJyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYWRkTWVzc2FnZXMobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgcm9vdFBhdGgsIG9iaiwgbXNnVHlwZSwgdmFsdWVQcm9wKSB7XG4gICAgICAgIF9hZGRNZXNzYWdlcyhyb290UGF0aCwgb2JqKTtcblxuXG4gICAgICAgIGZ1bmN0aW9uIF9hZGRNZXNzYWdlcyhyb290UGF0aCwgb2JqKSB7XG4gICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvYmopKSB7XG4gICAgICAgICAgICAgICAgdmFyIHBhdGhTeW50YXggPSByb290UGF0aCArICdbJCRdJztcbiAgICAgICAgICAgICAgICBvYmouZm9yRWFjaChmdW5jdGlvbih2YWx1ZSwgaW5kZXgpIHtcbiAgICAgICAgICAgICAgICAgICAgYWRkTWVzc2FnZSh2YWx1ZSwgaW5kZXgsIHBhdGhTeW50YXgpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YXIgcGF0aFN5bnRheCA9IHJvb3RQYXRoICsgJy4kJCc7XG4gICAgICAgICAgICAgICAgXy5lYWNoS2V5KG9iaiwgZnVuY3Rpb24odmFsdWUsIGtleSkge1xuICAgICAgICAgICAgICAgICAgICBhZGRNZXNzYWdlKHZhbHVlLCBrZXksIHBhdGhTeW50YXgpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gYWRkTWVzc2FnZSh2YWx1ZSwga2V5LCBwYXRoU3ludGF4KSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHBhdGhTeW50YXgucmVwbGFjZSgnJCQnLCBrZXkpXG4gICAgICAgICAgICAgICAgLCBleGlzdGluZ01zZyA9IG1lc3NhZ2VzSGFzaFtwYXRoXTtcblxuICAgICAgICAgICAgaWYgKGV4aXN0aW5nTXNnKSB7XG4gICAgICAgICAgICAgICAgaWYgKGV4aXN0aW5nTXNnLnR5cGUgPT0gbXNnVHlwZSlcbiAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCdzZXR0ZXIgZXJyb3I6IHNhbWUgbWVzc2FnZSB0eXBlIHBvc3RlZCBvbiB0aGUgc2FtZSBwYXRoJyk7XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGV4aXN0aW5nTXNnLnR5cGUgPSAnY2hhbmdlZCc7XG4gICAgICAgICAgICAgICAgICAgIGV4aXN0aW5nTXNnW3ZhbHVlUHJvcF0gPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHZhciBtc2cgPSB7IHBhdGg6IHBhdGgsIHR5cGU6IG1zZ1R5cGUgfTtcbiAgICAgICAgICAgICAgICBtc2dbdmFsdWVQcm9wXSA9IHZhbHVlO1xuICAgICAgICAgICAgICAgIGFkZENoYW5nZU1lc3NhZ2UobWVzc2FnZXMsIG1lc3NhZ2VzSGFzaCwgbXNnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHZhbHVlSXNUcmVlKHZhbHVlKSlcbiAgICAgICAgICAgICAgICBfYWRkTWVzc2FnZXMocGF0aCwgdmFsdWUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY2xvbmVUcmVlKHZhbHVlKSB7XG4gICAgICAgIHJldHVybiB2YWx1ZUlzTm9ybWFsT2JqZWN0KHZhbHVlKVxuICAgICAgICAgICAgICAgID8gXy5kZWVwQ2xvbmUodmFsdWUpXG4gICAgICAgICAgICAgICAgOiB2YWx1ZTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwcm90ZWN0VmFsdWUodmFsdWUpIHtcbiAgICAgICAgcmV0dXJuICEgdmFsdWVJc05vcm1hbE9iamVjdCh2YWx1ZSlcbiAgICAgICAgICAgICAgICA/IHZhbHVlXG4gICAgICAgICAgICAgICAgOiBBcnJheS5pc0FycmF5KHZhbHVlKVxuICAgICAgICAgICAgICAgICAgICA/IHZhbHVlLnNsaWNlKClcbiAgICAgICAgICAgICAgICAgICAgOiBPYmplY3QuY3JlYXRlKHZhbHVlKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB2YWx1ZUlzVHJlZSh2YWx1ZSkge1xuICAgICAgICByZXR1cm4gdmFsdWVJc05vcm1hbE9iamVjdCh2YWx1ZSlcbiAgICAgICAgICAgICAgICAmJiBPYmplY3Qua2V5cyh2YWx1ZSkubGVuZ3RoO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHZhbHVlSXNOb3JtYWxPYmplY3QodmFsdWUpIHtcbiAgICAgICAgcmV0dXJuIHZhbHVlICE9IG51bGxcbiAgICAgICAgICAgICAgICAmJiB0eXBlb2YgdmFsdWUgPT0gXCJvYmplY3RcIlxuICAgICAgICAgICAgICAgICYmICEgKHZhbHVlIGluc3RhbmNlb2YgRGF0ZSlcbiAgICAgICAgICAgICAgICAmJiAhICh2YWx1ZSBpbnN0YW5jZW9mIFJlZ0V4cCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYWRkQmF0Y2hJZHNUb01lc3NhZ2UobXNnLCBiYXRjaElkLCBtc2dJZCkge1xuICAgICAgICBfLmRlZmluZVByb3BlcnRpZXMobXNnLCB7XG4gICAgICAgICAgICBfX2JhdGNoX2lkOiBiYXRjaElkLFxuICAgICAgICAgICAgX19tc2dfaWQ6IG1zZ0lkXG4gICAgICAgIH0pO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIEV4cG9ydHMgYHN5bnRoZXNpemVgIGZ1bmN0aW9uIHdpdGggdGhlIGZvbGxvd2luZzpcbiAqXG4gKiAtIC5tb2RlbE1ldGhvZHMuc2V0IC0gYHNldGAgbWV0aG9kIGZvciBNb2RlbFxuICogLSAubW9kZWxNZXRob2RzLmRlbCAtIGBkZWxgIG1ldGhvZCBmb3IgTW9kZWxcbiAqIC0gLm1vZGVsTWV0aG9kcy5zcGxpY2UgLSBgc3BsaWNlYCBtZXRob2QgZm9yIE1vZGVsXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gc3ludGhlc2l6ZVBhdGhNZXRob2RzO1xuXG52YXIgbW9kZWxNZXRob2RzID0gXy5tYXBLZXlzKG1vZGVsU3ludGhlc2l6ZXJzLCBmdW5jdGlvbihzeW50aGVzaXplcikge1xuICAgIHJldHVybiBfc3ludGhlc2l6ZShzeW50aGVzaXplciwgJycsIFtdKTtcbn0pO1xuXG5zeW50aGVzaXplUGF0aE1ldGhvZHMubW9kZWxNZXRob2RzID0gbW9kZWxNZXRob2RzO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIGBtaWxvLnV0aWxzLmNoZWNrYFxuICpcbiAqIENoZWNrIGlzIGEgbW9kdWxlIGZvciBwYXJhbWV0ZXJzIGNoZWNraW5nIGV4dHJhY3RlZCBmcm9tIFtNZXRlb3JdKGh0dHA6Ly9kb2NzLm1ldGVvci5jb20vKSBmcmFtZXdvcmsuXG4gKlxuICogSXQgYWxsb3dzIHRvIGJvdGggZG9jdW1lbnQgYW5kIHRvIGNoZWNrIHBhcmFtZXRlciB0eXBlcyBpbiB5b3VyIGZ1bmN0aW9uXG4gKiBtYWtpbmcgY29kZSBib3RoIHJlYWRhYmxlIGFuZCBzdGFibGUuXG4gKlxuICpcbiAqICMjIyBVc2FnZVxuICpgYGBcbiAqIHZhciBjaGVjayA9IG1pbG8uY2hlY2tcbiAqICAgICAsIE1hdGNoID0gY2hlY2suTWF0Y2g7XG4gKlxuICogZnVuY3Rpb24gTXkobmFtZSwgb2JqLCBjYikge1xuICogICAgIC8vIGlmIGFueSBvZiBjaGVja3MgZmFpbCBhbiBlcnJvciB3aWxsIGJlIHRocm93blxuICogICAgIGNoZWNrKG5hbWUsIFN0cmluZyk7XG4gKiAgICAgY2hlY2sob2JqLCBNYXRjaC5PYmplY3RJbmNsdWRpbmcoeyBvcHRpb25zOiBPYmplY3QgfSkpO1xuICogICAgIGNoZWNrKGNiLCBGdW5jdGlvbik7XG4gKlxuICogICAgIC8vIC4uLiB5b3VyIGNvZGVcbiAqIH1cbiAqYGBgXG4gKiBTZWUgW01ldGVvciBkb2NzXShodHRwOi8vZG9jcy5tZXRlb3IuY29tLyNtYXRjaCkgdG8gc2VlIGhvdyBpdCB3b3Jrc1xuICpcbiAqXG4gKiAjIyMgUGF0dGVybnNcbiAqXG4gKiBBbGwgcGF0dGVybnMgYW5kIGZ1bmN0aW9ucyBkZXNjcmliZWQgaW4gTWV0ZW9yIGRvY3Mgd29yay5cbiAqXG4gKiBVbmxpa2UgaW4gTWV0ZW9yLCBPYmplY3QgcGF0dGVybiBtYXRjaGVzIGluc3RhbmNlIG9mIGFueSBjbGFzcyxcbiAqIG5vdCBvbmx5IHBsYWluIG9iamVjdC5cbiAqXG4gKiBJbiBhZGRpdGlvbiB0byBwYXR0ZXJucyBkZXNjcmliZWQgaW4gTWV0ZW9yIGRvY3MgdGhlIGZvbGxvd2luZyBwYXR0ZXJucyBhcmUgaW1wbGVtZW50ZWRcbiAqXG4gKiAqIE1hdGNoLl9fT2JqZWN0SGFzaF9fKF9wYXR0ZXJuXylcbiAqXG4gKiAgIE1hdGNoZXMgYW4gb2JqZWN0IHdoZXJlIGFsbCBwcm9wZXJ0aWVzIG1hdGNoIGEgZ2l2ZW4gcGF0dGVyblxuICpcbiAqICogTWF0Y2guX19TdWJjbGFzc19fKF9jb25zdHJ1Y3Rvcl8gWywgX21hdGNoVGhpc0NsYXNzVG9vX10pXG4gKlxuICogICBNYXRjaGVzIGEgY2xhc3MgdGhhdCBpcyBhIHN1YmNsYXNzIG9mIGEgZ2l2ZW4gY2xhc3MuIElmIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gKiAgIGlzIHRydWUsIGl0IHdpbGwgYWxzbyBtYXRjaCB0aGUgY2xhc3MgaXRzZWxmLlxuICpcbiAqICAgV2l0aG91dCB0aGlzIHBhdHRlcm4gdG8gY2hlY2sgaWYgX015U3ViY2xhc3NfIGlzIGEgc3ViY2xhc3Mgb2YgX015Q2xhc3NfXG4gKiAgIHlvdSB3b3VsZCBoYXZlIHRvIHVzZVxuICpcbiAqICAgICAgIGNoZWNrKE15U3ViY2xhc3MsIE1hdGNoLldoZXJlKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgIHJldHVybiBNeVN1YmNsYXNzLnByb3RvdHlwZSBpbnN0YW5jZW9mIE15Q2xhc3M7XG4gKiAgICAgICB9KTtcbiAqXG4gKlxuICogVGhpbmdzIHdlIGV4cGxpY2l0bHkgZG8gTk9UIHN1cHBvcnQ6XG4gKiAgICAtIGhldGVyb2dlbm91cyBhcnJheXNcbioqL1xuXG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpXG4gICAgLCBjb25maWcgPSByZXF1aXJlKCcuLi9jb25maWcnKTtcblxudmFyIGNoZWNrID0gZnVuY3Rpb24gKHZhbHVlLCBwYXR0ZXJuKSB7XG4gICAgaWYgKGNvbmZpZy5jaGVjayA9PT0gZmFsc2UpXG4gICAgICAgIHJldHVybjtcblxuICAgIC8vIFJlY29yZCB0aGF0IGNoZWNrIGdvdCBjYWxsZWQsIGlmIHNvbWVib2R5IGNhcmVkLlxuICAgIHRyeSB7XG4gICAgICAgIGNoZWNrU3VidHJlZSh2YWx1ZSwgcGF0dGVybik7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGlmICgoZXJyIGluc3RhbmNlb2YgTWF0Y2guRXJyb3IpICYmIGVyci5wYXRoKVxuICAgICAgICAgICAgZXJyLm1lc3NhZ2UgKz0gXCIgaW4gZmllbGQgXCIgKyBlcnIucGF0aDtcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gY2hlY2s7XG5cbnZhciBNYXRjaCA9IGNoZWNrLk1hdGNoID0ge1xuICAgIE9wdGlvbmFsOiBmdW5jdGlvbiAocGF0dGVybikge1xuICAgICAgICByZXR1cm4gbmV3IE9wdGlvbmFsKHBhdHRlcm4pO1xuICAgIH0sXG4gICAgT25lT2Y6IGZ1bmN0aW9uICgvKiBhcmd1bWVudHMgKi8pIHtcbiAgICAgICAgcmV0dXJuIG5ldyBPbmVPZihhcmd1bWVudHMpO1xuICAgIH0sXG4gICAgQW55OiBbJ19fYW55X18nXSxcbiAgICBXaGVyZTogZnVuY3Rpb24gKGNvbmRpdGlvbikge1xuICAgICAgICByZXR1cm4gbmV3IFdoZXJlKGNvbmRpdGlvbik7XG4gICAgfSxcbiAgICBPYmplY3RJbmNsdWRpbmc6IGZ1bmN0aW9uIChwYXR0ZXJuKSB7XG4gICAgICAgIHJldHVybiBuZXcgT2JqZWN0SW5jbHVkaW5nKHBhdHRlcm4pO1xuICAgIH0sXG4gICAgLy8gTWF0Y2hlcyBvbmx5IHNpZ25lZCAzMi1iaXQgaW50ZWdlcnNcbiAgICBJbnRlZ2VyOiBbJ19faW50ZWdlcl9fJ10sXG5cbiAgICAvLyBNYXRjaGVzIHN0cmluZyB0aGF0IGlzIGEgdmFsaWQgaWRlbnRpZmllciwgd2lsbCBub3QgYWxsb3cgamF2YXNjcmlwdCByZXNlcnZlZCB3b3Jkc1xuICAgIElkZW50aWZpZXJTdHJpbmc6IC9eW2Etel8kXVswLTlhLXpfJF0qJC9pLFxuXG4gICAgLy8gTWF0Y2hlcyBoYXNoIChvYmplY3QpIHdpdGggdmFsdWVzIG1hdGNoaW5nIHBhdHRlcm5cbiAgICBPYmplY3RIYXNoOiBmdW5jdGlvbihwYXR0ZXJuKSB7XG4gICAgICAgIHJldHVybiBuZXcgT2JqZWN0SGFzaChwYXR0ZXJuKTtcbiAgICB9LFxuXG4gICAgU3ViY2xhc3M6IGZ1bmN0aW9uKFN1cGVyY2xhc3MsIG1hdGNoU3VwZXJjbGFzc1Rvbykge1xuICAgICAgICByZXR1cm4gbmV3IFN1YmNsYXNzKFN1cGVyY2xhc3MsIG1hdGNoU3VwZXJjbGFzc1Rvbyk7XG4gICAgfSxcblxuICAgIC8vIFhYWCBtYXRjaGVycyBzaG91bGQga25vdyBob3cgdG8gZGVzY3JpYmUgdGhlbXNlbHZlcyBmb3IgZXJyb3JzXG4gICAgRXJyb3I6IFR5cGVFcnJvcixcblxuICAgIC8vIE1ldGVvci5tYWtlRXJyb3JUeXBlKFwiTWF0Y2guRXJyb3JcIiwgZnVuY3Rpb24gKG1zZykge1xuICAgICAgICAvLyB0aGlzLm1lc3NhZ2UgPSBcIk1hdGNoIGVycm9yOiBcIiArIG1zZztcbiAgICAgICAgLy8gVGhlIHBhdGggb2YgdGhlIHZhbHVlIHRoYXQgZmFpbGVkIHRvIG1hdGNoLiBJbml0aWFsbHkgZW1wdHksIHRoaXMgZ2V0c1xuICAgICAgICAvLyBwb3B1bGF0ZWQgYnkgY2F0Y2hpbmcgYW5kIHJldGhyb3dpbmcgdGhlIGV4Y2VwdGlvbiBhcyBpdCBnb2VzIGJhY2sgdXAgdGhlXG4gICAgICAgIC8vIHN0YWNrLlxuICAgICAgICAvLyBFLmcuOiBcInZhbHNbM10uZW50aXR5LmNyZWF0ZWRcIlxuICAgICAgICAvLyB0aGlzLnBhdGggPSBcIlwiO1xuICAgICAgICAvLyBJZiB0aGlzIGdldHMgc2VudCBvdmVyIEREUCwgZG9uJ3QgZ2l2ZSBmdWxsIGludGVybmFsIGRldGFpbHMgYnV0IGF0IGxlYXN0XG4gICAgICAgIC8vIHByb3ZpZGUgc29tZXRoaW5nIGJldHRlciB0aGFuIDUwMCBJbnRlcm5hbCBzZXJ2ZXIgZXJyb3IuXG4gICAgLy8gICAgIHRoaXMuc2FuaXRpemVkRXJyb3IgPSBuZXcgTWV0ZW9yLkVycm9yKDQwMCwgXCJNYXRjaCBmYWlsZWRcIik7XG4gICAgLy8gfSksXG5cbiAgICAvLyBUZXN0cyB0byBzZWUgaWYgdmFsdWUgbWF0Y2hlcyBwYXR0ZXJuLiBVbmxpa2UgY2hlY2ssIGl0IG1lcmVseSByZXR1cm5zIHRydWVcbiAgICAvLyBvciBmYWxzZSAodW5sZXNzIGFuIGVycm9yIG90aGVyIHRoYW4gTWF0Y2guRXJyb3Igd2FzIHRocm93bikuXG4gICAgdGVzdDogZnVuY3Rpb24gKHZhbHVlLCBwYXR0ZXJuKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjaGVja1N1YnRyZWUodmFsdWUsIHBhdHRlcm4pO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGlmIChlIGluc3RhbmNlb2YgTWF0Y2guRXJyb3IpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgLy8gUmV0aHJvdyBvdGhlciBlcnJvcnMuXG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuZnVuY3Rpb24gT3B0aW9uYWwocGF0dGVybikge1xuICAgIHRoaXMucGF0dGVybiA9IHBhdHRlcm47XG59O1xuXG5mdW5jdGlvbiBPbmVPZihjaG9pY2VzKSB7XG4gICAgaWYgKGNob2ljZXMubGVuZ3RoID09IDApXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIk11c3QgcHJvdmlkZSBhdCBsZWFzdCBvbmUgY2hvaWNlIHRvIE1hdGNoLk9uZU9mXCIpO1xuICAgIHRoaXMuY2hvaWNlcyA9IGNob2ljZXM7XG59O1xuXG5mdW5jdGlvbiBXaGVyZShjb25kaXRpb24pIHtcbiAgICB0aGlzLmNvbmRpdGlvbiA9IGNvbmRpdGlvbjtcbn07XG5cbmZ1bmN0aW9uIE9iamVjdEluY2x1ZGluZyhwYXR0ZXJuKSB7XG4gICAgdGhpcy5wYXR0ZXJuID0gcGF0dGVybjtcbn07XG5cbmZ1bmN0aW9uIE9iamVjdEhhc2gocGF0dGVybikge1xuICAgIHRoaXMucGF0dGVybiA9IHBhdHRlcm47XG59O1xuXG5mdW5jdGlvbiBTdWJjbGFzcyhTdXBlcmNsYXNzLCBtYXRjaFN1cGVyY2xhc3NUb28pIHtcbiAgICB0aGlzLlN1cGVyY2xhc3MgPSBTdXBlcmNsYXNzO1xuICAgIHRoaXMubWF0Y2hTdXBlcmNsYXNzID0gbWF0Y2hTdXBlcmNsYXNzVG9vO1xufTtcblxudmFyIHR5cGVvZkNoZWNrcyA9IFtcbiAgICBbU3RyaW5nLCBcInN0cmluZ1wiXSxcbiAgICBbTnVtYmVyLCBcIm51bWJlclwiXSxcbiAgICBbQm9vbGVhbiwgXCJib29sZWFuXCJdLFxuICAgIFtGdW5jdGlvbiwgXCJmdW5jdGlvblwiXSxcbiAgICAvLyBXaGlsZSB3ZSBkb24ndCBhbGxvdyB1bmRlZmluZWQgaW4gSlNPTiwgdGhpcyBpcyBnb29kIGZvciBvcHRpb25hbFxuICAgIC8vIGFyZ3VtZW50cyB3aXRoIE9uZU9mLlxuICAgIFt1bmRlZmluZWQsIFwidW5kZWZpbmVkXCJdXG5dO1xuXG5mdW5jdGlvbiBjaGVja1N1YnRyZWUodmFsdWUsIHBhdHRlcm4pIHtcbiAgICAvLyBNYXRjaCBhbnl0aGluZyFcbiAgICBpZiAocGF0dGVybiA9PT0gTWF0Y2guQW55KVxuICAgICAgICByZXR1cm47XG5cbiAgICAvLyBCYXNpYyBhdG9taWMgdHlwZXMuXG4gICAgLy8gRG8gbm90IG1hdGNoIGJveGVkIG9iamVjdHMgKGUuZy4gU3RyaW5nLCBCb29sZWFuKVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdHlwZW9mQ2hlY2tzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIGlmIChwYXR0ZXJuID09PSB0eXBlb2ZDaGVja3NbaV1bMF0pIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IHR5cGVvZkNoZWNrc1tpXVsxXSlcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB0aHJvdyBuZXcgTWF0Y2guRXJyb3IoXCJFeHBlY3RlZCBcIiArIHR5cGVvZkNoZWNrc1tpXVsxXSArIFwiLCBnb3QgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlb2YgdmFsdWUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChwYXR0ZXJuID09PSBudWxsKSB7XG4gICAgICAgIGlmICh2YWx1ZSA9PT0gbnVsbClcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgdGhyb3cgbmV3IE1hdGNoLkVycm9yKFwiRXhwZWN0ZWQgbnVsbCwgZ290IFwiICsgSlNPTi5zdHJpbmdpZnkodmFsdWUpKTtcbiAgICB9XG5cbiAgICAvLyBNYXRjaC5JbnRlZ2VyIGlzIHNwZWNpYWwgdHlwZSBlbmNvZGVkIHdpdGggYXJyYXlcbiAgICBpZiAocGF0dGVybiA9PT0gTWF0Y2guSW50ZWdlcikge1xuICAgICAgICAvLyBUaGVyZSBpcyBubyBjb25zaXN0ZW50IGFuZCByZWxpYWJsZSB3YXkgdG8gY2hlY2sgaWYgdmFyaWFibGUgaXMgYSA2NC1iaXRcbiAgICAgICAgLy8gaW50ZWdlci4gT25lIG9mIHRoZSBwb3B1bGFyIHNvbHV0aW9ucyBpcyB0byBnZXQgcmVtaW5kZXIgb2YgZGl2aXNpb24gYnkgMVxuICAgICAgICAvLyBidXQgdGhpcyBtZXRob2QgZmFpbHMgb24gcmVhbGx5IGxhcmdlIGZsb2F0cyB3aXRoIGJpZyBwcmVjaXNpb24uXG4gICAgICAgIC8vIEUuZy46IDEuMzQ4MTkyMzA4NDkxODI0ZSsyMyAlIDEgPT09IDAgaW4gVjhcbiAgICAgICAgLy8gQml0d2lzZSBvcGVyYXRvcnMgd29yayBjb25zaXN0YW50bHkgYnV0IGFsd2F5cyBjYXN0IHZhcmlhYmxlIHRvIDMyLWJpdFxuICAgICAgICAvLyBzaWduZWQgaW50ZWdlciBhY2NvcmRpbmcgdG8gSmF2YVNjcmlwdCBzcGVjcy5cbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgJiYgKHZhbHVlIHwgMCkgPT09IHZhbHVlKVxuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIHRocm93IG5ldyBNYXRjaC5FcnJvcignRXhwZWN0ZWQgSW50ZWdlciwgZ290ICdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKyAodmFsdWUgaW5zdGFuY2VvZiBPYmplY3QgPyBKU09OLnN0cmluZ2lmeSh2YWx1ZSkgOiB2YWx1ZSkpO1xuICAgIH1cblxuICAgIGlmIChwYXR0ZXJuID09PSBNYXRjaC5JZGVudGlmaWVyU3RyaW5nKSB7XG4gICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIE1hdGNoLklkZW50aWZpZXJTdHJpbmcudGVzdCh2YWx1ZSlcbiAgICAgICAgICAgICAgICAmJiBfanNLZXl3b3Jkcy5pbmRleE9mKGtleSkgPT0gLTEpXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIHRocm93IG5ldyBNYXRjaC5FcnJvcignRXhwZWN0ZWQgaWRlbnRpZmllciBzdHJpbmcsIGdvdCAnXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICsgKHZhbHVlIGluc3RhbmNlb2YgT2JqZWN0ID8gSlNPTi5zdHJpbmdpZnkodmFsdWUpIDogdmFsdWUpKTtcbiAgICB9XG5cbiAgICAvLyBcIk9iamVjdFwiIGlzIHNob3J0aGFuZCBmb3IgTWF0Y2guT2JqZWN0SW5jbHVkaW5nKHt9KTtcbiAgICBpZiAocGF0dGVybiA9PT0gT2JqZWN0KVxuICAgICAgICBwYXR0ZXJuID0gTWF0Y2guT2JqZWN0SW5jbHVkaW5nKHt9KTtcblxuICAgIC8vIEFycmF5IChjaGVja2VkIEFGVEVSIEFueSwgd2hpY2ggaXMgaW1wbGVtZW50ZWQgYXMgYW4gQXJyYXkpLlxuICAgIGlmIChwYXR0ZXJuIGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICAgICAgaWYgKHBhdHRlcm4ubGVuZ3RoICE9PSAxKVxuICAgICAgICAgICAgdGhyb3cgRXJyb3IoXCJCYWQgcGF0dGVybjogYXJyYXlzIG11c3QgaGF2ZSBvbmUgdHlwZSBlbGVtZW50XCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkocGF0dGVybikpO1xuICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgTWF0Y2guRXJyb3IoXCJFeHBlY3RlZCBhcnJheSwgZ290IFwiICsgSlNPTi5zdHJpbmdpZnkodmFsdWUpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhbHVlLmZvckVhY2goZnVuY3Rpb24gKHZhbHVlRWxlbWVudCwgaW5kZXgpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgY2hlY2tTdWJ0cmVlKHZhbHVlRWxlbWVudCwgcGF0dGVyblswXSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyIGluc3RhbmNlb2YgTWF0Y2guRXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgZXJyLnBhdGggPSBfcHJlcGVuZFBhdGgoaW5kZXgsIGVyci5wYXRoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEFyYml0cmFyeSB2YWxpZGF0aW9uIGNoZWNrcy4gVGhlIGNvbmRpdGlvbiBjYW4gcmV0dXJuIGZhbHNlIG9yIHRocm93IGFcbiAgICAvLyBNYXRjaC5FcnJvciAoaWUsIGl0IGNhbiBpbnRlcm5hbGx5IHVzZSBjaGVjaygpKSB0byBmYWlsLlxuICAgIGlmIChwYXR0ZXJuIGluc3RhbmNlb2YgV2hlcmUpIHtcbiAgICAgICAgaWYgKHBhdHRlcm4uY29uZGl0aW9uKHZhbHVlKSlcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgLy8gWFhYIHRoaXMgZXJyb3IgaXMgdGVycmlibGVcbiAgICAgICAgdGhyb3cgbmV3IE1hdGNoLkVycm9yKFwiRmFpbGVkIE1hdGNoLldoZXJlIHZhbGlkYXRpb25cIik7XG4gICAgfVxuXG5cbiAgICBpZiAocGF0dGVybiBpbnN0YW5jZW9mIE9wdGlvbmFsKVxuICAgICAgICBwYXR0ZXJuID0gTWF0Y2guT25lT2YodW5kZWZpbmVkLCBwYXR0ZXJuLnBhdHRlcm4pO1xuXG4gICAgaWYgKHBhdHRlcm4gaW5zdGFuY2VvZiBPbmVPZikge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBhdHRlcm4uY2hvaWNlcy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjaGVja1N1YnRyZWUodmFsdWUsIHBhdHRlcm4uY2hvaWNlc1tpXSk7XG4gICAgICAgICAgICAgICAgLy8gTm8gZXJyb3I/IFlheSwgcmV0dXJuLlxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIC8vIE90aGVyIGVycm9ycyBzaG91bGQgYmUgdGhyb3duLiBNYXRjaCBlcnJvcnMganVzdCBtZWFuIHRyeSBhbm90aGVyXG4gICAgICAgICAgICAgICAgLy8gY2hvaWNlLlxuICAgICAgICAgICAgICAgIGlmICghKGVyciBpbnN0YW5jZW9mIE1hdGNoLkVycm9yKSlcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIFhYWCB0aGlzIGVycm9yIGlzIHRlcnJpYmxlXG4gICAgICAgIHRocm93IG5ldyBNYXRjaC5FcnJvcihcIkZhaWxlZCBNYXRjaC5PbmVPZiBvciBNYXRjaC5PcHRpb25hbCB2YWxpZGF0aW9uXCIpO1xuICAgIH1cblxuICAgIC8vIEEgZnVuY3Rpb24gdGhhdCBpc24ndCBzb21ldGhpbmcgd2Ugc3BlY2lhbC1jYXNlIGlzIGFzc3VtZWQgdG8gYmUgYVxuICAgIC8vIGNvbnN0cnVjdG9yLlxuICAgIGlmIChwYXR0ZXJuIGluc3RhbmNlb2YgRnVuY3Rpb24pIHtcbiAgICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgcGF0dGVybilcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgLy8gWFhYIHdoYXQgaWYgLm5hbWUgaXNuJ3QgZGVmaW5lZFxuICAgICAgICB0aHJvdyBuZXcgTWF0Y2guRXJyb3IoXCJFeHBlY3RlZCBcIiArIHBhdHRlcm4uY29uc3RydWN0b3IubmFtZSk7XG4gICAgfVxuXG4gICAgdmFyIHVua25vd25LZXlzQWxsb3dlZCA9IGZhbHNlO1xuICAgIGlmIChwYXR0ZXJuIGluc3RhbmNlb2YgT2JqZWN0SW5jbHVkaW5nKSB7XG4gICAgICAgIHVua25vd25LZXlzQWxsb3dlZCA9IHRydWU7XG4gICAgICAgIHBhdHRlcm4gPSBwYXR0ZXJuLnBhdHRlcm47XG4gICAgfVxuXG4gICAgaWYgKHBhdHRlcm4gaW5zdGFuY2VvZiBPYmplY3RIYXNoKSB7XG4gICAgICAgIHZhciBrZXlQYXR0ZXJuID0gcGF0dGVybi5wYXR0ZXJuO1xuICAgICAgICB2YXIgZW1wdHlIYXNoID0gdHJ1ZTtcbiAgICAgICAgZm9yICh2YXIga2V5IGluIHZhbHVlKSB7XG4gICAgICAgICAgICBlbXB0eUhhc2ggPSBmYWxzZTtcbiAgICAgICAgICAgIGNoZWNrKHZhbHVlW2tleV0sIGtleVBhdHRlcm4pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChlbXB0eUhhc2gpXG4gICAgICAgICAgICB0aHJvdyBuZXcgTWF0Y2guRXJyb3IoXCJFeHBlY3RlZCBcIiArIHBhdHRlcm4uY29uc3RydWN0b3IubmFtZSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAocGF0dGVybiBpbnN0YW5jZW9mIFN1YmNsYXNzKSB7XG4gICAgICAgIHZhciBTdXBlcmNsYXNzID0gcGF0dGVybi5TdXBlcmNsYXNzO1xuICAgICAgICBpZiAocGF0dGVybi5tYXRjaFN1cGVyY2xhc3MgJiYgdmFsdWUgPT0gU3VwZXJjbGFzcylcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgaWYgKCEgKHZhbHVlLnByb3RvdHlwZSBpbnN0YW5jZW9mIFN1cGVyY2xhc3MpKVxuICAgICAgICAgICAgdGhyb3cgbmV3IE1hdGNoLkVycm9yKFwiRXhwZWN0ZWQgXCIgKyBwYXR0ZXJuLmNvbnN0cnVjdG9yLm5hbWUgKyBcIiBvZiBcIiArIFN1cGVyY2xhc3MubmFtZSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHBhdHRlcm4gIT09IFwib2JqZWN0XCIpXG4gICAgICAgIHRocm93IEVycm9yKFwiQmFkIHBhdHRlcm46IHVua25vd24gcGF0dGVybiB0eXBlXCIpO1xuXG4gICAgLy8gQW4gb2JqZWN0LCB3aXRoIHJlcXVpcmVkIGFuZCBvcHRpb25hbCBrZXlzLiBOb3RlIHRoYXQgdGhpcyBkb2VzIE5PVCBkb1xuICAgIC8vIHN0cnVjdHVyYWwgbWF0Y2hlcyBhZ2FpbnN0IG9iamVjdHMgb2Ygc3BlY2lhbCB0eXBlcyB0aGF0IGhhcHBlbiB0byBtYXRjaFxuICAgIC8vIHRoZSBwYXR0ZXJuOiB0aGlzIHJlYWxseSBuZWVkcyB0byBiZSBhIHBsYWluIG9sZCB7T2JqZWN0fSFcbiAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnb2JqZWN0JylcbiAgICAgICAgdGhyb3cgbmV3IE1hdGNoLkVycm9yKFwiRXhwZWN0ZWQgb2JqZWN0LCBnb3QgXCIgKyB0eXBlb2YgdmFsdWUpO1xuICAgIGlmICh2YWx1ZSA9PT0gbnVsbClcbiAgICAgICAgdGhyb3cgbmV3IE1hdGNoLkVycm9yKFwiRXhwZWN0ZWQgb2JqZWN0LCBnb3QgbnVsbFwiKTtcblxuICAgIHZhciByZXF1aXJlZFBhdHRlcm5zID0ge307XG4gICAgdmFyIG9wdGlvbmFsUGF0dGVybnMgPSB7fTtcblxuICAgIF8uZWFjaEtleShwYXR0ZXJuLCBmdW5jdGlvbihzdWJQYXR0ZXJuLCBrZXkpIHtcbiAgICAgICAgaWYgKHBhdHRlcm5ba2V5XSBpbnN0YW5jZW9mIE9wdGlvbmFsKVxuICAgICAgICAgICAgb3B0aW9uYWxQYXR0ZXJuc1trZXldID0gcGF0dGVybltrZXldLnBhdHRlcm47XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHJlcXVpcmVkUGF0dGVybnNba2V5XSA9IHBhdHRlcm5ba2V5XTtcbiAgICB9LCB0aGlzLCB0cnVlKTtcblxuICAgIF8uZWFjaEtleSh2YWx1ZSwgZnVuY3Rpb24oc3ViVmFsdWUsIGtleSkge1xuICAgICAgICB2YXIgc3ViVmFsdWUgPSB2YWx1ZVtrZXldO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKHJlcXVpcmVkUGF0dGVybnMuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICAgICAgICAgIGNoZWNrU3VidHJlZShzdWJWYWx1ZSwgcmVxdWlyZWRQYXR0ZXJuc1trZXldKTtcbiAgICAgICAgICAgICAgICBkZWxldGUgcmVxdWlyZWRQYXR0ZXJuc1trZXldO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25hbFBhdHRlcm5zLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICBjaGVja1N1YnRyZWUoc3ViVmFsdWUsIG9wdGlvbmFsUGF0dGVybnNba2V5XSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmICghdW5rbm93bktleXNBbGxvd2VkKVxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgTWF0Y2guRXJyb3IoXCJVbmtub3duIGtleVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBpZiAoZXJyIGluc3RhbmNlb2YgTWF0Y2guRXJyb3IpXG4gICAgICAgICAgICAgICAgZXJyLnBhdGggPSBfcHJlcGVuZFBhdGgoa2V5LCBlcnIucGF0aCk7XG4gICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH1cbiAgICB9LCB0aGlzLCB0cnVlKTtcblxuICAgIF8uZWFjaEtleShyZXF1aXJlZFBhdHRlcm5zLCBmdW5jdGlvbih2YWx1ZSwga2V5KSB7XG4gICAgICAgIHRocm93IG5ldyBNYXRjaC5FcnJvcihcIk1pc3Npbmcga2V5ICdcIiArIGtleSArIFwiJ1wiKTtcbiAgICB9LCB0aGlzLCB0cnVlKTtcbn07XG5cblxudmFyIF9qc0tleXdvcmRzID0gW1wiZG9cIiwgXCJpZlwiLCBcImluXCIsIFwiZm9yXCIsIFwibGV0XCIsIFwibmV3XCIsIFwidHJ5XCIsIFwidmFyXCIsIFwiY2FzZVwiLFxuICAgIFwiZWxzZVwiLCBcImVudW1cIiwgXCJldmFsXCIsIFwiZmFsc2VcIiwgXCJudWxsXCIsIFwidGhpc1wiLCBcInRydWVcIiwgXCJ2b2lkXCIsIFwid2l0aFwiLFxuICAgIFwiYnJlYWtcIiwgXCJjYXRjaFwiLCBcImNsYXNzXCIsIFwiY29uc3RcIiwgXCJzdXBlclwiLCBcInRocm93XCIsIFwid2hpbGVcIiwgXCJ5aWVsZFwiLFxuICAgIFwiZGVsZXRlXCIsIFwiZXhwb3J0XCIsIFwiaW1wb3J0XCIsIFwicHVibGljXCIsIFwicmV0dXJuXCIsIFwic3RhdGljXCIsIFwic3dpdGNoXCIsXG4gICAgXCJ0eXBlb2ZcIiwgXCJkZWZhdWx0XCIsIFwiZXh0ZW5kc1wiLCBcImZpbmFsbHlcIiwgXCJwYWNrYWdlXCIsIFwicHJpdmF0ZVwiLCBcImNvbnRpbnVlXCIsXG4gICAgXCJkZWJ1Z2dlclwiLCBcImZ1bmN0aW9uXCIsIFwiYXJndW1lbnRzXCIsIFwiaW50ZXJmYWNlXCIsIFwicHJvdGVjdGVkXCIsIFwiaW1wbGVtZW50c1wiLFxuICAgIFwiaW5zdGFuY2VvZlwiXTtcblxuLy8gQXNzdW1lcyB0aGUgYmFzZSBvZiBwYXRoIGlzIGFscmVhZHkgZXNjYXBlZCBwcm9wZXJseVxuLy8gcmV0dXJucyBrZXkgKyBiYXNlXG5mdW5jdGlvbiBfcHJlcGVuZFBhdGgoa2V5LCBiYXNlKSB7XG4gICAgaWYgKCh0eXBlb2Yga2V5KSA9PT0gXCJudW1iZXJcIiB8fCBrZXkubWF0Y2goL15bMC05XSskLykpXG4gICAgICAgIGtleSA9IFwiW1wiICsga2V5ICsgXCJdXCI7XG4gICAgZWxzZSBpZiAoIWtleS5tYXRjaChNYXRjaC5JZGVudGlmaWVyU3RyaW5nKSB8fCBfanNLZXl3b3Jkcy5pbmRleE9mKGtleSkgIT0gLTEpXG4gICAgICAgIGtleSA9IEpTT04uc3RyaW5naWZ5KFtrZXldKTtcblxuICAgIGlmIChiYXNlICYmIGJhc2VbMF0gIT09IFwiW1wiKVxuICAgICAgICByZXR1cm4ga2V5ICsgJy4nICsgYmFzZTtcbiAgICByZXR1cm4ga2V5ICsgYmFzZTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogYG1pbG8udXRpbGBcbiAqL1xudmFyIHV0aWwgPSB7XG4gICAgbG9nZ2VyOiByZXF1aXJlKCcuL2xvZ2dlcicpLFxuICAgIGNoZWNrOiByZXF1aXJlKCcuL2NoZWNrJyksXG4gICAgZG9UOiByZXF1aXJlKCdkb3QnKVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSB1dGlsO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyA8YSBuYW1lPVwidXRpbHMtbG9nZ2VyXCI+PC9hPlxuLy8gbWlsby51dGlscy5sb2dnZXJcbi8vIC0tLS0tLS0tLS0tXG5cbi8vIEFwcGxpY2F0aW9uIGxvZ2dlciB0aGF0IGhhcyBlcnJvciwgd2FybiwgaW5mbyBhbmQgZGVidWdcbi8vIG1ldGhvZHMsIHRoYXQgY2FuIGJlIHN1cHByZXNzZWQgYnkgc2V0dGluZyBsb2cgbGV2ZWwuXG5cbi8vIFByb3BlcnRpZXM6XG5cbi8vIC0gbGV2ZWxcblxuLy8gICAtIDAgLSBlcnJvclxuLy8gICAtIDEgLSB3YXJuXG4vLyAgIC0gMiAtIGluZm9cbi8vICAgLSAzIC0gZGVidWcgKGRlZmF1bHQpXG5cbi8vIC0gZW5hYmxlZFxuXG4vLyAgIHRydWUgYnkgZGVmYXVsdC4gU2V0IHRvIGZhbHNlIHRvIGRpc2FibGUgYWxsIGxvZ2dpbmcgaW4gYnJvd3NlciBjb25zb2xlLlxuXG5cbnZhciBMb2dnZXIgPSByZXF1aXJlKCcuL2xvZ2dlcl9jbGFzcycpO1xuXG52YXIgbG9nZ2VyID0gbmV3IExvZ2dlcih7IGxldmVsOiAzIH0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGxvZ2dlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gIyMjIExvZ2dlciBDbGFzc1xuXG4vLyBQcm9wZXJ0aWVzOlxuXG4vLyAtIGxldmVsXG5cbi8vICAgLSAwIC0gZXJyb3Jcbi8vICAgLSAxIC0gd2FyblxuLy8gICAtIDIgLSBpbmZvXG4vLyAgIC0gMyAtIGRlYnVnIChkZWZhdWx0KVxuXG4vLyAtIGVuYWJsZWRcblxuLy8gICB0cnVlIGJ5IGRlZmF1bHQuIFNldCB0byBmYWxzZSB0byBkaXNhYmxlIGFsbCBsb2dnaW5nIGluIGJyb3dzZXIgY29uc29sZS5cblxuXG52YXIgXyA9IHJlcXVpcmUoJ21vbC1wcm90bycpO1xuXG5cbi8qKlxuICogTG9nIGxldmVscy5cbiAqL1xuXG52YXIgbGV2ZWxzID0gW1xuICAgICdlcnJvcicsXG4gICAgJ3dhcm4nLFxuICAgICdpbmZvJyxcbiAgICAnZGVidWcnXG5dO1xuXG52YXIgbWF4TGV2ZWxMZW5ndGggPSBNYXRoLm1heC5hcHBseShNYXRoLCBsZXZlbHMubWFwKGZ1bmN0aW9uKGxldmVsKSB7IHJldHVybiBsZXZlbC5sZW5ndGg7IH0pKTtcblxuLyoqXG4gKiBDb2xvcnMgZm9yIGxvZyBsZXZlbHMuXG4gKi9cblxudmFyIGNvbG9ycyA9IFtcbiAgICAzMSxcbiAgICAzMyxcbiAgICAzNixcbiAgICA5MFxuXTtcblxuLyoqXG4gKiBQYWRzIHRoZSBuaWNlIG91dHB1dCB0byB0aGUgbG9uZ2VzdCBsb2cgbGV2ZWwuXG4gKi9cbmZ1bmN0aW9uIHBhZChzdHIpIHtcbiAgICBpZiAoc3RyLmxlbmd0aCA8IG1heExldmVsTGVuZ3RoKVxuICAgICAgICByZXR1cm4gc3RyICsgbmV3IEFycmF5KG1heExldmVsTGVuZ3RoIC0gc3RyLmxlbmd0aCArIDEpLmpvaW4oJyAnKTtcblxuICAgIHJldHVybiBzdHI7XG59O1xuXG5cbmZ1bmN0aW9uIGNvbG9yZWQoc3RyLCBjb2xvcikge1xuICAgIHJldHVybiAnXFx4MUJbJyArIGNvbG9yICsgJ20nICsgc3RyICsgJyAtXFx4MUJbMzltJztcbn1cblxuXG52YXIgREVGQVVMVF9PUFRJT05TID0ge1xuICAgIGxldmVsOiAzLFxuICAgIHRocm93TGV2ZWw6IC0xLCAvLyBuZXZlciB0aHJvd1xuICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgbG9nUHJlZml4OiAnJ1xufVxuXG5cbi8qKlxuICogTG9nZ2VyIChjb25zb2xlKS5cbiAqXG4gKiBAYXBpIHB1YmxpY1xuICovXG52YXIgTG9nZ2VyID0gZnVuY3Rpb24gKG9wdHMpIHtcbiAgICBfLmV4dGVuZCh0aGlzLCBERUZBVUxUX09QVElPTlMpO1xuICAgIF8uZXh0ZW5kKHRoaXMsIG9wdHMgfHwge30pO1xufTtcblxuXG4vKipcbiAqIExvZyBtZXRob2QuXG4gKlxuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5Mb2dnZXIucHJvdG90eXBlLmxvZyA9IGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgdmFyIGluZGV4ID0gbGV2ZWxzLmluZGV4T2YodHlwZSk7XG5cbiAgICBpZiAoISB0aGlzLmVuYWJsZWQgfHwgaW5kZXggPiB0aGlzLmxldmVsKVxuICAgICAgICByZXR1cm4gdGhpcztcblxuICAgIHZhciBhcmdzID0gXy5zbGljZShhcmd1bWVudHMsIDEpO1xuXG4gICAgaWYgKGluZGV4IDw9IHRoaXMudGhyb3dMZXZlbClcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFt0aGlzLmxvZ1ByZWZpeCwgdHlwZSArICc6J10uY29uY2F0KGFyZ3MpLmpvaW4oJyAnKSk7XG5cbiAgICBjb25zb2xlLmxvZy5hcHBseShcbiAgICAgICAgICBjb25zb2xlXG4gICAgICAgICwgWyB0aGlzLmxvZ1ByZWZpeENvbG9yXG4gICAgICAgICAgICAgID8gJyAgICcgKyBjb2xvcmVkKHRoaXMubG9nUHJlZml4LCB0aGlzLmxvZ1ByZWZpeENvbG9yKVxuICAgICAgICAgICAgICA6IHRoaXMubG9nUHJlZml4LFxuICAgICAgICAgICAgKHRoaXMuY29sb3JzXG4gICAgICAgICAgICAgID8gJyAnICsgY29sb3JlZChwYWQodHlwZSksIGNvbG9yc1tpbmRleF0pXG4gICAgICAgICAgICAgIDogdHlwZSkgKyAnOidcbiAgICAgICAgICBdLmNvbmNhdChhcmdzKVxuICAgICk7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogR2VuZXJhdGUgbWV0aG9kcy5cbiAqL1xuXG5sZXZlbHMuZm9yRWFjaChmdW5jdGlvbiAobmFtZSkge1xuICAgIExvZ2dlci5wcm90b3R5cGVbbmFtZV0gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMubG9nLmFwcGx5KHRoaXMsIFtuYW1lXS5jb25jYXQoXy50b0FycmF5KGFyZ3VtZW50cykpKTtcbiAgICB9O1xufSk7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBMb2dnZXI7XG4iLCIvLyBkb1QuanNcbi8vIDIwMTEtMjAxNCwgTGF1cmEgRG9rdG9yb3ZhLCBodHRwczovL2dpdGh1Yi5jb20vb2xhZG8vZG9UXG4vLyBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG5cbihmdW5jdGlvbigpIHtcblx0XCJ1c2Ugc3RyaWN0XCI7XG5cblx0dmFyIGRvVCA9IHtcblx0XHR2ZXJzaW9uOiBcIjEuMC4zXCIsXG5cdFx0dGVtcGxhdGVTZXR0aW5nczoge1xuXHRcdFx0ZXZhbHVhdGU6ICAgIC9cXHtcXHsoW1xcc1xcU10rPyhcXH0/KSspXFx9XFx9L2csXG5cdFx0XHRpbnRlcnBvbGF0ZTogL1xce1xcez0oW1xcc1xcU10rPylcXH1cXH0vZyxcblx0XHRcdGVuY29kZTogICAgICAvXFx7XFx7IShbXFxzXFxTXSs/KVxcfVxcfS9nLFxuXHRcdFx0dXNlOiAgICAgICAgIC9cXHtcXHsjKFtcXHNcXFNdKz8pXFx9XFx9L2csXG5cdFx0XHR1c2VQYXJhbXM6ICAgLyhefFteXFx3JF0pZGVmKD86XFwufFxcW1tcXCdcXFwiXSkoW1xcdyRcXC5dKykoPzpbXFwnXFxcIl1cXF0pP1xccypcXDpcXHMqKFtcXHckXFwuXSt8XFxcIlteXFxcIl0rXFxcInxcXCdbXlxcJ10rXFwnfFxce1teXFx9XStcXH0pL2csXG5cdFx0XHRkZWZpbmU6ICAgICAgL1xce1xceyMjXFxzKihbXFx3XFwuJF0rKVxccyooXFw6fD0pKFtcXHNcXFNdKz8pI1xcfVxcfS9nLFxuXHRcdFx0ZGVmaW5lUGFyYW1zOi9eXFxzKihbXFx3JF0rKTooW1xcc1xcU10rKS8sXG5cdFx0XHRjb25kaXRpb25hbDogL1xce1xce1xcPyhcXD8pP1xccyooW1xcc1xcU10qPylcXHMqXFx9XFx9L2csXG5cdFx0XHRpdGVyYXRlOiAgICAgL1xce1xce35cXHMqKD86XFx9XFx9fChbXFxzXFxTXSs/KVxccypcXDpcXHMqKFtcXHckXSspXFxzKig/OlxcOlxccyooW1xcdyRdKykpP1xccypcXH1cXH0pL2csXG5cdFx0XHR2YXJuYW1lOlx0XCJpdFwiLFxuXHRcdFx0c3RyaXA6XHRcdHRydWUsXG5cdFx0XHRhcHBlbmQ6XHRcdHRydWUsXG5cdFx0XHRzZWxmY29udGFpbmVkOiBmYWxzZSxcblx0XHRcdGRvTm90U2tpcEVuY29kZWQ6IGZhbHNlXG5cdFx0fSxcblx0XHR0ZW1wbGF0ZTogdW5kZWZpbmVkLCAvL2ZuLCBjb21waWxlIHRlbXBsYXRlXG5cdFx0Y29tcGlsZTogIHVuZGVmaW5lZCAgLy9mbiwgZm9yIGV4cHJlc3Ncblx0fSwgX2dsb2JhbHM7XG5cblx0ZG9ULmVuY29kZUhUTUxTb3VyY2UgPSBmdW5jdGlvbihkb05vdFNraXBFbmNvZGVkKSB7XG5cdFx0dmFyIGVuY29kZUhUTUxSdWxlcyA9IHsgXCImXCI6IFwiJiMzODtcIiwgXCI8XCI6IFwiJiM2MDtcIiwgXCI+XCI6IFwiJiM2MjtcIiwgJ1wiJzogXCImIzM0O1wiLCBcIidcIjogXCImIzM5O1wiLCBcIi9cIjogXCImIzQ3O1wiIH0sXG5cdFx0XHRtYXRjaEhUTUwgPSBkb05vdFNraXBFbmNvZGVkID8gL1smPD5cIidcXC9dL2cgOiAvJig/ISM/XFx3KzspfDx8PnxcInwnfFxcLy9nO1xuXHRcdHJldHVybiBmdW5jdGlvbihjb2RlKSB7XG5cdFx0XHRyZXR1cm4gY29kZSA/IGNvZGUudG9TdHJpbmcoKS5yZXBsYWNlKG1hdGNoSFRNTCwgZnVuY3Rpb24obSkge3JldHVybiBlbmNvZGVIVE1MUnVsZXNbbV0gfHwgbTt9KSA6IFwiXCI7XG5cdFx0fTtcblx0fTtcblxuXHRfZ2xvYmFscyA9IChmdW5jdGlvbigpeyByZXR1cm4gdGhpcyB8fCAoMCxldmFsKShcInRoaXNcIik7IH0oKSk7XG5cblx0aWYgKHR5cGVvZiBtb2R1bGUgIT09IFwidW5kZWZpbmVkXCIgJiYgbW9kdWxlLmV4cG9ydHMpIHtcblx0XHRtb2R1bGUuZXhwb3J0cyA9IGRvVDtcblx0fSBlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgZGVmaW5lLmFtZCkge1xuXHRcdGRlZmluZShmdW5jdGlvbigpe3JldHVybiBkb1Q7fSk7XG5cdH0gZWxzZSB7XG5cdFx0X2dsb2JhbHMuZG9UID0gZG9UO1xuXHR9XG5cblx0dmFyIHN0YXJ0ZW5kID0ge1xuXHRcdGFwcGVuZDogeyBzdGFydDogXCInKyhcIiwgICAgICBlbmQ6IFwiKSsnXCIsICAgICAgc3RhcnRlbmNvZGU6IFwiJytlbmNvZGVIVE1MKFwiIH0sXG5cdFx0c3BsaXQ6ICB7IHN0YXJ0OiBcIic7b3V0Kz0oXCIsIGVuZDogXCIpO291dCs9J1wiLCBzdGFydGVuY29kZTogXCInO291dCs9ZW5jb2RlSFRNTChcIiB9XG5cdH0sIHNraXAgPSAvJF4vO1xuXG5cdGZ1bmN0aW9uIHJlc29sdmVEZWZzKGMsIGJsb2NrLCBkZWYpIHtcblx0XHRyZXR1cm4gKCh0eXBlb2YgYmxvY2sgPT09IFwic3RyaW5nXCIpID8gYmxvY2sgOiBibG9jay50b1N0cmluZygpKVxuXHRcdC5yZXBsYWNlKGMuZGVmaW5lIHx8IHNraXAsIGZ1bmN0aW9uKG0sIGNvZGUsIGFzc2lnbiwgdmFsdWUpIHtcblx0XHRcdGlmIChjb2RlLmluZGV4T2YoXCJkZWYuXCIpID09PSAwKSB7XG5cdFx0XHRcdGNvZGUgPSBjb2RlLnN1YnN0cmluZyg0KTtcblx0XHRcdH1cblx0XHRcdGlmICghKGNvZGUgaW4gZGVmKSkge1xuXHRcdFx0XHRpZiAoYXNzaWduID09PSBcIjpcIikge1xuXHRcdFx0XHRcdGlmIChjLmRlZmluZVBhcmFtcykgdmFsdWUucmVwbGFjZShjLmRlZmluZVBhcmFtcywgZnVuY3Rpb24obSwgcGFyYW0sIHYpIHtcblx0XHRcdFx0XHRcdGRlZltjb2RlXSA9IHthcmc6IHBhcmFtLCB0ZXh0OiB2fTtcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRpZiAoIShjb2RlIGluIGRlZikpIGRlZltjb2RlXT0gdmFsdWU7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0bmV3IEZ1bmN0aW9uKFwiZGVmXCIsIFwiZGVmWydcIitjb2RlK1wiJ109XCIgKyB2YWx1ZSkoZGVmKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIFwiXCI7XG5cdFx0fSlcblx0XHQucmVwbGFjZShjLnVzZSB8fCBza2lwLCBmdW5jdGlvbihtLCBjb2RlKSB7XG5cdFx0XHRpZiAoYy51c2VQYXJhbXMpIGNvZGUgPSBjb2RlLnJlcGxhY2UoYy51c2VQYXJhbXMsIGZ1bmN0aW9uKG0sIHMsIGQsIHBhcmFtKSB7XG5cdFx0XHRcdGlmIChkZWZbZF0gJiYgZGVmW2RdLmFyZyAmJiBwYXJhbSkge1xuXHRcdFx0XHRcdHZhciBydyA9IChkK1wiOlwiK3BhcmFtKS5yZXBsYWNlKC8nfFxcXFwvZywgXCJfXCIpO1xuXHRcdFx0XHRcdGRlZi5fX2V4cCA9IGRlZi5fX2V4cCB8fCB7fTtcblx0XHRcdFx0XHRkZWYuX19leHBbcnddID0gZGVmW2RdLnRleHQucmVwbGFjZShuZXcgUmVnRXhwKFwiKF58W15cXFxcdyRdKVwiICsgZGVmW2RdLmFyZyArIFwiKFteXFxcXHckXSlcIiwgXCJnXCIpLCBcIiQxXCIgKyBwYXJhbSArIFwiJDJcIik7XG5cdFx0XHRcdFx0cmV0dXJuIHMgKyBcImRlZi5fX2V4cFsnXCIrcncrXCInXVwiO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHRcdHZhciB2ID0gbmV3IEZ1bmN0aW9uKFwiZGVmXCIsIFwicmV0dXJuIFwiICsgY29kZSkoZGVmKTtcblx0XHRcdHJldHVybiB2ID8gcmVzb2x2ZURlZnMoYywgdiwgZGVmKSA6IHY7XG5cdFx0fSk7XG5cdH1cblxuXHRmdW5jdGlvbiB1bmVzY2FwZShjb2RlKSB7XG5cdFx0cmV0dXJuIGNvZGUucmVwbGFjZSgvXFxcXCgnfFxcXFwpL2csIFwiJDFcIikucmVwbGFjZSgvW1xcclxcdFxcbl0vZywgXCIgXCIpO1xuXHR9XG5cblx0ZG9ULnRlbXBsYXRlID0gZnVuY3Rpb24odG1wbCwgYywgZGVmKSB7XG5cdFx0YyA9IGMgfHwgZG9ULnRlbXBsYXRlU2V0dGluZ3M7XG5cdFx0dmFyIGNzZSA9IGMuYXBwZW5kID8gc3RhcnRlbmQuYXBwZW5kIDogc3RhcnRlbmQuc3BsaXQsIG5lZWRodG1sZW5jb2RlLCBzaWQgPSAwLCBpbmR2LFxuXHRcdFx0c3RyICA9IChjLnVzZSB8fCBjLmRlZmluZSkgPyByZXNvbHZlRGVmcyhjLCB0bXBsLCBkZWYgfHwge30pIDogdG1wbDtcblxuXHRcdHN0ciA9IChcInZhciBvdXQ9J1wiICsgKGMuc3RyaXAgPyBzdHIucmVwbGFjZSgvKF58XFxyfFxcbilcXHQqICt8ICtcXHQqKFxccnxcXG58JCkvZyxcIiBcIilcblx0XHRcdFx0XHQucmVwbGFjZSgvXFxyfFxcbnxcXHR8XFwvXFwqW1xcc1xcU10qP1xcKlxcLy9nLFwiXCIpOiBzdHIpXG5cdFx0XHQucmVwbGFjZSgvJ3xcXFxcL2csIFwiXFxcXCQmXCIpXG5cdFx0XHQucmVwbGFjZShjLmludGVycG9sYXRlIHx8IHNraXAsIGZ1bmN0aW9uKG0sIGNvZGUpIHtcblx0XHRcdFx0cmV0dXJuIGNzZS5zdGFydCArIHVuZXNjYXBlKGNvZGUpICsgY3NlLmVuZDtcblx0XHRcdH0pXG5cdFx0XHQucmVwbGFjZShjLmVuY29kZSB8fCBza2lwLCBmdW5jdGlvbihtLCBjb2RlKSB7XG5cdFx0XHRcdG5lZWRodG1sZW5jb2RlID0gdHJ1ZTtcblx0XHRcdFx0cmV0dXJuIGNzZS5zdGFydGVuY29kZSArIHVuZXNjYXBlKGNvZGUpICsgY3NlLmVuZDtcblx0XHRcdH0pXG5cdFx0XHQucmVwbGFjZShjLmNvbmRpdGlvbmFsIHx8IHNraXAsIGZ1bmN0aW9uKG0sIGVsc2VjYXNlLCBjb2RlKSB7XG5cdFx0XHRcdHJldHVybiBlbHNlY2FzZSA/XG5cdFx0XHRcdFx0KGNvZGUgPyBcIic7fWVsc2UgaWYoXCIgKyB1bmVzY2FwZShjb2RlKSArIFwiKXtvdXQrPSdcIiA6IFwiJzt9ZWxzZXtvdXQrPSdcIikgOlxuXHRcdFx0XHRcdChjb2RlID8gXCInO2lmKFwiICsgdW5lc2NhcGUoY29kZSkgKyBcIil7b3V0Kz0nXCIgOiBcIic7fW91dCs9J1wiKTtcblx0XHRcdH0pXG5cdFx0XHQucmVwbGFjZShjLml0ZXJhdGUgfHwgc2tpcCwgZnVuY3Rpb24obSwgaXRlcmF0ZSwgdm5hbWUsIGluYW1lKSB7XG5cdFx0XHRcdGlmICghaXRlcmF0ZSkgcmV0dXJuIFwiJzt9IH0gb3V0Kz0nXCI7XG5cdFx0XHRcdHNpZCs9MTsgaW5kdj1pbmFtZSB8fCBcImlcIitzaWQ7IGl0ZXJhdGU9dW5lc2NhcGUoaXRlcmF0ZSk7XG5cdFx0XHRcdHJldHVybiBcIic7dmFyIGFyclwiK3NpZCtcIj1cIitpdGVyYXRlK1wiO2lmKGFyclwiK3NpZCtcIil7dmFyIFwiK3ZuYW1lK1wiLFwiK2luZHYrXCI9LTEsbFwiK3NpZCtcIj1hcnJcIitzaWQrXCIubGVuZ3RoLTE7d2hpbGUoXCIraW5kditcIjxsXCIrc2lkK1wiKXtcIlxuXHRcdFx0XHRcdCt2bmFtZStcIj1hcnJcIitzaWQrXCJbXCIraW5kditcIis9MV07b3V0Kz0nXCI7XG5cdFx0XHR9KVxuXHRcdFx0LnJlcGxhY2UoYy5ldmFsdWF0ZSB8fCBza2lwLCBmdW5jdGlvbihtLCBjb2RlKSB7XG5cdFx0XHRcdHJldHVybiBcIic7XCIgKyB1bmVzY2FwZShjb2RlKSArIFwib3V0Kz0nXCI7XG5cdFx0XHR9KVxuXHRcdFx0KyBcIic7cmV0dXJuIG91dDtcIilcblx0XHRcdC5yZXBsYWNlKC9cXG4vZywgXCJcXFxcblwiKS5yZXBsYWNlKC9cXHQvZywgJ1xcXFx0JykucmVwbGFjZSgvXFxyL2csIFwiXFxcXHJcIilcblx0XHRcdC5yZXBsYWNlKC8oXFxzfDt8XFx9fF58XFx7KW91dFxcKz0nJzsvZywgJyQxJykucmVwbGFjZSgvXFwrJycvZywgXCJcIik7XG5cdFx0XHQvLy5yZXBsYWNlKC8oXFxzfDt8XFx9fF58XFx7KW91dFxcKz0nJ1xcKy9nLCckMW91dCs9Jyk7XG5cblx0XHRpZiAobmVlZGh0bWxlbmNvZGUpIHtcblx0XHRcdGlmICghYy5zZWxmY29udGFpbmVkICYmIF9nbG9iYWxzICYmICFfZ2xvYmFscy5fZW5jb2RlSFRNTCkgX2dsb2JhbHMuX2VuY29kZUhUTUwgPSBkb1QuZW5jb2RlSFRNTFNvdXJjZShjLmRvTm90U2tpcEVuY29kZWQpO1xuXHRcdFx0c3RyID0gXCJ2YXIgZW5jb2RlSFRNTCA9IHR5cGVvZiBfZW5jb2RlSFRNTCAhPT0gJ3VuZGVmaW5lZCcgPyBfZW5jb2RlSFRNTCA6IChcIlxuXHRcdFx0XHQrIGRvVC5lbmNvZGVIVE1MU291cmNlLnRvU3RyaW5nKCkgKyBcIihcIiArIChjLmRvTm90U2tpcEVuY29kZWQgfHwgJycpICsgXCIpKTtcIlxuXHRcdFx0XHQrIHN0cjtcblx0XHR9XG5cdFx0dHJ5IHtcblx0XHRcdHJldHVybiBuZXcgRnVuY3Rpb24oYy52YXJuYW1lLCBzdHIpO1xuXHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdGlmICh0eXBlb2YgY29uc29sZSAhPT0gXCJ1bmRlZmluZWRcIikgY29uc29sZS5sb2coXCJDb3VsZCBub3QgY3JlYXRlIGEgdGVtcGxhdGUgZnVuY3Rpb246IFwiICsgc3RyKTtcblx0XHRcdHRocm93IGU7XG5cdFx0fVxuXHR9O1xuXG5cdGRvVC5jb21waWxlID0gZnVuY3Rpb24odG1wbCwgZGVmKSB7XG5cdFx0cmV0dXJuIGRvVC50ZW1wbGF0ZSh0bXBsLCBudWxsLCBkZWYpO1xuXHR9O1xufSgpKTtcbiIsIi8qIGRvVCArIGF1dG8tY29tcGlsYXRpb24gb2YgZG9UIHRlbXBsYXRlc1xuICpcbiAqIDIwMTIsIExhdXJhIERva3Rvcm92YSwgaHR0cHM6Ly9naXRodWIuY29tL29sYWRvL2RvVFxuICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlXG4gKlxuICogQ29tcGlsZXMgLmRlZiwgLmRvdCwgLmpzdCBmaWxlcyBmb3VuZCB1bmRlciB0aGUgc3BlY2lmaWVkIHBhdGguXG4gKiBJdCBpZ25vcmVzIHN1Yi1kaXJlY3Rvcmllcy5cbiAqIFRlbXBsYXRlIGZpbGVzIGNhbiBoYXZlIG11bHRpcGxlIGV4dGVuc2lvbnMgYXQgdGhlIHNhbWUgdGltZS5cbiAqIEZpbGVzIHdpdGggLmRlZiBleHRlbnNpb24gY2FuIGJlIGluY2x1ZGVkIGluIG90aGVyIGZpbGVzIHZpYSB7eyNkZWYubmFtZX19XG4gKiBGaWxlcyB3aXRoIC5kb3QgZXh0ZW5zaW9uIGFyZSBjb21waWxlZCBpbnRvIGZ1bmN0aW9ucyB3aXRoIHRoZSBzYW1lIG5hbWUgYW5kXG4gKiBjYW4gYmUgYWNjZXNzZWQgYXMgcmVuZGVyZXIuZmlsZW5hbWVcbiAqIEZpbGVzIHdpdGggLmpzdCBleHRlbnNpb24gYXJlIGNvbXBpbGVkIGludG8gLmpzIGZpbGVzLiBQcm9kdWNlZCAuanMgZmlsZSBjYW4gYmVcbiAqIGxvYWRlZCBhcyBhIGNvbW1vbkpTLCBBTUQgbW9kdWxlLCBvciBqdXN0IGluc3RhbGxlZCBpbnRvIGEgZ2xvYmFsIHZhcmlhYmxlXG4gKiAoZGVmYXVsdCBpcyBzZXQgdG8gd2luZG93LnJlbmRlcikuXG4gKiBBbGwgaW5saW5lIGRlZmluZXMgZGVmaW5lZCBpbiB0aGUgLmpzdCBmaWxlIGFyZVxuICogY29tcGlsZWQgaW50byBzZXBhcmF0ZSBmdW5jdGlvbnMgYW5kIGFyZSBhdmFpbGFibGUgdmlhIF9yZW5kZXIuZmlsZW5hbWUuZGVmaW5lbmFtZVxuICpcbiAqIEJhc2ljIHVzYWdlOlxuICogdmFyIGRvdHMgPSByZXF1aXJlKFwiZG90XCIpLnByb2Nlc3Moe3BhdGg6IFwiLi92aWV3c1wifSk7XG4gKiBkb3RzLm15dGVtcGxhdGUoe2ZvbzpcImhlbGxvIHdvcmxkXCJ9KTtcbiAqXG4gKiBUaGUgYWJvdmUgc25pcHBldCB3aWxsOlxuICogMS4gQ29tcGlsZSBhbGwgdGVtcGxhdGVzIGluIHZpZXdzIGZvbGRlciAoLmRvdCwgLmRlZiwgLmpzdClcbiAqIDIuIFBsYWNlIC5qcyBmaWxlcyBjb21waWxlZCBmcm9tIC5qc3QgdGVtcGxhdGVzIGludG8gdGhlIHNhbWUgZm9sZGVyLlxuICogICAgVGhlc2UgZmlsZXMgY2FuIGJlIHVzZWQgd2l0aCByZXF1aXJlLCBpLmUuIHJlcXVpcmUoXCIuL3ZpZXdzL215dGVtcGxhdGVcIikuXG4gKiAzLiBSZXR1cm4gYW4gb2JqZWN0IHdpdGggZnVuY3Rpb25zIGNvbXBpbGVkIGZyb20gLmRvdCB0ZW1wbGF0ZXMgYXMgaXRzIHByb3BlcnRpZXMuXG4gKiA0LiBSZW5kZXIgbXl0ZW1wbGF0ZSB0ZW1wbGF0ZS5cbiAqL1xuXG52YXIgZnMgPSByZXF1aXJlKFwiZnNcIiksXG5cdGRvVCA9IG1vZHVsZS5leHBvcnRzID0gcmVxdWlyZShcIi4vZG9UXCIpO1xuXG5kb1QucHJvY2VzcyA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcblx0Ly9wYXRoLCBkZXN0aW5hdGlvbiwgZ2xvYmFsLCByZW5kZXJtb2R1bGUsIHRlbXBsYXRlU2V0dGluZ3Ncblx0cmV0dXJuIG5ldyBJbnN0YWxsRG90cyhvcHRpb25zKS5jb21waWxlQWxsKCk7XG59O1xuXG5mdW5jdGlvbiBJbnN0YWxsRG90cyhvKSB7XG5cdHRoaXMuX19wYXRoIFx0XHQ9IG8ucGF0aCB8fCBcIi4vXCI7XG5cdGlmICh0aGlzLl9fcGF0aFt0aGlzLl9fcGF0aC5sZW5ndGgtMV0gIT09ICcvJykgdGhpcy5fX3BhdGggKz0gJy8nO1xuXHR0aGlzLl9fZGVzdGluYXRpb25cdD0gby5kZXN0aW5hdGlvbiB8fCB0aGlzLl9fcGF0aDtcblx0aWYgKHRoaXMuX19kZXN0aW5hdGlvblt0aGlzLl9fZGVzdGluYXRpb24ubGVuZ3RoLTFdICE9PSAnLycpIHRoaXMuX19kZXN0aW5hdGlvbiArPSAnLyc7XG5cdHRoaXMuX19nbG9iYWxcdFx0PSBvLmdsb2JhbCB8fCBcIndpbmRvdy5yZW5kZXJcIjtcblx0dGhpcy5fX3JlbmRlcm1vZHVsZVx0PSBvLnJlbmRlcm1vZHVsZSB8fCB7fTtcblx0dGhpcy5fX3NldHRpbmdzIFx0PSBvLnRlbXBsYXRlU2V0dGluZ3MgPyBjb3B5KG8udGVtcGxhdGVTZXR0aW5ncywgY29weShkb1QudGVtcGxhdGVTZXR0aW5ncykpIDogdW5kZWZpbmVkO1xuXHR0aGlzLl9faW5jbHVkZXNcdFx0PSB7fTtcbn1cblxuSW5zdGFsbERvdHMucHJvdG90eXBlLmNvbXBpbGVUb0ZpbGUgPSBmdW5jdGlvbihwYXRoLCB0ZW1wbGF0ZSwgZGVmKSB7XG5cdGRlZiA9IGRlZiB8fCB7fTtcblx0dmFyIG1vZHVsZW5hbWUgPSBwYXRoLnN1YnN0cmluZyhwYXRoLmxhc3RJbmRleE9mKFwiL1wiKSsxLCBwYXRoLmxhc3RJbmRleE9mKFwiLlwiKSlcblx0XHQsIGRlZnMgPSBjb3B5KHRoaXMuX19pbmNsdWRlcywgY29weShkZWYpKVxuXHRcdCwgc2V0dGluZ3MgPSB0aGlzLl9fc2V0dGluZ3MgfHwgZG9ULnRlbXBsYXRlU2V0dGluZ3Ncblx0XHQsIGNvbXBpbGVvcHRpb25zID0gY29weShzZXR0aW5ncylcblx0XHQsIGRlZmF1bHRjb21waWxlZCA9IGRvVC50ZW1wbGF0ZSh0ZW1wbGF0ZSwgc2V0dGluZ3MsIGRlZnMpXG5cdFx0LCBleHBvcnRzID0gW11cblx0XHQsIGNvbXBpbGVkID0gXCJcIlxuXHRcdCwgZm47XG5cblx0Zm9yICh2YXIgcHJvcGVydHkgaW4gZGVmcykge1xuXHRcdGlmIChkZWZzW3Byb3BlcnR5XSAhPT0gZGVmW3Byb3BlcnR5XSAmJiBkZWZzW3Byb3BlcnR5XSAhPT0gdGhpcy5fX2luY2x1ZGVzW3Byb3BlcnR5XSkge1xuXHRcdFx0Zm4gPSB1bmRlZmluZWQ7XG5cdFx0XHRpZiAodHlwZW9mIGRlZnNbcHJvcGVydHldID09PSAnc3RyaW5nJykge1xuXHRcdFx0XHRmbiA9IGRvVC50ZW1wbGF0ZShkZWZzW3Byb3BlcnR5XSwgc2V0dGluZ3MsIGRlZnMpO1xuXHRcdFx0fSBlbHNlIGlmICh0eXBlb2YgZGVmc1twcm9wZXJ0eV0gPT09ICdmdW5jdGlvbicpIHtcblx0XHRcdFx0Zm4gPSBkZWZzW3Byb3BlcnR5XTtcblx0XHRcdH0gZWxzZSBpZiAoZGVmc1twcm9wZXJ0eV0uYXJnKSB7XG5cdFx0XHRcdGNvbXBpbGVvcHRpb25zLnZhcm5hbWUgPSBkZWZzW3Byb3BlcnR5XS5hcmc7XG5cdFx0XHRcdGZuID0gZG9ULnRlbXBsYXRlKGRlZnNbcHJvcGVydHldLnRleHQsIGNvbXBpbGVvcHRpb25zLCBkZWZzKTtcblx0XHRcdH1cblx0XHRcdGlmIChmbikge1xuXHRcdFx0XHRjb21waWxlZCArPSBmbi50b1N0cmluZygpLnJlcGxhY2UoJ2Fub255bW91cycsIHByb3BlcnR5KTtcblx0XHRcdFx0ZXhwb3J0cy5wdXNoKHByb3BlcnR5KTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblx0Y29tcGlsZWQgKz0gZGVmYXVsdGNvbXBpbGVkLnRvU3RyaW5nKCkucmVwbGFjZSgnYW5vbnltb3VzJywgbW9kdWxlbmFtZSk7XG5cdGZzLndyaXRlRmlsZVN5bmMocGF0aCwgXCIoZnVuY3Rpb24oKXtcIiArIGNvbXBpbGVkXG5cdFx0KyBcInZhciBpdHNlbGY9XCIgKyBtb2R1bGVuYW1lICsgXCIsIF9lbmNvZGVIVE1MPShcIiArIGRvVC5lbmNvZGVIVE1MU291cmNlLnRvU3RyaW5nKCkgKyBcIihcIiArIChzZXR0aW5ncy5kb05vdFNraXBFbmNvZGVkIHx8ICcnKSArIFwiKSk7XCJcblx0XHQrIGFkZGV4cG9ydHMoZXhwb3J0cylcblx0XHQrIFwiaWYodHlwZW9mIG1vZHVsZSE9PSd1bmRlZmluZWQnICYmIG1vZHVsZS5leHBvcnRzKSBtb2R1bGUuZXhwb3J0cz1pdHNlbGY7ZWxzZSBpZih0eXBlb2YgZGVmaW5lPT09J2Z1bmN0aW9uJylkZWZpbmUoZnVuY3Rpb24oKXtyZXR1cm4gaXRzZWxmO30pO2Vsc2Uge1wiXG5cdFx0KyB0aGlzLl9fZ2xvYmFsICsgXCI9XCIgKyB0aGlzLl9fZ2xvYmFsICsgXCJ8fHt9O1wiICsgdGhpcy5fX2dsb2JhbCArIFwiWydcIiArIG1vZHVsZW5hbWUgKyBcIiddPWl0c2VsZjt9fSgpKTtcIik7XG59O1xuXG5mdW5jdGlvbiBhZGRleHBvcnRzKGV4cG9ydHMpIHtcblx0Zm9yICh2YXIgcmV0ID0nJywgaT0wOyBpPCBleHBvcnRzLmxlbmd0aDsgaSsrKSB7XG5cdFx0cmV0ICs9IFwiaXRzZWxmLlwiICsgZXhwb3J0c1tpXSsgXCI9XCIgKyBleHBvcnRzW2ldK1wiO1wiO1xuXHR9XG5cdHJldHVybiByZXQ7XG59XG5cbmZ1bmN0aW9uIGNvcHkobywgdG8pIHtcblx0dG8gPSB0byB8fCB7fTtcblx0Zm9yICh2YXIgcHJvcGVydHkgaW4gbykge1xuXHRcdHRvW3Byb3BlcnR5XSA9IG9bcHJvcGVydHldO1xuXHR9XG5cdHJldHVybiB0bztcbn1cblxuZnVuY3Rpb24gcmVhZGRhdGEocGF0aCkge1xuXHR2YXIgZGF0YSA9IGZzLnJlYWRGaWxlU3luYyhwYXRoKTtcblx0aWYgKGRhdGEpIHJldHVybiBkYXRhLnRvU3RyaW5nKCk7XG5cdGNvbnNvbGUubG9nKFwicHJvYmxlbXMgd2l0aCBcIiArIHBhdGgpO1xufVxuXG5JbnN0YWxsRG90cy5wcm90b3R5cGUuY29tcGlsZVBhdGggPSBmdW5jdGlvbihwYXRoKSB7XG5cdHZhciBkYXRhID0gcmVhZGRhdGEocGF0aCk7XG5cdGlmIChkYXRhKSB7XG5cdFx0cmV0dXJuIGRvVC50ZW1wbGF0ZShkYXRhLFxuXHRcdFx0XHRcdHRoaXMuX19zZXR0aW5ncyB8fCBkb1QudGVtcGxhdGVTZXR0aW5ncyxcblx0XHRcdFx0XHRjb3B5KHRoaXMuX19pbmNsdWRlcykpO1xuXHR9XG59O1xuXG5JbnN0YWxsRG90cy5wcm90b3R5cGUuY29tcGlsZUFsbCA9IGZ1bmN0aW9uKCkge1xuXHRjb25zb2xlLmxvZyhcIkNvbXBpbGluZyBhbGwgZG9UIHRlbXBsYXRlcy4uLlwiKTtcblxuXHR2YXIgZGVmRm9sZGVyID0gdGhpcy5fX3BhdGgsXG5cdFx0c291cmNlcyA9IGZzLnJlYWRkaXJTeW5jKGRlZkZvbGRlciksXG5cdFx0aywgbCwgbmFtZTtcblxuXHRmb3IoIGsgPSAwLCBsID0gc291cmNlcy5sZW5ndGg7IGsgPCBsOyBrKyspIHtcblx0XHRuYW1lID0gc291cmNlc1trXTtcblx0XHRpZiAoL1xcLmRlZihcXC5kb3R8XFwuanN0KT8kLy50ZXN0KG5hbWUpKSB7XG5cdFx0XHRjb25zb2xlLmxvZyhcIkxvYWRlZCBkZWYgXCIgKyBuYW1lKTtcblx0XHRcdHRoaXMuX19pbmNsdWRlc1tuYW1lLnN1YnN0cmluZygwLCBuYW1lLmluZGV4T2YoJy4nKSldID0gcmVhZGRhdGEoZGVmRm9sZGVyICsgbmFtZSk7XG5cdFx0fVxuXHR9XG5cblx0Zm9yKCBrID0gMCwgbCA9IHNvdXJjZXMubGVuZ3RoOyBrIDwgbDsgaysrKSB7XG5cdFx0bmFtZSA9IHNvdXJjZXNba107XG5cdFx0aWYgKC9cXC5kb3QoXFwuZGVmfFxcLmpzdCk/JC8udGVzdChuYW1lKSkge1xuXHRcdFx0Y29uc29sZS5sb2coXCJDb21waWxpbmcgXCIgKyBuYW1lICsgXCIgdG8gZnVuY3Rpb25cIik7XG5cdFx0XHR0aGlzLl9fcmVuZGVybW9kdWxlW25hbWUuc3Vic3RyaW5nKDAsIG5hbWUuaW5kZXhPZignLicpKV0gPSB0aGlzLmNvbXBpbGVQYXRoKGRlZkZvbGRlciArIG5hbWUpO1xuXHRcdH1cblx0XHRpZiAoL1xcLmpzdChcXC5kb3R8XFwuZGVmKT8kLy50ZXN0KG5hbWUpKSB7XG5cdFx0XHRjb25zb2xlLmxvZyhcIkNvbXBpbGluZyBcIiArIG5hbWUgKyBcIiB0byBmaWxlXCIpO1xuXHRcdFx0dGhpcy5jb21waWxlVG9GaWxlKHRoaXMuX19kZXN0aW5hdGlvbiArIG5hbWUuc3Vic3RyaW5nKDAsIG5hbWUuaW5kZXhPZignLicpKSArICcuanMnLFxuXHRcdFx0XHRcdHJlYWRkYXRhKGRlZkZvbGRlciArIG5hbWUpKTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIHRoaXMuX19yZW5kZXJtb2R1bGU7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzJyk7XG5cblxuLyoqXG4gKiBbX19Qcm90b3R5cGUgZnVuY3Rpb25zX19dKHByb3RvX3Byb3RvdHlwZS5qcy5odG1sKVxuICpcbiAqIC0gW2V4dGVuZFByb3RvXShwcm90b19wcm90b3R5cGUuanMuaHRtbCNleHRlbmRQcm90bylcbiAqIC0gW2NyZWF0ZVN1YmNsYXNzXShwcm90b19wcm90b3R5cGUuanMuaHRtbCNjcmVhdGVTdWJjbGFzcylcbiAqIC0gW21ha2VTdWJjbGFzc10ocHJvdG9fcHJvdG90eXBlLmpzLmh0bWwjbWFrZVN1YmNsYXNzKVxuICogLSBbbmV3QXBwbHldKHByb3RvX3Byb3RvdHlwZS5qcy5odG1sI25ld0FwcGx5KVxuICovXG52YXIgcHJvdG90eXBlTWV0aG9kcyA9IHJlcXVpcmUoJy4vcHJvdG9fcHJvdG90eXBlJyk7XG5cblxuLyoqXG4gKiBbX19PYmplY3QgZnVuY3Rpb25zX19dKHByb3RvX29iamVjdC5qcy5odG1sKVxuICpcbiAqIC0gW2V4dGVuZF0ocHJvdG9fb2JqZWN0LmpzLmh0bWwjZXh0ZW5kKVxuICogLSBbY2xvbmVdKHByb3RvX29iamVjdC5qcy5odG1sI2Nsb25lKVxuICogLSBbZGVmaW5lUHJvcGVydHldKHByb3RvX29iamVjdC5qcy5odG1sI2RlZmluZVByb3BlcnR5KVxuICogLSBbZGVmaW5lUHJvcGVydGllc10ocHJvdG9fb2JqZWN0LmpzLmh0bWwjZGVmaW5lUHJvcGVydGllcylcbiAqIC0gW2RlZXBFeHRlbmRdKHByb3RvX29iamVjdC5qcy5odG1sI2RlZXBFeHRlbmQpXG4gKiAtIFtkZWVwQ2xvbmVdKHByb3RvX29iamVjdC5qcy5odG1sI2RlZXBDbG9uZSlcbiAqIC0gW2tleXNdKHByb3RvX29iamVjdC5qcy5odG1sI2tleXMpXG4gKiAtIFthbGxLZXlzXShwcm90b19vYmplY3QuanMuaHRtbCNhbGxLZXlzKVxuICogLSBbdmFsdWVzXShwcm90b19vYmplY3QuanMuaHRtbCN2YWx1ZXMpXG4gKiAtIFtrZXlPZl0ocHJvdG9fb2JqZWN0LmpzLmh0bWwja2V5T2YpXG4gKiAtIFthbGxLZXlzT2ZdKHByb3RvX29iamVjdC5qcy5odG1sI2FsbEtleXNPZilcbiAqIC0gW2VhY2hLZXldKHByb3RvX29iamVjdC5qcy5odG1sI2VhY2hLZXkpXG4gKiAtIFttYXBLZXlzXShwcm90b19vYmplY3QuanMuaHRtbCNtYXBLZXlzKVxuICogLSBbcmVkdWNlS2V5c10ocHJvdG9fb2JqZWN0LmpzLmh0bWwjcmVkdWNlS2V5cylcbiAqIC0gW2ZpbHRlcktleXNdKHByb3RvX29iamVjdC5qcy5odG1sI2ZpbHRlcktleXMpXG4gKiAtIFtzb21lS2V5XShwcm90b19vYmplY3QuanMuaHRtbCNzb21lS2V5KVxuICogLSBbZXZlcnlLZXldKHByb3RvX29iamVjdC5qcy5odG1sI2V2ZXJ5S2V5KVxuICogLSBbZmluZFZhbHVlXShwcm90b19vYmplY3QuanMuaHRtbCNmaW5kVmFsdWUpXG4gKiAtIFtmaW5kS2V5XShwcm90b19vYmplY3QuanMuaHRtbCNmaW5kS2V5KVxuICogLSBbcGlja0tleXNdKHByb3RvX29iamVjdC5qcy5odG1sI3BpY2tLZXlzKVxuICogLSBbb21pdEtleXNdKHByb3RvX29iamVjdC5qcy5odG1sI29taXRLZXlzKVxuICogLSBbaXNFcXVhbF0ocHJvdG9fb2JqZWN0LmpzLmh0bWwjaXNFcXVhbClcbiAqIC0gW2lzTm90XShwcm90b19vYmplY3QuanMuaHRtbCNpc05vdClcbiAqL1xudmFyIG9iamVjdE1ldGhvZHMgPSByZXF1aXJlKCcuL3Byb3RvX29iamVjdCcpO1xuXG5cbi8qKlxuICogW19fQXJyYXkgZnVuY3Rpb25zX19dKHByb3RvX2FycmF5LmpzLmh0bWwpXG4gKlxuICogLSBbZmluZF0ocHJvdG9fYXJyYXkuanMuaHRtbCNmaW5kKVxuICogLSBbZmluZEluZGV4XShwcm90b19hcnJheS5qcy5odG1sI2ZpbmRJbmRleClcbiAqIC0gW2FwcGVuZEFycmF5XShwcm90b19hcnJheS5qcy5odG1sI2FwcGVuZEFycmF5KVxuICogLSBbcHJlcGVuZEFycmF5XShwcm90b19hcnJheS5qcy5odG1sI3ByZXBlbmRBcnJheSlcbiAqIC0gW3NwbGljZUl0ZW1dKHByb3RvX2FycmF5LmpzLmh0bWwjc3BsaWNlSXRlbSlcbiAqIC0gW3RvQXJyYXldKHByb3RvX2FycmF5LmpzLmh0bWwjdG9BcnJheSlcbiAqIC0gW29iamVjdF0ocHJvdG9fYXJyYXkuanMuaHRtbCNvYmplY3QpXG4gKiAtIFttYXBUb09iamVjdF0ocHJvdG9fYXJyYXkuanMuaHRtbCNtYXBUb09iamVjdClcbiAqIC0gW3VuaXF1ZV0ocHJvdG9fYXJyYXkuanMuaHRtbCN1bmlxdWUpXG4gKiAtIFtkZWVwRm9yRWFjaF0ocHJvdG9fYXJyYXkuanMuaHRtbCNkZWVwRm9yRWFjaClcbiAqXG4gKiBGdW5jdGlvbnMgdGhhdCBBcnJheSBbaW1wbGVtZW50cyBuYXRpdmVseV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvcHJvdG90eXBlI01ldGhvZHMpIGFyZSBhbHNvIGFkZGVkIC0gdGhleSBjYW4gYmUgdXNlZCB3aXRoIGFycmF5LWxpa2Ugb2JqZWN0cyBhbmQgZm9yIGNoYWluaW5nIChuYXRpdmUgZnVuY3Rpb25zIGFyZSBhbHdheXMgY2FsbGVkKS5cbiAqL1xudmFyIGFycmF5TWV0aG9kcyA9IHJlcXVpcmUoJy4vcHJvdG9fYXJyYXknKTtcblxuXG4vKipcbiAqIFtfX0Z1bmN0aW9uIGZ1bmN0aW9uc19fXShwcm90b19mdW5jdGlvbi5qcy5odG1sKVxuICpcbiAqIC0gW21ha2VGdW5jdGlvbl0ocHJvdG9fZnVuY3Rpb24uanMuaHRtbCNtYWtlRnVuY3Rpb24pXG4gKiAtIFtwYXJ0aWFsXShwcm90b19mdW5jdGlvbi5qcy5odG1sI3BhcnRpYWwpXG4gKiAtIFtwYXJ0aWFsUmlnaHRdKHByb3RvX2Z1bmN0aW9uLmpzLmh0bWwjcGFydGlhbFJpZ2h0KVxuICogLSBbbWVtb2l6ZV0ocHJvdG9fZnVuY3Rpb24uanMuaHRtbCNtZW1vaXplKVxuICogLSBbZGVsYXldKHByb3RvX2Z1bmN0aW9uLmpzLmh0bWwjZGVsYXkpXG4gKiAtIFtkZWZlcl0ocHJvdG9fZnVuY3Rpb24uanMuaHRtbCNkZWZlcilcbiAqIC0gW2RlbGF5ZWRdKHByb3RvX2Z1bmN0aW9uLmpzLmh0bWwjZGVsYXllZClcbiAqIC0gW2RlZmVycmVkXShwcm90b19mdW5jdGlvbi5qcy5odG1sI2RlZmVycmVkKVxuICogLSBbZGVmZXJUaWNrc10ocHJvdG9fZnVuY3Rpb24uanMuaHRtbCNkZWZlclRpY2tzKVxuICogLSBbZGVsYXlNZXRob2RdKHByb3RvX2Z1bmN0aW9uLmpzLmh0bWwjZGVsYXlNZXRob2QpXG4gKiAtIFtkZWZlck1ldGhvZF0ocHJvdG9fZnVuY3Rpb24uanMuaHRtbCNkZWZlck1ldGhvZClcbiAqIC0gW2RlYm91bmNlXShwcm90b19mdW5jdGlvbi5qcy5odG1sI2RlYm91bmNlKVxuICogLSBbdGhyb3R0bGVdKHByb3RvX2Z1bmN0aW9uLmpzLmh0bWwjdGhyb3R0bGUpXG4gKiAtIFtvbmNlXShwcm90b19mdW5jdGlvbi5qcy5odG1sI29uY2UpXG4gKiAtIFt3YWl0Rm9yXShwcm90b19mdW5jdGlvbi5qcy5odG1sI3dhaXRGb3IpXG4qL1xudmFyIGZ1bmN0aW9uTWV0aG9kcyA9IHJlcXVpcmUoJy4vcHJvdG9fZnVuY3Rpb24nKTtcblxuXG4vKipcbiAqIFtfX1N0cmluZyBmdW5jdGlvbnNfX10ocHJvdG9fc3RyaW5nLmpzLmh0bWwpXG4gKlxuICogLSBbZmlyc3RVcHBlckNhc2VdKHByb3RvX3N0cmluZy5qcy5odG1sI2ZpcnN0VXBwZXJDYXNlKVxuICogLSBbZmlyc3RMb3dlckNhc2VdKHByb3RvX3N0cmluZy5qcy5odG1sI2ZpcnN0TG93ZXJDYXNlKVxuICogLSBbdG9SZWdFeHBdKHByb3RvX3N0cmluZy5qcy5odG1sI3RvUmVnRXhwKVxuICogLSBbdG9GdW5jdGlvbl0ocHJvdG9fc3RyaW5nLmpzLmh0bWwjdG9GdW5jdGlvbilcbiAqIC0gW3RvRGF0ZV0ocHJvdG9fc3RyaW5nLmpzLmh0bWwjdG9EYXRlKVxuICogLSBbdG9RdWVyeVN0cmluZ10ocHJvdG9fc3RyaW5nLmpzLmh0bWwjdG9RdWVyeVN0cmluZylcbiAqIC0gW2Zyb21RdWVyeVN0cmluZ10ocHJvdG9fc3RyaW5nLmpzLmh0bWwjZnJvbVF1ZXJ5U3RyaW5nKVxuICogLSBbanNvblBhcnNlXShwcm90b19zdHJpbmcuanMuaHRtbCNqc29uUGFyc2UpXG4gKiAtIFtoYXNoQ29kZV0ocHJvdG9fc3RyaW5nLmpzLmh0bWwjaGFzaENvZGUpXG4gKiAtIFt1blByZWZpeF0ocHJvdG9fc3RyaW5nLmpzLmh0bWwjdW5QcmVmaXgpXG4gKi9cbnZhciBzdHJpbmdNZXRob2RzID0gcmVxdWlyZSgnLi9wcm90b19zdHJpbmcnKTtcblxuXG4vKipcbiAqIFtfX051bWJlciBmdW5jdGlvbnNfX10ocHJvdG9fbnVtYmVyLmpzLmh0bWwpXG4gKlxuICogLSBbaXNOdW1lcmljXShwcm90b19udW1iZXIuanMuaHRtbCNpc051bWVyaWMpXG4gKi9cbnZhciBudW1iZXJNZXRob2RzID0gcmVxdWlyZSgnLi9wcm90b19udW1iZXInKTtcblxuXG4vKipcbiAqIFtfX1V0aWxpdHkgZnVuY3Rpb25zX19dKHByb3RvX3V0aWwuanMuaHRtbClcbiAqXG4gKiAtIFt0aW1lc10ocHJvdG9fdXRpbC5qcy5odG1sI3RpbWVzKVxuICogLSBbcmVwZWF0XShwcm90b191dGlsLmpzLmh0bWwjcmVwZWF0KVxuICogLSBbdGFwXShwcm90b191dGlsLmpzLmh0bWwjdGFwKVxuICogLSBbcmVzdWx0XShwcm90b191dGlsLmpzLmh0bWwjcmVzdWx0KVxuICogLSBbaWRlbnRpdHldKHByb3RvX3V0aWwuanMuaHRtbCNpZGVudGl0eSlcbiAqIC0gW3Byb3BlcnR5XShwcm90b191dGlsLmpzLmh0bWwjcHJvcGVydHkpXG4gKiAtIFtjb21wYXJlUHJvcGVydHldKHByb3RvX3V0aWwuanMuaHRtbCNjb21wYXJlUHJvcGVydHkpXG4gKiAtIFtub29wXShwcm90b191dGlsLmpzLmh0bWwjbm9vcClcbiAqL1xudmFyIHV0aWxNZXRob2RzID0gcmVxdWlyZSgnLi9wcm90b191dGlsJyk7XG5cblxuLyoqXG4gKiBDaGFpbmluZ1xuICogPT09PT09PT1cbiAqXG4gKiBgX2AgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGEgd3JhcHBlZCB2YWx1ZSAob2JqZWN0LCBmdW5jdGlvbiwgYXJyYXksIGV0Yy4pIHRvIGFsbG93IGNoYWluaW5nIG9mIFByb3RvIGZ1bmN0aW9ucy5cbiAqIFRvIHVud3JhcCwgYF9gIG1ldGhvZCBvZiBhIHdyYXBwZWQgdmFsdWUgc2hvdWxkIGJlIHVzZWQuXG4gKiBVc2FnZTpcbiAqIGBgYFxuICogdmFyIGFyciA9IF8oeyAwOiAzLCAxOiA0LCAyOiA1LCBsZW5ndGg6IDN9KVxuICogICAgICAgICAgICAgIC50b0FycmF5KClcbiAqICAgICAgICAgICAgICAucHJlcGVuZEFycmF5KFsxLCAyXSlcbiAqICAgICAgICAgICAgICAuYXBwZW5kQXJyYXkoWzYsIDcsIDhdKVxuICogICAgICAgICAgICAgIC5fKCk7XG4gKiBgYGBcbiAqIEEgd3JhcHBlZCBvYmplY3QgaXMgYW4gaW5zdGFuY2Ugb2YgYF9gIChgUHJvdG9gIGNsYXNzKS5cbiAqXG4gKiBDaGFpbmluZyBpcyBpbXBsZW1lbnRlZCBmb3IgZGV2ZWxvcG1lbnQgY29udmVuaWVuY2UsIGJ1dCBpdCBoYXMgcGVyZm9ybWFuY2Ugb3ZlcmhlYWQsIG5vdCBvbmx5IHRvIHdyYXAgYW5kIHVud3JhcCB2YWx1ZXMgYnV0IGluIGVhY2ggZnVuY3Rpb24gY2FsbC5cbiAqIEFsdGhvdWdoIGFsbCBQcm90byBmdW5jdGlvbnMgYXJlIGltcGxlbWVudGVkIGFzIG1ldGhvZHMgb3BlcmF0aW5nIG9uIHRoaXMgYW5kIHRoZSBvdmVyaGVhZCB0byByZWRlZmluZSB0aGVtIGFzIGZ1bmN0aW9ucyBpcyB2ZXJ5IHNtYWxsLCB0aGUgb3ZlcmhlYWQgdG8gcmVkZWZpbmUgdGhlbSBhcyBtZXRob2RzIG9mIHdyYXBwZWQgdmFsdWUgaXMgc2xpZ2h0bHkgaGlnaGVyIC0gY2hhaW5pbmcgaXMgMTUtMjUlIHNsb3dlciB0aGFuIHVzaW5nIGZ1bmN0aW9ucyAocHJvcGVydGllcyBvZiBfIHRoYXQgdGFrZSB0aGUgZmlyc3QgcGFyYW1ldGVyKS5cbiAqIEluIGNhc2VzIHdoZW4gcGVyZm9ybWFuY2UgaXMgY3JpdGljYWwsIHlvdSBtYXkgd2FudCB0byBhdm9pZCB1c2luZyBjaGFpbmluZy5cbiAqXG4gKiBAcGFyYW0ge0FueX0gc2VsZiBBIHZhbHVlIHRvIGJlIHdyYXBwZWRcbiAqIEByZXR1cm4ge1Byb3RvfVxuICovXG5mdW5jdGlvbiBQcm90byhzZWxmKSB7XG4gICAgLy8gd3JhcCBwYXNzZWQgcGFyYW1ldGVyIGluIF8gb2JqZWN0XG4gICAgdmFyIHdyYXBwZWQgPSBPYmplY3QuY3JlYXRlKFByb3RvLnByb3RvdHlwZSk7XG4gICAgd3JhcHBlZC5zZWxmID0gc2VsZjtcbiAgICByZXR1cm4gd3JhcHBlZDtcbn07XG5cbnZhciBfID0gUHJvdG87XG5cblxuLy8gc3RvcmUgcmF3IG1ldGhvZHMgZnJvbSBkaWZmZXJlbnQgbW9kdWxlcyBpbiBfXyBvYmplY3QgKGRvdWJsZSBcIl9cIilcbnZhciBfXyA9IHt9O1xuXG5vYmplY3RNZXRob2RzLmV4dGVuZC5jYWxsKF9fLCBvYmplY3RNZXRob2RzKTtcbl9fLmV4dGVuZC5jYWxsKF9fLCBwcm90b3R5cGVNZXRob2RzKTtcbl9fLmV4dGVuZC5jYWxsKF9fLCBhcnJheU1ldGhvZHMpO1xuX18uZXh0ZW5kLmNhbGwoX18sIHN0cmluZ01ldGhvZHMpO1xuX18uZXh0ZW5kLmNhbGwoX18sIG51bWJlck1ldGhvZHMpO1xuX18uZXh0ZW5kLmNhbGwoX18sIGZ1bmN0aW9uTWV0aG9kcyk7XG5fXy5leHRlbmQuY2FsbChfXywgdXRpbE1ldGhvZHMpO1xuXG5cbi8vIGFkZCBfXyBhcyBwcm9wZXJ0eSBvZiBQcm90bywgc28gdGhleSBjYW4gYmUgdXNlZCBhcyBtaXhpbnMgaW4gb3RoZXIgY2xhc3Nlc1xuX18uZGVmaW5lUHJvcGVydHkoUHJvdG8sICdfXycsIF9fKTtcblxuXG4vLyBhZGQgXyBtZXRob2QgdG8gdW53cmFwIHdyYXBwZWQgdmFsdWUgKFByb3RvIGluc3RhbmNlKVxuZnVuY3Rpb24gdW53cmFwUHJvdG8oKSB7IHJldHVybiB0aGlzLnNlbGY7IH1cbl9fLmV4dGVuZFByb3RvLmNhbGwoUHJvdG8sIHsgXzogdW53cmFwUHJvdG8gfSk7XG5cbi8vIGFkZCBjb25zdGFudHMgKGZ1bmN0aW9ucyB3aWxsIGJlIG92ZXJ3cml0dGVuKVxuX18uZXh0ZW5kLmNhbGwoUHJvdG8sIG9iamVjdE1ldGhvZHMuX2NvbnN0YW50cyk7XG5cbi8vIGFkZCBmdW5jdGlvbnMgdGhhdCB0YWtlIGZpcnN0IHBhcmFtZXRlciBpbnN0ZWFkIG9mIFwidGhpc1wiIHRvIFByb3RvXG52YXIgcHJvdG9GdW5jcyA9IF9fLm1hcEtleXMuY2FsbChfXywgdXRpbHMubWFrZVByb3RvRnVuY3Rpb24sIHRydWUpO1xuX18uZXh0ZW5kLmNhbGwoUHJvdG8sIHByb3RvRnVuY3MpO1xuXG4vLyBhZGQgUHJvdG8gd3JhcHBlZCB2YWx1ZSBpbnN0YW5jZSBtZXRob2RzIHRvIFByb3RvIHByb3RvdHlwZVxudmFyIHByb3RvSW5zdGFuY2VNZXRob2RzID0gX18ubWFwS2V5cy5jYWxsKF9fLCB1dGlscy5tYWtlUHJvdG9JbnN0YW5jZU1ldGhvZCwgdHJ1ZSk7XG5fXy5leHRlbmRQcm90by5jYWxsKFByb3RvLCBwcm90b0luc3RhbmNlTWV0aG9kcyk7XG5cblxuLyoqXG4gKiBJbiB3aW5kb3dzIGVudmlyb25tZW50LCBhIGdsb2JhbCBgX2AgdmFsdWUgaXMgcHJlc2VydmVkIGluIGBfLnVuZGVyc2NvcmVgXG4gKi9cbmlmICh0eXBlb2Ygd2luZG93ID09ICdvYmplY3QnKSB7XG4gICAgLy8gcHJlc2VydmUgZXhpc3RpbmcgXyBvYmplY3RcbiAgICBpZiAod2luZG93Ll8pXG4gICAgICAgIFByb3RvLnVuZGVyc2NvcmUgPSB3aW5kb3cuX1xuXG4gICAgLy8gZXhwb3NlIGdsb2JhbCBfIGFuZCBQcm90b1xuICAgIHdpbmRvdy5fID0gUHJvdG87XG59XG5cbmlmICh0eXBlb2YgbW9kdWxlID09ICdvYmplY3QnICYmIG1vZHVsZS5leHBvcnRzKVxuICAgIC8vIGV4cG9ydCBmb3Igbm9kZS9icm93c2VyaWZ5XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBQcm90bztcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIF9fID0gcmVxdWlyZSgnLi9wcm90b19vYmplY3QnKVxuICAgICwgdXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzJyk7XG5cblxuLyoqXG4gKiAtIFtmaW5kXSgjZmluZClcbiAqIC0gW2ZpbmRJbmRleF0oI2ZpbmRJbmRleClcbiAqIC0gW2FwcGVuZEFycmF5XSgjYXBwZW5kQXJyYXkpXG4gKiAtIFtwcmVwZW5kQXJyYXldKCNwcmVwZW5kQXJyYXkpXG4gKiAtIFtzcGxpY2VJdGVtXSgjc3BsaWNlSXRlbSlcbiAqIC0gW3RvQXJyYXldKCN0b0FycmF5KVxuICogLSBbb2JqZWN0XSgjb2JqZWN0KVxuICogLSBbbWFwVG9PYmplY3RdKCNtYXBUb09iamVjdClcbiAqIC0gW3VuaXF1ZV0oI3VuaXF1ZSlcbiAqIC0gW2RlZXBGb3JFYWNoXSgjZGVlcEZvckVhY2gpXG4gKlxuICogVGhlc2UgbWV0aG9kcyBjYW4gYmUgW2NoYWluZWRdKHByb3RvLmpzLmh0bWwjUHJvdG8pLlxuICovXG52YXIgYXJyYXlNZXRob2RzID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgLy8gZmluZDogc2VlIGJlbG93XG4gICAgLy8gZmluZEluZGV4OiBzZWUgYmVsb3dcbiAgICBhcHBlbmRBcnJheTogYXBwZW5kQXJyYXksXG4gICAgcHJlcGVuZEFycmF5OiBwcmVwZW5kQXJyYXksXG4gICAgdG9BcnJheTogdG9BcnJheSxcbiAgICBvYmplY3Q6IG9iamVjdCxcbiAgICBtYXBUb09iamVjdDogbWFwVG9PYmplY3QsXG4gICAgdW5pcXVlOiB1bmlxdWUsXG4gICAgZGVlcEZvckVhY2g6IGRlZXBGb3JFYWNoLFxuICAgIHNwbGljZUl0ZW06IHNwbGljZUl0ZW1cbn07XG5cblxuLyoqXG4gKiBGdW5jdGlvbnMgdGhhdCBBcnJheSBbaW1wbGVtZW50cyBuYXRpdmVseV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvcHJvdG90eXBlI01ldGhvZHMpIGFyZSBhbHNvIGluY2x1ZGVkIGZvciBjb252ZW5pZW5jZSAtIHRoZXkgY2FuIGJlIHVzZWQgd2l0aCBhcnJheS1saWtlIG9iamVjdHMgYW5kIGZvciBjaGFpbmluZyAobmF0aXZlIGZ1bmN0aW9ucyBhcmUgYWx3YXlzIGNhbGxlZCkuXG4gKiBUaGVzZSBtZXRob2RzIGNhbiBiZSBbY2hhaW5lZF0ocHJvdG8uanMuaHRtbCNQcm90bykgdG9vLlxuICovXG52YXIgbmF0aXZlQXJyYXlNZXRob2RzTmFtZXMgPSBbICdqb2luJywgJ3BvcCcsICdwdXNoJywgJ2NvbmNhdCcsXG4gICAgJ3JldmVyc2UnLCAnc2hpZnQnLCAndW5zaGlmdCcsICdzbGljZScsICdzcGxpY2UnLFxuICAgICdzb3J0JywgJ2ZpbHRlcicsICdmb3JFYWNoJywgJ3NvbWUnLCAnZXZlcnknLFxuICAgICdtYXAnLCAnaW5kZXhPZicsICdsYXN0SW5kZXhPZicsICdyZWR1Y2UnLCAncmVkdWNlUmlnaHQnXTtcblxudmFyIG5hdGl2ZUFycmF5TWV0aG9kcyA9IG1hcFRvT2JqZWN0LmNhbGwobmF0aXZlQXJyYXlNZXRob2RzTmFtZXMsXG4gICAgICAgIGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybiBBcnJheS5wcm90b3R5cGVbbWV0aG9kTmFtZV07XG4gICAgICAgIH0pO1xuXG5fXy5leHRlbmQuY2FsbChhcnJheU1ldGhvZHMsIG5hdGl2ZUFycmF5TWV0aG9kcyk7XG5cblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiBFUzYgW0FycmF5IF9fZmluZF9fIG1ldGhvZF0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvZmluZCkgKG5hdGl2ZSBtZXRob2QgaXMgdXNlZCBpZiBhdmFpbGFibGUpLlxuICogUmV0dXJucyBhcnJheSBlbGVtZW50IHRoYXQgcGFzc2VzIGNhbGxiYWNrIHRlc3QuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gc2VsZiBhcnJheSB0byBzZWFyY2ggaW5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIHNob3VsZCByZXR1cm4gYHRydWVgIGZvciBpdGVtIHRvIHBhc3MgdGhlIHRlc3QsIHBhc3NlZCBgdmFsdWVgLCBgaW5kZXhgIGFuZCBgc2VsZmAgYXMgcGFyYW1ldGVyc1xuICogQHBhcmFtIHtPYmplY3R9IHRoaXNBcmcgb3B0aW9uYWwgY29udGV4dCAoYHRoaXNgKSBvZiBjYWxsYmFjayBjYWxsXG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmFycmF5TWV0aG9kcy5maW5kID0gQXJyYXkucHJvdG90eXBlLmZpbmRcbiAgICB8fCB1dGlscy5tYWtlRmluZE1ldGhvZChhcnJheU1ldGhvZHMuZm9yRWFjaCwgJ3ZhbHVlJyk7XG5cblxuLyoqXG4gKiBJbXBsZW1lbnRhdGlvbiBvZiBFUzYgW0FycmF5IF9fZmluZEluZGV4X18gbWV0aG9kXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9maW5kSW5kZXgpIChuYXRpdmUgbWV0aG9kIGlzIHVzZWQgaWYgYXZhaWxhYmxlKS5cbiAqIFJldHVybnMgdGhlIGluZGV4IG9mIGFycmF5IGVsZW1lbnQgdGhhdCBwYXNzZXMgY2FsbGJhY2sgdGVzdC4gUmV0dXJucyBgLTFgIGlmIG5vdCBmb3VuZC5cbiAqXG4gKiBAcGFyYW0ge0FycmF5fSBzZWxmIGFycmF5IHRvIHNlYXJjaCBpblxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgc2hvdWxkIHJldHVybiBgdHJ1ZWAgZm9yIGl0ZW0gdG8gcGFzcyB0aGUgdGVzdCwgcGFzc2VkIGB2YWx1ZWAsIGBpbmRleGAgYW5kIGBzZWxmYCBhcyBwYXJhbWV0ZXJzXG4gKiBAcGFyYW0ge09iamVjdH0gdGhpc0FyZyBvcHRpb25hbCBjb250ZXh0IChgdGhpc2ApIG9mIGNhbGxiYWNrIGNhbGxcbiAqIEByZXR1cm4ge0ludGVnZXJ9XG4gKi9cbmFycmF5TWV0aG9kcy5maW5kSW5kZXggPSBBcnJheS5wcm90b3R5cGUuZmluZEluZGV4XG4gICAgfHwgdXRpbHMubWFrZUZpbmRNZXRob2QoYXJyYXlNZXRob2RzLmZvckVhY2gsICdpbmRleCcpO1xuXG5cbi8qKlxuICogQXBwZW5kcyBgYXJyYXlUb0FwcGVuZGAgdG8gdGhlIGVuZCBvZiBhcnJheSBgc2VsZmAgaW4gcGxhY2UgKGNhbiBiZSBhbiBpbnN0YW5jZSBvZiBBcnJheSBvciBhcnJheS1saWtlIG9iamVjdCkuXG4gKiBDaGFuZ2VzIHRoZSB2YWx1ZSBvZiBgc2VsZmAgKGl0IHVzZXMgYEFycmF5LnByb3RvdHlwZS5zcGxpY2VgKSBhbmQgcmV0dXJucyBgc2VsZmAuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gc2VsZiBBbiBhcnJheSB0aGF0IHdpbGwgYmUgbW9kaWZpZWRcbiAqIEBwYXJhbSB7QXJyYXl8QXJyYXktbGlrZX0gYXJyYXlUb0FwcGVuZCBBbiBhcnJheSB0aGF0IHdpbGwgYmUgYXBwZW5kZWRcbiAqIEByZXR1cm4ge0FycmF5fVxuICovXG5mdW5jdGlvbiBhcHBlbmRBcnJheShhcnJheVRvQXBwZW5kKSB7XG4gICAgaWYgKCEgYXJyYXlUb0FwcGVuZC5sZW5ndGgpIHJldHVybiB0aGlzO1xuICAgIGlmICghIEFycmF5LmlzQXJyYXkoYXJyYXlUb0FwcGVuZCkpXG4gICAgICAgIGFycmF5VG9BcHBlbmQgPSB0b0FycmF5LmNhbGwoYXJyYXlUb0FwcGVuZCk7XG4gICAgXG4gICAgdmFyIGFyZ3MgPSBbdGhpcy5sZW5ndGgsIDBdLmNvbmNhdChhcnJheVRvQXBwZW5kKTtcbiAgICBhcnJheU1ldGhvZHMuc3BsaWNlLmFwcGx5KHRoaXMsIGFyZ3MpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBQcmVwZW5kcyBgYXJyYXlUb1ByZXBlbmRgIHRvIHRoZSBiZWdpbm5pZyBvZiBhcnJheSBgc2VsZmAgaW4gcGxhY2UgKGNhbiBiZSBhbiBpbnN0YW5jZSBvZiBBcnJheSBvciBhcnJheS1saWtlIG9iamVjdCkuXG4gKiBDaGFuZ2VzIHRoZSB2YWx1ZSBvZiBgc2VsZmAgKGl0IHVzZXMgYEFycmF5LnByb3RvdHlwZS5zcGxpY2VgKSBhbmQgcmV0dXJucyBgc2VsZmAuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gc2VsZiBBbiBhcnJheSB0aGF0IHdpbGwgYmUgbW9kaWZpZWRcbiAqIEBwYXJhbSB7QXJyYXl8QXJyYXktbGlrZX0gYXJyYXlUb0FwcGVuZCBBbiBhcnJheSB0aGF0IHdpbGwgYmUgcHJlcGVuZGVkXG4gKiBAcmV0dXJuIHtBcnJheX1cbiAqL1xuZnVuY3Rpb24gcHJlcGVuZEFycmF5KGFycmF5VG9QcmVwZW5kKSB7XG4gICAgaWYgKCEgYXJyYXlUb1ByZXBlbmQubGVuZ3RoKSByZXR1cm4gdGhpcztcbiAgICBpZiAoISBBcnJheS5pc0FycmF5KGFycmF5VG9QcmVwZW5kKSlcbiAgICAgICAgYXJyYXlUb1ByZXBlbmQgPSB0b0FycmF5LmNhbGwoYXJyYXlUb1ByZXBlbmQpO1xuXG4gICAgdmFyIGFyZ3MgPSBbMCwgMF0uY29uY2F0KGFycmF5VG9QcmVwZW5kKTtcbiAgICBhcnJheU1ldGhvZHMuc3BsaWNlLmFwcGx5KHRoaXMsIGFyZ3MpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBSZW1vdmVzIGl0ZW0gZnJvbSBhcnJheSB0aGF0IGlzIGZvdW5kIHVzaW5nIGluZGV4T2YgKGkuZS4gJz09PScpXG4gKiBNb2RpZmllcyBvcmlnaW5hbCBhcnJheSBhbmQgcmV0dXJucyB0aGUgcmVmZXJlbmNlIHRvIGl0LlxuICogXG4gKiBAcGFyYW0ge0FycmF5fSBzZWxmIEFuIGFycmF5IHRoYXQgd2lsbCBiZSBtb2RpZmllZFxuICogQHBhcmFtICB7QW55fSBpdGVtIGl0ZW0gdG8gYmUgcmVtb3ZlZFxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIHNwbGljZUl0ZW0oaXRlbSkge1xuICAgIHZhciBpbmRleCA9IHRoaXMuaW5kZXhPZihpdGVtKTtcbiAgICBpZiAoaW5kZXggPj0gMCkgdGhpcy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBuZXcgYXJyYXkgY3JlYXRlZCBmcm9tIGFycmF5LWxpa2Ugb2JqZWN0IChlLmcuLCBgYXJndW1lbnRzYCBwc2V1ZG8tYXJyYXkpLlxuICpcbiAqIEBwYXJhbSB7QXJyYXktbGlrZX0gc2VsZiBPYmplY3Qgd2l0aCBudW1lcmljIHByb3BlcnR5IGxlbmd0aFxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIHRvQXJyYXkoKSB7XG4gICAgcmV0dXJuIGFycmF5TWV0aG9kcy5zbGljZS5jYWxsKHRoaXMpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBhbiBvYmplY3QgY3JlYXRlZCBmcm9tIHRoZSBhcnJheSBvZiBga2V5c2AgYW5kIG9wdGlvbmFsIGFycmF5IG9mIGB2YWx1ZXNgLlxuICpcbiAqIEBwYXJhbSB7QXJyYXl9IHNlbGYgQXJyYXkgb2Yga2V5c1xuICogQHBhcmFtIHtBcnJheXxhbnl9IHZhbHVlcyBPcHRpb25hbCBhcnJheSBvZiB2YWx1ZXMgb3IgdGhlIHZhbHVlIHRvIGJlIGFzc2lnbmVkIHRvIGVhY2ggcHJvcGVydHkuXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIG9iamVjdCh2YWx1ZXMpIHtcbiAgICB2YXIgb2JqID0ge31cbiAgICAgICAgLCB2YWx1ZXNJc0FycmF5ID0gQXJyYXkuaXNBcnJheSh2YWx1ZXMpO1xuICAgIGFycmF5TWV0aG9kcy5mb3JFYWNoLmNhbGwodGhpcywgZnVuY3Rpb24oa2V5LCBpbmRleCkge1xuICAgICAgICBvYmpba2V5XSA9IHZhbHVlc0lzQXJyYXkgPyB2YWx1ZXNbaW5kZXhdIDogdmFsdWVzO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIG9iajtcbn1cblxuXG4vKipcbiAqIE1hcHMgYXJyYXkgdG8gb2JqZWN0LlxuICogQXJyYXkgZWxlbWVudHMgYmVjb21lIGtleXMsIHZhbHVlIGFyZSB0YWtlbiBmcm9tIGBjYWxsYmFja2AuXG4gKiBcbiAqIEBwYXJhbSB7QXJyYXl9IHNlbGYgQW4gYXJyYXkgd2hpY2ggdmFsdWVzIHdpbGwgYmVjb21lIGtleXMgb2YgdGhlIHJlc3VsdFxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGJhY2sgaXMgcGFzc2VkIGB2YWx1ZWAsIGBpbmRleGAgYW5kIGBzZWxmYCBhbmQgc2hvdWxkIHJldHVybiB2YWx1ZSB0aGF0IHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIHJlc3VsdC5cbiAqIEBwYXJhbSB7T2JqZWN0fSB0aGlzQXJnIEFuIG9wdGlvbmFsIGNvbnRleHQgb2YgaXRlcmF0aW9uICh0aGUgdmFsdWVvZiBgdGhpc2ApLCB3aWxsIGJlIHVuZGVmaW5lZCBpZiB0aGlzIHBhcmFtZXRlciBpcyBub3QgcGFzc2VkLlxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5mdW5jdGlvbiBtYXBUb09iamVjdChjYWxsYmFjaywgdGhpc0FyZykge1xuICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICBBcnJheS5wcm90b3R5cGUuZm9yRWFjaC5jYWxsKHRoaXMsIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCkge1xuICAgICAgICByZXN1bHRbdmFsdWVdID0gY2FsbGJhY2suY2FsbCh0aGlzQXJnLCB2YWx1ZSwgaW5kZXgsIHRoaXMpO1xuICAgIH0sIHRoaXMpO1xuICAgIHJldHVybiByZXN1bHQ7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGFycmF5IHdpdGhvdXQgZHVwbGljYXRlcy4gRG9lcyBub3QgbW9kaWZ5IG9yaWdpbmFsIGFycmF5LlxuICpcbiAqIEBwYXJhbSB7QXJyYXl9IHNlbGYgb3JpZ2luYWwgYXJyYXlcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIGNvbXBhcmlzb24gZnVuY3Rpb24sIHNob3VsZCByZXR1cm4gdHJ1ZSBmb3IgZXF1YWwgaXRlbXMsIFwiPT09XCIgaXMgdXNlZCBpZiBub3QgcGFzc2VkLlxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIHVuaXF1ZShjYWxsYmFjaykge1xuICAgIHZhciBmaWx0ZXJlZCA9IFtdO1xuICAgIGlmICghIGNhbGxiYWNrKVxuICAgICAgICBpdGVtSW5kZXggPSBpdGVtSW5kZXhPZjtcblxuICAgIHRoaXMuZm9yRWFjaChmdW5jdGlvbihpdGVtKSB7XG4gICAgICAgIHZhciBpbmRleCA9IGl0ZW1JbmRleChpdGVtKTtcbiAgICAgICAgaWYgKGluZGV4ID09IC0xKVxuICAgICAgICAgICAgZmlsdGVyZWQucHVzaChpdGVtKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBmaWx0ZXJlZDtcblxuXG4gICAgZnVuY3Rpb24gaXRlbUluZGV4KGl0ZW0pIHtcbiAgICAgICAgcmV0dXJuIGFycmF5TWV0aG9kcy5maW5kSW5kZXguY2FsbChmaWx0ZXJlZCwgZnVuY3Rpb24oaXQpIHtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhpdGVtLCBpdCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGl0ZW1JbmRleE9mKGl0ZW0pIHtcbiAgICAgICAgcmV0dXJuIGZpbHRlcmVkLmluZGV4T2YoaXRlbSk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogSXRlcmF0ZXMgYXJyYXkgYW5kIGVsZW1lbnRzIHRoYXQgYXJlIGFycmF5cyBjYWxsaW5nIGNhbGxiYWNrIHdpdGggZWFjaCBlbGVtZW50IHRoYXQgaXMgbm90IGFuIGFycmF5LiBDYW4gYmUgdXNlZCB0byBpdGVyYXRlIG92ZXIgYXJndW1lbnRzIGxpc3QgdG8gYXZvaWQgY2hlY2tpbmcgd2hldGhlciBhcnJheSBvciBsaXN0IG9mIHBhcmFtZXRlcnMgaXMgcGFzc2VkLlxuICpcbiAqIEBwYXJhbSB7QXJyYXl8QXJyYXktbGlrZX0gc2VsZiBhcnJheSBvZiBlbGVtZW50cyBhbmQgYXJyYXlzdG8gaXRlcmF0ZS5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIGNhbGxlZCBmb3IgZWFjaCBpdGVtIHRoYXQgaXMgbm90IGFuIGFycmF5LiBDYWxsYmFjayBpcyBwYXNzZWQgaXRlbSwgaW5kZXggYW5kIG9yaWdpbmFsIGFycmF5IGFzIHBhcmFtZXRlcnMuXG4gKiBAcGFyYW0ge0FueX0gdGhpc0FyZyBvcHRpb25hbCBjYWxsYmFjayBlbnZvY2F0aW9uIGNvbnRleHRcbiAqL1xuZnVuY3Rpb24gZGVlcEZvckVhY2goY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICB2YXIgaW5kZXggPSAwLCBhcnIgPSB0aGlzO1xuICAgIF9kZWVwRm9yRWFjaC5jYWxsKHRoaXMpO1xuXG4gICAgZnVuY3Rpb24gX2RlZXBGb3JFYWNoKCkge1xuICAgICAgICBhcnJheU1ldGhvZHMuZm9yRWFjaC5jYWxsKHRoaXMsIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpXG4gICAgICAgICAgICAgICAgX2RlZXBGb3JFYWNoLmNhbGwodmFsdWUpO1xuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwodGhpc0FyZywgdmFsdWUsIGluZGV4KyssIGFycik7XG4gICAgICAgIH0pO1xuICAgIH1cbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgbWFrZVByb3RvRnVuY3Rpb24gPSByZXF1aXJlKCcuL3V0aWxzJykubWFrZVByb3RvRnVuY3Rpb25cbiAgICAsIHJlcGVhdCA9IHJlcXVpcmUoJy4vcHJvdG9fdXRpbCcpLnJlcGVhdDtcblxuXG4vKipcbiAqIC0gW21ha2VGdW5jdGlvbl0oI21ha2VGdW5jdGlvbilcbiAqIC0gW3BhcnRpYWxdKCNwYXJ0aWFsKVxuICogLSBbcGFydGlhbFJpZ2h0XSgjcGFydGlhbFJpZ2h0KVxuICogLSBbbWVtb2l6ZV0oI21lbW9pemUpXG4gKiAtIFtkZWxheV0oI2RlbGF5KVxuICogLSBbZGVmZXJdKCNkZWZlcilcbiAqIC0gW2RlbGF5ZWRdKCNkZWxheWVkKVxuICogLSBbZGVmZXJyZWRdKCNkZWZlcnJlZClcbiAqIC0gW2RlZmVyVGlja3NdKCNkZWZlclRpY2tzKVxuICogLSBbZGVsYXlNZXRob2RdKCNkZWxheU1ldGhvZClcbiAqIC0gW2RlZmVyTWV0aG9kXSgjZGVmZXJNZXRob2QpXG4gKiAtIFtkZWJvdW5jZV0oI2RlYm91bmNlKVxuICogLSBbdGhyb3R0bGVdKCN0aHJvdHRsZSlcbiAqIC0gW29uY2VdKCNvbmNlKVxuICogLSBbd2FpdEZvcl0oI3dhaXRGb3IpXG4gKiAtIFtub3RdKCNub3QpXG4gKlxuICogVGhlc2UgbWV0aG9kcyBjYW4gYmUgW2NoYWluZWRdKHByb3RvLmpzLmh0bWwjUHJvdG8pXG4gKi9cbnZhciBmdW5jdGlvbk1ldGhvZHMgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBtYWtlRnVuY3Rpb246IG1ha2VGdW5jdGlvbixcbiAgICBwYXJ0aWFsOiBwYXJ0aWFsLFxuICAgIHBhcnRpYWxSaWdodDogcGFydGlhbFJpZ2h0LFxuICAgIG1lbW9pemU6IG1lbW9pemUsXG4gICAgZGVsYXk6IGRlbGF5LFxuICAgIGRlZmVyOiBkZWZlcixcbiAgICBkZWxheWVkOiBkZWxheWVkLFxuICAgIGRlZmVycmVkOiBkZWZlcnJlZCxcbiAgICBkZWZlclRpY2tzOiBkZWZlclRpY2tzLFxuICAgIGRlbGF5TWV0aG9kOiBkZWxheU1ldGhvZCxcbiAgICBkZWZlck1ldGhvZDogZGVmZXJNZXRob2QsXG4gICAgZGVib3VuY2U6IGRlYm91bmNlLFxuICAgIHRocm90dGxlOiB0aHJvdHRsZSxcbiAgICBvbmNlOiBvbmNlLFxuICAgIHdhaXRGb3I6IHdhaXRGb3IsXG4gICAgbm90OiBub3Rcbn07XG5cblxudmFyIHNsaWNlID0gQXJyYXkucHJvdG90eXBlLnNsaWNlO1xuXG5cbi8qKlxuICogU2ltaWxhcmx5IHRvIEZ1bmN0aW9uIGNvbnN0cnVjdG9yIGNyZWF0ZXMgYSBmdW5jdGlvbiBmcm9tIGNvZGUuXG4gKiBVbmxpa2UgRnVuY3Rpb24gY29uc3RydWN0b3IsIHRoZSBmaXJzdCBhcmd1bWVudCBpcyBhIGZ1bmN0aW9uIG5hbWVcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBuZXcgZnVuY3Rpb24gbmFtZVxuICogQHBhcmFtIHtTdHJpbmd9IGFyZzEsIGFyZzIsIC4uLiB0aGUgbmFtZXMgb2YgZnVuY3Rpb24gcGFyYW1ldGVyc1xuICogQHBhcmFtIHtTdHJpbmd9IGZ1bmNCb2R5IGZ1bmN0aW9uIGJvZHlcbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBtYWtlRnVuY3Rpb24oYXJnMSwgYXJnMiwgZnVuY0JvZHkpIHtcbiAgICB2YXIgbmFtZSA9IHRoaXNcbiAgICAgICAgLCBjb3VudCA9IGFyZ3VtZW50cy5sZW5ndGggLSAxXG4gICAgICAgICwgZnVuY0JvZHkgPSBhcmd1bWVudHNbY291bnRdXG4gICAgICAgICwgZnVuY1xuICAgICAgICAsIGNvZGUgPSAnJztcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvdW50OyBpKyspXG4gICAgICAgIGNvZGUgKz0gJywgJyArIGFyZ3VtZW50c1tpXTtcbiAgICBjb2RlID0gWydmdW5jID0gZnVuY3Rpb24gJywgbmFtZSwgJygnLCBjb2RlLnNsaWNlKDIpLCAnKSB7XFxuJ1xuICAgICAgICAgICAgICAgICwgZnVuY0JvZHksICdcXG59J10uam9pbignJyk7XG4gICAgZXZhbChjb2RlKTtcbiAgICByZXR1cm4gZnVuYztcbn1cblxuXG4vKipcbiAqIENyZWF0ZXMgYSBmdW5jdGlvbiBhcyBhIHJlc3VsdCBvZiBwYXJ0aWFsIGZ1bmN0aW9uIGFwcGxpY2F0aW9uIHdpdGggdGhlIHBhc3NlZCBwYXJhbWV0ZXJzLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgRnVuY3Rpb24gdG8gYmUgYXBwbGllZFxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgQXJndW1lbnRzIGFmdGVyIHNlbGYgd2lsbCBiZSBwcmVwZW5kZWQgdG8gdGhlIG9yaWdpbmFsIGZ1bmN0aW9uIGNhbGwgd2hlbiB0aGUgcGFydGlhbCBmdW5jdGlvbiBpcyBjYWxsZWQuXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gcGFydGlhbCgpIHsgLy8gLCAuLi4gYXJndW1lbnRzXG4gICAgdmFyIGZ1bmMgPSB0aGlzO1xuICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIGZ1bmMuYXBwbHkodGhpcywgYXJncy5jb25jYXQoc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgfTtcbn1cblxuXG4vKipcbiAqIENyZWF0ZXMgYSBmdW5jdGlvbiBhcyBhIHJlc3VsdCBvZiBwYXJ0aWFsIGZ1bmN0aW9uIGFwcGxpY2F0aW9uIHdpdGggdGhlIHBhc3NlZCBwYXJhbWV0ZXJzLCBidXQgcGFyYW1ldGVycyBhcmUgYXBwZW5kZWQgb24gdGhlIHJpZ2h0LlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgRnVuY3Rpb24gdG8gYmUgYXBwbGllZFxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgQXJndW1lbnRzIGFmdGVyIHNlbGYgd2lsbCBiZSBhcHBlbmRlZCBvbiB0aGUgcmlnaHQgdG8gdGhlIG9yaWdpbmFsIGZ1bmN0aW9uIGNhbGwgd2hlbiB0aGUgcGFydGlhbCBmdW5jdGlvbiBpcyBjYWxsZWQuXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gcGFydGlhbFJpZ2h0KCkgeyAvLyAsIC4uLiBhcmd1bWVudHNcbiAgICB2YXIgZnVuYyA9IHRoaXM7XG4gICAgdmFyIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gZnVuYy5hcHBseSh0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cykuY29uY2F0KGFyZ3MpKTtcbiAgICB9O1xufVxuXG5cbi8qKlxuICogQ3JlYXRlcyBhIG1lbW9pemVkIHZlcnNpb24gb2YgdGhlIGZ1bmN0aW9uIHVzaW5nIHN1cHBsaWVkIGhhc2ggZnVuY3Rpb24gYXMga2V5LiBJZiB0aGUgaGFzaCBpcyBub3Qgc3VwcGxpZWQsIHVzZXMgaXRzIGZpcnN0IHBhcmFtZXRlciBhcyB0aGUgaGFzaC5cbiAqIFxuICogQHBhcmFtIHtGdW5jdGlvbn0gc2VsZiBmdW5jdGlvbiB0byBiZSBtZW1vaXplZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gaGFzaEZ1bmMgb3B0aW9uYWwgaGFzaCBmdW5jdGlvbiB0aGF0IGlzIHBhc3NlZCBhbGwgZnVuY3Rpb24gYXJndW1lbnRzIGFuZCBzaG91bGQgcmV0dXJuIGNhY2hlIGtleS5cbiAqIEBwYXJhbSB7SW50ZWdlcn0gbGltaXQgb3B0aW9uYWwgbWF4aW11bSBudW1iZXIgb2YgcmVzdWx0cyB0byBiZSBzdG9yZWQgaW4gdGhlIGNhY2hlLiAxMDAwIGJ5IGRlZmF1bHQuXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn0gbWVtb2l6ZWQgZnVuY3Rpb25cbiAqL1xuZnVuY3Rpb24gbWVtb2l6ZShoYXNoRnVuYywgbGltaXQpIHtcbiAgICB2YXIgZnVuYyA9IHRoaXM7XG4gICAgdmFyIGNhY2hlID0ge30sIGtleXNMaXN0ID0gW107XG4gICAgbGltaXQgPSBsaW1pdCB8fCAxMDAwO1xuXG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIga2V5ID0gaGFzaEZ1bmMgPyBoYXNoRnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpIDogYXJndW1lbnRzWzBdO1xuICAgICAgICBpZiAoY2FjaGUuaGFzT3duUHJvcGVydHkoa2V5KSlcbiAgICAgICAgICAgIHJldHVybiBjYWNoZVtrZXldO1xuXG4gICAgICAgIHZhciByZXN1bHQgPSBjYWNoZVtrZXldID0gZnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICBrZXlzTGlzdC5wdXNoKGtleSk7XG5cbiAgICAgICAgaWYgKGtleXNMaXN0Lmxlbmd0aCA+IGxpbWl0KVxuICAgICAgICAgICAgZGVsZXRlIGNhY2hlW2tleXNMaXN0LnNoaWZ0KCldO1xuXG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbn1cblxuXG4vKipcbiAqIERlbGF5cyBmdW5jdGlvbiBleGVjdXRpb24gYnkgYSBnaXZlbiB0aW1lIGluIG1pbGxpc2Vjb25kcy5cbiAqIFRoZSBjb250ZXh0IGluIGZ1bmN0aW9uIHdoZW4gaXQgaXMgZXhlY3V0ZWQgaXMgc2V0IHRvIGBudWxsYC5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzZWxmIGZ1bmN0aW9uIHRoYXQgZXhlY3V0aW9uIGhhcyB0byBiZSBkZWxheWVkXG4gKiBAcGFyYW0ge051bWJlcn0gd2FpdCBhcHByb3hpbWF0ZSBkYWxheSB0aW1lIGluIG1pbGxpc2Vjb25kc1xuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgb3B0aW9uYWwgYXJndW1lbnRzIHRoYXQgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uXG4gKi9cbmZ1bmN0aW9uIGRlbGF5KHdhaXQpIHsgLy8gLCBhcmd1bWVudHNcbiAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICByZXR1cm4gX2RlbGF5KHRoaXMsIHdhaXQsIGFyZ3MpO1xufVxuIFxuXG4vKipcbiAqIERlZmVycyBmdW5jdGlvbiBleGVjdXRpb24gKGV4ZWN1dGVzIGFzIHNvb24gYXMgZXhlY3V0aW9uIGxvb3AgYmVjb21lcyBmcmVlKVxuICogVGhlIGNvbnRleHQgaW4gZnVuY3Rpb24gd2hlbiBpdCBpcyBleGVjdXRlZCBpcyBzZXQgdG8gYG51bGxgLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgZnVuY3Rpb24gdGhhdCBleGVjdXRpb24gaGFzIHRvIGJlIGRlbGF5ZWRcbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIG9wdGlvbmFsIGFyZ3VtZW50cyB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvblxuICovXG5mdW5jdGlvbiBkZWZlcigpIHsgLy8gLCBhcmd1bWVudHNcbiAgICByZXR1cm4gX2RlbGF5KHRoaXMsIDEsIGFyZ3VtZW50cyk7XG59XG5cbmZ1bmN0aW9uIF9kZWxheShmdW5jLCB3YWl0LCBhcmdzLCBjb250ZXh0KSB7XG4gICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuYy5hcHBseS5iaW5kKGZ1bmMsIGNvbnRleHQgfHwgbnVsbCwgYXJncyksIHdhaXQpO1xufVxuXG4vKipcbiAqIFNhbWUgYXMgXy5kZWZlciwgdGFrZXMgZmlyc3QgYXJndW1lbnQgYXMgdGhlIGZ1bmN0aW9uIHRvIGJlIGRlZmVycmVkXG4gKi9cbnZhciBkZWZlckZ1bmMgPSBtYWtlUHJvdG9GdW5jdGlvbihkZWZlcik7XG5cbi8qKlxuICogRGVmZXJzIGZ1bmN0aW9uIGV4ZWN1dGlvbiBmb3IgYHRpbWVzYCB0aWNrcyAoZXhlY3V0ZXMgYWZ0ZXIgZXhlY3V0aW9uIGxvb3AgYmVjb21lcyBmcmVlIGB0aW1lc2AgdGltZXMpXG4gKiBUaGUgY29udGV4dCBpbiBmdW5jdGlvbiB3aGVuIGl0IGlzIGV4ZWN1dGVkIGlzIHNldCB0byBgbnVsbGAuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gc2VsZiBmdW5jdGlvbiB0aGF0IGV4ZWN1dGlvbiBoYXMgdG8gYmUgZGVsYXllZFxuICogQHBhcmFtIHtJbnRlZ2VyfSB0aWNrcyBudW1iZXIgb2YgdGltZXMgdG8gZGVmZXIgZXhlY3V0aW9uXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBvcHRpb25hbCBhcmd1bWVudHMgdGhhdCB3aWxsIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb25cbiAqL1xuZnVuY3Rpb24gZGVmZXJUaWNrcyh0aWNrcykgeyAvLyAsIGFyZ3VtZW50c1xuICAgIGlmICh0aWNrcyA8IDIpIHJldHVybiBkZWZlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHZhciBhcmdzID0gcmVwZWF0LmNhbGwoZGVmZXJGdW5jLCB0aWNrcyAtIDEpO1xuICAgIGFyZ3MgPSBhcmdzLmNvbmNhdCh0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cywgMSkpOyBcbiAgICByZXR1cm4gZGVmZXJGdW5jLmFwcGx5KG51bGwsIGFyZ3MpO1xufVxuXG5cbi8qKlxuICogV29ya3MgbGlrZSBfLmRlbGF5IGJ1dCBhbGxvd3MgdG8gZGVmZXIgbWV0aG9kIGNhbGwgb2YgYHNlbGZgIHdoaWNoIHdpbGwgYmUgdGhlIGZpcnN0IF8uZGVsYXlNZXRob2QgcGFyYW1ldGVyXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgb2JqZWN0IHRvIGRlbGF5IG1ldGhvZCBjYWxsIG9mXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufFN0cmluZ30gZnVuY09yTWV0aG9kTmFtZSBmdW5jdGlvbiBvciBuYW1lIG9mIG1ldGhvZFxuICogQHBhcmFtIHtOdW1iZXJ9IHdhaXQgYXBwcm94aW1hdGUgZGFsYXkgdGltZSBpbiBtaWxsaXNlY29uZHNcbiAqIEBwYXJhbSB7TGlzdH0gYXJndW1lbnRzIGFyZ3VtZW50cyB0byBwYXNzIHRvIG1ldGhvZFxuICovXG5mdW5jdGlvbiBkZWxheU1ldGhvZChmdW5jT3JNZXRob2ROYW1lLCB3YWl0KSB7IC8vICwgLi4uIGFyZ3VtZW50c1xuICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgIHJldHVybiBfZGVsYXlNZXRob2QodGhpcywgZnVuY09yTWV0aG9kTmFtZSwgd2FpdCwgYXJncyk7XG59XG5cblxuLyoqXG4gKiBXb3JrcyBsaWtlIF8uZGVmZXIgYnV0IGFsbG93cyB0byBkZWZlciBtZXRob2QgY2FsbCBvZiBgc2VsZmAgd2hpY2ggd2lsbCBiZSB0aGUgZmlyc3QgXy5kZWZlck1ldGhvZCBwYXJhbWV0ZXJcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBvYmplY3QgdG8gZGVmZXIgbWV0aG9kIGNhbGwgb2ZcbiAqIEBwYXJhbSB7RnVuY3Rpb258U3RyaW5nfSBmdW5jT3JNZXRob2ROYW1lIGZ1bmN0aW9uIG9yIG5hbWUgb2YgbWV0aG9kXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBhcmd1bWVudHMgdG8gcGFzcyB0byBtZXRob2RcbiAqL1xuZnVuY3Rpb24gZGVmZXJNZXRob2QoZnVuY09yTWV0aG9kTmFtZSkgeyAvLyAsIC4uLiBhcmd1bWVudHNcbiAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICByZXR1cm4gX2RlbGF5TWV0aG9kKHRoaXMsIGZ1bmNPck1ldGhvZE5hbWUsIDEsIGFyZ3MpO1xufVxuXG5mdW5jdGlvbiBfZGVsYXlNZXRob2Qob2JqZWN0LCBmdW5jT3JNZXRob2ROYW1lLCB3YWl0LCBhcmdzKSB7XG4gICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBmdW5jID0gdHlwZW9mIGZ1bmNPck1ldGhvZE5hbWUgPT0gJ3N0cmluZydcbiAgICAgICAgICAgICAgICAgICAgPyBvYmplY3RbZnVuY09yTWV0aG9kTmFtZV1cbiAgICAgICAgICAgICAgICAgICAgOiBmdW5jT3JNZXRob2ROYW1lO1xuICAgICAgICBmdW5jLmFwcGx5KG9iamVjdCwgYXJncyk7XG4gICAgfSwgd2FpdCk7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGZ1bmN0aW9uIHRoYXQgd2lsbCBleGVjdXRlIHRoZSBvcmlnaW5hbCBmdW5jdGlvbiBgd2FpdGAgbXMgYWZ0ZXIgaXQgaGFzIGJlZW4gY2FsbGVkXG4gKiBUaGUgY29udGV4dCBpbiBmdW5jdGlvbiB3aGVuIGl0IGlzIGV4ZWN1dGVkIGlzIHNldCB0byBgbnVsbGAuXG4gKiBBcmd1bWVudHMgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbiBhcmUgYXBwZW5kZWQgdG8gdGhlIGFyZ3VtZW50cyBwYXNzZWQgdG8gZGVsYXllZC5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzZWxmIGZ1bmN0aW9uIHdoaWNoIGV4ZWN1dGlvbiBoYXMgdG8gYmUgZGVmZXJyZWRcbiAqIEBwYXJhbSB7TnVtYmVyfSB3YWl0IGFwcHJveGltYXRlIGRhbGF5IHRpbWUgaW4gbWlsbGlzZWNvbmRzXG4gKiBAcGFyYW0ge0xpc3R9IGFyZ3VtZW50cyBvcHRpb25hbCBhcmd1bWVudHMgdGhhdCB3aWxsIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb25cbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBkZWxheWVkKHdhaXQpIHsgLy8sIC4uLiBhcmd1bWVudHNcbiAgICB2YXIgZnVuYyA9IHRoaXNcbiAgICAgICAgLCBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHJldHVybiBmdW5jdGlvbigpIHsgLy8gLi4uIGFyZ3VtZW50c1xuICAgICAgICB2YXIgcGFzc0FyZ3MgPSBhcmdzLmNvbmNhdChzbGljZS5jYWxsKGFyZ3VtZW50cykpO1xuICAgICAgICByZXR1cm4gX2RlbGF5KGZ1bmMsIHdhaXQsIHBhc3NBcmdzLCB0aGlzKTtcbiAgICB9O1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBmdW5jdGlvbiB0aGF0IHdpbGwgZXhlY3V0ZSB0aGUgb3JpZ2luYWwgZnVuY3Rpb24gb24gdGhlIG5leHQgdGljayBvbmNlIGl0IGhhcyBiZWVuIGNhbGxlZFxuICogVGhlIGNvbnRleHQgaW4gZnVuY3Rpb24gd2hlbiBpdCBpcyBleGVjdXRlZCBpcyBzZXQgdG8gYG51bGxgLlxuICogQXJndW1lbnRzIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24gYXJlIGFwcGVuZGVkIHRvIHRoZSBhcmd1bWVudHMgcGFzc2VkIHRvIGRlZmVycmVkLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgZnVuY3Rpb24gd2hpY2ggZXhlY3V0aW9uIGhhcyB0byBiZSBkZWZlcnJlZFxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgb3B0aW9uYWwgYXJndW1lbnRzIHRoYXQgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gZGVmZXJyZWQoKSB7IC8vLCAuLi4gYXJndW1lbnRzXG4gICAgdmFyIGZ1bmMgPSB0aGlzXG4gICAgICAgICwgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7IC8vIC4uLiBhcmd1bWVudHNcbiAgICAgICAgdmFyIHBhc3NBcmdzID0gYXJncy5jb25jYXQoc2xpY2UuY2FsbChhcmd1bWVudHMpKTtcbiAgICAgICAgcmV0dXJuIF9kZWxheShmdW5jLCAxLCBwYXNzQXJncywgdGhpcyk7XG4gICAgfTtcbn1cblxuXG4vKipcbiAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0IHdpbGwgY2FsbCBvcmlnaW5hbCBmdW5jdGlvbiBvbmNlIGl0IGhhcyBub3QgYmVlbiBjYWxsZWQgZm9yIGEgc3BlY2lmaWVkIHRpbWVcbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzZWxmIGZ1bmN0aW9uIHRoYXQgZXhlY3V0aW9uIGhhcyB0byBiZSBkZWxheWVkXG4gKiBAcGFyYW0ge051bWJlcn0gd2FpdCBhcHByb3hpbWF0ZSBkYWxheSB0aW1lIGluIG1pbGxpc2Vjb25kc1xuICogQHBhcmFtIHtCb29sZWFufSBpbW1lZGlhdGUgdHJ1ZSB0byBpbnZva2UgZnVuY2l0b24gaW1tZWRpYXRlbHkgYW5kIHRoZW4gaWdub3JlIGZvbGxvd2luZyBjYWxscyBmb3Igd2FpdCBtaWxsaXNlY29uZHNcbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBkZWJvdW5jZSh3YWl0LCBpbW1lZGlhdGUpIHtcbiAgICB2YXIgZnVuYyA9IHRoaXM7IC8vIGZpcnN0IHBhcmFtZXRlciBvZiBfLmRlYm91bmNlXG4gICAgdmFyIHRpbWVvdXQsIGFyZ3MsIGNvbnRleHQsIHRpbWVzdGFtcCwgcmVzdWx0O1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgY29udGV4dCA9IHRoaXM7IC8vIHN0b3JlIG9yaWdpbmFsIGNvbnRleHRcbiAgICAgICAgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgICAgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgICAgdmFyIGNhbGxOb3cgPSBpbW1lZGlhdGUgJiYgISB0aW1lb3V0O1xuICAgICAgICBpZiAoISB0aW1lb3V0KVxuICAgICAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQobGF0ZXIsIHdhaXQpO1xuICAgICAgICBpZiAoY2FsbE5vdylcbiAgICAgICAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG5cbiAgICAgICAgZnVuY3Rpb24gbGF0ZXIoKSB7XG4gICAgICAgICAgICB2YXIgbGFzdCA9IERhdGUubm93KCkgLSB0aW1lc3RhbXA7XG4gICAgICAgICAgICBpZiAobGFzdCA8IHdhaXQpXG4gICAgICAgICAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQobGF0ZXIsIHdhaXQgLSBsYXN0KTtcbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRpbWVvdXQgPSBudWxsO1xuICAgICAgICAgICAgICAgIGlmICghIGltbWVkaWF0ZSlcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGEgZnVuY3Rpb24sIHRoYXQsIHdoZW4gaW52b2tlZCwgd2lsbCBvbmx5IGJlIHRyaWdnZXJlZCBhdCBtb3N0IG9uY2UgZHVyaW5nIGEgZ2l2ZW4gd2luZG93IG9mIHRpbWUuIFxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgZnVuY3Rpb24gdGhhdCBleGVjdXRpb24gaGFzIHRvIGJlIGRlbGF5ZWRcbiAqIEBwYXJhbSB7TnVtYmVyfSB3YWl0IGFwcHJveGltYXRlIGRlbGF5IHRpbWUgaW4gbWlsbGlzZWNvbmRzXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBge2xlYWRpbmc6IGZhbHNlfWAgdG8gZGlzYWJsZSB0aGUgZXhlY3V0aW9uIG9uIHRoZSBsZWFkaW5nIGVkZ2VcbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiB0aHJvdHRsZSh3YWl0LCBvcHRpb25zKSB7XG4gICAgdmFyIGZ1bmMgPSB0aGlzOyAvLyBmaXJzdCBwYXJhbWV0ZXIgb2YgXy50aHJvdHRsZVxuICAgIHZhciBjb250ZXh0LCBhcmdzLCByZXN1bHQ7XG4gICAgdmFyIHRpbWVvdXQgPSBudWxsO1xuICAgIHZhciBwcmV2aW91cyA9IDA7XG4gICAgb3B0aW9ucyB8fCAob3B0aW9ucyA9IHt9KTtcblxuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIG5vdyA9IERhdGUubm93KCk7XG4gICAgICAgIGlmICghcHJldmlvdXMgJiYgb3B0aW9ucy5sZWFkaW5nID09PSBmYWxzZSkgcHJldmlvdXMgPSBub3c7XG4gICAgICAgIHZhciByZW1haW5pbmcgPSB3YWl0IC0gKG5vdyAtIHByZXZpb3VzKTtcbiAgICAgICAgY29udGV4dCA9IHRoaXM7XG4gICAgICAgIGFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICAgIGlmIChyZW1haW5pbmcgPD0gMCkge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICAgICAgdGltZW91dCA9IG51bGw7XG4gICAgICAgICAgICBwcmV2aW91cyA9IG5vdztcbiAgICAgICAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgICAgIH0gZWxzZSBpZiAoIXRpbWVvdXQgJiYgb3B0aW9ucy50cmFpbGluZyAhPT0gZmFsc2UpXG4gICAgICAgICAgICB0aW1lb3V0ID0gc2V0VGltZW91dChsYXRlciwgcmVtYWluaW5nKTtcblxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiBsYXRlcigpIHtcbiAgICAgICAgcHJldmlvdXMgPSBvcHRpb25zLmxlYWRpbmcgPT09IGZhbHNlID8gMCA6IERhdGUubm93KCk7XG4gICAgICAgIHRpbWVvdXQgPSBudWxsO1xuICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MpO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIENhbGwgcGFzc2VkIGZ1bmN0aW9uIG9ubHkgb25jZVxuICogQHJldHVybiB7RnVuY3Rpb259IHNlbGZcbiAqL1xuZnVuY3Rpb24gb25jZSgpIHtcbiAgICB2YXIgZnVuYyA9IHRoaXNcbiAgICAgICAgLCByYW4gPSBmYWxzZVxuICAgICAgICAsIG1lbW87XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAocmFuKSByZXR1cm4gbWVtbztcbiAgICAgICAgcmFuID0gdHJ1ZTtcbiAgICAgICAgbWVtbyA9IGZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgZnVuYyA9IG51bGw7XG4gICAgICAgIHJldHVybiBtZW1vO1xuICAgIH07XG59XG5cblxuLyoqXG4gKiBFeGVjdXRlIGEgZnVuY3Rpb24gd2hlbiB0aGUgY29uZGl0aW9uIGZ1bmN0aW9uIHJldHVybnMgYSB0cnV0aHkgdmFsdWVcbiAqIGl0IHJ1bnMgdGhlIGNvbmRpdGlvbiBmdW5jdGlvbiBldmVyeSBgY2hlY2tJbnRlcnZhbGAgbWlsbGlzZWNvbmRzIChkZWZhdWx0IDUwKVxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHNlbGYgZnVuY3Rpb246IGlmIGl0IHJldHVybnMgdHJ1ZSB0aGUgY2FsbGJhY2sgaXMgZXhlY3V0ZWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIHJ1bnMgd2hlbiB0aGUgY29uZGl0aW9uIGlzIHRydWVcbiAqIEBwYXJhbSB7TnVtYmVyfSBtYXhUaW1lb3V0IHRpbWVvdXQgYmVmb3JlIGdpdmluZyB1cCAodGltZSBpbiBtaWxsaXNlY29uZHMpXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aW1lZE91dEZ1bmMgYSBmdW5jdGlvbiBjYWxsZWQgaWYgdGltZW91dCBpcyByZWFjaGVkXG4gKiBAcGFyYW0ge051bWJlcn0gY2hlY2tJbnRlcnZhbCB0aW1lIGludGVydmFsIHdoZW4geW91IHJ1biB0aGUgY29uZGl0aW9uIGZ1bmN0aW9uICh0aW1lIGluIG1pbGxpc2Vjb25kcyksIGRlZmF1bHQgNTAgbXNcbiAqL1xuZnVuY3Rpb24gd2FpdEZvcihjYWxsYmFjaywgbWF4VGltZW91dCwgdGltZWRPdXRGdW5jLCBjaGVja0ludGVydmFsKXtcbiAgICB2YXIgc3RhcnQgPSBEYXRlLm5vdygpO1xuICAgIHZhciBjb25kaXRpb24gPSB0aGlzO1xuICAgIGNoZWNrSW50ZXJ2YWwgPSBjaGVja0ludGVydmFsIHx8IDUwO1xuICAgIHZhciBpbnRlcnZhbCA9IHNldEludGVydmFsKHRlc3RDb25kaXRpb24sIGNoZWNrSW50ZXJ2YWwpO1xuXG4gICAgZnVuY3Rpb24gdGVzdENvbmRpdGlvbigpIHtcbiAgICAgICAgaWYgKGNvbmRpdGlvbigpKSBjYWxsYmFjaygpO1xuICAgICAgICBlbHNlIGlmIChEYXRlLm5vdygpIC0gc3RhcnQgPj0gbWF4VGltZW91dClcbiAgICAgICAgICAgIHRpbWVkT3V0RnVuYyAmJiB0aW1lZE91dEZ1bmMoKTtcbiAgICAgICAgZWxzZSByZXR1cm47XG4gICAgICAgIGNsZWFySW50ZXJ2YWwoaW50ZXJ2YWwpO1xuICAgIH07XG59XG5cblxuLyoqXG4gKiByZXR1cm5zIHRoZSBmdW5jdGlvbiB0aGF0IG5lZ2F0ZXMgKCEgb3BlcmF0b3IpIHRoZSByZXN1bHQgb2YgdGhlIG9yaWdpbmFsIGZ1bmN0aW9uXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzZWxmIGZ1bmN0aW9uIHRvIG5lZ2F0ZVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIG5vdCgpIHtcbiAgICB2YXIgZnVuYyA9IHRoaXM7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gIWZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9O1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIC0gW2lzTnVtZXJpY10oI2lzTnVtZXJpYylcbiAqL1xudmFyIG51bWJlck1ldGhvZHMgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBpc051bWVyaWM6IGlzTnVtZXJpY1xufTtcblxuXG4vKipcbiAqIEZ1bmN0aW9uIHRvIHRlc3QgaWYgYSB2YWx1ZSBpcyBudW1lcmljXG4gKlxuICogQHBhcmFtIHtBbnl9IHNlbGYgdmFsdWUgdG8gYmUgdGVzdGVkXG4gKiBAcmV0dXJuIHtCb29sZWFufSB0cnVlIGlmIGl0IGlzIGEgbnVtZXJpYyB2YWx1ZVxuICovXG5mdW5jdGlvbiBpc051bWVyaWMoKSB7XG4gICAgcmV0dXJuICFpc05hTihwYXJzZUZsb2F0KHRoaXMpKSAmJiBpc0Zpbml0ZSh0aGlzKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi91dGlscycpO1xuXG5cbi8qKlxuICogLSBbZXh0ZW5kXSgjZXh0ZW5kKVxuICogLSBbY2xvbmVdKCNjbG9uZSlcbiAqIC0gW2RlZmluZVByb3BlcnR5XSgjZGVmaW5lUHJvcGVydHkpXG4gKiAtIFtkZWZpbmVQcm9wZXJ0aWVzXSgjZGVmaW5lUHJvcGVydGllcylcbiAqIC0gW2RlZXBFeHRlbmRdKCNkZWVwRXh0ZW5kKVxuICogLSBbZGVlcENsb25lXSgjZGVlcENsb25lKVxuICogLSBba2V5c10oI2tleXMpXG4gKiAtIFthbGxLZXlzXSgjYWxsS2V5cylcbiAqIC0gW3ZhbHVlc10oI3ZhbHVlcylcbiAqIC0gW2tleU9mXSgja2V5T2YpXG4gKiAtIFthbGxLZXlzT2ZdKCNhbGxLZXlzT2YpXG4gKiAtIFtlYWNoS2V5XSgjZWFjaEtleSlcbiAqIC0gW21hcEtleXNdKCNtYXBLZXlzKVxuICogLSBbcmVkdWNlS2V5c10oI3JlZHVjZUtleXMpXG4gKiAtIFtmaWx0ZXJLZXlzXSgjZmlsdGVyS2V5cylcbiAqIC0gW3NvbWVLZXldKCNzb21lS2V5KVxuICogLSBbZXZlcnlLZXldKCNldmVyeUtleSlcbiAqIC0gW2ZpbmRWYWx1ZV0oI2ZpbmRWYWx1ZSlcbiAqIC0gW2ZpbmRLZXldKCNmaW5kS2V5KVxuICogLSBbcGlja0tleXNdKCNwaWNrS2V5cylcbiAqIC0gW29taXRLZXlzXSgjb21pdEtleXMpXG4gKiAtIFtpc0VxdWFsXSgjaXNFcXVhbClcbiAqIC0gW2lzTm90XSgjaXNOb3QpXG4gKlxuICogQWxsIHRoZXNlIG1ldGhvZHMgY2FuIGJlIFtjaGFpbmVkXShwcm90by5qcy5odG1sI1Byb3RvKVxuICovXG52YXIgb2JqZWN0TWV0aG9kcyA9IG1vZHVsZS5leHBvcnRzID0ge1xuICAgIGV4dGVuZDogZXh0ZW5kLFxuICAgIGNsb25lOiBjbG9uZSxcbiAgICBkZWZpbmVQcm9wZXJ0eTogZGVmaW5lUHJvcGVydHksXG4gICAgZGVmaW5lUHJvcGVydGllczogZGVmaW5lUHJvcGVydGllcyxcbiAgICBkZWVwRXh0ZW5kOiBkZWVwRXh0ZW5kLFxuICAgIGRlZXBDbG9uZTogZGVlcENsb25lLFxuICAgIGtleXM6IGtleXMsXG4gICAgYWxsS2V5czogYWxsS2V5cyxcbiAgICB2YWx1ZXM6IHZhbHVlcyxcbiAgICBrZXlPZjoga2V5T2YsXG4gICAgYWxsS2V5c09mOiBhbGxLZXlzT2YsXG4gICAgZWFjaEtleTogZWFjaEtleSxcbiAgICBtYXBLZXlzOiBtYXBLZXlzLFxuICAgIHJlZHVjZUtleXM6IHJlZHVjZUtleXMsXG4gICAgZmlsdGVyS2V5czogZmlsdGVyS2V5cyxcbiAgICBzb21lS2V5OiBzb21lS2V5LFxuICAgIGV2ZXJ5S2V5OiBldmVyeUtleSxcbiAgICBwaWNrS2V5czogcGlja0tleXMsXG4gICAgb21pdEtleXM6IG9taXRLZXlzLFxuICAgIGlzRXF1YWw6IGlzRXF1YWwsXG4gICAgaXNOb3Q6IGlzTm90XG59O1xuXG5cbi8qKlxuICogIyMjI1Byb3BlcnR5IGRlc2NyaXB0b3IgY29uc3RhbnRzIyMjI1xuICogVGhlIHN1bSBvZiB0aGVzZSBjb25zdGFudHMgY2FuIGJlIHVzZWQgYXMgbGFzdCBwYXJhbWV0ZXIgb2YgZGVmaW5lUHJvcGVydHkgYW5kIGRlZmluZVByb3BlcnRpZXMgdG8gZGV0ZXJtaW5lIHR5cGVzIG9mIHByb3BlcnRpZXMuXG4gKi9cbnZhciBjb25zdGFudHMgPSB7XG4gICAgRU5VTUVSQUJMRTogMSxcbiAgICBFTlVNOiAxLFxuICAgIENPTkZJR1VSQUJMRTogMixcbiAgICBDT05GOiAyLFxuICAgIFdSSVRBQkxFOiA0LFxuICAgIFdSSVQ6IDRcbn07XG5cbmRlZmluZVByb3BlcnR5LmNhbGwob2JqZWN0TWV0aG9kcywgJ19jb25zdGFudHMnLCBjb25zdGFudHMpO1xuXG5cbi8qKlxuICogQW5hbG9ndWUgb2YgRVM2IFtBcnJheSBfX2ZpbmRfXyBtZXRob2RdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0FycmF5L2ZpbmQpLlxuICogUmV0dXJucyB0aGUgdmFsdWUgb2Ygb2JqZWN0IHByb3BlcnR5IHRoYXQgcGFzc2VzIGNhbGxiYWNrIHRlc3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgb2JqZWN0IHRvIHNlYXJjaCBpblxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgc2hvdWxkIHJldHVybiBgdHJ1ZWAgZm9yIGl0ZW0gdG8gcGFzcyB0aGUgdGVzdCwgcGFzc2VkIGB2YWx1ZWAsIGBrZXlgIGFuZCBgc2VsZmAgYXMgcGFyYW1ldGVyc1xuICogQHBhcmFtIHtPYmplY3R9IHRoaXNBcmcgb3B0aW9uYWwgY29udGV4dCAoYHRoaXNgKSBvZiBjYWxsYmFjayBjYWxsXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIEFuIG9wdGlvbmFsIGB0cnVlYCB0byBpdGVyYXRlIGVudW1lcmFibGUgcHJvcGVydGllcyBvbmx5LlxuICogQHJldHVybiB7QW55fVxuICovXG5vYmplY3RNZXRob2RzLmZpbmRWYWx1ZSA9IHV0aWxzLm1ha2VGaW5kTWV0aG9kKGVhY2hLZXksICd2YWx1ZScpO1xuXG5cbi8qKlxuICogQW5hbG9ndWUgb2YgRVM2IFtBcnJheSBfX2ZpbmRJbmRleF9fIG1ldGhvZF0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvZmluZEluZGV4KS5cbiAqIFJldHVybnMgdGhlIGtleSBvZiBvYmplY3QgcHJvcGVydHkgdGhhdCBwYXNzZXMgY2FsbGJhY2sgdGVzdC4gUmV0dXJucyBgdW5kZWZpbmVkYCBpZiBub3QgZm91bmQgKHVubGlrZSBgZmluZEluZGV4YCwgdGhhdCByZXR1cm5zIC0xIGluIHRoaXMgY2FzZSkuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgb2JqZWN0IHRvIHNlYXJjaCBpblxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgc2hvdWxkIHJldHVybiBgdHJ1ZWAgZm9yIGl0ZW0gdG8gcGFzcyB0aGUgdGVzdCwgcGFzc2VkIGB2YWx1ZWAsIGBrZXlgIGFuZCBgc2VsZmAgYXMgcGFyYW1ldGVyc1xuICogQHBhcmFtIHtPYmplY3R9IHRoaXNBcmcgb3B0aW9uYWwgY29udGV4dCAoYHRoaXNgKSBvZiBjYWxsYmFjayBjYWxsXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIEFuIG9wdGlvbmFsIGB0cnVlYCB0byBpdGVyYXRlIGVudW1lcmFibGUgcHJvcGVydGllcyBvbmx5LlxuICogQHJldHVybiB7SW50ZWdlcn1cbiAqL1xub2JqZWN0TWV0aG9kcy5maW5kS2V5ID0gdXRpbHMubWFrZUZpbmRNZXRob2QoZWFjaEtleSwgJ2tleScpO1xuXG5cbi8qKlxuICogRXh0ZW5kcyBvYmplY3QgYHNlbGZgIHdpdGggdGhlIHByb3BlcnRpZXMgb2YgdGhlIG9iamVjdCBgb2JqYCBjb3B5aW5nIGFsbCBvd24gcHJvcGVydGllcyAobm90IHRob3NlIGluaGVyaXRlZCB2aWEgcHJvdG90eXBlIGNoYWluKSwgaW5jbHVkaW5nIG5vbi1lbnVtZXJhYmxlIHByb3BlcnRpZXMgKHVubGVzcyBgb25seUVudW1lcmFibGVgIGlzIHRydXRoeSkuXG4gKiBDcmVhdGVkIHByb3BlcnRpZXMgd2lsbCBoYXZlIHRoZSBzYW1lIGRlc2NyaXB0b3JzIGFzIHRoZSBwcm9wZXJ0aXMgb2YgYG9iamAuXG4gKiBSZXR1cm5zIGBzZWxmYCB0byBhbGxvdyBjaGFpbmluZyB3aXRoIG90aGVyIGZ1bmN0aW9ucy5cbiAqIENhbiBiZSB1c2VkIHdpdGggZnVuY3Rpb25zLCB0byBjb3B5IGNsYXNzIG1ldGhvZHMsIGUuZy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3QgdG8gYmUgZXh0ZW5kZWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogQW4gb2JqZWN0IHdoaWNoIHByb3BlcnRpZXMgd2lsbCBiZSBjb3BpZWQgdG8gc2VsZlxuICogQHBhcmFtIHtCb29sZWFufSBvbmx5RW51bWVyYWJsZSBPcHRpb25hbCBmbGFnIHRvIHByZXZlbnQgY29weWluZyBub24tZW51bWVyYWJsZSBwcm9wZXJ0aWVzLCBgZmFsc2VgIGJ5IGRlZmF1bHRcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZXh0ZW5kKG9iaiwgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgZGVzY3JpcHRvcnMgPSB7fTtcblxuICAgIGVhY2hLZXkuY2FsbChvYmosIGZ1bmN0aW9uKHZhbHVlLCBwcm9wKSB7XG4gICAgICAgIGRlc2NyaXB0b3JzW3Byb3BdID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihvYmosIHByb3ApO1xuICAgIH0sIHRoaXMsIG9ubHlFbnVtZXJhYmxlKTtcblxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIGRlc2NyaXB0b3JzKTtcblxuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogTWFrZXMgYSBzaGFsbG93IGNsb25lIG9mIG9iamVjdCBgb2JqYCBjcmVhdGluZyBhbiBpbnN0YW5jZSBvZiB0aGUgc2FtZSBjbGFzczsgdGhlIHByb3BlcnRpZXMgd2lsbCBoYXZlIHRoZSBzYW1lIGRlc2NyaXB0b3JzLlxuICogVG8gY2xvbmUgYW4gYXJyYXkgdXNlXG4gKiBgYGBcbiAqIHZhciBjbG9uZWRBcnJheSA9IFtdLmNvbmNhdChhcnIpO1xuICogYGBgXG4gKiBUaGlzIGZ1bmN0aW9uIHNob3VsZCBub3QgYmUgdXNlZCB0byBjbG9uZSBhbiBhcnJheSwgYmVjYXVzZSBpdCBpcyBpbmVmZmljaWVudC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3QgdG8gYmUgY2xvbmVkXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIGNsb25lKCkge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMpKSByZXR1cm4gdGhpcy5zbGljZSgpO1xuICAgIGlmICh0aGlzIGluc3RhbmNlb2YgRGF0ZSkgcmV0dXJuIG5ldyBEYXRlKHRoaXMpO1xuICAgIGlmICh0aGlzIGluc3RhbmNlb2YgUmVnRXhwKSByZXR1cm4gbmV3IFJlZ0V4cCh0aGlzKTtcbiAgICB2YXIgY2xvbmVkT2JqZWN0ID0gT2JqZWN0LmNyZWF0ZSh0aGlzLmNvbnN0cnVjdG9yLnByb3RvdHlwZSk7XG4gICAgZXh0ZW5kLmNhbGwoY2xvbmVkT2JqZWN0LCB0aGlzKTtcbiAgICByZXR1cm4gY2xvbmVkT2JqZWN0O1xufVxuXG5cbi8qKlxuICogU3ludGF4IHN1Z2FyIHRvIHNob3J0ZW4gdXNhZ2Ugb2YgYE9iamVjdC5kZWZpbmVQcm9wZXJ0eWAuXG4gKiBUaGUgc2ltcGxlc3QgdXNhZ2UgKHRvIGFkZCBub24tZW51bWVyYWJsZSwgbm9uLWNvbmZpZ3VyYWJsZSwgbm9uLXdyaXRhYmxlIHByb3BlcnR5KTpcbiAqIGBgYFxuICogXy5kZWZpbmVQcm9wZXJ0eShvYmosICdrZXknLCB2YWx1ZSk7XG4gKiBgYGBcbiAqXG4gKiBUbyBkZWZpbmUgc29tZSBvdGhlciBwcm9wZXJ0aWVzIHVzZSBzdW0gb2YgdGhlIGZsYWdzIGBfLkVOVU1FUkFCTEVgIChvciBgXy5FTlVNYCksIGBfLkNPTkZJR1VSQUJMRWAgKG9yIGBfLkNPTkZgKSBhbmQgYF8uV1JJVEFCTEVgIChvciBgXy5XUklUYCk6XG4gKiBgYGBcbiAqIF8uZGVmaW5lUHJvcGVydHkob2JqLCAna2V5JywgdmFsdWUsIF8uRU5VTSArIF8uV1JJVCk7XG4gKiBgYGBcbiAqIFJldHVybnMgYHNlbGZgLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZWxmIEFuIG9iamVjdCB0byBhZGQgYSBwcm9wZXJ0eSB0b1xuICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5TmFtZSB0aGUgbmFtZSBvZiB0aGUgcHJvcGVydHkgdGhhdCB3aWxsIGJlIGFkZGVkXG4gKiBAcGFyYW0ge0FueX0gdmFsdWUgdGhlIHZhbHVlIG9mIGFkZGVkIHByb3BlcnR5XG4gKiBAcGFyYW0ge0ludGVnZXJ9IGRlY3JpcHRvckZsYWdzIGJpdCBtYXNrIG9mIHByb3BlcnR5IGRlc2NyaXB0b3IgcHJvcGVydGllcyBjb21wb3NlZCBmcm9tIGBfLkVOVU1FUkFCTEVgIChvciBgXy5FTlVNYCksIGBfLkNPTkZJR1VSQUJMRWAgKG9yIGBfLkNPTkZgKSBhbmQgYF8uV1JJVEFCTEVgIChvciBgXy5XUklUYClcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZGVmaW5lUHJvcGVydHkocHJvcGVydHlOYW1lLCB2YWx1ZSwgZGVjcmlwdG9yRmxhZ3MpIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgcHJvcGVydHlOYW1lLFxuICAgICAgICBfZ2V0RGVzY3JpcHRvcih2YWx1ZSwgZGVjcmlwdG9yRmxhZ3MpKTtcbiAgICByZXR1cm4gdGhpcztcbn1cblxuXG5mdW5jdGlvbiBfZ2V0RGVzY3JpcHRvcih2YWx1ZSwgZGVjcmlwdG9yRmxhZ3MpIHtcbiAgICB2YXIgZGVzY3JpcHRvciA9IHsgdmFsdWU6IHZhbHVlIH07XG4gICAgaWYgKGRlY3JpcHRvckZsYWdzKVxuICAgICAgICBleHRlbmQuY2FsbChkZXNjcmlwdG9yLCB7XG4gICAgICAgICAgICBlbnVtZXJhYmxlOiAhISAoZGVjcmlwdG9yRmxhZ3MgJiBjb25zdGFudHMuRU5VTUVSQUJMRSksXG4gICAgICAgICAgICBjb25maWd1cmFibGU6ICEhIChkZWNyaXB0b3JGbGFncyAmIGNvbnN0YW50cy5DT05GSUdVUkFCTEUpLFxuICAgICAgICAgICAgd3JpdGFibGU6ICEhIChkZWNyaXB0b3JGbGFncyAmIGNvbnN0YW50cy5XUklUQUJMRSlcbiAgICAgICAgfSk7XG5cbiAgICByZXR1cm4gZGVzY3JpcHRvcjtcbn1cblxuXG4vKipcbiAqIFN5bnRheCBzdWdhciB0byBzaG9ydGVuIHVzYWdlIG9mIGBPYmplY3QuZGVmaW5lUHJvcGVydGllc2AuXG4gKiBUaGUgc2ltcGxlc3QgdXNhZ2UgKHRvIGFkZCBub24tZW51bWVyYWJsZSwgbm9uLWNvbmZpZ3VyYWJsZSwgbm9uLXdyaXRhYmxlIHByb3BlcnRpZXMpOlxuICogYGBgXG4gKiBfLmRlZmluZVByb3BlcnRpZXMob2JqLCB7XG4gKiAgICAga2V5MTogdmFsdWUxLFxuICogICAgIGtleTI6IHZhbHVlMlxuICogfSk7XG4gKiBgYGBcbiAqIFRvIGRlZmluZSBzb21lIG90aGVyIHByb3BlcnRpZXMgdXNlIHN1bSBvZiB0aGUgZmxhZ3MgYF8uRU5VTUVSQUJMRWAgKG9yIGBfLkVOVU1gKSwgYF8uQ09ORklHVVJBQkxFYCAob3IgYF8uQ09ORmApIGFuZCBgXy5XUklUQUJMRWAgKG9yIGBfLldSSVRgKTpcbiAqIGBgYFxuICogXy5kZWZpbmVQcm9wZXJ0aWVzKG9iaiwge1xuICogICAgIGtleTE6IHZhbHVlMSxcbiAqICAgICBrZXkyOiB2YWx1ZTJcbiAqIH0sIF8uRU5VTSArIF8uV1JJVCk7XG4gKiBgYGBcbiAqIFJldHVybnMgYHNlbGZgLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZWxmIEFuIG9iamVjdCB0byBhZGQgYSBwcm9wZXJ0eSB0b1xuICogQHBhcmFtIHtPYmplY3R9IHByb3BlcnR5VmFsdWVzIEEgbWFwIG9mIGtleXMgYW5kIHZhbHVlcyBvZiBwcm9wZXJ0aWVzIHRoYXR3aWxsIGJlIGFkZGVkLiBUaGUgZGVzY3JpcHRvcnMgb2YgcHJvcGVydGllcyB3aWxsIGJlIGRlZmluZWQgYnkgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzLlxuICogQHBhcmFtIHtJbnRlZ2VyfSBkZWNyaXB0b3JGbGFncyBiaXQgbWFzayBvZiBwcm9wZXJ0eSBkZXNjcmlwdG9yIHByb3BlcnRpZXMgY29tcG9zZWQgZnJvbSBgXy5FTlVNRVJBQkxFYCAob3IgYF8uRU5VTWApLCBgXy5DT05GSUdVUkFCTEVgIChvciBgXy5DT05GYCkgYW5kIGBfLldSSVRBQkxFYCAob3IgYF8uV1JJVGApXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIGRlZmluZVByb3BlcnRpZXMocHJvcGVydHlWYWx1ZXMsIGRlY3JpcHRvckZsYWdzKSB7XG4gICAgdmFyIGRlc2NyaXB0b3JzID0gbWFwS2V5cy5jYWxsKHByb3BlcnR5VmFsdWVzLCBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICByZXR1cm4gX2dldERlc2NyaXB0b3IodmFsdWUsIGRlY3JpcHRvckZsYWdzKTtcbiAgICB9LCB0cnVlKTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh0aGlzLCBkZXNjcmlwdG9ycyk7XG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBFeHRlbmRzIG9iamVjdCBgc2VsZmAgd2l0aCBwcm9wZXJ0aWVzIG9mIGBvYmpgIHRvIGFueSBkZXB0aCwgd2l0aG91dCBvdmVyd3J0aXRpbmcgZXhpc3Rpbmcgb2JqZWN0IHByb3BlcnRpZXMgb2YgYHNlbGZgIHdpdGggb2JqZWN0IHByb3BlcnRpZXMgb2YgYG9iamAuXG4gKiBTY2FsYXIgcHJvcGVydGllcyBvZiBgb2JqYCB3aWxsIG92ZXJ3cml0ZSBwcm9wZXJ0aWVzIG9mIGBzZWxmYC4gU2NhbGFyIHBvcnBlcnRpZXMgb2YgYHNlbGZgIHdpbGwgYWxzbyBiZSBvdmVyd3JpdHRlbi5cbiAqIENvcnJlY3RseSB3b3JrcyB3aXRoIHJlY3Vyc2l2ZSBvYmplY3RzLlxuICogVXNhZ2U6XG4gKiBgYGBcbiAqIHZhciBvYmogPSB7XG4gKiAgICAgaW5uZXI6IHtcbiAqICAgICAgICAgYTogMVxuICogICAgIH1cbiAqIH07XG4gKlxuICogXy5kZWVwRXh0ZW5kKG9iaiwge1xuICogICAgIGlubmVyOiB7XG4gKiAgICAgICAgIGI6IDJcbiAqICAgICB9XG4gKiB9KTtcbiAqXG4gKiBhc3NlcnQuZGVlcEVxdWFsKG9iaiwge1xuICogICAgIGlubmVyOiB7XG4gKiAgICAgICAgIGE6IDEsXG4gKiAgICAgICAgIGI6IDJcbiAqICAgICB9XG4gKiB9KTsgLy8gYXNzZXJ0IHBhc3Nlc1xuICogYGBgXG4gKiBSZXR1cm5zIGBzZWxmYC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3QgdG8gYmUgZXh0ZW5kZWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogQW4gb2JqZWN0IHdpdGggcHJvcGVydGllcyB0byBjb3B5IHRvXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIE9wdGlvbmFsIGB0cnVlYCB0byB1c2Ugb25seSBlbnVtZXJhYmxlIHByb3BlcnRpZXNcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZGVlcEV4dGVuZChvYmosIG9ubHlFbnVtZXJhYmxlKSB7XG4gICAgcmV0dXJuIF9leHRlbmRUcmVlKHRoaXMsIG9iaiwgb25seUVudW1lcmFibGUsIFtdKTtcbn1cblxuXG5mdW5jdGlvbiBfZXh0ZW5kVHJlZShzZWxmTm9kZSwgb2JqTm9kZSwgb25seUVudW1lcmFibGUsIG9ialRyYXZlcnNlZCkge1xuICAgIGlmIChvYmpUcmF2ZXJzZWQuaW5kZXhPZihvYmpOb2RlKSA+PSAwKSByZXR1cm47IC8vIG5vZGUgYWxyZWFkeSB0cmF2ZXJzZWQsIG9iaiBoYXMgcmVjdXJzaW9uXG5cbiAgICAvLyBzdG9yZSBub2RlIHRvIHJlY29nbmlzZSByZWN1cnNpb25cbiAgICBvYmpUcmF2ZXJzZWQucHVzaChvYmpOb2RlKTtcblxuICAgIHZhciBsb29wID0gQXJyYXkuaXNBcnJheShvYmpOb2RlKSA/IEFycmF5LnByb3RvdHlwZS5mb3JFYWNoIDogZWFjaEtleTtcblxuICAgIGxvb3AuY2FsbChvYmpOb2RlLCBmdW5jdGlvbih2YWx1ZSwgcHJvcCkge1xuICAgICAgICB2YXIgZGVzY3JpcHRvciA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3Iob2JqTm9kZSwgcHJvcCk7XG4gICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCcgJiYgdmFsdWUgIT0gbnVsbFxuICAgICAgICAgICAgICAgICYmICEgKHZhbHVlIGluc3RhbmNlb2YgUmVnRXhwKSAmJiAhICh2YWx1ZSBpbnN0YW5jZW9mIERhdGUpKSB7XG4gICAgICAgICAgICBpZiAoISAoc2VsZk5vZGUuaGFzT3duUHJvcGVydHkocHJvcClcbiAgICAgICAgICAgICAgICAgICAgJiYgdHlwZW9mIHNlbGZOb2RlW3Byb3BdID09ICdvYmplY3QnICYmIHNlbGZOb2RlW3Byb3BdICE9IG51bGwpKVxuICAgICAgICAgICAgICAgIHNlbGZOb2RlW3Byb3BdID0gKEFycmF5LmlzQXJyYXkodmFsdWUpKSA/IFtdIDoge307XG4gICAgICAgICAgICBfZXh0ZW5kVHJlZShzZWxmTm9kZVtwcm9wXSwgdmFsdWUsIG9ubHlFbnVtZXJhYmxlLCBvYmpUcmF2ZXJzZWQpO1xuICAgICAgICB9IGVsc2VcbiAgICAgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShzZWxmTm9kZSwgcHJvcCwgZGVzY3JpcHRvcik7XG4gICAgfSwgdGhpcywgb25seUVudW1lcmFibGUpO1xuXG4gICAgcmV0dXJuIHNlbGZOb2RlO1xufVxuXG5cbi8qKlxuICogQ2xvbmVzIGFsbCBvYmplY3QgdHJlZS4gQ2xhc3Mgb2Ygb3JpZ2luYWwgb2JqZWN0IGlzIG5vdCBwcmVzZXJ2ZWQuIFJldHVybnMgYHNlbGZgXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgQW4gb2JqZWN0IHRvIGJlIGV4dGVuZGVkXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIE9wdGlvbmFsIGB0cnVlYCB0byB1c2Ugb25seSBlbnVtZXJhYmxlIHByb3BlcnRpZXNcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZGVlcENsb25lKG9ubHlFbnVtZXJhYmxlKSB7XG4gICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBEYXRlKSByZXR1cm4gbmV3IERhdGUodGhpcyk7XG4gICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBSZWdFeHApIHJldHVybiBuZXcgUmVnRXhwKHRoaXMpO1xuICAgIHZhciBjbG9uZWRPYmplY3QgPSBBcnJheS5pc0FycmF5KHRoaXMpID8gW10gOiB7fTtcbiAgICBkZWVwRXh0ZW5kLmNhbGwoY2xvbmVkT2JqZWN0LCB0aGlzLCBvbmx5RW51bWVyYWJsZSk7XG4gICAgcmV0dXJuIGNsb25lZE9iamVjdDtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgYXJyYXkgb2YgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9mIHRoZSBvYmplY3RcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBvYmplY3QgdG8gcmV0dXJuIGtleXMgb2ZcbiAqIEByZXR1cm4ge0FycmF5fVxuICovXG5mdW5jdGlvbiBrZXlzKCkge1xuICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzKTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgYXJyYXkgb2YgdmFsdWVzIG9mIHRoZSBvYmplY3QncyBrZXlzXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgb2JqZWN0IHRvIHJldHVybiB2YWx1ZXMgZnJvbVxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbmZ1bmN0aW9uIHZhbHVlcyhvbmx5RW51bWVyYWJsZSkge1xuICAgIHZhciBwcm9wZXJ0aWVzID0gb25seUVudW1lcmFibGVcbiAgICAgICAgICAgICAgICA/IE9iamVjdC5rZXlzKHRoaXMpXG4gICAgICAgICAgICAgICAgOiBhbGxLZXlzLmNhbGwodGhpcyk7XG5cbiAgICByZXR1cm4gcHJvcGVydGllcy5tYXAoZnVuY3Rpb24ocHJvcCkge1xuICAgICAgICByZXR1cm4gdGhpc1twcm9wXTtcbiAgICB9LCB0aGlzKTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgYXJyYXkgb2YgYWxsIHByb3BlcnR5IG5hbWVzIG9mIGFuIG9iamVjdCBgc2VsZmAgKGluY2x1ZGluZyBub24tZW51bWVyYmFsZSkuXG4gKiBUbyBnZXQgb25seSBlbnVtZXJhYmxlIHByb3BlcnRpZXMsIHVzZSBgT2JqZWN0LmtleXMoKWAuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgQW4gb2JqZWN0IHRvIGdldCBhbGwgcHJvcGVydGllcyBvZi5cbiAqIEByZXR1cm4ge0FycmF5fVxuICovXG4gZnVuY3Rpb24gYWxsS2V5cygpIHtcbiAgICByZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModGhpcyk7XG4gfVxuXG5cbi8qKlxuICogQW4gYW5hbG9ndWUgb2YgYGluZGV4T2ZgIG1ldGhvZCBvZiBBcnJheSBwcm90b3R5cGUuXG4gKiBSZXR1cm5zIHRoZSBga2V5YCBvZiBgc2VhcmNoRWxlbWVudGAgaW4gdGhlIG9iamVjdCBgc2VsZmAuXG4gKiBBcyBvYmplY3Qga2V5cyBhcmUgdW5zb3J0ZWQsIGlmIHRoZXJlIGFyZSBzZXZlcmFsIGtleXMgdGhhdCBob2xkIGBzZWFyY2hFbGVtZW50YCBhbnkgb2YgdGhlbSBjYW4gYmUgcmV0dXJuZWQuIFVzZSBgYWxsS2V5c09mYCB0byByZXR1cm4gYWxsIGtleXMuXG4gKiBBbGwgb3duIHByb3BlcnRpZXMgYXJlIHNlYXJjaGVkIChub3QgdGhvc2UgaW5oZXJpdGVkIHZpYSBwcm90b3R5cGUgY2hhaW4pLCBpbmNsdWRpbmcgbm9uLWVudW1lcmFibGUgcHJvcGVydGllcyAodW5sZXNzIGBvbmx5RW51bWVyYWJsZWAgaXMgdHJ1dGh5KS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3QgdG8gc2VhcmNoIGEgdmFsdWUgaW5cbiAqIEBwYXJhbSB7QW55fSBzZWFyY2hFbGVtZW50IEFuIGVsZW1lbnQgdGhhdCB3aWxsIGJlIHNlYXJjaGVkLiBBbiBleGFjdCBlcXVhbGl0eSBpcyB0ZXN0ZWQsIHNvIGAwYCBpcyBub3QgdGhlIHNhbWUgYXMgYCcwJ2AuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIEFuIG9wdGlvbmFsIHRydWUgdG8gc2VhcmNoIGFtb25nIGVudW1lcmFibGUgcHJvcGVydGllcyBvbmx5LlxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiBrZXlPZihzZWFyY2hFbGVtZW50LCBvbmx5RW51bWVyYWJsZSkge1xuICAgIHZhciBwcm9wZXJ0aWVzID0gb25seUVudW1lcmFibGVcbiAgICAgICAgICAgICAgICAgICAgICAgID8gT2JqZWN0LmtleXModGhpcylcbiAgICAgICAgICAgICAgICAgICAgICAgIDogYWxsS2V5cy5jYWxsKHRoaXMpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwcm9wZXJ0aWVzLmxlbmd0aDsgaSsrKVxuICAgICAgICBpZiAoc2VhcmNoRWxlbWVudCA9PT0gdGhpc1twcm9wZXJ0aWVzW2ldXSlcbiAgICAgICAgICAgIHJldHVybiBwcm9wZXJ0aWVzW2ldO1xuXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuXG4vKipcbiAqIFdvcmtzIHNpbWlsYXJseSB0byB0aGUgcHJldmlvdXMgZnVuY3Rpb24sIGJ1dCByZXR1cm5zIHRoZSBhcnJheSBvZiBrZXlzIGhvbGRpbmcgYHNlYXJjaEVsZW1lbnRgIGFzIHRoZWlyIHZhbHVlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZWxmIEFuIG9iamVjdCB0byBzZWFyY2ggYSB2YWx1ZSBpblxuICogQHBhcmFtIHtBbnl9IHNlYXJjaEVsZW1lbnQgQW4gZWxlbWVudCB0aGF0IHdpbGwgYmUgc2VhcmNoZWQuIEFuIGV4YWN0IGVxdWFsaXR5IGlzIHRlc3RlZCwgc28gYDBgIGlzIG5vdCB0aGUgc2FtZSBhcyBgJzAnYC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gb25seUVudW1lcmFibGUgQW4gb3B0aW9uYWwgdHJ1ZSB0byBzZWFyY2ggYW1vbmcgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9ubHkuXG4gKiBAcmV0dXJuIHtBcnJheVtTdHJpbmddfVxuICovXG5mdW5jdGlvbiBhbGxLZXlzT2Yoc2VhcmNoRWxlbWVudCwgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgcHJvcGVydGllcyA9IG9ubHlFbnVtZXJhYmxlXG4gICAgICAgICAgICAgICAgICAgICAgICA/IE9iamVjdC5rZXlzKHRoaXMpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGFsbEtleXMuY2FsbCh0aGlzKTtcblxuICAgIHZhciBrZXlzID0gcHJvcGVydGllcy5maWx0ZXIoZnVuY3Rpb24ocHJvcCkge1xuICAgICAgICByZXR1cm4gc2VhcmNoRWxlbWVudCA9PT0gdGhpc1twcm9wXTtcbiAgICB9LCB0aGlzKTtcblxuICAgIHJldHVybiBrZXlzO1xufVxuXG5cbi8qKlxuICogQW4gYW5hbG9ndWUgb2YgW2ZvckVhY2hdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0FycmF5L2ZvckVhY2gpIG1ldGhvZCBvZiBBcnJheSBwcm90b3R5cGUuXG4gKiBJdGVyYXRlcyBhbGwgb3duIHByb3BlcnRpZXMgb2YgYHNlbGZgIChvciBvbmx5IGVudW1lcmFibGUgb3duIHByb3BlcnRpZXMgaWYgYG9ubHlFbnVtZXJhYmxlYCBpcyB0cnV0aHkpIGNhbGxpbmcgY2FsbGJhY2sgZm9yIGVhY2gga2V5LlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIG5vdCBiZSB1c2VkIHdpdGggYXJyYXlzLCBpdCB3aWxsIGluY2x1ZGUgYGxlbmd0aGAgcHJvcGVydHkgaW4gaXRlcmF0aW9uLlxuICogVG8gaXRlcmF0ZSBhcnJheS1saWtlIG9iamVjdHMgKGUuZy4sIGBhcmd1bWVudHNgIHBzZXVkby1hcnJheSkgdXNlOlxuICogYGBgXG4gKiBfLmZvckVhY2goYXJndW1lbnRzLCBjYWxsYmFjaywgdGhpc0FyZyk7XG4gKiBgYGBcbiAqIEZ1bmN0aW9uIHJldHVybnMgYHNlbGZgIHRvIGFsbG93IFtjaGFpbmluZ10ocHJvdG8uanMuaHRtbClcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3Qgd2hpY2ggcHJvcGVydGllcyB3aWxsIGJlIGl0ZXJhdGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayBpcyBwYXNzZWQgYHZhbHVlYCwgYGtleWAgYW5kIGBzZWxmYCwgaXRzIHJldHVybiB2YWx1ZSBpcyBub3QgdXNlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSB0aGlzQXJnIEFuIG9wdGlvbmFsIGNvbnRleHQgb2YgaXRlcmF0aW9uICh0aGUgdmFsdWVvZiBgdGhpc2ApLCB3aWxsIGJlIHVuZGVmaW5lZCBpZiB0aGlzIHBhcmFtZXRlciBpcyBub3QgcGFzc2VkLlxuICogQHBhcmFtIHtCb29sZWFufSBvbmx5RW51bWVyYWJsZSBBbiBvcHRpb25hbCBgdHJ1ZWAgdG8gaXRlcmF0ZSBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb25seS5cbiAqL1xuZnVuY3Rpb24gZWFjaEtleShjYWxsYmFjaywgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgcHJvcGVydGllcyA9IG9ubHlFbnVtZXJhYmxlXG4gICAgICAgICAgICAgICAgICAgICAgICA/IE9iamVjdC5rZXlzKHRoaXMpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGFsbEtleXMuY2FsbCh0aGlzKTtcblxuICAgIHByb3BlcnRpZXMuZm9yRWFjaChmdW5jdGlvbihwcm9wKSB7XG4gICAgICAgIGNhbGxiYWNrLmNhbGwodGhpc0FyZywgdGhpc1twcm9wXSwgcHJvcCwgdGhpcyk7XG4gICAgfSwgdGhpcyk7XG5cbiAgICByZXR1cm4gdGhpcztcbn1cblxuXG4vKipcbiAqIEFuIGFuYWxvZ3VlIG9mIFttYXBdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0FycmF5L21hcCkgbWV0aG9kIG9mIEFycmF5IHByb3RvdHlwZS5cbiAqIFJldHVybnMgdGhlIG9iamVjdCB0aGF0IGlzIHRoZSByZXN1bHQgb2YgdGhlIGFwcGxpY2F0aW9uIG9mIGNhbGxiYWNrIHRvIHZhbHVlcyBpbiBhbGwgb3duIHByb3BlcnRpZXMgb2YgYHNlbGZgIChvciBvbmx5IGVudW1lcmFibGUgb3duIHByb3BlcnRpZXMgaWYgYG9ubHlFbnVtZXJhYmxlYCBpcyB0cnV0aHkpLlxuICogVGhlIHJldHVybmVkIG9iamVjdCB3aWxsIGJlIHRoZSBpbnN0YW5jZSBvZiB0aGUgc2FtZSBjbGFzcyBhcyBgc2VsZmAuXG4gKiBQcm9wZXJ0eSBkZXNjcmlwdG9ycyBvZiB0aGUgcmV0dXJuZWQgb2JqZWN0IHdpbGwgaGF2ZSB0aGUgc2FtZSBgZW51bWVyYWJsZWAsIGBjb25maWd1cmFibGVgIGFuZCBgd3JpdGFibGVgIHNldHRpbmdzIGFzIHRoZSBwcm9wZXJ0aWVzIG9mIGBzZWxmYC5cbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBub3QgYmUgdXNlZCB3aXRoIGFycmF5cywgaXQgd2lsbCBpbmNsdWRlIGBsZW5ndGhgIHByb3BlcnR5IGluIGl0ZXJhdGlvbi5cbiAqIFRvIG1hcCBhcnJheS1saWtlIG9iamVjdHMgdXNlOlxuICogYGBgXG4gKiB2YXIgcmVzdWx0ID0gXy5tYXAoYXJndW1lbnRzLCBjYWxsYmFjaywgdGhpc0FyZyk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3Qgd2hpY2ggcHJvcGVydGllcyB3aWxsIGJlIGl0ZXJhdGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayBpcyBwYXNzZWQgYHZhbHVlYCwgYGtleWAgYW5kIGBzZWxmYCBhbmQgc2hvdWxkIHJldHVybiB2YWx1ZSB0aGF0IHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG1hcC5cbiAqIEBwYXJhbSB7T2JqZWN0fSB0aGlzQXJnIEFuIG9wdGlvbmFsIGNvbnRleHQgb2YgaXRlcmF0aW9uICh0aGUgdmFsdWVvZiBgdGhpc2ApLCB3aWxsIGJlIHVuZGVmaW5lZCBpZiB0aGlzIHBhcmFtZXRlciBpcyBub3QgcGFzc2VkLlxuICogQHBhcmFtIHtCb29sZWFufSBvbmx5RW51bWVyYWJsZSBBbiBvcHRpb25hbCBgdHJ1ZWAgdG8gaXRlcmF0ZSBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb25seS5cbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gbWFwS2V5cyhjYWxsYmFjaywgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgZGVzY3JpcHRvcnMgPSB7fTtcbiAgICBlYWNoS2V5LmNhbGwodGhpcywgbWFwUHJvcGVydHksIHRoaXNBcmcsIG9ubHlFbnVtZXJhYmxlKTtcbiAgICByZXR1cm4gT2JqZWN0LmNyZWF0ZSh0aGlzLmNvbnN0cnVjdG9yLnByb3RvdHlwZSwgZGVzY3JpcHRvcnMpO1xuXG4gICAgZnVuY3Rpb24gbWFwUHJvcGVydHkodmFsdWUsIGtleSwgc2VsZikge1xuICAgICAgICBkZXNjcmlwdG9yc1trZXldID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihzZWxmLCBrZXkpO1xuICAgICAgICBkZXNjcmlwdG9yc1trZXldLnZhbHVlID0gY2FsbGJhY2suY2FsbCh0aGlzLCB2YWx1ZSwga2V5LCBzZWxmKTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBBbiBhbmFsb2d1ZSBvZiBbcmVkdWNlXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9SZWR1Y2UpIG1ldGhvZCBvZiBBcnJheSBwcm90b3R5cGUuXG4gKiBUaGlzIG1ldGhvZCByZWR1Y2VzIHRoZSBvYmplY3QgdG8gYSBzaW5nbGUgdmFsdWUuIEl0ZXJhdGlvbiBvcmRlciBpcyBpbXBvc3NpYmxlIHRvIGNvbnRyb2wgd2l0aCBvYmplY3QuXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgbm90IGJlIHVzZWQgd2l0aCBhcnJheXMsIGl0IHdpbGwgaW5jbHVkZSBgbGVuZ3RoYCBwcm9wZXJ0eSBpbiBpdGVyYXRpb24uXG4gKiBUbyByZWR1Y2UgYXJyYXktbGlrZSBvYmplY3RzIHVzZTpcbiAqIGBgYFxuICogdmFyIHJlc3VsdCA9IF8ucmVkdWNlKGFyZ3VtZW50cywgY2FsbGJhY2ssIGluaXRpYWxWYWx1ZSwgdGhpc0FyZyk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3Qgd2hpY2ggcHJvcGVydGllcyB3aWxsIGJlIGl0ZXJhdGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayBpcyBwYXNzZWQgYHByZXZpb3VzVmFsdWVgLCBgdmFsdWVgLCBga2V5YCBhbmQgYHNlbGZgIGFuZCBzaG91bGQgcmV0dXJuIHZhbHVlIHRoYXQgd2lsbCBiZSB1c2VkIGFzIHRoZSBgcHJldmlvdXNWYWx1ZWAgZm9yIHRoZSBuZXh0IGBjYWxsYmFja2AgY2FsbC5cbiAqIEBwYXJhbSB7QW55fSBpbml0aWFsVmFsdWUgVGhlIGluaXRpYWwgdmFsdWUgcGFzc2VkIHRvIGNhbGxiYWNrIGFzIHRoZSBmaXJzdCBwYXJhbWV0ZXIgb24gdGhlIGZpcnN0IGNhbGwuXG4gKiBAcGFyYW0ge09iamVjdH0gdGhpc0FyZyBBbiBvcHRpb25hbCBjb250ZXh0IG9mIGl0ZXJhdGlvbiAodGhlIHZhbHVlb2YgYHRoaXNgKSwgd2lsbCBiZSB1bmRlZmluZWQgaWYgdGhpcyBwYXJhbWV0ZXIgaXMgbm90IHBhc3NlZC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gb25seUVudW1lcmFibGUgQW4gb3B0aW9uYWwgYHRydWVgIHRvIGl0ZXJhdGUgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9ubHkuXG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmZ1bmN0aW9uIHJlZHVjZUtleXMoY2FsbGJhY2ssIGluaXRpYWxWYWx1ZSwgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgcHJvcGVydGllcyA9IG9ubHlFbnVtZXJhYmxlXG4gICAgICAgICAgICAgICAgICAgICAgICA/IE9iamVjdC5rZXlzKHRoaXMpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGFsbEtleXMuY2FsbCh0aGlzKTtcblxuICAgIHZhciBtZW1vID0gaW5pdGlhbFZhbHVlO1xuXG4gICAgcHJvcGVydGllcy5mb3JFYWNoKGZ1bmN0aW9uKHByb3ApIHtcbiAgICAgICAgbWVtbyA9IGNhbGxiYWNrLmNhbGwodGhpc0FyZywgbWVtbywgdGhpc1twcm9wXSwgcHJvcCwgdGhpcyk7XG4gICAgfSwgdGhpcyk7XG5cbiAgICByZXR1cm4gbWVtbztcbn1cblxuXG4vKipcbiAqIEFuIGFuYWxvZ3VlIG9mIFtmaWx0ZXJdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0FycmF5L2ZpbHRlcikgbWV0aG9kIG9mIEFycmF5IHByb3RvdHlwZS5cbiAqIFJldHVybnMgdGhlIG5ldyBvYmplY3Qgd2l0aCBrZXlzIGZvciB3aGljaCBjYWxsYmFjayByZXR1cm5zIHRydWUuXG4gKiBQcm9wZXJ0eSBkZXNjcmlwdG9ycyBvZiB0aGUgcmV0dXJuZWQgb2JqZWN0IHdpbGwgaGF2ZSB0aGUgc2FtZSBgZW51bWVyYWJsZWAsIGBjb25maWd1cmFibGVgIGFuZCBgd3JpdGFibGVgIHNldHRpbmdzIGFzIHRoZSBwcm9wZXJ0aWVzIG9mIGBzZWxmYC5cbiAqIFRvIGZpbHRlciBhcnJheS1saWtlIG9iamVjdHMgdXNlOlxuICogYGBgXG4gKiB2YXIgcmVzdWx0ID0gXy5maWx0ZXIoYXJndW1lbnRzLCBjYWxsYmFjaywgdGhpc0FyZyk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBBbiBvYmplY3Qgd2hpY2ggcHJvcGVydGllcyB3aWxsIGJlIGl0ZXJhdGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayBpcyBwYXNzZWQgYHZhbHVlYCwgYGtleWAgYW5kIGBzZWxmYC4gSWYgaXQgcmV0dXJucyB0cnV0aHkgdmFsdWUsIHRoZSBrZXkvdmFsdWUgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgcmVzdWx0aW5nIG9iamVjdC5cbiAqIEBwYXJhbSB7T2JqZWN0fSB0aGlzQXJnIEFuIG9wdGlvbmFsIGNvbnRleHQgb2YgaXRlcmF0aW9uICh0aGUgdmFsdWVvZiBgdGhpc2ApLCB3aWxsIGJlIHVuZGVmaW5lZCBpZiB0aGlzIHBhcmFtZXRlciBpcyBub3QgcGFzc2VkLlxuICogQHBhcmFtIHtCb29sZWFufSBvbmx5RW51bWVyYWJsZSBBbiBvcHRpb25hbCBgdHJ1ZWAgdG8gaXRlcmF0ZSBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb25seS5cbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gZmlsdGVyS2V5cyhjYWxsYmFjaywgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB2YXIgZGVzY3JpcHRvcnMgPSB7fTtcbiAgICBlYWNoS2V5LmNhbGwodGhpcywgZmlsdGVyUHJvcGVydHksIHRoaXNBcmcsIG9ubHlFbnVtZXJhYmxlKTtcbiAgICByZXR1cm4gT2JqZWN0LmNyZWF0ZSh0aGlzLmNvbnN0cnVjdG9yLnByb3RvdHlwZSwgZGVzY3JpcHRvcnMpOztcblxuICAgIGZ1bmN0aW9uIGZpbHRlclByb3BlcnR5KHZhbHVlLCBrZXksIHNlbGYpIHtcbiAgICAgICAgaWYgKGNhbGxiYWNrLmNhbGwodGhpcywgdmFsdWUsIGtleSwgc2VsZikpXG4gICAgICAgICAgICBkZXNjcmlwdG9yc1trZXldID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihzZWxmLCBrZXkpO1xuICAgIH1cbn1cblxuXG52YXIgX3Bhc3NlZCA9IHt9XG4gICAgLCBfZGlkTm90UGFzcyA9IHt9O1xuXG4vKipcbiAqIEFuIGFuYWxvZ3VlIG9mIFtzb21lXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9zb21lKSBtZXRob2Qgb2YgQXJyYXkgcHJvdG90eXBlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZWxmIEFuIG9iamVjdCB3aGljaCBwcm9wZXJ0aWVzIHdpbGwgYmUgaXRlcmF0ZWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIENhbGxiYWNrIGlzIHBhc3NlZCBgdmFsdWVgLCBga2V5YCBhbmQgYHNlbGZgLiBJZiBpdCByZXR1cm5zIHRydXRoeSB2YWx1ZSwgdGhlIGZ1bmN0aW9uIGltbWVhZGl0ZWx5IHJldHVybnMgYHRydWVgLlxuICogQHBhcmFtIHtPYmplY3R9IHRoaXNBcmcgQW4gb3B0aW9uYWwgY29udGV4dCBvZiBpdGVyYXRpb24gKHRoZSB2YWx1ZW9mIGB0aGlzYCksIHdpbGwgYmUgdW5kZWZpbmVkIGlmIHRoaXMgcGFyYW1ldGVyIGlzIG5vdCBwYXNzZWQuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9ubHlFbnVtZXJhYmxlIEFuIG9wdGlvbmFsIGB0cnVlYCB0byBpdGVyYXRlIGVudW1lcmFibGUgcHJvcGVydGllcyBvbmx5LlxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gc29tZUtleShjYWxsYmFjaywgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB0cnkge1xuICAgICAgICBlYWNoS2V5LmNhbGwodGhpcywgdGVzdFByb3BlcnR5LCB0aGlzQXJnLCBvbmx5RW51bWVyYWJsZSk7XG4gICAgfSBjYXRjaCAodGVzdCkge1xuICAgICAgICBpZiAodGVzdCA9PT0gX3Bhc3NlZCkgcmV0dXJuIHRydWU7XG4gICAgICAgIGVsc2UgdGhyb3cgdGVzdDtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuXG4gICAgZnVuY3Rpb24gdGVzdFByb3BlcnR5KHZhbHVlLCBrZXksIHNlbGYpIHtcbiAgICAgICAgaWYgKGNhbGxiYWNrLmNhbGwodGhpcywgdmFsdWUsIGtleSwgc2VsZikpXG4gICAgICAgICAgICB0aHJvdyBfcGFzc2VkO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIEFuIGFuYWxvZ3VlIG9mIFtldmVyeV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvZXZlcnkpIG1ldGhvZCBvZiBBcnJheSBwcm90b3R5cGUuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlbGYgQW4gb2JqZWN0IHdoaWNoIHByb3BlcnRpZXMgd2lsbCBiZSBpdGVyYXRlZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGJhY2sgaXMgcGFzc2VkIGB2YWx1ZWAsIGBrZXlgIGFuZCBgc2VsZmAuIElmIGl0IHJldHVybnMgZmFsc3kgdmFsdWUsIHRoZSBmdW5jdGlvbiBpbW1lYWRpdGVseSByZXR1cm5zIGBmYWxzZWAuXG4gKiBAcGFyYW0ge09iamVjdH0gdGhpc0FyZyBBbiBvcHRpb25hbCBjb250ZXh0IG9mIGl0ZXJhdGlvbiAodGhlIHZhbHVlb2YgYHRoaXNgKSwgd2lsbCBiZSB1bmRlZmluZWQgaWYgdGhpcyBwYXJhbWV0ZXIgaXMgbm90IHBhc3NlZC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gb25seUVudW1lcmFibGUgQW4gb3B0aW9uYWwgYHRydWVgIHRvIGl0ZXJhdGUgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9ubHkuXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBldmVyeUtleShjYWxsYmFjaywgdGhpc0FyZywgb25seUVudW1lcmFibGUpIHtcbiAgICB0cnkge1xuICAgICAgICBlYWNoS2V5LmNhbGwodGhpcywgdGVzdFByb3BlcnR5LCB0aGlzQXJnLCBvbmx5RW51bWVyYWJsZSk7XG4gICAgfSBjYXRjaCAodGVzdCkge1xuICAgICAgICBpZiAodGVzdCA9PT0gX2RpZE5vdFBhc3MpIHJldHVybiBmYWxzZTtcbiAgICAgICAgZWxzZSB0aHJvdyB0ZXN0O1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcblxuICAgIGZ1bmN0aW9uIHRlc3RQcm9wZXJ0eSh2YWx1ZSwga2V5LCBzZWxmKSB7XG4gICAgICAgIGlmICghIGNhbGxiYWNrLmNhbGwodGhpcywgdmFsdWUsIGtleSwgc2VsZikpXG4gICAgICAgICAgICB0aHJvdyBfZGlkTm90UGFzcztcbiAgICB9XG59XG5cblxudmFyIEFycmF5UHJvdG8gPSBBcnJheS5wcm90b3R5cGVcbiAgICAsIGNvbmNhdCA9IEFycmF5UHJvdG8uY29uY2F0O1xuLyoqXG4gKiBSZXR1cm5zIG9iamVjdCBvZiB0aGUgc2FtZSBjbGFzcyB3aXRoIG9ubHkgc3BlY2lmaWVkIGtleXMsIHRoYXQgYXJlIHBhc3NlZCBhcyBzdHJpbmcgcGFyYW1ldGVycyBvciBhcnJheShzKSBvZiBrZXlzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZWxmIGFuIG9iamVjdCB0byBwaWNrIGtleXMgZnJvbVxuICogQHBhcmFtIHtMaXN0W1N0cmluZ3xBcnJheV19IGFyZ3VtZW50cyBsaXN0IG9mIGtleXMgKG9yIGFycmF5KHMpIG9mIGtleXMpXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbmZ1bmN0aW9uIHBpY2tLZXlzKCkgeyAvLyAsIC4uLiBrZXlzXG4gICAgdmFyIGtleXMgPSBjb25jYXQuYXBwbHkoQXJyYXlQcm90bywgYXJndW1lbnRzKVxuICAgICAgICAsIG9iaiA9IE9iamVjdC5jcmVhdGUodGhpcy5jb25zdHJ1Y3Rvci5wcm90b3R5cGUpO1xuICAgIGtleXMuZm9yRWFjaChmdW5jdGlvbihrZXkpIHtcbiAgICAgICAgaWYgKHRoaXMuaGFzT3duUHJvcGVydHkoa2V5KSlcbiAgICAgICAgICAgIG9ialtrZXldID0gdGhpc1trZXldO1xuICAgIH0sIHRoaXMpO1xuICAgIHJldHVybiBvYmo7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIG9iamVjdCBvZiB0aGUgc2FtZSBjbGFzcyB3aXRob3V0IHNwZWNpZmllZCBrZXlzLCB0aGF0IGFyZSBwYXNzZWQgYXMgc3RyaW5nIHBhcmFtZXRlcnMgb3IgYXJyYXkocykgb2Yga2V5cy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBhbiBvYmplY3QgdG8gb21pdCBrZXlzIGluXG4gKiBAcGFyYW0ge0xpc3RbU3RyaW5nfEFycmF5XX0gYXJndW1lbnRzIGxpc3Qgb2Yga2V5cyAob3IgYXJyYXkocykgb2Yga2V5cylcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuZnVuY3Rpb24gb21pdEtleXMoKSB7IC8vICwgLi4uIGtleXNcbiAgICB2YXIga2V5cyA9IGNvbmNhdC5hcHBseShBcnJheVByb3RvLCBhcmd1bWVudHMpXG4gICAgICAgICwgb2JqID0gY2xvbmUuY2FsbCh0aGlzKTtcbiAgICBrZXlzLmZvckVhY2goZnVuY3Rpb24oa2V5KXtcbiAgICAgICAgZGVsZXRlIG9ialtrZXldO1xuICAgIH0sIHRoaXMpO1xuICAgIHJldHVybiBvYmo7XG59XG5cblxuLyoqXG4gKiBQZXJmb3JtcyBkZWVwIGVxdWFsaXR5IHRlc3Qgb2YgdGhlIG9iamVjdC4gRG9lcyBub3Qgd29yayB3aXRoIHJlY3Vyc2l2ZSBvYmplY3RzXG4gKiBAcGFyYW0gIHtBbnl9IHNlbGYgb2JqZWN0IHRvIGNvbXBhcmVcbiAqIEBwYXJhbSAge0FueX0gb2JqIG9iamVjdCB0byBjb21wYXJlXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBpc0VxdWFsKG9iaikge1xuICAgIGlmICh0aGlzID09PSBvYmopIHJldHVybiB0aGlzICE9PSAwIHx8IDEvdGhpcyA9PSAxL29iajsgLy8gMCBhbmQgLTAgYXJlIGNvbnNpZGVyZWQgbm90IGVxdWFsLCBhbHRob3VnaCAwID09PSAtMCBpcyB0cnVlXG4gICAgaWYgKHRoaXMgPT0gbnVsbCB8fCBvYmogPT0gbnVsbCkgcmV0dXJuIGZhbHNlO1xuICAgIHZhciBjbGFzc05hbWUgPSB0aGlzLmNvbnN0cnVjdG9yLm5hbWU7XG4gICAgaWYgKGNsYXNzTmFtZSAhPSBvYmouY29uc3RydWN0b3IubmFtZSkgcmV0dXJuIGZhbHNlO1xuICAgIHN3aXRjaCAoY2xhc3NOYW1lKSB7XG4gICAgICAgIGNhc2UgJ1N0cmluZyc6XG4gICAgICAgICAgICByZXR1cm4gdGhpcyA9PSBTdHJpbmcob2JqKTtcbiAgICAgICAgY2FzZSAnTnVtYmVyJzpcbiAgICAgICAgICAgIHJldHVybiB0aGlzICE9ICt0aGlzID8gb2JqICE9ICtvYmogOiAodGhpcyA9PSAwID8gMS90aGlzID09IDEvb2JqIDogdGhpcyA9PSArb2JqKTtcbiAgICAgICAgY2FzZSAnRGF0ZSc6XG4gICAgICAgIGNhc2UgJ0Jvb2xlYW4nOlxuICAgICAgICAgICAgcmV0dXJuICt0aGlzID09ICtvYmo7XG4gICAgICAgIGNhc2UgJ1JlZ0V4cCc6XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zb3VyY2UgPT0gb2JqLnNvdXJjZVxuICAgICAgICAgICAgICAgICAgICAmJiB0aGlzLmdsb2JhbCA9PSBvYmouZ2xvYmFsXG4gICAgICAgICAgICAgICAgICAgICYmIHRoaXMubXVsdGlsaW5lID09IG9iai5tdWx0aWxpbmVcbiAgICAgICAgICAgICAgICAgICAgJiYgdGhpcy5pZ25vcmVDYXNlID09IG9iai5pZ25vcmVDYXNlO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIHRoaXMgIT0gJ29iamVjdCcgfHwgdHlwZW9mIG9iaiAhPSAnb2JqZWN0JykgcmV0dXJuIGZhbHNlO1xuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkodGhpcykpXG4gICAgICAgIHJldHVybiB0aGlzLmxlbmd0aCA9PSBvYmoubGVuZ3RoXG4gICAgICAgICAgICAgICAgJiYgdGhpcy5ldmVyeShmdW5jdGlvbihpdGVtLCBpbmRleCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaXNFcXVhbC5jYWxsKGl0ZW0sIG9ialtpbmRleF0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgIGVsc2Uge1xuICAgICAgICByZXR1cm4gYWxsS2V5cy5jYWxsKHRoaXMpLmxlbmd0aCA9PSBhbGxLZXlzLmNhbGwob2JqKS5sZW5ndGhcbiAgICAgICAgICAgICAgICAmJiBldmVyeUtleS5jYWxsKHRoaXMsIGZ1bmN0aW9uKHZhbHVlLCBrZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGlzRXF1YWwuY2FsbCh2YWx1ZSwgb2JqW2tleV0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIFRoZSBvcHBvc2l0ZSBvZiBpc0VxdWFsXG4gKiBAcGFyYW0gIHtBbnl9IHNlbGYgb2JqZWN0IHRvIGNvbXBhcmVcbiAqIEBwYXJhbSAge0FueX0gb2JqIG9iamVjdCB0byBjb21wYXJlXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5mdW5jdGlvbiBpc05vdChvYmopIHtcbiAgICByZXR1cm4gIWlzRXF1YWwuY2FsbCh0aGlzLCBvYmopO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqIC0gW2V4dGVuZFByb3RvXSgjZXh0ZW5kUHJvdG8pXG4gKiAtIFtjcmVhdGVTdWJjbGFzc10oI2NyZWF0ZVN1YmNsYXNzKVxuICogLSBbbWFrZVN1YmNsYXNzXSgjbWFrZVN1YmNsYXNzKVxuICogLSBbbmV3QXBwbHldKCNuZXdBcHBseSlcbiAqXG4gKiBUaGVzZSBtZXRob2RzIGNhbiBiZSBbY2hhaW5lZF0ocHJvdG8uanMuaHRtbCNQcm90bylcbiAqL1xudmFyIHByb3RvdHlwZU1ldGhvZHMgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBleHRlbmRQcm90bzogZXh0ZW5kUHJvdG8sXG4gICAgY3JlYXRlU3ViY2xhc3M6IGNyZWF0ZVN1YmNsYXNzLFxuICAgIG1ha2VTdWJjbGFzczogbWFrZVN1YmNsYXNzLFxuICAgIG5ld0FwcGx5OiBuZXdBcHBseVxufTtcblxuXG52YXIgX18gPSByZXF1aXJlKCcuL3Byb3RvX29iamVjdCcpO1xuXG5fXy5leHRlbmQuY2FsbChfXywgcmVxdWlyZSgnLi9wcm90b19mdW5jdGlvbicpKTtcblxuXG4vKipcbiAqIEFkZHMgbm9uLWVudW1lcmFibGUsIG5vbi1jb25maWd1cmFibGUgYW5kIG5vbi13cml0YWJsZSBwcm9wZXJ0aWVzIHRvIHRoZSBwcm90b3R5cGUgb2YgY29uc3RydWN0b3IgZnVuY3Rpb24uXG4gKiBVc2FnZTpcbiAqIGBgYFxuICogZnVuY3Rpb24gTXlDbGFzcygpIHt9XG4gKiBfLmV4dGVuZFByb3RvKE15Q2xhc3MsIHtcbiAqICAgICBtZXRob2QxOiBmdW5jdGlvbigpIHt9LFxuICogICAgIG1ldGhvZDI6IGZ1bmN0aW9uKCkge31cbiAqIH0pO1xuICogYGBgXG4gKiBUbyBleHRlbmQgY2xhc3MgdmlhIG9iamVjdDpcbiAqIGBgYFxuICogXy5leHRlbmRQcm90byhvYmouY29uc3RydWN0b3IsIG1ldGhvZHMpO1xuICogYGBgXG4gKiBSZXR1cm5zIHBhc3NlZCBjb25zdHJ1Y3Rvciwgc28gZnVuY3Rpb25zIF8uZXh0ZW5kUHJvdG8sIFtfLmV4dGVuZF0ob2JqZWN0LmpzLmh0bWwjZXh0ZW5kKSBhbmQgXy5tYWtlU3ViY2xhc3MgY2FuIGJlIFtjaGFpbmVkXShwcm90by5qcy5odG1sKS4gXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gc2VsZiBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICogQHBhcmFtIHtPYmplY3R9IG1ldGhvZHMgYSBtYXAgb2YgZnVuY3Rpb25zLCBrZXlzIHdpbGwgYmUgaW5zdGFuY2UgbWV0aG9kcyAocHJvcGVydGllcyBvZiB0aGUgY29uc3RydWN0b3IgcHJvdG90eXBlKVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIGV4dGVuZFByb3RvKG1ldGhvZHMpIHtcbiAgICB2YXIgcHJvcERlc2NyaXB0b3JzID0ge307XG5cbiAgICBfXy5lYWNoS2V5LmNhbGwobWV0aG9kcywgZnVuY3Rpb24obWV0aG9kLCBuYW1lKSB7XG4gICAgICAgIHByb3BEZXNjcmlwdG9yc1tuYW1lXSA9IHtcbiAgICAgICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICAgICAgY29uZmlndXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIHdyaXRhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIHZhbHVlOiBtZXRob2RcbiAgICAgICAgfTtcbiAgICB9KTtcblxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMucHJvdG90eXBlLCBwcm9wRGVzY3JpcHRvcnMpO1xuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogTWFrZXMgYSBzdWJjbGFzcyBvZiBjbGFzcyBgdGhpc0NsYXNzYC5cbiAqIFRoZSByZXR1cm5lZCBmdW5jdGlvbiB3aWxsIGhhdmUgc3BlY2lmaWVkIGBuYW1lYCBpZiBzdXBwbGllZC5cbiAqIFRoZSBjb25zdHJ1Y3RvciBvZiBzdXBlcmNsYXNzIHdpbGwgYmUgY2FsbGVkIGluIHN1YmNsYXNzIGNvbnN0cnVjdG9yIGJ5IGRlZmF1bHQgdW5sZXNzIGBhcHBseUNvbnN0cnVjdG9yID09PSBmYWxzZWAgKG5vdCBqdXN0IGZhbHN5KS5cbiAqIENvcGllcyBgdGhpc0NsYXNzYCBjbGFzcyBtZXRob2RzIHRvIGNyZWF0ZWQgc3ViY2xhc3MuIEZvciB0aGVtIHRvIHdvcmsgY29ycmVjdGx5IHRoZXkgc2hvdWxkIHVzZSBgdGhpc2AgdG8gcmVmZXIgdG8gdGhlIGNsYXNzIHJhdGhlciB0aGFuIGV4cGxpY2l0IHN1cGVyY2xhc3MgbmFtZS5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzQ2xhc3MgQSBjbGFzcyB0byBtYWtlIHN1YmNsYXNzIG9mXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBPcHRpb25hbCBuYW1lIG9mIHN1YmNsYXNzIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGFwcGx5Q29uc3RydWN0b3IgT3B0aW9uYWwgZmFsc2UgdmFsdWUgKG5vdCBmYWxzeSkgdG8gcHJldmVudCBjYWxsIG9mIGluaGVyaXRlZCBjb25zdHJ1Y3RvciBpbiB0aGUgY29uc3RydWN0b3Igb2Ygc3ViY2xhc3NcbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBjcmVhdGVTdWJjbGFzcyhuYW1lLCBhcHBseUNvbnN0cnVjdG9yKSB7XG4gICAgdmFyIHRoaXNDbGFzcyA9IHRoaXM7XG4gICAgdmFyIHN1YmNsYXNzO1xuXG4gICAgLy8gbmFtZSBpcyBvcHRpb25hbFxuICAgIG5hbWUgPSBuYW1lIHx8ICcnO1xuXG4gICAgLy8gYXBwbHkgc3VwZXJjbGFzcyBjb25zdHJ1Y3RvclxuICAgIHZhciBjb25zdHJ1Y3RvckNvZGUgPSBhcHBseUNvbnN0cnVjdG9yID09PSBmYWxzZVxuICAgICAgICAgICAgPyAnJ1xuICAgICAgICAgICAgOiAndGhpc0NsYXNzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7JztcblxuICAgIGV2YWwoJ3N1YmNsYXNzID0gZnVuY3Rpb24gJyArIG5hbWUgKyAnKCl7ICcgKyBjb25zdHJ1Y3RvckNvZGUgKyAnIH0nKTtcblxuICAgIG1ha2VTdWJjbGFzcy5jYWxsKHN1YmNsYXNzLCB0aGlzQ2xhc3MpO1xuXG4gICAgLy8gY29weSBjbGFzcyBtZXRob2RzXG4gICAgLy8gLSBmb3IgdGhlbSB0byB3b3JrIGNvcnJlY3RseSB0aGV5IHNob3VsZCBub3QgZXhwbGljdGx5IHVzZSBzdXBlcmNsYXNzIG5hbWVcbiAgICAvLyBhbmQgdXNlIFwidGhpc1wiIGluc3RlYWRcbiAgICBfXy5kZWVwRXh0ZW5kLmNhbGwoc3ViY2xhc3MsIHRoaXNDbGFzcywgdHJ1ZSk7XG5cbiAgICByZXR1cm4gc3ViY2xhc3M7XG59XG5cblxuLyoqXG4gKiBTZXRzIHVwIHByb3RvdHlwZSBjaGFpbiB0byBjaGFuZ2UgYHRoaXNDbGFzc2AgKGEgY29uc3RydWN0b3IgZnVuY3Rpb24pIHNvIHRoYXQgaXQgYmVjb21lcyBhIHN1YmNsYXNzIG9mIGBTdXBlcmNsYXNzYC5cbiAqIFJldHVybnMgYHRoaXNDbGFzc2Agc28gaXQgY2FuIGJlIFtjaGFpbmVkXShwcm90by5qcy5odG1sKSB3aXRoIF8uZXh0ZW5kUHJvdG8gYW5kIFtfLmV4dGVuZF0ob2JqZWN0LmpzLmh0bWwjZXh0ZW5kKS5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzQ2xhc3MgQSBjbGFzcyB0aGF0IHdpbGwgYmVjb21lIGEgc3ViY2xhc3Mgb2YgU3VwZXJjbGFzc1xuICogQHBhcmFtIHtGdW5jdGlvbn0gU3VwZXJjbGFzcyBBIGNsYXNzIHRoYXQgd2lsbCBiZWNvbWUgYSBzdXBlcmNsYXNzIG9mIHRoaXNDbGFzc1xuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIG1ha2VTdWJjbGFzcyhTdXBlcmNsYXNzKSB7XG4gICAgLy8gcHJvdG90eXBlIGNoYWluXG4gICAgdGhpcy5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKFN1cGVyY2xhc3MucHJvdG90eXBlKTtcbiAgICBcbiAgICAvLyBzdWJjbGFzcyBpZGVudGl0eVxuICAgIGV4dGVuZFByb3RvLmNhbGwodGhpcywge1xuICAgICAgICBjb25zdHJ1Y3RvcjogdGhpc1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xufVxuXG5cbi8qKlxuICogQ2FsbHMgY29uc3RydWN0b3IgYHRoaXNgIHdpdGggYXJndW1lbnRzIHBhc3NlZCBhcyBhcnJheVxuICogXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0aGlzQ2xhc3MgQSBjbGFzcyBjb25zdHJ1Y3RvciB0aGF0IHdpbGwgYmUgY2FsbGVkXG4gKiBAcmV0dXJuIHtBcnJheXxBcnJheS1saWtlfSBhcmdzIEFycmF5IG9mIGFyZ3VtZW50cyB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIGNvbnN0cnVjdG9yXG4gKi9cbmZ1bmN0aW9uIG5ld0FwcGx5KGFyZ3MpIHtcbiAgICBpZiAoISBBcnJheS5pc0FycmF5KGFyZ3MpKVxuICAgICAgICBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJncyk7XG4gICAgLy8gXCJudWxsXCIgaXMgY29udGV4dCB0byBwYXNzIHRvIGNsYXNzIGNvbnN0cnVjdG9yLCBmaXJzdCBwYXJhbWV0ZXIgb2YgYmluZFxuICAgIHZhciBhcmdzID0gW251bGxdLmNvbmNhdChhcmdzKTtcbiAgICByZXR1cm4gbmV3IChGdW5jdGlvbi5wcm90b3R5cGUuYmluZC5hcHBseSh0aGlzLCBhcmdzKSk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIF9fID0gcmVxdWlyZSgnLi9wcm90b19vYmplY3QnKTtcblxuXG4vKipcbiAqIC0gW2ZpcnN0VXBwZXJDYXNlXSgjZmlyc3RVcHBlckNhc2UpXG4gKiAtIFtmaXJzdExvd2VyQ2FzZV0oI2ZpcnN0TG93ZXJDYXNlKVxuICogLSBbdG9SZWdFeHBdKCN0b1JlZ0V4cClcbiAqIC0gW3RvRnVuY3Rpb25dKCN0b0Z1bmN0aW9uKVxuICogLSBbdG9EYXRlXSgjdG9EYXRlKVxuICogLSBbdG9RdWVyeVN0cmluZ10oI3RvUXVlcnlTdHJpbmcpXG4gKiAtIFtmcm9tUXVlcnlTdHJpbmddKCNmcm9tUXVlcnlTdHJpbmcpXG4gKiAtIFtqc29uUGFyc2VdKCNqc29uUGFyc2UpXG4gKiAtIFtoYXNoQ29kZV0oI2hhc2hDb2RlKVxuICogLSBbdW5QcmVmaXhdKCN1blByZWZpeClcbiAqL1xuIHZhciBzdHJpbmdNZXRob2RzID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgZmlyc3RVcHBlckNhc2U6IGZpcnN0VXBwZXJDYXNlLFxuICAgIGZpcnN0TG93ZXJDYXNlOiBmaXJzdExvd2VyQ2FzZSxcbiAgICB0b1JlZ0V4cDogdG9SZWdFeHAsXG4gICAgdG9GdW5jdGlvbjogdG9GdW5jdGlvbixcbiAgICB0b0RhdGU6IHRvRGF0ZSxcbiAgICB0b1F1ZXJ5U3RyaW5nOiB0b1F1ZXJ5U3RyaW5nLFxuICAgIGZyb21RdWVyeVN0cmluZzogZnJvbVF1ZXJ5U3RyaW5nLFxuICAgIGpzb25QYXJzZToganNvblBhcnNlLFxuICAgIGhhc2hDb2RlOiBoYXNoQ29kZSxcbiAgICB1blByZWZpeDogdW5QcmVmaXhcbn07XG5cblxuLyoqXG4gKiBSZXR1cm5zIHN0cmluZyB3aXRoIHRoZSBmaXJzdCBjaGFyYWN0ZXIgY2hhbmdlZCB0byB1cHBlciBjYXNlLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzZWxmIEEgc3RyaW5nIHRoYXQgd2lsbCBoYXZlIGl0cyBmaXJzdCBjaGFyYWN0ZXIgcmVwbGFjZWRcbiAqL1xuZnVuY3Rpb24gZmlyc3RVcHBlckNhc2UoKSB7XG4gICAgcmV0dXJuIHRoaXMgPyB0aGlzWzBdLnRvVXBwZXJDYXNlKCkgKyB0aGlzLnNsaWNlKDEpIDogdGhpcztcbn1cblxuXG4vKipcbiAqIFJldHVybnMgc3RyaW5nIHdpdGggdGhlIGZpcnN0IGNoYXJhY3RlciBjaGFuZ2VkIHRvIGxvd2VyIGNhc2UuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHNlbGYgQSBzdHJpbmcgdGhhdCB3aWxsIGhhdmUgaXRzIGZpcnN0IGNoYXJhY3RlciByZXBsYWNlZFxuICovXG5mdW5jdGlvbiBmaXJzdExvd2VyQ2FzZSgpIHtcbiAgICByZXR1cm4gdGhpcyA/IHRoaXNbMF0udG9Mb3dlckNhc2UoKSArIHRoaXMuc2xpY2UoMSkgOiB0aGlzO1xufVxuXG5cbi8qKlxuICogQ29udmVydHMgc3RyaW5nIGNyZWF0ZWQgYnkgYHRvU3RyaW5nYCBtZXRob2Qgb2YgUmVnRXhwIGJhY2sgdG8gUmVnRXhwXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHNlbGYgc3RyaW5nIGNvbnRhaW5pbmcgcmVndWxhciBleHByZXNzaW9uIGluY2x1ZGluZyBlbmNsb3NpbmcgXCIvXCIgc3ltYm9scyBhbmQgZmxhZ3NcbiAqIEByZXR1cm4ge1JlZ0V4cH1cbiAqL1xuZnVuY3Rpb24gdG9SZWdFeHAoKSB7XG4gICAgdmFyIHJ4ID0gdGhpcy5tYXRjaChyZWdleHBTdHJpbmdQYXR0ZXJuKTtcbiAgICBpZiAocngpIHJldHVybiBuZXcgUmVnRXhwKHJ4WzFdLCByeFsyXSk7XG59XG52YXIgcmVnZXhwU3RyaW5nUGF0dGVybiA9IC9eXFwvKC4qKVxcLyhbZ2lteV0qKSQvO1xuXG5cbi8qKlxuICogQ29udmVydHMgc3RyaW5nIGNyZWF0ZWQgYnkgYHRvU3RyaW5nYCBtZXRob2Qgb2YgZnVuY3Rpb24gYmFjayB0byBmdW5jdGlvblxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzZWxmIHN0cmluZyBjb250YWluaW5nIGZ1bGwgZnVuY3Rpb24gY29kZVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmZ1bmN0aW9uIHRvRnVuY3Rpb24oKSB7XG4gICAgdmFyIGZ1bmM7XG4gICAgdmFyIGNvZGUgPSAnZnVuYyA9ICcgKyB0aGlzICsgJzsnO1xuICAgIHRyeSB7XG4gICAgICAgIGV2YWwoY29kZSk7XG4gICAgICAgIHJldHVybiBmdW5jO1xuICAgIH0gY2F0Y2goZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxufVxuXG5cbi8qKlxuICogQ29udmVydHMgc3RyaW5nIHRvIGRhdGUgaW4gYSBzYWZlIHdheSBzbyB0aGF0IHRoZSByZXNpdWx0IGlzIHVuZGVmaW5lZCBpZiBkYXRlIGlzIGludmFsaWRcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ3xEYXRlfSBzZWxmIHN0cmluZyBvciBkYXRlIG9iamVjdCB0byBjb252ZXJ0IHRvIFZBTElEIGRhdGVcbiAqIEByZXR1cm4ge1t0eXBlXX0gW2Rlc2NyaXB0aW9uXVxuICovXG5mdW5jdGlvbiB0b0RhdGUoKSB7XG4gICAgaWYgKCEgdGhpcykgcmV0dXJuO1xuICAgIHRyeSB7XG4gICAgICAgIHZhciBkYXRlID0gbmV3IERhdGUodGhpcyk7XG4gICAgfSBjYXRjaCAoZSkge31cbiAgICBpZiAoZGF0ZSAmJiBkYXRlLmdldFRpbWUgJiYgIWlzTmFOKGRhdGUuZ2V0VGltZSgpKSlcbiAgICAgICAgcmV0dXJuIGRhdGU7XG59XG5cblxuLyoqXG4gKiBDb252ZXJ0IHBhcmFtcyBvYmplY3QgdG8gYSB1cmwgc3R5bGUgcXVlcnkgc3RyaW5nICh3aXRob3V0IFwiP1wiKVxuICogXG4gKiBAcGFyYW0ge09iamVjdH0gc2VsZiBUaGUgb2JqZWN0IGhhc2ggdG8gYmUgY29udmVydGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmNvZGUgb3B0aW9uYWwgZnVuY3Rpb24gdXNlZCB0byBlbmNvZGUgZGF0YSwgZW5jb2RlVVJJQ29tcG9uZW50IGlzIHVzZWQgaWYgbm90IHNwZWNpZmllZFxuICogQHJldHVybiB7U3RyaW5nfSB0aGUgcmVzdWx0aW5nIHF1ZXJ5IHN0cmluZ1xuICovXG5mdW5jdGlvbiB0b1F1ZXJ5U3RyaW5nKGVuY29kZSkge1xuICAgIHZhciBxcyA9ICcnXG4gICAgICAgICwgcGFyYW1zID0gdGhpcyB8fCB7fVxuICAgICAgICAsIGVuY29kZSA9IGVuY29kZSB8fCBlbmNvZGVVUklDb21wb25lbnQ7XG5cbiAgICBfXy5lYWNoS2V5LmNhbGwocGFyYW1zLCBmdW5jdGlvbih2YWx1ZSwga2V5KSB7XG4gICAgICAgIHFzICs9IGtleSArICc9JyArIGVuY29kZSh2YWx1ZSkgKyAnJic7XG4gICAgfSk7XG4gICAgXG4gICAgcmV0dXJuIHFzLnNsaWNlKDAsIC0xKTtcbn1cblxuXG4vKipcbiAqIENvbnZlcnQgdXJsIHN0eWxlIHF1ZXJ5IHN0cmluZyAod2l0aG91dCBcIj9cIikgaW50byBvYmplY3QgaGFzaFxuICogXG4gKiBAcGFyYW0ge1N0cmluZ30gc2VsZiBUaGUgc3RyaW5nIHRvIGJlIGNvbnZlcnRlZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gZGVjb2RlIG9wdGlvbmFsIGRlY29kZSBmdW5jdGlvbiwgZGVjb2RlVVJJQ29tcG9uZW50IHdpbGwgYmUgdXNlZCBpZiBub3Qgc3VwcGxpZWRcbiAqIEByZXR1cm4ge09iamVjdH0gVGhlIHJlc3VsdGluZyBvYmplY3QgaGFzaFxuICovXG5mdW5jdGlvbiBmcm9tUXVlcnlTdHJpbmcoZGVjb2RlKSB7XG4gICAgdmFyIHBhaXJzID0gdGhpcy5zcGxpdCgnJicpXG4gICAgICAgICwgcmVzdWx0cyA9IHt9XG4gICAgICAgICwgZGVjb2RlID0gZGVjb2RlIHx8IGRlY29kZVVSSUNvbXBvbmVudDtcblxuICAgIHBhaXJzLmZvckVhY2goZnVuY3Rpb24ocGFpcikge1xuICAgICAgICB2YXIgc3BsaXRQYWlyID0gcGFpci5zcGxpdCgnPScpO1xuICAgICAgICBpZiAoc3BsaXRQYWlyLmxlbmd0aCA8IDIpIHJldHVybjtcbiAgICAgICAgdmFyIGtleSA9IHNwbGl0UGFpclswXVxuICAgICAgICAgICAgLCB2YWx1ZSA9IGRlY29kZShzcGxpdFBhaXJbMV0gfHwgJycpO1xuICAgICAgICBpZiAoIWtleSkgcmV0dXJuO1xuICAgICAgICByZXN1bHRzW2tleV0gPSB2YWx1ZTtcbiAgICB9KTtcblxuICAgIHJldHVybiByZXN1bHRzO1xufVxuXG5cbi8qKlxuICogU2FmZSBKU09OLnBhcnNlLCByZXR1cm5zIHVuZGVmaW5lZCBpZiBKU09OLnBhcnNlIHRocm93cyBhbiBleGNlcHRpb25cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gc2VsZiBKU09OIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBvYmplY3RcbiAqIEByZXR1cm4ge09iamVjdHx1bmRlZmluZWR9XG4gKi9cbmZ1bmN0aW9uIGpzb25QYXJzZSgpIHtcbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZSh0aGlzKTtcbiAgICB9IGNhdGNoIChlKSB7fVxufVxuXG5cbi8qKlxuICogRGFuIEJlcm5zdGVpbidzIGFsZ29yeXRobSB0byBjcmVhdGUgaGFzaCBmcm9tIHN0cmluZ1xuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzZWxmIHN0cmluZyB0byBjb252ZXJ0IHRvIGhhc2hcbiAqIEByZXR1cm4ge051bWJlcn1cbiAqL1xuZnVuY3Rpb24gaGFzaENvZGUoKSB7XG4gICAgdmFyIGhhc2ggPSA1MzgxXG4gICAgICAgICwgc3RyID0gdGhpc1xuICAgICAgICAsIGxlbiA9IHN0ci5sZW5ndGg7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgICB2YXIgY2hhciA9IHN0ci5jaGFyQ29kZUF0KGkpO1xuICAgICAgICBoYXNoID0gKChoYXNoIDw8IDUpICsgaGFzaCkgKyBjaGFyOyAvKiBoYXNoICogMzMgKyBjICovXG4gICAgfVxuICAgIHJldHVybiBoYXNoO1xufVxuXG5cbi8qKlxuICogUmVtb3ZlcyBnaXZlbiBwcmVmaXggZnJvbSB0aGUgc3RyaW5nLiBJZiBzdHJpbmcgZG9lcyBub3QgYmVnaW4gZnJvbSB0aGUgcHJlZml4LCByZXR1cm5zIHVuZGVmaW5lZFxuICogXG4gKiBAcGFyYW0ge1N0cmluZ30gc2VsZlxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5mdW5jdGlvbiB1blByZWZpeChzdHIpIHtcbiAgICBpZiAodGhpcy5pbmRleE9mKHN0cikgPT0gMClcbiAgICAgICAgcmV0dXJuIHRoaXMucmVwbGFjZShzdHIsICcnKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiAtIFt0aW1lc10oI3RpbWVzKVxuICogLSBbcmVwZWF0XSgjcmVwZWF0KVxuICogLSBbdGFwXSgjdGFwKVxuICogLSBbcmVzdWx0XSgjcmVzdWx0KVxuICogLSBbaWRlbnRpdHldKCNpZGVudGl0eSlcbiAqIC0gW3Byb3BlcnR5XSgjcHJvcGVydHkpXG4gKiAtIFtjb21wYXJlUHJvcGVydHldKCNjb21wYXJlUHJvcGVydHkpXG4gKiAtIFtub29wXSgjbm9vcClcbiAqL1xudmFyIHV0aWxNZXRob2RzID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgdGltZXM6IHRpbWVzLFxuICAgIHJlcGVhdDogcmVwZWF0LFxuICAgIHRhcDogdGFwLFxuICAgIHJlc3VsdDogcmVzdWx0LFxuICAgIGlkZW50aXR5OiBpZGVudGl0eSxcbiAgICBwcm9wZXJ0eTogcHJvcGVydHksXG4gICAgY29tcGFyZVByb3BlcnR5OiBjb21wYXJlUHJvcGVydHksXG4gICAgbm9vcDogbm9vcFxufTtcblxuXG4vKipcbiAqIENhbGxzIGBjYWxsYmFja2AgYHNlbGZgIHRpbWVzIHdpdGggYHRoaXNBcmdgIGFzIGNvbnRleHQuIENhbGxiYWNrIGlzIHBhc3NlZCBpdGVyYXRpb24gaW5kZXggZnJvbSAwIHRvIGBzZWxmLTFgXG4gKiBcbiAqIEBwYXJhbSB7SW50ZWdlcn0gc2VsZlxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7QW55fSB0aGlzQXJnXG4gKiBAcmV0dXJuIHtBcnJheX1cbiAqL1xuZnVuY3Rpb24gdGltZXMoY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICB2YXIgYXJyID0gQXJyYXkoTWF0aC5tYXgoMCwgdGhpcykpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpczsgaSsrKVxuICAgICAgICBhcnJbaV0gPSBjYWxsYmFjay5jYWxsKHRoaXNBcmcsIGkpO1xuICAgIHJldHVybiBhcnI7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGFycmF5IHdpdGggdGhlIGZpcnN0IGFyZ3VtZW50IHJlcGVhdGVkIGB0aW1lc2AgdGltZXNcbiAqIEBwYXJhbSAge0FueX0gc2VsZlxuICogQHBhcmFtICB7SW50ZWdlcn0gdGltZXNcbiAqIEByZXR1cm4ge0FycmF5W0FueV19XG4gKi9cbmZ1bmN0aW9uIHJlcGVhdCh0aW1lcykge1xuICAgIHZhciBhcnIgPSBBcnJheShNYXRoLm1heCgwLCB0aW1lcykpOztcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRpbWVzOyBpKyspXG4gICAgICAgIGFycltpXSA9IHRoaXM7XG4gICAgcmV0dXJuIGFycjtcbn1cblxuXG4vKipcbiAqIEZ1bmN0aW9uIHRvIHRhcCBpbnRvIGNoYWluZWQgbWV0aG9kcyBhbmQgdG8gaW5zcGVjdCBpbnRlcm1lZGlhcnkgcmVzdWx0XG4gKlxuICogQHBhcmFtIHtBbnl9IHNlbGYgdmFsdWUgdGhhdCdzIHBhc3NlZCBiZXR3ZWVuIGNoYWluZWQgbWV0aG9kc1xuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgY2FsbGVkIHdpdGggdGhlIHZhbHVlIChib3RoIGFzIGNvbnRleHQgYW5kIGFzIHRoZSBmaXJzdCBwYXJhbWV0ZXIpXG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmZ1bmN0aW9uIHRhcChmdW5jKSB7XG4gICAgZnVuYy5jYWxsKHRoaXMsIHRoaXMpO1xuICAgIHJldHVybiB0aGlzO1xufTtcblxuXG4vKipcbiAqIENhbGxzIGZ1bmN0aW9uIGBzZWxmYCAoZmlyc3QgcGFyYW1ldGVyIG9mIF8ucmVzdWx0KSB3aXRoIGdpdmVuIGNvbnRleHQgYW5kIGFyZ3VtZW50c1xuICogXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufEFueX0gc2VsZlxuICogQHBhcmFtIHtBbnl9IHRoaXNBcmcgY29udGV4dFxuICogQHBhcmFtIHtMaXN0fSBhcmd1bWVudHMgZXh0cmEgYXJndW1lbnRzXG4gKiBAcmV0dXJuIHtBbnl9XG4gKi9cbmZ1bmN0aW9uIHJlc3VsdCh0aGlzQXJnKSB7IC8vLCBhcmd1bWVudHNcbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgcmV0dXJuIHR5cGVvZiB0aGlzID09ICdmdW5jdGlvbidcbiAgICAgICAgICAgID8gdGhpcy5hcHBseSh0aGlzQXJnLCBhcmdzKVxuICAgICAgICAgICAgOiB0aGlzO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBzZWxmLiBVc2VmdWwgZm9yIHVzaW5nIGFzIGFuIGl0ZXJhdG9yIGlmIHRoZSBhY3R1YWwgdmFsdWUgbmVlZHMgdG8gYmUgcmV0dXJuZWQuIFVubGlrZSBpbiB1bmRlcnNjb3JlIGFuZCBsb2Rhc2gsIHRoaXMgZnVuY3Rpb24gaXMgTk9UIHVzZWQgYXMgZGVmYXVsdCBpdGVyYXRvci5cbiAqXG4gKiBAcGFyYW0ge0FueX0gc2VsZiBcbiAqIEByZXR1cm4ge0FueX1cbiAqL1xuZnVuY3Rpb24gaWRlbnRpdHkoKSB7XG4gICAgcmV0dXJuIHRoaXM7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGZ1bmN0aW9uIHRoYXQgcGlja3MgdGhlIHByb3BlcnR5IGZyb20gdGhlIG9iamVjdFxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzZWxmXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gcHJvcGVydHkoKSB7XG4gICAgdmFyIGtleSA9IHRoaXM7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKG9iaikge1xuICAgICAgICByZXR1cm4gb2JqW2tleV07XG4gICAgfTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZCBpbiBhcnJheSBzb3J0IHRvIHNvcnQgYnkgYSBnaXZlbiBwcm9wZXJ0eVxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBzZWxmXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZnVuY3Rpb24gY29tcGFyZVByb3BlcnR5KCkge1xuICAgIHZhciBrZXkgPSB0aGlzO1xuICAgIHJldHVybiBmdW5jdGlvbihhLCBiKSB7XG4gICAgICAgIHJldHVybiBhW2tleV0gPCBiW2tleV1cbiAgICAgICAgICAgID8gLTFcbiAgICAgICAgICAgIDogYVtrZXldID4gYltrZXldXG4gICAgICAgICAgICAgICAgPyAxXG4gICAgICAgICAgICAgICAgOiAwO1xuICAgIH07XG59XG5cblxuLyoqXG4gKiBGdW5jdGlvbiB0aGF0IGRvZXMgbm90aGluZ1xuICovXG5mdW5jdGlvbiBub29wKCkge31cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHV0aWxzID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgbWFrZVByb3RvSW5zdGFuY2VNZXRob2Q6IG1ha2VQcm90b0luc3RhbmNlTWV0aG9kLFxuICAgIG1ha2VQcm90b0Z1bmN0aW9uOiBtYWtlUHJvdG9GdW5jdGlvbixcbiAgICBtYWtlRmluZE1ldGhvZDogbWFrZUZpbmRNZXRob2Rcbn1cblxuXG5mdW5jdGlvbiBtYWtlUHJvdG9JbnN0YW5jZU1ldGhvZChtZXRob2QpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIHRoaXMuc2VsZiA9IG1ldGhvZC5hcHBseSh0aGlzLnNlbGYsIGFyZ3VtZW50cyk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG59XG5cblxuZnVuY3Rpb24gbWFrZVByb3RvRnVuY3Rpb24obWV0aG9kKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICAvLyB3aGVuIHRoZSBtZXRob2QgaXMgZXhlY3V0ZWQsIHRoZSB2YWx1ZSBvZiBcInRoaXNcIiB3aWxsIGJlIGFyZ3VtZW50c1swXSxcbiAgICAgICAgLy8gb3RoZXIgYXJndW1lbnRzIHN0YXJ0aW5nIGZyb20gIzEgd2lsbCBwYXNzZWQgdG8gbWV0aG9kIGFzIHBhcmFtZXRlcnMuXG4gICAgICAgIHJldHVybiBtZXRob2QuY2FsbC5hcHBseShtZXRob2QsIGFyZ3VtZW50cyk7XG4gICAgfTtcbn1cblxuXG52YXIgX2Vycm9yID0gbmV3IEVycm9yO1xuXG4vKipcbiAqIFJldHVybnMgYGZpbmRgIG9yIGBmaW5kSW5kZXhgIG1ldGhvZCwgZGVwZW5kaW5nIG9uIHBhcmFtZXRlclxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVhY2hNZXRob2QgLSBtZXRob2QgdG8gdXNlIGZvciBpdGVyYXRpb24gKGZvckVhY2ggZm9yIGFycmF5IG9yIGVhY2hLZXkgZm9yIG9iamVjdClcbiAqIEBwYXJhbSB7U3RyaW5nfSBmaW5kV2hhdCAndmFsdWUnIC0gcmV0dXJucyBmaW5kIG1ldGhvZCBvZiBBcnJheSAoaW1wbGVtZW50ZWQgaW4gRVM2KSBvciBmaW5kVmFsdWUgbWV0aG9kIG9mIE9iamVjdCwgYW55dGhpbmcgZWxzZSA9IHJldHVybnMgZmluZEluZGV4L2ZpbmRLZXkgbWV0aG9kcy5cbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBtYWtlRmluZE1ldGhvZChlYWNoTWV0aG9kLCBmaW5kV2hhdCkge1xuICAgIHZhciBhcmdJbmRleCA9IGZpbmRXaGF0ID09ICd2YWx1ZScgPyAwIDogMTtcblxuICAgIHJldHVybiBmdW5jdGlvbiBmaW5kVmFsdWVPckluZGV4KGNhbGxiYWNrLCB0aGlzQXJnLCBvbmx5RW51bWVyYWJsZSkge1xuICAgICAgICB2YXIgY2F1Z2h0RXJyb3I7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBlYWNoTWV0aG9kLmNhbGwodGhpcywgdGVzdEl0ZW0sIHRoaXNBcmcsIG9ubHlFbnVtZXJhYmxlKTtcbiAgICAgICAgfSBjYXRjaCAoZm91bmQpIHtcbiAgICAgICAgICAgIGlmIChmb3VuZCA9PT0gX2Vycm9yKSB0aHJvdyBjYXVnaHRFcnJvcjtcbiAgICAgICAgICAgIGVsc2UgcmV0dXJuIGZvdW5kO1xuICAgICAgICB9XG4gICAgICAgIC8vIGlmIGxvb2tpbmcgZm9yIGluZGV4IGFuZCBub3QgZm91bmQsIHJldHVybiAtMVxuICAgICAgICBpZiAoYXJnSW5kZXggJiYgZWFjaE1ldGhvZCA9PSBBcnJheS5wcm90b3R5cGUuZm9yRWFjaClcbiAgICAgICAgICAgIHJldHVybiAtMTsgXG5cbiAgICAgICAgZnVuY3Rpb24gdGVzdEl0ZW0odmFsdWUsIGluZGV4LCBzZWxmKSB7XG4gICAgICAgICAgICB2YXIgdGVzdDtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdGVzdCA9IGNhbGxiYWNrLmNhbGwodGhpcywgdmFsdWUsIGluZGV4LCBzZWxmKTtcbiAgICAgICAgICAgIH0gY2F0Y2goZXJyKSB7XG4gICAgICAgICAgICAgICAgY2F1Z2h0RXJyb3IgPSBlcnI7XG4gICAgICAgICAgICAgICAgdGhyb3cgX2Vycm9yO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRlc3QpXG4gICAgICAgICAgICAgICAgdGhyb3cgYXJndW1lbnRzW2FyZ0luZGV4XTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiJdfQ==
;
\ No newline at end of file
diff --git a/milo.bundle.map b/milo.bundle.map
index 765d7fd..d2ec26a 100644
--- a/milo.bundle.map
+++ b/milo.bundle.map
@@ -3,7 +3,6 @@
"sources": [
"/Users/evgenypoberezkin/Work/CC/milo/lib/abstract/facet.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/abstract/faceted_object.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/abstract/mixin.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/abstract/registry.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/attributes/a_bind.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/attributes/a_class.js",
@@ -67,20 +66,7 @@
"/Users/evgenypoberezkin/Work/CC/milo/lib/components/ui/bootstrap/Dropdown.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/config.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/loader.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/messenger/index.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/messenger/m_api.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/messenger/m_api_rx.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/messenger/m_source.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/messenger/msngr_source.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/milo.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/model/change_data.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/model/index.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/model/m_msg_api.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/model/m_path.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/model/model_utils.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/model/path_msg_api.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/model/path_utils.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/model/synthesize/index.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/registry.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/services/de_constrs.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/services/dom_source.js",
@@ -90,7 +76,6 @@
"/Users/evgenypoberezkin/Work/CC/milo/lib/services/window.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/use_components.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/use_facets.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/util/check.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/util/component_name.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/util/count.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/util/create_component_class.js",
@@ -102,8 +87,6 @@
"/Users/evgenypoberezkin/Work/CC/milo/lib/util/fragment.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/util/index.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/util/json_parse.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/util/logger.js",
- "/Users/evgenypoberezkin/Work/CC/milo/lib/util/logger_class.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/util/request.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/util/selection/index.js",
"/Users/evgenypoberezkin/Work/CC/milo/lib/util/storage/index.js",
@@ -114,8 +97,6 @@
"/Users/evgenypoberezkin/Work/CC/milo/lib/util/websocket/msg_src.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/base32/lib/base32.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/browserify/node_modules/browser-builtins/builtin/fs.js",
- "/Users/evgenypoberezkin/Work/CC/milo/node_modules/dot/doT.js",
- "/Users/evgenypoberezkin/Work/CC/milo/node_modules/dot/index.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/abstract/mixin.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/classes.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/config.js",
@@ -131,6 +112,7 @@
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/model/index.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/model/m_msg_api.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/model/m_path.js",
+ "/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/model/model_utils.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/model/path_msg_api.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/model/path_utils.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/model/synthesize/index.js",
@@ -138,6 +120,8 @@
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/util/index.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/util/logger.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/lib/util/logger_class.js",
+ "/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/node_modules/dot/doT.js",
+ "/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/node_modules/dot/index.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/node_modules/mol-proto/lib/proto.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/node_modules/mol-proto/lib/proto_array.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/node_modules/mol-proto/lib/proto_function.js",
@@ -146,154 +130,134 @@
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/node_modules/mol-proto/lib/proto_prototype.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/node_modules/mol-proto/lib/proto_string.js",
"/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/node_modules/mol-proto/lib/proto_util.js",
- "/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/node_modules/mol-proto/lib/utils.js",
- "/Users/evgenypoberezkin/Work/CC/milo/node_modules/mol-proto/lib/proto.js",
- "/Users/evgenypoberezkin/Work/CC/milo/node_modules/mol-proto/lib/proto_array.js",
- "/Users/evgenypoberezkin/Work/CC/milo/node_modules/mol-proto/lib/proto_prototype.js",
- "/Users/evgenypoberezkin/Work/CC/milo/node_modules/mol-proto/lib/proto_string.js"
+ "/Users/evgenypoberezkin/Work/CC/milo/node_modules/milo-core/node_modules/mol-proto/lib/utils.js"
],
"names": [],
- "mappings": ";AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACz5BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9aA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9mBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1OA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3HA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9ZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnMA;AACA;AACA;AACA;AACA;;ACJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvpBA;;ACAA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9KA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3ZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7NA;;ACAA;;;;ACAA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1MA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;;ACAA;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvYA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACznBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/DA;;ACAA;;;;;;;;ACAA;;ACAA",
+ "mappings": ";AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACx5BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9aA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/mBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACfA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7ZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnMA;AACA;AACA;AACA;AACA;;ACJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3ZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3HA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvYA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACznBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA",
"file": "generated.js",
"sourceRoot": "",
"sourcesContent": [
- "'use strict';\n\n\nvar _ = require('mol-proto');\n\nmodule.exports = Facet;\n\n\n/**\n * `milo.classes.Facet`\n * Base Facet class is an ancestor of [ComponentFacet](../components/c_facet.js.html) class, the main building block in milo.\n * \n * @param {FacetedObject} owner an instance of FacetedObject subclass that stores the facet on its property with the same name as `name` property of facet\n * @param {Object} config optional facet configuration, used in subclasses\n */\nfunction Facet(owner, config) {\n this.name = _.firstLowerCase(this.constructor.name);\n this.owner = owner;\n this.config = config || {};\n this.init.apply(this, arguments);\n}\n\n\n/**\n * `init` method of subclass will be called by Facet constructor.\n */\n_.extendProto(Facet, {\n init: function() {}\n});\n",
- "'use strict';\n\n\nvar Facet = require('./facet')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match\n , FacetError = require('../util/error').Facet;\n\nmodule.exports = FacetedObject;\n\n\n/**\n * `milo.classes.FacetedObject`\n * Component class is based on an abstract ```FacetedObject``` class. This class can be used in any situation where objects can be represented via collection of facets (a facet is an object of a certain class, it holds its own configuration, data and methods).\n * In a way, \"facets pattern\" is an inversion of \"adapter pattern\" - while the latter allows finding a class/methods that has specific functionality, faceted object is simply constructed to have these functionalities.\n * With this architecture it is possible to create a virtually unlimited number of component classes with a very limited number of building blocks without having any hierarchy of classes - all components inherit directly from Component class.\n *\n * This constructor should be called by all subclasses constructor (it will happen automatically if a subclass is created with `_.createSubclass`).\n *\n * @return {FacetedObject}\n */\nfunction FacetedObject() {\n // this.facetsConfig and this.facetsClasses were stored on a specific class prototype\n // when the class was created by FacetedObject.createFacetedClass\n var facetsConfig = this.facetsConfig || {};\n\n var facetsDescriptors = {}\n , facets = {};\n\n // FacetedObject class itself is not meant to be instantiated - it has no facets\n // It may change, as adding facets is possible to instances\n if (this.constructor == FacetedObject) \n throw new FacetError('FacetedObject is an abstract class, can\\'t be instantiated');\n\n // instantiate class facets\n if (this.facetsClasses)\n _.eachKey(this.facetsClasses, instantiateFacet, this, true);\n\n // add facets to the class as properties under their own name\n Object.defineProperties(this, facetsDescriptors);\n\n // store all facets on `facets` property so that they can be enumerated\n _.defineProperty(this, 'facets', facets); \n\n // call `init`method if it is defined in subclass\n if (this.init)\n this.init.apply(this, arguments);\n\n // instantiate facet with a given class (FacetClass) and name (facetName)\n function instantiateFacet(FacetClass, facetName) {\n // get facet configuration\n var fctConfig = facetsConfig[facetName];\n\n // instatiate facets\n facets[facetName] = new FacetClass(this, fctConfig);\n\n // add facet to property descriptors\n facetsDescriptors[facetName] = {\n enumerable: true,\n value: facets[facetName]\n };\n }\n}\n\n\n/**\n * ####FacetedObject class methods####\n *\n * - [createFacetedClass](#FacetedObject$$createFacetedClass)\n * - [hasFacet](#FacetedObject$$hasFacet)\n */\n_.extend(FacetedObject, {\n createFacetedClass: FacetedObject$$createFacetedClass,\n hasFacet: FacetedObject$$hasFacet,\n getFacetConfig: FacetedObject$$getFacetConfig\n});\n\n\n/**\n * ####FacetedObject instance methods####\n *\n * - [addFacet](#FacetedObject$addFacet)\n */\n_.extendProto(FacetedObject, {\n addFacet: FacetedObject$addFacet\n});\n\n\n/**\n * FacetedObject instance method.\n * Adds a facet to the instance of FacetedObject subclass.\n * Returns an instance of the facet that was created.\n *\n * @param {Function} FacetClass facet class constructor\n * @param {Object} facetConfig optional facet configuration\n * @param {String} facetName optional facet name, FacetClass.name will be used if facetName is not passed.\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n * @return {Facet}\n */\nfunction FacetedObject$addFacet(FacetClass, facetConfig, facetName, throwOnErrors) {\n check(FacetClass, Function);\n check(facetName, Match.Optional(String));\n\n // first letter of facet name should be lowercase\n facetName = _.firstLowerCase(facetName || FacetClass.name);\n\n // get facets defined in class\n var protoFacets = this.constructor.prototype.facetsClasses;\n\n // check that this facetName was not already used in the class\n if (protoFacets && protoFacets[facetName])\n throw new FacetError('facet ' + facetName + ' is already part of the class ' + this.constructor.name);\n\n // check that this faceName does not already exist on the faceted object\n if (this[facetName]) {\n var message = 'facet ' + facetName + ' is already present in object';\n if (throwOnErrors === false)\n return logger.error('FacetedObject addFacet: ', message);\n else\n throw new FacetError(message);\n }\n\n // instantiate the facet\n var newFacet = this.facets[facetName] = new FacetClass(this, facetConfig);\n\n // add facet to faceted object\n _.defineProperty(this, facetName, newFacet, _.ENUM);\n\n return newFacet;\n}\n\n\n/**\n * FacetedObject class method\n * Returns reference to the facet class if the facet with `facetName` is part of the class, `undefined` otherwise. If subclass is created using _.createSubclass (as it should be) it will also have this method.\n * \n * @param {Subclass(FacetedObject)} this this in this method refers to FacetedObject (or its subclass) that calls this method\n * @param {String} facetName\n * @return {Subclass(Facet)|undefined} \n */\nfunction FacetedObject$$hasFacet(facetName) {\n // this refers to the FacetedObject class (or subclass), not instance\n var protoFacets = this.prototype.facetsClasses;\n return protoFacets && protoFacets[facetName];\n}\n\n/**\n * FacetedObject class method\n * Return the configuration of a facet\n * @param {String} facetName the facet which config should be retrieved\n * @return {Object} the configuration object that was passed to the facet\n */\nfunction FacetedObject$$getFacetConfig(facetName) {\n return this.hasFacet(facetName) ? this.prototype.facetsConfig[facetName] : null;\n}\n\n\n/**\n * FacetedObject class method\n * Class factory that creates classes (constructor functions) from the maps of facets and their configurations.\n * Created class will be subclass of `FacetedObject`.\n *\n * @param {Subclass(FacetedObject)} this this in this method refers to FacetedObject (or its subclass) that calls this method\n * @param {String} name class name (will be function name of class constructor function)\n * @param {Object[Subclass(Facet)]} facetsClasses map of classes of facets that will constitute the created class\n * @param {Object[Object]} facetsConfig map of facets configuration, should have the same keys as the map of classes. Some facets may not have configuration, but the configuration for a facet that is not included in facetsClasses will throw an exception\n * @return {Subclass(FacetedObject)}\n */\nfunction FacetedObject$$createFacetedClass(name, facetsClasses, facetsConfig) {\n check(name, String);\n check(facetsClasses, Match.Optional(Match.ObjectHash(Match.Subclass(Facet, true))));\n check(facetsConfig, Match.Optional(Object));\n\n // throw exception if config passed for facet for which there is no class\n if (facetsConfig)\n _.eachKey(facetsConfig, function(fctConfig, fctName) {\n if (! facetsClasses.hasOwnProperty(fctName))\n throw new FacetError('configuration for facet (' + fctName + ') passed that is not in class');\n });\n\n // create subclass of the current class (this refers to the class that calls this method)\n var FacetedClass = _.createSubclass(this, name, true);\n\n // get facets classes and configurations from parent class\n facetsClasses = addInheritedFacets(this, facetsClasses, 'facetsClasses');\n facetsConfig = addInheritedFacets(this, facetsConfig, 'facetsConfig');\n\n // store facets classes and configurations of class prototype\n _.extendProto(FacetedClass, {\n facetsClasses: facetsClasses,\n facetsConfig: facetsConfig\n });\n\n return FacetedClass;\n\n\n function addInheritedFacets(superClass, facetsInfo, facetsInfoName) {\n var inheritedFacetsInfo = superClass.prototype[facetsInfoName];\n if (inheritedFacetsInfo)\n return _(inheritedFacetsInfo)\n .clone()\n .extend(facetsInfo || {})._();\n else\n return facetsInfo;\n }\n};\n",
- "'use strict';\n\nvar _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match\n , MixinError = require('../util/error').Mixin\n , config = require('../config');\n\n\nmodule.exports = Mixin;\n\n/**\n * `milo.classes.Mixin` - an abstract Mixin class.\n * Can be subclassed using:\n * ```\n * var MyMixin = _.createSubclass(milo.classes.Mixin, 'MyMixin');\n * ```\n *\n * Mixin pattern is also used, but Mixin in milo is implemented as a separate object that is stored on the property of the host object and can create proxy methods on the host object if required.\n * Classes [Messenger](../messenger/index.js.html) and [MessageSource](../messenger/m_source.js.html) are subclasses of Mixin abstract class. `this` in proxy methods refers to Mixin instance, the reference to the host object is `this._hostObject`.\n *\n * @param {Object} hostObject Optional object where a Mixin instance will be stored on. It is used to proxy methods and also to find the reference when it is needed for host object implementation.\n * @param {Object} proxyMethods Optional map of proxy method names as keys and Mixin methods names as values, so proxied methods can be renamed to avoid name-space conflicts if two different Mixin instances with the same method names are put on the object\n * @param {List} arguments all constructor arguments will be passed to init method of Mixin subclass together with hostObject and proxyMethods\n * @return {Mixin}\n */\nfunction Mixin(hostObject, proxyMethods) { // , other args - passed to init method\n check(hostObject, Match.Optional(Match.OneOf(Object, Function)));\n\n // store hostObject\n _.defineProperty(this, '_hostObject', hostObject);\n\n // proxy methods to hostObject\n if (proxyMethods)\n this._createProxyMethods(proxyMethods);\n\n // calling init if it is defined in the class\n if (this.init)\n this.init.apply(this, arguments);\n}\n\n\n/**\n * ####Mixin instance methods####\n * These methods are called by constructor, they are not to be called from subclasses.\n *\n * - [_createProxyMethod](#_createProxyMethod)\n * - [_createProxyMethods](#_createProxyMethods)\n */\n_.extendProto(Mixin, {\n _createProxyMethod: _createProxyMethod, // deprecated, should not be used\n _createProxyMethods: _createProxyMethods // deprecated, should not be used\n});\n\n\n/**\n * ####Mixin class methods####\n * These method should be called in host class declaration.\n *\n * - [useWith](#Mixin$$useWith)\n */\n_.extend(Mixin, {\n useWith: Mixin$$useWith\n});\n\n\n/**\n * Creates a proxied method of Mixin subclass on host object.\n *\n * @param {String} mixinMethodName name of method in Mixin subclass\n * @param {String} proxyMethodName name of created proxy method on host object\n * @param {Object} hostObject Optional reference to the host object; if not specified the host object passed to constructor wil be used. It allows to use the same instance of Mixin on two host objects.\n */\nfunction _createProxyMethod(proxyMethodName, mixinMethodName, hostObject) {\n hostObject = hostObject || this._hostObject;\n\n // Mixin class does not allow shadowing methods that exist on the host object\n if (hostObject[proxyMethodName])\n throw new MixinError('method ' + proxyMethodName +\n ' already defined in host object');\n\n var method = this[mixinMethodName]\n check(method, Function);\n\n // Bind proxied Mixin's method to Mixin instance\n var boundMethod = method.bind(this);\n\n _.defineProperty(hostObject, proxyMethodName, boundMethod, _.WRIT);\n}\n\n\n/**\n * Creates proxied methods of Mixin subclass on host object.\n *\n * @param {Hash[String]|Array[String]} proxyMethods map of names of methods, key - proxy method name, value - mixin method name. Can be array.\n * @param {Object} hostObject an optional reference to the host object; if not specified the host object passed to constructor wil be used. It allows to use the same instance of Mixin on two host objects.\n */\nfunction _createProxyMethods(proxyMethods, hostObject) {\n check(proxyMethods, Match.Optional(Match.OneOf([String], Match.ObjectHash(String))));\n\n // creating and binding proxy methods on the host object\n if (Array.isArray(proxyMethods))\n proxyMethods.forEach(function(methodName) {\n // method called this way to allow using _createProxyMethods with objects\n // that are not inheriting from Mixin\n _createProxyMethod.call(this, methodName, methodName, hostObject);\n }, this);\n else\n _.eachKey(proxyMethods, function(mixinMethodName, proxyMethodName) {\n // method called this way to allow using _createProxyMethods with objects\n // that are not inheriting from Mixin\n _createProxyMethod.call(this, proxyMethodName, mixinMethodName, hostObject);\n }, this);\n}\n\n\n/**\n * Sets mixin instance property name on the host class\n * Can be called only once\n *\n * @private\n * @param {Function} this Mixin subclass (not instance)\n * @param {Function} hostClass\n * @param {String} instanceKey\n */\nfunction Mixin_setInstanceKey(hostClass, method, instanceKey) {\n check(hostClass, Function);\n check(instanceKey, Match.IdentifierString);\n\n var prop = config.mixin.instancePropertiesMap\n , instanceKeys = hostClass[prop] = hostClass[prop] || {};\n\n if (instanceKeys[method.name])\n throw new Error('Mixin: instance property for method with name '\n + method.name + ' is already set');\n\n instanceKeys[method.name] = instanceKey;\n}\n\n\n/**\n * Adds method of Mixin subclass to host class prototype.\n *\n * @private\n * @param {Function} this Mixin subclass (not instance)\n * @param {String} mixinMethodName name of method in Mixin subclass\n * @param {String} hostMethodName (optional) name of created proxy method on host object, same if not specified\n * @param {Object} hostObject object class, must be specified as the last parameter (2nd or 3rd)\n */\nfunction Mixin_addMethod(hostClass, instanceKey, mixinMethodName, hostMethodName) {\n var method = this.prototype[mixinMethodName];\n check(method, Function);\n\n var wrappedMethod = _wrapMixinMethod.call(this, method);\n\n _.defineProperty(hostClass.prototype, hostMethodName, wrappedMethod, _.WRIT);\n\n Mixin_setInstanceKey(hostClass, method, instanceKey)\n}\n\n\n/**\n * Returns method that will be exposed on the host class prototype\n *\n * @private\n * @param {Function} this Mixin subclass (not instance)\n * @return {Function}\n */\nfunction _wrapMixinMethod(method) {\n return function() { // ,... arguments\n var mixinInstance = _getMixinInstance.call(this, method.name);\n return method.apply(mixinInstance, arguments);\n }\n}\n\n\n/**\n * Returns the reference to the instance of mixin subclass.\n * This method is used when methods are exposed on the host class prototype (using addMehtods) rather than on host instance.\n * Subclasses should not use this methods - whenever subclass method is exposed on the prototype it will be wrapped to set correct context for the subclass method.\n *\n * @private\n * @return {Object}\n */\nfunction _getMixinInstance(methodName) {\n if (this instanceof Mixin) return this;\n var instanceKeys = this.constructor[config.mixin.instancePropertiesMap]\n return this[instanceKeys[methodName]];\n}\n\n\n/**\n * Adds methods of Mixin subclass to host class prototype.\n *\n * @param {Function} this Mixin subclass (not instance)\n * @param {Object} hostClass host object class; must be specified.\n * @param {String} instanceKey the name of the property the host class instance will store mixin instance on\n * @param {Hash[String]|Array[String]} mixinMethods map of names of methods, key - host method name, value - mixin method name. Can be array.\n */\nfunction Mixin$$useWith(hostClass, instanceKey, mixinMethods) {\n check(mixinMethods, Match.Optional(Match.OneOf([String], Match.ObjectHash(String))));\n\n if (Array.isArray(mixinMethods))\n mixinMethods.forEach(function(methodName) {\n Mixin_addMethod.call(this, hostClass, instanceKey, methodName, methodName);\n }, this);\n else\n _.eachKey(mixinMethods, function(mixinMethodName, hostMethodName) {\n Mixin_addMethod.call(this, hostClass, instanceKey, mixinMethodName, hostMethodName);\n }, this);\n}\n",
- "'use strict';\n\nvar _ = require('mol-proto')\n , RegistryError = require('../util/error').Registry\n , check = require('../util/check')\n , Match = check.Match;\n\nmodule.exports = ClassRegistry;\n\n\n/**\n * `milo.classes.ClassRegistry` - the registry of classes class.\n * Components and Facets register themselves in registries. It allows to avoid requiring them from one module and prevents circular dependencies between modules.\n * \n * @param {Function} FoundationClass All classes that are registered in the registry should be subclasses of the FoundationClass\n * @return {Object}\n */\nfunction ClassRegistry (FoundationClass) {\n if (FoundationClass)\n this.setClass(FoundationClass);\n\n this.__registeredClasses = {};\n}\n\n\n/**\n * ####ClassRegistry instance methods####\n *\n * - [add](#add)\n * - [get](#get)\n * - [remove](#remove)\n * - [clean](#clean)\n * - [setClass](#setClass)\n */\n_.extendProto(ClassRegistry, {\n add: add,\n get: get,\n remove: remove,\n clean: clean,\n setClass: setClass\n});\n\n\n/**\n * ClassRegistry instance method that registers a class in the registry.\n * The method will throw an exception if a class is registered under the same name as previously registered class.\n * The method allows registering the same class under a different name, so class aliases can be created.\n *\n * @param {Function} aClass class to register in the registry. Should be subclass of `this.FoundationClass`.\n * @param {String} name Optional class name. If class name is not specified, it will be taken from constructor function name. Class name should be a valid identifier and cannot be an empty string.\n */\nfunction add(aClass, name) {\n name = name || aClass.name;\n\n check(name, Match.IdentifierString, 'class name must be identifier string');\n\n if (this.FoundationClass) {\n if (aClass != this.FoundationClass)\n check(aClass, Match.Subclass(this.FoundationClass), 'class must be a sub(class) of a foundation class');\n } else\n throw new RegistryError('foundation class must be set before adding classes to registry');\n\n if (this.__registeredClasses[name])\n throw new RegistryError('class \"' + name + '\" is already registered');\n\n this.__registeredClasses[name] = aClass;\n};\n\n\n/**\n * Gets class from registry by name\n *\n * @param {String} name Class name\n * @return {Function}\n */\nfunction get(name) {\n check(name, String, 'class name must be string');\n return this.__registeredClasses[name];\n};\n\n\n/**\n * Remove class from registry by its name.\n * If class is not registered, this method will throw an exception.\n * \n * @param {String|Function} nameOrClass Class name. If class constructor is supplied, its name will be used.\n */\nfunction remove(nameOrClass) {\n check(nameOrClass, Match.OneOf(String, Function), 'class or name must be supplied');\n\n var name = typeof nameOrClass == 'string'\n ? nameOrClass\n : nameOrClass.name;\n \n if (! this.__registeredClasses[name])\n throw new RegistryError('class is not registered');\n\n delete this.__registeredClasses[name];\n};\n\n\n/**\n * Removes all classes from registry.\n */\nfunction clean() {\n this.__registeredClasses = {};\n};\n\n\n/**\n * Sets `FoundationClass` of the registry. It should be set before any class can be added.\n *\n * @param {Function} FoundationClass Any class that will be added to the registry should be a subclass of this class. FoundationClass itself can be added to the registry too.\n */\nfunction setClass(FoundationClass) {\n check(FoundationClass, Function);\n _.defineProperty(this, 'FoundationClass', FoundationClass, _.ENUM);\n}\n",
- "'use strict';\n\nvar Attribute = require('./a_class')\n , AttributeError = require('../util/error').Attribute\n , config = require('../config')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match;\n\n\nvar ATTRIBUTE_REGEXP= /^([^\\:\\[\\]]*)(?:\\[([^\\:\\[\\]]*)\\])?\\:?([^:]*)$/\n , FACETS_SPLIT_REGEXP = /\\s*(?:\\,|\\s)\\s*/\n , ATTRIBUTE_TEMPLATE = '%compClass%compFacets:%compName';\n\n\n/**\n * `milo.attributes.bind`\n * BindAttribute class parses/validates/etc. an attribute that binds DOM elements to milo components.\n * Possible attribute values are:\n *\n * - `:myView` - only component name\n * - `View:myView` - class and component name\n * - `[Events, Data]:myView` - facets and component name\n * - `View[Events]:myView` - class, facet(s) and component name\n *\n * See [binder](../binder.js.html) for more information.\n */\nvar BindAttribute = _.createSubclass(Attribute, 'BindAttribute', true);\n\n\n/**\n * ####BindAttribute instance methods####\n *\n * - [attrName](#attrName)\n * - [parse](#parse)\n * - [validate](#validate)\n * - [render](#render)\n */\n_.extendProto(BindAttribute, {\n attrName: attrName,\n parse: parse,\n validate: validate,\n render: render\n});\n\n\n/**\n * BindAttribute class methods\n *\n * - [setInfo](#BindAttribute$$setInfo)\n */\n_.extend(BindAttribute, {\n setInfo: BindAttribute$$setInfo\n});\n\n\nmodule.exports = BindAttribute;\n\n\n/**\n * BindAttribute instance method that returns attribute name, by default - `'ml-bind'`.\n * To configure bind attribute name use:\n * ```\n * milo.config({ attrs: { bind: 'cc-bind' } }); // will set bind attribute to 'cc-bind'\n * ```\n *\n * @return {String}\n */\nfunction attrName() {\n return config.attrs.bind;\n}\n\n\n/**\n * BindAttribute instance method that parses bind attribute if it is present on the element.\n * It defines properties `compClass`, `compFacets` and `compName` on BindAttribute instance.\n * Returns the instance for method chaining.\n *\n * @return {BindAttribute}\n */\n function parse() {\n if (! this.node) return;\n\n var value = this.get();\n\n if (value)\n var bindTo = value.match(ATTRIBUTE_REGEXP);\n\n if (! bindTo)\n throw new AttributeError('invalid bind attribute ' + value);\n\n this.compClass = bindTo[1] || 'Component';\n this.compFacets = (bindTo[2] && bindTo[2].split(FACETS_SPLIT_REGEXP)) || undefined;\n this.compName = bindTo[3] || undefined; // undefined is not same as ''\n\n return this;\n}\n\n\n/**\n * BindAttribute instance method that validates bind attribute, throws if it has an invalid value.\n * Returns the instance for method chaining.\n *\n * @return {BindAttribute}\n */\nfunction validate() {\n check(this.compName, Match.IdentifierString);\n\n if (! this.compClass)\n throw new AttributeError('empty component class name ' + this.compClass);\n\n return this;\n}\n\n\n/**\n * BindAttribute instance method that returns the attribute value for given values of properties `compClass`, `compName` and `compFacets`.\n * If `this.compName` is not set it will be generated automatically.\n *\n * @return {String}\n */\nfunction render() {\n this.compName = this.compName || milo.util.componentName();\n return ATTRIBUTE_TEMPLATE\n .replace('%compClass', this.compClass || '')\n .replace('%compFacets', this.compFacets && this.compFacets.length\n ? '[' + this.compFacets.join(', ') + ']'\n : '')\n .replace('%compName', this.compName);\n}\n\n\n/**\n * BindAttribute class method\n * @param {Element} el\n * @param {String} componentClass optional class name\n * @param {String} componentName optional\n * @param {Array} componentFacets optional extra facet to add to the class\n */\nfunction BindAttribute$$setInfo(el, componentClass, componentName, componentFacets) {\n var attr = new BindAttribute(el);\n _.extend(attr, {\n compClass: componentClass,\n compName: componentName,\n compFacets: componentFacets\n });\n attr.decorate();\n}\n",
- "'use strict';\n\nvar _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match\n , toBeImplemented = require('../util/error').toBeImplemented;\n\n\nmodule.exports = Attribute;\n\n\n/**\n * An absctract class for parsing and validation of element attributes.\n * Subclasses should define methods `attrName`, `parse`, `validate` and `render`.\n *\n * @param {Element} el DOM element where attribute is attached\n * @param {String} name Optional name of the attribute, usually supplied by subclass via `attrName` method\n */\nfunction Attribute(el, name) {\n this.name = name || this.attrName();\n this.el = el;\n\n // attribute node\n this.node = el.attributes[this.name];\n}\n\n\n_.extend(Attribute, {\n remove: Attribute$$remove\n});\n\n\n/**\n * ####Attribute instance methods####\n *\n * - [get](#Attribute$get)\n * - [set](#Attribute$set)\n * - [decorate](#Attribute$decorate)\n *\n * The following instance methods should be defined by subclass\n *\n * - attrName - should return attribute name\n * - parse - should parse attribute value\n * - validate - should validate attribute value, throwing exception if it is incorrect \n * - render - should return attribute value for a given attribute state (other properties, as defined in subclass)\n */\n_.extendProto(Attribute, {\n get: Attribute$get,\n set: Attribute$set,\n remove: Attribute$remove,\n decorate: Attribute$decorate,\n\n destroy: Attribute$destroy,\n\n // should be defined in subclass\n attrName: toBeImplemented,\n parse: toBeImplemented,\n validate: toBeImplemented,\n render: toBeImplemented\n});\n\n\nfunction Attribute$$remove(el, deep) {\n var name = this.prototype.attrName();\n el.removeAttribute(name);\n\n if (deep) {\n var selector = '[' + name + ']';\n var children = el.querySelectorAll(selector);\n _.forEach(children, function(childEl) {\n childEl.removeAttribute(name);\n })\n }\n}\n\n\nfunction Attribute$remove() {\n delete this.node;\n}\n\n\nfunction Attribute$destroy() {\n delete this.el;\n delete this.node;\n}\n\n/**\n * Attribute instance method that returns attribute value as string.\n *\n * @return {String}\n */\nfunction Attribute$get() {\n return this.el.getAttribute(this.name);\n}\n\n\n/**\n * Attribute instance method that sets attribute value.\n *\n * @param {String} value\n */\nfunction Attribute$set(value) {\n this.el.setAttribute(this.name, value);\n}\n\n\n/**\n * Attribute instance method that decorates element with its rendered value.\n * Uses `render` method that should be defiend in subclass.\n */\nfunction Attribute$decorate() {\n this.set(this.render());\n}\n",
- "'use strict';\n\nvar Attribute = require('./a_class')\n , AttributeError = require('../util/error').Attribute\n , config = require('../config')\n , _ = require('mol-proto');\n\n\n/**\n * `milo.attributes.load`\n * LoadAttribute class parses/validates/etc. an attribute that loads sub-views into the page.\n * Attribute value should be URL of the file to load subview from.\n * See [loader](../loader.js.html) for more information.\n */\nvar LoadAttribute = _.createSubclass(Attribute, 'LoadAttribute', true);\n\n\n/**\n * ####LoadAttribute instance methods####\n *\n * - [attrName](#attrName)\n * - [parse](#parse)\n * - [validate](#validate)\n * - [render](#render)\n */\n_.extendProto(LoadAttribute, {\n attrName: attrName,\n parse: parse,\n validate: validate,\n render: render\n});\n\nmodule.exports = LoadAttribute;\n\n\n/**\n * BindAttribute instance method that returns attribute name, by default - `'ml-load'`.\n * To configure load attribute name use:\n * ```\n * milo.config({ attrs: { load: 'cc-load' } }); // will set bind attribute to 'cc-load'\n * ```\n *\n * @return {String}\n */\nfunction attrName() {\n return config.attrs.load;\n}\n\n\n/**\n * LoadAttribute instance method that parses load attribute if it is present on the element.\n * It defines property `loadUrl` on LoadAttribute instance.\n * Returns the instance for method chaining.\n *\n * @return {LoadAttribute}\n */\nfunction parse() {\n if (! this.node) return;\n\n this.loadUrl = this.get();\n return this;\n}\n\n\n/**\n * LoadAttribute instance method that should validate load attribute and throw if it has an invalid value.\n * TODO - implement url validation.\n * Returns the instance for method chaining.\n *\n * @return {LoadAttribute}\n */\nfunction validate() {\n // TODO url validation\n return this;\n}\n\n\n/**\n * LoadAttribute instance method - returns URL\n *\n * @return {String}\n */\nfunction render() {\n return this.loadUrl;\n}\n",
+ "'use strict';\n\n\nvar _ = require('milo-core').proto;\n\nmodule.exports = Facet;\n\n\n/**\n * `milo.classes.Facet`\n * Base Facet class is an ancestor of [ComponentFacet](../components/c_facet.js.html) class, the main building block in milo.\n * \n * @param {FacetedObject} owner an instance of FacetedObject subclass that stores the facet on its property with the same name as `name` property of facet\n * @param {Object} config optional facet configuration, used in subclasses\n */\nfunction Facet(owner, config) {\n this.name = _.firstLowerCase(this.constructor.name);\n this.owner = owner;\n this.config = config || {};\n this.init.apply(this, arguments);\n}\n\n\n/**\n * `init` method of subclass will be called by Facet constructor.\n */\n_.extendProto(Facet, {\n init: function() {}\n});\n",
+ "'use strict';\n\n\nvar Facet = require('./facet')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\nmodule.exports = FacetedObject;\n\n\n/**\n * `milo.classes.FacetedObject`\n * Component class is based on an abstract ```FacetedObject``` class. This class can be used in any situation where objects can be represented via collection of facets (a facet is an object of a certain class, it holds its own configuration, data and methods).\n * In a way, \"facets pattern\" is an inversion of \"adapter pattern\" - while the latter allows finding a class/methods that has specific functionality, faceted object is simply constructed to have these functionalities.\n * With this architecture it is possible to create a virtually unlimited number of component classes with a very limited number of building blocks without having any hierarchy of classes - all components inherit directly from Component class.\n *\n * This constructor should be called by all subclasses constructor (it will happen automatically if a subclass is created with `_.createSubclass`).\n *\n * @return {FacetedObject}\n */\nfunction FacetedObject() {\n // this.facetsConfig and this.facetsClasses were stored on a specific class prototype\n // when the class was created by FacetedObject.createFacetedClass\n var facetsConfig = this.facetsConfig || {};\n\n var facetsDescriptors = {}\n , facets = {};\n\n // FacetedObject class itself is not meant to be instantiated - it has no facets\n // It may change, as adding facets is possible to instances\n if (this.constructor == FacetedObject) \n throw new Error('FacetedObject is an abstract class, can\\'t be instantiated');\n\n // instantiate class facets\n if (this.facetsClasses)\n _.eachKey(this.facetsClasses, instantiateFacet, this, true);\n\n // add facets to the class as properties under their own name\n Object.defineProperties(this, facetsDescriptors);\n\n // store all facets on `facets` property so that they can be enumerated\n _.defineProperty(this, 'facets', facets); \n\n // call `init`method if it is defined in subclass\n if (this.init)\n this.init.apply(this, arguments);\n\n // instantiate facet with a given class (FacetClass) and name (facetName)\n function instantiateFacet(FacetClass, facetName) {\n // get facet configuration\n var fctConfig = facetsConfig[facetName];\n\n // instatiate facets\n facets[facetName] = new FacetClass(this, fctConfig);\n\n // add facet to property descriptors\n facetsDescriptors[facetName] = {\n enumerable: true,\n value: facets[facetName]\n };\n }\n}\n\n\n/**\n * ####FacetedObject class methods####\n *\n * - [createFacetedClass](#FacetedObject$$createFacetedClass)\n * - [hasFacet](#FacetedObject$$hasFacet)\n */\n_.extend(FacetedObject, {\n createFacetedClass: FacetedObject$$createFacetedClass,\n hasFacet: FacetedObject$$hasFacet,\n getFacetConfig: FacetedObject$$getFacetConfig\n});\n\n\n/**\n * ####FacetedObject instance methods####\n *\n * - [addFacet](#FacetedObject$addFacet)\n */\n_.extendProto(FacetedObject, {\n addFacet: FacetedObject$addFacet\n});\n\n\n/**\n * FacetedObject instance method.\n * Adds a facet to the instance of FacetedObject subclass.\n * Returns an instance of the facet that was created.\n *\n * @param {Function} FacetClass facet class constructor\n * @param {Object} facetConfig optional facet configuration\n * @param {String} facetName optional facet name, FacetClass.name will be used if facetName is not passed.\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n * @return {Facet}\n */\nfunction FacetedObject$addFacet(FacetClass, facetConfig, facetName, throwOnErrors) {\n check(FacetClass, Function);\n check(facetName, Match.Optional(String));\n\n // first letter of facet name should be lowercase\n facetName = _.firstLowerCase(facetName || FacetClass.name);\n\n // get facets defined in class\n var protoFacets = this.constructor.prototype.facetsClasses;\n\n // check that this facetName was not already used in the class\n if (protoFacets && protoFacets[facetName])\n throw new Error('facet ' + facetName + ' is already part of the class ' + this.constructor.name);\n\n // check that this faceName does not already exist on the faceted object\n if (this[facetName]) {\n var message = 'facet ' + facetName + ' is already present in object';\n if (throwOnErrors === false)\n return logger.error('FacetedObject addFacet: ', message);\n else\n throw new Error(message);\n }\n\n // instantiate the facet\n var newFacet = this.facets[facetName] = new FacetClass(this, facetConfig);\n\n // add facet to faceted object\n _.defineProperty(this, facetName, newFacet, _.ENUM);\n\n return newFacet;\n}\n\n\n/**\n * FacetedObject class method\n * Returns reference to the facet class if the facet with `facetName` is part of the class, `undefined` otherwise. If subclass is created using _.createSubclass (as it should be) it will also have this method.\n * \n * @param {Subclass(FacetedObject)} this this in this method refers to FacetedObject (or its subclass) that calls this method\n * @param {String} facetName\n * @return {Subclass(Facet)|undefined} \n */\nfunction FacetedObject$$hasFacet(facetName) {\n // this refers to the FacetedObject class (or subclass), not instance\n var protoFacets = this.prototype.facetsClasses;\n return protoFacets && protoFacets[facetName];\n}\n\n/**\n * FacetedObject class method\n * Return the configuration of a facet\n * @param {String} facetName the facet which config should be retrieved\n * @return {Object} the configuration object that was passed to the facet\n */\nfunction FacetedObject$$getFacetConfig(facetName) {\n return this.hasFacet(facetName) ? this.prototype.facetsConfig[facetName] : null;\n}\n\n\n/**\n * FacetedObject class method\n * Class factory that creates classes (constructor functions) from the maps of facets and their configurations.\n * Created class will be subclass of `FacetedObject`.\n *\n * @param {Subclass(FacetedObject)} this this in this method refers to FacetedObject (or its subclass) that calls this method\n * @param {String} name class name (will be function name of class constructor function)\n * @param {Object[Subclass(Facet)]} facetsClasses map of classes of facets that will constitute the created class\n * @param {Object[Object]} facetsConfig map of facets configuration, should have the same keys as the map of classes. Some facets may not have configuration, but the configuration for a facet that is not included in facetsClasses will throw an exception\n * @return {Subclass(FacetedObject)}\n */\nfunction FacetedObject$$createFacetedClass(name, facetsClasses, facetsConfig) {\n check(name, String);\n check(facetsClasses, Match.Optional(Match.ObjectHash(Match.Subclass(Facet, true))));\n check(facetsConfig, Match.Optional(Object));\n\n // throw exception if config passed for facet for which there is no class\n if (facetsConfig)\n _.eachKey(facetsConfig, function(fctConfig, fctName) {\n if (! facetsClasses.hasOwnProperty(fctName))\n throw new Error('configuration for facet (' + fctName + ') passed that is not in class');\n });\n\n // create subclass of the current class (this refers to the class that calls this method)\n var FacetedClass = _.createSubclass(this, name, true);\n\n // get facets classes and configurations from parent class\n facetsClasses = addInheritedFacets(this, facetsClasses, 'facetsClasses');\n facetsConfig = addInheritedFacets(this, facetsConfig, 'facetsConfig');\n\n // store facets classes and configurations of class prototype\n _.extendProto(FacetedClass, {\n facetsClasses: facetsClasses,\n facetsConfig: facetsConfig\n });\n\n return FacetedClass;\n\n\n function addInheritedFacets(superClass, facetsInfo, facetsInfoName) {\n var inheritedFacetsInfo = superClass.prototype[facetsInfoName];\n if (inheritedFacetsInfo)\n return _(inheritedFacetsInfo)\n .clone()\n .extend(facetsInfo || {})._();\n else\n return facetsInfo;\n }\n};\n",
+ "'use strict';\n\nvar miloCore = require('milo-core')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\nmodule.exports = ClassRegistry;\n\n\n/**\n * `milo.classes.ClassRegistry` - the registry of classes class.\n * Components and Facets register themselves in registries. It allows to avoid requiring them from one module and prevents circular dependencies between modules.\n * \n * @param {Function} FoundationClass All classes that are registered in the registry should be subclasses of the FoundationClass\n * @return {Object}\n */\nfunction ClassRegistry (FoundationClass) {\n if (FoundationClass)\n this.setClass(FoundationClass);\n\n this.__registeredClasses = {};\n}\n\n\n/**\n * ####ClassRegistry instance methods####\n *\n * - [add](#add)\n * - [get](#get)\n * - [remove](#remove)\n * - [clean](#clean)\n * - [setClass](#setClass)\n */\n_.extendProto(ClassRegistry, {\n add: add,\n get: get,\n remove: remove,\n clean: clean,\n setClass: setClass\n});\n\n\n/**\n * ClassRegistry instance method that registers a class in the registry.\n * The method will throw an exception if a class is registered under the same name as previously registered class.\n * The method allows registering the same class under a different name, so class aliases can be created.\n *\n * @param {Function} aClass class to register in the registry. Should be subclass of `this.FoundationClass`.\n * @param {String} name Optional class name. If class name is not specified, it will be taken from constructor function name. Class name should be a valid identifier and cannot be an empty string.\n */\nfunction add(aClass, name) {\n name = name || aClass.name;\n\n check(name, Match.IdentifierString, 'class name must be identifier string');\n\n if (this.FoundationClass) {\n if (aClass != this.FoundationClass)\n check(aClass, Match.Subclass(this.FoundationClass), 'class must be a sub(class) of a foundation class');\n } else\n throw new Error('foundation class must be set before adding classes to registry');\n\n if (this.__registeredClasses[name])\n throw new Error('class \"' + name + '\" is already registered');\n\n this.__registeredClasses[name] = aClass;\n};\n\n\n/**\n * Gets class from registry by name\n *\n * @param {String} name Class name\n * @return {Function}\n */\nfunction get(name) {\n check(name, String, 'class name must be string');\n return this.__registeredClasses[name];\n};\n\n\n/**\n * Remove class from registry by its name.\n * If class is not registered, this method will throw an exception.\n * \n * @param {String|Function} nameOrClass Class name. If class constructor is supplied, its name will be used.\n */\nfunction remove(nameOrClass) {\n check(nameOrClass, Match.OneOf(String, Function), 'class or name must be supplied');\n\n var name = typeof nameOrClass == 'string'\n ? nameOrClass\n : nameOrClass.name;\n \n if (! this.__registeredClasses[name])\n throw new Error('class is not registered');\n\n delete this.__registeredClasses[name];\n};\n\n\n/**\n * Removes all classes from registry.\n */\nfunction clean() {\n this.__registeredClasses = {};\n};\n\n\n/**\n * Sets `FoundationClass` of the registry. It should be set before any class can be added.\n *\n * @param {Function} FoundationClass Any class that will be added to the registry should be a subclass of this class. FoundationClass itself can be added to the registry too.\n */\nfunction setClass(FoundationClass) {\n check(FoundationClass, Function);\n _.defineProperty(this, 'FoundationClass', FoundationClass, _.ENUM);\n}\n",
+ "'use strict';\n\nvar Attribute = require('./a_class')\n , config = require('../config')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\n\nvar ATTRIBUTE_REGEXP= /^([^\\:\\[\\]]*)(?:\\[([^\\:\\[\\]]*)\\])?\\:?([^:]*)$/\n , FACETS_SPLIT_REGEXP = /\\s*(?:\\,|\\s)\\s*/\n , ATTRIBUTE_TEMPLATE = '%compClass%compFacets:%compName';\n\n\n/**\n * `milo.attributes.bind`\n * BindAttribute class parses/validates/etc. an attribute that binds DOM elements to milo components.\n * Possible attribute values are:\n *\n * - `:myView` - only component name\n * - `View:myView` - class and component name\n * - `[Events, Data]:myView` - facets and component name\n * - `View[Events]:myView` - class, facet(s) and component name\n *\n * See [binder](../binder.js.html) for more information.\n */\nvar BindAttribute = _.createSubclass(Attribute, 'BindAttribute', true);\n\n\n/**\n * ####BindAttribute instance methods####\n *\n * - [attrName](#attrName)\n * - [parse](#parse)\n * - [validate](#validate)\n * - [render](#render)\n */\n_.extendProto(BindAttribute, {\n attrName: attrName,\n parse: parse,\n validate: validate,\n render: render\n});\n\n\n/**\n * BindAttribute class methods\n *\n * - [setInfo](#BindAttribute$$setInfo)\n */\n_.extend(BindAttribute, {\n setInfo: BindAttribute$$setInfo\n});\n\n\nmodule.exports = BindAttribute;\n\n\n/**\n * BindAttribute instance method that returns attribute name, by default - `'ml-bind'`.\n * To configure bind attribute name use:\n * ```\n * milo.config({ attrs: { bind: 'cc-bind' } }); // will set bind attribute to 'cc-bind'\n * ```\n *\n * @return {String}\n */\nfunction attrName() {\n return config.attrs.bind;\n}\n\n\n/**\n * BindAttribute instance method that parses bind attribute if it is present on the element.\n * It defines properties `compClass`, `compFacets` and `compName` on BindAttribute instance.\n * Returns the instance for method chaining.\n *\n * @return {BindAttribute}\n */\n function parse() {\n if (! this.node) return;\n\n var value = this.get();\n\n if (value)\n var bindTo = value.match(ATTRIBUTE_REGEXP);\n\n if (! bindTo)\n throw new Error('invalid bind attribute ' + value);\n\n this.compClass = bindTo[1] || 'Component';\n this.compFacets = (bindTo[2] && bindTo[2].split(FACETS_SPLIT_REGEXP)) || undefined;\n this.compName = bindTo[3] || undefined; // undefined is not same as ''\n\n return this;\n}\n\n\n/**\n * BindAttribute instance method that validates bind attribute, throws if it has an invalid value.\n * Returns the instance for method chaining.\n *\n * @return {BindAttribute}\n */\nfunction validate() {\n check(this.compName, Match.IdentifierString);\n\n if (! this.compClass)\n throw new Error('empty component class name ' + this.compClass);\n\n return this;\n}\n\n\n/**\n * BindAttribute instance method that returns the attribute value for given values of properties `compClass`, `compName` and `compFacets`.\n * If `this.compName` is not set it will be generated automatically.\n *\n * @return {String}\n */\nfunction render() {\n this.compName = this.compName || milo.util.componentName();\n return ATTRIBUTE_TEMPLATE\n .replace('%compClass', this.compClass || '')\n .replace('%compFacets', this.compFacets && this.compFacets.length\n ? '[' + this.compFacets.join(', ') + ']'\n : '')\n .replace('%compName', this.compName);\n}\n\n\n/**\n * BindAttribute class method\n * @param {Element} el\n * @param {String} componentClass optional class name\n * @param {String} componentName optional\n * @param {Array} componentFacets optional extra facet to add to the class\n */\nfunction BindAttribute$$setInfo(el, componentClass, componentName, componentFacets) {\n var attr = new BindAttribute(el);\n _.extend(attr, {\n compClass: componentClass,\n compName: componentName,\n compFacets: componentFacets\n });\n attr.decorate();\n}\n",
+ "'use strict';\n\nvar miloCore = require('milo-core')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\n\nmodule.exports = Attribute;\n\n\n/**\n * An absctract class for parsing and validation of element attributes.\n * Subclasses should define methods `attrName`, `parse`, `validate` and `render`.\n *\n * @param {Element} el DOM element where attribute is attached\n * @param {String} name Optional name of the attribute, usually supplied by subclass via `attrName` method\n */\nfunction Attribute(el, name) {\n this.name = name || this.attrName();\n this.el = el;\n\n // attribute node\n this.node = el.attributes[this.name];\n}\n\n\n_.extend(Attribute, {\n remove: Attribute$$remove\n});\n\n\n/**\n * ####Attribute instance methods####\n *\n * - [get](#Attribute$get)\n * - [set](#Attribute$set)\n * - [decorate](#Attribute$decorate)\n *\n * The following instance methods should be defined by subclass\n *\n * - attrName - should return attribute name\n * - parse - should parse attribute value\n * - validate - should validate attribute value, throwing exception if it is incorrect \n * - render - should return attribute value for a given attribute state (other properties, as defined in subclass)\n */\n_.extendProto(Attribute, {\n get: Attribute$get,\n set: Attribute$set,\n remove: Attribute$remove,\n decorate: Attribute$decorate,\n\n destroy: Attribute$destroy,\n\n // should be defined in subclass\n attrName: toBeImplemented,\n parse: toBeImplemented,\n validate: toBeImplemented,\n render: toBeImplemented\n});\n\n\nfunction Attribute$$remove(el, deep) {\n var name = this.prototype.attrName();\n el.removeAttribute(name);\n\n if (deep) {\n var selector = '[' + name + ']';\n var children = el.querySelectorAll(selector);\n _.forEach(children, function(childEl) {\n childEl.removeAttribute(name);\n })\n }\n}\n\n\nfunction Attribute$remove() {\n delete this.node;\n}\n\n\nfunction Attribute$destroy() {\n delete this.el;\n delete this.node;\n}\n\n/**\n * Attribute instance method that returns attribute value as string.\n *\n * @return {String}\n */\nfunction Attribute$get() {\n return this.el.getAttribute(this.name);\n}\n\n\n/**\n * Attribute instance method that sets attribute value.\n *\n * @param {String} value\n */\nfunction Attribute$set(value) {\n this.el.setAttribute(this.name, value);\n}\n\n\n/**\n * Attribute instance method that decorates element with its rendered value.\n * Uses `render` method that should be defiend in subclass.\n */\nfunction Attribute$decorate() {\n this.set(this.render());\n}\n\n\nfunction toBeImplemented() {\n throw new Error('calling the method of an absctract class');\n}\n",
+ "'use strict';\n\nvar Attribute = require('./a_class')\n , config = require('../config')\n , _ = require('milo-core').proto;\n\n\n/**\n * `milo.attributes.load`\n * LoadAttribute class parses/validates/etc. an attribute that loads sub-views into the page.\n * Attribute value should be URL of the file to load subview from.\n * See [loader](../loader.js.html) for more information.\n */\nvar LoadAttribute = _.createSubclass(Attribute, 'LoadAttribute', true);\n\n\n/**\n * ####LoadAttribute instance methods####\n *\n * - [attrName](#attrName)\n * - [parse](#parse)\n * - [validate](#validate)\n * - [render](#render)\n */\n_.extendProto(LoadAttribute, {\n attrName: attrName,\n parse: parse,\n validate: validate,\n render: render\n});\n\nmodule.exports = LoadAttribute;\n\n\n/**\n * BindAttribute instance method that returns attribute name, by default - `'ml-load'`.\n * To configure load attribute name use:\n * ```\n * milo.config({ attrs: { load: 'cc-load' } }); // will set bind attribute to 'cc-load'\n * ```\n *\n * @return {String}\n */\nfunction attrName() {\n return config.attrs.load;\n}\n\n\n/**\n * LoadAttribute instance method that parses load attribute if it is present on the element.\n * It defines property `loadUrl` on LoadAttribute instance.\n * Returns the instance for method chaining.\n *\n * @return {LoadAttribute}\n */\nfunction parse() {\n if (! this.node) return;\n\n this.loadUrl = this.get();\n return this;\n}\n\n\n/**\n * LoadAttribute instance method that should validate load attribute and throw if it has an invalid value.\n * TODO - implement url validation.\n * Returns the instance for method chaining.\n *\n * @return {LoadAttribute}\n */\nfunction validate() {\n // TODO url validation\n return this;\n}\n\n\n/**\n * LoadAttribute instance method - returns URL\n *\n * @return {String}\n */\nfunction render() {\n return this.loadUrl;\n}\n",
"'use strict';\n\n/**\n * Subclasses of [Attribute](./a_class.js.html) class\n *\n * - [BindAttribute](./a_bind.js.html)\n * - [LoadAttribute](./a_load.js.html)\n */\nvar attributes = module.exports = {\n bind: require('./a_bind'),\n load: require('./a_load')\n};\n",
- "'use strict';\n\nvar miloMail = require('./services/mail')\n , componentsRegistry = require('./components/c_registry')\n , facetsRegistry = require('./components/c_facets/cf_registry')\n , Component = componentsRegistry.get('Component')\n , ComponentInfo = require('./components/c_info')\n , Scope = require('./components/scope')\n , BindAttribute = require('./attributes/a_bind')\n , BinderError = require('./util/error').Binder\n , _ = require('mol-proto')\n , check = require('./util/check')\n , utilDom = require('./util/dom')\n , Match = check.Match;\n\n\nbinder.scan = scan;\nbinder.create = create;\nbinder.twoPass = twoPass;\n\n\nmodule.exports = binder;\n\n\n/**\n * `milo.binder`\n *\n * Recursively scans the document tree inside `scopeEl` (document.body by default) looking for __ml-bind__ attribute that should contain the class, additional facets and the name of the component that should be created and bound to the element.\n *\n * Possible values of __ml-bind__ attribute:\n *\n * - `:myView` - only component name. An instance of Component class will be created without any facets.\n * - `View:myView` - class and component name. An instance of View class will be created.\n * - `[Events, Data]:myView` - facets and component name. An instance of Component class will be created with the addition of facets Events and Data.\n * - `View[Events, Data]:myView` - class, facet(s) and component name. An instance of View class will be created with the addition of facets Events and Data.\n *\n * Function returns an instance of [`Scope`](./components/scope.js.html) class containing all components created as a result of scanning DOM.\n *\n * If the component has [`Container`](./components/c_facets/Container.js) facet, children of this element will be stored in the `scope` object, available as scope property on the Container facet of this component. Names of components within the scope should be unique, but they can be the same as the names of components in outer scope (or some other scope).\n *\n * @param {Element} scopeEl root element inside which DOM will be scanned and bound\n * @param {Scope} rootScope Optional Root scope object where top level components will be saved.\n * @param {Boolean} bindRootElement If set to false, then the root element will not be bound. True by default.\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n * @return {Scope}\n */\nfunction binder(scopeEl, rootScope, bindRootElement, throwOnErrors) {\n return createBinderScope(scopeEl, function(scope, el, attr, throwOnErrors) {\n var info = new ComponentInfo(scope, el, attr, throwOnErrors);\n return Component.create(info, throwOnErrors);\n }, rootScope, bindRootElement, throwOnErrors);\n}\n\n\n// bind in two passes\nfunction twoPass(scopeEl, rootScope, bindRootElement, throwOnErrors) {\n var scanScope = binder.scan(scopeEl, rootScope, bindRootElement, throwOnErrors);\n return binder.create(scanScope, undefined, throwOnErrors);\n}\n\n\n// scan DOM for BindAttribute\nfunction scan(scopeEl, rootScope, bindRootElement, throwOnErrors) {\n return createBinderScope(scopeEl, function(scope, el, attr, throwOnErrors) {\n return new ComponentInfo(scope, el, attr, throwOnErrors);\n }, rootScope, bindRootElement, throwOnErrors);\n}\n\n\n// create bound components\nfunction create(scanScope, hostObject, throwOnErrors) {\n var scope = new Scope(scanScope._rootEl, hostObject)\n , addMethod = throwOnErrors === false ? '_safeAdd' : '_add';\n\n scanScope._each(function(compInfo) {\n // set correct component's scope\n var info = _.clone(compInfo)\n info.scope = scope;\n\n // create component\n var aComponent = Component.create(info, throwOnErrors);\n\n scope[addMethod](aComponent, aComponent.name);\n if (aComponent.container)\n aComponent.container.scope = create(compInfo.container.scope, aComponent.container, throwOnErrors);\n });\n\n return scope;\n}\n\n/**\n * `createBinderScope`\n * @param {Element} scopeEl scopeEl root element inside which DOM will be scanned and bound (document.body by default).\n * @param {Function} scopeObjectFactory See [binder](#milo.binder)\n * @param {Scope} rootScope Optional Root scope object where top level components will be saved.\n * @param {Boolean} bindRootElement If set to false, then the root element will not be bound. True by default.\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n * @return {Scope} [description]\n */\nfunction createBinderScope(scopeEl, scopeObjectFactory, rootScope, bindRootElement, throwOnErrors) {\n var scopeEl = scopeEl || document.body\n , scope = rootScope || new Scope(scopeEl)\n , addMethod = throwOnErrors === false ? '_safeAdd' : '_add';\n\n createScopeForElement(scope, scopeEl, bindRootElement);\n\n return scope;\n\n\n function createScopeForElement(scope, el, bindRootElement) {\n // get element's binding attribute (ml-bind by default)\n var attr = new BindAttribute(el);\n\n // if element has bind attribute crate scope object (Component or ComponentInfo)\n if (attr.node && bindRootElement !== false) {\n var scopedObject = scopeObjectFactory(scope, el, attr, throwOnErrors)\n , isContainer = typeof scopedObject != 'undefined' && scopedObject.container;\n }\n\n // if there are childNodes add children to new scope if this element has component with Container facet\n // otherwise create a new scope\n if (el.childNodes && el.childNodes.length) {\n if (isContainer) {\n var innerScope = new Scope(el);\n scopedObject.container.scope = innerScope;\n innerScope._hostObject = scopedObject.container;\n }\n\n createScopeForChildren(el, isContainer ? innerScope : scope);\n }\n\n // if scope wasn't previously created on container facet, create empty scope anyway\n if (isContainer && ! scopedObject.container.scope)\n scopedObject.container.scope = new Scope(el);\n\n\n // TODO condition after && is a hack, should not be used!\n if (scopedObject) // && ! scope[attr.compName])\n scope[addMethod](scopedObject, attr.compName);\n\n // _.defer(postChildrenBoundMessage, el);\n postChildrenBoundMessage(el);\n\n return scopedObject;\n\n\n function postChildrenBoundMessage(el) {\n var elComp = Component.getComponent(el);\n\n if (elComp)\n elComp.postMessageSync('childrenbound');\n }\n }\n\n\n function createScopeForChildren(containerEl, scope) {\n var children = utilDom.children(containerEl);\n\n _.forEach(children, function(node) {\n createScopeForElement(scope, node, true);\n });\n return scope;\n }\n}\n",
- "'use strict';\n\n// \n// milo.classes\n// -----------\n\n// This module contains foundation classes and class registries.\n\nvar classes = {\n Facet: require('./abstract/facet'),\n FacetedObject: require('./abstract/faceted_object'),\n Scope: require('./components/scope'),\n ClassRegistry: require('./abstract/registry'),\n Mixin: require('./abstract/mixin'),\n MessageSource: require('./messenger/m_source'),\n MessengerMessageSource: require('./messenger/msngr_source'),\n MessengerAPI: require('./messenger/m_api'),\n DOMEventsSource: require('./components/msg_src/dom_events'),\n Transaction: require('./command/transaction'),\n TransactionHistory: require('./command/transaction_history')\n};\n\nmodule.exports = classes;\n",
- "'use strict';\n\n\nvar _ = require('mol-proto')\n , logger = require('../util/logger');\n\n\nmodule.exports = ActionsHistory;\n\n\n/**\n * Stores list of commands or transactions\n *\n * @constructor\n * @param {Number} maxLength\n */\nfunction ActionsHistory(maxLength) {\n this._maxLength = maxLength || Infinity;\n this.actions = [];\n this.position = 0;\n}\n\n\n_.extendProto(ActionsHistory, {\n store: ActionsHistory$store,\n deleteLast: ActionsHistory$deleteLast,\n undo: ActionsHistory$undo,\n redo: ActionsHistory$redo,\n undoAll: ActionsHistory$undoAll,\n redoAll: ActionsHistory$redoAll,\n undoAllAsync: ActionsHistory$undoAllAsync,\n redoAllAsync: ActionsHistory$redoAllAsync,\n each: ActionsHistory$each,\n eachReverse: ActionsHistory$eachReverse,\n getLastAction: ActionsHistory$getLastAction,\n\n getDescription: ActionsHistory$getDescription\n});\n\n\nfunction ActionsHistory$store(command) {\n _truncateToCurrentPosition.call(this);\n this.actions.push(command);\n\n if (this.actions.length > this._maxLength) {\n var act = this.actions.shift();\n act.destroy();\n }\n\n this.position = this.actions.length;\n return this.position - 1\n}\n\n\nfunction ActionsHistory$deleteLast() {\n if (!this.actions.length) return;\n this.position--;\n this.actions.length--;\n}\n\n\nfunction _truncateToCurrentPosition() {\n for (var i = this.position; i < this.actions.length; i++)\n this.actions[i].destroy();\n this.actions.length = this.position;\n}\n\n\nfunction ActionsHistory$undo(cb) {\n if (this.position == 0) return; // nothing to undo\n var act = this.actions[--this.position];\n act.undo(cb);\n return act;\n}\n\n\nfunction ActionsHistory$redo(cb) {\n if (this.position == this.actions.length) return; // nothing to redo\n var act = this.actions[this.position++];\n act.redo(cb);\n return act;\n}\n\n\nfunction ActionsHistory$undoAll() {\n while (this.position) this.undo();\n}\n\n\nfunction ActionsHistory$redoAll() {\n while (this.position < this.actions.length) this.redo();\n}\n\n\nfunction ActionsHistory$undoAllAsync(cb) {\n if (this.position) {\n this.undo();\n if (this.position)\n _.deferMethod(this, 'undoAllAsync', cb);\n else\n if (cb) _.defer(cb);\n }\n}\n\n\nfunction ActionsHistory$redoAllAsync(cb) {\n if (this.position < this.actions.length) {\n this.redo();\n if (this.position < this.actions.length) \n _.deferMethod(this, 'redoAllAsync', cb);\n else\n if (cb) _.defer(cb);\n }\n}\n\n\nfunction ActionsHistory$each(funcOrMethod, thisArg) {\n var func = typeof funcOrMethod == 'string'\n ? function(act) { act[funcOrMethod](); }\n : funcOrMethod;\n\n this.actions.forEach(func, thisArg || this);\n}\n\n\nfunction ActionsHistory$eachReverse(funcOrMethod, thisArg) {\n this.actions.reverse();\n this.each(funcOrMethod, thisArg);\n this.actions.reverse();\n}\n\n\nfunction ActionsHistory$getLastAction() {\n return this.position && this.actions[this.position - 1];\n}\n\n\nfunction ActionsHistory$getDescription() {\n var actions = this.actions.map(function(act) {\n return act.getDescription();\n });\n return {\n actions: actions,\n position: this.position,\n length: actions.length\n };\n}\n",
+ "'use strict';\n\nvar miloMail = require('./services/mail')\n , componentsRegistry = require('./components/c_registry')\n , facetsRegistry = require('./components/c_facets/cf_registry')\n , Component = componentsRegistry.get('Component')\n , ComponentInfo = require('./components/c_info')\n , Scope = require('./components/scope')\n , BindAttribute = require('./attributes/a_bind')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , utilDom = require('./util/dom')\n , Match = check.Match;\n\n\nbinder.scan = scan;\nbinder.create = create;\nbinder.twoPass = twoPass;\n\n\nmodule.exports = binder;\n\n\n/**\n * `milo.binder`\n *\n * Recursively scans the document tree inside `scopeEl` (document.body by default) looking for __ml-bind__ attribute that should contain the class, additional facets and the name of the component that should be created and bound to the element.\n *\n * Possible values of __ml-bind__ attribute:\n *\n * - `:myView` - only component name. An instance of Component class will be created without any facets.\n * - `View:myView` - class and component name. An instance of View class will be created.\n * - `[Events, Data]:myView` - facets and component name. An instance of Component class will be created with the addition of facets Events and Data.\n * - `View[Events, Data]:myView` - class, facet(s) and component name. An instance of View class will be created with the addition of facets Events and Data.\n *\n * Function returns an instance of [`Scope`](./components/scope.js.html) class containing all components created as a result of scanning DOM.\n *\n * If the component has [`Container`](./components/c_facets/Container.js) facet, children of this element will be stored in the `scope` object, available as scope property on the Container facet of this component. Names of components within the scope should be unique, but they can be the same as the names of components in outer scope (or some other scope).\n *\n * @param {Element} scopeEl root element inside which DOM will be scanned and bound\n * @param {Scope} rootScope Optional Root scope object where top level components will be saved.\n * @param {Boolean} bindRootElement If set to false, then the root element will not be bound. True by default.\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n * @return {Scope}\n */\nfunction binder(scopeEl, rootScope, bindRootElement, throwOnErrors) {\n return createBinderScope(scopeEl, function(scope, el, attr, throwOnErrors) {\n var info = new ComponentInfo(scope, el, attr, throwOnErrors);\n return Component.create(info, throwOnErrors);\n }, rootScope, bindRootElement, throwOnErrors);\n}\n\n\n// bind in two passes\nfunction twoPass(scopeEl, rootScope, bindRootElement, throwOnErrors) {\n var scanScope = binder.scan(scopeEl, rootScope, bindRootElement, throwOnErrors);\n return binder.create(scanScope, undefined, throwOnErrors);\n}\n\n\n// scan DOM for BindAttribute\nfunction scan(scopeEl, rootScope, bindRootElement, throwOnErrors) {\n return createBinderScope(scopeEl, function(scope, el, attr, throwOnErrors) {\n return new ComponentInfo(scope, el, attr, throwOnErrors);\n }, rootScope, bindRootElement, throwOnErrors);\n}\n\n\n// create bound components\nfunction create(scanScope, hostObject, throwOnErrors) {\n var scope = new Scope(scanScope._rootEl, hostObject)\n , addMethod = throwOnErrors === false ? '_safeAdd' : '_add';\n\n scanScope._each(function(compInfo) {\n // set correct component's scope\n var info = _.clone(compInfo)\n info.scope = scope;\n\n // create component\n var aComponent = Component.create(info, throwOnErrors);\n\n scope[addMethod](aComponent, aComponent.name);\n if (aComponent.container)\n aComponent.container.scope = create(compInfo.container.scope, aComponent.container, throwOnErrors);\n });\n\n return scope;\n}\n\n/**\n * `createBinderScope`\n * @param {Element} scopeEl scopeEl root element inside which DOM will be scanned and bound (document.body by default).\n * @param {Function} scopeObjectFactory See [binder](#milo.binder)\n * @param {Scope} rootScope Optional Root scope object where top level components will be saved.\n * @param {Boolean} bindRootElement If set to false, then the root element will not be bound. True by default.\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n * @return {Scope} [description]\n */\nfunction createBinderScope(scopeEl, scopeObjectFactory, rootScope, bindRootElement, throwOnErrors) {\n var scopeEl = scopeEl || document.body\n , scope = rootScope || new Scope(scopeEl)\n , addMethod = throwOnErrors === false ? '_safeAdd' : '_add';\n\n createScopeForElement(scope, scopeEl, bindRootElement);\n\n return scope;\n\n\n function createScopeForElement(scope, el, bindRootElement) {\n // get element's binding attribute (ml-bind by default)\n var attr = new BindAttribute(el);\n\n // if element has bind attribute crate scope object (Component or ComponentInfo)\n if (attr.node && bindRootElement !== false) {\n var scopedObject = scopeObjectFactory(scope, el, attr, throwOnErrors)\n , isContainer = typeof scopedObject != 'undefined' && scopedObject.container;\n }\n\n // if there are childNodes add children to new scope if this element has component with Container facet\n // otherwise create a new scope\n if (el.childNodes && el.childNodes.length) {\n if (isContainer) {\n var innerScope = new Scope(el);\n scopedObject.container.scope = innerScope;\n innerScope._hostObject = scopedObject.container;\n }\n\n createScopeForChildren(el, isContainer ? innerScope : scope);\n }\n\n // if scope wasn't previously created on container facet, create empty scope anyway\n if (isContainer && ! scopedObject.container.scope)\n scopedObject.container.scope = new Scope(el);\n\n\n // TODO condition after && is a hack, should not be used!\n if (scopedObject) // && ! scope[attr.compName])\n scope[addMethod](scopedObject, attr.compName);\n\n // _.defer(postChildrenBoundMessage, el);\n postChildrenBoundMessage(el);\n\n return scopedObject;\n\n\n function postChildrenBoundMessage(el) {\n var elComp = Component.getComponent(el);\n\n if (elComp)\n elComp.postMessageSync('childrenbound');\n }\n }\n\n\n function createScopeForChildren(containerEl, scope) {\n var children = utilDom.children(containerEl);\n\n _.forEach(children, function(node) {\n createScopeForElement(scope, node, true);\n });\n return scope;\n }\n}\n",
+ "'use strict';\n\nvar coreClasses = require('milo-core').classes;\n\n// \n// milo.classes\n// -----------\n\n// This module contains foundation classes and class registries.\n\nvar classes = {\n Facet: require('./abstract/facet'),\n FacetedObject: require('./abstract/faceted_object'),\n Scope: require('./components/scope'),\n ClassRegistry: require('./abstract/registry'),\n Mixin: coreClasses.Mixin,\n MessageSource: coreClasses.MessageSource,\n MessengerMessageSource: coreClasses.MessengerMessageSource,\n MessengerAPI: coreClasses.MessengerAPI,\n DOMEventsSource: require('./components/msg_src/dom_events'),\n Transaction: require('./command/transaction'),\n TransactionHistory: require('./command/transaction_history')\n};\n\nmodule.exports = classes;\n",
+ "'use strict';\n\n\nvar miloCore = require('milo-core')\n , _ = miloCore.proto\n , logger = miloCore.util.logger;\n\n\nmodule.exports = ActionsHistory;\n\n\n/**\n * Stores list of commands or transactions\n *\n * @constructor\n * @param {Number} maxLength\n */\nfunction ActionsHistory(maxLength) {\n this._maxLength = maxLength || Infinity;\n this.actions = [];\n this.position = 0;\n}\n\n\n_.extendProto(ActionsHistory, {\n store: ActionsHistory$store,\n deleteLast: ActionsHistory$deleteLast,\n undo: ActionsHistory$undo,\n redo: ActionsHistory$redo,\n undoAll: ActionsHistory$undoAll,\n redoAll: ActionsHistory$redoAll,\n undoAllAsync: ActionsHistory$undoAllAsync,\n redoAllAsync: ActionsHistory$redoAllAsync,\n each: ActionsHistory$each,\n eachReverse: ActionsHistory$eachReverse,\n getLastAction: ActionsHistory$getLastAction,\n\n getDescription: ActionsHistory$getDescription\n});\n\n\nfunction ActionsHistory$store(command) {\n _truncateToCurrentPosition.call(this);\n this.actions.push(command);\n\n if (this.actions.length > this._maxLength) {\n var act = this.actions.shift();\n act.destroy();\n }\n\n this.position = this.actions.length;\n return this.position - 1\n}\n\n\nfunction ActionsHistory$deleteLast() {\n if (!this.actions.length) return;\n this.position--;\n this.actions.length--;\n}\n\n\nfunction _truncateToCurrentPosition() {\n for (var i = this.position; i < this.actions.length; i++)\n this.actions[i].destroy();\n this.actions.length = this.position;\n}\n\n\nfunction ActionsHistory$undo(cb) {\n if (this.position == 0) return; // nothing to undo\n var act = this.actions[--this.position];\n act.undo(cb);\n return act;\n}\n\n\nfunction ActionsHistory$redo(cb) {\n if (this.position == this.actions.length) return; // nothing to redo\n var act = this.actions[this.position++];\n act.redo(cb);\n return act;\n}\n\n\nfunction ActionsHistory$undoAll() {\n while (this.position) this.undo();\n}\n\n\nfunction ActionsHistory$redoAll() {\n while (this.position < this.actions.length) this.redo();\n}\n\n\nfunction ActionsHistory$undoAllAsync(cb) {\n if (this.position) {\n this.undo();\n if (this.position)\n _.deferMethod(this, 'undoAllAsync', cb);\n else\n if (cb) _.defer(cb);\n }\n}\n\n\nfunction ActionsHistory$redoAllAsync(cb) {\n if (this.position < this.actions.length) {\n this.redo();\n if (this.position < this.actions.length) \n _.deferMethod(this, 'redoAllAsync', cb);\n else\n if (cb) _.defer(cb);\n }\n}\n\n\nfunction ActionsHistory$each(funcOrMethod, thisArg) {\n var func = typeof funcOrMethod == 'string'\n ? function(act) { act[funcOrMethod](); }\n : funcOrMethod;\n\n this.actions.forEach(func, thisArg || this);\n}\n\n\nfunction ActionsHistory$eachReverse(funcOrMethod, thisArg) {\n this.actions.reverse();\n this.each(funcOrMethod, thisArg);\n this.actions.reverse();\n}\n\n\nfunction ActionsHistory$getLastAction() {\n return this.position && this.actions[this.position - 1];\n}\n\n\nfunction ActionsHistory$getDescription() {\n var actions = this.actions.map(function(act) {\n return act.getDescription();\n });\n return {\n actions: actions,\n position: this.position,\n length: actions.length\n };\n}\n",
"'use strict';\n\nvar ClassRegistry = require('../abstract/registry')\n , Command = require('./index');\n\n/**\n * `milo.registry.components`\n * An instance of [ClassRegistry](../abstract/registry.js.html) class that is used by milo to register and find components.\n */\nvar commandsRegistry = new ClassRegistry(Command);\n\n// add common ancestor to all components to the registry.\ncommandsRegistry.add(Command);\n\nmodule.exports = commandsRegistry;\n",
- "'use strict';\n\n\nvar _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match\n , logger = require('../util/logger');\n\n\nvar UNDO_COMMAND = '_undoCommand';\n\n\nmodule.exports = Command;\n\n\n/**\n * Command class to implement \"command pattern\" - packaging ll information necessary for delayed method execution\n *\n * @constructor\n * @param {Function} func method name or function to be executed\n * @param {List} *arguments parameters to be passed to method or function\n */\nfunction Command(func) { // , ... arguments\n this.init.apply(this, arguments);\n}\n\n\n/**\n * Command instance methods\n * \n * - [init](#Command$execute) - initialize command, should be overwritten by subclasses\n * - [execute](#Command$execute) - execute command\n * - [setUndo](#Command$setUndo) - set undo command for this command\n * - [getUndo](#Command$getUndo) - get undo command of this command\n * - [setArguments](#Command$setArguments) - set commands arguments\n * - [addArguments](#Command$addArguments) - add arguments to command\n * - [destroy](#Command$destroy)\n */\n_.extendProto(Command, {\n init: Command$init,\n execute: Command$execute,\n setUndo: Command$setUndo,\n getUndo: Command$getUndo,\n undo: Command$undo,\n redo: Command$execute, // same for command, different for transaction\n setArguments: Command$setArguments,\n addArguments: Command$addArguments,\n getArguments: Command$getArguments,\n changeArguments: Command$changeArguments,\n destroy: Command$destroy,\n\n setComment: Command$setComment,\n getDescription: Command$getDescription\n});\n\n\n/**\n * Command class methods\n *\n * - [create](#Command$$create) - commands factory\n */\n_.extend(Command, {\n create: Command$$create,\n createWithUndo: Command$$createWithUndo\n});\n\n\nfunction Command$init(func) { // , ... arguments\n check(func, Match.Optional(Function));\n this.func = func || function(){};\n this.args = _.slice(arguments, 1); \n}\n\n\n/**\n * Execute command making command object available via function property. \n */\nfunction Command$execute(cb) {\n var result = this.func.apply(this, this.args);\n if (cb) _.defer(cb);\n return result;\n}\n\n\n/**\n * Set undo command for this command. This command becomes undo command for undo command (so undo command can change this command during its execution).\n * \n * @param {Command} undoCommand\n */\nfunction Command$setUndo(undoCommand) {\n if (this[UNDO_COMMAND])\n logger.warn('Command setUndo: undo command is already set');\n\n this[UNDO_COMMAND] = undoCommand;\n undoCommand[UNDO_COMMAND] = this;\n}\n\n\n/**\n * Returns undo command of a given command\n *\n * @return {Command}\n */\nfunction Command$getUndo() {\n return this[UNDO_COMMAND];\n}\n\n\n/**\n * Executes undo command of current command\n */\nfunction Command$undo(cb) {\n var undoCmd = this.getUndo();\n if (! undoCmd) return logger.error('Command undo called without undo command present');\n var result = undoCmd.execute();\n if (cb) _.defer(cb);\n return result;\n}\n\n\n/**\n * Set command's arguments. If arguments were set during command's creation, this method will overwrite arguments and log warning.\n *\n * @param {List} *arguments\n */\nfunction Command$setArguments() { //, ... arguments\n if (this.args && this.args.length)\n logger.warn('Command setArguments: command arguments are already set');\n this.args = _.toArray(arguments);\n}\n\n\nfunction Command$getArguments() {\n return this.args;\n}\n\n\nfunction Command$changeArguments() { //, ... arguments\n this.args = _.toArray(arguments);\n}\n\n\n/**\n * Add (append) arguments to command\n *\n * @param {List} *arguments arguments list to be appended to command\n */\nfunction Command$addArguments() { //, ... arguments\n if (! this.args) this.args = [];\n _.appendArray(this.args, arguments);\n}\n\n\n/**\n * Commands factory. Likely ot be overridden by subclasses to implement custom logic of command construction\n * \n * @this {Function} Class of command\n * @param {Function} func method name or function to be executed\n * @param {List} *arguments parameters to be passed to method or function\n * @return {Command}\n */\nfunction Command$$create(func) { // , ... arguments\n return _.newApply(this, arguments);\n}\n\n\nfunction Command$$createWithUndo() {\n throw new Error('createWithUndo should be implemented by subsclass');\n}\n\n\n/**\n * Destroy current command (to prevent potential memory leaks when commands point to DOM elements)\n */\nfunction Command$destroy() {\n delete this.func;\n delete this.args;\n var undoCmd = this[UNDO_COMMAND];\n if (undoCmd) {\n delete this[UNDO_COMMAND][UNDO_COMMAND];\n delete this[UNDO_COMMAND];\n undoCmd.destroy();\n }\n}\n\n\nfunction Command$setComment(comment) {\n this.comment = comment;\n}\n\n\nfunction Command$getDescription() {\n return {\n func: this.func.name,\n comment: this.comment\n };\n}\n",
- "'use strict';\n\n\nvar ActionsHistory = require('./actions_history')\n , _ = require('mol-proto');\n\n\nmodule.exports = Transaction;\n\n\nfunction Transaction() {\n this.commands = new ActionsHistory;\n}\n\n\n_.extendProto(Transaction, {\n execute: Transaction$execute,\n undo: Transaction$undo,\n redo: Transaction$redo,\n destroy: Transaction$destroy,\n storeCommand: Transaction$storeCommand,\n merge: Transaction$merge,\n\n setComment: Transaction$setComment,\n getDescription: Transaction$getDescription\n});\n\n\nfunction Transaction$execute() {\n this.commands.each('execute');\n}\n\n\nfunction Transaction$undo(cb) {\n this.commands.undoAllAsync(cb);\n}\n\n\nfunction Transaction$redo(cb) {\n this.commands.redoAllAsync(cb);\n}\n\n\nfunction Transaction$destroy() {\n this.commands.each('destroy');\n}\n\n\nfunction Transaction$storeCommand(command) {\n this.commands.store(command);\n}\n\n\nfunction Transaction$merge(transaction) {\n transaction.commands.each(function(cmd) {\n this.commands.store(cmd);\n }, this);\n}\n\n\nfunction Transaction$setComment(comment) {\n this.comment = comment\n}\n\n\nfunction Transaction$getDescription() {\n var commands = this.commands.getDescription();\n return {\n commands: commands.actions,\n comment: this.comment\n }\n}\n",
- "'use strict';\n\n\nvar ActionsHistory = require('./actions_history')\n , Transaction = require('./transaction')\n , logger = require('../util/logger')\n , Messenger = require('../messenger')\n , _ = require('mol-proto');\n\n\nmodule.exports = TransactionHistory;\n\n\nvar SCHEDULED = '_scheduled';\n\n\nfunction TransactionHistory(maxLength) {\n this.transactions = new ActionsHistory(maxLength);\n this.currentBatch = undefined;\n this.currentTransaction = undefined;\n this[SCHEDULED] = false;\n}\n\n\n_.extendProto(TransactionHistory, {\n storeCommand: TransactionHistory$storeCommand,\n endTransaction: TransactionHistory$endTransaction,\n storeTransaction: TransactionHistory$storeTransaction,\n deleteLastTransaction: TransactionHistory$deleteLastTransaction,\n undo: TransactionHistory$undo,\n redo: TransactionHistory$redo,\n inTransaction: TransactionHistory$inTransaction,\n\n getDescription: TransactionHistory$getDescription,\n useMessenger: TransactionHistory$useMessenger,\n destroy: TransactionHistory$destroy\n});\n\n\n/**\n * Stores command in the history. \n * @param {Command} command \n * @param {Boolean} appendTransaction If `true`, appends to the current or previous transaction if there is no current transaction.\n */\nfunction TransactionHistory$storeCommand(command, appendTransaction) {\n if (appendTransaction && !(this.currentTransaction || this.currentBatch)) {\n var transaction = this.transactions.getLastAction();\n transaction.storeCommand(command);\n _postTransactionMessage.call(this, 'appended', transaction);\n return;\n }\n\n if (! this.currentBatch) this.currentBatch = new Transaction;\n this.currentBatch.storeCommand(command);\n if (! this[SCHEDULED]) {\n this[SCHEDULED] = true;\n _.deferMethod(this, _storeTransaction);\n }\n}\n\n\nfunction TransactionHistory$deleteLastTransaction() {\n if (this.currentBatch || this.currentTransaction) {\n this.currentBatch = undefined;\n this.currentTransaction = undefined;\n } else {\n this.transactions.deleteLast();\n }\n}\n\n\nfunction _storeTransaction() {\n if (this.currentBatch) {\n _addBatchToTransaction.call(this);\n _.deferMethod(this, _storeTransaction);\n } else {\n _storeCurrentTransaction.call(this);\n this[SCHEDULED] = false;\n }\n}\n\n\nfunction TransactionHistory$endTransaction() {\n _addBatchToTransaction.call(this);\n _storeCurrentTransaction.call(this);\n}\n\n\nfunction _addBatchToTransaction() {\n if (this.currentBatch) {\n if (! this.currentTransaction) this.currentTransaction = new Transaction;\n this.currentTransaction.merge(this.currentBatch);\n this.currentBatch = undefined;\n } \n}\n\n\nfunction _storeCurrentTransaction() {\n if (this.currentTransaction) {\n var t = this.currentTransaction;\n this.transactions.store(t);\n _postTransactionMessage.call(this, 'stored', t);\n\n this.currentTransaction = undefined;\n }\n}\n\n\nfunction TransactionHistory$storeTransaction(transaction) {\n this.endTransaction();\n\n this.transactions.store(transaction);\n _postTransactionMessage.call(this, 'stored', transaction);\n}\n\n\nfunction _postTransactionMessage(msg, transaction) {\n if (this._messenger)\n this._messenger.postMessage(msg, { transaction: transaction });\n}\n\n\nfunction TransactionHistory$undo(cb) {\n var t = this.transactions.undo(cb);\n if (t) _postTransactionMessage.call(this, 'undone', t);\n return t;\n}\n\n\nfunction TransactionHistory$redo(cb) {\n var t = this.transactions.redo(cb);\n if (t) _postTransactionMessage.call(this, 'redone', t);\n return t;\n}\n\n\nfunction TransactionHistory$inTransaction() {\n return this[SCHEDULED];\n}\n\n\nfunction TransactionHistory$getDescription() {\n return this.transactions.getDescription();\n}\n\n\nfunction TransactionHistory$useMessenger() {\n return this._messenger = new Messenger(this, Messenger.defaultMethods);\n}\n\n\nfunction TransactionHistory$destroy() {\n if (this._messenger) this._messenger.destroy();\n delete this.transactions;\n}\n",
- "'use strict';\n\n\nvar FacetedObject = require('../abstract/faceted_object')\n , facetsRegistry = require('./c_facets/cf_registry')\n , ComponentFacet = facetsRegistry.get('ComponentFacet')\n , componentUtils = require('./c_utils')\n , Messenger = require('../messenger')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match\n , config = require('../config')\n , miloComponentName = require('../util/component_name')\n , logger = require('../util/logger')\n , domUtils = require('../util/dom')\n , ComponentError = require('../util/error').Component\n , BindAttribute = require('../attributes/a_bind')\n , Scope = require('./scope')\n , DOMStorage = require('../util/storage')\n , jsonParse = require('../util/json_parse');\n\nvar _makeComponentConditionFunc = componentUtils._makeComponentConditionFunc;\n\n\n/**\n * `milo.Component`\n * Base Component class. Subclass of [FacetedObject](../abstract/faceted_object.js.html), but none of this class methods should be directly used with component.\n * Its constructor passes its parameters, including its [scope](./scope.js.html), DOM element and name to [`init`](#init) method.\n * The constructor of Component class rarely needs to be used directly, as [milo.binder](../binder.js.html) creates components when it scans DOM tree.\n * [`Component.createComponentClass`](#createComponentClass) should be used to create a subclass of Component class with configured facets.\n *\n *\n * ####Component instance properties####\n *\n * - el - DOM element that component is attached to. If the second component is attached to the same DOM element, the warning will be logged to console. To get component reference from DOM element use [Component.getComponent](./c_utils.js.html#getComponent) class method. To inspect component via element in browser check `___milo_component` property of element (property name be changed using `milo.config`).\n * - scope - parent scope object, an instance of [Scope](./scope.js.html) class. To get parent component use [getScopeParent](#Component$getScopeParent) instance method of component. The actual path to get parent of conponent is `component.scope._hostObject.owner`, where `_hostObject` refers to [Container](c_facets/Container.js.html) facet of parent component and `owner` to the parent itself. The children of component are accessible via the scope of its container facet: `component.container.scope`. The scope hierarchy can be the same or different as the DOM hierarchy - DOM children of the component will be on the same scope as component if it does not have `Container` facet and in the scope of its Container facet if it has it. See [Scope](./scope.js.html).\n * - name - the name of component, should be unique for the scope where component belongs. To find component in scope the component's name should be used as property of scope object. See [Scope](./scope.js.html).\n * - facets - map of references of all component's facets (facet names are lowercase in this map). All facets can be accessed directly as properties of component, this property can be used to iterate facets (it is used in this way in [allFacets](#Component$allFacets) component's instance method that allows to call method with the same name on all facets).\n * - extraFacets - an array of names of facets that are added to component and do not form the part of component's class.\n * - _messenger - the reference to component's [messenger](../messenger/index.js.html). Rarely needs to be used directly as all commonly used methods of mesenger are available directly on component.\n *\n *\n * ####Component events####\n *\n * - 'childrenbound' - synchronously dispatched when children of DOM element which compnent is connected to are connected to components. The event is dispatched when component is created with `milo.binder` (as is almost always the case, as all Component class methods that create/copy components use `milo.binder` internally - component constructor and Component.create methods are not used in framework outside of `milo.binder` and rarely if ever need to be used in aplication).\n * - 'addedtoscope' - synchronously dispatched when component is added to scope.\n * - 'stateready' - aynchronously dispatched when component (together with its scope children) is created with [Component.createFromState](#Component$$createFromState) (or `createFromDataTransfer`) method. Can be dispatched by application if the component's state is set with some other mechanism. This event is not used in `milo`, it can be used in application in particular subclasses of component.\n * - 'getstatestarted' - emitted synchronously just before getState executes so components and facets can clean up their state for serialization. \n * - 'getstatecompleted' - emitted asynchronously after getState executes so components and facets can restore their state after serialization.\n *\n *\n * ####Component \"lifecycle\"####\n *\n * 1. Component constructor is called. Component's constructor simply calls constructor of [FacetedObject](../abstract/faceted_object.js.html) that is a superclass of Component. Subclasses of Component should not implement their own constructor, they can optionally implement `init` method, but most components do not need to do it.\n * 2. constructors and `init` methods of all facets are called in sequence. Same as components, facet do not implement their constructors, they can optionally implement `init` and `start` methods (see below). Inside `init` method there should be only general initialization code without any dependency on component itself (it is not ready yet) and other facets (as there is no specific facets creation order). If facet implements `init` method it MUST call inherited init with `ComponentFacet.prototype.init.apply(this, arguments)`.\n * 3. `init` method of component is called. At this point all facets are created but facets still can be not ready as they can have initialization code in `start` method. If component subclass implements `init` method it MUST call inherited method with `.prototype.init.apply(this, arguments)`, where is Component or another superclass the component is a subclass of.\n * 4. `check` method of all facets is called. This method adds facets that are not part of the component declaration (being part of the class or explicitely listed in bind attribute) but are required by facets that the compnent already has. Subclasses of [ComponentFacet](./c_facet.js.html) do not need to implement this method.\n * 5. `start` method of all facets is called. This method is usually implemented by ComponentFacet subclasses and it can have any initialization code that depends on component or on other facets that are the dependencies of a facet. Inherited `start` method should be called int he same way as written above.\n * 6. `start` method of component is called. This component method can be implemented by subclasses if they need to have some initialization code that depends on some facets and requires that these facets are fully inialized. Often such code also depends on component's scope children as well so this code should be inside `'childrenbound'` event subscriber.\n * 7. 'addedtoscope' event is dispatched when component is added to its parent's scope or to top level scope created by `milo.binder`.\n * 8. component's children are created (steps 1-6 above are followed for each child).\n * 9. 'childrenbound' event is dispatched when all component's children are created and added to their scope (see event description below).\n * 10. 'stateready' event is dispatched for component and all its children when component is create from state (see event description below).\n * 11. at this point component is in the \"interactive\" state when it and its facets will only respond to messages/events that they subscribed to during initialization.\n *\n *\n * @param {Scope} scope scope to which component will belong. It is usually a top level scope object returned by `milo.binder` or `scope` property of Container facet.\n * @param {Element} element DOM element that component is attached to\n * @param {String} name component name, should be unique in the scope of component\n * @param {ComponentInfo} componentInfo instance of ComponentInfo class that can be used to create a copy of component\n * TODO try removing it\n * @return {Component}\n */\nvar Component = _.createSubclass(FacetedObject, 'Component', true);\n\nmodule.exports = Component;\n\n_registerWithDomStorage('Component');\n\n\n/**\n * ####Component class methods####\n *\n * - [createComponentClass](#Component$$createComponentClass)\n * - [create](#Component$$create)\n * - [copy](#Component$$copy)\n * - [createOnElement](#Component$$createOnElement)\n * - [isComponent](c_utils.js.html#isComponent)\n * - [getComponent](c_utils.js.html#getComponent)\n * - [getContainingComponent](c_utils.js.html#getContainingComponent)\n * - [createFromState](#Component$$createFromState)\n * - [createFromDataTransfer](#Component$$createFromDataTransfer)\n */\n_.extend(Component, {\n createComponentClass: Component$$createComponentClass,\n create: Component$$create,\n copy: Component$$copy,\n createOnElement: Component$$createOnElement,\n isComponent: componentUtils.isComponent,\n getComponent: componentUtils.getComponent,\n getContainingComponent: componentUtils.getContainingComponent,\n createFromState: Component$$createFromState,\n createFromDataTransfer: Component$$createFromDataTransfer\n});\ndelete Component.createFacetedClass;\n\n\n/**\n * ####Component instance methods####\n *\n * - [init](#Component$init)\n * - [createElement](#Component$createElement)\n * - [hasFacet](#Component$hasFacet)\n * - [addFacet](#Component$addFacet)\n * - [allFacets](#Component$allFacets)\n * - [rename](#Component$rename)\n * - [remove](#Component$remove)\n * - [getState](#Component$getState)\n * - [getTransferState](#Component$getTransferState)\n * - [setState](#Component$setState)\n * - [getScopeParent](#Component$getScopeParent)\n * - [getTopScopeParent](#Component$getTopScopeParent)\n * - [getScopeParentWithClass](#Component$getScopeParentWithClass)\n * - [getTopScopeParentWithClass](#Component$getTopScopeParentWithClass)\n * - [walkScopeTree](#Component$walkScopeTree)\n * - [broadcast](#Component$broadcast)\n * - [destroy](#Component$destroy)\n * - [isDestroyed](#Component$isDestroyed)\n *\n *\n * #####[Messenger](../messenger/index.js.html) methods available on component#####\n *\n * - [on](../messenger/index.js.html#Messenger$on) - single subscribe\n * - [off](../messenger/index.js.html#Messenger$off) - single unsubscribe\n * - [onMessages](../messenger/index.js.html#Messenger$onMessages) - multiple subscribe\n * - [offMessages](../messenger/index.js.html#Messenger$offMessages) - multiple unsubscribe\n * - [postMessage](../messenger/index.js.html#Messenger$postMessage) - post message on component\n * - [getSubscribers](../messenger/index.js.html#Messenger$getSubscribers) - get subscribers for a given message\n */\n_.extendProto(Component, {\n init: Component$init,\n start: Component$start,\n createElement: Component$createElement,\n hasFacet: Component$hasFacet,\n addFacet: Component$addFacet,\n allFacets: Component$allFacets,\n rename: Component$rename,\n remove: Component$remove,\n insertInto: Component$insertInto,\n\n getState: Component$getState,\n getTransferState: Component$getTransferState,\n _getState: Component$_getState,\n setState: Component$setState,\n \n getScopeParent: Component$getScopeParent,\n getTopScopeParent: Component$getTopScopeParent,\n getScopeParentWithClass: Component$getScopeParentWithClass,\n getTopScopeParentWithClass: Component$getTopScopeParentWithClass,\n\n setScopeParentFromDOM: Component$setScopeParentFromDOM,\n\n walkScopeTree: Component$walkScopeTree,\n\n treePathOf: Component$treePathOf,\n getComponentAtTreePath: Component$getComponentAtTreePath,\n insertAtTreePath: Component$insertAtTreePath,\n\n broadcast: Component$broadcast,\n destroy: Component$destroy,\n isDestroyed: Component$isDestroyed\n});\n\n\n/**\n * Expose Messenger methods on Component prototype\n */\nvar MESSENGER_PROPERTY = '_messenger';\nMessenger.useWith(Component, MESSENGER_PROPERTY, Messenger.defaultMethods);\n\n\nvar COMPONENT_DATA_TYPE_PREFIX = 'x-application/milo-component';\nvar COMPONENT_DATA_TYPE_REGEX = /x-application\\/milo-component\\/([a-z_$][0-9a-z_$]*)(?:\\/())/i;\n\n/**\n * Component class method\n * Creates a subclass of component from the map of configured facets.\n * This method wraps and replaces [`createFacetedClass`](../abstract/faceted_object.js.html#createFacetedClass) class method of FacetedObject.\n * Unlike createFacetedClass, this method take facet classes from registry by their name, so only map of facets configuration needs to be passed. All facets classes should be subclasses of [ComponentFacet](./c_facet.js.html)\n *\n * @param {String} name class name\n * @param {Object[Object] | Array[String]} facetsConfig map of facets configuration.\n * If some facet does not require configuration, `undefined` should be passed as the configuration for the facet.\n * If no facet requires configuration, the array of facets names can be passed.\n * @return {Subclass(Component)}\n */\nfunction Component$$createComponentClass(name, facetsConfig) {\n // convert array of facet names to map of empty facets configurations\n if (Array.isArray(facetsConfig)) {\n var configMap = {};\n facetsConfig.forEach(function(fct) {\n var fctName = _.firstLowerCase(fct);\n configMap[fctName] = {};\n });\n facetsConfig = configMap;\n }\n\n // construct map of facets classes from facetRegistry\n var facetsClasses;\n if (typeof facetsConfig == 'object' && _.keys(facetsConfig).length) {\n facetsClasses = {};\n _.eachKey(facetsConfig, function(fctConfig, fct) {\n var fctName = _.firstLowerCase(fct);\n var fctClassName = _.firstUpperCase(fct);\n facetsClasses[fctName] = facetsRegistry.get(fctClassName);\n });\n }\n\n // create subclass of Component using method of FacetedObject\n var ComponentClass = FacetedObject.createFacetedClass.call(this, name, facetsClasses, facetsConfig);\n \n _registerWithDomStorage(name);\n\n return ComponentClass;\n}\n\n\nfunction _registerWithDomStorage(className) {\n DOMStorage.registerDataType(className, Component_domStorageSerializer, Component_domStorageParser);\n}\n\n\nfunction Component_domStorageSerializer(component) {\n var state = component.getState();\n return JSON.stringify(state); \n}\n\n\nfunction Component_domStorageParser(compStr, compClassName) {\n var state = jsonParse(compStr);\n if (state)\n return Component.createFromState(state);\n}\n\n\n/**\n * Component class method\n * Creates component from [ComponentInfo](./c_info.js.html) (used by [milo.binder](../binder.js.html) and to copy component)\n * Component of any registered class (see [componentsRegistry](./c_registry.js.html)) with any additional registered facets (see [facetsRegistry](./c_facets/cf_registry.js.html)) can be created using this method.\n *\n * @param {ComponentInfo} info\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n @ @return {Component}\n */\nfunction Component$$create(info, throwOnErrors) {\n var ComponentClass = info.ComponentClass;\n\n if (typeof ComponentClass != 'function') {\n var message = 'create: component class should be function, \"' + typeof ComponentClass + '\" passed'; \n if (throwOnErrors === false) {\n logger.error('Component', message, ';using base Component class instead');\n ComponentClass = Component;\n } else\n throw new ComponentError(message);\n }\n\n var aComponent = new ComponentClass(info.scope, info.el, info.name, info);\n\n if (info.extraFacetsClasses)\n _.eachKey(info.extraFacetsClasses, function(FacetClass) {\n if (! aComponent.hasFacet(FacetClass))\n aComponent.addFacet(FacetClass, undefined, undefined, throwOnErrors);\n });\n\n return aComponent;\n}\n\n\n/**\n * Component class method\n * Create a copy of component, including a copy of DOM element. Returns a copy of `component` (of the same class) with new DOM element (not inserted into page).\n * Component is added to the same scope as the original component.\n *\n * @param {Component} component an instance of Component class or subclass\n * @param {Boolean} deepCopy optional `true` to make deep copy of DOM element, otherwise only element without children is copied\n * @return {Component}\n */\nfunction Component$$copy(component, deepCopy) {\n check(component, Component);\n check(deepCopy, Match.Optional(Boolean));\n\n if (deepCopy && !component.container) \n throw new ComponentError('Cannot deep copy component without container facet');\n\n // copy DOM element, using Dom facet if it is available\n var newEl = component.dom \n ? component.dom.copy(deepCopy)\n : component.el.cloneNode(deepCopy);\n\n var ComponentClass = component.constructor;\n\n // create component of the same class on the element\n var aComponent = ComponentClass.createOnElement(newEl, undefined, component.scope, component.extraFacets);\n var state = component._getState(deepCopy || false);\n aComponent.setState(state);\n _.deferMethod(aComponent, 'broadcast', 'stateready');\n return aComponent;\n}\n\n\n/**\n * Component class method\n * Creates an instance of component atached to element. All subclasses of component inherit this method.\n * Returns the component of the class this method is used with (thecontext of the method call).\n *\n * @param {Element} el optional element to attach component to. If element is not passed, it will be created\n * @param {String} innerHTML optional inner html to insert in element before binding.\n * @param {Scope} rootScope optional scope to put component in. If not passed, component will be attached to the scope that contains the element. If such scope does not exist, new scope will be created.\n * @param {Array[String]} extraFacets list of extra facet to add to component\n * @return {Subclass(Component)}\n */\nfunction Component$$createOnElement(el, innerHTML, rootScope, extraFacets) {\n check(innerHTML, Match.Optional(String));\n check(rootScope, Match.Optional(Scope));\n check(extraFacets, Match.Optional([String]));\n\n // \"this\" refers to the class of component here, as this is a class method\n if (el && innerHTML) el.innerHTML = innerHTML;\n el = el || _createComponentElement.call(this, innerHTML);\n rootScope = rootScope || _findOrCreateComponentRootScope(el);\n var aComponent = _addAttributeAndBindComponent.call(this, el, rootScope, extraFacets);\n aComponent.broadcast('stateready');\n return aComponent;\n}\n\nfunction _createComponentElement(innerHTML) {\n // \"this\" refers to the class of component here, as this is a class method\n var Dom = facetsRegistry.get('Dom')\n , domFacetConfig = this.getFacetConfig('dom')\n , templateFacetConfig = this.getFacetConfig('template')\n , template = templateFacetConfig && templateFacetConfig.template;\n\n var elConfig = {\n domConfig: domFacetConfig,\n template: template,\n content: innerHTML\n };\n\n return Dom.createElement(elConfig);\n}\n\nfunction _findOrCreateComponentRootScope(el) {\n var parent = Component.getContainingComponent(el, false, 'Container');\n return parent ? parent.container.scope : new Scope(el);\n}\n\nfunction _addAttributeAndBindComponent(el, rootScope, extraFacets) {\n // add bind attribute to element\n var attr = new BindAttribute(el);\n // \"this\" refers to the class of component here, as this is a class method\n attr.compClass = this.name;\n attr.compFacets = extraFacets;\n attr.decorate();\n\n // should be required here to resolve circular dependency\n var miloBinder = require('../binder');\n miloBinder(el, rootScope);\n\n return rootScope[attr.compName];\n}\n\n/**\n * Component class method\n * Creates component from component state, that includes information about its class, extra facets, facets data and all scope children.\n * This is used to save/load, copy/paste and drag/drop component\n *\n * @param {Object} state state from which component will be created\n * @param {Scope} rootScope scope to which component will be added\n * @param {Boolean} newUniqueName optional `true` to create component with the name different from the original one. `False` by default.\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n * @return {Component} component\n */\nfunction Component$$createFromState(state, rootScope, newUniqueName, throwOnErrors) {\n check(state, Match.ObjectIncluding({\n compName: Match.Optional(String),\n compClass: Match.Optional(String),\n extraFacets: Match.Optional([String]),\n facetsStates: Match.Optional(Object),\n outerHTML: String\n }));\n\n var miloBinder = require('../binder');\n\n // create wrapper element optionally renaming component\n var wrapEl = _createComponentWrapElement(state, newUniqueName);\n\n // instantiate all components from HTML\n var scope = miloBinder(wrapEl, undefined, undefined, throwOnErrors);\n\n // as there should only be one component, call to _any will return it\n var component = scope._any();\n\n // set component's scope\n if (rootScope) {\n component.scope = rootScope;\n rootScope._add(component);\n }\n\n // restore component state\n component.setState(state);\n _.deferMethod(component, 'broadcast', 'stateready');\n\n return component; \n}\n\n\n// used by Component$$createFromState\nfunction _createComponentWrapElement(state, newUniqueName) {\n var wrapEl = document.createElement('div');\n wrapEl.innerHTML = state.outerHTML;\n\n var children = domUtils.children(wrapEl);\n if (children.length != 1)\n throw new ComponentError('cannot create component: incorrect HTML, elements number: ' + children.length + ' (should be 1)');\n var compEl = children[0];\n var attr = new BindAttribute(compEl);\n attr.compName = newUniqueName ? miloComponentName() : state.compName;\n attr.compClass = state.compClass;\n attr.compFacets = state.extraFacets;\n attr.decorate();\n\n return wrapEl;\n}\n\n/**\n * Creates a component from a DataTransfer object (if possible)\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer\n * @param {DataTransfer} dataTransfer Data transfer\n */\nfunction Component$$createFromDataTransfer(dataTransfer) {\n var dataType = _.find(dataTransfer.types, function (type) {\n return COMPONENT_DATA_TYPE_REGEX.test(type);\n });\n if (!dataType) return;\n\n var state = _.jsonParse(dataTransfer.getData(dataType));\n if (!state) return;\n\n return Component.createFromState(state, undefined, true);\n}\n\n\n/**\n * Component instance method.\n * Initializes component. Automatically called by inherited constructor of FacetedObject.\n * Subclasses should call inherited init methods:\n * ```\n * Component.prototype.init.apply(this, arguments)\n * ```\n *\n * @param {Scope} scope scope to which component will belong. It is usually a top level scope object returned by `milo.binder` or `scope` property of Container facet.\n * @param {Element} element DOM element that component is attached to\n * @param {String} name component name, should be unique in the scope of component\n * @param {ComponentInfo} componentInfo instance of ComponentInfo class that can be used to create a copy of component\n * TODO try removing it\n */\nfunction Component$init(scope, element, name, componentInfo) {\n // create DOM element if it wasn't passed to Constructor\n this.el = element || this.createElement();\n\n // store reference to component on DOM element\n if (this.el) {\n // check that element does not have a component already atached\n var elComp = this.el[config.componentRef];\n if (elComp)\n logger.warn('component ' + name + ' attached to element that already has component ' + elComp.name);\n\n this.el[config.componentRef] = this;\n }\n\n _.defineProperties(this, {\n componentInfo: componentInfo,\n extraFacets: []\n }, _.ENUM);\n\n this.name = name;\n this.scope = scope;\n\n // create component messenger\n var messenger = new Messenger(this);\n _.defineProperty(this, MESSENGER_PROPERTY, messenger);\n\n // check all facets dependencies (required facets)\n this.allFacets('check');\n\n // start all facets\n this.allFacets('start');\n\n // call start method if it's defined in subclass\n if (this.start) this.start();\n}\n\n\n/**\n * This is a stub to avoid confusion whether the method of superclass should be called in subclasses\n * The start method of subclass instance is called once all the facets are created, initialized and started (see above)\n */\nfunction Component$start() {}\n\n\n/**\n * Component instance method.\n * Initializes the element which this component is bound to\n *\n * This method is called when a component is instantiated outside the DOM and\n * will generate a new element for the component.\n * \n * @return {Element}\n */\nfunction Component$createElement() {\n if (typeof document == 'undefined')\n return;\n\n this.el = this.dom\n ? this.dom.createElement()\n : document.createElement('DIV');\n\n return this.el;\n}\n\n\n/**\n * Component instance method\n * Returns true if component has facet\n *\n * @param {Function|String} facetNameOrClass\n * @return {Boolean}\n */\nfunction Component$hasFacet(facetNameOrClass) {\n var facetName = _.firstLowerCase(typeof facetNameOrClass == 'function'\n ? facetNameOrClass.name\n : facetNameOrClass);\n\n var facet = this[facetName];\n if (! facet instanceof ComponentFacet)\n logger.warn('expected facet', facetName, 'but this property name is used for something else');\n\n return !! facet;\n}\n\n\n/**\n * Component instance method.\n * Adds facet with given name or class to the instance of Component (or its subclass).\n * \n * @param {String|Subclass(Component)} facetNameOrClass name of facet class or the class itself. If name is passed, the class will be retireved from facetsRegistry\n * @param {Object} facetConfig optional facet configuration\n * @param {String} facetName optional facet name. Allows to add facet under a name different from the class name supplied.\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n */\nfunction Component$addFacet(facetNameOrClass, facetConfig, facetName, throwOnErrors) {\n check(facetNameOrClass, Match.OneOf(String, Match.Subclass(ComponentFacet)));\n check(facetConfig, Match.Optional(Object));\n check(facetName, Match.Optional(String));\n\n var FacetClass;\n // if only name passed, retrieve facet class from registry\n if (typeof facetNameOrClass == 'string') {\n var facetClassName = _.firstUpperCase(facetNameOrClass);\n FacetClass = facetsRegistry.get(facetClassName);\n } else \n FacetClass = facetNameOrClass;\n\n if (!facetName)\n facetName = _.firstLowerCase(FacetClass.name);\n\n this.extraFacets.push(facetName);\n\n // add facet using method of FacetedObject\n var newFacet = FacetedObject.prototype.addFacet.call(this, FacetClass, facetConfig, facetName, throwOnErrors);\n\n // check depenedencies and start facet\n if (newFacet.check) newFacet.check();\n if (newFacet.start) newFacet.start();\n}\n\n\n/**\n * Component instance method.\n * Envoke given method with optional parameters on all facets.\n * Returns the map of values returned by all facets. If the facet doesn't have the method it is simply not called and the value in the map will be undefined.\n *\n * @param {String} method method name to envoke on the facet\n * @return {Object}\n */\nfunction Component$allFacets(method) { // ,... arguments\n var args = _.slice(arguments, 1);\n\n return _.mapKeys(this.facets, function(facet, fctName) {\n if (facet && typeof facet[method] == 'function')\n return facet[method].apply(facet, args);\n });\n}\n\n\n/**\n * Component instance method.\n * \n * @param {[String]} name optional new name of component, \n * @param {[Boolean]} renameInScope optional false to not rename ComponentInfo object in its scope, true by default\n */\nfunction Component$rename(name, renameInScope) {\n name = name || miloComponentName();\n this.componentInfo.rename(name, false);\n Scope.rename(this, name, renameInScope);\n}\n\n\n/**\n * Component instance method.\n * Removes component from its scope.\n *\n * @param {Boolean} preserveScopeProperty true not to delete scope property of component\n * @param {Boolean} quiet optional true to suppress the warning message if the component is not in scope\n */\nfunction Component$remove(preserveScopeProperty, quiet) {\n if (this.scope) {\n this.scope._remove(this.name, quiet);\n if (! preserveScopeProperty)\n delete this.scope;\n }\n}\n\n\n/**\n * Component instance method.\n * Inserts the component into the DOM and attempts to adjust the scope tree accordingly.\n * @param {HTMLElement} parentEl The element into which the component should be inserted.\n * @param {HTMLElement} referenceEl (optional) The reference element it should be inserted before.\n */\nfunction Component$insertInto(parentEl, referenceEl) {\n parentEl.insertBefore(this.el, referenceEl);\n this.setScopeParentFromDOM();\n}\n\n\n/**\n * Component instance method\n * Retrieves all component state, including information about its class, extra facets, facets data and all scope children.\n * This information is used to save/load, copy/paste and drag/drop component \n * Returns component state\n *\n * @this {Component} component which state will be saved\n * @return {Object}\n */\nfunction Component$getState() {\n this.broadcast('getstatestarted', { rootComponent: this }, undefined, true);\n var state = this._getState(true);\n state.outerHTML = this.el.outerHTML;\n _.deferMethod(this, 'broadcast', 'getstatecompleted', { rootComponent: this }, undefined, true);\n return state;\n}\n\n\n/**\n * Component instance method\n * Retrieves all component state, including information about its class, extra facets, facets data and all scope children.\n * This information is used to save/load, copy/paste and drag/drop component \n * If component has [Transfer](./c_facets/Transfer.js.html) facet on it, this method retrieves state from this facet\n * Returns component state\n *\n * @this {Component} component which state will be saved\n * @param {Object} options can be used by subclasses. \n * @return {Object}\n */\nfunction Component$getTransferState(options) {\n return this.transfer\n ? this.transfer.getState(options)\n : this.getState(options);\n}\n\n\n/**\n * Component instance method\n * Returns the state of component\n * Used by class method `Component.getState` and by [Container](./c_facets/Container.js.html) facet.\n *\n * @private\n * @param {Boolean} deepState false to get shallow state from all facets (true by default)\n * @return {Object}\n */\nfunction Component$_getState(deepState){\n\n var facetsStates = this.allFacets('getState', deepState === false ? false : true);\n facetsStates = _.filterKeys(facetsStates, function(fctState) {\n return !! fctState;\n });\n\n return {\n compName: this.name,\n compClass: this.constructor.name,\n extraFacets: this.extraFacets,\n facetsStates: facetsStates\n };\n}\n\n\n/**\n * Component instance method\n * Sets the state of component.\n * Used by class method `Component.createFromState` and by [Container](./c_facets/Container.js.html) facet.\n *\n * @private\n * @param {Object} state state to set the component\n */\nfunction Component$setState(state) {\n if (state.facetsStates)\n _.eachKey(state.facetsStates, function(fctState, fctName) {\n var facet = this[fctName];\n if (facet && typeof facet.setState == 'function')\n facet.setState(fctState);\n }, this);\n}\n\n\n/**\n * Component instance method.\n * Returns the scope parent of a component.\n * If `conditionOrFacet` parameter is not specified, an immediate parent will be returned, otherwise the closest ancestor with a specified facet or passing condition test.\n *\n * @param {Function|String} conditionOrFacet optional condition that component should pass (or facet name it should contain)\n * @return {Component|undefined}\n */\nfunction Component$getScopeParent(conditionOrFacet) {\n return _callGetScopeParent.call(this, _getScopeParent, conditionOrFacet);\n}\n\nfunction _callGetScopeParent(_getScopeParentFunc, conditionOrFacet) {\n check(conditionOrFacet, Match.Optional(Match.OneOf(Function, String)));\n var conditionFunc = componentUtils._makeComponentConditionFunc(conditionOrFacet);\n return _getScopeParentFunc.call(this, conditionFunc); \n}\n\nfunction _getScopeParent(conditionFunc) {\n var parent;\n try { parent = this.scope._hostObject.owner; } catch(e) {}\n\n // Where there is no parent, this function will return undefined\n // The parent component is checked recursively\n if (parent) {\n if (! conditionFunc || conditionFunc(parent) )\n return parent;\n else\n return _getScopeParent.call(parent, conditionFunc);\n }\n}\n\n\n/**\n * Component instance method\n * Returns scope parent with a given class, with same class if not specified\n *\n * @param {[Function]} ComponentClass component class that the parent should have, same class by default\n * @return {Component}\n */\nfunction Component$getScopeParentWithClass(ComponentClass) {\n ComponentClass = ComponentClass || this.constructor;\n return _getScopeParent.call(this, function(comp) {\n return comp instanceof ComponentClass;\n });\n}\n\n\n/**\n * Component instance method.\n * Returns the topmost scope parent of a component.\n * If `conditionOrFacet` parameter is not specified, the topmost scope parent will be returned, otherwise the topmost ancestor with a specified facet or passing condition test.\n *\n * @param {Function|String} conditionOrFacet optional condition that component should pass (or facet name it should contain)\n * @return {Component|undefined}\n */\nfunction Component$getTopScopeParent(conditionOrFacet) {\n return _callGetScopeParent.call(this, _getTopScopeParent, conditionOrFacet);\n}\n\nfunction _getTopScopeParent(conditionFunc) {\n var topParent\n , parent = this;\n do {\n parent = _getScopeParent.call(parent, conditionFunc);\n if (parent)\n topParent = parent;\n } while (parent);\n\n return topParent;\n}\n\n\n/**\n * Component instance method\n * Returns scope parent with a given class, with same class if not specified\n *\n * @param {[Function]} ComponentClass component class that the parent should have, same class by default\n * @return {Component}\n */\nfunction Component$getTopScopeParentWithClass(ComponentClass) {\n ComponentClass = ComponentClass || this.constructor;\n return _getTopScopeParent.call(this, function(comp) {\n return comp instanceof ComponentClass;\n });\n}\n\n\n/**\n * Component instance method\n * Finds scope parent of component using DOM tree (unlike getScopeParent that simply goes up the scope tree).\n * While getScopeParent is faster it may fail if scope chain is not setup yet (e.g., when component has been just inserted).\n * The scope property of component will be changed to point to scope object of container facet of that parent.\n * Returned scope parent of the component will be undefined (as well as component's scope property) if no parent in the DOM tree has container facet.\n * TODO Method will not bind DOM children correctly if component has no container facet.\n *\n * @return {Component}\n */\nfunction Component$setScopeParentFromDOM() {\n var parentEl = this.el.parentNode;\n\n var parent, foundParent;\n while (parentEl && ! foundParent) {\n parent = Component.getComponent(parentEl);\n foundParent = parent && parent.container;\n parentEl = parentEl.parentNode;\n }\n\n this.remove(); // remove component from its current scope (if it is defined)\n if (foundParent) {\n this.rename(undefined, false);\n parent.container.scope._add(this);\n return parent;\n } \n}\n\n\n/**\n * Walks component tree, calling provided callback on each component\n *\n * @param callback\n * @param thisArg\n */\nfunction Component$walkScopeTree(callback, thisArg) {\n callback.call(thisArg, this);\n if (!this.container) return;\n this.container.scope._each(function(component) {\n component.walkScopeTree(callback, thisArg);\n });\n}\n\n\nfunction Component$treePathOf(component) {\n return domUtils.treePathOf(this.el, component.el);\n}\n\n\nfunction Component$getComponentAtTreePath(treePath, nearest) {\n var node = domUtils.getNodeAtTreePath(this.el, treePath, nearest);\n return Component.getComponent(node);\n}\n\n\nfunction Component$insertAtTreePath(treePath, component, nearest) {\n var wasInserted = domUtils.insertAtTreePath(this.el, treePath, component.el);\n if (wasInserted) component.setScopeParentFromDOM();\n return wasInserted;\n}\n\n\n/**\n * Broadcast message to component and to all its scope children\n *\n * @param {String|RegExp} msg message to be sent\n * @param {[Any]} data optional message data\n * @param {[Function]} callback optional callback\n * @param {[Boolean]} synchronously if it should use postMessageSync\n */\nfunction Component$broadcast(msg, data, callback, synchronously) {\n var postMethod = synchronously ? 'postMessageSync' : 'postMessage';\n this.walkScopeTree(function(component) {\n component[postMethod](msg, data, callback);\n });\n}\n\n\n/**\n * Destroy component: removes component from DOM, removes it from scope, deletes all references to DOM nodes and unsubscribes from all messages both component and all facets\n */\nfunction Component$destroy(quiet) {\n if (this._destroyed) {\n if (!quiet) logger.warn('Component destroy: component is already destroyed');\n return;\n }\n this.remove(false, quiet);\n this.allFacets('destroy');\n this[MESSENGER_PROPERTY].destroy();\n if (this.el) {\n domUtils.detachComponent(this.el);\n domUtils.removeElement(this.el);\n delete this.el;\n }\n this.componentInfo.destroy();\n this._destroyed = true;\n}\n\n\n/**\n * Returns true if component was destroyed\n *\n * @return {Boolean}\n */\nfunction Component$isDestroyed() {\n return this._destroyed;\n}\n",
- "'use strict';\n\n/**\n * `milo.Component.Facet`\n *\n * The class fot the facet of component. When a component is created, it\n * creates all its facets.\n *\n * See Facets section on information about available facets and on\n * how to create new facets classes.\n *\n * - Component - basic compponent class\n * - ComponentFacet - basic\n */\n\nvar Facet = require('../abstract/facet')\n , Messenger = require('../messenger')\n , FacetError = require('../util/error').Facet\n , componentUtils = require('./c_utils')\n , _ = require('mol-proto');\n\nvar ComponentFacet = _.createSubclass(Facet, 'ComponentFacet');\n\nmodule.exports = ComponentFacet;\n\n\n/**\n * postDomParent\n *\n * If facet has DOM parent facet (see `domParent` method), posts the message to this facet.\n *\n * @param {String} messageType\n * @param {Object} messageData\n */\nvar postDomParent = _.partial(_postParent, domParent);\n\n/**\n * postScopeParent\n *\n * If facet has scope parent facet (see `scopeParent` method), posts the message to this facet.\n *\n * @param {String} messageType\n * @param {Object} messageData\n */\nvar postScopeParent = _.partial(_postParent, scopeParent);\n\n\n_.extendProto(ComponentFacet, {\n init: ComponentFacet$init,\n start: ComponentFacet$start,\n check: ComponentFacet$check,\n destroy: ComponentFacet$destroy,\n onConfigMessages: ComponentFacet$onConfigMessages,\n domParent: domParent,\n postDomParent: postDomParent,\n scopeParent: scopeParent,\n postScopeParent: postScopeParent,\n getMessageSource: getMessageSource,\n dispatchSourceMessage: dispatchSourceMessage,\n _createMessenger: _createMessenger,\n _setMessageSource: _setMessageSource,\n _createMessageSource: _createMessageSource,\n _createMessageSourceWithAPI: _createMessageSourceWithAPI\n});\n\n_.extend(ComponentFacet, {\n requiresFacet: requiresFacet\n});\n\n\n/**\n * Expose Messenger methods on Facet prototype\n */\nvar MESSENGER_PROPERTY = '_messenger';\nMessenger.useWith(ComponentFacet, MESSENGER_PROPERTY, Messenger.defaultMethods);\n\n\n// initComponentFacet\nfunction ComponentFacet$init() {\n this._createMessenger();\n}\n\n\n// some subclasses (e.g. ModelFacet) overrride this method and do not create their own messenger\nfunction _createMessenger(){\n _.defineProperty(this, MESSENGER_PROPERTY, new Messenger(this));\n}\n\n\n// startComponentFacet\nfunction ComponentFacet$start() {\n if (this.config.messages)\n this.onConfigMessages(this.config.messages);\n}\n\n\nfunction ComponentFacet$onConfigMessages(messageSubscribers) {\n var notYetRegisteredMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {\n var subscriberType = typeof subscriber;\n if (subscriberType == 'function')\n return this.on(messages, subscriber);\n\n if (subscriberType == 'object') {\n var contextType = typeof subscriber.context;\n if (contextType == 'object')\n return this.on(messages, subscriber);\n\n if (contextType == 'string') {\n if (subscriber.context == this.name || subscriber.context == 'facet')\n subscriber = {\n subscriber: subscriber.subscriber,\n context: this\n };\n else if (subscriber.context == 'owner')\n subscriber = {\n subscriber: subscriber.subscriber,\n context: this.owner\n };\n else\n throw new FacetError('unknown subscriber context in configuration: ' + subscriber.context);\n\n return this.on(messages, subscriber);\n }\n\n throw new FacetError('unknown subscriber context type in configuration: ' + contextType);\n }\n\n throw new FacetError('unknown subscriber type in configuration: ' + subscriberType);\n }, this);\n\n return notYetRegisteredMap;\n}\n\n\n// checkDependencies\nfunction ComponentFacet$check() {\n if (this.require) {\n this.require.forEach(function(reqFacet) {\n if (! this.owner.hasFacet(reqFacet))\n this.owner.addFacet(reqFacet);\n }, this);\n }\n}\n\n\n// destroys facet\nfunction ComponentFacet$destroy() {\n if (this[MESSENGER_PROPERTY]) this[MESSENGER_PROPERTY].destroy();\n this._destroyed = true;\n}\n\n\n/**\n * domParent\n *\n * @return {ComponentFacet} reference to the facet of the same class of the closest parent DOM element, that has a component with the same facet class attached to it. If such element doesn't exist method will return undefined.\n */\nfunction domParent() {\n var parentComponent = componentUtils.getContainingComponent(this.owner.el, false, this.name);\n return parentComponent && parentComponent[this.name];\n}\n\n\n/**\n * scopeParent\n *\n * @return {ComponentFacet} reference to the facet of the same class as `this` facet of the closest scope parent (i.e., the component that has the scope of the current component in its container facet).\n */\nfunction scopeParent() {\n var parentComponent = this.owner.getScopeParent(this.name);\n return parentComponent && parentComponent[this.name];\n}\n\n\nfunction _postParent(getParentMethod, messageType, messageData) {\n var parentFacet = getParentMethod.call(this);\n if (parentFacet)\n parentFacet.postMessage(messageType, messageData);\n}\n\n\nfunction _setMessageSource(messageSource) {\n this[MESSENGER_PROPERTY]._setMessageSource(messageSource);\n}\n\n\nfunction getMessageSource() {\n return this[MESSENGER_PROPERTY].getMessageSource();\n}\n\n\nfunction dispatchSourceMessage(message, data) {\n return this.getMessageSource().dispatchMessage(message, data);\n}\n\n\nfunction _createMessageSource(MessageSourceClass, options) {\n var messageSource = new MessageSourceClass(this, undefined, undefined, this.owner, options);\n this._setMessageSource(messageSource)\n\n _.defineProperty(this, '_messageSource', messageSource);\n}\n\n\nfunction _createMessageSourceWithAPI(MessageSourceClass, messengerAPIOrClass, options) {\n var messageSource = new MessageSourceClass(this, undefined, messengerAPIOrClass, this.owner, options);\n this._setMessageSource(messageSource)\n\n _.defineProperty(this, '_messageSource', messageSource);\n}\n\n\nfunction requiresFacet(facetName) {\n // 'this' refers to the Facet Class\n var facetRequire = this.prototype.require;\n\n return facetRequire && (facetRequire.indexOf(_.firstUpperCase(facetName)) >= 0\n || facetRequire.indexOf(_.firstLowerCase(facetName)) >= 0);\n}\n",
- "'use strict';\n\n\nvar ComponentFacet = require('../c_facet')\n , miloBinder = require('../../binder')\n , Scope = require('../scope')\n , _ = require('mol-proto')\n , facetsRegistry = require('./cf_registry')\n , domUtils = require('../../util/dom')\n , logger = require('../../util/logger');\n\n\n/**\n * `milo.registry.facets.get('Container')`\n * A special component facet that makes component create its own inner scope.\n * When [milo.binder](../../binder.js.html) binds DOM tree and creates components, if components are inside component WITH Container facet, they are put on the `scope` of it (component.container.scope - see [Scope](../scope.js.html)), otherwise they are put on the same scope even though they may be deeper in DOM tree.\n * It allows creating namespaces avoiding components names conflicts, at the same time creating more shallow components tree than the DOM tree.\n * To create components for elements inside the current component use:\n * ```\n * component.container.binder();\n * ```\n * See [milo.binder](../../binder.js.html)\n */\nvar Container = _.createSubclass(ComponentFacet, 'Container');\n\n\n/**\n * ####Container facet instance methods####\n *\n * - [binder](#Container$binder) - create components from DOM inside the current one\n */\n_.extendProto(Container, {\n start: Container$start,\n path: Container$path,\n getState: Container$getState,\n setState: Container$setState,\n binder: Container$binder,\n destroy: Container$destroy,\n unwrap: Container$unwrap,\n\n append: Container$append,\n insertBefore: Container$insertBefore,\n remove: Container$remove\n});\n\nfacetsRegistry.add(Container);\n\nmodule.exports = Container;\n\n\n/**\n * Container instance method.\n * Scans DOM, creates components and adds to scope children of component element.\n */\nfunction Container$binder() {\n return miloBinder(this.owner.el, this.scope, false);\n}\n\n\n/**\n * Container instance method.\n * Setup empty scope object on start\n */\nfunction Container$start() {\n ComponentFacet.prototype.start.apply(this, arguments);\n this.scope = new Scope(this.owner.el, this);\n}\n\n\nvar allowedNamePattern = /^[A-Za-z][A-Za-z0-9\\_\\$]*$/;\n/**\n * Container instance method.\n * Safely traverses component scope\n * Returns component in scope for a given path\n * If path is invalid the method will throw, if there is no component at a given path or some of the components along the path does not have Container facet the method will return undefined, \n * \n * @param {String} path path of child component in scope, each name should be prefixed with '.', e.g.: '.child.subchild'\n * @return {Component}\n */\nfunction Container$path(path) {\n path = path.split('.');\n var len = path.length;\n if (path[0] || len < 2) throwInvalidPath();\n var comp = this.owner;\n for (var i = 1; i < len; i++) {\n var name = path[i];\n if (!allowedNamePattern.test(name)) throwInvalidPath();\n if (!comp.container) return;\n comp = comp.container.scope[name];\n if (!comp) return;\n }\n return comp;\n\n function throwInvalidPath() {\n throw new Error('path ' + path + ' is invalid');\n }\n}\n\n\n/**\n * Container instance method\n * Called by `Component.prototype.getState` to get facet's state\n * Returns the state of components in the scope\n *\n * @param {Boolean} deepCopy true by default\n * @return {Object}\n */\nfunction Container$getState(deepCopy) {\n var state = { scope: {} };\n if (deepCopy !== false)\n this.scope._each(function(component, compName) {\n state.scope[compName] = component._getState();\n });\n return state;\n}\n\n\n/**\n * Container instance method\n * Called by `Component.prototype.setState` to set facet's state\n * Sets the state of components in the scope\n *\n * @param {Object} data data to set on facet's model\n */\nfunction Container$setState(state) {\n _.eachKey(state.scope, function(compData, compName) {\n var component = this.scope[compName];\n if (component)\n component.setState(compData);\n else\n logger.warn('component \"' + compName + '\" does not exist on scope');\n }, this);\n}\n\nfunction Container$destroy() {\n this.scope._each(function(component) {\n component.destroy();\n });\n this.scope._detachElement();\n ComponentFacet.prototype.destroy.apply(this, arguments);\n}\n\n\n/**\n * Container instance method\n * Moves all of the contents of the owner into the parent scope\n * \n * @param {Boolean} renameChildren pass false to not rename scope children (default is true)\n * @param {Boolean} destroy If not false, the component will be destroyed at the end (default is true).\n */\nfunction Container$unwrap(renameChildren, destroy) {\n domUtils.unwrapElement(this.owner.el);\n this.scope && this.scope._each(function (child) {\n child.remove();\n if (renameChildren !== false) child.rename(undefined, false);\n this.owner.scope && this.owner.scope._add(child);\n }, this);\n if (destroy !== false) this.owner.destroy();\n}\n\n\n/**\n * Container instance method\n * Append component to DOM and to scope\n * @param {Component} comp component that will be appended\n */\nfunction Container$append(comp) {\n this.scope._add(comp);\n this.owner.el.appendChild(comp.el);\n}\n\n\n/**\n * Container instance method\n * Insert component to DOM and to scope before another component\n * @param {Component} comp component that will be inserted\n * @param {Component} sibling component before which component will be appended\n */\nfunction Container$insertBefore(comp, sibling) {\n this.scope._add(comp);\n this.el.insertBefore(comp.el, sibling && sibling.el);\n}\n\nfunction Container$remove(comp) {\n this.scope._remove(comp);\n this.owner.el.removeChild(comp.el);\n}\n",
- "'use strict';\n\nvar Mixin = require('../../abstract/mixin')\n , ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n\n , Messenger = require('../../messenger')\n , DOMEventsSource = require('../msg_src/dom_events')\n , DataMsgAPI = require('../msg_api/data')\n , getElementDataAccess = require('../msg_api/de_data')\n , pathUtils = require('../../model/path_utils')\n , ModelPath = require('../../model/m_path')\n , modelUtils = require('../../model/model_utils')\n , changeDataHandler = require('../../model/change_data')\n , getTransactionFlag = changeDataHandler.getTransactionFlag\n , setTransactionFlag = changeDataHandler.setTransactionFlag\n , postTransactionFinished = changeDataHandler.postTransactionFinished\n\n , _ = require('mol-proto')\n , logger = require('../../util/logger');\n\n\n/**\n * `milo.registry.facets.get('Data')`\n * Facet to give access to DOM data\n */\nvar Data = _.createSubclass(ComponentFacet, 'Data');\n\n\n/**\n * Data facet instance methods\n *\n * - [start](#Data$start) - start Data facet\n * - [get](#Data$get) - get DOM data from DOM tree\n * - [set](#Data$set) - set DOM data to DOM tree\n * - [path](#Data$path) - get reference to Data facet by path\n */\n_.extendProto(Data, {\n start: Data$start,\n getState: Data$getState,\n setState: Data$setState,\n\n get: Data$get,\n set: Data$set,\n del: Data$del,\n splice: Data$splice,\n len: Data$len,\n path: Data$path,\n getPath: Data$getPath,\n getKey: Data$getKey,\n\n _get: Data$_get,\n _set: Data$_set,\n _del: Data$_del,\n _splice: Data$_splice,\n _len: Data$_len,\n\n _setScalarValue: Data$_setScalarValue,\n _getScalarValue: Data$_getScalarValue,\n _bubbleUpDataChange: Data$_bubbleUpDataChange,\n _queueDataChange: Data$_queueDataChange,\n _postDataChanges: Data$_postDataChanges,\n _prepareMessageSource: _prepareMessageSource\n});\n\nfacetsRegistry.add(Data);\n\nmodule.exports = Data;\n\n\n/**\n * ModelPath methods added to Data prototype\n */\n['push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {\n var method = ModelPath.prototype[methodName];\n _.defineProperty(Data.prototype, methodName, method);\n});\n\n\n\n// these methods will be wrapped to support \"*\" pattern subscriptions\nvar proxyDataSourceMethods = {\n // value: 'value',\n trigger: 'trigger'\n };\n\n\n/**\n * Data facet instance method\n * Starts Data facet\n * Called by component after component is initialized.\n */\nfunction Data$start() {\n // change messenger methods to work with \"*\" subscriptions (like Model class)\n pathUtils.wrapMessengerMethods.call(this);\n\n ComponentFacet.prototype.start.apply(this, arguments);\n\n // get/set methods to set data of element\n this.elData = getElementDataAccess(this.owner.el);\n\n this._dataChangesQueue = [];\n\n this._prepareMessageSource();\n\n // store facet data path\n this._path = '.' + this.owner.name;\n\n // current value\n this._value = this.get();\n\n // prepare internal and external messengers\n // this._prepareMessengers();\n\n // subscribe to DOM event and accessors' messages\n this.onSync('', onOwnDataChange);\n\n // message to mark the end of batch on the current level\n this.onSync('datachangesfinished', onDataChangesFinished);\n\n // changes in scope children with Data facet\n this.onSync('childdata', onChildData);\n\n // to enable reactive connections\n this.onSync('changedata', changeDataHandler);\n}\n\n\n/**\n * Data facet instance method\n * Create and connect internal and external messengers of Data facet.\n * External messenger's methods are proxied on the Data facet and they allows \"*\" subscriptions.\n */\n// function _prepareMessengers() {\n // Data facet will post all its changes on internal messenger\n // var internalMessenger = new Messenger(this);\n\n // message source to connect internal messenger to external\n // var internalMessengerSource = new MessengerMessageSource(this, undefined, new ModelMsgAPI, internalMessenger);\n\n // external messenger to which all model users will subscribe,\n // that will allow \"*\" subscriptions and support \"changedata\" message api.\n // var externalMessenger = new Messenger(this, Messenger.defaultMethods, internalMessengerSource);\n\n// _.defineProperties(this, {\n// _messenger: externalMessenger,\n// _internalMessenger: internalMessenger\n// });\n// }\n\n\n/**\n * Data facet instance method\n * Initializes DOMEventsSource and connects it to Data facet messenger\n *\n * @private\n */\nfunction _prepareMessageSource() {\n var dataAPI = new DataMsgAPI(this.owner)\n , dataEventsSource = new DOMEventsSource(this, proxyDataSourceMethods, dataAPI, this.owner);\n this._setMessageSource(dataEventsSource);\n\n _.defineProperty(this, '_dataEventsSource', dataEventsSource);\n\n // make value method of DataMsgAPI available on Data facet\n // this is a private method, get() should be used to get data.\n Mixin.prototype._createProxyMethod.call(dataAPI, 'value', 'value', this);\n}\n\n\n/**\n * Subscriber to data change event\n *\n * @private\n * @param {String} msgType in this instance will be ''\n * @param {Object} data data change information\n */\nfunction onOwnDataChange(msgType, data) {\n this._bubbleUpDataChange(data);\n this._queueDataChange(data);\n if (data.path === '') {\n var inTransaction = getTransactionFlag(data);\n this.postMessage('datachangesfinished', { transaction: inTransaction });\n }\n}\n\n\n/**\n * Data facet instance method\n * Sends data `message` to DOM parent\n *\n * @private\n * @param {Object} msgData data change message\n */\nfunction Data$_bubbleUpDataChange(msgData) {\n var parentData = this.scopeParent();\n\n if (parentData) {\n var parentMsg = _.clone(msgData);\n parentMsg.path = (this._path || ('.' + this.owner.name)) + parentMsg.path;\n parentData.postMessage('childdata', parentMsg || msgData);\n }\n}\n\n\n/**\n * Data facet instance method\n * Queues data messages to be dispatched to connector\n *\n * @private\n * @param {Object} change data change description\n */\nfunction Data$_queueDataChange(change) {\n this._dataChangesQueue.push(change);\n}\n\n\n/**\n * Subscriber to datachangesfinished event.\n * Calls the method to post changes batch and bubbles up the message\n *\n * @param {[type]} msg [description]\n * @param {[type]} data [description]\n */\nfunction onDataChangesFinished(msg, data) {\n this._postDataChanges(data.inTransaction);\n var parentData = this.scopeParent();\n if (parentData) parentData.postMessage('datachangesfinished', data);\n}\n\n\n/**\n * Dispatches all changes collected in the batch\n * Used for data propagation - connector subscribes to this message\n *\n * @private\n */\nfunction Data$_postDataChanges(inTransaction) {\n var queue = this._dataChangesQueue.reverse();\n this.postMessageSync('datachanges', {\n changes: queue,\n transaction: inTransaction\n });\n this._dataChangesQueue = []; // it can't be .length = 0, as the actual array may still be used\n}\n\n\n/**\n * Subscriber to data change event in child Data facet\n *\n * @private\n * @param {String} msgType\n * @param {Obejct} data data change information\n */\nfunction onChildData(msgType, data) {\n this.postMessage(data.path, data);\n this._bubbleUpDataChange(data);\n this._queueDataChange(data);\n}\n\n\n/**\n * Data facet instance method\n * Sets data in DOM hierarchy recursively.\n * Returns the object with the data actually set (can be different, if components matching some properties are missing).\n *\n * @param {Object|String|Number} value value to be set. If the value if scalar, it will be set on component's element, if the value is object - on DOM tree inside component\n * @return {Object|String|Number}\n */\nfunction Data$set(value) {\n var inTransaction = getTransactionFlag(Data$set);\n\n var componentSetter = this.config.set;\n if (typeof componentSetter == 'function') {\n var result = componentSetter.call(this.owner, value);\n return result;\n }\n\n setTransactionFlag(this._set, inTransaction);\n\n var oldValue = this._value\n , newValue = this._set(value);\n\n // this message triggers onOwnDataChange, as well as actuall DOM change\n // so the parent gets notified\n var msg = { path: '', type: 'changed',\n newValue: newValue, oldValue: oldValue };\n setTransactionFlag(msg, inTransaction);\n this.postMessage('', msg);\n\n return newValue;\n}\n\n\nfunction Data$_set(value) {\n var inTransaction = getTransactionFlag(Data$_set);\n\n var valueSet;\n if (value != null && typeof value == 'object') {\n if (Array.isArray(value)) {\n valueSet = [];\n\n var listFacet = this.owner.list;\n if (listFacet){\n var listLength = listFacet.count()\n , newItemsCount = value.length - listLength;\n if (newItemsCount >= 3) {\n listFacet._addItems(newItemsCount);\n listFacet._updateDataPaths(listLength, listFacet.count());\n }\n\n value.forEach(function(childValue, index) {\n setChildData.call(this, valueSet, childValue, index, '[$$]');\n }, this);\n\n var listCount = listFacet.count()\n , removeCount = listCount - value.length;\n\n while (removeCount-- > 0)\n listFacet._removeItem(value.length);\n } else\n logger.warn('Data: setting array data without List facet');\n } else {\n valueSet = {};\n _.eachKey(value, function(childValue, key) {\n setChildData.call(this, valueSet, childValue, key, '.$$');\n }, this);\n }\n } else\n valueSet = this._setScalarValue(value);\n\n this._value = valueSet;\n\n return valueSet;\n\n\n function setChildData(valueSet, childValue, key, pathSyntax) {\n var childPath = pathSyntax.replace('$$', key);\n var childDataFacet = this.path(childPath, typeof childValue != 'undefined');\n if (childDataFacet) {\n setTransactionFlag(childDataFacet.set, inTransaction);\n valueSet[key] = childDataFacet.set(childValue);\n }\n }\n}\n\n\n/**\n * Data facet instance method\n * Deletes component from view and scope, only in case it has Item facet on it\n *\n * @param {String|Number} value value to set to DOM element\n */\nfunction Data$del() {\n var inTransaction = getTransactionFlag(Data$del);\n\n var componentDelete = this.config.del;\n if (typeof componentDelete == 'function') {\n var result = componentDelete.call(this.owner);\n postTransactionFinished.call(this, inTransaction);\n return result;\n }\n\n var oldValue = this._value;\n\n setTransactionFlag(this._del, inTransaction);\n this._del();\n\n // this message triggers onOwnDataChange, as well as actuall DOM change\n // so the parent gets notified\n var msg = { path: '', type: 'deleted', oldValue: oldValue };\n setTransactionFlag(msg, inTransaction);\n this.postMessage('', msg);\n}\n\n\nfunction Data$_del() {\n var inTransaction = getTransactionFlag(Data$_del);\n setTransactionFlag(this._set, inTransaction);\n this._set();\n}\n\n\n/**\n * Data facet instance method\n * Sets scalar value to DOM element\n *\n * @private\n * @param {String|Number} value value to set to DOM element\n */\nfunction Data$_setScalarValue(value) {\n return this.elData.set(this.owner.el, value);\n}\n\n\n/**\n * Data facet instance method\n * Get structured data from DOM hierarchy recursively\n * Returns DOM data\n *\n * @param {Boolean} deepGet true by default\n * @return {Object}\n */\nfunction Data$get(deepGet) {\n var componentGetter = this.config.get;\n if (typeof componentGetter == 'function')\n return componentGetter.call(this.owner, deepGet);\n\n return this._get(deepGet);\n}\n\nfunction Data$_get(deepGet) {\n if (deepGet === false) // a hack to enable getting shallow state\n return;\n\n var comp = this.owner\n , scopeData;\n\n if (comp.list) {\n scopeData = [];\n comp.list.each(function(listItem, index) {\n scopeData[index] = listItem.data.get();\n });\n\n if (comp.container)\n comp.container.scope._each(function(scopeItem, name) {\n if (! comp.list.contains(scopeItem) && scopeItem.data)\n scopeData[name] = scopeItem.data.get();\n });\n } else if (comp.container) {\n scopeData = {};\n comp.container.scope._each(function(scopeItem, name) {\n if (scopeItem.data)\n scopeData[name] = scopeItem.data.get();\n });\n } else\n scopeData = this._getScalarValue();\n\n this._value = scopeData;\n\n return scopeData;\n}\n\n\n/**\n * Data facet instance method\n * Gets scalar data from DOM element\n *\n * @private\n */\nfunction Data$_getScalarValue() {\n return this.elData.get(this.owner.el);\n}\n\n\n/**\n * Data facet instance method\n * Splices List items. Requires List facet to be present on component. Works in the same way as array splice.\n * Returns data retrieved from removed items\n *\n * @param {Integer} spliceIndex index to delete/insert at\n * @param {Integer} spliceHowMany number of items to delete\n * @param {List} arguments optional items to insert\n * @return {Array}\n */\nfunction Data$splice(spliceIndex, spliceHowMany) { //, ... arguments\n var inTransaction = getTransactionFlag(Data$splice);\n var result;\n\n var componentSplice = this.config.splice;\n if (typeof componentSplice == 'function') {\n result = componentSplice.apply(this.owner, arguments);\n postTransactionFinished.call(this, inTransaction);\n return result;\n }\n\n setTransactionFlag(this._splice, inTransaction);\n result = this._splice.apply(this, arguments);\n\n if (!result) return;\n\n var msg = { path: '', type: 'splice',\n index: result.spliceIndex,\n removed: result.removed,\n addedCount: result.addedCount,\n newValue: this._value };\n setTransactionFlag(msg, inTransaction);\n this.postMessage('', msg);\n\n return result.removed;\n}\n\n\nfunction Data$_splice(spliceIndex, spliceHowMany) { //, ... arguments\n var inTransaction = getTransactionFlag(Data$_splice);\n\n var listFacet = this.owner.list;\n if (! listFacet)\n return logger.warn('Data: cannot use splice method without List facet');\n\n var removed = [];\n\n var listLength = listFacet.count();\n arguments[0] = spliceIndex =\n modelUtils.normalizeSpliceIndex(spliceIndex, listLength);\n\n if (spliceHowMany > 0 && listLength > 0) {\n for (var i = spliceIndex; i < spliceIndex + spliceHowMany; i++) {\n var item = listFacet.item(spliceIndex);\n if (item) {\n var itemData = item.data.get();\n listFacet._removeItem(spliceIndex);\n } else\n logger.warn('Data: no item for index', i);\n\n removed.push(itemData);\n }\n\n listFacet._updateDataPaths(spliceIndex, listFacet.count());\n }\n\n var added = [];\n\n var argsLen = arguments.length\n , addItems = argsLen > 2\n , addedCount = argsLen - 2;\n if (addItems) {\n listFacet._addItems(addedCount, spliceIndex);\n for (var i = 2, j = spliceIndex; i < argsLen; i++, j++) {\n var item = listFacet.item(j);\n if (item) {\n setTransactionFlag(item.data.set, inTransaction);\n var itemData = item.data.set(arguments[i]);\n } else\n logger.warn('Data: no item for index', j);\n\n added.push(itemData);\n }\n\n // change paths of items that were added and items after them\n listFacet._updateDataPaths(spliceIndex, listFacet.count());\n }\n\n // if (Array.isArray(this._value)) {\n // _.prependArray(added, [spliceIndex, spliceHowMany]);\n // Array.prototype.splice.apply(this._value, added);\n // } else\n this._value = this.get();\n\n return {\n spliceIndex: spliceIndex,\n removed: removed,\n addedCount: addItems ? addedCount : 0\n };\n}\n\n\nfunction Data$len() {\n var componentLen = this.config.len;\n if (typeof componentLen == 'function')\n return componentLen.call(this.owner);\n else\n return this._len();\n}\n\n\nfunction Data$_len() {\n if (this.owner.list) return this.owner.list.count();\n else logger.error('Data: len called without list facet');\n}\n\n\n/**\n * Data facet instance method\n * Returns data facet of a child component (by scopes) corresponding to the path\n * @param {String} accessPath data access path\n */\nfunction Data$path(accessPath, createItem) {\n // createItem = true; // this hack seems to be no longer needed...\n\n if (! accessPath)\n return this;\n\n var parsedPath = pathUtils.parseAccessPath(accessPath);\n var currentComponent = this.owner;\n\n for (var i = 0, len = parsedPath.length; i < len; i++) {\n var pathNode = parsedPath[i]\n , nodeKey = pathUtils.getPathNodeKey(pathNode);\n if (pathNode.syntax == 'array' && currentComponent.list) {\n var itemComponent = currentComponent.list.item(nodeKey);\n if (! itemComponent && createItem !== false) {\n itemComponent = currentComponent.list._addItem(nodeKey);\n itemComponent.data._path = pathNode.property;\n }\n currentComponent = itemComponent;\n } else if (currentComponent.container)\n currentComponent = currentComponent.container.scope[nodeKey];\n\n var currentDataFacet = currentComponent && currentComponent.data;\n if (! currentDataFacet)\n break;\n }\n\n return currentDataFacet;\n}\n\n\n/**\n * Data facet instance method\n * Returns path to access this data facet from parent (using path method)\n *\n * @return {String}\n */\nfunction Data$getPath() {\n return this._path;\n}\n\n\n/**\n * Data facet instance method\n * Returns key to access the value related to this data facet on the value related to parent data facet.\n * If component has List facet, returns index\n *\n * @return {String|Integer}\n */\nfunction Data$getKey() {\n var path = this._path;\n return path[0] == '['\n ? +path.slice(1, -1) // remove \"[\" and \"]\"\n : path.slice(1) // remove leading \".\"\n}\n\n\n/**\n * Data facet instance method\n * Called by `Component.prototype.getState` to get facet's state\n * Returns DOM data\n *\n * @param {Boolean} deepState, true by default\n * @return {Object}\n */\nfunction Data$getState(deepState) {\n return { state: this.get(deepState) };\n}\n\n\n/**\n * Data facet instance method\n * Called by `Component.prototype.setState` to set facet's state\n * Simply sets model data\n *\n * @param {Object} state data to set on facet's model\n */\nfunction Data$setState(state) {\n return this.set(state.state);\n}\n",
- "'use strict';\n\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry') \n , _ = require('mol-proto')\n , check = require('../../util/check')\n , Match = check.Match\n , binder = require('../../binder')\n , BindAttribute = require('../../attributes/a_bind')\n , DomFacetError = require('../../util/error').DomFacet\n , domUtils = require('../../util/dom')\n , config = require('../../config')\n , doT = require('dot');\n\n\n/**\n * `milo.registry.facets.get('Dom')`\n * Facet with component related dom utils\n */\nvar Dom = _.createSubclass(ComponentFacet, 'Dom');\n\n_.extend(Dom, {\n createElement: Dom$$createElement\n});\n\n\n/**\n * Facet class method\n * Creates an element from a passed configuation object\n * \n * @param {Object} config with the properties `domConfig`, `content`, `template`\n * @return {Element} an html element \n */\nfunction Dom$$createElement(config) {\n var domConfig = config.domConfig || {}\n , tagName = domConfig.tagName || 'div'\n , newEl = document.createElement(tagName)\n , content = config.content\n , template = config.template;\n\n // TODO it will be called again when/if component is instantiated\n // Should be someproperty on element to indicate it's been called?\n _applyConfigToElement(newEl, domConfig);\n\n if (typeof content == 'string') {\n if (template)\n newEl.innerHTML = doT.template(template)({content: content});\n else\n newEl.innerHTML = content;\n }\n return newEl;\n}\n\n\nfunction _applyConfigToElement(el, config) {\n var cssClasses = config && config.cls\n , configAttributes = config && config.attributes;\n\n if (configAttributes)\n _.eachKey(configAttributes, function(attrValue, attrName) {\n el.setAttribute(attrName, attrValue);\n });\n\n if (cssClasses)\n _attachCssClasses(el, 'add', cssClasses);\n}\n\n\n_.extendProto(Dom, {\n start: start,\n\n show: show,\n hide: hide,\n toggle: toggle,\n detach: detach,\n remove: remove,\n append: append,\n prepend: prepend,\n appendChildren: appendChildren,\n prependChildren: prependChildren,\n insertAfter: insertAfter,\n insertBefore: insertBefore,\n appendToScopeParent: appendToScopeParent,\n children: Dom$children,\n setStyle: setStyle,\n setStyles: setStyles,\n copy: copy,\n createElement: createElement,\n\n addCssClasses: _.partial(_manageCssClasses, 'add'),\n removeCssClasses: _.partial(_manageCssClasses, 'remove'),\n toggleCssClasses: _.partial(_manageCssClasses, 'toggle'),\n\n find: find,\n hasTextBeforeSelection: hasTextBeforeSelection,\n hasTextAfterSelection: hasTextAfterSelection,\n});\n\nfacetsRegistry.add(Dom);\n\nmodule.exports = Dom;\n\n\n// start Dom facet\nfunction start() {\n var el = this.owner.el;\n _applyConfigToElement(el, this.config);\n var currentStyle = window.getComputedStyle(el)\n this._visible = currentStyle && currentStyle.display != 'none';\n}\n\n// show HTML element of component\nfunction show() {\n this.toggle(true);\n}\n\n// hide HTML element of component\nfunction hide() {\n this.toggle(false);\n}\n\n// show/hide\nfunction toggle(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._visible\n : !! doShow;\n\n this._visible = doShow;\n var el = this.owner.el;\n\n el.style.display = doShow ? 'block' : 'none';\n\n return doShow;\n}\n\n\nfunction _manageCssClasses(methodName, cssClasses, enforce) {\n _attachCssClasses(this.owner.el, methodName, cssClasses, enforce);\n}\n\n\nfunction _attachCssClasses(el, methodName, cssClasses, enforce) {\n var classList = el.classList\n , doToggle = methodName == 'toggle';\n\n if (Array.isArray(cssClasses))\n cssClasses.forEach(callMethod);\n else if (typeof cssClasses == 'string')\n callMethod(cssClasses);\n else\n throw new DomFacetError('unknown type of CSS classes parameter');\n\n function callMethod(cssCls) {\n doToggle\n // Only pass 'enforce' if a value has been provided (The 'toggle' function of the classList will treat undefined === false resulting in only allowing classes to be removed)\n ? enforce === undefined ? classList[methodName](cssCls) : classList[methodName](cssCls, enforce)\n : classList[methodName](cssCls);\n }\n}\n\n\nfunction detach() {\n if (this.owner.el) \n domUtils.detachComponent(this.owner.el);\n}\n\n\nfunction setStyle(property, value) {\n if (!this.owner.el) {\n throw new Error(\"Cannot call setStyle on owner with no element: \" + this.owner.constructor.name);\n }\n this.owner.el.style[property] = value;\n}\n\nfunction setStyles(properties) {\n for (var property in properties)\n this.owner.el.style[property] = properties[property];\n}\n\n\n// create a copy of DOM element using facet config if set\nfunction copy(isDeep) {\n return this.owner.el && this.owner.el.cloneNode(isDeep);\n}\n\n\nfunction createElement() {\n var newEl = Dom.createElement(this.config);\n return newEl;\n}\n\n\n// remove HTML element of component\nfunction remove() {\n domUtils.removeElement(this.owner.el);\n}\n\n// append inside HTML element of component\nfunction append(el) {\n this.owner.el.appendChild(el);\n}\n\n// prepend inside HTML element of component\nfunction prepend(el) {\n var thisEl = this.owner.el\n , firstChild = thisEl.firstChild;\n if (firstChild)\n thisEl.insertBefore(el, firstChild);\n else\n thisEl.appendChild(el);\n}\n\n// appends children of element inside this component's element\nfunction appendChildren(el) {\n while(el.childNodes.length)\n this.append(el.childNodes[0]);\n}\n\n// prepends children of element inside this component's element\nfunction prependChildren(el) {\n while(el.childNodes.length)\n this.prepend(el.childNodes[el.childNodes.length - 1]);\n}\n\nfunction insertAfter(el) {\n var thisEl = this.owner.el\n , parent = thisEl.parentNode; \n parent.insertBefore(el, thisEl.nextSibling);\n}\n\nfunction insertBefore(el) {\n var thisEl = this.owner.el\n , parent = thisEl.parentNode;\n parent.insertBefore(el, thisEl);\n}\n\n\n// appends component's element to scope parent. If it was alredy in DOM it will be moved\nfunction appendToScopeParent() {\n var parent = this.owner.getScopeParent();\n if (parent) parent.el.appendChild(this.owner.el);\n}\n\n\n/**\n * Dom facet instance method\n * Returns the list of child elements of the component element\n *\n * @return {Array[Element]}\n */\nfunction Dom$children() {\n return domUtils.children(this.owner.el);\n}\n\n\nvar findDirections = {\n 'up': 'previousNode',\n 'down': 'nextNode'\n};\n\n// Finds component passing optional iterator's test\n// in the same scope as the current component (this)\n// by traversing DOM tree upwards (direction = \"up\")\n// or downwards (direction = \"down\")\nfunction find(direction, iterator) {\n if (! findDirections.hasOwnProperty(direction))\n throw new DomFacetError('incorrect find direction: ' + direction);\n\n var el = this.owner.el\n , scope = this.owner.scope\n , treeWalker = document.createTreeWalker(scope._rootEl, NodeFilter.SHOW_ELEMENT);\n\n treeWalker.currentNode = el;\n var nextNode = treeWalker[findDirections[direction]]()\n , componentsNames = Object.keys(scope)\n , found = false;\n\n while (nextNode) {\n var attr = new BindAttribute(nextNode);\n if (attr.node) {\n attr.parse().validate();\n if (scope.hasOwnProperty(attr.compName)) {\n var component = scope[attr.compName];\n if (! iterator || iterator(component)) {\n found = true;\n break;\n }\n }\n }\n treeWalker.currentNode = nextNode;\n nextNode = treeWalker[findDirections[direction]]();\n }\n\n if (found) return component;\n}\n\n\n// returns true if the element has text before selection\nfunction hasTextBeforeSelection() {\n var selection = window.getSelection();\n if (! selection.isCollapsed) return true;\n \n var text = selection.focusNode && selection.focusNode.textContent;\n var startPos = text && text.charAt(0) == ' ' ? 1 : 0;\n if (selection.anchorOffset != startPos) return true;\n\n // walk up the DOM tree to check if there are text nodes before cursor\n var treeWalker = document.createTreeWalker(this.owner.el, NodeFilter.SHOW_TEXT);\n treeWalker.currentNode = selection.anchorNode;\n var prevNode = treeWalker.previousNode();\n\n var isText = prevNode ? !prevNode.nodeValue.trim() == '' : false;\n\n return isText;\n}\n\n\nfunction hasTextAfterSelection() {\n var selection = window.getSelection();\n if (! selection.isCollapsed) return true;\n\n var text = selection.focusNode && selection.focusNode.textContent;\n var startPos = text && text.charAt(text.length-1) == ' ' ? selection.anchorNode.length-1 : selection.anchorNode.length;\n if (selection.anchorOffset < startPos) return true;\n\n // walk up the DOM tree to check if there are text nodes after cursor\n var treeWalker = document.createTreeWalker(this.owner.el, NodeFilter.SHOW_TEXT);\n treeWalker.currentNode = selection.anchorNode;\n var nextNode = treeWalker.nextNode();\n \n //To capture when treewalker gives us an empty text node (unknown reason)\n var isText = nextNode ? !nextNode.nodeValue.trim() == '' : false;\n\n return isText;\n}\n",
- "'use strict';\n\n// \n// ###drag facet\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , DOMEventsSource = require('../msg_src/dom_events')\n , Component = require('../c_class')\n , DragDrop = require('../../util/dragdrop')\n , _ = require('mol-proto')\n , logger = require('../../util/logger');\n\n\n/**\n * `milo.registry.facets.get('Drag')`\n * Facet for components that can be dragged\n * Drag facet supports the following configuration parameters:\n *\n * - meta: object with properties\n * - params: object of key-value pairs that will be converted in url-like query string in the end of data type for metadata data type (or function that returns this object). See config.dragDrop.dataTypes.componentMetaTemplate\n * all values will converted to lowercase as datatype cannot store uppercase letters.\n * - data: data that will be stored in the above meta data type (or function)\n * - allowedEffects: string (or function) as specified here: https://developer.mozilla.org/en-US/docs/DragDrop/Drag_Operations#dragstart\n * - dataTypes: map of additional data types the component will supply to data transfer object, key is data type, value is a function that returns it, component will be passed as the context to this function\n *\n * If function is specified in any parameter it will be called with the component as the context\n */\nvar Drag = _.createSubclass(ComponentFacet, 'Drag');\n\n_.extendProto(Drag, {\n init: Drag$init,\n start: Drag$start,\n setHandle: Drag$setHandle\n});\n\nfacetsRegistry.add(Drag);\n\nmodule.exports = Drag;\n\n\nfunction Drag$init() {\n ComponentFacet.prototype.init.apply(this, arguments); \n\n this._createMessageSourceWithAPI(DOMEventsSource);\n this._dragData = {};\n\n var dataTypeInfo = this.config._dataTypeInfo || '';\n this._dataTypeInfo = typeof dataTypeInfo == 'function'\n ? dataTypeInfo\n : function() { return dataTypeInfo; };\n}\n\n\n/**\n * Drag facet instance method\n * Sets the drag handle element of component. This element has to be dragged for the component to be dragged.\n *\n * @param {Element} handleEl\n */\nfunction Drag$setHandle(handleEl) {\n if (! this.owner.el.contains(handleEl))\n return logger.warn('drag handle should be inside element to be dragged')\n this._dragHandle = handleEl;\n}\n\n\nfunction Drag$start() {\n ComponentFacet.prototype.start.apply(this, arguments);\n _addDragAttribute.call(this);\n\n this.onMessages({\n 'mousedown': onMouseDown,\n 'mouseenter mouseleave mousemove': onMouseMovement,\n 'dragstart': onDragStart,\n 'drag': onDragging,\n 'dragend': onDragEnd\n });\n\n this.owner.onMessages({\n 'getstatestarted':\n { subscriber: _removeDragAttribute, context: this },\n 'getstatecompleted':\n { subscriber: _addDragAttribute, context: this }\n });\n}\n\n\n/**\n * Adds draggable attribute to component's element\n *\n * @private\n */\nfunction _addDragAttribute() {\n if (this.owner.el)\n this.owner.el.setAttribute('draggable', true);\n}\n\n\nfunction _removeDragAttribute() {\n if (this.owner.el)\n this.owner.el.removeAttribute('draggable');\n}\n\n\nfunction onMouseDown(eventType, event) {\n this.__mouseDownTarget = event.target;\n if (targetInDragHandle.call(this)) {\n window.getSelection().empty();\n event.stopPropagation();\n }\n}\n\n\nfunction onMouseMovement(eventType, event) {\n var shouldBeDraggable = targetInDragHandle.call(this);\n this.owner.el.setAttribute('draggable', shouldBeDraggable);\n if (document.body.getAttribute('data-dragEnableEvent') != 'false')\n event.stopPropagation();\n}\n\n\nfunction onDragStart(eventType, event) {\n event.stopPropagation();\n if (this.config.off || ! targetInDragHandle.call(this)) {\n event.preventDefault();\n return;\n }\n\n var owner = this.owner;\n var dt = new DragDrop(event);\n\n this._dragData = dt.setComponentState(owner);\n setMeta.call(this);\n setAdditionalDataTypes.call(this);\n _setAllowedEffects.call(this, dt);\n\n DragDrop.service.postMessageSync('dragdropstarted', {\n eventType: 'dragstart',\n dragDrop: dt,\n dragFacet: this\n });\n\n function setMeta() {\n var metaConfig = this.config.meta\n , paramsConfig = metaConfig && metaConfig.params\n , metaDataConfig = metaConfig && metaConfig.data;\n\n var params = _.result(paramsConfig, owner)\n , data = _.result(metaDataConfig, owner);\n\n this._dragMetaDataType = dt.setComponentMeta(owner, params, data);\n this._dragMetaData = data;\n }\n\n function setAdditionalDataTypes() {\n if (this.config.dataTypes) {\n this._dataTypesData = _.mapKeys(this.config.dataTypes, function (getDataFunc, dataType) {\n var data = getDataFunc.call(this.owner, dataType);\n if (typeof data == 'object') data = JSON.stringify(data);\n if (data) dt.setData(dataType, data);\n return data;\n }, this);\n }\n }\n}\n\n\nfunction onDragging(eventType, event) {\n if (_dragIsDisabled.call(this, event)) return;\n\n var dt = new DragDrop(event);\n dt.setComponentState(this.owner, this._dragData);\n dt.setData(this._dragMetaDataType, this._dragMetaData);\n if (this._dataTypesData) {\n _.eachKey(this._dataTypesData, function(data, dataType) {\n if (data) dt.setData(dataType, data);\n });\n }\n\n _setAllowedEffects.call(this, dt);\n}\n\n\nfunction onDragEnd(eventType, event) {\n if (_dragIsDisabled.call(this, event)) return;\n\n event.stopPropagation();\n var dt = new DragDrop(event);\n DragDrop.service.postMessageSync('completedragdrop', {\n eventType: 'dragend',\n dragDrop: dt,\n dragFacet: this\n });\n}\n\n\nfunction _setAllowedEffects(DragDrop) {\n var effects = _.result(this.config.allowedEffects, this.owner);\n DragDrop.setAllowedEffects(effects);\n}\n\n\nfunction targetInDragHandle() {\n return ! this._dragHandle || this._dragHandle.contains(this.__mouseDownTarget);\n}\n\n\nfunction _dragIsDisabled(event) {\n if (this.config.off) {\n event.preventDefault();\n return true;\n }\n return false;\n}\n",
- "'use strict';\n\n// \n// ###drop facet\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , DOMEventsSource = require('../msg_src/dom_events')\n , DropMsgAPI = require('../msg_api/drop')\n , DragDrop = require('../../util/dragdrop')\n , DropError = require('../../util/error').Drop\n , _ = require('mol-proto')\n , _handleDropDependency;\n\n/**\n * `milo.registry.facets.get('Drop')`\n * Facet for components that can accept drops\n * Drop facet supports the following configuration parameters:\n *\n * - allow - an object that will define allowed data types during drag (`dragenter` and `dragover` events) with these properties:\n * - components: `true` by default (all components will be accepted)\n * OR string with allowed component class\n * OR list of allowed components classes (strings)\n * OR map with allowed classes in keys and `true`/test functions in values\n * OR test function that will be passed object defined below\n * OR `false` to NOT accept components\n * - dataTypes: `false` by default (no other data types will be accepted)\n * OR string with allowed data type\n * OR list of additional data types that a drop target would accept\n * OR test function that will be passed DragDrop object\n * OR `true` to accept all data types\n * - checkParent: `false` by default\n * OR `true` will call parent component drop allow to check if parent component will accept the component\n * If test functions are used, they should return boolean. Each test function can also set drop effect as defined here:\n * https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer#dropEffect.28.29\n * Setting drop effect that is not allowed by dragged object will prevent drop.\n * Test functions for components will be passed the owner of Drop facet as context, the object with the following possible properties as the first parameter:\n * compClass - name of component class as stored in registry\n * compName - name of component (all lowercase)\n * params - parameters as encoded in dataType, passed to `milo.util.dragDrop.setComponentMeta` by Drag facet\n * metaDataType - data type of the data that has compClass, compName and params encoded\n *\n * ... and DragDrop instance as the second parameter\n *\n * Test function for other data types will be passed the owner of Drop facet as context and DragDrop instance as the first parameter\n *\n * ####Events####\n *\n * In addition to configuring allowed components and data types, components classes should subscribe to events.\n * At the very least, they should subscribe to `drop` event.\n *\n * Drop facet emits dragin/dragout messages that are emitted whenever actual component element is entered or left\n * (which is different from dragenter and dragleave messages that are emitted whenever any child element is entered or left, as long as event bubbles up)\n * If child component has drop facet attached, dragout will be emitted on the current component when the child is entered.\n *\n * You can see the demonstration of when messages are emitted [here](http://jsbin.com/buqov/6)\n * \n */\nvar Drop = _.createSubclass(ComponentFacet, 'Drop');\n\n\n_.extendProto(Drop, {\n init: Drop$init,\n start: Drop$start\n // _reattach: _reattachEventsOnElementChange\n});\n\nfacetsRegistry.add(Drop);\n\nmodule.exports = Drop;\n\n\nfunction Drop$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n this._createMessageSourceWithAPI(DOMEventsSource, new DropMsgAPI);\n}\n\n\nfunction Drop$start() {\n ComponentFacet.prototype.start.apply(this, arguments);\n this.owner.el.classList.add('cc-module-relative');\n this.onMessages({\n 'dragenter dragover': onDragging,\n 'drop': onDrop,\n 'dragenter dragover dragleave drop dragin dragout': postToService\n });\n}\n\n\nfunction onDragging(eventType, event) {\n var dt = new DragDrop(event);\n\n event.stopPropagation();\n event.preventDefault();\n\n if (! _handleDropDependency.call(this, dt))\n dt.setDropEffect('none');\n}\n\n\nfunction onDrop(eventType, event) {\n event.stopPropagation();\n var dt = new DragDrop(event);\n DragDrop.service.postMessageSync('dragdropcompleted', {\n eventType: 'drop',\n dragDrop: dt,\n dropFacet: this,\n component: this.owner\n });\n}\n\n\nfunction postToService(eventType, event) {\n DragDrop.service.postMessageSync(eventType, {\n event: event,\n dropFacet: this,\n component: this.owner\n });\n}\n\n\n_handleDropDependency = _.throttle(_handleDropDependencyNothrottle, 50);\nfunction _handleDropDependencyNothrottle(dt, originalDropComponent) {\n var allow = this.config.allow\n , parentAllowed = true;\n\n originalDropComponent = originalDropComponent || this.owner;\n\n if (allow && allow.checkParent) {\n var parent = this.owner.getScopeParent('Drop');\n if (parent)\n parentAllowed = _handleDropDependencyNothrottle.call(parent.drop, dt, originalDropComponent);\n }\n\n return parentAllowed && _isDropAllowed.call(this, dt, originalDropComponent);\n}\n\n\n/**\n * Checks if drop is allowed based on facet configuration (see above)\n * \n * @param {DragDrop} dt\n * @return {Boolean}\n */\nfunction _isDropAllowed(dt, originalDropComponent) {\n var allow = this.config.allow;\n\n if (dt.isComponent()) {\n var allowComps = allow && allow.components\n , meta = dt.getComponentMeta();\n\n switch (typeof allowComps) {\n case 'undefined':\n return true;\n case 'boolean':\n return allowComps;\n // component class\n case 'string':\n return meta && meta.compClass == allowComps;\n // test function\n case 'function':\n return allowComps.call(this.owner, meta, dt, originalDropComponent);\n case 'object':\n if (Array.isArray(allowComps))\n // list of allowed classes\n return allowComps.indexOf(meta && meta.compClass) >= 0;\n else {\n // map of class: boolean|test function\n var test = allowComps[meta && meta.compClass];\n return !! _.result(test, this.owner, meta, dt);\n }\n default:\n throw new DropError('Incorrect allowed components in config');\n }\n } else {\n var dataTypes = allow && allow.dataTypes\n switch (typeof dataTypes) {\n case 'undefined':\n return false;\n case 'string':\n return dt.types.indexOf(dataTypes) >= 0;\n }\n }\n\n // TODO test for other data types\n}\n",
- "'use strict';\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , Messenger = require('../../messenger')\n , DOMEventsSource = require('../msg_src/dom_events')\n , _ = require('mol-proto');\n\n\n/**\n * `milo.registry.facets.get('Events')`\n * Component facet that manages subscriptions to DOM events using [Messenger](../../messenger/index.js.html) with [DOMEventsSource](../msg_src/dom_events.js.html).\n * All public methods of Messenger and `trigger` method of [DOMEventsSource](../msg_src/dom_events.js.html) are proxied directly to this facet.\n * For example, to subscribe to `click` event use:\n * ```\n * component.frame.on('click', function() {\n * // ...\n * });\n * ```\n * See [Messenger](../../messenger/index.js.html)\n */\nvar Events = _.createSubclass(ComponentFacet, 'Events');\n\n\n/**\n * ####Events facet instance methods####\n *\n * - [init](#Events$init) - called by constructor automatically\n */\n_.extendProto(Events, {\n init: Events$init\n // _reattach: _reattachEventsOnElementChange\n});\n\nfacetsRegistry.add(Events);\n\nmodule.exports = Events;\n\n\n/**\n * Expose DOMEventsSource trigger method on Events prototype\n */\nvar MSG_SOURCE_KEY = '_domEventsSource'\nDOMEventsSource.useWith(Events, MSG_SOURCE_KEY, ['trigger']);\n\n\n/**\n * Events facet instance method\n * Initialzes facet, connects DOMEventsSource to facet's messenger\n */\nfunction Events$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n\n var domEventsSource = new DOMEventsSource(this, undefined, undefined, this.owner);\n this._setMessageSource(domEventsSource);\n _.defineProperty(this, MSG_SOURCE_KEY, domEventsSource);\n}\n",
- "'use strict';\n\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , Messenger = require('../../messenger')\n , FrameMessageSource = require('../msg_src/frame')\n , domEventsConstructors = require('../../services/de_constrs')\n , _ = require('mol-proto');\n\n\n/**\n * `milo.registry.facets.get('Frame')`\n * Component facet that simplifies sending window messages to iframe and subscribing to messages on inner window of iframe.\n * All public methods of Messenger and `trigger` method of [FrameMessageSource](../msg_src/frame.js.html) are proxied directly to this facet.\n * For example, to send custom message to iframe window use:\n * ```\n * iframeComponent.frame.trigger('mymessage', myData);\n * ```\n * To subscribe to this messages inside frame use (with milo - see [milo.mail](../../mail/index.js.html)):\n * ```\n * milo.mail.on('message:mymessage', function(msgType, msgData) {\n * // data is inside of window message data\n * // msgType == 'message:mymessage'\n * var myData = msgData.data;\n * // ... app logic here\n * });\n * ```\n * or without milo:\n * ```\n * window.attachEventListener('message', function(message) {\n * var msgType = message.type; // e.g., 'mymessage'\n * var myData = message.data;\n * // ... message routing and code here\n * });\n * ```\n * Milo does routing based on sent message type automatically.\n * See [Messenger](../../messenger/index.js.html) and [milo.mail](../../mail/index.js.html).\n */\n var Frame = _.createSubclass(ComponentFacet, 'Frame');\n\n\n/**\n * Calls passed function when frame DOM becomes ready. If already ready calls immediately\n */\nvar Frame$whenReady = _makeWhenReadyFunc(Frame$isReady, 'domready');\n\n/**\n * Calls passed function when frame milo becomes ready. If already ready calls immediately\n */\nvar Frame$whenMiloReady = _makeWhenReadyFunc(Frame$isMiloReady, 'message:miloready');\n\n\n/**\n * ####Events facet instance methods####\n *\n * - [init](#Frame$init) - called by constructor automatically\n */\n_.extendProto(Frame, {\n init: Frame$init,\n start: Frame$start,\n destroy: Frame$destroy,\n getWindow: Frame$getWindow,\n isReady: Frame$isReady,\n whenReady: Frame$whenReady,\n isMiloReady: Frame$isMiloReady,\n whenMiloReady: Frame$whenMiloReady,\n milo: Frame$milo\n // _reattach: _reattachEventsOnElementChange\n});\n\n\nfacetsRegistry.add(Frame);\n\nmodule.exports = Frame;\n\n\n/**\n * Expose FrameMessageSource trigger method on Events prototype\n */\nvar MSG_SOURCE_KEY = '_messageSource';\nFrameMessageSource.useWith(Frame, MSG_SOURCE_KEY, ['trigger']);\n\n\n/**\n * Frame facet instance method\n * Initialzes facet, connects FrameMessageSource to facet's messenger\n */\nfunction Frame$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n \n var messageSource = new FrameMessageSource(this, undefined, undefined, this.owner);\n this._setMessageSource(messageSource);\n\n _.defineProperty(this, MSG_SOURCE_KEY, messageSource);\n}\n\n\n/**\n * Frame facet instance method\n * Emits frameloaded event when ready.\n */\nfunction Frame$start() {\n ComponentFacet.prototype.start.apply(this, arguments);\n var self = this;\n milo(postDomReady);\n\n function postDomReady(event) {\n self.postMessage('domready', event);\n }\n}\n\n\nfunction Frame$destroy() {\n ComponentFacet.prototype.destroy.apply(this, arguments);\n}\n\n\n/**\n * Frame facet instance method\n * Retrieves the internal window of the frame \n *\n * @param {Window}\n */\nfunction Frame$getWindow() {\n return this.owner.el.contentWindow;\n}\n\n\n/**\n * Frame facet instance method\n * Returns document.readyState if frame doument state is 'interactive' or 'complete', false otherwise\n *\n * @return {String|Boolean}\n */\nfunction Frame$isReady() {\n var readyState = this.getWindow().document.readyState;\n return readyState != 'loading' ? readyState : false;\n}\n\n\n/**\n * Frame facet instance method\n * Returns true if milo is loaded and has finished initializing inside the frame\n *\n * @return {Boolean}\n */\nfunction Frame$isMiloReady() {\n var frameMilo = this.getWindow().milo;\n return this.isReady() && frameMilo && frameMilo.milo_version;\n}\n\n\n/**\n * Gives access to milo in the frame (assuming it is loaded there)\n * Calls function when both milo and DOM are ready if function is passed.\n * Returns the reference to milo inside the frame if the window is already available.\n * \n * @param {Function} func function to be called when milo and DOM are ready in the frame\n * @return {Function} reference to milo in the frame \n */\nfunction Frame$milo(func) {\n if (typeof func == 'function') {\n var self = this;\n this.whenMiloReady(function() {\n self.getWindow().milo(func)\n });\n }\n var win = this.getWindow();\n return win && win.milo;\n}\n\n\nfunction _makeWhenReadyFunc(isReadyFunc, event) {\n return function Frame_whenReadyFunc(func) { // , arguments\n var self = this\n , args = _.slice(arguments, 1);\n if (isReadyFunc.call(this))\n callFunc();\n else\n this.on(event, callFunc);\n\n function callFunc() {\n func.apply(self, args);\n }\n }\n}\n",
- "'use strict';\n\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , Model = require('../../model')\n , _ = require('mol-proto')\n , miloMail = require('../../services/mail');\n\n\nvar ItemFacet = _.createSubclass(ComponentFacet, 'Item');\n\n_.extendProto(ItemFacet, {\n getState: ItemFacet$getState,\n setState: ItemFacet$setState,\n getIndex: ItemFacet$getIndex,\n setIndex: ItemFacet$setIndex,\n removeItem: ItemFacet$removeItem,\n extractItem: ItemFacet$extractItem,\n require: ['Container', 'Dom', 'Data']\n});\n\nfacetsRegistry.add(ItemFacet);\n\nmodule.exports = ItemFacet;\n\n\nfunction ItemFacet$getState() {\n return { state: {\n index: this.getIndex()\n }};\n}\n\n\nfunction ItemFacet$setState(state) {\n this.setIndex(state.state.index);\n}\n\n\n/**\n * Facet instance method\n * Returns the index of the owner component in it's parent list component\n * @return {Integer} The index\n */\nfunction ItemFacet$getIndex() {\n return this.index;\n}\n\n\n/**\n * Facet instance method\n * Sets the index of this component\n * @param {Integer} index The index to be set\n */\nfunction ItemFacet$setIndex(index) {\n this.index = index;\n}\n\n\n/**\n * ItemFacet instance method\n * Removes component from the list, component gets destroyed\n */\nfunction ItemFacet$removeItem() {\n // this.list and this.index are set by the list when the item is added\n this.list.removeItem(this.index);\n}\n\n\n/**\n * ItemFacet instance method\n * Removes component from the list, component is NOT destroyed\n */\nfunction ItemFacet$extractItem() {\n this.list.extractItem(this.index);\n}\n",
- "'use strict';\n\nvar ComponentFacet = require('../c_facet')\n , Component = require('../c_class')\n , facetsRegistry = require('./cf_registry')\n , _ = require('mol-proto')\n , miloMail = require('../../services/mail')\n , miloBinder = require('../../binder')\n , miloUtil = require('../../util')\n , ListError = miloUtil.error.List\n , logger = miloUtil.logger\n , doT = require('dot')\n , check = miloUtil.check\n , Match = check.Match\n , domUtils = miloUtil.dom\n , miloConfig = require('../../config');\n\n\nvar LIST_SAMPLE_CSS_CLASS = 'ml-list-item-sample';\n\n/**\n * `milo.registry.facets.get('List')`\n * Facet enabling list functionality\n */\nvar List = _.createSubclass(ComponentFacet, 'List');\n\n_.extendProto(List, {\n init: List$init,\n start: List$start,\n destroy: List$destroy,\n\n require: ['Container', 'Dom', 'Data'],\n _itemPreviousComponent: _itemPreviousComponent,\n\n item: List$item,\n count: List$count,\n contains: List$contains,\n addItem: List$addItem,\n addItems: List$addItems,\n replaceItem: List$replaceItem,\n removeItem: List$removeItem,\n extractItem: List$extractItem,\n each: List$each,\n _setItem: List$_setItem,\n _removeItem: List$_removeItem,\n _addItem: List$_addItem,\n _addItems: List$_addItems,\n _createCacheTemplate: List$_createCacheTemplate,\n _updateDataPaths: List$_updateDataPaths\n});\n\nfacetsRegistry.add(List);\n\nmodule.exports = List;\n\n\n/**\n * Facet instance method\n * Initialized List facet instance and sets up item properties.\n */\nfunction List$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n var self = this;\n\n _.defineProperties(this, {\n _listItems: [],\n _listItemsHash: {}\n });\n _.defineProperty(this, 'itemSample', null, _.WRIT);\n}\n\n\n/**\n * Facet instance method\n * Starts the List facet instance, finds child with Item facet.\n */\nfunction List$start() {\n // Fired by __binder__ when all children of component are bound\n this.owner.on('childrenbound', onChildrenBound);\n}\n\n\nfunction onChildrenBound() {\n // get items already in the list\n var children = this.dom.children()\n , items = this.list._listItems\n , itemsHash = this.list._listItemsHash;\n\n children && children.forEach(function(childEl) {\n var comp = Component.getComponent(childEl);\n if (comp && comp.item) {\n items.push(comp);\n itemsHash[comp.name] = comp;\n comp.item.list = this.list;\n }\n }, this);\n\n if (items.length) {\n var foundItem = items[0];\n items.splice(0, 1);\n delete itemsHash[foundItem.name];\n items.forEach(function(item, index) {\n item.item.setIndex(index);\n });\n }\n \n // Component must have one child with an Item facet \n if (! foundItem) throw new ListError('No child component has Item facet');\n\n this.list.itemSample = foundItem;\n\n // After keeping a reference to the item sample, it must be hidden and removed from scope\n foundItem.dom.hide();\n foundItem.remove(true);\n foundItem.dom.removeCssClasses(LIST_SAMPLE_CSS_CLASS);\n\n // remove references to components from sample item\n foundItem.walkScopeTree(function(comp) {\n delete comp.el[miloConfig.componentRef];\n });\n\n this.list._createCacheTemplate();\n}\n\n\nfunction List$_createCacheTemplate() {\n if (!this.itemSample) return false;\n \n var itemSample = this.itemSample;\n\n // create item template to insert many items at once\n var itemElCopy = itemSample.el.cloneNode(true);\n var attr = itemSample.componentInfo.attr;\n var attrCopy = _.clone(attr);\n attr.compName = '{{= it.componentName() }}';\n attr.el = itemElCopy;\n attr.decorate();\n\n var itemsTemplateStr = \n '{{ var i = it.count; while(i--) { }}'\n + itemElCopy.outerHTML\n + '{{ } }}';\n\n this.itemsTemplate = doT.compile(itemsTemplateStr);\n}\n\n\n/**\n * Facet instance method\n * Retrieve a particular child item by index\n * @param {Integer} index The index of the child item to get.\n * @return {Component} The component found\n */\nfunction List$item(index) {\n return this._listItems[index];\n}\n\n\n/**\n * Facet instance method\n * Gets the total number of child items\n * @return {Integer} The total\n */\nfunction List$count() {\n return this._listItems.length;\n}\n\n\nfunction List$_setItem(index, component) {\n this._listItems.splice(index, 0, component);\n this._listItemsHash[component.name] = component;\n component.item.list = this;\n component.item.setIndex(+index);\n}\n\n\n/**\n * Facet instance method\n * Returns true if a particular child item exists in the list\n * @param {Component} component The component to look for.\n * @return {Boolean}\n */\nfunction List$contains(component) {\n return this._listItemsHash[component.name] == component;\n}\n\n\n/**\n * Facet instance method\n * Adds a new child component at a particular index and returns the new component.\n * This method uses data facet, so notification will be emitted on data facet.\n * @param {Integer} index The index to add at\n * @return {Component} The newly created component\n */\nfunction List$addItem(index, itemData) {\n index = index || this.count();\n this.owner.data.splice(index, 0, itemData || {});\n return this.item(index);\n}\n\n\n/**\n * Facet instance method\n * Adds a new child component at a particular index and returns the new component\n * @param {Integer} index The index to add at\n * @return {Component} The newly created component\n */\nfunction List$_addItem(index) {\n index = index || this.count();\n if (this.item(index))\n throw ListError('attempt to create item with ID of existing item');\n\n // Copy component\n var component = Component.copy(this.itemSample, true);\n var prevComponent = this._itemPreviousComponent(index);\n\n if (!prevComponent.el.parentNode)\n return logger.warn('list item sample was removed from DOM, probably caused by wrong data. Reset list data with array');\n\n // Add it to the DOM\n prevComponent.dom.insertAfter(component.el);\n\n // Add to list items\n this._setItem(index, component);\n\n // Show the list item component\n component.el.style.display = '';\n\n _updateItemsIndexes.call(this, index + 1);\n\n return component;\n}\n\n\nfunction _updateItemsIndexes(fromIndex, toIndex) {\n fromIndex = fromIndex || 0;\n toIndex = toIndex || this.count();\n for (var i = fromIndex; i < toIndex; i++) {\n var component = this._listItems[i];\n if (component)\n component.item.setIndex(i);\n else\n logger.warn('List: no item at position', i);\n }\n}\n\n\nfunction List$addItems(count, index) { // ,... items data\n var itemsData = _.slice(arguments, 2);\n if (itemsData.length < count) \n itemsData.concat(_.repeat(count - itemsData.length, {}));\n var spliceArgs = [index, 0].concat(itemsData);\n var dataFacet = this.owner.data;\n dataFacet.splice.apply(dataFacet, spliceArgs);\n}\n\n\n/**\n * List facet instance method\n * Adds a given number of items using template rendering rather than adding elements one by one\n *\n * @param {Integer} count number of items to add\n * @param {[Integer]} index optional index of item after which to add\n */\nfunction List$_addItems(count, index) {\n check(count, Match.Integer);\n if (count < 0)\n throw new ListError('can\\'t add negative number of items');\n\n if (count == 0) return;\n\n var itemsHTML = this.itemsTemplate({\n componentName: miloUtil.componentName,\n count: count\n });\n\n var wrapEl = document.createElement('div');\n wrapEl.innerHTML = itemsHTML;\n\n miloBinder(wrapEl, this.owner.container.scope);\n var children = domUtils.children(wrapEl);\n\n if (count != children.length)\n logger.error('number of items added is different from requested');\n\n if (children && children.length) {\n var listLength = this.count();\n var spliceIndex = index < 0\n ? 0\n : typeof index == 'undefined' || index > listLength\n ? listLength\n : index;\n\n var prevComponent = spliceIndex == 0\n ? this.itemSample\n : this._listItems[spliceIndex - 1];\n\n var frag = document.createDocumentFragment()\n , newComponents = [];\n\n children.forEach(function(el, i) {\n var component = Component.getComponent(el);\n if (! component)\n return logger.error('List: element in new items is not a component');\n newComponents.push(component);\n this._setItem(spliceIndex++, component);\n frag.appendChild(el);\n el.style.display = '';\n }, this);\n\n _updateItemsIndexes.call(this, spliceIndex);\n\n if (!prevComponent.el.parentNode)\n return logger.warn('list item sample was removed from DOM, probably caused by wrong data. Reset list data with array');\n\n // Add it to the DOM\n prevComponent.dom.insertAfter(frag);\n\n _.deferMethod(newComponents, 'forEach', function(comp) {\n comp.broadcast('stateready');\n });\n }\n}\n\n\n/**\n * List facet instance method\n * @param {Integer} index The index of the item to remove\n * @return {Array[Object]} The spliced data\n */\nfunction List$removeItem(index) {\n return this.owner.data.splice(index, 1);\n}\n\n\n/**\n * List facet instance method\n * @param {Integer} index The index of the item to extract\n * @return {Component} The extracted item\n */\nfunction List$extractItem(index) {\n var itemComp = this._removeItem(index, false);\n this._updateDataPaths(index, this.count());\n return itemComp;\n}\n\n\n/**\n * List facet instance method\n * Removes item, returns the removed item that is destroyed by default.\n * \n * @param {Number} index item index\n * @param {Boolean} doDestroyItem optional false to prevent item destruction, true by default\n * @return {Component}\n */\nfunction List$_removeItem(index, doDestroyItem) {\n var comp = this.item(index);\n\n if (! comp)\n return logger.warn('attempt to remove list item with id that does not exist');\n\n this._listItems[index] = undefined;\n delete this._listItemsHash[comp.name];\n if (doDestroyItem !== false) comp.destroy();\n else {\n comp.remove();\n comp.dom.remove();\n }\n\n this._listItems.splice(index, 1);\n _updateItemsIndexes.call(this, index);\n\n return comp;\n}\n\n\nfunction List$replaceItem(index, newItem){\n var oldItem = this.item(index);\n oldItem.dom.insertAfter(newItem.el);\n this._removeItem(index);\n this._setItem(index, newItem);\n}\n\n\n// Returns the previous item component given an index\nfunction _itemPreviousComponent(index) {\n while (index >= 0 && ! this._listItems[index])\n index--;\n\n return index >= 0\n ? this._listItems[index]\n : this.itemSample;\n}\n\n\n// toIndex is not included\n// no range checking is made\nfunction List$_updateDataPaths(fromIndex, toIndex) {\n for (var i = fromIndex; i < toIndex; i++) {\n var item = this.item(i);\n if (item)\n item.data._path = '[' + i + ']';\n else\n logger.warn('Data: no item for index', j);\n }\n}\n\n\n/**\n * Facet instance method\n * Similar to forEach method of Array, iterates each of the child items.\n * @param {Function} callback An iterator function to be called on each child item.\n * @param {[type]} thisArg Context to set `this`.\n */\nfunction List$each(callback, thisArg) {\n this._listItems.forEach(function(item, index) {\n if (item) callback.apply(this, arguments); // passes item, index to callback\n else logger.warn('List$each: item', index, 'is undefined');\n }, thisArg || this);\n}\n\n\n/**\n * Facet instance method\n * Destroys the list\n */\nfunction List$destroy() {\n if (this.itemSample) this.itemSample.destroy(true);\n ComponentFacet.prototype.destroy.apply(this, arguments);\n}\n",
- "'use strict';\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , Model = require('../../model')\n , Mixin = require('../../abstract/mixin')\n , _ = require('mol-proto');\n\n\n// generic drag handler, should be overridden\nvar ModelFacet = _.createSubclass(ComponentFacet, 'Model');\n\n_.extendProto(ModelFacet, {\n init: ModelFacet$init,\n getState: ModelFacet$getState,\n setState: ModelFacet$setState,\n _createMessenger: ModelFacet$_createMessenger,\n destroy: ModelFacet$destroy\n});\n\nfacetsRegistry.add(ModelFacet);\n\nmodule.exports = ModelFacet;\n\n\n/**\n * Expose Model class methods on ModelFacet\n */\nModel.useWith(ModelFacet, 'm');\n\n\nfunction ModelFacet$init() {\n this.m = new Model(this.config.data, this);\n ComponentFacet.prototype.init.apply(this, arguments);\n // this.m.proxyMethods(this); // Creates model's methods directly on facet\n}\n\n\n/**\n * ModelFacet instance method\n * Called by `Component.prototype.getState` to get facet's state\n * Simply returns model data\n *\n * @return {Object}\n */\nfunction ModelFacet$getState() {\n var modelValue = this.m.get();\n if (typeof modelValue == 'object')\n modelValue = _.deepClone(modelValue);\n return { state: modelValue };\n}\n\n\n/**\n * ModelFacet instance method\n * Called by `Component.prototype.setState` to set facet's state\n * Simply sets model data\n *\n * @param {Object} state data to set on facet's model\n */\nfunction ModelFacet$setState(state) {\n return this.m.set(state.state);\n}\n\n\nfunction ModelFacet$_createMessenger() { // Called by inherited init\n this._messenger = this.m._messenger;\n}\n\n\nfunction ModelFacet$destroy() {\n this.m.destroy();\n ComponentFacet.prototype.destroy.apply(this, arguments);\n}\n",
- "'use strict';\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , Model = require('../../model')\n\n , _ = require('mol-proto');\n\n\n// generic drag handler, should be overridden\nvar Options = _.createSubclass(ComponentFacet, 'Options');\n\n_.extendProto(Options, {\n init: Options$init,\n destroy: Options$destroy,\n _createMessenger: Options$_createMessenger\n});\n\nfacetsRegistry.add(Options);\n\nmodule.exports = Options;\n\n\nfunction Options$init() {\n this.m = new Model(this.config.options, this);\n ComponentFacet.prototype.init.apply(this, arguments);\n this.m.proxyMethods(this); // Creates model's methods directly on facet\n}\n\n\nfunction Options$_createMessenger() { // Called by inherited init\n this._messenger = this.m._messenger;\n}\n\n\nfunction Options$destroy() {\n this.m.destroy();\n ComponentFacet.prototype.destroy.apply(this, arguments);\n}\n",
- "'use strict';\n\n// \n// ###template facet\n\n// simplifies rendering of component element from template.\n// Any templating enging can be used that supports template compilation\n// (or you can mock this compilation easily by creating closure storing\n// template string in case your engine doesn't support compilation).\n// By default milo uses [doT](), the most versatile, conscise and at the\n// same time the fastest templating engine.\n// If you use milo in browser, it is the part of milo bundle and available\n// as global variable `doT`.\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , _ = require('mol-proto')\n , check = require('../../util/check')\n , logger = require('../../util/logger')\n , Match = check.Match\n , binder = require('../../binder');\n\n\n// data model connection facet\nvar Template = _.createSubclass(ComponentFacet, 'Template');\n\n_.extendProto(Template, {\n init: Template$init,\n start: Template$start,\n set: Template$set,\n getCompiled: Template$getCompiled,\n render: Template$render,\n binder: Template$binder\n\n // _reattach: _reattachEventsOnElementChange\n});\n\nfacetsRegistry.add(Template);\n\nmodule.exports = Template;\n\n\nfunction Template$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n\n // templates are interpolated with default (doT) or configured engine (this.config.compile)\n // unless this.config.interpolate is false\n var compile = this.config.interpolate === false\n ? undefined\n : this.config.compile || milo.config.template.compile;\n\n this.set(this.config.template || '', compile, this.config.compileOptions);\n}\n\n\nfunction Template$start() {\n ComponentFacet.prototype.start.apply(this, arguments);\n if (this.config.autoRender) {\n this.render();\n if (this.config.autoBinder)\n this.binder();\n }\n}\n\n\nfunction Template$getCompiled() {\n return this._template;\n}\n\n\nfunction Template$set(templateStr, compile, compileOptions) {\n check(templateStr, Match.OneOf(String, Function));\n check(compile, Match.Optional(Function));\n\n if (typeof templateStr == 'function')\n this._template = templateStr;\n else {\n this._templateStr = templateStr;\n if (compile)\n this._compile = compile;\n else\n compile = this._compile;\n\n if (compile)\n this._template = compile(templateStr, compileOptions);\n }\n\n return this;\n}\n\n\nfunction Template$render(data) { // we need data only if use templating engine\n this.owner.el.innerHTML = this._template\n ? this._template(data)\n : this._templateStr;\n\n return this;\n}\n\n\nfunction Template$binder() {\n if (this.owner.container)\n return this.owner.container.binder();\n else\n logger.error('TemplateFacet: Binder called without container facet.');\n}\n",
- "'use strict';\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , _ = require('mol-proto');\n\n\n/**\n * Transfer facet is designed for components to be able to represent other components\n * If a [Component](../c_class.js.html) has Transfer facet, when `Component.getState` is called for this componet it returns previously saved data, possibly from another component.\n * For example, a list of documents can use this facet so that each item in the list can store actual document component on it.\n */\nvar Transfer = _.createSubclass(ComponentFacet, 'Transfer');\n\n_.extendProto(Transfer, {\n init: Transfer$init,\n getState: Transfer$getState,\n setState: Transfer$setState,\n setActiveState: Transfer$setActiveState,\n setStateWithKey: Transfer$setStateWithKey,\n getStateWithKey: Transfer$getStateWithKey,\n getComponentMeta: Transfer$getComponentMeta\n});\n\nfacetsRegistry.add(Transfer);\n\nmodule.exports = Transfer;\n\n\nfunction Transfer$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n this._activeState = '';\n this._defaultKey = '';\n this._state = {};\n}\n\n\n/**\n * Transfer facet instance method\n * Returns transfer state for component. Can be obtained from another component by using `Component.getState`\n *\n * @return {Object}\n */\nfunction Transfer$getState() {\n return this._state[this._activeState] || this._state[this._defaultKey];\n}\n\n\n/**\n * Transfer facet instance method\n * Sets transfer state for component. Can be obtained from another component by using `Component.getState`\n *\n * @param {Object} state\n */\nfunction Transfer$setState(state) {\n this._state[''] = state;\n this.setActiveState('');\n}\n\n/**\n * Transfer facet instance method\n * Sets the active state (used by getState)\n * @param {[type]} key [description]\n */\nfunction Transfer$setActiveState(key) {\n this._activeState = key;\n}\n\n/**\n * Transfer facet instance method\n * Sets transfer state for component without default key. Can be obtained from another component by using `Component.getState`\n * When the active state is set to the expected key\n * @param {[type]} key [description]\n * @param {[type]} state [description]\n * @param {Boolean} isDefaultKey (Optional)\n */\nfunction Transfer$setStateWithKey(key, state, isDefaultKey) {\n if (!key) throw new Error('Transfer$setStateWithKey: no key');\n\n if (isDefaultKey)\n this._defaultKey = key;\n else\n this._defaultKey = this._defaultKey || key;\n\n this._state[key] = state;\n this.setActiveState(key);\n}\n\n\nfunction Transfer$getStateWithKey(key) {\n return typeof key == 'string' && this._state[key];\n}\n\n\nfunction Transfer$getComponentMeta() {\n var state = this.getState();\n return {\n compName: state && state.compName,\n compClass: state && state.compClass\n };\n}\n",
+ "'use strict';\n\n\nvar miloCore = require('milo-core')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match\n , logger = miloCore.util.logger;\n\n\nvar UNDO_COMMAND = '_undoCommand';\n\n\nmodule.exports = Command;\n\n\n/**\n * Command class to implement \"command pattern\" - packaging ll information necessary for delayed method execution\n *\n * @constructor\n * @param {Function} func method name or function to be executed\n * @param {List} *arguments parameters to be passed to method or function\n */\nfunction Command(func) { // , ... arguments\n this.init.apply(this, arguments);\n}\n\n\n/**\n * Command instance methods\n * \n * - [init](#Command$execute) - initialize command, should be overwritten by subclasses\n * - [execute](#Command$execute) - execute command\n * - [setUndo](#Command$setUndo) - set undo command for this command\n * - [getUndo](#Command$getUndo) - get undo command of this command\n * - [setArguments](#Command$setArguments) - set commands arguments\n * - [addArguments](#Command$addArguments) - add arguments to command\n * - [destroy](#Command$destroy)\n */\n_.extendProto(Command, {\n init: Command$init,\n execute: Command$execute,\n setUndo: Command$setUndo,\n getUndo: Command$getUndo,\n undo: Command$undo,\n redo: Command$execute, // same for command, different for transaction\n setArguments: Command$setArguments,\n addArguments: Command$addArguments,\n getArguments: Command$getArguments,\n changeArguments: Command$changeArguments,\n destroy: Command$destroy,\n\n setComment: Command$setComment,\n getDescription: Command$getDescription\n});\n\n\n/**\n * Command class methods\n *\n * - [create](#Command$$create) - commands factory\n */\n_.extend(Command, {\n create: Command$$create,\n createWithUndo: Command$$createWithUndo\n});\n\n\nfunction Command$init(func) { // , ... arguments\n check(func, Match.Optional(Function));\n this.func = func || function(){};\n this.args = _.slice(arguments, 1); \n}\n\n\n/**\n * Execute command making command object available via function property. \n */\nfunction Command$execute(cb) {\n var result = this.func.apply(this, this.args);\n if (cb) _.defer(cb);\n return result;\n}\n\n\n/**\n * Set undo command for this command. This command becomes undo command for undo command (so undo command can change this command during its execution).\n * \n * @param {Command} undoCommand\n */\nfunction Command$setUndo(undoCommand) {\n if (this[UNDO_COMMAND])\n logger.warn('Command setUndo: undo command is already set');\n\n this[UNDO_COMMAND] = undoCommand;\n undoCommand[UNDO_COMMAND] = this;\n}\n\n\n/**\n * Returns undo command of a given command\n *\n * @return {Command}\n */\nfunction Command$getUndo() {\n return this[UNDO_COMMAND];\n}\n\n\n/**\n * Executes undo command of current command\n */\nfunction Command$undo(cb) {\n var undoCmd = this.getUndo();\n if (! undoCmd) return logger.error('Command undo called without undo command present');\n var result = undoCmd.execute();\n if (cb) _.defer(cb);\n return result;\n}\n\n\n/**\n * Set command's arguments. If arguments were set during command's creation, this method will overwrite arguments and log warning.\n *\n * @param {List} *arguments\n */\nfunction Command$setArguments() { //, ... arguments\n if (this.args && this.args.length)\n logger.warn('Command setArguments: command arguments are already set');\n this.args = _.toArray(arguments);\n}\n\n\nfunction Command$getArguments() {\n return this.args;\n}\n\n\nfunction Command$changeArguments() { //, ... arguments\n this.args = _.toArray(arguments);\n}\n\n\n/**\n * Add (append) arguments to command\n *\n * @param {List} *arguments arguments list to be appended to command\n */\nfunction Command$addArguments() { //, ... arguments\n if (! this.args) this.args = [];\n _.appendArray(this.args, arguments);\n}\n\n\n/**\n * Commands factory. Likely ot be overridden by subclasses to implement custom logic of command construction\n * \n * @this {Function} Class of command\n * @param {Function} func method name or function to be executed\n * @param {List} *arguments parameters to be passed to method or function\n * @return {Command}\n */\nfunction Command$$create(func) { // , ... arguments\n return _.newApply(this, arguments);\n}\n\n\nfunction Command$$createWithUndo() {\n throw new Error('createWithUndo should be implemented by subsclass');\n}\n\n\n/**\n * Destroy current command (to prevent potential memory leaks when commands point to DOM elements)\n */\nfunction Command$destroy() {\n delete this.func;\n delete this.args;\n var undoCmd = this[UNDO_COMMAND];\n if (undoCmd) {\n delete this[UNDO_COMMAND][UNDO_COMMAND];\n delete this[UNDO_COMMAND];\n undoCmd.destroy();\n }\n}\n\n\nfunction Command$setComment(comment) {\n this.comment = comment;\n}\n\n\nfunction Command$getDescription() {\n return {\n func: this.func.name,\n comment: this.comment\n };\n}\n",
+ "'use strict';\n\n\nvar ActionsHistory = require('./actions_history')\n , _ = require('milo-core').proto;\n\n\nmodule.exports = Transaction;\n\n\nfunction Transaction() {\n this.commands = new ActionsHistory;\n}\n\n\n_.extendProto(Transaction, {\n execute: Transaction$execute,\n undo: Transaction$undo,\n redo: Transaction$redo,\n destroy: Transaction$destroy,\n storeCommand: Transaction$storeCommand,\n merge: Transaction$merge,\n\n setComment: Transaction$setComment,\n getDescription: Transaction$getDescription\n});\n\n\nfunction Transaction$execute() {\n this.commands.each('execute');\n}\n\n\nfunction Transaction$undo(cb) {\n this.commands.undoAllAsync(cb);\n}\n\n\nfunction Transaction$redo(cb) {\n this.commands.redoAllAsync(cb);\n}\n\n\nfunction Transaction$destroy() {\n this.commands.each('destroy');\n}\n\n\nfunction Transaction$storeCommand(command) {\n this.commands.store(command);\n}\n\n\nfunction Transaction$merge(transaction) {\n transaction.commands.each(function(cmd) {\n this.commands.store(cmd);\n }, this);\n}\n\n\nfunction Transaction$setComment(comment) {\n this.comment = comment\n}\n\n\nfunction Transaction$getDescription() {\n var commands = this.commands.getDescription();\n return {\n commands: commands.actions,\n comment: this.comment\n }\n}\n",
+ "'use strict';\n\n\nvar ActionsHistory = require('./actions_history')\n , Transaction = require('./transaction')\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , Messenger = miloCore.Messenger\n , _ = miloCore.proto;\n\n\nmodule.exports = TransactionHistory;\n\n\nvar SCHEDULED = '_scheduled';\n\n\nfunction TransactionHistory(maxLength) {\n this.transactions = new ActionsHistory(maxLength);\n this.currentBatch = undefined;\n this.currentTransaction = undefined;\n this[SCHEDULED] = false;\n}\n\n\n_.extendProto(TransactionHistory, {\n storeCommand: TransactionHistory$storeCommand,\n endTransaction: TransactionHistory$endTransaction,\n storeTransaction: TransactionHistory$storeTransaction,\n deleteLastTransaction: TransactionHistory$deleteLastTransaction,\n undo: TransactionHistory$undo,\n redo: TransactionHistory$redo,\n inTransaction: TransactionHistory$inTransaction,\n\n getDescription: TransactionHistory$getDescription,\n useMessenger: TransactionHistory$useMessenger,\n destroy: TransactionHistory$destroy\n});\n\n\n/**\n * Stores command in the history. \n * @param {Command} command \n * @param {Boolean} appendTransaction If `true`, appends to the current or previous transaction if there is no current transaction.\n */\nfunction TransactionHistory$storeCommand(command, appendTransaction) {\n if (appendTransaction && !(this.currentTransaction || this.currentBatch)) {\n var transaction = this.transactions.getLastAction();\n transaction.storeCommand(command);\n _postTransactionMessage.call(this, 'appended', transaction);\n return;\n }\n\n if (! this.currentBatch) this.currentBatch = new Transaction;\n this.currentBatch.storeCommand(command);\n if (! this[SCHEDULED]) {\n this[SCHEDULED] = true;\n _.deferMethod(this, _storeTransaction);\n }\n}\n\n\nfunction TransactionHistory$deleteLastTransaction() {\n if (this.currentBatch || this.currentTransaction) {\n this.currentBatch = undefined;\n this.currentTransaction = undefined;\n } else {\n this.transactions.deleteLast();\n }\n}\n\n\nfunction _storeTransaction() {\n if (this.currentBatch) {\n _addBatchToTransaction.call(this);\n _.deferMethod(this, _storeTransaction);\n } else {\n _storeCurrentTransaction.call(this);\n this[SCHEDULED] = false;\n }\n}\n\n\nfunction TransactionHistory$endTransaction() {\n _addBatchToTransaction.call(this);\n _storeCurrentTransaction.call(this);\n}\n\n\nfunction _addBatchToTransaction() {\n if (this.currentBatch) {\n if (! this.currentTransaction) this.currentTransaction = new Transaction;\n this.currentTransaction.merge(this.currentBatch);\n this.currentBatch = undefined;\n } \n}\n\n\nfunction _storeCurrentTransaction() {\n if (this.currentTransaction) {\n var t = this.currentTransaction;\n this.transactions.store(t);\n _postTransactionMessage.call(this, 'stored', t);\n\n this.currentTransaction = undefined;\n }\n}\n\n\nfunction TransactionHistory$storeTransaction(transaction) {\n this.endTransaction();\n\n this.transactions.store(transaction);\n _postTransactionMessage.call(this, 'stored', transaction);\n}\n\n\nfunction _postTransactionMessage(msg, transaction) {\n if (this._messenger)\n this._messenger.postMessage(msg, { transaction: transaction });\n}\n\n\nfunction TransactionHistory$undo(cb) {\n var t = this.transactions.undo(cb);\n if (t) _postTransactionMessage.call(this, 'undone', t);\n return t;\n}\n\n\nfunction TransactionHistory$redo(cb) {\n var t = this.transactions.redo(cb);\n if (t) _postTransactionMessage.call(this, 'redone', t);\n return t;\n}\n\n\nfunction TransactionHistory$inTransaction() {\n return this[SCHEDULED];\n}\n\n\nfunction TransactionHistory$getDescription() {\n return this.transactions.getDescription();\n}\n\n\nfunction TransactionHistory$useMessenger() {\n return this._messenger = new Messenger(this, Messenger.defaultMethods);\n}\n\n\nfunction TransactionHistory$destroy() {\n if (this._messenger) this._messenger.destroy();\n delete this.transactions;\n}\n",
+ "'use strict';\n\n\nvar FacetedObject = require('../abstract/faceted_object')\n , facetsRegistry = require('./c_facets/cf_registry')\n , ComponentFacet = facetsRegistry.get('ComponentFacet')\n , componentUtils = require('./c_utils')\n , miloCore = require('milo-core')\n , Messenger = miloCore.Messenger\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match\n , config = require('../config')\n , miloComponentName = require('../util/component_name')\n , logger = miloCore.util.logger\n , domUtils = require('../util/dom')\n , BindAttribute = require('../attributes/a_bind')\n , Scope = require('./scope')\n , DOMStorage = require('../util/storage');\n\nvar _makeComponentConditionFunc = componentUtils._makeComponentConditionFunc;\n\n\n/**\n * `milo.Component`\n * Base Component class. Subclass of [FacetedObject](../abstract/faceted_object.js.html), but none of this class methods should be directly used with component.\n * Its constructor passes its parameters, including its [scope](./scope.js.html), DOM element and name to [`init`](#init) method.\n * The constructor of Component class rarely needs to be used directly, as [milo.binder](../binder.js.html) creates components when it scans DOM tree.\n * [`Component.createComponentClass`](#createComponentClass) should be used to create a subclass of Component class with configured facets.\n *\n *\n * ####Component instance properties####\n *\n * - el - DOM element that component is attached to. If the second component is attached to the same DOM element, the warning will be logged to console. To get component reference from DOM element use [Component.getComponent](./c_utils.js.html#getComponent) class method. To inspect component via element in browser check `___milo_component` property of element (property name be changed using `milo.config`).\n * - scope - parent scope object, an instance of [Scope](./scope.js.html) class. To get parent component use [getScopeParent](#Component$getScopeParent) instance method of component. The actual path to get parent of conponent is `component.scope._hostObject.owner`, where `_hostObject` refers to [Container](c_facets/Container.js.html) facet of parent component and `owner` to the parent itself. The children of component are accessible via the scope of its container facet: `component.container.scope`. The scope hierarchy can be the same or different as the DOM hierarchy - DOM children of the component will be on the same scope as component if it does not have `Container` facet and in the scope of its Container facet if it has it. See [Scope](./scope.js.html).\n * - name - the name of component, should be unique for the scope where component belongs. To find component in scope the component's name should be used as property of scope object. See [Scope](./scope.js.html).\n * - facets - map of references of all component's facets (facet names are lowercase in this map). All facets can be accessed directly as properties of component, this property can be used to iterate facets (it is used in this way in [allFacets](#Component$allFacets) component's instance method that allows to call method with the same name on all facets).\n * - extraFacets - an array of names of facets that are added to component and do not form the part of component's class.\n * - _messenger - the reference to component's [messenger](../messenger/index.js.html). Rarely needs to be used directly as all commonly used methods of mesenger are available directly on component.\n *\n *\n * ####Component events####\n *\n * - 'childrenbound' - synchronously dispatched when children of DOM element which compnent is connected to are connected to components. The event is dispatched when component is created with `milo.binder` (as is almost always the case, as all Component class methods that create/copy components use `milo.binder` internally - component constructor and Component.create methods are not used in framework outside of `milo.binder` and rarely if ever need to be used in aplication).\n * - 'addedtoscope' - synchronously dispatched when component is added to scope.\n * - 'stateready' - aynchronously dispatched when component (together with its scope children) is created with [Component.createFromState](#Component$$createFromState) (or `createFromDataTransfer`) method. Can be dispatched by application if the component's state is set with some other mechanism. This event is not used in `milo`, it can be used in application in particular subclasses of component.\n * - 'getstatestarted' - emitted synchronously just before getState executes so components and facets can clean up their state for serialization. \n * - 'getstatecompleted' - emitted asynchronously after getState executes so components and facets can restore their state after serialization.\n *\n *\n * ####Component \"lifecycle\"####\n *\n * 1. Component constructor is called. Component's constructor simply calls constructor of [FacetedObject](../abstract/faceted_object.js.html) that is a superclass of Component. Subclasses of Component should not implement their own constructor, they can optionally implement `init` method, but most components do not need to do it.\n * 2. constructors and `init` methods of all facets are called in sequence. Same as components, facet do not implement their constructors, they can optionally implement `init` and `start` methods (see below). Inside `init` method there should be only general initialization code without any dependency on component itself (it is not ready yet) and other facets (as there is no specific facets creation order). If facet implements `init` method it MUST call inherited init with `ComponentFacet.prototype.init.apply(this, arguments)`.\n * 3. `init` method of component is called. At this point all facets are created but facets still can be not ready as they can have initialization code in `start` method. If component subclass implements `init` method it MUST call inherited method with `.prototype.init.apply(this, arguments)`, where is Component or another superclass the component is a subclass of.\n * 4. `check` method of all facets is called. This method adds facets that are not part of the component declaration (being part of the class or explicitely listed in bind attribute) but are required by facets that the compnent already has. Subclasses of [ComponentFacet](./c_facet.js.html) do not need to implement this method.\n * 5. `start` method of all facets is called. This method is usually implemented by ComponentFacet subclasses and it can have any initialization code that depends on component or on other facets that are the dependencies of a facet. Inherited `start` method should be called int he same way as written above.\n * 6. `start` method of component is called. This component method can be implemented by subclasses if they need to have some initialization code that depends on some facets and requires that these facets are fully inialized. Often such code also depends on component's scope children as well so this code should be inside `'childrenbound'` event subscriber.\n * 7. 'addedtoscope' event is dispatched when component is added to its parent's scope or to top level scope created by `milo.binder`.\n * 8. component's children are created (steps 1-6 above are followed for each child).\n * 9. 'childrenbound' event is dispatched when all component's children are created and added to their scope (see event description below).\n * 10. 'stateready' event is dispatched for component and all its children when component is create from state (see event description below).\n * 11. at this point component is in the \"interactive\" state when it and its facets will only respond to messages/events that they subscribed to during initialization.\n *\n *\n * @param {Scope} scope scope to which component will belong. It is usually a top level scope object returned by `milo.binder` or `scope` property of Container facet.\n * @param {Element} element DOM element that component is attached to\n * @param {String} name component name, should be unique in the scope of component\n * @param {ComponentInfo} componentInfo instance of ComponentInfo class that can be used to create a copy of component\n * TODO try removing it\n * @return {Component}\n */\nvar Component = _.createSubclass(FacetedObject, 'Component', true);\n\nmodule.exports = Component;\n\n_registerWithDomStorage('Component');\n\n\n/**\n * ####Component class methods####\n *\n * - [createComponentClass](#Component$$createComponentClass)\n * - [create](#Component$$create)\n * - [copy](#Component$$copy)\n * - [createOnElement](#Component$$createOnElement)\n * - [isComponent](c_utils.js.html#isComponent)\n * - [getComponent](c_utils.js.html#getComponent)\n * - [getContainingComponent](c_utils.js.html#getContainingComponent)\n * - [createFromState](#Component$$createFromState)\n * - [createFromDataTransfer](#Component$$createFromDataTransfer)\n */\n_.extend(Component, {\n createComponentClass: Component$$createComponentClass,\n create: Component$$create,\n copy: Component$$copy,\n createOnElement: Component$$createOnElement,\n isComponent: componentUtils.isComponent,\n getComponent: componentUtils.getComponent,\n getContainingComponent: componentUtils.getContainingComponent,\n createFromState: Component$$createFromState,\n createFromDataTransfer: Component$$createFromDataTransfer\n});\ndelete Component.createFacetedClass;\n\n\n/**\n * ####Component instance methods####\n *\n * - [init](#Component$init)\n * - [createElement](#Component$createElement)\n * - [hasFacet](#Component$hasFacet)\n * - [addFacet](#Component$addFacet)\n * - [allFacets](#Component$allFacets)\n * - [rename](#Component$rename)\n * - [remove](#Component$remove)\n * - [getState](#Component$getState)\n * - [getTransferState](#Component$getTransferState)\n * - [setState](#Component$setState)\n * - [getScopeParent](#Component$getScopeParent)\n * - [getTopScopeParent](#Component$getTopScopeParent)\n * - [getScopeParentWithClass](#Component$getScopeParentWithClass)\n * - [getTopScopeParentWithClass](#Component$getTopScopeParentWithClass)\n * - [walkScopeTree](#Component$walkScopeTree)\n * - [broadcast](#Component$broadcast)\n * - [destroy](#Component$destroy)\n * - [isDestroyed](#Component$isDestroyed)\n *\n *\n * #####[Messenger](../messenger/index.js.html) methods available on component#####\n *\n * - [on](../messenger/index.js.html#Messenger$on) - single subscribe\n * - [off](../messenger/index.js.html#Messenger$off) - single unsubscribe\n * - [onMessages](../messenger/index.js.html#Messenger$onMessages) - multiple subscribe\n * - [offMessages](../messenger/index.js.html#Messenger$offMessages) - multiple unsubscribe\n * - [postMessage](../messenger/index.js.html#Messenger$postMessage) - post message on component\n * - [getSubscribers](../messenger/index.js.html#Messenger$getSubscribers) - get subscribers for a given message\n */\n_.extendProto(Component, {\n init: Component$init,\n start: Component$start,\n createElement: Component$createElement,\n hasFacet: Component$hasFacet,\n addFacet: Component$addFacet,\n allFacets: Component$allFacets,\n rename: Component$rename,\n remove: Component$remove,\n insertInto: Component$insertInto,\n\n getState: Component$getState,\n getTransferState: Component$getTransferState,\n _getState: Component$_getState,\n setState: Component$setState,\n \n getScopeParent: Component$getScopeParent,\n getTopScopeParent: Component$getTopScopeParent,\n getScopeParentWithClass: Component$getScopeParentWithClass,\n getTopScopeParentWithClass: Component$getTopScopeParentWithClass,\n\n setScopeParentFromDOM: Component$setScopeParentFromDOM,\n\n walkScopeTree: Component$walkScopeTree,\n\n treePathOf: Component$treePathOf,\n getComponentAtTreePath: Component$getComponentAtTreePath,\n insertAtTreePath: Component$insertAtTreePath,\n\n broadcast: Component$broadcast,\n destroy: Component$destroy,\n isDestroyed: Component$isDestroyed\n});\n\n\n/**\n * Expose Messenger methods on Component prototype\n */\nvar MESSENGER_PROPERTY = '_messenger';\nMessenger.useWith(Component, MESSENGER_PROPERTY, Messenger.defaultMethods);\n\n\nvar COMPONENT_DATA_TYPE_PREFIX = 'x-application/milo-component';\nvar COMPONENT_DATA_TYPE_REGEX = /x-application\\/milo-component\\/([a-z_$][0-9a-z_$]*)(?:\\/())/i;\n\n/**\n * Component class method\n * Creates a subclass of component from the map of configured facets.\n * This method wraps and replaces [`createFacetedClass`](../abstract/faceted_object.js.html#createFacetedClass) class method of FacetedObject.\n * Unlike createFacetedClass, this method take facet classes from registry by their name, so only map of facets configuration needs to be passed. All facets classes should be subclasses of [ComponentFacet](./c_facet.js.html)\n *\n * @param {String} name class name\n * @param {Object[Object] | Array[String]} facetsConfig map of facets configuration.\n * If some facet does not require configuration, `undefined` should be passed as the configuration for the facet.\n * If no facet requires configuration, the array of facets names can be passed.\n * @return {Subclass(Component)}\n */\nfunction Component$$createComponentClass(name, facetsConfig) {\n // convert array of facet names to map of empty facets configurations\n if (Array.isArray(facetsConfig)) {\n var configMap = {};\n facetsConfig.forEach(function(fct) {\n var fctName = _.firstLowerCase(fct);\n configMap[fctName] = {};\n });\n facetsConfig = configMap;\n }\n\n // construct map of facets classes from facetRegistry\n var facetsClasses;\n if (typeof facetsConfig == 'object' && _.keys(facetsConfig).length) {\n facetsClasses = {};\n _.eachKey(facetsConfig, function(fctConfig, fct) {\n var fctName = _.firstLowerCase(fct);\n var fctClassName = _.firstUpperCase(fct);\n facetsClasses[fctName] = facetsRegistry.get(fctClassName);\n });\n }\n\n // create subclass of Component using method of FacetedObject\n var ComponentClass = FacetedObject.createFacetedClass.call(this, name, facetsClasses, facetsConfig);\n \n _registerWithDomStorage(name);\n\n return ComponentClass;\n}\n\n\nfunction _registerWithDomStorage(className) {\n DOMStorage.registerDataType(className, Component_domStorageSerializer, Component_domStorageParser);\n}\n\n\nfunction Component_domStorageSerializer(component) {\n var state = component.getState();\n return JSON.stringify(state); \n}\n\n\nfunction Component_domStorageParser(compStr, compClassName) {\n var state = _.jsonParse(compStr);\n if (state)\n return Component.createFromState(state);\n}\n\n\n/**\n * Component class method\n * Creates component from [ComponentInfo](./c_info.js.html) (used by [milo.binder](../binder.js.html) and to copy component)\n * Component of any registered class (see [componentsRegistry](./c_registry.js.html)) with any additional registered facets (see [facetsRegistry](./c_facets/cf_registry.js.html)) can be created using this method.\n *\n * @param {ComponentInfo} info\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n @ @return {Component}\n */\nfunction Component$$create(info, throwOnErrors) {\n var ComponentClass = info.ComponentClass;\n\n if (typeof ComponentClass != 'function') {\n var message = 'create: component class should be function, \"' + typeof ComponentClass + '\" passed'; \n if (throwOnErrors === false) {\n logger.error('Component', message, ';using base Component class instead');\n ComponentClass = Component;\n } else\n throw new Error(message);\n }\n\n var aComponent = new ComponentClass(info.scope, info.el, info.name, info);\n\n if (info.extraFacetsClasses)\n _.eachKey(info.extraFacetsClasses, function(FacetClass) {\n if (! aComponent.hasFacet(FacetClass))\n aComponent.addFacet(FacetClass, undefined, undefined, throwOnErrors);\n });\n\n return aComponent;\n}\n\n\n/**\n * Component class method\n * Create a copy of component, including a copy of DOM element. Returns a copy of `component` (of the same class) with new DOM element (not inserted into page).\n * Component is added to the same scope as the original component.\n *\n * @param {Component} component an instance of Component class or subclass\n * @param {Boolean} deepCopy optional `true` to make deep copy of DOM element, otherwise only element without children is copied\n * @return {Component}\n */\nfunction Component$$copy(component, deepCopy) {\n check(component, Component);\n check(deepCopy, Match.Optional(Boolean));\n\n if (deepCopy && !component.container) \n throw new Error('Cannot deep copy component without container facet');\n\n // copy DOM element, using Dom facet if it is available\n var newEl = component.dom \n ? component.dom.copy(deepCopy)\n : component.el.cloneNode(deepCopy);\n\n var ComponentClass = component.constructor;\n\n // create component of the same class on the element\n var aComponent = ComponentClass.createOnElement(newEl, undefined, component.scope, component.extraFacets);\n var state = component._getState(deepCopy || false);\n aComponent.setState(state);\n _.deferMethod(aComponent, 'broadcast', 'stateready');\n return aComponent;\n}\n\n\n/**\n * Component class method\n * Creates an instance of component atached to element. All subclasses of component inherit this method.\n * Returns the component of the class this method is used with (thecontext of the method call).\n *\n * @param {Element} el optional element to attach component to. If element is not passed, it will be created\n * @param {String} innerHTML optional inner html to insert in element before binding.\n * @param {Scope} rootScope optional scope to put component in. If not passed, component will be attached to the scope that contains the element. If such scope does not exist, new scope will be created.\n * @param {Array[String]} extraFacets list of extra facet to add to component\n * @return {Subclass(Component)}\n */\nfunction Component$$createOnElement(el, innerHTML, rootScope, extraFacets) {\n check(innerHTML, Match.Optional(String));\n check(rootScope, Match.Optional(Scope));\n check(extraFacets, Match.Optional([String]));\n\n // \"this\" refers to the class of component here, as this is a class method\n if (el && innerHTML) el.innerHTML = innerHTML;\n el = el || _createComponentElement.call(this, innerHTML);\n rootScope = rootScope || _findOrCreateComponentRootScope(el);\n var aComponent = _addAttributeAndBindComponent.call(this, el, rootScope, extraFacets);\n aComponent.broadcast('stateready');\n return aComponent;\n}\n\nfunction _createComponentElement(innerHTML) {\n // \"this\" refers to the class of component here, as this is a class method\n var Dom = facetsRegistry.get('Dom')\n , domFacetConfig = this.getFacetConfig('dom')\n , templateFacetConfig = this.getFacetConfig('template')\n , template = templateFacetConfig && templateFacetConfig.template;\n\n var elConfig = {\n domConfig: domFacetConfig,\n template: template,\n content: innerHTML\n };\n\n return Dom.createElement(elConfig);\n}\n\nfunction _findOrCreateComponentRootScope(el) {\n var parent = Component.getContainingComponent(el, false, 'Container');\n return parent ? parent.container.scope : new Scope(el);\n}\n\nfunction _addAttributeAndBindComponent(el, rootScope, extraFacets) {\n // add bind attribute to element\n var attr = new BindAttribute(el);\n // \"this\" refers to the class of component here, as this is a class method\n attr.compClass = this.name;\n attr.compFacets = extraFacets;\n attr.decorate();\n\n // should be required here to resolve circular dependency\n var miloBinder = require('../binder');\n miloBinder(el, rootScope);\n\n return rootScope[attr.compName];\n}\n\n/**\n * Component class method\n * Creates component from component state, that includes information about its class, extra facets, facets data and all scope children.\n * This is used to save/load, copy/paste and drag/drop component\n *\n * @param {Object} state state from which component will be created\n * @param {Scope} rootScope scope to which component will be added\n * @param {Boolean} newUniqueName optional `true` to create component with the name different from the original one. `False` by default.\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n * @return {Component} component\n */\nfunction Component$$createFromState(state, rootScope, newUniqueName, throwOnErrors) {\n check(state, Match.ObjectIncluding({\n compName: Match.Optional(String),\n compClass: Match.Optional(String),\n extraFacets: Match.Optional([String]),\n facetsStates: Match.Optional(Object),\n outerHTML: String\n }));\n\n var miloBinder = require('../binder');\n\n // create wrapper element optionally renaming component\n var wrapEl = _createComponentWrapElement(state, newUniqueName);\n\n // instantiate all components from HTML\n var scope = miloBinder(wrapEl, undefined, undefined, throwOnErrors);\n\n // as there should only be one component, call to _any will return it\n var component = scope._any();\n\n // set component's scope\n if (rootScope) {\n component.scope = rootScope;\n rootScope._add(component);\n }\n\n // restore component state\n component.setState(state);\n _.deferMethod(component, 'broadcast', 'stateready');\n\n return component; \n}\n\n\n// used by Component$$createFromState\nfunction _createComponentWrapElement(state, newUniqueName) {\n var wrapEl = document.createElement('div');\n wrapEl.innerHTML = state.outerHTML;\n\n var children = domUtils.children(wrapEl);\n if (children.length != 1)\n throw new Error('cannot create component: incorrect HTML, elements number: ' + children.length + ' (should be 1)');\n var compEl = children[0];\n var attr = new BindAttribute(compEl);\n attr.compName = newUniqueName ? miloComponentName() : state.compName;\n attr.compClass = state.compClass;\n attr.compFacets = state.extraFacets;\n attr.decorate();\n\n return wrapEl;\n}\n\n/**\n * Creates a component from a DataTransfer object (if possible)\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer\n * @param {DataTransfer} dataTransfer Data transfer\n */\nfunction Component$$createFromDataTransfer(dataTransfer) {\n var dataType = _.find(dataTransfer.types, function (type) {\n return COMPONENT_DATA_TYPE_REGEX.test(type);\n });\n if (!dataType) return;\n\n var state = _.jsonParse(dataTransfer.getData(dataType));\n if (!state) return;\n\n return Component.createFromState(state, undefined, true);\n}\n\n\n/**\n * Component instance method.\n * Initializes component. Automatically called by inherited constructor of FacetedObject.\n * Subclasses should call inherited init methods:\n * ```\n * Component.prototype.init.apply(this, arguments)\n * ```\n *\n * @param {Scope} scope scope to which component will belong. It is usually a top level scope object returned by `milo.binder` or `scope` property of Container facet.\n * @param {Element} element DOM element that component is attached to\n * @param {String} name component name, should be unique in the scope of component\n * @param {ComponentInfo} componentInfo instance of ComponentInfo class that can be used to create a copy of component\n * TODO try removing it\n */\nfunction Component$init(scope, element, name, componentInfo) {\n // create DOM element if it wasn't passed to Constructor\n this.el = element || this.createElement();\n\n // store reference to component on DOM element\n if (this.el) {\n // check that element does not have a component already atached\n var elComp = this.el[config.componentRef];\n if (elComp)\n logger.warn('component ' + name + ' attached to element that already has component ' + elComp.name);\n\n this.el[config.componentRef] = this;\n }\n\n _.defineProperties(this, {\n componentInfo: componentInfo,\n extraFacets: []\n }, _.ENUM);\n\n this.name = name;\n this.scope = scope;\n\n // create component messenger\n var messenger = new Messenger(this);\n _.defineProperty(this, MESSENGER_PROPERTY, messenger);\n\n // check all facets dependencies (required facets)\n this.allFacets('check');\n\n // start all facets\n this.allFacets('start');\n\n // call start method if it's defined in subclass\n if (this.start) this.start();\n}\n\n\n/**\n * This is a stub to avoid confusion whether the method of superclass should be called in subclasses\n * The start method of subclass instance is called once all the facets are created, initialized and started (see above)\n */\nfunction Component$start() {}\n\n\n/**\n * Component instance method.\n * Initializes the element which this component is bound to\n *\n * This method is called when a component is instantiated outside the DOM and\n * will generate a new element for the component.\n * \n * @return {Element}\n */\nfunction Component$createElement() {\n if (typeof document == 'undefined')\n return;\n\n this.el = this.dom\n ? this.dom.createElement()\n : document.createElement('DIV');\n\n return this.el;\n}\n\n\n/**\n * Component instance method\n * Returns true if component has facet\n *\n * @param {Function|String} facetNameOrClass\n * @return {Boolean}\n */\nfunction Component$hasFacet(facetNameOrClass) {\n var facetName = _.firstLowerCase(typeof facetNameOrClass == 'function'\n ? facetNameOrClass.name\n : facetNameOrClass);\n\n var facet = this[facetName];\n if (! facet instanceof ComponentFacet)\n logger.warn('expected facet', facetName, 'but this property name is used for something else');\n\n return !! facet;\n}\n\n\n/**\n * Component instance method.\n * Adds facet with given name or class to the instance of Component (or its subclass).\n * \n * @param {String|Subclass(Component)} facetNameOrClass name of facet class or the class itself. If name is passed, the class will be retireved from facetsRegistry\n * @param {Object} facetConfig optional facet configuration\n * @param {String} facetName optional facet name. Allows to add facet under a name different from the class name supplied.\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n */\nfunction Component$addFacet(facetNameOrClass, facetConfig, facetName, throwOnErrors) {\n check(facetNameOrClass, Match.OneOf(String, Match.Subclass(ComponentFacet)));\n check(facetConfig, Match.Optional(Object));\n check(facetName, Match.Optional(String));\n\n var FacetClass;\n // if only name passed, retrieve facet class from registry\n if (typeof facetNameOrClass == 'string') {\n var facetClassName = _.firstUpperCase(facetNameOrClass);\n FacetClass = facetsRegistry.get(facetClassName);\n } else \n FacetClass = facetNameOrClass;\n\n if (!facetName)\n facetName = _.firstLowerCase(FacetClass.name);\n\n this.extraFacets.push(facetName);\n\n // add facet using method of FacetedObject\n var newFacet = FacetedObject.prototype.addFacet.call(this, FacetClass, facetConfig, facetName, throwOnErrors);\n\n // check depenedencies and start facet\n if (newFacet.check) newFacet.check();\n if (newFacet.start) newFacet.start();\n}\n\n\n/**\n * Component instance method.\n * Envoke given method with optional parameters on all facets.\n * Returns the map of values returned by all facets. If the facet doesn't have the method it is simply not called and the value in the map will be undefined.\n *\n * @param {String} method method name to envoke on the facet\n * @return {Object}\n */\nfunction Component$allFacets(method) { // ,... arguments\n var args = _.slice(arguments, 1);\n\n return _.mapKeys(this.facets, function(facet, fctName) {\n if (facet && typeof facet[method] == 'function')\n return facet[method].apply(facet, args);\n });\n}\n\n\n/**\n * Component instance method.\n * \n * @param {[String]} name optional new name of component, \n * @param {[Boolean]} renameInScope optional false to not rename ComponentInfo object in its scope, true by default\n */\nfunction Component$rename(name, renameInScope) {\n name = name || miloComponentName();\n this.componentInfo.rename(name, false);\n Scope.rename(this, name, renameInScope);\n}\n\n\n/**\n * Component instance method.\n * Removes component from its scope.\n *\n * @param {Boolean} preserveScopeProperty true not to delete scope property of component\n * @param {Boolean} quiet optional true to suppress the warning message if the component is not in scope\n */\nfunction Component$remove(preserveScopeProperty, quiet) {\n if (this.scope) {\n this.scope._remove(this.name, quiet);\n if (! preserveScopeProperty)\n delete this.scope;\n }\n}\n\n\n/**\n * Component instance method.\n * Inserts the component into the DOM and attempts to adjust the scope tree accordingly.\n * @param {HTMLElement} parentEl The element into which the component should be inserted.\n * @param {HTMLElement} referenceEl (optional) The reference element it should be inserted before.\n */\nfunction Component$insertInto(parentEl, referenceEl) {\n parentEl.insertBefore(this.el, referenceEl);\n this.setScopeParentFromDOM();\n}\n\n\n/**\n * Component instance method\n * Retrieves all component state, including information about its class, extra facets, facets data and all scope children.\n * This information is used to save/load, copy/paste and drag/drop component \n * Returns component state\n *\n * @this {Component} component which state will be saved\n * @return {Object}\n */\nfunction Component$getState() {\n this.broadcast('getstatestarted', { rootComponent: this }, undefined, true);\n var state = this._getState(true);\n state.outerHTML = this.el.outerHTML;\n _.deferMethod(this, 'broadcast', 'getstatecompleted', { rootComponent: this }, undefined, true);\n return state;\n}\n\n\n/**\n * Component instance method\n * Retrieves all component state, including information about its class, extra facets, facets data and all scope children.\n * This information is used to save/load, copy/paste and drag/drop component \n * If component has [Transfer](./c_facets/Transfer.js.html) facet on it, this method retrieves state from this facet\n * Returns component state\n *\n * @this {Component} component which state will be saved\n * @param {Object} options can be used by subclasses. \n * @return {Object}\n */\nfunction Component$getTransferState(options) {\n return this.transfer\n ? this.transfer.getState(options)\n : this.getState(options);\n}\n\n\n/**\n * Component instance method\n * Returns the state of component\n * Used by class method `Component.getState` and by [Container](./c_facets/Container.js.html) facet.\n *\n * @private\n * @param {Boolean} deepState false to get shallow state from all facets (true by default)\n * @return {Object}\n */\nfunction Component$_getState(deepState){\n\n var facetsStates = this.allFacets('getState', deepState === false ? false : true);\n facetsStates = _.filterKeys(facetsStates, function(fctState) {\n return !! fctState;\n });\n\n return {\n compName: this.name,\n compClass: this.constructor.name,\n extraFacets: this.extraFacets,\n facetsStates: facetsStates\n };\n}\n\n\n/**\n * Component instance method\n * Sets the state of component.\n * Used by class method `Component.createFromState` and by [Container](./c_facets/Container.js.html) facet.\n *\n * @private\n * @param {Object} state state to set the component\n */\nfunction Component$setState(state) {\n if (state.facetsStates)\n _.eachKey(state.facetsStates, function(fctState, fctName) {\n var facet = this[fctName];\n if (facet && typeof facet.setState == 'function')\n facet.setState(fctState);\n }, this);\n}\n\n\n/**\n * Component instance method.\n * Returns the scope parent of a component.\n * If `conditionOrFacet` parameter is not specified, an immediate parent will be returned, otherwise the closest ancestor with a specified facet or passing condition test.\n *\n * @param {Function|String} conditionOrFacet optional condition that component should pass (or facet name it should contain)\n * @return {Component|undefined}\n */\nfunction Component$getScopeParent(conditionOrFacet) {\n return _callGetScopeParent.call(this, _getScopeParent, conditionOrFacet);\n}\n\nfunction _callGetScopeParent(_getScopeParentFunc, conditionOrFacet) {\n check(conditionOrFacet, Match.Optional(Match.OneOf(Function, String)));\n var conditionFunc = componentUtils._makeComponentConditionFunc(conditionOrFacet);\n return _getScopeParentFunc.call(this, conditionFunc); \n}\n\nfunction _getScopeParent(conditionFunc) {\n var parent;\n try { parent = this.scope._hostObject.owner; } catch(e) {}\n\n // Where there is no parent, this function will return undefined\n // The parent component is checked recursively\n if (parent) {\n if (! conditionFunc || conditionFunc(parent) )\n return parent;\n else\n return _getScopeParent.call(parent, conditionFunc);\n }\n}\n\n\n/**\n * Component instance method\n * Returns scope parent with a given class, with same class if not specified\n *\n * @param {[Function]} ComponentClass component class that the parent should have, same class by default\n * @return {Component}\n */\nfunction Component$getScopeParentWithClass(ComponentClass) {\n ComponentClass = ComponentClass || this.constructor;\n return _getScopeParent.call(this, function(comp) {\n return comp instanceof ComponentClass;\n });\n}\n\n\n/**\n * Component instance method.\n * Returns the topmost scope parent of a component.\n * If `conditionOrFacet` parameter is not specified, the topmost scope parent will be returned, otherwise the topmost ancestor with a specified facet or passing condition test.\n *\n * @param {Function|String} conditionOrFacet optional condition that component should pass (or facet name it should contain)\n * @return {Component|undefined}\n */\nfunction Component$getTopScopeParent(conditionOrFacet) {\n return _callGetScopeParent.call(this, _getTopScopeParent, conditionOrFacet);\n}\n\nfunction _getTopScopeParent(conditionFunc) {\n var topParent\n , parent = this;\n do {\n parent = _getScopeParent.call(parent, conditionFunc);\n if (parent)\n topParent = parent;\n } while (parent);\n\n return topParent;\n}\n\n\n/**\n * Component instance method\n * Returns scope parent with a given class, with same class if not specified\n *\n * @param {[Function]} ComponentClass component class that the parent should have, same class by default\n * @return {Component}\n */\nfunction Component$getTopScopeParentWithClass(ComponentClass) {\n ComponentClass = ComponentClass || this.constructor;\n return _getTopScopeParent.call(this, function(comp) {\n return comp instanceof ComponentClass;\n });\n}\n\n\n/**\n * Component instance method\n * Finds scope parent of component using DOM tree (unlike getScopeParent that simply goes up the scope tree).\n * While getScopeParent is faster it may fail if scope chain is not setup yet (e.g., when component has been just inserted).\n * The scope property of component will be changed to point to scope object of container facet of that parent.\n * Returned scope parent of the component will be undefined (as well as component's scope property) if no parent in the DOM tree has container facet.\n * TODO Method will not bind DOM children correctly if component has no container facet.\n *\n * @return {Component}\n */\nfunction Component$setScopeParentFromDOM() {\n var parentEl = this.el.parentNode;\n\n var parent, foundParent;\n while (parentEl && ! foundParent) {\n parent = Component.getComponent(parentEl);\n foundParent = parent && parent.container;\n parentEl = parentEl.parentNode;\n }\n\n this.remove(); // remove component from its current scope (if it is defined)\n if (foundParent) {\n this.rename(undefined, false);\n parent.container.scope._add(this);\n return parent;\n } \n}\n\n\n/**\n * Walks component tree, calling provided callback on each component\n *\n * @param callback\n * @param thisArg\n */\nfunction Component$walkScopeTree(callback, thisArg) {\n callback.call(thisArg, this);\n if (!this.container) return;\n this.container.scope._each(function(component) {\n component.walkScopeTree(callback, thisArg);\n });\n}\n\n\nfunction Component$treePathOf(component) {\n return domUtils.treePathOf(this.el, component.el);\n}\n\n\nfunction Component$getComponentAtTreePath(treePath, nearest) {\n var node = domUtils.getNodeAtTreePath(this.el, treePath, nearest);\n return Component.getComponent(node);\n}\n\n\nfunction Component$insertAtTreePath(treePath, component, nearest) {\n var wasInserted = domUtils.insertAtTreePath(this.el, treePath, component.el);\n if (wasInserted) component.setScopeParentFromDOM();\n return wasInserted;\n}\n\n\n/**\n * Broadcast message to component and to all its scope children\n *\n * @param {String|RegExp} msg message to be sent\n * @param {[Any]} data optional message data\n * @param {[Function]} callback optional callback\n * @param {[Boolean]} synchronously if it should use postMessageSync\n */\nfunction Component$broadcast(msg, data, callback, synchronously) {\n var postMethod = synchronously ? 'postMessageSync' : 'postMessage';\n this.walkScopeTree(function(component) {\n component[postMethod](msg, data, callback);\n });\n}\n\n\n/**\n * Destroy component: removes component from DOM, removes it from scope, deletes all references to DOM nodes and unsubscribes from all messages both component and all facets\n */\nfunction Component$destroy(quiet) {\n if (this._destroyed) {\n if (!quiet) logger.warn('Component destroy: component is already destroyed');\n return;\n }\n this.remove(false, quiet);\n this.allFacets('destroy');\n this[MESSENGER_PROPERTY].destroy();\n if (this.el) {\n domUtils.detachComponent(this.el);\n domUtils.removeElement(this.el);\n delete this.el;\n }\n this.componentInfo.destroy();\n this._destroyed = true;\n}\n\n\n/**\n * Returns true if component was destroyed\n *\n * @return {Boolean}\n */\nfunction Component$isDestroyed() {\n return this._destroyed;\n}\n",
+ "'use strict';\n\n/**\n * `milo.Component.Facet`\n *\n * The class fot the facet of component. When a component is created, it\n * creates all its facets.\n *\n * See Facets section on information about available facets and on\n * how to create new facets classes.\n *\n * - Component - basic compponent class\n * - ComponentFacet - basic\n */\n\nvar Facet = require('../abstract/facet')\n , miloCore = require('milo-core')\n , Messenger = miloCore.Messenger\n , componentUtils = require('./c_utils')\n , _ = miloCore.proto;\n\nvar ComponentFacet = _.createSubclass(Facet, 'ComponentFacet');\n\nmodule.exports = ComponentFacet;\n\n\n/**\n * postDomParent\n *\n * If facet has DOM parent facet (see `domParent` method), posts the message to this facet.\n *\n * @param {String} messageType\n * @param {Object} messageData\n */\nvar postDomParent = _.partial(_postParent, domParent);\n\n/**\n * postScopeParent\n *\n * If facet has scope parent facet (see `scopeParent` method), posts the message to this facet.\n *\n * @param {String} messageType\n * @param {Object} messageData\n */\nvar postScopeParent = _.partial(_postParent, scopeParent);\n\n\n_.extendProto(ComponentFacet, {\n init: ComponentFacet$init,\n start: ComponentFacet$start,\n check: ComponentFacet$check,\n destroy: ComponentFacet$destroy,\n onConfigMessages: ComponentFacet$onConfigMessages,\n domParent: domParent,\n postDomParent: postDomParent,\n scopeParent: scopeParent,\n postScopeParent: postScopeParent,\n getMessageSource: getMessageSource,\n dispatchSourceMessage: dispatchSourceMessage,\n _createMessenger: _createMessenger,\n _setMessageSource: _setMessageSource,\n _createMessageSource: _createMessageSource,\n _createMessageSourceWithAPI: _createMessageSourceWithAPI\n});\n\n_.extend(ComponentFacet, {\n requiresFacet: requiresFacet\n});\n\n\n/**\n * Expose Messenger methods on Facet prototype\n */\nvar MESSENGER_PROPERTY = '_messenger';\nMessenger.useWith(ComponentFacet, MESSENGER_PROPERTY, Messenger.defaultMethods);\n\n\n// initComponentFacet\nfunction ComponentFacet$init() {\n this._createMessenger();\n}\n\n\n// some subclasses (e.g. ModelFacet) overrride this method and do not create their own messenger\nfunction _createMessenger(){\n _.defineProperty(this, MESSENGER_PROPERTY, new Messenger(this));\n}\n\n\n// startComponentFacet\nfunction ComponentFacet$start() {\n if (this.config.messages)\n this.onConfigMessages(this.config.messages);\n}\n\n\nfunction ComponentFacet$onConfigMessages(messageSubscribers) {\n var notYetRegisteredMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {\n var subscriberType = typeof subscriber;\n if (subscriberType == 'function')\n return this.on(messages, subscriber);\n\n if (subscriberType == 'object') {\n var contextType = typeof subscriber.context;\n if (contextType == 'object')\n return this.on(messages, subscriber);\n\n if (contextType == 'string') {\n if (subscriber.context == this.name || subscriber.context == 'facet')\n subscriber = {\n subscriber: subscriber.subscriber,\n context: this\n };\n else if (subscriber.context == 'owner')\n subscriber = {\n subscriber: subscriber.subscriber,\n context: this.owner\n };\n else\n throw new Error('unknown subscriber context in configuration: ' + subscriber.context);\n\n return this.on(messages, subscriber);\n }\n\n throw new Error('unknown subscriber context type in configuration: ' + contextType);\n }\n\n throw new Error('unknown subscriber type in configuration: ' + subscriberType);\n }, this);\n\n return notYetRegisteredMap;\n}\n\n\n// checkDependencies\nfunction ComponentFacet$check() {\n if (this.require) {\n this.require.forEach(function(reqFacet) {\n if (! this.owner.hasFacet(reqFacet))\n this.owner.addFacet(reqFacet);\n }, this);\n }\n}\n\n\n// destroys facet\nfunction ComponentFacet$destroy() {\n if (this[MESSENGER_PROPERTY]) this[MESSENGER_PROPERTY].destroy();\n this._destroyed = true;\n}\n\n\n/**\n * domParent\n *\n * @return {ComponentFacet} reference to the facet of the same class of the closest parent DOM element, that has a component with the same facet class attached to it. If such element doesn't exist method will return undefined.\n */\nfunction domParent() {\n var parentComponent = componentUtils.getContainingComponent(this.owner.el, false, this.name);\n return parentComponent && parentComponent[this.name];\n}\n\n\n/**\n * scopeParent\n *\n * @return {ComponentFacet} reference to the facet of the same class as `this` facet of the closest scope parent (i.e., the component that has the scope of the current component in its container facet).\n */\nfunction scopeParent() {\n var parentComponent = this.owner.getScopeParent(this.name);\n return parentComponent && parentComponent[this.name];\n}\n\n\nfunction _postParent(getParentMethod, messageType, messageData) {\n var parentFacet = getParentMethod.call(this);\n if (parentFacet)\n parentFacet.postMessage(messageType, messageData);\n}\n\n\nfunction _setMessageSource(messageSource) {\n this[MESSENGER_PROPERTY]._setMessageSource(messageSource);\n}\n\n\nfunction getMessageSource() {\n return this[MESSENGER_PROPERTY].getMessageSource();\n}\n\n\nfunction dispatchSourceMessage(message, data) {\n return this.getMessageSource().dispatchMessage(message, data);\n}\n\n\nfunction _createMessageSource(MessageSourceClass, options) {\n var messageSource = new MessageSourceClass(this, undefined, undefined, this.owner, options);\n this._setMessageSource(messageSource)\n\n _.defineProperty(this, '_messageSource', messageSource);\n}\n\n\nfunction _createMessageSourceWithAPI(MessageSourceClass, messengerAPIOrClass, options) {\n var messageSource = new MessageSourceClass(this, undefined, messengerAPIOrClass, this.owner, options);\n this._setMessageSource(messageSource)\n\n _.defineProperty(this, '_messageSource', messageSource);\n}\n\n\nfunction requiresFacet(facetName) {\n // 'this' refers to the Facet Class\n var facetRequire = this.prototype.require;\n\n return facetRequire && (facetRequire.indexOf(_.firstUpperCase(facetName)) >= 0\n || facetRequire.indexOf(_.firstLowerCase(facetName)) >= 0);\n}\n",
+ "'use strict';\n\n\nvar ComponentFacet = require('../c_facet')\n , miloBinder = require('../../binder')\n , Scope = require('../scope')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , logger = miloCore.util.logger\n , facetsRegistry = require('./cf_registry')\n , domUtils = require('../../util/dom');\n\n\n/**\n * `milo.registry.facets.get('Container')`\n * A special component facet that makes component create its own inner scope.\n * When [milo.binder](../../binder.js.html) binds DOM tree and creates components, if components are inside component WITH Container facet, they are put on the `scope` of it (component.container.scope - see [Scope](../scope.js.html)), otherwise they are put on the same scope even though they may be deeper in DOM tree.\n * It allows creating namespaces avoiding components names conflicts, at the same time creating more shallow components tree than the DOM tree.\n * To create components for elements inside the current component use:\n * ```\n * component.container.binder();\n * ```\n * See [milo.binder](../../binder.js.html)\n */\nvar Container = _.createSubclass(ComponentFacet, 'Container');\n\n\n/**\n * ####Container facet instance methods####\n *\n * - [binder](#Container$binder) - create components from DOM inside the current one\n */\n_.extendProto(Container, {\n start: Container$start,\n path: Container$path,\n getState: Container$getState,\n setState: Container$setState,\n binder: Container$binder,\n destroy: Container$destroy,\n unwrap: Container$unwrap,\n\n append: Container$append,\n insertBefore: Container$insertBefore,\n remove: Container$remove\n});\n\nfacetsRegistry.add(Container);\n\nmodule.exports = Container;\n\n\n/**\n * Container instance method.\n * Scans DOM, creates components and adds to scope children of component element.\n */\nfunction Container$binder() {\n return miloBinder(this.owner.el, this.scope, false);\n}\n\n\n/**\n * Container instance method.\n * Setup empty scope object on start\n */\nfunction Container$start() {\n ComponentFacet.prototype.start.apply(this, arguments);\n this.scope = new Scope(this.owner.el, this);\n}\n\n\nvar allowedNamePattern = /^[A-Za-z][A-Za-z0-9\\_\\$]*$/;\n/**\n * Container instance method.\n * Safely traverses component scope\n * Returns component in scope for a given path\n * If path is invalid the method will throw, if there is no component at a given path or some of the components along the path does not have Container facet the method will return undefined, \n * \n * @param {String} path path of child component in scope, each name should be prefixed with '.', e.g.: '.child.subchild'\n * @return {Component}\n */\nfunction Container$path(path) {\n path = path.split('.');\n var len = path.length;\n if (path[0] || len < 2) throwInvalidPath();\n var comp = this.owner;\n for (var i = 1; i < len; i++) {\n var name = path[i];\n if (!allowedNamePattern.test(name)) throwInvalidPath();\n if (!comp.container) return;\n comp = comp.container.scope[name];\n if (!comp) return;\n }\n return comp;\n\n function throwInvalidPath() {\n throw new Error('path ' + path + ' is invalid');\n }\n}\n\n\n/**\n * Container instance method\n * Called by `Component.prototype.getState` to get facet's state\n * Returns the state of components in the scope\n *\n * @param {Boolean} deepCopy true by default\n * @return {Object}\n */\nfunction Container$getState(deepCopy) {\n var state = { scope: {} };\n if (deepCopy !== false)\n this.scope._each(function(component, compName) {\n state.scope[compName] = component._getState();\n });\n return state;\n}\n\n\n/**\n * Container instance method\n * Called by `Component.prototype.setState` to set facet's state\n * Sets the state of components in the scope\n *\n * @param {Object} data data to set on facet's model\n */\nfunction Container$setState(state) {\n _.eachKey(state.scope, function(compData, compName) {\n var component = this.scope[compName];\n if (component)\n component.setState(compData);\n else\n logger.warn('component \"' + compName + '\" does not exist on scope');\n }, this);\n}\n\nfunction Container$destroy() {\n this.scope._each(function(component) {\n component.destroy();\n });\n this.scope._detachElement();\n ComponentFacet.prototype.destroy.apply(this, arguments);\n}\n\n\n/**\n * Container instance method\n * Moves all of the contents of the owner into the parent scope\n * \n * @param {Boolean} renameChildren pass false to not rename scope children (default is true)\n * @param {Boolean} destroy If not false, the component will be destroyed at the end (default is true).\n */\nfunction Container$unwrap(renameChildren, destroy) {\n domUtils.unwrapElement(this.owner.el);\n this.scope && this.scope._each(function (child) {\n child.remove();\n if (renameChildren !== false) child.rename(undefined, false);\n this.owner.scope && this.owner.scope._add(child);\n }, this);\n if (destroy !== false) this.owner.destroy();\n}\n\n\n/**\n * Container instance method\n * Append component to DOM and to scope\n * @param {Component} comp component that will be appended\n */\nfunction Container$append(comp) {\n this.scope._add(comp);\n this.owner.el.appendChild(comp.el);\n}\n\n\n/**\n * Container instance method\n * Insert component to DOM and to scope before another component\n * @param {Component} comp component that will be inserted\n * @param {Component} sibling component before which component will be appended\n */\nfunction Container$insertBefore(comp, sibling) {\n this.scope._add(comp);\n this.el.insertBefore(comp.el, sibling && sibling.el);\n}\n\nfunction Container$remove(comp) {\n this.scope._remove(comp);\n this.owner.el.removeChild(comp.el);\n}\n",
+ "'use strict';\n\nvar miloCore = require('milo-core')\n , Mixin = miloCore.classes.Mixin\n , ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n\n , Messenger = miloCore.Messenger\n , DOMEventsSource = require('../msg_src/dom_events')\n , DataMsgAPI = require('../msg_api/data')\n , getElementDataAccess = require('../msg_api/de_data')\n , Model = miloCore.Model\n , pathUtils = Model._utils.path\n , modelUtils = Model._utils.model\n , changeDataHandler = Model._utils.changeDataHandler\n , getTransactionFlag = changeDataHandler.getTransactionFlag\n , setTransactionFlag = changeDataHandler.setTransactionFlag\n , postTransactionFinished = changeDataHandler.postTransactionFinished\n\n , _ = miloCore.proto\n , logger = miloCore.util.logger;\n\n\n/**\n * `milo.registry.facets.get('Data')`\n * Facet to give access to DOM data\n */\nvar Data = _.createSubclass(ComponentFacet, 'Data');\n\n\n/**\n * Data facet instance methods\n *\n * - [start](#Data$start) - start Data facet\n * - [get](#Data$get) - get DOM data from DOM tree\n * - [set](#Data$set) - set DOM data to DOM tree\n * - [path](#Data$path) - get reference to Data facet by path\n */\n_.extendProto(Data, {\n start: Data$start,\n getState: Data$getState,\n setState: Data$setState,\n\n get: Data$get,\n set: Data$set,\n del: Data$del,\n splice: Data$splice,\n len: Data$len,\n path: Data$path,\n getPath: Data$getPath,\n getKey: Data$getKey,\n\n _get: Data$_get,\n _set: Data$_set,\n _del: Data$_del,\n _splice: Data$_splice,\n _len: Data$_len,\n\n _setScalarValue: Data$_setScalarValue,\n _getScalarValue: Data$_getScalarValue,\n _bubbleUpDataChange: Data$_bubbleUpDataChange,\n _queueDataChange: Data$_queueDataChange,\n _postDataChanges: Data$_postDataChanges,\n _prepareMessageSource: _prepareMessageSource\n});\n\nfacetsRegistry.add(Data);\n\nmodule.exports = Data;\n\n\n/**\n * ModelPath methods added to Data prototype\n */\n['push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {\n var method = Model.Path.prototype[methodName];\n _.defineProperty(Data.prototype, methodName, method);\n});\n\n\n\n// these methods will be wrapped to support \"*\" pattern subscriptions\nvar proxyDataSourceMethods = {\n // value: 'value',\n trigger: 'trigger'\n };\n\n\n/**\n * Data facet instance method\n * Starts Data facet\n * Called by component after component is initialized.\n */\nfunction Data$start() {\n // change messenger methods to work with \"*\" subscriptions (like Model class)\n pathUtils.wrapMessengerMethods.call(this);\n\n ComponentFacet.prototype.start.apply(this, arguments);\n\n // get/set methods to set data of element\n this.elData = getElementDataAccess(this.owner.el);\n\n this._dataChangesQueue = [];\n\n this._prepareMessageSource();\n\n // store facet data path\n this._path = '.' + this.owner.name;\n\n // current value\n this._value = this.get();\n\n // prepare internal and external messengers\n // this._prepareMessengers();\n\n // subscribe to DOM event and accessors' messages\n this.onSync('', onOwnDataChange);\n\n // message to mark the end of batch on the current level\n this.onSync('datachangesfinished', onDataChangesFinished);\n\n // changes in scope children with Data facet\n this.onSync('childdata', onChildData);\n\n // to enable reactive connections\n this.onSync('changedata', changeDataHandler);\n}\n\n\n/**\n * Data facet instance method\n * Create and connect internal and external messengers of Data facet.\n * External messenger's methods are proxied on the Data facet and they allows \"*\" subscriptions.\n */\n// function _prepareMessengers() {\n // Data facet will post all its changes on internal messenger\n // var internalMessenger = new Messenger(this);\n\n // message source to connect internal messenger to external\n // var internalMessengerSource = new MessengerMessageSource(this, undefined, new ModelMsgAPI, internalMessenger);\n\n // external messenger to which all model users will subscribe,\n // that will allow \"*\" subscriptions and support \"changedata\" message api.\n // var externalMessenger = new Messenger(this, Messenger.defaultMethods, internalMessengerSource);\n\n// _.defineProperties(this, {\n// _messenger: externalMessenger,\n// _internalMessenger: internalMessenger\n// });\n// }\n\n\n/**\n * Data facet instance method\n * Initializes DOMEventsSource and connects it to Data facet messenger\n *\n * @private\n */\nfunction _prepareMessageSource() {\n var dataAPI = new DataMsgAPI(this.owner)\n , dataEventsSource = new DOMEventsSource(this, proxyDataSourceMethods, dataAPI, this.owner);\n this._setMessageSource(dataEventsSource);\n\n _.defineProperty(this, '_dataEventsSource', dataEventsSource);\n\n // make value method of DataMsgAPI available on Data facet\n // this is a private method, get() should be used to get data.\n Mixin.prototype._createProxyMethod.call(dataAPI, 'value', 'value', this);\n}\n\n\n/**\n * Subscriber to data change event\n *\n * @private\n * @param {String} msgType in this instance will be ''\n * @param {Object} data data change information\n */\nfunction onOwnDataChange(msgType, data) {\n this._bubbleUpDataChange(data);\n this._queueDataChange(data);\n if (data.path === '') {\n var inTransaction = getTransactionFlag(data);\n this.postMessage('datachangesfinished', { transaction: inTransaction });\n }\n}\n\n\n/**\n * Data facet instance method\n * Sends data `message` to DOM parent\n *\n * @private\n * @param {Object} msgData data change message\n */\nfunction Data$_bubbleUpDataChange(msgData) {\n var parentData = this.scopeParent();\n\n if (parentData) {\n var parentMsg = _.clone(msgData);\n parentMsg.path = (this._path || ('.' + this.owner.name)) + parentMsg.path;\n parentData.postMessage('childdata', parentMsg || msgData);\n }\n}\n\n\n/**\n * Data facet instance method\n * Queues data messages to be dispatched to connector\n *\n * @private\n * @param {Object} change data change description\n */\nfunction Data$_queueDataChange(change) {\n this._dataChangesQueue.push(change);\n}\n\n\n/**\n * Subscriber to datachangesfinished event.\n * Calls the method to post changes batch and bubbles up the message\n *\n * @param {[type]} msg [description]\n * @param {[type]} data [description]\n */\nfunction onDataChangesFinished(msg, data) {\n this._postDataChanges(data.inTransaction);\n var parentData = this.scopeParent();\n if (parentData) parentData.postMessage('datachangesfinished', data);\n}\n\n\n/**\n * Dispatches all changes collected in the batch\n * Used for data propagation - connector subscribes to this message\n *\n * @private\n */\nfunction Data$_postDataChanges(inTransaction) {\n var queue = this._dataChangesQueue.reverse();\n this.postMessageSync('datachanges', {\n changes: queue,\n transaction: inTransaction\n });\n this._dataChangesQueue = []; // it can't be .length = 0, as the actual array may still be used\n}\n\n\n/**\n * Subscriber to data change event in child Data facet\n *\n * @private\n * @param {String} msgType\n * @param {Obejct} data data change information\n */\nfunction onChildData(msgType, data) {\n this.postMessage(data.path, data);\n this._bubbleUpDataChange(data);\n this._queueDataChange(data);\n}\n\n\n/**\n * Data facet instance method\n * Sets data in DOM hierarchy recursively.\n * Returns the object with the data actually set (can be different, if components matching some properties are missing).\n *\n * @param {Object|String|Number} value value to be set. If the value if scalar, it will be set on component's element, if the value is object - on DOM tree inside component\n * @return {Object|String|Number}\n */\nfunction Data$set(value) {\n var inTransaction = getTransactionFlag(Data$set);\n\n var componentSetter = this.config.set;\n if (typeof componentSetter == 'function') {\n var result = componentSetter.call(this.owner, value);\n return result;\n }\n\n setTransactionFlag(this._set, inTransaction);\n\n var oldValue = this._value\n , newValue = this._set(value);\n\n // this message triggers onOwnDataChange, as well as actuall DOM change\n // so the parent gets notified\n var msg = { path: '', type: 'changed',\n newValue: newValue, oldValue: oldValue };\n setTransactionFlag(msg, inTransaction);\n this.postMessage('', msg);\n\n return newValue;\n}\n\n\nfunction Data$_set(value) {\n var inTransaction = getTransactionFlag(Data$_set);\n\n var valueSet;\n if (value != null && typeof value == 'object') {\n if (Array.isArray(value)) {\n valueSet = [];\n\n var listFacet = this.owner.list;\n if (listFacet){\n var listLength = listFacet.count()\n , newItemsCount = value.length - listLength;\n if (newItemsCount >= 3) {\n listFacet._addItems(newItemsCount);\n listFacet._updateDataPaths(listLength, listFacet.count());\n }\n\n value.forEach(function(childValue, index) {\n setChildData.call(this, valueSet, childValue, index, '[$$]');\n }, this);\n\n var listCount = listFacet.count()\n , removeCount = listCount - value.length;\n\n while (removeCount-- > 0)\n listFacet._removeItem(value.length);\n } else\n logger.warn('Data: setting array data without List facet');\n } else {\n valueSet = {};\n _.eachKey(value, function(childValue, key) {\n setChildData.call(this, valueSet, childValue, key, '.$$');\n }, this);\n }\n } else\n valueSet = this._setScalarValue(value);\n\n this._value = valueSet;\n\n return valueSet;\n\n\n function setChildData(valueSet, childValue, key, pathSyntax) {\n var childPath = pathSyntax.replace('$$', key);\n var childDataFacet = this.path(childPath, typeof childValue != 'undefined');\n if (childDataFacet) {\n setTransactionFlag(childDataFacet.set, inTransaction);\n valueSet[key] = childDataFacet.set(childValue);\n }\n }\n}\n\n\n/**\n * Data facet instance method\n * Deletes component from view and scope, only in case it has Item facet on it\n *\n * @param {String|Number} value value to set to DOM element\n */\nfunction Data$del() {\n var inTransaction = getTransactionFlag(Data$del);\n\n var componentDelete = this.config.del;\n if (typeof componentDelete == 'function') {\n var result = componentDelete.call(this.owner);\n postTransactionFinished.call(this, inTransaction);\n return result;\n }\n\n var oldValue = this._value;\n\n setTransactionFlag(this._del, inTransaction);\n this._del();\n\n // this message triggers onOwnDataChange, as well as actuall DOM change\n // so the parent gets notified\n var msg = { path: '', type: 'deleted', oldValue: oldValue };\n setTransactionFlag(msg, inTransaction);\n this.postMessage('', msg);\n}\n\n\nfunction Data$_del() {\n var inTransaction = getTransactionFlag(Data$_del);\n setTransactionFlag(this._set, inTransaction);\n this._set();\n}\n\n\n/**\n * Data facet instance method\n * Sets scalar value to DOM element\n *\n * @private\n * @param {String|Number} value value to set to DOM element\n */\nfunction Data$_setScalarValue(value) {\n return this.elData.set(this.owner.el, value);\n}\n\n\n/**\n * Data facet instance method\n * Get structured data from DOM hierarchy recursively\n * Returns DOM data\n *\n * @param {Boolean} deepGet true by default\n * @return {Object}\n */\nfunction Data$get(deepGet) {\n var componentGetter = this.config.get;\n if (typeof componentGetter == 'function')\n return componentGetter.call(this.owner, deepGet);\n\n return this._get(deepGet);\n}\n\nfunction Data$_get(deepGet) {\n if (deepGet === false) // a hack to enable getting shallow state\n return;\n\n var comp = this.owner\n , scopeData;\n\n if (comp.list) {\n scopeData = [];\n comp.list.each(function(listItem, index) {\n scopeData[index] = listItem.data.get();\n });\n\n if (comp.container)\n comp.container.scope._each(function(scopeItem, name) {\n if (! comp.list.contains(scopeItem) && scopeItem.data)\n scopeData[name] = scopeItem.data.get();\n });\n } else if (comp.container) {\n scopeData = {};\n comp.container.scope._each(function(scopeItem, name) {\n if (scopeItem.data)\n scopeData[name] = scopeItem.data.get();\n });\n } else\n scopeData = this._getScalarValue();\n\n this._value = scopeData;\n\n return scopeData;\n}\n\n\n/**\n * Data facet instance method\n * Gets scalar data from DOM element\n *\n * @private\n */\nfunction Data$_getScalarValue() {\n return this.elData.get(this.owner.el);\n}\n\n\n/**\n * Data facet instance method\n * Splices List items. Requires List facet to be present on component. Works in the same way as array splice.\n * Returns data retrieved from removed items\n *\n * @param {Integer} spliceIndex index to delete/insert at\n * @param {Integer} spliceHowMany number of items to delete\n * @param {List} arguments optional items to insert\n * @return {Array}\n */\nfunction Data$splice(spliceIndex, spliceHowMany) { //, ... arguments\n var inTransaction = getTransactionFlag(Data$splice);\n var result;\n\n var componentSplice = this.config.splice;\n if (typeof componentSplice == 'function') {\n result = componentSplice.apply(this.owner, arguments);\n postTransactionFinished.call(this, inTransaction);\n return result;\n }\n\n setTransactionFlag(this._splice, inTransaction);\n result = this._splice.apply(this, arguments);\n\n if (!result) return;\n\n var msg = { path: '', type: 'splice',\n index: result.spliceIndex,\n removed: result.removed,\n addedCount: result.addedCount,\n newValue: this._value };\n setTransactionFlag(msg, inTransaction);\n this.postMessage('', msg);\n\n return result.removed;\n}\n\n\nfunction Data$_splice(spliceIndex, spliceHowMany) { //, ... arguments\n var inTransaction = getTransactionFlag(Data$_splice);\n\n var listFacet = this.owner.list;\n if (! listFacet)\n return logger.warn('Data: cannot use splice method without List facet');\n\n var removed = [];\n\n var listLength = listFacet.count();\n arguments[0] = spliceIndex =\n modelUtils.normalizeSpliceIndex(spliceIndex, listLength);\n\n if (spliceHowMany > 0 && listLength > 0) {\n for (var i = spliceIndex; i < spliceIndex + spliceHowMany; i++) {\n var item = listFacet.item(spliceIndex);\n if (item) {\n var itemData = item.data.get();\n listFacet._removeItem(spliceIndex);\n } else\n logger.warn('Data: no item for index', i);\n\n removed.push(itemData);\n }\n\n listFacet._updateDataPaths(spliceIndex, listFacet.count());\n }\n\n var added = [];\n\n var argsLen = arguments.length\n , addItems = argsLen > 2\n , addedCount = argsLen - 2;\n if (addItems) {\n listFacet._addItems(addedCount, spliceIndex);\n for (var i = 2, j = spliceIndex; i < argsLen; i++, j++) {\n var item = listFacet.item(j);\n if (item) {\n setTransactionFlag(item.data.set, inTransaction);\n var itemData = item.data.set(arguments[i]);\n } else\n logger.warn('Data: no item for index', j);\n\n added.push(itemData);\n }\n\n // change paths of items that were added and items after them\n listFacet._updateDataPaths(spliceIndex, listFacet.count());\n }\n\n // if (Array.isArray(this._value)) {\n // _.prependArray(added, [spliceIndex, spliceHowMany]);\n // Array.prototype.splice.apply(this._value, added);\n // } else\n this._value = this.get();\n\n return {\n spliceIndex: spliceIndex,\n removed: removed,\n addedCount: addItems ? addedCount : 0\n };\n}\n\n\nfunction Data$len() {\n var componentLen = this.config.len;\n if (typeof componentLen == 'function')\n return componentLen.call(this.owner);\n else\n return this._len();\n}\n\n\nfunction Data$_len() {\n if (this.owner.list) return this.owner.list.count();\n else logger.error('Data: len called without list facet');\n}\n\n\n/**\n * Data facet instance method\n * Returns data facet of a child component (by scopes) corresponding to the path\n * @param {String} accessPath data access path\n */\nfunction Data$path(accessPath, createItem) {\n // createItem = true; // this hack seems to be no longer needed...\n\n if (! accessPath)\n return this;\n\n var parsedPath = pathUtils.parseAccessPath(accessPath);\n var currentComponent = this.owner;\n\n for (var i = 0, len = parsedPath.length; i < len; i++) {\n var pathNode = parsedPath[i]\n , nodeKey = pathUtils.getPathNodeKey(pathNode);\n if (pathNode.syntax == 'array' && currentComponent.list) {\n var itemComponent = currentComponent.list.item(nodeKey);\n if (! itemComponent && createItem !== false) {\n itemComponent = currentComponent.list._addItem(nodeKey);\n itemComponent.data._path = pathNode.property;\n }\n currentComponent = itemComponent;\n } else if (currentComponent.container)\n currentComponent = currentComponent.container.scope[nodeKey];\n\n var currentDataFacet = currentComponent && currentComponent.data;\n if (! currentDataFacet)\n break;\n }\n\n return currentDataFacet;\n}\n\n\n/**\n * Data facet instance method\n * Returns path to access this data facet from parent (using path method)\n *\n * @return {String}\n */\nfunction Data$getPath() {\n return this._path;\n}\n\n\n/**\n * Data facet instance method\n * Returns key to access the value related to this data facet on the value related to parent data facet.\n * If component has List facet, returns index\n *\n * @return {String|Integer}\n */\nfunction Data$getKey() {\n var path = this._path;\n return path[0] == '['\n ? +path.slice(1, -1) // remove \"[\" and \"]\"\n : path.slice(1) // remove leading \".\"\n}\n\n\n/**\n * Data facet instance method\n * Called by `Component.prototype.getState` to get facet's state\n * Returns DOM data\n *\n * @param {Boolean} deepState, true by default\n * @return {Object}\n */\nfunction Data$getState(deepState) {\n return { state: this.get(deepState) };\n}\n\n\n/**\n * Data facet instance method\n * Called by `Component.prototype.setState` to set facet's state\n * Simply sets model data\n *\n * @param {Object} state data to set on facet's model\n */\nfunction Data$setState(state) {\n return this.set(state.state);\n}\n",
+ "'use strict';\n\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry') \n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match\n , doT = miloCore.util.doT\n , binder = require('../../binder')\n , BindAttribute = require('../../attributes/a_bind')\n , domUtils = require('../../util/dom')\n , config = require('../../config');\n\n\n/**\n * `milo.registry.facets.get('Dom')`\n * Facet with component related dom utils\n */\nvar Dom = _.createSubclass(ComponentFacet, 'Dom');\n\n_.extend(Dom, {\n createElement: Dom$$createElement\n});\n\n\n/**\n * Facet class method\n * Creates an element from a passed configuation object\n * \n * @param {Object} config with the properties `domConfig`, `content`, `template`\n * @return {Element} an html element \n */\nfunction Dom$$createElement(config) {\n var domConfig = config.domConfig || {}\n , tagName = domConfig.tagName || 'div'\n , newEl = document.createElement(tagName)\n , content = config.content\n , template = config.template;\n\n // TODO it will be called again when/if component is instantiated\n // Should be someproperty on element to indicate it's been called?\n _applyConfigToElement(newEl, domConfig);\n\n if (typeof content == 'string') {\n if (template)\n newEl.innerHTML = doT.template(template)({content: content});\n else\n newEl.innerHTML = content;\n }\n return newEl;\n}\n\n\nfunction _applyConfigToElement(el, config) {\n var cssClasses = config && config.cls\n , configAttributes = config && config.attributes;\n\n if (configAttributes)\n _.eachKey(configAttributes, function(attrValue, attrName) {\n el.setAttribute(attrName, attrValue);\n });\n\n if (cssClasses)\n _attachCssClasses(el, 'add', cssClasses);\n}\n\n\n_.extendProto(Dom, {\n start: start,\n\n show: show,\n hide: hide,\n toggle: toggle,\n detach: detach,\n remove: remove,\n append: append,\n prepend: prepend,\n appendChildren: appendChildren,\n prependChildren: prependChildren,\n insertAfter: insertAfter,\n insertBefore: insertBefore,\n appendToScopeParent: appendToScopeParent,\n children: Dom$children,\n setStyle: setStyle,\n setStyles: setStyles,\n copy: copy,\n createElement: createElement,\n\n addCssClasses: _.partial(_manageCssClasses, 'add'),\n removeCssClasses: _.partial(_manageCssClasses, 'remove'),\n toggleCssClasses: _.partial(_manageCssClasses, 'toggle'),\n\n find: find,\n hasTextBeforeSelection: hasTextBeforeSelection,\n hasTextAfterSelection: hasTextAfterSelection,\n});\n\nfacetsRegistry.add(Dom);\n\nmodule.exports = Dom;\n\n\n// start Dom facet\nfunction start() {\n var el = this.owner.el;\n _applyConfigToElement(el, this.config);\n var currentStyle = window.getComputedStyle(el)\n this._visible = currentStyle && currentStyle.display != 'none';\n}\n\n// show HTML element of component\nfunction show() {\n this.toggle(true);\n}\n\n// hide HTML element of component\nfunction hide() {\n this.toggle(false);\n}\n\n// show/hide\nfunction toggle(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._visible\n : !! doShow;\n\n this._visible = doShow;\n var el = this.owner.el;\n\n el.style.display = doShow ? 'block' : 'none';\n\n return doShow;\n}\n\n\nfunction _manageCssClasses(methodName, cssClasses, enforce) {\n _attachCssClasses(this.owner.el, methodName, cssClasses, enforce);\n}\n\n\nfunction _attachCssClasses(el, methodName, cssClasses, enforce) {\n var classList = el.classList\n , doToggle = methodName == 'toggle';\n\n if (Array.isArray(cssClasses))\n cssClasses.forEach(callMethod);\n else if (typeof cssClasses == 'string')\n callMethod(cssClasses);\n else\n throw new Error('unknown type of CSS classes parameter');\n\n function callMethod(cssCls) {\n doToggle\n // Only pass 'enforce' if a value has been provided (The 'toggle' function of the classList will treat undefined === false resulting in only allowing classes to be removed)\n ? enforce === undefined ? classList[methodName](cssCls) : classList[methodName](cssCls, enforce)\n : classList[methodName](cssCls);\n }\n}\n\n\nfunction detach() {\n if (this.owner.el) \n domUtils.detachComponent(this.owner.el);\n}\n\n\nfunction setStyle(property, value) {\n if (!this.owner.el) {\n throw new Error(\"Cannot call setStyle on owner with no element: \" + this.owner.constructor.name);\n }\n this.owner.el.style[property] = value;\n}\n\nfunction setStyles(properties) {\n for (var property in properties)\n this.owner.el.style[property] = properties[property];\n}\n\n\n// create a copy of DOM element using facet config if set\nfunction copy(isDeep) {\n return this.owner.el && this.owner.el.cloneNode(isDeep);\n}\n\n\nfunction createElement() {\n var newEl = Dom.createElement(this.config);\n return newEl;\n}\n\n\n// remove HTML element of component\nfunction remove() {\n domUtils.removeElement(this.owner.el);\n}\n\n// append inside HTML element of component\nfunction append(el) {\n this.owner.el.appendChild(el);\n}\n\n// prepend inside HTML element of component\nfunction prepend(el) {\n var thisEl = this.owner.el\n , firstChild = thisEl.firstChild;\n if (firstChild)\n thisEl.insertBefore(el, firstChild);\n else\n thisEl.appendChild(el);\n}\n\n// appends children of element inside this component's element\nfunction appendChildren(el) {\n while(el.childNodes.length)\n this.append(el.childNodes[0]);\n}\n\n// prepends children of element inside this component's element\nfunction prependChildren(el) {\n while(el.childNodes.length)\n this.prepend(el.childNodes[el.childNodes.length - 1]);\n}\n\nfunction insertAfter(el) {\n var thisEl = this.owner.el\n , parent = thisEl.parentNode; \n parent.insertBefore(el, thisEl.nextSibling);\n}\n\nfunction insertBefore(el) {\n var thisEl = this.owner.el\n , parent = thisEl.parentNode;\n parent.insertBefore(el, thisEl);\n}\n\n\n// appends component's element to scope parent. If it was alredy in DOM it will be moved\nfunction appendToScopeParent() {\n var parent = this.owner.getScopeParent();\n if (parent) parent.el.appendChild(this.owner.el);\n}\n\n\n/**\n * Dom facet instance method\n * Returns the list of child elements of the component element\n *\n * @return {Array[Element]}\n */\nfunction Dom$children() {\n return domUtils.children(this.owner.el);\n}\n\n\nvar findDirections = {\n 'up': 'previousNode',\n 'down': 'nextNode'\n};\n\n// Finds component passing optional iterator's test\n// in the same scope as the current component (this)\n// by traversing DOM tree upwards (direction = \"up\")\n// or downwards (direction = \"down\")\nfunction find(direction, iterator) {\n if (! findDirections.hasOwnProperty(direction))\n throw new Error('incorrect find direction: ' + direction);\n\n var el = this.owner.el\n , scope = this.owner.scope\n , treeWalker = document.createTreeWalker(scope._rootEl, NodeFilter.SHOW_ELEMENT);\n\n treeWalker.currentNode = el;\n var nextNode = treeWalker[findDirections[direction]]()\n , componentsNames = Object.keys(scope)\n , found = false;\n\n while (nextNode) {\n var attr = new BindAttribute(nextNode);\n if (attr.node) {\n attr.parse().validate();\n if (scope.hasOwnProperty(attr.compName)) {\n var component = scope[attr.compName];\n if (! iterator || iterator(component)) {\n found = true;\n break;\n }\n }\n }\n treeWalker.currentNode = nextNode;\n nextNode = treeWalker[findDirections[direction]]();\n }\n\n if (found) return component;\n}\n\n\n// returns true if the element has text before selection\nfunction hasTextBeforeSelection() {\n var selection = window.getSelection();\n if (! selection.isCollapsed) return true;\n \n var text = selection.focusNode && selection.focusNode.textContent;\n var startPos = text && text.charAt(0) == ' ' ? 1 : 0;\n if (selection.anchorOffset != startPos) return true;\n\n // walk up the DOM tree to check if there are text nodes before cursor\n var treeWalker = document.createTreeWalker(this.owner.el, NodeFilter.SHOW_TEXT);\n treeWalker.currentNode = selection.anchorNode;\n var prevNode = treeWalker.previousNode();\n\n var isText = prevNode ? !prevNode.nodeValue.trim() == '' : false;\n\n return isText;\n}\n\n\nfunction hasTextAfterSelection() {\n var selection = window.getSelection();\n if (! selection.isCollapsed) return true;\n\n var text = selection.focusNode && selection.focusNode.textContent;\n var startPos = text && text.charAt(text.length-1) == ' ' ? selection.anchorNode.length-1 : selection.anchorNode.length;\n if (selection.anchorOffset < startPos) return true;\n\n // walk up the DOM tree to check if there are text nodes after cursor\n var treeWalker = document.createTreeWalker(this.owner.el, NodeFilter.SHOW_TEXT);\n treeWalker.currentNode = selection.anchorNode;\n var nextNode = treeWalker.nextNode();\n \n //To capture when treewalker gives us an empty text node (unknown reason)\n var isText = nextNode ? !nextNode.nodeValue.trim() == '' : false;\n\n return isText;\n}\n",
+ "'use strict';\n\n// \n// ###drag facet\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , DOMEventsSource = require('../msg_src/dom_events')\n , Component = require('../c_class')\n , DragDrop = require('../../util/dragdrop')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , logger = miloCore.util.logger;\n\n\n/**\n * `milo.registry.facets.get('Drag')`\n * Facet for components that can be dragged\n * Drag facet supports the following configuration parameters:\n *\n * - meta: object with properties\n * - params: object of key-value pairs that will be converted in url-like query string in the end of data type for metadata data type (or function that returns this object). See config.dragDrop.dataTypes.componentMetaTemplate\n * all values will converted to lowercase as datatype cannot store uppercase letters.\n * - data: data that will be stored in the above meta data type (or function)\n * - allowedEffects: string (or function) as specified here: https://developer.mozilla.org/en-US/docs/DragDrop/Drag_Operations#dragstart\n * - dataTypes: map of additional data types the component will supply to data transfer object, key is data type, value is a function that returns it, component will be passed as the context to this function\n *\n * If function is specified in any parameter it will be called with the component as the context\n */\nvar Drag = _.createSubclass(ComponentFacet, 'Drag');\n\n_.extendProto(Drag, {\n init: Drag$init,\n start: Drag$start,\n setHandle: Drag$setHandle\n});\n\nfacetsRegistry.add(Drag);\n\nmodule.exports = Drag;\n\n\nfunction Drag$init() {\n ComponentFacet.prototype.init.apply(this, arguments); \n\n this._createMessageSourceWithAPI(DOMEventsSource);\n this._dragData = {};\n\n var dataTypeInfo = this.config._dataTypeInfo || '';\n this._dataTypeInfo = typeof dataTypeInfo == 'function'\n ? dataTypeInfo\n : function() { return dataTypeInfo; };\n}\n\n\n/**\n * Drag facet instance method\n * Sets the drag handle element of component. This element has to be dragged for the component to be dragged.\n *\n * @param {Element} handleEl\n */\nfunction Drag$setHandle(handleEl) {\n if (! this.owner.el.contains(handleEl))\n return logger.warn('drag handle should be inside element to be dragged')\n this._dragHandle = handleEl;\n}\n\n\nfunction Drag$start() {\n ComponentFacet.prototype.start.apply(this, arguments);\n _addDragAttribute.call(this);\n\n this.onMessages({\n 'mousedown': onMouseDown,\n 'mouseenter mouseleave mousemove': onMouseMovement,\n 'dragstart': onDragStart,\n 'drag': onDragging,\n 'dragend': onDragEnd\n });\n\n this.owner.onMessages({\n 'getstatestarted':\n { subscriber: _removeDragAttribute, context: this },\n 'getstatecompleted':\n { subscriber: _addDragAttribute, context: this }\n });\n}\n\n\n/**\n * Adds draggable attribute to component's element\n *\n * @private\n */\nfunction _addDragAttribute() {\n if (this.owner.el)\n this.owner.el.setAttribute('draggable', true);\n}\n\n\nfunction _removeDragAttribute() {\n if (this.owner.el)\n this.owner.el.removeAttribute('draggable');\n}\n\n\nfunction onMouseDown(eventType, event) {\n this.__mouseDownTarget = event.target;\n if (targetInDragHandle.call(this)) {\n window.getSelection().empty();\n event.stopPropagation();\n }\n}\n\n\nfunction onMouseMovement(eventType, event) {\n var shouldBeDraggable = targetInDragHandle.call(this);\n this.owner.el.setAttribute('draggable', shouldBeDraggable);\n if (document.body.getAttribute('data-dragEnableEvent') != 'false')\n event.stopPropagation();\n}\n\n\nfunction onDragStart(eventType, event) {\n event.stopPropagation();\n if (this.config.off || ! targetInDragHandle.call(this)) {\n event.preventDefault();\n return;\n }\n\n var owner = this.owner;\n var dt = new DragDrop(event);\n\n this._dragData = dt.setComponentState(owner);\n setMeta.call(this);\n setAdditionalDataTypes.call(this);\n _setAllowedEffects.call(this, dt);\n\n DragDrop.service.postMessageSync('dragdropstarted', {\n eventType: 'dragstart',\n dragDrop: dt,\n dragFacet: this\n });\n\n function setMeta() {\n var metaConfig = this.config.meta\n , paramsConfig = metaConfig && metaConfig.params\n , metaDataConfig = metaConfig && metaConfig.data;\n\n var params = _.result(paramsConfig, owner)\n , data = _.result(metaDataConfig, owner);\n\n this._dragMetaDataType = dt.setComponentMeta(owner, params, data);\n this._dragMetaData = data;\n }\n\n function setAdditionalDataTypes() {\n if (this.config.dataTypes) {\n this._dataTypesData = _.mapKeys(this.config.dataTypes, function (getDataFunc, dataType) {\n var data = getDataFunc.call(this.owner, dataType);\n if (typeof data == 'object') data = JSON.stringify(data);\n if (data) dt.setData(dataType, data);\n return data;\n }, this);\n }\n }\n}\n\n\nfunction onDragging(eventType, event) {\n if (_dragIsDisabled.call(this, event)) return;\n\n var dt = new DragDrop(event);\n dt.setComponentState(this.owner, this._dragData);\n dt.setData(this._dragMetaDataType, this._dragMetaData);\n if (this._dataTypesData) {\n _.eachKey(this._dataTypesData, function(data, dataType) {\n if (data) dt.setData(dataType, data);\n });\n }\n\n _setAllowedEffects.call(this, dt);\n}\n\n\nfunction onDragEnd(eventType, event) {\n if (_dragIsDisabled.call(this, event)) return;\n\n event.stopPropagation();\n var dt = new DragDrop(event);\n DragDrop.service.postMessageSync('completedragdrop', {\n eventType: 'dragend',\n dragDrop: dt,\n dragFacet: this\n });\n}\n\n\nfunction _setAllowedEffects(DragDrop) {\n var effects = _.result(this.config.allowedEffects, this.owner);\n DragDrop.setAllowedEffects(effects);\n}\n\n\nfunction targetInDragHandle() {\n return ! this._dragHandle || this._dragHandle.contains(this.__mouseDownTarget);\n}\n\n\nfunction _dragIsDisabled(event) {\n if (this.config.off) {\n event.preventDefault();\n return true;\n }\n return false;\n}\n",
+ "'use strict';\n\n// \n// ###drop facet\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , DOMEventsSource = require('../msg_src/dom_events')\n , DropMsgAPI = require('../msg_api/drop')\n , DragDrop = require('../../util/dragdrop')\n , _ = require('milo-core').proto;\n\n/**\n * `milo.registry.facets.get('Drop')`\n * Facet for components that can accept drops\n * Drop facet supports the following configuration parameters:\n *\n * - allow - an object that will define allowed data types during drag (`dragenter` and `dragover` events) with these properties:\n * - components: `true` by default (all components will be accepted)\n * OR string with allowed component class\n * OR list of allowed components classes (strings)\n * OR map with allowed classes in keys and `true`/test functions in values\n * OR test function that will be passed object defined below\n * OR `false` to NOT accept components\n * - dataTypes: `false` by default (no other data types will be accepted)\n * OR string with allowed data type\n * OR list of additional data types that a drop target would accept\n * OR test function that will be passed DragDrop object\n * OR `true` to accept all data types\n * - checkParent: `false` by default\n * OR `true` will call parent component drop allow to check if parent component will accept the component\n * If test functions are used, they should return boolean. Each test function can also set drop effect as defined here:\n * https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer#dropEffect.28.29\n * Setting drop effect that is not allowed by dragged object will prevent drop.\n * Test functions for components will be passed the owner of Drop facet as context, the object with the following possible properties as the first parameter:\n * compClass - name of component class as stored in registry\n * compName - name of component (all lowercase)\n * params - parameters as encoded in dataType, passed to `milo.util.dragDrop.setComponentMeta` by Drag facet\n * metaDataType - data type of the data that has compClass, compName and params encoded\n *\n * ... and DragDrop instance as the second parameter\n *\n * Test function for other data types will be passed the owner of Drop facet as context and DragDrop instance as the first parameter\n *\n * ####Events####\n *\n * In addition to configuring allowed components and data types, components classes should subscribe to events.\n * At the very least, they should subscribe to `drop` event.\n *\n * Drop facet emits dragin/dragout messages that are emitted whenever actual component element is entered or left\n * (which is different from dragenter and dragleave messages that are emitted whenever any child element is entered or left, as long as event bubbles up)\n * If child component has drop facet attached, dragout will be emitted on the current component when the child is entered.\n *\n * You can see the demonstration of when messages are emitted [here](http://jsbin.com/buqov/6)\n * \n */\nvar Drop = _.createSubclass(ComponentFacet, 'Drop');\n\n\n_.extendProto(Drop, {\n init: Drop$init,\n start: Drop$start\n // _reattach: _reattachEventsOnElementChange\n});\n\nfacetsRegistry.add(Drop);\n\nmodule.exports = Drop;\n\n\nfunction Drop$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n this._createMessageSourceWithAPI(DOMEventsSource, new DropMsgAPI);\n}\n\n\nfunction Drop$start() {\n ComponentFacet.prototype.start.apply(this, arguments);\n this.owner.el.classList.add('cc-module-relative');\n this.onMessages({\n 'dragenter dragover': onDragging,\n 'drop': onDrop,\n 'dragenter dragover dragleave drop dragin dragout': postToService\n });\n}\n\n\nfunction onDragging(eventType, event) {\n var dt = new DragDrop(event);\n\n event.stopPropagation();\n event.preventDefault();\n\n if (! _handleDropDependency.call(this, dt))\n dt.setDropEffect('none');\n}\n\n\nfunction onDrop(eventType, event) {\n event.stopPropagation();\n var dt = new DragDrop(event);\n DragDrop.service.postMessageSync('dragdropcompleted', {\n eventType: 'drop',\n dragDrop: dt,\n dropFacet: this,\n component: this.owner\n });\n}\n\n\nfunction postToService(eventType, event) {\n DragDrop.service.postMessageSync(eventType, {\n event: event,\n dropFacet: this,\n component: this.owner\n });\n}\n\n\nvar _handleDropDependency = _.throttle(_handleDropDependencyNothrottle, 50);\nfunction _handleDropDependencyNothrottle(dt, originalDropComponent) {\n var allow = this.config.allow\n , parentAllowed = true;\n\n originalDropComponent = originalDropComponent || this.owner;\n\n if (allow && allow.checkParent) {\n var parent = this.owner.getScopeParent('Drop');\n if (parent)\n parentAllowed = _handleDropDependencyNothrottle.call(parent.drop, dt, originalDropComponent);\n }\n\n return parentAllowed && _isDropAllowed.call(this, dt, originalDropComponent);\n}\n\n\n/**\n * Checks if drop is allowed based on facet configuration (see above)\n * \n * @param {DragDrop} dt\n * @return {Boolean}\n */\nfunction _isDropAllowed(dt, originalDropComponent) {\n var allow = this.config.allow;\n\n if (dt.isComponent()) {\n var allowComps = allow && allow.components\n , meta = dt.getComponentMeta();\n\n switch (typeof allowComps) {\n case 'undefined':\n return true;\n case 'boolean':\n return allowComps;\n // component class\n case 'string':\n return meta && meta.compClass == allowComps;\n // test function\n case 'function':\n return allowComps.call(this.owner, meta, dt, originalDropComponent);\n case 'object':\n if (Array.isArray(allowComps))\n // list of allowed classes\n return allowComps.indexOf(meta && meta.compClass) >= 0;\n else {\n // map of class: boolean|test function\n var test = allowComps[meta && meta.compClass];\n return !! _.result(test, this.owner, meta, dt);\n }\n default:\n throw new Error('Incorrect allowed components in config');\n }\n } else {\n var dataTypes = allow && allow.dataTypes\n switch (typeof dataTypes) {\n case 'undefined':\n return false;\n case 'string':\n return dt.types.indexOf(dataTypes) >= 0;\n }\n }\n\n // TODO test for other data types\n}\n",
+ "'use strict';\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , miloCore = require('milo-core')\n , Messenger = miloCore.Messenger\n , DOMEventsSource = require('../msg_src/dom_events')\n , _ = miloCore.proto;\n\n\n/**\n * `milo.registry.facets.get('Events')`\n * Component facet that manages subscriptions to DOM events using [Messenger](../../messenger/index.js.html) with [DOMEventsSource](../msg_src/dom_events.js.html).\n * All public methods of Messenger and `trigger` method of [DOMEventsSource](../msg_src/dom_events.js.html) are proxied directly to this facet.\n * For example, to subscribe to `click` event use:\n * ```\n * component.frame.on('click', function() {\n * // ...\n * });\n * ```\n * See [Messenger](../../messenger/index.js.html)\n */\nvar Events = _.createSubclass(ComponentFacet, 'Events');\n\n\n/**\n * ####Events facet instance methods####\n *\n * - [init](#Events$init) - called by constructor automatically\n */\n_.extendProto(Events, {\n init: Events$init\n // _reattach: _reattachEventsOnElementChange\n});\n\nfacetsRegistry.add(Events);\n\nmodule.exports = Events;\n\n\n/**\n * Expose DOMEventsSource trigger method on Events prototype\n */\nvar MSG_SOURCE_KEY = '_domEventsSource'\nDOMEventsSource.useWith(Events, MSG_SOURCE_KEY, ['trigger']);\n\n\n/**\n * Events facet instance method\n * Initialzes facet, connects DOMEventsSource to facet's messenger\n */\nfunction Events$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n\n var domEventsSource = new DOMEventsSource(this, undefined, undefined, this.owner);\n this._setMessageSource(domEventsSource);\n _.defineProperty(this, MSG_SOURCE_KEY, domEventsSource);\n}\n",
+ "'use strict';\n\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , miloCore = require('milo-core')\n , Messenger = miloCore.Messenger\n , FrameMessageSource = require('../msg_src/frame')\n , domEventsConstructors = require('../../services/de_constrs')\n , _ = miloCore.proto;\n\n\n/**\n * `milo.registry.facets.get('Frame')`\n * Component facet that simplifies sending window messages to iframe and subscribing to messages on inner window of iframe.\n * All public methods of Messenger and `trigger` method of [FrameMessageSource](../msg_src/frame.js.html) are proxied directly to this facet.\n * For example, to send custom message to iframe window use:\n * ```\n * iframeComponent.frame.trigger('mymessage', myData);\n * ```\n * To subscribe to this messages inside frame use (with milo - see [milo.mail](../../mail/index.js.html)):\n * ```\n * milo.mail.on('message:mymessage', function(msgType, msgData) {\n * // data is inside of window message data\n * // msgType == 'message:mymessage'\n * var myData = msgData.data;\n * // ... app logic here\n * });\n * ```\n * or without milo:\n * ```\n * window.attachEventListener('message', function(message) {\n * var msgType = message.type; // e.g., 'mymessage'\n * var myData = message.data;\n * // ... message routing and code here\n * });\n * ```\n * Milo does routing based on sent message type automatically.\n * See [Messenger](../../messenger/index.js.html) and [milo.mail](../../mail/index.js.html).\n */\n var Frame = _.createSubclass(ComponentFacet, 'Frame');\n\n\n/**\n * Calls passed function when frame DOM becomes ready. If already ready calls immediately\n */\nvar Frame$whenReady = _makeWhenReadyFunc(Frame$isReady, 'domready');\n\n/**\n * Calls passed function when frame milo becomes ready. If already ready calls immediately\n */\nvar Frame$whenMiloReady = _makeWhenReadyFunc(Frame$isMiloReady, 'message:miloready');\n\n\n/**\n * ####Events facet instance methods####\n *\n * - [init](#Frame$init) - called by constructor automatically\n */\n_.extendProto(Frame, {\n init: Frame$init,\n start: Frame$start,\n destroy: Frame$destroy,\n getWindow: Frame$getWindow,\n isReady: Frame$isReady,\n whenReady: Frame$whenReady,\n isMiloReady: Frame$isMiloReady,\n whenMiloReady: Frame$whenMiloReady,\n milo: Frame$milo\n // _reattach: _reattachEventsOnElementChange\n});\n\n\nfacetsRegistry.add(Frame);\n\nmodule.exports = Frame;\n\n\n/**\n * Expose FrameMessageSource trigger method on Events prototype\n */\nvar MSG_SOURCE_KEY = '_messageSource';\nFrameMessageSource.useWith(Frame, MSG_SOURCE_KEY, ['trigger']);\n\n\n/**\n * Frame facet instance method\n * Initialzes facet, connects FrameMessageSource to facet's messenger\n */\nfunction Frame$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n \n var messageSource = new FrameMessageSource(this, undefined, undefined, this.owner);\n this._setMessageSource(messageSource);\n\n _.defineProperty(this, MSG_SOURCE_KEY, messageSource);\n}\n\n\n/**\n * Frame facet instance method\n * Emits frameloaded event when ready.\n */\nfunction Frame$start() {\n ComponentFacet.prototype.start.apply(this, arguments);\n var self = this;\n milo(postDomReady);\n\n function postDomReady(event) {\n self.postMessage('domready', event);\n }\n}\n\n\nfunction Frame$destroy() {\n ComponentFacet.prototype.destroy.apply(this, arguments);\n}\n\n\n/**\n * Frame facet instance method\n * Retrieves the internal window of the frame \n *\n * @param {Window}\n */\nfunction Frame$getWindow() {\n return this.owner.el.contentWindow;\n}\n\n\n/**\n * Frame facet instance method\n * Returns document.readyState if frame doument state is 'interactive' or 'complete', false otherwise\n *\n * @return {String|Boolean}\n */\nfunction Frame$isReady() {\n var readyState = this.getWindow().document.readyState;\n return readyState != 'loading' ? readyState : false;\n}\n\n\n/**\n * Frame facet instance method\n * Returns true if milo is loaded and has finished initializing inside the frame\n *\n * @return {Boolean}\n */\nfunction Frame$isMiloReady() {\n var frameMilo = this.getWindow().milo;\n return this.isReady() && frameMilo && frameMilo.milo_version;\n}\n\n\n/**\n * Gives access to milo in the frame (assuming it is loaded there)\n * Calls function when both milo and DOM are ready if function is passed.\n * Returns the reference to milo inside the frame if the window is already available.\n * \n * @param {Function} func function to be called when milo and DOM are ready in the frame\n * @return {Function} reference to milo in the frame \n */\nfunction Frame$milo(func) {\n if (typeof func == 'function') {\n var self = this;\n this.whenMiloReady(function() {\n self.getWindow().milo(func)\n });\n }\n var win = this.getWindow();\n return win && win.milo;\n}\n\n\nfunction _makeWhenReadyFunc(isReadyFunc, event) {\n return function Frame_whenReadyFunc(func) { // , arguments\n var self = this\n , args = _.slice(arguments, 1);\n if (isReadyFunc.call(this))\n callFunc();\n else\n this.on(event, callFunc);\n\n function callFunc() {\n func.apply(self, args);\n }\n }\n}\n",
+ "'use strict';\n\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , miloCore = require('milo-core')\n , Model = miloCore.Model\n , _ = miloCore.proto\n , miloMail = require('../../services/mail');\n\n\nvar ItemFacet = _.createSubclass(ComponentFacet, 'Item');\n\n_.extendProto(ItemFacet, {\n getState: ItemFacet$getState,\n setState: ItemFacet$setState,\n getIndex: ItemFacet$getIndex,\n setIndex: ItemFacet$setIndex,\n removeItem: ItemFacet$removeItem,\n extractItem: ItemFacet$extractItem,\n require: ['Container', 'Dom', 'Data']\n});\n\nfacetsRegistry.add(ItemFacet);\n\nmodule.exports = ItemFacet;\n\n\nfunction ItemFacet$getState() {\n return { state: {\n index: this.getIndex()\n }};\n}\n\n\nfunction ItemFacet$setState(state) {\n this.setIndex(state.state.index);\n}\n\n\n/**\n * Facet instance method\n * Returns the index of the owner component in it's parent list component\n * @return {Integer} The index\n */\nfunction ItemFacet$getIndex() {\n return this.index;\n}\n\n\n/**\n * Facet instance method\n * Sets the index of this component\n * @param {Integer} index The index to be set\n */\nfunction ItemFacet$setIndex(index) {\n this.index = index;\n}\n\n\n/**\n * ItemFacet instance method\n * Removes component from the list, component gets destroyed\n */\nfunction ItemFacet$removeItem() {\n // this.list and this.index are set by the list when the item is added\n this.list.removeItem(this.index);\n}\n\n\n/**\n * ItemFacet instance method\n * Removes component from the list, component is NOT destroyed\n */\nfunction ItemFacet$extractItem() {\n this.list.extractItem(this.index);\n}\n",
+ "'use strict';\n\nvar ComponentFacet = require('../c_facet')\n , Component = require('../c_class')\n , facetsRegistry = require('./cf_registry')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , miloMail = require('../../services/mail')\n , miloBinder = require('../../binder')\n , logger = miloCore.util.logger\n , doT = miloCore.util.doT\n , check = miloCore.util.check\n , Match = check.Match\n , domUtils = require('../../util/dom')\n , componentName = require('../../util/component_name')\n , miloConfig = require('../../config');\n\n\nvar LIST_SAMPLE_CSS_CLASS = 'ml-list-item-sample';\n\n/**\n * `milo.registry.facets.get('List')`\n * Facet enabling list functionality\n */\nvar List = _.createSubclass(ComponentFacet, 'List');\n\n_.extendProto(List, {\n init: List$init,\n start: List$start,\n destroy: List$destroy,\n\n require: ['Container', 'Dom', 'Data'],\n _itemPreviousComponent: _itemPreviousComponent,\n\n item: List$item,\n count: List$count,\n contains: List$contains,\n addItem: List$addItem,\n addItems: List$addItems,\n replaceItem: List$replaceItem,\n removeItem: List$removeItem,\n extractItem: List$extractItem,\n each: List$each,\n _setItem: List$_setItem,\n _removeItem: List$_removeItem,\n _addItem: List$_addItem,\n _addItems: List$_addItems,\n _createCacheTemplate: List$_createCacheTemplate,\n _updateDataPaths: List$_updateDataPaths\n});\n\nfacetsRegistry.add(List);\n\nmodule.exports = List;\n\n\n/**\n * Facet instance method\n * Initialized List facet instance and sets up item properties.\n */\nfunction List$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n var self = this;\n\n _.defineProperties(this, {\n _listItems: [],\n _listItemsHash: {}\n });\n _.defineProperty(this, 'itemSample', null, _.WRIT);\n}\n\n\n/**\n * Facet instance method\n * Starts the List facet instance, finds child with Item facet.\n */\nfunction List$start() {\n // Fired by __binder__ when all children of component are bound\n this.owner.on('childrenbound', onChildrenBound);\n}\n\n\nfunction onChildrenBound() {\n // get items already in the list\n var children = this.dom.children()\n , items = this.list._listItems\n , itemsHash = this.list._listItemsHash;\n\n children && children.forEach(function(childEl) {\n var comp = Component.getComponent(childEl);\n if (comp && comp.item) {\n items.push(comp);\n itemsHash[comp.name] = comp;\n comp.item.list = this.list;\n }\n }, this);\n\n if (items.length) {\n var foundItem = items[0];\n items.splice(0, 1);\n delete itemsHash[foundItem.name];\n items.forEach(function(item, index) {\n item.item.setIndex(index);\n });\n }\n \n // Component must have one child with an Item facet \n if (! foundItem) throw new Error('No child component has Item facet');\n\n this.list.itemSample = foundItem;\n\n // After keeping a reference to the item sample, it must be hidden and removed from scope\n foundItem.dom.hide();\n foundItem.remove(true);\n foundItem.dom.removeCssClasses(LIST_SAMPLE_CSS_CLASS);\n\n // remove references to components from sample item\n foundItem.walkScopeTree(function(comp) {\n delete comp.el[miloConfig.componentRef];\n });\n\n this.list._createCacheTemplate();\n}\n\n\nfunction List$_createCacheTemplate() {\n if (!this.itemSample) return false;\n \n var itemSample = this.itemSample;\n\n // create item template to insert many items at once\n var itemElCopy = itemSample.el.cloneNode(true);\n var attr = itemSample.componentInfo.attr;\n var attrCopy = _.clone(attr);\n attr.compName = '{{= it.componentName() }}';\n attr.el = itemElCopy;\n attr.decorate();\n\n var itemsTemplateStr = \n '{{ var i = it.count; while(i--) { }}'\n + itemElCopy.outerHTML\n + '{{ } }}';\n\n this.itemsTemplate = doT.compile(itemsTemplateStr);\n}\n\n\n/**\n * Facet instance method\n * Retrieve a particular child item by index\n * @param {Integer} index The index of the child item to get.\n * @return {Component} The component found\n */\nfunction List$item(index) {\n return this._listItems[index];\n}\n\n\n/**\n * Facet instance method\n * Gets the total number of child items\n * @return {Integer} The total\n */\nfunction List$count() {\n return this._listItems.length;\n}\n\n\nfunction List$_setItem(index, component) {\n this._listItems.splice(index, 0, component);\n this._listItemsHash[component.name] = component;\n component.item.list = this;\n component.item.setIndex(+index);\n}\n\n\n/**\n * Facet instance method\n * Returns true if a particular child item exists in the list\n * @param {Component} component The component to look for.\n * @return {Boolean}\n */\nfunction List$contains(component) {\n return this._listItemsHash[component.name] == component;\n}\n\n\n/**\n * Facet instance method\n * Adds a new child component at a particular index and returns the new component.\n * This method uses data facet, so notification will be emitted on data facet.\n * @param {Integer} index The index to add at\n * @return {Component} The newly created component\n */\nfunction List$addItem(index, itemData) {\n index = index || this.count();\n this.owner.data.splice(index, 0, itemData || {});\n return this.item(index);\n}\n\n\n/**\n * Facet instance method\n * Adds a new child component at a particular index and returns the new component\n * @param {Integer} index The index to add at\n * @return {Component} The newly created component\n */\nfunction List$_addItem(index) {\n index = index || this.count();\n if (this.item(index))\n throw Error('attempt to create item with ID of existing item');\n\n // Copy component\n var component = Component.copy(this.itemSample, true);\n var prevComponent = this._itemPreviousComponent(index);\n\n if (!prevComponent.el.parentNode)\n return logger.warn('list item sample was removed from DOM, probably caused by wrong data. Reset list data with array');\n\n // Add it to the DOM\n prevComponent.dom.insertAfter(component.el);\n\n // Add to list items\n this._setItem(index, component);\n\n // Show the list item component\n component.el.style.display = '';\n\n _updateItemsIndexes.call(this, index + 1);\n\n return component;\n}\n\n\nfunction _updateItemsIndexes(fromIndex, toIndex) {\n fromIndex = fromIndex || 0;\n toIndex = toIndex || this.count();\n for (var i = fromIndex; i < toIndex; i++) {\n var component = this._listItems[i];\n if (component)\n component.item.setIndex(i);\n else\n logger.warn('List: no item at position', i);\n }\n}\n\n\nfunction List$addItems(count, index) { // ,... items data\n var itemsData = _.slice(arguments, 2);\n if (itemsData.length < count) \n itemsData.concat(_.repeat(count - itemsData.length, {}));\n var spliceArgs = [index, 0].concat(itemsData);\n var dataFacet = this.owner.data;\n dataFacet.splice.apply(dataFacet, spliceArgs);\n}\n\n\n/**\n * List facet instance method\n * Adds a given number of items using template rendering rather than adding elements one by one\n *\n * @param {Integer} count number of items to add\n * @param {[Integer]} index optional index of item after which to add\n */\nfunction List$_addItems(count, index) {\n check(count, Match.Integer);\n if (count < 0)\n throw new Error('can\\'t add negative number of items');\n\n if (count == 0) return;\n\n var itemsHTML = this.itemsTemplate({\n componentName: componentName,\n count: count\n });\n\n var wrapEl = document.createElement('div');\n wrapEl.innerHTML = itemsHTML;\n\n miloBinder(wrapEl, this.owner.container.scope);\n var children = domUtils.children(wrapEl);\n\n if (count != children.length)\n logger.error('number of items added is different from requested');\n\n if (children && children.length) {\n var listLength = this.count();\n var spliceIndex = index < 0\n ? 0\n : typeof index == 'undefined' || index > listLength\n ? listLength\n : index;\n\n var prevComponent = spliceIndex == 0\n ? this.itemSample\n : this._listItems[spliceIndex - 1];\n\n var frag = document.createDocumentFragment()\n , newComponents = [];\n\n children.forEach(function(el, i) {\n var component = Component.getComponent(el);\n if (! component)\n return logger.error('List: element in new items is not a component');\n newComponents.push(component);\n this._setItem(spliceIndex++, component);\n frag.appendChild(el);\n el.style.display = '';\n }, this);\n\n _updateItemsIndexes.call(this, spliceIndex);\n\n if (!prevComponent.el.parentNode)\n return logger.warn('list item sample was removed from DOM, probably caused by wrong data. Reset list data with array');\n\n // Add it to the DOM\n prevComponent.dom.insertAfter(frag);\n\n _.deferMethod(newComponents, 'forEach', function(comp) {\n comp.broadcast('stateready');\n });\n }\n}\n\n\n/**\n * List facet instance method\n * @param {Integer} index The index of the item to remove\n * @return {Array[Object]} The spliced data\n */\nfunction List$removeItem(index) {\n return this.owner.data.splice(index, 1);\n}\n\n\n/**\n * List facet instance method\n * @param {Integer} index The index of the item to extract\n * @return {Component} The extracted item\n */\nfunction List$extractItem(index) {\n var itemComp = this._removeItem(index, false);\n this._updateDataPaths(index, this.count());\n return itemComp;\n}\n\n\n/**\n * List facet instance method\n * Removes item, returns the removed item that is destroyed by default.\n * \n * @param {Number} index item index\n * @param {Boolean} doDestroyItem optional false to prevent item destruction, true by default\n * @return {Component}\n */\nfunction List$_removeItem(index, doDestroyItem) {\n var comp = this.item(index);\n\n if (! comp)\n return logger.warn('attempt to remove list item with id that does not exist');\n\n this._listItems[index] = undefined;\n delete this._listItemsHash[comp.name];\n if (doDestroyItem !== false) comp.destroy();\n else {\n comp.remove();\n comp.dom.remove();\n }\n\n this._listItems.splice(index, 1);\n _updateItemsIndexes.call(this, index);\n\n return comp;\n}\n\n\nfunction List$replaceItem(index, newItem){\n var oldItem = this.item(index);\n oldItem.dom.insertAfter(newItem.el);\n this._removeItem(index);\n this._setItem(index, newItem);\n}\n\n\n// Returns the previous item component given an index\nfunction _itemPreviousComponent(index) {\n while (index >= 0 && ! this._listItems[index])\n index--;\n\n return index >= 0\n ? this._listItems[index]\n : this.itemSample;\n}\n\n\n// toIndex is not included\n// no range checking is made\nfunction List$_updateDataPaths(fromIndex, toIndex) {\n for (var i = fromIndex; i < toIndex; i++) {\n var item = this.item(i);\n if (item)\n item.data._path = '[' + i + ']';\n else\n logger.warn('Data: no item for index', j);\n }\n}\n\n\n/**\n * Facet instance method\n * Similar to forEach method of Array, iterates each of the child items.\n * @param {Function} callback An iterator function to be called on each child item.\n * @param {[type]} thisArg Context to set `this`.\n */\nfunction List$each(callback, thisArg) {\n this._listItems.forEach(function(item, index) {\n if (item) callback.apply(this, arguments); // passes item, index to callback\n else logger.warn('List$each: item', index, 'is undefined');\n }, thisArg || this);\n}\n\n\n/**\n * Facet instance method\n * Destroys the list\n */\nfunction List$destroy() {\n if (this.itemSample) this.itemSample.destroy(true);\n ComponentFacet.prototype.destroy.apply(this, arguments);\n}\n",
+ "'use strict';\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , miloCore = require('milo-core')\n , Model = miloCore.Model\n , Mixin = miloCore.classes.Mixin\n , _ = miloCore.proto;\n\n\n// generic drag handler, should be overridden\nvar ModelFacet = _.createSubclass(ComponentFacet, 'Model');\n\n_.extendProto(ModelFacet, {\n init: ModelFacet$init,\n getState: ModelFacet$getState,\n setState: ModelFacet$setState,\n _createMessenger: ModelFacet$_createMessenger,\n destroy: ModelFacet$destroy\n});\n\nfacetsRegistry.add(ModelFacet);\n\nmodule.exports = ModelFacet;\n\n\n/**\n * Expose Model class methods on ModelFacet\n */\nModel.useWith(ModelFacet, 'm');\n\n\nfunction ModelFacet$init() {\n this.m = new Model(this.config.data, this);\n ComponentFacet.prototype.init.apply(this, arguments);\n // this.m.proxyMethods(this); // Creates model's methods directly on facet\n}\n\n\n/**\n * ModelFacet instance method\n * Called by `Component.prototype.getState` to get facet's state\n * Simply returns model data\n *\n * @return {Object}\n */\nfunction ModelFacet$getState() {\n var modelValue = this.m.get();\n if (typeof modelValue == 'object')\n modelValue = _.deepClone(modelValue);\n return { state: modelValue };\n}\n\n\n/**\n * ModelFacet instance method\n * Called by `Component.prototype.setState` to set facet's state\n * Simply sets model data\n *\n * @param {Object} state data to set on facet's model\n */\nfunction ModelFacet$setState(state) {\n return this.m.set(state.state);\n}\n\n\nfunction ModelFacet$_createMessenger() { // Called by inherited init\n this._messenger = this.m._messenger;\n}\n\n\nfunction ModelFacet$destroy() {\n this.m.destroy();\n ComponentFacet.prototype.destroy.apply(this, arguments);\n}\n",
+ "'use strict';\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , miloCore = require('milo-core')\n , Model = miloCore.Model\n , _ = miloCore.proto;\n\n\n// generic drag handler, should be overridden\nvar Options = _.createSubclass(ComponentFacet, 'Options');\n\n_.extendProto(Options, {\n init: Options$init,\n destroy: Options$destroy,\n _createMessenger: Options$_createMessenger\n});\n\nfacetsRegistry.add(Options);\n\nmodule.exports = Options;\n\n\nfunction Options$init() {\n this.m = new Model(this.config.options, this);\n ComponentFacet.prototype.init.apply(this, arguments);\n this.m.proxyMethods(this); // Creates model's methods directly on facet\n}\n\n\nfunction Options$_createMessenger() { // Called by inherited init\n this._messenger = this.m._messenger;\n}\n\n\nfunction Options$destroy() {\n this.m.destroy();\n ComponentFacet.prototype.destroy.apply(this, arguments);\n}\n",
+ "'use strict';\n\n// \n// ###template facet\n\n// simplifies rendering of component element from template.\n// Any templating enging can be used that supports template compilation\n// (or you can mock this compilation easily by creating closure storing\n// template string in case your engine doesn't support compilation).\n// By default milo uses [doT](), the most versatile, conscise and at the\n// same time the fastest templating engine.\n// If you use milo in browser, it is the part of milo bundle and available\n// as global variable `doT`.\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , logger = miloCore.util.logger\n , Match = check.Match\n , binder = require('../../binder');\n\n\n// data model connection facet\nvar Template = _.createSubclass(ComponentFacet, 'Template');\n\n_.extendProto(Template, {\n init: Template$init,\n start: Template$start,\n set: Template$set,\n getCompiled: Template$getCompiled,\n render: Template$render,\n binder: Template$binder\n\n // _reattach: _reattachEventsOnElementChange\n});\n\nfacetsRegistry.add(Template);\n\nmodule.exports = Template;\n\n\nfunction Template$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n\n // templates are interpolated with default (doT) or configured engine (this.config.compile)\n // unless this.config.interpolate is false\n var compile = this.config.interpolate === false\n ? undefined\n : this.config.compile || milo.config.template.compile;\n\n this.set(this.config.template || '', compile, this.config.compileOptions);\n}\n\n\nfunction Template$start() {\n ComponentFacet.prototype.start.apply(this, arguments);\n if (this.config.autoRender) {\n this.render();\n if (this.config.autoBinder)\n this.binder();\n }\n}\n\n\nfunction Template$getCompiled() {\n return this._template;\n}\n\n\nfunction Template$set(templateStr, compile, compileOptions) {\n check(templateStr, Match.OneOf(String, Function));\n check(compile, Match.Optional(Function));\n\n if (typeof templateStr == 'function')\n this._template = templateStr;\n else {\n this._templateStr = templateStr;\n if (compile)\n this._compile = compile;\n else\n compile = this._compile;\n\n if (compile)\n this._template = compile(templateStr, compileOptions);\n }\n\n return this;\n}\n\n\nfunction Template$render(data) { // we need data only if use templating engine\n this.owner.el.innerHTML = this._template\n ? this._template(data)\n : this._templateStr;\n\n return this;\n}\n\n\nfunction Template$binder() {\n if (this.owner.container)\n return this.owner.container.binder();\n else\n logger.error('TemplateFacet: Binder called without container facet.');\n}\n",
+ "'use strict';\n\nvar ComponentFacet = require('../c_facet')\n , facetsRegistry = require('./cf_registry')\n , _ = require('milo-core').proto;\n\n\n/**\n * Transfer facet is designed for components to be able to represent other components\n * If a [Component](../c_class.js.html) has Transfer facet, when `Component.getState` is called for this componet it returns previously saved data, possibly from another component.\n * For example, a list of documents can use this facet so that each item in the list can store actual document component on it.\n */\nvar Transfer = _.createSubclass(ComponentFacet, 'Transfer');\n\n_.extendProto(Transfer, {\n init: Transfer$init,\n getState: Transfer$getState,\n setState: Transfer$setState,\n setActiveState: Transfer$setActiveState,\n setStateWithKey: Transfer$setStateWithKey,\n getStateWithKey: Transfer$getStateWithKey,\n getComponentMeta: Transfer$getComponentMeta\n});\n\nfacetsRegistry.add(Transfer);\n\nmodule.exports = Transfer;\n\n\nfunction Transfer$init() {\n ComponentFacet.prototype.init.apply(this, arguments);\n this._activeState = '';\n this._defaultKey = '';\n this._state = {};\n}\n\n\n/**\n * Transfer facet instance method\n * Returns transfer state for component. Can be obtained from another component by using `Component.getState`\n *\n * @return {Object}\n */\nfunction Transfer$getState() {\n return this._state[this._activeState] || this._state[this._defaultKey];\n}\n\n\n/**\n * Transfer facet instance method\n * Sets transfer state for component. Can be obtained from another component by using `Component.getState`\n *\n * @param {Object} state\n */\nfunction Transfer$setState(state) {\n this._state[''] = state;\n this.setActiveState('');\n}\n\n/**\n * Transfer facet instance method\n * Sets the active state (used by getState)\n * @param {[type]} key [description]\n */\nfunction Transfer$setActiveState(key) {\n this._activeState = key;\n}\n\n/**\n * Transfer facet instance method\n * Sets transfer state for component without default key. Can be obtained from another component by using `Component.getState`\n * When the active state is set to the expected key\n * @param {[type]} key [description]\n * @param {[type]} state [description]\n * @param {Boolean} isDefaultKey (Optional)\n */\nfunction Transfer$setStateWithKey(key, state, isDefaultKey) {\n if (!key) throw new Error('Transfer$setStateWithKey: no key');\n\n if (isDefaultKey)\n this._defaultKey = key;\n else\n this._defaultKey = this._defaultKey || key;\n\n this._state[key] = state;\n this.setActiveState(key);\n}\n\n\nfunction Transfer$getStateWithKey(key) {\n return typeof key == 'string' && this._state[key];\n}\n\n\nfunction Transfer$getComponentMeta() {\n var state = this.getState();\n return {\n compName: state && state.compName,\n compClass: state && state.compClass\n };\n}\n",
"'use strict';\n\nvar ClassRegistry = require('../../abstract/registry')\n , ComponentFacet = require('../c_facet');\n\n\n/**\n * `milo.registry.facets`\n * Component facets registry. An instance of [ClassRegistry](../../abstract/registry.js.html) class that is used by milo to register and find facets.\n */\n var facetsRegistry = new ClassRegistry(ComponentFacet);\n\n\n// Adds common ancestor to all facets of components to the registry.\nfacetsRegistry.add(ComponentFacet);\n\nmodule.exports = facetsRegistry;\n",
- "'use strict';\n\nvar componentsRegistry = require('./c_registry')\n , facetsRegistry = require('./c_facets/cf_registry')\n , componentName = require('../util/component_name')\n , Scope = require('./scope')\n , BinderError = require('../util/error').Binder\n , logger = require('../util/logger')\n , _ = require('mol-proto');\n\n\nmodule.exports = ComponentInfo;\n\n\n/**\n * Simple class to hold information allowing to create/copy component using [`Component.create`](./c_class.js.html#create) and [`Component.copy`](./c_class.js.html#copy).\n *\n * @constructor\n * @param {Scope} scope scope object the component belogs to, usually either top level scope that will be returned by [milo.binder](../binder.js.html) or `scope` property of [Container](./c_facets/Container.js.html) facet of containing component\n * @param {Element} el DOM element the component is attached to\n * @param {BindAttribute} attr BindAttribute instance that the component was created with\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n * @return {ComponentInfo}\n */\nfunction ComponentInfo(scope, el, attr, throwOnErrors) {\n attr.parse().validate();\n\n this.scope = scope;\n this.el = el;\n this.attr = attr;\n this.name = attr.compName;\n this.ComponentClass = getComponentClass(attr, throwOnErrors);\n this.extraFacetsClasses = getComponentExtraFacets(this.ComponentClass, attr, throwOnErrors);\n\n if (this.ComponentClass\n && hasContainerFacet(this.ComponentClass, this.extraFacetsClasses)) {\n this.container = {};\n }\n}\n\n\n/**\n * ####ComponentInfo instance methods####\n * \n * - [destroy](#ComponentInfo$destroy)\n * - [rename](#ComponentInfo$rename)\n */\n_.extendProto(ComponentInfo, {\n destroy: ComponentInfo$destroy,\n rename: ComponentInfo$rename\n});\n\n\n/**\n * ComponentInfo instance method\n * Destroys ComponentInfo by removing the references to DOM element\n */\nfunction ComponentInfo$destroy() {\n delete this.el;\n this.attr.destroy();\n}\n\n\n/**\n * ComponentInfo instance method\n * Renames ComponentInfo object\n *\n * @param {[String]} name optional new component name, generated from timestamp by default\n * @param {[Boolean]} renameInScope optional false to not rename ComponentInfo object in its scope, true by default\n */\nfunction ComponentInfo$rename(name, renameInScope) {\n name = name || componentName();\n Scope.rename(this, name, renameInScope);\n this.attr.compName = name;\n this.attr.decorate();\n}\n\n\nfunction getComponentClass(attr, throwOnErrors) {\n var ComponentClass = componentsRegistry.get(attr.compClass);\n if (! ComponentClass)\n reportBinderError(throwOnErrors, 'class ' + attr.compClass + ' is not registered');\n return ComponentClass;\n}\n\n\nfunction getComponentExtraFacets(ComponentClass, attr, throwOnErrors) {\n var facets = attr.compFacets\n , extraFacetsClasses = {};\n\n if (Array.isArray(facets))\n facets.forEach(function(fctName) {\n fctName = _.firstUpperCase(fctName);\n if (ComponentClass.hasFacet(fctName))\n reportBinderError(throwOnErrors, 'class ' + ComponentClass.name\n + ' already has facet ' + fctName);\n if (extraFacetsClasses[fctName])\n reportBinderError(throwOnErrors, 'component ' + attr.compName\n + ' already has facet ' + fctName);\n var FacetClass = facetsRegistry.get(fctName);\n extraFacetsClasses[fctName] = FacetClass;\n });\n\n return extraFacetsClasses;\n}\n\n\nfunction reportBinderError(throwOnErrors, message) {\n if (throwOnErrors === false)\n logger.error('ComponentInfo binder error:', message);\n else\n throw new BinderError(message);\n};\n\n\nfunction hasContainerFacet(ComponentClass, extraFacetsClasses) {\n return (ComponentClass.hasFacet('container')\n || 'Container' in extraFacetsClasses\n || _.someKey(extraFacetsClasses, facetRequiresContainer)\n || classHasFacetThatRequiresContainer());\n\n function classHasFacetThatRequiresContainer() {\n return (ComponentClass.prototype.facetsClasses\n && _.someKey(ComponentClass.prototype.facetsClasses, facetRequiresContainer))\n }\n\n function facetRequiresContainer(FacetClass) {\n return FacetClass.requiresFacet('container');\n }\n}\n",
+ "'use strict';\n\nvar componentsRegistry = require('./c_registry')\n , facetsRegistry = require('./c_facets/cf_registry')\n , componentName = require('../util/component_name')\n , Scope = require('./scope')\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , _ = miloCore.proto;\n\n\nmodule.exports = ComponentInfo;\n\n\n/**\n * Simple class to hold information allowing to create/copy component using [`Component.create`](./c_class.js.html#create) and [`Component.copy`](./c_class.js.html#copy).\n *\n * @constructor\n * @param {Scope} scope scope object the component belogs to, usually either top level scope that will be returned by [milo.binder](../binder.js.html) or `scope` property of [Container](./c_facets/Container.js.html) facet of containing component\n * @param {Element} el DOM element the component is attached to\n * @param {BindAttribute} attr BindAttribute instance that the component was created with\n * @param {Boolean} throwOnErrors If set to false, then errors will only be logged to console. True by default.\n * @return {ComponentInfo}\n */\nfunction ComponentInfo(scope, el, attr, throwOnErrors) {\n attr.parse().validate();\n\n this.scope = scope;\n this.el = el;\n this.attr = attr;\n this.name = attr.compName;\n this.ComponentClass = getComponentClass(attr, throwOnErrors);\n this.extraFacetsClasses = getComponentExtraFacets(this.ComponentClass, attr, throwOnErrors);\n\n if (this.ComponentClass\n && hasContainerFacet(this.ComponentClass, this.extraFacetsClasses)) {\n this.container = {};\n }\n}\n\n\n/**\n * ####ComponentInfo instance methods####\n * \n * - [destroy](#ComponentInfo$destroy)\n * - [rename](#ComponentInfo$rename)\n */\n_.extendProto(ComponentInfo, {\n destroy: ComponentInfo$destroy,\n rename: ComponentInfo$rename\n});\n\n\n/**\n * ComponentInfo instance method\n * Destroys ComponentInfo by removing the references to DOM element\n */\nfunction ComponentInfo$destroy() {\n delete this.el;\n this.attr.destroy();\n}\n\n\n/**\n * ComponentInfo instance method\n * Renames ComponentInfo object\n *\n * @param {[String]} name optional new component name, generated from timestamp by default\n * @param {[Boolean]} renameInScope optional false to not rename ComponentInfo object in its scope, true by default\n */\nfunction ComponentInfo$rename(name, renameInScope) {\n name = name || componentName();\n Scope.rename(this, name, renameInScope);\n this.attr.compName = name;\n this.attr.decorate();\n}\n\n\nfunction getComponentClass(attr, throwOnErrors) {\n var ComponentClass = componentsRegistry.get(attr.compClass);\n if (! ComponentClass)\n reportBinderError(throwOnErrors, 'class ' + attr.compClass + ' is not registered');\n return ComponentClass;\n}\n\n\nfunction getComponentExtraFacets(ComponentClass, attr, throwOnErrors) {\n var facets = attr.compFacets\n , extraFacetsClasses = {};\n\n if (Array.isArray(facets))\n facets.forEach(function(fctName) {\n fctName = _.firstUpperCase(fctName);\n if (ComponentClass.hasFacet(fctName))\n reportBinderError(throwOnErrors, 'class ' + ComponentClass.name\n + ' already has facet ' + fctName);\n if (extraFacetsClasses[fctName])\n reportBinderError(throwOnErrors, 'component ' + attr.compName\n + ' already has facet ' + fctName);\n var FacetClass = facetsRegistry.get(fctName);\n extraFacetsClasses[fctName] = FacetClass;\n });\n\n return extraFacetsClasses;\n}\n\n\nfunction reportBinderError(throwOnErrors, message) {\n if (throwOnErrors === false)\n logger.error('ComponentInfo binder error:', message);\n else\n throw new Error(message);\n};\n\n\nfunction hasContainerFacet(ComponentClass, extraFacetsClasses) {\n return (ComponentClass.hasFacet('container')\n || 'Container' in extraFacetsClasses\n || _.someKey(extraFacetsClasses, facetRequiresContainer)\n || classHasFacetThatRequiresContainer());\n\n function classHasFacetThatRequiresContainer() {\n return (ComponentClass.prototype.facetsClasses\n && _.someKey(ComponentClass.prototype.facetsClasses, facetRequiresContainer))\n }\n\n function facetRequiresContainer(FacetClass) {\n return FacetClass.requiresFacet('container');\n }\n}\n",
"'use strict';\n\nvar ClassRegistry = require('../abstract/registry')\n , Component = require('./c_class');\n\n/**\n * `milo.registry.components`\n * An instance of [ClassRegistry](../abstract/registry.js.html) class that is used by milo to register and find components.\n */\nvar componentsRegistry = new ClassRegistry(Component);\n\n// add common ancestor to all components to the registry.\ncomponentsRegistry.add(Component);\n\nmodule.exports = componentsRegistry;\n",
- "'use strict';\n\nvar config = require('../config')\n , check = require('../util/check')\n , Match = check.Match;\n\n\nvar componentUtils = module.exports = {\n isComponent: isComponent,\n getComponent: getComponent,\n getContainingComponent: getContainingComponent,\n _makeComponentConditionFunc: _makeComponentConditionFunc\n};\n\n\n/**\n * isComponent\n *\n * Checks if element has a component attached to it by\n * checking the presence of property difined in milo.config\n *\n * @param {Element} el DOM element\n * @return {Boolean} true, if it has milo component attached to it\n */\nfunction isComponent(el) {\n return el.hasOwnProperty(config.componentRef);\n}\n\n\n/**\n * getComponent\n *\n * @param {Element} el DOM element\n * @return {Component} component attached to element\n */\nfunction getComponent(el) {\n return el && el[config.componentRef];\n}\n\n\n/**\n * Returns the closest component which contains the specified element,\n * optionally, only component that passes `condition` test or contains specified facet\n *\n * Unless `returnCurrent` parameter is false, the function will return\n * the current component of the element (true by default).\n *\n * @param {Node} node DOM Element or text Node\n * @param {Boolean} returnCurrent optional boolean value indicating whether the component of the element can be returned. True by default, should be false to return only ancestors.\n * @param {Function|String} conditionOrFacet optional condition that component should pass (or facet name it should contain)\n * @return {Component} \n */\nfunction getContainingComponent(node, returnCurrent, conditionOrFacet) {\n // check(node, Node); - can't check tiype here as it is most likely coming from another frame\n check(returnCurrent, Match.Optional(Boolean));\n check(conditionOrFacet, Match.Optional(Match.OneOf(Function, String)));\n\n var conditionFunc = _makeComponentConditionFunc(conditionOrFacet);\n\n return _getContainingComponent(node, returnCurrent, conditionFunc);\n}\n\n\nfunction _makeComponentConditionFunc(conditionOrFacet) {\n if (typeof conditionOrFacet == 'function')\n return conditionOrFacet;\n else if (typeof conditionOrFacet == 'string') {\n var facetName = _.firstLowerCase(conditionOrFacet);\n return function (comp) {\n return comp.hasFacet(facetName);\n };\n }\n}\n\n\nfunction _getContainingComponent(el, returnCurrent, conditionFunc) {\n // Where the current element is a component it should be returned\n // if returnCurrent is true or undefined\n if (returnCurrent !== false) {\n var comp = getComponent(el);\n if (comp && (! conditionFunc || conditionFunc(comp)))\n return comp;\n }\n\n // Where there is no parent element, this function will return undefined\n // The parent element is checked recursively\n if (el.parentNode)\n return _getContainingComponent(el.parentNode, true, conditionFunc);\n}\n",
+ "'use strict';\n\nvar config = require('../config')\n , miloCore = require('milo-core')\n , check = miloCore.util.check\n , Match = check.Match\n , _ = miloCore.proto;\n\n\nvar componentUtils = module.exports = {\n isComponent: isComponent,\n getComponent: getComponent,\n getContainingComponent: getContainingComponent,\n _makeComponentConditionFunc: _makeComponentConditionFunc\n};\n\n\n/**\n * isComponent\n *\n * Checks if element has a component attached to it by\n * checking the presence of property difined in milo.config\n *\n * @param {Element} el DOM element\n * @return {Boolean} true, if it has milo component attached to it\n */\nfunction isComponent(el) {\n return el.hasOwnProperty(config.componentRef);\n}\n\n\n/**\n * getComponent\n *\n * @param {Element} el DOM element\n * @return {Component} component attached to element\n */\nfunction getComponent(el) {\n return el && el[config.componentRef];\n}\n\n\n/**\n * Returns the closest component which contains the specified element,\n * optionally, only component that passes `condition` test or contains specified facet\n *\n * Unless `returnCurrent` parameter is false, the function will return\n * the current component of the element (true by default).\n *\n * @param {Node} node DOM Element or text Node\n * @param {Boolean} returnCurrent optional boolean value indicating whether the component of the element can be returned. True by default, should be false to return only ancestors.\n * @param {Function|String} conditionOrFacet optional condition that component should pass (or facet name it should contain)\n * @return {Component} \n */\nfunction getContainingComponent(node, returnCurrent, conditionOrFacet) {\n // check(node, Node); - can't check tiype here as it is most likely coming from another frame\n check(returnCurrent, Match.Optional(Boolean));\n check(conditionOrFacet, Match.Optional(Match.OneOf(Function, String)));\n\n var conditionFunc = _makeComponentConditionFunc(conditionOrFacet);\n\n return _getContainingComponent(node, returnCurrent, conditionFunc);\n}\n\n\nfunction _makeComponentConditionFunc(conditionOrFacet) {\n if (typeof conditionOrFacet == 'function')\n return conditionOrFacet;\n else if (typeof conditionOrFacet == 'string') {\n var facetName = _.firstLowerCase(conditionOrFacet);\n return function (comp) {\n return comp.hasFacet(facetName);\n };\n }\n}\n\n\nfunction _getContainingComponent(el, returnCurrent, conditionFunc) {\n // Where the current element is a component it should be returned\n // if returnCurrent is true or undefined\n if (returnCurrent !== false) {\n var comp = getComponent(el);\n if (comp && (! conditionFunc || conditionFunc(comp)))\n return comp;\n }\n\n // Where there is no parent element, this function will return undefined\n // The parent element is checked recursively\n if (el.parentNode)\n return _getContainingComponent(el.parentNode, true, conditionFunc);\n}\n",
"'use strict';\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry');\n\n\nvar View = Component.createComponentClass('View', ['container']);\n\ncomponentsRegistry.add(View);\n\nmodule.exports = View;\n",
- "'use strict';\n\n\nvar MessengerAPI = require('../../messenger/m_api')\n , getElementDataAccess = require('./de_data')\n , _ = require('mol-proto')\n , check = require('../../util/check')\n , Match = check.Match;\n\n\n// class to handle subscribtions to changes in DOM for UI (maybe also content editable) elements\n\n/**\n * A class\n */\nvar DataMsgAPI = _.createSubclass(MessengerAPI, 'DataMsgAPI', true);\n\n\n_.extendProto(DataMsgAPI, {\n // implementing MessageSource interface\n init: DataMsgAPI$init,\n translateToSourceMessage: translateToSourceMessage,\n filterSourceMessage: filterSourceMessage,\n createInternalData: createInternalData,\n\n // class specific methods\n value: DataMsgAPI$value\n});\n\nmodule.exports = DataMsgAPI;\n\n\nfunction DataMsgAPI$init(component) {\n MessengerAPI.prototype.init.apply(this, arguments);\n\n this.component = component;\n this.elData = getElementDataAccess(component.el);\n}\n\n\n// getDomElementDataValue\nfunction DataMsgAPI$value() { // value method\n var componentGetter = this.component.data.config.get;\n var newValue = typeof componentGetter == 'function'\n ? componentGetter.call(this.component)\n : this.elData.get(this.component.el);\n\n this.component.data._value = newValue;\n\n return newValue;\n}\n\n\n// TODO: this function should return relevant DOM event dependent on element tag\n// Can also implement beforedatachanged event to allow preventing the change\n// translateToDomEvent\nfunction translateToSourceMessage(message) {\n var componentEvent = this.component.data.config.event;\n var event = componentEvent || this.elData.event(this.component.el);\n\n if (message == '' && event)\n return event; // this.tagEvent;\n}\n\n\n// filterDataMessage\nfunction filterSourceMessage(sourceMessage, message, data) {\n return data.newValue != data.oldValue;\n}\n\n\nfunction createInternalData(sourceMessage, message, data) {\n var oldValue = this.component.data._value\n , newValue = this.value();\n\n var internalData = { \n path: '',\n type: 'changed',\n oldValue: oldValue,\n newValue: newValue\n };\n return internalData;\n}\n",
- "'use strict';\n\n\nvar _ = require('mol-proto');\n\n\n/**\n * Returns data access methods and events for given DOM element.\n * Used by [Data](../c_facets/Data.js.html) facet and by [DataMsgAPI](./data.js.html)\n *\n * @param {Element} el\n * @return {Object}\n */\nvar getElementDataAccess = function(el) {\n var tagName = el.tagName.toLowerCase()\n , elData = domElementsDataAccess[tagName];\n return elData || domElementsDataAccess.byDefault;\n}\n\nmodule.exports = getElementDataAccess;\n\n\n/**\n * Data access methods and events for DOM elements.\n */\nvar domElementsDataAccess = {\n byDefault: {\n property: 'innerHTML',\n },\n 'div': {\n property: 'innerHTML', // hack, should be innerHTML? to make work with Editable facet\n // event: 'input'\n },\n 'span': {\n property: 'innerHTML',\n event: 'input'\n },\n 'p': {\n property: 'innerHTML',\n event: 'input'\n },\n 'input': {\n property: inputDataProperty,\n event: inputChangeEvent\n },\n 'textarea': {\n property: 'value',\n event: 'input'\n },\n 'select': {\n property: 'value',\n event: 'change'\n },\n 'img': {\n property: 'src'\n },\n 'caption': {\n property: 'innerHTML',\n event: 'input'\n },\n 'thead': {\n property: 'innerHTML',\n event: 'input'\n },\n 'tbody': {\n property: 'innerHTML',\n event: 'input'\n },\n 'tfoot': {\n property: 'innerHTML',\n event: 'input'\n }\n};\n\n\n// convert strings to functions and create getset methods\n_.eachKey(domElementsDataAccess, function(tagInfo) {\n var property = tagInfo.property\n , event = tagInfo.event;\n if (typeof property != 'function')\n tagInfo.property = function() { return property; };\n var propFunc = tagInfo.property;\n if (typeof event != 'function')\n tagInfo.event = function() { return event; };\n if (! tagInfo.get)\n tagInfo.get = function(el) { return el[propFunc(el)]; }\n if (! tagInfo.set)\n tagInfo.set = function(el, value) {\n return (el[propFunc(el)] = typeof value == 'undefined' ? '' : value);\n }\n});\n\n\n/**\n * Types of input elements\n */\nvar inputElementTypes = {\n byDefault: {\n property: 'value',\n event: 'input'\n },\n 'checkbox': {\n property: 'checked',\n event: 'change'\n },\n 'radio': {\n property: 'checked',\n event: 'change'\n },\n 'text': {\n property: 'value',\n event: 'input'\n }\n}\n\n\n/**\n * Return property of input element to get/set its data\n *\n * @param {Element} el\n * @return {String}\n */\nfunction inputDataProperty(el) {\n var inputType = inputElementTypes[el.type];\n return inputType\n ? inputType.property\n : inputElementTypes.byDefault.property;\n}\n\n\n/**\n * Returns DOM event type to listen to to react to input element change\n *\n * @param {Element} el\n * @return {String}\n */\nfunction inputChangeEvent(el) {\n var inputType = inputElementTypes[el.type];\n return inputType\n ? inputType.event\n : inputElementTypes.byDefault.event;\n}\n",
- "'use strict';\n\n\nvar MessengerAPI = require('../../messenger/m_api')\n\n\nvar DropMsgAPI = _.createSubclass(MessengerAPI, 'DropMsgAPI', true);\n\n\n_.extendProto(DropMsgAPI, {\n // implementing MessageSource interface\n translateToSourceMessage: translateToSourceMessage,\n filterSourceMessage: filterSourceMessage,\n});\n\n\nmodule.exports = DropMsgAPI;\n\n\nvar dropEventsMap = {\n 'dragin': 'dragenter',\n 'dragout': 'dragleave'\n};\n\n\nfunction translateToSourceMessage(message) {\n return dropEventsMap.hasOwnProperty(message)\n ? dropEventsMap[message]\n : message;\n}\n\nfunction resetFilterVars() {\n delete this._currentTarget;\n delete this._inside;\n}\n\nfunction filterSourceMessage(sourceMessage, message, data) { // data is DOM event object\n var ok = true;\n\n if (sourceMessage == 'dragenter' && message == 'dragin') {\n this._currentTarget = data.target;\n ok = !this._inside;\n this._inside = true;\n } else if (sourceMessage == 'dragleave' && message == 'dragout') {\n ok = this._currentTarget == data.target;\n if (ok) resetFilterVars.call(this);\n } else if (sourceMessage == 'drop') resetFilterVars.call(this);\n\n return ok;\n}\n",
- "'use strict';\n\n\nvar DOMEmitterSource = require('../../services/dom_source')\n , MessageSource = require('../../messenger/m_source')\n , Component = require('../c_class')\n , _ = require('mol-proto')\n , check = require('../../util/check')\n , Match = check.Match;\n\nvar DOMEventsSource = _.createSubclass(DOMEmitterSource, 'DOMEventsSource', true);\n\n\n_.extendProto(DOMEventsSource, {\n init: init,\n destroy: DOMEventsSource$destroy,\n emitter: emitter\n});\n\nmodule.exports = DOMEventsSource;\n\n\nvar useCapturePattern = /__capture$/\n , useCapturePostfix = '__capture';\n\n\n// init DOM event source\nfunction init(hostObject, proxyMethods, messengerAPIOrClass, component) {\n check(component, Component);\n this.component = component;\n MessageSource.prototype.init.apply(this, arguments);\n}\n\n\nfunction DOMEventsSource$destroy() {\n MessageSource.prototype.destroy.apply(this, arguments);\n delete this.component;\n}\n\n\n// get DOM element of component\nfunction emitter() {\n return this.component.el;\n}\n",
- "'use strict';\n\n// ###component iframe source\n\nvar MessageSource = require('../../messenger/m_source')\n , Component = require('../c_class')\n , _ = require('mol-proto')\n , check = require('../../util/check')\n , logger = require('../../util/logger')\n , Match = check.Match\n , FrameMessageSourceError = require('../../util/error').FrameMessageSource;\n\nvar FrameMessageSource = _.createSubclass(MessageSource, 'FrameMessageSource', true);\n\n\n_.extendProto(FrameMessageSource, {\n // implementing MessageSource interface\n init: init,\n addSourceSubscriber: addSourceSubscriber,\n removeSourceSubscriber: removeSourceSubscriber,\n trigger: trigger,\n\n //class specific methods\n frameWindow: frameWindow,\n handleEvent: handleEvent // event dispatcher - as defined by Event DOM API\n});\n\nmodule.exports = FrameMessageSource;\n\n\nfunction init(hostObject, proxyMethods, messengerAPIOrClass, component) {\n check(component, Component);\n this.component = component;\n\n if (component.el.tagName.toLowerCase() != 'iframe')\n throw new FrameMessageSourceError('component for FrameMessageSource can only be attached to iframe element');\n\n MessageSource.prototype.init.apply(this, arguments);\n}\n\n\nfunction frameWindow() {\n return this.component.el.contentWindow;\n}\n\n\n// addIFrameMessageListener\nfunction addSourceSubscriber(sourceMessage) {\n var win = this.frameWindow();\n if (win) win.addEventListener('message', this, false);\n else logger.warn('FrameMessageSource: frame window is undefined');\n}\n\n\n// removeIFrameMessageListener\nfunction removeSourceSubscriber(sourceMessage) {\n var win = this.frameWindow();\n if (win) win.removeEventListener('message', this, false);\n else logger.warn('FrameMessageSource: frame window is undefined');\n}\n\n\nfunction trigger(msgType, data) {\n data = data || {};\n data.type = msgType;\n\n this.frameWindow().postMessage(data, '*');\n}\n\n\n// TODO maybe refactor to FrameMsgAPI?\nfunction handleEvent(event) {\n this.dispatchMessage(event.data.type, event);\n}\n",
- "'use strict';\n\nvar _ = require('mol-proto')\n , componentName = require('../util/component_name')\n , check = require('../util/check')\n , Match = check.Match\n , ScopeError = require('../util/error').Scope\n , logger = require('../util/logger');\n\n\n/**\n * Scope class.\n * @param {Element} rootEl the root element of this scope\n * @param {Object} hostObject the host \n * @return {Scope}\n */\nfunction Scope(rootEl, hostObject) {\n _.defineProperties(this, {\n _rootEl: rootEl,\n _hostObject: hostObject\n }, _.WRIT); // writable\n};\n\n_.extendProto(Scope, {\n _add: Scope$_add,\n _safeAdd: Scope$_safeAdd,\n _copy: Scope$_copy,\n _each: Scope$_each,\n _move: Scope$_move,\n _merge: Scope$_merge,\n _length: Scope$_length,\n _any: Scope$_any,\n _remove: Scope$_remove,\n _clean: Scope$_clean,\n _detachElement: Scope$_detachElement,\n _has: Scope$_has,\n _filter: Scope$_filter\n});\n\n\n_.extend(Scope, {\n rename: Scope$$rename\n});\n\n\nmodule.exports = Scope;\n\n\nvar allowedNamePattern = /^[A-Za-z][A-Za-z0-9\\_\\$]*$/;\n\n\n/**\n * Scope instance method.\n * Adds object to the scope, throwing if name is not unique\n * @param {Component|ComponentInfo} object component or component info to add to the scope\n * @param {String} name the name of the component to add\n */\nfunction Scope$_add(object, name) {\n if (typeof name == 'string')\n object.name = name;\n else\n name = object.name;\n \n if (this.hasOwnProperty(name))\n throw new ScopeError('duplicate object name: ' + name);\n\n checkName(name);\n __add.call(this, object, name);\n}\n\n\n/**\n * Scope instance method\n * Adds object to scope renaming it if name is not unique\n * @param {Component|ComponentInfo} object component or component info to add to the scope\n * @param {String} name the name of the component to add\n */\nfunction Scope$_safeAdd(object, name) {\n if (typeof name == 'string')\n object.name = name;\n else\n name = object.name;\n\n var shouldRename = this.hasOwnProperty(name);\n if (shouldRename)\n logger.error('Scope: duplicate object name: ' + name);\n else {\n shouldRename = ! allowedNamePattern.test(name);\n if (shouldRename)\n logger.error('Scope: name should start from letter, this name is not allowed: ' + name);\n }\n\n if (shouldRename) {\n name = componentName();\n object.name = name;\n }\n\n __add.call(this, object, name);\n}\n\n\nfunction __add(object, name) {\n this[name] = object;\n object.scope = this;\n\n if (typeof object.postMessage === 'function')\n object.postMessage('addedtoscope'); \n}\n\n\n/**\n * Instance method.\n * copies all objects from one scope to another,\n * throwing if some object is not unique\n * @param {Scope} aScope the scope to copy\n */\nfunction Scope$_copy(aScope) {\n check(aScope, Scope);\n\n aScope._each(Scope$_add, this);\n}\n\n\n/**\n * Instance method.\n * Moves a component from this scope to another scope.\n * @param {Component} component the component to be moved\n * @param {Scope} otherScope the scope to copy the component to\n */\nfunction Scope$_move(component, otherScope) {\n otherScope._add(component);\n this._remove(component.name);\n component.scope = otherScope;\n}\n\n\n/**\n * Instance method.\n * Merges one scope into this scope\n * @param {Scope} scope the scope to absorb\n */\nfunction Scope$_merge(scope) {\n scope._each(function (comp) {\n this._add(comp, comp.name);\n scope._remove(comp.name);\n }, this);\n}\n\n\n/**\n * Instance method.\n * Enumerates each component in the scope\n * @param {Function} callback the function to execute for each component\n * @param {Object} thisArg the context\n */\nfunction Scope$_each(callback, thisArg) {\n _.eachKey(this, callback, thisArg || this, true); // enumerates enumerable properties only\n}\n\n\n/**\n * Instance method.\n * Returns a filtered list of components based on a callback\n * @param {Function} callback the function to execute for each component\n * @param {Object} thisArg the context\n * @return {Array}\n */\nfunction Scope$_filter(callback, thisArg) {\n return _.filterKeys(this, callback, thisArg || this, true);\n}\n\n\n/**\n * Checks the validity of a name.\n * @param {Function} callback the function to execute for each component\n */\nfunction checkName(name) {\n if (! allowedNamePattern.test(name))\n throw new ScopeError('name should start from letter, this name is not allowed: ' + name);\n}\n\n\n/**\n * Instance method.\n * Returns the number of objects in the scope\n * @return {Number}\n */\nfunction Scope$_length() {\n return Object.keys(this).length;\n}\n\n\n/**\n * Instance method.\n * Returns a component from the scope. It may look like it returns the first component\n * but in reality given that scopes are hashes, there is no such thing.\n * @return {Component}\n */\nfunction Scope$_any() {\n var key = Object.keys(this)[0];\n return key && this[key];\n}\n\n\n/**\n * Instance method.\n * Removes a component from the scope by it's name.\n * @param {String} name the name of the component to remove\n * @param {Boolean} quiet optional true to suppress the warning message if the component is not in scope\n */\nfunction Scope$_remove(name, quiet) {\n if (! (name in this)) {\n if (!quiet) logger.warn('removing object that is not in scope');\n return;\n }\n\n var object = this[name];\n\n delete this[name];\n\n if (typeof object.postMessage === 'function')\n object.postMessage('removedfromscope');\n}\n\n\n/**\n * Instance method.\n * Removes all components from the scope.\n */\nfunction Scope$_clean() {\n this._each(function(object, name) {\n delete this[name].scope;\n delete this[name];\n }, this);\n}\n\nfunction Scope$_detachElement() {\n this._rootEl = null;\n}\n\n\n/**\n * Checks if scope has object by object name\n * @param {Object} object\n * @return {Boolean}\n */\nfunction Scope$_has(object) {\n return this.hasOwnProperty(object.name);\n}\n\n\n/**\n * Change object name, renaming it in scope unless renameInScope is false\n * @param {Object} obj\n * @param {String} name new name\n * @param {Boolean} renameInScope true by default\n */\nfunction Scope$$rename(obj, name, renameInScope) {\n if (obj.scope && renameInScope !== false) {\n obj.scope._remove(obj.name);\n obj.scope._add(obj, name);\n } else\n obj.name = name;\n}\n",
- "'use strict';\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry');\n\n\nvar MLButton = Component.createComponentClass('MLButton', {\n events: undefined,\n dom: {\n cls: 'ml-ui-button'\n }\n});\n\ncomponentsRegistry.add(MLButton);\n\nmodule.exports = MLButton;\n\n_.extendProto(MLButton, {\n disable: MLButton$disable,\n isDisabled: MLButton$isDisabled\n});\n\n\nfunction MLButton$disable(disable) {\n this.el.disabled = disable;\n}\n\nfunction MLButton$isDisabled() {\n return !!this.el.disabled;\n}\n\n",
- "'use strict';\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry')\n , _ = require('mol-proto');\n\n\nvar COMBO_CHANGE_MESSAGE = 'mlcombochange';\n\nvar DATALIST_TEMPLATE = '{{~ it.comboOptions :option }} \\\n \\\n {{~}}';\n\nvar MLCombo = Component.createComponentClass('MLCombo', {\n events: undefined,\n data: {\n get: MLCombo_get,\n set: MLCombo_set,\n del: MLCombo_del,\n splice: undefined,\n event: COMBO_CHANGE_MESSAGE\n },\n model: {\n messages: {\n '***': { subscriber: onOptionsChange, context: 'owner' }\n }\n },\n dom: {\n cls: 'ml-ui-datalist'\n },\n container: undefined\n});\n\ncomponentsRegistry.add(MLCombo);\n\nmodule.exports = MLCombo;\n\n\n_.extendProto(MLCombo, {\n init: MLCombo$init\n});\n\n\nfunction MLCombo$init() {\n Component.prototype.init.apply(this, arguments);\n this.on('childrenbound', onChildrenBound);\n}\n\nfunction onChildrenBound() {\n _.defineProperties(this, {\n '_comboInput': this.container.scope.input,\n '_comboList': this.container.scope.datalist\n });\n\n this._comboList.template.set(DATALIST_TEMPLATE);\n\n this._comboInput.data.on('input',\n { subscriber: dispatchChangeMessage, context: this });\n}\n\nfunction MLCombo_get() {\n if (! this._comboInput) return;\n return this._comboInput.data.get();\n}\n\nfunction MLCombo_set(value) {\n return changeComboData.call(this, 'set', value);\n}\n\nfunction MLCombo_del() {\n return changeComboData.call(this, 'del', value);\n}\n\nfunction changeComboData(method, value) {\n if (! this._comboInput) return;\n var result = this._comboInput.data[method](value);\n dispatchChangeMessage.call(this);\n return result;\n}\n\n\n// Post the data change\nfunction dispatchChangeMessage() {\n this.data.dispatchSourceMessage(COMBO_CHANGE_MESSAGE);\n}\n\nfunction onOptionsChange(msg, data) {\n this._comboList.template.render({\n comboOptions: this.model.get()\n });\n}\n",
- "'use strict';\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry')\n , _ = require('mol-proto');\n\nvar COMBO_LIST_CHANGE_MESSAGE = 'mlcombolistchange';\n\n\nvar MLComboList = Component.createComponentClass('MLComboList', {\n dom: {\n cls: 'ml-ui-combo-list'\n },\n data: {\n get: MLComboList_get,\n set: MLComboList_set,\n del: MLComboList_del,\n event: COMBO_LIST_CHANGE_MESSAGE\n },\n events: undefined,\n container: undefined,\n model: {\n messages: {\n '***': { subscriber: onItemsChange, context: 'owner'}\n }\n },\n template: {\n template: '\\\n
\\\n
\\\n \\\n \\\n
\\\n
'\n }\n});\n\n\ncomponentsRegistry.add(MLComboList);\n\nmodule.exports = MLComboList;\n\n\n_.extendProto(MLComboList, {\n init: MLComboList$init,\n setOptions: MLComboList$setOptions,\n setDataValidation: MLComboList$setDataValidation,\n toggleAddButton: MLComboList$toggleAddButton,\n destroy: MLComboList$destroy,\n setAddItemPrompt: MLComboList$setAddItemPrompt,\n clearComboInput : MLComboList$clearComboInput\n});\n\n\nfunction MLComboList$init() {\n Component.prototype.init.apply(this, arguments);\n this._dataValidation = function () {};\n this.model.set([]);\n this.once('childrenbound', onChildrenBound);\n}\n\n\nfunction MLComboList$setDataValidation(dataValidation) {\n if (typeof dataValidation == 'function')\n this._dataValidation = dataValidation;\n}\n\nfunction MLComboList$setOptions(arr) {\n this._combo.setOptions(arr);\n}\n\n\nfunction MLComboList$clearComboInput () {\n this._combo.clearComboInput();\n}\n\n/**\n * Component instance method\n * Hides add button\n * @param {Boolean} show\n */\nfunction MLComboList$toggleAddButton(show) {\n this._combo.toggleAddButton(show);\n}\n\n\nfunction MLComboList$setAddItemPrompt(prompt) {\n this._combo.setAddItemPrompt(prompt);\n}\n\n\nfunction MLComboList$destroy() {\n Component.prototype.destroy.apply(this, arguments);\n this._connector && milo.minder.destroyConnector(this._connector);\n this._connector = null;\n}\n\n\nfunction onChildrenBound() {\n this.template.render().binder();\n componentSetup.call(this);\n}\n\nfunction componentSetup() {\n _.defineProperties(this, {\n '_combo': this.container.scope.combo,\n '_list': this.container.scope.list\n });\n\n this._connector = milo.minder(this._list.model, '<<<->>>', this.model);\n this._combo.data.on('', { subscriber: onComboChange, context: this });\n this._combo.on('additem', { subscriber: onAddItem, context: this });\n}\n\nfunction onComboChange(msg, data) {\n if (data.newValue && this._dataValidation(msg, data, this._list.model.get()))\n this._list.model.push(data.newValue);\n this._combo.data.del();\n // because of supercombo listeners off you have to set _value explicitly\n this._combo.data._value = '';\n}\n\nfunction onItemsChange(msg, data) {\n this.data.dispatchSourceMessage(COMBO_LIST_CHANGE_MESSAGE);\n}\n\nfunction MLComboList_get() {\n var value = this.model.get();\n return typeof value == 'object' ? _.clone(value) : value;\n}\n\nfunction MLComboList_set(value) {\n this.model.set(value);\n}\n\nfunction MLComboList_del() {\n return this.model.set([]);\n}\n\n\nfunction onAddItem(msg, data) {\n this.postMessage('additem', data);\n this.events.postMessage('milo_combolistadditem', data);\n}\n",
- "'use strict';\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry')\n , _ = require('mol-proto');\n\nvar MLDate = Component.createComponentClass('MLDate', {\n events: undefined,\n data: {\n get: MLDate_get,\n set: MLDate_set,\n del: MLDate_del,\n },\n dom: {\n cls: 'ml-ui-date'\n }\n});\n\n_.extendProto(MLDate, {\n getMin: MLDate$getMin,\n setMin: MLDate$setMin,\n getMax: MLDate$getMax,\n setMax: MLDate$setMax\n});\n\ncomponentsRegistry.add(MLDate);\n\nmodule.exports = MLDate;\n\n\nfunction MLDate$getMin() {\n return _.date(this.el.min);\n}\n\n\nfunction MLDate$setMin(value) {\n var date = _.toDate(value);\n\n this.el.min = date ? toISO8601Format(date) : '';\n}\n\n\nfunction MLDate$getMax() {\n return _.date(this.el.max);\n}\n\n\nfunction MLDate$setMax(value) {\n var date = _.toDate(value);\n\n this.el.max = date ? toISO8601Format(date) : '';\n}\n\n\nfunction MLDate_get() {\n return _.toDate(this.el.value);\n}\n\n\nfunction MLDate_set(value) {\n var date = _.toDate(value);\n\n this.el.value = date ? toISO8601Format(date) : '';\n\n dispatchInputMessage.call(this);\n}\n\nfunction MLDate_del() {\n this.el.value = '';\n\n dispatchInputMessage.call(this);\n}\n\n\nfunction dispatchInputMessage() {\n this.data.dispatchSourceMessage('input'); // Dispatch the 'input' (usually dispatched by the underlying element) event so that the data change can be listened to\n}\n\n\nfunction toISO8601Format(date) {\n var dateArr = [\n date.getFullYear(),\n pad(date.getMonth() + 1),\n pad(date.getDate())\n ];\n\n var dateStr = dateArr.join('-');\n\n return dateStr;\n\n function pad(n) { return n < 10 ? '0' + n : n; }\n}",
+ "'use strict';\n\n\nvar getElementDataAccess = require('./de_data')\n , miloCore = require('milo-core')\n , MessengerAPI = miloCore.classes.MessengerAPI\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\n\n// class to handle subscribtions to changes in DOM for UI (maybe also content editable) elements\n\n/**\n * A class\n */\nvar DataMsgAPI = _.createSubclass(MessengerAPI, 'DataMsgAPI', true);\n\n\n_.extendProto(DataMsgAPI, {\n // implementing MessageSource interface\n init: DataMsgAPI$init,\n translateToSourceMessage: translateToSourceMessage,\n filterSourceMessage: filterSourceMessage,\n createInternalData: createInternalData,\n\n // class specific methods\n value: DataMsgAPI$value\n});\n\nmodule.exports = DataMsgAPI;\n\n\nfunction DataMsgAPI$init(component) {\n MessengerAPI.prototype.init.apply(this, arguments);\n\n this.component = component;\n this.elData = getElementDataAccess(component.el);\n}\n\n\n// getDomElementDataValue\nfunction DataMsgAPI$value() { // value method\n var componentGetter = this.component.data.config.get;\n var newValue = typeof componentGetter == 'function'\n ? componentGetter.call(this.component)\n : this.elData.get(this.component.el);\n\n this.component.data._value = newValue;\n\n return newValue;\n}\n\n\n// TODO: this function should return relevant DOM event dependent on element tag\n// Can also implement beforedatachanged event to allow preventing the change\n// translateToDomEvent\nfunction translateToSourceMessage(message) {\n var componentEvent = this.component.data.config.event;\n var event = componentEvent || this.elData.event(this.component.el);\n\n if (message == '' && event)\n return event; // this.tagEvent;\n}\n\n\n// filterDataMessage\nfunction filterSourceMessage(sourceMessage, message, data) {\n return data.newValue != data.oldValue;\n}\n\n\nfunction createInternalData(sourceMessage, message, data) {\n var oldValue = this.component.data._value\n , newValue = this.value();\n\n var internalData = { \n path: '',\n type: 'changed',\n oldValue: oldValue,\n newValue: newValue\n };\n return internalData;\n}\n",
+ "'use strict';\n\n\nvar _ = require('milo-core').proto;\n\n\n/**\n * Returns data access methods and events for given DOM element.\n * Used by [Data](../c_facets/Data.js.html) facet and by [DataMsgAPI](./data.js.html)\n *\n * @param {Element} el\n * @return {Object}\n */\nvar getElementDataAccess = function(el) {\n var tagName = el.tagName.toLowerCase()\n , elData = domElementsDataAccess[tagName];\n return elData || domElementsDataAccess.byDefault;\n}\n\nmodule.exports = getElementDataAccess;\n\n\n/**\n * Data access methods and events for DOM elements.\n */\nvar domElementsDataAccess = {\n byDefault: {\n property: 'innerHTML',\n },\n 'div': {\n property: 'innerHTML', // hack, should be innerHTML? to make work with Editable facet\n // event: 'input'\n },\n 'span': {\n property: 'innerHTML',\n event: 'input'\n },\n 'p': {\n property: 'innerHTML',\n event: 'input'\n },\n 'input': {\n property: inputDataProperty,\n event: inputChangeEvent\n },\n 'textarea': {\n property: 'value',\n event: 'input'\n },\n 'select': {\n property: 'value',\n event: 'change'\n },\n 'img': {\n property: 'src'\n },\n 'caption': {\n property: 'innerHTML',\n event: 'input'\n },\n 'thead': {\n property: 'innerHTML',\n event: 'input'\n },\n 'tbody': {\n property: 'innerHTML',\n event: 'input'\n },\n 'tfoot': {\n property: 'innerHTML',\n event: 'input'\n }\n};\n\n\n// convert strings to functions and create getset methods\n_.eachKey(domElementsDataAccess, function(tagInfo) {\n var property = tagInfo.property\n , event = tagInfo.event;\n if (typeof property != 'function')\n tagInfo.property = function() { return property; };\n var propFunc = tagInfo.property;\n if (typeof event != 'function')\n tagInfo.event = function() { return event; };\n if (! tagInfo.get)\n tagInfo.get = function(el) { return el[propFunc(el)]; }\n if (! tagInfo.set)\n tagInfo.set = function(el, value) {\n return (el[propFunc(el)] = typeof value == 'undefined' ? '' : value);\n }\n});\n\n\n/**\n * Types of input elements\n */\nvar inputElementTypes = {\n byDefault: {\n property: 'value',\n event: 'input'\n },\n 'checkbox': {\n property: 'checked',\n event: 'change'\n },\n 'radio': {\n property: 'checked',\n event: 'change'\n },\n 'text': {\n property: 'value',\n event: 'input'\n }\n}\n\n\n/**\n * Return property of input element to get/set its data\n *\n * @param {Element} el\n * @return {String}\n */\nfunction inputDataProperty(el) {\n var inputType = inputElementTypes[el.type];\n return inputType\n ? inputType.property\n : inputElementTypes.byDefault.property;\n}\n\n\n/**\n * Returns DOM event type to listen to to react to input element change\n *\n * @param {Element} el\n * @return {String}\n */\nfunction inputChangeEvent(el) {\n var inputType = inputElementTypes[el.type];\n return inputType\n ? inputType.event\n : inputElementTypes.byDefault.event;\n}\n",
+ "'use strict';\n\n\nvar MessengerAPI = require('milo-core').classes.MessengerAPI;\n\n\nvar DropMsgAPI = _.createSubclass(MessengerAPI, 'DropMsgAPI', true);\n\n\n_.extendProto(DropMsgAPI, {\n // implementing MessageSource interface\n translateToSourceMessage: translateToSourceMessage,\n filterSourceMessage: filterSourceMessage,\n});\n\n\nmodule.exports = DropMsgAPI;\n\n\nvar dropEventsMap = {\n 'dragin': 'dragenter',\n 'dragout': 'dragleave'\n};\n\n\nfunction translateToSourceMessage(message) {\n return dropEventsMap.hasOwnProperty(message)\n ? dropEventsMap[message]\n : message;\n}\n\nfunction resetFilterVars() {\n delete this._currentTarget;\n delete this._inside;\n}\n\nfunction filterSourceMessage(sourceMessage, message, data) { // data is DOM event object\n var ok = true;\n\n if (sourceMessage == 'dragenter' && message == 'dragin') {\n this._currentTarget = data.target;\n ok = !this._inside;\n this._inside = true;\n } else if (sourceMessage == 'dragleave' && message == 'dragout') {\n ok = this._currentTarget == data.target;\n if (ok) resetFilterVars.call(this);\n } else if (sourceMessage == 'drop') resetFilterVars.call(this);\n\n return ok;\n}\n",
+ "'use strict';\n\n\nvar DOMEmitterSource = require('../../services/dom_source')\n , miloCore = require('milo-core')\n , MessageSource = miloCore.classes.MessageSource\n , Component = require('../c_class')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\nvar DOMEventsSource = _.createSubclass(DOMEmitterSource, 'DOMEventsSource', true);\n\n\n_.extendProto(DOMEventsSource, {\n init: init,\n destroy: DOMEventsSource$destroy,\n emitter: emitter\n});\n\nmodule.exports = DOMEventsSource;\n\n\nvar useCapturePattern = /__capture$/\n , useCapturePostfix = '__capture';\n\n\n// init DOM event source\nfunction init(hostObject, proxyMethods, messengerAPIOrClass, component) {\n check(component, Component);\n this.component = component;\n MessageSource.prototype.init.apply(this, arguments);\n}\n\n\nfunction DOMEventsSource$destroy() {\n MessageSource.prototype.destroy.apply(this, arguments);\n delete this.component;\n}\n\n\n// get DOM element of component\nfunction emitter() {\n return this.component.el;\n}\n",
+ "'use strict';\n\n// ###component iframe source\n\nvar Component = require('../c_class')\n , miloCore = require('milo-core')\n , MessageSource = miloCore.MessageSource\n , _ = miloCore.proto\n , check = miloCore.util.check\n , logger = miloCore.util.logger\n , Match = check.Match;\n\nvar FrameMessageSource = _.createSubclass(MessageSource, 'FrameMessageSource', true);\n\n\n_.extendProto(FrameMessageSource, {\n // implementing MessageSource interface\n init: init,\n addSourceSubscriber: addSourceSubscriber,\n removeSourceSubscriber: removeSourceSubscriber,\n trigger: trigger,\n\n //class specific methods\n frameWindow: frameWindow,\n handleEvent: handleEvent // event dispatcher - as defined by Event DOM API\n});\n\nmodule.exports = FrameMessageSource;\n\n\nfunction init(hostObject, proxyMethods, messengerAPIOrClass, component) {\n check(component, Component);\n this.component = component;\n\n if (component.el.tagName.toLowerCase() != 'iframe')\n throw new Error('component for FrameMessageSource can only be attached to iframe element');\n\n MessageSource.prototype.init.apply(this, arguments);\n}\n\n\nfunction frameWindow() {\n return this.component.el.contentWindow;\n}\n\n\n// addIFrameMessageListener\nfunction addSourceSubscriber(sourceMessage) {\n var win = this.frameWindow();\n if (win) win.addEventListener('message', this, false);\n else logger.warn('FrameMessageSource: frame window is undefined');\n}\n\n\n// removeIFrameMessageListener\nfunction removeSourceSubscriber(sourceMessage) {\n var win = this.frameWindow();\n if (win) win.removeEventListener('message', this, false);\n else logger.warn('FrameMessageSource: frame window is undefined');\n}\n\n\nfunction trigger(msgType, data) {\n data = data || {};\n data.type = msgType;\n\n this.frameWindow().postMessage(data, '*');\n}\n\n\n// TODO maybe refactor to FrameMsgAPI?\nfunction handleEvent(event) {\n this.dispatchMessage(event.data.type, event);\n}\n",
+ "'use strict';\n\nvar miloCore = require('milo-core')\n , _ = miloCore.proto\n , componentName = require('../util/component_name')\n , check = miloCore.util.check\n , Match = check.Match\n , logger = miloCore.util.logger;\n\n\n/**\n * Scope class.\n * @param {Element} rootEl the root element of this scope\n * @param {Object} hostObject the host \n * @return {Scope}\n */\nfunction Scope(rootEl, hostObject) {\n _.defineProperties(this, {\n _rootEl: rootEl,\n _hostObject: hostObject\n }, _.WRIT); // writable\n};\n\n_.extendProto(Scope, {\n _add: Scope$_add,\n _safeAdd: Scope$_safeAdd,\n _copy: Scope$_copy,\n _each: Scope$_each,\n _move: Scope$_move,\n _merge: Scope$_merge,\n _length: Scope$_length,\n _any: Scope$_any,\n _remove: Scope$_remove,\n _clean: Scope$_clean,\n _detachElement: Scope$_detachElement,\n _has: Scope$_has,\n _filter: Scope$_filter\n});\n\n\n_.extend(Scope, {\n rename: Scope$$rename\n});\n\n\nmodule.exports = Scope;\n\n\nvar allowedNamePattern = /^[A-Za-z][A-Za-z0-9\\_\\$]*$/;\n\n\n/**\n * Scope instance method.\n * Adds object to the scope, throwing if name is not unique\n * @param {Component|ComponentInfo} object component or component info to add to the scope\n * @param {String} name the name of the component to add\n */\nfunction Scope$_add(object, name) {\n if (typeof name == 'string')\n object.name = name;\n else\n name = object.name;\n \n if (this.hasOwnProperty(name))\n throw new Error('duplicate object name: ' + name);\n\n checkName(name);\n __add.call(this, object, name);\n}\n\n\n/**\n * Scope instance method\n * Adds object to scope renaming it if name is not unique\n * @param {Component|ComponentInfo} object component or component info to add to the scope\n * @param {String} name the name of the component to add\n */\nfunction Scope$_safeAdd(object, name) {\n if (typeof name == 'string')\n object.name = name;\n else\n name = object.name;\n\n var shouldRename = this.hasOwnProperty(name);\n if (shouldRename)\n logger.error('Scope: duplicate object name: ' + name);\n else {\n shouldRename = ! allowedNamePattern.test(name);\n if (shouldRename)\n logger.error('Scope: name should start from letter, this name is not allowed: ' + name);\n }\n\n if (shouldRename) {\n name = componentName();\n object.name = name;\n }\n\n __add.call(this, object, name);\n}\n\n\nfunction __add(object, name) {\n this[name] = object;\n object.scope = this;\n\n if (typeof object.postMessage === 'function')\n object.postMessage('addedtoscope'); \n}\n\n\n/**\n * Instance method.\n * copies all objects from one scope to another,\n * throwing if some object is not unique\n * @param {Scope} aScope the scope to copy\n */\nfunction Scope$_copy(aScope) {\n check(aScope, Scope);\n\n aScope._each(Scope$_add, this);\n}\n\n\n/**\n * Instance method.\n * Moves a component from this scope to another scope.\n * @param {Component} component the component to be moved\n * @param {Scope} otherScope the scope to copy the component to\n */\nfunction Scope$_move(component, otherScope) {\n otherScope._add(component);\n this._remove(component.name);\n component.scope = otherScope;\n}\n\n\n/**\n * Instance method.\n * Merges one scope into this scope\n * @param {Scope} scope the scope to absorb\n */\nfunction Scope$_merge(scope) {\n scope._each(function (comp) {\n this._add(comp, comp.name);\n scope._remove(comp.name);\n }, this);\n}\n\n\n/**\n * Instance method.\n * Enumerates each component in the scope\n * @param {Function} callback the function to execute for each component\n * @param {Object} thisArg the context\n */\nfunction Scope$_each(callback, thisArg) {\n _.eachKey(this, callback, thisArg || this, true); // enumerates enumerable properties only\n}\n\n\n/**\n * Instance method.\n * Returns a filtered list of components based on a callback\n * @param {Function} callback the function to execute for each component\n * @param {Object} thisArg the context\n * @return {Array}\n */\nfunction Scope$_filter(callback, thisArg) {\n return _.filterKeys(this, callback, thisArg || this, true);\n}\n\n\n/**\n * Checks the validity of a name.\n * @param {Function} callback the function to execute for each component\n */\nfunction checkName(name) {\n if (! allowedNamePattern.test(name))\n throw new Error('name should start from letter, this name is not allowed: ' + name);\n}\n\n\n/**\n * Instance method.\n * Returns the number of objects in the scope\n * @return {Number}\n */\nfunction Scope$_length() {\n return Object.keys(this).length;\n}\n\n\n/**\n * Instance method.\n * Returns a component from the scope. It may look like it returns the first component\n * but in reality given that scopes are hashes, there is no such thing.\n * @return {Component}\n */\nfunction Scope$_any() {\n var key = Object.keys(this)[0];\n return key && this[key];\n}\n\n\n/**\n * Instance method.\n * Removes a component from the scope by it's name.\n * @param {String} name the name of the component to remove\n * @param {Boolean} quiet optional true to suppress the warning message if the component is not in scope\n */\nfunction Scope$_remove(name, quiet) {\n if (! (name in this)) {\n if (!quiet) logger.warn('removing object that is not in scope');\n return;\n }\n\n var object = this[name];\n\n delete this[name];\n\n if (typeof object.postMessage === 'function')\n object.postMessage('removedfromscope');\n}\n\n\n/**\n * Instance method.\n * Removes all components from the scope.\n */\nfunction Scope$_clean() {\n this._each(function(object, name) {\n delete this[name].scope;\n delete this[name];\n }, this);\n}\n\nfunction Scope$_detachElement() {\n this._rootEl = null;\n}\n\n\n/**\n * Checks if scope has object by object name\n * @param {Object} object\n * @return {Boolean}\n */\nfunction Scope$_has(object) {\n return this.hasOwnProperty(object.name);\n}\n\n\n/**\n * Change object name, renaming it in scope unless renameInScope is false\n * @param {Object} obj\n * @param {String} name new name\n * @param {Boolean} renameInScope true by default\n */\nfunction Scope$$rename(obj, name, renameInScope) {\n if (obj.scope && renameInScope !== false) {\n obj.scope._remove(obj.name);\n obj.scope._add(obj, name);\n } else\n obj.name = name;\n}\n",
+ "'use strict';\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry')\n , _ = require('milo-core').proto;\n\n\nvar MLButton = Component.createComponentClass('MLButton', {\n events: undefined,\n dom: {\n cls: 'ml-ui-button'\n }\n});\n\ncomponentsRegistry.add(MLButton);\n\nmodule.exports = MLButton;\n\n_.extendProto(MLButton, {\n disable: MLButton$disable,\n isDisabled: MLButton$isDisabled\n});\n\n\nfunction MLButton$disable(disable) {\n this.el.disabled = disable;\n}\n\nfunction MLButton$isDisabled() {\n return !!this.el.disabled;\n}\n\n",
+ "'use strict';\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry')\n , _ = require('milo-core').proto;\n\n\nvar COMBO_CHANGE_MESSAGE = 'mlcombochange';\n\nvar DATALIST_TEMPLATE = '{{~ it.comboOptions :option }} \\\n \\\n {{~}}';\n\nvar MLCombo = Component.createComponentClass('MLCombo', {\n events: undefined,\n data: {\n get: MLCombo_get,\n set: MLCombo_set,\n del: MLCombo_del,\n splice: undefined,\n event: COMBO_CHANGE_MESSAGE\n },\n model: {\n messages: {\n '***': { subscriber: onOptionsChange, context: 'owner' }\n }\n },\n dom: {\n cls: 'ml-ui-datalist'\n },\n container: undefined\n});\n\ncomponentsRegistry.add(MLCombo);\n\nmodule.exports = MLCombo;\n\n\n_.extendProto(MLCombo, {\n init: MLCombo$init\n});\n\n\nfunction MLCombo$init() {\n Component.prototype.init.apply(this, arguments);\n this.on('childrenbound', onChildrenBound);\n}\n\nfunction onChildrenBound() {\n _.defineProperties(this, {\n '_comboInput': this.container.scope.input,\n '_comboList': this.container.scope.datalist\n });\n\n this._comboList.template.set(DATALIST_TEMPLATE);\n\n this._comboInput.data.on('input',\n { subscriber: dispatchChangeMessage, context: this });\n}\n\nfunction MLCombo_get() {\n if (! this._comboInput) return;\n return this._comboInput.data.get();\n}\n\nfunction MLCombo_set(value) {\n return changeComboData.call(this, 'set', value);\n}\n\nfunction MLCombo_del() {\n return changeComboData.call(this, 'del', value);\n}\n\nfunction changeComboData(method, value) {\n if (! this._comboInput) return;\n var result = this._comboInput.data[method](value);\n dispatchChangeMessage.call(this);\n return result;\n}\n\n\n// Post the data change\nfunction dispatchChangeMessage() {\n this.data.dispatchSourceMessage(COMBO_CHANGE_MESSAGE);\n}\n\nfunction onOptionsChange(msg, data) {\n this._comboList.template.render({\n comboOptions: this.model.get()\n });\n}\n",
+ "'use strict';\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry')\n , _ = require('milo-core').proto;\n\nvar COMBO_LIST_CHANGE_MESSAGE = 'mlcombolistchange';\n\n\nvar MLComboList = Component.createComponentClass('MLComboList', {\n dom: {\n cls: 'ml-ui-combo-list'\n },\n data: {\n get: MLComboList_get,\n set: MLComboList_set,\n del: MLComboList_del,\n event: COMBO_LIST_CHANGE_MESSAGE\n },\n events: undefined,\n container: undefined,\n model: {\n messages: {\n '***': { subscriber: onItemsChange, context: 'owner'}\n }\n },\n template: {\n template: '\\\n
\\\n
\\\n \\\n \\\n
\\\n
'\n }\n});\n\n\ncomponentsRegistry.add(MLComboList);\n\nmodule.exports = MLComboList;\n\n\n_.extendProto(MLComboList, {\n init: MLComboList$init,\n setOptions: MLComboList$setOptions,\n setDataValidation: MLComboList$setDataValidation,\n toggleAddButton: MLComboList$toggleAddButton,\n destroy: MLComboList$destroy,\n setAddItemPrompt: MLComboList$setAddItemPrompt,\n clearComboInput : MLComboList$clearComboInput\n});\n\n\nfunction MLComboList$init() {\n Component.prototype.init.apply(this, arguments);\n this._dataValidation = function () {};\n this.model.set([]);\n this.once('childrenbound', onChildrenBound);\n}\n\n\nfunction MLComboList$setDataValidation(dataValidation) {\n if (typeof dataValidation == 'function')\n this._dataValidation = dataValidation;\n}\n\nfunction MLComboList$setOptions(arr) {\n this._combo.setOptions(arr);\n}\n\n\nfunction MLComboList$clearComboInput () {\n this._combo.clearComboInput();\n}\n\n/**\n * Component instance method\n * Hides add button\n * @param {Boolean} show\n */\nfunction MLComboList$toggleAddButton(show) {\n this._combo.toggleAddButton(show);\n}\n\n\nfunction MLComboList$setAddItemPrompt(prompt) {\n this._combo.setAddItemPrompt(prompt);\n}\n\n\nfunction MLComboList$destroy() {\n Component.prototype.destroy.apply(this, arguments);\n this._connector && milo.minder.destroyConnector(this._connector);\n this._connector = null;\n}\n\n\nfunction onChildrenBound() {\n this.template.render().binder();\n componentSetup.call(this);\n}\n\nfunction componentSetup() {\n _.defineProperties(this, {\n '_combo': this.container.scope.combo,\n '_list': this.container.scope.list\n });\n\n this._connector = milo.minder(this._list.model, '<<<->>>', this.model);\n this._combo.data.on('', { subscriber: onComboChange, context: this });\n this._combo.on('additem', { subscriber: onAddItem, context: this });\n}\n\nfunction onComboChange(msg, data) {\n if (data.newValue && this._dataValidation(msg, data, this._list.model.get()))\n this._list.model.push(data.newValue);\n this._combo.data.del();\n // because of supercombo listeners off you have to set _value explicitly\n this._combo.data._value = '';\n}\n\nfunction onItemsChange(msg, data) {\n this.data.dispatchSourceMessage(COMBO_LIST_CHANGE_MESSAGE);\n}\n\nfunction MLComboList_get() {\n var value = this.model.get();\n return typeof value == 'object' ? _.clone(value) : value;\n}\n\nfunction MLComboList_set(value) {\n this.model.set(value);\n}\n\nfunction MLComboList_del() {\n return this.model.set([]);\n}\n\n\nfunction onAddItem(msg, data) {\n this.postMessage('additem', data);\n this.events.postMessage('milo_combolistadditem', data);\n}\n",
+ "'use strict';\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry')\n , _ = require('milo-core').proto;\n\nvar MLDate = Component.createComponentClass('MLDate', {\n events: undefined,\n data: {\n get: MLDate_get,\n set: MLDate_set,\n del: MLDate_del,\n },\n dom: {\n cls: 'ml-ui-date'\n }\n});\n\n_.extendProto(MLDate, {\n getMin: MLDate$getMin,\n setMin: MLDate$setMin,\n getMax: MLDate$getMax,\n setMax: MLDate$setMax\n});\n\ncomponentsRegistry.add(MLDate);\n\nmodule.exports = MLDate;\n\n\nfunction MLDate$getMin() {\n return _.date(this.el.min);\n}\n\n\nfunction MLDate$setMin(value) {\n var date = _.toDate(value);\n\n this.el.min = date ? toISO8601Format(date) : '';\n}\n\n\nfunction MLDate$getMax() {\n return _.date(this.el.max);\n}\n\n\nfunction MLDate$setMax(value) {\n var date = _.toDate(value);\n\n this.el.max = date ? toISO8601Format(date) : '';\n}\n\n\nfunction MLDate_get() {\n return _.toDate(this.el.value);\n}\n\n\nfunction MLDate_set(value) {\n var date = _.toDate(value);\n\n this.el.value = date ? toISO8601Format(date) : '';\n\n dispatchInputMessage.call(this);\n}\n\nfunction MLDate_del() {\n this.el.value = '';\n\n dispatchInputMessage.call(this);\n}\n\n\nfunction dispatchInputMessage() {\n this.data.dispatchSourceMessage('input'); // Dispatch the 'input' (usually dispatched by the underlying element) event so that the data change can be listened to\n}\n\n\nfunction toISO8601Format(date) {\n var dateArr = [\n date.getFullYear(),\n pad(date.getMonth() + 1),\n pad(date.getDate())\n ];\n\n var dateStr = dateArr.join('-');\n\n return dateStr;\n\n function pad(n) { return n < 10 ? '0' + n : n; }\n}",
"'use strict';\n\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry');\n\n\nvar MLDropTarget = Component.createComponentClass('MLDropTarget', ['drop']);\n\n\ncomponentsRegistry.add(MLDropTarget);\n\nmodule.exports = MLDropTarget;\n",
- "'use strict';\n\nvar doT = require('dot')\n , componentsRegistry = require('../c_registry')\n , Component = require('../c_class')\n , miloCount = require('../../util/count');\n\nvar TREE_TEMPLATE = '
'\n }\n});\n\ncomponentsRegistry.add(MLDialog);\n\nmodule.exports = MLDialog;\n\n\n_.extend(MLDialog, {\n createDialog: MLDialog$$createDialog,\n openDialog: MLDialog$$openDialog,\n getOpenedDialog: MLDialog$$getOpenedDialog\n});\n\n\n_.extendProto(MLDialog, {\n openDialog: MLDialog$openDialog,\n closeDialog: MLDialog$closeDialog,\n destroy: MLDialog$destroy\n});\n\n\n/**\n * Creates and returns dialog instance. To create and open at the same time [openDialog](#MLDialog$$openDialog)\n * `options` is an object with the following properties:\n *\n * title: optional dialog title\n * html: optional dialog text as html (will take precedence over text if both text nd html are passed)\n * or\n * text: optional dialog text\n * close: optional false to prevent backdrop and esc key from closing the dialog and removing close button in top right corner\n * or true (default) to enable all close options\n * or object with properties\n * backdrop: false or true (default), close dialog when backdrop clicked\n * keyboard: false or true (default), close dialog when esc key is pressed\n * button: false or true (default), show close button in the header (won't be shown if there is no header when title is not passed)\n * buttons: optional array of buttons configurations, where each button config is an object\n * name: optional name of component, should be unique and should not be `closeBtn`, if not passed a timestamp based name will be used\n * type: button type, will determine button CSS style. Possible types are: defult, primary, success, info, warning, danger, link (map to related bootstrap button styles)\n * label: button label\n * close: optional false to prevent this button from closing dialog\n * result: string with dialog close result that will be passed to dialog subscriber as the first parameter\n * data: any value/object or function to create data that will be passed to dialog subscriber as the second parameter.\n * If function is passed it will be called with dialog as context and button options as parameter.\n *\n * If `title` is not passed, dialog will not have title section \n * If neither `text` nor `html` is passed, dialog will not have body section.\n * If `buttons` are not passed, there will only be OK button.\n *\n * When dialog is closed, the subscriber is called with reault and optional data as defined in buttons configurations.\n * If backdrop is clicked or ESC key is pressed the result will be 'dismissed'\n * If close button in the top right corner is clicked, the result will be 'closed' (default result)\n * \n * @param {Object} options dialog configuration\n * @param {Function} initialize function that is called to initialize the dialog\n */\nfunction MLDialog$$createDialog(options, initialize) {\n check(options, {\n title: Match.Optional(String),\n html: Match.Optional(String),\n text: Match.Optional(String),\n close: Match.Optional(Match.OneOf(Boolean, {\n backdrop: Match.Optional(Boolean),\n keyboard: Match.Optional(Boolean),\n button: Match.Optional(Boolean)\n })),\n buttons: Match.Optional([ {\n name: Match.Optional(String),\n type: String,\n label: String,\n close: Match.Optional(Boolean),\n result: Match.Optional(String),\n data: Match.Optional(Match.Any),\n cls: Match.Optional(String)\n } ])\n });\n\n var dialog = MLDialog.createOnElement();\n\n options = _prepareOptions(options);\n dialog._dialog = {\n options: options,\n visible: false\n };\n\n dialog.template\n .render(options)\n .binder();\n\n var dialogScope = dialog.container.scope;\n\n if (options.close.backdrop)\n dialog.events.on('click',\n { subscriber: _onBackdropClick, context: dialog });\n\n if (options.title && options.close.button)\n dialogScope.closeBtn.events.on('click',\n { subscriber: _onCloseBtnClick, context: dialog });\n\n options.buttons.forEach(function(btn) {\n var buttonSubscriber = {\n subscriber: _.partial(_dialogButtonClick, btn),\n context: dialog\n };\n dialogScope[btn.name].events.on('click', buttonSubscriber);\n });\n\n if (initialize) initialize(dialog);\n return dialog;\n}\n\n\nfunction _dialogButtonClick(button) {\n if (button.close !== false)\n _toggleDialog.call(this, false);\n\n var data = _.result(button.data, this, button);\n _dispatchResult.call(this, button.result, data);\n}\n\n\nfunction _dispatchResult(result, data) {\n var subscriber = this._dialog.subscriber;\n if (typeof subscriber == 'function')\n subscriber.call(this, result, data);\n else\n subscriber.subscriber.call(subscriber.context, result, data);\n}\n\n\nfunction _onBackdropClick(eventType, event) {\n if (event.target == this.el)\n this.closeDialog('dismissed');\n}\n\n\nfunction _onCloseBtnClick() {\n this.closeDialog('closed');\n}\n\n\nfunction _onKeyDown(event) {\n if (openedDialog\n && openedDialog._dialog.options.close.keyboard\n && event.keyCode == 27) // esc key\n openedDialog.closeDialog('dismissed');\n}\n\n\nfunction _prepareOptions(options) {\n options = _.clone(options);\n options.buttons = _.clone(options.buttons || DEFAULT_BUTTONS);\n options.buttons.forEach(function(btn) {\n btn.name = btn.name || componentName();\n });\n\n options.close = typeof options.close == 'undefined' || options.close === true\n ? _.object(CLOSE_OPTIONS, true)\n : typeof options.close == 'object'\n ? _.mapToObject(CLOSE_OPTIONS,\n function(opt) { return options.close[opt] !== false; })\n : _.object(CLOSE_OPTIONS, false);\n\n return options;\n}\n\n\n/**\n * Create and show dialog popup\n * \n * @param {Object} options object with title, text and buttons. See [createDialog](#MLDialog$$createDialog) for more information.\n * @param {Function|Object} subscriber optional subscriber function or object that is passed result and optional data. Unless context is defined, dialog will be the context.\n */\nfunction MLDialog$$openDialog(options, subscriber, initialize) {\n var dialog = MLDialog.createDialog(options, initialize);\n dialog.openDialog(subscriber);\n return dialog;\n}\n\n\n\nfunction _toggleDialog(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._dialog.visible\n : !! doShow;\n\n var addRemove = doShow ? 'add' : 'remove'\n , appendRemove = doShow ? 'appendChild' : 'removeChild';\n\n this._dialog.visible = doShow;\n\n if (doShow && ! dialogsInitialized)\n _initializeDialogs();\n\n document.body[appendRemove](this.el);\n if (backdropEl)\n document.body[appendRemove](backdropEl);\n this.dom.toggle(doShow);\n this.el.setAttribute('aria-hidden', !doShow);\n document.body.classList[addRemove]('modal-open');\n this.el.classList[addRemove]('in');\n\n openedDialog = doShow ? this : undefined;\n this.el[doShow ? 'focus' : 'blur']();\n}\n\n\nvar dialogsInitialized, backdropEl;\n\nfunction _initializeDialogs() {\n backdropEl = document.createElement('div');\n backdropEl.className = 'modal-backdrop fade in';\n document.addEventListener('keydown', _onKeyDown);\n dialogsInitialized = true;\n}\n\n\nvar openedDialog;\n\n/**\n * Opens dialog instance.\n * Subscriber object should have the same format as the subscriber for the Messenger (although Messenger is not used) - either function or object with subscriber and context properties.\n * \n * @param {Function|Object} subscriber subscriber object\n */\nfunction MLDialog$openDialog(subscriber) {\n check(subscriber, Match.OneOf(Function, { subscriber: Function, context: Match.Any }));\n\n if (openedDialog)\n return logger.warn('MLDialog openDialog: can\\'t open dialog, another dialog is already open');\n\n this._dialog.subscriber = subscriber;\n _toggleDialog.call(this, true);\n}\n\n\n/**\n * Closes dialog instance, optionally passing result and data to dialog subscriber.\n * If no result is passed, 'closed' will be passed to subscriber.\n *\n * @param {String} result dialog result, passed as the first parameter to subcsriber\n * @param {Any} data optional dialog data, passed as the second parameter to subscriber\n */\nfunction MLDialog$closeDialog(result, data) {\n if (! openedDialog)\n return logger.warn('MLDialog closeDialog: can\\'t close dialog, no dialog open');\n\n result = result || 'closed';\n\n _toggleDialog.call(this, false);\n _dispatchResult.call(this, result, data);\n}\n\n\n/**\n * Returns currently opened dialog\n *\n * @return {MLDialog}\n */\nfunction MLDialog$$getOpenedDialog() {\n return openedDialog;\n}\n\n\nfunction MLDialog$destroy() {\n document.removeEventListener('keydown', _onKeyDown);\n Component.prototype.destroy.apply(this, arguments);\n}\n",
- "'use strict';\n\nvar Component = require('../../c_class')\n , componentsRegistry = require('../../c_registry')\n , _ = require('mol-proto')\n , logger = require('../../../util/logger')\n , DOMListeners = require('../../../util/dom_listeners');\n\n\nvar TOGGLE_CSS_CLASS = 'dropdown-toggle'\n , MENU_CSS_CLASS = 'dropdown-menu';\n\n\nvar MLDropdown = Component.createComponentClass('MLDropdown', {\n events: undefined,\n dom: {\n cls: ['ml-bs-dropdown', 'dropdown']\n }\n});\n\ncomponentsRegistry.add(MLDropdown);\n\nmodule.exports = MLDropdown;\n\n\n_.extendProto(MLDropdown, {\n start: MLDropdown$start,\n destroy: MLDropdown$destroy,\n toggleMenu: MLDropdown$toggleMenu,\n showMenu: MLDropdown$showMenu,\n hideMenu: MLDropdown$hideMenu\n});\n\n\nfunction MLDropdown$start() {\n var toggleEl = this.el.querySelector('.' + TOGGLE_CSS_CLASS)\n , menuEl = this.el.querySelector('.' + MENU_CSS_CLASS);\n\n if (! (toggleEl && menuEl))\n return logger.error('MLDropdown:', TOGGLE_CSS_CLASS, 'or', MENU_CSS_CLASS, 'isn\\'t found');\n\n var doc = window.document\n , clickHandler = this.toggleMenu.bind(this, undefined);\n\n var listeners = new DOMListeners;\n this._dropdown = {\n menu: menuEl,\n visible: false,\n listeners: listeners\n };\n this.hideMenu();\n var self = this;\n\n listeners.add(toggleEl, 'click', clickHandler);\n //maybe only add this events if is open?\n listeners.add(doc, 'mouseout', onDocOut);\n listeners.add(doc, 'click', onClick);\n\n\n function onDocOut(event) {\n var target = event.target\n , relatedTarget = event.relatedTarget\n , listeners = self._dropdown.listeners;\n\n if (isIframe(target))\n listeners.remove(target.contentWindow.document, 'click', onClick);\n\n if (isIframe(relatedTarget))\n listeners.add(relatedTarget.contentWindow.document, 'click', onClick);\n }\n\n function onClick(event) {\n if (!self.el.contains(event.target))\n self.hideMenu();\n }\n}\n\n\nfunction isIframe(el) {\n return el && el.tagName == 'IFRAME';\n}\n\n\nfunction MLDropdown$destroy() {\n this._dropdown.listeners.removeAll();\n delete this._dropdown;\n Component.prototype.destroy.apply(this, arguments);\n}\n\n\nfunction MLDropdown$showMenu() {\n this.toggleMenu(true);\n}\n\n\nfunction MLDropdown$hideMenu() {\n this.toggleMenu(false);\n}\n\n\nfunction MLDropdown$toggleMenu(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._dropdown.visible\n : !! doShow;\n\n this._dropdown.visible = doShow;\n\n var menu = this._dropdown.menu;\n menu.style.display = doShow\n ? 'block'\n : 'none';\n}\n",
- "'use strict';\n\n\n// \n// milo.config\n// -----------\n\n// It is the function that allows to change milo configurations and also\n// access them on config's properties.\n\n// ```javascript\n// milo.config({\n// attrs: {\n// bind: 'ml-bind',\n// load: 'ml-load'\n// }\n// });\n// ```\n\n\nvar _ = require('mol-proto')\n , doT = require('dot');\n\n\nmodule.exports = config;\n\nfunction config(options) {\n _.deepExtend(config, options);\n}\n\nconfig({\n attrs: {\n bind: 'ml-bind',\n load: 'ml-load'\n },\n componentRef: '___milo_component',\n componentPrefix: 'milo_',\n mixin: {\n instancePropertiesMap: '___mixin_instances'\n },\n template: {\n compile: doT.compile\n },\n domStorage: {\n typeSuffix: ':___milo_data_type',\n prefixSeparator: '/',\n root: '',\n messageKey: '___milo_message/',\n messageTimestamp: '___milo_timestamp',\n quotaExceeded: {\n throwError: true,\n message: false\n }\n },\n dragDrop: {\n dataTypes: {\n component: 'x-application/milo/component',\n componentMetaTemplate: 'x-application/milo/component-meta/%class/%name/%params',\n componentMetaRegex: /^x\\-application\\/milo\\/component\\-meta\\/([a-z0-9]+)\\/([a-z0-9]+)\\/([a-z0-9]*)$/,\n }\n },\n request: {\n jsonpTimeout: 60000,\n jsonpCallbackPrefix: '___milo_callback_',\n optionsKey: '___milo_options',\n defaults: {\n timeout: 60000\n }\n },\n websocket: {\n rpc: {\n timeout: 15000,\n responsePrefix: 'response_'\n }\n },\n check: true,\n debug: false\n});\n",
- "'use strict';\n\n\nvar miloMail = require('./services/mail')\n , request = require('./util/request')\n , logger = require('./util/logger')\n , utilDom = require('./util/dom')\n , config = require('./config')\n , LoadAttribute = require('./attributes/a_load')\n , LoaderError = require('./util/error').Loader;\n\n\nmodule.exports = loader;\n\n/**\n * `milo.loader`\n * \n * Recursively scans the document tree inside `rootEl` (document.body by default) looking for __ml-load__ @attribute.\n * One level load is executed. No additional loader get called on inside __ml-load__ attributes. \n *\n * Possible usages:\n * - milo.loader([myRootEl,][myRemoveAttribute,]myCallback)\n * \n * @param {Element} rootEl Root element inside which DOM will be scanned (document.body by default).\n * @param {Boolean} removeAttribute If set to true, then the __ml-load__ attribute will be removed once loader has been executed (False by default).\n * @param {Function} callback Callback to call after all elements get loaded (Required).\n */\nfunction loader(rootEl, removeAttribute, callback) {\n milo(function() {\n _loader(rootEl, removeAttribute, callback);\n });\n}\n\n\nfunction _loader(rootEl, removeAttribute, callback) {\n if (typeof rootEl == 'function') {\n callback = rootEl;\n rootEl = undefined;\n removeAttribute = false;\n }\n\n if (typeof removeAttribute == 'function') {\n callback = removeAttribute;\n removeAttribute = false;\n }\n\n rootEl = rootEl || document.body;\n\n miloMail.postMessage('loader', { state: 'started' });\n _loadViewsInElement(rootEl, removeAttribute, function(views) {\n miloMail.postMessage('loader', { \n state: 'finished',\n views: views\n });\n callback(views);\n });\n}\n\n\nfunction _loadViewsInElement(rootEl, removeAttribute, callback) {\n var loadElements = rootEl.getAttribute(config.attrs.load)\n ? [rootEl]\n : rootEl.querySelectorAll('[' + config.attrs.load + ']');\n\n var views = {}\n , totalCount = loadElements.length\n , loadedCount = 0;\n\n _.forEach(loadElements, function (el) {\n loadView(el, removeAttribute, function(err) {\n views[el.id] = err || el;\n loadedCount++;\n if (loadedCount == totalCount)\n callback(views);\n });\n });\n};\n\n\nfunction loadView(el, removeAttribute, callback) {\n if (utilDom.children(el).length)\n throw new LoaderError('can\\'t load html into element that is not empty');\n\n var attr = new LoadAttribute(el);\n\n attr.parse().validate();\n\n request.get(attr.loadUrl, function(err, html) {\n if (err) {\n err.message = err.message || 'can\\'t load file ' + attr.loadUrl;\n // logger.error(err.message);\n callback(err);\n return;\n }\n\n el.innerHTML = html;\n if (removeAttribute) LoadAttribute.remove(el);\n callback(null);\n });\n}\n",
- "'use strict';\n\nvar Mixin = require('../abstract/mixin')\n // , MessageSource = require('./message_source')\n , MessageSource = require('./m_source')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match\n , MessengerError = require('../util/error').Messenger;\n\n\n/**\n * `milo.Messenger`\n * A generic Messenger class that is used for all kinds of messaging in milo. It is subclassed from [Mixin](../abstract/mixin.js.html) and it proxies its methods to the host object for convenience.\n * All facets and components have messenger attached to them. Messenger class interoperates with [MessageSource](./m_source.js.html) class that connects the messenger to some external source of messages (e.g., DOM events) and [MessengerAPI](./m_api.js.html) class that allows to define higher level messages than messages that exist on the source.\n * Messenger class is used internally in milo and can be used together with any objects/classes in the application.\n * milo also defines a global messenger [milo.mail](../mail/index.js.html) that dispatches `domready` event and can be used for any application wide messaging.\n * To initialize your app after DOM is ready use:\n * ```\n * milo.mail.on('domready', function() {\n * // application starts\n * });\n * ```\n * or the following shorter form of the same:\n * ```\n * milo(function() {\n * // application starts\n * });\n * ```\n */\nvar Messenger = _.createSubclass(Mixin, 'Messenger');\n\nvar messagesSplitRegExp = Messenger.messagesSplitRegExp = /\\s*(?:\\,|\\s)\\s*/;\n\n\n/**\n * ####Messenger instance methods####\n *\n * - [init](#init)\n * - [on](#Messenger$on) (alias - onMessage, deprecated)\n * - [off](#Messenger$off) (alias - offMessage, deprecated)\n * - [onMessages](#onMessages)\n * - [offMessages](#offMessages)\n * - [once](#once)\n * - [onceSync](#onceSync)\n * - [postMessage](#postMessage)\n * - [getSubscribers](#getSubscribers)\n *\n * \"Private\" methods\n *\n * - [_chooseSubscribersHash](#_chooseSubscribersHash)\n * - [_registerSubscriber](#_registerSubscriber)\n * - [_removeSubscriber](#_removeSubscriber)\n * - [_removeAllSubscribers](#_removeAllSubscribers)\n * - [_callPatternSubscribers](#_callPatternSubscribers)\n * - [_callSubscribers](#_callSubscribers)\n * - [_setMessageSource](#_setMessageSource)\n * - [getMessageSource](#getMessageSource)\n */\n_.extendProto(Messenger, {\n init: init, // called by Mixin (superclass)\n destroy: Messenger$destroy,\n on: Messenger$on,\n once: Messenger$once,\n onceSync: Messenger$onceSync,\n onSync: Messenger$onSync,\n onAsync: Messenger$onAsync,\n onMessage: Messenger$on, // deprecated\n off: Messenger$off,\n offMessage: Messenger$off, // deprecated\n onMessages: onMessages,\n offMessages: offMessages,\n offAll: Messenger$offAll,\n postMessage: postMessage,\n postMessageSync: postMessageSync,\n getSubscribers: getSubscribers,\n getMessageSource: getMessageSource,\n _chooseSubscribersHash: _chooseSubscribersHash,\n _registerSubscriber: _registerSubscriber,\n _removeSubscriber: _removeSubscriber,\n _removeAllSubscribers: _removeAllSubscribers,\n _callPatternSubscribers: _callPatternSubscribers,\n _callSubscribers: _callSubscribers,\n _callSubscriber: _callSubscriber,\n _setMessageSource: _setMessageSource\n});\n\n\n/**\n * A default map of proxy methods used by ComponentFacet and Component classes to pass to Messenger when it is instantiated.\n * This map is for convenience only, it is NOT used internally by Messenger, a host class should pass it for methods to be proxied this way.\n */\nMessenger.defaultMethods = {\n on: 'on',\n onSync: 'onSync',\n once: 'once',\n onceSync: 'onceSync',\n off: 'off',\n onMessages: 'onMessages',\n offMessages: 'offMessages',\n postMessage: 'postMessage',\n postMessageSync: 'postMessageSync',\n getSubscribers: 'getSubscribers'\n};\n\n\nmodule.exports = Messenger;\n\n\nMessenger.subscriptions = [];\n\n\n/**\n * Messenger instance method\n * Initializes Messenger. Method is called by Mixin class constructor.\n * See [on](#Messenger$on) method, [Messenger](#Messenger) class above and [MessageSource](./m_source.js.html) class.\n *\n * @param {Object} hostObject Optional object that stores the messenger on one of its properties. It is used to proxy methods of messenger and also as a context for subscribers when they are called by the Messenger. See `on` method.\n * @param {Object} proxyMethods Optional map of method names; key - proxy method name, value - messenger's method name.\n * @param {MessageSource} messageSource Optional messageSource linked to the messenger. If messageSource is supplied, the reference to the messenger will stored on its 'messenger' property\n */\nfunction init(hostObject, proxyMethods, messageSource) {\n // hostObject and proxyMethods are used in Mixin and checked there\n if (messageSource)\n this._setMessageSource(messageSource);\n\n _initializeSubscribers.call(this);\n}\n\n\nfunction _initializeSubscribers() {\n _.defineProperties(this, {\n _messageSubscribers: {},\n _patternMessageSubscribers: {},\n }, _.CONF);\n}\n\n\n/**\n * Destroys messenger. Maybe needs to unsubscribe all subscribers\n */\nfunction Messenger$destroy() {\n this.offAll();\n var messageSource = this.getMessageSource();\n if (messageSource)\n messageSource.destroy();\n}\n\n\n/**\n * Messenger instance method.\n * Registers a subscriber function for a certain message(s).\n * This method returns `true` if the subscription was successful. It can be unsuccessful if the passed subscriber has already been subscribed to this message type - double subscription never happens and it is safe to subscribe again - no error or warning is thrown or logged.\n * Subscriber is passed two parameters: `message` (string) and `data` (object). Data object is supplied when message is dispatched, Messenger itself adds nothing to it. For example, [events facet](../components/c_facets/Events.js.html) sends actual DOM event when it posts message.\n * Usage:\n * ```\n * // subscribes onMouseUpDown to two DOM events on component via events facet.\n * myComp.events.on('mousedown mouseup', onMouseUpDown);\n * function onMouseUpDown(eventType, event) {\n * // ...\n * }\n *\n * myComp.data.on(/.+/, function(msg, data) {\n * logger.debug(msg, data);\n * }); // subscribes anonymous function to all non-empty messages on data facet\n * // it will not be possible to unsubscribe anonymous subscriber separately,\n * // but myComp.data.off(/.+/) will unsubscribe it\n * ```\n * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added, so it can subscribe to the source.\n * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `on` when they proxy it.\n * See [postMessage](#postMessage).\n *\n * @param {String|Array[String]|RegExp} messages Message types that should envoke the subscriber.\n * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.\n * If an array of strings is passed, each string is a message type to subscribe for.\n * If a RegExp is passed, the subscriber will be envoked when the message dispatched on the messenger matches the pattern (or IS the RegExp with identical pattern).\n * Pattern subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.\n * @param {Function|Object} subscriber Message subscriber - a function that will be called when the message is dispatched on the messenger (usually via proxied postMessage method of host object).\n * If hostObject was supplied to Messenger constructor, hostObject will be the context (the value of this) for the subscriber envocation.\n * Subscriber can also be an object with properties `subscriber` (function) and `context` (\"this\" value when subscriber is called)\n * @return {Boolean}\n */\nfunction Messenger$on(messages, subscriber) {\n return _Messenger_onWithOptions.call(this, messages, subscriber);\n}\n\n\nfunction Messenger$once(messages, subscriber) {\n return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1 });\n}\n\nfunction Messenger$onceSync(messages, subscriber) {\n return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1, sync: true });\n}\n\n\nfunction Messenger$onSync(messages, subscriber) {\n return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: true });\n}\n\n\nfunction Messenger$onAsync(messages, subscriber) {\n return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: false });\n}\n\n\nfunction _Messenger_onWithOptions(messages, subscriber, options) {\n check(messages, Match.OneOf(String, [String], RegExp));\n check(subscriber, Match.OneOf(Function, {\n subscriber: Function,\n context: Match.Any,\n options: Match.Optional(Object),\n }));\n\n if (typeof subscriber == 'function') {\n subscriber = {\n subscriber: subscriber,\n context: this._hostObject,\n };\n }\n\n if (options) {\n subscriber.options = subscriber.options || {};\n _.extend(subscriber.options, options);\n }\n\n return _Messenger_on.call(this, messages, subscriber);\n}\n\n\nfunction _Messenger_on(messages, subscriber) {\n _.defineProperty(subscriber, '__messages', messages);\n return _eachMessage.call(this, '_registerSubscriber', messages, subscriber);\n}\n\n\nfunction _eachMessage(methodName, messages, subscriber) {\n if (typeof messages == 'string')\n messages = messages.split(messagesSplitRegExp);\n\n var subscribersHash = this._chooseSubscribersHash(messages);\n\n if (messages instanceof RegExp)\n return this[methodName](subscribersHash, messages, subscriber);\n\n else {\n var changed = false;\n\n messages.forEach(function(message) {\n var subscriptionChanged = this[methodName](subscribersHash, message, subscriber);\n changed = changed || subscriptionChanged;\n }, this);\n\n return changed;\n }\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * It is called by [on](#Messenger$on) to register subscriber for one message type.\n * Returns `true` if this subscriber is not yet registered for this type of message.\n * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added.\n *\n * @private\n * @param {Object} subscribersHash The map of subscribers determined by [on](#Messenger$on) based on Message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`\n * @param {String} message Message type\n * @param {Function|Object} subscriber Subscriber function to be added or object with properties `subscriber` (function) and `context` (value of \"this\" when subscriber is called)\n * @return {Boolean}\n */\nfunction _registerSubscriber(subscribersHash, message, subscriber) {\n if (! (subscribersHash[message] && subscribersHash[message].length)) {\n subscribersHash[message] = [];\n if (message instanceof RegExp)\n subscribersHash[message].pattern = message;\n if (this._messageSource)\n this._messageSource.onSubscriberAdded(message);\n var noSubscribers = true;\n }\n\n var msgSubscribers = subscribersHash[message];\n var notYetRegistered = noSubscribers || _indexOfSubscriber.call(this, msgSubscribers, subscriber) == -1;\n\n if (notYetRegistered)\n msgSubscribers.push(subscriber);\n\n return notYetRegistered;\n}\n\n\n/**\n * Finds subscriber index in the list\n *\n * @param {Array[Function|Object]} list list of subscribers\n * @param {Function|Object} subscriber subscriber function or object with properties `subscriber` (function) and `context` (\"this\" object)\n */\nfunction _indexOfSubscriber(list, subscriber) {\n var self = this;\n return _.findIndex(list, function(subscr){\n return subscriber.subscriber == subscr.subscriber\n && subscriber.context == subscr.context\n });\n}\n\n\n/**\n * Messenger instance method.\n * Subscribes to multiple messages passed as map together with subscribers.\n * Usage:\n * ```\n * myComp.events.onMessages({\n * 'mousedown': onMouseDown,\n * 'mouseup': onMouseUp\n * });\n * function onMouseDown(eventType, event) {}\n * function onMouseUp(eventType, event) {}\n * ```\n * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was added.\n * It is NOT possible to add pattern subscriber using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.\n *\n * @param {Object[Function]} messageSubscribers Map of message subscribers to be added\n * @return {Object[Boolean]}\n */\nfunction onMessages(messageSubscribers) {\n check(messageSubscribers, Match.ObjectHash(Match.OneOf(Function, { subscriber: Function, context: Match.Any })));\n\n var notYetRegisteredMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {\n return this.on(messages, subscriber);\n }, this);\n\n return notYetRegisteredMap;\n}\n\n\n/**\n * Messenger instance method.\n * Removes a subscriber for message(s). Removes all subscribers for the message if subscriber isn't passed.\n * This method returns `true` if the subscriber was registered. No error or warning is thrown or logged if you remove subscriber that was not registered.\n * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `off` when they proxy it.\n * Usage:\n * ```\n * // unsubscribes onMouseUpDown from two DOM events.\n * myComp.events.off('mousedown mouseup', onMouseUpDown);\n * ```\n * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.\n *\n * @param {String|Array[String]|RegExp} messages Message types that a subscriber should be removed for.\n * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.\n * If an array of strings is passed, each string is a message type to remove a subscriber for.\n * If a RegExp is passed, the pattern subscriber will be removed.\n * RegExp subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.\n * @param {Function} subscriber Message subscriber - Optional function that will be removed from the list of subscribers for the message(s). If subscriber is not supplied, all subscribers will be removed from this message(s).\n * @return {Boolean}\n */\nfunction Messenger$off(messages, subscriber) {\n check(messages, Match.OneOf(String, [String], RegExp));\n check(subscriber, Match.Optional(Match.OneOf(Function, {\n subscriber: Function,\n context: Match.Any,\n options: Match.Optional(Object),\n // __messages: Match.Optional(Match.OneOf(String, [String], RegExp))\n })));\n\n return _Messenger_off.call(this, messages, subscriber);\n}\n\n\nfunction _Messenger_off(messages, subscriber) {\n return _eachMessage.call(this, '_removeSubscriber', messages, subscriber);\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * It is called by [off](#Messenger$off) to remove subscriber for one message type.\n * Returns `true` if this subscriber was registered for this type of message.\n * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.\n *\n * @private\n * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`\n * @param {String} message Message type\n * @param {Function} subscriber Subscriber function to be removed\n * @return {Boolean}\n */\nfunction _removeSubscriber(subscribersHash, message, subscriber) {\n var msgSubscribers = subscribersHash[message];\n if (! msgSubscribers || ! msgSubscribers.length)\n return false; // nothing removed\n\n if (subscriber) {\n if (typeof subscriber == 'function')\n subscriber = { subscriber: subscriber, context: this._hostObject };\n\n var subscriberIndex = _indexOfSubscriber.call(this, msgSubscribers, subscriber);\n if (subscriberIndex == -1)\n return false; // nothing removed\n msgSubscribers.splice(subscriberIndex, 1);\n if (! msgSubscribers.length)\n this._removeAllSubscribers(subscribersHash, message);\n\n } else\n this._removeAllSubscribers(subscribersHash, message);\n\n return true; // subscriber(s) removed\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * It is called by [_removeSubscriber](#_removeSubscriber) to remove all subscribers for one message type.\n * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified that all message subscribers were removed so it can unsubscribe from the source.\n *\n * @private\n * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`\n * @param {String} message Message type\n */\nfunction _removeAllSubscribers(subscribersHash, message) {\n delete subscribersHash[message];\n if (this._messageSource && typeof message == 'string')\n this._messageSource.onSubscriberRemoved(message);\n}\n\n\n/**\n * Messenger instance method.\n * Unsubscribes from multiple messages passed as map together with subscribers.\n * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was removed.\n * If a subscriber for one of the messages is not supplied, all subscribers for this message will be removed.\n * Usage:\n * ```\n * myComp.events.offMessages({\n * 'mousedown': onMouseDown,\n * 'mouseup': onMouseUp,\n * 'click': undefined // all subscribers to this message will be removed\n * });\n * ```\n * It is NOT possible to remove pattern subscriber(s) using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.\n *\n * @param {Object[Function]} messageSubscribers Map of message subscribers to be removed\n * @return {Object[Boolean]}\n */\nfunction offMessages(messageSubscribers) {\n check(messageSubscribers, Match.ObjectHash(Match.Optional(Match.OneOf(Function, { subscriber: Function, context: Match.Any }))));\n\n var subscriberRemovedMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {\n return this.off(messages, subscriber);\n }, this);\n\n return subscriberRemovedMap;\n}\n\n\n/**\n * Unsubscribes all subscribers\n */\nfunction Messenger$offAll() {\n _offAllSubscribers.call(this, this._patternMessageSubscribers);\n _offAllSubscribers.call(this, this._messageSubscribers);\n}\n\n\nfunction _offAllSubscribers(subscribersHash) {\n _.eachKey(subscribersHash, function(subscribers, message) {\n this._removeAllSubscribers(subscribersHash, message);\n }, this);\n}\n\n\n// TODO - send event to messageSource\n\n\n/**\n * Messenger instance method.\n * Dispatches the message calling all subscribers registered for this message and, if the message is a string, calling all pattern subscribers when message matches the pattern.\n * Each subscriber is passed the same parameters that are passed to theis method.\n * The context of the subscriber envocation is set to the host object (`this._hostObject`) that was passed to the messenger constructor.\n * Subscribers are called in the next tick (\"asynchronously\") apart from those that were subscribed with `onSync` (or that have `options.sync == true`).\n *\n * @param {String|RegExp} message message to be dispatched\n * If the message is a string, the subscribers registered with exactly this message will be called and also pattern subscribers registered with the pattern that matches the dispatched message.\n * If the message is RegExp, only the subscribers registered with exactly this pattern will be called.\n * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.\n * @param {Function} callback optional callback to pass to subscriber\n * @param {Boolean} _synchronous if true passed, subscribers will be envoked synchronously apart from those that have `options.sync == false`. This parameter should not be used, instead postMessageSync should be used.\n */\nfunction postMessage(message, data, callback, _synchronous) {\n check(message, Match.OneOf(String, RegExp));\n check(callback, Match.Optional(Function));\n\n var subscribersHash = this._chooseSubscribersHash(message);\n var msgSubscribers = subscribersHash[message];\n\n this._callSubscribers(message, data, callback, msgSubscribers, _synchronous);\n\n if (typeof message == 'string')\n this._callPatternSubscribers(message, data, callback, msgSubscribers, _synchronous);\n}\n\n\n/**\n * Same as postMessage apart from envoking subscribers synchronously, apart from those subscribed with `onAsync` (or with `options.sync == false`).\n *\n * @param {String|RegExp} message\n * @param {Any} data\n * @param {Function} callback\n */\nfunction postMessageSync(message, data, callback) {\n this.postMessage(message, data, callback, true);\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * Envokes pattern subscribers with the pattern that matches the message.\n * The method is called by [postMessage](#postMessage) - see more information there.\n *\n * @private\n * @param {String} message message to be dispatched. Pattern subscribers registered with the pattern that matches the dispatched message will be called.\n * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.\n * @param {Function} callback optional callback to pass to subscriber\n * @param {Array[Function|Object]} calledMsgSubscribers array of subscribers already called, they won't be called again if they are among pattern subscribers.\n */\nfunction _callPatternSubscribers(message, data, callback, calledMsgSubscribers, _synchronous) {\n _.eachKey(this._patternMessageSubscribers,\n function(patternSubscribers) {\n var pattern = patternSubscribers.pattern;\n if (pattern.test(message)) {\n if (calledMsgSubscribers) {\n var patternSubscribers = patternSubscribers.filter(function(subscriber) {\n var index = _indexOfSubscriber.call(this, calledMsgSubscribers, subscriber);\n return index == -1;\n });\n }\n this._callSubscribers(message, data, callback, patternSubscribers, _synchronous);\n }\n }\n , this);\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * Envokes subscribers from the passed list.\n * The method is called by [postMessage](#postMessage) and [_callPatternSubscribers](#_callPatternSubscribers).\n *\n * @private\n * @param {String} message message to be dispatched, passed to subscribers as the first parameter.\n * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.\n * @param {Array[Function|Object]} msgSubscribers the array of message subscribers to be called. Each subscriber is called with the host object (see Messenger constructor) as the context.\n * @param {Function} callback optional callback to pass to subscriber\n */\nfunction _callSubscribers(message, data, callback, msgSubscribers, _synchronous) {\n if (msgSubscribers && msgSubscribers.length) {\n // cloning is necessary as some of the subscribers\n // can be unsubscribed during the dispatch\n // so this array would change in the process\n msgSubscribers = msgSubscribers.slice();\n\n msgSubscribers.forEach(function(subscriber) {\n this._callSubscriber(subscriber, message, data, callback, _synchronous);\n }, this);\n }\n}\n\n\nfunction _callSubscriber(subscriber, message, data, callback, _synchronous) {\n var syncSubscriber = subscriber.options && subscriber.options.sync\n , synchro = (_synchronous && syncSubscriber !== false)\n || syncSubscriber;\n\n var dispatchTimes = subscriber.options && subscriber.options.dispatchTimes;\n if (dispatchTimes) {\n if (dispatchTimes <= 1) {\n var messages = subscriber.__messages;\n this.off(messages, subscriber);\n } else if (dispatchTimes > 1)\n subscriber.options.dispatchTimes--;\n }\n\n if (synchro)\n subscriber.subscriber.call(subscriber.context, message, data, callback);\n else\n _.deferMethod(subscriber.subscriber, 'call', subscriber.context, message, data, callback);\n}\n\n\n/**\n * Messenger instance method.\n * Returns the array of subscribers that would be called if the message were dispatched.\n * If `includePatternSubscribers === false`, pattern subscribers with matching patters will not be included (by default they are included).\n * If there are no subscribers to the message, `undefined` will be returned, not an empty array, so it is safe to use the result in boolean tests.\n *\n * @param {String|RegExp} message Message to get subscribers for.\n * If the message is RegExp, only pattern subscribers registered with exactly this pattern will be returned.\n * If the message is String, subscribers registered with the string messages and pattern subscribers registered with matching pattern will be returned (unless the second parameter is false).\n * @param {Boolean} includePatternSubscribers Optional false to prevent inclusion of patter subscribers, by default they are included.\n * @return {Array|undefined}\n */\nfunction getSubscribers(message, includePatternSubscribers) {\n check(message, Match.OneOf(String, RegExp));\n\n var subscribersHash = this._chooseSubscribersHash(message);\n var msgSubscribers = subscribersHash[message]\n ? [].concat(subscribersHash[message])\n : [];\n\n // pattern subscribers are incuded by default\n if (includePatternSubscribers !== false && typeof message == 'string') {\n _.eachKey(this._patternMessageSubscribers,\n function(patternSubscribers) {\n var pattern = patternSubscribers.pattern;\n if (patternSubscribers && patternSubscribers.length\n && pattern.test(message))\n _.appendArray(msgSubscribers, patternSubscribers);\n }\n );\n }\n\n // return undefined if there are no subscribers\n return msgSubscribers.length\n ? msgSubscribers\n : undefined;\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * Returns the map of subscribers for a given message type.\n *\n * @private\n * @param {String|RegExp} message Message to choose the map of subscribers for\n * @return {Object[Function]}\n */\nfunction _chooseSubscribersHash(message) {\n return message instanceof RegExp\n ? this._patternMessageSubscribers\n : this._messageSubscribers;\n}\n\n\n/**\n * Messenger instance method\n * Sets [MessageSource](./m_source.js.html) for the messenger also setting the reference to the messenger in the MessageSource.\n * MessageSource can be passed to message constructor; this method allows to set it at a later time. For example, the subclasses of [ComponentFacet](../components/c_facet.js.html) use this method to set different MessageSource'es in the messenger that is created by ComponentFacet.\n * Currently the method is implemented in such way that it can be called only once - MessageSource cannot be changed after this method is called.\n *\n * @param {MessageSource} messageSource an instance of MessageSource class to attach to this messenger (and to have this messenger attached to it too)\n */\nfunction _setMessageSource(messageSource) {\n check(messageSource, MessageSource);\n\n _.defineProperty(this, '_messageSource', messageSource);\n messageSource.messenger = this;\n}\n\n\n/**\n * Messenger instance method\n * Returns messenger MessageSource\n *\n * @return {MessageSource}\n */\nfunction getMessageSource() {\n return this._messageSource\n}\n",
- "'use strict';\n\nvar _ = require('mol-proto')\n , logger = require('../util/logger');\n\n\nmodule.exports = MessengerAPI;\n\n\n/**\n * `milo.classes.MessengerAPI`\n * Base class, subclasses of which can supplement the functionality of [MessageSource](./m_source.js.html) by implementing three methods:\n *\n * - `translateToSourceMessage` to translate source messages (recieved from external source via `MessageSOurce`) to internal messages (that are dispatched on Messenger), allowing to make internal messages more detailed than source messages. For example, [Data facet](../components/c_facets/Data.js.html) uses [DataMsgAPI](../components/msg_api/data.js.html) to define several internal messages related to the change of state in contenteditable DOM element.\n * - `createInternalData` to modify message data received from source to some more meaningful or more detailed message data that will be dispatched on Messenger. For example, [Data facet](../components/c_facets/Data.js.html) uses [DataMsgAPI](../components/msg_api/data.js.html) (subclass of MessengerAPI) to translate DOM messages to data change messages.\n * - `filterSourceMessage` to enable/disable message dispatch based on some conditions in data.\n *\n * If `MessageSource` constructor is not passed an instance of some subclass of `MessengerAPI`, it automatically creates an instance of MessengerAPI that defines all 3 of those methods in a trivial way. See these methods below for their signatures.\n *\n * @constructor\n * @this {MessengerAPI}\n * @return {MessengerAPI}\n */\nfunction MessengerAPI() {\n if (this.init)\n this.init.apply(this, arguments);\n}\n\n\n/**\n * ####MessengerAPI instance methods####\n *\n * - [init](#init) - initializes MessengerAPI\n * - [addInternalMessage](#addInternalMessage) - adds internal message\n * - [removeInternalMessage](#removeInternalMessage) - removes internal message\n * - [getInternalMessages](#getInternalMessages) - returns the list of internal messages for given source message\n *\n * These methods should be redefined by subclass:\n *\n * - [translateToSourceMessage](#translateToSourceMessage) - converts internal message type to source (external) message type\n * - [createInternalData](#createInternalData) - converts source message data received via MessageSource to internal message data\n * - [filterSourceMessage](#filterSourceMessage) - filters source message based on the data of the message and the corresponding internal message that is about to be sent on Messenger\n */\n_.extendProto(MessengerAPI, {\n init: init,\n destroy: MessengerAPI$destroy,\n addInternalMessage: addInternalMessage,\n removeInternalMessage: removeInternalMessage,\n getInternalMessages: getInternalMessages,\n\n // should be redefined by subclass\n translateToSourceMessage: translateToSourceMessage,\n createInternalData: createInternalData,\n filterSourceMessage: filterSourceMessage\n});\n\n\n/**\n * MessengerAPI instance method\n * Called by MessengerAPI constructor. Subclasses that re-implement `init` method should call this method using: `MessengerAPI.prototype.init.apply(this, arguments)`\n */\nfunction init() {\n _.defineProperty(this, '_internalMessages', {});\n}\n\n\n/**\n * Destroys messenger API\n */\nfunction MessengerAPI$destroy() {\n\n}\n\n\n/**\n * MessengerAPI instance method\n * Translates internal `message` to source message, adds internal `message` to the list, making sure the same `message` wasn't passed before (it would indicate Messenger error).\n * Returns source message if it is used first time (so that `MessageSource` subcribes to this source message) or `undefined`.\n *\n * @param {String} message internal message to be translated and added\n * @return {String|undefined}\n */\nfunction addInternalMessage(message) {\n var internalMsgs\n , sourceMessage = this.translateToSourceMessage(message);\n\n if (typeof sourceMessage == 'undefined') return;\n\n if (this._internalMessages.hasOwnProperty(sourceMessage)) {\n internalMsgs = this._internalMessages[sourceMessage];\n if (internalMsgs.indexOf(message) == -1)\n internalMsgs.push(message);\n else\n logger.warn('Duplicate addInternalMessage call for internal message ' + message);\n } else {\n internalMsgs = this._internalMessages[sourceMessage] = [];\n internalMsgs.push(message);\n return sourceMessage;\n }\n}\n\n\n/**\n * MessengerAPI instance method\n * Removes internal `message` from the list connected to corresponding source message (`translateToSourceMessage` is used for translation).\n * Returns source message, if the last internal message was removed (so that `MessageSource` can unsubscribe from this source message), or `undefined`.\n *\n * @param {String} message internal message to be translated and removed\n * @return {String|undefined}\n */\nfunction removeInternalMessage(message) {\n var sourceMessage = this.translateToSourceMessage(message);\n\n if (typeof sourceMessage == 'undefined') return;\n\n var internalMsgs = this._internalMessages[sourceMessage];\n\n if (internalMsgs && internalMsgs.length) {\n var messageIndex = internalMsgs.indexOf(message);\n if (messageIndex >= 0) {\n internalMsgs.splice(messageIndex, 1);\n if (internalMsgs.length == 0) {\n delete this._internalMessages[sourceMessage];\n return sourceMessage;\n }\n } else\n unexpectedNotificationWarning();\n } else\n unexpectedNotificationWarning();\n\n\n function unexpectedNotificationWarning() {\n logger.warn('notification received: un-subscribe from internal message ' + message\n + ' without previous subscription notification');\n }\n}\n\n\n/**\n * MessengerAPI instance method\n * Returns the array of internal messages that were translated to given `sourceMessage`.\n * This method is used by `MessageSource` to dispatch source message on the `Mesenger`.\n *\n * @param {String} sourceMessage source message\n * @return {Array[String]}\n */\nfunction getInternalMessages(sourceMessage) {\n return this._internalMessages[sourceMessage];\n}\n\n\n/**\n * MessengerAPI instance method\n * Subclasses should re-implement this method to define the rule for translation of internal `message` to source message. This class simply returns the same `message`.\n *\n * @param {String} message internal message to be translated\n * @return {String}\n */\nfunction translateToSourceMessage(message) {\n return message\n}\n\n\n/**\n * MessengerAPI instance method\n * Subclasses should re-implement this method to define the rule for translation of source message data to internal message data. This class simply returns the same `sourceData`.\n * This method is used in [dispatchMessage](./m_source.js.html#dispatchMessage) method of `MessageSource`.\n *\n * @param {String} sourceMessage source message, can be used in translation rule\n * @param {String} message internal message, can be used in translation rule\n * @param {Object} sourceData data received from source that has to be translated to data that will be sent to internal Messenger subscriber\n * @return {Object}\n */\nfunction createInternalData(sourceMessage, message, sourceData) {\n return sourceData;\n}\n\n\n/**\n * MessengerAPI instance method\n * Subclasses should re-implement this method to define the dispatch filter for internal messages. This method should return `true` to allow and `false` to prevent internal message dispatch. This class always returns `true`.\n * This method is used in [dispatchMessage](./m_source.js.html#dispatchMessage) method of `MessageSource`.\n *\n * @param {String} sourceMessage source message, can be used in filter rule\n * @param {String} message internal message, can be used in filter rule\n * @param {Object} internalData data translated by `createInternalData` method from source data, can be used in filter rule\n * @return {Boolean}\n */\nfunction filterSourceMessage(sourceMessage, message, internalData) {\n return true;\n}\n",
- "'use strict';\n\nvar MessengerAPI = require('./m_api')\n , _ = require('mol-proto');\n\n\n/**\n * A generic subsclass of [MessengerAPI](./m_api.js.html) that supports pattern subscriptions to source.\n * Can be useful if the source is another Messenger.\n */\n var MessengerRegexpAPI = _.createSubclass(MessengerAPI, 'MessengerRegexpAPI');\n\n module.exports = MessengerRegexpAPI;\n\n\n_.extendProto(MessengerRegexpAPI, {\n init: init,\n addInternalMessage: addInternalMessage,\n removeInternalMessage: removeInternalMessage,\n getInternalMessages: getInternalMessages\n});\n\n\n/**\n * MessengerRegexpAPI instance method\n * Called by MessengerRegexpAPI constructor.\n */\nfunction init() {\n MessengerAPI.prototype.init.apply(this, arguments);\n _.defineProperties(this, {\n _patternInternalMessages: {}\n });\n this._catchAllSubscribed = false;\n}\n\n\n/**\n * MessengerRegexpAPI instance method\n * Augments MessengerAPI method by storing regexp\n *\n * @param {String} message internal message to be translated and added\n * @return {String|RegExp|undefined}\n */\nfunction addInternalMessage(message) {\n var sourceMessage = MessengerAPI.prototype.addInternalMessage.apply(this, arguments);\n \n // store regexp itself if sourceMessage is regexp\n if (sourceMessage && sourceMessage instanceof RegExp) {\n this._internalMessages[sourceMessage].pattern = sourceMessage;\n this._patternInternalMessages[sourceMessage] = this._internalMessages[sourceMessage];\n if (this._catchAllSubscribed) return;\n this._catchAllSubscribed = true;\n return /.*/;\n }\n\n return sourceMessage;\n}\n\n\n/**\n * MessengerRegexpAPI instance method\n * Augments MessengerAPI method by removing regexp subscirption\n * \n * @param {String} message internal message to be translated and added\n * @return {String|RegExp|undefined}\n */\nfunction removeInternalMessage(message) {\n var sourceMessage = MessengerAPI.prototype.removeInternalMessage.apply(this, arguments);\n\n if (sourceMessage && sourceMessage instanceof RegExp) {\n delete this._patternInternalMessages[sourceMessage];\n var noPatternInternalMessages = ! Object.keys(this._patternInternalMessages).length;\n if (noPatternInternalMessages) {\n this._catchAllSubscribed = false;\n return /.*/;\n }\n }\n\n return sourceMessage;\n}\n\n\n/**\n * MessengerAPI instance method\n * Augments MessengerAPI method by returning messages subscribed with regexp\n * This method is used by `MessageSource` to dispatch source message on the `Mesenger`.\n *\n * @param {String|RegExp} sourceMessage source message\n * @return {Array[String]}\n */\nfunction getInternalMessages(sourceMessage) {\n var internalMessages = MessengerAPI.prototype.getInternalMessages.apply(this, arguments);\n\n // add internal messages for regexp source subscriptions\n if (typeof sourceMessage == 'string') {\n internalMessages = internalMessages || [];\n var internalMessagesHash = _.object(internalMessages, true);\n\n _.eachKey(this._patternInternalMessages, function(patternMessages) {\n var sourcePattern = patternMessages.pattern;\n\n if (sourcePattern.test(sourceMessage))\n patternMessages.forEach(function(message) {\n if (internalMessagesHash[message]) return;\n internalMessages.push(message);\n internalMessagesHash[message] = true;\n });\n });\n } \n\n return internalMessages;\n}\n",
- "'use strict';\n\nvar Mixin = require('../abstract/mixin')\n , MessengerAPI = require('./m_api')\n , logger = require('../util/logger')\n , toBeImplemented = require('../util/error').toBeImplemented\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match;\n\n\n/**\n * `milo.classes.MessageSource`\n * An abstract class (subclass of [Mixin](../abstract/mixin.js.html)) for connecting [Messenger](./index.js.html) to external sources of messages (like DOM events) and defining higher level messages.\n * An instance of MessageSource can either be passed to Messenger constructor or later using `_setMessageSource` method of Messenger. Once set, MessageSource of Messenger cannot be changed.\n */\nvar MessageSource = _.createSubclass(Mixin, 'MessageSource', true);\n\nmodule.exports = MessageSource;\n\n\n/**\n * ####MessageSource instance methods####\n *\n * - [init](#init) - initializes messageSource - called by Mixin superclass\n * - [setMessenger](#setMessenger) - connects Messenger to MessageSource, is called from `init` or `_setMessageSource` methods of [Messenger](./index.js.html).\n * - [onSubscriberAdded](#onSubscriberAdded) - called by Messenger to notify when the first subscriber for an internal message was added, so MessageSource can subscribe to source\n * - [onSubscriberRemoved](#onSubscriberRemoved) - called by Messenger to notify when the last subscriber for an internal message was removed, so MessageSource can unsubscribe from source\n * - [dispatchMessage](#dispatchMessage) - dispatches source message. MessageSource subclass should implement mechanism when on actual source message this method is called.\n *\n * Methods below should be implemented in subclass:\n *\n * - [trigger](#trigger) - triggers messages on the source (an optional method)\n * - [addSourceSubscriber](#addSourceSubscriber) - adds listener/subscriber to external message\n * - [removeSourceSubscriber](#removeSourceSubscriber) - removes listener/subscriber from external message\n */\n_.extendProto(MessageSource, {\n init: init,\n destroy: MessageSource$destroy,\n setMessenger: setMessenger,\n onSubscriberAdded: onSubscriberAdded,\n onSubscriberRemoved: onSubscriberRemoved, \n dispatchMessage: dispatchMessage,\n postMessage: postMessage,\n _prepareMessengerAPI: _prepareMessengerAPI,\n\n // Methods below must be implemented in subclass\n trigger: toBeImplemented,\n addSourceSubscriber: toBeImplemented,\n removeSourceSubscriber: toBeImplemented\n});\n\n\n/**\n * MessageSource instance method.\n * Called by Mixin constructor.\n * MessageSource constructor should be passed the same parameters as this method signature.\n * If an instance of [MessengerAPI](./m_api.js.html) is passed as the third parameter, it extends MessageSource functionality to allow it to define new messages, to filter messages based on their data and to change message data. See [MessengerAPI](./m_api.js.html).\n *\n * @param {Object} hostObject Optional object that stores the MessageSource on one of its properties. It is used to proxy methods of MessageSource.\n * @param {Object[String]} proxyMethods Optional map of method names; key - proxy method name, value - MessageSource's method name.\n * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI.\n */\nfunction init(hostObject, proxyMethods, messengerAPI) {\n this._prepareMessengerAPI(messengerAPI);\n}\n\n\n/**\n * Destroys message source\n */\nfunction MessageSource$destroy() {\n if (this.messengerAPI)\n this.messengerAPI.destroy();\n}\n\n\n/**\n * MessageSource instance method.\n * Sets reference to Messenger instance.\n *\n * @param {Messenger} messenger reference to Messenger instance linked to this MessageSource\n */\nfunction setMessenger(messenger) {\n _.defineProperty(this, 'messenger', messenger);\n}\n\n\n/**\n * MessageSource instance method.\n * Prepares [MessengerAPI](./m_api.js.html) passed to constructor by proxying its methods to itself or if MessengerAPI wasn't passed defines two methods to avoid checking their availability every time the message is dispatched.\n *\n * @private\n * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI\n */\nfunction _prepareMessengerAPI(messengerAPI) {\n check(messengerAPI, Match.Optional(MessengerAPI));\n\n if (! messengerAPI)\n messengerAPI = new MessengerAPI;\n\n _.defineProperty(this, 'messengerAPI', messengerAPI);\n}\n\n\n/**\n * MessageSource instance method.\n * Subscribes to external source using `addSourceSubscriber` method that should be implemented in subclass.\n * This method is called by [Messenger](./index.js.html) when the first subscriber to the `message` is added.\n * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.addInternalMessage` will return undefined if this `sourceMessage` was already subscribed to to prevent duplicate subscription.\n *\n * @param {String} message internal Messenger message that has to be subscribed to at the external source of messages.\n */\nfunction onSubscriberAdded(message) {\n var newSourceMessage = this.messengerAPI.addInternalMessage(message);\n if (typeof newSourceMessage != 'undefined')\n this.addSourceSubscriber(newSourceMessage);\n}\n\n\n/**\n * MessageSource instance method.\n * Unsubscribes from external source using `removeSourceSubscriber` method that should be implemented in subclass.\n * This method is called by [Messenger](./index.js.html) when the last subscriber to the `message` is removed.\n * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.removeInternalMessage` will return undefined if this `sourceMessage` was not yet subscribed to to prevent unsubscription without previous subscription.\n *\n * @param {String} message internal Messenger message that has to be unsubscribed from at the external source of messages.\n */\nfunction onSubscriberRemoved(message) {\n var removedSourceMessage = this.messengerAPI.removeInternalMessage(message);\n if (typeof removedSourceMessage != 'undefined')\n this.removeSourceSubscriber(removedSourceMessage);\n}\n\n\n/**\n * MessageSource instance method.\n * Dispatches sourceMessage to Messenger.\n * Mechanism that calls this method when the source message is received should be implemented by subclass (see [DOMEventsSource](../components/msg_src/dom_events.js.html) for example).\n * Delegates to supplied or default [MessengerAPI](./m_api.js.html) to create internal message data (`createInternalData`) and to filter the message based on its data and/or message (`filterSourceMessage`).\n * Base MessengerAPI class implements these two methods in a trivial way (`createInternalData` simply returns external data, `filterSourceMessage` returns `true`), they are meant to be implemented by subclass.\n *\n * @param {String} sourceMessage source message received from external source\n * @param {Object} sourceData data received from external source\n */\nfunction dispatchMessage(sourceMessage, sourceData) {\n var api = this.messengerAPI\n , internalMessages = api.getInternalMessages(sourceMessage);\n\n if (internalMessages) \n internalMessages.forEach(function (message) {\n var internalData = api.createInternalData(sourceMessage, message, sourceData);\n\n var shouldDispatch = api.filterSourceMessage(sourceMessage, message, internalData);\n if (shouldDispatch) \n this.postMessage(message, internalData); \n \n }, this);\n}\n\n\n/**\n * Posts message on the messenger. This method is separated so specific message sources can make message dispatch synchronous by using `postMessageSync`\n * \n * @param {String} message\n * @param {Object} data\n */\nfunction postMessage(message, data) {\n this.messenger.postMessage(message, data);\n}\n",
- "'use strict';\n\n\nvar MessageSource = require('./m_source')\n , _ = require('mol-proto')\n , check = require('../util/check');\n\n\n/**\n * Subclass of MessageSource that allows to connect Messenger to another Messenger using it as external source.\n */\nvar MessengerMessageSource = _.createSubclass(MessageSource, 'MessengerMessageSource');\n\nmodule.exports = MessengerMessageSource;\n\n\n/**\n * ####MessengerMessageSource instance methods####\n */\n_.extendProto(MessengerMessageSource, {\n init: init,\n addSourceSubscriber: addSourceSubscriber,\n removeSourceSubscriber: removeSourceSubscriber,\n postMessage: MessengerMessageSource$postMessage\n});\n\n/**\n * Initializes MessengerMessageSource\n * Defines one parameter in addition to [MessageSource](./m_source.js.html) parameters\n *\n * @param {Messenger} sourceMessenger messenger this message source connects to\n */\nfunction init(hostObject, proxyMethods, messengerAPI, sourceMessenger) {\n MessageSource.prototype.init.apply(this, arguments);\n this.sourceMessenger = sourceMessenger;\n}\n\n\n/**\n * Subscribes to source message. See [MessageSource](./m_source.js.html) docs.\n *\n * @param {String|Regex} sourceMessage source message to subscribe to\n */\nfunction addSourceSubscriber(sourceMessage) {\n this.sourceMessenger.onSync(sourceMessage, { context: this, subscriber: this.dispatchMessage });\n}\n\n\n/**\n * Unsubscribes from source message. See [MessageSource](./m_source.js.html) docs.\n *\n * @param {String|Regex} sourceMessage source message to unsubscribe from\n */\nfunction removeSourceSubscriber(sourceMessage) {\n this.sourceMessenger.off(sourceMessage, { context: this, subscriber: this.dispatchMessage });\n}\n\n\n/**\n * Overrides defalut message source to dispatch messages synchronously\n * \n * @param {String} message\n * @param {Object} data\n */\nfunction MessengerMessageSource$postMessage(message, data) {\n this.messenger.postMessageSync(message, data);\n}\n",
- "'use strict';\n\nvar core = require('milo-core');\nvar _ = require('mol-proto');\n\n\n// register included facets\nrequire('./use_facets');\n\n// register included components\nrequire('./use_components');\n\n\n/**\n * `milo`\n *\n * A minimalist browser framework that binds DOM elements to JS components and components to models.\n *\n * `milo` is available as global object in the browser.\n * At the moment it is not possiible to require it with browserify to have it bundled with the app because of the way [brfs](https://github.com/substack/brfs) browserify plugin is implemented.\n * It is possible though to require `milo` with node to use universal parts of the framework (abstract classes, Messenger, Model, etc.):\n * ```\n * var milo = require('mol-milo');\n * ```\n * \n * `milo` itself is a function that in the browser can be used to delay execution until DOM is ready.\n */\nfunction milo(func) {\n milo.util.domReady(func);\n}\n\n\n/**\n * ####Milo packages####\n *\n * - [loader](./loader.js.html) - loading subviews into page\n * - [binder](./binder.js.html) - components instantiation and binding of DOM elements to them\n * - [minder](./minder.js.html) - data reactivity, one or two way, shallow or deep, as you like it\n * - [mail](./mail/index.js.html) - applicaiton level messenger, also connects to messages from other windows dispatched with `window.postMessage`.\n * - [config](./config.js.html) - milo configuration\n * - [util](./util/index.js.html) - logger, request, dom, check, error, etc.\n * - [classes](./classes.js.html) - abstract and base classes\n * - [attributes](./attributes/index.js.html) - classes that wrap DOM elements attributes recognized by milo\n * - [ComponentFacet](./components/c_facet.js.html) - base class of Component facet\n * - [Component](./components/c_class.js.html) - base Component class\n * - [Messenger](./messenger/index.js.html) - generic Messenger used in most other milo classes, can be mixed into app classes too.\n * - [Model](./model/index.js.html) - Model class that emits messages on changes to any depth without timer based watching\n * - [registry](./registry.js.html) - registries of fasets and components classes\n */\n_.extend(milo, {\n Messenger: core.Messenger,\n Model: core.Model,\n minder: core.minder,\n loader: require('./loader'),\n binder: require('./binder'),\n mail: require('./services/mail'),\n window: require('./services/window'),\n config: require('./config'),\n util: require('./util'),\n classes: require('./classes'),\n attributes: require('./attributes'),\n ComponentFacet: require('./components/c_facet'),\n Component: require('./components/c_class'),\n Command: require('./command'),\n registry: require('./registry'),\n milo_version: '0.1.4',\n createComponentClass: require('./util/create_component_class'),\n destroy: destroy\n});\n\n\n// export for node/browserify\nif (typeof module == 'object' && module.exports) \n module.exports = milo;\n\n// global milo for browser\nif (typeof window == 'object') {\n window.milo = milo;\n milo.mail.trigger('miloready');\n}\n\n\nfunction destroy() {\n milo.mail.destroy();\n milo.window.destroy();\n milo.minder.destroy();\n milo.util.destroy();\n}\n",
- "'use strict';\n\n\nvar facetsRegistry = require('../components/c_facets/cf_registry')\n , logger = require('../util/logger')\n , config = require('../config')\n , pathUtils = require('./path_utils')\n , _ = require('mol-proto');\n\n/**\n * Utility function to process \"changedata\" messages emitted by Connector object.\n */\nmodule.exports = changeDataHandler;\n\n\n_.extend(changeDataHandler, {\n setTransactionFlag: setTransactionFlag,\n getTransactionFlag: getTransactionFlag,\n passTransactionFlag: passTransactionFlag,\n postTransactionFinished: postTransactionFinished\n});\n\n\n/**\n * Change data uses hidden property on accessor methods to pass flag that the accessor is executed as a part of change transaction.\n * Accessor methods are supposed to store this flag in a local variable and to clear it (because another accessor can be executed in or out of transaction) using `getTransactionFlag`\n *\n * @private\n * @param {Function} func accessor method reference\n * @param {Boolean} flag a flag to be set\n */\nfunction setTransactionFlag(func, flag) {\n _.defineProperty(func, '__inChangeTransaction', flag, _.CONF | _.WRIT);\n}\n\n\n/**\n * Retrieves and clears transaction flag from accessor method\n *\n * @private\n * @param {Function} func accessor method reference\n * @return {Boolean}\n */\nfunction getTransactionFlag(func) {\n var inTransaction = func.__inChangeTransaction;\n delete func.__inChangeTransaction;\n return inTransaction;\n}\n\n\nfunction passTransactionFlag(fromFunc, toFunc) {\n var inTransaction = getTransactionFlag(fromFunc);\n setTransactionFlag(toFunc, inTransaction);\n return inTransaction;\n}\n\n\n/**\n * Posts message on this to indicate the end of transaction unless `inChangeTransaction` is `true`.\n */\nfunction postTransactionFinished() {\n this.postMessageSync('datachanges', { transaction: false, changes: [] });\n}\n\n\n/**\n * subscriber to \"changedata\" event emitted by [Connector](./connector.js.html) object to enable reactive connections\n * Used by Data facet, Model and ModelPath. Can be used by any object that implements get/set/del/splice api and sets data deeply to the whole tree.\n * Object should call `changeDataHandler.initialize.call(this)` in its constructor.\n * TODO: optimize messages list to avoid setting duplicate values down the tree\n *\n * @param {String} msg should be \"changedata\" here\n * @param {Object} data batch of data change desciption objects\n * @param {Function} callback callback to call before and after the data is processed\n */\nfunction changeDataHandler(message, data, callback) {\n processChanges.call(this, data.changes, callback);\n}\n\n\n// map of message types to methods\nvar CHANGE_TYPE_TO_METHOD_MAP = {\n 'added': 'set',\n 'changed': 'set',\n 'deleted': 'del',\n 'removed': 'del'\n};\n\n\n/**\n * Processes queued \"changedata\" messages.\n * Posts \"changestarted\" and \"changecompleted\" messages and calls callback\n *\n * @param {[Function]} callback optional callback that is called with `(null, false)` parameters before change processing starts and `(null, true)` after it's finished.\n */\nfunction processChanges(transaction, callback) {\n notify.call(this, callback, false);\n processTransaction.call(this,\n prepareTransaction(\n validateTransaction(transaction)));\n notify.call(this, callback, true);\n}\n\n\nfunction notify(callback, changeFinished) {\n callback && callback(null, changeFinished);\n this.postMessage(changeFinished ? 'changecompleted' : 'changestarted');\n}\n\n\n/**\n * Checks that all messages from the transaction come from the same source.\n * Hack: reverses the transaction if it comes from the Data facet\n * Returns the reference to the transaction (for chaining)\n * \n * @param {Array} transaction transaction of data changes\n * @return {Array} \n */\nfunction validateTransaction(transaction) {\n var source = transaction[0].source\n , sameSource = true;\n\n if (transaction.length > 1) {\n for (var i = 1, len = transaction.length; i < len; i++)\n if (transaction[i].source != source) {\n logger.error('changedata: changes from different sources in the same transaction, sources:', transaction[i].source.name, source.name);\n sameSource = false;\n source = transaction[i].source;\n }\n }\n\n return transaction;\n}\n\n\nfunction prepareTransaction(transaction) {\n var todo = []\n , pathsToSplice = []\n , pathsToChange = []\n , hadSplice\n , exitLoop = {};\n\n\n try { transaction.forEach(checkChange); }\n catch (e) { if (e != exitLoop) throw e; }\n\n return todo;\n\n\n function checkChange(data) {\n (data.type == 'splice' ? checkSplice : checkMethod)(data);\n }\n\n\n function checkSplice(data) {\n var parsedPath = pathUtils.parseAccessPath(data.path);\n var parentPathChanged = pathsToChange.some(function(parentPath) {\n if (parsedPath.length < parentPath.length) return;\n return _pathIsParentOf(parentPath, parsedPath);\n });\n\n if (parentPathChanged) return;\n\n todo.push(data);\n\n if (! config.debug) throw exitLoop;\n pathsToSplice.push(parsedPath);\n hadSplice = true;\n }\n\n\n function checkMethod(data) {\n var parsedPath = pathUtils.parseAccessPath(data.path);\n var parentPathSpliced = pathsToSplice && pathsToSplice.some(function(parentPath) {\n if (parsedPath.length <= parentPath.length\n || parsedPath[parentPath.length].syntax != 'array') return;\n return _pathIsParentOf(parentPath, parsedPath);\n });\n\n if (parentPathSpliced) return;\n if (hadSplice) logger.error('changedata: child change is executed after splice; probably data source did not emit message with data.type==\"finished\"');\n\n var parentPathChanged = pathsToChange.some(function(parentPath) {\n if (parsedPath.length <= parentPath.length) return;\n return _pathIsParentOf(parentPath, parsedPath);\n });\n\n if (parentPathChanged) return;\n\n pathsToChange.push(parsedPath);\n\n todo.push(data);\n }\n\n\n function _pathIsParentOf(parentPath, childPath) {\n return parentPath.every(function(pathNode, index) {\n return pathNode.property == childPath[index].property;\n });\n }\n}\n\n\nfunction processTransaction(transaction) {\n transaction.forEach(processChange, this);\n postTransactionFinished.call(this, false);\n\n function processChange(data) {\n var modelPath = this.path(data.path, data.type != 'removed' && data.type != 'deleted');\n if (! modelPath) return;\n (data.type == 'splice' ? executeSplice : executeMethod)(modelPath, data);\n }\n}\n\n\nfunction executeSplice(modelPath, data) {\n var index = data.index\n , howMany = data.removed.length\n , spliceArgs = [index, howMany];\n\n spliceArgs = spliceArgs.concat(data.newValue.slice(index, index + data.addedCount));\n setTransactionFlag(modelPath.splice, true);\n modelPath.splice.apply(modelPath, spliceArgs);\n}\n\n\nfunction executeMethod(modelPath, data) {\n var methodName = CHANGE_TYPE_TO_METHOD_MAP[data.type];\n if (methodName) {\n setTransactionFlag(modelPath[methodName], true);\n modelPath[methodName](data.newValue);\n } else\n logger.error('unknown data change type');\n}\n",
- "'use strict';\n\nvar ModelPath = require('./m_path')\n , synthesize = require('./synthesize')\n , pathUtils = require('./path_utils')\n , changeDataHandler = require('./change_data')\n , Messenger = require('../messenger')\n , MessengerMessageSource = require('../messenger/msngr_source')\n , ModelMsgAPI = require('./m_msg_api')\n , ModelError = require('../util/error').Model\n , Mixin = require('../abstract/mixin')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match\n , logger = require('../util/logger')\n , jsonParse = require('../util/json_parse');\n\n\nmodule.exports = Model;\n\n\n/**\n * `milo.Model`\n * Model class instantiates objects that allow deep data access with __safe getters__ that return undefined (rather than throwing exception) when properties/items of unexisting objects/arrays are requested and __safe setters__ that create object trees when properties/items of unexisting objects/arrays are set and also post messages to allow subscription on changes and enable data reactivity.\n * Reactivity is implememnted via [Connector](./connector.js.html) that can be instantiated either directly or with more convenient interface of [milo.minder](../minder.js.html). At the moment model can be connected to [Data facet](../components/c_facets/Data.js.html) or to another model or [ModelPath](./m_path.js.html).\n * Model constructor returns objects that are functions at the same time; when called they return ModelPath objects that allow get/set access to any point in model data. See [ModelData](#ModelData) below.\n *\n * You can subscribe to model changes with `on` method by passing model access path in place of message, pattern or string with any number of stars to subscribe to a certain depth in model (e.g., `'***'` to subscribe to three levels).\n *\n * @constructor\n * @param {Object|Array} data optional initial array data. If it is planned to connect model to view it is usually better to instantiate an empty Model (`var m = new Model`), connect it to [Component](../components/c_class.js.html)'s [Data facet](../components/c_facets/Data.js.html) (e.g., `milo.minder(m, '<<->>', c.data);`) and then set the model with `m.set(data)` - the view will be automatically updated.\n * @param {Object} hostObject optional object that hosts model on one of its properties. Can be used when model itself is the context of the message subscriber and you need to travers to this object (although it is possible to set any context). Can also be used to proxy model's methods to the host like [Model facet](../components/c_facets/ModelFacet.js.html) is doing.\n * @param {Object} options pass { reactive: false } to use model without messaging when it is not needed - it makes it much faster\n * @return {Model}\n */\nfunction Model(data, hostObject, options) {\n // `model` will be returned by constructor instead of `this`. `model`\n // (`modelPath` function) should return a ModelPath object with \"synthesized\" methods\n // to get/set model properties, to subscribe to property changes, etc.\n // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.\n var model = function modelPath(accessPath) { // , ... arguments that will be interpolated\n return Model$path.apply(model, arguments);\n };\n model.__proto__ = Model.prototype;\n\n model._hostObject = hostObject;\n model._options = options || {};\n\n if (model._options.reactive !== false) {\n model._prepareMessengers();\n // subscribe to \"changedata\" message to enable reactive connections\n model.onSync('changedata', changeDataHandler);\n }\n\n if (data) model._data = data;\n\n return model;\n}\n\nModel.prototype.__proto__ = Model.__proto__;\n\n\n/**\n * ####Model instance methods####\n *\n * - [path](#path) - returns ModelPath object that allows access to any point in Model\n * - [get](#Model$get) - get model data\n * - set - set model data, synthesized\n * - splice - splice model data (as array or pseudo-array), synthesized\n * - [len](./m_path.js.html#ModelPath$len) - returns length of array (or pseudo-array) in model in safe way, 0 if no length is set\n * - [push](./m_path.js.html#ModelPath$push) - add items to the end of array (or pseudo-array) in model\n * - [pop](./m_path.js.html#ModelPath$pop) - remove item from the end of array (or pseudo-array) in model\n * - [unshift](./m_path.js.html#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in model\n * - [shift](./m_path.js.html#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in model\n * - [proxyMessenger](#proxyMessenger) - proxy model's Messenger methods to host object\n * - [proxyMethods](#proxyMethods) - proxy model methods to host object\n */\n_.extendProto(Model, {\n path: Model$path,\n get: Model$get,\n proxyMessenger: proxyMessenger, // deprecated, should not be used\n proxyMethods: proxyMethods,\n _prepareMessengers: _prepareMessengers,\n _getHostObject: _getHostObject,\n destroy: Model$destroy\n});\n\n// set, del, splice are added to model\n_.extendProto(Model, synthesize.modelMethods);\n\n\n/**\n * - Path: ModelPath class as `milo.Model.Path`\n * - [registerWithDOMStorage](#Model$$registerWithDOMStorage)\n */\n_.extend(Model, {\n Path: ModelPath,\n registerWithDOMStorage: Model$$registerWithDOMStorage,\n useWith: Model$$useWith\n});\n\n\n/**\n * Expose Messenger methods on Facet prototype\n */\nvar MESSENGER_PROPERTY = '_messenger';\nMessenger.useWith(Model, MESSENGER_PROPERTY, Messenger.defaultMethods);\n\n\n/**\n * ModelPath methods added to Model prototype\n */\n['len', 'push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {\n var method = ModelPath.prototype[methodName];\n _.defineProperty(Model.prototype, methodName, method);\n});\n\n\n/**\n * Model instance method.\n * Get model data.\n *\n * @return {Any}\n */\nfunction Model$get() {\n return this._data;\n}\n\n\n/**\n * Model instance method.\n * Returns ModelPath object that implements the same API as model but allows access to any point inside model as defined by `accessPath`.\n * See [ModelPath](./m_path.js.html) class for more information.\n *\n * @param {String} accessPath string that defines path to access model.\n * Path string consists of parts to define either property access (`\".name\"` to access property name) or array item access (`\"[1]\"` to access item with index 1).\n * Access path can contain as many parts as necessary (e.g. `\".list[0].name\"` to access property `name` in the first element of array stored in property `list`.\n * @param {List} arguments additional arguments of this method can be used to create interpolated paths.\n * E.g. `m.path(\"[$1].$2\", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m(\"[\" + id + \"].\" + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.\n * @return {ModelPath}\n */\nfunction Model$path(accessPath) { // , ... arguments that will be interpolated\n if (! accessPath) return this;\n\n // \"null\" is context to pass to ModelPath, first parameter of bind\n // \"this\" (model) is added in front of all arguments\n _.splice(arguments, 0, 0, null, this);\n\n // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...\n return new (Function.prototype.bind.apply(ModelPath, arguments));\n}\n\n\n/**\n * Model instance method.\n * Proxy model's Messenger methods to host object.\n *\n * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.\n */\nfunction proxyMessenger(modelHostObject) {\n modelHostObject = modelHostObject || this._hostObject;\n Mixin.prototype._createProxyMethods.call(this[MESSENGER_PROPERTY], Messenger.defaultMethods, modelHostObject);\n}\n\n\nvar modelMethodsToProxy = ['path', 'get', 'set', 'del', 'splice', 'len', 'push', 'pop', 'unshift', 'shift'];\n\n\n/**\n * Expose model methods on\n * See same method in Mixin class for parameters meaning\n *\n * @param {Function} hostClass\n * @param {[type]} instanceKey\n * @param {[type]} mixinMethods optional\n */\nfunction Model$$useWith(hostClass, instanceKey, mixinMethods) {\n mixinMethods = mixinMethods || modelMethodsToProxy;\n Mixin.useWith.call(Model, hostClass, instanceKey, mixinMethods);\n}\n\n\n/**\n * Model instance method.\n * Proxy model methods to host object.\n *\n * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.\n */\nfunction proxyMethods(modelHostObject) {\n modelHostObject = modelHostObject || this._hostObject;\n Mixin.prototype._createProxyMethods.call(this, modelMethodsToProxy, modelHostObject);\n}\n\n\n/**\n * Model instance method.\n * Create and connect internal and external model's messengers.\n * External messenger's methods are proxied on the model and they allows \"*\" subscriptions.\n */\nfunction _prepareMessengers() {\n // model will post all its changes on internal messenger\n var internalMessenger = new Messenger(this, undefined, undefined);\n\n // message source to connect internal messenger to external\n var internalMessengerSource = new MessengerMessageSource(this, undefined, new ModelMsgAPI, internalMessenger);\n\n // external messenger to which all model users will subscribe,\n // that will allow \"*\" subscriptions and support \"changedata\" message api.\n var externalMessenger = new Messenger(this, undefined, internalMessengerSource);\n\n _.defineProperty(this, MESSENGER_PROPERTY, externalMessenger);\n _.defineProperty(this, '_internalMessenger', internalMessenger);\n}\n\n\nfunction _getHostObject() {\n return this._hostObject;\n}\n\n\nfunction Model$$registerWithDOMStorage() {\n var DOMStorage = require('../util/storage');\n DOMStorage.registerDataType('Model', Model_domStorageSerializer, Model_domStorageParser);\n DOMStorage.registerDataType('ModelPath', Model_domStorageSerializer, Model_domStorageParser, 'Model');\n}\n\n\nfunction Model_domStorageSerializer(value) {\n var data = value.get();\n return JSON.stringify(data);\n}\n\n\nfunction Model_domStorageParser(valueStr) {\n var data = jsonParse(valueStr);\n return new Model(data);\n}\n\n\nfunction Model$destroy() {\n this[MESSENGER_PROPERTY].destroy();\n this._internalMessenger.destroy();\n this._destroyed = true;\n}\n",
- "'use strict';\n\nvar MessengerRegexpAPI = require('../messenger/m_api_rx')\n , pathUtils = require('./path_utils')\n , _ = require('mol-proto');\n\n\n/**\n * Subclass of MessengerRegexpAPI that is used to translate messages of external messenger of Model to internal messenger of Model.\n */\nvar ModelMsgAPI = _.createSubclass(MessengerRegexpAPI, 'ModelMsgAPI');\n\nmodule.exports = ModelMsgAPI;\n\n\n/**\n * ####ModelMsgAPI instance methods####\n *\n * - [translateToSourceMessage](#translateToSourceMessage) - translates subscription paths with \"*\"s to regex, leaving other strings untouched\n */\n_.extendProto(ModelMsgAPI, {\n translateToSourceMessage: translateToSourceMessage,\n});\n\n\n/**\n * ModelMsgAPI instance method\n * Translates subscription paths with \"*\"s to regex, leaving other strings untouched.\n *\n * @param {String} accessPath relative access path to be translated\n * @return {RegExp|String}\n */\nfunction translateToSourceMessage(accessPath) {\n if (accessPath instanceof RegExp) return accessPath;\n\n return pathUtils.createRegexPath(accessPath);\n}\n",
- "'use strict';\n\nvar synthesize = require('./synthesize')\n , pathUtils = require('./path_utils')\n , changeDataHandler = require('./change_data')\n , Messenger = require('../messenger')\n , ModelPathMsgAPI = require('./path_msg_api')\n , MessengerMessageSource = require('../messenger/msngr_source')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match;\n\n\nmodule.exports = ModelPath;\n\n\n/**\n * `milo.Model.Path`\n * ModelPath object that allows access to any point inside [Model](./index.js.html) as defined by `accessPath`\n *\n * @constructor\n * @param {Model} model Model instance that ModelPath gives access to.\n * @param {String} accessPath string that defines path to access model.\n * Path string consists of parts to define either property access (`\".name\"` to access property name) or array item access (`\"[1]\"` to access item with index 1).\n * Access path can contain as many parts as necessary (e.g. `\".list[0].name\"` to access property `name` in the first element of array stored in property `list`.\n * @param {List} arguments additional arguments of this method can be used to create interpolated paths.\n * E.g. `m.path(\"[$1].$2\", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m(\"[\" + id + \"].\" + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.\n * @return {ModelPath}\n */\nfunction ModelPath(model, path) { // ,... - additional arguments for interpolation\n // check(model, Model);\n check(path, String);\n\n // `modelPath` will be returned by constructor instead of `this`. `modelPath`\n // (`modelPath_path` function) should also return a ModelPath object with \"synthesized\" methods\n // to get/set model properties, to subscribe to property changes, etc.\n // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.\n var modelPath = function modelPath_path(accessPath) { // , ... arguments that will be interpolated\n return ModelPath$path.apply(modelPath, arguments);\n };\n modelPath.__proto__ = ModelPath.prototype;\n\n\n _.defineProperties(modelPath, {\n _model: model,\n _path: path,\n _args: _.slice(arguments, 1), // path will be the first element of this array\n _options: model._options\n });\n\n // parse access path\n var parsedPath = pathUtils.parseAccessPath(path);\n\n // compute access path string\n _.defineProperty(modelPath, '_accessPath', interpolateAccessPath(parsedPath, modelPath._args));\n\n if (modelPath._options.reactive !== false) {\n // messenger fails on \"*\" subscriptions\n modelPath._prepareMessenger();\n // subscribe to \"changedata\" message to enable reactive connections\n modelPath.onSync('changedata', changeDataHandler);\n }\n\n // compiling getter and setter\n var methods = synthesize(path, parsedPath);\n\n // adding methods to model path\n _.defineProperties(modelPath, methods);\n\n Object.freeze(modelPath);\n\n return modelPath;\n}\n\nModelPath.prototype.__proto__ = ModelPath.__proto__;\n\n\n/**\n * Interpolates path elements to compute real path\n *\n * @param {Array} parsedPath parsed path - array of path nodes\n * @param {Array} args path interpolation arguments, args[0] is path itself\n * @return {String}\n */\nfunction interpolateAccessPath(parsedPath, args) {\n return parsedPath.reduce(function(accessPathStr, currNode, index) {\n var interpolate = currNode.interpolate;\n return accessPathStr +\n (interpolate\n ? (currNode.syntax == 'array'\n ? '[' + args[interpolate] + ']'\n : '.' + args[interpolate])\n : currNode.property);\n }, '');\n}\n\n\n/**\n * ####ModelPath instance methods####\n *\n * - [path](#ModelPath$path) - gives access to path inside ModelPath\n * - get - synthesized\n * - set - synthesized\n * - splice - splice model data (as array or pseudo-array), synthesized\n * - [len](#ModelPath$len) - returns length of array (or pseudo-array) in safe way, 0 if no length is set\n * - [push](#ModelPath$push) - add items to the end of array (or pseudo-array) in ModelPath\n * - [pop](#ModelPath$pop) - remove item from the end of array (or pseudo-array) in ModelPath\n * - [unshift](#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in ModelPath\n * - [shift](#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in ModelPath\n */\n_.extendProto(ModelPath, {\n path: ModelPath$path,\n len: ModelPath$len,\n push: ModelPath$push,\n pop: ModelPath$pop,\n unshift: ModelPath$unshift,\n shift: ModelPath$shift,\n _prepareMessenger: _prepareMessenger,\n _getDefinition: _getDefinition,\n destroy: ModelPath$destroy\n});\n\n\n_.extend(ModelPath, {\n _createFromDefinition: _createFromDefinition\n})\n\n\n/**\n * Expose Messenger methods on Facet prototype\n */\nvar MESSENGER_PROPERTY = '_messenger';\nMessenger.useWith(ModelPath, MESSENGER_PROPERTY, Messenger.defaultMethods);\n\n\n/**\n * ModelPath instance method\n * Gives access to path inside ModelPath. Method works similarly to [path method](#Model$path) of model, using relative paths.\n *\n * @param {String} accessPath string that defines path to access model.\n * Path string consists of parts to define either property access (`\".name\"` to access property name) or array item access (`\"[1]\"` to access item with index 1).\n * Access path can contain as many parts as necessary (e.g. `\".list[0].name\"` to access property `name` in the first element of array stored in property `list`.\n * @param {List} arguments additional arguments of this method can be used to create interpolated paths.\n * E.g. `m.path(\"[$1].$2\", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m(\"[\" + id + \"].\" + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.\n * @return {ModelPath}\n */\nfunction ModelPath$path(accessPath) { // , ... arguments that will be interpolated\n if (! accessPath) return this;\n\n var thisPathArgsCount = this._args.length - 1;\n\n if (thisPathArgsCount > 0) {// this path has interpolated arguments too\n accessPath = accessPath.replace(/\\$[1-9][0-9]*/g, function(str) {\n return '$' + (+str.slice(1) + thisPathArgsCount);\n });\n }\n\n var newPath = this._path + accessPath;\n\n // this._model is added in front of all arguments as the first parameter\n // of ModelPath constructor\n var args = [this._model, newPath]\n .concat(this._args.slice(1)) // remove old path from _args, as it is 1 based\n .concat(_.slice(arguments, 1)); // add new interpolation arguments\n\n // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...\n return _.newApply(ModelPath, args);\n}\n\n\n/**\n * ModelPath and Model instance method\n * Returns length property and sets it to 0 if it wasn't set.\n *\n * @return {Any}\n */\nfunction ModelPath$len() {\n return this.path('.length').get() || 0;\n}\n\n\n/**\n * ModelPath and Model instance method\n * Adds items to the end of array (or pseudo-array). Returns new length.\n *\n * @param {List} arguments list of items that will be added to array (pseudo array)\n * @return {Integer}\n */\nfunction ModelPath$push() { // arguments\n var length = this.len();\n var newLength = length + arguments.length;\n\n _.splice(arguments, 0, 0, length, 0);\n this.splice.apply(this, arguments);\n\n return newLength;\n}\n\n\n/**\n * ModelPath and Model instance method\n * Removes item from the end of array (or pseudo-array). Returns this item.\n *\n * @return {Any}\n */\nfunction ModelPath$pop() {\n return this.splice(this.len() - 1, 1)[0];\n}\n\n\n/**\n * ModelPath and Model instance method\n * Inserts items to the beginning of the array. Returns new length.\n *\n * @param {List} arguments items to be inserted in the beginning of array\n * @return {Integer}\n */\nfunction ModelPath$unshift() { // arguments\n var length = this.len();\n length += arguments.length;\n\n _.splice(arguments, 0, 0, 0, 0);\n this.splice.apply(this, arguments);\n\n return length;\n}\n\n\n/**\n * ModelPath and Model instance method\n * Removes the item from the beginning of array (or pseudo-array). Returns this item.\n *\n * @return {Any}\n */\nfunction ModelPath$shift() { // arguments\n return this.splice(0, 1)[0];\n}\n\n\n/**\n * ModelPath instance method\n * Initializes ModelPath mesenger with Model's messenger as its source ([MessengerMessageSource](../messenger/msngr_source.js.html)) and [ModelPathMsgAPI](./path_msg_api.js.html) as [MessengerAPI](../messenger/m_api.js.html)\n */\nfunction _prepareMessenger() {\n var mPathAPI = new ModelPathMsgAPI(this._accessPath);\n\n // create MessengerMessageSource connected to Model's messenger\n var modelMessageSource = new MessengerMessageSource(this, undefined, mPathAPI, this._model);\n\n // create messenger with model passed as hostObject (default message dispatch context)\n // and without proxying methods (we don't want to proxy them to Model)\n var mPathMessenger = new Messenger(this, undefined, modelMessageSource);\n\n // store messenger on ModelPath instance\n _.defineProperty(this, MESSENGER_PROPERTY, mPathMessenger);\n}\n\n\n/**\n * Returns the object allowing to recreate model path\n *\n * @return {Object}\n */\nfunction _getDefinition() {\n return {\n model: this._model,\n path: this._path,\n args: this._args\n };\n}\n\n\n/**\n * Class method\n * Creates modelPath object from definition created by _getDefinition\n *\n * @param {Object} definition\n * @return {ModelPath}\n */\nfunction _createFromDefinition(definition) {\n check(definition, {\n model: Function, // Model\n path: String,\n args: Array\n });\n\n var m = definition.model;\n\n return m.apply(m, definition.args);\n}\n\n\nfunction ModelPath$destroy() {\n this[MESSENGER_PROPERTY].destroy();\n}\n",
- "'use strict';\n\n\nvar modelUtils = {\n normalizeSpliceIndex: normalizeSpliceIndex\n};\n\nmodule.exports = modelUtils;\n\n\nfunction normalizeSpliceIndex(spliceIndex, length) {\n return spliceIndex > length\n ? length\n : spliceIndex >= 0\n ? spliceIndex\n : spliceIndex + length > 0\n ? spliceIndex + length\n : 0;\n}\n",
- "'use strict';\n\nvar MessengerAPI = require('../messenger/m_api')\n , pathUtils = require('./path_utils')\n , logger = require('../util/logger')\n , _ = require('mol-proto');\n\n\n/**\n * Subclass of MessengerAPI that is used to translate messages of Messenger on ModelPath to Messenger on Model.\n */\nvar ModelPathMsgAPI = _.createSubclass(MessengerAPI, 'ModelPathMsgAPI');\n\nmodule.exports = ModelPathMsgAPI;\n\n\n/**\n * ####ModelPathMsgAPI instance methods####\n *\n * - [init](#init) - initializes ModelPathMsgAPI\n * - [translateToSourceMessage](#translateToSourceMessage) - translates relative access paths of ModelPath to full path of Model\n * - [createInternalData](#createInternalData) - changes path in message on model to relative path and adds `fullPath` property to message data\n */\n_.extendProto(ModelPathMsgAPI, {\n init: init,\n translateToSourceMessage: translateToSourceMessage,\n createInternalData: createInternalData,\n});\n\n\n/**\n * ModelPathMsgAPI instance method\n * Called by MessengerAPI constructor.\n *\n * @param {String} rootPath root path of model path\n */\nfunction init(rootPath) {\n MessengerAPI.prototype.init.apply(this, arguments);\n this.rootPath = rootPath;\n}\n\n/**\n * ModelPathMsgAPI instance method\n * Translates relative access paths of ModelPath to full path of Model.\n *\n * @param {String} accessPath relative access path to be translated\n * @return {String}\n */\nfunction translateToSourceMessage(message) {\n // TODO should prepend RegExes\n // TODO should not prepend changedata too???\n if (message instanceof RegExp)\n return message;\n if (message == 'datachanges')\n return message;\n \n return this.rootPath + message;\n}\n\n\n/**\n * ModelPathMsgAPI instance method\n * Changes path in message on model to relative path and adds `fullPath` property to message data.\n *\n * @param {String} sourceMessage full access path on Model\n * @param {String} message relative access path on ModelPath\n * @param {Object} sourceData data received from Model, will be translated as described to be dispatched to ModelPath\n * @return {Object}\n */\nfunction createInternalData(sourceMessage, message, sourceData) {\n // TODO return on changedata too???\n if (message == 'datachanges') {\n var internalChanges = sourceData.changes\n .map(truncateChangePath, this)\n .filter(function(change) { return change; });\n var internalData = {\n changes: internalChanges,\n transaction: sourceData.transaction\n };\n\n return internalData\n }\n\n var internalData = truncateChangePath.call(this, sourceData);\n return internalData;\n}\n\n\nfunction truncateChangePath(change) {\n var fullPath = change.path\n , path = _.unPrefix(fullPath, this.rootPath);\n\n if (typeof path == 'string') {\n var change = _.clone(change);\n change.fullPath = fullPath;\n change.path = path;\n return change;\n }\n}\n",
- "'use strict';\n\n// \n// ### model path utils\n\nvar check = require('../util/check')\n , Match = check.Match\n , _ = require('mol-proto')\n , ModelError = require('../util/error').Model;\n\nvar pathUtils = {\n parseAccessPath: parseAccessPath,\n createRegexPath: createRegexPath,\n getPathNodeKey: getPathNodeKey,\n wrapMessengerMethods: wrapMessengerMethods\n};\n\nmodule.exports = pathUtils;\n\n\nvar propertyPathSyntax = '\\\\.[A-Za-z_-][A-Za-z0-9_-]*'\n , arrayPathSyntax = '\\\\[[0-9]+\\\\]'\n , interpolationSyntax = '\\\\$[1-9][0-9]*'\n , propertyInterpolateSyntax = '\\\\.' + interpolationSyntax\n , arrayInterpolateSyntax = '\\\\[' + interpolationSyntax + '\\\\]'\n\n , propertyStarSyntax = '\\\\.\\\\*'\n , arrayStarSyntax = '\\\\[\\\\*\\\\]'\n , starSyntax = '\\\\*'\n\n , pathParseSyntax = [\n propertyPathSyntax,\n arrayPathSyntax,\n propertyInterpolateSyntax,\n arrayInterpolateSyntax\n ].join('|')\n , pathParsePattern = new RegExp(pathParseSyntax, 'g')\n\n , patternPathParseSyntax = [\n pathParseSyntax,\n propertyStarSyntax,\n arrayStarSyntax,\n starSyntax\n ].join('|')\n , patternPathParsePattern = new RegExp(patternPathParseSyntax, 'g')\n\n //, targetPathParsePattern = /\\.[A-Za-z][A-Za-z0-9_]*|\\[[0-9]+\\]|\\.\\$[1-9][0-9]*|\\[\\$[1-9][0-9]*\\]|\\$[1-9][0-9]/g\n , pathNodeTypes = {\n '.': { syntax: 'object', empty: '{}' },\n '[': { syntax: 'array', empty: '[]'},\n '*': { syntax: 'match', empty: '{}'},\n };\n\nfunction parseAccessPath(path, nodeParsePattern) {\n nodeParsePattern = nodeParsePattern || pathParsePattern;\n\n var parsedPath = [];\n\n if (! path)\n return parsedPath;\n\n var unparsed = path.replace(nodeParsePattern, function(nodeStr) {\n var pathNode = { property: nodeStr };\n _.extend(pathNode, pathNodeTypes[nodeStr[0]]);\n if (nodeStr[1] == '$')\n pathNode.interpolate = getPathNodeKey(pathNode, true);\n\n parsedPath.push(pathNode);\n return '';\n });\n if (unparsed)\n throw new ModelError('incorrect model path: ' + path);\n\n return parsedPath;\n}\n\n\nvar nodeRegex = {\n '.*': propertyPathSyntax,\n '[*]': arrayPathSyntax\n};\nnodeRegex['*'] = nodeRegex['.*'] + '|' + nodeRegex['[*]'];\n\nfunction createRegexPath(path) {\n check(path, Match.OneOf(String, RegExp));\n\n if (path instanceof RegExp || path.indexOf('*') == -1)\n return path;\n\n var parsedPath = pathUtils.parseAccessPath(path, patternPathParsePattern)\n , regexStr = '^'\n // , regexStrEnd = ''\n , patternsStarted = false;\n\n parsedPath.forEach(function(pathNode) {\n var prop = pathNode.property\n , regex = nodeRegex[prop];\n \n if (regex) {\n // regexStr += '(' + regex;\n // regexStrEnd += '|)';\n regexStr += '(' + regex + '|)';\n // regexStrEnd += '|)';\n patternsStarted = true;\n } else {\n // if (patternsStarted)\n // throw new ModelError('\"*\" path segment cannot be in the middle of the path: ' + path);\n regexStr += prop.replace(/(\\.|\\[|\\])/g, '\\\\$1'); // add slash in front of symbols that have special meaning in regex\n }\n });\n\n regexStr += /* regexStrEnd + */ '$';\n\n try {\n return new RegExp(regexStr);\n } catch (e) {\n throw new ModelError('can\\'t construct regex for path pattern: ' + path);\n }\n}\n\n\nfunction getPathNodeKey(pathNode, interpolated) {\n var prop = pathNode.property\n , startIndex = interpolated ? 2 : 1;\n return pathNode.syntax == 'array'\n ? prop.slice(startIndex, prop.length - 1)\n : prop.slice(startIndex);\n}\n\n\n// TODO allow for multiple messages in a string\nfunction wrapMessengerMethods(methodsNames) {\n methodsNames = methodsNames || ['on', 'off'];\n var wrappedMethods = _.mapToObject(methodsNames, function(methodName) {\n var origMethod = this[methodName];\n // replacing message subsribe/unsubscribe/etc. to convert \"*\" message patterns to regexps\n return function(path, subscriber) {\n var regexPath = createRegexPath(path);\n origMethod.call(this, regexPath, subscriber);\n };\n }, this);\n _.defineProperties(this, wrappedMethods);\n}\n",
- "'use strict';\n\nvar pathUtils = require('../path_utils')\n , modelUtils = require('../model_utils')\n , logger = require('../../util/logger')\n , miloCount = require('../../util/count')\n , fs = require('fs')\n , doT = require('dot')\n , _ = require('mol-proto')\n , changeDataHandler = require('../change_data')\n , getTransactionFlag = changeDataHandler.getTransactionFlag\n , postTransactionFinished = changeDataHandler.postTransactionFinished;\n\n\n/**\n * Templates to synthesize model getters and setters\n */\nvar templates = {\n get: \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\nmethod = function get() {\\n var m = {{# def.modelAccessPrefix }};\\n return m {{~ it.parsedPath :pathNode }}\\n {{? pathNode.interpolate}}\\n && (m = m[this._args[ {{= pathNode.interpolate }} ]])\\n {{??}}\\n && (m = m{{= pathNode.property }})\\n {{?}} {{~}};\\n};\\n\",\n set: \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n{{# def.include_defines }}\\n{{# def.include_create_tree }}\\n\\n\\n/**\\n * Template that synthesizes setter for Model and for ModelPath\\n */\\nmethod = function set(value) {\\n {{# def.initVars:'set' }}\\n\\n {{# def.createTree:'set' }}\\n\\n {{\\n currNode = nextNode;\\n currProp = currNode && currNode.property;\\n }}\\n\\n {{ /* assign value to the last property */ }}\\n {{? currProp }}\\n wasDef = {{# def.wasDefined}};\\n {{# def.changeAccessPath }}\\n\\n var old = m{{# def.currProp }};\\n\\n {{ /* clone value to prevent same reference in linked models */ }}\\n m{{# def.currProp }} = cloneTree(value);\\n {{?}}\\n\\n {{ /* add message related to the last property change */ }}\\n if (this._options.reactive !== false) {\\n if (! wasDef)\\n {{# def.addMsg }} accessPath, type: 'added',\\n newValue: value });\\n else if (old != value)\\n {{# def.addMsg }} accessPath, type: 'changed',\\n oldValue: old, newValue: value });\\n\\n {{ /* add message related to changes in (sub)properties inside removed and assigned value */ }}\\n if (! wasDef || old != value)\\n addTreeChangesMessages(messages, messagesHash,\\n accessPath, old, value); /* defined in the function that synthesizes ModelPath setter */\\n\\n {{ /* post all stored messages */ }}\\n {{# def.postMessages }}\\n }\\n};\\n\",\n del: \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n{{# def.include_defines }}\\n{{# def.include_traverse_tree }}\\n\\nmethod = function del() {\\n {{# def.initVars:'del' }}\\n\\n {{? it.parsedPath.length }}\\n {{# def.traverseTree }}\\n\\n {{\\n var currNode = it.parsedPath[count];\\n var currProp = currNode.property; \\n }}\\n\\n if (! treeDoesNotExist && m && m.hasOwnProperty && {{# def.wasDefined}}) {\\n var old = m{{# def.currProp }};\\n delete m{{# def.currProp }};\\n {{# def.changeAccessPath }}\\n var didDelete = true;\\n }\\n {{??}}\\n if (typeof m != 'undefined') {\\n var old = m;\\n {{# def.modelAccessPrefix }} = undefined;\\n var didDelete = true;\\n }\\n {{?}}\\n\\n if (didDelete && this._options.reactive !== false) {\\n {{# def.addMsg }} accessPath, type: 'deleted', oldValue: old });\\n\\n addTreeChangesMessages(messages, messagesHash,\\n accessPath, old, undefined); /* defined in the function that synthesizes ModelPath setter */\\n\\n {{ /* post all stored messages */ }}\\n {{# def.postMessages }}\\n }\\n};\\n\",\n splice: \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n{{# def.include_defines }}\\n{{# def.include_create_tree }}\\n{{# def.include_traverse_tree }}\\n\\nmethod = function splice(spliceIndex, spliceHowMany) { /* ,... - extra arguments to splice into array */\\n {{# def.initVars:'splice' }}\\n\\n var argsLen = arguments.length;\\n var addItems = argsLen > 2;\\n\\n if (addItems) {\\n {{ /* only create model tree if items are inserted in array */ }}\\n\\n {{ /* if model is undefined it will be set to an empty array */ }} \\n var value = [];\\n {{# def.createTree:'splice' }}\\n\\n {{? nextNode }}\\n {{\\n var currNode = nextNode;\\n var currProp = currNode.property;\\n var emptyProp = '[]';\\n }}\\n\\n {{# def.createTreeStep }}\\n {{?}}\\n\\n } else if (spliceHowMany > 0) {\\n {{ /* if items are not inserted, only traverse model tree if items are deleted from array */ }}\\n {{? it.parsedPath.length }}\\n {{# def.traverseTree }}\\n\\n {{\\n var currNode = it.parsedPath[count];\\n var currProp = currNode.property; \\n }}\\n\\n {{ /* extra brace closes 'else' in def.traverseTreeStep */ }}\\n {{# def.traverseTreeStep }} }\\n {{?}}\\n }\\n\\n {{ /* splice items */ }}\\n if (addItems || (! treeDoesNotExist && m\\n && m.length > spliceIndex ) ) {\\n var oldLength = m.length = m.length || 0;\\n\\n arguments[0] = spliceIndex = normalizeSpliceIndex(spliceIndex, m.length);\\n\\n {{ /* clone added arguments to prevent same references in linked models */ }}\\n if (addItems)\\n for (var i = 2; i < argsLen; i++)\\n arguments[i] = cloneTree(arguments[i]);\\n\\n {{ /* actual splice call */ }}\\n var removed = Array.prototype.splice.apply(m, arguments);\\n\\n if (this._options.reactive !== false) {\\n {{# def.addMsg }} accessPath, type: 'splice',\\n index: spliceIndex, removed: removed, addedCount: addItems ? argsLen - 2 : 0,\\n newValue: m });\\n\\n if (removed && removed.length)\\n removed.forEach(function(item, index) {\\n var itemPath = accessPath + '[' + (spliceIndex + index) + ']';\\n {{# def.addMsg }} itemPath, type: 'removed', oldValue: item });\\n\\n if (valueIsTree(item))\\n addMessages(messages, messagesHash, itemPath, item, 'removed', 'oldValue');\\n });\\n\\n if (addItems)\\n for (var i = 2; i < argsLen; i++) {\\n var item = arguments[i];\\n var itemPath = accessPath + '[' + (spliceIndex + i - 2) + ']';\\n {{# def.addMsg }} itemPath, type: 'added', newValue: item });\\n\\n if (valueIsTree(item))\\n addMessages(messages, messagesHash, itemPath, item, 'added', 'newValue');\\n }\\n\\n {{ /* post all stored messages */ }}\\n {{# def.postMessages }}\\n }\\n }\\n\\n return removed || [];\\n}\\n\"\n};\n\nvar include_defines = \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n/**\\n * Inserts initialization code\\n */\\n {{## def.initVars:method:\\n var m = {{# def.modelAccessPrefix }};\\n var messages = [], messagesHash = {};\\n var accessPath = '';\\n var treeDoesNotExist;\\n /* hack to prevent sending finished events to allow for propagation of batches without splitting them */\\n var inChangeTransaction = getTransactionFlag( {{= method }} );\\n #}}\\n\\n/**\\n * Inserts the beginning of function call to add message to list\\n */\\n{{## def.addMsg: addChangeMessage(messages, messagesHash, { path: #}}\\n\\n/**\\n * Inserts current property/index for both normal and interpolated properties/indexes\\n */\\n{{## def.currProp:{{? currNode.interpolate }}[this._args[ {{= currNode.interpolate }} ]]{{??}}{{= currProp }}{{?}} #}}\\n\\n/**\\n * Inserts condition to test whether normal/interpolated property/index exists\\n */\\n{{## def.wasDefined: m.hasOwnProperty(\\n {{? currNode.interpolate }}\\n this._args[ {{= currNode.interpolate }} ]\\n {{??}}\\n '{{= it.getPathNodeKey(currNode) }}'\\n {{?}}\\n) #}}\\n\\n\\n/**\\n * Inserts code to update access path for current property\\n * Because of the possibility of interpolated properties, it can't be calculated in template, it can only be calculated during accessor call.\\n */\\n{{## def.changeAccessPath:\\n accessPath += {{? currNode.interpolate }}\\n {{? currNode.syntax == 'array' }}\\n '[' + this._args[ {{= currNode.interpolate }} ] + ']';\\n {{??}}\\n '.' + this._args[ {{= currNode.interpolate }} ];\\n {{?}}\\n {{??}}\\n '{{= currProp }}';\\n {{?}}\\n#}}\\n\\n\\n/**\\n * Inserts code to post stored messages\\n */\\n{{## def.postMessages:\\n if (messages.length) {\\n {{# def.modelPostBatchCode }}('datachanges', {\\n changes: messages,\\n transaction: inChangeTransaction\\n });\\n\\n messages.forEach(function(msg) {\\n {{# def.modelPostMessageCode }}(msg.path, msg);\\n }, this);\\n }\\n#}}\\n\"\n , include_create_tree = \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n/**\\n * Inserts code to create model tree as neccessary for `set` and `splice` accessors and to add messages to send list if the tree changes.\\n */\\n{{## def.createTree:method:\\n var wasDef = true;\\n var old = m;\\n\\n {{ var emptyProp = it.parsedPath[0] && it.parsedPath[0].empty; }}\\n {{? emptyProp }}\\n {{ /* create top level model if it was not previously defined */ }}\\n if (! m) {\\n m = {{# def.modelAccessPrefix }} = {{= emptyProp }};\\n wasDef = false;\\n\\n if (this._options.reactive !== false) {\\n {{# def.addMsg }} '', type: 'added',\\n newValue: m });\\n }\\n }\\n {{??}}\\n {{? method == 'splice' }}\\n if (! m) {\\n {{?}}\\n m = {{# def.modelAccessPrefix }} = cloneTree(value);\\n wasDef = typeof old != 'undefined';\\n {{? method == 'splice' }}\\n }\\n {{?}} \\n {{?}}\\n\\n\\n {{ /* create model tree if it doesn't exist */ }}\\n {{ var modelDataProperty = '';\\n var nextNode = it.parsedPath[0];\\n var count = it.parsedPath.length - 1;\\n\\n for (var i = 0; i < count; i++) {\\n var currNode = nextNode;\\n var currProp = currNode.property;\\n nextNode = it.parsedPath[i + 1];\\n var emptyProp = nextNode && nextNode.empty;\\n }}\\n\\n {{# def.createTreeStep }}\\n\\n {{ } /* for loop */ }}\\n#}}\\n\\n\\n/**\\n * Inserts code to create one step in the model tree\\n */\\n{{## def.createTreeStep:\\n {{# def.changeAccessPath }}\\n\\n if (! {{# def.wasDefined }}) { \\n {{ /* property does not exist */ }}\\n m = m{{# def.currProp }} = {{= emptyProp }};\\n\\n if (this._options.reactive !== false) {\\n {{# def.addMsg }} accessPath, type: 'added', \\n newValue: m });\\n }\\n\\n } else if (typeof m{{# def.currProp }} != 'object') {\\n {{ /* property is not object */ }}\\n var old = m{{# def.currProp }};\\n m = m{{# def.currProp }} = {{= emptyProp }};\\n\\n if (this._options.reactive !== false) {\\n {{# def.addMsg }} accessPath, type: 'changed', \\n oldValue: old, newValue: m });\\n }\\n\\n } else {\\n {{ /* property exists, just traverse down the model tree */ }}\\n m = m{{# def.currProp }};\\n }\\n#}}\\n\"\n , include_traverse_tree = \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n/**\\n * Inserts code to traverse model tree for `delete` and `splice` accessors.\\n */\\n{{## def.traverseTree:\\n {{ \\n var count = it.parsedPath.length-1;\\n\\n for (var i = 0; i < count; i++) { \\n var currNode = it.parsedPath[i];\\n var currProp = currNode.property;\\n }}\\n {{# def.traverseTreeStep }}\\n\\n {{ } /* for loop */\\n\\n var i = count;\\n while (i--) { /* closing braces for else's above */\\n }}\\n }\\n {{ } /* while loop */ }}\\n#}}\\n\\n\\n/**\\n * Inserts code to traverse one step in the model tree\\n */\\n{{## def.traverseTreeStep:\\n if (! (m && m.hasOwnProperty && {{# def.wasDefined}} ) )\\n treeDoesNotExist = true;\\n else {\\n m = m{{# def.currProp }};\\n {{# def.changeAccessPath }}\\n {{ /* brace from else is not closed on purpose - all braces are closed in while loop */ }}\\n#}}\\n\";\n\nvar dotDef = {\n include_defines: include_defines,\n include_create_tree: include_create_tree,\n include_traverse_tree: include_traverse_tree,\n getPathNodeKey: pathUtils.getPathNodeKey,\n modelAccessPrefix: 'this._model._data',\n modelPostMessageCode: 'this._model._internalMessenger.postMessage',\n modelPostBatchCode: 'this._model.postMessageSync',\n internalMessenger: 'this._model._internalMessenger'\n};\n\nvar modelDotDef = _(dotDef).clone().extend({\n modelAccessPrefix: 'this._data',\n modelPostMessageCode: 'this._internalMessenger.postMessage',\n modelPostBatchCode: 'this.postMessageSync',\n internalMessenger: 'this._internalMessenger'\n})._();\n\n\nvar dotSettings = _.clone(doT.templateSettings);\ndotSettings.strip = false;\n\nvar synthesizers = _.mapKeys(templates, function(tmpl) {\n return doT.template(tmpl, dotSettings, dotDef); \n});\n\n\nvar modelSynthesizers = _.mapToObject(['set', 'del', 'splice'], function(methodName) {\n return doT.template(templates[methodName], dotSettings, modelDotDef);\n});\n\n\n/**\n * Function that synthesizes accessor methods.\n * Function is memoized so accessors are cached (up to 1000).\n *\n * @param {String} path Model/ModelPath access path\n * @param {Array} parsedPath array of path nodes\n * @return {Object[Function]}\n */\nvar synthesizePathMethods = _.memoize(_synthesizePathMethods, undefined, 1000);\n\nfunction _synthesizePathMethods(path, parsedPath) {\n var methods = _.mapKeys(synthesizers, function(synthszr) {\n return _synthesize(synthszr, path, parsedPath);\n });\n return methods;\n}\n\n\nvar normalizeSpliceIndex = modelUtils.normalizeSpliceIndex; // used in splice.dot.js\n\n\nfunction _synthesize(synthesizer, path, parsedPath) {\n var method\n , methodCode = synthesizer({\n parsedPath: parsedPath,\n getPathNodeKey: pathUtils.getPathNodeKey\n });\n\n try {\n eval(methodCode);\n } catch (e) {\n throw ModelError('ModelPath method compilation error; path: ' + path + ', code: ' + methodCode);\n }\n\n return method;\n\n\n // functions used by methods `set`, `delete` and `splice` (synthesized by template)\n function addChangeMessage(messages, messagesHash, msg) {\n messages.push(msg);\n messagesHash[msg.path] = msg;\n }\n\n function addTreeChangesMessages(messages, messagesHash, rootPath, oldValue, newValue) {\n var oldIsTree = valueIsTree(oldValue)\n , newIsTree = valueIsTree(newValue);\n\n if (newIsTree)\n addMessages(messages, messagesHash, rootPath, newValue, 'added', 'newValue');\n \n if (oldIsTree)\n addMessages(messages, messagesHash, rootPath, oldValue, 'removed', 'oldValue');\n }\n\n function addMessages(messages, messagesHash, rootPath, obj, msgType, valueProp) {\n _addMessages(rootPath, obj);\n\n\n function _addMessages(rootPath, obj) {\n if (Array.isArray(obj)) {\n var pathSyntax = rootPath + '[$$]';\n obj.forEach(function(value, index) {\n addMessage(value, index, pathSyntax);\n });\n } else {\n var pathSyntax = rootPath + '.$$';\n _.eachKey(obj, function(value, key) {\n addMessage(value, key, pathSyntax);\n });\n }\n }\n\n function addMessage(value, key, pathSyntax) {\n var path = pathSyntax.replace('$$', key)\n , existingMsg = messagesHash[path];\n\n if (existingMsg) {\n if (existingMsg.type == msgType)\n logger.error('setter error: same message type posted on the same path');\n else {\n existingMsg.type = 'changed';\n existingMsg[valueProp] = value;\n }\n } else {\n var msg = { path: path, type: msgType };\n msg[valueProp] = value;\n addChangeMessage(messages, messagesHash, msg);\n }\n\n if (valueIsTree(value))\n _addMessages(path, value);\n }\n }\n\n function cloneTree(value) {\n return valueIsNormalObject(value)\n ? _.deepClone(value)\n : value;\n }\n\n function protectValue(value) {\n return ! valueIsNormalObject(value)\n ? value\n : Array.isArray(value)\n ? value.slice()\n : Object.create(value);\n }\n\n function valueIsTree(value) {\n return valueIsNormalObject(value)\n && Object.keys(value).length;\n }\n\n function valueIsNormalObject(value) {\n return value != null\n && typeof value == \"object\"\n && ! (value instanceof Date)\n && ! (value instanceof RegExp);\n }\n\n function addBatchIdsToMessage(msg, batchId, msgId) {\n _.defineProperties(msg, {\n __batch_id: batchId,\n __msg_id: msgId\n });\n }\n}\n\n\n/**\n * Exports `synthesize` function with the following:\n *\n * - .modelMethods.set - `set` method for Model\n * - .modelMethods.del - `del` method for Model\n * - .modelMethods.splice - `splice` method for Model\n */\nmodule.exports = synthesizePathMethods;\n\nvar modelMethods = _.mapKeys(modelSynthesizers, function(synthesizer) {\n return _synthesize(synthesizer, '', []);\n});\n\nsynthesizePathMethods.modelMethods = modelMethods;\n",
+ "'use strict';\n\nvar Component = require('../../c_class')\n , componentsRegistry = require('../../c_registry')\n , componentName = require('../../../util/component_name')\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , check = miloCore.util.check\n , Match = check.Match\n , _ = miloCore.proto;\n\n\nvar ALERT_CSS_CLASSES = {\n success: 'alert-success',\n warning: 'alert-warning',\n info: 'alert-info',\n danger: 'alert-danger',\n fixed: 'alert-fixed'\n};\n\n\nvar MLAlert = Component.createComponentClass('MLAlert', {\n container: undefined,\n events: undefined,\n dom: {\n cls: ['ml-bs-alert', 'alert', 'fade'],\n attributes: {\n 'role': 'alert',\n 'aria-hidden': 'true'\n }\n },\n template: {\n template: '\\\n {{? it.close }}\\\n \\\n {{?}}\\\n {{= it.message}}'\n }\n});\n\ncomponentsRegistry.add(MLAlert);\n\nmodule.exports = MLAlert;\n\n\n_.extend(MLAlert, {\n createAlert: MLAlert$$createAlert,\n openAlert: MLAlert$$openAlert,\n});\n\n\n_.extendProto(MLAlert, {\n openAlert: MLAlert$openAlert,\n closeAlert: MLAlert$closeAlert\n});\n\n\n/**\n * Creates and returns a new alert instance. To create and open at the same time use [openAlert](#MLAlert$$openAlert)\n * `options` is an object with the following properties:\n *\n * message: string alert message\n * type: optional string the type of alert message, one of success, warning, info, danger, fixed\n * default 'info'\n * close: optional false to prevent user from closing\n * or true (default) to enable closing and render a close button\n * timeout: optional timer, in milliseconds to automatically close the alert\n *\n * @param {Object} options alert configuration\n */\nfunction MLAlert$$createAlert(options) {\n check(options, {\n message: String,\n type: Match.Optional(String),\n close: Match.Optional(Boolean),\n timeout: Match.Optional(Number)\n });\n\n var alert = MLAlert.createOnElement();\n\n options = _prepareOptions(options);\n\n var alertCls = ALERT_CSS_CLASSES[options.type];\n alert.dom.addCssClasses(alertCls);\n\n alert._alert = {\n options: options,\n visible: false\n };\n\n alert.template.render(options).binder();\n\n var alertScope = alert.container.scope;\n\n if (options.close)\n alertScope.closeBtn.events.on('click',\n { subscriber: _onCloseBtnClick, context: alert });\n\n if (options.timeout)\n var timer = setTimeout(function(){\n if(alert._alert.visible)\n alert.closeAlert();\n }, options.timeout);\n\n return alert;\n}\n\n\n/**\n * Create and show alert popup\n *\n * @param {Object} options object with message, type, close and timeout\n * @return {MLAlert} the alert instance\n */\nfunction MLAlert$$openAlert(options) {\n var alert = MLAlert.createAlert(options);\n alert.openAlert();\n return alert;\n}\n\n\nfunction _onCloseBtnClick(type, event) {\n this.closeAlert();\n}\n\n\nfunction _prepareOptions(options) {\n options = _.clone(options);\n options.close = typeof options.close == 'undefined' || options.close === true;\n options.timeout = Math.floor(options.timeout);\n options.type = options.type || 'info';\n\n return options;\n}\n\n\n/**\n * Open the alert\n */\nfunction MLAlert$openAlert() {\n _toggleAlert.call(this, true);\n}\n\n\n/**\n * Close the alert\n */\nfunction MLAlert$closeAlert() {\n _toggleAlert.call(this, false);\n this.destroy();\n}\n\n\nfunction _toggleAlert(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._alert.visible\n : !! doShow;\n\n var addRemove = doShow ? 'add' : 'remove'\n , appendRemove = doShow ? 'appendChild' : 'removeChild';\n\n this._alert.visible = doShow;\n\n document.body[appendRemove](this.el);\n this.dom.toggle(doShow);\n this.el.setAttribute('aria-hidden', !doShow);\n this.el.classList[addRemove]('in');\n this.el[doShow ? 'focus' : 'blur']();\n}\n",
+ "'use strict';\n\nvar Component = require('../../c_class')\n , componentsRegistry = require('../../c_registry')\n , componentName = require('../../../util/component_name')\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , check = miloCore.util.check\n , Match = check.Match\n , _ = miloCore.proto;\n\n\nvar DEFAULT_BUTTONS = [ { type: 'default', label: 'OK', result: 'OK' } ];\n\nvar CLOSE_OPTIONS = ['backdrop', 'keyboard', 'button'];\n\nvar BUTTON_CSS_CLASSES = { // TODO - use in template\n default: 'btn-default',\n primary: 'btn-primary',\n success: 'btn-success',\n info: 'btn-info',\n warning: 'btn-warning',\n danger: 'btn-danger',\n link: 'btn-link'\n};\n\n\n/**\n * Dialog class to show custom dialog boxes based on configuration - see [createDialog](#MLDialog$$createDialog) method.\n * Only one dialog can be opened at a time - trying to open another will log error to console. Currently opened dialog can be retrieved using [getCurrentDialog](#MLDialog$$getCurrentDialog) class method.\n */\nvar MLDialog = Component.createComponentClass('MLDialog', {\n container: undefined,\n events: undefined,\n dom: {\n cls: ['ml-bs-dialog', 'modal', 'fade'],\n attributes: {\n 'role': 'dialog',\n 'aria-hidden': 'true'\n }\n },\n template: {\n template: '\\\n
'\n }\n});\n\ncomponentsRegistry.add(MLDialog);\n\nmodule.exports = MLDialog;\n\n\n_.extend(MLDialog, {\n createDialog: MLDialog$$createDialog,\n openDialog: MLDialog$$openDialog,\n getOpenedDialog: MLDialog$$getOpenedDialog\n});\n\n\n_.extendProto(MLDialog, {\n openDialog: MLDialog$openDialog,\n closeDialog: MLDialog$closeDialog,\n destroy: MLDialog$destroy\n});\n\n\n/**\n * Creates and returns dialog instance. To create and open at the same time [openDialog](#MLDialog$$openDialog)\n * `options` is an object with the following properties:\n *\n * title: optional dialog title\n * html: optional dialog text as html (will take precedence over text if both text nd html are passed)\n * or\n * text: optional dialog text\n * close: optional false to prevent backdrop and esc key from closing the dialog and removing close button in top right corner\n * or true (default) to enable all close options\n * or object with properties\n * backdrop: false or true (default), close dialog when backdrop clicked\n * keyboard: false or true (default), close dialog when esc key is pressed\n * button: false or true (default), show close button in the header (won't be shown if there is no header when title is not passed)\n * buttons: optional array of buttons configurations, where each button config is an object\n * name: optional name of component, should be unique and should not be `closeBtn`, if not passed a timestamp based name will be used\n * type: button type, will determine button CSS style. Possible types are: defult, primary, success, info, warning, danger, link (map to related bootstrap button styles)\n * label: button label\n * close: optional false to prevent this button from closing dialog\n * result: string with dialog close result that will be passed to dialog subscriber as the first parameter\n * data: any value/object or function to create data that will be passed to dialog subscriber as the second parameter.\n * If function is passed it will be called with dialog as context and button options as parameter.\n *\n * If `title` is not passed, dialog will not have title section \n * If neither `text` nor `html` is passed, dialog will not have body section.\n * If `buttons` are not passed, there will only be OK button.\n *\n * When dialog is closed, the subscriber is called with reault and optional data as defined in buttons configurations.\n * If backdrop is clicked or ESC key is pressed the result will be 'dismissed'\n * If close button in the top right corner is clicked, the result will be 'closed' (default result)\n * \n * @param {Object} options dialog configuration\n * @param {Function} initialize function that is called to initialize the dialog\n */\nfunction MLDialog$$createDialog(options, initialize) {\n check(options, {\n title: Match.Optional(String),\n html: Match.Optional(String),\n text: Match.Optional(String),\n close: Match.Optional(Match.OneOf(Boolean, {\n backdrop: Match.Optional(Boolean),\n keyboard: Match.Optional(Boolean),\n button: Match.Optional(Boolean)\n })),\n buttons: Match.Optional([ {\n name: Match.Optional(String),\n type: String,\n label: String,\n close: Match.Optional(Boolean),\n result: Match.Optional(String),\n data: Match.Optional(Match.Any),\n cls: Match.Optional(String)\n } ])\n });\n\n var dialog = MLDialog.createOnElement();\n\n options = _prepareOptions(options);\n dialog._dialog = {\n options: options,\n visible: false\n };\n\n dialog.template\n .render(options)\n .binder();\n\n var dialogScope = dialog.container.scope;\n\n if (options.close.backdrop)\n dialog.events.on('click',\n { subscriber: _onBackdropClick, context: dialog });\n\n if (options.title && options.close.button)\n dialogScope.closeBtn.events.on('click',\n { subscriber: _onCloseBtnClick, context: dialog });\n\n options.buttons.forEach(function(btn) {\n var buttonSubscriber = {\n subscriber: _.partial(_dialogButtonClick, btn),\n context: dialog\n };\n dialogScope[btn.name].events.on('click', buttonSubscriber);\n });\n\n if (initialize) initialize(dialog);\n return dialog;\n}\n\n\nfunction _dialogButtonClick(button) {\n if (button.close !== false)\n _toggleDialog.call(this, false);\n\n var data = _.result(button.data, this, button);\n _dispatchResult.call(this, button.result, data);\n}\n\n\nfunction _dispatchResult(result, data) {\n var subscriber = this._dialog.subscriber;\n if (typeof subscriber == 'function')\n subscriber.call(this, result, data);\n else\n subscriber.subscriber.call(subscriber.context, result, data);\n}\n\n\nfunction _onBackdropClick(eventType, event) {\n if (event.target == this.el)\n this.closeDialog('dismissed');\n}\n\n\nfunction _onCloseBtnClick() {\n this.closeDialog('closed');\n}\n\n\nfunction _onKeyDown(event) {\n if (openedDialog\n && openedDialog._dialog.options.close.keyboard\n && event.keyCode == 27) // esc key\n openedDialog.closeDialog('dismissed');\n}\n\n\nfunction _prepareOptions(options) {\n options = _.clone(options);\n options.buttons = _.clone(options.buttons || DEFAULT_BUTTONS);\n options.buttons.forEach(function(btn) {\n btn.name = btn.name || componentName();\n });\n\n options.close = typeof options.close == 'undefined' || options.close === true\n ? _.object(CLOSE_OPTIONS, true)\n : typeof options.close == 'object'\n ? _.mapToObject(CLOSE_OPTIONS,\n function(opt) { return options.close[opt] !== false; })\n : _.object(CLOSE_OPTIONS, false);\n\n return options;\n}\n\n\n/**\n * Create and show dialog popup\n * \n * @param {Object} options object with title, text and buttons. See [createDialog](#MLDialog$$createDialog) for more information.\n * @param {Function|Object} subscriber optional subscriber function or object that is passed result and optional data. Unless context is defined, dialog will be the context.\n */\nfunction MLDialog$$openDialog(options, subscriber, initialize) {\n var dialog = MLDialog.createDialog(options, initialize);\n dialog.openDialog(subscriber);\n return dialog;\n}\n\n\n\nfunction _toggleDialog(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._dialog.visible\n : !! doShow;\n\n var addRemove = doShow ? 'add' : 'remove'\n , appendRemove = doShow ? 'appendChild' : 'removeChild';\n\n this._dialog.visible = doShow;\n\n if (doShow && ! dialogsInitialized)\n _initializeDialogs();\n\n document.body[appendRemove](this.el);\n if (backdropEl)\n document.body[appendRemove](backdropEl);\n this.dom.toggle(doShow);\n this.el.setAttribute('aria-hidden', !doShow);\n document.body.classList[addRemove]('modal-open');\n this.el.classList[addRemove]('in');\n\n openedDialog = doShow ? this : undefined;\n this.el[doShow ? 'focus' : 'blur']();\n}\n\n\nvar dialogsInitialized, backdropEl;\n\nfunction _initializeDialogs() {\n backdropEl = document.createElement('div');\n backdropEl.className = 'modal-backdrop fade in';\n document.addEventListener('keydown', _onKeyDown);\n dialogsInitialized = true;\n}\n\n\nvar openedDialog;\n\n/**\n * Opens dialog instance.\n * Subscriber object should have the same format as the subscriber for the Messenger (although Messenger is not used) - either function or object with subscriber and context properties.\n * \n * @param {Function|Object} subscriber subscriber object\n */\nfunction MLDialog$openDialog(subscriber) {\n check(subscriber, Match.OneOf(Function, { subscriber: Function, context: Match.Any }));\n\n if (openedDialog)\n return logger.warn('MLDialog openDialog: can\\'t open dialog, another dialog is already open');\n\n this._dialog.subscriber = subscriber;\n _toggleDialog.call(this, true);\n}\n\n\n/**\n * Closes dialog instance, optionally passing result and data to dialog subscriber.\n * If no result is passed, 'closed' will be passed to subscriber.\n *\n * @param {String} result dialog result, passed as the first parameter to subcsriber\n * @param {Any} data optional dialog data, passed as the second parameter to subscriber\n */\nfunction MLDialog$closeDialog(result, data) {\n if (! openedDialog)\n return logger.warn('MLDialog closeDialog: can\\'t close dialog, no dialog open');\n\n result = result || 'closed';\n\n _toggleDialog.call(this, false);\n _dispatchResult.call(this, result, data);\n}\n\n\n/**\n * Returns currently opened dialog\n *\n * @return {MLDialog}\n */\nfunction MLDialog$$getOpenedDialog() {\n return openedDialog;\n}\n\n\nfunction MLDialog$destroy() {\n document.removeEventListener('keydown', _onKeyDown);\n Component.prototype.destroy.apply(this, arguments);\n}\n",
+ "'use strict';\n\nvar Component = require('../../c_class')\n , componentsRegistry = require('../../c_registry')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , logger = miloCore.util.logger\n , DOMListeners = require('../../../util/dom_listeners');\n\n\nvar TOGGLE_CSS_CLASS = 'dropdown-toggle'\n , MENU_CSS_CLASS = 'dropdown-menu';\n\n\nvar MLDropdown = Component.createComponentClass('MLDropdown', {\n events: undefined,\n dom: {\n cls: ['ml-bs-dropdown', 'dropdown']\n }\n});\n\ncomponentsRegistry.add(MLDropdown);\n\nmodule.exports = MLDropdown;\n\n\n_.extendProto(MLDropdown, {\n start: MLDropdown$start,\n destroy: MLDropdown$destroy,\n toggleMenu: MLDropdown$toggleMenu,\n showMenu: MLDropdown$showMenu,\n hideMenu: MLDropdown$hideMenu\n});\n\n\nfunction MLDropdown$start() {\n var toggleEl = this.el.querySelector('.' + TOGGLE_CSS_CLASS)\n , menuEl = this.el.querySelector('.' + MENU_CSS_CLASS);\n\n if (! (toggleEl && menuEl))\n return logger.error('MLDropdown:', TOGGLE_CSS_CLASS, 'or', MENU_CSS_CLASS, 'isn\\'t found');\n\n var doc = window.document\n , clickHandler = this.toggleMenu.bind(this, undefined);\n\n var listeners = new DOMListeners;\n this._dropdown = {\n menu: menuEl,\n visible: false,\n listeners: listeners\n };\n this.hideMenu();\n var self = this;\n\n listeners.add(toggleEl, 'click', clickHandler);\n //maybe only add this events if is open?\n listeners.add(doc, 'mouseout', onDocOut);\n listeners.add(doc, 'click', onClick);\n\n\n function onDocOut(event) {\n var target = event.target\n , relatedTarget = event.relatedTarget\n , listeners = self._dropdown.listeners;\n\n if (isIframe(target))\n listeners.remove(target.contentWindow.document, 'click', onClick);\n\n if (isIframe(relatedTarget))\n listeners.add(relatedTarget.contentWindow.document, 'click', onClick);\n }\n\n function onClick(event) {\n if (!self.el.contains(event.target))\n self.hideMenu();\n }\n}\n\n\nfunction isIframe(el) {\n return el && el.tagName == 'IFRAME';\n}\n\n\nfunction MLDropdown$destroy() {\n this._dropdown.listeners.removeAll();\n delete this._dropdown;\n Component.prototype.destroy.apply(this, arguments);\n}\n\n\nfunction MLDropdown$showMenu() {\n this.toggleMenu(true);\n}\n\n\nfunction MLDropdown$hideMenu() {\n this.toggleMenu(false);\n}\n\n\nfunction MLDropdown$toggleMenu(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._dropdown.visible\n : !! doShow;\n\n this._dropdown.visible = doShow;\n\n var menu = this._dropdown.menu;\n menu.style.display = doShow\n ? 'block'\n : 'none';\n}\n",
+ "'use strict';\n\n\n// \n// milo.config\n// -----------\n\n// It is the function that allows to change milo configurations and also\n// access them on config's properties.\n\n// ```javascript\n// milo.config({\n// attrs: {\n// bind: 'ml-bind',\n// load: 'ml-load'\n// }\n// });\n// ```\n\n\nvar miloCore = require('milo-core')\n , _ = miloCore.proto\n , doT = miloCore.util.doT;\n\n\nvar config = module.exports = miloCore.config;\n\n\nconfig({\n attrs: {\n bind: 'ml-bind',\n load: 'ml-load'\n },\n componentRef: '___milo_component',\n componentPrefix: 'milo_',\n template: {\n compile: doT.compile\n },\n domStorage: {\n typeSuffix: ':___milo_data_type',\n prefixSeparator: '/',\n root: '',\n messageKey: '___milo_message/',\n messageTimestamp: '___milo_timestamp',\n quotaExceeded: {\n throwError: true,\n message: false\n }\n },\n dragDrop: {\n dataTypes: {\n component: 'x-application/milo/component',\n componentMetaTemplate: 'x-application/milo/component-meta/%class/%name/%params',\n componentMetaRegex: /^x\\-application\\/milo\\/component\\-meta\\/([a-z0-9]+)\\/([a-z0-9]+)\\/([a-z0-9]*)$/,\n }\n },\n request: {\n jsonpTimeout: 60000,\n jsonpCallbackPrefix: '___milo_callback_',\n optionsKey: '___milo_options',\n defaults: {\n timeout: 60000\n }\n },\n websocket: {\n rpc: {\n timeout: 15000,\n responsePrefix: 'response_'\n }\n }\n});\n",
+ "'use strict';\n\n\nvar miloMail = require('./services/mail')\n , request = require('./util/request')\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , _ = miloCore.proto\n , utilDom = require('./util/dom')\n , config = require('./config')\n , LoadAttribute = require('./attributes/a_load');\n\n\nmodule.exports = loader;\n\n/**\n * `milo.loader`\n * \n * Recursively scans the document tree inside `rootEl` (document.body by default) looking for __ml-load__ @attribute.\n * One level load is executed. No additional loader get called on inside __ml-load__ attributes. \n *\n * Possible usages:\n * - milo.loader([myRootEl,][myRemoveAttribute,]myCallback)\n * \n * @param {Element} rootEl Root element inside which DOM will be scanned (document.body by default).\n * @param {Boolean} removeAttribute If set to true, then the __ml-load__ attribute will be removed once loader has been executed (False by default).\n * @param {Function} callback Callback to call after all elements get loaded (Required).\n */\nfunction loader(rootEl, removeAttribute, callback) {\n milo(function() {\n _loader(rootEl, removeAttribute, callback);\n });\n}\n\n\nfunction _loader(rootEl, removeAttribute, callback) {\n if (typeof rootEl == 'function') {\n callback = rootEl;\n rootEl = undefined;\n removeAttribute = false;\n }\n\n if (typeof removeAttribute == 'function') {\n callback = removeAttribute;\n removeAttribute = false;\n }\n\n rootEl = rootEl || document.body;\n\n miloMail.postMessage('loader', { state: 'started' });\n _loadViewsInElement(rootEl, removeAttribute, function(views) {\n miloMail.postMessage('loader', { \n state: 'finished',\n views: views\n });\n callback(views);\n });\n}\n\n\nfunction _loadViewsInElement(rootEl, removeAttribute, callback) {\n var loadElements = rootEl.getAttribute(config.attrs.load)\n ? [rootEl]\n : rootEl.querySelectorAll('[' + config.attrs.load + ']');\n\n var views = {}\n , totalCount = loadElements.length\n , loadedCount = 0;\n\n _.forEach(loadElements, function (el) {\n loadView(el, removeAttribute, function(err) {\n views[el.id] = err || el;\n loadedCount++;\n if (loadedCount == totalCount)\n callback(views);\n });\n });\n};\n\n\nfunction loadView(el, removeAttribute, callback) {\n if (utilDom.children(el).length)\n throw new Error('can\\'t load html into element that is not empty');\n\n var attr = new LoadAttribute(el);\n\n attr.parse().validate();\n\n request.get(attr.loadUrl, function(err, html) {\n if (err) {\n err.message = err.message || 'can\\'t load file ' + attr.loadUrl;\n // logger.error(err.message);\n callback(err);\n return;\n }\n\n el.innerHTML = html;\n if (removeAttribute) LoadAttribute.remove(el);\n callback(null);\n });\n}\n",
+ "'use strict';\n\nvar miloCore = require('milo-core')\n , _ = miloCore.proto;\n\n\n// register included facets\nrequire('./use_facets');\n\n// register included components\nrequire('./use_components');\n\n\n/**\n * `milo`\n *\n * A minimalist browser framework that binds DOM elements to JS components and components to models.\n *\n * `milo` is available as global object in the browser.\n * At the moment it is not possiible to require it with browserify to have it bundled with the app because of the way [brfs](https://github.com/substack/brfs) browserify plugin is implemented.\n * It is possible though to require `milo` with node to use universal parts of the framework (abstract classes, Messenger, Model, etc.):\n * ```\n * var milo = require('mol-milo');\n * ```\n * \n * `milo` itself is a function that in the browser can be used to delay execution until DOM is ready.\n */\nfunction milo(func) {\n milo.util.domReady(func);\n}\n\n\n/**\n * ####Milo packages####\n *\n * - [loader](./loader.js.html) - loading subviews into page\n * - [binder](./binder.js.html) - components instantiation and binding of DOM elements to them\n * - [minder](./minder.js.html) - data reactivity, one or two way, shallow or deep, as you like it\n * - [mail](./mail/index.js.html) - applicaiton level messenger, also connects to messages from other windows dispatched with `window.postMessage`.\n * - [config](./config.js.html) - milo configuration\n * - [util](./util/index.js.html) - logger, request, dom, check, error, etc.\n * - [classes](./classes.js.html) - abstract and base classes\n * - [attributes](./attributes/index.js.html) - classes that wrap DOM elements attributes recognized by milo\n * - [ComponentFacet](./components/c_facet.js.html) - base class of Component facet\n * - [Component](./components/c_class.js.html) - base Component class\n * - [Messenger](./messenger/index.js.html) - generic Messenger used in most other milo classes, can be mixed into app classes too.\n * - [Model](./model/index.js.html) - Model class that emits messages on changes to any depth without timer based watching\n * - [registry](./registry.js.html) - registries of fasets and components classes\n */\n_.extend(milo, {\n Messenger: miloCore.Messenger,\n Model: miloCore.Model,\n minder: miloCore.minder,\n loader: require('./loader'),\n binder: require('./binder'),\n mail: require('./services/mail'),\n window: require('./services/window'),\n config: require('./config'),\n util: require('./util'),\n classes: require('./classes'),\n attributes: require('./attributes'),\n ComponentFacet: require('./components/c_facet'),\n Component: require('./components/c_class'),\n Command: require('./command'),\n registry: require('./registry'),\n milo_version: '0.1.10',\n createComponentClass: require('./util/create_component_class'),\n destroy: destroy\n});\n\n\n// export for node/browserify\nif (typeof module == 'object' && module.exports) \n module.exports = milo;\n\n// global milo for browser\nif (typeof window == 'object') {\n window.milo = milo;\n milo.mail.trigger('miloready');\n}\n\n\nfunction destroy() {\n miloCore.destroy();\n milo.mail.destroy();\n milo.window.destroy();\n milo.util.destroy();\n}\n",
"'use strict';\n\n/**\n * Registries of facets and of components\n *\n * - [facets](./components/c_facets/cf_registry.js.html)\n * - [components](./components/c_registry.js.html)\n */\nvar registry = module.exports = {\n facets: require('./components/c_facets/cf_registry'),\n components: require('./components/c_registry'),\n commands: require('./command/cmd_registry')\n};\n",
- "'use strict';\n\n// \n// ###dom events constructors\n\n\nvar _ = require('mol-proto');\n\n\n// https://developer.mozilla.org/en-US/docs/Web/Reference/Events\n\nvar eventTypes = {\n ClipboardEvent: ['copy', 'cut', 'paste', 'beforecopy', 'beforecut', 'beforepaste'],\n Event: ['input', 'readystatechange'],\n FocusEvent: ['focus', 'blur', 'focusin', 'focusout'],\n KeyboardEvent: ['keydown', 'keypress', 'keyup'],\n MouseEvent: ['click', 'contextmenu', 'dblclick', 'mousedown', 'mouseup',\n 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover',\n 'show' /* context menu */],\n TouchEvent: ['touchstart', 'touchend', 'touchmove', 'touchenter', 'touchleave', 'touchcancel'],\n};\n\n\n// mock window and event constructors for testing\nif (typeof window != 'undefined')\n var global = window;\nelse {\n global = {};\n _.eachKey(eventTypes, function(eTypes, eventConstructorName) {\n var eventConstructor = _.makeFunction(eventConstructorName, 'type', 'properties',\n 'this.type = type; _.extend(this, properties);');\n global[eventConstructorName] = eventConstructor;\n });\n}\n\n\nvar domEventsConstructors = {};\n\n_.eachKey(eventTypes, function(eTypes, eventConstructorName) {\n eTypes.forEach(function(type) {\n if (Object.hasOwnProperty(domEventsConstructors, type))\n throw new Error('duplicate event type ' + type);\n\n domEventsConstructors[type] = global[eventConstructorName];\n });\n});\n\n\nmodule.exports = domEventsConstructors;\n",
- "'use strict';\n\n\nvar MessageSource = require('../messenger/m_source')\n , Component = require('../components/c_class')\n , domEventsConstructors = require('./de_constrs') // TODO merge with DOMEventSource ??\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match;\n\nvar DOMEmitterSource = _.createSubclass(MessageSource, 'DOMEmitterSource', true);\n\n\n_.extendProto(DOMEmitterSource, {\n // implementing MessageSource interface\n init: init,\n destroy: DOMEmitterSource$destroy,\n addSourceSubscriber: _.partial(sourceSubscriberMethod, 'addEventListener'),\n removeSourceSubscriber: _.partial(sourceSubscriberMethod, 'removeEventListener'),\n postMessage: DOMEmitterSource$postMessage,\n trigger: trigger,\n\n // class specific methods\n emitter: emitter,\n handleEvent: handleEvent, // event dispatcher - as defined by Event DOM API\n});\n\nmodule.exports = DOMEmitterSource;\n\n\nvar useCapturePattern = /__capture$/\n , useCapturePostfix = '__capture';\n\n\n// init DOM event source\nfunction init(hostObject, proxyMethods, messengerAPIOrClass, eventEmitter) {\n this.eventEmitter = eventEmitter;\n MessageSource.prototype.init.apply(this, arguments);\n}\n\n\nfunction DOMEmitterSource$destroy() {\n MessageSource.prototype.destroy.apply(this, arguments);\n delete this.eventEmitter;\n}\n\n\n// get DOM element of component\nfunction emitter() {\n return this.eventEmitter;\n}\n\n\nfunction sourceSubscriberMethod(method, eventType) {\n if (! (eventType && typeof eventType == 'string')) return;\n var capture = useCapturePattern.test(eventType);\n eventType = eventType.replace(useCapturePattern, '');\n this.emitter()[method](eventType, this, capture);\n}\n\n\n// event dispatcher - as defined by Event DOM API\nfunction handleEvent(event) {\n var isCapturePhase;\n if (typeof window != 'undefined')\n isCapturePhase = event.eventPhase == window.Event.CAPTURING_PHASE;\n\n if (isCapturePhase)\n event += useCapturePostfix;\n\n this.dispatchMessage(event.type, event);\n}\n\n\nfunction DOMEmitterSource$postMessage(message, data) {\n this.messenger.postMessageSync(message, data);\n}\n\n\nfunction trigger(eventType, properties) {\n check(eventType, String);\n check(properties, Match.Optional(Object));\n\n eventType = eventType.replace(useCapturePattern, '');\n var EventConstructor = domEventsConstructors[eventType];\n\n if (typeof EventConstructor != 'function')\n throw new Error('unsupported event type');\n\n // check if it is correct\n if (typeof properties != 'undefined')\n properties.type = eventType;\n\n var domEvent = new EventConstructor(eventType, properties);\n var notCancelled = this.emitter().dispatchEvent(domEvent);\n return notCancelled;\n}\n",
- "'use strict';\n\n/**\n * `milo.mail`\n * It is an application level messenger that is an instance of Messenger class.\n *\n * At the moment, in addition to application messages that you define, you can subscribe to __domready__ message that is guaranteed to fire once,\n * even if DOM was ready at the time of the subscription.\n *\n * Messaging between frames is available via milo.mail. See [Frame facet](../components/c_facets/Frame.js.html).\n *\n * See [Messenger](../messenger/index.js.html).\n * \n**/\n\n\nvar Messenger = require('../../messenger')\n , MailMsgAPI = require('./mail_api')\n , MailMessageSource = require('./mail_source')\n , _ = require('mol-proto');\n\n\nvar miloMail = new Messenger;\n\nvar mailMsgSource = new MailMessageSource(miloMail, { trigger: 'trigger' }, new MailMsgAPI);\n\nmiloMail._setMessageSource(mailMsgSource);\n\n\nmodule.exports = miloMail;\n",
- "'use strict';\n\nvar MessengerAPI = require('../../messenger/m_api')\n , _ = require('mol-proto')\n , check = require('../../util/check')\n , Match = check.Match;\n\n\nvar MailMsgAPI = _.createSubclass(MessengerAPI, 'MailMsgAPI', true);\n\n\n_.extendProto(MailMsgAPI, {\n translateToSourceMessage: translateToSourceMessage,\n filterSourceMessage: filterSourceMessage\n});\n\nmodule.exports = MailMsgAPI;\n\n\n// TODO: this function should return relevant DOM event dependent on element tag\n// Can also implement beforedatachanged event to allow preventing the change\n// translateToDomEvent\nvar windowMessageRegExp = /^message\\:/\n , windowMessagePrefix = 'message:';\n\nfunction translateToSourceMessage(message) {\n if (message == 'domready')\n return 'readystatechange';\n else if (windowMessageRegExp.test(message))\n return 'message';\n}\n\n\n// filterDataMessage\nfunction filterSourceMessage(sourceMessage, msgType, msgData) {\n if (sourceMessage == 'readystatechange') {\n //return document.readyState == 'interactive';\n // return false;\n // _.defineProperty(this, '_domReadyFired', true, _.WRIT);\n return true;\n } else if (sourceMessage == 'message')\n return windowMessagePrefix + msgData.data.type == msgType;\n};\n",
- "'use strict';\n\nvar MessageSource = require('../../messenger/m_source')\n , domEventsConstructors = require('../de_constrs')\n , MailMessageSourceError = require('../../util/error').MailMessageSource\n , _ = require('mol-proto')\n , check = require('../../util/check')\n , Match = check.Match;\n\n\nvar MailMessageSource = _.createSubclass(MessageSource, 'MailMessageSource', true);\n\n\n_.extendProto(MailMessageSource, {\n // implementing MessageSource interface\n addSourceSubscriber: addSourceSubscriber,\n removeSourceSubscriber: removeSourceSubscriber,\n trigger: trigger,\n\n // class specific methods\n _windowSubscriberMethod: _windowSubscriberMethod,\n handleEvent: handleEvent, // event dispatcher - as defined by Event DOM API\n});\n\n\nmodule.exports = MailMessageSource;\n\n\nfunction addSourceSubscriber(sourceMessage) {\n if (isReadyStateChange(sourceMessage)) {\n if (document.readyState == 'loading')\n document.addEventListener('readystatechange', this, false);\n else {\n var EventConstructor = domEventsConstructors.readystatechange;\n var domEvent = new EventConstructor('readystatechange', { target: document });\n this.dispatchMessage('readystatechange', domEvent);\n }\n } else\n this._windowSubscriberMethod('addEventListener', sourceMessage);\n}\n\n\nfunction removeSourceSubscriber(sourceMessage) {\n if (isReadyStateChange(sourceMessage))\n document.removeEventListener('readystatechange', this, false);\n else \n this._windowSubscriberMethod('removeEventListener', sourceMessage);\n}\n\n\nfunction isReadyStateChange(sourceMessage) {\n return sourceMessage == 'readystatechange' && typeof document == 'object';\n}\n\nfunction isWindowMessage(sourceMessage) {\n return sourceMessage == 'message' && typeof window == 'object';\n}\n\nfunction _windowSubscriberMethod(method, sourceMessage) {\n if (isWindowMessage(sourceMessage))\n window[method]('message', this, false);\n}\n\n\n// event dispatcher - as defined by Event DOM API\nfunction handleEvent(event) {\n this.dispatchMessage(event.type, event);\n}\n\n\nfunction trigger(msgType, data) {\n data = data || {};\n data.type = 'message:' + msgType;\n \n if (typeof window == 'object')\n window.postMessage(data, '*')\n}\n",
- "'use strict';\n\n\nvar Messenger = require('../messenger')\n , DOMEmitterSource = require('./dom_source');\n\n\nvar windowService = new Messenger;\nvar domEmitterSource = new DOMEmitterSource(windowService, { trigger: 'trigger' }, undefined, window);\nwindowService._setMessageSource(domEmitterSource);\n\n\nmodule.exports = windowService;\n\n\n_.extend(windowService, {\n isTop: windowService_isTop\n});\n\n\nfunction windowService_isTop() {\n return window.top == window.self || window.__karma__;\n}\n",
+ "'use strict';\n\n// \n// ###dom events constructors\n\n\nvar _ = require('milo-core').proto;\n\n\n// https://developer.mozilla.org/en-US/docs/Web/Reference/Events\n\nvar eventTypes = {\n ClipboardEvent: ['copy', 'cut', 'paste', 'beforecopy', 'beforecut', 'beforepaste'],\n Event: ['input', 'readystatechange'],\n FocusEvent: ['focus', 'blur', 'focusin', 'focusout'],\n KeyboardEvent: ['keydown', 'keypress', 'keyup'],\n MouseEvent: ['click', 'contextmenu', 'dblclick', 'mousedown', 'mouseup',\n 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover',\n 'show' /* context menu */],\n TouchEvent: ['touchstart', 'touchend', 'touchmove', 'touchenter', 'touchleave', 'touchcancel'],\n};\n\n\n// mock window and event constructors for testing\nif (typeof window != 'undefined')\n var global = window;\nelse {\n global = {};\n _.eachKey(eventTypes, function(eTypes, eventConstructorName) {\n var eventConstructor = _.makeFunction(eventConstructorName, 'type', 'properties',\n 'this.type = type; _.extend(this, properties);');\n global[eventConstructorName] = eventConstructor;\n });\n}\n\n\nvar domEventsConstructors = {};\n\n_.eachKey(eventTypes, function(eTypes, eventConstructorName) {\n eTypes.forEach(function(type) {\n if (Object.hasOwnProperty(domEventsConstructors, type))\n throw new Error('duplicate event type ' + type);\n\n domEventsConstructors[type] = global[eventConstructorName];\n });\n});\n\n\nmodule.exports = domEventsConstructors;\n",
+ "'use strict';\n\n\nvar miloCore = require('milo-core')\n , MessageSource = miloCore.classes.MessageSource\n , Component = require('../components/c_class')\n , domEventsConstructors = require('./de_constrs') // TODO merge with DOMEventSource ??\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\nvar DOMEmitterSource = _.createSubclass(MessageSource, 'DOMEmitterSource', true);\n\n\n_.extendProto(DOMEmitterSource, {\n // implementing MessageSource interface\n init: init,\n destroy: DOMEmitterSource$destroy,\n addSourceSubscriber: _.partial(sourceSubscriberMethod, 'addEventListener'),\n removeSourceSubscriber: _.partial(sourceSubscriberMethod, 'removeEventListener'),\n postMessage: DOMEmitterSource$postMessage,\n trigger: trigger,\n\n // class specific methods\n emitter: emitter,\n handleEvent: handleEvent, // event dispatcher - as defined by Event DOM API\n});\n\nmodule.exports = DOMEmitterSource;\n\n\nvar useCapturePattern = /__capture$/\n , useCapturePostfix = '__capture';\n\n\n// init DOM event source\nfunction init(hostObject, proxyMethods, messengerAPIOrClass, eventEmitter) {\n this.eventEmitter = eventEmitter;\n MessageSource.prototype.init.apply(this, arguments);\n}\n\n\nfunction DOMEmitterSource$destroy() {\n MessageSource.prototype.destroy.apply(this, arguments);\n delete this.eventEmitter;\n}\n\n\n// get DOM element of component\nfunction emitter() {\n return this.eventEmitter;\n}\n\n\nfunction sourceSubscriberMethod(method, eventType) {\n if (! (eventType && typeof eventType == 'string')) return;\n var capture = useCapturePattern.test(eventType);\n eventType = eventType.replace(useCapturePattern, '');\n this.emitter()[method](eventType, this, capture);\n}\n\n\n// event dispatcher - as defined by Event DOM API\nfunction handleEvent(event) {\n var isCapturePhase;\n if (typeof window != 'undefined')\n isCapturePhase = event.eventPhase == window.Event.CAPTURING_PHASE;\n\n if (isCapturePhase)\n event += useCapturePostfix;\n\n this.dispatchMessage(event.type, event);\n}\n\n\nfunction DOMEmitterSource$postMessage(message, data) {\n this.messenger.postMessageSync(message, data);\n}\n\n\nfunction trigger(eventType, properties) {\n check(eventType, String);\n check(properties, Match.Optional(Object));\n\n eventType = eventType.replace(useCapturePattern, '');\n var EventConstructor = domEventsConstructors[eventType];\n\n if (typeof EventConstructor != 'function')\n throw new Error('unsupported event type');\n\n // check if it is correct\n if (typeof properties != 'undefined')\n properties.type = eventType;\n\n var domEvent = new EventConstructor(eventType, properties);\n var notCancelled = this.emitter().dispatchEvent(domEvent);\n return notCancelled;\n}\n",
+ "'use strict';\n\n/**\n * `milo.mail`\n * It is an application level messenger that is an instance of Messenger class.\n *\n * At the moment, in addition to application messages that you define, you can subscribe to __domready__ message that is guaranteed to fire once,\n * even if DOM was ready at the time of the subscription.\n *\n * Messaging between frames is available via milo.mail. See [Frame facet](../components/c_facets/Frame.js.html).\n *\n * See [Messenger](../messenger/index.js.html).\n * \n**/\n\n\nvar miloCore = require('milo-core')\n , Messenger = miloCore.Messenger\n , MailMsgAPI = require('./mail_api')\n , MailMessageSource = require('./mail_source')\n , _ = miloCore.proto;\n\n\nvar miloMail = new Messenger;\n\nvar mailMsgSource = new MailMessageSource(miloMail, { trigger: 'trigger' }, new MailMsgAPI);\n\nmiloMail._setMessageSource(mailMsgSource);\n\n\nmodule.exports = miloMail;\n",
+ "'use strict';\n\nvar miloCore = require('milo-core')\n , MessengerAPI = miloCore.classes.MessengerAPI\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\n\nvar MailMsgAPI = _.createSubclass(MessengerAPI, 'MailMsgAPI', true);\n\n\n_.extendProto(MailMsgAPI, {\n translateToSourceMessage: translateToSourceMessage,\n filterSourceMessage: filterSourceMessage\n});\n\nmodule.exports = MailMsgAPI;\n\n\n// TODO: this function should return relevant DOM event dependent on element tag\n// Can also implement beforedatachanged event to allow preventing the change\n// translateToDomEvent\nvar windowMessageRegExp = /^message\\:/\n , windowMessagePrefix = 'message:';\n\nfunction translateToSourceMessage(message) {\n if (message == 'domready')\n return 'readystatechange';\n else if (windowMessageRegExp.test(message))\n return 'message';\n}\n\n\n// filterDataMessage\nfunction filterSourceMessage(sourceMessage, msgType, msgData) {\n if (sourceMessage == 'readystatechange') {\n //return document.readyState == 'interactive';\n // return false;\n // _.defineProperty(this, '_domReadyFired', true, _.WRIT);\n return true;\n } else if (sourceMessage == 'message')\n return windowMessagePrefix + msgData.data.type == msgType;\n};\n",
+ "'use strict';\n\nvar miloCore = require('milo-core')\n , MessageSource = miloCore.classes.MessageSource\n , domEventsConstructors = require('../de_constrs')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\n\nvar MailMessageSource = _.createSubclass(MessageSource, 'MailMessageSource', true);\n\n\n_.extendProto(MailMessageSource, {\n // implementing MessageSource interface\n addSourceSubscriber: addSourceSubscriber,\n removeSourceSubscriber: removeSourceSubscriber,\n trigger: trigger,\n\n // class specific methods\n _windowSubscriberMethod: _windowSubscriberMethod,\n handleEvent: handleEvent, // event dispatcher - as defined by Event DOM API\n});\n\n\nmodule.exports = MailMessageSource;\n\n\nfunction addSourceSubscriber(sourceMessage) {\n if (isReadyStateChange(sourceMessage)) {\n if (document.readyState == 'loading')\n document.addEventListener('readystatechange', this, false);\n else {\n var EventConstructor = domEventsConstructors.readystatechange;\n var domEvent = new EventConstructor('readystatechange', { target: document });\n this.dispatchMessage('readystatechange', domEvent);\n }\n } else\n this._windowSubscriberMethod('addEventListener', sourceMessage);\n}\n\n\nfunction removeSourceSubscriber(sourceMessage) {\n if (isReadyStateChange(sourceMessage))\n document.removeEventListener('readystatechange', this, false);\n else \n this._windowSubscriberMethod('removeEventListener', sourceMessage);\n}\n\n\nfunction isReadyStateChange(sourceMessage) {\n return sourceMessage == 'readystatechange' && typeof document == 'object';\n}\n\nfunction isWindowMessage(sourceMessage) {\n return sourceMessage == 'message' && typeof window == 'object';\n}\n\nfunction _windowSubscriberMethod(method, sourceMessage) {\n if (isWindowMessage(sourceMessage))\n window[method]('message', this, false);\n}\n\n\n// event dispatcher - as defined by Event DOM API\nfunction handleEvent(event) {\n this.dispatchMessage(event.type, event);\n}\n\n\nfunction trigger(msgType, data) {\n data = data || {};\n data.type = 'message:' + msgType;\n \n if (typeof window == 'object')\n window.postMessage(data, '*')\n}\n",
+ "'use strict';\n\n\nvar miloCore = require('milo-core')\n , Messenger = miloCore.Messenger\n , DOMEmitterSource = require('./dom_source')\n , _ = miloCore.proto;\n\n\nvar windowService = new Messenger;\nvar domEmitterSource = new DOMEmitterSource(windowService, { trigger: 'trigger' }, undefined, window);\nwindowService._setMessageSource(domEmitterSource);\n\n\nmodule.exports = windowService;\n\n\n_.extend(windowService, {\n isTop: windowService_isTop\n});\n\n\nfunction windowService_isTop() {\n return window.top == window.self || window.__karma__;\n}\n",
"'use strict';\n\nrequire('./components/classes/View');\nrequire('./components/ui/Group');\nrequire('./components/ui/Wrapper');\nrequire('./components/ui/Text');\nrequire('./components/ui/Select');\nrequire('./components/ui/Input');\nrequire('./components/ui/InputList');\nrequire('./components/ui/Textarea');\nrequire('./components/ui/RadioGroup');\nrequire('./components/ui/Button');\nrequire('./components/ui/Hyperlink');\nrequire('./components/ui/List');\nrequire('./components/ui/ListItem');\nrequire('./components/ui/Time');\nrequire('./components/ui/Date');\nrequire('./components/ui/Combo');\nrequire('./components/ui/SuperCombo');\nrequire('./components/ui/ComboList');\nrequire('./components/ui/Image');\nrequire('./components/ui/DropTarget');\nrequire('./components/ui/FoldTree');\n\nrequire('./components/ui/bootstrap/Dropdown');\n// require('./components/ui/bootstrap/Dialog');\n",
"'use strict';\n\nrequire('./components/c_facets/Dom');\nrequire('./components/c_facets/Data');\nrequire('./components/c_facets/Frame');\nrequire('./components/c_facets/Events');\nrequire('./components/c_facets/Options');\nrequire('./components/c_facets/Template');\nrequire('./components/c_facets/Container');\nrequire('./components/c_facets/ModelFacet');\nrequire('./components/c_facets/Drag');\nrequire('./components/c_facets/Drop');\nrequire('./components/c_facets/List');\nrequire('./components/c_facets/Item');\nrequire('./components/c_facets/Transfer');\n",
- "'use strict';\n\n/**\n * `milo.utils.check`\n *\n * Check is a module for parameters checking extracted from [Meteor](http://docs.meteor.com/) framework.\n *\n * It allows to both document and to check parameter types in your function\n * making code both readable and stable.\n *\n *\n * ### Usage\n *```\n * var check = milo.check\n * , Match = check.Match;\n *\n * function My(name, obj, cb) {\n * // if any of checks fail an error will be thrown\n * check(name, String);\n * check(obj, Match.ObjectIncluding({ options: Object }));\n * check(cb, Function);\n *\n * // ... your code\n * }\n *```\n * See [Meteor docs](http://docs.meteor.com/#match) to see how it works\n *\n *\n * ### Patterns\n *\n * All patterns and functions described in Meteor docs work.\n *\n * Unlike in Meteor, Object pattern matches instance of any class,\n * not only plain object.\n *\n * In addition to patterns described in Meteor docs the following patterns are implemented\n *\n * * Match.__ObjectHash__(_pattern_)\n *\n * Matches an object where all properties match a given pattern\n *\n * * Match.__Subclass__(_constructor_ [, _matchThisClassToo_])\n *\n * Matches a class that is a subclass of a given class. If the second parameter\n * is true, it will also match the class itself.\n *\n * Without this pattern to check if _MySubclass_ is a subclass of _MyClass_\n * you would have to use\n *\n * check(MySubclass, Match.Where(function() {\n * return MySubclass.prototype instanceof MyClass;\n * });\n *\n *\n * Things we explicitly do NOT support:\n * - heterogenous arrays\n**/\n\nvar _ = require('mol-proto')\n , config = require('../config');\n\nvar check = function (value, pattern) {\n if (config.check === false)\n return;\n\n // Record that check got called, if somebody cared.\n try {\n checkSubtree(value, pattern);\n } catch (err) {\n if ((err instanceof Match.Error) && err.path)\n err.message += \" in field \" + err.path;\n throw err;\n }\n};\n\nmodule.exports = check;\n\nvar Match = check.Match = {\n Optional: function (pattern) {\n return new Optional(pattern);\n },\n OneOf: function (/* arguments */) {\n return new OneOf(arguments);\n },\n Any: ['__any__'],\n Where: function (condition) {\n return new Where(condition);\n },\n ObjectIncluding: function (pattern) {\n return new ObjectIncluding(pattern);\n },\n // Matches only signed 32-bit integers\n Integer: ['__integer__'],\n\n // Matches string that is a valid identifier, will not allow javascript reserved words\n IdentifierString: /^[a-z_$][0-9a-z_$]*$/i,\n\n // Matches hash (object) with values matching pattern\n ObjectHash: function(pattern) {\n return new ObjectHash(pattern);\n },\n\n Subclass: function(Superclass, matchSuperclassToo) {\n return new Subclass(Superclass, matchSuperclassToo);\n },\n\n // XXX matchers should know how to describe themselves for errors\n Error: TypeError,\n\n // Meteor.makeErrorType(\"Match.Error\", function (msg) {\n // this.message = \"Match error: \" + msg;\n // The path of the value that failed to match. Initially empty, this gets\n // populated by catching and rethrowing the exception as it goes back up the\n // stack.\n // E.g.: \"vals[3].entity.created\"\n // this.path = \"\";\n // If this gets sent over DDP, don't give full internal details but at least\n // provide something better than 500 Internal server error.\n // this.sanitizedError = new Meteor.Error(400, \"Match failed\");\n // }),\n\n // Tests to see if value matches pattern. Unlike check, it merely returns true\n // or false (unless an error other than Match.Error was thrown).\n test: function (value, pattern) {\n try {\n checkSubtree(value, pattern);\n return true;\n } catch (e) {\n if (e instanceof Match.Error)\n return false;\n // Rethrow other errors.\n throw e;\n }\n }\n};\n\nfunction Optional(pattern) {\n this.pattern = pattern;\n};\n\nfunction OneOf(choices) {\n if (choices.length == 0)\n throw new Error(\"Must provide at least one choice to Match.OneOf\");\n this.choices = choices;\n};\n\nfunction Where(condition) {\n this.condition = condition;\n};\n\nfunction ObjectIncluding(pattern) {\n this.pattern = pattern;\n};\n\nfunction ObjectHash(pattern) {\n this.pattern = pattern;\n};\n\nfunction Subclass(Superclass, matchSuperclassToo) {\n this.Superclass = Superclass;\n this.matchSuperclass = matchSuperclassToo;\n};\n\nvar typeofChecks = [\n [String, \"string\"],\n [Number, \"number\"],\n [Boolean, \"boolean\"],\n [Function, \"function\"],\n // While we don't allow undefined in JSON, this is good for optional\n // arguments with OneOf.\n [undefined, \"undefined\"]\n];\n\nfunction checkSubtree(value, pattern) {\n // Match anything!\n if (pattern === Match.Any)\n return;\n\n // Basic atomic types.\n // Do not match boxed objects (e.g. String, Boolean)\n for (var i = 0; i < typeofChecks.length; ++i) {\n if (pattern === typeofChecks[i][0]) {\n if (typeof value === typeofChecks[i][1])\n return;\n throw new Match.Error(\"Expected \" + typeofChecks[i][1] + \", got \" +\n typeof value);\n }\n }\n if (pattern === null) {\n if (value === null)\n return;\n throw new Match.Error(\"Expected null, got \" + JSON.stringify(value));\n }\n\n // Match.Integer is special type encoded with array\n if (pattern === Match.Integer) {\n // There is no consistent and reliable way to check if variable is a 64-bit\n // integer. One of the popular solutions is to get reminder of division by 1\n // but this method fails on really large floats with big precision.\n // E.g.: 1.348192308491824e+23 % 1 === 0 in V8\n // Bitwise operators work consistantly but always cast variable to 32-bit\n // signed integer according to JavaScript specs.\n if (typeof value === 'number' && (value | 0) === value)\n return\n throw new Match.Error('Expected Integer, got '\n + (value instanceof Object ? JSON.stringify(value) : value));\n }\n\n if (pattern === Match.IdentifierString) {\n if (typeof value === 'string' && Match.IdentifierString.test(value)\n && _jsKeywords.indexOf(key) == -1)\n return;\n throw new Match.Error('Expected identifier string, got '\n + (value instanceof Object ? JSON.stringify(value) : value));\n }\n\n // \"Object\" is shorthand for Match.ObjectIncluding({});\n if (pattern === Object)\n pattern = Match.ObjectIncluding({});\n\n // Array (checked AFTER Any, which is implemented as an Array).\n if (pattern instanceof Array) {\n if (pattern.length !== 1)\n throw Error(\"Bad pattern: arrays must have one type element\" +\n JSON.stringify(pattern));\n if (!Array.isArray(value)) {\n throw new Match.Error(\"Expected array, got \" + JSON.stringify(value));\n }\n\n value.forEach(function (valueElement, index) {\n try {\n checkSubtree(valueElement, pattern[0]);\n } catch (err) {\n if (err instanceof Match.Error) {\n err.path = _prependPath(index, err.path);\n }\n throw err;\n }\n });\n return;\n }\n\n // Arbitrary validation checks. The condition can return false or throw a\n // Match.Error (ie, it can internally use check()) to fail.\n if (pattern instanceof Where) {\n if (pattern.condition(value))\n return;\n // XXX this error is terrible\n throw new Match.Error(\"Failed Match.Where validation\");\n }\n\n\n if (pattern instanceof Optional)\n pattern = Match.OneOf(undefined, pattern.pattern);\n\n if (pattern instanceof OneOf) {\n for (var i = 0; i < pattern.choices.length; ++i) {\n try {\n checkSubtree(value, pattern.choices[i]);\n // No error? Yay, return.\n return;\n } catch (err) {\n // Other errors should be thrown. Match errors just mean try another\n // choice.\n if (!(err instanceof Match.Error))\n throw err;\n }\n }\n // XXX this error is terrible\n throw new Match.Error(\"Failed Match.OneOf or Match.Optional validation\");\n }\n\n // A function that isn't something we special-case is assumed to be a\n // constructor.\n if (pattern instanceof Function) {\n if (value instanceof pattern)\n return;\n // XXX what if .name isn't defined\n throw new Match.Error(\"Expected \" + pattern.constructor.name);\n }\n\n var unknownKeysAllowed = false;\n if (pattern instanceof ObjectIncluding) {\n unknownKeysAllowed = true;\n pattern = pattern.pattern;\n }\n\n if (pattern instanceof ObjectHash) {\n var keyPattern = pattern.pattern;\n var emptyHash = true;\n for (var key in value) {\n emptyHash = false;\n check(value[key], keyPattern);\n }\n if (emptyHash)\n throw new Match.Error(\"Expected \" + pattern.constructor.name);\n return;\n }\n\n if (pattern instanceof Subclass) {\n var Superclass = pattern.Superclass;\n if (pattern.matchSuperclass && value == Superclass)\n return;\n if (! (value.prototype instanceof Superclass))\n throw new Match.Error(\"Expected \" + pattern.constructor.name + \" of \" + Superclass.name);\n return;\n }\n\n if (typeof pattern !== \"object\")\n throw Error(\"Bad pattern: unknown pattern type\");\n\n // An object, with required and optional keys. Note that this does NOT do\n // structural matches against objects of special types that happen to match\n // the pattern: this really needs to be a plain old {Object}!\n if (typeof value !== 'object')\n throw new Match.Error(\"Expected object, got \" + typeof value);\n if (value === null)\n throw new Match.Error(\"Expected object, got null\");\n\n var requiredPatterns = {};\n var optionalPatterns = {};\n\n _.eachKey(pattern, function(subPattern, key) {\n if (pattern[key] instanceof Optional)\n optionalPatterns[key] = pattern[key].pattern;\n else\n requiredPatterns[key] = pattern[key];\n }, this, true);\n\n _.eachKey(value, function(subValue, key) {\n var subValue = value[key];\n try {\n if (requiredPatterns.hasOwnProperty(key)) {\n checkSubtree(subValue, requiredPatterns[key]);\n delete requiredPatterns[key];\n } else if (optionalPatterns.hasOwnProperty(key)) {\n checkSubtree(subValue, optionalPatterns[key]);\n } else {\n if (!unknownKeysAllowed)\n throw new Match.Error(\"Unknown key\");\n }\n } catch (err) {\n if (err instanceof Match.Error)\n err.path = _prependPath(key, err.path);\n throw err;\n }\n }, this, true);\n\n _.eachKey(requiredPatterns, function(value, key) {\n throw new Match.Error(\"Missing key '\" + key + \"'\");\n }, this, true);\n};\n\n\nvar _jsKeywords = [\"do\", \"if\", \"in\", \"for\", \"let\", \"new\", \"try\", \"var\", \"case\",\n \"else\", \"enum\", \"eval\", \"false\", \"null\", \"this\", \"true\", \"void\", \"with\",\n \"break\", \"catch\", \"class\", \"const\", \"super\", \"throw\", \"while\", \"yield\",\n \"delete\", \"export\", \"import\", \"public\", \"return\", \"static\", \"switch\",\n \"typeof\", \"default\", \"extends\", \"finally\", \"package\", \"private\", \"continue\",\n \"debugger\", \"function\", \"arguments\", \"interface\", \"protected\", \"implements\",\n \"instanceof\"];\n\n// Assumes the base of path is already escaped properly\n// returns key + base\nfunction _prependPath(key, base) {\n if ((typeof key) === \"number\" || key.match(/^[0-9]+$/))\n key = \"[\" + key + \"]\";\n else if (!key.match(Match.IdentifierString) || _jsKeywords.indexOf(key) != -1)\n key = JSON.stringify([key]);\n\n if (base && base[0] !== \"[\")\n return key + '.' + base;\n return key + base;\n};\n",
"'use strict';\n\nvar count = require('./count')\n , config = require('../config')\n , prefix = config.componentPrefix;\n\n\nmodule.exports = componentName;\n\n\nfunction componentName() {\n return prefix + count();\n}\n",
"'use strict';\n\nvar timestamp = Date.now()\n , count = ''\n , uniqueID = '' + timestamp;\n\nfunction uniqueCount() {\n var newTimestamp = Date.now();\n uniqueID = '' + newTimestamp;\n if (timestamp == newTimestamp) {\n count = count === '' ? 0 : count + 1;\n uniqueID += '_' + count;\n } else {\n timestamp = newTimestamp;\n count = '';\n }\n\n return uniqueID;\n}\n\nuniqueCount.get = function() {\n return uniqueID;\n}\n\nmodule.exports = uniqueCount;\n",
- "'use strict';\n\nmodule.exports = createComponentClass;\n\n/**\n * Utility function which creates and registers new milo component. The component created will have\n * a reference to the super class used in its creation (Accessable using .super).\n *\n * @param {string} config.className - The name of the new component\n * @param {string} ['Component'] config.superClassName - The name of an existing component to be used as the new component's super class\n * @param {object=} config.facets - Facet configuration (Hash of facet name {string} to config {object})\n * @param {object=} config.methods - Methods of the new component (Hash of function name {string} to function {function})\n * @param {object=} config.staticMethods - Static methods of the new component (Hash of function name {string} to function {function})\n */\nfunction createComponentClass(config) {\n var componentRegistry = milo.registry.components;\n var SuperClass = componentRegistry.get(config.superClassName || 'Component');\n var ComponentClass = SuperClass.createComponentClass(config.className, config.facets);\n\n if(config.methods) {\n _.extendProto(ComponentClass, config.methods);\n }\n\n if(config.staticMethods) {\n if(config.staticMethods.super !== undefined) throw '\\'super\\' is a reserved keyword';\n\n _.extend(ComponentClass, config.staticMethods);\n }\n\n ComponentClass.super = SuperClass.prototype;\n \n componentRegistry.add(ComponentClass);\n\n return ComponentClass;\n}",
- "'use strict';\n\n\nvar config = require('../config')\n , _ = require('mol-proto')\n , logger = require('./logger');\n\nvar domUtils = {\n children: children,\n filterNodeListByType: filterNodeListByType,\n containingElement: containingElement,\n selectElementContents: selectElementContents,\n selectElementText: selectElementText,\n getElementOffset: getElementOffset,\n setCaretPosition: setCaretPosition,\n getSelectionDirection: getSelectionDirection,\n setSelection: setSelection,\n clearSelection: clearSelection,\n removeElement: removeElement,\n unwrapElement: unwrapElement,\n wrapInElement: wrapInElement,\n detachComponent: detachComponent,\n firstTextNode: firstTextNode,\n lastTextNode: lastTextNode,\n trimNodeRight: trimNodeRight,\n trimNodeLeft: trimNodeLeft,\n stripHtml: stripHtml,\n htmlEntities: htmlEntities,\n walkTree: walkTree,\n createTreeWalker: createTreeWalker,\n\n treePathOf: treePathOf,\n getNodeAtTreePath: getNodeAtTreePath,\n insertAtTreePath: insertAtTreePath,\n isTreePathBefore: isTreePathBefore,\n\n getNodeWindow: getNodeWindow,\n\n getComponentsFromRange: getComponentsFromRange,\n deleteRangeWithComponents: deleteRangeWithComponents,\n forEachNodesInRange: forEachNodesInRange,\n areRangesEqual: areRangesEqual,\n\n addDebugPoint: addDebugPoint\n};\n\nmodule.exports = domUtils;\n\n\n/**\n * Returns the list of element children of DOM element\n *\n * @param {Element} el element to return the children of (only DOM elements)\n * @return {Array[Element]}\n */\n function children(el) {\n return filterNodeListByType(el.childNodes, Node.ELEMENT_NODE);\n }\n\n\n/**\n * Filters the list of nodes by type\n *\n * @param {NodeList} nodeList the list of nodes, for example childNodes property of DOM element\n * @param {Integer} nodeType an integer constant [defined by DOM API](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType), e.g. `Node.ELEMENT_NODE` or `Node.TEXT_NODE`\n * @return {Array[Node]}\n */\nfunction filterNodeListByType(nodeList, nodeType) {\n return _.filter(nodeList, function (node) {\n return node.nodeType == nodeType;\n });\n}\n\n\n/**\n * Find nearest parent element for node.\n * If node is an element, it will be returned.\n *\n * @param {Node} node\n * @return {Element|null}\n */\nfunction containingElement(node) {\n while (node) {\n if (node.nodeType == Node.ELEMENT_NODE)\n return node;\n node = node.parentNode;\n }\n return null;\n}\n\n\n/**\n * Selects inner contents of DOM element\n *\n * @param {Element} el DOM element\n */\nfunction selectElementContents(el) {\n var doc = el.ownerDocument;\n if (! doc) return logger.error('selectElementContents: element has no document');\n var range = doc.createRange();\n range.selectNodeContents(el);\n var win = getNodeWindow(el)\n , sel = win.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n\n/**\n * Selects text inside element\n * @param {Element} el\n */\nfunction selectElementText(el) {\n var fromNode = firstTextNode(el)\n , toNode = lastTextNode(el);\n\n if (fromNode && toNode)\n setSelection(fromNode, 0, toNode, toNode.textContent.length);\n}\n\n\n/**\n * Sets the caret position to the position in the node\n *\n * @param {Node} node DOM node\n * @param {Number} pos caret position\n */\nfunction setCaretPosition(node, pos) {\n var doc = node.ownerDocument;\n if (! doc) return logger.error('setCaretPosition: element has no document');\n var range = doc.createRange();\n range.setStart(node, pos);\n var win = getNodeWindow(node)\n , sel = win.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * get the direction of a selection\n *\n * 1 forward, -1 backward, 0 no direction, undefined one of the node is detached or in a different frame\n *\n * @param {sel} a selection object\n * @return {-1|0|1|undefined}\n */\nfunction getSelectionDirection(sel){\n return _getDirection(sel.anchorNode, sel.anchorOffset, sel.focusNode, sel.focusOffset);\n}\n\nfunction _getDirection(fromNode, startOffset, toNode, endOffset){\n var docPosition = fromNode.compareDocumentPosition(toNode);\n if (docPosition & Node.DOCUMENT_POSITION_FOLLOWING){\n return 1;\n }\n else if (docPosition & Node.DOCUMENT_POSITION_PRECEDING){\n return -1;\n }\n else if (fromNode == toNode){\n if (startOffset < endOffset){\n return 1;\n }\n else if (startOffset > endOffset){\n return -1;\n }\n else {\n return 0;\n }\n }\n}\n\n/**\n * Selects a range in a document\n *\n * @param {Node} fromNode DOM node to start selection in\n * @param {Number} startOffset\n * @param {Node} toNode DOM node to end selection in\n * @param {Number} endOffset\n */\nfunction setSelection(fromNode, startOffset, toNode, endOffset) {\n var doc = fromNode.ownerDocument;\n if (! doc) return logger('setCaretPosition: element has no document');\n var backward = _getDirection(fromNode, startOffset, toNode, endOffset) == -1;\n var range = doc.createRange();\n var container, originalContentEditable;\n // does not work in non contentEditable items\n\n var win = getNodeWindow(fromNode)\n , sel = win.getSelection();\n\n\n if (backward){\n range.setStart(toNode, endOffset);\n range.setEnd(fromNode, startOffset);\n range.collapse(false);\n }\n else {\n range.setStart(fromNode, startOffset);\n range.setEnd(toNode, endOffset);\n }\n\n container = range.commonAncestorContainer == Node.ELEMENT_NODE ?\n range.commonAncestorContainer :\n range.commonAncestorContainer.parentElement;\n\n if (!container.isContentEditable){\n originalContentEditable = container.contentEditable; // false or inherit\n container.contentEditable = \"true\";\n }\n\n sel.removeAllRanges();\n sel.addRange(range);\n\n if (backward){\n sel.extend(toNode, endOffset);\n }\n\n if (originalContentEditable){\n // restoring contentEditable\n container.contentEditable = originalContentEditable;\n }\n}\n\n/**\n * Clears selection in a given window\n * @param {Window} win\n */\nfunction clearSelection(win) {\n win = win || window;\n var sel = win.getSelection();\n sel.removeAllRanges();\n}\n\n\n/**\n * Calculates an element's total top and left offset from the document edge.\n *\n * @param {Element} el the element for which position needs to be returned\n * @param {includeBorder} if is to include the border width\n * @return {Object} vector object with properties topOffset and leftOffset\n */\nfunction getElementOffset(el, includeBorder) {\n var yPos, xPos;\n\n yPos = el.offsetTop;\n xPos = el.offsetLeft;\n el = el.offsetParent;\n\n while (el) {\n yPos += el.offsetTop + getBorder(el, 'Height', includeBorder);\n xPos += el.offsetLeft + getBorder(el, 'Width', includeBorder);\n el = el.offsetParent;\n }\n\n return { topOffset: yPos, leftOffset: xPos };\n}\n\n\nfunction getBorder(el, type, includeBorder) {\n if (includeBorder) {\n var side = (type == 'Height') ? 'top' : 'left',\n styles = window.getComputedStyle(el),\n sideValue = parseInt(styles.getPropertyValue('border-' + side + '-width'), 10);\n\n if (sideValue) return sideValue;\n }\n return 0;\n}\n\n\n/**\n * Removes element from the document\n *\n * @param {Element} el the element to be removed\n */\nfunction removeElement(el) {\n var parent = el.parentNode;\n if (parent){\n parent.removeChild(el);\n parent.normalize();\n }\n}\n\n\n/**\n * Returns the first child text node of an element\n *\n * @param {Element|Node} node the node to be searched, if the node is text node we return the node.\n * @return {TextNode}\n */\nfunction firstTextNode(node) {\n if (node.nodeType == Node.TEXT_NODE) return node;\n var treeWalker = createTreeWalker(node, NodeFilter.SHOW_TEXT);\n return treeWalker.firstChild();\n}\n\n\n/**\n * Returns the last child text node of an element\n *\n * @param {Element|Node} node the node to be searched, if the node is text node we return the node.\n * @return {TextNode}\n */\nfunction lastTextNode(node) {\n if (node.nodeType == Node.TEXT_NODE) return node;\n var treeWalker = createTreeWalker(node, NodeFilter.SHOW_TEXT);\n return treeWalker.lastChild();\n}\n\n\n/**\n * Removes element from the document putting its children in its place\n *\n * @param {Element} el the element to be \"unwrapped\"\n */\nfunction unwrapElement(el) {\n var parent = el.parentNode;\n\n if (parent) {\n var frag = document.createDocumentFragment();\n // must be copied to avoid iterating a mutating list of childNodes\n var children = _.slice(el.childNodes);\n children.forEach(frag.appendChild, frag);\n parent.replaceChild(frag, el);\n parent.normalize();\n }\n}\n\n\n/**\n * Wraps an element in another element\n *\n * @param {Element} wrapIntoEl\n * @param {Element} el\n */\nfunction wrapInElement(wrapIntoEl, el) {\n var parent = el.parentNode;\n\n if (parent) {\n parent.insertBefore(wrapIntoEl, el);\n wrapIntoEl.appendChild(el);\n }\n}\n\n\n/**\n * Trims a text node of trailing spaces, and returns true if a trim was performed.\n *\n * @param {TextNode} node\n * @return {Boolean}\n */\nfunction trimNodeRight(node) {\n return _trimNode(node, 'trimRight');\n}\n\n\n/**\n * Trims a text node of leading spaces, and returns true if a trim was performed.\n *\n * @param {TextNode} node\n * @return {Boolean}\n */\nfunction trimNodeLeft(node) {\n return _trimNode(node, 'trimLeft');\n}\n\n\nfunction _trimNode(node, methodName) {\n var len = node.length;\n node.textContent = node.textContent[methodName]();\n return len !== node.length;\n}\n\n\n/**\n * Removes the reference to component from element\n *\n * @param {Element} el\n */\nfunction detachComponent(el) {\n delete el[config.componentRef];\n}\n\n\n/**\n * Retrieves the content of a html string\n * @param {String} str Any string\n * @return {String} returns the string cleaned of any html content.\n */\nfunction stripHtml(str) {\n var div = document.createElement('DIV');\n div.innerHTML = str;\n return div.textContent || '';\n}\n\n\n/**\n * Convenience wrapper for native TreeWalker that automatically walks the tree and calls an iterator function.\n * This will not iterate the root element.\n * @param {HTMLElement} root The containing root element to be walked. Will not be iterated.\n * @param {NodeFiler} filter A NodeFilter constant, see https://developer.mozilla.org/en/docs/Web/API/TreeWalker\n * @param {Function} iterator A function to be called on each node. Returning 'false' will break.\n * @param {Object} context An optional context to passed, defaults to root.\n */\nfunction walkTree(root, filter, iterator, context) {\n var tw = document.createTreeWalker(root, filter);\n while(tw.nextNode()) {\n var result = iterator.call(context || root, tw.currentNode);\n if (result === false) break;\n }\n}\n\n\n/**\n * Returns array of child indexes of element path inside root element in DOM tree using breadth first tree traversal.\n * Returns undefined if the element is not inside root element, 0 if the root element itself is passed.\n *\n * @param {Element} rootEl element to search\n * @param {Element} el element to find the index of\n * @return {Array[Number]}\n */\nfunction treePathOf(rootEl, el) {\n if (! (rootEl && rootEl.contains(el))) return;\n\n var treePath = []\n , node = rootEl;\n\n while (node != el) {\n var nodeIndex = _.findIndex(node.childNodes, containsEl);\n treePath.push(nodeIndex);\n node = node.childNodes[nodeIndex];\n }\n\n return treePath;\n\n function containsEl(child) {\n return child.contains(el);\n }\n}\n\n\n/**\n * Returns element at given tree path\n *\n * @param {Element} rootEl\n * @param {Array[Number]} treePath\n * @param {Boolean} nearest return nearest possible node if exact node does not exist\n * @return {Node}\n */\nfunction getNodeAtTreePath(rootEl, treePath, nearest) {\n if (!treePath) return;\n\n var len = treePath.length;\n if (len === 0) return rootEl;\n\n var node = rootEl;\n\n for (var i = 0; i < len; i++) {\n var children = node.childNodes;\n if (! children) {\n if (! nearest) node = undefined;\n break;\n }\n var childIndex = treePath[i]\n , child = children[childIndex];\n if (! child) {\n node = nearest\n ? children[children.length - 1]\n : undefined;\n break;\n }\n node = child;\n }\n\n return node;\n}\n\n\n/**\n * Inserts an element inside root at a given path in tree (that has the same meaning as the index returned by `treePathOf` function). If element is already in the root's tree, it will be removed first and then moved to the passed treeIndex\n * Insertion at index 0 is not possible and will return undefined as it would mean replacing the root element.\n *\n * @param {Element} rootEl element into which to insert\n * @param {Number} treeIndex index in DOM tree inside root element (see treePathOf)\n * @param {Element} el element to be inserted\n * @return {Boolean} true if was successfully inserted\n */\nfunction insertAtTreePath(rootEl, treePath, el, nearest) {\n var toNormalize = el.nodeType == Node.TEXT_NODE;\n if (rootEl.contains(el))\n removeElement(el); // can't use removeChild as rootEl here is not an immediate parent\n\n if (treePath.length == 0) return;\n\n var parent = getNodeAtTreePath(rootEl, treePath.slice(0, -1), nearest)\n , children = parent.childNodes;\n\n if (! children) {\n if (nearest) {\n parent = parent.parentNode;\n children = parent.childNodes;\n } else return;\n }\n\n var childIndex = treePath[treePath.length - 1]\n , child = children[childIndex];\n\n if (child) {\n parent.insertBefore(el, child);\n if (toNormalize) parent.normalize();\n return true;\n } else if (children.length === 0 && (childIndex === 0 || nearest)) {\n parent.appendChild(el);\n if (toNormalize) parent.normalize();\n return true;\n } else {\n child = children[childIndex - 1];\n if (child || nearest) {\n parent.appendChild(el);\n if (toNormalize) parent.normalize();\n return true;\n }\n }\n}\n\n\n/**\n * Returns `true` if the first tree path points to a node which is before the other in the document order.\n * @param {Array} path1 A treepath array\n * @param {Array} path2 A treepath array\n * @return {Boolean}\n */\nfunction isTreePathBefore(path1, path2) {\n var i = 0\n , isBefore;\n if (!Array.isArray(path1) && Array.isArray(path2))\n return logger.error('isTreePathBefore: One or both paths are not valid treepath arrays.');\n\n for (i; i < path1.length; i++) {\n if (path1[i] < path2[i]) {\n isBefore = true;\n break;\n } else if (path1[i] > path2[i]) {\n isBefore = false;\n break;\n }\n }\n\n if (typeof isBefore == 'undefined')\n if (path1.length < path2.length)\n logger.warn('isTreePathBefore: One node is inside another');\n\n return isBefore || false;\n}\n\n\n/**\n * Converts non latin characters to HTML entity codes.\n * @param {String} str the string to convert\n * @return {String} the string with html entities\n */\nfunction htmlEntities(str) {\n return str.replace(/[\\u00A0-\\u99999<>\\&]/gim, function(i) {\n return ''+i.charCodeAt(0)+';';\n });\n}\n\n\nfunction createTreeWalker(el, whatToShow) {\n whatToShow = whatToShow || (NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT);\n return document.createTreeWalker(el, whatToShow);\n}\n\n\n/**\n * Returns the reference to the window the node is in\n *\n * @param {Node} node\n * @return {Window}\n */\nfunction getNodeWindow(node) {\n var doc = node.ownerDocument;\n return doc && (doc.defaultView || doc.parentWindow);\n}\n\n\n\n/**\n * do something for each nodes contained in a range\n *\n * @param {range} a range\n * @param {cb} a function taking a node as argument\n\n */\nfunction forEachNodesInRange(range, cb){\n var rangeContainer = range.commonAncestorContainer\n , doc = rangeContainer.ownerDocument;\n\n function isNodeInsideRange(node){\n var nodeRange = document.createRange();\n var isInside = false;\n nodeRange.selectNode(node);\n\n if (nodeRange.compareBoundaryPoints(window.Range.START_TO_START, range) != -1\n && nodeRange.compareBoundaryPoints(window.Range.END_TO_END, range) != 1){\n isInside = true;\n }\n nodeRange.detach();\n return isInside;\n }\n\n var treeWalker = doc.createTreeWalker(rangeContainer,\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);\n\n var currentNode;\n while (currentNode = treeWalker.nextNode()){ // should be assignment\n if (isNodeInsideRange(currentNode)){\n cb(currentNode);\n }\n }\n}\n\n/**\n * get all components contained in a range\n *\n * @param {range} a DOM range.\n */\nfunction getComponentsFromRange(range) {\n var win = getNodeWindow(range.startContainer)\n , Component = win.milo.Component;\n\n var components = [];\n forEachNodesInRange(range, function (node){\n if (node.nodeType != Node.TEXT_NODE) {\n var comp = Component.getComponent(node);\n if (comp)\n components.push(comp);\n }\n });\n\n return components;\n}\n\n/**\n * delete a range\n *\n * @param {range} delete a DOM range and all the components inside\n */\nfunction deleteRangeWithComponents(range) {\n var components = getComponentsFromRange(range);\n\n components.forEach(function(comp) {\n comp.destroy(true);\n });\n\n range.deleteContents();\n}\n\n/**\n * check if two ranges are equivalent\n *\n * @param {range} range1\n * @param {range} range2\n * @return {Boolean} are the two ranges equivalent\n */\nfunction areRangesEqual(range1, range2){\n return range1.compareBoundaryPoints(window.Range.START_TO_START, range2) == 0 && range1.compareBoundaryPoints(window.Range.END_TO_END, range2) == 0;\n}\n\n\n/**\n * Adds a single pixel div to the body at a given x and y position. Useful for debugging position specific code.\n * @param {Number} x\n * @param {Number} y\n */\nfunction addDebugPoint(x, y) {\n var dbEl = document.createElement('div');\n dbEl.setAttribute('style', 'width: 1px; height: 1px; position:fixed; left:'+x+'px; top:'+y+'px; background-color:red; z-index: 100');\n setTimeout(function() {document.body.appendChild(dbEl);}, 200);\n}\n",
- "'use strict';\n\n\nvar _ = require('mol-proto')\n , check = require('./check');\n\n\nmodule.exports = DOMListeners;\n\n\nfunction DOMListeners() {\n this.listeners = [];\n}\n\n\n_.extendProto(DOMListeners, {\n add: DOMListeners$add,\n remove: DOMListeners$remove,\n removeAll: DOMListeners$removeAll\n});\n\n\nfunction DOMListeners$add(target, eventType, handler) {\n this.listeners.push({\n target: target,\n eventType: eventType,\n handler: handler\n });\n target.addEventListener(eventType, handler);\n}\n\n\nfunction DOMListeners$remove(target, eventType, handler) {\n var listener = {\n target: target,\n eventType: eventType,\n handler: handler\n };\n var idx = _.findIndex(this.listeners, _.partial(_.isEqual, listener));\n\n if (idx > -1) {\n this.listeners.splice(idx, 1);\n _removeListener(listener);\n }\n}\n\n\nfunction DOMListeners$removeAll() {\n this.listeners.forEach(_removeListener);\n this.listeners = [];\n}\n\n\nfunction _removeListener(l) {\n l.target.removeEventListener(l.eventType, l.handler);\n}\n",
- "'use strict';\n\n\nvar _ = require('mol-proto');\n\n\nmodule.exports = domReady;\n\n\nvar domReadyFuncs = []\n , domReadySubscribed = false;\n\n\nfunction domReady(func) { // , arguments\n var self = this\n , args = _.slice(arguments, 1);\n if (isReady.call(this))\n callFunc();\n else {\n if (!domReadySubscribed) {\n document.addEventListener('readystatechange', onDomReady);\n domReadySubscribed = true;\n }\n domReadyFuncs.push(callFunc); // closure is added, so every time different function will be called\n }\n\n function callFunc() {\n func.apply(self, args);\n }\n}\n\n\nfunction onDomReady() {\n document.removeEventListener('readystatechange', onDomReady);\n domReadyFuncs.forEach(function(func) { func(); });\n}\n\n\n_.extend(domReady, {\n isReady: isReady\n});\n\n\nfunction isReady() {\n var readyState = document.readyState;\n return readyState == 'loading' ? false : readyState;\n}\n",
- "'use strict';\n\nvar Component = require('../components/c_class')\n , Messenger = require('../messenger')\n , dragDropConfig = require('../config').dragDrop\n , componentMetaRegex = dragDropConfig.dataTypes.componentMetaRegex\n , jsonParse = require('./json_parse')\n , _ = require('mol-proto')\n , base32 = require('base32');\n\n\nmodule.exports = DragDrop;\n\n\n/**\n * Wrapper for event.dataTransfer of drag-drop HTML API\n *\n * @constructor\n * @param {event} DOM event\n * @return {DragDrop}\n */\nfunction DragDrop(event) {\n this.event = event;\n this.dataTransfer = event.dataTransfer;\n this.types = event.dataTransfer.types;\n}\n\n/**\n * Usage:\n * var testDT = new DragDrop(event);\n * testDT.setComponentMeta(newComponent, {test: 'test', test2: 'test2'});\n * testDT.getComponentMeta();\n */\n\n_.extend(DragDrop, {\n componentDataType: DragDrop$$componentDataType\n});\n\n_.extendProto(DragDrop, {\n isComponent: DragDrop$isComponent,\n getComponentState: DragDrop$getComponentState,\n setComponentState: DragDrop$setComponentState,\n getComponentMeta: DragDrop$getComponentMeta,\n setComponentMeta: DragDrop$setComponentMeta,\n getAllowedEffects: DragDrop$getAllowedEffects,\n setAllowedEffects: DragDrop$setAllowedEffects,\n getDropEffect: DragDrop$getDropEffect,\n setDropEffect: DragDrop$setDropEffect,\n isEffectAllowed: DragDrop$isEffectAllowed,\n getData: DragDrop$getData,\n setData: DragDrop$setData,\n clearData: DragDrop$clearData\n});\n\n\nfunction DragDrop$$componentDataType() {\n return dragDropConfig.dataTypes.component;\n}\n\n\nfunction DragDrop$isComponent() {\n return _.indexOf(this.types, DragDrop.componentDataType()) >= 0;\n}\n\n\nfunction DragDrop$getComponentState() {\n var dataType = DragDrop.componentDataType()\n , stateStr = this.dataTransfer.getData(dataType)\n , state = jsonParse(stateStr);\n\n return state;\n}\n\n\nfunction DragDrop$setComponentState(component, stateStr){\n if (! stateStr) {\n var state = component.getTransferState({ requestedBy: 'drag' });\n stateStr = JSON.stringify(state);\n }\n var dataType = DragDrop.componentDataType();\n\n stateStr && this.dataTransfer.setData(dataType, stateStr);\n this.dataTransfer.setData('text/html', component.el.outerHTML);\n return stateStr;\n}\n\n\nfunction DragDrop$setComponentMeta(component, params, data) {\n var meta = _componentMeta(component);\n\n var paramsStr = _.toQueryString(params);\n var dataType = dragDropConfig.dataTypes.componentMetaTemplate\n .replace('%class', _encode(meta.compClass || ''))\n .replace('%name', _encode(meta.compName || ''))\n .replace('%params', _encode(paramsStr || ''));\n\n if (data && typeof data == 'object') data = JSON.stringify(data);\n\n this.dataTransfer.setData(dataType, data || '');\n\n return dataType;\n}\n\n\nfunction _encode(str) {\n return base32.encode(str).toLowerCase();\n}\n\n\nfunction _componentMeta(component) {\n return component.transfer\n ? component.transfer.getComponentMeta()\n : { \n compClass: component.constructor.name,\n compName: component.name\n };\n}\n\n\nfunction DragDrop$getComponentMeta() {\n var match;\n var metaDataType = _.find(this.types, function (dType) {\n match = dType.match(componentMetaRegex);\n return !!match;\n });\n if (!metaDataType) return;\n\n for (var i=1; i<4; i++)\n match[i] = base32.decode(match[i]);\n\n return {\n compClass: match[1],\n compName: match[2],\n params: _.fromQueryString(match[3]),\n metaDataType: metaDataType,\n metaData: _.jsonParse(this.dataTransfer.getData(metaDataType)) \n ? _.jsonParse(this.dataTransfer.getData(metaDataType)) \n : this.dataTransfer.getData(metaDataType)\n };\n}\n\n\n// as defined here: https://developer.mozilla.org/en-US/docs/DragDrop/Drag_Operations#dragstart\nfunction DragDrop$getAllowedEffects() {\n return this.dataTransfer.effectAllowed;\n}\n\n\nfunction DragDrop$setAllowedEffects(effects) {\n this.dataTransfer.effectAllowed = effects;\n}\n\n\nfunction DragDrop$getDropEffect() {\n return this.dataTransfer.dropEffect;\n}\n\n\nfunction DragDrop$setDropEffect(effect) {\n this.dataTransfer.dropEffect = effect;\n}\n\n\nfunction DragDrop$isEffectAllowed(effect) {\n var allowedEffects = this.getAllowedEffects()\n , isCopy = effect == 'copy'\n , isMove = effect == 'move'\n , isLink = effect == 'link'\n , isAllowed = isCopy || isLink || isMove;\n\n switch (allowedEffects) {\n case 'copy':\n case 'move':\n case 'link':\n return allowedEffects == effect;\n case 'copyLink':\n return isCopy || isLink;\n case 'copyMove':\n return isCopy || isMove;\n case 'linkMove':\n return isLink || isMove;\n case 'all':\n case 'uninitialized':\n return isAllowed;\n case 'none':\n return false;\n }\n}\n\n\nfunction DragDrop$getData(dataType) {\n return this.dataTransfer.getData(dataType);\n}\n\n\nfunction DragDrop$setData(dataType, dataStr) {\n this.dataTransfer.setData(dataType, dataStr);\n}\n\n\nfunction DragDrop$clearData(dataType) {\n this.dataTransfer.clearData(dataType);\n}\n\n\n/**\n * Drag drop service compensating for the lack of communication from drop target to drag source in DOM API\n */\nvar dragDropService = new Messenger;\n\nvar _currentDragDrop, _currentDragFacet;\n\n_.extend(DragDrop, {\n service: dragDropService,\n destroy: DragDrop_destroy\n});\n\n\ndragDropService.onMessages({\n // data is DragDropDataTransfer instance\n // fired by Drag facet on \"dragstart\" event\n 'dragdropstarted': onDragDropStarted, \n // data is object with at least dropEffect property\n // fired by Drop facet on \"drop\" event\n 'dragdropcompleted': onDragDropCompleted, \n // fired by Drag facet on \"dragend\" event to complete drag\n // if drop happended in another window or if it was cancelled\n 'completedragdrop': onCompleteDragDrop\n});\n\n\n_.extend(dragDropService, {\n getCurrentDragDrop: getCurrentDragDrop\n});\n\n\nfunction onDragDropStarted(msg, data) {\n _currentDragDrop = data.dragDrop;\n _currentDragFacet = data.dragFacet;\n}\n\n\nfunction onDragDropCompleted(msg, data) {\n _currentDragFacet && _currentDragFacet.postMessageSync('dragdropcompleted', data);\n _currentDragDrop = undefined;\n _currentDragFacet = undefined;\n}\n\n\nfunction onCompleteDragDrop(msg, data) {\n if (_currentDragDrop)\n dragDropService.postMessageSync('dragdropcompleted', data);\n}\n\n\nfunction getCurrentDragDrop() {\n return _currentDragDrop;\n}\n\n\nfunction DragDrop_destroy() {\n dragDropService.offAll();\n}\n",
- "// \n// milo.utils.error\n// -----------\n\n'use strict';\n\nvar _ = require('mol-proto');\n\n\n// module exports error classes for all names defined in this array\nvar errorClassNames = ['AbstractClass', 'Mixin', 'Messenger', 'Component',\n 'Attribute', 'Binder', 'Loader', 'MailMessageSource', 'Facet',\n 'Scope', 'Model', 'DomFacet', 'EditableFacet',\n 'List', 'Connector', 'Registry', 'FrameMessageSource',\n 'Drop', 'Angular', 'StorageMessageSource'];\n\nvar error = {\n toBeImplemented: error$toBeImplemented,\n createClass: error$createClass\n};\n\nerrorClassNames.forEach(function(name) {\n error[name] = error$createClass(name + 'Error');\n});\n\nmodule.exports = error;\n\n\nfunction error$createClass(errorClassName) {\n var ErrorClass = _.makeFunction(errorClassName, 'message',\n 'this.name = \"' + errorClassName + '\"; \\\n this.message = message || \"There was an error\";');\n _.makeSubclass(ErrorClass, Error);\n\n return ErrorClass;\n}\n\n\nfunction error$toBeImplemented() {\n throw new error.AbstractClass('calling the method of an absctract class');\n}\n",
- "'use strict';\n\n\nvar Component = require('../components/c_class')\n , BindAttribute = require('../attributes/a_bind')\n , binder = require('../binder')\n , domUtils = require('./dom')\n , logger = require('./logger')\n , check = require('./check')\n , _ = require('mol-proto');\n\n\nvar createRangePaths = _createNodesAndPathsFunc(domUtils.treePathOf);\nvar createRangeNodes = _createNodesAndPathsFunc(domUtils.getNodeAtTreePath);\n\n\nvar fragmentUtils = module.exports = {\n getState: fragment_getState,\n getStateAsync: fragment_getStateAsync,\n\n expandRangeToSiblings: expandRangeToSiblings,\n getRangeSiblings: getRangeSiblings,\n createRangeFromSiblings: createRangeFromSiblings,\n createRangeFromNodes: createRangeFromSiblings, // alias\n createRangePaths: createRangePaths,\n createRangeNodes: createRangeNodes\n};\n\n\n/**\n * Creates an object with the state of wrapped range with components, including partially selected. The range will be cloned and wrapped in component with container facet before getting its state.\n * This function will log error and return undefined if range has no common ancestor that has component with container facet\n * \n * @param {Range} range DOM Range instance\n * @param {Boolean} renameChildren optional parameter, `true` to rename fragment child components\n * @param {String} wrapperClassName optional parameter to wrap in a custom component class\n * @return {Object}\n */\nfunction fragment_getState(range, renameChildren, wrapperClassName) {\n var rangeContainer = _getRangeContainer(range);\n if (! rangeContainer) {\n logger.error('fragment.getState: range has no common container');\n return;\n }\n\n var frag = range.cloneContents()\n , wrapper = _wrapFragmentInContainer(frag, wrapperClassName);\n\n _transferStates(rangeContainer, wrapper);\n if (renameChildren) _renameChildren(wrapper);\n var wrapperState = wrapper.getState();\n _.deferMethod(wrapper, 'destroy');\n return wrapperState;\n}\n\n\n/**\n * Creates an object with the state of wrapped range with components, including partially selected. The range will be cloned and wrapped in component with container facet before getting its state.\n * This function will return result and any error via callback.\n * \n * @param {Range} range DOM Range instance\n * @param {Boolean} renameChildren optional parameter, `true` to rename fragment child components\n * @param {Function} callback always the last parameter, optional parameters can be dropped; result is passed via callback with any error as first parameter\n */\nfunction fragment_getStateAsync(range, renameChildren, callback) {\n try {\n var rangeContainer = _getRangeContainer(range);\n if (! rangeContainer) {\n callback(new Error('fragment.getState: range has no common container'));\n return; // do NOT connect return to previous callback, getState should return undefined\n }\n\n if (typeof renameChildren == 'function') {\n callback = renameChildren;\n renameChildren = false;\n }\n\n var frag = range.cloneContents()\n , wrapper = _wrapFragmentInContainer(frag);\n\n _transferStates(rangeContainer, wrapper);\n _.defer(function() {\n wrapper.broadcast('stateready');\n _.defer(function() {\n if (renameChildren) _renameChildren(wrapper);\n var wrapperState = wrapper.getState();\n wrapper.destroy();\n callback(null, wrapperState);\n });\n });\n } catch (err) {\n callback(err);\n }\n}\n\n\nfunction _wrapFragmentInContainer(frag, wrapperClassName) {\n var wrapEl = document.createElement('div')\n , attr = new BindAttribute(wrapEl);\n\n _.extend(attr, {\n compClass: wrapperClassName || 'Component',\n compFacets: wrapperClassName ? [] : ['container'],\n compName: 'wrapper'\n });\n\n attr.decorate();\n\n wrapEl.appendChild(frag);\n var scope = binder(wrapEl);\n return scope.wrapper;\n}\n\n\nfunction _getRangeContainer(range) {\n var el = domUtils.containingElement(range.commonAncestorContainer);\n return Component.getContainingComponent(el, true, 'container');\n}\n\n\nfunction _transferStates(fromComp, toComp) {\n var fromScope = fromComp.container.scope;\n toComp.container.scope._each(function(toChildComp, name) {\n var fromChildComp = fromScope[name];\n if (! fromChildComp) return logger.error('fragment.getState: conponent', name, 'not found in range');\n var state = fromChildComp._getState(true);\n toChildComp.setState(state);\n });\n}\n\n\nfunction _renameChildren(comp) {\n comp.container.scope._each(function(child) {\n child.rename();\n });\n}\n\n\nfunction expandRangeToSiblings(range) {\n var siblings = getRangeSiblings(range);\n range = createRangeFromSiblings(siblings);\n return range;\n}\n\n\nfunction createRangeFromSiblings(nodes) {\n var range = document.createRange();\n if (nodes.siblings) {\n range.setStartBefore(nodes.start);\n range.setEndAfter(nodes.end);\n } else\n range.selectNode(nodes.start);\n return range;\n}\n\n\nfunction getRangeSiblings(range) {\n var containerNode = range.commonAncestorContainer\n , startNode = range.startContainer\n , endNode = range.endContainer;\n\n if (startNode == endNode) {\n if (startNode != containerNode) logger.error('deleteSelectionCommand logical error: start==end, but container is different');\n return { siblings: false, start: startNode };\n }\n\n if (startNode == containerNode || endNode == containerNode)\n return { siblings: false, start: containerNode };\n\n var startSibling = _findContainingChild(containerNode, startNode);\n var endSibling = _findContainingChild(containerNode, endNode);\n\n if (startSibling && endSibling) {\n if (startSibling == endSibling) {\n logger.error('deleteSelectionCommand logical error: same siblings');\n return { siblings: false, start: startSibling };\n } else\n return { siblings: true, start: startSibling, end: endSibling };\n }\n}\n\n\nfunction _findContainingChild(containerNode, selNode) {\n return _.find(containerNode.childNodes, function(node) {\n return node.contains(selNode);\n });\n}\n\n\nfunction _createNodesAndPathsFunc(func) {\n return function(rootEl, fromObj) {\n var toObj = {\n siblings: fromObj.siblings,\n start: func(rootEl, fromObj.start)\n };\n if (toObj.siblings)\n toObj.end = func(rootEl, fromObj.end);\n return toObj;\n };\n}\n\n\n",
- "'use strict';\n\n/**\n * `milo.util`\n */\nvar util = {\n logger: require('./logger'),\n request: require('./request'),\n websocket: require('./websocket'),\n check: require('./check'),\n error: require('./error'),\n count: require('./count'), // deprecated\n uniqueId: require('./count'),\n componentName: require('./component_name'),\n dom: require('./dom'),\n domListeners: require('./dom_listeners'),\n selection: require('./selection'),\n fragment: require('./fragment'),\n jsonParse: require('./json_parse'),\n storage: require('./storage'),\n domReady: require('./domready'),\n dragDrop: require('./dragdrop'),\n dialog: require('../components/ui/bootstrap/Dialog'),\n alert: require('../components/ui/bootstrap/Alert'),\n doT: require('dot'),\n destroy: util_destroy\n};\n\nmodule.exports = util;\n\n\nfunction util_destroy() {\n util.request.destroy();\n util.dragDrop.destroy();\n}\n",
+ "'use strict';\n\nvar _ = require('milo-core').proto;\n\n\nmodule.exports = createComponentClass;\n\n/**\n * Utility function which creates and registers new milo component. The component created will have\n * a reference to the super class used in its creation (Accessable using .super).\n *\n * @param {string} config.className - The name of the new component\n * @param {string} ['Component'] config.superClassName - The name of an existing component to be used as the new component's super class\n * @param {object=} config.facets - Facet configuration (Hash of facet name {string} to config {object})\n * @param {object=} config.methods - Methods of the new component (Hash of function name {string} to function {function})\n * @param {object=} config.staticMethods - Static methods of the new component (Hash of function name {string} to function {function})\n */\nfunction createComponentClass(config) {\n var componentRegistry = milo.registry.components;\n var SuperClass = componentRegistry.get(config.superClassName || 'Component');\n var ComponentClass = SuperClass.createComponentClass(config.className, config.facets);\n\n if(config.methods) {\n _.extendProto(ComponentClass, config.methods);\n }\n\n if(config.staticMethods) {\n if(config.staticMethods.super !== undefined) throw '\\'super\\' is a reserved keyword';\n\n _.extend(ComponentClass, config.staticMethods);\n }\n\n ComponentClass.super = SuperClass.prototype;\n \n componentRegistry.add(ComponentClass);\n\n return ComponentClass;\n}\n",
+ "'use strict';\n\n\nvar config = require('../config')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , logger = miloCore.util.logger;\n\nvar domUtils = {\n children: children,\n filterNodeListByType: filterNodeListByType,\n containingElement: containingElement,\n selectElementContents: selectElementContents,\n selectElementText: selectElementText,\n getElementOffset: getElementOffset,\n setCaretPosition: setCaretPosition,\n getSelectionDirection: getSelectionDirection,\n setSelection: setSelection,\n clearSelection: clearSelection,\n removeElement: removeElement,\n unwrapElement: unwrapElement,\n wrapInElement: wrapInElement,\n detachComponent: detachComponent,\n firstTextNode: firstTextNode,\n lastTextNode: lastTextNode,\n trimNodeRight: trimNodeRight,\n trimNodeLeft: trimNodeLeft,\n stripHtml: stripHtml,\n htmlEntities: htmlEntities,\n walkTree: walkTree,\n createTreeWalker: createTreeWalker,\n\n treePathOf: treePathOf,\n getNodeAtTreePath: getNodeAtTreePath,\n insertAtTreePath: insertAtTreePath,\n isTreePathBefore: isTreePathBefore,\n\n getNodeWindow: getNodeWindow,\n\n getComponentsFromRange: getComponentsFromRange,\n deleteRangeWithComponents: deleteRangeWithComponents,\n forEachNodesInRange: forEachNodesInRange,\n areRangesEqual: areRangesEqual,\n\n addDebugPoint: addDebugPoint\n};\n\nmodule.exports = domUtils;\n\n\n/**\n * Returns the list of element children of DOM element\n *\n * @param {Element} el element to return the children of (only DOM elements)\n * @return {Array[Element]}\n */\n function children(el) {\n return filterNodeListByType(el.childNodes, Node.ELEMENT_NODE);\n }\n\n\n/**\n * Filters the list of nodes by type\n *\n * @param {NodeList} nodeList the list of nodes, for example childNodes property of DOM element\n * @param {Integer} nodeType an integer constant [defined by DOM API](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType), e.g. `Node.ELEMENT_NODE` or `Node.TEXT_NODE`\n * @return {Array[Node]}\n */\nfunction filterNodeListByType(nodeList, nodeType) {\n return _.filter(nodeList, function (node) {\n return node.nodeType == nodeType;\n });\n}\n\n\n/**\n * Find nearest parent element for node.\n * If node is an element, it will be returned.\n *\n * @param {Node} node\n * @return {Element|null}\n */\nfunction containingElement(node) {\n while (node) {\n if (node.nodeType == Node.ELEMENT_NODE)\n return node;\n node = node.parentNode;\n }\n return null;\n}\n\n\n/**\n * Selects inner contents of DOM element\n *\n * @param {Element} el DOM element\n */\nfunction selectElementContents(el) {\n var doc = el.ownerDocument;\n if (! doc) return logger.error('selectElementContents: element has no document');\n var range = doc.createRange();\n range.selectNodeContents(el);\n var win = getNodeWindow(el)\n , sel = win.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n\n/**\n * Selects text inside element\n * @param {Element} el\n */\nfunction selectElementText(el) {\n var fromNode = firstTextNode(el)\n , toNode = lastTextNode(el);\n\n if (fromNode && toNode)\n setSelection(fromNode, 0, toNode, toNode.textContent.length);\n}\n\n\n/**\n * Sets the caret position to the position in the node\n *\n * @param {Node} node DOM node\n * @param {Number} pos caret position\n */\nfunction setCaretPosition(node, pos) {\n var doc = node.ownerDocument;\n if (! doc) return logger.error('setCaretPosition: element has no document');\n var range = doc.createRange();\n range.setStart(node, pos);\n var win = getNodeWindow(node)\n , sel = win.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * get the direction of a selection\n *\n * 1 forward, -1 backward, 0 no direction, undefined one of the node is detached or in a different frame\n *\n * @param {sel} a selection object\n * @return {-1|0|1|undefined}\n */\nfunction getSelectionDirection(sel){\n return _getDirection(sel.anchorNode, sel.anchorOffset, sel.focusNode, sel.focusOffset);\n}\n\nfunction _getDirection(fromNode, startOffset, toNode, endOffset){\n var docPosition = fromNode.compareDocumentPosition(toNode);\n if (docPosition & Node.DOCUMENT_POSITION_FOLLOWING){\n return 1;\n }\n else if (docPosition & Node.DOCUMENT_POSITION_PRECEDING){\n return -1;\n }\n else if (fromNode == toNode){\n if (startOffset < endOffset){\n return 1;\n }\n else if (startOffset > endOffset){\n return -1;\n }\n else {\n return 0;\n }\n }\n}\n\n/**\n * Selects a range in a document\n *\n * @param {Node} fromNode DOM node to start selection in\n * @param {Number} startOffset\n * @param {Node} toNode DOM node to end selection in\n * @param {Number} endOffset\n */\nfunction setSelection(fromNode, startOffset, toNode, endOffset) {\n var doc = fromNode.ownerDocument;\n if (! doc) return logger('setCaretPosition: element has no document');\n var backward = _getDirection(fromNode, startOffset, toNode, endOffset) == -1;\n var range = doc.createRange();\n var container, originalContentEditable;\n // does not work in non contentEditable items\n\n var win = getNodeWindow(fromNode)\n , sel = win.getSelection();\n\n\n if (backward){\n range.setStart(toNode, endOffset);\n range.setEnd(fromNode, startOffset);\n range.collapse(false);\n }\n else {\n range.setStart(fromNode, startOffset);\n range.setEnd(toNode, endOffset);\n }\n\n container = range.commonAncestorContainer == Node.ELEMENT_NODE ?\n range.commonAncestorContainer :\n range.commonAncestorContainer.parentElement;\n\n if (!container.isContentEditable){\n originalContentEditable = container.contentEditable; // false or inherit\n container.contentEditable = \"true\";\n }\n\n sel.removeAllRanges();\n sel.addRange(range);\n\n if (backward){\n sel.extend(toNode, endOffset);\n }\n\n if (originalContentEditable){\n // restoring contentEditable\n container.contentEditable = originalContentEditable;\n }\n}\n\n/**\n * Clears selection in a given window\n * @param {Window} win\n */\nfunction clearSelection(win) {\n win = win || window;\n var sel = win.getSelection();\n sel.removeAllRanges();\n}\n\n\n/**\n * Calculates an element's total top and left offset from the document edge.\n *\n * @param {Element} el the element for which position needs to be returned\n * @param {includeBorder} if is to include the border width\n * @return {Object} vector object with properties topOffset and leftOffset\n */\nfunction getElementOffset(el, includeBorder) {\n var yPos, xPos;\n\n yPos = el.offsetTop;\n xPos = el.offsetLeft;\n el = el.offsetParent;\n\n while (el) {\n yPos += el.offsetTop + getBorder(el, 'Height', includeBorder);\n xPos += el.offsetLeft + getBorder(el, 'Width', includeBorder);\n el = el.offsetParent;\n }\n\n return { topOffset: yPos, leftOffset: xPos };\n}\n\n\nfunction getBorder(el, type, includeBorder) {\n if (includeBorder) {\n var side = (type == 'Height') ? 'top' : 'left',\n styles = window.getComputedStyle(el),\n sideValue = parseInt(styles.getPropertyValue('border-' + side + '-width'), 10);\n\n if (sideValue) return sideValue;\n }\n return 0;\n}\n\n\n/**\n * Removes element from the document\n *\n * @param {Element} el the element to be removed\n */\nfunction removeElement(el) {\n var parent = el.parentNode;\n if (parent){\n parent.removeChild(el);\n parent.normalize();\n }\n}\n\n\n/**\n * Returns the first child text node of an element\n *\n * @param {Element|Node} node the node to be searched, if the node is text node we return the node.\n * @return {TextNode}\n */\nfunction firstTextNode(node) {\n if (node.nodeType == Node.TEXT_NODE) return node;\n var treeWalker = createTreeWalker(node, NodeFilter.SHOW_TEXT);\n return treeWalker.firstChild();\n}\n\n\n/**\n * Returns the last child text node of an element\n *\n * @param {Element|Node} node the node to be searched, if the node is text node we return the node.\n * @return {TextNode}\n */\nfunction lastTextNode(node) {\n if (node.nodeType == Node.TEXT_NODE) return node;\n var treeWalker = createTreeWalker(node, NodeFilter.SHOW_TEXT);\n return treeWalker.lastChild();\n}\n\n\n/**\n * Removes element from the document putting its children in its place\n *\n * @param {Element} el the element to be \"unwrapped\"\n */\nfunction unwrapElement(el) {\n var parent = el.parentNode;\n\n if (parent) {\n var frag = document.createDocumentFragment();\n // must be copied to avoid iterating a mutating list of childNodes\n var children = _.slice(el.childNodes);\n children.forEach(frag.appendChild, frag);\n parent.replaceChild(frag, el);\n parent.normalize();\n }\n}\n\n\n/**\n * Wraps an element in another element\n *\n * @param {Element} wrapIntoEl\n * @param {Element} el\n */\nfunction wrapInElement(wrapIntoEl, el) {\n var parent = el.parentNode;\n\n if (parent) {\n parent.insertBefore(wrapIntoEl, el);\n wrapIntoEl.appendChild(el);\n }\n}\n\n\n/**\n * Trims a text node of trailing spaces, and returns true if a trim was performed.\n *\n * @param {TextNode} node\n * @return {Boolean}\n */\nfunction trimNodeRight(node) {\n return _trimNode(node, 'trimRight');\n}\n\n\n/**\n * Trims a text node of leading spaces, and returns true if a trim was performed.\n *\n * @param {TextNode} node\n * @return {Boolean}\n */\nfunction trimNodeLeft(node) {\n return _trimNode(node, 'trimLeft');\n}\n\n\nfunction _trimNode(node, methodName) {\n var len = node.length;\n node.textContent = node.textContent[methodName]();\n return len !== node.length;\n}\n\n\n/**\n * Removes the reference to component from element\n *\n * @param {Element} el\n */\nfunction detachComponent(el) {\n delete el[config.componentRef];\n}\n\n\n/**\n * Retrieves the content of a html string\n * @param {String} str Any string\n * @return {String} returns the string cleaned of any html content.\n */\nfunction stripHtml(str) {\n var div = document.createElement('DIV');\n div.innerHTML = str;\n return div.textContent || '';\n}\n\n\n/**\n * Convenience wrapper for native TreeWalker that automatically walks the tree and calls an iterator function.\n * This will not iterate the root element.\n * @param {HTMLElement} root The containing root element to be walked. Will not be iterated.\n * @param {NodeFiler} filter A NodeFilter constant, see https://developer.mozilla.org/en/docs/Web/API/TreeWalker\n * @param {Function} iterator A function to be called on each node. Returning 'false' will break.\n * @param {Object} context An optional context to passed, defaults to root.\n */\nfunction walkTree(root, filter, iterator, context) {\n var tw = document.createTreeWalker(root, filter);\n while(tw.nextNode()) {\n var result = iterator.call(context || root, tw.currentNode);\n if (result === false) break;\n }\n}\n\n\n/**\n * Returns array of child indexes of element path inside root element in DOM tree using breadth first tree traversal.\n * Returns undefined if the element is not inside root element, 0 if the root element itself is passed.\n *\n * @param {Element} rootEl element to search\n * @param {Element} el element to find the index of\n * @return {Array[Number]}\n */\nfunction treePathOf(rootEl, el) {\n if (! (rootEl && rootEl.contains(el))) return;\n\n var treePath = []\n , node = rootEl;\n\n while (node != el) {\n var nodeIndex = _.findIndex(node.childNodes, containsEl);\n treePath.push(nodeIndex);\n node = node.childNodes[nodeIndex];\n }\n\n return treePath;\n\n function containsEl(child) {\n return child.contains(el);\n }\n}\n\n\n/**\n * Returns element at given tree path\n *\n * @param {Element} rootEl\n * @param {Array[Number]} treePath\n * @param {Boolean} nearest return nearest possible node if exact node does not exist\n * @return {Node}\n */\nfunction getNodeAtTreePath(rootEl, treePath, nearest) {\n if (!treePath) return;\n\n var len = treePath.length;\n if (len === 0) return rootEl;\n\n var node = rootEl;\n\n for (var i = 0; i < len; i++) {\n var children = node.childNodes;\n if (! children) {\n if (! nearest) node = undefined;\n break;\n }\n var childIndex = treePath[i]\n , child = children[childIndex];\n if (! child) {\n node = nearest\n ? children[children.length - 1]\n : undefined;\n break;\n }\n node = child;\n }\n\n return node;\n}\n\n\n/**\n * Inserts an element inside root at a given path in tree (that has the same meaning as the index returned by `treePathOf` function). If element is already in the root's tree, it will be removed first and then moved to the passed treeIndex\n * Insertion at index 0 is not possible and will return undefined as it would mean replacing the root element.\n *\n * @param {Element} rootEl element into which to insert\n * @param {Number} treeIndex index in DOM tree inside root element (see treePathOf)\n * @param {Element} el element to be inserted\n * @return {Boolean} true if was successfully inserted\n */\nfunction insertAtTreePath(rootEl, treePath, el, nearest) {\n var toNormalize = el.nodeType == Node.TEXT_NODE;\n if (rootEl.contains(el))\n removeElement(el); // can't use removeChild as rootEl here is not an immediate parent\n\n if (treePath.length == 0) return;\n\n var parent = getNodeAtTreePath(rootEl, treePath.slice(0, -1), nearest)\n , children = parent.childNodes;\n\n if (! children) {\n if (nearest) {\n parent = parent.parentNode;\n children = parent.childNodes;\n } else return;\n }\n\n var childIndex = treePath[treePath.length - 1]\n , child = children[childIndex];\n\n if (child) {\n parent.insertBefore(el, child);\n if (toNormalize) parent.normalize();\n return true;\n } else if (children.length === 0 && (childIndex === 0 || nearest)) {\n parent.appendChild(el);\n if (toNormalize) parent.normalize();\n return true;\n } else {\n child = children[childIndex - 1];\n if (child || nearest) {\n parent.appendChild(el);\n if (toNormalize) parent.normalize();\n return true;\n }\n }\n}\n\n\n/**\n * Returns `true` if the first tree path points to a node which is before the other in the document order.\n * @param {Array} path1 A treepath array\n * @param {Array} path2 A treepath array\n * @return {Boolean}\n */\nfunction isTreePathBefore(path1, path2) {\n var i = 0\n , isBefore;\n if (!Array.isArray(path1) && Array.isArray(path2))\n return logger.error('isTreePathBefore: One or both paths are not valid treepath arrays.');\n\n for (i; i < path1.length; i++) {\n if (path1[i] < path2[i]) {\n isBefore = true;\n break;\n } else if (path1[i] > path2[i]) {\n isBefore = false;\n break;\n }\n }\n\n if (typeof isBefore == 'undefined')\n if (path1.length < path2.length)\n logger.warn('isTreePathBefore: One node is inside another');\n\n return isBefore || false;\n}\n\n\n/**\n * Converts non latin characters to HTML entity codes.\n * @param {String} str the string to convert\n * @return {String} the string with html entities\n */\nfunction htmlEntities(str) {\n return str.replace(/[\\u00A0-\\u99999<>\\&]/gim, function(i) {\n return ''+i.charCodeAt(0)+';';\n });\n}\n\n\nfunction createTreeWalker(el, whatToShow) {\n whatToShow = whatToShow || (NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT);\n return document.createTreeWalker(el, whatToShow);\n}\n\n\n/**\n * Returns the reference to the window the node is in\n *\n * @param {Node} node\n * @return {Window}\n */\nfunction getNodeWindow(node) {\n var doc = node.ownerDocument;\n return doc && (doc.defaultView || doc.parentWindow);\n}\n\n\n\n/**\n * do something for each nodes contained in a range\n *\n * @param {range} a range\n * @param {cb} a function taking a node as argument\n\n */\nfunction forEachNodesInRange(range, cb){\n var rangeContainer = range.commonAncestorContainer\n , doc = rangeContainer.ownerDocument;\n\n function isNodeInsideRange(node){\n var nodeRange = document.createRange();\n var isInside = false;\n nodeRange.selectNode(node);\n\n if (nodeRange.compareBoundaryPoints(window.Range.START_TO_START, range) != -1\n && nodeRange.compareBoundaryPoints(window.Range.END_TO_END, range) != 1){\n isInside = true;\n }\n nodeRange.detach();\n return isInside;\n }\n\n var treeWalker = doc.createTreeWalker(rangeContainer,\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);\n\n var currentNode;\n while (currentNode = treeWalker.nextNode()){ // should be assignment\n if (isNodeInsideRange(currentNode)){\n cb(currentNode);\n }\n }\n}\n\n/**\n * get all components contained in a range\n *\n * @param {range} a DOM range.\n */\nfunction getComponentsFromRange(range) {\n var win = getNodeWindow(range.startContainer)\n , Component = win.milo.Component;\n\n var components = [];\n forEachNodesInRange(range, function (node){\n if (node.nodeType != Node.TEXT_NODE) {\n var comp = Component.getComponent(node);\n if (comp)\n components.push(comp);\n }\n });\n\n return components;\n}\n\n/**\n * delete a range\n *\n * @param {range} delete a DOM range and all the components inside\n */\nfunction deleteRangeWithComponents(range) {\n var components = getComponentsFromRange(range);\n\n components.forEach(function(comp) {\n comp.destroy(true);\n });\n\n range.deleteContents();\n}\n\n/**\n * check if two ranges are equivalent\n *\n * @param {range} range1\n * @param {range} range2\n * @return {Boolean} are the two ranges equivalent\n */\nfunction areRangesEqual(range1, range2){\n return range1.compareBoundaryPoints(window.Range.START_TO_START, range2) == 0 && range1.compareBoundaryPoints(window.Range.END_TO_END, range2) == 0;\n}\n\n\n/**\n * Adds a single pixel div to the body at a given x and y position. Useful for debugging position specific code.\n * @param {Number} x\n * @param {Number} y\n */\nfunction addDebugPoint(x, y) {\n var dbEl = document.createElement('div');\n dbEl.setAttribute('style', 'width: 1px; height: 1px; position:fixed; left:'+x+'px; top:'+y+'px; background-color:red; z-index: 100');\n setTimeout(function() {document.body.appendChild(dbEl);}, 200);\n}\n",
+ "'use strict';\n\n\nvar _ = require('milo-core').proto;\n\n\nmodule.exports = DOMListeners;\n\n\nfunction DOMListeners() {\n this.listeners = [];\n}\n\n\n_.extendProto(DOMListeners, {\n add: DOMListeners$add,\n remove: DOMListeners$remove,\n removeAll: DOMListeners$removeAll\n});\n\n\nfunction DOMListeners$add(target, eventType, handler) {\n this.listeners.push({\n target: target,\n eventType: eventType,\n handler: handler\n });\n target.addEventListener(eventType, handler);\n}\n\n\nfunction DOMListeners$remove(target, eventType, handler) {\n var listener = {\n target: target,\n eventType: eventType,\n handler: handler\n };\n var idx = _.findIndex(this.listeners, _.partial(_.isEqual, listener));\n\n if (idx > -1) {\n this.listeners.splice(idx, 1);\n _removeListener(listener);\n }\n}\n\n\nfunction DOMListeners$removeAll() {\n this.listeners.forEach(_removeListener);\n this.listeners = [];\n}\n\n\nfunction _removeListener(l) {\n l.target.removeEventListener(l.eventType, l.handler);\n}\n",
+ "'use strict';\n\n\nvar _ = require('milo-core').proto;\n\n\nmodule.exports = domReady;\n\n\nvar domReadyFuncs = []\n , domReadySubscribed = false;\n\n\nfunction domReady(func) { // , arguments\n var self = this\n , args = _.slice(arguments, 1);\n if (isReady.call(this))\n callFunc();\n else {\n if (!domReadySubscribed) {\n document.addEventListener('readystatechange', onDomReady);\n domReadySubscribed = true;\n }\n domReadyFuncs.push(callFunc); // closure is added, so every time different function will be called\n }\n\n function callFunc() {\n func.apply(self, args);\n }\n}\n\n\nfunction onDomReady() {\n document.removeEventListener('readystatechange', onDomReady);\n domReadyFuncs.forEach(function(func) { func(); });\n}\n\n\n_.extend(domReady, {\n isReady: isReady\n});\n\n\nfunction isReady() {\n var readyState = document.readyState;\n return readyState == 'loading' ? false : readyState;\n}\n",
+ "'use strict';\n\nvar Component = require('../components/c_class')\n , miloCore = require('milo-core')\n , Messenger = miloCore.Messenger\n , dragDropConfig = require('../config').dragDrop\n , componentMetaRegex = dragDropConfig.dataTypes.componentMetaRegex\n , _ = miloCore.proto\n , base32 = require('base32');\n\n\nmodule.exports = DragDrop;\n\n\n/**\n * Wrapper for event.dataTransfer of drag-drop HTML API\n *\n * @constructor\n * @param {event} DOM event\n * @return {DragDrop}\n */\nfunction DragDrop(event) {\n this.event = event;\n this.dataTransfer = event.dataTransfer;\n this.types = event.dataTransfer.types;\n}\n\n/**\n * Usage:\n * var testDT = new DragDrop(event);\n * testDT.setComponentMeta(newComponent, {test: 'test', test2: 'test2'});\n * testDT.getComponentMeta();\n */\n\n_.extend(DragDrop, {\n componentDataType: DragDrop$$componentDataType\n});\n\n_.extendProto(DragDrop, {\n isComponent: DragDrop$isComponent,\n getComponentState: DragDrop$getComponentState,\n setComponentState: DragDrop$setComponentState,\n getComponentMeta: DragDrop$getComponentMeta,\n setComponentMeta: DragDrop$setComponentMeta,\n getAllowedEffects: DragDrop$getAllowedEffects,\n setAllowedEffects: DragDrop$setAllowedEffects,\n getDropEffect: DragDrop$getDropEffect,\n setDropEffect: DragDrop$setDropEffect,\n isEffectAllowed: DragDrop$isEffectAllowed,\n getData: DragDrop$getData,\n setData: DragDrop$setData,\n clearData: DragDrop$clearData\n});\n\n\nfunction DragDrop$$componentDataType() {\n return dragDropConfig.dataTypes.component;\n}\n\n\nfunction DragDrop$isComponent() {\n return _.indexOf(this.types, DragDrop.componentDataType()) >= 0;\n}\n\n\nfunction DragDrop$getComponentState() {\n var dataType = DragDrop.componentDataType()\n , stateStr = this.dataTransfer.getData(dataType)\n , state = _.jsonParse(stateStr);\n\n return state;\n}\n\n\nfunction DragDrop$setComponentState(component, stateStr){\n if (! stateStr) {\n var state = component.getTransferState({ requestedBy: 'drag' });\n stateStr = JSON.stringify(state);\n }\n var dataType = DragDrop.componentDataType();\n\n stateStr && this.dataTransfer.setData(dataType, stateStr);\n this.dataTransfer.setData('text/html', component.el.outerHTML);\n return stateStr;\n}\n\n\nfunction DragDrop$setComponentMeta(component, params, data) {\n var meta = _componentMeta(component);\n\n var paramsStr = _.toQueryString(params);\n var dataType = dragDropConfig.dataTypes.componentMetaTemplate\n .replace('%class', _encode(meta.compClass || ''))\n .replace('%name', _encode(meta.compName || ''))\n .replace('%params', _encode(paramsStr || ''));\n\n if (data && typeof data == 'object') data = JSON.stringify(data);\n\n this.dataTransfer.setData(dataType, data || '');\n\n return dataType;\n}\n\n\nfunction _encode(str) {\n return base32.encode(str).toLowerCase();\n}\n\n\nfunction _componentMeta(component) {\n return component.transfer\n ? component.transfer.getComponentMeta()\n : { \n compClass: component.constructor.name,\n compName: component.name\n };\n}\n\n\nfunction DragDrop$getComponentMeta() {\n var match;\n var metaDataType = _.find(this.types, function (dType) {\n match = dType.match(componentMetaRegex);\n return !!match;\n });\n if (!metaDataType) return;\n\n for (var i=1; i<4; i++)\n match[i] = base32.decode(match[i]);\n\n return {\n compClass: match[1],\n compName: match[2],\n params: _.fromQueryString(match[3]),\n metaDataType: metaDataType,\n metaData: _.jsonParse(this.dataTransfer.getData(metaDataType)) \n ? _.jsonParse(this.dataTransfer.getData(metaDataType)) \n : this.dataTransfer.getData(metaDataType)\n };\n}\n\n\n// as defined here: https://developer.mozilla.org/en-US/docs/DragDrop/Drag_Operations#dragstart\nfunction DragDrop$getAllowedEffects() {\n return this.dataTransfer.effectAllowed;\n}\n\n\nfunction DragDrop$setAllowedEffects(effects) {\n this.dataTransfer.effectAllowed = effects;\n}\n\n\nfunction DragDrop$getDropEffect() {\n return this.dataTransfer.dropEffect;\n}\n\n\nfunction DragDrop$setDropEffect(effect) {\n this.dataTransfer.dropEffect = effect;\n}\n\n\nfunction DragDrop$isEffectAllowed(effect) {\n var allowedEffects = this.getAllowedEffects()\n , isCopy = effect == 'copy'\n , isMove = effect == 'move'\n , isLink = effect == 'link'\n , isAllowed = isCopy || isLink || isMove;\n\n switch (allowedEffects) {\n case 'copy':\n case 'move':\n case 'link':\n return allowedEffects == effect;\n case 'copyLink':\n return isCopy || isLink;\n case 'copyMove':\n return isCopy || isMove;\n case 'linkMove':\n return isLink || isMove;\n case 'all':\n case 'uninitialized':\n return isAllowed;\n case 'none':\n return false;\n }\n}\n\n\nfunction DragDrop$getData(dataType) {\n return this.dataTransfer.getData(dataType);\n}\n\n\nfunction DragDrop$setData(dataType, dataStr) {\n this.dataTransfer.setData(dataType, dataStr);\n}\n\n\nfunction DragDrop$clearData(dataType) {\n this.dataTransfer.clearData(dataType);\n}\n\n\n/**\n * Drag drop service compensating for the lack of communication from drop target to drag source in DOM API\n */\nvar dragDropService = new Messenger;\n\nvar _currentDragDrop, _currentDragFacet;\n\n_.extend(DragDrop, {\n service: dragDropService,\n destroy: DragDrop_destroy\n});\n\n\ndragDropService.onMessages({\n // data is DragDropDataTransfer instance\n // fired by Drag facet on \"dragstart\" event\n 'dragdropstarted': onDragDropStarted, \n // data is object with at least dropEffect property\n // fired by Drop facet on \"drop\" event\n 'dragdropcompleted': onDragDropCompleted, \n // fired by Drag facet on \"dragend\" event to complete drag\n // if drop happended in another window or if it was cancelled\n 'completedragdrop': onCompleteDragDrop\n});\n\n\n_.extend(dragDropService, {\n getCurrentDragDrop: getCurrentDragDrop\n});\n\n\nfunction onDragDropStarted(msg, data) {\n _currentDragDrop = data.dragDrop;\n _currentDragFacet = data.dragFacet;\n}\n\n\nfunction onDragDropCompleted(msg, data) {\n _currentDragFacet && _currentDragFacet.postMessageSync('dragdropcompleted', data);\n _currentDragDrop = undefined;\n _currentDragFacet = undefined;\n}\n\n\nfunction onCompleteDragDrop(msg, data) {\n if (_currentDragDrop)\n dragDropService.postMessageSync('dragdropcompleted', data);\n}\n\n\nfunction getCurrentDragDrop() {\n return _currentDragDrop;\n}\n\n\nfunction DragDrop_destroy() {\n dragDropService.offAll();\n}\n",
+ "// \n// milo.utils.error\n// -----------\n\n'use strict';\n\nvar _ = require('milo-core').proto;\n\n\n// module exports error classes for all names defined in this array\nvar errorClassNames = ['AbstractClass', 'Mixin', 'Messenger', 'Component',\n 'Attribute', 'Binder', 'Loader', 'MailMessageSource', 'Facet',\n 'Scope', 'Model', 'DomFacet', 'EditableFacet',\n 'List', 'Connector', 'Registry', 'FrameMessageSource',\n 'Drop', 'Angular', 'StorageMessageSource'];\n\nvar error = {\n toBeImplemented: error$toBeImplemented,\n createClass: error$createClass\n};\n\nerrorClassNames.forEach(function(name) {\n error[name] = error$createClass(name + 'Error');\n});\n\nmodule.exports = error;\n\n\nfunction error$createClass(errorClassName) {\n var ErrorClass = _.makeFunction(errorClassName, 'message',\n 'this.name = \"' + errorClassName + '\"; \\\n this.message = message || \"There was an error\";');\n _.makeSubclass(ErrorClass, Error);\n\n return ErrorClass;\n}\n\n\nfunction error$toBeImplemented() {\n throw new error.AbstractClass('calling the method of an absctract class');\n}\n",
+ "'use strict';\n\n\nvar Component = require('../components/c_class')\n , BindAttribute = require('../attributes/a_bind')\n , binder = require('../binder')\n , domUtils = require('./dom')\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , check = miloCore.util.check\n , _ = miloCore.proto;\n\n\nvar createRangePaths = _createNodesAndPathsFunc(domUtils.treePathOf);\nvar createRangeNodes = _createNodesAndPathsFunc(domUtils.getNodeAtTreePath);\n\n\nvar fragmentUtils = module.exports = {\n getState: fragment_getState,\n getStateAsync: fragment_getStateAsync,\n\n expandRangeToSiblings: expandRangeToSiblings,\n getRangeSiblings: getRangeSiblings,\n createRangeFromSiblings: createRangeFromSiblings,\n createRangeFromNodes: createRangeFromSiblings, // alias\n createRangePaths: createRangePaths,\n createRangeNodes: createRangeNodes\n};\n\n\n/**\n * Creates an object with the state of wrapped range with components, including partially selected. The range will be cloned and wrapped in component with container facet before getting its state.\n * This function will log error and return undefined if range has no common ancestor that has component with container facet\n * \n * @param {Range} range DOM Range instance\n * @param {Boolean} renameChildren optional parameter, `true` to rename fragment child components\n * @param {String} wrapperClassName optional parameter to wrap in a custom component class\n * @return {Object}\n */\nfunction fragment_getState(range, renameChildren, wrapperClassName) {\n var rangeContainer = _getRangeContainer(range);\n if (! rangeContainer) {\n logger.error('fragment.getState: range has no common container');\n return;\n }\n\n var frag = range.cloneContents()\n , wrapper = _wrapFragmentInContainer(frag, wrapperClassName);\n\n _transferStates(rangeContainer, wrapper);\n if (renameChildren) _renameChildren(wrapper);\n var wrapperState = wrapper.getState();\n _.deferMethod(wrapper, 'destroy');\n return wrapperState;\n}\n\n\n/**\n * Creates an object with the state of wrapped range with components, including partially selected. The range will be cloned and wrapped in component with container facet before getting its state.\n * This function will return result and any error via callback.\n * \n * @param {Range} range DOM Range instance\n * @param {Boolean} renameChildren optional parameter, `true` to rename fragment child components\n * @param {Function} callback always the last parameter, optional parameters can be dropped; result is passed via callback with any error as first parameter\n */\nfunction fragment_getStateAsync(range, renameChildren, callback) {\n try {\n var rangeContainer = _getRangeContainer(range);\n if (! rangeContainer) {\n callback(new Error('fragment.getState: range has no common container'));\n return; // do NOT connect return to previous callback, getState should return undefined\n }\n\n if (typeof renameChildren == 'function') {\n callback = renameChildren;\n renameChildren = false;\n }\n\n var frag = range.cloneContents()\n , wrapper = _wrapFragmentInContainer(frag);\n\n _transferStates(rangeContainer, wrapper);\n _.defer(function() {\n wrapper.broadcast('stateready');\n _.defer(function() {\n if (renameChildren) _renameChildren(wrapper);\n var wrapperState = wrapper.getState();\n wrapper.destroy();\n callback(null, wrapperState);\n });\n });\n } catch (err) {\n callback(err);\n }\n}\n\n\nfunction _wrapFragmentInContainer(frag, wrapperClassName) {\n var wrapEl = document.createElement('div')\n , attr = new BindAttribute(wrapEl);\n\n _.extend(attr, {\n compClass: wrapperClassName || 'Component',\n compFacets: wrapperClassName ? [] : ['container'],\n compName: 'wrapper'\n });\n\n attr.decorate();\n\n wrapEl.appendChild(frag);\n var scope = binder(wrapEl);\n return scope.wrapper;\n}\n\n\nfunction _getRangeContainer(range) {\n var el = domUtils.containingElement(range.commonAncestorContainer);\n return Component.getContainingComponent(el, true, 'container');\n}\n\n\nfunction _transferStates(fromComp, toComp) {\n var fromScope = fromComp.container.scope;\n toComp.container.scope._each(function(toChildComp, name) {\n var fromChildComp = fromScope[name];\n if (! fromChildComp) return logger.error('fragment.getState: conponent', name, 'not found in range');\n var state = fromChildComp._getState(true);\n toChildComp.setState(state);\n });\n}\n\n\nfunction _renameChildren(comp) {\n comp.container.scope._each(function(child) {\n child.rename();\n });\n}\n\n\nfunction expandRangeToSiblings(range) {\n var siblings = getRangeSiblings(range);\n range = createRangeFromSiblings(siblings);\n return range;\n}\n\n\nfunction createRangeFromSiblings(nodes) {\n var range = document.createRange();\n if (nodes.siblings) {\n range.setStartBefore(nodes.start);\n range.setEndAfter(nodes.end);\n } else\n range.selectNode(nodes.start);\n return range;\n}\n\n\nfunction getRangeSiblings(range) {\n var containerNode = range.commonAncestorContainer\n , startNode = range.startContainer\n , endNode = range.endContainer;\n\n if (startNode == endNode) {\n if (startNode != containerNode) logger.error('deleteSelectionCommand logical error: start==end, but container is different');\n return { siblings: false, start: startNode };\n }\n\n if (startNode == containerNode || endNode == containerNode)\n return { siblings: false, start: containerNode };\n\n var startSibling = _findContainingChild(containerNode, startNode);\n var endSibling = _findContainingChild(containerNode, endNode);\n\n if (startSibling && endSibling) {\n if (startSibling == endSibling) {\n logger.error('deleteSelectionCommand logical error: same siblings');\n return { siblings: false, start: startSibling };\n } else\n return { siblings: true, start: startSibling, end: endSibling };\n }\n}\n\n\nfunction _findContainingChild(containerNode, selNode) {\n return _.find(containerNode.childNodes, function(node) {\n return node.contains(selNode);\n });\n}\n\n\nfunction _createNodesAndPathsFunc(func) {\n return function(rootEl, fromObj) {\n var toObj = {\n siblings: fromObj.siblings,\n start: func(rootEl, fromObj.start)\n };\n if (toObj.siblings)\n toObj.end = func(rootEl, fromObj.end);\n return toObj;\n };\n}\n\n\n",
+ "'use strict';\n\nvar miloCore = require('milo-core');\n\n/**\n * `milo.util`\n */\nvar util = {\n logger: miloCore.util.logger,\n request: require('./request'),\n websocket: require('./websocket'),\n check: miloCore.util.check,\n error: require('./error'), // deprecated\n count: require('./count'), // deprecated\n uniqueId: require('./count'),\n componentName: require('./component_name'),\n dom: require('./dom'),\n domListeners: require('./dom_listeners'),\n selection: require('./selection'),\n fragment: require('./fragment'),\n jsonParse: require('./json_parse'), // deprecated\n storage: require('./storage'),\n domReady: require('./domready'),\n dragDrop: require('./dragdrop'),\n dialog: require('../components/ui/bootstrap/Dialog'), // deprecated - should be used from registry\n alert: require('../components/ui/bootstrap/Alert'), // deprecated - should be used from registry\n doT: miloCore.util.doT,\n destroy: util_destroy\n};\n\nmodule.exports = util;\n\n\nfunction util_destroy() {\n util.request.destroy();\n util.dragDrop.destroy();\n}\n",
"'use strict';\n\n\nmodule.exports = jsonParse;\n\n\n/**\n * `milo.util.jsonParse`\n * Safe JSON.parse, returns undefined if JSON.parse throws an exception\n *\n * @param {String} str - JSON string representation of object\n * @return {Object|undefined}\n */\nfunction jsonParse(str) {\n try {\n return JSON.parse(str);\n } catch (e) {}\n}\n",
- "'use strict';\n\n// \n// milo.utils.logger\n// -----------\n\n// Application logger that has error, warn, info and debug\n// methods, that can be suppressed by setting log level.\n\n// Properties:\n\n// - level\n\n// - 0 - error\n// - 1 - warn\n// - 2 - info\n// - 3 - debug (default)\n\n// - enabled\n\n// true by default. Set to false to disable all logging in browser console.\n\n\nvar Logger = require('./logger_class');\n\nvar logger = new Logger({ level: 3 });\n\nmodule.exports = logger;\n",
- "'use strict';\n\n// ### Logger Class\n\n// Properties:\n\n// - level\n\n// - 0 - error\n// - 1 - warn\n// - 2 - info\n// - 3 - debug (default)\n\n// - enabled\n\n// true by default. Set to false to disable all logging in browser console.\n\n\nvar _ = require('mol-proto');\n\n\n/**\n * Log levels.\n */\n\nvar levels = [\n 'error',\n 'warn',\n 'info',\n 'debug'\n];\n\nvar maxLevelLength = Math.max.apply(Math, levels.map(function(level) { return level.length; }));\n\n/**\n * Colors for log levels.\n */\n\nvar colors = [\n 31,\n 33,\n 36,\n 90\n];\n\n/**\n * Pads the nice output to the longest log level.\n */\nfunction pad(str) {\n if (str.length < maxLevelLength)\n return str + new Array(maxLevelLength - str.length + 1).join(' ');\n\n return str;\n};\n\n\nfunction colored(str, color) {\n return '\\x1B[' + color + 'm' + str + ' -\\x1B[39m';\n}\n\n\nvar DEFAULT_OPTIONS = {\n level: 3,\n throwLevel: -1, // never throw\n enabled: true,\n logPrefix: ''\n}\n\n\n/**\n * Logger (console).\n *\n * @api public\n */\nvar Logger = function (opts) {\n _.extend(this, DEFAULT_OPTIONS);\n _.extend(this, opts || {});\n};\n\n\n/**\n * Log method.\n *\n * @api public\n */\n\nLogger.prototype.log = function (type) {\n var index = levels.indexOf(type);\n\n if (! this.enabled || index > this.level)\n return this;\n\n var args = _.slice(arguments, 1);\n\n if (index <= this.throwLevel)\n throw new Error([this.logPrefix, type + ':'].concat(args).join(' '));\n\n console.log.apply(\n console\n , [ this.logPrefixColor\n ? ' ' + colored(this.logPrefix, this.logPrefixColor)\n : this.logPrefix,\n (this.colors\n ? ' ' + colored(pad(type), colors[index])\n : type) + ':'\n ].concat(args)\n );\n\n return this;\n};\n\n/**\n * Generate methods.\n */\n\nlevels.forEach(function (name) {\n Logger.prototype[name] = function () {\n this.log.apply(this, [name].concat(_.toArray(arguments)));\n };\n});\n\n\nmodule.exports = Logger;\n",
- "'use strict';\n\n// milo.utils.request\n// -----------\n\n// Convenience functions wrapping XMLHTTPRequest functionality.\n\n// ```\n// var request = milo.utils.request\n// , opts: { method: 'GET' };\n\n// request(url, opts, function(err, data) {\n// logger.debug(data);\n// });\n\n// request.get(url, function(err, data) {\n// logger.debug(data);\n// });\n// ```\n\n// Only generic request and get, json, post convenience methods are currently implemented.\n\n\nvar _ = require('mol-proto')\n , count = require('./count')\n , config = require('../config')\n , logger = require('./logger')\n , Messenger = require('../messenger');\n\nmodule.exports = request;\n\n\nvar _pendingRequests = [];\n\nvar promiseThen = createPromiseOverride('then');\nvar promiseCatch = createPromiseOverride('catch');\n\n/**\n * Creates a function which is used to override standard promise behaviour and allow promise instances \n * created to maintain a reference to the request object no matter if .then() or .catch() is called.\n */\nfunction createPromiseOverride(functionName) {\n return function() {\n var promise = Promise.prototype[functionName].apply(this, arguments);\n keepRequestObject(promise, this._request);\n return promise;\n }\n}\n\n\nfunction request(url, opts, callback) {\n opts.url = url;\n opts.contentType = opts.contentType || 'application/json;charset=UTF-8';\n if (_messenger) request.postMessageSync('request', { options: opts });\n\n var req = new XMLHttpRequest();\n req.open(opts.method, opts.url, true);\n req.setRequestHeader('Content-Type', opts.contentType);\n setRequestHeaders(req, opts.headers);\n\n req.timeout = opts.timeout || config.request.defaults.timeout;\n req.onreadystatechange = req.ontimeout = req.onabort = onReady;\n\n var xPromise = _createXPromise(req);\n\n req.send(JSON.stringify(opts.data));\n req[config.request.optionsKey] = opts;\n\n _pendingRequests.push(req);\n\n return xPromise.promise;\n\n function onReady(e) {\n _onReady(req, callback, xPromise, e.type);\n }\n}\n\n\nfunction _createXPromise(request) {\n var resolvePromise, rejectPromise;\n var promise = new Promise(function(resolve, reject) {\n resolvePromise = resolve;\n rejectPromise = reject;\n });\n\n keepRequestObject(promise, request);\n promise.catch(_.noop); // Sometimes errors are handled within callbacks, so uncaught promise error message should be suppressed.\n\n return {\n promise: promise,\n resolve: resolvePromise,\n reject: rejectPromise\n }\n}\n\n// Ensures that the promise (and any promises created when calling .then/.catch) has a reference to the original request object\nfunction keepRequestObject(promise, request) {\n promise._request = request;\n promise.then = promiseThen;\n promise.catch = promiseCatch;\n\n return promise;\n}\n\n\nfunction setRequestHeaders(req, headers) {\n if (headers)\n _.eachKey(headers, function(value, key) {\n req.setRequestHeader(key, value);\n });\n}\n\nfunction _onReady(req, callback, xPromise, eventType) {\n if (req.readyState != 4) return;\n if (!req.status && eventType == 'readystatechange') return;\n\n _.spliceItem(_pendingRequests, req);\n\n var error;\n try {\n if ( req.status >= 200 && req.status < 400 ) {\n try {\n postMessage('success');\n callback && callback(null, req.responseText, req);\n } catch(e) { error = e; }\n xPromise.resolve(req.responseText);\n }\n else {\n var errorReason = req.status || eventType;\n try {\n postMessage('error');\n postMessage('error' + errorReason);\n callback && callback(errorReason, req.responseText, req);\n } catch(e) { error = e; }\n xPromise.reject({ reason: errorReason, response: req.responseText });\n }\n } catch(e) {\n error = error || e;\n }\n\n // not removing subscription creates memory leak, deleting property would not remove subscription\n req.onreadystatechange = req.ontimeout = req.onabort = undefined;\n\n if (!_pendingRequests.length)\n postMessage('requestscompleted');\n\n if (error) throw new Error('Exception: ' + error);\n\n function postMessage(msg) {\n if (_messenger) request.postMessage(msg,\n { status: status, response: req.responseText });\n }\n}\n\n\n_.extend(request, {\n get: request$get,\n post: request$post,\n json: request$json,\n jsonp: request$jsonp,\n file: request$file,\n useMessenger: request$useMessenger,\n destroy: request$destroy,\n whenRequestsCompleted: whenRequestsCompleted\n});\n\n\nvar _messenger;\n\n\nfunction request$useMessenger() {\n _messenger = new Messenger(request, ['on', 'once', 'onSync', 'off', 'onMessages', 'offMessages', 'postMessage', 'postMessageSync']);\n}\n\n\nfunction request$get(url, callback) {\n return request(url, { method: 'GET' }, callback);\n}\n\n\nfunction request$post(url, data, callback) {\n return request(url, { method: 'POST', data: data }, callback);\n}\n\n\nfunction request$json(url, callback) {\n var promise = request(url, { method: 'GET' });\n\n var jsonPromise = promise.then(JSON.parse);\n\n if (callback)\n jsonPromise\n .then(function(data) { callback(null, data); })\n .catch(function(errData) { callback(errData.reason, errData.response); });\n\n return jsonPromise;\n}\n\n\nvar jsonpOptions = { method: 'GET', jsonp: true };\nfunction request$jsonp(url, callback) {\n var script = document.createElement('script'),\n xPromise = _createXPromise(script),\n head = window.document.head,\n uniqueCallback = config.request.jsonpCallbackPrefix + count();\n\n var opts = _.extend({ url: url }, jsonpOptions);\n if (_messenger) request.postMessageSync('request', { options: opts });\n\n if (! _.isEqual(_.omitKeys(opts, 'url'), jsonpOptions))\n logger.warn('Ignored not allowed request options change in JSONP request - only URL can be changed');\n\n var timeout = setTimeout(function() {\n var err = new Error('No JSONP response or no callback in response');\n _onResult(err);\n }, config.request.jsonpTimeout);\n\n window[uniqueCallback] = _.partial(_onResult, null);\n\n _pendingRequests.push(window[uniqueCallback]);\n\n script.type = 'text/javascript';\n script.src = opts.url + (opts.url.indexOf('?') == -1 ? '?' : '&') + 'callback=' + uniqueCallback;\n\n head.appendChild(script);\n\n return xPromise.promise;\n\n\n function _onResult(err, result) {\n _.spliceItem(_pendingRequests, window[uniqueCallback]);\n try {\n postMessage(err ? 'error' : 'success', err, result);\n if (err) {\n logger.error('No JSONP response or timeout');\n postMessage('errorjsonptimeout', err);\n }\n callback && callback(err, result);\n }\n catch(e) { var error = e; }\n if (err) xPromise.reject(err);\n else xPromise.resolve(result);\n\n cleanUp();\n if (!_pendingRequests.length)\n postMessage('requestscompleted');\n\n if (error) throw error;\n }\n\n\n function cleanUp() {\n clearTimeout(timeout);\n head.removeChild(script);\n delete window[uniqueCallback];\n }\n\n\n function postMessage(msg, status, result) {\n if (_messenger) request.postMessage(msg,\n { status: status, response: result });\n }\n}\n\n\nfunction request$file(opts, fileData, callback, progress) {\n if (typeof opts == 'string')\n opts = { method: 'POST', url: opts };\n\n opts.method = opts.method || 'POST';\n opts.file = true;\n\n if (_messenger) request.postMessageSync('request', { options: opts });\n\n var req = new XMLHttpRequest();\n if (progress) req.upload.onprogress = progress;\n\n req.open(opts.method, opts.url, true);\n setRequestHeaders(req, opts.headers);\n\n req.timeout = opts.timeout || config.request.defaults.timeout;\n req.onreadystatechange = req.ontimeout = req.onabort = onReady;\n\n var xPromise = _createXPromise(req);\n\n if (opts.binary)\n req.send(fileData);\n else {\n var formData = new FormData();\n formData.append('file', fileData);\n req.send(formData);\n }\n\n _pendingRequests.push(req);\n\n return xPromise.promise;\n\n function onReady(e) {\n if (progress) req.upload.onprogress = undefined;\n _onReady(req, callback, xPromise, e.type);\n }\n}\n\n\nfunction request$destroy() {\n if (_messenger) _messenger.destroy();\n request._destroyed = true;\n}\n\n\nfunction whenRequestsCompleted(callback, timeout) {\n callback = _.once(callback);\n if (timeout)\n _.delay(callback, timeout, 'timeout');\n\n if (_pendingRequests.length)\n _messenger.once('requestscompleted', callback);\n else\n _.defer(callback);\n}\n",
- "'use strict';\n\n\nvar domUtils = require('../dom')\n , containingElement = domUtils.containingElement\n , setCaretPosition = domUtils.setCaretPosition\n , getComponentsFromRange = domUtils.getComponentsFromRange\n , deleteRangeWithComponents = domUtils.deleteRangeWithComponents\n , logger = require('../logger')\n , Component = require('../../components/c_class')\n , _ = require('mol-proto');\n\nmodule.exports = TextSelection;\n\n\n/**\n * Text selection class.\n * Serves as a helper to manage current selection\n * The object cannot be reused, if the selection changes some of its properties may contain information related to previous selection\n *\n * @param {Window} win window in which text selection is processed\n */\nfunction TextSelection(win) {\n if (! this instanceof TextSelection)\n return new TextSelection(win);\n this.window = win || window;\n this.init();\n}\n\n\n/**\n * TextSelection instance method\n * Returns selection start element\n *\n * @return {Element|null}\n */\nvar TextSelection$startElement = \n _.partial(_getElement, '_startElement', 'startContainer');\n\n\n/**\n * TextSelection instance method\n * Returns selection end element\n *\n * @return {Element|null}\n */\nvar TextSelection$endElement = \n _.partial(_getElement, '_endElement', 'endContainer');\n\n\n/**\n * TextSelection instance method\n * Returns selection end element\n *\n * @return {Element|null}\n */\nvar TextSelection$containingElement = \n _.partial(_getElement, '_containingElement', 'commonAncestorContainer');\n\n\n/**\n * TextSelection instance method\n * Returns selection start Component\n *\n * @return {Component}\n */\nvar TextSelection$startComponent = \n _.partial(_getComponent, '_startComponent', 'startElement');\n\n\n/**\n * TextSelection instance method\n * Returns selection end Component\n *\n * @return {Component}\n */\nvar TextSelection$endComponent = \n _.partial(_getComponent, '_endComponent', 'endElement');\n\n\n/**\n * TextSelection instance method\n * Returns selection end Component\n *\n * @return {Component}\n */\nvar TextSelection$containingComponent = \n _.partial(_getComponent, '_containingComponent', 'containingElement');\n\n\n_.extendProto(TextSelection, {\n init: TextSelection$init,\n text: TextSelection$text,\n textNodes: TextSelection$textNodes,\n clear: TextSelection$clear,\n\n startElement: TextSelection$startElement,\n endElement: TextSelection$endElement,\n containingElement: TextSelection$containingElement,\n\n startComponent: TextSelection$startComponent,\n endComponent: TextSelection$endComponent,\n containingComponent: TextSelection$containingComponent,\n\n containedComponents: TextSelection$containedComponents,\n eachContainedComponent: TextSelection$eachContainedComponent,\n del: TextSelection$del,\n _getPostDeleteSelectionPoint: _getPostDeleteSelectionPoint,\n _selectAfterDelete: _selectAfterDelete,\n\n getRange: TextSelection$getRange,\n getState: TextSelection$getState,\n getNormalizedRange: TextSelection$$getNormalizedRange,\n getDirection: TextSelection$$getDirection\n});\n\n\n_.extend(TextSelection, {\n createFromRange: TextSelection$$createFromRange,\n createFromState: TextSelection$$createFromState,\n createStateObject: TextSelection$$createStateObject\n});\n\n\n/**\n * TextSelection instance method\n * Initializes TextSelection from the current selection\n */\nfunction TextSelection$init() {\n this.selection = this.window.getSelection();\n if (this.selection.rangeCount)\n this.range = this.selection.getRangeAt(0);\n this.isCollapsed = this.selection.isCollapsed;\n}\n\n\n/**\n * TextSelection instance method\n * Retrieves and returns selection text\n *\n * @return {String}\n */\nfunction TextSelection$text() {\n if (! this.range) return undefined;\n\n if (! this._text)\n this._text = this.range.toString();\n\n return this._text;\n}\n\n\n/**\n * TextSelection instance method\n * Retrieves and returns selection text nodes\n *\n * @return {Array[Node]}\n */\nfunction TextSelection$textNodes() {\n if (! this.range) return undefined;\n\n if (! this._textNodes)\n this._textNodes = _getTextNodes.call(this);\n return this._textNodes;\n}\n\n\nfunction TextSelection$clear() {\n this.selection.removeAllRanges();\n}\n\n\n/**\n * Retrieves text and text nodes from selection saving them on properties of object\n *\n * @private\n * @param {TextSelection} this\n */\nfunction _getTextNodes() {\n // list of selected text nodes\n var textNodes = [];\n\n if (this.isCollapsed)\n return textNodes;\n\n // create TreeWalker to traverse the tree to select all text nodes\n var selStart = this.range.startContainer\n , selEnd = this.range.endContainer\n , rangeContainer = this.range.commonAncestorContainer;\n\n var treeWalker = this.window.document.createTreeWalker(rangeContainer, NodeFilter.SHOW_TEXT);\n var node = treeWalker.currentNode = selStart;\n\n // traverse DOM tree to collect all selected text nodes\n while (node && (! inEnd || selEnd.contains(node))) {\n textNodes.push(node);\n var inEnd = inEnd || selEnd.contains(node);\n node = treeWalker.nextNode();\n }\n return textNodes;\n}\n\n\n/**\n * Retrieves and returns start/end element from selection saving them on properties of object\n *\n * @private\n * @param {TextSelection} this\n * @return {Element|null}\n */\nfunction _getElement(thisPropName, rangePropName) {\n if (! this.range) return undefined;\n\n if (typeof this[thisPropName] == 'undefined')\n this[thisPropName] = containingElement(this.range[rangePropName]);\n return this[thisPropName];\n}\n\n\n/**\n * Retrieves and returns start/end component from selection saving them on properties of object\n *\n * @private\n * @param {TextSelection} this\n * @return {Component}\n */\nfunction _getComponent(thisPropName, elMethodName) {\n if (! this.range) return undefined;\n\n if (typeof this[thisPropName] == 'undefined')\n this[thisPropName] = Component.getContainingComponent(this[elMethodName]());\n return this[thisPropName];\n}\n\n\nfunction TextSelection$containedComponents() {\n if (this._containedComponents)\n return this._containedComponents;\n\n var components = this._containedComponents = [];\n\n if (this.isCollapsed || ! this.range) return components;\n\n return getComponentsFromRange(this.range);\n}\n\n\nfunction TextSelection$eachContainedComponent(callback, thisArg) {\n if (this.isCollapsed || ! this.range) return;\n\n var components = this.containedComponents();\n\n components.forEach(callback, thisArg);\n}\n\n\n/**\n * TextSelection instance method\n * Deletes the current selection and all components in it\n * \n * @param {Boolean} selectEndContainer set to true if the end container should be selected after deletion\n */\nfunction TextSelection$del(selectEndContainer) {\n if (this.isCollapsed || ! this.range) return;\n\n var selPoint = this._getPostDeleteSelectionPoint(selectEndContainer);\n\n deleteRangeWithComponents(this.range);\n\n this._selectAfterDelete(selPoint);\n selPoint.node.parentNode.normalize();\n}\n\n\nfunction _getPostDeleteSelectionPoint(selectEndContainer) {\n var selNode = this.range.startContainer;\n var selOffset = this.range.startOffset;\n if (selectEndContainer && this.range.startContainer != this.range.endContainer) {\n selNode = this.range.endContainer;\n selOffset = 0;\n }\n return { node: selNode, offset: selOffset };\n}\n\n\nfunction _selectAfterDelete(selPoint) {\n var selNode = selPoint.node\n , selOffset = selPoint.offset;\n\n if (!selNode) return;\n if (selNode.nodeType == Node.TEXT_NODE)\n selNode.textContent = selNode.textContent.trimRight();\n if (!selNode.nodeValue)\n selNode.nodeValue = '\\u00A0'; //non-breaking space, \\u200B for zero width space;\n\n var position = selOffset > selNode.length ? selNode.length : selOffset;\n setCaretPosition(selNode, position);\n}\n\n\n/**\n * Returns selection range\n *\n * @return {Range}\n */\nfunction TextSelection$getRange() {\n return this.range;\n}\n\n\n/**\n * Stores selection window, nodes and offsets in object\n */\nfunction TextSelection$getState(rootEl) {\n var r = this.range;\n var doc = rootEl.ownerDocument\n , win = doc.defaultView || doc.parentWindow;\n if (!r) return { window: win };\n return TextSelection.createStateObject(rootEl, r.startContainer, r.startOffset, r.endContainer, r.endOffset);\n}\n\n\nfunction TextSelection$$createStateObject(rootEl, startContainer, startOffset, endContainer, endOffset) {\n endContainer = endContainer || startContainer;\n endOffset = endOffset || startOffset;\n var doc = rootEl.ownerDocument\n , win = doc.defaultView || doc.parentWindow;\n return {\n window: win,\n rootEl: rootEl,\n start: _getSelectionPointState(rootEl, startContainer, startOffset),\n end: _getSelectionPointState(rootEl, endContainer, endOffset)\n };\n}\n\n\nfunction _getSelectionPointState(rootEl, node, offset) {\n var treePath = domUtils.treePathOf(rootEl, node);\n if (! treePath) logger.error('Selection point is outside of root element');\n return {\n treePath: treePath,\n offset: offset\n };\n}\n\n\n/**\n * Restores actual selection to the stored range\n */\nfunction TextSelection$$createFromState(state) {\n var domUtils = state.window.milo.util.dom;\n\n if (state.rootEl && state.start && state.end) {\n var startNode = _selectionNodeFromState(state.rootEl, state.start)\n , endNode = _selectionNodeFromState(state.rootEl, state.end);\n\n try {\n domUtils.setSelection(startNode, state.start.offset, endNode, state.end.offset);\n return new TextSelection(state.window);\n } catch(e) {\n logger.error('Text selection: can\\'t create selection', e, e.message);\n }\n } else {\n domUtils.clearSelection(state.window);\n return new TextSelection(state.window);\n }\n}\n\n\nfunction _selectionNodeFromState(rootEl, pointState) {\n var node = domUtils.getNodeAtTreePath(rootEl, pointState.treePath);\n if (! node) logger.error('TextSelection createFromState: no node at treePath');\n return node;\n}\n\n\n/**\n * Creates selection from passed range\n * \n * @param {Range} range\n * @param {Boolean} backward\n *\n * @return {TextSelection}\n */\nfunction TextSelection$$createFromRange(range, backward) {\n var win = range.startContainer.ownerDocument.defaultView\n , sel = win.getSelection()\n , endRange;\n\n sel.removeAllRanges();\n\n if (backward){\n endRange = range.cloneRange();\n endRange.collapse(false);\n\n sel.addRange(endRange);\n sel.extend(range.startContainer, range.startOffset) \n }\n else {\n sel.addRange(range);\n }\n\n return new TextSelection(win);\n}\n\n/**\n * Returns a normalized copy of the range\n * If you triple click an item, the end of the range is positioned at the beginning of the NEXT node.\n * this function returns a range with the end positioned at the end of the last textnode contained \n * inside a component with the \"editable\" facet\n * \n * @return {range}\n */\nfunction TextSelection$$getNormalizedRange(){\n var doc = this.range.commonAncestorContainer.ownerDocument\n , tw, previousNode\n , newRange = this.range.cloneRange();\n\n if (newRange.endContainer.nodeType !== Node.TEXT_NODE) {\n tw = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT);\n tw.currentNode = newRange.endContainer;\n previousNode = tw.previousNode();\n newRange.setEnd(previousNode, previousNode.length);\n }\n\n return newRange;\n}\n\n/**\n * get the direction of a selection\n *\n * 1 forward, -1 backward, 0 no direction, undefined one of the node is detached or in a different frame\n *\n * @return {-1|0|1|undefined}\n */\nfunction TextSelection$$getDirection(){\n return domUtils.getSelectionDirection(this.selection); \n}\n\n",
- "'use strict';\n\n\nvar DOMStorageError = require('../error').createClass('DomStorageError')\n , Messenger = require('../../messenger')\n , StorageMessageSource = require('./msg_src')\n , config = require('../../config')\n , jsonParse = require('../json_parse')\n , _ = require('mol-proto')\n , check = require('../check')\n , Match = check.Match;\n\nrequire('./model')\n\nmodule.exports = DOMStorage;\n\n\n// shared keys stored by all instances, include key prefixes\nvar _storedKeys = {\n true: {}, // session storage\n false: {} // local storage\n};\n\n\n/**\n * DOMStorage class to simplify storage and retrieval of multiple items with types preservation to DOM storage (localStorage and sessionStorage).\n * Types will be stored in the key created from value keys with appended `milo.config.domStorage.typeSuffix`\n *\n * @param {String} keyPrefix prefix that will be added to all keys followed by `milo.config.domStorage.prefixSeparator` (\"/\" by default).\n * @param {Boolean} sessionOnly true to use sessionStorage. localStorage will be used by default.\n * @param {Window} win window to work in\n */\nfunction DOMStorage(keyPrefix, sessionOnly, win) {\n if (typeof window == 'undefined') return;\n win = win || window;\n\n keyPrefix = config.domStorage.root +\n (keyPrefix\n ? keyPrefix + config.domStorage.prefixSeparator\n : '');\n\n _.defineProperties(this, {\n keyPrefix: keyPrefix,\n sessionOnly: !! sessionOnly,\n window: win,\n _storage: sessionOnly ? win.sessionStorage : win.localStorage,\n _typeSuffix: config.domStorage.typeSuffix,\n _keys: {}\n }, _.WRIT);\n}\n\n\n_.extendProto(DOMStorage, {\n get: DOMStorage$get,\n set: DOMStorage$set,\n remove: DOMStorage$remove,\n hasItem: DOMStorage$hasItem,\n getItem: DOMStorage$getItem,\n setItem: DOMStorage$setItem,\n removeItem: DOMStorage$removeItem,\n _storageKey: DOMStorage$_storageKey,\n _domStorageKey: DOMStorage$_domStorageKey,\n getAllKeys: DOMStorage$getAllKeys,\n getAllItems: DOMStorage$getAllItems,\n createMessenger: DOMStorage$createMessenger,\n destroy: DOMStorage$destroy\n});\n\n\n/**\n * Expose Mesenger and MessageSource methods on DOMStorage\n */\nMessenger.useWith(DOMStorage, '_messenger', Messenger.defaultMethods);\nStorageMessageSource.useWith(DOMStorage, '_messageSource', ['trigger']);\n\n\nvar _sessionStorage = new DOMStorage('', true)\n , _localStorage = new DOMStorage('', false);\n\nvar _domStorage = {\n true: _sessionStorage,\n false: _localStorage\n };\n\n_.extend(DOMStorage, {\n registerDataType: DOMStorage$$registerDataType,\n local: _localStorage,\n session: _sessionStorage,\n storage: _domStorage,\n _storedKeys: _storedKeys // exposed for testing\n});\n\n\n/**\n * Sets data to DOM storage. `this.keyPrefix` is prepended to keys.\n *\n * @param {Object} data single object can be passed in which case keys will be used as keys in local storage.\n * @param {List} arguments alternatively just the list of arguments can be passed where arguments can be sequentially used as keys and values.\n */\nfunction DOMStorage$set(data) { // or arguments\n if (typeof data == 'object')\n _.eachKey(data, function(value, key) {\n this.setItem(key, value);\n }, this);\n else {\n var argsLen = arguments.length;\n if (argsLen % 2)\n throw new DomStorageError('DOMStorage: set should have even number of arguments or object');\n\n for (var i = 0; i < argsLen; i++) {\n var key = arguments[i]\n , value = arguments[++i];\n\n this.setItem(key, value);\n }\n }\n}\n\n\n/**\n * Gets data from DOM storage. `this.keyPrefix` is prepended to passed keys, but returned object will have keys without root keys.\n *\n * @param {List} arguments keys can be passed as strings or arrays of strings\n * @returns {Object}\n */\nfunction DOMStorage$get() { // , ... arguments\n var data = {};\n _.deepForEach(arguments, function(key) {\n data[key] = this.getItem(key);\n }, this);\n return data;\n}\n\n\n/**\n * Removes keys from DOM storage. `this.keyPrefix` is prepended to passed keys.\n *\n * @param {List} arguments keys can be passed as strings or arrays of strings\n */\nfunction DOMStorage$remove() { //, ... arguments\n _.deepForEach(arguments, function(key) {\n this.removeItem(key);\n }, this);\n}\n\n\n/**\n * Check for presence of single item in DOM storage. `this.keyPrefix` is prepended to passed key.\n *\n * @param {String} key\n * @return {Boolean}\n */\nfunction DOMStorage$hasItem(key) {\n var pKey = this._storageKey(key);\n return this._storage.getItem(pKey) != null;\n}\n\n\n/**\n * Gets single item from DOM storage prepending `this.keyPrefix` to passed key.\n * Reads type of the originally stored value from `key + this._typeSuffix` and converts data to the original type.\n *\n * @param {String} key\n * @return {Any}\n */\nfunction DOMStorage$getItem(key) {\n var pKey = this._storageKey(key);\n var dataType = _getKeyDataType.call(this, pKey);\n var valueStr = this._storage.getItem(pKey);\n var value = _parseData(valueStr, dataType);\n return value;\n}\n\n\n/**\n * Sets single item to DOM storage prepending `this.keyPrefix` to passed key.\n * Stores type of the stored value to `key + this._typeSuffix`.\n *\n * @param {String} key\n * @return {Any}\n */\nfunction DOMStorage$setItem(key, value) {\n var pKey = this._storageKey(key);\n var dataType = _setKeyDataType.call(this, pKey, value);\n var valueStr = _serializeData(value, dataType);\n try {\n this._storage.setItem(pKey, valueStr);\n } catch(e) {\n if (e.name == 'QuotaExceededError') {\n var cfg = config.domStorage.quotaExceeded;\n if (cfg.message)\n milo.mail.postMessage('quotaexceedederror', value);\n if (cfg.throwError)\n throw e;\n } else\n throw e;\n }\n this._keys[key] = true;\n _domStorage[this.sessionOnly]._keys[pKey] = true;\n}\n\n\n/**\n * Removes single item from DOM storage prepending `this.keyPrefix` to passed key.\n * Type of the stored value (in `key + this._typeSuffix` key) is also removed.\n *\n * @param {String} key\n * @return {Any}\n */\nfunction DOMStorage$removeItem(key) {\n var pKey = this._storageKey(key);\n this._storage.removeItem(pKey);\n _removeKeyDataType.call(this, pKey)\n delete this._keys[key];\n delete _domStorage[this.sessionOnly]._keys[pKey];\n}\n\n\n/**\n * Returns the array of all keys stored by this instance of DOMStorage\n *\n * @return {Array}\n */\nfunction DOMStorage$getAllKeys() {\n var storedKeys = Object.keys(this._keys);\n var keysInStorage = storedKeys.filter(function(key) {\n if (this.hasItem(key)) return true;\n else delete this._keys[key];\n }, this);\n return keysInStorage;\n}\n\n\n/**\n * Returns the map with all keys and values (deserialized) stored using this instance of DOMStorage\n *\n * @return {Object}\n */\nfunction DOMStorage$getAllItems() {\n return this.get(this.getAllKeys());\n}\n\n\n/**\n * Returns prefixed key for DOM storage for given unprefixed key.\n *\n * @param {String} key\n * @return {String}\n */\nfunction DOMStorage$_storageKey(key) {\n return this.keyPrefix + key;\n}\n\n\n/**\n * Returns unprefixed key to be used with this instance of DOMStorage fir given actual key in storage\n * If key has different prefix from the keyPrefix returns undefined\n *\n * @param {String} storageKey actual key in local/session storage\n * @return {String}\n */\nfunction DOMStorage$_domStorageKey(storageKey) {\n if (storageKey.indexOf(this._typeSuffix) >= 0) return;\n return _.unPrefix(storageKey, this.keyPrefix);\n}\n\n\n/**\n * Gets originally stored data type for given (prefixed) `key`.\n *\n * @param {String} pKey prefixed key of stored value\n * @return {String}\n */\nfunction _getKeyDataType(pKey) {\n pKey = _dataTypeKey.call(this, pKey);\n return this._storage.getItem(pKey);\n}\n\n\n/**\n * Stores data type for given (prefixed) `key` and `value`.\n * Returns data type for `value`.\n *\n * @param {String} pKey prefixed key of stored value\n * @param {Any} value\n * @return {String}\n */\nfunction _setKeyDataType(pKey, value) {\n var dataType = _getValueType(value);\n pKey = _dataTypeKey.call(this, pKey);\n this._storage.setItem(pKey, dataType);\n return dataType;\n}\n\n\n/**\n * Removes stored data type for given (prefixed) `key`.\n *\n * @param {String} pKey prefixed key of stored value\n */\nfunction _removeKeyDataType(pKey) {\n pKey = _dataTypeKey.call(this, pKey);\n this._storage.removeItem(pKey);\n}\n\n\n/**\n * Returns the key to store data type for given (prefixed) `key`.\n *\n * @param {String} pKey prefixed key of stored value\n * @return {String}\n */\nfunction _dataTypeKey(pKey) {\n return pKey + this._typeSuffix;\n}\n\n\n/**\n * Returns type of value as string. Class name returned for objects ('null' for null).\n * @param {Any} value\n * @return {String}\n */\nfunction _getValueType(value) {\n var valueType = typeof value\n , className = value && value.constructor.name\n , dataType = valuesDataTypes[className];\n return dataType || (\n valueType != 'object'\n ? valueType\n : value == null\n ? 'null'\n : value.constructor.name);\n}\nvar valuesDataTypes = {\n // can be registered with `registerDataType`\n}\n\n\n/**\n * Serializes value to be stored in DOM storage.\n *\n * @param {Any} value value to be serialized\n * @param {String} valueType optional data type to define serializer, _getValueType is used if not passed.\n * @return {String}\n */\nfunction _serializeData(value, valueType) {\n valueType = valueType || _getValueType(value);\n var serializer = dataSerializers[valueType];\n return serializer\n ? serializer(value, valueType)\n : value && value.toString == Object.prototype.toString\n ? JSON.stringify(value)\n : '' + value;\n}\nvar dataSerializers = {\n 'Array': JSON.stringify\n}\n\n\n/**\n * Parses string retrieved from DOM storage.\n *\n * @param {String} valueStr\n * @param {String} valueType data type that defines parser. Original sring will be returned if parser is not defined.\n * @return {Any}\n */\nfunction _parseData(valueStr, valueType) {\n var parser = dataParsers[valueType];\n return parser\n ? parser(valueStr, valueType)\n : valueStr;\n}\nvar dataParsers = {\n Object: jsonParse,\n Array: jsonParse,\n Date: function(valStr) { return new Date(valStr); },\n boolean: function(valStr) { return valStr == 'true'; },\n number: function(valStr) { return Number(valStr); },\n function: function(valStr) { return _.toFunction(valStr); },\n RegExp: function(valStr) { return _.toRegExp(valStr); }\n};\n\n\n/**\n * Registers data type to be saved in DOM storage. Class name can be used or result of `typeof` operator for non-objects to override default conversions.\n *\n * @param {String} valueType class (constructor) name or the string returned by typeof.\n * @param {Function} serializer optional serializer for this type\n * @param {Function} parser optional parser for this type\n * @param {[String]} storeAsDataType optional name of stored data type if different from valueType\n */\nfunction DOMStorage$$registerDataType(valueType, serializer, parser, storeAsDataType) {\n if (serializer) dataSerializers[valueType] = serializer;\n if (parser) dataParsers[valueType] = parser;\n valuesDataTypes[valueType] = storeAsDataType || valueType;\n}\n\n\nfunction DOMStorage$createMessenger() {\n var storageMessageSource = new StorageMessageSource(this);\n var messenger = new Messenger(this, undefined, storageMessageSource);\n _.defineProperties(this, {\n _messenger: messenger,\n _messageSource: storageMessageSource\n }, _.WRIT);\n}\n\n\nfunction DOMStorage$destroy() {\n this._storage = undefined;\n this.window = undefined;\n if (this._messenger) this._messenger.destroy();\n this._destroyed = true;\n}\n",
- "'use strict';\n\nvar Model = require('milo-core').Model\n\nModel.registerWithDOMStorage = Model$$registerWithDOMStorage;\n\n\nfunction Model$$registerWithDOMStorage() {\n var DOMStorage = require('./index');\n DOMStorage.registerDataType('Model', Model_domStorageSerializer, Model_domStorageParser);\n DOMStorage.registerDataType('ModelPath', Model_domStorageSerializer, Model_domStorageParser, 'Model');\n}\n\n\nfunction Model_domStorageSerializer(value) {\n var data = value.get();\n return JSON.stringify(data);\n}\n\n\nfunction Model_domStorageParser(valueStr) {\n var data = _.jsonParse(valueStr);\n return new Model(data);\n}\n",
- "'use strict';\n\n\nvar MessageSource = require('../../messenger/m_source')\n , _ = require('mol-proto')\n , config = require('../../config')\n , miloCount = require('../../util/count')\n , StorageMessageSourceError = require('../../util/error').StorageMessageSource;\n\nvar StorageMessageSource = _.createSubclass(MessageSource, 'StorageMessageSource', true);\n\n\n_.extendProto(StorageMessageSource, {\n // implementing MessageSource interface\n init: init,\n addSourceSubscriber: StorageMessageSource$addSourceSubscriber,\n removeSourceSubscriber: StorageMessageSource$removeSourceSubscriber,\n postMessage: StorageMessageSource$postMessage,\n trigger: StorageMessageSource$trigger,\n\n //class specific methods\n handleEvent: handleEvent // event dispatcher - as defined by Event DOM API\n});\n\nmodule.exports = StorageMessageSource;\n\n\nfunction init(hostObject, proxyMethods, messengerAPIOrClass) {\n if (hostObject.constructor.name != 'DOMStorage')\n throw new StorageMessageSourceError('hostObject should be an instance of DOMStorage');\n this.storage = hostObject;\n this.messageKey = config.domStorage.messageKey;\n this.window = hostObject.window;\n MessageSource.prototype.init.apply(this, arguments);\n}\n\n\nfunction StorageMessageSource$addSourceSubscriber(sourceMessage) {\n this.window.addEventListener('storage', this, false);\n}\n\n\nfunction StorageMessageSource$removeSourceSubscriber(sourceMessage) {\n this.window.removeEventListener('storage', this, false);\n}\n\n\nfunction StorageMessageSource$postMessage(message, data) {\n this.messenger.postMessageSync(message, data);\n}\n\n\nfunction StorageMessageSource$trigger(msgType, data) {\n var key = this.messageKey + msgType;\n data = data || {};\n data[config.domStorage.messageTimestamp] = miloCount();\n _.deferMethod(this.storage, 'setItem', key, data);\n}\n\n\nfunction handleEvent(event) {\n if (event.storageArea != this.storage._storage) return;\n var key = this.storage._domStorageKey(event.key); if (! key) return;\n var msgType = _.unPrefix(key, this.messageKey); if (! msgType) return;\n var data = this.storage.getItem(key); if (! data) return;\n this.dispatchMessage(msgType, data);\n}\n",
- "'use strict';\n\n/**\n * `milo.util.websocket` \n**/\n\n\nvar Messenger = require('../../messenger')\n , WSMessageSource = require('./msg_src')\n , WSMsgAPI = require('./msg_api');\n\n\nfunction websocket() {\n var wsMessenger = new Messenger;\n var wsMsgSource = new WSMessageSource(wsMessenger, { send: 'trigger', connect: 'connect' }, new WSMsgAPI);\n wsMessenger._setMessageSource(wsMsgSource);\n return wsMessenger;\n}\n\n\nmodule.exports = websocket;\n",
- "'use strict';\n\nvar MessengerAPI = require('../../messenger/m_api')\n , _ = require('mol-proto')\n , check = require('../../util/check')\n , Match = check.Match;\n\n\nvar WSMsgAPI = _.createSubclass(MessengerAPI, 'WSMsgAPI', true);\n\n\n_.extendProto(WSMsgAPI, {\n translateToSourceMessage: translateToSourceMessage,\n filterSourceMessage: filterSourceMessage,\n createInternalData: createInternalData\n});\n\nmodule.exports = WSMsgAPI;\n\n\nvar SOCKET_MESSAGES = ['open', 'close', 'error', 'message'];\n\nfunction translateToSourceMessage(message) {\n return SOCKET_MESSAGES.indexOf(message) >= 0\n ? message\n : 'message';\n}\n\n\nfunction filterSourceMessage(sourceMessage, message, msgData) {\n if (SOCKET_MESSAGES.indexOf(message) >= 0) return true; // internal message is one of external messages\n if (sourceMessage == 'message') {\n var msgType = msgData && msgData.type;\n return msgType == message; // type equals internal message\n }\n};\n\n\nfunction createInternalData(sourceMessage, message, event) {\n var internalData = sourceMessage == 'message'\n ? _.jsonParse(event.data) || event.data\n : event;\n return internalData;\n}\n",
- "'use strict';\n\n\nvar MessageSource = require('../../messenger/m_source')\n , _ = require('mol-proto')\n , logger = require('../../util/logger')\n , uniqueId = require('../../util/count')\n , config = require('../../config')\n , check = require('../../util/check')\n , Match = check.Match;\n\n\nvar WSMessageSource = _.createSubclass(MessageSource, 'WSMessageSource', true);\n\n\n_.extendProto(WSMessageSource, {\n // implementing MessageSource interface\n addSourceSubscriber: addSourceSubscriber,\n removeSourceSubscriber: removeSourceSubscriber,\n \n // class specific methods\n handleEvent: WSMessageSource$handleEvent,\n connect: WSMessageSource$connect,\n trigger: WSMessageSource$trigger\n});\n\n\nmodule.exports = WSMessageSource;\n\n\nfunction WSMessageSource$connect(options) {\n this._options = options = options || {};\n\n var host = options.host || window.location.host.replace(/:.*/, '')\n , port = options.port || '8080';\n\n var self = this;\n\n if (this._ws) {\n // TODO should unsubscribe differently\n this._ws.onopen = this.ws.onmessage = this.ws.onclose = this.ws.onerror = undefined;\n this._ws.close();\n }\n\n this._ws = new WebSocket('ws://' + host + ':' + port);\n\n // TODO reconnect\n}\n\n\n\nfunction addSourceSubscriber (sourceMessage) {\n _wsSubscriberMethod.call(this, 'addEventListener', sourceMessage);\n}\n\n\nfunction removeSourceSubscriber (sourceMessage) {\n _wsSubscriberMethod.call(this, 'removeEventListener', sourceMessage);\n}\n\n\nfunction _wsSubscriberMethod (method, sourceMessage) { \n if (!this._ws) return logger.error('websocket is not created');\n this._ws[method](sourceMessage, this);\n}\n\n\n// event dispatcher - as defined by Event DOM API\nfunction WSMessageSource$handleEvent (event) {\n this.dispatchMessage(event.type, event);\n}\n\n\nfunction WSMessageSource$trigger (msg, data, callback) {\n if (!this._ws) return logger.error('websocket is not created');\n\n data = data || {};\n data.type = msg;\n\n var self = this;\n \n if (callback) {\n data.callbackCorrId = uniqueId();\n var interval = _.delay(onTimeout, config.websocket.rpc.timeout);\n toggleRpcSubscription('once', data.callbackCorrId);\n } \n\n this._ws.send(JSON.stringify(data));\n\n\n function onTimeout() {\n toggleRpcSubscription('off', data.callbackCorrId);\n callback(new Error('websocket rpc: timeout'));\n }\n\n function onResponse(msg, msgData) {\n clearInterval(interval);\n if (typeof msgData == 'object') {\n var err = msgData.error ? new Error(msgData.error) : null;\n callback(err, msgData.data)\n } else\n callback(new Error('websocket rpc: invalid response data'), msgData);\n }\n\n function toggleRpcSubscription(onOff, corrId) {\n self.messenger[onOff](config.websocket.rpc.responsePrefix + corrId, onResponse);\n }\n}\n",
+ "'use strict';\n\n// milo.utils.request\n// -----------\n\n// Convenience functions wrapping XMLHTTPRequest functionality.\n\n// ```\n// var request = milo.utils.request\n// , opts: { method: 'GET' };\n\n// request(url, opts, function(err, data) {\n// logger.debug(data);\n// });\n\n// request.get(url, function(err, data) {\n// logger.debug(data);\n// });\n// ```\n\n// Only generic request and get, json, post convenience methods are currently implemented.\n\n\nvar miloCore = require('milo-core')\n , _ = miloCore.proto\n , count = require('./count')\n , config = require('../config')\n , logger = miloCore.util.logger\n , Messenger = miloCore.Messenger;\n\nmodule.exports = request;\n\n\nvar _pendingRequests = [];\n\nvar promiseThen = createPromiseOverride('then');\nvar promiseCatch = createPromiseOverride('catch');\n\n/**\n * Creates a function which is used to override standard promise behaviour and allow promise instances \n * created to maintain a reference to the request object no matter if .then() or .catch() is called.\n */\nfunction createPromiseOverride(functionName) {\n return function() {\n var promise = Promise.prototype[functionName].apply(this, arguments);\n keepRequestObject(promise, this._request);\n return promise;\n }\n}\n\n\nfunction request(url, opts, callback) {\n opts.url = url;\n opts.contentType = opts.contentType || 'application/json;charset=UTF-8';\n if (_messenger) request.postMessageSync('request', { options: opts });\n\n var req = new XMLHttpRequest();\n req.open(opts.method, opts.url, true);\n req.setRequestHeader('Content-Type', opts.contentType);\n setRequestHeaders(req, opts.headers);\n\n req.timeout = opts.timeout || config.request.defaults.timeout;\n req.onreadystatechange = req.ontimeout = req.onabort = onReady;\n\n var xPromise = _createXPromise(req);\n\n req.send(JSON.stringify(opts.data));\n req[config.request.optionsKey] = opts;\n\n _pendingRequests.push(req);\n\n return xPromise.promise;\n\n function onReady(e) {\n _onReady(req, callback, xPromise, e.type);\n }\n}\n\n\nfunction _createXPromise(request) {\n var resolvePromise, rejectPromise;\n var promise = new Promise(function(resolve, reject) {\n resolvePromise = resolve;\n rejectPromise = reject;\n });\n\n keepRequestObject(promise, request);\n promise.catch(_.noop); // Sometimes errors are handled within callbacks, so uncaught promise error message should be suppressed.\n\n return {\n promise: promise,\n resolve: resolvePromise,\n reject: rejectPromise\n }\n}\n\n// Ensures that the promise (and any promises created when calling .then/.catch) has a reference to the original request object\nfunction keepRequestObject(promise, request) {\n promise._request = request;\n promise.then = promiseThen;\n promise.catch = promiseCatch;\n\n return promise;\n}\n\n\nfunction setRequestHeaders(req, headers) {\n if (headers)\n _.eachKey(headers, function(value, key) {\n req.setRequestHeader(key, value);\n });\n}\n\nfunction _onReady(req, callback, xPromise, eventType) {\n if (req.readyState != 4) return;\n if (!req.status && eventType == 'readystatechange') return;\n\n _.spliceItem(_pendingRequests, req);\n\n var error;\n try {\n if ( req.status >= 200 && req.status < 400 ) {\n try {\n postMessage('success');\n callback && callback(null, req.responseText, req);\n } catch(e) { error = e; }\n xPromise.resolve(req.responseText);\n }\n else {\n var errorReason = req.status || eventType;\n try {\n postMessage('error');\n postMessage('error' + errorReason);\n callback && callback(errorReason, req.responseText, req);\n } catch(e) { error = e; }\n xPromise.reject({ reason: errorReason, response: req.responseText });\n }\n } catch(e) {\n error = error || e;\n }\n\n // not removing subscription creates memory leak, deleting property would not remove subscription\n req.onreadystatechange = req.ontimeout = req.onabort = undefined;\n\n if (!_pendingRequests.length)\n postMessage('requestscompleted');\n\n if (error) throw new Error('Exception: ' + error);\n\n function postMessage(msg) {\n if (_messenger) request.postMessage(msg,\n { status: status, response: req.responseText });\n }\n}\n\n\n_.extend(request, {\n get: request$get,\n post: request$post,\n json: request$json,\n jsonp: request$jsonp,\n file: request$file,\n useMessenger: request$useMessenger,\n destroy: request$destroy,\n whenRequestsCompleted: whenRequestsCompleted\n});\n\n\nvar _messenger;\n\n\nfunction request$useMessenger() {\n _messenger = new Messenger(request, ['on', 'once', 'onSync', 'off', 'onMessages', 'offMessages', 'postMessage', 'postMessageSync']);\n}\n\n\nfunction request$get(url, callback) {\n return request(url, { method: 'GET' }, callback);\n}\n\n\nfunction request$post(url, data, callback) {\n return request(url, { method: 'POST', data: data }, callback);\n}\n\n\nfunction request$json(url, callback) {\n var promise = request(url, { method: 'GET' });\n\n var jsonPromise = promise.then(JSON.parse);\n\n if (callback)\n jsonPromise\n .then(function(data) { callback(null, data); })\n .catch(function(errData) { callback(errData.reason, errData.response); });\n\n return jsonPromise;\n}\n\n\nvar jsonpOptions = { method: 'GET', jsonp: true };\nfunction request$jsonp(url, callback) {\n var script = document.createElement('script'),\n xPromise = _createXPromise(script),\n head = window.document.head,\n uniqueCallback = config.request.jsonpCallbackPrefix + count();\n\n var opts = _.extend({ url: url }, jsonpOptions);\n if (_messenger) request.postMessageSync('request', { options: opts });\n\n if (! _.isEqual(_.omitKeys(opts, 'url'), jsonpOptions))\n logger.warn('Ignored not allowed request options change in JSONP request - only URL can be changed');\n\n var timeout = setTimeout(function() {\n var err = new Error('No JSONP response or no callback in response');\n _onResult(err);\n }, config.request.jsonpTimeout);\n\n window[uniqueCallback] = _.partial(_onResult, null);\n\n _pendingRequests.push(window[uniqueCallback]);\n\n script.type = 'text/javascript';\n script.src = opts.url + (opts.url.indexOf('?') == -1 ? '?' : '&') + 'callback=' + uniqueCallback;\n\n head.appendChild(script);\n\n return xPromise.promise;\n\n\n function _onResult(err, result) {\n _.spliceItem(_pendingRequests, window[uniqueCallback]);\n try {\n postMessage(err ? 'error' : 'success', err, result);\n if (err) {\n logger.error('No JSONP response or timeout');\n postMessage('errorjsonptimeout', err);\n }\n callback && callback(err, result);\n }\n catch(e) { var error = e; }\n if (err) xPromise.reject(err);\n else xPromise.resolve(result);\n\n cleanUp();\n if (!_pendingRequests.length)\n postMessage('requestscompleted');\n\n if (error) throw error;\n }\n\n\n function cleanUp() {\n clearTimeout(timeout);\n head.removeChild(script);\n delete window[uniqueCallback];\n }\n\n\n function postMessage(msg, status, result) {\n if (_messenger) request.postMessage(msg,\n { status: status, response: result });\n }\n}\n\n\nfunction request$file(opts, fileData, callback, progress) {\n if (typeof opts == 'string')\n opts = { method: 'POST', url: opts };\n\n opts.method = opts.method || 'POST';\n opts.file = true;\n\n if (_messenger) request.postMessageSync('request', { options: opts });\n\n var req = new XMLHttpRequest();\n if (progress) req.upload.onprogress = progress;\n\n req.open(opts.method, opts.url, true);\n setRequestHeaders(req, opts.headers);\n\n req.timeout = opts.timeout || config.request.defaults.timeout;\n req.onreadystatechange = req.ontimeout = req.onabort = onReady;\n\n var xPromise = _createXPromise(req);\n\n if (opts.binary)\n req.send(fileData);\n else {\n var formData = new FormData();\n formData.append('file', fileData);\n req.send(formData);\n }\n\n _pendingRequests.push(req);\n\n return xPromise.promise;\n\n function onReady(e) {\n if (progress) req.upload.onprogress = undefined;\n _onReady(req, callback, xPromise, e.type);\n }\n}\n\n\nfunction request$destroy() {\n if (_messenger) _messenger.destroy();\n request._destroyed = true;\n}\n\n\nfunction whenRequestsCompleted(callback, timeout) {\n callback = _.once(callback);\n if (timeout)\n _.delay(callback, timeout, 'timeout');\n\n if (_pendingRequests.length)\n _messenger.once('requestscompleted', callback);\n else\n _.defer(callback);\n}\n",
+ "'use strict';\n\n\nvar domUtils = require('../dom')\n , containingElement = domUtils.containingElement\n , setCaretPosition = domUtils.setCaretPosition\n , getComponentsFromRange = domUtils.getComponentsFromRange\n , deleteRangeWithComponents = domUtils.deleteRangeWithComponents\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , Component = require('../../components/c_class')\n , _ = miloCore.proto;\n\nmodule.exports = TextSelection;\n\n\n/**\n * Text selection class.\n * Serves as a helper to manage current selection\n * The object cannot be reused, if the selection changes some of its properties may contain information related to previous selection\n *\n * @param {Window} win window in which text selection is processed\n */\nfunction TextSelection(win) {\n if (! this instanceof TextSelection)\n return new TextSelection(win);\n this.window = win || window;\n this.init();\n}\n\n\n/**\n * TextSelection instance method\n * Returns selection start element\n *\n * @return {Element|null}\n */\nvar TextSelection$startElement = \n _.partial(_getElement, '_startElement', 'startContainer');\n\n\n/**\n * TextSelection instance method\n * Returns selection end element\n *\n * @return {Element|null}\n */\nvar TextSelection$endElement = \n _.partial(_getElement, '_endElement', 'endContainer');\n\n\n/**\n * TextSelection instance method\n * Returns selection end element\n *\n * @return {Element|null}\n */\nvar TextSelection$containingElement = \n _.partial(_getElement, '_containingElement', 'commonAncestorContainer');\n\n\n/**\n * TextSelection instance method\n * Returns selection start Component\n *\n * @return {Component}\n */\nvar TextSelection$startComponent = \n _.partial(_getComponent, '_startComponent', 'startElement');\n\n\n/**\n * TextSelection instance method\n * Returns selection end Component\n *\n * @return {Component}\n */\nvar TextSelection$endComponent = \n _.partial(_getComponent, '_endComponent', 'endElement');\n\n\n/**\n * TextSelection instance method\n * Returns selection end Component\n *\n * @return {Component}\n */\nvar TextSelection$containingComponent = \n _.partial(_getComponent, '_containingComponent', 'containingElement');\n\n\n_.extendProto(TextSelection, {\n init: TextSelection$init,\n text: TextSelection$text,\n textNodes: TextSelection$textNodes,\n clear: TextSelection$clear,\n\n startElement: TextSelection$startElement,\n endElement: TextSelection$endElement,\n containingElement: TextSelection$containingElement,\n\n startComponent: TextSelection$startComponent,\n endComponent: TextSelection$endComponent,\n containingComponent: TextSelection$containingComponent,\n\n containedComponents: TextSelection$containedComponents,\n eachContainedComponent: TextSelection$eachContainedComponent,\n del: TextSelection$del,\n _getPostDeleteSelectionPoint: _getPostDeleteSelectionPoint,\n _selectAfterDelete: _selectAfterDelete,\n\n getRange: TextSelection$getRange,\n getState: TextSelection$getState,\n getNormalizedRange: TextSelection$$getNormalizedRange,\n getDirection: TextSelection$$getDirection\n});\n\n\n_.extend(TextSelection, {\n createFromRange: TextSelection$$createFromRange,\n createFromState: TextSelection$$createFromState,\n createStateObject: TextSelection$$createStateObject\n});\n\n\n/**\n * TextSelection instance method\n * Initializes TextSelection from the current selection\n */\nfunction TextSelection$init() {\n this.selection = this.window.getSelection();\n if (this.selection.rangeCount)\n this.range = this.selection.getRangeAt(0);\n this.isCollapsed = this.selection.isCollapsed;\n}\n\n\n/**\n * TextSelection instance method\n * Retrieves and returns selection text\n *\n * @return {String}\n */\nfunction TextSelection$text() {\n if (! this.range) return undefined;\n\n if (! this._text)\n this._text = this.range.toString();\n\n return this._text;\n}\n\n\n/**\n * TextSelection instance method\n * Retrieves and returns selection text nodes\n *\n * @return {Array[Node]}\n */\nfunction TextSelection$textNodes() {\n if (! this.range) return undefined;\n\n if (! this._textNodes)\n this._textNodes = _getTextNodes.call(this);\n return this._textNodes;\n}\n\n\nfunction TextSelection$clear() {\n this.selection.removeAllRanges();\n}\n\n\n/**\n * Retrieves text and text nodes from selection saving them on properties of object\n *\n * @private\n * @param {TextSelection} this\n */\nfunction _getTextNodes() {\n // list of selected text nodes\n var textNodes = [];\n\n if (this.isCollapsed)\n return textNodes;\n\n // create TreeWalker to traverse the tree to select all text nodes\n var selStart = this.range.startContainer\n , selEnd = this.range.endContainer\n , rangeContainer = this.range.commonAncestorContainer;\n\n var treeWalker = this.window.document.createTreeWalker(rangeContainer, NodeFilter.SHOW_TEXT);\n var node = treeWalker.currentNode = selStart;\n\n // traverse DOM tree to collect all selected text nodes\n while (node && (! inEnd || selEnd.contains(node))) {\n textNodes.push(node);\n var inEnd = inEnd || selEnd.contains(node);\n node = treeWalker.nextNode();\n }\n return textNodes;\n}\n\n\n/**\n * Retrieves and returns start/end element from selection saving them on properties of object\n *\n * @private\n * @param {TextSelection} this\n * @return {Element|null}\n */\nfunction _getElement(thisPropName, rangePropName) {\n if (! this.range) return undefined;\n\n if (typeof this[thisPropName] == 'undefined')\n this[thisPropName] = containingElement(this.range[rangePropName]);\n return this[thisPropName];\n}\n\n\n/**\n * Retrieves and returns start/end component from selection saving them on properties of object\n *\n * @private\n * @param {TextSelection} this\n * @return {Component}\n */\nfunction _getComponent(thisPropName, elMethodName) {\n if (! this.range) return undefined;\n\n if (typeof this[thisPropName] == 'undefined')\n this[thisPropName] = Component.getContainingComponent(this[elMethodName]());\n return this[thisPropName];\n}\n\n\nfunction TextSelection$containedComponents() {\n if (this._containedComponents)\n return this._containedComponents;\n\n var components = this._containedComponents = [];\n\n if (this.isCollapsed || ! this.range) return components;\n\n return getComponentsFromRange(this.range);\n}\n\n\nfunction TextSelection$eachContainedComponent(callback, thisArg) {\n if (this.isCollapsed || ! this.range) return;\n\n var components = this.containedComponents();\n\n components.forEach(callback, thisArg);\n}\n\n\n/**\n * TextSelection instance method\n * Deletes the current selection and all components in it\n * \n * @param {Boolean} selectEndContainer set to true if the end container should be selected after deletion\n */\nfunction TextSelection$del(selectEndContainer) {\n if (this.isCollapsed || ! this.range) return;\n\n var selPoint = this._getPostDeleteSelectionPoint(selectEndContainer);\n\n deleteRangeWithComponents(this.range);\n\n this._selectAfterDelete(selPoint);\n selPoint.node.parentNode.normalize();\n}\n\n\nfunction _getPostDeleteSelectionPoint(selectEndContainer) {\n var selNode = this.range.startContainer;\n var selOffset = this.range.startOffset;\n if (selectEndContainer && this.range.startContainer != this.range.endContainer) {\n selNode = this.range.endContainer;\n selOffset = 0;\n }\n return { node: selNode, offset: selOffset };\n}\n\n\nfunction _selectAfterDelete(selPoint) {\n var selNode = selPoint.node\n , selOffset = selPoint.offset;\n\n if (!selNode) return;\n if (selNode.nodeType == Node.TEXT_NODE)\n selNode.textContent = selNode.textContent.trimRight();\n if (!selNode.nodeValue)\n selNode.nodeValue = '\\u00A0'; //non-breaking space, \\u200B for zero width space;\n\n var position = selOffset > selNode.length ? selNode.length : selOffset;\n setCaretPosition(selNode, position);\n}\n\n\n/**\n * Returns selection range\n *\n * @return {Range}\n */\nfunction TextSelection$getRange() {\n return this.range;\n}\n\n\n/**\n * Stores selection window, nodes and offsets in object\n */\nfunction TextSelection$getState(rootEl) {\n var r = this.range;\n var doc = rootEl.ownerDocument\n , win = doc.defaultView || doc.parentWindow;\n if (!r) return { window: win };\n return TextSelection.createStateObject(rootEl, r.startContainer, r.startOffset, r.endContainer, r.endOffset);\n}\n\n\nfunction TextSelection$$createStateObject(rootEl, startContainer, startOffset, endContainer, endOffset) {\n endContainer = endContainer || startContainer;\n endOffset = endOffset || startOffset;\n var doc = rootEl.ownerDocument\n , win = doc.defaultView || doc.parentWindow;\n return {\n window: win,\n rootEl: rootEl,\n start: _getSelectionPointState(rootEl, startContainer, startOffset),\n end: _getSelectionPointState(rootEl, endContainer, endOffset)\n };\n}\n\n\nfunction _getSelectionPointState(rootEl, node, offset) {\n var treePath = domUtils.treePathOf(rootEl, node);\n if (! treePath) logger.error('Selection point is outside of root element');\n return {\n treePath: treePath,\n offset: offset\n };\n}\n\n\n/**\n * Restores actual selection to the stored range\n */\nfunction TextSelection$$createFromState(state) {\n var domUtils = state.window.milo.util.dom;\n\n if (state.rootEl && state.start && state.end) {\n var startNode = _selectionNodeFromState(state.rootEl, state.start)\n , endNode = _selectionNodeFromState(state.rootEl, state.end);\n\n try {\n domUtils.setSelection(startNode, state.start.offset, endNode, state.end.offset);\n return new TextSelection(state.window);\n } catch(e) {\n logger.error('Text selection: can\\'t create selection', e, e.message);\n }\n } else {\n domUtils.clearSelection(state.window);\n return new TextSelection(state.window);\n }\n}\n\n\nfunction _selectionNodeFromState(rootEl, pointState) {\n var node = domUtils.getNodeAtTreePath(rootEl, pointState.treePath);\n if (! node) logger.error('TextSelection createFromState: no node at treePath');\n return node;\n}\n\n\n/**\n * Creates selection from passed range\n * \n * @param {Range} range\n * @param {Boolean} backward\n *\n * @return {TextSelection}\n */\nfunction TextSelection$$createFromRange(range, backward) {\n var win = range.startContainer.ownerDocument.defaultView\n , sel = win.getSelection()\n , endRange;\n\n sel.removeAllRanges();\n\n if (backward){\n endRange = range.cloneRange();\n endRange.collapse(false);\n\n sel.addRange(endRange);\n sel.extend(range.startContainer, range.startOffset) \n }\n else {\n sel.addRange(range);\n }\n\n return new TextSelection(win);\n}\n\n/**\n * Returns a normalized copy of the range\n * If you triple click an item, the end of the range is positioned at the beginning of the NEXT node.\n * this function returns a range with the end positioned at the end of the last textnode contained \n * inside a component with the \"editable\" facet\n * \n * @return {range}\n */\nfunction TextSelection$$getNormalizedRange(){\n var doc = this.range.commonAncestorContainer.ownerDocument\n , tw, previousNode\n , newRange = this.range.cloneRange();\n\n if (newRange.endContainer.nodeType !== Node.TEXT_NODE) {\n tw = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT);\n tw.currentNode = newRange.endContainer;\n previousNode = tw.previousNode();\n newRange.setEnd(previousNode, previousNode.length);\n }\n\n return newRange;\n}\n\n/**\n * get the direction of a selection\n *\n * 1 forward, -1 backward, 0 no direction, undefined one of the node is detached or in a different frame\n *\n * @return {-1|0|1|undefined}\n */\nfunction TextSelection$$getDirection(){\n return domUtils.getSelectionDirection(this.selection); \n}\n\n",
+ "'use strict';\n\n\nvar miloCore = require('milo-core')\n , Messenger = miloCore.Messenger\n , StorageMessageSource = require('./msg_src')\n , config = require('../../config')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\nrequire('./model')\n\nmodule.exports = DOMStorage;\n\n\n// shared keys stored by all instances, include key prefixes\nvar _storedKeys = {\n true: {}, // session storage\n false: {} // local storage\n};\n\n\n/**\n * DOMStorage class to simplify storage and retrieval of multiple items with types preservation to DOM storage (localStorage and sessionStorage).\n * Types will be stored in the key created from value keys with appended `milo.config.domStorage.typeSuffix`\n *\n * @param {String} keyPrefix prefix that will be added to all keys followed by `milo.config.domStorage.prefixSeparator` (\"/\" by default).\n * @param {Boolean} sessionOnly true to use sessionStorage. localStorage will be used by default.\n * @param {Window} win window to work in\n */\nfunction DOMStorage(keyPrefix, sessionOnly, win) {\n if (typeof window == 'undefined') return;\n win = win || window;\n\n keyPrefix = config.domStorage.root +\n (keyPrefix\n ? keyPrefix + config.domStorage.prefixSeparator\n : '');\n\n _.defineProperties(this, {\n keyPrefix: keyPrefix,\n sessionOnly: !! sessionOnly,\n window: win,\n _storage: sessionOnly ? win.sessionStorage : win.localStorage,\n _typeSuffix: config.domStorage.typeSuffix,\n _keys: {}\n }, _.WRIT);\n}\n\n\n_.extendProto(DOMStorage, {\n get: DOMStorage$get,\n set: DOMStorage$set,\n remove: DOMStorage$remove,\n hasItem: DOMStorage$hasItem,\n getItem: DOMStorage$getItem,\n setItem: DOMStorage$setItem,\n removeItem: DOMStorage$removeItem,\n _storageKey: DOMStorage$_storageKey,\n _domStorageKey: DOMStorage$_domStorageKey,\n getAllKeys: DOMStorage$getAllKeys,\n getAllItems: DOMStorage$getAllItems,\n createMessenger: DOMStorage$createMessenger,\n destroy: DOMStorage$destroy\n});\n\n\n/**\n * Expose Mesenger and MessageSource methods on DOMStorage\n */\nMessenger.useWith(DOMStorage, '_messenger', Messenger.defaultMethods);\nStorageMessageSource.useWith(DOMStorage, '_messageSource', ['trigger']);\n\n\nvar _sessionStorage = new DOMStorage('', true)\n , _localStorage = new DOMStorage('', false);\n\nvar _domStorage = {\n true: _sessionStorage,\n false: _localStorage\n };\n\n_.extend(DOMStorage, {\n registerDataType: DOMStorage$$registerDataType,\n local: _localStorage,\n session: _sessionStorage,\n storage: _domStorage,\n _storedKeys: _storedKeys // exposed for testing\n});\n\n\n/**\n * Sets data to DOM storage. `this.keyPrefix` is prepended to keys.\n *\n * @param {Object} data single object can be passed in which case keys will be used as keys in local storage.\n * @param {List} arguments alternatively just the list of arguments can be passed where arguments can be sequentially used as keys and values.\n */\nfunction DOMStorage$set(data) { // or arguments\n if (typeof data == 'object')\n _.eachKey(data, function(value, key) {\n this.setItem(key, value);\n }, this);\n else {\n var argsLen = arguments.length;\n if (argsLen % 2)\n throw new DomStorageError('DOMStorage: set should have even number of arguments or object');\n\n for (var i = 0; i < argsLen; i++) {\n var key = arguments[i]\n , value = arguments[++i];\n\n this.setItem(key, value);\n }\n }\n}\n\n\n/**\n * Gets data from DOM storage. `this.keyPrefix` is prepended to passed keys, but returned object will have keys without root keys.\n *\n * @param {List} arguments keys can be passed as strings or arrays of strings\n * @returns {Object}\n */\nfunction DOMStorage$get() { // , ... arguments\n var data = {};\n _.deepForEach(arguments, function(key) {\n data[key] = this.getItem(key);\n }, this);\n return data;\n}\n\n\n/**\n * Removes keys from DOM storage. `this.keyPrefix` is prepended to passed keys.\n *\n * @param {List} arguments keys can be passed as strings or arrays of strings\n */\nfunction DOMStorage$remove() { //, ... arguments\n _.deepForEach(arguments, function(key) {\n this.removeItem(key);\n }, this);\n}\n\n\n/**\n * Check for presence of single item in DOM storage. `this.keyPrefix` is prepended to passed key.\n *\n * @param {String} key\n * @return {Boolean}\n */\nfunction DOMStorage$hasItem(key) {\n var pKey = this._storageKey(key);\n return this._storage.getItem(pKey) != null;\n}\n\n\n/**\n * Gets single item from DOM storage prepending `this.keyPrefix` to passed key.\n * Reads type of the originally stored value from `key + this._typeSuffix` and converts data to the original type.\n *\n * @param {String} key\n * @return {Any}\n */\nfunction DOMStorage$getItem(key) {\n var pKey = this._storageKey(key);\n var dataType = _getKeyDataType.call(this, pKey);\n var valueStr = this._storage.getItem(pKey);\n var value = _parseData(valueStr, dataType);\n return value;\n}\n\n\n/**\n * Sets single item to DOM storage prepending `this.keyPrefix` to passed key.\n * Stores type of the stored value to `key + this._typeSuffix`.\n *\n * @param {String} key\n * @return {Any}\n */\nfunction DOMStorage$setItem(key, value) {\n var pKey = this._storageKey(key);\n var dataType = _setKeyDataType.call(this, pKey, value);\n var valueStr = _serializeData(value, dataType);\n try {\n this._storage.setItem(pKey, valueStr);\n } catch(e) {\n if (e.name == 'QuotaExceededError') {\n var cfg = config.domStorage.quotaExceeded;\n if (cfg.message)\n milo.mail.postMessage('quotaexceedederror', value);\n if (cfg.throwError)\n throw e;\n } else\n throw e;\n }\n this._keys[key] = true;\n _domStorage[this.sessionOnly]._keys[pKey] = true;\n}\n\n\n/**\n * Removes single item from DOM storage prepending `this.keyPrefix` to passed key.\n * Type of the stored value (in `key + this._typeSuffix` key) is also removed.\n *\n * @param {String} key\n * @return {Any}\n */\nfunction DOMStorage$removeItem(key) {\n var pKey = this._storageKey(key);\n this._storage.removeItem(pKey);\n _removeKeyDataType.call(this, pKey)\n delete this._keys[key];\n delete _domStorage[this.sessionOnly]._keys[pKey];\n}\n\n\n/**\n * Returns the array of all keys stored by this instance of DOMStorage\n *\n * @return {Array}\n */\nfunction DOMStorage$getAllKeys() {\n var storedKeys = Object.keys(this._keys);\n var keysInStorage = storedKeys.filter(function(key) {\n if (this.hasItem(key)) return true;\n else delete this._keys[key];\n }, this);\n return keysInStorage;\n}\n\n\n/**\n * Returns the map with all keys and values (deserialized) stored using this instance of DOMStorage\n *\n * @return {Object}\n */\nfunction DOMStorage$getAllItems() {\n return this.get(this.getAllKeys());\n}\n\n\n/**\n * Returns prefixed key for DOM storage for given unprefixed key.\n *\n * @param {String} key\n * @return {String}\n */\nfunction DOMStorage$_storageKey(key) {\n return this.keyPrefix + key;\n}\n\n\n/**\n * Returns unprefixed key to be used with this instance of DOMStorage fir given actual key in storage\n * If key has different prefix from the keyPrefix returns undefined\n *\n * @param {String} storageKey actual key in local/session storage\n * @return {String}\n */\nfunction DOMStorage$_domStorageKey(storageKey) {\n if (storageKey.indexOf(this._typeSuffix) >= 0) return;\n return _.unPrefix(storageKey, this.keyPrefix);\n}\n\n\n/**\n * Gets originally stored data type for given (prefixed) `key`.\n *\n * @param {String} pKey prefixed key of stored value\n * @return {String}\n */\nfunction _getKeyDataType(pKey) {\n pKey = _dataTypeKey.call(this, pKey);\n return this._storage.getItem(pKey);\n}\n\n\n/**\n * Stores data type for given (prefixed) `key` and `value`.\n * Returns data type for `value`.\n *\n * @param {String} pKey prefixed key of stored value\n * @param {Any} value\n * @return {String}\n */\nfunction _setKeyDataType(pKey, value) {\n var dataType = _getValueType(value);\n pKey = _dataTypeKey.call(this, pKey);\n this._storage.setItem(pKey, dataType);\n return dataType;\n}\n\n\n/**\n * Removes stored data type for given (prefixed) `key`.\n *\n * @param {String} pKey prefixed key of stored value\n */\nfunction _removeKeyDataType(pKey) {\n pKey = _dataTypeKey.call(this, pKey);\n this._storage.removeItem(pKey);\n}\n\n\n/**\n * Returns the key to store data type for given (prefixed) `key`.\n *\n * @param {String} pKey prefixed key of stored value\n * @return {String}\n */\nfunction _dataTypeKey(pKey) {\n return pKey + this._typeSuffix;\n}\n\n\n/**\n * Returns type of value as string. Class name returned for objects ('null' for null).\n * @param {Any} value\n * @return {String}\n */\nfunction _getValueType(value) {\n var valueType = typeof value\n , className = value && value.constructor.name\n , dataType = valuesDataTypes[className];\n return dataType || (\n valueType != 'object'\n ? valueType\n : value == null\n ? 'null'\n : value.constructor.name);\n}\nvar valuesDataTypes = {\n // can be registered with `registerDataType`\n}\n\n\n/**\n * Serializes value to be stored in DOM storage.\n *\n * @param {Any} value value to be serialized\n * @param {String} valueType optional data type to define serializer, _getValueType is used if not passed.\n * @return {String}\n */\nfunction _serializeData(value, valueType) {\n valueType = valueType || _getValueType(value);\n var serializer = dataSerializers[valueType];\n return serializer\n ? serializer(value, valueType)\n : value && value.toString == Object.prototype.toString\n ? JSON.stringify(value)\n : '' + value;\n}\nvar dataSerializers = {\n 'Array': JSON.stringify\n}\n\n\n/**\n * Parses string retrieved from DOM storage.\n *\n * @param {String} valueStr\n * @param {String} valueType data type that defines parser. Original sring will be returned if parser is not defined.\n * @return {Any}\n */\nfunction _parseData(valueStr, valueType) {\n var parser = dataParsers[valueType];\n return parser\n ? parser(valueStr, valueType)\n : valueStr;\n}\nvar dataParsers = {\n Object: _.jsonParse,\n Array: _.jsonParse,\n Date: function(valStr) { return new Date(valStr); },\n boolean: function(valStr) { return valStr == 'true'; },\n number: Number,\n function: _.toFunction,\n RegExp: _.toRegExp\n};\n\n\n/**\n * Registers data type to be saved in DOM storage. Class name can be used or result of `typeof` operator for non-objects to override default conversions.\n *\n * @param {String} valueType class (constructor) name or the string returned by typeof.\n * @param {Function} serializer optional serializer for this type\n * @param {Function} parser optional parser for this type\n * @param {[String]} storeAsDataType optional name of stored data type if different from valueType\n */\nfunction DOMStorage$$registerDataType(valueType, serializer, parser, storeAsDataType) {\n if (serializer) dataSerializers[valueType] = serializer;\n if (parser) dataParsers[valueType] = parser;\n valuesDataTypes[valueType] = storeAsDataType || valueType;\n}\n\n\nfunction DOMStorage$createMessenger() {\n var storageMessageSource = new StorageMessageSource(this);\n var messenger = new Messenger(this, undefined, storageMessageSource);\n _.defineProperties(this, {\n _messenger: messenger,\n _messageSource: storageMessageSource\n }, _.WRIT);\n}\n\n\nfunction DOMStorage$destroy() {\n this._storage = undefined;\n this.window = undefined;\n if (this._messenger) this._messenger.destroy();\n this._destroyed = true;\n}\n",
+ "'use strict';\n\nvar miloCore = require('milo-core')\n , Model = miloCore.Model\n , _ = miloCore.proto;\n\nModel.registerWithDOMStorage = Model$$registerWithDOMStorage;\n\n\nfunction Model$$registerWithDOMStorage() {\n var DOMStorage = require('./index');\n DOMStorage.registerDataType('Model', Model_domStorageSerializer, Model_domStorageParser);\n DOMStorage.registerDataType('ModelPath', Model_domStorageSerializer, Model_domStorageParser, 'Model');\n}\n\n\nfunction Model_domStorageSerializer(value) {\n var data = value.get();\n return JSON.stringify(data);\n}\n\n\nfunction Model_domStorageParser(valueStr) {\n var data = _.jsonParse(valueStr);\n return new Model(data);\n}\n",
+ "'use strict';\n\n\nvar miloCore = require('milo-core')\n , MessageSource = miloCore.classes.MessageSource\n , _ = miloCore.proto\n , config = require('../../config')\n , miloCount = require('../../util/count');\n\nvar StorageMessageSource = _.createSubclass(MessageSource, 'StorageMessageSource', true);\n\n\n_.extendProto(StorageMessageSource, {\n // implementing MessageSource interface\n init: init,\n addSourceSubscriber: StorageMessageSource$addSourceSubscriber,\n removeSourceSubscriber: StorageMessageSource$removeSourceSubscriber,\n postMessage: StorageMessageSource$postMessage,\n trigger: StorageMessageSource$trigger,\n\n //class specific methods\n handleEvent: handleEvent // event dispatcher - as defined by Event DOM API\n});\n\nmodule.exports = StorageMessageSource;\n\n\nfunction init(hostObject, proxyMethods, messengerAPIOrClass) {\n if (hostObject.constructor.name != 'DOMStorage')\n throw new Error('hostObject should be an instance of DOMStorage');\n this.storage = hostObject;\n this.messageKey = config.domStorage.messageKey;\n this.window = hostObject.window;\n MessageSource.prototype.init.apply(this, arguments);\n}\n\n\nfunction StorageMessageSource$addSourceSubscriber(sourceMessage) {\n this.window.addEventListener('storage', this, false);\n}\n\n\nfunction StorageMessageSource$removeSourceSubscriber(sourceMessage) {\n this.window.removeEventListener('storage', this, false);\n}\n\n\nfunction StorageMessageSource$postMessage(message, data) {\n this.messenger.postMessageSync(message, data);\n}\n\n\nfunction StorageMessageSource$trigger(msgType, data) {\n var key = this.messageKey + msgType;\n data = data || {};\n data[config.domStorage.messageTimestamp] = miloCount();\n _.deferMethod(this.storage, 'setItem', key, data);\n}\n\n\nfunction handleEvent(event) {\n if (event.storageArea != this.storage._storage) return;\n var key = this.storage._domStorageKey(event.key); if (! key) return;\n var msgType = _.unPrefix(key, this.messageKey); if (! msgType) return;\n var data = this.storage.getItem(key); if (! data) return;\n this.dispatchMessage(msgType, data);\n}\n",
+ "'use strict';\n\n/**\n * `milo.util.websocket` \n**/\n\n\nvar Messenger = require('milo-core').Messenger\n , WSMessageSource = require('./msg_src')\n , WSMsgAPI = require('./msg_api');\n\n\nfunction websocket() {\n var wsMessenger = new Messenger;\n var wsMsgSource = new WSMessageSource(wsMessenger, { send: 'trigger', connect: 'connect' }, new WSMsgAPI);\n wsMessenger._setMessageSource(wsMsgSource);\n return wsMessenger;\n}\n\n\nmodule.exports = websocket;\n",
+ "'use strict';\n\nvar miloCore = require('milo-core')\n , MessengerAPI = miloCore.classes.MessengerAPI\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match;\n\n\nvar WSMsgAPI = _.createSubclass(MessengerAPI, 'WSMsgAPI', true);\n\n\n_.extendProto(WSMsgAPI, {\n translateToSourceMessage: translateToSourceMessage,\n filterSourceMessage: filterSourceMessage,\n createInternalData: createInternalData\n});\n\nmodule.exports = WSMsgAPI;\n\n\nvar SOCKET_MESSAGES = ['open', 'close', 'error', 'message'];\n\nfunction translateToSourceMessage(message) {\n return SOCKET_MESSAGES.indexOf(message) >= 0\n ? message\n : 'message';\n}\n\n\nfunction filterSourceMessage(sourceMessage, message, msgData) {\n if (SOCKET_MESSAGES.indexOf(message) >= 0) return true; // internal message is one of external messages\n if (sourceMessage == 'message') {\n var msgType = msgData && msgData.type;\n return msgType == message; // type equals internal message\n }\n};\n\n\nfunction createInternalData(sourceMessage, message, event) {\n var internalData = sourceMessage == 'message'\n ? _.jsonParse(event.data) || event.data\n : event;\n return internalData;\n}\n",
+ "'use strict';\n\n\nvar miloCore = require('milo-core')\n , MessageSource = miloCore.classes.MessageSource\n , _ = miloCore.proto\n , logger = miloCore.util.logger\n , uniqueId = require('../../util/count')\n , config = require('../../config')\n , check = miloCore.util.check\n , Match = check.Match;\n\n\nvar WSMessageSource = _.createSubclass(MessageSource, 'WSMessageSource', true);\n\n\n_.extendProto(WSMessageSource, {\n // implementing MessageSource interface\n addSourceSubscriber: addSourceSubscriber,\n removeSourceSubscriber: removeSourceSubscriber,\n \n // class specific methods\n handleEvent: WSMessageSource$handleEvent,\n connect: WSMessageSource$connect,\n trigger: WSMessageSource$trigger\n});\n\n\nmodule.exports = WSMessageSource;\n\n\nfunction WSMessageSource$connect(options) {\n this._options = options = options || {};\n\n var host = options.host || window.location.host.replace(/:.*/, '')\n , port = options.port || '8080';\n\n var self = this;\n\n if (this._ws) {\n // TODO should unsubscribe differently\n this._ws.onopen = this.ws.onmessage = this.ws.onclose = this.ws.onerror = undefined;\n this._ws.close();\n }\n\n this._ws = new WebSocket('ws://' + host + ':' + port);\n\n // TODO reconnect\n}\n\n\n\nfunction addSourceSubscriber (sourceMessage) {\n _wsSubscriberMethod.call(this, 'addEventListener', sourceMessage);\n}\n\n\nfunction removeSourceSubscriber (sourceMessage) {\n _wsSubscriberMethod.call(this, 'removeEventListener', sourceMessage);\n}\n\n\nfunction _wsSubscriberMethod (method, sourceMessage) { \n if (!this._ws) return logger.error('websocket is not created');\n this._ws[method](sourceMessage, this);\n}\n\n\n// event dispatcher - as defined by Event DOM API\nfunction WSMessageSource$handleEvent (event) {\n this.dispatchMessage(event.type, event);\n}\n\n\nfunction WSMessageSource$trigger (msg, data, callback) {\n if (!this._ws) return logger.error('websocket is not created');\n\n data = data || {};\n data.type = msg;\n\n var self = this;\n \n if (callback) {\n data.callbackCorrId = uniqueId();\n var interval = _.delay(onTimeout, config.websocket.rpc.timeout);\n toggleRpcSubscription('once', data.callbackCorrId);\n } \n\n this._ws.send(JSON.stringify(data));\n\n\n function onTimeout() {\n toggleRpcSubscription('off', data.callbackCorrId);\n callback(new Error('websocket rpc: timeout'));\n }\n\n function onResponse(msg, msgData) {\n clearInterval(interval);\n if (typeof msgData == 'object') {\n var err = msgData.error ? new Error(msgData.error) : null;\n callback(err, msgData.data)\n } else\n callback(new Error('websocket rpc: invalid response data'), msgData);\n }\n\n function toggleRpcSubscription(onOff, corrId) {\n self.messenger[onOff](config.websocket.rpc.responsePrefix + corrId, onResponse);\n }\n}\n",
";(function(){\n\n// This would be the place to edit if you want a different\n// Base32 implementation\n\nvar alphabet = '0123456789abcdefghjkmnpqrtuvwxyz'\nvar alias = { o:0, i:1, l:1, s:5 }\n\n/**\n * Build a lookup table and memoize it\n *\n * Return an object that maps a character to its\n * byte value.\n */\n\nvar lookup = function() {\n var table = {}\n // Invert 'alphabet'\n for (var i = 0; i < alphabet.length; i++) {\n table[alphabet[i]] = i\n }\n // Splice in 'alias'\n for (var key in alias) {\n if (!alias.hasOwnProperty(key)) continue\n table[key] = table['' + alias[key]]\n }\n lookup = function() { return table }\n return table\n}\n\n/**\n * A streaming encoder\n *\n * var encoder = new base32.Encoder()\n * var output1 = encoder.update(input1)\n * var output2 = encoder.update(input2)\n * var lastoutput = encode.update(lastinput, true)\n */\n\nfunction Encoder() {\n var skip = 0 // how many bits we will skip from the first byte\n var bits = 0 // 5 high bits, carry from one byte to the next\n\n this.output = ''\n\n // Read one byte of input\n // Should not really be used except by \"update\"\n this.readByte = function(byte) {\n // coerce the byte to an int\n if (typeof byte == 'string') byte = byte.charCodeAt(0)\n\n if (skip < 0) { // we have a carry from the previous byte\n bits |= (byte >> (-skip))\n } else { // no carry\n bits = (byte << skip) & 248\n }\n\n if (skip > 3) {\n // not enough data to produce a character, get us another one\n skip -= 8\n return 1\n }\n\n if (skip < 4) {\n // produce a character\n this.output += alphabet[bits >> 3]\n skip += 5\n }\n\n return 0\n }\n\n // Flush any remaining bits left in the stream\n this.finish = function(check) {\n var output = this.output + (skip < 0 ? alphabet[bits >> 3] : '') + (check ? '$' : '')\n this.output = ''\n return output\n }\n}\n\n/**\n * Process additional input\n *\n * input: string of bytes to convert\n * flush: boolean, should we flush any trailing bits left\n * in the stream\n * returns: a string of characters representing 'input' in base32\n */\n\nEncoder.prototype.update = function(input, flush) {\n for (var i = 0; i < input.length; ) {\n i += this.readByte(input[i])\n }\n // consume all output\n var output = this.output\n this.output = ''\n if (flush) {\n output += this.finish()\n }\n return output\n}\n\n// Functions analogously to Encoder\n\nfunction Decoder() {\n var skip = 0 // how many bits we have from the previous character\n var byte = 0 // current byte we're producing\n\n this.output = ''\n\n // Consume a character from the stream, store\n // the output in this.output. As before, better\n // to use update().\n this.readChar = function(char) {\n if (typeof char != 'string'){\n if (typeof char == 'number') {\n char = String.fromCharCode(char)\n }\n }\n char = char.toLowerCase()\n var val = lookup()[char]\n if (typeof val == 'undefined') {\n // character does not exist in our lookup table\n return // skip silently. An alternative would be:\n // throw Error('Could not find character \"' + char + '\" in lookup table.')\n }\n val <<= 3 // move to the high bits\n byte |= val >>> skip\n skip += 5\n if (skip >= 8) {\n // we have enough to preduce output\n this.output += String.fromCharCode(byte)\n skip -= 8\n if (skip > 0) byte = (val << (5 - skip)) & 255\n else byte = 0\n }\n\n }\n\n this.finish = function(check) {\n var output = this.output + (skip < 0 ? alphabet[bits >> 3] : '') + (check ? '$' : '')\n this.output = ''\n return output\n }\n}\n\nDecoder.prototype.update = function(input, flush) {\n for (var i = 0; i < input.length; i++) {\n this.readChar(input[i])\n }\n var output = this.output\n this.output = ''\n if (flush) {\n output += this.finish()\n }\n return output\n}\n\n/** Convenience functions\n *\n * These are the ones to use if you just have a string and\n * want to convert it without dealing with streams and whatnot.\n */\n\n// String of data goes in, Base32-encoded string comes out.\nfunction encode(input) {\n var encoder = new Encoder()\n var output = encoder.update(input, true)\n return output\n}\n\n// Base32-encoded string goes in, decoded data comes out.\nfunction decode(input) {\n var decoder = new Decoder()\n var output = decoder.update(input, true)\n return output\n}\n\nvar base32 = {\n Decoder: Decoder,\n Encoder: Encoder,\n encode: encode,\n decode: decode\n}\n\nif (typeof window !== 'undefined') {\n // we're in a browser - OMG!\n window.base32 = base32\n}\n\nif (typeof module !== 'undefined' && module.exports) {\n // nodejs/browserify\n module.exports = base32\n}\n})();\n",
"\n// not implemented\n// The reason for having an empty file and not throwing is to allow\n// untraditional implementation of this module.\n",
- "// doT.js\n// 2011-2014, Laura Doktorova, https://github.com/olado/doT\n// Licensed under the MIT license.\n\n(function() {\n\t\"use strict\";\n\n\tvar doT = {\n\t\tversion: \"1.0.3\",\n\t\ttemplateSettings: {\n\t\t\tevaluate: /\\{\\{([\\s\\S]+?(\\}?)+)\\}\\}/g,\n\t\t\tinterpolate: /\\{\\{=([\\s\\S]+?)\\}\\}/g,\n\t\t\tencode: /\\{\\{!([\\s\\S]+?)\\}\\}/g,\n\t\t\tuse: /\\{\\{#([\\s\\S]+?)\\}\\}/g,\n\t\t\tuseParams: /(^|[^\\w$])def(?:\\.|\\[[\\'\\\"])([\\w$\\.]+)(?:[\\'\\\"]\\])?\\s*\\:\\s*([\\w$\\.]+|\\\"[^\\\"]+\\\"|\\'[^\\']+\\'|\\{[^\\}]+\\})/g,\n\t\t\tdefine: /\\{\\{##\\s*([\\w\\.$]+)\\s*(\\:|=)([\\s\\S]+?)#\\}\\}/g,\n\t\t\tdefineParams:/^\\s*([\\w$]+):([\\s\\S]+)/,\n\t\t\tconditional: /\\{\\{\\?(\\?)?\\s*([\\s\\S]*?)\\s*\\}\\}/g,\n\t\t\titerate: /\\{\\{~\\s*(?:\\}\\}|([\\s\\S]+?)\\s*\\:\\s*([\\w$]+)\\s*(?:\\:\\s*([\\w$]+))?\\s*\\}\\})/g,\n\t\t\tvarname:\t\"it\",\n\t\t\tstrip:\t\ttrue,\n\t\t\tappend:\t\ttrue,\n\t\t\tselfcontained: false,\n\t\t\tdoNotSkipEncoded: false\n\t\t},\n\t\ttemplate: undefined, //fn, compile template\n\t\tcompile: undefined //fn, for express\n\t}, _globals;\n\n\tdoT.encodeHTMLSource = function(doNotSkipEncoded) {\n\t\tvar encodeHTMLRules = { \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\", \"/\": \"/\" },\n\t\t\tmatchHTML = doNotSkipEncoded ? /[&<>\"'\\/]/g : /&(?!#?\\w+;)|<|>|\"|'|\\//g;\n\t\treturn function(code) {\n\t\t\treturn code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : \"\";\n\t\t};\n\t};\n\n\t_globals = (function(){ return this || (0,eval)(\"this\"); }());\n\n\tif (typeof module !== \"undefined\" && module.exports) {\n\t\tmodule.exports = doT;\n\t} else if (typeof define === \"function\" && define.amd) {\n\t\tdefine(function(){return doT;});\n\t} else {\n\t\t_globals.doT = doT;\n\t}\n\n\tvar startend = {\n\t\tappend: { start: \"'+(\", end: \")+'\", startencode: \"'+encodeHTML(\" },\n\t\tsplit: { start: \"';out+=(\", end: \");out+='\", startencode: \"';out+=encodeHTML(\" }\n\t}, skip = /$^/;\n\n\tfunction resolveDefs(c, block, def) {\n\t\treturn ((typeof block === \"string\") ? block : block.toString())\n\t\t.replace(c.define || skip, function(m, code, assign, value) {\n\t\t\tif (code.indexOf(\"def.\") === 0) {\n\t\t\t\tcode = code.substring(4);\n\t\t\t}\n\t\t\tif (!(code in def)) {\n\t\t\t\tif (assign === \":\") {\n\t\t\t\t\tif (c.defineParams) value.replace(c.defineParams, function(m, param, v) {\n\t\t\t\t\t\tdef[code] = {arg: param, text: v};\n\t\t\t\t\t});\n\t\t\t\t\tif (!(code in def)) def[code]= value;\n\t\t\t\t} else {\n\t\t\t\t\tnew Function(\"def\", \"def['\"+code+\"']=\" + value)(def);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn \"\";\n\t\t})\n\t\t.replace(c.use || skip, function(m, code) {\n\t\t\tif (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {\n\t\t\t\tif (def[d] && def[d].arg && param) {\n\t\t\t\t\tvar rw = (d+\":\"+param).replace(/'|\\\\/g, \"_\");\n\t\t\t\t\tdef.__exp = def.__exp || {};\n\t\t\t\t\tdef.__exp[rw] = def[d].text.replace(new RegExp(\"(^|[^\\\\w$])\" + def[d].arg + \"([^\\\\w$])\", \"g\"), \"$1\" + param + \"$2\");\n\t\t\t\t\treturn s + \"def.__exp['\"+rw+\"']\";\n\t\t\t\t}\n\t\t\t});\n\t\t\tvar v = new Function(\"def\", \"return \" + code)(def);\n\t\t\treturn v ? resolveDefs(c, v, def) : v;\n\t\t});\n\t}\n\n\tfunction unescape(code) {\n\t\treturn code.replace(/\\\\('|\\\\)/g, \"$1\").replace(/[\\r\\t\\n]/g, \" \");\n\t}\n\n\tdoT.template = function(tmpl, c, def) {\n\t\tc = c || doT.templateSettings;\n\t\tvar cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,\n\t\t\tstr = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;\n\n\t\tstr = (\"var out='\" + (c.strip ? str.replace(/(^|\\r|\\n)\\t* +| +\\t*(\\r|\\n|$)/g,\" \")\n\t\t\t\t\t.replace(/\\r|\\n|\\t|\\/\\*[\\s\\S]*?\\*\\//g,\"\"): str)\n\t\t\t.replace(/'|\\\\/g, \"\\\\$&\")\n\t\t\t.replace(c.interpolate || skip, function(m, code) {\n\t\t\t\treturn cse.start + unescape(code) + cse.end;\n\t\t\t})\n\t\t\t.replace(c.encode || skip, function(m, code) {\n\t\t\t\tneedhtmlencode = true;\n\t\t\t\treturn cse.startencode + unescape(code) + cse.end;\n\t\t\t})\n\t\t\t.replace(c.conditional || skip, function(m, elsecase, code) {\n\t\t\t\treturn elsecase ?\n\t\t\t\t\t(code ? \"';}else if(\" + unescape(code) + \"){out+='\" : \"';}else{out+='\") :\n\t\t\t\t\t(code ? \"';if(\" + unescape(code) + \"){out+='\" : \"';}out+='\");\n\t\t\t})\n\t\t\t.replace(c.iterate || skip, function(m, iterate, vname, iname) {\n\t\t\t\tif (!iterate) return \"';} } out+='\";\n\t\t\t\tsid+=1; indv=iname || \"i\"+sid; iterate=unescape(iterate);\n\t\t\t\treturn \"';var arr\"+sid+\"=\"+iterate+\";if(arr\"+sid+\"){var \"+vname+\",\"+indv+\"=-1,l\"+sid+\"=arr\"+sid+\".length-1;while(\"+indv+\"\n// milo.classes\n// -----------\n\n// This module contains foundation classes\n\nvar classes = {\n Mixin: require('./abstract/mixin'),\n MessageSource: require('./messenger/m_source'),\n MessengerMessageSource: require('./messenger/msngr_source'),\n MessengerAPI: require('./messenger/m_api'),\n MessengerRegexpAPI: require('./messenger/m_api_rx')\n};\n\nmodule.exports = classes;\n",
"'use strict';\n\n\nvar _ = require('mol-proto');\n\n\nmodule.exports = config;\n\nfunction config(options) {\n _.deepExtend(config, options);\n}\n\nconfig({\n mixin: {\n instancePropertiesMap: '___mixin_instances'\n },\n check: true,\n debug: false\n});\n",
"'use strict';\n\nvar Mixin = require('../abstract/mixin')\n , MessageSource = require('./m_source')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match;\n\n\n/**\n * `milo.Messenger`\n * A generic Messenger class that is used for all kinds of messaging in milo. It is subclassed from [Mixin](../abstract/mixin.js.html) and it proxies its methods to the host object for convenience.\n * All facets and components have messenger attached to them. Messenger class interoperates with [MessageSource](./m_source.js.html) class that connects the messenger to some external source of messages (e.g., DOM events) and [MessengerAPI](./m_api.js.html) class that allows to define higher level messages than messages that exist on the source.\n * Messenger class is used internally in milo and can be used together with any objects/classes in the application.\n * milo also defines a global messenger [milo.mail](../mail/index.js.html) that dispatches `domready` event and can be used for any application wide messaging.\n * To initialize your app after DOM is ready use:\n * ```\n * milo.mail.on('domready', function() {\n * // application starts\n * });\n * ```\n * or the following shorter form of the same:\n * ```\n * milo(function() {\n * // application starts\n * });\n * ```\n */\nvar Messenger = _.createSubclass(Mixin, 'Messenger');\n\nvar messagesSplitRegExp = Messenger.messagesSplitRegExp = /\\s*(?:\\,|\\s)\\s*/;\n\n\n/**\n * ####Messenger instance methods####\n *\n * - [init](#init)\n * - [on](#Messenger$on) (alias - onMessage, deprecated)\n * - [off](#Messenger$off) (alias - offMessage, deprecated)\n * - [onMessages](#onMessages)\n * - [offMessages](#offMessages)\n * - [once](#once)\n * - [onceSync](#onceSync)\n * - [postMessage](#postMessage)\n * - [getSubscribers](#getSubscribers)\n *\n * \"Private\" methods\n *\n * - [_chooseSubscribersHash](#_chooseSubscribersHash)\n * - [_registerSubscriber](#_registerSubscriber)\n * - [_removeSubscriber](#_removeSubscriber)\n * - [_removeAllSubscribers](#_removeAllSubscribers)\n * - [_callPatternSubscribers](#_callPatternSubscribers)\n * - [_callSubscribers](#_callSubscribers)\n * - [_setMessageSource](#_setMessageSource)\n * - [getMessageSource](#getMessageSource)\n */\n_.extendProto(Messenger, {\n init: init, // called by Mixin (superclass)\n destroy: Messenger$destroy,\n on: Messenger$on,\n once: Messenger$once,\n onceSync: Messenger$onceSync,\n onSync: Messenger$onSync,\n onAsync: Messenger$onAsync,\n onMessage: Messenger$on, // deprecated\n off: Messenger$off,\n offMessage: Messenger$off, // deprecated\n onMessages: onMessages,\n offMessages: offMessages,\n offAll: Messenger$offAll,\n postMessage: postMessage,\n postMessageSync: postMessageSync,\n getSubscribers: getSubscribers,\n getMessageSource: getMessageSource,\n _chooseSubscribersHash: _chooseSubscribersHash,\n _registerSubscriber: _registerSubscriber,\n _removeSubscriber: _removeSubscriber,\n _removeAllSubscribers: _removeAllSubscribers,\n _callPatternSubscribers: _callPatternSubscribers,\n _callSubscribers: _callSubscribers,\n _callSubscriber: _callSubscriber,\n _setMessageSource: _setMessageSource\n});\n\n\n/**\n * A default map of proxy methods used by ComponentFacet and Component classes to pass to Messenger when it is instantiated.\n * This map is for convenience only, it is NOT used internally by Messenger, a host class should pass it for methods to be proxied this way.\n */\nMessenger.defaultMethods = {\n on: 'on',\n onSync: 'onSync',\n once: 'once',\n onceSync: 'onceSync',\n off: 'off',\n onMessages: 'onMessages',\n offMessages: 'offMessages',\n postMessage: 'postMessage',\n postMessageSync: 'postMessageSync',\n getSubscribers: 'getSubscribers'\n};\n\n\nmodule.exports = Messenger;\n\n\nMessenger.subscriptions = [];\n\n\n/**\n * Messenger instance method\n * Initializes Messenger. Method is called by Mixin class constructor.\n * See [on](#Messenger$on) method, [Messenger](#Messenger) class above and [MessageSource](./m_source.js.html) class.\n *\n * @param {Object} hostObject Optional object that stores the messenger on one of its properties. It is used to proxy methods of messenger and also as a context for subscribers when they are called by the Messenger. See `on` method.\n * @param {Object} proxyMethods Optional map of method names; key - proxy method name, value - messenger's method name.\n * @param {MessageSource} messageSource Optional messageSource linked to the messenger. If messageSource is supplied, the reference to the messenger will stored on its 'messenger' property\n */\nfunction init(hostObject, proxyMethods, messageSource) {\n // hostObject and proxyMethods are used in Mixin and checked there\n if (messageSource)\n this._setMessageSource(messageSource);\n\n _initializeSubscribers.call(this);\n}\n\n\nfunction _initializeSubscribers() {\n _.defineProperties(this, {\n _messageSubscribers: {},\n _patternMessageSubscribers: {},\n }, _.CONF);\n}\n\n\n/**\n * Destroys messenger. Maybe needs to unsubscribe all subscribers\n */\nfunction Messenger$destroy() {\n this.offAll();\n var messageSource = this.getMessageSource();\n if (messageSource)\n messageSource.destroy();\n}\n\n\n/**\n * Messenger instance method.\n * Registers a subscriber function for a certain message(s).\n * This method returns `true` if the subscription was successful. It can be unsuccessful if the passed subscriber has already been subscribed to this message type - double subscription never happens and it is safe to subscribe again - no error or warning is thrown or logged.\n * Subscriber is passed two parameters: `message` (string) and `data` (object). Data object is supplied when message is dispatched, Messenger itself adds nothing to it. For example, [events facet](../components/c_facets/Events.js.html) sends actual DOM event when it posts message.\n * Usage:\n * ```\n * // subscribes onMouseUpDown to two DOM events on component via events facet.\n * myComp.events.on('mousedown mouseup', onMouseUpDown);\n * function onMouseUpDown(eventType, event) {\n * // ...\n * }\n *\n * myComp.data.on(/.+/, function(msg, data) {\n * logger.debug(msg, data);\n * }); // subscribes anonymous function to all non-empty messages on data facet\n * // it will not be possible to unsubscribe anonymous subscriber separately,\n * // but myComp.data.off(/.+/) will unsubscribe it\n * ```\n * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added, so it can subscribe to the source.\n * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `on` when they proxy it.\n * See [postMessage](#postMessage).\n *\n * @param {String|Array[String]|RegExp} messages Message types that should envoke the subscriber.\n * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.\n * If an array of strings is passed, each string is a message type to subscribe for.\n * If a RegExp is passed, the subscriber will be envoked when the message dispatched on the messenger matches the pattern (or IS the RegExp with identical pattern).\n * Pattern subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.\n * @param {Function|Object} subscriber Message subscriber - a function that will be called when the message is dispatched on the messenger (usually via proxied postMessage method of host object).\n * If hostObject was supplied to Messenger constructor, hostObject will be the context (the value of this) for the subscriber envocation.\n * Subscriber can also be an object with properties `subscriber` (function) and `context` (\"this\" value when subscriber is called)\n * @return {Boolean}\n */\nfunction Messenger$on(messages, subscriber) {\n return _Messenger_onWithOptions.call(this, messages, subscriber);\n}\n\n\nfunction Messenger$once(messages, subscriber) {\n return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1 });\n}\n\nfunction Messenger$onceSync(messages, subscriber) {\n return _Messenger_onWithOptions.call(this, messages, subscriber, { dispatchTimes: 1, sync: true });\n}\n\n\nfunction Messenger$onSync(messages, subscriber) {\n return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: true });\n}\n\n\nfunction Messenger$onAsync(messages, subscriber) {\n return _Messenger_onWithOptions.call(this, messages, subscriber, { sync: false });\n}\n\n\nfunction _Messenger_onWithOptions(messages, subscriber, options) {\n check(messages, Match.OneOf(String, [String], RegExp));\n check(subscriber, Match.OneOf(Function, {\n subscriber: Function,\n context: Match.Any,\n options: Match.Optional(Object),\n }));\n\n if (typeof subscriber == 'function') {\n subscriber = {\n subscriber: subscriber,\n context: this._hostObject,\n };\n }\n\n if (options) {\n subscriber.options = subscriber.options || {};\n _.extend(subscriber.options, options);\n }\n\n return _Messenger_on.call(this, messages, subscriber);\n}\n\n\nfunction _Messenger_on(messages, subscriber) {\n _.defineProperty(subscriber, '__messages', messages);\n return _eachMessage.call(this, '_registerSubscriber', messages, subscriber);\n}\n\n\nfunction _eachMessage(methodName, messages, subscriber) {\n if (typeof messages == 'string')\n messages = messages.split(messagesSplitRegExp);\n\n var subscribersHash = this._chooseSubscribersHash(messages);\n\n if (messages instanceof RegExp)\n return this[methodName](subscribersHash, messages, subscriber);\n\n else {\n var changed = false;\n\n messages.forEach(function(message) {\n var subscriptionChanged = this[methodName](subscribersHash, message, subscriber);\n changed = changed || subscriptionChanged;\n }, this);\n\n return changed;\n }\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * It is called by [on](#Messenger$on) to register subscriber for one message type.\n * Returns `true` if this subscriber is not yet registered for this type of message.\n * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the first subscriber for a given message is added.\n *\n * @private\n * @param {Object} subscribersHash The map of subscribers determined by [on](#Messenger$on) based on Message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`\n * @param {String} message Message type\n * @param {Function|Object} subscriber Subscriber function to be added or object with properties `subscriber` (function) and `context` (value of \"this\" when subscriber is called)\n * @return {Boolean}\n */\nfunction _registerSubscriber(subscribersHash, message, subscriber) {\n if (! (subscribersHash[message] && subscribersHash[message].length)) {\n subscribersHash[message] = [];\n if (message instanceof RegExp)\n subscribersHash[message].pattern = message;\n if (this._messageSource)\n this._messageSource.onSubscriberAdded(message);\n var noSubscribers = true;\n }\n\n var msgSubscribers = subscribersHash[message];\n var notYetRegistered = noSubscribers || _indexOfSubscriber.call(this, msgSubscribers, subscriber) == -1;\n\n if (notYetRegistered)\n msgSubscribers.push(subscriber);\n\n return notYetRegistered;\n}\n\n\n/**\n * Finds subscriber index in the list\n *\n * @param {Array[Function|Object]} list list of subscribers\n * @param {Function|Object} subscriber subscriber function or object with properties `subscriber` (function) and `context` (\"this\" object)\n */\nfunction _indexOfSubscriber(list, subscriber) {\n var self = this;\n return _.findIndex(list, function(subscr){\n return subscriber.subscriber == subscr.subscriber\n && subscriber.context == subscr.context\n });\n}\n\n\n/**\n * Messenger instance method.\n * Subscribes to multiple messages passed as map together with subscribers.\n * Usage:\n * ```\n * myComp.events.onMessages({\n * 'mousedown': onMouseDown,\n * 'mouseup': onMouseUp\n * });\n * function onMouseDown(eventType, event) {}\n * function onMouseUp(eventType, event) {}\n * ```\n * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was added.\n * It is NOT possible to add pattern subscriber using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.\n *\n * @param {Object[Function]} messageSubscribers Map of message subscribers to be added\n * @return {Object[Boolean]}\n */\nfunction onMessages(messageSubscribers) {\n check(messageSubscribers, Match.ObjectHash(Match.OneOf(Function, { subscriber: Function, context: Match.Any })));\n\n var notYetRegisteredMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {\n return this.on(messages, subscriber);\n }, this);\n\n return notYetRegisteredMap;\n}\n\n\n/**\n * Messenger instance method.\n * Removes a subscriber for message(s). Removes all subscribers for the message if subscriber isn't passed.\n * This method returns `true` if the subscriber was registered. No error or warning is thrown or logged if you remove subscriber that was not registered.\n * [Components](../components/c_class.js.html) and [facets](../components/c_facet.js.html) change this method name to `off` when they proxy it.\n * Usage:\n * ```\n * // unsubscribes onMouseUpDown from two DOM events.\n * myComp.events.off('mousedown mouseup', onMouseUpDown);\n * ```\n * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.\n *\n * @param {String|Array[String]|RegExp} messages Message types that a subscriber should be removed for.\n * If string is passed, it can be a sigle message or multiple message types separated by whitespace with optional commas.\n * If an array of strings is passed, each string is a message type to remove a subscriber for.\n * If a RegExp is passed, the pattern subscriber will be removed.\n * RegExp subscriber does NOT cause any subscription to MessageSource, it only captures messages that are already subscribed to with precise message types.\n * @param {Function} subscriber Message subscriber - Optional function that will be removed from the list of subscribers for the message(s). If subscriber is not supplied, all subscribers will be removed from this message(s).\n * @return {Boolean}\n */\nfunction Messenger$off(messages, subscriber) {\n check(messages, Match.OneOf(String, [String], RegExp));\n check(subscriber, Match.Optional(Match.OneOf(Function, {\n subscriber: Function,\n context: Match.Any,\n options: Match.Optional(Object),\n // __messages: Match.Optional(Match.OneOf(String, [String], RegExp))\n })));\n\n return _Messenger_off.call(this, messages, subscriber);\n}\n\n\nfunction _Messenger_off(messages, subscriber) {\n return _eachMessage.call(this, '_removeSubscriber', messages, subscriber);\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * It is called by [off](#Messenger$off) to remove subscriber for one message type.\n * Returns `true` if this subscriber was registered for this type of message.\n * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified when the last subscriber for a given message is removed and there is no more subscribers for this message.\n *\n * @private\n * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`\n * @param {String} message Message type\n * @param {Function} subscriber Subscriber function to be removed\n * @return {Boolean}\n */\nfunction _removeSubscriber(subscribersHash, message, subscriber) {\n var msgSubscribers = subscribersHash[message];\n if (! msgSubscribers || ! msgSubscribers.length)\n return false; // nothing removed\n\n if (subscriber) {\n if (typeof subscriber == 'function')\n subscriber = { subscriber: subscriber, context: this._hostObject };\n\n var subscriberIndex = _indexOfSubscriber.call(this, msgSubscribers, subscriber);\n if (subscriberIndex == -1)\n return false; // nothing removed\n msgSubscribers.splice(subscriberIndex, 1);\n if (! msgSubscribers.length)\n this._removeAllSubscribers(subscribersHash, message);\n\n } else\n this._removeAllSubscribers(subscribersHash, message);\n\n return true; // subscriber(s) removed\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * It is called by [_removeSubscriber](#_removeSubscriber) to remove all subscribers for one message type.\n * If messenger has [MessageSource](./m_source.js.html) attached to it, MessageSource will be notified that all message subscribers were removed so it can unsubscribe from the source.\n *\n * @private\n * @param {Object} subscribersHash The map of subscribers determined by [off](#Messenger$off) based on message type, can be `this._patternMessageSubscribers` or `this._messageSubscribers`\n * @param {String} message Message type\n */\nfunction _removeAllSubscribers(subscribersHash, message) {\n delete subscribersHash[message];\n if (this._messageSource && typeof message == 'string')\n this._messageSource.onSubscriberRemoved(message);\n}\n\n\n/**\n * Messenger instance method.\n * Unsubscribes from multiple messages passed as map together with subscribers.\n * Returns map with the same keys (message types) and boolean values indicating whether particular subscriber was removed.\n * If a subscriber for one of the messages is not supplied, all subscribers for this message will be removed.\n * Usage:\n * ```\n * myComp.events.offMessages({\n * 'mousedown': onMouseDown,\n * 'mouseup': onMouseUp,\n * 'click': undefined // all subscribers to this message will be removed\n * });\n * ```\n * It is NOT possible to remove pattern subscriber(s) using this method, as although you can use RegExp as the key, JavaScript will automatically convert it to string.\n *\n * @param {Object[Function]} messageSubscribers Map of message subscribers to be removed\n * @return {Object[Boolean]}\n */\nfunction offMessages(messageSubscribers) {\n check(messageSubscribers, Match.ObjectHash(Match.Optional(Match.OneOf(Function, { subscriber: Function, context: Match.Any }))));\n\n var subscriberRemovedMap = _.mapKeys(messageSubscribers, function(subscriber, messages) {\n return this.off(messages, subscriber);\n }, this);\n\n return subscriberRemovedMap;\n}\n\n\n/**\n * Unsubscribes all subscribers\n */\nfunction Messenger$offAll() {\n _offAllSubscribers.call(this, this._patternMessageSubscribers);\n _offAllSubscribers.call(this, this._messageSubscribers);\n}\n\n\nfunction _offAllSubscribers(subscribersHash) {\n _.eachKey(subscribersHash, function(subscribers, message) {\n this._removeAllSubscribers(subscribersHash, message);\n }, this);\n}\n\n\n// TODO - send event to messageSource\n\n\n/**\n * Messenger instance method.\n * Dispatches the message calling all subscribers registered for this message and, if the message is a string, calling all pattern subscribers when message matches the pattern.\n * Each subscriber is passed the same parameters that are passed to theis method.\n * The context of the subscriber envocation is set to the host object (`this._hostObject`) that was passed to the messenger constructor.\n * Subscribers are called in the next tick (\"asynchronously\") apart from those that were subscribed with `onSync` (or that have `options.sync == true`).\n *\n * @param {String|RegExp} message message to be dispatched\n * If the message is a string, the subscribers registered with exactly this message will be called and also pattern subscribers registered with the pattern that matches the dispatched message.\n * If the message is RegExp, only the subscribers registered with exactly this pattern will be called.\n * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.\n * @param {Function} callback optional callback to pass to subscriber\n * @param {Boolean} _synchronous if true passed, subscribers will be envoked synchronously apart from those that have `options.sync == false`. This parameter should not be used, instead postMessageSync should be used.\n */\nfunction postMessage(message, data, callback, _synchronous) {\n check(message, Match.OneOf(String, RegExp));\n check(callback, Match.Optional(Function));\n\n var subscribersHash = this._chooseSubscribersHash(message);\n var msgSubscribers = subscribersHash[message];\n\n this._callSubscribers(message, data, callback, msgSubscribers, _synchronous);\n\n if (typeof message == 'string')\n this._callPatternSubscribers(message, data, callback, msgSubscribers, _synchronous);\n}\n\n\n/**\n * Same as postMessage apart from envoking subscribers synchronously, apart from those subscribed with `onAsync` (or with `options.sync == false`).\n *\n * @param {String|RegExp} message\n * @param {Any} data\n * @param {Function} callback\n */\nfunction postMessageSync(message, data, callback) {\n this.postMessage(message, data, callback, true);\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * Envokes pattern subscribers with the pattern that matches the message.\n * The method is called by [postMessage](#postMessage) - see more information there.\n *\n * @private\n * @param {String} message message to be dispatched. Pattern subscribers registered with the pattern that matches the dispatched message will be called.\n * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.\n * @param {Function} callback optional callback to pass to subscriber\n * @param {Array[Function|Object]} calledMsgSubscribers array of subscribers already called, they won't be called again if they are among pattern subscribers.\n */\nfunction _callPatternSubscribers(message, data, callback, calledMsgSubscribers, _synchronous) {\n _.eachKey(this._patternMessageSubscribers,\n function(patternSubscribers) {\n var pattern = patternSubscribers.pattern;\n if (pattern.test(message)) {\n if (calledMsgSubscribers) {\n var patternSubscribers = patternSubscribers.filter(function(subscriber) {\n var index = _indexOfSubscriber.call(this, calledMsgSubscribers, subscriber);\n return index == -1;\n });\n }\n this._callSubscribers(message, data, callback, patternSubscribers, _synchronous);\n }\n }\n , this);\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * Envokes subscribers from the passed list.\n * The method is called by [postMessage](#postMessage) and [_callPatternSubscribers](#_callPatternSubscribers).\n *\n * @private\n * @param {String} message message to be dispatched, passed to subscribers as the first parameter.\n * @param {Any} data data that will be passed to the subscriber as the second parameter. Messenger does not modify this data in any way.\n * @param {Array[Function|Object]} msgSubscribers the array of message subscribers to be called. Each subscriber is called with the host object (see Messenger constructor) as the context.\n * @param {Function} callback optional callback to pass to subscriber\n */\nfunction _callSubscribers(message, data, callback, msgSubscribers, _synchronous) {\n if (msgSubscribers && msgSubscribers.length) {\n // cloning is necessary as some of the subscribers\n // can be unsubscribed during the dispatch\n // so this array would change in the process\n msgSubscribers = msgSubscribers.slice();\n\n msgSubscribers.forEach(function(subscriber) {\n this._callSubscriber(subscriber, message, data, callback, _synchronous);\n }, this);\n }\n}\n\n\nfunction _callSubscriber(subscriber, message, data, callback, _synchronous) {\n var syncSubscriber = subscriber.options && subscriber.options.sync\n , synchro = (_synchronous && syncSubscriber !== false)\n || syncSubscriber;\n\n var dispatchTimes = subscriber.options && subscriber.options.dispatchTimes;\n if (dispatchTimes) {\n if (dispatchTimes <= 1) {\n var messages = subscriber.__messages;\n this.off(messages, subscriber);\n } else if (dispatchTimes > 1)\n subscriber.options.dispatchTimes--;\n }\n\n if (synchro)\n subscriber.subscriber.call(subscriber.context, message, data, callback);\n else\n _.deferMethod(subscriber.subscriber, 'call', subscriber.context, message, data, callback);\n}\n\n\n/**\n * Messenger instance method.\n * Returns the array of subscribers that would be called if the message were dispatched.\n * If `includePatternSubscribers === false`, pattern subscribers with matching patters will not be included (by default they are included).\n * If there are no subscribers to the message, `undefined` will be returned, not an empty array, so it is safe to use the result in boolean tests.\n *\n * @param {String|RegExp} message Message to get subscribers for.\n * If the message is RegExp, only pattern subscribers registered with exactly this pattern will be returned.\n * If the message is String, subscribers registered with the string messages and pattern subscribers registered with matching pattern will be returned (unless the second parameter is false).\n * @param {Boolean} includePatternSubscribers Optional false to prevent inclusion of patter subscribers, by default they are included.\n * @return {Array|undefined}\n */\nfunction getSubscribers(message, includePatternSubscribers) {\n check(message, Match.OneOf(String, RegExp));\n\n var subscribersHash = this._chooseSubscribersHash(message);\n var msgSubscribers = subscribersHash[message]\n ? [].concat(subscribersHash[message])\n : [];\n\n // pattern subscribers are incuded by default\n if (includePatternSubscribers !== false && typeof message == 'string') {\n _.eachKey(this._patternMessageSubscribers,\n function(patternSubscribers) {\n var pattern = patternSubscribers.pattern;\n if (patternSubscribers && patternSubscribers.length\n && pattern.test(message))\n _.appendArray(msgSubscribers, patternSubscribers);\n }\n );\n }\n\n // return undefined if there are no subscribers\n return msgSubscribers.length\n ? msgSubscribers\n : undefined;\n}\n\n\n/**\n * \"Private\" Messenger instance method\n * Returns the map of subscribers for a given message type.\n *\n * @private\n * @param {String|RegExp} message Message to choose the map of subscribers for\n * @return {Object[Function]}\n */\nfunction _chooseSubscribersHash(message) {\n return message instanceof RegExp\n ? this._patternMessageSubscribers\n : this._messageSubscribers;\n}\n\n\n/**\n * Messenger instance method\n * Sets [MessageSource](./m_source.js.html) for the messenger also setting the reference to the messenger in the MessageSource.\n * MessageSource can be passed to message constructor; this method allows to set it at a later time. For example, the subclasses of [ComponentFacet](../components/c_facet.js.html) use this method to set different MessageSource'es in the messenger that is created by ComponentFacet.\n * Currently the method is implemented in such way that it can be called only once - MessageSource cannot be changed after this method is called.\n *\n * @param {MessageSource} messageSource an instance of MessageSource class to attach to this messenger (and to have this messenger attached to it too)\n */\nfunction _setMessageSource(messageSource) {\n check(messageSource, MessageSource);\n\n _.defineProperty(this, '_messageSource', messageSource);\n messageSource.messenger = this;\n}\n\n\n/**\n * Messenger instance method\n * Returns messenger MessageSource\n *\n * @return {MessageSource}\n */\nfunction getMessageSource() {\n return this._messageSource\n}\n",
- "arguments[4][68][0].apply(exports,arguments)",
- "arguments[4][69][0].apply(exports,arguments)",
+ "'use strict';\n\nvar _ = require('mol-proto')\n , logger = require('../util/logger');\n\n\nmodule.exports = MessengerAPI;\n\n\n/**\n * `milo.classes.MessengerAPI`\n * Base class, subclasses of which can supplement the functionality of [MessageSource](./m_source.js.html) by implementing three methods:\n *\n * - `translateToSourceMessage` to translate source messages (recieved from external source via `MessageSOurce`) to internal messages (that are dispatched on Messenger), allowing to make internal messages more detailed than source messages. For example, [Data facet](../components/c_facets/Data.js.html) uses [DataMsgAPI](../components/msg_api/data.js.html) to define several internal messages related to the change of state in contenteditable DOM element.\n * - `createInternalData` to modify message data received from source to some more meaningful or more detailed message data that will be dispatched on Messenger. For example, [Data facet](../components/c_facets/Data.js.html) uses [DataMsgAPI](../components/msg_api/data.js.html) (subclass of MessengerAPI) to translate DOM messages to data change messages.\n * - `filterSourceMessage` to enable/disable message dispatch based on some conditions in data.\n *\n * If `MessageSource` constructor is not passed an instance of some subclass of `MessengerAPI`, it automatically creates an instance of MessengerAPI that defines all 3 of those methods in a trivial way. See these methods below for their signatures.\n *\n * @constructor\n * @this {MessengerAPI}\n * @return {MessengerAPI}\n */\nfunction MessengerAPI() {\n if (this.init)\n this.init.apply(this, arguments);\n}\n\n\n/**\n * ####MessengerAPI instance methods####\n *\n * - [init](#init) - initializes MessengerAPI\n * - [addInternalMessage](#addInternalMessage) - adds internal message\n * - [removeInternalMessage](#removeInternalMessage) - removes internal message\n * - [getInternalMessages](#getInternalMessages) - returns the list of internal messages for given source message\n *\n * These methods should be redefined by subclass:\n *\n * - [translateToSourceMessage](#translateToSourceMessage) - converts internal message type to source (external) message type\n * - [createInternalData](#createInternalData) - converts source message data received via MessageSource to internal message data\n * - [filterSourceMessage](#filterSourceMessage) - filters source message based on the data of the message and the corresponding internal message that is about to be sent on Messenger\n */\n_.extendProto(MessengerAPI, {\n init: init,\n destroy: MessengerAPI$destroy,\n addInternalMessage: addInternalMessage,\n removeInternalMessage: removeInternalMessage,\n getInternalMessages: getInternalMessages,\n\n // should be redefined by subclass\n translateToSourceMessage: translateToSourceMessage,\n createInternalData: createInternalData,\n filterSourceMessage: filterSourceMessage\n});\n\n\n/**\n * MessengerAPI instance method\n * Called by MessengerAPI constructor. Subclasses that re-implement `init` method should call this method using: `MessengerAPI.prototype.init.apply(this, arguments)`\n */\nfunction init() {\n _.defineProperty(this, '_internalMessages', {});\n}\n\n\n/**\n * Destroys messenger API\n */\nfunction MessengerAPI$destroy() {\n\n}\n\n\n/**\n * MessengerAPI instance method\n * Translates internal `message` to source message, adds internal `message` to the list, making sure the same `message` wasn't passed before (it would indicate Messenger error).\n * Returns source message if it is used first time (so that `MessageSource` subcribes to this source message) or `undefined`.\n *\n * @param {String} message internal message to be translated and added\n * @return {String|undefined}\n */\nfunction addInternalMessage(message) {\n var internalMsgs\n , sourceMessage = this.translateToSourceMessage(message);\n\n if (typeof sourceMessage == 'undefined') return;\n\n if (this._internalMessages.hasOwnProperty(sourceMessage)) {\n internalMsgs = this._internalMessages[sourceMessage];\n if (internalMsgs.indexOf(message) == -1)\n internalMsgs.push(message);\n else\n logger.warn('Duplicate addInternalMessage call for internal message ' + message);\n } else {\n internalMsgs = this._internalMessages[sourceMessage] = [];\n internalMsgs.push(message);\n return sourceMessage;\n }\n}\n\n\n/**\n * MessengerAPI instance method\n * Removes internal `message` from the list connected to corresponding source message (`translateToSourceMessage` is used for translation).\n * Returns source message, if the last internal message was removed (so that `MessageSource` can unsubscribe from this source message), or `undefined`.\n *\n * @param {String} message internal message to be translated and removed\n * @return {String|undefined}\n */\nfunction removeInternalMessage(message) {\n var sourceMessage = this.translateToSourceMessage(message);\n\n if (typeof sourceMessage == 'undefined') return;\n\n var internalMsgs = this._internalMessages[sourceMessage];\n\n if (internalMsgs && internalMsgs.length) {\n var messageIndex = internalMsgs.indexOf(message);\n if (messageIndex >= 0) {\n internalMsgs.splice(messageIndex, 1);\n if (internalMsgs.length == 0) {\n delete this._internalMessages[sourceMessage];\n return sourceMessage;\n }\n } else\n unexpectedNotificationWarning();\n } else\n unexpectedNotificationWarning();\n\n\n function unexpectedNotificationWarning() {\n logger.warn('notification received: un-subscribe from internal message ' + message\n + ' without previous subscription notification');\n }\n}\n\n\n/**\n * MessengerAPI instance method\n * Returns the array of internal messages that were translated to given `sourceMessage`.\n * This method is used by `MessageSource` to dispatch source message on the `Mesenger`.\n *\n * @param {String} sourceMessage source message\n * @return {Array[String]}\n */\nfunction getInternalMessages(sourceMessage) {\n return this._internalMessages[sourceMessage];\n}\n\n\n/**\n * MessengerAPI instance method\n * Subclasses should re-implement this method to define the rule for translation of internal `message` to source message. This class simply returns the same `message`.\n *\n * @param {String} message internal message to be translated\n * @return {String}\n */\nfunction translateToSourceMessage(message) {\n return message\n}\n\n\n/**\n * MessengerAPI instance method\n * Subclasses should re-implement this method to define the rule for translation of source message data to internal message data. This class simply returns the same `sourceData`.\n * This method is used in [dispatchMessage](./m_source.js.html#dispatchMessage) method of `MessageSource`.\n *\n * @param {String} sourceMessage source message, can be used in translation rule\n * @param {String} message internal message, can be used in translation rule\n * @param {Object} sourceData data received from source that has to be translated to data that will be sent to internal Messenger subscriber\n * @return {Object}\n */\nfunction createInternalData(sourceMessage, message, sourceData) {\n return sourceData;\n}\n\n\n/**\n * MessengerAPI instance method\n * Subclasses should re-implement this method to define the dispatch filter for internal messages. This method should return `true` to allow and `false` to prevent internal message dispatch. This class always returns `true`.\n * This method is used in [dispatchMessage](./m_source.js.html#dispatchMessage) method of `MessageSource`.\n *\n * @param {String} sourceMessage source message, can be used in filter rule\n * @param {String} message internal message, can be used in filter rule\n * @param {Object} internalData data translated by `createInternalData` method from source data, can be used in filter rule\n * @return {Boolean}\n */\nfunction filterSourceMessage(sourceMessage, message, internalData) {\n return true;\n}\n",
+ "'use strict';\n\nvar MessengerAPI = require('./m_api')\n , _ = require('mol-proto');\n\n\n/**\n * A generic subsclass of [MessengerAPI](./m_api.js.html) that supports pattern subscriptions to source.\n * Can be useful if the source is another Messenger.\n */\n var MessengerRegexpAPI = _.createSubclass(MessengerAPI, 'MessengerRegexpAPI');\n\n module.exports = MessengerRegexpAPI;\n\n\n_.extendProto(MessengerRegexpAPI, {\n init: init,\n addInternalMessage: addInternalMessage,\n removeInternalMessage: removeInternalMessage,\n getInternalMessages: getInternalMessages\n});\n\n\n/**\n * MessengerRegexpAPI instance method\n * Called by MessengerRegexpAPI constructor.\n */\nfunction init() {\n MessengerAPI.prototype.init.apply(this, arguments);\n _.defineProperties(this, {\n _patternInternalMessages: {}\n });\n this._catchAllSubscribed = false;\n}\n\n\n/**\n * MessengerRegexpAPI instance method\n * Augments MessengerAPI method by storing regexp\n *\n * @param {String} message internal message to be translated and added\n * @return {String|RegExp|undefined}\n */\nfunction addInternalMessage(message) {\n var sourceMessage = MessengerAPI.prototype.addInternalMessage.apply(this, arguments);\n \n // store regexp itself if sourceMessage is regexp\n if (sourceMessage && sourceMessage instanceof RegExp) {\n this._internalMessages[sourceMessage].pattern = sourceMessage;\n this._patternInternalMessages[sourceMessage] = this._internalMessages[sourceMessage];\n if (this._catchAllSubscribed) return;\n this._catchAllSubscribed = true;\n return /.*/;\n }\n\n return sourceMessage;\n}\n\n\n/**\n * MessengerRegexpAPI instance method\n * Augments MessengerAPI method by removing regexp subscirption\n * \n * @param {String} message internal message to be translated and added\n * @return {String|RegExp|undefined}\n */\nfunction removeInternalMessage(message) {\n var sourceMessage = MessengerAPI.prototype.removeInternalMessage.apply(this, arguments);\n\n if (sourceMessage && sourceMessage instanceof RegExp) {\n delete this._patternInternalMessages[sourceMessage];\n var noPatternInternalMessages = ! Object.keys(this._patternInternalMessages).length;\n if (noPatternInternalMessages) {\n this._catchAllSubscribed = false;\n return /.*/;\n }\n }\n\n return sourceMessage;\n}\n\n\n/**\n * MessengerAPI instance method\n * Augments MessengerAPI method by returning messages subscribed with regexp\n * This method is used by `MessageSource` to dispatch source message on the `Mesenger`.\n *\n * @param {String|RegExp} sourceMessage source message\n * @return {Array[String]}\n */\nfunction getInternalMessages(sourceMessage) {\n var internalMessages = MessengerAPI.prototype.getInternalMessages.apply(this, arguments);\n\n // add internal messages for regexp source subscriptions\n if (typeof sourceMessage == 'string') {\n internalMessages = internalMessages || [];\n var internalMessagesHash = _.object(internalMessages, true);\n\n _.eachKey(this._patternInternalMessages, function(patternMessages) {\n var sourcePattern = patternMessages.pattern;\n\n if (sourcePattern.test(sourceMessage))\n patternMessages.forEach(function(message) {\n if (internalMessagesHash[message]) return;\n internalMessages.push(message);\n internalMessagesHash[message] = true;\n });\n });\n } \n\n return internalMessages;\n}\n",
"'use strict';\n\nvar Mixin = require('../abstract/mixin')\n , MessengerAPI = require('./m_api')\n , logger = require('../util/logger')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match;\n\n\n/**\n * `milo.classes.MessageSource`\n * An abstract class (subclass of [Mixin](../abstract/mixin.js.html)) for connecting [Messenger](./index.js.html) to external sources of messages (like DOM events) and defining higher level messages.\n * An instance of MessageSource can either be passed to Messenger constructor or later using `_setMessageSource` method of Messenger. Once set, MessageSource of Messenger cannot be changed.\n */\nvar MessageSource = _.createSubclass(Mixin, 'MessageSource', true);\n\nmodule.exports = MessageSource;\n\n\n/**\n * ####MessageSource instance methods####\n *\n * - [init](#init) - initializes messageSource - called by Mixin superclass\n * - [setMessenger](#setMessenger) - connects Messenger to MessageSource, is called from `init` or `_setMessageSource` methods of [Messenger](./index.js.html).\n * - [onSubscriberAdded](#onSubscriberAdded) - called by Messenger to notify when the first subscriber for an internal message was added, so MessageSource can subscribe to source\n * - [onSubscriberRemoved](#onSubscriberRemoved) - called by Messenger to notify when the last subscriber for an internal message was removed, so MessageSource can unsubscribe from source\n * - [dispatchMessage](#dispatchMessage) - dispatches source message. MessageSource subclass should implement mechanism when on actual source message this method is called.\n *\n * Methods below should be implemented in subclass:\n *\n * - [trigger](#trigger) - triggers messages on the source (an optional method)\n * - [addSourceSubscriber](#addSourceSubscriber) - adds listener/subscriber to external message\n * - [removeSourceSubscriber](#removeSourceSubscriber) - removes listener/subscriber from external message\n */\n_.extendProto(MessageSource, {\n init: init,\n destroy: MessageSource$destroy,\n setMessenger: setMessenger,\n onSubscriberAdded: onSubscriberAdded,\n onSubscriberRemoved: onSubscriberRemoved, \n dispatchMessage: dispatchMessage,\n postMessage: postMessage,\n _prepareMessengerAPI: _prepareMessengerAPI,\n\n // Methods below must be implemented in subclass\n trigger: toBeImplemented,\n addSourceSubscriber: toBeImplemented,\n removeSourceSubscriber: toBeImplemented\n});\n\n\n/**\n * MessageSource instance method.\n * Called by Mixin constructor.\n * MessageSource constructor should be passed the same parameters as this method signature.\n * If an instance of [MessengerAPI](./m_api.js.html) is passed as the third parameter, it extends MessageSource functionality to allow it to define new messages, to filter messages based on their data and to change message data. See [MessengerAPI](./m_api.js.html).\n *\n * @param {Object} hostObject Optional object that stores the MessageSource on one of its properties. It is used to proxy methods of MessageSource.\n * @param {Object[String]} proxyMethods Optional map of method names; key - proxy method name, value - MessageSource's method name.\n * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI.\n */\nfunction init(hostObject, proxyMethods, messengerAPI) {\n this._prepareMessengerAPI(messengerAPI);\n}\n\n\n/**\n * Destroys message source\n */\nfunction MessageSource$destroy() {\n if (this.messengerAPI)\n this.messengerAPI.destroy();\n}\n\n\n/**\n * MessageSource instance method.\n * Sets reference to Messenger instance.\n *\n * @param {Messenger} messenger reference to Messenger instance linked to this MessageSource\n */\nfunction setMessenger(messenger) {\n _.defineProperty(this, 'messenger', messenger);\n}\n\n\n/**\n * MessageSource instance method.\n * Prepares [MessengerAPI](./m_api.js.html) passed to constructor by proxying its methods to itself or if MessengerAPI wasn't passed defines two methods to avoid checking their availability every time the message is dispatched.\n *\n * @private\n * @param {MessengerAPI} messengerAPI Optional instance of MessengerAPI\n */\nfunction _prepareMessengerAPI(messengerAPI) {\n check(messengerAPI, Match.Optional(MessengerAPI));\n\n if (! messengerAPI)\n messengerAPI = new MessengerAPI;\n\n _.defineProperty(this, 'messengerAPI', messengerAPI);\n}\n\n\n/**\n * MessageSource instance method.\n * Subscribes to external source using `addSourceSubscriber` method that should be implemented in subclass.\n * This method is called by [Messenger](./index.js.html) when the first subscriber to the `message` is added.\n * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.addInternalMessage` will return undefined if this `sourceMessage` was already subscribed to to prevent duplicate subscription.\n *\n * @param {String} message internal Messenger message that has to be subscribed to at the external source of messages.\n */\nfunction onSubscriberAdded(message) {\n var newSourceMessage = this.messengerAPI.addInternalMessage(message);\n if (typeof newSourceMessage != 'undefined')\n this.addSourceSubscriber(newSourceMessage);\n}\n\n\n/**\n * MessageSource instance method.\n * Unsubscribes from external source using `removeSourceSubscriber` method that should be implemented in subclass.\n * This method is called by [Messenger](./index.js.html) when the last subscriber to the `message` is removed.\n * Delegates to supplied or default [MessengerAPI](./m_api.js.html) for translation of `message` to `sourceMessage`. `MessageAPI.prototype.removeInternalMessage` will return undefined if this `sourceMessage` was not yet subscribed to to prevent unsubscription without previous subscription.\n *\n * @param {String} message internal Messenger message that has to be unsubscribed from at the external source of messages.\n */\nfunction onSubscriberRemoved(message) {\n var removedSourceMessage = this.messengerAPI.removeInternalMessage(message);\n if (typeof removedSourceMessage != 'undefined')\n this.removeSourceSubscriber(removedSourceMessage);\n}\n\n\n/**\n * MessageSource instance method.\n * Dispatches sourceMessage to Messenger.\n * Mechanism that calls this method when the source message is received should be implemented by subclass (see [DOMEventsSource](../components/msg_src/dom_events.js.html) for example).\n * Delegates to supplied or default [MessengerAPI](./m_api.js.html) to create internal message data (`createInternalData`) and to filter the message based on its data and/or message (`filterSourceMessage`).\n * Base MessengerAPI class implements these two methods in a trivial way (`createInternalData` simply returns external data, `filterSourceMessage` returns `true`), they are meant to be implemented by subclass.\n *\n * @param {String} sourceMessage source message received from external source\n * @param {Object} sourceData data received from external source\n */\nfunction dispatchMessage(sourceMessage, sourceData) {\n var api = this.messengerAPI\n , internalMessages = api.getInternalMessages(sourceMessage);\n\n if (internalMessages) \n internalMessages.forEach(function (message) {\n var internalData = api.createInternalData(sourceMessage, message, sourceData);\n\n var shouldDispatch = api.filterSourceMessage(sourceMessage, message, internalData);\n if (shouldDispatch) \n this.postMessage(message, internalData); \n \n }, this);\n}\n\n\n/**\n * Posts message on the messenger. This method is separated so specific message sources can make message dispatch synchronous by using `postMessageSync`\n * \n * @param {String} message\n * @param {Object} data\n */\nfunction postMessage(message, data) {\n this.messenger.postMessage(message, data);\n}\n\n\nfunction toBeImplemented() {\n throw new Error('calling the method of an absctract class');\n}\n",
- "arguments[4][71][0].apply(exports,arguments)",
- "'use strict';\n\nvar _ = require('mol-proto');\n\n\n/**\n * ####Milo packages####\n *\n * - [minder](./minder.js.html) - data reactivity, one or two way, shallow or deep, as you like it\n * - [config](./config.js.html) - milo configuration\n * - [util](./util/index.js.html) - logger, request, dom, check, error, etc.\n * - [classes](./classes.js.html) - abstract and base classes\n * - [Messenger](./messenger/index.js.html) - generic Messenger used in most other milo classes, can be mixed into app classes too.\n * - [Model](./model/index.js.html) - Model class that emits messages on changes to any depth without timer based watching\n */\nvar milo = {\n minder: require('./minder'),\n config: require('./config'),\n util: require('./util'),\n classes: require('./classes'),\n Messenger: require('./messenger'),\n Model: require('./model'),\n destroy: destroy\n};\n\n\n// export for node/browserify\nif (typeof module == 'object' && module.exports) \n module.exports = milo;\n\n// global milo for browser\nif (typeof window == 'object')\n window.milo = milo;\n\n\nfunction destroy() {\n milo.minder.destroy();\n}\n",
+ "'use strict';\n\n\nvar MessageSource = require('./m_source')\n , _ = require('mol-proto')\n , check = require('../util/check');\n\n\n/**\n * Subclass of MessageSource that allows to connect Messenger to another Messenger using it as external source.\n */\nvar MessengerMessageSource = _.createSubclass(MessageSource, 'MessengerMessageSource');\n\nmodule.exports = MessengerMessageSource;\n\n\n/**\n * ####MessengerMessageSource instance methods####\n */\n_.extendProto(MessengerMessageSource, {\n init: init,\n addSourceSubscriber: addSourceSubscriber,\n removeSourceSubscriber: removeSourceSubscriber,\n postMessage: MessengerMessageSource$postMessage\n});\n\n/**\n * Initializes MessengerMessageSource\n * Defines one parameter in addition to [MessageSource](./m_source.js.html) parameters\n *\n * @param {Messenger} sourceMessenger messenger this message source connects to\n */\nfunction init(hostObject, proxyMethods, messengerAPI, sourceMessenger) {\n MessageSource.prototype.init.apply(this, arguments);\n this.sourceMessenger = sourceMessenger;\n}\n\n\n/**\n * Subscribes to source message. See [MessageSource](./m_source.js.html) docs.\n *\n * @param {String|Regex} sourceMessage source message to subscribe to\n */\nfunction addSourceSubscriber(sourceMessage) {\n this.sourceMessenger.onSync(sourceMessage, { context: this, subscriber: this.dispatchMessage });\n}\n\n\n/**\n * Unsubscribes from source message. See [MessageSource](./m_source.js.html) docs.\n *\n * @param {String|Regex} sourceMessage source message to unsubscribe from\n */\nfunction removeSourceSubscriber(sourceMessage) {\n this.sourceMessenger.off(sourceMessage, { context: this, subscriber: this.dispatchMessage });\n}\n\n\n/**\n * Overrides defalut message source to dispatch messages synchronously\n * \n * @param {String} message\n * @param {Object} data\n */\nfunction MessengerMessageSource$postMessage(message, data) {\n this.messenger.postMessageSync(message, data);\n}\n",
+ "'use strict';\n\nvar _ = require('mol-proto');\n\n\n/**\n * ####Milo packages####\n *\n * - [minder](./minder.js.html) - data reactivity, one or two way, shallow or deep, as you like it\n * - [config](./config.js.html) - milo configuration\n * - [util](./util/index.js.html) - logger, request, dom, check, error, etc.\n * - [classes](./classes.js.html) - abstract and base classes\n * - [Messenger](./messenger/index.js.html) - generic Messenger used in most other milo classes, can be mixed into app classes too.\n * - [Model](./model/index.js.html) - Model class that emits messages on changes to any depth without timer based watching\n */\nvar milo = {\n minder: require('./minder'),\n config: require('./config'),\n util: require('./util'),\n classes: require('./classes'),\n Messenger: require('./messenger'),\n Model: require('./model'),\n destroy: destroy,\n proto: _\n};\n\n\n// export for node/browserify\nif (typeof module == 'object' && module.exports) \n module.exports = milo;\n\n// global milo for browser\nif (typeof window == 'object')\n window.milo = milo;\n\n\nfunction destroy() {\n milo.minder.destroy();\n}\n",
"'use strict';\n\nvar Connector = require('./model/connector')\n , Messenger = require('./messenger')\n , _ = require('mol-proto')\n , logger = require('./util/logger');\n\n\nmodule.exports = minder;\n\n\n/**\n * This function creates one or many Connector objects that\n * create live reactive connection between objects implementing\n * dataSource interface:\n * Objects should emit messages when any part of their data changes,\n * methods `on` and `off` should be implemented to subscribe/unsubscribe\n * to change notification messages, methods `set` and `get` should be implemented to get/set data\n * on path objects, pointing to particular parts of the object, method `path`\n * should return path object for a given path string (see path utils for path string syntax).\n * Both Model and Data facet are such data sources, they can be linked by Connector object.\n *\n * @param {Object} ds1 the first data source. Instead of the first data source an array can be passed with arrays of Connection objects parameters in each array element.\n * @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.\n * @param {Object} ds2 the second data source\n * @param {Object} options not implemented yet\n */\nfunction minder(ds1, mode, ds2, options) {\n if (Array.isArray(ds1)) {\n var connDescriptions = ds1;\n var connectors = connDescriptions.map(function(descr) {\n return new Connector(descr[0], descr[1], descr[2], descr[3]);\n });\n connectors.forEach(_addConnector);\n return connectors;\n } else {\n var cnct = new Connector(ds1, mode, ds2, options);\n _addConnector(cnct);\n return cnct;\n }\n}\n\n\n/**\n * messenger of minder where it emits events related to all connectors\n * @type {Messenger}\n */\nvar _messenger = new Messenger(minder, Messenger.defaultMethods);\n\n\nvar _connectors = []\n , _receivedMessages = []\n , _isPropagating = false;\n\n\n_.extend(minder, {\n getConnectors: minder_getConnectors,\n getExpandedConnections: minder_getExpandedConnections,\n isPropagating: minder_isPropagating,\n whenPropagationCompleted: minder_whenPropagationCompleted,\n destroyConnector: minder_destroyConnector,\n destroy: minder_destroy\n});\n\n\nfunction _addConnector(cnct) {\n cnct.___minder_id = _connectors.push(cnct) - 1;\n cnct.on(/.*/, onConnectorMessage);\n minder.postMessage('added', { connector: cnct });\n minder.postMessage('turnedon', { connector: cnct });\n}\n\n\nfunction onConnectorMessage(msg, data) {\n var data = data ? _.clone(data) : {};\n _.extend(data, {\n id: this.___minder_id,\n connector: this\n });\n minder.postMessage(msg, data);\n if (! _receivedMessages.length && ! _isPropagating) {\n _.defer(_idleCheck);\n _isPropagating = true;\n }\n\n _receivedMessages.push({ msg: msg, data: data });\n}\n\n\nfunction _idleCheck() {\n if (_receivedMessages.length) {\n _receivedMessages.length = 0;\n _.defer(_idleCheck);\n minder.postMessage('propagationticked');\n } else {\n _isPropagating = false;\n minder.postMessage('propagationcompleted');\n }\n}\n\n\nfunction minder_isPropagating() {\n return _isPropagating;\n}\n\n\nfunction minder_whenPropagationCompleted(callback) {\n if (_isPropagating)\n minder.once('propagationcompleted', executeCallback);\n else\n _.defer(executeCallback);\n\n function executeCallback() {\n if (_isPropagating)\n minder.once('propagationcompleted', executeCallback);\n else\n callback();\n }\n}\n\n\nfunction minder_getConnectors(onOff) {\n if (typeof onOff == 'undefined')\n return _connectors;\n\n return _connectors.filter(function(cnct) {\n return cnct.isOn === onOff;\n });\n}\n\n\nfunction minder_destroyConnector(cnct) {\n cnct.destroy();\n var index = _connectors.indexOf(cnct);\n if (index >= 0)\n delete _connectors[index];\n else\n logger.warn('minder: connector destroyed that is not registered in minder');\n}\n\n\nfunction minder_getExpandedConnections(onOff, searchStr) {\n var connectors = minder.getConnectors(onOff);\n var connections = connectors.map(function(cnct) {\n var connection = {\n leftSource: _getExpandedSource(cnct.ds1),\n rightSource: _getExpandedSource(cnct.ds2),\n mode: cnct.mode,\n isOn: cnct.isOn\n };\n \n if (cnct.options)\n connection.options = cnct.options;\n\n return connection;\n });\n\n if (searchStr)\n connections = connections.filter(function(cnctn) {\n return _sourceMatchesString(cnctn.leftSource, searchStr)\n || _sourceMatchesString(cnctn.rightSource, searchStr);\n });\n\n return connections;\n}\n\n\nfunction _getExpandedSource(ds) {\n var source = [];\n if (typeof ds == 'function') {\n if (ds._model && ds._accessPath) {\n source.unshift(ds._accessPath);\n ds = ds._model;\n }\n\n source.unshift(ds);\n ds = ds._hostObject;\n }\n\n if (typeof ds == 'object') {\n source.unshift(ds);\n\n if (ds.owner)\n source.unshift(ds.owner);\n }\n\n return source;\n}\n\n\nfunction _sourceMatchesString(source, matchStr) {\n return source.some(function(srcNode) {\n var className = srcNode.constructor && srcNode.constructor.name;\n return _stringMatch(className, matchStr)\n || _stringMatch(srcNode.name, matchStr)\n || _stringMatch(srcNode, matchStr);\n });\n}\n\n\nfunction _stringMatch(str, substr) {\n return str && typeof str == 'string' && str.indexOf(substr) >= 0;\n}\n\n\nfunction minder_destroy() {\n _connectors.forEach(function(cnct) {\n destroyDS(cnct.ds1);\n destroyDS(cnct.ds2);\n cnct.destroy();\n });\n _messenger.destroy();\n minder._destroyed = true;\n\n function destroyDS(ds) {\n if (ds && !ds._destroyed) ds.destroy();\n }\n}\n",
"'use strict';\n\n\nvar logger = require('../util/logger')\n , config = require('../config')\n , pathUtils = require('./path_utils')\n , _ = require('mol-proto');\n\n/**\n * Utility function to process \"changedata\" messages emitted by Connector object.\n */\nmodule.exports = changeDataHandler;\n\n\n_.extend(changeDataHandler, {\n setTransactionFlag: setTransactionFlag,\n getTransactionFlag: getTransactionFlag,\n passTransactionFlag: passTransactionFlag,\n postTransactionFinished: postTransactionFinished\n});\n\n\n/**\n * Change data uses hidden property on accessor methods to pass flag that the accessor is executed as a part of change transaction.\n * Accessor methods are supposed to store this flag in a local variable and to clear it (because another accessor can be executed in or out of transaction) using `getTransactionFlag`\n *\n * @private\n * @param {Function} func accessor method reference\n * @param {Boolean} flag a flag to be set\n */\nfunction setTransactionFlag(func, flag) {\n _.defineProperty(func, '__inChangeTransaction', flag, _.CONF | _.WRIT);\n}\n\n\n/**\n * Retrieves and clears transaction flag from accessor method\n *\n * @private\n * @param {Function} func accessor method reference\n * @return {Boolean}\n */\nfunction getTransactionFlag(func) {\n var inTransaction = func.__inChangeTransaction;\n delete func.__inChangeTransaction;\n return inTransaction;\n}\n\n\nfunction passTransactionFlag(fromFunc, toFunc) {\n var inTransaction = getTransactionFlag(fromFunc);\n setTransactionFlag(toFunc, inTransaction);\n return inTransaction;\n}\n\n\n/**\n * Posts message on this to indicate the end of transaction unless `inChangeTransaction` is `true`.\n */\nfunction postTransactionFinished() {\n this.postMessageSync('datachanges', { transaction: false, changes: [] });\n}\n\n\n/**\n * subscriber to \"changedata\" event emitted by [Connector](./connector.js.html) object to enable reactive connections\n * Used by Data facet, Model and ModelPath. Can be used by any object that implements get/set/del/splice api and sets data deeply to the whole tree.\n * Object should call `changeDataHandler.initialize.call(this)` in its constructor.\n * TODO: optimize messages list to avoid setting duplicate values down the tree\n *\n * @param {String} msg should be \"changedata\" here\n * @param {Object} data batch of data change desciption objects\n * @param {Function} callback callback to call before and after the data is processed\n */\nfunction changeDataHandler(message, data, callback) {\n processChanges.call(this, data.changes, callback);\n}\n\n\n// map of message types to methods\nvar CHANGE_TYPE_TO_METHOD_MAP = {\n 'added': 'set',\n 'changed': 'set',\n 'deleted': 'del',\n 'removed': 'del'\n};\n\n\n/**\n * Processes queued \"changedata\" messages.\n * Posts \"changestarted\" and \"changecompleted\" messages and calls callback\n *\n * @param {[Function]} callback optional callback that is called with `(null, false)` parameters before change processing starts and `(null, true)` after it's finished.\n */\nfunction processChanges(transaction, callback) {\n notify.call(this, callback, false);\n processTransaction.call(this,\n prepareTransaction(\n validateTransaction(transaction)));\n notify.call(this, callback, true);\n}\n\n\nfunction notify(callback, changeFinished) {\n callback && callback(null, changeFinished);\n this.postMessage(changeFinished ? 'changecompleted' : 'changestarted');\n}\n\n\n/**\n * Checks that all messages from the transaction come from the same source.\n * Hack: reverses the transaction if it comes from the Data facet\n * Returns the reference to the transaction (for chaining)\n * \n * @param {Array} transaction transaction of data changes\n * @return {Array} \n */\nfunction validateTransaction(transaction) {\n var source = transaction[0].source\n , sameSource = true;\n\n if (transaction.length > 1) {\n for (var i = 1, len = transaction.length; i < len; i++)\n if (transaction[i].source != source) {\n logger.error('changedata: changes from different sources in the same transaction, sources:', transaction[i].source.name, source.name);\n sameSource = false;\n source = transaction[i].source;\n }\n }\n\n return transaction;\n}\n\n\nfunction prepareTransaction(transaction) {\n var todo = []\n , pathsToSplice = []\n , pathsToChange = []\n , hadSplice\n , exitLoop = {};\n\n\n try { transaction.forEach(checkChange); }\n catch (e) { if (e != exitLoop) throw e; }\n\n return todo;\n\n\n function checkChange(data) {\n (data.type == 'splice' ? checkSplice : checkMethod)(data);\n }\n\n\n function checkSplice(data) {\n var parsedPath = pathUtils.parseAccessPath(data.path);\n var parentPathChanged = pathsToChange.some(function(parentPath) {\n if (parsedPath.length < parentPath.length) return;\n return _pathIsParentOf(parentPath, parsedPath);\n });\n\n if (parentPathChanged) return;\n\n todo.push(data);\n\n if (! config.debug) throw exitLoop;\n pathsToSplice.push(parsedPath);\n hadSplice = true;\n }\n\n\n function checkMethod(data) {\n var parsedPath = pathUtils.parseAccessPath(data.path);\n var parentPathSpliced = pathsToSplice && pathsToSplice.some(function(parentPath) {\n if (parsedPath.length <= parentPath.length\n || parsedPath[parentPath.length].syntax != 'array') return;\n return _pathIsParentOf(parentPath, parsedPath);\n });\n\n if (parentPathSpliced) return;\n if (hadSplice) logger.error('changedata: child change is executed after splice; probably data source did not emit message with data.type==\"finished\"');\n\n var parentPathChanged = pathsToChange.some(function(parentPath) {\n if (parsedPath.length <= parentPath.length) return;\n return _pathIsParentOf(parentPath, parsedPath);\n });\n\n if (parentPathChanged) return;\n\n pathsToChange.push(parsedPath);\n\n todo.push(data);\n }\n\n\n function _pathIsParentOf(parentPath, childPath) {\n return parentPath.every(function(pathNode, index) {\n return pathNode.property == childPath[index].property;\n });\n }\n}\n\n\nfunction processTransaction(transaction) {\n transaction.forEach(processChange, this);\n postTransactionFinished.call(this, false);\n\n function processChange(data) {\n var modelPath = this.path(data.path, data.type != 'removed' && data.type != 'deleted');\n if (! modelPath) return;\n (data.type == 'splice' ? executeSplice : executeMethod)(modelPath, data);\n }\n}\n\n\nfunction executeSplice(modelPath, data) {\n var index = data.index\n , howMany = data.removed.length\n , spliceArgs = [index, howMany];\n\n spliceArgs = spliceArgs.concat(data.newValue.slice(index, index + data.addedCount));\n setTransactionFlag(modelPath.splice, true);\n modelPath.splice.apply(modelPath, spliceArgs);\n}\n\n\nfunction executeMethod(modelPath, data) {\n var methodName = CHANGE_TYPE_TO_METHOD_MAP[data.type];\n if (methodName) {\n setTransactionFlag(modelPath[methodName], true);\n modelPath[methodName](data.newValue);\n } else\n logger.error('unknown data change type');\n}\n",
"'use strict';\n\nvar Messenger = require('../messenger')\n , pathUtils = require('./path_utils')\n , _ = require('mol-proto')\n , logger = require('../util/logger');\n\n\nmodule.exports = Connector;\n\n\nvar modePattern = /^(\\<*)\\-+(\\>*)$/;\n\n\n/**\n * Connector\n * Class that creates connector object for data connection between\n * two data-sources\n * Data-sources should implement the following API:\n * get() - get value from datasource or its path\n * set(value) - set value to datasource or to its path\n * on(path, subscriber) - subscription to data changes with \"*\" support\n * off(path, subscriber)\n * path(accessPath) - to return the object that gives reference to some part of datasource\n * and complies with that api too.\n *\n * ####Events####\n *\n * - 'turnedon' - connector was turned on\n * - 'turnedoff' - connector was turned off\n * - 'changestarted' - change on connected datasource is started\n * - 'changecompleted' - change on connected datasource is completed\n * - 'destroyed' - connector was destroyed\n * \n * @param {Object} ds1 the first data source.\n * @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.\n * @param {Object} ds2 the second data source\n * @param {Object} options not implemented yet\n * @return {Connector} when called with `new`, creates a Connector object.\n */\nfunction Connector(ds1, mode, ds2, options) {\n setupMode.call(this, mode);\n\n _.extend(this, {\n ds1: ds1,\n ds2: ds2,\n isOn: false,\n _changesQueue1: [],\n _changesQueue2: [],\n _messenger: new Messenger(this, Messenger.defaultMethods)\n });\n\n if (options) {\n this.options = options;\n\n var pathTranslation = options.pathTranslation;\n if (pathTranslation) {\n pathTranslation = _.clone(pathTranslation);\n var patternTranslation = getPatternTranslations(pathTranslation);\n _.extend(this, {\n pathTranslation1: reverseTranslationRules(pathTranslation),\n pathTranslation2: pathTranslation,\n patternTranslation1: reversePatternTranslationRules(patternTranslation),\n patternTranslation2: patternTranslation\n });\n }\n\n var dataTranslation = options.dataTranslation;\n if (dataTranslation) {\n _.extend(this, {\n dataTranslation1: dataTranslation['<-'],\n dataTranslation2: dataTranslation['->']\n });\n }\n\n var dataValidation = options.dataValidation;\n if (dataValidation) {\n _.extend(this, {\n dataValidation1: dataValidation['<-'],\n dataValidation2: dataValidation['->']\n });\n }\n }\n\n this.turnOn();\n}\n\n\nfunction setupMode(mode){\n var parsedMode = mode.match(modePattern);\n\n if (! parsedMode)\n modeParseError();\n\n var depth1 = parsedMode[1].length\n , depth2 = parsedMode[2].length;\n\n if (depth1 && depth2 && depth1 != depth2)\n modeParseError();\n\n if (! depth1 && ! depth2)\n modeParseError();\n\n _.extend(this, {\n mode: mode,\n depth1: depth1,\n depth2: depth2,\n });\n\n function modeParseError() {\n throw new Error('invalid Connector mode: ' + mode);\n }\n}\n\n\n_.extendProto(Connector, {\n turnOn: Connector$turnOn,\n turnOff: Connector$turnOff,\n destroy: Connector$destroy,\n changeMode: Connector$changeMode,\n deferChangeMode: Connector$deferChangeMode\n});\n\n/**\n * Function change the mode of the connection\n *\n * @param @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.\n * @return {Object[String]}\n */\nfunction Connector$changeMode(mode) {\n this.turnOff();\n setupMode.call(this, mode);\n this.turnOn();\n return this;\n}\n\n\n/**\n * Function change the mode of the connection\n *\n * @param @param {String} mode the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc.\n * @return {Object[String]}\n */\nfunction Connector$deferChangeMode(mode) {\n _.deferMethod(this, 'changeMode', mode);\n return this;\n}\n\n\n/**\n * Function that reverses translation rules for paths of connected odata sources\n *\n * @param {Object[String]} rules map of paths defining the translation rules\n * @return {Object[String]}\n */\nfunction reverseTranslationRules(rules) {\n var reverseRules = {};\n _.eachKey(rules, function(path2_value, path1_key) {\n reverseRules[path2_value] = path1_key;\n });\n return reverseRules;\n}\n\n\nfunction getPatternTranslations(pathTranslation) {\n var patternTranslation = [];\n _.eachKey(pathTranslation, function(path2_value, path1_key) {\n var starIndex1 = path1_key.indexOf('*')\n , starIndex2 = path2_value.indexOf('*');\n if (starIndex1 >= 0 && starIndex2 >= 0) { // pattern translation\n if (path1_key.slice(starIndex1) != path2_value.slice(starIndex2))\n _throwInvalidTranslation(path1_key, path2_value);\n delete pathTranslation[path1_key]; \n\n patternTranslation.push({\n fromPattern: pathUtils.createRegexPath(path1_key),\n fromStaticPath: _getStaticPath(path1_key, starIndex1),\n toPattern: pathUtils.createRegexPath(path2_value),\n toStaticPath: _getStaticPath(path2_value, starIndex2)\n });\n } else if (starIndex1 >= 0 || starIndex2 >= 0) // pattern only on one side of translation\n _throwInvalidTranslation(path1_key, path2_value);\n });\n\n return patternTranslation;\n\n\n function _throwInvalidTranslation(path1, path2) {\n throw new Error('Invalid pattern translation: ' + path1 + ', ' + path2);\n }\n\n\n function _getStaticPath(path, starIndex) {\n return path.replace(/[\\.\\[]?\\*.*$/, '');\n }\n}\n\n\nfunction reversePatternTranslationRules(patternTranslation) {\n return patternTranslation.map(function(pt) {\n return {\n fromPattern: pt.toPattern,\n fromStaticPath: pt.toStaticPath,\n toPattern: pt.fromPattern,\n toStaticPath: pt.fromStaticPath\n };\n });\n}\n\n\n/**\n * turnOn\n * Method of Connector that enables connection (if it was previously disabled)\n */\nfunction Connector$turnOn() {\n if (this.isOn)\n return logger.warn('data sources are already connected');\n\n var subscriptionPath = this._subscriptionPath =\n new Array(this.depth1 || this.depth2).join('*');\n\n var subscriptionPattern = pathUtils.createRegexPath(subscriptionPath);\n\n var self = this;\n if (this.depth1)\n this._link1 = linkDataSource('_link2', this.ds2, this.ds1, this._changesQueue1, this.pathTranslation1, this.patternTranslation1, this.dataTranslation1, this.dataValidation1);\n if (this.depth2)\n this._link2 = linkDataSource('_link1', this.ds1, this.ds2, this._changesQueue2, this.pathTranslation2, this.patternTranslation2, this.dataTranslation2, this.dataValidation2);\n\n this.isOn = true;\n this.postMessage('turnedon');\n\n\n function linkDataSource(reverseLink, fromDS, toDS, changesQueue, pathTranslation, patternTranslation, dataTranslation, dataValidation) {\n fromDS.onSync('datachanges', onData);\n return onData;\n\n function onData(message, batch) {\n var sendData = {\n changes: [],\n transaction: batch.transaction\n }\n\n batch.changes.forEach(function(change) {\n var sourcePath = change.path\n , targetPath = translatePath(sourcePath);\n\n if (typeof targetPath == 'undefined') return;\n\n var change = _.clone(change);\n _.extend(change, {\n source: fromDS,\n path: targetPath\n });\n\n translateData(sourcePath, change);\n validateData(sourcePath, change);\n });\n\n if (! changesQueue.length)\n _.defer(postChangeData);\n\n changesQueue.push(sendData);\n\n\n function translatePath(sourcePath) {\n if (pathTranslation) {\n var translatedPath = pathTranslation[sourcePath];\n if (translatedPath) return translatedPath;\n if (!patternTranslation.length) return;\n var pt = _.find(patternTranslation, function(pTranslation) {\n return pTranslation.fromPattern.test(sourcePath);\n });\n if (!pt) return;\n var translatedPath = sourcePath.replace(pt.fromStaticPath, pt.toStaticPath);\n } else if (! ((subscriptionPattern instanceof RegExp\n && subscriptionPattern.test(sourcePath))\n || subscriptionPattern == sourcePath)) return;\n\n return translatedPath || sourcePath;\n }\n\n\n function translateData(sourcePath, change) {\n if (dataTranslation) {\n var translate = dataTranslation[sourcePath];\n if (translate && typeof translate == 'function') {\n change.oldValue = translate(change.oldValue);\n change.newValue = translate(change.newValue);\n }\n }\n }\n\n \n function validateData(sourcePath, change) {\n propagateData(change);\n\n if (dataValidation) {\n var validators = dataValidation[sourcePath]\n , passedCount = 0\n , alreadyFailed = false;\n\n if (validators)\n validators.forEach(callValidator); \n }\n\n\n function callValidator(validator) {\n validator(change.newValue, function(err, response) {\n response.path = sourcePath;\n if (! alreadyFailed && (err || response.valid) && ++passedCount == validators.length) {\n fromDS.postMessage('validated', response);\n } else if (! response.valid) {\n alreadyFailed = true;\n fromDS.postMessage('validated', response);\n }\n });\n }\n }\n\n\n function propagateData(change) {\n sendData.changes.push(change);\n }\n\n\n function postChangeData() {\n // prevent endless loop of updates for 2-way connection\n if (self[reverseLink]) var callback = subscriptionSwitch;\n\n var transactions = mergeTransactions(changesQueue);\n changesQueue.length = 0;\n transactions.forEach(function(transaction) {\n // send data change instruction as message\n toDS.postMessageSync('changedata', { changes: transaction }, callback);\n });\n }\n\n\n function subscriptionSwitch(err, changeFinished) {\n if (err) return;\n var onOff = changeFinished ? 'onSync' : 'off';\n toDS[onOff]('datachanges', self[reverseLink]);\n\n var message = changeFinished ? 'changecompleted' : 'changestarted';\n self.postMessage(message, { source: fromDS, target: toDS });\n }\n\n\n function mergeTransactions(batches) {\n var transactions = []\n , currentTransaction;\n\n batches.forEach(function(batch) {\n if (! batch.transaction) currentTransaction = undefined;\n if (! batch.changes.length) return;\n\n if (batch.transaction) {\n if (currentTransaction)\n _.appendArray(currentTransaction, batch.changes);\n else {\n currentTransaction = _.clone(batch.changes);\n transactions.push(currentTransaction);\n }\n } else\n transactions.push(batch.changes);\n });\n\n return transactions;\n }\n }\n }\n}\n\n\n/**\n * turnOff\n * Method of Connector that disables connection (if it was previously enabled)\n */\nfunction Connector$turnOff() {\n if (! this.isOn)\n return logger.warn('data sources are already disconnected');\n\n var self = this;\n unlinkDataSource(this.ds1, '_link2', this.pathTranslation2);\n unlinkDataSource(this.ds2, '_link1', this.pathTranslation1);\n\n this.isOn = false;\n this.postMessage('turnedoff');\n\n\n function unlinkDataSource(fromDS, linkName, pathTranslation) {\n if (self[linkName]) {\n fromDS.off('datachanges', self[linkName]);\n delete self[linkName];\n }\n }\n}\n\n\n/**\n * Destroys connector object by turning it off and removing references to connected sources\n */\nfunction Connector$destroy() {\n this.turnOff();\n this.postMessage('destroyed');\n this._messenger.destroy();\n delete this.ds1;\n delete this.ds2;\n this._destroyed = true;\n}\n",
- "'use strict';\n\nvar ModelPath = require('./m_path')\n , synthesize = require('./synthesize')\n , pathUtils = require('./path_utils')\n , changeDataHandler = require('./change_data')\n , Messenger = require('../messenger')\n , MessengerMessageSource = require('../messenger/msngr_source')\n , ModelMsgAPI = require('./m_msg_api')\n , Mixin = require('../abstract/mixin')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match\n , logger = require('../util/logger');\n\n\nmodule.exports = Model;\n\n\n/**\n * `milo.Model`\n * Model class instantiates objects that allow deep data access with __safe getters__ that return undefined (rather than throwing exception) when properties/items of unexisting objects/arrays are requested and __safe setters__ that create object trees when properties/items of unexisting objects/arrays are set and also post messages to allow subscription on changes and enable data reactivity.\n * Reactivity is implememnted via [Connector](./connector.js.html) that can be instantiated either directly or with more convenient interface of [milo.minder](../minder.js.html). At the moment model can be connected to [Data facet](../components/c_facets/Data.js.html) or to another model or [ModelPath](./m_path.js.html).\n * Model constructor returns objects that are functions at the same time; when called they return ModelPath objects that allow get/set access to any point in model data. See [ModelData](#ModelData) below.\n *\n * You can subscribe to model changes with `on` method by passing model access path in place of message, pattern or string with any number of stars to subscribe to a certain depth in model (e.g., `'***'` to subscribe to three levels).\n *\n * @constructor\n * @param {Object|Array} data optional initial array data. If it is planned to connect model to view it is usually better to instantiate an empty Model (`var m = new Model`), connect it to [Component](../components/c_class.js.html)'s [Data facet](../components/c_facets/Data.js.html) (e.g., `milo.minder(m, '<<->>', c.data);`) and then set the model with `m.set(data)` - the view will be automatically updated.\n * @param {Object} hostObject optional object that hosts model on one of its properties. Can be used when model itself is the context of the message subscriber and you need to travers to this object (although it is possible to set any context). Can also be used to proxy model's methods to the host like [Model facet](../components/c_facets/ModelFacet.js.html) is doing.\n * @param {Object} options pass { reactive: false } to use model without messaging when it is not needed - it makes it much faster\n * @return {Model}\n */\nfunction Model(data, hostObject, options) {\n // `model` will be returned by constructor instead of `this`. `model`\n // (`modelPath` function) should return a ModelPath object with \"synthesized\" methods\n // to get/set model properties, to subscribe to property changes, etc.\n // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.\n var model = function modelPath(accessPath) { // , ... arguments that will be interpolated\n return Model$path.apply(model, arguments);\n };\n model.__proto__ = Model.prototype;\n\n model._hostObject = hostObject;\n model._options = options || {};\n\n if (model._options.reactive !== false) {\n model._prepareMessengers();\n // subscribe to \"changedata\" message to enable reactive connections\n model.onSync('changedata', changeDataHandler);\n }\n\n if (data) model._data = data;\n\n return model;\n}\n\nModel.prototype.__proto__ = Model.__proto__;\n\n\n/**\n * ####Model instance methods####\n *\n * - [path](#path) - returns ModelPath object that allows access to any point in Model\n * - [get](#Model$get) - get model data\n * - set - set model data, synthesized\n * - splice - splice model data (as array or pseudo-array), synthesized\n * - [len](./m_path.js.html#ModelPath$len) - returns length of array (or pseudo-array) in model in safe way, 0 if no length is set\n * - [push](./m_path.js.html#ModelPath$push) - add items to the end of array (or pseudo-array) in model\n * - [pop](./m_path.js.html#ModelPath$pop) - remove item from the end of array (or pseudo-array) in model\n * - [unshift](./m_path.js.html#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in model\n * - [shift](./m_path.js.html#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in model\n * - [proxyMessenger](#proxyMessenger) - proxy model's Messenger methods to host object\n * - [proxyMethods](#proxyMethods) - proxy model methods to host object\n */\n_.extendProto(Model, {\n path: Model$path,\n get: Model$get,\n proxyMessenger: proxyMessenger, // deprecated, should not be used\n proxyMethods: proxyMethods,\n _prepareMessengers: _prepareMessengers,\n _getHostObject: _getHostObject,\n destroy: Model$destroy\n});\n\n// set, del, splice are added to model\n_.extendProto(Model, synthesize.modelMethods);\n\n\n/**\n * - Path: ModelPath class as `milo.Model.Path`\n */\n_.extend(Model, {\n Path: ModelPath,\n useWith: Model$$useWith\n});\n\n\n/**\n * Expose Messenger methods on Facet prototype\n */\nvar MESSENGER_PROPERTY = '_messenger';\nMessenger.useWith(Model, MESSENGER_PROPERTY, Messenger.defaultMethods);\n\n\n/**\n * ModelPath methods added to Model prototype\n */\n['len', 'push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {\n var method = ModelPath.prototype[methodName];\n _.defineProperty(Model.prototype, methodName, method);\n});\n\n\n/**\n * Model instance method.\n * Get model data.\n *\n * @return {Any}\n */\nfunction Model$get() {\n return this._data;\n}\n\n\n/**\n * Model instance method.\n * Returns ModelPath object that implements the same API as model but allows access to any point inside model as defined by `accessPath`.\n * See [ModelPath](./m_path.js.html) class for more information.\n *\n * @param {String} accessPath string that defines path to access model.\n * Path string consists of parts to define either property access (`\".name\"` to access property name) or array item access (`\"[1]\"` to access item with index 1).\n * Access path can contain as many parts as necessary (e.g. `\".list[0].name\"` to access property `name` in the first element of array stored in property `list`.\n * @param {List} arguments additional arguments of this method can be used to create interpolated paths.\n * E.g. `m.path(\"[$1].$2\", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m(\"[\" + id + \"].\" + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.\n * @return {ModelPath}\n */\nfunction Model$path(accessPath) { // , ... arguments that will be interpolated\n if (! accessPath) return this;\n\n // \"null\" is context to pass to ModelPath, first parameter of bind\n // \"this\" (model) is added in front of all arguments\n _.splice(arguments, 0, 0, null, this);\n\n // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...\n return new (Function.prototype.bind.apply(ModelPath, arguments));\n}\n\n\n/**\n * Model instance method.\n * Proxy model's Messenger methods to host object.\n *\n * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.\n */\nfunction proxyMessenger(modelHostObject) {\n modelHostObject = modelHostObject || this._hostObject;\n Mixin.prototype._createProxyMethods.call(this[MESSENGER_PROPERTY], Messenger.defaultMethods, modelHostObject);\n}\n\n\nvar modelMethodsToProxy = ['path', 'get', 'set', 'del', 'splice', 'len', 'push', 'pop', 'unshift', 'shift'];\n\n\n/**\n * Expose model methods on\n * See same method in Mixin class for parameters meaning\n *\n * @param {Function} hostClass\n * @param {[type]} instanceKey\n * @param {[type]} mixinMethods optional\n */\nfunction Model$$useWith(hostClass, instanceKey, mixinMethods) {\n mixinMethods = mixinMethods || modelMethodsToProxy;\n Mixin.useWith.call(Model, hostClass, instanceKey, mixinMethods);\n}\n\n\n/**\n * Model instance method.\n * Proxy model methods to host object.\n *\n * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.\n */\nfunction proxyMethods(modelHostObject) {\n modelHostObject = modelHostObject || this._hostObject;\n Mixin.prototype._createProxyMethods.call(this, modelMethodsToProxy, modelHostObject);\n}\n\n\n/**\n * Model instance method.\n * Create and connect internal and external model's messengers.\n * External messenger's methods are proxied on the model and they allows \"*\" subscriptions.\n */\nfunction _prepareMessengers() {\n // model will post all its changes on internal messenger\n var internalMessenger = new Messenger(this, undefined, undefined);\n\n // message source to connect internal messenger to external\n var internalMessengerSource = new MessengerMessageSource(this, undefined, new ModelMsgAPI, internalMessenger);\n\n // external messenger to which all model users will subscribe,\n // that will allow \"*\" subscriptions and support \"changedata\" message api.\n var externalMessenger = new Messenger(this, undefined, internalMessengerSource);\n\n _.defineProperty(this, MESSENGER_PROPERTY, externalMessenger);\n _.defineProperty(this, '_internalMessenger', internalMessenger);\n}\n\n\nfunction _getHostObject() {\n return this._hostObject;\n}\n\n\nfunction Model$destroy() {\n this[MESSENGER_PROPERTY].destroy();\n this._internalMessenger.destroy();\n this._destroyed = true;\n}\n",
- "arguments[4][75][0].apply(exports,arguments)",
- "arguments[4][76][0].apply(exports,arguments)",
- "arguments[4][78][0].apply(exports,arguments)",
+ "'use strict';\n\nvar ModelPath = require('./m_path')\n , synthesize = require('./synthesize')\n , pathUtils = require('./path_utils')\n , modelUtils = require('./model_utils')\n , changeDataHandler = require('./change_data')\n , Messenger = require('../messenger')\n , MessengerMessageSource = require('../messenger/msngr_source')\n , ModelMsgAPI = require('./m_msg_api')\n , Mixin = require('../abstract/mixin')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match\n , logger = require('../util/logger');\n\n\nmodule.exports = Model;\n\n\n/**\n * `milo.Model`\n * Model class instantiates objects that allow deep data access with __safe getters__ that return undefined (rather than throwing exception) when properties/items of unexisting objects/arrays are requested and __safe setters__ that create object trees when properties/items of unexisting objects/arrays are set and also post messages to allow subscription on changes and enable data reactivity.\n * Reactivity is implememnted via [Connector](./connector.js.html) that can be instantiated either directly or with more convenient interface of [milo.minder](../minder.js.html). At the moment model can be connected to [Data facet](../components/c_facets/Data.js.html) or to another model or [ModelPath](./m_path.js.html).\n * Model constructor returns objects that are functions at the same time; when called they return ModelPath objects that allow get/set access to any point in model data. See [ModelData](#ModelData) below.\n *\n * You can subscribe to model changes with `on` method by passing model access path in place of message, pattern or string with any number of stars to subscribe to a certain depth in model (e.g., `'***'` to subscribe to three levels).\n *\n * @constructor\n * @param {Object|Array} data optional initial array data. If it is planned to connect model to view it is usually better to instantiate an empty Model (`var m = new Model`), connect it to [Component](../components/c_class.js.html)'s [Data facet](../components/c_facets/Data.js.html) (e.g., `milo.minder(m, '<<->>', c.data);`) and then set the model with `m.set(data)` - the view will be automatically updated.\n * @param {Object} hostObject optional object that hosts model on one of its properties. Can be used when model itself is the context of the message subscriber and you need to travers to this object (although it is possible to set any context). Can also be used to proxy model's methods to the host like [Model facet](../components/c_facets/ModelFacet.js.html) is doing.\n * @param {Object} options pass { reactive: false } to use model without messaging when it is not needed - it makes it much faster\n * @return {Model}\n */\nfunction Model(data, hostObject, options) {\n // `model` will be returned by constructor instead of `this`. `model`\n // (`modelPath` function) should return a ModelPath object with \"synthesized\" methods\n // to get/set model properties, to subscribe to property changes, etc.\n // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.\n var model = function modelPath(accessPath) { // , ... arguments that will be interpolated\n return Model$path.apply(model, arguments);\n };\n model.__proto__ = Model.prototype;\n\n model._hostObject = hostObject;\n model._options = options || {};\n\n if (model._options.reactive !== false) {\n model._prepareMessengers();\n // subscribe to \"changedata\" message to enable reactive connections\n model.onSync('changedata', changeDataHandler);\n }\n\n if (data) model._data = data;\n\n return model;\n}\n\nModel.prototype.__proto__ = Model.__proto__;\n\n\n/**\n * ####Model instance methods####\n *\n * - [path](#path) - returns ModelPath object that allows access to any point in Model\n * - [get](#Model$get) - get model data\n * - set - set model data, synthesized\n * - splice - splice model data (as array or pseudo-array), synthesized\n * - [len](./m_path.js.html#ModelPath$len) - returns length of array (or pseudo-array) in model in safe way, 0 if no length is set\n * - [push](./m_path.js.html#ModelPath$push) - add items to the end of array (or pseudo-array) in model\n * - [pop](./m_path.js.html#ModelPath$pop) - remove item from the end of array (or pseudo-array) in model\n * - [unshift](./m_path.js.html#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in model\n * - [shift](./m_path.js.html#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in model\n * - [proxyMessenger](#proxyMessenger) - proxy model's Messenger methods to host object\n * - [proxyMethods](#proxyMethods) - proxy model methods to host object\n */\n_.extendProto(Model, {\n path: Model$path,\n get: Model$get,\n proxyMessenger: proxyMessenger, // deprecated, should not be used\n proxyMethods: proxyMethods,\n _prepareMessengers: _prepareMessengers,\n _getHostObject: _getHostObject,\n destroy: Model$destroy\n});\n\n// set, del, splice are added to model\n_.extendProto(Model, synthesize.modelMethods);\n\n\n/**\n * - Path: ModelPath class as `milo.Model.Path`\n */\n_.extend(Model, {\n Path: ModelPath,\n useWith: Model$$useWith,\n _utils: {\n path: pathUtils,\n model: modelUtils,\n changeDataHandler: changeDataHandler\n }\n});\n\n\n/**\n * Expose Messenger methods on Facet prototype\n */\nvar MESSENGER_PROPERTY = '_messenger';\nMessenger.useWith(Model, MESSENGER_PROPERTY, Messenger.defaultMethods);\n\n\n/**\n * ModelPath methods added to Model prototype\n */\n['len', 'push', 'pop', 'unshift', 'shift'].forEach(function(methodName) {\n var method = ModelPath.prototype[methodName];\n _.defineProperty(Model.prototype, methodName, method);\n});\n\n\n/**\n * Model instance method.\n * Get model data.\n *\n * @return {Any}\n */\nfunction Model$get() {\n return this._data;\n}\n\n\n/**\n * Model instance method.\n * Returns ModelPath object that implements the same API as model but allows access to any point inside model as defined by `accessPath`.\n * See [ModelPath](./m_path.js.html) class for more information.\n *\n * @param {String} accessPath string that defines path to access model.\n * Path string consists of parts to define either property access (`\".name\"` to access property name) or array item access (`\"[1]\"` to access item with index 1).\n * Access path can contain as many parts as necessary (e.g. `\".list[0].name\"` to access property `name` in the first element of array stored in property `list`.\n * @param {List} arguments additional arguments of this method can be used to create interpolated paths.\n * E.g. `m.path(\"[$1].$2\", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m(\"[\" + id + \"].\" + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.\n * @return {ModelPath}\n */\nfunction Model$path(accessPath) { // , ... arguments that will be interpolated\n if (! accessPath) return this;\n\n // \"null\" is context to pass to ModelPath, first parameter of bind\n // \"this\" (model) is added in front of all arguments\n _.splice(arguments, 0, 0, null, this);\n\n // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...\n return new (Function.prototype.bind.apply(ModelPath, arguments));\n}\n\n\n/**\n * Model instance method.\n * Proxy model's Messenger methods to host object.\n *\n * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.\n */\nfunction proxyMessenger(modelHostObject) {\n modelHostObject = modelHostObject || this._hostObject;\n Mixin.prototype._createProxyMethods.call(this[MESSENGER_PROPERTY], Messenger.defaultMethods, modelHostObject);\n}\n\n\nvar modelMethodsToProxy = ['path', 'get', 'set', 'del', 'splice', 'len', 'push', 'pop', 'unshift', 'shift'];\n\n\n/**\n * Expose model methods on\n * See same method in Mixin class for parameters meaning\n *\n * @param {Function} hostClass\n * @param {[type]} instanceKey\n * @param {[type]} mixinMethods optional\n */\nfunction Model$$useWith(hostClass, instanceKey, mixinMethods) {\n mixinMethods = mixinMethods || modelMethodsToProxy;\n Mixin.useWith.call(Model, hostClass, instanceKey, mixinMethods);\n}\n\n\n/**\n * Model instance method.\n * Proxy model methods to host object.\n *\n * @param {Object} modelHostObject optional host object. If not passed, hostObject passed to Model constructor will be used.\n */\nfunction proxyMethods(modelHostObject) {\n modelHostObject = modelHostObject || this._hostObject;\n Mixin.prototype._createProxyMethods.call(this, modelMethodsToProxy, modelHostObject);\n}\n\n\n/**\n * Model instance method.\n * Create and connect internal and external model's messengers.\n * External messenger's methods are proxied on the model and they allows \"*\" subscriptions.\n */\nfunction _prepareMessengers() {\n // model will post all its changes on internal messenger\n var internalMessenger = new Messenger(this, undefined, undefined);\n\n // message source to connect internal messenger to external\n var internalMessengerSource = new MessengerMessageSource(this, undefined, new ModelMsgAPI, internalMessenger);\n\n // external messenger to which all model users will subscribe,\n // that will allow \"*\" subscriptions and support \"changedata\" message api.\n var externalMessenger = new Messenger(this, undefined, internalMessengerSource);\n\n _.defineProperty(this, MESSENGER_PROPERTY, externalMessenger);\n _.defineProperty(this, '_internalMessenger', internalMessenger);\n}\n\n\nfunction _getHostObject() {\n return this._hostObject;\n}\n\n\nfunction Model$destroy() {\n this[MESSENGER_PROPERTY].destroy();\n this._internalMessenger.destroy();\n this._destroyed = true;\n}\n",
+ "'use strict';\n\nvar MessengerRegexpAPI = require('../messenger/m_api_rx')\n , pathUtils = require('./path_utils')\n , _ = require('mol-proto');\n\n\n/**\n * Subclass of MessengerRegexpAPI that is used to translate messages of external messenger of Model to internal messenger of Model.\n */\nvar ModelMsgAPI = _.createSubclass(MessengerRegexpAPI, 'ModelMsgAPI');\n\nmodule.exports = ModelMsgAPI;\n\n\n/**\n * ####ModelMsgAPI instance methods####\n *\n * - [translateToSourceMessage](#translateToSourceMessage) - translates subscription paths with \"*\"s to regex, leaving other strings untouched\n */\n_.extendProto(ModelMsgAPI, {\n translateToSourceMessage: translateToSourceMessage,\n});\n\n\n/**\n * ModelMsgAPI instance method\n * Translates subscription paths with \"*\"s to regex, leaving other strings untouched.\n *\n * @param {String} accessPath relative access path to be translated\n * @return {RegExp|String}\n */\nfunction translateToSourceMessage(accessPath) {\n if (accessPath instanceof RegExp) return accessPath;\n\n return pathUtils.createRegexPath(accessPath);\n}\n",
+ "'use strict';\n\nvar synthesize = require('./synthesize')\n , pathUtils = require('./path_utils')\n , changeDataHandler = require('./change_data')\n , Messenger = require('../messenger')\n , ModelPathMsgAPI = require('./path_msg_api')\n , MessengerMessageSource = require('../messenger/msngr_source')\n , _ = require('mol-proto')\n , check = require('../util/check')\n , Match = check.Match;\n\n\nmodule.exports = ModelPath;\n\n\n/**\n * `milo.Model.Path`\n * ModelPath object that allows access to any point inside [Model](./index.js.html) as defined by `accessPath`\n *\n * @constructor\n * @param {Model} model Model instance that ModelPath gives access to.\n * @param {String} accessPath string that defines path to access model.\n * Path string consists of parts to define either property access (`\".name\"` to access property name) or array item access (`\"[1]\"` to access item with index 1).\n * Access path can contain as many parts as necessary (e.g. `\".list[0].name\"` to access property `name` in the first element of array stored in property `list`.\n * @param {List} arguments additional arguments of this method can be used to create interpolated paths.\n * E.g. `m.path(\"[$1].$2\", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m(\"[\" + id + \"].\" + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.\n * @return {ModelPath}\n */\nfunction ModelPath(model, path) { // ,... - additional arguments for interpolation\n // check(model, Model);\n check(path, String);\n\n // `modelPath` will be returned by constructor instead of `this`. `modelPath`\n // (`modelPath_path` function) should also return a ModelPath object with \"synthesized\" methods\n // to get/set model properties, to subscribe to property changes, etc.\n // Additional arguments of modelPath can be used in the path using interpolation - see ModelPath below.\n var modelPath = function modelPath_path(accessPath) { // , ... arguments that will be interpolated\n return ModelPath$path.apply(modelPath, arguments);\n };\n modelPath.__proto__ = ModelPath.prototype;\n\n\n _.defineProperties(modelPath, {\n _model: model,\n _path: path,\n _args: _.slice(arguments, 1), // path will be the first element of this array\n _options: model._options\n });\n\n // parse access path\n var parsedPath = pathUtils.parseAccessPath(path);\n\n // compute access path string\n _.defineProperty(modelPath, '_accessPath', interpolateAccessPath(parsedPath, modelPath._args));\n\n if (modelPath._options.reactive !== false) {\n // messenger fails on \"*\" subscriptions\n modelPath._prepareMessenger();\n // subscribe to \"changedata\" message to enable reactive connections\n modelPath.onSync('changedata', changeDataHandler);\n }\n\n // compiling getter and setter\n var methods = synthesize(path, parsedPath);\n\n // adding methods to model path\n _.defineProperties(modelPath, methods);\n\n Object.freeze(modelPath);\n\n return modelPath;\n}\n\nModelPath.prototype.__proto__ = ModelPath.__proto__;\n\n\n/**\n * Interpolates path elements to compute real path\n *\n * @param {Array} parsedPath parsed path - array of path nodes\n * @param {Array} args path interpolation arguments, args[0] is path itself\n * @return {String}\n */\nfunction interpolateAccessPath(parsedPath, args) {\n return parsedPath.reduce(function(accessPathStr, currNode, index) {\n var interpolate = currNode.interpolate;\n return accessPathStr +\n (interpolate\n ? (currNode.syntax == 'array'\n ? '[' + args[interpolate] + ']'\n : '.' + args[interpolate])\n : currNode.property);\n }, '');\n}\n\n\n/**\n * ####ModelPath instance methods####\n *\n * - [path](#ModelPath$path) - gives access to path inside ModelPath\n * - get - synthesized\n * - set - synthesized\n * - splice - splice model data (as array or pseudo-array), synthesized\n * - [len](#ModelPath$len) - returns length of array (or pseudo-array) in safe way, 0 if no length is set\n * - [push](#ModelPath$push) - add items to the end of array (or pseudo-array) in ModelPath\n * - [pop](#ModelPath$pop) - remove item from the end of array (or pseudo-array) in ModelPath\n * - [unshift](#ModelPath$unshift) - add items to the beginning of array (or pseudo-array) in ModelPath\n * - [shift](#ModelPath$shift) - remove item from the beginning of array (or pseudo-array) in ModelPath\n */\n_.extendProto(ModelPath, {\n path: ModelPath$path,\n len: ModelPath$len,\n push: ModelPath$push,\n pop: ModelPath$pop,\n unshift: ModelPath$unshift,\n shift: ModelPath$shift,\n _prepareMessenger: _prepareMessenger,\n _getDefinition: _getDefinition,\n destroy: ModelPath$destroy\n});\n\n\n_.extend(ModelPath, {\n _createFromDefinition: _createFromDefinition\n})\n\n\n/**\n * Expose Messenger methods on Facet prototype\n */\nvar MESSENGER_PROPERTY = '_messenger';\nMessenger.useWith(ModelPath, MESSENGER_PROPERTY, Messenger.defaultMethods);\n\n\n/**\n * ModelPath instance method\n * Gives access to path inside ModelPath. Method works similarly to [path method](#Model$path) of model, using relative paths.\n *\n * @param {String} accessPath string that defines path to access model.\n * Path string consists of parts to define either property access (`\".name\"` to access property name) or array item access (`\"[1]\"` to access item with index 1).\n * Access path can contain as many parts as necessary (e.g. `\".list[0].name\"` to access property `name` in the first element of array stored in property `list`.\n * @param {List} arguments additional arguments of this method can be used to create interpolated paths.\n * E.g. `m.path(\"[$1].$2\", id, prop)` returns ModelPath to access property with name `prop` in array item with index `id`. Although this ModelPath object will work exactly as `m(\"[\" + id + \"].\" + prop)`, the interpolated is much more efficient as ModelPath with interpolation will not synthesize new getters and setters, while ModelPath with computed access path will synthesize new getters and setters for each pair of values of `id` and `prop`.\n * @return {ModelPath}\n */\nfunction ModelPath$path(accessPath) { // , ... arguments that will be interpolated\n if (! accessPath) return this;\n\n var thisPathArgsCount = this._args.length - 1;\n\n if (thisPathArgsCount > 0) {// this path has interpolated arguments too\n accessPath = accessPath.replace(/\\$[1-9][0-9]*/g, function(str) {\n return '$' + (+str.slice(1) + thisPathArgsCount);\n });\n }\n\n var newPath = this._path + accessPath;\n\n // this._model is added in front of all arguments as the first parameter\n // of ModelPath constructor\n var args = [this._model, newPath]\n .concat(this._args.slice(1)) // remove old path from _args, as it is 1 based\n .concat(_.slice(arguments, 1)); // add new interpolation arguments\n\n // calling ModelPath constructor with new and the list of arguments: this (model), accessPath, ...\n return _.newApply(ModelPath, args);\n}\n\n\n/**\n * ModelPath and Model instance method\n * Returns length property and sets it to 0 if it wasn't set.\n *\n * @return {Any}\n */\nfunction ModelPath$len() {\n return this.path('.length').get() || 0;\n}\n\n\n/**\n * ModelPath and Model instance method\n * Adds items to the end of array (or pseudo-array). Returns new length.\n *\n * @param {List} arguments list of items that will be added to array (pseudo array)\n * @return {Integer}\n */\nfunction ModelPath$push() { // arguments\n var length = this.len();\n var newLength = length + arguments.length;\n\n _.splice(arguments, 0, 0, length, 0);\n this.splice.apply(this, arguments);\n\n return newLength;\n}\n\n\n/**\n * ModelPath and Model instance method\n * Removes item from the end of array (or pseudo-array). Returns this item.\n *\n * @return {Any}\n */\nfunction ModelPath$pop() {\n return this.splice(this.len() - 1, 1)[0];\n}\n\n\n/**\n * ModelPath and Model instance method\n * Inserts items to the beginning of the array. Returns new length.\n *\n * @param {List} arguments items to be inserted in the beginning of array\n * @return {Integer}\n */\nfunction ModelPath$unshift() { // arguments\n var length = this.len();\n length += arguments.length;\n\n _.splice(arguments, 0, 0, 0, 0);\n this.splice.apply(this, arguments);\n\n return length;\n}\n\n\n/**\n * ModelPath and Model instance method\n * Removes the item from the beginning of array (or pseudo-array). Returns this item.\n *\n * @return {Any}\n */\nfunction ModelPath$shift() { // arguments\n return this.splice(0, 1)[0];\n}\n\n\n/**\n * ModelPath instance method\n * Initializes ModelPath mesenger with Model's messenger as its source ([MessengerMessageSource](../messenger/msngr_source.js.html)) and [ModelPathMsgAPI](./path_msg_api.js.html) as [MessengerAPI](../messenger/m_api.js.html)\n */\nfunction _prepareMessenger() {\n var mPathAPI = new ModelPathMsgAPI(this._accessPath);\n\n // create MessengerMessageSource connected to Model's messenger\n var modelMessageSource = new MessengerMessageSource(this, undefined, mPathAPI, this._model);\n\n // create messenger with model passed as hostObject (default message dispatch context)\n // and without proxying methods (we don't want to proxy them to Model)\n var mPathMessenger = new Messenger(this, undefined, modelMessageSource);\n\n // store messenger on ModelPath instance\n _.defineProperty(this, MESSENGER_PROPERTY, mPathMessenger);\n}\n\n\n/**\n * Returns the object allowing to recreate model path\n *\n * @return {Object}\n */\nfunction _getDefinition() {\n return {\n model: this._model,\n path: this._path,\n args: this._args\n };\n}\n\n\n/**\n * Class method\n * Creates modelPath object from definition created by _getDefinition\n *\n * @param {Object} definition\n * @return {ModelPath}\n */\nfunction _createFromDefinition(definition) {\n check(definition, {\n model: Function, // Model\n path: String,\n args: Array\n });\n\n var m = definition.model;\n\n return m.apply(m, definition.args);\n}\n\n\nfunction ModelPath$destroy() {\n this[MESSENGER_PROPERTY].destroy();\n}\n",
+ "'use strict';\n\n\nvar modelUtils = {\n normalizeSpliceIndex: normalizeSpliceIndex\n};\n\nmodule.exports = modelUtils;\n\n\nfunction normalizeSpliceIndex(spliceIndex, length) {\n return spliceIndex > length\n ? length\n : spliceIndex >= 0\n ? spliceIndex\n : spliceIndex + length > 0\n ? spliceIndex + length\n : 0;\n}\n",
+ "'use strict';\n\nvar MessengerAPI = require('../messenger/m_api')\n , pathUtils = require('./path_utils')\n , logger = require('../util/logger')\n , _ = require('mol-proto');\n\n\n/**\n * Subclass of MessengerAPI that is used to translate messages of Messenger on ModelPath to Messenger on Model.\n */\nvar ModelPathMsgAPI = _.createSubclass(MessengerAPI, 'ModelPathMsgAPI');\n\nmodule.exports = ModelPathMsgAPI;\n\n\n/**\n * ####ModelPathMsgAPI instance methods####\n *\n * - [init](#init) - initializes ModelPathMsgAPI\n * - [translateToSourceMessage](#translateToSourceMessage) - translates relative access paths of ModelPath to full path of Model\n * - [createInternalData](#createInternalData) - changes path in message on model to relative path and adds `fullPath` property to message data\n */\n_.extendProto(ModelPathMsgAPI, {\n init: init,\n translateToSourceMessage: translateToSourceMessage,\n createInternalData: createInternalData,\n});\n\n\n/**\n * ModelPathMsgAPI instance method\n * Called by MessengerAPI constructor.\n *\n * @param {String} rootPath root path of model path\n */\nfunction init(rootPath) {\n MessengerAPI.prototype.init.apply(this, arguments);\n this.rootPath = rootPath;\n}\n\n/**\n * ModelPathMsgAPI instance method\n * Translates relative access paths of ModelPath to full path of Model.\n *\n * @param {String} accessPath relative access path to be translated\n * @return {String}\n */\nfunction translateToSourceMessage(message) {\n // TODO should prepend RegExes\n // TODO should not prepend changedata too???\n if (message instanceof RegExp)\n return message;\n if (message == 'datachanges')\n return message;\n \n return this.rootPath + message;\n}\n\n\n/**\n * ModelPathMsgAPI instance method\n * Changes path in message on model to relative path and adds `fullPath` property to message data.\n *\n * @param {String} sourceMessage full access path on Model\n * @param {String} message relative access path on ModelPath\n * @param {Object} sourceData data received from Model, will be translated as described to be dispatched to ModelPath\n * @return {Object}\n */\nfunction createInternalData(sourceMessage, message, sourceData) {\n // TODO return on changedata too???\n if (message == 'datachanges') {\n var internalChanges = sourceData.changes\n .map(truncateChangePath, this)\n .filter(function(change) { return change; });\n var internalData = {\n changes: internalChanges,\n transaction: sourceData.transaction\n };\n\n return internalData\n }\n\n var internalData = truncateChangePath.call(this, sourceData);\n return internalData;\n}\n\n\nfunction truncateChangePath(change) {\n var fullPath = change.path\n , path = _.unPrefix(fullPath, this.rootPath);\n\n if (typeof path == 'string') {\n var change = _.clone(change);\n change.fullPath = fullPath;\n change.path = path;\n return change;\n }\n}\n",
"'use strict';\n\n// \n// ### model path utils\n\nvar check = require('../util/check')\n , Match = check.Match\n , _ = require('mol-proto');\n\nvar pathUtils = {\n parseAccessPath: parseAccessPath,\n createRegexPath: createRegexPath,\n getPathNodeKey: getPathNodeKey,\n wrapMessengerMethods: wrapMessengerMethods\n};\n\nmodule.exports = pathUtils;\n\n\nvar propertyPathSyntax = '\\\\.[A-Za-z_-][A-Za-z0-9_-]*'\n , arrayPathSyntax = '\\\\[[0-9]+\\\\]'\n , interpolationSyntax = '\\\\$[1-9][0-9]*'\n , propertyInterpolateSyntax = '\\\\.' + interpolationSyntax\n , arrayInterpolateSyntax = '\\\\[' + interpolationSyntax + '\\\\]'\n\n , propertyStarSyntax = '\\\\.\\\\*'\n , arrayStarSyntax = '\\\\[\\\\*\\\\]'\n , starSyntax = '\\\\*'\n\n , pathParseSyntax = [\n propertyPathSyntax,\n arrayPathSyntax,\n propertyInterpolateSyntax,\n arrayInterpolateSyntax\n ].join('|')\n , pathParsePattern = new RegExp(pathParseSyntax, 'g')\n\n , patternPathParseSyntax = [\n pathParseSyntax,\n propertyStarSyntax,\n arrayStarSyntax,\n starSyntax\n ].join('|')\n , patternPathParsePattern = new RegExp(patternPathParseSyntax, 'g')\n\n //, targetPathParsePattern = /\\.[A-Za-z][A-Za-z0-9_]*|\\[[0-9]+\\]|\\.\\$[1-9][0-9]*|\\[\\$[1-9][0-9]*\\]|\\$[1-9][0-9]/g\n , pathNodeTypes = {\n '.': { syntax: 'object', empty: '{}' },\n '[': { syntax: 'array', empty: '[]'},\n '*': { syntax: 'match', empty: '{}'},\n };\n\nfunction parseAccessPath(path, nodeParsePattern) {\n nodeParsePattern = nodeParsePattern || pathParsePattern;\n\n var parsedPath = [];\n\n if (! path)\n return parsedPath;\n\n var unparsed = path.replace(nodeParsePattern, function(nodeStr) {\n var pathNode = { property: nodeStr };\n _.extend(pathNode, pathNodeTypes[nodeStr[0]]);\n if (nodeStr[1] == '$')\n pathNode.interpolate = getPathNodeKey(pathNode, true);\n\n parsedPath.push(pathNode);\n return '';\n });\n if (unparsed)\n throw new Error('incorrect model path: ' + path);\n\n return parsedPath;\n}\n\n\nvar nodeRegex = {\n '.*': propertyPathSyntax,\n '[*]': arrayPathSyntax\n};\nnodeRegex['*'] = nodeRegex['.*'] + '|' + nodeRegex['[*]'];\n\nfunction createRegexPath(path) {\n check(path, Match.OneOf(String, RegExp));\n\n if (path instanceof RegExp || path.indexOf('*') == -1)\n return path;\n\n var parsedPath = pathUtils.parseAccessPath(path, patternPathParsePattern)\n , regexStr = '^'\n // , regexStrEnd = ''\n , patternsStarted = false;\n\n parsedPath.forEach(function(pathNode) {\n var prop = pathNode.property\n , regex = nodeRegex[prop];\n \n if (regex) {\n // regexStr += '(' + regex;\n // regexStrEnd += '|)';\n regexStr += '(' + regex + '|)';\n // regexStrEnd += '|)';\n patternsStarted = true;\n } else {\n // if (patternsStarted)\n // throw new Error('\"*\" path segment cannot be in the middle of the path: ' + path);\n regexStr += prop.replace(/(\\.|\\[|\\])/g, '\\\\$1'); // add slash in front of symbols that have special meaning in regex\n }\n });\n\n regexStr += /* regexStrEnd + */ '$';\n\n try {\n return new RegExp(regexStr);\n } catch (e) {\n throw new Error('can\\'t construct regex for path pattern: ' + path);\n }\n}\n\n\nfunction getPathNodeKey(pathNode, interpolated) {\n var prop = pathNode.property\n , startIndex = interpolated ? 2 : 1;\n return pathNode.syntax == 'array'\n ? prop.slice(startIndex, prop.length - 1)\n : prop.slice(startIndex);\n}\n\n\n// TODO allow for multiple messages in a string\nfunction wrapMessengerMethods(methodsNames) {\n methodsNames = methodsNames || ['on', 'off'];\n var wrappedMethods = _.mapToObject(methodsNames, function(methodName) {\n var origMethod = this[methodName];\n // replacing message subsribe/unsubscribe/etc. to convert \"*\" message patterns to regexps\n return function(path, subscriber) {\n var regexPath = createRegexPath(path);\n origMethod.call(this, regexPath, subscriber);\n };\n }, this);\n _.defineProperties(this, wrappedMethods);\n}\n",
"'use strict';\n\nvar pathUtils = require('../path_utils')\n , modelUtils = require('../model_utils')\n , logger = require('../../util/logger')\n , fs = require('fs')\n , doT = require('dot')\n , _ = require('mol-proto')\n , changeDataHandler = require('../change_data')\n , getTransactionFlag = changeDataHandler.getTransactionFlag\n , postTransactionFinished = changeDataHandler.postTransactionFinished;\n\n\n/**\n * Templates to synthesize model getters and setters\n */\nvar templates = {\n get: \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\nmethod = function get() {\\n var m = {{# def.modelAccessPrefix }};\\n return m {{~ it.parsedPath :pathNode }}\\n {{? pathNode.interpolate}}\\n && (m = m[this._args[ {{= pathNode.interpolate }} ]])\\n {{??}}\\n && (m = m{{= pathNode.property }})\\n {{?}} {{~}};\\n};\\n\",\n set: \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n{{# def.include_defines }}\\n{{# def.include_create_tree }}\\n\\n\\n/**\\n * Template that synthesizes setter for Model and for ModelPath\\n */\\nmethod = function set(value) {\\n {{# def.initVars:'set' }}\\n\\n {{# def.createTree:'set' }}\\n\\n {{\\n currNode = nextNode;\\n currProp = currNode && currNode.property;\\n }}\\n\\n {{ /* assign value to the last property */ }}\\n {{? currProp }}\\n wasDef = {{# def.wasDefined}};\\n {{# def.changeAccessPath }}\\n\\n var old = m{{# def.currProp }};\\n\\n {{ /* clone value to prevent same reference in linked models */ }}\\n m{{# def.currProp }} = cloneTree(value);\\n {{?}}\\n\\n {{ /* add message related to the last property change */ }}\\n if (this._options.reactive !== false) {\\n if (! wasDef)\\n {{# def.addMsg }} accessPath, type: 'added',\\n newValue: value });\\n else if (old != value)\\n {{# def.addMsg }} accessPath, type: 'changed',\\n oldValue: old, newValue: value });\\n\\n {{ /* add message related to changes in (sub)properties inside removed and assigned value */ }}\\n if (! wasDef || old != value)\\n addTreeChangesMessages(messages, messagesHash,\\n accessPath, old, value); /* defined in the function that synthesizes ModelPath setter */\\n\\n {{ /* post all stored messages */ }}\\n {{# def.postMessages }}\\n }\\n};\\n\",\n del: \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n{{# def.include_defines }}\\n{{# def.include_traverse_tree }}\\n\\nmethod = function del() {\\n {{# def.initVars:'del' }}\\n\\n {{? it.parsedPath.length }}\\n {{# def.traverseTree }}\\n\\n {{\\n var currNode = it.parsedPath[count];\\n var currProp = currNode.property; \\n }}\\n\\n if (! treeDoesNotExist && m && m.hasOwnProperty && {{# def.wasDefined}}) {\\n var old = m{{# def.currProp }};\\n delete m{{# def.currProp }};\\n {{# def.changeAccessPath }}\\n var didDelete = true;\\n }\\n {{??}}\\n if (typeof m != 'undefined') {\\n var old = m;\\n {{# def.modelAccessPrefix }} = undefined;\\n var didDelete = true;\\n }\\n {{?}}\\n\\n if (didDelete && this._options.reactive !== false) {\\n {{# def.addMsg }} accessPath, type: 'deleted', oldValue: old });\\n\\n addTreeChangesMessages(messages, messagesHash,\\n accessPath, old, undefined); /* defined in the function that synthesizes ModelPath setter */\\n\\n {{ /* post all stored messages */ }}\\n {{# def.postMessages }}\\n }\\n};\\n\",\n splice: \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n{{# def.include_defines }}\\n{{# def.include_create_tree }}\\n{{# def.include_traverse_tree }}\\n\\nmethod = function splice(spliceIndex, spliceHowMany) { /* ,... - extra arguments to splice into array */\\n {{# def.initVars:'splice' }}\\n\\n var argsLen = arguments.length;\\n var addItems = argsLen > 2;\\n\\n if (addItems) {\\n {{ /* only create model tree if items are inserted in array */ }}\\n\\n {{ /* if model is undefined it will be set to an empty array */ }} \\n var value = [];\\n {{# def.createTree:'splice' }}\\n\\n {{? nextNode }}\\n {{\\n var currNode = nextNode;\\n var currProp = currNode.property;\\n var emptyProp = '[]';\\n }}\\n\\n {{# def.createTreeStep }}\\n {{?}}\\n\\n } else if (spliceHowMany > 0) {\\n {{ /* if items are not inserted, only traverse model tree if items are deleted from array */ }}\\n {{? it.parsedPath.length }}\\n {{# def.traverseTree }}\\n\\n {{\\n var currNode = it.parsedPath[count];\\n var currProp = currNode.property; \\n }}\\n\\n {{ /* extra brace closes 'else' in def.traverseTreeStep */ }}\\n {{# def.traverseTreeStep }} }\\n {{?}}\\n }\\n\\n {{ /* splice items */ }}\\n if (addItems || (! treeDoesNotExist && m\\n && m.length > spliceIndex ) ) {\\n var oldLength = m.length = m.length || 0;\\n\\n arguments[0] = spliceIndex = normalizeSpliceIndex(spliceIndex, m.length);\\n\\n {{ /* clone added arguments to prevent same references in linked models */ }}\\n if (addItems)\\n for (var i = 2; i < argsLen; i++)\\n arguments[i] = cloneTree(arguments[i]);\\n\\n {{ /* actual splice call */ }}\\n var removed = Array.prototype.splice.apply(m, arguments);\\n\\n if (this._options.reactive !== false) {\\n {{# def.addMsg }} accessPath, type: 'splice',\\n index: spliceIndex, removed: removed, addedCount: addItems ? argsLen - 2 : 0,\\n newValue: m });\\n\\n if (removed && removed.length)\\n removed.forEach(function(item, index) {\\n var itemPath = accessPath + '[' + (spliceIndex + index) + ']';\\n {{# def.addMsg }} itemPath, type: 'removed', oldValue: item });\\n\\n if (valueIsTree(item))\\n addMessages(messages, messagesHash, itemPath, item, 'removed', 'oldValue');\\n });\\n\\n if (addItems)\\n for (var i = 2; i < argsLen; i++) {\\n var item = arguments[i];\\n var itemPath = accessPath + '[' + (spliceIndex + i - 2) + ']';\\n {{# def.addMsg }} itemPath, type: 'added', newValue: item });\\n\\n if (valueIsTree(item))\\n addMessages(messages, messagesHash, itemPath, item, 'added', 'newValue');\\n }\\n\\n {{ /* post all stored messages */ }}\\n {{# def.postMessages }}\\n }\\n }\\n\\n return removed || [];\\n}\\n\"\n};\n\nvar include_defines = \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n/**\\n * Inserts initialization code\\n */\\n {{## def.initVars:method:\\n var m = {{# def.modelAccessPrefix }};\\n var messages = [], messagesHash = {};\\n var accessPath = '';\\n var treeDoesNotExist;\\n /* hack to prevent sending finished events to allow for propagation of batches without splitting them */\\n var inChangeTransaction = getTransactionFlag( {{= method }} );\\n #}}\\n\\n/**\\n * Inserts the beginning of function call to add message to list\\n */\\n{{## def.addMsg: addChangeMessage(messages, messagesHash, { path: #}}\\n\\n/**\\n * Inserts current property/index for both normal and interpolated properties/indexes\\n */\\n{{## def.currProp:{{? currNode.interpolate }}[this._args[ {{= currNode.interpolate }} ]]{{??}}{{= currProp }}{{?}} #}}\\n\\n/**\\n * Inserts condition to test whether normal/interpolated property/index exists\\n */\\n{{## def.wasDefined: m.hasOwnProperty(\\n {{? currNode.interpolate }}\\n this._args[ {{= currNode.interpolate }} ]\\n {{??}}\\n '{{= it.getPathNodeKey(currNode) }}'\\n {{?}}\\n) #}}\\n\\n\\n/**\\n * Inserts code to update access path for current property\\n * Because of the possibility of interpolated properties, it can't be calculated in template, it can only be calculated during accessor call.\\n */\\n{{## def.changeAccessPath:\\n accessPath += {{? currNode.interpolate }}\\n {{? currNode.syntax == 'array' }}\\n '[' + this._args[ {{= currNode.interpolate }} ] + ']';\\n {{??}}\\n '.' + this._args[ {{= currNode.interpolate }} ];\\n {{?}}\\n {{??}}\\n '{{= currProp }}';\\n {{?}}\\n#}}\\n\\n\\n/**\\n * Inserts code to post stored messages\\n */\\n{{## def.postMessages:\\n if (messages.length) {\\n {{# def.modelPostBatchCode }}('datachanges', {\\n changes: messages,\\n transaction: inChangeTransaction\\n });\\n\\n messages.forEach(function(msg) {\\n {{# def.modelPostMessageCode }}(msg.path, msg);\\n }, this);\\n }\\n#}}\\n\"\n , include_create_tree = \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n/**\\n * Inserts code to create model tree as neccessary for `set` and `splice` accessors and to add messages to send list if the tree changes.\\n */\\n{{## def.createTree:method:\\n var wasDef = true;\\n var old = m;\\n\\n {{ var emptyProp = it.parsedPath[0] && it.parsedPath[0].empty; }}\\n {{? emptyProp }}\\n {{ /* create top level model if it was not previously defined */ }}\\n if (! m) {\\n m = {{# def.modelAccessPrefix }} = {{= emptyProp }};\\n wasDef = false;\\n\\n if (this._options.reactive !== false) {\\n {{# def.addMsg }} '', type: 'added',\\n newValue: m });\\n }\\n }\\n {{??}}\\n {{? method == 'splice' }}\\n if (! m) {\\n {{?}}\\n m = {{# def.modelAccessPrefix }} = cloneTree(value);\\n wasDef = typeof old != 'undefined';\\n {{? method == 'splice' }}\\n }\\n {{?}} \\n {{?}}\\n\\n\\n {{ /* create model tree if it doesn't exist */ }}\\n {{ var modelDataProperty = '';\\n var nextNode = it.parsedPath[0];\\n var count = it.parsedPath.length - 1;\\n\\n for (var i = 0; i < count; i++) {\\n var currNode = nextNode;\\n var currProp = currNode.property;\\n nextNode = it.parsedPath[i + 1];\\n var emptyProp = nextNode && nextNode.empty;\\n }}\\n\\n {{# def.createTreeStep }}\\n\\n {{ } /* for loop */ }}\\n#}}\\n\\n\\n/**\\n * Inserts code to create one step in the model tree\\n */\\n{{## def.createTreeStep:\\n {{# def.changeAccessPath }}\\n\\n if (! {{# def.wasDefined }}) { \\n {{ /* property does not exist */ }}\\n m = m{{# def.currProp }} = {{= emptyProp }};\\n\\n if (this._options.reactive !== false) {\\n {{# def.addMsg }} accessPath, type: 'added', \\n newValue: m });\\n }\\n\\n } else if (typeof m{{# def.currProp }} != 'object') {\\n {{ /* property is not object */ }}\\n var old = m{{# def.currProp }};\\n m = m{{# def.currProp }} = {{= emptyProp }};\\n\\n if (this._options.reactive !== false) {\\n {{# def.addMsg }} accessPath, type: 'changed', \\n oldValue: old, newValue: m });\\n }\\n\\n } else {\\n {{ /* property exists, just traverse down the model tree */ }}\\n m = m{{# def.currProp }};\\n }\\n#}}\\n\"\n , include_traverse_tree = \"'use strict';\\n/* Only use this style of comments, not \\\"//\\\" */\\n\\n/**\\n * Inserts code to traverse model tree for `delete` and `splice` accessors.\\n */\\n{{## def.traverseTree:\\n {{ \\n var count = it.parsedPath.length-1;\\n\\n for (var i = 0; i < count; i++) { \\n var currNode = it.parsedPath[i];\\n var currProp = currNode.property;\\n }}\\n {{# def.traverseTreeStep }}\\n\\n {{ } /* for loop */\\n\\n var i = count;\\n while (i--) { /* closing braces for else's above */\\n }}\\n }\\n {{ } /* while loop */ }}\\n#}}\\n\\n\\n/**\\n * Inserts code to traverse one step in the model tree\\n */\\n{{## def.traverseTreeStep:\\n if (! (m && m.hasOwnProperty && {{# def.wasDefined}} ) )\\n treeDoesNotExist = true;\\n else {\\n m = m{{# def.currProp }};\\n {{# def.changeAccessPath }}\\n {{ /* brace from else is not closed on purpose - all braces are closed in while loop */ }}\\n#}}\\n\";\n\nvar dotDef = {\n include_defines: include_defines,\n include_create_tree: include_create_tree,\n include_traverse_tree: include_traverse_tree,\n getPathNodeKey: pathUtils.getPathNodeKey,\n modelAccessPrefix: 'this._model._data',\n modelPostMessageCode: 'this._model._internalMessenger.postMessage',\n modelPostBatchCode: 'this._model.postMessageSync',\n internalMessenger: 'this._model._internalMessenger'\n};\n\nvar modelDotDef = _(dotDef).clone().extend({\n modelAccessPrefix: 'this._data',\n modelPostMessageCode: 'this._internalMessenger.postMessage',\n modelPostBatchCode: 'this.postMessageSync',\n internalMessenger: 'this._internalMessenger'\n})._();\n\n\nvar dotSettings = _.clone(doT.templateSettings);\ndotSettings.strip = false;\n\nvar synthesizers = _.mapKeys(templates, function(tmpl) {\n return doT.template(tmpl, dotSettings, dotDef); \n});\n\n\nvar modelSynthesizers = _.mapToObject(['set', 'del', 'splice'], function(methodName) {\n return doT.template(templates[methodName], dotSettings, modelDotDef);\n});\n\n\n/**\n * Function that synthesizes accessor methods.\n * Function is memoized so accessors are cached (up to 1000).\n *\n * @param {String} path Model/ModelPath access path\n * @param {Array} parsedPath array of path nodes\n * @return {Object[Function]}\n */\nvar synthesizePathMethods = _.memoize(_synthesizePathMethods, undefined, 1000);\n\nfunction _synthesizePathMethods(path, parsedPath) {\n var methods = _.mapKeys(synthesizers, function(synthszr) {\n return _synthesize(synthszr, path, parsedPath);\n });\n return methods;\n}\n\n\nvar normalizeSpliceIndex = modelUtils.normalizeSpliceIndex; // used in splice.dot.js\n\n\nfunction _synthesize(synthesizer, path, parsedPath) {\n var method\n , methodCode = synthesizer({\n parsedPath: parsedPath,\n getPathNodeKey: pathUtils.getPathNodeKey\n });\n\n try {\n eval(methodCode);\n } catch (e) {\n throw ModelError('ModelPath method compilation error; path: ' + path + ', code: ' + methodCode);\n }\n\n return method;\n\n\n // functions used by methods `set`, `delete` and `splice` (synthesized by template)\n function addChangeMessage(messages, messagesHash, msg) {\n messages.push(msg);\n messagesHash[msg.path] = msg;\n }\n\n function addTreeChangesMessages(messages, messagesHash, rootPath, oldValue, newValue) {\n var oldIsTree = valueIsTree(oldValue)\n , newIsTree = valueIsTree(newValue);\n\n if (newIsTree)\n addMessages(messages, messagesHash, rootPath, newValue, 'added', 'newValue');\n \n if (oldIsTree)\n addMessages(messages, messagesHash, rootPath, oldValue, 'removed', 'oldValue');\n }\n\n function addMessages(messages, messagesHash, rootPath, obj, msgType, valueProp) {\n _addMessages(rootPath, obj);\n\n\n function _addMessages(rootPath, obj) {\n if (Array.isArray(obj)) {\n var pathSyntax = rootPath + '[$$]';\n obj.forEach(function(value, index) {\n addMessage(value, index, pathSyntax);\n });\n } else {\n var pathSyntax = rootPath + '.$$';\n _.eachKey(obj, function(value, key) {\n addMessage(value, key, pathSyntax);\n });\n }\n }\n\n function addMessage(value, key, pathSyntax) {\n var path = pathSyntax.replace('$$', key)\n , existingMsg = messagesHash[path];\n\n if (existingMsg) {\n if (existingMsg.type == msgType)\n logger.error('setter error: same message type posted on the same path');\n else {\n existingMsg.type = 'changed';\n existingMsg[valueProp] = value;\n }\n } else {\n var msg = { path: path, type: msgType };\n msg[valueProp] = value;\n addChangeMessage(messages, messagesHash, msg);\n }\n\n if (valueIsTree(value))\n _addMessages(path, value);\n }\n }\n\n function cloneTree(value) {\n return valueIsNormalObject(value)\n ? _.deepClone(value)\n : value;\n }\n\n function protectValue(value) {\n return ! valueIsNormalObject(value)\n ? value\n : Array.isArray(value)\n ? value.slice()\n : Object.create(value);\n }\n\n function valueIsTree(value) {\n return valueIsNormalObject(value)\n && Object.keys(value).length;\n }\n\n function valueIsNormalObject(value) {\n return value != null\n && typeof value == \"object\"\n && ! (value instanceof Date)\n && ! (value instanceof RegExp);\n }\n\n function addBatchIdsToMessage(msg, batchId, msgId) {\n _.defineProperties(msg, {\n __batch_id: batchId,\n __msg_id: msgId\n });\n }\n}\n\n\n/**\n * Exports `synthesize` function with the following:\n *\n * - .modelMethods.set - `set` method for Model\n * - .modelMethods.del - `del` method for Model\n * - .modelMethods.splice - `splice` method for Model\n */\nmodule.exports = synthesizePathMethods;\n\nvar modelMethods = _.mapKeys(modelSynthesizers, function(synthesizer) {\n return _synthesize(synthesizer, '', []);\n});\n\nsynthesizePathMethods.modelMethods = modelMethods;\n",
- "arguments[4][90][0].apply(exports,arguments)",
- "'use strict';\n\n/**\n * `milo.util`\n */\nvar util = {\n logger: require('./logger'),\n check: require('./check'),\n};\n\nmodule.exports = util;\n",
- "arguments[4][102][0].apply(exports,arguments)",
- "arguments[4][103][0].apply(exports,arguments)",
+ "'use strict';\n\n/**\n * `milo.utils.check`\n *\n * Check is a module for parameters checking extracted from [Meteor](http://docs.meteor.com/) framework.\n *\n * It allows to both document and to check parameter types in your function\n * making code both readable and stable.\n *\n *\n * ### Usage\n *```\n * var check = milo.check\n * , Match = check.Match;\n *\n * function My(name, obj, cb) {\n * // if any of checks fail an error will be thrown\n * check(name, String);\n * check(obj, Match.ObjectIncluding({ options: Object }));\n * check(cb, Function);\n *\n * // ... your code\n * }\n *```\n * See [Meteor docs](http://docs.meteor.com/#match) to see how it works\n *\n *\n * ### Patterns\n *\n * All patterns and functions described in Meteor docs work.\n *\n * Unlike in Meteor, Object pattern matches instance of any class,\n * not only plain object.\n *\n * In addition to patterns described in Meteor docs the following patterns are implemented\n *\n * * Match.__ObjectHash__(_pattern_)\n *\n * Matches an object where all properties match a given pattern\n *\n * * Match.__Subclass__(_constructor_ [, _matchThisClassToo_])\n *\n * Matches a class that is a subclass of a given class. If the second parameter\n * is true, it will also match the class itself.\n *\n * Without this pattern to check if _MySubclass_ is a subclass of _MyClass_\n * you would have to use\n *\n * check(MySubclass, Match.Where(function() {\n * return MySubclass.prototype instanceof MyClass;\n * });\n *\n *\n * Things we explicitly do NOT support:\n * - heterogenous arrays\n**/\n\nvar _ = require('mol-proto')\n , config = require('../config');\n\nvar check = function (value, pattern) {\n if (config.check === false)\n return;\n\n // Record that check got called, if somebody cared.\n try {\n checkSubtree(value, pattern);\n } catch (err) {\n if ((err instanceof Match.Error) && err.path)\n err.message += \" in field \" + err.path;\n throw err;\n }\n};\n\nmodule.exports = check;\n\nvar Match = check.Match = {\n Optional: function (pattern) {\n return new Optional(pattern);\n },\n OneOf: function (/* arguments */) {\n return new OneOf(arguments);\n },\n Any: ['__any__'],\n Where: function (condition) {\n return new Where(condition);\n },\n ObjectIncluding: function (pattern) {\n return new ObjectIncluding(pattern);\n },\n // Matches only signed 32-bit integers\n Integer: ['__integer__'],\n\n // Matches string that is a valid identifier, will not allow javascript reserved words\n IdentifierString: /^[a-z_$][0-9a-z_$]*$/i,\n\n // Matches hash (object) with values matching pattern\n ObjectHash: function(pattern) {\n return new ObjectHash(pattern);\n },\n\n Subclass: function(Superclass, matchSuperclassToo) {\n return new Subclass(Superclass, matchSuperclassToo);\n },\n\n // XXX matchers should know how to describe themselves for errors\n Error: TypeError,\n\n // Meteor.makeErrorType(\"Match.Error\", function (msg) {\n // this.message = \"Match error: \" + msg;\n // The path of the value that failed to match. Initially empty, this gets\n // populated by catching and rethrowing the exception as it goes back up the\n // stack.\n // E.g.: \"vals[3].entity.created\"\n // this.path = \"\";\n // If this gets sent over DDP, don't give full internal details but at least\n // provide something better than 500 Internal server error.\n // this.sanitizedError = new Meteor.Error(400, \"Match failed\");\n // }),\n\n // Tests to see if value matches pattern. Unlike check, it merely returns true\n // or false (unless an error other than Match.Error was thrown).\n test: function (value, pattern) {\n try {\n checkSubtree(value, pattern);\n return true;\n } catch (e) {\n if (e instanceof Match.Error)\n return false;\n // Rethrow other errors.\n throw e;\n }\n }\n};\n\nfunction Optional(pattern) {\n this.pattern = pattern;\n};\n\nfunction OneOf(choices) {\n if (choices.length == 0)\n throw new Error(\"Must provide at least one choice to Match.OneOf\");\n this.choices = choices;\n};\n\nfunction Where(condition) {\n this.condition = condition;\n};\n\nfunction ObjectIncluding(pattern) {\n this.pattern = pattern;\n};\n\nfunction ObjectHash(pattern) {\n this.pattern = pattern;\n};\n\nfunction Subclass(Superclass, matchSuperclassToo) {\n this.Superclass = Superclass;\n this.matchSuperclass = matchSuperclassToo;\n};\n\nvar typeofChecks = [\n [String, \"string\"],\n [Number, \"number\"],\n [Boolean, \"boolean\"],\n [Function, \"function\"],\n // While we don't allow undefined in JSON, this is good for optional\n // arguments with OneOf.\n [undefined, \"undefined\"]\n];\n\nfunction checkSubtree(value, pattern) {\n // Match anything!\n if (pattern === Match.Any)\n return;\n\n // Basic atomic types.\n // Do not match boxed objects (e.g. String, Boolean)\n for (var i = 0; i < typeofChecks.length; ++i) {\n if (pattern === typeofChecks[i][0]) {\n if (typeof value === typeofChecks[i][1])\n return;\n throw new Match.Error(\"Expected \" + typeofChecks[i][1] + \", got \" +\n typeof value);\n }\n }\n if (pattern === null) {\n if (value === null)\n return;\n throw new Match.Error(\"Expected null, got \" + JSON.stringify(value));\n }\n\n // Match.Integer is special type encoded with array\n if (pattern === Match.Integer) {\n // There is no consistent and reliable way to check if variable is a 64-bit\n // integer. One of the popular solutions is to get reminder of division by 1\n // but this method fails on really large floats with big precision.\n // E.g.: 1.348192308491824e+23 % 1 === 0 in V8\n // Bitwise operators work consistantly but always cast variable to 32-bit\n // signed integer according to JavaScript specs.\n if (typeof value === 'number' && (value | 0) === value)\n return\n throw new Match.Error('Expected Integer, got '\n + (value instanceof Object ? JSON.stringify(value) : value));\n }\n\n if (pattern === Match.IdentifierString) {\n if (typeof value === 'string' && Match.IdentifierString.test(value)\n && _jsKeywords.indexOf(key) == -1)\n return;\n throw new Match.Error('Expected identifier string, got '\n + (value instanceof Object ? JSON.stringify(value) : value));\n }\n\n // \"Object\" is shorthand for Match.ObjectIncluding({});\n if (pattern === Object)\n pattern = Match.ObjectIncluding({});\n\n // Array (checked AFTER Any, which is implemented as an Array).\n if (pattern instanceof Array) {\n if (pattern.length !== 1)\n throw Error(\"Bad pattern: arrays must have one type element\" +\n JSON.stringify(pattern));\n if (!Array.isArray(value)) {\n throw new Match.Error(\"Expected array, got \" + JSON.stringify(value));\n }\n\n value.forEach(function (valueElement, index) {\n try {\n checkSubtree(valueElement, pattern[0]);\n } catch (err) {\n if (err instanceof Match.Error) {\n err.path = _prependPath(index, err.path);\n }\n throw err;\n }\n });\n return;\n }\n\n // Arbitrary validation checks. The condition can return false or throw a\n // Match.Error (ie, it can internally use check()) to fail.\n if (pattern instanceof Where) {\n if (pattern.condition(value))\n return;\n // XXX this error is terrible\n throw new Match.Error(\"Failed Match.Where validation\");\n }\n\n\n if (pattern instanceof Optional)\n pattern = Match.OneOf(undefined, pattern.pattern);\n\n if (pattern instanceof OneOf) {\n for (var i = 0; i < pattern.choices.length; ++i) {\n try {\n checkSubtree(value, pattern.choices[i]);\n // No error? Yay, return.\n return;\n } catch (err) {\n // Other errors should be thrown. Match errors just mean try another\n // choice.\n if (!(err instanceof Match.Error))\n throw err;\n }\n }\n // XXX this error is terrible\n throw new Match.Error(\"Failed Match.OneOf or Match.Optional validation\");\n }\n\n // A function that isn't something we special-case is assumed to be a\n // constructor.\n if (pattern instanceof Function) {\n if (value instanceof pattern)\n return;\n // XXX what if .name isn't defined\n throw new Match.Error(\"Expected \" + pattern.constructor.name);\n }\n\n var unknownKeysAllowed = false;\n if (pattern instanceof ObjectIncluding) {\n unknownKeysAllowed = true;\n pattern = pattern.pattern;\n }\n\n if (pattern instanceof ObjectHash) {\n var keyPattern = pattern.pattern;\n var emptyHash = true;\n for (var key in value) {\n emptyHash = false;\n check(value[key], keyPattern);\n }\n if (emptyHash)\n throw new Match.Error(\"Expected \" + pattern.constructor.name);\n return;\n }\n\n if (pattern instanceof Subclass) {\n var Superclass = pattern.Superclass;\n if (pattern.matchSuperclass && value == Superclass)\n return;\n if (! (value.prototype instanceof Superclass))\n throw new Match.Error(\"Expected \" + pattern.constructor.name + \" of \" + Superclass.name);\n return;\n }\n\n if (typeof pattern !== \"object\")\n throw Error(\"Bad pattern: unknown pattern type\");\n\n // An object, with required and optional keys. Note that this does NOT do\n // structural matches against objects of special types that happen to match\n // the pattern: this really needs to be a plain old {Object}!\n if (typeof value !== 'object')\n throw new Match.Error(\"Expected object, got \" + typeof value);\n if (value === null)\n throw new Match.Error(\"Expected object, got null\");\n\n var requiredPatterns = {};\n var optionalPatterns = {};\n\n _.eachKey(pattern, function(subPattern, key) {\n if (pattern[key] instanceof Optional)\n optionalPatterns[key] = pattern[key].pattern;\n else\n requiredPatterns[key] = pattern[key];\n }, this, true);\n\n _.eachKey(value, function(subValue, key) {\n var subValue = value[key];\n try {\n if (requiredPatterns.hasOwnProperty(key)) {\n checkSubtree(subValue, requiredPatterns[key]);\n delete requiredPatterns[key];\n } else if (optionalPatterns.hasOwnProperty(key)) {\n checkSubtree(subValue, optionalPatterns[key]);\n } else {\n if (!unknownKeysAllowed)\n throw new Match.Error(\"Unknown key\");\n }\n } catch (err) {\n if (err instanceof Match.Error)\n err.path = _prependPath(key, err.path);\n throw err;\n }\n }, this, true);\n\n _.eachKey(requiredPatterns, function(value, key) {\n throw new Match.Error(\"Missing key '\" + key + \"'\");\n }, this, true);\n};\n\n\nvar _jsKeywords = [\"do\", \"if\", \"in\", \"for\", \"let\", \"new\", \"try\", \"var\", \"case\",\n \"else\", \"enum\", \"eval\", \"false\", \"null\", \"this\", \"true\", \"void\", \"with\",\n \"break\", \"catch\", \"class\", \"const\", \"super\", \"throw\", \"while\", \"yield\",\n \"delete\", \"export\", \"import\", \"public\", \"return\", \"static\", \"switch\",\n \"typeof\", \"default\", \"extends\", \"finally\", \"package\", \"private\", \"continue\",\n \"debugger\", \"function\", \"arguments\", \"interface\", \"protected\", \"implements\",\n \"instanceof\"];\n\n// Assumes the base of path is already escaped properly\n// returns key + base\nfunction _prependPath(key, base) {\n if ((typeof key) === \"number\" || key.match(/^[0-9]+$/))\n key = \"[\" + key + \"]\";\n else if (!key.match(Match.IdentifierString) || _jsKeywords.indexOf(key) != -1)\n key = JSON.stringify([key]);\n\n if (base && base[0] !== \"[\")\n return key + '.' + base;\n return key + base;\n};\n",
+ "'use strict';\n\n/**\n * `milo.util`\n */\nvar util = {\n logger: require('./logger'),\n check: require('./check'),\n doT: require('dot')\n};\n\nmodule.exports = util;\n",
+ "'use strict';\n\n// \n// milo.utils.logger\n// -----------\n\n// Application logger that has error, warn, info and debug\n// methods, that can be suppressed by setting log level.\n\n// Properties:\n\n// - level\n\n// - 0 - error\n// - 1 - warn\n// - 2 - info\n// - 3 - debug (default)\n\n// - enabled\n\n// true by default. Set to false to disable all logging in browser console.\n\n\nvar Logger = require('./logger_class');\n\nvar logger = new Logger({ level: 3 });\n\nmodule.exports = logger;\n",
+ "'use strict';\n\n// ### Logger Class\n\n// Properties:\n\n// - level\n\n// - 0 - error\n// - 1 - warn\n// - 2 - info\n// - 3 - debug (default)\n\n// - enabled\n\n// true by default. Set to false to disable all logging in browser console.\n\n\nvar _ = require('mol-proto');\n\n\n/**\n * Log levels.\n */\n\nvar levels = [\n 'error',\n 'warn',\n 'info',\n 'debug'\n];\n\nvar maxLevelLength = Math.max.apply(Math, levels.map(function(level) { return level.length; }));\n\n/**\n * Colors for log levels.\n */\n\nvar colors = [\n 31,\n 33,\n 36,\n 90\n];\n\n/**\n * Pads the nice output to the longest log level.\n */\nfunction pad(str) {\n if (str.length < maxLevelLength)\n return str + new Array(maxLevelLength - str.length + 1).join(' ');\n\n return str;\n};\n\n\nfunction colored(str, color) {\n return '\\x1B[' + color + 'm' + str + ' -\\x1B[39m';\n}\n\n\nvar DEFAULT_OPTIONS = {\n level: 3,\n throwLevel: -1, // never throw\n enabled: true,\n logPrefix: ''\n}\n\n\n/**\n * Logger (console).\n *\n * @api public\n */\nvar Logger = function (opts) {\n _.extend(this, DEFAULT_OPTIONS);\n _.extend(this, opts || {});\n};\n\n\n/**\n * Log method.\n *\n * @api public\n */\n\nLogger.prototype.log = function (type) {\n var index = levels.indexOf(type);\n\n if (! this.enabled || index > this.level)\n return this;\n\n var args = _.slice(arguments, 1);\n\n if (index <= this.throwLevel)\n throw new Error([this.logPrefix, type + ':'].concat(args).join(' '));\n\n console.log.apply(\n console\n , [ this.logPrefixColor\n ? ' ' + colored(this.logPrefix, this.logPrefixColor)\n : this.logPrefix,\n (this.colors\n ? ' ' + colored(pad(type), colors[index])\n : type) + ':'\n ].concat(args)\n );\n\n return this;\n};\n\n/**\n * Generate methods.\n */\n\nlevels.forEach(function (name) {\n Logger.prototype[name] = function () {\n this.log.apply(this, [name].concat(_.toArray(arguments)));\n };\n});\n\n\nmodule.exports = Logger;\n",
+ "// doT.js\n// 2011-2014, Laura Doktorova, https://github.com/olado/doT\n// Licensed under the MIT license.\n\n(function() {\n\t\"use strict\";\n\n\tvar doT = {\n\t\tversion: \"1.0.3\",\n\t\ttemplateSettings: {\n\t\t\tevaluate: /\\{\\{([\\s\\S]+?(\\}?)+)\\}\\}/g,\n\t\t\tinterpolate: /\\{\\{=([\\s\\S]+?)\\}\\}/g,\n\t\t\tencode: /\\{\\{!([\\s\\S]+?)\\}\\}/g,\n\t\t\tuse: /\\{\\{#([\\s\\S]+?)\\}\\}/g,\n\t\t\tuseParams: /(^|[^\\w$])def(?:\\.|\\[[\\'\\\"])([\\w$\\.]+)(?:[\\'\\\"]\\])?\\s*\\:\\s*([\\w$\\.]+|\\\"[^\\\"]+\\\"|\\'[^\\']+\\'|\\{[^\\}]+\\})/g,\n\t\t\tdefine: /\\{\\{##\\s*([\\w\\.$]+)\\s*(\\:|=)([\\s\\S]+?)#\\}\\}/g,\n\t\t\tdefineParams:/^\\s*([\\w$]+):([\\s\\S]+)/,\n\t\t\tconditional: /\\{\\{\\?(\\?)?\\s*([\\s\\S]*?)\\s*\\}\\}/g,\n\t\t\titerate: /\\{\\{~\\s*(?:\\}\\}|([\\s\\S]+?)\\s*\\:\\s*([\\w$]+)\\s*(?:\\:\\s*([\\w$]+))?\\s*\\}\\})/g,\n\t\t\tvarname:\t\"it\",\n\t\t\tstrip:\t\ttrue,\n\t\t\tappend:\t\ttrue,\n\t\t\tselfcontained: false,\n\t\t\tdoNotSkipEncoded: false\n\t\t},\n\t\ttemplate: undefined, //fn, compile template\n\t\tcompile: undefined //fn, for express\n\t}, _globals;\n\n\tdoT.encodeHTMLSource = function(doNotSkipEncoded) {\n\t\tvar encodeHTMLRules = { \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\", \"/\": \"/\" },\n\t\t\tmatchHTML = doNotSkipEncoded ? /[&<>\"'\\/]/g : /&(?!#?\\w+;)|<|>|\"|'|\\//g;\n\t\treturn function(code) {\n\t\t\treturn code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : \"\";\n\t\t};\n\t};\n\n\t_globals = (function(){ return this || (0,eval)(\"this\"); }());\n\n\tif (typeof module !== \"undefined\" && module.exports) {\n\t\tmodule.exports = doT;\n\t} else if (typeof define === \"function\" && define.amd) {\n\t\tdefine(function(){return doT;});\n\t} else {\n\t\t_globals.doT = doT;\n\t}\n\n\tvar startend = {\n\t\tappend: { start: \"'+(\", end: \")+'\", startencode: \"'+encodeHTML(\" },\n\t\tsplit: { start: \"';out+=(\", end: \");out+='\", startencode: \"';out+=encodeHTML(\" }\n\t}, skip = /$^/;\n\n\tfunction resolveDefs(c, block, def) {\n\t\treturn ((typeof block === \"string\") ? block : block.toString())\n\t\t.replace(c.define || skip, function(m, code, assign, value) {\n\t\t\tif (code.indexOf(\"def.\") === 0) {\n\t\t\t\tcode = code.substring(4);\n\t\t\t}\n\t\t\tif (!(code in def)) {\n\t\t\t\tif (assign === \":\") {\n\t\t\t\t\tif (c.defineParams) value.replace(c.defineParams, function(m, param, v) {\n\t\t\t\t\t\tdef[code] = {arg: param, text: v};\n\t\t\t\t\t});\n\t\t\t\t\tif (!(code in def)) def[code]= value;\n\t\t\t\t} else {\n\t\t\t\t\tnew Function(\"def\", \"def['\"+code+\"']=\" + value)(def);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn \"\";\n\t\t})\n\t\t.replace(c.use || skip, function(m, code) {\n\t\t\tif (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {\n\t\t\t\tif (def[d] && def[d].arg && param) {\n\t\t\t\t\tvar rw = (d+\":\"+param).replace(/'|\\\\/g, \"_\");\n\t\t\t\t\tdef.__exp = def.__exp || {};\n\t\t\t\t\tdef.__exp[rw] = def[d].text.replace(new RegExp(\"(^|[^\\\\w$])\" + def[d].arg + \"([^\\\\w$])\", \"g\"), \"$1\" + param + \"$2\");\n\t\t\t\t\treturn s + \"def.__exp['\"+rw+\"']\";\n\t\t\t\t}\n\t\t\t});\n\t\t\tvar v = new Function(\"def\", \"return \" + code)(def);\n\t\t\treturn v ? resolveDefs(c, v, def) : v;\n\t\t});\n\t}\n\n\tfunction unescape(code) {\n\t\treturn code.replace(/\\\\('|\\\\)/g, \"$1\").replace(/[\\r\\t\\n]/g, \" \");\n\t}\n\n\tdoT.template = function(tmpl, c, def) {\n\t\tc = c || doT.templateSettings;\n\t\tvar cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,\n\t\t\tstr = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;\n\n\t\tstr = (\"var out='\" + (c.strip ? str.replace(/(^|\\r|\\n)\\t* +| +\\t*(\\r|\\n|$)/g,\" \")\n\t\t\t\t\t.replace(/\\r|\\n|\\t|\\/\\*[\\s\\S]*?\\*\\//g,\"\"): str)\n\t\t\t.replace(/'|\\\\/g, \"\\\\$&\")\n\t\t\t.replace(c.interpolate || skip, function(m, code) {\n\t\t\t\treturn cse.start + unescape(code) + cse.end;\n\t\t\t})\n\t\t\t.replace(c.encode || skip, function(m, code) {\n\t\t\t\tneedhtmlencode = true;\n\t\t\t\treturn cse.startencode + unescape(code) + cse.end;\n\t\t\t})\n\t\t\t.replace(c.conditional || skip, function(m, elsecase, code) {\n\t\t\t\treturn elsecase ?\n\t\t\t\t\t(code ? \"';}else if(\" + unescape(code) + \"){out+='\" : \"';}else{out+='\") :\n\t\t\t\t\t(code ? \"';if(\" + unescape(code) + \"){out+='\" : \"';}out+='\");\n\t\t\t})\n\t\t\t.replace(c.iterate || skip, function(m, iterate, vname, iname) {\n\t\t\t\tif (!iterate) return \"';} } out+='\";\n\t\t\t\tsid+=1; indv=iname || \"i\"+sid; iterate=unescape(iterate);\n\t\t\t\treturn \"';var arr\"+sid+\"=\"+iterate+\";if(arr\"+sid+\"){var \"+vname+\",\"+indv+\"=-1,l\"+sid+\"=arr\"+sid+\".length-1;while(\"+indv+\"= 0) this.splice(index, 1);\n return this;\n}\n\n\n/**\n * Returns new array created from array-like object (e.g., `arguments` pseudo-array).\n *\n * @param {Array-like} self Object with numeric property length\n * @return {Array}\n */\nfunction toArray() {\n return arrayMethods.slice.call(this);\n}\n\n\n/**\n * Returns an object created from the array of `keys` and optional array of `values`.\n *\n * @param {Array} self Array of keys\n * @param {Array|any} values Optional array of values or the value to be assigned to each property.\n * @return {Object}\n */\nfunction object(values) {\n var obj = {}\n , valuesIsArray = Array.isArray(values);\n arrayMethods.forEach.call(this, function(key, index) {\n obj[key] = valuesIsArray ? values[index] : values;\n });\n\n return obj;\n}\n\n\n/**\n * Maps array to object.\n * Array elements become keys, value are taken from `callback`.\n * \n * @param {Array} self An array which values will become keys of the result\n * @param {Function} callback Callback is passed `value`, `index` and `self` and should return value that will be included in the result.\n * @param {Object} thisArg An optional context of iteration (the valueof `this`), will be undefined if this parameter is not passed.\n * @return {Object}\n */\nfunction mapToObject(callback, thisArg) {\n var result = {};\n Array.prototype.forEach.call(this, function(value, index) {\n result[value] = callback.call(thisArg, value, index, this);\n }, this);\n return result;\n}\n\n\n/**\n * Returns array without duplicates. Does not modify original array.\n *\n * @param {Array} self original array\n * @param {Function} callback comparison function, should return true for equal items, \"===\" is used if not passed.\n * @return {Array}\n */\nfunction unique(callback) {\n var filtered = [];\n if (! callback)\n itemIndex = itemIndexOf;\n\n this.forEach(function(item) {\n var index = itemIndex(item);\n if (index == -1)\n filtered.push(item);\n });\n\n return filtered;\n\n\n function itemIndex(item) {\n return arrayMethods.findIndex.call(filtered, function(it) {\n return callback(item, it);\n });\n }\n\n function itemIndexOf(item) {\n return filtered.indexOf(item);\n }\n}\n\n\n/**\n * Iterates array and elements that are arrays calling callback with each element that is not an array. Can be used to iterate over arguments list to avoid checking whether array or list of parameters is passed.\n *\n * @param {Array|Array-like} self array of elements and arraysto iterate.\n * @param {Function} callback called for each item that is not an array. Callback is passed item, index and original array as parameters.\n * @param {Any} thisArg optional callback envocation context\n */\nfunction deepForEach(callback, thisArg) {\n var index = 0, arr = this;\n _deepForEach.call(this);\n\n function _deepForEach() {\n arrayMethods.forEach.call(this, function(value) {\n if (Array.isArray(value))\n _deepForEach.call(value);\n else\n callback.call(thisArg, value, index++, arr);\n });\n }\n}\n",
"'use strict';\n\n\nvar makeProtoFunction = require('./utils').makeProtoFunction\n , repeat = require('./proto_util').repeat;\n\n\n/**\n * - [makeFunction](#makeFunction)\n * - [partial](#partial)\n * - [partialRight](#partialRight)\n * - [memoize](#memoize)\n * - [delay](#delay)\n * - [defer](#defer)\n * - [delayed](#delayed)\n * - [deferred](#deferred)\n * - [deferTicks](#deferTicks)\n * - [delayMethod](#delayMethod)\n * - [deferMethod](#deferMethod)\n * - [debounce](#debounce)\n * - [throttle](#throttle)\n * - [once](#once)\n * - [waitFor](#waitFor)\n * - [not](#not)\n *\n * These methods can be [chained](proto.js.html#Proto)\n */\nvar functionMethods = module.exports = {\n makeFunction: makeFunction,\n partial: partial,\n partialRight: partialRight,\n memoize: memoize,\n delay: delay,\n defer: defer,\n delayed: delayed,\n deferred: deferred,\n deferTicks: deferTicks,\n delayMethod: delayMethod,\n deferMethod: deferMethod,\n debounce: debounce,\n throttle: throttle,\n once: once,\n waitFor: waitFor,\n not: not\n};\n\n\nvar slice = Array.prototype.slice;\n\n\n/**\n * Similarly to Function constructor creates a function from code.\n * Unlike Function constructor, the first argument is a function name\n *\n * @param {String} name new function name\n * @param {String} arg1, arg2, ... the names of function parameters\n * @param {String} funcBody function body\n * @return {Function}\n */\nfunction makeFunction(arg1, arg2, funcBody) {\n var name = this\n , count = arguments.length - 1\n , funcBody = arguments[count]\n , func\n , code = '';\n for (var i = 0; i < count; i++)\n code += ', ' + arguments[i];\n code = ['func = function ', name, '(', code.slice(2), ') {\\n'\n , funcBody, '\\n}'].join('');\n eval(code);\n return func;\n}\n\n\n/**\n * Creates a function as a result of partial function application with the passed parameters.\n *\n * @param {Function} self Function to be applied\n * @param {List} arguments Arguments after self will be prepended to the original function call when the partial function is called.\n * @return {Function}\n */\nfunction partial() { // , ... arguments\n var func = this;\n var args = slice.call(arguments);\n return function() {\n return func.apply(this, args.concat(slice.call(arguments)));\n };\n}\n\n\n/**\n * Creates a function as a result of partial function application with the passed parameters, but parameters are appended on the right.\n *\n * @param {Function} self Function to be applied\n * @param {List} arguments Arguments after self will be appended on the right to the original function call when the partial function is called.\n * @return {Function}\n */\nfunction partialRight() { // , ... arguments\n var func = this;\n var args = slice.call(arguments);\n return function() {\n return func.apply(this, slice.call(arguments).concat(args));\n };\n}\n\n\n/**\n * Creates a memoized version of the function using supplied hash function as key. If the hash is not supplied, uses its first parameter as the hash.\n * \n * @param {Function} self function to be memoized\n * @param {Function} hashFunc optional hash function that is passed all function arguments and should return cache key.\n * @param {Integer} limit optional maximum number of results to be stored in the cache. 1000 by default.\n * @return {Function} memoized function\n */\nfunction memoize(hashFunc, limit) {\n var func = this;\n var cache = {}, keysList = [];\n limit = limit || 1000;\n\n return function() {\n var key = hashFunc ? hashFunc.apply(this, arguments) : arguments[0];\n if (cache.hasOwnProperty(key))\n return cache[key];\n\n var result = cache[key] = func.apply(this, arguments);\n keysList.push(key);\n\n if (keysList.length > limit)\n delete cache[keysList.shift()];\n\n return result;\n };\n}\n\n\n/**\n * Delays function execution by a given time in milliseconds.\n * The context in function when it is executed is set to `null`.\n *\n * @param {Function} self function that execution has to be delayed\n * @param {Number} wait approximate dalay time in milliseconds\n * @param {List} arguments optional arguments that will be passed to the function\n */\nfunction delay(wait) { // , arguments\n var args = slice.call(arguments, 1);\n return _delay(this, wait, args);\n}\n \n\n/**\n * Defers function execution (executes as soon as execution loop becomes free)\n * The context in function when it is executed is set to `null`.\n *\n * @param {Function} self function that execution has to be delayed\n * @param {List} arguments optional arguments that will be passed to the function\n */\nfunction defer() { // , arguments\n return _delay(this, 1, arguments);\n}\n\nfunction _delay(func, wait, args, context) {\n return setTimeout(func.apply.bind(func, context || null, args), wait);\n}\n\n/**\n * Same as _.defer, takes first argument as the function to be deferred\n */\nvar deferFunc = makeProtoFunction(defer);\n\n/**\n * Defers function execution for `times` ticks (executes after execution loop becomes free `times` times)\n * The context in function when it is executed is set to `null`.\n *\n * @param {Function} self function that execution has to be delayed\n * @param {Integer} ticks number of times to defer execution\n * @param {List} arguments optional arguments that will be passed to the function\n */\nfunction deferTicks(ticks) { // , arguments\n if (ticks < 2) return defer.apply(this, arguments);\n var args = repeat.call(deferFunc, ticks - 1);\n args = args.concat(this, slice.call(arguments, 1)); \n return deferFunc.apply(null, args);\n}\n\n\n/**\n * Works like _.delay but allows to defer method call of `self` which will be the first _.delayMethod parameter\n *\n * @param {Object} self object to delay method call of\n * @param {Function|String} funcOrMethodName function or name of method\n * @param {Number} wait approximate dalay time in milliseconds\n * @param {List} arguments arguments to pass to method\n */\nfunction delayMethod(funcOrMethodName, wait) { // , ... arguments\n var args = slice.call(arguments, 2);\n return _delayMethod(this, funcOrMethodName, wait, args);\n}\n\n\n/**\n * Works like _.defer but allows to defer method call of `self` which will be the first _.deferMethod parameter\n *\n * @param {Object} self object to defer method call of\n * @param {Function|String} funcOrMethodName function or name of method\n * @param {List} arguments arguments to pass to method\n */\nfunction deferMethod(funcOrMethodName) { // , ... arguments\n var args = slice.call(arguments, 1);\n return _delayMethod(this, funcOrMethodName, 1, args);\n}\n\nfunction _delayMethod(object, funcOrMethodName, wait, args) {\n return setTimeout(function() {\n var func = typeof funcOrMethodName == 'string'\n ? object[funcOrMethodName]\n : funcOrMethodName;\n func.apply(object, args);\n }, wait);\n}\n\n\n/**\n * Returns function that will execute the original function `wait` ms after it has been called\n * The context in function when it is executed is set to `null`.\n * Arguments passed to the function are appended to the arguments passed to delayed.\n *\n * @param {Function} self function which execution has to be deferred\n * @param {Number} wait approximate dalay time in milliseconds\n * @param {List} arguments optional arguments that will be passed to the function\n * @return {Function}\n */\nfunction delayed(wait) { //, ... arguments\n var func = this\n , args = slice.call(arguments, 1);\n return function() { // ... arguments\n var passArgs = args.concat(slice.call(arguments));\n return _delay(func, wait, passArgs, this);\n };\n}\n\n\n/**\n * Returns function that will execute the original function on the next tick once it has been called\n * The context in function when it is executed is set to `null`.\n * Arguments passed to the function are appended to the arguments passed to deferred.\n *\n * @param {Function} self function which execution has to be deferred\n * @param {List} arguments optional arguments that will be passed to the function\n * @return {Function}\n */\nfunction deferred() { //, ... arguments\n var func = this\n , args = slice.call(arguments);\n return function() { // ... arguments\n var passArgs = args.concat(slice.call(arguments));\n return _delay(func, 1, passArgs, this);\n };\n}\n\n\n/**\n * Creates a function that will call original function once it has not been called for a specified time\n *\n * @param {Function} self function that execution has to be delayed\n * @param {Number} wait approximate dalay time in milliseconds\n * @param {Boolean} immediate true to invoke funciton immediately and then ignore following calls for wait milliseconds\n * @return {Function}\n */\nfunction debounce(wait, immediate) {\n var func = this; // first parameter of _.debounce\n var timeout, args, context, timestamp, result;\n return function() {\n context = this; // store original context\n args = arguments;\n timestamp = Date.now();\n var callNow = immediate && ! timeout;\n if (! timeout)\n timeout = setTimeout(later, wait);\n if (callNow)\n result = func.apply(context, args);\n return result;\n\n function later() {\n var last = Date.now() - timestamp;\n if (last < wait)\n timeout = setTimeout(later, wait - last);\n else {\n timeout = null;\n if (! immediate)\n result = func.apply(context, args);\n }\n }\n };\n}\n\n\n/**\n * Returns a function, that, when invoked, will only be triggered at most once during a given window of time. \n *\n * @param {Function} self function that execution has to be delayed\n * @param {Number} wait approximate delay time in milliseconds\n * @param {Object} options `{leading: false}` to disable the execution on the leading edge\n * @return {Function}\n */\nfunction throttle(wait, options) {\n var func = this; // first parameter of _.throttle\n var context, args, result;\n var timeout = null;\n var previous = 0;\n options || (options = {});\n\n return function() {\n var now = Date.now();\n if (!previous && options.leading === false) previous = now;\n var remaining = wait - (now - previous);\n context = this;\n args = arguments;\n if (remaining <= 0) {\n clearTimeout(timeout);\n timeout = null;\n previous = now;\n result = func.apply(context, args);\n } else if (!timeout && options.trailing !== false)\n timeout = setTimeout(later, remaining);\n\n return result;\n };\n\n function later() {\n previous = options.leading === false ? 0 : Date.now();\n timeout = null;\n result = func.apply(context, args);\n }\n}\n\n\n/**\n * Call passed function only once\n * @return {Function} self\n */\nfunction once() {\n var func = this\n , ran = false\n , memo;\n return function() {\n if (ran) return memo;\n ran = true;\n memo = func.apply(this, arguments);\n func = null;\n return memo;\n };\n}\n\n\n/**\n * Execute a function when the condition function returns a truthy value\n * it runs the condition function every `checkInterval` milliseconds (default 50)\n *\n * @param {Function} self function: if it returns true the callback is executed\n * @param {Function} callback runs when the condition is true\n * @param {Number} maxTimeout timeout before giving up (time in milliseconds)\n * @param {Function} timedOutFunc a function called if timeout is reached\n * @param {Number} checkInterval time interval when you run the condition function (time in milliseconds), default 50 ms\n */\nfunction waitFor(callback, maxTimeout, timedOutFunc, checkInterval){\n var start = Date.now();\n var condition = this;\n checkInterval = checkInterval || 50;\n var interval = setInterval(testCondition, checkInterval);\n\n function testCondition() {\n if (condition()) callback();\n else if (Date.now() - start >= maxTimeout)\n timedOutFunc && timedOutFunc();\n else return;\n clearInterval(interval);\n };\n}\n\n\n/**\n * returns the function that negates (! operator) the result of the original function\n * @param {Function} self function to negate\n * @return {Function}\n */\nfunction not() {\n var func = this;\n return function() {\n return !func.apply(this, arguments);\n };\n}\n",
@@ -302,10 +266,6 @@
"'use strict';\n\n/**\n * - [extendProto](#extendProto)\n * - [createSubclass](#createSubclass)\n * - [makeSubclass](#makeSubclass)\n * - [newApply](#newApply)\n *\n * These methods can be [chained](proto.js.html#Proto)\n */\nvar prototypeMethods = module.exports = {\n extendProto: extendProto,\n createSubclass: createSubclass,\n makeSubclass: makeSubclass,\n newApply: newApply\n};\n\n\nvar __ = require('./proto_object');\n\n__.extend.call(__, require('./proto_function'));\n\n\n/**\n * Adds non-enumerable, non-configurable and non-writable properties to the prototype of constructor function.\n * Usage:\n * ```\n * function MyClass() {}\n * _.extendProto(MyClass, {\n * method1: function() {},\n * method2: function() {}\n * });\n * ```\n * To extend class via object:\n * ```\n * _.extendProto(obj.constructor, methods);\n * ```\n * Returns passed constructor, so functions _.extendProto, [_.extend](object.js.html#extend) and _.makeSubclass can be [chained](proto.js.html). \n *\n * @param {Function} self constructor function\n * @param {Object} methods a map of functions, keys will be instance methods (properties of the constructor prototype)\n * @return {Function}\n */\nfunction extendProto(methods) {\n var propDescriptors = {};\n\n __.eachKey.call(methods, function(method, name) {\n propDescriptors[name] = {\n enumerable: false,\n configurable: false,\n writable: false,\n value: method\n };\n });\n\n Object.defineProperties(this.prototype, propDescriptors);\n return this;\n}\n\n\n/**\n * Makes a subclass of class `thisClass`.\n * The returned function will have specified `name` if supplied.\n * The constructor of superclass will be called in subclass constructor by default unless `applyConstructor === false` (not just falsy).\n * Copies `thisClass` class methods to created subclass. For them to work correctly they should use `this` to refer to the class rather than explicit superclass name.\n *\n * @param {Function} thisClass A class to make subclass of\n * @param {String} name Optional name of subclass constructor function\n * @param {Boolean} applyConstructor Optional false value (not falsy) to prevent call of inherited constructor in the constructor of subclass\n * @return {Function}\n */\nfunction createSubclass(name, applyConstructor) {\n var thisClass = this;\n var subclass;\n\n // name is optional\n name = name || '';\n\n // apply superclass constructor\n var constructorCode = applyConstructor === false\n ? ''\n : 'thisClass.apply(this, arguments);';\n\n eval('subclass = function ' + name + '(){ ' + constructorCode + ' }');\n\n makeSubclass.call(subclass, thisClass);\n\n // copy class methods\n // - for them to work correctly they should not explictly use superclass name\n // and use \"this\" instead\n __.deepExtend.call(subclass, thisClass, true);\n\n return subclass;\n}\n\n\n/**\n * Sets up prototype chain to change `thisClass` (a constructor function) so that it becomes a subclass of `Superclass`.\n * Returns `thisClass` so it can be [chained](proto.js.html) with _.extendProto and [_.extend](object.js.html#extend).\n *\n * @param {Function} thisClass A class that will become a subclass of Superclass\n * @param {Function} Superclass A class that will become a superclass of thisClass\n * @return {Function}\n */\nfunction makeSubclass(Superclass) {\n // prototype chain\n this.prototype = Object.create(Superclass.prototype);\n \n // subclass identity\n extendProto.call(this, {\n constructor: this\n });\n return this;\n}\n\n\n/**\n * Calls constructor `this` with arguments passed as array\n * \n * @param {Function} thisClass A class constructor that will be called\n * @return {Array|Array-like} args Array of arguments that will be passed to constructor\n */\nfunction newApply(args) {\n if (! Array.isArray(args))\n args = Array.prototype.slice.call(args);\n // \"null\" is context to pass to class constructor, first parameter of bind\n var args = [null].concat(args);\n return new (Function.prototype.bind.apply(this, args));\n}\n",
"'use strict';\n\n\nvar __ = require('./proto_object');\n\n\n/**\n * - [firstUpperCase](#firstUpperCase)\n * - [firstLowerCase](#firstLowerCase)\n * - [toRegExp](#toRegExp)\n * - [toFunction](#toFunction)\n * - [toDate](#toDate)\n * - [toQueryString](#toQueryString)\n * - [fromQueryString](#fromQueryString)\n * - [jsonParse](#jsonParse)\n * - [hashCode](#hashCode)\n * - [unPrefix](#unPrefix)\n */\n var stringMethods = module.exports = {\n firstUpperCase: firstUpperCase,\n firstLowerCase: firstLowerCase,\n toRegExp: toRegExp,\n toFunction: toFunction,\n toDate: toDate,\n toQueryString: toQueryString,\n fromQueryString: fromQueryString,\n jsonParse: jsonParse,\n hashCode: hashCode,\n unPrefix: unPrefix\n};\n\n\n/**\n * Returns string with the first character changed to upper case.\n *\n * @param {String} self A string that will have its first character replaced\n */\nfunction firstUpperCase() {\n return this ? this[0].toUpperCase() + this.slice(1) : this;\n}\n\n\n/**\n * Returns string with the first character changed to lower case.\n *\n * @param {String} self A string that will have its first character replaced\n */\nfunction firstLowerCase() {\n return this ? this[0].toLowerCase() + this.slice(1) : this;\n}\n\n\n/**\n * Converts string created by `toString` method of RegExp back to RegExp\n *\n * @param {String} self string containing regular expression including enclosing \"/\" symbols and flags\n * @return {RegExp}\n */\nfunction toRegExp() {\n var rx = this.match(regexpStringPattern);\n if (rx) return new RegExp(rx[1], rx[2]);\n}\nvar regexpStringPattern = /^\\/(.*)\\/([gimy]*)$/;\n\n\n/**\n * Converts string created by `toString` method of function back to function\n *\n * @param {String} self string containing full function code\n * @return {Function}\n */\nfunction toFunction() {\n var func;\n var code = 'func = ' + this + ';';\n try {\n eval(code);\n return func;\n } catch(e) {\n return;\n }\n}\n\n\n/**\n * Converts string to date in a safe way so that the resiult is undefined if date is invalid\n *\n * @param {String|Date} self string or date object to convert to VALID date\n * @return {[type]} [description]\n */\nfunction toDate() {\n if (! this) return;\n try {\n var date = new Date(this);\n } catch (e) {}\n if (date && date.getTime && !isNaN(date.getTime()))\n return date;\n}\n\n\n/**\n * Convert params object to a url style query string (without \"?\")\n * \n * @param {Object} self The object hash to be converted\n * @param {Function} encode optional function used to encode data, encodeURIComponent is used if not specified\n * @return {String} the resulting query string\n */\nfunction toQueryString(encode) {\n var qs = ''\n , params = this || {}\n , encode = encode || encodeURIComponent;\n\n __.eachKey.call(params, function(value, key) {\n qs += key + '=' + encode(value) + '&';\n });\n \n return qs.slice(0, -1);\n}\n\n\n/**\n * Convert url style query string (without \"?\") into object hash\n * \n * @param {String} self The string to be converted\n * @param {Function} decode optional decode function, decodeURIComponent will be used if not supplied\n * @return {Object} The resulting object hash\n */\nfunction fromQueryString(decode) {\n var pairs = this.split('&')\n , results = {}\n , decode = decode || decodeURIComponent;\n\n pairs.forEach(function(pair) {\n var splitPair = pair.split('=');\n if (splitPair.length < 2) return;\n var key = splitPair[0]\n , value = decode(splitPair[1] || '');\n if (!key) return;\n results[key] = value;\n });\n\n return results;\n}\n\n\n/**\n * Safe JSON.parse, returns undefined if JSON.parse throws an exception\n *\n * @param {String} self JSON string representation of object\n * @return {Object|undefined}\n */\nfunction jsonParse() {\n try {\n return JSON.parse(this);\n } catch (e) {}\n}\n\n\n/**\n * Dan Bernstein's algorythm to create hash from string\n *\n * @param {String} self string to convert to hash\n * @return {Number}\n */\nfunction hashCode() {\n var hash = 5381\n , str = this\n , len = str.length;\n for (var i = 0; i < len; i++) {\n var char = str.charCodeAt(i);\n hash = ((hash << 5) + hash) + char; /* hash * 33 + c */\n }\n return hash;\n}\n\n\n/**\n * Removes given prefix from the string. If string does not begin from the prefix, returns undefined\n * \n * @param {String} self\n * @return {String}\n */\nfunction unPrefix(str) {\n if (this.indexOf(str) == 0)\n return this.replace(str, '');\n}\n",
"'use strict';\n\n/**\n * - [times](#times)\n * - [repeat](#repeat)\n * - [tap](#tap)\n * - [result](#result)\n * - [identity](#identity)\n * - [property](#property)\n * - [compareProperty](#compareProperty)\n * - [noop](#noop)\n */\nvar utilMethods = module.exports = {\n times: times,\n repeat: repeat,\n tap: tap,\n result: result,\n identity: identity,\n property: property,\n compareProperty: compareProperty,\n noop: noop\n};\n\n\n/**\n * Calls `callback` `self` times with `thisArg` as context. Callback is passed iteration index from 0 to `self-1`\n * \n * @param {Integer} self\n * @param {Function} callback\n * @param {Any} thisArg\n * @return {Array}\n */\nfunction times(callback, thisArg) {\n var arr = Array(Math.max(0, this));\n for (var i = 0; i < this; i++)\n arr[i] = callback.call(thisArg, i);\n return arr;\n}\n\n\n/**\n * Returns array with the first argument repeated `times` times\n * @param {Any} self\n * @param {Integer} times\n * @return {Array[Any]}\n */\nfunction repeat(times) {\n var arr = Array(Math.max(0, times));;\n for (var i = 0; i < times; i++)\n arr[i] = this;\n return arr;\n}\n\n\n/**\n * Function to tap into chained methods and to inspect intermediary result\n *\n * @param {Any} self value that's passed between chained methods\n * @param {Function} func function that will be called with the value (both as context and as the first parameter)\n * @return {Any}\n */\nfunction tap(func) {\n func.call(this, this);\n return this;\n};\n\n\n/**\n * Calls function `self` (first parameter of _.result) with given context and arguments\n * \n * @param {Function|Any} self\n * @param {Any} thisArg context\n * @param {List} arguments extra arguments\n * @return {Any}\n */\nfunction result(thisArg) { //, arguments\n var args = Array.prototype.slice.call(arguments, 1);\n return typeof this == 'function'\n ? this.apply(thisArg, args)\n : this;\n}\n\n\n/**\n * Returns self. Useful for using as an iterator if the actual value needs to be returned. Unlike in underscore and lodash, this function is NOT used as default iterator.\n *\n * @param {Any} self \n * @return {Any}\n */\nfunction identity() {\n return this;\n}\n\n\n/**\n * Returns function that picks the property from the object\n *\n * @param {String} self\n * @return {Function}\n */\nfunction property() {\n var key = this;\n return function(obj) {\n return obj[key];\n };\n}\n\n\n/**\n * Returns function that can be used in array sort to sort by a given property\n *\n * @param {String} self\n * @return {Function}\n */\nfunction compareProperty() {\n var key = this;\n return function(a, b) {\n return a[key] < b[key]\n ? -1\n : a[key] > b[key]\n ? 1\n : 0;\n };\n}\n\n\n/**\n * Function that does nothing\n */\nfunction noop() {}\n",
- "'use strict';\n\nvar utils = module.exports = {\n makeProtoInstanceMethod: makeProtoInstanceMethod,\n makeProtoFunction: makeProtoFunction,\n makeFindMethod: makeFindMethod\n}\n\n\nfunction makeProtoInstanceMethod(method) {\n return function() {\n this.self = method.apply(this.self, arguments);\n return this;\n };\n}\n\n\nfunction makeProtoFunction(method) {\n return function() {\n // when the method is executed, the value of \"this\" will be arguments[0],\n // other arguments starting from #1 will passed to method as parameters.\n return method.call.apply(method, arguments);\n };\n}\n\n\nvar _error = new Error;\n\n/**\n * Returns `find` or `findIndex` method, depending on parameter\n *\n * @param {Function} eachMethod - method to use for iteration (forEach for array or eachKey for object)\n * @param {String} findWhat 'value' - returns find method of Array (implemented in ES6) or findValue method of Object, anything else = returns findIndex/findKey methods.\n * @return {Function}\n */\nfunction makeFindMethod(eachMethod, findWhat) {\n var argIndex = findWhat == 'value' ? 0 : 1;\n\n return function findValueOrIndex(callback, thisArg, onlyEnumerable) {\n var caughtError;\n try {\n eachMethod.call(this, testItem, thisArg, onlyEnumerable);\n } catch (found) {\n if (found === _error) throw caughtError;\n else return found;\n }\n // if looking for index and not found, return -1\n if (argIndex && eachMethod == Array.prototype.forEach)\n return -1; \n\n function testItem(value, index, self) {\n var test;\n try {\n test = callback.call(this, value, index, self);\n } catch(err) {\n caughtError = err;\n throw _error;\n }\n if (test)\n throw arguments[argIndex];\n }\n }\n}\n",
- "arguments[4][141][0].apply(exports,arguments)",
- "arguments[4][142][0].apply(exports,arguments)",
- "arguments[4][146][0].apply(exports,arguments)",
- "arguments[4][147][0].apply(exports,arguments)"
+ "'use strict';\n\nvar utils = module.exports = {\n makeProtoInstanceMethod: makeProtoInstanceMethod,\n makeProtoFunction: makeProtoFunction,\n makeFindMethod: makeFindMethod\n}\n\n\nfunction makeProtoInstanceMethod(method) {\n return function() {\n this.self = method.apply(this.self, arguments);\n return this;\n };\n}\n\n\nfunction makeProtoFunction(method) {\n return function() {\n // when the method is executed, the value of \"this\" will be arguments[0],\n // other arguments starting from #1 will passed to method as parameters.\n return method.call.apply(method, arguments);\n };\n}\n\n\nvar _error = new Error;\n\n/**\n * Returns `find` or `findIndex` method, depending on parameter\n *\n * @param {Function} eachMethod - method to use for iteration (forEach for array or eachKey for object)\n * @param {String} findWhat 'value' - returns find method of Array (implemented in ES6) or findValue method of Object, anything else = returns findIndex/findKey methods.\n * @return {Function}\n */\nfunction makeFindMethod(eachMethod, findWhat) {\n var argIndex = findWhat == 'value' ? 0 : 1;\n\n return function findValueOrIndex(callback, thisArg, onlyEnumerable) {\n var caughtError;\n try {\n eachMethod.call(this, testItem, thisArg, onlyEnumerable);\n } catch (found) {\n if (found === _error) throw caughtError;\n else return found;\n }\n // if looking for index and not found, return -1\n if (argIndex && eachMethod == Array.prototype.forEach)\n return -1; \n\n function testItem(value, index, self) {\n var test;\n try {\n test = callback.call(this, value, index, self);\n } catch(err) {\n caughtError = err;\n throw _error;\n }\n if (test)\n throw arguments[argIndex];\n }\n }\n}\n"
]
}
\ No newline at end of file
diff --git a/milo.min.js b/milo.min.js
index 3c1e988..f74e519 100644
--- a/milo.min.js
+++ b/milo.min.js
@@ -1,9 +1,8 @@
-!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;gthis._maxLength){var b=this.actions.shift();b.destroy()}return this.position=this.actions.length,this.position-1}function e(){this.actions.length&&(this.position--,this.actions.length--)}function f(){for(var a=this.position;a=0||b.indexOf(v.firstLowerCase(a))>=0)}var r=a("../abstract/facet"),s=a("../messenger"),t=a("../util/error").Facet,u=a("./c_utils"),v=a("mol-proto"),w=v.createSubclass(r,"ComponentFacet");b.exports=w;var x=v.partial(k,i),y=v.partial(k,j);v.extendProto(w,{init:c,start:e,check:g,destroy:h,onConfigMessages:f,domParent:i,postDomParent:x,scopeParent:j,postScopeParent:y,getMessageSource:m,dispatchSourceMessage:n,_createMessenger:d,_setMessageSource:l,_createMessageSource:o,_createMessageSourceWithAPI:p}),v.extend(w,{requiresFacet:q});var z="_messenger";s.useWith(w,z,s.defaultMethods)},{"../abstract/facet":1,"../messenger":67,"../util/error":98,"./c_utils":34,"mol-proto":150}],18:[function(a,b){"use strict";function c(){return n(this.owner.el,this.scope,!1)}function d(){m.prototype.start.apply(this,arguments),this.scope=new o(this.owner.el,this)}function e(a){function b(){throw new Error("path "+a+" is invalid")}a=a.split(".");var c=a.length;(a[0]||2>c)&&b();for(var d=this.owner,e=1;c>e;e++){var f=a[e];if(u.test(f)||b(),!d.container)return;if(d=d.container.scope[f],!d)return}return d}function f(a){var b={scope:{}};return a!==!1&&this.scope._each(function(a,c){b.scope[c]=a._getState()}),b}function g(a){p.eachKey(a.scope,function(a,b){var c=this.scope[b];c?c.setState(a):s.warn('component "'+b+'" does not exist on scope')},this)}function h(){this.scope._each(function(a){a.destroy()}),this.scope._detachElement(),m.prototype.destroy.apply(this,arguments)}function i(a,b){r.unwrapElement(this.owner.el),this.scope&&this.scope._each(function(b){b.remove(),a!==!1&&b.rename(void 0,!1),this.owner.scope&&this.owner.scope._add(b)},this),b!==!1&&this.owner.destroy()}function j(a){this.scope._add(a),this.owner.el.appendChild(a.el)}function k(a,b){this.scope._add(a),this.el.insertBefore(a.el,b&&b.el)}function l(a){this.scope._remove(a),this.owner.el.removeChild(a.el)}var m=a("../c_facet"),n=a("../../binder"),o=a("../scope"),p=a("mol-proto"),q=a("./cf_registry"),r=a("../../util/dom"),s=a("../../util/logger"),t=p.createSubclass(m,"Container");p.extendProto(t,{start:d,path:e,getState:f,setState:g,binder:c,destroy:h,unwrap:i,append:j,insertBefore:k,remove:l}),q.add(t),b.exports=t;var u=/^[A-Za-z][A-Za-z0-9\_\$]*$/},{"../../binder":9,"../../util/dom":94,"../../util/logger":102,"../c_facet":17,"../scope":41,"./cf_registry":31,"mol-proto":150}],19:[function(a,b){"use strict";function c(){H.wrapMessengerMethods.call(this),C.prototype.start.apply(this,arguments),this.elData=G(this.owner.el),this._dataChangesQueue=[],this._prepareMessageSource(),this._path="."+this.owner.name,this._value=this.get(),this.onSync("",e),this.onSync("datachangesfinished",h),this.onSync("childdata",j),this.onSync("changedata",K)}function d(){var a=new F(this.owner),b=new E(this,R,a,this.owner);this._setMessageSource(b),O.defineProperty(this,"_dataEventsSource",b),B.prototype._createProxyMethod.call(a,"value","value",this)}function e(a,b){if(this._bubbleUpDataChange(b),this._queueDataChange(b),""===b.path){var c=L(b);this.postMessage("datachangesfinished",{transaction:c})}}function f(a){var b=this.scopeParent();if(b){var c=O.clone(a);c.path=(this._path||"."+this.owner.name)+c.path,b.postMessage("childdata",c||a)}}function g(a){this._dataChangesQueue.push(a)}function h(a,b){this._postDataChanges(b.inTransaction);var c=this.scopeParent();c&&c.postMessage("datachangesfinished",b)}function i(a){var b=this._dataChangesQueue.reverse();this.postMessageSync("datachanges",{changes:b,transaction:a}),this._dataChangesQueue=[]}function j(a,b){this.postMessage(b.path,b),this._bubbleUpDataChange(b),this._queueDataChange(b)}function k(a){var b=L(k),c=this.config.set;if("function"==typeof c){var d=c.call(this.owner,a);return d}M(this._set,b);var e=this._value,f=this._set(a),g={path:"",type:"changed",newValue:f,oldValue:e};return M(g,b),this.postMessage("",g),f}function l(a){function b(a,b,c,e){var f=e.replace("$$",c),g=this.path(f,"undefined"!=typeof b);g&&(M(g.set,d),a[c]=g.set(b))}var c,d=L(l);if(null!=a&&"object"==typeof a)if(Array.isArray(a)){c=[];var e=this.owner.list;if(e){var f=e.count(),g=a.length-f;g>=3&&(e._addItems(g),e._updateDataPaths(f,e.count())),a.forEach(function(a,d){b.call(this,c,a,d,"[$$]")},this);for(var h=e.count(),i=h-a.length;i-->0;)e._removeItem(a.length)}else P.warn("Data: setting array data without List facet")}else c={},O.eachKey(a,function(a,d){b.call(this,c,a,d,".$$")},this);else c=this._setScalarValue(a);return this._value=c,c}function m(){var a=L(m),b=this.config.del;if("function"==typeof b){var c=b.call(this.owner);return N.call(this,a),c}var d=this._value;M(this._del,a),this._del();var e={path:"",type:"deleted",oldValue:d};M(e,a),this.postMessage("",e)}function n(){var a=L(n);M(this._set,a),this._set()}function o(a){return this.elData.set(this.owner.el,a)}function p(a){var b=this.config.get;return"function"==typeof b?b.call(this.owner,a):this._get(a)}function q(a){if(a!==!1){var b,c=this.owner;return c.list?(b=[],c.list.each(function(a,c){b[c]=a.data.get()}),c.container&&c.container.scope._each(function(a,d){!c.list.contains(a)&&a.data&&(b[d]=a.data.get())})):c.container?(b={},c.container.scope._each(function(a,c){a.data&&(b[c]=a.data.get())})):b=this._getScalarValue(),this._value=b,b}}function r(){return this.elData.get(this.owner.el)}function s(){var a,b=L(s),c=this.config.splice;if("function"==typeof c)return a=c.apply(this.owner,arguments),N.call(this,b),a;if(M(this._splice,b),a=this._splice.apply(this,arguments)){var d={path:"",type:"splice",index:a.spliceIndex,removed:a.removed,addedCount:a.addedCount,newValue:this._value};return M(d,b),this.postMessage("",d),a.removed}}function t(a,b){var c=L(t),d=this.owner.list;if(!d)return P.warn("Data: cannot use splice method without List facet");var e=[],f=d.count();if(arguments[0]=a=J.normalizeSpliceIndex(a,f),b>0&&f>0){for(var g=a;a+b>g;g++){var h=d.item(a);if(h){var i=h.data.get();d._removeItem(a)}else P.warn("Data: no item for index",g);e.push(i)}d._updateDataPaths(a,d.count())}var j=[],k=arguments.length,l=k>2,m=k-2;if(l){d._addItems(m,a);for(var g=2,n=a;k>g;g++,n++){var h=d.item(n);if(h){M(h.data.set,c);var i=h.data.set(arguments[g])}else P.warn("Data: no item for index",n);j.push(i)}d._updateDataPaths(a,d.count())}return this._value=this.get(),{spliceIndex:a,removed:e,addedCount:l?m:0}
-}function u(){var a=this.config.len;return"function"==typeof a?a.call(this.owner):this._len()}function v(){return this.owner.list?this.owner.list.count():void P.error("Data: len called without list facet")}function w(a,b){if(!a)return this;for(var c=H.parseAccessPath(a),d=this.owner,e=0,f=c.length;f>e;e++){var g=c[e],h=H.getPathNodeKey(g);if("array"==g.syntax&&d.list){var i=d.list.item(h);i||b===!1||(i=d.list._addItem(h),i.data._path=g.property),d=i}else d.container&&(d=d.container.scope[h]);var j=d&&d.data;if(!j)break}return j}function x(){return this._path}function y(){var a=this._path;return"["==a[0]?+a.slice(1,-1):a.slice(1)}function z(a){return{state:this.get(a)}}function A(a){return this.set(a.state)}var B=a("../../abstract/mixin"),C=a("../c_facet"),D=a("./cf_registry"),E=(a("../../messenger"),a("../msg_src/dom_events")),F=a("../msg_api/data"),G=a("../msg_api/de_data"),H=a("../../model/path_utils"),I=a("../../model/m_path"),J=a("../../model/model_utils"),K=a("../../model/change_data"),L=K.getTransactionFlag,M=K.setTransactionFlag,N=K.postTransactionFinished,O=a("mol-proto"),P=a("../../util/logger"),Q=O.createSubclass(C,"Data");O.extendProto(Q,{start:c,getState:z,setState:A,get:p,set:k,del:m,splice:s,len:u,path:w,getPath:x,getKey:y,_get:q,_set:l,_del:n,_splice:t,_len:v,_setScalarValue:o,_getScalarValue:r,_bubbleUpDataChange:f,_queueDataChange:g,_postDataChanges:i,_prepareMessageSource:d}),D.add(Q),b.exports=Q,["push","pop","unshift","shift"].forEach(function(a){var b=I.prototype[a];O.defineProperty(Q.prototype,a,b)});var R={trigger:"trigger"}},{"../../abstract/mixin":3,"../../messenger":67,"../../model/change_data":73,"../../model/m_path":76,"../../model/model_utils":77,"../../model/path_utils":79,"../../util/logger":102,"../c_facet":17,"../msg_api/data":36,"../msg_api/de_data":37,"../msg_src/dom_events":39,"./cf_registry":31,"mol-proto":150}],20:[function(a,b){"use strict";function c(a){var b=a.domConfig||{},c=b.tagName||"div",e=document.createElement(c),f=a.content,g=a.template;return d(e,b),"string"==typeof f&&(e.innerHTML=g?I.template(g)({content:f}):f),e}function d(a,b){var c=b&&b.cls,d=b&&b.attributes;d&&D.eachKey(d,function(b,c){a.setAttribute(c,b)}),c&&j(a,"add",c)}function e(){var a=this.owner.el;d(a,this.config);var b=window.getComputedStyle(a);this._visible=b&&"none"!=b.display}function f(){this.toggle(!0)}function g(){this.toggle(!1)}function h(a){a="undefined"==typeof a?!this._visible:!!a,this._visible=a;var b=this.owner.el;return b.style.display=a?"block":"none",a}function i(a,b,c){j(this.owner.el,a,b,c)}function j(a,b,c,d){function e(a){g?void 0===d?f[b](a):f[b](a,d):f[b](a)}var f=a.classList,g="toggle"==b;if(Array.isArray(c))c.forEach(e);else{if("string"!=typeof c)throw new G("unknown type of CSS classes parameter");e(c)}}function k(){this.owner.el&&H.detachComponent(this.owner.el)}function l(a,b){if(!this.owner.el)throw new Error("Cannot call setStyle on owner with no element: "+this.owner.constructor.name);this.owner.el.style[a]=b}function m(a){for(var b in a)this.owner.el.style[b]=a[b]}function n(a){return this.owner.el&&this.owner.el.cloneNode(a)}function o(){var a=J.createElement(this.config);return a}function p(){H.removeElement(this.owner.el)}function q(a){this.owner.el.appendChild(a)}function r(a){var b=this.owner.el,c=b.firstChild;c?b.insertBefore(a,c):b.appendChild(a)}function s(a){for(;a.childNodes.length;)this.append(a.childNodes[0])}function t(a){for(;a.childNodes.length;)this.prepend(a.childNodes[a.childNodes.length-1])}function u(a){var b=this.owner.el,c=b.parentNode;c.insertBefore(a,b.nextSibling)}function v(a){var b=this.owner.el,c=b.parentNode;c.insertBefore(a,b)}function w(){var a=this.owner.getScopeParent();a&&a.el.appendChild(this.owner.el)}function x(){return H.children(this.owner.el)}function y(a,b){if(!K.hasOwnProperty(a))throw new G("incorrect find direction: "+a);var c=this.owner.el,d=this.owner.scope,e=document.createTreeWalker(d._rootEl,NodeFilter.SHOW_ELEMENT);e.currentNode=c;for(var f=e[K[a]](),g=(Object.keys(d),!1);f;){var h=new F(f);if(h.node&&(h.parse().validate(),d.hasOwnProperty(h.compName))){var i=d[h.compName];if(!b||b(i)){g=!0;break}}e.currentNode=f,f=e[K[a]]()}return g?i:void 0}function z(){var a=window.getSelection();if(!a.isCollapsed)return!0;var b=a.focusNode&&a.focusNode.textContent,c=b&&" "==b.charAt(0)?1:0;if(a.anchorOffset!=c)return!0;var d=document.createTreeWalker(this.owner.el,NodeFilter.SHOW_TEXT);d.currentNode=a.anchorNode;var e=d.previousNode(),f=e?""==!e.nodeValue.trim():!1;return f}function A(){var a=window.getSelection();if(!a.isCollapsed)return!0;var b=a.focusNode&&a.focusNode.textContent,c=b&&" "==b.charAt(b.length-1)?a.anchorNode.length-1:a.anchorNode.length;if(a.anchorOffset=0;var f=d[e&&e.compClass];return!!q.result(f,this.owner,e,a);default:throw new p("Incorrect allowed components in config")}}else{var g=c&&c.dataTypes;switch(typeof g){case"undefined":return!1;case"string":return a.types.indexOf(g)>=0}}}var j,k=a("../c_facet"),l=a("./cf_registry"),m=a("../msg_src/dom_events"),n=a("../msg_api/drop"),o=a("../../util/dragdrop"),p=a("../../util/error").Drop,q=a("mol-proto"),r=q.createSubclass(k,"Drop");q.extendProto(r,{init:c,start:d}),l.add(r),b.exports=r,j=q.throttle(h,50)},{"../../util/dragdrop":97,"../../util/error":98,"../c_facet":17,"../msg_api/drop":38,"../msg_src/dom_events":39,"./cf_registry":31,"mol-proto":150}],23:[function(a,b){"use strict";function c(){d.prototype.init.apply(this,arguments);var a=new f(this,void 0,void 0,this.owner);this._setMessageSource(a),g.defineProperty(this,i,a)}var d=a("../c_facet"),e=a("./cf_registry"),f=(a("../../messenger"),a("../msg_src/dom_events")),g=a("mol-proto"),h=g.createSubclass(d,"Events");g.extendProto(h,{init:c}),e.add(h),b.exports=h;var i="_domEventsSource";f.useWith(h,i,["trigger"])},{"../../messenger":67,"../c_facet":17,"../msg_src/dom_events":39,"./cf_registry":31,"mol-proto":150}],24:[function(a,b){"use strict";function c(){k.prototype.init.apply(this,arguments);var a=new m(this,void 0,void 0,this.owner);this._setMessageSource(a),n.defineProperty(this,r,a)}function d(){function a(a){b.postMessage("domready",a)}k.prototype.start.apply(this,arguments);var b=this;milo(a)}function e(){k.prototype.destroy.apply(this,arguments)}function f(){return this.owner.el.contentWindow}function g(){var a=this.getWindow().document.readyState;return"loading"!=a?a:!1}function h(){var a=this.getWindow().milo;return this.isReady()&&a&&a.milo_version}function i(a){if("function"==typeof a){var b=this;this.whenMiloReady(function(){b.getWindow().milo(a)})}var c=this.getWindow();return c&&c.milo}function j(a,b){return function(c){function d(){c.apply(e,f)}var e=this,f=n.slice(arguments,1);a.call(this)?d():this.on(b,d)}}var k=a("../c_facet"),l=a("./cf_registry"),m=(a("../../messenger"),a("../msg_src/frame")),n=(a("../../services/de_constrs"),a("mol-proto")),o=n.createSubclass(k,"Frame"),p=j(g,"domready"),q=j(h,"message:miloready");n.extendProto(o,{init:c,start:d,destroy:e,getWindow:f,isReady:g,whenReady:p,isMiloReady:h,whenMiloReady:q,milo:i}),l.add(o),b.exports=o;var r="_messageSource";m.useWith(o,r,["trigger"])},{"../../messenger":67,"../../services/de_constrs":82,"../c_facet":17,"../msg_src/frame":40,"./cf_registry":31,"mol-proto":150}],25:[function(a,b){"use strict";function c(){return{state:{index:this.getIndex()}}}function d(a){this.setIndex(a.state.index)}function e(){return this.index}function f(a){this.index=a}function g(){this.list.removeItem(this.index)}function h(){this.list.extractItem(this.index)}var i=a("../c_facet"),j=a("./cf_registry"),k=(a("../../model"),a("mol-proto")),l=(a("../../services/mail"),k.createSubclass(i,"Item"));k.extendProto(l,{getState:c,setState:d,getIndex:e,setIndex:f,removeItem:g,extractItem:h,require:["Container","Dom","Data"]}),j.add(l),b.exports=l},{"../../model":74,"../../services/mail":84,"../c_facet":17,"./cf_registry":31,"mol-proto":150}],26:[function(a,b){"use strict";function c(){y.prototype.init.apply(this,arguments);B.defineProperties(this,{_listItems:[],_listItemsHash:{}}),B.defineProperty(this,"itemSample",null,B.WRIT)}function d(){this.owner.on("childrenbound",e)}function e(){var a=this.dom.children(),b=this.list._listItems,c=this.list._listItemsHash;if(a&&a.forEach(function(a){var d=z.getComponent(a);d&&d.item&&(b.push(d),c[d.name]=d,d.item.list=this.list)},this),b.length){var d=b[0];b.splice(0,1),delete c[d.name],b.forEach(function(a,b){a.item.setIndex(b)})}if(!d)throw new E("No child component has Item facet");this.list.itemSample=d,d.dom.hide(),d.remove(!0),d.dom.removeCssClasses(L),d.walkScopeTree(function(a){delete a.el[K.componentRef]}),this.list._createCacheTemplate()}function f(){if(!this.itemSample)return!1;{var a=this.itemSample,b=a.el.cloneNode(!0),c=a.componentInfo.attr;B.clone(c)}c.compName="{{= it.componentName() }}",c.el=b,c.decorate();var d="{{ var i = it.count; while(i--) { }}"+b.outerHTML+"{{ } }}";this.itemsTemplate=G.compile(d)}function g(a){return this._listItems[a]}function h(){return this._listItems.length}function i(a,b){this._listItems.splice(a,0,b),this._listItemsHash[b.name]=b,b.item.list=this,b.item.setIndex(+a)}function k(a){return this._listItemsHash[a.name]==a}function l(a,b){return a=a||this.count(),this.owner.data.splice(a,0,b||{}),this.item(a)}function m(a){if(a=a||this.count(),this.item(a))throw E("attempt to create item with ID of existing item");var b=z.copy(this.itemSample,!0),c=this._itemPreviousComponent(a);return c.el.parentNode?(c.dom.insertAfter(b.el),this._setItem(a,b),b.el.style.display="",n.call(this,a+1),b):F.warn("list item sample was removed from DOM, probably caused by wrong data. Reset list data with array")}function n(a,b){a=a||0,b=b||this.count();for(var c=a;b>c;c++){var d=this._listItems[c];d?d.item.setIndex(c):F.warn("List: no item at position",c)}}function o(a,b){var c=B.slice(arguments,2);c.lengtha)throw new E("can't add negative number of items");if(0!=a){var c=this.itemsTemplate({componentName:D.componentName,count:a}),d=document.createElement("div");d.innerHTML=c,C(d,this.owner.container.scope);var e=J.children(d);if(a!=e.length&&F.error("number of items added is different from requested"),e&&e.length){var f=this.count(),g=0>b?0:"undefined"==typeof b||b>f?f:b,h=0==g?this.itemSample:this._listItems[g-1],i=document.createDocumentFragment(),j=[];if(e.forEach(function(a){var b=z.getComponent(a);return b?(j.push(b),this._setItem(g++,b),i.appendChild(a),void(a.style.display="")):F.error("List: element in new items is not a component")},this),n.call(this,g),!h.el.parentNode)return F.warn("list item sample was removed from DOM, probably caused by wrong data. Reset list data with array");h.dom.insertAfter(i),B.deferMethod(j,"forEach",function(a){a.broadcast("stateready")})}}}function q(a){return this.owner.data.splice(a,1)}function r(a){var b=this._removeItem(a,!1);return this._updateDataPaths(a,this.count()),b}function s(a,b){var c=this.item(a);return c?(this._listItems[a]=void 0,delete this._listItemsHash[c.name],b!==!1?c.destroy():(c.remove(),c.dom.remove()),this._listItems.splice(a,1),n.call(this,a),c):F.warn("attempt to remove list item with id that does not exist")}function t(a,b){var c=this.item(a);c.dom.insertAfter(b.el),this._removeItem(a),this._setItem(a,b)}function u(a){for(;a>=0&&!this._listItems[a];)a--;return a>=0?this._listItems[a]:this.itemSample}function v(a,b){for(var c=a;b>c;c++){var d=this.item(c);d?d.data._path="["+c+"]":F.warn("Data: no item for index",j)}}function w(a,b){this._listItems.forEach(function(b,c){b?a.apply(this,arguments):F.warn("List$each: item",c,"is undefined")},b||this)}function x(){this.itemSample&&this.itemSample.destroy(!0),y.prototype.destroy.apply(this,arguments)}var y=a("../c_facet"),z=a("../c_class"),A=a("./cf_registry"),B=a("mol-proto"),C=(a("../../services/mail"),a("../../binder")),D=a("../../util"),E=D.error.List,F=D.logger,G=a("dot"),H=D.check,I=H.Match,J=D.dom,K=a("../../config"),L="ml-list-item-sample",M=B.createSubclass(y,"List");B.extendProto(M,{init:c,start:d,destroy:x,require:["Container","Dom","Data"],_itemPreviousComponent:u,item:g,count:h,contains:k,addItem:l,addItems:o,replaceItem:t,removeItem:q,extractItem:r,each:w,_setItem:i,_removeItem:s,_addItem:m,_addItems:p,_createCacheTemplate:f,_updateDataPaths:v}),A.add(M),b.exports=M},{"../../binder":9,"../../config":65,"../../services/mail":84,"../../util":100,"../c_class":16,"../c_facet":17,"./cf_registry":31,dot:115,"mol-proto":150}],27:[function(a,b){"use strict";function c(){this.m=new j(this.config.data,this),h.prototype.init.apply(this,arguments)}function d(){var a=this.m.get();return"object"==typeof a&&(a=k.deepClone(a)),{state:a}}function e(a){return this.m.set(a.state)}function f(){this._messenger=this.m._messenger}function g(){this.m.destroy(),h.prototype.destroy.apply(this,arguments)}var h=a("../c_facet"),i=a("./cf_registry"),j=a("../../model"),k=(a("../../abstract/mixin"),a("mol-proto")),l=k.createSubclass(h,"Model");k.extendProto(l,{init:c,getState:d,setState:e,_createMessenger:f,destroy:g}),i.add(l),b.exports=l,j.useWith(l,"m")},{"../../abstract/mixin":3,"../../model":74,"../c_facet":17,"./cf_registry":31,"mol-proto":150}],28:[function(a,b){"use strict";function c(){this.m=new h(this.config.options,this),f.prototype.init.apply(this,arguments),this.m.proxyMethods(this)}function d(){this._messenger=this.m._messenger}function e(){this.m.destroy(),f.prototype.destroy.apply(this,arguments)}var f=a("../c_facet"),g=a("./cf_registry"),h=a("../../model"),i=a("mol-proto"),j=i.createSubclass(f,"Options");i.extendProto(j,{init:c,destroy:e,_createMessenger:d}),g.add(j),b.exports=j},{"../../model":74,"../c_facet":17,"./cf_registry":31,"mol-proto":150}],29:[function(a,b){"use strict";function c(){i.prototype.init.apply(this,arguments);var a=this.config.interpolate===!1?void 0:this.config.compile||milo.config.template.compile;this.set(this.config.template||"",a,this.config.compileOptions)}function d(){i.prototype.start.apply(this,arguments),this.config.autoRender&&(this.render(),this.config.autoBinder&&this.binder())}function e(){return this._template}function f(a,b,c){return l(a,n.OneOf(String,Function)),l(b,n.Optional(Function)),"function"==typeof a?this._template=a:(this._templateStr=a,b?this._compile=b:b=this._compile,b&&(this._template=b(a,c))),this}function g(a){return this.owner.el.innerHTML=this._template?this._template(a):this._templateStr,this}function h(){return this.owner.container?this.owner.container.binder():void m.error("TemplateFacet: Binder called without container facet.")}var i=a("../c_facet"),j=a("./cf_registry"),k=a("mol-proto"),l=a("../../util/check"),m=a("../../util/logger"),n=l.Match,o=(a("../../binder"),k.createSubclass(i,"Template"));k.extendProto(o,{init:c,start:d,set:f,getCompiled:e,render:g,binder:h}),j.add(o),b.exports=o},{"../../binder":9,"../../util/check":90,"../../util/logger":102,"../c_facet":17,"./cf_registry":31,"mol-proto":150}],30:[function(a,b){"use strict";function c(){j.prototype.init.apply(this,arguments),this._activeState="",this._defaultKey="",this._state={}}function d(){return this._state[this._activeState]||this._state[this._defaultKey]}function e(a){this._state[""]=a,this.setActiveState("")}function f(a){this._activeState=a}function g(a,b,c){if(!a)throw new Error("Transfer$setStateWithKey: no key");this._defaultKey=c?a:this._defaultKey||a,this._state[a]=b,this.setActiveState(a)}function h(a){return"string"==typeof a&&this._state[a]}function i(){var a=this.getState();return{compName:a&&a.compName,compClass:a&&a.compClass}}var j=a("../c_facet"),k=a("./cf_registry"),l=a("mol-proto"),m=l.createSubclass(j,"Transfer");l.extendProto(m,{init:c,getState:d,setState:e,setActiveState:f,setStateWithKey:g,getStateWithKey:h,getComponentMeta:i}),k.add(m),b.exports=m},{"../c_facet":17,"./cf_registry":31,"mol-proto":150}],31:[function(a,b){"use strict";var c=a("../../abstract/registry"),d=a("../c_facet"),e=new c(d);e.add(d),b.exports=e},{"../../abstract/registry":4,"../c_facet":17}],32:[function(a,b){"use strict";function c(a,b,c,d){c.parse().validate(),this.scope=a,this.el=b,this.attr=c,this.name=c.compName,this.ComponentClass=f(c,d),this.extraFacetsClasses=g(this.ComponentClass,c,d),this.ComponentClass&&i(this.ComponentClass,this.extraFacetsClasses)&&(this.container={})}function d(){delete this.el,this.attr.destroy()}function e(a,b){a=a||l(),m.rename(this,a,b),this.attr.compName=a,this.attr.decorate()}function f(a,b){var c=j.get(a.compClass);return c||h(b,"class "+a.compClass+" is not registered"),c}function g(a,b,c){var d=b.compFacets,e={};return Array.isArray(d)&&d.forEach(function(d){d=p.firstUpperCase(d),a.hasFacet(d)&&h(c,"class "+a.name+" already has facet "+d),e[d]&&h(c,"component "+b.compName+" already has facet "+d);var f=k.get(d);e[d]=f}),e}function h(a,b){if(a!==!1)throw new n(b);o.error("ComponentInfo binder error:",b)}function i(a,b){function c(){return a.prototype.facetsClasses&&p.someKey(a.prototype.facetsClasses,d)}function d(a){return a.requiresFacet("container")}return a.hasFacet("container")||"Container"in b||p.someKey(b,d)||c()}var j=a("./c_registry"),k=a("./c_facets/cf_registry"),l=a("../util/component_name"),m=a("./scope"),n=a("../util/error").Binder,o=a("../util/logger"),p=a("mol-proto");b.exports=c,p.extendProto(c,{destroy:d,rename:e})},{"../util/component_name":91,"../util/error":98,"../util/logger":102,"./c_facets/cf_registry":31,"./c_registry":33,"./scope":41,"mol-proto":150}],33:[function(a,b){"use strict";var c=a("../abstract/registry"),d=a("./c_class"),e=new c(d);e.add(d),b.exports=e},{"../abstract/registry":4,"./c_class":16}],34:[function(a,b){"use strict";function c(a){return a.hasOwnProperty(h.componentRef)}function d(a){return a&&a[h.componentRef]}function e(a,b,c){i(b,j.Optional(Boolean)),i(c,j.Optional(j.OneOf(Function,String)));var d=f(c);return g(a,b,d)}function f(a){if("function"==typeof a)return a;if("string"==typeof a){var b=_.firstLowerCase(a);return function(a){return a.hasFacet(b)}}}function g(a,b,c){if(b!==!1){var e=d(a);if(e&&(!c||c(e)))return e}return a.parentNode?g(a.parentNode,!0,c):void 0}{var h=a("../config"),i=a("../util/check"),j=i.Match;b.exports={isComponent:c,getComponent:d,getContainingComponent:e,_makeComponentConditionFunc:f}}},{"../config":65,"../util/check":90}],35:[function(a,b){"use strict";var c=a("../c_class"),d=a("../c_registry"),e=c.createComponentClass("View",["container"]);d.add(e),b.exports=e},{"../c_class":16,"../c_registry":33}],36:[function(a,b){"use strict";function c(a){h.prototype.init.apply(this,arguments),this.component=a,this.elData=i(a.el)}function d(){var a=this.component.data.config.get,b="function"==typeof a?a.call(this.component):this.elData.get(this.component.el);return this.component.data._value=b,b}function e(a){var b=this.component.data.config.event,c=b||this.elData.event(this.component.el);return""==a&&c?c:void 0}function f(a,b,c){return c.newValue!=c.oldValue}function g(){var a=this.component.data._value,b=this.value(),c={path:"",type:"changed",oldValue:a,newValue:b};return c}var h=a("../../messenger/m_api"),i=a("./de_data"),j=a("mol-proto"),k=a("../../util/check"),l=(k.Match,j.createSubclass(h,"DataMsgAPI",!0));j.extendProto(l,{init:c,translateToSourceMessage:e,filterSourceMessage:f,createInternalData:g,value:d}),b.exports=l},{"../../messenger/m_api":68,"../../util/check":90,"./de_data":37,"mol-proto":150}],37:[function(a,b){"use strict";function c(a){var b=h[a.type];return b?b.property:h.byDefault.property}function d(a){var b=h[a.type];return b?b.event:h.byDefault.event}var e=a("mol-proto"),f=function(a){var b=a.tagName.toLowerCase(),c=g[b];return c||g.byDefault};b.exports=f;var g={byDefault:{property:"innerHTML"},div:{property:"innerHTML"},span:{property:"innerHTML",event:"input"},p:{property:"innerHTML",event:"input"},input:{property:c,event:d},textarea:{property:"value",event:"input"},select:{property:"value",event:"change"},img:{property:"src"},caption:{property:"innerHTML",event:"input"},thead:{property:"innerHTML",event:"input"},tbody:{property:"innerHTML",event:"input"},tfoot:{property:"innerHTML",event:"input"}};e.eachKey(g,function(a){var b=a.property,c=a.event;"function"!=typeof b&&(a.property=function(){return b});var d=a.property;"function"!=typeof c&&(a.event=function(){return c}),a.get||(a.get=function(a){return a[d(a)]}),a.set||(a.set=function(a,b){return a[d(a)]="undefined"==typeof b?"":b})});var h={byDefault:{property:"value",event:"input"},checkbox:{property:"checked",event:"change"},radio:{property:"checked",event:"change"},text:{property:"value",event:"input"}}},{"mol-proto":150}],38:[function(a,b){"use strict";function c(a){return h.hasOwnProperty(a)?h[a]:a}function d(){delete this._currentTarget,delete this._inside}function e(a,b,c){var e=!0;return"dragenter"==a&&"dragin"==b?(this._currentTarget=c.target,e=!this._inside,this._inside=!0):"dragleave"==a&&"dragout"==b?(e=this._currentTarget==c.target,e&&d.call(this)):"drop"==a&&d.call(this),e}var f=a("../../messenger/m_api"),g=_.createSubclass(f,"DropMsgAPI",!0);_.extendProto(g,{translateToSourceMessage:c,filterSourceMessage:e}),b.exports=g;var h={dragin:"dragenter",dragout:"dragleave"}},{"../../messenger/m_api":68}],39:[function(a,b){"use strict";function c(a,b,c,d){j(d,h),this.component=d,g.prototype.init.apply(this,arguments)}function d(){g.prototype.destroy.apply(this,arguments),delete this.component}function e(){return this.component.el}var f=a("../../services/dom_source"),g=a("../../messenger/m_source"),h=a("../c_class"),i=a("mol-proto"),j=a("../../util/check"),k=(j.Match,i.createSubclass(f,"DOMEventsSource",!0));i.extendProto(k,{init:c,destroy:d,emitter:e}),b.exports=k},{"../../messenger/m_source":70,"../../services/dom_source":83,"../../util/check":90,"../c_class":16,"mol-proto":150}],40:[function(a,b){"use strict";function c(a,b,c,d){if(l(d,j),this.component=d,"iframe"!=d.el.tagName.toLowerCase())throw new n("component for FrameMessageSource can only be attached to iframe element");i.prototype.init.apply(this,arguments)}function d(){return this.component.el.contentWindow}function e(){var a=this.frameWindow();a?a.addEventListener("message",this,!1):m.warn("FrameMessageSource: frame window is undefined")}function f(){var a=this.frameWindow();a?a.removeEventListener("message",this,!1):m.warn("FrameMessageSource: frame window is undefined")}function g(a,b){b=b||{},b.type=a,this.frameWindow().postMessage(b,"*")}function h(a){this.dispatchMessage(a.data.type,a)}var i=a("../../messenger/m_source"),j=a("../c_class"),k=a("mol-proto"),l=a("../../util/check"),m=a("../../util/logger"),n=(l.Match,a("../../util/error").FrameMessageSource),o=k.createSubclass(i,"FrameMessageSource",!0);k.extendProto(o,{init:c,addSourceSubscriber:e,removeSourceSubscriber:f,trigger:g,frameWindow:d,handleEvent:h}),b.exports=o},{"../../messenger/m_source":70,"../../util/check":90,"../../util/error":98,"../../util/logger":102,"../c_class":16,"mol-proto":150}],41:[function(a,b){"use strict";function c(a,b){t.defineProperties(this,{_rootEl:a,_hostObject:b},t.WRIT)}function d(a,b){if("string"==typeof b?a.name=b:b=a.name,this.hasOwnProperty(b))throw new w("duplicate object name: "+b);l(b),f.call(this,a,b)}function e(a,b){"string"==typeof b?a.name=b:b=a.name;var c=this.hasOwnProperty(b);c?x.error("Scope: duplicate object name: "+b):(c=!y.test(b),c&&x.error("Scope: name should start from letter, this name is not allowed: "+b)),c&&(b=u(),a.name=b),f.call(this,a,b)}function f(a,b){this[b]=a,a.scope=this,"function"==typeof a.postMessage&&a.postMessage("addedtoscope")}function g(a){v(a,c),a._each(d,this)}function h(a,b){b._add(a),this._remove(a.name),a.scope=b}function i(a){a._each(function(b){this._add(b,b.name),a._remove(b.name)},this)}function j(a,b){t.eachKey(this,a,b||this,!0)}function k(a,b){return t.filterKeys(this,a,b||this,!0)}function l(a){if(!y.test(a))throw new w("name should start from letter, this name is not allowed: "+a)}function m(){return Object.keys(this).length}function n(){var a=Object.keys(this)[0];return a&&this[a]}function o(a,b){if(!(a in this))return void(b||x.warn("removing object that is not in scope"));var c=this[a];delete this[a],"function"==typeof c.postMessage&&c.postMessage("removedfromscope")}function p(){this._each(function(a,b){delete this[b].scope,delete this[b]},this)}function q(){this._rootEl=null}function r(a){return this.hasOwnProperty(a.name)}function s(a,b,c){a.scope&&c!==!1?(a.scope._remove(a.name),a.scope._add(a,b)):a.name=b}var t=a("mol-proto"),u=a("../util/component_name"),v=a("../util/check"),w=(v.Match,a("../util/error").Scope),x=a("../util/logger");t.extendProto(c,{_add:d,_safeAdd:e,_copy:g,_each:j,_move:h,_merge:i,_length:m,_any:n,_remove:o,_clean:p,_detachElement:q,_has:r,_filter:k}),t.extend(c,{rename:s}),b.exports=c;var y=/^[A-Za-z][A-Za-z0-9\_\$]*$/},{"../util/check":90,"../util/component_name":91,"../util/error":98,"../util/logger":102,"mol-proto":150}],42:[function(a,b){"use strict";function c(a){this.el.disabled=a}function d(){return!!this.el.disabled}var e=a("../c_class"),f=a("../c_registry"),g=e.createComponentClass("MLButton",{events:void 0,dom:{cls:"ml-ui-button"}});f.add(g),b.exports=g,_.extendProto(g,{disable:c,isDisabled:d})},{"../c_class":16,"../c_registry":33}],43:[function(a,b){"use strict";function c(){k.prototype.init.apply(this,arguments),this.on("childrenbound",d)}function d(){m.defineProperties(this,{_comboInput:this.container.scope.input,_comboList:this.container.scope.datalist}),this._comboList.template.set(o),this._comboInput.data.on("input",{subscriber:i,context:this})}function e(){return this._comboInput?this._comboInput.data.get():void 0}function f(a){return h.call(this,"set",a)}function g(){return h.call(this,"del",value)}function h(a,b){if(this._comboInput){var c=this._comboInput.data[a](b);return i.call(this),c}}function i(){this.data.dispatchSourceMessage(n)}function j(){this._comboList.template.render({comboOptions:this.model.get()})}var k=a("../c_class"),l=a("../c_registry"),m=a("mol-proto"),n="mlcombochange",o='{{~ it.comboOptions :option }} {{~}}',p=k.createComponentClass("MLCombo",{events:void 0,data:{get:e,set:f,del:g,splice:void 0,event:n},model:{messages:{"***":{subscriber:j,context:"owner"}}},dom:{cls:"ml-ui-datalist"},container:void 0});l.add(p),b.exports=p,m.extendProto(p,{init:c})},{"../c_class":16,"../c_registry":33,"mol-proto":150}],44:[function(a,b){"use strict";function c(){r.prototype.init.apply(this,arguments),this._dataValidation=function(){},this.model.set([]),this.once("childrenbound",j)}function d(a){"function"==typeof a&&(this._dataValidation=a)}function e(a){this._combo.setOptions(a)}function f(){this._combo.clearComboInput()
-}function g(a){this._combo.toggleAddButton(a)}function h(a){this._combo.setAddItemPrompt(a)}function i(){r.prototype.destroy.apply(this,arguments),this._connector&&milo.minder.destroyConnector(this._connector),this._connector=null}function j(){this.template.render().binder(),k.call(this)}function k(){t.defineProperties(this,{_combo:this.container.scope.combo,_list:this.container.scope.list}),this._connector=milo.minder(this._list.model,"<<<->>>",this.model),this._combo.data.on("",{subscriber:l,context:this}),this._combo.on("additem",{subscriber:q,context:this})}function l(a,b){b.newValue&&this._dataValidation(a,b,this._list.model.get())&&this._list.model.push(b.newValue),this._combo.data.del(),this._combo.data._value=""}function m(){this.data.dispatchSourceMessage(u)}function n(){var a=this.model.get();return"object"==typeof a?t.clone(a):a}function o(a){this.model.set(a)}function p(){return this.model.set([])}function q(a,b){this.postMessage("additem",b),this.events.postMessage("milo_combolistadditem",b)}var r=a("../c_class"),s=a("../c_registry"),t=a("mol-proto"),u="mlcombolistchange",v=r.createComponentClass("MLComboList",{dom:{cls:"ml-ui-combo-list"},data:{get:n,set:o,del:p,event:u},events:void 0,container:void 0,model:{messages:{"***":{subscriber:m,context:"owner"}}},template:{template:'