UNPKG

ngs-json-utils

Version:

A set of Angular utilities for deep cloning, serialization, and JSON manipulation.

412 lines 50.5 kB
import { Injectable } from '@angular/core'; import * as i0 from "@angular/core"; /** * A utility service for performing common JSON-related operations safely and effectively. */ export class NgsJsonUtilsService { /** * Safely converts a JavaScript value to a JSON string. * If an error occurs during serialization, returns `undefined` instead of throwing an error. * * @param data - The value to serialize into a JSON string. * @param replacer - Optional function to filter or transform properties. * @param space - Optional number of spaces for formatting the output JSON. * @returns A JSON string representation of the data, or `undefined` if serialization fails. */ stringify(data, replacer, space) { try { return JSON.stringify(data, replacer, space); } catch (error) { console.error('Error during JSON.stringify:', error); return undefined; } } /** * Safely parses a JSON string into a JavaScript object or value. * If parsing fails, returns the provided default value (or `null` if not provided). * * @param json - The JSON string to parse. * @param defaultValue - A fallback value to return if parsing fails (defaults to `null`). * @returns The parsed object/value, or the default value if parsing fails. */ parse(json, defaultValue = null) { try { return JSON.parse(json); } catch (error) { console.error('Error during JSON.parse:', error); return defaultValue; } } /** * Creates a deep copy of a given value using JSON serialization. * It relies on the JSON.stringify and JSON.parse methods to safely clone an object. * This approach doesn't handle cyclic references and non-serializable properties (like functions). * * @param data - The value to create a deep copy of. * @returns A deep copy of the input value, or undefined if cloning fails. */ deepCopy(data) { try { // Serializing and immediately deserializing the object to create a deep copy const jsonString = JSON.stringify(data); return JSON.parse(jsonString); } catch (error) { console.error('Error during deep copy (JSON serialization)', error); return undefined; } } /** * Safely validates if a given string is in valid JSON format. * If the string is invalid, it logs the error and returns `false`. * * @param jsonString - The string to validate. * @returns `true` if the string is valid JSON; otherwise, `false`. */ isValidJSON(jsonString) { if (!jsonString) { console.error('Invalid JSON string: empty or undefined input'); return false; } try { JSON.parse(jsonString); return true; } catch (error) { console.error('Invalid JSON string:', error); return false; } } /** * Compares two JSON-compatible values for equality using serialization. * Logs an error to the console if serialization fails. * * @param obj1 - The first JSON-compatible value to compare. * @param obj2 - The second JSON-compatible value to compare. * @returns `true` if the two values are equal, `false` otherwise. */ equalJSON(obj1, obj2) { try { return JSON.stringify(obj1) === JSON.stringify(obj2); } catch (error) { console.error('Failed to serialize objects for comparison', { obj1, obj2, error, }); return false; } } /** * Safely compares two values for deep equality, adhering strictly to JSON-compatible types. * It does not handle cyclic references or non-JSON-serializable objects. * * @param obj1 - The first value to compare. * @param obj2 - The second value to compare. * @returns `true` if the two values are deeply equal, `false` otherwise. */ deepEqualJSON(obj1, obj2) { const isObject = (val) => typeof val === 'object' && val !== null; const deepEqualHelper = (a, b) => { if (a === b) return true; if (Array.isArray(a) && Array.isArray(b)) { if (a.length !== b.length) return false; return a.every((item, index) => deepEqualHelper(item, b[index])); } if (isObject(a) && isObject(b)) { const keysA = Object.keys(a); const keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; return keysA.every((key) => keysB.includes(key) && deepEqualHelper(a[key], b[key])); } return false; }; return deepEqualHelper(obj1, obj2); } /** * Safely performs a deep merge of two objects using JSON serialization. * Handles cyclic references by catching errors gracefully. * Source properties will overwrite corresponding target properties. * * @param target - The target object to be updated. * @param source - The source object providing updates. * @returns A new object with merged properties, or the original target if an error occurs. */ deepMerge(target, source) { try { const targetClone = JSON.stringify(target); const sourceClone = JSON.stringify(source); const merged = JSON.parse(`{${targetClone.slice(1, -1)},${sourceClone.slice(1, -1)}}`); return merged; } catch (error) { console.error('Error during safe deep merge:', error); return target; } } /** * Safely filters an object's properties, keeping only those specified in the allowed keys. * Handles cyclic references and non-serializable objects gracefully. * Logs errors if any occur. * * @param obj - The object to filter. * @param allowedKeys - An array of keys to retain in the filtered object. * @returns A new object containing only the allowed keys, or an empty object if an error occurs. */ filterKeys(obj, allowedKeys) { try { const serializedObj = JSON.stringify(obj, (key, value) => { if (typeof value === 'function') { return undefined; } return value; }); const parsedObj = JSON.parse(serializedObj); return allowedKeys.reduce((acc, key) => { if (key in parsedObj) { acc[key] = parsedObj[key]; } return acc; }, {}); } catch (error) { console.error('Error during filtering object:', error); return {}; } } /** * Safely recursively updates the target object with values from the updates object. * Handles serialization of objects and logs errors if any occur (e.g., with non-serializable data). * If an error occurs during the update, the target remains unchanged. * * @param target - The object to be updated. * @param updates - The object containing updates to apply. * @returns A new object with updated values, or the original target if an error occurs. */ deepUpdate(target, updates) { try { const serializedUpdates = JSON.stringify(updates, (key, value) => { if (typeof value === 'function' || value === undefined) { return undefined; } return value; }); const parsedUpdates = JSON.parse(serializedUpdates); return Object.keys(parsedUpdates).reduce((acc, key) => { const value = parsedUpdates[key]; if (value && typeof value === 'object' && !Array.isArray(value)) { acc[key] = this.deepUpdate(acc[key] || {}, value); } else { acc[key] = value; } return acc; }, { ...target }); } catch (error) { console.error('Error during deep update:', error); return target; } } /** * Searches for a value in a nested object by its key. * * @param obj - The object to search within. * @param key - The key to look for. * @returns The value associated with the key, or `undefined` if not found. */ findValueByKey(obj, key) { if (key in obj) { return obj[key]; } for (const k in obj) { if (typeof obj[k] === 'object' && obj[k] !== null) { const result = this.findValueByKey(obj[k], key); if (result !== undefined) { return result; } } } return undefined; } /** * Safely searches for a value in a nested object by its key. * If an error occurs during the search, returns `undefined` instead of throwing. * * @param obj - The object to search within. * @param key - The key to look for. * @returns The value associated with the key, or `undefined` if not found or an error occurs. */ safeFindValueByKey(obj, key) { try { if (key in obj) { return obj[key]; } for (const k in obj) { if (typeof obj[k] === 'object' && obj[k] !== null) { const result = this.safeFindValueByKey(obj[k], key); if (result !== undefined) { return result; } } } return undefined; } catch (error) { console.error('Error during object search:', error); return undefined; } } /** * Safely removes all `undefined` values from an object. * If an error occurs during the cleaning process, returns the original object. * * @param obj - The object to clean. * @returns A new object without `undefined` values, or the original object if an error occurs. */ removeUndefined(obj) { try { return JSON.parse(JSON.stringify(obj, (_, value) => value === undefined ? undefined : value)); } catch (error) { console.error('Error during object cleaning:', error); return obj; } } /** * Safely converts a Map object to a plain JSON object. * If an error occurs during the conversion, returns an empty object. * * @param map - The Map to convert. * @returns A JSON object with the same key-value pairs as the Map, or an empty object if an error occurs. */ mapToJSON(map) { try { const obj = {}; map.forEach((value, key) => { obj[String(key)] = value; }); return obj; } catch (error) { console.error('Error during Map to JSON conversion:', error); return {}; } } /** * Safely converts a plain JSON object to a Map object. * If an error occurs during the conversion, returns an empty Map. * * @param json - The JSON object to convert. * @returns A Map containing the key-value pairs from the JSON object, or an empty Map if an error occurs. */ jsonToMap(json) { try { if (json && typeof json === 'object' && !Array.isArray(json)) { return new Map(Object.entries(json)); } return new Map(); } catch (error) { console.error('Error during JSON to Map conversion:', error); return new Map(); } } /** * Safely merges multiple arrays of objects, keeping only unique objects based on a specified key. * If invalid input is provided (non-array or non-object values), returns an empty array. * * @param arrays - An array of arrays of objects to merge. * @param key - The key used to determine uniqueness (objects with the same key value are considered duplicates). * @returns An array of unique objects based on the specified key, or an empty array if the input is invalid. */ mergeUniqueByKey(arrays, key) { // Проверяем, что входные данные являются массивом и ключ - строкой if (!Array.isArray(arrays) || typeof key !== 'string') return []; return arrays.flat().reduce((acc, obj) => { // Проверяем, что каждый объект содержит заданный ключ if (obj && obj.hasOwnProperty(key) && !acc.some((item) => item[key] === obj[key])) { acc.push(obj); } return acc; }, []); } /** * Safely removes all keys from an object that have null or empty values. * If the input is not an object, returns an empty object. * * @param obj - The object from which to remove empty values. * @returns A new object with only non-empty values, or an empty object if the input is invalid. */ removeEmptyValues(obj) { if (typeof obj !== 'object' || obj === null) return {}; return Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null && v !== '')); } /** * Safely retrieves the value from an object based on a specified path (array of keys). * Returns undefined if the object or the path is invalid. * * @param obj - The object to retrieve the value from. * @param path - An array of keys representing the path to the value. * @returns The value at the specified path, or undefined if the object or path is invalid. */ getByPath(obj, path) { if (typeof obj !== 'object' || obj === null || !Array.isArray(path)) return undefined; return path.reduce((acc, key) => (acc && acc[key] !== undefined ? acc[key] : undefined), obj); } /** * Safely extracts unique values from an array of objects based on a specific key. * If the input is invalid (non-array or non-object values), returns an empty array. * * @param arr - An array of objects from which to extract unique values. * @param key - The key used to extract unique values. * @returns An array of unique values based on the specified key, or an empty array if the input is invalid. */ uniqueValuesByKey(arr, key) { if (!Array.isArray(arr) || typeof key !== 'string') return []; return Array.from(new Set(arr.map((item) => (item && key in item ? item[key] : undefined)))); } /** * Safely flattens a nested object into a single-level object, using dot notation for nested keys. * If the input is invalid (non-object or null), returns an empty object. * * @param obj - The object to flatten. * @param prefix - The prefix to prepend to each key (used for nested objects). * @returns A flattened object with dot notation keys, or an empty object if the input is invalid. */ flattenObject(obj, prefix = '') { if (typeof obj !== 'object' || obj === null) return {}; return Object.entries(obj).reduce((acc, [key, value]) => { const newKey = prefix ? `${prefix}.${key}` : key; if (typeof value === 'object' && value !== null) { Object.assign(acc, this.flattenObject(value, newKey)); } else { acc[newKey] = value; } return acc; }, {}); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: NgsJsonUtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: NgsJsonUtilsService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: NgsJsonUtilsService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmdzLWpzb24tdXRpbHMuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25ncy1qc29uLXV0aWxzL3NyYy9saWIvbmdzLWpzb24tdXRpbHMuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDOztBQUUzQzs7R0FFRztBQUlILE1BQU0sT0FBTyxtQkFBbUI7SUFDOUI7Ozs7Ozs7O09BUUc7SUFDSCxTQUFTLENBQ1AsSUFBYSxFQUNiLFFBQTJDLEVBQzNDLEtBQWM7UUFFZCxJQUFJLENBQUM7WUFDSCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMvQyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsOEJBQThCLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDckQsT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsS0FBSyxDQUFJLElBQVksRUFBRSxlQUF5QixJQUFJO1FBQ2xELElBQUksQ0FBQztZQUNILE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQU0sQ0FBQztRQUMvQixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsMEJBQTBCLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDakQsT0FBTyxZQUFZLENBQUM7UUFDdEIsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsUUFBUSxDQUFJLElBQU87UUFDakIsSUFBSSxDQUFDO1lBQ0gsNkVBQTZFO1lBQzdFLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDeEMsT0FBTyxJQUFJLENBQUMs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QkFBTSxDQUFDO2dCQUNOLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUM7WUFDdEIsQ0FBQztZQUNELE9BQU8sR0FBRyxDQUFDO1FBQ2IsQ0FBQyxFQUNELEVBQUUsQ0FDSCxDQUFDO0lBQ0osQ0FBQzt3R0FyZFUsbUJBQW1COzRHQUFuQixtQkFBbUIsY0FGbEIsTUFBTTs7NEZBRVAsbUJBQW1CO2tCQUgvQixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuLyoqXG4gKiBBIHV0aWxpdHkgc2VydmljZSBmb3IgcGVyZm9ybWluZyBjb21tb24gSlNPTi1yZWxhdGVkIG9wZXJhdGlvbnMgc2FmZWx5IGFuZCBlZmZlY3RpdmVseS5cbiAqL1xuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCcsXG59KVxuZXhwb3J0IGNsYXNzIE5nc0pzb25VdGlsc1NlcnZpY2Uge1xuICAvKipcbiAgICogU2FmZWx5IGNvbnZlcnRzIGEgSmF2YVNjcmlwdCB2YWx1ZSB0byBhIEpTT04gc3RyaW5nLlxuICAgKiBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHNlcmlhbGl6YXRpb24sIHJldHVybnMgYHVuZGVmaW5lZGAgaW5zdGVhZCBvZiB0aHJvd2luZyBhbiBlcnJvci5cbiAgICpcbiAgICogQHBhcmFtIGRhdGEgLSBUaGUgdmFsdWUgdG8gc2VyaWFsaXplIGludG8gYSBKU09OIHN0cmluZy5cbiAgICogQHBhcmFtIHJlcGxhY2VyIC0gT3B0aW9uYWwgZnVuY3Rpb24gdG8gZmlsdGVyIG9yIHRyYW5zZm9ybSBwcm9wZXJ0aWVzLlxuICAgKiBAcGFyYW0gc3BhY2UgLSBPcHRpb25hbCBudW1iZXIgb2Ygc3BhY2VzIGZvciBmb3JtYXR0aW5nIHRoZSBvdXRwdXQgSlNPTi5cbiAgICogQHJldHVybnMgQSBKU09OIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgZGF0YSwgb3IgYHVuZGVmaW5lZGAgaWYgc2VyaWFsaXphdGlvbiBmYWlscy5cbiAgICovXG4gIHN0cmluZ2lmeShcbiAgICBkYXRhOiB1bmtub3duLFxuICAgIHJlcGxhY2VyPzogKGtleTogc3RyaW5nLCB2YWx1ZTogYW55KSA9PiBhbnksXG4gICAgc3BhY2U/OiBudW1iZXIsXG4gICk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShkYXRhLCByZXBsYWNlciwgc3BhY2UpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBkdXJpbmcgSlNPTi5zdHJpbmdpZnk6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2FmZWx5IHBhcnNlcyBhIEpTT04gc3RyaW5nIGludG8gYSBKYXZhU2NyaXB0IG9iamVjdCBvciB2YWx1ZS5cbiAgICogSWYgcGFyc2luZyBmYWlscywgcmV0dXJucyB0aGUgcHJvdmlkZWQgZGVmYXVsdCB2YWx1ZSAob3IgYG51bGxgIGlmIG5vdCBwcm92aWRlZCkuXG4gICAqXG4gICAqIEBwYXJhbSBqc29uIC0gVGhlIEpTT04gc3RyaW5nIHRvIHBhcnNlLlxuICAgKiBAcGFyYW0gZGVmYXVsdFZhbHVlIC0gQSBmYWxsYmFjayB2YWx1ZSB0byByZXR1cm4gaWYgcGFyc2luZyBmYWlscyAoZGVmYXVsdHMgdG8gYG51bGxgKS5cbiAgICogQHJldHVybnMgVGhlIHBhcnNlZCBvYmplY3QvdmFsdWUsIG9yIHRoZSBkZWZhdWx0IHZhbHVlIGlmIHBhcnNpbmcgZmFpbHMuXG4gICAqL1xuICBwYXJzZTxUPihqc29uOiBzdHJpbmcsIGRlZmF1bHRWYWx1ZTogVCB8IG51bGwgPSBudWxsKTogVCB8IG51bGwge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gSlNPTi5wYXJzZShqc29uKSBhcyBUO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBkdXJpbmcgSlNPTi5wYXJzZTonLCBlcnJvcik7XG4gICAgICByZXR1cm4gZGVmYXVsdFZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIGEgZ2l2ZW4gdmFsdWUgdXNpbmcgSlNPTiBzZXJpYWxpemF0aW9uLlxuICAgKiBJdCByZWxpZXMgb24gdGhlIEpTT04uc3RyaW5naWZ5IGFuZCBKU09OLnBhcnNlIG1ldGhvZHMgdG8gc2FmZWx5IGNsb25lIGFuIG9iamVjdC5cbiAgICogVGhpcyBhcHByb2FjaCBkb2Vzbid0IGhhbmRsZSBjeWNsaWMgcmVmZXJlbmNlcyBhbmQgbm9uLXNlcmlhbGl6YWJsZSBwcm9wZXJ0aWVzIChsaWtlIGZ1bmN0aW9ucykuXG4gICAqXG4gICAqIEBwYXJhbSBkYXRhIC0gVGhlIHZhbHVlIHRvIGNyZWF0ZSBhIGRlZXAgY29weSBvZi5cbiAgICogQHJldHVybnMgQSBkZWVwIGNvcHkgb2YgdGhlIGlucHV0IHZhbHVlLCBvciB1bmRlZmluZWQgaWYgY2xvbmluZyBmYWlscy5cbiAgICovXG4gIGRlZXBDb3B5PFQ+KGRhdGE6IFQpOiBUIHwgdW5kZWZpbmVkIHtcbiAgICB0cnkge1xuICAgICAgLy8gU2VyaWFsaXppbmcgYW5kIGltbWVkaWF0ZWx5IGRlc2VyaWFsaXppbmcgdGhlIG9iamVjdCB0byBjcmVhdGUgYSBkZWVwIGNvcHlcbiAgICAgIGNvbnN0IGpzb25TdHJpbmcgPSBKU09OLnN0cmluZ2lmeShkYXRhKTtcbiAgICAgIHJldHVybiBKU09OLnBhcnNlKGpzb25TdHJpbmcpIGFzIFQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGR1cmluZyBkZWVwIGNvcHkgKEpTT04gc2VyaWFsaXphdGlvbiknLCBlcnJvcik7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTYWZlbHkgdmFsaWRhdGVzIGlmIGEgZ2l2ZW4gc3RyaW5nIGlzIGluIHZhbGlkIEpTT04gZm9ybWF0LlxuICAgKiBJZiB0aGUgc3RyaW5nIGlzIGludmFsaWQsIGl0IGxvZ3MgdGhlIGVycm9yIGFuZCByZXR1cm5zIGBmYWxzZWAuXG4gICAqXG4gICAqIEBwYXJhbSBqc29uU3RyaW5nIC0gVGhlIHN0cmluZyB0byB2YWxpZGF0ZS5cbiAgICogQHJldHVybnMgYHRydWVgIGlmIHRoZSBzdHJpbmcgaXMgdmFsaWQgSlNPTjsgb3RoZXJ3aXNlLCBgZmFsc2VgLlxuICAgKi9cbiAgaXNWYWxpZEpTT04oanNvblN0cmluZzogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKCFqc29uU3RyaW5nKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdJbnZhbGlkIEpTT04gc3RyaW5nOiBlbXB0eSBvciB1bmRlZmluZWQgaW5wdXQnKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgSlNPTi5wYXJzZShqc29uU3RyaW5nKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdJbnZhbGlkIEpTT04gc3RyaW5nOicsIGVycm9yKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ29tcGFyZXMgdHdvIEpTT04tY29tcGF0aWJsZSB2YWx1ZXMgZm9yIGVxdWFsaXR5IHVzaW5nIHNlcmlhbGl6YXRpb24uXG4gICAqIExvZ3MgYW4gZXJyb3IgdG8gdGhlIGNvbnNvbGUgaWYgc2VyaWFsaXphdGlvbiBmYWlscy5cbiAgICpcbiAgICogQHBhcmFtIG9iajEgLSBUaGUgZmlyc3QgSlNPTi1jb21wYXRpYmxlIHZhbHVlIHRvIGNvbXBhcmUuXG4gICAqIEBwYXJhbSBvYmoyIC0gVGhlIHNlY29uZCBKU09OLWNvbXBhdGlibGUgdmFsdWUgdG8gY29tcGFyZS5cbiAgICogQHJldHVybnMgYHRydWVgIGlmIHRoZSB0d28gdmFsdWVzIGFyZSBlcXVhbCwgYGZhbHNlYCBvdGhlcndpc2UuXG4gICAqL1xuICBlcXVhbEpTT048VD4ob2JqMTogVCwgb2JqMjogVCk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob2JqMSkgPT09IEpTT04uc3RyaW5naWZ5KG9iajIpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdGYWlsZWQgdG8gc2VyaWFsaXplIG9iamVjdHMgZm9yIGNvbXBhcmlzb24nLCB7XG4gICAgICAgIG9iajEsXG4gICAgICAgIG9iajIsXG4gICAgICAgIGVycm9yLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNhZmVseSBjb21wYXJlcyB0d28gdmFsdWVzIGZvciBkZWVwIGVxdWFsaXR5LCBhZGhlcmluZyBzdHJpY3RseSB0byBKU09OLWNvbXBhdGlibGUgdHlwZXMuXG4gICAqIEl0IGRvZXMgbm90IGhhbmRsZSBjeWNsaWMgcmVmZXJlbmNlcyBvciBub24tSlNPTi1zZXJpYWxpemFibGUgb2JqZWN0cy5cbiAgICpcbiAgICogQHBhcmFtIG9iajEgLSBUaGUgZmlyc3QgdmFsdWUgdG8gY29tcGFyZS5cbiAgICogQHBhcmFtIG9iajIgLSBUaGUgc2Vjb25kIHZhbHVlIHRvIGNvbXBhcmUuXG4gICAqIEByZXR1cm5zIGB0cnVlYCBpZiB0aGUgdHdvIHZhbHVlcyBhcmUgZGVlcGx5IGVxdWFsLCBgZmFsc2VgIG90aGVyd2lzZS5cbiAgICovXG4gIGRlZXBFcXVhbEpTT048VD4ob2JqMTogVCwgb2JqMjogVCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGlzT2JqZWN0ID0gKHZhbDogdW5rbm93bik6IHZhbCBpcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9PlxuICAgICAgdHlwZW9mIHZhbCA9PT0gJ29iamVjdCcgJiYgdmFsICE9PSBudWxsO1xuXG4gICAgY29uc3QgZGVlcEVxdWFsSGVscGVyID0gKGE6IHVua25vd24sIGI6IHVua25vd24pOiBib29sZWFuID0+IHtcbiAgICAgIGlmIChhID09PSBiKSByZXR1cm4gdHJ1ZTtcblxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoYSkgJiYgQXJyYXkuaXNBcnJheShiKSkge1xuICAgICAgICBpZiAoYS5sZW5ndGggIT09IGIubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHJldHVybiBhLmV2ZXJ5KChpdGVtLCBpbmRleCkgPT4gZGVlcEVxdWFsSGVscGVyKGl0ZW0sIGJbaW5kZXhdKSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc09iamVjdChhKSAmJiBpc09iamVjdChiKSkge1xuICAgICAgICBjb25zdCBrZXlzQSA9IE9iamVjdC5rZXlzKGEpO1xuICAgICAgICBjb25zdCBrZXlzQiA9IE9iamVjdC5rZXlzKGIpO1xuXG4gICAgICAgIGlmIChrZXlzQS5sZW5ndGggIT09IGtleXNCLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIHJldHVybiBrZXlzQS5ldmVyeShcbiAgICAgICAgICAoa2V5KSA9PiBrZXlzQi5pbmNsdWRlcyhrZXkpICYmIGRlZXBFcXVhbEhlbHBlcihhW2tleV0sIGJba2V5XSksXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIGRlZXBFcXVhbEhlbHBlcihvYmoxLCBvYmoyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYWZlbHkgcGVyZm9ybXMgYSBkZWVwIG1lcmdlIG9mIHR3byBvYmplY3RzIHVzaW5nIEpTT04gc2VyaWFsaXphdGlvbi5cbiAgICogSGFuZGxlcyBjeWNsaWMgcmVmZXJlbmNlcyBieSBjYXRjaGluZyBlcnJvcnMgZ3JhY2VmdWxseS5cbiAgICogU291cmNlIHByb3BlcnRpZXMgd2lsbCBvdmVyd3JpdGUgY29ycmVzcG9uZGluZyB0YXJnZXQgcHJvcGVydGllcy5cbiAgICpcbiAgICogQHBhcmFtIHRhcmdldCAtIFRoZSB0YXJnZXQgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXG4gICAqIEBwYXJhbSBzb3VyY2UgLSBUaGUgc291cmNlIG9iamVjdCBwcm92aWRpbmcgdXBkYXRlcy5cbiAgICogQHJldHVybnMgQSBuZXcgb2JqZWN0IHdpdGggbWVyZ2VkIHByb3BlcnRpZXMsIG9yIHRoZSBvcmlnaW5hbCB0YXJnZXQgaWYgYW4gZXJyb3Igb2NjdXJzLlxuICAgKi9cbiAgZGVlcE1lcmdlPFQ+KHRhcmdldDogVCwgc291cmNlOiBQYXJ0aWFsPFQ+KTogVCB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHRhcmdldENsb25lID0gSlNPTi5zdHJpbmdpZnkodGFyZ2V0KTtcbiAgICAgIGNvbnN0IHNvdXJjZUNsb25lID0gSlNPTi5zdHJpbmdpZnkoc291cmNlKTtcblxuICAgICAgY29uc3QgbWVyZ2VkID0gSlNPTi5wYXJzZShcbiAgICAgICAgYHske3RhcmdldENsb25lLnNsaWNlKDEsIC0xKX0sJHtzb3VyY2VDbG9uZS5zbGljZSgxLCAtMSl9fWAsXG4gICAgICApO1xuXG4gICAgICByZXR1cm4gbWVyZ2VkIGFzIFQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGR1cmluZyBzYWZlIGRlZXAgbWVyZ2U6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2FmZWx5IGZpbHRlcnMgYW4gb2JqZWN0J3MgcHJvcGVydGllcywga2VlcGluZyBvbmx5IHRob3NlIHNwZWNpZmllZCBpbiB0aGUgYWxsb3dlZCBrZXlzLlxuICAgKiBIYW5kbGVzIGN5Y2xpYyByZWZlcmVuY2VzIGFuZCBub24tc2VyaWFsaXphYmxlIG9iamVjdHMgZ3JhY2VmdWxseS5cbiAgICogTG9ncyBlcnJvcnMgaWYgYW55IG9jY3VyLlxuICAgKlxuICAgKiBAcGFyYW0gb2JqIC0gVGhlIG9iamVjdCB0byBmaWx0ZXIuXG4gICAqIEBwYXJhbSBhbGxvd2VkS2V5cyAtIEFuIGFycmF5IG9mIGtleXMgdG8gcmV0YWluIGluIHRoZSBmaWx0ZXJlZCBvYmplY3QuXG4gICAqIEByZXR1cm5zIEEgbmV3IG9iamVjdCBjb250YWluaW5nIG9ubHkgdGhlIGFsbG93ZWQga2V5cywgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIGFuIGVycm9yIG9jY3Vycy5cbiAgICovXG4gIGZpbHRlcktleXM8VCBleHRlbmRzIG9iamVjdCwgSyBleHRlbmRzIGtleW9mIFQ+KFxuICAgIG9iajogVCxcbiAgICBhbGxvd2VkS2V5czogS1tdLFxuICApOiBQYXJ0aWFsPFBpY2s8VCwgSz4+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc2VyaWFsaXplZE9iaiA9IEpTT04uc3RyaW5naWZ5KG9iaiwgKGtleSwgdmFsdWUpID0+IHtcbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgfSk7XG4gICAgICBjb25zdCBwYXJzZWRPYmogPSBKU09OLnBhcnNlKHNlcmlhbGl6ZWRPYmopO1xuXG4gICAgICByZXR1cm4gYWxsb3dlZEtleXMucmVkdWNlKFxuICAgICAgICAoYWNjLCBrZXkpID0+IHtcbiAgICAgICAgICBpZiAoa2V5IGluIHBhcnNlZE9iaikge1xuICAgICAgICAgICAgYWNjW2tleV0gPSBwYXJzZWRPYmpba2V5XTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgICAgfSxcbiAgICAgICAge30gYXMgUGFydGlhbDxQaWNrPFQsIEs+PixcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGR1cmluZyBmaWx0ZXJpbmcgb2JqZWN0OicsIGVycm9yKTtcbiAgICAgIHJldHVybiB7fSBhcyBQYXJ0aWFsPFBpY2s8VCwgSz4+O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTYWZlbHkgcmVjdXJzaXZlbHkgdXBkYXRlcyB0aGUgdGFyZ2V0IG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIHRoZSB1cGRhdGVzIG9iamVjdC5cbiAgICogSGFuZGxlcyBzZXJpYWxpemF0aW9uIG9mIG9iamVjdHMgYW5kIGxvZ3MgZXJyb3JzIGlmIGFueSBvY2N1ciAoZS5nLiwgd2l0aCBub24tc2VyaWFsaXphYmxlIGRhdGEpLlxuICAgKiBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSB1cGRhdGUsIHRoZSB0YXJnZXQgcmVtYWlucyB1bmNoYW5nZWQuXG4gICAqXG4gICAqIEBwYXJhbSB0YXJnZXQgLSBUaGUgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXG4gICAqIEBwYXJhbSB1cGRhdGVzIC0gVGhlIG9iamVjdCBjb250YWluaW5nIHVwZGF0ZXMgdG8gYXBwbHkuXG4gICAqIEByZXR1cm5zIEEgbmV3IG9iamVjdCB3aXRoIHVwZGF0ZWQgdmFsdWVzLCBvciB0aGUgb3JpZ2luYWwgdGFyZ2V0IGlmIGFuIGVycm9yIG9jY3Vycy5cbiAgICovXG4gIGRlZXBVcGRhdGU8VD4odGFyZ2V0OiBULCB1cGRhdGVzOiBQYXJ0aWFsPFQ+KTogVCB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHNlcmlhbGl6ZWRVcGRhdGVzID0gSlNPTi5zdHJpbmdpZnkodXBkYXRlcywgKGtleSwgdmFsdWUpID0+IHtcbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJyB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHBhcnNlZFVwZGF0ZXMgPSBKU09OLnBhcnNlKHNlcmlhbGl6ZWRVcGRhdGVzKTtcblxuICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKHBhcnNlZFVwZGF0ZXMpLnJlZHVjZShcbiAgICAgICAgKGFjYywga2V5KSA9PiB7XG4gICAgICAgICAgY29uc3QgdmFsdWUgPSBwYXJzZWRVcGRhdGVzW2tleSBhcyBrZXlvZiBUXTtcbiAgICAgICAgICBpZiAodmFsdWUgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgIGFjY1trZXkgYXMga2V5b2YgVF0gPSB0aGlzLmRlZXBVcGRhdGUoXG4gICAgICAgICAgICAgIGFjY1trZXkgYXMga2V5b2YgVF0gfHwgKHt9IGFzIFQpLFxuICAgICAgICAgICAgICB2YWx1ZSxcbiAgICAgICAgICAgICkgYXMgYW55O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhY2Nba2V5IGFzIGtleW9mIFRdID0gdmFsdWUgYXMgYW55O1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgICB9LFxuICAgICAgICB7IC4uLnRhcmdldCB9LFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZHVyaW5nIGRlZXAgdXBkYXRlOicsIGVycm9yKTtcbiAgICAgIHJldHVybiB0YXJnZXQ7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNlYXJjaGVzIGZvciBhIHZhbHVlIGluIGEgbmVzdGVkIG9iamVjdCBieSBpdHMga2V5LlxuICAgKlxuICAgKiBAcGFyYW0gb2JqIC0gVGhlIG9iamVjdCB0byBzZWFyY2ggd2l0aGluLlxuICAgKiBAcGFyYW0ga2V5IC0gVGhlIGtleSB0byBsb29rIGZvci5cbiAgICogQHJldHVybnMgVGhlIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGUga2V5LCBvciBgdW5kZWZpbmVkYCBpZiBub3QgZm91bmQuXG4gICAqL1xuICBmaW5kVmFsdWVCeUtleTxUIGV4dGVuZHMgb2JqZWN0LCBLIGV4dGVuZHMga2V5b2YgVD4oXG4gICAgb2JqOiBULFxuICAgIGtleTogSyxcbiAgKTogVFtLXSB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKGtleSBpbiBvYmopIHtcbiAgICAgIHJldHVybiBvYmpba2V5XTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGsgaW4gb2JqKSB7XG4gICAgICBpZiAodHlwZW9mIG9ialtrXSA9PT0gJ29iamVjdCcgJiYgb2JqW2tdICE9PSBudWxsKSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuZmluZFZhbHVlQnlLZXkob2JqW2tdIGFzIFQsIGtleSk7XG4gICAgICAgIGlmIChyZXN1bHQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFNhZmVseSBzZWFyY2hlcyBmb3IgYSB2YWx1ZSBpbiBhIG5lc3RlZCBvYmplY3QgYnkgaXRzIGtleS5cbiAgICogSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgc2VhcmNoLCByZXR1cm5zIGB1bmRlZmluZWRgIGluc3RlYWQgb2YgdGhyb3dpbmcuXG4gICAqXG4gICAqIEBwYXJhbSBvYmogLSBUaGUgb2JqZWN0IHRvIHNlYXJjaCB3aXRoaW4uXG4gICAqIEBwYXJhbSBrZXkgLSBUaGUga2V5IHRvIGxvb2sgZm9yLlxuICAgKiBAcmV0dXJucyBUaGUgdmFsdWUgYXNzb2NpYXRlZCB3aXRoIHRoZSBrZXksIG9yIGB1bmRlZmluZWRgIGlmIG5vdCBmb3VuZCBvciBhbiBlcnJvciBvY2N1cnMuXG4gICAqL1xuICBzYWZlRmluZFZhbHVlQnlLZXk8VCBleHRlbmRzIG9iamVjdCwgSyBleHRlbmRzIGtleW9mIFQ+KFxuICAgIG9iajogVCxcbiAgICBrZXk6IEssXG4gICk6IFRbS10gfCB1bmRlZmluZWQge1xuICAgIHRyeSB7XG4gICAgICBpZiAoa2V5IGluIG9iaikge1xuICAgICAgICByZXR1cm4gb2JqW2tleV07XG4gICAgICB9XG5cbiAgICAgIGZvciAoY29uc3QgayBpbiBvYmopIHtcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpba10gPT09ICdvYmplY3QnICYmIG9ialtrXSAhPT0gbnVsbCkge1xuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuc2FmZUZpbmRWYWx1ZUJ5S2V5KG9ialtrXSBhcyBULCBrZXkpO1xuICAgICAgICAgIGlmIChyZXN1bHQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZHVyaW5nIG9iamVjdCBzZWFyY2g6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2FmZWx5IHJlbW92ZXMgYWxsIGB1bmRlZmluZWRgIHZhbHVlcyBmcm9tIGFuIG9iamVjdC5cbiAgICogSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgY2xlYW5pbmcgcHJvY2VzcywgcmV0dXJucyB0aGUgb3JpZ2luYWwgb2JqZWN0LlxuICAgKlxuICAgKiBAcGFyYW0gb2JqIC0gVGhlIG9iamVjdCB0byBjbGVhbi5cbiAgICogQHJldHVybnMgQSBuZXcgb2JqZWN0IHdpdGhvdXQgYHVuZGVmaW5lZGAgdmFsdWVzLCBvciB0aGUgb3JpZ2luYWwgb2JqZWN0IGlmIGFuIGVycm9yIG9jY3Vycy5cbiAgICovXG4gIHJlbW92ZVVuZGVmaW5lZDxUPihvYmo6IFQpOiBUIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEpTT04ucGFyc2UoXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KG9iaiwgKF8sIHZhbHVlKSA9PlxuICAgICAgICAgIHZhbHVlID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiB2YWx1ZSxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGR1cmluZyBvYmplY3QgY2xlYW5pbmc6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIG9iajtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2FmZWx5IGNvbnZlcnRzIGEgTWFwIG9iamVjdCB0byBhIHBsYWluIEpTT04gb2JqZWN0LlxuICAgKiBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSBjb252ZXJzaW9uLCByZXR1cm5zIGFuIGVtcHR5IG9iamVjdC5cbiAgICpcbiAgICogQHBhcmFtIG1hcCAtIFRoZSBNYXAgdG8gY29udmVydC5cbiAgICogQHJldHVybnMgQSBKU09OIG9iamVjdCB3aXRoIHRoZSBzYW1lIGtleS12YWx1ZSBwYWlycyBhcyB0aGUgTWFwLCBvciBhbiBlbXB0eSBvYmplY3QgaWYgYW4gZXJyb3Igb2NjdXJzLlxuICAgKi9cbiAgbWFwVG9KU09OPEssIFY+KG1hcDogTWFwPEssIFY+KTogUmVjb3JkPHN0cmluZywgVj4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBvYmo6IFJlY29yZDxzdHJpbmcsIFY+ID0ge307XG4gICAgICBtYXAuZm9yRWFjaCgodmFsdWUsIGtleSkgPT4ge1xuICAgICAgICBvYmpbU3RyaW5nKGtleSldID0gdmFsdWU7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiBvYmo7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGR1cmluZyBNYXAgdG8gSlNPTiBjb252ZXJzaW9uOicsIGVycm9yKTtcbiAgICAgIHJldHVybiB7fTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2FmZWx5IGNvbnZlcnRzIGEgcGxhaW4gSlNPTiBvYmplY3QgdG8gYSBNYXAgb2JqZWN0LlxuICAgKiBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSBjb252ZXJzaW9uLCByZXR1cm5zIGFuIGVtcHR5IE1hcC5cbiAgICpcbiAgICogQHBhcmFtIGpzb24gLSBUaGUgSlNPTiBvYmplY3QgdG8gY29udmVydC5cbiAgICogQHJldHVybnMgQSBNYXAgY29udGFpbmluZyB0aGUga2V5LXZhbHVlIHBhaXJzIGZyb20gdGhlIEpTT04gb2JqZWN0LCBvciBhbiBlbXB0eSBNYXAgaWYgYW4gZXJyb3Igb2NjdXJzLlxuICAgKi9cbiAganNvblRvTWFwPFY+KGpzb246IFJlY29yZDxzdHJpbmcsIFY+KTogTWFwPHN0cmluZywgVj4ge1xuICAgIHRyeSB7XG4gICAgICBpZiAoanNvbiAmJiB0eXBlb2YganNvbiA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoanNvbikpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBNYXAoT2JqZWN0LmVudHJpZXMoanNvbikpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5ldyBNYXAoKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZHVyaW5nIEpTT04gdG8gTWFwIGNvbnZlcnNpb246JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIG5ldyBNYXAoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2FmZWx5IG1lcmdlcyBtdWx0aXBsZSBhcnJheXMgb2Ygb2JqZWN0cywga2VlcGluZyBvbmx5IHVuaXF1ZSBvYmplY3RzIGJhc2VkIG9uIGEgc3BlY2lmaWVkIGtleS5cbiAgICogSWYgaW52YWxpZCBpbnB1dCBpcyBwcm92aWRlZCAobm9uLWFycmF5IG9yIG5vbi1vYmplY3QgdmFsdWVzKSwgcmV0dXJucyBhbiBlbXB0eSBhcnJheS5cbiAgICpcbiAgICogQHBhcmFtIGFycmF5cyAtIEFuIGFycmF5IG9mIGFycmF5cyBvZiBvYmplY3RzIHRvIG1lcmdlLlxuICAgKiBAcGFyYW0ga2V5IC0gVGhlIGtleSB1c2VkIHRvIGRldGVybWluZSB1bmlxdWVuZXNzIChvYmplY3RzIHdpdGggdGhlIHNhbWUga2V5IHZhbHVlIGFyZSBjb25zaWRlcmVkIGR1cGxpY2F0ZXMpLlxuICAgKiBAcmV0dXJucyBBbiBhcnJheSBvZiB1bmlxdWUgb2JqZWN0cyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIGtleSwgb3IgYW4gZW1wdHkgYXJyYXkgaWYgdGhlIGlucHV0IGlzIGludmFsaWQuXG4gICAqL1xuICBtZXJnZVVuaXF1ZUJ5S2V5PFQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+PihcbiAgICBhcnJheXM6IFRbXSxcbiAgICBrZXk6IHN0cmluZyxcbiAgKTogVFtdIHtcbiAgICAvLyDQn9GA0L7QstC10YDRj9C10LwsINGH0YLQviDQstGF0L7QtNC90YvQtSDQtNCw0L3QvdGL0LUg0Y/QstC70Y/RjtGC0YHRjyDQvNCw0YHRgdC40LLQvtC8INC4INC60LvRjtGHIC0g0YHRgtGA0L7QutC+0LlcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkoYXJyYXlzKSB8fCB0eXBlb2Yga2V5ICE9PSAnc3RyaW5nJykgcmV0dXJuIFtdO1xuXG4gICAgcmV0dXJuIGFycmF5cy5mbGF0KCkucmVkdWNlKChhY2M6IFRbXSwgb2JqOiBUKSA9PiB7XG4gICAgICAvLyDQn9GA0L7QstC10YDRj9C10LwsINGH0YLQviDQutCw0LbQtNGL0Lkg0L7QsdGK0LXQutGCINGB0L7QtNC10YDQttC40YIg0LfQsNC00LDQvdC90YvQuSDQutC70Y7Rh1xuICAgICAgaWYgKFxuICAgICAgICBvYmogJiZcbiAgICAgICAgb2JqLmhhc093blByb3BlcnR5KGtleSkgJiZcbiAgICAgICAgIWFjYy5zb21lKChpdGVtKSA9PiBpdGVtW2tleV0gPT09IG9ialtrZXldKVxuICAgICAgKSB7XG4gICAgICAgIGFjYy5wdXNoKG9iaik7XG4gICAgICB9XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sIFtdKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYWZlbHkgcmVtb3ZlcyBhbGwga2V5cyBmcm9tIGFuIG9iamVjdCB0aGF0IGhhdmUgbnVsbCBvciBlbXB0eSB2YWx1ZXMuXG4gICAqIElmIHRoZSBpbnB1dCBpcyBub3QgYW4gb2JqZWN0LCByZXR1cm5zIGFuIGVtcHR5IG9iamVjdC5cbiAgICpcbiAgICogQHBhcmFtIG9iaiAtIFRoZSBvYmplY3QgZnJvbSB3aGljaCB0byByZW1vdmUgZW1wdHkgdmFsdWVzLlxuICAgKiBAcmV0dXJucyBBIG5ldyBvYmplY3Qgd2l0aCBvbmx5IG5vbi1lbXB0eSB2YWx1ZXMsIG9yIGFuIGVtcHR5IG9iamVjdCBpZiB0aGUgaW5wdXQgaXMgaW52YWxpZC5cbiAgICovXG4gIHJlbW92ZUVtcHR5VmFsdWVzKG9iajogYW55KTogYW55IHtcbiAgICBpZiAodHlwZW9mIG9iaiAhPT0gJ29iamVjdCcgfHwgb2JqID09PSBudWxsKSByZXR1cm4ge307XG5cbiAgICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgT2JqZWN0LmVudHJpZXMob2JqKS5maWx0ZXIoKFtfLCB2XSkgPT4gdiAhPSBudWxsICYmIHYgIT09ICcnKSxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFNhZmVseSByZXRyaWV2ZXMgdGhlIHZhbHVlIGZyb20gYW4gb2JqZWN0IGJhc2VkIG9uIGEgc3BlY2lmaWVkIHBhdGggKGFycmF5IG9mIGtleXMpLlxuICAgKiBSZXR1cm5zIHVuZGVmaW5lZCBpZiB0aGUgb2JqZWN0IG9yIHRoZSBwYXRoIGlzIGludmFsaWQuXG4gICAqXG4gICAqIEBwYXJhbSBvYmogLSBUaGUgb2JqZWN0IHRvIHJldHJpZXZlIHRoZSB2YWx1ZSBmcm9tLlxuICAgKiBAcGFyYW0gcGF0aCAtIEFuIGFycmF5IG9mIGtleXMgcmVwcmVzZW50aW5nIHRoZSBwYXRoIHRvIHRoZSB2YWx1ZS5cbiAgICogQHJldHVybnMgVGhlIHZhbHVlIGF0IHRoZSBzcGVjaWZpZWQgcGF0aCwgb3IgdW5kZWZpbmVkIGlmIHRoZSBvYmplY3Qgb3IgcGF0aCBpcyBpbnZhbGlkLlxuICAgKi9cbiAgZ2V0QnlQYXRoKG9iajogYW55LCBwYXRoOiBzdHJpbmdbXSk6IGFueSB7XG4gICAgaWYgKHR5cGVvZiBvYmogIT09ICdvYmplY3QnIHx8IG9iaiA9PT0gbnVsbCB8fCAhQXJyYXkuaXNBcnJheShwYXRoKSlcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICByZXR1cm4gcGF0aC5yZWR1Y2UoXG4gICAgICAoYWNjLCBrZXkpID0+IChhY2MgJiYgYWNjW2tleV0gIT09IHVuZGVmaW5lZCA/IGFjY1trZXldIDogdW5kZWZpbmVkKSxcbiAgICAgIG9iaixcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFNhZmVseSBleHRyYWN0cyB1bmlxdWUgdmFsdWVzIGZyb20gYW4gYXJyYXkgb2Ygb2JqZWN0cyBiYXNlZCBvbiBhIHNwZWNpZmljIGtleS5cbiAgICogSWYgdGhlIGlucHV0IGlzIGludmFsaWQgKG5vbi1hcnJheSBvciBub24tb2JqZWN0IHZhbHVlcyksIHJldHVybnMgYW4gZW1wdHkgYXJyYXkuXG4gICAqXG4gICAqIEBwYXJhbSBhcnIgLSBBbiBhcnJheSBvZiBvYmplY3RzIGZyb20gd2hpY2ggdG8gZXh0cmFjdCB1bmlxdWUgdmFsdWVzLlxuICAgKiBAcGFyYW0ga2V5IC0gVGhlIGtleSB1c2VkIHRvIGV4dHJhY3QgdW5pcXVlIHZhbHVlcy5cbiAgICogQHJldHVybnMgQW4gYXJyYXkgb2YgdW5pcXVlIHZhbHVlcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIGtleSwgb3IgYW4gZW1wdHkgYXJyYXkgaWYgdGhlIGlucHV0IGlzIGludmFsaWQuXG4gICAqL1xuICB1bmlxdWVWYWx1ZXNCeUtleTxUIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4+KFxuICAgIGFycjogVFtdLFxuICAgIGtleTogc3RyaW5nLFxuICApOiB1bmtub3duW10ge1xuICAgIGlmICghQXJyYXkuaXNBcnJheShhcnIpIHx8IHR5cGVvZiBrZXkgIT09ICdzdHJpbmcnKSByZXR1cm4gW107XG5cbiAgICByZXR1cm4gQXJyYXkuZnJvbShcbiAgICAgIG5ldyBTZXQoYXJyLm1hcCgoaXRlbSkgPT4gKGl0ZW0gJiYga2V5IGluIGl0ZW0gPyBpdGVtW2tleV0gOiB1bmRlZmluZWQpKSksXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYWZlbHkgZmxhdHRlbnMgYSBuZXN0ZWQgb2JqZWN0IGludG8gYSBzaW5nbGUtbGV2ZWwgb2JqZWN0LCB1c2luZyBkb3Qgbm90YXRpb24gZm9yIG5lc3RlZCBrZXlzLlxuICAgKiBJZiB0aGUgaW5wdXQgaXMgaW52YWxpZCAobm9uLW9iamVjdCBvciBudWxsKSwgcmV0dXJucyBhbiBlbXB0eSBvYmplY3QuXG4gICAqXG4gICAqIEBwYXJhbSBvYmogLSBUaGUgb2JqZWN0IHRvIGZsYXR0ZW4uXG4gICAqIEBwYXJhbSBwcmVmaXggLSBUaGUgcHJlZml4IHRvIHByZXBlbmQgdG8gZWFjaCBrZXkgKHVzZWQgZm9yIG5lc3RlZCBvYmplY3RzKS5cbiAgICogQHJldHVybnMgQSBmbGF0dGVuZWQgb2JqZWN0IHdpdGggZG90IG5vdGF0aW9uIGtleXMsIG9yIGFuIGVtcHR5IG9iamVjdCBpZiB0aGUgaW5wdXQgaXMgaW52YWxpZC5cbiAgICovXG4gIGZsYXR0ZW5PYmplY3Q8VCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+PihcbiAgICBvYmo6IFQsXG4gICAgcHJlZml4OiBzdHJpbmcgPSAnJyxcbiAgKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICAgIGlmICh0eXBlb2Ygb2JqICE9PSAnb2JqZWN0JyB8fCBvYmogPT09IG51bGwpIHJldHVybiB7fTtcblxuICAgIHJldHVybiBPYmplY3QuZW50cmllcyhvYmopLnJlZHVjZShcbiAgICAgIChhY2M6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgICAgY29uc3QgbmV3S2V5ID0gcHJlZml4ID8gYCR7cHJlZml4fS4ke2tleX1gIDoga2V5O1xuIC