@dollhousemcp/mcp-server
Version:
DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.
349 lines • 39.3 kB
JavaScript
/**
* Element source priority configuration
*
* This module defines the centralized configuration for element sourcing priority,
* determining the order in which element sources (local, GitHub, collection) are
* checked when searching for or installing elements.
*
* @module config/sourcePriority
*/
import { logger } from '../utils/logger.js';
/**
* Enumeration of available element sources
*
* @example
* // Using ElementSource in configuration
* const priority = [ElementSource.LOCAL, ElementSource.GITHUB, ElementSource.COLLECTION];
*/
export var ElementSource;
(function (ElementSource) {
/** Local portfolio (~/.dollhouse/portfolio/) */
ElementSource["LOCAL"] = "local";
/** User's GitHub portfolio repository */
ElementSource["GITHUB"] = "github";
/** DollhouseMCP community collection */
ElementSource["COLLECTION"] = "collection";
})(ElementSource || (ElementSource = {}));
/**
* Default source priority configuration
*
* Priority order: Local → GitHub → Collection
* This ensures users' local customizations take precedence over remote sources.
*
* @example
* // Using the default configuration
* import { DEFAULT_SOURCE_PRIORITY } from './sourcePriority.js';
*
* const config = DEFAULT_SOURCE_PRIORITY;
* console.log(config.priority); // [ElementSource.LOCAL, ElementSource.GITHUB, ElementSource.COLLECTION]
*/
export const DEFAULT_SOURCE_PRIORITY = {
priority: [ElementSource.LOCAL, ElementSource.GITHUB, ElementSource.COLLECTION],
stopOnFirst: true,
checkAllForUpdates: false,
fallbackOnError: true
};
/**
* Get current source priority configuration
*
* Priority order for configuration sources:
* 1. User configuration (from config file)
* 2. Environment variables (for testing)
* 3. Default configuration
*
* @returns {SourcePriorityConfig} The current source priority configuration
*
* @example
* // Get the current configuration
* import { getSourcePriorityConfig } from './sourcePriority.js';
*
* const config = getSourcePriorityConfig();
* console.log(config.priority); // [ElementSource.LOCAL, ElementSource.GITHUB, ElementSource.COLLECTION]
*
* @example
* // Use in a search operation
* const config = getSourcePriorityConfig();
* for (const source of config.priority) {
* const results = await searchSource(source);
* if (results.length > 0 && config.stopOnFirst) {
* break;
* }
* }
*/
export function getSourcePriorityConfig() {
// Note: ConfigManager integration for source priority loading would require async support
// For now, we rely on environment variables and defaults
// Future enhancement: Add async getSourcePriorityConfigAsync() that can load from ConfigManager
// Environment variable support for testing
if (process.env.SOURCE_PRIORITY) {
try {
const envConfig = JSON.parse(process.env.SOURCE_PRIORITY);
const validation = validateSourcePriority(envConfig);
if (validation.isValid) {
return envConfig;
}
logger.warn('SOURCE_PRIORITY environment variable contains invalid configuration, using defaults');
}
catch (error) {
// Invalid JSON in environment variable, fall through to default
logger.warn('Failed to parse SOURCE_PRIORITY environment variable, using defaults', { error: error instanceof Error ? error.message : String(error) });
}
}
// Return default configuration
return DEFAULT_SOURCE_PRIORITY;
}
/**
* Pre-computed list of valid element sources
* Used for validation to avoid repeated Object.values() calls
* @private
*/
const VALID_SOURCES = Object.values(ElementSource);
/**
* Validate source priority configuration
*
* Checks for:
* - Empty priority list
* - Duplicate sources
* - Unknown/invalid sources
*
* @param {SourcePriorityConfig} config - The configuration to validate
* @returns {ValidationResult} Validation result with error messages
*
* @example
* // Validate a valid configuration
* const config = {
* priority: [ElementSource.LOCAL, ElementSource.GITHUB],
* stopOnFirst: true,
* checkAllForUpdates: false,
* fallbackOnError: true
* };
* const result = validateSourcePriority(config);
* console.log(result.isValid); // true
* console.log(result.errors); // []
*
* @example
* // Validate an invalid configuration (duplicate sources)
* const config = {
* priority: [ElementSource.LOCAL, ElementSource.LOCAL],
* stopOnFirst: true,
* checkAllForUpdates: false,
* fallbackOnError: true
* };
* const result = validateSourcePriority(config);
* console.log(result.isValid); // false
* console.log(result.errors); // ['Duplicate sources in priority list']
*
* @example
* // Validate an invalid configuration (empty priority)
* const config = {
* priority: [],
* stopOnFirst: true,
* checkAllForUpdates: false,
* fallbackOnError: true
* };
* const result = validateSourcePriority(config);
* console.log(result.isValid); // false
* console.log(result.errors); // ['Priority list cannot be empty']
*/
export function validateSourcePriority(config) {
const errors = [];
// Check for empty priority list
if (!config.priority || config.priority.length === 0) {
errors.push('Priority list cannot be empty');
// Return early to avoid null/undefined errors in subsequent checks
return {
isValid: false,
errors
};
}
// Check for duplicate sources
const uniqueSources = new Set(config.priority);
if (uniqueSources.size !== config.priority.length) {
errors.push('Duplicate sources in priority list');
}
// Check for unknown sources using pre-computed valid sources list
for (const source of config.priority) {
if (!VALID_SOURCES.includes(source)) {
errors.push(`Unknown source: ${source}`);
}
}
return {
isValid: errors.length === 0,
errors
};
}
/**
* Save source priority configuration to config file
*
* Validates the configuration before saving and persists it via ConfigManager.
* The configuration will be saved to ~/.dollhouse/config.yml under the
* source_priority key.
*
* @param {SourcePriorityConfig} config - The source priority configuration to save
* @returns {Promise<void>}
* @throws {Error} If configuration is invalid or save fails
*
* @example
* // Save a custom configuration
* await saveSourcePriorityConfig({
* priority: [ElementSource.GITHUB, ElementSource.LOCAL, ElementSource.COLLECTION],
* stopOnFirst: false,
* checkAllForUpdates: true,
* fallbackOnError: true
* });
*
* @example
* // Validate before saving
* const config = {
* priority: [ElementSource.LOCAL, ElementSource.GITHUB],
* stopOnFirst: true,
* checkAllForUpdates: false,
* fallbackOnError: true
* };
* const validation = validateSourcePriority(config);
* if (validation.isValid) {
* await saveSourcePriorityConfig(config);
* }
*/
export async function saveSourcePriorityConfig(config) {
// Validate configuration before saving
const validation = validateSourcePriority(config);
if (!validation.isValid) {
throw new Error(`Invalid source priority configuration: ${validation.errors.join(', ')}`);
}
// Dynamic imports to avoid circular dependency (ESM-compatible)
const { ConfigManager } = await import('./ConfigManager.js');
const { FileOperationsService } = await import('../services/FileOperationsService.js');
const { FileLockManager } = await import('../security/fileLockManager.js');
const os = await import('os');
const fileLockManager = new FileLockManager();
const fileOperations = new FileOperationsService(fileLockManager);
const configManager = new ConfigManager(fileOperations, os);
// Save to config file using ConfigManager
await configManager.updateSetting('source_priority', config);
}
/**
* Get user-friendly display name for an element source
*
* Maps ElementSource enum values to human-readable names suitable for
* user-facing messages, logs, and documentation.
*
* @param {ElementSource} source - The source to get display name for
* @returns {string} User-friendly display name
* @throws {Error} If source is not a valid ElementSource value
*
* @example
* // Get display names for all sources
* console.log(getSourceDisplayName(ElementSource.LOCAL)); // "Local Portfolio"
* console.log(getSourceDisplayName(ElementSource.GITHUB)); // "GitHub Portfolio"
* console.log(getSourceDisplayName(ElementSource.COLLECTION)); // "Community Collection"
*
* @example
* // Use in a log message
* const source = ElementSource.LOCAL;
* console.log(`Found element in ${getSourceDisplayName(source)}`);
* // Output: "Found element in Local Portfolio"
*
* @example
* // Generate a source list for user display
* const config = getSourcePriorityConfig();
* const sourceNames = config.priority.map(s => getSourceDisplayName(s)).join(' → ');
* console.log(`Search order: ${sourceNames}`);
* // Output: "Search order: Local Portfolio → GitHub Portfolio → Community Collection"
*/
export function getSourceDisplayName(source) {
const names = {
[ElementSource.LOCAL]: 'Local Portfolio',
[ElementSource.GITHUB]: 'GitHub Portfolio',
[ElementSource.COLLECTION]: 'Community Collection'
};
// Type-safe fallback for invalid sources
const displayName = names[source];
if (displayName === undefined) {
throw new Error(`Invalid element source: ${source}. Expected one of: ${VALID_SOURCES.join(', ')}`);
}
return displayName;
}
/**
* Parse a single item from source priority array
*
* Converts a single source item (string or ElementSource) to a validated
* ElementSource enum value. Handles both string names (case-insensitive)
* and ElementSource enum values.
*
* @param {unknown} item - Item to parse (string source name or ElementSource value)
* @returns {ElementSource} Validated ElementSource enum value
* @throws {Error} If item is not a valid source
* @private
*
* @example
* // Parse from lowercase string
* parseSourceItem('local'); // Returns: ElementSource.LOCAL
*
* @example
* // Parse from ElementSource value
* parseSourceItem(ElementSource.GITHUB); // Returns: ElementSource.GITHUB
*
* @example
* // Invalid source throws error
* parseSourceItem('invalid'); // Throws: Unknown source: invalid
*/
function parseSourceItem(item) {
// Handle string input (case-insensitive)
if (typeof item === 'string') {
const lowerItem = item.toLowerCase();
if (VALID_SOURCES.includes(lowerItem)) {
return lowerItem;
}
throw new Error(`Unknown source: ${item}. Valid sources: ${VALID_SOURCES.join(', ')}`);
}
// Handle ElementSource enum value
if (Object.values(ElementSource).includes(item)) {
return item;
}
// Invalid type or value
throw new Error(`Invalid source value: ${item}`);
}
/**
* Parse source priority order from various input formats
*
* Accepts arrays of ElementSource values or string source names and
* normalizes them to an array of ElementSource enum values.
*
* @param {unknown} value - The value to parse (array of sources or JSON string)
* @returns {ElementSource[]} Parsed array of element sources
* @throws {Error} If value cannot be parsed or contains invalid sources
*
* @example
* // Parse from array of strings
* const order = parseSourcePriorityOrder(['local', 'github', 'collection']);
* // Returns: [ElementSource.LOCAL, ElementSource.GITHUB, ElementSource.COLLECTION]
*
* @example
* // Parse from JSON string
* const order = parseSourcePriorityOrder('["github", "local"]');
* // Returns: [ElementSource.GITHUB, ElementSource.LOCAL]
*
* @example
* // Parse from ElementSource values
* const order = parseSourcePriorityOrder([ElementSource.LOCAL, ElementSource.GITHUB]);
* // Returns: [ElementSource.LOCAL, ElementSource.GITHUB]
*/
export function parseSourcePriorityOrder(value) {
// Handle string input (JSON array)
if (typeof value === 'string') {
try {
value = JSON.parse(value);
}
catch (error) {
throw new Error(`Invalid JSON in source priority order: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Ensure we have an array
if (!Array.isArray(value)) {
throw new TypeError('Source priority order must be an array');
}
// Convert each item to ElementSource enum value
return value.map(item => parseSourceItem(item));
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlUHJpb3JpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uZmlnL3NvdXJjZVByaW9yaXR5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBRUgsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRTVDOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBTixJQUFZLGFBU1g7QUFURCxXQUFZLGFBQWE7SUFDdkIsZ0RBQWdEO0lBQ2hELGdDQUFlLENBQUE7SUFFZix5Q0FBeUM7SUFDekMsa0NBQWlCLENBQUE7SUFFakIsd0NBQXdDO0lBQ3hDLDBDQUF5QixDQUFBO0FBQzNCLENBQUMsRUFUVyxhQUFhLEtBQWIsYUFBYSxRQVN4QjtBQXFFRDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBeUI7SUFDM0QsUUFBUSxFQUFFLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxhQUFhLENBQUMsTUFBTSxFQUFFLGFBQWEsQ0FBQyxVQUFVLENBQUM7SUFDL0UsV0FBVyxFQUFFLElBQUk7SUFDakIsa0JBQWtCLEVBQUUsS0FBSztJQUN6QixlQUFlLEVBQUUsSUFBSTtDQUN0QixDQUFDO0FBRUY7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMEJHO0FBQ0gsTUFBTSxVQUFVLHVCQUF1QjtJQUNyQywwRkFBMEY7SUFDMUYseURBQXlEO0lBQ3pELGdHQUFnRztJQUVoRywyQ0FBMkM7SUFDM0MsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ2hDLElBQUksQ0FBQztZQUNILE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUMxRCxNQUFNLFVBQVUsR0FBRyxzQkFBc0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUNyRCxJQUFJLFVBQVUsQ0FBQyxP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ZXNDb250ZW50IjpbIi8qKlxuICogRWxlbWVudCBzb3VyY2UgcHJpb3JpdHkgY29uZmlndXJhdGlvblxuICpcbiAqIFRoaXMgbW9kdWxlIGRlZmluZXMgdGhlIGNlbnRyYWxpemVkIGNvbmZpZ3VyYXRpb24gZm9yIGVsZW1lbnQgc291cmNpbmcgcHJpb3JpdHksXG4gKiBkZXRlcm1pbmluZyB0aGUgb3JkZXIgaW4gd2hpY2ggZWxlbWVudCBzb3VyY2VzIChsb2NhbCwgR2l0SHViLCBjb2xsZWN0aW9uKSBhcmVcbiAqIGNoZWNrZWQgd2hlbiBzZWFyY2hpbmcgZm9yIG9yIGluc3RhbGxpbmcgZWxlbWVudHMuXG4gKlxuICogQG1vZHVsZSBjb25maWcvc291cmNlUHJpb3JpdHlcbiAqL1xuXG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuXG4vKipcbiAqIEVudW1lcmF0aW9uIG9mIGF2YWlsYWJsZSBlbGVtZW50IHNvdXJjZXNcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gVXNpbmcgRWxlbWVudFNvdXJjZSBpbiBjb25maWd1cmF0aW9uXG4gKiBjb25zdCBwcmlvcml0eSA9IFtFbGVtZW50U291cmNlLkxPQ0FMLCBFbGVtZW50U291cmNlLkdJVEhVQiwgRWxlbWVudFNvdXJjZS5DT0xMRUNUSU9OXTtcbiAqL1xuZXhwb3J0IGVudW0gRWxlbWVudFNvdXJjZSB7XG4gIC8qKiBMb2NhbCBwb3J0Zm9saW8gKH4vLmRvbGxob3VzZS9wb3J0Zm9saW8vKSAqL1xuICBMT0NBTCA9ICdsb2NhbCcsXG5cbiAgLyoqIFVzZXIncyBHaXRIdWIgcG9ydGZvbGlvIHJlcG9zaXRvcnkgKi9cbiAgR0lUSFVCID0gJ2dpdGh1YicsXG5cbiAgLyoqIERvbGxob3VzZU1DUCBjb21tdW5pdHkgY29sbGVjdGlvbiAqL1xuICBDT0xMRUNUSU9OID0gJ2NvbGxlY3Rpb24nXG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBmb3IgZWxlbWVudCBzb3VyY2UgcHJpb3JpdHlcbiAqXG4gKiBAaW50ZXJmYWNlIFNvdXJjZVByaW9yaXR5Q29uZmlnXG4gKiBAcHJvcGVydHkge0VsZW1lbnRTb3VyY2VbXX0gcHJpb3JpdHkgLSBPcmRlcmVkIGxpc3Qgb2Ygc291cmNlcyB0byBjaGVjayAoZmlyc3QgPSBoaWdoZXN0IHByaW9yaXR5KVxuICogQHByb3BlcnR5IHtib29sZWFufSBzdG9wT25GaXJzdCAtIFdoZXRoZXIgdG8gc3RvcCBzZWFyY2hpbmcgYWZ0ZXIgZmluZGluZyBlbGVtZW50IGluIGZpcnN0IHNvdXJjZVxuICogQHByb3BlcnR5IHtib29sZWFufSBjaGVja0FsbEZvclVwZGF0ZXMgLSBXaGV0aGVyIHRvIGNoZWNrIGFsbCBzb3VyY2VzIGZvciB2ZXJzaW9uIGNvbXBhcmlzb25cbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gZmFsbGJhY2tPbkVycm9yIC0gV2hldGhlciB0byB0cnkgbmV4dCBzb3VyY2Ugd2hlbiBjdXJyZW50IHNvdXJjZSBmYWlsc1xuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBEZWZhdWx0IGNvbmZpZ3VyYXRpb24gKGxvY2FsIOKGkiBHaXRIdWIg4oaSIGNvbGxlY3Rpb24pXG4gKiBjb25zdCBjb25maWc6IFNvdXJjZVByaW9yaXR5Q29uZmlnID0ge1xuICogICBwcmlvcml0eTogW0VsZW1lbnRTb3VyY2UuTE9DQUwsIEVsZW1lbnRTb3VyY2UuR0lUSFVCLCBFbGVtZW50U291cmNlLkNPTExFQ1RJT05dLFxuICogICBzdG9wT25GaXJzdDogdHJ1ZSxcbiAqICAgY2hlY2tBbGxGb3JVcGRhdGVzOiBmYWxzZSxcbiAqICAgZmFsbGJhY2tPbkVycm9yOiB0cnVlXG4gKiB9O1xuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBDdXN0b20gY29uZmlndXJhdGlvbiAoY29sbGVjdGlvbi1maXJzdCBmb3IgZGlzY292ZXJ5KVxuICogY29uc3QgY29uZmlnOiBTb3VyY2VQcmlvcml0eUNvbmZpZyA9IHtcbiAqICAgcHJpb3JpdHk6IFtFbGVtZW50U291cmNlLkNPTExFQ1RJT04sIEVsZW1lbnRTb3VyY2UuTE9DQUwsIEVsZW1lbnRTb3VyY2UuR0lUSFVCXSxcbiAqICAgc3RvcE9uRmlyc3Q6IGZhbHNlLFxuICogICBjaGVja0FsbEZvclVwZGF0ZXM6IHRydWUsXG4gKiAgIGZhbGxiYWNrT25FcnJvcjogdHJ1ZVxuICogfTtcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTb3VyY2VQcmlvcml0eUNvbmZpZyB7XG4gIC8qKlxuICAgKiBPcmRlcmVkIGxpc3Qgb2Ygc291cmNlcyB0byBjaGVjayAoZmlyc3QgPSBoaWdoZXN0IHByaW9yaXR5KVxuICAgKlxuICAgKiBUaGUgc3lzdGVtIHdpbGwgY2hlY2sgc291cmNlcyBpbiB0aGlzIG9yZGVyLCBzdG9wcGluZyBlYXJseSBpZlxuICAgKiBzdG9wT25GaXJzdCBpcyB0cnVlIGFuZCBhbiBlbGVtZW50IGlzIGZvdW5kLlxuICAgKi9cbiAgcHJpb3JpdHk6IEVsZW1lbnRTb3VyY2VbXTtcblxuICAvKipcbiAgICogV2hldGhlciB0byBzdG9wIHNlYXJjaGluZyBhZnRlciBmaW5kaW5nIGVsZW1lbnQgaW4gZmlyc3Qgc291cmNlXG4gICAqXG4gICAqIFdoZW4gdHJ1ZSwgdGhlIHNlYXJjaCB0ZXJtaW5hdGVzIGFzIHNvb24gYXMgYW4gZWxlbWVudCBpcyBmb3VuZCBpblxuICAgKiBhbnkgc291cmNlLiBXaGVuIGZhbHNlLCBhbGwgZW5hYmxlZCBzb3VyY2VzIGFyZSBzZWFyY2hlZC5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgc3RvcE9uRmlyc3Q6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gY2hlY2sgYWxsIHNvdXJjZXMgZm9yIHZlcnNpb24gY29tcGFyaXNvblxuICAgKlxuICAgKiBXaGVuIHRydWUsIGFsbCBzb3VyY2VzIGFyZSBjaGVja2VkIHRvIGZpbmQgdGhlIGxhdGVzdCB2ZXJzaW9uLFxuICAgKiBldmVuIGlmIHN0b3BPbkZpcnN0IGlzIHRydWUuIFVzZWZ1bCBmb3IgZGV0ZWN0aW5nIHVwZGF0ZXMuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICBjaGVja0FsbEZvclVwZGF0ZXM6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gdHJ5IG5leHQgc291cmNlIHdoZW4gY3VycmVudCBzb3VyY2UgZmFpbHNcbiAgICpcbiAgICogV2hlbiB0cnVlLCBlcnJvcnMgaW4gb25lIHNvdXJjZSB3b24ndCBwcmV2ZW50IHNlYXJjaGluZyBvdGhlciBzb3VyY2VzLlxuICAgKiBXaGVuIGZhbHNlLCBhbnkgc291cmNlIGVycm9yIHdpbGwgaGFsdCB0aGUgc2VhcmNoIGFuZCByZXR1cm4gdGhlIGVycm9yLlxuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICBmYWxsYmFja09uRXJyb3I6IGJvb2xlYW47XG59XG5cbi8qKlxuICogRGVmYXVsdCBzb3VyY2UgcHJpb3JpdHkgY29uZmlndXJhdGlvblxuICpcbiAqIFByaW9yaXR5IG9yZGVyOiBMb2NhbCDihpIgR2l0SHViIOKGkiBDb2xsZWN0aW9uXG4gKiBUaGlzIGVuc3VyZXMgdXNlcnMnIGxvY2FsIGN1c3RvbWl6YXRpb25zIHRha2UgcHJlY2VkZW5jZSBvdmVyIHJlbW90ZSBzb3VyY2VzLlxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBVc2luZyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uXG4gKiBpbXBvcnQgeyBERUZBVUxUX1NPVVJDRV9QUklPUklUWSB9IGZyb20gJy4vc291cmNlUHJpb3JpdHkuanMnO1xuICpcbiAqIGNvbnN0IGNvbmZpZyA9IERFRkFVTFRfU09VUkNFX1BSSU9SSVRZO1xuICogY29uc29sZS5sb2coY29uZmlnLnByaW9yaXR5KTsgLy8gW0VsZW1lbnRTb3VyY2UuTE9DQUwsIEVsZW1lbnRTb3VyY2UuR0lUSFVCLCBFbGVtZW50U291cmNlLkNPTExFQ1RJT05dXG4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX1NPVVJDRV9QUklPUklUWTogU291cmNlUHJpb3JpdHlDb25maWcgPSB7XG4gIHByaW9yaXR5OiBbRWxlbWVudFNvdXJjZS5MT0NBTCwgRWxlbWVudFNvdXJjZS5HSVRIVUIsIEVsZW1lbnRTb3VyY2UuQ09MTEVDVElPTl0sXG4gIHN0b3BPbkZpcnN0OiB0cnVlLFxuICBjaGVja0FsbEZvclVwZGF0ZXM6IGZhbHNlLFxuICBmYWxsYmFja09uRXJyb3I6IHRydWVcbn07XG5cbi8qKlxuICogR2V0IGN1cnJlbnQgc291cmNlIHByaW9yaXR5IGNvbmZpZ3VyYXRpb25cbiAqXG4gKiBQcmlvcml0eSBvcmRlciBmb3IgY29uZmlndXJhdGlvbiBzb3VyY2VzOlxuICogMS4gVXNlciBjb25maWd1cmF0aW9uIChmcm9tIGNvbmZpZyBmaWxlKVxuICogMi4gRW52aXJvbm1lbnQgdmFyaWFibGVzIChmb3IgdGVzdGluZylcbiAqIDMuIERlZmF1bHQgY29uZmlndXJhdGlvblxuICpcbiAqIEByZXR1cm5zIHtTb3VyY2VQcmlvcml0eUNvbmZpZ30gVGhlIGN1cnJlbnQgc291cmNlIHByaW9yaXR5IGNvbmZpZ3VyYXRpb25cbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gR2V0IHRoZSBjdXJyZW50IGNvbmZpZ3VyYXRpb25cbiAqIGltcG9ydCB7IGdldFNvdXJjZVByaW9yaXR5Q29uZmlnIH0gZnJvbSAnLi9zb3VyY2VQcmlvcml0eS5qcyc7XG4gKlxuICogY29uc3QgY29uZmlnID0gZ2V0U291cmNlUHJpb3JpdHlDb25maWcoKTtcbiAqIGNvbnNvbGUubG9nKGNvbmZpZy5wcmlvcml0eSk7IC8vIFtFbGVtZW50U291cmNlLkxPQ0FMLCBFbGVtZW50U291cmNlLkdJVEhVQiwgRWxlbWVudFNvdXJjZS5DT0xMRUNUSU9OXVxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBVc2UgaW4gYSBzZWFyY2ggb3BlcmF0aW9uXG4gKiBjb25zdCBjb25maWcgPSBnZXRTb3VyY2VQcmlvcml0eUNvbmZpZygpO1xuICogZm9yIChjb25zdCBzb3VyY2Ugb2YgY29uZmlnLnByaW9yaXR5KSB7XG4gKiAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBzZWFyY2hTb3VyY2Uoc291cmNlKTtcbiAqICAgaWYgKHJlc3VsdHMubGVuZ3RoID4gMCAmJiBjb25maWcuc3RvcE9uRmlyc3QpIHtcbiAqICAgICBicmVhaztcbiAqICAgfVxuICogfVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U291cmNlUHJpb3JpdHlDb25maWcoKTogU291cmNlUHJpb3JpdHlDb25maWcge1xuICAvLyBOb3RlOiBDb25maWdNYW5hZ2VyIGludGVncmF0aW9uIGZvciBzb3VyY2UgcHJpb3JpdHkgbG9hZGluZyB3b3VsZCByZXF1aXJlIGFzeW5jIHN1cHBvcnRcbiAgLy8gRm9yIG5vdywgd2UgcmVseSBvbiBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYW5kIGRlZmF1bHRzXG4gIC8vIEZ1dHVyZSBlbmhhbmNlbWVudDogQWRkIGFzeW5jIGdldFNvdXJjZVByaW9yaXR5Q29uZmlnQXN5bmMoKSB0aGF0IGNhbiBsb2FkIGZyb20gQ29uZmlnTWFuYWdlclxuXG4gIC8vIEVudmlyb25tZW50IHZhcmlhYmxlIHN1cHBvcnQgZm9yIHRlc3RpbmdcbiAgaWYgKHByb2Nlc3MuZW52LlNPVVJDRV9QUklPUklUWSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBlbnZDb25maWcgPSBKU09OLnBhcnNlKHByb2Nlc3MuZW52LlNPVVJDRV9QUklPUklUWSk7XG4gICAgICBjb25zdCB2YWxpZGF0aW9uID0gdmFsaWRhdGVTb3VyY2VQcmlvcml0eShlbnZDb25maWcpO1xuICAgICAgaWYgKHZhbGlkYXRpb24uaXNWYWxpZCkge1xuICAgICAgICByZXR1cm4gZW52Q29uZmlnO1xuICAgICAgfVxuICAgICAgbG9nZ2VyLndhcm4oJ1NPVVJDRV9QUklPUklUWSBlbnZpcm9ubWVudCB2YXJpYWJsZSBjb250YWlucyBpbnZhbGlkIGNvbmZpZ3VyYXRpb24sIHVzaW5nIGRlZmF1bHRzJyk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIEludmFsaWQgSlNPTiBpbiBlbnZpcm9ubWVudCB2YXJpYWJsZSwgZmFsbCB0aHJvdWdoIHRvIGRlZmF1bHRcbiAgICAgIGxvZ2dlci53YXJuKCdGYWlsZWQgdG8gcGFyc2UgU09VUkNFX1BSSU9SSVRZIGVudmlyb25tZW50IHZhcmlhYmxlLCB1c2luZyBkZWZhdWx0cycsIHsgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSB9KTtcbiAgICB9XG4gIH1cblxuICAvLyBSZXR1cm4gZGVmYXVsdCBjb25maWd1cmF0aW9uXG4gIHJldHVybiBERUZBVUxUX1NPVVJDRV9QUklPUklUWTtcbn1cblxuLyoqXG4gKiBWYWxpZGF0aW9uIHJlc3VsdCBmb3Igc291cmNlIHByaW9yaXR5IGNvbmZpZ3VyYXRpb25cbiAqXG4gKiBAaW50ZXJmYWNlIFZhbGlkYXRpb25SZXN1bHRcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gaXNWYWxpZCAtIFdoZXRoZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgdmFsaWRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IGVycm9ycyAtIExpc3Qgb2YgdmFsaWRhdGlvbiBlcnJvciBtZXNzYWdlcyAoZW1wdHkgaWYgdmFsaWQpXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVmFsaWRhdGlvblJlc3VsdCB7XG4gIGlzVmFsaWQ6IGJvb2xlYW47XG4gIGVycm9yczogc3RyaW5nW107XG59XG5cbi8qKlxuICogUHJlLWNvbXB1dGVkIGxpc3Qgb2YgdmFsaWQgZWxlbWVudCBzb3VyY2VzXG4gKiBVc2VkIGZvciB2YWxpZGF0aW9uIHRvIGF2b2lkIHJlcGVhdGVkIE9iamVjdC52YWx1ZXMoKSBjYWxsc1xuICogQHByaXZhdGVcbiAqL1xuY29uc3QgVkFMSURfU09VUkNFUzogRWxlbWVudFNvdXJjZVtdID0gT2JqZWN0LnZhbHVlcyhFbGVtZW50U291cmNlKTtcblxuLyoqXG4gKiBWYWxpZGF0ZSBzb3VyY2UgcHJpb3JpdHkgY29uZmlndXJhdGlvblxuICpcbiAqIENoZWNrcyBmb3I6XG4gKiAtIEVtcHR5IHByaW9yaXR5IGxpc3RcbiAqIC0gRHVwbGljYXRlIHNvdXJjZXNcbiAqIC0gVW5rbm93bi9pbnZhbGlkIHNvdXJjZXNcbiAqXG4gKiBAcGFyYW0ge1NvdXJjZVByaW9yaXR5Q29uZmlnfSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiB0byB2YWxpZGF0ZVxuICogQHJldHVybnMge1ZhbGlkYXRpb25SZXN1bHR9IFZhbGlkYXRpb24gcmVzdWx0IHdpdGggZXJyb3IgbWVzc2FnZXNcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gVmFsaWRhdGUgYSB2YWxpZCBjb25maWd1cmF0aW9uXG4gKiBjb25zdCBjb25maWcgPSB7XG4gKiAgIHByaW9yaXR5OiBbRWxlbWVudFNvdXJjZS5MT0NBTCwgRWxlbWVudFNvdXJjZS5HSVRIVUJdLFxuICogICBzdG9wT25GaXJzdDogdHJ1ZSxcbiAqICAgY2hlY2tBbGxGb3JVcGRhdGVzOiBmYWxzZSxcbiAqICAgZmFsbGJhY2tPbkVycm9yOiB0cnVlXG4gKiB9O1xuICogY29uc3QgcmVzdWx0ID0gdmFsaWRhdGVTb3VyY2VQcmlvcml0eShjb25maWcpO1xuICogY29uc29sZS5sb2cocmVzdWx0LmlzVmFsaWQpOyAvLyB0cnVlXG4gKiBjb25zb2xlLmxvZyhyZXN1bHQuZXJyb3JzKTsgLy8gW11cbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gVmFsaWRhdGUgYW4gaW52YWxpZCBjb25maWd1cmF0aW9uIChkdXBsaWNhdGUgc291cmNlcylcbiAqIGNvbnN0IGNvbmZpZyA9IHtcbiAqICAgcHJpb3JpdHk6IFtFbGVtZW50U291cmNlLkxPQ0FMLCBFbGVtZW50U291cmNlLkxPQ0FMXSxcbiAqICAgc3RvcE9uRmlyc3Q6IHRydWUsXG4gKiAgIGNoZWNrQWxsRm9yVXBkYXRlczogZmFsc2UsXG4gKiAgIGZhbGxiYWNrT25FcnJvcjogdHJ1ZVxuICogfTtcbiAqIGNvbnN0IHJlc3VsdCA9IHZhbGlkYXRlU291cmNlUHJpb3JpdHkoY29uZmlnKTtcbiAqIGNvbnNvbGUubG9nKHJlc3VsdC5pc1ZhbGlkKTsgLy8gZmFsc2VcbiAqIGNvbnNvbGUubG9nKHJlc3VsdC5lcnJvcnMpOyAvLyBbJ0R1cGxpY2F0ZSBzb3VyY2VzIGluIHByaW9yaXR5IGxpc3QnXVxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBWYWxpZGF0ZSBhbiBpbnZhbGlkIGNvbmZpZ3VyYXRpb24gKGVtcHR5IHByaW9yaXR5KVxuICogY29uc3QgY29uZmlnID0ge1xuICogICBwcmlvcml0eTogW10sXG4gKiAgIHN0b3BPbkZpcnN0OiB0cnVlLFxuICogICBjaGVja0FsbEZvclVwZGF0ZXM6IGZhbHNlLFxuICogICBmYWxsYmFja09uRXJyb3I6IHRydWVcbiAqIH07XG4gKiBjb25zdCByZXN1bHQgPSB2YWxpZGF0ZVNvdXJjZVByaW9yaXR5KGNvbmZpZyk7XG4gKiBjb25zb2xlLmxvZyhyZXN1bHQuaXNWYWxpZCk7IC8vIGZhbHNlXG4gKiBjb25zb2xlLmxvZyhyZXN1bHQuZXJyb3JzKTsgLy8gWydQcmlvcml0eSBsaXN0IGNhbm5vdCBiZSBlbXB0eSddXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZVNvdXJjZVByaW9yaXR5KGNvbmZpZzogU291cmNlUHJpb3JpdHlDb25maWcpOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgY29uc3QgZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIC8vIENoZWNrIGZvciBlbXB0eSBwcmlvcml0eSBsaXN0XG4gIGlmICghY29uZmlnLnByaW9yaXR5IHx8IGNvbmZpZy5wcmlvcml0eS5sZW5ndGggPT09IDApIHtcbiAgICBlcnJvcnMucHVzaCgnUHJpb3JpdHkgbGlzdCBjYW5ub3QgYmUgZW1wdHknKTtcbiAgICAvLyBSZXR1cm4gZWFybHkgdG8gYXZvaWQgbnVsbC91bmRlZmluZWQgZXJyb3JzIGluIHN1YnNlcXVlbnQgY2hlY2tzXG4gICAgcmV0dXJuIHtcbiAgICAgIGlzVmFsaWQ6IGZhbHNlLFxuICAgICAgZXJyb3JzXG4gICAgfTtcbiAgfVxuXG4gIC8vIENoZWNrIGZvciBkdXBsaWNhdGUgc291cmNlc1xuICBjb25zdCB1bmlxdWVTb3VyY2VzID0gbmV3IFNldChjb25maWcucHJpb3JpdHkpO1xuICBpZiAodW5pcXVlU291cmNlcy5zaXplICE9PSBjb25maWcucHJpb3JpdHkubGVuZ3RoKSB7XG4gICAgZXJyb3JzLnB1c2goJ0R1cGxpY2F0ZSBzb3VyY2VzIGluIHByaW9yaXR5IGxpc3QnKTtcbiAgfVxuXG4gIC8vIENoZWNrIGZvciB1bmtub3duIHNvdXJjZXMgdXNpbmcgcHJlLWNvbXB1dGVkIHZhbGlkIHNvdXJjZXMgbGlzdFxuICBmb3IgKGNvbnN0IHNvdXJjZSBvZiBjb25maWcucHJpb3JpdHkpIHtcbiAgICBpZiAoIVZBTElEX1NPVVJDRVMuaW5jbHVkZXMoc291cmNlKSkge1xuICAgICAgZXJyb3JzLnB1c2goYFVua25vd24gc291cmNlOiAke3NvdXJjZX1gKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIGlzVmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsXG4gICAgZXJyb3JzXG4gIH07XG59XG5cbi8qKlxuICogU2F2ZSBzb3VyY2UgcHJpb3JpdHkgY29uZmlndXJhdGlvbiB0byBjb25maWcgZmlsZVxuICpcbiAqIFZhbGlkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBiZWZvcmUgc2F2aW5nIGFuZCBwZXJzaXN0cyBpdCB2aWEgQ29uZmlnTWFuYWdlci5cbiAqIFRoZSBjb25maWd1cmF0aW9uIHdpbGwgYmUgc2F2ZWQgdG8gfi8uZG9sbGhvdXNlL2NvbmZpZy55bWwgdW5kZXIgdGhlXG4gKiBzb3VyY2VfcHJpb3JpdHkga2V5LlxuICpcbiAqIEBwYXJhbSB7U291cmNlUHJpb3JpdHlDb25maWd9IGNvbmZpZyAtIFRoZSBzb3VyY2UgcHJpb3JpdHkgY29uZmlndXJhdGlvbiB0byBzYXZlXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiBjb25maWd1cmF0aW9uIGlzIGludmFsaWQgb3Igc2F2ZSBmYWlsc1xuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBTYXZlIGEgY3VzdG9tIGNvbmZpZ3VyYXRpb25cbiAqIGF3YWl0IHNhdmVTb3VyY2VQcmlvcml0eUNvbmZpZyh7XG4gKiAgIHByaW9yaXR5OiBbRWxlbWVudFNvdXJjZS5HSVRIVUIsIEVsZW1lbnRTb3VyY2UuTE9DQUwsIEVsZW1lbnRTb3VyY2UuQ09MTEVDVElPTl0sXG4gKiAgIHN0b3BPbkZpcnN0OiBmYWxzZSxcbiAqICAgY2hlY2tBbGxGb3JVcGRhdGVzOiB0cnVlLFxuICogICBmYWxsYmFja09uRXJyb3I6IHRydWVcbiAqIH0pO1xuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBWYWxpZGF0ZSBiZWZvcmUgc2F2aW5nXG4gKiBjb25zdCBjb25maWcgPSB7XG4gKiAgIHByaW9yaXR5OiBbRWxlbWVudFNvdXJjZS5MT0NBTCwgRWxlbWVudFNvdXJjZS5HSVRIVUJdLFxuICogICBzdG9wT25GaXJzdDogdHJ1ZSxcbiAqICAgY2hlY2tBbGxGb3JVcGRhdGVzOiBmYWxzZSxcbiAqICAgZmFsbGJhY2tPbkVycm9yOiB0cnVlXG4gKiB9O1xuICogY29uc3QgdmFsaWRhdGlvbiA9IHZhbGlkYXRlU291cmNlUHJpb3JpdHkoY29uZmlnKTtcbiAqIGlmICh2YWxpZGF0aW9uLmlzVmFsaWQpIHtcbiAqICAgYXdhaXQgc2F2ZVNvdXJjZVByaW9yaXR5Q29uZmlnKGNvbmZpZyk7XG4gKiB9XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzYXZlU291cmNlUHJpb3JpdHlDb25maWcoY29uZmlnOiBTb3VyY2VQcmlvcml0eUNvbmZpZyk6IFByb21pc2U8dm9pZD4ge1xuICAvLyBWYWxpZGF0ZSBjb25maWd1cmF0aW9uIGJlZm9yZSBzYXZpbmdcbiAgY29uc3QgdmFsaWRhdGlvbiA9IHZhbGlkYXRlU291cmNlUHJpb3JpdHkoY29uZmlnKTtcbiAgaWYgKCF2YWxpZGF0aW9uLmlzVmFsaWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc291cmNlIHByaW9yaXR5IGNvbmZpZ3VyYXRpb246ICR7dmFsaWRhdGlvbi5lcnJvcnMuam9pbignLCAnKX1gKTtcbiAgfVxuXG4gIC8vIER5bmFtaWMgaW1wb3J0cyB0byBhdm9pZCBjaXJjdWxhciBkZXBlbmRlbmN5IChFU00tY29tcGF0aWJsZSlcbiAgY29uc3QgeyBDb25maWdNYW5hZ2VyIH0gPSBhd2FpdCBpbXBvcnQoJy4vQ29uZmlnTWFuYWdlci5qcycpO1xuICBjb25zdCB7IEZpbGVPcGVyYXRpb25zU2VydmljZSB9ID0gYXdhaXQgaW1wb3J0KCcuLi9zZXJ2aWNlcy9GaWxlT3BlcmF0aW9uc1NlcnZpY2UuanMnKTtcbiAgY29uc3QgeyBGaWxlTG9ja01hbmFnZXIgfSA9IGF3YWl0IGltcG9ydCgnLi4vc2VjdXJpdHkvZmlsZUxvY2tNYW5hZ2VyLmpzJyk7XG4gIGNvbnN0IG9zID0gYXdhaXQgaW1wb3J0KCdvcycpO1xuXG4gIGNvbnN0IGZpbGVMb2NrTWFuYWdlciA9IG5ldyBGaWxlTG9ja01hbmFnZXIoKTtcbiAgY29uc3QgZmlsZU9wZXJhdGlvbnMgPSBuZXcgRmlsZU9wZXJhdGlvbnNTZXJ2aWNlKGZpbGVMb2NrTWFuYWdlcik7XG4gIGNvbnN0IGNvbmZpZ01hbmFnZXIgPSBuZXcgQ29uZmlnTWFuYWdlcihmaWxlT3BlcmF0aW9ucywgb3MpO1xuXG4gIC8vIFNhdmUgdG8gY29uZmlnIGZpbGUgdXNpbmcgQ29uZmlnTWFuYWdlclxuICBhd2FpdCBjb25maWdNYW5hZ2VyLnVwZGF0ZVNldHRpbmcoJ3NvdXJjZV9wcmlvcml0eScsIGNvbmZpZyk7XG59XG5cbi8qKlxuICogR2V0IHVzZXItZnJpZW5kbHkgZGlzcGxheSBuYW1lIGZvciBhbiBlbGVtZW50IHNvdXJjZVxuICpcbiAqIE1hcHMgRWxlbWVudFNvdXJjZSBlbnVtIHZhbHVlcyB0byBodW1hbi1yZWFkYWJsZSBuYW1lcyBzdWl0YWJsZSBmb3JcbiAqIHVzZXItZmFjaW5nIG1lc3NhZ2VzLCBsb2dzLCBhbmQgZG9jdW1lbnRhdGlvbi5cbiAqXG4gKiBAcGFyYW0ge0VsZW1lbnRTb3VyY2V9IHNvdXJjZSAtIFRoZSBzb3VyY2UgdG8gZ2V0IGRpc3BsYXkgbmFtZSBmb3JcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFVzZXItZnJpZW5kbHkgZGlzcGxheSBuYW1lXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgc291cmNlIGlzIG5vdCBhIHZhbGlkIEVsZW1lbnRTb3VyY2UgdmFsdWVcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gR2V0IGRpc3BsYXkgbmFtZXMgZm9yIGFsbCBzb3VyY2VzXG4gKiBjb25zb2xlLmxvZyhnZXRTb3VyY2VEaXNwbGF5TmFtZShFbGVtZW50U291cmNlLkxPQ0FMKSk7IC8vIFwiTG9jYWwgUG9ydGZvbGlvXCJcbiAqIGNvbnNvbGUubG9nKGdldFNvdXJjZURpc3BsYXlOYW1lKEVsZW1lbnRTb3VyY2UuR0lUSFVCKSk7IC8vIFwiR2l0SHViIFBvcnRmb2xpb1wiXG4gKiBjb25zb2xlLmxvZyhnZXRTb3VyY2VEaXNwbGF5TmFtZShFbGVtZW50U291cmNlLkNPTExFQ1RJT04pKTsgLy8gXCJDb21tdW5pdHkgQ29sbGVjdGlvblwiXG4gKlxuICogQGV4YW1wbGVcbiAqIC8vIFVzZSBpbiBhIGxvZyBtZXNzYWdlXG4gKiBjb25zdCBzb3VyY2UgPSBFbGVtZW50U291cmNlLkxPQ0FMO1xuICogY29uc29sZS5sb2coYEZvdW5kIGVsZW1lbnQgaW4gJHtnZXRTb3VyY2VEaXNwbGF5TmFtZShzb3VyY2UpfWApO1xuICogLy8gT3V0cHV0OiBcIkZvdW5kIGVsZW1lbnQgaW4gTG9jYWwgUG9ydGZvbGlvXCJcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gR2VuZXJhdGUgYSBzb3VyY2UgbGlzdCBmb3IgdXNlciBkaXNwbGF5XG4gKiBjb25zdCBjb25maWcgPSBnZXRTb3VyY2VQcmlvcml0eUNvbmZpZygpO1xuICogY29uc3Qgc291cmNlTmFtZXMgPSBjb25maWcucHJpb3JpdHkubWFwKHMgPT4gZ2V0U291cmNlRGlzcGxheU5hbWUocykpLmpvaW4oJyDihpIgJyk7XG4gKiBjb25zb2xlLmxvZyhgU2VhcmNoIG9yZGVyOiAke3NvdXJjZU5hbWVzfWApO1xuICogLy8gT3V0cHV0OiBcIlNlYXJjaCBvcmRlcjogTG9jYWwgUG9ydGZvbGlvIOKGkiBHaXRIdWIgUG9ydGZvbGlvIOKGkiBDb21tdW5pdHkgQ29sbGVjdGlvblwiXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTb3VyY2VEaXNwbGF5TmFtZShzb3VyY2U6IEVsZW1lbnRTb3VyY2UpOiBzdHJpbmcge1xuICBjb25zdCBuYW1lczogUmVjb3JkPEVsZW1lbnRTb3VyY2UsIHN0cmluZz4gPSB7XG4gICAgW0VsZW1lbnRTb3VyY2UuTE9DQUxdOiAnTG9jYWwgUG9ydGZvbGlvJyxcbiAgICBbRWxlbWVudFNvdXJjZS5HSVRIVUJdOiAnR2l0SHViIFBvcnRmb2xpbycsXG4gICAgW0VsZW1lbnRTb3VyY2UuQ09MTEVDVElPTl06ICdDb21tdW5pdHkgQ29sbGVjdGlvbidcbiAgfTtcblxuICAvLyBUeXBlLXNhZmUgZmFsbGJhY2sgZm9yIGludmFsaWQgc291cmNlc1xuICBjb25zdCBkaXNwbGF5TmFtZSA9IG5hbWVzW3NvdXJjZV07XG4gIGlmIChkaXNwbGF5TmFtZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGVsZW1lbnQgc291cmNlOiAke3NvdXJjZX0uIEV4cGVjdGVkIG9uZSBvZjogJHtWQUxJRF9TT1VSQ0VTLmpvaW4oJywgJyl9YCk7XG4gIH1cblxuICByZXR1cm4gZGlzcGxheU5hbWU7XG59XG5cbi8qKlxuICogUGFyc2UgYSBzaW5nbGUgaXRlbSBmcm9tIHNvdXJjZSBwcmlvcml0eSBhcnJheVxuICpcbiAqIENvbnZlcnRzIGEgc2luZ2xlIHNvdXJjZSBpdGVtIChzdHJpbmcgb3IgRWxlbWVudFNvdXJjZSkgdG8gYSB2YWxpZGF0ZWRcbiAqIEVsZW1lbnRTb3VyY2UgZW51bSB2YWx1ZS4gSGFuZGxlcyBib3RoIHN0cmluZyBuYW1lcyAoY2FzZS1pbnNlbnNpdGl2ZSlcbiAqIGFuZCBFbGVtZW50U291cmNlIGVudW0gdmFsdWVzLlxuICpcbiAqIEBwYXJhbSB7dW5rbm93bn0gaXRlbSAtIEl0ZW0gdG8gcGFyc2UgKHN0cmluZyBzb3VyY2UgbmFtZSBvciBFbGVtZW50U291cmNlIHZhbHVlKVxuICogQHJldHVybnMge0VsZW1lbnRTb3VyY2V9IFZhbGlkYXRlZCBFbGVtZW50U291cmNlIGVudW0gdmFsdWVcbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiBpdGVtIGlzIG5vdCBhIHZhbGlkIHNvdXJjZVxuICogQHByaXZhdGVcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gUGFyc2UgZnJvbSBsb3dlcmNhc2Ugc3RyaW5nXG4gKiBwYXJzZVNvdXJjZUl0ZW0oJ2xvY2FsJyk7IC8vIFJldHVybnM6IEVsZW1lbnRTb3VyY2UuTE9DQUxcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gUGFyc2UgZnJvbSBFbGVtZW50U291cmNlIHZhbHVlXG4gKiBwYXJzZVNvdXJjZUl0ZW0oRWxlbWVudFNvdXJjZS5HSVRIVUIpOyAvLyBSZXR1cm5zOiBFbGVtZW50U291cmNlLkdJVEhVQlxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBJbnZhbGlkIHNvdXJjZSB0aHJvd3MgZXJyb3JcbiAqIHBhcnNlU291cmNlSXRlbSgnaW52YWxpZCcpOyAvLyBUaHJvd3M6IFVua25vd24gc291cmNlOiBpbnZhbGlkXG4gKi9cbmZ1bmN0aW9uIHBhcnNlU291cmNlSXRlbShpdGVtOiB1bmtub3duKTogRWxlbWVudFNvdXJjZSB7XG4gIC8vIEhhbmRsZSBzdHJpbmcgaW5wdXQgKGNhc2UtaW5zZW5zaXRpdmUpXG4gIGlmICh0eXBlb2YgaXRlbSA9PT0gJ3N0cmluZycpIHtcbiAgICBjb25zdCBsb3dlckl0ZW0gPSBpdGVtLnRvTG93ZXJDYXNlKCk7XG4gICAgaWYgKFZBTElEX1NPVVJDRVMuaW5jbHVkZXMobG93ZXJJdGVtIGFzIEVsZW1lbnRTb3VyY2UpKSB7XG4gICAgICByZXR1cm4gbG93ZXJJdGVtIGFzIEVsZW1lbnRTb3VyY2U7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBzb3VyY2U6ICR7aXRlbX0uIFZhbGlkIHNvdXJjZXM6ICR7VkFMSURfU09VUkNFUy5qb2luKCcsICcpfWApO1xuICB9XG5cbiAgLy8gSGFuZGxlIEVsZW1lbnRTb3VyY2UgZW51bSB2YWx1ZVxuICBpZiAoT2JqZWN0LnZhbHVlcyhFbGVtZW50U291cmNlKS5pbmNsdWRlcyhpdGVtIGFzIEVsZW1lbnRTb3VyY2UpKSB7XG4gICAgcmV0dXJuIGl0ZW0gYXMgRWxlbWVudFNvdXJjZTtcbiAgfVxuXG4gIC8vIEludmFsaWQgdHlwZSBvciB2YWx1ZVxuICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc291cmNlIHZhbHVlOiAke2l0ZW19YCk7XG59XG5cbi8qKlxuICogUGFyc2Ugc291cmNlIHByaW9yaXR5IG9yZGVyIGZyb20gdmFyaW91cyBpbnB1dCBmb3JtYXRzXG4gKlxuICogQWNjZXB0cyBhcnJheXMgb2YgRWxlbWVudFNvdXJjZSB2YWx1ZXMgb3Igc3RyaW5nIHNvdXJjZSBuYW1lcyBhbmRcbiAqIG5vcm1hbGl6ZXMgdGhlbSB0byBhbiBhcnJheSBvZiBFbGVtZW50U291cmNlIGVudW0gdmFsdWVzLlxuICpcbiAqIEBwYXJhbSB7dW5rbm93bn0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gcGFyc2UgKGFycmF5IG9mIHNvdXJjZXMgb3IgSlNPTiBzdHJpbmcpXG4gKiBAcmV0dXJucyB7RWxlbWVudFNvdXJjZVtdfSBQYXJzZWQgYXJyYXkgb2YgZWxlbWVudCBzb3VyY2VzXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgdmFsdWUgY2Fubm90IGJlIHBhcnNlZCBvciBjb250YWlucyBpbnZhbGlkIHNvdXJjZXNcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gUGFyc2UgZnJvbSBhcnJheSBvZiBzdHJpbmdzXG4gKiBjb25zdCBvcmRlciA9IHBhcnNlU291cmNlUHJpb3JpdHlPcmRlcihbJ2xvY2FsJywgJ2dpdGh1YicsICdjb2xsZWN0aW9uJ10pO1xuICogLy8gUmV0dXJuczogW0VsZW1lbnRTb3VyY2UuTE9DQUwsIEVsZW1lbnRTb3VyY2UuR0lUSFVCLCBFbGVtZW50U291cmNlLkNPTExFQ1RJT05dXG4gKlxuICogQGV4YW1wbGVcbiAqIC8vIFBhcnNlIGZyb20gSlNPTiBzdHJpbmdcbiAqIGNvbnN0IG9yZGVyID0gcGFyc2VTb3VyY2VQcmlvcml0eU9yZGVyKCdbXCJnaXRodWJcIiwgXCJsb2NhbFwiXScpO1xuICogLy8gUmV0dXJuczogW0VsZW1lbnRTb3VyY2UuR0lUSFVCLCBFbGVtZW50U291cmNlLkxPQ0FMXVxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBQYXJzZSBmcm9tIEVsZW1lbnRTb3VyY2UgdmFsdWVzXG4gKiBjb25zdCBvcmRlciA9IHBhcnNlU291cmNlUHJpb3JpdHlPcmRlcihbRWxlbWVudFNvdXJjZS5MT0NBTCwgRWxlbWVudFNvdXJjZS5HSVRIVUJdKTtcbiAqIC8vIFJldHVybnM6IFtFbGVtZW50U291cmNlLkxPQ0FMLCBFbGVtZW50U291cmNlLkdJVEhVQl1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlU291cmNlUHJpb3JpdHlPcmRlcih2YWx1ZTogdW5rbm93bik6IEVsZW1lbnRTb3VyY2VbXSB7XG4gIC8vIEhhbmRsZSBzdHJpbmcgaW5wdXQgKEpTT04gYXJyYXkpXG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgdHJ5IHtcbiAgICAgIHZhbHVlID0gSlNPTi5wYXJzZSh2YWx1ZSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBKU09OIGluIHNvdXJjZSBwcmlvcml0eSBvcmRlcjogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCk7XG4gICAgfVxuICB9XG5cbiAgLy8gRW5zdXJlIHdlIGhhdmUgYW4gYXJyYXlcbiAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1NvdXJjZSBwcmlvcml0eSBvcmRlciBtdXN0IGJlIGFuIGFycmF5Jyk7XG4gIH1cblxuICAvLyBDb252ZXJ0IGVhY2ggaXRlbSB0byBFbGVtZW50U291cmNlIGVudW0gdmFsdWVcbiAgcmV0dXJuIHZhbHVlLm1hcChpdGVtID0+IHBhcnNlU291cmNlSXRlbShpdGVtKSk7XG59XG4iXX0=