UNPKG

israeli-bank-scrapers

Version:

Provide scrapers for all major Israeli banks and credit card companies

243 lines (241 loc) 36.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _moment = _interopRequireDefault(require("moment/moment")); var _debug = require("../helpers/debug"); var _fetch = require("../helpers/fetch"); var _transactions = require("../helpers/transactions"); var _transactions2 = require("../transactions"); var _baseScraper = require("./base-scraper"); var _errors = require("./errors"); var _oneZeroQueries = require("./one-zero-queries"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const HEBREW_WORDS_REGEX = /[\u0590-\u05FF][\u0590-\u05FF"'\-_ /\\]*[\u0590-\u05FF]/g; const debug = (0, _debug.getDebug)('one-zero'); const IDENTITY_SERVER_URL = 'https://identity.tfd-bank.com/v1/'; const GRAPHQL_API_URL = 'https://mobile.tfd-bank.com/mobile-graph/graphql'; class OneZeroScraper extends _baseScraper.BaseScraper { async triggerTwoFactorAuth(phoneNumber) { if (!phoneNumber.startsWith('+')) { return (0, _errors.createGenericError)('A full international phone number starting with + and a three digit country code is required'); } debug('Fetching device token'); const deviceTokenResponse = await (0, _fetch.fetchPost)(`${IDENTITY_SERVER_URL}/devices/token`, { extClientId: 'mobile', os: 'Android' }); const { resultData: { deviceToken } } = deviceTokenResponse; debug(`Sending OTP to phone number ${phoneNumber}`); const otpPrepareResponse = await (0, _fetch.fetchPost)(`${IDENTITY_SERVER_URL}/otp/prepare`, { factorValue: phoneNumber, deviceToken, otpChannel: 'SMS_OTP' }); const { resultData: { otpContext } } = otpPrepareResponse; this.otpContext = otpContext; return { success: true }; } async getLongTermTwoFactorToken(otpCode) { if (!this.otpContext) { return (0, _errors.createGenericError)('triggerOtp was not called before calling getPermenantOtpToken()'); } debug('Requesting OTP token'); const otpVerifyResponse = await (0, _fetch.fetchPost)(`${IDENTITY_SERVER_URL}/otp/verify`, { otpContext: this.otpContext, otpCode }); const { resultData: { otpToken } } = otpVerifyResponse; return { success: true, longTermTwoFactorAuthToken: otpToken }; } async resolveOtpToken(credentials) { if ('otpLongTermToken' in credentials) { if (!credentials.otpLongTermToken) { return (0, _errors.createGenericError)('Invalid otpLongTermToken'); } return { success: true, longTermTwoFactorAuthToken: credentials.otpLongTermToken }; } if (!credentials.otpCodeRetriever) { return { success: false, errorType: _errors.ScraperErrorTypes.TwoFactorRetrieverMissing, errorMessage: 'otpCodeRetriever is required when otpPermanentToken is not provided' }; } if (!credentials.phoneNumber) { return (0, _errors.createGenericError)('phoneNumber is required when providing a otpCodeRetriever callback'); } debug('Triggering user supplied otpCodeRetriever callback'); const triggerResult = await this.triggerTwoFactorAuth(credentials.phoneNumber); if (!triggerResult.success) { return triggerResult; } const otpCode = await credentials.otpCodeRetriever(); const otpTokenResult = await this.getLongTermTwoFactorToken(otpCode); if (!otpTokenResult.success) { return otpTokenResult; } return { success: true, longTermTwoFactorAuthToken: otpTokenResult.longTermTwoFactorAuthToken }; } async login(credentials) { const otpTokenResult = await this.resolveOtpToken(credentials); if (!otpTokenResult.success) { return otpTokenResult; } debug('Requesting id token'); const getIdTokenResponse = await (0, _fetch.fetchPost)(`${IDENTITY_SERVER_URL}/getIdToken`, { otpSmsToken: otpTokenResult.longTermTwoFactorAuthToken, email: credentials.email, pass: credentials.password, pinCode: '' }); const { resultData: { idToken } } = getIdTokenResponse; debug('Requesting session token'); const getSessionTokenResponse = await (0, _fetch.fetchPost)(`${IDENTITY_SERVER_URL}/sessions/token`, { idToken, pass: credentials.password }); const { resultData: { accessToken } } = getSessionTokenResponse; this.accessToken = accessToken; return { success: true, persistentOtpToken: otpTokenResult.longTermTwoFactorAuthToken }; } async fetchPortfolioMovements(portfolio, startDate) { // TODO: Find out if we need the other accounts, there seems to always be one const account = portfolio.accounts[0]; let cursor = null; const movements = []; while (!movements.length || new Date(movements[0].movementTimestamp) >= startDate) { debug(`Fetching transactions for account ${portfolio.portfolioNum}...`); const { movements: { movements: newMovements, pagination } } = await (0, _fetch.fetchGraphql)(GRAPHQL_API_URL, _oneZeroQueries.GET_MOVEMENTS, { portfolioId: portfolio.portfolioId, accountId: account.accountId, language: 'HEBREW', pagination: { cursor, limit: 50 } }, { authorization: `Bearer ${this.accessToken}` }); movements.unshift(...newMovements); cursor = pagination.cursor; if (!pagination.hasMore) { break; } } movements.sort((x, y) => new Date(x.movementTimestamp).valueOf() - new Date(y.movementTimestamp).valueOf()); const matchingMovements = movements.filter(movement => new Date(movement.movementTimestamp) >= startDate); return { accountNumber: portfolio.portfolioNum, balance: !movements.length ? 0 : parseFloat(movements[movements.length - 1].runningBalance), txns: matchingMovements.map(movement => { const hasInstallments = movement.transaction?.enrichment?.recurrences?.some(x => x.isRecurrent); const modifier = movement.creditDebit === 'DEBIT' ? -1 : 1; const result = { identifier: movement.movementId, date: movement.valueDate, chargedAmount: +movement.movementAmount * modifier, chargedCurrency: movement.movementCurrency, originalAmount: +movement.movementAmount * modifier, originalCurrency: movement.movementCurrency, description: this.sanitizeHebrew(movement.description), processedDate: movement.movementTimestamp, status: _transactions2.TransactionStatuses.Completed, type: hasInstallments ? _transactions2.TransactionTypes.Installments : _transactions2.TransactionTypes.Normal }; if (this.options?.includeRawTransaction) { result.rawTransaction = (0, _transactions.getRawTransaction)(movement); } return result; }) }; } /** * one zero hebrew strings are reversed with a unicode control character that forces display in LTR order * We need to remove the unicode control character, and then reverse hebrew substrings inside the string */ sanitizeHebrew(text) { if (!text.includes('\u202d')) { return text.trim(); } const plainString = text.replace(/\u202d/gi, '').trim(); const hebrewSubStringsRanges = [...plainString.matchAll(HEBREW_WORDS_REGEX)]; const rangesToReverse = hebrewSubStringsRanges.map(str => ({ start: str.index, end: str.index + str[0].length })); const out = []; let index = 0; for (const { start, end } of rangesToReverse) { out.push(...plainString.substring(index, start)); index += start - index; const reversed = [...plainString.substring(start, end)].reverse(); out.push(...reversed); index += end - start; } out.push(...plainString.substring(index, plainString.length)); return out.join(''); } async fetchData() { if (!this.accessToken) { return (0, _errors.createGenericError)('login() was not called'); } const defaultStartMoment = (0, _moment.default)().subtract(1, 'years').add(1, 'day'); const startDate = this.options.startDate || defaultStartMoment.toDate(); const startMoment = _moment.default.max(defaultStartMoment, (0, _moment.default)(startDate)); debug('Fetching account list'); const result = await (0, _fetch.fetchGraphql)(GRAPHQL_API_URL, _oneZeroQueries.GET_CUSTOMER, {}, { authorization: `Bearer ${this.accessToken}` }); const portfolios = result.customer.flatMap(customer => customer.portfolios || []); return { success: true, accounts: await Promise.all(portfolios.map(portfolio => this.fetchPortfolioMovements(portfolio, startMoment.toDate()))) }; } } exports.default = OneZeroScraper; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbW9tZW50IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfZGVidWciLCJfZmV0Y2giLCJfdHJhbnNhY3Rpb25zIiwiX3RyYW5zYWN0aW9uczIiLCJfYmFzZVNjcmFwZXIiLCJfZXJyb3JzIiwiX29uZVplcm9RdWVyaWVzIiwiZSIsIl9fZXNNb2R1bGUiLCJkZWZhdWx0IiwiSEVCUkVXX1dPUkRTX1JFR0VYIiwiZGVidWciLCJnZXREZWJ1ZyIsIklERU5USVRZX1NFUlZFUl9VUkwiLCJHUkFQSFFMX0FQSV9VUkwiLCJPbmVaZXJvU2NyYXBlciIsIkJhc2VTY3JhcGVyIiwidHJpZ2dlclR3b0ZhY3RvckF1dGgiLCJwaG9uZU51bWJlciIsInN0YXJ0c1dpdGgiLCJjcmVhdGVHZW5lcmljRXJyb3IiLCJkZXZpY2VUb2tlblJlc3BvbnNlIiwiZmV0Y2hQb3N0IiwiZXh0Q2xpZW50SWQiLCJvcyIsInJlc3VsdERhdGEiLCJkZXZpY2VUb2tlbiIsIm90cFByZXBhcmVSZXNwb25zZSIsImZhY3RvclZhbHVlIiwib3RwQ2hhbm5lbCIsIm90cENvbnRleHQiLCJzdWNjZXNzIiwiZ2V0TG9uZ1Rlcm1Ud29GYWN0b3JUb2tlbiIsIm90cENvZGUiLCJvdHBWZXJpZnlSZXNwb25zZSIsIm90cFRva2VuIiwibG9uZ1Rlcm1Ud29GYWN0b3JBdXRoVG9rZW4iLCJyZXNvbHZlT3RwVG9rZW4iLCJjcmVkZW50aWFscyIsIm90cExvbmdUZXJtVG9rZW4iLCJvdHBDb2RlUmV0cmlldmVyIiwiZXJyb3JUeXBlIiwiU2NyYXBlckVycm9yVHlwZXMiLCJUd29GYWN0b3JSZXRyaWV2ZXJNaXNzaW5nIiwiZXJyb3JNZXNzYWdlIiwidHJpZ2dlclJlc3VsdCIsIm90cFRva2VuUmVzdWx0IiwibG9naW4iLCJnZXRJZFRva2VuUmVzcG9uc2UiLCJvdHBTbXNUb2tlbiIsImVtYWlsIiwicGFzcyIsInBhc3N3b3JkIiwicGluQ29kZSIsImlkVG9rZW4iLCJnZXRTZXNzaW9uVG9rZW5SZXNwb25zZSIsImFjY2Vzc1Rva2VuIiwicGVyc2lzdGVudE90cFRva2VuIiwiZmV0Y2hQb3J0Zm9saW9Nb3ZlbWVudHMiLCJwb3J0Zm9saW8iLCJzdGFydERhdGUiLCJhY2NvdW50IiwiYWNjb3VudHMiLCJjdXJzb3IiLCJtb3ZlbWVudHMiLCJsZW5ndGgiLCJEYXRlIiwibW92ZW1lbnRUaW1lc3RhbXAiLCJwb3J0Zm9saW9OdW0iLCJuZXdNb3ZlbWVudHMiLCJwYWdpbmF0aW9uIiwiZmV0Y2hHcmFwaHFsIiwiR0VUX01PVkVNRU5UUyIsInBvcnRmb2xpb0lkIiwiYWNjb3VudElkIiwibGFuZ3VhZ2UiLCJsaW1pdCIsImF1dGhvcml6YXRpb24iLCJ1bnNoaWZ0IiwiaGFzTW9yZSIsInNvcnQiLCJ4IiwieSIsInZhbHVlT2YiLCJtYXRjaGluZ01vdmVtZW50cyIsImZpbHRlciIsIm1vdmVtZW50IiwiYWNjb3VudE51bWJlciIsImJhbGFuY2UiLCJwYXJzZUZsb2F0IiwicnVubmluZ0JhbGFuY2UiLCJ0eG5zIiwibWFwIiwiaGFzSW5zdGFsbG1lbnRzIiwidHJhbnNhY3Rpb24iLCJlbnJpY2htZW50IiwicmVjdXJyZW5jZXMiLCJzb21lIiwiaXNSZWN1cnJlbnQiLCJtb2RpZmllciIsImNyZWRpdERlYml0IiwicmVzdWx0IiwiaWRlbnRpZmllciIsIm1vdmVtZW50SWQiLCJkYXRlIiwidmFsdWVEYXRlIiwiY2hhcmdlZEFtb3VudCIsIm1vdmVtZW50QW1vdW50IiwiY2hhcmdlZEN1cnJlbmN5IiwibW92ZW1lbnRDdXJyZW5jeSIsIm9yaWdpbmFsQW1vdW50Iiwib3JpZ2luYWxDdXJyZW5jeSIsImRlc2NyaXB0aW9uIiwic2FuaXRpemVIZWJyZXciLCJwcm9jZXNzZWREYXRlIiwic3RhdHVzIiwiVHJhbnNhY3Rpb25TdGF0dXNlcyIsIkNvbXBsZXRlZCIsInR5cGUiLCJUcmFuc2FjdGlvblR5cGVzIiwiSW5zdGFsbG1lbnRzIiwiTm9ybWFsIiwib3B0aW9ucyIsImluY2x1ZGVSYXdUcmFuc2FjdGlvbiIsInJhd1RyYW5zYWN0aW9uIiwiZ2V0UmF3VHJhbnNhY3Rpb24iLCJ0ZXh0IiwiaW5jbHVkZXMiLCJ0cmltIiwicGxhaW5TdHJpbmciLCJyZXBsYWNlIiwiaGVicmV3U3ViU3RyaW5nc1JhbmdlcyIsIm1hdGNoQWxsIiwicmFuZ2VzVG9SZXZlcnNlIiwic3RyIiwic3RhcnQiLCJpbmRleCIsImVuZCIsIm91dCIsInB1c2giLCJzdWJzdHJpbmciLCJyZXZlcnNlZCIsInJldmVyc2UiLCJqb2luIiwiZmV0Y2hEYXRhIiwiZGVmYXVsdFN0YXJ0TW9tZW50IiwibW9tZW50Iiwic3VidHJhY3QiLCJhZGQiLCJ0b0RhdGUiLCJzdGFydE1vbWVudCIsIm1heCIsIkdFVF9DVVNUT01FUiIsInBvcnRmb2xpb3MiLCJjdXN0b21lciIsImZsYXRNYXAiLCJQcm9taXNlIiwiYWxsIiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY3JhcGVycy9vbmUtemVyby50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgbW9tZW50IGZyb20gJ21vbWVudC9tb21lbnQnO1xuaW1wb3J0IHsgZ2V0RGVidWcgfSBmcm9tICcuLi9oZWxwZXJzL2RlYnVnJztcbmltcG9ydCB7IGZldGNoR3JhcGhxbCwgZmV0Y2hQb3N0IH0gZnJvbSAnLi4vaGVscGVycy9mZXRjaCc7XG5pbXBvcnQgeyBnZXRSYXdUcmFuc2FjdGlvbiB9IGZyb20gJy4uL2hlbHBlcnMvdHJhbnNhY3Rpb25zJztcbmltcG9ydCB7XG4gIHR5cGUgVHJhbnNhY3Rpb24gYXMgU2NyYXBpbmdUcmFuc2FjdGlvbixcbiAgVHJhbnNhY3Rpb25TdGF0dXNlcyxcbiAgVHJhbnNhY3Rpb25UeXBlcyxcbiAgdHlwZSBUcmFuc2FjdGlvbnNBY2NvdW50LFxufSBmcm9tICcuLi90cmFuc2FjdGlvbnMnO1xuaW1wb3J0IHsgQmFzZVNjcmFwZXIgfSBmcm9tICcuL2Jhc2Utc2NyYXBlcic7XG5pbXBvcnQgeyBTY3JhcGVyRXJyb3JUeXBlcywgY3JlYXRlR2VuZXJpY0Vycm9yIH0gZnJvbSAnLi9lcnJvcnMnO1xuaW1wb3J0IHtcbiAgdHlwZSBTY3JhcGVyR2V0TG9uZ1Rlcm1Ud29GYWN0b3JUb2tlblJlc3VsdCxcbiAgdHlwZSBTY3JhcGVyTG9naW5SZXN1bHQsXG4gIHR5cGUgU2NyYXBlclNjcmFwaW5nUmVzdWx0LFxuICB0eXBlIFNjcmFwZXJUd29GYWN0b3JBdXRoVHJpZ2dlclJlc3VsdCxcbn0gZnJvbSAnLi9pbnRlcmZhY2UnO1xuaW1wb3J0IHsgR0VUX0NVU1RPTUVSLCBHRVRfTU9WRU1FTlRTIH0gZnJvbSAnLi9vbmUtemVyby1xdWVyaWVzJztcblxuY29uc3QgSEVCUkVXX1dPUkRTX1JFR0VYID0gL1tcXHUwNTkwLVxcdTA1RkZdW1xcdTA1OTAtXFx1MDVGRlwiJ1xcLV8gL1xcXFxdKltcXHUwNTkwLVxcdTA1RkZdL2c7XG5cbmNvbnN0IGRlYnVnID0gZ2V0RGVidWcoJ29uZS16ZXJvJyk7XG5cbnR5cGUgQWNjb3VudCA9IHtcbiAgYWNjb3VudElkOiBzdHJpbmc7XG59O1xuXG50eXBlIFBvcnRmb2xpbyA9IHtcbiAgYWNjb3VudHM6IEFycmF5PEFjY291bnQ+O1xuICBwb3J0Zm9saW9JZDogc3RyaW5nO1xuICBwb3J0Zm9saW9OdW06IHN0cmluZztcbn07XG5cbnR5cGUgQ3VzdG9tZXIgPSB7XG4gIGN1c3RvbWVySWQ6IHN0cmluZztcbiAgcG9ydGZvbGlvcz86IEFycmF5PFBvcnRmb2xpbz4gfCBudWxsO1xufTtcblxuZXhwb3J0IHR5cGUgQ2F0ZWdvcnkgPSB7XG4gIGNhdGVnb3J5SWQ6IG51bWJlcjtcbiAgZGF0YVNvdXJjZTogc3RyaW5nO1xuICBzdWJDYXRlZ29yeUlkPzogbnVtYmVyIHwgbnVsbDtcbn07XG5cbmV4cG9ydCB0eXBlIFJlY3VycmVuY2UgPSB7XG4gIGRhdGFTb3VyY2U6IHN0cmluZztcbiAgaXNSZWN1cnJlbnQ6IGJvb2xlYW47XG59O1xuXG50eXBlIFRyYW5zYWN0aW9uRW5yaWNobWVudCA9IHtcbiAgY2F0ZWdvcmllcz86IENhdGVnb3J5W10gfCBudWxsO1xuICByZWN1cnJlbmNlcz86IFJlY3VycmVuY2VbXSB8IG51bGw7XG59O1xuXG50eXBlIFRyYW5zYWN0aW9uID0ge1xuICBlbnJpY2htZW50PzogVHJhbnNhY3Rpb25FbnJpY2htZW50IHwgbnVsbDtcbiAgLy8gVE9ETzogR2V0IGluc3RhbGxtZW50cyBpbmZvcm1hdGlvbiBoZXJlXG4gIC8vIHRyYW5zYWN0aW9uRGV0YWlsczogVHJhbnNhY3Rpb25EZXRhaWxzO1xufTtcblxudHlwZSBNb3ZlbWVudCA9IHtcbiAgYWNjb3VudElkOiBzdHJpbmc7XG4gIGJhbmtDdXJyZW5jeUFtb3VudDogc3RyaW5nO1xuICBib29raW5nRGF0ZTogc3RyaW5nO1xuICBjb252ZXJzaW9uUmF0ZTogc3RyaW5nO1xuICBjcmVkaXREZWJpdDogc3RyaW5nO1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICBpc1JldmVyc2VkOiBib29sZWFuO1xuICBtb3ZlbWVudEFtb3VudDogc3RyaW5nO1xuICBtb3ZlbWVudEN1cnJlbmN5OiBzdHJpbmc7XG4gIG1vdmVtZW50SWQ6IHN0cmluZztcbiAgbW92ZW1lbnRSZXZlcnNlZElkPzogc3RyaW5nIHwgbnVsbDtcbiAgbW92ZW1lbnRUaW1lc3RhbXA6IHN0cmluZztcbiAgbW92ZW1lbnRUeXBlOiBzdHJpbmc7XG4gIHBvcnRmb2xpb0lkOiBzdHJpbmc7XG4gIHJ1bm5pbmdCYWxhbmNlOiBzdHJpbmc7XG4gIHRyYW5zYWN0aW9uPzogVHJhbnNhY3Rpb24gfCBudWxsO1xuICB2YWx1ZURhdGU6IHN0cmluZztcbn07XG5cbnR5cGUgUXVlcnlQYWdpbmF0aW9uID0geyBoYXNNb3JlOiBib29sZWFuOyBjdXJzb3I6IHN0cmluZyB9O1xuXG5jb25zdCBJREVOVElUWV9TRVJWRVJfVVJMID0gJ2h0dHBzOi8vaWRlbnRpdHkudGZkLWJhbmsuY29tL3YxLyc7XG5cbmNvbnN0IEdSQVBIUUxfQVBJX1VSTCA9ICdodHRwczovL21vYmlsZS50ZmQtYmFuay5jb20vbW9iaWxlLWdyYXBoL2dyYXBocWwnO1xuXG50eXBlIFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzID0geyBlbWFpbDogc3RyaW5nOyBwYXNzd29yZDogc3RyaW5nIH0gJiAoXG4gIHwge1xuICAgICAgb3RwQ29kZVJldHJpZXZlcjogKCkgPT4gUHJvbWlzZTxzdHJpbmc+O1xuICAgICAgcGhvbmVOdW1iZXI6IHN0cmluZztcbiAgICB9XG4gIHwge1xuICAgICAgb3RwTG9uZ1Rlcm1Ub2tlbjogc3RyaW5nO1xuICAgIH1cbik7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE9uZVplcm9TY3JhcGVyIGV4dGVuZHMgQmFzZVNjcmFwZXI8U2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHM+IHtcbiAgcHJpdmF0ZSBvdHBDb250ZXh0Pzogc3RyaW5nO1xuXG4gIHByaXZhdGUgYWNjZXNzVG9rZW4/OiBzdHJpbmc7XG5cbiAgYXN5bmMgdHJpZ2dlclR3b0ZhY3RvckF1dGgocGhvbmVOdW1iZXI6IHN0cmluZyk6IFByb21pc2U8U2NyYXBlclR3b0ZhY3RvckF1dGhUcmlnZ2VyUmVzdWx0PiB7XG4gICAgaWYgKCFwaG9uZU51bWJlci5zdGFydHNXaXRoKCcrJykpIHtcbiAgICAgIHJldHVybiBjcmVhdGVHZW5lcmljRXJyb3IoXG4gICAgICAgICdBIGZ1bGwgaW50ZXJuYXRpb25hbCBwaG9uZSBudW1iZXIgc3RhcnRpbmcgd2l0aCArIGFuZCBhIHRocmVlIGRpZ2l0IGNvdW50cnkgY29kZSBpcyByZXF1aXJlZCcsXG4gICAgICApO1xuICAgIH1cblxuICAgIGRlYnVnKCdGZXRjaGluZyBkZXZpY2UgdG9rZW4nKTtcbiAgICBjb25zdCBkZXZpY2VUb2tlblJlc3BvbnNlID0gYXdhaXQgZmV0Y2hQb3N0KGAke0lERU5USVRZX1NFUlZFUl9VUkx9L2RldmljZXMvdG9rZW5gLCB7XG4gICAgICBleHRDbGllbnRJZDogJ21vYmlsZScsXG4gICAgICBvczogJ0FuZHJvaWQnLFxuICAgIH0pO1xuXG4gICAgY29uc3Qge1xuICAgICAgcmVzdWx0RGF0YTogeyBkZXZpY2VUb2tlbiB9LFxuICAgIH0gPSBkZXZpY2VUb2tlblJlc3BvbnNlO1xuXG4gICAgZGVidWcoYFNlbmRpbmcgT1RQIHRvIHBob25lIG51bWJlciAke3Bob25lTnVtYmVyfWApO1xuXG4gICAgY29uc3Qgb3RwUHJlcGFyZVJlc3BvbnNlID0gYXdhaXQgZmV0Y2hQb3N0KGAke0lERU5USVRZX1NFUlZFUl9VUkx9L290cC9wcmVwYXJlYCwge1xuICAgICAgZmFjdG9yVmFsdWU6IHBob25lTnVtYmVyLFxuICAgICAgZGV2aWNlVG9rZW4sXG4gICAgICBvdHBDaGFubmVsOiAnU01TX09UUCcsXG4gICAgfSk7XG5cbiAgICBjb25zdCB7XG4gICAgICByZXN1bHREYXRhOiB7IG90cENvbnRleHQgfSxcbiAgICB9ID0gb3RwUHJlcGFyZVJlc3BvbnNlO1xuXG4gICAgdGhpcy5vdHBDb250ZXh0ID0gb3RwQ29udGV4dDtcblxuICAgIHJldHVybiB7XG4gICAgICBzdWNjZXNzOiB0cnVlLFxuICAgIH07XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZ2V0TG9uZ1Rlcm1Ud29GYWN0b3JUb2tlbihvdHBDb2RlOiBzdHJpbmcpOiBQcm9taXNlPFNjcmFwZXJHZXRMb25nVGVybVR3b0ZhY3RvclRva2VuUmVzdWx0PiB7XG4gICAgaWYgKCF0aGlzLm90cENvbnRleHQpIHtcbiAgICAgIHJldHVybiBjcmVhdGVHZW5lcmljRXJyb3IoJ3RyaWdnZXJPdHAgd2FzIG5vdCBjYWxsZWQgYmVmb3JlIGNhbGxpbmcgZ2V0UGVybWVuYW50T3RwVG9rZW4oKScpO1xuICAgIH1cblxuICAgIGRlYnVnKCdSZXF1ZXN0aW5nIE9UUCB0b2tlbicpO1xuICAgIGNvbnN0IG90cFZlcmlmeVJlc3BvbnNlID0gYXdhaXQgZmV0Y2hQb3N0KGAke0lERU5USVRZX1NFUlZFUl9VUkx9L290cC92ZXJpZnlgLCB7XG4gICAgICBvdHBDb250ZXh0OiB0aGlzLm90cENvbnRleHQsXG4gICAgICBvdHBDb2RlLFxuICAgIH0pO1xuXG4gICAgY29uc3Qge1xuICAgICAgcmVzdWx0RGF0YTogeyBvdHBUb2tlbiB9LFxuICAgIH0gPSBvdHBWZXJpZnlSZXNwb25zZTtcbiAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlLCBsb25nVGVybVR3b0ZhY3RvckF1dGhUb2tlbjogb3RwVG9rZW4gfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcmVzb2x2ZU90cFRva2VuKFxuICAgIGNyZWRlbnRpYWxzOiBTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscyxcbiAgKTogUHJvbWlzZTxTY3JhcGVyR2V0TG9uZ1Rlcm1Ud29GYWN0b3JUb2tlblJlc3VsdD4ge1xuICAgIGlmICgnb3RwTG9uZ1Rlcm1Ub2tlbicgaW4gY3JlZGVudGlhbHMpIHtcbiAgICAgIGlmICghY3JlZGVudGlhbHMub3RwTG9uZ1Rlcm1Ub2tlbikge1xuICAgICAgICByZXR1cm4gY3JlYXRlR2VuZXJpY0Vycm9yKCdJbnZhbGlkIG90cExvbmdUZXJtVG9rZW4nKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUsIGxvbmdUZXJtVHdvRmFjdG9yQXV0aFRva2VuOiBjcmVkZW50aWFscy5vdHBMb25nVGVybVRva2VuIH07XG4gICAgfVxuXG4gICAgaWYgKCFjcmVkZW50aWFscy5vdHBDb2RlUmV0cmlldmVyKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgZXJyb3JUeXBlOiBTY3JhcGVyRXJyb3JUeXBlcy5Ud29GYWN0b3JSZXRyaWV2ZXJNaXNzaW5nLFxuICAgICAgICBlcnJvck1lc3NhZ2U6ICdvdHBDb2RlUmV0cmlldmVyIGlzIHJlcXVpcmVkIHdoZW4gb3RwUGVybWFuZW50VG9rZW4gaXMgbm90IHByb3ZpZGVkJyxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKCFjcmVkZW50aWFscy5waG9uZU51bWJlcikge1xuICAgICAgcmV0dXJuIGNyZWF0ZUdlbmVyaWNFcnJvcigncGhvbmVOdW1iZXIgaXMgcmVxdWlyZWQgd2hlbiBwcm92aWRpbmcgYSBvdHBDb2RlUmV0cmlldmVyIGNhbGxiYWNrJyk7XG4gICAgfVxuXG4gICAgZGVidWcoJ1RyaWdnZXJpbmcgdXNlciBzdXBwbGllZCBvdHBDb2RlUmV0cmlldmVyIGNhbGxiYWNrJyk7XG4gICAgY29uc3QgdHJpZ2dlclJlc3VsdCA9IGF3YWl0IHRoaXMudHJpZ2dlclR3b0ZhY3RvckF1dGgoY3JlZGVudGlhbHMucGhvbmVOdW1iZXIpO1xuXG4gICAgaWYgKCF0cmlnZ2VyUmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICAgIHJldHVybiB0cmlnZ2VyUmVzdWx0O1xuICAgIH1cblxuICAgIGNvbnN0IG90cENvZGUgPSBhd2FpdCBjcmVkZW50aWFscy5vdHBDb2RlUmV0cmlldmVyKCk7XG5cbiAgICBjb25zdCBvdHBUb2tlblJlc3VsdCA9IGF3YWl0IHRoaXMuZ2V0TG9uZ1Rlcm1Ud29GYWN0b3JUb2tlbihvdHBDb2RlKTtcbiAgICBpZiAoIW90cFRva2VuUmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICAgIHJldHVybiBvdHBUb2tlblJlc3VsdDtcbiAgICB9XG5cbiAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlLCBsb25nVGVybVR3b0ZhY3RvckF1dGhUb2tlbjogb3RwVG9rZW5SZXN1bHQubG9uZ1Rlcm1Ud29GYWN0b3JBdXRoVG9rZW4gfTtcbiAgfVxuXG4gIGFzeW5jIGxvZ2luKGNyZWRlbnRpYWxzOiBTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscyk6IFByb21pc2U8U2NyYXBlckxvZ2luUmVzdWx0PiB7XG4gICAgY29uc3Qgb3RwVG9rZW5SZXN1bHQgPSBhd2FpdCB0aGlzLnJlc29sdmVPdHBUb2tlbihjcmVkZW50aWFscyk7XG4gICAgaWYgKCFvdHBUb2tlblJlc3VsdC5zdWNjZXNzKSB7XG4gICAgICByZXR1cm4gb3RwVG9rZW5SZXN1bHQ7XG4gICAgfVxuXG4gICAgZGVidWcoJ1JlcXVlc3RpbmcgaWQgdG9rZW4nKTtcbiAgICBjb25zdCBnZXRJZFRva2VuUmVzcG9uc2UgPSBhd2FpdCBmZXRjaFBvc3QoYCR7SURFTlRJVFlfU0VSVkVSX1VSTH0vZ2V0SWRUb2tlbmAsIHtcbiAgICAgIG90cFNtc1Rva2VuOiBvdHBUb2tlblJlc3VsdC5sb25nVGVybVR3b0ZhY3RvckF1dGhUb2tlbixcbiAgICAgIGVtYWlsOiBjcmVkZW50aWFscy5lbWFpbCxcbiAgICAgIHBhc3M6IGNyZWRlbnRpYWxzLnBhc3N3b3JkLFxuICAgICAgcGluQ29kZTogJycsXG4gICAgfSk7XG5cbiAgICBjb25zdCB7XG4gICAgICByZXN1bHREYXRhOiB7IGlkVG9rZW4gfSxcbiAgICB9ID0gZ2V0SWRUb2tlblJlc3BvbnNlO1xuXG4gICAgZGVidWcoJ1JlcXVlc3Rpbmcgc2Vzc2lvbiB0b2tlbicpO1xuXG4gICAgY29uc3QgZ2V0U2Vzc2lvblRva2VuUmVzcG9uc2UgPSBhd2FpdCBmZXRjaFBvc3QoYCR7SURFTlRJVFlfU0VSVkVSX1VSTH0vc2Vzc2lvbnMvdG9rZW5gLCB7XG4gICAgICBpZFRva2VuLFxuICAgICAgcGFzczogY3JlZGVudGlhbHMucGFzc3dvcmQsXG4gICAgfSk7XG5cbiAgICBjb25zdCB7XG4gICAgICByZXN1bHREYXRhOiB7IGFjY2Vzc1Rva2VuIH0sXG4gICAgfSA9IGdldFNlc3Npb25Ub2tlblJlc3BvbnNlO1xuXG4gICAgdGhpcy5hY2Nlc3NUb2tlbiA9IGFjY2Vzc1Rva2VuO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICBwZXJzaXN0ZW50T3RwVG9rZW46IG90cFRva2VuUmVzdWx0LmxvbmdUZXJtVHdvRmFjdG9yQXV0aFRva2VuLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGZldGNoUG9ydGZvbGlvTW92ZW1lbnRzKHBvcnRmb2xpbzogUG9ydGZvbGlvLCBzdGFydERhdGU6IERhdGUpOiBQcm9taXNlPFRyYW5zYWN0aW9uc0FjY291bnQ+IHtcbiAgICAvLyBUT0RPOiBGaW5kIG91dCBpZiB3ZSBuZWVkIHRoZSBvdGhlciBhY2NvdW50cywgdGhlcmUgc2VlbXMgdG8gYWx3YXlzIGJlIG9uZVxuICAgIGNvbnN0IGFjY291bnQgPSBwb3J0Zm9saW8uYWNjb3VudHNbMF07XG4gICAgbGV0IGN1cnNvciA9IG51bGw7XG4gICAgY29uc3QgbW92ZW1lbnRzID0gW107XG5cbiAgICB3aGlsZSAoIW1vdmVtZW50cy5sZW5ndGggfHwgbmV3IERhdGUobW92ZW1lbnRzWzBdLm1vdmVtZW50VGltZXN0YW1wKSA+PSBzdGFydERhdGUpIHtcbiAgICAgIGRlYnVnKGBGZXRjaGluZyB0cmFuc2FjdGlvbnMgZm9yIGFjY291bnQgJHtwb3J0Zm9saW8ucG9ydGZvbGlvTnVtfS4uLmApO1xuICAgICAgY29uc3Qge1xuICAgICAgICBtb3ZlbWVudHM6IHsgbW92ZW1lbnRzOiBuZXdNb3ZlbWVudHMsIHBhZ2luYXRpb24gfSxcbiAgICAgIH06IHsgbW92ZW1lbnRzOiB7IG1vdmVtZW50czogTW92ZW1lbnRbXTsgcGFnaW5hdGlvbjogUXVlcnlQYWdpbmF0aW9uIH0gfSA9IGF3YWl0IGZldGNoR3JhcGhxbChcbiAgICAgICAgR1JBUEhRTF9BUElfVVJMLFxuICAgICAgICBHRVRfTU9WRU1FTlRTLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydGZvbGlvSWQ6IHBvcnRmb2xpby5wb3J0Zm9saW9JZCxcbiAgICAgICAgICBhY2NvdW50SWQ6IGFjY291bnQuYWNjb3VudElkLFxuICAgICAgICAgIGxhbmd1YWdlOiAnSEVCUkVXJyxcbiAgICAgICAgICBwYWdpbmF0aW9uOiB7XG4gICAgICAgICAgICBjdXJzb3IsXG4gICAgICAgICAgICBsaW1pdDogNTAsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgeyBhdXRob3JpemF0aW9uOiBgQmVhcmVyICR7dGhpcy5hY2Nlc3NUb2tlbn1gIH0sXG4gICAgICApO1xuXG4gICAgICBtb3ZlbWVudHMudW5zaGlmdCguLi5uZXdNb3ZlbWVudHMpO1xuICAgICAgY3Vyc29yID0gcGFnaW5hdGlvbi5jdXJzb3I7XG4gICAgICBpZiAoIXBhZ2luYXRpb24uaGFzTW9yZSkge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBtb3ZlbWVudHMuc29ydCgoeCwgeSkgPT4gbmV3IERhdGUoeC5tb3ZlbWVudFRpbWVzdGFtcCkudmFsdWVPZigpIC0gbmV3IERhdGUoeS5tb3ZlbWVudFRpbWVzdGFtcCkudmFsdWVPZigpKTtcblxuICAgIGNvbnN0IG1hdGNoaW5nTW92ZW1lbnRzID0gbW92ZW1lbnRzLmZpbHRlcihtb3ZlbWVudCA9PiBuZXcgRGF0ZShtb3ZlbWVudC5tb3ZlbWVudFRpbWVzdGFtcCkgPj0gc3RhcnREYXRlKTtcbiAgICByZXR1cm4ge1xuICAgICAgYWNjb3VudE51bWJlcjogcG9ydGZvbGlvLnBvcnRmb2xpb051bSxcbiAgICAgIGJhbGFuY2U6ICFtb3ZlbWVudHMubGVuZ3RoID8gMCA6IHBhcnNlRmxvYXQobW92ZW1lbnRzW21vdmVtZW50cy5sZW5ndGggLSAxXS5ydW5uaW5nQmFsYW5jZSksXG4gICAgICB0eG5zOiBtYXRjaGluZ01vdmVtZW50cy5tYXAoKG1vdmVtZW50KTogU2NyYXBpbmdUcmFuc2FjdGlvbiA9PiB7XG4gICAgICAgIGNvbnN0IGhhc0luc3RhbGxtZW50cyA9IG1vdmVtZW50LnRyYW5zYWN0aW9uPy5lbnJpY2htZW50Py5yZWN1cnJlbmNlcz8uc29tZSh4ID0+IHguaXNSZWN1cnJlbnQpO1xuICAgICAgICBjb25zdCBtb2RpZmllciA9IG1vdmVtZW50LmNyZWRpdERlYml0ID09PSAnREVCSVQnID8gLTEgOiAxO1xuICAgICAgICBjb25zdCByZXN1bHQ6IFNjcmFwaW5nVHJhbnNhY3Rpb24gPSB7XG4gICAgICAgICAgaWRlbnRpZmllcjogbW92ZW1lbnQubW92ZW1lbnRJZCxcbiAgICAgICAgICBkYXRlOiBtb3ZlbWVudC52YWx1ZURhdGUsXG4gICAgICAgICAgY2hhcmdlZEFtb3VudDogK21vdmVtZW50Lm1vdmVtZW50QW1vdW50ICogbW9kaWZpZXIsXG4gICAgICAgICAgY2hhcmdlZEN1cnJlbmN5OiBtb3ZlbWVudC5tb3ZlbWVudEN1cnJlbmN5LFxuICAgICAgICAgIG9yaWdpbmFsQW1vdW50OiArbW92ZW1lbnQubW92ZW1lbnRBbW91bnQgKiBtb2RpZmllcixcbiAgICAgICAgICBvcmlnaW5hbEN1cnJlbmN5OiBtb3ZlbWVudC5tb3ZlbWVudEN1cnJlbmN5LFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiB0aGlzLnNhbml0aXplSGVicmV3KG1vdmVtZW50LmRlc2NyaXB0aW9uKSxcbiAgICAgICAgICBwcm9jZXNzZWREYXRlOiBtb3ZlbWVudC5tb3ZlbWVudFRpbWVzdGFtcCxcbiAgICAgICAgICBzdGF0dXM6IFRyYW5zYWN0aW9uU3RhdHVzZXMuQ29tcGxldGVkLFxuICAgICAgICAgIHR5cGU6IGhhc0luc3RhbGxtZW50cyA/IFRyYW5zYWN0aW9uVHlwZXMuSW5zdGFsbG1lbnRzIDogVHJhbnNhY3Rpb25UeXBlcy5Ob3JtYWwsXG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucz8uaW5jbHVkZVJhd1RyYW5zYWN0aW9uKSB7XG4gICAgICAgICAgcmVzdWx0LnJhd1RyYW5zYWN0aW9uID0gZ2V0UmF3VHJhbnNhY3Rpb24obW92ZW1lbnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH0pLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogb25lIHplcm8gaGVicmV3IHN0cmluZ3MgYXJlIHJldmVyc2VkIHdpdGggYSB1bmljb2RlIGNvbnRyb2wgY2hhcmFjdGVyIHRoYXQgZm9yY2VzIGRpc3BsYXkgaW4gTFRSIG9yZGVyXG4gICAqIFdlIG5lZWQgdG8gcmVtb3ZlIHRoZSB1bmljb2RlIGNvbnRyb2wgY2hhcmFjdGVyLCBhbmQgdGhlbiByZXZlcnNlIGhlYnJldyBzdWJzdHJpbmdzIGluc2lkZSB0aGUgc3RyaW5nXG4gICAqL1xuICBwcml2YXRlIHNhbml0aXplSGVicmV3KHRleHQ6IHN0cmluZykge1xuICAgIGlmICghdGV4dC5pbmNsdWRlcygnXFx1MjAyZCcpKSB7XG4gICAgICByZXR1cm4gdGV4dC50cmltKCk7XG4gICAgfVxuXG4gICAgY29uc3QgcGxhaW5TdHJpbmcgPSB0ZXh0LnJlcGxhY2UoL1xcdTIwMmQvZ2ksICcnKS50cmltKCk7XG4gICAgY29uc3QgaGVicmV3U3ViU3RyaW5nc1JhbmdlcyA9IFsuLi5wbGFpblN0cmluZy5tYXRjaEFsbChIRUJSRVdfV09SRFNfUkVHRVgpXTtcbiAgICBjb25zdCByYW5nZXNUb1JldmVyc2UgPSBoZWJyZXdTdWJTdHJpbmdzUmFuZ2VzLm1hcChzdHIgPT4gKHsgc3RhcnQ6IHN0ci5pbmRleCEsIGVuZDogc3RyLmluZGV4ISArIHN0clswXS5sZW5ndGggfSkpO1xuICAgIGNvbnN0IG91dCA9IFtdO1xuICAgIGxldCBpbmRleCA9IDA7XG5cbiAgICBmb3IgKGNvbnN0IHsgc3RhcnQsIGVuZCB9IG9mIHJhbmdlc1RvUmV2ZXJzZSkge1xuICAgICAgb3V0LnB1c2goLi4ucGxhaW5TdHJpbmcuc3Vic3RyaW5nKGluZGV4LCBzdGFydCkpO1xuICAgICAgaW5kZXggKz0gc3RhcnQgLSBpbmRleDtcbiAgICAgIGNvbnN0IHJldmVyc2VkID0gWy4uLnBsYWluU3RyaW5nLnN1YnN0cmluZyhzdGFydCwgZW5kKV0ucmV2ZXJzZSgpO1xuICAgICAgb3V0LnB1c2goLi4ucmV2ZXJzZWQpO1xuICAgICAgaW5kZXggKz0gZW5kIC0gc3RhcnQ7XG4gICAgfVxuXG4gICAgb3V0LnB1c2goLi4ucGxhaW5TdHJpbmcuc3Vic3RyaW5nKGluZGV4LCBwbGFpblN0cmluZy5sZW5ndGgpKTtcblxuICAgIHJldHVybiBvdXQuam9pbignJyk7XG4gIH1cblxuICBhc3luYyBmZXRjaERhdGEoKTogUHJvbWlzZTxTY3JhcGVyU2NyYXBpbmdSZXN1bHQ+IHtcbiAgICBpZiAoIXRoaXMuYWNjZXNzVG9rZW4pIHtcbiAgICAgIHJldHVybiBjcmVhdGVHZW5lcmljRXJyb3IoJ2xvZ2luKCkgd2FzIG5vdCBjYWxsZWQnKTtcbiAgICB9XG5cbiAgICBjb25zdCBkZWZhdWx0U3RhcnRNb21lbnQgPSBtb21lbnQoKS5zdWJ0cmFjdCgxLCAneWVhcnMnKS5hZGQoMSwgJ2RheScpO1xuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IHRoaXMub3B0aW9ucy5zdGFydERhdGUgfHwgZGVmYXVsdFN0YXJ0TW9tZW50LnRvRGF0ZSgpO1xuICAgIGNvbnN0IHN0YXJ0TW9tZW50ID0gbW9tZW50Lm1heChkZWZhdWx0U3RhcnRNb21lbnQsIG1vbWVudChzdGFydERhdGUpKTtcblxuICAgIGRlYnVnKCdGZXRjaGluZyBhY2NvdW50IGxpc3QnKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBmZXRjaEdyYXBocWw8eyBjdXN0b21lcjogQ3VzdG9tZXJbXSB9PihcbiAgICAgIEdSQVBIUUxfQVBJX1VSTCxcbiAgICAgIEdFVF9DVVNUT01FUixcbiAgICAgIHt9LFxuICAgICAgeyBhdXRob3JpemF0aW9uOiBgQmVhcmVyICR7dGhpcy5hY2Nlc3NUb2tlbn1gIH0sXG4gICAgKTtcbiAgICBjb25zdCBwb3J0Zm9saW9zID0gcmVzdWx0LmN1c3RvbWVyLmZsYXRNYXAoY3VzdG9tZXIgPT4gY3VzdG9tZXIucG9ydGZvbGlvcyB8fCBbXSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgIGFjY291bnRzOiBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgcG9ydGZvbGlvcy5tYXAocG9ydGZvbGlvID0+IHRoaXMuZmV0Y2hQb3J0Zm9saW9Nb3ZlbWVudHMocG9ydGZvbGlvLCBzdGFydE1vbWVudC50b0RhdGUoKSkpLFxuICAgICAgKSxcbiAgICB9O1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLE1BQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLE1BQUEsR0FBQUYsT0FBQTtBQUNB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