UNPKG

@energica-city/shared-amplify-utils

Version:

Shared utilities for AWS Amplify projects

283 lines 32.8 kB
import { logger } from '../log'; /** * Generic middleware chain implementation * * Provides Express-style middleware functionality for AWS Lambda handlers and GraphQL resolvers. * Middleware executes in an "onion model" where each middleware wraps the next one in the chain. * * **Execution Flow:** * ``` * Middleware 1 (before) → * Middleware 2 (before) → * Final Handler → * Middleware 2 (after) ← * Middleware 1 (after) ← * ``` * * **Input Mutation:** * - Middleware can mutate the input object directly * - Changes are visible to all subsequent middleware and the final handler * - Consider input immutability for complex applications * * **Error Handling:** * - Errors thrown by middleware are enhanced with chain context * - Execution stops at the first error (no subsequent middleware execute) * - Configure `onError` handler for centralized error processing * * **Performance:** * - Each execution creates a closure chain - consider reusing chains for high-frequency operations * - Debug logging adds overhead - disable in production * * @template TInput - Type of input data passed through the chain * @template TOutput - Type of output returned by the chain * * @example * ```typescript * const chain = new MiddlewareChain<MyInput, MyOutput>({ * enableDebugLogging: true, * onError: (error, middlewareName) => { * console.error(`Middleware ${middlewareName} failed:`, error); * } * }); * * chain * .use('auth', authMiddleware) * .use('logging', loggingMiddleware) * .use('validation', validationMiddleware); * * const result = await chain.execute(input, finalHandler); * ``` */ export class MiddlewareChain { middlewares = []; config; constructor(config = {}) { this.config = config; } /** * Create a middleware chain specifically for AWS Lambda handlers * * This is a convenience method that creates a chain with the standard * Lambda input structure: `{ event: TEvent; context: TContext }` * * @template TEvent - Type of the Lambda event * @template TContext - Type of the Lambda context * @template TReturn - Type of the Lambda return value * @param config - Configuration options for the chain * @returns A new middleware chain configured for Lambda handlers * * @example * ```typescript * const chain = MiddlewareChain.createLambdaChain<APIGatewayProxyEvent, Context, APIGatewayProxyResult>(); * ``` */ static createLambdaChain(config = {}) { return new MiddlewareChain(config); } /** * Create a middleware chain specifically for GraphQL resolvers * * This is a convenience method that creates a chain with the standard * GraphQL resolver input structure: `{ source, args, context, info }` * * @template TArgs - Type of the GraphQL arguments * @template TSource - Type of the GraphQL source * @template TReturn - Type of the GraphQL return value * @param config - Configuration options for the chain * @returns A new middleware chain configured for GraphQL resolvers * * @example * ```typescript * const chain = MiddlewareChain.createGraphQLChain<MyArgs, MySource, MyReturn>(); * ``` */ static createGraphQLChain(config = {}) { return new MiddlewareChain(config); } /** * Add middleware to the chain * * Middleware functions are executed in the order they are added. * Each middleware receives the input and a `next` function to continue * to the next middleware or final handler. * * @param name - Descriptive name for the middleware (used in error messages and logging) * @param middleware - The middleware function to add * @returns This chain instance for method chaining * * @example * ```typescript * chain * .use('authentication', authMiddleware) * .use('logging', loggingMiddleware) * .use('validation', validationMiddleware); * ``` */ use(name, middleware) { this.middlewares.push({ name, middleware }); return this; } /** * Execute the middleware chain with the given input and final handler * * This method runs all middleware in the chain, followed by the final handler. * If any middleware throws an error, execution stops and the error is enhanced * with chain context before being re-thrown. * * @param input - The input data to pass through the middleware chain * @param finalHandler - The final handler function that processes the input * @returns Promise resolving to the output from the final handler * * @example * ```typescript * const result = await chain.execute( * { userId: '123', data: { name: 'John' } }, * async (input) => { * return await fetchUserData(input.userId); * } * ); * ``` */ async execute(input, finalHandler) { if (this.middlewares.length === 0) { return finalHandler(input); } let index = 0; const executeNext = async (modifiedInput) => { if (index >= this.middlewares.length) { return finalHandler(modifiedInput ?? input); } const { name, middleware } = this.middlewares[index]; index++; if (this.config.enableDebugLogging) { logger.debug(`Executing middleware: ${name}`); } try { return await middleware(modifiedInput ?? input, executeNext); } catch (error) { // Create enhanced error with chain context const enhancedError = error instanceof Error ? error : new Error(String(error)); // Add middleware context without mutating original error if (!enhancedError.middlewareName) { enhancedError.middlewareName = name; enhancedError.middlewareIndex = index - 1; enhancedError.totalMiddlewares = this.middlewares.length; enhancedError.middlewareChain = this.middlewares.map(m => m.name); // Store original error if we created a new Error object if (!(error instanceof Error)) { enhancedError.originalError = error; } } if (this.config.onError) { this.config.onError(enhancedError, name); } throw enhancedError; } }; return executeNext(); } /** * Get the number of middlewares in the chain * * @returns The count of middleware functions currently in the chain * * @example * ```typescript * const chain = new MiddlewareChain(); * console.log(chain.length); // 0 * * chain.use('auth', authMiddleware); * chain.use('logging', loggingMiddleware); * console.log(chain.length); // 2 * ``` */ get length() { return this.middlewares.length; } /** * Clear all middlewares from the chain * * Removes all middleware functions, resetting the chain to empty state. * Useful for reusing chain instances or cleaning up during testing. * * @returns This chain instance for method chaining * * @example * ```typescript * const chain = new MiddlewareChain(); * chain.use('auth', authMiddleware); * chain.use('logging', loggingMiddleware); * * chain.clear(); // Chain is now empty * console.log(chain.length); // 0 * ``` */ clear() { this.middlewares = []; return this; } } /** * Wrap a Lambda handler with middleware chain functionality * * This function creates a new Lambda handler that executes the middleware chain * before calling the original handler. The middleware chain receives the Lambda * event and context as input. * * @template TEvent - Type of the Lambda event * @template TContext - Type of the Lambda context * @template TReturn - Type of the Lambda return value * @param chain - The middleware chain to execute * @param handler - The original Lambda handler function * @returns A new Lambda handler function that includes middleware execution * * @example * ```typescript * const wrappedHandler = wrapLambdaHandler( * chain, * async (event, context) => { * return { statusCode: 200, body: 'Hello World' }; * } * ); * ``` */ export function wrapLambdaHandler(chain, handler) { return async (event, context) => { return await chain.execute({ event, context }, async (input) => { return await handler(input.event, input.context); }); }; } /** * Wrap a GraphQL resolver with middleware chain functionality * * This function creates a new GraphQL resolver that executes the middleware chain * before calling the original resolver. The middleware chain receives the GraphQL * source, args, context, and info as input. * * @template TArgs - Type of the GraphQL arguments * @template TSource - Type of the GraphQL source * @template TReturn - Type of the GraphQL return value * @param chain - The middleware chain to execute * @param resolver - The original GraphQL resolver function * @returns A new GraphQL resolver function that includes middleware execution * * @example * ```typescript * const wrappedResolver = wrapGraphQLResolver( * chain, * async (source, args, context, info) => { * return await fetchUserData(args.id); * } * ); * ``` */ export function wrapGraphQLResolver(chain, resolver) { return async (source, args, context, info) => { return await chain.execute({ source, args, context, info }, async (input) => { return await resolver(input.source, input.args, input.context, input.info); }); }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZUNoYWluLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vbWlkZGxld2FyZS9taWRkbGV3YXJlQ2hhaW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFFBQVEsQ0FBQztBQTBEaEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWdERztBQUNILE1BQU0sT0FBTyxlQUFlO0lBQ2xCLFdBQVcsR0FHZCxFQUFFLENBQUM7SUFDQSxNQUFNLENBQXdCO0lBRXRDLFlBQVksU0FBZ0MsRUFBRTtRQUM1QyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN2QixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7T0FnQkc7SUFDSCxNQUFNLENBQUMsaUJBQWlCLENBS3RCLFNBQWdDLEVBQUU7UUFFbEMsT0FBTyxJQUFJLGVBQWUsQ0FDeEIsTUFBTSxDQUNQLENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7T0FnQkc7SUFDSCxNQUFNLENBQUMsa0JBQWtCLENBS3ZCLFNBQWdDLEVBQUU7UUFVbEMsT0FBTyxJQUFJLGVBQWUsQ0FReEIsTUFBTSxDQUFDLENBQUM7SUFDWixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQWtCRztJQUNILEdBQUcsQ0FBQyxJQUFZLEVBQUUsVUFBdUM7UUFDdkQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUM1QyxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FvQkc7SUFDSCxLQUFLLENBQUMsT0FBTyxDQUNYLEtBQWEsRUFDYixZQUFpRDtRQUVqRCxJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2xDLE9BQU8sWUFBWSxD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QUMsQ0FBQztJQUNMLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F1Qkc7QUFDSCxNQUFNLFVBQVUsbUJBQW1CLENBS2pDLEtBUUMsRUFDRCxRQUsrQjtJQU8vQixPQUFPLEtBQUssRUFDVixNQUFlLEVBQ2YsSUFBVyxFQUNYLE9BQWdDLEVBQ2hDLElBQTZCLEVBQzdCLEVBQUU7UUFDRixPQUFPLE1BQU0sS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLEtBQUssRUFBQyxLQUFLLEVBQUMsRUFBRTtZQUN4RSxPQUFPLE1BQU0sUUFBUSxDQUNuQixLQUFLLENBQUMsTUFBTSxFQUNaLEtBQUssQ0FBQyxJQUFJLEVBQ1YsS0FBSyxDQUFDLE9BQU8sRUFDYixLQUFLLENBQUMsSUFBSSxDQUNYLENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi9sb2cnO1xuXG4vLyBGdXR1cmUgRW5oYW5jZW1lbnQ6IFJlc3BvbnNlIFRyYW5zZm9ybWF0aW9uIFN1cHBvcnRcbi8vIFBsYW5uZWQgZmVhdHVyZXMgZm9yIHJlc3BvbnNlIHByb2Nlc3Npbmc6XG4vLyAtIHVzZVJlc3BvbnNlVHJhbnNmb3JtZXIoKSBtZXRob2QgZm9yIHJlc3BvbnNlLW9ubHkgdHJhbnNmb3JtYXRpb25zXG4vLyAtIHVzZUZ1bGwoKSBtZXRob2QgZm9yIGNvbWJpbmVkIHJlcXVlc3QvcmVzcG9uc2UgbWlkZGxld2FyZVxuLy8gLSBSZXNwb25zZVRyYW5zZm9ybWVyPFRJbnB1dCwgVE91dHB1dD4gdHlwZSBmb3IgdHlwZS1zYWZlIHJlc3BvbnNlIG1vZGlmaWNhdGlvbnNcbi8vIFRoZXNlIGZlYXR1cmVzIHdpbGwgcHJvdmlkZSBjbGVhbmVyIHBhdHRlcm5zIGZvciByZXNwb25zZSBwcm9jZXNzaW5nICh0aW1lc3RhbXBzLCBjb21wcmVzc2lvbiwgaGVhZGVycywgZXRjLilcblxuLyoqXG4gKiBCYXNlIG1pZGRsZXdhcmUgZnVuY3Rpb24gdHlwZVxuICpcbiAqIE1pZGRsZXdhcmUgZm9sbG93cyB0aGUgXCJvbmlvbiBtb2RlbFwiIHBhdHRlcm46XG4gKiAxLiBNaWRkbGV3YXJlIGV4ZWN1dGVzIGluIHRoZSBvcmRlciB0aGV5IHdlcmUgYWRkZWRcbiAqIDIuIEVhY2ggbWlkZGxld2FyZSBjYW4gbW9kaWZ5IGlucHV0IGJlZm9yZSBjYWxsaW5nIG5leHQoKVxuICogMy4gRWFjaCBtaWRkbGV3YXJlIGNhbiBwcm9jZXNzIHRoZSByZXN1bHQgYWZ0ZXIgbmV4dCgpIHJldHVybnNcbiAqIDQuIElmIG5leHQoKSBpcyBub3QgY2FsbGVkLCB0aGUgY2hhaW4gc3RvcHMgYW5kIHJlbWFpbmluZyBtaWRkbGV3YXJlL2hhbmRsZXIgYXJlIHNraXBwZWRcbiAqXG4gKiBAdGVtcGxhdGUgVElucHV0IC0gVHlwZSBvZiBpbnB1dCBwYXNzZWQgdG8gbWlkZGxld2FyZVxuICogQHRlbXBsYXRlIFRPdXRwdXQgLSBUeXBlIG9mIG91dHB1dCByZXR1cm5lZCBieSBtaWRkbGV3YXJlIGNoYWluXG4gKiBAcGFyYW0gaW5wdXQgLSBUaGUgaW5wdXQgZGF0YSBwYXNzZWQgdGhyb3VnaCB0aGUgY2hhaW5cbiAqIEBwYXJhbSBuZXh0IC0gRnVuY3Rpb24gdG8gY29udGludWUgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBvciBmaW5hbCBoYW5kbGVyXG4gKiBAcmV0dXJucyBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgb3V0cHV0IG9mIHRoZSBjaGFpblxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBsb2dnaW5nTWlkZGxld2FyZTogTWlkZGxld2FyZTxNeUlucHV0LCBNeU91dHB1dD4gPSBhc3luYyAoaW5wdXQsIG5leHQpID0+IHtcbiAqICAgY29uc29sZS5sb2coJ0JlZm9yZSBoYW5kbGVyJyk7XG4gKiAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IG5leHQoKTtcbiAqICAgY29uc29sZS5sb2coJ0FmdGVyIGhhbmRsZXInKTtcbiAqICAgcmV0dXJuIHJlc3VsdDtcbiAqIH07XG4gKiBgYGBcbiAqL1xuZXhwb3J0IHR5cGUgTWlkZGxld2FyZTxUSW5wdXQgPSB1bmtub3duLCBUT3V0cHV0ID0gdW5rbm93bj4gPSAoXG4gIGlucHV0OiBUSW5wdXQsXG4gIG5leHQ6IChpbnB1dD86IFRJbnB1dCkgPT4gUHJvbWlzZTxUT3V0cHV0PixcbikgPT4gUHJvbWlzZTxUT3V0cHV0PjtcblxuLyoqXG4gKiBFbmhhbmNlZCBlcnJvciB3aXRoIG1pZGRsZXdhcmUgY2hhaW4gY29udGV4dFxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1pZGRsZXdhcmVFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgbWlkZGxld2FyZU5hbWU/OiBzdHJpbmc7XG4gIG1pZGRsZXdhcmVJbmRleD86IG51bWJlcjtcbiAgdG90YWxNaWRkbGV3YXJlcz86IG51bWJlcjtcbiAgbWlkZGxld2FyZUNoYWluPzogc3RyaW5nW107XG4gIG9yaWdpbmFsRXJyb3I/OiB1bmtub3duO1xufVxuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIG1pZGRsZXdhcmUgY2hhaW5cbiAqL1xuaW50ZXJmYWNlIE1pZGRsZXdhcmVDaGFpbkNvbmZpZyB7XG4gIGVuYWJsZURlYnVnTG9nZ2luZz86IGJvb2xlYW47XG4gIG9uRXJyb3I/OiAoZXJyb3I6IHVua25vd24sIG1pZGRsZXdhcmVOYW1lOiBzdHJpbmcpID0+IHZvaWQ7XG59XG5cbi8qKlxuICogR2VuZXJpYyBtaWRkbGV3YXJlIGNoYWluIGltcGxlbWVudGF0aW9uXG4gKlxuICogUHJvdmlkZXMgRXhwcmVzcy1zdHlsZSBtaWRkbGV3YXJlIGZ1bmN0aW9uYWxpdHkgZm9yIEFXUyBMYW1iZGEgaGFuZGxlcnMgYW5kIEdyYXBoUUwgcmVzb2x2ZXJzLlxuICogTWlkZGxld2FyZSBleGVjdXRlcyBpbiBhbiBcIm9uaW9uIG1vZGVsXCIgd2hlcmUgZWFjaCBtaWRkbGV3YXJlIHdyYXBzIHRoZSBuZXh0IG9uZSBpbiB0aGUgY2hhaW4uXG4gKlxuICogKipFeGVjdXRpb24gRmxvdzoqKlxuICogYGBgXG4gKiBNaWRkbGV3YXJlIDEgKGJlZm9yZSkg4oaSXG4gKiAgIE1pZGRsZXdhcmUgMiAoYmVmb3JlKSDihpJcbiAqICAgICBGaW5hbCBIYW5kbGVyIOKGklxuICogICBNaWRkbGV3YXJlIDIgKGFmdGVyKSDihpBcbiAqIE1pZGRsZXdhcmUgMSAoYWZ0ZXIpIOKGkFxuICogYGBgXG4gKlxuICogKipJbnB1dCBNdXRhdGlvbjoqKlxuICogLSBNaWRkbGV3YXJlIGNhbiBtdXRhdGUgdGhlIGlucHV0IG9iamVjdCBkaXJlY3RseVxuICogLSBDaGFuZ2VzIGFyZSB2aXNpYmxlIHRvIGFsbCBzdWJzZXF1ZW50IG1pZGRsZXdhcmUgYW5kIHRoZSBmaW5hbCBoYW5kbGVyXG4gKiAtIENvbnNpZGVyIGlucHV0IGltbXV0YWJpbGl0eSBmb3IgY29tcGxleCBhcHBsaWNhdGlvbnNcbiAqXG4gKiAqKkVycm9yIEhhbmRsaW5nOioqXG4gKiAtIEVycm9ycyB0aHJvd24gYnkgbWlkZGxld2FyZSBhcmUgZW5oYW5jZWQgd2l0aCBjaGFpbiBjb250ZXh0XG4gKiAtIEV4ZWN1dGlvbiBzdG9wcyBhdCB0aGUgZmlyc3QgZXJyb3IgKG5vIHN1YnNlcXVlbnQgbWlkZGxld2FyZSBleGVjdXRlKVxuICogLSBDb25maWd1cmUgYG9uRXJyb3JgIGhhbmRsZXIgZm9yIGNlbnRyYWxpemVkIGVycm9yIHByb2Nlc3NpbmdcbiAqXG4gKiAqKlBlcmZvcm1hbmNlOioqXG4gKiAtIEVhY2ggZXhlY3V0aW9uIGNyZWF0ZXMgYSBjbG9zdXJlIGNoYWluIC0gY29uc2lkZXIgcmV1c2luZyBjaGFpbnMgZm9yIGhpZ2gtZnJlcXVlbmN5IG9wZXJhdGlvbnNcbiAqIC0gRGVidWcgbG9nZ2luZyBhZGRzIG92ZXJoZWFkIC0gZGlzYWJsZSBpbiBwcm9kdWN0aW9uXG4gKlxuICogQHRlbXBsYXRlIFRJbnB1dCAtIFR5cGUgb2YgaW5wdXQgZGF0YSBwYXNzZWQgdGhyb3VnaCB0aGUgY2hhaW5cbiAqIEB0ZW1wbGF0ZSBUT3V0cHV0IC0gVHlwZSBvZiBvdXRwdXQgcmV0dXJuZWQgYnkgdGhlIGNoYWluXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGNoYWluID0gbmV3IE1pZGRsZXdhcmVDaGFpbjxNeUlucHV0LCBNeU91dHB1dD4oe1xuICogICBlbmFibGVEZWJ1Z0xvZ2dpbmc6IHRydWUsXG4gKiAgIG9uRXJyb3I6IChlcnJvciwgbWlkZGxld2FyZU5hbWUpID0+IHtcbiAqICAgICBjb25zb2xlLmVycm9yKGBNaWRkbGV3YXJlICR7bWlkZGxld2FyZU5hbWV9IGZhaWxlZDpgLCBlcnJvcik7XG4gKiAgIH1cbiAqIH0pO1xuICpcbiAqIGNoYWluXG4gKiAgIC51c2UoJ2F1dGgnLCBhdXRoTWlkZGxld2FyZSlcbiAqICAgLnVzZSgnbG9nZ2luZycsIGxvZ2dpbmdNaWRkbGV3YXJlKVxuICogICAudXNlKCd2YWxpZGF0aW9uJywgdmFsaWRhdGlvbk1pZGRsZXdhcmUpO1xuICpcbiAqIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNoYWluLmV4ZWN1dGUoaW5wdXQsIGZpbmFsSGFuZGxlcik7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIE1pZGRsZXdhcmVDaGFpbjxUSW5wdXQgPSB1bmtub3duLCBUT3V0cHV0ID0gdW5rbm93bj4ge1xuICBwcml2YXRlIG1pZGRsZXdhcmVzOiBBcnJheTx7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIG1pZGRsZXdhcmU6IE1pZGRsZXdhcmU8VElucHV0LCBUT3V0cHV0PjtcbiAgfT4gPSBbXTtcbiAgcHJpdmF0ZSBjb25maWc6IE1pZGRsZXdhcmVDaGFpbkNvbmZpZztcblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IE1pZGRsZXdhcmVDaGFpbkNvbmZpZyA9IHt9KSB7XG4gICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgbWlkZGxld2FyZSBjaGFpbiBzcGVjaWZpY2FsbHkgZm9yIEFXUyBMYW1iZGEgaGFuZGxlcnNcbiAgICpcbiAgICogVGhpcyBpcyBhIGNvbnZlbmllbmNlIG1ldGhvZCB0aGF0IGNyZWF0ZXMgYSBjaGFpbiB3aXRoIHRoZSBzdGFuZGFyZFxuICAgKiBMYW1iZGEgaW5wdXQgc3RydWN0dXJlOiBgeyBldmVudDogVEV2ZW50OyBjb250ZXh0OiBUQ29udGV4dCB9YFxuICAgKlxuICAgKiBAdGVtcGxhdGUgVEV2ZW50IC0gVHlwZSBvZiB0aGUgTGFtYmRhIGV2ZW50XG4gICAqIEB0ZW1wbGF0ZSBUQ29udGV4dCAtIFR5cGUgb2YgdGhlIExhbWJkYSBjb250ZXh0XG4gICAqIEB0ZW1wbGF0ZSBUUmV0dXJuIC0gVHlwZSBvZiB0aGUgTGFtYmRhIHJldHVybiB2YWx1ZVxuICAgKiBAcGFyYW0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY2hhaW5cbiAgICogQHJldHVybnMgQSBuZXcgbWlkZGxld2FyZSBjaGFpbiBjb25maWd1cmVkIGZvciBMYW1iZGEgaGFuZGxlcnNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCBjaGFpbiA9IE1pZGRsZXdhcmVDaGFpbi5jcmVhdGVMYW1iZGFDaGFpbjxBUElHYXRld2F5UHJveHlFdmVudCwgQ29udGV4dCwgQVBJR2F0ZXdheVByb3h5UmVzdWx0PigpO1xuICAgKiBgYGBcbiAgICovXG4gIHN0YXRpYyBjcmVhdGVMYW1iZGFDaGFpbjxcbiAgICBURXZlbnQgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBUQ29udGV4dCA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgIFRSZXR1cm4gPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgPihcbiAgICBjb25maWc6IE1pZGRsZXdhcmVDaGFpbkNvbmZpZyA9IHt9LFxuICApOiBNaWRkbGV3YXJlQ2hhaW48eyBldmVudDogVEV2ZW50OyBjb250ZXh0OiBUQ29udGV4dCB9LCBUUmV0dXJuPiB7XG4gICAgcmV0dXJuIG5ldyBNaWRkbGV3YXJlQ2hhaW48eyBldmVudDogVEV2ZW50OyBjb250ZXh0OiBUQ29udGV4dCB9LCBUUmV0dXJuPihcbiAgICAgIGNvbmZpZyxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIG1pZGRsZXdhcmUgY2hhaW4gc3BlY2lmaWNhbGx5IGZvciBHcmFwaFFMIHJlc29sdmVyc1xuICAgKlxuICAgKiBUaGlzIGlzIGEgY29udmVuaWVuY2UgbWV0aG9kIHRoYXQgY3JlYXRlcyBhIGNoYWluIHdpdGggdGhlIHN0YW5kYXJkXG4gICAqIEdyYXBoUUwgcmVzb2x2ZXIgaW5wdXQgc3RydWN0dXJlOiBgeyBzb3VyY2UsIGFyZ3MsIGNvbnRleHQsIGluZm8gfWBcbiAgICpcbiAgICogQHRlbXBsYXRlIFRBcmdzIC0gVHlwZSBvZiB0aGUgR3JhcGhRTCBhcmd1bWVudHNcbiAgICogQHRlbXBsYXRlIFRTb3VyY2UgLSBUeXBlIG9mIHRoZSBHcmFwaFFMIHNvdXJjZVxuICAgKiBAdGVtcGxhdGUgVFJldHVybiAtIFR5cGUgb2YgdGhlIEdyYXBoUUwgcmV0dXJuIHZhbHVlXG4gICAqIEBwYXJhbSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjaGFpblxuICAgKiBAcmV0dXJucyBBIG5ldyBtaWRkbGV3YXJlIGNoYWluIGNvbmZpZ3VyZWQgZm9yIEdyYXBoUUwgcmVzb2x2ZXJzXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgY2hhaW4gPSBNaWRkbGV3YXJlQ2hhaW4uY3JlYXRlR3JhcGhRTENoYWluPE15QXJncywgTXlTb3VyY2UsIE15UmV0dXJuPigpO1xuICAgKiBgYGBcbiAgICovXG4gIHN0YXRpYyBjcmVhdGVHcmFwaFFMQ2hhaW48XG4gICAgVEFyZ3MgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBUU291cmNlID0gdW5rbm93bixcbiAgICBUUmV0dXJuID0gdW5rbm93bixcbiAgPihcbiAgICBjb25maWc6IE1pZGRsZXdhcmVDaGFpbkNvbmZpZyA9IHt9LFxuICApOiBNaWRkbGV3YXJlQ2hhaW48XG4gICAge1xuICAgICAgc291cmNlOiBUU291cmNlO1xuICAgICAgYXJnczogVEFyZ3M7XG4gICAgICBjb250ZXh0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAgIGluZm86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIH0sXG4gICAgVFJldHVyblxuICA+IHtcbiAgICByZXR1cm4gbmV3IE1pZGRsZXdhcmVDaGFpbjxcbiAgICAgIHtcbiAgICAgICAgc291cmNlOiBUU291cmNlO1xuICAgICAgICBhcmdzOiBUQXJncztcbiAgICAgICAgY29udGV4dDogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgICAgIGluZm86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgICAgfSxcbiAgICAgIFRSZXR1cm5cbiAgICA+KGNvbmZpZyk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIG1pZGRsZXdhcmUgdG8gdGhlIGNoYWluXG4gICAqXG4gICAqIE1pZGRsZXdhcmUgZnVuY3Rpb25zIGFyZSBleGVjdXRlZCBpbiB0aGUgb3JkZXIgdGhleSBhcmUgYWRkZWQuXG4gICAqIEVhY2ggbWlkZGxld2FyZSByZWNlaXZlcyB0aGUgaW5wdXQgYW5kIGEgYG5leHRgIGZ1bmN0aW9uIHRvIGNvbnRpbnVlXG4gICAqIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgb3IgZmluYWwgaGFuZGxlci5cbiAgICpcbiAgICogQHBhcmFtIG5hbWUgLSBEZXNjcmlwdGl2ZSBuYW1lIGZvciB0aGUgbWlkZGxld2FyZSAodXNlZCBpbiBlcnJvciBtZXNzYWdlcyBhbmQgbG9nZ2luZylcbiAgICogQHBhcmFtIG1pZGRsZXdhcmUgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbiB0byBhZGRcbiAgICogQHJldHVybnMgVGhpcyBjaGFpbiBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY2hhaW5cbiAgICogICAudXNlKCdhdXRoZW50aWNhdGlvbicsIGF1dGhNaWRkbGV3YXJlKVxuICAgKiAgIC51c2UoJ2xvZ2dpbmcnLCBsb2dnaW5nTWlkZGxld2FyZSlcbiAgICogICAudXNlKCd2YWxpZGF0aW9uJywgdmFsaWRhdGlvbk1pZGRsZXdhcmUpO1xuICAgKiBgYGBcbiAgICovXG4gIHVzZShuYW1lOiBzdHJpbmcsIG1pZGRsZXdhcmU6IE1pZGRsZXdhcmU8VElucHV0LCBUT3V0cHV0Pik6IHRoaXMge1xuICAgIHRoaXMubWlkZGxld2FyZXMucHVzaCh7IG5hbWUsIG1pZGRsZXdhcmUgfSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSB0aGUgbWlkZGxld2FyZSBjaGFpbiB3aXRoIHRoZSBnaXZlbiBpbnB1dCBhbmQgZmluYWwgaGFuZGxlclxuICAgKlxuICAgKiBUaGlzIG1ldGhvZCBydW5zIGFsbCBtaWRkbGV3YXJlIGluIHRoZSBjaGFpbiwgZm9sbG93ZWQgYnkgdGhlIGZpbmFsIGhhbmRsZXIuXG4gICAqIElmIGFueSBtaWRkbGV3YXJlIHRocm93cyBhbiBlcnJvciwgZXhlY3V0aW9uIHN0b3BzIGFuZCB0aGUgZXJyb3IgaXMgZW5oYW5jZWRcbiAgICogd2l0aCBjaGFpbiBjb250ZXh0IGJlZm9yZSBiZWluZyByZS10aHJvd24uXG4gICAqXG4gICAqIEBwYXJhbSBpbnB1dCAtIFRoZSBpbnB1dCBkYXRhIHRvIHBhc3MgdGhyb3VnaCB0aGUgbWlkZGxld2FyZSBjaGFpblxuICAgKiBAcGFyYW0gZmluYWxIYW5kbGVyIC0gVGhlIGZpbmFsIGhhbmRsZXIgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgdGhlIGlucHV0XG4gICAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBvdXRwdXQgZnJvbSB0aGUgZmluYWwgaGFuZGxlclxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNoYWluLmV4ZWN1dGUoXG4gICAqICAgeyB1c2VySWQ6ICcxMjMnLCBkYXRhOiB7IG5hbWU6ICdKb2huJyB9IH0sXG4gICAqICAgYXN5bmMgKGlucHV0KSA9PiB7XG4gICAqICAgICByZXR1cm4gYXdhaXQgZmV0Y2hVc2VyRGF0YShpbnB1dC51c2VySWQpO1xuICAgKiAgIH1cbiAgICogKTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBleGVjdXRlKFxuICAgIGlucHV0OiBUSW5wdXQsXG4gICAgZmluYWxIYW5kbGVyOiAoaW5wdXQ6IFRJbnB1dCkgPT4gUHJvbWlzZTxUT3V0cHV0PixcbiAgKTogUHJvbWlzZTxUT3V0cHV0PiB7XG4gICAgaWYgKHRoaXMubWlkZGxld2FyZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gZmluYWxIYW5kbGVyKGlucHV0KTtcbiAgICB9XG5cbiAgICBsZXQgaW5kZXggPSAwO1xuXG4gICAgY29uc3QgZXhlY3V0ZU5leHQgPSBhc3luYyAobW9kaWZpZWRJbnB1dD86IFRJbnB1dCk6IFByb21pc2U8VE91dHB1dD4gPT4ge1xuICAgICAgaWYgKGluZGV4ID49IHRoaXMubWlkZGxld2FyZXMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybiBmaW5hbEhhbmRsZXIobW9kaWZpZWRJbnB1dCA/PyBpbnB1dCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHsgbmFtZSwgbWlkZGxld2FyZSB9ID0gdGhpcy5taWRkbGV3YXJlc1tpbmRleF07XG4gICAgICBpbmRleCsrO1xuXG4gICAgICBpZiAodGhpcy5jb25maWcuZW5hYmxlRGVidWdMb2dnaW5nKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgRXhlY3V0aW5nIG1pZGRsZXdhcmU6ICR7bmFtZX1gKTtcbiAgICAgIH1cblxuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IG1pZGRsZXdhcmUobW9kaWZpZWRJbnB1dCA/PyBpbnB1dCwgZXhlY3V0ZU5leHQpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gQ3JlYXRlIGVuaGFuY2VkIGVycm9yIHdpdGggY2hhaW4gY29udGV4dFxuICAgICAgICBjb25zdCBlbmhhbmNlZEVycm9yOiBNaWRkbGV3YXJlRXJyb3IgPVxuICAgICAgICAgIGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKTtcblxuICAgICAgICAvLyBBZGQgbWlkZGxld2FyZSBjb250ZXh0IHdpdGhvdXQgbXV0YXRpbmcgb3JpZ2luYWwgZXJyb3JcbiAgICAgICAgaWYgKCFlbmhhbmNlZEVycm9yLm1pZGRsZXdhcmVOYW1lKSB7XG4gICAgICAgICAgZW5oYW5jZWRFcnJvci5taWRkbGV3YXJlTmFtZSA9IG5hbWU7XG4gICAgICAgICAgZW5oYW5jZWRFcnJvci5taWRkbGV3YXJlSW5kZXggPSBpbmRleCAtIDE7XG4gICAgICAgICAgZW5oYW5jZWRFcnJvci50b3RhbE1pZGRsZXdhcmVzID0gdGhpcy5taWRkbGV3YXJlcy5sZW5ndGg7XG4gICAgICAgICAgZW5oYW5jZWRFcnJvci5taWRkbGV3YXJlQ2hhaW4gPSB0aGlzLm1pZGRsZXdhcmVzLm1hcChtID0+IG0ubmFtZSk7XG5cbiAgICAgICAgICAvLyBTdG9yZSBvcmlnaW5hbCBlcnJvciBpZiB3ZSBjcmVhdGVkIGEgbmV3IEVycm9yIG9iamVjdFxuICAgICAgICAgIGlmICghKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpKSB7XG4gICAgICAgICAgICBlbmhhbmNlZEVycm9yLm9yaWdpbmFsRXJyb3IgPSBlcnJvcjtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5jb25maWcub25FcnJvcikge1xuICAgICAgICAgIHRoaXMuY29uZmlnLm9uRXJyb3IoZW5oYW5jZWRFcnJvciwgbmFtZSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZW5oYW5jZWRFcnJvcjtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuIGV4ZWN1dGVOZXh0KCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBudW1iZXIgb2YgbWlkZGxld2FyZXMgaW4gdGhlIGNoYWluXG4gICAqXG4gICAqIEByZXR1cm5zIFRoZSBjb3VudCBvZiBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBjdXJyZW50bHkgaW4gdGhlIGNoYWluXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgY2hhaW4gPSBuZXcgTWlkZGxld2FyZUNoYWluKCk7XG4gICAqIGNvbnNvbGUubG9nKGNoYWluLmxlbmd0aCk7IC8vIDBcbiAgICpcbiAgICogY2hhaW4udXNlKCdhdXRoJywgYXV0aE1pZGRsZXdhcmUpO1xuICAgKiBjaGFpbi51c2UoJ2xvZ2dpbmcnLCBsb2dnaW5nTWlkZGxld2FyZSk7XG4gICAqIGNvbnNvbGUubG9nKGNoYWluLmxlbmd0aCk7IC8vIDJcbiAgICogYGBgXG4gICAqL1xuICBnZXQgbGVuZ3RoKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubWlkZGxld2FyZXMubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIENsZWFyIGFsbCBtaWRkbGV3YXJlcyBmcm9tIHRoZSBjaGFpblxuICAgKlxuICAgKiBSZW1vdmVzIGFsbCBtaWRkbGV3YXJlIGZ1bmN0aW9ucywgcmVzZXR0aW5nIHRoZSBjaGFpbiB0byBlbXB0eSBzdGF0ZS5cbiAgICogVXNlZnVsIGZvciByZXVzaW5nIGNoYWluIGluc3RhbmNlcyBvciBjbGVhbmluZyB1cCBkdXJpbmcgdGVzdGluZy5cbiAgICpcbiAgICogQHJldHVybnMgVGhpcyBjaGFpbiBpbnN0YW5jZSBmb3IgbWV0aG9kIGNoYWluaW5nXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgY2hhaW4gPSBuZXcgTWlkZGxld2FyZUNoYWluKCk7XG4gICAqIGNoYWluLnVzZSgnYXV0aCcsIGF1dGhNaWRkbGV3YXJlKTtcbiAgICogY2hhaW4udXNlKCdsb2dnaW5nJywgbG9nZ2luZ01pZGRsZXdhcmUpO1xuICAgKlxuICAgKiBjaGFpbi5jbGVhcigpOyAvLyBDaGFpbiBpcyBub3cgZW1wdHlcbiAgICogY29uc29sZS5sb2coY2hhaW4ubGVuZ3RoKTsgLy8gMFxuICAgKiBgYGBcbiAgICovXG4gIGNsZWFyKCk6IHRoaXMge1xuICAgIHRoaXMubWlkZGxld2FyZXMgPSBbXTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuXG4vKipcbiAqIFdyYXAgYSBMYW1iZGEgaGFuZGxlciB3aXRoIG1pZGRsZXdhcmUgY2hhaW4gZnVuY3Rpb25hbGl0eVxuICpcbiAqIFRoaXMgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBMYW1iZGEgaGFuZGxlciB0aGF0IGV4ZWN1dGVzIHRoZSBtaWRkbGV3YXJlIGNoYWluXG4gKiBiZWZvcmUgY2FsbGluZyB0aGUgb3JpZ2luYWwgaGFuZGxlci4gVGhlIG1pZGRsZXdhcmUgY2hhaW4gcmVjZWl2ZXMgdGhlIExhbWJkYVxuICogZXZlbnQgYW5kIGNvbnRleHQgYXMgaW5wdXQuXG4gKlxuICogQHRlbXBsYXRlIFRFdmVudCAtIFR5cGUgb2YgdGhlIExhbWJkYSBldmVudFxuICogQHRlbXBsYXRlIFRDb250ZXh0IC0gVHlwZSBvZiB0aGUgTGFtYmRhIGNvbnRleHRcbiAqIEB0ZW1wbGF0ZSBUUmV0dXJuIC0gVHlwZSBvZiB0aGUgTGFtYmRhIHJldHVybiB2YWx1ZVxuICogQHBhcmFtIGNoYWluIC0gVGhlIG1pZGRsZXdhcmUgY2hhaW4gdG8gZXhlY3V0ZVxuICogQHBhcmFtIGhhbmRsZXIgLSBUaGUgb3JpZ2luYWwgTGFtYmRhIGhhbmRsZXIgZnVuY3Rpb25cbiAqIEByZXR1cm5zIEEgbmV3IExhbWJkYSBoYW5kbGVyIGZ1bmN0aW9uIHRoYXQgaW5jbHVkZXMgbWlkZGxld2FyZSBleGVjdXRpb25cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3Qgd3JhcHBlZEhhbmRsZXIgPSB3cmFwTGFtYmRhSGFuZGxlcihcbiAqICAgY2hhaW4sXG4gKiAgIGFzeW5jIChldmVudCwgY29udGV4dCkgPT4ge1xuICogICAgIHJldHVybiB7IHN0YXR1c0NvZGU6IDIwMCwgYm9keTogJ0hlbGxvIFdvcmxkJyB9O1xuICogICB9XG4gKiApO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3cmFwTGFtYmRhSGFuZGxlcjxcbiAgVEV2ZW50ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFRDb250ZXh0ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFRSZXR1cm4gPSB1bmtub3duLFxuPihcbiAgY2hhaW46IE1pZGRsZXdhcmVDaGFpbjx7IGV2ZW50OiBURXZlbnQ7IGNvbnRleHQ6IFRDb250ZXh0IH0sIFRSZXR1cm4+LFxuICBoYW5kbGVyOiAoZXZlbnQ6IFRFdmVudCwgY29udGV4dDogVENvbnRleHQpID0+IFByb21pc2U8VFJldHVybj4sXG4pOiAoZXZlbnQ6IFRFdmVudCwgY29udGV4dDogVENvbnRleHQpID0+IFByb21pc2U8VFJldHVybj4ge1xuICByZXR1cm4gYXN5bmMgKGV2ZW50OiBURXZlbnQsIGNvbnRleHQ6IFRDb250ZXh0KSA9PiB7XG4gICAgcmV0dXJuIGF3YWl0IGNoYWluLmV4ZWN1dGUoeyBldmVudCwgY29udGV4dCB9LCBhc3luYyBpbnB1dCA9PiB7XG4gICAgICByZXR1cm4gYXdhaXQgaGFuZGxlcihpbnB1dC5ldmVudCwgaW5wdXQuY29udGV4dCk7XG4gICAgfSk7XG4gIH07XG59XG5cbi8qKlxuICogV3JhcCBhIEdyYXBoUUwgcmVzb2x2ZXIgd2l0aCBtaWRkbGV3YXJlIGNoYWluIGZ1bmN0aW9uYWxpdHlcbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgR3JhcGhRTCByZXNvbHZlciB0aGF0IGV4ZWN1dGVzIHRoZSBtaWRkbGV3YXJlIGNoYWluXG4gKiBiZWZvcmUgY2FsbGluZyB0aGUgb3JpZ2luYWwgcmVzb2x2ZXIuIFRoZSBtaWRkbGV3YXJlIGNoYWluIHJlY2VpdmVzIHRoZSBHcmFwaFFMXG4gKiBzb3VyY2UsIGFyZ3MsIGNvbnRleHQsIGFuZCBpbmZvIGFzIGlucHV0LlxuICpcbiAqIEB0ZW1wbGF0ZSBUQXJncyAtIFR5cGUgb2YgdGhlIEdyYXBoUUwgYXJndW1lbnRzXG4gKiBAdGVtcGxhdGUgVFNvdXJjZSAtIFR5cGUgb2YgdGhlIEdyYXBoUUwgc291cmNlXG4gKiBAdGVtcGxhdGUgVFJldHVybiAtIFR5cGUgb2YgdGhlIEdyYXBoUUwgcmV0dXJuIHZhbHVlXG4gKiBAcGFyYW0gY2hhaW4gLSBUaGUgbWlkZGxld2FyZSBjaGFpbiB0byBleGVjdXRlXG4gKiBAcGFyYW0gcmVzb2x2ZXIgLSBUaGUgb3JpZ2luYWwgR3JhcGhRTCByZXNvbHZlciBmdW5jdGlvblxuICogQHJldHVybnMgQSBuZXcgR3JhcGhRTCByZXNvbHZlciBmdW5jdGlvbiB0aGF0IGluY2x1ZGVzIG1pZGRsZXdhcmUgZXhlY3V0aW9uXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHdyYXBwZWRSZXNvbHZlciA9IHdyYXBHcmFwaFFMUmVzb2x2ZXIoXG4gKiAgIGNoYWluLFxuICogICBhc3luYyAoc291cmNlLCBhcmdzLCBjb250ZXh0LCBpbmZvKSA9PiB7XG4gKiAgICAgcmV0dXJuIGF3YWl0IGZldGNoVXNlckRhdGEoYXJncy5pZCk7XG4gKiAgIH1cbiAqICk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdyYXBHcmFwaFFMUmVzb2x2ZXI8XG4gIFRBcmdzID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFRTb3VyY2UgPSB1bmtub3duLFxuICBUUmV0dXJuID0gdW5rbm93bixcbj4oXG4gIGNoYWluOiBNaWRkbGV3YXJlQ2hhaW48XG4gICAge1xuICAgICAgc291cmNlOiBUU291cmNlO1xuICAgICAgYXJnczogVEFyZ3M7XG4gICAgICBjb250ZXh0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAgIGluZm86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIH0sXG4gICAgVFJldHVyblxuICA+LFxuICByZXNvbHZlcjogKFxuICAgIHNvdXJjZTogVFNvdXJjZSxcbiAgICBhcmdzOiBUQXJncyxcbiAgICBjb250ZXh0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBpbmZvOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgKSA9PiBQcm9taXNlPFRSZXR1cm4+IHwgVFJldHVybixcbik6IChcbiAgc291cmNlOiBUU291cmNlLFxuICBhcmdzOiBUQXJncyxcbiAgY29udGV4dDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIGluZm86IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuKSA9PiBQcm9taXNlPFRSZXR1cm4+IHtcbiAgcmV0dXJuIGFzeW5jIChcbiAgICBzb3VyY2U6IFRTb3VyY2UsXG4gICAgYXJnczogVEFyZ3MsXG4gICAgY29udGV4dDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICAgaW5mbzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICkgPT4ge1xuICAgIHJldHVybiBhd2FpdCBjaGFpbi5leGVjdXRlKHsgc291cmNlLCBhcmdzLCBjb250ZXh0LCBpbmZvIH0sIGFzeW5jIGlucHV0ID0+IHtcbiAgICAgIHJldHVybiBhd2FpdCByZXNvbHZlcihcbiAgICAgICAgaW5wdXQuc291cmNlLFxuICAgICAgICBpbnB1dC5hcmdzLFxuICAgICAgICBpbnB1dC5jb250ZXh0LFxuICAgICAgICBpbnB1dC5pbmZvLFxuICAgICAgKTtcbiAgICB9KTtcbiAgfTtcbn1cbiJdfQ==