angular2
Version:
Angular 2 - a web framework for modern web apps
516 lines • 59.9 kB
JavaScript
import { provide, platform, AppViewManager, Compiler, NgZone } from 'angular2/core';
import { ObservableWrapper } from 'angular2/src/facade/async';
import { BROWSER_PROVIDERS, BROWSER_APP_PROVIDERS } from 'angular2/platform/browser';
import { getComponentInfo } from './metadata';
import { onError, controllerKey } from './util';
import { NG1_COMPILE, NG1_INJECTOR, NG1_PARSE, NG1_ROOT_SCOPE, NG2_APP_VIEW_MANAGER, NG2_COMPILER, NG2_INJECTOR, NG2_HOST_VIEW_FACTORY_REF_MAP, NG2_ZONE, REQUIRE_INJECTOR } from './constants';
import { DowngradeNg2ComponentAdapter } from './downgrade_ng2_adapter';
import { UpgradeNg1ComponentAdapterBuilder } from './upgrade_ng1_adapter';
import * as angular from './angular_js';
var upgradeCount = 0;
/**
* Use `UpgradeAdapter` to allow AngularJS v1 and Angular v2 to coexist in a single application.
*
* The `UpgradeAdapter` allows:
* 1. creation of Angular v2 component from AngularJS v1 component directive
* (See [UpgradeAdapter#upgradeNg1Component()])
* 2. creation of AngularJS v1 directive from Angular v2 component.
* (See [UpgradeAdapter#downgradeNg2Component()])
* 3. Bootstrapping of a hybrid Angular application which contains both of the frameworks
* coexisting in a single application.
*
* ## Mental Model
*
* When reasoning about how a hybrid application works it is useful to have a mental model which
* describes what is happening and explains what is happening at the lowest level.
*
* 1. There are two independent frameworks running in a single application, each framework treats
* the other as a black box.
* 2. Each DOM element on the page is owned exactly by one framework. Whichever framework
* instantiated the element is the owner. Each framework only updates/interacts with its own
* DOM elements and ignores others.
* 3. AngularJS v1 directives always execute inside AngularJS v1 framework codebase regardless of
* where they are instantiated.
* 4. Angular v2 components always execute inside Angular v2 framework codebase regardless of
* where they are instantiated.
* 5. An AngularJS v1 component can be upgraded to an Angular v2 component. This creates an
* Angular v2 directive, which bootstraps the AngularJS v1 component directive in that location.
* 6. An Angular v2 component can be downgraded to an AngularJS v1 component directive. This creates
* an AngularJS v1 directive, which bootstraps the Angular v2 component in that location.
* 7. Whenever an adapter component is instantiated the host element is owned by the framework
* doing the instantiation. The other framework then instantiates and owns the view for that
* component. This implies that component bindings will always follow the semantics of the
* instantiation framework. The syntax is always that of Angular v2 syntax.
* 8. AngularJS v1 is always bootstrapped first and owns the bottom most view.
* 9. The new application is running in Angular v2 zone, and therefore it no longer needs calls to
* `$apply()`.
*
* ### Example
*
* ```
* var adapter = new UpgradeAdapter();
* var module = angular.module('myExample', []);
* module.directive('ng2', adapter.downgradeNg2Component(Ng2));
*
* module.directive('ng1', function() {
* return {
* scope: { title: '=' },
* template: 'ng1[Hello {{title}}!](<span ng-transclude></span>)'
* };
* });
*
*
* @Component({
* selector: 'ng2',
* inputs: ['name'],
* template: 'ng2[<ng1 [title]="name">transclude</ng1>](<ng-content></ng-content>)',
* directives: [adapter.upgradeNg1Component('ng1')]
* })
* class Ng2 {
* }
*
* document.body.innerHTML = '<ng2 name="World">project</ng2>';
*
* adapter.bootstrap(document.body, ['myExample']).ready(function() {
* expect(document.body.textContent).toEqual(
* "ng2[ng1[Hello World!](transclude)](project)");
* });
* ```
*/
export class UpgradeAdapter {
constructor() {
/* @internal */
this.idPrefix = `NG2_UPGRADE_${upgradeCount++}_`;
/* @internal */
this.upgradedComponents = [];
/* @internal */
this.downgradedComponents = {};
/* @internal */
this.providers = [];
}
/**
* Allows Angular v2 Component to be used from AngularJS v1.
*
* Use `downgradeNg2Component` to create an AngularJS v1 Directive Definition Factory from
* Angular v2 Component. The adapter will bootstrap Angular v2 component from within the
* AngularJS v1 template.
*
* ## Mental Model
*
* 1. The component is instantiated by being listed in AngularJS v1 template. This means that the
* host element is controlled by AngularJS v1, but the component's view will be controlled by
* Angular v2.
* 2. Even thought the component is instantiated in AngularJS v1, it will be using Angular v2
* syntax. This has to be done, this way because we must follow Angular v2 components do not
* declare how the attributes should be interpreted.
*
* ## Supported Features
*
* - Bindings:
* - Attribute: `<comp name="World">`
* - Interpolation: `<comp greeting="Hello {{name}}!">`
* - Expression: `<comp [name]="username">`
* - Event: `<comp (close)="doSomething()">`
* - Content projection: yes
*
* ### Example
*
* ```
* var adapter = new UpgradeAdapter();
* var module = angular.module('myExample', []);
* module.directive('greet', adapter.downgradeNg2Component(Greeter));
*
* @Component({
* selector: 'greet',
* template: '{{salutation}} {{name}}! - <ng-content></ng-content>'
* })
* class Greeter {
* @Input() salutation: string;
* @Input() name: string;
* }
*
* document.body.innerHTML =
* 'ng1 template: <greet salutation="Hello" [name]="world">text</greet>';
*
* adapter.bootstrap(document.body, ['myExample']).ready(function() {
* expect(document.body.textContent).toEqual("ng1 template: Hello world! - text");
* });
* ```
*/
downgradeNg2Component(type) {
this.upgradedComponents.push(type);
var info = getComponentInfo(type);
return ng1ComponentDirective(info, `${this.idPrefix}${info.selector}_c`);
}
/**
* Allows AngularJS v1 Component to be used from Angular v2.
*
* Use `upgradeNg1Component` to create an Angular v2 component from AngularJS v1 Component
* directive. The adapter will bootstrap AngularJS v1 component from within the Angular v2
* template.
*
* ## Mental Model
*
* 1. The component is instantiated by being listed in Angular v2 template. This means that the
* host element is controlled by Angular v2, but the component's view will be controlled by
* AngularJS v1.
*
* ## Supported Features
*
* - Bindings:
* - Attribute: `<comp name="World">`
* - Interpolation: `<comp greeting="Hello {{name}}!">`
* - Expression: `<comp [name]="username">`
* - Event: `<comp (close)="doSomething()">`
* - Transclusion: yes
* - Only some of the features of
* [Directive Definition Object](https://docs.angularjs.org/api/ng/service/$compile) are
* supported:
* - `compile`: not supported because the host element is owned by Angular v2, which does
* not allow modifying DOM structure during compilation.
* - `controller`: supported. (NOTE: injection of `$attrs` and `$transclude` is not supported.)
* - `controllerAs': supported.
* - `bindToController': supported.
* - `link': supported. (NOTE: only pre-link function is supported.)
* - `name': supported.
* - `priority': ignored.
* - `replace': not supported.
* - `require`: supported.
* - `restrict`: must be set to 'E'.
* - `scope`: supported.
* - `template`: supported.
* - `templateUrl`: supported.
* - `terminal`: ignored.
* - `transclude`: supported.
*
*
* ### Example
*
* ```
* var adapter = new UpgradeAdapter();
* var module = angular.module('myExample', []);
*
* module.directive('greet', function() {
* return {
* scope: {salutation: '=', name: '=' },
* template: '{{salutation}} {{name}}! - <span ng-transclude></span>'
* };
* });
*
* module.directive('ng2', adapter.downgradeNg2Component(Ng2));
*
* @Component({
* selector: 'ng2',
* template: 'ng2 template: <greet salutation="Hello" [name]="world">text</greet>'
* directives: [adapter.upgradeNg1Component('greet')]
* })
* class Ng2 {
* }
*
* document.body.innerHTML = '<ng2></ng2>';
*
* adapter.bootstrap(document.body, ['myExample']).ready(function() {
* expect(document.body.textContent).toEqual("ng2 template: Hello world! - text");
* });
* ```
*/
upgradeNg1Component(name) {
if (this.downgradedComponents.hasOwnProperty(name)) {
return this.downgradedComponents[name].type;
}
else {
return (this.downgradedComponents[name] = new UpgradeNg1ComponentAdapterBuilder(name)).type;
}
}
/**
* Bootstrap a hybrid AngularJS v1 / Angular v2 application.
*
* This `bootstrap` method is a direct replacement (takes same arguments) for AngularJS v1
* [`bootstrap`](https://docs.angularjs.org/api/ng/function/angular.bootstrap) method. Unlike
* AngularJS v1, this bootstrap is asynchronous.
*
* ### Example
*
* ```
* var adapter = new UpgradeAdapter();
* var module = angular.module('myExample', []);
* module.directive('ng2', adapter.downgradeNg2Component(Ng2));
*
* module.directive('ng1', function() {
* return {
* scope: { title: '=' },
* template: 'ng1[Hello {{title}}!](<span ng-transclude></span>)'
* };
* });
*
*
* @Component({
* selector: 'ng2',
* inputs: ['name'],
* template: 'ng2[<ng1 [title]="name">transclude</ng1>](<ng-content></ng-content>)',
* directives: [adapter.upgradeNg1Component('ng1')]
* })
* class Ng2 {
* }
*
* document.body.innerHTML = '<ng2 name="World">project</ng2>';
*
* adapter.bootstrap(document.body, ['myExample']).ready(function() {
* expect(document.body.textContent).toEqual(
* "ng2[ng1[Hello World!](transclude)](project)");
* });
* ```
*/
bootstrap(element, modules, config) {
var upgrade = new UpgradeAdapterRef();
var ng1Injector = null;
var platformRef = platform(BROWSER_PROVIDERS);
var applicationRef = platformRef.application([
BROWSER_APP_PROVIDERS,
provide(NG1_INJECTOR, { useFactory: () => ng1Injector }),
provide(NG1_COMPILE, { useFactory: () => ng1Injector.get(NG1_COMPILE) }),
this.providers
]);
var injector = applicationRef.injector;
var ngZone = injector.get(NgZone);
var compiler = injector.get(Compiler);
var delayApplyExps = [];
var original$applyFn;
var rootScopePrototype;
var rootScope;
var hostViewFactoryRefMap = {};
var ng1Module = angular.module(this.idPrefix, modules);
var ng1compilePromise = null;
ng1Module.value(NG2_INJECTOR, injector)
.value(NG2_ZONE, ngZone)
.value(NG2_COMPILER, compiler)
.value(NG2_HOST_VIEW_FACTORY_REF_MAP, hostViewFactoryRefMap)
.value(NG2_APP_VIEW_MANAGER, injector.get(AppViewManager))
.config([
'$provide',
(provide) => {
provide.decorator(NG1_ROOT_SCOPE, [
'$delegate',
function (rootScopeDelegate) {
rootScopePrototype = rootScopeDelegate.constructor.prototype;
if (rootScopePrototype.hasOwnProperty('$apply')) {
original$applyFn = rootScopePrototype.$apply;
rootScopePrototype.$apply = (exp) => delayApplyExps.push(exp);
}
else {
throw new Error("Failed to find '$apply' on '$rootScope'!");
}
return rootScope = rootScopeDelegate;
}
]);
}
])
.run([
'$injector',
'$rootScope',
(injector, rootScope) => {
ng1Injector = injector;
ObservableWrapper.subscribe(ngZone.onTurnDone, (_) => ngZone.runOutsideAngular(() => rootScope.$apply()));
ng1compilePromise =
UpgradeNg1ComponentAdapterBuilder.resolve(this.downgradedComponents, injector);
}
]);
angular.element(element).data(controllerKey(NG2_INJECTOR), injector);
ngZone.run(() => { angular.bootstrap(element, [this.idPrefix], config); });
Promise.all([this.compileNg2Components(compiler, hostViewFactoryRefMap), ng1compilePromise])
.then(() => {
ngZone.run(() => {
if (rootScopePrototype) {
rootScopePrototype.$apply = original$applyFn; // restore original $apply
while (delayApplyExps.length) {
rootScope.$apply(delayApplyExps.shift());
}
upgrade._bootstrapDone(applicationRef, ng1Injector);
rootScopePrototype = null;
}
});
}, onError);
return upgrade;
}
/**
* Adds a provider to the top level environment of a hybrid AngularJS v1 / Angular v2 application.
*
* In hybrid AngularJS v1 / Angular v2 application, there is no one root Angular v2 component,
* for this reason we provide an application global way of registering providers which is
* consistent with single global injection in AngularJS v1.
*
* ### Example
*
* ```
* class Greeter {
* greet(name) {
* alert('Hello ' + name + '!');
* }
* }
*
* @Component({
* selector: 'app',
* template: ''
* })
* class App {
* constructor(greeter: Greeter) {
* this.greeter('World');
* }
* }
*
* var adapter = new UpgradeAdapter();
* adapter.addProvider(Greeter);
*
* var module = angular.module('myExample', []);
* module.directive('app', adapter.downgradeNg2Component(App));
*
* document.body.innerHTML = '<app></app>'
* adapter.bootstrap(document.body, ['myExample']);
*```
*/
addProvider(provider) { this.providers.push(provider); }
/**
* Allows AngularJS v1 service to be accessible from Angular v2.
*
*
* ### Example
*
* ```
* class Login { ... }
* class Server { ... }
*
* @Injectable()
* class Example {
* constructor(@Inject('server') server, login: Login) {
* ...
* }
* }
*
* var module = angular.module('myExample', []);
* module.service('server', Server);
* module.service('login', Login);
*
* var adapter = new UpgradeAdapter();
* adapter.upgradeNg1Provider('server');
* adapter.upgradeNg1Provider('login', {asToken: Login});
* adapter.addProvider(Example);
*
* adapter.bootstrap(document.body, ['myExample']).ready((ref) => {
* var example: Example = ref.ng2Injector.get(Example);
* });
*
* ```
*/
upgradeNg1Provider(name, options) {
var token = options && options.asToken || name;
this.providers.push(provide(token, {
useFactory: (ng1Injector) => ng1Injector.get(name),
deps: [NG1_INJECTOR]
}));
}
/**
* Allows Angular v2 service to be accessible from AngularJS v1.
*
*
* ### Example
*
* ```
* class Example {
* }
*
* var adapter = new UpgradeAdapter();
* adapter.addProvider(Example);
*
* var module = angular.module('myExample', []);
* module.factory('example', adapter.downgradeNg2Provider(Example));
*
* adapter.bootstrap(document.body, ['myExample']).ready((ref) => {
* var example: Example = ref.ng1Injector.get('example');
* });
*
* ```
*/
downgradeNg2Provider(token) {
var factory = function (injector) { return injector.get(token); };
factory.$inject = [NG2_INJECTOR];
return factory;
}
/* @internal */
compileNg2Components(compiler, hostViewFactoryRefMap) {
var promises = [];
var types = this.upgradedComponents;
for (var i = 0; i < types.length; i++) {
promises.push(compiler.compileInHost(types[i]));
}
return Promise.all(promises).then((hostViewFactories) => {
var types = this.upgradedComponents;
for (var i = 0; i < hostViewFactories.length; i++) {
hostViewFactoryRefMap[getComponentInfo(types[i]).selector] = hostViewFactories[i];
}
return hostViewFactoryRefMap;
}, onError);
}
}
function ng1ComponentDirective(info, idPrefix) {
directiveFactory.$inject =
[NG2_HOST_VIEW_FACTORY_REF_MAP, NG2_APP_VIEW_MANAGER, NG1_PARSE];
function directiveFactory(hostViewFactoryRefMap, viewManager, parse) {
var hostViewFactory = hostViewFactoryRefMap[info.selector];
if (!hostViewFactory)
throw new Error('Expecting HostViewFactoryRef for: ' + info.selector);
var idCount = 0;
return {
restrict: 'E',
require: REQUIRE_INJECTOR,
link: {
post: (scope, element, attrs, parentInjector, transclude) => {
var domElement = element[0];
var facade = new DowngradeNg2ComponentAdapter(idPrefix + (idCount++), info, element, attrs, scope, parentInjector, parse, viewManager, hostViewFactory);
facade.setupInputs();
facade.bootstrapNg2();
facade.projectContent();
facade.setupOutputs();
facade.registerCleanup();
}
}
};
}
return directiveFactory;
}
/**
* Use `UgradeAdapterRef` to control a hybrid AngularJS v1 / Angular v2 application.
*/
export class UpgradeAdapterRef {
constructor() {
/* @internal */
this._readyFn = null;
this.ng1RootScope = null;
this.ng1Injector = null;
this.ng2ApplicationRef = null;
this.ng2Injector = null;
}
/* @internal */
_bootstrapDone(applicationRef, ng1Injector) {
this.ng2ApplicationRef = applicationRef;
this.ng2Injector = applicationRef.injector;
this.ng1Injector = ng1Injector;
this.ng1RootScope = ng1Injector.get(NG1_ROOT_SCOPE);
this._readyFn && this._readyFn(this);
}
/**
* Register a callback function which is notified upon successful hybrid AngularJS v1 / Angular v2
* application has been bootstrapped.
*
* The `ready` callback function is invoked inside the Angular v2 zone, therefore it does not
* require a call to `$apply()`.
*/
ready(fn) { this._readyFn = fn; }
/**
* Dispose of running hybrid AngularJS v1 / Angular v2 application.
*/
dispose() {
this.ng1Injector.get(NG1_ROOT_SCOPE).$destroy();
this.ng2ApplicationRef.dispose();
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBncmFkZV9hZGFwdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYW5ndWxhcjIvc3JjL3VwZ3JhZGUvdXBncmFkZV9hZGFwdGVyLnRzIl0sIm5hbWVzIjpbIlVwZ3JhZGVBZGFwdGVyIiwiVXBncmFkZUFkYXB0ZXIuY29uc3RydWN0b3IiLCJVcGdyYWRlQWRhcHRlci5kb3duZ3JhZGVOZzJDb21wb25lbnQiLCJVcGdyYWRlQWRhcHRlci51cGdyYWRlTmcxQ29tcG9uZW50IiwiVXBncmFkZUFkYXB0ZXIuYm9vdHN0cmFwIiwiVXBncmFkZUFkYXB0ZXIuYWRkUHJvdmlkZXIiLCJVcGdyYWRlQWRhcHRlci51cGdyYWRlTmcxUHJvdmlkZXIiLCJVcGdyYWRlQWRhcHRlci5kb3duZ3JhZGVOZzJQcm92aWRlciIsIlVwZ3JhZGVBZGFwdGVyLmNvbXBpbGVOZzJDb21wb25lbnRzIiwibmcxQ29tcG9uZW50RGlyZWN0aXZlIiwibmcxQ29tcG9uZW50RGlyZWN0aXZlLmRpcmVjdGl2ZUZhY3RvcnkiLCJVcGdyYWRlQWRhcHRlclJlZiIsIlVwZ3JhZGVBZGFwdGVyUmVmLmNvbnN0cnVjdG9yIiwiVXBncmFkZUFkYXB0ZXJSZWYuX2Jvb3RzdHJhcERvbmUiLCJVcGdyYWRlQWRhcHRlclJlZi5yZWFkeSIsIlVwZ3JhZGVBZGFwdGVyUmVmLmRpc3Bvc2UiXSwibWFwcGluZ3MiOiJPQUFPLEVBQ0wsT0FBTyxFQUNQLFFBQVEsRUFFUixjQUFjLEVBQ2QsUUFBUSxFQUVSLE1BQU0sRUFNUCxNQUFNLGVBQWU7T0FDZixFQUFDLGlCQUFpQixFQUFDLE1BQU0sMkJBQTJCO09BQ3BELEVBQUMsaUJBQWlCLEVBQUUscUJBQXFCLEVBQUMsTUFBTSwyQkFBMkI7T0FFM0UsRUFBQyxnQkFBZ0IsRUFBZ0IsTUFBTSxZQUFZO09BQ25ELEVBQUMsT0FBTyxFQUFFLGFBQWEsRUFBQyxNQUFNLFFBQVE7T0FDdEMsRUFDTCxXQUFXLEVBQ1gsWUFBWSxFQUNaLFNBQVMsRUFDVCxjQUFj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UUFDL0NBLGdCQUFXQSxHQUE2QkEsSUFBSUEsQ0FBQ0E7UUFDN0NBLHNCQUFpQkEsR0FBbUJBLElBQUlBLENBQUNBO1FBQ3pDQSxnQkFBV0EsR0FBYUEsSUFBSUEsQ0FBQ0E7SUEyQnRDQSxDQUFDQTtJQXpCQ0QsZUFBZUE7SUFDUEEsY0FBY0EsQ0FBQ0EsY0FBOEJBLEVBQUVBLFdBQXFDQTtRQUMxRkUsSUFBSUEsQ0FBQ0EsaUJBQWlCQSxHQUFHQSxjQUFjQSxDQUFDQTtRQUN4Q0EsSUFBSUEsQ0FBQ0EsV0FBV0EsR0FBR0EsY0FBY0EsQ0FBQ0EsUUFBUUEsQ0FBQ0E7UUFDM0NBLElBQUlBLENBQUNBLFdBQVdBLEdBQUdBLFdBQVdBLENBQUNBO1FBQy9CQSxJQUFJQSxDQUFDQSxZQUFZQSxHQUFHQSxXQUFXQSxDQUFDQSxHQUFHQSxDQUFDQSxjQUFjQSxDQUFDQSxDQUFDQTtRQUNwREEsSUFBSUEsQ0FBQ0EsUUFBUUEsSUFBSUEsSUFBSUEsQ0FBQ0EsUUFBUUEsQ0FBQ0EsSUFBSUEsQ0FBQ0EsQ0FBQ0E7SUFDdkNBLENBQUNBO0lBRURGOzs7Ozs7T0FNR0E7SUFDSUEsS0FBS0EsQ0FBQ0EsRUFBbURBLElBQUlHLElBQUlBLENBQUNBLFFBQVFBLEdBQUdBLEVBQUVBLENBQUNBLENBQUNBLENBQUNBO0lBRXpGSDs7T0FFR0E7SUFDSUEsT0FBT0E7UUFDWkksSUFBSUEsQ0FBQ0EsV0FBV0EsQ0FBQ0EsR0FBR0EsQ0FBQ0EsY0FBY0EsQ0FBQ0EsQ0FBQ0EsUUFBUUEsRUFBRUEsQ0FBQ0E7UUFDaERBLElBQUlBLENBQUNBLGlCQUFpQkEsQ0FBQ0EsT0FBT0EsRUFBRUEsQ0FBQ0E7SUFDbkNBLENBQUNBO0FBQ0hKLENBQUNBO0FBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBwcm92aWRlLFxuICBwbGF0Zm9ybSxcbiAgQXBwbGljYXRpb25SZWYsXG4gIEFwcFZpZXdNYW5hZ2VyLFxuICBDb21waWxlcixcbiAgSW5qZWN0b3IsXG4gIE5nWm9uZSxcbiAgUGxhdGZvcm1SZWYsXG4gIEhvc3RWaWV3RmFjdG9yeVJlZixcbiAgUHJvdmlkZXIsXG4gIFR5cGUsXG4gIEFQUExJQ0FUSU9OX0NPTU1PTl9QUk9WSURFUlNcbn0gZnJvbSAnYW5ndWxhcjIvY29yZSc7XG5pbXBvcnQge09ic2VydmFibGVXcmFwcGVyfSBmcm9tICdhbmd1bGFyMi9zcmMvZmFjYWRlL2FzeW5jJztcbmltcG9ydCB7QlJPV1NFUl9QUk9WSURFUlMsIEJST1dTRVJfQVBQX1BST1ZJREVSU30gZnJvbSAnYW5ndWxhcjIvcGxhdGZvcm0vYnJvd3Nlcic7XG5cbmltcG9ydCB7Z2V0Q29tcG9uZW50SW5mbywgQ29tcG9uZW50SW5mb30gZnJvbSAnLi9tZXRhZGF0YSc7XG5pbXBvcnQge29uRXJyb3IsIGNvbnRyb2xsZXJLZXl9IGZyb20gJy4vdXRpbCc7XG5pbXBvcnQge1xuICBORzFfQ09NUElMRSxcbiAgTkcxX0lOSkVDVE9SLFxuICBORzFfUEFSU0UsXG4gIE5HMV9ST09UX1NDT1BFLFxuICBORzFfU0NPUEUsXG4gIE5HMl9BUFBfVklFV19NQU5BR0VSLFxuICBORzJfQ09NUElMRVIsXG4gIE5HMl9JTkpFQ1RPUixcbiAgTkcyX0hPU1RfVklFV19GQUNUT1JZX1JFRl9NQVAsXG4gIE5HMl9aT05FLFxuICBSRVFVSVJFX0lOSkVDVE9SXG59IGZyb20gJy4vY29uc3RhbnRzJztcbmltcG9ydCB7RG93bmdyYWRlTmcyQ29tcG9uZW50QWRhcHRlcn0gZnJvbSAnLi9kb3duZ3JhZGVfbmcyX2FkYXB0ZXInO1xuaW1wb3J0IHtVcGdyYWRlTmcxQ29tcG9uZW50QWRhcHRlckJ1aWxkZXJ9IGZyb20gJy4vdXBncmFkZV9uZzFfYWRhcHRlcic7XG5pbXBvcnQgKiBhcyBhbmd1bGFyIGZyb20gJy4vYW5ndWxhcl9qcyc7XG5cbnZhciB1cGdyYWRlQ291bnQ6IG51bWJlciA9IDA7XG5cbi8qKlxuICogVXNlIGBVcGdyYWRlQWRhcHRlcmAgdG8gYWxsb3cgQW5ndWxhckpTIHYxIGFuZCBBbmd1bGFyIHYyIHRvIGNvZXhpc3QgaW4gYSBzaW5nbGUgYXBwbGljYXRpb24uXG4gKlxuICogVGhlIGBVcGdyYWRlQWRhcHRlcmAgYWxsb3dzOlxuICogMS4gY3JlYXRpb24gb2YgQW5ndWxhciB2MiBjb21wb25lbnQgZnJvbSBBbmd1bGFySlMgdjEgY29tcG9uZW50IGRpcmVjdGl2ZVxuICogICAgKFNlZSBbVXBncmFkZUFkYXB0ZXIjdXBncmFkZU5nMUNvbXBvbmVudCgpXSlcbiAqIDIuIGNyZWF0aW9uIG9mIEFuZ3VsYXJKUyB2MSBkaXJlY3RpdmUgZnJvbSBBbmd1bGFyIHYyIGNvbXBvbmVudC5cbiAqICAgIChTZWUgW1VwZ3JhZGVBZGFwdGVyI2Rvd25ncmFkZU5nMkNvbXBvbmVudCgpXSlcbiAqIDMuIEJvb3RzdHJhcHBpbmcgb2YgYSBoeWJyaWQgQW5ndWxhciBhcHBsaWNhdGlvbiB3aGljaCBjb250YWlucyBib3RoIG9mIHRoZSBmcmFtZXdvcmtzXG4gKiAgICBjb2V4aXN0aW5nIGluIGEgc2luZ2xlIGFwcGxpY2F0aW9uLlxuICpcbiAqICMjIE1lbnRhbCBNb2RlbFxuICpcbiAqIFdoZW4gcmVhc29uaW5nIGFib3V0IGhvdyBhIGh5YnJpZCBhcHBsaWNhdGlvbiB3b3JrcyBpdCBpcyB1c2VmdWwgdG8gaGF2ZSBhIG1lbnRhbCBtb2RlbCB3aGljaFxuICogZGVzY3JpYmVzIHdoYXQgaXMgaGFwcGVuaW5nIGFuZCBleHBsYWlucyB3aGF0IGlzIGhhcHBlbmluZyBhdCB0aGUgbG93ZXN0IGxldmVsLlxuICpcbiAqIDEuIFRoZXJlIGFyZSB0d28gaW5kZXBlbmRlbnQgZnJhbWV3b3JrcyBydW5uaW5nIGluIGEgc2luZ2xlIGFwcGxpY2F0aW9uLCBlYWNoIGZyYW1ld29yayB0cmVhdHNcbiAqICAgIHRoZSBvdGhlciBhcyBhIGJsYWNrIGJveC5cbiAqIDIuIEVhY2ggRE9NIGVsZW1lbnQgb24gdGhlIHBhZ2UgaXMgb3duZWQgZXhhY3RseSBieSBvbmUgZnJhbWV3b3JrLiBXaGljaGV2ZXIgZnJhbWV3b3JrXG4gKiAgICBpbnN0YW50aWF0ZWQgdGhlIGVsZW1lbnQgaXMgdGhlIG93bmVyLiBFYWNoIGZyYW1ld29yayBvbmx5IHVwZGF0ZXMvaW50ZXJhY3RzIHdpdGggaXRzIG93blxuICogICAgRE9NIGVsZW1lbnRzIGFuZCBpZ25vcmVzIG90aGVycy5cbiAqIDMuIEFuZ3VsYXJKUyB2MSBkaXJlY3RpdmVzIGFsd2F5cyBleGVjdXRlIGluc2lkZSBBbmd1bGFySlMgdjEgZnJhbWV3b3JrIGNvZGViYXNlIHJlZ2FyZGxlc3Mgb2ZcbiAqICAgIHdoZXJlIHRoZXkgYXJlIGluc3RhbnRpYXRlZC5cbiAqIDQuIEFuZ3VsYXIgdjIgY29tcG9uZW50cyBhbHdheXMgZXhlY3V0ZSBpbnNpZGUgQW5ndWxhciB2MiBmcmFtZXdvcmsgY29kZWJhc2UgcmVnYXJkbGVzcyBvZlxuICogICAgd2hlcmUgdGhleSBhcmUgaW5zdGFudGlhdGVkLlxuICogNS4gQW4gQW5ndWxhckpTIHYxIGNvbXBvbmVudCBjYW4gYmUgdXBncmFkZWQgdG8gYW4gQW5ndWxhciB2MiBjb21wb25lbnQuIFRoaXMgY3JlYXRlcyBhblxuICogICAgQW5ndWxhciB2MiBkaXJlY3RpdmUsIHdoaWNoIGJvb3RzdHJhcHMgdGhlIEFuZ3VsYXJKUyB2MSBjb21wb25lbnQgZGlyZWN0aXZlIGluIHRoYXQgbG9jYXRpb24uXG4gKiA2LiBBbiBBbmd1bGFyIHYyIGNvbXBvbmVudCBjYW4gYmUgZG93bmdyYWRlZCB0byBhbiBBbmd1bGFySlMgdjEgY29tcG9uZW50IGRpcmVjdGl2ZS4gVGhpcyBjcmVhdGVzXG4gKiAgICBhbiBBbmd1bGFySlMgdjEgZGlyZWN0aXZlLCB3aGljaCBib290c3RyYXBzIHRoZSBBbmd1bGFyIHYyIGNvbXBvbmVudCBpbiB0aGF0IGxvY2F0aW9uLlxuICogNy4gV2hlbmV2ZXIgYW4gYWRhcHRlciBjb21wb25lbnQgaXMgaW5zdGFudGlhdGVkIHRoZSBob3N0IGVsZW1lbnQgaXMgb3duZWQgYnkgdGhlIGZyYW1ld29ya1xuICogICAgZG9pbmcgdGhlIGluc3RhbnRpYXRpb24uIFRoZSBvdGhlciBmcmFtZXdvcmsgdGhlbiBpbnN0YW50aWF0ZXMgYW5kIG93bnMgdGhlIHZpZXcgZm9yIHRoYXRcbiAqICAgIGNvbXBvbmVudC4gVGhpcyBpbXBsaWVzIHRoYXQgY29tcG9uZW50IGJpbmRpbmdzIHdpbGwgYWx3YXlzIGZvbGxvdyB0aGUgc2VtYW50aWNzIG9mIHRoZVxuICogICAgaW5zdGFudGlhdGlvbiBmcmFtZXdvcmsuIFRoZSBzeW50YXggaXMgYWx3YXlzIHRoYXQgb2YgQW5ndWxhciB2MiBzeW50YXguXG4gKiA4LiBBbmd1bGFySlMgdjEgaXMgYWx3YXlzIGJvb3RzdHJhcHBlZCBmaXJzdCBhbmQgb3ducyB0aGUgYm90dG9tIG1vc3Qgdmlldy5cbiAqIDkuIFRoZSBuZXcgYXBwbGljYXRpb24gaXMgcnVubmluZyBpbiBBbmd1bGFyIHYyIHpvbmUsIGFuZCB0aGVyZWZvcmUgaXQgbm8gbG9uZ2VyIG5lZWRzIGNhbGxzIHRvXG4gKiAgICBgJGFwcGx5KClgLlxuICpcbiAqICMjIyBFeGFtcGxlXG4gKlxuICogYGBgXG4gKiB2YXIgYWRhcHRlciA9IG5ldyBVcGdyYWRlQWRhcHRlcigpO1xuICogdmFyIG1vZHVsZSA9IGFuZ3VsYXIubW9kdWxlKCdteUV4YW1wbGUnLCBbXSk7XG4gKiBtb2R1bGUuZGlyZWN0aXZlKCduZzInLCBhZGFwdGVyLmRvd25ncmFkZU5nMkNvbXBvbmVudChOZzIpKTtcbiAqXG4gKiBtb2R1bGUuZGlyZWN0aXZlKCduZzEnLCBmdW5jdGlvbigpIHtcbiAqICAgcmV0dXJuIHtcbiAqICAgICAgc2NvcGU6IHsgdGl0bGU6ICc9JyB9LFxuICogICAgICB0ZW1wbGF0ZTogJ25nMVtIZWxsbyB7e3RpdGxlfX0hXSg8c3BhbiBuZy10cmFuc2NsdWRlPjwvc3Bhbj4pJ1xuICogICB9O1xuICogfSk7XG4gKlxuICpcbiAqIEBDb21wb25lbnQoe1xuICogICBzZWxlY3RvcjogJ25nMicsXG4gKiAgIGlucHV0czogWyduYW1lJ10sXG4gKiAgIHRlbXBsYXRlOiAnbmcyWzxuZzEgW3RpdGxlXT1cIm5hbWVcIj50cmFuc2NsdWRlPC9uZzE+XSg8bmctY29udGVudD48L25nLWNvbnRlbnQ+KScsXG4gKiAgIGRpcmVjdGl2ZXM6IFthZGFwdGVyLnVwZ3JhZGVOZzFDb21wb25lbnQoJ25nMScpXVxuICogfSlcbiAqIGNsYXNzIE5nMiB7XG4gKiB9XG4gKlxuICogZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPSAnPG5nMiBuYW1lPVwiV29ybGRcIj5wcm9qZWN0PC9uZzI+JztcbiAqXG4gKiBhZGFwdGVyLmJvb3RzdHJhcChkb2N1bWVudC5ib2R5LCBbJ215RXhhbXBsZSddKS5yZWFkeShmdW5jdGlvbigpIHtcbiAqICAgZXhwZWN0KGRvY3VtZW50LmJvZHkudGV4dENvbnRlbnQpLnRvRXF1YWwoXG4gKiAgICAgICBcIm5nMltuZzFbSGVsbG8gV29ybGQhXSh0cmFuc2NsdWRlKV0ocHJvamVjdClcIik7XG4gKiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgVXBncmFkZUFkYXB0ZXIge1xuICAvKiBAaW50ZXJuYWwgKi9cbiAgcHJpdmF0ZSBpZFByZWZpeDogc3RyaW5nID0gYE5HMl9VUEdSQURFXyR7dXBncmFkZUNvdW50Kyt9X2A7XG4gIC8qIEBpbnRlcm5hbCAqL1xuICBwcml2YXRlIHVwZ3JhZGVkQ29tcG9uZW50czogVHlwZVtdID0gW107XG4gIC8qIEBpbnRlcm5hbCAqL1xuICBwcml2YXRlIGRvd25ncmFkZWRDb21wb25lbnRzOiB7W25hbWU6IHN0cmluZ106IFVwZ3JhZGVOZzFDb21wb25lbnRBZGFwdGVyQnVpbGRlcn0gPSB7fTtcbiAgLyogQGludGVybmFsICovXG4gIHByaXZhdGUgcHJvdmlkZXJzOiBBcnJheTxUeXBlIHwgUHJvdmlkZXIgfCBhbnlbXT4gPSBbXTtcblxuICAvKipcbiAgICogQWxsb3dzIEFuZ3VsYXIgdjIgQ29tcG9uZW50IHRvIGJlIHVzZWQgZnJvbSBBbmd1bGFySlMgdjEuXG4gICAqXG4gICAqIFVzZSBgZG93bmdyYWRlTmcyQ29tcG9uZW50YCB0byBjcmVhdGUgYW4gQW5ndWxhckpTIHYxIERpcmVjdGl2ZSBEZWZpbml0aW9uIEZhY3RvcnkgZnJvbVxuICAgKiBBbmd1bGFyIHYyIENvbXBvbmVudC4gVGhlIGFkYXB0ZXIgd2lsbCBib290c3RyYXAgQW5ndWxhciB2MiBjb21wb25lbnQgZnJvbSB3aXRoaW4gdGhlXG4gICAqIEFuZ3VsYXJKUyB2MSB0ZW1wbGF0ZS5cbiAgICpcbiAgICogIyMgTWVudGFsIE1vZGVsXG4gICAqXG4gICAqIDEuIFRoZSBjb21wb25lbnQgaXMgaW5zdGFudGlhdGVkIGJ5IGJlaW5nIGxpc3RlZCBpbiBBbmd1bGFySlMgdjEgdGVtcGxhdGUuIFRoaXMgbWVhbnMgdGhhdCB0aGVcbiAgICogICAgaG9zdCBlbGVtZW50IGlzIGNvbnRyb2xsZWQgYnkgQW5ndWxhckpTIHYxLCBidXQgdGhlIGNvbXBvbmVudCdzIHZpZXcgd2lsbCBiZSBjb250cm9sbGVkIGJ5XG4gICAqICAgIEFuZ3VsYXIgdjIuXG4gICAqIDIuIEV2ZW4gdGhvdWdodCB0aGUgY29tcG9uZW50IGlzIGluc3RhbnRpYXRlZCBpbiBBbmd1bGFySlMgdjEsIGl0IHdpbGwgYmUgdXNpbmcgQW5ndWxhciB2MlxuICAgKiAgICBzeW50YXguIFRoaXMgaGFzIHRvIGJlIGRvbmUsIHRoaXMgd2F5IGJlY2F1c2Ugd2UgbXVzdCBmb2xsb3cgQW5ndWxhciB2MiBjb21wb25lbnRzIGRvIG5vdFxuICAgKiAgICBkZWNsYXJlIGhvdyB0aGUgYXR0cmlidXRlcyBzaG91bGQgYmUgaW50ZXJwcmV0ZWQuXG4gICAqXG4gICAqICMjIFN1cHBvcnRlZCBGZWF0dXJlc1xuICAgKlxuICAgKiAtIEJpbmRpbmdzOlxuICAgKiAgIC0gQXR0cmlidXRlOiBgPGNvbXAgbmFtZT1cIldvcmxkXCI+YFxuICAgKiAgIC0gSW50ZXJwb2xhdGlvbjogIGA8Y29tcCBncmVldGluZz1cIkhlbGxvIHt7bmFtZX19IVwiPmBcbiAgICogICAtIEV4cHJlc3Npb246ICBgPGNvbXAgW25hbWVdPVwidXNlcm5hbWVcIj5gXG4gICAqICAgLSBFdmVudDogIGA8Y29tcCAoY2xvc2UpPVwiZG9Tb21ldGhpbmcoKVwiPmBcbiAgICogLSBDb250ZW50IHByb2plY3Rpb246IHllc1xuICAgKlxuICAgKiAjIyMgRXhhbXBsZVxuICAgKlxuICAgKiBgYGBcbiAgICogdmFyIGFkYXB0ZXIgPSBuZXcgVXBncmFkZUFkYXB0ZXIoKTtcbiAgICogdmFyIG1vZHVsZSA9IGFuZ3VsYXIubW9kdWxlKCdteUV4YW1wbGUnLCBbXSk7XG4gICAqIG1vZHVsZS5kaXJlY3RpdmUoJ2dyZWV0JywgYWRhcHRlci5kb3duZ3JhZGVOZzJDb21wb25lbnQoR3JlZXRlcikpO1xuICAgKlxuICAgKiBAQ29tcG9uZW50KHtcbiAgICogICBzZWxlY3RvcjogJ2dyZWV0JyxcbiAgICogICB0ZW1wbGF0ZTogJ3t7c2FsdXRhdGlvbn19IHt7bmFtZX19ISAtIDxuZy1jb250ZW50PjwvbmctY29udGVudD4nXG4gICAqIH0pXG4gICAqIGNsYXNzIEdyZWV0ZXIge1xuICAgKiAgIEBJbnB1dCgpIHNhbHV0YXRpb246IHN0cmluZztcbiAgICogICBASW5wdXQoKSBuYW1lOiBzdHJpbmc7XG4gICAqIH1cbiAgICpcbiAgICogZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxuICAgKiAgICduZzEgdGVtcGxhdGU6IDxncmVldCBzYWx1dGF0aW9uPVwiSGVsbG9cIiBbbmFtZV09XCJ3b3JsZFwiPnRleHQ8L2dyZWV0Pic7XG4gICAqXG4gICAqIGFkYXB0ZXIuYm9vdHN0cmFwKGRvY3VtZW50LmJvZHksIFsnbXlFeGFtcGxlJ10pLnJlYWR5KGZ1bmN0aW9uKCkge1xuICAgKiAgIGV4cGVjdChkb2N1bWVudC5ib2R5LnRleHRDb250ZW50KS50b0VxdWFsKFwibmcxIHRlbXBsYXRlOiBIZWxsbyB3b3JsZCEgLSB0ZXh0XCIpO1xuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBkb3duZ3JhZGVOZzJDb21wb25lbnQodHlwZTogVHlwZSk6IEZ1bmN0aW9uIHtcbiAgICB0aGlzLnVwZ3JhZGVkQ29tcG9uZW50cy5wdXNoKHR5cGUpO1xuICAgIHZhciBpbmZvOiBDb21wb25lbnRJbmZvID0gZ2V0Q29tcG9uZW50SW5mbyh0eXBlKTtcbiAgICByZXR1cm4gbmcxQ29tcG9uZW50RGlyZWN0aXZlKGluZm8sIGAke3RoaXMuaWRQcmVmaXh9JHtpbmZvLnNlbGVjdG9yfV9jYCk7XG4gIH1cblxuICAvKipcbiAgICogQWxsb3dzIEFuZ3VsYXJKUyB2MSBDb21wb25lbnQgdG8gYmUgdXNlZCBmcm9tIEFuZ3VsYXIgdjIuXG4gICAqXG4gICAqIFVzZSBgdXBncmFkZU5nMUNvbXBvbmVudGAgdG8gY3JlYXRlIGFuIEFuZ3VsYXIgdjIgY29tcG9uZW50IGZyb20gQW5ndWxhckpTIHYxIENvbXBvbmVudFxuICAgKiBkaXJlY3RpdmUuIFRoZSBhZGFwdGVyIHdpbGwgYm9vdHN0cmFwIEFuZ3VsYXJKUyB2MSBjb21wb25lbnQgZnJvbSB3aXRoaW4gdGhlIEFuZ3VsYXIgdjJcbiAgICogdGVtcGxhdGUuXG4gICAqXG4gICAqICMjIE1lbnRhbCBNb2RlbFxuICAgKlxuICAgKiAxLiBUaGUgY29tcG9uZW50IGlzIGluc3RhbnRpYXRlZCBieSBiZWluZyBsaXN0ZWQgaW4gQW5ndWxhciB2MiB0ZW1wbGF0ZS4gVGhpcyBtZWFucyB0aGF0IHRoZVxuICAgKiAgICBob3N0IGVsZW1lbnQgaXMgY29udHJvbGxlZCBieSBBbmd1bGFyIHYyLCBidXQgdGhlIGNvbXBvbmVudCdzIHZpZXcgd2lsbCBiZSBjb250cm9sbGVkIGJ5XG4gICAqICAgIEFuZ3VsYXJKUyB2MS5cbiAgICpcbiAgICogIyMgU3VwcG9ydGVkIEZlYXR1cmVzXG4gICAqXG4gICAqIC0gQmluZGluZ3M6XG4gICAqICAgLSBBdHRyaWJ1dGU6IGA8Y29tcCBuYW1lPVwiV29ybGRcIj5gXG4gICAqICAgLSBJbnRlcnBvbGF0aW9uOiAgYDxjb21wIGdyZWV0aW5nPVwiSGVsbG8ge3tuYW1lfX0hXCI+YFxuICAgKiAgIC0gRXhwcmVzc2lvbjogIGA8Y29tcCBbbmFtZV09XCJ1c2VybmFtZVwiPmBcbiAgICogICAtIEV2ZW50OiAgYDxjb21wIChjbG9zZSk9XCJkb1NvbWV0aGluZygpXCI+YFxuICAgKiAtIFRyYW5zY2x1c2lvbjogeWVzXG4gICAqIC0gT25seSBzb21lIG9mIHRoZSBmZWF0dXJlcyBvZlxuICAgKiAgIFtEaXJlY3RpdmUgRGVmaW5pdGlvbiBPYmplY3RdKGh0dHBzOi8vZG9jcy5hbmd1bGFyanMub3JnL2FwaS9uZy9zZXJ2aWNlLyRjb21waWxlKSBhcmVcbiAgICogICBzdXBwb3J0ZWQ6XG4gICAqICAgLSBgY29tcGlsZWA6IG5vdCBzdXBwb3J0ZWQgYmVjYXVzZSB0aGUgaG9zdCBlbGVtZW50IGlzIG93bmVkIGJ5IEFuZ3VsYXIgdjIsIHdoaWNoIGRvZXNcbiAgICogICAgIG5vdCBhbGxvdyBtb2RpZnlpbmcgRE9NIHN0cnVjdHVyZSBkdXJpbmcgY29tcGlsYXRpb24uXG4gICAqICAgLSBgY29udHJvbGxlcmA6IHN1cHBvcnRlZC4gKE5PVEU6IGluamVjdGlvbiBvZiBgJGF0dHJzYCBhbmQgYCR0cmFuc2NsdWRlYCBpcyBub3Qgc3VwcG9ydGVkLilcbiAgICogICAtIGBjb250cm9sbGVyQXMnOiBzdXBwb3J0ZWQuXG4gICAqICAgLSBgYmluZFRvQ29udHJvbGxlcic6IHN1cHBvcnRlZC5cbiAgICogICAtIGBsaW5rJzogc3VwcG9ydGVkLiAoTk9URTogb25seSBwcmUtbGluayBmdW5jdGlvbiBpcyBzdXBwb3J0ZWQuKVxuICAgKiAgIC0gYG5hbWUnOiBzdXBwb3J0ZWQuXG4gICAqICAgLSBgcHJpb3JpdHknOiBpZ25vcmVkLlxuICAgKiAgIC0gYHJlcGxhY2UnOiBub3Qgc3VwcG9ydGVkLlxuICAgKiAgIC0gYHJlcXVpcmVgOiBzdXBwb3J0ZWQuXG4gICAqICAgLSBgcmVzdHJpY3RgOiBtdXN0IGJlIHNldCB0byAnRScuXG4gICAqICAgLSBgc2NvcGVgOiBzdXBwb3J0ZWQuXG4gICAqICAgLSBgdGVtcGxhdGVgOiBzdXBwb3J0ZWQuXG4gICAqICAgLSBgdGVtcGxhdGVVcmxgOiBzdXBwb3J0ZWQuXG4gICAqICAgLSBgdGVybWluYWxgOiBpZ25vcmVkLlxuICAgKiAgIC0gYHRyYW5zY2x1ZGVgOiBzdXBwb3J0ZWQuXG4gICAqXG4gICAqXG4gICAqICMjIyBFeGFtcGxlXG4gICAqXG4gICAqIGBgYFxuICAgKiB2YXIgYWRhcHRlciA9IG5ldyBVcGdyYWRlQWRhcHRlcigpO1xuICAgKiB2YXIgbW9kdWxlID0gYW5ndWxhci5tb2R1bGUoJ215RXhhbXBsZScsIFtdKTtcbiAgICpcbiAgICogbW9kdWxlLmRpcmVjdGl2ZSgnZ3JlZXQnLCBmdW5jdGlvbigpIHtcbiAgICogICByZXR1cm4ge1xuICAgKiAgICAgc2NvcGU6IHtzYWx1dGF0aW9uOiAnPScsIG5hbWU6ICc9JyB9LFxuICAgKiAgICAgdGVtcGxhdGU6ICd7e3NhbHV0YXRpb259fSB7e25hbWV9fSEgLSA8c3BhbiBuZy10cmFuc2NsdWRlPjwvc3Bhbj4nXG4gICAqICAgfTtcbiAgICogfSk7XG4gICAqXG4gICAqIG1vZHVsZS5kaXJlY3RpdmUoJ25nMicsIGFkYXB0ZXIuZG93bmdyYWRlTmcyQ29tcG9uZW50KE5nMikpO1xuICAgKlxuICAgKiBAQ29tcG9uZW50KHtcbiAgICogICBzZWxlY3RvcjogJ25nMicsXG4gICAqICAgdGVtcGxhdGU6ICduZzIgdGVtcGxhdGU6IDxncmVldCBzYWx1dGF0aW9uPVwiSGVsbG9cIiBbbmFtZV09XCJ3b3JsZFwiPnRleHQ8L2dyZWV0PidcbiAgICogICBkaXJlY3RpdmVzOiBbYWRhcHRlci51cGdyYWRlTmcxQ29tcG9uZW50KCdncmVldCcpXVxuICAgKiB9KVxuICAgKiBjbGFzcyBOZzIge1xuICAgKiB9XG4gICAqXG4gICAqIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID0gJzxuZzI+PC9uZzI+JztcbiAgICpcbiAgICogYWRhcHRlci5ib290c3RyYXAoZG9jdW1lbnQuYm9keSwgWydteUV4YW1wbGUnXSkucmVhZHkoZnVuY3Rpb24oKSB7XG4gICAqICAgZXhwZWN0KGRvY3VtZW50LmJvZHkudGV4dENvbnRlbnQpLnRvRXF1YWwoXCJuZzIgdGVtcGxhdGU6IEhlbGxvIHdvcmxkISAtIHRleHRcIik7XG4gICAqIH0pO1xuICAgKiBgYGBcbiAgICovXG4gIHVwZ3JhZGVOZzFDb21wb25lbnQobmFtZTogc3RyaW5nKTogVHlwZSB7XG4gICAgaWYgKCg8YW55PnRoaXMuZG93bmdyYWRlZENvbXBvbmVudHMpLmhhc093blByb3BlcnR5KG5hbWUpKSB7XG4gICAgICByZXR1cm4gdGhpcy5kb3duZ3JhZGVkQ29tcG9uZW50c1tuYW1lXS50eXBlO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gKHRoaXMuZG93bmdyYWRlZENvbXBvbmVudHNbbmFtZV0gPSBuZXcgVXBncmFkZU5nMUNvbXBvbmVudEFkYXB0ZXJCdWlsZGVyKG5hbWUpKS50eXBlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBCb290c3RyYXAgYSBoeWJyaWQgQW5ndWxhckpTIHYxIC8gQW5ndWxhciB2MiBhcHBsaWNhdGlvbi5cbiAgICpcbiAgICogVGhpcyBgYm9vdHN0cmFwYCBtZXRob2QgaXMgYSBkaXJlY3QgcmVwbGFjZW1lbnQgKHRha2VzIHNhbWUgYXJndW1lbnRzKSBmb3IgQW5ndWxhckpTIHYxXG4gICAqIFtgYm9vdHN0cmFwYF0oaHR0cHM6Ly9kb2NzLmFuZ3VsYXJqcy5vcmcvYXBpL25nL2Z1bmN0aW9uL2FuZ3VsYXIuYm9vdHN0cmFwKSBtZXRob2QuIFVubGlrZVxuICAgKiBBbmd1bGFySlMgdjEsIHRoaXMgYm9vdHN0cmFwIGlzIGFzeW5jaHJvbm91cy5cbiAgICpcbiAgICogIyMjIEV4YW1wbGVcbiAgICpcbiAgICogYGBgXG4gICAqIHZhciBhZGFwdGVyID0gbmV3IFVwZ3JhZGVBZGFwdGVyKCk7XG4gICAqIHZhciBtb2R1bGUgPSBhbmd1bGFyLm1vZHVsZSgnbXlFeGFtcGxlJywgW10pO1xuICAgKiBtb2R1bGUuZGlyZWN0aXZlKCduZzInLCBhZGFwdGVyLmRvd25ncmFkZU5nMkNvbXBvbmVudChOZzIpKTtcbiAgICpcbiAgICogbW9kdWxlLmRpcmVjdGl2ZSgnbmcxJywgZnVuY3Rpb24oKSB7XG4gICAqICAgcmV0dXJuIHtcbiAgICogICAgICBzY29wZTogeyB0aXRsZTogJz0nIH0sXG4gICAqICAgICAgdGVtcGxhdGU6ICduZzFbSGVsbG8ge3t0aXRsZX19IV0oPHNwYW4gbmctdHJhbnNjbHVkZT48L3NwYW4+KSdcbiAgICogICB9O1xuICAgKiB9KTtcbiAgICpcbiAgICpcbiAgICogQENvbXBvbmVudCh7XG4gICAqICAgc2VsZWN0b3I6ICduZzInLFxuICAgKiAgIGlucHV0czogWyduYW1lJ10sXG4gICAqICAgdGVtcGxhdGU6ICduZzJbPG5nMSBbdGl0bGVdPVwibmFtZVwiPnRyYW5zY2x1ZGU8L25nMT5dKDxuZy1jb250ZW50PjwvbmctY29udGVudD4pJyxcbiAgICogICBkaXJlY3RpdmVzOiBbYWRhcHRlci51cGdyYWRlTmcxQ29tcG9uZW50KCduZzEnKV1cbiAgICogfSlcbiAgICogY2xhc3MgTmcyIHtcbiAgICogfVxuICAgKlxuICAgKiBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9ICc8bmcyIG5hbWU9XCJXb3JsZFwiPnByb2plY3Q8L25nMj4nO1xuICAgKlxuICAgKiBhZGFwdGVyLmJvb3RzdHJhcChkb2N1bWVudC5ib2R5LCBbJ215RXhhbXBsZSddKS5yZWFkeShmdW5jdGlvbigpIHtcbiAgICogICBleHBlY3QoZG9jdW1lbnQuYm9keS50ZXh0Q29udGVudCkudG9FcXVhbChcbiAgICogICAgICAgXCJuZzJbbmcxW0hlbGxvIFdvcmxkIV0odHJhbnNjbHVkZSldKHByb2plY3QpXCIpO1xuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBib290c3RyYXAoZWxlbWVudDogRWxlbWVudCwgbW9kdWxlcz86IGFueVtdLFxuICAgICAgICAgICAgY29uZmlnPzogYW5ndWxhci5JQW5ndWxhckJvb3RzdHJhcENvbmZpZyk6IFVwZ3JhZGVBZGFwdGVyUmVmIHtcbiAgICB2YXIgdXBncmFkZSA9IG5ldyBVcGdyYWRlQWRhcHRlclJlZigpO1xuICAgIHZhciBuZzFJbmplY3RvcjogYW5ndWxhci5JSW5qZWN0b3JTZXJ2aWNlID0gbnVsbDtcbiAgICB2YXIgcGxhdGZvcm1SZWY6IFBsYXRmb3JtUmVmID0gcGxhdGZvcm0oQlJPV1NFUl9QUk9WSURFUlMpO1xuICAgIHZhciBhcHBsaWNhdGlvblJlZjogQXBwbGljYXRpb25SZWYgPSBwbGF0Zm9ybVJlZi5hcHBsaWNhdGlvbihbXG4gICAgICBCUk9XU0VSX0FQUF9QUk9WSURFUlMsXG4gICAgICBwcm92aWRlKE5HMV9JTkpFQ1RPUiwge3VzZUZhY3Rvcnk6ICgpID0+IG5nMUluamVjdG9yfSksXG4gICAgICBwcm92aWRlKE5HMV9DT01QSUxFLCB7dXNlRmFjdG9yeTogKCkgPT4gbmcxSW5qZWN0b3IuZ2V0KE5HMV9DT01QSUxFKX0pLFxuICAgICAgdGhpcy5wcm92aWRlcnNcbiAgICBdKTtcbiAgICB2YXIgaW5qZWN0b3I6IEluamVjdG9yID0gYXBwbGljYXRpb25SZWYuaW5qZWN0b3I7XG4gICAgdmFyIG5nWm9uZTogTmdab25lID0gaW5qZWN0b3IuZ2V0KE5nWm9uZSk7XG4gICAgdmFyIGNvbXBpbGVyOiBDb21waWxlciA9IGluamVjdG9yLmdldChDb21waWxlcik7XG4gICAgdmFyIGRlbGF5QXBwbHlFeHBzOiBGdW5jdGlvbltdID0gW107XG4gICAgdmFyIG9yaWdpbmFsJGFwcGx5Rm46IEZ1bmN0aW9uO1xuICAgIHZhciByb290U2NvcGVQcm90b3R5cGU6IGFueTtcbiAgICB2YXIgcm9vdFNjb3BlOiBhbmd1bGFyLklSb290U2NvcGVTZXJ2aWNlO1xuICAgIHZhciBob3N0Vmlld0ZhY3RvcnlSZWZNYXA6IEhvc3RWaWV3RmFjdG9yeVJlZk1hcCA9IHt9O1xuICAgIHZhciBuZzFNb2R1bGUgPSBhbmd1bGFyLm1vZHVsZSh0aGlzLmlkUHJlZml4LCBtb2R1bGVzKTtcbiAgICB2YXIgbmcxY29tcGlsZVByb21pc2U6IFByb21pc2U8YW55PiA9IG51bGw7XG4gICAgbmcxTW9kdWxlLnZhbHVlKE5HMl9JTkpFQ1RPUiwgaW5qZWN0b3IpXG4gICAgICAgIC52YWx1ZShORzJfWk9ORSwgbmdab25lKVxuICAgICAgICAudmFsdWUoTkcyX0NPTVBJTEVSLCBjb21waWxlcilcbiAgICAgICAgLnZhbHVlKE5HMl9IT1NUX1ZJRVdfRkFDVE9SWV9SRUZfTUFQLCBob3N0Vmlld0ZhY3RvcnlSZWZNYXApXG4gICAgICAgIC52YWx1ZShORzJfQVBQX1ZJRVdfTUFOQUdFUiwgaW5qZWN0b3IuZ2V0KEFwcFZpZXdNYW5hZ2VyKSlcbiAgICAgICAgLmNvbmZpZyhbXG4gICAgICAgICAgJyRwcm92aWRlJyxcbiAgICAgICAgICAocHJvdmlkZSkgPT4ge1xuICAgICAgICAgICAgcHJvdmlkZS5kZWNvcmF0b3IoTkcxX1JPT1RfU0NPUEUsIFtcbiAgICAgICAgICAgICAgJyRkZWxlZ2F0ZScsXG4gICAgICAgICAgICAgIGZ1bmN0aW9uKHJvb3RTY29wZURlbGVnYXRlOiBhbmd1bGFyLklSb290U2NvcGVTZXJ2aWNlKSB7XG4gICAgICAgICAgICAgICAgcm9vdFNjb3BlUHJvdG90eXBlID0gcm9vdFNjb3BlRGVsZWdhdGUuY29uc3RydWN0b3IucHJvdG90eXBlO1xuICAgICAgICAgICAgICAgIGlmIChyb290U2NvcGVQcm90b3R5cGUuaGFzT3duUHJvcGVydHkoJyRhcHBseScpKSB7XG4gICAgICAgICAgICAgICAgICBvcmlnaW5hbCRhcHBseUZuID0gcm9vdFNjb3BlUHJvdG90eXBlLiRhcHBseTtcbiAgICAgICAgICAgICAgICAgIHJvb3RTY29wZVByb3RvdHlwZS4kYXBwbHkgPSAoZXhwKSA9PiBkZWxheUFwcGx5RXhwcy5wdXNoKGV4cCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkZhaWxlZCB0byBmaW5kICckYXBwbHknIG9uICckcm9vdFNjb3BlJyFcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiByb290U2NvcGUgPSByb290U2NvcGVEZWxlZ2F0ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgXSk7XG4gICAgICAgICAgfVxuICAgICAgICBdKVxuICAgICAgICAucnVuKFtcbiAgICAgICAgICAnJGluamVjdG9yJyxcbiAgICAgICAgICAnJHJvb3RTY29wZScsXG4gICAgICAgICAgKGluamVjdG9yOiBhbmd1bGFyLklJbmplY3RvclNlcnZpY2UsIHJvb3RTY29wZTogYW5ndWxhci5JUm9vdFNjb3BlU2VydmljZSkgPT4ge1xuICAgICAgICAgICAgbmcxSW5qZWN0b3IgPSBpbmplY3RvcjtcbiAgICAgICAgICAgIE9ic2VydmFibGVXcmFwcGVyLnN1YnNjcmliZShuZ1pvbmUub25UdXJuRG9uZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoXykgPT4gbmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHJvb3RTY29wZS4kYXBwbHkoKSkpO1xuICAgICAgICAgICAgbmcxY29tcGlsZVByb21pc2UgPVxuICAgICAgICAgICAgICAgIFVwZ3JhZGVOZzFDb21wb25lbnRBZGFwdGVyQnVpbGRlci5yZXNvbHZlKHRoaXMuZG93bmdyYWRlZENvbXBvbmVudHMsIGluamVjdG9yKTtcbiAgICAgI