UNPKG

@iotize/tap-scripts

Version:

IoTize Tap scripts

312 lines 19.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ScriptRunner = exports.DisplayToLogFunction = exports.OutputToLogFunction = exports.TestRunnerContext = void 0; const byte_converter_1 = require("@iotize/common/byte-converter"); const rxjs_1 = require("rxjs"); const errors_1 = require("./errors"); const instructions_1 = require("./instructions"); const logger_1 = require("./logger"); /** * */ class TestRunnerContext { constructor(device, instructions, io) { this.device = device; this.instructions = instructions; this.io = io; this._labels = {}; this.current = -1; this.resultCode = null; this._data = {}; this._running = false; this.nextChanged = false; this.errorHandler = (error) => { throw error; }; this.instructions.forEach((instruction, index) => { if (instruction instanceof instructions_1.LabelInstruction) { this.mapLabel(instruction.name, index); } }); } store(key, value) { if (arguments.length === 2) { this._data[key] = value; } else { return this._data[key]; } } get labels() { return this._labels; } set lastLwm2mGetResponse(r) { this._lastLwm2mGetResponse = r; this.lastLwm2mResponse = r; } get lastLwm2mGetResponse() { if (!this._lastLwm2mGetResponse) { throw new Error(`No last LWM2M get response available yet`); } return this._lastLwm2mGetResponse; } // asObservable() { // return this._observer!.asObservable(); // TODO fix // } /** * Resume script execution */ continue() { return __awaiter(this, void 0, void 0, function* () { this._running = true; while (this._running && !this.isEnded()) { if (!this.nextChanged) { this.current++; } this.nextChanged = false; yield this.safeRunOne(this.current); } this._running = false; }); } runAll() { return new rxjs_1.Observable((observer) => { this._observer = observer; this.resultCode = null; this.current = -1; this.continue() .then(() => [this._observer, undefined]) .catch((err) => [this._observer, err]) .then(([observer, err]) => { this._observer = undefined; if (!err) { observer === null || observer === void 0 ? void 0 : observer.complete(); } else { observer === null || observer === void 0 ? void 0 : observer.error(err); } }); return () => { this._observer = undefined; this.stop(); }; }); } isRunning() { return this._running; } /** * Pause script execution */ stop() { this._running = false; } /** * Return true script execution is finished */ isEnded() { return (this.resultCode !== null || this.current >= this.instructions.length); } getCurrentIndex() { return this.current; } setNextIndex(index) { (0, logger_1.debug)(`TestRunnerContext`, `Jumping to index: ${index}`); this.current = index; this.nextChanged = true; } runCurrent() { return this.safeRunOne(this.current); } /** * Run instruction at given index * @param index */ runOne(index) { var _a; return __awaiter(this, void 0, void 0, function* () { this.current = index; // debug(`next on instruction ${index}/${this.instructions.length}`); if (index < this.instructions.length) { const instruction = this.instructions[index]; if (!instruction) { throw errors_1.ScriptError.internalError(`Instruction should not be null at index ${index}`); } (0, logger_1.debug)(`Running instruction ${index + 1}/${this.instructions.length}: ${instruction.constructor.name} (${instruction.toString()})`); const progressInfo = { loaded: index, total: this.instructions.length }; (_a = this._observer) === null || _a === void 0 ? void 0 : _a.next({ type: 'before', instruction: instruction, progress: progressInfo }); const result = instruction.run(this); let promise; if (result instanceof Promise) { promise = result; } else { promise = Promise.resolve(result); } return promise.then(res => { var _a; (_a = this._observer) === null || _a === void 0 ? void 0 : _a.next({ type: 'after', instruction: instruction, progress: progressInfo, result: result }); return res; }); } else { this.end(); return Promise.resolve(); } }); } next() { return __awaiter(this, void 0, void 0, function* () { const result = yield this.safeRunOne(this.current + 1); this.next(); }); } /** * TODO use result code */ end(resultCode = 0) { var _a; if (typeof resultCode !== 'number') { throw errors_1.ScriptError.internalError(`result code should be a number. Given: "${resultCode}" (type=${typeof resultCode})`); } this.resultCode = resultCode; (0, logger_1.debug)(`Ending script with result code ${resultCode}`); (_a = this._observer) === null || _a === void 0 ? void 0 : _a.next({ type: 'end', resultCode: resultCode, progress: { total: this.instructions.length, loaded: this.instructions.length } }); } onError(err) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { // debug('ScriptRunner', `An error occured`, err); try { if (!this.errorHandler) { this._running = false; (_a = this._observer) === null || _a === void 0 ? void 0 : _a.error(err); } else { yield this.errorHandler(err); } } catch (error) { this._running = false; (_b = this._observer) === null || _b === void 0 ? void 0 : _b.error(err); } }); } mapLabel(name, value) { // debug(`Adding label "${name}" to index ${value}`) this._labels[name] = value; } getLabel(name) { if (name in this._labels) { return this._labels[name]; } else { return undefined; } } safeRunOne(index) { return __awaiter(this, void 0, void 0, function* () { try { return yield this.runOne(index); } catch (err) { yield this.onError(err); } }); } } exports.TestRunnerContext = TestRunnerContext; function OutputToLogFunction(response) { let message; if (response) { message = (0, byte_converter_1.bufferToHexString)(response.toBytes()); } else { message = 'NO OUTPUT YET'; } (0, logger_1.debug)(message + '\r\n'); } exports.OutputToLogFunction = OutputToLogFunction; function DisplayToLogFunction(logLevel, message) { const map = { error: 'error', verbose: 'debug', message: 'info' }; console[map[logLevel]](message); } exports.DisplayToLogFunction = DisplayToLogFunction; /** * Script runner * */ class ScriptRunner { constructor(io = { output: OutputToLogFunction, display: DisplayToLogFunction }) { this.io = io; } /** * Configure error handler */ set errorHandler(handler) { this._errorHandler = handler; } get errorHandler() { return this._errorHandler; } isRunning() { var _a; return !!((_a = this.context) === null || _a === void 0 ? void 0 : _a.isRunning()); } /** * Run script instructions * @param instructions * @param device */ run(instructions, device) { if (this.context) { // should we throw an error when script is already running ? } this.context = new TestRunnerContext(device, instructions, this.io); if (this.context.errorHandler) { this.context.errorHandler = this._errorHandler; } return this.context.runAll(); } stop() { var _a; (_a = this.context) === null || _a === void 0 ? void 0 : _a.stop(); } } exports.ScriptRunner = ScriptRunner; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NyaXB0LXJ1bm5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvc2NyaXB0LXJ1bm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFBQSxrRUFBa0U7QUFHbEUsK0JBQTRDO0FBRzVDLHFDQUF1QztBQUN2QyxpREFBa0Q7QUFFbEQscUNBQWlDO0FBVWpDOztHQUVHO0FBQ0gsTUFBYSxpQkFBaUI7SUEyQzFCLFlBQ1csTUFBVyxFQUNYLFlBQWlDLEVBQ2pDLEVBQXdEO1FBRnhELFdBQU0sR0FBTixNQUFNLENBQUs7UUFDWCxpQkFBWSxHQUFaLFlBQVksQ0FBcUI7UUFDakMsT0FBRSxHQUFGLEVBQUUsQ0FBc0Q7UUF6Q3pELFlBQU8sR0FBZ0MsRUFBRSxDQUFDO1FBQzFDLFlBQU8sR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNiLGVBQVUsR0FBa0IsSUFBSSxDQUFDO1FBQ2pDLFVBQUssR0FBMkIsRUFBRSxDQUFDO1FBQ25DLGFBQVEsR0FBWSxLQUFLLENBQUM7UUFFcEMsZ0JBQVcsR0FBWSxLQUFLLENBQUM7UUEyQnRCLGlCQUFZLEdBQTZCLENBQUMsS0FBWSxFQUFFLEVBQUU7WUFDN0QsTUFBTSxLQUFLLENBQUM7UUFDaEIsQ0FBQyxDQUFDO1FBUUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLEVBQUUsS0FBSyxFQUFFLEVBQUU7WUFDN0MsSUFBSSxXQUFXLFlBQVksK0JBQWdCLEVBQUU7Z0JBQ3pDLElBQUksQ0FBQyxRQUFRLENBQUUsV0FBZ0MsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7YUFDaEU7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUF2Q0QsS0FBSyxDQUFDLEdBQVEsRUFBRSxLQUFXO1FBQ3ZCLElBQUksU0FBUyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7WUFDeEIsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUM7U0FDM0I7YUFBTTtZQUNILE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUMxQjtJQUNMLENBQUM7SUFFRCxJQUFJLE1BQU07UUFDTixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQztJQUVELElBQUksb0JBQW9CLENBQUMsQ0FBK0I7UUFDcEQsSUFBSSxDQUFDLHFCQUFxQixHQUFHLENBQUMsQ0FBQztRQUMvQixJQUFJLENBQUMsaUJBQWlCLEdBQUcsQ0FBQyxDQUFDO0lBQy9CLENBQUM7SUFFRCxJQUFJLG9CQUFvQjtRQUNwQixJQUFJLENBQUMsSUFBSSxDQUFDLHFCQUFxQixFQUFFO1lBQzdCLE1BQU0sSUFBSSxLQUFLLENBQUMsMENBQTBDLENBQUMsQ0FBQztTQUMvRDtRQUNELE9BQU8sSUFBSSxDQUFDLHFCQUFxQixDQUFDO0lBQ3RDLENBQUM7SUFtQkQsbUJBQW1CO0lBQ25CLHlEQUF5RDtJQUN6RCxJQUFJO0lBRUo7O09BRUc7SUFDRyxRQUFROztZQUNWLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO1lBQ3JCLE9BQU8sSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRTtnQkFDckMsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUU7b0JBQ25CLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztpQkFDbEI7Z0JBQ0QsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUM7Z0JBQ3pCLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7YUFDdkM7WUFDRCxJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztRQUMxQixDQUFDO0tBQUE7SUFFRCxNQUFNO1FBQ0YsT0FBTyxJQUFJLGlCQUFVLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRTtZQUMvQixJQUFJLENBQUMsU0FBUyxHQUFHLFFBQVEsQ0FBQztZQUMxQixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztZQUN2QixJQUFJLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ2xCLElBQUksQ0FBQyxRQUFRLEVBQUU7aUJBQ1YsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQztpQkFDdkMsS0FBSyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDLENBQUM7aUJBQ3JDLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUU7Z0JBQ3RCLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO2dCQUMzQixJQUFJLENBQUMsR0FBRyxFQUFFO29CQUNOLFFBQVEsYUFBUixRQUFRLHVCQUFSLFFBQVEsQ0FBRSxRQUFRLEVBQUUsQ0FBQztpQkFDeEI7cUJBQ0k7b0JBQ0QsUUFBUSxhQUFSLFFBQVEsdUJBQVIsUUFBUSxDQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztpQkFDeEI7WUFDTCxDQUFDLENBQUMsQ0FBQztZQUVQLE9BQU8sR0FBRyxFQUFFO2dCQUNSLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO2dCQUMzQixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDaEIsQ0FBQyxDQUFBO1FBQ0wsQ0FBQyxDQUFDLENBQUE7SUFDTixDQUFDO0lBRU0sU0FBUztRQUNaLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN6QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJO1FBQ0EsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDMUIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsT0FBTztRQUNILE9BQU8sQ0FDSCxJQUFJLENBQUMsVUFBVSxLQUFLLElBQUksSUFBSSxJQUFJLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUN2RSxDQUFDO0lBQ04sQ0FBQztJQUVELGVBQWU7UUFDWCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQztJQUVELFlBQVksQ0FBQyxLQUFhO1FBQ3RCLElBQUEsY0FBSyxFQUFDLG1CQUFtQixFQUFFLHFCQUFxQixLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ3pELElBQUksQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDO1FBQ3JCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO0lBQzVCLENBQUM7SUFFRCxVQUFVO1FBQ04sT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBR0Q7OztPQUdHO0lBQ0csTUFBTSxDQUFDLEtBQWE7OztZQUN0QixJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztZQUNyQixxRUFBcUU7WUFDckUsSUFBSSxLQUFLLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQUU7Z0JBQ2xDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQzdDLElBQUksQ0FBQyxXQUFXLEVBQUU7b0JBQ2QsTUFBTSxvQkFBVyxDQUFDLGFBQWEsQ0FDM0IsMkNBQTJDLEtBQUssRUFBRSxDQUNyRCxDQUFDO2lCQUNMO2dCQUNELElBQUEsY0FBSyxFQUNELHVCQUF1QixLQUFLLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsTUFDdEQsS0FBSyxXQUFXLENBQUMsV0FBVyxDQUFDLElBQUksS0FBSyxXQUFXLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FDbEUsQ0FBQztnQkFDRixNQUFNLFlBQVksR0FBa0I7b0JBQ2hDLE1BQU0sRUFBRSxLQUFLO29CQUNiLEtBQUssRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU07aUJBQ2xDLENBQUM7Z0JBQ0YsTUFBQSxJQUFJLENBQUMsU0FBUywwQ0FBRSxJQUFJLENBQUM7b0JBQ2pCLElBQUksRUFBRSxRQUFRO29CQUNkLFdBQVcsRUFBRSxXQUFXO29CQUN4QixRQUFRLEVBQUUsWUFBWTtpQkFDekIsQ0FBQyxDQUFDO2dCQUNILE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ3JDLElBQUksT0FBcUIsQ0FBQztnQkFDMUIsSUFBSSxNQUFNLFlBQVksT0FBTyxFQUFFO29CQUMzQixPQUFPLEdBQUcsTUFBTSxDQUFDO2lCQUNwQjtxQkFBTTtvQkFDSCxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztpQkFDckM7Z0JBQ0QsT0FBTyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFOztvQkFDdEIsTUFBQSxJQUFJLENBQUMsU0FBUywwQ0FBRSxJQUFJLENBQUM7d0JBQ2pCLElBQUksRUFBRSxPQUFPO3dCQUNiLFdBQVcsRUFBRSxXQUFXO3dCQUN4QixRQUFRLEVBQUUsWUFBWTt3QkFDdEIsTUFBTSxFQUFFLE1BQU07cUJBQ2pCLENBQUMsQ0FBQztvQkFDSCxPQUFPLEdBQUcsQ0FBQztnQkFDZixDQUFDLENBQUMsQ0FBQzthQUNOO2lCQUFNO2dCQUNILElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDWCxPQUFPLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQzthQUM1Qjs7S0FDSjtJQUVLLElBQUk7O1lBQ04sTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDdkQsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2hCLENBQUM7S0FBQTtJQUVEOztPQUVHO0lBQ0gsR0FBRyxDQUFDLGFBQXFCLENBQUM7O1FBQ3RCLElBQUksT0FBTyxVQUFVLEtBQUssUUFBUSxFQUFFO1lBQ2hDLE1BQU0sb0JBQVcsQ0FBQyxhQUFhLENBQzNCLDJDQUEyQyxVQUFVLFdBQVcsT0FBTyxVQUFVLEdBQUcsQ0FDdkYsQ0FBQztTQUNMO1FBQ0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFDN0IsSUFBQSxjQUFLLEVBQUMsa0NBQWtDLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDdEQsTUFBQSxJQUFJLENBQUMsU0FBUywwQ0FBRSxJQUFJLENBQUM7WUFDakIsSUFBSSxFQUFFLEtBQUs7WUFDWCxVQUFVLEVBQUUsVUFBVTtZQUN0QixRQUFRLEVBQUU7Z0JBQ04sS0FBSyxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTTtnQkFDL0IsTUFBTSxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTTthQUNuQztTQUNKLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFSyxPQUFPLENBQUMsR0FBVTs7O1lBQ3BCLGtEQUFrRDtZQUNsRCxJQUFJO2dCQUNBLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFO29CQUNwQixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztvQkFDdEIsTUFBQSxJQUFJLENBQUMsU0FBUywwQ0FBRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7aUJBQzlCO3FCQUFNO29CQUNILE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztpQkFDaEM7YUFDSjtZQUFDLE9BQU8sS0FBSyxFQUFFO2dCQUNaLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO2dCQUN0QixNQUFBLElBQUksQ0FBQyxTQUFTLDBDQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQzthQUM5Qjs7S0FDSjtJQUVELFFBQVEsQ0FBQyxJQUFZLEVBQUUsS0FBYTtRQUNoQyxvREFBb0Q7UUFDcEQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUM7SUFDL0IsQ0FBQztJQUVELFFBQVEsQ0FBQyxJQUFZO1FBQ2pCLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDdEIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQzdCO2FBQU07WUFDSCxPQUFPLFNBQVMsQ0FBQztTQUNwQjtJQUNMLENBQUM7SUFFYSxVQUFVLENBQUMsS0FBYTs7WUFDbEMsSUFBSTtnQkFDQSxPQUFPLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQzthQUNuQztZQUFDLE9BQU8sR0FBUSxFQUFFO2dCQUNmLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQzthQUMzQjtRQUNMLENBQUM7S0FBQTtDQUVKO0FBclBELDhDQXFQQztBQUVELFNBQWdCLG1CQUFtQixDQUFDLFFBQXNDO0lBQ3RFLElBQUksT0FBZSxDQUFDO0lBQ3BCLElBQUksUUFBUSxFQUFFO1FBQ1YsT0FBTyxHQUFHLElBQUEsa0NBQWlCLEVBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7S0FDbkQ7U0FBTTtRQUNILE9BQU8sR0FBRyxlQUFlLENBQUM7S0FDN0I7SUFDRCxJQUFBLGNBQUssRUFBQyxPQUFPLEdBQUcsTUFBTSxDQUFDLENBQUM7QUFDNUIsQ0FBQztBQVJELGtEQVFDO0FBRUQsU0FBZ0Isb0JBQW9CLENBQUMsUUFBa0IsRUFBRSxPQUFlO0lBQ3BFLE1BQU0sR0FBRyxHQUFHO1FBQ1IsS0FBSyxFQUFFLE9BQU87UUFDZCxPQUFPLEVBQUUsT0FBTztRQUNoQixPQUFPLEVBQUUsTUFBTTtLQUNsQixDQUFDO0lBQ0QsT0FBZSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQzdDLENBQUM7QUFQRCxvREFPQztBQUVEOzs7R0FHRztBQUNILE1BQWEsWUFBWTtJQUtyQixZQUNJLEtBQXFCO1FBQ2pCLE1BQU0sRUFBRSxtQkFBbUI7UUFDM0IsT0FBTyxFQUFFLG9CQUFvQjtLQUNoQztRQUVELElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksWUFBWSxDQUFDLE9BQWlDO1FBQzlDLElBQUksQ0FBQyxhQUFhLEdBQUcsT0FBTyxDQUFDO0lBQ2pDLENBQUM7SUFFRCxJQUFJLFlBQVk7UUFDWixPQUFPLElBQUksQ0FBQyxhQUFhLENBQUM7SUFDOUIsQ0FBQztJQUVNLFNBQVM7O1FBQ1osT0FBTyxDQUFDLENBQUMsQ0FBQSxNQUFBLElBQUksQ0FBQyxPQUFPLDBDQUFFLFNBQVMsRUFBRSxDQUFBLENBQUM7SUFDdkMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxHQUFHLENBQ04sWUFBaUMsRUFDakMsTUFBVztRQUVYLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNkLDREQUE0RDtTQUMvRDtRQUNELElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsWUFBWSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNwRSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFO1lBQzNCLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUM7U0FDbEQ7UUFDRCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDakMsQ0FBQztJQUVNLElBQUk7O1FBQ1AsTUFBQSxJQUFJLENBQUMsT0FBTywwQ0FBRSxJQUFJLEVBQUUsQ0FBQztJQUN6QixDQUFDO0NBQ0o7QUFuREQsb0NBbURDIn0=