@genialis/resolwe
Version:
Resolwe frontend libraries
495 lines (494 loc) • 51.8 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var _ = require("lodash");
var Rx = require("rx");
var angular = require("angular");
var lang_1 = require("../utils/lang");
var immutable = require("../utils/immutable");
var Actions = /** @class */ (function () {
function Actions() {
}
Actions.prototype.set = function (value) {
return { type: Actions.SET, value: value };
};
/// Internal action for setting this store to a specific value.
Actions.SET = '@@internal/SET';
return Actions;
}());
exports.Actions = Actions;
/**
* A shared store represents state that is shared between multiple components in
* a predictable way. Components update the store by dispatching actions to
* it using the `dispatch` method.
*
* Each shared store also provides a way for the components to subscribe to any
* changes in the store's state.
*
* Consider defining actions for use in a shared store separately from the store,
* in the `actions` subdirectory. See [[SharedStoreManager]] for details.
*
* Don't forget to call constructor with actions as an argument when extending
* this class.
*/
var SharedStore = /** @class */ (function () {
function SharedStore(actions) {
this._queries = {};
this._subject = new Rx.BehaviorSubject(this.initialState());
this._actions = actions;
// Create a local dispatcher.
this._dispatcher = new Dispatcher();
this._dispatcher.setDispatcher(this._dispatch.bind(this), this.value.bind(this));
}
Object.defineProperty(SharedStore.prototype, "storeId", {
/**
* Returns a unique identifier for this shared store.
*/
get: function () {
return this._storeId;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SharedStore.prototype, "actions", {
/**
* Returns store actions.
*/
get: function () {
return this._actions;
},
enumerable: true,
configurable: true
});
/**
* Internal dispatcher implementation.
*
* NOTE: This method is public because there is no way to define private
* but accessible to other classes within this module in TypeScript.
*/
SharedStore.prototype._dispatch = function (action) {
var existingValue = this.value();
var reducer;
if (_.startsWith(action.type, '@@internal/')) {
reducer = this._reduceInternal.bind(this);
}
else {
reducer = this.reduce.bind(this);
}
var newValue = reducer(existingValue, action);
if (_.isUndefined(newValue))
return;
if (angular.equals(existingValue, newValue))
return;
this._subject.onNext(immutable.makeImmutable(newValue));
};
/**
* Dispatches an action to this shared store.
*
* @param action Action to dispatch
*/
SharedStore.prototype.dispatch = function (action) {
return this._dispatcher.dispatch(action);
};
/**
* Performs internal reduce actions implemented for each shared store.
*
* @param state Existing shared store state
* @param action Action to perform
* @return New shared store state
*/
SharedStore.prototype._reduceInternal = function (state, action) {
switch (action.type) {
case Actions.SET: {
var nextState = action['value'];
return this.onStateLoad(state, nextState);
}
default: {
// Do nothing.
}
}
};
/**
* This method gets called when the data store's state is loaded from
* an external source (when the SET action is dispatched to the store).
*
* It is called before the new state has been set. The default implementation
* does nothing.
*
* @param state Old state
* @param nextState New state
* @return Possibly modified state that should be used instead
*/
SharedStore.prototype.onStateLoad = function (state, nextState) {
return nextState;
};
/**
* A helper method for defining shared store queries. If the query is already
* defined, the existing observable is returned.
*
* @param name Query name
* @param query Query function
* @return Resulting query observable
*/
SharedStore.prototype.defineQuery = function (name, query) {
var observable = this._queries[name];
if (observable)
return observable;
observable = this._queries[name] = this.observable().let(query).distinctUntilChanged();
return observable;
};
/**
* Returns the current value stored in the store.
*
* You MUST ensure that the resulting object is NOT mutated in any way. Any
* mutation may cause undefined behavior.
*/
SharedStore.prototype.value = function () {
return this._subject.getValue();
};
/**
* Returns an observable of the store's value.
*
* You MUST ensure that the observed value is NOT mutated in any way. Any
* mutation may cause undefined behavior.
*/
SharedStore.prototype.observable = function () {
return this._subject;
};
/**
* Returns a value that should be used when saving store state.
*
* By default, this will return the same as [[value]].
*/
SharedStore.prototype.saveValue = function () {
return this.value();
};
return SharedStore;
}());
exports.SharedStore = SharedStore;
/**
* [[SimpleSharedStore]] is a helper class intended to be used as a type in conjunction with
* [[SharedStoreProvider]]'s `create` method where only SET action is used.
*
* In this case no subclassing of store and actions is needed because only SET action is used.
* This is convenient for use cases where you only need to set a value that you can subscribe
* to from other components.
*/
var SimpleSharedStore = /** @class */ (function (_super) {
__extends(SimpleSharedStore, _super);
function SimpleSharedStore() {
return _super !== null && _super.apply(this, arguments) || this;
}
return SimpleSharedStore;
}(SharedStore));
exports.SimpleSharedStore = SimpleSharedStore;
/**
* Used to dispatch actions to shared stores.
*/
var Dispatcher = /** @class */ (function (_super) {
__extends(Dispatcher, _super);
function Dispatcher() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this._getState = function () { return undefined; };
return _this;
}
/**
* Configures a dispatcher function for this dispatcher.
*
* @param dispatcher The dispatcher function
*/
Dispatcher.prototype.setDispatcher = function (dispatcher, getState) {
// The dispatcher is used to dispatch all actions using a queue, so actions
// may invoke the dispatch method without causing recursion. The currentThread
// scheduler puts all pending items inside a queue, which is dispatched after
// returning from active dispatch.
this.observeOn(Rx.Scheduler.currentThread).subscribe(dispatcher);
if (getState)
this._getState = getState;
};
/**
* Dispatches an action via this dispatcher.
*/
Dispatcher.prototype.dispatch = function (action) {
if (_.isFunction(action)) {
// A thunk has been passed. Execute it with the dispatcher argument and
// return the result.
return action(this, this._getState);
}
else {
this.onNext(action);
}
};
return Dispatcher;
}(Rx.Subject));
exports.Dispatcher = Dispatcher;
/**
* Shared store provider, enabling registration of shared stores. All stores
* must be registered in the application configuration phase.
*/
var SharedStoreProvider = /** @class */ (function () {
// @ngInject
SharedStoreProvider.$inject = ["$provide"];
function SharedStoreProvider($provide) {
/// A list of registered stores.
this._stores = [];
this._provide = $provide;
}
Object.defineProperty(SharedStoreProvider.prototype, "stores", {
/**
* A list of registered stores.
*/
get: function () {
return this._stores;
},
enumerable: true,
configurable: true
});
/**
* Creates a new shared store.
*
* When choosing an identifier for the store, you should write it using
* kebab-case and not include the string 'store' either as a prefix or
* a suffix.
*
* This method may only be called in the application's configuration
* phase.
*
* @param storeId Identifier of the shared store (must be globally unique)
* @param initialState Optional initial state of the shared store
*/
SharedStoreProvider.prototype.create = function (storeId, initialState) {
if (initialState === void 0) { initialState = null; }
var Extended = /** @class */ (function (_super) {
__extends(Extended, _super);
function Extended() {
return _super !== null && _super.apply(this, arguments) || this;
}
Extended.prototype.initialState = function () { return initialState; };
Extended.prototype.reduce = function (state, action) { return undefined; };
return Extended;
}(SimpleSharedStore));
this.register(storeId, Extended);
};
/**
* Registers a new shared store. A store with the same name must not already
* be registered.
*
* This method may only be called in the application's configuration
* phase.
*
* @param storeId Identifier of the shared store (must be globally unique)
* @param Shared store class
*/
SharedStoreProvider.prototype.register = function (storeId, storeType) {
// Register the store as an angular service. We use factory instead of service
// so we can set the `_storeId` on the instance.
this._provide.factory(storeIdToServiceId(storeId),
// @ngInject
["$injector", function ($injector) {
var store = $injector.instantiate(storeType);
store._storeId = storeId;
return store;
}]);
this._stores.push(storeId);
};
/**
* Registers a new actions class.
*
* This method may only be called in the application's configuration
* phase.
*
* @param actionsId Identifier of the actions class (must be globally unique)
* @param Actions class
*/
SharedStoreProvider.prototype.registerActions = function (actionsId, actionsType) {
this._provide.service(actionsIdToServiceId(actionsId), actionsType);
};
// @ngInject
SharedStoreProvider.prototype.$get = function ($injector, dispatcher) {
return new SharedStoreManager($injector, dispatcher, this);
};
SharedStoreProvider.prototype.$get.$inject = ["$injector", "dispatcher"];
return SharedStoreProvider;
}());
exports.SharedStoreProvider = SharedStoreProvider;
/**
* Manager of all shared stores (see [[SharedStore]]) in an application. Each store
* requires a globally unique identifier, which is also used during state serialization.
*
* In order to use shared stores, you must first create them. The best way to do
* this is inside your module's `config` function as follows:
* ```
* module.config((sharedStoreManagerProvider: SharedStoreProvider) => {
* // Create the selected ROSE2 data items shared store.
* sharedStoreManagerProvider.create('rose2-selected-data-item');
* });
* ```
*
* The store may then be used as input to shared state defined on stateful
* components (see [[StatefulComponentBase]]) and can also be injected using
* a specific token. If a store is named `my-nice-items`, it will be injectable
* by using the token `myNiceItemsStore`.
*
* If you wish to define shared stores which support additional actions, you
* should subclass [[SharedStore]] and register your store by using [[register]]
* as follows:
* ```
* class ComplexActions {
* static ADD_ITEM = 'complex/add_item';
* public addItem(value: types.SampleData) {
* return { type: ComplexActions.ADD_ITEM, item: value };
* }
* }
*
* class ComplexStore extends SharedStore<types.SampleData[], ComplexActions> {
* // @ngInject
* constructor(complexActions: ComplexActions) {
* super(complexActions);
* }
*
* protected initialState(): types.SampleData[] {
* return [];
* }
*
* protected reduce(state: types.SampleData[], action: any): void {
* switch (action.type) {
* case ADD_ITEM: {
* return _.union(state, action.item);
* }
* // ...
* }
* }
* }
*
* module.config((sharedStoreManagerProvider: SharedStoreProvider) => {
* sharedStoreManagerProvider.registerActions('complex', ComplexActions);
* sharedStoreManagerProvider.register('complex', ComplexStore);
* });
* ```
*
* When creating a new shared store, a good design practice is to separate
* actions into the `actions` directory and implement actions as methods on
* the actions class named after your store (eg. for store `FooStore` put
* actions into `FooActions`).
*
* Stores themselves should only implement the state management functionality
* and most business logic should be contained in the actions class. For
* example, if actions require some asynchronous operations to be performed
* on a remote backend all this functionality should be put into the actions
* class and not into the store.
*
* All actions classes should be registered via the [[SharedStoreProvider]]
* and support Angular dependency injection. Actions classes are injectable
* under the token `idActions` where the `id` part is the value defined by
* `actionsId`, formatted in camelCase. The constructor of an actions
* class may also inject other dependencies.
*
* For convenience, you may inject your actions class in your shared store
* class under the public attribute `actions`. This way one may get the
* actions class simply by accessing `store.actions` when given a shared
* store instance.
*/
var SharedStoreManager = /** @class */ (function () {
// @ngInject
SharedStoreManager.$inject = ["$injector", "dispatcher", "sharedStoreManagerProvider"];
function SharedStoreManager($injector, dispatcher, sharedStoreManagerProvider) {
this._provider = sharedStoreManagerProvider;
this._injector = $injector;
this._dispatcher = dispatcher;
this._dispatcher.setDispatcher(this._dispatch.bind(this));
}
/**
* Returns a previously registered store. It is an error to request a store
* which doesn't exist.
*
* @param storeId Identifier of the shared store
* @return Shared store instance
*/
SharedStoreManager.prototype.getStore = function (storeId) {
return this._injector.get(storeIdToServiceId(storeId));
};
/**
* Dispatches an action to all shared stores.
*
* @param action Action to dispatch
*/
SharedStoreManager.prototype.dispatch = function (action) {
return this._dispatcher.dispatch(action);
};
/**
* Internal global dispatch implementation.
*/
SharedStoreManager.prototype._dispatch = function (action) {
for (var _i = 0, _a = this._provider.stores; _i < _a.length; _i++) {
var storeId = _a[_i];
this.getStore(storeId)._dispatch(action);
}
};
/**
* Serializes the values of all shared stores.
*/
SharedStoreManager.prototype.saveState = function () {
var result = {};
for (var _i = 0, _a = this._provider.stores; _i < _a.length; _i++) {
var storeId = _a[_i];
var value = this.getStore(storeId).saveValue();
if (lang_1.isJsonable(value)) {
result[storeId] = value.toJSON();
}
else {
result[storeId] = angular.copy(value);
}
}
return result;
};
/**
* Loads serialized values of all shared stores. Existing values are overwritten.
*/
SharedStoreManager.prototype.loadState = function (state) {
for (var _i = 0, _a = this._provider.stores; _i < _a.length; _i++) {
var storeId = _a[_i];
if (!(storeId in state))
continue;
var value = state[storeId];
this.getStore(storeId).dispatch({ type: Actions.SET, value: value });
}
};
return SharedStoreManager;
}());
exports.SharedStoreManager = SharedStoreManager;
/**
* Returns the Angular service identifier that can be used to inject a
* store via dependency injection.
*
* @param storeId Store identifier
*/
function storeIdToServiceId(storeId) {
return _.camelCase(storeId + "-store");
}
/**
* Returns the Angular service identifier that can be used to inject an
* actions object via dependency injection.
*
* @param actionsId Actions object identifier
*/
function actionsIdToServiceId(actionsId) {
return _.camelCase(actionsId + "-actions");
}
var angularModule = angular.module('resolwe.services.shared_store', []);
// Register injectable services.
angularModule.provider('sharedStoreManager', SharedStoreProvider);
angularModule.service('dispatcher', Dispatcher);
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb3JlL3NoYXJlZF9zdG9yZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFBQSwwQkFBNEI7QUFDNUIsdUJBQXlCO0FBQ3pCLGlDQUFtQztBQUVuQyxzQ0FBeUM7QUFDekMsOENBQWdEO0FBOEJoRDtJQUFBO0lBTUEsQ0FBQztJQUhVLHFCQUFHLEdBQVYsVUFBVyxLQUFVO1FBQ2pCLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLEdBQUcsRUFBRSxLQUFLLE9BQUEsRUFBRSxDQUFDO0lBQ3hDLENBQUM7SUFKRCwrREFBK0Q7SUFDakQsV0FBRyxHQUFzQixnQkFBZ0IsQ0FBQztJQUk1RCxjQUFDO0NBTkQsQUFNQyxJQUFBO0FBTlksMEJBQU87QUFRcEI7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNIO0lBT0kscUJBQVksT0FBVztRQUpmLGFBQVEsR0FBeUMsRUFBRSxDQUFDO1FBS3hELElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxFQUFFLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDO1FBQzVELElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFDO1FBRXhCLDZCQUE2QjtRQUM3QixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksVUFBVSxFQUFFLENBQUM7UUFDcEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNyRixDQUFDO0lBS0Qsc0JBQVcsZ0NBQU87UUFIbEI7O1dBRUc7YUFDSDtZQUNJLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztRQUN6QixDQUFDOzs7T0FBQTtJQUtELHNCQUFXLGdDQUFPO1FBSGxCOztXQUVHO2FBQ0g7WUFDSSxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUM7UUFDekIsQ0FBQzs7O09BQUE7SUFFRDs7Ozs7T0FLRztJQUNJLCtCQUFTLEdBQWhCLFVBQWlCLE1BQWM7UUFDM0IsSUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ25DLElBQUksT0FBd0MsQ0FBQztRQUM3QyxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxhQUFhLENBQUMsRUFBRTtZQUMxQyxPQUFPLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDN0M7YUFBTTtZQUNILE9BQU8sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNwQztRQUVELElBQUksUUFBUSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDOUMsSUFBSSxDQUFDLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQztZQUFFLE9BQU87UUFFcEMsSUFBSSxPQUFPLENBQUMsTUFBTSxDQUFDLGFBQWEsRUFBRSxRQUFRLENBQUM7WUFBRSxPQUFPO1FBQ3BELElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUM1RCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLDhCQUFRLEdBQWYsVUFBZ0IsTUFBbUQ7UUFDL0QsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBa0IsTUFBTSxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNLLHFDQUFlLEdBQXZCLFVBQXdCLEtBQVEsRUFBRSxNQUFjO1FBQzVDLFFBQVEsTUFBTSxDQUFDLElBQUksRUFBRTtZQUNqQixLQUFLLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDZCxJQUFNLFNBQVMsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ2xDLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLENBQUM7YUFDN0M7WUFDRCxPQUFPLENBQUMsQ0FBQztnQkFDTCxjQUFjO2FBQ2pCO1NBQ0o7SUFDTCxDQUFDO0lBcUJEOzs7Ozs7Ozs7O09BVUc7SUFDTyxpQ0FBVyxHQUFyQixVQUFzQixLQUFRLEVBQUUsU0FBWTtRQUN4QyxPQUFPLFNBQVMsQ0FBQztJQUNyQixDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNPLGlDQUFXLEdBQXJCLFVBQXlCLElBQVksRUFBRSxLQUE2QjtRQUNoRSxJQUFJLFVBQVUsR0FBcUIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN2RCxJQUFJLFVBQVU7WUFBRSxPQUFPLFVBQVUsQ0FBQztRQUVsQyxVQUFVLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFDdkYsT0FBTyxVQUFVLENBQUM7SUFDdEIsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksMkJBQUssR0FBWjtRQUNJLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUNwQyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxnQ0FBVSxHQUFqQjtRQUNJLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN6QixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLCtCQUFTLEdBQWhCO1FBQ0ksT0FBTyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDeEIsQ0FBQztJQUNMLGtCQUFDO0FBQUQsQ0E5SkEsQUE4SkMsSUFBQTtBQTlKcUIsa0NBQVc7QUFnS2pDOzs7Ozs7O0dBT0c7QUFDSDtJQUFtRCxxQ0FBZ0M7SUFBbkY7O0lBQXNGLENBQUM7SUFBRCx3QkFBQztBQUFELENBQXRGLEFBQXVGLENBQXBDLFdBQVcsR0FBeUI7QUFBakUsOENBQWlCO0FBRXZDOztHQUVHO0FBQ0g7SUFBZ0MsOEJBQWtCO0lBQWxEO1FBQUEscUVBNkJDO1FBNUJXLGVBQVMsR0FBYyxjQUFNLE9BQUEsU0FBUyxFQUFULENBQVMsQ0FBQzs7SUE0Qm5ELENBQUM7SUExQkc7Ozs7T0FJRztJQUNJLGtDQUFhLEdBQXBCLFVBQXFCLFVBQW9DLEVBQUUsUUFBb0I7UUFDM0UsMkVBQTJFO1FBQzNFLDhFQUE4RTtRQUM5RSw2RUFBNkU7UUFDN0Usa0NBQWtDO1FBQ2xDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDakUsSUFBSSxRQUFRO1lBQUUsSUFBSSxDQUFDLFNBQVMsR0FBRyxRQUFRLENBQUM7SUFDNUMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksNkJBQVEsR0FBZixVQUFnQixNQUFzQjtRQUNsQyxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDdEIsdUVBQXVFO1lBQ3ZFLHFCQUFxQjtZQUNyQixPQUFPLE1BQU0sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1NBQ3ZDO2FBQU07WUFDSCxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1NBQ3ZCO0lBQ0wsQ0FBQztJQUNMLGlCQUFDO0FBQUQsQ0E3QkEsQUE2QkMsQ0E3QitCLEVBQUUsQ0FBQyxPQUFPLEdBNkJ6QztBQTdCWSxnQ0FBVTtBQXVDdkI7OztHQUdHO0FBQ0g7SUFNSSxZQUFZO0lBQ1osNkJBQVksUUFBc0M7UUFObEQsZ0NBQWdDO1FBQ3hCLFlBQU8sR0FBYSxFQUFFLENBQUM7UUFNM0IsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7SUFDN0IsQ0FBQztJQUtELHNCQUFXLHVDQUFNO1FBSGpCOztXQUVHO2FBQ0g7WUFDSSxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDeEIsQ0FBQzs7O09BQUE7SUFFRDs7Ozs7Ozs7Ozs7O09BWUc7SUFDSSxvQ0FBTSxHQUFiLFVBQWlCLE9BQWUsRUFBRSxZQUFzQjtRQUF0Qiw2QkFBQSxFQUFBLG1CQUFzQjtRQUNwRDtZQUF1Qiw0QkFBb0I7WUFBM0M7O1lBR0EsQ0FBQztZQUZhLCtCQUFZLEdBQXRCLGNBQTJCLE9BQU8sWUFBWSxDQUFDLENBQUMsQ0FBQztZQUN2Qyx5QkFBTSxHQUFoQixVQUFpQixLQUFRLEVBQUUsTUFBYyxJQUFPLE9BQU8sU0FBUyxDQUFDLENBQUMsQ0FBQztZQUN2RSxlQUFDO1FBQUQsQ0FIQSxBQUdDLENBSHNCLGlCQUFpQixHQUd2QztRQUVELElBQUksQ0FBQyxRQUFRLENBQUksT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3hDLENBQUM7SUFFRDs7Ozs7Ozs7O09BU0c7SUFDSSxzQ0FBUSxHQUFmLFVBQW1CLE9BQWUsRUFBRSxTQUFxQztRQUNyRSw4RUFBOEU7UUFDOUUsZ0RBQWdEO1FBQ2hELElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUNqQixrQkFBa0IsQ0FBQyxPQUFPLENBQUM7UUFDM0IsWUFBWTtRQUNaLFVBQUMsU0FBd0M7WUFDckMsSUFBTSxLQUFLLEdBQVEsU0FBUyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUNwRCxLQUFLLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQztZQUN6QixPQUFPLEtBQUssQ0FBQztRQUNqQixDQUFDLENBQ0osQ0FBQztRQUNGLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQy9CLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNJLDZDQUFlLEdBQXRCLFVBQXVCLFNBQWlCLEVBQUUsV0FBMEI7UUFDaEUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsb0JBQW9CLENBQUMsU0FBUyxDQUFDLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUVELFlBQVk7SUFDTCxrQ0FBSSxHQUFYLFVBQVksU0FBd0MsRUFDeEMsVUFBc0I7UUFDOUIsT0FBTyxJQUFJLGtCQUFrQixDQUFDLFNBQVMsRUFBRSxVQUFVLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUNMLDBCQUFDO0FBQUQsQ0FuRkEsQUFtRkMsSUFBQTtBQW5GWSxrREFBbUI7QUFxRmhDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNEVHO0FBQ0g7SUFRSSxZQUFZO0lBQ1osNEJBQVksU0FBd0MsRUFDeEMsVUFBc0IsRUFDdEIsMEJBQStDO1FBQ3ZELElBQUksQ0FBQyxTQUFTLEdBQUcsMEJBQTBCLENBQUM7UUFDNUMsSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUM7UUFDM0IsSUFBSSxDQUFDLFdBQVcsR0FBRyxVQUFVLENBQUM7UUFDOUIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUM5RCxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0kscUNBQVEsR0FBZixVQUFtQixPQUFlO1FBQzlCLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQXNCLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDaEYsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxxQ0FBUSxHQUFmLFVBQWdCLE1BQXNCO1FBQ2xDLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUVEOztPQUVHO0lBQ0ssc0NBQVMsR0FBakIsVUFBa0IsTUFBYztRQUM1QixLQUFzQixVQUFxQixFQUFyQixLQUFBLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFyQixjQUFxQixFQUFyQixJQUFxQixFQUFFO1lBQXhDLElBQU0sT0FBTyxTQUFBO1lBQ2QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7U0FDNUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxzQ0FBUyxHQUFoQjtRQUNJLElBQUksTUFBTSxHQUFHLEVBQUUsQ0FBQztRQUNoQixLQUFzQixVQUFxQixFQUFyQixLQUFBLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFyQixjQUFxQixFQUFyQixJQUFxQixFQUFFO1lBQXhDLElBQU0sT0FBTyxTQUFBO1lBQ2QsSUFBSSxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUMvQyxJQUFJLGlCQUFVLENBQUMsS0FBSyxDQUFDLEVBQUU7Z0JBQ25CLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7YUFDcEM7aUJBQU07Z0JBQ0gsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7YUFDekM7U0FDSjtRQUVELE9BQU8sTUFBTSxDQUFDO0lBQ2xCLENBQUM7SUFFRDs7T0FFRztJQUNJLHNDQUFTLEdBQWhCLFVBQWlCLEtBQVU7UUFDdkIsS0FBc0IsVUFBcUIsRUFBckIsS0FBQSxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBckIsY0FBcUIsRUFBckIsSUFBcUIsRUFBRTtZQUF4QyxJQUFNLE9BQU8sU0FBQTtZQUNkLElBQUksQ0FBQyxDQUFDLE9BQU8sSUFBSSxLQUFLLENBQUM7Z0JBQUUsU0FBUztZQUVsQyxJQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDN0IsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFDLENBQUMsQ0FBQztTQUN0RTtJQUNMLENBQUM7SUFDTCx5QkFBQztBQUFELENBM0VBLEFBMkVDLElBQUE7QUEzRVksZ0RBQWtCO0FBNkUvQjs7Ozs7R0FLRztBQUNILFNBQVMsa0JBQWtCLENBQUMsT0FBZTtJQUN2QyxPQUFPLENBQUMsQ0FBQyxTQUFTLENBQUksT0FBTyxXQUFRLENBQUMsQ0FBQztBQUMzQyxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFTLG9CQUFvQixDQUFDLFNBQWlCO0lBQzNDLE9BQU8sQ0FBQyxDQUFDLFNBQVMsQ0FBSSxTQUFTLGFBQVUsQ0FBQyxDQUFDO0FBQy9DLENBQUM7QUFFRCxJQUFNLGFBQWEsR0FBb0IsT0FBTyxDQUFDLE1BQU0sQ0FBQywrQkFBK0IsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUUzRixnQ0FBZ0M7QUFDaEMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxvQkFBb0IsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0FBQ2xFLGFBQWEsQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLFVBQVUsQ0FBQyxDQUFDIiwiZmlsZSI6ImNvcmUvc2hhcmVkX3N0b3JlL2luZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0ICogYXMgUnggZnJvbSAncngnO1xuaW1wb3J0ICogYXMgYW5ndWxhciBmcm9tICdhbmd1bGFyJztcblxuaW1wb3J0IHtpc0pzb25hYmxlfSBmcm9tICcuLi91dGlscy9sYW5nJztcbmltcG9ydCAqIGFzIGltbXV0YWJsZSBmcm9tICcuLi91dGlscy9pbW11dGFibGUnO1xuXG4vKipcbiAqIEEgc2hhcmVkIHN0b3JlIGFjdGlvbiBjb250YWlucyBhIGB0eXBlYCBwcm9wZXJ0eSBhbmQgYW55IG51bWJlciBvZiBvdGhlclxuICogY3VzdG9tIHByb3BlcnRpZXMuIEFjdGlvbiB0eXBlcyBzdGFydGluZyB3aXRoIGBAQGludGVybmFsL2AgYXJlIHJlc2VydmVkXG4gKiBmb3IgaW50ZXJuYWwgdXNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEFjdGlvbiB7XG4gICAgdHlwZTogc3RyaW5nO1xuICAgIFtwcm9wZXJ0eU5hbWU6IHN0cmluZ106IGFueTtcbn1cblxuLy8gdHNsaW50OmRpc2FibGU6bm8tc2hhZG93ZWQtdmFyaWFibGVcbnR5cGUgTWV0aG9kUmV0dXJuczxBY3Rpb25zPiA9IEFjdGlvbnMgZXh0ZW5kcyB7IFtrZXkgaW4ga2V5b2YgQWN0aW9uc106ICgoKSA9PiBpbmZlciBSZXR1cm4pIHwgaW5mZXIgRWxzZSB9ID8gUmV0dXJuIDogbmV2ZXI7XG50eXBlIEZpbHRlckFjdGlvbnM8UmV0dXJuPiA9IFJldHVybiBleHRlbmRzIHsgdHlwZTogaW5mZXIgUiB9ID8gUmV0dXJuIDogbmV2ZXI7XG5leHBvcnQgdHlwZSBHZXRBY3Rpb25zPEFjdGlvbnM+ID0gRmlsdGVyQWN0aW9uczxNZXRob2RSZXR1cm5zPEFjdGlvbnM+PiB8IHsgdHlwZTogJy4uLicgfTtcbi8vIHRzbGludDplbmFibGU6bm8tc2hhZG93ZWQtdmFyaWFibGVcblxuLyoqXG4gKiBBIHRodW5rIGlzIGEgZnVuY3Rpb24sIHdoaWNoIG1lZGlhdGVzIHRoZSBkaXNwYXRjaCBvZiBhbiBhY3Rpb24uIEl0IG1heVxuICogYmUgZGlzcGF0Y2hlZCBpbiB0aGUgc2FtZSB3YXkgYXMgYW4gYWN0aW9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRodW5rIHtcbiAgICAoZGlzcGF0Y2hlcjogRGlzcGF0Y2hlciwgZ2V0U3RhdGU6ICgpID0+IGFueSk6IGFueTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTaGFyZWRTdG9yZVF1ZXJ5PFQsIFU+IHtcbiAgICAoc3RhdGU6IFJ4Lk9ic2VydmFibGU8VD4pOiBSeC5PYnNlcnZhYmxlPFU+O1xufVxuXG5leHBvcnQgY2xhc3MgQWN0aW9ucyB7XG4gICAgLy8vIEludGVybmFsIGFjdGlvbiBmb3Igc2V0dGluZyB0aGlzIHN0b3JlIHRvIGEgc3BlY2lmaWMgdmFsdWUuXG4gICAgcHVibGljIHN0YXRpYyBTRVQgPSA8J0BAaW50ZXJuYWwvU0VUJz4gJ0BAaW50ZXJuYWwvU0VUJztcbiAgICBwdWJsaWMgc2V0KHZhbHVlOiBhbnkpIHtcbiAgICAgICAgcmV0dXJuIHsgdHlwZTogQWN0aW9ucy5TRVQsIHZhbHVlIH07XG4gICAgfVxufVxuXG4vKipcbiAqIEEgc2hhcmVkIHN0b3JlIHJlcHJlc2VudHMgc3RhdGUgdGhhdCBpcyBzaGFyZWQgYmV0d2VlbiBtdWx0aXBsZSBjb21wb25lbnRzIGluXG4gKiBhIHByZWRpY3RhYmxlIHdheS4gQ29tcG9uZW50cyB1cGRhdGUgdGhlIHN0b3JlIGJ5IGRpc3BhdGNoaW5nIGFjdGlvbnMgdG9cbiAqIGl0IHVzaW5nIHRoZSBgZGlzcGF0Y2hgIG1ldGhvZC5cbiAqXG4gKiBFYWNoIHNoYXJlZCBzdG9yZSBhbHNvIHByb3ZpZGVzIGEgd2F5IGZvciB0aGUgY29tcG9uZW50cyB0byBzdWJzY3JpYmUgdG8gYW55XG4gKiBjaGFuZ2VzIGluIHRoZSBzdG9yZSdzIHN0YXRlLlxuICpcbiAqIENvbnNpZGVyIGRlZmluaW5nIGFjdGlvbnMgZm9yIHVzZSBpbiBhIHNoYXJlZCBzdG9yZSBzZXBhcmF0ZWx5IGZyb20gdGhlIHN0b3JlLFxuICogaW4gdGhlIGBhY3Rpb25zYCBzdWJkaXJlY3RvcnkuIFNlZSBbW1NoYXJlZFN0b3JlTWFuYWdlcl1dIGZvciBkZXRhaWxzLlxuICpcbiAqIERvbid0IGZvcmdldCB0byBjYWxsIGNvbnN0cnVjdG9yIHdpdGggYWN0aW9ucyBhcyBhbiBhcmd1bWVudCB3aGVuIGV4dGVuZGluZ1xuICogdGhpcyBjbGFzcy5cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFNoYXJlZFN0b3JlPFQsIFU+IHtcbiAgICBwcml2YXRlIF9zdWJqZWN0OiBSeC5CZWhhdmlvclN1YmplY3Q8VD47XG4gICAgcHJpdmF0ZSBfZGlzcGF0Y2hlcjogRGlzcGF0Y2hlcjtcbiAgICBwcml2YXRlIF9xdWVyaWVzOiB7W25hbWU6IHN0cmluZ106IFJ4Lk9ic2VydmFibGU8YW55Pn0gPSB7fTtcbiAgICBwcml2YXRlIF9hY3Rpb25zOiBVO1xuICAgIHByaXZhdGUgX3N0b3JlSWQ6IHN0cmluZztcblxuICAgIGNvbnN0cnVjdG9yKGFjdGlvbnM/OiBVKSB7XG4gICAgICAgIHRoaXMuX3N1YmplY3QgPSBuZXcgUnguQmVoYXZpb3JTdWJqZWN0KHRoaXMuaW5pdGlhbFN0YXRlKCkpO1xuICAgICAgICB0aGlzLl9hY3Rpb25zID0gYWN0aW9ucztcblxuICAgICAgICAvLyBDcmVhdGUgYSBsb2NhbCBkaXNwYXRjaGVyLlxuICAgICAgICB0aGlzLl9kaXNwYXRjaGVyID0gbmV3IERpc3BhdGNoZXIoKTtcbiAgICAgICAgdGhpcy5fZGlzcGF0Y2hlci5zZXREaXNwYXRjaGVyKHRoaXMuX2Rpc3BhdGNoLmJpbmQodGhpcyksIHRoaXMudmFsdWUuYmluZCh0aGlzKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIHVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGlzIHNoYXJlZCBzdG9yZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHN0b3JlSWQoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N0b3JlSWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBzdG9yZSBhY3Rpb25zLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgYWN0aW9ucygpOiBVIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2FjdGlvbnM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW50ZXJuYWwgZGlzcGF0Y2hlciBpbXBsZW1lbnRhdGlvbi5cbiAgICAgKlxuICAgICAqIE5PVEU6IFRoaXMgbWV0aG9kIGlzIHB1YmxpYyBiZWNhdXNlIHRoZXJlIGlzIG5vIHdheSB0byBkZWZpbmUgcHJpdmF0ZVxuICAgICAqIGJ1dCBhY2Nlc3NpYmxlIHRvIG90aGVyIGNsYXNzZXMgd2l0aGluIHRoaXMgbW9kdWxlIGluIFR5cGVTY3JpcHQuXG4gICAgICovXG4gICAgcHVibGljIF9kaXNwYXRjaChhY3Rpb246IEFjdGlvbik6IHZvaWQge1xuICAgICAgICBjb25zdCBleGlzdGluZ1ZhbHVlID0gdGhpcy52YWx1ZSgpO1xuICAgICAgICBsZXQgcmVkdWNlcjogKHZhbHVlOiBULCBhY3Rpb246IEFjdGlvbikgPT4gVDtcbiAgICAgICAgaWYgKF8uc3RhcnRzV2l0aChhY3Rpb24udHlwZSwgJ0BAaW50ZXJuYWwvJykpIHtcbiAgICAgICAgICAgIHJlZHVjZXIgPSB0aGlzLl9yZWR1Y2VJbnRlcm5hbC5iaW5kKHRoaXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVkdWNlciA9IHRoaXMucmVkdWNlLmJpbmQodGhpcyk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbmV3VmFsdWUgPSByZWR1Y2VyKGV4aXN0aW5nVmFsdWUsIGFjdGlvbik7XG4gICAgICAgIGlmIChfLmlzVW5kZWZpbmVkKG5ld1ZhbHVlKSkgcmV0dXJuO1xuXG4gICAgICAgIGlmIChhbmd1bGFyLmVxdWFscyhleGlzdGluZ1ZhbHVlLCBuZXdWYWx1ZSkpIHJldHVybjtcbiAgICAgICAgdGhpcy5fc3ViamVjdC5vbk5leHQoaW1tdXRhYmxlLm1ha2VJbW11dGFibGUobmV3VmFsdWUpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEaXNwYXRjaGVzIGFuIGFjdGlvbiB0byB0aGlzIHNoYXJlZCBzdG9yZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBhY3Rpb24gQWN0aW9uIHRvIGRpc3BhdGNoXG4gICAgICovXG4gICAgcHVibGljIGRpc3BhdGNoKGFjdGlvbjogR2V0QWN0aW9uczxVPiB8IEdldEFjdGlvbnM8QWN0aW9ucz4gfCBUaHVuayk6IGFueSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kaXNwYXRjaGVyLmRpc3BhdGNoKDxBY3Rpb24gfCBUaHVuaz4gYWN0aW9uKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQZXJmb3JtcyBpbnRlcm5hbCByZWR1Y2UgYWN0aW9ucyBpbXBsZW1lbnRlZCBmb3IgZWFjaCBzaGFyZWQgc3RvcmUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc3RhdGUgRXhpc3Rpbmcgc2hhcmVkIHN0b3JlIHN0YXRlXG4gICAgICogQHBhcmFtIGFjdGlvbiBBY3Rpb24gdG8gcGVyZm9ybVxuICAgICAqIEByZXR1cm4gTmV3IHNoYXJlZCBzdG9yZSBzdGF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgX3JlZHVjZUludGVybmFsKHN0YXRlOiBULCBhY3Rpb246IEFjdGlvbik6IFQge1xuICAgICAgICBzd2l0Y2ggKGFjdGlvbi50eXBlKSB7XG4gICAgICAgICAgICBjYXNlIEFjdGlvbnMuU0VUOiB7XG4gICAgICAgICAgICAgICAgY29uc3QgbmV4dFN0YXRlID0gYWN0aW9uWyd2YWx1ZSddO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm9uU3RhdGVMb2FkKHN0YXRlLCBuZXh0U3RhdGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGVmYXVsdDoge1xuICAgICAgICAgICAgICAgIC8vIERvIG5vdGhpbmcuXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQZXJmb3JtcyB0aGUgZ2l2ZW4gYWN0aW9uIG9uIHRoZSB1bmRlcmx5aW5nIHN0YXRlLlxuICAgICAqXG4gICAgICogU3ViY2xhc3NlcyBtYXkgb3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gaW1wbGVtZW50IGFyYml0cmFyeSBjb21wbGV4XG4gICAgICogYWN0aW9ucyBvbiB0aGUgZGF0YSBzdG9yZS4gVGhpcyBtZXRob2QgTVVTVCBOT1QgbXV0YXRlIHRoZSBleGlzdGluZ1xuICAgICAqIHN0YXRlLiBJbnN0ZWFkLCBpdCBNVVNUIHJldHVybiBhbiBpbW11dGFibGUgY29weS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB2YWx1ZSBFeGlzdGluZyBzaGFyZWQgc3RvcmUgc3RhdGVcbiAgICAgKiBAcGFyYW0gYWN0aW9uIE9wZXJhdGlvbiB0byBwZXJmb3JtXG4gICAgICogQHJldHVybiBOZXcgc2hhcmVkIHN0b3JlIHN0YXRlXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IHJlZHVjZShzdGF0ZTogVCwgYWN0aW9uOiBHZXRBY3Rpb25zPFU+KTogVDtcblxuICAgIC8qKlxuICAgICAqIFByb3ZpZGVzIHRoZSBpbml0aWFsIHN0YXRlIGZvciB0aGlzIHNoYXJlZCBzdG9yZS4gVGhpcyBzdGF0ZSBpc1xuICAgICAqIHVzZWQgd2hlbiB0aGUgc3RvcmUgaXMgaW5pdGlhbGl6ZWQuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGluaXRpYWxTdGF0ZSgpOiBUO1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBtZXRob2QgZ2V0cyBjYWxsZWQgd2hlbiB0aGUgZGF0YSBzdG9yZSdzIHN0YXRlIGlzIGxvYWRlZCBmcm9tXG4gICAgICogYW4gZXh0ZXJuYWwgc291cmNlICh3aGVuIHRoZSBTRVQgYWN0aW9uIGlzIGRpc3BhdGNoZWQgdG8gdGhlIHN0b3JlKS5cbiAgICAgKlxuICAgICAqIEl0IGlzIGNhbGxlZCBiZWZvcmUgdGhlIG5ldyBzdGF0ZSBoYXMgYmVlbiBzZXQuIFRoZSBkZWZhdWx0IGltcGxlbWVudGF0aW9uXG4gICAgICogZG9lcyBub3RoaW5nLlxuICAgICAqXG4gICAgICogQHBhcmFtIHN0YXRlIE9sZCBzdGF0ZVxuICAgICAqIEBwYXJhbSBuZXh0U3RhdGUgTmV3IHN0YXRlXG4gICAgICogQHJldHVybiBQb3NzaWJseSBtb2RpZmllZCBzdGF0ZSB0aGF0IHNob3VsZCBiZSB1c2VkIGluc3RlYWRcbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgb25TdGF0ZUxvYWQoc3RhdGU6IFQsIG5leHRTdGF0ZTogVCk6IFQge1xuICAgICAgICByZXR1cm4gbmV4dFN0YXRlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEEgaGVscGVyIG1ldGhvZCBmb3IgZGVmaW5pbmcgc2hhcmVkIHN0b3JlIHF1ZXJpZXMuIElmIHRoZSBxdWVyeSBpcyBhbHJlYWR5XG4gICAgICogZGVmaW5lZCwgdGhlIGV4aXN0aW5nIG9ic2VydmFibGUgaXMgcmV0dXJuZWQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gbmFtZSBRdWVyeSBuYW1lXG4gICAgICogQHBhcmFtIHF1ZXJ5IFF1ZXJ5IGZ1bmN0aW9uXG4gICAgICogQHJldHVybiBSZXN1bHRpbmcgcXVlcnkgb2JzZXJ2YWJsZVxuICAgICAqL1xuICAgIHByb3RlY3RlZCBkZWZpbmVRdWVyeTxWPihuYW1lOiBzdHJpbmcsIHF1ZXJ5OiBTaGFyZWRTdG9yZVF1ZXJ5PFQsIFY+KTogUnguT2JzZXJ2YWJsZTxWPiB7XG4gICAgICAgIGxldCBvYnNlcnZhYmxlOiBSeC5PYnNlcnZhYmxlPFY+ID0gdGhpcy5fcXVlcmllc1tuYW1lXTtcbiAgICAgICAgaWYgKG9ic2VydmFibGUpIHJldHVybiBvYnNlcnZhYmxlO1xuXG4gICAgICAgIG9ic2VydmFibGUgPSB0aGlzLl9xdWVyaWVzW25hbWVdID0gdGhpcy5vYnNlcnZhYmxlKCkubGV0KHF1ZXJ5KS5kaXN0aW5jdFVudGlsQ2hhbmdlZCgpO1xuICAgICAgICByZXR1cm4gb2JzZXJ2YWJsZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHZhbHVlIHN0b3JlZCBpbiB0aGUgc3RvcmUuXG4gICAgICpcbiAgICAgKiBZb3UgTVVTVCBlbnN1cmUgdGhhdCB0aGUgcmVzdWx0aW5nIG9iamVjdCBpcyBOT1QgbXV0YXRlZCBpbiBhbnkgd2F5LiBBbnlcbiAgICAgKiBtdXRhdGlvbiBtYXkgY2F1c2UgdW5kZWZpbmVkIGJlaGF2aW9yLlxuICAgICAqL1xuICAgIHB1YmxpYyB2YWx1ZSgpOiBUIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGFuIG9ic2VydmFibGUgb2YgdGhlIHN0b3JlJ3MgdmFsdWUuXG4gICAgICpcbiAgICAgKiBZb3UgTVVTVCBlbnN1cmUgdGhhdCB0aGUgb2JzZXJ2ZWQgdmFsdWUgaXMgTk9UIG11dGF0ZWQgaW4gYW55IHdheS4gQW55XG4gICAgICogbXV0YXRpb24gbWF5IGNhdXNlIHVuZGVmaW5lZCBiZWhhdmlvci5cbiAgICAgKi9cbiAgICBwdWJsaWMgb2JzZXJ2YWJsZSgpOiBSeC5PYnNlcnZhYmxlPFQ+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N1YmplY3Q7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIHZhbHVlIHRoYXQgc2hvdWxkIGJlIHVzZWQgd2hlbiBzYXZpbmcgc3RvcmUgc3RhdGUuXG4gICAgICpcbiAgICAgKiBCeSBkZWZhdWx0LCB0aGlzIHdpbGwgcmV0dXJuIHRoZSBzYW1lIGFzIFtbdmFsdWVdXS5cbiAgICAgKi9cbiAgICBwdWJsaWMgc2F2ZVZhbHVlKCk6IFQge1xuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZSgpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBbW1NpbXBsZVNoYXJlZFN0b3JlXV0gaXMgYSBoZWxwZXIgY2xhc3MgaW50ZW5kZWQgdG8gYmUgdXNlZCBhcyBhIHR5cGUgaW4gY29uanVuY3Rpb24gd2l0aFxuICogW1tTaGFyZWRTdG9yZVByb3ZpZGVyXV0ncyBgY3JlYXRlYCBtZXRob2Qgd2hlcmUgb25seSBTRVQgYWN0aW9uIGlzIHVzZWQuXG4gKlxuICogSW4gdGhpcyBjYXNlIG5vIHN1YmNsYXNzaW5nIG9mIHN0b3JlIGFuZCBhY3Rpb25zIGlzIG5lZWRlZCBiZWNhdXNlIG9ubHkgU0VUIGFjdGlvbiBpcyB1c2VkLlxuICogVGhpcyBpcyBjb252ZW5pZW50IGZvciB1c2UgY2FzZXMgd2hlcmUgeW91IG9ubHkgbmVlZCB0byBzZXQgYSB2YWx1ZSB0aGF0IHlvdSBjYW4gc3Vic2NyaWJlXG4gKiB0byBmcm9tIG90aGVyIGNvbXBvbmVudHMuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBTaW1wbGVTaGFyZWRTdG9yZTxUPiBleHRlbmRzIFNoYXJlZFN0b3JlPFQsIHR5cGVvZiB1bmRlZmluZWQ+IHsgfVxuXG4vKipcbiAqIFVzZWQgdG8gZGlzcGF0Y2ggYWN0aW9ucyB0byBzaGFyZWQgc3RvcmVzLlxuICovXG5leHBvcnQgY2xhc3MgRGlzcGF0Y2hlciBleHRlbmRzIFJ4LlN1YmplY3Q8QWN0aW9uPiB7XG4gICAgcHJpdmF0ZSBfZ2V0U3RhdGU6ICgpID0+IGFueSA9ICgpID0+IHVuZGVmaW5lZDtcblxuICAgIC8qKlxuICAgICAqIENvbmZpZ3VyZXMgYSBkaXNwYXRjaGVyIGZ1bmN0aW9uIGZvciB0aGlzIGRpc3BhdGNoZXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gZGlzcGF0Y2hlciBUaGUgZGlzcGF0Y2hlciBmdW5jdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyBzZXREaXNwYXRjaGVyKGRpc3BhdGNoZXI6IChhY3Rpb246IEFjdGlvbikgPT4gdm9pZCwgZ2V0U3RhdGU/OiAoKSA9PiBhbnkpOiB2b2lkIHtcbiAgICAgICAgLy8gVGhlIGRpc3BhdGNoZXIgaXMgdXNlZCB0byBkaXNwYXRjaCBhbGwgYWN0aW9ucyB1c2luZyBhIHF1ZXVlLCBzbyBhY3Rpb25zXG4gICAgICAgIC8vIG1heSBpbnZva2UgdGhlIGRpc3BhdGNoIG1ldGhvZCB3aXRob3V0IGNhdXNpbmcgcmVjdXJzaW9uLiBUaGUgY3VycmVudFRocmVhZFxuICAgICAgICAvLyBzY2hlZHVsZXIgcHV0cyBhbGwgcGVuZGluZyBpdGVtcyBpbnNpZGUgYSBxdWV1ZSwgd2hpY2ggaXMgZGlzcGF0Y2hlZCBhZnRlclxuICAgICAgICAvLyByZXR1cm5pbmcgZnJvbSBhY3RpdmUgZGlzcGF0Y2guXG4gICAgICAgIHRoaXMub2JzZXJ2ZU9uKFJ4LlNjaGVkdWxlci5jdXJyZW50VGhyZWFkKS5zdWJzY3JpYmUoZGlzcGF0Y2hlcik7XG4gICAgICAgIGlmIChnZXRTdGF0ZSkgdGhpcy5fZ2V0U3RhdGUgPSBnZXRTdGF0ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEaXNwYXRjaGVzIGFuIGFjdGlvbiB2aWEgdGhpcyBkaXNwYXRjaGVyLlxuICAgICAqL1xuICAgIHB1YmxpYyBkaXNwYXRjaChhY3Rpb246IEFjdGlvbiB8IFRodW5rKTogYW55IHtcbiAgICAgICAgaWYgKF8uaXNGdW5jdGlvbihhY3Rpb24pKSB7XG4gICAgICAgICAgICAvLyBBIHRodW5rIGhhcyBiZWVuIHBhc3NlZC4gRXhlY3V0ZSBpdCB3aXRoIHRoZSBkaXNwYXRjaGVyIGFyZ3VtZW50IGFuZFxuICAgICAgICAgICAgLy8gcmV0dXJuIHRoZSByZXN1bHQuXG4gICAgICAgICAgICByZXR1cm4gYWN0aW9uKHRoaXMsIHRoaXMuX2dldFN0YXRlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMub25OZXh0KGFjdGlvbik7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2hhcmVkU3RvcmVGYWN0b3J5PFQsIFU+IHtcbiAgICBuZXcgKC4uLmFyZ3MpOiBTaGFyZWRTdG9yZTxULCBVPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBY3Rpb25GYWN0b3J5IHtcbiAgICBuZXcgKC4uLmFyZ3MpOiBhbnk7XG59XG5cbi8qKlxuICogU2hhcmVkIHN0b3JlIHByb3ZpZGVyLCBlbmFibGluZyByZWdpc3RyYXRpb24gb2Ygc2hhcmVkIHN0b3Jlcy4gQWxsIHN0b3Jlc1xuICogbXVzdCBiZSByZWdpc3RlcmVkIGluIHRoZSBhcHBsaWNhdGlvbiBjb25maWd1cmF0aW9uIHBoYXNlLlxuICovXG5leHBvcnQgY2xhc3MgU2hhcmVkU3RvcmVQcm92aWRlciB7XG4gICAgLy8vIEEgbGlzdCBvZiByZWdpc3RlcmVkIHN0b3Jlcy5cbiAgICBwcml2YXRlIF9zdG9yZXM6IHN0cmluZ1tdID0gW107XG4gICAgLy8vIFByb3ZpZGUgc2VydmljZS5cbiAgICBwcml2YXRlIF9wcm92aWRlOiBhbmd1bGFyLmF1dG8uSVByb3ZpZGVTZXJ2aWNlO1xuXG4gICAgLy8gQG5nSW5qZWN0XG4gICAgY29uc3RydWN0b3IoJHByb3ZpZGU6IGFuZ3VsYXIuYXV0by5JUHJvdmlkZVNlcnZpY2UpIHtcbiAgICAgICAgdGhpcy5fcHJvdmlkZSA9ICRwcm92aWRlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEEgbGlzdCBvZiByZWdpc3RlcmVkIHN0b3Jlcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHN0b3JlcygpOiBzdHJpbmdbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9zdG9yZXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIG5ldyBzaGFyZWQgc3RvcmUuXG4gICAgICpcbiAgICAgKiBXaGVuIGNob29zaW5nIGFuIGlkZW50aWZpZXIgZm9yIHRoZSBzdG9yZSwgeW91IHNob3VsZCB3cml0ZSBpdCB1c2luZ1xuICAgICAqIGtlYmFiLWNhc2UgYW5kIG5vdCBpbmNsdWRlIHRoZSBzdHJpbmcgJ3N0b3JlJyBlaXRoZXIgYXMgYSBwcmVmaXggb3JcbiAgICAgKiBhIHN1ZmZpeC5cbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIG1heSBvbmx5IGJlIGNhbGxlZCBpbiB0aGUgYXBwbGljYXRpb24ncyBjb25maWd1cmF0aW9uXG4gICAgICogcGhhc2UuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc3RvcmVJZCBJZGVudGlmaWVyIG9mIHRoZSBzaGFyZWQgc3RvcmUgKG11c3QgYmUgZ2xvYmFsbHkgdW5pcXVlKVxuICAgICAqIEBwYXJhbSBpbml0aWFsU3RhdGUgT3B0aW9uYWwgaW5pdGlhbCBzdGF0ZSBvZiB0aGUgc2hhcmVkIHN0b3JlXG4gICAgICovXG4gICAgcHVibGljIGNyZWF0ZTxUPihzdG9yZUlkOiBzdHJpbmcsIGluaXRpYWxTdGF0ZTogVCA9IG51bGwpOiB2b2lkIHtcbiAgICAgICAgY2xhc3MgRXh0ZW5kZWQgZXh0ZW5kcyBTaW1wbGVTaGFyZWRTdG9yZTxUPiB7XG4gICAgICAgICAgICBwcm90ZWN0ZWQgaW5pdGlhbFN0YXRlKCkgeyByZXR1cm4gaW5pdGlhbFN0YXRlOyB9XG4gICAgICAgICAgICBwcm90ZWN0ZWQgcmVkdWNlKHN0YXRlOiBULCBhY3Rpb246IEFjdGlvbik6IFQgeyByZXR1cm4gdW5kZWZpbmVkOyB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnJlZ2lzdGVyPFQ+KHN0b3JlSWQsIEV4dGVuZGVkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWdpc3RlcnMgYSBuZXcgc2hhcmVkIHN0b3JlLiBBIHN0b3JlIHdpdGggdGhlIHNhbWUgbmFtZSBtdXN0IG5vdCBhbHJlYWR5XG4gICAgICogYmUgcmVnaXN0ZXJlZC5cbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIG1heSBvbmx5IGJlIGNhbGxlZCBpbiB0aGUgYXBwbGljYXRpb24ncyBjb25maWd1cmF0aW9uXG4gICAgICogcGhhc2UuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc3RvcmVJZCBJZGVudGlmaWVyIG9mIHRoZSBzaGFyZWQgc3RvcmUgKG11c3QgYmUgZ2xvYmFsbHkgdW5pcXVlKVxuICAgICAqIEBwYXJhbSBTaGFyZWQgc3RvcmUgY2xhc3NcbiAgICAgKi9cbiAgICBwdWJsaWMgcmVnaXN0ZXI8VD4oc3RvcmVJZDogc3RyaW5nLCBzdG9yZVR5cGU6IFNoYXJlZFN0b3JlRmFjdG9yeTxULCBhbnk+KTogdm9pZCB7XG4gICAgICAgIC8vIFJlZ2lzdGVyIHRoZSBzdG9yZSBhcyBhbiBhbmd1bGFyIHNlcnZpY2UuIFdlIHVzZSBmYWN0b3J5IGluc3RlYWQgb2Ygc2VydmljZVxuICAgICAgICAvLyBzbyB3ZSBjYW4gc2V0IHRoZSBgX3N0b3JlSWRgIG9uIHRoZSBpbnN0YW5jZS5cbiAgICAgICAgdGhpcy5fcHJvdmlkZS5mYWN0b3J5KFxuICAgICAgICAgICAgc3RvcmVJZFRvU2VydmljZUlkKHN0b3JlSWQpLFxuICAgICAgICAgICAgLy8gQG5nSW5qZWN0XG4gICAgICAgICAgICAoJGluamVjdG9yOiBhbmd1bGFyLmF1dG8uSUluamVjdG9yU2VydmljZSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHN0b3JlOiBhbnkgPSAkaW5qZWN0b3IuaW5zdGFudGlhdGUoc3RvcmVUeXBlKTtcbiAgICAgICAgICAgICAgICBzdG9yZS5fc3RvcmVJZCA9IHN0b3JlSWQ7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0b3JlO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgICB0aGlzLl9zdG9yZXMucHVzaChzdG9yZUlkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWdpc3RlcnMgYSBuZXcgYWN0aW9ucyBjbGFzcy5cbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIG1heSBvbmx5IGJlIGNhbGxlZCBpbiB0aGUgYXBwbGljYXRpb24ncyBjb25maWd1cmF0aW9uXG4gICAgICogcGhhc2UuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gYWN0aW9uc0lkIElkZW50aWZpZXIgb2YgdGhlIGFjdGlvbnMgY2xhc3MgKG11c3QgYmUgZ2xvYmFsbHkgdW5pcXVlKVxuICAgICAqIEBwYXJhbSBBY3Rpb25zIGNsYXNzXG4gICAgICovXG4gICAgcHVibGljIHJlZ2lzdGVyQWN0aW9ucyhhY3Rpb25zSWQ6IHN0cmluZywgYWN0aW9uc1R5cGU6IEFjdGlvbkZhY3RvcnkpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fcHJvdmlkZS5zZXJ2aWNlKGFjdGlvbnNJZFRvU2VydmljZUlkKGFjdGlvbnNJZCksIGFjdGlvbnNUeXBlKTtcbiAgICB9XG5cbiAgICAvLyBAbmdJbmplY3RcbiAgICBwdWJsaWMgJGdldCgkaW5qZWN0b3I6IGFuZ3VsYXIuYXV0by5JSW5qZWN0b3JTZXJ2aWNlLFxuICAgICAgICAgICAgICAgIGRpc3BhdGNoZXI6IERpc3BhdGNoZXIpOiBTaGFyZWRTdG9yZU1hbmFnZXIge1xuICAgICAgICByZXR1cm4gbmV3IFNoYXJlZFN0b3JlTWFuYWdlcigkaW5qZWN0b3IsIGRpc3BhdGNoZXIsIHRoaXMpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBNYW5hZ2VyIG9mIGFsbCBzaGFyZWQgc3RvcmVzIChzZWUgW1tTaGFyZWRTdG9yZV1dKSBpbiBhbiBhcHBsaWNhdGlvbi4gRWFjaCBzdG9yZVxuICogcmVxdWlyZXMgYSBnbG9iYWxseSB1bmlxdWUgaWRlbnRpZmllciwgd2hpY2ggaXMgYWxzbyB1c2VkIGR1cmluZyBzdGF0ZSBzZXJpYWxpemF0aW9uLlxuICpcbiAqIEluIG9yZGVyIHRvIHVzZSBzaGFyZWQgc3RvcmVzLCB5b3UgbXVzdCBmaXJzdCBjcmVhdGUgdGhlbS4gVGhlIGJlc3Qgd2F5IHRvIGRvXG4gKiB0aGlzIGlzIGluc2lkZSB5b3VyIG1vZHVsZSdzIGBjb25maWdgIGZ1bmN0aW9uIGFzIGZvbGxvd3M6XG4gKiBgYGBcbiAqIG1vZHVsZS5jb25maWcoKHNoYXJlZFN0b3JlTWFuYWdlclByb3ZpZGVyOiBTaGFyZWRTdG9yZVByb3ZpZGVyKSA9PiB7XG4gKiAgICAgLy8gQ3JlYXRlIHRoZSBzZWxlY3RlZCBST1NFMiBkYXRhIGl0ZW1zIHNoYXJlZCBzdG9yZS5cbiAqICAgICBzaGFyZWRTdG9yZU1hbmFnZXJQcm92aWRlci5jcmVhdGUoJ3Jvc2UyLXNlbGVjdGVkLWRhdGEtaXRlbScpO1xuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBUaGUgc3RvcmUgbWF5IHRoZW4gYmUgdXNlZCBhcyBpbnB1dCB0byBzaGFyZWQgc3RhdGUgZGVmaW5lZCBvbiBzdGF0ZWZ1bFxuICogY29tcG9uZW50cyAoc2VlIFtbU3RhdGVmdWxDb21wb25lbnRCYXNlXV0pIGFuZCBjYW4gYWxzbyBiZSBpbmplY3RlZCB1c2luZ1xuICogYSBzcGVjaWZpYyB0b2tlbi4gSWYgYSBzdG9yZSBpcyBuYW1lZCBgbXktbmljZS1pdGVtc2AsIGl0IHdpbGwgYmUgaW5qZWN0YWJsZVxuICogYnkgdXNpbmcgdGhlIHRva2VuIGBteU5pY2VJdGVtc1N0b3JlYC5cbiAqXG4gKiBJZiB5b3Ugd2lzaCB0byBkZWZpbmUgc2hhcmVkIHN0b3JlcyB3aGljaCBzdXBwb3J0IGFkZGl0aW9uYWwgYWN0aW9ucywgeW91XG4gKiBzaG91bGQgc3ViY2xhc3MgW1tTaGFyZWRTdG9yZV1dIGFuZCByZWdpc3RlciB5b3VyIHN0b3JlIGJ5IHVzaW5nIFtbcmVnaXN0ZXJdXVxuICogYXMgZm9sbG93czpcbiAqIGBgYFxuICogY2xhc3MgQ29tcGxleEFjdGlvbnMge1xuICogICAgIHN0YXRpYyBBRERfSVRFTSA9ICdjb21wbGV4L2FkZF9pdGVtJztcbiAqICAgICBwdWJsaWMgYWRkSXRlbSh2YWx1ZTogdHlwZXMuU2FtcGxlRGF0YSkge1xuICogICAgICAgICByZXR1cm4geyB0eXBlOiBDb21wbGV4QWN0aW9ucy5BRERfSVRFTSwgaXRlbTogdmFsdWUgfTtcbiAqICAgICB9XG4gKiB9XG4gKlxuICogY2xhc3MgQ29tcGxleFN0b3JlIGV4dGVuZHMgU2hhcmVkU3RvcmU8dHlwZXMuU2FtcGxlRGF0YVtdLCBDb21wbGV4QWN0aW9ucz4ge1xuICogICAgIC8vIEBuZ0luamVjdFxuICogICAgIGNvbnN0cnVjdG9yKGNvbXBsZXhBY3Rpb25zOiBDb21wbGV4QWN0aW9ucykge1xuICogICAgICAgICBzdXBlcihjb21wbGV4QWN0aW9ucyk7XG4gKiAgICAgfVxuICpcbiAqICAgICBwcm90ZWN0ZWQgaW5pdGlhbFN0YXRlKCk6IHR5cGVzLlNhbXBsZURhdGFbXSB7XG4gKiAgICAgICAgIHJldHVybiBbXTtcbiAqICAgICB9XG4gKlxuICogICAgIHByb3RlY3RlZCByZWR1Y2Uoc3RhdGU6IHR5cGVzLlNhbXBsZURhdGFbXSwgYWN0aW9uOiBhbnkpOiB2b2lkIHtcbiAqICAgICAgICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICogICAgICAgICAgICAgY2FzZSBBRERfSVRFTToge1xuICogICAgICAgICAgICAgICAgIHJldHVybiBfLnVuaW9uKHN0YXRlLCBhY3Rpb24uaXRlbSk7XG4gKiAgICAgICAgICAgICB9XG4gKiAgICAgICAgICAgICAvLyAuLi5cbiAqICAgICAgICAgfVxuICogICAgIH1cbiAqIH1cbiAqXG4gKiBtb2R1bGUuY29uZmlnKChzaGFyZWRTdG9yZU1hbmFnZXJQcm92aWRlcjogU2hhcmVkU3RvcmVQcm92aWRlcikgPT4ge1xuICogICAgIHNoYXJlZFN0b3JlTWFuYWdlclByb3ZpZGVyLnJlZ2lzdGVyQWN0aW9ucygnY29tcGxleCcsIENvbXBsZXhBY3Rpb25zKTtcbiAqICAgICBzaGFyZWRTdG9yZU1hbmFnZXJQcm92aWRlci5yZWdpc3RlcignY29tcGxleCcsIENvbXBsZXhTdG9yZSk7XG4gKiB9KTtcbiAqIGBgYFxuICpcbiAqIFdoZW4gY3JlYXRpbmcgYSBuZXcgc2hhcmVkIHN0b3JlLCBhIGdvb2QgZGVzaWduIHByYWN0aWNlIGlzIHRvIHNlcGFyYXRlXG4gKiBhY3Rpb25zIGludG8gdGhlIGBhY3Rpb25zYCBkaXJlY3RvcnkgYW5kIGltcGxlbWVudCBhY3Rpb25zIGFzIG1ldGhvZHMgb25cbiAqIHRoZSBhY3Rpb25zIGNsYXNzIG5hbWVkIGFmdGVyIHlvdXIgc3RvcmUgKGVnLiBmb3Igc3RvcmUgYEZvb1N0b3JlYCBwdXRcbiAqIGFjdGlvbnMgaW50byBgRm9vQWN0aW9uc2ApLlxuICpcbiAqIFN0b3JlcyB0aGVtc2VsdmVzIHNob3VsZCBvbmx5IGltcGxlbWVudCB0aGUgc3RhdGUgbWFuYWdlbWVudCBmdW5jdGlvbmFsaXR5XG4gKiBhbmQgbW9zdCBidXNpbmVzcyBsb2dpYyBzaG91bGQgYmUgY29udGFpbmVkIGluIHRoZSBhY3Rpb25zIGNsYXNzLiBGb3JcbiAqIGV4YW1wbGUsIGlmIGFjdGlvbnMgcmVxdWlyZSBzb21lIGFzeW5jaHJvbm91cyBvcGVyYXRpb25zIHRvIGJlIHBlcmZvcm1lZFxuICogb24gYSByZW1vdGUgYmFja2VuZCBhbGwgdGhpcyBmdW5jdGlvbmFsaXR5IHNob3VsZCBiZSBwdXQgaW50byB0aGUgYWN0aW9uc1xuICogY2xhc3MgYW5kIG5vdCBpbnRvIHRoZSBzdG9yZS5cbiAqXG4gKiBBbGwgYWN0aW9ucyBjbGFzc2VzIHNob3VsZCBiZSByZWdpc3RlcmVkIHZpYSB0aGUgW1tTaGFyZWRTdG9yZVByb3ZpZGVyXV1cbiAqIGFuZCBzdXBwb3J0IEFuZ3VsYXIgZGVwZW5kZW5jeSBpbmplY3Rpb24uIEFjdGlvbnMgY2xhc3NlcyBhcmUgaW5qZWN0YWJsZVxuICogdW5kZXIgdGhlIHRva2VuIGBpZEFjdGlvbnNgIHdoZXJlIHRoZSBgaWRgIHBhcnQgaXMgdGhlIHZhbHVlIGRlZmluZWQgYnlcbiAqIGBhY3Rpb25zSWRgLCBmb3JtYXR0ZWQgaW4gY2FtZWxDYXNlLiBUaGUgY29uc3RydWN0b3Igb2YgYW4gYWN0aW9uc1xuICogY2xhc3MgbWF5IGFsc28gaW5qZWN0IG90aGVyIGRlcGVuZGVuY2llcy5cbiAqXG4gKiBGb3IgY29udmVuaWVuY2UsIHlvdSBtYXkgaW5qZWN0IHlvdXIgYWN0aW9ucyBjbGFzcyBpbiB5b3VyIHNoYXJlZCBzdG9yZVxuICogY2xhc3MgdW5kZXIgdGhlIHB1YmxpYyBhdHRyaWJ1dGUgYGFjdGlvbnNgLiBUaGlzIHdheSBvbmUgbWF5IGdldCB0aGVcbiAqIGFjdGlvbnMgY2xhc3Mgc2ltcGx5IGJ5IGFjY2Vzc2luZyBgc3RvcmUuYWN0aW9uc2Agd2hlbiBnaXZlbiBhIHNoYXJlZFxuICogc3RvcmUgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBjbGFzcyBTaGFyZWRTdG9yZU1hbmFnZXIge1xuICAgIC8vLyBTaGFyZWQgc3RvcmUgcHJvdmlkZXIuXG4gICAgcHJpdmF0ZSBfcHJvdmlkZXI6IFNoYXJlZFN0b3JlUHJvdmlkZXI7XG4gICAgLy8vIERpc3BhdGNoZXIuXG4gICAgcHJpdmF0ZSBfZGlzcGF0Y2hlcjogRGlzcGF0Y2hlcjtcbiAgICAvLy8gQW5ndWxhciBpbmplY3Rvci5cbiAgICBwcml2YXRlIF9pbmplY3RvcjogYW5ndWxhci5hdXRvLklJbmplY3RvclNlcnZpY2U7XG5cbiAgICAvLyBAbmdJbmplY3RcbiAgICBjb25zdHJ1Y3RvcigkaW5qZWN0b3I6IGFuZ3VsYXIuYXV0by5JSW5qZWN0b3JTZXJ2aWNlLFxuICAgICAgICAgICAgICAgIGRpc3BhdGNoZXI6IERpc3BhdGNoZXIsXG4gICAgICAgICAgICAgICAgc2hhcmVkU3RvcmVNYW5hZ2VyUHJvdmlkZXI6IFNoYXJlZFN0b3JlUHJvdmlkZXIpIHtcbiAgICAgICAgdGhpcy5fcHJvdmlkZXIgPSBzaGFyZWRTdG9yZU1hbmFnZXJQcm92aWRlcjtcbiAgICAgICAgdGhpcy5faW5qZWN0b3IgPSAkaW5qZWN0b3I7XG4gICAgICAgIHRoaXMuX2Rpc3BhdGNoZXIgPSBkaXNwYXRjaGVyO1xuICAgICAgICB0aGlzLl9kaXNwYXRjaGVyLnNldERpc3BhdGNoZXIodGhpcy5fZGlzcGF0Y2guYmluZCh0aGlzKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCBzdG9yZS4gSXQgaXMgYW4gZXJyb3IgdG8gcmVxdWVzdCBhIHN0b3JlXG4gICAgICogd2hpY2ggZG9lc24ndCBleGlzdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBzdG9yZUlkIElkZW50aWZpZXIgb2YgdGhlIHNoYXJlZCBzdG9yZVxuICAgICAqIEByZXR1cm4gU2hhcmVkIHN0b3JlIGluc3RhbmNlXG4gICAgICovXG4gICAgcHVibGljIGdldFN0b3JlPFQ+KHN0b3JlSWQ6IHN0cmluZyk6IFNoYXJlZFN0b3JlPFQsIGFueT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5faW5qZWN0b3IuZ2V0PFNoYXJlZFN0b3JlPFQsIGFueT4+KHN0b3JlSWRUb1NlcnZpY2VJZChzdG9yZUlkKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGlzcGF0Y2hlcyBhbiBhY3Rpb24gdG8gYWxsIHNoYXJlZCBzdG9yZXMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gYWN0aW9uIEFjdGlvbiB0byBkaXNwYXRjaFxuICAgICAqL1xuICAgIHB1YmxpYyBkaXNwYXRjaChhY3Rpb246IEFjdGlvbiB8IFRodW5rKTogYW55IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2Rpc3BhdGNoZXIuZGlzcGF0Y2goYWN0aW9uKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbnRlcm5hbCBnbG9iYWwgZGlzcGF0Y2ggaW1wbGVtZW50YXRpb24uXG4gICAgICovXG4gICAgcHJpdmF0ZSBfZGlzcGF0Y2goYWN0aW9uOiBBY3Rpb24pOiB2b2lkIHtcbiAgICAgICAgZm9yIChjb25zdCBzdG9yZUlkIG9mIHRoaXMuX3Byb3ZpZGVyLnN0b3Jlcykge1xuICAgICAgICAgICAgdGhpcy5nZXRTdG9yZShzdG9yZUlkKS5fZGlzcGF0Y2goYWN0aW9uKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlcmlhbGl6ZXMgdGhlIHZhbHVlcyBvZiBhbGwgc2hhcmVkIHN0b3Jlcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgc2F2ZVN0YXRlKCk6IGFueSB7XG4gICAgICAgIGxldCByZXN1bHQgPSB7fTtcbiAgICAgICAgZm9yIChjb25zdCBzdG9yZUlkIG9mIHRoaXMuX3Byb3ZpZGVyLnN0b3Jlcykge1xuICAgICAgICAgICAgbGV0IHZhbHVlID0gdGhpcy5nZXRTdG9yZShzdG9yZUlkKS5zYXZlVmFsdWUoKTtcbiAgICAgICAgICAgIGlmIChpc0pzb25hYmxlKHZhbHVlKSkge1xuICAgICAgICAgICAgICAgIHJlc3VsdFtzdG9yZUlkXSA9IHZhbHVlLn