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)
222 lines (221 loc) • 22.8 kB
JavaScript
;
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _async_to_generator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
import HistoryDatabase from './historyDatabase';
import Logger from '../../logger';
import { openDB } from 'idb';
let BrowserHistoryDatabase = class BrowserHistoryDatabase extends HistoryDatabase {
/**
* 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
*/ loadHistory(accountId, application) {
var _this = this;
return _async_to_generator(function*() {
let db;
try {
db = yield _this._getDatabase();
let deals = yield _this._readDb(db, 'deals', accountId + '-' + application);
deals.forEach((deal)=>deal.time = new Date(deal.time));
let historyOrders = yield _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);
yield _this.clear(accountId, application);
return {
deals: [],
historyOrders: []
};
} finally{
try {
yield 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
*/ clear(accountId, application) {
var _this = this;
return _async_to_generator(function*() {
const prefix = accountId + '-' + application;
const range = IDBKeyRange.bound(prefix, prefix + ':');
let db;
try {
db = yield _this._getDatabase();
yield db.delete('deals', range);
yield db.delete('dealsIndex', range);
yield db.delete('historyOrders', range);
yield db.delete('historyOrdersIndex', range);
} catch (e) {
_this._logger.warn(`${accountId}: failed to clear history storage`, e);
} finally{
try {
yield 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
*/ flush(accountId, application, newHistoryOrders, newDeals) {
var _this = this;
return _async_to_generator(function*() {
let db;
try {
db = yield _this._getDatabase();
yield _this._appendDb(db, 'deals', accountId + '-' + application, newDeals);
yield _this._appendDb(db, 'historyOrders', accountId + '-' + application, newHistoryOrders);
} catch (e) {
_this._logger.warn(`${accountId}: failed to flush history storage`, e);
} finally{
try {
yield db.close();
} catch (err) {
_this._logger.error(`${accountId}: error closing db`, err);
}
}
})();
}
_getDatabase() {
return _async_to_generator(function*() {
const keyPath = 'id';
const db = yield 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;
})();
}
_readDb(db, store, prefix) {
return _async_to_generator(function*() {
const keys = yield db.getAllKeys(store, IDBKeyRange.bound(prefix, prefix + '-' + ':'));
let result = [];
for (let key of keys){
let value = yield 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;
})();
}
_appendDb(db, store, prefix, records) {
return _async_to_generator(function*() {
if (records && records.length) {
let lastKey = yield db.get(store + 'Index', prefix + '-' + 'sn');
let index = (lastKey || {
index: 0
}).index + 1;
let data = records.map((r)=>JSON.stringify(r) + '\n').join('');
yield db.put(store, {
data,
id: prefix + '-' + index
});
yield db.put(store + 'Index', {
id: prefix + '-' + 'sn',
index
});
}
})();
}
/**
* Constructs the class instance
*/ constructor(){
super();
this._logger = Logger.getLogger('BrowserHistoryDatabase');
}
};
/**
* Provides access to history database stored in a browser IndexedDB
*/ export { BrowserHistoryDatabase as default };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBIaXN0b3J5RGF0YWJhc2UgZnJvbSAnLi9oaXN0b3J5RGF0YWJhc2UnO1xuaW1wb3J0IExvZ2dlciBmcm9tICcuLi8uLi9sb2dnZXInO1xuaW1wb3J0IHtvcGVuREJ9IGZyb20gJ2lkYic7XG5cbi8qKlxuICogUHJvdmlkZXMgYWNjZXNzIHRvIGhpc3RvcnkgZGF0YWJhc2Ugc3RvcmVkIGluIGEgYnJvd3NlciBJbmRleGVkREJcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQnJvd3Nlckhpc3RvcnlEYXRhYmFzZSBleHRlbmRzIEhpc3RvcnlEYXRhYmFzZSB7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgdGhlIGNsYXNzIGluc3RhbmNlXG4gICAqL1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuX2xvZ2dlciA9IExvZ2dlci5nZXRMb2dnZXIoJ0Jyb3dzZXJIaXN0b3J5RGF0YWJhc2UnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGhpc3RvcnkgZGF0YWJhc2UgaW5zdGFuY2VcbiAgICogQHJldHVybnMge0hpc3RvcnlEYXRhYmFzZX0gaGlzdG9yeSBkYXRhYmFzZSBpbnN0YW5jZVxuICAgKi9cbiAgc3RhdGljIGdldEluc3RhbmNlKCkge1xuICAgIGlmICghQnJvd3Nlckhpc3RvcnlEYXRhYmFzZS5pbnN0YW5jZSkge1xuICAgICAgQnJvd3Nlckhpc3RvcnlEYXRhYmFzZS5pbnN0YW5jZSA9IG5ldyBCcm93c2VySGlzdG9yeURhdGFiYXNlKCk7XG4gICAgfVxuICAgIHJldHVybiBCcm93c2VySGlzdG9yeURhdGFiYXNlLmluc3RhbmNlO1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWRzIGhpc3RvcnkgZnJvbSBkYXRhYmFzZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudElkIGFjY291bnQgaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFwcGxpY2F0aW9uIGFwcGxpY2F0aW9uIG5hbWVcbiAgICogQHJldHVybiB7UHJvbWlzZTx7ZGVhbHM6IEFycmF5PE1ldGF0cmFkZXJEZWFsPiwgaGlzdG9yeU9yZGVyczogQXJyYXk8TWV0YXRyYWRlck9yZGVyPn0+fSBmdWxsIGFjY291bnQgaGlzdG9yeVxuICAgKi9cbiAgYXN5bmMgbG9hZEhpc3RvcnkoYWNjb3VudElkLCBhcHBsaWNhdGlvbikge1xuICAgIGxldCBkYjtcbiAgICB0cnkge1xuICAgICAgZGIgPSBhd2FpdCB0aGlzLl9nZXREYXRhYmFzZSgpO1xuICAgICAgbGV0IGRlYWxzID0gYXdhaXQgdGhpcy5fcmVhZERiKGRiLCAnZGVhbHMnLCBhY2NvdW50SWQgKyAnLScgKyBhcHBsaWNhdGlvbik7XG4gICAgICBkZWFscy5mb3JFYWNoKGRlYWwgPT4gZGVhbC50aW1lID0gbmV3IERhdGUoZGVhbC50aW1lKSk7XG4gICAgICBsZXQgaGlzdG9yeU9yZGVycyA9IGF3YWl0IHRoaXMuX3JlYWREYihkYiwgJ2hpc3RvcnlPcmRlcnMnLCBhY2NvdW50SWQgKyAnLScgKyBhcHBsaWNhdGlvbik7XG4gICAgICBoaXN0b3J5T3JkZXJzLmZvckVhY2goaGlzdG9yeU9yZGVyID0+IHtcbiAgICAgICAgaGlzdG9yeU9yZGVyLnRpbWUgPSBuZXcgRGF0ZShoaXN0b3J5T3JkZXIudGltZSk7XG4gICAgICAgIGhpc3RvcnlPcmRlci5kb25lVGltZSA9IG5ldyBEYXRlKGhpc3RvcnlPcmRlci5kb25lVGltZSk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiB7ZGVhbHMsIGhpc3RvcnlPcmRlcnN9O1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5fbG9nZ2VyLndhcm4oYCR7YWNjb3VudElkfTogZmFpbGVkIHRvIHJlYWQgaGlzdG9yeSBkYXRhYmFzZSwgd2lsbCByZWluaXRpYWxpemUgaXQgbm93YCwgZXJyKTtcbiAgICAgIGF3YWl0IHRoaXMuY2xlYXIoYWNjb3VudElkLCBhcHBsaWNhdGlvbik7XG4gICAgICByZXR1cm4ge2RlYWxzOiBbXSwgaGlzdG9yeU9yZGVyczogW119O1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBkYi5jbG9zZSgpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcihgJHthY2NvdW50SWR9OiBlcnJvciBjbG9zaW5nIGRiYCwgZXJyKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBoaXN0b3J5IGZyb20gZGF0YWJhc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcHBsaWNhdGlvbiBhcHBsaWNhdGlvbiBuYW1lXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2UgcmVzb2x2aW5nIHdoZW4gdGhlIGhpc3RvcnkgaXMgcmVtb3ZlZFxuICAgKi9cbiAgYXN5bmMgY2xlYXIoYWNjb3VudElkLCBhcHBsaWNhdGlvbikge1xuICAgIGNvbnN0IHByZWZpeCA9IGFjY291bnRJZCArICctJyArIGFwcGxpY2F0aW9uO1xuICAgIGNvbnN0IHJhbmdlID0gSURCS2V5UmFuZ2UuYm91bmQocHJlZml4LCBwcmVmaXggKyAnOicpO1xuICAgIGxldCBkYjtcbiAgICB0cnkge1xuICAgICAgZGIgPSBhd2FpdCB0aGlzLl9nZXREYXRhYmFzZSgpO1xuICAgICAgYXdhaXQgZGIuZGVsZXRlKCdkZWFscycsIHJhbmdlKTtcbiAgICAgIGF3YWl0IGRiLmRlbGV0ZSgnZGVhbHNJbmRleCcsIHJhbmdlKTtcbiAgICAgIGF3YWl0IGRiLmRlbGV0ZSgnaGlzdG9yeU9yZGVycycsIHJhbmdlKTtcbiAgICAgIGF3YWl0IGRiLmRlbGV0ZSgnaGlzdG9yeU9yZGVyc0luZGV4JywgcmFuZ2UpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRoaXMuX2xvZ2dlci53YXJuKGAke2FjY291bnRJZH06IGZhaWxlZCB0byBjbGVhciBoaXN0b3J5IHN0b3JhZ2VgLCBlKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZGIuY2xvc2UoKTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICB0aGlzLl9sb2dnZXIuZXJyb3IoYCR7YWNjb3VudElkfTogZXJyb3IgY2xvc2luZyBkYmAsIGVycik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEZsdXNoZXMgdGhlIG5ldyBoaXN0b3J5IHRvIGRiXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXBwbGljYXRpb24gYXBwbGljYXRpb24gbmFtZVxuICAgKiBAcGFyYW0ge0FycmF5PE1ldGF0cmFkZXJPcmRlcj59IG5ld0hpc3RvcnlPcmRlcnMgaGlzdG9yeSBvcmRlcnMgdG8gc2F2ZSB0byBkYlxuICAgKiBAcGFyYW0ge0FycmF5PE1ldGF0cmFkZXJEZWFsPn0gbmV3RGVhbHMgZGVhbHMgdG8gc2F2ZSB0byBkYlxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIHRoZSBoaXN0b3J5IGlzIGZsdXNoZWRcbiAgICovXG4gIGFzeW5jIGZsdXNoKGFjY291bnRJZCwgYXBwbGljYXRpb24sIG5ld0hpc3RvcnlPcmRlcnMsIG5ld0RlYWxzKSB7XG4gICAgbGV0IGRiO1xuICAgIHRyeSB7XG4gICAgICBkYiA9IGF3YWl0IHRoaXMuX2dldERhdGFiYXNlKCk7XG4gICAgICBhd2FpdCB0aGlzLl9hcHBlbmREYihkYiwgJ2RlYWxzJywgYWNjb3VudElkICsgJy0nICsgYXBwbGljYXRpb24sIG5ld0RlYWxzKTtcbiAgICAgIGF3YWl0IHRoaXMuX2FwcGVuZERiKGRiLCAnaGlzdG9yeU9yZGVycycsIGFjY291bnRJZCArICctJyArIGFwcGxpY2F0aW9uLCBuZXdIaXN0b3J5T3JkZXJzKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aGlzLl9sb2dnZXIud2FybihgJHthY2NvdW50SWR9OiBmYWlsZWQgdG8gZmx1c2ggaGlzdG9yeSBzdG9yYWdlYCwgZSk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGRiLmNsb3NlKCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgdGhpcy5fbG9nZ2VyLmVycm9yKGAke2FjY291bnRJZH06IGVycm9yIGNsb3NpbmcgZGJgLCBlcnIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIF9nZXREYXRhYmFzZSgpIHtcbiAgICBjb25zdCBrZXlQYXRoID0gJ2lkJztcbiAgICBjb25zdCBkYiA9IGF3YWl0IG9wZW5EQignbWV0YWFwaScsIDIsIHtcbiAgICAgIHVwZ3JhZGUoZGF0YWJhc2UsIG9sZFZlcnNpb24sIG5ld1ZlcnNpb24sIHRyYW5zYWN0aW9uKSB7XG4gICAgICAgIGlmIChvbGRWZXJzaW9uICE9PSAyKSB7XG4gICAgICAgICAgaWYgKGRhdGFiYXNlLm9iamVjdFN0b3JlTmFtZXMuY29udGFpbnMoJ2RlYWxzJykpIHtcbiAgICAgICAgICAgIGRhdGFiYXNlLmRlbGV0ZU9iamVjdFN0b3JlKCdkZWFscycpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZGF0YWJhc2Uub2JqZWN0U3RvcmVOYW1lcy5jb250YWlucygnaGlzdG9yeU9yZGVycycpKSB7XG4gICAgICAgICAgICBkYXRhYmFzZS5kZWxldGVPYmplY3RTdG9yZSgnaGlzdG9yeU9yZGVycycpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRhdGFiYXNlLm9iamVjdFN0b3JlTmFtZXMuY29udGFpbnMoJ2RlYWxzSW5kZXgnKSkge1xuICAgICAgICAgIGRhdGFiYXNlLmNyZWF0ZU9iamVjdFN0b3JlKCdkZWFsc0luZGV4Jywge2tleVBhdGh9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRhdGFiYXNlLm9iamVjdFN0b3JlTmFtZXMuY29udGFpbnMoJ2RlYWxzJykpIHtcbiAgICAgICAgICBkYXRhYmFzZS5jcmVhdGVPYmplY3RTdG9yZSgnZGVhbHMnLCB7a2V5UGF0aH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmICghZGF0YWJhc2Uub2JqZWN0U3RvcmVOYW1lcy5jb250YWlucygnaGlzdG9yeU9yZGVyc0luZGV4JykpIHtcbiAgICAgICAgICBkYXRhYmFzZS5jcmVhdGVPYmplY3RTdG9yZSgnaGlzdG9yeU9yZGVyc0luZGV4Jywge2tleVBhdGh9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRhdGFiYXNlLm9iamVjdFN0b3JlTmFtZXMuY29udGFpbnMoJ2hpc3RvcnlPcmRlcnMnKSkge1xuICAgICAgICAgIGRhdGFiYXNlLmNyZWF0ZU9iamVjdFN0b3JlKCdoaXN0b3J5T3JkZXJzJywge2tleVBhdGh9KTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9KTtcbiAgICByZXR1cm4gZGI7XG4gIH1cblxuICBhc3luYyBfcmVhZERiKGRiLCBzdG9yZSwgcHJlZml4KSB7XG4gICAgY29uc3Qga2V5cyA9IGF3YWl0IGRiLmdldEFsbEtleXMoc3RvcmUsIElEQktleVJhbmdlLmJvdW5kKHByZWZpeCwgcHJlZml4ICsgJy0nICsgJzonKSk7XG4gICAgbGV0IHJlc3VsdCA9IFtdO1xuICAgIGZvciAobGV0IGtleSBvZiBrZXlzKSB7XG4gICAgICBsZXQgdmFsdWUgPSBhd2FpdCBkYi5nZXQoc3RvcmUsIGtleSk7XG4gICAgICBpZiAodmFsdWUpIHtcbiAgICAgICAgZm9yIChsZXQgbGluZSBvZiB2YWx1ZS5kYXRhLnNwbGl0KCdcXG4nKSkge1xuICAgICAgICAgIGlmIChsaW5lLmxlbmd0aCkge1xuICAgICAgICAgICAgbGV0IHJlY29yZCA9IEpTT04ucGFyc2UobGluZSk7XG4gICAgICAgICAgICByZXN1bHQucHVzaChyZWNvcmQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgYXN5bmMgX2FwcGVuZERiKGRiLCBzdG9yZSwgcHJlZml4LCByZWNvcmRzKSB7XG4gICAgaWYgKHJlY29yZHMgJiYgcmVjb3Jkcy5sZW5ndGgpIHtcbiAgICAgIGxldCBsYXN0S2V5ID0gYXdhaXQgZGIuZ2V0KHN0b3JlICsgJ0luZGV4JywgcHJlZml4ICsgJy0nICsgJ3NuJyk7XG4gICAgICBsZXQgaW5kZXggPSAobGFzdEtleSB8fCB7aW5kZXg6IDB9KS5pbmRleCArIDE7XG4gICAgICBsZXQgZGF0YSA9IHJlY29yZHMubWFwKHIgPT4gSlNPTi5zdHJpbmdpZnkocikgKyAnXFxuJykuam9pbignJyk7XG4gICAgICBhd2FpdCBkYi5wdXQoc3RvcmUsIHtkYXRhLCBpZDogcHJlZml4ICsgJy0nICsgaW5kZXh9KTtcbiAgICAgIGF3YWl0IGRiLnB1dChzdG9yZSArICdJbmRleCcsIHtpZDogcHJlZml4ICsgJy0nICsgJ3NuJywgaW5kZXh9KTtcbiAgICB9XG4gIH1cblxufVxuIl0sIm5hbWVzIjpbIkhpc3RvcnlEYXRhYmFzZSIsIkxvZ2dlciIsIm9wZW5EQiIsIkJyb3dzZXJIaXN0b3J5RGF0YWJhc2UiLCJnZXRJbnN0YW5jZSIsImluc3RhbmNlIiwibG9hZEhpc3RvcnkiLCJhY2NvdW50SWQiLCJhcHBsaWNhdGlvbiIsImRiIiwiX2dldERhdGFiYXNlIiwiZGVhbHMiLCJfcmVhZERiIiwiZm9yRWFjaCIsImRlYWwiLCJ0aW1lIiwiRGF0ZSIsImhpc3RvcnlPcmRlcnMiLCJoaXN0b3J5T3JkZXIiLCJkb25lVGltZSIsImVyciIsIl9sb2dnZXIiLCJ3YXJuIiwiY2xlYXIiLCJjbG9zZSIsImVycm9yIiwicHJlZml4IiwicmFuZ2UiLCJJREJLZXlSYW5nZSIsImJvdW5kIiwiZGVsZXRlIiwiZSIsImZsdXNoIiwibmV3SGlzdG9yeU9yZGVycyIsIm5ld0RlYWxzIiwiX2FwcGVuZERiIiwia2V5UGF0aCIsInVwZ3JhZGUiLCJkYXRhYmFzZSIsIm9sZFZlcnNpb24iLCJuZXdWZXJzaW9uIiwidHJhbnNhY3Rpb24iLCJvYmplY3RTdG9yZU5hbWVzIiwiY29udGFpbnMiLCJkZWxldGVPYmplY3RTdG9yZSIsImNyZWF0ZU9iamVjdFN0b3JlIiwic3RvcmUiLCJrZXlzIiwiZ2V0QWxsS2V5cyIsInJlc3VsdCIsImtleSIsInZhbHVlIiwiZ2V0IiwibGluZSIsImRhdGEiLCJzcGxpdCIsImxlbmd0aCIsInJlY29yZCIsIkpTT04iLCJwYXJzZSIsInB1c2giLCJyZWNvcmRzIiwibGFzdEtleSIsImluZGV4IiwibWFwIiwiciIsInN0cmluZ2lmeSIsImpvaW4iLCJwdXQiLCJpZCIsImNvbnN0cnVjdG9yIiwiZ2V0TG9nZ2VyIl0sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUEsT0FBT0EscUJBQXFCLG9CQUFvQjtBQUNoRCxPQUFPQyxZQUFZLGVBQWU7QUFDbEMsU0FBUUMsTUFBTSxRQUFPLE1BQU07QUFLWixJQUFBLEFBQU1DLHlCQUFOLE1BQU1BLCtCQUErQkg7SUFVbEQ7OztHQUdDLEdBQ0QsT0FBT0ksY0FBYztRQUNuQixJQUFJLENBQUNELHVCQUF1QkUsUUFBUSxFQUFFO1lBQ3BDRix1QkFBdUJFLFFBQVEsR0FBRyxJQUFJRjtRQUN4QztRQUNBLE9BQU9BLHVCQUF1QkUsUUFBUTtJQUN4QztJQUVBOzs7OztHQUtDLEdBQ0QsQUFBTUMsWUFBWUMsU0FBUyxFQUFFQyxXQUFXOztlQUF4QyxvQkFBQTtZQUNFLElBQUlDO1lBQ0osSUFBSTtnQkFDRkEsS0FBSyxNQUFNLE1BQUtDLFlBQVk7Z0JBQzVCLElBQUlDLFFBQVEsTUFBTSxNQUFLQyxPQUFPLENBQUNILElBQUksU0FBU0YsWUFBWSxNQUFNQztnQkFDOURHLE1BQU1FLE9BQU8sQ0FBQ0MsQ0FBQUEsT0FBUUEsS0FBS0MsSUFBSSxHQUFHLElBQUlDLEtBQUtGLEtBQUtDLElBQUk7Z0JBQ3BELElBQUlFLGdCQUFnQixNQUFNLE1BQUtMLE9BQU8sQ0FBQ0gsSUFBSSxpQkFBaUJGLFlBQVksTUFBTUM7Z0JBQzlFUyxjQUFjSixPQUFPLENBQUNLLENBQUFBO29CQUNwQkEsYUFBYUgsSUFBSSxHQUFHLElBQUlDLEtBQUtFLGFBQWFILElBQUk7b0JBQzlDRyxhQUFhQyxRQUFRLEdBQUcsSUFBSUgsS0FBS0UsYUFBYUMsUUFBUTtnQkFDeEQ7Z0JBQ0EsT0FBTztvQkFBQ1I7b0JBQU9NO2dCQUFhO1lBQzlCLEVBQUUsT0FBT0csS0FBSztnQkFDWixNQUFLQyxPQUFPLENBQUNDLElBQUksQ0FBQyxDQUFDLEVBQUVmLFVBQVUsMkRBQTJELENBQUMsRUFBRWE7Z0JBQzdGLE1BQU0sTUFBS0csS0FBSyxDQUFDaEIsV0FBV0M7Z0JBQzVCLE9BQU87b0JBQUNHLE9BQU8sRUFBRTtvQkFBRU0sZUFBZSxFQUFFO2dCQUFBO1lBQ3RDLFNBQVU7Z0JBQ1IsSUFBSTtvQkFDRixNQUFNUixHQUFHZSxLQUFLO2dCQUNoQixFQUFFLE9BQU9KLEtBQUs7b0JBQ1osTUFBS0MsT0FBTyxDQUFDSSxLQUFLLENBQUMsQ0FBQyxFQUFFbEIsVUFBVSxrQkFBa0IsQ0FBQyxFQUFFYTtnQkFDdkQ7WUFDRjtRQUNGOztJQUVBOzs7OztHQUtDLEdBQ0QsQUFBTUcsTUFBTWhCLFNBQVMsRUFBRUMsV0FBVzs7ZUFBbEMsb0JBQUE7WUFDRSxNQUFNa0IsU0FBU25CLFlBQVksTUFBTUM7WUFDakMsTUFBTW1CLFFBQVFDLFlBQVlDLEtBQUssQ0FBQ0gsUUFBUUEsU0FBUztZQUNqRCxJQUFJakI7WUFDSixJQUFJO2dCQUNGQSxLQUFLLE1BQU0sTUFBS0MsWUFBWTtnQkFDNUIsTUFBTUQsR0FBR3FCLE1BQU0sQ0FBQyxTQUFTSDtnQkFDekIsTUFBTWxCLEdBQUdxQixNQUFNLENBQUMsY0FBY0g7Z0JBQzlCLE1BQU1sQixHQUFHcUIsTUFBTSxDQUFDLGlCQUFpQkg7Z0JBQ2pDLE1BQU1sQixHQUFHcUIsTUFBTSxDQUFDLHNCQUFzQkg7WUFDeEMsRUFBRSxPQUFPSSxHQUFHO2dCQUNWLE1BQUtWLE9BQU8sQ0FBQ0MsSUFBSSxDQUFDLENBQUMsRUFBRWYsVUFBVSxpQ0FBaUMsQ0FBQyxFQUFFd0I7WUFDckUsU0FBVTtnQkFDUixJQUFJO29CQUNGLE1BQU10QixHQUFHZSxLQUFLO2dCQUNoQixFQUFFLE9BQU9KLEtBQUs7b0JBQ1osTUFBS0MsT0FBTyxDQUFDSSxLQUFLLENBQUMsQ0FBQyxFQUFFbEIsVUFBVSxrQkFBa0IsQ0FBQyxFQUFFYTtnQkFDdkQ7WUFDRjtRQUNGOztJQUVBOzs7Ozs7O0dBT0MsR0FDRCxBQUFNWSxNQUFNekIsU0FBUyxFQUFFQyxXQUFXLEVBQUV5QixnQkFBZ0IsRUFBRUMsUUFBUTs7ZUFBOUQsb0JBQUE7WUFDRSxJQUFJekI7WUFDSixJQUFJO2dCQUNGQSxLQUFLLE1BQU0sTUFBS0MsWUFBWTtnQkFDNUIsTUFBTSxNQUFLeUIsU0FBUyxDQUFDMUIsSUFBSSxTQUFTRixZQUFZLE1BQU1DLGFBQWEwQjtnQkFDakUsTUFBTSxNQUFLQyxTQUFTLENBQUMxQixJQUFJLGlCQUFpQkYsWUFBWSxNQUFNQyxhQUFheUI7WUFDM0UsRUFBRSxPQUFPRixHQUFHO2dCQUNWLE1BQUtWLE9BQU8sQ0FBQ0MsSUFBSSxDQUFDLENBQUMsRUFBRWYsVUFBVSxpQ0FBaUMsQ0FBQyxFQUFFd0I7WUFDckUsU0FBVTtnQkFDUixJQUFJO29CQUNGLE1BQU10QixHQUFHZSxLQUFLO2dCQUNoQixFQUFFLE9BQU9KLEtBQUs7b0JBQ1osTUFBS0MsT0FBTyxDQUFDSSxLQUFLLENBQUMsQ0FBQyxFQUFFbEIsVUFBVSxrQkFBa0IsQ0FBQyxFQUFFYTtnQkFDdkQ7WUFDRjtRQUNGOztJQUVNVjtlQUFOLG9CQUFBO1lBQ0UsTUFBTTBCLFVBQVU7WUFDaEIsTUFBTTNCLEtBQUssTUFBTVAsT0FBTyxXQUFXLEdBQUc7Z0JBQ3BDbUMsU0FBUUMsUUFBUSxFQUFFQyxVQUFVLEVBQUVDLFVBQVUsRUFBRUMsV0FBVztvQkFDbkQsSUFBSUYsZUFBZSxHQUFHO3dCQUNwQixJQUFJRCxTQUFTSSxnQkFBZ0IsQ0FBQ0MsUUFBUSxDQUFDLFVBQVU7NEJBQy9DTCxTQUFTTSxpQkFBaUIsQ0FBQzt3QkFDN0I7d0JBQ0EsSUFBSU4sU0FBU0ksZ0JBQWdCLENBQUNDLFFBQVEsQ0FBQyxrQkFBa0I7NEJBQ3ZETCxTQUFTTSxpQkFBaUIsQ0FBQzt3QkFDN0I7b0JBQ0Y7b0JBQ0EsSUFBSSxDQUFDTixTQUFTSSxnQkFBZ0IsQ0FBQ0MsUUFBUSxDQUFDLGVBQWU7d0JBQ3JETCxTQUFTTyxpQkFBaUIsQ0FBQyxjQUFjOzRCQUFDVDt3QkFBTztvQkFDbkQ7b0JBQ0EsSUFBSSxDQUFDRSxTQUFTSSxnQkFBZ0IsQ0FBQ0MsUUFBUSxDQUFDLFVBQVU7d0JBQ2hETCxTQUFTTyxpQkFBaUIsQ0FBQyxTQUFTOzRCQUFDVDt3QkFBTztvQkFDOUM7b0JBQ0EsSUFBSSxDQUFDRSxTQUFTSSxnQkFBZ0IsQ0FBQ0MsUUFBUSxDQUFDLHVCQUF1Qjt3QkFDN0RMLFNBQVNPLGlCQUFpQixDQUFDLHNCQUFzQjs0QkFBQ1Q7d0JBQU87b0JBQzNEO29CQUNBLElBQUksQ0FBQ0UsU0FBU0ksZ0JBQWdCLENBQUNDLFFBQVEsQ0FBQyxrQkFBa0I7d0JBQ3hETCxTQUFTTyxpQkFBaUIsQ0FBQyxpQkFBaUI7NEJBQUNUO3dCQUFPO29CQUN0RDtnQkFDRjtZQUNGO1lBQ0EsT0FBTzNCO1FBQ1Q7O0lBRU1HLFFBQVFILEVBQUUsRUFBRXFDLEtBQUssRUFBRXBCLE1BQU07ZUFBL0Isb0JBQUE7WUFDRSxNQUFNcUIsT0FBTyxNQUFNdEMsR0FBR3VDLFVBQVUsQ0FBQ0YsT0FBT2xCLFlBQVlDLEtBQUssQ0FBQ0gsUUFBUUEsU0FBUyxNQUFNO1lBQ2pGLElBQUl1QixTQUFTLEVBQUU7WUFDZixLQUFLLElBQUlDLE9BQU9ILEtBQU07Z0JBQ3BCLElBQUlJLFFBQVEsTUFBTTFDLEdBQUcyQyxHQUFHLENBQUNOLE9BQU9JO2dCQUNoQyxJQUFJQyxPQUFPO29CQUNULEtBQUssSUFBSUUsUUFBUUYsTUFBTUcsSUFBSSxDQUFDQyxLQUFLLENBQUMsTUFBTzt3QkFDdkMsSUFBSUYsS0FBS0csTUFBTSxFQUFFOzRCQUNmLElBQUlDLFNBQVNDLEtBQUtDLEtBQUssQ0FBQ047NEJBQ3hCSixPQUFPVyxJQUFJLENBQUNIO3dCQUNkO29CQUNGO2dCQUNGO1lBQ0Y7WUFDQSxPQUFPUjtRQUNUOztJQUVNZCxVQUFVMUIsRUFBRSxFQUFFcUMsS0FBSyxFQUFFcEIsTUFBTSxFQUFFbUMsT0FBTztlQUExQyxvQkFBQTtZQUNFLElBQUlBLFdBQVdBLFFBQVFMLE1BQU0sRUFBRTtnQkFDN0IsSUFBSU0sVUFBVSxNQUFNckQsR0FBRzJDLEdBQUcsQ0FBQ04sUUFBUSxTQUFTcEIsU0FBUyxNQUFNO2dCQUMzRCxJQUFJcUMsUUFBUSxBQUFDRCxDQUFBQSxXQUFXO29CQUFDQyxPQUFPO2dCQUFDLENBQUEsRUFBR0EsS0FBSyxHQUFHO2dCQUM1QyxJQUFJVCxPQUFPTyxRQUFRRyxHQUFHLENBQUNDLENBQUFBLElBQUtQLEtBQUtRLFNBQVMsQ0FBQ0QsS0FBSyxNQUFNRSxJQUFJLENBQUM7Z0JBQzNELE1BQU0xRCxHQUFHMkQsR0FBRyxDQUFDdEIsT0FBTztvQkFBQ1E7b0JBQU1lLElBQUkzQyxTQUFTLE1BQU1xQztnQkFBSztnQkFDbkQsTUFBTXRELEdBQUcyRCxHQUFHLENBQUN0QixRQUFRLFNBQVM7b0JBQUN1QixJQUFJM0MsU0FBUyxNQUFNO29CQUFNcUM7Z0JBQUs7WUFDL0Q7UUFDRjs7SUE1SkE7O0dBRUMsR0FDRE8sYUFBYztRQUNaLEtBQUs7UUFDTCxJQUFJLENBQUNqRCxPQUFPLEdBQUdwQixPQUFPc0UsU0FBUyxDQUFDO0lBQ2xDO0FBd0pGO0FBbktBOztDQUVDLEdBQ0QsU0FBcUJwRSxvQ0FnS3BCIn0=