UNPKG

@decaf-ts/db-decorators

Version:

Agnostic database decorators and repository

221 lines (219 loc) 24.2 kB
import { date, propMetadata, required, sf, type, Validation, } from "@decaf-ts/decorator-validation"; import { DBKeys, DEFAULT_TIMESTAMP_FORMAT } from "../model/constants"; import { DEFAULT_ERROR_MESSAGES } from "./constants"; import { DBOperations, OperationKeys } from "../operations/constants"; import { after, on, onCreateUpdate } from "../operations/decorators"; import { SerializationError } from "../repository/errors"; import { apply, metadata } from "@decaf-ts/reflection"; import { Repository } from "../repository"; /** * Marks the property as readonly. * * @param {string} [message] the error message. Defaults to {@link DEFAULT_ERROR_MESSAGES.READONLY.INVALID} * * @decorator readonly * * @category Decorators */ export function readonly(message = DEFAULT_ERROR_MESSAGES.READONLY.INVALID) { return propMetadata(Validation.updateKey(DBKeys.READONLY), { message: message, }); } export async function timestampHandler(context, data, key, model) { model[key] = context.timestamp; } /** * Marks the property as timestamp. * Makes it {@link required} * Makes it a {@link date} * * Date Format: * * <pre> * Using similar formatting as Moment.js, Class DateTimeFormatter (Java), and Class SimpleDateFormat (Java), * I implemented a comprehensive solution formatDate(date, patternStr) where the code is easy to read and modify. * You can display date, time, AM/PM, etc. * * Date and Time Patterns * yy = 2-digit year; yyyy = full year * M = digit month; MM = 2-digit month; MMM = short month name; MMMM = full month name * EEEE = full weekday name; EEE = short weekday name * d = digit day; dd = 2-digit day * h = hours am/pm; hh = 2-digit hours am/pm; H = hours; HH = 2-digit hours * m = minutes; mm = 2-digit minutes; aaa = AM/PM * s = seconds; ss = 2-digit seconds * S = miliseconds * </pre> * * @param {string[]} operation The {@link DBOperations} to act on. Defaults to {@link DBOperations.CREATE_UPDATE} * @param {string} [format] The TimeStamp format. defaults to {@link DEFAULT_TIMESTAMP_FORMAT} * @param {{new: UpdateValidator}} [validator] defaults to {@link TimestampValidator} * * @decorator timestamp * * @category Decorators */ export function timestamp(operation = DBOperations.CREATE_UPDATE, format = DEFAULT_TIMESTAMP_FORMAT) { const decorators = [ date(format, DEFAULT_ERROR_MESSAGES.TIMESTAMP.DATE), required(DEFAULT_ERROR_MESSAGES.TIMESTAMP.REQUIRED), on(operation, timestampHandler), ]; if (operation.indexOf(OperationKeys.UPDATE) !== -1) decorators.push(propMetadata(Validation.updateKey(DBKeys.TIMESTAMP), { message: DEFAULT_ERROR_MESSAGES.TIMESTAMP.INVALID, })); return apply(...decorators); } export async function serializeOnCreateUpdate(data, key, model, oldModel) { if (!model[key]) return; try { model[key] = JSON.stringify(model[key]); } catch (e) { throw new SerializationError(sf("Failed to serialize {0} property on {1} model: {2}", key, model.constructor.name, e.message)); } } export async function serializeAfterAll(data, key, model) { if (!model[key]) return; if (typeof model[key] !== "string") return; try { model[key] = JSON.parse(model[key]); } catch (e) { throw new SerializationError(sf("Failed to deserialize {0} property on {1} model: {2}", key, model.constructor.name, e.message)); } } /** * @summary Serialize Decorator * @description properties decorated will the serialized before stored in the db * * @function serialize * * @memberOf module:wallet-db.Decorators */ export function serialize() { return apply(onCreateUpdate(serializeOnCreateUpdate), after(DBOperations.ALL, serializeAfterAll), type([String.name, Object.name]), metadata(Repository.key(DBKeys.SERIALIZE), {})); } // // /** // * @summary One To One relation Decorators // * // * @param {Constructor<any>} clazz the {@link Sequence} to use. Defaults to {@link NoneSequence} // * @param {CascadeMetadata} [cascadeOptions] // * @param {boolean} _populate If true, replaces the specified key in the document with the corresponding record from the database // * // * @function onToOne // * // * @memberOf module:wallet-db.Decorators // * // * @see oneToMany // * @see manyToOne // */ // export function oneToOne( // clazz: Constructor<any>, // cascadeOptions: CascadeMetadata = DefaultCascade, // _populate: boolean = true, // ) { // Model.register(clazz); // return (target: any, propertyKey: string) => { // type([clazz.name, String.name])(target, propertyKey); // onCreate(oneToOneOnCreate)(target, propertyKey); // onUpdate(oneToOneOnUpdate, cascadeOptions as any)(target, propertyKey); // onDelete(oneToOneOnDelete, cascadeOptions)(target, propertyKey); // // afterCreate(populate, _populate)(target, propertyKey); // afterUpdate(populate, _populate)(target, propertyKey); // afterRead(populate, _populate)(target, propertyKey); // afterDelete(populate, _populate)(target, propertyKey); // // Reflect.defineMetadata( // getDBKey(WalletDbKeys.ONE_TO_ONE), // { // constructor: clazz.name, // cascade: cascadeOptions, // populate: _populate, // }, // target, // propertyKey, // ); // }; // } // // /** // * @summary One To Many relation Decorators // * // * @param {Constructor<any>} clazz the {@link Sequence} to use. Defaults to {@link NoneSequence} // * @param {CascadeMetadata} [cascadeOptions] // * // * @function onToMany // * // * @memberOf module:wallet-db.Decorators // * // * @see oneToOne // * @see manyToOne // */ // export function oneToMany( // clazz: Constructor<any>, // cascadeOptions: CascadeMetadata = DefaultCascade, // _populate: boolean = true, // ) { // Model.register(clazz); // return (target: any, propertyKey: string) => { // list([clazz, String])(target, propertyKey); // onCreate(oneToManyOnCreate)(target, propertyKey); // onUpdate(oneToManyOnUpdate, cascadeOptions)(target, propertyKey); // onDelete(oneToManyOnDelete, cascadeOptions)(target, propertyKey); // // afterCreate(populate, _populate)(target, propertyKey); // afterUpdate(populate, _populate)(target, propertyKey); // afterRead(populate, _populate)(target, propertyKey); // afterDelete(populate, _populate)(target, propertyKey); // // Reflect.defineMetadata( // getDBKey(WalletDbKeys.ONE_TO_MANY), // { // constructor: clazz.name, // cascade: cascadeOptions, // }, // target, // propertyKey, // ); // }; // } // // /** // * @summary Many To One relation Decorators // * // * @param {Constructor<any>} clazz the {@link Sequence} to use. Defaults to {@link NoneSequence} // * @param {CascadeMetadata} [cascadeOptions] // * // * @function manyToOne // * // * @memberOf module:wallet-db.Decorators // * // * @see oneToMany // * @see oneToOne // */ // export function manyToOne( // clazz: Constructor<any>, // cascadeOptions: CascadeMetadata = DefaultCascade, // ) { // Model.register(clazz); // return (target: any, propertyKey: string) => { // Reflect.defineMetadata( // getDBKey(WalletDbKeys.MANY_TO_ONE), // { // constructor: clazz.name, // cascade: cascadeOptions, // }, // target, // propertyKey, // ); // }; // } //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy92YWxpZGF0aW9uL2RlY29yYXRvcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLElBQUksRUFFSixZQUFZLEVBQ1osUUFBUSxFQUNSLEVBQUUsRUFDRixJQUFJLEVBQ0osVUFBVSxHQUNYLE1BQU0sZ0NBQWdDLENBQUM7QUFDeEMsT0FBTyxFQUFFLE1BQU0sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3RFLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNyRCxPQUFPLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3RFLE9BQU8sRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLGNBQWMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRXJFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzFELE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdkQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUczQzs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sVUFBVSxRQUFRLENBQ3RCLFVBQWtCLHNCQUFzQixDQUFDLFFBQVEsQ0FBQyxPQUFPO0lBRXpELE9BQU8sWUFBWSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxFQUFFO1FBQ3pELE9BQU8sRUFBRSxPQUFPO0tBQ2pCLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxNQUFNLENBQUMsS0FBSyxVQUFVLGdCQUFnQixDQUkzQixPQUFtQixFQUFFLElBQU8sRUFBRSxHQUFXLEVBQUUsS0FBUTtJQUMzRCxLQUFhLENBQUMsR0FBRyxDQUFDLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQztBQUMxQyxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQThCRztBQUNILE1BQU0s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RywrQ0FBK0M7QUFDL0MsS0FBSztBQUNMLHlCQUF5QjtBQUN6QixLQUFLO0FBQ0wsMkNBQTJDO0FBQzNDLEtBQUs7QUFDTCxvQkFBb0I7QUFDcEIsbUJBQW1CO0FBQ25CLE1BQU07QUFDTiw2QkFBNkI7QUFDN0IsNkJBQTZCO0FBQzdCLHNEQUFzRDtBQUN0RCxNQUFNO0FBQ04sMkJBQTJCO0FBQzNCLG1EQUFtRDtBQUNuRCw4QkFBOEI7QUFDOUIsNENBQTRDO0FBQzVDLFVBQVU7QUFDVixtQ0FBbUM7QUFDbkMsbUNBQW1DO0FBQ25DLFdBQVc7QUFDWCxnQkFBZ0I7QUFDaEIscUJBQXFCO0FBQ3JCLFNBQVM7QUFDVCxPQUFPO0FBQ1AsSUFBSSIsImZpbGUiOiJ2YWxpZGF0aW9uL2RlY29yYXRvcnMuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBkYXRlLFxuICBNb2RlbCxcbiAgcHJvcE1ldGFkYXRhLFxuICByZXF1aXJlZCxcbiAgc2YsXG4gIHR5cGUsXG4gIFZhbGlkYXRpb24sXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IERCS2V5cywgREVGQVVMVF9USU1FU1RBTVBfRk9STUFUIH0gZnJvbSBcIi4uL21vZGVsL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgREVGQVVMVF9FUlJPUl9NRVNTQUdFUyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgREJPcGVyYXRpb25zLCBPcGVyYXRpb25LZXlzIH0gZnJvbSBcIi4uL29wZXJhdGlvbnMvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBhZnRlciwgb24sIG9uQ3JlYXRlVXBkYXRlIH0gZnJvbSBcIi4uL29wZXJhdGlvbnMvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgSVJlcG9zaXRvcnkgfSBmcm9tIFwiLi4vaW50ZXJmYWNlcy9JUmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgU2VyaWFsaXphdGlvbkVycm9yIH0gZnJvbSBcIi4uL3JlcG9zaXRvcnkvZXJyb3JzXCI7XG5pbXBvcnQgeyBhcHBseSwgbWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL3JlZmxlY3Rpb25cIjtcbmltcG9ydCB7IFJlcG9zaXRvcnkgfSBmcm9tIFwiLi4vcmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgQ29udGV4dCB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L0NvbnRleHRcIjtcblxuLyoqXG4gKiBNYXJrcyB0aGUgcHJvcGVydHkgYXMgcmVhZG9ubHkuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IFttZXNzYWdlXSB0aGUgZXJyb3IgbWVzc2FnZS4gRGVmYXVsdHMgdG8ge0BsaW5rIERFRkFVTFRfRVJST1JfTUVTU0FHRVMuUkVBRE9OTFkuSU5WQUxJRH1cbiAqXG4gKiBAZGVjb3JhdG9yIHJlYWRvbmx5XG4gKlxuICogQGNhdGVnb3J5IERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlYWRvbmx5KFxuICBtZXNzYWdlOiBzdHJpbmcgPSBERUZBVUxUX0VSUk9SX01FU1NBR0VTLlJFQURPTkxZLklOVkFMSURcbikge1xuICByZXR1cm4gcHJvcE1ldGFkYXRhKFZhbGlkYXRpb24udXBkYXRlS2V5KERCS2V5cy5SRUFET05MWSksIHtcbiAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICB9KTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRpbWVzdGFtcEhhbmRsZXI8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgViBleHRlbmRzIElSZXBvc2l0b3J5PE0+LFxuICBZID0gYW55LFxuPih0aGlzOiBWLCBjb250ZXh0OiBDb250ZXh0PE0+LCBkYXRhOiBZLCBrZXk6IHN0cmluZywgbW9kZWw6IE0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgKG1vZGVsIGFzIGFueSlba2V5XSA9IGNvbnRleHQudGltZXN0YW1wO1xufVxuXG4vKipcbiAqIE1hcmtzIHRoZSBwcm9wZXJ0eSBhcyB0aW1lc3RhbXAuXG4gKiBNYWtlcyBpdCB7QGxpbmsgcmVxdWlyZWR9XG4gKiBNYWtlcyBpdCBhIHtAbGluayBkYXRlfVxuICpcbiAqIERhdGUgRm9ybWF0OlxuICpcbiAqIDxwcmU+XG4gKiAgICAgIFVzaW5nIHNpbWlsYXIgZm9ybWF0dGluZyBhcyBNb21lbnQuanMsIENsYXNzIERhdGVUaW1lRm9ybWF0dGVyIChKYXZhKSwgYW5kIENsYXNzIFNpbXBsZURhdGVGb3JtYXQgKEphdmEpLFxuICogICAgICBJIGltcGxlbWVudGVkIGEgY29tcHJlaGVuc2l2ZSBzb2x1dGlvbiBmb3JtYXREYXRlKGRhdGUsIHBhdHRlcm5TdHIpIHdoZXJlIHRoZSBjb2RlIGlzIGVhc3kgdG8gcmVhZCBhbmQgbW9kaWZ5LlxuICogICAgICBZb3UgY2FuIGRpc3BsYXkgZGF0ZSwgdGltZSwgQU0vUE0sIGV0Yy5cbiAqXG4gKiAgICAgIERhdGUgYW5kIFRpbWUgUGF0dGVybnNcbiAqICAgICAgeXkgPSAyLWRpZ2l0IHllYXI7IHl5eXkgPSBmdWxsIHllYXJcbiAqICAgICAgTSA9IGRpZ2l0IG1vbnRoOyBNTSA9IDItZGlnaXQgbW9udGg7IE1NTSA9IHNob3J0IG1vbnRoIG5hbWU7IE1NTU0gPSBmdWxsIG1vbnRoIG5hbWVcbiAqICAgICAgRUVFRSA9IGZ1bGwgd2Vla2RheSBuYW1lOyBFRUUgPSBzaG9ydCB3ZWVrZGF5IG5hbWVcbiAqICAgICAgZCA9IGRpZ2l0IGRheTsgZGQgPSAyLWRpZ2l0IGRheVxuICogICAgICBoID0gaG91cnMgYW0vcG07IGhoID0gMi1kaWdpdCBob3VycyBhbS9wbTsgSCA9IGhvdXJzOyBISCA9IDItZGlnaXQgaG91cnNcbiAqICAgICAgbSA9IG1pbnV0ZXM7IG1tID0gMi1kaWdpdCBtaW51dGVzOyBhYWEgPSBBTS9QTVxuICogICAgICBzID0gc2Vjb25kczsgc3MgPSAyLWRpZ2l0IHNlY29uZHNcbiAqICAgICAgUyA9IG1pbGlzZWNvbmRzXG4gKiA8L3ByZT5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBvcGVyYXRpb24gVGhlIHtAbGluayBEQk9wZXJhdGlvbnN9IHRvIGFjdCBvbi4gRGVmYXVsdHMgdG8ge0BsaW5rIERCT3BlcmF0aW9ucy5DUkVBVEVfVVBEQVRFfVxuICogQHBhcmFtIHtzdHJpbmd9IFtmb3JtYXRdIFRoZSBUaW1lU3RhbXAgZm9ybWF0LiBkZWZhdWx0cyB0byB7QGxpbmsgREVGQVVMVF9USU1FU1RBTVBfRk9STUFUfVxuICogQHBhcmFtIHt7bmV3OiBVcGRhdGVWYWxpZGF0b3J9fSBbdmFsaWRhdG9yXSBkZWZhdWx0cyB0byB7QGxpbmsgVGltZXN0YW1wVmFsaWRhdG9yfVxuICpcbiAqIEBkZWNvcmF0b3IgdGltZXN0YW1wXG4gKlxuICogQGNhdGVnb3J5IERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRpbWVzdGFtcChcbiAgb3BlcmF0aW9uOiBPcGVyYXRpb25LZXlzW10gPSBEQk9wZXJhdGlvbnMuQ1JFQVRFX1VQREFURSBhcyB1bmtub3duIGFzIE9wZXJhdGlvbktleXNbXSxcbiAgZm9ybWF0OiBzdHJpbmcgPSBERUZBVUxUX1RJTUVTVEFNUF9GT1JNQVRcbikge1xuICBjb25zdCBkZWNvcmF0b3JzOiBhbnlbXSA9IFtcbiAgICBkYXRlKGZvcm1hdCwgREVGQVVMVF9FUlJPUl9NRVNTQUdFUy5USU1FU1RBTVAuREFURSksXG4gICAgcmVxdWlyZWQoREVGQVVMVF9FUlJPUl9NRVNTQUdFUy5USU1FU1RBTVAuUkVRVUlSRUQpLFxuICAgIG9uKG9wZXJhdGlvbiwgdGltZXN0YW1wSGFuZGxlciksXG4gIF07XG5cbiAgaWYgKG9wZXJhdGlvbi5pbmRleE9mKE9wZXJhdGlvbktleXMuVVBEQVRFKSAhPT0gLTEpXG4gICAgZGVjb3JhdG9ycy5wdXNoKFxuICAgICAgcHJvcE1ldGFkYXRhKFZhbGlkYXRpb24udXBkYXRlS2V5KERCS2V5cy5USU1FU1RBTVApLCB7XG4gICAgICAgIG1lc3NhZ2U6IERFRkFVTFRfRVJST1JfTUVTU0FHRVMuVElNRVNUQU1QLklOVkFMSUQsXG4gICAgICB9KVxuICAgICk7XG5cbiAgcmV0dXJuIGFwcGx5KC4uLmRlY29yYXRvcnMpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2VyaWFsaXplT25DcmVhdGVVcGRhdGU8XG4gIFQgZXh0ZW5kcyBNb2RlbCxcbiAgViBleHRlbmRzIElSZXBvc2l0b3J5PFQ+LFxuICBZID0gYW55LFxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4+KHRoaXM6IFYsIGRhdGE6IFksIGtleTogc3RyaW5nLCBtb2RlbDogVCwgb2xkTW9kZWw6IFQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKCEobW9kZWwgYXMgYW55KVtrZXldKSByZXR1cm47XG4gIHRyeSB7XG4gICAgKG1vZGVsIGFzIGFueSlba2V5XSA9IEpTT04uc3RyaW5naWZ5KChtb2RlbCBhcyBhbnkpW2tleV0pO1xuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICB0aHJvdyBuZXcgU2VyaWFsaXphdGlvbkVycm9yKFxuICAgICAgc2YoXG4gICAgICAgIFwiRmFpbGVkIHRvIHNlcmlhbGl6ZSB7MH0gcHJvcGVydHkgb24gezF9IG1vZGVsOiB7Mn1cIixcbiAgICAgICAga2V5LFxuICAgICAgICBtb2RlbC5jb25zdHJ1Y3Rvci5uYW1lLFxuICAgICAgICBlLm1lc3NhZ2VcbiAgICAgIClcbiAgICApO1xuICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZXJpYWxpemVBZnRlckFsbDxcbiAgVCBleHRlbmRzIE1vZGVsLFxuICBWIGV4dGVuZHMgSVJlcG9zaXRvcnk8VD4sXG4gIFkgPSBhbnksXG4+KHRoaXM6IFYsIGRhdGE6IFksIGtleTogc3RyaW5nLCBtb2RlbDogVCk6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoIShtb2RlbCBhcyBhbnkpW2tleV0pIHJldHVybjtcbiAgaWYgKHR5cGVvZiAobW9kZWwgYXMgYW55KVtrZXldICE9PSBcInN0cmluZ1wiKSByZXR1cm47XG5cbiAgdHJ5IHtcbiAgICAobW9kZWwgYXMgYW55KVtrZXldID0gSlNPTi5wYXJzZSgobW9kZWwgYXMgYW55KVtrZXldKTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgdGhyb3cgbmV3IFNlcmlhbGl6YXRpb25FcnJvcihcbiAgICAgIHNmKFxuICAgICAgICBcIkZhaWxlZCB0byBkZXNlcmlhbGl6ZSB7MH0gcHJvcGVydHkgb24gezF9IG1vZGVsOiB7Mn1cIixcbiAgICAgICAga2V5LFxuICAgICAgICBtb2RlbC5jb25zdHJ1Y3Rvci5uYW1lLFxuICAgICAgICBlLm1lc3NhZ2VcbiAgICAgIClcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogQHN1bW1hcnkgU2VyaWFsaXplIERlY29yYXRvclxuICogQGRlc2NyaXB0aW9uIHByb3BlcnRpZXMgZGVjb3JhdGVkIHdpbGwgdGhlIHNlcmlhbGl6ZWQgYmVmb3JlIHN0b3JlZCBpbiB0aGUgZGJcbiAqXG4gKiBAZnVuY3Rpb24gc2VyaWFsaXplXG4gKlxuICogQG1lbWJlck9mIG1vZHVsZTp3YWxsZXQtZGIuRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gc2VyaWFsaXplKCkge1xuICByZXR1cm4gYXBwbHkoXG4gICAgb25DcmVhdGVVcGRhdGUoc2VyaWFsaXplT25DcmVhdGVVcGRhdGUpLFxuICAgIGFmdGVyKERCT3BlcmF0aW9ucy5BTEwsIHNlcmlhbGl6ZUFmdGVyQWxsKSxcbiAgICB0eXBlKFtTdHJpbmcubmFtZSwgT2JqZWN0Lm5hbWVdKSxcbiAgICBtZXRhZGF0YShSZXBvc2l0b3J5LmtleShEQktleXMuU0VSSUFMSVpFKSwge30pXG4gICk7XG59XG5cbi8vXG4vLyAvKipcbi8vICAqIEBzdW1tYXJ5IE9uZSBUbyBPbmUgcmVsYXRpb24gRGVjb3JhdG9yc1xuLy8gICpcbi8vICAqIEBwYXJhbSB7Q29uc3RydWN0b3I8YW55Pn0gY2xhenogdGhlIHtAbGluayBTZXF1ZW5jZX0gdG8gdXNlLiBEZWZhdWx0cyB0byB7QGxpbmsgTm9uZVNlcXVlbmNlfVxuLy8gICogQHBhcmFtIHtDYXNjYWRlTWV0YWRhdGF9IFtjYXNjYWRlT3B0aW9uc11cbi8vICAqIEBwYXJhbSB7Ym9vbGVhbn0gX3BvcHVsYXRlIElmIHRydWUsIHJlcGxhY2VzIHRoZSBzcGVjaWZpZWQga2V5IGluIHRoZSBkb2N1bWVudCB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIHJlY29yZCBmcm9tIHRoZSBkYXRhYmFzZVxuLy8gICpcbi8vICAqIEBmdW5jdGlvbiBvblRvT25lXG4vLyAgKlxuLy8gICogQG1lbWJlck9mIG1vZHVsZTp3YWxsZXQtZGIuRGVjb3JhdG9yc1xuLy8gICpcbi8vICAqIEBzZWUgb25lVG9NYW55XG4vLyAgKiBAc2VlIG1hbnlUb09uZVxuLy8gICovXG4vLyBleHBvcnQgZnVuY3Rpb24gb25lVG9PbmUoXG4vLyAgIGNsYXp6OiBDb25zdHJ1Y3Rvcjxhbnk+LFxuLy8gICBjYXNjYWRlT3B0aW9uczogQ2FzY2FkZU1ldGFkYXRhID0gRGVmYXVsdENhc2NhZGUsXG4vLyAgIF9wb3B1bGF0ZTogYm9vbGVhbiA9IHRydWUsXG4vLyApIHtcbi8vICAgTW9kZWwucmVnaXN0ZXIoY2xhenopO1xuLy8gICByZXR1cm4gKHRhcmdldDogYW55LCBwcm9wZXJ0eUtleTogc3RyaW5nKSA9PiB7XG4vLyAgICAgdHlwZShbY2xhenoubmFtZSwgU3RyaW5nLm5hbWVdKSh0YXJnZXQsIHByb3BlcnR5S2V5KTtcbi8vICAgICBvbkNyZWF0ZShvbmVUb09uZU9uQ3JlYXRlKSh0YXJnZXQsIHByb3BlcnR5S2V5KTtcbi8vICAgICBvblVwZGF0ZShvbmVUb09uZU9uVXBkYXRlLCBjYXNjYWRlT3B0aW9ucyBhcyBhbnkpKHRhcmdldCwgcHJvcGVydHlLZXkpO1xuLy8gICAgIG9uRGVsZXRlKG9uZVRvT25lT25EZWxldGUsIGNhc2NhZGVPcHRpb25zKSh0YXJnZXQsIHByb3BlcnR5S2V5KTtcbi8vXG4vLyAgICAgYWZ0ZXJDcmVhdGUocG9wdWxhdGUsIF9wb3B1bGF0ZSkodGFyZ2V0LCBwcm9wZXJ0eUtleSk7XG4vLyAgICAgYWZ0ZXJVcGRhdGUocG9wdWxhdGUsIF9wb3B1bGF0ZSkodGFyZ2V0LCBwcm9wZXJ0eUtleSk7XG4vLyAgICAgYWZ0ZXJSZWFkKHBvcHVsYXRlLCBfcG9wdWxhdGUpKHRhcmdldCwgcHJvcGVydHlLZXkpO1xuLy8gICAgIGFmdGVyRGVsZXRlKHBvcHVsYXRlLCBfcG9wdWxhdGUpKHRhcmdldCwgcHJvcGVydHlLZXkpO1xuLy9cbi8vICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKFxuLy8gICAgICAgZ2V0REJLZXkoV2FsbGV0RGJLZXlzLk9ORV9UT19PTkUpLFxuLy8gICAgICAge1xuLy8gICAgICAgICBjb25zdHJ1Y3RvcjogY2xhenoubmFtZSxcbi8vICAgICAgICAgY2FzY2FkZTogY2FzY2FkZU9wdGlvbnMsXG4vLyAgICAgICAgIHBvcHVsYXRlOiBfcG9wdWxhdGUsXG4vLyAgICAgICB9LFxuLy8gICAgICAgdGFyZ2V0LFxuLy8gICAgICAgcHJvcGVydHlLZXksXG4vLyAgICAgKTtcbi8vICAgfTtcbi8vIH1cbi8vXG4vLyAvKipcbi8vICAqIEBzdW1tYXJ5IE9uZSBUbyBNYW55IHJlbGF0aW9uIERlY29yYXRvcnNcbi8vICAqXG4vLyAgKiBAcGFyYW0ge0NvbnN0cnVjdG9yPGFueT59IGNsYXp6IHRoZSB7QGxpbmsgU2VxdWVuY2V9IHRvIHVzZS4gRGVmYXVsdHMgdG8ge0BsaW5rIE5vbmVTZXF1ZW5jZX1cbi8vICAqIEBwYXJhbSB7Q2FzY2FkZU1ldGFkYXRhfSBbY2FzY2FkZU9wdGlvbnNdXG4vLyAgKlxuLy8gICogQGZ1bmN0aW9uIG9uVG9NYW55XG4vLyAgKlxuLy8gICogQG1lbWJlck9mIG1vZHVsZTp3YWxsZXQtZGIuRGVjb3JhdG9yc1xuLy8gICpcbi8vICAqIEBzZWUgb25lVG9PbmVcbi8vICAqIEBzZWUgbWFueVRvT25lXG4vLyAgKi9cbi8vIGV4cG9ydCBmdW5jdGlvbiBvbmVUb01hbnkoXG4vLyAgIGNsYXp6OiBDb25zdHJ1Y3Rvcjxhbnk+LFxuLy8gICBjYXNjYWRlT3B0aW9uczogQ2FzY2FkZU1ldGFkYXRhID0gRGVmYXVsdENhc2NhZGUsXG4vLyAgIF9wb3B1bGF0ZTogYm9vbGVhbiA9IHRydWUsXG4vLyApIHtcbi8vICAgTW9kZWwucmVnaXN0ZXIoY2xhenopO1xuLy8gICByZXR1cm4gKHRhcmdldDogYW55LCBwcm9wZXJ0eUtleTogc3RyaW5nKSA9PiB7XG4vLyAgICAgbGlzdChbY2xhenosIFN0cmluZ10pKHRhcmdldCwgcHJvcGVydHlLZXkpO1xuLy8gICAgIG9uQ3JlYXRlKG9uZVRvTWFueU9uQ3JlYXRlKSh0YXJnZXQsIHByb3BlcnR5S2V5KTtcbi8vICAgICBvblVwZGF0ZShvbmVUb01hbnlPblVwZGF0ZSwgY2FzY2FkZU9wdGlvbnMpKHRhcmdldCwgcHJvcGVydHlLZXkpO1xuLy8gICAgIG9uRGVsZXRlKG9uZVRvTWFueU9uRGVsZXRlLCBjYXNjYWRlT3B0aW9ucykodGFyZ2V0LCBwcm9wZXJ0eUtleSk7XG4vL1xuLy8gICAgIGFmdGVyQ3JlYXRlKHBvcHVsYXRlLCBfcG9wdWxhdGUpKHRhcmdldCwgcHJvcGVydHlLZXkpO1xuLy8gICAgIGFmdGVyVXBkYXRlKHBvcHVsYXRlLCBfcG9wdWxhdGUpKHRhcmdldCwgcHJvcGVydHlLZXkpO1xuLy8gICAgIGFmdGVyUmVhZChwb3B1bGF0ZSwgX3BvcHVsYXRlKSh0YXJnZXQsIHByb3BlcnR5S2V5KTtcbi8vICAgICBhZnRlckRlbGV0ZShwb3B1bGF0ZSwgX3BvcHVsYXRlKSh0YXJnZXQsIHByb3BlcnR5S2V5KTtcbi8vXG4vLyAgICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShcbi8vICAgICAgIGdldERCS2V5KFdhbGxldERiS2V5cy5PTkVfVE9fTUFOWSksXG4vLyAgICAgICB7XG4vLyAgICAgICAgIGNvbnN0cnVjdG9yOiBjbGF6ei5uYW1lLFxuLy8gICAgICAgICBjYXNjYWRlOiBjYXNjYWRlT3B0aW9ucyxcbi8vICAgICAgIH0sXG4vLyAgICAgICB0YXJnZXQsXG4vLyAgICAgICBwcm9wZXJ0eUtleSxcbi8vICAgICApO1xuLy8gICB9O1xuLy8gfVxuLy9cbi8vIC8qKlxuLy8gICogQHN1bW1hcnkgTWFueSBUbyBPbmUgcmVsYXRpb24gRGVjb3JhdG9yc1xuLy8gICpcbi8vICAqIEBwYXJhbSB7Q29uc3RydWN0b3I8YW55Pn0gY2xhenogdGhlIHtAbGluayBTZXF1ZW5jZX0gdG8gdXNlLiBEZWZhdWx0cyB0byB7QGxpbmsgTm9uZVNlcXVlbmNlfVxuLy8gICogQHBhcmFtIHtDYXNjYWRlTWV0YWRhdGF9IFtjYXNjYWRlT3B0aW9uc11cbi8vICAqXG4vLyAgKiBAZnVuY3Rpb24gbWFueVRvT25lXG4vLyAgKlxuLy8gICogQG1lbWJlck9mIG1vZHVsZTp3YWxsZXQtZGIuRGVjb3JhdG9yc1xuLy8gICpcbi8vICAqIEBzZWUgb25lVG9NYW55XG4vLyAgKiBAc2VlIG9uZVRvT25lXG4vLyAgKi9cbi8vIGV4cG9ydCBmdW5jdGlvbiBtYW55VG9PbmUoXG4vLyAgIGNsYXp6OiBDb25zdHJ1Y3Rvcjxhbnk+LFxuLy8gICBjYXNjYWRlT3B0aW9uczogQ2FzY2FkZU1ldGFkYXRhID0gRGVmYXVsdENhc2NhZGUsXG4vLyApIHtcbi8vICAgTW9kZWwucmVnaXN0ZXIoY2xhenopO1xuLy8gICByZXR1cm4gKHRhcmdldDogYW55LCBwcm9wZXJ0eUtleTogc3RyaW5nKSA9PiB7XG4vLyAgICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShcbi8vICAgICAgIGdldERCS2V5KFdhbGxldERiS2V5cy5NQU5ZX1RPX09ORSksXG4vLyAgICAgICB7XG4vLyAgICAgICAgIGNvbnN0cnVjdG9yOiBjbGF6ei5uYW1lLFxuLy8gICAgICAgICBjYXNjYWRlOiBjYXNjYWRlT3B0aW9ucyxcbi8vICAgICAgIH0sXG4vLyAgICAgICB0YXJnZXQsXG4vLyAgICAgICBwcm9wZXJ0eUtleSxcbi8vICAgICApO1xuLy8gICB9O1xuLy8gfVxuIl19