UNPKG

@genialis/resolwe

Version:
583 lines (582 loc) 71.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var angular = require("angular"); var _ = require("lodash"); var Rx = require("rx"); var lang_1 = require("../utils/lang"); var error_1 = require("../errors/error"); var DirectiveType; (function (DirectiveType) { DirectiveType[DirectiveType["COMPONENT"] = 0] = "COMPONENT"; DirectiveType[DirectiveType["ATTRIBUTE"] = 1] = "ATTRIBUTE"; })(DirectiveType || (DirectiveType = {})); function safeCallbackApply($scope, callback) { if ($scope.$$destroyed) { return; } callback(); $scope.$evalAsync(); } function safeApply(observable, scope, callback) { callback = angular.isFunction(callback) ? callback : _.noop; return observable.takeWhile(function () { return !scope['$$destroyed']; }).tap(function (data) { safeCallbackApply(scope, function () { callback(data); }); }); } /** * Abstraction of a computation with dependencies to observables. */ var Computation = /** @class */ (function () { /** * Constructs a new computation. * * @param component Owning component * @param content Computation content */ function Computation(component, content) { this.component = component; this.content = content; this._subscriptions = []; this._pendingSubscriptions = []; this._dispose = function () { }; this._done = false; } /** * Return true if this computation has finished. */ Computation.prototype.isDone = function () { return this._done; }; /** * Sets an alternative dispose callback for this computation. This callback * is invoked when [[unsubscribe]] is called. */ Computation.prototype.setDisposeCallback = function (callback) { this._dispose = callback; }; /** * Subscribes to an observable, registering the subscription as a dependency * of this component. The subscription is automatically stopped when the * component is destroyed. * * For the target argument, you can either specify a string, in which case * it represents the name of the component member variable that will be * populated with the result ite. Or you can specify a function with one * argument, which will be called when query results change and can do * anything. * * @param target Target component member atribute name or callback * @param observable Observable or promise to subscribe to * @return Underlying subscription disposable */ Computation.prototype.subscribe = function (target, observable, options) { var _this = this; if (options === void 0) { options = {}; } // Create a guard object that can be removed when a subscription is done. We need // to use guard objects instead of a simple reference counter because the pending // subscriptions array may be cleared while callbacks are still outstanding. var guard = new Object(); if (!options.ignoreReady) { this._pendingSubscriptions.push(guard); } var convertedObservable; if (lang_1.isPromiseLike(observable)) { convertedObservable = Rx.Observable.fromPromise(observable); } else { convertedObservable = observable; } var releaseGuard = function () { _this._pendingSubscriptions = _.without(_this._pendingSubscriptions, guard); }; convertedObservable = convertedObservable.tap(releaseGuard, releaseGuard); var subscription = safeApply(convertedObservable, this.component.$scope, function (item) { try { if (_.isFunction(target)) { target(item); } else { _this.component[target] = item; } } catch (exception) { console.warn('Ignored error in ' + _this.component.getConfig().directive, exception); } finally { // Dispose of the subscription immediately if this is a one shot subscription. if (options.oneShot && subscription) { subscription.dispose(); } } }).subscribe( // Success handler. _.noop, // Error handler. function (exception) { if (options.onError) { console.log('Handled error in ' + _this.component.getConfig().directive, exception); safeCallbackApply(_this.component.$scope, function () { options.onError(exception); }); } else { console.warn('Unhandled error in ' + _this.component.getConfig().directive, exception); } }); this._subscriptions.push(subscription); return subscription; }; /** * Returns true if all subscriptions created by calling `subscribe` are ready. * A subscription is ready when it has received its first batch of data after * subscribing. */ Computation.prototype.subscriptionsReady = function () { return this._pendingSubscriptions.length === 0; }; /** * Runs the computation. */ Computation.prototype.compute = function () { // Stop all subscriptions before running again. this.stop(); this.content(this); }; /** * Disposes of all registered subscriptions. */ Computation.prototype.stop = function () { for (var _i = 0, _a = this._subscriptions; _i < _a.length; _i++) { var subscription = _a[_i]; subscription.dispose(); } this._subscriptions = []; this._pendingSubscriptions = []; }; /** * Stops all subscriptions currently registered in this computation and removes * this computation from the parent component. If a dispose handler has been * configured, it is invoked. */ Computation.prototype.unsubscribe = function () { this.component.unsubscribe(this); if (this._dispose) this._dispose(); this._done = true; }; return Computation; }()); exports.Computation = Computation; /** * An abstract base class for all components. */ var ComponentBase = /** @class */ (function () { // @ngInject ComponentBase.$inject = ["$scope"]; function ComponentBase($scope) { var _this = this; this.$scope = $scope; // Computations. this._computations = []; // Component state. this._ready = false; $scope.$on('$destroy', function () { _this._ready = false; // Ensure that all computations get stopped when the component is destroyed. for (var _i = 0, _a = _this._computations; _i < _a.length; _i++) { var computation = _a[_i]; computation.stop(); } _this._computations = []; // Call destroyed hook. _this.onComponentDestroyed(); }); // Angular calls $onInit after constructor and bindings initialization. this['$onInit'] = function () { _this.onComponentInit(); }; } /** * This method will be called after the whole chain of constructors is executed, * via angular component $onInit. Use it if you have an abstract component that * manipulates class properties and, as a result, needs to wait for all child * class properties to be assigned and constructors to finish. (Class properties * defined in child components are assigned before child's constructor). * * Value of `$compileProvider.preAssignBindingsEnabled` (false by default since angular 1.6.0) * determines if bindings are to be present in `onComponentInit` method (false) or pre-assigned * in constructor (true). * * Order of execution: * ```ts * class Child extends Middle { * public propertyA = 'c' // 5 * constructor() { super() } // 6 * } * class Middle extends Abstract { * public propertyB = 'b' // 3 * constructor() { super() } // 4 * } * class Abstract { * public propertyA = 'a' // 1 * constructor() {} // 2 * onComponentInit() {} // 7 * } * ``` */ ComponentBase.prototype.onComponentInit = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } // Default implementation does nothing. }; /** * Destroys the component. */ ComponentBase.prototype.destroy = function () { this.$scope.$destroy(); }; /** * This method will be called in the compile phase of the directive and may * be overriden by component implementations. */ ComponentBase.onComponentCompile = function (element, attributes) { // Default implementation does nothing. }; /** * @internal */ ComponentBase.prototype._onComponentLink = function (scope, element, attributes) { var args = []; for (var _i = 3; _i < arguments.length; _i++) { args[_i - 3] = arguments[_i]; } try { // Call the public method that can be overriden by the user. this.onComponentLink.apply(this, [scope, element, attributes].concat(args)); } finally { this._ready = true; } }; /** * This method will be called in the post-link phase of the directive and may * be overriden by component implementations. */ ComponentBase.prototype.onComponentLink = function (scope, element, attributes) { var args = []; for (var _i = 3; _i < arguments.length; _i++) { args[_i - 3] = arguments[_i]; } // Default implementation does nothing. }; /** * This method will be called after the component scope has been destroyed. */ ComponentBase.prototype.onComponentDestroyed = function () { // Default implementation does nothing. }; /** * Returns true if the component has been created. */ ComponentBase.prototype.isReady = function () { return this._ready; }; /** * Returns true if all subscriptions created by calling `subscribe` are ready. * A subscription is ready when it has received its first batch of data after * subscribing. */ ComponentBase.prototype.subscriptionsReady = function () { // Wait until the component has been created. if (!this.isReady()) return false; return _.every(this._computations, function (computation) { return computation.subscriptionsReady(); }); }; ComponentBase.prototype._createComputation = function (content) { if (content === void 0) { content = _.noop; } var computation = new Computation(this, content); this._computations.push(computation); return computation; }; /** * Watch component scope and run a computation on changes. The computation is * executed once immediately prior to watching. * * Returned computation instance may be used to stop the watch by calling its * [[Computation.unsubscribe]] method. * * @param context Function which returns the context to watch * @param content Function to run on changes * @param objectEquality Should `angular.equals` be used for comparisons * @returns Computation instance */ ComponentBase.prototype.watch = function (context, content, objectEquality) { var computation = this._createComputation(content); computation.compute(); // Initial evaluation may stop the computation. In this case, don't // even create a watch and just return the (done) computation. if (computation.isDone()) return computation; var expressions = Array.isArray(context) ? context : [context]; if (!objectEquality) { var unwatch = this.$scope.$watchGroup(expressions, computation.compute.bind(computation)); computation.setDisposeCallback(unwatch); return computation; } else { var watchedExpression = function () { return _.map(expressions, function (fn) { return fn(); }); }; if (expressions.length === 1) { // optimize watchedExpression = expressions[0]; } var unwatch = this.$scope.$watch(watchedExpression, computation.compute.bind(computation), true); computation.setDisposeCallback(unwatch); return computation; } }; /** * Watch component scope and run a computation on changes. This version uses Angular's * collection watch. The computation is executed once immediately prior to watching. * * Returned computation instance may be used to stop the watch by calling its * [[Computation.unsubscribe]] method. * * @param context Function which returns the context to watch * @param content Function to run on changes * @returns Computation instance */ ComponentBase.prototype.watchCollection = function (context, content) { var computation = this._createComputation(content); computation.compute(); // Initial evaluation may stop the computation. In this case, don't // even create a watch and just return the (done) computation. if (computation.isDone()) return computation; var unwatch = this.$scope.$watchCollection(context, computation.compute.bind(computation)); computation.setDisposeCallback(unwatch); return computation; }; /** * Subscribes to an observable, registering the subscription as a dependency * of this component. The subscription is automatically stopped when the * component is destroyed. * * For the target argument, you can either specify a string, in which case * it represents the name of the component member variable that will be * populated with the result ite. Or you can specify a function with one * argument, which will be called when query results change and can do * anything. * * @param target Target component member atribute name or callback * @param observable Observable to subscribe to * @return Underlying subscription */ ComponentBase.prototype.subscribe = function (target, observable, options) { if (options === void 0) { options = {}; } var computation = this._createComputation(); computation.subscribe(target, observable, options); return computation; }; /** * Unsubscribes the given computation from this component. * * @param computation Computation instance */ ComponentBase.prototype.unsubscribe = function (computation) { computation.stop(); _.pull(this._computations, computation); }; /** * Helper function to create a wrapper observable around watch. * * @param context Function which returns the context to watch * @param objectEquality Should `angular.equals` be used for comparisons * @returns Watch observable */ ComponentBase.prototype.createWatchObservable = function (context, objectEquality) { var _this = this; var notifyObserver = function (observer) { observer.onNext(context()); }; return Rx.Observable.create(function (observer) { notifyObserver(observer); var computation = _this.watch(context, function () { return notifyObserver(observer); }, objectEquality); return function () { computation.unsubscribe(); }; }); }; /** * Returns component configuration. */ ComponentBase.getConfig = function () { return this.__componentConfig; }; /** * Returns component configuration. */ ComponentBase.prototype.getConfig = function () { return this.constructor.getConfig(); }; /** * Returns true if the component has a specified attribute configured as * a binding. * * @param name Name of the bound attribute */ ComponentBase.hasBinding = function (name) { return _.some(this.__componentConfig.bindings, function (value, key) { // In case no attribute name is specified, compare the binding key, // otherwise compare the attribute name. var matchedName = value.replace(/^[=@&<]\??/, ''); var boundAttribute = matchedName || key; return boundAttribute === name; }); }; /** * Returns a view configuration that renders this component. This method can be * used when configuring the Angular UI router as follows: * * $stateProvider.state('foo', { * url: '/foo', * views: { application: MyComponent.asView() }, * }); */ ComponentBase.asView = function (options) { var _this = this; if (options === void 0) { options = {}; } var template = '<' + this.__componentConfig.directive; var attributes = options.attributes || {}; // Setup input bindings. if (!_.isEmpty(options.inputs)) { _.forOwn(options.inputs, function (input, key) { if (!_this.hasBinding(key)) { throw new error_1.GenError("Input '" + key + "' is not defined on component."); } attributes[key] = input; }); } // Generate attributes. if (!_.isEmpty(attributes)) { _.forOwn(attributes, function (attribute, attributeName) { if (_.contains(attribute, '"')) { throw new error_1.GenError("asView attribute '" + attribute + "' is currently not supported."); } // TODO: Properly escape attribute values. template += ' ' + _.kebabCase(attributeName) + '="' + attribute + '"'; }); } template += '></' + this.__componentConfig.directive + '>'; var result = { template: template, }; // Setup parent scope for the intermediate template. if (options.parent) { result.scope = options.parent.$scope; } return _.extend(result, options.extendWith || {}); }; /** * Performs any modifications of the component configuration. This method is * invoked during component class decoration and may arbitrarily modify the * passed component configuration, before the component is registered with * Angular. * * @param config Component configuration * @return Modified component configuration */ ComponentBase.configureComponent = function (config) { return config; }; return ComponentBase; }()); exports.ComponentBase = ComponentBase; function directiveFactory(config, type) { return function (target) { // Store component configuration on the component, extending configuration obtained from base class. if (target.__componentConfig) { target.__componentConfig = _.cloneDeep(target.__componentConfig); // Don't inherit the abstract flag as otherwise you would be required to explicitly // set it to false in all subclasses. delete target.__componentConfig.abstract; _.merge(target.__componentConfig, config); } else { target.__componentConfig = config; } config = target.configureComponent(target.__componentConfig); if (!config.abstract) { // If module or directive is not defined for a non-abstract component, this is an error. if (!config.directive) { throw new error_1.GenError("Directive not defined for component."); } if (!_.startsWith(config.directive, 'gen-')) { throw new error_1.GenError("Directive not prefixed with \"gen-\": " + config.directive); } if (!config.module) { throw new error_1.GenError("Module not defined for component '" + config.directive + "'."); } if (_.any(config.bindings, function (value, key) { return _.startsWith(value.substring(1) || key, 'data'); })) { throw new Error("Bindings should not start with 'data'"); } config.module.directive(_.camelCase(config.directive), function () { var controllerBinding = config.controllerAs || 'ctrl'; var result = { scope: {}, bindToController: config.bindings || {}, controller: target, controllerAs: controllerBinding, compile: function (element, attributes) { // Call the compile life-cycle static method. target.onComponentCompile(element, attributes); return function (scope, element, attributes) { var _a; var args = []; for (var _i = 3; _i < arguments.length; _i++) { args[_i - 3] = arguments[_i]; } // Get controller from the scope and call the link life-cycle method. (_a = scope[controllerBinding])._onComponentLink.apply(_a, [scope, element, attributes].concat(args)); }; }, templateUrl: config.templateUrl, template: config.template, transclude: config.transclude, require: config.require, }; switch (type) { case DirectiveType.COMPONENT: { result.restrict = 'E'; break; } case DirectiveType.ATTRIBUTE: { result.restrict = 'A'; break; } default: { // TODO: use error handler throw new error_1.GenError("Unknown type " + type); } } return result; }); } return target; }; } /** * A decorator that transforms the decorated class into an AngularJS * component directive with proper dependency injection. */ function component(config) { return directiveFactory(config, DirectiveType.COMPONENT); } exports.component = component; /** * A decorator that transforms the decorated class into an AngularJS * attribute directive with proper dependency injection. */ function directive(config) { return directiveFactory(config, DirectiveType.ATTRIBUTE); } exports.directive = directive; //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb3JlL2NvbXBvbmVudHMvYmFzZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLGlDQUFtQztBQUNuQywwQkFBNEI7QUFDNUIsdUJBQXlCO0FBRXpCLHNDQUE0QztBQUM1Qyx5Q0FBeUM7QUFFekMsSUFBSyxhQUdKO0FBSEQsV0FBSyxhQUFhO0lBQ2QsMkRBQVMsQ0FBQTtJQUNULDJEQUFTLENBQUE7QUFDYixDQUFDLEVBSEksYUFBYSxLQUFiLGFBQWEsUUFHakI7QUEyQ0QsU0FBUyxpQkFBaUIsQ0FBQyxNQUFzQixFQUFFLFFBQW9CO0lBQ25FLElBQVcsTUFBTyxDQUFDLFdBQVcsRUFBRTtRQUM1QixPQUFPO0tBQ1Y7SUFFRCxRQUFRLEVBQUUsQ0FBQztJQUNYLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztBQUN4QixDQUFDO0FBRUQsU0FBUyxTQUFTLENBQUksVUFBNEIsRUFBRSxLQUFxQixFQUFFLFFBQTJCO0lBQ2xHLFFBQVEsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFFNUQsT0FBTyxVQUFVLENBQUMsU0FBUyxDQUFDO1FBQ3hCLE9BQU8sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDakMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFVBQUMsSUFBSTtRQUNSLGlCQUFpQixDQUFDLEtBQUssRUFBRSxjQUFRLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hELENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQztBQUVEOztHQUVHO0FBQ0g7SUFNSTs7Ozs7T0FLRztJQUNILHFCQUFtQixTQUF3QixFQUFTLE9BQTRCO1FBQTdELGNBQVMsR0FBVCxTQUFTLENBQWU7UUFBUyxZQUFPLEdBQVAsT0FBTyxDQUFxQjtRQUM1RSxJQUFJLENBQUMsY0FBYyxHQUFH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QVMsQ0FBQyxDQUFDO0FBQzlFLENBQUM7QUFGRCw4QkFFQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLFNBQVMsQ0FBQyxNQUE4QjtJQUNwRCxPQUF3QixnQkFBZ0IsQ0FBQyxNQUFNLEVBQUUsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQzlFLENBQUM7QUFGRCw4QkFFQyIsImZpbGUiOiJjb3JlL2NvbXBvbmVudHMvYmFzZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGFuZ3VsYXIgZnJvbSAnYW5ndWxhcic7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgKiBhcyBSeCBmcm9tICdyeCc7XG5cbmltcG9ydCB7aXNQcm9taXNlTGlrZX0gZnJvbSAnLi4vdXRpbHMvbGFuZyc7XG5pbXBvcnQge0dlbkVycm9yfSBmcm9tICcuLi9lcnJvcnMvZXJyb3InO1xuXG5lbnVtIERpcmVjdGl2ZVR5cGUge1xuICAgIENPTVBPTkVOVCxcbiAgICBBVFRSSUJVVEUsXG59XG5cbi8qKlxuICogQ29tcG9uZW50IGNvbmZpZ3VyYXRpb24uIERpcmVjdGl2ZSBuYW1lIHNob3VsZCBiZSBpbiBkYXNoLWNhc2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcG9uZW50Q29uZmlndXJhdGlvbiB7XG4gICAgYWJzdHJhY3Q/OiBib29sZWFuO1xuICAgIG1vZHVsZT86IGFuZ3VsYXIuSU1vZHVsZTtcbiAgICBkaXJlY3RpdmU/OiBzdHJpbmc7XG4gICAgYmluZGluZ3M/OiBfLkRpY3Rpb25hcnk8c3RyaW5nPjtcbiAgICBjb250cm9sbGVyQXM/OiBzdHJpbmc7XG4gICAgdGVtcGxhdGVVcmw/OiBzdHJpbmc7XG4gICAgdGVtcGxhdGU/OiBzdHJpbmc7XG4gICAgdHJhbnNjbHVkZT86IGJvb2xlYW4gfCB7W3Nsb3Q6IHN0cmluZ106IHN0cmluZ307XG4gICAgcmVxdWlyZT86IHN0cmluZyB8IHN0cmluZ1tdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbXBvbmVudFZpZXdPcHRpb25zIHtcbiAgICBpbnB1dHM/OiBPYmplY3Q7XG4gICAgcGFyZW50PzogQ29tcG9uZW50QmFzZTtcbiAgICBhdHRyaWJ1dGVzPzogT2JqZWN0O1xuICAgIGV4dGVuZFdpdGg/OiBPYmplY3Q7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcHV0YXRpb25GdW5jdGlvbiB7XG4gICAgKGNvbXB1dGF0aW9uOiBDb21wdXRhdGlvbik6IHZvaWQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3Vic2NyaXB0aW9uIHtcbiAgICB1bnN1YnNjcmliZSgpOiB2b2lkO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN1YnNjcmliZUNvbXBvbmVudE9wdGlvbnMge1xuICAgIG9uZVNob3Q/OiBib29sZWFuO1xuICAgIG9uRXJyb3I/OiAoZXhjZXB0aW9uOiBhbnkpID0+IHZvaWQ7XG5cbiAgICAvLyBTZXQgdGhpcyB0byB0cnVlIHRvIG1ha2UgdGhlIHN1YnNjcmlwdGlvbiBiZSBpZ25vcmVkIHdoZW4gZGV0ZXJtaW5pbmdcbiAgICAvLyB3aGV0aGVyIHRoZSBjb21wb25lbnQgaXMgZG9uZSB3YWl0aW5nIGZvciBzdWJzY3JpcHRpb25zLlxuICAgIGlnbm9yZVJlYWR5PzogYm9vbGVhbjtcbn1cblxudHlwZSBTdWJzY3JpcHRpb25HdWFyZCA9IHt9O1xuXG5mdW5jdGlvbiBzYWZlQ2FsbGJhY2tBcHBseSgkc2NvcGU6IGFuZ3VsYXIuSVNjb3BlLCBjYWxsYmFjazogKCkgPT4gdm9pZCk6IHZvaWQge1xuICAgIGlmICgoPGFueT4gJHNjb3BlKS4kJGRlc3Ryb3llZCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY2FsbGJhY2soKTtcbiAgICAkc2NvcGUuJGV2YWxBc3luYygpO1xufVxuXG5mdW5jdGlvbiBzYWZlQXBwbHk8VD4ob2JzZXJ2YWJsZTogUnguT2JzZXJ2YWJsZTxUPiwgc2NvcGU6IGFuZ3VsYXIuSVNjb3BlLCBjYWxsYmFjazogKGRhdGE6IFQpID0+IHZvaWQpIHtcbiAgICBjYWxsYmFjayA9IGFuZ3VsYXIuaXNGdW5jdGlvbihjYWxsYmFjaykgPyBjYWxsYmFjayA6IF8ubm9vcDtcblxuICAgIHJldHVybiBvYnNlcnZhYmxlLnRha2VXaGlsZSgoKSA9PiB7XG4gICAgICAgIHJldHVybiAhc2NvcGVbJyQkZGVzdHJveWVkJ107XG4gICAgfSkudGFwKChkYXRhKSA9PiB7XG4gICAgICAgIHNhZmVDYWxsYmFja0FwcGx5KHNjb3BlLCAoKSA9PiB7IGNhbGxiYWNrKGRhdGEpOyB9KTtcbiAgICB9KTtcbn1cblxuLyoqXG4gKiBBYnN0cmFjdGlvbiBvZiBhIGNvbXB1dGF0aW9uIHdpdGggZGVwZW5kZW5jaWVzIHRvIG9ic2VydmFibGVzLlxuICovXG5leHBvcnQgY2xhc3MgQ29tcHV0YXRpb24ge1xuICAgIHByaXZhdGUgX3N1YnNjcmlwdGlvbnM6IFJ4LkRpc3Bvc2FibGVbXTtcbiAgICBwcml2YXRlIF9wZW5kaW5nU3Vic2NyaXB0aW9uczogU3Vic2NyaXB0aW9uR3VhcmRbXTtcbiAgICBwcml2YXRlIF9kaXNwb3NlOiAoKSA9PiB2b2lkO1xuICAgIHByaXZhdGUgX2RvbmU6IGJvb2xlYW47XG5cbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3RzIGEgbmV3IGNvbXB1dGF0aW9uLlxuICAgICAqXG4gICAgICogQHBhcmFtIGNvbXBvbmVudCBPd25pbmcgY29tcG9uZW50XG4gICAgICogQHBhcmFtIGNvbnRlbnQgQ29tcHV0YXRpb24gY29udGVudFxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHB1YmxpYyBjb21wb25lbnQ6IENvbXBvbmVudEJhc2UsIHB1YmxpYyBjb250ZW50OiBDb21wdXRhdGlvbkZ1bmN0aW9uKSB7IC8vIHRzbGludDpkaXNhYmxlLWxpbmU6bm8tc2hhZG93ZWQtdmFyaWFibGVcbiAgICAgICAgdGhpcy5fc3Vic2NyaXB0aW9ucyA9IFtdO1xuICAgICAgICB0aGlzLl9wZW5kaW5nU3Vic2NyaXB0aW9ucyA9IFtdO1xuICAgICAgICB0aGlzLl9kaXNwb3NlID0gKCkgPT4geyAvKiBEbyBub3RoaW5nIGJ5IGRlZmF1bHQuICovIH07XG4gICAgICAgIHRoaXMuX2RvbmUgPSBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm4gdHJ1ZSBpZiB0aGlzIGNvbXB1dGF0aW9uIGhhcyBmaW5pc2hlZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgaXNEb25lKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fZG9uZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIGFuIGFsdGVybmF0aXZlIGRpc3Bvc2UgY2FsbGJhY2sgZm9yIHRoaXMgY29tcHV0YXRpb24uIFRoaXMgY2FsbGJhY2tcbiAgICAgKiBpcyBpbnZva2VkIHdoZW4gW1t1bnN1YnNjcmliZV1dIGlzIGNhbGxlZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgc2V0RGlzcG9zZUNhbGxiYWNrKGNhbGxiYWNrOiAoKSA9PiB2b2lkKSB7XG4gICAgICAgIHRoaXMuX2Rpc3Bvc2UgPSBjYWxsYmFjaztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTdWJzY3JpYmVzIHRvIGFuIG9ic2VydmFibGUsIHJlZ2lzdGVyaW5nIHRoZSBzdWJzY3JpcHRpb24gYXMgYSBkZXBlbmRlbmN5XG4gICAgICogb2YgdGhpcyBjb21wb25lbnQuIFRoZSBzdWJzY3JpcHRpb24gaXMgYXV0b21hdGljYWxseSBzdG9wcGVkIHdoZW4gdGhlXG4gICAgICogY29tcG9uZW50IGlzIGRlc3Ryb3llZC5cbiAgICAgKlxuICAgICAqIEZvciB0aGUgdGFyZ2V0IGFyZ3VtZW50LCB5b3UgY2FuIGVpdGhlciBzcGVjaWZ5IGEgc3RyaW5nLCBpbiB3aGljaCBjYXNlXG4gICAgICogaXQgcmVwcmVzZW50cyB0aGUgbmFtZSBvZiB0aGUgY29tcG9uZW50IG1lbWJlciB2YXJpYWJsZSB0aGF0IHdpbGwgYmVcbiAgICAgKiBwb3B1bGF0ZWQgd2l0aCB0aGUgcmVzdWx0IGl0ZS4gT3IgeW91IGNhbiBzcGVjaWZ5IGEgZnVuY3Rpb24gd2l0aCBvbmVcbiAgICAgKiBhcmd1bWVudCwgd2hpY2ggd2lsbCBiZSBjYWxsZWQgd2hlbiBxdWVyeSByZXN1bHRzIGNoYW5nZSBhbmQgY2FuIGRvXG4gICAgICogYW55dGhpbmcuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdGFyZ2V0IFRhcmdldCBjb21wb25lbnQgbWVtYmVyIGF0cmlidXRlIG5hbWUgb3IgY2FsbGJhY2tcbiAgICAgKiBAcGFyYW0gb2JzZXJ2YWJsZSBPYnNlcnZhYmxlIG9yIHByb21pc2UgdG8gc3Vic2NyaWJlIHRvXG4gICAgICogQHJldHVybiBVbmRlcmx5aW5nIHN1YnNjcmlwdGlvbiBkaXNwb3NhYmxlXG4gICAgICovXG4gICAgcHVibGljIHN1YnNjcmliZTxUPih0YXJnZXQ6IHN0cmluZyB8ICgoZGF0YTogVCkgPT4gYW55KSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmFibGU6IFJ4Lk9ic2VydmFibGU8VD4gfCBQcm9taXNlPGFueT4gfCBhbmd1bGFyLklQcm9taXNlPGFueT4sXG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zOiBTdWJzY3JpYmVDb21wb25lbnRPcHRpb25zID0ge30pIHtcbiAgICAgICAgLy8gQ3JlYXRlIGEgZ3VhcmQgb2JqZWN0IHRoYXQgY2FuIGJlIHJlbW92ZWQgd2hlbiBhIHN1YnNjcmlwdGlvbiBpcyBkb25lLiBXZSBuZWVkXG4gICAgICAgIC8vIHRvIHVzZSBndWFyZCBvYmplY3RzIGluc3RlYWQgb2YgYSBzaW1wbGUgcmVmZXJlbmNlIGNvdW50ZXIgYmVjYXVzZSB0aGUgcGVuZGluZ1xuICAgICAgICAvLyBzdWJzY3JpcHRpb25zIGFycmF5IG1heSBiZSBjbGVhcmVkIHdoaWxlIGNhbGxiYWNrcyBhcmUgc3RpbGwgb3V0c3RhbmRpbmcuXG4gICAgICAgIGNvbnN0IGd1YXJkID0gbmV3IE9iamVjdCgpO1xuICAgICAgICBpZiAoIW9wdGlvbnMuaWdub3JlUmVhZHkpIHtcbiAgICAgICAgICAgIHRoaXMuX3BlbmRpbmdTdWJzY3JpcHRpb25zLnB1c2goZ3VhcmQpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGNvbnZlcnRlZE9ic2VydmFibGU6IFJ4Lk9ic2VydmFibGU8VD47XG4gICAgICAgIGlmIChpc1Byb21pc2VMaWtlKG9ic2VydmFibGUpKSB7XG4gICAgICAgICAgICBjb252ZXJ0ZWRPYnNlcnZhYmxlID0gUnguT2JzZXJ2YWJsZS5mcm9tUHJvbWlzZShvYnNlcnZhYmxlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnZlcnRlZE9ic2VydmFibGUgPSBvYnNlcnZhYmxlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVsZWFzZUd1YXJkID0gKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5fcGVuZGluZ1N1YnNjcmlwdGlvbnMgPSBfLndpdGhvdXQodGhpcy5fcGVuZGluZ1N1YnNjcmlwdGlvbnMsIGd1YXJkKTtcbiAgICAgICAgfTtcbiAgICAgICAgY29udmVydGVkT2JzZXJ2YWJsZSA9IGNvbnZlcnRlZE9ic2VydmFibGUudGFwKHJlbGVhc2VHdWFyZCwgcmVsZWFzZUd1YXJkKTtcblxuICAgICAgICBjb25zdCBzdWJzY3JpcHRpb24gPSBzYWZlQXBwbHkoXG4gICAgICAgICAgICBjb252ZXJ0ZWRPYnNlcnZhYmxlLFxuICAgICAgICAgICAgdGhpcy5jb21wb25lbnQuJHNjb3BlLFxuICAgICAgICAgICAgKGl0ZW0pID0+IHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoXy5pc0Z1bmN0aW9uKHRhcmdldCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldChpdGVtKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY29tcG9uZW50W3RhcmdldF0gPSBpdGVtO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXhjZXB0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignSWdub3JlZCBlcnJvciBpbiAnICsgdGhpcy5jb21wb25lbnQuZ2V0Q29uZmlnKCkuZGlyZWN0aXZlLCBleGNlcHRpb24pO1xuICAgICAgICAgICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIERpc3Bvc2Ugb2YgdGhlIHN1YnNjcmlwdGlvbiBpbW1lZGlhdGVseSBpZiB0aGlzIGlzIGEgb25lIHNob3Qgc3Vic2NyaXB0aW9uLlxuICAgICAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5vbmVTaG90ICYmIHN1YnNjcmlwdGlvbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2NyaXB0aW9uLmRpc3Bvc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgKS5zdWJzY3JpYmUoXG4gICAgICAgICAgICAvLyBTdWNjZXNzIGhhbmRsZXIuXG4gICAgICAgICAgICBfLm5vb3AsXG4gICAgICAgICAgICAvLyBFcnJvciBoYW5kbGVyLlxuICAgICAgICAgICAgKGV4Y2VwdGlvbikgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLm9uRXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQGlmbmRlZiBHRU5KU19QUk9EVUNUSU9OXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnSGFuZGxlZCBlcnJvciBpbiAnICsgdGhpcy5jb21wb25lbnQuZ2V0Q29uZmlnKCkuZGlyZWN0aXZlLCBleGNlcHRpb24pO1xuICAgICAgICAgICAgICAgICAgICAvLyBAZW5kaWZcbiAgICAgICAgICAgICAgICAgICAgc2FmZUNhbGxiYWNrQXBwbHkodGhpcy5jb21wb25lbnQuJHNjb3BlLCAoKSA9PiB7IG9wdGlvbnMub25FcnJvcihleGNlcHRpb24pOyB9KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1VuaGFuZGxlZCBlcnJvciBpbiAnICsgdGhpcy5jb21wb25lbnQuZ2V0Q29uZmlnKCkuZGlyZWN0aXZlLCBleGNlcHRpb24pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLl9zdWJzY3JpcHRpb25zLnB1c2goc3Vic2NyaXB0aW9uKTtcbiAgICAgICAgcmV0dXJuIHN1YnNjcmlwdGlvbjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRydWUgaWYgYWxsIHN1YnNjcmlwdGlvbnMgY3JlYXRlZCBieSBjYWxsaW5nIGBzdWJzY3JpYmVgIGFyZSByZWFkeS5cbiAgICAgKiBBIHN1YnNjcmlwdGlvbiBpcyByZWFkeSB3aGVuIGl0IGhhcyByZWNlaXZlZCBpdHMgZmlyc3QgYmF0Y2ggb2YgZGF0YSBhZnRlclxuICAgICAqIHN1YnNjcmliaW5nLlxuICAgICAqL1xuICAgIHB1YmxpYyBzdWJzY3JpcHRpb25zUmVhZHkoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wZW5kaW5nU3Vic2NyaXB0aW9ucy5sZW5ndGggPT09IDA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUnVucyB0aGUgY29tcHV0YXRpb24uXG4gICAgICovXG4gICAgcHVibGljIGNvbXB1dGUoKSB7XG4gICAgICAgIC8vIFN0b3AgYWxsIHN1YnNjcmlwdGlvbnMgYmVmb3JlIHJ1bm5pbmcgYWdhaW4uXG4gICAgICAgIHRoaXMuc3RvcCgpO1xuICAgICAgICB0aGlzLmNvbnRlbnQodGhpcyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGlzcG9zZXMgb2YgYWxsIHJlZ2lzdGVyZWQgc3Vic2NyaXB0aW9ucy5cbiAgICAgKi9cbiAgICBwdWJsaWMgc3RvcCgpIHtcbiAgICAgICAgZm9yIChsZXQgc3Vic2NyaXB0aW9uIG9mIHRoaXMuX3N1YnNjcmlwdGlvbnMpIHtcbiAgICAgICAgICAgIHN1YnNjcmlwdGlvbi5kaXNwb3NlKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fc3Vic2NyaXB0aW9ucyA9IFtdO1xuICAgICAgICB0aGlzLl9wZW5kaW5nU3Vic2NyaXB0aW9ucyA9IFtdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN0b3BzIGFsbCBzdWJzY3JpcHRpb25zIGN1cnJlbnRseSByZWdpc3RlcmVkIGluIHRoaXMgY29tcHV0YXRpb24gYW5kIHJlbW92ZXNcbiAgICAgKiB0aGlzIGNvbXB1dGF0aW9uIGZyb20gdGhlIHBhcmVudCBjb21wb25lbnQuIElmIGEgZGlzcG9zZSBoYW5kbGVyIGhhcyBiZWVuXG4gICAgICogY29uZmlndXJlZCwgaXQgaXMgaW52b2tlZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgdW5zdWJzY3JpYmUoKSB7XG4gICAgICAgIHRoaXMuY29tcG9uZW50LnVuc3Vic2NyaWJlKHRoaXMpO1xuICAgICAgICBpZiAodGhpcy5fZGlzcG9zZSkgdGhpcy5fZGlzcG9zZSgpO1xuICAgICAgICB0aGlzLl9kb25lID0gdHJ1ZTtcbiAgICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2F0Y2hFeHByZXNzaW9uT2Y8VD4ge1xuICAgICgpOiBUO1xufVxuZXhwb3J0IHR5cGUgV2F0Y2hFeHByZXNzaW9uID0gV2F0Y2hFeHByZXNzaW9uT2Y8e30+O1xuXG4vKipcbiAqIEFuIGFic3RyYWN0IGJhc2UgY2xhc3MgZm9yIGFsbCBjb21wb25lbnRzLlxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgQ29tcG9uZW50QmFzZSB7XG4gICAgLy8gQ29tcG9uZW50IGNvbmZpZ3VyYXRpb24uXG4gICAgcHVibGljIHN0YXRpYyBfX2NvbXBvbmVudENvbmZpZzogQ29tcG9uZW50Q29uZmlndXJhdGlvbjtcbiAgICAvLyBDb21wdXRhdGlvbnMuXG4gICAgcHJpdmF0ZSBfY29tcHV0YXRpb25zOiBDb21wdXRhdGlvbltdID0gW107XG4gICAgLy8gQ29tcG9uZW50IHN0YXRlLlxuICAgIHByaXZhdGUgX3JlYWR5OiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvLyBAbmdJbmplY3RcbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgJHNjb3BlOiBhbmd1bGFyLklTY29wZSkge1xuICAgICAgICAkc2NvcGUuJG9uKCckZGVzdHJveScsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuX3JlYWR5ID0gZmFsc2U7XG5cbiAgICAgICAgICAgIC8vIEVuc3VyZSB0aGF0IGFsbCBjb21wdXRhdGlvbnMgZ2V0IHN0b3BwZWQgd2hlbiB0aGUgY29tcG9uZW50IGlzIGRlc3Ryb3llZC5cbiAgICAgICAgICAgIGZvciAobGV0IGNv