UNPKG

@genialis/resolwe

Version:
495 lines (494 loc) 51.8 kB
"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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb3JlL3NoYXJlZF9zdG9yZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFBQSwwQkFBNEI7QUFDNUIsdUJBQXlCO0FBQ3pCLGlDQUFtQztBQUVuQyxzQ0FBeUM7QUFDekMsOENBQWdEO0FBOEJoRDtJQUFBO0lBTUEsQ0FBQztJQUhVLHFCQUFHLEdBQVYsVUFBVyxLQUFVO1FBQ2pCLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLEdBQUcsRUFBRSxLQUFLLE9BQUEsRUFBRSxDQUFDO0lBQ3hDLENBQUM7SUFKRCwrREFBK0Q7SUFDakQsV0FBRyxHQUFzQixnQkFBZ0IsQ0FBQztJQUk1RCxjQUFDO0NBTkQsQUFNQyxJQUFBO0FBTlksMEJBQU87QUFRcEI7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNIO0lBT0kscUJBQVksT0FBVztRQUpmLGFBQVEsR0FBeUMsRUFBRSxDQUFDO1FBS3hELElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxFQUFFLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDO1FBQzVELElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFDO1FBRXhCLDZCQUE2QjtRQUM3QixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksVUFBVSxFQUFFLENBQUM7UUFDcEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNyRixDQUFDO0lBS0Qsc0JBQVcsZ0NBQU87UUFIbEI7O1dBRUc7YUFDSDtZQUNJLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztRQUN6QixDQUFDOzs7T0FBQTtJQUtELHNCQUFXLGdDQUFPO1FBSGxCOztXQUVHO2FBQ0g7WUFDSSxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUM7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QUksT0FBTyxXQUFRLENBQUMsQ0FBQztBQUMzQyxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFTLG9CQUFvQixDQUFDLFNBQWlCO0lBQzNDLE9BQU8sQ0FBQyxDQUFDLFNBQVMsQ0FBSSxTQUFTLGFBQVUsQ0FBQyxDQUFDO0FBQy9DLENBQUM7QUFFRCxJQUFNLGFBQWEsR0FBb0IsT0FBTyxDQUFDLE1BQU0sQ0FBQywrQkFBK0IsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUUzRixnQ0FBZ0M7QUFDaEMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxvQkFBb0IsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0FBQ2xFLGFBQWEsQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLFVBQVUsQ0FBQyxDQUFDIiwiZmlsZSI6ImNvcmUvc2hhcmVkX3N0b3JlL2luZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0ICogYXMgUnggZnJvbSAncngnO1xuaW1wb3J0ICogYXMgYW5ndWxhciBmcm9tICdhbmd1bGFyJztcblxuaW1wb3J0IHtpc0pzb25hYmxlfSBmcm9tICcuLi91dGlscy9sYW5nJztcbmltcG9ydCAqIGFzIGltbXV0YWJsZSBmcm9tICcuLi91dGlscy9pbW11dGFibGUnO1xuXG4vKipcbiAqIEEgc2hhcmVkIHN0b3JlIGFjdGlvbiBjb250YWlucyBhIGB0eXBlYCBwcm9wZXJ0eSBhbmQgYW55IG51bWJlciBvZiBvdGhlclxuICogY3VzdG9tIHByb3BlcnRpZXMuIEFjdGlvbiB0eXBlcyBzdGFydGluZyB3aXRoIGBAQGludGVybmFsL2AgYXJlIHJlc2VydmVkXG4gKiBmb3IgaW50ZXJuYWwgdXNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEFjdGlvbiB7XG4gICAgdHlwZTogc3RyaW5nO1xuICAgIFtwcm9wZXJ0eU5hbWU6IHN0cmluZ106IGFueTtcbn1cblxuLy8gdHNsaW50OmRpc2FibGU6bm8tc2hhZG93ZWQtdmFyaWFibGVcbnR5cGUgTWV0aG9kUmV0dXJuczxBY3Rpb25zPiA9IEFjdGlvbnMgZXh0ZW5kcyB7IFtrZXkgaW4ga2V5b2YgQWN0aW9uc106ICgoKSA9PiBpbmZlciBSZXR1cm4pIHwgaW5mZXIgRWxzZSB9ID8gUmV0dXJuIDogbmV2ZXI7XG50eXBlIEZpbHRlckFjdGlvbnM8UmV0dXJuPiA9IFJldHVybiBleHRlbmRzIHsgdHlwZTogaW5mZXIgUiB9ID8gUmV0dXJuIDogbmV2ZXI7XG5leHBvcnQgdHlwZSBHZXRBY3Rpb25zPEFjdGlvbnM+ID0gRmlsdGVyQWN0aW9uczxNZXRob2RSZXR1cm5zPEFjdGlvbnM+PiB8IHsgdHlwZTogJy4uLicgfTtcbi8vIHRzbGludDplbmFibGU6bm8tc2hhZG93ZWQtdmFyaWFibGVcblxuLyoqXG4gKiBBIHRodW5rIGlzIGEgZnVuY3Rpb24sIHdoaWNoIG1lZGlhdGVzIHRoZSBkaXNwYXRjaCBvZiBhbiBhY3Rpb24uIEl0IG1heVxuICogYmUgZGlzcGF0Y2hlZCBpbiB0aGUgc2FtZSB3YXkgYXMgYW4gYWN0aW9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRodW5rIHtcbiAgICAoZGlzcGF0Y2hlcjogRGlzcGF0Y2hlciwgZ2V0U3RhdGU6ICgpID0+IGFueSk6IGFueTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTaGFyZWRTdG9yZVF1ZXJ5PFQsIFU+IHtcbiAgICAoc3RhdGU6IFJ4Lk9ic2VydmFibGU8VD4pOiBSeC5PYnNlcnZhYmxlPFU+O1xufVxuXG5leHBvcnQgY2xhc3MgQWN0aW9ucyB7XG4gICAgLy8vIEludGVybmFsIGFjdGlvbiBmb3Igc2V0dGluZyB0aGlzIHN0b3JlIHRvIGEgc3BlY2lmaWMgdmFsdWUuXG4gICAgcHVibGljIHN0YXRpYyBTRVQgPSA8J0BAaW50ZXJuYWwvU0VUJz4gJ0BAaW50ZXJuYWwvU0VUJztcbiAgICBwdWJsaWMgc2V0KHZhbHVlOiBhbnkpIHtcbiAgICAgICAgcmV0dXJuIHsgdHlwZTogQWN0aW9ucy5TRVQsIHZhbHVlIH07XG4gICAgfVxufVxuXG4vKipcbiAqIEEgc2hhcmVkIHN0b3JlIHJlcHJlc2VudHMgc3RhdGUgdGhhdCBpcyBzaGFyZWQgYmV0d2VlbiBtdWx0aXBsZSBjb21wb25lbnRzIGluXG4gKiBhIHByZWRpY3RhYmxlIHdheS4gQ29tcG9uZW50cyB1cGRhdGUgdGhlIHN0b3JlIGJ5IGRpc3BhdGNoaW5nIGFjdGlvbnMgdG9cbiAqIGl0IHVzaW5nIHRoZSBgZGlzcGF0Y2hgIG1ldGhvZC5cbiAqXG4gKiBFYWNoIHNoYXJlZCBzdG9yZSBhbHNvIHByb3ZpZGVzIGEgd2F5IGZvciB0aGUgY29tcG9uZW50cyB0byBzdWJzY3JpYmUgdG8gYW55XG4gKiBjaGFuZ2VzIGluIHRoZSBzdG9yZSdzIHN0YXRlLlxuICpcbiAqIENvbnNpZGVyIGRlZmluaW5nIGFjdGlvbnMgZm9yIHVzZSBpbiBhIHNoYXJlZCBzdG9yZSBzZXBhcmF0ZWx5IGZyb20gdGhlIHN0b3JlLFxuICogaW4gdGhlIGBhY3Rpb25zYCBzdWJkaXJlY3RvcnkuIFNlZSBbW1NoYXJlZFN0b3JlTWFuYWdlcl1dIGZvciBkZXRhaWxzLlxuICpcbiAqIERvbid0IGZvcmdldCB0byBjYWxsIGNvbnN0cnVjdG9yIHdpdGggYWN0aW9ucyBhcyBhbiBhcmd1bWVudCB3aGVuIGV4dGVuZGluZ1xuICogdGhpcyBjbGFzcy5cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFNoYXJlZFN0b3JlPFQsIFU+IHtcbiAgICBwcml2YXRlIF9zdWJqZWN0OiBSeC5CZWhhdmlvclN1YmplY3Q8VD47XG4gICAgcHJpdmF0ZSBfZGlzcGF0Y2hlcjogRGlzcGF0Y2hlcjtcbiAgICBwcml2YXRlIF9xdWVyaWVzOiB7W25hbWU6IHN0cmluZ106IFJ4Lk9ic2VydmFibGU8YW55Pn0gPSB7fTtcbiAgICBwcml2YXRlIF9hY3Rpb25zOiBVO1xuICAgIHByaXZhdGUgX3N0b3JlSWQ6IHN0cmluZztcblxuICAgIGNvbnN0cnVjdG9yKGFjdGlvbnM/OiBVKSB7XG4gICAgICAgIHRoaXMuX3N1YmplY3QgPSBuZXcgUnguQmVoYXZpb3JTdWJqZWN0KHRoaXMuaW5pdGlhbFN0YXRlKCkpO1xuICAgICAgICB0aGlzLl9hY3Rpb25zID0gYWN0aW9ucztcblxuICAgICAgICAvLyBDcmVhdGUgYSBsb2NhbCBkaXNwYXRjaGVyLlxuICAgICAgICB0aGlzLl9kaXNwYXRjaGVyID0gbmV3IERpc3BhdGNoZXIoKTtcbiAgICAgICAgdGhpcy5fZGlzcGF0Y2hlci5zZXREaXNwYXRjaGVyKHRoaXMuX2Rpc3BhdGNoLmJpbmQodGhpcyksIHRoaXMudmFsdWUuYmluZCh0aGlzKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIHVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGlzIHNoYXJlZCBzdG9yZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHN0b3JlSWQoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N0b3JlSWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBzdG9yZSBhY3Rpb25zLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgYWN0aW9ucygpOiBVIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2FjdGlvbnM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW50ZXJuYWwgZGlzcGF0Y2hlciBpbXBsZW1lbnRhdGlvbi5cbiAgICAgKlxuICAgICAqIE5PVEU6IFRoaXMgbWV0aG9kIGlzIHB1YmxpYyBiZWNhdXNlIHRoZXJlIGlzIG5vIHdheSB0byBkZWZpbmUgcHJpdmF0ZVxuICAgICAqIGJ1dCBhY2Nlc3NpYmxlIHRvIG90aGVyIGNsYXNzZXMgd2l0aGluIHRoaXMgbW9kdWxlIGluIFR5cGVTY3JpcHQuXG4gICAgICovXG4gICAgcHVibGljIF9kaXNwYXRjaChhY3Rpb246IEFjdGlvbik6IHZvaWQge1xuICAgICAgICBjb25zdCBleGlzdGluZ1ZhbHVlID0gdGhpcy52YWx1ZSgpO1xuICAgICAgICBsZXQgcmVkdWNlcjogKHZhbHVlOiBULCBhY3Rpb246IEFjdGlvbikgPT4gVDtcbiAgICAgICAgaWYgKF8uc3RhcnRzV2l0aChhY3Rpb24udHlwZSwgJ0BAaW50ZXJuYWwvJykpIHtcbiAgICAgICAgICAgIHJlZHVjZXIgPSB0aGlzLl9yZWR1Y2VJbnRlcm5hbC5iaW5kKHRoaXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVkdWNlciA9IHRoaXMucmVkdWNlLmJpbmQodGhpcyk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbmV3VmFsdWUgPSByZWR1Y2VyKGV4aXN0aW5nVmFsdWUsIGFjdGlvbik7XG4gICAgICAgIGlmIChfLmlzVW5kZWZpbmVkKG5ld1ZhbHVlKSkgcmV0dXJuO1xuXG4gICAgICAgIGlmIChhbmd1bGFyLmVxdWFscyhleGlzdGluZ1ZhbHVlLCBuZXdWYWx1ZSkpIHJldHVybjtcbiAgICAgICAgdGhpcy5fc3ViamVjdC5vbk5leHQoaW1tdXRhYmxlLm1ha2VJbW11dGFibGUobmV3VmFsdWUpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEaXNwYXRjaGVzIGFuIGFjdGlvbiB0byB0aGlzIHNoYXJlZCBzdG9yZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBhY3Rpb24gQWN0aW9uIHRvIGRpc3BhdGNoXG4gICAgICovXG4gICAgcHVibGljIGRpc3BhdGNoKGFjdGlvbjogR2V0QWN0aW9uczxVPiB8IEdldEFjdGlvbnM8QWN0aW9ucz4gfCBUaHVuayk6IGFueSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kaXNwYXRjaGVyLmRpc3BhdGNoKDxBY3Rpb24gfCBUaHVuaz4gYWN0aW9uKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQZXJmb3JtcyBpbnRlcm5hbCByZWR1Y2UgYWN0aW9ucyBpbXBsZW1lbnRlZCBmb3IgZWFjaCBzaGFyZWQgc3RvcmUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc3RhdGUgRXhpc3Rpbmcgc2hhcmVkIHN0b3JlIHN0YXRlXG4gICAgICogQHBhcmFtIGFjdGlvbiBBY3Rpb24gdG8gcGVyZm9ybVxuICAgICAqIEByZXR1cm4gTmV3IHNoYXJlZCBzdG9yZSBzdGF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgX3JlZHVjZUludGVybmFsKHN0YXRlOiBULCBhY3Rpb246IEFjdGlvbik6IFQge1xuICAgICAgICBzd2l0Y2ggKGFjdGlvbi50eXBlKSB7XG4gICAgICAgICAgICBjYXNlIEFjdGlvbnMuU0VUOiB7XG4gICAgICAgICAgICAgICAgY29uc3QgbmV4dFN0YXRlID0gYWN0aW9uWyd2YWx1ZSddO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm9uU3RhdGVMb2FkKHN0YXRlLCBuZXh0U3RhdGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGVmYXVsdDoge1xuICAgICAgICAgICAgICAgIC8vIERvIG5vdGhpbmcuXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQZXJmb3JtcyB0aGUgZ2l2ZW4gYWN0aW9uIG9uIHRoZSB1bmRlcmx5aW5nIHN0YXRlLlxuICAgICAqXG4gICAgICogU3ViY2xhc3NlcyBtYXkgb3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gaW1wbGVtZW50IGFyYml0cmFyeSBjb21wbGV4XG4gICAgICogYWN0aW9ucyBvbiB0aGUgZGF0YSBzdG9yZS4gVGhpcyBtZXRob2QgTVVTVCBOT1QgbXV0YXRlIHRoZSBleGlzdGluZ1xuICAgICAqIHN0YXRlLiBJbnN0ZWFkLCBpdCBNVVNUIHJldHVybiBhbiBpbW11dGFibGUgY29weS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB2YWx1ZSBFeGlzdGluZyBzaGFyZWQgc3RvcmUgc3RhdGVcbiAgICAgKiBAcGFyYW0gYWN0aW9uIE9wZXJhdGlvbiB0byBwZXJmb3JtXG4gICAgICogQHJldHVybiBOZXcgc2hhcmVkIHN0b3JlIHN0YXRlXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IHJlZHVjZShzdGF0ZTogVCwgYWN0aW9uOiBHZXRBY3Rpb25zPFU+KTogVDtcblxuICAgIC8qKlxuICAgICAqIFByb3ZpZGVzIHRoZSBpbml0aWFsIHN0YXRlIGZvciB0aGlzIHNoYXJlZCBzdG9yZS4gVGhpcyBzdGF0ZSBpc1xuICAgICAqIHVzZWQgd2hlbiB0aGUgc3RvcmUgaXMgaW5pdGlhbGl6ZWQuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGluaXRpYWxTdGF0ZSgpOiBUO1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBtZXRob2QgZ2V0cyBjYWxsZWQgd2hlbiB0aGUgZGF0YSBzdG9yZSdzIHN0YXRlIGlzIGxvYWRlZCBmcm9tXG4gICAgICogYW4gZXh0ZXJuYWwgc291cmNlICh3aGVuIHRoZSBTRVQgYWN0aW9uIGlzIGRpc3BhdGNoZWQgdG8gdGhlIHN0b3JlKS5cbiAgICAgKlxuICAgICAqIEl0IGlzIGNhbGxlZCBiZWZvcmUgdGhlIG5ldyBzdGF0ZSBoYXMgYmVlbiBzZXQuIFRoZSBkZWZhdWx0IGltcGxlbWVudGF0aW9uXG4gICAgICogZG9lcyBub3RoaW5nLlxuICAgICAqXG4gICAgICogQHBhcmFtIHN0YXRlIE9sZCBzdGF0ZVxuICAgICAqIEBwYXJhbSBuZXh0U3RhdGUgTmV3IHN0YXRlXG4gICAgICogQHJldHVybiBQb3NzaWJseSBtb2RpZmllZCBzdGF0ZSB0aGF0IHNob3VsZCBiZSB1c2VkIGluc3RlYWRcbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgb25TdGF0ZUxvYWQoc3RhdGU6IFQsIG5leHRTdGF0ZTogVCk6IFQge1xuICAgICAgICByZXR1cm4gbmV4dFN0YXRlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEEgaGVscGVyIG1ldGhvZCBmb3IgZGVmaW5pbmcgc2hhcmVkIHN0b3JlIHF1ZXJpZXMuIElmIHRoZSBxdWVyeSBpcyBhbHJlYWR5XG4gICAgICogZGVmaW5lZCwgdGhlIGV4aXN0aW5nIG9ic2VydmFibGUgaXMgcmV0dXJuZWQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gbmFtZSBRdWVyeSBuYW1lXG4gICAgICogQHBhcmFtIHF1ZXJ5IFF1ZXJ5IGZ1bmN0aW9uXG4gICAgICogQHJldHVybiBSZXN1bHRpbmcgcXVlcnkgb2JzZXJ2YWJsZVxuICAgICAqL1xuICAgIHByb3RlY3RlZCBkZWZpbmVRdWVyeTxWPihuYW1lOiBzdHJpbmcsIHF1ZXJ5OiBTaGFyZWRTdG9yZVF1ZXJ5PFQsIFY+KTogUnguT2JzZXJ2YWJsZTxWPiB7XG4gICAgICAgIGxldCBvYnNlcnZhYmxlOiBSeC5PYnNlcnZhYmxlPFY+ID0gdGhpcy5fcXVlcmllc1tuYW1lXTtcbiAgICAgICAgaWYgKG9ic2VydmFibGUpIHJldHVybiBvYnNlcnZhYmxlO1xuXG4gICAgICAgIG9ic2VydmFibGUgPSB0aGlzLl9xdWVyaWVzW25hbWVdID0gdGhpcy5vYnNlcnZhYmxlKCkubGV0KHF1ZXJ5KS5kaXN0aW5jdFVudGlsQ2hhbmdlZCgpO1xuICAgICAgICByZXR1cm4gb2JzZXJ2YWJsZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHZhbHVlIHN0b3JlZCBpbiB0aGUgc3RvcmUuXG4gICAgICpcbiAgICAgKiBZb3UgTVVTVCBlbnN1cmUgdGhhdCB0aGUgcmVzdWx0aW5nIG9iamVjdCBpcyBOT1QgbXV0YXRlZCBpbiBhbnkgd2F5LiBBbnlcbiAgICAgKiBtdXRhdGlvbiBtYXkgY2F1c2UgdW5kZWZpbmVkIGJlaGF2aW9yLlxuICAgICAqL1xuICAgIHB1YmxpYyB2YWx1ZSgpOiBUIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGFuIG9ic2VydmFibGUgb2YgdGhlIHN0b3JlJ3MgdmFsdWUuXG4gICAgICpcbiAgICAgKiBZb3UgTVVTVCBlbnN1cmUgdGhhdCB0aGUgb2JzZXJ2ZWQgdmFsdWUgaXMgTk9UIG11dGF0ZWQgaW4gYW55IHdheS4gQW55XG4gICAgICogbXV0YXRpb24gbWF5IGNhdXNlIHVuZGVmaW5lZCBiZWhhdmlvci5cbiAgICAgKi9cbiAgICBwdWJsaWMgb2JzZXJ2YWJsZSgpOiBSeC5PYnNlcnZhYmxlPFQ+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N1YmplY3Q7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIHZhbHVlIHRoYXQgc2hvdWxkIGJlIHVzZWQgd2hlbiBzYXZpbmcgc3RvcmUgc3RhdGUuXG4gICAgICpcbiAgICAgKiBCeSBkZWZhdWx0LCB0aGlzIHdpbGwgcmV0dXJuIHRoZSBzYW1lIGFzIFtbdmFsdWVdXS5cbiAgICAgKi9cbiAgICBwdWJsaWMgc2F2ZVZhbHVlKCk6IFQge1xuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZSgpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBbW1NpbXBsZVNoYXJlZFN0b3JlXV0gaXMgYSBoZWxwZXIgY2xhc3MgaW50ZW5kZWQgdG8gYmUgdXNlZCBhcyBhIHR5cGUgaW4gY29uanVuY3Rpb24gd2l0aFxuICogW1tTaGFyZWRTdG9yZVByb3ZpZGVyXV0ncyBgY3JlYXRlYCBtZXRob2Qgd2hlcmUgb25seSBTRVQgYWN0aW9uIGlzIHVzZWQuXG4gKlxuICogSW4gdGhpcyBjYXNlIG5vIHN1YmNsYXNzaW5nIG9mIHN0b3JlIGFuZCBhY3Rpb25zIGlzIG5lZWRlZCBiZWNhdXNlIG9ubHkgU0VUIGFjdGlvbiBpcyB1c2VkLlxuICogVGhpcyBpcyBjb252ZW5pZW50IGZvciB1c2UgY2FzZXMgd2hlcmUgeW91IG9ubHkgbmVlZCB0byBzZXQgYSB2YWx1ZSB0aGF0IHlvdSBjYW4gc3Vic2NyaWJlXG4gKiB0byBmcm9tIG90aGVyIGNvbXBvbmVudHMuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBTaW1wbGVTaGFyZWRTdG9yZTxUPiBleHRlbmRzIFNoYXJlZFN0b3JlPFQsIHR5cGVvZiB1bmRlZmluZWQ+IHsgfVxuXG4vKipcbiAqIFVzZWQgdG8gZGlzcGF0Y2ggYWN0aW9ucyB0byBzaGFyZWQgc3RvcmVzLlxuICovXG5leHBvcnQgY2xhc3MgRGlzcGF0Y2hlciBleHRlbmRzIFJ4LlN1YmplY3Q8QWN0aW9uPiB7XG4gICAgcHJpdmF0ZSBfZ2V0U3RhdGU6ICgpID0+IGFueSA9ICgpID0+IHVuZGVmaW5lZDtcblxuICAgIC8qKlxuICAgICAqIENvbmZpZ3VyZXMgYSBkaXNwYXRjaGVyIGZ1bmN0aW9uIGZvciB0aGlzIGRpc3BhdGNoZXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gZGlzcGF0Y2hlciBUaGUgZGlzcGF0Y2hlciBmdW5jdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyBzZXREaXNwYXRjaGVyKGRpc3BhdGNoZXI6IChhY3Rpb246IEFjdGlvbikgPT4gdm9pZCwgZ2V0U3RhdGU/OiAoKSA9PiBhbnkpOiB2b2lkIHtcbiAgICAgICAgLy8gVGhlIGRpc3BhdGNoZXIgaXMgdXNlZCB0byBkaXNwYXRjaCBhbGwgYWN0aW9ucyB1c2luZyBhIHF1ZXVlLCBzbyBhY3Rpb25zXG4gICAgICAgIC8vIG1heSBpbnZva2UgdGhlIGRpc3BhdGNoIG1ldGhvZCB3aXRob3V0IGNhdXNpbmcgcmVjdXJzaW9uLiBUaGUgY3VycmVudFRocmVhZFxuICAgICAgICAvLyBzY2hlZHVsZXIgcHV0cyBhbGwgcGVuZGluZyBpdGVtcyBpbnNpZGUgYSBxdWV1ZSwgd2hpY2ggaXMgZGlzcGF0Y2hlZCBhZnRlclxuICAgICAgICAvLyByZXR1cm5pbmcgZnJvbSBhY3RpdmUgZGlzcGF0Y2guXG4gICAgICAgIHRoaXMub2JzZXJ2ZU9uKFJ4LlNjaGVkdWxlci5jdXJyZW50VGhyZWFkKS5zdWJzY3JpYmUoZGlzcGF0Y2hlcik7XG4gICAgICAgIGlmIChnZXRTdGF0ZSkgdGhpcy5fZ2V0U3RhdGUgPSBnZXRTdGF0ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEaXNwYXRjaGVzIGFuIGFjdGlvbiB2aWEgdGhpcyBkaXNwYXRjaGVyLlxuICAgICAqL1xuICAgIHB1YmxpYyBkaXNwYXRjaChhY3Rpb246IEFjdGlvbiB8IFRodW5rKTogYW55IHtcbiAgICAgICAgaWYgKF8uaXNGdW5jdGlvbihhY3Rpb24pKSB7XG4gICAgICAgICAgICAvLyBBIHRodW5rIGhhcyBiZWVuIHBhc3NlZC4gRXhlY3V0ZSBpdCB3aXRoIHRoZSBkaXNwYXRjaGVyIGFyZ3VtZW50IGFuZFxuICAgICAgICAgICAgLy8gcmV0dXJuIHRoZSByZXN1bHQuXG4gICAgICAgICAgICByZXR1cm4gYWN0aW9uKHRoaXMsIHRoaXMuX2dldFN0YXRlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMub25OZXh0KGFjdGlvbik7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2hhcmVkU3RvcmVGYWN0b3J5PFQsIFU+IHtcbiAgICBuZXcgKC4uLmFyZ3MpOiBTaGFyZWRTdG9yZTxULCBVPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBY3Rpb25GYWN0b3J5IHtcbiAgICBuZXcgKC4uLmFyZ3MpOiBhbnk7XG59XG5cbi8qKlxuICogU2hhcmVkIHN0b3JlIHByb3ZpZGVyLCBlbmFibGluZyByZWdpc3RyYXRpb24gb2Ygc2hhcmVkIHN0b3Jlcy4gQWxsIHN0b3Jlc1xuICogbXVzdCBiZSByZWdpc3RlcmVkIGluIHRoZSBhcHBsaWNhdGlvbiBjb25maWd1cmF0aW9uIHBoYXNlLlxuICovXG5leHBvcnQgY2xhc3MgU2hhcmVkU3RvcmVQcm92aWRlciB7XG4gICAgLy8vIEEgbGlzdCBvZiByZWdpc3RlcmVkIHN0b3Jlcy5cbiAgICBwcml2YXRlIF9zdG9yZXM6IHN0cmluZ1tdID0gW107XG4gICAgLy8vIFByb3ZpZGUgc2VydmljZS5cbiAgICBwcml2YXRlIF9wcm92aWRlOiBhbmd1bGFyLmF1dG8uSVByb3ZpZGVTZXJ2aWNlO1xuXG4gICAgLy8gQG5nSW5qZWN0XG4gICAgY29uc3RydWN0b3IoJHByb3ZpZGU6IGFuZ3VsYXIuYXV0by5JUHJvdmlkZVNlcnZpY2UpIHtcbiAgICAgICAgdGhpcy5fcHJvdmlkZSA9ICRwcm92aWRlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEEgbGlzdCBvZiByZWdpc3RlcmVkIHN0b3Jlcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHN0b3JlcygpOiBzdHJpbmdbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9zdG9yZXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIG5ldyBzaGFyZWQgc3RvcmUuXG4gICAgICpcbiAgICAgKiBXaGVuIGNob29zaW5nIGFuIGlkZW50aWZpZXIgZm9yIHRoZSBzdG9yZSwgeW91IHNob3VsZCB3cml0ZSBpdCB1c2luZ1xuICAgICAqIGtlYmFiLWNhc2UgYW5kIG5vdCBpbmNsdWRlIHRoZSBzdHJpbmcgJ3N0b3JlJyBlaXRoZXIgYXMgYSBwcmVmaXggb3JcbiAgICAgKiBhIHN1ZmZpeC5cbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIG1heSBvbmx5IGJlIGNhbGxlZCBpbiB0aGUgYXBwbGljYXRpb24ncyBjb25maWd1cmF0aW9uXG4gICAgICogcGhhc2UuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc3RvcmVJZCBJZGVudGlmaWVyIG9mIHRoZSBzaGFyZWQgc3RvcmUgKG11c3QgYmUgZ2xvYmFsbHkgdW5pcXVlKVxuICAgICAqIEBwYXJhbSBpbml0aWFsU3RhdGUgT3B0aW9uYWwgaW5pdGlhbCBzdGF0ZSBvZiB0aGUgc2hhcmVkIHN0b3JlXG4gICAgICovXG4gICAgcHVibGljIGNyZWF0ZTxUPihzdG9yZUlkOiBzdHJpbmcsIGluaXRpYWxTdGF0ZTogVCA9IG51bGwpOiB2b2lkIHtcbiAgICAgICAgY2xhc3MgRXh0ZW5kZWQgZXh0ZW5kcyBTaW1wbGVTaGFyZWRTdG9yZTxUPiB7XG4gICAgICAgICAgICBwcm90ZWN0ZWQgaW5pdGlhbFN0YXRlKCkgeyByZXR1cm4gaW5pdGlhbFN0YXRlOyB9XG4gICAgICAgICAgICBwcm90ZWN0ZWQgcmVkdWNlKHN0YXRlOiBULCBhY3Rpb246IEFjdGlvbik6IFQgeyByZXR1cm4gdW5kZWZpbmVkOyB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnJlZ2lzdGVyPFQ+KHN0b3JlSWQsIEV4dGVuZGVkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWdpc3RlcnMgYSBuZXcgc2hhcmVkIHN0b3JlLiBBIHN0b3JlIHdpdGggdGhlIHNhbWUgbmFtZSBtdXN0IG5vdCBhbHJlYWR5XG4gICAgICogYmUgcmVnaXN0ZXJlZC5cbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIG1heSBvbmx5IGJlIGNhbGxlZCBpbiB0aGUgYXBwbGljYXRpb24ncyBjb25maWd1cmF0aW9uXG4gICAgICogcGhhc2UuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc3RvcmVJZCBJZGVudGlmaWVyIG9mIHRoZSBzaGFyZWQgc3RvcmUgKG11c3QgYmUgZ2xvYmFsbHkgdW5pcXVlKVxuICAgICAqIEBwYXJhbSBTaGFyZWQgc3RvcmUgY2xhc3NcbiAgICAgKi9cbiAgICBwdWJsaWMgcmVnaXN0ZXI8VD4oc3RvcmVJZDogc3RyaW5nLCBzdG9yZVR5cGU6IFNoYXJlZFN0b3JlRmFjdG9yeTxULCBhbnk+KTogdm9pZCB7XG4gICAgICAgIC8vIFJlZ2lzdGVyIHRoZSBzdG9yZSBhcyBhbiBhbmd1bGFyIHNlcnZpY2UuIFdlIHVzZSBmYWN0b3J5IGluc3RlYWQgb2Ygc2VydmljZVxuICAgICAgICAvLyBzbyB3ZSBjYW4gc2V0IHRoZSBgX3N0b3JlSWRgIG9uIHRoZSBpbnN0YW5jZS5cbiAgICAgICAgdGhpcy5fcHJvdmlkZS5mYWN0b3J5KFxuICAgICAgICAgICAgc3RvcmVJZFRvU2VydmljZUlkKHN0b3JlSWQpLFxuICAgICAgICAgICAgLy8gQG5nSW5qZWN0XG4gICAgICAgICAgICAoJGluamVjdG9yOiBhbmd1bGFyLmF1dG8uSUluamVjdG9yU2VydmljZSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHN0b3JlOiBhbnkgPSAkaW5qZWN0b3IuaW5zdGFudGlhdGUoc3RvcmVUeXBlKTtcbiAgICAgICAgICAgICAgICBzdG9yZS5fc3RvcmVJZCA9IHN0b3JlSWQ7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0b3JlO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgICB0aGlzLl9zdG9yZXMucHVzaChzdG9yZUlkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWdpc3RlcnMgYSBuZXcgYWN0aW9ucyBjbGFzcy5cbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIG1heSBvbmx5IGJlIGNhbGxlZCBpbiB0aGUgYXBwbGljYXRpb24ncyBjb25maWd1cmF0aW9uXG4gICAgICogcGhhc2UuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gYWN0aW9uc0lkIElkZW50aWZpZXIgb2YgdGhlIGFjdGlvbnMgY2xhc3MgKG11c3QgYmUgZ2xvYmFsbHkgdW5pcXVlKVxuICAgICAqIEBwYXJhbSBBY3Rpb25zIGNsYXNzXG4gICAgICovXG4gICAgcHVibGljIHJlZ2lzdGVyQWN0aW9ucyhhY3Rpb25zSWQ6IHN0cmluZywgYWN0aW9uc1R5cGU6IEFjdGlvbkZhY3RvcnkpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fcHJvdmlkZS5zZXJ2aWNlKGFjdGlvbnNJZFRvU2VydmljZUlkKGFjdGlvbnNJZCksIGFjdGlvbnNUeXBlKTtcbiAgICB9XG5cbiAgICAvLyBAbmdJbmplY3RcbiAgICBwdWJsaWMgJGdldCgkaW5qZWN0b3I6IGFuZ3VsYXIuYXV0by5JSW5qZWN0b3JTZXJ2aWNlLFxuICAgICAgICAgICAgICAgIGRpc3BhdGNoZXI6IERpc3BhdGNoZXIpOiBTaGFyZWRTdG9yZU1hbmFnZXIge1xuICAgICAgICByZXR1cm4gbmV3IFNoYXJlZFN0b3JlTWFuYWdlcigkaW5qZWN0b3IsIGRpc3BhdGNoZXIsIHRoaXMpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBNYW5hZ2VyIG9mIGFsbCBzaGFyZWQgc3RvcmVzIChzZWUgW1tTaGFyZWRTdG9yZV1dKSBpbiBhbiBhcHBsaWNhdGlvbi4gRWFjaCBzdG9yZVxuICogcmVxdWlyZXMgYSBnbG9iYWxseSB1bmlxdWUgaWRlbnRpZmllciwgd2hpY2ggaXMgYWxzbyB1c2VkIGR1cmluZyBzdGF0ZSBzZXJpYWxpemF0aW9uLlxuICpcbiAqIEluIG9yZGVyIHRvIHVzZSBzaGFyZWQgc3RvcmVzLCB5b3UgbXVzdCBmaXJzdCBjcmVhdGUgdGhlbS4gVGhlIGJlc3Qgd2F5IHRvIGRvXG4gKiB0aGlzIGlzIGluc2lkZSB5b3VyIG1vZHVsZSdzIGBjb25maWdgIGZ1bmN0aW9uIGFzIGZvbGxvd3M6XG4gKiBgYGBcbiAqIG1vZHVsZS5jb25maWcoKHNoYXJlZFN0b3JlTWFuYWdlclByb3ZpZGVyOiBTaGFyZWRTdG9yZVByb3ZpZGVyKSA9PiB7XG4gKiAgICAgLy8gQ3JlYXRlIHRoZSBzZWxlY3RlZCBST1NFMiBkYXRhIGl0ZW1zIHNoYXJlZCBzdG9yZS5cbiAqICAgICBzaGFyZWRTdG9yZU1hbmFnZXJQcm92aWRlci5jcmVhdGUoJ3Jvc2UyLXNlbGVjdGVkLWRhdGEtaXRlbScpO1xuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBUaGUgc3RvcmUgbWF5IHRoZW4gYmUgdXNlZCBhcyBpbnB1dCB0byBzaGFyZWQgc3RhdGUgZGVmaW5lZCBvbiBzdGF0ZWZ1bFxuICogY29tcG9uZW50cyAoc2VlIFtbU3RhdGVmdWxDb21wb25lbnRCYXNlXV0pIGFuZCBjYW4gYWxzbyBiZSBpbmplY3RlZCB1c2luZ1xuICogYSBzcGVjaWZpYyB0b2tlbi4gSWYgYSBzdG9yZSBpcyBuYW1lZCBgbXktbmljZS1pdGVtc2AsIGl0IHdpbGwgYmUgaW5qZWN0YWJsZVxuICogYnkgdXNpbmcgdGhlIHRva2VuIGBteU5pY2VJdGVtc1N0b3JlYC5cbiAqXG4gKiBJZiB5b3Ugd2lzaCB0byBkZWZpbmUgc2hhcmVkIHN0b3JlcyB3aGljaCBzdXBwb3J0IGFkZGl0aW9uYWwgYWN0aW9ucywgeW91XG4gKiBzaG91bGQgc3ViY2xhc3MgW1tTaGFyZWRTdG9yZV1dIGFuZCByZWdpc3RlciB5b3VyIHN0b3JlIGJ5IHVzaW5nIFtbcmVnaXN0ZXJdXVxuICogYXMgZm9sbG93czpcbiAqIGBgYFxuICogY2xhc3MgQ29tcGxleEFjdGlvbnMge1xuICogICAgIHN0YXRpYyBBRERfSVRFTSA9ICdjb21wbGV4L2FkZF9pdGVtJztcbiAqICAgICBwdWJsaWMgYWRkSXRlbSh2YWx1ZTogdHlwZXMuU2FtcGxlRGF0YSkge1xuICogICAgICAgICByZXR1cm4geyB0eXBlOiBDb21wbGV4QWN0aW9ucy5BRERfSVRFTSwgaXRlbTogdmFsdWUgfTtcbiAqICAgICB9XG4gKiB9XG4gKlxuICogY2xhc3MgQ29tcGxleFN0b3JlIGV4dGVuZHMgU2hhcmVkU3RvcmU8dHlwZXMuU2FtcGxlRGF0YVtdLCBDb21wbGV4QWN0aW9ucz4ge1xuICogICAgIC8vIEBuZ0luamVjdFxuICogICAgIGNvbnN0cnVjdG9yKGNvbXBsZXhBY3Rpb25zOiBDb21wbGV4QWN0aW9ucykge1xuICogICAgICAgICBzdXBlcihjb21wbGV4QWN0aW9ucyk7XG4gKiAgICAgfVxuICpcbiAqICAgICBwcm90ZWN0ZWQgaW5pdGlhbFN0YXRlKCk6IHR5cGVzLlNhbXBsZURhdGFbXSB7XG4gKiAgICAgICAgIHJldHVybiBbXTtcbiAqICAgICB9XG4gKlxuICogICAgIHByb3RlY3RlZCByZWR1Y2Uoc3RhdGU6IHR5cGVzLlNhbXBsZURhdGFbXSwgYWN0aW9uOiBhbnkpOiB2b2lkIHtcbiAqICAgICAgICAgc3dpdGNoIChhY3Rpb24udHlwZSkge1xuICogICAgICAgICAgICAgY2FzZSBBRERfSVRFTToge1xuICogICAgICAgICAgICAgICAgIHJldHVybiBfLnVuaW9uKHN0YXRlLCBhY3Rpb24uaXRlbSk7XG4gKiAgICAgICAgICAgICB9XG4gKiAgICAgICAgICAgICAvLyAuLi5cbiAqICAgICAgICAgfVxuICogICAgIH1cbiAqIH1cbiAqXG4gKiBtb2R1bGUuY29uZmlnKChzaGFyZWRTdG9yZU1hbmFnZXJQcm92aWRlcjogU2hhcmVkU3RvcmVQcm92aWRlcikgPT4ge1xuICogICAgIHNoYXJlZFN0b3JlTWFuYWdlclByb3ZpZGVyLnJlZ2lzdGVyQWN0aW9ucygnY29tcGxleCcsIENvbXBsZXhBY3Rpb25zKTtcbiAqICAgICBzaGFyZWRTdG9yZU1hbmFnZXJQcm92aWRlci5yZWdpc3RlcignY29tcGxleCcsIENvbXBsZXhTdG9yZSk7XG4gKiB9KTtcbiAqIGBgYFxuICpcbiAqIFdoZW4gY3JlYXRpbmcgYSBuZXcgc2hhcmVkIHN0b3JlLCBhIGdvb2QgZGVzaWduIHByYWN0aWNlIGlzIHRvIHNlcGFyYXRlXG4gKiBhY3Rpb25zIGludG8gdGhlIGBhY3Rpb25zYCBkaXJlY3RvcnkgYW5kIGltcGxlbWVudCBhY3Rpb25zIGFzIG1ldGhvZHMgb25cbiAqIHRoZSBhY3Rpb25zIGNsYXNzIG5hbWVkIGFmdGVyIHlvdXIgc3RvcmUgKGVnLiBmb3Igc3RvcmUgYEZvb1N0b3JlYCBwdXRcbiAqIGFjdGlvbnMgaW50byBgRm9vQWN0aW9uc2ApLlxuICpcbiAqIFN0b3JlcyB0aGVtc2VsdmVzIHNob3VsZCBvbmx5IGltcGxlbWVudCB0aGUgc3RhdGUgbWFuYWdlbWVudCBmdW5jdGlvbmFsaXR5XG4gKiBhbmQgbW9zdCBidXNpbmVzcyBsb2dpYyBzaG91bGQgYmUgY29udGFpbmVkIGluIHRoZSBhY3Rpb25zIGNsYXNzLiBGb3JcbiAqIGV4YW1wbGUsIGlmIGFjdGlvbnMgcmVxdWlyZSBzb21lIGFzeW5jaHJvbm91cyBvcGVyYXRpb25zIHRvIGJlIHBlcmZvcm1lZFxuICogb24gYSByZW1vdGUgYmFja2VuZCBhbGwgdGhpcyBmdW5jdGlvbmFsaXR5IHNob3VsZCBiZSBwdXQgaW50byB0aGUgYWN0aW9uc1xuICogY2xhc3MgYW5kIG5vdCBpbnRvIHRoZSBzdG9yZS5cbiAqXG4gKiBBbGwgYWN0aW9ucyBjbGFzc2VzIHNob3VsZCBiZSByZWdpc3RlcmVkIHZpYSB0aGUgW1tTaGFyZWRTdG9yZVByb3ZpZGVyXV1cbiAqIGFuZCBzdXBwb3J0IEFuZ3VsYXIgZGVwZW5kZW5jeSBpbmplY3Rpb24uIEFjdGlvbnMgY2xhc3NlcyBhcmUgaW5qZWN0YWJsZVxuICogdW5kZXIgdGhlIHRva2VuIGBpZEFjdGlvbnNgIHdoZXJlIHRoZSBgaWRgIHBhcnQgaXMgdGhlIHZhbHVlIGRlZmluZWQgYnlcbiAqIGBhY3Rpb25zSWRgLCBmb3JtYXR0ZWQgaW4gY2FtZWxDYXNlLiBUaGUgY29uc3RydWN0b3Igb2YgYW4gYWN0aW9uc1xuICogY2xhc3MgbWF5IGFsc28gaW5qZWN0IG90aGVyIGRlcGVuZGVuY2llcy5cbiAqXG4gKiBGb3IgY29udmVuaWVuY2UsIHlvdSBtYXkgaW5qZWN0IHlvdXIgYWN0aW9ucyBjbGFzcyBpbiB5b3VyIHNoYXJlZCBzdG9yZVxuICogY2xhc3MgdW5kZXIgdGhlIHB1YmxpYyBhdHRyaWJ1dGUgYGFjdGlvbnNgLiBUaGlzIHdheSBvbmUgbWF5IGdldCB0aGVcbiAqIGFjdGlvbnMgY2xhc3Mgc2ltcGx5IGJ5IGFjY2Vzc2luZyBgc3RvcmUuYWN0aW9uc2Agd2hlbiBnaXZlbiBhIHNoYXJlZFxuICogc3RvcmUgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBjbGFzcyBTaGFyZWRTdG9yZU1hbmFnZXIge1xuICAgIC8vLyBTaGFyZWQgc3RvcmUgcHJvdmlkZXIuXG4gICAgcHJpdmF0ZSBfcHJvdmlkZXI6IFNoYXJlZFN0b3JlUHJvdmlkZXI7XG4gICAgLy8vIERpc3BhdGNoZXIuXG4gICAgcHJpdmF0ZSBfZGlzcGF0Y2hlcjogRGlzcGF0Y2hlcjtcbiAgICAvLy8gQW5ndWxhciBpbmplY3Rvci5cbiAgICBwcml2YXRlIF9pbmplY3RvcjogYW5ndWxhci5hdXRvLklJbmplY3RvclNlcnZpY2U7XG5cbiAgICAvLyBAbmdJbmplY3RcbiAgICBjb25zdHJ1Y3RvcigkaW5qZWN0b3I6IGFuZ3VsYXIuYXV0by5JSW5qZWN0b3JTZXJ2aWNlLFxuICAgICAgICAgICAgICAgIGRpc3BhdGNoZXI6IERpc3BhdGNoZXIsXG4gICAgICAgICAgICAgICAgc2hhcmVkU3RvcmVNYW5hZ2VyUHJvdmlkZXI6IFNoYXJlZFN0b3JlUHJvdmlkZXIpIHtcbiAgICAgICAgdGhpcy5fcHJvdmlkZXIgPSBzaGFyZWRTdG9yZU1hbmFnZXJQcm92aWRlcjtcbiAgICAgICAgdGhpcy5faW5qZWN0b3IgPSAkaW5qZWN0b3I7XG4gICAgICAgIHRoaXMuX2Rpc3BhdGNoZXIgPSBkaXNwYXRjaGVyO1xuICAgICAgICB0aGlzLl9kaXNwYXRjaGVyLnNldERpc3BhdGNoZXIodGhpcy5fZGlzcGF0Y2guYmluZCh0aGlzKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCBzdG9yZS4gSXQgaXMgYW4gZXJyb3IgdG8gcmVxdWVzdCBhIHN0b3JlXG4gICAgICogd2hpY2ggZG9lc24ndCBleGlzdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBzdG9yZUlkIElkZW50aWZpZXIgb2YgdGhlIHNoYXJlZCBzdG9yZVxuICAgICAqIEByZXR1cm4gU2hhcmVkIHN0b3JlIGluc3RhbmNlXG4gICAgICovXG4gICAgcHVibGljIGdldFN0b3JlPFQ+KHN0b3JlSWQ6IHN0cmluZyk6IFNoYXJlZFN0b3JlPFQsIGFueT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5faW5qZWN0b3IuZ2V0PFNoYXJlZFN0b3JlPFQsIGFueT4+KHN0b3JlSWRUb1NlcnZpY2VJZChzdG9yZUlkKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGlzcGF0Y2hlcyBhbiBhY3Rpb24gdG8gYWxsIHNoYXJlZCBzdG9yZXMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gYWN0aW9uIEFjdGlvbiB0byBkaXNwYXRjaFxuICAgICAqL1xuICAgIHB1YmxpYyBkaXNwYXRjaChhY3Rpb246IEFjdGlvbiB8IFRodW5rKTogYW55IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2Rpc3BhdGNoZXIuZGlzcGF0Y2goYWN0aW9uKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbnRlcm5hbCBnbG9iYWwgZGlzcGF0Y2ggaW1wbGVtZW50YXRpb24uXG4gICAgICovXG4gICAgcHJpdmF0ZSBfZGlzcGF0Y2goYWN0aW9uOiBBY3Rpb24pOiB2b2lkIHtcbiAgICAgICAgZm9yIChjb25zdCBzdG9yZUlkIG9mIHRoaXMuX3Byb3ZpZGVyLnN0b3Jlcykge1xuICAgICAgICAgICAgdGhpcy5nZXRTdG9yZShzdG9yZUlkKS5fZGlzcGF0Y2goYWN0aW9uKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlcmlhbGl6ZXMgdGhlIHZhbHVlcyBvZiBhbGwgc2hhcmVkIHN0b3Jlcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgc2F2ZVN0YXRlKCk6IGFueSB7XG4gICAgICAgIGxldCByZXN1bHQgPSB7fTtcbiAgICAgICAgZm9yIChjb25zdCBzdG9yZUlkIG9mIHRoaXMuX3Byb3ZpZGVyLnN0b3Jlcykge1xuICAgICAgICAgICAgbGV0IHZhbHVlID0gdGhpcy5nZXRTdG9yZShzdG9yZUlkKS5zYXZlVmFsdWUoKTtcbiAgICAgICAgICAgIGlmIChpc0pzb25hYmxlKHZhbHVlKSkge1xuICAgICAgICAgICAgICAgIHJlc3VsdFtzdG9yZUlkXSA9IHZhbHVlLn