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.

229 lines 26.3 kB
/** * Inverted Index for fast collection search * * Provides O(k) search performance where k = number of matching entries * compared to O(n) linear search through all entries. * * Architecture: * - Token -> Set<entryId> mapping for fast lookups * - Separate indexes for different fields (name, description, tags, etc.) * - Efficient tokenization with stop word filtering * - Case-insensitive with normalization */ import { normalizeSearchTerm } from '../utils/searchUtils.js'; /** * Inverted index for fast collection search */ export class InvertedIndex { // Main index: token -> entry IDs and field locations index = new Map(); // Entry storage: ID -> full entry entries = []; // ID lookup: entry path -> entry ID pathToId = new Map(); // Statistics stats = { totalTokens: 0, totalEntries: 0, avgTokensPerEntry: 0, estimatedMemoryKB: 0, lastBuilt: new Date(), buildTimeMs: 0 }; /** * Build inverted index from entries */ build(entries) { const startTime = performance.now(); // Clear existing index this.index.clear(); this.entries = []; this.pathToId.clear(); // Build index entries.forEach((entry, idx) => { // Store entry this.entries.push(entry); this.pathToId.set(entry.path, idx); // Tokenize and index each field this.indexField(idx, entry.name, 'name'); this.indexField(idx, entry.description, 'description'); this.indexField(idx, entry.path, 'path'); // Index tags separately entry.tags.forEach(tag => { this.indexField(idx, tag, 'tags'); }); }); // Update statistics const endTime = performance.now(); this.updateStats(endTime - startTime); } /** * Index a single field for an entry */ indexField(entryId, fieldValue, fieldName) { const tokens = this.tokenize(fieldValue); tokens.forEach(token => { let tokenEntry = this.index.get(token); if (!tokenEntry) { tokenEntry = { token, entryIds: new Set(), fields: new Map() }; this.index.set(token, tokenEntry); } // Add entry ID to this token tokenEntry.entryIds.add(entryId); // Track which field this token appears in if (!tokenEntry.fields.has(entryId)) { tokenEntry.fields.set(entryId, new Set()); } tokenEntry.fields.get(entryId).add(fieldName); }); } /** * Tokenize a string into searchable tokens * * Uses the same normalization as searchUtils for consistency */ tokenize(text) { if (!text || text.trim().length === 0) { return []; } // Normalize using shared utility const normalized = normalizeSearchTerm(text); // Split into words const tokens = normalized.split(/\s+/).filter(token => { // Remove empty tokens and common stop words return token.length > 0 && !this.isStopWord(token); }); return tokens; } /** * Check if a token is a common stop word * * Stop words are filtered to reduce index size and improve relevance */ isStopWord(token) { // Common English stop words that don't add search value const stopWords = new Set([ 'a', 'an', 'and', 'are', 'as', 'at', 'be', 'by', 'for', 'from', 'has', 'he', 'in', 'is', 'it', 'its', 'of', 'on', 'that', 'the', 'to', 'was', 'will', 'with' ]); return stopWords.has(token); } /** * Search the index for matching entries * * Returns entry IDs matching the query with relevance scores */ search(query) { const queryTokens = this.tokenize(query); if (queryTokens.length === 0) { return []; } // Find all entries matching any query token const candidateScores = new Map(); queryTokens.forEach(queryToken => { const tokenEntry = this.index.get(queryToken); if (tokenEntry) { // Add matching entries with field-based scoring tokenEntry.entryIds.forEach(entryId => { const fields = tokenEntry.fields.get(entryId); const score = this.calculateFieldScore(fields); // Accumulate scores (multiple token matches increase relevance) const currentScore = candidateScores.get(entryId) || 0; candidateScores.set(entryId, currentScore + score); }); } }); // Convert to array and sort by score return Array.from(candidateScores.entries()) .map(([entryId, score]) => ({ entryId, score })) .sort((a, b) => b.score - a.score); } /** * Calculate relevance score based on which fields matched * * Name matches are most relevant, followed by tags, description, path */ calculateFieldScore(fields) { if (!fields) return 0; let score = 0; // Field weights (name is most important) if (fields.has('name')) score += 100; if (fields.has('tags')) score += 25; if (fields.has('description')) score += 50; if (fields.has('path')) score += 10; return score; } /** * Get entry by ID */ getEntry(entryId) { return this.entries[entryId]; } /** * Get all entries (for filtering/sorting after search) */ getAllEntries() { return this.entries; } /** * Get index statistics */ getStats() { return { ...this.stats }; } /** * Update statistics after index build */ updateStats(buildTimeMs) { const totalTokenInstances = Array.from(this.index.values()) .reduce((sum, entry) => sum + entry.entryIds.size, 0); this.stats = { totalTokens: this.index.size, totalEntries: this.entries.length, avgTokensPerEntry: this.entries.length > 0 ? totalTokenInstances / this.entries.length : 0, estimatedMemoryKB: this.estimateMemoryUsage(), lastBuilt: new Date(), buildTimeMs }; } /** * Estimate memory usage of the index */ estimateMemoryUsage() { // Token string overhead: ~50 bytes per unique token const tokenOverhead = this.index.size * 50; // Set overhead: ~8 bytes per entry ID const entryIdOverhead = Array.from(this.index.values()) .reduce((sum, entry) => sum + entry.entryIds.size * 8, 0); // Field map overhead: ~16 bytes per field tracking const fieldOverhead = Array.from(this.index.values()) .reduce((sum, entry) => sum + entry.fields.size * 16, 0); // Total in KB return (tokenOverhead + entryIdOverhead + fieldOverhead) / 1024; } /** * Check if index is empty */ isEmpty() { return this.entries.length === 0; } /** * Get number of indexed entries */ size() { return this.entries.length; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW52ZXJ0ZWRJbmRleC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb2xsZWN0aW9uL0ludmVydGVkSW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7O0dBV0c7QUFHSCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQXdCOUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQUN4QixxREFBcUQ7SUFDN0MsS0FBSyxHQUE0QixJQUFJLEdBQUcsRUFBRSxDQUFDO0lBRW5ELGtDQUFrQztJQUMxQixPQUFPLEdBQWlCLEVBQUUsQ0FBQztJQUVuQyxvQ0FBb0M7SUFDNUIsUUFBUSxHQUF3QixJQUFJLEdBQUcsRUFBRSxDQUFDO0lBRWxELGFBQWE7SUFDTCxLQUFLLEdBQXVCO1FBQ2xDLFdBQVcsRUFBRSxDQUFDO1FBQ2QsWUFBWSxFQUFFLENBQUM7UUFDZixpQkFBaUIsRUFBRSxDQUFDO1FBQ3BCLGlCQUFpQixFQUFFLENBQUM7UUFDcEIsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFO1FBQ3JCLFdBQVcsRUFBRSxDQUFDO0tBQ2YsQ0FBQztJQUVGOztPQUVHO0lBQ0gsS0FBSyxDQUFDLE9BQXFCO1FBQ3pCLE1BQU0sU0FBUyxHQUFHLFdBQVcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUVwQyx1QkFBdUI7UUFDdkIsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNuQixJQUFJLENBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNsQixJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBRXRCLGNBQWM7UUFDZCxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxFQUFFO1lBQzdCLGNBQWM7WUFDZCxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUN6QixJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBRW5DLGdDQUFnQztZQUNoQyxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ3pDLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxXQUFXLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDdkQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztZQUV6Qyx3QkFBd0I7WUFDeEIsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUU7Z0JBQ3ZCLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUNwQyxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsb0JBQW9CO1FBQ3BCLE1BQU0sT0FBTyxHQUFHLFdBQVcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNsQyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sR0FBRyxTQUFTLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBRUQ7O09BRUc7SUFDSyxVQUFVLENBQ2hCLE9BQWUsRUFDZixVQUFrQixFQUNsQixTQUFtRDtRQUVuRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRXpDLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDckIsSUFBSSxVQUFVLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7WUFFdkMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO2dCQUNoQixVQUFVLEdBQUc7b0JBQ1gsS0FBSztvQkFDTCxRQUFRLEVBQUUsSUFBSSxHQUFHLEVBQUU7b0JBQ25CLE1BQU0sRUFBRSxJQUFJLEdBQUcsRUFBRTtpQkFDbEIsQ0FBQztnQkFDRixJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDcEMsQ0FBQztZQUVELDZCQUE2QjtZQUM3QixVQUFVLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUVqQywwQ0FBMEM7WUFDMUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7Z0JBQ3BDLFVBQVUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLEdBQUcsRUFBRSxDQUFDLENBQUM7WUFDNUMsQ0FBQztZQUNELFVBQVUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBRSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNqRCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ssUUFBUSxDQUFDLElBQVk7UUFDM0IsSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3RDLE9BQU8sRUFBRSxDQUFDO1FBQ1osQ0FBQztRQUVELGlDQUFpQztRQUNqQyxNQUFNLFVBQVUsR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUU3QyxtQkFBbUI7UUFDbkIsTUFBTSxNQUFNLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDcEQsNENBQTRDO1lBQzVDLE9BQU8sS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3JELENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxVQUFVLENBQUMsS0FBYTtRQUM5Qix3REFBd0Q7UUFDeEQsTUFBTSxTQUFTLEdBQUcsSUFBSSxHQUFHLENBQUM7WUFDeEIsR0FBRyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLO1lBQ3RELE1BQU0sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsSUFBSTtZQUN4RCxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU07U0FDM0MsQ0FBQyxDQUFDO1FBRUgsT0FBTyxTQUFTLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsTUFBTSxDQUFDLEtBQWE7UUFDbEIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUV6QyxJQUFJLFdBQVcsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDN0IsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO1FBRUQsNENBQTRDO1FBQzVDLE1BQU0sZUFBZSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO1FBRWxELFdBQVcsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDL0IsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUM7WUFFOUMsSUFBSSxVQUFVLEVBQUUsQ0FBQztnQkFDZixnREFBZ0Q7Z0JBQ2hELFVBQVUsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFO29CQUNwQyxNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztvQkFDOUMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUUvQyxnRUFBZ0U7b0JBQ2hFLE1BQU0sWUFBWSxHQUFHLGVBQWUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUN2RCxlQUFlLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxZQUFZLEdBQUcsS0FBSyxDQUFDLENBQUM7Z0JBQ3JELENBQUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgscUNBQXFDO1FBQ3JDLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxFQUFFLENBQUM7YUFDekMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzthQUMvQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLG1CQUFtQixDQUFDLE1BQWlFO1FBQzNGLElBQUksQ0FBQyxNQUFNO1lBQUUsT0FBTyxDQUFDLENBQUM7UUFFdEIsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO1FBRWQseUNBQXlDO1FBQ3pDLElBQUksTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUM7WUFBRSxLQUFLLElBQUksR0FBRyxDQUFDO1FBQ3JDLElBQUksTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUM7WUFBRSxLQUFLLElBQUksRUFBRSxDQUFDO1FBQ3BDLElBQUksTUFBTSxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUM7WUFBRSxLQUFLLElBQUksRUFBRSxDQUFDO1FBQzNDLElBQUksTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUM7WUFBRSxLQUFLLElBQUksRUFBRSxDQUFDO1FBRXBDLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOztPQUVHO0lBQ0gsUUFBUSxDQUFDLE9BQWU7UUFDdEIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQy9CLENBQUM7SUFFRDs7T0FFRztJQUNILGFBQWE7UUFDWCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDdEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsUUFBUTtRQUNOLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxXQUFXLENBQUMsV0FBbUI7UUFDckMsTUFBTSxtQkFBbUIsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7YUFDeEQsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRXhELElBQUksQ0FBQyxLQUFLLEdBQUc7WUFDWCxXQUFXLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJO1lBQzVCLFlBQVksRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU07WUFDakMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQztnQkFDeEMsQ0FBQyxDQUFDLG1CQUFtQixHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTTtnQkFDM0MsQ0FBQyxDQUFDLENBQUM7WUFDTCxpQkFBaUIsRUFBRSxJQUFJLENBQUMsbUJBQW1CLEVBQUU7WUFDN0MsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFO1lBQ3JCLFdBQVc7U0FDWixDQUFDO0lBQ0osQ0FBQztJQUVEOztPQUVHO0lBQ0ssbUJBQW1CO1FBQ3pCLG9EQUFvRDtRQUNwRCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxFQUFFLENBQUM7UUFFM0Msc0NBQXNDO1FBQ3RDLE1BQU0sZUFBZSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQzthQUNwRCxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRTVELG1EQUFtRDtRQUNuRCxNQUFNLGFBQWEsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7YUFDbEQsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUUzRCxjQUFjO1FBQ2QsT0FBTyxDQUFDLGFBQWEsR0FBRyxlQUFlLEdBQUcsYUFBYSxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBQ2xFLENBQUM7SUFFRDs7T0FFRztJQUNILE9BQU87UUFDTCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJO1FBQ0YsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQztJQUM3QixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEludmVydGVkIEluZGV4IGZvciBmYXN0IGNvbGxlY3Rpb24gc2VhcmNoXG4gKlxuICogUHJvdmlkZXMgTyhrKSBzZWFyY2ggcGVyZm9ybWFuY2Ugd2hlcmUgayA9IG51bWJlciBvZiBtYXRjaGluZyBlbnRyaWVzXG4gKiBjb21wYXJlZCB0byBPKG4pIGxpbmVhciBzZWFyY2ggdGhyb3VnaCBhbGwgZW50cmllcy5cbiAqXG4gKiBBcmNoaXRlY3R1cmU6XG4gKiAtIFRva2VuIC0+IFNldDxlbnRyeUlkPiBtYXBwaW5nIGZvciBmYXN0IGxvb2t1cHNcbiAqIC0gU2VwYXJhdGUgaW5kZXhlcyBmb3IgZGlmZmVyZW50IGZpZWxkcyAobmFtZSwgZGVzY3JpcHRpb24sIHRhZ3MsIGV0Yy4pXG4gKiAtIEVmZmljaWVudCB0b2tlbml6YXRpb24gd2l0aCBzdG9wIHdvcmQgZmlsdGVyaW5nXG4gKiAtIENhc2UtaW5zZW5zaXRpdmUgd2l0aCBub3JtYWxpemF0aW9uXG4gKi9cblxuaW1wb3J0IHsgSW5kZXhFbnRyeSB9IGZyb20gJy4uL3R5cGVzL2NvbGxlY3Rpb24uanMnO1xuaW1wb3J0IHsgbm9ybWFsaXplU2VhcmNoVGVybSB9IGZyb20gJy4uL3V0aWxzL3NlYXJjaFV0aWxzLmpzJztcblxuLyoqXG4gKiBTaW5nbGUgdG9rZW4gZW50cnkgaW4gdGhlIGludmVydGVkIGluZGV4XG4gKi9cbmludGVyZmFjZSBUb2tlbkVudHJ5IHtcbiAgdG9rZW46IHN0cmluZztcbiAgZW50cnlJZHM6IFNldDxudW1iZXI+O1xuICAvLyBGaWVsZCB3aGVyZSB0aGlzIHRva2VuIGFwcGVhcnMgKGZvciB3ZWlnaHRlZCBzY29yaW5nKVxuICBmaWVsZHM6IE1hcDxudW1iZXIsIFNldDwnbmFtZScgfCAnZGVzY3JpcHRpb24nIHwgJ3RhZ3MnIHwgJ3BhdGgnPj47XG59XG5cbi8qKlxuICogU3RhdGlzdGljcyBhYm91dCB0aGUgaW52ZXJ0ZWQgaW5kZXhcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJbnZlcnRlZEluZGV4U3RhdHMge1xuICB0b3RhbFRva2VuczogbnVtYmVyO1xuICB0b3RhbEVudHJpZXM6IG51bWJlcjtcbiAgYXZnVG9rZW5zUGVyRW50cnk6IG51bWJlcjtcbiAgZXN0aW1hdGVkTWVtb3J5S0I6IG51bWJlcjtcbiAgbGFzdEJ1aWx0OiBEYXRlO1xuICBidWlsZFRpbWVNczogbnVtYmVyO1xufVxuXG4vKipcbiAqIEludmVydGVkIGluZGV4IGZvciBmYXN0IGNvbGxlY3Rpb24gc2VhcmNoXG4gKi9cbmV4cG9ydCBjbGFzcyBJbnZlcnRlZEluZGV4IHtcbiAgLy8gTWFpbiBpbmRleDogdG9rZW4gLT4gZW50cnkgSURzIGFuZCBmaWVsZCBsb2NhdGlvbnNcbiAgcHJpdmF0ZSBpbmRleDogTWFwPHN0cmluZywgVG9rZW5FbnRyeT4gPSBuZXcgTWFwKCk7XG5cbiAgLy8gRW50cnkgc3RvcmFnZTogSUQgLT4gZnVsbCBlbnRyeVxuICBwcml2YXRlIGVudHJpZXM6IEluZGV4RW50cnlbXSA9IFtdO1xuXG4gIC8vIElEIGxvb2t1cDogZW50cnkgcGF0aCAtPiBlbnRyeSBJRFxuICBwcml2YXRlIHBhdGhUb0lkOiBNYXA8c3RyaW5nLCBudW1iZXI+ID0gbmV3IE1hcCgpO1xuXG4gIC8vIFN0YXRpc3RpY3NcbiAgcHJpdmF0ZSBzdGF0czogSW52ZXJ0ZWRJbmRleFN0YXRzID0ge1xuICAgIHRvdGFsVG9rZW5zOiAwLFxuICAgIHRvdGFsRW50cmllczogMCxcbiAgICBhdmdUb2tlbnNQZXJFbnRyeTogMCxcbiAgICBlc3RpbWF0ZWRNZW1vcnlLQjogMCxcbiAgICBsYXN0QnVpbHQ6IG5ldyBEYXRlKCksXG4gICAgYnVpbGRUaW1lTXM6IDBcbiAgfTtcblxuICAvKipcbiAgICogQnVpbGQgaW52ZXJ0ZWQgaW5kZXggZnJvbSBlbnRyaWVzXG4gICAqL1xuICBidWlsZChlbnRyaWVzOiBJbmRleEVudHJ5W10pOiB2b2lkIHtcbiAgICBjb25zdCBzdGFydFRpbWUgPSBwZXJmb3JtYW5jZS5ub3coKTtcblxuICAgIC8vIENsZWFyIGV4aXN0aW5nIGluZGV4XG4gICAgdGhpcy5pbmRleC5jbGVhcigpO1xuICAgIHRoaXMuZW50cmllcyA9IFtdO1xuICAgIHRoaXMucGF0aFRvSWQuY2xlYXIoKTtcblxuICAgIC8vIEJ1aWxkIGluZGV4XG4gICAgZW50cmllcy5mb3JFYWNoKChlbnRyeSwgaWR4KSA9PiB7XG4gICAgICAvLyBTdG9yZSBlbnRyeVxuICAgICAgdGhpcy5lbnRyaWVzLnB1c2goZW50cnkpO1xuICAgICAgdGhpcy5wYXRoVG9JZC5zZXQoZW50cnkucGF0aCwgaWR4KTtcblxuICAgICAgLy8gVG9rZW5pemUgYW5kIGluZGV4IGVhY2ggZmllbGRcbiAgICAgIHRoaXMuaW5kZXhGaWVsZChpZHgsIGVudHJ5Lm5hbWUsICduYW1lJyk7XG4gICAgICB0aGlzLmluZGV4RmllbGQoaWR4LCBlbnRyeS5kZXNjcmlwdGlvbiwgJ2Rlc2NyaXB0aW9uJyk7XG4gICAgICB0aGlzLmluZGV4RmllbGQoaWR4LCBlbnRyeS5wYXRoLCAncGF0aCcpO1xuXG4gICAgICAvLyBJbmRleCB0YWdzIHNlcGFyYXRlbHlcbiAgICAgIGVudHJ5LnRhZ3MuZm9yRWFjaCh0YWcgPT4ge1xuICAgICAgICB0aGlzLmluZGV4RmllbGQoaWR4LCB0YWcsICd0YWdzJyk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIFVwZGF0ZSBzdGF0aXN0aWNzXG4gICAgY29uc3QgZW5kVGltZSA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgIHRoaXMudXBkYXRlU3RhdHMoZW5kVGltZSAtIHN0YXJ0VGltZSk7XG4gIH1cblxuICAvKipcbiAgICogSW5kZXggYSBzaW5nbGUgZmllbGQgZm9yIGFuIGVudHJ5XG4gICAqL1xuICBwcml2YXRlIGluZGV4RmllbGQoXG4gICAgZW50cnlJZDogbnVtYmVyLFxuICAgIGZpZWxkVmFsdWU6IHN0cmluZyxcbiAgICBmaWVsZE5hbWU6ICduYW1lJyB8ICdkZXNjcmlwdGlvbicgfCAndGFncycgfCAncGF0aCdcbiAgKTogdm9pZCB7XG4gICAgY29uc3QgdG9rZW5zID0gdGhpcy50b2tlbml6ZShmaWVsZFZhbHVlKTtcblxuICAgIHRva2Vucy5mb3JFYWNoKHRva2VuID0+IHtcbiAgICAgIGxldCB0b2tlbkVudHJ5ID0gdGhpcy5pbmRleC5nZXQodG9rZW4pO1xuXG4gICAgICBpZiAoIXRva2VuRW50cnkpIHtcbiAgICAgICAgdG9rZW5FbnRyeSA9IHtcbiAgICAgICAgICB0b2tlbixcbiAgICAgICAgICBlbnRyeUlkczogbmV3IFNldCgpLFxuICAgICAgICAgIGZpZWxkczogbmV3IE1hcCgpXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaW5kZXguc2V0KHRva2VuLCB0b2tlbkVudHJ5KTtcbiAgICAgIH1cblxuICAgICAgLy8gQWRkIGVudHJ5IElEIHRvIHRoaXMgdG9rZW5cbiAgICAgIHRva2VuRW50cnkuZW50cnlJZHMuYWRkKGVudHJ5SWQpO1xuXG4gICAgICAvLyBUcmFjayB3aGljaCBmaWVsZCB0aGlzIHRva2VuIGFwcGVhcnMgaW5cbiAgICAgIGlmICghdG9rZW5FbnRyeS5maWVsZHMuaGFzKGVudHJ5SWQpKSB7XG4gICAgICAgIHRva2VuRW50cnkuZmllbGRzLnNldChlbnRyeUlkLCBuZXcgU2V0KCkpO1xuICAgICAgfVxuICAgICAgdG9rZW5FbnRyeS5maWVsZHMuZ2V0KGVudHJ5SWQpIS5hZGQoZmllbGROYW1lKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUb2tlbml6ZSBhIHN0cmluZyBpbnRvIHNlYXJjaGFibGUgdG9rZW5zXG4gICAqXG4gICAqIFVzZXMgdGhlIHNhbWUgbm9ybWFsaXphdGlvbiBhcyBzZWFyY2hVdGlscyBmb3IgY29uc2lzdGVuY3lcbiAgICovXG4gIHByaXZhdGUgdG9rZW5pemUodGV4dDogc3RyaW5nKTogc3RyaW5nW10ge1xuICAgIGlmICghdGV4dCB8fCB0ZXh0LnRyaW0oKS5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICAvLyBOb3JtYWxpemUgdXNpbmcgc2hhcmVkIHV0aWxpdHlcbiAgICBjb25zdCBub3JtYWxpemVkID0gbm9ybWFsaXplU2VhcmNoVGVybSh0ZXh0KTtcblxuICAgIC8vIFNwbGl0IGludG8gd29yZHNcbiAgICBjb25zdCB0b2tlbnMgPSBub3JtYWxpemVkLnNwbGl0KC9cXHMrLykuZmlsdGVyKHRva2VuID0+IHtcbiAgICAgIC8vIFJlbW92ZSBlbXB0eSB0b2tlbnMgYW5kIGNvbW1vbiBzdG9wIHdvcmRzXG4gICAgICByZXR1cm4gdG9rZW4ubGVuZ3RoID4gMCAmJiAhdGhpcy5pc1N0b3BXb3JkKHRva2VuKTtcbiAgICB9KTtcblxuICAgIHJldHVybiB0b2tlbnM7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgYSB0b2tlbiBpcyBhIGNvbW1vbiBzdG9wIHdvcmRcbiAgICpcbiAgICogU3RvcCB3b3JkcyBhcmUgZmlsdGVyZWQgdG8gcmVkdWNlIGluZGV4IHNpemUgYW5kIGltcHJvdmUgcmVsZXZhbmNlXG4gICAqL1xuICBwcml2YXRlIGlzU3RvcFdvcmQodG9rZW46IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIC8vIENvbW1vbiBFbmdsaXNoIHN0b3Agd29yZHMgdGhhdCBkb24ndCBhZGQgc2VhcmNoIHZhbHVlXG4gICAgY29uc3Qgc3RvcFdvcmRzID0gbmV3IFNldChbXG4gICAgICAnYScsICdhbicsICdhbmQnLCAnYXJlJywgJ2FzJywgJ2F0JywgJ2JlJywgJ2J5JywgJ2ZvcicsXG4gICAgICAnZnJvbScsICdoYXMnLCAnaGUnLCAnaW4nLCAnaXMnLCAnaXQnLCAnaXRzJywgJ29mJywgJ29uJyxcbiAgICAgICd0aGF0JywgJ3RoZScsICd0bycsICd3YXMnLCAnd2lsbCcsICd3aXRoJ1xuICAgIF0pO1xuXG4gICAgcmV0dXJuIHN0b3BXb3Jkcy5oYXModG9rZW4pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlYXJjaCB0aGUgaW5kZXggZm9yIG1hdGNoaW5nIGVudHJpZXNcbiAgICpcbiAgICogUmV0dXJucyBlbnRyeSBJRHMgbWF0Y2hpbmcgdGhlIHF1ZXJ5IHdpdGggcmVsZXZhbmNlIHNjb3Jlc1xuICAgKi9cbiAgc2VhcmNoKHF1ZXJ5OiBzdHJpbmcpOiBBcnJheTx7IGVudHJ5SWQ6IG51bWJlcjsgc2NvcmU6IG51bWJlciB9PiB7XG4gICAgY29uc3QgcXVlcnlUb2tlbnMgPSB0aGlzLnRva2VuaXplKHF1ZXJ5KTtcblxuICAgIGlmIChxdWVyeVRva2Vucy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICAvLyBGaW5kIGFsbCBlbnRyaWVzIG1hdGNoaW5nIGFueSBxdWVyeSB0b2tlblxuICAgIGNvbnN0IGNhbmRpZGF0ZVNjb3JlcyA9IG5ldyBNYXA8bnVtYmVyLCBudW1iZXI+KCk7XG5cbiAgICBxdWVyeVRva2Vucy5mb3JFYWNoKHF1ZXJ5VG9rZW4gPT4ge1xuICAgICAgY29uc3QgdG9rZW5FbnRyeSA9IHRoaXMuaW5kZXguZ2V0KHF1ZXJ5VG9rZW4pO1xuXG4gICAgICBpZiAodG9rZW5FbnRyeSkge1xuICAgICAgICAvLyBBZGQgbWF0Y2hpbmcgZW50cmllcyB3aXRoIGZpZWxkLWJhc2VkIHNjb3JpbmdcbiAgICAgICAgdG9rZW5FbnRyeS5lbnRyeUlkcy5mb3JFYWNoKGVudHJ5SWQgPT4ge1xuICAgICAgICAgIGNvbnN0IGZpZWxkcyA9IHRva2VuRW50cnkuZmllbGRzLmdldChlbnRyeUlkKTtcbiAgICAgICAgICBjb25zdCBzY29yZSA9IHRoaXMuY2FsY3VsYXRlRmllbGRTY29yZShmaWVsZHMpO1xuXG4gICAgICAgICAgLy8gQWNjdW11bGF0ZSBzY29yZXMgKG11bHRpcGxlIHRva2VuIG1hdGNoZXMgaW5jcmVhc2UgcmVsZXZhbmNlKVxuICAgICAgICAgIGNvbnN0IGN1cnJlbnRTY29yZSA9IGNhbmRpZGF0ZVNjb3Jlcy5nZXQoZW50cnlJZCkgfHwgMDtcbiAgICAgICAgICBjYW5kaWRhdGVTY29yZXMuc2V0KGVudHJ5SWQsIGN1cnJlbnRTY29yZSArIHNjb3JlKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBDb252ZXJ0IHRvIGFycmF5IGFuZCBzb3J0IGJ5IHNjb3JlXG4gICAgcmV0dXJuIEFycmF5LmZyb20oY2FuZGlkYXRlU2NvcmVzLmVudHJpZXMoKSlcbiAgICAgIC5tYXAoKFtlbnRyeUlkLCBzY29yZV0pID0+ICh7IGVudHJ5SWQsIHNjb3JlIH0pKVxuICAgICAgLnNvcnQoKGEsIGIpID0+IGIuc2NvcmUgLSBhLnNjb3JlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgcmVsZXZhbmNlIHNjb3JlIGJhc2VkIG9uIHdoaWNoIGZpZWxkcyBtYXRjaGVkXG4gICAqXG4gICAqIE5hbWUgbWF0Y2hlcyBhcmUgbW9zdCByZWxldmFudCwgZm9sbG93ZWQgYnkgdGFncywgZGVzY3JpcHRpb24sIHBhdGhcbiAgICovXG4gIHByaXZhdGUgY2FsY3VsYXRlRmllbGRTY29yZShmaWVsZHM6IFNldDwnbmFtZScgfCAnZGVzY3JpcHRpb24nIHwgJ3RhZ3MnIHwgJ3BhdGgnPiB8IHVuZGVmaW5lZCk6IG51bWJlciB7XG4gICAgaWYgKCFmaWVsZHMpIHJldHVybiAwO1xuXG4gICAgbGV0IHNjb3JlID0gMDtcblxuICAgIC8vIEZpZWxkIHdlaWdodHMgKG5hbWUgaXMgbW9zdCBpbXBvcnRhbnQpXG4gICAgaWYgKGZpZWxkcy5oYXMoJ25hbWUnKSkgc2NvcmUgKz0gMTAwO1xuICAgIGlmIChmaWVsZHMuaGFzKCd0YWdzJykpIHNjb3JlICs9IDI1O1xuICAgIGlmIChmaWVsZHMuaGFzKCdkZXNjcmlwdGlvbicpKSBzY29yZSArPSA1MDtcbiAgICBpZiAoZmllbGRzLmhhcygncGF0aCcpKSBzY29yZSArPSAxMDtcblxuICAgIHJldHVybiBzY29yZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZW50cnkgYnkgSURcbiAgICovXG4gIGdldEVudHJ5KGVudHJ5SWQ6IG51bWJlcik6IEluZGV4RW50cnkgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmVudHJpZXNbZW50cnlJZF07XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFsbCBlbnRyaWVzIChmb3IgZmlsdGVyaW5nL3NvcnRpbmcgYWZ0ZXIgc2VhcmNoKVxuICAgKi9cbiAgZ2V0QWxsRW50cmllcygpOiBJbmRleEVudHJ5W10ge1xuICAgIHJldHVybiB0aGlzLmVudHJpZXM7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGluZGV4IHN0YXRpc3RpY3NcbiAgICovXG4gIGdldFN0YXRzKCk6IEludmVydGVkSW5kZXhTdGF0cyB7XG4gICAgcmV0dXJuIHsgLi4udGhpcy5zdGF0cyB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZSBzdGF0aXN0aWNzIGFmdGVyIGluZGV4IGJ1aWxkXG4gICAqL1xuICBwcml2YXRlIHVwZGF0ZVN0YXRzKGJ1aWxkVGltZU1zOiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCB0b3RhbFRva2VuSW5zdGFuY2VzID0gQXJyYXkuZnJvbSh0aGlzLmluZGV4LnZhbHVlcygpKVxuICAgICAgLnJlZHVjZSgoc3VtLCBlbnRyeSkgPT4gc3VtICsgZW50cnkuZW50cnlJZHMuc2l6ZSwgMCk7XG5cbiAgICB0aGlzLnN0YXRzID0ge1xuICAgICAgdG90YWxUb2tlbnM6IHRoaXMuaW5kZXguc2l6ZSxcbiAgICAgIHRvdGFsRW50cmllczogdGhpcy5lbnRyaWVzLmxlbmd0aCxcbiAgICAgIGF2Z1Rva2Vuc1BlckVudHJ5OiB0aGlzLmVudHJpZXMubGVuZ3RoID4gMFxuICAgICAgICA/IHRvdGFsVG9rZW5JbnN0YW5jZXMgLyB0aGlzLmVudHJpZXMubGVuZ3RoXG4gICAgICAgIDogMCxcbiAgICAgIGVzdGltYXRlZE1lbW9yeUtCOiB0aGlzLmVzdGltYXRlTWVtb3J5VXNhZ2UoKSxcbiAgICAgIGxhc3RCdWlsdDogbmV3IERhdGUoKSxcbiAgICAgIGJ1aWxkVGltZU1zXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFc3RpbWF0ZSBtZW1vcnkgdXNhZ2Ugb2YgdGhlIGluZGV4XG4gICAqL1xuICBwcml2YXRlIGVzdGltYXRlTWVtb3J5VXNhZ2UoKTogbnVtYmVyIHtcbiAgICAvLyBUb2tlbiBzdHJpbmcgb3ZlcmhlYWQ6IH41MCBieXRlcyBwZXIgdW5pcXVlIHRva2VuXG4gICAgY29uc3QgdG9rZW5PdmVyaGVhZCA9IHRoaXMuaW5kZXguc2l6ZSAqIDUwO1xuXG4gICAgLy8gU2V0IG92ZXJoZWFkOiB+OCBieXRlcyBwZXIgZW50cnkgSURcbiAgICBjb25zdCBlbnRyeUlkT3ZlcmhlYWQgPSBBcnJheS5mcm9tKHRoaXMuaW5kZXgudmFsdWVzKCkpXG4gICAgICAucmVkdWNlKChzdW0sIGVudHJ5KSA9PiBzdW0gKyBlbnRyeS5lbnRyeUlkcy5zaXplICogOCwgMCk7XG5cbiAgICAvLyBGaWVsZCBtYXAgb3ZlcmhlYWQ6IH4xNiBieXRlcyBwZXIgZmllbGQgdHJhY2tpbmdcbiAgICBjb25zdCBmaWVsZE92ZXJoZWFkID0gQXJyYXkuZnJvbSh0aGlzLmluZGV4LnZhbHVlcygpKVxuICAgICAgLnJlZHVjZSgoc3VtLCBlbnRyeSkgPT4gc3VtICsgZW50cnkuZmllbGRzLnNpemUgKiAxNiwgMCk7XG5cbiAgICAvLyBUb3RhbCBpbiBLQlxuICAgIHJldHVybiAodG9rZW5PdmVyaGVhZCArIGVudHJ5SWRPdmVyaGVhZCArIGZpZWxkT3ZlcmhlYWQpIC8gMTAyNDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBpbmRleCBpcyBlbXB0eVxuICAgKi9cbiAgaXNFbXB0eSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5lbnRyaWVzLmxlbmd0aCA9PT0gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgbnVtYmVyIG9mIGluZGV4ZWQgZW50cmllc1xuICAgKi9cbiAgc2l6ZSgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmVudHJpZXMubGVuZ3RoO1xuICB9XG59XG4iXX0=