@ngrx/data 13.0.0-beta.0 → 13.0.0-rc.0
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/{esm2015/index.js → esm2020/index.mjs} +0 -0
- package/{esm2015/ngrx-data.js → esm2020/ngrx-data.mjs} +0 -0
- package/{esm2015/public_api.js → esm2020/public_api.mjs} +0 -0
- package/esm2020/src/actions/entity-action-factory.mjs +50 -0
- package/{esm2015/src/actions/entity-action-guard.js → esm2020/src/actions/entity-action-guard.mjs} +0 -0
- package/{esm2015/src/actions/entity-action-operators.js → esm2020/src/actions/entity-action-operators.mjs} +0 -0
- package/{esm2015/src/actions/entity-action.js → esm2020/src/actions/entity-action.mjs} +0 -0
- package/esm2020/src/actions/entity-cache-action.mjs +116 -0
- package/esm2020/src/actions/entity-cache-change-set.mjs +50 -0
- package/{esm2015/src/actions/entity-op.js → esm2020/src/actions/entity-op.mjs} +0 -0
- package/{esm2015/src/actions/merge-strategy.js → esm2020/src/actions/merge-strategy.mjs} +0 -0
- package/{esm2015/src/actions/update-response-data.js → esm2020/src/actions/update-response-data.mjs} +0 -0
- package/{esm2015/src/dataservices/data-service-error.js → esm2020/src/dataservices/data-service-error.mjs} +0 -0
- package/{esm2015/src/dataservices/default-data-service-config.js → esm2020/src/dataservices/default-data-service-config.mjs} +0 -0
- package/{esm2015/src/dataservices/default-data.service.js → esm2020/src/dataservices/default-data.service.mjs} +4 -4
- package/esm2020/src/dataservices/entity-cache-data.service.mjs +146 -0
- package/esm2020/src/dataservices/entity-data.service.mjs +63 -0
- package/esm2020/src/dataservices/http-url-generator.mjs +86 -0
- package/{esm2015/src/dataservices/interfaces.js → esm2020/src/dataservices/interfaces.mjs} +0 -0
- package/{esm2015/src/dataservices/persistence-result-handler.service.js → esm2020/src/dataservices/persistence-result-handler.service.mjs} +4 -4
- package/esm2020/src/dispatchers/entity-cache-dispatcher.mjs +163 -0
- package/{esm2015/src/dispatchers/entity-commands.js → esm2020/src/dispatchers/entity-commands.mjs} +0 -0
- package/esm2020/src/dispatchers/entity-dispatcher-base.mjs +405 -0
- package/{esm2015/src/dispatchers/entity-dispatcher-default-options.js → esm2020/src/dispatchers/entity-dispatcher-default-options.mjs} +4 -4
- package/esm2020/src/dispatchers/entity-dispatcher-factory.mjs +65 -0
- package/{esm2015/src/dispatchers/entity-dispatcher.js → esm2020/src/dispatchers/entity-dispatcher.mjs} +0 -0
- package/esm2020/src/effects/entity-cache-effects.mjs +115 -0
- package/{esm2015/src/effects/entity-effects-scheduler.js → esm2020/src/effects/entity-effects-scheduler.mjs} +0 -0
- package/esm2020/src/effects/entity-effects.mjs +148 -0
- package/{esm2015/src/entity-data-without-effects.module.js → esm2020/src/entity-data-without-effects.module.mjs} +5 -5
- package/{esm2015/src/entity-data.module.js → esm2020/src/entity-data.module.mjs} +5 -5
- package/esm2020/src/entity-metadata/entity-definition.mjs +33 -0
- package/esm2020/src/entity-metadata/entity-definition.service.mjs +93 -0
- package/{esm2015/src/entity-metadata/entity-filters.js → esm2020/src/entity-metadata/entity-filters.mjs} +0 -0
- package/{esm2015/src/entity-metadata/entity-metadata.js → esm2020/src/entity-metadata/entity-metadata.mjs} +0 -0
- package/{esm2015/src/entity-services/entity-collection-service-base.js → esm2020/src/entity-services/entity-collection-service-base.mjs} +0 -0
- package/{esm2015/src/entity-services/entity-collection-service-elements-factory.js → esm2020/src/entity-services/entity-collection-service-elements-factory.mjs} +4 -4
- package/{esm2015/src/entity-services/entity-collection-service-factory.js → esm2020/src/entity-services/entity-collection-service-factory.mjs} +4 -4
- package/{esm2015/src/entity-services/entity-collection-service.js → esm2020/src/entity-services/entity-collection-service.mjs} +0 -0
- package/{esm2015/src/entity-services/entity-services-base.js → esm2020/src/entity-services/entity-services-base.mjs} +4 -4
- package/{esm2015/src/entity-services/entity-services-elements.js → esm2020/src/entity-services/entity-services-elements.mjs} +4 -4
- package/{esm2015/src/entity-services/entity-services.js → esm2020/src/entity-services/entity-services.mjs} +0 -0
- package/{esm2015/src/index.js → esm2020/src/index.mjs} +0 -0
- package/{esm2015/src/reducers/constants.js → esm2020/src/reducers/constants.mjs} +0 -0
- package/esm2020/src/reducers/entity-cache-reducer.mjs +271 -0
- package/{esm2015/src/reducers/entity-cache.js → esm2020/src/reducers/entity-cache.mjs} +0 -0
- package/esm2020/src/reducers/entity-change-tracker-base.mjs +587 -0
- package/{esm2015/src/reducers/entity-change-tracker.js → esm2020/src/reducers/entity-change-tracker.mjs} +0 -0
- package/{esm2015/src/reducers/entity-collection-creator.js → esm2020/src/reducers/entity-collection-creator.mjs} +4 -4
- package/esm2020/src/reducers/entity-collection-reducer-methods.mjs +806 -0
- package/{esm2015/src/reducers/entity-collection-reducer-registry.js → esm2020/src/reducers/entity-collection-reducer-registry.mjs} +4 -4
- package/{esm2015/src/reducers/entity-collection-reducer.js → esm2020/src/reducers/entity-collection-reducer.mjs} +4 -4
- package/{esm2015/src/reducers/entity-collection.js → esm2020/src/reducers/entity-collection.mjs} +0 -0
- package/{esm2015/src/selectors/entity-cache-selector.js → esm2020/src/selectors/entity-cache-selector.mjs} +0 -0
- package/{esm2015/src/selectors/entity-selectors$.js → esm2020/src/selectors/entity-selectors$.mjs} +4 -4
- package/esm2020/src/selectors/entity-selectors.mjs +96 -0
- package/{esm2015/src/utils/correlation-id-generator.js → esm2020/src/utils/correlation-id-generator.mjs} +4 -4
- package/{esm2015/src/utils/default-logger.js → esm2020/src/utils/default-logger.mjs} +4 -4
- package/{esm2015/src/utils/default-pluralizer.js → esm2020/src/utils/default-pluralizer.mjs} +5 -5
- package/{esm2015/src/utils/guid-fns.js → esm2020/src/utils/guid-fns.mjs} +0 -0
- package/{esm2015/src/utils/interfaces.js → esm2020/src/utils/interfaces.mjs} +0 -0
- package/{esm2015/src/utils/utilities.js → esm2020/src/utils/utilities.mjs} +0 -0
- package/fesm2015/{ngrx-data.js → ngrx-data.mjs} +194 -169
- package/fesm2015/ngrx-data.mjs.map +1 -0
- package/fesm2020/ngrx-data.mjs +4936 -0
- package/fesm2020/ngrx-data.mjs.map +1 -0
- package/package.json +26 -13
- package/schematics/ng-add/index.js +29 -25
- package/schematics/ng-add/index.js.map +1 -1
- package/schematics-core/utility/angular-utils.js +6 -5
- package/schematics-core/utility/angular-utils.js.map +1 -1
- package/schematics-core/utility/ast-utils.js +12 -8
- package/schematics-core/utility/ast-utils.js.map +1 -1
- package/schematics-core/utility/find-component.js +12 -12
- package/schematics-core/utility/find-component.js.map +1 -1
- package/schematics-core/utility/find-module.js +12 -12
- package/schematics-core/utility/find-module.js.map +1 -1
- package/schematics-core/utility/json-utilts.js.map +1 -1
- package/schematics-core/utility/ngrx-utils.js +16 -12
- package/schematics-core/utility/ngrx-utils.js.map +1 -1
- package/schematics-core/utility/parse-name.js +3 -3
- package/schematics-core/utility/parse-name.js.map +1 -1
- package/schematics-core/utility/project.js +1 -1
- package/schematics-core/utility/project.js.map +1 -1
- package/schematics-core/utility/visitors.js +2 -2
- package/schematics-core/utility/visitors.js.map +1 -1
- package/bundles/ngrx-data.umd.js +0 -5491
- package/bundles/ngrx-data.umd.js.map +0 -1
- package/esm2015/src/actions/entity-action-factory.js +0 -46
- package/esm2015/src/actions/entity-cache-action.js +0 -116
- package/esm2015/src/actions/entity-cache-change-set.js +0 -50
- package/esm2015/src/dataservices/entity-cache-data.service.js +0 -140
- package/esm2015/src/dataservices/entity-data.service.js +0 -63
- package/esm2015/src/dataservices/http-url-generator.js +0 -83
- package/esm2015/src/dispatchers/entity-cache-dispatcher.js +0 -163
- package/esm2015/src/dispatchers/entity-dispatcher-base.js +0 -401
- package/esm2015/src/dispatchers/entity-dispatcher-factory.js +0 -62
- package/esm2015/src/effects/entity-cache-effects.js +0 -115
- package/esm2015/src/effects/entity-effects.js +0 -148
- package/esm2015/src/entity-metadata/entity-definition.js +0 -26
- package/esm2015/src/entity-metadata/entity-definition.service.js +0 -93
- package/esm2015/src/reducers/entity-cache-reducer.js +0 -271
- package/esm2015/src/reducers/entity-change-tracker-base.js +0 -575
- package/esm2015/src/reducers/entity-collection-reducer-methods.js +0 -784
- package/esm2015/src/selectors/entity-selectors.js +0 -89
- package/fesm2015/ngrx-data.js.map +0 -1
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
import { ChangeType } from './entity-collection';
|
|
2
|
+
import { defaultSelectId } from '../utils/utilities';
|
|
3
|
+
import { MergeStrategy } from '../actions/merge-strategy';
|
|
4
|
+
/**
|
|
5
|
+
* The default implementation of EntityChangeTracker with
|
|
6
|
+
* methods for tracking, committing, and reverting/undoing unsaved entity changes.
|
|
7
|
+
* Used by EntityCollectionReducerMethods which should call tracker methods BEFORE modifying the collection.
|
|
8
|
+
* See EntityChangeTracker docs.
|
|
9
|
+
*/
|
|
10
|
+
export class EntityChangeTrackerBase {
|
|
11
|
+
constructor(adapter, selectId) {
|
|
12
|
+
this.adapter = adapter;
|
|
13
|
+
this.selectId = selectId;
|
|
14
|
+
/** Extract the primary key (id); default to `id` */
|
|
15
|
+
this.selectId = selectId || defaultSelectId;
|
|
16
|
+
}
|
|
17
|
+
// #region commit methods
|
|
18
|
+
/**
|
|
19
|
+
* Commit all changes as when the collection has been completely reloaded from the server.
|
|
20
|
+
* Harmless when there are no entity changes to commit.
|
|
21
|
+
* @param collection The entity collection
|
|
22
|
+
*/
|
|
23
|
+
commitAll(collection) {
|
|
24
|
+
return Object.keys(collection.changeState).length === 0
|
|
25
|
+
? collection
|
|
26
|
+
: { ...collection, changeState: {} };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Commit changes for the given entities as when they have been refreshed from the server.
|
|
30
|
+
* Harmless when there are no entity changes to commit.
|
|
31
|
+
* @param entityOrIdList The entities to clear tracking or their ids.
|
|
32
|
+
* @param collection The entity collection
|
|
33
|
+
*/
|
|
34
|
+
commitMany(entityOrIdList, collection) {
|
|
35
|
+
if (entityOrIdList == null || entityOrIdList.length === 0) {
|
|
36
|
+
return collection; // nothing to commit
|
|
37
|
+
}
|
|
38
|
+
let didMutate = false;
|
|
39
|
+
const changeState = entityOrIdList.reduce((chgState, entityOrId) => {
|
|
40
|
+
const id = typeof entityOrId === 'object'
|
|
41
|
+
? this.selectId(entityOrId)
|
|
42
|
+
: entityOrId;
|
|
43
|
+
if (chgState[id]) {
|
|
44
|
+
if (!didMutate) {
|
|
45
|
+
chgState = { ...chgState };
|
|
46
|
+
didMutate = true;
|
|
47
|
+
}
|
|
48
|
+
delete chgState[id];
|
|
49
|
+
}
|
|
50
|
+
return chgState;
|
|
51
|
+
}, collection.changeState);
|
|
52
|
+
return didMutate ? { ...collection, changeState } : collection;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Commit changes for the given entity as when it have been refreshed from the server.
|
|
56
|
+
* Harmless when no entity changes to commit.
|
|
57
|
+
* @param entityOrId The entity to clear tracking or its id.
|
|
58
|
+
* @param collection The entity collection
|
|
59
|
+
*/
|
|
60
|
+
commitOne(entityOrId, collection) {
|
|
61
|
+
return entityOrId == null
|
|
62
|
+
? collection
|
|
63
|
+
: this.commitMany([entityOrId], collection);
|
|
64
|
+
}
|
|
65
|
+
// #endregion commit methods
|
|
66
|
+
// #region merge query
|
|
67
|
+
/**
|
|
68
|
+
* Merge query results into the collection, adjusting the ChangeState per the mergeStrategy.
|
|
69
|
+
* @param entities Entities returned from querying the server.
|
|
70
|
+
* @param collection The entity collection
|
|
71
|
+
* @param [mergeStrategy] How to merge a queried entity when the corresponding entity in the collection has an unsaved change.
|
|
72
|
+
* Defaults to MergeStrategy.PreserveChanges.
|
|
73
|
+
* @returns The merged EntityCollection.
|
|
74
|
+
*/
|
|
75
|
+
mergeQueryResults(entities, collection, mergeStrategy) {
|
|
76
|
+
return this.mergeServerUpserts(entities, collection, MergeStrategy.PreserveChanges, mergeStrategy);
|
|
77
|
+
}
|
|
78
|
+
// #endregion merge query results
|
|
79
|
+
// #region merge save results
|
|
80
|
+
/**
|
|
81
|
+
* Merge result of saving new entities into the collection, adjusting the ChangeState per the mergeStrategy.
|
|
82
|
+
* The default is MergeStrategy.OverwriteChanges.
|
|
83
|
+
* @param entities Entities returned from saving new entities to the server.
|
|
84
|
+
* @param collection The entity collection
|
|
85
|
+
* @param [mergeStrategy] How to merge a saved entity when the corresponding entity in the collection has an unsaved change.
|
|
86
|
+
* Defaults to MergeStrategy.OverwriteChanges.
|
|
87
|
+
* @returns The merged EntityCollection.
|
|
88
|
+
*/
|
|
89
|
+
mergeSaveAdds(entities, collection, mergeStrategy) {
|
|
90
|
+
return this.mergeServerUpserts(entities, collection, MergeStrategy.OverwriteChanges, mergeStrategy);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Merge successful result of deleting entities on the server that have the given primary keys
|
|
94
|
+
* Clears the entity changeState for those keys unless the MergeStrategy is ignoreChanges.
|
|
95
|
+
* @param entities keys primary keys of the entities to remove/delete.
|
|
96
|
+
* @param collection The entity collection
|
|
97
|
+
* @param [mergeStrategy] How to adjust change tracking when the corresponding entity in the collection has an unsaved change.
|
|
98
|
+
* Defaults to MergeStrategy.OverwriteChanges.
|
|
99
|
+
* @returns The merged EntityCollection.
|
|
100
|
+
*/
|
|
101
|
+
mergeSaveDeletes(keys, collection, mergeStrategy) {
|
|
102
|
+
mergeStrategy =
|
|
103
|
+
mergeStrategy == null ? MergeStrategy.OverwriteChanges : mergeStrategy;
|
|
104
|
+
// same logic for all non-ignore merge strategies: always clear (commit) the changes
|
|
105
|
+
const deleteIds = keys; // make TypeScript happy
|
|
106
|
+
collection =
|
|
107
|
+
mergeStrategy === MergeStrategy.IgnoreChanges
|
|
108
|
+
? collection
|
|
109
|
+
: this.commitMany(deleteIds, collection);
|
|
110
|
+
return this.adapter.removeMany(deleteIds, collection);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Merge result of saving updated entities into the collection, adjusting the ChangeState per the mergeStrategy.
|
|
114
|
+
* The default is MergeStrategy.OverwriteChanges.
|
|
115
|
+
* @param updateResponseData Entity response data returned from saving updated entities to the server.
|
|
116
|
+
* @param collection The entity collection
|
|
117
|
+
* @param [mergeStrategy] How to merge a saved entity when the corresponding entity in the collection has an unsaved change.
|
|
118
|
+
* Defaults to MergeStrategy.OverwriteChanges.
|
|
119
|
+
* @param [skipUnchanged] True means skip update if server didn't change it. False by default.
|
|
120
|
+
* If the update was optimistic and the server didn't make more changes of its own
|
|
121
|
+
* then the updates are already in the collection and shouldn't make them again.
|
|
122
|
+
* @returns The merged EntityCollection.
|
|
123
|
+
*/
|
|
124
|
+
mergeSaveUpdates(updateResponseData, collection, mergeStrategy, skipUnchanged = false) {
|
|
125
|
+
if (updateResponseData == null || updateResponseData.length === 0) {
|
|
126
|
+
return collection; // nothing to merge.
|
|
127
|
+
}
|
|
128
|
+
let didMutate = false;
|
|
129
|
+
let changeState = collection.changeState;
|
|
130
|
+
mergeStrategy =
|
|
131
|
+
mergeStrategy == null ? MergeStrategy.OverwriteChanges : mergeStrategy;
|
|
132
|
+
let updates;
|
|
133
|
+
switch (mergeStrategy) {
|
|
134
|
+
case MergeStrategy.IgnoreChanges:
|
|
135
|
+
updates = filterChanged(updateResponseData);
|
|
136
|
+
return this.adapter.updateMany(updates, collection);
|
|
137
|
+
case MergeStrategy.OverwriteChanges:
|
|
138
|
+
changeState = updateResponseData.reduce((chgState, update) => {
|
|
139
|
+
const oldId = update.id;
|
|
140
|
+
const change = chgState[oldId];
|
|
141
|
+
if (change) {
|
|
142
|
+
if (!didMutate) {
|
|
143
|
+
chgState = { ...chgState };
|
|
144
|
+
didMutate = true;
|
|
145
|
+
}
|
|
146
|
+
delete chgState[oldId];
|
|
147
|
+
}
|
|
148
|
+
return chgState;
|
|
149
|
+
}, collection.changeState);
|
|
150
|
+
collection = didMutate ? { ...collection, changeState } : collection;
|
|
151
|
+
updates = filterChanged(updateResponseData);
|
|
152
|
+
return this.adapter.updateMany(updates, collection);
|
|
153
|
+
case MergeStrategy.PreserveChanges: {
|
|
154
|
+
const updateableEntities = [];
|
|
155
|
+
changeState = updateResponseData.reduce((chgState, update) => {
|
|
156
|
+
const oldId = update.id;
|
|
157
|
+
const change = chgState[oldId];
|
|
158
|
+
if (change) {
|
|
159
|
+
// Tracking a change so update original value but not the current value
|
|
160
|
+
if (!didMutate) {
|
|
161
|
+
chgState = { ...chgState };
|
|
162
|
+
didMutate = true;
|
|
163
|
+
}
|
|
164
|
+
const newId = this.selectId(update.changes);
|
|
165
|
+
const oldChangeState = change;
|
|
166
|
+
// If the server changed the id, register the new "originalValue" under the new id
|
|
167
|
+
// and remove the change tracked under the old id.
|
|
168
|
+
if (newId !== oldId) {
|
|
169
|
+
delete chgState[oldId];
|
|
170
|
+
}
|
|
171
|
+
const newOrigValue = {
|
|
172
|
+
...oldChangeState.originalValue,
|
|
173
|
+
...update.changes,
|
|
174
|
+
};
|
|
175
|
+
chgState[newId] = {
|
|
176
|
+
...oldChangeState,
|
|
177
|
+
originalValue: newOrigValue,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
updateableEntities.push(update);
|
|
182
|
+
}
|
|
183
|
+
return chgState;
|
|
184
|
+
}, collection.changeState);
|
|
185
|
+
collection = didMutate ? { ...collection, changeState } : collection;
|
|
186
|
+
updates = filterChanged(updateableEntities);
|
|
187
|
+
return this.adapter.updateMany(updates, collection);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Conditionally keep only those updates that have additional server changes.
|
|
192
|
+
* (e.g., for optimistic saves because they updates are already in the current collection)
|
|
193
|
+
* Strip off the `changed` property.
|
|
194
|
+
* @responseData Entity response data from server.
|
|
195
|
+
* May be an UpdateResponseData<T>, a subclass of Update<T> with a 'changed' flag.
|
|
196
|
+
* @returns Update<T> (without the changed flag)
|
|
197
|
+
*/
|
|
198
|
+
function filterChanged(responseData) {
|
|
199
|
+
if (skipUnchanged === true) {
|
|
200
|
+
// keep only those updates that the server changed (knowable if is UpdateResponseData<T>)
|
|
201
|
+
responseData = responseData.filter((r) => r.changed === true);
|
|
202
|
+
}
|
|
203
|
+
// Strip unchanged property from responseData, leaving just the pure Update<T>
|
|
204
|
+
// TODO: Remove? probably not necessary as the Update isn't stored and adapter will ignore `changed`.
|
|
205
|
+
return responseData.map((r) => ({ id: r.id, changes: r.changes }));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Merge result of saving upserted entities into the collection, adjusting the ChangeState per the mergeStrategy.
|
|
210
|
+
* The default is MergeStrategy.OverwriteChanges.
|
|
211
|
+
* @param entities Entities returned from saving upserts to the server.
|
|
212
|
+
* @param collection The entity collection
|
|
213
|
+
* @param [mergeStrategy] How to merge a saved entity when the corresponding entity in the collection has an unsaved change.
|
|
214
|
+
* Defaults to MergeStrategy.OverwriteChanges.
|
|
215
|
+
* @returns The merged EntityCollection.
|
|
216
|
+
*/
|
|
217
|
+
mergeSaveUpserts(entities, collection, mergeStrategy) {
|
|
218
|
+
return this.mergeServerUpserts(entities, collection, MergeStrategy.OverwriteChanges, mergeStrategy);
|
|
219
|
+
}
|
|
220
|
+
// #endregion merge save results
|
|
221
|
+
// #region query & save helpers
|
|
222
|
+
/**
|
|
223
|
+
*
|
|
224
|
+
* @param entities Entities to merge
|
|
225
|
+
* @param collection Collection into which entities are merged
|
|
226
|
+
* @param defaultMergeStrategy How to merge when action's MergeStrategy is unspecified
|
|
227
|
+
* @param [mergeStrategy] The action's MergeStrategy
|
|
228
|
+
*/
|
|
229
|
+
mergeServerUpserts(entities, collection, defaultMergeStrategy, mergeStrategy) {
|
|
230
|
+
if (entities == null || entities.length === 0) {
|
|
231
|
+
return collection; // nothing to merge.
|
|
232
|
+
}
|
|
233
|
+
let didMutate = false;
|
|
234
|
+
let changeState = collection.changeState;
|
|
235
|
+
mergeStrategy =
|
|
236
|
+
mergeStrategy == null ? defaultMergeStrategy : mergeStrategy;
|
|
237
|
+
switch (mergeStrategy) {
|
|
238
|
+
case MergeStrategy.IgnoreChanges:
|
|
239
|
+
return this.adapter.upsertMany(entities, collection);
|
|
240
|
+
case MergeStrategy.OverwriteChanges:
|
|
241
|
+
collection = this.adapter.upsertMany(entities, collection);
|
|
242
|
+
changeState = entities.reduce((chgState, entity) => {
|
|
243
|
+
const id = this.selectId(entity);
|
|
244
|
+
const change = chgState[id];
|
|
245
|
+
if (change) {
|
|
246
|
+
if (!didMutate) {
|
|
247
|
+
chgState = { ...chgState };
|
|
248
|
+
didMutate = true;
|
|
249
|
+
}
|
|
250
|
+
delete chgState[id];
|
|
251
|
+
}
|
|
252
|
+
return chgState;
|
|
253
|
+
}, collection.changeState);
|
|
254
|
+
return didMutate ? { ...collection, changeState } : collection;
|
|
255
|
+
case MergeStrategy.PreserveChanges: {
|
|
256
|
+
const upsertEntities = [];
|
|
257
|
+
changeState = entities.reduce((chgState, entity) => {
|
|
258
|
+
const id = this.selectId(entity);
|
|
259
|
+
const change = chgState[id];
|
|
260
|
+
if (change) {
|
|
261
|
+
if (!didMutate) {
|
|
262
|
+
chgState = {
|
|
263
|
+
...chgState,
|
|
264
|
+
[id]: {
|
|
265
|
+
...chgState[id],
|
|
266
|
+
originalValue: entity,
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
didMutate = true;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
upsertEntities.push(entity);
|
|
274
|
+
}
|
|
275
|
+
return chgState;
|
|
276
|
+
}, collection.changeState);
|
|
277
|
+
collection = this.adapter.upsertMany(upsertEntities, collection);
|
|
278
|
+
return didMutate ? { ...collection, changeState } : collection;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// #endregion query & save helpers
|
|
283
|
+
// #region track methods
|
|
284
|
+
/**
|
|
285
|
+
* Track multiple entities before adding them to the collection.
|
|
286
|
+
* Does NOT add to the collection (the reducer's job).
|
|
287
|
+
* @param entities The entities to add. They must all have their ids.
|
|
288
|
+
* @param collection The entity collection
|
|
289
|
+
* @param [mergeStrategy] Track by default. Don't track if is MergeStrategy.IgnoreChanges.
|
|
290
|
+
*/
|
|
291
|
+
trackAddMany(entities, collection, mergeStrategy) {
|
|
292
|
+
if (mergeStrategy === MergeStrategy.IgnoreChanges ||
|
|
293
|
+
entities == null ||
|
|
294
|
+
entities.length === 0) {
|
|
295
|
+
return collection; // nothing to track
|
|
296
|
+
}
|
|
297
|
+
let didMutate = false;
|
|
298
|
+
const changeState = entities.reduce((chgState, entity) => {
|
|
299
|
+
const id = this.selectId(entity);
|
|
300
|
+
if (id == null || id === '') {
|
|
301
|
+
throw new Error(`${collection.entityName} entity add requires a key to be tracked`);
|
|
302
|
+
}
|
|
303
|
+
const trackedChange = chgState[id];
|
|
304
|
+
if (!trackedChange) {
|
|
305
|
+
if (!didMutate) {
|
|
306
|
+
didMutate = true;
|
|
307
|
+
chgState = { ...chgState };
|
|
308
|
+
}
|
|
309
|
+
chgState[id] = { changeType: ChangeType.Added };
|
|
310
|
+
}
|
|
311
|
+
return chgState;
|
|
312
|
+
}, collection.changeState);
|
|
313
|
+
return didMutate ? { ...collection, changeState } : collection;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Track an entity before adding it to the collection.
|
|
317
|
+
* Does NOT add to the collection (the reducer's job).
|
|
318
|
+
* @param entity The entity to add. It must have an id.
|
|
319
|
+
* @param collection The entity collection
|
|
320
|
+
* @param [mergeStrategy] Track by default. Don't track if is MergeStrategy.IgnoreChanges.
|
|
321
|
+
* If not specified, implementation supplies a default strategy.
|
|
322
|
+
*/
|
|
323
|
+
trackAddOne(entity, collection, mergeStrategy) {
|
|
324
|
+
return entity == null
|
|
325
|
+
? collection
|
|
326
|
+
: this.trackAddMany([entity], collection, mergeStrategy);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Track multiple entities before removing them with the intention of deleting them on the server.
|
|
330
|
+
* Does NOT remove from the collection (the reducer's job).
|
|
331
|
+
* @param keys The primary keys of the entities to delete.
|
|
332
|
+
* @param collection The entity collection
|
|
333
|
+
* @param [mergeStrategy] Track by default. Don't track if is MergeStrategy.IgnoreChanges.
|
|
334
|
+
*/
|
|
335
|
+
trackDeleteMany(keys, collection, mergeStrategy) {
|
|
336
|
+
if (mergeStrategy === MergeStrategy.IgnoreChanges ||
|
|
337
|
+
keys == null ||
|
|
338
|
+
keys.length === 0) {
|
|
339
|
+
return collection; // nothing to track
|
|
340
|
+
}
|
|
341
|
+
let didMutate = false;
|
|
342
|
+
const entityMap = collection.entities;
|
|
343
|
+
const changeState = keys.reduce((chgState, id) => {
|
|
344
|
+
const originalValue = entityMap[id];
|
|
345
|
+
if (originalValue) {
|
|
346
|
+
const trackedChange = chgState[id];
|
|
347
|
+
if (trackedChange) {
|
|
348
|
+
if (trackedChange.changeType === ChangeType.Added) {
|
|
349
|
+
// Special case: stop tracking an added entity that you delete
|
|
350
|
+
// The caller must also detect this, remove it immediately from the collection
|
|
351
|
+
// and skip attempt to delete on the server.
|
|
352
|
+
cloneChgStateOnce();
|
|
353
|
+
delete chgState[id];
|
|
354
|
+
}
|
|
355
|
+
else if (trackedChange.changeType === ChangeType.Updated) {
|
|
356
|
+
// Special case: switch change type from Updated to Deleted.
|
|
357
|
+
cloneChgStateOnce();
|
|
358
|
+
chgState[id] = { ...chgState[id], changeType: ChangeType.Deleted };
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
// Start tracking this entity
|
|
363
|
+
cloneChgStateOnce();
|
|
364
|
+
chgState[id] = { changeType: ChangeType.Deleted, originalValue };
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return chgState;
|
|
368
|
+
function cloneChgStateOnce() {
|
|
369
|
+
if (!didMutate) {
|
|
370
|
+
didMutate = true;
|
|
371
|
+
chgState = { ...chgState };
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}, collection.changeState);
|
|
375
|
+
return didMutate ? { ...collection, changeState } : collection;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Track an entity before it is removed with the intention of deleting it on the server.
|
|
379
|
+
* Does NOT remove from the collection (the reducer's job).
|
|
380
|
+
* @param key The primary key of the entity to delete.
|
|
381
|
+
* @param collection The entity collection
|
|
382
|
+
* @param [mergeStrategy] Track by default. Don't track if is MergeStrategy.IgnoreChanges.
|
|
383
|
+
*/
|
|
384
|
+
trackDeleteOne(key, collection, mergeStrategy) {
|
|
385
|
+
return key == null
|
|
386
|
+
? collection
|
|
387
|
+
: this.trackDeleteMany([key], collection, mergeStrategy);
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Track multiple entities before updating them in the collection.
|
|
391
|
+
* Does NOT update the collection (the reducer's job).
|
|
392
|
+
* @param updates The entities to update.
|
|
393
|
+
* @param collection The entity collection
|
|
394
|
+
* @param [mergeStrategy] Track by default. Don't track if is MergeStrategy.IgnoreChanges.
|
|
395
|
+
*/
|
|
396
|
+
trackUpdateMany(updates, collection, mergeStrategy) {
|
|
397
|
+
if (mergeStrategy === MergeStrategy.IgnoreChanges ||
|
|
398
|
+
updates == null ||
|
|
399
|
+
updates.length === 0) {
|
|
400
|
+
return collection; // nothing to track
|
|
401
|
+
}
|
|
402
|
+
let didMutate = false;
|
|
403
|
+
const entityMap = collection.entities;
|
|
404
|
+
const changeState = updates.reduce((chgState, update) => {
|
|
405
|
+
const { id, changes: entity } = update;
|
|
406
|
+
if (id == null || id === '') {
|
|
407
|
+
throw new Error(`${collection.entityName} entity update requires a key to be tracked`);
|
|
408
|
+
}
|
|
409
|
+
const originalValue = entityMap[id];
|
|
410
|
+
// Only track if it is in the collection. Silently ignore if it is not.
|
|
411
|
+
// @ngrx/entity adapter would also silently ignore.
|
|
412
|
+
// Todo: should missing update entity really be reported as an error?
|
|
413
|
+
if (originalValue) {
|
|
414
|
+
const trackedChange = chgState[id];
|
|
415
|
+
if (!trackedChange) {
|
|
416
|
+
if (!didMutate) {
|
|
417
|
+
didMutate = true;
|
|
418
|
+
chgState = { ...chgState };
|
|
419
|
+
}
|
|
420
|
+
chgState[id] = { changeType: ChangeType.Updated, originalValue };
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return chgState;
|
|
424
|
+
}, collection.changeState);
|
|
425
|
+
return didMutate ? { ...collection, changeState } : collection;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Track an entity before updating it in the collection.
|
|
429
|
+
* Does NOT update the collection (the reducer's job).
|
|
430
|
+
* @param update The entity to update.
|
|
431
|
+
* @param collection The entity collection
|
|
432
|
+
* @param [mergeStrategy] Track by default. Don't track if is MergeStrategy.IgnoreChanges.
|
|
433
|
+
*/
|
|
434
|
+
trackUpdateOne(update, collection, mergeStrategy) {
|
|
435
|
+
return update == null
|
|
436
|
+
? collection
|
|
437
|
+
: this.trackUpdateMany([update], collection, mergeStrategy);
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Track multiple entities before upserting (adding and updating) them to the collection.
|
|
441
|
+
* Does NOT update the collection (the reducer's job).
|
|
442
|
+
* @param entities The entities to add or update. They must be complete entities with ids.
|
|
443
|
+
* @param collection The entity collection
|
|
444
|
+
* @param [mergeStrategy] Track by default. Don't track if is MergeStrategy.IgnoreChanges.
|
|
445
|
+
*/
|
|
446
|
+
trackUpsertMany(entities, collection, mergeStrategy) {
|
|
447
|
+
if (mergeStrategy === MergeStrategy.IgnoreChanges ||
|
|
448
|
+
entities == null ||
|
|
449
|
+
entities.length === 0) {
|
|
450
|
+
return collection; // nothing to track
|
|
451
|
+
}
|
|
452
|
+
let didMutate = false;
|
|
453
|
+
const entityMap = collection.entities;
|
|
454
|
+
const changeState = entities.reduce((chgState, entity) => {
|
|
455
|
+
const id = this.selectId(entity);
|
|
456
|
+
if (id == null || id === '') {
|
|
457
|
+
throw new Error(`${collection.entityName} entity upsert requires a key to be tracked`);
|
|
458
|
+
}
|
|
459
|
+
const trackedChange = chgState[id];
|
|
460
|
+
if (!trackedChange) {
|
|
461
|
+
if (!didMutate) {
|
|
462
|
+
didMutate = true;
|
|
463
|
+
chgState = { ...chgState };
|
|
464
|
+
}
|
|
465
|
+
const originalValue = entityMap[id];
|
|
466
|
+
chgState[id] =
|
|
467
|
+
originalValue == null
|
|
468
|
+
? { changeType: ChangeType.Added }
|
|
469
|
+
: { changeType: ChangeType.Updated, originalValue };
|
|
470
|
+
}
|
|
471
|
+
return chgState;
|
|
472
|
+
}, collection.changeState);
|
|
473
|
+
return didMutate ? { ...collection, changeState } : collection;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Track an entity before upsert (adding and updating) it to the collection.
|
|
477
|
+
* Does NOT update the collection (the reducer's job).
|
|
478
|
+
* @param entities The entity to add or update. It must be a complete entity with its id.
|
|
479
|
+
* @param collection The entity collection
|
|
480
|
+
* @param [mergeStrategy] Track by default. Don't track if is MergeStrategy.IgnoreChanges.
|
|
481
|
+
*/
|
|
482
|
+
trackUpsertOne(entity, collection, mergeStrategy) {
|
|
483
|
+
return entity == null
|
|
484
|
+
? collection
|
|
485
|
+
: this.trackUpsertMany([entity], collection, mergeStrategy);
|
|
486
|
+
}
|
|
487
|
+
// #endregion track methods
|
|
488
|
+
// #region undo methods
|
|
489
|
+
/**
|
|
490
|
+
* Revert the unsaved changes for all collection.
|
|
491
|
+
* Harmless when there are no entity changes to undo.
|
|
492
|
+
* @param collection The entity collection
|
|
493
|
+
*/
|
|
494
|
+
undoAll(collection) {
|
|
495
|
+
const ids = Object.keys(collection.changeState);
|
|
496
|
+
const { remove, upsert } = ids.reduce((acc, id) => {
|
|
497
|
+
const changeState = acc.chgState[id];
|
|
498
|
+
switch (changeState.changeType) {
|
|
499
|
+
case ChangeType.Added:
|
|
500
|
+
acc.remove.push(id);
|
|
501
|
+
break;
|
|
502
|
+
case ChangeType.Deleted:
|
|
503
|
+
const removed = changeState.originalValue;
|
|
504
|
+
if (removed) {
|
|
505
|
+
acc.upsert.push(removed);
|
|
506
|
+
}
|
|
507
|
+
break;
|
|
508
|
+
case ChangeType.Updated:
|
|
509
|
+
acc.upsert.push(changeState.originalValue);
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
return acc;
|
|
513
|
+
},
|
|
514
|
+
// entitiesToUndo
|
|
515
|
+
{
|
|
516
|
+
remove: [],
|
|
517
|
+
upsert: [],
|
|
518
|
+
chgState: collection.changeState,
|
|
519
|
+
});
|
|
520
|
+
collection = this.adapter.removeMany(remove, collection);
|
|
521
|
+
collection = this.adapter.upsertMany(upsert, collection);
|
|
522
|
+
return { ...collection, changeState: {} };
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Revert the unsaved changes for the given entities.
|
|
526
|
+
* Harmless when there are no entity changes to undo.
|
|
527
|
+
* @param entityOrIdList The entities to revert or their ids.
|
|
528
|
+
* @param collection The entity collection
|
|
529
|
+
*/
|
|
530
|
+
undoMany(entityOrIdList, collection) {
|
|
531
|
+
if (entityOrIdList == null || entityOrIdList.length === 0) {
|
|
532
|
+
return collection; // nothing to undo
|
|
533
|
+
}
|
|
534
|
+
let didMutate = false;
|
|
535
|
+
const { changeState, remove, upsert } = entityOrIdList.reduce((acc, entityOrId) => {
|
|
536
|
+
let chgState = acc.changeState;
|
|
537
|
+
const id = typeof entityOrId === 'object'
|
|
538
|
+
? this.selectId(entityOrId)
|
|
539
|
+
: entityOrId;
|
|
540
|
+
const change = chgState[id];
|
|
541
|
+
if (change) {
|
|
542
|
+
if (!didMutate) {
|
|
543
|
+
chgState = { ...chgState };
|
|
544
|
+
didMutate = true;
|
|
545
|
+
}
|
|
546
|
+
delete chgState[id]; // clear tracking of this entity
|
|
547
|
+
acc.changeState = chgState;
|
|
548
|
+
switch (change.changeType) {
|
|
549
|
+
case ChangeType.Added:
|
|
550
|
+
acc.remove.push(id);
|
|
551
|
+
break;
|
|
552
|
+
case ChangeType.Deleted:
|
|
553
|
+
const removed = change.originalValue;
|
|
554
|
+
if (removed) {
|
|
555
|
+
acc.upsert.push(removed);
|
|
556
|
+
}
|
|
557
|
+
break;
|
|
558
|
+
case ChangeType.Updated:
|
|
559
|
+
acc.upsert.push(change.originalValue);
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return acc;
|
|
564
|
+
},
|
|
565
|
+
// entitiesToUndo
|
|
566
|
+
{
|
|
567
|
+
remove: [],
|
|
568
|
+
upsert: [],
|
|
569
|
+
changeState: collection.changeState,
|
|
570
|
+
});
|
|
571
|
+
collection = this.adapter.removeMany(remove, collection);
|
|
572
|
+
collection = this.adapter.upsertMany(upsert, collection);
|
|
573
|
+
return didMutate ? { ...collection, changeState } : collection;
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Revert the unsaved changes for the given entity.
|
|
577
|
+
* Harmless when there are no entity changes to undo.
|
|
578
|
+
* @param entityOrId The entity to revert or its id.
|
|
579
|
+
* @param collection The entity collection
|
|
580
|
+
*/
|
|
581
|
+
undoOne(entityOrId, collection) {
|
|
582
|
+
return entityOrId == null
|
|
583
|
+
? collection
|
|
584
|
+
: this.undoMany([entityOrId], collection);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LWNoYW5nZS10cmFja2VyLWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9tb2R1bGVzL2RhdGEvc3JjL3JlZHVjZXJzL2VudGl0eS1jaGFuZ2UtdHJhY2tlci1iYXNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxVQUFVLEVBQW9CLE1BQU0scUJBQXFCLENBQUM7QUFDbkUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRXJELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUcxRDs7Ozs7R0FLRztBQUNILE1BQU0sT0FBTyx1QkFBdUI7SUFDbEMsWUFDVSxPQUF5QixFQUN6QixRQUF1QjtRQUR2QixZQUFPLEdBQVAsT0FBTyxDQUFrQjtRQUN6QixhQUFRLEdBQVIsUUFBUSxDQUFlO1FBRS9CLG9EQUFvRDtRQUNwRCxJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsSUFBSSxlQUFlLENBQUM7SUFDOUMsQ0FBQztJQUVELHlCQUF5QjtJQUN6Qjs7OztPQUlHO0lBQ0gsU0FBUyxDQUFDLFVBQStCO1FBQ3ZDLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUM7WUFDckQsQ0FBQyxDQUFDLFVBQVU7WUFDWixDQUFDLENBQUMsRUFBRSxHQUFHLFVBQVUsRUFBRSxXQUFXLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDekMsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsVUFBVSxDQUNSLGNBQXVDLEVBQ3ZDLFVBQStCO1FBRS9CLElBQUksY0FBYyxJQUFJLElBQUksSUFBSSxjQUFjLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUN6RCxPQUFPLFVBQVUsQ0FBQyxDQUFDLG9CQUFvQjtTQUN4QztRQUNELElBQUksU0FBUyxHQUFHLEtBQUssQ0FBQztRQUN0QixNQUFNLFdBQVcs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QUcsVUFBVSxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUM7SUFDakUsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsT0FBTyxDQUNMLFVBQStCLEVBQy9CLFVBQStCO1FBRS9CLE9BQU8sVUFBVSxJQUFJLElBQUk7WUFDdkIsQ0FBQyxDQUFDLFVBQVU7WUFDWixDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQzlDLENBQUM7Q0FFRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEVudGl0eUFkYXB0ZXIsIElkU2VsZWN0b3IsIFVwZGF0ZSB9IGZyb20gJ0BuZ3J4L2VudGl0eSc7XG5cbmltcG9ydCB7IENoYW5nZVR5cGUsIEVudGl0eUNvbGxlY3Rpb24gfSBmcm9tICcuL2VudGl0eS1jb2xsZWN0aW9uJztcbmltcG9ydCB7IGRlZmF1bHRTZWxlY3RJZCB9IGZyb20gJy4uL3V0aWxzL3V0aWxpdGllcyc7XG5pbXBvcnQgeyBFbnRpdHlDaGFuZ2VUcmFja2VyIH0gZnJvbSAnLi9lbnRpdHktY2hhbmdlLXRyYWNrZXInO1xuaW1wb3J0IHsgTWVyZ2VTdHJhdGVneSB9IGZyb20gJy4uL2FjdGlvbnMvbWVyZ2Utc3RyYXRlZ3knO1xuaW1wb3J0IHsgVXBkYXRlUmVzcG9uc2VEYXRhIH0gZnJvbSAnLi4vYWN0aW9ucy91cGRhdGUtcmVzcG9uc2UtZGF0YSc7XG5cbi8qKlxuICogVGhlIGRlZmF1bHQgaW1wbGVtZW50YXRpb24gb2YgRW50aXR5Q2hhbmdlVHJhY2tlciB3aXRoXG4gKiBtZXRob2RzIGZvciB0cmFja2luZywgY29tbWl0dGluZywgYW5kIHJldmVydGluZy91bmRvaW5nIHVuc2F2ZWQgZW50aXR5IGNoYW5nZXMuXG4gKiBVc2VkIGJ5IEVudGl0eUNvbGxlY3Rpb25SZWR1Y2VyTWV0aG9kcyB3aGljaCBzaG91bGQgY2FsbCB0cmFja2VyIG1ldGhvZHMgQkVGT1JFIG1vZGlmeWluZyB0aGUgY29sbGVjdGlvbi5cbiAqIFNlZSBFbnRpdHlDaGFuZ2VUcmFja2VyIGRvY3MuXG4gKi9cbmV4cG9ydCBjbGFzcyBFbnRpdHlDaGFuZ2VUcmFja2VyQmFzZTxUPiBpbXBsZW1lbnRzIEVudGl0eUNoYW5nZVRyYWNrZXI8VD4ge1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGFkYXB0ZXI6IEVudGl0eUFkYXB0ZXI8VD4sXG4gICAgcHJpdmF0ZSBzZWxlY3RJZDogSWRTZWxlY3RvcjxUPlxuICApIHtcbiAgICAvKiogRXh0cmFjdCB0aGUgcHJpbWFyeSBrZXkgKGlkKTsgZGVmYXVsdCB0byBgaWRgICovXG4gICAgdGhpcy5zZWxlY3RJZCA9IHNlbGVjdElkIHx8IGRlZmF1bHRTZWxlY3RJZDtcbiAgfVxuXG4gIC8vICNyZWdpb24gY29tbWl0IG1ldGhvZHNcbiAgLyoqXG4gICAqIENvbW1pdCBhbGwgY2hhbmdlcyBhcyB3aGVuIHRoZSBjb2xsZWN0aW9uIGhhcyBiZWVuIGNvbXBsZXRlbHkgcmVsb2FkZWQgZnJvbSB0aGUgc2VydmVyLlxuICAgKiBIYXJtbGVzcyB3aGVuIHRoZXJlIGFyZSBubyBlbnRpdHkgY2hhbmdlcyB0byBjb21taXQuXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uIFRoZSBlbnRpdHkgY29sbGVjdGlvblxuICAgKi9cbiAgY29tbWl0QWxsKGNvbGxlY3Rpb246IEVudGl0eUNvbGxlY3Rpb248VD4pOiBFbnRpdHlDb2xsZWN0aW9uPFQ+IHtcbiAgICByZXR1cm4gT2JqZWN0LmtleXMoY29sbGVjdGlvbi5jaGFuZ2VTdGF0ZSkubGVuZ3RoID09PSAwXG4gICAgICA/IGNvbGxlY3Rpb25cbiAgICAgIDogeyAuLi5jb2xsZWN0aW9uLCBjaGFuZ2VTdGF0ZToge30gfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb21taXQgY2hhbmdlcyBmb3IgdGhlIGdpdmVuIGVudGl0aWVzIGFzIHdoZW4gdGhleSBoYXZlIGJlZW4gcmVmcmVzaGVkIGZyb20gdGhlIHNlcnZlci5cbiAgICogSGFybWxlc3Mgd2hlbiB0aGVyZSBhcmUgbm8gZW50aXR5IGNoYW5nZXMgdG8gY29tbWl0LlxuICAgKiBAcGFyYW0gZW50aXR5T3JJZExpc3QgVGhlIGVudGl0aWVzIHRvIGNsZWFyIHRyYWNraW5nIG9yIHRoZWlyIGlkcy5cbiAgICogQHBhcmFtIGNvbGxlY3Rpb24gVGhlIGVudGl0eSBjb2xsZWN0aW9uXG4gICAqL1xuICBjb21taXRNYW55KFxuICAgIGVudGl0eU9ySWRMaXN0OiAobnVtYmVyIHwgc3RyaW5nIHwgVClbXSxcbiAgICBjb2xsZWN0aW9uOiBFbnRpdHlDb2xsZWN0aW9uPFQ+XG4gICk6IEVudGl0eUNvbGxlY3Rpb248VD4ge1xuICAgIGlmIChlbnRpdHlPcklkTGlzdCA9PSBudWxsIHx8IGVudGl0eU9ySWRMaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIGNvbGxlY3Rpb247IC8vIG5vdGhpbmcgdG8gY29tbWl0XG4gICAgfVxuICAgIGxldCBkaWRNdXRhdGUgPSBmYWxzZTtcbiAgICBjb25zdCBjaGFuZ2VTdGF0ZSA9IGVudGl0eU9ySWRMaXN0LnJlZHVjZSgoY2hnU3RhdGUsIGVudGl0eU9ySWQpID0+IHtcbiAgICAgIGNvbnN0IGlkID1cbiAgICAgICAgdHlwZW9mIGVudGl0eU9ySWQgPT09ICdvYmplY3QnXG4gICAgICAgICAgPyB0aGlzLnNlbGVjdElkKGVudGl0eU9ySWQpXG4gICAgICAgICAgOiAoZW50aXR5T3JJZCBhcyBzdHJpbmcgfCBudW1iZXIpO1xuICAgICAgaWYgKGNoZ1N0YXRlW2lkXSkge1xuICAgICAgICBpZiAoIWRpZE11dGF0ZSkge1xuICAgICAgICAgIGNoZ1N0YXRlID0geyAuLi5jaGdTdGF0ZSB9O1xuICAgICAgICAgIGRpZE11dGF0ZSA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgZGVsZXRlIGNoZ1N0YXRlW2lkXTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjaGdTdGF0ZTtcbiAgICB9LCBjb2xsZWN0aW9uLmNoYW5nZVN0YXRlKTtcblxuICAgIHJldHVybiBkaWRNdXRhdGUgPyB7IC4uLmNvbGxlY3Rpb24sIGNoYW5nZVN0YXRlIH0gOiBjb2xsZWN0aW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbW1pdCBjaGFuZ2VzIGZvciB0aGUgZ2l2ZW4gZW50aXR5IGFzIHdoZW4gaXQgaGF2ZSBiZWVuIHJlZnJlc2hlZCBmcm9tIHRoZSBzZXJ2ZXIuXG4gICAqIEhhcm1sZXNzIHdoZW4gbm8gZW50aXR5IGNoYW5nZXMgdG8gY29tbWl0LlxuICAgKiBAcGFyYW0gZW50aXR5T3JJZCBUaGUgZW50aXR5IHRvIGNsZWFyIHRyYWNraW5nIG9yIGl0cyBpZC5cbiAgICogQHBhcmFtIGNvbGxlY3Rpb24gVGhlIGVudGl0eSBjb2xsZWN0aW9uXG4gICAqL1xuICBjb21taXRPbmUoXG4gICAgZW50aXR5T3JJZDogbnVtYmVyIHwgc3RyaW5nIHwgVCxcbiAgICBjb2xsZWN0aW9uOiBFbnRpdHlDb2xsZWN0aW9uPFQ+XG4gICk6IEVudGl0eUNvbGxlY3Rpb248VD4ge1xuICAgIHJldHVybiBlbnRpdHlPcklkID09IG51bGxcbiAgICAgID8gY29sbGVjdGlvblxuICAgICAgOiB0aGlzLmNvbW1pdE1hbnkoW2VudGl0eU9ySWRdLCBjb2xsZWN0aW9uKTtcbiAgfVxuXG4gIC8vICNlbmRyZWdpb24gY29tbWl0IG1ldGhvZHNcblxuICAvLyAjcmVnaW9uIG1lcmdlIHF1ZXJ5XG4gIC8qKlxuICAgKiBNZXJnZSBxdWVyeSByZXN1bHRzIGludG8gdGhlIGNvbGxlY3Rpb24sIGFkanVzdGluZyB0aGUgQ2hhbmdlU3RhdGUgcGVyIHRoZSBtZXJnZVN0cmF0ZWd5LlxuICAgKiBAcGFyYW0gZW50aXRpZXMgRW50aXRpZXMgcmV0dXJuZWQgZnJvbSBxdWVyeWluZyB0aGUgc2VydmVyLlxuICAgKiBAcGFyYW0gY29sbGVjdGlvbiBUaGUgZW50aXR5IGNvbGxlY3Rpb25cbiAgICogQHBhcmFtIFttZXJnZVN0cmF0ZWd5XSBIb3cgdG8gbWVyZ2UgYSBxdWVyaWVkIGVudGl0eSB3aGVuIHRoZSBjb3JyZXNwb25kaW5nIGVudGl0eSBpbiB0aGUgY29sbGVjdGlvbiBoYXMgYW4gdW5zYXZlZCBjaGFuZ2UuXG4gICAqIERlZmF1bHRzIHRvIE1lcmdlU3RyYXRlZ3kuUHJlc2VydmVDaGFuZ2VzLlxuICAgKiBAcmV0dXJucyBUaGUgbWVyZ2VkIEVudGl0eUNvbGxlY3Rpb24uXG4gICAqL1xuICBtZXJnZVF1ZXJ5UmVzdWx0cyhcbiAgICBlbnRpdGllczogVFtdLFxuICAgIGNvbGxlY3Rpb246IEVudGl0eUNvbGxlY3Rpb248VD4sXG4gICAgbWVyZ2VTdHJhdGVneT86IE1lcmdlU3RyYXRlZ3lcbiAgKTogRW50aXR5Q29sbGVjdGlvbjxUPiB7XG4gICAgcmV0dXJuIHRoaXMubWVyZ2VTZXJ2ZXJVcHNlcnRzKFxuICAgICAgZW50aXRpZXMsXG4gICAgICBjb2xsZWN0aW9uLFxuICAgICAgTWVyZ2VTdHJhdGVneS5QcmVzZXJ2ZUNoYW5nZXMsXG4gICAgICBtZXJnZVN0cmF0ZWd5XG4gICAgKTtcbiAgfVxuICAvLyAjZW5kcmVnaW9uIG1lcmdlIHF1ZXJ5IHJlc3VsdHNcblxuICAvLyAjcmVnaW9uIG1lcmdlIHNhdmUgcmVzdWx0c1xuICAvKipcbiAgICogTWVyZ2UgcmVzdWx0IG9mIHNhdmluZyBuZXcgZW50aXRpZXMgaW50byB0aGUgY29sbGVjdGlvbiwgYWRqdXN0aW5nIHRoZSBDaGFuZ2VTdGF0ZSBwZXIgdGhlIG1lcmdlU3RyYXRlZ3kuXG4gICAqIFRoZSBkZWZhdWx0IGlzIE1lcmdlU3RyYXRlZ3kuT3ZlcndyaXRlQ2hhbmdlcy5cbiAgICogQHBhcmFtIGVudGl0aWVzIEVudGl0aWVzIHJldHVybmVkIGZyb20gc2F2aW5nIG5ldyBlbnRpdGllcyB0byB0aGUgc2VydmVyLlxuICAgKiBAcGFyYW0gY29sbGVjdGlvbiBUaGUgZW50aXR5IGNvbGxlY3Rpb25cbiAgICogQHBhcmFtIFttZXJnZVN0cmF0ZWd5XSBIb3cgdG8gbWVyZ2UgYSBzYXZlZCBlbnRpdHkgd2hlbiB0aGUgY29ycmVzcG9uZGluZyBlbnRpdHkgaW4gdGhlIGNvbGxlY3Rpb24gaGFzIGFuIHVuc2F2ZWQgY2hhbmdlLlxuICAgKiBEZWZhdWx0cyB0byBNZXJnZVN0cmF0ZWd5Lk92ZXJ3cml0ZUNoYW5nZXMuXG4gICAqIEByZXR1cm5zIFRoZSBtZXJnZWQgRW50aXR5Q29sbGVjdGlvbi5cbiAgICovXG4gIG1lcmdlU2F2ZUFkZHMoXG4gICAgZW50aXRpZXM6IFRbXSxcbiAgICBjb2xsZWN0aW9uOiBFbnRpdHlDb2xsZWN0aW9uPFQ+LFxuICAgIG1lcmdlU3RyYXRlZ3k/OiBNZXJnZVN0cmF0ZWd5XG4gICk6IEVudGl0eUNvbGxlY3Rpb248VD4ge1xuICAgIHJldHVybiB0aGlzLm1lcmdlU2VydmVyVXBzZXJ0cyhcbiAgICAgIGVudGl0aWVzLFxuICAgICAgY29sbGVjdGlvbixcbiAgICAgIE1lcmdlU3RyYXRlZ3kuT3ZlcndyaXRlQ2hhbmdlcyxcbiAgICAgIG1lcmdlU3RyYXRlZ3lcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIE1lcmdlIHN1Y2Nlc3NmdWwgcmVzdWx0IG9mIGRlbGV0aW5nIGVudGl0aWVzIG9uIHRoZSBzZXJ2ZXIgdGhhdCBoYXZlIHRoZSBnaXZlbiBwcmltYXJ5IGtleXNcbiAgICogQ2xlYXJzIHRoZSBlbnRpdHkgY2hhbmdlU3RhdGUgZm9yIHRob3NlIGtleXMgdW5sZXNzIHRoZSBNZXJnZVN0cmF0ZWd5IGlzIGlnbm9yZUNoYW5nZXMuXG4gICAqIEBwYXJhbSBlbnRpdGllcyBrZXlzIHByaW1hcnkga2V5cyBvZiB0aGUgZW50aXRpZXMgdG8gcmVtb3ZlL2RlbGV0ZS5cbiAgICogQHBhcmFtIGNvbGxlY3Rpb24gVGhlIGVudGl0eSBjb2xsZWN0aW9uXG4gICAqIEBwYXJhbSBbbWVyZ2VTdHJhdGVneV0gSG93IHRvIGFkanVzdCBjaGFuZ2UgdHJhY2tpbmcgd2hlbiB0aGUgY29ycmVzcG9uZGluZyBlbnRpdHkgaW4gdGhlIGNvbGxlY3Rpb24gaGFzIGFuIHVuc2F2ZWQgY2hhbmdlLlxuICAgKiBEZWZhdWx0cyB0byBNZXJnZVN0cmF0ZWd5Lk92ZXJ3cml0ZUNoYW5nZXMuXG4gICAqIEByZXR1cm5zIFRoZSBtZXJnZWQgRW50aXR5Q29sbGVjdGlvbi5cbiAgICovXG4gIG1lcmdlU2F2ZURlbGV0ZXMoXG4gICAga2V5czogKG51bWJlciB8IHN0cmluZylbXSxcbiAgICBjb2xsZWN0aW9uOiBFbnRpdHlDb2xsZWN0aW9uPFQ+LFxuICAgIG1lcmdlU3RyYXRlZ3k/OiBNZXJnZVN0cmF0ZWd5XG4gICk6IEVudGl0eUNvbGxlY3Rpb248VD4ge1xuICAgIG1lcmdlU3RyYXRlZ3kgPVxuICAgICAgbWVyZ2VTdHJhdGVneSA9PSBudWxsID8gTWVyZ2VTdHJhdGVneS5PdmVyd3JpdGVDaGFuZ2VzIDogbWVyZ2VTdHJhdGVneTtcbiAgICAvLyBzYW1lIGxvZ2ljIGZvciBhbGwgbm9uLWlnbm9yZSBtZXJnZSBzdHJhdGVnaWVzOiBhbHdheXMgY2xlYXIgKGNvbW1pdCkgdGhlIGNoYW5nZXNcbiAgICBjb25zdCBkZWxldGVJZHMgPSBrZXlzIGFzIHN0cmluZ1tdOyAvLyBtYWtlIFR5cGVTY3JpcHQgaGFwcHlcbiAgICBjb2xsZWN0aW9uID1cbiAgICAgIG1lcmdlU3RyYXRlZ3kgPT09IE1lcmdlU3RyYXRlZ3kuSWdub3JlQ2hhbmdlc1xuICAgICAgICA/IGNvbGxlY3Rpb25cbiAgICAgICAgOiB0aGlzLmNvbW1pdE1hbnkoZGVsZXRlSWRzLCBjb2xsZWN0aW9uKTtcbiAgICByZXR1cm4gdGhpcy5hZGFwdGVyLnJlbW92ZU1hbnkoZGVsZXRlSWRzLCBjb2xsZWN0aW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXJnZSByZXN1bHQgb2Ygc2F2aW5nIHVwZGF0ZWQgZW50aXRpZXMgaW50byB0aGUgY29sbGVjdGlvbiwgYWRqdXN0aW5nIHRoZSBDaGFuZ2VTdGF0ZSBwZXIgdGhlIG1lcmdlU3RyYXRlZ3kuXG4gICAqIFRoZSBkZWZhdWx0IGlzIE1lcmdlU3RyYXRlZ3kuT3ZlcndyaXRlQ2hhbmdlcy5cbiAgICogQHBhcmFtIHVwZGF0ZVJlc3BvbnNlRGF0YSBFbnRpdHkgcmVzcG9uc2UgZGF0YSByZXR1cm5lZCBmcm9tIHNhdmluZyB1cGRhdGVkIGVudGl0aWVzIHRvIHRoZSBzZXJ2ZXIuXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uIFRoZSBlbnRpdHkgY29sbGVjdGlvblxuICAgKiBAcGFyYW0gW21lcmdlU3RyYXRlZ3ldIEhvdyB0byBtZXJnZSBhIHNhdmVkIGVudGl0eSB3aGVuIHRoZSBjb3JyZXNwb25kaW5nIGVudGl0eSBpbiB0aGUgY29sbGVjdGlvbiBoYXMgYW4gdW5zYXZlZCBjaGFuZ2UuXG4gICAqIERlZmF1bHRzIHRvIE1lcmdlU3RyYXRlZ3kuT3ZlcndyaXRlQ2hhbmdlcy5cbiAgICogQHBhcmFtIFtza2lwVW5jaGFuZ2VkXSBUcnVlIG1lYW5zIHNraXAgdXBkYXRlIGlmIHNlcnZlciBkaWRuJ3QgY2hhbmdlIGl0LiBGYWxzZSBieSBkZWZhdWx0LlxuICAgKiBJZiB0aGUgdXBkYXRlIHdhcyBvcHRpbWlzdGljIGFuZCB0aGUgc2VydmVyIGRpZG4ndCBtYWtlIG1vcmUgY2hhbmdlcyBvZiBpdHMgb3duXG4gICAqIHRoZW4gdGhlIHVwZGF0ZXMgYXJlIGFscmVhZHkgaW4gdGhlIGNvbGxlY3Rpb24gYW5kIHNob3VsZG4ndCBtYWtlIHRoZW0gYWdhaW4uXG4gICAqIEByZXR1cm5zIFRoZSBtZXJnZWQgRW50aXR5Q29sbGVjdGlvbi5cbiAgICovXG4gIG1lcmdlU2F2ZVVwZGF0ZXMoXG4gICAgdXBkYXRlUmVzcG9uc2VEYXRhOiBVcGRhdGVSZXNwb25zZURhdGE8VD5bXSxcbiAgICBjb2xsZWN0aW9uOiBFbnRpdHlDb2xsZWN0aW9uPFQ+LFxuICAgIG1lcmdlU3RyYXRlZ3k/OiBNZXJnZVN0cmF0ZWd5LFxuICAgIHNraXBVbmNoYW5nZWQgPSBmYWxzZVxuICApOiBFbnRpdHlDb2xsZWN0aW9uPFQ+IHtcbiAgICBpZiAodXBkYXRlUmVzcG9uc2VEYXRhID09IG51bGwgfHwgdXBkYXRlUmVzcG9uc2VEYXRhLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIGNvbGxlY3Rpb247IC8vIG5vdGhpbmcgdG8gbWVyZ2UuXG4gICAgfVxuXG4gICAgbGV0IGRpZE11dGF0ZSA9IGZhbHNlO1xuICAgIGxldCBjaGFuZ2VTdGF0ZSA9IGNvbGxlY3Rpb24uY2hhbmdlU3RhdGU7XG4gICAgbWVyZ2VTdHJhdGVneSA9XG4gICAgICBtZXJnZVN0cmF0ZWd5ID09IG51bGwgPyBNZXJnZVN0cmF0ZWd5Lk92ZXJ3cml0ZUNoYW5nZXMgOiBtZXJnZVN0cmF0ZWd5O1xuICAgIGxldCB1cGRhdGVzOiBVcGRhdGU8VD5bXTtcblxuICAgIHN3aXRjaCAobWVyZ2VTdHJhdGVneSkge1xuICAgICAgY2FzZSBNZXJnZVN0cmF0ZWd5Lklnbm9yZUNoYW5nZXM6XG4gICAgICAgIHVwZGF0ZXMgPSBmaWx0ZXJDaGFuZ2VkKHVwZGF0ZVJlc3BvbnNlRGF0YSk7XG4gICAgICAgIHJldHVybiB0aGlzLmFkYXB0ZXIudXBkYXRlTWFueSh1cGRhdGVzLCBjb2xsZWN0aW9uKTtcblxuICAgICAgY2FzZSBNZXJnZVN0cmF0ZWd5Lk92ZXJ3cml0ZUNoYW5nZXM6XG4gICAgICAgIGNoYW5nZVN0YXRlID0gdXBkYXRlUmVzcG9uc2VEYXRhLnJlZHVjZSgoY2hnU3RhdGUsIHVwZGF0ZSkgPT4ge1xuICAgICAgICAgIGNvbnN0IG9sZElkID0gdXBkYXRlLmlkO1xuICAgICAgICAgIGNvbnN0IGNoYW5nZSA9IGNoZ1N0YXRlW29sZElkXTtcbiAgICAgICAgICBpZiAoY2hhbmdlKSB7XG4gICAgICAgICAgICBpZiAoIWRpZE11dGF0ZSkge1xuICAgICAgICAgICAgICBjaGdTdGF0ZSA9IHsgLi4uY2hnU3RhdGUgfTtcbiAgICAgICAgICAgICAgZGlkTXV0YXRlID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRlbGV0ZSBjaGdTdGF0ZVtvbGRJZF07XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBjaGdTdGF0ZTtcbiAgICAgICAgfSwgY29sbGVjdGlvbi5jaGFuZ2VTdGF0ZSk7XG5cbiAgICAgICAgY29sbGVjdGlvbiA9IGRpZE11dGF0ZSA/IHsgLi4uY29sbGVjdGlvbiwgY2hhbmdlU3RhdGUgfSA6IGNvbGxlY3Rpb247XG5cbiAgICAgICAgdXBkYXRlcyA9IGZpbHRlckNoYW5nZWQodXBkYXRlUmVzcG9uc2VEYXRhKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRhcHRlci51cGRhdGVNYW55KHVwZGF0ZXMsIGNvbGxlY3Rpb24pO1xuXG4gICAgICBjYXNlIE1lcmdlU3RyYXRlZ3kuUHJlc2VydmVDaGFuZ2VzOiB7XG4gICAgICAgIGNvbnN0IHVwZGF0ZWFibGVFbnRpdGllcyA9IFtdIGFzIFVwZGF0ZVJlc3BvbnNlRGF0YTxUPltdO1xuICAgICAgICBjaGFuZ2VTdGF0ZSA9IHVwZGF0ZVJlc3BvbnNlRGF0YS5yZWR1Y2UoKGNoZ1N0YXRlLCB1cGRhdGUpID0+IHtcbiAgICAgICAgICBjb25zdCBvbGRJZCA9IHVwZGF0ZS5pZDtcbiAgICAgICAgICBjb25zdCBjaGFuZ2UgPSBjaGdTdGF0ZVtvbGRJZF07XG4gICAgICAgICAgaWYgKGNoYW5nZSkge1xuICAgICAgICAgICAgLy8gVHJhY2tpbmcgYSBjaGFuZ2Ugc28gdXBkYXRlIG9yaWdpbmFsIHZhbHVlIGJ1dCBub3QgdGhlIGN1cnJlbnQgdmFsdWVcbiAgICAgICAgICAgIGlmICghZGlkTXV0YXRlKSB7XG4gICAgICAgICAgICAgIGNoZ1N0YXRlID0geyAuLi5jaGdTdGF0ZSB9O1xuICAgICAgICAgICAgICBkaWRNdXRhdGUgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgbmV3SWQgPSB0aGlzLnNlbGVjdElkKHVwZGF0ZS5jaGFuZ2VzIGFzIFQpO1xuICAgICAgICAgICAgY29uc3Qgb2xkQ2hhbmdlU3RhdGUgPSBjaGFuZ2U7XG4gICAgICAgICAgICAvLyBJZiB0aGUgc2VydmVyIGNoYW5nZWQgdGhlIGlkLCByZWdpc3RlciB0aGUgbmV3IFwib3JpZ2luYWxWYWx1ZVwiIHVuZGVyIHRoZSBuZXcgaWRcbiAgICAgICAgICAgIC8vIGFuZCByZW1vdmUgdGhlIGNoYW5nZSB0cmFja2VkIHVuZGVyIHRoZSBvbGQgaWQuXG4gICAgICAgICAgICBpZiAobmV3SWQgIT09IG9sZElkKSB7XG4gICAgICAgICAgICAgIGRlbGV0ZSBjaGdTdGF0ZVtvbGRJZF07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBuZXdPcmlnVmFsdWUgPSB7XG4gICAgICAgICAgICAgIC4uLihvbGRDaGFuZ2VTdGF0ZSEub3JpZ2luYWxWYWx1ZSBhcyBhbnkpLFxuICAgICAgICAgICAgICAuLi4odXBkYXRlLmNoYW5nZXMgYXMgYW55KSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAoY2hnU3RhdGUgYXMgYW55KVtuZXdJZF0gPSB7XG4gICAgICAgICAgICAgIC4uLm9sZENoYW5nZVN0YXRlLFxuICAgICAgICAgICAgICBvcmlnaW5hbFZhbHVlOiBuZXdPcmlnVmFsdWUsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB1cGRhdGVhYmxlRW50aXRpZXMucHVzaCh1cGRhdGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gY2hnU3RhdGU7XG4gICAgICAgIH0sIGNvbGxlY3Rpb24uY2hhbmdlU3RhdGUpO1xuICAgICAgICBjb2xsZWN0aW9uID0gZGlkTXV0YXRlID8geyAuLi5jb2xsZWN0aW9uLCBjaGFuZ2VTdGF0ZSB9IDogY29sbGVjdGlvbjtcblxuICAgICAgICB1cGRhdGVzID0gZmlsdGVyQ2hhbmdlZCh1cGRhdGVhYmxlRW50aXRpZXMpO1xuICAgICAgICByZXR1cm4gdGhpcy5hZGFwdGVyLnVwZGF0ZU1hbnkodXBkYXRlcywgY29sbGVjdGlvbik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29uZGl0aW9uYWxseSBrZWVwIG9ubHkgdGhvc2UgdXBkYXRlcyB0aGF0IGhhdmUgYWRkaXRpb25hbCBzZXJ2ZXIgY2hhbmdlcy5cbiAgICAgKiAoZS5nLiwgZm9yIG9wdGltaXN0aWMgc2F2ZXMgYmVjYXVzZSB0aGV5IHVwZGF0ZXMgYXJlIGFscmVhZHkgaW4gdGhlIGN1cnJlbnQgY29sbGVjdGlvbilcbiAgICAgKiBTdHJpcCBvZmYgdGhlIGBjaGFuZ2VkYCBwcm9wZXJ0eS5cbiAgICAgKiBAcmVzcG9uc2VEYXRhIEVudGl0eSByZXNwb25zZSBkYXRhIGZyb20gc2VydmVyLlxuICAgICAqIE1heSBiZSBhbiBVcGRhdGVSZXNwb25zZURhdGE8VD4sIGEgc3ViY2xhc3Mgb2YgVXBkYXRlPFQ+IHdpdGggYSAnY2hhbmdlZCcgZmxhZy5cbiAgICAgKiBAcmV0dXJucyBVcGRhdGU8VD4gKHdpdGhvdXQgdGhlIGNoYW5nZWQgZmxhZylcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBmaWx0ZXJDaGFuZ2VkKHJlc3BvbnNlRGF0YTogVXBkYXRlUmVzcG9uc2VEYXRhPFQ+W10pOiBVcGRhdGU8VD5bXSB7XG4gICAgICBpZiAoc2tpcFVuY2hhbmdlZCA9PT0gdHJ1ZSkge1xuICAgICAgICAvLyBrZWVwIG9ubHkgdGhvc2UgdXBkYXRlcyB0aGF0IHRoZSBzZXJ2ZXIgY2hhbmdlZCAoa25vd2FibGUgaWYgaXMgVXBkYXRlUmVzcG9uc2VEYXRhPFQ+KVxuICAgICAgICByZXNwb25zZURhdGEgPSByZXNwb25zZURhdGEuZmlsdGVyKChyKSA9PiByLmNoYW5nZWQgPT09IHRydWUpO1xuICAgICAgfVxuICAgICAgLy8gU3RyaXAgdW5jaGFuZ2VkIHByb3BlcnR5IGZyb20gcmVzcG9uc2VEYXRhLCBsZWF2aW5nIGp1c3QgdGhlIHB1cmUgVXBkYXRlPFQ+XG4gICAgICAvLyBUT0RPOiBSZW1vdmU/IHByb2JhYmx5IG5vdCBuZWNlc3NhcnkgYXMgdGhlIFVwZGF0ZSBpc24ndCBzdG9yZWQgYW5kIGFkYXB0ZXIgd2lsbCBpZ25vcmUgYGNoYW5nZWRgLlxuICAgICAgcmV0dXJuIHJlc3BvbnNlRGF0YS5tYXAoKHIpID0+ICh7IGlkOiByLmlkIGFzIGFueSwgY2hhbmdlczogci5jaGFuZ2VzIH0pKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTWVyZ2UgcmVzdWx0IG9mIHNhdmluZyB1cHNlcnRlZCBlbnRpdGllcyBpbnRvIHRoZSBjb2xsZWN0aW9uLCBhZGp1c3RpbmcgdGhlIENoYW5nZVN0YXRlIHBlciB0aGUgbWVyZ2VTdHJhdGVneS5cbiAgICogVGhlIGRlZmF1bHQgaXMgTWVyZ2VTdHJhdGVneS5PdmVyd3JpdGVDaGFuZ2VzLlxuICAgKiBAcGFyYW0gZW50aXRpZXMgRW50aXRpZXMgcmV0dXJuZWQgZnJvbSBzYXZpbmcgdXBzZXJ0cyB0byB0aGUgc2VydmVyLlxuICAgKiBAcGFyYW0gY29sbGVjdGlvbiBUaGUgZW50aXR5IGNvbGxlY3Rpb25cbiAgICogQHBhcmFtIFttZXJnZVN0cmF0ZWd5XSBIb3cgdG8gbWVyZ2UgYSBzYXZlZCBlbnRpdHkgd2hlbiB0aGUgY29ycmVzcG9uZGluZyBlbnRpdHkgaW4gdGhlIGNvbGxlY3Rpb24gaGFzIGFuIHVuc2F2ZWQgY2hhbmdlLlxuICAgKiBEZWZhdWx0cyB0byBNZXJnZVN0cmF0ZWd5Lk92ZXJ3cml0ZUNoYW5nZXMuXG4gICAqIEByZXR1cm5zIFRoZSBtZXJnZWQgRW50aXR5Q29sbGVjdGlvbi5cbiAgICovXG4gIG1lcmdlU2F2ZVVwc2VydHMoXG4gICAgZW50aXRpZXM6IFRbXSxcbiAgICBjb2xsZWN0aW9uOiBFbnRpdHlDb2xsZWN0aW9uPFQ+LFxuICAgIG1lcmdlU3RyYXRlZ3k/OiBNZXJnZVN0cmF0ZWd5XG4gICk6IEVudGl0eUNvbGxlY3Rpb248VD4ge1xuICAgIHJldHVybiB0aGlzLm1lcmdlU2VydmVyVXBzZXJ0cyhcbiAgICAgIGVudGl0aWVzLFxuICAgICAgY29sbGVjdGlvbixcbiAgICAgIE1lcmdlU3RyYXRlZ3kuT3ZlcndyaXRlQ2hhbmdlcyxcbiAgICAgIG1lcmdlU3RyYXRlZ3lcbiAgICApO1xuICB9XG4gIC8vICNlbmRyZWdpb24gbWVyZ2Ugc2F2ZSByZXN1bHRzXG5cbiAgLy8gI3JlZ2lvbiBxdWVyeSAmIHNhdmUgaGVscGVyc1xuICAvKipcbiAgICpcbiAgICogQHBhcmFtIGVudGl0aWVzIEVudGl0aWVzIHRvIG1lcmdlXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uIENvbGxlY3Rpb24gaW50byB3aGljaCBlbnRpdGllcyBhcmUgbWVyZ2VkXG4gICAqIEBwYXJhbSBkZWZhdWx0TWVyZ2VTdHJhdGVneSBIb3cgdG8gbWVyZ2Ugd2hlbiBhY3Rpb24ncyBNZXJnZVN0cmF0ZWd5IGlzIHVuc3BlY2lmaWVkXG4gICAqIEBwYXJhbSBbbWVyZ2VTdHJhdGVneV0gVGhlIGFjdGlvbidzIE1lcmdlU3RyYXRlZ3lcbiAgICovXG4gIHByaXZhdGUgbWVyZ2VTZXJ2ZXJVcHNlcnRzKFxuICAgIGVudGl0aWVzOiBUW10sXG4gICAgY29sbGVjdGlvbjogRW50aXR5Q29sbGVjdGlvbjxUPixcbiAgICBkZWZhdWx0TWVyZ2VTdHJhdGVneTogTWVyZ2VTdHJhdGVneSxcbiAgICBtZXJnZVN0cmF0ZWd5PzogTWVyZ2VTdHJhdGVneVxuICApOiBFbnRpdHlDb2xsZWN0aW9uPFQ+IHtcbiAgICBpZiAoZW50aXRpZXMgPT0gbnVsbCB8fCBlbnRpdGllcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBjb2xsZWN0aW9uOyAvLyBub3RoaW5nIHRvIG1lcmdlLlxuICAgIH1cblxuICAgIGxldCBkaWRNdXRhdGUgPSBmYWxzZTtcbiAgICBsZXQgY2hhbmdlU3RhdGUgPSBjb2xsZWN0aW9uLmNoYW5nZVN0YXRlO1xuICAgIG1lcmdlU3RyYXRlZ3kgPVxuICAgICAgbWVyZ2VTdHJhdGVneSA9PSBudWxsID8gZGVmYXVsdE1lcmdlU3RyYXRlZ3kgOiBtZXJnZVN0cmF0ZWd5O1xuXG4gICAgc3dpdGNoIChtZXJnZVN0cmF0ZWd5KSB7XG4gICAgICBjYXNlIE1lcmdlU3RyYXRlZ3kuSWdub3JlQ2hhbmdlczpcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRhcHRlci51cHNlcnRNYW55KGVudGl0aWVzLCBjb2xsZWN0aW9uKTtcblxuICAgICAgY2FzZSBNZXJnZVN0cmF0ZWd5Lk92ZXJ3cml0ZUNoYW5nZXM6XG4gICAgICAgIGNvbGxlY3Rpb24gPSB0aGlzLmFkYXB0ZXIudXBzZXJ0TWFueShlbnRpdGllcywgY29sbGVjdGlvbik7XG5cbiAgICAgICAgY2hhbmdlU3RhdGUgPSBlbnRpdGllcy5yZWR1Y2UoKGNoZ1N0YXRlLCBlbnRpdHkpID0+IHtcbiAgICAgICAgICBjb25zdCBpZCA9IHRoaXMuc2VsZWN0SWQoZW50aXR5KTtcbiAgICAgICAgICBjb25zdCBjaGFuZ2UgPSBjaGdTdGF0ZVtpZF07XG4gICAgICAgICAgaWYgKGNoYW5nZSkge1xuICAgICAgICAgICAgaWYgKCFkaWRNdXRhdGUpIHtcbiAgICAgICAgICAgICAgY2hnU3RhdGUgPSB7IC4uLmNoZ1N0YXRlIH07XG4gICAgICAgICAgICAgIGRpZE11dGF0ZSA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkZWxldGUgY2hnU3RhdGVbaWRdO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gY2hnU3RhdGU7XG4gICAgICAgIH0sIGNvbGxlY3Rpb24uY2hhbmdlU3RhdGUpO1xuXG4gICAgICAgIHJldHVybiBkaWRNdXRhdGUgPyB7IC4uLmNvbGxlY3Rpb24sIGNoYW5nZVN0YXRlIH0gOiBjb2xsZWN0aW9uO1xuXG4gICAgICBjYXNlIE1lcmdlU3RyYXRlZ3kuUHJlc2VydmVDaGFuZ2VzOiB7XG4gICAgICAgIGNvbnN0IHVwc2VydEVudGl0aWVzID0gW10gYXMgVFtdO1xuICAgICAgICBjaGFuZ2VTdGF0ZSA9IGVudGl0aWVzLnJlZHVjZSgoY2hnU3RhdGUsIGVudGl0eSkgPT4ge1xuICAgICAgICAgIGNvbnN0IGlkID0gdGhpcy5zZWxlY3RJZChlbnRpdHkpO1xuICAgICAgICAgIGNvbnN0IGNoYW5nZSA9IGNoZ1N0YXRlW2lkXTtcbiAgICAgICAgICBpZiAoY2hhbmdlKSB7XG4gICAgICAgICAgICBpZiAoIWRpZE11dGF0ZSkge1xuICAgICAgICAgICAgICBjaGdTdGF0ZSA9IHtcbiAgICAgICAgICAgICAgICAuLi5jaGdTdGF0ZSxcbiAgICAgICAgICAgICAgICBbaWRdOiB7XG4gICAgICAgICAgICAgICAgICAuLi5jaGdTdGF0ZVtpZF0hLFxuICAgICAgICAgICAgICAgICAgb3JpZ2luYWxWYWx1ZTogZW50aXR5LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgIGRpZE11dGF0ZSA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHVwc2VydEVudGl0aWVzLnB1c2goZW50aXR5KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGNoZ1N0YXRlO1xuICAgICAgICB9LCBjb2xsZWN0aW9uLmNoYW5nZVN0YXRlKTtcblxuICAgICAgICBjb2xsZWN0aW9uID0gdGhpcy5hZGFwdGVyLnVwc2VydE1hbnkodXBzZXJ0RW50aXRpZXMsIGNvbGxlY3Rpb24pO1xuICAgICAgICByZXR1cm4gZGlkTXV0YXRlID8geyAuLi5jb2xsZWN0aW9uLCBjaGFuZ2VTdGF0ZSB9IDogY29sbGVjdGlvbjtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgLy8gI2VuZHJlZ2lvbiBxdWVyeSAmIHNhdmUgaGVscGVyc1xuXG4gIC8vICNyZWdpb24gdHJhY2sgbWV0aG9kc1xuICAvKipcbiAgICogVHJhY2sgbXVsdGlwbGUgZW50aXRpZXMgYmVmb3JlIGFkZGluZyB0aGVtIHRvIHRoZSBjb2xsZWN0aW9uLlxuICAgKiBEb2VzIE5PVCBhZGQgdG8gdGhlIGNvbGxlY3Rpb24gKHRoZSByZWR1Y2VyJ3Mgam9iKS5cbiAgICogQHBhcmFtIGVudGl0aWVzIFRoZSBlbnRpdGllcyB0byBhZGQuIFRoZXkgbXVzdCBhbGwgaGF2ZSB0aGVpciBpZHMuXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uIFRoZSBlbnRpdHkgY29sbGVjdGlvblxuICAgKiBAcGFyYW0gW21lcmdlU3RyYXRlZ3ldIFRyYWNrIGJ5IGRlZmF1bHQuIERvbid0IHRyYWNrIGlmIGlzIE1lcmdlU3RyYXRlZ3kuSWdub3JlQ2hhbmdlcy5cbiAgICovXG4gIHRyYWNrQWRkTWFueShcbiAgICBlbnRpdGllczogVFtdLFxuICAgIGNvbGxlY3Rpb246IEVudGl0eUNvbGxlY3Rpb248VD4sXG4gICAgbWVyZ2VTdHJhdGVneT86IE1lcmdlU3RyYXRlZ3lcbiAgKTogRW50aXR5Q29sbGVjdGlvbjxUPiB7XG4gICAgaWYgKFxuICAgICAgbWVyZ2VTdHJhdGVneSA9PT0gTWVyZ2VTdHJhdGVneS5JZ25vcmVDaGFuZ2VzIHx8XG4gICAgICBlbnRpdGllcyA9PSBudWxsIHx8XG4gICAgICBlbnRpdGllcy5sZW5ndGggPT09IDBcbiAgICApIHtcbiAgICAgIHJldHVybiBjb2xsZWN0aW9uOyAvLyBub3RoaW5nIHRvIHRyYWNrXG4gICAgfVxuICAgIGxldCBkaWRNdXRhdGUgPSBmYWxzZTtcbiAgICBjb25zdCBjaGFuZ2VTdGF0ZSA9IGVudGl0aWVzLnJlZHVjZSgoY2hnU3RhdGUsIGVudGl0eSkgPT4ge1xuICAgICAgY29uc3QgaWQgPSB0aGlzLnNlbGVjdElkKGVudGl0eSk7XG4gICAgICBpZiAoaWQgPT0gbnVsbCB8fCBpZCA9PT0gJycpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGAke2NvbGxlY3Rpb24uZW50aXR5TmFtZX0gZW50aXR5IGFkZCByZXF1aXJlcyBhIGtleSB0byBiZSB0cmFja2VkYFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgY29uc3QgdHJhY2tlZENoYW5nZSA9IGNoZ1N0YXRlW2lkXTtcblxuICAgICAgaWYgKCF0cmFja2VkQ2hhbmdlKSB7XG4gICAgICAgIGlmICghZGlkTXV0YXRlKSB7XG4gICAgICAgICAgZGlkTXV0YXRlID0gdHJ1ZTtcbiAgICAgICAgICBjaGdTdGF0ZSA9IHsgLi4uY2hnU3RhdGUgfTtcbiAgICAgICAgfVxuICAgICAgICBjaGdTdGF0ZVtpZF0gPSB7IGNoYW5nZVR5cGU6IENoYW5nZVR5cGUuQWRkZWQgfTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjaGdTdGF0ZTtcbiAgICB9LCBjb2xsZWN0aW9uLmNoYW5nZVN0YXRlKTtcbiAgICByZXR1cm4gZGlkTXV0YXRlID8geyAuLi5jb2xsZWN0aW9uLCBjaGFuZ2VTdGF0ZSB9IDogY29sbGVjdGlvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFjayBhbiBlbnRpdHkgYmVmb3JlIGFkZGluZyBpdCB0byB0aGUgY29sbGVjdGlvbi5cbiAgICogRG9lcyBOT1QgYWRkIHRvIHRoZSBjb2xsZWN0aW9uICh0aGUgcmVkdWNlcidzIGpvYikuXG4gICAqIEBwYXJhbSBlbnRpdHkgVGhlIGVudGl0eSB0byBhZGQuIEl0IG11c3QgaGF2ZSBhbiBpZC5cbiAgICogQHBhcmFtIGNvbGxlY3Rpb24gVGhlIGVudGl0eSBjb2xsZWN0aW9uXG4gICAqIEBwYXJhbSBbbWVyZ2VTdHJhdGVneV0gVHJhY2sgYnkgZGVmYXVsdC4gRG9uJ3QgdHJhY2sgaWYgaXMgTWVyZ2VTdHJhdGVneS5JZ25vcmVDaGFuZ2VzLlxuICAgKiBJZiBub3Qgc3BlY2lmaWVkLCBpbXBsZW1lbnRhdGlvbiBzdXBwbGllcyBhIGRlZmF1bHQgc3RyYXRlZ3kuXG4gICAqL1xuICB0cmFja0FkZE9uZShcbiAgICBlbnRpdHk6IFQsXG4gICAgY29sbGVjdGlvbjogRW50aXR5Q29sbGVjdGlvbjxUPixcbiAgICBtZXJnZVN0cmF0ZWd5PzogTWVyZ2VTdHJhdGVneVxuICApOiBFbnRpdHlDb2xsZWN0aW9uPFQ+IHtcbiAgICByZXR1cm4gZW50aXR5ID09IG51bGxcbiAgICAgID8gY29sbGVjdGlvblxuICAgICAgOiB0aGlzLnRyYWNrQWRkTWFueShbZW50aXR5XSwgY29sbGVjdGlvbiwgbWVyZ2VTdHJhdGVneSk7XG4gIH1cblxuICAvKipcbiAgICogVHJhY2sgbXVsdGlwbGUgZW50aXRpZXMgYmVmb3JlIHJlbW92aW5nIHRoZW0gd2l0aCB0aGUgaW50ZW50aW9uIG9mIGRlbGV0aW5nIHRoZW0gb24gdGhlIHNlcnZlci5cbiAgICogRG9lcyBOT1QgcmVtb3ZlIGZyb20gdGhlIGNvbGxlY3Rpb24gKHRoZSByZWR1Y2VyJ3Mgam9iKS5cbiAgICogQHBhcmFtIGtleXMgVGhlIHByaW1hcnkga2V5cyBvZiB0aGUgZW50aXRpZXMgdG8gZGVsZXRlLlxuICAgKiBAcGFyYW0gY29sbGVjdGlvbiBUaGUgZW50aXR5IGNvbGxlY3Rpb25cbiAgICogQHBhcmFtIFttZXJnZVN0cmF0ZWd5XSBUcmFjayBieSBkZWZhdWx0LiBEb24ndCB0cmFjayBpZiBpcyBNZXJnZVN0cmF0ZWd5Lklnbm9yZUNoYW5nZXMuXG4gICAqL1xuICB0cmFja0RlbGV0ZU1hbnkoXG4gICAga2V5czogKG51bWJlciB8IHN0cmluZylbXSxcbiAgICBjb2xsZWN0aW9uOiBFbnRpdHlDb2xsZWN0aW9uPFQ+LFxuICAgIG1lcmdlU3RyYXRlZ3k/OiBNZXJnZVN0cmF0ZWd5XG4gICk6IEVudGl0eUNvbGxlY3Rpb248VD4ge1xuICAgIGlmIChcbiAgICAgIG1lcmdlU3RyYXRlZ3kgPT09IE1lcmdlU3RyYXRlZ3kuSWdub3JlQ2hhbmdlcyB8fFxuICAgICAga2V5cyA9PSBudWxsIHx8XG4gICAgICBrZXlzLmxlbmd0aCA9PT0gMFxuICAgICkge1xuICAgICAgcmV0dXJuIGNvbGxlY3Rpb247IC8vIG5vdGhpbmcgdG8gdHJhY2tcbiAgICB9XG4gICAgbGV0IGRpZE11dGF0ZSA9IGZhbHNlO1xuICAgIGNvbnN0IGVudGl0eU1hcCA9IGNvbGxlY3Rpb24uZW50aXRpZXM7XG4gICAgY29uc3QgY2hhbmdlU3RhdGUgPSBrZXlzLnJlZHVjZSgoY2hnU3RhdGUsIGlkKSA9PiB7XG4gICAgICBjb25zdCBvcmlnaW5hbFZhbHVlID0gZW50aXR5TWFwW2lkXTtcbiAgICAgIGlmIChvcmlnaW5hbFZhbHVlKSB7XG4gICAgICAgIGNvbnN0IHRyYWNrZWRDaGFuZ2UgPSBjaGdTdGF0ZVtpZF07XG4gICAgICAgIGlmICh0cmFja2VkQ2hhbmdlKSB7XG4gICAgICAgICAgaWYgKHRyYWNrZWRDaGFuZ2UuY2hhbmdlVHlwZSA9PT0gQ2hhbmdlVHlwZS5BZGRlZCkge1xuICAgICAgICAgICAgLy8gU3BlY2lhbCBjYXNlOiBzdG9wIHRyYWNraW5nIGFuIGFkZGVkIGVudGl0eSB0aGF0IHlvdSBkZWxldGVcbiAgICAgICAgICAgIC8vIFRoZSBjYWxsZXIgbXVzdCBhbHNvIGRldGVjdCB0aGlzLCByZW1vdmUgaXQgaW1tZWRpYXRlbHkgZnJvbSB0aGUgY29sbGVjdGlvblxuICAgICAgICAgICAgLy8gYW5kIHNraXAgYXR0ZW1wdCB0byBkZWxldGUgb24gdGhlIHNlcnZlci5cbiAgICAgICAgICAgIGNsb25lQ2hnU3RhdGVPbmNlKCk7XG4gICAgICAgICAgICBkZWxldGUgY2hnU3RhdGVbaWRdO1xuICAgICAgICAgIH0gZWxzZSBpZiAodHJhY2tlZENoYW5nZS5jaGFuZ2VUeXBlID09PSBDaGFuZ2VUeXBlLlVwZGF0ZWQpIHtcbiAgICAgICAgICAgIC8vIFNwZWNpYWwgY2FzZTogc3dpdGNoIGNoYW5nZSB0eXBlIGZyb20gVXBkYXRlZCB0byBEZWxldGVkLlxuICAgICAgICAgICAgY2xvbmVDaGdTdGF0ZU9uY2UoKTtcbiAgICAgICAgICAgIGNoZ1N0YXRlW2lkXSA9IHsgLi4uY2hnU3RhdGVbaWRdLCBjaGFuZ2VUeXBlOiBDaGFuZ2VUeXBlLkRlbGV0ZWQgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gU3RhcnQgdHJhY2tpbmcgdGhpcyBlbnRpdHlcbiAgICAgICAgICBjbG9uZUNoZ1N0YXRlT25jZSgpO1xuICAgICAgICAgIGNoZ1N0YXRlW2lkXSA9IHsgY2hhbmdlVHlwZTogQ2hhbmdlVHlwZS5EZWxldGVkLCBvcmlnaW5hbFZhbHVlIH07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBjaGdTdGF0ZTtcblxuICAgICAgZnVuY3Rpb24gY2xvbmVDaGdTdGF0ZU9uY2UoKSB7XG4gICAgICAgIGlmICghZGlkTXV0YXRlKSB7XG4gICAgICAgICAgZGlkTXV0YXRlID0gdHJ1ZTtcbiAgICAgICAgICBjaGdTdGF0ZSA9IHsgLi4uY2hnU3RhdGUgfTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sIGNvbGxlY3Rpb24uY2hhbmdlU3RhdGUpO1xuXG4gICAgcmV0dXJuIGRpZE11dGF0ZSA/IHsgLi4uY29sbGVjdGlvbiwgY2hhbmdlU3RhdGUgfSA6IGNvbGxlY3Rpb247XG4gIH1cblxuICAvKipcbiAgICogVHJhY2sgYW4gZW50aXR5IGJlZm9yZSBpdCBpcyByZW1vdmVkIHdpdGggdGhlIGludGVudGlvbiBvZiBkZWxldGluZyBpdCBvbiB0aGUgc2VydmVyLlxuICAgKiBEb2VzIE5PVCByZW1vdmUgZnJvbSB0aGUgY29sbGVjdGlvbiAodGhlIHJlZHVjZXIncyBqb2IpLlxuICAgKiBAcGFyYW0ga2V5IFRoZSBwcmltYXJ5IGtleSBvZiB0aGUgZW50aXR5IHRvIGRlbGV0ZS5cbiAgICogQHBhcmFtIGNvbGxlY3Rpb24gVGhlIGVudGl0eSBjb2xsZWN0aW9uXG4gICAqIEBwYXJhbSBbbWVyZ2VTdHJhdGVneV0gVHJhY2sgYnkgZGVmYXVsdC4gRG9uJ3QgdHJhY2sgaWYgaXMgTWVyZ2VTdHJhdGVneS5JZ25vcmVDaGFuZ2VzLlxuICAgKi9cbiAgdHJhY2tEZWxldGVPbmUoXG4gICAga2V5OiBudW1iZXIgfCBzdHJpbmcsXG4gICAgY29sbGVjdGlvbjogRW50aXR5Q29sbGVjdGlvbjxUPixcbiAgICBtZXJnZVN0cmF0ZWd5PzogTWVyZ2VTdHJhdGVneVxuICApOiBFbnRpdHlDb2xsZWN0aW9uPFQ+IHtcbiAgICByZXR1cm4ga2V5ID09IG51bGxcbiAgICAgID8gY29sbGVjdGlvblxuICAgICAgOiB0aGlzLnRyYWNrRGVsZXRlTWFueShba2V5XSwgY29sbGVjdGlvbiwgbWVyZ2VTdHJhdGVneSk7XG4gIH1cblxuICAvKipcbiAgICogVHJhY2sgbXVsdGlwbGUgZW50aXRpZXMgYmVmb3JlIHVwZGF0aW5nIHRoZW0gaW4gdGhlIGNvbGxlY3Rpb24uXG4gICAqIERvZXMgTk9UIHVwZGF0ZSB0aGUgY29sbGVjdGlvbiAodGhlIHJlZHVjZXIncyBqb2IpLlxuICAgKiBAcGFyYW0gdXBkYXRlcyBUaGUgZW50aXRpZXMgdG8gdXBkYXRlLlxuICAgKiBAcGFyYW0gY29sbGVjdGlvbiBUaGUgZW50aXR5IGNvbGxlY3Rpb25cbiAgICogQHBhcmFtIFttZXJnZVN0cmF0ZWd5XSBUcmFjayBieSBkZWZhdWx0LiBEb24ndCB0cmFjayBpZiBpcyBNZXJnZVN0cmF0ZWd5Lklnbm9yZUNoYW5nZXMuXG4gICAqL1xuICB0cmFja1VwZGF0ZU1hbnkoXG4gICAgdXBkYXRlczogVXBkYXRlPFQ+W10sXG4gICAgY29sbGVjdGlvbjogRW50aXR5Q29sbGVjdGlvbjxUPixcbiAgICBtZXJnZVN0cmF0ZWd5PzogTWVyZ2VTdHJhdGVneVxuICApOiBFbnRpdHlDb2xsZWN0aW9uPFQ+IHtcbiAgICBpZiAoXG4gICAgICBtZXJnZVN0cmF0ZWd5ID09PSBNZXJnZVN0cmF0ZWd5Lklnbm9yZUNoYW5nZXMgfHxcbiAgICAgIHVwZGF0ZXMgPT0gbnVsbCB8fFxuICAgICAgdXBkYXRlcy5sZW5ndGggPT09IDBcbiAgICApIHtcbiAgICAgIHJldHVybiBjb2xsZWN0aW9uOyAvLyBub3RoaW5nIHRvIHRyYWNrXG4gICAgfVxuICAgIGxldCBkaWRNdXRhdGUgPSBmYWxzZTtcbiAgICBjb25zdCBlbnRpdHlNYXAgPSBjb2xsZWN0aW9uLmVudGl0aWVzO1xuICAgIGNvbnN0IGNoYW5nZVN0YXRlID0gdXBkYXRlcy5yZWR1Y2UoKGNoZ1N0YXRlLCB1cGRhdGUpID0+IHtcbiAgICAgIGNvbnN0IHsgaWQsIGNoYW5nZXM6IGVudGl0eSB9ID0gdXBkYXRlO1xuICAgICAgaWYgKGlkID09IG51bGwgfHwgaWQgPT09ICcnKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgJHtjb2xsZWN0aW9uLmVudGl0eU5hbWV9IGVudGl0eSB1cGRhdGUgcmVxdWlyZXMgYSBrZXkgdG8gYmUgdHJhY2tlZGBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IG9yaWdpbmFsVmFsdWUgPSBlbnRpdHlNYXBbaWRdO1xuICAgICAgLy8gT25seSB0cmFjayBpZiBpdCBpcyBpbiB0aGUgY29sbGVjdGlvbi4gU2lsZW50bHkgaWdub3JlIGlmIGl0IGlzIG5vdC5cbiAgICAgIC8vIEBuZ3J4L2VudGl0eSBhZGFwdGVyIHdvdWxkIGFsc28gc2lsZW50bHkgaWdub3JlLlxuICAgICAgLy8gVG9kbzogc2hvdWxkIG1pc3NpbmcgdXBkYXRlIGVudGl0eSByZWFsbHkgYmUgcmVwb3J0ZWQgYXMgYW4gZXJyb3I/XG4gICAgICBpZiAob3JpZ2luYWxWYWx1ZSkge1xuICAgICAgICBjb25zdCB0cmFja2VkQ2hhbmdlID0gY2hnU3RhdGVbaWRdO1xuICAgICAgICBpZiAoIXRyYWNrZWRDaGFuZ2UpIHtcbiAgICAgICAgICBpZiAoIWRpZE11dGF0ZSkge1xuICAgICAgICAgICAgZGlkTXV0YXRlID0gdHJ1ZTtcbiAgICAgICAgICAgIGNoZ1N0YXRlID0geyAuLi5jaGdTdGF0ZSB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICBjaGdTdGF0ZVtpZF0gPSB7IGNoYW5nZVR5cGU6IENoYW5nZVR5cGUuVXBkYXRlZCwgb3JpZ2luYWxWYWx1ZSB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gY2hnU3RhdGU7XG4gICAgfSwgY29sbGVjdGlvbi5jaGFuZ2VTdGF0ZSk7XG4gICAgcmV0dXJuIGRpZE11dGF0ZSA/IHsgLi4uY29sbGVjdGlvbiwgY2hhbmdlU3RhdGUgfSA6IGNvbGxlY3Rpb247XG4gIH1cblxuICAvKipcbiAgICogVHJhY2sgYW4gZW50aXR5IGJlZm9yZSB1cGRhdGluZyBpdCBpbiB0aGUgY29sbGVjdGlvbi5cbiAgICogRG9lcyBOT1QgdXBkYXRlIHRoZSBjb2xsZWN0aW9uICh0aGUgcmVkdWNlcidzIGpvYikuXG4gICAqIEBwYXJhbSB1cGRhdGUgVGhlIGVudGl0eSB0byB1cGRhdGUuXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uIFRoZSBlbnRpdHkgY29sbGVjdGlvblxuICAgKiBAcGFyYW0gW21lcmdlU3RyYXRlZ3ldIFRyYWNrIGJ5IGRlZmF1bHQuIERvbid0IHRyYWNrIGlmIGlzIE1lcmdlU3RyYXRlZ3kuSWdub3JlQ2hhbmdlcy5cbiAgICovXG4gIHRyYWNrVXBkYXRlT25lKFxuICAgIHVwZGF0ZTogVXBkYXRlPFQ+LFxuICAgIGNvbGxlY3Rpb246IEVudGl0eUNvbGxlY3Rpb248VD4sXG4gICAgbWVyZ2VTdHJhdGVneT86IE1lcmdlU3RyYXRlZ3lcbiAgKTogRW50aXR5Q29sbGVjdGlvbjxUPiB7XG4gICAgcmV0dXJuIHVwZGF0ZSA9PSBudWxsXG4gICAgICA/IGNvbGxlY3Rpb25cbiAgICAgIDogdGhpcy50cmFja1VwZGF0ZU1hbnkoW3VwZGF0ZV0sIGNvbGxlY3Rpb24sIG1lcmdlU3RyYXRlZ3kpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYWNrIG11bHRpcGxlIGVudGl0aWVzIGJlZm9yZSB1cHNlcnRpbmcgKGFkZGluZyBhbmQgdXBkYXRpbmcpIHRoZW0gdG8gdGhlIGNvbGxlY3Rpb24uXG4gICAqIERvZXMgTk9UIHVwZGF0ZSB0aGUgY29sbGVjdGlvbiAodGhlIHJlZHVjZXIncyBqb2IpLlxuICAgKiBAcGFyYW0gZW50aXRpZXMgVGhlIGVudGl0aWVzIHRvIGFkZCBvciB1cGRhdGUuIFRoZXkgbXVzdCBiZSBjb21wbGV0ZSBlbnRpdGllcyB3aXRoIGlkcy5cbiAgICogQHBhcmFtIGNvbGxlY3Rpb24gVGhlIGVudGl0eSBjb2xsZWN0aW9uXG4gICAqIEBwYXJhbSBbbWVyZ2VTdHJhdGVneV0gVHJhY2sgYnkgZGVmYXVsdC4gRG9uJ3QgdHJhY2sgaWYgaXMgTWVyZ2VTdHJhdGVneS5JZ25vcmVDaGFuZ2VzLlxuICAgKi9cbiAgdHJhY2tVcHNlcnRNYW55KFxuICAgIGVudGl0aWVzOiBUW10sXG4gICAgY29sbGVjdGlvbjogRW50aXR5Q29sbGVjdGlvbjxUPixcbiAgICBtZXJnZVN0cmF0ZWd5PzogTWVyZ2VTdHJhdGVneVxuICApOiBFbnRpdHlDb2xsZWN0aW9uPFQ+IHtcbiAgICBpZiAoXG4gICAgICBtZXJnZVN0cmF0ZWd5ID09PSBNZXJnZVN0cmF0ZWd5Lklnbm9yZUNoYW5nZXMgfHxcbiAgICAgIGVudGl0aWVzID09IG51bGwgfHxcbiAgICAgIGVudGl0aWVzLmxlbmd0aCA9PT0gMFxuICAgICkge1xuICAgICAgcmV0dXJuIGNvbGxlY3Rpb247IC8vIG5vdGhpbmcgdG8gdHJhY2tcbiAgICB9XG4gICAgbGV0IGRpZE11dGF0ZSA9IGZhbHNlO1xuICAgIGNvbnN0IGVudGl0eU1hcCA9IGNvbGxlY3Rpb24uZW50aXRpZXM7XG4gICAgY29uc3QgY2hhbmdlU3RhdGUgPSBlbnRpdGllcy5yZWR1Y2UoKGNoZ1N0YXRlLCBlbnRpdHkpID0+IHtcbiAgICAgIGNvbnN0IGlkID0gdGhpcy5zZWxlY3RJZChlbnRpdHkpO1xuICAgICAgaWYgKGlkID09IG51bGwgfHwgaWQgPT09ICcnKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgJHtjb2xsZWN0aW9uLmVudGl0eU5hbWV9IGVudGl0eSB1cHNlcnQgcmVxdWlyZXMgYSBrZXkgdG8gYmUgdHJhY2tlZGBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHRyYWNrZWRDaGFuZ2UgPSBjaGdTdGF0ZVtpZF07XG5cbiAgICAgIGlmICghdHJhY2tlZENoYW5nZSkge1xuICAgICAgICBpZiAoIWRpZE11dGF0ZSkge1xuICAgICAgICAgIGRpZE11dGF0ZSA9IHRydWU7XG4gICAgICAgICAgY2hnU3RhdGUgPSB7IC4uLmNoZ1N0YXRlIH07XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBvcmlnaW5hbFZhbHVlID0gZW50aXR5TWFwW2lkXTtcbiAgICAgICAgY2hnU3RhdGVbaWRdID1cbiAgICAgICAgICBvcmlnaW5hbFZhbHVlID09IG51bGxcbiAgICAgICAgICAgID8geyBjaGFuZ2VUeXBlOiBDaGFuZ2VUeXBlLkFkZGVkIH1cbiAgICAgICAgICAgIDogeyBjaGFuZ2VUeXBlOiBDaGFuZ2VUeXBlLlVwZGF0ZWQsIG9yaWdpbmFsVmFsdWUgfTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjaGdTdGF0ZTtcbiAgICB9LCBjb2xsZWN0aW9uLmNoYW5nZVN0YXRlKTtcbiAgICByZXR1cm4gZGlkTXV0YXRlID8geyAuLi5jb2xsZWN0aW9uLCBjaGFuZ2VTdGF0ZSB9IDogY29sbGVjdGlvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFjayBhbiBlbnRpdHkgYmVmb3JlIHVwc2VydCAoYWRkaW5nIGFuZCB1cGRhdGluZykgaXQgdG8gdGhlIGNvbGxlY3Rpb24uXG4gICAqIERvZXMgTk9UIHVwZGF0ZSB0aGUgY29sbGVjdGlvbiAodGhlIHJlZHVjZXIncyBqb2IpLlxuICAgKiBAcGFyYW0gZW50aXRpZXMgVGhlIGVudGl0eSB0byBhZGQgb3IgdXBkYXRlLiBJdCBtdXN0IGJlIGEgY29tcGxldGUgZW50aXR5IHdpdGggaXRzIGlkLlxuICAgKiBAcGFyYW0gY29sbGVjdGlvbiBUaGUgZW50aXR5IGNvbGxlY3Rpb25cbiAgICogQHBhcmFtIFttZXJnZVN0cmF0ZWd5XSBUcmFjayBieSBkZWZhdWx0LiBEb24ndCB0cmFjayBpZiBpcyBNZXJnZVN0cmF0ZWd5Lklnbm9yZUNoYW5nZXMuXG4gICAqL1xuICB0cmFja1Vwc2VydE9uZShcbiAgICBlbnRpdHk6IFQsXG4gICAgY29sbGVjdGlvbjogRW50aXR5Q29sbGVjdGlvbjxUPixcbiAgICBtZXJnZVN0cmF0ZWd5PzogTWVyZ2VTdHJhdGVneVxuICApOiBFbnRpdHlDb2xsZWN0aW9uPFQ+IHtcbiAgICByZXR1cm4gZW50aXR5ID09IG51bGxcbiAgICAgID8gY29sbGVjdGlvblxuICAgICAgOiB0aGlzLnRyYWNrVXBzZXJ0TWFueShbZW50aXR5XSwgY29sbGVjdGlvbiwgbWVyZ2VTdHJhdGVneSk7XG4gIH1cbiAgLy8gI2VuZHJlZ2lvbiB0cmFjayBtZXRob2RzXG5cbiAgLy8gI3JlZ2lvbiB1bmRvIG1ldGhvZHNcbiAgLyoqXG4gICAqIFJldmVydCB0aGUgdW5zYXZlZCBjaGFuZ2VzIGZvciBhbGwgY29sbGVjdGlvbi5cbiAgICogSGFybWxlc3Mgd2hlbiB0aGVyZSBhcmUgbm8gZW50aXR5IGNoYW5nZXMgdG8gdW5kby5cbiAgICogQHBhcmFtIGNvbGxlY3Rpb24gVGhlIGVudGl0eSBjb2xsZWN0aW9uXG4gICAqL1xuICB1bmRvQWxsKGNvbGxlY3Rpb246IEVudGl0eUNvbGxlY3Rpb248VD4pOiBFbnRpdHlDb2xsZWN0aW9uPFQ+IHtcbiAgICBjb25zdCBpZHMgPSBPYmplY3Qua2V5cyhjb2xsZWN0aW9uLmNoYW5nZVN0YXRlKTtcblxuICAgIGNvbnN0IHsgcmVtb3ZlLCB1cHNlcnQgfSA9IGlkcy5yZWR1Y2UoXG4gICAgICAoYWNjLCBpZCkgPT4ge1xuICAgICAgICBjb25zdCBjaGFuZ2VTdGF0ZSA9IGFjYy5jaGdTdGF0ZVtpZF0hO1xuICAgICAgICBzd2l0Y2ggKGNoYW5nZVN0YXRlLmNoYW5nZVR5cGUpIHtcbiAgICAgICAgICBjYXNlIENoYW5nZVR5cGUuQWRkZWQ6XG4gICAgICAgICAgICBhY2MucmVtb3ZlLnB1c2goaWQpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgY2FzZSBDaGFuZ2VUeXBlLkRlbGV0ZWQ6XG4gICAgICAgICAgICBjb25zdCByZW1vdmVkID0gY2hhbmdlU3RhdGUhLm9yaWdpbmFsVmFsdWU7XG4gICAgICAgICAgICBpZiAocmVtb3ZlZCkge1xuICAgICAgICAgICAgICBhY2MudXBzZXJ0LnB1c2gocmVtb3ZlZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlIENoYW5nZVR5cGUuVXBkYXRlZDpcbiAgICAgICAgICAgIGFjYy51cHNlcnQucHVzaChjaGFuZ2VTdGF0ZSEub3JpZ2luYWxWYWx1ZSEpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sXG4gICAgICAvLyBlbnRpdGllc1RvVW5kb1xuICAgICAge1xuICAgICAgICByZW1vdmU6IFtdIGFzIChudW1iZXIgfCBzdHJpbmcpW10sXG4gICAgICAgIHVwc2VydDogW10gYXMgVFtdLFxuICAgICAgICBjaGdTdGF0ZTogY29sbGVjdGlvbi5jaGFuZ2VTdGF0ZSxcbiAgICAgIH1cbiAgICApO1xuXG4gICAgY29sbGVjdGlvbiA9IHRoaXMuYWRhcHRlci5yZW1vdmVNYW55KHJlbW92ZSBhcyBzdHJpbmdbXSwgY29sbGVjdGlvbik7XG4gICAgY29sbGVjdGlvbiA9IHRoaXMuYWRhcHRlci51cHNlcnRNYW55KHVwc2VydCwgY29sbGVjdGlvbik7XG5cbiAgICByZXR1cm4geyAuLi5jb2xsZWN0aW9uLCBjaGFuZ2VTdGF0ZToge30gfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXZlcnQgdGhlIHVuc2F2ZWQgY2hhbmdlcyBmb3IgdGhlIGdpdmVuIGVudGl0aWVzLlxuICAgKiBIYXJtbGVzcyB3aGVuIHRoZXJlIGFyZSBubyBlbnRpdHkgY2hhbmdlcyB0byB1bmRvLlxuICAgKiBAcGFyYW0gZW50aXR5T3JJZExpc3QgVGhlIGVudGl0aWVzIHRvIHJldmVydCBvciB0aGVpciBpZHMuXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uIFRoZSBlbnRpdHkgY29sbGVjdGlvblxuICAgKi9cbiAgdW5kb01hbnkoXG4gICAgZW50aXR5T3JJZExpc3Q6IChudW1iZXIgfCBzdHJpbmcgfCBUKVtdLFxuICAgIGNvbGxlY3Rpb246IEVudGl0eUNvbGxlY3Rpb248VD5cbiAgKTogRW50aXR5Q29sbGVjdGlvbjxUPiB7XG4gICAgaWYgKGVudGl0eU9ySWRMaXN0ID09IG51bGwgfHwgZW50aXR5T3JJZExpc3QubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gY29sbGVjdGlvbjsgLy8gbm90aGluZyB0byB1bmRvXG4gICAgfVxuICAgIGxldCBkaWRNdXRhdGUgPSBmYWxzZTtcblxuICAgIGNvbnN0IHsgY2hhbmdlU3RhdGUsIHJlbW92ZSwgdXBzZXJ0IH0gPSBlbnRpdHlPcklkTGlzdC5yZWR1Y2UoXG4gICAgICAoYWNjLCBlbnRpdHlPcklkKSA9PiB7XG4gICAgICAgIGxldCBjaGdTdGF0ZSA9IGFjYy5jaGFuZ2VTdGF0ZTtcbiAgICAgICAgY29uc3QgaWQgPVxuICAgICAgICAgIHR5cGVvZiBlbnRpdHlPcklkID09PSAnb2JqZWN0J1xuICAgICAgICAgICAgPyB0aGlzLnNlbGVjdElkKGVudGl0eU9ySWQpXG4gICAgICAgICAgICA6IChlbnRpdHlPcklkIGFzIHN0cmluZyB8IG51bWJlcik7XG4gICAgICAgIGNvbnN0IGNoYW5nZSA9IGNoZ1N0YXRlW2lkXSE7XG4gICAgICAgIGlmIChjaGFuZ2UpIHtcbiAgICAgICAgICBpZiAoIWRpZE11dGF0ZSkge1xuICAgICAgICAgICAgY2hnU3RhdGUgPSB7IC4uLmNoZ1N0YXRlIH07XG4gICAgICAgICAgICBkaWRNdXRhdGUgPSB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgICBkZWxldGUgY2hnU3RhdGVbaWRdOyAvLyBjbGVhciB0cmFja2luZyBvZiB0aGlzIGVudGl0eVxuICAgICAgICAgIGFjYy5jaGFuZ2VTdGF0ZSA9IGNoZ1N0YXRlO1xuICAgICAgICAgIHN3aXRjaCAoY2hhbmdlLmNoYW5nZVR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgQ2hhbmdlVHlwZS5BZGRlZDpcbiAgICAgICAgICAgICAgYWNjLnJlbW92ZS5wdXNoKGlkKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIENoYW5nZVR5cGUuRGVsZXRlZDpcbiAgICAgICAgICAgICAgY29uc3QgcmVtb3ZlZCA9IGNoYW5nZSEub3JpZ2luYWxWYWx1ZTtcbiAgICAgICAgICAgICAgaWYgKHJlbW92ZWQpIHtcbiAgICAgICAgICAgICAgICBhY2MudXBzZXJ0LnB1c2gocmVtb3ZlZCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIENoYW5nZVR5cGUuVXBkYXRlZDpcbiAgICAgICAgICAgICAgYWNjLnVwc2VydC5wdXNoKGNoYW5nZSEub3JpZ2luYWxWYWx1ZSEpO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgIH0sXG4gICAgICAvLyBlbnRpdGllc1RvVW5kb1xuICAgICAge1xuICAgICAgICByZW1vdmU6IFtdIGFzIChudW1iZXIgfCBzdHJpbmcpW10sXG4gICAgICAgIHVwc2VydDogW10gYXMgVFtdLFxuICAgICAgICBjaGFuZ2VTdGF0ZTogY29sbGVjdGlvbi5jaGFuZ2VTdGF0ZSxcbiAgICAgIH1cbiAgICApO1xuXG4gICAgY29sbGVjdGlvbiA9IHRoaXMuYWRhcHRlci5yZW1vdmVNYW55KHJlbW92ZSBhcyBzdHJpbmdbXSwgY29sbGVjdGlvbik7XG4gICAgY29sbGVjdGlvbiA9IHRoaXMuYWRhcHRlci51cHNlcnRNYW55KHVwc2VydCwgY29sbGVjdGlvbik7XG4gICAgcmV0dXJuIGRpZE11dGF0ZSA/IHsgLi4uY29sbGVjdGlvbiwgY2hhbmdlU3RhdGUgfSA6IGNvbGxlY3Rpb247XG4gIH1cblxuICAvKipcbiAgICogUmV2ZXJ0IHRoZSB1bnNhdmVkIGNoYW5nZXMgZm9yIHRoZSBnaXZlbiBlbnRpdHkuXG4gICAqIEhhcm1sZXNzIHdoZW4gdGhlcmUgYXJlIG5vIGVudGl0eSBjaGFuZ2VzIHRvIHVuZG8uXG4gICAqIEBwYXJhbSBlbnRpdHlPcklkIFRoZSBlbnRpdHkgdG8gcmV2ZXJ0IG9yIGl0cyBpZC5cbiAgICogQHBhcmFtIGNvbGxlY3Rpb24gVGhlIGVudGl0eSBjb2xsZWN0aW9uXG4gICAqL1xuICB1bmRvT25lKFxuICAgIGVudGl0eU9ySWQ6IG51bWJlciB8IHN0cmluZyB8IFQsXG4gICAgY29sbGVjdGlvbjogRW50aXR5Q29sbGVjdGlvbjxUPlxuICApOiBFbnRpdHlDb2xsZWN0aW9uPFQ+IHtcbiAgICByZXR1cm4gZW50aXR5T3JJZCA9PSBudWxsXG4gICAgICA/IGNvbGxlY3Rpb25cbiAgICAgIDogdGhpcy51bmRvTWFueShbZW50aXR5T3JJZF0sIGNvbGxlY3Rpb24pO1xuICB9XG4gIC8vICNlbmRyZWdpb24gdW5kbyBtZXRob2RzXG59XG4iXX0=
|