@decaf-ts/db-decorators
Version:
Agnostic database decorators and repository
221 lines (219 loc) • 24.2 kB
JavaScript
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