StatusHandler.js 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.flatten = flatten;
  6. exports.jobStatusHandler = jobStatusHandler;
  7. exports.pushStatusHandler = pushStatusHandler;
  8. var _cryptoUtils = require("./cryptoUtils");
  9. var _KeyPromiseQueue = require("./KeyPromiseQueue");
  10. var _logger = require("./logger");
  11. var _rest = _interopRequireDefault(require("./rest"));
  12. var _Auth = _interopRequireDefault(require("./Auth"));
  13. function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
  14. function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
  15. function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
  16. function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
  17. function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
  18. function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
  19. const PUSH_STATUS_COLLECTION = '_PushStatus';
  20. const JOB_STATUS_COLLECTION = '_JobStatus';
  21. const pushPromiseQueue = new _KeyPromiseQueue.KeyPromiseQueue();
  22. const jobPromiseQueue = new _KeyPromiseQueue.KeyPromiseQueue();
  23. const incrementOp = function (object = {}, key, amount = 1) {
  24. if (!object[key]) {
  25. object[key] = {
  26. __op: 'Increment',
  27. amount: amount
  28. };
  29. } else {
  30. object[key].amount += amount;
  31. }
  32. return object[key];
  33. };
  34. function flatten(array) {
  35. var flattened = [];
  36. for (var i = 0; i < array.length; i++) {
  37. if (Array.isArray(array[i])) {
  38. flattened = flattened.concat(flatten(array[i]));
  39. } else {
  40. flattened.push(array[i]);
  41. }
  42. }
  43. return flattened;
  44. }
  45. function statusHandler(className, database) {
  46. function create(object) {
  47. return database.create(className, object).then(() => {
  48. return Promise.resolve(object);
  49. });
  50. }
  51. function update(where, object) {
  52. return jobPromiseQueue.enqueue(where.objectId, () => database.update(className, where, object));
  53. }
  54. return Object.freeze({
  55. create,
  56. update
  57. });
  58. }
  59. function restStatusHandler(className, config) {
  60. const auth = _Auth.default.master(config);
  61. function create(object) {
  62. return _rest.default.create(config, auth, className, object).then(({
  63. response
  64. }) => {
  65. return _objectSpread(_objectSpread({}, object), response);
  66. });
  67. }
  68. function update(where, object) {
  69. return pushPromiseQueue.enqueue(where.objectId, () => _rest.default.update(config, auth, className, {
  70. objectId: where.objectId
  71. }, object).then(({
  72. response
  73. }) => {
  74. return _objectSpread(_objectSpread({}, object), response);
  75. }));
  76. }
  77. return Object.freeze({
  78. create,
  79. update
  80. });
  81. }
  82. function jobStatusHandler(config) {
  83. let jobStatus;
  84. const objectId = (0, _cryptoUtils.newObjectId)(config.objectIdSize);
  85. const database = config.database;
  86. const handler = statusHandler(JOB_STATUS_COLLECTION, database);
  87. const setRunning = function (jobName, params) {
  88. const now = new Date();
  89. jobStatus = {
  90. objectId,
  91. jobName,
  92. params,
  93. status: 'running',
  94. source: 'api',
  95. createdAt: now,
  96. // lockdown!
  97. ACL: {}
  98. };
  99. return handler.create(jobStatus);
  100. };
  101. const setMessage = function (message) {
  102. if (!message || typeof message !== 'string') {
  103. return Promise.resolve();
  104. }
  105. return handler.update({
  106. objectId
  107. }, {
  108. message
  109. });
  110. };
  111. const setSucceeded = function (message) {
  112. return setFinalStatus('succeeded', message);
  113. };
  114. const setFailed = function (message) {
  115. return setFinalStatus('failed', message);
  116. };
  117. const setFinalStatus = function (status, message = undefined) {
  118. const finishedAt = new Date();
  119. const update = {
  120. status,
  121. finishedAt
  122. };
  123. if (message && typeof message === 'string') {
  124. update.message = message;
  125. }
  126. if (message instanceof Error && typeof message.message === 'string') {
  127. update.message = message.message;
  128. }
  129. return handler.update({
  130. objectId
  131. }, update);
  132. };
  133. return Object.freeze({
  134. setRunning,
  135. setSucceeded,
  136. setMessage,
  137. setFailed
  138. });
  139. }
  140. function pushStatusHandler(config, existingObjectId) {
  141. let pushStatus;
  142. const database = config.database;
  143. const handler = restStatusHandler(PUSH_STATUS_COLLECTION, config);
  144. let objectId = existingObjectId;
  145. const setInitial = function (body = {}, where, options = {
  146. source: 'rest'
  147. }) {
  148. const now = new Date();
  149. let pushTime = now.toISOString();
  150. let status = 'pending';
  151. if (Object.prototype.hasOwnProperty.call(body, 'push_time')) {
  152. if (config.hasPushScheduledSupport) {
  153. pushTime = body.push_time;
  154. status = 'scheduled';
  155. } else {
  156. _logger.logger.warn('Trying to schedule a push while server is not configured.');
  157. _logger.logger.warn('Push will be sent immediately');
  158. }
  159. }
  160. const data = body.data || {};
  161. const payloadString = JSON.stringify(data);
  162. let pushHash;
  163. if (typeof data.alert === 'string') {
  164. pushHash = (0, _cryptoUtils.md5Hash)(data.alert);
  165. } else if (typeof data.alert === 'object') {
  166. pushHash = (0, _cryptoUtils.md5Hash)(JSON.stringify(data.alert));
  167. } else {
  168. pushHash = 'd41d8cd98f00b204e9800998ecf8427e';
  169. }
  170. const object = {
  171. pushTime,
  172. query: JSON.stringify(where),
  173. payload: payloadString,
  174. source: options.source,
  175. title: options.title,
  176. expiry: body.expiration_time,
  177. expiration_interval: body.expiration_interval,
  178. status: status,
  179. numSent: 0,
  180. pushHash,
  181. // lockdown!
  182. ACL: {}
  183. };
  184. return handler.create(object).then(result => {
  185. objectId = result.objectId;
  186. pushStatus = {
  187. objectId
  188. };
  189. return Promise.resolve(pushStatus);
  190. });
  191. };
  192. const setRunning = function (batches) {
  193. _logger.logger.verbose(`_PushStatus ${objectId}: sending push to installations with %d batches`, batches);
  194. return handler.update({
  195. status: 'pending',
  196. objectId: objectId
  197. }, {
  198. status: 'running',
  199. count: batches
  200. });
  201. };
  202. const trackSent = function (results, UTCOffset, cleanupInstallations = process.env.PARSE_SERVER_CLEANUP_INVALID_INSTALLATIONS) {
  203. const update = {
  204. numSent: 0,
  205. numFailed: 0
  206. };
  207. const devicesToRemove = [];
  208. if (Array.isArray(results)) {
  209. results = flatten(results);
  210. results.reduce((memo, result) => {
  211. // Cannot handle that
  212. if (!result || !result.device || !result.device.deviceType) {
  213. return memo;
  214. }
  215. const deviceType = result.device.deviceType;
  216. const key = result.transmitted ? `sentPerType.${deviceType}` : `failedPerType.${deviceType}`;
  217. memo[key] = incrementOp(memo, key);
  218. if (typeof UTCOffset !== 'undefined') {
  219. const offsetKey = result.transmitted ? `sentPerUTCOffset.${UTCOffset}` : `failedPerUTCOffset.${UTCOffset}`;
  220. memo[offsetKey] = incrementOp(memo, offsetKey);
  221. }
  222. if (result.transmitted) {
  223. memo.numSent++;
  224. } else {
  225. if (result && result.response && result.response.error && result.device && result.device.deviceToken) {
  226. const token = result.device.deviceToken;
  227. const error = result.response.error;
  228. // GCM / FCM HTTP v1 API errors; see:
  229. // https://firebase.google.com/docs/reference/fcm/rest/v1/ErrorCode
  230. if (error === 'NotRegistered' || error === 'InvalidRegistration') {
  231. devicesToRemove.push(token);
  232. }
  233. // FCM API v2 errors; see:
  234. // https://firebase.google.com/docs/cloud-messaging/manage-tokens
  235. // https://github.com/firebase/functions-samples/blob/703c0359eacf07a551751d1319d34f912a2cd828/Node/fcm-notifications/functions/index.js#L89-L93C16
  236. if ((error === null || error === void 0 ? void 0 : error.code) === 'messaging/registration-token-not-registered' || (error === null || error === void 0 ? void 0 : error.code) === 'messaging/invalid-registration-token' || (error === null || error === void 0 ? void 0 : error.code) === 'messaging/invalid-argument' && (error === null || error === void 0 ? void 0 : error.message) === 'The registration token is not a valid FCM registration token') {
  237. devicesToRemove.push(token);
  238. }
  239. // APNS errors; see:
  240. // https://developer.apple.com/documentation/usernotifications/handling-notification-responses-from-apns
  241. if (error === 'Unregistered' || error === 'BadDeviceToken') {
  242. devicesToRemove.push(token);
  243. }
  244. }
  245. memo.numFailed++;
  246. }
  247. return memo;
  248. }, update);
  249. }
  250. _logger.logger.verbose(`_PushStatus ${objectId}: sent push! %d success, %d failures`, update.numSent, update.numFailed);
  251. _logger.logger.verbose(`_PushStatus ${objectId}: needs cleanup`, {
  252. devicesToRemove
  253. });
  254. ['numSent', 'numFailed'].forEach(key => {
  255. if (update[key] > 0) {
  256. update[key] = {
  257. __op: 'Increment',
  258. amount: update[key]
  259. };
  260. } else {
  261. delete update[key];
  262. }
  263. });
  264. if (devicesToRemove.length > 0 && cleanupInstallations) {
  265. _logger.logger.info(`Removing device tokens on ${devicesToRemove.length} _Installations`);
  266. database.update('_Installation', {
  267. deviceToken: {
  268. $in: devicesToRemove
  269. }
  270. }, {
  271. deviceToken: {
  272. __op: 'Delete'
  273. }
  274. }, {
  275. acl: undefined,
  276. many: true
  277. });
  278. }
  279. incrementOp(update, 'count', -1);
  280. update.status = 'running';
  281. return handler.update({
  282. objectId
  283. }, update).then(res => {
  284. if (res && res.count === 0) {
  285. return this.complete();
  286. }
  287. });
  288. };
  289. const complete = function () {
  290. return handler.update({
  291. objectId
  292. }, {
  293. status: 'succeeded',
  294. count: {
  295. __op: 'Delete'
  296. }
  297. });
  298. };
  299. const fail = function (err) {
  300. if (typeof err === 'string') {
  301. err = {
  302. message: err
  303. };
  304. }
  305. const update = {
  306. errorMessage: err,
  307. status: 'failed'
  308. };
  309. return handler.update({
  310. objectId
  311. }, update);
  312. };
  313. const rval = {
  314. setInitial,
  315. setRunning,
  316. trackSent,
  317. complete,
  318. fail
  319. };
  320. // define objectId to be dynamic
  321. Object.defineProperty(rval, 'objectId', {
  322. get: () => objectId
  323. });
  324. return Object.freeze(rval);
  325. }
  326. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfY3J5cHRvVXRpbHMiLCJyZXF1aXJlIiwiX0tleVByb21pc2VRdWV1ZSIsIl9sb2dnZXIiLCJfcmVzdCIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfQXV0aCIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsIm93bktleXMiLCJyIiwidCIsIk9iamVjdCIsImtleXMiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJvIiwiZmlsdGVyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwiZW51bWVyYWJsZSIsInB1c2giLCJhcHBseSIsIl9vYmplY3RTcHJlYWQiLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJmb3JFYWNoIiwiX2RlZmluZVByb3BlcnR5IiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJkZWZpbmVQcm9wZXJ0eSIsIl90b1Byb3BlcnR5S2V5IiwidmFsdWUiLCJjb25maWd1cmFibGUiLCJ3cml0YWJsZSIsImkiLCJfdG9QcmltaXRpdmUiLCJTeW1ib2wiLCJ0b1ByaW1pdGl2ZSIsImNhbGwiLCJUeXBlRXJyb3IiLCJTdHJpbmciLCJOdW1iZXIiLCJQVVNIX1NUQVRVU19DT0xMRUNUSU9OIiwiSk9CX1NUQVRVU19DT0xMRUNUSU9OIiwicHVzaFByb21pc2VRdWV1ZSIsIktleVByb21pc2VRdWV1ZSIsImpvYlByb21pc2VRdWV1ZSIsImluY3JlbWVudE9wIiwib2JqZWN0Iiwia2V5IiwiYW1vdW50IiwiX19vcCIsImZsYXR0ZW4iLCJhcnJheSIsImZsYXR0ZW5lZCIsIkFycmF5IiwiaXNBcnJheSIsImNvbmNhdCIsInN0YXR1c0hhbmRsZXIiLCJjbGFzc05hbWUiLCJkYXRhYmFzZSIsImNyZWF0ZSIsInRoZW4iLCJQcm9taXNlIiwicmVzb2x2ZSIsInVwZGF0ZSIsIndoZXJlIiwiZW5xdWV1ZSIsIm9iamVjdElkIiwiZnJlZXplIiwicmVzdFN0YXR1c0hhbmRsZXIiLCJjb25maWciLCJhdXRoIiwiQXV0aCIsIm1hc3RlciIsInJlc3QiLCJyZXNwb25zZSIsImpvYlN0YXR1c0hhbmRsZXIiLCJqb2JTdGF0dXMiLCJuZXdPYmplY3RJZCIsIm9iamVjdElkU2l6ZSIsImhhbmRsZXIiLCJzZXRSdW5uaW5nIiwiam9iTmFtZSIsInBhcmFtcyIsIm5vdyIsIkRhdGUiLCJzdGF0dXMiLCJzb3VyY2UiLCJjcmVhdGVkQXQiLCJBQ0wiLCJzZXRNZXNzYWdlIiwibWVzc2FnZSIsInNldFN1Y2NlZWRlZCIsInNldEZpbmFsU3RhdHVzIiwic2V0RmFpbGVkIiwidW5kZWZpbmVkIiwiZmluaXNoZWRBdCIsIkVycm9yIiwicHVzaFN0YXR1c0hhbmRsZXIiLCJleGlzdGluZ09iamVjdElkIiwicHVzaFN0YXR1cyIsInNldEluaXRpYWwiLCJib2R5Iiwib3B0aW9ucyIsInB1c2hUaW1lIiwidG9JU09TdHJpbmciLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImhhc1B1c2hTY2hlZHVsZWRTdXBwb3J0IiwicHVzaF90aW1lIiwibG9nZ2VyIiwid2FybiIsImRhdGEiLCJwYXlsb2FkU3RyaW5nIiwiSlNPTiIsInN0cmluZ2lmeSIsInB1c2hIYXNoIiwiYWxlcnQiLCJtZDVIYXNoIiwicXVlcnkiLCJwYXlsb2FkIiwidGl0bGUiLCJleHBpcnkiLCJleHBpcmF0aW9uX3RpbWUiLCJleHBpcmF0aW9uX2ludGVydmFsIiwibnVtU2VudCIsInJlc3VsdCIsImJhdGNoZXMiLCJ2ZXJib3NlIiwiY291bnQiLCJ0cmFja1NlbnQiLCJyZXN1bHRzIiwiVVRDT2Zmc2V0IiwiY2xlYW51cEluc3RhbGxhdGlvbnMiLCJwcm9jZXNzIiwiZW52IiwiUEFSU0VfU0VSVkVSX0NMRUFOVVBfSU5WQUxJRF9JTlNUQUxMQVRJT05TIiwibnVtRmFpbGVkIiwiZGV2aWNlc1RvUmVtb3ZlIiwicmVkdWNlIiwibWVtbyIsImRldmljZSIsImRldmljZVR5cGUiLCJ0cmFuc21pdHRlZCIsIm9mZnNldEtleSIsImVycm9yIiwiZGV2aWNlVG9rZW4iLCJ0b2tlbiIsImNvZGUiLCJpbmZvIiwiJGluIiwiYWNsIiwibWFueSIsInJlcyIsImNvbXBsZXRlIiwiZmFpbCIsImVyciIsImVycm9yTWVzc2FnZSIsInJ2YWwiLCJnZXQiXSwic291cmNlcyI6WyIuLi9zcmMvU3RhdHVzSGFuZGxlci5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBtZDVIYXNoLCBuZXdPYmplY3RJZCB9IGZyb20gJy4vY3J5cHRvVXRpbHMnO1xuaW1wb3J0IHsgS2V5UHJvbWlzZVF1ZXVlIH0gZnJvbSAnLi9LZXlQcm9taXNlUXVldWUnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi9sb2dnZXInO1xuaW1wb3J0IHJlc3QgZnJvbSAnLi9yZXN0JztcbmltcG9ydCBBdXRoIGZyb20gJy4vQXV0aCc7XG5cbmNvbnN0IFBVU0hfU1RBVFVTX0NPTExFQ1RJT04gPSAnX1B1c2hTdGF0dXMnO1xuY29uc3QgSk9CX1NUQVRVU19DT0xMRUNUSU9OID0gJ19Kb2JTdGF0dXMnO1xuXG5jb25zdCBwdXNoUHJvbWlzZVF1ZXVlID0gbmV3IEtleVByb21pc2VRdWV1ZSgpO1xuY29uc3Qgam9iUHJvbWlzZVF1ZXVlID0gbmV3IEtleVByb21pc2VRdWV1ZSgpO1xuXG5jb25zdCBpbmNyZW1lbnRPcCA9IGZ1bmN0aW9uIChvYmplY3QgPSB7fSwga2V5LCBhbW91bnQgPSAxKSB7XG4gIGlmICghb2JqZWN0W2tleV0pIHtcbiAgICBvYmplY3Rba2V5XSA9IHsgX19vcDogJ0luY3JlbWVudCcsIGFtb3VudDogYW1vdW50IH07XG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0W2tleV0uYW1vdW50ICs9IGFtb3VudDtcbiAgfVxuICByZXR1cm4gb2JqZWN0W2tleV07XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gZmxhdHRlbihhcnJheSkge1xuICB2YXIgZmxhdHRlbmVkID0gW107XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgYXJyYXkubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShhcnJheVtpXSkpIHtcbiAgICAgIGZsYXR0ZW5lZCA9IGZsYXR0ZW5lZC5jb25jYXQoZmxhdHRlbihhcnJheVtpXSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBmbGF0dGVuZWQucHVzaChhcnJheVtpXSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBmbGF0dGVuZWQ7XG59XG5cbmZ1bmN0aW9uIHN0YXR1c0hhbmRsZXIoY2xhc3NOYW1lLCBkYXRhYmFzZSkge1xuICBmdW5jdGlvbiBjcmVhdGUob2JqZWN0KSB7XG4gICAgcmV0dXJuIGRhdGFiYXNlLmNyZWF0ZShjbGFzc05hbWUsIG9iamVjdCkudGhlbigoKSA9PiB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKG9iamVjdCk7XG4gICAgfSk7XG4gIH1cblxuICBmdW5jdGlvbiB1cGRhdGUod2hlcmUsIG9iamVjdCkge1xuICAgIHJldHVybiBqb2JQcm9taXNlUXVldWUuZW5xdWV1ZSh3aGVyZS5vYmplY3RJZCwgKCkgPT4gZGF0YWJhc2UudXBkYXRlKGNsYXNzTmFtZSwgd2hlcmUsIG9iamVjdCkpO1xuICB9XG5cbiAgcmV0dXJuIE9iamVjdC5mcmVlemUoe1xuICAgIGNyZWF0ZSxcbiAgICB1cGRhdGUsXG4gIH0pO1xufVxuXG5mdW5jdGlvbiByZXN0U3RhdHVzSGFuZGxlcihjbGFzc05hbWUsIGNvbmZpZykge1xuICBjb25zdCBhdXRoID0gQXV0aC5tYXN0ZXIoY29uZmlnKTtcbiAgZnVuY3Rpb24gY3JlYXRlKG9iamVjdCkge1xuICAgIHJldHVybiByZXN0LmNyZWF0ZShjb25maWcsIGF1dGgsIGNsYXNzTmFtZSwgb2JqZWN0KS50aGVuKCh7IHJlc3BvbnNlIH0pID0+IHtcbiAgICAgIHJldHVybiB7IC4uLm9iamVjdCwgLi4ucmVzcG9uc2UgfTtcbiAgICB9KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHVwZGF0ZSh3aGVyZSwgb2JqZWN0KSB7XG4gICAgcmV0dXJuIHB1c2hQcm9taXNlUXVldWUuZW5xdWV1ZSh3aGVyZS5vYmplY3RJZCwgKCkgPT5cbiAgICAgIHJlc3RcbiAgICAgICAgLnVwZGF0ZShjb25maWcsIGF1dGgsIGNsYXNzTmFtZSwgeyBvYmplY3RJZDogd2hlcmUub2JqZWN0SWQgfSwgb2JqZWN0KVxuICAgICAgICAudGhlbigoeyByZXNwb25zZSB9KSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHsgLi4ub2JqZWN0LCAuLi5yZXNwb25zZSB9O1xuICAgICAgICB9KVxuICAgICk7XG4gIH1cblxuICByZXR1cm4gT2JqZWN0LmZyZWV6ZSh7XG4gICAgY3JlYXRlLFxuICAgIHVwZGF0ZSxcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBqb2JTdGF0dXNIYW5kbGVyKGNvbmZpZykge1xuICBsZXQgam9iU3RhdHVzO1xuICBjb25zdCBvYmplY3RJZCA9IG5ld09iamVjdElkKGNvbmZpZy5vYmplY3RJZFNpemUpO1xuICBjb25zdCBkYXRhYmFzZSA9IGNvbmZpZy5kYXRhYmFzZTtcbiAgY29uc3QgaGFuZGxlciA9IHN0YXR1c0hhbmRsZXIoSk9CX1NUQVRVU19DT0xMRUNUSU9OLCBkYXRhYmFzZSk7XG4gIGNvbnN0IHNldFJ1bm5pbmcgPSBmdW5jdGlvbiAoam9iTmFtZSwgcGFyYW1zKSB7XG4gICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcbiAgICBqb2JTdGF0dXMgPSB7XG4gICAgICBvYmplY3RJZCxcbiAgICAgIGpvYk5hbWUsXG4gICAgICBwYXJhbXMsXG4gICAgICBzdGF0dXM6ICdydW5uaW5nJyxcbiAgICAgIHNvdXJjZTogJ2FwaScsXG4gICAgICBjcmVhdGVkQXQ6IG5vdyxcbiAgICAgIC8vIGxvY2tkb3duIVxuICAgICAgQUNMOiB7fSxcbiAgICB9O1xuXG4gICAgcmV0dXJuIGhhbmRsZXIuY3JlYXRlKGpvYlN0YXR1cyk7XG4gIH07XG5cbiAgY29uc3Qgc2V0TWVzc2FnZSA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgaWYgKCFtZXNzYWdlIHx8IHR5cGVvZiBtZXNzYWdlICE9PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH1cbiAgICByZXR1cm4gaGFuZGxlci51cGRhdGUoeyBvYmplY3RJZCB9LCB7IG1lc3NhZ2UgfSk7XG4gIH07XG5cbiAgY29uc3Qgc2V0U3VjY2VlZGVkID0gZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICByZXR1cm4gc2V0RmluYWxTdGF0dXMoJ3N1Y2NlZWRlZCcsIG1lc3NhZ2UpO1xuICB9O1xuXG4gIGNvbnN0IHNldEZhaWxlZCA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgcmV0dXJuIHNldEZpbmFsU3RhdHVzKCdmYWlsZWQnLCBtZXNzYWdlKTtcbiAgfTtcblxuICBjb25zdCBzZXRGaW5hbFN0YXR1cyA9IGZ1bmN0aW9uIChzdGF0dXMsIG1lc3NhZ2UgPSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBmaW5pc2hlZEF0ID0gbmV3IERhdGUoKTtcbiAgICBjb25zdCB1cGRhdGUgPSB7IHN0YXR1cywgZmluaXNoZWRBdCB9O1xuICAgIGlmIChtZXNzYWdlICYmIHR5cGVvZiBtZXNzYWdlID09PSAnc3RyaW5nJykge1xuICAgICAgdXBkYXRlLm1lc3NhZ2UgPSBtZXNzYWdlO1xuICAgIH1cbiAgICBpZiAobWVzc2FnZSBpbnN0YW5jZW9mIEVycm9yICYmIHR5cGVvZiBtZXNzYWdlLm1lc3NhZ2UgPT09ICdzdHJpbmcnKSB7XG4gICAgICB1cGRhdGUubWVzc2FnZSA9IG1lc3NhZ2UubWVzc2FnZTtcbiAgICB9XG4gICAgcmV0dXJuIGhhbmRsZXIudXBkYXRlKHsgb2JqZWN0SWQgfSwgdXBkYXRlKTtcbiAgfTtcblxuICByZXR1cm4gT2JqZWN0LmZyZWV6ZSh7XG4gICAgc2V0UnVubmluZyxcbiAgICBzZXRTdWNjZWVkZWQsXG4gICAgc2V0TWVzc2FnZSxcbiAgICBzZXRGYWlsZWQsXG4gIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcHVzaFN0YXR1c0hhbmRsZXIoY29uZmlnLCBleGlzdGluZ09iamVjdElkKSB7XG4gIGxldCBwdXNoU3RhdHVzO1xuICBjb25zdCBkYXRhYmFzZSA9IGNvbmZpZy5kYXRhYmFzZTtcbiAgY29uc3QgaGFuZGxlciA9IHJlc3RTdGF0dXNIYW5kbGVyKFBVU0hfU1RBVFVTX0NPTExFQ1RJT04sIGNvbmZpZyk7XG4gIGxldCBvYmplY3RJZCA9IGV4aXN0aW5nT2JqZWN0SWQ7XG4gIGNvbnN0IHNldEluaXRpYWwgPSBmdW5jdGlvbiAoYm9keSA9IHt9LCB3aGVyZSwgb3B0aW9ucyA9IHsgc291cmNlOiAncmVzdCcgfSkge1xuICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG4gICAgbGV0IHB1c2hUaW1lID0gbm93LnRvSVNPU3RyaW5nKCk7XG4gICAgbGV0IHN0YXR1cyA9ICdwZW5kaW5nJztcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGJvZHksICdwdXNoX3RpbWUnKSkge1xuICAgICAgaWYgKGNvbmZpZy5oYXNQdXNoU2NoZWR1bGVkU3VwcG9ydCkge1xuICAgICAgICBwdXNoVGltZSA9IGJvZHkucHVzaF90aW1lO1xuICAgICAgICBzdGF0dXMgPSAnc2NoZWR1bGVkJztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZ2dlci53YXJuKCdUcnlpbmcgdG8gc2NoZWR1bGUgYSBwdXNoIHdoaWxlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZC4nKTtcbiAgICAgICAgbG9nZ2VyLndhcm4oJ1B1c2ggd2lsbCBiZSBzZW50IGltbWVkaWF0ZWx5Jyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgZGF0YSA9IGJvZHkuZGF0YSB8fCB7fTtcbiAgICBjb25zdCBwYXlsb2FkU3RyaW5nID0gSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgbGV0IHB1c2hIYXNoO1xuICAgIGlmICh0eXBlb2YgZGF0YS5hbGVydCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHB1c2hIYXNoID0gbWQ1SGFzaChkYXRhLmFsZXJ0KTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBkYXRhLmFsZXJ0ID09PSAnb2JqZWN0Jykge1xuICAgICAgcHVzaEhhc2ggPSBtZDVIYXNoKEpTT04uc3RyaW5naWZ5KGRhdGEuYWxlcnQpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcHVzaEhhc2ggPSAnZDQxZDhjZDk4ZjAwYjIwNGU5ODAwOTk4ZWNmODQyN2UnO1xuICAgIH1cbiAgICBjb25zdCBvYmplY3QgPSB7XG4gICAgICBwdXNoVGltZSxcbiAgICAgIHF1ZXJ5OiBKU09OLnN0cmluZ2lmeSh3aGVyZSksXG4gICAgICBwYXlsb2FkOiBwYXlsb2FkU3RyaW5nLFxuICAgICAgc291cmNlOiBvcHRpb25zLnNvdXJjZSxcbiAgICAgIHRpdGxlOiBvcHRpb25zLnRpdGxlLFxuICAgICAgZXhwaXJ5OiBib2R5LmV4cGlyYXRpb25fdGltZSxcbiAgICAgIGV4cGlyYXRpb25faW50ZXJ2YWw6IGJvZHkuZXhwaXJhdGlvbl9pbnRlcnZhbCxcbiAgICAgIHN0YXR1czogc3RhdHVzLFxuICAgICAgbnVtU2VudDogMCxcbiAgICAgIHB1c2hIYXNoLFxuICAgICAgLy8gbG9ja2Rvd24hXG4gICAgICBBQ0w6IHt9LFxuICAgIH07XG4gICAgcmV0dXJuIGhhbmRsZXIuY3JlYXRlKG9iamVjdCkudGhlbihyZXN1bHQgPT4ge1xuICAgICAgb2JqZWN0SWQgPSByZXN1bHQub2JqZWN0SWQ7XG4gICAgICBwdXNoU3RhdHVzID0ge1xuICAgICAgICBvYmplY3RJZCxcbiAgICAgIH07XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHB1c2hTdGF0dXMpO1xuICAgIH0pO1xuICB9O1xuXG4gIGNvbnN0IHNldFJ1bm5pbmcgPSBmdW5jdGlvbiAoYmF0Y2hlcykge1xuICAgIGxvZ2dlci52ZXJib3NlKFxuICAgICAgYF9QdXNoU3RhdHVzICR7b2JqZWN0SWR9OiBzZW5kaW5nIHB1c2ggdG8gaW5zdGFsbGF0aW9ucyB3aXRoICVkIGJhdGNoZXNgLFxuICAgICAgYmF0Y2hlc1xuICAgICk7XG4gICAgcmV0dXJuIGhhbmRsZXIudXBkYXRlKFxuICAgICAge1xuICAgICAgICBzdGF0dXM6ICdwZW5kaW5nJyxcbiAgICAgICAgb2JqZWN0SWQ6IG9iamVjdElkLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgc3RhdHVzOiAncnVubmluZycsXG4gICAgICAgIGNvdW50OiBiYXRjaGVzLFxuICAgICAgfVxuICAgICk7XG4gIH07XG5cbiAgY29uc3QgdHJhY2tTZW50ID0gZnVuY3Rpb24gKFxuICAgIHJlc3VsdHMsXG4gICAgVVRDT2Zmc2V0LFxuICAgIGNsZWFudXBJbnN0YWxsYXRpb25zID0gcHJvY2Vzcy5lbnYuUEFSU0VfU0VSVkVSX0NMRUFOVVBfSU5WQUxJRF9JTlNUQUxMQVRJT05TXG4gICkge1xuICAgIGNvbnN0IHVwZGF0ZSA9IHtcbiAgICAgIG51bVNlbnQ6IDAsXG4gICAgICBudW1GYWlsZWQ6IDAsXG4gICAgfTtcbiAgICBjb25zdCBkZXZpY2VzVG9SZW1vdmUgPSBbXTtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShyZXN1bHRzKSkge1xuICAgICAgcmVzdWx0cyA9IGZsYXR0ZW4ocmVzdWx0cyk7XG4gICAgICByZXN1bHRzLnJlZHVjZSgobWVtbywgcmVzdWx0KSA9PiB7XG4gICAgICAgIC8vIENhbm5vdCBoYW5kbGUgdGhhdFxuICAgICAgICBpZiAoIXJlc3VsdCB8fCAhcmVzdWx0LmRldmljZSB8fCAhcmVzdWx0LmRldmljZS5kZXZpY2VUeXBlKSB7XG4gICAgICAgICAgcmV0dXJuIG1lbW87XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZGV2aWNlVHlwZSA9IHJlc3VsdC5kZXZpY2UuZGV2aWNlVHlwZTtcbiAgICAgICAgY29uc3Qga2V5ID0gcmVzdWx0LnRyYW5zbWl0dGVkXG4gICAgICAgICAgPyBgc2VudFBlclR5cGUuJHtkZXZpY2VUeXBlfWBcbiAgICAgICAgICA6IGBmYWlsZWRQZXJUeXBlLiR7ZGV2aWNlVHlwZX1gO1xuICAgICAgICBtZW1vW2tleV0gPSBpbmNyZW1lbnRPcChtZW1vLCBrZXkpO1xuICAgICAgICBpZiAodHlwZW9mIFVUQ09mZnNldCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICBjb25zdCBvZmZzZXRLZXkgPSByZXN1bHQudHJhbnNtaXR0ZWRcbiAgICAgICAgICAgID8gYHNlbnRQZXJVVENPZmZzZXQuJHtVVENPZmZzZXR9YFxuICAgICAgICAgICAgOiBgZmFpbGVkUGVyVVRDT2Zmc2V0LiR7VVRDT2Zmc2V0fWA7XG4gICAgICAgICAgbWVtb1tvZmZzZXRLZXldID0gaW5jcmVtZW50T3AobWVtbywgb2Zmc2V0S2V5KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocmVzdWx0LnRyYW5zbWl0dGVkKSB7XG4gICAgICAgICAgbWVtby5udW1TZW50Kys7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgcmVzdWx0ICYmXG4gICAgICAgICAgICByZXN1bHQucmVzcG9uc2UgJiZcbiAgICAgICAgICAgIHJlc3VsdC5yZXNwb25zZS5lcnJvciAmJlxuICAgICAgICAgICAgcmVzdWx0LmRldmljZSAmJlxuICAgICAgICAgICAgcmVzdWx0LmRldmljZS5kZXZpY2VUb2tlblxuICAgICAgICAgICkge1xuICAgICAgICAgICAgY29uc3QgdG9rZW4gPSByZXN1bHQuZGV2aWNlLmRldmljZVRva2VuO1xuICAgICAgICAgICAgY29uc3QgZXJyb3IgPSByZXN1bHQucmVzcG9uc2UuZXJyb3I7XG4gICAgICAgICAgICAvLyBHQ00gLyBGQ00gSFRUUCB2MSBBUEkgZXJyb3JzOyBzZWU6XG4gICAgICAgICAgICAvLyBodHRwczovL2ZpcmViYXNlLmdvb2dsZS5jb20vZG9jcy9yZWZlcmVuY2UvZmNtL3Jlc3QvdjEvRXJyb3JDb2RlXG4gICAgICAgICAgICBpZiAoZXJyb3IgPT09ICdOb3RSZWdpc3RlcmVkJyB8fCBlcnJvciA9PT0gJ0ludmFsaWRSZWdpc3RyYXRpb24nKSB7XG4gICAgICAgICAgICAgIGRldmljZXNUb1JlbW92ZS5wdXNoKHRva2VuKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEZDTSBBUEkgdjIgZXJyb3JzOyBzZWU6XG4gICAgICAgICAgICAvLyBodHRwczovL2ZpcmViYXNlLmdvb2dsZS5jb20vZG9jcy9jbG91ZC1tZXNzYWdpbmcvbWFuYWdlLXRva2Vuc1xuICAgICAgICAgICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2ZpcmViYXNlL2Z1bmN0aW9ucy1zYW1wbGVzL2Jsb2IvNzAzYzAzNTllYWNmMDdhNTUxNzUxZDEzMTlkMzRmOTEyYTJjZDgyOC9Ob2RlL2ZjbS1ub3RpZmljYXRpb25zL2Z1bmN0aW9ucy9pbmRleC5qcyNMODktTDkzQzE2XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgIGVycm9yPy5jb2RlID09PSAnbWVzc2FnaW5nL3JlZ2lzdHJhdGlvbi10b2tlbi1ub3QtcmVnaXN0ZXJlZCcgfHxcbiAgICAgICAgICAgICAgZXJyb3I/LmNvZGUgPT09ICdtZXNzYWdpbmcvaW52YWxpZC1yZWdpc3RyYXRpb24tdG9rZW4nIHx8XG4gICAgICAgICAgICAgIChlcnJvcj8uY29kZSA9PT0gJ21lc3NhZ2luZy9pbnZhbGlkLWFyZ3VtZW50JyAmJiBlcnJvcj8ubWVzc2FnZSA9PT0gJ1RoZSByZWdpc3RyYXRpb24gdG9rZW4gaXMgbm90IGEgdmFsaWQgRkNNIHJlZ2lzdHJhdGlvbiB0b2tlbicpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgZGV2aWNlc1RvUmVtb3ZlLnB1c2godG9rZW4pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gQVBOUyBlcnJvcnM7IHNlZTpcbiAgICAgICAgICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLmFwcGxlLmNvbS9kb2N1bWVudGF0aW9uL3VzZXJub3RpZmljYXRpb25zL2hhbmRsaW5nLW5vdGlmaWNhdGlvbi1yZXNwb25zZXMtZnJvbS1hcG5zXG4gICAgICAgICAgICBpZiAoZXJyb3IgPT09ICdVbnJlZ2lzdGVyZWQnIHx8IGVycm9yID09PSAnQmFkRGV2aWNlVG9rZW4nKSB7XG4gICAgICAgICAgICAgIGRldmljZXNUb1JlbW92ZS5wdXNoKHRva2VuKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgbWVtby5udW1GYWlsZWQrKztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbWVtbztcbiAgICAgIH0sIHVwZGF0ZSk7XG4gICAgfVxuXG4gICAgbG9nZ2VyLnZlcmJvc2UoXG4gICAgICBgX1B1c2hTdGF0dXMgJHtvYmplY3RJZH06IHNlbnQgcHVzaCEgJWQgc3VjY2VzcywgJWQgZmFpbHVyZXNgLFxuICAgICAgdXBkYXRlLm51bVNlbnQsXG4gICAgICB1cGRhdGUubnVtRmFpbGVkXG4gICAgKTtcbiAgICBsb2dnZXIudmVyYm9zZShgX1B1c2hTdGF0dXMgJHtvYmplY3RJZH06IG5lZWRzIGNsZWFudXBgLCB7XG4gICAgICBkZXZpY2VzVG9SZW1vdmUsXG4gICAgfSk7XG4gICAgWydudW1TZW50JywgJ251bUZhaWxlZCddLmZvckVhY2goa2V5ID0+IHtcbiAgICAgIGlmICh1cGRhdGVba2V5XSA+IDApIHtcbiAgICAgICAgdXBkYXRlW2tleV0gPSB7XG4gICAgICAgICAgX19vcDogJ0luY3JlbWVudCcsXG4gICAgICAgICAgYW1vdW50OiB1cGRhdGVba2V5XSxcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGRlbGV0ZSB1cGRhdGVba2V5XTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGlmIChkZXZpY2VzVG9SZW1vdmUubGVuZ3RoID4gMCAmJiBjbGVhbnVwSW5zdGFsbGF0aW9ucykge1xuICAgICAgbG9nZ2VyLmluZm8oYFJlbW92aW5nIGRldmljZSB0b2tlbnMgb24gJHtkZXZpY2VzVG9SZW1vdmUubGVuZ3RofSBfSW5zdGFsbGF0aW9uc2ApO1xuICAgICAgZGF0YWJhc2UudXBkYXRlKFxuICAgICAgICAnX0luc3RhbGxhdGlvbicsXG4gICAgICAgIHsgZGV2aWNlVG9rZW46IHsgJGluOiBkZXZpY2VzVG9SZW1vdmUgfSB9LFxuICAgICAgICB7IGRldmljZVRva2VuOiB7IF9fb3A6ICdEZWxldGUnIH0gfSxcbiAgICAgICAge1xuICAgICAgICAgIGFjbDogdW5kZWZpbmVkLFxuICAgICAgICAgIG1hbnk6IHRydWUsXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuICAgIGluY3JlbWVudE9wKHVwZGF0ZSwgJ2NvdW50JywgLTEpO1xuICAgIHVwZGF0ZS5zdGF0dXMgPSAncnVubmluZyc7XG5cbiAgICByZXR1cm4gaGFuZGxlci51cGRhdGUoeyBvYmplY3RJZCB9LCB1cGRhdGUpLnRoZW4ocmVzID0+IHtcbiAgICAgIGlmIChyZXMgJiYgcmVzLmNvdW50ID09PSAwKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbXBsZXRlKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgY29uc3QgY29tcGxldGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIGhhbmRsZXIudXBkYXRlKFxuICAgICAgeyBvYmplY3RJZCB9LFxuICAgICAge1xuICAgICAgICBzdGF0dXM6ICdzdWNjZWVkZWQnLFxuICAgICAgICBjb3VudDogeyBfX29wOiAnRGVsZXRlJyB9LFxuICAgICAgfVxuICAgICk7XG4gIH07XG5cbiAgY29uc3QgZmFpbCA9IGZ1bmN0aW9uIChlcnIpIHtcbiAgICBpZiAodHlwZW9mIGVyciA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGVyciA9IHsgbWVzc2FnZTogZXJyIH07XG4gICAgfVxuICAgIGNvbnN0IHVwZGF0ZSA9IHtcbiAgICAgIGVycm9yTWVzc2FnZTogZXJyLFxuICAgICAgc3RhdHVzOiAnZmFpbGVkJyxcbiAgICB9O1xuICAgIHJldHVybiBoYW5kbGVyLnVwZGF0ZSh7IG9iamVjdElkIH0sIHVwZGF0ZSk7XG4gIH07XG5cbiAgY29uc3QgcnZhbCA9IHtcbiAgICBzZXRJbml0aWFsLFxuICAgIHNldFJ1bm5pbmcsXG4gICAgdHJhY2tTZW50LFxuICAgIGNvbXBsZXRlLFxuICAgIGZhaWwsXG4gIH07XG5cbiAgLy8gZGVmaW5lIG9iamVjdElkIHRvIGJlIGR5bmFtaWNcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHJ2YWwsICdvYmplY3RJZCcsIHtcbiAgICBnZXQ6ICgpID0+IG9iamVjdElkLFxuICB9KTtcblxuICByZXR1cm4gT2JqZWN0LmZyZWV6ZShydmFsKTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFBQSxJQUFBQSxZQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxnQkFBQSxHQUFBRCxPQUFBO0FBQ0EsSUFBQUUsT0FBQSxHQUFBRixPQUFBO0FBQ0EsSUFBQUcsS0FBQSxHQUFBQyxzQkFBQSxDQUFBSixPQUFBO0FBQ0EsSUFBQUssS0FBQSxHQUFBRCxzQkFBQSxDQUFBSixPQUFBO0FBQTBCLFNBQUFJLHVCQUFBRSxDQUFBLFdBQUFBLENBQUEsSUFBQUEsQ0FBQSxDQUFBQyxVQUFBLEdBQUFELENBQUEsS0FBQUUsT0FBQSxFQUFBRixDQUFBO0FBQUEsU0FBQUcsUUFBQUgsQ0FBQSxFQUFBSSxDQUFBLFFBQUFDLENBQUEsR0FBQUMsTUFBQSxDQUFBQyxJQUFBLENBQUFQLENBQUEsT0FBQU0sTUFBQSxDQUFBRSxxQkFBQSxRQUFBQyxDQUFBLEdBQUFILE1BQUEsQ0FBQUUscUJBQUEsQ0FBQVIsQ0FBQSxHQUFBSSxDQUFBLEtBQUFLLENBQUEsR0FBQUEsQ0FBQSxDQUFBQyxNQUFBLFdBQUFOLENBQUEsV0FBQUUsTUFBQSxDQUFBSyx3QkFBQSxDQUFBWCxDQUFBLEVBQUFJLENBQUEsRUFBQVEsVUFBQSxPQUFBUCxDQUFBLENBQUFRLElBQUEsQ0FBQUMsS0FBQSxDQUFBVCxDQUFBLEVBQUFJLENBQUEsWUFBQUosQ0FBQTtBQUFBLFNBQUFVLGNBQUFmLENBQUEsYUFBQUksQ0FBQSxNQUFBQSxDQUFBLEdBQUFZLFNBQUEsQ0FBQUMsTUFBQSxFQUFBYixDQUFBLFVBQUFDLENBQUEsV0FBQVcsU0FBQSxDQUFBWixDQUFBLElBQUFZLFNBQUEsQ0FBQVosQ0FBQSxRQUFBQSxDQUFBLE9BQUFELE9BQUEs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QUN6QztRQUFFUSxXQUFXLEVBQUU7VUFBRWhHLElBQUksRUFBRTtRQUFTO01BQUUsQ0FBQyxFQUNuQztRQUNFcUcsR0FBRyxFQUFFeEQsU0FBUztRQUNkeUQsSUFBSSxFQUFFO01BQ1IsQ0FDRixDQUFDO0lBQ0g7SUFDQTFHLFdBQVcsQ0FBQ2tCLE1BQU0sRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDaENBLE1BQU0sQ0FBQ3NCLE1BQU0sR0FBRyxTQUFTO0lBRXpCLE9BQU9OLE9BQU8sQ0FBQ2hCLE1BQU0sQ0FBQztNQUFFRztJQUFTLENBQUMsRUFBRUgsTUFBTSxDQUFDLENBQUNILElBQUksQ0FBQzRGLEdBQUcsSUFBSTtNQUN0RCxJQUFJQSxHQUFHLElBQUlBLEdBQUcsQ0FBQ3hCLEtBQUssS0FBSyxDQUFDLEVBQUU7UUFDMUIsT0FBTyxJQUFJLENBQUN5QixRQUFRLENBQUMsQ0FBQztNQUN4QjtJQUNGLENBQUMsQ0FBQztFQUNKLENBQUM7RUFFRCxNQUFNQSxRQUFRLEdBQUcsU0FBQUEsQ0FBQSxFQUFZO0lBQzNCLE9BQU8xRSxPQUFPLENBQUNoQixNQUFNLENBQ25CO01BQUVHO0lBQVMsQ0FBQyxFQUNaO01BQ0VtQixNQUFNLEVBQUUsV0FBVztNQUNuQjJDLEtBQUssRUFBRTtRQUFFL0UsSUFBSSxFQUFFO01BQVM7SUFDMUIsQ0FDRixDQUFDO0VBQ0gsQ0FBQztFQUVELE1BQU15RyxJQUFJLEdBQUcsU0FBQUEsQ0FBVUMsR0FBRyxFQUFFO0lBQzFCLElBQUksT0FBT0EsR0FBRyxLQUFLLFFBQVEsRUFBRTtNQUMzQkEsR0FBRyxHQUFHO1FBQUVqRSxPQUFPLEVBQUVpRTtNQUFJLENBQUM7SUFDeEI7SUFDQSxNQUFNNUYsTUFBTSxHQUFHO01BQ2I2RixZQUFZLEVBQUVELEdBQUc7TUFDakJ0RSxNQUFNLEVBQUU7SUFDVixDQUFDO0lBQ0QsT0FBT04sT0FBTyxDQUFDaEIsTUFBTSxDQUFDO01BQUVHO0lBQVMsQ0FBQyxFQUFFSCxNQUFNLENBQUM7RUFDN0MsQ0FBQztFQUVELE1BQU04RixJQUFJLEdBQUc7SUFDWHpELFVBQVU7SUFDVnBCLFVBQVU7SUFDVmlELFNBQVM7SUFDVHdCLFFBQVE7SUFDUkM7RUFDRixDQUFDOztFQUVEO0VBQ0EvSSxNQUFNLENBQUNnQixjQUFjLENBQUNrSSxJQUFJLEVBQUUsVUFBVSxFQUFFO0lBQ3RDQyxHQUFHLEVBQUVBLENBQUEsS0FBTTVGO0VBQ2IsQ0FBQyxDQUFDO0VBRUYsT0FBT3ZELE1BQU0sQ0FBQ3dELE1BQU0sQ0FBQzBGLElBQUksQ0FBQztBQUM1QiIsImlnbm9yZUxpc3QiOltdfQ==