ngx-indexed-db
Version:
Angular wrapper to IndexedDB database.
498 lines • 76.8 kB
JavaScript
import { __awaiter } from "tslib";
import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
import { openDatabase, CreateObjectStore } from './ngx-indexed-db';
import { createTransaction, optionsGenerator, validateBeforeTransaction } from '../utils';
import { CONFIG_TOKEN, DBMode } from './ngx-indexed-db.meta';
import { isPlatformBrowser } from '@angular/common';
import { from, Subject } from 'rxjs';
import { take } from 'rxjs/operators';
export class NgxIndexedDBService {
constructor(dbConfig, platformId) {
this.dbConfig = dbConfig;
this.platformId = platformId;
if (!dbConfig.name) {
throw new Error('NgxIndexedDB: Please, provide the dbName in the configuration');
}
if (!dbConfig.version) {
throw new Error('NgxIndexedDB: Please, provide the db version in the configuration');
}
this.isBrowser = isPlatformBrowser(this.platformId);
if (this.isBrowser) {
this.indexedDB =
window.indexedDB ||
window.mozIndexedDB ||
window.webkitIndexedDB ||
window.msIndexedDB;
CreateObjectStore(this.indexedDB, dbConfig.name, dbConfig.version, dbConfig.objectStoresMeta, dbConfig.migrationFactory);
}
}
/**
* Allows to crate a new object store ad-hoc
* @param storeName The name of the store to be created
* @param migrationFactory The migration factory if exists
*/
createObjectStore(storeSchema, migrationFactory) {
const storeSchemas = [storeSchema];
CreateObjectStore(this.indexedDB, this.dbConfig.name, ++this.dbConfig.version, storeSchemas, migrationFactory);
}
/**
* Adds new entry in the store and returns its key
* @param storeName The name of the store to add the item
* @param value The entry to be added
* @param key The optional key for the entry
*/
add(storeName, value, key) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
const transaction = createTransaction(db, optionsGenerator(DBMode.readwrite, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const request = Boolean(key)
? objectStore.add(value, key)
: objectStore.add(value);
request.onsuccess = (evt) => {
const result = evt.target.result;
resolve(result);
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Adds new entries in the store and returns its key
* @param storeName The name of the store to add the item
* @param values The entries to be added containing optional key attribute
*/
bulkAdd(storeName, values) {
const promises = values.map((value) => {
return new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
const transaction = createTransaction(db, optionsGenerator(DBMode.readwrite, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const key = value.key;
delete value.key;
const request = Boolean(key)
? objectStore.add(value, key)
: objectStore.add(value);
request.onsuccess = (evt) => {
const result = evt.target.result;
resolve(result);
};
})
.catch((reason) => reject(reason));
});
});
return from(Promise.resolve(Promise.all(promises)));
}
/**
* Adds new entry in the store and returns the item that was added
* @param storeName The name of the store to add the item
* @param value The entry to be added
* @param key The optional key for the entry
*/
addItem(storeName, value, key) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
const transaction = createTransaction(db, optionsGenerator(DBMode.readwrite, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const hasKey = Boolean(key);
const request = hasKey ? objectStore.add(value, key) : objectStore.add(value);
request.onsuccess = (evt) => {
const result = evt.target.result;
const itemKey = hasKey ? key : result;
this.getByKey(storeName, itemKey).subscribe((newValue) => {
resolve(newValue);
});
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Adds new entry in the store and returns the item that was added
* @param storeName The name of the store to add the item
* @param value The entry to be added
* @param key The key for the entry
*/
addItemWithKey(storeName, value, key) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
const transaction = createTransaction(db, optionsGenerator(DBMode.readwrite, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
transaction.oncomplete = () => {
this.getByKey(storeName, key).subscribe((newValue) => {
resolve(newValue);
});
};
objectStore.add(value, key);
})
.catch((reason) => reject(reason));
}));
}
/**
* Returns entry by key.
* @param storeName The name of the store to query
* @param key The entry key
*/
getByKey(storeName, key) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
const transaction = createTransaction(db, optionsGenerator(DBMode.readonly, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const request = objectStore.get(key);
request.onsuccess = (event) => {
resolve(event.target.result);
};
request.onerror = (event) => {
reject(event);
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Retrieve multiple entries in the store
* @param storeName The name of the store to retrieve the items
* @param keys The ids entries to be retrieve
*/
bulkGet(storeName, keys) {
const promises = keys.map(key => this.getByKey(storeName, key).toPromise());
return from(Promise.resolve(Promise.all(promises)));
}
/**
* Returns entry by id.
* @param storeName The name of the store to query
* @param id The entry id
*/
getByID(storeName, id) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readonly, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const request = objectStore.get(id);
request.onsuccess = (event) => {
resolve(event.target.result);
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Returns entry by index.
* @param storeName The name of the store to query
* @param indexName The index name to filter
* @param key The entry key.
*/
getByIndex(storeName, indexName, key) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readonly, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const index = objectStore.index(indexName);
const request = index.get(key);
request.onsuccess = (event) => {
resolve(event.target.result);
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Return all elements from one store
* @param storeName The name of the store to select the items
*/
getAll(storeName) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readonly, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const request = objectStore.getAll();
request.onerror = (evt) => {
reject(evt);
};
request.onsuccess = ({ target: { result: ResultAll } }) => {
resolve(ResultAll);
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Returns all items from the store after update.
* @param storeName The name of the store to update
* @param value The new value for the entry
* @param key The key of the entry to update if exists
*/
update(storeName, value, key) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readwrite, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
transaction.oncomplete = () => {
this.getAll(storeName)
.pipe(take(1))
.subscribe((newValues) => {
resolve(newValues);
});
};
key ? objectStore.put(value, key) : objectStore.put(value);
})
.catch((reason) => reject(reason));
}));
}
/**
* Returns the item you updated from the store after the update.
* @param storeName The name of the store to update
* @param value The new value for the entry
* @param key The key of the entry to update
*/
updateByKey(storeName, value, key) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readwrite, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
transaction.oncomplete = () => {
this.getByKey(storeName, key).subscribe((newValue) => {
resolve(newValue);
});
};
objectStore.put(value, key);
})
.catch((reason) => reject(reason));
}));
}
/**
* Returns all items from the store after delete.
* @param storeName The name of the store to have the entry deleted
* @param key The key of the entry to be deleted
*/
delete(storeName, key) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readwrite, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
objectStore.delete(key);
transaction.oncomplete = () => {
this.getAll(storeName)
.pipe(take(1))
.subscribe((newValues) => {
resolve(newValues);
});
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Returns true from the store after a successful delete.
* @param storeName The name of the store to have the entry deleted
* @param key The key of the entry to be deleted
*/
deleteByKey(storeName, key) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readwrite, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
transaction.oncomplete = () => {
resolve(true);
};
objectStore.delete(key);
})
.catch((reason) => reject(reason));
}));
}
/**
* Returns true if successfully delete all entries from the store.
* @param storeName The name of the store to have the entries deleted
*/
clear(storeName) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readwrite, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
objectStore.clear();
transaction.oncomplete = () => {
resolve(true);
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Returns true if successfully delete the DB.
*/
deleteDatabase() {
return from(new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
try {
const db = yield openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version);
yield db.close();
const deleteDBRequest = this.indexedDB.deleteDatabase(this.dbConfig.name);
deleteDBRequest.onsuccess = () => {
resolve(true);
};
deleteDBRequest.onerror = reject;
deleteDBRequest.onblocked = () => {
throw new Error(`Unable to delete database because it's blocked`);
};
}
catch (evt) {
reject(evt);
}
})));
}
/**
* Returns the open cursor event
* @param storeName The name of the store to have the entries deleted
* @param keyRange The key range which the cursor should be open on
*/
openCursor(storeName, keyRange) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readonly, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const request = keyRange === undefined ? objectStore.openCursor() : objectStore.openCursor(keyRange);
request.onsuccess = (event) => {
resolve(event);
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Open a cursor by index filter.
* @param storeName The name of the store to query.
* @param indexName The index name to filter.
* @param keyRange The range value and criteria to apply on the index.
*/
openCursorByIndex(storeName, indexName, keyRange, mode = DBMode.readonly) {
const obs = new Subject();
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, (reason) => {
obs.error(reason);
});
const transaction = createTransaction(db, optionsGenerator(mode, storeName, (reason) => {
obs.error(reason);
}, () => {
obs.next();
}));
const objectStore = transaction.objectStore(storeName);
const index = objectStore.index(indexName);
const request = index.openCursor(keyRange);
request.onsuccess = (event) => {
obs.next(event);
};
})
.catch((reason) => obs.error(reason));
return obs;
}
/**
* Returns all items by an index.
* @param storeName The name of the store to query
* @param indexName The index name to filter
* @param keyRange The range value and criteria to apply on the index.
*/
getAllByIndex(storeName, indexName, keyRange) {
const data = [];
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readonly, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const index = objectStore.index(indexName);
const request = index.openCursor(keyRange);
request.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
data.push(cursor.value);
cursor.continue();
}
else {
resolve(data);
}
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Returns all primary keys by an index.
* @param storeName The name of the store to query
* @param indexName The index name to filter
* @param keyRange The range value and criteria to apply on the index.
*/
getAllKeysByIndex(storeName, indexName, keyRange) {
const data = [];
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readonly, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const index = objectStore.index(indexName);
const request = index.openKeyCursor(keyRange);
request.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
data.push({ primaryKey: cursor.primaryKey, key: cursor.key });
cursor.continue();
}
else {
resolve(data);
}
};
})
.catch((reason) => reject(reason));
}));
}
/**
* Returns the number of rows in a store.
* @param storeName The name of the store to query
* @param keyRange The range value and criteria to apply.
*/
count(storeName, keyRange) {
return from(new Promise((resolve, reject) => {
openDatabase(this.indexedDB, this.dbConfig.name, this.dbConfig.version)
.then((db) => {
validateBeforeTransaction(db, storeName, reject);
const transaction = createTransaction(db, optionsGenerator(DBMode.readonly, storeName, reject, resolve));
const objectStore = transaction.objectStore(storeName);
const request = objectStore.count(keyRange);
request.onerror = (e) => reject(e);
request.onsuccess = (e) => resolve(e.target.result);
})
.catch((reason) => reject(reason));
}));
}
}
NgxIndexedDBService.decorators = [
{ type: Injectable }
];
NgxIndexedDBService.ctorParameters = () => [
{ type: undefined, decorators: [{ type: Inject, args: [CONFIG_TOKEN,] }] },
{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
];
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWluZGV4ZWQtZGIuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1pbmRleGVkLWRiL3NyYy9saWIvbmd4LWluZGV4ZWQtZGIuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxZQUFZLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNuRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsZ0JBQWdCLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDMUYsT0FBTyxFQUFFLFlBQVksRUFBZ0QsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDM0csT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDcEQsT0FBTyxFQUFjLElBQUksRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDakQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBR3RDLE1BQU0sT0FBTyxtQkFBbUI7SUFJOUIsWUFBMEMsUUFBa0IsRUFBK0IsVUFBZTtRQUFoRSxhQUFRLEdBQVIsUUFBUSxDQUFVO1FBQStCLGVBQVUsR0FBVixVQUFVLENBQUs7UUFDeEcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUU7WUFDbEIsTUFBTSxJQUFJLEtBQUssQ0FBQywrREFBK0QsQ0FBQyxDQUFDO1NBQ2xGO1FBQ0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUU7WUFDckIsTUFBTSxJQUFJLEtBQUssQ0FBQyxtRUFBbUUsQ0FBQyxDQUFDO1NBQ3RGO1FBQ0QsSUFBSSxDQUFDLFNBQVMsR0FBRyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDcEQsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFO1lBQ2xCLElBQUksQ0FBQyxTQUFTO2dCQUNaLE1BQU0sQ0FBQyxTQUFTO29CQUNmLE1BQWMsQ0FBQyxZQUFZO29CQUMzQixNQUFjLENBQUMsZUFBZTtvQkFDOUIsTUFBYyxDQUFDLFdBQVcsQ0FBQztZQUM5QixpQkFBaUIsQ0FDZixJQUFJLENBQUMsU0FBUyxFQUNkLFFBQVEsQ0FBQyxJQUFJLEVBQ2IsUUFBUSxDQUFDLE9BQU8sRUFDaEIsUUFBUSxDQUFDLGdCQUFnQixFQUN6QixRQUFRLENBQUMsZ0JBQWdCLENBQzFCLENBQUM7U0FDSDtJQUNILENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsaUJBQWlCLENBQ2YsV0FBNEIsRUFDNUIsZ0JBQWtHO1FBRWxHLE1BQU0sWUFBWSxHQUFzQixDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3RELGlCQUFpQixDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxZQUFZLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztJQUNqSCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxHQUFHLENBQUksU0FBaUIsRUFBRSxLQUFRLEVBQUUsR0FBUztRQUMzQyxPQUFPLElBQUksQ0FDVCxJQUFJLE9BQU8sQ0FBUyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUN0QyxZQUFZLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztpQkFDcEUsSUFBSSxDQUFDLENBQUMsRUFBZSxFQUFFLEVBQUU7Z0JBQ3hCLE1BQU0sV0FBVyxHQUFHLGlCQUFpQixDQUFDLEVBQUUsRUFBRSxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDMUcsTUFBTSxXQUFXLEdBQUcsV0FBVyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDdkQsTUFBTSxPQUFPLEdBQTRCLE9BQU8sQ0FBQyxHQUFHLENBQUM7b0JBQ25ELENBQUMsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUM7b0JBQzdCLENBQUMsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUUzQixPQUFPLENBQUMsU0FBUyxHQUFHLENBQUMsR0FBVSxFQUFFLEVBQUU7b0JBQ2pDLE1BQU0sTUFBTSxHQUFJLEdBQUcsQ0FBQyxNQUEyQixDQUFDLE1BQU0sQ0FBQztvQkFDdkQsT0FBTyxDQUFFLE1BQTRCLENBQUMsQ0FBQztnQkFDekMsQ0FBQyxDQUFDO1lBQ0osQ0FBQyxDQUFDO2lCQUNELEtBQUssQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDdkMsQ0FBQyxDQUFDLENBQ0gsQ0FBQztJQUNKLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsT0FBTyxDQUFJLFNBQWlCLEVBQUUsTUFBMkI7UUFDdkQsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQ3BDLE9BQU8sSUFBSSxPQUFPLENBQVMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7Z0JBQzdDLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO3FCQUNwRSxJQUFJLENBQUMsQ0FBQyxFQUFlLEVBQUUsRUFBRTtvQkFDeEIsTUFBTSxXQUFXLEdBQUcsaUJBQWlCLENBQUMsRUFBRSxFQUFFLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO29CQUMxRyxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO29CQUV2RCxNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDO29CQUN0QixPQUFPLEtBQUssQ0FBQyxHQUFHLENBQUM7b0JBRWpCLE1BQU0sT0FBTyxHQUE0QixPQUFPLENBQUMsR0FBRyxDQUFDO3dCQUNuRCxDQUFDLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDO3dCQUM3QixDQUFDLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFFM0IsT0FBTyxDQUFDLFNBQVMsR0FBRyxDQUFDLEdBQVUsRUFBRSxFQUFFO3dCQUNqQyxNQUFNLE1BQU0sR0FBSSxHQUFHLENBQUMsTUFBMkIsQ0FBQyxNQUFNLENBQUM7d0JBQ3ZELE9BQU8sQ0FBRSxNQUE0QixDQUFDLENBQUM7b0JBQ3pDLENBQUMsQ0FBQztnQkFDSixDQUFDLENBQUM7cUJBQ0QsS0FBSyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztZQUN2QyxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxPQUFPLENBQUksU0FBaUIsRUFBRSxLQUFRLEVBQUUsR0FBUztRQUMvQyxPQUFPLElBQUksQ0FDVCxJQUFJLE9BQU8sQ0FBSSxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUNqQyxZQUFZLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztpQkFDcEUsSUFBSSxDQUFDLENBQUMsRUFBZSxFQUFFLEVBQUU7Z0JBQ3hCLE1BQU0sV0FBVyxHQUFHLGlCQUFpQixDQUFDLEVBQUUsRUFBRSxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDMUcsTUFBTSxXQUFXLEdBQUcsV0FBVyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDdkQsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUM1QixNQUFNLE9BQU8sR0FBNEIsTUFBTSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFFdkcsT0FBTyxDQUFDLFNBQVMsR0FBRyxDQUFDLEdBQVUsRUFBRSxFQUFFO29CQUNqQyxNQUFNLE1BQU0sR0FBSSxHQUFHLENBQUMsTUFBMkIsQ0FBQyxNQUFNLENBQUM7b0JBQ3ZELE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBRyxNQUE2QixDQUFDO29CQUMvRCxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRTt3QkFDdkQsT0FBTyxDQUFDLFFBQWEsQ0FBQyxDQUFDO29CQUN6QixDQUFDLENBQUMsQ0FBQztnQkFDTCxDQUFDLENBQUM7WUFDSixDQUFDLENBQUM7aUJBQ0QsS0FBSyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUN2QyxDQUFDLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsY0FBYyxDQUFJLFNBQWlCLEVBQUUsS0FBUSxFQUFFLEdBQWdCO1FBQzdELE9BQU8sSUFBSSxDQUNULElBQUksT0FBTyxDQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ2pDLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO2lCQUNwRSxJQUFJLENBQUMsQ0FBQyxFQUFlLEVBQUUsRUFBRTtnQkFDeEIsTUFBTSxXQUFXLEdBQUcsaUJBQWlCLENBQUMsRUFBRSxFQUFFLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUMxRyxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUV2RCxXQUFXLENBQUMsVUFBVSxHQUFHLEdBQUcsRUFBRTtvQkFDNUIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUU7d0JBQ25ELE9BQU8sQ0FBQyxRQUFhLENBQUMsQ0FBQztvQkFDekIsQ0FBQyxDQUFDLENBQUM7Z0JBQ0wsQ0FBQyxDQUFDO2dCQUVGLFdBQVcsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQzlCLENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILFFBQVEsQ0FBSSxTQUFpQixFQUFFLEdBQWdCO1FBQzdDLE9BQU8sSUFBSSxDQUNULElBQUksT0FBTyxDQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ2pDLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO2lCQUNwRSxJQUFJLENBQUMsQ0FBQyxFQUFlLEVBQUUsRUFBRTtnQkFDeEIsTUFBTSxXQUFXLEdBQUcsaUJBQWlCLENBQUMsRUFBRSxFQUFFLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUN6RyxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUN2RCxNQUFNLE9BQU8sR0FBRyxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBa0IsQ0FBQztnQkFDdEQsT0FBTyxDQUFDLFNBQVMsR0FBRyxDQUFDLEtBQVksRUFBRSxFQUFFO29CQUNuQyxPQUFPLENBQUUsS0FBSyxDQUFDLE1BQXdCLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ2xELENBQUMsQ0FBQztnQkFDRixPQUFPLENBQUMsT0FBTyxHQUFHLENBQUMsS0FBWSxFQUFFLEVBQUU7b0JBQ2pDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDaEIsQ0FBQyxDQUFDO1lBQ0osQ0FBQyxDQUFDO2lCQUNELEtBQUssQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDdkMsQ0FBQyxDQUFDLENBQ0gsQ0FBQztJQUNKLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsT0FBTyxDQUFJLFNBQWlCLEVBQUUsSUFBd0I7UUFDcEQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7UUFDNUUsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE9BQU8sQ0FBSSxTQUFpQixFQUFFLEVBQW1CO1FBQy9DLE9BQU8sSUFBSSxDQUNULElBQUksT0FBTyxDQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ2pDLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO2lCQUNwRSxJQUFJLENBQUMsQ0FBQyxFQUFlLEVBQUUsRUFBRTtnQkFDeEIseUJBQXlCLENBQUMsRUFBRSxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDakQsTUFBTSxXQUFXLEdBQUcsaUJBQWlCLENBQUMsRUFBRSxFQUFFLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUN6RyxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUN2RCxNQUFNLE9BQU8sR0FBZSxXQUFXLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBa0IsQ0FBQztnQkFDakUsT0FBTyxDQUFDLFNBQVMsR0FBRyxDQUFDLEtBQVksRUFBRSxFQUFFO29CQUNuQyxPQUFPLENBQUUsS0FBSyxDQUFDLE1BQXdCLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ2xELENBQUMsQ0FBQztZQUNKLENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxVQUFVLENBQUksU0FBaUIsRUFBRSxTQUFpQixFQUFFLEdBQWdCO1FBQ2xFLE9BQU8sSUFBSSxDQUNULElBQUksT0FBTyxDQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ2pDLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO2lCQUNwRSxJQUFJLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRTtnQkFDWCx5QkFBeUIsQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUNqRCxNQUFNLFdBQVcsR0FBRyxpQkFBaUIsQ0FBQyxFQUFFLEVBQUUsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7Z0JBQ3pHLE1BQU0sV0FBVyxHQUFHLFdBQVcsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3ZELE1BQU0sS0FBSyxHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQzNDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFrQixDQUFDO2dCQUNoRCxPQUFPLENBQUMsU0FBUyxHQUFHLENBQUMsS0FBWSxFQUFFLEVBQUU7b0JBQ25DLE9BQU8sQ0FBRSxLQUFLLENBQUMsTUFBd0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDbEQsQ0FBQyxDQUFDO1lBQ0osQ0FBQyxDQUFDO2lCQUNELEtBQUssQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDdkMsQ0FBQyxDQUFDLENBQ0gsQ0FBQztJQUNKLENBQUM7SUFFRDs7O09BR0c7SUFDSCxNQUFNLENBQUksU0FBaUI7UUFDekIsT0FBTyxJQUFJLENBQ1QsSUFBSSxPQUFPLENBQU0sQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDbkMsWUFBWSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7aUJBQ3BFLElBQUksQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFO2dCQUNYLHlCQUF5QixDQUFDLEVBQUUsRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUM7Z0JBQ2pELE1BQU0sV0FBVyxHQUFHLGlCQUFpQixDQUFDLEVBQUUsRUFBRSxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDekcsTUFBTSxXQUFXLEdBQUcsV0FBVyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFFdkQsTUFBTSxPQUFPLEdBQWUsV0FBVyxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUVqRCxPQUFPLENBQUMsT0FBTyxHQUFHLENBQUMsR0FBVSxFQUFFLEVBQUU7b0JBQy9CLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDZCxDQUFDLENBQUM7Z0JBRUYsT0FBTyxDQUFDLFNBQVMsR0FBRyxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxFQUFtQixFQUFFLEVBQUU7b0JBQ3pFLE9BQU8sQ0FBQyxTQUFnQixDQUFDLENBQUM7Z0JBQzVCLENBQUMsQ0FBQztZQUNKLENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxNQUFNLENBQUksU0FBaUIsRUFBRSxLQUFRLEVBQUUsR0FBUztRQUM5QyxPQUFPLElBQUksQ0FDVCxJQUFJLE9BQU8sQ0FBTSxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUNuQyxZQUFZLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztpQkFDcEUsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUU7Z0JBQ1gseUJBQXlCLENBQUMsRUFBRSxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDakQsTUFBTSxXQUFXLEdBQUcsaUJBQWlCLENBQUMsRUFBRSxFQUFFLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUMxRyxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUV2RCxXQUFXLENBQUMsVUFBVSxHQUFHLEdBQUcsRUFBRTtvQkFDNUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUM7eUJBQ25CLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7eUJBQ2IsU0FBUyxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUU7d0JBQ3ZCLE9BQU8sQ0FBQyxTQUFnQixDQUFDLENBQUM7b0JBQzVCLENBQUMsQ0FBQyxDQUFDO2dCQUNQLENBQUMsQ0FBQztnQkFFRixHQUFHLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzdELENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxXQUFXLENBQUksU0FBaUIsRUFBRSxLQUFRLEVBQUUsR0FBZ0I7UUFDMUQsT0FBTyxJQUFJLENBQ1QsSUFBSSxPQUFPLENBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDakMsWUFBWSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7aUJBQ3BFLElBQUksQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFO2dCQUNYLHlCQUF5QixDQUFDLEVBQUUsRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUM7Z0JBQ2pELE1BQU0sV0FBVyxHQUFHLGlCQUFpQixDQUFDLEVBQUUsRUFBRSxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDMUcsTUFBTSxXQUFXLEdBQUcsV0FBVyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFFdkQsV0FBVyxDQUFDLFVBQVUsR0FBRyxHQUFHLEVBQUU7b0JBQzVCLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFO3dCQUNuRCxPQUFPLENBQUMsUUFBYSxDQUFDLENBQUM7b0JBQ3pCLENBQUMsQ0FBQyxDQUFDO2dCQUNMLENBQUMsQ0FBQztnQkFFRixXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQztZQUM5QixDQUFDLENBQUM7aUJBQ0QsS0FBSyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUN2QyxDQUFDLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxNQUFNLENBQUksU0FBaUIsRUFBRSxHQUFRO1FBQ25DLE9BQU8sSUFBSSxDQUNULElBQUksT0FBTyxDQUFNLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ25DLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO2lCQUNwRSxJQUFJLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRTtnQkFDWCx5QkFBeUIsQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUNqRCxNQUFNLFdBQVcsR0FBRyxpQkFBaUIsQ0FBQyxFQUFFLEVBQUUsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7Z0JBQzFHLE1BQU0sV0FBVyxHQUFHLFdBQVcsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3ZELFdBQVcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBRXhCLFdBQVcsQ0FBQyxVQUFVLEdBQUcsR0FBRyxFQUFFO29CQUM1QixJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQzt5QkFDbkIsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQzt5QkFDYixTQUFTLENBQUMsQ0FBQyxTQUFTLEVBQUUsRUFBRTt3QkFDdkIsT0FBTyxDQUFDLFNBQWdCLENBQUMsQ0FBQztvQkFDNUIsQ0FBQyxDQUFDLENBQUM7Z0JBQ1AsQ0FBQyxDQUFDO1lBQ0osQ0FBQyxDQUFDO2lCQUNELEtBQUssQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDdkMsQ0FBQyxDQUFDLENBQ0gsQ0FBQztJQUNKLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsV0FBVyxDQUFDLFNBQWlCLEVBQUUsR0FBUTtRQUNyQyxPQUFPLElBQUksQ0FDVCxJQUFJLE9BQU8sQ0FBVSxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUN2QyxZQUFZLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztpQkFDcEUsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUU7Z0JBQ1gseUJBQXlCLENBQUMsRUFBRSxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDakQsTUFBTSxXQUFXLEdBQUcsaUJBQWlCLENBQUMsRUFBRSxFQUFFLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUMxRyxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUV2RCxXQUFXLENBQUMsVUFBVSxHQUFHLEdBQUcsRUFBRTtvQkFDNUIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNoQixDQUFDLENBQUM7Z0JBRUYsV0FBVyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMxQixDQUFDLENBQUM7aUJBQ0QsS0FBSyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUN2QyxDQUFDLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxTQUFpQjtRQUNyQixPQUFPLElBQUksQ0FDVCxJQUFJLE9BQU8sQ0FBVSxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUN2QyxZQUFZLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztpQkFDcEUsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUU7Z0JBQ1gseUJBQXlCLENBQUMsRUFBRSxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDakQsTUFBTSxXQUFXLEdBQUcsaUJBQWlCLENBQUMsRUFBRSxFQUFFLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUMxRyxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUN2RCxXQUFXLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ3BCLFdBQVcsQ0FBQyxVQUFVLEdBQUcsR0FBRyxFQUFFO29CQUM1QixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2hCLENBQUMsQ0FBQztZQUNKLENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSCxjQUFjO1FBQ1osT0FBTyxJQUFJLENBQ1QsSUFBSSxPQUFPLENBQVUsQ0FBTyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDN0MsSUFBSTtnQkFDRixNQUFNLEVBQUUsR0FBRyxNQUFNLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3pGLE1BQU0sRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUNqQixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUMxRSxlQUFlLENBQUMsU0FBUyxHQUFHLEdBQUcsRUFBRTtvQkFDL0IsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNoQixDQUFDLENBQUM7Z0JBQ0YsZUFBZSxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7Z0JBQ2pDLGVBQWUsQ0FBQyxTQUFTLEdBQUcsR0FBRyxFQUFFO29CQUMvQixNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7Z0JBQ3BFLENBQUMsQ0FBQzthQUNIO1lBQUMsT0FBTyxHQUFHLEVBQUU7Z0JBQ1osTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQ2I7UUFDSCxDQUFDLENBQUEsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILFVBQVUsQ0FBQyxTQUFpQixFQUFFLFFBQXNCO1FBQ2xELE9BQU8sSUFBSSxDQUNULElBQUksT0FBTyxDQUFRLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ3JDLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO2lCQUNwRSxJQUFJLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRTtnQkFDWCx5QkFBeUIsQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUNqRCxNQUFNLFdBQVcsR0FBRyxpQkFBaUIsQ0FBQyxFQUFFLEVBQUUsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7Z0JBQ3pHLE1BQU0sV0FBVyxHQUFHLFdBQVcsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3ZELE1BQU0sT0FBTyxHQUFHLFFBQVEsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFFckcsT0FBTyxDQUFDLFNBQVMsR0FBRyxDQUFDLEtBQVksRUFBRSxFQUFFO29CQUNuQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ2pCLENBQUMsQ0FBQztZQUNKLENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxpQkFBaUIsQ0FDZixTQUFpQixFQUNqQixTQUFpQixFQUNqQixRQUFxQixFQUNyQixPQUFlLE1BQU0sQ0FBQyxRQUFRO1FBRTlCLE1BQU0sR0FBRyxHQUFHLElBQUksT0FBTyxFQUFTLENBQUM7UUFFakMsWUFBWSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7YUFDcEUsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUU7WUFDWCx5QkFBeUIsQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLENBQUMsTUFBTSxFQUFFLEVBQUU7Z0JBQ2xELEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDcEIsQ0FBQyxDQUFDLENBQUM7WUFDSCxNQUFNLFdBQVcsR0FBRyxpQkFBaUIsQ0FDbkMsRUFBRSxFQUNGLGdCQUFnQixDQUNkLElBQUksRUFDSixTQUFTLEVBQ1QsQ0FBQyxNQUFNLEVBQUUsRUFBRTtnQkFDVCxHQUFHLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3BCLENBQUMsRUFDRCxHQUFHLEVBQUU7Z0JBQ0gsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2IsQ0FBQyxDQUNGLENBQ0YsQ0FBQztZQUNGLE1BQU0sV0FBVyxHQUFHLFdBQVcsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDdkQsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUMzQyxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBRTNDLE9BQU8sQ0FBQyxTQUFTLEdBQUcsQ0FBQyxLQUFZLEVBQUUsRUFBRTtnQkFDbkMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNsQixDQUFDLENBQUM7UUFDSixDQUFDLENBQUM7YUFDRCxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUV4QyxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILGFBQWEsQ0FBSSxTQUFpQixFQUFFLFNBQWlCLEVBQUUsUUFBcUI7UUFDMUUsTUFBTSxJQUFJLEdBQVEsRUFBRSxDQUFDO1FBQ3JCLE9BQU8sSUFBSSxDQUNULElBQUksT0FBTyxDQUFNLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ25DLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO2lCQUNwRSxJQUFJLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRTtnQkFDWCx5QkFBeUIsQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUNqRCxNQUFNLFdBQVcsR0FBRyxpQkFBaUIsQ0FBQyxFQUFFLEVBQUUsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7Z0JBQ3pHLE1BQU0sV0FBVyxHQUFHLFdBQVcsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3ZELE1BQU0sS0FBSyxHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQzNDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzNDLE9BQU8sQ0FBQyxTQUFTLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRTtvQkFDNUIsTUFBTSxNQUFNLEdBQXdCLEtBQUssQ0FBQyxNQUF5QyxDQUFDLE1BQU0sQ0FBQztvQkFDM0YsSUFBSSxNQUFNLEVBQUU7d0JBQ1YsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7d0JBQ3hCLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztxQkFDbkI7eUJBQU07d0JBQ0wsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO3FCQUNmO2dCQUNILENBQUMsQ0FBQztZQUNKLENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxpQkFBaUIsQ0FDZixTQUFpQixFQUNqQixTQUFpQixFQUNqQixRQUFxQjtRQUVyQixNQUFNLElBQUksR0FBb0MsRUFBRSxDQUFDO1FBQ2pELE9BQU8sSUFBSSxDQUNULElBQUksT0FBTyxDQUFrQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUMvRCxZQUFZLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztpQkFDcEUsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUU7Z0JBQ1gseUJBQXlCLENBQUMsRUFBRSxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDakQsTUFBTSxXQUFXLEdBQUcsaUJBQWlCLENBQUMsRUFBRSxFQUFFLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUN6RyxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUN2RCxNQUFNLEtBQUssR0FBRyxXQUFXLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUMzQyxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUM5QyxPQUFPLENBQUMsU0FBUyxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUU7b0JBQzVCLE1BQU0sTUFBTSxHQUFlLEtBQUssQ0FBQyxNQUFnQyxDQUFDLE1BQU0sQ0FBQztvQkFDekUsSUFBSSxNQUFNLEVBQUU7d0JBQ1YsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLENBQUMsVUFBVSxFQUFFLEdBQUcsRUFBRSxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQzt3QkFDOUQsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO3FCQUNuQjt5QkFBTTt3QkFDTCxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7cUJBQ2Y7Z0JBQ0gsQ0FBQyxDQUFDO1lBQ0osQ0FBQyxDQUFDO2lCQUNELEtBQUssQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDdkMsQ0FBQyxDQUFDLENBQ0gsQ0FBQztJQUNKLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLFNBQWlCLEVBQUUsUUFBb0M7UUFDM0QsT0FBTyxJQUFJLENBQ1QsSUFBSSxPQUFPLENBQVMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDdEMsWUFBWSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7aUJBQ3BFLElBQUksQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFO2dCQUNYLHlCQUF5QixDQUFDLEVBQUUsRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUM7Z0JBQ2pELE1BQU0sV0FBVyxHQUFHLGlCQUFpQixDQUFDLEVBQUUsRUFBRSxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDekcsTUFBTSxXQUFXLEdBQUcsV0FBVyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDdkQsTUFBTSxPQUFPLEdBQWUsV0FBVyxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDeEQsT0FBTyxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNuQyxPQUFPLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUcsQ0FBQyxDQUFDLE1BQTJCLENBQUMsTUFBNEIsQ0FBQyxDQUFDO1lBQ25HLENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDOzs7WUFya0JGLFVBQVU7Ozs0Q0FLSSxNQUFNLFNBQUMsWUFBWTs0Q0FBK0IsTUFBTSxTQUFDLFdBQVciLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBJbmplY3QsIFBMQVRGT1JNX0lEIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBvcGVuRGF0YWJhc2UsIENyZWF0ZU9iamVjdFN0b3JlIH0gZnJvbSAnLi9uZ3gtaW5kZXhlZC1kYic7XG5pbXBvcnQgeyBjcmVhdGVUcmFuc2FjdGlvbiwgb3B0aW9uc0dlbmVyYXRvciwgdmFsaWRhdGVCZWZvcmVUcmFuc2FjdGlvbiB9IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7IENPTkZJR19UT0tFTiwgREJDb25maWcsIEtleSwgUmVxdWVzdEV2ZW50LCBPYmplY3RTdG9yZU1ldGEsIERCTW9kZSB9IGZyb20gJy4vbmd4LWluZGV4ZWQtZGIubWV0YSc7XG5pbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBmcm9tLCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyB0YWtlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgTmd4SW5kZXhlZERCU2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgaXNCcm93c2VyOiBib29sZWFuO1xuICBwcml2YXRlIGluZGV4ZWREQjogSURCRmFjdG9yeTtcblxuICBjb25zdHJ1Y3RvcihASW5qZWN0KENPTkZJR19UT0tFTikgcHJpdmF0ZSBkYkNvbmZpZzogREJDb25maWcsIEBJbmplY3QoUExBVEZPUk1fSUQpIHByaXZhdGUgcGxhdGZvcm1JZDogYW55KSB7XG4gICAgaWYgKCFkYkNvbmZpZy5uYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05neEluZGV4ZWREQjogUGxlYXNlLCBwcm92aWRlIHRoZSBkYk5hbWUgaW4gdGhlIGNvbmZpZ3VyYXRpb24nKTtcbiAgICB9XG4gICAgaWYgKCFkYkNvbmZpZy52ZXJzaW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05neEluZGV4ZWREQjogUGxlYXNlLCBwcm92aWRlIHRoZSBkYiB2ZXJzaW9uIGluIHRoZSBjb25maWd1cmF0aW9uJyk7XG4gICAgfVxuICAgIHRoaXMuaXNCcm93c2VyID0gaXNQbGF0Zm9ybUJyb3dzZXIodGhpcy5wbGF0Zm9ybUlkKTtcbiAgICBpZiAodGhpcy5pc0Jyb3dzZXIpIHtcbiAgICAgIHRoaXMuaW5kZXhlZERCID1cbiAgICAgICAgd2luZG93LmluZGV4ZWREQiB8fFxuICAgICAgICAod2luZG93IGFzIGFueSkubW96SW5kZXhlZERCIHx8XG4gICAgICAgICh3aW5kb3cgYXMgYW55KS53ZWJraXRJbmRleGVkREIgfHxcbiAgICAgICAgKHdpbmRvdyBhcyBhbnkpLm1zSW5kZXhlZERCO1xuICAgICAgQ3JlYXRlT2JqZWN0U3RvcmUoXG4gICAgICAgIHRoaXMuaW5kZXhlZERCLFxuICAgICAgICBkYkNvbmZpZy5uYW1lLFxuICAgICAgICBkYkNvbmZpZy52ZXJzaW9uLFxuICAgICAgICBkYkNvbmZpZy5vYmplY3RTdG9yZXNNZXRhLFxuICAgICAgICBkYkNvbmZpZy5taWdyYXRpb25GYWN0b3J5XG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBbGxvd3MgdG8gY3JhdGUgYSBuZXcgb2JqZWN0IHN0b3JlIGFkLWhvY1xuICAgKiBAcGFyYW0gc3RvcmVOYW1lIFRoZSBuYW1lIG9mIHRoZSBzdG9yZSB0byBiZSBjcmVhdGVkXG4gICAqIEBwYXJhbSBtaWdyYXRpb25GYWN0b3J5IFRoZSBtaWdyYXRpb24gZmFjdG9yeSBpZiBleGlzdHNcbiAgICovXG4gIGNyZWF0ZU9iamVjdFN0b3JlKFxuICAgIHN0b3JlU2NoZW1hOiBPYmplY3RTdG9yZU1ldGEsXG4gICAgbWlncmF0aW9uRmFjdG9yeT86ICgpID0+IHsgW2tleTogbnVtYmVyXTogKGRiOiBJREJEYXRhYmFzZSwgdHJhbnNhY3Rpb246IElEQlRyYW5zYWN0aW9uKSA9PiB2b2lkIH1cbiAgKTogdm9pZCB7XG4gICAgY29uc3Qgc3RvcmVTY2hlbWFzOiBPYmplY3RTdG9yZU1ldGFbXSA9IFtzdG9yZVNjaGVtYV07XG4gICAgQ3JlYXRlT2JqZWN0U3RvcmUodGhpcy5pbmRleGVkREIsIHRoaXMuZGJDb25maWcubmFtZSwgKyt0aGlzLmRiQ29uZmlnLnZlcnNpb24sIHN0b3JlU2NoZW1hcywgbWlncmF0aW9uRmFjdG9yeSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBuZXcgZW50cnkgaW4gdGhlIHN0b3JlIGFuZCByZXR1cm5zIGl0cyBrZXlcbiAgICogQHBhcmFtIHN0b3JlTmFtZSBUaGUgbmFtZSBvZiB0aGUgc3RvcmUgdG8gYWRkIHRoZSBpdGVtXG4gICAqIEBwYXJhbSB2YWx1ZSBUaGUgZW50cnkgdG8gYmUgYWRkZWRcbiAgICogQHBhcmFtIGtleSBUaGUgb3B0aW9uYWwga2V5IGZvciB0aGUgZW50cnlcbiAgICovXG4gIGFkZDxUPihzdG9yZU5hbWU6IHN0cmluZywgdmFsdWU6IFQsIGtleT86IGFueSk6IE9ic2VydmFibGU8bnVtYmVyPiB7XG4gICAgcmV0dXJuIGZyb20oXG4gICAgICBuZXcgUHJvbWlzZTxudW1iZXI+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgb3BlbkRhdGFiYXNlKHRoaXMuaW5kZXhlZERCLCB0aGlzLmRiQ29uZmlnLm5hbWUsIHRoaXMuZGJDb25maWcudmVyc2lvbilcbiAgICAgICAgICAudGhlbigoZGI6IElEQkRhdGFiYXNlKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IGNyZWF0ZVRyYW5zYWN0aW9uKGRiLCBvcHRpb25zR2VuZXJhdG9yKERCTW9kZS5yZWFkd3JpdGUsIHN0b3JlTmFtZSwgcmVqZWN0LCByZXNvbHZlKSk7XG4gICAgICAgICAgICBjb25zdCBvYmplY3RTdG9yZSA9IHRyYW5zYWN0aW9uLm9iamVjdFN0b3JlKHN0b3JlTmFtZSk7XG4gICAgICAgICAgICBjb25zdCByZXF1ZXN0OiBJREJSZXF1ZXN0PElEQlZhbGlkS2V5PiA9IEJvb2xlYW4oa2V5KVxuICAgICAgICAgICAgICA/IG9iamVjdFN0b3JlLm