UNPKG

@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.

318 lines 42.4 kB
/** * PersonaElementValidator - Specialized validator for persona elements * * Restores and extends the original PersonaValidator functionality including: * - Content length quality checks (min 50 chars, warn if >5000) * - Age rating validation * - Improvement suggestions * - Validation report generation * * This validator provides persona-specific validation logic while using * the shared validation services for security-first patterns. */ import { ElementType } from '../../portfolio/types.js'; // VALID_CATEGORIES import removed — categories are deprecated (see config/constants.ts) import { ValidatorHelpers } from './ElementValidator.js'; import { GenericElementValidator } from './GenericElementValidator.js'; /** * Valid age ratings for personas */ const VALID_AGE_RATINGS = ['all', '13+', '18+']; /** * Specialized validator for persona elements */ export class PersonaElementValidator extends GenericElementValidator { constructor(validationService, triggerValidationService, metadataService) { super(ElementType.PERSONA, validationService, triggerValidationService, metadataService); } /** * Validate data for persona creation * Extends base validation with persona-specific checks */ async validateCreate(data, options) { // Start with base validation const baseResult = await super.validateCreate(data, options); const errors = [...baseResult.errors]; const warnings = [...baseResult.warnings]; const suggestions = baseResult.suggestions ? [...baseResult.suggestions] : []; if (!data || typeof data !== 'object') { return baseResult; } const record = data; const content = String(record.content || record.instructions || ''); // Persona-specific: Minimum content length check (warning, not error) // The base validator already checks for minimum 10 characters if (content && content.trim().length >= 10 && content.trim().length < 50) { warnings.push('Persona content is short (recommended minimum 50 characters)'); } // Persona-specific: Content length warning if (content && content.length > 5000) { warnings.push('Persona content is very long - consider breaking it into sections'); } // Validate age rating if present if (record.age_rating !== undefined) { const ageRatingResult = this.validateAgeRating(record.age_rating); if (!ageRatingResult.isValid) { warnings.push(...ageRatingResult.errors); } } // Generate persona-specific suggestions const personaSuggestions = this.suggestImprovements(record); suggestions.push(...personaSuggestions); return { isValid: errors.length === 0, errors, warnings, suggestions: suggestions.length > 0 ? suggestions : undefined }; } /** * Validate metadata with persona-specific rules */ async validateMetadata(metadata, options) { // Start with base metadata validation const baseResult = await super.validateMetadata(metadata, { ...options, requiredFields: options?.requiredFields || ['name', 'description'] }); const errors = [...baseResult.errors]; const warnings = [...baseResult.warnings]; if (!metadata || typeof metadata !== 'object') { return baseResult; } const record = metadata; // Persona-specific: Validate age rating if (record.age_rating) { const ageRatingResult = this.validateAgeRating(record.age_rating); if (!ageRatingResult.isValid) { warnings.push(...ageRatingResult.errors); } } // Warn about missing optional but important fields if (!record.triggers || (Array.isArray(record.triggers) && record.triggers.length === 0)) { warnings.push('No trigger keywords defined - users may have difficulty finding this persona'); } if (!record.version) { warnings.push("No version specified - defaulting to '1.0'"); } if (!record.unique_id) { warnings.push('No unique_id - one will be generated automatically'); } return { isValid: errors.length === 0, errors, warnings }; } /** * Generate a comprehensive validation report for a persona * Restores original PersonaValidator report generation */ async generateReport(element) { const details = []; let status = 'pass'; if (!element || typeof element !== 'object') { return { status: 'fail', summary: 'Invalid persona: must be a non-null object', details: ['Persona validation failed - invalid input type'], timestamp: new Date() }; } const record = element; const metadata = (record.metadata || record); const content = String(record.content || record.instructions || ''); // Validate the persona const createResult = await this.validateCreate({ name: metadata.name, description: metadata.description, content, triggers: metadata.triggers, author: metadata.author, version: metadata.version, category: metadata.category, age_rating: metadata.age_rating }); const metadataResult = await this.validateMetadata(metadata); // Merge results const allErrors = [...createResult.errors, ...metadataResult.errors]; const allWarnings = [...createResult.warnings, ...metadataResult.warnings]; const suggestions = createResult.suggestions || []; // Generate formatted report (matching original PersonaValidator format) if (allErrors.length === 0 && allWarnings.length === 0) { details.push('All Checks Passed!'); details.push(''); details.push(`Persona: ${metadata.name}`); details.push(`Category: ${metadata.category || 'general'}`); details.push(`Version: ${metadata.version || '1.0'}`); details.push(`Content Length: ${content.length} characters`); details.push(`Triggers: ${Array.isArray(metadata.triggers) ? metadata.triggers.length : 0} keywords`); details.push(''); details.push('This persona meets all validation requirements and is ready for use!'); } else { if (allErrors.length > 0) { status = 'fail'; details.push(`Issues Found (${allErrors.length}):`); allErrors.forEach((error, i) => { details.push(` ${i + 1}. ${error}`); }); details.push(''); } if (allWarnings.length > 0) { if (status === 'pass') { status = 'warning'; } details.push(`Warnings (${allWarnings.length}):`); allWarnings.forEach((warning, i) => { details.push(` ${i + 1}. ${warning}`); }); details.push(''); } if (status === 'fail') { details.push('Fix Required: Please address the issues above before using this persona.'); } else { details.push('Status: This persona is valid but could be improved. Consider addressing the warnings.'); } } // Add suggestions if any if (suggestions.length > 0) { details.push(''); details.push(`Suggestions (${suggestions.length}):`); suggestions.forEach((suggestion, i) => { details.push(` ${i + 1}. ${suggestion}`); }); } // Calculate metrics const triggerCount = Array.isArray(metadata.triggers) ? metadata.triggers.length : 0; // Generate summary let summary; if (status === 'pass') { summary = `Persona "${metadata.name}" validation passed`; } else if (status === 'warning') { summary = `Persona "${metadata.name}" is valid with ${allWarnings.length} warning(s)`; } else { summary = `Persona "${metadata.name}" validation failed with ${allErrors.length} error(s)`; } return { status, summary, details, timestamp: new Date(), metrics: { contentLength: content.length, triggerCount, qualityScore: this.calculatePersonaQualityScore(metadata, content) } }; } /** * Validate age rating */ validateAgeRating(ageRating) { if (typeof ageRating !== 'string') { return ValidatorHelpers.fail(["Age rating must be a string"]); } if (!VALID_AGE_RATINGS.includes(ageRating)) { return ValidatorHelpers.fail([ `Invalid age_rating '${ageRating}'. Should be one of: ${VALID_AGE_RATINGS.join(', ')}` ]); } return ValidatorHelpers.pass(); } /** * Suggest improvements for a persona * Restores original PersonaValidator.suggestImprovements functionality */ suggestImprovements(record) { const suggestions = []; const triggers = record.triggers; const content = String(record.content || record.instructions || ''); // Trigger suggestions if (!triggers || !Array.isArray(triggers) || triggers.length < 3) { suggestions.push('Add more trigger keywords to improve discoverability'); } // Author suggestion if (!record.author) { suggestions.push('Add an author field for proper attribution'); } // Content length suggestion if (content.length < 200) { suggestions.push('Expand the persona instructions for better AI guidance'); } // Version suggestion if (!record.version) { suggestions.push('Add a version number for tracking updates'); } return suggestions; } /** * Check if a persona name is valid * Restores original PersonaValidator.isValidPersonaName functionality */ isValidPersonaName(name) { if (!name || name.trim().length === 0) return false; if (name.length > 50) return false; // Check for invalid characters return !/[<>:"/\\|?*]/.test(name); } /** * Calculate a quality score specific to personas (0-100) */ calculatePersonaQualityScore(metadata, content) { let score = 0; // Name quality (0-15 points) if (metadata.name && typeof metadata.name === 'string') { score += 10; if (this.isValidPersonaName(metadata.name)) { score += 5; } } // Description quality (0-15 points) if (metadata.description && typeof metadata.description === 'string') { score += 10; const desc = metadata.description; if (desc.length >= 20 && desc.length <= 200) { score += 5; } } // Content quality (0-30 points) - stricter for personas if (content) { if (content.length >= 50) { score += 15; } if (content.length >= 200) { score += 10; } if (content.length >= 50 && content.length <= 5000) { score += 5; } } // Metadata completeness (0-20 points) if (metadata.author) score += 5; if (metadata.version) score += 5; if (metadata.category) score += 5; if (metadata.age_rating && VALID_AGE_RATINGS.includes(String(metadata.age_rating))) score += 5; // Triggers (0-20 points) - important for personas if (Array.isArray(metadata.triggers)) { const triggers = metadata.triggers; if (triggers.length > 0) score += 10; if (triggers.length >= 3) score += 5; if (triggers.length <= 10) score += 5; } return Math.min(100, score); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVyc29uYUVsZW1lbnRWYWxpZGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvdmFsaWRhdGlvbi9QZXJzb25hRWxlbWVudFZhbGlkYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7R0FXRztBQUVILE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUl2RCx3RkFBd0Y7QUFDeEYsT0FBTyxFQUtMLGdCQUFnQixFQUNqQixNQUFNLHVCQUF1QixDQUFDO0FBQy9CLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRXZFOztHQUVHO0FBQ0gsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFVLENBQUM7QUFHekQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sdUJBQXdCLFNBQVEsdUJBQXVCO0lBQ2xFLFlBQ0UsaUJBQW9DLEVBQ3BDLHdCQUFrRCxFQUNsRCxlQUFnQztRQUVoQyxLQUFLLENBQ0gsV0FBVyxDQUFDLE9BQU8sRUFDbkIsaUJBQWlCLEVBQ2pCLHdCQUF3QixFQUN4QixlQUFlLENBQ2hCLENBQUM7SUFDSixDQUFDO0lBRUQ7OztPQUdHO0lBQ00sS0FBSyxDQUFDLGNBQWMsQ0FDM0IsSUFBYSxFQUNiLE9BQWtDO1FBRWxDLDZCQUE2QjtRQUM3QixNQUFNLFVBQVUsR0FBRyxNQUFNLEtBQUssQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzdELE1BQU0sTUFBTSxHQUFHLENBQUMsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdEMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUMxQyxNQUFNLFdBQVcsR0FBRyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxDQUFD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LENBQUM7Z0JBQ25ELEtBQUssSUFBSSxDQUFDLENBQUM7WUFDYixDQUFDO1FBQ0gsQ0FBQztRQUVELHNDQUFzQztRQUN0QyxJQUFJLFFBQVEsQ0FBQyxNQUFNO1lBQUUsS0FBSyxJQUFJLENBQUMsQ0FBQztRQUNoQyxJQUFJLFFBQVEsQ0FBQyxPQUFPO1lBQUUsS0FBSyxJQUFJLENBQUMsQ0FBQztRQUNqQyxJQUFJLFFBQVEsQ0FBQyxRQUFRO1lBQUUsS0FBSyxJQUFJLENBQUMsQ0FBQztRQUNsQyxJQUFJLFFBQVEsQ0FBQyxVQUFVLElBQUksaUJBQWlCLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFjLENBQUM7WUFBRSxLQUFLLElBQUksQ0FBQyxDQUFDO1FBRTVHLGtEQUFrRDtRQUNsRCxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDckMsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLFFBQXFCLENBQUM7WUFDaEQsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUM7Z0JBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUNyQyxJQUFJLFFBQVEsQ0FBQyxNQUFNLElBQUksQ0FBQztnQkFBRSxLQUFLLElBQUksQ0FBQyxDQUFDO1lBQ3JDLElBQUksUUFBUSxDQUFDLE1BQU0sSUFBSSxFQUFFO2dCQUFFLEtBQUssSUFBSSxDQUFDLENBQUM7UUFDeEMsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDOUIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQZXJzb25hRWxlbWVudFZhbGlkYXRvciAtIFNwZWNpYWxpemVkIHZhbGlkYXRvciBmb3IgcGVyc29uYSBlbGVtZW50c1xuICpcbiAqIFJlc3RvcmVzIGFuZCBleHRlbmRzIHRoZSBvcmlnaW5hbCBQZXJzb25hVmFsaWRhdG9yIGZ1bmN0aW9uYWxpdHkgaW5jbHVkaW5nOlxuICogLSBDb250ZW50IGxlbmd0aCBxdWFsaXR5IGNoZWNrcyAobWluIDUwIGNoYXJzLCB3YXJuIGlmID41MDAwKVxuICogLSBBZ2UgcmF0aW5nIHZhbGlkYXRpb25cbiAqIC0gSW1wcm92ZW1lbnQgc3VnZ2VzdGlvbnNcbiAqIC0gVmFsaWRhdGlvbiByZXBvcnQgZ2VuZXJhdGlvblxuICpcbiAqIFRoaXMgdmFsaWRhdG9yIHByb3ZpZGVzIHBlcnNvbmEtc3BlY2lmaWMgdmFsaWRhdGlvbiBsb2dpYyB3aGlsZSB1c2luZ1xuICogdGhlIHNoYXJlZCB2YWxpZGF0aW9uIHNlcnZpY2VzIGZvciBzZWN1cml0eS1maXJzdCBwYXR0ZXJucy5cbiAqL1xuXG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4uLy4uL3BvcnRmb2xpby90eXBlcy5qcyc7XG5pbXBvcnQgeyBWYWxpZGF0aW9uU2VydmljZSB9IGZyb20gJy4vVmFsaWRhdGlvblNlcnZpY2UuanMnO1xuaW1wb3J0IHsgVHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi9UcmlnZ2VyVmFsaWRhdGlvblNlcnZpY2UuanMnO1xuaW1wb3J0IHsgTWV0YWRhdGFTZXJ2aWNlIH0gZnJvbSAnLi4vTWV0YWRhdGFTZXJ2aWNlLmpzJztcbi8vIFZBTElEX0NBVEVHT1JJRVMgaW1wb3J0IHJlbW92ZWQg4oCUIGNhdGVnb3JpZXMgYXJlIGRlcHJlY2F0ZWQgKHNlZSBjb25maWcvY29uc3RhbnRzLnRzKVxuaW1wb3J0IHtcbiAgVmFsaWRhdGlvblJlc3VsdCxcbiAgVmFsaWRhdGlvblJlcG9ydCxcbiAgRWxlbWVudFZhbGlkYXRpb25PcHRpb25zLFxuICBNZXRhZGF0YVZhbGlkYXRpb25PcHRpb25zLFxuICBWYWxpZGF0b3JIZWxwZXJzXG59IGZyb20gJy4vRWxlbWVudFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBHZW5lcmljRWxlbWVudFZhbGlkYXRvciB9IGZyb20gJy4vR2VuZXJpY0VsZW1lbnRWYWxpZGF0b3IuanMnO1xuXG4vKipcbiAqIFZhbGlkIGFnZSByYXRpbmdzIGZvciBwZXJzb25hc1xuICovXG5jb25zdCBWQUxJRF9BR0VfUkFUSU5HUyA9IFsnYWxsJywgJzEzKycsICcxOCsnXSBhcyBjb25zdDtcbnR5cGUgQWdlUmF0aW5nID0gdHlwZW9mIFZBTElEX0FHRV9SQVRJTkdTW251bWJlcl07XG5cbi8qKlxuICogU3BlY2lhbGl6ZWQgdmFsaWRhdG9yIGZvciBwZXJzb25hIGVsZW1lbnRzXG4gKi9cbmV4cG9ydCBjbGFzcyBQZXJzb25hRWxlbWVudFZhbGlkYXRvciBleHRlbmRzIEdlbmVyaWNFbGVtZW50VmFsaWRhdG9yIHtcbiAgY29uc3RydWN0b3IoXG4gICAgdmFsaWRhdGlvblNlcnZpY2U6IFZhbGlkYXRpb25TZXJ2aWNlLFxuICAgIHRyaWdnZXJWYWxpZGF0aW9uU2VydmljZTogVHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLFxuICAgIG1ldGFkYXRhU2VydmljZTogTWV0YWRhdGFTZXJ2aWNlXG4gICkge1xuICAgIHN1cGVyKFxuICAgICAgRWxlbWVudFR5cGUuUEVSU09OQSxcbiAgICAgIHZhbGlkYXRpb25TZXJ2aWNlLFxuICAgICAgdHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLFxuICAgICAgbWV0YWRhdGFTZXJ2aWNlXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBkYXRhIGZvciBwZXJzb25hIGNyZWF0aW9uXG4gICAqIEV4dGVuZHMgYmFzZSB2YWxpZGF0aW9uIHdpdGggcGVyc29uYS1zcGVjaWZpYyBjaGVja3NcbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIHZhbGlkYXRlQ3JlYXRlKFxuICAgIGRhdGE6IHVua25vd24sXG4gICAgb3B0aW9ucz86IEVsZW1lbnRWYWxpZGF0aW9uT3B0aW9uc1xuICApOiBQcm9taXNlPFZhbGlkYXRpb25SZXN1bHQ+IHtcbiAgICAvLyBTdGFydCB3aXRoIGJhc2UgdmFsaWRhdGlvblxuICAgIGNvbnN0IGJhc2VSZXN1bHQgPSBhd2FpdCBzdXBlci52YWxpZGF0ZUNyZWF0ZShkYXRhLCBvcHRpb25zKTtcbiAgICBjb25zdCBlcnJvcnMgPSBbLi4uYmFzZVJlc3VsdC5lcnJvcnNdO1xuICAgIGNvbnN0IHdhcm5pbmdzID0gWy4uLmJhc2VSZXN1bHQud2FybmluZ3NdO1xuICAgIGNvbnN0IHN1Z2dlc3Rpb25zID0gYmFzZVJlc3VsdC5zdWdnZXN0aW9ucyA/IFsuLi5iYXNlUmVzdWx0LnN1Z2dlc3Rpb25zXSA6IFtdO1xuXG4gICAgaWYgKCFkYXRhIHx8IHR5cGVvZiBkYXRhICE9PSAnb2JqZWN0Jykge1xuICAgICAgcmV0dXJuIGJhc2VSZXN1bHQ7XG4gICAgfVxuXG4gICAgY29uc3QgcmVjb3JkID0gZGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICBjb25zdCBjb250ZW50ID0gU3RyaW5nKHJlY29yZC5jb250ZW50IHx8IHJlY29yZC5pbnN0cnVjdGlvbnMgfHwgJycpO1xuXG4gICAgLy8gUGVyc29uYS1zcGVjaWZpYzogTWluaW11bSBjb250ZW50IGxlbmd0aCBjaGVjayAod2FybmluZywgbm90IGVycm9yKVxuICAgIC8vIFRoZSBiYXNlIHZhbGlkYXRvciBhbHJlYWR5IGNoZWNrcyBmb3IgbWluaW11bSAxMCBjaGFyYWN0ZXJzXG4gICAgaWYgKGNvbnRlbnQgJiYgY29udGVudC50cmltKCkubGVuZ3RoID49IDEwICYmIGNvbnRlbnQudHJpbSgpLmxlbmd0aCA8IDUwKSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKCdQZXJzb25hIGNvbnRlbnQgaXMgc2hvcnQgKHJlY29tbWVuZGVkIG1pbmltdW0gNTAgY2hhcmFjdGVycyknKTtcbiAgICB9XG5cbiAgICAvLyBQZXJzb25hLXNwZWNpZmljOiBDb250ZW50IGxlbmd0aCB3YXJuaW5nXG4gICAgaWYgKGNvbnRlbnQgJiYgY29udGVudC5sZW5ndGggPiA1MDAwKSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKCdQZXJzb25hIGNvbnRlbnQgaXMgdmVyeSBsb25nIC0gY29uc2lkZXIgYnJlYWtpbmcgaXQgaW50byBzZWN0aW9ucycpO1xuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIGFnZSByYXRpbmcgaWYgcHJlc2VudFxuICAgIGlmIChyZWNvcmQuYWdlX3JhdGluZyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBhZ2VSYXRpbmdSZXN1bHQgPSB0aGlzLnZhbGlkYXRlQWdlUmF0aW5nKHJlY29yZC5hZ2VfcmF0aW5nKTtcbiAgICAgIGlmICghYWdlUmF0aW5nUmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgd2FybmluZ3MucHVzaCguLi5hZ2VSYXRpbmdSZXN1bHQuZXJyb3JzKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBHZW5lcmF0ZSBwZXJzb25hLXNwZWNpZmljIHN1Z2dlc3Rpb25zXG4gICAgY29uc3QgcGVyc29uYVN1Z2dlc3Rpb25zID0gdGhpcy5zdWdnZXN0SW1wcm92ZW1lbnRzKHJlY29yZCk7XG4gICAgc3VnZ2VzdGlvbnMucHVzaCguLi5wZXJzb25hU3VnZ2VzdGlvbnMpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlzVmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsXG4gICAgICBlcnJvcnMsXG4gICAgICB3YXJuaW5ncyxcbiAgICAgIHN1Z2dlc3Rpb25zOiBzdWdnZXN0aW9ucy5sZW5ndGggPiAwID8gc3VnZ2VzdGlvbnMgOiB1bmRlZmluZWRcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIG1ldGFkYXRhIHdpdGggcGVyc29uYS1zcGVjaWZpYyBydWxlc1xuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgdmFsaWRhdGVNZXRhZGF0YShcbiAgICBtZXRhZGF0YTogdW5rbm93bixcbiAgICBvcHRpb25zPzogTWV0YWRhdGFWYWxpZGF0aW9uT3B0aW9uc1xuICApOiBQcm9taXNlPFZhbGlkYXRpb25SZXN1bHQ+IHtcbiAgICAvLyBTdGFydCB3aXRoIGJhc2UgbWV0YWRhdGEgdmFsaWRhdGlvblxuICAgIGNvbnN0IGJhc2VSZXN1bHQgPSBhd2FpdCBzdXBlci52YWxpZGF0ZU1ldGFkYXRhKG1ldGFkYXRhLCB7XG4gICAgICAuLi5vcHRpb25zLFxuICAgICAgcmVxdWlyZWRGaWVsZHM6IG9wdGlvbnM/LnJlcXVpcmVkRmllbGRzIHx8IFsnbmFtZScsICdkZXNjcmlwdGlvbiddXG4gICAgfSk7XG5cbiAgICBjb25zdCBlcnJvcnMgPSBbLi4uYmFzZVJlc3VsdC5lcnJvcnNdO1xuICAgIGNvbnN0IHdhcm5pbmdzID0gWy4uLmJhc2VSZXN1bHQud2FybmluZ3NdO1xuXG4gICAgaWYgKCFtZXRhZGF0YSB8fCB0eXBlb2YgbWV0YWRhdGEgIT09ICdvYmplY3QnKSB7XG4gICAgICByZXR1cm4gYmFzZVJlc3VsdDtcbiAgICB9XG5cbiAgICBjb25zdCByZWNvcmQgPSBtZXRhZGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcblxuICAgIC8vIFBlcnNvbmEtc3BlY2lmaWM6IFZhbGlkYXRlIGFnZSByYXRpbmdcbiAgICBpZiAocmVjb3JkLmFnZV9yYXRpbmcpIHtcbiAgICAgIGNvbnN0IGFnZVJhdGluZ1Jlc3VsdCA9IHRoaXMudmFsaWRhdGVBZ2VSYXRpbmcocmVjb3JkLmFnZV9yYXRpbmcpO1xuICAgICAgaWYgKCFhZ2VSYXRpbmdSZXN1bHQuaXNWYWxpZCkge1xuICAgICAgICB3YXJuaW5ncy5wdXNoKC4uLmFnZVJhdGluZ1Jlc3VsdC5lcnJvcnMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFdhcm4gYWJvdXQgbWlzc2luZyBvcHRpb25hbCBidXQgaW1wb3J0YW50IGZpZWxkc1xuICAgIGlmICghcmVjb3JkLnRyaWdnZXJzIHx8IChBcnJheS5pc0FycmF5KHJlY29yZC50cmlnZ2VycykgJiYgcmVjb3JkLnRyaWdnZXJzLmxlbmd0aCA9PT0gMCkpIHtcbiAgICAgIHdhcm5pbmdzLnB1c2goJ05vIHRyaWdnZXIga2V5d29yZHMgZGVmaW5lZCAtIHVzZXJzIG1heSBoYXZlIGRpZmZpY3VsdHkgZmluZGluZyB0aGlzIHBlcnNvbmEnKTtcbiAgICB9XG4gICAgaWYgKCFyZWNvcmQudmVyc2lvbikge1xuICAgICAgd2FybmluZ3MucHVzaChcIk5vIHZlcnNpb24gc3BlY2lmaWVkIC0gZGVmYXVsdGluZyB0byAnMS4wJ1wiKTtcbiAgICB9XG4gICAgaWYgKCFyZWNvcmQudW5pcXVlX2lkKSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKCdObyB1bmlxdWVfaWQgLSBvbmUgd2lsbCBiZSBnZW5lcmF0ZWQgYXV0b21hdGljYWxseScpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBpc1ZhbGlkOiBlcnJvcnMubGVuZ3RoID09PSAwLFxuICAgICAgZXJyb3JzLFxuICAgICAgd2FybmluZ3NcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEgY29tcHJlaGVuc2l2ZSB2YWxpZGF0aW9uIHJlcG9ydCBmb3IgYSBwZXJzb25hXG4gICAqIFJlc3RvcmVzIG9yaWdpbmFsIFBlcnNvbmFWYWxpZGF0b3IgcmVwb3J0IGdlbmVyYXRpb25cbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIGdlbmVyYXRlUmVwb3J0KGVsZW1lbnQ6IHVua25vd24pOiBQcm9taXNlPFZhbGlkYXRpb25SZXBvcnQ+IHtcbiAgICBjb25zdCBkZXRhaWxzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGxldCBzdGF0dXM6ICdwYXNzJyB8ICdmYWlsJyB8ICd3YXJuaW5nJyA9ICdwYXNzJztcblxuICAgIGlmICghZWxlbWVudCB8fCB0eXBlb2YgZWxlbWVudCAhPT0gJ29iamVjdCcpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN0YXR1czogJ2ZhaWwnLFxuICAgICAgICBzdW1tYXJ5OiAnSW52YWxpZCBwZXJzb25hOiBtdXN0IGJlIGEgbm9uLW51bGwgb2JqZWN0JyxcbiAgICAgICAgZGV0YWlsczogWydQZXJzb25hIHZhbGlkYXRpb24gZmFpbGVkIC0gaW52YWxpZCBpbnB1dCB0eXBlJ10sXG4gICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKVxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCByZWNvcmQgPSBlbGVtZW50IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIGNvbnN0IG1ldGFkYXRhID0gKHJlY29yZC5tZXRhZGF0YSB8fCByZWNvcmQpIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIGNvbnN0IGNvbnRlbnQgPSBTdHJpbmcocmVjb3JkLmNvbnRlbnQgfHwgcmVjb3JkLmluc3RydWN0aW9ucyB8fCAnJyk7XG5cbiAgICAvLyBWYWxpZGF0ZSB0aGUgcGVyc29uYVxuICAgIGNvbnN0IGNyZWF0ZVJlc3VsdCA9IGF3YWl0IHRoaXMudmFsaWRhdGVDcmVhdGUoe1xuICAgICAgbmFtZTogbWV0YWRhdGEubmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiBtZXRhZGF0YS5kZXNjcmlwdGlvbixcbiAgICAgIGNvbnRlbnQsXG4gICAgICB0cmlnZ2VyczogbWV0YWRhdGEudHJpZ2dlcnMsXG4gICAgICBhdXRob3I6IG1ldGFkYXRhLmF1dGhvcixcbiAgICAgIHZlcnNpb246IG1ldGFkYXRhLnZlcnNpb24sXG4gICAgICBjYXRlZ29yeTogbWV0YWRhdGEuY2F0ZWdvcnksXG4gICAgICBhZ2VfcmF0aW5nOiBtZXRhZGF0YS5hZ2VfcmF0aW5nXG4gICAgfSk7XG5cbiAgICBjb25zdCBtZXRhZGF0YVJlc3VsdCA9IGF3YWl0IHRoaXMudmFsaWRhdGVNZXRhZGF0YShtZXRhZGF0YSk7XG5cbiAgICAvLyBNZXJnZSByZXN1bHRzXG4gICAgY29uc3QgYWxsRXJyb3JzID0gWy4uLmNyZWF0ZVJlc3VsdC5lcnJvcnMsIC4uLm1ldGFkYXRhUmVzdWx0LmVycm9yc107XG4gICAgY29uc3QgYWxsV2FybmluZ3MgPSBbLi4uY3JlYXRlUmVzdWx0Lndhcm5pbmdzLCAuLi5tZXRhZGF0YVJlc3VsdC53YXJuaW5nc107XG4gICAgY29uc3Qgc3VnZ2VzdGlvbnMgPSBjcmVhdGVSZXN1bHQuc3VnZ2VzdGlvbnMgfHwgW107XG5cbiAgICAvLyBHZW5lcmF0ZSBmb3JtYXR0ZWQgcmVwb3J0IChtYXRjaGluZyBvcmlnaW5hbCBQZXJzb25hVmFsaWRhdG9yIGZvcm1hdClcbiAgICBpZiAoYWxsRXJyb3JzLmxlbmd0aCA9PT0gMCAmJiBhbGxXYXJuaW5ncy5sZW5ndGggPT09IDApIHtcbiAgICAgIGRldGFpbHMucHVzaCgnQWxsIENoZWNrcyBQYXNzZWQhJyk7XG4gICAgICBkZXRhaWxzLnB1c2goJycpO1xuICAgICAgZGV0YWlscy5wdXNoKGBQZXJzb25hOiAke21ldGFkYXRhLm5hbWV9YCk7XG4gICAgICBkZXRhaWxzLnB1c2goYENhdGVnb3J5OiAke21ldGFkYXRhLmNhdGVnb3J5IHx8ICdnZW5lcmFsJ31gKTtcbiAgICAgIGRldGFpbHMucHVzaChgVmVyc2lvbjogJHttZXRhZGF0YS52ZXJzaW9uIHx8ICcxLjAnfWApO1xuICAgICAgZGV0YWlscy5wdXNoKGBDb250ZW50IExlbmd0aDogJHtjb250ZW50Lmxlbmd0aH0gY2hhcmFjdGVyc2ApO1xuICAgICAgZGV0YWlscy5wdXNoKGBUcmlnZ2VyczogJHtBcnJheS5pc0FycmF5KG1ldGFkYXRhLnRyaWdnZXJzKSA/IG1ldGFkYXRhLnRyaWdnZXJzLmxlbmd0aCA6IDB9IGtleXdvcmRzYCk7XG4gICAgICBkZXRhaWxzLnB1c2goJycpO1xuICAgICAgZGV0YWlscy5wdXNoKCdUaGlzIHBlcnNvbmEgbWVldHMgYWxsIHZhbGlkYXRpb24gcmVxdWlyZW1lbnRzIGFuZCBpcyByZWFkeSBmb3IgdXNlIScpO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoYWxsRXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgc3RhdHVzID0gJ2ZhaWwnO1xuICAgICAgICBkZXRhaWxzLnB1c2goYElzc3VlcyBGb3VuZCAoJHthbGxFcnJvcnMubGVuZ3RofSk6YCk7XG4gICAgICAgIGFsbEVycm9ycy5mb3JFYWNoKChlcnJvciwgaSkgPT4ge1xuICAgICAgICAgIGRldGFpbHMucHVzaChgICAgJHtpICsgMX0uICR7ZXJyb3J9YCk7XG4gICAgICAgIH0pO1xuICAgICAgICBkZXRhaWxzLnB1c2goJycpO1xuICAgICAgfVxuXG4gICAgICBpZiAoYWxsV2FybmluZ3MubGVuZ3RoID4gMCkge1xuICAgICAgICBpZiAoc3RhdHVzID09PSAncGFzcycpIHtcbiAgICAgICAgICBzdGF0dXMgPSAnd2FybmluZyc7XG4gICAgICAgIH1cbiAgICAgICAgZGV0YWlscy5wdXNoKGBXYXJuaW5ncyAoJHthbGxXYXJuaW5ncy5sZW5ndGh9KTpgKTtcbiAgICAgICAgYWxsV2FybmluZ3MuZm9yRWFjaCgod2FybmluZywgaSkgPT4ge1xuICAgICAgICAgIGRldGFpbHMucHVzaChgICAgJHtpICsgMX0uICR7d2FybmluZ31gKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGRldGFpbHMucHVzaCgnJyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzdGF0dXMgPT09ICdmYWlsJykge1xuICAgICAgICBkZXRhaWxzLnB1c2goJ0ZpeCBSZXF1aXJlZDogUGxlYXNlIGFkZHJlc3MgdGhlIGlzc3VlcyBhYm92ZSBiZWZvcmUgdXNpbmcgdGhpcyBwZXJzb25hLicpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZGV0YWlscy5wdXNoKCdTdGF0dXM6IFRoaXMgcGVyc29uYSBpcyB2YWxpZCBidXQgY291bGQgYmUgaW1wcm92ZWQuIENvbnNpZGVyIGFkZHJlc3NpbmcgdGhlIHdhcm5pbmdzLicpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFkZCBzdWdnZXN0aW9ucyBpZiBhbnlcbiAgICBpZiAoc3VnZ2VzdGlvbnMubGVuZ3RoID4gMCkge1xuICAgICAgZGV0YWlscy5wdXNoKCcnKTtcbiAgICAgIGRldGFpbHMucHVzaChgU3VnZ2VzdGlvbnMgKCR7c3VnZ2VzdGlvbnMubGVuZ3RofSk6YCk7XG4gICAgICBzdWdnZXN0aW9ucy5mb3JFYWNoKChzdWdnZXN0aW9uLCBpKSA9PiB7XG4gICAgICAgIGRldGFpbHMucHVzaChgICAgJHtpICsgMX0uICR7c3VnZ2VzdGlvbn1gKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIENhbGN1bGF0ZSBtZXRyaWNzXG4gICAgY29uc3QgdHJpZ2dlckNvdW50ID0gQXJyYXkuaXNBcnJheShtZXRhZGF0YS50cmlnZ2VycykgPyBtZXRhZGF0YS50cmlnZ2Vycy5sZW5ndGggOiAwO1xuXG4gICAgLy8gR2VuZXJhdGUgc3VtbWFyeVxuICAgIGxldCBzdW1tYXJ5OiBzdHJpbmc7XG4gICAgaWYgKHN0YXR1cyA9PT0gJ3Bhc3MnKSB7XG4gICAgICBzdW1tYXJ5ID0gYFBlcnNvbmEgXCIke21ldGFkYXRhLm5hbWV9XCIgdmFsaWRhdGlvbiBwYXNzZWRgO1xuICAgIH0gZWxzZSBpZiAoc3RhdHVzID09PSAnd2FybmluZycpIHtcbiAgICAgIHN1bW1hcnkgPSBgUGVyc29uYSBcIiR7bWV0YWRhdGEubmFtZX1cIiBpcyB2YWxpZCB3aXRoICR7YWxsV2FybmluZ3MubGVuZ3RofSB3YXJuaW5nKHMpYDtcbiAgICB9IGVsc2Uge1xuICAgICAgc3VtbWFyeSA9IGBQZXJzb25hIFwiJHttZXRhZGF0YS5uYW1lfVwiIHZhbGlkYXRpb24gZmFpbGVkIHdpdGggJHthbGxFcnJvcnMubGVuZ3RofSBlcnJvcihzKWA7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN0YXR1cyxcbiAgICAgIHN1bW1hcnksXG4gICAgICBkZXRhaWxzLFxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLFxuICAgICAgbWV0cmljczoge1xuICAgICAgICBjb250ZW50TGVuZ3RoOiBjb250ZW50Lmxlbmd0aCxcbiAgICAgICAgdHJpZ2dlckNvdW50LFxuICAgICAgICBxdWFsaXR5U2NvcmU6IHRoaXMuY2FsY3VsYXRlUGVyc29uYVF1YWxpdHlTY29yZShtZXRhZGF0YSwgY29udGVudClcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFnZSByYXRpbmdcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVBZ2VSYXRpbmcoYWdlUmF0aW5nOiB1bmtub3duKTogVmFsaWRhdGlvblJlc3VsdCB7XG4gICAgaWYgKHR5cGVvZiBhZ2VSYXRpbmcgIT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gVmFsaWRhdG9ySGVscGVycy5mYWlsKFtcIkFnZSByYXRpbmcgbXVzdCBiZSBhIHN0cmluZ1wiXSk7XG4gICAgfVxuXG4gICAgaWYgKCFWQUxJRF9BR0VfUkFUSU5HUy5pbmNsdWRlcyhhZ2VSYXRpbmcgYXMgQWdlUmF0aW5nKSkge1xuICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbXG4gICAgICAgIGBJbnZhbGlkIGFnZV9yYXRpbmcgJyR7YWdlUmF0aW5nfScuIFNob3VsZCBiZSBvbmUgb2Y6ICR7VkFMSURfQUdFX1JBVElOR1Muam9pbignLCAnKX1gXG4gICAgICBdKTtcbiAgICB9XG5cbiAgICByZXR1cm4gVmFsaWRhdG9ySGVscGVycy5wYXNzKCk7XG4gIH1cblxuICAvKipcbiAgICogU3VnZ2VzdCBpbXByb3ZlbWVudHMgZm9yIGEgcGVyc29uYVxuICAgKiBSZXN0b3JlcyBvcmlnaW5hbCBQZXJzb25hVmFsaWRhdG9yLnN1Z2dlc3RJbXByb3ZlbWVudHMgZnVuY3Rpb25hbGl0eVxuICAgKi9cbiAgcHJpdmF0ZSBzdWdnZXN0SW1wcm92ZW1lbnRzKHJlY29yZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBzdHJpbmdbXSB7XG4gICAgY29uc3Qgc3VnZ2VzdGlvbnM6IHN0cmluZ1tdID0gW107XG4gICAgY29uc3QgdHJpZ2dlcnMgPSByZWNvcmQudHJpZ2dlcnM7XG4gICAgY29uc3QgY29udGVudCA9IFN0cmluZyhyZWNvcmQuY29udGVudCB8fCByZWNvcmQuaW5zdHJ1Y3Rpb25zIHx8ICcnKTtcblxuICAgIC8vIFRyaWdnZXIgc3VnZ2VzdGlvbnNcbiAgICBpZiAoIXRyaWdnZXJzIHx8ICFBcnJheS5pc0FycmF5KHRyaWdnZXJzKSB8fCB0cmlnZ2Vycy5sZW5ndGggPCAzKSB7XG4gICAgICBzdWdnZXN0aW9ucy5wdXNoKCdBZGQgbW9yZSB0cmlnZ2VyIGtleXdvcmRzIHRvIGltcHJvdmUgZGlzY292ZXJhYmlsaXR5Jyk7XG4gICAgfVxuXG4gICAgLy8gQXV0aG9yIHN1Z2dlc3Rpb25cbiAgICBpZiAoIXJlY29yZC5hdXRob3IpIHtcbiAgICAgIHN1Z2dlc3Rpb25zLnB1c2goJ0FkZCBhbiBhdXRob3IgZmllbGQgZm9yIHByb3BlciBhdHRyaWJ1dGlvbicpO1xuICAgIH1cblxuICAgIC8vIENvbnRlbnQgbGVuZ3RoIHN1Z2dlc3Rpb25cbiAgICBpZiAoY29udGVudC5sZW5ndGggPCAyMDApIHtcbiAgICAgIHN1Z2dlc3Rpb25zLnB1c2goJ0V4cGFuZCB0aGUgcGVyc29uYSBpbnN0cnVjdGlvbnMgZm9yIGJldHRlciBBSSBndWlkYW5jZScpO1xuICAgIH1cblxuICAgIC8vIFZlcnNpb24gc3VnZ2VzdGlvblxuICAgIGlmICghcmVjb3JkLnZlcnNpb24pIHtcbiAgICAgIHN1Z2dlc3Rpb25zLnB1c2goJ0FkZCBhIHZlcnNpb24gbnVtYmVyIGZvciB0cmFja2luZyB1cGRhdGVzJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHN1Z2dlc3Rpb25zO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIGEgcGVyc29uYSBuYW1lIGlzIHZhbGlkXG4gICAqIFJlc3RvcmVzIG9yaWdpbmFsIFBlcnNvbmFWYWxpZGF0b3IuaXNWYWxpZFBlcnNvbmFOYW1lIGZ1bmN0aW9uYWxpdHlcbiAgICovXG4gIGlzVmFsaWRQZXJzb25hTmFtZShuYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBpZiAoIW5hbWUgfHwgbmFtZS50cmltKCkubGVuZ3RoID09PSAwKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKG5hbWUubGVuZ3RoID4gNTApIHJldHVybiBmYWxzZTtcbiAgICAvLyBDaGVjayBmb3IgaW52YWxpZCBjaGFyYWN0ZXJzXG4gICAgcmV0dXJuICEvWzw+OlwiL1xcXFx8PypdLy50ZXN0KG5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZSBhIHF1YWxpdHkgc2NvcmUgc3BlY2lmaWMgdG8gcGVyc29uYXMgKDAtMTAwKVxuICAgKi9cbiAgcHJpdmF0ZSBjYWxjdWxhdGVQZXJzb25hUXVhbGl0eVNjb3JlKFxuICAgIG1ldGFkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBjb250ZW50OiBzdHJpbmdcbiAgKTogbnVtYmVyIHtcbiAgICBsZXQgc2NvcmUgPSAwO1xuXG4gICAgLy8gTmFtZSBxdWFsaXR5ICgwLTE1IHBvaW50cylcbiAgICBpZiAobWV0YWRhdGEubmFtZSAmJiB0eXBlb2YgbWV0YWRhdGEubmFtZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHNjb3JlICs9IDEwO1xuICAgICAgaWYgKHRoaXMuaXNWYWxpZFBlcnNvbmFOYW1lKG1ldGFkYXRhLm5hbWUpKSB7XG4gICAgICAgIHNjb3JlICs9IDU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gRGVzY3JpcHRpb24gcXVhbGl0eSAoMC0xNSBwb2ludHMpXG4gICAgaWYgKG1ldGFkYXRhLmRlc2NyaXB0aW9uICYmIHR5cGVvZiBtZXRhZGF0YS5kZXNjcmlwdGlvbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHNjb3JlICs9IDEwO1xuICAgICAgY29uc3QgZGVzYyA9IG1ldGFkYXRhLmRlc2NyaXB0aW9uIGFzIHN0cmluZztcbiAgICAgIGlmIChkZXNjLmxlbmd0aCA+PSAyMCAmJiBkZXNjLmxlbmd0aCA8PSAyMDApIHtcbiAgICAgICAgc2NvcmUgKz0gNTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDb250ZW50IHF1YWxpdHkgKDAtMzAgcG9pbnRzKSAtIHN0cmljdGVyIGZvciBwZXJzb25hc1xuICAgIGlmIChjb250ZW50KSB7XG4gICAgICBpZiAoY29udGVudC5sZW5ndGggPj0gNTApIHtcbiAgICAgICAgc2NvcmUgKz0gMTU7XG4gICAgICB9XG4gICAgICBpZiAoY29udGVudC5sZW5ndGggPj0gMjAwKSB7XG4gICAgICAgIHNjb3JlICs9IDEwO1xuICAgICAgfVxuICAgICAgaWYgKGNvbnRlbnQubGVuZ3RoID49IDUwICYmIGNvbnRlbnQubGVuZ3RoIDw9IDUwMDApIHtcbiAgICAgICAgc2NvcmUgKz0gNTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBNZXRhZGF0YSBjb21wbGV0ZW5lc3MgKDAtMjAgcG9pbnRzKVxuICAgIGlmIChtZXRhZGF0YS5hdXRob3IpIHNjb3JlICs9IDU7XG4gICAgaWYgKG1ldGFkYXRhLnZlcnNpb24pIHNjb3JlICs9IDU7XG4gICAgaWYgKG1ldGFkYXRhLmNhdGVnb3J5KSBzY29yZSArPSA1O1xuICAgIGlmIChtZXRhZGF0YS5hZ2VfcmF0aW5nICYmIFZBTElEX0FHRV9SQVRJTkdTLmluY2x1ZGVzKFN0cmluZyhtZXRhZGF0YS5hZ2VfcmF0aW5nKSBhcyBBZ2VSYXRpbmcpKSBzY29yZSArPSA1O1xuXG4gICAgLy8gVHJpZ2dlcnMgKDAtMjAgcG9pbnRzKSAtIGltcG9ydGFudCBmb3IgcGVyc29uYXNcbiAgICBpZiAoQXJyYXkuaXNBcnJheShtZXRhZGF0YS50cmlnZ2VycykpIHtcbiAgICAgIGNvbnN0IHRyaWdnZXJzID0gbWV0YWRhdGEudHJpZ2dlcnMgYXMgdW5rbm93bltdO1xuICAgICAgaWYgKHRyaWdnZXJzLmxlbmd0aCA+IDApIHNjb3JlICs9IDEwO1xuICAgICAgaWYgKHRyaWdnZXJzLmxlbmd0aCA+PSAzKSBzY29yZSArPSA1O1xuICAgICAgaWYgKHRyaWdnZXJzLmxlbmd0aCA8PSAxMCkgc2NvcmUgKz0gNTtcbiAgICB9XG5cbiAgICByZXR1cm4gTWF0aC5taW4oMTAwLCBzY29yZSk7XG4gIH1cbn1cbiJdfQ==