431 lines
56 KiB
JavaScript
431 lines
56 KiB
JavaScript
|
|
/*!
|
||
|
|
* @pixiv/three-vrm-node-constraint v3.4.1
|
||
|
|
* Node constraint module for @pixiv/three-vrm
|
||
|
|
*
|
||
|
|
* Copyright (c) 2019-2025 pixiv Inc.
|
||
|
|
* @pixiv/three-vrm-node-constraint is distributed under MIT License
|
||
|
|
* https://github.com/pixiv/three-vrm/blob/release/LICENSE
|
||
|
|
*/
|
||
|
|
var __async = (__this, __arguments, generator) => {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
var fulfilled = (value) => {
|
||
|
|
try {
|
||
|
|
step(generator.next(value));
|
||
|
|
} catch (e) {
|
||
|
|
reject(e);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
var rejected = (value) => {
|
||
|
|
try {
|
||
|
|
step(generator.throw(value));
|
||
|
|
} catch (e) {
|
||
|
|
reject(e);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
||
|
|
step((generator = generator.apply(__this, __arguments)).next());
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
// src/helpers/VRMNodeConstraintHelper.ts
|
||
|
|
import * as THREE from "three";
|
||
|
|
var _v3A = new THREE.Vector3();
|
||
|
|
var VRMNodeConstraintHelper = class extends THREE.Group {
|
||
|
|
constructor(constraint) {
|
||
|
|
super();
|
||
|
|
this._attrPosition = new THREE.BufferAttribute(new Float32Array([0, 0, 0, 0, 0, 0]), 3);
|
||
|
|
this._attrPosition.setUsage(THREE.DynamicDrawUsage);
|
||
|
|
const geometry = new THREE.BufferGeometry();
|
||
|
|
geometry.setAttribute("position", this._attrPosition);
|
||
|
|
const material = new THREE.LineBasicMaterial({
|
||
|
|
color: 16711935,
|
||
|
|
depthTest: false,
|
||
|
|
depthWrite: false
|
||
|
|
});
|
||
|
|
this._line = new THREE.Line(geometry, material);
|
||
|
|
this.add(this._line);
|
||
|
|
this.constraint = constraint;
|
||
|
|
}
|
||
|
|
updateMatrixWorld(force) {
|
||
|
|
_v3A.setFromMatrixPosition(this.constraint.destination.matrixWorld);
|
||
|
|
this._attrPosition.setXYZ(0, _v3A.x, _v3A.y, _v3A.z);
|
||
|
|
if (this.constraint.source) {
|
||
|
|
_v3A.setFromMatrixPosition(this.constraint.source.matrixWorld);
|
||
|
|
}
|
||
|
|
this._attrPosition.setXYZ(1, _v3A.x, _v3A.y, _v3A.z);
|
||
|
|
this._attrPosition.needsUpdate = true;
|
||
|
|
super.updateMatrixWorld(force);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// src/VRMAimConstraint.ts
|
||
|
|
import * as THREE3 from "three";
|
||
|
|
|
||
|
|
// src/utils/decomposePosition.ts
|
||
|
|
function decomposePosition(matrix, target) {
|
||
|
|
return target.set(matrix.elements[12], matrix.elements[13], matrix.elements[14]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// src/utils/decomposeRotation.ts
|
||
|
|
import * as THREE2 from "three";
|
||
|
|
var _v3A2 = new THREE2.Vector3();
|
||
|
|
var _v3B = new THREE2.Vector3();
|
||
|
|
function decomposeRotation(matrix, target) {
|
||
|
|
matrix.decompose(_v3A2, target, _v3B);
|
||
|
|
return target;
|
||
|
|
}
|
||
|
|
|
||
|
|
// src/utils/quatInvertCompat.ts
|
||
|
|
function quatInvertCompat(target) {
|
||
|
|
if (target.invert) {
|
||
|
|
target.invert();
|
||
|
|
} else {
|
||
|
|
target.inverse();
|
||
|
|
}
|
||
|
|
return target;
|
||
|
|
}
|
||
|
|
|
||
|
|
// src/VRMNodeConstraint.ts
|
||
|
|
var VRMNodeConstraint = class {
|
||
|
|
/**
|
||
|
|
* @param destination The destination object
|
||
|
|
* @param source The source object
|
||
|
|
*/
|
||
|
|
constructor(destination, source) {
|
||
|
|
this.destination = destination;
|
||
|
|
this.source = source;
|
||
|
|
this.weight = 1;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// src/VRMAimConstraint.ts
|
||
|
|
var _v3A3 = new THREE3.Vector3();
|
||
|
|
var _v3B2 = new THREE3.Vector3();
|
||
|
|
var _v3C = new THREE3.Vector3();
|
||
|
|
var _quatA = new THREE3.Quaternion();
|
||
|
|
var _quatB = new THREE3.Quaternion();
|
||
|
|
var _quatC = new THREE3.Quaternion();
|
||
|
|
var VRMAimConstraint = class extends VRMNodeConstraint {
|
||
|
|
/**
|
||
|
|
* The aim axis of the constraint.
|
||
|
|
*/
|
||
|
|
get aimAxis() {
|
||
|
|
return this._aimAxis;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* The aim axis of the constraint.
|
||
|
|
*/
|
||
|
|
set aimAxis(aimAxis) {
|
||
|
|
this._aimAxis = aimAxis;
|
||
|
|
this._v3AimAxis.set(
|
||
|
|
aimAxis === "PositiveX" ? 1 : aimAxis === "NegativeX" ? -1 : 0,
|
||
|
|
aimAxis === "PositiveY" ? 1 : aimAxis === "NegativeY" ? -1 : 0,
|
||
|
|
aimAxis === "PositiveZ" ? 1 : aimAxis === "NegativeZ" ? -1 : 0
|
||
|
|
);
|
||
|
|
}
|
||
|
|
get dependencies() {
|
||
|
|
const set = /* @__PURE__ */ new Set([this.source]);
|
||
|
|
if (this.destination.parent) {
|
||
|
|
set.add(this.destination.parent);
|
||
|
|
}
|
||
|
|
return set;
|
||
|
|
}
|
||
|
|
constructor(destination, source) {
|
||
|
|
super(destination, source);
|
||
|
|
this._aimAxis = "PositiveX";
|
||
|
|
this._v3AimAxis = new THREE3.Vector3(1, 0, 0);
|
||
|
|
this._dstRestQuat = new THREE3.Quaternion();
|
||
|
|
}
|
||
|
|
setInitState() {
|
||
|
|
this._dstRestQuat.copy(this.destination.quaternion);
|
||
|
|
}
|
||
|
|
update() {
|
||
|
|
this.destination.updateWorldMatrix(true, false);
|
||
|
|
this.source.updateWorldMatrix(true, false);
|
||
|
|
const dstParentWorldQuat = _quatA.identity();
|
||
|
|
const invDstParentWorldQuat = _quatB.identity();
|
||
|
|
if (this.destination.parent) {
|
||
|
|
decomposeRotation(this.destination.parent.matrixWorld, dstParentWorldQuat);
|
||
|
|
quatInvertCompat(invDstParentWorldQuat.copy(dstParentWorldQuat));
|
||
|
|
}
|
||
|
|
const a0 = _v3A3.copy(this._v3AimAxis).applyQuaternion(this._dstRestQuat).applyQuaternion(dstParentWorldQuat);
|
||
|
|
const a1 = decomposePosition(this.source.matrixWorld, _v3B2).sub(decomposePosition(this.destination.matrixWorld, _v3C)).normalize();
|
||
|
|
const targetQuat = _quatC.setFromUnitVectors(a0, a1).premultiply(invDstParentWorldQuat).multiply(dstParentWorldQuat).multiply(this._dstRestQuat);
|
||
|
|
this.destination.quaternion.copy(this._dstRestQuat).slerp(targetQuat, this.weight);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// src/utils/traverseAncestorsFromRoot.ts
|
||
|
|
function traverseAncestorsFromRoot(object, callback) {
|
||
|
|
const ancestors = [object];
|
||
|
|
let head = object.parent;
|
||
|
|
while (head !== null) {
|
||
|
|
ancestors.unshift(head);
|
||
|
|
head = head.parent;
|
||
|
|
}
|
||
|
|
ancestors.forEach((ancestor) => {
|
||
|
|
callback(ancestor);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// src/VRMNodeConstraintManager.ts
|
||
|
|
var VRMNodeConstraintManager = class {
|
||
|
|
constructor() {
|
||
|
|
this._constraints = /* @__PURE__ */ new Set();
|
||
|
|
this._objectConstraintsMap = /* @__PURE__ */ new Map();
|
||
|
|
}
|
||
|
|
get constraints() {
|
||
|
|
return this._constraints;
|
||
|
|
}
|
||
|
|
addConstraint(constraint) {
|
||
|
|
this._constraints.add(constraint);
|
||
|
|
let objectSet = this._objectConstraintsMap.get(constraint.destination);
|
||
|
|
if (objectSet == null) {
|
||
|
|
objectSet = /* @__PURE__ */ new Set();
|
||
|
|
this._objectConstraintsMap.set(constraint.destination, objectSet);
|
||
|
|
}
|
||
|
|
objectSet.add(constraint);
|
||
|
|
}
|
||
|
|
deleteConstraint(constraint) {
|
||
|
|
this._constraints.delete(constraint);
|
||
|
|
const objectSet = this._objectConstraintsMap.get(constraint.destination);
|
||
|
|
objectSet.delete(constraint);
|
||
|
|
}
|
||
|
|
setInitState() {
|
||
|
|
const constraintsTried = /* @__PURE__ */ new Set();
|
||
|
|
const constraintsDone = /* @__PURE__ */ new Set();
|
||
|
|
for (const constraint of this._constraints) {
|
||
|
|
this._processConstraint(constraint, constraintsTried, constraintsDone, (constraint2) => constraint2.setInitState());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
update() {
|
||
|
|
const constraintsTried = /* @__PURE__ */ new Set();
|
||
|
|
const constraintsDone = /* @__PURE__ */ new Set();
|
||
|
|
for (const constraint of this._constraints) {
|
||
|
|
this._processConstraint(constraint, constraintsTried, constraintsDone, (constraint2) => constraint2.update());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Update a constraint.
|
||
|
|
* If there are other constraints that are dependant, it will try to update them recursively.
|
||
|
|
* It might throw an error if there are circular dependencies.
|
||
|
|
*
|
||
|
|
* Intended to be used in {@link update} and {@link _processConstraint} itself recursively.
|
||
|
|
*
|
||
|
|
* @param constraint A constraint you want to update
|
||
|
|
* @param constraintsTried Set of constraints that are already tried to be updated
|
||
|
|
* @param constraintsDone Set of constraints that are already up to date
|
||
|
|
*/
|
||
|
|
_processConstraint(constraint, constraintsTried, constraintsDone, callback) {
|
||
|
|
if (constraintsDone.has(constraint)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (constraintsTried.has(constraint)) {
|
||
|
|
throw new Error("VRMNodeConstraintManager: Circular dependency detected while updating constraints");
|
||
|
|
}
|
||
|
|
constraintsTried.add(constraint);
|
||
|
|
const depObjects = constraint.dependencies;
|
||
|
|
for (const depObject of depObjects) {
|
||
|
|
traverseAncestorsFromRoot(depObject, (depObjectAncestor) => {
|
||
|
|
const objectSet = this._objectConstraintsMap.get(depObjectAncestor);
|
||
|
|
if (objectSet) {
|
||
|
|
for (const depConstraint of objectSet) {
|
||
|
|
this._processConstraint(depConstraint, constraintsTried, constraintsDone, callback);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
callback(constraint);
|
||
|
|
constraintsDone.add(constraint);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// src/VRMRotationConstraint.ts
|
||
|
|
import * as THREE4 from "three";
|
||
|
|
var _quatA2 = new THREE4.Quaternion();
|
||
|
|
var _quatB2 = new THREE4.Quaternion();
|
||
|
|
var VRMRotationConstraint = class extends VRMNodeConstraint {
|
||
|
|
get dependencies() {
|
||
|
|
return /* @__PURE__ */ new Set([this.source]);
|
||
|
|
}
|
||
|
|
constructor(destination, source) {
|
||
|
|
super(destination, source);
|
||
|
|
this._dstRestQuat = new THREE4.Quaternion();
|
||
|
|
this._invSrcRestQuat = new THREE4.Quaternion();
|
||
|
|
}
|
||
|
|
setInitState() {
|
||
|
|
this._dstRestQuat.copy(this.destination.quaternion);
|
||
|
|
quatInvertCompat(this._invSrcRestQuat.copy(this.source.quaternion));
|
||
|
|
}
|
||
|
|
update() {
|
||
|
|
const srcDeltaQuat = _quatA2.copy(this._invSrcRestQuat).multiply(this.source.quaternion);
|
||
|
|
const targetQuat = _quatB2.copy(this._dstRestQuat).multiply(srcDeltaQuat);
|
||
|
|
this.destination.quaternion.copy(this._dstRestQuat).slerp(targetQuat, this.weight);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// src/VRMRollConstraint.ts
|
||
|
|
import * as THREE5 from "three";
|
||
|
|
var _v3A4 = new THREE5.Vector3();
|
||
|
|
var _quatA3 = new THREE5.Quaternion();
|
||
|
|
var _quatB3 = new THREE5.Quaternion();
|
||
|
|
var VRMRollConstraint = class extends VRMNodeConstraint {
|
||
|
|
/**
|
||
|
|
* The roll axis of the constraint.
|
||
|
|
*/
|
||
|
|
get rollAxis() {
|
||
|
|
return this._rollAxis;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* The roll axis of the constraint.
|
||
|
|
*/
|
||
|
|
set rollAxis(rollAxis) {
|
||
|
|
this._rollAxis = rollAxis;
|
||
|
|
this._v3RollAxis.set(rollAxis === "X" ? 1 : 0, rollAxis === "Y" ? 1 : 0, rollAxis === "Z" ? 1 : 0);
|
||
|
|
}
|
||
|
|
get dependencies() {
|
||
|
|
return /* @__PURE__ */ new Set([this.source]);
|
||
|
|
}
|
||
|
|
constructor(destination, source) {
|
||
|
|
super(destination, source);
|
||
|
|
this._rollAxis = "X";
|
||
|
|
this._v3RollAxis = new THREE5.Vector3(1, 0, 0);
|
||
|
|
this._dstRestQuat = new THREE5.Quaternion();
|
||
|
|
this._invDstRestQuat = new THREE5.Quaternion();
|
||
|
|
this._invSrcRestQuatMulDstRestQuat = new THREE5.Quaternion();
|
||
|
|
}
|
||
|
|
setInitState() {
|
||
|
|
this._dstRestQuat.copy(this.destination.quaternion);
|
||
|
|
quatInvertCompat(this._invDstRestQuat.copy(this._dstRestQuat));
|
||
|
|
quatInvertCompat(this._invSrcRestQuatMulDstRestQuat.copy(this.source.quaternion)).multiply(this._dstRestQuat);
|
||
|
|
}
|
||
|
|
update() {
|
||
|
|
const quatDelta = _quatA3.copy(this._invDstRestQuat).multiply(this.source.quaternion).multiply(this._invSrcRestQuatMulDstRestQuat);
|
||
|
|
const n1 = _v3A4.copy(this._v3RollAxis).applyQuaternion(quatDelta);
|
||
|
|
const quatFromTo = _quatB3.setFromUnitVectors(n1, this._v3RollAxis);
|
||
|
|
const targetQuat = quatFromTo.premultiply(this._dstRestQuat).multiply(quatDelta);
|
||
|
|
this.destination.quaternion.copy(this._dstRestQuat).slerp(targetQuat, this.weight);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// src/VRMNodeConstraintLoaderPlugin.ts
|
||
|
|
var POSSIBLE_SPEC_VERSIONS = /* @__PURE__ */ new Set(["1.0", "1.0-beta"]);
|
||
|
|
var _VRMNodeConstraintLoaderPlugin = class _VRMNodeConstraintLoaderPlugin {
|
||
|
|
get name() {
|
||
|
|
return _VRMNodeConstraintLoaderPlugin.EXTENSION_NAME;
|
||
|
|
}
|
||
|
|
constructor(parser, options) {
|
||
|
|
this.parser = parser;
|
||
|
|
this.helperRoot = options == null ? void 0 : options.helperRoot;
|
||
|
|
}
|
||
|
|
afterRoot(gltf) {
|
||
|
|
return __async(this, null, function* () {
|
||
|
|
gltf.userData.vrmNodeConstraintManager = yield this._import(gltf);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Import constraints from a GLTF and returns a {@link VRMNodeConstraintManager}.
|
||
|
|
* It might return `null` instead when it does not need to be created or something go wrong.
|
||
|
|
*
|
||
|
|
* @param gltf A parsed result of GLTF taken from GLTFLoader
|
||
|
|
*/
|
||
|
|
_import(gltf) {
|
||
|
|
return __async(this, null, function* () {
|
||
|
|
var _a;
|
||
|
|
const json = this.parser.json;
|
||
|
|
const isConstraintsUsed = ((_a = json.extensionsUsed) == null ? void 0 : _a.indexOf(_VRMNodeConstraintLoaderPlugin.EXTENSION_NAME)) !== -1;
|
||
|
|
if (!isConstraintsUsed) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
const manager = new VRMNodeConstraintManager();
|
||
|
|
const threeNodes = yield this.parser.getDependencies("node");
|
||
|
|
threeNodes.forEach((node, nodeIndex) => {
|
||
|
|
var _a2;
|
||
|
|
const schemaNode = json.nodes[nodeIndex];
|
||
|
|
const extension = (_a2 = schemaNode == null ? void 0 : schemaNode.extensions) == null ? void 0 : _a2[_VRMNodeConstraintLoaderPlugin.EXTENSION_NAME];
|
||
|
|
if (extension == null) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const specVersion = extension.specVersion;
|
||
|
|
if (!POSSIBLE_SPEC_VERSIONS.has(specVersion)) {
|
||
|
|
console.warn(
|
||
|
|
`VRMNodeConstraintLoaderPlugin: Unknown ${_VRMNodeConstraintLoaderPlugin.EXTENSION_NAME} specVersion "${specVersion}"`
|
||
|
|
);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const constraintDef = extension.constraint;
|
||
|
|
if (constraintDef.roll != null) {
|
||
|
|
const constraint = this._importRollConstraint(node, threeNodes, constraintDef.roll);
|
||
|
|
manager.addConstraint(constraint);
|
||
|
|
} else if (constraintDef.aim != null) {
|
||
|
|
const constraint = this._importAimConstraint(node, threeNodes, constraintDef.aim);
|
||
|
|
manager.addConstraint(constraint);
|
||
|
|
} else if (constraintDef.rotation != null) {
|
||
|
|
const constraint = this._importRotationConstraint(node, threeNodes, constraintDef.rotation);
|
||
|
|
manager.addConstraint(constraint);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
gltf.scene.updateMatrixWorld();
|
||
|
|
manager.setInitState();
|
||
|
|
return manager;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
_importRollConstraint(destination, nodes, rollConstraintDef) {
|
||
|
|
const { source: sourceIndex, rollAxis, weight } = rollConstraintDef;
|
||
|
|
const source = nodes[sourceIndex];
|
||
|
|
const constraint = new VRMRollConstraint(destination, source);
|
||
|
|
if (rollAxis != null) {
|
||
|
|
constraint.rollAxis = rollAxis;
|
||
|
|
}
|
||
|
|
if (weight != null) {
|
||
|
|
constraint.weight = weight;
|
||
|
|
}
|
||
|
|
if (this.helperRoot) {
|
||
|
|
const helper = new VRMNodeConstraintHelper(constraint);
|
||
|
|
this.helperRoot.add(helper);
|
||
|
|
}
|
||
|
|
return constraint;
|
||
|
|
}
|
||
|
|
_importAimConstraint(destination, nodes, aimConstraintDef) {
|
||
|
|
const { source: sourceIndex, aimAxis, weight } = aimConstraintDef;
|
||
|
|
const source = nodes[sourceIndex];
|
||
|
|
const constraint = new VRMAimConstraint(destination, source);
|
||
|
|
if (aimAxis != null) {
|
||
|
|
constraint.aimAxis = aimAxis;
|
||
|
|
}
|
||
|
|
if (weight != null) {
|
||
|
|
constraint.weight = weight;
|
||
|
|
}
|
||
|
|
if (this.helperRoot) {
|
||
|
|
const helper = new VRMNodeConstraintHelper(constraint);
|
||
|
|
this.helperRoot.add(helper);
|
||
|
|
}
|
||
|
|
return constraint;
|
||
|
|
}
|
||
|
|
_importRotationConstraint(destination, nodes, rotationConstraintDef) {
|
||
|
|
const { source: sourceIndex, weight } = rotationConstraintDef;
|
||
|
|
const source = nodes[sourceIndex];
|
||
|
|
const constraint = new VRMRotationConstraint(destination, source);
|
||
|
|
if (weight != null) {
|
||
|
|
constraint.weight = weight;
|
||
|
|
}
|
||
|
|
if (this.helperRoot) {
|
||
|
|
const helper = new VRMNodeConstraintHelper(constraint);
|
||
|
|
this.helperRoot.add(helper);
|
||
|
|
}
|
||
|
|
return constraint;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
_VRMNodeConstraintLoaderPlugin.EXTENSION_NAME = "VRMC_node_constraint";
|
||
|
|
var VRMNodeConstraintLoaderPlugin = _VRMNodeConstraintLoaderPlugin;
|
||
|
|
export {
|
||
|
|
VRMAimConstraint,
|
||
|
|
VRMNodeConstraint,
|
||
|
|
VRMNodeConstraintHelper,
|
||
|
|
VRMNodeConstraintLoaderPlugin,
|
||
|
|
VRMNodeConstraintManager,
|
||
|
|
VRMRollConstraint,
|
||
|
|
VRMRotationConstraint
|
||
|
|
};
|
||
|
|
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2hlbHBlcnMvVlJNTm9kZUNvbnN0cmFpbnRIZWxwZXIudHMiLCAiLi4vc3JjL1ZSTUFpbUNvbnN0cmFpbnQudHMiLCAiLi4vc3JjL3V0aWxzL2RlY29tcG9zZVBvc2l0aW9uLnRzIiwgIi4uL3NyYy91dGlscy9kZWNvbXBvc2VSb3RhdGlvbi50cyIsICIuLi9zcmMvdXRpbHMvcXVhdEludmVydENvbXBhdC50cyIsICIuLi9zcmMvVlJNTm9kZUNvbnN0cmFpbnQudHMiLCAiLi4vc3JjL3V0aWxzL3RyYXZlcnNlQW5jZXN0b3JzRnJvbVJvb3QudHMiLCAiLi4vc3JjL1ZSTU5vZGVDb25zdHJhaW50TWFuYWdlci50cyIsICIuLi9zcmMvVlJNUm90YXRpb25Db25zdHJhaW50LnRzIiwgIi4uL3NyYy9WUk1Sb2xsQ29uc3RyYWludC50cyIsICIuLi9zcmMvVlJNTm9kZUNvbnN0cmFpbnRMb2FkZXJQbHVnaW4udHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCAqIGFzIFRIUkVFIGZyb20gJ3RocmVlJztcbmltcG9ydCB7IFZSTU5vZGVDb25zdHJhaW50IH0gZnJvbSAnLi4vVlJNTm9kZUNvbnN0cmFpbnQnO1xuXG5jb25zdCBfdjNBID0gbmV3IFRIUkVFLlZlY3RvcjMoKTtcblxuZXhwb3J0IGNsYXNzIFZSTU5vZGVDb25zdHJhaW50SGVscGVyIGV4dGVuZHMgVEhSRUUuR3JvdXAge1xuICBwdWJsaWMgcmVhZG9ubHkgY29uc3RyYWludDogVlJNTm9kZUNvbnN0cmFpbnQ7XG4gIHByaXZhdGUgX2xpbmU6IFRIUkVFLkxpbmU7XG4gIHByaXZhdGUgX2F0dHJQb3NpdGlvbjogVEhSRUUuQnVmZmVyQXR0cmlidXRlO1xuXG4gIHB1YmxpYyBjb25zdHJ1Y3Rvcihjb25zdHJhaW50OiBWUk1Ob2RlQ29uc3RyYWludCkge1xuICAgIHN1cGVyKCk7XG5cbiAgICB0aGlzLl9hdHRyUG9zaXRpb24gPSBuZXcgVEhSRUUuQnVmZmVyQXR0cmlidXRlKG5ldyBGbG9hdDMyQXJyYXkoWzAsIDAsIDAsIDAsIDAsIDBdKSwgMyk7XG4gICAgdGhpcy5fYXR0clBvc2l0aW9uLnNldFVzYWdlKFRIUkVFLkR5bmFtaWNEcmF3VXNhZ2UpO1xuXG4gICAgY29uc3QgZ2VvbWV0cnkgPSBuZXcgVEhSRUUuQnVmZmVyR2VvbWV0cnkoKTtcbiAgICBnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoJ3Bvc2l0aW9uJywgdGhpcy5fYXR0clBvc2l0aW9uKTtcblxuICAgIGNvbnN0IG1hdGVyaWFsID0gbmV3IFRIUkVFLkxpbmVCYXNpY01hdGVyaWFsKHtcbiAgICAgIGNvbG9yOiAweGZmMDBmZixcbiAgICAgIGRlcHRoVGVzdDogZmFsc2UsXG4gICAgICBkZXB0aFdyaXRlOiBmYWxzZSxcbiAgICB9KTtcblxuICAgIHRoaXMuX2xpbmUgPSBuZXcgVEhSRUUuTGluZShnZW9tZXRyeSwgbWF0ZXJpYWwpO1xuICAgIHRoaXMuYWRkKHRoaXMuX2xpbmUpO1xuXG4gICAgdGhpcy5jb25zdHJhaW50ID0gY29uc3RyYWludDtcbiAgfVxuXG4gIHB1YmxpYyB1cGRhdGVNYXRyaXhXb3JsZChmb3JjZT86IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBfdjNBLnNldEZyb21NYXRyaXhQb3NpdGlvbih0aGlzLmNvbnN0cmFpbnQuZGVzdGluYXRpb24ubWF0cml4V29ybGQpO1xuICAgIHRoaXMuX2F0dHJQb3NpdGlvbi5zZXRYWVooMCwgX3YzQS54LCBfdjNBLnksIF92M0Eueik7XG5cbiAgICBpZiAodGhpcy5jb25zdHJhaW50LnNvdXJjZSkge1xuICAgICAgX3YzQS5zZXRGcm9tTWF0cml4UG9zaXRpb24odGhpcy5jb25zdHJhaW50LnNvdXJjZS5tYXRyaXhXb3JsZCk7XG4gICAgfVxuICAgIHRoaXMuX2F0dHJQb3NpdGlvbi5zZXRYWVooMSwgX3YzQS54LCBfdjNBLnksIF92M0Eueik7XG5cbiAgICB0aGlzLl9hdHRyUG9zaXRpb24ubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG4gICAgc3VwZXIudXBkYXRlTWF0cml4V29ybGQoZm9yY2UpO1xuICB9XG59XG4iLCAiaW1wb3J0ICogYXMgVEhSRUUgZnJvbSAndGhyZWUnO1xuaW1wb3J0IHsgZGVjb21wb3NlUG9zaXRpb24gfSBmcm9tICcuL3V0aWxzL2RlY29tcG9zZVBvc2l0aW9uJztcbmltcG9ydCB7IGRlY29tcG9zZVJvdGF0aW9uIH0gZnJvbSAnLi91dGlscy9kZWNvbXBvc2VSb3RhdGlvbic7XG5pbXBvcnQgeyBxdWF0SW52ZXJ0Q29tcGF0IH0gZnJvbSAnLi91dGlscy9xdWF0SW52ZXJ0Q29tcGF0JztcbmltcG9ydCB7IFZSTU5vZGVDb25zdHJhaW50IH0gZnJvbSAnLi9WUk1Ob2RlQ29uc3RyYWludCc7XG5cbmNvbnN0IF92M0EgPSBuZXcgVEhSRUUuVmVjdG9yMygpO1xuY29uc3QgX3YzQiA9IG5ldyBUSFJFRS5WZWN0b3IzKCk7XG5jb25zdCBfdjNDID0gbmV3IFRIUkVFLlZlY3RvcjMoKTtcbmNvbnN0IF9xdWF0QSA9IG5ldyBUSFJFRS5RdWF0ZXJuaW9uKCk7XG5jb25zdCBfcXVhdEIgPSBuZXcgVEhSRUUuUXVhdGVybmlvbigpO1xuY29uc3QgX3F1YXRDID0gbmV3IFRIUkVFLlF1YXRlcm5pb24oKTtcblxuLyoqXG4gKiBBIGNvbnN0cmFpbnQgdGhhdCBtYWtlcyBpdCBsb29rIGF0IGEgc291cmNlIG9iamVjdC5cbiAqXG4gKiBTZWU6IGh0dHBzOi8vZ2l0aHViLmNvbS92cm0tYy92cm0tc3BlY2lmaWNhdGlvbi90cmVlL21hc3Rlci9zcGVjaWZpY2F0aW9uL1ZSTUNfbm9kZV9jb25zdHJhaW50LTEuMF9iZXRhI3JvbGwtY29uc3RyYWludFxuICovXG5leHBvcnQgY2xhc3MgVlJNQWltQ29uc3RyYWludCBleHRlbmRzIFZSTU5vZGVDb25zdHJhaW50IHtcbiAgLyoqXG4gICAqIFRoZSBhaW0gYXhpcyBvZiB0aGUgY29uc3RyYWludC5cbiAgICovXG4gIHB1YmxpYyBnZXQgYWltQXhpcygpOiAnUG9zaXRpdmVYJyB8ICdOZWdhdGl2ZVgnIHwgJ1Bvc2l0aXZlWScgfCAnTmVnYXRpdmVZJyB8ICdQb3NpdGl2ZVonIHwgJ05lZ2F0aXZlWicge1xuICAgIHJldHVybiB0aGlzLl9haW1BeGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBhaW0gYXhpcyBvZiB0aGUgY29uc3RyYWludC5cbiAgICovXG4gIHB1YmxpYyBzZXQgYWltQXhpcyhhaW1BeGlzOiAnUG9zaXRpdmVYJyB8ICdOZWdhdGl2ZVgnIHwgJ1Bvc2l0aXZlWScgfCAnTmVnYXRpdmVZJyB8ICdQb3NpdGl2ZVonIHwgJ05lZ2F0aXZlWicpIHtcbiAgICB0aGlzLl9haW1BeGlzID0gYWltQXhpcztcbiAgICB0aGlzLl92M0FpbUF4aXMuc2V0KFxuICAgICAgYWltQ
|