@dcl-sdk/utils
Version:
A collection of helpers to make it easier to build a Decentraland scene using the SDK 7.
126 lines • 22.1 kB
JavaScript
import { engine, EntityState, Schemas, Transform } from '@dcl/sdk/ecs';
import { Scalar, Vector3, Quaternion } from '@dcl/sdk/math';
import { createCatmullRomSpline } from './math';
import { priority } from './priority';
function createPaths(targetEngine) {
const FollowPath = targetEngine.defineComponent('dcl.utils.FollowPath', {
points: Schemas.Array(Schemas.Vector3),
faceDirection: Schemas.Boolean,
speed: Schemas.Number,
normalizedTime: Schemas.Number,
currentIndex: Schemas.Number,
segmentTimes: Schemas.Array(Schemas.Number),
curveSegmentCount: Schemas.Number
});
const finishCbs = new Map();
const pointReachedCbs = new Map();
function unregisterEntity(entity) {
finishCbs.delete(entity);
pointReachedCbs.delete(entity);
FollowPath.deleteFrom(entity);
}
function system(dt) {
const deadPaths = [];
const pointReachedPaths = [];
for (const entity of finishCbs.keys()) {
if (targetEngine.getEntityState(entity) == EntityState.Removed || !FollowPath.has(entity)) {
unregisterEntity(entity);
continue;
}
const transform = Transform.getMutable(entity);
const path = FollowPath.getMutable(entity);
path.normalizedTime = Scalar.clamp(path.normalizedTime + dt * path.speed, 0, 1);
if (path.normalizedTime >= 1)
deadPaths.push(entity);
while (path.normalizedTime >= path.segmentTimes[path.currentIndex] &&
path.currentIndex < path.points.length - 1) {
if (path.faceDirection) {
const direction = Vector3.subtract(path.points[path.currentIndex + 1], path.points[path.currentIndex]);
transform.rotation = Quaternion.lookRotation(direction);
}
if (path.currentIndex > 0 && path.currentIndex % path.curveSegmentCount == 0) {
const pointIndex = path.currentIndex / path.curveSegmentCount;
const pointCoords = path.points[path.currentIndex];
const nextPointCoords = path.points[path.currentIndex + path.curveSegmentCount];
pointReachedPaths.push({ entity: entity, index: pointIndex, coords: pointCoords, nextCoords: nextPointCoords });
}
path.currentIndex += 1;
}
const timeDiff = path.segmentTimes[path.currentIndex] - path.segmentTimes[path.currentIndex - 1];
const coef = (path.segmentTimes[path.currentIndex] - path.normalizedTime) / timeDiff;
transform.position = Vector3.lerp(path.points[path.currentIndex], path.points[path.currentIndex - 1], coef);
}
for (const pointReached of pointReachedPaths) {
const callback = pointReachedCbs.get(pointReached.entity);
if (callback) {
callback(pointReached.index, pointReached.coords, pointReached.nextCoords);
}
}
for (const entity of deadPaths) {
const callback = finishCbs.get(entity);
unregisterEntity(entity);
if (callback)
callback();
}
}
targetEngine.addSystem(system, priority.PathSystemPriority);
function startPath(entity, points, duration, faceDirection, curveSegmentCount, onFinishCallback, onPointReachedCallback) {
if (points.length < 2)
throw new Error('At least 2 points are required to form a path.');
if (duration == 0)
throw new Error('Path duration must not be zero');
if (curveSegmentCount) {
const loop = Vector3.equals(points[0], points[points.length - 1]);
if (loop) {
points.pop();
points.unshift(points.pop());
}
points = createCatmullRomSpline(points, curveSegmentCount, loop);
}
else {
curveSegmentCount = 1;
}
finishCbs.set(entity, onFinishCallback);
pointReachedCbs.set(entity, onPointReachedCallback);
let totalLength = 0;
const segmentLengths = [];
for (let i = 0; i < points.length - 1; i++) {
let sqDist = Vector3.distance(points[i], points[i + 1]);
totalLength += sqDist;
segmentLengths.push(sqDist);
}
const segmentTimes = [0];
for (let i = 0; i < segmentLengths.length; i++) {
segmentTimes.push(segmentLengths[i] / totalLength + segmentTimes[i]);
}
FollowPath.createOrReplace(entity, {
points: points,
segmentTimes: segmentTimes,
curveSegmentCount: curveSegmentCount,
speed: 1 / duration,
normalizedTime: 0,
currentIndex: 0,
faceDirection: faceDirection
});
}
return {
startStraightPath(entity, points, duration, faceDirection, onFinishCallback, onPointReachedCallback) {
return startPath(entity, points, duration, faceDirection, 0, onFinishCallback, onPointReachedCallback);
},
startSmoothPath(entity, points, duration, segmentCount, faceDirection, onFinishCallback, onPointReachedCallback) {
if (segmentCount < 2 || !Number.isInteger(segmentCount))
throw new Error(`segmentCount must be an integer that is greater than 2, got: ${segmentCount}`);
return startPath(entity, points, duration, faceDirection, segmentCount, onFinishCallback, onPointReachedCallback);
},
stopPath(entity) {
unregisterEntity(entity);
},
getOnFinishCallback(entity) {
if (!finishCbs.has(entity))
throw new Error(`Entity ${entity} is not registered in triggers system`);
return finishCbs.get(entity);
}
};
}
export const paths = createPaths(engine);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9wYXRoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQVUsV0FBVyxFQUFXLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxjQUFjLENBQUE7QUFDdkYsT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQzNELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLFFBQVEsQ0FBQTtBQUMvQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBT3JDLFNBQVMsV0FBVyxDQUFDLFlBQXFCO0lBQ3hDLE1BQU0sVUFBVSxHQUFHLFlBQVksQ0FBQyxlQUFlLENBQUMsc0JBQXNCLEVBQUU7UUFDdEUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQztRQUN0QyxhQUFhLEVBQUUsT0FBTyxDQUFDLE9BQU87UUFDOUIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxNQUFNO1FBQ3JCLGNBQWMsRUFBRSxPQUFPLENBQUMsTUFBTTtRQUM5QixZQUFZLEVBQUUsT0FBTyxDQUFDLE1BQU07UUFDNUIsWUFBWSxFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQztRQUMzQyxpQkFBaUIsRUFBRSxPQUFPLENBQUMsTUFBTTtLQUNsQyxDQUFDLENBQUE7SUFLRixNQUFNLFNBQVMsR0FBc0IsSUFBSSxHQUFHLEVBQUUsQ0FBQTtJQUM5QyxNQUFNLGVBQWUsR0FBOEIsSUFBSSxHQUFHLEVBQUUsQ0FBQTtJQUU1RCxTQUFTLGdCQUFnQixDQUFDLE1BQWM7UUFDdEMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUN4QixlQUFlLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQzlCLFVBQVUsQ0FBQyxVQUFVLENBQUMsTUFB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LENBQUMsTUFBYztZQUNyQixnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUMxQixDQUFDO1FBQ0QsbUJBQW1CLENBQUMsTUFBYztZQUNoQyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUM7Z0JBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxNQUFNLHVDQUF1QyxDQUFDLENBQUE7WUFDMUUsT0FBTyxTQUFTLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQzlCLENBQUM7S0FDRixDQUFBO0FBQ0gsQ0FBQztBQUVELE1BQU0sQ0FBQyxNQUFNLEtBQUssR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBlbmdpbmUsIEVudGl0eSwgRW50aXR5U3RhdGUsIElFbmdpbmUsIFNjaGVtYXMsIFRyYW5zZm9ybSB9IGZyb20gJ0BkY2wvc2RrL2VjcydcbmltcG9ydCB7IFNjYWxhciwgVmVjdG9yMywgUXVhdGVybmlvbiB9IGZyb20gJ0BkY2wvc2RrL21hdGgnXG5pbXBvcnQgeyBjcmVhdGVDYXRtdWxsUm9tU3BsaW5lIH0gZnJvbSAnLi9tYXRoJ1xuaW1wb3J0IHsgcHJpb3JpdHkgfSBmcm9tICcuL3ByaW9yaXR5J1xuXG5leHBvcnQgdHlwZSBQYXRocyA9IFJldHVyblR5cGU8dHlwZW9mIGNyZWF0ZVBhdGhzPlxuXG5leHBvcnQgdHlwZSBPbkZpbmlzaENhbGxiYWNrID0gKCkgPT4gdm9pZFxuZXhwb3J0IHR5cGUgT25Qb2ludFJlYWNoZWRDYWxsYmFjayA9IChwb2ludEluZGV4OiBudW1iZXIsIHBvaW50OiBWZWN0b3IzLCBuZXh0UG9pbnQ6IFZlY3RvcjMpID0+IHZvaWRcblxuZnVuY3Rpb24gY3JlYXRlUGF0aHModGFyZ2V0RW5naW5lOiBJRW5naW5lKSB7XG4gIGNvbnN0IEZvbGxvd1BhdGggPSB0YXJnZXRFbmdpbmUuZGVmaW5lQ29tcG9uZW50KCdkY2wudXRpbHMuRm9sbG93UGF0aCcsIHtcbiAgICBwb2ludHM6IFNjaGVtYXMuQXJyYXkoU2NoZW1hcy5WZWN0b3IzKSxcbiAgICBmYWNlRGlyZWN0aW9uOiBTY2hlbWFzLkJvb2xlYW4sXG4gICAgc3BlZWQ6IFNjaGVtYXMuTnVtYmVyLFxuICAgIG5vcm1hbGl6ZWRUaW1lOiBTY2hlbWFzLk51bWJlcixcbiAgICBjdXJyZW50SW5kZXg6IFNjaGVtYXMuTnVtYmVyLFxuICAgIHNlZ21lbnRUaW1lczogU2NoZW1hcy5BcnJheShTY2hlbWFzLk51bWJlciksXG4gICAgY3VydmVTZWdtZW50Q291bnQ6IFNjaGVtYXMuTnVtYmVyXG4gIH0pXG5cbiAgdHlwZSBGaW5pc2hDYWxsYmFja01hcCA9IE1hcDxFbnRpdHksIE9uRmluaXNoQ2FsbGJhY2sgfCB1bmRlZmluZWQ+XG4gIHR5cGUgT25Qb2ludFJlYWNoZWRDYWxsYmFja01hcCA9IE1hcDxFbnRpdHksIE9uUG9pbnRSZWFjaGVkQ2FsbGJhY2sgfCB1bmRlZmluZWQ+XG5cbiAgY29uc3QgZmluaXNoQ2JzOiBGaW5pc2hDYWxsYmFja01hcCA9IG5ldyBNYXAoKVxuICBjb25zdCBwb2ludFJlYWNoZWRDYnM6IE9uUG9pbnRSZWFjaGVkQ2FsbGJhY2tNYXAgPSBuZXcgTWFwKClcblxuICBmdW5jdGlvbiB1bnJlZ2lzdGVyRW50aXR5KGVudGl0eTogRW50aXR5KSB7XG4gICAgZmluaXNoQ2JzLmRlbGV0ZShlbnRpdHkpXG4gICAgcG9pbnRSZWFjaGVkQ2JzLmRlbGV0ZShlbnRpdHkpXG4gICAgRm9sbG93UGF0aC5kZWxldGVGcm9tKGVudGl0eSlcbiAgfVxuXG4gIGZ1bmN0aW9uIHN5c3RlbShkdDogbnVtYmVyKSB7XG4gICAgY29uc3QgZGVhZFBhdGhzID0gW11cbiAgICBjb25zdCBwb2ludFJlYWNoZWRQYXRocyA9IFtdXG5cbiAgICBmb3IgKGNvbnN0IGVudGl0eSBvZiBmaW5pc2hDYnMua2V5cygpKSB7XG4gICAgICBpZiAodGFyZ2V0RW5naW5lLmdldEVudGl0eVN0YXRlKGVudGl0eSkgPT0gRW50aXR5U3RhdGUuUmVtb3ZlZCB8fCAhRm9sbG93UGF0aC5oYXMoZW50aXR5KSkge1xuICAgICAgICB1bnJlZ2lzdGVyRW50aXR5KGVudGl0eSlcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgY29uc3QgdHJhbnNmb3JtID0gVHJhbnNmb3JtLmdldE11dGFibGUoZW50aXR5KVxuICAgICAgY29uc3QgcGF0aCA9IEZvbGxvd1BhdGguZ2V0TXV0YWJsZShlbnRpdHkpXG4gICAgICBwYXRoLm5vcm1hbGl6ZWRUaW1lID0gU2NhbGFyLmNsYW1wKHBhdGgubm9ybWFsaXplZFRpbWUgKyBkdCAqIHBhdGguc3BlZWQsIDAsIDEpXG4gICAgICBpZiAocGF0aC5ub3JtYWxpemVkVGltZSA+PSAxKVxuICAgICAgICBkZWFkUGF0aHMucHVzaChlbnRpdHkpXG5cbiAgICAgIHdoaWxlIChcbiAgICAgICAgcGF0aC5ub3JtYWxpemVkVGltZSA+PSBwYXRoLnNlZ21lbnRUaW1lc1twYXRoLmN1cnJlbnRJbmRleF0gJiZcbiAgICAgICAgcGF0aC5jdXJyZW50SW5kZXggPCBwYXRoLnBvaW50cy5sZW5ndGggLSAxXG4gICAgICApIHtcbiAgICAgICAgaWYgKHBhdGguZmFjZURpcmVjdGlvbikge1xuICAgICAgICAgIGNvbnN0IGRpcmVjdGlvbiA9IFZlY3RvcjMuc3VidHJhY3QocGF0aC5wb2ludHNbcGF0aC5jdXJyZW50SW5kZXggKyAxXSwgcGF0aC5wb2ludHNbcGF0aC5jdXJyZW50SW5kZXhdKVxuICAgICAgICAgIHRyYW5zZm9ybS5yb3RhdGlvbiA9IFF1YXRlcm5pb24ubG9va1JvdGF0aW9uKGRpcmVjdGlvbilcbiAgICAgICAgfVxuICAgICAgICBpZiAocGF0aC5jdXJyZW50SW5kZXggPiAwICYmIHBhdGguY3VycmVudEluZGV4ICUgcGF0aC5jdXJ2ZVNlZ21lbnRDb3VudCA9PSAwKSB7XG4gICAgICAgICAgY29uc3QgcG9pbnRJbmRleCA9IHBhdGguY3VycmVudEluZGV4IC8gcGF0aC5jdXJ2ZVNlZ21lbnRDb3VudFxuICAgICAgICAgIGNvbnN0IHBvaW50Q29vcmRzID0gcGF0aC5wb2ludHNbcGF0aC5jdXJyZW50SW5kZXhdXG4gICAgICAgICAgY29uc3QgbmV4dFBvaW50Q29vcmRzID0gcGF0aC5wb2ludHNbcGF0aC5jdXJyZW50SW5kZXggKyBwYXRoLmN1cnZlU2VnbWVudENvdW50XVxuICAgICAgICAgIHBvaW50UmVhY2hlZFBhdGhzLnB1c2goe2VudGl0eTogZW50aXR5LCBpbmRleDogcG9pbnRJbmRleCwgY29vcmRzOiBwb2ludENvb3JkcywgbmV4dENvb3JkczogbmV4dFBvaW50Q29vcmRzfSlcbiAgICAgICAgfVxuICAgICAgICBwYXRoLmN1cnJlbnRJbmRleCArPSAxXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHRpbWVEaWZmID0gcGF0aC5zZWdtZW50VGltZXNbcGF0aC5jdXJyZW50SW5kZXhdIC0gcGF0aC5zZWdtZW50VGltZXNbcGF0aC5jdXJyZW50SW5kZXggLSAxXVxuICAgICAgY29uc3QgY29lZiA9IChwYXRoLnNlZ21lbnRUaW1lc1twYXRoLmN1cnJlbnRJbmRleF0gLSBwYXRoLm5vcm1hbGl6ZWRUaW1lKSAvIHRpbWVEaWZmXG4gICAgICB0cmFuc2Zvcm0ucG9zaXRpb24gPSBWZWN0b3IzLmxlcnAocGF0aC5wb2ludHNbcGF0aC5jdXJyZW50SW5kZXhdLCBwYXRoLnBvaW50c1twYXRoLmN1cnJlbnRJbmRleCAtIDFdLCBjb2VmKVxuICAgIH1cblxuICAgIGZvciAoY29uc3QgcG9pbnRSZWFjaGVkIG9mIHBvaW50UmVhY2hlZFBhdGhzKSB7XG4gICAgICBjb25zdCBjYWxsYmFjayA9IHBvaW50UmVhY2hlZENicy5nZXQocG9pbnRSZWFjaGVkLmVudGl0eSlcbiAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICBjYWxsYmFjayhwb2ludFJlYWNoZWQuaW5kZXgsIHBvaW50UmVhY2hlZC5jb29yZHMsIHBvaW50UmVhY2hlZC5uZXh0Q29vcmRzKVxuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAoY29uc3QgZW50aXR5IG9mIGRlYWRQYXRocykge1xuICAgICAgY29uc3QgY2FsbGJhY2sgPSBmaW5pc2hDYnMuZ2V0KGVudGl0eSlcbiAgICAgIHVucmVnaXN0ZXJFbnRpdHkoZW50aXR5KVxuICAgICAgaWYgKGNhbGxiYWNrKVxuICAgICAgICBjYWxsYmFjaygpXG4gICAgfVxuICB9XG5cbiAgdGFyZ2V0RW5naW5lLmFkZFN5c3RlbShzeXN0ZW0sIHByaW9yaXR5LlBhdGhTeXN0ZW1Qcmlvcml0eSlcblxuICBmdW5jdGlvbiBzdGFydFBhdGgoXG4gICAgZW50aXR5OiBFbnRpdHksXG4gICAgcG9pbnRzOiBWZWN0b3IzW10sXG4gICAgZHVyYXRpb246IG51bWJlcixcbiAgICBmYWNlRGlyZWN0aW9uPzogYm9vbGVhbixcbiAgICBjdXJ2ZVNlZ21lbnRDb3VudD86IG51bWJlcixcbiAgICBvbkZpbmlzaENhbGxiYWNrPzogT25GaW5pc2hDYWxsYmFjayxcbiAgICBvblBvaW50UmVhY2hlZENhbGxiYWNrPzogT25Qb2ludFJlYWNoZWRDYWxsYmFja1xuICApIHtcbiAgICBpZiAocG9pbnRzLmxlbmd0aCA8IDIpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0F0IGxlYXN0IDIgcG9pbnRzIGFyZSByZXF1aXJlZCB0byBmb3JtIGEgcGF0aC4nKVxuXG4gICAgaWYgKGR1cmF0aW9uID09IDApXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BhdGggZHVyYXRpb24gbXVzdCBub3QgYmUgemVybycpXG5cbiAgICBpZiAoY3VydmVTZWdtZW50Q291bnQpIHtcbiAgICAgIGNvbnN0IGxvb3AgPSBWZWN0b3IzLmVxdWFscyhwb2ludHNbMF0sIHBvaW50c1twb2ludHMubGVuZ3RoIC0gMV0pXG4gICAgICBpZiAobG9vcCkge1xuICAgICAgICBwb2ludHMucG9wKClcbiAgICAgICAgcG9pbnRzLnVuc2hpZnQocG9pbnRzLnBvcCgpISlcbiAgICAgIH1cbiAgICAgIHBvaW50cyA9IGNyZWF0ZUNhdG11bGxSb21TcGxpbmUocG9pbnRzLCBjdXJ2ZVNlZ21lbnRDb3VudCwgbG9vcClcbiAgICB9IGVsc2Uge1xuICAgICAgY3VydmVTZWdtZW50Q291bnQgPSAxXG4gICAgfVxuXG4gICAgZmluaXNoQ2JzLnNldChlbnRpdHksIG9uRmluaXNoQ2FsbGJhY2spXG4gICAgcG9pbnRSZWFjaGVkQ2JzLnNldChlbnRpdHksIG9uUG9pbnRSZWFjaGVkQ2FsbGJhY2spXG5cbiAgICBsZXQgdG90YWxMZW5ndGggPSAwXG4gICAgY29uc3Qgc2VnbWVudExlbmd0aHMgPSBbXVxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aCAtIDE7IGkrKykge1xuICAgICAgbGV0IHNxRGlzdCA9IFZlY3RvcjMuZGlzdGFuY2UocG9pbnRzW2ldLCBwb2ludHNbaSArIDFdKVxuICAgICAgdG90YWxMZW5ndGggKz0gc3FEaXN0XG4gICAgICBzZWdtZW50TGVuZ3Rocy5wdXNoKHNxRGlzdClcbiAgICB9XG5cbiAgICBjb25zdCBzZWdtZW50VGltZXMgPSBbMF1cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNlZ21lbnRMZW5ndGhzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBzZWdtZW50VGltZXMucHVzaChzZWdtZW50TGVuZ3Roc1tpXSAvIHRvdGFsTGVuZ3RoICsgc2VnbWVudFRpbWVzW2ldKVxuICAgIH1cblxuICAgIEZvbGxvd1BhdGguY3JlYXRlT3JSZXBsYWNlKGVudGl0eSwge1xuICAgICAgcG9pbnRzOiBwb2ludHMsXG4gICAgICBzZWdtZW50VGltZXM6IHNlZ21lbnRUaW1lcyxcbiAgICAgIGN1cnZlU2VnbWVudENvdW50OiBjdXJ2ZVNlZ21lbnRDb3VudCxcbiAgICAgIHNwZWVkOiAxIC8gZHVyYXRpb24sXG4gICAgICBub3JtYWxpemVkVGltZTogMCxcbiAgICAgIGN1cnJlbnRJbmRleDogMCxcbiAgICAgIGZhY2VEaXJlY3Rpb246IGZhY2VEaXJlY3Rpb25cbiAgICB9KVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBzdGFydFN0cmFpZ2h0UGF0aChcbiAgICAgIGVudGl0eTogRW50aXR5LFxuICAgICAgcG9pbnRzOiBWZWN0b3IzW10sXG4gICAgICBkdXJhdGlvbjogbnVtYmVyLFxuICAgICAgZmFjZURpcmVjdGlvbj86IGJvb2xlYW4sXG4gICAgICBvbkZpbmlzaENhbGxiYWNrPzogT25GaW5pc2hDYWxsYmFjayxcbiAgICAgIG9uUG9pbnRSZWFjaGVkQ2FsbGJhY2s/OiBPblBvaW50UmVhY2hlZENhbGxiYWNrXG4gICAgKSB7XG4gICAgICByZXR1cm4gc3RhcnRQYXRoKGVudGl0eSwgcG9pbnRzLCBkdXJhdGlvbiwgZmFjZURpcmVjdGlvbiwgMCwgb25GaW5pc2hDYWxsYmFjaywgb25Qb2ludFJlYWNoZWRDYWxsYmFjaylcbiAgICB9LFxuICAgIHN0YXJ0U21vb3RoUGF0aChcbiAgICAgIGVudGl0eTogRW50aXR5LFxuICAgICAgcG9pbnRzOiBWZWN0b3IzW10sXG4gICAgICBkdXJhdGlvbjogbnVtYmVyLFxuICAgICAgc2VnbWVudENvdW50OiBudW1iZXIsXG4gICAgICBmYWNlRGlyZWN0aW9uPzogYm9vbGVhbixcbiAgICAgIG9uRmluaXNoQ2FsbGJhY2s/OiBPbkZpbmlzaENhbGxiYWNrLFxuICAgICAgb25Qb2ludFJlYWNoZWRDYWxsYmFjaz86IE9uUG9pbnRSZWFjaGVkQ2FsbGJhY2tcbiAgICApIHtcbiAgICAgIGlmIChzZWdtZW50Q291bnQgPCAyIHx8ICFOdW1iZXIuaXNJbnRlZ2VyKHNlZ21lbnRDb3VudCkpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgc2VnbWVudENvdW50IG11c3QgYmUgYW4gaW50ZWdlciB0aGF0IGlzIGdyZWF0ZXIgdGhhbiAyLCBnb3Q6ICR7c2VnbWVudENvdW50fWApXG4gICAgICByZXR1cm4gc3RhcnRQYXRoKGVudGl0eSwgcG9pbnRzLCBkdXJhdGlvbiwgZmFjZURpcmVjdGlvbiwgc2VnbWVudENvdW50LCBvbkZpbmlzaENhbGxiYWNrLCBvblBvaW50UmVhY2hlZENhbGxiYWNrKVxuICAgIH0sXG4gICAgc3RvcFBhdGgoZW50aXR5OiBFbnRpdHkpIHtcbiAgICAgIHVucmVnaXN0ZXJFbnRpdHkoZW50aXR5KVxuICAgIH0sXG4gICAgZ2V0T25GaW5pc2hDYWxsYmFjayhlbnRpdHk6IEVudGl0eSkge1xuICAgICAgaWYgKCFmaW5pc2hDYnMuaGFzKGVudGl0eSkpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRW50aXR5ICR7ZW50aXR5fSBpcyBub3QgcmVnaXN0ZXJlZCBpbiB0cmlnZ2VycyBzeXN0ZW1gKVxuICAgICAgcmV0dXJuIGZpbmlzaENicy5nZXQoZW50aXR5KVxuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgY29uc3QgcGF0aHMgPSBjcmVhdGVQYXRocyhlbmdpbmUpXG4iXX0=