metaapi.cloud-sdk
Version:
SDK for MetaApi, a professional cloud forex API which includes MetaTrader REST API and MetaTrader websocket API. Supports both MetaTrader 5 (MT5) and MetaTrader 4 (MT4). CopyFactory copy trading API included. (https://metaapi.cloud)
189 lines (188 loc) • 21.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return BrowserHistoryDatabase;
}
});
const _historyDatabase = /*#__PURE__*/ _interop_require_default(require("./historyDatabase"));
const _logger = /*#__PURE__*/ _interop_require_default(require("../../logger"));
const _idb = require("idb");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let BrowserHistoryDatabase = class BrowserHistoryDatabase extends _historyDatabase.default {
/**
* Returns history database instance
* @returns {HistoryDatabase} history database instance
*/ static getInstance() {
if (!BrowserHistoryDatabase.instance) {
BrowserHistoryDatabase.instance = new BrowserHistoryDatabase();
}
return BrowserHistoryDatabase.instance;
}
/**
* Loads history from database
* @param {string} accountId account id
* @param {string} application application name
* @return {Promise<{deals: Array<MetatraderDeal>, historyOrders: Array<MetatraderOrder>}>} full account history
*/ async loadHistory(accountId, application) {
let db;
try {
db = await this._getDatabase();
let deals = await this._readDb(db, "deals", accountId + "-" + application);
deals.forEach((deal)=>deal.time = new Date(deal.time));
let historyOrders = await this._readDb(db, "historyOrders", accountId + "-" + application);
historyOrders.forEach((historyOrder)=>{
historyOrder.time = new Date(historyOrder.time);
historyOrder.doneTime = new Date(historyOrder.doneTime);
});
return {
deals,
historyOrders
};
} catch (err) {
this._logger.warn(`${accountId}: failed to read history database, will reinitialize it now`, err);
await this.clear(accountId, application);
return {
deals: [],
historyOrders: []
};
} finally{
try {
await db.close();
} catch (err) {
this._logger.error(`${accountId}: error closing db`, err);
}
}
}
/**
* Removes history from database
* @param {string} accountId account id
* @param {string} application application name
* @return {Promise} promise resolving when the history is removed
*/ async clear(accountId, application) {
const prefix = accountId + "-" + application;
const range = IDBKeyRange.bound(prefix, prefix + ":");
let db;
try {
db = await this._getDatabase();
await db.delete("deals", range);
await db.delete("dealsIndex", range);
await db.delete("historyOrders", range);
await db.delete("historyOrdersIndex", range);
} catch (e) {
this._logger.warn(`${accountId}: failed to clear history storage`, e);
} finally{
try {
await db.close();
} catch (err) {
this._logger.error(`${accountId}: error closing db`, err);
}
}
}
/**
* Flushes the new history to db
* @param {string} accountId account id
* @param {string} application application name
* @param {Array<MetatraderOrder>} newHistoryOrders history orders to save to db
* @param {Array<MetatraderDeal>} newDeals deals to save to db
* @return {Promise} promise resolving when the history is flushed
*/ async flush(accountId, application, newHistoryOrders, newDeals) {
let db;
try {
db = await this._getDatabase();
await this._appendDb(db, "deals", accountId + "-" + application, newDeals);
await this._appendDb(db, "historyOrders", accountId + "-" + application, newHistoryOrders);
} catch (e) {
this._logger.warn(`${accountId}: failed to flush history storage`, e);
} finally{
try {
await db.close();
} catch (err) {
this._logger.error(`${accountId}: error closing db`, err);
}
}
}
async _getDatabase() {
const keyPath = "id";
const db = await (0, _idb.openDB)("metaapi", 2, {
upgrade (database, oldVersion, newVersion, transaction) {
if (oldVersion !== 2) {
if (database.objectStoreNames.contains("deals")) {
database.deleteObjectStore("deals");
}
if (database.objectStoreNames.contains("historyOrders")) {
database.deleteObjectStore("historyOrders");
}
}
if (!database.objectStoreNames.contains("dealsIndex")) {
database.createObjectStore("dealsIndex", {
keyPath
});
}
if (!database.objectStoreNames.contains("deals")) {
database.createObjectStore("deals", {
keyPath
});
}
if (!database.objectStoreNames.contains("historyOrdersIndex")) {
database.createObjectStore("historyOrdersIndex", {
keyPath
});
}
if (!database.objectStoreNames.contains("historyOrders")) {
database.createObjectStore("historyOrders", {
keyPath
});
}
}
});
return db;
}
async _readDb(db, store, prefix) {
const keys = await db.getAllKeys(store, IDBKeyRange.bound(prefix, prefix + "-" + ":"));
let result = [];
for (let key of keys){
let value = await db.get(store, key);
if (value) {
for (let line of value.data.split("\n")){
if (line.length) {
let record = JSON.parse(line);
result.push(record);
}
}
}
}
return result;
}
async _appendDb(db, store, prefix, records) {
if (records && records.length) {
let lastKey = await db.get(store + "Index", prefix + "-" + "sn");
let index = (lastKey || {
index: 0
}).index + 1;
let data = records.map((r)=>JSON.stringify(r) + "\n").join("");
await db.put(store, {
data,
id: prefix + "-" + index
});
await db.put(store + "Index", {
id: prefix + "-" + "sn",
index
});
}
}
/**
* Constructs the class instance
*/ constructor(){
super();
this._logger = _logger.default.getLogger("BrowserHistoryDatabase");
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBIaXN0b3J5RGF0YWJhc2UgZnJvbSAnLi9oaXN0b3J5RGF0YWJhc2UnO1xuaW1wb3J0IExvZ2dlciBmcm9tICcuLi8uLi9sb2dnZXInO1xuaW1wb3J0IHtvcGVuREJ9IGZyb20gJ2lkYic7XG5cbi8qKlxuICogUHJvdmlkZXMgYWNjZXNzIHRvIGhpc3RvcnkgZGF0YWJhc2Ugc3RvcmVkIGluIGEgYnJvd3NlciBJbmRleGVkREJcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQnJvd3Nlckhpc3RvcnlEYXRhYmFzZSBleHRlbmRzIEhpc3RvcnlEYXRhYmFzZSB7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgdGhlIGNsYXNzIGluc3RhbmNlXG4gICAqL1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuX2xvZ2dlciA9IExvZ2dlci5nZXRMb2dnZXIoJ0Jyb3dzZXJIaXN0b3J5RGF0YWJhc2UnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGhpc3RvcnkgZGF0YWJhc2UgaW5zdGFuY2VcbiAgICogQHJldHVybnMge0hpc3RvcnlEYXRhYmFzZX0gaGlzdG9yeSBkYXRhYmFzZSBpbnN0YW5jZVxuICAgKi9cbiAgc3RhdGljIGdldEluc3RhbmNlKCkge1xuICAgIGlmICghQnJvd3Nlckhpc3RvcnlEYXRhYmFzZS5pbnN0YW5jZSkge1xuICAgICAgQnJvd3Nlckhpc3RvcnlEYXRhYmFzZS5pbnN0YW5jZSA9IG5ldyBCcm93c2VySGlzdG9yeURhdGFiYXNlKCk7XG4gICAgfVxuICAgIHJldHVybiBCcm93c2VySGlzdG9yeURhdGFiYXNlLmluc3RhbmNlO1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWRzIGhpc3RvcnkgZnJvbSBkYXRhYmFzZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudElkIGFjY291bnQgaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFwcGxpY2F0aW9uIGFwcGxpY2F0aW9uIG5hbWVcbiAgICogQHJldHVybiB7UHJvbWlzZTx7ZGVhbHM6IEFycmF5PE1ldGF0cmFkZXJEZWFsPiwgaGlzdG9yeU9yZGVyczogQXJyYXk8TWV0YXRyYWRlck9yZGVyPn0+fSBmdWxsIGFjY291bnQgaGlzdG9yeVxuICAgKi9cbiAgYXN5bmMgbG9hZEhpc3RvcnkoYWNjb3VudElkLCBhcHBsaWNhdGlvbikge1xuICAgIGxldCBkYjtcbiAgICB0cnkge1xuICAgICAgZGIgPSBhd2FpdCB0aGlzLl9nZXREYXRhYmFzZSgpO1xuICAgICAgbGV0IGRlYWxzID0gYXdhaXQgdGhpcy5fcmVhZERiKGRiLCAnZGVhbHMnLCBhY2NvdW50SWQgKyAnLScgKyBhcHBsaWNhdGlvbik7XG4gICAgICBkZWFscy5mb3JFYWNoKGRlYWwgPT4gZGVhbC50aW1lID0gbmV3IERhdGUoZGVhbC50aW1lKSk7XG4gICAgICBsZXQgaGlzdG9yeU9yZGVycyA9IGF3YWl0IHRoaXMuX3JlYWREYihkYiwgJ2hpc3RvcnlPcmRlcnMnLCBhY2NvdW50SWQgKyAnLScgKyBhcHBsaWNhdGlvbik7XG4gICAgICBoaXN0b3J5T3JkZXJzLmZvckVhY2goaGlzdG9yeU9yZGVyID0+IHtcbiAgICAgICAgaGlzdG9yeU9yZGVyLnRpbWUgPSBuZXcgRGF0ZShoaXN0b3J5T3JkZXIudGltZSk7XG4gICAgICAgIGhpc3RvcnlPcmRlci5kb25lVGltZSA9IG5ldyBEYXRlKGhpc3RvcnlPcmRlci5kb25lVGltZSk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiB7ZGVhbHMsIGhpc3RvcnlPcmRlcnN9O1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5fbG9nZ2VyLndhcm4oYCR7YWNjb3VudElkfTogZmFpbGVkIHRvIHJlYWQgaGlzdG9yeSBkYXRhYmFzZSwgd2lsbCByZWluaXRpYWxpemUgaXQgbm93YCwgZXJyKTtcbiAgICAgIGF3YWl0IHRoaXMuY2xlYXIoYWNjb3VudElkLCBhcHBsaWNhdGlvbik7XG4gICAgICByZXR1cm4ge2RlYWxzOiBbXSwgaGlzdG9yeU9yZGVyczogW119O1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBkYi5jbG9zZSgpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcihgJHthY2NvdW50SWR9OiBlcnJvciBjbG9zaW5nIGRiYCwgZXJyKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBoaXN0b3J5IGZyb20gZGF0YWJhc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcHBsaWNhdGlvbiBhcHBsaWNhdGlvbiBuYW1lXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2UgcmVzb2x2aW5nIHdoZW4gdGhlIGhpc3RvcnkgaXMgcmVtb3ZlZFxuICAgKi9cbiAgYXN5bmMgY2xlYXIoYWNjb3VudElkLCBhcHBsaWNhdGlvbikge1xuICAgIGNvbnN0IHByZWZpeCA9IGFjY291bnRJZCArICctJyArIGFwcGxpY2F0aW9uO1xuICAgIGNvbnN0IHJhbmdlID0gSURCS2V5UmFuZ2UuYm91bmQocHJlZml4LCBwcmVmaXggKyAnOicpO1xuICAgIGxldCBkYjtcbiAgICB0cnkge1xuICAgICAgZGIgPSBhd2FpdCB0aGlzLl9nZXREYXRhYmFzZSgpO1xuICAgICAgYXdhaXQgZGIuZGVsZXRlKCdkZWFscycsIHJhbmdlKTtcbiAgICAgIGF3YWl0IGRiLmRlbGV0ZSgnZGVhbHNJbmRleCcsIHJhbmdlKTtcbiAgICAgIGF3YWl0IGRiLmRlbGV0ZSgnaGlzdG9yeU9yZGVycycsIHJhbmdlKTtcbiAgICAgIGF3YWl0IGRiLmRlbGV0ZSgnaGlzdG9yeU9yZGVyc0luZGV4JywgcmFuZ2UpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRoaXMuX2xvZ2dlci53YXJuKGAke2FjY291bnRJZH06IGZhaWxlZCB0byBjbGVhciBoaXN0b3J5IHN0b3JhZ2VgLCBlKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZGIuY2xvc2UoKTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICB0aGlzLl9sb2dnZXIuZXJyb3IoYCR7YWNjb3VudElkfTogZXJyb3IgY2xvc2luZyBkYmAsIGVycik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEZsdXNoZXMgdGhlIG5ldyBoaXN0b3J5IHRvIGRiXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXBwbGljYXRpb24gYXBwbGljYXRpb24gbmFtZVxuICAgKiBAcGFyYW0ge0FycmF5PE1ldGF0cmFkZXJPcmRlcj59IG5ld0hpc3RvcnlPcmRlcnMgaGlzdG9yeSBvcmRlcnMgdG8gc2F2ZSB0byBkYlxuICAgKiBAcGFyYW0ge0FycmF5PE1ldGF0cmFkZXJEZWFsPn0gbmV3RGVhbHMgZGVhbHMgdG8gc2F2ZSB0byBkYlxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIHRoZSBoaXN0b3J5IGlzIGZsdXNoZWRcbiAgICovXG4gIGFzeW5jIGZsdXNoKGFjY291bnRJZCwgYXBwbGljYXRpb24sIG5ld0hpc3RvcnlPcmRlcnMsIG5ld0RlYWxzKSB7XG4gICAgbGV0IGRiO1xuICAgIHRyeSB7XG4gICAgICBkYiA9IGF3YWl0IHRoaXMuX2dldERhdGFiYXNlKCk7XG4gICAgICBhd2FpdCB0aGlzLl9hcHBlbmREYihkYiwgJ2RlYWxzJywgYWNjb3VudElkICsgJy0nICsgYXBwbGljYXRpb24sIG5ld0RlYWxzKTtcbiAgICAgIGF3YWl0IHRoaXMuX2FwcGVuZERiKGRiLCAnaGlzdG9yeU9yZGVycycsIGFjY291bnRJZCArICctJyArIGFwcGxpY2F0aW9uLCBuZXdIaXN0b3J5T3JkZXJzKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aGlzLl9sb2dnZXIud2FybihgJHthY2NvdW50SWR9OiBmYWlsZWQgdG8gZmx1c2ggaGlzdG9yeSBzdG9yYWdlYCwgZSk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGRiLmNsb3NlKCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgdGhpcy5fbG9nZ2VyLmVycm9yKGAke2FjY291bnRJZH06IGVycm9yIGNsb3NpbmcgZGJgLCBlcnIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIF9nZXREYXRhYmFzZSgpIHtcbiAgICBjb25zdCBrZXlQYXRoID0gJ2lkJztcbiAgICBjb25zdCBkYiA9IGF3YWl0IG9wZW5EQignbWV0YWFwaScsIDIsIHtcbiAgICAgIHVwZ3JhZGUoZGF0YWJhc2UsIG9sZFZlcnNpb24sIG5ld1ZlcnNpb24sIHRyYW5zYWN0aW9uKSB7XG4gICAgICAgIGlmIChvbGRWZXJzaW9uICE9PSAyKSB7XG4gICAgICAgICAgaWYgKGRhdGFiYXNlLm9iamVjdFN0b3JlTmFtZXMuY29udGFpbnMoJ2RlYWxzJykpIHtcbiAgICAgICAgICAgIGRhdGFiYXNlLmRlbGV0ZU9iamVjdFN0b3JlKCdkZWFscycpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZGF0YWJhc2Uub2JqZWN0U3RvcmVOYW1lcy5jb250YWlucygnaGlzdG9yeU9yZGVycycpKSB7XG4gICAgICAgICAgICBkYXRhYmFzZS5kZWxldGVPYmplY3RTdG9yZSgnaGlzdG9yeU9yZGVycycpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRhdGFiYXNlLm9iamVjdFN0b3JlTmFtZXMuY29udGFpbnMoJ2RlYWxzSW5kZXgnKSkge1xuICAgICAgICAgIGRhdGFiYXNlLmNyZWF0ZU9iamVjdFN0b3JlKCdkZWFsc0luZGV4Jywge2tleVBhdGh9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRhdGFiYXNlLm9iamVjdFN0b3JlTmFtZXMuY29udGFpbnMoJ2RlYWxzJykpIHtcbiAgICAgICAgICBkYXRhYmFzZS5jcmVhdGVPYmplY3RTdG9yZSgnZGVhbHMnLCB7a2V5UGF0aH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmICghZGF0YWJhc2Uub2JqZWN0U3RvcmVOYW1lcy5jb250YWlucygnaGlzdG9yeU9yZGVyc0luZGV4JykpIHtcbiAgICAgICAgICBkYXRhYmFzZS5jcmVhdGVPYmplY3RTdG9yZSgnaGlzdG9yeU9yZGVyc0luZGV4Jywge2tleVBhdGh9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRhdGFiYXNlLm9iamVjdFN0b3JlTmFtZXMuY29udGFpbnMoJ2hpc3RvcnlPcmRlcnMnKSkge1xuICAgICAgICAgIGRhdGFiYXNlLmNyZWF0ZU9iamVjdFN0b3JlKCdoaXN0b3J5T3JkZXJzJywge2tleVBhdGh9KTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9KTtcbiAgICByZXR1cm4gZGI7XG4gIH1cblxuICBhc3luYyBfcmVhZERiKGRiLCBzdG9yZSwgcHJlZml4KSB7XG4gICAgY29uc3Qga2V5cyA9IGF3YWl0IGRiLmdldEFsbEtleXMoc3RvcmUsIElEQktleVJhbmdlLmJvdW5kKHByZWZpeCwgcHJlZml4ICsgJy0nICsgJzonKSk7XG4gICAgbGV0IHJlc3VsdCA9IFtdO1xuICAgIGZvciAobGV0IGtleSBvZiBrZXlzKSB7XG4gICAgICBsZXQgdmFsdWUgPSBhd2FpdCBkYi5nZXQoc3RvcmUsIGtleSk7XG4gICAgICBpZiAodmFsdWUpIHtcbiAgICAgICAgZm9yIChsZXQgbGluZSBvZiB2YWx1ZS5kYXRhLnNwbGl0KCdcXG4nKSkge1xuICAgICAgICAgIGlmIChsaW5lLmxlbmd0aCkge1xuICAgICAgICAgICAgbGV0IHJlY29yZCA9IEpTT04ucGFyc2UobGluZSk7XG4gICAgICAgICAgICByZXN1bHQucHVzaChyZWNvcmQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgYXN5bmMgX2FwcGVuZERiKGRiLCBzdG9yZSwgcHJlZml4LCByZWNvcmRzKSB7XG4gICAgaWYgKHJlY29yZHMgJiYgcmVjb3Jkcy5sZW5ndGgpIHtcbiAgICAgIGxldCBsYXN0S2V5ID0gYXdhaXQgZGIuZ2V0KHN0b3JlICsgJ0luZGV4JywgcHJlZml4ICsgJy0nICsgJ3NuJyk7XG4gICAgICBsZXQgaW5kZXggPSAobGFzdEtleSB8fCB7aW5kZXg6IDB9KS5pbmRleCArIDE7XG4gICAgICBsZXQgZGF0YSA9IHJlY29yZHMubWFwKHIgPT4gSlNPTi5zdHJpbmdpZnkocikgKyAnXFxuJykuam9pbignJyk7XG4gICAgICBhd2FpdCBkYi5wdXQoc3RvcmUsIHtkYXRhLCBpZDogcHJlZml4ICsgJy0nICsgaW5kZXh9KTtcbiAgICAgIGF3YWl0IGRiLnB1dChzdG9yZSArICdJbmRleCcsIHtpZDogcHJlZml4ICsgJy0nICsgJ3NuJywgaW5kZXh9KTtcbiAgICB9XG4gIH1cblxufVxuIl0sIm5hbWVzIjpbIkJyb3dzZXJIaXN0b3J5RGF0YWJhc2UiLCJIaXN0b3J5RGF0YWJhc2UiLCJnZXRJbnN0YW5jZSIsImluc3RhbmNlIiwibG9hZEhpc3RvcnkiLCJhY2NvdW50SWQiLCJhcHBsaWNhdGlvbiIsImRiIiwiX2dldERhdGFiYXNlIiwiZGVhbHMiLCJfcmVhZERiIiwiZm9yRWFjaCIsImRlYWwiLCJ0aW1lIiwiRGF0ZSIsImhpc3RvcnlPcmRlcnMiLCJoaXN0b3J5T3JkZXIiLCJkb25lVGltZSIsImVyciIsIl9sb2dnZXIiLCJ3YXJuIiwiY2xlYXIiLCJjbG9zZSIsImVycm9yIiwicHJlZml4IiwicmFuZ2UiLCJJREJLZXlSYW5nZSIsImJvdW5kIiwiZGVsZXRlIiwiZSIsImZsdXNoIiwibmV3SGlzdG9yeU9yZGVycyIsIm5ld0RlYWxzIiwiX2FwcGVuZERiIiwia2V5UGF0aCIsIm9wZW5EQiIsInVwZ3JhZGUiLCJkYXRhYmFzZSIsIm9sZFZlcnNpb24iLCJuZXdWZXJzaW9uIiwidHJhbnNhY3Rpb24iLCJvYmplY3RTdG9yZU5hbWVzIiwiY29udGFpbnMiLCJkZWxldGVPYmplY3RTdG9yZSIsImNyZWF0ZU9iamVjdFN0b3JlIiwic3RvcmUiLCJrZXlzIiwiZ2V0QWxsS2V5cyIsInJlc3VsdCIsImtleSIsInZhbHVlIiwiZ2V0IiwibGluZSIsImRhdGEiLCJzcGxpdCIsImxlbmd0aCIsInJlY29yZCIsIkpTT04iLCJwYXJzZSIsInB1c2giLCJyZWNvcmRzIiwibGFzdEtleSIsImluZGV4IiwibWFwIiwiciIsInN0cmluZ2lmeSIsImpvaW4iLCJwdXQiLCJpZCIsImNvbnN0cnVjdG9yIiwiTG9nZ2VyIiwiZ2V0TG9nZ2VyIl0sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztlQVNxQkE7Ozt3RUFQTzsrREFDVDtxQkFDRTs7Ozs7O0FBS04sSUFBQSxBQUFNQSx5QkFBTixNQUFNQSwrQkFBK0JDLHdCQUFlO0lBVWpFOzs7R0FHQyxHQUNELE9BQU9DLGNBQWM7UUFDbkIsSUFBSSxDQUFDRix1QkFBdUJHLFFBQVEsRUFBRTtZQUNwQ0gsdUJBQXVCRyxRQUFRLEdBQUcsSUFBSUg7UUFDeEM7UUFDQSxPQUFPQSx1QkFBdUJHLFFBQVE7SUFDeEM7SUFFQTs7Ozs7R0FLQyxHQUNELE1BQU1DLFlBQVlDLFNBQVMsRUFBRUMsV0FBVyxFQUFFO1FBQ3hDLElBQUlDO1FBQ0osSUFBSTtZQUNGQSxLQUFLLE1BQU0sSUFBSSxDQUFDQyxZQUFZO1lBQzVCLElBQUlDLFFBQVEsTUFBTSxJQUFJLENBQUNDLE9BQU8sQ0FBQ0gsSUFBSSxTQUFTRixZQUFZLE1BQU1DO1lBQzlERyxNQUFNRSxPQUFPLENBQUNDLENBQUFBLE9BQVFBLEtBQUtDLElBQUksR0FBRyxJQUFJQyxLQUFLRixLQUFLQyxJQUFJO1lBQ3BELElBQUlFLGdCQUFnQixNQUFNLElBQUksQ0FBQ0wsT0FBTyxDQUFDSCxJQUFJLGlCQUFpQkYsWUFBWSxNQUFNQztZQUM5RVMsY0FBY0osT0FBTyxDQUFDSyxDQUFBQTtnQkFDcEJB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