@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.
552 lines • 75.4 kB
JavaScript
/**
* Base abstract class implementing IElement interface.
* Provides common functionality that all element types can extend.
*/
import { ElementStatus } from '../types/elements/index.js';
import { v4 as uuidv4 } from 'uuid';
import * as yaml from 'js-yaml';
import { logger } from '../utils/logger.js';
import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
import { SecurityMonitor } from '../security/securityMonitor.js';
import { SecureYamlParser } from '../security/secureYamlParser.js';
/**
* Normalizes version strings to full semver format (X.Y.Z)
* This helps maintain consistency while accepting flexible input formats
*
* @param version - The version string to normalize
* @returns Normalized version string in X.Y.Z format with leading zeros removed
*
* @example
* normalizeVersion("1") // "1.0.0"
* normalizeVersion("1.2") // "1.2.0"
* normalizeVersion("1.2.3") // "1.2.3"
* normalizeVersion("1.0-beta") // "1.0.0-beta"
* normalizeVersion("01.02.03") // "1.2.3" (strips leading zeros)
*/
export function normalizeVersion(version) {
// Extract base version and any prerelease/build metadata
const match = version.match(/^(\d+)(?:\.(\d+))?(?:\.(\d+))?([-+].+)?$/);
if (!match) {
// Return as-is if not a valid version format
return version;
}
const [, major, minor = '0', patch = '0', suffix = ''] = match;
// Strip leading zeros but preserve "0" as valid
const normalizedMajor = Number.parseInt(major, 10).toString();
const normalizedMinor = Number.parseInt(minor, 10).toString();
const normalizedPatch = Number.parseInt(patch, 10).toString();
return `${normalizedMajor}.${normalizedMinor}.${normalizedPatch}${suffix}`;
}
export class BaseElement {
static TRANSIENT_METADATA_FIELDS = new Set([
'gatekeeperDiagnostics',
]);
// Identity
id;
type;
version;
// Metadata
metadata;
// Dual-field semantic architecture (v2.0)
// All element types inherit these; subclasses may override with richer behavior.
// - instructions: behavioral directives (command voice, imperatives to follow)
// - content: reference material (informational data to draw from)
// Declared as accessor pairs so subclasses (e.g., Memory) can override with custom getters.
_instructions = '';
_content = '';
get instructions() { return this._instructions; }
set instructions(value) { this._instructions = value; }
get content() { return this._content; }
set content(value) { this._content = value; }
// Features
references;
extensions;
ratings;
// Internal state
_status = ElementStatus.INACTIVE;
_isDirty = false;
// Constants
MAX_FEEDBACK_HISTORY = 100;
constructor(type, metadata = {}, metadataService // Required injection for DI
) {
// Normalize common metadata via service (skip type-specific defaults)
const normalized = metadataService.normalizeMetadata(metadata, type, {
skipTypeDefaults: true // Let element-specific classes handle their own defaults
});
this.type = type;
this.id = metadata.name ? this.generateId(normalized.name) : uuidv4();
this.version = normalized.version || '1.0.0'; // Guaranteed by normalizeMetadata, but add fallback for type safety
// Spread normalized common metadata
const baseMetadata = {
...normalized,
type: this.type // Ensure type field is set correctly
};
// Preserve element-specific fields that MetadataService doesn't handle
// These are passed through unchanged via the spread operator in MetadataService
// Preserve triggers (Persona/Memory-specific)
if ('triggers' in metadata && Array.isArray(metadata.triggers)) {
baseMetadata.triggers = metadata.triggers;
}
// FIX #1430: Preserve Memory-specific metadata fields (autoLoad, priority)
// These are defined in MemoryMetadata but need to be preserved in baseMetadata
if ('autoLoad' in metadata) {
baseMetadata.autoLoad = metadata.autoLoad;
}
if ('priority' in metadata) {
baseMetadata.priority = metadata.priority;
}
this.metadata = baseMetadata;
// Initialize optional features
this.references = [];
this.extensions = {};
this.ratings = {
aiRating: 0,
userRating: undefined,
ratingCount: 0,
lastEvaluated: new Date(),
confidence: 0,
trend: 'stable',
feedbackHistory: []
};
}
/**
* Generate a unique ID for the element based on its name and type.
* Format: type_name-slug_timestamp
*/
generateId(name) {
const typeSlug = this.type.toLowerCase();
const nameSlug = name
.toLowerCase()
.replaceAll(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric chars with hyphens
.replaceAll(/(^-)|(-$)/g, ''); // Trim leading/trailing hyphens
const timestamp = Date.now();
return `${typeSlug}_${nameSlug}_${timestamp}`;
}
/**
* Core validation that all elements share.
* Subclasses should override and call super.validate() first.
*/
validate() {
const errors = [];
const warnings = [];
const suggestions = [];
// Validate required fields
if (!this.id) {
errors.push({ field: 'id', message: 'Element ID is required' });
}
if (!this.metadata.name || this.metadata.name.trim() === '') {
errors.push({ field: 'metadata.name', message: 'Element name is required' });
}
if (!this.metadata.description || this.metadata.description.trim() === '') {
warnings.push({
field: 'metadata.description',
message: 'Element description is recommended',
severity: 'medium'
});
}
// Validate version format - more flexible to support LLM-generated content
// FIX for Issue #935: Allow flexible version formats like "1.0", "1.1", "2.0.0"
// Previously: Strict semver regex requiring X.Y.Z format caused skills activation failures
// Now: Accept common version patterns that LLMs and humans naturally use
// Note: Leading zeros are allowed (e.g., "01.02.03") but will be normalized to "1.2.3"
// Security: No injection risk as version is just metadata, not executed
const flexibleVersionRegex = /^\d+(\.\d+)?(\.\d+)?(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
if (!flexibleVersionRegex.test(this.version)) {
errors.push({
field: 'version',
message: 'Version must start with numbers in format: MAJOR[.MINOR][.PATCH][-PRERELEASE][+BUILD]. Valid examples: "1", "1.0", "1.0.0", "2.1", "1.0.0-beta", "1.0.0-alpha.1", "1.0.0+build123". The major version is required, minor and patch are optional. Note: Leading zeros (e.g., "01.02") are accepted but will be normalized to "1.2".',
code: 'INVALID_VERSION_FORMAT'
});
}
// Validate references
if (this.references) {
this.references.forEach((ref, index) => {
if (!ref.uri || ref.uri.trim() === '') {
errors.push({
field: `references[${index}].uri`,
message: 'Reference URI is required'
});
}
if (!ref.title || ref.title.trim() === '') {
warnings.push({
field: `references[${index}].title`,
message: 'Reference title is recommended',
severity: 'low'
});
}
});
}
// Validate ratings if present
if (this.ratings) {
if (this.ratings.aiRating < 0 || this.ratings.aiRating > 5) {
errors.push({
field: 'ratings.aiRating',
message: 'AI rating must be between 0 and 5'
});
}
if (this.ratings.userRating !== undefined &&
(this.ratings.userRating < 0 || this.ratings.userRating > 5)) {
errors.push({
field: 'ratings.userRating',
message: 'User rating must be between 0 and 5'
});
}
}
// Add suggestions
if (!this.metadata.tags || this.metadata.tags.length === 0) {
suggestions.push('Consider adding tags to improve discoverability');
}
if (!this.metadata.author) {
suggestions.push('Consider adding author information');
}
return {
valid: errors.length === 0,
errors: errors.length > 0 ? errors : undefined,
warnings: warnings.length > 0 ? warnings : undefined,
suggestions: suggestions.length > 0 ? suggestions : undefined
};
}
/**
* Serialize to JSON format for internal use and testing.
* Maintains backward compatibility with existing tests.
*/
serializeToJSON() {
const data = {
id: this.id,
type: this.type,
version: this.version,
metadata: this.metadata,
references: this.references,
extensions: this.extensions,
ratings: this.ratings
};
return JSON.stringify(data, null, 2);
}
/**
* Default serialization to markdown with YAML frontmatter.
* Uses js-yaml for secure YAML generation to prevent injection attacks.
* FIX: Changed from JSON to proper markdown format for GitHub portfolio storage.
* This ensures elements are readable on GitHub and compatible with collection workflow.
*/
serialize() {
// Build YAML frontmatter starting with all metadata fields
// This ensures subclasses can add their own fields
const frontmatter = {
...this.metadata, // Include all metadata fields
type: this.type,
version: this.version
};
// Note: metadata already includes name, description, author, created, modified
// and any additional fields added by subclasses
if (this.references && this.references.length > 0) {
frontmatter.references = this.references.map(ref => ({
type: ref.type,
uri: ref.uri,
title: ref.title
}));
}
if (this.ratings && this.ratings.aiRating > 0) {
frontmatter.ratings = {
aiRating: this.ratings.aiRating,
userRating: this.ratings.userRating,
ratingCount: this.ratings.ratingCount
};
}
// Remove undefined/null values recursively
const cleanFrontmatter = this.deepCleanObject(frontmatter);
// Use js-yaml for secure YAML generation
// This prevents YAML injection attacks and handles special characters properly
let yamlFrontmatter;
try {
yamlFrontmatter = yaml.dump(cleanFrontmatter, {
noRefs: true, // Don't use YAML references
sortKeys: false, // Keep our order
lineWidth: -1, // Don't wrap lines
quotingType: '"', // Use double quotes when needed
forceQuotes: false, // Only quote when necessary
skipInvalid: false // Don't skip invalid values
});
}
catch (error) {
// If YAML generation fails, log and throw a more informative error
logger.error('Failed to generate YAML frontmatter', { error, frontmatter: cleanFrontmatter });
throw new Error(`Failed to serialize element metadata to YAML: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
// Validate the generated YAML can be parsed back using SecureYamlParser
// HIGH SEVERITY FIX: Use SecureYamlParser instead of yaml.load to prevent code execution
try {
SecureYamlParser.parse(yamlFrontmatter, {
maxYamlSize: 64 * 1024, // 64KB limit for frontmatter
validateContent: true
});
}
catch (error) {
logger.error('Generated invalid YAML', { error, yaml: yamlFrontmatter });
throw new Error(`Generated YAML is invalid: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
// Get content - subclasses should override this to provide actual content
const content = this.getContent ? this.getContent() : `# ${this.metadata.name}\n\n${this.metadata.description || ''}`;
// Trim the YAML to remove trailing newline that yaml.dump adds
return `---\n${yamlFrontmatter.trim()}\n---\n\n${content}`;
}
/**
* Recursively remove undefined and null values from an object.
* This ensures YAML serialization doesn't fail on undefined values.
*/
deepCleanObject(obj) {
if (obj === null || obj === undefined) {
return undefined;
}
if (Array.isArray(obj)) {
return obj
.map(item => this.deepCleanObject(item))
.filter(item => item !== undefined);
}
if (typeof obj === 'object') {
const cleaned = {};
for (const [key, value] of Object.entries(obj)) {
if (BaseElement.TRANSIENT_METADATA_FIELDS.has(key)) {
continue;
}
const cleanedValue = this.deepCleanObject(value);
if (cleanedValue !== undefined) {
cleaned[key] = cleanedValue;
}
}
return cleaned;
}
return obj;
}
/**
* Default deserialization from JSON.
* Subclasses can override for custom formats.
*/
deserialize(data) {
try {
// Normalize Unicode input before parsing
const validationResult = UnicodeValidator.normalize(data);
const parsed = JSON.parse(validationResult.normalizedContent);
// Validate required fields
if (!parsed.id || !parsed.type || !parsed.metadata) {
throw new Error('Invalid element data: missing required fields');
}
// Update properties
this.id = parsed.id;
this.type = parsed.type;
this.version = normalizeVersion(String(parsed.version ?? '1.0.0'));
this.metadata = parsed.metadata;
this.references = parsed.references || [];
this.extensions = parsed.extensions || {};
this.ratings = parsed.ratings;
this._isDirty = false;
}
catch (error) {
// Enhanced error context preservation
const errorMessage = error instanceof Error ? error.message : String(error);
const errorStack = error instanceof Error ? error.stack : undefined;
logger.error('Failed to deserialize element', {
error: errorMessage,
stack: errorStack,
dataPreview: data.substring(0, 200), // First 200 chars for context
elementType: this.type
});
// Create new error with original as cause
const deserializeError = new Error(`BaseElement deserialization failed: ${errorMessage}`);
if (error instanceof Error) {
deserializeError.cause = error;
}
throw deserializeError;
}
}
/**
* Process user feedback and update ratings.
*/
receiveFeedback(feedback, context) {
// Normalize Unicode input to prevent security issues
const validationResult = UnicodeValidator.normalize(feedback);
const normalizedFeedback = validationResult.normalizedContent;
// Log security event for feedback processing
SecurityMonitor.logSecurityEvent({
type: 'CONTENT_INJECTION_ATTEMPT',
severity: 'LOW',
source: 'BaseElement.receiveFeedback',
details: `Feedback processed for element ${this.type}:${this.id}`,
additionalData: {
elementType: this.type,
elementId: this.id,
feedbackLength: feedback.length,
hasUnicodeIssues: !validationResult.isValid
}
});
if (!this.ratings) {
this.ratings = {
aiRating: 0,
userRating: undefined,
ratingCount: 0,
lastEvaluated: new Date(),
confidence: 0,
trend: 'stable',
feedbackHistory: []
};
}
// Create feedback entry with normalized content
const userFeedback = {
timestamp: new Date(),
feedback: normalizedFeedback,
sentiment: this.analyzeSentiment(normalizedFeedback),
inferredRating: this.inferRating(normalizedFeedback),
context,
elementVersion: this.version
};
// Add to history with bounds checking
if (!this.ratings.feedbackHistory) {
this.ratings.feedbackHistory = [];
}
this.ratings.feedbackHistory.push(userFeedback);
// Prevent unbounded growth
if (this.ratings.feedbackHistory.length > this.MAX_FEEDBACK_HISTORY) {
this.ratings.feedbackHistory = this.ratings.feedbackHistory.slice(-this.MAX_FEEDBACK_HISTORY);
logger.debug(`Feedback history trimmed to ${this.MAX_FEEDBACK_HISTORY} entries for element ${this.id}`);
}
// Update user rating if we inferred one
if (userFeedback.inferredRating !== undefined) {
this.updateUserRating(userFeedback.inferredRating);
}
this._isDirty = true;
}
/**
* Simple sentiment analysis.
* Subclasses can override for more sophisticated analysis.
*/
analyzeSentiment(feedback) {
const lower = feedback.toLowerCase();
const positiveWords = ['excellent', 'great', 'good', 'helpful', 'useful', 'perfect', 'amazing', 'love'];
const negativeWords = ['bad', 'poor', 'terrible', 'useless', 'broken', 'hate', 'awful', 'disappointing'];
const positiveCount = positiveWords.filter(word => lower.includes(word)).length;
const negativeCount = negativeWords.filter(word => lower.includes(word)).length;
if (positiveCount > negativeCount)
return 'positive';
if (negativeCount > positiveCount)
return 'negative';
return 'neutral';
}
/**
* Simple rating inference from feedback.
* Subclasses can override for more sophisticated inference.
*/
inferRating(feedback) {
const sentiment = this.analyzeSentiment(feedback);
const lower = feedback.toLowerCase();
// Look for explicit ratings
const ratingMatch = lower.match(/(\d+)\s*(stars?|\/5|out of 5)/);
if (ratingMatch) {
const rating = Number.parseInt(ratingMatch[1]);
if (rating >= 1 && rating <= 5)
return rating;
}
// Infer from sentiment
if (sentiment === 'positive') {
if (lower.includes('perfect') || lower.includes('excellent'))
return 5;
if (lower.includes('great') || lower.includes('very good'))
return 4;
return 4;
}
else if (sentiment === 'negative') {
if (lower.includes('terrible') || lower.includes('awful'))
return 1;
if (lower.includes('poor') || lower.includes('bad'))
return 2;
return 2;
}
return 3; // Neutral
}
/**
* Update user rating with a new value.
*/
updateUserRating(newRating) {
if (!this.ratings)
return;
if (this.ratings.userRating === undefined) {
this.ratings.userRating = newRating;
this.ratings.ratingCount = 1;
}
else {
// Calculate running average
const totalRating = this.ratings.userRating * this.ratings.ratingCount + newRating;
this.ratings.ratingCount++;
this.ratings.userRating = totalRating / this.ratings.ratingCount;
}
// Update delta and trend
this.ratings.ratingDelta = this.ratings.userRating - this.ratings.aiRating;
// Simple trend calculation based on recent feedback
const recentFeedback = this.ratings.feedbackHistory?.slice(-5) || [];
const recentSentiments = recentFeedback.map(f => f.sentiment);
const positiveCount = recentSentiments.filter(s => s === 'positive').length;
const negativeCount = recentSentiments.filter(s => s === 'negative').length;
if (positiveCount > negativeCount + 1) {
this.ratings.trend = 'improving';
}
else if (negativeCount > positiveCount + 1) {
this.ratings.trend = 'declining';
}
else {
this.ratings.trend = 'stable';
}
}
/**
* Get current element status.
*/
getStatus() {
return this._status;
}
/**
* Status property getter for convenient access.
*/
get status() {
return this._status;
}
/**
* Default lifecycle methods - subclasses should override as needed.
*/
async beforeActivate() {
logger.debug(`Preparing to activate ${this.type} element: ${this.metadata.name}`);
this._status = ElementStatus.ACTIVATING;
}
async activate() {
if (this._status !== ElementStatus.ACTIVE) {
logger.info(`Activating ${this.type} element: ${this.metadata.name}`);
}
// Re-activations of the same element are silent — no value in logging
this._status = ElementStatus.ACTIVE;
}
async afterActivate() {
logger.debug(`Completed activation of ${this.type} element: ${this.metadata.name}`);
}
async deactivate() {
logger.info(`Deactivating ${this.type} element: ${this.metadata.name}`);
this._status = ElementStatus.DEACTIVATING;
// Subclasses should implement cleanup logic
this._status = ElementStatus.INACTIVE;
}
/**
* Mark element as modified.
*/
markDirty() {
this._isDirty = true;
this.metadata.modified = new Date().toISOString();
}
/**
* Check if element has unsaved changes.
*/
isDirty() {
return this._isDirty;
}
/**
* Mark element as saved.
*/
markClean() {
this._isDirty = false;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQmFzZUVsZW1lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZWxlbWVudHMvQmFzZUVsZW1lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxFQUdMLGFBQWEsRUFRZCxNQUFNLDRCQUE0QixDQUFDO0FBRXBDLE9BQU8sRUFBRSxFQUFFLElBQUksTUFBTSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3BDLE9BQU8sS0FBSyxJQUFJLE1BQU0sU0FBUyxDQUFDO0FBQ2hDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUM5RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDakUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFHbkU7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxPQUFlO0lBQzlDLHlEQUF5RDtJQUN6RCxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7SUFFeEUsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsNkNBQTZDO1FBQzdDLE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFFRCxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsS0FBSyxHQUFHLEdBQUcsRUFBRSxLQUFLLEdBQUcsR0FBRyxFQUFFLE1BQU0sR0FBRyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUM7SUFFL0QsZ0RBQWdEO0lBQ2hELE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQzlELE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FB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QUMsUUFBUSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7T0FFRztJQUNJLFNBQVM7UUFDZCxJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUN4QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBCYXNlIGFic3RyYWN0IGNsYXNzIGltcGxlbWVudGluZyBJRWxlbWVudCBpbnRlcmZhY2UuXG4gKiBQcm92aWRlcyBjb21tb24gZnVuY3Rpb25hbGl0eSB0aGF0IGFsbCBlbGVtZW50IHR5cGVzIGNhbiBleHRlbmQuXG4gKi9cblxuaW1wb3J0IHtcbiAgSUVsZW1lbnQsXG4gIElFbGVtZW50TWV0YWRhdGEsXG4gIEVsZW1lbnRTdGF0dXMsXG4gIEVsZW1lbnRSYXRpbmdzLFxuICBSZWZlcmVuY2UsXG4gIEVsZW1lbnRWYWxpZGF0aW9uUmVzdWx0LFxuICBWYWxpZGF0aW9uRXJyb3IsXG4gIFZhbGlkYXRpb25XYXJuaW5nLFxuICBGZWVkYmFja0NvbnRleHQsXG4gIFVzZXJGZWVkYmFja1xufSBmcm9tICcuLi90eXBlcy9lbGVtZW50cy9pbmRleC5qcyc7XG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4uL3BvcnRmb2xpby90eXBlcy5qcyc7XG5pbXBvcnQgeyB2NCBhcyB1dWlkdjQgfSBmcm9tICd1dWlkJztcbmltcG9ydCAqIGFzIHlhbWwgZnJvbSAnanMteWFtbCc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuaW1wb3J0IHsgU2VjdXJlWWFtbFBhcnNlciB9IGZyb20gJy4uL3NlY3VyaXR5L3NlY3VyZVlhbWxQYXJzZXIuanMnO1xuaW1wb3J0IHsgTWV0YWRhdGFTZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvTWV0YWRhdGFTZXJ2aWNlLmpzJztcblxuLyoqXG4gKiBOb3JtYWxpemVzIHZlcnNpb24gc3RyaW5ncyB0byBmdWxsIHNlbXZlciBmb3JtYXQgKFguWS5aKVxuICogVGhpcyBoZWxwcyBtYWludGFpbiBjb25zaXN0ZW5jeSB3aGlsZSBhY2NlcHRpbmcgZmxleGlibGUgaW5wdXQgZm9ybWF0c1xuICogXG4gKiBAcGFyYW0gdmVyc2lvbiAtIFRoZSB2ZXJzaW9uIHN0cmluZyB0byBub3JtYWxpemVcbiAqIEByZXR1cm5zIE5vcm1hbGl6ZWQgdmVyc2lvbiBzdHJpbmcgaW4gWC5ZLlogZm9ybWF0IHdpdGggbGVhZGluZyB6ZXJvcyByZW1vdmVkXG4gKiBcbiAqIEBleGFtcGxlXG4gKiBub3JtYWxpemVWZXJzaW9uKFwiMVwiKSAgICAgICAgLy8gXCIxLjAuMFwiXG4gKiBub3JtYWxpemVWZXJzaW9uKFwiMS4yXCIpICAgICAgLy8gXCIxLjIuMFwiXG4gKiBub3JtYWxpemVWZXJzaW9uKFwiMS4yLjNcIikgICAgLy8gXCIxLjIuM1wiXG4gKiBub3JtYWxpemVWZXJzaW9uKFwiMS4wLWJldGFcIikgLy8gXCIxLjAuMC1iZXRhXCJcbiAqIG5vcm1hbGl6ZVZlcnNpb24oXCIwMS4wMi4wM1wiKSAvLyBcIjEuMi4zXCIgKHN0cmlwcyBsZWFkaW5nIHplcm9zKVxuICovXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplVmVyc2lvbih2ZXJzaW9uOiBzdHJpbmcpOiBzdHJpbmcge1xuICAvLyBFeHRyYWN0IGJhc2UgdmVyc2lvbiBhbmQgYW55IHByZXJlbGVhc2UvYnVpbGQgbWV0YWRhdGFcbiAgY29uc3QgbWF0Y2ggPSB2ZXJzaW9uLm1hdGNoKC9eKFxcZCspKD86XFwuKFxcZCspKT8oPzpcXC4oXFxkKykpPyhbLStdLispPyQvKTtcbiAgXG4gIGlmICghbWF0Y2gpIHtcbiAgICAvLyBSZXR1cm4gYXMtaXMgaWYgbm90IGEgdmFsaWQgdmVyc2lvbiBmb3JtYXRcbiAgICByZXR1cm4gdmVyc2lvbjtcbiAgfVxuICBcbiAgY29uc3QgWywgbWFqb3IsIG1pbm9yID0gJzAnLCBwYXRjaCA9ICcwJywgc3VmZml4ID0gJyddID0gbWF0Y2g7XG4gIFxuICAvLyBTdHJpcCBsZWFkaW5nIHplcm9zIGJ1dCBwcmVzZXJ2ZSBcIjBcIiBhcyB2YWxpZFxuICBjb25zdCBub3JtYWxpemVkTWFqb3IgPSBOdW1iZXIucGFyc2VJbnQobWFqb3IsIDEwKS50b1N0cmluZygpO1xuICBjb25zdCBub3JtYWxpemVkTWlub3IgPSBOdW1iZXIucGFyc2VJbnQobWlub3IsIDEwKS50b1N0cmluZygpO1xuICBjb25zdCBub3JtYWxpemVkUGF0Y2ggPSBOdW1iZXIucGFyc2VJbnQocGF0Y2gsIDEwKS50b1N0cmluZygpO1xuICBcbiAgcmV0dXJuIGAke25vcm1hbGl6ZWRNYWpvcn0uJHtub3JtYWxpemVkTWlub3J9LiR7bm9ybWFsaXplZFBhdGNofSR7c3VmZml4fWA7XG59XG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNlRWxlbWVudCBpbXBsZW1lbnRzIElFbGVtZW50IHtcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgVFJBTlNJRU5UX01FVEFEQVRBX0ZJRUxEUyA9IG5ldyBTZXQoW1xuICAgICdnYXRla2VlcGVyRGlhZ25vc3RpY3MnLFxuICBdKTtcbiAgLy8gSWRlbnRpdHlcbiAgcHVibGljIGlkOiBzdHJpbmc7XG4gIHB1YmxpYyB0eXBlOiBFbGVtZW50VHlwZTtcbiAgcHVibGljIHZlcnNpb246IHN0cmluZztcbiAgXG4gIC8vIE1ldGFkYXRhXG4gIHB1YmxpYyBtZXRhZGF0YTogSUVsZW1lbnRNZXRhZGF0YTtcbiAgXG4gIC8vIER1YWwtZmllbGQgc2VtYW50aWMgYXJjaGl0ZWN0dXJlICh2Mi4wKVxuICAvLyBBbGwgZWxlbWVudCB0eXBlcyBpbmhlcml0IHRoZXNlOyBzdWJjbGFzc2VzIG1heSBvdmVycmlkZSB3aXRoIHJpY2hlciBiZWhhdmlvci5cbiAgLy8gLSBpbnN0cnVjdGlvbnM6IGJlaGF2aW9yYWwgZGlyZWN0aXZlcyAoY29tbWFuZCB2b2ljZSwgaW1wZXJhdGl2ZXMgdG8gZm9sbG93KVxuICAvLyAtIGNvbnRlbnQ6IHJlZmVyZW5jZSBtYXRlcmlhbCAoaW5mb3JtYXRpb25hbCBkYXRhIHRvIGRyYXcgZnJvbSlcbiAgLy8gRGVjbGFyZWQgYXMgYWNjZXNzb3IgcGFpcnMgc28gc3ViY2xhc3NlcyAoZS5nLiwgTWVtb3J5KSBjYW4gb3ZlcnJpZGUgd2l0aCBjdXN0b20gZ2V0dGVycy5cbiAgcHJvdGVjdGVkIF9pbnN0cnVjdGlvbnM6IHN0cmluZyA9ICcnO1xuICBwcm90ZWN0ZWQgX2NvbnRlbnQ6IHN0cmluZyA9ICcnO1xuXG4gIHB1YmxpYyBnZXQgaW5zdHJ1Y3Rpb25zKCk6IHN0cmluZyB7IHJldHVybiB0aGlzLl9pbnN0cnVjdGlvbnM7IH1cbiAgcHVibGljIHNldCBpbnN0cnVjdGlvbnModmFsdWU6IHN0cmluZykgeyB0aGlzLl9pbnN0cnVjdGlvbnMgPSB2YWx1ZTsgfVxuXG4gIHB1YmxpYyBnZXQgY29udGVudCgpOiBzdHJpbmcgeyByZXR1cm4gdGhpcy5fY29udGVudDsgfVxuICBwdWJsaWMgc2V0IGNvbnRlbnQodmFsdWU6IHN0cmluZykgeyB0aGlzLl9jb250ZW50ID0gdmFsdWU7IH1cblxuICAvLyBGZWF0dXJlc1xuICBwdWJsaWMgcmVmZXJlbmNlcz86IFJlZmVyZW5jZVtdO1xuICBwdWJsaWMgZXh0ZW5zaW9ucz86IFJlY29yZDxzdHJpbmcsIGFueT47XG4gIHB1YmxpYyByYXRpbmdzPzogRWxlbWVudFJhdGluZ3M7XG4gIFxuICAvLyBJbnRlcm5hbCBzdGF0ZVxuICBwcm90ZWN0ZWQgX3N0YXR1czogRWxlbWVudFN0YXR1cyA9IEVsZW1lbnRTdGF0dXMuSU5BQ1RJVkU7XG4gIHByb3RlY3RlZCBfaXNEaXJ0eTogYm9vbGVhbiA9IGZhbHNlO1xuICBcbiAgLy8gQ29uc3RhbnRzXG4gIHByaXZhdGUgcmVhZG9ubHkgTUFYX0ZFRURCQUNLX0hJU1RPUlkgPSAxMDA7XG4gIFxuICBjb25zdHJ1Y3RvcihcbiAgICB0eXBlOiBFbGVtZW50VHlwZSxcbiAgICBtZXRhZGF0YTogUGFydGlhbDxJRWxlbWVudE1ldGFkYXRhPiA9IHt9LFxuICAgIG1ldGFkYXRhU2VydmljZTogTWV0YWRhdGFTZXJ2aWNlICAvLyBSZXF1aXJlZCBpbmplY3Rpb24gZm9yIERJXG4gICkge1xuICAgIC8vIE5vcm1hbGl6ZSBjb21tb24gbWV0YWRhdGEgdmlhIHNlcnZpY2UgKHNraXAgdHlwZS1zcGVjaWZpYyBkZWZhdWx0cylcbiAgICBjb25zdCBub3JtYWxpemVkID0gbWV0YWRhdGFTZXJ2aWNlLm5vcm1hbGl6ZU1ldGFkYXRhKG1ldGFkYXRhLCB0eXBlLCB7XG4gICAgICBza2lwVHlwZURlZmF1bHRzOiB0cnVlICAvLyBMZXQgZWxlbWVudC1zcGVjaWZpYyBjbGFzc2VzIGhhbmRsZSB0aGVpciBvd24gZGVmYXVsdHNcbiAgICB9KTtcblxuICAgIHRoaXMudHlwZSA9IHR5cGU7XG4gICAgdGhpcy5pZCA9IG1ldGFkY