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 { isForwardRef, resolveForwardRef } from '../di/forward_ref';
|
---|
9 | import { injectRootLimpMode, setInjectImplementation } from '../di/inject_switch';
|
---|
10 | import { InjectFlags } from '../di/interface/injector';
|
---|
11 | import { assertDefined, assertEqual, assertIndexInRange } from '../util/assert';
|
---|
12 | import { noSideEffects } from '../util/closure';
|
---|
13 | import { assertDirectiveDef, assertNodeInjector, assertTNodeForLView } from './assert';
|
---|
14 | import { getFactoryDef } from './definition_factory';
|
---|
15 | import { throwCyclicDependencyError, throwProviderNotFoundError } from './errors_di';
|
---|
16 | import { NG_ELEMENT_ID, NG_FACTORY_DEF } from './fields';
|
---|
17 | import { registerPreOrderHooks } from './hooks';
|
---|
18 | import { isFactory, NO_PARENT_INJECTOR } from './interfaces/injector';
|
---|
19 | import { isComponentDef, isComponentHost } from './interfaces/type_checks';
|
---|
20 | import { DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, INJECTOR, T_HOST, TVIEW } from './interfaces/view';
|
---|
21 | import { assertTNodeType } from './node_assert';
|
---|
22 | import { enterDI, getCurrentTNode, getLView, leaveDI } from './state';
|
---|
23 | import { isNameOnlyAttributeMarker } from './util/attrs_utils';
|
---|
24 | import { getParentInjectorIndex, getParentInjectorView, hasParentInjector } from './util/injector_utils';
|
---|
25 | import { stringifyForError } from './util/stringify_utils';
|
---|
26 | /**
|
---|
27 | * Defines if the call to `inject` should include `viewProviders` in its resolution.
|
---|
28 | *
|
---|
29 | * This is set to true when we try to instantiate a component. This value is reset in
|
---|
30 | * `getNodeInjectable` to a value which matches the declaration location of the token about to be
|
---|
31 | * instantiated. This is done so that if we are injecting a token which was declared outside of
|
---|
32 | * `viewProviders` we don't accidentally pull `viewProviders` in.
|
---|
33 | *
|
---|
34 | * Example:
|
---|
35 | *
|
---|
36 | * ```
|
---|
37 | * @Injectable()
|
---|
38 | * class MyService {
|
---|
39 | * constructor(public value: String) {}
|
---|
40 | * }
|
---|
41 | *
|
---|
42 | * @Component({
|
---|
43 | * providers: [
|
---|
44 | * MyService,
|
---|
45 | * {provide: String, value: 'providers' }
|
---|
46 | * ]
|
---|
47 | * viewProviders: [
|
---|
48 | * {provide: String, value: 'viewProviders'}
|
---|
49 | * ]
|
---|
50 | * })
|
---|
51 | * class MyComponent {
|
---|
52 | * constructor(myService: MyService, value: String) {
|
---|
53 | * // We expect that Component can see into `viewProviders`.
|
---|
54 | * expect(value).toEqual('viewProviders');
|
---|
55 | * // `MyService` was not declared in `viewProviders` hence it can't see it.
|
---|
56 | * expect(myService.value).toEqual('providers');
|
---|
57 | * }
|
---|
58 | * }
|
---|
59 | *
|
---|
60 | * ```
|
---|
61 | */
|
---|
62 | let includeViewProviders = true;
|
---|
63 | export function setIncludeViewProviders(v) {
|
---|
64 | const oldValue = includeViewProviders;
|
---|
65 | includeViewProviders = v;
|
---|
66 | return oldValue;
|
---|
67 | }
|
---|
68 | /**
|
---|
69 | * The number of slots in each bloom filter (used by DI). The larger this number, the fewer
|
---|
70 | * directives that will share slots, and thus, the fewer false positives when checking for
|
---|
71 | * the existence of a directive.
|
---|
72 | */
|
---|
73 | const BLOOM_SIZE = 256;
|
---|
74 | const BLOOM_MASK = BLOOM_SIZE - 1;
|
---|
75 | /**
|
---|
76 | * The number of bits that is represented by a single bloom bucket. JS bit operations are 32 bits,
|
---|
77 | * so each bucket represents 32 distinct tokens which accounts for log2(32) = 5 bits of a bloom hash
|
---|
78 | * number.
|
---|
79 | */
|
---|
80 | const BLOOM_BUCKET_BITS = 5;
|
---|
81 | /** Counter used to generate unique IDs for directives. */
|
---|
82 | let nextNgElementId = 0;
|
---|
83 | /**
|
---|
84 | * Registers this directive as present in its node's injector by flipping the directive's
|
---|
85 | * corresponding bit in the injector's bloom filter.
|
---|
86 | *
|
---|
87 | * @param injectorIndex The index of the node injector where this token should be registered
|
---|
88 | * @param tView The TView for the injector's bloom filters
|
---|
89 | * @param type The directive token to register
|
---|
90 | */
|
---|
91 | export function bloomAdd(injectorIndex, tView, type) {
|
---|
92 | ngDevMode && assertEqual(tView.firstCreatePass, true, 'expected firstCreatePass to be true');
|
---|
93 | let id;
|
---|
94 | if (typeof type === 'string') {
|
---|
95 | id = type.charCodeAt(0) || 0;
|
---|
96 | }
|
---|
97 | else if (type.hasOwnProperty(NG_ELEMENT_ID)) {
|
---|
98 | id = type[NG_ELEMENT_ID];
|
---|
99 | }
|
---|
100 | // Set a unique ID on the directive type, so if something tries to inject the directive,
|
---|
101 | // we can easily retrieve the ID and hash it into the bloom bit that should be checked.
|
---|
102 | if (id == null) {
|
---|
103 | id = type[NG_ELEMENT_ID] = nextNgElementId++;
|
---|
104 | }
|
---|
105 | // We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each),
|
---|
106 | // so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter.
|
---|
107 | const bloomHash = id & BLOOM_MASK;
|
---|
108 | // Create a mask that targets the specific bit associated with the directive.
|
---|
109 | // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
|
---|
110 | // to bit positions 0 - 31 in a 32 bit integer.
|
---|
111 | const mask = 1 << bloomHash;
|
---|
112 | // Each bloom bucket in `tData` represents `BLOOM_BUCKET_BITS` number of bits of `bloomHash`.
|
---|
113 | // Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset that the mask
|
---|
114 | // should be written to.
|
---|
115 | tView.data[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)] |= mask;
|
---|
116 | }
|
---|
117 | /**
|
---|
118 | * Creates (or gets an existing) injector for a given element or container.
|
---|
119 | *
|
---|
120 | * @param tNode for which an injector should be retrieved / created.
|
---|
121 | * @param lView View where the node is stored
|
---|
122 | * @returns Node injector
|
---|
123 | */
|
---|
124 | export function getOrCreateNodeInjectorForNode(tNode, lView) {
|
---|
125 | const existingInjectorIndex = getInjectorIndex(tNode, lView);
|
---|
126 | if (existingInjectorIndex !== -1) {
|
---|
127 | return existingInjectorIndex;
|
---|
128 | }
|
---|
129 | const tView = lView[TVIEW];
|
---|
130 | if (tView.firstCreatePass) {
|
---|
131 | tNode.injectorIndex = lView.length;
|
---|
132 | insertBloom(tView.data, tNode); // foundation for node bloom
|
---|
133 | insertBloom(lView, null); // foundation for cumulative bloom
|
---|
134 | insertBloom(tView.blueprint, null);
|
---|
135 | }
|
---|
136 | const parentLoc = getParentInjectorLocation(tNode, lView);
|
---|
137 | const injectorIndex = tNode.injectorIndex;
|
---|
138 | // If a parent injector can't be found, its location is set to -1.
|
---|
139 | // In that case, we don't need to set up a cumulative bloom
|
---|
140 | if (hasParentInjector(parentLoc)) {
|
---|
141 | const parentIndex = getParentInjectorIndex(parentLoc);
|
---|
142 | const parentLView = getParentInjectorView(parentLoc, lView);
|
---|
143 | const parentData = parentLView[TVIEW].data;
|
---|
144 | // Creates a cumulative bloom filter that merges the parent's bloom filter
|
---|
145 | // and its own cumulative bloom (which contains tokens for all ancestors)
|
---|
146 | for (let i = 0; i < 8 /* BLOOM_SIZE */; i++) {
|
---|
147 | lView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i];
|
---|
148 | }
|
---|
149 | }
|
---|
150 | lView[injectorIndex + 8 /* PARENT */] = parentLoc;
|
---|
151 | return injectorIndex;
|
---|
152 | }
|
---|
153 | function insertBloom(arr, footer) {
|
---|
154 | arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer);
|
---|
155 | }
|
---|
156 | export function getInjectorIndex(tNode, lView) {
|
---|
157 | if (tNode.injectorIndex === -1 ||
|
---|
158 | // If the injector index is the same as its parent's injector index, then the index has been
|
---|
159 | // copied down from the parent node. No injector has been created yet on this node.
|
---|
160 | (tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) ||
|
---|
161 | // After the first template pass, the injector index might exist but the parent values
|
---|
162 | // might not have been calculated yet for this instance
|
---|
163 | lView[tNode.injectorIndex + 8 /* PARENT */] === null) {
|
---|
164 | return -1;
|
---|
165 | }
|
---|
166 | else {
|
---|
167 | ngDevMode && assertIndexInRange(lView, tNode.injectorIndex);
|
---|
168 | return tNode.injectorIndex;
|
---|
169 | }
|
---|
170 | }
|
---|
171 | /**
|
---|
172 | * Finds the index of the parent injector, with a view offset if applicable. Used to set the
|
---|
173 | * parent injector initially.
|
---|
174 | *
|
---|
175 | * @returns Returns a number that is the combination of the number of LViews that we have to go up
|
---|
176 | * to find the LView containing the parent inject AND the index of the injector within that LView.
|
---|
177 | */
|
---|
178 | export function getParentInjectorLocation(tNode, lView) {
|
---|
179 | if (tNode.parent && tNode.parent.injectorIndex !== -1) {
|
---|
180 | // If we have a parent `TNode` and there is an injector associated with it we are done, because
|
---|
181 | // the parent injector is within the current `LView`.
|
---|
182 | return tNode.parent.injectorIndex; // ViewOffset is 0
|
---|
183 | }
|
---|
184 | // When parent injector location is computed it may be outside of the current view. (ie it could
|
---|
185 | // be pointing to a declared parent location). This variable stores number of declaration parents
|
---|
186 | // we need to walk up in order to find the parent injector location.
|
---|
187 | let declarationViewOffset = 0;
|
---|
188 | let parentTNode = null;
|
---|
189 | let lViewCursor = lView;
|
---|
190 | // The parent injector is not in the current `LView`. We will have to walk the declared parent
|
---|
191 | // `LView` hierarchy and look for it. If we walk of the top, that means that there is no parent
|
---|
192 | // `NodeInjector`.
|
---|
193 | while (lViewCursor !== null) {
|
---|
194 | // First determine the `parentTNode` location. The parent pointer differs based on `TView.type`.
|
---|
195 | const tView = lViewCursor[TVIEW];
|
---|
196 | const tViewType = tView.type;
|
---|
197 | if (tViewType === 2 /* Embedded */) {
|
---|
198 | ngDevMode &&
|
---|
199 | assertDefined(tView.declTNode, 'Embedded TNodes should have declaration parents.');
|
---|
200 | parentTNode = tView.declTNode;
|
---|
201 | }
|
---|
202 | else if (tViewType === 1 /* Component */) {
|
---|
203 | // Components don't have `TView.declTNode` because each instance of component could be
|
---|
204 | // inserted in different location, hence `TView.declTNode` is meaningless.
|
---|
205 | parentTNode = lViewCursor[T_HOST];
|
---|
206 | }
|
---|
207 | else {
|
---|
208 | ngDevMode && assertEqual(tView.type, 0 /* Root */, 'Root type expected');
|
---|
209 | parentTNode = null;
|
---|
210 | }
|
---|
211 | if (parentTNode === null) {
|
---|
212 | // If we have no parent, than we are done.
|
---|
213 | return NO_PARENT_INJECTOR;
|
---|
214 | }
|
---|
215 | ngDevMode && parentTNode && assertTNodeForLView(parentTNode, lViewCursor[DECLARATION_VIEW]);
|
---|
216 | // Every iteration of the loop requires that we go to the declared parent.
|
---|
217 | declarationViewOffset++;
|
---|
218 | lViewCursor = lViewCursor[DECLARATION_VIEW];
|
---|
219 | if (parentTNode.injectorIndex !== -1) {
|
---|
220 | // We found a NodeInjector which points to something.
|
---|
221 | return (parentTNode.injectorIndex |
|
---|
222 | (declarationViewOffset << 16 /* ViewOffsetShift */));
|
---|
223 | }
|
---|
224 | }
|
---|
225 | return NO_PARENT_INJECTOR;
|
---|
226 | }
|
---|
227 | /**
|
---|
228 | * Makes a type or an injection token public to the DI system by adding it to an
|
---|
229 | * injector's bloom filter.
|
---|
230 | *
|
---|
231 | * @param di The node injector in which a directive will be added
|
---|
232 | * @param token The type or the injection token to be made public
|
---|
233 | */
|
---|
234 | export function diPublicInInjector(injectorIndex, tView, token) {
|
---|
235 | bloomAdd(injectorIndex, tView, token);
|
---|
236 | }
|
---|
237 | /**
|
---|
238 | * Inject static attribute value into directive constructor.
|
---|
239 | *
|
---|
240 | * This method is used with `factory` functions which are generated as part of
|
---|
241 | * `defineDirective` or `defineComponent`. The method retrieves the static value
|
---|
242 | * of an attribute. (Dynamic attributes are not supported since they are not resolved
|
---|
243 | * at the time of injection and can change over time.)
|
---|
244 | *
|
---|
245 | * # Example
|
---|
246 | * Given:
|
---|
247 | * ```
|
---|
248 | * @Component(...)
|
---|
249 | * class MyComponent {
|
---|
250 | * constructor(@Attribute('title') title: string) { ... }
|
---|
251 | * }
|
---|
252 | * ```
|
---|
253 | * When instantiated with
|
---|
254 | * ```
|
---|
255 | * <my-component title="Hello"></my-component>
|
---|
256 | * ```
|
---|
257 | *
|
---|
258 | * Then factory method generated is:
|
---|
259 | * ```
|
---|
260 | * MyComponent.ɵcmp = defineComponent({
|
---|
261 | * factory: () => new MyComponent(injectAttribute('title'))
|
---|
262 | * ...
|
---|
263 | * })
|
---|
264 | * ```
|
---|
265 | *
|
---|
266 | * @publicApi
|
---|
267 | */
|
---|
268 | export function injectAttributeImpl(tNode, attrNameToInject) {
|
---|
269 | ngDevMode && assertTNodeType(tNode, 12 /* AnyContainer */ | 3 /* AnyRNode */);
|
---|
270 | ngDevMode && assertDefined(tNode, 'expecting tNode');
|
---|
271 | if (attrNameToInject === 'class') {
|
---|
272 | return tNode.classes;
|
---|
273 | }
|
---|
274 | if (attrNameToInject === 'style') {
|
---|
275 | return tNode.styles;
|
---|
276 | }
|
---|
277 | const attrs = tNode.attrs;
|
---|
278 | if (attrs) {
|
---|
279 | const attrsLength = attrs.length;
|
---|
280 | let i = 0;
|
---|
281 | while (i < attrsLength) {
|
---|
282 | const value = attrs[i];
|
---|
283 | // If we hit a `Bindings` or `Template` marker then we are done.
|
---|
284 | if (isNameOnlyAttributeMarker(value))
|
---|
285 | break;
|
---|
286 | // Skip namespaced attributes
|
---|
287 | if (value === 0 /* NamespaceURI */) {
|
---|
288 | // we skip the next two values
|
---|
289 | // as namespaced attributes looks like
|
---|
290 | // [..., AttributeMarker.NamespaceURI, 'http://someuri.com/test', 'test:exist',
|
---|
291 | // 'existValue', ...]
|
---|
292 | i = i + 2;
|
---|
293 | }
|
---|
294 | else if (typeof value === 'number') {
|
---|
295 | // Skip to the first value of the marked attribute.
|
---|
296 | i++;
|
---|
297 | while (i < attrsLength && typeof attrs[i] === 'string') {
|
---|
298 | i++;
|
---|
299 | }
|
---|
300 | }
|
---|
301 | else if (value === attrNameToInject) {
|
---|
302 | return attrs[i + 1];
|
---|
303 | }
|
---|
304 | else {
|
---|
305 | i = i + 2;
|
---|
306 | }
|
---|
307 | }
|
---|
308 | }
|
---|
309 | return null;
|
---|
310 | }
|
---|
311 | function notFoundValueOrThrow(notFoundValue, token, flags) {
|
---|
312 | if (flags & InjectFlags.Optional) {
|
---|
313 | return notFoundValue;
|
---|
314 | }
|
---|
315 | else {
|
---|
316 | throwProviderNotFoundError(token, 'NodeInjector');
|
---|
317 | }
|
---|
318 | }
|
---|
319 | /**
|
---|
320 | * Returns the value associated to the given token from the ModuleInjector or throws exception
|
---|
321 | *
|
---|
322 | * @param lView The `LView` that contains the `tNode`
|
---|
323 | * @param token The token to look for
|
---|
324 | * @param flags Injection flags
|
---|
325 | * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
|
---|
326 | * @returns the value from the injector or throws an exception
|
---|
327 | */
|
---|
328 | function lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue) {
|
---|
329 | if (flags & InjectFlags.Optional && notFoundValue === undefined) {
|
---|
330 | // This must be set or the NullInjector will throw for optional deps
|
---|
331 | notFoundValue = null;
|
---|
332 | }
|
---|
333 | if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) {
|
---|
334 | const moduleInjector = lView[INJECTOR];
|
---|
335 | // switch to `injectInjectorOnly` implementation for module injector, since module injector
|
---|
336 | // should not have access to Component/Directive DI scope (that may happen through
|
---|
337 | // `directiveInject` implementation)
|
---|
338 | const previousInjectImplementation = setInjectImplementation(undefined);
|
---|
339 | try {
|
---|
340 | if (moduleInjector) {
|
---|
341 | return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional);
|
---|
342 | }
|
---|
343 | else {
|
---|
344 | return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional);
|
---|
345 | }
|
---|
346 | }
|
---|
347 | finally {
|
---|
348 | setInjectImplementation(previousInjectImplementation);
|
---|
349 | }
|
---|
350 | }
|
---|
351 | return notFoundValueOrThrow(notFoundValue, token, flags);
|
---|
352 | }
|
---|
353 | /**
|
---|
354 | * Returns the value associated to the given token from the NodeInjectors => ModuleInjector.
|
---|
355 | *
|
---|
356 | * Look for the injector providing the token by walking up the node injector tree and then
|
---|
357 | * the module injector tree.
|
---|
358 | *
|
---|
359 | * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom
|
---|
360 | * filter. `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`)
|
---|
361 | *
|
---|
362 | * @param tNode The Node where the search for the injector should start
|
---|
363 | * @param lView The `LView` that contains the `tNode`
|
---|
364 | * @param token The token to look for
|
---|
365 | * @param flags Injection flags
|
---|
366 | * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional`
|
---|
367 | * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided
|
---|
368 | */
|
---|
369 | export function getOrCreateInjectable(tNode, lView, token, flags = InjectFlags.Default, notFoundValue) {
|
---|
370 | if (tNode !== null) {
|
---|
371 | const bloomHash = bloomHashBitOrFactory(token);
|
---|
372 | // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
|
---|
373 | // so just call the factory function to create it.
|
---|
374 | if (typeof bloomHash === 'function') {
|
---|
375 | if (!enterDI(lView, tNode, flags)) {
|
---|
376 | // Failed to enter DI, try module injector instead. If a token is injected with the @Host
|
---|
377 | // flag, the module injector is not searched for that token in Ivy.
|
---|
378 | return (flags & InjectFlags.Host) ?
|
---|
379 | notFoundValueOrThrow(notFoundValue, token, flags) :
|
---|
380 | lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
|
---|
381 | }
|
---|
382 | try {
|
---|
383 | const value = bloomHash(flags);
|
---|
384 | if (value == null && !(flags & InjectFlags.Optional)) {
|
---|
385 | throwProviderNotFoundError(token);
|
---|
386 | }
|
---|
387 | else {
|
---|
388 | return value;
|
---|
389 | }
|
---|
390 | }
|
---|
391 | finally {
|
---|
392 | leaveDI();
|
---|
393 | }
|
---|
394 | }
|
---|
395 | else if (typeof bloomHash === 'number') {
|
---|
396 | // A reference to the previous injector TView that was found while climbing the element
|
---|
397 | // injector tree. This is used to know if viewProviders can be accessed on the current
|
---|
398 | // injector.
|
---|
399 | let previousTView = null;
|
---|
400 | let injectorIndex = getInjectorIndex(tNode, lView);
|
---|
401 | let parentLocation = NO_PARENT_INJECTOR;
|
---|
402 | let hostTElementNode = flags & InjectFlags.Host ? lView[DECLARATION_COMPONENT_VIEW][T_HOST] : null;
|
---|
403 | // If we should skip this injector, or if there is no injector on this node, start by
|
---|
404 | // searching the parent injector.
|
---|
405 | if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) {
|
---|
406 | parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) :
|
---|
407 | lView[injectorIndex + 8 /* PARENT */];
|
---|
408 | if (parentLocation === NO_PARENT_INJECTOR || !shouldSearchParent(flags, false)) {
|
---|
409 | injectorIndex = -1;
|
---|
410 | }
|
---|
411 | else {
|
---|
412 | previousTView = lView[TVIEW];
|
---|
413 | injectorIndex = getParentInjectorIndex(parentLocation);
|
---|
414 | lView = getParentInjectorView(parentLocation, lView);
|
---|
415 | }
|
---|
416 | }
|
---|
417 | // Traverse up the injector tree until we find a potential match or until we know there
|
---|
418 | // *isn't* a match.
|
---|
419 | while (injectorIndex !== -1) {
|
---|
420 | ngDevMode && assertNodeInjector(lView, injectorIndex);
|
---|
421 | // Check the current injector. If it matches, see if it contains token.
|
---|
422 | const tView = lView[TVIEW];
|
---|
423 | ngDevMode &&
|
---|
424 | assertTNodeForLView(tView.data[injectorIndex + 8 /* TNODE */], lView);
|
---|
425 | if (bloomHasToken(bloomHash, injectorIndex, tView.data)) {
|
---|
426 | // At this point, we have an injector which *may* contain the token, so we step through
|
---|
427 | // the providers and directives associated with the injector's corresponding node to get
|
---|
428 | // the instance.
|
---|
429 | const instance = searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode);
|
---|
430 | if (instance !== NOT_FOUND) {
|
---|
431 | return instance;
|
---|
432 | }
|
---|
433 | }
|
---|
434 | parentLocation = lView[injectorIndex + 8 /* PARENT */];
|
---|
435 | if (parentLocation !== NO_PARENT_INJECTOR &&
|
---|
436 | shouldSearchParent(flags, lView[TVIEW].data[injectorIndex + 8 /* TNODE */] === hostTElementNode) &&
|
---|
437 | bloomHasToken(bloomHash, injectorIndex, lView)) {
|
---|
438 | // The def wasn't found anywhere on this node, so it was a false positive.
|
---|
439 | // Traverse up the tree and continue searching.
|
---|
440 | previousTView = tView;
|
---|
441 | injectorIndex = getParentInjectorIndex(parentLocation);
|
---|
442 | lView = getParentInjectorView(parentLocation, lView);
|
---|
443 | }
|
---|
444 | else {
|
---|
445 | // If we should not search parent OR If the ancestor bloom filter value does not have the
|
---|
446 | // bit corresponding to the directive we can give up on traversing up to find the specific
|
---|
447 | // injector.
|
---|
448 | injectorIndex = -1;
|
---|
449 | }
|
---|
450 | }
|
---|
451 | }
|
---|
452 | }
|
---|
453 | return lookupTokenUsingModuleInjector(lView, token, flags, notFoundValue);
|
---|
454 | }
|
---|
455 | const NOT_FOUND = {};
|
---|
456 | export function createNodeInjector() {
|
---|
457 | return new NodeInjector(getCurrentTNode(), getLView());
|
---|
458 | }
|
---|
459 | function searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode) {
|
---|
460 | const currentTView = lView[TVIEW];
|
---|
461 | const tNode = currentTView.data[injectorIndex + 8 /* TNODE */];
|
---|
462 | // First, we need to determine if view providers can be accessed by the starting element.
|
---|
463 | // There are two possibilities
|
---|
464 | const canAccessViewProviders = previousTView == null ?
|
---|
465 | // 1) This is the first invocation `previousTView == null` which means that we are at the
|
---|
466 | // `TNode` of where injector is starting to look. In such a case the only time we are allowed
|
---|
467 | // to look into the ViewProviders is if:
|
---|
468 | // - we are on a component
|
---|
469 | // - AND the injector set `includeViewProviders` to true (implying that the token can see
|
---|
470 | // ViewProviders because it is the Component or a Service which itself was declared in
|
---|
471 | // ViewProviders)
|
---|
472 | (isComponentHost(tNode) && includeViewProviders) :
|
---|
473 | // 2) `previousTView != null` which means that we are now walking across the parent nodes.
|
---|
474 | // In such a case we are only allowed to look into the ViewProviders if:
|
---|
475 | // - We just crossed from child View to Parent View `previousTView != currentTView`
|
---|
476 | // - AND the parent TNode is an Element.
|
---|
477 | // This means that we just came from the Component's View and therefore are allowed to see
|
---|
478 | // into the ViewProviders.
|
---|
479 | (previousTView != currentTView && ((tNode.type & 3 /* AnyRNode */) !== 0));
|
---|
480 | // This special case happens when there is a @host on the inject and when we are searching
|
---|
481 | // on the host element node.
|
---|
482 | const isHostSpecialCase = (flags & InjectFlags.Host) && hostTElementNode === tNode;
|
---|
483 | const injectableIdx = locateDirectiveOrProvider(tNode, currentTView, token, canAccessViewProviders, isHostSpecialCase);
|
---|
484 | if (injectableIdx !== null) {
|
---|
485 | return getNodeInjectable(lView, currentTView, injectableIdx, tNode);
|
---|
486 | }
|
---|
487 | else {
|
---|
488 | return NOT_FOUND;
|
---|
489 | }
|
---|
490 | }
|
---|
491 | /**
|
---|
492 | * Searches for the given token among the node's directives and providers.
|
---|
493 | *
|
---|
494 | * @param tNode TNode on which directives are present.
|
---|
495 | * @param tView The tView we are currently processing
|
---|
496 | * @param token Provider token or type of a directive to look for.
|
---|
497 | * @param canAccessViewProviders Whether view providers should be considered.
|
---|
498 | * @param isHostSpecialCase Whether the host special case applies.
|
---|
499 | * @returns Index of a found directive or provider, or null when none found.
|
---|
500 | */
|
---|
501 | export function locateDirectiveOrProvider(tNode, tView, token, canAccessViewProviders, isHostSpecialCase) {
|
---|
502 | const nodeProviderIndexes = tNode.providerIndexes;
|
---|
503 | const tInjectables = tView.data;
|
---|
504 | const injectablesStart = nodeProviderIndexes & 1048575 /* ProvidersStartIndexMask */;
|
---|
505 | const directivesStart = tNode.directiveStart;
|
---|
506 | const directiveEnd = tNode.directiveEnd;
|
---|
507 | const cptViewProvidersCount = nodeProviderIndexes >> 20 /* CptViewProvidersCountShift */;
|
---|
508 | const startingIndex = canAccessViewProviders ? injectablesStart : injectablesStart + cptViewProvidersCount;
|
---|
509 | // When the host special case applies, only the viewProviders and the component are visible
|
---|
510 | const endIndex = isHostSpecialCase ? injectablesStart + cptViewProvidersCount : directiveEnd;
|
---|
511 | for (let i = startingIndex; i < endIndex; i++) {
|
---|
512 | const providerTokenOrDef = tInjectables[i];
|
---|
513 | if (i < directivesStart && token === providerTokenOrDef ||
|
---|
514 | i >= directivesStart && providerTokenOrDef.type === token) {
|
---|
515 | return i;
|
---|
516 | }
|
---|
517 | }
|
---|
518 | if (isHostSpecialCase) {
|
---|
519 | const dirDef = tInjectables[directivesStart];
|
---|
520 | if (dirDef && isComponentDef(dirDef) && dirDef.type === token) {
|
---|
521 | return directivesStart;
|
---|
522 | }
|
---|
523 | }
|
---|
524 | return null;
|
---|
525 | }
|
---|
526 | /**
|
---|
527 | * Retrieve or instantiate the injectable from the `LView` at particular `index`.
|
---|
528 | *
|
---|
529 | * This function checks to see if the value has already been instantiated and if so returns the
|
---|
530 | * cached `injectable`. Otherwise if it detects that the value is still a factory it
|
---|
531 | * instantiates the `injectable` and caches the value.
|
---|
532 | */
|
---|
533 | export function getNodeInjectable(lView, tView, index, tNode) {
|
---|
534 | let value = lView[index];
|
---|
535 | const tData = tView.data;
|
---|
536 | if (isFactory(value)) {
|
---|
537 | const factory = value;
|
---|
538 | if (factory.resolving) {
|
---|
539 | throwCyclicDependencyError(stringifyForError(tData[index]));
|
---|
540 | }
|
---|
541 | const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders);
|
---|
542 | factory.resolving = true;
|
---|
543 | const previousInjectImplementation = factory.injectImpl ? setInjectImplementation(factory.injectImpl) : null;
|
---|
544 | const success = enterDI(lView, tNode, InjectFlags.Default);
|
---|
545 | ngDevMode &&
|
---|
546 | assertEqual(success, true, 'Because flags do not contain \`SkipSelf\' we expect this to always succeed.');
|
---|
547 | try {
|
---|
548 | value = lView[index] = factory.factory(undefined, tData, lView, tNode);
|
---|
549 | // This code path is hit for both directives and providers.
|
---|
550 | // For perf reasons, we want to avoid searching for hooks on providers.
|
---|
551 | // It does no harm to try (the hooks just won't exist), but the extra
|
---|
552 | // checks are unnecessary and this is a hot path. So we check to see
|
---|
553 | // if the index of the dependency is in the directive range for this
|
---|
554 | // tNode. If it's not, we know it's a provider and skip hook registration.
|
---|
555 | if (tView.firstCreatePass && index >= tNode.directiveStart) {
|
---|
556 | ngDevMode && assertDirectiveDef(tData[index]);
|
---|
557 | registerPreOrderHooks(index, tData[index], tView);
|
---|
558 | }
|
---|
559 | }
|
---|
560 | finally {
|
---|
561 | previousInjectImplementation !== null &&
|
---|
562 | setInjectImplementation(previousInjectImplementation);
|
---|
563 | setIncludeViewProviders(previousIncludeViewProviders);
|
---|
564 | factory.resolving = false;
|
---|
565 | leaveDI();
|
---|
566 | }
|
---|
567 | }
|
---|
568 | return value;
|
---|
569 | }
|
---|
570 | /**
|
---|
571 | * Returns the bit in an injector's bloom filter that should be used to determine whether or not
|
---|
572 | * the directive might be provided by the injector.
|
---|
573 | *
|
---|
574 | * When a directive is public, it is added to the bloom filter and given a unique ID that can be
|
---|
575 | * retrieved on the Type. When the directive isn't public or the token is not a directive `null`
|
---|
576 | * is returned as the node injector can not possibly provide that token.
|
---|
577 | *
|
---|
578 | * @param token the injection token
|
---|
579 | * @returns the matching bit to check in the bloom filter or `null` if the token is not known.
|
---|
580 | * When the returned value is negative then it represents special values such as `Injector`.
|
---|
581 | */
|
---|
582 | export function bloomHashBitOrFactory(token) {
|
---|
583 | ngDevMode && assertDefined(token, 'token must be defined');
|
---|
584 | if (typeof token === 'string') {
|
---|
585 | return token.charCodeAt(0) || 0;
|
---|
586 | }
|
---|
587 | const tokenId =
|
---|
588 | // First check with `hasOwnProperty` so we don't get an inherited ID.
|
---|
589 | token.hasOwnProperty(NG_ELEMENT_ID) ? token[NG_ELEMENT_ID] : undefined;
|
---|
590 | // Negative token IDs are used for special objects such as `Injector`
|
---|
591 | if (typeof tokenId === 'number') {
|
---|
592 | if (tokenId >= 0) {
|
---|
593 | return tokenId & BLOOM_MASK;
|
---|
594 | }
|
---|
595 | else {
|
---|
596 | ngDevMode &&
|
---|
597 | assertEqual(tokenId, -1 /* Injector */, 'Expecting to get Special Injector Id');
|
---|
598 | return createNodeInjector;
|
---|
599 | }
|
---|
600 | }
|
---|
601 | else {
|
---|
602 | return tokenId;
|
---|
603 | }
|
---|
604 | }
|
---|
605 | export function bloomHasToken(bloomHash, injectorIndex, injectorView) {
|
---|
606 | // Create a mask that targets the specific bit associated with the directive we're looking for.
|
---|
607 | // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding
|
---|
608 | // to bit positions 0 - 31 in a 32 bit integer.
|
---|
609 | const mask = 1 << bloomHash;
|
---|
610 | // Each bloom bucket in `injectorView` represents `BLOOM_BUCKET_BITS` number of bits of
|
---|
611 | // `bloomHash`. Any bits in `bloomHash` beyond `BLOOM_BUCKET_BITS` indicate the bucket offset
|
---|
612 | // that should be used.
|
---|
613 | const value = injectorView[injectorIndex + (bloomHash >> BLOOM_BUCKET_BITS)];
|
---|
614 | // If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on,
|
---|
615 | // this injector is a potential match.
|
---|
616 | return !!(value & mask);
|
---|
617 | }
|
---|
618 | /** Returns true if flags prevent parent injector from being searched for tokens */
|
---|
619 | function shouldSearchParent(flags, isFirstHostTNode) {
|
---|
620 | return !(flags & InjectFlags.Self) && !(flags & InjectFlags.Host && isFirstHostTNode);
|
---|
621 | }
|
---|
622 | export class NodeInjector {
|
---|
623 | constructor(_tNode, _lView) {
|
---|
624 | this._tNode = _tNode;
|
---|
625 | this._lView = _lView;
|
---|
626 | }
|
---|
627 | get(token, notFoundValue) {
|
---|
628 | return getOrCreateInjectable(this._tNode, this._lView, token, undefined, notFoundValue);
|
---|
629 | }
|
---|
630 | }
|
---|
631 | /**
|
---|
632 | * @codeGenApi
|
---|
633 | */
|
---|
634 | export function ɵɵgetInheritedFactory(type) {
|
---|
635 | return noSideEffects(() => {
|
---|
636 | const ownConstructor = type.prototype.constructor;
|
---|
637 | const ownFactory = ownConstructor[NG_FACTORY_DEF] || getFactoryOf(ownConstructor);
|
---|
638 | const objectPrototype = Object.prototype;
|
---|
639 | let parent = Object.getPrototypeOf(type.prototype).constructor;
|
---|
640 | // Go up the prototype until we hit `Object`.
|
---|
641 | while (parent && parent !== objectPrototype) {
|
---|
642 | const factory = parent[NG_FACTORY_DEF] || getFactoryOf(parent);
|
---|
643 | // If we hit something that has a factory and the factory isn't the same as the type,
|
---|
644 | // we've found the inherited factory. Note the check that the factory isn't the type's
|
---|
645 | // own factory is redundant in most cases, but if the user has custom decorators on the
|
---|
646 | // class, this lookup will start one level down in the prototype chain, causing us to
|
---|
647 | // find the own factory first and potentially triggering an infinite loop downstream.
|
---|
648 | if (factory && factory !== ownFactory) {
|
---|
649 | return factory;
|
---|
650 | }
|
---|
651 | parent = Object.getPrototypeOf(parent);
|
---|
652 | }
|
---|
653 | // There is no factory defined. Either this was improper usage of inheritance
|
---|
654 | // (no Angular decorator on the superclass) or there is no constructor at all
|
---|
655 | // in the inheritance chain. Since the two cases cannot be distinguished, the
|
---|
656 | // latter has to be assumed.
|
---|
657 | return t => new t();
|
---|
658 | });
|
---|
659 | }
|
---|
660 | function getFactoryOf(type) {
|
---|
661 | if (isForwardRef(type)) {
|
---|
662 | return () => {
|
---|
663 | const factory = getFactoryOf(resolveForwardRef(type));
|
---|
664 | return factory && factory();
|
---|
665 | };
|
---|
666 | }
|
---|
667 | return getFactoryDef(type);
|
---|
668 | }
|
---|
669 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3NyYy9yZW5kZXIzL2RpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBQyxZQUFZLEVBQUUsaUJBQWlCLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUNsRSxPQUFPLEVBQUMsa0JBQWtCLEVBQUUsdUJBQXVCLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUdoRixPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFHckQsT0FBTyxFQUFDLGFBQWEsRUFBRSxXQUFXLEVBQUUsa0JBQWtCLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5RSxPQUFPLEVBQUMsYUFBYSxFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFFOUMsT0FBTyxFQUFDLGtCQUFrQixFQUFFLGtCQUFrQixFQUFFLG1CQUFtQixFQUFDLE1BQU0sVUFBVSxDQUFDO0FBQ3JGLE9BQU8sRUFBWSxhQUFhLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUM5RCxPQUFPLEVBQUMsMEJBQTBCLEVBQUUsMEJBQTBCLEVBQUMsTUFBTSxhQUFhLENBQUM7QUFDbkYsT0FBTyxFQUFDLGFBQWEsRUFBRSxjQUFjLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDdkQsT0FBTyxFQUFDLHFCQUFxQixFQUFDLE1BQU0sU0FBUyxDQUFDO0FBRTlDLE9BQU8sRUFBQyxTQUFTLEVBQUUsa0JBQWtCLEVBQW1HLE1BQU0sdUJBQXVCLENBQUM7QUFFdEssT0FBTyxFQUFDLGNBQWMsRUFBRSxlQUFlLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQUN6RSxPQUFPLEVBQUMsMEJBQTBCLEVBQUUsZ0JBQWdCLEVBQUUsUUFBUSxFQUFTLE1BQU0sRUFBUyxLQUFLLEVBQW1CLE1BQU0sbUJBQW1CLENBQUM7QUFDeEksT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLGVB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RTtnQkFDckMsT0FBTyxPQUFPLENBQUM7YUFDaEI7WUFFRCxNQUFNLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQztTQUN4QztRQUVELDZFQUE2RTtRQUM3RSw2RUFBNkU7UUFDN0UsNkVBQTZFO1FBQzdFLDRCQUE0QjtRQUM1QixPQUFPLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN0QixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxTQUFTLFlBQVksQ0FBSSxJQUFlO0lBQ3RDLElBQUksWUFBWSxDQUFDLElBQUksQ0FBQyxFQUFFO1FBQ3RCLE9BQU8sR0FBRyxFQUFFO1lBQ1YsTUFBTSxPQUFPLEdBQUcsWUFBWSxDQUFJLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDekQsT0FBTyxPQUFPLElBQUksT0FBTyxFQUFFLENBQUM7UUFDOUIsQ0FBQyxDQUFDO0tBQ0g7SUFDRCxPQUFPLGFBQWEsQ0FBSSxJQUFJLENBQUMsQ0FBQztBQUNoQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7aXNGb3J3YXJkUmVmLCByZXNvbHZlRm9yd2FyZFJlZn0gZnJvbSAnLi4vZGkvZm9yd2FyZF9yZWYnO1xuaW1wb3J0IHtpbmplY3RSb290TGltcE1vZGUsIHNldEluamVjdEltcGxlbWVudGF0aW9ufSBmcm9tICcuLi9kaS9pbmplY3Rfc3dpdGNoJztcbmltcG9ydCB7SW5qZWN0b3J9IGZyb20gJy4uL2RpL2luamVjdG9yJztcbmltcG9ydCB7SW5qZWN0b3JNYXJrZXJzfSBmcm9tICcuLi9kaS9pbmplY3Rvcl9tYXJrZXInO1xuaW1wb3J0IHtJbmplY3RGbGFnc30gZnJvbSAnLi4vZGkvaW50ZXJmYWNlL2luamVjdG9yJztcbmltcG9ydCB7UHJvdmlkZXJUb2tlbn0gZnJvbSAnLi4vZGkvcHJvdmlkZXJfdG9rZW4nO1xuaW1wb3J0IHtUeXBlfSBmcm9tICcuLi9pbnRlcmZhY2UvdHlwZSc7XG5pbXBvcnQge2Fzc2VydERlZmluZWQsIGFzc2VydEVxdWFsLCBhc3NlcnRJbmRleEluUmFuZ2V9IGZyb20gJy4uL3V0aWwvYXNzZXJ0JztcbmltcG9ydCB7bm9TaWRlRWZmZWN0c30gZnJvbSAnLi4vdXRpbC9jbG9zdXJlJztcblxuaW1wb3J0IHthc3NlcnREaXJlY3RpdmVEZWYsIGFzc2VydE5vZGVJbmplY3RvciwgYXNzZXJ0VE5vZGVGb3JMVmlld30gZnJvbSAnLi9hc3NlcnQnO1xuaW1wb3J0IHtGYWN0b3J5Rm4sIGdldEZhY3RvcnlEZWZ9IGZyb20gJy4vZGVmaW5pdGlvbl9mYWN0b3J5JztcbmltcG9ydCB7dGhyb3dDeWNsaWNEZXBlbmRlbmN5RXJyb3IsIHRocm93UHJvdmlkZXJOb3RGb3VuZEVycm9yfSBmcm9tICcuL2Vycm9yc19kaSc7XG5pbXBvcnQge05HX0VMRU1FTlRfSUQsIE5HX0ZBQ1RPUllfREVGfSBmcm9tICcuL2ZpZWxkcyc7XG5pbXBvcnQge3JlZ2lzdGVyUHJlT3JkZXJIb29rc30gZnJvbSAnLi9ob29rcyc7XG5pbXBvcnQge0RpcmVjdGl2ZURlZn0gZnJvbSAnLi9pbnRlcmZhY2VzL2RlZmluaXRpb24nO1xuaW1wb3J0IHtpc0ZhY3RvcnksIE5PX1BBUkVOVF9JTkpFQ1RPUiwgTm9kZUluamVjdG9yRmFjdG9yeSwgTm9kZUluamVjdG9yT2Zmc2V0LCBSZWxhdGl2ZUluamVjdG9yTG9jYXRpb24sIFJlbGF0aXZlSW5qZWN0b3JMb2NhdGlvbkZsYWdzfSBmcm9tICcuL2ludGVyZmFjZXMvaW5qZWN0b3InO1xuaW1wb3J0IHtBdHRyaWJ1dGVNYXJrZXIsIFRDb250YWluZXJOb2RlLCBURGlyZWN0aXZlSG9zdE5vZGUsIFRFbGVtZW50Q29udGFpbmVyTm9kZSwgVEVsZW1lbnROb2RlLCBUTm9kZSwgVE5vZGVQcm92aWRlckluZGV4ZXMsIFROb2RlVHlwZX0gZnJvbSAnLi9pbnRlcmZhY2VzL25vZGUnO1xuaW1wb3J0IHtpc0NvbXBvbmVudERlZiwgaXNDb21wb25lbnRIb3N0fSBmcm9tICcuL2ludGVyZmFjZXMvdHlwZV9jaGVja3MnO1xuaW1wb3J0IHtERUNMQVJBVElPTl9DT01QT05FTlRfVklFVywgREVDTEFSQVRJT05fVklFVywgSU5KRUNUT1IsIExWaWV3LCBUX0hPU1QsIFREYXRhLCBUVklFVywgVFZpZXcsIFRWaWV3VHlwZX0gZnJvbSAnLi9pbnRlcmZhY2VzL3ZpZXcnO1xuaW1wb3J0IHthc3NlcnRUTm9kZVR5cGV9IGZyb20gJy4vbm9kZV9hc3NlcnQnO1xuaW1wb3J0IHtlbnRlckRJLCBnZXRDdXJyZW50VE5vZGUsIGdldExWaWV3LCBsZWF2ZURJfSBmcm9tICcuL3N0YXRlJztcbmltcG9ydCB7aXNOYW1lT25seUF0dHJpYnV0ZU1hcmtlcn0gZnJvbSAnLi91dGlsL2F0dHJzX3V0aWxzJztcbmltcG9ydCB7Z2V0UGFyZW50SW5qZWN0b3JJbmRleCwgZ2V0UGFyZW50SW5qZWN0b3JWaWV3LCBoYXNQYXJlbnRJbmplY3Rvcn0gZnJvbSAnLi91dGlsL2luamVjdG9yX3V0aWxzJztcbmltcG9ydCB7c3RyaW5naWZ5Rm9yRXJyb3J9IGZyb20gJy4vdXRpbC9zdHJpbmdpZnlfdXRpbHMnO1xuXG5cblxuLyoqXG4gKiBEZWZpbmVzIGlmIHRoZSBjYWxsIHRvIGBpbmplY3RgIHNob3VsZCBpbmNsdWRlIGB2aWV3UHJvdmlkZXJzYCBpbiBpdHMgcmVzb2x1dGlvbi5cbiAqXG4gKiBUaGlzIGlzIHNldCB0byB0cnVlIHdoZW4gd2UgdHJ5IHRvIGluc3RhbnRpYXRlIGEgY29tcG9uZW50LiBUaGlzIHZhbHVlIGlzIHJlc2V0IGluXG4gKiBgZ2V0Tm9kZUluamVjdGFibGVgIHRvIGEgdmFsdWUgd2hpY2ggbWF0Y2hlcyB0aGUgZGVjbGFyYXRpb24gbG9jYXRpb24gb2YgdGhlIHRva2VuIGFib3V0IHRvIGJlXG4gKiBpbnN0YW50aWF0ZWQuIFRoaXMgaXMgZG9uZSBzbyB0aGF0IGlmIHdlIGFyZSBpbmplY3RpbmcgYSB0b2tlbiB3aGljaCB3YXMgZGVjbGFyZWQgb3V0c2lkZSBvZlxuICogYHZpZXdQcm92aWRlcnNgIHdlIGRvbid0IGFjY2lkZW50YWxseSBwdWxsIGB2aWV3UHJvdmlkZXJzYCBpbi5cbiAqXG4gKiBFeGFtcGxlOlxuICpcbiAqIGBgYFxuICogQEluamVjdGFibGUoKVxuICogY2xhc3MgTXlTZXJ2aWNlIHtcbiAqICAgY29uc3RydWN0b3IocHVibGljIHZhbHVlOiBTdHJpbmcpIHt9XG4gKiB9XG4gKlxuICogQENvbXBvbmVudCh7XG4gKiAgIHByb3ZpZGVyczogW1xuICogICAgIE15U2VydmljZSxcbiAqICAgICB7cHJvdmlkZTogU3RyaW5nLCB2YWx1ZTogJ3Byb3ZpZGVycycgfVxuICogICBdXG4gKiAgIHZpZXdQcm92aWRlcnM6IFtcbiAqICAgICB7cHJvdmlkZTogU3RyaW5nLCB2YWx1ZTogJ3ZpZXdQcm92aWRlcnMnfVxuICogICBdXG4gKiB9KVxuICogY2xhc3MgTXlDb21wb25lbnQge1xuICogICBjb25zdHJ1Y3RvcihteVNlcnZpY2U6IE15U2VydmljZSwgdmFsdWU6IFN0cmluZykge1xuICogICAgIC8vIFdlIGV4cGVjdCB0aGF0IENvbXBvbmVudCBjYW4gc2VlIGludG8gYHZpZXdQcm92aWRlcnNgLlxuICogICAgIGV4cGVjdCh2YWx1ZSkudG9FcXVhbCgndmlld1Byb3ZpZGVycycpO1xuICogICAgIC8vIGBNeVNlcnZpY2VgIHdhcyBub3QgZGVjbGFyZWQgaW4gYHZpZXdQcm92aWRlcnNgIGhlbmNlIGl0IGNhbid0IHNlZSBpdC5cbiAqICAgICBleHBlY3QobXlTZXJ2aWNlLnZhbHVlKS50b0VxdWFsKCdwcm92aWRlcnMnKTtcbiAqICAgfVxuICogfVxuICpcbiAqIGBgYFxuICovXG5sZXQgaW5jbHVkZVZpZXdQcm92aWRlcnMgPSB0cnVlO1xuXG5leHBvcnQgZnVuY3Rpb24gc2V0SW5jbHVkZVZpZXdQcm92aWRlcnModjogYm9vbGVhbik6IGJvb2xlYW4ge1xuICBjb25zdCBvbGRWYWx1ZSA9IGluY2x1ZGVWaWV3UHJvdmlkZXJzO1xuICBpbmNsdWRlVmlld1Byb3ZpZGVycyA9IHY7XG4gIHJldHVybiBvbGRWYWx1ZTtcbn1cblxuLyoqXG4gKiBUaGUgbnVtYmVyIG9mIHNsb3RzIGluIGVhY2ggYmxvb20gZmlsdGVyICh1c2VkIGJ5IERJKS4gVGhlIGxhcmdlciB0aGlzIG51bWJlciwgdGhlIGZld2VyXG4gKiBkaXJlY3RpdmVzIHRoYXQgd2lsbCBzaGFyZSBzbG90cywgYW5kIHRodXMsIHRoZSBmZXdlciBmYWxzZSBwb3NpdGl2ZXMgd2hlbiBjaGVja2luZyBmb3JcbiAqIHRoZSBleGlzdGVuY2Ugb2YgYSBkaXJlY3RpdmUuXG4gKi9cbmNvbnN0IEJMT09NX1NJWkUgPSAyNTY7XG5jb25zdCBCTE9PTV9NQVNLID0gQkxPT01fU0laRSAtIDE7XG5cbi8qKlxuICogVGhlIG51bWJlciBvZiBiaXRzIHRoYXQgaXMgcmVwcmVzZW50ZWQgYnkgYSBzaW5nbGUgYmxvb20gYnVja2V0LiBKUyBiaXQgb3BlcmF0aW9ucyBhcmUgMzIgYml0cyxcbiAqIHNvIGVhY2ggYnVja2V0IHJlcHJlc2VudHMgMzIgZGlzdGluY3QgdG9rZW5zIHdoaWNoIGFjY291bnRzIGZvciBsb2cyKDMyKSA9IDUgYml0cyBvZiBhIGJsb29tIGhhc2hcbiAqIG51bWJlci5cbiAqL1xuY29uc3QgQkxPT01fQlVDS0VUX0JJVFMgPSA1O1xuXG4vKiogQ291bnRlciB1c2VkIHRvIGdlbmVyYXRlIHVuaXF1ZSBJRHMgZm9yIGRpcmVjdGl2ZXMuICovXG5sZXQgbmV4dE5nRWxlbWVudElkID0gMDtcblxuLyoqXG4gKiBSZWdpc3RlcnMgdGhpcyBkaXJlY3RpdmUgYXMgcHJlc2VudCBpbiBpdHMgbm9kZSdzIGluamVjdG9yIGJ5IGZsaXBwaW5nIHRoZSBkaXJlY3RpdmUnc1xuICogY29ycmVzcG9uZGluZyBiaXQgaW4gdGhlIGluamVjdG9yJ3MgYmxvb20gZmlsdGVyLlxuICpcbiAqIEBwYXJhbSBpbmplY3RvckluZGV4IFRoZSBpbmRleCBvZiB0aGUgbm9kZSBpbmplY3RvciB3aGVyZSB0aGlzIHRva2VuIHNob3VsZCBiZSByZWdpc3RlcmVkXG4gKiBAcGFyYW0gdFZpZXcgVGhlIFRWaWV3IGZvciB0aGUgaW5qZWN0b3IncyBibG9vbSBmaWx0ZXJzXG4gKiBAcGFyYW0gdHlwZSBUaGUgZGlyZWN0aXZlIHRva2VuIHRvIHJlZ2lzdGVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBibG9vbUFkZChcbiAgICBpbmplY3RvckluZGV4OiBudW1iZXIsIHRWaWV3OiBUVmlldywgdHlwZTogUHJvdmlkZXJUb2tlbjxhbnk+fHN0cmluZyk6IHZvaWQge1xuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0RXF1YWwodFZpZXcuZmlyc3RDcmVhdGVQYXNzLCB0cnVlLCAnZXhwZWN0ZWQgZmlyc3RDcmVhdGVQYXNzIHRvIGJlIHRydWUnKTtcbiAgbGV0IGlkOiBudW1iZXJ8dW5kZWZpbmVkO1xuICBpZiAodHlwZW9mIHR5cGUgPT09ICdzdHJpbmcnKSB7XG4gICAgaWQgPSB0eXBlLmNoYXJDb2RlQXQoMCkgfHwgMDtcbiAgfSBlbHNlIGlmICh0eXBlLmhhc093blByb3BlcnR5KE5HX0VMRU1FTlRfSUQpKSB7XG4gICAgaWQgPSAodHlwZSBhcyBhbnkpW05HX0VMRU1FTlRfSURdO1xuICB9XG5cbiAgLy8gU2V0IGEgdW5pcXVlIElEIG9uIHRoZSBkaXJlY3RpdmUgdHlwZSwgc28gaWYgc29tZXRoaW5nIHRyaWVzIHRvIGluamVjdCB0aGUgZGlyZWN0aXZlLFxuICAvLyB3ZSBjYW4gZWFzaWx5IHJldHJpZXZlIHRoZSBJRCBhbmQgaGFzaCBpdCBpbnRvIHRoZSBibG9vbSBiaXQgdGhhdCBzaG91bGQgYmUgY2hlY2tlZC5cbiAgaWYgKGlkID09IG51bGwpIHtcbiAgICBpZCA9ICh0eXBlIGFzIGFueSlbTkdfRUxFTUVOVF9JRF0gPSBuZXh0TmdFbGVtZW50SWQrKztcbiAgfVxuXG4gIC8vIFdlIG9ubHkgaGF2ZSBCTE9PTV9TSVpFICgyNTYpIHNsb3RzIGluIG91ciBibG9vbSBmaWx0ZXIgKDggYnVja2V0cyAqIDMyIGJpdHMgZWFjaCksXG4gIC8vIHNvIGFsbCB1bmlxdWUgSURzIG11c3QgYmUgbW9kdWxvLWVkIGludG8gYSBudW1iZXIgZnJvbSAwIC0gMjU1IHRvIGZpdCBpbnRvIHRoZSBmaWx0ZXIuXG4gIGNvbnN0IGJsb29tSGFzaCA9IGlkICYgQkxPT01fTUFTSztcblxuICAvLyBDcmVhdGUgYSBtYXNrIHRoYXQgdGFyZ2V0cyB0aGUgc3BlY2lmaWMgYml0IGFzc29jaWF0ZWQgd2l0aCB0aGUgZGlyZWN0aXZlLlxuICAvLyBKUyBiaXQgb3BlcmF0aW9ucyBhcmUgMzIgYml0cywgc28gdGhpcyB3aWxsIGJlIGEgbnVtYmVyIGJldHdlZW4gMl4wIGFuZCAyXjMxLCBjb3JyZXNwb25kaW5nXG4gIC8vIHRvIGJpdCBwb3NpdGlvbnMgMCAtIDMxIGluIGEgMzIgYml0IGludGVnZXIuXG4gIGNvbnN0IG1hc2sgPSAxIDw8IGJsb29tSGFzaDtcblxuICAvLyBFYWNoIGJsb29tIGJ1Y2tldCBpbiBgdERhdGFgIHJlcHJlc2VudHMgYEJMT09NX0JVQ0tFVF9CSVRTYCBudW1iZXIgb2YgYml0cyBvZiBgYmxvb21IYXNoYC5cbiAgLy8gQW55IGJpdHMgaW4gYGJsb29tSGFzaGAgYmV5b25kIGBCTE9PTV9CVUNLRVRfQklUU2AgaW5kaWNhdGUgdGhlIGJ1Y2tldCBvZmZzZXQgdGhhdCB0aGUgbWFza1xuICAvLyBzaG91bGQgYmUgd3JpdHRlbiB0by5cbiAgKHRWaWV3LmRhdGEgYXMgbnVtYmVyW10pW2luamVjdG9ySW5kZXggKyAoYmxvb21IYXNoID4+IEJMT09NX0JVQ0tFVF9CSVRTKV0gfD0gbWFzaztcbn1cblxuLyoqXG4gKiBDcmVhdGVzIChvciBnZXRzIGFuIGV4aXN0aW5nKSBpbmplY3RvciBmb3IgYSBnaXZlbiBlbGVtZW50IG9yIGNvbnRhaW5lci5cbiAqXG4gKiBAcGFyYW0gdE5vZGUgZm9yIHdoaWNoIGFuIGluamVjdG9yIHNob3VsZCBiZSByZXRyaWV2ZWQgLyBjcmVhdGVkLlxuICogQHBhcmFtIGxWaWV3IFZpZXcgd2hlcmUgdGhlIG5vZGUgaXMgc3RvcmVkXG4gKiBAcmV0dXJucyBOb2RlIGluamVjdG9yXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRPckNyZWF0ZU5vZGVJbmplY3RvckZvck5vZGUoXG4gICAgdE5vZGU6IFRFbGVtZW50Tm9kZXxUQ29udGFpbmVyTm9kZXxURWxlbWVudENvbnRhaW5lck5vZGUsIGxWaWV3OiBMVmlldyk6IG51bWJlciB7XG4gIGNvbnN0IGV4aXN0aW5nSW5qZWN0b3JJbmRleCA9IGdldEluamVjdG9ySW5kZXgodE5vZGUsIGxWaWV3KTtcbiAgaWYgKGV4aXN0aW5nSW5qZWN0b3JJbmRleCAhPT0gLTEpIHtcbiAgICByZXR1cm4gZXhpc3RpbmdJbmplY3RvckluZGV4O1xuICB9XG5cbiAgY29uc3QgdFZpZXcgPSBsVmlld1tUVklFV107XG4gIGlmICh0Vmlldy5maXJzdENyZWF0ZVBhc3MpIHtcbiAgICB0Tm9kZS5pbmplY3RvckluZGV4ID0gbFZpZXcubGVuZ3RoO1xuICAgIGluc2VydEJsb29tKHRWaWV3LmRhdGEsIHROb2RlKTsgIC8vIGZvdW5kYXRpb24gZm9yIG5vZGUgYmxvb21cbiAgICBpbnNlcnRCbG9vbShsVmlldywgbnVsbCk7ICAgICAgICAvLyBmb3VuZGF0aW9uIGZvciBjdW11bGF0aXZlIGJsb29tXG4gICAgaW5zZXJ0Qmxvb20odFZpZXcuYmx1ZXByaW50LCBudWxsKTtcbiAgfVxuXG4gIGNvbnN0IHBhcmVudExvYyA9IGdldFBhcmVudEluamVjdG9yTG9jYXRpb24odE5vZGUsIGxWaWV3KTtcbiAgY29uc3QgaW5qZWN0b3JJbmRleCA9IHROb2RlLmluamVjdG9ySW5kZXg7XG5cbiAgLy8gSWYgYSBwYXJlbnQgaW5qZWN0b3IgY2FuJ3QgYmUgZm91bmQsIGl0cyBsb2NhdGlvbiBpcyBzZXQgdG8gLTEuXG4gIC8vIEluIHRoYXQgY2FzZSwgd2UgZG9uJ3QgbmVlZCB0byBzZXQgdXAgYSBjdW11bGF0aXZlIGJsb29tXG4gIGlmIChoYXNQYXJlbnRJbmplY3RvcihwYXJlbnRMb2MpKSB7XG4gICAgY29uc3QgcGFyZW50SW5kZXggPSBnZXRQYXJlbnRJbmplY3RvckluZGV4KHBhcmVudExvYyk7XG4gICAgY29uc3QgcGFyZW50TFZpZXcgPSBnZXRQYXJlbnRJbmplY3RvclZpZXcocGFyZW50TG9jLCBsVmlldyk7XG4gICAgY29uc3QgcGFyZW50RGF0YSA9IHBhcmVudExWaWV3W1RWSUVXXS5kYXRhIGFzIGFueTtcbiAgICAvLyBDcmVhdGVzIGEgY3VtdWxhdGl2ZSBibG9vbSBmaWx0ZXIgdGhhdCBtZXJnZXMgdGhlIHBhcmVudCdzIGJsb29tIGZpbHRlclxuICAgIC8vIGFuZCBpdHMgb3duIGN1bXVsYXRpdmUgYmxvb20gKHdoaWNoIGNvbnRhaW5zIHRva2VucyBmb3IgYWxsIGFuY2VzdG9ycylcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IE5vZGVJbmplY3Rvck9mZnNldC5CTE9PTV9TSVpFOyBpKyspIHtcbiAgICAgIGxWaWV3W2luamVjdG9ySW5kZXggKyBpXSA9IHBhcmVudExWaWV3W3BhcmVudEluZGV4ICsgaV0gfCBwYXJlbnREYXRhW3BhcmVudEluZGV4ICsgaV07XG4gICAgfVxuICB9XG5cbiAgbFZpZXdbaW5qZWN0b3JJbmRleCArIE5vZGVJbmplY3Rvck9mZnNldC5QQVJFTlRdID0gcGFyZW50TG9jO1xuICByZXR1cm4gaW5qZWN0b3JJbmRleDtcbn1cblxuZnVuY3Rpb24gaW5zZXJ0Qmxvb20oYXJyOiBhbnlbXSwgZm9vdGVyOiBUTm9kZXxudWxsKTogdm9pZCB7XG4gIGFyci5wdXNoKDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIGZvb3Rlcik7XG59XG5cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEluamVjdG9ySW5kZXgodE5vZGU6IFROb2RlLCBsVmlldzogTFZpZXcpOiBudW1iZXIge1xuICBpZiAodE5vZGUuaW5qZWN0b3JJbmRleCA9PT0gLTEgfHxcbiAgICAgIC8vIElmIHRoZSBpbmplY3RvciBpbmRleCBpcyB0aGUgc2FtZSBhcyBpdHMgcGFyZW50J3MgaW5qZWN0b3IgaW5kZXgsIHRoZW4gdGhlIGluZGV4IGhhcyBiZWVuXG4gICAgICAvLyBjb3BpZWQgZG93biBmcm9tIHRoZSBwYXJlbnQgbm9kZS4gTm8gaW5qZWN0b3IgaGFzIGJlZW4gY3JlYXRlZCB5ZXQgb24gdGhpcyBub2RlLlxuICAgICAgKHROb2RlLnBhcmVudCAmJiB0Tm9kZS5wYXJlbnQuaW5qZWN0b3JJbmRleCA9PT0gdE5vZGUuaW5qZWN0b3JJbmRleCkgfHxcbiAgICAgIC8vIEFmdGVyIHRoZSBmaXJzdCB0ZW1wbGF0ZSBwYXNzLCB0aGUgaW5qZWN0b3IgaW5kZXggbWlnaHQgZXhpc3QgYnV0IHRoZSBwYXJlbnQgdmFsdWVzXG4gICAgICAvLyBtaWdodCBub3QgaGF2ZSBiZWVuIGNhbGN1bGF0ZWQgeWV0IGZvciB0aGlzIGluc3RhbmNlXG4gICAgICBsVmlld1t0Tm9kZS5pbmplY3RvckluZGV4ICsgTm9kZUluamVjdG9yT2Zmc2V0LlBBUkVOVF0gPT09IG51bGwpIHtcbiAgICByZXR1cm4gLTE7XG4gIH0gZWxzZSB7XG4gICAgbmdEZXZNb2RlICYmIGFzc2VydEluZGV4SW5SYW5nZShsVmlldywgdE5vZGUuaW5qZWN0b3JJbmRleCk7XG4gICAgcmV0dXJuIHROb2RlLmluamVjdG9ySW5kZXg7XG4gIH1cbn1cblxuLyoqXG4gKiBGaW5kcyB0aGUgaW5kZXggb2YgdGhlIHBhcmVudCBpbmplY3Rvciwgd2l0aCBhIHZpZXcgb2Zmc2V0IGlmIGFwcGxpY2FibGUuIFVzZWQgdG8gc2V0IHRoZVxuICogcGFyZW50IGluamVjdG9yIGluaXRpYWxseS5cbiAqXG4gKiBAcmV0dXJucyBSZXR1cm5zIGEgbnVtYmVyIHRoYXQgaXMgdGhlIGNvbWJpbmF0aW9uIG9mIHRoZSBudW1iZXIgb2YgTFZpZXdzIHRoYXQgd2UgaGF2ZSB0byBnbyB1cFxuICogdG8gZmluZCB0aGUgTFZpZXcgY29udGFpbmluZyB0aGUgcGFyZW50IGluamVjdCBBTkQgdGhlIGluZGV4IG9mIHRoZSBpbmplY3RvciB3aXRoaW4gdGhhdCBMVmlldy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFBhcmVudEluamVjdG9yTG9jYXRpb24odE5vZGU6IFROb2RlLCBsVmlldzogTFZpZXcpOiBSZWxhdGl2ZUluamVjdG9yTG9jYXRpb24ge1xuICBpZiAodE5vZGUucGFyZW50ICYmIHROb2RlLnBhcmVudC5pbmplY3RvckluZGV4ICE9PSAtMSkge1xuICAgIC8vIElmIHdlIGhhdmUgYSBwYXJlbnQgYFROb2RlYCBhbmQgdGhlcmUgaXMgYW4gaW5qZWN0b3IgYXNzb2NpYXRlZCB3aXRoIGl0IHdlIGFyZSBkb25lLCBiZWNhdXNlXG4gICAgLy8gdGhlIHBhcmVudCBpbmplY3RvciBpcyB3aXRoaW4gdGhlIGN1cnJlbnQgYExWaWV3YC5cbiAgICByZXR1cm4gdE5vZGUucGFyZW50LmluamVjdG9ySW5kZXggYXMgYW55OyAgLy8gVmlld09mZnNldCBpcyAwXG4gIH1cblxuICAvLyBXaGVuIHBhcmVudCBpbmplY3RvciBsb2NhdGlvbiBpcyBjb21wdXRlZCBpdCBtYXkgYmUgb3V0c2lkZSBvZiB0aGUgY3VycmVudCB2aWV3LiAoaWUgaXQgY291bGRcbiAgLy8gYmUgcG9pbnRpbmcgdG8gYSBkZWNsYXJlZCBwYXJlbnQgbG9jYXRpb24pLiBUaGlzIHZhcmlhYmxlIHN0b3JlcyBudW1iZXIgb2YgZGVjbGFyYXRpb24gcGFyZW50c1xuICAvLyB3ZSBuZWVkIHRvIHdhbGsgdXAgaW4gb3JkZXIgdG8gZmluZCB0aGUgcGFyZW50IGluamVjdG9yIGxvY2F0aW9uLlxuICBsZXQgZGVjbGFyYXRpb25WaWV3T2Zmc2V0ID0gMDtcbiAgbGV0IHBhcmVudFROb2RlOiBUTm9kZXxudWxsID0gbnVsbDtcbiAgbGV0IGxWaWV3Q3Vyc29yOiBMVmlld3xudWxsID0gbFZpZXc7XG5cbiAgLy8gVGhlIHBhcmVudCBpbmplY3RvciBpcyBub3QgaW4gdGhlIGN1cnJlbnQgYExWaWV3YC4gV2Ugd2lsbCBoYXZlIHRvIHdhbGsgdGhlIGRlY2xhcmVkIHBhcmVudFxuICAvLyBgTFZpZXdgIGhpZXJhcmNoeSBhbmQgbG9vayBmb3IgaXQuIElmIHdlIHdhbGsgb2YgdGhlIHRvcCwgdGhhdCBtZWFucyB0aGF0IHRoZXJlIGlzIG5vIHBhcmVudFxuICAvLyBgTm9kZUluamVjdG9yYC5cbiAgd2hpbGUgKGxWaWV3Q3Vyc29yICE9PSBudWxsKSB7XG4gICAgLy8gRmlyc3QgZGV0ZXJtaW5lIHRoZSBgcGFyZW50VE5vZGVgIGxvY2F0aW9uLiBUaGUgcGFyZW50IHBvaW50ZXIgZGlmZmVycyBiYXNlZCBvbiBgVFZpZXcudHlwZWAuXG4gICAgY29uc3QgdFZpZXcgPSBsVmlld0N1cnNvcltUVklFV107XG4gICAgY29uc3QgdFZpZXdUeXBlID0gdFZpZXcudHlwZTtcbiAgICBpZiAodFZpZXdUeXBlID09PSBUVmlld1R5cGUuRW1iZWRkZWQpIHtcbiAgICAgIG5nRGV2TW9kZSAmJlxuICAgICAgICAgIGFzc2VydERlZmluZWQodFZpZXcuZGVjbFROb2RlLCAnRW1iZWRkZWQgVE5vZGVzIHNob3VsZCBoYXZlIGRlY2xhcmF0aW9uIHBhcmVudHMuJyk7XG4gICAgICBwYXJlbnRUTm9kZSA9IHRWaWV3LmRlY2xUTm9kZTtcbiAgICB9IGVsc2UgaWYgKHRWaWV3VHlwZSA9PT0gVFZpZXdUeXBlLkNvbXBvbmVudCkge1xuICAgICAgLy8gQ29tcG9uZW50cyBkb24ndCBoYXZlIGBUVmlldy5kZWNsVE5vZGVgIGJlY2F1c2UgZWFjaCBpbnN0YW5jZSBvZiBjb21wb25lbnQgY291bGQgYmVcbiAgICAgIC8vIGluc2VydGVkIGluIGRpZmZlcmVudCBsb2NhdGlvbiwgaGVuY2UgYFRWaWV3LmRlY2xUTm9kZWAgaXMgbWVhbmluZ2xlc3MuXG4gICAgICBwYXJlbnRUTm9kZSA9IGxWaWV3Q3Vyc29yW1RfSE9TVF07XG4gICAgfSBlbHNlIHtcbiAgICAgIG5nRGV2TW9kZSAmJiBhc3NlcnRFcXVhbCh0Vmlldy50eXBlLCBUVmlld1R5cGUuUm9vdCwgJ1Jvb3QgdHlwZSBleHBlY3RlZCcpO1xuICAgICAgcGFyZW50VE5vZGUgPSBudWxsO1xuICAgIH1cbiAgICBpZiAocGFyZW50VE5vZGUgPT09IG51bGwpIHtcbiAgICAgIC8vIElmIHdlIGhhdmUgbm8gcGFyZW50LCB0aGFuIHdlIGFyZSBkb25lLlxuICAgICAgcmV0dXJuIE5PX1BBUkVOVF9JTkpFQ1RPUjtcbiAgICB9XG5cbiAgICBuZ0Rldk1vZGUgJiYgcGFyZW50VE5vZGUgJiYgYXNzZXJ0VE5vZGVGb3JMVmlldyhwYXJlbnRUTm9kZSEsIGxWaWV3Q3Vyc29yW0RFQ0xBUkFUSU9OX1ZJRVddISk7XG4gICAgLy8gRXZlcnkgaXRlcmF0aW9uIG9mIHRoZSBsb29wIHJlcXVpcmVzIHRoYXQgd2UgZ28gdG8gdGhlIGRlY2xhcmVkIHBhcmVudC5cbiAgICBkZWNsYXJhdGlvblZpZXdPZmZzZXQrKztcbiAgICBsVmlld0N1cnNvciA9IGxWaWV3Q3Vyc29yW0RFQ0xBUkFUSU9OX1ZJRVddO1xuXG4gICAgaWYgKHBhcmVudFROb2RlLmluamVjdG9ySW5kZXggIT09IC0xKSB7XG4gICAgICAvLyBXZSBmb3VuZCBhIE5vZGVJbmplY3RvciB3aGljaCBwb2ludHMgdG8gc29tZXRoaW5nLlxuICAgICAgcmV0dXJuIChwYXJlbnRUTm9kZS5pbmplY3RvckluZGV4IHxcbiAgICAgICAgICAgICAgKGRlY2xhcmF0aW9uVmlld09mZnNldCA8PCBSZWxhdGl2ZUluamVjdG9yTG9jYXRpb25GbGFncy5WaWV3T2Zmc2V0U2hpZnQpKSBhcyBhbnk7XG4gICAgfVxuICB9XG4gIHJldHVybiBOT19QQVJFTlRfSU5KRUNUT1I7XG59XG4vKipcbiAqIE1ha2VzIGEgdHlwZSBvciBhbiBpbmplY3Rpb24gdG9rZW4gcHVibGljIHRvIHRoZSBESSBzeXN0ZW0gYnkgYWRkaW5nIGl0IHRvIGFuXG4gKiBpbmplY3RvcidzIGJsb29tIGZpbHRlci5cbiAqXG4gKiBAcGFyYW0gZGkgVGhlIG5vZGUgaW5qZWN0b3IgaW4gd2hpY2ggYSBkaXJlY3RpdmUgd2lsbCBiZSBhZGRlZFxuICogQHBhcmFtIHRva2VuIFRoZSB0eXBlIG9yIHRoZSBpbmplY3Rpb24gdG9rZW4gdG8gYmUgbWFkZSBwdWJsaWNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRpUHVibGljSW5JbmplY3RvcihcbiAgICBpbmplY3RvckluZGV4OiBudW1iZXIsIHRWaWV3OiBUVmlldywgdG9rZW46IFByb3ZpZGVyVG9rZW48YW55Pik6IHZvaWQge1xuICBibG9vbUFkZChpbmplY3RvckluZGV4LCB0VmlldywgdG9rZW4pO1xufVxuXG4vKipcbiAqIEluamVjdCBzdGF0aWMgYXR0cmlidXRlIHZhbHVlIGludG8gZGlyZWN0aXZlIGNvbnN0cnVjdG9yLlxuICpcbiAqIFRoaXMgbWV0aG9kIGlzIHVzZWQgd2l0aCBgZmFjdG9yeWAgZnVuY3Rpb25zIHdoaWNoIGFyZSBnZW5lcmF0ZWQgYXMgcGFydCBvZlxuICogYGRlZmluZURpcmVjdGl2ZWAgb3IgYGRlZmluZUNvbXBvbmVudGAuIFRoZSBtZXRob2QgcmV0cmlldmVzIHRoZSBzdGF0aWMgdmFsdWVcbiAqIG9mIGFuIGF0dHJpYnV0ZS4gKER5bmFtaWMgYXR0cmlidXRlcyBhcmUgbm90IHN1cHBvcnRlZCBzaW5jZSB0aGV5IGFyZSBub3QgcmVzb2x2ZWRcbiAqICBhdCB0aGUgdGltZSBvZiBpbmplY3Rpb24gYW5kIGNhbiBjaGFuZ2Ugb3ZlciB0aW1lLilcbiAqXG4gKiAjIEV4YW1wbGVcbiAqIEdpdmVuOlxuICogYGBgXG4gKiBAQ29tcG9uZW50KC4uLilcbiAqIGNsYXNzIE15Q29tcG9uZW50IHtcbiAqICAgY29uc3RydWN0b3IoQEF0dHJpYnV0ZSgndGl0bGUnKSB0aXRsZTogc3RyaW5nKSB7IC4uLiB9XG4gKiB9XG4gKiBgYGBcbiAqIFdoZW4gaW5zdGFudGlhdGVkIHdpdGhcbiAqIGBgYFxuICogPG15LWNvbXBvbmVudCB0aXRsZT1cIkhlbGxvXCI+PC9teS1jb21wb25lbnQ+XG4gKiBgYGBcbiAqXG4gKiBUaGVuIGZhY3RvcnkgbWV0aG9kIGdlbmVyYXRlZCBpczpcbiAqIGBgYFxuICogTXlDb21wb25lbnQuybVjbXAgPSBkZWZpbmVDb21wb25lbnQoe1xuICogICBmYWN0b3J5OiAoKSA9PiBuZXcgTXlDb21wb25lbnQoaW5qZWN0QXR0cmlidXRlKCd0aXRsZScpKVxuICogICAuLi5cbiAqIH0pXG4gKiBgYGBcbiAqXG4gKiBAcHVibGljQXBpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbmplY3RBdHRyaWJ1dGVJbXBsKHROb2RlOiBUTm9kZSwgYXR0ck5hbWVUb0luamVjdDogc3RyaW5nKTogc3RyaW5nfG51bGwge1xuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0VE5vZGVUeXBlKHROb2RlLCBUTm9kZVR5cGUuQW55Q29udGFpbmVyIHwgVE5vZGVUeXBlLkFueVJOb2RlKTtcbiAgbmdEZXZNb2RlICYmIGFzc2VydERlZmluZWQodE5vZGUsICdleHBlY3RpbmcgdE5vZGUnKTtcbiAgaWYgKGF0dHJOYW1lVG9JbmplY3QgPT09ICdjbGFzcycpIHtcbiAgICByZXR1cm4gdE5vZGUuY2xhc3NlcztcbiAgfVxuICBpZiAoYXR0ck5hbWVUb0luamVjdCA9PT0gJ3N0eWxlJykge1xuICAgIHJldHVybiB0Tm9kZS5zdHlsZXM7XG4gIH1cblxuICBjb25zdCBhdHRycyA9IHROb2RlLmF0dHJzO1xuICBpZiAoYXR0cnMpIHtcbiAgICBjb25zdCBhdHRyc0xlbmd0aCA9IGF0dHJzLmxlbmd0aDtcbiAgICBsZXQgaSA9IDA7XG4gICAgd2hpbGUgKGkgPCBhdHRyc0xlbmd0aCkge1xuICAgICAgY29uc3QgdmFsdWUgPSBhdHRyc1tpXTtcblxuICAgICAgLy8gSWYgd2UgaGl0IGEgYEJpbmRpbmdzYCBvciBgVGVtcGxhdGVgIG1hcmtlciB0aGVuIHdlIGFyZSBkb25lLlxuICAgICAgaWYgKGlzTmFtZU9ubHlBdHRyaWJ1dGVNYXJrZXIodmFsdWUpKSBicmVhaztcblxuICAgICAgLy8gU2tpcCBuYW1lc3BhY2VkIGF0dHJpYnV0ZXNcbiAgICAgIGlmICh2YWx1ZSA9PT0gQXR0cmlidXRlTWFya2VyLk5hbWVzcGFjZVVSSSkge1xuICAgICAgICAvLyB3ZSBza2lwIHRoZSBuZXh0IHR3byB2YWx1ZXNcbiAgICAgICAgLy8gYXMgbmFtZXNwYWNlZCBhdHRyaWJ1dGVzIGxvb2tzIGxpa2VcbiAgICAgICAgLy8gWy4uLiwgQXR0cmlidXRlTWFya2VyLk5hbWVzcGFjZVVSSSwgJ2h0dHA6Ly9zb21ldXJpLmNvbS90ZXN0JywgJ3Rlc3Q6ZXhpc3QnLFxuICAgICAgICAvLyAnZXhpc3RWYWx1ZScsIC4uLl1cbiAgICAgICAgaSA9IGkgKyAyO1xuICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgICAgIC8vIFNraXAgdG8gdGhlIGZpcnN0IHZhbHVlIG9mIHRoZSBtYXJrZWQgYXR0cmlidXRlLlxuICAgICAgICBpKys7XG4gICAgICAgIHdoaWxlIChpIDwgYXR0cnNMZW5ndGggJiYgdHlwZW9mIGF0dHJzW2ldID09PSAnc3RyaW5nJykge1xuICAgICAgICAgIGkrKztcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PT0gYXR0ck5hbWVUb0luamVjdCkge1xuICAgICAgICByZXR1cm4gYXR0cnNbaSArIDFdIGFzIHN0cmluZztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGkgPSBpICsgMjtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cblxuZnVuY3Rpb24gbm90Rm91bmRWYWx1ZU9yVGhyb3c8VD4oXG4gICAgbm90Rm91bmRWYWx1ZTogVHxudWxsLCB0b2tlbjogUHJvdmlkZXJUb2tlbjxUPiwgZmxhZ3M6IEluamVjdEZsYWdzKTogVHxudWxsIHtcbiAgaWYgKGZsYWdzICYgSW5qZWN0RmxhZ3MuT3B0aW9uYWwpIHtcbiAgICByZXR1cm4gbm90Rm91bmRWYWx1ZTtcbiAgfSBlbHNlIHtcbiAgICB0aHJvd1Byb3ZpZGVyTm90Rm91bmRFcnJvcih0b2tlbiwgJ05vZGVJbmplY3RvcicpO1xuICB9XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgdmFsdWUgYXNzb2NpYXRlZCB0byB0aGUgZ2l2ZW4gdG9rZW4gZnJvbSB0aGUgTW9kdWxlSW5qZWN0b3Igb3IgdGhyb3dzIGV4Y2VwdGlvblxuICpcbiAqIEBwYXJhbSBsVmlldyBUaGUgYExWaWV3YCB0aGF0IGNvbnRhaW5zIHRoZSBgdE5vZGVgXG4gKiBAcGFyYW0gdG9rZW4gVGhlIHRva2VuIHRvIGxvb2sgZm9yXG4gKiBAcGFyYW0gZmxhZ3MgSW5qZWN0aW9uIGZsYWdzXG4gKiBAcGFyYW0gbm90Rm91bmRWYWx1ZSBUaGUgdmFsdWUgdG8gcmV0dXJuIHdoZW4gdGhlIGluamVjdGlvbiBmbGFncyBpcyBgSW5qZWN0RmxhZ3MuT3B0aW9uYWxgXG4gKiBAcmV0dXJucyB0aGUgdmFsdWUgZnJvbSB0aGUgaW5qZWN0b3Igb3IgdGhyb3dzIGFuIGV4Y2VwdGlvblxuICovXG5mdW5jdGlvbiBsb29rdXBUb2tlblVzaW5nTW9kdWxlSW5qZWN0b3I8VD4oXG4gICAgbFZpZXc6IExWaWV3LCB0b2tlbjogUHJvdmlkZXJUb2tlbjxUPiwgZmxhZ3M6IEluamVjdEZsYWdzLCBub3RGb3VuZFZhbHVlPzogYW55KTogVHxudWxsIHtcbiAgaWYgKGZsYWdzICYgSW5qZWN0RmxhZ3MuT3B0aW9uYWwgJiYgbm90Rm91bmRWYWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgLy8gVGhpcyBtdXN0IGJlIHNldCBvciB0aGUgTnVsbEluamVjdG9yIHdpbGwgdGhyb3cgZm9yIG9wdGlvbmFsIGRlcHNcbiAgICBub3RGb3VuZFZhbHVlID0gbnVsbDtcbiAgfVxuXG4gIGlmICgoZmxhZ3MgJiAoSW5qZWN0RmxhZ3MuU2VsZiB8IEluamVjdEZsYWdzLkhvc3QpKSA9PT0gMCkge1xuICAgIGNvbnN0IG1vZHVsZUluamVjdG9yID0gbFZpZXdbSU5KRUNUT1JdO1xuICAgIC8vIHN3aXRjaCB0byBgaW5qZWN0SW5qZWN0b3JPbmx5YCBpbXBsZW1lbnRhdGlvbiBmb3IgbW9kdWxlIGluamVjdG9yLCBzaW5jZSBtb2R1bGUgaW5qZWN0b3JcbiAgICAvLyBzaG91bGQgbm90IGhhdmUgYWNjZXNzIHRvIENvbXBvbmVudC9EaXJlY3RpdmUgREkgc2NvcGUgKHRoYXQgbWF5IGhhcHBlbiB0aHJvdWdoXG4gICAgLy8gYGRpcmVjdGl2ZUluamVjdGAgaW1wbGVtZW50YXRpb24pXG4gICAgY29uc3QgcHJldmlvdXNJbmplY3RJbXBsZW1lbnRhdGlvbiA9IHNldEluamVjdEltcGxlbWVudGF0aW9uKHVuZGVmaW5lZCk7XG4gICAgdHJ5IHtcbiAgICAgIGlmIChtb2R1bGVJbmplY3Rvcikge1xuICAgICAgICByZXR1cm4gbW9kdWxlSW5qZWN0b3IuZ2V0KHRva2VuLCBub3RGb3VuZFZhbHVlLCBmbGFncyAmIEluamVjdEZsYWdzLk9wdGlvbmFsKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBpbmplY3RSb290TGltcE1vZGUodG9rZW4sIG5vdEZvdW5kVmFsdWUsIGZsYWdzICYgSW5qZWN0RmxhZ3MuT3B0aW9uYWwpO1xuICAgICAgfVxuICAgIH0gZmluYWxseSB7XG4gICAgICBzZXRJbmplY3RJbXBsZW1lbnRhdGlvbihwcmV2aW91c0luamVjdEltcGxlbWVudGF0aW9uKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG5vdEZvdW5kVmFsdWVPclRocm93PFQ+KG5vdEZvdW5kVmFsdWUsIHRva2VuLCBmbGFncyk7XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgdmFsdWUgYXNzb2NpYXRlZCB0byB0aGUgZ2l2ZW4gdG9rZW4gZnJvbSB0aGUgTm9kZUluamVjdG9ycyA9PiBNb2R1bGVJbmplY3Rvci5cbiAqXG4gKiBMb29rIGZvciB0aGUgaW5qZWN0b3IgcHJvdmlkaW5nIHRoZSB0b2tlbiBieSB3YWxraW5nIHVwIHRoZSBub2RlIGluamVjdG9yIHRyZWUgYW5kIHRoZW5cbiAqIHRoZSBtb2R1bGUgaW5qZWN0b3IgdHJlZS5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIHBhdGNoZXMgYHRva2VuYCB3aXRoIGBfX05HX0VMRU1FTlRfSURfX2Agd2hpY2ggY29udGFpbnMgdGhlIGlkIGZvciB0aGUgYmxvb21cbiAqIGZpbHRlci4gYC0xYCBpcyByZXNlcnZlZCBmb3IgaW5qZWN0aW5nIGBJbmplY3RvcmAgKGltcGxlbWVudGVkIGJ5IGBOb2RlSW5qZWN0b3JgKVxuICpcbiAqIEBwYXJhbSB0Tm9kZSBUaGUgTm9kZSB3aGVyZSB0aGUgc2VhcmNoIGZvciB0aGUgaW5qZWN0b3Igc2hvdWxkIHN0YXJ0XG4gKiBAcGFyYW0gbFZpZXcgVGhlIGBMVmlld2AgdGhhdCBjb250YWlucyB0aGUgYHROb2RlYFxuICogQHBhcmFtIHRva2VuIFRoZSB0b2tlbiB0byBsb29rIGZvclxuICogQHBhcmFtIGZsYWdzIEluamVjdGlvbiBmbGFnc1xuICogQHBhcmFtIG5vdEZvdW5kVmFsdWUgVGhlIHZhbHVlIHRvIHJldHVybiB3aGVuIHRoZSBpbmplY3Rpb24gZmxhZ3MgaXMgYEluamVjdEZsYWdzLk9wdGlvbmFsYFxuICogQHJldHVybnMgdGhlIHZhbHVlIGZyb20gdGhlIGluamVjdG9yLCBgbnVsbGAgd2hlbiBub3QgZm91bmQsIG9yIGBub3RGb3VuZFZhbHVlYCBpZiBwcm92aWRlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0T3JDcmVhdGVJbmplY3RhYmxlPFQ+KFxuICAgIHROb2RlOiBURGlyZWN0aXZlSG9zdE5vZGV8bnVsbCwgbFZpZXc6IExWaWV3LCB0b2tlbjogUHJvdmlkZXJUb2tlbjxUPixcbiAgICBmbGFnczogSW5qZWN0RmxhZ3MgPSBJbmplY3RGbGFncy5EZWZhdWx0LCBub3RGb3VuZFZhbHVlPzogYW55KTogVHxudWxsIHtcbiAgaWYgKHROb2RlICE9PSBudWxsKSB7XG4gICAgY29uc3QgYmxvb21IYXNoID0gYmxvb21IYXNoQml0T3JGYWN0b3J5KHRva2VuKTtcbiAgICAvLyBJZiB0aGUgSUQgc3RvcmVkIGhlcmUgaXMgYSBmdW5jdGlvbiwgdGhpcyBpcyBhIHNwZWNpYWwgb2JqZWN0IGxpa2UgRWxlbWVudFJlZiBvciBUZW1wbGF0ZVJlZlxuICAgIC8vIHNvIGp1c3QgY2FsbCB0aGUgZmFjdG9yeSBmdW5jdGlvbiB0byBjcmVhdGUgaXQuXG4gICAgaWYgKHR5cGVvZiBibG9vbUhhc2ggPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIGlmICghZW50ZXJESShsVmlldywgdE5vZGUsIGZsYWdzKSkge1xuICAgICAgICAvLyBGYWlsZWQgdG8gZW50ZXIgREksIHRyeSBtb2R1bGUgaW5qZWN0b3IgaW5zdGVhZC4gSWYgYSB0b2tlbiBpcyBpbmplY3RlZCB3aXRoIHRoZSBASG9zdFxuICAgICAgICAvLyBmbGFnLCB0aGUgbW9kdWxlIGluamVjdG9yIGlzIG5vdCBzZWFyY2hlZCBmb3IgdGhhdCB0b2tlbiBpbiBJdnkuXG4gICAgICAgIHJldHVybiAoZmxhZ3MgJiBJbmplY3RGbGFncy5Ib3N0KSA/XG4gICAgICAgICAgICBub3RGb3VuZFZhbHVlT3JUaHJvdzxUPihub3RGb3VuZFZhbHVlLCB0b2tlbiwgZmxhZ3MpIDpcbiAgICAgICAgICAgIGxvb2t1cFRva2VuVXNpbmdNb2R1bGVJbmplY3RvcjxUPihsVmlldywgdG9rZW4sIGZsYWdzLCBub3RGb3VuZFZhbHVlKTtcbiAgICAgIH1cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gYmxvb21IYXNoKGZsYWdzKTtcbiAgICAgICAgaWYgKHZhbHVlID09IG51bGwgJiYgIShmbGFncyAmIEluamVjdEZsYWdzLk9wdGlvbmFsKSkge1xuICAgICAgICAgIHRocm93UHJvdmlkZXJOb3RGb3VuZEVycm9yKHRva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgIH1cbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGxlYXZlREkoKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBibG9vbUhhc2ggPT09ICdudW1iZXInKSB7XG4gICAgICAvLyBBIHJlZmVyZW5jZSB0byB0aGUgcHJldmlvdXMgaW5qZWN0b3IgVFZpZXcgdGhhdCB3YXMgZm91bmQgd2hpbGUgY2xpbWJpbmcgdGhlIGVsZW1lbnRcbiAgICAgIC8vIGluamVjdG9yIHRyZWUuIFRoaXMgaXMgdXNlZCB0byBrbm93IGlmIHZpZXdQcm92aWRlcnMgY2FuIGJlIGFjY2Vzc2VkIG9uIHRoZSBjdXJyZW50XG4gICAgICAvLyBpbmplY3Rvci5cbiAgICAgIGxldCBwcmV2aW91c1RWaWV3OiBUVmlld3xudWxsID0gbnVsbDtcbiAgICAgIGxldCBpbmplY3RvckluZGV4ID0gZ2V0SW5qZWN0b3JJbmRleCh0Tm9kZSwgbFZpZXcpO1xuICAgICAgbGV0IHBhcmVudExvY2F0aW9uOiBSZWxhdGl2ZUluamVjdG9yTG9jYXRpb24gPSBOT19QQVJFTlRfSU5KRUNUT1I7XG4gICAgICBsZXQgaG9zdFRFbGVtZW50Tm9kZTogVE5vZGV8bnVsbCA9XG4gICAgICAgICAgZmxhZ3MgJiBJbmplY3RGbGFncy5Ib3N0ID8gbFZpZXdbREVDTEFSQVRJT05fQ09NUE9ORU5UX1ZJRVddW1RfSE9TVF0gOiBudWxsO1xuXG4gICAgICAvLyBJZiB3ZSBzaG91bGQgc2tpcCB0aGlzIGluamVjdG9yLCBvciBpZiB0aGVyZSBpcyBubyBpbmplY3RvciBvbiB0aGlzIG5vZGUsIHN0YXJ0IGJ5XG4gICAgICAvLyBzZWFyY2hpbmcgdGhlIHBhcmVudCBpbmplY3Rvci5cbiAgICAgIGlmIChpbmplY3RvckluZGV4ID09PSAtMSB8fCBmbGFncyAmIEluamVjdEZsYWdzLlNraXBTZWxmKSB7XG4gICAgICAgIHBhcmVudExvY2F0aW9uID0gaW5qZWN0b3JJbmRleCA9PT0gLTEgPyBnZXRQYXJlbnRJbmplY3RvckxvY2F0aW9uKHROb2RlLCBsVmlldykgOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbFZpZXdbaW5qZWN0b3JJbmRleCArIE5vZGVJbmplY3Rvck9mZnNldC5QQVJFTlRdO1xuXG4gICAgICAgIGlmIChwYXJlbnRMb2NhdGlvbiA9PT0gTk9fUEFSRU5UX0lOSkVDVE9SIHx8ICFzaG91bGRTZWFyY2hQYXJlbnQoZmxhZ3MsIGZhbHNlKSkge1xuICAgICAgICAgIGluamVjdG9ySW5kZXggPSAtMTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBwcmV2aW91c1RWaWV3ID0gbFZpZXdbVFZJRVddO1xuICAgICAgICAgIGluamVjdG9ySW5kZXggPSBnZXRQYXJlbnRJbmplY3RvckluZGV4KHBhcmVudExvY2F0aW9uKTtcbiAgICAgICAgICBsVmlldyA9IGdldFBhcmVudEluamVjdG9yVmlldyhwYXJlbnRMb2NhdGlvbiwgbFZpZXcpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFRyYXZlcnNlIHVwIHRoZSBpbmplY3RvciB0cmVlIHVudGlsIHdlIGZpbmQgYSBwb3RlbnRpYWwgbWF0Y2ggb3IgdW50aWwgd2Uga25vdyB0aGVyZVxuICAgICAgLy8gKmlzbid0KiBhIG1hdGNoLlxuICAgICAgd2hpbGUgKGluamVjdG9ySW5kZXggIT09IC0xKSB7XG4gICAgICAgIG5nRGV2TW9kZSAmJiBhc3NlcnROb2RlSW5qZWN0b3IobFZpZXcsIGluamVjdG9ySW5kZXgpO1xuXG4gICAgICAgIC8vIENoZWNrIHRoZSBjdXJyZW50IGluamVjdG9yLiBJZiBpdCBtYXRjaGVzLCBzZWUgaWYgaXQgY29udGFpbnMgdG9rZW4uXG4gICAgICAgIGNvbnN0IHRWaWV3ID0gbFZpZXdbVFZJRVddO1xuICAgICAgICBuZ0Rldk1vZGUgJiZcbiAgICAgICAgICAgIGFzc2VydFROb2RlRm9yTFZpZXcoXG4gICAgICAgICAgICAgICAgdFZpZXcuZGF0YVtpbmplY3RvckluZGV4ICsgTm9kZUluamVjdG9yT2Zmc2V0LlROT0RFXSBhcyBUTm9kZSwgbFZpZXcpO1xuICAgICAgICBpZiAoYmxvb21IYXNUb2tlbihibG9vbUhhc2gsIGluamVjdG9ySW5kZXgsIHRWaWV3LmRhdGEpKSB7XG4gICAgICAgICAgLy8gQXQgdGhpcyBwb2ludCwgd2UgaGF2ZSBhbiBpbmplY3RvciB3aGljaCAqbWF5KiBjb250YWluIHRoZSB0b2tlbiwgc28gd2Ugc3RlcCB0aHJvdWdoXG4gICAgICAgICAgLy8gdGhlIHByb3ZpZGVycyBhbmQgZGlyZWN0aXZlcyBhc3NvY2lhdGVkIHdpdGggdGhlIGluamVjdG9yJ3MgY29ycmVzcG9uZGluZyBub2RlIHRvIGdldFxuICAgICAgICAgIC8vIHRoZSBpbnN0YW5jZS5cbiAgICAgICAgICBjb25zdCBpbnN0YW5jZTogVHxudWxsID0gc2VhcmNoVG9rZW5zT25JbmplY3RvcjxUPihcbiAgICAgICAgICAgICAgaW5qZWN0b3JJbmRleCwgbFZpZXcsIHRva2VuLCBwcmV2aW91c1RWaWV3LCBmbGFncywgaG9zdFRFbGVtZW50Tm9kZSk7XG4gICAgICAgICAgaWYgKGluc3RhbmNlICE9PSBOT1RfRk9VTkQpIHtcbiAgICAgICAgICAgIHJldHVybiBpbnN0YW5jZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcGFyZW50TG9jYXRpb24gPSBsVmlld1tpbmplY3RvckluZGV4ICsgTm9kZUluamVjdG9yT2Zmc2V0LlBBUkVOVF07XG4gICAgICAgIGlmIChwYXJlbnRMb2NhdGlvbiAhPT0gTk9fUEFSRU5UX0lOSkVDVE9SICYmXG4gICAgICAgICAgICBzaG91bGRTZWFyY2hQYXJlbnQoXG4gICAgICAgICAgICAgICAgZmxhZ3MsXG4gICAgICAgICAgICAgICAgbFZpZXdbVFZJRVddLmRhdGFbaW5qZWN0b3JJbmRleCArIE5vZGVJbmplY3Rvck9mZnNldC5UTk9ERV0gPT09IGhvc3RURWxlbWVudE5vZGUpICYmXG4gICAgICAgICAgICBibG9vbUhhc1Rva2VuKGJsb29tSGFzaCwgaW5qZWN0b3JJbmRleCwgbFZpZXcpKSB7XG4gICAgICAgICAgLy8gVGhlIGRlZiB3YXNuJ3QgZm91bmQgYW55d2hlcmUgb24gdGhpcyBub2RlLCBzbyBpdCB3YXMgYSBmYWxzZSBwb3NpdGl2ZS5cbiAgICAgICAgICAvLyBUcmF2ZXJzZSB1cCB0aGUgdHJlZSBhbmQgY29udGludWUgc2VhcmNoaW5nLlxuICAgICAgICAgIHByZXZpb3VzVFZpZXcgPSB0VmlldztcbiAgICAgICAgICBpbmplY3RvckluZGV4ID0gZ2V0UGFyZW50SW5qZWN0b3JJbmRleChwYXJlbnRMb2NhdGlvbik7XG4gICAgICAgICAgbFZpZXcgPSBnZXRQYXJlbnRJbmplY3RvclZpZXcocGFyZW50TG9jYXRpb24sIGxWaWV3KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBJZiB3ZSBzaG91bGQgbm90IHNlYXJjaCBwYXJlbnQgT1IgSWYgdGhlIGFuY2VzdG9yIGJsb29tIGZpbHRlciB2YWx1ZSBkb2VzIG5vdCBoYXZlIHRoZVxuICAgICAgICAgIC8vIGJpdCBjb3JyZXNwb25kaW5nIHRvIHRoZSBkaXJlY3RpdmUgd2UgY2FuIGdpdmUgdXAgb24gdHJhdmVyc2luZyB1cCB0byBmaW5kIHRoZSBzcGVjaWZpY1xuICAgICAgICAgIC8vIGluamVjdG9yLlxuICAgICAgICAgIGluamVjdG9ySW5kZXggPSAtMTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBsb29rdXBUb2tlblVzaW5nTW9kdWxlSW5qZWN0b3I8VD4obFZpZXcsIHRva2VuLCBmbGFncywgbm90Rm91bmRWYWx1ZSk7XG59XG5cbmNvbnN0IE5PVF9GT1VORCA9IHt9O1xuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlTm9kZUluamVjdG9yKCk6IEluamVjdG9yIHtcbiAgcmV0dXJuIG5ldyBOb2RlSW5qZWN0b3IoZ2V0Q3VycmVudFROb2RlKCkhIGFzIFREaXJlY3RpdmVIb3N0Tm9kZSwgZ2V0TFZpZXcoKSkgYXMgYW55O1xufVxuXG5mdW5jdGlvbiBzZWFyY2hUb2tlbnNPbkluamVjdG9yPFQ+KFxuICAgIGluamVjdG9ySW5kZXg6IG51bWJlciwgbFZpZXc6IExWaWV3LCB0b2tlbjogUHJvdmlkZXJUb2tlbjxUPiwgcHJldmlvdXNUVmlldzogVFZpZXd8bnVsbCxcbiAgICBmbGFnczogSW5qZWN0RmxhZ3MsIGhvc3RURWxlbWVudE5vZGU6IFROb2RlfG51bGwpIHtcbiAgY29uc3QgY3VycmVudFRWaWV3ID0gbFZpZXdbVFZJRVddO1xuICBjb25zdCB0Tm9kZSA9IGN1cnJlbnRUVmlldy5kYXRhW2luamVjdG9ySW5kZXggKyBOb2RlSW5qZWN0b3JPZmZzZXQuVE5PREVdIGFzIFROb2RlO1xuICAvLyBGaXJzdCwgd2UgbmVlZCB0byBkZXRlcm1pbmUgaWYgdmlldyBwcm92aWRlcnMgY2FuIGJlIGFjY2Vzc2VkIGJ5IHRoZSBzdGFydGluZyBlbGVtZW50LlxuICAvLyBUaGVyZSBhcmUgdHdvIHBvc3NpYmlsaXRpZXNcbiAgY29uc3QgY2FuQWNjZXNzVmlld1Byb3ZpZGVycyA9IHByZXZpb3VzVFZpZXcgPT0gbnVsbCA/XG4gICAgICAvLyAxKSBUaGlzIGlzIHRoZSBmaXJzdCBpbnZvY2F0aW9uIGBwcmV2aW91c1RWaWV3ID09IG51bGxgIHdoaWNoIG1lYW5zIHRoYXQgd2UgYXJlIGF0IHRoZVxuICAgICAgLy8gYFROb2RlYCBvZiB3aGVyZSBpbmplY3RvciBpcyBzdGFydGluZyB0byBsb29rLiBJbiBzdWNoIGEgY2FzZSB0aGUgb25seSB0aW1lIHdlIGFyZSBhbGxvd2VkXG4gICAgICAvLyB0byBsb29rIGludG8gdGhlIFZpZXdQcm92aWRlcnMgaXMgaWY6XG4gICAgICAvLyAtIHdlIGFyZSBvbiBhIGNvbXBvbmVudFxuICAgICAgLy8gLSBBTkQgdGhlIGluamVjdG9yIHNldCBgaW5jbHVkZVZpZXdQcm92aWRlcnNgIHRvIHRydWUgKGltcGx5aW5nIHRoYXQgdGhlIHRva2VuIGNhbiBzZWVcbiAgICAgIC8vIFZpZXdQcm92aWRlcnMgYmVjYXVzZSBpdCBpcyB0aGUgQ29tcG9uZW50IG9yIGEgU2VydmljZSB3aGljaCBpdHNlbGYgd2FzIGRlY2xhcmVkIGluXG4gICAgICAvLyBWaWV3UHJvdmlkZXJzKVxuICAgICAgKGlzQ29tcG9uZW50SG9zdCh0Tm9kZSkgJiYgaW5jbHVkZVZpZXdQcm92aWRlcnMpIDpcbiAgICAgIC8vIDIpIGBwcmV2aW91c1RWaWV3ICE9IG51bGxgIHdoaWNoIG1lYW5zIHRoYXQgd2UgYXJlIG5vdyB3YWxraW5nIGFjcm9zcyB0aGUgcGFyZW50IG5vZGVzLlxuICAgICAgLy8gSW4gc3VjaCBhIGNhc2Ugd2UgYXJlIG9ubHkgYWxsb3dlZCB0byBsb29rIGludG8gdGhlIFZpZXdQcm92aWRlcnMgaWY6XG4gICAgICAvLyAtIFdlIGp1c3QgY3Jvc3NlZCBmcm9tIGNoaWxkIFZpZXcgdG8gUGFyZW50IFZpZXcgYHByZXZpb3VzVFZpZXcgIT0gY3VycmVudFRWaWV3YFxuICAgICAgLy8gLSBBTkQgdGhlIHBhcmVudCBUTm9kZSBpcyBhbiBFbGVtZW50LlxuICAgICAgLy8gVGhpcyBtZWFucyB0aGF0IHdlIGp1c3QgY2FtZSBmcm9tIHRoZSBDb21wb25lbnQncyBWaWV3IGFuZCB0aGVyZWZvcmUgYXJlIGFsbG93ZWQgdG8gc2VlXG4gICAgICAvLyBpbnRvIHRoZSBWaWV3UHJvdmlkZXJzLlxuICAgICAgKHByZXZpb3VzVFZpZXcgIT0gY3VycmVudFRWaWV3ICYmICgodE5vZGUudHlwZSAmIFROb2RlVHlwZS5BbnlSTm9kZSkgIT09IDApKTtcblxuICAvLyBUaGlzIHNwZWNpYWwgY2FzZSBoYXBwZW5zIHdoZW4gdGhlcmUgaXMgYSBAaG9zdCBvbiB0aGUgaW5qZWN0IGFuZCB3aGVuIHdlIGFyZSBzZWFyY2hpbmdcbiAgLy8gb24gdGhlIGhvc3QgZWxlbWVudCBub2RlLlxuICBjb25zdCBpc0hvc3RTcGVjaWFsQ2FzZSA9IChmbGFncyAmIEluamVjdEZsYWdzLkhvc3QpICYmIGhvc3RURWxlbWVudE5vZGUgPT09IHROb2RlO1xuXG4gIGNvbnN0IGluamVjdGFibGVJZHggPSBsb2NhdGVEaXJlY3RpdmVPclByb3ZpZGVyKFxuICAgICAgdE5vZGUsIGN1cnJlbnRUVmlldywgdG9rZW4sIGNhbkFjY2Vzc1ZpZXdQcm92aWRlcnMsIGlzSG9zdFNwZWNpYWxDYXNlKTtcbiAgaWYgKGluamVjdGFibGVJZHggIT09IG51bGwpIHtcbiAgICByZXR1cm4gZ2V0Tm9kZUluamVjdGFibGUobFZpZXcsIGN1cnJlbnRUVmlldywgaW5qZWN0YWJsZUlkeCwgdE5vZGUgYXMgVEVsZW1lbnROb2RlKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gTk9UX0ZPVU5EO1xuICB9XG59XG5cbi8qKlxuICogU2VhcmNoZXMgZm9yIHRoZSBnaXZlbiB0b2tlbiBhbW9uZyB0aGUgbm9kZSdzIGRpcmVjdGl2ZXMgYW5kIHByb3ZpZGVycy5cbiAqXG4gKiBAcGFyYW0gdE5vZGUgVE5vZGUgb24gd2hpY2ggZGlyZWN0aXZlcyBhcmUgcHJlc2VudC5cbiAqIEBwYXJhbSB0VmlldyBUaGUgdFZpZXcgd2UgYXJlIGN1cnJlbnRseSBwcm9jZXNzaW5nXG4gKiBAcGFyYW0gdG9rZW4gUHJvdmlkZXIgdG9rZW4gb3IgdHlwZSBvZiBhIGRpcmVjdGl2ZSB0byBsb29rIGZvci5cbiAqIEBwYXJhbSBjYW5BY2Nlc3NWaWV3UHJvdmlkZXJzIFdoZXRoZXIgdmlldyBwcm92aWRlcnMgc2hvdWxkIGJlIGNvbnNpZGVyZWQuXG4gKiBAcGFyYW0gaXNIb3N0U3BlY2lhbENhc2UgV2hldGhlciB0aGUgaG9zdCBzcGVjaWFsIGNhc2UgYXBwbGllcy5cbiAqIEByZXR1cm5zIEluZGV4IG9mIGEgZm91bmQgZGlyZWN0aXZlIG9yIHByb3ZpZGVyLCBvciBudWxsIHdoZW4gbm9uZSBmb3VuZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxvY2F0ZURpcmVjdGl2ZU9yUHJvdmlkZXI8VD4oXG4gICAgdE5vZGU6IFROb2RlLCB0VmlldzogVFZpZXcsIHRva2VuOiBQcm92aWRlclRva2VuPFQ+fHN0cmluZywgY2FuQWNjZXNzVmlld1Byb3ZpZGVyczogYm9vbGVhbixcbiAgICBpc0hvc3RTcGVjaWFsQ2FzZTogYm9vbGVhbnxudW1iZXIpOiBudW1iZXJ8bnVsbCB7XG4gIGNvbnN0IG5vZGVQcm92aWRlckluZGV4ZXMgPSB0Tm9kZS5wcm92aWRlckluZGV4ZXM7XG4gIGNvbnN0IHRJbmplY3RhYmxlcyA9IHRWaWV3LmRhdGE7XG5cbiAgY29uc3QgaW5qZWN0YWJsZXNTdGFydCA9IG5vZGVQcm92aWRlckluZGV4ZXMgJiBUTm9kZVByb3ZpZGVySW5kZXhlcy5Qcm92aWRlcnNTdGFydEluZGV4TWFzaztcbiAgY29uc3QgZGlyZWN0aXZlc1N0YXJ0ID0gdE5vZGUuZGlyZWN0aXZlU3RhcnQ7XG4gIGNvbnN0IGRpcmVjdGl2ZUVuZCA9IHROb2RlLmRpcmVjdGl2ZUVuZDtcbiAgY29uc3QgY3B0Vmlld1Byb3ZpZGVyc0NvdW50ID1cbiAgICAgIG5vZGVQcm92aWRlckluZGV4ZXMgPj4gVE5vZGVQcm92aWRlckluZGV4ZXMuQ3B0Vmlld1Byb3ZpZGVyc0NvdW50U2hpZnQ7XG4gIGNvbnN0IHN0YXJ0aW5nSW5kZXggPVxuICAgICAgY2FuQWNjZXNzVmlld1Byb3ZpZGVycyA/IGluamVjdGFibGVzU3RhcnQgOiBpbmplY3RhYmxlc1N0YXJ0ICsgY3B0Vmlld1Byb3ZpZGVyc0NvdW50O1xuICAvLyBXaGVuIHRoZSBob3N0IHNwZWNpYWwgY2FzZSBhcHBsaWVzLCBvbmx5IHRoZSB2aWV3UHJvdmlkZXJzIGFuZCB0aGUgY29tcG9uZW50IGFyZSB2aXNpYmxlXG4gIGNvbnN0IGVuZEluZGV4ID0gaXNIb3N0U3BlY2lhbENhc2UgPyBpbmplY3RhYmxlc1N0YXJ0ICsgY3B0Vmlld1Byb3ZpZGVyc0NvdW50IDogZGlyZWN0aXZlRW5kO1xuICBmb3IgKGxldCBpID0gc3RhcnRpbmdJbmRleDsgaSA8IGVuZEluZGV4OyBpKyspIHtcbiAgICBjb25zdCBwcm92aWRlclRva2VuT3JEZWYgPSB0SW5qZWN0YWJsZXNbaV0gYXMgUHJvdmlkZXJUb2tlbjxhbnk+fCBEaXJlY3RpdmVEZWY8YW55Pnwgc3RyaW5nO1xuICAgIGlmIChpIDwgZGlyZWN0aXZlc1N0YXJ0ICYmIHRva2VuID09PSBwcm92aWRlclRva2VuT3JEZWYgfHxcbiAgICAgICAgaSA+PSBkaXJlY3RpdmVzU3RhcnQgJiYgKHByb3ZpZGVyVG9rZW5PckRlZiBhcyBEaXJlY3RpdmVEZWY8YW55PikudHlwZSA9PT0gdG9rZW4pIHtcbiAgICAgIHJldHVybiBpO1xuICAgIH1cbiAgfVxuICBpZiAoaXNIb3N0U3BlY2lhbENhc2UpIHtcbiAgICBjb25zdCBkaXJEZWYgPSB0SW5qZWN0YWJsZXNbZGlyZWN0aXZlc1N0YXJ0XSBhcyBEaXJlY3RpdmVEZWY8YW55PjtcbiAgICBpZiAoZGlyRGVmICYmIGlzQ29tcG9uZW50RGVmKGRpckRlZikgJiYgZGlyRGVmLnR5cGUgPT09IHRva2VuKSB7XG4gICAgICByZXR1cm4gZGlyZWN0aXZlc1N0YXJ0O1xuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqXG4gKiBSZXRyaWV2ZSBvciBpbnN0YW50aWF0ZSB0aGUgaW5qZWN0YWJsZSBmcm9tIHRoZSBgTFZpZXdgIGF0IHBhcnRpY3VsYXIgYGluZGV4YC5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGNoZWNrcyB0byBzZWUgaWYgdGhlIHZhbHVlIGhhcyBhbHJlYWR5IGJlZW4gaW5zdGFudGlhdGVkIGFuZCBpZiBzbyByZXR1cm5zIHRoZVxuICogY2FjaGVkIGBpbmplY3RhYmxlYC4gT3RoZXJ3aXNlIGlmIGl0IGRldGVjdHMgdGhhdCB0aGUgdmFsdWUgaXMgc3RpbGwgYSBmYWN0b3J5IGl0XG4gKiBpbnN0YW50aWF0ZXMgdGhlIGBpbmplY3RhYmxlYCBhbmQgY2FjaGVzIHRoZSB2YWx1ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE5vZGVJbmplY3RhYmxlKFxuICAgIGxWaWV3OiBMVmlldywgdFZpZXc6IFRWaWV3LCBpbmRleDogbnVtYmVyLCB0Tm9kZTogVERpcmVjdGl2ZUhvc3ROb2RlKTogYW55IHtcbiAgbGV0IHZhbHVlID0gbFZpZXdbaW5kZXhdO1xuICBjb25zdCB0RGF0YSA9IHRWaWV3LmRhdGE7XG4gIGlmIChpc0ZhY3RvcnkodmFsdWUpKSB7XG4gICAgY29uc3QgZmFjdG9yeTogTm9kZUluamVjdG9yRmFjdG9yeSA9IHZhbHVlO1xuICAgIGlmIChmYWN0b3J5LnJlc29sdmluZykge1xuICAgICAgdGhyb3dDeWNsaWNEZXBlbmRlbmN5RXJyb3Ioc3RyaW5naWZ5Rm9yRXJyb3IodERhdGFbaW5kZXhdKSk7XG4gICAgfVxuICAgIGNvbnN0IHByZXZpb3VzSW5jbHVkZVZpZXdQcm92aWRlcnMgPSBzZXRJbmNsdWRlVmlld1Byb3ZpZGVycyhmYWN0b3J5LmNhblNlZVZpZXdQcm92aWRlcnMpO1xuICAgIGZhY3RvcnkucmVzb2x2aW5nID0gdHJ1ZTtcbiAgICBjb25zdCBwcmV2aW91c0luamVjdEltcGxlbWVudGF0aW9uID1cbiAgICAgICAgZmFjdG9yeS5pbmplY3RJbXBsID8gc2V0SW5qZWN0SW1wbGVtZW50YXRpb24oZmFjdG9yeS5pbmplY3RJbXBsKSA6IG51bGw7XG4gICAgY29uc3Qgc3VjY2VzcyA9IGVudGVyREkobFZpZXcsIHROb2RlLCBJbmplY3RGbGFncy5EZWZhdWx0KTtcbiAgICBuZ0Rldk1vZGUgJiZcbiAgICAgICAgYXNzZXJ0RXF1YWwoXG4gICAgICAgICAgICBzdWNjZXNzLCB0cnVlLFxuICAgICAgICAgICAgJ0JlY2F1c2UgZmxhZ3MgZG8gbm90IGNvbnRhaW4gXFxgU2tpcFNlbGZcXCcgd2UgZXhwZWN0IHRoaXMgdG8gYWx3YXlzIHN1Y2NlZWQuJyk7XG4gICAgdHJ5IHtcbiAgICAgIHZhbHVlID0gbFZpZXdbaW5kZXhdID0gZmFjdG9yeS5mYWN0b3J5KHVuZGVmaW5lZCwgdERhdGEsIGxWaWV3LCB0Tm9kZSk7XG4gICAgICAvLyBUaGlzIGNvZGUgcGF0aCBpcyBoaXQgZm9yIGJvdGggZGlyZWN0aXZlcyBhbmQgcHJvdmlkZXJzLlxuICAgICAgLy8gRm9yIHBlcmYgcmVhc29ucywgd2Ugd2FudCB0byBhdm9pZCBzZWFyY2hpbmcgZm9yIGhvb2tzIG9uIHByb3ZpZGVycy5cbiAgICAgIC8vIEl0IGRvZXMgbm8gaGFybSB0byB0cnkgKHRoZSBob29rcyBqdXN0IHdvbid0IGV4aXN0KSwgYnV0IHRoZSBleHRyYVxuICAgICAgLy8gY2hlY2tzIGFyZSB1bm5lY2Vzc2FyeSBhbmQgdGhpcyBpcyBhIGhvdCBwYXRoLiBTbyB3ZSBjaGVjayB0byBzZWVcbiAgICAgIC8vIGlmIHRoZSBpbmRleCBvZiB0aGUgZGVwZW5kZW5jeSBpcyBpbiB0aGUgZGlyZWN0aXZlIHJhbmdlIGZvciB0aGlzXG4gICAgICAvLyB0Tm9kZS4gSWYgaXQncyBub3QsIHdlIGtub3cgaXQncyBhIHByb3ZpZGVyIGFuZCBza2lwIGhvb2sgcmVnaXN0cmF0aW9uLlxuICAgICAgaWYgKHRWaWV3LmZpcnN0Q3JlYXRlUGFzcyAmJiBpbmRleCA+PSB0Tm9kZS5kaXJlY3RpdmVTdGFydCkge1xuICAgICAgICBuZ0Rldk1vZGUgJiYgYXNzZXJ0RGlyZWN0aXZlRGVmKHREYXRhW2luZGV4XSk7XG4gICAgICAgIHJlZ2lzdGVyUHJlT3JkZXJIb29rcyhpbmRleCwgdERhdGFbaW5kZXhdIGFzIERpcmVjdGl2ZURlZjxhbnk+LCB0Vmlldyk7XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHByZXZpb3VzSW5qZWN0SW1wbGVtZW50YXRpb24gIT09IG51bGwgJiZcbiAgICAgICAgICBzZXRJbmplY3RJbXBsZW1lbnRhdGlvbihwcmV2aW91c0luamVjdEltcGxlbWVudGF0aW9uKTtcbiAgICAgIHNldEluY2x1ZGVWaWV3UHJvdmlkZXJzKHByZXZpb3VzSW5jbHVkZVZpZXdQcm92aWRlcnMpO1xuICAgICAgZmFjdG9yeS5yZXNvbHZpbmcgPSBmYWxzZTtcbiAgICAgIGxlYXZlREkoKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHZhbHVlO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIGJpdCBpbiBhbiBpbmplY3RvcidzIGJsb29tIGZpbHRlciB0aGF0IHNob3VsZCBiZSB1c2VkIHRvIGRldGVybWluZSB3aGV0aGVyIG9yIG5vdFxuICogdGhlIGRpcmVjdGl2ZSBtaWdodCBiZSBwcm92aWRlZCBieSB0aGUgaW5qZWN0b3IuXG4gKlxuICogV2hlbiBhIGRpcmVjdGl2ZSBpcyBwdWJsaWMsIGl0IGlzIGFkZGVkIHRvIHRoZSBibG9vbSBmaWx0ZXIgYW5kIGdpdmVuIGEgdW5pcXVlIElEIHRoYXQgY2FuIGJlXG4gKiByZXRyaWV2ZWQgb24gdGhlIFR5cGUuIFdoZW4gdGhlIGRpcmVjdGl2ZSBpc24ndCBwdWJsaWMgb3IgdGhlIHRva2VuIGlzIG5vdCBhIGRpcmVjdGl2ZSBgbnVsbGBcbiAqIGlzIHJldHVybmVkIGFzIHRoZSBub2RlIGluamVjdG9yIGNhbiBub3QgcG9zc2libHkgcHJvdmlkZSB0aGF0IHRva2VuLlxuICpcbiAqIEBwYXJhbSB0b2tlbiB0aGUgaW5qZWN0aW9uIHRva2VuXG4gKiBAcmV0dXJucyB0aGUgbWF0Y2hpbmcgYml0IHRvIGNoZWNrIGluIHRoZSBibG9vbSBmaWx0ZXIgb3IgYG51bGxgIGlmIHRoZSB0b2tlbiBpcyBub3Qga25vd24uXG4gKiAgIFdoZW4gdGhlIHJldHVybmVkIHZhbHVlIGlzIG5lZ2F0aXZlIHRoZW4gaXQgcmVwcmVzZW50cyBzcGVjaWFsIHZhbHVlcyBzdWNoIGFzIGBJbmplY3RvcmAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBibG9vbUhhc2hCaXRPckZhY3RvcnkodG9rZW46IFByb3ZpZGVyVG9rZW48YW55PnxzdHJpbmcpOiBudW1iZXJ8RnVuY3Rpb258dW5kZWZpbmVkIHtcbiAgbmdEZXZNb2RlICYmIGFzc2VydERlZmluZWQodG9rZW4sICd0b2tlbiBtdXN0IGJlIGRlZmluZWQnKTtcbiAgaWYgKHR5cGVvZiB0b2tlbiA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gdG9rZW4uY2hhckNvZGVBdCgwKSB8fCAwO1xuICB9XG4gIGNvbnN0IHRva2VuSWQ6IG51bWJlcnx1bmRlZmluZWQgPVxuICAgICAgLy8gRmlyc3QgY2hlY2sgd2l0aCBgaGFzT3duUHJvcGVydHlgIHNvIHdlIGRvbid0IGdldCBhbiBpbmhlcml0ZWQgSUQuXG4gICAgICB0b2tlbi5oYXNPd25Qcm9wZXJ0eShOR19FTEVNRU5UX0lEKSA/ICh0b2tlbiBhcyBhbnkpW05HX0VMRU1FTlRfSURdIDogdW5kZWZpbmVkO1xuICAvLyBOZWdhdGl2ZSB0b2tlbiBJRHMgYXJlIHVzZWQgZm9yIHNwZWNpYWwgb2JqZWN0cyBzdWNoIGFzIGBJbmplY3RvcmBcbiAgaWYgKHR5cGVvZiB0b2tlbklkID09PSAnbnVtYmVyJykge1xuICAgIGlmICh0b2tlbklkID49IDApIHtcbiAgICAgIHJldHVybiB0b2tlbklkICYgQkxPT01fTUFTSztcbiAgICB9IGVsc2Uge1xuICAgICAgbmdEZXZNb2RlICYmXG4gICAgICAgICAgYXNzZXJ0RXF1YWwodG9rZW5JZCwgSW5qZWN0b3JNYXJrZXJzLkluamVjdG9yLCAnRXhwZWN0aW5nIHRvIGdldCBTcGVjaWFsIEluamVjdG9yIElkJyk7XG4gICAgICByZXR1cm4gY3JlYXRlTm9kZUluamVjdG9yO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gdG9rZW5JZDtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gYmxvb21IYXNUb2tlbihibG9vbUhhc2g6IG51bWJlciwgaW5qZWN0b3JJbmRleDogbnVtYmVyLCBpbmplY3RvclZpZXc6IExWaWV3fFREYXRhKSB7XG4gIC8vIENyZWF0ZSBhIG1hc2sgdGhhdCB0YXJnZXRzIHRoZSBzcGVjaWZpYyBiaXQgYXNzb2NpYXRlZCB3aXRoIHRoZSBkaXJlY3RpdmUgd2UncmUgbG9va2luZyBmb3IuXG4gIC8vIEpTIGJpdCBvcGVyYXRpb25zIGFyZSAzMiBiaXRzLCBzbyB0aGlzIHdpbGwgYmUgYSBudW1iZXIgYmV0d2VlbiAyXjAgYW5kIDJeMzEsIGNvcnJlc3BvbmRpbmdcbiAgLy8gdG8gYml0IHBvc2l0aW9ucyAwIC0gMzEgaW4gYSAzMiBiaXQgaW50ZWdlci5cbiAgY29uc3QgbWFzayA9IDEgPDwgYmxvb21IYXNoO1xuXG4gIC8vIEVhY2ggYmxvb20gYnVja2V0IGluIGBpbmplY3RvclZpZXdgIHJlcHJlc2VudHMgYEJMT09NX0JVQ0tFVF9CSVRTYCBudW1iZXIgb2YgYml0cyBvZlxuICAvLyBgYmxvb21IYXNoYC4gQW55IGJpdHMgaW4gYGJsb29tSGFzaGAgYmV5b25kIGBCTE9PTV9CVUNLRVRfQklUU2AgaW5kaWNhdGUgdGhlIGJ1Y2tldCBvZmZzZXRcbiAgLy8gdGhhdCBzaG91bGQgYmUgdXNlZC5cbiAgY29uc3QgdmFsdWUgPSBpbmplY3RvclZpZXdbaW5qZWN0b3JJbmRleCArIChibG9vbUhhc2ggPj4gQkxPT01fQlVDS0VUX0JJVFMpXTtcblxuICAvLyBJZiB0aGUgYmxvb20gZmlsdGVyIHZhbHVlIGhhcyB0aGUgYml0IGNvcnJlc3BvbmRpbmcgdG8gdGhlIGRpcmVjdGl2ZSdzIGJsb29tQml0IGZsaXBwZWQgb24sXG4gIC8vIHRoaXMgaW5qZWN0b3IgaXMgYSBwb3RlbnRpYWwgbWF0Y2guXG4gIHJldHVybiAhISh2YWx1ZSAmIG1hc2spO1xufVxuXG4vKiogUmV0dXJucyB0cnVlIGlmIGZsYWdzIHByZXZlbnQgcGFyZW50IGluamVjdG9yIGZyb20gYmVpbmcgc2VhcmNoZWQgZm9yIHRva2VucyAqL1xuZnVuY3Rpb24gc2hvdWxkU2VhcmNoUGFyZW50KGZsYWdzOiBJbmplY3RGbGFncywgaXNGaXJzdEhvc3RUTm9kZTogYm9vbGVhbik6IGJvb2xlYW58bnVtYmVyIHtcbiAgcmV0dXJuICEoZmxhZ3MgJiBJbmplY3RGbGFncy5TZWxmKSAmJiAhKGZsYWdzICYgSW5qZWN0RmxhZ3MuSG9zdCAmJiBpc0ZpcnN0SG9zdFROb2RlKTtcbn1cblxuZXhwb3J0IGNsYXNzIE5vZGVJbmplY3RvciBpbXBsZW1lbnRzIEluamVjdG9yIHtcbiAgY29uc3RydWN0b3IoXG4gICAgICBwcml2YXRlIF90Tm9kZTogVEVsZW1lbnROb2RlfFRDb250YWluZXJOb2RlfFRFbGVtZW50Q29udGFpbmVyTm9kZXxudWxsLFxuICAgICAgcHJpdmF0ZSBfbFZpZXc6IExWaWV3KSB7fVxuXG4gIGdldCh0b2tlbjogYW55LCBub3RGb3VuZFZhbHVlPzogYW55KTogYW55IHtcbiAgICByZXR1cm4gZ2V0T3JDcmVhdGVJbmplY3RhYmxlKHRoaXMuX3ROb2RlLCB0aGlzLl9sVmlldywgdG9rZW4sIHVuZGVmaW5lZCwgbm90Rm91bmRWYWx1ZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAY29kZUdlbkFwaVxuICovXG5leHBvcnQgZnVuY3Rpb24gybXJtWdldEluaGVyaXRlZEZhY3Rvcnk8VD4odHlwZTogVHlwZTxhbnk+KTogKHR5cGU6IFR5cGU8VD4pID0+IFQge1xuICByZXR1cm4gbm9TaWRlRWZmZWN0cygoKSA9PiB7XG4gICAgY29uc3Qgb3duQ29uc3RydWN0b3IgPSB0eXBlLnByb3RvdHlwZS5jb25zdHJ1Y3RvcjtcbiAgICBjb25zdCBvd25GYWN0b3J5ID0gb3duQ29uc3RydWN0b3JbTkdfRkFDVE9SWV9ERUZdIHx8IGdldEZhY3RvcnlPZihvd25Db25zdHJ1Y3Rvcik7XG4gICAgY29uc3Qgb2JqZWN0UHJvdG90eXBlID0gT2JqZWN0LnByb3RvdHlwZTtcbiAgICBsZXQgcGFyZW50ID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKHR5cGUucHJvdG90eXBlKS5jb25zdHJ1Y3RvcjtcblxuICAgIC8vIEdvIHVwIHRoZSBwcm90b3R5cGUgdW50aWwgd2UgaGl0IGBPYmplY3RgLlxuICAgIHdoaWxlIChwYXJlbnQgJiYgcGFyZW50ICE9PSBvYmplY3RQcm90b3R5cGUpIHtcbiAgICAgIGNvbnN0IGZhY3RvcnkgPSBwYXJlbnRbTkdfRkFDVE9SWV9ERUZdIHx8IGdldEZhY3RvcnlPZihwYXJlbnQpO1xuXG4gICAgICAvLyBJZiB3ZSBoaXQgc29tZXRoaW5nIHRoYXQgaGFzIGEgZmFjdG9yeSBhbmQgdGhlIGZhY3RvcnkgaXNuJ3QgdGhlIHNhbWUgYXMgdGhlIHR5cGUsXG4gICAgICAvLyB3ZSd2ZSBmb3VuZCB0aGUgaW5oZXJpdGVkIGZhY3RvcnkuIE5vdGUgdGhlIGNoZWNrIHRoYXQgdGhlIGZhY3RvcnkgaXNuJ3QgdGhlIHR5cGUnc1xuICAgICAgLy8gb3duIGZhY3RvcnkgaXMgcmVkdW5kYW50IGluIG1vc3QgY2FzZXMsIGJ1dCBpZiB0aGUgdXNlciBoYXMgY3VzdG9tIGRlY29yYXRvcnMgb24gdGhlXG4gICAgICAvLyBjbGFzcywgdGhpcyBsb29rdXAgd2lsbCBzdGFydCBvbmUgbGV2ZWwgZG93biBpbiB0aGUgcHJvdG90eXBlIGNoYWluLCBjYXVzaW5nIHVzIHRvXG4gICAgICAvLyBmaW5kIHRoZSBvd24gZmFjdG9yeSBmaXJzdCBhbmQgcG90ZW50aWFsbHkgdHJpZ2dlcmluZyBhbiBpbmZpbml0ZSBsb29wIGRvd25zdHJlYW0uXG4gICAgICBpZiAoZmFjdG9yeSAmJiBmYWN0b3J5ICE9PSBvd25GYWN0b3J5KSB7XG4gICAgICAgIHJldHVybiBmYWN0b3J5O1xuICAgICAgfVxuXG4gICAgICBwYXJlbnQgPSBPYmplY3QuZ2V0UHJvdG90eXBlT2YocGFyZW50KTtcbiAgICB9XG5cbiAgICAvLyBUaGVyZSBpcyBubyBmYWN0b3J5IGRlZmluZWQuIEVpdGhlciB0aGlzIHdhcyBpbXByb3BlciB1c2FnZSBvZiBpbmhlcml0YW5jZVxuICAgIC8vIChubyBBbmd1bGFyIGRlY29yYXRvciBvbiB0aGUgc3VwZXJjbGFzcykgb3IgdGhlcmUgaXMgbm8gY29uc3RydWN0b3IgYXQgYWxsXG4gICAgLy8gaW4gdGhlIGluaGVyaXRhbmNlIGNoYWluLiBTaW5jZSB0aGUgdHdvIGNhc2VzIGNhbm5vdCBiZSBkaXN0aW5ndWlzaGVkLCB0aGVcbiAgICAvLyBsYXR0ZXIgaGFzIHRvIGJlIGFzc3VtZWQuXG4gICAgcmV0dXJuIHQgPT4gbmV3IHQoKTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGdldEZhY3RvcnlPZjxUPih0eXBlOiBUeXBlPGFueT4pOiAoKHR5cGU/OiBUeXBlPFQ+KSA9PiBUIHwgbnVsbCl8bnVsbCB7XG4gIGlmIChpc0ZvcndhcmRSZWYodHlwZSkpIHtcbiAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgY29uc3QgZmFjdG9yeSA9IGdldEZhY3RvcnlPZjxUPihyZXNvbHZlRm9yd2FyZFJlZih0eXBlKSk7XG4gICAgICByZXR1cm4gZmFjdG9yeSAmJiBmYWN0b3J5KCk7XG4gICAgfTtcbiAgfVxuICByZXR1cm4gZ2V0RmFjdG9yeURlZjxUPih0eXBlKTtcbn1cbiJdfQ== |
---|