parse-server 9.9.0-alpha.2 → 9.9.0-alpha.3

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,178 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.applyDuplicateDeviceTokenMerge = applyDuplicateDeviceTokenMerge;
7
+ exports.default = void 0;
8
+ exports.removeConflictingDeviceToken = removeConflictingDeviceToken;
9
+ var _node = _interopRequireDefault(require("parse/node"));
10
+ var _logger = _interopRequireDefault(require("./logger"));
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ const CLASS_NAME = '_Installation';
13
+ function logResult(action, count, err) {
14
+ if (err && err.code === _node.default.Error.OBJECT_NOT_FOUND) {
15
+ _logger.default.verbose(`Installation dedup ${action} matched no rows; nothing to do.`);
16
+ return;
17
+ }
18
+ if (err && err.code === _node.default.Error.OPERATION_FORBIDDEN) {
19
+ _logger.default.warn(`Installation dedup ${action} skipped: caller has no permission to ${action} the conflicting row(s). The conflicting row remains.`);
20
+ return;
21
+ }
22
+ if (err) {
23
+ _logger.default.error(`Installation dedup ${action} failed: ${err.message || err}`);
24
+ return;
25
+ }
26
+ _logger.default.verbose(`Installation dedup ${action} applied to ${count == null ? 'matching' : count} conflicting row(s).`);
27
+ }
28
+ async function performAction({
29
+ database,
30
+ query,
31
+ action,
32
+ fieldToClear,
33
+ runOptions,
34
+ many,
35
+ validSchemaController
36
+ }) {
37
+ if (action === 'delete') {
38
+ return database.destroy(CLASS_NAME, query, runOptions, validSchemaController);
39
+ }
40
+ if (action === 'update') {
41
+ return database.update(CLASS_NAME, query, {
42
+ [fieldToClear]: {
43
+ __op: 'Delete'
44
+ }
45
+ }, {
46
+ ...runOptions,
47
+ many
48
+ }, false, false, validSchemaController);
49
+ }
50
+ throw new Error(`Unknown installation dedup action: ${action}`);
51
+ }
52
+
53
+ /**
54
+ * Removes or updates `_Installation` rows that hold a `deviceToken` matching the query,
55
+ * allowing the caller to claim that `deviceToken` exclusively. Used when a new or updated
56
+ * install collides with one or more existing rows on `deviceToken`.
57
+ *
58
+ * @param {Object} options
59
+ * @param {DatabaseController} options.database
60
+ * @param {Object} options.query e.g. { deviceToken: 'X', installationId: { $ne: 'I' } }
61
+ * @param {'delete'|'update'} options.action
62
+ * @param {boolean} options.enforceAuth
63
+ * @param {Object} options.runOptions RestWrite.runOptions
64
+ * @param {SchemaController} options.validSchemaController
65
+ */
66
+ async function removeConflictingDeviceToken({
67
+ database,
68
+ query,
69
+ action,
70
+ enforceAuth,
71
+ runOptions,
72
+ validSchemaController
73
+ }) {
74
+ const opts = enforceAuth ? runOptions : {};
75
+ try {
76
+ await performAction({
77
+ database,
78
+ query,
79
+ action,
80
+ fieldToClear: 'deviceToken',
81
+ runOptions: opts,
82
+ many: true,
83
+ validSchemaController
84
+ });
85
+ logResult(action, null, null);
86
+ } catch (err) {
87
+ if (err && err.code === _node.default.Error.OBJECT_NOT_FOUND) {
88
+ logResult(action, 0, err);
89
+ return;
90
+ }
91
+ if (err && err.code === _node.default.Error.OPERATION_FORBIDDEN) {
92
+ logResult(action, null, err);
93
+ return;
94
+ }
95
+ logResult(action, null, err);
96
+ throw err;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Resolves a merge conflict between two `_Installation` rows that together represent the
102
+ * same install: one matched by `installationId`/`objectId` (`idMatch`), and another holding
103
+ * the same `deviceToken` but no `installationId` (`deviceTokenMatch`). The `mergePriority`
104
+ * determines which row survives; the loser receives the configured `action`. Returns the
105
+ * survivor's `objectId` so the save flow can target it.
106
+ *
107
+ * @param {Object} options
108
+ * @param {DatabaseController} options.database
109
+ * @param {{ objectId: string, installationId?: string, deviceToken?: string }} options.idMatch
110
+ * @param {{ objectId: string, deviceToken?: string }} options.deviceTokenMatch
111
+ * @param {'delete'|'update'} options.action
112
+ * @param {'deviceToken'|'installationId'} options.mergePriority
113
+ * @param {boolean} options.enforceAuth
114
+ * @param {Object} options.runOptions
115
+ * @param {SchemaController} options.validSchemaController
116
+ * @returns {Promise<string>} survivor's objectId
117
+ */
118
+ async function applyDuplicateDeviceTokenMerge({
119
+ database,
120
+ idMatch,
121
+ deviceTokenMatch,
122
+ action,
123
+ mergePriority,
124
+ enforceAuth,
125
+ runOptions,
126
+ validSchemaController
127
+ }) {
128
+ // Self-merge guard: when both matches resolve to the same row, there's
129
+ // nothing to clean up. Skip the action so we don't destroy/update the row
130
+ // we're about to return as the survivor.
131
+ if (idMatch.objectId === deviceTokenMatch.objectId) {
132
+ return idMatch.objectId;
133
+ }
134
+ const opts = enforceAuth ? runOptions : {};
135
+ let loser;
136
+ let survivorId;
137
+ let fieldToClear;
138
+ if (mergePriority === 'deviceToken') {
139
+ loser = idMatch;
140
+ survivorId = deviceTokenMatch.objectId;
141
+ fieldToClear = 'installationId';
142
+ } else if (mergePriority === 'installationId') {
143
+ loser = deviceTokenMatch;
144
+ survivorId = idMatch.objectId;
145
+ fieldToClear = 'deviceToken';
146
+ } else {
147
+ throw new Error(`Unknown installation dedup mergePriority: ${mergePriority}`);
148
+ }
149
+ try {
150
+ await performAction({
151
+ database,
152
+ query: {
153
+ objectId: loser.objectId
154
+ },
155
+ action,
156
+ fieldToClear,
157
+ runOptions: opts,
158
+ many: false,
159
+ validSchemaController
160
+ });
161
+ logResult(action, 1, null);
162
+ } catch (err) {
163
+ if (err && err.code === _node.default.Error.OBJECT_NOT_FOUND) {
164
+ logResult(action, 0, err);
165
+ } else if (err && err.code === _node.default.Error.OPERATION_FORBIDDEN) {
166
+ logResult(action, null, err);
167
+ } else {
168
+ logResult(action, null, err);
169
+ throw err;
170
+ }
171
+ }
172
+ return survivorId;
173
+ }
174
+ var _default = exports.default = {
175
+ removeConflictingDeviceToken,
176
+ applyDuplicateDeviceTokenMerge
177
+ };
178
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbm9kZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX2xvZ2dlciIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsIkNMQVNTX05BTUUiLCJsb2dSZXN1bHQiLCJhY3Rpb24iLCJjb3VudCIsImVyciIsImNvZGUiLCJQYXJzZSIsIkVycm9yIiwiT0JKRUNUX05PVF9GT1VORCIsImxvZ2dlciIsInZlcmJvc2UiLCJPUEVSQVRJT05fRk9SQklEREVOIiwid2FybiIsImVycm9yIiwibWVzc2FnZSIsInBlcmZvcm1BY3Rpb24iLCJkYXRhYmFzZSIsInF1ZXJ5IiwiZmllbGRUb0NsZWFyIiwicnVuT3B0aW9ucyIsIm1hbnkiLCJ2YWxpZFNjaGVtYUNvbnRyb2xsZXIiLCJkZXN0cm95IiwidXBkYXRlIiwiX19vcCIsInJlbW92ZUNvbmZsaWN0aW5nRGV2aWNlVG9rZW4iLCJlbmZvcmNlQXV0aCIsIm9wdHMiLCJhcHBseUR1cGxpY2F0ZURldmljZVRva2VuTWVyZ2UiLCJpZE1hdGNoIiwiZGV2aWNlVG9rZW5NYXRjaCIsIm1lcmdlUHJpb3JpdHkiLCJvYmplY3RJZCIsImxvc2VyIiwic3Vydml2b3JJZCIsIl9kZWZhdWx0IiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uL3NyYy9JbnN0YWxsYXRpb25EZWR1cC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUGFyc2UgZnJvbSAncGFyc2Uvbm9kZSc7XG5pbXBvcnQgbG9nZ2VyIGZyb20gJy4vbG9nZ2VyJztcblxuY29uc3QgQ0xBU1NfTkFNRSA9ICdfSW5zdGFsbGF0aW9uJztcblxuZnVuY3Rpb24gbG9nUmVzdWx0KGFjdGlvbiwgY291bnQsIGVycikge1xuICBpZiAoZXJyICYmIGVyci5jb2RlID09PSBQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5EKSB7XG4gICAgbG9nZ2VyLnZlcmJvc2UoYEluc3RhbGxhdGlvbiBkZWR1cCAke2FjdGlvbn0gbWF0Y2hlZCBubyByb3dzOyBub3RoaW5nIHRvIGRvLmApO1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoZXJyICYmIGVyci5jb2RlID09PSBQYXJzZS5FcnJvci5PUEVSQVRJT05fRk9SQklEREVOKSB7XG4gICAgbG9nZ2VyLndhcm4oXG4gICAgICBgSW5zdGFsbGF0aW9uIGRlZHVwICR7YWN0aW9ufSBza2lwcGVkOiBjYWxsZXIgaGFzIG5vIHBlcm1pc3Npb24gdG8gJHthY3Rpb259IHRoZSBjb25mbGljdGluZyByb3cocykuIFRoZSBjb25mbGljdGluZyByb3cgcmVtYWlucy5gXG4gICAgKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGVycikge1xuICAgIGxvZ2dlci5lcnJvcihgSW5zdGFsbGF0aW9uIGRlZHVwICR7YWN0aW9ufSBmYWlsZWQ6ICR7ZXJyLm1lc3NhZ2UgfHwgZXJyfWApO1xuICAgIHJldHVybjtcbiAgfVxuICBsb2dnZXIudmVyYm9zZShcbiAgICBgSW5zdGFsbGF0aW9uIGRlZHVwICR7YWN0aW9ufSBhcHBsaWVkIHRvICR7Y291bnQgPT0gbnVsbCA/ICdtYXRjaGluZycgOiBjb3VudH0gY29uZmxpY3Rpbmcgcm93KHMpLmBcbiAgKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcGVyZm9ybUFjdGlvbih7XG4gIGRhdGFiYXNlLFxuICBxdWVyeSxcbiAgYWN0aW9uLFxuICBmaWVsZFRvQ2xlYXIsXG4gIHJ1bk9wdGlvbnMsXG4gIG1hbnksXG4gIHZhbGlkU2NoZW1hQ29udHJvbGxlcixcbn0pIHtcbiAgaWYgKGFjdGlvbiA9PT0gJ2RlbGV0ZScpIHtcbiAgICByZXR1cm4gZGF0YWJhc2UuZGVzdHJveShDTEFTU19OQU1FLCBxdWVyeSwgcnVuT3B0aW9ucywgdmFsaWRTY2hlbWFDb250cm9sbGVyKTtcbiAgfVxuICBpZiAoYWN0aW9uID09PSAndXBkYXRlJykge1xuICAgIHJldHVybiBkYXRhYmFzZS51cGRhdGUoXG4gICAgICBDTEFTU19OQU1FLFxuICAgICAgcXVlcnksXG4gICAgICB7IFtmaWVsZFRvQ2xlYXJdOiB7IF9fb3A6ICdEZWxldGUnIH0gfSxcbiAgICAgIHsgLi4ucnVuT3B0aW9ucywgbWFueSB9LFxuICAgICAgZmFsc2UsXG4gICAgICBmYWxzZSxcbiAgICAgIHZhbGlkU2NoZW1hQ29udHJvbGxlclxuICAgICk7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIGluc3RhbGxhdGlvbiBkZWR1cCBhY3Rpb246ICR7YWN0aW9ufWApO1xufVxuXG4vKipcbiAqIFJlbW92ZXMgb3IgdXBkYXRlcyBgX0luc3RhbGxhdGlvbmAgcm93cyB0aGF0IGhvbGQgYSBgZGV2aWNlVG9rZW5gIG1hdGNoaW5nIHRoZSBxdWVyeSxcbiAqIGFsbG93aW5nIHRoZSBjYWxsZXIgdG8gY2xhaW0gdGhhdCBgZGV2aWNlVG9rZW5gIGV4Y2x1c2l2ZWx5LiBVc2VkIHdoZW4gYSBuZXcgb3IgdXBkYXRlZFxuICogaW5zdGFsbCBjb2xsaWRlcyB3aXRoIG9uZSBvciBtb3JlIGV4aXN0aW5nIHJvd3Mgb24gYGRldmljZVRva2VuYC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xuICogQHBhcmFtIHtEYXRhYmFzZUNvbnRyb2xsZXJ9IG9wdGlvbnMuZGF0YWJhc2VcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zLnF1ZXJ5IGUuZy4geyBkZXZpY2VUb2tlbjogJ1gnLCBpbnN0YWxsYXRpb25JZDogeyAkbmU6ICdJJyB9IH1cbiAqIEBwYXJhbSB7J2RlbGV0ZSd8J3VwZGF0ZSd9IG9wdGlvbnMuYWN0aW9uXG4gKiBAcGFyYW0ge2Jvb2xlYW59IG9wdGlvbnMuZW5mb3JjZUF1dGhcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zLnJ1bk9wdGlvbnMgUmVzdFdyaXRlLnJ1bk9wdGlvbnNcbiAqIEBwYXJhbSB7U2NoZW1hQ29udHJvbGxlcn0gb3B0aW9ucy52YWxpZFNjaGVtYUNvbnRyb2xsZXJcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlbW92ZUNvbmZsaWN0aW5nRGV2aWNlVG9rZW4oe1xuICBkYXRhYmFzZSxcbiAgcXVlcnksXG4gIGFjdGlvbixcbiAgZW5mb3JjZUF1dGgsXG4gIHJ1bk9wdGlvbnMsXG4gIHZhbGlkU2NoZW1hQ29udHJvbGxlcixcbn0pIHtcbiAgY29uc3Qgb3B0cyA9IGVuZm9yY2VBdXRoID8gcnVuT3B0aW9ucyA6IHt9O1xuICB0cnkge1xuICAgIGF3YWl0IHBlcmZvcm1BY3Rpb24oe1xuICAgICAgZGF0YWJhc2UsXG4gICAgICBxdWVyeSxcbiAgICAgIGFjdGlvbixcbiAgICAgIGZpZWxkVG9DbGVhcjogJ2RldmljZVRva2VuJyxcbiAgICAgIHJ1bk9wdGlvbnM6IG9wdHMsXG4gICAgICBtYW55OiB0cnVlLFxuICAgICAgdmFsaWRTY2hlbWFDb250cm9sbGVyLFxuICAgIH0pO1xuICAgIGxvZ1Jlc3VsdChhY3Rpb24sIG51bGwsIG51bGwpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBpZiAoZXJyICYmIGVyci5jb2RlID09PSBQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5EKSB7XG4gICAgICBsb2dSZXN1bHQoYWN0aW9uLCAwLCBlcnIpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoZXJyICYmIGVyci5jb2RlID09PSBQYXJzZS5FcnJvci5PUEVSQVRJT05fRk9SQklEREVOKSB7XG4gICAgICBsb2dSZXN1bHQoYWN0aW9uLCBudWxsLCBlcnIpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsb2dSZXN1bHQoYWN0aW9uLCBudWxsLCBlcnIpO1xuICAgIHRocm93IGVycjtcbiAgfVxufVxuXG4vKipcbiAqIFJlc29sdmVzIGEgbWVyZ2UgY29uZmxpY3QgYmV0d2VlbiB0d28gYF9JbnN0YWxsYXRpb25gIHJvd3MgdGhhdCB0b2dldGhlciByZXByZXNlbnQgdGhlXG4gKiBzYW1lIGluc3RhbGw6IG9uZSBtYXRjaGVkIGJ5IGBpbnN0YWxsYXRpb25JZGAvYG9iamVjdElkYCAoYGlkTWF0Y2hgKSwgYW5kIGFub3RoZXIgaG9sZGluZ1xuICogdGhlIHNhbWUgYGRldmljZVRva2VuYCBidXQgbm8gYGluc3RhbGxhdGlvbklkYCAoYGRldmljZVRva2VuTWF0Y2hgKS4gVGhlIGBtZXJnZVByaW9yaXR5YFxuICogZGV0ZXJtaW5lcyB3aGljaCByb3cgc3Vydml2ZXM7IHRoZSBsb3NlciByZWNlaXZlcyB0aGUgY29uZmlndXJlZCBgYWN0aW9uYC4gUmV0dXJucyB0aGVcbiAqIHN1cnZpdm9yJ3MgYG9iamVjdElkYCBzbyB0aGUgc2F2ZSBmbG93IGNhbiB0YXJnZXQgaXQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnNcbiAqIEBwYXJhbSB7RGF0YWJhc2VDb250cm9sbGVyfSBvcHRpb25zLmRhdGFiYXNlXG4gKiBAcGFyYW0ge3sgb2JqZWN0SWQ6IHN0cmluZywgaW5zdGFsbGF0aW9uSWQ/OiBzdHJpbmcsIGRldmljZVRva2VuPzogc3RyaW5nIH19IG9wdGlvbnMuaWRNYXRjaFxuICogQHBhcmFtIHt7IG9iamVjdElkOiBzdHJpbmcsIGRldmljZVRva2VuPzogc3RyaW5nIH19IG9wdGlvbnMuZGV2aWNlVG9rZW5NYXRjaFxuICogQHBhcmFtIHsnZGVsZXRlJ3wndXBkYXRlJ30gb3B0aW9ucy5hY3Rpb25cbiAqIEBwYXJhbSB7J2RldmljZVRva2VuJ3wnaW5zdGFsbGF0aW9uSWQnfSBvcHRpb25zLm1lcmdlUHJpb3JpdHlcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gb3B0aW9ucy5lbmZvcmNlQXV0aFxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMucnVuT3B0aW9uc1xuICogQHBhcmFtIHtTY2hlbWFDb250cm9sbGVyfSBvcHRpb25zLnZhbGlkU2NoZW1hQ29udHJvbGxlclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gc3Vydml2b3IncyBvYmplY3RJZFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYXBwbHlEdXBsaWNhdGVEZXZpY2VUb2tlbk1lcmdlKHtcbiAgZGF0YWJhc2UsXG4gIGlkTWF0Y2gsXG4gIGRldmljZVRva2VuTWF0Y2gsXG4gIGFjdGlvbixcbiAgbWVyZ2VQcmlvcml0eSxcbiAgZW5mb3JjZUF1dGgsXG4gIHJ1bk9wdGlvbnMsXG4gIHZhbGlkU2NoZW1hQ29udHJvbGxlcixcbn0pIHtcbiAgLy8gU2VsZi1tZXJnZSBndWFyZDogd2hlbiBib3RoIG1hdGNoZXMgcmVzb2x2ZSB0byB0aGUgc2FtZSByb3csIHRoZXJlJ3NcbiAgLy8gbm90aGluZyB0byBjbGVhbiB1cC4gU2tpcCB0aGUgYWN0aW9uIHNvIHdlIGRvbid0IGRlc3Ryb3kvdXBkYXRlIHRoZSByb3dcbiAgLy8gd2UncmUgYWJvdXQgdG8gcmV0dXJuIGFzIHRoZSBzdXJ2aXZvci5cbiAgaWYgKGlkTWF0Y2gub2JqZWN0SWQgPT09IGRldmljZVRva2VuTWF0Y2gub2JqZWN0SWQpIHtcbiAgICByZXR1cm4gaWRNYXRjaC5vYmplY3RJZDtcbiAgfVxuICBjb25zdCBvcHRzID0gZW5mb3JjZUF1dGggPyBydW5PcHRpb25zIDoge307XG4gIGxldCBsb3NlcjtcbiAgbGV0IHN1cnZpdm9ySWQ7XG4gIGxldCBmaWVsZFRvQ2xlYXI7XG4gIGlmIChtZXJnZVByaW9yaXR5ID09PSAnZGV2aWNlVG9rZW4nKSB7XG4gICAgbG9zZXIgPSBpZE1hdGNoO1xuICAgIHN1cnZpdm9ySWQgPSBkZXZpY2VUb2tlbk1hdGNoLm9iamVjdElkO1xuICAgIGZpZWxkVG9DbGVhciA9ICdpbnN0YWxsYXRpb25JZCc7XG4gIH0gZWxzZSBpZiAobWVyZ2VQcmlvcml0eSA9PT0gJ2luc3RhbGxhdGlvbklkJykge1xuICAgIGxvc2VyID0gZGV2aWNlVG9rZW5NYXRjaDtcbiAgICBzdXJ2aXZvcklkID0gaWRNYXRjaC5vYmplY3RJZDtcbiAgICBmaWVsZFRvQ2xlYXIgPSAnZGV2aWNlVG9rZW4nO1xuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBpbnN0YWxsYXRpb24gZGVkdXAgbWVyZ2VQcmlvcml0eTogJHttZXJnZVByaW9yaXR5fWApO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBwZXJmb3JtQWN0aW9uKHtcbiAgICAgIGRhdGFiYXNlLFxuICAgICAgcXVlcnk6IHsgb2JqZWN0SWQ6IGxvc2VyLm9iamVjdElkIH0sXG4gICAgICBhY3Rpb24sXG4gICAgICBmaWVsZFRvQ2xlYXIsXG4gICAgICBydW5PcHRpb25zOiBvcHRzLFxuICAgICAgbWFueTogZmFsc2UsXG4gICAgICB2YWxpZFNjaGVtYUNvbnRyb2xsZXIsXG4gICAgfSk7XG4gICAgbG9nUmVzdWx0KGFjdGlvbiwgMSwgbnVsbCk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGlmIChlcnIgJiYgZXJyLmNvZGUgPT09IFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQpIHtcbiAgICAgIGxvZ1Jlc3VsdChhY3Rpb24sIDAsIGVycik7XG4gICAgfSBlbHNlIGlmIChlcnIgJiYgZXJyLmNvZGUgPT09IFBhcnNlLkVycm9yLk9QRVJBVElPTl9GT1JCSURERU4pIHtcbiAgICAgIGxvZ1Jlc3VsdChhY3Rpb24sIG51bGwsIGVycik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZ1Jlc3VsdChhY3Rpb24sIG51bGwsIGVycik7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICB9XG4gIHJldHVybiBzdXJ2aXZvcklkO1xufVxuXG5leHBvcnQgZGVmYXVsdCB7XG4gIHJlbW92ZUNvbmZsaWN0aW5nRGV2aWNlVG9rZW4sXG4gIGFwcGx5RHVwbGljYXRlRGV2aWNlVG9rZW5NZXJnZSxcbn07XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBQUEsSUFBQUEsS0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsT0FBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBQThCLFNBQUFELHVCQUFBRyxDQUFBLFdBQUFBLENBQUEsSUFBQUEsQ0FBQSxDQUFBQyxVQUFBLEdBQUFELENBQUEsS0FBQUUsT0FBQSxFQUFBRixDQUFBO0FBRTlCLE1BQU1HLFVBQVUsR0FBRyxlQUFlO0FBRWxDLFNBQVNDLFNBQVNBLENBQUNDLE1BQU0sRUFB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