UNPKG

21.7 kBJavaScriptView Raw
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 */
8import { Inject, Injectable, InjectionToken, Optional, SkipSelf } from '@angular/core';
9import { Subject } from 'rxjs';
10import { debounceTime, distinctUntilChanged, startWith } from 'rxjs/operators';
11import * as i0 from "@angular/core";
12/** Injection token used for an implementation of MenuStack. */
13export const MENU_STACK = new InjectionToken('cdk-menu-stack');
14/** Provider that provides the parent menu stack, or a new menu stack if there is no parent one. */
15export const PARENT_OR_NEW_MENU_STACK_PROVIDER = {
16 provide: MENU_STACK,
17 deps: [[new Optional(), new SkipSelf(), new Inject(MENU_STACK)]],
18 useFactory: (parentMenuStack) => parentMenuStack || new MenuStack(),
19};
20/** Provider that provides the parent menu stack, or a new inline menu stack if there is no parent one. */
21export const PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER = (orientation) => ({
22 provide: MENU_STACK,
23 deps: [[new Optional(), new SkipSelf(), new Inject(MENU_STACK)]],
24 useFactory: (parentMenuStack) => parentMenuStack || MenuStack.inline(orientation),
25});
26/** The next available menu stack ID. */
27let nextId = 0;
28/**
29 * MenuStack allows subscribers to listen for close events (when a MenuStackItem is popped off
30 * of the stack) in order to perform closing actions. Upon the MenuStack being empty it emits
31 * from the `empty` observable specifying the next focus action which the listener should perform
32 * as requested by the closer.
33 */
34class MenuStack {
35 constructor() {
36 /** The ID of this menu stack. */
37 this.id = `${nextId++}`;
38 /** All MenuStackItems tracked by this MenuStack. */
39 this._elements = [];
40 /** Emits the element which was popped off of the stack when requested by a closer. */
41 this._close = new Subject();
42 /** Emits once the MenuStack has become empty after popping off elements. */
43 this._empty = new Subject();
44 /** Emits whether any menu in the menu stack has focus. */
45 this._hasFocus = new Subject();
46 /** Observable which emits the MenuStackItem which has been requested to close. */
47 this.closed = this._close;
48 /** Observable which emits whether any menu in the menu stack has focus. */
49 this.hasFocus = this._hasFocus.pipe(startWith(false), debounceTime(0), distinctUntilChanged());
50 /**
51 * Observable which emits when the MenuStack is empty after popping off the last element. It
52 * emits a FocusNext event which specifies the action the closer has requested the listener
53 * perform.
54 */
55 this.emptied = this._empty;
56 /**
57 * Whether the inline menu associated with this menu stack is vertical or horizontal.
58 * `null` indicates there is no inline menu associated with this menu stack.
59 */
60 this._inlineMenuOrientation = null;
61 }
62 /** Creates a menu stack that originates from an inline menu. */
63 static inline(orientation) {
64 const stack = new MenuStack();
65 stack._inlineMenuOrientation = orientation;
66 return stack;
67 }
68 /**
69 * Adds an item to the menu stack.
70 * @param menu the MenuStackItem to put on the stack.
71 */
72 push(menu) {
73 this._elements.push(menu);
74 }
75 /**
76 * Pop items off of the stack up to and including `lastItem` and emit each on the close
77 * observable. If the stack is empty or `lastItem` is not on the stack it does nothing.
78 * @param lastItem the last item to pop off the stack.
79 * @param options Options that configure behavior on close.
80 */
81 close(lastItem, options) {
82 const { focusNextOnEmpty, focusParentTrigger } = { ...options };
83 if (this._elements.indexOf(lastItem) >= 0) {
84 let poppedElement;
85 do {
86 poppedElement = this._elements.pop();
87 this._close.next({ item: poppedElement, focusParentTrigger });
88 } while (poppedElement !== lastItem);
89 if (this.isEmpty()) {
90 this._empty.next(focusNextOnEmpty);
91 }
92 }
93 }
94 /**
95 * Pop items off of the stack up to but excluding `lastItem` and emit each on the close
96 * observable. If the stack is empty or `lastItem` is not on the stack it does nothing.
97 * @param lastItem the element which should be left on the stack
98 * @return whether or not an item was removed from the stack
99 */
100 closeSubMenuOf(lastItem) {
101 let removed = false;
102 if (this._elements.indexOf(lastItem) >= 0) {
103 removed = this.peek() !== lastItem;
104 while (this.peek() !== lastItem) {
105 this._close.next({ item: this._elements.pop() });
106 }
107 }
108 return removed;
109 }
110 /**
111 * Pop off all MenuStackItems and emit each one on the `close` observable one by one.
112 * @param options Options that configure behavior on close.
113 */
114 closeAll(options) {
115 const { focusNextOnEmpty, focusParentTrigger } = { ...options };
116 if (!this.isEmpty()) {
117 while (!this.isEmpty()) {
118 const menuStackItem = this._elements.pop();
119 if (menuStackItem) {
120 this._close.next({ item: menuStackItem, focusParentTrigger });
121 }
122 }
123 this._empty.next(focusNextOnEmpty);
124 }
125 }
126 /** Return true if this stack is empty. */
127 isEmpty() {
128 return !this._elements.length;
129 }
130 /** Return the length of the stack. */
131 length() {
132 return this._elements.length;
133 }
134 /** Get the top most element on the stack. */
135 peek() {
136 return this._elements[this._elements.length - 1];
137 }
138 /** Whether the menu stack is associated with an inline menu. */
139 hasInlineMenu() {
140 return this._inlineMenuOrientation != null;
141 }
142 /** The orientation of the associated inline menu. */
143 inlineMenuOrientation() {
144 return this._inlineMenuOrientation;
145 }
146 /** Sets whether the menu stack contains the focused element. */
147 setHasFocus(hasFocus) {
148 this._hasFocus.next(hasFocus);
149 }
150 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MenuStack, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
151 static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MenuStack }); }
152}
153export { MenuStack };
154i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: MenuStack, decorators: [{
155 type: Injectable
156 }] });
157//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVudS1zdGFjay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9jZGsvbWVudS9tZW51LXN0YWNrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBQyxNQUFNLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQ3JGLE9BQU8sRUFBYSxPQUFPLEVBQUMsTUFBTSxNQUFNLENBQUM7QUFDekMsT0FBTyxFQUFDLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxTQUFTLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQzs7QUFlN0UsK0RBQStEO0FBQy9ELE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRyxJQUFJLGNBQWMsQ0FBWSxnQkFBZ0IsQ0FBQyxDQUFDO0FBRTFFLG1HQUFtRztBQUNuRyxNQUFNLENBQUMsTUFBTSxpQ0FBaUMsR0FBRztJQUMvQyxPQUFPLEVBQUUsVUFBVTtJQUNuQixJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksUUFBUSxFQUFFLEVBQUUsSUFBSSxRQUFRLEVBQUUsRUFBRSxJQUFJLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQ2hFLFVBQVUsRUFBRSxDQUFDLGVBQTJCLEVBQUUsRUFBRSxDQUFDLGVBQWUsSUFBSSxJQUFJLFNBQVMsRUFBRTtDQUNoRixDQUFDO0FBRUYsMEdBQTBHO0FBQzFHLE1BQU0sQ0FBQyxNQUFNLHdDQUF3QyxHQUFHLENBQ3RELFdBQXNDLEVBQ3RDLEVBQUUsQ0FBQyxDQUFDO0lBQ0osT0FBTyxFQUFFLFVBQVU7SUFDbkIsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLFFBQVEsRUFBRSxFQUFFLElBQUksUUFBUSxFQUFFLEVBQUUsSUFBSSxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUNoRSxVQUFVLEVBQUUsQ0FBQyxlQUEyQixFQUFFLEVBQUUsQ0FBQyxl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QXpJVSxTQUFTO2tIQUFULFNBQVM7O1NBQVQsU0FBUzsyRkFBVCxTQUFTO2tCQURyQixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7SW5qZWN0LCBJbmplY3RhYmxlLCBJbmplY3Rpb25Ub2tlbiwgT3B0aW9uYWwsIFNraXBTZWxmfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7T2JzZXJ2YWJsZSwgU3ViamVjdH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge2RlYm91bmNlVGltZSwgZGlzdGluY3RVbnRpbENoYW5nZWQsIHN0YXJ0V2l0aH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG4vKiogVGhlIHJlbGF0aXZlIGl0ZW0gaW4gdGhlIGlubGluZSBtZW51IHRvIGZvY3VzIGFmdGVyIGNsb3NpbmcgYWxsIHBvcHVwIG1lbnVzLiAqL1xuZXhwb3J0IGNvbnN0IGVudW0gRm9jdXNOZXh0IHtcbiAgbmV4dEl0ZW0sXG4gIHByZXZpb3VzSXRlbSxcbiAgY3VycmVudEl0ZW0sXG59XG5cbi8qKiBBIHNpbmdsZSBpdGVtIChtZW51KSBpbiB0aGUgbWVudSBzdGFjay4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWVudVN0YWNrSXRlbSB7XG4gIC8qKiBBIHJlZmVyZW5jZSB0byB0aGUgbWVudSBzdGFjayB0aGlzIG1lbnUgc3RhY2sgaXRlbSBiZWxvbmdzIHRvLiAqL1xuICBtZW51U3RhY2s/OiBNZW51U3RhY2s7XG59XG5cbi8qKiBJbmplY3Rpb24gdG9rZW4gdXNlZCBmb3IgYW4gaW1wbGVtZW50YXRpb24gb2YgTWVudVN0YWNrLiAqL1xuZXhwb3J0IGNvbnN0IE1FTlVfU1RBQ0sgPSBuZXcgSW5qZWN0aW9uVG9rZW48TWVudVN0YWNrPignY2RrLW1lbnUtc3RhY2snKTtcblxuLyoqIFByb3ZpZGVyIHRoYXQgcHJvdmlkZXMgdGhlIHBhcmVudCBtZW51IHN0YWNrLCBvciBhIG5ldyBtZW51IHN0YWNrIGlmIHRoZXJlIGlzIG5vIHBhcmVudCBvbmUuICovXG5leHBvcnQgY29uc3QgUEFSRU5UX09SX05FV19NRU5VX1NUQUNLX1BST1ZJREVSID0ge1xuICBwcm92aWRlOiBNRU5VX1NUQUNLLFxuICBkZXBzOiBbW25ldyBPcHRpb25hbCgpLCBuZXcgU2tpcFNlbGYoKSwgbmV3IEluamVjdChNRU5VX1NUQUNLKV1dLFxuICB1c2VGYWN0b3J5OiAocGFyZW50TWVudVN0YWNrPzogTWVudVN0YWNrKSA9PiBwYXJlbnRNZW51U3RhY2sgfHwgbmV3IE1lbnVTdGFjaygpLFxufTtcblxuLyoqIFByb3ZpZGVyIHRoYXQgcHJvdmlkZXMgdGhlIHBhcmVudCBtZW51IHN0YWNrLCBvciBhIG5ldyBpbmxpbmUgbWVudSBzdGFjayBpZiB0aGVyZSBpcyBubyBwYXJlbnQgb25lLiAqL1xuZXhwb3J0IGNvbnN0IFBBUkVOVF9PUl9ORVdfSU5MSU5FX01FTlVfU1RBQ0tfUFJPVklERVIgPSAoXG4gIG9yaWVudGF0aW9uOiAndmVydGljYWwnIHwgJ2hvcml6b250YWwnLFxuKSA9PiAoe1xuICBwcm92aWRlOiBNRU5VX1NUQUNLLFxuICBkZXBzOiBbW25ldyBPcHRpb25hbCgpLCBuZXcgU2tpcFNlbGYoKSwgbmV3IEluamVjdChNRU5VX1NUQUNLKV1dLFxuICB1c2VGYWN0b3J5OiAocGFyZW50TWVudVN0YWNrPzogTWVudVN0YWNrKSA9PiBwYXJlbnRNZW51U3RhY2sgfHwgTWVudVN0YWNrLmlubGluZShvcmllbnRhdGlvbiksXG59KTtcblxuLyoqIE9wdGlvbnMgdGhhdCBjYW4gYmUgcHJvdmlkZWQgdG8gdGhlIGNsb3NlIG9yIGNsb3NlQWxsIG1ldGhvZHMuICovXG5leHBvcnQgaW50ZXJmYWNlIENsb3NlT3B0aW9ucyB7XG4gIC8qKiBUaGUgZWxlbWVudCB0byBmb2N1cyBuZXh0IGlmIHRoZSBjbG9zZSBvcGVyYXRpb24gY2F1c2VzIHRoZSBtZW51IHN0YWNrIHRvIGJlY29tZSBlbXB0eS4gKi9cbiAgZm9jdXNOZXh0T25FbXB0eT86IEZvY3VzTmV4dDtcbiAgLyoqIFdoZXRoZXIgdG8gZm9jdXMgdGhlIHBhcmVudCB0cmlnZ2VyIGFmdGVyIGNsb3NpbmcgdGhlIG1lbnUuICovXG4gIGZvY3VzUGFyZW50VHJpZ2dlcj86IGJvb2xlYW47XG59XG5cbi8qKiBFdmVudCBkaXNwYXRjaGVkIHdoZW4gYSBtZW51IGlzIGNsb3NlZC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWVudVN0YWNrQ2xvc2VFdmVudCB7XG4gIC8qKiBUaGUgbWVudSBiZWluZyBjbG9zZWQuICovXG4gIGl0ZW06IE1lbnVTdGFja0l0ZW07XG4gIC8qKiBXaGV0aGVyIHRvIGZvY3VzIHRoZSBwYXJlbnQgdHJpZ2dlciBhZnRlciBjbG9zaW5nIHRoZSBtZW51LiAqL1xuICBmb2N1c1BhcmVudFRyaWdnZXI/OiBib29sZWFuO1xufVxuXG4vKiogVGhlIG5leHQgYXZhaWxhYmxlIG1lbnUgc3RhY2sgSUQuICovXG5sZXQgbmV4dElkID0gMDtcblxuLyoqXG4gKiBNZW51U3RhY2sgYWxsb3dzIHN1YnNjcmliZXJzIHRvIGxpc3RlbiBmb3IgY2xvc2UgZXZlbnRzICh3aGVuIGEgTWVudVN0YWNrSXRlbSBpcyBwb3BwZWQgb2ZmXG4gKiBvZiB0aGUgc3RhY2spIGluIG9yZGVyIHRvIHBlcmZvcm0gY2xvc2luZyBhY3Rpb25zLiBVcG9uIHRoZSBNZW51U3RhY2sgYmVpbmcgZW1wdHkgaXQgZW1pdHNcbiAqIGZyb20gdGhlIGBlbXB0eWAgb2JzZXJ2YWJsZSBzcGVjaWZ5aW5nIHRoZSBuZXh0IGZvY3VzIGFjdGlvbiB3aGljaCB0aGUgbGlzdGVuZXIgc2hvdWxkIHBlcmZvcm1cbiAqIGFzIHJlcXVlc3RlZCBieSB0aGUgY2xvc2VyLlxuICovXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgTWVudVN0YWNrIHtcbiAgLyoqIFRoZSBJRCBvZiB0aGlzIG1lbnUgc3RhY2suICovXG4gIHJlYWRvbmx5IGlkID0gYCR7bmV4dElkKyt9YDtcblxuICAvKiogQWxsIE1lbnVTdGFja0l0ZW1zIHRyYWNrZWQgYnkgdGhpcyBNZW51U3RhY2suICovXG4gIHByaXZhdGUgcmVhZG9ubHkgX2VsZW1lbnRzOiBNZW51U3RhY2tJdGVtW10gPSBbXTtcblxuICAvKiogRW1pdHMgdGhlIGVsZW1lbnQgd2hpY2ggd2FzIHBvcHBlZCBvZmYgb2YgdGhlIHN0YWNrIHdoZW4gcmVxdWVzdGVkIGJ5IGEgY2xvc2VyLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IF9jbG9zZSA9IG5ldyBTdWJqZWN0PE1lbnVTdGFja0Nsb3NlRXZlbnQ+KCk7XG5cbiAgLyoqIEVtaXRzIG9uY2UgdGhlIE1lbnVTdGFjayBoYXMgYmVjb21lIGVtcHR5IGFmdGVyIHBvcHBpbmcgb2ZmIGVsZW1lbnRzLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IF9lbXB0eSA9IG5ldyBTdWJqZWN0PEZvY3VzTmV4dCB8IHVuZGVmaW5lZD4oKTtcblxuICAvKiogRW1pdHMgd2hldGhlciBhbnkgbWVudSBpbiB0aGUgbWVudSBzdGFjayBoYXMgZm9jdXMuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgX2hhc0ZvY3VzID0gbmV3IFN1YmplY3Q8Ym9vbGVhbj4oKTtcblxuICAvKiogT2JzZXJ2YWJsZSB3aGljaCBlbWl0cyB0aGUgTWVudVN0YWNrSXRlbSB3aGljaCBoYXMgYmVlbiByZXF1ZXN0ZWQgdG8gY2xvc2UuICovXG4gIHJlYWRvbmx5IGNsb3NlZDogT2JzZXJ2YWJsZTxNZW51U3RhY2tDbG9zZUV2ZW50PiA9IHRoaXMuX2Nsb3NlO1xuXG4gIC8qKiBPYnNlcnZhYmxlIHdoaWNoIGVtaXRzIHdoZXRoZXIgYW55IG1lbnUgaW4gdGhlIG1lbnUgc3RhY2sgaGFzIGZvY3VzLiAqL1xuICByZWFkb25seSBoYXNGb2N1czogT2JzZXJ2YWJsZTxib29sZWFuPiA9IHRoaXMuX2hhc0ZvY3VzLnBpcGUoXG4gICAgc3RhcnRXaXRoKGZhbHNlKSxcbiAgICBkZWJvdW5jZVRpbWUoMCksXG4gICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKSxcbiAgKTtcblxuICAvKipcbiAgICogT2JzZXJ2YWJsZSB3aGljaCBlbWl0cyB3aGVuIHRoZSBNZW51U3RhY2sgaXMgZW1wdHkgYWZ0ZXIgcG9wcGluZyBvZmYgdGhlIGxhc3QgZWxlbWVudC4gSXRcbiAgICogZW1pdHMgYSBGb2N1c05leHQgZXZlbnQgd2hpY2ggc3BlY2lmaWVzIHRoZSBhY3Rpb24gdGhlIGNsb3NlciBoYXMgcmVxdWVzdGVkIHRoZSBsaXN0ZW5lclxuICAgKiBwZXJmb3JtLlxuICAgKi9cbiAgcmVhZG9ubHkgZW1wdGllZDogT2JzZXJ2YWJsZTxGb2N1c05leHQgfCB1bmRlZmluZWQ+ID0gdGhpcy5fZW1wdHk7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIGlubGluZSBtZW51IGFzc29jaWF0ZWQgd2l0aCB0aGlzIG1lbnUgc3RhY2sgaXMgdmVydGljYWwgb3IgaG9yaXpvbnRhbC5cbiAgICogYG51bGxgIGluZGljYXRlcyB0aGVyZSBpcyBubyBpbmxpbmUgbWVudSBhc3NvY2lhdGVkIHdpdGggdGhpcyBtZW51IHN0YWNrLlxuICAgKi9cbiAgcHJpdmF0ZSBfaW5saW5lTWVudU9yaWVudGF0aW9uOiAndmVydGljYWwnIHwgJ2hvcml6b250YWwnIHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqIENyZWF0ZXMgYSBtZW51IHN0YWNrIHRoYXQgb3JpZ2luYXRlcyBmcm9tIGFuIGlubGluZSBtZW51LiAqL1xuICBzdGF0aWMgaW5saW5lKG9yaWVudGF0aW9uOiAndmVydGljYWwnIHwgJ2hvcml6b250YWwnKSB7XG4gICAgY29uc3Qgc3RhY2sgPSBuZXcgTWVudVN0YWNrKCk7XG4gICAgc3RhY2suX2lubGluZU1lbnVPcmllbnRhdGlvbiA9IG9yaWVudGF0aW9uO1xuICAgIHJldHVybiBzdGFjaztcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGFuIGl0ZW0gdG8gdGhlIG1lbnUgc3RhY2suXG4gICAqIEBwYXJhbSBtZW51IHRoZSBNZW51U3RhY2tJdGVtIHRvIHB1dCBvbiB0aGUgc3RhY2suXG4gICAqL1xuICBwdXNoKG1lbnU6IE1lbnVTdGFja0l0ZW0pIHtcbiAgICB0aGlzLl9lbGVtZW50cy5wdXNoKG1lbnUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFBvcCBpdGVtcyBvZmYgb2YgdGhlIHN0YWNrIHVwIHRvIGFuZCBpbmNsdWRpbmcgYGxhc3RJdGVtYCBhbmQgZW1pdCBlYWNoIG9uIHRoZSBjbG9zZVxuICAgKiBvYnNlcnZhYmxlLiBJZiB0aGUgc3RhY2sgaXMgZW1wdHkgb3IgYGxhc3RJdGVtYCBpcyBub3Qgb24gdGhlIHN0YWNrIGl0IGRvZXMgbm90aGluZy5cbiAgICogQHBhcmFtIGxhc3RJdGVtIHRoZSBsYXN0IGl0ZW0gdG8gcG9wIG9mZiB0aGUgc3RhY2suXG4gICAqIEBwYXJhbSBvcHRpb25zIE9wdGlvbnMgdGhhdCBjb25maWd1cmUgYmVoYXZpb3Igb24gY2xvc2UuXG4gICAqL1xuICBjbG9zZShsYXN0SXRlbTogTWVudVN0YWNrSXRlbSwgb3B0aW9ucz86IENsb3NlT3B0aW9ucykge1xuICAgIGNvbnN0IHtmb2N1c05leHRPbkVtcHR5LCBmb2N1c1BhcmVudFRyaWdnZXJ9ID0gey4uLm9wdGlvbnN9O1xuICAgIGlmICh0aGlzLl9lbGVtZW50cy5pbmRleE9mKGxhc3RJdGVtKSA+PSAwKSB7XG4gICAgICBsZXQgcG9wcGVkRWxlbWVudDtcbiAgICAgIGRvIHtcbiAgICAgICAgcG9wcGVkRWxlbWVudCA9IHRoaXMuX2VsZW1lbnRzLnBvcCgpITtcbiAgICAgICAgdGhpcy5fY2xvc2UubmV4dCh7aXRlbTogcG9wcGVkRWxlbWVudCwgZm9jdXNQYXJlbnRUcmlnZ2VyfSk7XG4gICAgICB9IHdoaWxlIChwb3BwZWRFbGVtZW50ICE9PSBsYXN0SXRlbSk7XG5cbiAgICAgIGlmICh0aGlzLmlzRW1wdHkoKSkge1xuICAgICAgICB0aGlzLl9lbXB0eS5uZXh0KGZvY3VzTmV4dE9uRW1wdHkpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQb3AgaXRlbXMgb2ZmIG9mIHRoZSBzdGFjayB1cCB0byBidXQgZXhjbHVkaW5nIGBsYXN0SXRlbWAgYW5kIGVtaXQgZWFjaCBvbiB0aGUgY2xvc2VcbiAgICogb2JzZXJ2YWJsZS4gSWYgdGhlIHN0YWNrIGlzIGVtcHR5IG9yIGBsYXN0SXRlbWAgaXMgbm90IG9uIHRoZSBzdGFjayBpdCBkb2VzIG5vdGhpbmcuXG4gICAqIEBwYXJhbSBsYXN0SXRlbSB0aGUgZWxlbWVudCB3aGljaCBzaG91bGQgYmUgbGVmdCBvbiB0aGUgc3RhY2tcbiAgICogQHJldHVybiB3aGV0aGVyIG9yIG5vdCBhbiBpdGVtIHdhcyByZW1vdmVkIGZyb20gdGhlIHN0YWNrXG4gICAqL1xuICBjbG9zZVN1Yk1lbnVPZihsYXN0SXRlbTogTWVudVN0YWNrSXRlbSkge1xuICAgIGxldCByZW1vdmVkID0gZmFsc2U7XG4gICAgaWYgKHRoaXMuX2VsZW1lbnRzLmluZGV4T2YobGFzdEl0ZW0pID49IDApIHtcbiAgICAgIHJlbW92ZWQgPSB0aGlzLnBlZWsoKSAhPT0gbGFzdEl0ZW07XG4gICAgICB3aGlsZSAodGhpcy5wZWVrKCkgIT09IGxhc3RJdGVtKSB7XG4gICAgICAgIHRoaXMuX2Nsb3NlLm5leHQoe2l0ZW06IHRoaXMuX2VsZW1lbnRzLnBvcCgpIX0pO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVtb3ZlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBQb3Agb2ZmIGFsbCBNZW51U3RhY2tJdGVtcyBhbmQgZW1pdCBlYWNoIG9uZSBvbiB0aGUgYGNsb3NlYCBvYnNlcnZhYmxlIG9uZSBieSBvbmUuXG4gICAqIEBwYXJhbSBvcHRpb25zIE9wdGlvbnMgdGhhdCBjb25maWd1cmUgYmVoYXZpb3Igb24gY2xvc2UuXG4gICAqL1xuICBjbG9zZUFsbChvcHRpb25zPzogQ2xvc2VPcHRpb25zKSB7XG4gICAgY29uc3Qge2ZvY3VzTmV4dE9uRW1wdHksIGZvY3VzUGFyZW50VHJpZ2dlcn0gPSB7Li4ub3B0aW9uc307XG4gICAgaWYgKCF0aGlzLmlzRW1wdHkoKSkge1xuICAgICAgd2hpbGUgKCF0aGlzLmlzRW1wdHkoKSkge1xuICAgICAgICBjb25zdCBtZW51U3RhY2tJdGVtID0gdGhpcy5fZWxlbWVudHMucG9wKCk7XG4gICAgICAgIGlmIChtZW51U3RhY2tJdGVtKSB7XG4gICAgICAgICAgdGhpcy5fY2xvc2UubmV4dCh7aXRlbTogbWVudVN0YWNrSXRlbSwgZm9jdXNQYXJlbnRUcmlnZ2VyfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRoaXMuX2VtcHR5Lm5leHQoZm9jdXNOZXh0T25FbXB0eSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFJldHVybiB0cnVlIGlmIHRoaXMgc3RhY2sgaXMgZW1wdHkuICovXG4gIGlzRW1wdHkoKSB7XG4gICAgcmV0dXJuICF0aGlzLl9lbGVtZW50cy5sZW5ndGg7XG4gIH1cblxuICAvKiogUmV0dXJuIHRoZSBsZW5ndGggb2YgdGhlIHN0YWNrLiAqL1xuICBsZW5ndGgoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2VsZW1lbnRzLmxlbmd0aDtcbiAgfVxuXG4gIC8qKiBHZXQgdGhlIHRvcCBtb3N0IGVsZW1lbnQgb24gdGhlIHN0YWNrLiAqL1xuICBwZWVrKCk6IE1lbnVTdGFja0l0ZW0gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9lbGVtZW50c1t0aGlzLl9lbGVtZW50cy5sZW5ndGggLSAxXTtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIHRoZSBtZW51IHN0YWNrIGlzIGFzc29jaWF0ZWQgd2l0aCBhbiBpbmxpbmUgbWVudS4gKi9cbiAgaGFzSW5saW5lTWVudSgpIHtcbiAgICByZXR1cm4gdGhpcy5faW5saW5lTWVudU9yaWVudGF0aW9uICE9IG51bGw7XG4gIH1cblxuICAvKiogVGhlIG9yaWVudGF0aW9uIG9mIHRoZSBhc3NvY2lhdGVkIGlubGluZSBtZW51LiAqL1xuICBpbmxpbmVNZW51T3JpZW50YXRpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuX2lubGluZU1lbnVPcmllbnRhdGlvbjtcbiAgfVxuXG4gIC8qKiBTZXRzIHdoZXRoZXIgdGhlIG1lbnUgc3RhY2sgY29udGFpbnMgdGhlIGZvY3VzZWQgZWxlbWVudC4gKi9cbiAgc2V0SGFzRm9jdXMoaGFzRm9jdXM6IGJvb2xlYW4pIHtcbiAgICB0aGlzLl9oYXNGb2N1cy5uZXh0KGhhc0ZvY3VzKTtcbiAgfVxufVxuIl19
\No newline at end of file