Files
rspade_system/storage-broken/rsx-tmp/babel_ef09ea5d75a0a5536aad9638ff22c731.js
root 77b4d10af8 Refactor filename naming system and apply convention-based renames
Standardize settings file naming and relocate documentation files
Fix code quality violations from rsx:check
Reorganize user_management directory into logical subdirectories
Move Quill Bundle to core and align with Tom Select pattern
Simplify Site Settings page to focus on core site information
Complete Phase 5: Multi-tenant authentication with login flow and site selection
Add route query parameter rule and synchronize filename validation logic
Fix critical bug in UpdateNpmCommand causing missing JavaScript stubs
Implement filename convention rule and resolve VS Code auto-rename conflict
Implement js-sanitizer RPC server to eliminate 900+ Node.js process spawns
Implement RPC server architecture for JavaScript parsing
WIP: Add RPC server infrastructure for JS parsing (partial implementation)
Update jqhtml terminology from destroy to stop, fix datagrid DOM preservation
Add JQHTML-CLASS-01 rule and fix redundant class names
Improve code quality rules and resolve violations
Remove legacy fatal error format in favor of unified 'fatal' error type
Filter internal keys from window.rsxapp output
Update button styling and comprehensive form/modal documentation
Add conditional fly-in animation for modals
Fix non-deterministic bundle compilation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 19:10:02 +00:00

350 lines
40 KiB
JavaScript
Executable File

"use strict";
/**
* Manifest - JavaScript class registry and metadata system
*
* This class maintains a registry of all JavaScript classes in the bundle,
* tracking their names and inheritance relationships. It provides utilities
* for working with class hierarchies and calling initialization methods.
*/
class Manifest {
/**
* Define classes in the manifest (framework internal)
* @param {Array} items - Array of class definitions [[Class, "ClassName", ParentClass, decorators], ...]
*/
static _define(items) {
// Initialize the classes object if not already defined
if (typeof Manifest._classes === 'undefined') {
Manifest._classes = {};
}
// Process each class definition
items.forEach(item => {
let class_object = item[0];
let class_name = item[1];
let class_extends = item[2] || null;
let decorators = item[3] || null;
// Store the class information (using object to avoid duplicates)
Manifest._classes[class_name] = {
class: class_object,
name: class_name,
extends: class_extends,
decorators: decorators // Store compact decorator data
};
// Add metadata to the class object itself
class_object._name = class_name;
class_object._extends = class_extends;
class_object._decorators = decorators;
});
// Build the subclass index after all classes are defined
Manifest._build_subclass_index();
}
/**
* Build an index of subclasses for efficient lookups
* This creates a mapping where each class name points to an array of all its subclasses
* @private
*/
static _build_subclass_index() {
// Initialize the subclass index
Manifest._subclass_index = {};
// Step through each class and walk up its parent chain
for (let class_name in Manifest._classes) {
const classdata = Manifest._classes[class_name];
let current_class_name = class_name;
let current_classdata = classdata;
// Walk up the parent chain until we reach the root
while (current_classdata) {
const extends_name = current_classdata.extends;
if (extends_name) {
// Initialize the parent's subclass array if needed
if (!Manifest._subclass_index[extends_name]) {
Manifest._subclass_index[extends_name] = [];
}
// Add this class to its parent's subclass list
if (!Manifest._subclass_index[extends_name].includes(class_name)) {
Manifest._subclass_index[extends_name].push(class_name);
}
// Move up to the parent's metadata (if it exists in manifest)
if (Manifest._classes[extends_name]) {
current_classdata = Manifest._classes[extends_name];
} else {
// Parent not in manifest (e.g., native JavaScript class), stop here
current_classdata = null;
}
} else {
// No parent, we've reached the root
current_classdata = null;
}
}
}
}
/**
* Get all classes that extend a given base class
* @param {Class|string} base_class - The base class (object or name string) to check for
* @returns {Array} Array of objects with {class_name, class_object} for classes that extend the base class
*/
static get_extending(base_class) {
if (!Manifest._classes) {
return [];
}
// Convert string to class object if needed
let base_class_object = base_class;
if (typeof base_class === 'string') {
base_class_object = Manifest.get_class_by_name(base_class);
if (!base_class_object) {
throw new Error(`Base class not found: ${base_class}`);
}
}
const classes = [];
for (let class_name in Manifest._classes) {
const classdata = Manifest._classes[class_name];
if (Manifest.js_is_subclass_of(classdata.class, base_class_object)) {
classes.push({
class_name: class_name,
class_object: classdata.class
});
}
}
// Sort alphabetically by class name to ensure deterministic behavior and prevent race condition bugs
classes.sort((a, b) => a.class_name.localeCompare(b.class_name));
return classes;
}
/**
* Check if a class is a subclass of another class
* Matches PHP Manifest::js_is_subclass_of() signature and behavior
* @param {Class|string} subclass - The child class (object or name) to check
* @param {Class|string} superclass - The parent class (object or name) to check against
* @returns {boolean} True if subclass extends superclass (directly or indirectly)
*/
static js_is_subclass_of(subclass, superclass) {
// Convert string names to class objects
let subclass_object = subclass;
if (typeof subclass === 'string') {
subclass_object = Manifest.get_class_by_name(subclass);
if (!subclass_object) {
// Can't resolve subclass - return false per spec
return false;
}
}
let superclass_object = superclass;
if (typeof superclass === 'string') {
superclass_object = Manifest.get_class_by_name(superclass);
if (!superclass_object) {
// Can't resolve superclass - fail loud per spec
throw new Error(`Superclass not found in manifest: ${superclass}`);
}
}
// Classes are not subclasses of themselves
if (subclass_object === superclass_object) {
return false;
}
// Walk up the inheritance chain
let current_class = subclass_object;
while (current_class) {
if (current_class === superclass_object) {
return true;
}
// Move up to parent class
if (current_class._extends) {
// _extends may be a string or class reference
if (typeof current_class._extends === 'string') {
current_class = Manifest.get_class_by_name(current_class._extends);
} else {
current_class = current_class._extends;
}
} else {
current_class = null;
}
}
return false;
}
/**
* Get a class by its name
* @param {string} class_name - The name of the class
* @returns {Class|null} The class object or null if not found
*/
static get_class_by_name(class_name) {
if (!Manifest._classes || !Manifest._classes[class_name]) {
return null;
}
return Manifest._classes[class_name].class;
}
/**
* Get all registered classes
* @returns {Array} Array of objects with {class_name, class_object, extends}
*/
static get_all_classes() {
if (!Manifest._classes) {
return [];
}
const results = [];
for (let class_name in Manifest._classes) {
const classdata = Manifest._classes[class_name];
results.push({
class_name: classdata.name,
class_object: classdata.class,
extends: classdata.extends
});
}
// Sort alphabetically by class name to ensure deterministic behavior and prevent race condition bugs
results.sort((a, b) => a.class_name.localeCompare(b.class_name));
return results;
}
/**
* Get the build key from the application configuration
* @returns {string} The build key or "NOBUILD" if not available
*/
static build_key() {
if (window.rsxapp && window.rsxapp.build_key) {
return window.rsxapp.build_key;
}
return 'NOBUILD';
}
/**
* Get decorators for a specific class and method
* @param {string|Class} class_name - The class name or class object
* @param {string} method_name - The method name
* @returns {Array|null} Array of decorator objects or null if none found
*/
static get_decorators(class_name, method_name) {
// Convert class object to name if needed
if (typeof class_name !== 'string') {
class_name = class_name._name || class_name.name;
}
const class_info = Manifest._classes[class_name];
if (!class_info || !class_info.decorators || !class_info.decorators[method_name]) {
return null;
}
// Transform compact format to object format
return Manifest._transform_decorators(class_info.decorators[method_name]);
}
/**
* Get all methods with decorators for a class
* @param {string|Class} class_name - The class name or class object
* @returns {Object} Object with method names as keys and decorator arrays as values
*/
static get_all_decorators(class_name) {
// Convert class object to name if needed
if (typeof class_name !== 'string') {
class_name = class_name._name || class_name.name;
}
const class_info = Manifest._classes[class_name];
if (!class_info || !class_info.decorators) {
return {};
}
// Transform all decorators from compact to object format
const result = {};
for (let method_name in class_info.decorators) {
result[method_name] = Manifest._transform_decorators(class_info.decorators[method_name]);
}
return result;
}
/**
* Transform compact decorator format to object format
* @param {Array} compact_decorators - Array of [name, [args]] tuples
* @returns {Array} Array of decorator objects with name and arguments properties
* @private
*/
static _transform_decorators(compact_decorators) {
if (!Array.isArray(compact_decorators)) {
return [];
}
return compact_decorators.map(decorator => {
if (Array.isArray(decorator) && decorator.length >= 2) {
return {
name: decorator[0],
arguments: decorator[1] || []
};
}
// Handle malformed decorator data
return {
name: 'unknown',
arguments: []
};
});
}
/**
* Check if a method has a specific decorator
* @param {string|Class} class_name - The class name or class object
* @param {string} method_name - The method name
* @param {string} decorator_name - The decorator name to check for
* @returns {boolean} True if the method has the decorator
*/
static has_decorator(class_name, method_name, decorator_name) {
const decorators = Manifest.get_decorators(class_name, method_name);
if (!decorators) {
return false;
}
return decorators.some(d => d.name === decorator_name);
}
/**
* Get all subclasses of a given class using the pre-built index
* This is the JavaScript equivalent of PHP's Manifest::js_get_subclasses_of()
* @param {Class|string} base_class - The base class (object or name string) to get subclasses of
* @returns {Array<Class>} Array of actual class objects that are subclasses of the base class
*/
static js_get_subclasses_of(base_class) {
// Initialize index if needed
if (!Manifest._subclass_index) {
Manifest._build_subclass_index();
}
// Convert class object to name if needed
let base_class_name = base_class;
if (typeof base_class !== 'string') {
base_class_name = base_class._name || base_class.name;
}
// Check if the base class exists
if (!Manifest._classes[base_class_name]) {
// Base class not in manifest - return empty array
return [];
}
// Get subclass names from the index
const subclass_names = Manifest._subclass_index[base_class_name] || [];
// Convert names to actual class objects
const subclass_objects = [];
for (let subclass_name of subclass_names) {
const classdata = Manifest._classes[subclass_name];
subclass_objects.push(classdata.class);
}
// Sort by class name for deterministic behavior
subclass_objects.sort((a, b) => {
const name_a = a._name || a.name;
const name_b = b._name || b.name;
return name_a.localeCompare(name_b);
});
return subclass_objects;
}
}
// RSX manifest automatically makes classes global - no manual assignment needed
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNYW5pZmVzdCIsIl9kZWZpbmUiLCJpdGVtcyIsIl9jbGFzc2VzIiwiZm9yRWFjaCIsIml0ZW0iLCJjbGFzc19vYmplY3QiLCJjbGFzc19uYW1lIiwiY2xhc3NfZXh0ZW5kcyIsImRlY29yYXRvcnMiLCJjbGFzcyIsIm5hbWUiLCJleHRlbmRzIiwiX25hbWUiLCJfZXh0ZW5kcyIsIl9kZWNvcmF0b3JzIiwiX2J1aWxkX3N1YmNsYXNzX2luZGV4IiwiX3N1YmNsYXNzX2luZGV4IiwiY2xhc3NkYXRhIiwiY3VycmVudF9jbGFzc19uYW1lIiwiY3VycmVudF9jbGFzc2RhdGEiLCJleHRlbmRzX25hbWUiLCJpbmNsdWRlcyIsInB1c2giLCJnZXRfZXh0ZW5kaW5nIiwiYmFzZV9jbGFzcyIsImJhc2VfY2xhc3Nfb2JqZWN0IiwiZ2V0X2NsYXNzX2J5X25hbWUiLCJFcnJvciIsImNsYXNzZXMiLCJqc19pc19zdWJjbGFzc19vZiIsInNvcnQiLCJhIiwiYiIsImxvY2FsZUNvbXBhcmUiLCJzdWJjbGFzcyIsInN1cGVyY2xhc3MiLCJzdWJjbGFzc19vYmplY3QiLCJzdXBlcmNsYXNzX29iamVjdCIsImN1cnJlbnRfY2xhc3MiLCJnZXRfYWxsX2NsYXNzZXMiLCJyZXN1bHRzIiwiYnVpbGRfa2V5Iiwid2luZG93IiwicnN4YXBwIiwiZ2V0X2RlY29yYXRvcnMiLCJtZXRob2RfbmFtZSIsImNsYXNzX2luZm8iLCJfdHJhbnNmb3JtX2RlY29yYXRvcnMiLCJnZXRfYWxsX2RlY29yYXRvcnMiLCJyZXN1bHQiLCJjb21wYWN0X2RlY29yYXRvcnMiLCJBcnJheSIsImlzQXJyYXkiLCJtYXAiLCJkZWNvcmF0b3IiLCJsZW5ndGgiLCJhcmd1bWVudHMiLCJoYXNfZGVjb3JhdG9yIiwiZGVjb3JhdG9yX25hbWUiLCJzb21lIiwiZCIsImpzX2dldF9zdWJjbGFzc2VzX29mIiwiYmFzZV9jbGFzc19uYW1lIiwic3ViY2xhc3NfbmFtZXMiLCJzdWJjbGFzc19vYmplY3RzIiwic3ViY2xhc3NfbmFtZSIsIm5hbWVfYSIsIm5hbWVfYiJdLCJzb3VyY2VzIjpbImFwcC9SU3BhZGUvQ29yZS9Kcy9NYW5pZmVzdC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1hbmlmZXN0IC0gSmF2YVNjcmlwdCBjbGFzcyByZWdpc3RyeSBhbmQgbWV0YWRhdGEgc3lzdGVtXG4gKlxuICogVGhpcyBjbGFzcyBtYWludGFpbnMgYSByZWdpc3RyeSBvZiBhbGwgSmF2YVNjcmlwdCBjbGFzc2VzIGluIHRoZSBidW5kbGUsXG4gKiB0cmFja2luZyB0aGVpciBuYW1lcyBhbmQgaW5oZXJpdGFuY2UgcmVsYXRpb25zaGlwcy4gSXQgcHJvdmlkZXMgdXRpbGl0aWVzXG4gKiBmb3Igd29ya2luZyB3aXRoIGNsYXNzIGhpZXJhcmNoaWVzIGFuZCBjYWxsaW5nIGluaXRpYWxpemF0aW9uIG1ldGhvZHMuXG4gKi9cbmNsYXNzIE1hbmlmZXN0IHtcbiAgICAvKipcbiAgICAgKiBEZWZpbmUgY2xhc3NlcyBpbiB0aGUgbWFuaWZlc3QgKGZyYW1ld29yayBpbnRlcm5hbClcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBpdGVtcyAtIEFycmF5IG9mIGNsYXNzIGRlZmluaXRpb25zIFtbQ2xhc3MsIFwiQ2xhc3NOYW1lXCIsIFBhcmVudENsYXNzLCBkZWNvcmF0b3JzXSwgLi4uXVxuICAgICAqL1xuICAgIHN0YXRpYyBfZGVmaW5lKGl0ZW1zKSB7XG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIGNsYXNzZXMgb2JqZWN0IGlmIG5vdCBhbHJlYWR5IGRlZmluZWRcbiAgICAgICAgaWYgKHR5cGVvZiBNYW5pZmVzdC5fY2xhc3NlcyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIE1hbmlmZXN0Ll9jbGFzc2VzID0ge307XG4gICAgICAgIH1cblxuICAgICAgICAvLyBQcm9jZXNzIGVhY2ggY2xhc3MgZGVmaW5pdGlvblxuICAgICAgICBpdGVtcy5mb3JFYWNoKChpdGVtKSA9PiB7XG4gICAgICAgICAgICBsZXQgY2xhc3Nfb2JqZWN0ID0gaXRlbVswXTtcbiAgICAgICAgICAgIGxldCBjbGFzc19uYW1lID0gaXRlbVsxXTtcbiAgICAgICAgICAgIGxldCBjbGFzc19leHRlbmRzID0gaXRlbVsyXSB8fCBudWxsO1xuICAgICAgICAgICAgbGV0IGRlY29yYXRvcnMgPSBpdGVtWzNdIHx8IG51bGw7XG5cbiAgICAgICAgICAgIC8vIFN0b3JlIHRoZSBjbGFzcyBpbmZvcm1hdGlvbiAodXNpbmcgb2JqZWN0IHRvIGF2b2lkIGR1cGxpY2F0ZXMpXG4gICAgICAgICAgICBNYW5pZmVzdC5fY2xhc3Nlc1tjbGFzc19uYW1lXSA9IHtcbiAgICAgICAgICAgICAgICBjbGFzczogY2xhc3Nfb2JqZWN0LFxuICAgICAgICAgICAgICAgIG5hbWU6IGNsYXNzX25hbWUsXG4gICAgICAgICAgICAgICAgZXh0ZW5kczogY2xhc3NfZXh0ZW5kcyxcbiAgICAgICAgICAgICAgICBkZWNvcmF0b3JzOiBkZWNvcmF0b3JzLCAgLy8gU3RvcmUgY29tcGFjdCBkZWNvcmF0b3IgZGF0YVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy8gQWRkIG1ldGFkYXRhIHRvIHRoZSBjbGFzcyBvYmplY3QgaXRzZWxmXG4gICAgICAgICAgICBjbGFzc19vYmplY3QuX25hbWUgPSBjbGFzc19uYW1lO1xuICAgICAgICAgICAgY2xhc3Nfb2JqZWN0Ll9leHRlbmRzID0gY2xhc3NfZXh0ZW5kcztcbiAgICAgICAgICAgIGNsYXNzX29iamVjdC5fZGVjb3JhdG9ycyA9IGRlY29yYXRvcnM7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEJ1aWxkIHRoZSBzdWJjbGFzcyBpbmRleCBhZnRlciBhbGwgY2xhc3NlcyBhcmUgZGVmaW5lZFxuICAgICAgICBNYW5pZmVzdC5fYnVpbGRfc3ViY2xhc3NfaW5kZXgoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBCdWlsZCBhbiBpbmRleCBvZiBzdWJjbGFzc2VzIGZvciBlZmZpY2llbnQgbG9va3Vwc1xuICAgICAqIFRoaXMgY3JlYXRlcyBhIG1hcHBpbmcgd2hlcmUgZWFjaCBjbGFzcyBuYW1lIHBvaW50cyB0byBhbiBhcnJheSBvZiBhbGwgaXRzIHN1YmNsYXNzZXNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBfYnVpbGRfc3ViY2xhc3NfaW5kZXgoKSB7XG4gICAgICAgIC8vIEluaXRpYWxpemUgdGhlIHN1YmNsYXNzIGluZGV4XG4gICAgICAgIE1hbmlmZXN0Ll9zdWJjbGFzc19pbmRleCA9IHt9O1xuXG4gICAgICAgIC8vIFN0ZXAgdGhyb3VnaCBlYWNoIGNsYXNzIGFuZCB3YWxrIHVwIGl0cyBwYXJlbnQgY2hhaW5cbiAgICAgICAgZm9yIChsZXQgY2xhc3NfbmFtZSBpbiBNYW5pZmVzdC5fY2xhc3Nlcykge1xuICAgICAgICAgICAgY29uc3QgY2xhc3NkYXRhID0gTWFuaWZlc3QuX2NsYXNzZXNbY2xhc3NfbmFtZV07XG4gICAgICAgICAgICBsZXQgY3VycmVudF9jbGFzc19uYW1lID0gY2xhc3NfbmFtZTtcbiAgICAgICAgICAgIGxldCBjdXJyZW50X2NsYXNzZGF0YSA9IGNsYXNzZGF0YTtcblxuICAgICAgICAgICAgLy8gV2FsayB1cCB0aGUgcGFyZW50IGNoYWluIHVudGlsIHdlIHJlYWNoIHRoZSByb290XG4gICAgICAgICAgICB3aGlsZSAoY3VycmVudF9jbGFzc2RhdGEpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBleHRlbmRzX25hbWUgPSBjdXJyZW50X2NsYXNzZGF0YS5leHRlbmRzO1xuXG4gICAgICAgICAgICAgICAgaWYgKGV4dGVuZHNfbmFtZSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBwYXJlbnQncyBzdWJjbGFzcyBhcnJheSBpZiBuZWVkZWRcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFNYW5pZmVzdC5fc3ViY2xhc3NfaW5kZXhbZXh0ZW5kc19uYW1lXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgTWFuaWZlc3QuX3N1YmNsYXNzX2luZGV4W2V4dGVuZHNfbmFtZV0gPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIEFkZCB0aGlzIGNsYXNzIHRvIGl0cyBwYXJlbnQncyBzdWJjbGFzcyBsaXN0XG4gICAgICAgICAgICAgICAgICAgIGlmICghTWFuaWZlc3QuX3N1YmNsYXNzX2luZGV4W2V4dGVuZHNfbmFtZV0uaW5jbHVkZXMoY2xhc3NfbmFtZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIE1hbmlmZXN0Ll9zdWJjbGFzc19pbmRleFtleHRlbmRzX25hbWVdLnB1c2goY2xhc3NfbmFtZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBNb3ZlIHVwIHRvIHRoZSBwYXJlbnQncyBtZXRhZGF0YSAoaWYgaXQgZXhpc3RzIGluIG1hbmlmZXN0KVxuICAgICAgICAgICAgICAgICAgICBpZiAoTWFuaWZlc3QuX2NsYXNzZXNbZXh0ZW5kc19uYW1lXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudF9jbGFzc2RhdGEgPSBNYW5pZmVzdC5fY2xhc3Nlc1tleHRlbmRzX25hbWVdO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUGFyZW50IG5vdCBpbiBtYW5pZmVzdCAoZS5nLiwgbmF0aXZlIEphdmFTY3JpcHQgY2xhc3MpLCBzdG9wIGhlcmVcbiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRfY2xhc3NkYXRhID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIE5vIHBhcmVudCwgd2UndmUgcmVhY2hlZCB0aGUgcm9vdFxuICAgICAgICAgICAgICAgICAgICBjdXJyZW50X2NsYXNzZGF0YSA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBjbGFzc2VzIHRoYXQgZXh0ZW5kIGEgZ2l2ZW4gYmFzZSBjbGFzc1xuICAgICAqIEBwYXJhbSB7Q2xhc3N8c3RyaW5nfSBiYXNlX2NsYXNzIC0gVGhlIGJhc2UgY2xhc3MgKG9iamVjdCBvciBuYW1lIHN0cmluZykgdG8gY2hlY2sgZm9yXG4gICAgICogQHJldHVybnMge0FycmF5fSBBcnJheSBvZiBvYmplY3RzIHdpdGgge2NsYXNzX25hbWUsIGNsYXNzX29iamVjdH0gZm9yIGNsYXNzZXMgdGhhdCBleHRlbmQgdGhlIGJhc2UgY2xhc3NcbiAgICAgKi9cbiAgICBzdGF0aWMgZ2V0X2V4dGVuZGluZyhiYXNlX2NsYXNzKSB7XG4gICAgICAgIGlmICghTWFuaWZlc3QuX2NsYXNzZXMpIHtcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENvbnZlcnQgc3RyaW5nIHRvIGNsYXNzIG9iamVjdCBpZiBuZWVkZWRcbiAgICAgICAgbGV0IGJhc2VfY2xhc3Nfb2JqZWN0ID0gYmFzZV9jbGFzcztcbiAgICAgICAgaWYgKHR5cGVvZiBiYXNlX2NsYXNzID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgYmFzZV9jbGFzc19vYmplY3QgPSBNYW5pZmVzdC5nZXRfY2xhc3NfYnlfbmFtZShiYXNlX2NsYXNzKTtcbiAgICAgICAgICAgIGlmICghYmFzZV9jbGFzc19vYmplY3QpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEJhc2UgY2xhc3Mgbm90IGZvdW5kOiAke2Jhc2VfY2xhc3N9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjbGFzc2VzID0gW107XG5cbiAgICAgICAgZm9yIChsZXQgY2xhc3NfbmFtZSBpbiBNYW5pZmVzdC5fY2xhc3Nlcykge1xuICAgICAgICAgICAgY29uc3QgY2xhc3NkYXRhID0gTWFuaWZlc3QuX2NsYXNzZXNbY2xhc3NfbmFtZV07XG4gICAgICAgICAgICBpZiAoTWFuaWZlc3QuanNfaXNfc3ViY2xhc3Nfb2YoY2xhc3NkYXRhLmNsYXNzLCBiYXNlX2NsYXNzX29iamVjdCkpIHtcbiAgICAgICAgICAgICAgICBjbGFzc2VzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBjbGFzc19uYW1lOiBjbGFzc19uYW1lLFxuICAgICAgICAgICAgICAgICAgICBjbGFzc19vYmplY3Q6IGNsYXNzZGF0YS5jbGFzcyxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNvcnQgYWxwaGFiZXRpY2FsbHkgYnkgY2xhc3MgbmFtZSB0byBlbnN1cmUgZGV0ZXJtaW5pc3RpYyBiZWhhdmlvciBhbmQgcHJldmVudCByYWNlIGNvbmRpdGlvbiBidWdzXG4gICAgICAgIGNsYXNzZXMuc29ydCgoYSwgYikgPT4gYS5jbGFzc19uYW1lLmxvY2FsZUNvbXBhcmUoYi5jbGFzc19uYW1lKSk7XG5cbiAgICAgICAgcmV0dXJuIGNsYXNzZXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2sgaWYgYSBjbGFzcyBpcyBhIHN1YmNsYXNzIG9mIGFub3RoZXIgY2xhc3NcbiAgICAgKiBNYXRjaGVzIFBIUCBNYW5pZmVzdDo6anNfaXNfc3ViY2xhc3Nfb2YoKSBzaWduYXR1cmUgYW5kIGJlaGF2aW9yXG4gICAgICogQHBhcmFtIHtDbGFzc3xzdHJpbmd9IHN1YmNsYXNzIC0gVGhlIGNoaWxkIGNsYXNzIChvYmplY3Qgb3IgbmFtZSkgdG8gY2hlY2tcbiAgICAgKiBAcGFyYW0ge0NsYXNzfHN0cmluZ30gc3VwZXJjbGFzcyAtIFRoZSBwYXJlbnQgY2xhc3MgKG9iamVjdCBvciBuYW1lKSB0byBjaGVjayBhZ2FpbnN0XG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgc3ViY2xhc3MgZXh0ZW5kcyBzdXBlcmNsYXNzIChkaXJlY3RseSBvciBpbmRpcmVjdGx5KVxuICAgICAqL1xuICAgIHN0YXRpYyBqc19pc19zdWJjbGFzc19vZihzdWJjbGFzcywgc3VwZXJjbGFzcykge1xuICAgICAgICAvLyBDb252ZXJ0IHN0cmluZyBuYW1lcyB0byBjbGFzcyBvYmplY3RzXG4gICAgICAgIGxldCBzdWJjbGFzc19vYmplY3QgPSBzdWJjbGFzcztcbiAgICAgICAgaWYgKHR5cGVvZiBzdWJjbGFzcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHN1YmNsYXNzX29iamVjdCA9IE1hbmlmZXN0LmdldF9jbGFzc19ieV9uYW1lKHN1YmNsYXNzKTtcbiAgICAgICAgICAgIGlmICghc3ViY2xhc3Nfb2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgLy8gQ2FuJ3QgcmVzb2x2ZSBzdWJjbGFzcyAtIHJldHVybiBmYWxzZSBwZXIgc3BlY1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBzdXBlcmNsYXNzX29iamVjdCA9IHN1cGVyY2xhc3M7XG4gICAgICAgIGlmICh0eXBlb2Ygc3VwZXJjbGFzcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHN1cGVyY2xhc3Nfb2JqZWN0ID0gTWFuaWZlc3QuZ2V0X2NsYXNzX2J5X25hbWUoc3VwZXJjbGFzcyk7XG4gICAgICAgICAgICBpZiAoIXN1cGVyY2xhc3Nfb2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgLy8gQ2FuJ3QgcmVzb2x2ZSBzdXBlcmNsYXNzIC0gZmFpbCBsb3VkIHBlciBzcGVjXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTdXBlcmNsYXNzIG5vdCBmb3VuZCBpbiBtYW5pZmVzdDogJHtzdXBlcmNsYXNzfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2xhc3NlcyBhcmUgbm90IHN1YmNsYXNzZXMgb2YgdGhlbXNlbHZlc1xuICAgICAgICBpZiAoc3ViY2xhc3Nfb2JqZWN0ID09PSBzdXBlcmNsYXNzX29iamVjdCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gV2FsayB1cCB0aGUgaW5oZXJpdGFuY2UgY2hhaW5cbiAgICAgICAgbGV0IGN1cnJlbnRfY2xhc3MgPSBzdWJjbGFzc19vYmplY3Q7XG4gICAgICAgIHdoaWxlIChjdXJyZW50X2NsYXNzKSB7XG4gICAgICAgICAgICBpZiAoY3VycmVudF9jbGFzcyA9PT0gc3VwZXJjbGFzc19vYmplY3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIE1vdmUgdXAgdG8gcGFyZW50IGNsYXNzXG4gICAgICAgICAgICBpZiAoY3VycmVudF9jbGFzcy5fZXh0ZW5kcykge1xuICAgICAgICAgICAgICAgIC8vIF9leHRlbmRzIG1heSBiZSBhIHN0cmluZyBvciBjbGFzcyByZWZlcmVuY2VcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGN1cnJlbnRfY2xhc3MuX2V4dGVuZHMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnRfY2xhc3MgPSBNYW5pZmVzdC5nZXRfY2xhc3NfYnlfbmFtZShjdXJyZW50X2NsYXNzLl9leHRlbmRzKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjdXJyZW50X2NsYXNzID0gY3VycmVudF9jbGFzcy5fZXh0ZW5kcztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRfY2xhc3MgPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhIGNsYXNzIGJ5IGl0cyBuYW1lXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGNsYXNzX25hbWUgLSBUaGUgbmFtZSBvZiB0aGUgY2xhc3NcbiAgICAgKiBAcmV0dXJucyB7Q2xhc3N8bnVsbH0gVGhlIGNsYXNzIG9iamVjdCBvciBudWxsIGlmIG5vdCBmb3VuZFxuICAgICAqL1xuICAgIHN0YXRpYyBnZXRfY2xhc3NfYnlfbmFtZShjbGFzc19uYW1lKSB7XG4gICAgICAgIGlmICghTWFuaWZlc3QuX2NsYXNzZXMgfHwgIU1hbmlmZXN0Ll9jbGFzc2VzW2NsYXNzX25hbWVdKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBNYW5pZmVzdC5fY2xhc3Nlc1tjbGFzc19uYW1lXS5jbGFzcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgYWxsIHJlZ2lzdGVyZWQgY2xhc3Nlc1xuICAgICAqIEByZXR1cm5zIHtBcnJheX0gQXJyYXkgb2Ygb2JqZWN0cyB3aXRoIHtjbGFzc19uYW1lLCBjbGFzc19vYmplY3QsIGV4dGVuZHN9XG4gICAgICovXG4gICAgc3RhdGljIGdldF9hbGxfY2xhc3NlcygpIHtcbiAgICAgICAgaWYgKCFNYW5pZmVzdC5fY2xhc3Nlcykge1xuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzdWx0cyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBjbGFzc19uYW1lIGluIE1hbmlmZXN0Ll9jbGFzc2VzKSB7XG4gICAgICAgICAgICBjb25zdCBjbGFzc2RhdGEgPSBNYW5pZmVzdC5fY2xhc3Nlc1tjbGFzc19uYW1lXTtcbiAgICAgICAgICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICAgICAgICAgICAgY2xhc3NfbmFtZTogY2xhc3NkYXRhLm5hbWUsXG4gICAgICAgICAgICAgICAgY2xhc3Nfb2JqZWN0OiBjbGFzc2RhdGEuY2xhc3MsXG4gICAgICAgICAgICAgICAgZXh0ZW5kczogY2xhc3NkYXRhLmV4dGVuZHMsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNvcnQgYWxwaGFiZXRpY2FsbHkgYnkgY2xhc3MgbmFtZSB0byBlbnN1cmUgZGV0ZXJtaW5pc3RpYyBiZWhhdmlvciBhbmQgcHJldmVudCByYWNlIGNvbmRpdGlvbiBidWdzXG4gICAgICAgIHJlc3VsdHMuc29ydCgoYSwgYikgPT4gYS5jbGFzc19uYW1lLmxvY2FsZUNvbXBhcmUoYi5jbGFzc19uYW1lKSk7XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdHM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBidWlsZCBrZXkgZnJvbSB0aGUgYXBwbGljYXRpb24gY29uZmlndXJhdGlvblxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBidWlsZCBrZXkgb3IgXCJOT0JVSUxEXCIgaWYgbm90IGF2YWlsYWJsZVxuICAgICAqL1xuICAgIHN0YXRpYyBidWlsZF9rZXkoKSB7XG4gICAgICAgIGlmICh3aW5kb3cucnN4YXBwICYmIHdpbmRvdy5yc3hhcHAuYnVpbGRfa2V5KSB7XG4gICAgICAgICAgICByZXR1cm4gd2luZG93LnJzeGFwcC5idWlsZF9rZXk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICdOT0JVSUxEJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgZGVjb3JhdG9ycyBmb3IgYSBzcGVjaWZpYyBjbGFzcyBhbmQgbWV0aG9kXG4gICAgICogQHBhcmFtIHtzdHJpbmd8Q2xhc3N9IGNsYXNzX25hbWUgLSBUaGUgY2xhc3MgbmFtZSBvciBjbGFzcyBvYmplY3RcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbWV0aG9kX25hbWUgLSBUaGUgbWV0aG9kIG5hbWVcbiAgICAgKiBAcmV0dXJucyB7QXJyYXl8bnVsbH0gQXJyYXkgb2YgZGVjb3JhdG9yIG9iamVjdHMgb3IgbnVsbCBpZiBub25lIGZvdW5kXG4gICAgICovXG4gICAgc3RhdGljIGdldF9kZWNvcmF0b3JzKGNsYXNzX25hbWUsIG1ldGhvZF9uYW1lKSB7XG4gICAgICAgIC8vIENvbnZlcnQgY2xhc3Mgb2JqZWN0IHRvIG5hbWUgaWYgbmVlZGVkXG4gICAgICAgIGlmICh0eXBlb2YgY2xhc3NfbmFtZSAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGNsYXNzX25hbWUgPSBjbGFzc19uYW1lLl9uYW1lIHx8IGNsYXNzX25hbWUubmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNsYXNzX2luZm8gPSBNYW5pZmVzdC5fY2xhc3Nlc1tjbGFzc19uYW1lXTtcbiAgICAgICAgaWYgKCFjbGFzc19pbmZvIHx8ICFjbGFzc19pbmZvLmRlY29yYXRvcnMgfHwgIWNsYXNzX2luZm8uZGVjb3JhdG9yc1ttZXRob2RfbmFtZV0pIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVHJhbnNmb3JtIGNvbXBhY3QgZm9ybWF0IHRvIG9iamVjdCBmb3JtYXRcbiAgICAgICAgcmV0dXJuIE1hbmlmZXN0Ll90cmFuc2Zvcm1fZGVjb3JhdG9ycyhjbGFzc19pbmZvLmRlY29yYXRvcnNbbWV0aG9kX25hbWVdKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgYWxsIG1ldGhvZHMgd2l0aCBkZWNvcmF0b3JzIGZvciBhIGNsYXNzXG4gICAgICogQHBhcmFtIHtzdHJpbmd8Q2xhc3N9IGNsYXNzX25hbWUgLSBUaGUgY2xhc3MgbmFtZSBvciBjbGFzcyBvYmplY3RcbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBPYmplY3Qgd2l0aCBtZXRob2QgbmFtZXMgYXMga2V5cyBhbmQgZGVjb3JhdG9yIGFycmF5cyBhcyB2YWx1ZXNcbiAgICAgKi9cbiAgICBzdGF0aWMgZ2V0X2FsbF9kZWNvcmF0b3JzKGNsYXNzX25hbWUpIHtcbiAgICAgICAgLy8gQ29udmVydCBjbGFzcyBvYmplY3QgdG8gbmFtZSBpZiBuZWVkZWRcbiAgICAgICAgaWYgKHR5cGVvZiBjbGFzc19uYW1lICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgY2xhc3NfbmFtZSA9IGNsYXNzX25hbWUuX25hbWUgfHwgY2xhc3NfbmFtZS5uYW1lO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY2xhc3NfaW5mbyA9IE1hbmlmZXN0Ll9jbGFzc2VzW2NsYXNzX25hbWVdO1xuICAgICAgICBpZiAoIWNsYXNzX2luZm8gfHwgIWNsYXNzX2luZm8uZGVjb3JhdG9ycykge1xuICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVHJhbnNmb3JtIGFsbCBkZWNvcmF0b3JzIGZyb20gY29tcGFjdCB0byBvYmplY3QgZm9ybWF0XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IHt9O1xuICAgICAgICBmb3IgKGxldCBtZXRob2RfbmFtZSBpbiBjbGFzc19pbmZvLmRlY29yYXRvcnMpIHtcbiAgICAgICAgICAgIHJlc3VsdFttZXRob2RfbmFtZV0gPSBNYW5pZmVzdC5fdHJhbnNmb3JtX2RlY29yYXRvcnMoY2xhc3NfaW5mby5kZWNvcmF0b3JzW21ldGhvZF9uYW1lXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUcmFuc2Zvcm0gY29tcGFjdCBkZWNvcmF0b3IgZm9ybWF0IHRvIG9iamVjdCBmb3JtYXRcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBjb21wYWN0X2RlY29yYXRvcnMgLSBBcnJheSBvZiBbbmFtZSwgW2FyZ3NdXSB0dXBsZXNcbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IEFycmF5IG9mIGRlY29yYXRvciBvYmplY3RzIHdpdGggbmFtZSBhbmQgYXJndW1lbnRzIHByb3BlcnRpZXNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBfdHJhbnNmb3JtX2RlY29yYXRvcnMoY29tcGFjdF9kZWNvcmF0b3JzKSB7XG4gICAgICAgIGlmICghQXJyYXkuaXNBcnJheShjb21wYWN0X2RlY29yYXRvcnMpKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY29tcGFjdF9kZWNvcmF0b3JzLm1hcChkZWNvcmF0b3IgPT4ge1xuICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZGVjb3JhdG9yKSAmJiBkZWNvcmF0b3IubGVuZ3RoID49IDIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICBuYW1lOiBkZWNvcmF0b3JbMF0sXG4gICAgICAgICAgICAgICAgICAgIGFyZ3VtZW50czogZGVjb3JhdG9yWzFdIHx8IFtdXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEhhbmRsZSBtYWxmb3JtZWQgZGVjb3JhdG9yIGRhdGFcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgbmFtZTogJ3Vua25vd24nLFxuICAgICAgICAgICAgICAgIGFyZ3VtZW50czogW11cbiAgICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrIGlmIGEgbWV0aG9kIGhhcyBhIHNwZWNpZmljIGRlY29yYXRvclxuICAgICAqIEBwYXJhbSB7c3RyaW5nfENsYXNzfSBjbGFzc19uYW1lIC0gVGhlIGNsYXNzIG5hbWUgb3IgY2xhc3Mgb2JqZWN0XG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG1ldGhvZF9uYW1lIC0gVGhlIG1ldGhvZCBuYW1lXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGRlY29yYXRvcl9uYW1lIC0gVGhlIGRlY29yYXRvciBuYW1lIHRvIGNoZWNrIGZvclxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSBtZXRob2QgaGFzIHRoZSBkZWNvcmF0b3JcbiAgICAgKi9cbiAgICBzdGF0aWMgaGFzX2RlY29yYXRvcihjbGFzc19uYW1lLCBtZXRob2RfbmFtZSwgZGVjb3JhdG9yX25hbWUpIHtcbiAgICAgICAgY29uc3QgZGVjb3JhdG9ycyA9IE1hbmlmZXN0LmdldF9kZWNvcmF0b3JzKGNsYXNzX25hbWUsIG1ldGhvZF9uYW1lKTtcbiAgICAgICAgaWYgKCFkZWNvcmF0b3JzKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZGVjb3JhdG9ycy5zb21lKGQgPT4gZC5uYW1lID09PSBkZWNvcmF0b3JfbmFtZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBzdWJjbGFzc2VzIG9mIGEgZ2l2ZW4gY2xhc3MgdXNpbmcgdGhlIHByZS1idWlsdCBpbmRleFxuICAgICAqIFRoaXMgaXMgdGhlIEphdmFTY3JpcHQgZXF1aXZhbGVudCBvZiBQSFAncyBNYW5pZmVzdDo6anNfZ2V0X3N1YmNsYXNzZXNfb2YoKVxuICAgICAqIEBwYXJhbSB7Q2xhc3N8c3RyaW5nfSBiYXNlX2NsYXNzIC0gVGhlIGJhc2UgY2xhc3MgKG9iamVjdCBvciBuYW1lIHN0cmluZykgdG8gZ2V0IHN1YmNsYXNzZXMgb2ZcbiAgICAgKiBAcmV0dXJucyB7QXJyYXk8Q2xhc3M+fSBBcnJheSBvZiBhY3R1YWwgY2xhc3Mgb2JqZWN0cyB0aGF0IGFyZSBzdWJjbGFzc2VzIG9mIHRoZSBiYXNlIGNsYXNzXG4gICAgICovXG4gICAgc3RhdGljIGpzX2dldF9zdWJjbGFzc2VzX29mKGJhc2VfY2xhc3MpIHtcbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBpbmRleCBpZiBuZWVkZWRcbiAgICAgICAgaWYgKCFNYW5pZmVzdC5fc3ViY2xhc3NfaW5kZXgpIHtcbiAgICAgICAgICAgIE1hbmlmZXN0Ll9idWlsZF9zdWJjbGFzc19pbmRleCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29udmVydCBjbGFzcyBvYmplY3QgdG8gbmFtZSBpZiBuZWVkZWRcbiAgICAgICAgbGV0IGJhc2VfY2xhc3NfbmFtZSA9IGJhc2VfY2xhc3M7XG4gICAgICAgIGlmICh0eXBlb2YgYmFzZV9jbGFzcyAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGJhc2VfY2xhc3NfbmFtZSA9IGJhc2VfY2xhc3MuX25hbWUgfHwgYmFzZV9jbGFzcy5uYW1lO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGJhc2UgY2xhc3MgZXhpc3RzXG4gICAgICAgIGlmICghTWFuaWZlc3QuX2NsYXNzZXNbYmFzZV9jbGFzc19uYW1lXSkge1xuICAgICAgICAgICAgLy8gQmFzZSBjbGFzcyBub3QgaW4gbWFuaWZlc3QgLSByZXR1cm4gZW1wdHkgYXJyYXlcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEdldCBzdWJjbGFzcyBuYW1lcyBmcm9tIHRoZSBpbmRleFxuICAgICAgICBjb25zdCBzdWJjbGFzc19uYW1lcyA9IE1hbmlmZXN0Ll9zdWJjbGFzc19pbmRleFtiYXNlX2NsYXNzX25hbWVdIHx8IFtdO1xuXG4gICAgICAgIC8vIENvbnZlcnQgbmFtZXMgdG8gYWN0dWFsIGNsYXNzIG9iamVjdHNcbiAgICAgICAgY29uc3Qgc3ViY2xhc3Nfb2JqZWN0cyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBzdWJjbGFzc19uYW1lIG9mIHN1YmNsYXNzX25hbWVzKSB7XG4gICAgICAgICAgICBjb25zdCBjbGFzc2RhdGEgPSBNYW5pZmVzdC5fY2xhc3Nlc1tzdWJjbGFzc19uYW1lXTtcbiAgICAgICAgICAgIHN1YmNsYXNzX29iamVjdHMucHVzaChjbGFzc2RhdGEuY2xhc3MpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU29ydCBieSBjbGFzcyBuYW1lIGZvciBkZXRlcm1pbmlzdGljIGJlaGF2aW9yXG4gICAgICAgIHN1YmNsYXNzX29iamVjdHMuc29ydCgoYSwgYikgPT4ge1xuICAgICAgICAgICAgY29uc3QgbmFtZV9hID0gYS5fbmFtZSB8fCBhLm5hbWU7XG4gICAgICAgICAgICBjb25zdCBuYW1lX2IgPSBiLl9uYW1lIHx8IGIubmFtZTtcbiAgICAgICAgICAgIHJldHVybiBuYW1lX2EubG9jYWxlQ29tcGFyZShuYW1lX2IpO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gc3ViY2xhc3Nfb2JqZWN0cztcbiAgICB9XG59XG5cbi8vIFJTWCBtYW5pZmVzdCBhdXRvbWF0aWNhbGx5IG1ha2VzIGNsYXNzZXMgZ2xvYmFsIC0gbm8gbWFudWFsIGFzc2lnbm1lbnQgbmVlZGVkXG4iXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNQSxRQUFRLENBQUM7RUFDWDtBQUNKO0FBQ0E7QUFDQTtFQUNJLE9BQU9DLE9BQU9BLENBQUNDLEtBQUssRUFBRTtJQUNsQjtJQUNBLElBQUksT0FBT0YsUUFBUSxDQUFDRyxRQUFRLEtBQUssV0FBVyxFQUFFO01BQzFDSCxRQUFRLENBQUNHLFFBQVEsR0FBRyxDQUFDLENBQUM7SUFDMUI7O0lBRUE7SUFDQUQsS0FBSyxDQUFDRSxPQUFPLENBQUVDLElBQUksSUFBSztNQUNwQixJQUFJQyxZQUFZLEdBQUdELElBQUksQ0FBQyxDQUFDLENBQUM7TUFDMUIsSUFBSUUsVUFBVSxHQUFHRixJQUFJLENBQUMsQ0FBQyxDQUFDO01BQ3hCLElBQUlHLGFBQWEsR0FBR0gsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUk7TUFDbkMsSUFBSUksVUFBVSxHQUFHSixJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSTs7TUFFaEM7TUFDQUwsUUFBUSxDQUFDRyxRQUFRLENBQUNJLFVBQVUsQ0FBQyxHQUFHO1FBQzVCRyxLQUFLLEVBQUVKLFlBQVk7UUFDbkJLLElBQUksRUFBRUosVUFBVTtRQUNoQkssT0FBTyxFQUFFSixhQUFhO1FBQ3RCQyxVQUFVLEVBQUVBLFVBQVUsQ0FBRztNQUM3QixDQUFDOztNQUVEO01BQ0FILFlBQVksQ0FBQ08sS0FBSyxHQUFHTixVQUFVO01BQy9CRCxZQUFZLENBQUNRLFFBQVEsR0FBR04sYUFBYTtNQUNyQ0YsWUFBWSxDQUFDUyxXQUFXLEdBQUdOLFVBQVU7SUFDekMsQ0FBQyxDQUFDOztJQUVGO0lBQ0FU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