@ali-hm/angular-tree-component 16.0.1 → 17.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/esm2022/ali-hm-angular-tree-component.mjs +4 -4
  2. package/esm2022/lib/angular-tree-component.module.mjs +99 -99
  3. package/esm2022/lib/components/loading.component.mjs +20 -20
  4. package/esm2022/lib/components/tree-node-checkbox.component.mjs +14 -14
  5. package/esm2022/lib/components/tree-node-collection.component.mjs +119 -119
  6. package/esm2022/lib/components/tree-node-content.component.mjs +22 -22
  7. package/esm2022/lib/components/tree-node-drop-slot.component.mjs +25 -25
  8. package/esm2022/lib/components/tree-node-expander.component.mjs +15 -15
  9. package/esm2022/lib/components/tree-node-wrapper.component.mjs +23 -23
  10. package/esm2022/lib/components/tree-viewport.component.mjs +55 -55
  11. package/esm2022/lib/components/tree.component.mjs +137 -137
  12. package/esm2022/lib/constants/events.mjs +19 -19
  13. package/esm2022/lib/constants/keys.mjs +9 -9
  14. package/esm2022/lib/defs/api.mjs +1 -1
  15. package/esm2022/lib/directives/tree-animate-open.directive.mjs +101 -101
  16. package/esm2022/lib/directives/tree-drag.directive.mjs +65 -65
  17. package/esm2022/lib/directives/tree-drop.directive.mjs +127 -127
  18. package/esm2022/lib/mobx-angular/mobx-proxy.mjs +16 -16
  19. package/esm2022/lib/mobx-angular/tree-mobx-autorun.directive.mjs +40 -40
  20. package/esm2022/lib/models/tree-dragged-element.model.mjs +24 -24
  21. package/esm2022/lib/models/tree-node.model.mjs +389 -389
  22. package/esm2022/lib/models/tree-options.model.mjs +150 -150
  23. package/esm2022/lib/models/tree-virtual-scroll.model.mjs +197 -197
  24. package/esm2022/lib/models/tree.model.mjs +546 -546
  25. package/esm2022/public-api.mjs +4 -4
  26. package/fesm2022/ali-hm-angular-tree-component.mjs +2080 -2080
  27. package/fesm2022/ali-hm-angular-tree-component.mjs.map +1 -1
  28. package/index.d.ts +5 -5
  29. package/lib/angular-tree-component.module.d.ts +43 -43
  30. package/lib/components/loading.component.d.ts +9 -9
  31. package/lib/components/tree-node-checkbox.component.d.ts +7 -7
  32. package/lib/components/tree-node-collection.component.d.ts +34 -34
  33. package/lib/components/tree-node-content.component.d.ts +10 -10
  34. package/lib/components/tree-node-drop-slot.component.d.ts +10 -10
  35. package/lib/components/tree-node-expander.component.d.ts +7 -7
  36. package/lib/components/tree-node-wrapper.component.d.ts +9 -9
  37. package/lib/components/tree-viewport.component.d.ts +17 -17
  38. package/lib/components/tree.component.d.ts +47 -47
  39. package/lib/constants/events.d.ts +19 -19
  40. package/lib/constants/keys.d.ts +9 -9
  41. package/lib/defs/api.d.ts +611 -611
  42. package/lib/directives/tree-animate-open.directive.d.ts +20 -20
  43. package/lib/directives/tree-drag.directive.d.ts +21 -21
  44. package/lib/directives/tree-drop.directive.d.ts +33 -33
  45. package/lib/mobx-angular/mobx-proxy.d.ts +7 -7
  46. package/lib/mobx-angular/tree-mobx-autorun.directive.d.ts +17 -17
  47. package/lib/models/tree-dragged-element.model.d.ts +9 -9
  48. package/lib/models/tree-node.model.d.ts +83 -83
  49. package/lib/models/tree-options.model.d.ts +77 -77
  50. package/lib/models/tree-virtual-scroll.model.d.ts +27 -27
  51. package/lib/models/tree.model.d.ts +91 -91
  52. package/package.json +3 -3
  53. package/public-api.d.ts +1 -1
@@ -1,197 +1,197 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { Injectable } from '@angular/core';
8
- import { observable, computed, action, autorun, reaction } from 'mobx';
9
- import { TREE_EVENTS } from '../constants/events';
10
- import * as i0 from "@angular/core";
11
- import * as i1 from "./tree.model";
12
- const Y_OFFSET = 500; // Extra pixels outside the viewport, in each direction, to render nodes in
13
- const Y_EPSILON = 150; // Minimum pixel change required to recalculate the rendered nodes
14
- export class TreeVirtualScroll {
15
- get y() {
16
- return this.yBlocks * Y_EPSILON;
17
- }
18
- get totalHeight() {
19
- return this.treeModel.virtualRoot ? this.treeModel.virtualRoot.height : 0;
20
- }
21
- constructor(treeModel) {
22
- this.treeModel = treeModel;
23
- this.yBlocks = 0;
24
- this.x = 0;
25
- this.viewportHeight = null;
26
- this.viewport = null;
27
- treeModel.virtualScroll = this;
28
- this._dispose = [autorun(() => this.fixScroll())];
29
- }
30
- fireEvent(event) {
31
- this.treeModel.fireEvent(event);
32
- }
33
- init() {
34
- const fn = this.recalcPositions.bind(this);
35
- fn();
36
- this._dispose = [
37
- ...this._dispose,
38
- reaction(() => this.treeModel.roots, fn),
39
- reaction(() => this.treeModel.expandedNodeIds, fn),
40
- reaction(() => this.treeModel.hiddenNodeIds, fn)
41
- ];
42
- this.treeModel.subscribe(TREE_EVENTS.loadNodeChildren, fn);
43
- }
44
- isEnabled() {
45
- return this.treeModel.options.useVirtualScroll;
46
- }
47
- _setYBlocks(value) {
48
- this.yBlocks = value;
49
- }
50
- recalcPositions() {
51
- this.treeModel.virtualRoot.height = this._getPositionAfter(this.treeModel.getVisibleRoots(), 0);
52
- }
53
- _getPositionAfter(nodes, startPos) {
54
- let position = startPos;
55
- nodes.forEach((node) => {
56
- node.position = position;
57
- position = this._getPositionAfterNode(node, position);
58
- });
59
- return position;
60
- }
61
- _getPositionAfterNode(node, startPos) {
62
- let position = node.getSelfHeight() + startPos;
63
- if (node.children && node.isExpanded) { // TBD: consider loading component as well
64
- position = this._getPositionAfter(node.visibleChildren, position);
65
- }
66
- node.height = position - startPos;
67
- return position;
68
- }
69
- clear() {
70
- this._dispose.forEach((d) => d());
71
- }
72
- setViewport(viewport) {
73
- Object.assign(this, {
74
- viewport,
75
- x: viewport.scrollLeft,
76
- yBlocks: Math.round(viewport.scrollTop / Y_EPSILON),
77
- viewportHeight: viewport.getBoundingClientRect ? viewport.getBoundingClientRect().height : 0
78
- });
79
- }
80
- scrollIntoView(node, force, scrollToMiddle = true) {
81
- if (node.options.scrollContainer) {
82
- const scrollContainer = node.options.scrollContainer;
83
- const scrollContainerHeight = scrollContainer.getBoundingClientRect().height;
84
- const scrollContainerTop = scrollContainer.getBoundingClientRect().top;
85
- const nodeTop = this.viewport.getBoundingClientRect().top + node.position - scrollContainerTop;
86
- if (force || // force scroll to node
87
- nodeTop < scrollContainer.scrollTop || // node is above scroll container
88
- nodeTop + node.getSelfHeight() > scrollContainer.scrollTop + scrollContainerHeight) { // node is below container
89
- scrollContainer.scrollTop = scrollToMiddle ?
90
- nodeTop - scrollContainerHeight / 2 : // scroll to middle
91
- nodeTop; // scroll to start
92
- }
93
- }
94
- else {
95
- if (force || // force scroll to node
96
- node.position < this.y || // node is above viewport
97
- node.position + node.getSelfHeight() > this.y + this.viewportHeight) { // node is below viewport
98
- if (this.viewport) {
99
- this.viewport.scrollTop = scrollToMiddle ?
100
- node.position - this.viewportHeight / 2 : // scroll to middle
101
- node.position; // scroll to start
102
- this._setYBlocks(Math.floor(this.viewport.scrollTop / Y_EPSILON));
103
- }
104
- }
105
- }
106
- }
107
- getViewportNodes(nodes) {
108
- if (!nodes)
109
- return [];
110
- const visibleNodes = nodes.filter((node) => !node.isHidden);
111
- if (!this.isEnabled())
112
- return visibleNodes;
113
- if (!this.viewportHeight || !visibleNodes.length)
114
- return [];
115
- // When loading children async this method is called before their height and position is calculated.
116
- // In that case firstIndex === 0 and lastIndex === visibleNodes.length - 1 (e.g. 1000),
117
- // which means that it loops through every visibleNodes item and push them into viewportNodes array.
118
- // We can prevent nodes from being pushed to the array and wait for the appropriate calculations to take place
119
- const lastVisibleNode = visibleNodes.slice(-1)[0];
120
- if (!lastVisibleNode.height && lastVisibleNode.position === 0)
121
- return [];
122
- // Search for first node in the viewport using binary search
123
- // Look for first node that starts after the beginning of the viewport (with buffer)
124
- // Or that ends after the beginning of the viewport
125
- const firstIndex = binarySearch(visibleNodes, (node) => {
126
- return (node.position + Y_OFFSET > this.y) ||
127
- (node.position + node.height > this.y);
128
- });
129
- // Search for last node in the viewport using binary search
130
- // Look for first node that starts after the end of the viewport (with buffer)
131
- const lastIndex = binarySearch(visibleNodes, (node) => {
132
- return node.position - Y_OFFSET > this.y + this.viewportHeight;
133
- }, firstIndex);
134
- const viewportNodes = [];
135
- for (let i = firstIndex; i <= lastIndex; i++) {
136
- viewportNodes.push(visibleNodes[i]);
137
- }
138
- return viewportNodes;
139
- }
140
- fixScroll() {
141
- const maxY = Math.max(0, this.totalHeight - this.viewportHeight);
142
- if (this.y < 0)
143
- this._setYBlocks(0);
144
- if (this.y > maxY)
145
- this._setYBlocks(maxY / Y_EPSILON);
146
- }
147
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TreeVirtualScroll, deps: [{ token: i1.TreeModel }], target: i0.ɵɵFactoryTarget.Injectable }); }
148
- /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TreeVirtualScroll }); }
149
- }
150
- __decorate([
151
- observable
152
- ], TreeVirtualScroll.prototype, "yBlocks", void 0);
153
- __decorate([
154
- observable
155
- ], TreeVirtualScroll.prototype, "x", void 0);
156
- __decorate([
157
- observable
158
- ], TreeVirtualScroll.prototype, "viewportHeight", void 0);
159
- __decorate([
160
- computed
161
- ], TreeVirtualScroll.prototype, "y", null);
162
- __decorate([
163
- computed
164
- ], TreeVirtualScroll.prototype, "totalHeight", null);
165
- __decorate([
166
- action
167
- ], TreeVirtualScroll.prototype, "_setYBlocks", null);
168
- __decorate([
169
- action
170
- ], TreeVirtualScroll.prototype, "recalcPositions", null);
171
- __decorate([
172
- action
173
- ], TreeVirtualScroll.prototype, "setViewport", null);
174
- __decorate([
175
- action
176
- ], TreeVirtualScroll.prototype, "scrollIntoView", null);
177
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TreeVirtualScroll, decorators: [{
178
- type: Injectable
179
- }], ctorParameters: function () { return [{ type: i1.TreeModel }]; }, propDecorators: { yBlocks: [], x: [], viewportHeight: [], y: [], totalHeight: [], _setYBlocks: [], recalcPositions: [], setViewport: [], scrollIntoView: [] } });
180
- function binarySearch(nodes, condition, firstIndex = 0) {
181
- let index = firstIndex;
182
- let toIndex = nodes.length - 1;
183
- while (index !== toIndex) {
184
- let midIndex = Math.floor((index + toIndex) / 2);
185
- if (condition(nodes[midIndex])) {
186
- toIndex = midIndex;
187
- }
188
- else {
189
- if (index === midIndex)
190
- index = toIndex;
191
- else
192
- index = midIndex;
193
- }
194
- }
195
- return index;
196
- }
197
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS12aXJ0dWFsLXNjcm9sbC5tb2RlbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItdHJlZS1jb21wb25lbnQvc3JjL2xpYi9tb2RlbHMvdHJlZS12aXJ0dWFsLXNjcm9sbC5tb2RlbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRXZFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7O0FBRWxELE1BQU0sUUFBUSxHQUFHLEdBQUcsQ0FBQyxDQUFDLDJFQUEyRTtBQUNqRyxNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsQ0FBQyxrRUFBa0U7QUFHekYsTUFBTSxPQUFPLGlCQUFpQjtJQVFsQixJQUFJLENBQUM7UUFDYixPQUFPLElBQUksQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDO0lBQ2xDLENBQUM7SUFFUyxJQUFJLFdBQVc7UUFDdkIsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUVELFlBQW9CLFNBQW9CO1FBQXBCLGNBQVMsR0FBVCxTQUFTLENBQVc7UUFiNUIsWUFBTyxHQUFHLENBQUMsQ0FBQztRQUNaLE1BQUMsR0FBRyxDQUFDLENBQUM7UUFDTixtQkFBYyxHQUFHLElBQUksQ0FBQztRQUNsQyxhQUFRLEdBQUcsSUFBSSxDQUFDO1FBV2QsU0FBUyxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUM7UUFDL0IsSUFBSSxDQUFDLFFBQVEsR0FBRyxDQUFDLE9BQU8sQ0FB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VTs0Q0FBTztBQUNOO0lBQVgsVUFBVTt5REFBdUI7QUFHeEI7SUFBVCxRQUFROzBDQUVSO0FBRVM7SUFBVCxRQUFRO29EQUVSO0FBNEJPO0lBQVAsTUFBTTtvREFFTjtBQUVPO0lBQVAsTUFBTTt3REFFTjtBQTJCTztJQUFQLE1BQU07b0RBT047QUFFTztJQUFQLE1BQU07dURBMkJOOzRGQS9HVSxpQkFBaUI7a0JBRDdCLFVBQVU7Z0dBSUcsT0FBTyxNQUNQLENBQUMsTUFDRCxjQUFjLE1BR1osQ0FBQyxNQUlELFdBQVcsTUE4QlQsV0FBVyxNQUluQixlQUFlLE1BNkJmLFdBQVcsTUFTWCxjQUFjO0FBNEV4QixTQUFTLFlBQVksQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLFVBQVUsR0FBRyxDQUFDO0lBQ3BELElBQUksS0FBSyxHQUFHLFVBQVUsQ0FBQztJQUN2QixJQUFJLE9BQU8sR0FBRyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztJQUUvQixPQUFPLEtBQUssS0FBSyxPQUFPLEVBQUU7UUFDeEIsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUVqRCxJQUFJLFNBQVMsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRTtZQUM5QixPQUFPLEdBQUcsUUFBUSxDQUFDO1NBQ3BCO2FBQ0k7WUFDSCxJQUFJLEtBQUssS0FBSyxRQUFRO2dCQUFFLEtBQUssR0FBRyxPQUFPLENBQUM7O2dCQUNuQyxLQUFLLEdBQUcsUUFBUSxDQUFDO1NBQ3ZCO0tBQ0Y7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IG9ic2VydmFibGUsIGNvbXB1dGVkLCBhY3Rpb24sIGF1dG9ydW4sIHJlYWN0aW9uIH0gZnJvbSAnbW9ieCc7XHJcbmltcG9ydCB7IFRyZWVNb2RlbCB9IGZyb20gJy4vdHJlZS5tb2RlbCc7XHJcbmltcG9ydCB7IFRSRUVfRVZFTlRTIH0gZnJvbSAnLi4vY29uc3RhbnRzL2V2ZW50cyc7XHJcblxyXG5jb25zdCBZX09GRlNFVCA9IDUwMDsgLy8gRXh0cmEgcGl4ZWxzIG91dHNpZGUgdGhlIHZpZXdwb3J0LCBpbiBlYWNoIGRpcmVjdGlvbiwgdG8gcmVuZGVyIG5vZGVzIGluXHJcbmNvbnN0IFlfRVBTSUxPTiA9IDE1MDsgLy8gTWluaW11bSBwaXhlbCBjaGFuZ2UgcmVxdWlyZWQgdG8gcmVjYWxjdWxhdGUgdGhlIHJlbmRlcmVkIG5vZGVzXHJcblxyXG5ASW5qZWN0YWJsZSgpXHJcbmV4cG9ydCBjbGFzcyBUcmVlVmlydHVhbFNjcm9sbCB7XHJcbiAgcHJpdmF0ZSBfZGlzcG9zZTogYW55O1xyXG5cclxuICBAb2JzZXJ2YWJsZSB5QmxvY2tzID0gMDtcclxuICBAb2JzZXJ2YWJsZSB4ID0gMDtcclxuICBAb2JzZXJ2YWJsZSB2aWV3cG9ydEhlaWdodCA9IG51bGw7XHJcbiAgdmlld3BvcnQgPSBudWxsO1xyXG5cclxuICBAY29tcHV0ZWQgZ2V0IHkoKSB7XHJcbiAgICByZXR1cm4gdGhpcy55QmxvY2tzICogWV9FUFNJTE9OO1xyXG4gIH1cclxuXHJcbiAgQGNvbXB1dGVkIGdldCB0b3RhbEhlaWdodCgpIHtcclxuICAgIHJldHVybiB0aGlzLnRyZWVNb2RlbC52aXJ0dWFsUm9vdCA/IHRoaXMudHJlZU1vZGVsLnZpcnR1YWxSb290LmhlaWdodCA6IDA7XHJcbiAgfVxyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHRyZWVNb2RlbDogVHJlZU1vZGVsKSB7XHJcbiAgICB0cmVlTW9kZWwudmlydHVhbFNjcm9sbCA9IHRoaXM7XHJcbiAgICB0aGlzLl9kaXNwb3NlID0gW2F1dG9ydW4oKCkgPT4gdGhpcy5maXhTY3JvbGwoKSldO1xyXG4gIH1cclxuXHJcbiAgZmlyZUV2ZW50KGV2ZW50KSB7XHJcbiAgICB0aGlzLnRyZWVNb2RlbC5maXJlRXZlbnQoZXZlbnQpO1xyXG4gIH1cclxuXHJcbiAgaW5pdCgpIHtcclxuICAgIGNvbnN0IGZuID0gdGhpcy5yZWNhbGNQb3NpdGlvbnMuYmluZCh0aGlzKTtcclxuXHJcbiAgICBmbigpO1xyXG4gICAgdGhpcy5fZGlzcG9zZSA9IFtcclxuICAgICAgLi4udGhpcy5fZGlzcG9zZSxcclxuICAgICAgcmVhY3Rpb24oKCkgPT4gdGhpcy50cmVlTW9kZWwucm9vdHMsIGZuKSxcclxuICAgICAgcmVhY3Rpb24oKCkgPT4gdGhpcy50cmVlTW9kZWwuZXhwYW5kZWROb2RlSWRzLCBmbiksXHJcbiAgICAgIHJlYWN0aW9uKCgpID0+IHRoaXMudHJlZU1vZGVsLmhpZGRlbk5vZGVJZHMsIGZuKVxyXG4gICAgXTtcclxuICAgIHRoaXMudHJlZU1vZGVsLnN1YnNjcmliZShUUkVFX0VWRU5UUy5sb2FkTm9kZUNoaWxkcmVuLCBmbik7XHJcbiAgfVxyXG5cclxuICBpc0VuYWJsZWQoKSB7XHJcbiAgICByZXR1cm4gdGhpcy50cmVlTW9kZWwub3B0aW9ucy51c2VWaXJ0dWFsU2Nyb2xsO1xyXG4gIH1cclxuXHJcbiAgQGFjdGlvbiBwcml2YXRlIF9zZXRZQmxvY2tzKHZhbHVlKSB7XHJcbiAgICB0aGlzLnlCbG9ja3MgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIEBhY3Rpb24gcmVjYWxjUG9zaXRpb25zKCkge1xyXG4gICAgdGhpcy50cmVlTW9kZWwudmlydHVhbFJvb3QuaGVpZ2h0ID0gdGhpcy5fZ2V0UG9zaXRpb25BZnRlcih0aGlzLnRyZWVNb2RlbC5nZXRWaXNpYmxlUm9vdHMoKSwgMCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIF9nZXRQb3NpdGlvbkFmdGVyKG5vZGVzLCBzdGFydFBvcykge1xyXG4gICAgbGV0IHBvc2l0aW9uID0gc3RhcnRQb3M7XHJcblxyXG4gICAgbm9kZXMuZm9yRWFjaCgobm9kZSkgPT4ge1xyXG4gICAgICBub2RlLnBvc2l0aW9uID0gcG9zaXRpb247XHJcbiAgICAgIHBvc2l0aW9uID0gdGhpcy5fZ2V0UG9zaXRpb25BZnRlck5vZGUobm9kZSwgcG9zaXRpb24pO1xyXG4gICAgfSk7XHJcbiAgICByZXR1cm4gcG9zaXRpb247XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIF9nZXRQb3NpdGlvbkFmdGVyTm9kZShub2RlLCBzdGFydFBvcykge1xyXG4gICAgbGV0IHBvc2l0aW9uID0gbm9kZS5nZXRTZWxmSGVpZ2h0KCkgKyBzdGFydFBvcztcclxuXHJcbiAgICBpZiAobm9kZS5jaGlsZHJlbiAmJiBub2RlLmlzRXhwYW5kZWQpIHsgLy8gVEJEOiBjb25zaWRlciBsb2FkaW5nIGNvbXBvbmVudCBhcyB3ZWxsXHJcbiAgICAgIHBvc2l0aW9uID0gdGhpcy5fZ2V0UG9zaXRpb25BZnRlcihub2RlLnZpc2libGVDaGlsZHJlbiwgcG9zaXRpb24pO1xyXG4gICAgfVxyXG4gICAgbm9kZS5oZWlnaHQgPSBwb3NpdGlvbiAtIHN0YXJ0UG9zO1xyXG4gICAgcmV0dXJuIHBvc2l0aW9uO1xyXG4gIH1cclxuXHJcblxyXG4gIGNsZWFyKCkge1xyXG4gICAgdGhpcy5fZGlzcG9zZS5mb3JFYWNoKChkKSA9PiBkKCkpO1xyXG4gIH1cclxuXHJcbiAgQGFjdGlvbiBzZXRWaWV3cG9ydCh2aWV3cG9ydCkge1xyXG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCB7XHJcbiAgICAgIHZpZXdwb3J0LFxyXG4gICAgICB4OiB2aWV3cG9ydC5zY3JvbGxMZWZ0LFxyXG4gICAgICB5QmxvY2tzOiBNYXRoLnJvdW5kKHZpZXdwb3J0LnNjcm9sbFRvcCAvIFlfRVBTSUxPTiksXHJcbiAgICAgIHZpZXdwb3J0SGVpZ2h0OiB2aWV3cG9ydC5nZXRCb3VuZGluZ0NsaWVudFJlY3QgPyB2aWV3cG9ydC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQgOiAwXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIEBhY3Rpb24gc2Nyb2xsSW50b1ZpZXcobm9kZSwgZm9yY2UsIHNjcm9sbFRvTWlkZGxlID0gdHJ1ZSkge1xyXG4gICAgaWYgKG5vZGUub3B0aW9ucy5zY3JvbGxDb250YWluZXIpIHtcclxuICAgICAgY29uc3Qgc2Nyb2xsQ29udGFpbmVyID0gbm9kZS5vcHRpb25zLnNjcm9sbENvbnRhaW5lcjtcclxuICAgICAgY29uc3Qgc2Nyb2xsQ29udGFpbmVySGVpZ2h0ID0gc2Nyb2xsQ29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmhlaWdodDtcclxuICAgICAgY29uc3Qgc2Nyb2xsQ29udGFpbmVyVG9wID0gc2Nyb2xsQ29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcDtcclxuICAgICAgY29uc3Qgbm9kZVRvcCA9IHRoaXMudmlld3BvcnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wICsgbm9kZS5wb3NpdGlvbiAtIHNjcm9sbENvbnRhaW5lclRvcDtcclxuXHJcbiAgICAgIGlmIChmb3JjZSB8fCAvLyBmb3JjZSBzY3JvbGwgdG8gbm9kZVxyXG4gICAgICAgIG5vZGVUb3AgPCBzY3JvbGxDb250YWluZXIuc2Nyb2xsVG9wIHx8IC8vIG5vZGUgaXMgYWJvdmUgc2Nyb2xsIGNvbnRhaW5lclxyXG4gICAgICAgIG5vZGVUb3AgKyBub2RlLmdldFNlbGZIZWlnaHQoKSA+IHNjcm9sbENvbnRhaW5lci5zY3JvbGxUb3AgKyBzY3JvbGxDb250YWluZXJIZWlnaHQpIHsgLy8gbm9kZSBpcyBiZWxvdyBjb250YWluZXJcclxuICAgICAgICBzY3JvbGxDb250YWluZXIuc2Nyb2xsVG9wID0gc2Nyb2xsVG9NaWRkbGUgP1xyXG4gICAgICAgICAgbm9kZVRvcCAtIHNjcm9sbENvbnRhaW5lckhlaWdodCAvIDIgOiAvLyBzY3JvbGwgdG8gbWlkZGxlXHJcbiAgICAgICAgICBub2RlVG9wOyAvLyBzY3JvbGwgdG8gc3RhcnRcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgaWYgKGZvcmNlIHx8IC8vIGZvcmNlIHNjcm9sbCB0byBub2RlXHJcbiAgICAgICAgbm9kZS5wb3NpdGlvbiA8IHRoaXMueSB8fCAvLyBub2RlIGlzIGFib3ZlIHZpZXdwb3J0XHJcbiAgICAgICAgbm9kZS5wb3NpdGlvbiArIG5vZGUuZ2V0U2VsZkhlaWdodCgpID4gdGhpcy55ICsgdGhpcy52aWV3cG9ydEhlaWdodCkgeyAvLyBub2RlIGlzIGJlbG93IHZpZXdwb3J0XHJcbiAgICAgICAgaWYgKHRoaXMudmlld3BvcnQpIHtcclxuICAgICAgICAgIHRoaXMudmlld3BvcnQuc2Nyb2xsVG9wID0gc2Nyb2xsVG9NaWRkbGUgP1xyXG4gICAgICAgICAgbm9kZS5wb3NpdGlvbiAtIHRoaXMudmlld3BvcnRIZWlnaHQgLyAyIDogLy8gc2Nyb2xsIHRvIG1pZGRsZVxyXG4gICAgICAgICAgbm9kZS5wb3NpdGlvbjsgLy8gc2Nyb2xsIHRvIHN0YXJ0XHJcblxyXG4gICAgICAgICAgdGhpcy5fc2V0WUJsb2NrcyhNYXRoLmZsb29yKHRoaXMudmlld3BvcnQuc2Nyb2xsVG9wIC8gWV9FUFNJTE9OKSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXRWaWV3cG9ydE5vZGVzKG5vZGVzKSB7XHJcbiAgICBpZiAoIW5vZGVzKSByZXR1cm4gW107XHJcblxyXG4gICAgY29uc3QgdmlzaWJsZU5vZGVzID0gbm9kZXMuZmlsdGVyKChub2RlKSA9PiAhbm9kZS5pc0hpZGRlbik7XHJcblxyXG4gICAgaWYgKCF0aGlzLmlzRW5hYmxlZCgpKSByZXR1cm4gdmlzaWJsZU5vZGVzO1xyXG5cclxuICAgIGlmICghdGhpcy52aWV3cG9ydEhlaWdodCB8fCAhdmlzaWJsZU5vZGVzLmxlbmd0aCkgcmV0dXJuIFtdO1xyXG5cclxuICAgIC8vIFdoZW4gbG9hZGluZyBjaGlsZHJlbiBhc3luYyB0aGlzIG1ldGhvZCBpcyBjYWxsZWQgYmVmb3JlIHRoZWlyIGhlaWdodCBhbmQgcG9zaXRpb24gaXMgY2FsY3VsYXRlZC5cclxuICAgIC8vIEluIHRoYXQgY2FzZSBmaXJzdEluZGV4ID09PSAwIGFuZCBsYXN0SW5kZXggPT09IHZpc2libGVOb2Rlcy5sZW5ndGggLSAxIChlLmcuIDEwMDApLFxyXG4gICAgLy8gd2hpY2ggbWVhbnMgdGhhdCBpdCBsb29wcyB0aHJvdWdoIGV2ZXJ5IHZpc2libGVOb2RlcyBpdGVtIGFuZCBwdXNoIHRoZW0gaW50byB2aWV3cG9ydE5vZGVzIGFycmF5LlxyXG4gICAgLy8gV2UgY2FuIHByZXZlbnQgbm9kZXMgZnJvbSBiZWluZyBwdXNoZWQgdG8gdGhlIGFycmF5IGFuZCB3YWl0IGZvciB0aGUgYXBwcm9wcmlhdGUgY2FsY3VsYXRpb25zIHRvIHRha2UgcGxhY2VcclxuICAgIGNvbnN0IGxhc3RWaXNpYmxlTm9kZSA9IHZpc2libGVOb2Rlcy5zbGljZSgtMSlbMF1cclxuICAgIGlmICghbGFzdFZpc2libGVOb2RlLmhlaWdodCAmJiBsYXN0VmlzaWJsZU5vZGUucG9zaXRpb24gPT09IDApIHJldHVybiBbXTtcclxuXHJcbiAgICAvLyBTZWFyY2ggZm9yIGZpcnN0IG5vZGUgaW4gdGhlIHZpZXdwb3J0IHVzaW5nIGJpbmFyeSBzZWFyY2hcclxuICAgIC8vIExvb2sgZm9yIGZpcnN0IG5vZGUgdGhhdCBzdGFydHMgYWZ0ZXIgdGhlIGJlZ2lubmluZyBvZiB0aGUgdmlld3BvcnQgKHdpdGggYnVmZmVyKVxyXG4gICAgLy8gT3IgdGhhdCBlbmRzIGFmdGVyIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHZpZXdwb3J0XHJcbiAgICBjb25zdCBmaXJzdEluZGV4ID0gYmluYXJ5U2VhcmNoKHZpc2libGVOb2RlcywgKG5vZGUpID0+IHtcclxuICAgICAgcmV0dXJuIChub2RlLnBvc2l0aW9uICsgWV9PRkZTRVQgPiB0aGlzLnkpIHx8XHJcbiAgICAgICAgICAgICAobm9kZS5wb3NpdGlvbiArIG5vZGUuaGVpZ2h0ID4gdGhpcy55KTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFNlYXJjaCBmb3IgbGFzdCBub2RlIGluIHRoZSB2aWV3cG9ydCB1c2luZyBiaW5hcnkgc2VhcmNoXHJcbiAgICAvLyBMb29rIGZvciBmaXJzdCBub2RlIHRoYXQgc3RhcnRzIGFmdGVyIHRoZSBlbmQgb2YgdGhlIHZpZXdwb3J0ICh3aXRoIGJ1ZmZlcilcclxuICAgIGNvbnN0IGxhc3RJbmRleCA9IGJpbmFyeVNlYXJjaCh2aXNpYmxlTm9kZXMsIChub2RlKSA9PiB7XHJcbiAgICAgIHJldHVybiBub2RlLnBvc2l0aW9uIC0gWV9PRkZTRVQgPiB0aGlzLnkgKyB0aGlzLnZpZXdwb3J0SGVpZ2h0O1xyXG4gICAgfSwgZmlyc3RJbmRleCk7XHJcblxyXG4gICAgY29uc3Qgdmlld3BvcnROb2RlcyA9IFtdO1xyXG5cclxuICAgIGZvciAobGV0IGkgPSBmaXJzdEluZGV4OyBpIDw9IGxhc3RJbmRleDsgaSsrKSB7XHJcbiAgICAgIHZpZXdwb3J0Tm9kZXMucHVzaCh2aXNpYmxlTm9kZXNbaV0pO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB2aWV3cG9ydE5vZGVzO1xyXG4gIH1cclxuXHJcbiAgZml4U2Nyb2xsKCkge1xyXG4gICAgY29uc3QgbWF4WSA9IE1hdGgubWF4KDAsIHRoaXMudG90YWxIZWlnaHQgLSB0aGlzLnZpZXdwb3J0SGVpZ2h0KTtcclxuXHJcbiAgICBpZiAodGhpcy55IDwgMCkgdGhpcy5fc2V0WUJsb2NrcygwKTtcclxuICAgIGlmICh0aGlzLnkgPiBtYXhZKSB0aGlzLl9zZXRZQmxvY2tzKG1heFkgLyBZX0VQU0lMT04pO1xyXG4gIH1cclxufVxyXG5cclxuZnVuY3Rpb24gYmluYXJ5U2VhcmNoKG5vZGVzLCBjb25kaXRpb24sIGZpcnN0SW5kZXggPSAwKSB7XHJcbiAgbGV0IGluZGV4ID0gZmlyc3RJbmRleDtcclxuICBsZXQgdG9JbmRleCA9IG5vZGVzLmxlbmd0aCAtIDE7XHJcblxyXG4gIHdoaWxlIChpbmRleCAhPT0gdG9JbmRleCkge1xyXG4gICAgbGV0IG1pZEluZGV4ID0gTWF0aC5mbG9vcigoaW5kZXggKyB0b0luZGV4KSAvIDIpO1xyXG5cclxuICAgIGlmIChjb25kaXRpb24obm9kZXNbbWlkSW5kZXhdKSkge1xyXG4gICAgICB0b0luZGV4ID0gbWlkSW5kZXg7XHJcbiAgICB9XHJcbiAgICBlbHNlIHtcclxuICAgICAgaWYgKGluZGV4ID09PSBtaWRJbmRleCkgaW5kZXggPSB0b0luZGV4O1xyXG4gICAgICBlbHNlIGluZGV4ID0gbWlkSW5kZXg7XHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiBpbmRleDtcclxufVxyXG4iXX0=
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Injectable } from '@angular/core';
8
+ import { observable, computed, action, autorun, reaction } from 'mobx';
9
+ import { TREE_EVENTS } from '../constants/events';
10
+ import * as i0 from "@angular/core";
11
+ import * as i1 from "./tree.model";
12
+ const Y_OFFSET = 500; // Extra pixels outside the viewport, in each direction, to render nodes in
13
+ const Y_EPSILON = 150; // Minimum pixel change required to recalculate the rendered nodes
14
+ export class TreeVirtualScroll {
15
+ get y() {
16
+ return this.yBlocks * Y_EPSILON;
17
+ }
18
+ get totalHeight() {
19
+ return this.treeModel.virtualRoot ? this.treeModel.virtualRoot.height : 0;
20
+ }
21
+ constructor(treeModel) {
22
+ this.treeModel = treeModel;
23
+ this.yBlocks = 0;
24
+ this.x = 0;
25
+ this.viewportHeight = null;
26
+ this.viewport = null;
27
+ treeModel.virtualScroll = this;
28
+ this._dispose = [autorun(() => this.fixScroll())];
29
+ }
30
+ fireEvent(event) {
31
+ this.treeModel.fireEvent(event);
32
+ }
33
+ init() {
34
+ const fn = this.recalcPositions.bind(this);
35
+ fn();
36
+ this._dispose = [
37
+ ...this._dispose,
38
+ reaction(() => this.treeModel.roots, fn),
39
+ reaction(() => this.treeModel.expandedNodeIds, fn),
40
+ reaction(() => this.treeModel.hiddenNodeIds, fn)
41
+ ];
42
+ this.treeModel.subscribe(TREE_EVENTS.loadNodeChildren, fn);
43
+ }
44
+ isEnabled() {
45
+ return this.treeModel.options.useVirtualScroll;
46
+ }
47
+ _setYBlocks(value) {
48
+ this.yBlocks = value;
49
+ }
50
+ recalcPositions() {
51
+ this.treeModel.virtualRoot.height = this._getPositionAfter(this.treeModel.getVisibleRoots(), 0);
52
+ }
53
+ _getPositionAfter(nodes, startPos) {
54
+ let position = startPos;
55
+ nodes.forEach((node) => {
56
+ node.position = position;
57
+ position = this._getPositionAfterNode(node, position);
58
+ });
59
+ return position;
60
+ }
61
+ _getPositionAfterNode(node, startPos) {
62
+ let position = node.getSelfHeight() + startPos;
63
+ if (node.children && node.isExpanded) { // TBD: consider loading component as well
64
+ position = this._getPositionAfter(node.visibleChildren, position);
65
+ }
66
+ node.height = position - startPos;
67
+ return position;
68
+ }
69
+ clear() {
70
+ this._dispose.forEach((d) => d());
71
+ }
72
+ setViewport(viewport) {
73
+ Object.assign(this, {
74
+ viewport,
75
+ x: viewport.scrollLeft,
76
+ yBlocks: Math.round(viewport.scrollTop / Y_EPSILON),
77
+ viewportHeight: viewport.getBoundingClientRect ? viewport.getBoundingClientRect().height : 0
78
+ });
79
+ }
80
+ scrollIntoView(node, force, scrollToMiddle = true) {
81
+ if (node.options.scrollContainer) {
82
+ const scrollContainer = node.options.scrollContainer;
83
+ const scrollContainerHeight = scrollContainer.getBoundingClientRect().height;
84
+ const scrollContainerTop = scrollContainer.getBoundingClientRect().top;
85
+ const nodeTop = this.viewport.getBoundingClientRect().top + node.position - scrollContainerTop;
86
+ if (force || // force scroll to node
87
+ nodeTop < scrollContainer.scrollTop || // node is above scroll container
88
+ nodeTop + node.getSelfHeight() > scrollContainer.scrollTop + scrollContainerHeight) { // node is below container
89
+ scrollContainer.scrollTop = scrollToMiddle ?
90
+ nodeTop - scrollContainerHeight / 2 : // scroll to middle
91
+ nodeTop; // scroll to start
92
+ }
93
+ }
94
+ else {
95
+ if (force || // force scroll to node
96
+ node.position < this.y || // node is above viewport
97
+ node.position + node.getSelfHeight() > this.y + this.viewportHeight) { // node is below viewport
98
+ if (this.viewport) {
99
+ this.viewport.scrollTop = scrollToMiddle ?
100
+ node.position - this.viewportHeight / 2 : // scroll to middle
101
+ node.position; // scroll to start
102
+ this._setYBlocks(Math.floor(this.viewport.scrollTop / Y_EPSILON));
103
+ }
104
+ }
105
+ }
106
+ }
107
+ getViewportNodes(nodes) {
108
+ if (!nodes)
109
+ return [];
110
+ const visibleNodes = nodes.filter((node) => !node.isHidden);
111
+ if (!this.isEnabled())
112
+ return visibleNodes;
113
+ if (!this.viewportHeight || !visibleNodes.length)
114
+ return [];
115
+ // When loading children async this method is called before their height and position is calculated.
116
+ // In that case firstIndex === 0 and lastIndex === visibleNodes.length - 1 (e.g. 1000),
117
+ // which means that it loops through every visibleNodes item and push them into viewportNodes array.
118
+ // We can prevent nodes from being pushed to the array and wait for the appropriate calculations to take place
119
+ const lastVisibleNode = visibleNodes.slice(-1)[0];
120
+ if (!lastVisibleNode.height && lastVisibleNode.position === 0)
121
+ return [];
122
+ // Search for first node in the viewport using binary search
123
+ // Look for first node that starts after the beginning of the viewport (with buffer)
124
+ // Or that ends after the beginning of the viewport
125
+ const firstIndex = binarySearch(visibleNodes, (node) => {
126
+ return (node.position + Y_OFFSET > this.y) ||
127
+ (node.position + node.height > this.y);
128
+ });
129
+ // Search for last node in the viewport using binary search
130
+ // Look for first node that starts after the end of the viewport (with buffer)
131
+ const lastIndex = binarySearch(visibleNodes, (node) => {
132
+ return node.position - Y_OFFSET > this.y + this.viewportHeight;
133
+ }, firstIndex);
134
+ const viewportNodes = [];
135
+ for (let i = firstIndex; i <= lastIndex; i++) {
136
+ viewportNodes.push(visibleNodes[i]);
137
+ }
138
+ return viewportNodes;
139
+ }
140
+ fixScroll() {
141
+ const maxY = Math.max(0, this.totalHeight - this.viewportHeight);
142
+ if (this.y < 0)
143
+ this._setYBlocks(0);
144
+ if (this.y > maxY)
145
+ this._setYBlocks(maxY / Y_EPSILON);
146
+ }
147
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TreeVirtualScroll, deps: [{ token: i1.TreeModel }], target: i0.ɵɵFactoryTarget.Injectable }); }
148
+ /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TreeVirtualScroll }); }
149
+ }
150
+ __decorate([
151
+ observable
152
+ ], TreeVirtualScroll.prototype, "yBlocks", void 0);
153
+ __decorate([
154
+ observable
155
+ ], TreeVirtualScroll.prototype, "x", void 0);
156
+ __decorate([
157
+ observable
158
+ ], TreeVirtualScroll.prototype, "viewportHeight", void 0);
159
+ __decorate([
160
+ computed
161
+ ], TreeVirtualScroll.prototype, "y", null);
162
+ __decorate([
163
+ computed
164
+ ], TreeVirtualScroll.prototype, "totalHeight", null);
165
+ __decorate([
166
+ action
167
+ ], TreeVirtualScroll.prototype, "_setYBlocks", null);
168
+ __decorate([
169
+ action
170
+ ], TreeVirtualScroll.prototype, "recalcPositions", null);
171
+ __decorate([
172
+ action
173
+ ], TreeVirtualScroll.prototype, "setViewport", null);
174
+ __decorate([
175
+ action
176
+ ], TreeVirtualScroll.prototype, "scrollIntoView", null);
177
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TreeVirtualScroll, decorators: [{
178
+ type: Injectable
179
+ }], ctorParameters: () => [{ type: i1.TreeModel }], propDecorators: { yBlocks: [], x: [], viewportHeight: [], y: [], totalHeight: [], _setYBlocks: [], recalcPositions: [], setViewport: [], scrollIntoView: [] } });
180
+ function binarySearch(nodes, condition, firstIndex = 0) {
181
+ let index = firstIndex;
182
+ let toIndex = nodes.length - 1;
183
+ while (index !== toIndex) {
184
+ let midIndex = Math.floor((index + toIndex) / 2);
185
+ if (condition(nodes[midIndex])) {
186
+ toIndex = midIndex;
187
+ }
188
+ else {
189
+ if (index === midIndex)
190
+ index = toIndex;
191
+ else
192
+ index = midIndex;
193
+ }
194
+ }
195
+ return index;
196
+ }
197
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS12aXJ0dWFsLXNjcm9sbC5tb2RlbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItdHJlZS1jb21wb25lbnQvc3JjL2xpYi9tb2RlbHMvdHJlZS12aXJ0dWFsLXNjcm9sbC5tb2RlbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRXZFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7O0FBRWxELE1BQU0sUUFBUSxHQUFHLEdBQUcsQ0FBQyxDQUFDLDJFQUEyRTtBQUNqRyxNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsQ0FBQyxrRUFBa0U7QUFHekYsTUFBTSxPQUFPLGlCQUFpQjtJQVFsQixJQUFJLENBQUM7UUFDYixPQUFPLElBQUksQ0FBQyxPQUFPLEdBQUcsU0FBUyxDQUFDO0lBQ2xDLENBQUM7SUFFUyxJQUFJLFdBQVc7UUFDdkIsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUVELFlBQW9CLFNBQW9CO1FBQXBCLGNBQVMsR0FBVCxTQUFTLENBQVc7UUFiNUIsWUFBTyxHQUFHLENBQUMsQ0FBQztRQUNaLE1BQUMsR0FBRyxDQUFDLENBQUM7UUFDTixtQkFBYyxHQUFHLElBQUksQ0FBQztRQUNsQyxhQUFRLEdBQUcsSUFBSSxDQUFDO1FBV2QsU0FBUyxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUM7UUFDL0IsSUFBSSxDQUFDLFFBQVEsR0FBRyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRCxTQUFTLENBQUMsS0FBSztRQUNiLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFRCxJQUFJO1FBQ0YsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFM0MsRUFBRSxFQUFFLENBQUM7UUFDTCxJQUFJLENBQUMsUUFBUSxHQUFHO1lBQ2QsR0FBRyxJQUFJLENBQUMsUUFBUTtZQUNoQixRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDO1lBQ3hDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLGVBQWUsRUFBRSxFQUFFLENBQUM7WUFDbEQsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQztTQUNqRCxDQUFDO1FBQ0YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLGdCQUFnQixFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRCxTQUFTO1FBQ1AsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQztJQUNqRCxDQUFDO0lBRWUsV0FBVyxDQUFDLEtBQUs7UUFDL0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFDdkIsQ0FBQztJQUVPLGVBQWU7UUFDckIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLGVBQWUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ2xHLENBQUM7SUFFTyxpQkFBaUIsQ0FBQyxLQUFLLEVBQUUsUUFBUTtRQUN2QyxJQUFJLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFFeEIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1lBQ3JCLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1lBQ3pCLFFBQVEsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ3hELENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVPLHFCQUFxQixDQUFDLElBQUksRUFBRSxRQUFRO1FBQzFDLElBQUksUUFBUSxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsR0FBRyxRQUFRLENBQUM7UUFFL0MsSUFBSSxJQUFJLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLDBDQUEwQztZQUNoRixRQUFRLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDcEUsQ0FBQztRQUNELElBQUksQ0FBQyxNQUFNLEdBQUcsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUNsQyxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBR0QsS0FBSztRQUNILElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFTyxXQUFXLENBQUMsUUFBUTtRQUMxQixNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRTtZQUNsQixRQUFRO1lBQ1IsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxVQUFVO1lBQ3RCLE9BQU8sRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1lBQ25ELGNBQWMsRUFBRSxRQUFRLENBQUMscUJBQXFCLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUM3RixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sY0FBYyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsY0FBYyxHQUFHLElBQUk7UUFDdkQsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDO1lBQ3JELE1BQU0scUJBQXFCLEdBQUcsZUFBZSxDQUFDLHFCQUFxQixFQUFFLENBQUMsTUFBTSxDQUFDO1lBQzdFLE1BQU0sa0JBQWtCLEdBQUcsZUFBZSxDQUFDLHFCQUFxQixFQUFFLENBQUMsR0FBRyxDQUFDO1lBQ3ZFLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMscUJBQXFCLEVBQUUsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLFFBQVEsR0FBRyxrQkFBa0IsQ0FBQztZQUUvRixJQUFJLEtBQUssSUFBSSx1QkFBdUI7Z0JBQ2xDLE9BQU8sR0FBRyxlQUFlLENBQUMsU0FBUyxJQUFJLGlDQUFpQztnQkFDeEUsT0FBTyxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsR0FBRyxlQUFlLENBQUMsU0FBUyxHQUFHLHFCQUFxQixFQUFFLENBQUMsQ0FBQywwQkFBMEI7Z0JBQ2hILGVBQWUsQ0FBQyxTQUFTLEdBQUcsY0FBYyxDQUFDLENBQUM7b0JBQzFDLE9BQU8sR0FBRyxxQkFBcUIsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLG1CQUFtQjtvQkFDekQsT0FBTyxDQUFDLENBQUMsa0JBQWtCO1lBQy9CLENBQUM7UUFDSCxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksS0FBSyxJQUFJLHVCQUF1QjtnQkFDbEMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsQ0FBQyxJQUFJLHlCQUF5QjtnQkFDbkQsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQyx5QkFBeUI7Z0JBQ2hHLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO29CQUNsQixJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsR0FBRyxjQUFjLENBQUMsQ0FBQzt3QkFDMUMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsY0FBYyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsbUJBQW1CO3dCQUM3RCxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsa0JBQWtCO29CQUVqQyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQztnQkFDcEUsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELGdCQUFnQixDQUFDLEtBQUs7UUFDcEIsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUV0QixNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUU1RCxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRTtZQUFFLE9BQU8sWUFBWSxDQUFDO1FBRTNDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU07WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUU1RCxvR0FBb0c7UUFDcEcsdUZBQXVGO1FBQ3ZGLG9HQUFvRztRQUNwRyw4R0FBOEc7UUFDOUcsTUFBTSxlQUFlLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQ2pELElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxJQUFJLGVBQWUsQ0FBQyxRQUFRLEtBQUssQ0FBQztZQUFFLE9BQU8sRUFBRSxDQUFDO1FBRXpFLDREQUE0RDtRQUM1RCxvRkFBb0Y7UUFDcEYsbURBQW1EO1FBQ25ELE1BQU0sVUFBVSxHQUFHLFlBQVksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUNyRCxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFDbkMsQ0FBQyxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2hELENBQUMsQ0FBQyxDQUFDO1FBRUgsMkRBQTJEO1FBQzNELDhFQUE4RTtRQUM5RSxNQUFNLFNBQVMsR0FBRyxZQUFZLENBQUMsWUFBWSxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUU7WUFDcEQsT0FBTyxJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsR0FBRyxJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUM7UUFDakUsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRWYsTUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFDO1FBRXpCLEtBQUssSUFBSSxDQUFDLEdBQUcsVUFBVSxFQUFFLENBQUMsSUFBSSxTQUFTLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUM3QyxhQUFhLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3RDLENBQUM7UUFFRCxPQUFPLGFBQWEsQ0FBQztJQUN2QixDQUFDO0lBRUQsU0FBUztRQUNQLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBRWpFLElBQUksSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDO1lBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNwQyxJQUFJLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSTtZQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxHQUFHLFNBQVMsQ0FBQyxDQUFDO0lBQ3hELENBQUM7a0lBN0pVLGlCQUFpQjtzSUFBakIsaUJBQWlCOztBQUdoQjtJQUFYLFVBQVU7a0RBQWE7QUFDWjtJQUFYLFVBQVU7NENBQU87QUFDTjtJQUFYLFVBQVU7eURBQXVCO0FBR3hCO0lBQVQsUUFBUTswQ0FFUjtBQUVTO0lBQVQsUUFBUTtvREFFUjtBQTRCZTtJQUFmLE1BQU07b0RBRU47QUFFTztJQUFQLE1BQU07d0RBRU47QUEyQk87SUFBUCxNQUFNO29EQU9OO0FBRU87SUFBUCxNQUFNO3VEQTJCTjs0RkEvR1UsaUJBQWlCO2tCQUQ3QixVQUFVOzhFQUlHLE9BQU8sTUFDUCxDQUFDLE1BQ0QsY0FBYyxNQUdaLENBQUMsTUFJRCxXQUFXLE1BOEJULFdBQVcsTUFJbkIsZUFBZSxNQTZCZixXQUFXLE1BU1gsY0FBYztBQTRFeEIsU0FBUyxZQUFZLENBQUMsS0FBSyxFQUFFLFNBQVMsRUFBRSxVQUFVLEdBQUcsQ0FBQztJQUNwRCxJQUFJLEtBQUssR0FBRyxVQUFVLENBQUM7SUFDdkIsSUFBSSxPQUFPLEdBQUcsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFFL0IsT0FBTyxLQUFLLEtBQUssT0FBTyxFQUFFLENBQUM7UUFDekIsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUVqRCxJQUFJLFNBQVMsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQy9CLE9BQU8sR0FBRyxRQUFRLENBQUM7UUFDckIsQ0FBQzthQUNJLENBQUM7WUFDSixJQUFJLEtBQUssS0FBSyxRQUFRO2dCQUFFLEtBQUssR0FBRyxPQUFPLENBQUM7O2dCQUNuQyxLQUFLLEdBQUcsUUFBUSxDQUFDO1FBQ3hCLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBvYnNlcnZhYmxlLCBjb21wdXRlZCwgYWN0aW9uLCBhdXRvcnVuLCByZWFjdGlvbiB9IGZyb20gJ21vYngnO1xyXG5pbXBvcnQgeyBUcmVlTW9kZWwgfSBmcm9tICcuL3RyZWUubW9kZWwnO1xyXG5pbXBvcnQgeyBUUkVFX0VWRU5UUyB9IGZyb20gJy4uL2NvbnN0YW50cy9ldmVudHMnO1xyXG5cclxuY29uc3QgWV9PRkZTRVQgPSA1MDA7IC8vIEV4dHJhIHBpeGVscyBvdXRzaWRlIHRoZSB2aWV3cG9ydCwgaW4gZWFjaCBkaXJlY3Rpb24sIHRvIHJlbmRlciBub2RlcyBpblxyXG5jb25zdCBZX0VQU0lMT04gPSAxNTA7IC8vIE1pbmltdW0gcGl4ZWwgY2hhbmdlIHJlcXVpcmVkIHRvIHJlY2FsY3VsYXRlIHRoZSByZW5kZXJlZCBub2Rlc1xyXG5cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgVHJlZVZpcnR1YWxTY3JvbGwge1xyXG4gIHByaXZhdGUgX2Rpc3Bvc2U6IGFueTtcclxuXHJcbiAgQG9ic2VydmFibGUgeUJsb2NrcyA9IDA7XHJcbiAgQG9ic2VydmFibGUgeCA9IDA7XHJcbiAgQG9ic2VydmFibGUgdmlld3BvcnRIZWlnaHQgPSBudWxsO1xyXG4gIHZpZXdwb3J0ID0gbnVsbDtcclxuXHJcbiAgQGNvbXB1dGVkIGdldCB5KCkge1xyXG4gICAgcmV0dXJuIHRoaXMueUJsb2NrcyAqIFlfRVBTSUxPTjtcclxuICB9XHJcblxyXG4gIEBjb21wdXRlZCBnZXQgdG90YWxIZWlnaHQoKSB7XHJcbiAgICByZXR1cm4gdGhpcy50cmVlTW9kZWwudmlydHVhbFJvb3QgPyB0aGlzLnRyZWVNb2RlbC52aXJ0dWFsUm9vdC5oZWlnaHQgOiAwO1xyXG4gIH1cclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSB0cmVlTW9kZWw6IFRyZWVNb2RlbCkge1xyXG4gICAgdHJlZU1vZGVsLnZpcnR1YWxTY3JvbGwgPSB0aGlzO1xyXG4gICAgdGhpcy5fZGlzcG9zZSA9IFthdXRvcnVuKCgpID0+IHRoaXMuZml4U2Nyb2xsKCkpXTtcclxuICB9XHJcblxyXG4gIGZpcmVFdmVudChldmVudCkge1xyXG4gICAgdGhpcy50cmVlTW9kZWwuZmlyZUV2ZW50KGV2ZW50KTtcclxuICB9XHJcblxyXG4gIGluaXQoKSB7XHJcbiAgICBjb25zdCBmbiA9IHRoaXMucmVjYWxjUG9zaXRpb25zLmJpbmQodGhpcyk7XHJcblxyXG4gICAgZm4oKTtcclxuICAgIHRoaXMuX2Rpc3Bvc2UgPSBbXHJcbiAgICAgIC4uLnRoaXMuX2Rpc3Bvc2UsXHJcbiAgICAgIHJlYWN0aW9uKCgpID0+IHRoaXMudHJlZU1vZGVsLnJvb3RzLCBmbiksXHJcbiAgICAgIHJlYWN0aW9uKCgpID0+IHRoaXMudHJlZU1vZGVsLmV4cGFuZGVkTm9kZUlkcywgZm4pLFxyXG4gICAgICByZWFjdGlvbigoKSA9PiB0aGlzLnRyZWVNb2RlbC5oaWRkZW5Ob2RlSWRzLCBmbilcclxuICAgIF07XHJcbiAgICB0aGlzLnRyZWVNb2RlbC5zdWJzY3JpYmUoVFJFRV9FVkVOVFMubG9hZE5vZGVDaGlsZHJlbiwgZm4pO1xyXG4gIH1cclxuXHJcbiAgaXNFbmFibGVkKCkge1xyXG4gICAgcmV0dXJuIHRoaXMudHJlZU1vZGVsLm9wdGlvbnMudXNlVmlydHVhbFNjcm9sbDtcclxuICB9XHJcblxyXG4gIEBhY3Rpb24gcHJpdmF0ZSBfc2V0WUJsb2Nrcyh2YWx1ZSkge1xyXG4gICAgdGhpcy55QmxvY2tzID0gdmFsdWU7XHJcbiAgfVxyXG5cclxuICBAYWN0aW9uIHJlY2FsY1Bvc2l0aW9ucygpIHtcclxuICAgIHRoaXMudHJlZU1vZGVsLnZpcnR1YWxSb290LmhlaWdodCA9IHRoaXMuX2dldFBvc2l0aW9uQWZ0ZXIodGhpcy50cmVlTW9kZWwuZ2V0VmlzaWJsZVJvb3RzKCksIDApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBfZ2V0UG9zaXRpb25BZnRlcihub2Rlcywgc3RhcnRQb3MpIHtcclxuICAgIGxldCBwb3NpdGlvbiA9IHN0YXJ0UG9zO1xyXG5cclxuICAgIG5vZGVzLmZvckVhY2goKG5vZGUpID0+IHtcclxuICAgICAgbm9kZS5wb3NpdGlvbiA9IHBvc2l0aW9uO1xyXG4gICAgICBwb3NpdGlvbiA9IHRoaXMuX2dldFBvc2l0aW9uQWZ0ZXJOb2RlKG5vZGUsIHBvc2l0aW9uKTtcclxuICAgIH0pO1xyXG4gICAgcmV0dXJuIHBvc2l0aW9uO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBfZ2V0UG9zaXRpb25BZnRlck5vZGUobm9kZSwgc3RhcnRQb3MpIHtcclxuICAgIGxldCBwb3NpdGlvbiA9IG5vZGUuZ2V0U2VsZkhlaWdodCgpICsgc3RhcnRQb3M7XHJcblxyXG4gICAgaWYgKG5vZGUuY2hpbGRyZW4gJiYgbm9kZS5pc0V4cGFuZGVkKSB7IC8vIFRCRDogY29uc2lkZXIgbG9hZGluZyBjb21wb25lbnQgYXMgd2VsbFxyXG4gICAgICBwb3NpdGlvbiA9IHRoaXMuX2dldFBvc2l0aW9uQWZ0ZXIobm9kZS52aXNpYmxlQ2hpbGRyZW4sIHBvc2l0aW9uKTtcclxuICAgIH1cclxuICAgIG5vZGUuaGVpZ2h0ID0gcG9zaXRpb24gLSBzdGFydFBvcztcclxuICAgIHJldHVybiBwb3NpdGlvbjtcclxuICB9XHJcblxyXG5cclxuICBjbGVhcigpIHtcclxuICAgIHRoaXMuX2Rpc3Bvc2UuZm9yRWFjaCgoZCkgPT4gZCgpKTtcclxuICB9XHJcblxyXG4gIEBhY3Rpb24gc2V0Vmlld3BvcnQodmlld3BvcnQpIHtcclxuICAgIE9iamVjdC5hc3NpZ24odGhpcywge1xyXG4gICAgICB2aWV3cG9ydCxcclxuICAgICAgeDogdmlld3BvcnQuc2Nyb2xsTGVmdCxcclxuICAgICAgeUJsb2NrczogTWF0aC5yb3VuZCh2aWV3cG9ydC5zY3JvbGxUb3AgLyBZX0VQU0lMT04pLFxyXG4gICAgICB2aWV3cG9ydEhlaWdodDogdmlld3BvcnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0ID8gdmlld3BvcnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0IDogMFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBAYWN0aW9uIHNjcm9sbEludG9WaWV3KG5vZGUsIGZvcmNlLCBzY3JvbGxUb01pZGRsZSA9IHRydWUpIHtcclxuICAgIGlmIChub2RlLm9wdGlvbnMuc2Nyb2xsQ29udGFpbmVyKSB7XHJcbiAgICAgIGNvbnN0IHNjcm9sbENvbnRhaW5lciA9IG5vZGUub3B0aW9ucy5zY3JvbGxDb250YWluZXI7XHJcbiAgICAgIGNvbnN0IHNjcm9sbENvbnRhaW5lckhlaWdodCA9IHNjcm9sbENvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQ7XHJcbiAgICAgIGNvbnN0IHNjcm9sbENvbnRhaW5lclRvcCA9IHNjcm9sbENvbnRhaW5lci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3A7XHJcbiAgICAgIGNvbnN0IG5vZGVUb3AgPSB0aGlzLnZpZXdwb3J0LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCArIG5vZGUucG9zaXRpb24gLSBzY3JvbGxDb250YWluZXJUb3A7XHJcblxyXG4gICAgICBpZiAoZm9yY2UgfHwgLy8gZm9yY2Ugc2Nyb2xsIHRvIG5vZGVcclxuICAgICAgICBub2RlVG9wIDwgc2Nyb2xsQ29udGFpbmVyLnNjcm9sbFRvcCB8fCAvLyBub2RlIGlzIGFib3ZlIHNjcm9sbCBjb250YWluZXJcclxuICAgICAgICBub2RlVG9wICsgbm9kZS5nZXRTZWxmSGVpZ2h0KCkgPiBzY3JvbGxDb250YWluZXIuc2Nyb2xsVG9wICsgc2Nyb2xsQ29udGFpbmVySGVpZ2h0KSB7IC8vIG5vZGUgaXMgYmVsb3cgY29udGFpbmVyXHJcbiAgICAgICAgc2Nyb2xsQ29udGFpbmVyLnNjcm9sbFRvcCA9IHNjcm9sbFRvTWlkZGxlID9cclxuICAgICAgICAgIG5vZGVUb3AgLSBzY3JvbGxDb250YWluZXJIZWlnaHQgLyAyIDogLy8gc2Nyb2xsIHRvIG1pZGRsZVxyXG4gICAgICAgICAgbm9kZVRvcDsgLy8gc2Nyb2xsIHRvIHN0YXJ0XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGlmIChmb3JjZSB8fCAvLyBmb3JjZSBzY3JvbGwgdG8gbm9kZVxyXG4gICAgICAgIG5vZGUucG9zaXRpb24gPCB0aGlzLnkgfHwgLy8gbm9kZSBpcyBhYm92ZSB2aWV3cG9ydFxyXG4gICAgICAgIG5vZGUucG9zaXRpb24gKyBub2RlLmdldFNlbGZIZWlnaHQoKSA+IHRoaXMueSArIHRoaXMudmlld3BvcnRIZWlnaHQpIHsgLy8gbm9kZSBpcyBiZWxvdyB2aWV3cG9ydFxyXG4gICAgICAgIGlmICh0aGlzLnZpZXdwb3J0KSB7XHJcbiAgICAgICAgICB0aGlzLnZpZXdwb3J0LnNjcm9sbFRvcCA9IHNjcm9sbFRvTWlkZGxlID9cclxuICAgICAgICAgIG5vZGUucG9zaXRpb24gLSB0aGlzLnZpZXdwb3J0SGVpZ2h0IC8gMiA6IC8vIHNjcm9sbCB0byBtaWRkbGVcclxuICAgICAgICAgIG5vZGUucG9zaXRpb247IC8vIHNjcm9sbCB0byBzdGFydFxyXG5cclxuICAgICAgICAgIHRoaXMuX3NldFlCbG9ja3MoTWF0aC5mbG9vcih0aGlzLnZpZXdwb3J0LnNjcm9sbFRvcCAvIFlfRVBTSUxPTikpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0Vmlld3BvcnROb2Rlcyhub2Rlcykge1xyXG4gICAgaWYgKCFub2RlcykgcmV0dXJuIFtdO1xyXG5cclxuICAgIGNvbnN0IHZpc2libGVOb2RlcyA9IG5vZGVzLmZpbHRlcigobm9kZSkgPT4gIW5vZGUuaXNIaWRkZW4pO1xyXG5cclxuICAgIGlmICghdGhpcy5pc0VuYWJsZWQoKSkgcmV0dXJuIHZpc2libGVOb2RlcztcclxuXHJcbiAgICBpZiAoIXRoaXMudmlld3BvcnRIZWlnaHQgfHwgIXZpc2libGVOb2Rlcy5sZW5ndGgpIHJldHVybiBbXTtcclxuXHJcbiAgICAvLyBXaGVuIGxvYWRpbmcgY2hpbGRyZW4gYXN5bmMgdGhpcyBtZXRob2QgaXMgY2FsbGVkIGJlZm9yZSB0aGVpciBoZWlnaHQgYW5kIHBvc2l0aW9uIGlzIGNhbGN1bGF0ZWQuXHJcbiAgICAvLyBJbiB0aGF0IGNhc2UgZmlyc3RJbmRleCA9PT0gMCBhbmQgbGFzdEluZGV4ID09PSB2aXNpYmxlTm9kZXMubGVuZ3RoIC0gMSAoZS5nLiAxMDAwKSxcclxuICAgIC8vIHdoaWNoIG1lYW5zIHRoYXQgaXQgbG9vcHMgdGhyb3VnaCBldmVyeSB2aXNpYmxlTm9kZXMgaXRlbSBhbmQgcHVzaCB0aGVtIGludG8gdmlld3BvcnROb2RlcyBhcnJheS5cclxuICAgIC8vIFdlIGNhbiBwcmV2ZW50IG5vZGVzIGZyb20gYmVpbmcgcHVzaGVkIHRvIHRoZSBhcnJheSBhbmQgd2FpdCBmb3IgdGhlIGFwcHJvcHJpYXRlIGNhbGN1bGF0aW9ucyB0byB0YWtlIHBsYWNlXHJcbiAgICBjb25zdCBsYXN0VmlzaWJsZU5vZGUgPSB2aXNpYmxlTm9kZXMuc2xpY2UoLTEpWzBdXHJcbiAgICBpZiAoIWxhc3RWaXNpYmxlTm9kZS5oZWlnaHQgJiYgbGFzdFZpc2libGVOb2RlLnBvc2l0aW9uID09PSAwKSByZXR1cm4gW107XHJcblxyXG4gICAgLy8gU2VhcmNoIGZvciBmaXJzdCBub2RlIGluIHRoZSB2aWV3cG9ydCB1c2luZyBiaW5hcnkgc2VhcmNoXHJcbiAgICAvLyBMb29rIGZvciBmaXJzdCBub2RlIHRoYXQgc3RhcnRzIGFmdGVyIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHZpZXdwb3J0ICh3aXRoIGJ1ZmZlcilcclxuICAgIC8vIE9yIHRoYXQgZW5kcyBhZnRlciB0aGUgYmVnaW5uaW5nIG9mIHRoZSB2aWV3cG9ydFxyXG4gICAgY29uc3QgZmlyc3RJbmRleCA9IGJpbmFyeVNlYXJjaCh2aXNpYmxlTm9kZXMsIChub2RlKSA9PiB7XHJcbiAgICAgIHJldHVybiAobm9kZS5wb3NpdGlvbiArIFlfT0ZGU0VUID4gdGhpcy55KSB8fFxyXG4gICAgICAgICAgICAgKG5vZGUucG9zaXRpb24gKyBub2RlLmhlaWdodCA+IHRoaXMueSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZWFyY2ggZm9yIGxhc3Qgbm9kZSBpbiB0aGUgdmlld3BvcnQgdXNpbmcgYmluYXJ5IHNlYXJjaFxyXG4gICAgLy8gTG9vayBmb3IgZmlyc3Qgbm9kZSB0aGF0IHN0YXJ0cyBhZnRlciB0aGUgZW5kIG9mIHRoZSB2aWV3cG9ydCAod2l0aCBidWZmZXIpXHJcbiAgICBjb25zdCBsYXN0SW5kZXggPSBiaW5hcnlTZWFyY2godmlzaWJsZU5vZGVzLCAobm9kZSkgPT4ge1xyXG4gICAgICByZXR1cm4gbm9kZS5wb3NpdGlvbiAtIFlfT0ZGU0VUID4gdGhpcy55ICsgdGhpcy52aWV3cG9ydEhlaWdodDtcclxuICAgIH0sIGZpcnN0SW5kZXgpO1xyXG5cclxuICAgIGNvbnN0IHZpZXdwb3J0Tm9kZXMgPSBbXTtcclxuXHJcbiAgICBmb3IgKGxldCBpID0gZmlyc3RJbmRleDsgaSA8PSBsYXN0SW5kZXg7IGkrKykge1xyXG4gICAgICB2aWV3cG9ydE5vZGVzLnB1c2godmlzaWJsZU5vZGVzW2ldKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdmlld3BvcnROb2RlcztcclxuICB9XHJcblxyXG4gIGZpeFNjcm9sbCgpIHtcclxuICAgIGNvbnN0IG1heFkgPSBNYXRoLm1heCgwLCB0aGlzLnRvdGFsSGVpZ2h0IC0gdGhpcy52aWV3cG9ydEhlaWdodCk7XHJcblxyXG4gICAgaWYgKHRoaXMueSA8IDApIHRoaXMuX3NldFlCbG9ja3MoMCk7XHJcbiAgICBpZiAodGhpcy55ID4gbWF4WSkgdGhpcy5fc2V0WUJsb2NrcyhtYXhZIC8gWV9FUFNJTE9OKTtcclxuICB9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGJpbmFyeVNlYXJjaChub2RlcywgY29uZGl0aW9uLCBmaXJzdEluZGV4ID0gMCkge1xyXG4gIGxldCBpbmRleCA9IGZpcnN0SW5kZXg7XHJcbiAgbGV0IHRvSW5kZXggPSBub2Rlcy5sZW5ndGggLSAxO1xyXG5cclxuICB3aGlsZSAoaW5kZXggIT09IHRvSW5kZXgpIHtcclxuICAgIGxldCBtaWRJbmRleCA9IE1hdGguZmxvb3IoKGluZGV4ICsgdG9JbmRleCkgLyAyKTtcclxuXHJcbiAgICBpZiAoY29uZGl0aW9uKG5vZGVzW21pZEluZGV4XSkpIHtcclxuICAgICAgdG9JbmRleCA9IG1pZEluZGV4O1xyXG4gICAgfVxyXG4gICAgZWxzZSB7XHJcbiAgICAgIGlmIChpbmRleCA9PT0gbWlkSW5kZXgpIGluZGV4ID0gdG9JbmRleDtcclxuICAgICAgZWxzZSBpbmRleCA9IG1pZEluZGV4O1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5kZXg7XHJcbn1cclxuIl19