contextMenuContent.component.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /**
  2. * @fileoverview added by tsickle
  3. * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  4. */
  5. import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
  6. import { OverlayRef } from '@angular/cdk/overlay';
  7. import { ChangeDetectorRef, Component, ElementRef, EventEmitter, HostListener, Inject, Input, Optional, Output, QueryList, ViewChild, ViewChildren } from '@angular/core';
  8. import { Subscription } from 'rxjs';
  9. import { CONTEXT_MENU_OPTIONS } from './contextMenu.tokens';
  10. /**
  11. * @record
  12. */
  13. export function ILinkConfig() { }
  14. if (false) {
  15. /** @type {?} */
  16. ILinkConfig.prototype.click;
  17. /** @type {?|undefined} */
  18. ILinkConfig.prototype.enabled;
  19. /** @type {?} */
  20. ILinkConfig.prototype.html;
  21. }
  22. /** @type {?} */
  23. const ARROW_LEFT_KEYCODE = 37;
  24. export class ContextMenuContentComponent {
  25. /**
  26. * @param {?} changeDetector
  27. * @param {?} elementRef
  28. * @param {?} options
  29. */
  30. constructor(changeDetector, elementRef, options) {
  31. this.changeDetector = changeDetector;
  32. this.elementRef = elementRef;
  33. this.options = options;
  34. this.menuItems = [];
  35. this.isLeaf = false;
  36. this.execute = new EventEmitter();
  37. this.openSubMenu = new EventEmitter();
  38. this.closeLeafMenu = new EventEmitter();
  39. this.closeAllMenus = new EventEmitter();
  40. this.autoFocus = false;
  41. this.useBootstrap4 = false;
  42. this.subscription = new Subscription();
  43. if (options) {
  44. this.autoFocus = options.autoFocus;
  45. this.useBootstrap4 = options.useBootstrap4;
  46. }
  47. }
  48. /**
  49. * @return {?}
  50. */
  51. ngOnInit() {
  52. this.menuItems.forEach((/**
  53. * @param {?} menuItem
  54. * @return {?}
  55. */
  56. menuItem => {
  57. menuItem.currentItem = this.item;
  58. this.subscription.add(menuItem.execute.subscribe((/**
  59. * @param {?} event
  60. * @return {?}
  61. */
  62. event => this.execute.emit(Object.assign({}, event, { menuItem })))));
  63. }));
  64. /** @type {?} */
  65. const queryList = new QueryList();
  66. queryList.reset(this.menuItems);
  67. this._keyManager = new ActiveDescendantKeyManager(queryList).withWrap();
  68. }
  69. /**
  70. * @return {?}
  71. */
  72. ngAfterViewInit() {
  73. if (this.autoFocus) {
  74. setTimeout((/**
  75. * @return {?}
  76. */
  77. () => this.focus()));
  78. }
  79. this.overlay.updatePosition();
  80. }
  81. /**
  82. * @return {?}
  83. */
  84. ngOnDestroy() {
  85. this.subscription.unsubscribe();
  86. }
  87. /**
  88. * @return {?}
  89. */
  90. focus() {
  91. if (this.autoFocus) {
  92. this.menuElement.nativeElement.focus();
  93. }
  94. }
  95. /**
  96. * @param {?} $event
  97. * @return {?}
  98. */
  99. stopEvent($event) {
  100. $event.stopPropagation();
  101. }
  102. /**
  103. * @param {?} menuItem
  104. * @return {?}
  105. */
  106. isMenuItemEnabled(menuItem) {
  107. return this.evaluateIfFunction(menuItem && menuItem.enabled);
  108. }
  109. /**
  110. * @param {?} menuItem
  111. * @return {?}
  112. */
  113. isMenuItemVisible(menuItem) {
  114. return this.evaluateIfFunction(menuItem && menuItem.visible);
  115. }
  116. /**
  117. * @param {?} value
  118. * @return {?}
  119. */
  120. evaluateIfFunction(value) {
  121. if (value instanceof Function) {
  122. return value(this.item);
  123. }
  124. return value;
  125. }
  126. /**
  127. * @param {?} link
  128. * @return {?}
  129. */
  130. isDisabled(link) {
  131. return link.enabled && !link.enabled(this.item);
  132. }
  133. /**
  134. * @param {?} event
  135. * @return {?}
  136. */
  137. onKeyEvent(event) {
  138. if (!this.isLeaf) {
  139. return;
  140. }
  141. this._keyManager.onKeydown(event);
  142. }
  143. /**
  144. * @param {?=} event
  145. * @return {?}
  146. */
  147. keyboardOpenSubMenu(event) {
  148. if (!this.isLeaf) {
  149. return;
  150. }
  151. this.cancelEvent(event);
  152. /** @type {?} */
  153. const menuItem = this.menuItems[this._keyManager.activeItemIndex];
  154. if (menuItem) {
  155. this.onOpenSubMenu(menuItem);
  156. }
  157. }
  158. /**
  159. * @param {?=} event
  160. * @return {?}
  161. */
  162. keyboardMenuItemSelect(event) {
  163. if (!this.isLeaf) {
  164. return;
  165. }
  166. this.cancelEvent(event);
  167. /** @type {?} */
  168. const menuItem = this.menuItems[this._keyManager.activeItemIndex];
  169. if (menuItem) {
  170. this.onMenuItemSelect(menuItem, event);
  171. }
  172. }
  173. /**
  174. * @param {?} event
  175. * @return {?}
  176. */
  177. onCloseLeafMenu(event) {
  178. if (!this.isLeaf) {
  179. return;
  180. }
  181. this.cancelEvent(event);
  182. this.closeLeafMenu.emit({
  183. exceptRootMenu: event.keyCode === ARROW_LEFT_KEYCODE,
  184. event
  185. });
  186. }
  187. /**
  188. * @param {?} event
  189. * @return {?}
  190. */
  191. closeMenu(event) {
  192. if (event.type === 'click' && event.button === 2) {
  193. return;
  194. }
  195. this.closeAllMenus.emit({ event });
  196. }
  197. /**
  198. * @param {?} menuItem
  199. * @param {?=} event
  200. * @return {?}
  201. */
  202. onOpenSubMenu(menuItem, event) {
  203. /** @type {?} */
  204. const anchorElementRef = this.menuItemElements.toArray()[this._keyManager.activeItemIndex];
  205. /** @type {?} */
  206. const anchorElement = anchorElementRef && anchorElementRef.nativeElement;
  207. this.openSubMenu.emit({
  208. anchorElement,
  209. contextMenu: menuItem.subMenu,
  210. event,
  211. item: this.item,
  212. parentContextMenu: this
  213. });
  214. }
  215. /**
  216. * @param {?} menuItem
  217. * @param {?} event
  218. * @return {?}
  219. */
  220. onMenuItemSelect(menuItem, event) {
  221. event.preventDefault();
  222. event.stopPropagation();
  223. this.onOpenSubMenu(menuItem, event);
  224. if (!menuItem.subMenu) {
  225. menuItem.triggerExecute(this.item, event);
  226. }
  227. }
  228. /**
  229. * @private
  230. * @param {?} event
  231. * @return {?}
  232. */
  233. cancelEvent(event) {
  234. if (!event) {
  235. return;
  236. }
  237. /** @type {?} */
  238. const target = event.target;
  239. if (['INPUT', 'TEXTAREA', 'SELECT'].indexOf(target.tagName) > -1 ||
  240. target.isContentEditable) {
  241. return;
  242. }
  243. event.preventDefault();
  244. event.stopPropagation();
  245. }
  246. }
  247. ContextMenuContentComponent.decorators = [
  248. { type: Component, args: [{
  249. selector: 'context-menu-content',
  250. template: `
  251. <div
  252. class="dropdown open show ngx-contextmenu"
  253. [ngClass]="menuClass"
  254. tabindex="0"
  255. >
  256. <ul
  257. #menu
  258. class="dropdown-menu show"
  259. style="position: static; float: none;"
  260. tabindex="0"
  261. >
  262. <li
  263. #li
  264. *ngFor="let menuItem of menuItems; let i = index"
  265. [class.disabled]="!isMenuItemEnabled(menuItem)"
  266. [class.divider]="menuItem.divider"
  267. [class.dropdown-divider]="useBootstrap4 && menuItem.divider"
  268. [class.active]="menuItem.isActive && isMenuItemEnabled(menuItem)"
  269. [attr.role]="menuItem.divider ? 'separator' : undefined"
  270. >
  271. <a
  272. *ngIf="!menuItem.divider && !menuItem.passive"
  273. href
  274. [class.dropdown-item]="useBootstrap4"
  275. [class.active]="menuItem.isActive && isMenuItemEnabled(menuItem)"
  276. [class.disabled]="useBootstrap4 && !isMenuItemEnabled(menuItem)"
  277. [class.hasSubMenu]="!!menuItem.subMenu"
  278. (click)="onMenuItemSelect(menuItem, $event)"
  279. (mouseenter)="onOpenSubMenu(menuItem, $event)"
  280. >
  281. <ng-template
  282. [ngTemplateOutlet]="menuItem.template"
  283. [ngTemplateOutletContext]="{ $implicit: item }"
  284. ></ng-template>
  285. </a>
  286. <span
  287. (click)="stopEvent($event)"
  288. (contextmenu)="stopEvent($event)"
  289. class="passive"
  290. *ngIf="!menuItem.divider && menuItem.passive"
  291. [class.dropdown-item]="useBootstrap4"
  292. [class.disabled]="useBootstrap4 && !isMenuItemEnabled(menuItem)"
  293. >
  294. <ng-template
  295. [ngTemplateOutlet]="menuItem.template"
  296. [ngTemplateOutletContext]="{ $implicit: item }"
  297. ></ng-template>
  298. </span>
  299. </li>
  300. </ul>
  301. </div>
  302. `,
  303. styles: [`
  304. .passive {
  305. display: block;
  306. padding: 3px 20px;
  307. clear: both;
  308. font-weight: normal;
  309. line-height: @line-height-base;
  310. white-space: nowrap;
  311. }
  312. .hasSubMenu:before {
  313. content: '\u25B6';
  314. float: right;
  315. }
  316. `]
  317. }] }
  318. ];
  319. /** @nocollapse */
  320. ContextMenuContentComponent.ctorParameters = () => [
  321. { type: ChangeDetectorRef },
  322. { type: ElementRef },
  323. { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [CONTEXT_MENU_OPTIONS,] }] }
  324. ];
  325. ContextMenuContentComponent.propDecorators = {
  326. menuItems: [{ type: Input }],
  327. item: [{ type: Input }],
  328. event: [{ type: Input }],
  329. parentContextMenu: [{ type: Input }],
  330. menuClass: [{ type: Input }],
  331. overlay: [{ type: Input }],
  332. isLeaf: [{ type: Input }],
  333. execute: [{ type: Output }],
  334. openSubMenu: [{ type: Output }],
  335. closeLeafMenu: [{ type: Output }],
  336. closeAllMenus: [{ type: Output }],
  337. menuElement: [{ type: ViewChild, args: ['menu', { static: true },] }],
  338. menuItemElements: [{ type: ViewChildren, args: ['li',] }],
  339. onKeyEvent: [{ type: HostListener, args: ['window:keydown.ArrowDown', ['$event'],] }, { type: HostListener, args: ['window:keydown.ArrowUp', ['$event'],] }],
  340. keyboardOpenSubMenu: [{ type: HostListener, args: ['window:keydown.ArrowRight', ['$event'],] }],
  341. keyboardMenuItemSelect: [{ type: HostListener, args: ['window:keydown.Enter', ['$event'],] }, { type: HostListener, args: ['window:keydown.Space', ['$event'],] }],
  342. onCloseLeafMenu: [{ type: HostListener, args: ['window:keydown.Escape', ['$event'],] }, { type: HostListener, args: ['window:keydown.ArrowLeft', ['$event'],] }],
  343. closeMenu: [{ type: HostListener, args: ['document:click', ['$event'],] }, { type: HostListener, args: ['document:contextmenu', ['$event'],] }]
  344. };
  345. if (false) {
  346. /** @type {?} */
  347. ContextMenuContentComponent.prototype.menuItems;
  348. /** @type {?} */
  349. ContextMenuContentComponent.prototype.item;
  350. /** @type {?} */
  351. ContextMenuContentComponent.prototype.event;
  352. /** @type {?} */
  353. ContextMenuContentComponent.prototype.parentContextMenu;
  354. /** @type {?} */
  355. ContextMenuContentComponent.prototype.menuClass;
  356. /** @type {?} */
  357. ContextMenuContentComponent.prototype.overlay;
  358. /** @type {?} */
  359. ContextMenuContentComponent.prototype.isLeaf;
  360. /** @type {?} */
  361. ContextMenuContentComponent.prototype.execute;
  362. /** @type {?} */
  363. ContextMenuContentComponent.prototype.openSubMenu;
  364. /** @type {?} */
  365. ContextMenuContentComponent.prototype.closeLeafMenu;
  366. /** @type {?} */
  367. ContextMenuContentComponent.prototype.closeAllMenus;
  368. /** @type {?} */
  369. ContextMenuContentComponent.prototype.menuElement;
  370. /** @type {?} */
  371. ContextMenuContentComponent.prototype.menuItemElements;
  372. /** @type {?} */
  373. ContextMenuContentComponent.prototype.autoFocus;
  374. /** @type {?} */
  375. ContextMenuContentComponent.prototype.useBootstrap4;
  376. /**
  377. * @type {?}
  378. * @private
  379. */
  380. ContextMenuContentComponent.prototype._keyManager;
  381. /**
  382. * @type {?}
  383. * @private
  384. */
  385. ContextMenuContentComponent.prototype.subscription;
  386. /**
  387. * @type {?}
  388. * @private
  389. */
  390. ContextMenuContentComponent.prototype.changeDetector;
  391. /**
  392. * @type {?}
  393. * @private
  394. */
  395. ContextMenuContentComponent.prototype.elementRef;
  396. /**
  397. * @type {?}
  398. * @private
  399. */
  400. ContextMenuContentComponent.prototype.options;
  401. }
  402. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dE1lbnVDb250ZW50LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL25neC1jb250ZXh0bWVudS8iLCJzb3VyY2VzIjpbImxpYi9jb250ZXh0TWVudUNvbnRlbnQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxFQUVMLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixZQUFZLEVBQ1osTUFBTSxFQUNOLEtBQUssRUFHTCxRQUFRLEVBQ1IsTUFBTSxFQUNOLFNBQVMsRUFDVCxTQUFTLEVBQ1QsWUFBWSxFQUNiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFPcEMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7Ozs7QUFFNUQsaUNBSUM7OztJQUhDLDRCQUFnRDs7SUFDaEQsOEJBQWlDOztJQUNqQywyQkFBNEI7OztNQUd4QixrQkFBa0IsR0FBRyxFQUFFO0FBMkU3QixNQUFNLE9BQU8sMkJBQTJCOzs7Ozs7SUE4QnRDLFlBQ1UsY0FBaUMsRUFDakMsVUFBc0IsRUFHdEIsT0FBNEI7UUFKNUIsbUJBQWMsR0FBZCxjQUFjLENBQW1CO1FBQ2pDLGVBQVUsR0FBVixVQUFVLENBQVk7UUFHdEIsWUFBTyxHQUFQLE9BQU8sQ0FBcUI7UUFqQ3RCLGNBQVMsR0FBK0IsRUFBRSxDQUFDO1FBTTNDLFdBQU0sR0FBRyxLQUFLLENBQUM7UUFDZCxZQUFPLEdBSW5CLElBQUksWUFBWSxFQUFFLENBQUM7UUFDUCxnQkFBVyxHQUV4QixJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ04sa0JBQWEsR0FFMUIsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNOLGtC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QUN4QixrREFFdUI7O0lBQ3ZCLG9EQUV1Qjs7SUFDdkIsb0RBRXdCOztJQUN4QixrREFBb0U7O0lBQ3BFLHVEQUFtRTs7SUFFbkUsZ0RBQXlCOztJQUN6QixvREFBNkI7Ozs7O0lBQzdCLGtEQUEwRTs7Ozs7SUFDMUUsbURBQXdEOzs7OztJQUV0RCxxREFBeUM7Ozs7O0lBQ3pDLGlEQUE4Qjs7Ozs7SUFDOUIsOENBRW9DIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQWN0aXZlRGVzY2VuZGFudEtleU1hbmFnZXIgfSBmcm9tICdAYW5ndWxhci9jZGsvYTExeSc7XG5pbXBvcnQgeyBPdmVybGF5UmVmIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL292ZXJsYXknO1xuaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgRWxlbWVudFJlZixcbiAgRXZlbnRFbWl0dGVyLFxuICBIb3N0TGlzdGVuZXIsXG4gIEluamVjdCxcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBPcHRpb25hbCxcbiAgT3V0cHV0LFxuICBRdWVyeUxpc3QsXG4gIFZpZXdDaGlsZCxcbiAgVmlld0NoaWxkcmVuXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBDb250ZXh0TWVudUl0ZW1EaXJlY3RpdmUgfSBmcm9tICcuL2NvbnRleHRNZW51Lml0ZW0uZGlyZWN0aXZlJztcbmltcG9ydCB7IElDb250ZXh0TWVudU9wdGlvbnMgfSBmcm9tICcuL2NvbnRleHRNZW51Lm9wdGlvbnMnO1xuaW1wb3J0IHtcbiAgQ2xvc2VMZWFmTWVudUV2ZW50LFxuICBJQ29udGV4dE1lbnVDbGlja0V2ZW50XG59IGZyb20gJy4vY29udGV4dE1lbnUuc2VydmljZSc7XG5pbXBvcnQgeyBDT05URVhUX01FTlVfT1BUSU9OUyB9IGZyb20gJy4vY29udGV4dE1lbnUudG9rZW5zJztcblxuZXhwb3J0IGludGVyZmFjZSBJTGlua0NvbmZpZyB7XG4gIGNsaWNrOiAoaXRlbTogYW55LCAkZXZlbnQ/OiBNb3VzZUV2ZW50KSA9PiB2b2lkO1xuICBlbmFibGVkPzogKGl0ZW06IGFueSkgPT4gYm9vbGVhbjtcbiAgaHRtbDogKGl0ZW06IGFueSkgPT4gc3RyaW5nO1xufVxuXG5jb25zdCBBUlJPV19MRUZUX0tFWUNPREUgPSAzNztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY29udGV4dC1tZW51LWNvbnRlbnQnLFxuICBzdHlsZXM6IFtcbiAgICBgXG4gICAgICAucGFzc2l2ZSB7XG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgICBwYWRkaW5nOiAzcHggMjBweDtcbiAgICAgICAgY2xlYXI6IGJvdGg7XG4gICAgICAgIGZvbnQtd2VpZ2h0OiBub3JtYWw7XG4gICAgICAgIGxpbmUtaGVpZ2h0OiBAbGluZS1oZWlnaHQtYmFzZTtcbiAgICAgICAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgICAgIH1cbiAgICAgIC5oYXNTdWJNZW51OmJlZm9yZSB7XG4gICAgICAgIGNvbnRlbnQ6ICdcXHUyNUI2JztcbiAgICAgICAgZmxvYXQ6IHJpZ2h0O1xuICAgICAgfVxuICAgIGBcbiAgXSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2XG4gICAgICBjbGFzcz1cImRyb3Bkb3duIG9wZW4gc2hvdyBuZ3gtY29udGV4dG1lbnVcIlxuICAgICAgW25nQ2xhc3NdPVwibWVudUNsYXNzXCJcbiAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgPlxuICAgICAgPHVsXG4gICAgICAgICNtZW51XG4gICAgICAgIGNsYXNzPVwiZHJvcGRvd24tbWVudSBzaG93XCJcbiAgICAgICAgc3R5bGU9XCJwb3NpdGlvbjogc3RhdGljOyBmbG9hdDogbm9uZTtcIlxuICAgICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgPlxuICAgICAgICA8bGlcbiAgICAgICAgICAjbGlcbiAgICAgICAgICAqbmdGb3I9XCJsZXQgbWVudUl0ZW0gb2YgbWVudUl0ZW1zOyBsZXQgaSA9IGluZGV4XCJcbiAgICAgICAgICBbY2xhc3MuZGlzYWJsZWRdPVwiIWlzTWVudUl0ZW1FbmFibGVkKG1lbnVJdGVtKVwiXG4gICAgICAgICAgW2NsYXNzLmRpdmlkZXJdPVwibWVudUl0ZW0uZGl2aWRlclwiXG4gICAgICAgICAgW2NsYXNzLmRyb3Bkb3duLWRpdmlkZXJdPVwidXNlQm9vdHN0cmFwNCAmJiBtZW51SXRlbS5kaXZpZGVyXCJcbiAgICAgICAgICBbY2xhc3MuYWN0aXZlXT1cIm1lbnVJdGVtLmlzQWN0aXZlICYmIGlzTWVudUl0ZW1FbmFibGVkKG1lbnVJdGVtKVwiXG4gICAgICAgICAgW2F0dHIucm9sZV09XCJtZW51SXRlbS5kaXZpZGVyID8gJ3NlcGFyYXRvcicgOiB1bmRlZmluZWRcIlxuICAgICAgICA+XG4gICAgICAgICAgPGFcbiAgICAgICAgICAgICpuZ0lmPVwiIW1lbnVJdGVtLmRpdmlkZXIgJiYgIW1lbnVJdGVtLnBhc3NpdmVcIlxuICAgICAgICAgICAgaHJlZlxuICAgICAgICAgICAgW2NsYXNzLmRyb3Bkb3duLWl0ZW1dPVwidXNlQm9vdHN0cmFwNFwiXG4gICAgICAgICAgICBbY2xhc3MuYWN0aXZlXT1cIm1lbnVJdGVtLmlzQWN0aXZlICYmIGlzTWVudUl0ZW1FbmFibGVkKG1lbnVJdGVtKVwiXG4gICAgICAgICAgICBbY2xhc3MuZGlzYWJsZWRdPVwidXNlQm9vdHN0cmFwNCAmJiAhaXNNZW51SXRlbUVuYWJsZWQobWVudUl0ZW0pXCJcbiAgICAgICAgICAgIFtjbGFzcy5oYXNTdWJNZW51XT1cIiEhbWVudUl0ZW0uc3ViTWVudVwiXG4gICAgICAgICAgICAoY2xpY2spPVwib25NZW51SXRlbVNlbGVjdChtZW51SXRlbSwgJGV2ZW50KVwiXG4gICAgICAgICAgICAobW91c2VlbnRlcik9XCJvbk9wZW5TdWJNZW51KG1lbnVJdGVtLCAkZXZlbnQpXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRdPVwibWVudUl0ZW0udGVtcGxhdGVcIlxuICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyAkaW1wbGljaXQ6IGl0ZW0gfVwiXG4gICAgICAgICAgICA+PC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8L2E+XG5cbiAgICAgICAgICA8c3BhblxuICAgICAgICAgICAgKGNsaWNrKT1cInN0b3BFdmVudCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChjb250ZXh0bWVudSk9XCJzdG9wRXZlbnQoJGV2ZW50KVwiXG4gICAgICAgICAgICBjbGFzcz1cInBhc3NpdmVcIlxuICAgICAgICAgICAgKm5nSWY9XCIhbWVudUl0ZW0uZGl2aWRlciAmJiBtZW51SXRlbS5wYXNzaXZlXCJcbiAgICAgICAgICAgIFtjbGFzcy5kcm9wZG93bi1pdGVtXT1cInVzZUJvb3RzdHJhcDRcIlxuICAgICAgICAgICAgW2NsYXNzLmRpc2FibGVkXT1cInVzZUJvb3RzdHJhcDQgJiYgIWlzTWVudUl0ZW1FbmFibGVkKG1lbnVJdGVtKVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPG5nLXRlbXBsYXRlXG4gICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cIm1lbnVJdGVtLnRlbXBsYXRlXCJcbiAgICAgICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgJGltcGxpY2l0OiBpdGVtIH1cIlxuICAgICAgICAgICAgPjwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgPC9zcGFuPlxuICAgICAgICA8L2xpPlxuICAgICAgPC91bD5cbiAgICA8L2Rpdj5cbiAgYFxufSlcbmV4cG9ydCBjbGFzcyBDb250ZXh0TWVudUNvbnRlbnRDb21wb25lbnRcbiAgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSwgQWZ0ZXJWaWV3SW5pdCB7XG4gIEBJbnB1dCgpIHB1YmxpYyBtZW51SXRlbXM6IENvbnRleHRNZW51SXRlbURpcmVjdGl2ZVtdID0gW107XG4gIEBJbnB1dCgpIHB1YmxpYyBpdGVtOiBhbnk7XG4gIEBJbnB1dCgpIHB1YmxpYyBldmVudDogTW91c2VFdmVudCB8IEtleWJvYXJkRXZlbnQ7XG4gIEBJbnB1dCgpIHB1YmxpYyBwYXJlbnRDb250ZXh0TWVudTogQ29udGV4dE1lbnVDb250ZW50Q29tcG9uZW50O1xuICBASW5wdXQoKSBwdWJsaWMgbWVudUNsYXNzOiBzdHJpbmc7XG4gIEBJbnB1dCgpIHB1YmxpYyBvdmVybGF5OiBPdmVybGF5UmVmO1xuICBASW5wdXQoKSBwdWJsaWMgaXNMZWFmID0gZmFsc2U7XG4gIEBPdXRwdXQoKSBwdWJsaWMgZXhlY3V0ZTogRXZlbnRFbWl0dGVyPHtcbiAgICBldmVudDogTW91c2VFdmVudCB8IEtleWJvYXJkRXZlbnQ7XG4gICAgaXRlbTogYW55O1xuICAgIG1lbnVJdGVtOiBDb250ZXh0TWVudUl0ZW1EaXJlY3RpdmU7XG4gIH0+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KCkgcHVibGljIG9wZW5TdWJNZW51OiBFdmVudEVtaXR0ZXI8XG4gICAgSUNvbnRleHRNZW51Q2xpY2tFdmVudFxuICA+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KCkgcHVibGljIGNsb3NlTGVhZk1lbnU6IEV2ZW50RW1pdHRlcjxcbiAgICBDbG9zZUxlYWZNZW51RXZlbnRcbiAgPiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQE91dHB1dCgpIHB1YmxpYyBjbG9zZUFsbE1lbnVzOiBFdmVudEVtaXR0ZXI8e1xuICAgIGV2ZW50OiBNb3VzZUV2ZW50O1xuICB9PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQFZpZXdDaGlsZCgnbWVudScsIHsgc3RhdGljOiB0cnVlIH0pIHB1YmxpYyBtZW51RWxlbWVudDogRWxlbWVudFJlZjtcbiAgQFZpZXdDaGlsZHJlbignbGknKSBwdWJsaWMgbWVudUl0ZW1FbGVtZW50czogUXVlcnlMaXN0PEVsZW1lbnRSZWY+O1xuXG4gIHB1YmxpYyBhdXRvRm9jdXMgPSBmYWxzZTtcbiAgcHVibGljIHVzZUJvb3RzdHJhcDQgPSBmYWxzZTtcbiAgcHJpdmF0ZSBfa2V5TWFuYWdlcjogQWN0aXZlRGVzY2VuZGFudEtleU1hbmFnZXI8Q29udGV4dE1lbnVJdGVtRGlyZWN0aXZlPjtcbiAgcHJpdmF0ZSBzdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbiA9IG5ldyBTdWJzY3JpcHRpb24oKTtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBjaGFuZ2VEZXRlY3RvcjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHJpdmF0ZSBlbGVtZW50UmVmOiBFbGVtZW50UmVmLFxuICAgIEBPcHRpb25hbCgpXG4gICAgQEluamVjdChDT05URVhUX01FTlVfT1BUSU9OUylcbiAgICBwcml2YXRlIG9wdGlvbnM6IElDb250ZXh0TWVudU9wdGlvbnNcbiAgKSB7XG4gICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgIHRoaXMuYXV0b0ZvY3VzID0gb3B0aW9ucy5hdXRvRm9jdXM7XG4gICAgICB0aGlzLnVzZUJvb3RzdHJhcDQgPSBvcHRpb25zLnVzZUJvb3RzdHJhcDQ7XG4gICAgfVxuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5tZW51SXRlbXMuZm9yRWFjaChtZW51SXRlbSA9PiB7XG4gICAgICBtZW51SXRlbS5jdXJyZW50SXRlbSA9IHRoaXMuaXRlbTtcbiAgICAgIHRoaXMuc3Vic2NyaXB0aW9uLmFkZChcbiAgICAgICAgbWVudUl0ZW0uZXhlY3V0ZS5zdWJzY3JpYmUoZXZlbnQgPT5cbiAgICAgICAgICB0aGlzLmV4ZWN1dGUuZW1pdCh7IC4uLmV2ZW50LCBtZW51SXRlbSB9KVxuICAgICAgICApXG4gICAgICApO1xuICAgIH0pO1xuICAgIGNvbnN0IHF1ZXJ5TGlzdCA9IG5ldyBRdWVyeUxpc3Q8Q29udGV4dE1lbnVJdGVtRGlyZWN0aXZlPigpO1xuICAgIHF1ZXJ5TGlzdC5yZXNldCh0aGlzLm1lbnVJdGVtcyk7XG4gICAgdGhpcy5fa2V5TWFuYWdlciA9IG5ldyBBY3RpdmVEZXNjZW5kYW50S2V5TWFuYWdlcjxDb250ZXh0TWVudUl0ZW1EaXJlY3RpdmU+KFxuICAgICAgcXVlcnlMaXN0XG4gICAgKS53aXRoV3JhcCgpO1xuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCkge1xuICAgIGlmICh0aGlzLmF1dG9Gb2N1cykge1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLmZvY3VzKCkpO1xuICAgIH1cbiAgICB0aGlzLm92ZXJsYXkudXBkYXRlUG9zaXRpb24oKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCkge1xuICAgIHRoaXMuc3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gIH1cblxuICBmb2N1cygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5hdXRvRm9jdXMpIHtcbiAgICAgIHRoaXMubWVudUVsZW1lbnQubmF0aXZlRWxlbWVudC5mb2N1cygpO1xuICAgIH1cbiAgfVxuXG4gIHN0b3BFdmVudCgkZXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICAkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gIH1cblxuICBwdWJsaWMgaXNNZW51SXRlbUVuYWJsZWQobWVudUl0ZW06IENvbnRleHRNZW51SXRlbURpcmVjdGl2ZSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmV2YWx1YXRlSWZGdW5jdGlvbihtZW51SXRlbSAmJiBtZW51SXRlbS5lbmFibGVkKTtcbiAgfVxuXG4gIHB1YmxpYyBpc01lbnVJdGVtVmlzaWJsZShtZW51SXRlbTogQ29udGV4dE1lbnVJdGVtRGlyZWN0aXZlKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuZXZhbHVhdGVJZkZ1bmN0aW9uKG1lbnVJdGVtICYmIG1lbnVJdGVtLnZpc2libGUpO1xuICB9XG5cbiAgcHVibGljIGV2YWx1YXRlSWZGdW5jdGlvbih2YWx1ZTogYW55KTogYW55IHtcbiAgICBpZiAodmFsdWUgaW5zdGFuY2VvZiBGdW5jdGlvbikge1xuICAgICAgcmV0dXJuIHZhbHVlKHRoaXMuaXRlbSk7XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbiAgfVxuXG4gIHB1YmxpYyBpc0Rpc2FibGVkKGxpbms6IElMaW5rQ29uZmlnKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGxpbmsuZW5hYmxlZCAmJiAhbGluay5lbmFibGVkKHRoaXMuaXRlbSk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6a2V5ZG93bi5BcnJvd0Rvd24nLCBbJyRldmVudCddKVxuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6a2V5ZG93bi5BcnJvd1VwJywgWyckZXZlbnQnXSlcbiAgcHVibGljIG9uS2V5RXZlbnQoZXZlbnQ6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNMZWFmKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuX2tleU1hbmFnZXIub25LZXlkb3duKGV2ZW50KTtcbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzprZXlkb3duLkFycm93UmlnaHQnLCBbJyRldmVudCddKVxuICBwdWJsaWMga2V5Ym9hcmRPcGVuU3ViTWVudShldmVudD86IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNMZWFmKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuY2FuY2VsRXZlbnQoZXZlbnQpO1xuICAgIGNvbnN0IG1lbnVJdGVtID0gdGhpcy5tZW51SXRlbXNbdGhpcy5fa2V5TWFuYWdlci5hY3RpdmVJdGVtSW5kZXhdO1xuICAgIGlmIChtZW51SXRlbSkge1xuICAgICAgdGhpcy5vbk9wZW5TdWJNZW51KG1lbnVJdGVtKTtcbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6a2V5ZG93bi5FbnRlcicsIFsnJGV2ZW50J10pXG4gIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzprZXlkb3duLlNwYWNlJywgWyckZXZlbnQnXSlcbiAgcHVibGljIGtleWJvYXJkTWVudUl0ZW1TZWxlY3QoZXZlbnQ/OiBLZXlib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmlzTGVhZikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmNhbmNlbEV2ZW50KGV2ZW50KTtcbiAgICBjb25zdCBtZW51SXRlbSA9IHRoaXMubWVudUl0ZW1zW3RoaXMuX2tleU1hbmFnZXIuYWN0aXZlSXRlbUluZGV4XTtcbiAgICBpZiAobWVudUl0ZW0pIHtcbiAgICAgIHRoaXMub25NZW51SXRlbVNlbGVjdChtZW51SXRlbSwgZXZlbnQpO1xuICAgIH1cbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzprZXlkb3duLkVzY2FwZScsIFsnJGV2ZW50J10pXG4gIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzprZXlkb3duLkFycm93TGVmdCcsIFsnJGV2ZW50J10pXG4gIHB1YmxpYyBvbkNsb3NlTGVhZk1lbnUoZXZlbnQ6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNMZWFmKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuY2FuY2VsRXZlbnQoZXZlbnQpO1xuICAgIHRoaXMuY2xvc2VMZWFmTWVudS5lbWl0KHtcbiAgICAgIGV4Y2VwdFJvb3RNZW51OiBldmVudC5rZXlDb2RlID09PSBBUlJPV19MRUZUX0tFWUNPREUsXG4gICAgICBldmVudFxuICAgIH0pO1xuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6Y2xpY2snLCBbJyRldmVudCddKVxuICBASG9zdExpc3RlbmVyKCdkb2N1bWVudDpjb250ZXh0bWVudScsIFsnJGV2ZW50J10pXG4gIHB1YmxpYyBjbG9zZU1lbnUoZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoZXZlbnQudHlwZSA9PT0gJ2NsaWNrJyAmJiBldmVudC5idXR0b24gPT09IDIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5jbG9zZUFsbE1lbnVzLmVtaXQoeyBldmVudCB9KTtcbiAgfVxuXG4gIHB1YmxpYyBvbk9wZW5TdWJNZW51KFxuICAgIG1lbnVJdGVtOiBDb250ZXh0TWVudUl0ZW1EaXJlY3RpdmUsXG4gICAgZXZlbnQ/OiBNb3VzZUV2ZW50IHwgS2V5Ym9hcmRFdmVudFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBhbmNob3JFbGVtZW50UmVmID0gdGhpcy5tZW51SXRlbUVsZW1lbnRzLnRvQXJyYXkoKVtcbiAgICAgIHRoaXMuX2tleU1hbmFnZXIuYWN0aXZlSXRlbUluZGV4XG4gICAgXTtcbiAgICBjb25zdCBhbmNob3JFbGVtZW50ID0gYW5jaG9yRWxlbWVudFJlZiAmJiBhbmNob3JFbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQ7XG4gICAgdGhpcy5vcGVuU3ViTWVudS5lbWl0KHtcbiAgICAgIGFuY2hvckVsZW1lbnQsXG4gICAgICBjb250ZXh0TWVudTogbWVudUl0ZW0uc3ViTWVudSxcbiAgICAgIGV2ZW50LFxuICAgICAgaXRlbTogdGhpcy5pdGVtLFxuICAgICAgcGFyZW50Q29udGV4dE1lbnU6IHRoaXNcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBvbk1lbnVJdGVtU2VsZWN0KFxuICAgIG1lbnVJdGVtOiBDb250ZXh0TWVudUl0ZW1EaXJlY3RpdmUsXG4gICAgZXZlbnQ6IE1vdXNlRXZlbnQgfCBLZXlib2FyZEV2ZW50XG4gICk6IHZvaWQge1xuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgdGhpcy5vbk9wZW5TdWJNZW51KG1lbnVJdGVtLCBldmVudCk7XG4gICAgaWYgKCFtZW51SXRlbS5zdWJNZW51KSB7XG4gICAgICBtZW51SXRlbS50cmlnZ2VyRXhlY3V0ZSh0aGlzLml0ZW0sIGV2ZW50KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGNhbmNlbEV2ZW50KGV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCFldmVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRhcmdldDogSFRNTEVsZW1lbnQgPSBldmVudC50YXJnZXQ7XG4gICAgaWYgKFxuICAgICAgWydJTlBVVCcsICdURVhUQVJFQScsICdTRUxFQ1QnXS5pbmRleE9mKHRhcmdldC50YWdOYW1lKSA+IC0xIHx8XG4gICAgICB0YXJnZXQuaXNDb250ZW50RWRpdGFibGVcbiAgICApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICB9XG59XG4iXX0=