@rudderstack/integrations-lib 0.2.32 → 0.2.33
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.
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration options for batch processing operations
|
|
3
|
+
*/
|
|
4
|
+
export interface BatchProcessingDefaults {
|
|
5
|
+
/**
|
|
6
|
+
* Default number of items to process in each batch
|
|
7
|
+
*/
|
|
8
|
+
batchSize?: number;
|
|
9
|
+
/**
|
|
10
|
+
* Default time threshold in milliseconds before yielding control back to the event loop
|
|
11
|
+
*/
|
|
12
|
+
yieldThreshold?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Configure global defaults for batch processing operations
|
|
16
|
+
*
|
|
17
|
+
* @param config - Configuration options for batch processing
|
|
18
|
+
* @returns The current configuration after applying changes
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* // Set both defaults
|
|
23
|
+
* configureBatchProcessingDefaults({ batchSize: 20, yieldThreshold: 5 });
|
|
24
|
+
*
|
|
25
|
+
* // Set only batch size
|
|
26
|
+
* configureBatchProcessingDefaults({ batchSize: 50 });
|
|
27
|
+
*
|
|
28
|
+
* // Get current configuration
|
|
29
|
+
* const currentConfig = configureBatchProcessingDefaults();
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function configureBatchProcessingDefaults(config?: BatchProcessingDefaults): BatchProcessingDefaults;
|
|
33
|
+
/**
|
|
34
|
+
* Maps over an array in batches to avoid blocking the event loop.
|
|
35
|
+
* Processes items in chunks and yields control back to the event loop between batches
|
|
36
|
+
* when the processing time exceeds the threshold.
|
|
37
|
+
*
|
|
38
|
+
* @template T - The type of items in the input array
|
|
39
|
+
* @template R - The type of items in the result array
|
|
40
|
+
* @param items - The array to map over
|
|
41
|
+
* @param mapFn - The mapping function to apply to each item. Receives the item and its index.
|
|
42
|
+
* @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
|
|
43
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
|
|
44
|
+
* @returns A promise that resolves to the mapped array
|
|
45
|
+
* @throws {Error} When batchSize is not a positive integer
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* // Synchronous mapping
|
|
50
|
+
* const doubled = await mapInBatches([1, 2, 3, 4], (x) => x * 2, 2);
|
|
51
|
+
* // Result: [2, 4, 6, 8]
|
|
52
|
+
*
|
|
53
|
+
* // Asynchronous mapping
|
|
54
|
+
* const fetched = await mapInBatches(urls, async (url) => fetch(url), 3);
|
|
55
|
+
*
|
|
56
|
+
* // With index
|
|
57
|
+
* const indexed = await mapInBatches(['a', 'b'], (item, index) => `${item}-${index}`);
|
|
58
|
+
* // Result: ['a-0', 'b-1']
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function mapInBatches<T, R>(items: T[], mapFn: (item: T, index: number) => R | Promise<R>, batchSize?: number, yieldThreshold?: number): Promise<R[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Filters an array in batches to avoid blocking the event loop.
|
|
64
|
+
* Processes items in chunks and yields control back to the event loop between batches
|
|
65
|
+
* when the processing time exceeds the threshold.
|
|
66
|
+
*
|
|
67
|
+
* @template T - The type of items in the array
|
|
68
|
+
* @param items - The array to filter
|
|
69
|
+
* @param predicate - The predicate function to test each item. Receives the item and its index.
|
|
70
|
+
* @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
|
|
71
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
|
|
72
|
+
* @returns A promise that resolves to the filtered array
|
|
73
|
+
* @throws {Error} When batchSize is not a positive integer
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* // Synchronous filtering
|
|
78
|
+
* const evens = await filterInBatches([1, 2, 3, 4, 5], (x) => x % 2 === 0, 2);
|
|
79
|
+
* // Result: [2, 4]
|
|
80
|
+
*
|
|
81
|
+
* // Asynchronous filtering
|
|
82
|
+
* const valid = await filterInBatches(urls, async (url) => {
|
|
83
|
+
* const response = await fetch(url);
|
|
84
|
+
* return response.ok;
|
|
85
|
+
* }, 3);
|
|
86
|
+
*
|
|
87
|
+
* // With index
|
|
88
|
+
* const evenIndices = await filterInBatches(['a', 'b', 'c'], (_, index) => index % 2 === 0);
|
|
89
|
+
* // Result: ['a', 'c']
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare function filterInBatches<T>(items: T[], predicate: (item: T, index: number) => boolean | Promise<boolean>, batchSize?: number, yieldThreshold?: number): Promise<T[]>;
|
|
93
|
+
/**
|
|
94
|
+
* Groups an array by a key function in batches to avoid blocking the event loop.
|
|
95
|
+
* Processes items in chunks and yields control back to the event loop between batches
|
|
96
|
+
* when the processing time exceeds the threshold.
|
|
97
|
+
*
|
|
98
|
+
* @template T - The type of items in the array
|
|
99
|
+
* @template K - The type of the grouping key (must extend PropertyKey)
|
|
100
|
+
* @param items - The array to group
|
|
101
|
+
* @param keyFn - The function to extract the grouping key from each item. Receives the item and its index.
|
|
102
|
+
* @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
|
|
103
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
|
|
104
|
+
* @returns A promise that resolves to an object with grouped items
|
|
105
|
+
* @throws {Error} When batchSize is not a positive integer
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* // Group by property
|
|
110
|
+
* const byType = await groupByInBatches(
|
|
111
|
+
* [{type: 'A', value: 1}, {type: 'B', value: 2}, {type: 'A', value: 3}],
|
|
112
|
+
* (item) => item.type,
|
|
113
|
+
* 2
|
|
114
|
+
* );
|
|
115
|
+
* // Result: {A: [{type: 'A', value: 1}, {type: 'A', value: 3}], B: [{type: 'B', value: 2}]}
|
|
116
|
+
*
|
|
117
|
+
* // Group by computed value
|
|
118
|
+
* const byParity = await groupByInBatches([1, 2, 3, 4], (x) => x % 2 === 0 ? 'even' : 'odd');
|
|
119
|
+
* // Result: {odd: [1, 3], even: [2, 4]}
|
|
120
|
+
*
|
|
121
|
+
* // Asynchronous key function
|
|
122
|
+
* const byCategory = await groupByInBatches(items, async (item) => {
|
|
123
|
+
* return await getCategoryForItem(item);
|
|
124
|
+
* });
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export declare function groupByInBatches<T, K extends PropertyKey>(items: T[], keyFn: (item: T, index: number) => K | Promise<K>, batchSize?: number, yieldThreshold?: number): Promise<Record<K, T[]>>;
|
|
128
|
+
/**
|
|
129
|
+
* Reduces an array in batches to avoid blocking the event loop.
|
|
130
|
+
* Processes items in chunks and yields control back to the event loop between batches
|
|
131
|
+
* when the processing time exceeds the threshold.
|
|
132
|
+
*
|
|
133
|
+
* @template T - The type of items in the array
|
|
134
|
+
* @template R - The type of the accumulator/result
|
|
135
|
+
* @param items - The array to reduce
|
|
136
|
+
* @param reducer - The reducer function. Receives the accumulator, current item, and index.
|
|
137
|
+
* @param initialValue - The initial value for the accumulator
|
|
138
|
+
* @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
|
|
139
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
|
|
140
|
+
* @returns A promise that resolves to the reduced value
|
|
141
|
+
* @throws {Error} When batchSize is not a positive integer
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* // Sum numbers
|
|
146
|
+
* const sum = await reduceInBatches([1, 2, 3, 4], (acc, x) => acc + x, 0, 2);
|
|
147
|
+
* // Result: 10
|
|
148
|
+
*
|
|
149
|
+
* // Concatenate strings
|
|
150
|
+
* const joined = await reduceInBatches(['a', 'b', 'c'], (acc, x) => acc + x, '');
|
|
151
|
+
* // Result: 'abc'
|
|
152
|
+
*
|
|
153
|
+
* // Build object with index
|
|
154
|
+
* const indexed = await reduceInBatches(
|
|
155
|
+
* ['x', 'y'],
|
|
156
|
+
* (acc, item, index) => ({ ...acc, [index]: item }),
|
|
157
|
+
* {}
|
|
158
|
+
* );
|
|
159
|
+
* // Result: {0: 'x', 1: 'y'}
|
|
160
|
+
*
|
|
161
|
+
* // Asynchronous reducer
|
|
162
|
+
* const processed = await reduceInBatches(urls, async (acc, url) => {
|
|
163
|
+
* const data = await fetch(url).then(r => r.json());
|
|
164
|
+
* return [...acc, data];
|
|
165
|
+
* }, []);
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export declare function reduceInBatches<T, R>(items: T[], reducer: (acc: R, item: T, index: number) => R | Promise<R>, initialValue: R, batchSize?: number, yieldThreshold?: number): Promise<R>;
|
|
169
|
+
/**
|
|
170
|
+
* FlatMaps an array in batches to avoid blocking the event loop.
|
|
171
|
+
* Processes items in chunks, flattens the results, and yields control back to the event loop between batches
|
|
172
|
+
* when the processing time exceeds the threshold.
|
|
173
|
+
*
|
|
174
|
+
* @template T - The type of items in the input array
|
|
175
|
+
* @template R - The type of items in the flattened result array
|
|
176
|
+
* @param items - The array to flatMap over
|
|
177
|
+
* @param mapFn - The mapping function that returns an array for each item. Receives the item and its index.
|
|
178
|
+
* @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
|
|
179
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
|
|
180
|
+
* @returns A promise that resolves to the flattened mapped array
|
|
181
|
+
* @throws {Error} When batchSize is not a positive integer
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* // Duplicate each item
|
|
186
|
+
* const duplicated = await flatMapInBatches([1, 2, 3], (x) => [x, x], 2);
|
|
187
|
+
* // Result: [1, 1, 2, 2, 3, 3]
|
|
188
|
+
*
|
|
189
|
+
* // Variable length results
|
|
190
|
+
* const repeated = await flatMapInBatches([1, 2, 3], (x) => Array(x).fill(x));
|
|
191
|
+
* // Result: [1, 2, 2, 3, 3, 3]
|
|
192
|
+
*
|
|
193
|
+
* // Split strings into characters
|
|
194
|
+
* const chars = await flatMapInBatches(['ab', 'cd'], (str) => str.split(''));
|
|
195
|
+
* // Result: ['a', 'b', 'c', 'd']
|
|
196
|
+
*
|
|
197
|
+
* // Asynchronous mapping
|
|
198
|
+
* const expanded = await flatMapInBatches(categories, async (category) => {
|
|
199
|
+
* const items = await fetchItemsForCategory(category);
|
|
200
|
+
* return items;
|
|
201
|
+
* });
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export declare function flatMapInBatches<T, R>(items: T[], mapFn: (item: T, index: number) => R[] | Promise<R[]>, batchSize?: number, yieldThreshold?: number): Promise<R[]>;
|
|
205
|
+
//# sourceMappingURL=batch-processing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-processing.d.ts","sourceRoot":"","sources":["../../src/utils/batch-processing.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gCAAgC,CAC9C,MAAM,CAAC,EAAE,uBAAuB,GAC/B,uBAAuB,CAqBzB;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,CAAC,EAC/B,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACjD,SAAS,SAAmB,EAC5B,cAAc,SAAwB,GACrC,OAAO,CAAC,CAAC,EAAE,CAAC,CAmBd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,KAAK,EAAE,CAAC,EAAE,EACV,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EACjE,SAAS,SAAmB,EAC5B,cAAc,SAAwB,GACrC,OAAO,CAAC,CAAC,EAAE,CAAC,CAqBd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,WAAW,EACvD,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACjD,SAAS,SAAmB,EAC5B,cAAc,SAAwB,GACrC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAiCzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAClC,KAAK,EAAE,CAAC,EAAE,EACV,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC3D,YAAY,EAAE,CAAC,EACf,SAAS,SAAmB,EAC5B,cAAc,SAAwB,GACrC,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EACnC,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,EACrD,SAAS,SAAmB,EAC5B,cAAc,SAAwB,GACrC,OAAO,CAAC,CAAC,EAAE,CAAC,CAoBd"}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configureBatchProcessingDefaults = configureBatchProcessingDefaults;
|
|
4
|
+
exports.mapInBatches = mapInBatches;
|
|
5
|
+
exports.filterInBatches = filterInBatches;
|
|
6
|
+
exports.groupByInBatches = groupByInBatches;
|
|
7
|
+
exports.reduceInBatches = reduceInBatches;
|
|
8
|
+
exports.flatMapInBatches = flatMapInBatches;
|
|
9
|
+
// Default configuration values (internal)
|
|
10
|
+
let defaultBatchSize = 10;
|
|
11
|
+
let defaultYieldThreshold = 10;
|
|
12
|
+
/**
|
|
13
|
+
* Configure global defaults for batch processing operations
|
|
14
|
+
*
|
|
15
|
+
* @param config - Configuration options for batch processing
|
|
16
|
+
* @returns The current configuration after applying changes
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Set both defaults
|
|
21
|
+
* configureBatchProcessingDefaults({ batchSize: 20, yieldThreshold: 5 });
|
|
22
|
+
*
|
|
23
|
+
* // Set only batch size
|
|
24
|
+
* configureBatchProcessingDefaults({ batchSize: 50 });
|
|
25
|
+
*
|
|
26
|
+
* // Get current configuration
|
|
27
|
+
* const currentConfig = configureBatchProcessingDefaults();
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
function configureBatchProcessingDefaults(config) {
|
|
31
|
+
if (config) {
|
|
32
|
+
if (config.batchSize !== undefined) {
|
|
33
|
+
if (!Number.isInteger(config.batchSize) || config.batchSize <= 0) {
|
|
34
|
+
throw new Error('batchSize must be a positive integer');
|
|
35
|
+
}
|
|
36
|
+
defaultBatchSize = config.batchSize;
|
|
37
|
+
}
|
|
38
|
+
if (config.yieldThreshold !== undefined) {
|
|
39
|
+
if (!Number.isInteger(config.yieldThreshold) || config.yieldThreshold < 0) {
|
|
40
|
+
throw new Error('yieldThreshold must be a non-negative integer');
|
|
41
|
+
}
|
|
42
|
+
defaultYieldThreshold = config.yieldThreshold;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
batchSize: defaultBatchSize,
|
|
47
|
+
yieldThreshold: defaultYieldThreshold,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Utility function to defer execution to the next tick of the event loop.
|
|
52
|
+
* This prevents blocking the event loop during heavy batch operations by
|
|
53
|
+
* yielding control back to the event loop using setImmediate.
|
|
54
|
+
*
|
|
55
|
+
* @param startTime - The timestamp when the current batch processing started
|
|
56
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control
|
|
57
|
+
* @returns A promise that resolves to a boolean indicating whether a yield occurred
|
|
58
|
+
* @internal
|
|
59
|
+
*/
|
|
60
|
+
function defer(startTime, yieldThreshold) {
|
|
61
|
+
const elapsed = Date.now() - startTime;
|
|
62
|
+
// Only yield if we've exceeded the threshold
|
|
63
|
+
if (elapsed >= yieldThreshold) {
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
setImmediate(() => resolve(true));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
// Otherwise continue immediately
|
|
69
|
+
return Promise.resolve(false);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Maps over an array in batches to avoid blocking the event loop.
|
|
73
|
+
* Processes items in chunks and yields control back to the event loop between batches
|
|
74
|
+
* when the processing time exceeds the threshold.
|
|
75
|
+
*
|
|
76
|
+
* @template T - The type of items in the input array
|
|
77
|
+
* @template R - The type of items in the result array
|
|
78
|
+
* @param items - The array to map over
|
|
79
|
+
* @param mapFn - The mapping function to apply to each item. Receives the item and its index.
|
|
80
|
+
* @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
|
|
81
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
|
|
82
|
+
* @returns A promise that resolves to the mapped array
|
|
83
|
+
* @throws {Error} When batchSize is not a positive integer
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* // Synchronous mapping
|
|
88
|
+
* const doubled = await mapInBatches([1, 2, 3, 4], (x) => x * 2, 2);
|
|
89
|
+
* // Result: [2, 4, 6, 8]
|
|
90
|
+
*
|
|
91
|
+
* // Asynchronous mapping
|
|
92
|
+
* const fetched = await mapInBatches(urls, async (url) => fetch(url), 3);
|
|
93
|
+
*
|
|
94
|
+
* // With index
|
|
95
|
+
* const indexed = await mapInBatches(['a', 'b'], (item, index) => `${item}-${index}`);
|
|
96
|
+
* // Result: ['a-0', 'b-1']
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
function mapInBatches(items, mapFn, batchSize = defaultBatchSize, yieldThreshold = defaultYieldThreshold) {
|
|
100
|
+
if (!Number.isInteger(batchSize) || batchSize <= 0) {
|
|
101
|
+
throw new Error('batchSize must be a positive integer');
|
|
102
|
+
}
|
|
103
|
+
if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
|
|
104
|
+
throw new Error('yieldThreshold must be a non-negative integer');
|
|
105
|
+
}
|
|
106
|
+
const process = async (i = 0, acc = [], startTime = Date.now()) => {
|
|
107
|
+
if (i >= items.length)
|
|
108
|
+
return acc;
|
|
109
|
+
const batch = items.slice(i, i + batchSize);
|
|
110
|
+
const mapped = await Promise.all(batch.map((item, j) => mapFn(item, i + j)));
|
|
111
|
+
return defer(startTime, yieldThreshold).then((didYield) => process(i + batchSize, acc.concat(mapped), didYield ? Date.now() : startTime));
|
|
112
|
+
};
|
|
113
|
+
return process();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Filters an array in batches to avoid blocking the event loop.
|
|
117
|
+
* Processes items in chunks and yields control back to the event loop between batches
|
|
118
|
+
* when the processing time exceeds the threshold.
|
|
119
|
+
*
|
|
120
|
+
* @template T - The type of items in the array
|
|
121
|
+
* @param items - The array to filter
|
|
122
|
+
* @param predicate - The predicate function to test each item. Receives the item and its index.
|
|
123
|
+
* @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
|
|
124
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
|
|
125
|
+
* @returns A promise that resolves to the filtered array
|
|
126
|
+
* @throws {Error} When batchSize is not a positive integer
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* // Synchronous filtering
|
|
131
|
+
* const evens = await filterInBatches([1, 2, 3, 4, 5], (x) => x % 2 === 0, 2);
|
|
132
|
+
* // Result: [2, 4]
|
|
133
|
+
*
|
|
134
|
+
* // Asynchronous filtering
|
|
135
|
+
* const valid = await filterInBatches(urls, async (url) => {
|
|
136
|
+
* const response = await fetch(url);
|
|
137
|
+
* return response.ok;
|
|
138
|
+
* }, 3);
|
|
139
|
+
*
|
|
140
|
+
* // With index
|
|
141
|
+
* const evenIndices = await filterInBatches(['a', 'b', 'c'], (_, index) => index % 2 === 0);
|
|
142
|
+
* // Result: ['a', 'c']
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
function filterInBatches(items, predicate, batchSize = defaultBatchSize, yieldThreshold = defaultYieldThreshold) {
|
|
146
|
+
if (!Number.isInteger(batchSize) || batchSize <= 0) {
|
|
147
|
+
throw new Error('batchSize must be a positive integer');
|
|
148
|
+
}
|
|
149
|
+
if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
|
|
150
|
+
throw new Error('yieldThreshold must be a non-negative integer');
|
|
151
|
+
}
|
|
152
|
+
const process = async (i = 0, acc = [], startTime = Date.now()) => {
|
|
153
|
+
if (i >= items.length)
|
|
154
|
+
return acc;
|
|
155
|
+
const batch = items.slice(i, i + batchSize);
|
|
156
|
+
const flags = await Promise.all(batch.map((item, j) => predicate(item, i + j)));
|
|
157
|
+
const filtered = batch.filter((_, j) => flags[j]);
|
|
158
|
+
return defer(startTime, yieldThreshold).then((didYield) => process(i + batchSize, acc.concat(filtered), didYield ? Date.now() : startTime));
|
|
159
|
+
};
|
|
160
|
+
return process();
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Groups an array by a key function in batches to avoid blocking the event loop.
|
|
164
|
+
* Processes items in chunks and yields control back to the event loop between batches
|
|
165
|
+
* when the processing time exceeds the threshold.
|
|
166
|
+
*
|
|
167
|
+
* @template T - The type of items in the array
|
|
168
|
+
* @template K - The type of the grouping key (must extend PropertyKey)
|
|
169
|
+
* @param items - The array to group
|
|
170
|
+
* @param keyFn - The function to extract the grouping key from each item. Receives the item and its index.
|
|
171
|
+
* @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
|
|
172
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
|
|
173
|
+
* @returns A promise that resolves to an object with grouped items
|
|
174
|
+
* @throws {Error} When batchSize is not a positive integer
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* // Group by property
|
|
179
|
+
* const byType = await groupByInBatches(
|
|
180
|
+
* [{type: 'A', value: 1}, {type: 'B', value: 2}, {type: 'A', value: 3}],
|
|
181
|
+
* (item) => item.type,
|
|
182
|
+
* 2
|
|
183
|
+
* );
|
|
184
|
+
* // Result: {A: [{type: 'A', value: 1}, {type: 'A', value: 3}], B: [{type: 'B', value: 2}]}
|
|
185
|
+
*
|
|
186
|
+
* // Group by computed value
|
|
187
|
+
* const byParity = await groupByInBatches([1, 2, 3, 4], (x) => x % 2 === 0 ? 'even' : 'odd');
|
|
188
|
+
* // Result: {odd: [1, 3], even: [2, 4]}
|
|
189
|
+
*
|
|
190
|
+
* // Asynchronous key function
|
|
191
|
+
* const byCategory = await groupByInBatches(items, async (item) => {
|
|
192
|
+
* return await getCategoryForItem(item);
|
|
193
|
+
* });
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
function groupByInBatches(items, keyFn, batchSize = defaultBatchSize, yieldThreshold = defaultYieldThreshold) {
|
|
197
|
+
if (!Number.isInteger(batchSize) || batchSize <= 0) {
|
|
198
|
+
throw new Error('batchSize must be a positive integer');
|
|
199
|
+
}
|
|
200
|
+
if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
|
|
201
|
+
throw new Error('yieldThreshold must be a non-negative integer');
|
|
202
|
+
}
|
|
203
|
+
const process = async (i = 0, acc = {}, startTime = Date.now()) => {
|
|
204
|
+
if (i >= items.length)
|
|
205
|
+
return acc;
|
|
206
|
+
const batch = items.slice(i, i + batchSize);
|
|
207
|
+
const keys = await Promise.all(batch.map((item, j) => keyFn(item, i + j)));
|
|
208
|
+
const updated = keys.reduce((res, key, j) => {
|
|
209
|
+
const item = batch[j];
|
|
210
|
+
if (!res[key])
|
|
211
|
+
res[key] = [];
|
|
212
|
+
res[key] = res[key].concat(item);
|
|
213
|
+
return res;
|
|
214
|
+
}, { ...acc });
|
|
215
|
+
return defer(startTime, yieldThreshold).then((didYield) => process(i + batchSize, updated, didYield ? Date.now() : startTime));
|
|
216
|
+
};
|
|
217
|
+
return process();
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Reduces an array in batches to avoid blocking the event loop.
|
|
221
|
+
* Processes items in chunks and yields control back to the event loop between batches
|
|
222
|
+
* when the processing time exceeds the threshold.
|
|
223
|
+
*
|
|
224
|
+
* @template T - The type of items in the array
|
|
225
|
+
* @template R - The type of the accumulator/result
|
|
226
|
+
* @param items - The array to reduce
|
|
227
|
+
* @param reducer - The reducer function. Receives the accumulator, current item, and index.
|
|
228
|
+
* @param initialValue - The initial value for the accumulator
|
|
229
|
+
* @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
|
|
230
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
|
|
231
|
+
* @returns A promise that resolves to the reduced value
|
|
232
|
+
* @throws {Error} When batchSize is not a positive integer
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```typescript
|
|
236
|
+
* // Sum numbers
|
|
237
|
+
* const sum = await reduceInBatches([1, 2, 3, 4], (acc, x) => acc + x, 0, 2);
|
|
238
|
+
* // Result: 10
|
|
239
|
+
*
|
|
240
|
+
* // Concatenate strings
|
|
241
|
+
* const joined = await reduceInBatches(['a', 'b', 'c'], (acc, x) => acc + x, '');
|
|
242
|
+
* // Result: 'abc'
|
|
243
|
+
*
|
|
244
|
+
* // Build object with index
|
|
245
|
+
* const indexed = await reduceInBatches(
|
|
246
|
+
* ['x', 'y'],
|
|
247
|
+
* (acc, item, index) => ({ ...acc, [index]: item }),
|
|
248
|
+
* {}
|
|
249
|
+
* );
|
|
250
|
+
* // Result: {0: 'x', 1: 'y'}
|
|
251
|
+
*
|
|
252
|
+
* // Asynchronous reducer
|
|
253
|
+
* const processed = await reduceInBatches(urls, async (acc, url) => {
|
|
254
|
+
* const data = await fetch(url).then(r => r.json());
|
|
255
|
+
* return [...acc, data];
|
|
256
|
+
* }, []);
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
function reduceInBatches(items, reducer, initialValue, batchSize = defaultBatchSize, yieldThreshold = defaultYieldThreshold) {
|
|
260
|
+
if (!Number.isInteger(batchSize) || batchSize <= 0) {
|
|
261
|
+
throw new Error('batchSize must be a positive integer');
|
|
262
|
+
}
|
|
263
|
+
if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
|
|
264
|
+
throw new Error('yieldThreshold must be a non-negative integer');
|
|
265
|
+
}
|
|
266
|
+
const process = async (i = 0, acc = initialValue, startTime = Date.now()) => {
|
|
267
|
+
if (i >= items.length)
|
|
268
|
+
return acc;
|
|
269
|
+
const batch = items.slice(i, i + batchSize);
|
|
270
|
+
const reduced = await batch.reduce(async (prevAcc, item, j) => {
|
|
271
|
+
const resolvedAcc = await prevAcc;
|
|
272
|
+
return reducer(resolvedAcc, item, i + j);
|
|
273
|
+
}, Promise.resolve(acc));
|
|
274
|
+
return defer(startTime, yieldThreshold).then((didYield) => process(i + batchSize, reduced, didYield ? Date.now() : startTime));
|
|
275
|
+
};
|
|
276
|
+
return process();
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* FlatMaps an array in batches to avoid blocking the event loop.
|
|
280
|
+
* Processes items in chunks, flattens the results, and yields control back to the event loop between batches
|
|
281
|
+
* when the processing time exceeds the threshold.
|
|
282
|
+
*
|
|
283
|
+
* @template T - The type of items in the input array
|
|
284
|
+
* @template R - The type of items in the flattened result array
|
|
285
|
+
* @param items - The array to flatMap over
|
|
286
|
+
* @param mapFn - The mapping function that returns an array for each item. Receives the item and its index.
|
|
287
|
+
* @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
|
|
288
|
+
* @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
|
|
289
|
+
* @returns A promise that resolves to the flattened mapped array
|
|
290
|
+
* @throws {Error} When batchSize is not a positive integer
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```typescript
|
|
294
|
+
* // Duplicate each item
|
|
295
|
+
* const duplicated = await flatMapInBatches([1, 2, 3], (x) => [x, x], 2);
|
|
296
|
+
* // Result: [1, 1, 2, 2, 3, 3]
|
|
297
|
+
*
|
|
298
|
+
* // Variable length results
|
|
299
|
+
* const repeated = await flatMapInBatches([1, 2, 3], (x) => Array(x).fill(x));
|
|
300
|
+
* // Result: [1, 2, 2, 3, 3, 3]
|
|
301
|
+
*
|
|
302
|
+
* // Split strings into characters
|
|
303
|
+
* const chars = await flatMapInBatches(['ab', 'cd'], (str) => str.split(''));
|
|
304
|
+
* // Result: ['a', 'b', 'c', 'd']
|
|
305
|
+
*
|
|
306
|
+
* // Asynchronous mapping
|
|
307
|
+
* const expanded = await flatMapInBatches(categories, async (category) => {
|
|
308
|
+
* const items = await fetchItemsForCategory(category);
|
|
309
|
+
* return items;
|
|
310
|
+
* });
|
|
311
|
+
* ```
|
|
312
|
+
*/
|
|
313
|
+
function flatMapInBatches(items, mapFn, batchSize = defaultBatchSize, yieldThreshold = defaultYieldThreshold) {
|
|
314
|
+
if (!Number.isInteger(batchSize) || batchSize <= 0) {
|
|
315
|
+
throw new Error('batchSize must be a positive integer');
|
|
316
|
+
}
|
|
317
|
+
if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
|
|
318
|
+
throw new Error('yieldThreshold must be a non-negative integer');
|
|
319
|
+
}
|
|
320
|
+
const process = async (i = 0, acc = [], startTime = Date.now()) => {
|
|
321
|
+
if (i >= items.length)
|
|
322
|
+
return acc;
|
|
323
|
+
const batch = items.slice(i, i + batchSize);
|
|
324
|
+
const mapped = await Promise.all(batch.map((item, j) => mapFn(item, i + j)));
|
|
325
|
+
const flattened = mapped.reduce((all, arr) => all.concat(arr), []);
|
|
326
|
+
return defer(startTime, yieldThreshold).then((didYield) => process(i + batchSize, acc.concat(flattened), didYield ? Date.now() : startTime));
|
|
327
|
+
};
|
|
328
|
+
return process();
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmF0Y2gtcHJvY2Vzc2luZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9iYXRjaC1wcm9jZXNzaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBcUNBLDRFQXVCQztBQXNERCxvQ0F3QkM7QUFnQ0QsMENBMEJDO0FBb0NELDRDQXNDQztBQTBDRCwwQ0E0QkM7QUFxQ0QsNENBeUJDO0FBbllELDBDQUEwQztBQUMxQyxJQUFJLGdCQUFnQixHQUFHLEVBQUUsQ0FBQztBQUMxQixJQUFJLHFCQUFxQixHQUFHLEVBQUUsQ0FBQztBQUUvQjs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxTQUFnQixnQ0FBZ0MsQ0FDOUMsTUFBZ0M7SUFFaEMsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUNYLElBQUksTUFBTSxDQUFDLFNBQVMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNuQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLElBQUksTUFBTSxDQUFDLFNBQVMsSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDakUsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO1lBQzFELENBQUM7WUFDRCxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDO1FBQ3RDLENBQUM7UUFFRCxJQUFJLE1BQU0sQ0FBQyxjQUFjLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDeEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxjQUFjLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzFFLE1BQU0sSUFBSSxLQUFLLENBQUMsK0NBQStDLENBQUMsQ0FBQztZQUNuRSxDQUFDO1lBQ0QscUJBQXFCLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQztRQUNoRCxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU87UUFDTCxTQUFTLEVBQUUsZ0JB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TyxFQUFFLENBQUM7QUFDbkIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciBiYXRjaCBwcm9jZXNzaW5nIG9wZXJhdGlvbnNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCYXRjaFByb2Nlc3NpbmdEZWZhdWx0cyB7XG4gIC8qKlxuICAgKiBEZWZhdWx0IG51bWJlciBvZiBpdGVtcyB0byBwcm9jZXNzIGluIGVhY2ggYmF0Y2hcbiAgICovXG4gIGJhdGNoU2l6ZT86IG51bWJlcjtcblxuICAvKipcbiAgICogRGVmYXVsdCB0aW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2wgYmFjayB0byB0aGUgZXZlbnQgbG9vcFxuICAgKi9cbiAgeWllbGRUaHJlc2hvbGQ/OiBudW1iZXI7XG59XG5cbi8vIERlZmF1bHQgY29uZmlndXJhdGlvbiB2YWx1ZXMgKGludGVybmFsKVxubGV0IGRlZmF1bHRCYXRjaFNpemUgPSAxMDtcbmxldCBkZWZhdWx0WWllbGRUaHJlc2hvbGQgPSAxMDtcblxuLyoqXG4gKiBDb25maWd1cmUgZ2xvYmFsIGRlZmF1bHRzIGZvciBiYXRjaCBwcm9jZXNzaW5nIG9wZXJhdGlvbnNcbiAqXG4gKiBAcGFyYW0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciBiYXRjaCBwcm9jZXNzaW5nXG4gKiBAcmV0dXJucyBUaGUgY3VycmVudCBjb25maWd1cmF0aW9uIGFmdGVyIGFwcGx5aW5nIGNoYW5nZXNcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gU2V0IGJvdGggZGVmYXVsdHNcbiAqIGNvbmZpZ3VyZUJhdGNoUHJvY2Vzc2luZ0RlZmF1bHRzKHsgYmF0Y2hTaXplOiAyMCwgeWllbGRUaHJlc2hvbGQ6IDUgfSk7XG4gKlxuICogLy8gU2V0IG9ubHkgYmF0Y2ggc2l6ZVxuICogY29uZmlndXJlQmF0Y2hQcm9jZXNzaW5nRGVmYXVsdHMoeyBiYXRjaFNpemU6IDUwIH0pO1xuICpcbiAqIC8vIEdldCBjdXJyZW50IGNvbmZpZ3VyYXRpb25cbiAqIGNvbnN0IGN1cnJlbnRDb25maWcgPSBjb25maWd1cmVCYXRjaFByb2Nlc3NpbmdEZWZhdWx0cygpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb25maWd1cmVCYXRjaFByb2Nlc3NpbmdEZWZhdWx0cyhcbiAgY29uZmlnPzogQmF0Y2hQcm9jZXNzaW5nRGVmYXVsdHMsXG4pOiBCYXRjaFByb2Nlc3NpbmdEZWZhdWx0cyB7XG4gIGlmIChjb25maWcpIHtcbiAgICBpZiAoY29uZmlnLmJhdGNoU2l6ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBpZiAoIU51bWJlci5pc0ludGVnZXIoY29uZmlnLmJhdGNoU2l6ZSkgfHwgY29uZmlnLmJhdGNoU2l6ZSA8PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignYmF0Y2hTaXplIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyJyk7XG4gICAgICB9XG4gICAgICBkZWZhdWx0QmF0Y2hTaXplID0gY29uZmlnLmJhdGNoU2l6ZTtcbiAgICB9XG5cbiAgICBpZiAoY29uZmlnLnlpZWxkVGhyZXNob2xkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmICghTnVtYmVyLmlzSW50ZWdlcihjb25maWcueWllbGRUaHJlc2hvbGQpIHx8IGNvbmZpZy55aWVsZFRocmVzaG9sZCA8IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd5aWVsZFRocmVzaG9sZCBtdXN0IGJlIGEgbm9uLW5lZ2F0aXZlIGludGVnZXInKTtcbiAgICAgIH1cbiAgICAgIGRlZmF1bHRZaWVsZFRocmVzaG9sZCA9IGNvbmZpZy55aWVsZFRocmVzaG9sZDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIGJhdGNoU2l6ZTogZGVmYXVsdEJhdGNoU2l6ZSxcbiAgICB5aWVsZFRocmVzaG9sZDogZGVmYXVsdFlpZWxkVGhyZXNob2xkLFxuICB9O1xufVxuXG4vKipcbiAqIFV0aWxpdHkgZnVuY3Rpb24gdG8gZGVmZXIgZXhlY3V0aW9uIHRvIHRoZSBuZXh0IHRpY2sgb2YgdGhlIGV2ZW50IGxvb3AuXG4gKiBUaGlzIHByZXZlbnRzIGJsb2NraW5nIHRoZSBldmVudCBsb29wIGR1cmluZyBoZWF2eSBiYXRjaCBvcGVyYXRpb25zIGJ5XG4gKiB5aWVsZGluZyBjb250cm9sIGJhY2sgdG8gdGhlIGV2ZW50IGxvb3AgdXNpbmcgc2V0SW1tZWRpYXRlLlxuICpcbiAqIEBwYXJhbSBzdGFydFRpbWUgLSBUaGUgdGltZXN0YW1wIHdoZW4gdGhlIGN1cnJlbnQgYmF0Y2ggcHJvY2Vzc2luZyBzdGFydGVkXG4gKiBAcGFyYW0geWllbGRUaHJlc2hvbGQgLSBUaW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2xcbiAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgYSB5aWVsZCBvY2N1cnJlZFxuICogQGludGVybmFsXG4gKi9cbmZ1bmN0aW9uIGRlZmVyKHN0YXJ0VGltZTogbnVtYmVyLCB5aWVsZFRocmVzaG9sZDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IGVsYXBzZWQgPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuXG4gIC8vIE9ubHkgeWllbGQgaWYgd2UndmUgZXhjZWVkZWQgdGhlIHRocmVzaG9sZFxuICBpZiAoZWxhcHNlZCA+PSB5aWVsZFRocmVzaG9sZCkge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgc2V0SW1tZWRpYXRlKCgpID0+IHJlc29sdmUodHJ1ZSkpO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gT3RoZXJ3aXNlIGNvbnRpbnVlIGltbWVkaWF0ZWx5XG4gIHJldHVybiBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xufVxuXG4vKipcbiAqIE1hcHMgb3ZlciBhbiBhcnJheSBpbiBiYXRjaGVzIHRvIGF2b2lkIGJsb2NraW5nIHRoZSBldmVudCBsb29wLlxuICogUHJvY2Vzc2VzIGl0ZW1zIGluIGNodW5rcyBhbmQgeWllbGRzIGNvbnRyb2wgYmFjayB0byB0aGUgZXZlbnQgbG9vcCBiZXR3ZWVuIGJhdGNoZXNcbiAqIHdoZW4gdGhlIHByb2Nlc3NpbmcgdGltZSBleGNlZWRzIHRoZSB0aHJlc2hvbGQuXG4gKlxuICogQHRlbXBsYXRlIFQgLSBUaGUgdHlwZSBvZiBpdGVtcyBpbiB0aGUgaW5wdXQgYXJyYXlcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgaXRlbXMgaW4gdGhlIHJlc3VsdCBhcnJheVxuICogQHBhcmFtIGl0ZW1zIC0gVGhlIGFycmF5IHRvIG1hcCBvdmVyXG4gKiBAcGFyYW0gbWFwRm4gLSBUaGUgbWFwcGluZyBmdW5jdGlvbiB0byBhcHBseSB0byBlYWNoIGl0ZW0uIFJlY2VpdmVzIHRoZSBpdGVtIGFuZCBpdHMgaW5kZXguXG4gKiBAcGFyYW0gYmF0Y2hTaXplIC0gVGhlIG51bWJlciBvZiBpdGVtcyB0byBwcm9jZXNzIGluIGVhY2ggYmF0Y2ggKGRlZmF1bHQ6IEBzZWUgZGVmYXVsdEJhdGNoU2l6ZSlcbiAqIEBwYXJhbSB5aWVsZFRocmVzaG9sZCAtIFRpbWUgdGhyZXNob2xkIGluIG1pbGxpc2Vjb25kcyBiZWZvcmUgeWllbGRpbmcgY29udHJvbCAoZGVmYXVsdDogQHNlZSBkZWZhdWx0WWllbGRUaHJlc2hvbGQpXG4gKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgbWFwcGVkIGFycmF5XG4gKiBAdGhyb3dzIHtFcnJvcn0gV2hlbiBiYXRjaFNpemUgaXMgbm90IGEgcG9zaXRpdmUgaW50ZWdlclxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBTeW5jaHJvbm91cyBtYXBwaW5nXG4gKiBjb25zdCBkb3VibGVkID0gYXdhaXQgbWFwSW5CYXRjaGVzKFsxLCAyLCAzLCA0XSwgKHgpID0+IHggKiAyLCAyKTtcbiAqIC8vIFJlc3VsdDogWzIsIDQsIDYsIDhdXG4gKlxuICogLy8gQXN5bmNocm9ub3VzIG1hcHBpbmdcbiAqIGNvbnN0IGZldGNoZWQgPSBhd2FpdCBtYXBJbkJhdGNoZXModXJscywgYXN5bmMgKHVybCkgPT4gZmV0Y2godXJsKSwgMyk7XG4gKlxuICogLy8gV2l0aCBpbmRleFxuICogY29uc3QgaW5kZXhlZCA9IGF3YWl0IG1hcEluQmF0Y2hlcyhbJ2EnLCAnYiddLCAoaXRlbSwgaW5kZXgpID0+IGAke2l0ZW19LSR7aW5kZXh9YCk7XG4gKiAvLyBSZXN1bHQ6IFsnYS0wJywgJ2ItMSddXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hcEluQmF0Y2hlczxULCBSPihcbiAgaXRlbXM6IFRbXSxcbiAgbWFwRm46IChpdGVtOiBULCBpbmRleDogbnVtYmVyKSA9PiBSIHwgUHJvbWlzZTxSPixcbiAgYmF0Y2hTaXplID0gZGVmYXVsdEJhdGNoU2l6ZSxcbiAgeWllbGRUaHJlc2hvbGQgPSBkZWZhdWx0WWllbGRUaHJlc2hvbGQsXG4pOiBQcm9taXNlPFJbXT4ge1xuICBpZiAoIU51bWJlci5pc0ludGVnZXIoYmF0Y2hTaXplKSB8fCBiYXRjaFNpemUgPD0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYmF0Y2hTaXplIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHlpZWxkVGhyZXNob2xkKSB8fCB5aWVsZFRocmVzaG9sZCA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3lpZWxkVGhyZXNob2xkIG11c3QgYmUgYSBub24tbmVnYXRpdmUgaW50ZWdlcicpO1xuICB9XG4gIGNvbnN0IHByb2Nlc3MgPSBhc3luYyAoaSA9IDAsIGFjYzogUltdID0gW10sIHN0YXJ0VGltZSA9IERhdGUubm93KCkpOiBQcm9taXNlPFJbXT4gPT4ge1xuICAgIGlmIChpID49IGl0ZW1zLmxlbmd0aCkgcmV0dXJuIGFjYztcblxuICAgIGNvbnN0IGJhdGNoID0gaXRlbXMuc2xpY2UoaSwgaSArIGJhdGNoU2l6ZSk7XG4gICAgY29uc3QgbWFwcGVkID0gYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2gubWFwKChpdGVtLCBqKSA9PiBtYXBGbihpdGVtLCBpICsgaikpKTtcblxuICAgIHJldHVybiBkZWZlcihzdGFydFRpbWUsIHlpZWxkVGhyZXNob2xkKS50aGVuKChkaWRZaWVsZCkgPT5cbiAgICAgIHByb2Nlc3MoaSArIGJhdGNoU2l6ZSwgYWNjLmNvbmNhdChtYXBwZWQpLCBkaWRZaWVsZCA/IERhdGUubm93KCkgOiBzdGFydFRpbWUpLFxuICAgICk7XG4gIH07XG5cbiAgcmV0dXJuIHByb2Nlc3MoKTtcbn1cblxuLyoqXG4gKiBGaWx0ZXJzIGFuIGFycmF5IGluIGJhdGNoZXMgdG8gYXZvaWQgYmxvY2tpbmcgdGhlIGV2ZW50IGxvb3AuXG4gKiBQcm9jZXNzZXMgaXRlbXMgaW4gY2h1bmtzIGFuZCB5aWVsZHMgY29udHJvbCBiYWNrIHRvIHRoZSBldmVudCBsb29wIGJldHdlZW4gYmF0Y2hlc1xuICogd2hlbiB0aGUgcHJvY2Vzc2luZyB0aW1lIGV4Y2VlZHMgdGhlIHRocmVzaG9sZC5cbiAqXG4gKiBAdGVtcGxhdGUgVCAtIFRoZSB0eXBlIG9mIGl0ZW1zIGluIHRoZSBhcnJheVxuICogQHBhcmFtIGl0ZW1zIC0gVGhlIGFycmF5IHRvIGZpbHRlclxuICogQHBhcmFtIHByZWRpY2F0ZSAtIFRoZSBwcmVkaWNhdGUgZnVuY3Rpb24gdG8gdGVzdCBlYWNoIGl0ZW0uIFJlY2VpdmVzIHRoZSBpdGVtIGFuZCBpdHMgaW5kZXguXG4gKiBAcGFyYW0gYmF0Y2hTaXplIC0gVGhlIG51bWJlciBvZiBpdGVtcyB0byBwcm9jZXNzIGluIGVhY2ggYmF0Y2ggKGRlZmF1bHQ6IEBzZWUgZGVmYXVsdEJhdGNoU2l6ZSlcbiAqIEBwYXJhbSB5aWVsZFRocmVzaG9sZCAtIFRpbWUgdGhyZXNob2xkIGluIG1pbGxpc2Vjb25kcyBiZWZvcmUgeWllbGRpbmcgY29udHJvbCAoZGVmYXVsdDogQHNlZSBkZWZhdWx0WWllbGRUaHJlc2hvbGQpXG4gKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZmlsdGVyZWQgYXJyYXlcbiAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIGJhdGNoU2l6ZSBpcyBub3QgYSBwb3NpdGl2ZSBpbnRlZ2VyXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIFN5bmNocm9ub3VzIGZpbHRlcmluZ1xuICogY29uc3QgZXZlbnMgPSBhd2FpdCBmaWx0ZXJJbkJhdGNoZXMoWzEsIDIsIDMsIDQsIDVdLCAoeCkgPT4geCAlIDIgPT09IDAsIDIpO1xuICogLy8gUmVzdWx0OiBbMiwgNF1cbiAqXG4gKiAvLyBBc3luY2hyb25vdXMgZmlsdGVyaW5nXG4gKiBjb25zdCB2YWxpZCA9IGF3YWl0IGZpbHRlckluQmF0Y2hlcyh1cmxzLCBhc3luYyAodXJsKSA9PiB7XG4gKiAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsKTtcbiAqICAgcmV0dXJuIHJlc3BvbnNlLm9rO1xuICogfSwgMyk7XG4gKlxuICogLy8gV2l0aCBpbmRleFxuICogY29uc3QgZXZlbkluZGljZXMgPSBhd2FpdCBmaWx0ZXJJbkJhdGNoZXMoWydhJywgJ2InLCAnYyddLCAoXywgaW5kZXgpID0+IGluZGV4ICUgMiA9PT0gMCk7XG4gKiAvLyBSZXN1bHQ6IFsnYScsICdjJ11cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gZmlsdGVySW5CYXRjaGVzPFQ+KFxuICBpdGVtczogVFtdLFxuICBwcmVkaWNhdGU6IChpdGVtOiBULCBpbmRleDogbnVtYmVyKSA9PiBib29sZWFuIHwgUHJvbWlzZTxib29sZWFuPixcbiAgYmF0Y2hTaXplID0gZGVmYXVsdEJhdGNoU2l6ZSxcbiAgeWllbGRUaHJlc2hvbGQgPSBkZWZhdWx0WWllbGRUaHJlc2hvbGQsXG4pOiBQcm9taXNlPFRbXT4ge1xuICBpZiAoIU51bWJlci5pc0ludGVnZXIoYmF0Y2hTaXplKSB8fCBiYXRjaFNpemUgPD0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYmF0Y2hTaXplIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHlpZWxkVGhyZXNob2xkKSB8fCB5aWVsZFRocmVzaG9sZCA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3lpZWxkVGhyZXNob2xkIG11c3QgYmUgYSBub24tbmVnYXRpdmUgaW50ZWdlcicpO1xuICB9XG4gIGNvbnN0IHByb2Nlc3MgPSBhc3luYyAoaSA9IDAsIGFjYzogVFtdID0gW10sIHN0YXJ0VGltZSA9IERhdGUubm93KCkpOiBQcm9taXNlPFRbXT4gPT4ge1xuICAgIGlmIChpID49IGl0ZW1zLmxlbmd0aCkgcmV0dXJuIGFjYztcblxuICAgIGNvbnN0IGJhdGNoID0gaXRlbXMuc2xpY2UoaSwgaSArIGJhdGNoU2l6ZSk7XG4gICAgY29uc3QgZmxhZ3MgPSBhd2FpdCBQcm9taXNlLmFsbChiYXRjaC5tYXAoKGl0ZW0sIGopID0+IHByZWRpY2F0ZShpdGVtLCBpICsgaikpKTtcblxuICAgIGNvbnN0IGZpbHRlcmVkID0gYmF0Y2guZmlsdGVyKChfLCBqKSA9PiBmbGFnc1tqXSk7XG5cbiAgICByZXR1cm4gZGVmZXIoc3RhcnRUaW1lLCB5aWVsZFRocmVzaG9sZCkudGhlbigoZGlkWWllbGQpID0+XG4gICAgICBwcm9jZXNzKGkgKyBiYXRjaFNpemUsIGFjYy5jb25jYXQoZmlsdGVyZWQpLCBkaWRZaWVsZCA/IERhdGUubm93KCkgOiBzdGFydFRpbWUpLFxuICAgICk7XG4gIH07XG5cbiAgcmV0dXJuIHByb2Nlc3MoKTtcbn1cblxuLyoqXG4gKiBHcm91cHMgYW4gYXJyYXkgYnkgYSBrZXkgZnVuY3Rpb24gaW4gYmF0Y2hlcyB0byBhdm9pZCBibG9ja2luZyB0aGUgZXZlbnQgbG9vcC5cbiAqIFByb2Nlc3NlcyBpdGVtcyBpbiBjaHVua3MgYW5kIHlpZWxkcyBjb250cm9sIGJhY2sgdG8gdGhlIGV2ZW50IGxvb3AgYmV0d2VlbiBiYXRjaGVzXG4gKiB3aGVuIHRoZSBwcm9jZXNzaW5nIHRpbWUgZXhjZWVkcyB0aGUgdGhyZXNob2xkLlxuICpcbiAqIEB0ZW1wbGF0ZSBUIC0gVGhlIHR5cGUgb2YgaXRlbXMgaW4gdGhlIGFycmF5XG4gKiBAdGVtcGxhdGUgSyAtIFRoZSB0eXBlIG9mIHRoZSBncm91cGluZyBrZXkgKG11c3QgZXh0ZW5kIFByb3BlcnR5S2V5KVxuICogQHBhcmFtIGl0ZW1zIC0gVGhlIGFycmF5IHRvIGdyb3VwXG4gKiBAcGFyYW0ga2V5Rm4gLSBUaGUgZnVuY3Rpb24gdG8gZXh0cmFjdCB0aGUgZ3JvdXBpbmcga2V5IGZyb20gZWFjaCBpdGVtLiBSZWNlaXZlcyB0aGUgaXRlbSBhbmQgaXRzIGluZGV4LlxuICogQHBhcmFtIGJhdGNoU2l6ZSAtIFRoZSBudW1iZXIgb2YgaXRlbXMgdG8gcHJvY2VzcyBpbiBlYWNoIGJhdGNoIChkZWZhdWx0OiBAc2VlIGRlZmF1bHRCYXRjaFNpemUpXG4gKiBAcGFyYW0geWllbGRUaHJlc2hvbGQgLSBUaW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2wgKGRlZmF1bHQ6IEBzZWUgZGVmYXVsdFlpZWxkVGhyZXNob2xkKVxuICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gb2JqZWN0IHdpdGggZ3JvdXBlZCBpdGVtc1xuICogQHRocm93cyB7RXJyb3J9IFdoZW4gYmF0Y2hTaXplIGlzIG5vdCBhIHBvc2l0aXZlIGludGVnZXJcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gR3JvdXAgYnkgcHJvcGVydHlcbiAqIGNvbnN0IGJ5VHlwZSA9IGF3YWl0IGdyb3VwQnlJbkJhdGNoZXMoXG4gKiAgIFt7dHlwZTogJ0EnLCB2YWx1ZTogMX0sIHt0eXBlOiAnQicsIHZhbHVlOiAyfSwge3R5cGU6ICdBJywgdmFsdWU6IDN9XSxcbiAqICAgKGl0ZW0pID0+IGl0ZW0udHlwZSxcbiAqICAgMlxuICogKTtcbiAqIC8vIFJlc3VsdDoge0E6IFt7dHlwZTogJ0EnLCB2YWx1ZTogMX0sIHt0eXBlOiAnQScsIHZhbHVlOiAzfV0sIEI6IFt7dHlwZTogJ0InLCB2YWx1ZTogMn1dfVxuICpcbiAqIC8vIEdyb3VwIGJ5IGNvbXB1dGVkIHZhbHVlXG4gKiBjb25zdCBieVBhcml0eSA9IGF3YWl0IGdyb3VwQnlJbkJhdGNoZXMoWzEsIDIsIDMsIDRdLCAoeCkgPT4geCAlIDIgPT09IDAgPyAnZXZlbicgOiAnb2RkJyk7XG4gKiAvLyBSZXN1bHQ6IHtvZGQ6IFsxLCAzXSwgZXZlbjogWzIsIDRdfVxuICpcbiAqIC8vIEFzeW5jaHJvbm91cyBrZXkgZnVuY3Rpb25cbiAqIGNvbnN0IGJ5Q2F0ZWdvcnkgPSBhd2FpdCBncm91cEJ5SW5CYXRjaGVzKGl0ZW1zLCBhc3luYyAoaXRlbSkgPT4ge1xuICogICByZXR1cm4gYXdhaXQgZ2V0Q2F0ZWdvcnlGb3JJdGVtKGl0ZW0pO1xuICogfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdyb3VwQnlJbkJhdGNoZXM8VCwgSyBleHRlbmRzIFByb3BlcnR5S2V5PihcbiAgaXRlbXM6IFRbXSxcbiAga2V5Rm46IChpdGVtOiBULCBpbmRleDogbnVtYmVyKSA9PiBLIHwgUHJvbWlzZTxLPixcbiAgYmF0Y2hTaXplID0gZGVmYXVsdEJhdGNoU2l6ZSxcbiAgeWllbGRUaHJlc2hvbGQgPSBkZWZhdWx0WWllbGRUaHJlc2hvbGQsXG4pOiBQcm9taXNlPFJlY29yZDxLLCBUW10+PiB7XG4gIGlmICghTnVtYmVyLmlzSW50ZWdlcihiYXRjaFNpemUpIHx8IGJhdGNoU2l6ZSA8PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdiYXRjaFNpemUgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXInKTtcbiAgfVxuICBpZiAoIU51bWJlci5pc0ludGVnZXIoeWllbGRUaHJlc2hvbGQpIHx8IHlpZWxkVGhyZXNob2xkIDwgMCkge1xuICAgIHRocm93IG5ldyBFcnJvcigneWllbGRUaHJlc2hvbGQgbXVzdCBiZSBhIG5vbi1uZWdhdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgY29uc3QgcHJvY2VzcyA9IGFzeW5jIChcbiAgICBpID0gMCxcbiAgICBhY2M6IFJlY29yZDxLLCBUW10+ID0ge30gYXMgUmVjb3JkPEssIFRbXT4sXG4gICAgc3RhcnRUaW1lID0gRGF0ZS5ub3coKSxcbiAgKTogUHJvbWlzZTxSZWNvcmQ8SywgVFtdPj4gPT4ge1xuICAgIGlmIChpID49IGl0ZW1zLmxlbmd0aCkgcmV0dXJuIGFjYztcblxuICAgIGNvbnN0IGJhdGNoID0gaXRlbXMuc2xpY2UoaSwgaSArIGJhdGNoU2l6ZSk7XG4gICAgY29uc3Qga2V5cyA9IGF3YWl0IFByb21pc2UuYWxsKGJhdGNoLm1hcCgoaXRlbSwgaikgPT4ga2V5Rm4oaXRlbSwgaSArIGopKSk7XG5cbiAgICBjb25zdCB1cGRhdGVkID0ga2V5cy5yZWR1Y2UoXG4gICAgICAocmVzLCBrZXksIGopID0+IHtcbiAgICAgICAgY29uc3QgaXRlbSA9IGJhdGNoW2pdO1xuICAgICAgICBpZiAoIXJlc1trZXldKSByZXNba2V5XSA9IFtdO1xuICAgICAgICByZXNba2V5XSA9IHJlc1trZXldLmNvbmNhdChpdGVtKTtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgIH0sXG4gICAgICB7IC4uLmFjYyB9LFxuICAgICk7XG5cbiAgICByZXR1cm4gZGVmZXIoc3RhcnRUaW1lLCB5aWVsZFRocmVzaG9sZCkudGhlbigoZGlkWWllbGQpID0+XG4gICAgICBwcm9jZXNzKGkgKyBiYXRjaFNpemUsIHVwZGF0ZWQsIGRpZFlpZWxkID8gRGF0ZS5ub3coKSA6IHN0YXJ0VGltZSksXG4gICAgKTtcbiAgfTtcblxuICByZXR1cm4gcHJvY2VzcygpO1xufVxuXG4vKipcbiAqIFJlZHVjZXMgYW4gYXJyYXkgaW4gYmF0Y2hlcyB0byBhdm9pZCBibG9ja2luZyB0aGUgZXZlbnQgbG9vcC5cbiAqIFByb2Nlc3NlcyBpdGVtcyBpbiBjaHVua3MgYW5kIHlpZWxkcyBjb250cm9sIGJhY2sgdG8gdGhlIGV2ZW50IGxvb3AgYmV0d2VlbiBiYXRjaGVzXG4gKiB3aGVuIHRoZSBwcm9jZXNzaW5nIHRpbWUgZXhjZWVkcyB0aGUgdGhyZXNob2xkLlxuICpcbiAqIEB0ZW1wbGF0ZSBUIC0gVGhlIHR5cGUgb2YgaXRlbXMgaW4gdGhlIGFycmF5XG4gKiBAdGVtcGxhdGUgUiAtIFRoZSB0eXBlIG9mIHRoZSBhY2N1bXVsYXRvci9yZXN1bHRcbiAqIEBwYXJhbSBpdGVtcyAtIFRoZSBhcnJheSB0byByZWR1Y2VcbiAqIEBwYXJhbSByZWR1Y2VyIC0gVGhlIHJlZHVjZXIgZnVuY3Rpb24uIFJlY2VpdmVzIHRoZSBhY2N1bXVsYXRvciwgY3VycmVudCBpdGVtLCBhbmQgaW5kZXguXG4gKiBAcGFyYW0gaW5pdGlhbFZhbHVlIC0gVGhlIGluaXRpYWwgdmFsdWUgZm9yIHRoZSBhY2N1bXVsYXRvclxuICogQHBhcmFtIGJhdGNoU2l6ZSAtIFRoZSBudW1iZXIgb2YgaXRlbXMgdG8gcHJvY2VzcyBpbiBlYWNoIGJhdGNoIChkZWZhdWx0OiBAc2VlIGRlZmF1bHRCYXRjaFNpemUpXG4gKiBAcGFyYW0geWllbGRUaHJlc2hvbGQgLSBUaW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2wgKGRlZmF1bHQ6IEBzZWUgZGVmYXVsdFlpZWxkVGhyZXNob2xkKVxuICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlZHVjZWQgdmFsdWVcbiAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIGJhdGNoU2l6ZSBpcyBub3QgYSBwb3NpdGl2ZSBpbnRlZ2VyXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIFN1bSBudW1iZXJzXG4gKiBjb25zdCBzdW0gPSBhd2FpdCByZWR1Y2VJbkJhdGNoZXMoWzEsIDIsIDMsIDRdLCAoYWNjLCB4KSA9PiBhY2MgKyB4LCAwLCAyKTtcbiAqIC8vIFJlc3VsdDogMTBcbiAqXG4gKiAvLyBDb25jYXRlbmF0ZSBzdHJpbmdzXG4gKiBjb25zdCBqb2luZWQgPSBhd2FpdCByZWR1Y2VJbkJhdGNoZXMoWydhJywgJ2InLCAnYyddLCAoYWNjLCB4KSA9PiBhY2MgKyB4LCAnJyk7XG4gKiAvLyBSZXN1bHQ6ICdhYmMnXG4gKlxuICogLy8gQnVpbGQgb2JqZWN0IHdpdGggaW5kZXhcbiAqIGNvbnN0IGluZGV4ZWQgPSBhd2FpdCByZWR1Y2VJbkJhdGNoZXMoXG4gKiAgIFsneCcsICd5J10sXG4gKiAgIChhY2MsIGl0ZW0sIGluZGV4KSA9PiAoeyAuLi5hY2MsIFtpbmRleF06IGl0ZW0gfSksXG4gKiAgIHt9XG4gKiApO1xuICogLy8gUmVzdWx0OiB7MDogJ3gnLCAxOiAneSd9XG4gKlxuICogLy8gQXN5bmNocm9ub3VzIHJlZHVjZXJcbiAqIGNvbnN0IHByb2Nlc3NlZCA9IGF3YWl0IHJlZHVjZUluQmF0Y2hlcyh1cmxzLCBhc3luYyAoYWNjLCB1cmwpID0+IHtcbiAqICAgY29uc3QgZGF0YSA9IGF3YWl0IGZldGNoKHVybCkudGhlbihyID0+IHIuanNvbigpKTtcbiAqICAgcmV0dXJuIFsuLi5hY2MsIGRhdGFdO1xuICogfSwgW10pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWR1Y2VJbkJhdGNoZXM8VCwgUj4oXG4gIGl0ZW1zOiBUW10sXG4gIHJlZHVjZXI6IChhY2M6IFIsIGl0ZW06IFQsIGluZGV4OiBudW1iZXIpID0+IFIgfCBQcm9taXNlPFI+LFxuICBpbml0aWFsVmFsdWU6IFIsXG4gIGJhdGNoU2l6ZSA9IGRlZmF1bHRCYXRjaFNpemUsXG4gIHlpZWxkVGhyZXNob2xkID0gZGVmYXVsdFlpZWxkVGhyZXNob2xkLFxuKTogUHJvbWlzZTxSPiB7XG4gIGlmICghTnVtYmVyLmlzSW50ZWdlcihiYXRjaFNpemUpIHx8IGJhdGNoU2l6ZSA8PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdiYXRjaFNpemUgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXInKTtcbiAgfVxuICBpZiAoIU51bWJlci5pc0ludGVnZXIoeWllbGRUaHJlc2hvbGQpIHx8IHlpZWxkVGhyZXNob2xkIDwgMCkge1xuICAgIHRocm93IG5ldyBFcnJvcigneWllbGRUaHJlc2hvbGQgbXVzdCBiZSBhIG5vbi1uZWdhdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgY29uc3QgcHJvY2VzcyA9IGFzeW5jIChpID0gMCwgYWNjOiBSID0gaW5pdGlhbFZhbHVlLCBzdGFydFRpbWUgPSBEYXRlLm5vdygpKTogUHJvbWlzZTxSPiA9PiB7XG4gICAgaWYgKGkgPj0gaXRlbXMubGVuZ3RoKSByZXR1cm4gYWNjO1xuXG4gICAgY29uc3QgYmF0Y2ggPSBpdGVtcy5zbGljZShpLCBpICsgYmF0Y2hTaXplKTtcbiAgICBjb25zdCByZWR1Y2VkID0gYXdhaXQgYmF0Y2gucmVkdWNlPFByb21pc2U8Uj4+KGFzeW5jIChwcmV2QWNjLCBpdGVtLCBqKSA9PiB7XG4gICAgICBjb25zdCByZXNvbHZlZEFjYyA9IGF3YWl0IHByZXZBY2M7XG4gICAgICByZXR1cm4gcmVkdWNlcihyZXNvbHZlZEFjYywgaXRlbSwgaSArIGopO1xuICAgIH0sIFByb21pc2UucmVzb2x2ZShhY2MpKTtcblxuICAgIHJldHVybiBkZWZlcihzdGFydFRpbWUsIHlpZWxkVGhyZXNob2xkKS50aGVuKChkaWRZaWVsZCkgPT5cbiAgICAgIHByb2Nlc3MoaSArIGJhdGNoU2l6ZSwgcmVkdWNlZCwgZGlkWWllbGQgPyBEYXRlLm5vdygpIDogc3RhcnRUaW1lKSxcbiAgICApO1xuICB9O1xuXG4gIHJldHVybiBwcm9jZXNzKCk7XG59XG5cbi8qKlxuICogRmxhdE1hcHMgYW4gYXJyYXkgaW4gYmF0Y2hlcyB0byBhdm9pZCBibG9ja2luZyB0aGUgZXZlbnQgbG9vcC5cbiAqIFByb2Nlc3NlcyBpdGVtcyBpbiBjaHVua3MsIGZsYXR0ZW5zIHRoZSByZXN1bHRzLCBhbmQgeWllbGRzIGNvbnRyb2wgYmFjayB0byB0aGUgZXZlbnQgbG9vcCBiZXR3ZWVuIGJhdGNoZXNcbiAqIHdoZW4gdGhlIHByb2Nlc3NpbmcgdGltZSBleGNlZWRzIHRoZSB0aHJlc2hvbGQuXG4gKlxuICogQHRlbXBsYXRlIFQgLSBUaGUgdHlwZSBvZiBpdGVtcyBpbiB0aGUgaW5wdXQgYXJyYXlcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgaXRlbXMgaW4gdGhlIGZsYXR0ZW5lZCByZXN1bHQgYXJyYXlcbiAqIEBwYXJhbSBpdGVtcyAtIFRoZSBhcnJheSB0byBmbGF0TWFwIG92ZXJcbiAqIEBwYXJhbSBtYXBGbiAtIFRoZSBtYXBwaW5nIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBhcnJheSBmb3IgZWFjaCBpdGVtLiBSZWNlaXZlcyB0aGUgaXRlbSBhbmQgaXRzIGluZGV4LlxuICogQHBhcmFtIGJhdGNoU2l6ZSAtIFRoZSBudW1iZXIgb2YgaXRlbXMgdG8gcHJvY2VzcyBpbiBlYWNoIGJhdGNoIChkZWZhdWx0OiBAc2VlIGRlZmF1bHRCYXRjaFNpemUpXG4gKiBAcGFyYW0geWllbGRUaHJlc2hvbGQgLSBUaW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2wgKGRlZmF1bHQ6IEBzZWUgZGVmYXVsdFlpZWxkVGhyZXNob2xkKVxuICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGZsYXR0ZW5lZCBtYXBwZWQgYXJyYXlcbiAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIGJhdGNoU2l6ZSBpcyBub3QgYSBwb3NpdGl2ZSBpbnRlZ2VyXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIER1cGxpY2F0ZSBlYWNoIGl0ZW1cbiAqIGNvbnN0IGR1cGxpY2F0ZWQgPSBhd2FpdCBmbGF0TWFwSW5CYXRjaGVzKFsxLCAyLCAzXSwgKHgpID0+IFt4LCB4XSwgMik7XG4gKiAvLyBSZXN1bHQ6IFsxLCAxLCAyLCAyLCAzLCAzXVxuICpcbiAqIC8vIFZhcmlhYmxlIGxlbmd0aCByZXN1bHRzXG4gKiBjb25zdCByZXBlYXRlZCA9IGF3YWl0IGZsYXRNYXBJbkJhdGNoZXMoWzEsIDIsIDNdLCAoeCkgPT4gQXJyYXkoeCkuZmlsbCh4KSk7XG4gKiAvLyBSZXN1bHQ6IFsxLCAyLCAyLCAzLCAzLCAzXVxuICpcbiAqIC8vIFNwbGl0IHN0cmluZ3MgaW50byBjaGFyYWN0ZXJzXG4gKiBjb25zdCBjaGFycyA9IGF3YWl0IGZsYXRNYXBJbkJhdGNoZXMoWydhYicsICdjZCddLCAoc3RyKSA9PiBzdHIuc3BsaXQoJycpKTtcbiAqIC8vIFJlc3VsdDogWydhJywgJ2InLCAnYycsICdkJ11cbiAqXG4gKiAvLyBBc3luY2hyb25vdXMgbWFwcGluZ1xuICogY29uc3QgZXhwYW5kZWQgPSBhd2FpdCBmbGF0TWFwSW5CYXRjaGVzKGNhdGVnb3JpZXMsIGFzeW5jIChjYXRlZ29yeSkgPT4ge1xuICogICBjb25zdCBpdGVtcyA9IGF3YWl0IGZldGNoSXRlbXNGb3JDYXRlZ29yeShjYXRlZ29yeSk7XG4gKiAgIHJldHVybiBpdGVtcztcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmbGF0TWFwSW5CYXRjaGVzPFQsIFI+KFxuICBpdGVtczogVFtdLFxuICBtYXBGbjogKGl0ZW06IFQsIGluZGV4OiBudW1iZXIpID0+IFJbXSB8IFByb21pc2U8UltdPixcbiAgYmF0Y2hTaXplID0gZGVmYXVsdEJhdGNoU2l6ZSxcbiAgeWllbGRUaHJlc2hvbGQgPSBkZWZhdWx0WWllbGRUaHJlc2hvbGQsXG4pOiBQcm9taXNlPFJbXT4ge1xuICBpZiAoIU51bWJlci5pc0ludGVnZXIoYmF0Y2hTaXplKSB8fCBiYXRjaFNpemUgPD0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYmF0Y2hTaXplIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHlpZWxkVGhyZXNob2xkKSB8fCB5aWVsZFRocmVzaG9sZCA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3lpZWxkVGhyZXNob2xkIG11c3QgYmUgYSBub24tbmVnYXRpdmUgaW50ZWdlcicpO1xuICB9XG4gIGNvbnN0IHByb2Nlc3MgPSBhc3luYyAoaSA9IDAsIGFjYzogUltdID0gW10sIHN0YXJ0VGltZSA9IERhdGUubm93KCkpOiBQcm9taXNlPFJbXT4gPT4ge1xuICAgIGlmIChpID49IGl0ZW1zLmxlbmd0aCkgcmV0dXJuIGFjYztcblxuICAgIGNvbnN0IGJhdGNoID0gaXRlbXMuc2xpY2UoaSwgaSArIGJhdGNoU2l6ZSk7XG4gICAgY29uc3QgbWFwcGVkID0gYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2gubWFwKChpdGVtLCBqKSA9PiBtYXBGbihpdGVtLCBpICsgaikpKTtcbiAgICBjb25zdCBmbGF0dGVuZWQgPSBtYXBwZWQucmVkdWNlKChhbGwsIGFycikgPT4gYWxsLmNvbmNhdChhcnIpLCBbXSk7XG5cbiAgICByZXR1cm4gZGVmZXIoc3RhcnRUaW1lLCB5aWVsZFRocmVzaG9sZCkudGhlbigoZGlkWWllbGQpID0+XG4gICAgICBwcm9jZXNzKGkgKyBiYXRjaFNpemUsIGFjYy5jb25jYXQoZmxhdHRlbmVkKSwgZGlkWWllbGQgPyBEYXRlLm5vdygpIDogc3RhcnRUaW1lKSxcbiAgICApO1xuICB9O1xuXG4gIHJldHVybiBwcm9jZXNzKCk7XG59XG4iXX0=
|
package/build/utils/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"}
|
package/build/utils/index.js
CHANGED
|
@@ -14,9 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./batch-processing"), exports);
|
|
17
18
|
__exportStar(require("./json-schema-generator"), exports);
|
|
18
19
|
__exportStar(require("./misc"), exports);
|
|
19
20
|
__exportStar(require("./request"), exports);
|
|
20
21
|
__exportStar(require("./tests"), exports);
|
|
21
22
|
__exportStar(require("./zod"), exports);
|
|
22
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
23
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHFEQUFtQztBQUNuQywwREFBd0M7QUFDeEMseUNBQXVCO0FBQ3ZCLDRDQUEwQjtBQUMxQiwwQ0FBd0I7QUFDeEIsd0NBQXNCIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9iYXRjaC1wcm9jZXNzaW5nJztcbmV4cG9ydCAqIGZyb20gJy4vanNvbi1zY2hlbWEtZ2VuZXJhdG9yJztcbmV4cG9ydCAqIGZyb20gJy4vbWlzYyc7XG5leHBvcnQgKiBmcm9tICcuL3JlcXVlc3QnO1xuZXhwb3J0ICogZnJvbSAnLi90ZXN0cyc7XG5leHBvcnQgKiBmcm9tICcuL3pvZCc7XG4iXX0=
|