@oneluiz/dual-datepicker 3.5.0 → 3.5.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.
- package/README.md +51 -3
- package/core/date-adapter.d.ts +298 -0
- package/core/date-clock.d.ts +82 -0
- package/core/dual-date-range.store.d.ts +9 -0
- package/core/index.d.ts +4 -0
- package/core/native-date-adapter.d.ts +152 -0
- package/core/preset.engine.d.ts +40 -6
- package/core/system-clock.d.ts +13 -0
- package/dual-datepicker.component.d.ts +17 -11
- package/esm2022/core/date-adapter.mjs +77 -0
- package/esm2022/core/date-clock.mjs +65 -0
- package/esm2022/core/dual-date-range.store.mjs +51 -15
- package/esm2022/core/index.mjs +5 -1
- package/esm2022/core/native-date-adapter.mjs +286 -0
- package/esm2022/core/preset.engine.mjs +154 -60
- package/esm2022/core/system-clock.mjs +34 -0
- package/esm2022/dual-datepicker.component.mjs +239 -195
- package/fesm2022/oneluiz-dual-datepicker.mjs +2470 -1850
- package/fesm2022/oneluiz-dual-datepicker.mjs.map +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Date Adapter Implementation
|
|
3
|
+
*
|
|
4
|
+
* Default adapter using JavaScript Date with timezone-safe operations.
|
|
5
|
+
*
|
|
6
|
+
* Zero dependencies. Conservative implementation that:
|
|
7
|
+
* - Normalizes all dates to start of day (00:00:00.000)
|
|
8
|
+
* - Uses manual YYYY-MM-DD construction (avoids toISOString() timezone shift)
|
|
9
|
+
* - Parses ISO dates to local timezone (avoids UTC interpretation)
|
|
10
|
+
* - Handles month overflow correctly (Jan 31 + 1 month = Feb 28, not Mar 3)
|
|
11
|
+
* - All comparisons work on normalized dates
|
|
12
|
+
*
|
|
13
|
+
* Limitations:
|
|
14
|
+
* - No timezone awareness (all operations in local timezone)
|
|
15
|
+
* - No DST-safe calculations across timezone changes
|
|
16
|
+
* - For advanced timezone needs, use LuxonDateAdapter or DayJSDateAdapter
|
|
17
|
+
*
|
|
18
|
+
* Perfect for:
|
|
19
|
+
* ✅ Most enterprise apps (ERP, POS, BI) where local timezone is sufficient
|
|
20
|
+
* ✅ Applications without cross-timezone requirements
|
|
21
|
+
* ✅ Minimizing bundle size (zero deps)
|
|
22
|
+
* ✅ Simple, predictable date handling
|
|
23
|
+
*/
|
|
24
|
+
import { Injectable } from '@angular/core';
|
|
25
|
+
import * as i0 from "@angular/core";
|
|
26
|
+
export class NativeDateAdapter {
|
|
27
|
+
/**
|
|
28
|
+
* Normalize date to start of day (00:00:00.000) in local timezone
|
|
29
|
+
*
|
|
30
|
+
* This is the foundation of timezone-safe operations.
|
|
31
|
+
* All other methods use normalized dates for comparisons.
|
|
32
|
+
*/
|
|
33
|
+
normalize(date) {
|
|
34
|
+
const normalized = new Date(date);
|
|
35
|
+
normalized.setHours(0, 0, 0, 0);
|
|
36
|
+
return normalized;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if two dates are the same calendar day
|
|
40
|
+
*
|
|
41
|
+
* Implementation: Compare YYYY-MM-DD components directly
|
|
42
|
+
* Avoids timezone issues from valueOf() comparisons
|
|
43
|
+
*/
|
|
44
|
+
isSameDay(a, b) {
|
|
45
|
+
return (a.getFullYear() === b.getFullYear() &&
|
|
46
|
+
a.getMonth() === b.getMonth() &&
|
|
47
|
+
a.getDate() === b.getDate());
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Check if date A is before date B (calendar day level)
|
|
51
|
+
*
|
|
52
|
+
* Implementation: Compare normalized dates using valueOf()
|
|
53
|
+
*/
|
|
54
|
+
isBeforeDay(a, b) {
|
|
55
|
+
return this.normalize(a).valueOf() < this.normalize(b).valueOf();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if date A is after date B (calendar day level)
|
|
59
|
+
*
|
|
60
|
+
* Implementation: Compare normalized dates using valueOf()
|
|
61
|
+
*/
|
|
62
|
+
isAfterDay(a, b) {
|
|
63
|
+
return this.normalize(a).valueOf() > this.normalize(b).valueOf();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Add days to a date
|
|
67
|
+
*
|
|
68
|
+
* Implementation: Use setDate() which handles month rollover automatically
|
|
69
|
+
*
|
|
70
|
+
* Example:
|
|
71
|
+
* Jan 31 + 3 days → Feb 3 ✅
|
|
72
|
+
* Feb 28 + 1 day → Mar 1 ✅ (non-leap year)
|
|
73
|
+
*/
|
|
74
|
+
addDays(date, days) {
|
|
75
|
+
const result = new Date(date);
|
|
76
|
+
result.setDate(result.getDate() + days);
|
|
77
|
+
return this.normalize(result);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Add months to a date
|
|
81
|
+
*
|
|
82
|
+
* CRITICAL: Handles month overflow correctly
|
|
83
|
+
*
|
|
84
|
+
* Algorithm:
|
|
85
|
+
* 1. Add months using setMonth()
|
|
86
|
+
* 2. If day-of-month changed (overflow), set to last day of target month
|
|
87
|
+
*
|
|
88
|
+
* Examples:
|
|
89
|
+
* - Jan 31 + 1 month → Feb 28 (or Feb 29 in leap year) ✅
|
|
90
|
+
* - Jan 31 + 2 months → Mar 31 ✅
|
|
91
|
+
* - Mar 31 + 1 month → Apr 30 ✅
|
|
92
|
+
* - Dec 31 + 1 month → Jan 31 (next year) ✅
|
|
93
|
+
*/
|
|
94
|
+
addMonths(date, months) {
|
|
95
|
+
const result = new Date(date);
|
|
96
|
+
const originalDay = result.getDate();
|
|
97
|
+
// Add months
|
|
98
|
+
result.setMonth(result.getMonth() + months);
|
|
99
|
+
// Check for day overflow (e.g., Jan 31 → Feb 31 becomes Mar 3)
|
|
100
|
+
if (result.getDate() !== originalDay) {
|
|
101
|
+
// Overflow detected: set to last day of target month
|
|
102
|
+
// Go to 1st of next month, then subtract 1 day
|
|
103
|
+
result.setDate(0); // Sets to last day of previous month
|
|
104
|
+
}
|
|
105
|
+
return this.normalize(result);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get start of day (00:00:00.000)
|
|
109
|
+
*
|
|
110
|
+
* Alias for normalize() with explicit intent
|
|
111
|
+
*/
|
|
112
|
+
startOfDay(date) {
|
|
113
|
+
return this.normalize(date);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get end of day (23:59:59.999)
|
|
117
|
+
*
|
|
118
|
+
* Useful for inclusive range queries
|
|
119
|
+
*/
|
|
120
|
+
endOfDay(date) {
|
|
121
|
+
const result = new Date(date);
|
|
122
|
+
result.setHours(23, 59, 59, 999);
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get first day of month (00:00:00.000)
|
|
127
|
+
*/
|
|
128
|
+
startOfMonth(date) {
|
|
129
|
+
const result = new Date(date);
|
|
130
|
+
result.setDate(1);
|
|
131
|
+
return this.normalize(result);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get last day of month (23:59:59.999)
|
|
135
|
+
*
|
|
136
|
+
* Algorithm: Go to 1st of next month, subtract 1 day
|
|
137
|
+
*/
|
|
138
|
+
endOfMonth(date) {
|
|
139
|
+
const result = new Date(date);
|
|
140
|
+
result.setMonth(result.getMonth() + 1, 0); // Day 0 = last day of previous month
|
|
141
|
+
return this.endOfDay(result);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get year (4-digit)
|
|
145
|
+
*/
|
|
146
|
+
getYear(date) {
|
|
147
|
+
return date.getFullYear();
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get month (0-11)
|
|
151
|
+
*/
|
|
152
|
+
getMonth(date) {
|
|
153
|
+
return date.getMonth();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get day of month (1-31)
|
|
157
|
+
*/
|
|
158
|
+
getDate(date) {
|
|
159
|
+
return date.getDate();
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get day of week (0-6, Sunday=0)
|
|
163
|
+
*/
|
|
164
|
+
getDay(date) {
|
|
165
|
+
return date.getDay();
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Convert Date to ISO date string (YYYY-MM-DD)
|
|
169
|
+
*
|
|
170
|
+
* CRITICAL: DO NOT use toISOString() - it converts to UTC!
|
|
171
|
+
*
|
|
172
|
+
* Manual construction ensures local timezone is preserved:
|
|
173
|
+
*
|
|
174
|
+
* Example problem with toISOString():
|
|
175
|
+
* ```
|
|
176
|
+
* // Local timezone: GMT-6 (CST)
|
|
177
|
+
* const date = new Date('2026-02-21T23:00:00'); // 11 PM Feb 21 local
|
|
178
|
+
*
|
|
179
|
+
* // WRONG ❌
|
|
180
|
+
* date.toISOString().split('T')[0]
|
|
181
|
+
* // Returns "2026-02-22" (converted to UTC = Feb 22 05:00 AM)
|
|
182
|
+
*
|
|
183
|
+
* // CORRECT ✅
|
|
184
|
+
* toISODate(date)
|
|
185
|
+
* // Returns "2026-02-21" (local date preserved)
|
|
186
|
+
* ```
|
|
187
|
+
*
|
|
188
|
+
* Implementation: Build YYYY-MM-DD manually from local date components
|
|
189
|
+
*/
|
|
190
|
+
toISODate(date) {
|
|
191
|
+
const year = date.getFullYear();
|
|
192
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
193
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
194
|
+
return `${year}-${month}-${day}`;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Parse ISO date string (YYYY-MM-DD) to Date
|
|
198
|
+
*
|
|
199
|
+
* CRITICAL: DO NOT use new Date(isoString) - may parse as UTC!
|
|
200
|
+
*
|
|
201
|
+
* Example problem with Date constructor:
|
|
202
|
+
* ```
|
|
203
|
+
* // Local timezone: GMT-6 (CST)
|
|
204
|
+
*
|
|
205
|
+
* // WRONG ❌
|
|
206
|
+
* new Date('2026-02-21')
|
|
207
|
+
* // Parsed as UTC: 2026-02-21T00:00:00Z
|
|
208
|
+
* // In local timezone: Feb 20, 2026 6:00 PM (previous day!)
|
|
209
|
+
*
|
|
210
|
+
* // CORRECT ✅
|
|
211
|
+
* parseISODate('2026-02-21')
|
|
212
|
+
* // Returns: 2026-02-21T00:00:00 local time
|
|
213
|
+
* ```
|
|
214
|
+
*
|
|
215
|
+
* Implementation: Parse components and construct Date in local timezone
|
|
216
|
+
*/
|
|
217
|
+
parseISODate(isoDate) {
|
|
218
|
+
if (!isoDate || typeof isoDate !== 'string') {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
// Match YYYY-MM-DD format
|
|
222
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(isoDate.trim());
|
|
223
|
+
if (!match) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
const year = parseInt(match[1], 10);
|
|
227
|
+
const month = parseInt(match[2], 10) - 1; // 0-indexed
|
|
228
|
+
const day = parseInt(match[3], 10);
|
|
229
|
+
// Validate ranges
|
|
230
|
+
if (month < 0 || month > 11) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
if (day < 1 || day > 31) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
// Construct date in local timezone
|
|
237
|
+
const date = new Date(year, month, day);
|
|
238
|
+
// Verify date is valid (e.g., Feb 31 would roll to Mar 3)
|
|
239
|
+
if (date.getFullYear() !== year ||
|
|
240
|
+
date.getMonth() !== month ||
|
|
241
|
+
date.getDate() !== day) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
return this.normalize(date);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Get week start day for locale
|
|
248
|
+
*
|
|
249
|
+
* Default: Sunday (0) for most locales
|
|
250
|
+
* Monday (1) for Europe, ISO 8601
|
|
251
|
+
*
|
|
252
|
+
* Implementation: Simple locale detection
|
|
253
|
+
* For advanced needs, use Intl.Locale or external library
|
|
254
|
+
*/
|
|
255
|
+
getWeekStart(locale) {
|
|
256
|
+
if (!locale) {
|
|
257
|
+
locale = typeof navigator !== 'undefined' ? navigator.language : 'en-US';
|
|
258
|
+
}
|
|
259
|
+
// ISO 8601: Monday start
|
|
260
|
+
const mondayStartLocales = [
|
|
261
|
+
'en-GB', 'en-IE', 'en-AU', 'en-NZ', 'en-CA',
|
|
262
|
+
'es', 'es-ES', 'es-MX',
|
|
263
|
+
'fr', 'fr-FR', 'fr-CA',
|
|
264
|
+
'de', 'de-DE', 'de-AT', 'de-CH',
|
|
265
|
+
'it', 'it-IT',
|
|
266
|
+
'pt', 'pt-PT', 'pt-BR',
|
|
267
|
+
'nl', 'nl-NL', 'nl-BE',
|
|
268
|
+
'ru', 'ru-RU',
|
|
269
|
+
'zh', 'zh-CN', 'zh-TW',
|
|
270
|
+
'ja', 'ja-JP',
|
|
271
|
+
'ko', 'ko-KR'
|
|
272
|
+
];
|
|
273
|
+
const normalizedLocale = locale.toLowerCase();
|
|
274
|
+
const startsWithMonday = mondayStartLocales.some(loc => normalizedLocale.startsWith(loc.toLowerCase()));
|
|
275
|
+
return startsWithMonday ? 1 : 0;
|
|
276
|
+
}
|
|
277
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NativeDateAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
278
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NativeDateAdapter, providedIn: 'root' });
|
|
279
|
+
}
|
|
280
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NativeDateAdapter, decorators: [{
|
|
281
|
+
type: Injectable,
|
|
282
|
+
args: [{
|
|
283
|
+
providedIn: 'root'
|
|
284
|
+
}]
|
|
285
|
+
}] });
|
|
286
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF0aXZlLWRhdGUtYWRhcHRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL25hdGl2ZS1kYXRlLWFkYXB0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FzQkc7QUFFSCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDOztBQU0zQyxNQUFNLE9BQU8saUJBQWlCO0lBQzVCOzs7OztPQUtHO0lBQ0gsU0FBUyxDQUFDLElBQVU7UUFDbEIsTUFBTSxVQUFVLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDbEMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNoQyxPQUFPLFVBQVUsQ0FBQztJQUNwQixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxTQUFTLENBQUMsQ0FBTyxFQUFFLENBQU87UUFDeEIsT0FBTyxDQUNMLENBQUMsQ0FBQyxXQUFXLEVBQUUsS0FBSyxDQUFDLENBQUMsV0FBVyxFQUFFO1lBQ25DLENBQUMsQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLENBQUMsUUFBUSxFQUFFO1lBQzdCLENBQUMsQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQzVCLENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILFdBQVcsQ0FBQyxDQUFPLEVBQUUsQ0FBTztRQUMxQixPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNuRSxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILFVBQVUsQ0FBQyxDQUFPLEVBQUUsQ0FBTztRQUN6QixPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFD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QixJQUFJLEVBQUUsT0FBTztZQUNiLElBQUksRUFBRSxPQUFPO1NBQ2QsQ0FBQztRQUVGLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzlDLE1BQU0sZ0JBQWdCLEdBQUcsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQ3JELGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FDL0MsQ0FBQztRQUVGLE9BQU8sZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xDLENBQUM7d0dBOVJVLGlCQUFpQjs0R0FBakIsaUJBQWlCLGNBRmhCLE1BQU07OzRGQUVQLGlCQUFpQjtrQkFIN0IsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE5hdGl2ZSBEYXRlIEFkYXB0ZXIgSW1wbGVtZW50YXRpb25cbiAqIFxuICogRGVmYXVsdCBhZGFwdGVyIHVzaW5nIEphdmFTY3JpcHQgRGF0ZSB3aXRoIHRpbWV6b25lLXNhZmUgb3BlcmF0aW9ucy5cbiAqIFxuICogWmVybyBkZXBlbmRlbmNpZXMuIENvbnNlcnZhdGl2ZSBpbXBsZW1lbnRhdGlvbiB0aGF0OlxuICogLSBOb3JtYWxpemVzIGFsbCBkYXRlcyB0byBzdGFydCBvZiBkYXkgKDAwOjAwOjAwLjAwMClcbiAqIC0gVXNlcyBtYW51YWwgWVlZWS1NTS1ERCBjb25zdHJ1Y3Rpb24gKGF2b2lkcyB0b0lTT1N0cmluZygpIHRpbWV6b25lIHNoaWZ0KVxuICogLSBQYXJzZXMgSVNPIGRhdGVzIHRvIGxvY2FsIHRpbWV6b25lIChhdm9pZHMgVVRDIGludGVycHJldGF0aW9uKVxuICogLSBIYW5kbGVzIG1vbnRoIG92ZXJmbG93IGNvcnJlY3RseSAoSmFuIDMxICsgMSBtb250aCA9IEZlYiAyOCwgbm90IE1hciAzKVxuICogLSBBbGwgY29tcGFyaXNvbnMgd29yayBvbiBub3JtYWxpemVkIGRhdGVzXG4gKiBcbiAqIExpbWl0YXRpb25zOlxuICogLSBObyB0aW1lem9uZSBhd2FyZW5lc3MgKGFsbCBvcGVyYXRpb25zIGluIGxvY2FsIHRpbWV6b25lKVxuICogLSBObyBEU1Qtc2FmZSBjYWxjdWxhdGlvbnMgYWNyb3NzIHRpbWV6b25lIGNoYW5nZXNcbiAqIC0gRm9yIGFkdmFuY2VkIHRpbWV6b25lIG5lZWRzLCB1c2UgTHV4b25EYXRlQWRhcHRlciBvciBEYXlKU0RhdGVBZGFwdGVyXG4gKiBcbiAqIFBlcmZlY3QgZm9yOlxuICog4pyFIE1vc3QgZW50ZXJwcmlzZSBhcHBzIChFUlAsIFBPUywgQkkpIHdoZXJlIGxvY2FsIHRpbWV6b25lIGlzIHN1ZmZpY2llbnRcbiAqIOKchSBBcHBsaWNhdGlvbnMgd2l0aG91dCBjcm9zcy10aW1lem9uZSByZXF1aXJlbWVudHNcbiAqIOKchSBNaW5pbWl6aW5nIGJ1bmRsZSBzaXplICh6ZXJvIGRlcHMpXG4gKiDinIUgU2ltcGxlLCBwcmVkaWN0YWJsZSBkYXRlIGhhbmRsaW5nXG4gKi9cblxuaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRGF0ZUFkYXB0ZXIgfSBmcm9tICcuL2RhdGUtYWRhcHRlcic7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIE5hdGl2ZURhdGVBZGFwdGVyIGltcGxlbWVudHMgRGF0ZUFkYXB0ZXIge1xuICAvKipcbiAgICogTm9ybWFsaXplIGRhdGUgdG8gc3RhcnQgb2YgZGF5ICgwMDowMDowMC4wMDApIGluIGxvY2FsIHRpbWV6b25lXG4gICAqIFxuICAgKiBUaGlzIGlzIHRoZSBmb3VuZGF0aW9uIG9mIHRpbWV6b25lLXNhZmUgb3BlcmF0aW9ucy5cbiAgICogQWxsIG90aGVyIG1ldGhvZHMgdXNlIG5vcm1hbGl6ZWQgZGF0ZXMgZm9yIGNvbXBhcmlzb25zLlxuICAgKi9cbiAgbm9ybWFsaXplKGRhdGU6IERhdGUpOiBEYXRlIHtcbiAgICBjb25zdCBub3JtYWxpemVkID0gbmV3IERhdGUoZGF0ZSk7XG4gICAgbm9ybWFsaXplZC5zZXRIb3VycygwLCAwLCAwLCAwKTtcbiAgICByZXR1cm4gbm9ybWFsaXplZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiB0d28gZGF0ZXMgYXJlIHRoZSBzYW1lIGNhbGVuZGFyIGRheVxuICAgKiBcbiAgICogSW1wbGVtZW50YXRpb246IENvbXBhcmUgWVlZWS1NTS1ERCBjb21wb25lbnRzIGRpcmVjdGx5XG4gICAqIEF2b2lkcyB0aW1lem9uZSBpc3N1ZXMgZnJvbSB2YWx1ZU9mKCkgY29tcGFyaXNvbnNcbiAgICovXG4gIGlzU2FtZURheShhOiBEYXRlLCBiOiBEYXRlKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIChcbiAgICAgIGEuZ2V0RnVsbFllYXIoKSA9PT0gYi5nZXRGdWxsWWVhcigpICYmXG4gICAgICBhLmdldE1vbnRoKCkgPT09IGIuZ2V0TW9udGgoKSAmJlxuICAgICAgYS5nZXREYXRlKCkgPT09IGIuZ2V0RGF0ZSgpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBkYXRlIEEgaXMgYmVmb3JlIGRhdGUgQiAoY2FsZW5kYXIgZGF5IGxldmVsKVxuICAgKiBcbiAgICogSW1wbGVtZW50YXRpb246IENvbXBhcmUgbm9ybWFsaXplZCBkYXRlcyB1c2luZyB2YWx1ZU9mKClcbiAgICovXG4gIGlzQmVmb3JlRGF5KGE6IERhdGUsIGI6IERhdGUpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5ub3JtYWxpemUoYSkudmFsdWVPZigpIDwgdGhpcy5ub3JtYWxpemUoYikudmFsdWVPZigpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIGRhdGUgQSBpcyBhZnRlciBkYXRlIEIgKGNhbGVuZGFyIGRheSBsZXZlbClcbiAgICogXG4gICAqIEltcGxlbWVudGF0aW9uOiBDb21wYXJlIG5vcm1hbGl6ZWQgZGF0ZXMgdXNpbmcgdmFsdWVPZigpXG4gICAqL1xuICBpc0FmdGVyRGF5KGE6IERhdGUsIGI6IERhdGUpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5ub3JtYWxpemUoYSkudmFsdWVPZigpID4gdGhpcy5ub3JtYWxpemUoYikudmFsdWVPZigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBkYXlzIHRvIGEgZGF0ZVxuICAgKiBcbiAgICogSW1wbGVtZW50YXRpb246IFVzZSBzZXREYXRlKCkgd2hpY2ggaGFuZGxlcyBtb250aCByb2xsb3ZlciBhdXRvbWF0aWNhbGx5XG4gICAqIFxuICAgKiBFeGFtcGxlOlxuICAgKiBKYW4gMzEgKyAzIGRheXMg4oaSIEZlYiAzIOKchVxuICAgKiBGZWIgMjggKyAxIGRheSDihpIgTWFyIDEg4pyFIChub24tbGVhcCB5ZWFyKVxuICAgKi9cbiAgYWRkRGF5cyhkYXRlOiBEYXRlLCBkYXlzOiBudW1iZXIpOiBEYXRlIHtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgRGF0ZShkYXRlKTtcbiAgICByZXN1bHQuc2V0RGF0ZShyZXN1bHQuZ2V0RGF0ZSgpICsgZGF5cyk7XG4gICAgcmV0dXJuIHRoaXMubm9ybWFsaXplKHJlc3VsdCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIG1vbnRocyB0byBhIGRhdGVcbiAgICogXG4gICAqIENSSVRJQ0FMOiBIYW5kbGVzIG1vbnRoIG92ZXJmbG93IGNvcnJlY3RseVxuICAgKiBcbiAgICogQWxnb3JpdGhtOlxuICAgKiAxLiBBZGQgbW9udGhzIHVzaW5nIHNldE1vbnRoKClcbiAgICogMi4gSWYgZGF5LW9mLW1vbnRoIGNoYW5nZWQgKG92ZXJmbG93KSwgc2V0IHRvIGxhc3QgZGF5IG9mIHRhcmdldCBtb250aFxuICAgKiBcbiAgICogRXhhbXBsZXM6XG4gICAqIC0gSmFuIDMxICsgMSBtb250aCDihpIgRmViIDI4IChvciBGZWIgMjkgaW4gbGVhcCB5ZWFyKSDinIVcbiAgICogLSBKYW4gMzEgKyAyIG1vbnRocyDihpIgTWFyIDMxIOKchVxuICAgKiAtIE1hciAzMSArIDEgbW9udGgg4oaSIEFwciAzMCDinIVcbiAgICogLSBEZWMgMzEgKyAxIG1vbnRoIOKGkiBKYW4gMzEgKG5leHQgeWVhcikg4pyFXG4gICAqL1xuICBhZGRNb250aHMoZGF0ZTogRGF0ZSwgbW9udGhzOiBudW1iZXIpOiBEYXRlIHtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgRGF0ZShkYXRlKTtcbiAgICBjb25zdCBvcmlnaW5hbERheSA9IHJlc3VsdC5nZXREYXRlKCk7XG4gICAgXG4gICAgLy8gQWRkIG1vbnRoc1xuICAgIHJlc3VsdC5zZXRNb250aChyZXN1bHQuZ2V0TW9udGgoKSArIG1vbnRocyk7XG4gICAgXG4gICAgLy8gQ2hlY2sgZm9yIGRheSBvdmVyZmxvdyAoZS5nLiwgSmFuIDMxIOKGkiBGZWIgMzEgYmVjb21lcyBNYXIgMylcbiAgICBpZiAocmVzdWx0LmdldERhdGUoKSAhPT0gb3JpZ2luYWxEYXkpIHtcbiAgICAgIC8vIE92ZXJmbG93IGRldGVjdGVkOiBzZXQgdG8gbGFzdCBkYXkgb2YgdGFyZ2V0IG1vbnRoXG4gICAgICAvLyBHbyB0byAxc3Qgb2YgbmV4dCBtb250aCwgdGhlbiBzdWJ0cmFjdCAxIGRheVxuICAgICAgcmVzdWx0LnNldERhdGUoMCk7IC8vIFNldHMgdG8gbGFzdCBkYXkgb2YgcHJldmlvdXMgbW9udGhcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHRoaXMubm9ybWFsaXplKHJlc3VsdCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHN0YXJ0IG9mIGRheSAoMDA6MDA6MDAuMDAwKVxuICAgKiBcbiAgICogQWxpYXMgZm9yIG5vcm1hbGl6ZSgpIHdpdGggZXhwbGljaXQgaW50ZW50XG4gICAqL1xuICBzdGFydE9mRGF5KGRhdGU6IERhdGUpOiBEYXRlIHtcbiAgICByZXR1cm4gdGhpcy5ub3JtYWxpemUoZGF0ZSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGVuZCBvZiBkYXkgKDIzOjU5OjU5Ljk5OSlcbiAgICogXG4gICAqIFVzZWZ1bCBmb3IgaW5jbHVzaXZlIHJhbmdlIHF1ZXJpZXNcbiAgICovXG4gIGVuZE9mRGF5KGRhdGU6IERhdGUpOiBEYXRlIHtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgRGF0ZShkYXRlKTtcbiAgICByZXN1bHQuc2V0SG91cnMoMjMsIDU5LCA1OSwgOTk5KTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBmaXJzdCBkYXkgb2YgbW9udGggKDAwOjAwOjAwLjAwMClcbiAgICovXG4gIHN0YXJ0T2ZNb250aChkYXRlOiBEYXRlKTogRGF0ZSB7XG4gICAgY29uc3QgcmVzdWx0ID0gbmV3IERhdGUoZGF0ZSk7XG4gICAgcmVzdWx0LnNldERhdGUoMSk7XG4gICAgcmV0dXJuIHRoaXMubm9ybWFsaXplKHJlc3VsdCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGxhc3QgZGF5IG9mIG1vbnRoICgyMzo1OTo1OS45OTkpXG4gICAqIFxuICAgKiBBbGdvcml0aG06IEdvIHRvIDFzdCBvZiBuZXh0IG1vbnRoLCBzdWJ0cmFjdCAxIGRheVxuICAgKi9cbiAgZW5kT2ZNb250aChkYXRlOiBEYXRlKTogRGF0ZSB7XG4gICAgY29uc3QgcmVzdWx0ID0gbmV3IERhdGUoZGF0ZSk7XG4gICAgcmVzdWx0LnNldE1vbnRoKHJlc3VsdC5nZXRNb250aCgpICsgMSwgMCk7IC8vIERheSAwID0gbGFzdCBkYXkgb2YgcHJldmlvdXMgbW9udGhcbiAgICByZXR1cm4gdGhpcy5lbmRPZkRheShyZXN1bHQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB5ZWFyICg0LWRpZ2l0KVxuICAgKi9cbiAgZ2V0WWVhcihkYXRlOiBEYXRlKTogbnVtYmVyIHtcbiAgICByZXR1cm4gZGF0ZS5nZXRGdWxsWWVhcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBtb250aCAoMC0xMSlcbiAgICovXG4gIGdldE1vbnRoKGRhdGU6IERhdGUpOiBudW1iZXIge1xuICAgIHJldHVybiBkYXRlLmdldE1vbnRoKCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGRheSBvZiBtb250aCAoMS0zMSlcbiAgICovXG4gIGdldERhdGUoZGF0ZTogRGF0ZSk6IG51bWJlciB7XG4gICAgcmV0dXJuIGRhdGUuZ2V0RGF0ZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBkYXkgb2Ygd2VlayAoMC02LCBTdW5kYXk9MClcbiAgICovXG4gIGdldERheShkYXRlOiBEYXRlKTogbnVtYmVyIHtcbiAgICByZXR1cm4gZGF0ZS5nZXREYXkoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IERhdGUgdG8gSVNPIGRhdGUgc3RyaW5nIChZWVlZLU1NLUREKVxuICAgKiBcbiAgICogQ1JJVElDQUw6IERPIE5PVCB1c2UgdG9JU09TdHJpbmcoKSAtIGl0IGNvbnZlcnRzIHRvIFVUQyFcbiAgICogXG4gICAqIE1hbnVhbCBjb25zdHJ1Y3Rpb24gZW5zdXJlcyBsb2NhbCB0aW1lem9uZSBpcyBwcmVzZXJ2ZWQ6XG4gICAqIFxuICAgKiBFeGFtcGxlIHByb2JsZW0gd2l0aCB0b0lTT1N0cmluZygpOlxuICAgKiBgYGBcbiAgICogLy8gTG9jYWwgdGltZXpvbmU6IEdNVC02IChDU1QpXG4gICAqIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZSgnMjAyNi0wMi0yMVQyMzowMDowMCcpOyAvLyAxMSBQTSBGZWIgMjEgbG9jYWxcbiAgICogXG4gICAqIC8vIFdST05HIOKdjFxuICAgKiBkYXRlLnRvSVNPU3RyaW5nKCkuc3BsaXQoJ1QnKVswXVxuICAgKiAvLyBSZXR1cm5zIFwiMjAyNi0wMi0yMlwiIChjb252ZXJ0ZWQgdG8gVVRDID0gRmViIDIyIDA1OjAwIEFNKVxuICAgKiBcbiAgICogLy8gQ09SUkVDVCDinIVcbiAgICogdG9JU09EYXRlKGRhdGUpXG4gICAqIC8vIFJldHVybnMgXCIyMDI2LTAyLTIxXCIgKGxvY2FsIGRhdGUgcHJlc2VydmVkKVxuICAgKiBgYGBcbiAgICogXG4gICAqIEltcGxlbWVudGF0aW9uOiBCdWlsZCBZWVlZLU1NLUREIG1hbnVhbGx5IGZyb20gbG9jYWwgZGF0ZSBjb21wb25lbnRzXG4gICAqL1xuICB0b0lTT0RhdGUoZGF0ZTogRGF0ZSk6IHN0cmluZyB7XG4gICAgY29uc3QgeWVhciA9IGRhdGUuZ2V0RnVsbFllYXIoKTtcbiAgICBjb25zdCBtb250aCA9IFN0cmluZyhkYXRlLmdldE1vbnRoKCkgKyAxKS5wYWRTdGFydCgyLCAnMCcpO1xuICAgIGNvbnN0IGRheSA9IFN0cmluZyhkYXRlLmdldERhdGUoKSkucGFkU3RhcnQoMiwgJzAnKTtcbiAgICByZXR1cm4gYCR7eWVhcn0tJHttb250aH0tJHtkYXl9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBQYXJzZSBJU08gZGF0ZSBzdHJpbmcgKFlZWVktTU0tREQpIHRvIERhdGVcbiAgICogXG4gICAqIENSSVRJQ0FMOiBETyBOT1QgdXNlIG5ldyBEYXRlKGlzb1N0cmluZykgLSBtYXkgcGFyc2UgYXMgVVRDIVxuICAgKiBcbiAgICogRXhhbXBsZSBwcm9ibGVtIHdpdGggRGF0ZSBjb25zdHJ1Y3RvcjpcbiAgICogYGBgXG4gICAqIC8vIExvY2FsIHRpbWV6b25lOiBHTVQtNiAoQ1NUKVxuICAgKiBcbiAgICogLy8gV1JPTkcg4p2MXG4gICAqIG5ldyBEYXRlKCcyMDI2LTAyLTIxJylcbiAgICogLy8gUGFyc2VkIGFzIFVUQzogMjAyNi0wMi0yMVQwMDowMDowMFpcbiAgICogLy8gSW4gbG9jYWwgdGltZXpvbmU6IEZlYiAyMCwgMjAyNiA2OjAwIFBNIChwcmV2aW91cyBkYXkhKVxuICAgKiBcbiAgICogLy8gQ09SUkVDVCDinIVcbiAgICogcGFyc2VJU09EYXRlKCcyMDI2LTAyLTIxJylcbiAgICogLy8gUmV0dXJuczogMjAyNi0wMi0yMVQwMDowMDowMCBsb2NhbCB0aW1lXG4gICAqIGBgYFxuICAgKiBcbiAgICogSW1wbGVtZW50YXRpb246IFBhcnNlIGNvbXBvbmVudHMgYW5kIGNvbnN0cnVjdCBEYXRlIGluIGxvY2FsIHRpbWV6b25lXG4gICAqL1xuICBwYXJzZUlTT0RhdGUoaXNvRGF0ZTogc3RyaW5nKTogRGF0ZSB8IG51bGwge1xuICAgIGlmICghaXNvRGF0ZSB8fCB0eXBlb2YgaXNvRGF0ZSAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIE1hdGNoIFlZWVktTU0tREQgZm9ybWF0XG4gICAgY29uc3QgbWF0Y2ggPSAvXihcXGR7NH0pLShcXGR7Mn0pLShcXGR7Mn0pJC8uZXhlYyhpc29EYXRlLnRyaW0oKSk7XG4gICAgXG4gICAgaWYgKCFtYXRjaCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgY29uc3QgeWVhciA9IHBhcnNlSW50KG1hdGNoWzFdLCAxMCk7XG4gICAgY29uc3QgbW9udGggPSBwYXJzZUludChtYXRjaFsyXSwgMTApIC0gMTsgLy8gMC1pbmRleGVkXG4gICAgY29uc3QgZGF5ID0gcGFyc2VJbnQobWF0Y2hbM10sIDEwKTtcblxuICAgIC8vIFZhbGlkYXRlIHJhbmdlc1xuICAgIGlmIChtb250aCA8IDAgfHwgbW9udGggPiAxMSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgaWYgKGRheSA8IDEgfHwgZGF5ID4gMzEpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIENvbnN0cnVjdCBkYXRlIGluIGxvY2FsIHRpbWV6b25lXG4gICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHllYXIsIG1vbnRoLCBkYXkpO1xuICAgIFxuICAgIC8vIFZlcmlmeSBkYXRlIGlzIHZhbGlkIChlLmcuLCBGZWIgMzEgd291bGQgcm9sbCB0byBNYXIgMylcbiAgICBpZiAoXG4gICAgICBkYXRlLmdldEZ1bGxZZWFyKCkgIT09IHllYXIgfHxcbiAgICAgIGRhdGUuZ2V0TW9udGgoKSAhPT0gbW9udGggfHxcbiAgICAgIGRhdGUuZ2V0RGF0ZSgpICE9PSBkYXlcbiAgICApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLm5vcm1hbGl6ZShkYXRlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgd2VlayBzdGFydCBkYXkgZm9yIGxvY2FsZVxuICAgKiBcbiAgICogRGVmYXVsdDogU3VuZGF5ICgwKSBmb3IgbW9zdCBsb2NhbGVzXG4gICAqIE1vbmRheSAoMSkgZm9yIEV1cm9wZSwgSVNPIDg2MDFcbiAgICogXG4gICAqIEltcGxlbWVudGF0aW9uOiBTaW1wbGUgbG9jYWxlIGRldGVjdGlvblxuICAgKiBGb3IgYWR2YW5jZWQgbmVlZHMsIHVzZSBJbnRsLkxvY2FsZSBvciBleHRlcm5hbCBsaWJyYXJ5XG4gICAqL1xuICBnZXRXZWVrU3RhcnQobG9jYWxlPzogc3RyaW5nKTogMCB8IDEgfCAyIHwgMyB8IDQgfCA1IHwgNiB7XG4gICAgaWYgKCFsb2NhbGUpIHtcbiAgICAgIGxvY2FsZSA9IHR5cGVvZiBuYXZpZ2F0b3IgIT09ICd1bmRlZmluZWQnID8gbmF2aWdhdG9yLmxhbmd1YWdlIDogJ2VuLVVTJztcbiAgICB9XG5cbiAgICAvLyBJU08gODYwMTogTW9uZGF5IHN0YXJ0XG4gICAgY29uc3QgbW9uZGF5U3RhcnRMb2NhbGVzID0gW1xuICAgICAgJ2VuLUdCJywgJ2VuLUlFJywgJ2VuLUFVJywgJ2VuLU5aJywgJ2VuLUNBJyxcbiAgICAgICdlcycsICdlcy1FUycsICdlcy1NWCcsXG4gICAgICAnZnInLCAnZnItRlInLCAnZnItQ0EnLFxuICAgICAgJ2RlJywgJ2RlLURFJywgJ2RlLUFUJywgJ2RlLUNIJyxcbiAgICAgICdpdCcsICdpdC1JVCcsXG4gICAgICAncHQnLCAncHQtUFQnLCAncHQtQlInLFxuICAgICAgJ25sJywgJ25sLU5MJywgJ25sLUJFJyxcbiAgICAgICdydScsICdydS1SVScsXG4gICAgICAnemgnLCAnemgtQ04nLCAnemgtVFcnLFxuICAgICAgJ2phJywgJ2phLUpQJyxcbiAgICAgICdrbycsICdrby1LUidcbiAgICBdO1xuXG4gICAgY29uc3Qgbm9ybWFsaXplZExvY2FsZSA9IGxvY2FsZS50b0xvd2VyQ2FzZSgpO1xuICAgIGNvbnN0IHN0YXJ0c1dpdGhNb25kYXkgPSBtb25kYXlTdGFydExvY2FsZXMuc29tZShsb2MgPT4gXG4gICAgICBub3JtYWxpemVkTG9jYWxlLnN0YXJ0c1dpdGgobG9jLnRvTG93ZXJDYXNlKCkpXG4gICAgKTtcblxuICAgIHJldHVybiBzdGFydHNXaXRoTW9uZGF5ID8gMSA6IDA7XG4gIH1cbn1cbiJdfQ==
|