1 | /**
|
2 | * @license
|
3 | * Copyright Google LLC All Rights Reserved.
|
4 | *
|
5 | * Use of this source code is governed by an MIT-style license that can be
|
6 | * found in the LICENSE file at https://angular.io/license
|
7 | */
|
8 | import { PlatformRef } from '@angular/core';
|
9 | import { platformBrowser } from '@angular/platform-browser';
|
10 | import { module_ as angularModule } from '../../src/common/src/angular1';
|
11 | import { $INJECTOR, $PROVIDE, DOWNGRADED_MODULE_COUNT_KEY, INJECTOR_KEY, LAZY_MODULE_REF, UPGRADE_APP_TYPE_KEY, UPGRADE_MODULE_NAME } from '../../src/common/src/constants';
|
12 | import { destroyApp, getDowngradedModuleCount, isFunction, isNgModuleType } from '../../src/common/src/util';
|
13 | import { angular1Providers, setTempInjectorRef } from './angular1_providers';
|
14 | import { NgAdapterInjector } from './util';
|
15 | let moduleUid = 0;
|
16 | /**
|
17 | * @description
|
18 | *
|
19 | * A helper function for creating an AngularJS module that can bootstrap an Angular module
|
20 | * "on-demand" (possibly lazily) when a {@link downgradeComponent downgraded component} needs to be
|
21 | * instantiated.
|
22 | *
|
23 | * *Part of the [upgrade/static](api?query=upgrade/static) library for hybrid upgrade apps that
|
24 | * support AOT compilation.*
|
25 | *
|
26 | * It allows loading/bootstrapping the Angular part of a hybrid application lazily and not having to
|
27 | * pay the cost up-front. For example, you can have an AngularJS application that uses Angular for
|
28 | * specific routes and only instantiate the Angular modules if/when the user visits one of these
|
29 | * routes.
|
30 | *
|
31 | * The Angular module will be bootstrapped once (when requested for the first time) and the same
|
32 | * reference will be used from that point onwards.
|
33 | *
|
34 | * `downgradeModule()` requires either an `NgModuleFactory`, `NgModule` class or a function:
|
35 | * - `NgModuleFactory`: If you pass an `NgModuleFactory`, it will be used to instantiate a module
|
36 | * using `platformBrowser`'s {@link PlatformRef#bootstrapModuleFactory bootstrapModuleFactory()}.
|
37 | * NOTE: this type of the argument is deprecated. Please either provide an `NgModule` class or a
|
38 | * bootstrap function instead.
|
39 | * - `NgModule` class: If you pass an NgModule class, it will be used to instantiate a module
|
40 | * using `platformBrowser`'s {@link PlatformRef#bootstrapModule bootstrapModule()}.
|
41 | * - `Function`: If you pass a function, it is expected to return a promise resolving to an
|
42 | * `NgModuleRef`. The function is called with an array of extra {@link StaticProvider Providers}
|
43 | * that are expected to be available from the returned `NgModuleRef`'s `Injector`.
|
44 | *
|
45 | * `downgradeModule()` returns the name of the created AngularJS wrapper module. You can use it to
|
46 | * declare a dependency in your main AngularJS module.
|
47 | *
|
48 | * {@example upgrade/static/ts/lite/module.ts region="basic-how-to"}
|
49 | *
|
50 | * For more details on how to use `downgradeModule()` see
|
51 | * [Upgrading for Performance](guide/upgrade-performance).
|
52 | *
|
53 | * @usageNotes
|
54 | *
|
55 | * Apart from `UpgradeModule`, you can use the rest of the `upgrade/static` helpers as usual to
|
56 | * build a hybrid application. Note that the Angular pieces (e.g. downgraded services) will not be
|
57 | * available until the downgraded module has been bootstrapped, i.e. by instantiating a downgraded
|
58 | * component.
|
59 | *
|
60 | * <div class="alert is-important">
|
61 | *
|
62 | * You cannot use `downgradeModule()` and `UpgradeModule` in the same hybrid application.<br />
|
63 | * Use one or the other.
|
64 | *
|
65 | * </div>
|
66 | *
|
67 | * ### Differences with `UpgradeModule`
|
68 | *
|
69 | * Besides their different API, there are two important internal differences between
|
70 | * `downgradeModule()` and `UpgradeModule` that affect the behavior of hybrid applications:
|
71 | *
|
72 | * 1. Unlike `UpgradeModule`, `downgradeModule()` does not bootstrap the main AngularJS module
|
73 | * inside the {@link NgZone Angular zone}.
|
74 | * 2. Unlike `UpgradeModule`, `downgradeModule()` does not automatically run a
|
75 | * [$digest()](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest) when changes are
|
76 | * detected in the Angular part of the application.
|
77 | *
|
78 | * What this means is that applications using `UpgradeModule` will run change detection more
|
79 | * frequently in order to ensure that both frameworks are properly notified about possible changes.
|
80 | * This will inevitably result in more change detection runs than necessary.
|
81 | *
|
82 | * `downgradeModule()`, on the other side, does not try to tie the two change detection systems as
|
83 | * tightly, restricting the explicit change detection runs only to cases where it knows it is
|
84 | * necessary (e.g. when the inputs of a downgraded component change). This improves performance,
|
85 | * especially in change-detection-heavy applications, but leaves it up to the developer to manually
|
86 | * notify each framework as needed.
|
87 | *
|
88 | * For a more detailed discussion of the differences and their implications, see
|
89 | * [Upgrading for Performance](guide/upgrade-performance).
|
90 | *
|
91 | * <div class="alert is-helpful">
|
92 | *
|
93 | * You can manually trigger a change detection run in AngularJS using
|
94 | * [scope.$apply(...)](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply) or
|
95 | * [$rootScope.$digest()](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest).
|
96 | *
|
97 | * You can manually trigger a change detection run in Angular using {@link NgZone#run
|
98 | * ngZone.run(...)}.
|
99 | *
|
100 | * </div>
|
101 | *
|
102 | * ### Downgrading multiple modules
|
103 | *
|
104 | * It is possible to downgrade multiple modules and include them in an AngularJS application. In
|
105 | * that case, each downgraded module will be bootstrapped when an associated downgraded component or
|
106 | * injectable needs to be instantiated.
|
107 | *
|
108 | * Things to keep in mind, when downgrading multiple modules:
|
109 | *
|
110 | * - Each downgraded component/injectable needs to be explicitly associated with a downgraded
|
111 | * module. See `downgradeComponent()` and `downgradeInjectable()` for more details.
|
112 | *
|
113 | * - If you want some injectables to be shared among all downgraded modules, you can provide them as
|
114 | * `StaticProvider`s, when creating the `PlatformRef` (e.g. via `platformBrowser` or
|
115 | * `platformBrowserDynamic`).
|
116 | *
|
117 | * - When using {@link PlatformRef#bootstrapmodule `bootstrapModule()`} or
|
118 | * {@link PlatformRef#bootstrapmodulefactory `bootstrapModuleFactory()`} to bootstrap the
|
119 | * downgraded modules, each one is considered a "root" module. As a consequence, a new instance
|
120 | * will be created for every injectable provided in `"root"` (via
|
121 | * {@link Injectable#providedIn `providedIn`}).
|
122 | * If this is not your intention, you can have a shared module (that will act as act as the "root"
|
123 | * module) and create all downgraded modules using that module's injector:
|
124 | *
|
125 | * {@example upgrade/static/ts/lite-multi-shared/module.ts region="shared-root-module"}
|
126 | *
|
127 | * @publicApi
|
128 | */
|
129 | export function downgradeModule(moduleOrBootstrapFn) {
|
130 | const lazyModuleName = `${UPGRADE_MODULE_NAME}.lazy${++moduleUid}`;
|
131 | const lazyModuleRefKey = `${LAZY_MODULE_REF}${lazyModuleName}`;
|
132 | const lazyInjectorKey = `${INJECTOR_KEY}${lazyModuleName}`;
|
133 | let bootstrapFn;
|
134 | if (isNgModuleType(moduleOrBootstrapFn)) {
|
135 | // NgModule class
|
136 | bootstrapFn = (extraProviders) => platformBrowser(extraProviders).bootstrapModule(moduleOrBootstrapFn);
|
137 | }
|
138 | else if (!isFunction(moduleOrBootstrapFn)) {
|
139 | // NgModule factory
|
140 | bootstrapFn = (extraProviders) => platformBrowser(extraProviders).bootstrapModuleFactory(moduleOrBootstrapFn);
|
141 | }
|
142 | else {
|
143 | // bootstrap function
|
144 | bootstrapFn = moduleOrBootstrapFn;
|
145 | }
|
146 | let injector;
|
147 | // Create an ng1 module to bootstrap.
|
148 | angularModule(lazyModuleName, [])
|
149 | .constant(UPGRADE_APP_TYPE_KEY, 3 /* UpgradeAppType.Lite */)
|
150 | .factory(INJECTOR_KEY, [lazyInjectorKey, identity])
|
151 | .factory(lazyInjectorKey, () => {
|
152 | if (!injector) {
|
153 | throw new Error('Trying to get the Angular injector before bootstrapping the corresponding ' +
|
154 | 'Angular module.');
|
155 | }
|
156 | return injector;
|
157 | })
|
158 | .factory(LAZY_MODULE_REF, [lazyModuleRefKey, identity])
|
159 | .factory(lazyModuleRefKey, [
|
160 | $INJECTOR,
|
161 | ($injector) => {
|
162 | setTempInjectorRef($injector);
|
163 | const result = {
|
164 | promise: bootstrapFn(angular1Providers).then(ref => {
|
165 | injector = result.injector = new NgAdapterInjector(ref.injector);
|
166 | injector.get($INJECTOR);
|
167 | // Destroy the AngularJS app once the Angular `PlatformRef` is destroyed.
|
168 | // This does not happen in a typical SPA scenario, but it might be useful for
|
169 | // other use-cases where disposing of an Angular/AngularJS app is necessary
|
170 | // (such as Hot Module Replacement (HMR)).
|
171 | // See https://github.com/angular/angular/issues/39935.
|
172 | injector.get(PlatformRef).onDestroy(() => destroyApp($injector));
|
173 | return injector;
|
174 | })
|
175 | };
|
176 | return result;
|
177 | }
|
178 | ])
|
179 | .config([
|
180 | $INJECTOR, $PROVIDE,
|
181 | ($injector, $provide) => {
|
182 | $provide.constant(DOWNGRADED_MODULE_COUNT_KEY, getDowngradedModuleCount($injector) + 1);
|
183 | }
|
184 | ]);
|
185 | return lazyModuleName;
|
186 | }
|
187 | function identity(x) {
|
188 | return x;
|
189 | }
|
190 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG93bmdyYWRlX21vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL3VwZ3JhZGUvc3RhdGljL3NyYy9kb3duZ3JhZGVfbW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBeUMsV0FBVyxFQUF1QixNQUFNLGVBQWUsQ0FBQztBQUN4RyxPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0sMkJBQTJCLENBQUM7QUFFMUQsT0FBTyxFQUFvQyxPQUFPLElBQUksYUFBYSxFQUFDLE1BQU0sK0JBQStCLENBQUM7QUFDMUcsT0FBTyxFQUFDLFNBQVMsRUFBRSxRQUFRLEVBQUUsMkJBQTJCLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxvQkFBb0IsRUFBRSxtQkFBbUIsRUFBQyxNQUFNLGdDQUFnQyxDQUFDO0FBQzFLLE9BQU8sRUFBQyxVQUFVLEVBQUUsd0JBQXdCLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBZ0MsTUFBTSwyQkFBMkIsQ0FBQztBQUUxSSxPQUFPLEVBQUMsaUJBQWlCLEVBQUUsa0JBQWtCLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUMzRSxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxRQUFRLENBQUM7QUFHekMsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO0FBME9sQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWdIRztBQUNILE1BQU0sVUFBVSxlQUFlLENBQUksbUJBQytCO0lBQ2hFLE1BQU0sY0FBYyxHQUFHLEdBQUcsbUJBQW1CLFFBQVEsRUFBRSxTQUFTLEVBQUUsQ0FBQztJQUNuRSxNQUFNLGdCQUFnQixHQUFHLEdBQUcsZUFBZSxHQUFHLGNBQWMsRUFBRSxDQUFDO0lBQy9ELE1BQU0sZUFBZSxHQUFHLEdBQUcsWUFBWSxHQUFHLGNBQWMsRUFBRSxDQUFDO0lBRTNELElBQUksV0FBMEUsQ0FBQztJQUMvRSxJQUFJLGNBQWMsQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFO1FBQ3ZDLGlCQUFpQjtRQUNqQixXQUFXLEdBQUcsQ0FBQyxjQUFnQyxFQUFFLEVBQUUsQ0FDL0MsZUFBZSxDQUFDLGNBQWMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0tBQzFFO1NBQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFO1FBQzNDLG1CQUFtQjtRQUNuQixXQUFXLEdBQUcsQ0FBQyxjQUFnQyxFQUFFLEVBQUUsQ0FDL0MsZUFBZSxDQUFDLGNBQWMsQ0FBQyxDQUFDLHNCQUFzQixDQUFDLG1CQUFtQixDQUFDLENBQUM7S0FDakY7U0FBTTtRQUNMLHFCQUFxQjtRQUNyQixXQUFXLEdBQUcsbUJBQW1CLENBQUM7S0FDbkM7SUFFRCxJQUFJLFFBQWtCLENBQUM7SUFFdkIscUNBQXFDO0lBQ3JDLGFBQWEsQ0FBQyxjQUFjLEVBQUUsRUFBRSxDQUFDO1NBQzVCLFFBQVEsQ0FBQyxvQkFBb0IsOEJBQXNCO1NBQ25ELE9BQU8sQ0FBQyxZQUFZLEVBQUUsQ0FBQyxlQUFlLEVBQUUsUUFBUSxDQUFDLENBQUM7U0FDbEQsT0FBTyxDQUNKLGVBQWUsRUFDZixHQUFHLEVBQUU7UUFDSCxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2IsTUFBTSxJQUFJLEtBQUssQ0FDWCw0RUFBNEU7Z0JBQzVFLGlCQUFpQixDQUFDLENBQUM7U0FDeEI7UUFDRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDLENBQUM7U0FDTCxPQUFPLENBQUMsZUFBZSxFQUFFLENBQUMsZ0JBQWdCLEVBQUUsUUFBUSxDQUFDLENBQUM7U0FDdEQsT0FBTyxDQUNKLGdCQUFnQixFQUNoQjtRQUNFLFNBQVM7UUFDVCxDQUFDLFNBQTJCLEVBQUUsRUFBRTtZQUM5QixrQkFBa0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUM5QixNQUFNLE1BQU0sR0FBa0I7Z0JBQzVCLE9BQU8sRUFBRSxXQUFXLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUU7b0JBQ2pELFFBQVEsR0FBRyxNQUFNLENBQUMsUUFBUSxHQUFHLElBQUksaUJBQWlCLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO29CQUNqRSxRQUFRLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO29CQUV4Qix5RUFBeUU7b0JBQ3pFLDZFQUE2RTtvQkFDN0UsMkVBQTJFO29CQUMzRSwwQ0FBMEM7b0JBQzFDLHVEQUF1RDtvQkFDdkQsUUFBUSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7b0JBRWpFLE9BQU8sUUFBUSxDQUFDO2dCQUNsQixDQUFDLENBQUM7YUFDSCxDQUFDO1lBQ0YsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztLQUNGLENBQUM7U0FDTCxNQUFNLENBQUM7UUFDTixTQUFTLEVBQUUsUUFBUTtRQUNuQixDQUFDLFNBQTJCLEVBQUUsUUFBeUIsRUFBRSxFQUFFO1lBQ3pELFFBQVEsQ0FBQyxRQUFRLENBQUMsMkJBQTJCLEVBQUUsd0JBQXdCLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDMUYsQ0FBQztLQUNGLENBQUMsQ0FBQztJQUVQLE9BQU8sY0FBYyxDQUFDO0FBQ3hCLENBQUM7QUFFRCxTQUFTLFFBQVEsQ0FBVSxDQUFJO0lBQzdCLE9BQU8sQ0FBQyxDQUFDO0FBQ1gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge0luamVjdG9yLCBOZ01vZHVsZUZhY3RvcnksIE5nTW9kdWxlUmVmLCBQbGF0Zm9ybVJlZiwgU3RhdGljUHJvdmlkZXIsIFR5cGV9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtwbGF0Zm9ybUJyb3dzZXJ9IGZyb20gJ0Bhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXInO1xuXG5pbXBvcnQge0lJbmplY3RvclNlcnZpY2UsIElQcm92aWRlU2VydmljZSwgbW9kdWxlXyBhcyBhbmd1bGFyTW9kdWxlfSBmcm9tICcuLi8uLi9zcmMvY29tbW9uL3NyYy9hbmd1bGFyMSc7XG5pbXBvcnQgeyRJTkpFQ1RPUiwgJFBST1ZJREUsIERPV05HUkFERURfTU9EVUxFX0NPVU5UX0tFWSwgSU5KRUNUT1JfS0VZLCBMQVpZX01PRFVMRV9SRUYsIFVQR1JBREVfQVBQX1RZUEVfS0VZLCBVUEdSQURFX01PRFVMRV9OQU1FfSBmcm9tICcuLi8uLi9zcmMvY29tbW9uL3NyYy9jb25zdGFudHMnO1xuaW1wb3J0IHtkZXN0cm95QXBwLCBnZXREb3duZ3JhZGVkTW9kdWxlQ291bnQsIGlzRnVuY3Rpb24sIGlzTmdNb2R1bGVUeXBlLCBMYXp5TW9kdWxlUmVmLCBVcGdyYWRlQXBwVHlwZX0gZnJvbSAnLi4vLi4vc3JjL2NvbW1vbi9zcmMvdXRpbCc7XG5cbmltcG9ydCB7YW5ndWxhcjFQcm92aWRlcnMsIHNldFRlbXBJbmplY3RvclJlZn0gZnJvbSAnLi9hbmd1bGFyMV9wcm92aWRlcnMnO1xuaW1wb3J0IHtOZ0FkYXB0ZXJJbmplY3Rvcn0gZnJvbSAnLi91dGlsJztcblxuXG5sZXQgbW9kdWxlVWlkID0gMDtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb25cbiAqXG4gKiBBIGhlbHBlciBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgYW4gQW5ndWxhckpTIG1vZHVsZSB0aGF0IGNhbiBib290c3RyYXAgYW4gQW5ndWxhciBtb2R1bGVcbiAqIFwib24tZGVtYW5kXCIgKHBvc3NpYmx5IGxhemlseSkgd2hlbiBhIHtAbGluayBkb3duZ3JhZGVDb21wb25lbnQgZG93bmdyYWRlZCBjb21wb25lbnR9IG5lZWRzIHRvIGJlXG4gKiBpbnN0YW50aWF0ZWQuXG4gKlxuICogKlBhcnQgb2YgdGhlIFt1cGdyYWRlL3N0YXRpY10oYXBpP3F1ZXJ5PXVwZ3JhZGUvc3RhdGljKSBsaWJyYXJ5IGZvciBoeWJyaWQgdXBncmFkZSBhcHBzIHRoYXRcbiAqIHN1cHBvcnQgQU9UIGNvbXBpbGF0aW9uLipcbiAqXG4gKiBJdCBhbGxvd3MgbG9hZGluZy9ib290c3RyYXBwaW5nIHRoZSBBbmd1bGFyIHBhcnQgb2YgYSBoeWJyaWQgYXBwbGljYXRpb24gbGF6aWx5IGFuZCBub3QgaGF2aW5nIHRvXG4gKiBwYXkgdGhlIGNvc3QgdXAtZnJvbnQuIEZvciBleGFtcGxlLCB5b3UgY2FuIGhhdmUgYW4gQW5ndWxhckpTIGFwcGxpY2F0aW9uIHRoYXQgdXNlcyBBbmd1bGFyIGZvclxuICogc3BlY2lmaWMgcm91dGVzIGFuZCBvbmx5IGluc3RhbnRpYXRlIHRoZSBBbmd1bGFyIG1vZHVsZXMgaWYvd2hlbiB0aGUgdXNlciB2aXNpdHMgb25lIG9mIHRoZXNlXG4gKiByb3V0ZXMuXG4gKlxuICogVGhlIEFuZ3VsYXIgbW9kdWxlIHdpbGwgYmUgYm9vdHN0cmFwcGVkIG9uY2UgKHdoZW4gcmVxdWVzdGVkIGZvciB0aGUgZmlyc3QgdGltZSkgYW5kIHRoZSBzYW1lXG4gKiByZWZlcmVuY2Ugd2lsbCBiZSB1c2VkIGZyb20gdGhhdCBwb2ludCBvbndhcmRzLlxuICpcbiAqIGBkb3duZ3JhZGVNb2R1bGUoKWAgcmVxdWlyZXMgZWl0aGVyIGFuIGBOZ01vZHVsZUZhY3RvcnlgLCBgTmdNb2R1bGVgIGNsYXNzIG9yIGEgZnVuY3Rpb246XG4gKiAtIGBOZ01vZHVsZUZhY3RvcnlgOiBJZiB5b3UgcGFzcyBhbiBgTmdNb2R1bGVGYWN0b3J5YCwgaXQgd2lsbCBiZSB1c2VkIHRvIGluc3RhbnRpYXRlIGEgbW9kdWxlXG4gKiAgIHVzaW5nIGBwbGF0Zm9ybUJyb3dzZXJgJ3Mge0BsaW5rIFBsYXRmb3JtUmVmI2Jvb3RzdHJhcE1vZHVsZUZhY3RvcnkgYm9vdHN0cmFwTW9kdWxlRmFjdG9yeSgpfS5cbiAqICAgTk9URTogdGhpcyB0eXBlIG9mIHRoZSBhcmd1bWVudCBpcyBkZXByZWNhdGVkLiBQbGVhc2UgZWl0aGVyIHByb3ZpZGUgYW4gYE5nTW9kdWxlYCBjbGFzcyBvciBhXG4gKiAgIGJvb3RzdHJhcCBmdW5jdGlvbiBpbnN0ZWFkLlxuICogLSBgTmdNb2R1bGVgIGNsYXNzOiBJZiB5b3UgcGFzcyBhbiBOZ01vZHVsZSBjbGFzcywgaXQgd2lsbCBiZSB1c2VkIHRvIGluc3RhbnRpYXRlIGEgbW9kdWxlXG4gKiAgIHVzaW5nIGBwbGF0Zm9ybUJyb3dzZXJgJ3Mge0BsaW5rIFBsYXRmb3JtUmVmI2Jvb3RzdHJhcE1vZHVsZSBib290c3RyYXBNb2R1bGUoKX0uXG4gKiAtIGBGdW5jdGlvbmA6IElmIHlvdSBwYXNzIGEgZnVuY3Rpb24sIGl0IGlzIGV4cGVjdGVkIHRvIHJldHVybiBhIHByb21pc2UgcmVzb2x2aW5nIHRvIGFuXG4gKiAgIGBOZ01vZHVsZVJlZmAuIFRoZSBmdW5jdGlvbiBpcyBjYWxsZWQgd2l0aCBhbiBhcnJheSBvZiBleHRyYSB7QGxpbmsgU3RhdGljUHJvdmlkZXIgUHJvdmlkZXJzfVxuICogICB0aGF0IGFyZSBleHBlY3RlZCB0byBiZSBhdmFpbGFibGUgZnJvbSB0aGUgcmV0dXJuZWQgYE5nTW9kdWxlUmVmYCdzIGBJbmplY3RvcmAuXG4gKlxuICogYGRvd25ncmFkZU1vZHVsZSgpYCByZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSBjcmVhdGVkIEFuZ3VsYXJKUyB3cmFwcGVyIG1vZHVsZS4gWW91IGNhbiB1c2UgaXQgdG9cbiAqIGRlY2xhcmUgYSBkZXBlbmRlbmN5IGluIHlvdXIgbWFpbiBBbmd1bGFySlMgbW9kdWxlLlxuICpcbiAqIHtAZXhhbXBsZSB1cGdyYWRlL3N0YXRpYy90cy9saXRlL21vZHVsZS50cyByZWdpb249XCJiYXNpYy1ob3ctdG9cIn1cbiAqXG4gKiBGb3IgbW9yZSBkZXRhaWxzIG9uIGhvdyB0byB1c2UgYGRvd25ncmFkZU1vZHVsZSgpYCBzZWVcbiAqIFtVcGdyYWRpbmcgZm9yIFBlcmZvcm1hbmNlXShndWlkZS91cGdyYWRlLXBlcmZvcm1hbmNlKS5cbiAqXG4gKiBAdXNhZ2VOb3Rlc1xuICpcbiAqIEFwYXJ0IGZyb20gYFVwZ3JhZGVNb2R1bGVgLCB5b3UgY2FuIHVzZSB0aGUgcmVzdCBvZiB0aGUgYHVwZ3JhZGUvc3RhdGljYCBoZWxwZXJzIGFzIHVzdWFsIHRvXG4gKiBidWlsZCBhIGh5YnJpZCBhcHBsaWNhdGlvbi4gTm90ZSB0aGF0IHRoZSBBbmd1bGFyIHBpZWNlcyAoZS5nLiBkb3duZ3JhZGVkIHNlcnZpY2VzKSB3aWxsIG5vdCBiZVxuICogYXZhaWxhYmxlIHVudGlsIHRoZSBkb3duZ3JhZGVkIG1vZHVsZSBoYXMgYmVlbiBib290c3RyYXBwZWQsIGkuZS4gYnkgaW5zdGFudGlhdGluZyBhIGRvd25ncmFkZWRcbiAqIGNvbXBvbmVudC5cbiAqXG4gKiA8ZGl2IGNsYXNzPVwiYWxlcnQgaXMtaW1wb3J0YW50XCI+XG4gKlxuICogICBZb3UgY2Fubm90IHVzZSBgZG93bmdyYWRlTW9kdWxlKClgIGFuZCBgVXBncmFkZU1vZHVsZWAgaW4gdGhlIHNhbWUgaHlicmlkIGFwcGxpY2F0aW9uLjxiciAvPlxuICogICBVc2Ugb25lIG9yIHRoZSBvdGhlci5cbiAqXG4gKiA8L2Rpdj5cbiAqXG4gKiAjIyMgRGlmZmVyZW5jZXMgd2l0aCBgVXBncmFkZU1vZHVsZWBcbiAqXG4gKiBCZXNpZGVzIHRoZWlyIGRpZmZlcmVudCBBUEksIHRoZXJlIGFyZSB0d28gaW1wb3J0YW50IGludGVybmFsIGRpZmZlcmVuY2VzIGJldHdlZW5cbiAqIGBkb3duZ3JhZGVNb2R1bGUoKWAgYW5kIGBVcGdyYWRlTW9kdWxlYCB0aGF0IGFmZmVjdCB0aGUgYmVoYXZpb3Igb2YgaHlicmlkIGFwcGxpY2F0aW9uczpcbiAqXG4gKiAxLiBVbmxpa2UgYFVwZ3JhZGVNb2R1bGVgLCBgZG93bmdyYWRlTW9kdWxlKClgIGRvZXMgbm90IGJvb3RzdHJhcCB0aGUgbWFpbiBBbmd1bGFySlMgbW9kdWxlXG4gKiAgICBpbnNpZGUgdGhlIHtAbGluayBOZ1pvbmUgQW5ndWxhciB6b25lfS5cbiAqIDIuIFVubGlrZSBgVXBncmFkZU1vZHVsZWAsIGBkb3duZ3JhZGVNb2R1bGUoKWAgZG9lcyBub3QgYXV0b21hdGljYWxseSBydW4gYVxuICogICAgWyRkaWdlc3QoKV0oaHR0cHM6Ly9kb2NzLmFuZ3VsYXJqcy5vcmcvYXBpL25nL3R5cGUvJHJvb3RTY29wZS5TY29wZSMkZGlnZXN0KSB3aGVuIGNoYW5nZXMgYXJlXG4gKiAgICBkZXRlY3RlZCBpbiB0aGUgQW5ndWxhciBwYXJ0IG9mIHRoZSBhcHBsaWNhdGlvbi5cbiAqXG4gKiBXaGF0IHRoaXMgbWVhbnMgaXMgdGhhdCBhcHBsaWNhdGlvbnMgdXNpbmcgYFVwZ3JhZGVNb2R1bGVgIHdpbGwgcnVuIGNoYW5nZSBkZXRlY3Rpb24gbW9yZVxuICogZnJlcXVlbnRseSBpbiBvcmRlciB0byBlbnN1cmUgdGhhdCBib3RoIGZyYW1ld29ya3MgYXJlIHByb3Blcmx5IG5vdGlmaWVkIGFib3V0IHBvc3NpYmxlIGNoYW5nZXMuXG4gKiBUaGlzIHdpbGwgaW5ldml0YWJseSByZXN1bHQgaW4gbW9yZSBjaGFuZ2UgZGV0ZWN0aW9uIHJ1bnMgdGhhbiBuZWNlc3NhcnkuXG4gKlxuICogYGRvd25ncmFkZU1vZHVsZSgpYCwgb24gdGhlIG90aGVyIHNpZGUsIGRvZXMgbm90IHRyeSB0byB0aWUgdGhlIHR3byBjaGFuZ2UgZGV0ZWN0aW9uIHN5c3RlbXMgYXNcbiAqIHRpZ2h0bHksIHJlc3RyaWN0aW5nIHRoZSBleHBsaWNpdCBjaGFuZ2UgZGV0ZWN0aW9uIHJ1bnMgb25seSB0byBjYXNlcyB3aGVyZSBpdCBrbm93cyBpdCBpc1xuICogbmVjZXNzYXJ5IChlLmcuIHdoZW4gdGhlIGlucHV0cyBvZiBhIGRvd25ncmFkZWQgY29tcG9uZW50IGNoYW5nZSkuIFRoaXMgaW1wcm92ZXMgcGVyZm9ybWFuY2UsXG4gKiBlc3BlY2lhbGx5IGluIGNoYW5nZS1kZXRlY3Rpb24taGVhdnkgYXBwbGljYXRpb25zLCBidXQgbGVhdmVzIGl0IHVwIHRvIHRoZSBkZXZlbG9wZXIgdG8gbWFudWFsbHlcbiAqIG5vdGlmeSBlYWNoIGZyYW1ld29yayBhcyBuZWVkZWQuXG4gKlxuICogRm9yIGEgbW9yZSBkZXRhaWxlZCBkaXNjdXNzaW9uIG9mIHRoZSBkaWZmZXJlbmNlcyBhbmQgdGhlaXIgaW1wbGljYXRpb25zLCBzZWVcbiAqIFtVcGdyYWRpbmcgZm9yIFBlcmZvcm1hbmNlXShndWlkZS91cGdyYWRlLXBlcmZvcm1hbmNlKS5cbiAqXG4gKiA8ZGl2IGNsYXNzPVwiYWxlcnQgaXMtaGVscGZ1bFwiPlxuICpcbiAqICAgWW91IGNhbiBtYW51YWxseSB0cmlnZ2VyIGEgY2hhbmdlIGRldGVjdGlvbiBydW4gaW4gQW5ndWxhckpTIHVzaW5nXG4gKiAgIFtzY29wZS4kYXBwbHkoLi4uKV0oaHR0cHM6Ly9kb2NzLmFuZ3VsYXJqcy5vcmcvYXBpL25nL3R5cGUvJHJvb3RTY29wZS5TY29wZSMkYXBwbHkpIG9yXG4gKiAgIFskcm9vdFNjb3BlLiRkaWdlc3QoKV0oaHR0cHM6Ly9kb2NzLmFuZ3VsYXJqcy5vcmcvYXBpL25nL3R5cGUvJHJvb3RTY29wZS5TY29wZSMkZGlnZXN0KS5cbiAqXG4gKiAgIFlvdSBjYW4gbWFudWFsbHkgdHJpZ2dlciBhIGNoYW5nZSBkZXRlY3Rpb24gcnVuIGluIEFuZ3VsYXIgdXNpbmcge0BsaW5rIE5nWm9uZSNydW5cbiAqICAgbmdab25lLnJ1biguLi4pfS5cbiAqXG4gKiA8L2Rpdj5cbiAqXG4gKiAjIyMgRG93bmdyYWRpbmcgbXVsdGlwbGUgbW9kdWxlc1xuICpcbiAqIEl0IGlzIHBvc3NpYmxlIHRvIGRvd25ncmFkZSBtdWx0aXBsZSBtb2R1bGVzIGFuZCBpbmNsdWRlIHRoZW0gaW4gYW4gQW5ndWxhckpTIGFwcGxpY2F0aW9uLiBJblxuICogdGhhdCBjYXNlLCBlYWNoIGRvd25ncmFkZWQgbW9kdWxlIHdpbGwgYmUgYm9vdHN0cmFwcGVkIHdoZW4gYW4gYXNzb2NpYXRlZCBkb3duZ3JhZGVkIGNvbXBvbmVudCBvclxuICogaW5qZWN0YWJsZSBuZWVkcyB0byBiZSBpbnN0YW50aWF0ZWQuXG4gKlxuICogVGhpbmdzIHRvIGtlZXAgaW4gbWluZCwgd2hlbiBkb3duZ3JhZGluZyBtdWx0aXBsZSBtb2R1bGVzOlxuICpcbiAqIC0gRWFjaCBkb3duZ3JhZGVkIGNvbXBvbmVudC9pbmplY3RhYmxlIG5lZWRzIHRvIGJlIGV4cGxpY2l0bHkgYXNzb2NpYXRlZCB3aXRoIGEgZG93bmdyYWRlZFxuICogICBtb2R1bGUuIFNlZSBgZG93bmdyYWRlQ29tcG9uZW50KClgIGFuZCBgZG93bmdyYWRlSW5qZWN0YWJsZSgpYCBmb3IgbW9yZSBkZXRhaWxzLlxuICpcbiAqIC0gSWYgeW91IHdhbnQgc29tZSBpbmplY3RhYmxlcyB0byBiZSBzaGFyZWQgYW1vbmcgYWxsIGRvd25ncmFkZWQgbW9kdWxlcywgeW91IGNhbiBwcm92aWRlIHRoZW0gYXNcbiAqICAgYFN0YXRpY1Byb3ZpZGVyYHMsIHdoZW4gY3JlYXRpbmcgdGhlIGBQbGF0Zm9ybVJlZmAgKGUuZy4gdmlhIGBwbGF0Zm9ybUJyb3dzZXJgIG9yXG4gKiAgIGBwbGF0Zm9ybUJyb3dzZXJEeW5hbWljYCkuXG4gKlxuICogLSBXaGVuIHVzaW5nIHtAbGluayBQbGF0Zm9ybVJlZiNib290c3RyYXBtb2R1bGUgYGJvb3RzdHJhcE1vZHVsZSgpYH0gb3JcbiAqICAge0BsaW5rIFBsYXRmb3JtUmVmI2Jvb3RzdHJhcG1vZHVsZWZhY3RvcnkgYGJvb3RzdHJhcE1vZHVsZUZhY3RvcnkoKWB9IHRvIGJvb3RzdHJhcCB0aGVcbiAqICAgZG93bmdyYWRlZCBtb2R1bGVzLCBlYWNoIG9uZSBpcyBjb25zaWRlcmVkIGEgXCJyb290XCIgbW9kdWxlLiBBcyBhIGNvbnNlcXVlbmNlLCBhIG5ldyBpbnN0YW5jZVxuICogICB3aWxsIGJlIGNyZWF0ZWQgZm9yIGV2ZXJ5IGluamVjdGFibGUgcHJvdmlkZWQgaW4gYFwicm9vdFwiYCAodmlhXG4gKiAgIHtAbGluayBJbmplY3RhYmxlI3Byb3ZpZGVkSW4gYHByb3ZpZGVkSW5gfSkuXG4gKiAgIElmIHRoaXMgaXMgbm90IHlvdXIgaW50ZW50aW9uLCB5b3UgY2FuIGhhdmUgYSBzaGFyZWQgbW9kdWxlICh0aGF0IHdpbGwgYWN0IGFzIGFjdCBhcyB0aGUgXCJyb290XCJcbiAqICAgbW9kdWxlKSBhbmQgY3JlYXRlIGFsbCBkb3duZ3JhZGVkIG1vZHVsZXMgdXNpbmcgdGhhdCBtb2R1bGUncyBpbmplY3RvcjpcbiAqXG4gKiAgIHtAZXhhbXBsZSB1cGdyYWRlL3N0YXRpYy90cy9saXRlLW11bHRpLXNoYXJlZC9tb2R1bGUudHMgcmVnaW9uPVwic2hhcmVkLXJvb3QtbW9kdWxlXCJ9XG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgZnVuY3Rpb24gZG93bmdyYWRlTW9kdWxlPFQ+KG1vZHVsZU9yQm9vdHN0cmFwRm46IFR5cGU8VD58KFxuICAgIChleHRyYVByb3ZpZGVyczogU3RhdGljUHJvdmlkZXJbXSkgPT4gUHJvbWlzZTxOZ01vZHVsZVJlZjxUPj4pKTogc3RyaW5nO1xuLyoqXG4gKiBAZGVzY3JpcHRpb25cbiAqXG4gKiBBIGhlbHBlciBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgYW4gQW5ndWxhckpTIG1vZHVsZSB0aGF0IGNhbiBib290c3RyYXAgYW4gQW5ndWxhciBtb2R1bGVcbiAqIFwib24tZGVtYW5kXCIgKHBvc3NpYmx5IGxhemlseSkgd2hlbiBhIHtAbGluayBkb3duZ3JhZGVDb21wb25lbnQgZG93bmdyYWRlZCBjb21wb25lbnR9IG5lZWRzIHRvIGJlXG4gKiBpbnN0YW50aWF0ZWQuXG4gKlxuICogKlBhcnQgb2YgdGhlIFt1cGdyYWRlL3N0YXRpY10oYXBpP3F1ZXJ5PXVwZ3JhZGUvc3RhdGljKSBsaWJyYXJ5IGZvciBoeWJyaWQgdXBncmFkZSBhcHBzIHRoYXRcbiAqIHN1cHBvcnQgQU9UIGNvbXBpbGF0aW9uLipcbiAqXG4gKiBJdCBhbGxvd3MgbG9hZGluZy9ib290c3RyYXBwaW5nIHRoZSBBbmd1bGFyIHBhcnQgb2YgYSBoeWJyaWQgYXBwbGljYXRpb24gbGF6aWx5IGFuZCBub3QgaGF2aW5nIHRvXG4gKiBwYXkgdGhlIGNvc3QgdXAtZnJvbnQuIEZvciBleGFtcGxlLCB5b3UgY2FuIGhhdmUgYW4gQW5ndWxhckpTIGFwcGxpY2F0aW9uIHRoYXQgdXNlcyBBbmd1bGFyIGZvclxuICogc3BlY2lmaWMgcm91dGVzIGFuZCBvbmx5IGluc3RhbnRpYXRlIHRoZSBBbmd1bGFyIG1vZHVsZXMgaWYvd2hlbiB0aGUgdXNlciB2aXNpdHMgb25lIG9mIHRoZXNlXG4gKiByb3V0ZXMuXG4gKlxuICogVGhlIEFuZ3VsYXIgbW9kdWxlIHdpbGwgYmUgYm9vdHN0cmFwcGVkIG9uY2UgKHdoZW4gcmVxdWVzdGVkIGZvciB0aGUgZmlyc3QgdGltZSkgYW5kIHRoZSBzYW1lXG4gKiByZWZlcmVuY2Ugd2lsbCBiZSB1c2VkIGZyb20gdGhhdCBwb2ludCBvbndhcmRzLlxuICpcbiAqIGBkb3duZ3JhZGVNb2R1bGUoKWAgcmVxdWlyZXMgZWl0aGVyIGFuIGBOZ01vZHVsZUZhY3RvcnlgLCBgTmdNb2R1bGVgIGNsYXNzIG9yIGEgZnVuY3Rpb246XG4gKiAtIGBOZ01vZHVsZUZhY3RvcnlgOiBJZiB5b3UgcGFzcyBhbiBgTmdNb2R1bGVGYWN0b3J5YCwgaXQgd2lsbCBiZSB1c2VkIHRvIGluc3RhbnRpYXRlIGEgbW9kdWxlXG4gKiAgIHVzaW5nIGBwbGF0Zm9ybUJyb3dzZXJgJ3Mge0BsaW5rIFBsYXRmb3JtUmVmI2Jvb3RzdHJhcE1vZHVsZUZhY3RvcnkgYm9vdHN0cmFwTW9kdWxlRmFjdG9yeSgpfS5cbiAqICAgTk9URTogdGhpcyB0eXBlIG9mIHRoZSBhcmd1bWVudCBpcyBkZXByZWNhdGVkLiBQbGVhc2UgZWl0aGVyIHByb3ZpZGUgYW4gYE5nTW9kdWxlYCBjbGFzcyBvciBhXG4gKiAgIGJvb3RzdHJhcCBmdW5jdGlvbiBpbnN0ZWFkLlxuICogLSBgTmdNb2R1bGVgIGNsYXNzOiBJZiB5b3UgcGFzcyBhbiBOZ01vZHVsZSBjbGFzcywgaXQgd2lsbCBiZSB1c2VkIHRvIGluc3RhbnRpYXRlIGEgbW9kdWxlXG4gKiAgIHVzaW5nIGBwbGF0Zm9ybUJyb3dzZXJgJ3Mge0BsaW5rIFBsYXRmb3JtUmVmI2Jvb3RzdHJhcE1vZHVsZSBib290c3RyYXBNb2R1bGUoKX0uXG4gKiAtIGBGdW5jdGlvbmA6IElmIHlvdSBwYXNzIGEgZnVuY3Rpb24sIGl0IGlzIGV4cGVjdGVkIHRvIHJldHVybiBhIHByb21pc2UgcmVzb2x2aW5nIHRvIGFuXG4gKiAgIGBOZ01vZHVsZVJlZmAuIFRoZSBmdW5jdGlvbiBpcyBjYWxsZWQgd2l0aCBhbiBhcnJheSBvZiBleHRyYSB7QGxpbmsgU3RhdGljUHJvdmlkZXIgUHJvdmlkZXJzfVxuICogICB0aGF0IGFyZSBleHBlY3RlZCB0byBiZSBhdmFpbGFibGUgZnJvbSB0aGUgcmV0dXJuZWQgYE5nTW9kdWxlUmVmYCdzIGBJbmplY3RvcmAuXG4gKlxuICogYGRvd25ncmFkZU1vZHVsZSgpYCByZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSBjcmVhdGVkIEFuZ3VsYXJKUyB3cmFwcGVyIG1vZHVsZS4gWW91IGNhbiB1c2UgaXQgdG9cbiAqIGRlY2xhcmUgYSBkZXBlbmRlbmN5IGluIHlvdXIgbWFpbiBBbmd1bGFySlMgbW9kdWxlLlxuICpcbiAqIHtAZXhhbXBsZSB1cGdyYWRlL3N0YXRpYy90cy9saXRlL21vZHVsZS50cyByZWdpb249XCJiYXNpYy1ob3ctdG9cIn1cbiAqXG4gKiBGb3IgbW9yZSBkZXRhaWxzIG9uIGhvdyB0byB1c2UgYGRvd25ncmFkZU1vZHVsZSgpYCBzZWVcbiAqIFtVcGdyYWRpbmcgZm9yIFBlcmZvcm1hbmNlXShndWlkZS91cGdyYWRlLXBlcmZvcm1hbmNlKS5cbiAqXG4gKiBAdXNhZ2VOb3Rlc1xuICpcbiAqIEFwYXJ0IGZyb20gYFVwZ3JhZGVNb2R1bGVgLCB5b3UgY2FuIHVzZSB0aGUgcmVzdCBvZiB0aGUgYHVwZ3JhZGUvc3RhdGljYCBoZWxwZXJzIGFzIHVzdWFsIHRvXG4gKiBidWlsZCBhIGh5YnJpZCBhcHBsaWNhdGlvbi4gTm90ZSB0aGF0IHRoZSBBbmd1bGFyIHBpZWNlcyAoZS5nLiBkb3duZ3JhZGVkIHNlcnZpY2VzKSB3aWxsIG5vdCBiZVxuICogYXZhaWxhYmxlIHVudGlsIHRoZSBkb3duZ3JhZGVkIG1vZHVsZSBoYXMgYmVlbiBib290c3RyYXBwZWQsIGkuZS4gYnkgaW5zdGFudGlhdGluZyBhIGRvd25ncmFkZWRcbiAqIGNvbXBvbmVudC5cbiAqXG4gKiA8ZGl2IGNsYXNzPVwiYWxlcnQgaXMtaW1wb3J0YW50XCI+XG4gKlxuICogICBZb3UgY2Fubm90IHVzZSBgZG93bmdyYWRlTW9kdWxlKClgIGFuZCBgVXBncmFkZU1vZHVsZWAgaW4gdGhlIHNhbWUgaHlicmlkIGFwcGxpY2F0aW9uLjxiciAvPlxuICogICBVc2Ugb25lIG9yIHRoZSBvdGhlci5cbiAqXG4gKiA8L2Rpdj5cbiAqXG4gKiAjIyMgRGlmZmVyZW5jZXMgd2l0aCBgVXBncmFkZU1vZHVsZWBcbiAqXG4gKiBCZXNpZGVzIHRoZWlyIGRpZmZlcmVudCBBUEksIHRoZXJlIGFyZSB0d28gaW1wb3J0YW50IGludGVybmFsIGRpZmZlcmVuY2VzIGJldHdlZW5cbiAqIGBkb3duZ3JhZGVNb2R1bGUoKWAgYW5kIGBVcGdyYWRlTW9kdWxlYCB0aGF0IGFmZmVjdCB0aGUgYmVoYXZpb3Igb2YgaHlicmlkIGFwcGxpY2F0aW9uczpcbiAqXG4gKiAxLiBVbmxpa2UgYFVwZ3JhZGVNb2R1bGVgLCBgZG93bmdyYWRlTW9kdWxlKClgIGRvZXMgbm90IGJvb3RzdHJhcCB0aGUgbWFpbiBBbmd1bGFySlMgbW9kdWxlXG4gKiAgICBpbnNpZGUgdGhlIHtAbGluayBOZ1pvbmUgQW5ndWxhciB6b25lfS5cbiAqIDIuIFVubGlrZSBgVXBncmFkZU1vZHVsZWAsIGBkb3duZ3JhZGVNb2R1bGUoKWAgZG9lcyBub3QgYXV0b21hdGljYWxseSBydW4gYVxuICogICAgWyRkaWdlc3QoKV0oaHR0cHM6Ly9kb2NzLmFuZ3VsYXJqcy5vcmcvYXBpL25nL3R5cGUvJHJvb3RTY29wZS5TY29wZSMkZGlnZXN0KSB3aGVuIGNoYW5nZXMgYXJlXG4gKiAgICBkZXRlY3RlZCBpbiB0aGUgQW5ndWxhciBwYXJ0IG9mIHRoZSBhcHBsaWNhdGlvbi5cbiAqXG4gKiBXaGF0IHRoaXMgbWVhbnMgaXMgdGhhdCBhcHBsaWNhdGlvbnMgdXNpbmcgYFVwZ3JhZGVNb2R1bGVgIHdpbGwgcnVuIGNoYW5nZSBkZXRlY3Rpb24gbW9yZVxuICogZnJlcXVlbnRseSBpbiBvcmRlciB0byBlbnN1cmUgdGhhdCBib3RoIGZyYW1ld29ya3MgYXJlIHByb3Blcmx5IG5vdGlmaWVkIGFib3V0IHBvc3NpYmxlIGNoYW5nZXMuXG4gKiBUaGlzIHdpbGwgaW5ldml0YWJseSByZXN1bHQgaW4gbW9yZSBjaGFuZ2UgZGV0ZWN0aW9uIHJ1bnMgdGhhbiBuZWNlc3NhcnkuXG4gKlxuICogYGRvd25ncmFkZU1vZHVsZSgpYCwgb24gdGhlIG90aGVyIHNpZGUsIGRvZXMgbm90IHRyeSB0byB0aWUgdGhlIHR3byBjaGFuZ2UgZGV0ZWN0aW9uIHN5c3RlbXMgYXNcbiAqIHRpZ2h0bHksIHJlc3RyaWN0aW5nIHRoZSBleHBsaWNpdCBjaGFuZ2UgZGV0ZWN0aW9uIHJ1bnMgb25seSB0byBjYXNlcyB3aGVyZSBpdCBrbm93cyBpdCBpc1xuICogbmVjZXNzYXJ5IChlLmcuIHdoZW4gdGhlIGlucHV0cyBvZiBhIGRvd25ncmFkZWQgY29tcG9uZW50IGNoYW5nZSkuIFRoaXMgaW1wcm92ZXMgcGVyZm9ybWFuY2UsXG4gKiBlc3BlY2lhbGx5IGluIGNoYW5nZS1kZXRlY3Rpb24taGVhdnkgYXBwbGljYXRpb25zLCBidXQgbGVhdmVzIGl0IHVwIHRvIHRoZSBkZXZlbG9wZXIgdG8gbWFudWFsbHlcbiAqIG5vdGlmeSBlYWNoIGZyYW1ld29yayBhcyBuZWVkZWQuXG4gKlxuICogRm9yIGEgbW9yZSBkZXRhaWxlZCBkaXNjdXNzaW9uIG9mIHRoZSBkaWZmZXJlbmNlcyBhbmQgdGhlaXIgaW1wbGljYXRpb25zLCBzZWVcbiAqIFtVcGdyYWRpbmcgZm9yIFBlcmZvcm1hbmNlXShndWlkZS91cGdyYWRlLXBlcmZvcm1hbmNlKS5cbiAqXG4gKiA8ZGl2IGNsYXNzPVwiYWxlcnQgaXMtaGVscGZ1bFwiPlxuICpcbiAqICAgWW91IGNhbiBtYW51YWxseSB0cmlnZ2VyIGEgY2hhbmdlIGRldGVjdGlvbiBydW4gaW4gQW5ndWxhckpTIHVzaW5nXG4gKiAgIFtzY29wZS4kYXBwbHkoLi4uKV0oaHR0cHM6Ly9kb2NzLmFuZ3VsYXJqcy5vcmcvYXBpL25nL3R5cGUvJHJvb3RTY29wZS5TY29wZSMkYXBwbHkpIG9yXG4gKiAgIFskcm9vdFNjb3BlLiRkaWdlc3QoKV0oaHR0cHM6Ly9kb2NzLmFuZ3VsYXJqcy5vcmcvYXBpL25nL3R5cGUvJHJvb3RTY29wZS5TY29wZSMkZGlnZXN0KS5cbiAqXG4gKiAgIFlvdSBjYW4gbWFudWFsbHkgdHJpZ2dlciBhIGNoYW5nZSBkZXRlY3Rpb24gcnVuIGluIEFuZ3VsYXIgdXNpbmcge0BsaW5rIE5nWm9uZSNydW5cbiAqICAgbmdab25lLnJ1biguLi4pfS5cbiAqXG4gKiA8L2Rpdj5cbiAqXG4gKiAjIyMgRG93bmdyYWRpbmcgbXVsdGlwbGUgbW9kdWxlc1xuICpcbiAqIEl0IGlzIHBvc3NpYmxlIHRvIGRvd25ncmFkZSBtdWx0aXBsZSBtb2R1bGVzIGFuZCBpbmNsdWRlIHRoZW0gaW4gYW4gQW5ndWxhckpTIGFwcGxpY2F0aW9uLiBJblxuICogdGhhdCBjYXNlLCBlYWNoIGRvd25ncmFkZWQgbW9kdWxlIHdpbGwgYmUgYm9vdHN0cmFwcGVkIHdoZW4gYW4gYXNzb2NpYXRlZCBkb3duZ3JhZGVkIGNvbXBvbmVudCBvclxuICogaW5qZWN0YWJsZSBuZWVkcyB0byBiZSBpbnN0YW50aWF0ZWQuXG4gKlxuICogVGhpbmdzIHRvIGtlZXAgaW4gbWluZCwgd2hlbiBkb3duZ3JhZGluZyBtdWx0aXBsZSBtb2R1bGVzOlxuICpcbiAqIC0gRWFjaCBkb3duZ3JhZGVkIGNvbXBvbmVudC9pbmplY3RhYmxlIG5lZWRzIHRvIGJlIGV4cGxpY2l0bHkgYXNzb2NpYXRlZCB3aXRoIGEgZG93bmdyYWRlZFxuICogICBtb2R1bGUuIFNlZSBgZG93bmdyYWRlQ29tcG9uZW50KClgIGFuZCBgZG93bmdyYWRlSW5qZWN0YWJsZSgpYCBmb3IgbW9yZSBkZXRhaWxzLlxuICpcbiAqIC0gSWYgeW91IHdhbnQgc29tZSBpbmplY3RhYmxlcyB0byBiZSBzaGFyZWQgYW1vbmcgYWxsIGRvd25ncmFkZWQgbW9kdWxlcywgeW91IGNhbiBwcm92aWRlIHRoZW0gYXNcbiAqICAgYFN0YXRpY1Byb3ZpZGVyYHMsIHdoZW4gY3JlYXRpbmcgdGhlIGBQbGF0Zm9ybVJlZmAgKGUuZy4gdmlhIGBwbGF0Zm9ybUJyb3dzZXJgIG9yXG4gKiAgIGBwbGF0Zm9ybUJyb3dzZXJEeW5hbWljYCkuXG4gKlxuICogLSBXaGVuIHVzaW5nIHtAbGluayBQbGF0Zm9ybVJlZiNib290c3RyYXBtb2R1bGUgYGJvb3RzdHJhcE1vZHVsZSgpYH0gb3JcbiAqICAge0BsaW5rIFBsYXRmb3JtUmVmI2Jvb3RzdHJhcG1vZHVsZWZhY3RvcnkgYGJvb3RzdHJhcE1vZHVsZUZhY3RvcnkoKWB9IHRvIGJvb3RzdHJhcCB0aGVcbiAqICAgZG93bmdyYWRlZCBtb2R1bGVzLCBlYWNoIG9uZSBpcyBjb25zaWRlcmVkIGEgXCJyb290XCIgbW9kdWxlLiBBcyBhIGNvbnNlcXVlbmNlLCBhIG5ldyBpbnN0YW5jZVxuICogICB3aWxsIGJlIGNyZWF0ZWQgZm9yIGV2ZXJ5IGluamVjdGFibGUgcHJvdmlkZWQgaW4gYFwicm9vdFwiYCAodmlhXG4gKiAgIHtAbGluayBJbmplY3RhYmxlI3Byb3ZpZGVkSW4gYHByb3ZpZGVkSW5gfSkuXG4gKiAgIElmIHRoaXMgaXMgbm90IHlvdXIgaW50ZW50aW9uLCB5b3UgY2FuIGhhdmUgYSBzaGFyZWQgbW9kdWxlICh0aGF0IHdpbGwgYWN0IGFzIGFjdCBhcyB0aGUgXCJyb290XCJcbiAqICAgbW9kdWxlKSBhbmQgY3JlYXRlIGFsbCBkb3duZ3JhZGVkIG1vZHVsZXMgdXNpbmcgdGhhdCBtb2R1bGUncyBpbmplY3RvcjpcbiAqXG4gKiAgIHtAZXhhbXBsZSB1cGdyYWRlL3N0YXRpYy90cy9saXRlLW11bHRpLXNoYXJlZC9tb2R1bGUudHMgcmVnaW9uPVwic2hhcmVkLXJvb3QtbW9kdWxlXCJ9XG4gKlxuICogQHB1YmxpY0FwaVxuICpcbiAqIEBkZXByZWNhdGVkIFBhc3NpbmcgYE5nTW9kdWxlRmFjdG9yeWAgYXMgdGhlIGBkb3duZ3JhZGVNb2R1bGVgIGZ1bmN0aW9uIGFyZ3VtZW50IGlzIGRlcHJlY2F0ZWQsXG4gKiAgICAgcGxlYXNlIHBhc3MgYW4gTmdNb2R1bGUgY2xhc3MgcmVmZXJlbmNlIGluc3RlYWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkb3duZ3JhZGVNb2R1bGU8VD4obW9kdWxlT3JCb290c3RyYXBGbjogTmdNb2R1bGVGYWN0b3J5PFQ+KTogc3RyaW5nO1xuLyoqXG4gKiBAZGVzY3JpcHRpb25cbiAqXG4gKiBBIGhlbHBlciBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgYW4gQW5ndWxhckpTIG1vZHVsZSB0aGF0IGNhbiBib290c3RyYXAgYW4gQW5ndWxhciBtb2R1bGVcbiAqIFwib24tZGVtYW5kXCIgKHBvc3NpYmx5IGxhemlseSkgd2hlbiBhIHtAbGluayBkb3duZ3JhZGVDb21wb25lbnQgZG93bmdyYWRlZCBjb21wb25lbnR9IG5lZWRzIHRvIGJlXG4gKiBpbnN0YW50aWF0ZWQuXG4gKlxuICogKlBhcnQgb2YgdGhlIFt1cGdyYWRlL3N0YXRpY10oYXBpP3F1ZXJ5PXVwZ3JhZGUvc3RhdGljKSBsaWJyYXJ5IGZvciBoeWJyaWQgdXBncmFkZSBhcHBzIHRoYXRcbiAqIHN1cHBvcnQgQU9UIGNvbXBpbGF0aW9uLipcbiAqXG4gKiBJdCBhbGxvd3MgbG9hZGluZy9ib290c3RyYXBwaW5nIHRoZSBBbmd1bGFyIHBhcnQgb2YgYSBoeWJyaWQgYXBwbGljYXRpb24gbGF6aWx5IGFuZCBub3QgaGF2aW5nIHRvXG4gKiBwYXkgdGhlIGNvc3QgdXAtZnJvbnQuIEZvciBleGFtcGxlLCB5b3UgY2FuIGhhdmUgYW4gQW5ndWxhckpTIGFwcGxpY2F0aW9uIHRoYXQgdXNlcyBBbmd1bGFyIGZvclxuICogc3BlY2lmaWMgcm91dGVzIGFuZCBvbmx5IGluc3RhbnRpYXRlIHRoZSBBbmd1bGFyIG1vZHVsZXMgaWYvd2hlbiB0aGUgdXNlciB2aXNpdHMgb25lIG9mIHRoZXNlXG4gKiByb3V0ZXMuXG4gKlxuICogVGhlIEFuZ3VsYXIgbW9kdWxlIHdpbGwgYmUgYm9vdHN0cmFwcGVkIG9uY2UgKHdoZW4gcmVxdWVzdGVkIGZvciB0aGUgZmlyc3QgdGltZSkgYW5kIHRoZSBzYW1lXG4gKiByZWZlcmVuY2Ugd2lsbCBiZSB1c2VkIGZyb20gdGhhdCBwb2ludCBvbndhcmRzLlxuICpcbiAqIGBkb3duZ3JhZGVNb2R1bGUoKWAgcmVxdWlyZXMgZWl0aGVyIGFuIGBOZ01vZHVsZUZhY3RvcnlgLCBgTmdNb2R1bGVgIGNsYXNzIG9yIGEgZnVuY3Rpb246XG4gKiAtIGBOZ01vZHVsZUZhY3RvcnlgOiBJZiB5b3UgcGFzcyBhbiBgTmdNb2R1bGVGYWN0b3J5YCwgaXQgd2lsbCBiZSB1c2VkIHRvIGluc3RhbnRpYXRlIGEgbW9kdWxlXG4gKiAgIHVzaW5nIGBwbGF0Zm9ybUJyb3dzZXJgJ3Mge0BsaW5rIFBsYXRmb3JtUmVmI2Jvb3RzdHJhcE1vZHVsZUZhY3RvcnkgYm9vdHN0cmFwTW9kdWxlRmFjdG9yeSgpfS5cbiAqICAgTk9URTogdGhpcyB0eXBlIG9mIHRoZSBhcmd1bWVudCBpcyBkZXByZWNhdGVkLiBQbGVhc2UgZWl0aGVyIHByb3ZpZGUgYW4gYE5nTW9kdWxlYCBjbGFzcyBvciBhXG4gKiAgIGJvb3RzdHJhcCBmdW5jdGlvbiBpbnN0ZWFkLlxuICogLSBgTmdNb2R1bGVgIGNsYXNzOiBJZiB5b3UgcGFzcyBhbiBOZ01vZHVsZSBjbGFzcywgaXQgd2lsbCBiZSB1c2VkIHRvIGluc3RhbnRpYXRlIGEgbW9kdWxlXG4gKiAgIHVzaW5nIGBwbGF0Zm9ybUJyb3dzZXJgJ3Mge0BsaW5rIFBsYXRmb3JtUmVmI2Jvb3RzdHJhcE1vZHVsZSBib290c3RyYXBNb2R1bGUoKX0uXG4gKiAtIGBGdW5jdGlvbmA6IElmIHlvdSBwYXNzIGEgZnVuY3Rpb24sIGl0IGlzIGV4cGVjdGVkIHRvIHJldHVybiBhIHByb21pc2UgcmVzb2x2aW5nIHRvIGFuXG4gKiAgIGBOZ01vZHVsZVJlZmAuIFRoZSBmdW5jdGlvbiBpcyBjYWxsZWQgd2l0aCBhbiBhcnJheSBvZiBleHRyYSB7QGxpbmsgU3RhdGljUHJvdmlkZXIgUHJvdmlkZXJzfVxuICogICB0aGF0IGFyZSBleHBlY3RlZCB0byBiZSBhdmFpbGFibGUgZnJvbSB0aGUgcmV0dXJuZWQgYE5nTW9kdWxlUmVmYCdzIGBJbmplY3RvcmAuXG4gKlxuICogYGRvd25ncmFkZU1vZHVsZSgpYCByZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSBjcmVhdGVkIEFuZ3VsYXJKUyB3cmFwcGVyIG1vZHVsZS4gWW91IGNhbiB1c2UgaXQgdG9cbiAqIGRlY2xhcmUgYSBkZXBlbmRlbmN5IGluIHlvdXIgbWFpbiBBbmd1bGFySlMgbW9kdWxlLlxuICpcbiAqIHtAZXhhbXBsZSB1cGdyYWRlL3N0YXRpYy90cy9saXRlL21vZHVsZS50cyByZWdpb249XCJiYXNpYy1ob3ctdG9cIn1cbiAqXG4gKiBGb3IgbW9yZSBkZXRhaWxzIG9uIGhvdyB0byB1c2UgYGRvd25ncmFkZU1vZHVsZSgpYCBzZWVcbiAqIFtVcGdyYWRpbmcgZm9yIFBlcmZvcm1hbmNlXShndWlkZS91cGdyYWRlLXBlcmZvcm1hbmNlKS5cbiAqXG4gKiBAdXNhZ2VOb3Rlc1xuICpcbiAqIEFwYXJ0IGZyb20gYFVwZ3JhZGVNb2R1bGVgLCB5b3UgY2FuIHVzZSB0aGUgcmVzdCBvZiB0aGUgYHVwZ3JhZGUvc3RhdGljYCBoZWxwZXJzIGFzIHVzdWFsIHRvXG4gKiBidWlsZCBhIGh5YnJpZCBhcHBsaWNhdGlvbi4gTm90ZSB0aGF0IHRoZSBBbmd1bGFyIHBpZWNlcyAoZS5nLiBkb3duZ3JhZGVkIHNlcnZpY2VzKSB3aWxsIG5vdCBiZVxuICogYXZhaWxhYmxlIHVudGlsIHRoZSBkb3duZ3JhZGVkIG1vZHVsZSBoYXMgYmVlbiBib290c3RyYXBwZWQsIGkuZS4gYnkgaW5zdGFudGlhdGluZyBhIGRvd25ncmFkZWRcbiAqIGNvbXBvbmVudC5cbiAqXG4gKiA8ZGl2IGNsYXNzPVwiYWxlcnQgaXMtaW1wb3J0YW50XCI+XG4gKlxuICogICBZb3UgY2Fubm90IHVzZSBgZG93bmdyYWRlTW9kdWxlKClgIGFuZCBgVXBncmFkZU1vZHVsZWAgaW4gdGhlIHNhbWUgaHlicmlkIGFwcGxpY2F0aW9uLjxiciAvPlxuICogICBVc2Ugb25lIG9yIHRoZSBvdGhlci5cbiAqXG4gKiA8L2Rpdj5cbiAqXG4gKiAjIyMgRGlmZmVyZW5jZXMgd2l0aCBgVXBncmFkZU1vZHVsZWBcbiAqXG4gKiBCZXNpZGVzIHRoZWlyIGRpZmZlcmVudCBBUEksIHRoZXJlIGFyZSB0d28gaW1wb3J0YW50IGludGVybmFsIGRpZmZlcmVuY2VzIGJldHdlZW5cbiAqIGBkb3duZ3JhZGVNb2R1bGUoKWAgYW5kIGBVcGdyYWRlTW9kdWxlYCB0aGF0IGFmZmVjdCB0aGUgYmVoYXZpb3Igb2YgaHlicmlkIGFwcGxpY2F0aW9uczpcbiAqXG4gKiAxLiBVbmxpa2UgYFVwZ3JhZGVNb2R1bGVgLCBgZG93bmdyYWRlTW9kdWxlKClgIGRvZXMgbm90IGJvb3RzdHJhcCB0aGUgbWFpbiBBbmd1bGFySlMgbW9kdWxlXG4gKiAgICBpbnNpZGUgdGhlIHtAbGluayBOZ1pvbmUgQW5ndWxhciB6b25lfS5cbiAqIDIuIFVubGlrZSBgVXBncmFkZU1vZHVsZWAsIGBkb3duZ3JhZGVNb2R1bGUoKWAgZG9lcyBub3QgYXV0b21hdGljYWxseSBydW4gYVxuICogICAgWyRkaWdlc3QoKV0oaHR0cHM6Ly9kb2NzLmFuZ3VsYXJqcy5vcmcvYXBpL25nL3R5cGUvJHJvb3RTY29wZS5TY29wZSMkZGlnZXN0KSB3aGVuIGNoYW5nZXMgYXJlXG4gKiAgICBkZXRlY3RlZCBpbiB0aGUgQW5ndWxhciBwYXJ0IG9mIHRoZSBhcHBsaWNhdGlvbi5cbiAqXG4gKiBXaGF0IHRoaXMgbWVhbnMgaXMgdGhhdCBhcHBsaWNhdGlvbnMgdXNpbmcgYFVwZ3JhZGVNb2R1bGVgIHdpbGwgcnVuIGNoYW5nZSBkZXRlY3Rpb24gbW9yZVxuICogZnJlcXVlbnRseSBpbiBvcmRlciB0byBlbnN1cmUgdGhhdCBib3RoIGZyYW1ld29ya3MgYXJlIHByb3Blcmx5IG5vdGlmaWVkIGFib3V0IHBvc3NpYmxlIGNoYW5nZXMuXG4gKiBUaGlzIHdpbGwgaW5ldml0YWJseSByZXN1bHQgaW4gbW9yZSBjaGFuZ2UgZGV0ZWN0aW9uIHJ1bnMgdGhhbiBuZWNlc3NhcnkuXG4gKlxuICogYGRvd25ncmFkZU1vZHVsZSgpYCwgb24gdGhlIG90aGVyIHNpZGUsIGRvZXMgbm90IHRyeSB0byB0aWUgdGhlIHR3byBjaGFuZ2UgZGV0ZWN0aW9uIHN5c3RlbXMgYXNcbiAqIHRpZ2h0bHksIHJlc3RyaWN0aW5nIHRoZSBleHBsaWNpdCBjaGFuZ2UgZGV0ZWN0aW9uIHJ1bnMgb25seSB0byBjYXNlcyB3aGVyZSBpdCBrbm93cyBpdCBpc1xuICogbmVjZXNzYXJ5IChlLmcuIHdoZW4gdGhlIGlucHV0cyBvZiBhIGRvd25ncmFkZWQgY29tcG9uZW50IGNoYW5nZSkuIFRoaXMgaW1wcm92ZXMgcGVyZm9ybWFuY2UsXG4gKiBlc3BlY2lhbGx5IGluIGNoYW5nZS1kZXRlY3Rpb24taGVhdnkgYXBwbGljYXRpb25zLCBidXQgbGVhdmVzIGl0IHVwIHRvIHRoZSBkZXZlbG9wZXIgdG8gbWFudWFsbHlcbiAqIG5vdGlmeSBlYWNoIGZyYW1ld29yayBhcyBuZWVkZWQuXG4gKlxuICogRm9yIGEgbW9yZSBkZXRhaWxlZCBkaXNjdXNzaW9uIG9mIHRoZSBkaWZmZXJlbmNlcyBhbmQgdGhlaXIgaW1wbGljYXRpb25zLCBzZWVcbiAqIFtVcGdyYWRpbmcgZm9yIFBlcmZvcm1hbmNlXShndWlkZS91cGdyYWRlLXBlcmZvcm1hbmNlKS5cbiAqXG4gKiA8ZGl2IGNsYXNzPVwiYWxlcnQgaXMtaGVscGZ1bFwiPlxuICpcbiAqICAgWW91IGNhbiBtYW51YWxseSB0cmlnZ2VyIGEgY2hhbmdlIGRldGVjdGlvbiBydW4gaW4gQW5ndWxhckpTIHVzaW5nXG4gKiAgIFtzY29wZS4kYXBwbHkoLi4uKV0oaHR0cHM6Ly9kb2NzLmFuZ3VsYXJqcy5vcmcvYXBpL25nL3R5cGUvJHJvb3RTY29wZS5TY29wZSMkYXBwbHkpIG9yXG4gKiAgIFskcm9vdFNjb3BlLiRkaWdlc3QoKV0oaHR0cHM6Ly9kb2NzLmFuZ3VsYXJqcy5vcmcvYXBpL25nL3R5cGUvJHJvb3RTY29wZS5TY29wZSMkZGlnZXN0KS5cbiAqXG4gKiAgIFlvdSBjYW4gbWFudWFsbHkgdHJpZ2dlciBhIGNoYW5nZSBkZXRlY3Rpb24gcnVuIGluIEFuZ3VsYXIgdXNpbmcge0BsaW5rIE5nWm9uZSNydW5cbiAqICAgbmdab25lLnJ1biguLi4pfS5cbiAqXG4gKiA8L2Rpdj5cbiAqXG4gKiAjIyMgRG93bmdyYWRpbmcgbXVsdGlwbGUgbW9kdWxlc1xuICpcbiAqIEl0IGlzIHBvc3NpYmxlIHRvIGRvd25ncmFkZSBtdWx0aXBsZSBtb2R1bGVzIGFuZCBpbmNsdWRlIHRoZW0gaW4gYW4gQW5ndWxhckpTIGFwcGxpY2F0aW9uLiBJblxuICogdGhhdCBjYXNlLCBlYWNoIGRvd25ncmFkZWQgbW9kdWxlIHdpbGwgYmUgYm9vdHN0cmFwcGVkIHdoZW4gYW4gYXNzb2NpYXRlZCBkb3duZ3JhZGVkIGNvbXBvbmVudCBvclxuICogaW5qZWN0YWJsZSBuZWVkcyB0byBiZSBpbnN0YW50aWF0ZWQuXG4gKlxuICogVGhpbmdzIHRvIGtlZXAgaW4gbWluZCwgd2hlbiBkb3duZ3JhZGluZyBtdWx0aXBsZSBtb2R1bGVzOlxuICpcbiAqIC0gRWFjaCBkb3duZ3JhZGVkIGNvbXBvbmVudC9pbmplY3RhYmxlIG5lZWRzIHRvIGJlIGV4cGxpY2l0bHkgYXNzb2NpYXRlZCB3aXRoIGEgZG93bmdyYWRlZFxuICogICBtb2R1bGUuIFNlZSBgZG93bmdyYWRlQ29tcG9uZW50KClgIGFuZCBgZG93bmdyYWRlSW5qZWN0YWJsZSgpYCBmb3IgbW9yZSBkZXRhaWxzLlxuICpcbiAqIC0gSWYgeW91IHdhbnQgc29tZSBpbmplY3RhYmxlcyB0byBiZSBzaGFyZWQgYW1vbmcgYWxsIGRvd25ncmFkZWQgbW9kdWxlcywgeW91IGNhbiBwcm92aWRlIHRoZW0gYXNcbiAqICAgYFN0YXRpY1Byb3ZpZGVyYHMsIHdoZW4gY3JlYXRpbmcgdGhlIGBQbGF0Zm9ybVJlZmAgKGUuZy4gdmlhIGBwbGF0Zm9ybUJyb3dzZXJgIG9yXG4gKiAgIGBwbGF0Zm9ybUJyb3dzZXJEeW5hbWljYCkuXG4gKlxuICogLSBXaGVuIHVzaW5nIHtAbGluayBQbGF0Zm9ybVJlZiNib290c3RyYXBtb2R1bGUgYGJvb3RzdHJhcE1vZHVsZSgpYH0gb3JcbiAqICAge0BsaW5rIFBsYXRmb3JtUmVmI2Jvb3RzdHJhcG1vZHVsZWZhY3RvcnkgYGJvb3RzdHJhcE1vZHVsZUZhY3RvcnkoKWB9IHRvIGJvb3RzdHJhcCB0aGVcbiAqICAgZG93bmdyYWRlZCBtb2R1bGVzLCBlYWNoIG9uZSBpcyBjb25zaWRlcmVkIGEgXCJyb290XCIgbW9kdWxlLiBBcyBhIGNvbnNlcXVlbmNlLCBhIG5ldyBpbnN0YW5jZVxuICogICB3aWxsIGJlIGNyZWF0ZWQgZm9yIGV2ZXJ5IGluamVjdGFibGUgcHJvdmlkZWQgaW4gYFwicm9vdFwiYCAodmlhXG4gKiAgIHtAbGluayBJbmplY3RhYmxlI3Byb3ZpZGVkSW4gYHByb3ZpZGVkSW5gfSkuXG4gKiAgIElmIHRoaXMgaXMgbm90IHlvdXIgaW50ZW50aW9uLCB5b3UgY2FuIGhhdmUgYSBzaGFyZWQgbW9kdWxlICh0aGF0IHdpbGwgYWN0IGFzIGFjdCBhcyB0aGUgXCJyb290XCJcbiAqICAgbW9kdWxlKSBhbmQgY3JlYXRlIGFsbCBkb3duZ3JhZGVkIG1vZHVsZXMgdXNpbmcgdGhhdCBtb2R1bGUncyBpbmplY3RvcjpcbiAqXG4gKiAgIHtAZXhhbXBsZSB1cGdyYWRlL3N0YXRpYy90cy9saXRlLW11bHRpLXNoYXJlZC9tb2R1bGUudHMgcmVnaW9uPVwic2hhcmVkLXJvb3QtbW9kdWxlXCJ9XG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgZnVuY3Rpb24gZG93bmdyYWRlTW9kdWxlPFQ+KG1vZHVsZU9yQm9vdHN0cmFwRm46IFR5cGU8VD58TmdNb2R1bGVGYWN0b3J5PFQ+fChcbiAgICAoZXh0cmFQcm92aWRlcnM6IFN0YXRpY1Byb3ZpZGVyW10pID0+IFByb21pc2U8TmdNb2R1bGVSZWY8VD4+KSk6IHN0cmluZyB7XG4gIGNvbnN0IGxhenlNb2R1bGVOYW1lID0gYCR7VVBHUkFERV9NT0RVTEVfTkFNRX0ubGF6eSR7Kyttb2R1bGVVaWR9YDtcbiAgY29uc3QgbGF6eU1vZHVsZVJlZktleSA9IGAke0xBWllfTU9EVUxFX1JFRn0ke2xhenlNb2R1bGVOYW1lfWA7XG4gIGNvbnN0IGxhenlJbmplY3RvcktleSA9IGAke0lOSkVDVE9SX0tFWX0ke2xhenlNb2R1bGVOYW1lfWA7XG5cbiAgbGV0IGJvb3RzdHJhcEZuOiAoZXh0cmFQcm92aWRlcnM6IFN0YXRpY1Byb3ZpZGVyW10pID0+IFByb21pc2U8TmdNb2R1bGVSZWY8VD4+O1xuICBpZiAoaXNOZ01vZHVsZVR5cGUobW9kdWxlT3JCb290c3RyYXBGbikpIHtcbiAgICAvLyBOZ01vZHVsZSBjbGFzc1xuICAgIGJvb3RzdHJhcEZuID0gKGV4dHJhUHJvdmlkZXJzOiBTdGF0aWNQcm92aWRlcltdKSA9PlxuICAgICAgICBwbGF0Zm9ybUJyb3dzZXIoZXh0cmFQcm92aWRlcnMpLmJvb3RzdHJhcE1vZHVsZShtb2R1bGVPckJvb3RzdHJhcEZuKTtcbiAgfSBlbHNlIGlmICghaXNGdW5jdGlvbihtb2R1bGVPckJvb3RzdHJhcEZuKSkge1xuICAgIC8vIE5nTW9kdWxlIGZhY3RvcnlcbiAgICBib290c3RyYXBGbiA9IChleHRyYVByb3ZpZGVyczogU3RhdGljUHJvdmlkZXJbXSkgPT5cbiAgICAgICAgcGxhdGZvcm1Ccm93c2VyKGV4dHJhUHJvdmlkZXJzKS5ib290c3RyYXBNb2R1bGVGYWN0b3J5KG1vZHVsZU9yQm9vdHN0cmFwRm4pO1xuICB9IGVsc2Uge1xuICAgIC8vIGJvb3RzdHJhcCBmdW5jdGlvblxuICAgIGJvb3RzdHJhcEZuID0gbW9kdWxlT3JCb290c3RyYXBGbjtcbiAgfVxuXG4gIGxldCBpbmplY3RvcjogSW5qZWN0b3I7XG5cbiAgLy8gQ3JlYXRlIGFuIG5nMSBtb2R1bGUgdG8gYm9vdHN0cmFwLlxuICBhbmd1bGFyTW9kdWxlKGxhenlNb2R1bGVOYW1lLCBbXSlcbiAgICAgIC5jb25zdGFudChVUEdSQURFX0FQUF9UWVBFX0tFWSwgVXBncmFkZUFwcFR5cGUuTGl0ZSlcbiAgICAgIC5mYWN0b3J5KElOSkVDVE9SX0tFWSwgW2xhenlJbmplY3RvcktleSwgaWRlbnRpdHldKVxuICAgICAgLmZhY3RvcnkoXG4gICAgICAgICAgbGF6eUluamVjdG9yS2V5LFxuICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgIGlmICghaW5qZWN0b3IpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICAgJ1RyeWluZyB0byBnZXQgdGhlIEFuZ3VsYXIgaW5qZWN0b3IgYmVmb3JlIGJvb3RzdHJhcHBpbmcgdGhlIGNvcnJlc3BvbmRpbmcgJyArXG4gICAgICAgICAgICAgICAgICAnQW5ndWxhciBtb2R1bGUuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaW5qZWN0b3I7XG4gICAgICAgICAgfSlcbiAgICAgIC5mYWN0b3J5KExBWllfTU9EVUxFX1JFRiwgW2xhenlNb2R1bGVSZWZLZXksIGlkZW50aXR5XSlcbiAgICAgIC5mYWN0b3J5KFxuICAgICAgICAgIGxhenlNb2R1bGVSZWZLZXksXG4gICAgICAgICAgW1xuICAgICAgICAgICAgJElOSkVDVE9SLFxuICAgICAgICAgICAgKCRpbmplY3RvcjogSUluamVjdG9yU2VydmljZSkgPT4ge1xuICAgICAgICAgICAgICBzZXRUZW1wSW5qZWN0b3JSZWYoJGluamVjdG9yKTtcbiAgICAgICAgICAgICAgY29uc3QgcmVzdWx0OiBMYXp5TW9kdWxlUmVmID0ge1xuICAgICAgICAgICAgICAgIHByb21pc2U6IGJvb3RzdHJhcEZuKGFuZ3VsYXIxUHJvdmlkZXJzKS50aGVuKHJlZiA9PiB7XG4gICAgICAgICAgICAgICAgICBpbmplY3RvciA9IHJlc3VsdC5pbmplY3RvciA9IG5ldyBOZ0FkYXB0ZXJJbmplY3RvcihyZWYuaW5qZWN0b3IpO1xuICAgICAgICAgICAgICAgICAgaW5qZWN0b3IuZ2V0KCRJTkpFQ1RPUik7XG5cbiAgICAgICAgICAgICAgICAgIC8vIERlc3Ryb3kgdGhlIEFuZ3VsYXJKUyBhcHAgb25jZSB0aGUgQW5ndWxhciBgUGxhdGZvcm1SZWZgIGlzIGRlc3Ryb3llZC5cbiAgICAgICAgICAgICAgICAgIC8vIFRoaXMgZG9lcyBub3QgaGFwcGVuIGluIGEgdHlwaWNhbCBTUEEgc2NlbmFyaW8sIGJ1dCBpdCBtaWdodCBiZSB1c2VmdWwgZm9yXG4gICAgICAgICAgICAgICAgICAvLyBvdGhlciB1c2UtY2FzZXMgd2hlcmUgZGlzcG9zaW5nIG9mIGFuIEFuZ3VsYXIvQW5ndWxhckpTIGFwcCBpcyBuZWNlc3NhcnlcbiAgICAgICAgICAgICAgICAgIC8vIChzdWNoIGFzIEhvdCBNb2R1bGUgUmVwbGFjZW1lbnQgKEhNUikpLlxuICAgICAgICAgICAgICAgICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2FuZ3VsYXIvaXNzdWVzLzM5OTM1LlxuICAgICAgICAgICAgICAgICAgaW5qZWN0b3IuZ2V0KFBsYXRmb3JtUmVmKS5vbkRlc3Ryb3koKCkgPT4gZGVzdHJveUFwcCgkaW5qZWN0b3IpKTtcblxuICAgICAgICAgICAgICAgICAgcmV0dXJuIGluamVjdG9yO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgXSlcbiAgICAgIC5jb25maWcoW1xuICAgICAgICAkSU5KRUNUT1IsICRQUk9WSURFLFxuICAgICAgICAoJGluamVjdG9yOiBJSW5qZWN0b3JTZXJ2aWNlLCAkcHJvdmlkZTogSVByb3ZpZGVTZXJ2aWNlKSA9PiB7XG4gICAgICAgICAgJHByb3ZpZGUuY29uc3RhbnQoRE9XTkdSQURFRF9NT0RVTEVfQ09VTlRfS0VZLCBnZXREb3duZ3JhZGVkTW9kdWxlQ291bnQoJGluamVjdG9yKSArIDEpO1xuICAgICAgICB9XG4gICAgICBdKTtcblxuICByZXR1cm4gbGF6eU1vZHVsZU5hbWU7XG59XG5cbmZ1bmN0aW9uIGlkZW50aXR5PFQgPSBhbnk+KHg6IFQpOiBUIHtcbiAgcmV0dXJuIHg7XG59XG4iXX0= |
\ | No newline at end of file |