raain-app 1.6.22 → 1.6.25

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.
package/CHANGELOG.md CHANGED
@@ -7,9 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [1.6.21] - 2025-12-15
10
+ ## [1.6.24] - 2026-01-19
11
11
 
12
- ## [1.6.20] - 2025-12-14
12
+ ## [1.6.23] - 2026-01-19
13
+
14
+ ### Added
15
+
16
+ - New `CumulativeSelectorComponent` for selecting and creating cumulative periods
17
+ - Lists available cumulative periods with window duration display
18
+ - Validates base cumulative coverage before allowing new period creation
19
+ - Polls for computation completion with progress feedback
20
+ - ProfileService: `getCumulativePeriods()` to list available cumulative periods
21
+ - ProfileService: `createCumulativePeriod()` to trigger cumulative computation
22
+
23
+ ### Changed
24
+
25
+ - Cumulative toggle now shows selector popup when enabling (instead of direct toggle)
26
+ - RaainDetails: cumulative period selection flow with `onCumulativePeriodSelected()`
27
+
28
+ ## [1.6.22] - 2025-12-16
13
29
 
14
30
  ### Added
15
31
 
@@ -0,0 +1,55 @@
1
+ import { ChangeDetectorRef, EventEmitter, OnInit } from '@angular/core';
2
+ import { ProfileService } from '../profile.service';
3
+ import { CumulativePeriod, IndividualCumulative } from 'raain-model';
4
+ import * as i0 from "@angular/core";
5
+ export interface CumulativeSelection {
6
+ periodBegin: Date;
7
+ periodEnd: Date;
8
+ windowInMinutes: number;
9
+ cumulativeId?: string;
10
+ cumulativeDate?: Date;
11
+ }
12
+ export declare class CumulativeSelectorComponent implements OnInit {
13
+ private profileService;
14
+ private cdr;
15
+ rainId: string;
16
+ currentPeriodBegin: Date;
17
+ currentPeriodEnd: Date;
18
+ provider: string;
19
+ timeStepInMinutes: number;
20
+ isAdmin: boolean;
21
+ periodSelected: EventEmitter<CumulativeSelection>;
22
+ cancelled: EventEmitter<void>;
23
+ availablePeriods: CumulativePeriod[];
24
+ baseCumulatives: CumulativePeriod;
25
+ loading: boolean;
26
+ creating: boolean;
27
+ creationProgress: string;
28
+ errorMessage: string;
29
+ coveragePercent: number;
30
+ canCreateNew: boolean;
31
+ currentWindowMinutes: number;
32
+ expandedPeriods: Map<string, IndividualCumulative[]>;
33
+ loadingExpanded: Set<string>;
34
+ private readonly POLL_TIMEOUT_MS;
35
+ private readonly POLL_INTERVAL_MS;
36
+ constructor(profileService: ProfileService, cdr: ChangeDetectorRef);
37
+ ngOnInit(): Promise<void>;
38
+ loadAvailablePeriods(): Promise<void>;
39
+ calculateCoverage(): void;
40
+ selectPeriod(period: CumulativePeriod): void;
41
+ toggleExpand(period: CumulativePeriod): Promise<void>;
42
+ selectIndividualCumulative(item: IndividualCumulative): void;
43
+ isExpanded(period: CumulativePeriod): boolean;
44
+ isLoadingExpanded(period: CumulativePeriod): boolean;
45
+ getExpandedItems(period: CumulativePeriod): IndividualCumulative[];
46
+ getItemPeriodBegin(item: IndividualCumulative): Date;
47
+ createNewPeriod(): Promise<void>;
48
+ private pollForCompletion;
49
+ private sleep;
50
+ cancel(): void;
51
+ formatPeriod(period: CumulativePeriod): string;
52
+ formatWindow(minutes: number): string;
53
+ static ɵfac: i0.ɵɵFactoryDeclaration<CumulativeSelectorComponent, never>;
54
+ static ɵcmp: i0.ɵɵComponentDeclaration<CumulativeSelectorComponent, "cumulative-selector", never, { "rainId": "rainId"; "currentPeriodBegin": "currentPeriodBegin"; "currentPeriodEnd": "currentPeriodEnd"; "provider": "provider"; "timeStepInMinutes": "timeStepInMinutes"; "isAdmin": "isAdmin"; }, { "periodSelected": "periodSelected"; "cancelled": "cancelled"; }, never, never, false, never>;
55
+ }
@@ -0,0 +1,250 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ import * as i1 from "../profile.service";
4
+ import * as i2 from "@angular/common";
5
+ import * as i3 from "@ionic/angular";
6
+ export class CumulativeSelectorComponent {
7
+ constructor(profileService, cdr) {
8
+ this.profileService = profileService;
9
+ this.cdr = cdr;
10
+ this.timeStepInMinutes = 5;
11
+ this.isAdmin = false;
12
+ this.periodSelected = new EventEmitter();
13
+ this.cancelled = new EventEmitter();
14
+ this.availablePeriods = [];
15
+ this.baseCumulatives = null;
16
+ this.loading = true;
17
+ this.creating = false;
18
+ this.creationProgress = '';
19
+ this.errorMessage = '';
20
+ this.coveragePercent = 0;
21
+ this.canCreateNew = false;
22
+ this.currentWindowMinutes = 0;
23
+ this.expandedPeriods = new Map();
24
+ this.loadingExpanded = new Set();
25
+ this.POLL_TIMEOUT_MS = 900000; // 900 seconds
26
+ this.POLL_INTERVAL_MS = 3000;
27
+ }
28
+ async ngOnInit() {
29
+ this.currentWindowMinutes = Math.round((this.currentPeriodEnd.getTime() - this.currentPeriodBegin.getTime()) / 60000);
30
+ await this.loadAvailablePeriods();
31
+ }
32
+ async loadAvailablePeriods() {
33
+ this.loading = true;
34
+ this.errorMessage = '';
35
+ this.cdr.markForCheck();
36
+ try {
37
+ // Fetch all cumulative periods (admin sees all, non-admin sees only customer-launched)
38
+ const response = await this.profileService.getCumulativePeriods(this.rainId, {
39
+ provider: this.provider,
40
+ forced: this.isAdmin,
41
+ });
42
+ // Filter for existing custom cumulatives (window > 0)
43
+ this.availablePeriods = response.periods.filter((p) => p.windowInMinutes > 0);
44
+ // Get base cumulatives (window = 0) to check coverage
45
+ this.baseCumulatives = response.periods.find((p) => p.windowInMinutes === 0);
46
+ this.calculateCoverage();
47
+ }
48
+ catch (e) {
49
+ this.errorMessage = 'Failed to load cumulative periods';
50
+ console.error('Error loading cumulative periods:', e);
51
+ }
52
+ this.loading = false;
53
+ this.cdr.markForCheck();
54
+ }
55
+ calculateCoverage() {
56
+ if (!this.baseCumulatives) {
57
+ this.coveragePercent = 0;
58
+ this.canCreateNew = false;
59
+ return;
60
+ }
61
+ const baseBegin = new Date(this.baseCumulatives.periodBegin);
62
+ const baseEnd = new Date(this.baseCumulatives.periodEnd);
63
+ // Check if current period is within base coverage
64
+ const currentInRange = this.currentPeriodBegin >= baseBegin && this.currentPeriodEnd <= baseEnd;
65
+ if (!currentInRange) {
66
+ this.coveragePercent = 0;
67
+ this.canCreateNew = false;
68
+ return;
69
+ }
70
+ // Calculate expected number of base cumulatives needed
71
+ const expectedCount = Math.ceil(this.currentWindowMinutes / this.timeStepInMinutes);
72
+ // Check if enough base cumulatives exist
73
+ // We assume coverage is complete if count >= expected (simplified check)
74
+ if (this.baseCumulatives.count >= expectedCount) {
75
+ this.coveragePercent = 100;
76
+ this.canCreateNew = true;
77
+ }
78
+ else {
79
+ this.coveragePercent = Math.round((this.baseCumulatives.count / expectedCount) * 100);
80
+ this.canCreateNew = this.coveragePercent >= 100;
81
+ }
82
+ }
83
+ selectPeriod(period) {
84
+ this.periodSelected.emit({
85
+ periodBegin: new Date(period.periodBegin),
86
+ periodEnd: new Date(period.periodEnd),
87
+ windowInMinutes: period.windowInMinutes,
88
+ });
89
+ }
90
+ async toggleExpand(period) {
91
+ const key = `${period.windowInMinutes}-${period.provider}`;
92
+ if (this.expandedPeriods.has(key)) {
93
+ this.expandedPeriods.delete(key);
94
+ this.cdr.markForCheck();
95
+ return;
96
+ }
97
+ this.loadingExpanded.add(key);
98
+ this.cdr.markForCheck();
99
+ try {
100
+ const response = await this.profileService.getCumulativePeriods(this.rainId, {
101
+ provider: this.provider,
102
+ windowInMinutes: period.windowInMinutes,
103
+ forced: this.isAdmin,
104
+ detailed: true,
105
+ });
106
+ this.expandedPeriods.set(key, response.cumulatives || []);
107
+ }
108
+ catch (e) {
109
+ console.error('Error loading individual cumulatives:', e);
110
+ this.expandedPeriods.set(key, []);
111
+ }
112
+ this.loadingExpanded.delete(key);
113
+ this.cdr.markForCheck();
114
+ }
115
+ selectIndividualCumulative(item) {
116
+ const endDate = new Date(item.date);
117
+ const beginDate = new Date(endDate.getTime() - item.windowInMinutes * 60000);
118
+ this.periodSelected.emit({
119
+ periodBegin: beginDate,
120
+ periodEnd: endDate,
121
+ windowInMinutes: item.windowInMinutes,
122
+ cumulativeId: item.id,
123
+ cumulativeDate: endDate,
124
+ });
125
+ }
126
+ isExpanded(period) {
127
+ return this.expandedPeriods.has(`${period.windowInMinutes}-${period.provider}`);
128
+ }
129
+ isLoadingExpanded(period) {
130
+ return this.loadingExpanded.has(`${period.windowInMinutes}-${period.provider}`);
131
+ }
132
+ getExpandedItems(period) {
133
+ return this.expandedPeriods.get(`${period.windowInMinutes}-${period.provider}`) || [];
134
+ }
135
+ getItemPeriodBegin(item) {
136
+ const endDate = new Date(item.date);
137
+ return new Date(endDate.getTime() - item.windowInMinutes * 60000);
138
+ }
139
+ async createNewPeriod() {
140
+ if (!this.canCreateNew || this.creating) {
141
+ return;
142
+ }
143
+ this.creating = true;
144
+ this.creationProgress = 'Starting cumulative computation...';
145
+ this.errorMessage = '';
146
+ this.cdr.markForCheck();
147
+ try {
148
+ // Trigger cumulative creation
149
+ const result = await this.profileService.createCumulativePeriod(this.rainId, {
150
+ periodBegin: this.currentPeriodBegin,
151
+ periodEnd: this.currentPeriodEnd,
152
+ provider: this.provider,
153
+ timeStepInMinutes: this.timeStepInMinutes,
154
+ });
155
+ if (!result) {
156
+ throw new Error('Failed to trigger cumulative computation');
157
+ }
158
+ this.creationProgress = `Jobs queued. Polling for completion...`;
159
+ this.cdr.markForCheck();
160
+ // Poll for completion
161
+ const success = await this.pollForCompletion();
162
+ if (success) {
163
+ this.periodSelected.emit({
164
+ periodBegin: this.currentPeriodBegin,
165
+ periodEnd: this.currentPeriodEnd,
166
+ windowInMinutes: this.currentWindowMinutes,
167
+ });
168
+ }
169
+ else {
170
+ this.errorMessage = 'Timeout waiting for cumulative computation';
171
+ }
172
+ }
173
+ catch (e) {
174
+ this.errorMessage = `Error: ${e.message || 'Unknown error'}`;
175
+ console.error('Error creating cumulative:', e);
176
+ }
177
+ this.creating = false;
178
+ this.cdr.markForCheck();
179
+ }
180
+ async pollForCompletion() {
181
+ const startTime = Date.now();
182
+ while (Date.now() - startTime < this.POLL_TIMEOUT_MS) {
183
+ try {
184
+ const progress = await this.profileService.getRainProgress(this.rainId);
185
+ if (progress === 0) {
186
+ // Queue is empty, check if cumulative exists (admin sees all cumulatives)
187
+ const response = await this.profileService.getCumulativePeriods(this.rainId, {
188
+ provider: this.provider,
189
+ windowInMinutes: this.currentWindowMinutes,
190
+ forced: this.isAdmin,
191
+ });
192
+ const found = response.periods.find((p) => p.windowInMinutes === this.currentWindowMinutes);
193
+ if (found) {
194
+ return true;
195
+ }
196
+ }
197
+ const elapsed = Math.round((Date.now() - startTime) / 1000);
198
+ this.creationProgress = `Computing... (${elapsed}s, queue: ${progress})`;
199
+ this.cdr.markForCheck();
200
+ await this.sleep(this.POLL_INTERVAL_MS);
201
+ }
202
+ catch (e) {
203
+ console.warn('Poll error:', e);
204
+ await this.sleep(this.POLL_INTERVAL_MS);
205
+ }
206
+ }
207
+ return false;
208
+ }
209
+ sleep(ms) {
210
+ return new Promise((resolve) => setTimeout(resolve, ms));
211
+ }
212
+ cancel() {
213
+ this.cancelled.emit();
214
+ }
215
+ formatPeriod(period) {
216
+ const begin = new Date(period.periodBegin);
217
+ const end = new Date(period.periodEnd);
218
+ return `${begin.toLocaleString()} → ${end.toLocaleString()}`;
219
+ }
220
+ formatWindow(minutes) {
221
+ if (minutes < 60) {
222
+ return `${minutes} min`;
223
+ }
224
+ const hours = minutes / 60;
225
+ return hours === 1 ? '1 hour' : `${hours} hours`;
226
+ }
227
+ }
228
+ CumulativeSelectorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CumulativeSelectorComponent, deps: [{ token: i1.ProfileService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
229
+ CumulativeSelectorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: CumulativeSelectorComponent, selector: "cumulative-selector", inputs: { rainId: "rainId", currentPeriodBegin: "currentPeriodBegin", currentPeriodEnd: "currentPeriodEnd", provider: "provider", timeStepInMinutes: "timeStepInMinutes", isAdmin: "isAdmin" }, outputs: { periodSelected: "periodSelected", cancelled: "cancelled" }, ngImport: i0, template: "<div class=\"cumulative-selector-overlay\">\n <div class=\"cumulative-selector-modal\">\n <div class=\"modal-header\">\n <h2>Select Cumulative Period</h2>\n <ion-button fill=\"clear\" (click)=\"cancel()\">\n <ion-icon name=\"close\"></ion-icon>\n </ion-button>\n </div>\n\n <div class=\"modal-content\">\n <!-- Loading state -->\n <div *ngIf=\"loading\" class=\"loading-state\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n <p>Loading available periods...</p>\n </div>\n\n <!-- Error message -->\n <div *ngIf=\"errorMessage\" class=\"error-message\">\n <ion-icon name=\"warning-outline\"></ion-icon>\n <span>{{ errorMessage }}</span>\n </div>\n\n <!-- Available periods list -->\n <div *ngIf=\"!loading && availablePeriods.length > 0\" class=\"periods-section\">\n <h3>Available Cumulative Periods</h3>\n <ion-list>\n <ng-container *ngFor=\"let period of availablePeriods\">\n <!-- Period header (click to expand) -->\n <ion-item button (click)=\"toggleExpand(period)\" [disabled]=\"creating\">\n <ion-icon [name]=\"isExpanded(period) ? 'chevron-down' : 'chevron-forward'\" slot=\"start\"></ion-icon>\n <ion-label>\n <h2>{{ formatWindow(period.windowInMinutes) }}</h2>\n <p>{{ formatPeriod(period) }}</p>\n <p class=\"count-info\">{{ period.count }} cumulative(s) - click to expand</p>\n </ion-label>\n </ion-item>\n\n <!-- Expanded: individual cumulatives -->\n <div *ngIf=\"isExpanded(period)\" class=\"expanded-items\">\n <ion-spinner *ngIf=\"isLoadingExpanded(period)\" name=\"crescent\"></ion-spinner>\n <ion-list *ngIf=\"!isLoadingExpanded(period)\" class=\"nested-list\">\n <ion-item *ngFor=\"let item of getExpandedItems(period)\"\n button\n (click)=\"selectIndividualCumulative(item)\"\n class=\"nested-item\"\n [disabled]=\"creating\">\n <ion-icon name=\"time-outline\" slot=\"start\"></ion-icon>\n <ion-label>\n <h3>{{ getItemPeriodBegin(item) | date:'HH:mm' }} - {{ item.date | date:'HH:mm' }}</h3>\n </ion-label>\n <ion-icon name=\"chevron-forward\" slot=\"end\"></ion-icon>\n </ion-item>\n <ion-item *ngIf=\"getExpandedItems(period).length === 0\" class=\"nested-item\">\n <ion-label>\n <p>No individual cumulatives found</p>\n </ion-label>\n </ion-item>\n </ion-list>\n </div>\n </ng-container>\n </ion-list>\n </div>\n\n <!-- No periods available -->\n <div *ngIf=\"!loading && availablePeriods.length === 0\" class=\"no-periods\">\n <ion-icon name=\"information-circle-outline\"></ion-icon>\n <p>No cumulative periods available yet.</p>\n </div>\n\n <!-- Create new section (admin only) -->\n <div *ngIf=\"!loading && isAdmin\" class=\"create-section\">\n <h3>Create New Cumulative</h3>\n <div class=\"create-info\">\n <p>\n <strong>Period:</strong>\n {{ currentPeriodBegin?.toLocaleString() }} \u2192 {{ currentPeriodEnd?.toLocaleString() }}\n </p>\n <p>\n <strong>Window:</strong> {{ formatWindow(currentWindowMinutes) }}\n </p>\n <p *ngIf=\"baseCumulatives\" class=\"coverage-info\"\n [class.coverage-ok]=\"coveragePercent >= 100\"\n [class.coverage-warn]=\"coveragePercent > 0 && coveragePercent < 100\"\n [class.coverage-error]=\"coveragePercent === 0\">\n <ion-icon [name]=\"coveragePercent >= 100 ? 'checkmark-circle' : 'alert-circle'\"></ion-icon>\n Base data coverage: {{ coveragePercent }}%\n </p>\n <p *ngIf=\"!baseCumulatives\" class=\"coverage-error\">\n <ion-icon name=\"alert-circle\"></ion-icon>\n No base cumulatives available\n </p>\n </div>\n\n <!-- Creation progress -->\n <div *ngIf=\"creating\" class=\"creation-progress\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n <span>{{ creationProgress }}</span>\n </div>\n\n <ion-button [disabled]=\"!canCreateNew || creating\"\n expand=\"block\"\n (click)=\"createNewPeriod()\">\n <ion-icon name=\"add-circle-outline\" slot=\"start\"></ion-icon>\n Create {{ formatWindow(currentWindowMinutes) }} Cumulative\n </ion-button>\n\n <p *ngIf=\"!canCreateNew && !creating\" class=\"create-hint\">\n Create is disabled because base 5-min cumulatives don't fully cover the selected period.\n </p>\n </div>\n </div>\n\n <div class=\"modal-footer\">\n <ion-button fill=\"outline\" (click)=\"cancel()\" [disabled]=\"creating\">\n Cancel\n </ion-button>\n </div>\n </div>\n</div>\n", styles: [".cumulative-selector-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;z-index:1000}.cumulative-selector-modal{background:var(--ion-background-color, #fff);border-radius:12px;max-width:500px;width:90%;max-height:80vh;display:flex;flex-direction:column;box-shadow:0 4px 20px #0000004d}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--ion-border-color, #ddd)}.modal-header h2{margin:0;font-size:1.25rem;font-weight:600}.modal-header ion-button{--padding-start: 8px;--padding-end: 8px}.modal-content{flex:1;overflow-y:auto;padding:16px 20px}.loading-state{display:flex;flex-direction:column;align-items:center;padding:40px 0}.loading-state ion-spinner{margin-bottom:16px}.loading-state p{color:var(--ion-color-medium)}.error-message{display:flex;align-items:center;gap:8px;padding:12px;background:var(--ion-color-danger-tint);color:var(--ion-color-danger);border-radius:8px;margin-bottom:16px}.error-message ion-icon{font-size:1.25rem}.periods-section{margin-bottom:24px}.periods-section h3{font-size:1rem;font-weight:600;margin-bottom:12px;color:var(--ion-color-dark)}.periods-section ion-list{border-radius:8px;overflow:hidden}.periods-section ion-item{--padding-start: 12px;--padding-end: 12px}.periods-section ion-item ion-label h2{font-weight:500}.periods-section ion-item ion-label p{font-size:.85rem;color:var(--ion-color-medium)}.periods-section ion-item ion-label .count-info{font-size:.75rem;color:var(--ion-color-primary)}.periods-section .expanded-items{background:var(--ion-color-light);padding:8px 0 8px 24px;border-left:3px solid var(--ion-color-primary);margin-left:16px}.periods-section .expanded-items ion-spinner{display:block;margin:16px auto}.periods-section .expanded-items .nested-list{background:transparent;padding:0}.periods-section .expanded-items .nested-list .nested-item{--background: transparent;--padding-start: 8px;--padding-top: 4px;--padding-bottom: 4px;--min-height: 32px}.periods-section .expanded-items .nested-list .nested-item ion-label{margin:0}.periods-section .expanded-items .nested-list .nested-item ion-label h3{font-size:.85rem;font-weight:500;margin:0}.periods-section .expanded-items .nested-list .nested-item ion-icon[slot=start]{color:var(--ion-color-primary);font-size:.9rem;margin-right:8px}.periods-section .expanded-items .nested-list .nested-item ion-icon[slot=end]{font-size:.8rem}.no-periods{display:flex;flex-direction:column;align-items:center;padding:24px;text-align:center;color:var(--ion-color-medium)}.no-periods ion-icon{font-size:2rem;margin-bottom:8px}.create-section{border-top:1px solid var(--ion-border-color, #ddd);padding-top:16px}.create-section h3{font-size:1rem;font-weight:600;margin-bottom:12px;color:var(--ion-color-dark)}.create-section .create-info{background:var(--ion-color-light);padding:12px;border-radius:8px;margin-bottom:16px}.create-section .create-info p{margin:4px 0;font-size:.9rem}.create-section .coverage-info{display:flex;align-items:center;gap:6px}.create-section .coverage-info ion-icon{font-size:1.1rem}.create-section .coverage-ok{color:var(--ion-color-success)}.create-section .coverage-warn{color:var(--ion-color-warning)}.create-section .coverage-error{color:var(--ion-color-danger)}.create-section .creation-progress{display:flex;align-items:center;gap:12px;padding:16px;background:var(--ion-color-primary-tint);border-radius:8px;margin-bottom:16px}.create-section .creation-progress ion-spinner{--color: var(--ion-color-primary)}.create-section .creation-progress span{color:var(--ion-color-primary);font-size:.9rem}.create-section .create-hint{font-size:.8rem;color:var(--ion-color-medium);text-align:center;margin-top:8px}.modal-footer{padding:16px 20px;border-top:1px solid var(--ion-border-color, #ddd);display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i3.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i3.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i3.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i3.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i3.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "pipe", type: i2.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
230
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CumulativeSelectorComponent, decorators: [{
231
+ type: Component,
232
+ args: [{ selector: 'cumulative-selector', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cumulative-selector-overlay\">\n <div class=\"cumulative-selector-modal\">\n <div class=\"modal-header\">\n <h2>Select Cumulative Period</h2>\n <ion-button fill=\"clear\" (click)=\"cancel()\">\n <ion-icon name=\"close\"></ion-icon>\n </ion-button>\n </div>\n\n <div class=\"modal-content\">\n <!-- Loading state -->\n <div *ngIf=\"loading\" class=\"loading-state\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n <p>Loading available periods...</p>\n </div>\n\n <!-- Error message -->\n <div *ngIf=\"errorMessage\" class=\"error-message\">\n <ion-icon name=\"warning-outline\"></ion-icon>\n <span>{{ errorMessage }}</span>\n </div>\n\n <!-- Available periods list -->\n <div *ngIf=\"!loading && availablePeriods.length > 0\" class=\"periods-section\">\n <h3>Available Cumulative Periods</h3>\n <ion-list>\n <ng-container *ngFor=\"let period of availablePeriods\">\n <!-- Period header (click to expand) -->\n <ion-item button (click)=\"toggleExpand(period)\" [disabled]=\"creating\">\n <ion-icon [name]=\"isExpanded(period) ? 'chevron-down' : 'chevron-forward'\" slot=\"start\"></ion-icon>\n <ion-label>\n <h2>{{ formatWindow(period.windowInMinutes) }}</h2>\n <p>{{ formatPeriod(period) }}</p>\n <p class=\"count-info\">{{ period.count }} cumulative(s) - click to expand</p>\n </ion-label>\n </ion-item>\n\n <!-- Expanded: individual cumulatives -->\n <div *ngIf=\"isExpanded(period)\" class=\"expanded-items\">\n <ion-spinner *ngIf=\"isLoadingExpanded(period)\" name=\"crescent\"></ion-spinner>\n <ion-list *ngIf=\"!isLoadingExpanded(period)\" class=\"nested-list\">\n <ion-item *ngFor=\"let item of getExpandedItems(period)\"\n button\n (click)=\"selectIndividualCumulative(item)\"\n class=\"nested-item\"\n [disabled]=\"creating\">\n <ion-icon name=\"time-outline\" slot=\"start\"></ion-icon>\n <ion-label>\n <h3>{{ getItemPeriodBegin(item) | date:'HH:mm' }} - {{ item.date | date:'HH:mm' }}</h3>\n </ion-label>\n <ion-icon name=\"chevron-forward\" slot=\"end\"></ion-icon>\n </ion-item>\n <ion-item *ngIf=\"getExpandedItems(period).length === 0\" class=\"nested-item\">\n <ion-label>\n <p>No individual cumulatives found</p>\n </ion-label>\n </ion-item>\n </ion-list>\n </div>\n </ng-container>\n </ion-list>\n </div>\n\n <!-- No periods available -->\n <div *ngIf=\"!loading && availablePeriods.length === 0\" class=\"no-periods\">\n <ion-icon name=\"information-circle-outline\"></ion-icon>\n <p>No cumulative periods available yet.</p>\n </div>\n\n <!-- Create new section (admin only) -->\n <div *ngIf=\"!loading && isAdmin\" class=\"create-section\">\n <h3>Create New Cumulative</h3>\n <div class=\"create-info\">\n <p>\n <strong>Period:</strong>\n {{ currentPeriodBegin?.toLocaleString() }} \u2192 {{ currentPeriodEnd?.toLocaleString() }}\n </p>\n <p>\n <strong>Window:</strong> {{ formatWindow(currentWindowMinutes) }}\n </p>\n <p *ngIf=\"baseCumulatives\" class=\"coverage-info\"\n [class.coverage-ok]=\"coveragePercent >= 100\"\n [class.coverage-warn]=\"coveragePercent > 0 && coveragePercent < 100\"\n [class.coverage-error]=\"coveragePercent === 0\">\n <ion-icon [name]=\"coveragePercent >= 100 ? 'checkmark-circle' : 'alert-circle'\"></ion-icon>\n Base data coverage: {{ coveragePercent }}%\n </p>\n <p *ngIf=\"!baseCumulatives\" class=\"coverage-error\">\n <ion-icon name=\"alert-circle\"></ion-icon>\n No base cumulatives available\n </p>\n </div>\n\n <!-- Creation progress -->\n <div *ngIf=\"creating\" class=\"creation-progress\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n <span>{{ creationProgress }}</span>\n </div>\n\n <ion-button [disabled]=\"!canCreateNew || creating\"\n expand=\"block\"\n (click)=\"createNewPeriod()\">\n <ion-icon name=\"add-circle-outline\" slot=\"start\"></ion-icon>\n Create {{ formatWindow(currentWindowMinutes) }} Cumulative\n </ion-button>\n\n <p *ngIf=\"!canCreateNew && !creating\" class=\"create-hint\">\n Create is disabled because base 5-min cumulatives don't fully cover the selected period.\n </p>\n </div>\n </div>\n\n <div class=\"modal-footer\">\n <ion-button fill=\"outline\" (click)=\"cancel()\" [disabled]=\"creating\">\n Cancel\n </ion-button>\n </div>\n </div>\n</div>\n", styles: [".cumulative-selector-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;z-index:1000}.cumulative-selector-modal{background:var(--ion-background-color, #fff);border-radius:12px;max-width:500px;width:90%;max-height:80vh;display:flex;flex-direction:column;box-shadow:0 4px 20px #0000004d}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--ion-border-color, #ddd)}.modal-header h2{margin:0;font-size:1.25rem;font-weight:600}.modal-header ion-button{--padding-start: 8px;--padding-end: 8px}.modal-content{flex:1;overflow-y:auto;padding:16px 20px}.loading-state{display:flex;flex-direction:column;align-items:center;padding:40px 0}.loading-state ion-spinner{margin-bottom:16px}.loading-state p{color:var(--ion-color-medium)}.error-message{display:flex;align-items:center;gap:8px;padding:12px;background:var(--ion-color-danger-tint);color:var(--ion-color-danger);border-radius:8px;margin-bottom:16px}.error-message ion-icon{font-size:1.25rem}.periods-section{margin-bottom:24px}.periods-section h3{font-size:1rem;font-weight:600;margin-bottom:12px;color:var(--ion-color-dark)}.periods-section ion-list{border-radius:8px;overflow:hidden}.periods-section ion-item{--padding-start: 12px;--padding-end: 12px}.periods-section ion-item ion-label h2{font-weight:500}.periods-section ion-item ion-label p{font-size:.85rem;color:var(--ion-color-medium)}.periods-section ion-item ion-label .count-info{font-size:.75rem;color:var(--ion-color-primary)}.periods-section .expanded-items{background:var(--ion-color-light);padding:8px 0 8px 24px;border-left:3px solid var(--ion-color-primary);margin-left:16px}.periods-section .expanded-items ion-spinner{display:block;margin:16px auto}.periods-section .expanded-items .nested-list{background:transparent;padding:0}.periods-section .expanded-items .nested-list .nested-item{--background: transparent;--padding-start: 8px;--padding-top: 4px;--padding-bottom: 4px;--min-height: 32px}.periods-section .expanded-items .nested-list .nested-item ion-label{margin:0}.periods-section .expanded-items .nested-list .nested-item ion-label h3{font-size:.85rem;font-weight:500;margin:0}.periods-section .expanded-items .nested-list .nested-item ion-icon[slot=start]{color:var(--ion-color-primary);font-size:.9rem;margin-right:8px}.periods-section .expanded-items .nested-list .nested-item ion-icon[slot=end]{font-size:.8rem}.no-periods{display:flex;flex-direction:column;align-items:center;padding:24px;text-align:center;color:var(--ion-color-medium)}.no-periods ion-icon{font-size:2rem;margin-bottom:8px}.create-section{border-top:1px solid var(--ion-border-color, #ddd);padding-top:16px}.create-section h3{font-size:1rem;font-weight:600;margin-bottom:12px;color:var(--ion-color-dark)}.create-section .create-info{background:var(--ion-color-light);padding:12px;border-radius:8px;margin-bottom:16px}.create-section .create-info p{margin:4px 0;font-size:.9rem}.create-section .coverage-info{display:flex;align-items:center;gap:6px}.create-section .coverage-info ion-icon{font-size:1.1rem}.create-section .coverage-ok{color:var(--ion-color-success)}.create-section .coverage-warn{color:var(--ion-color-warning)}.create-section .coverage-error{color:var(--ion-color-danger)}.create-section .creation-progress{display:flex;align-items:center;gap:12px;padding:16px;background:var(--ion-color-primary-tint);border-radius:8px;margin-bottom:16px}.create-section .creation-progress ion-spinner{--color: var(--ion-color-primary)}.create-section .creation-progress span{color:var(--ion-color-primary);font-size:.9rem}.create-section .create-hint{font-size:.8rem;color:var(--ion-color-medium);text-align:center;margin-top:8px}.modal-footer{padding:16px 20px;border-top:1px solid var(--ion-border-color, #ddd);display:flex;justify-content:flex-end}\n"] }]
233
+ }], ctorParameters: function () { return [{ type: i1.ProfileService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { rainId: [{
234
+ type: Input
235
+ }], currentPeriodBegin: [{
236
+ type: Input
237
+ }], currentPeriodEnd: [{
238
+ type: Input
239
+ }], provider: [{
240
+ type: Input
241
+ }], timeStepInMinutes: [{
242
+ type: Input
243
+ }], isAdmin: [{
244
+ type: Input
245
+ }], periodSelected: [{
246
+ type: Output
247
+ }], cancelled: [{
248
+ type: Output
249
+ }] } });
250
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VtdWxhdGl2ZS1zZWxlY3Rvci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29yZS9zaGFyZWQvY3VtdWxhdGl2ZS1zZWxlY3Rvci9jdW11bGF0aXZlLXNlbGVjdG9yLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uL3NyYy9jb3JlL3NoYXJlZC9jdW11bGF0aXZlLXNlbGVjdG9yL2N1bXVsYXRpdmUtc2VsZWN0b3IuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNILHVCQUF1QixFQUV2QixTQUFTLEVBQ1QsWUFBWSxFQUNaLEtBQUssRUFFTCxNQUFNLEdBQ1QsTUFBTSxlQUFlLENBQUM7Ozs7O0FBa0J2QixNQUFNLE9BQU8sMkJBQTJCO0lBNEJwQyxZQUNZLGNBQThCLEVBQzlCLEdBQXNCO1FBRHRCLG1CQUFjLEdBQWQsY0FBYyxDQUFnQjtRQUM5QixRQUFHLEdBQUgsR0FBRyxDQUFtQjtRQXpCekIsc0JBQWlCLEdBQVcsQ0FBQyxDQUFDO1FBQzlCLFlBQU8sR0FBWSxLQUFLLENBQUM7UUFFeEIsbUJBQWMsR0FBRyxJQUFJLFlBQVksRUFBdUIsQ0FBQztRQUN6RCxjQUFTLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUUvQyxxQkFBZ0IsR0FBdUIsRUFBRSxDQUFDO1FBQzFDLG9CQUFlLEdBQXFCLElBQUksQ0FBQztRQUN6QyxZQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ2YsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUNqQixxQkFBZ0IsR0FBRyxFQUFFLENBQUM7UUFDdEIsaUJBQVksR0FBRyxFQUFFLENBQUM7UUFFbEIsb0JBQWUsR0FBRyxDQUFDLENBQUM7UUFDcEIsaUJBQVksR0FBRyxLQUFLLENBQUM7UUFDckIseUJBQW9CLEdBQUcsQ0FBQyxDQUFDO1FBRXpCLG9CQUFlLEdBQXdDLElBQUksR0FBRyxFQUFFLENBQUM7UUFDakUsb0JBQWUsR0FBZ0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUV4QixvQkFBZSxHQUFHLE1BQU0sQ0FBQyxDQUFDLGNBQWM7UUFDeEMscUJBQWdCLEdBQUcsSUFBSSxDQUFDO0lBS3RDLENBQUM7SUFFSixLQUFLLENBQUMsUUFBUTtRQUNWLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUNsQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQ2hGLENBQUM7UUFDRixNQUFNLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO0lBQ3RDLENBQUM7SUFFRCxLQUFLLENBQUMsb0JBQW9CO1FBQ3RCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ3BCLElBQUksQ0FBQyxZQUFZLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7UUFFeEIsSUFBSTtZQUNBLHVGQUF1RjtZQUN2RixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtnQkFDekUsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO2dCQUN2QixNQUFNLEVBQUUsSUFBSSxDQUFDLE9BQU87YUFDdkIsQ0FBeUMsQ0FBQztZQUUzQyxzREFBc0Q7WUFDdEQsSUFBSSxDQUFDLGdCQUFnQixHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsZUFBZSxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBRTlFLHNEQUFzRDtZQUN0RCxJQUFJLENBQUMsZUFBZSxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsZUFBZSxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBRTdFLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1NBQzVCO1FBQUMsT0FBTyxDQUFDLEVBQUU7WUFDUixJQUFJLENBQUMsWUFBWSxHQUFHLG1DQUFtQyxDQUFDO1lBQ3hELE9BQU8sQ0FBQyxLQUFLLENBQUMsbUNBQW1DLEVBQUUsQ0FBQyxDQUFDLENBQUM7U0FDekQ7UUFFRCxJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztRQUNyQixJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQzVCLENBQUM7SUFFRCxpQkFBaUI7UUFDYixJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRTtZQUN2QixJQUFJLENBQUMsZUFBZSxHQUFHLENBQUMsQ0FBQztZQUN6QixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQztZQUMxQixPQUFPO1NBQ1Y7UUFFRCxNQUFNLFNBQVMsR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzdELE1BQU0sT0FBTyxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFekQsa0RBQWtEO1FBQ2xELE1BQU0sY0FBYyxHQUNoQixJQUFJLENBQUMsa0JBQWtCLElBQUksU0FBUyxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsSUFBSSxPQUFPLENBQUM7UUFFN0UsSUFBSSxDQUFDLGNBQWMsRUFBRTtZQUNqQixJQUFJLENBQUMsZUFBZSxHQUFHLENBQUMsQ0FBQztZQUN6QixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQztZQUMxQixPQUFPO1NBQ1Y7UUFFRCx1REFBdUQ7UUFDdkQsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFFcEYseUNBQXlDO1FBQ3pDLHlFQUF5RTtRQUN6RSxJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxJQUFJLGFBQWEsRUFBRTtZQUM3QyxJQUFJLENBQUMsZUFBZSxHQUFHLEdBQUcsQ0FBQztZQUMzQixJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQztTQUM1QjthQUFNO1lBQ0gsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEdBQUcsYUFBYSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7WUFDdEYsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsZUFBZSxJQUFJLEdBQUcsQ0FBQztTQUNuRDtJQUNMLENBQUM7SUFFRCxZQUFZLENBQUMsTUFBd0I7UUFDakMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUM7WUFDckIsV0FBVyxFQUFFLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUM7WUFDekMsU0FBUyxFQUFFLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUM7WUFDckMsZUFBZSxFQUFFLE1BQU0sQ0FBQyxlQUFlO1NBQzFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRCxLQUFLLENBQUMsWUFBWSxDQUFDLE1BQXdCO1FBQ3ZDLE1BQU0sR0FBRyxHQUFHLEdBQUcsTUFBTSxDQUFDLGVBQWUsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDM0QsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUMvQixJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNqQyxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3hCLE9BQU87U0FDVjtRQUVELElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzlCLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7UUFFeEIsSUFBSTtZQUNBLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFO2dCQUN6RSxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7Z0JBQ3ZCLGVBQWUsRUFBRSxNQUFNLENBQUMsZUFBZTtnQkFDdkMsTUFBTSxFQUFFLElBQUksQ0FBQyxPQUFPO2dCQUNwQixRQUFRLEVBQUUsSUFBSTthQUNqQixDQUE2QyxDQUFDO1lBRS9DLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsV0FBVyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1NBQzdEO1FBQUMsT0FBTyxDQUFDLEVBQUU7WUFDUixPQUFPLENBQUMsS0FBSyxDQUFDLHVDQUF1QyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQzFELElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztTQUNyQztRQUVELElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2pDLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDNUIsQ0FBQztJQUVELDBCQUEwQixDQUFDLElBQTBCO1FBQ2pELE1BQU0sT0FBTyxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwQyxNQUFNLFNBQVMsR0FBRyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLGVBQWUsR0FBRyxLQUFLLENBQUMsQ0FBQztRQUU3RSxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQztZQUNyQixXQUFXLEVBQUUsU0FBUztZQUN0QixTQUFTLEVBQUUsT0FBTztZQUNsQixlQUFlLEVBQUUsSUFBSSxDQUFDLGVBQWU7WUFDckMsWUFBWSxFQUFFLElBQUksQ0FBQyxFQUFFO1lBQ3JCLGNBQWMsRUFBRSxPQUFPO1NBQzFCLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRCxVQUFVLENBQUMsTUFBd0I7UUFDL0IsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxlQUFlLElBQUksTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDcEYsQ0FBQztJQUVELGlCQUFpQixDQUFDLE1BQXdCO1FBQ3RDLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsZUFBZSxJQUFJLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ3BGLENBQUM7SUFFRCxnQkFBZ0IsQ0FBQyxNQUF3QjtRQUNyQyxPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEdBQUcsTUFBTSxDQUFDLGVBQWUsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDMUYsQ0FBQztJQUVELGtCQUFrQixDQUFDLElBQTBCO1FBQ3pDLE1BQU0sT0FBTyxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwQyxPQUFPLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsZUFBZSxHQUFHLEtBQUssQ0FBQyxDQUFDO0lBQ3RFLENBQUM7SUFFRCxLQUFLLENBQUMsZUFBZTtRQUNqQixJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ3JDLE9BQU87U0FDVjtRQUVELElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxvQ0FBb0MsQ0FBQztRQUM3RCxJQUFJLENBQUMsWUFBWSxHQUFHLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO1FBRXhCLElBQUk7WUFDQSw4QkFBOEI7WUFDOUIsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUU7Z0JBQ3pFLFdBQVcsRUFBRSxJQUFJLENBQUMsa0JBQWtCO2dCQUNwQyxTQUFTLEVBQUUsSUFBSSxDQUFDLGdCQUFnQjtnQkFDaEMsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO2dCQUN2QixpQkFBaUIsRUFBRSxJQUFJLENBQUMsaUJBQWlCO2FBQzVDLENBQUMsQ0FBQztZQUVILElBQUksQ0FBQyxNQUFNLEVBQUU7Z0JBQ1QsTUFBTSxJQUFJLEtBQUssQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO2FBQy9EO1lBRUQsSUFBSSxDQUFDLGdCQUFnQixHQUFHLHdDQUF3QyxDQUFDO1lBQ2pFLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7WUFFeEIsc0JBQXNCO1lBQ3RCLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFFL0MsSUFBSSxPQUFPLEVBQUU7Z0JBQ1QsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUM7b0JBQ3JCLFdBQVcsRUFBRSxJQUFJLENBQUMsa0JBQWtCO29CQUNwQyxTQUFTLEVBQUUsSUFBSSxDQUFDLGdCQUFnQjtvQkFDaEMsZUFBZSxFQUFFLElBQUksQ0FBQyxvQkFBb0I7aUJBQzdDLENBQUMsQ0FBQzthQUNOO2lCQUFNO2dCQUNILElBQUksQ0FBQyxZQUFZLEdBQUcsNENBQTRDLENBQUM7YUFDcEU7U0FDSjtRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1IsSUFBSSxDQUFDLFlBQVksR0FBRyxVQUFVLENBQUMsQ0FBQyxPQUFPLElBQUksZUFBZSxFQUFFLENBQUM7WUFDN0QsT0FBTyxDQUFDLEtBQUssQ0FBQyw0QkFBNEIsRUFBRSxDQUFDLENBQUMsQ0FBQztTQUNsRDtRQUVELElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDNUIsQ0FBQztJQUVPLEtBQUssQ0FBQyxpQkFBaUI7UUFDM0IsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBRTdCLE9BQU8sSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFNBQVMsR0FBRyxJQUFJLENBQUMsZUFBZSxFQUFFO1lBQ2xELElBQUk7Z0JBQ0EsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBRXhFLElBQUksUUFBUSxLQUFLLENBQUMsRUFBRTtvQkFDaEIsMEVBQTBFO29CQUMxRSxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTt3QkFDekUsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO3dCQUN2QixlQUFlLEVBQUUsSUFBSSxDQUFDLG9CQUFvQjt3QkFDMUMsTUFBTSxFQUFFLElBQUksQ0FBQyxPQUFPO3FCQUN2QixDQUF5QyxDQUFDO29CQUUzQyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLElBQUksQ0FDL0IsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxlQUFlLEtBQUssSUFBSSxDQUFDLG9CQUFvQixDQUN6RCxDQUFDO29CQUVGLElBQUksS0FBSyxFQUFFO3dCQUNQLE9BQU8sSUFBSSxDQUFDO3FCQUNmO2lCQUNKO2dCQUVELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7Z0JBQzVELElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxpQkFBaUIsT0FBTyxhQUFhLFFBQVEsR0FBRyxDQUFDO2dCQUN6RSxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUV4QixNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7YUFDM0M7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDUixPQUFPLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDL0IsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO2FBQzNDO1NBQ0o7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNqQixDQUFDO0lBRU8sS0FBSyxDQUFDLEVBQVU7UUFDcEIsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRCxNQUFNO1FBQ0YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRUQsWUFBWSxDQUFDLE1BQXdCO1FBQ2pDLE1BQU0sS0FBSyxHQUFHLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUMzQyxNQUFNLEdBQUcsR0FBRyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDdkMsT0FBTyxHQUFHLEtBQUssQ0FBQyxjQUFjLEVBQUUsTUFBTSxHQUFHLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQztJQUNqRSxDQUFDO0lBRUQsWUFBWSxDQUFDLE9BQWU7UUFDeEIsSUFBSSxPQUFPLEdBQUcsRUFBRSxFQUFFO1lBQ2QsT0FBTyxHQUFHLE9BQU8sTUFBTSxDQUFDO1NBQzNCO1FBQ0QsTUFBTSxLQUFLLEdBQUcsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUMzQixPQUFPLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLFFBQVEsQ0FBQztJQUNyRCxDQUFDOzt5SEFsUlEsMkJBQTJCOzZHQUEzQiwyQkFBMkIsa1VDMUJ4Qyx5b01BdUhBOzRGRDdGYSwyQkFBMkI7a0JBTnZDLFNBQVM7K0JBQ0kscUJBQXFCLG1CQUdkLHVCQUF1QixDQUFDLE1BQU07cUlBR3RDLE1BQU07c0JBQWQsS0FBSztnQkFDRyxrQkFBa0I7c0JBQTFCLEtBQUs7Z0JBQ0csZ0JBQWdCO3NCQUF4QixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFFSSxjQUFjO3NCQUF2QixNQUFNO2dCQUNHLFNBQVM7c0JBQWxCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICAgIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICAgIENoYW5nZURldGVjdG9yUmVmLFxuICAgIENvbXBvbmVudCxcbiAgICBFdmVudEVtaXR0ZXIsXG4gICAgSW5wdXQsXG4gICAgT25Jbml0LFxuICAgIE91dHB1dCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1Byb2ZpbGVTZXJ2aWNlfSBmcm9tICcuLi9wcm9maWxlLnNlcnZpY2UnO1xuaW1wb3J0IHtDdW11bGF0aXZlUGVyaW9kLCBJbmRpdmlkdWFsQ3VtdWxhdGl2ZSwgUmFhaW5BcGlSYWluc0N1bXVsYXRpdmVzRGV0YWlsZWRSZXNwb25zZSwgUmFhaW5BcGlSYWluc0N1bXVsYXRpdmVzTGlzdFJlc3BvbnNlfSBmcm9tICdyYWFpbi1tb2RlbCc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3VtdWxhdGl2ZVNlbGVjdGlvbiB7XG4gICAgcGVyaW9kQmVnaW46IERhdGU7XG4gICAgcGVyaW9kRW5kOiBEYXRlO1xuICAgIHdpbmRvd0luTWludXRlczogbnVtYmVyO1xuICAgIGN1bXVsYXRpdmVJZD86IHN0cmluZztcbiAgICBjdW11bGF0aXZlRGF0ZT86IERhdGU7XG59XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnY3VtdWxhdGl2ZS1zZWxlY3RvcicsXG4gICAgdGVtcGxhdGVVcmw6ICcuL2N1bXVsYXRpdmUtc2VsZWN0b3IuY29tcG9uZW50Lmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL2N1bXVsYXRpdmUtc2VsZWN0b3IuY29tcG9uZW50LnNjc3MnXSxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgQ3VtdWxhdGl2ZVNlbGVjdG9yQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgICBASW5wdXQoKSByYWluSWQ6IHN0cmluZztcbiAgICBASW5wdXQoKSBjdXJyZW50UGVyaW9kQmVnaW46IERhdGU7XG4gICAgQElucHV0KCkgY3VycmVudFBlcmlvZEVuZDogRGF0ZTtcbiAgICBASW5wdXQoKSBwcm92aWRlcjogc3RyaW5nO1xuICAgIEBJbnB1dCgpIHRpbWVTdGVwSW5NaW51dGVzOiBudW1iZXIgPSA1O1xuICAgIEBJbnB1dCgpIGlzQWRtaW46IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIEBPdXRwdXQoKSBwZXJpb2RTZWxlY3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8Q3VtdWxhdGl2ZVNlbGVjdGlvbj4oKTtcbiAgICBAT3V0cHV0KCkgY2FuY2VsbGVkID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xuXG4gICAgYXZhaWxhYmxlUGVyaW9kczogQ3VtdWxhdGl2ZVBlcmlvZFtdID0gW107XG4gICAgYmFzZUN1bXVsYXRpdmVzOiBDdW11bGF0aXZlUGVyaW9kID0gbnVsbDtcbiAgICBsb2FkaW5nID0gdHJ1ZTtcbiAgICBjcmVhdGluZyA9IGZhbHNlO1xuICAgIGNyZWF0aW9uUHJvZ3Jlc3MgPSAnJztcbiAgICBlcnJvck1lc3NhZ2UgPSAnJztcblxuICAgIGNvdmVyYWdlUGVyY2VudCA9IDA7XG4gICAgY2FuQ3JlYXRlTmV3ID0gZmFsc2U7XG4gICAgY3VycmVudFdpbmRvd01pbnV0ZXMgPSAwO1xuXG4gICAgZXhwYW5kZWRQZXJpb2RzOiBNYXA8c3RyaW5nLCBJbmRpdmlkdWFsQ3VtdWxhdGl2ZVtdPiA9IG5ldyBNYXAoKTtcbiAgICBsb2FkaW5nRXhwYW5kZWQ6IFNldDxzdHJpbmc+ID0gbmV3IFNldCgpO1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBQT0xMX1RJTUVPVVRfTVMgPSA5MDAwMDA7IC8vIDkwMCBzZWNvbmRzXG4gICAgcHJpdmF0ZSByZWFkb25seSBQT0xMX0lOVEVSVkFMX01TID0gMzAwMDtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIHByb2ZpbGVTZXJ2aWNlOiBQcm9maWxlU2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBjZHI6IENoYW5nZURldGVjdG9yUmVmXG4gICAgKSB7fVxuXG4gICAgYXN5bmMgbmdPbkluaXQoKSB7XG4gICAgICAgIHRoaXMuY3VycmVudFdpbmRvd01pbnV0ZXMgPSBNYXRoLnJvdW5kKFxuICAgICAgICAgICAgKHRoaXMuY3VycmVudFBlcmlvZEVuZC5nZXRUaW1lKCkgLSB0aGlzLmN1cnJlbnRQZXJpb2RCZWdpbi5nZXRUaW1lKCkpIC8gNjAwMDBcbiAgICAgICAgKTtcbiAgICAgICAgYXdhaXQgdGhpcy5sb2FkQXZhaWxhYmxlUGVyaW9kcygpO1xuICAgIH1cblxuICAgIGFzeW5jIGxvYWRBdmFpbGFibGVQZXJpb2RzKCkge1xuICAgICAgICB0aGlzLmxvYWRpbmcgPSB0cnVlO1xuICAgICAgICB0aGlzLmVycm9yTWVzc2FnZSA9ICcnO1xuICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gRmV0Y2ggYWxsIGN1bXVsYXRpdmUgcGVyaW9kcyAoYWRtaW4gc2VlcyBhbGwsIG5vbi1hZG1pbiBzZWVzIG9ubHkgY3VzdG9tZXItbGF1bmNoZWQpXG4gICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMucHJvZmlsZVNlcnZpY2UuZ2V0Q3VtdWxhdGl2ZVBlcmlvZHModGhpcy5yYWluSWQsIHtcbiAgICAgICAgICAgICAgICBwcm92aWRlcjogdGhpcy5wcm92aWRlcixcbiAgICAgICAgICAgICAgICBmb3JjZWQ6IHRoaXMuaXNBZG1pbixcbiAgICAgICAgICAgIH0pIGFzIFJhYWluQXBpUmFpbnNDdW11bGF0aXZlc0xpc3RSZXNwb25zZTtcblxuICAgICAgICAgICAgLy8gRmlsdGVyIGZvciBleGlzdGluZyBjdXN0b20gY3VtdWxhdGl2ZXMgKHdpbmRvdyA+IDApXG4gICAgICAgICAgICB0aGlzLmF2YWlsYWJsZVBlcmlvZHMgPSByZXNwb25zZS5wZXJpb2RzLmZpbHRlcigocCkgPT4gcC53aW5kb3dJbk1pbnV0ZXMgPiAwKTtcblxuICAgICAgICAgICAgLy8gR2V0IGJhc2UgY3VtdWxhdGl2ZXMgKHdpbmRvdyA9IDApIHRvIGNoZWNrIGNvdmVyYWdlXG4gICAgICAgICAgICB0aGlzLmJhc2VDdW11bGF0aXZlcyA9IHJlc3BvbnNlLnBlcmlvZHMuZmluZCgocCkgPT4gcC53aW5kb3dJbk1pbnV0ZXMgPT09IDApO1xuXG4gICAgICAgICAgICB0aGlzLmNhbGN1bGF0ZUNvdmVyYWdlKCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHRoaXMuZXJyb3JNZXNzYWdlID0gJ0ZhaWxlZCB0byBsb2FkIGN1bXVsYXRpdmUgcGVyaW9kcyc7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBsb2FkaW5nIGN1bXVsYXRpdmUgcGVyaW9kczonLCBlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubG9hZGluZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICB9XG5cbiAgICBjYWxjdWxhdGVDb3ZlcmFnZSgpIHtcbiAgICAgICAgaWYgKCF0aGlzLmJhc2VDdW11bGF0aXZlcykge1xuICAgICAgICAgICAgdGhpcy5jb3ZlcmFnZVBlcmNlbnQgPSAwO1xuICAgICAgICAgICAgdGhpcy5jYW5DcmVhdGVOZXcgPSBmYWxzZTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJhc2VCZWdpbiA9IG5ldyBEYXRlKHRoaXMuYmFzZUN1bXVsYXRpdmVzLnBlcmlvZEJlZ2luKTtcbiAgICAgICAgY29uc3QgYmFzZUVuZCA9IG5ldyBEYXRlKHRoaXMuYmFzZUN1bXVsYXRpdmVzLnBlcmlvZEVuZCk7XG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgY3VycmVudCBwZXJpb2QgaXMgd2l0aGluIGJhc2UgY292ZXJhZ2VcbiAgICAgICAgY29uc3QgY3VycmVudEluUmFuZ2UgPVxuICAgICAgICAgICAgdGhpcy5jdXJyZW50UGVyaW9kQmVnaW4gPj0gYmFzZUJlZ2luICYmIHRoaXMuY3VycmVudFBlcmlvZEVuZCA8PSBiYXNlRW5kO1xuXG4gICAgICAgIGlmICghY3VycmVudEluUmFuZ2UpIHtcbiAgICAgICAgICAgIHRoaXMuY292ZXJhZ2VQZXJjZW50ID0gMDtcbiAgICAgICAgICAgIHRoaXMuY2FuQ3JlYXRlTmV3ID0gZmFsc2U7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDYWxjdWxhdGUgZXhwZWN0ZWQgbnVtYmVyIG9mIGJhc2UgY3VtdWxhdGl2ZXMgbmVlZGVkXG4gICAgICAgIGNvbnN0IGV4cGVjdGVkQ291bnQgPSBNYXRoLmNlaWwodGhpcy5jdXJyZW50V2luZG93TWludXRlcyAvIHRoaXMudGltZVN0ZXBJbk1pbnV0ZXMpO1xuXG4gICAgICAgIC8vIENoZWNrIGlmIGVub3VnaCBiYXNlIGN1bXVsYXRpdmVzIGV4aXN0XG4gICAgICAgIC8vIFdlIGFzc3VtZSBjb3ZlcmFnZSBpcyBjb21wbGV0ZSBpZiBjb3VudCA+PSBleHBlY3RlZCAoc2ltcGxpZmllZCBjaGVjaylcbiAgICAgICAgaWYgKHRoaXMuYmFzZUN1bXVsYXRpdmVzLmNvdW50ID49IGV4cGVjdGVkQ291bnQpIHtcbiAgICAgICAgICAgIHRoaXMuY292ZXJhZ2VQZXJjZW50ID0gMTAwO1xuICAgICAgICAgICAgdGhpcy5jYW5DcmVhdGVOZXcgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jb3ZlcmFnZVBlcmNlbnQgPSBNYXRoLnJvdW5kKCh0aGlzLmJhc2VDdW11bGF0aXZlcy5jb3VudCAvIGV4cGVjdGVkQ291bnQpICogMTAwKTtcbiAgICAgICAgICAgIHRoaXMuY2FuQ3JlYXRlTmV3ID0gdGhpcy5jb3ZlcmFnZVBlcmNlbnQgPj0gMTAwO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgc2VsZWN0UGVyaW9kKHBlcmlvZDogQ3VtdWxhdGl2ZVBlcmlvZCkge1xuICAgICAgICB0aGlzLnBlcmlvZFNlbGVjdGVkLmVtaXQoe1xuICAgICAgICAgICAgcGVyaW9kQmVnaW46IG5ldyBEYXRlKHBlcmlvZC5wZXJpb2RCZWdpbiksXG4gICAgICAgICAgICBwZXJpb2RFbmQ6IG5ldyBEYXRlKHBlcmlvZC5wZXJpb2RFbmQpLFxuICAgICAgICAgICAgd2luZG93SW5NaW51dGVzOiBwZXJpb2Qud2luZG93SW5NaW51dGVzLFxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBhc3luYyB0b2dnbGVFeHBhbmQocGVyaW9kOiBDdW11bGF0aXZlUGVyaW9kKSB7XG4gICAgICAgIGNvbnN0IGtleSA9IGAke3BlcmlvZC53aW5kb3dJbk1pbnV0ZXN9LSR7cGVyaW9kLnByb3ZpZGVyfWA7XG4gICAgICAgIGlmICh0aGlzLmV4cGFuZGVkUGVyaW9kcy5oYXMoa2V5KSkge1xuICAgICAgICAgICAgdGhpcy5leHBhbmRlZFBlcmlvZHMuZGVsZXRlKGtleSk7XG4gICAgICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubG9hZGluZ0V4cGFuZGVkLmFkZChrZXkpO1xuICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLnByb2ZpbGVTZXJ2aWNlLmdldEN1bXVsYXRpdmVQZXJpb2RzKHRoaXMucmFpbklkLCB7XG4gICAgICAgICAgICAgICAgcHJvdmlkZXI6IHRoaXMucHJvdmlkZXIsXG4gICAgICAgICAgICAgICAgd2luZG93SW5NaW51dGVzOiBwZXJpb2Qud2luZG93SW5NaW51dGVzLFxuICAgICAgICAgICAgICAgIGZvcmNlZDogdGhpcy5pc0FkbWluLFxuICAgICAgICAgICAgICAgIGRldGFpbGVkOiB0cnVlLFxuICAgICAgICAgICAgfSkgYXMgUmFhaW5BcGlSYWluc0N1bXVsYXRpdmVzRGV0YWlsZWRSZXNwb25zZTtcblxuICAgICAgICAgICAgdGhpcy5leHBhbmRlZFBlcmlvZHMuc2V0KGtleSwgcmVzcG9uc2UuY3VtdWxhdGl2ZXMgfHwgW10pO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBsb2FkaW5nIGluZGl2aWR1YWwgY3VtdWxhdGl2ZXM6JywgZSk7XG4gICAgICAgICAgICB0aGlzLmV4cGFuZGVkUGVyaW9kcy5zZXQoa2V5LCBbXSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmxvYWRpbmdFeHBhbmRlZC5kZWxldGUoa2V5KTtcbiAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgfVxuXG4gICAgc2VsZWN0SW5kaXZpZHVhbEN1bXVsYXRpdmUoaXRlbTogSW5kaXZpZHVhbEN1bXVsYXRpdmUpIHtcbiAgICAgICAgY29uc3QgZW5kRGF0ZSA9IG5ldyBEYXRlKGl0ZW0uZGF0ZSk7XG4gICAgICAgIGNvbnN0IGJlZ2luRGF0ZSA9IG5ldyBEYXRlKGVuZERhdGUuZ2V0VGltZSgpIC0gaXRlbS53aW5kb3dJbk1pbnV0ZXMgKiA2MDAwMCk7XG5cbiAgICAgICAgdGhpcy5wZXJpb2RTZWxlY3RlZC5lbWl0KHtcbiAgICAgICAgICAgIHBlcmlvZEJlZ2luOiBiZWdpbkRhdGUsXG4gICAgICAgICAgICBwZXJpb2RFbmQ6IGVuZERhdGUsXG4gICAgICAgICAgICB3aW5kb3dJbk1pbnV0ZXM6IGl0ZW0ud2luZG93SW5NaW51dGVzLFxuICAgICAgICAgICAgY3VtdWxhdGl2ZUlkOiBpdGVtLmlkLFxuICAgICAgICAgICAgY3VtdWxhdGl2ZURhdGU6IGVuZERhdGUsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlzRXhwYW5kZWQocGVyaW9kOiBDdW11bGF0aXZlUGVyaW9kKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLmV4cGFuZGVkUGVyaW9kcy5oYXMoYCR7cGVyaW9kLndpbmRvd0luTWludXRlc30tJHtwZXJpb2QucHJvdmlkZXJ9YCk7XG4gICAgfVxuXG4gICAgaXNMb2FkaW5nRXhwYW5kZWQocGVyaW9kOiBDdW11bGF0aXZlUGVyaW9kKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLmxvYWRpbmdFeHBhbmRlZC5oYXMoYCR7cGVyaW9kLndpbmRvd0luTWludXRlc30tJHtwZXJpb2QucHJvdmlkZXJ9YCk7XG4gICAgfVxuXG4gICAgZ2V0RXhwYW5kZWRJdGVtcyhwZXJpb2Q6IEN1bXVsYXRpdmVQZXJpb2QpOiBJbmRpdmlkdWFsQ3VtdWxhdGl2ZVtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZXhwYW5kZWRQZXJpb2RzLmdldChgJHtwZXJpb2Qud2luZG93SW5NaW51dGVzfS0ke3BlcmlvZC5wcm92aWRlcn1gKSB8fCBbXTtcbiAgICB9XG5cbiAgICBnZXRJdGVtUGVyaW9kQmVnaW4oaXRlbTogSW5kaXZpZHVhbEN1bXVsYXRpdmUpOiBEYXRlIHtcbiAgICAgICAgY29uc3QgZW5kRGF0ZSA9IG5ldyBEYXRlKGl0ZW0uZGF0ZSk7XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZShlbmREYXRlLmdldFRpbWUoKSAtIGl0ZW0ud2luZG93SW5NaW51dGVzICogNjAwMDApO1xuICAgIH1cblxuICAgIGFzeW5jIGNyZWF0ZU5ld1BlcmlvZCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLmNhbkNyZWF0ZU5ldyB8fCB0aGlzLmNyZWF0aW5nKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmNyZWF0aW5nID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5jcmVhdGlvblByb2dyZXNzID0gJ1N0YXJ0aW5nIGN1bXVsYXRpdmUgY29tcHV0YXRpb24uLi4nO1xuICAgICAgICB0aGlzLmVycm9yTWVzc2FnZSA9ICcnO1xuICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gVHJpZ2dlciBjdW11bGF0aXZlIGNyZWF0aW9uXG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnByb2ZpbGVTZXJ2aWNlLmNyZWF0ZUN1bXVsYXRpdmVQZXJpb2QodGhpcy5yYWluSWQsIHtcbiAgICAgICAgICAgICAgICBwZXJpb2RCZWdpbjogdGhpcy5jdXJyZW50UGVyaW9kQmVnaW4sXG4gICAgICAgICAgICAgICAgcGVyaW9kRW5kOiB0aGlzLmN1cnJlbnRQZXJpb2RFbmQsXG4gICAgICAgICAgICAgICAgcHJvdmlkZXI6IHRoaXMucHJvdmlkZXIsXG4gICAgICAgICAgICAgICAgdGltZVN0ZXBJbk1pbnV0ZXM6IHRoaXMudGltZVN0ZXBJbk1pbnV0ZXMsXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYgKCFyZXN1bHQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ZhaWxlZCB0byB0cmlnZ2VyIGN1bXVsYXRpdmUgY29tcHV0YXRpb24nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5jcmVhdGlvblByb2dyZXNzID0gYEpvYnMgcXVldWVkLiBQb2xsaW5nIGZvciBjb21wbGV0aW9uLi4uYDtcbiAgICAgICAgICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuXG4gICAgICAgICAgICAvLyBQb2xsIGZvciBjb21wbGV0aW9uXG4gICAgICAgICAgICBjb25zdCBzdWNjZXNzID0gYXdhaXQgdGhpcy5wb2xsRm9yQ29tcGxldGlvbigpO1xuXG4gICAgICAgICAgICBpZiAoc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgIHRoaXMucGVyaW9kU2VsZWN0ZWQuZW1pdCh7XG4gICAgICAgICAgICAgICAgICAgIHBlcmlvZEJlZ2luOiB0aGlzLmN1cnJlbnRQZXJpb2RCZWdpbixcbiAgICAgICAgICAgICAgICAgICAgcGVyaW9kRW5kOiB0aGlzLmN1cnJlbnRQZXJpb2RFbmQsXG4gICAgICAgICAgICAgICAgICAgIHdpbmRvd0luTWludXRlczogdGhpcy5jdXJyZW50V2luZG93TWludXRlcyxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvck1lc3NhZ2UgPSAnVGltZW91dCB3YWl0aW5nIGZvciBjdW11bGF0aXZlIGNvbXB1dGF0aW9uJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgdGhpcy5lcnJvck1lc3NhZ2UgPSBgRXJyb3I6ICR7ZS5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJ31gO1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgY3JlYXRpbmcgY3VtdWxhdGl2ZTonLCBlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY3JlYXRpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBwb2xsRm9yQ29tcGxldGlvbigpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcblxuICAgICAgICB3aGlsZSAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSA8IHRoaXMuUE9MTF9USU1FT1VUX01TKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHByb2dyZXNzID0gYXdhaXQgdGhpcy5wcm9maWxlU2VydmljZS5nZXRSYWluUHJvZ3Jlc3ModGhpcy5yYWluSWQpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHByb2dyZXNzID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFF1ZXVlIGlzIGVtcHR5LCBjaGVjayBpZiBjdW11bGF0aXZlIGV4aXN0cyAoYWRtaW4gc2VlcyBhbGwgY3VtdWxhdGl2ZXMpXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5wcm9maWxlU2VydmljZS5nZXRDdW11bGF0aXZlUGVyaW9kcyh0aGlzLnJhaW5JZCwge1xuICAgICAgICAgICAgICAgICAgICAgICAgcHJvdmlkZXI6IHRoaXMucHJvdmlkZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICB3aW5kb3dJbk1pbnV0ZXM6IHRoaXMuY3VycmVudFdpbmRvd01pbnV0ZXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBmb3JjZWQ6IHRoaXMuaXNBZG1pbixcbiAgICAgICAgICAgICAgICAgICAgfSkgYXMgUmFhaW5BcGlSYWluc0N1bXVsYXRpdmVzTGlzdFJlc3BvbnNlO1xuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGZvdW5kID0gcmVzcG9uc2UucGVyaW9kcy5maW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgKHApID0+IHAud2luZG93SW5NaW51dGVzID09PSB0aGlzLmN1cnJlbnRXaW5kb3dNaW51dGVzXG4gICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGZvdW5kKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNvbnN0IGVsYXBzZWQgPSBNYXRoLnJvdW5kKChEYXRlLm5vdygpIC0gc3RhcnRUaW1lKSAvIDEwMDApO1xuICAgICAgICAgICAgICAgIHRoaXMuY3JlYXRpb25Qcm9ncmVzcyA9IGBDb21wdXRpbmcuLi4gKCR7ZWxhcHNlZH1zLCBxdWV1ZTogJHtwcm9ncmVzc30pYDtcbiAgICAgICAgICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcblxuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuc2xlZXAodGhpcy5QT0xMX0lOVEVSVkFMX01TKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1BvbGwgZXJyb3I6JywgZSk7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5zbGVlcCh0aGlzLlBPTExfSU5URVJWQUxfTVMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgc2xlZXAobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcbiAgICB9XG5cbiAgICBjYW5jZWwoKSB7XG4gICAgICAgIHRoaXMuY2FuY2VsbGVkLmVtaXQoKTtcbiAgICB9XG5cbiAgICBmb3JtYXRQZXJpb2QocGVyaW9kOiBDdW11bGF0aXZlUGVyaW9kKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3QgYmVnaW4gPSBuZXcgRGF0ZShwZXJpb2QucGVyaW9kQmVnaW4pO1xuICAgICAgICBjb25zdCBlbmQgPSBuZXcgRGF0ZShwZXJpb2QucGVyaW9kRW5kKTtcbiAgICAgICAgcmV0dXJuIGAke2JlZ2luLnRvTG9jYWxlU3RyaW5nKCl9IOKGkiAke2VuZC50b0xvY2FsZVN0cmluZygpfWA7XG4gICAgfVxuXG4gICAgZm9ybWF0V2luZG93KG1pbnV0ZXM6IG51bWJlcik6IHN0cmluZyB7XG4gICAgICAgIGlmIChtaW51dGVzIDwgNjApIHtcbiAgICAgICAgICAgIHJldHVybiBgJHttaW51dGVzfSBtaW5gO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGhvdXJzID0gbWludXRlcyAvIDYwO1xuICAgICAgICByZXR1cm4gaG91cnMgPT09IDEgPyAnMSBob3VyJyA6IGAke2hvdXJzfSBob3Vyc2A7XG4gICAgfVxufVxuIiwiPGRpdiBjbGFzcz1cImN1bXVsYXRpdmUtc2VsZWN0b3Itb3ZlcmxheVwiPlxuICAgIDxkaXYgY2xhc3M9XCJjdW11bGF0aXZlLXNlbGVjdG9yLW1vZGFsXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1oZWFkZXJcIj5cbiAgICAgICAgICAgIDxoMj5TZWxlY3QgQ3VtdWxhdGl2ZSBQZXJpb2Q8L2gyPlxuICAgICAgICAgICAgPGlvbi1idXR0b24gZmlsbD1cImNsZWFyXCIgKGNsaWNrKT1cImNhbmNlbCgpXCI+XG4gICAgICAgICAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJjbG9zZVwiPjwvaW9uLWljb24+XG4gICAgICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1jb250ZW50XCI+XG4gICAgICAgICAgICA8IS0tIExvYWRpbmcgc3RhdGUgLS0+XG4gICAgICAgICAgICA8ZGl2ICpuZ0lmPVwibG9hZGluZ1wiIGNsYXNzPVwibG9hZGluZy1zdGF0ZVwiPlxuICAgICAgICAgICAgICAgIDxpb24tc3Bpbm5lciBuYW1lPVwiY3Jlc2NlbnRcIj48L2lvbi1zcGlubmVyPlxuICAgICAgICAgICAgICAgIDxwPkxvYWRpbmcgYXZhaWxhYmxlIHBlcmlvZHMuLi48L3A+XG4gICAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgICAgPCEtLSBFcnJvciBtZXNzYWdlIC0tPlxuICAgICAgICAgICAgPGRpdiAqbmdJZj1cImVycm9yTWVzc2FnZVwiIGNsYXNzPVwiZXJyb3ItbWVzc2FnZVwiPlxuICAgICAgICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwid2FybmluZy1vdXRsaW5lXCI+PC9pb24taWNvbj5cbiAgICAgICAgICAgICAgICA8c3Bhbj57eyBlcnJvck1lc3NhZ2UgfX08L3NwYW4+XG4gICAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgICAgPCEtLSBBdmFpbGFibGUgcGVyaW9kcyBsaXN0IC0tPlxuICAgICAgICAgICAgPGRpdiAqbmdJZj1cIiFsb2FkaW5nICYmIGF2YWlsYWJsZVBlcmlvZHMubGVuZ3RoID4gMFwiIGNsYXNzPVwicGVyaW9kcy1zZWN0aW9uXCI+XG4gICAgICAgICAgICAgICAgPGgzPkF2YWlsYWJsZSBDdW11bGF0aXZlIFBlcmlvZHM8L2gzPlxuICAgICAgICAgICAgICAgIDxpb24tbGlzdD5cbiAgICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgcGVyaW9kIG9mIGF2YWlsYWJsZVBlcmlvZHNcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwhLS0gUGVyaW9kIGhlYWRlciAoY2xpY2sgdG8gZXhwYW5kKSAtLT5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxpb24taXRlbSBidXR0b24gKGNsaWNrKT1cInRvZ2dsZUV4cGFuZChwZXJpb2QpXCIgW2Rpc2FibGVkXT1cImNyZWF0aW5nXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGlvbi1pY29uIFtuYW1lXT1cImlzRXhwYW5kZWQocGVyaW9kKSA/ICdjaGV2cm9uLWRvd24nIDogJ2NoZXZyb24tZm9yd2FyZCdcIiBzbG90PVwic3RhcnRcIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpb24tbGFiZWw+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxoMj57eyBmb3JtYXRXaW5kb3cocGVyaW9kLndpbmRvd0luTWludXRlcykgfX08L2gyPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8cD57eyBmb3JtYXRQZXJpb2QocGVyaW9kKSB9fTwvcD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHAgY2xhc3M9XCJjb3VudC1pbmZvXCI+e3sgcGVyaW9kLmNvdW50IH19IGN1bXVsYXRpdmUocykgLSBjbGljayB0byBleHBhbmQ8L3A+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgICAgICAgICAgICAgICAgICA8L2lvbi1pdGVtPlxuXG4gICAgICAgICAgICAgICAgICAgICAgICA8IS0tIEV4cGFuZGVkOiBpbmRpdmlkdWFsIGN1bXVsYXRpdmVzIC0tPlxuICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiAqbmdJZj1cImlzRXhwYW5kZWQocGVyaW9kKVwiIGNsYXNzPVwiZXhwYW5kZWQtaXRlbXNcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8aW9uLXNwaW5uZXIgKm5nSWY9XCJpc0xvYWRpbmdFeHBhbmRlZChwZXJpb2QpXCIgbmFtZT1cImNyZXNjZW50XCI+PC9pb24tc3Bpbm5lcj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8aW9uLWxpc3QgKm5nSWY9XCIhaXNMb2FkaW5nRXhwYW5kZWQocGVyaW9kKVwiIGNsYXNzPVwibmVzdGVkLWxpc3RcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGlvbi1pdGVtICpuZ0Zvcj1cImxldCBpdGVtIG9mIGdldEV4cGFuZGVkSXRlbXMocGVyaW9kKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJzZWxlY3RJbmRpdmlkdWFsQ3VtdWxhdGl2ZShpdGVtKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cIm5lc3RlZC1pdGVtXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJjcmVhdGluZ1wiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJ0aW1lLW91dGxpbmVcIiBzbG90PVwic3RhcnRcIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGlvbi1sYWJlbD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8aDM+e3sgZ2V0SXRlbVBlcmlvZEJlZ2luKGl0ZW0pIHwgZGF0ZTonSEg6bW0nIH19IC0ge3sgaXRlbS5kYXRlIHwgZGF0ZTonSEg6bW0nIH19PC9oMz5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvaW9uLWxhYmVsPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJjaGV2cm9uLWZvcndhcmRcIiBzbG90PVwiZW5kXCI+PC9pb24taWNvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9pb24taXRlbT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGlvbi1pdGVtICpuZ0lmPVwiZ2V0RXhwYW5kZWRJdGVtcyhwZXJpb2QpLmxlbmd0aCA9PT0gMFwiIGNsYXNzPVwibmVzdGVkLWl0ZW1cIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpb24tbGFiZWw+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHA+Tm8gaW5kaXZpZHVhbCBjdW11bGF0aXZlcyBmb3VuZDwvcD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvaW9uLWxhYmVsPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2lvbi1pdGVtPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvaW9uLWxpc3Q+XG4gICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgICAgPC9pb24tbGlzdD5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8IS0tIE5vIHBlcmlvZHMgYXZhaWxhYmxlIC0tPlxuICAgICAgICAgICAgPGRpdiAqbmdJZj1cIiFsb2FkaW5nICYmIGF2YWlsYWJsZVBlcmlvZHMubGVuZ3RoID09PSAwXCIgY2xhc3M9XCJuby1wZXJpb2RzXCI+XG4gICAgICAgICAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJpbmZvcm1hdGlvbi1jaXJjbGUtb3V0bGluZVwiPjwvaW9uLWljb24+XG4gICAgICAgICAgICAgICAgPHA+Tm8gY3VtdWxhdGl2ZSBwZXJpb2RzIGF2YWlsYWJsZSB5ZXQuPC9wPlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDwhLS0gQ3JlYXRlIG5ldyBzZWN0aW9uIChhZG1pbiBvbmx5KSAtLT5cbiAgICAgICAgICAgIDxkaXYgKm5nSWY9XCIhbG9hZGluZyAmJiBpc0FkbWluXCIgY2xhc3M9XCJjcmVhdGUtc2VjdGlvblwiPlxuICAgICAgICAgICAgICAgIDxoMz5DcmVhdGUgTmV3IEN1bXVsYXRpdmU8L2gzPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcmVhdGUtaW5mb1wiPlxuICAgICAgICAgICAgICAgICAgICA8cD5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxzdHJvbmc+UGVyaW9kOjwvc3Ryb25nPlxuICAgICAgICAgICAgICAgICAgICAgICAge3sgY3VycmVudFBlcmlvZEJlZ2luPy50b0xvY2FsZVN0cmluZygpIH19IOKGkiB7eyBjdXJyZW50UGVyaW9kRW5kPy50b0xvY2FsZVN0cmluZygpIH19XG4gICAgICAgICAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgICAgICAgICAgPHA+XG4gICAgICAgICAgICAgICAgICAgICAgICA8c3Ryb25nPldpbmRvdzo8L3N0cm9uZz4ge3sgZm9ybWF0V2luZG93KGN1cnJlbnRXaW5kb3dNaW51dGVzKSB9fVxuICAgICAgICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICAgICAgICAgIDxwICpuZ0lmPVwiYmFzZUN1bXVsYXRpdmVzXCIgY2xhc3M9XCJjb3ZlcmFnZS1pbmZvXCJcbiAgICAgICAgICAgICAgICAgICAgICAgW2NsYXNzLmNvdmVyYWdlLW9rXT1cImNvdmVyYWdlUGVyY2VudCA+PSAxMDBcIlxuICAgICAgICAgICAgICAgICAgICAgICBbY2xhc3MuY292ZXJhZ2Utd2Fybl09XCJjb3ZlcmFnZVBlcmNlbnQgPiAwICYmIGNvdmVyYWdlUGVyY2VudCA8IDEwMFwiXG4gICAgICAgICAgICAgICAgICAgICAgIFtjbGFzcy5jb3ZlcmFnZS1lcnJvcl09XCJjb3ZlcmFnZVBlcmNlbnQgPT09IDBcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxpb24taWNvbiBbbmFtZV09XCJjb3ZlcmFnZVBlcmNlbnQgPj0gMTAwID8gJ2NoZWNrbWFyay1jaXJjbGUnIDogJ2FsZXJ0LWNpcmNsZSdcIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgICAgICAgICAgICAgQmFzZSBkYXRhIGNvdmVyYWdlOiB7eyBjb3ZlcmFnZVBlcmNlbnQgfX0lXG4gICAgICAgICAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgICAgICAgICAgPHAgKm5nSWY9XCIhYmFzZUN1bXVsYXRpdmVzXCIgY2xhc3M9XCJjb3ZlcmFnZS1lcnJvclwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJhbGVydC1jaXJjbGVcIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgICAgICAgICAgICAgTm8gYmFzZSBjdW11bGF0aXZlcyBhdmFpbGFibGVcbiAgICAgICAgICAgICAgICAgICAgPC9wPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICAgICAgPCEtLSBDcmVhdGlvbiBwcm9ncmVzcyAtLT5cbiAgICAgICAgICAgICAgICA8ZGl2ICpuZ0lmPVwiY3JlYXRpbmdcIiBjbGFzcz1cImNyZWF0aW9uLXByb2dyZXNzXCI+XG4gICAgICAgICAgICAgICAgICAgIDxpb24tc3Bpbm5lciBuYW1lPVwiY3Jlc2NlbnRcIj48L2lvbi1zcGlubmVyPlxuICAgICAgICAgICAgICAgICAgICA8c3Bhbj57eyBjcmVhdGlvblByb2dyZXNzIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICAgICAgPGlvbi1idXR0b24gW2Rpc2FibGVkXT1cIiFjYW5DcmVhdGVOZXcgfHwgY3JlYXRpbmdcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cGFuZD1cImJsb2NrXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwiY3JlYXRlTmV3UGVyaW9kKClcIj5cbiAgICAgICAgICAgICAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJhZGQtY2lyY2xlLW91dGxpbmVcIiBzbG90PVwic3RhcnRcIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgICAgICAgICBDcmVhdGUge3sgZm9ybWF0V2luZG93KGN1cnJlbnRXaW5kb3dNaW51dGVzKSB9fSBDdW11bGF0aXZlXG4gICAgICAgICAgICAgICAgPC9pb24tYnV0dG9uPlxuXG4gICAgICAgICAgICAgICAgPHAgKm5nSWY9XCIhY2FuQ3JlYXRlTmV3ICYmICFjcmVhdGluZ1wiIGNsYXNzPVwiY3JlYXRlLWhpbnRcIj5cbiAgICAgICAgICAgICAgICAgICAgQ3JlYXRlIGlzIGRpc2FibGVkIGJlY2F1c2UgYmFzZSA1LW1pbiBjdW11bGF0aXZlcyBkb24ndCBmdWxseSBjb3ZlciB0aGUgc2VsZWN0ZWQgcGVyaW9kLlxuICAgICAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwibW9kYWwtZm9vdGVyXCI+XG4gICAgICAgICAgICA8aW9uLWJ1dHRvbiBmaWxsPVwib3V0bGluZVwiIChjbGljayk9XCJjYW5jZWwoKVwiIFtkaXNhYmxlZF09XCJjcmVhdGluZ1wiPlxuICAgICAgICAgICAgICAgIENhbmNlbFxuICAgICAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbjwvZGl2PlxuIl19
package/esm2020/index.mjs CHANGED
@@ -7,6 +7,7 @@ export * from './raain-speed/raain-speed.component';
7
7
  export * from './raain-compare-stack/raain-compare-stack.component';
8
8
  export * from './raain-globe/raain-globe.component';
9
9
  export * from './raain-details/raain-details.component';
10
+ export * from './cumulative-selector/cumulative-selector.component';
10
11
  export * from './tools';
11
12
  export * from './cache.service';
12
13
  export * from './fidj-storage.model';
@@ -19,4 +20,4 @@ export * from './storage.service';
19
20
  export * from './xytype';
20
21
  export * from './profile-icon.directive';
21
22
  export * from './pipes.module';
22
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29yZS9zaGFyZWQvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxpQ0FBaUMsQ0FBQztBQUNoRCxjQUFjLHlDQUF5QyxDQUFDO0FBQ3hELGNBQWMscURBQXFELENBQUM7QUFDcEUsY0FBYywrQ0FBK0MsQ0FBQztBQUM5RCxjQUFjLG1EQUFtRCxDQUFDO0FBQ2xFLGNBQWMscUNBQXFDLENBQUM7QUFDcEQsY0FBYyxxREFBcUQsQ0FBQztBQUNwRSxjQUFjLHFDQUFxQyxDQUFDO0FBQ3BELGNBQWMseUNBQXlDLENBQUM7QUFFeEQsY0FBYyxTQUFTLENBQUM7QUFFeEIsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLGdCQUFnQixDQUFDO0FBQy9CLGNBQWMsZUFBZSxDQUFDO0FBQzlCLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLFVBQVUsQ0FBQztBQUN6QixjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMsZ0JBQWdCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL3JhYWluLW1hcC9yYWFpbi1tYXAuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vcmFhaW4tY29tcGFyZS9yYWFpbi1jb21wYXJlLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL3JhYWluLWNvbmZpZ3VyYXRpb24vcmFhaW4tY29uZmlndXJhdGlvbi5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9yYWFpbi1kYXRlLWZvY3VzL3JhYWluLWRhdGUtZm9jdXMuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vcmFhaW4tZGF0ZS1keW5hbWljL3JhYWluLWRhdGUtZHluYW1pYy5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9yYWFpbi1zcGVlZC9yYWFpbi1zcGVlZC5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9yYWFpbi1jb21wYXJlLXN0YWNrL3JhYWluLWNvbXBhcmUtc3RhY2suY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vcmFhaW4tZ2xvYmUvcmFhaW4tZ2xvYmUuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vcmFhaW4tZGV0YWlscy9yYWFpbi1kZXRhaWxzLmNvbXBvbmVudCc7XG5cbmV4cG9ydCAqIGZyb20gJy4vdG9vbHMnO1xuXG5leHBvcnQgKiBmcm9tICcuL2NhY2hlLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9maWRqLXN0b3JhZ2UubW9kZWwnO1xuZXhwb3J0ICogZnJvbSAnLi9wcm9maWxlLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9yYWRhci5zZXJ2aWNlJztcbmV4cG9ydCAqIGZyb20gJy4vc2hhcmVkLmNvbnN0JztcbmV4cG9ydCAqIGZyb20gJy4vc2hhcmVkLnBpcGUnO1xuZXhwb3J0ICogZnJvbSAnLi9zaGFyZWQubW9kdWxlJztcbmV4cG9ydCAqIGZyb20gJy4vc3RvcmFnZS5zZXJ2aWNlJztcbmV4cG9ydCAqIGZyb20gJy4veHl0eXBlJztcbmV4cG9ydCAqIGZyb20gJy4vcHJvZmlsZS1pY29uLmRpcmVjdGl2ZSc7XG5leHBvcnQgKiBmcm9tICcuL3BpcGVzLm1vZHVsZSc7XG4iXX0=
23
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29yZS9zaGFyZWQvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxpQ0FBaUMsQ0FBQztBQUNoRCxjQUFjLHlDQUF5QyxDQUFDO0FBQ3hELGNBQWMscURBQXFELENBQUM7QUFDcEUsY0FBYywrQ0FBK0MsQ0FBQztBQUM5RCxjQUFjLG1EQUFtRCxDQUFDO0FBQ2xFLGNBQWMscUNBQXFDLENBQUM7QUFDcEQsY0FBYyxxREFBcUQsQ0FBQztBQUNwRSxjQUFjLHFDQUFxQyxDQUFDO0FBQ3BELGNBQWMseUNBQXlDLENBQUM7QUFDeEQsY0FBYyxxREFBcUQsQ0FBQztBQUVwRSxjQUFjLFNBQVMsQ0FBQztBQUV4QixjQUFjLGlCQUFpQixDQUFDO0FBQ2hDLGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLGlCQUFpQixDQUFDO0FBQ2hDLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLG1CQUFtQixDQUFDO0FBQ2xDLGNBQWMsVUFBVSxDQUFDO0FBQ3pCLGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYyxnQkFBZ0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vcmFhaW4tbWFwL3JhYWluLW1hcC5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9yYWFpbi1jb21wYXJlL3JhYWluLWNvbXBhcmUuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vcmFhaW4tY29uZmlndXJhdGlvbi9yYWFpbi1jb25maWd1cmF0aW9uLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL3JhYWluLWRhdGUtZm9jdXMvcmFhaW4tZGF0ZS1mb2N1cy5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9yYWFpbi1kYXRlLWR5bmFtaWMvcmFhaW4tZGF0ZS1keW5hbWljLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL3JhYWluLXNwZWVkL3JhYWluLXNwZWVkLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL3JhYWluLWNvbXBhcmUtc3RhY2svcmFhaW4tY29tcGFyZS1zdGFjay5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9yYWFpbi1nbG9iZS9yYWFpbi1nbG9iZS5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9yYWFpbi1kZXRhaWxzL3JhYWluLWRldGFpbHMuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vY3VtdWxhdGl2ZS1zZWxlY3Rvci9jdW11bGF0aXZlLXNlbGVjdG9yLmNvbXBvbmVudCc7XG5cbmV4cG9ydCAqIGZyb20gJy4vdG9vbHMnO1xuXG5leHBvcnQgKiBmcm9tICcuL2NhY2hlLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9maWRqLXN0b3JhZ2UubW9kZWwnO1xuZXhwb3J0ICogZnJvbSAnLi9wcm9maWxlLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9yYWRhci5zZXJ2aWNlJztcbmV4cG9ydCAqIGZyb20gJy4vc2hhcmVkLmNvbnN0JztcbmV4cG9ydCAqIGZyb20gJy4vc2hhcmVkLnBpcGUnO1xuZXhwb3J0ICogZnJvbSAnLi9zaGFyZWQubW9kdWxlJztcbmV4cG9ydCAqIGZyb20gJy4vc3RvcmFnZS5zZXJ2aWNlJztcbmV4cG9ydCAqIGZyb20gJy4veHl0eXBlJztcbmV4cG9ydCAqIGZyb20gJy4vcHJvZmlsZS1pY29uLmRpcmVjdGl2ZSc7XG5leHBvcnQgKiBmcm9tICcuL3BpcGVzLm1vZHVsZSc7XG4iXX0=