diff --git a/app_web/game.js b/app_web/game.js
new file mode 100644
index 0000000..627ec3a
--- /dev/null
+++ b/app_web/game.js
@@ -0,0 +1,2 @@
+(()=>{"use strict";const t=new class{constructor(){this.states=new Map}get(t){return this.states.get(t)}set(t,i){return this.states.set(t,i)}};class i{constructor(){this.inventory=[],this.currentRoom="start"}}class e{speak(t){}stop(){}setOptions(t){}}class s extends e{constructor(t={}){super(),this.timeout=100,this.timeout=t.timeout||100,this.init()}init(){this.container=document.createElement("div"),this.container.setAttribute("aria-live","polite"),this.speechDisplay=document.createElement("div"),this.speechDisplay.setAttribute("aria-live","polite"),this.container.append(this.speechDisplay),document.body.appendChild(this.container),document.body.insertBefore(this.container,document.body.firstChild)}speak(t){this.clearDisplay();const i=document.createTextNode(t),e=document.createElement("p");e.appendChild(i),this.speechDisplay.appendChild(e),setTimeout(this.clearDisplay.bind(this),this.timeout)}stop(){this.clearDisplay()}clearDisplay(){this.speechDisplay.innerHTML=""}}class o extends e{}class n{constructor(t=function(t="aria"){return"webtts"===t?o:s}()){this.output=t}speak(t){this.output.speak(t)}stop(){this.output.stop()}}class a{constructor(){this.tts=new n(new s),this.history=document.getElementById("output-area")}say(t){const i=document.createElement("p");i.appendChild(document.createTextNode(t)),this.history.appendChild(i)}}class r{constructor(t){this.handler=t,this.inputField=document.getElementById("input-area"),this.init()}init(){this.inputField.addEventListener("keydown",(t=>{if(13==t.which){const t=this.inputField.value;this.inputField.value="",this.handler.doCommand(t)}}))}}const h=[[["look","l"],function(t,i){i.examineRoom()}]];class c{constructor(t,i){this.context=t,this.commands=i||new Map,this.addDefaultCommands()}doCommand(t){const i=this.context.getRoom(this.context.player.currentRoom),e=t.split(" ");this.commands.get(e[0])&&this.commands.get(e[0])(e,this.context),i.getExit(e[0])&&this.context.move(i.getExit(e[0]))}addCommand(t,i){Array.isArray(t)?t.forEach((t=>this.commands.set(t,i))):this.commands.set(t,i)}addCommands(t){t.forEach((t=>{this.addCommand(t[0],t[1])}))}addDefaultCommands(){this.addCommands(h)}}class l{constructor(){this.id="room",this.title="A room",this.description="You see nothing special",this.firstDescription="As you walk into the room, you notice nothing special",this.objects=[],this.exits=new Map,this.enterCallback=null,this.exitCallback=null,this.canEnterLogic=null,this.canExitLogic=null,this.tickCallback=null,this.context=null}async onEnter(){if(this.enterCallback)return this.enterCallback(this.context)}async onExit(){if(this.exitCallback)return this.exitCallback(this.context)}canEnter(){return!this.canEnterLogic||this.canEnterLogic(this.context)}canExit(){return!this.canExitLogic||this.canExitLogic(this.context)}addExit(t,i){return this.exits.set(t,i),this}getExit(t){return this.exits.get(t)}addItem(t){this.objects.push(t)}addEnterCallback(t){this.enterCallback=t}addExitCallback(t){this.exitCallback=t}addEnterLogic(t){this.canEnterLogic=t}addExitLogic(t){this.canExitLogic=t}addTickCallback(t){this.tickCallback=t}}class d{constructor(){this.room=new l}withID(t){return this.room.id=t,this}withTitle(t){return this.room.title=t,this}withFirstDescription(t){return this.room.firstDescription=t,this}withDescription(t){return this.room.description=t,this}withExit(t,i){return this.room.addExit(t,i),this}withItem(t){return this.room.addItem(t),this}withEnterCallback(t){return this.room.addEnterCallback(t),this}withExitCallback(t){return this.room.addExitCallback(t),this}withEnterLogic(t){return this.room.addEnterLogic(t),this}withExitLogic(t){return this.room.addExitLogic(t),this}withTick(t){return this.room.addTickCallback(t),this}create(){return this.room}}const m=[(new d).withID("start").withTitle("The starting room").withFirstDescription("You set foot in your very first room").withDescription("The first room. Nothing special about it.").withExit("north","tunnel_1").withEnterCallback((async function(t){const{output:i,wait:e}=t;i.say("You slowly wake up"),await e(5e3),i.say("It's strange. You never used to be able to be conscious about the fact that you were waking up."),await e(5e3),i.say("Yet here we are.")})).create(),(new d).withID("tunnel_1").withTitle("A long dark tunnel").withFirstDescription("You first step foot in this dark loomy tunnel.").withDescription("The walls are wet. Everything is wet. Ugh. Why do you even.").withExit("south","start").create()];(new class{constructor(){this.player=new i,this.state=t,this.rooms=[],this.items=[],this.output=new a,this.commandHandler=new c(this),this.input=new r(this.commandHandler),this.visitedRooms=new Map}print(t){this.output.say(t)}init(t){this.rooms=t.rooms.map((t=>(t.context=this,t))),this.items=t.items.map((t=>(t.context=this,t))),this.state=t.state,this.commandHandler.addCommands(t.commands),this.player=new i,this.move(this.player.currentRoom)}examineRoom(){const t=this.getRoom(this.player.currentRoom);this.output.say(t.title),this.visitedRooms.get(this.player.currentRoom)||""==t.firstDescription?this.output.say(t.description):this.output.say(t.firstDescription)}getRoom(t){return this.rooms.find((i=>i.id==t))}getItem(t){return this.items.find((i=>i.id==t))}wait(t){return new Promise(((i,e)=>{setTimeout(i,t)}))}async move(t){const i=this.getRoom(this.player.currentRoom),e=this.getRoom(t);i.canExit()&&e.canEnter()&&(await i.onExit(),await e.onEnter(),this.player.currentRoom=t,this.examineRoom(),this.visitedRooms.set(t,!0))}}).init({rooms:m,commands:[[["meow","mew"],async function(t,i){i.print("You meow.")}]],items:[]})})();
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUNsQlAsS0FBS3FFLEtBQUtyRSxLQUFLa0UsT0FBT3pELGFBRzFCa0QsY0FDSSxNQUFNSyxFQUFPaEUsS0FBS2lFLFFBQVFqRSxLQUFLa0UsT0FBT3pELGFBQ3RDVCxLQUFLdUMsT0FBT00sSUFBSW1CLEVBQUtnQixPQUNoQmhGLEtBQUs2SCxhQUFhMUgsSUFBSUgsS0FBS2tFLE9BQU96RCxjQUF5QyxJQUF6QnVELEVBQUtrQixpQkFHeERsRixLQUFLdUMsT0FBT00sSUFBSW1CLEVBQUtpQixhQUZyQmpGLEtBQUt1QyxPQUFPTSxJQUFJbUIsRUFBS2tCLGtCQU03QmpCLFFBQVFjLEdBQ0osT0FBTy9FLEtBQUswSCxNQUFNTyxNQUFNakUsR0FBU0EsRUFBS2UsSUFBTUEsSUFHaERtRCxRQUFRbkQsR0FDSixPQUFPL0UsS0FBSzJILE1BQU1NLE1BQU1oQyxHQUFTQSxFQUFLbEIsSUFBTUEsSUFHaER5QyxLQUFLVyxHQUNELE9BQU8sSUFBSUMsU0FBUSxDQUFDQyxFQUFTQyxLQUN6QnBHLFdBQVdtRyxFQUFTRixNQUk1QnpDLFdBQVdLLEdBQ1AsTUFBTXRGLEVBQWNULEtBQUtpRSxRQUFRakUsS0FBS2tFLE9BQU96RCxhQUN2QzhILEVBQVV2SSxLQUFLaUUsUUFBUThCLEdBQ3pCdEYsRUFBWW1GLFdBQWEyQyxFQUFRNUMsbUJBQzNCbEYsRUFBWStILGVBQ1pELEVBQVFFLFVBQ2R6SSxLQUFLa0UsT0FBT3pELFlBQWNzRixFQUMxQi9GLEtBQUsyRCxjQUNMM0QsS0FBSzZILGFBQWF4SCxJQUFJMEYsR0FBUSxPRC9EckM1RSxLQUFLLENBQ051RyxNQUFPLEVBQ1A3RCxTQUFVLENBQ04sQ0FBQyxDQUFDLE9BQVEsT0VWSDZCLGVBQTJCakMsRUFBTUMsR0FDNUNBLEVBQVFvRSxNQUFNLGdCRldkSCxNQUFPLE0iLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL3N0YXRlLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvcGxheWVyLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9mcmFtZXdvcmsvdHRzL291dHB1dHMvYmFzZS1vdXRwdXQuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90dHMvb3V0cHV0cy9hcmlhLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9mcmFtZXdvcmsvdHRzL291dHB1dHMvd2VidHRzLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9mcmFtZXdvcmsvdHRzL2luZGV4LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9mcmFtZXdvcmsvdHRzL291dHB1dC1mYWN0b3J5LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvb3V0cHV0LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvaW5wdXQuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9jb21tYW5kcy5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL2NvbW1hbmRzL2xvb2suanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9yb29tLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvYnVpbGRlcnMvcm9vbS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9zdGFydC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9pbmRleC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy90dW5uZWwxLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2luZGV4LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvaW5kZXguanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2dhbWUvY29tbWFuZHMvbWVvdy5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjbGFzcyBTdGF0ZSB7XHJcbiAgICBjb25zdHJ1Y3RvcigpIHtcclxuICAgICAgICB0aGlzLnN0YXRlcyA9IG5ldyBNYXAoKTtcclxuICAgIH1cclxuXHJcbiAgICBnZXQoa2V5KSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVzLmdldChrZXkpO1xyXG4gICAgfVxyXG5cclxuICAgIHNldChrZXksIHZhbHVlKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVzLnNldChrZXksIHZhbHVlKTtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgbmV3IFN0YXRlKCk7IiwiZXhwb3J0IGRlZmF1bHQgY2xhc3MgUGxheWVyIHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMuaW52ZW50b3J5ID0gW107XHJcbiAgICAgICAgdGhpcy5jdXJyZW50Um9vbSA9IFwic3RhcnRcIjtcclxuICAgIH1cclxufSIsImV4cG9ydCBjbGFzcyBCYXNlT3V0cHV0IHtcclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBzdG9wKCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIHNldE9wdGlvbnMob3B0aW9ucykge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBCYXNlT3V0cHV0IH0gZnJvbSAnLi9iYXNlLW91dHB1dCc7XHJcbmV4cG9ydCBjbGFzcyBBcmlhT3V0cHV0IGV4dGVuZHMgQmFzZU91dHB1dCB7XHJcbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zID0ge30pIHtcclxuICAgICAgICBzdXBlcigpO1xyXG4gICAgICAgIHRoaXMudGltZW91dCA9IDEwMDtcclxuICAgICAgICB0aGlzLnRpbWVvdXQgPSBvcHRpb25zLnRpbWVvdXQgfHwgMTAwO1xyXG4gICAgICAgIHRoaXMuaW5pdCgpO1xyXG4gICAgfVxyXG4gICAgaW5pdCgpIHtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyLnNldEF0dHJpYnV0ZSgnYXJpYS1saXZlJywgJ3BvbGl0ZScpO1xyXG4gICAgICAgIHRoaXMuc3BlZWNoRGlzcGxheSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgICAgIHRoaXMuc3BlZWNoRGlzcGxheS5zZXRBdHRyaWJ1dGUoJ2FyaWEtbGl2ZScsICdwb2xpdGUnKTtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lci5hcHBlbmQodGhpcy5zcGVlY2hEaXNwbGF5KTtcclxuICAgICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHRoaXMuY29udGFpbmVyKTtcclxuICAgICAgICBkb2N1bWVudC5ib2R5Lmluc2VydEJlZm9yZSh0aGlzLmNvbnRhaW5lciwgZG9jdW1lbnQuYm9keS5maXJzdENoaWxkKTtcclxuICAgIH1cclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICB0aGlzLmNsZWFyRGlzcGxheSgpO1xyXG4gICAgICAgIGNvbnN0IG5vZGUgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSh0ZXh0KTtcclxuICAgICAgICBjb25zdCBwYXJhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgncCcpO1xyXG4gICAgICAgIHBhcmEuYXBwZW5kQ2hpbGQobm9kZSk7XHJcbiAgICAgICAgdGhpcy5zcGVlY2hEaXNwbGF5LmFwcGVuZENoaWxkKHBhcmEpO1xyXG4gICAgICAgIHNldFRpbWVvdXQodGhpcy5jbGVhckRpc3BsYXkuYmluZCh0aGlzKSwgdGhpcy50aW1lb3V0KTtcclxuICAgIH1cclxuICAgIHN0b3AoKSB7XHJcbiAgICAgICAgdGhpcy5jbGVhckRpc3BsYXkoKTtcclxuICAgIH1cclxuICAgIGNsZWFyRGlzcGxheSgpIHtcclxuICAgICAgICB0aGlzLnNwZWVjaERpc3BsYXkuaW5uZXJIVE1MID0gJyc7XHJcbiAgICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgQmFzZU91dHB1dCB9IGZyb20gJy4vYmFzZS1vdXRwdXQnO1xyXG5leHBvcnQgY2xhc3MgV2ViVFRTT3V0cHV0IGV4dGVuZHMgQmFzZU91dHB1dCB7XHJcbn1cclxuIiwiaW1wb3J0IHsgY3JlYXRlT3V0cHV0IH0gZnJvbSAnLi9vdXRwdXQtZmFjdG9yeSc7XHJcbmV4cG9ydCBjbGFzcyBUVFMge1xyXG4gICAgY29uc3RydWN0b3Iob3V0cHV0ID0gY3JlYXRlT3V0cHV0KCkpIHtcclxuICAgICAgICB0aGlzLm91dHB1dCA9IG91dHB1dDtcclxuICAgIH1cclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICB0aGlzLm91dHB1dC5zcGVhayh0ZXh0KTtcclxuICAgIH1cclxuICAgIHN0b3AoKSB7XHJcbiAgICAgICAgdGhpcy5vdXRwdXQuc3RvcCgpO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCB7IEJhc2VPdXRwdXQgfSBmcm9tICcuL291dHB1dHMvYmFzZS1vdXRwdXQnO1xyXG5pbXBvcnQgeyBBcmlhT3V0cHV0IH0gZnJvbSAnLi9vdXRwdXRzL2FyaWEnO1xyXG5pbXBvcnQgeyBXZWJUVFNPdXRwdXQgfSBmcm9tICcuL291dHB1dHMvd2VidHRzJztcclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU91dHB1dChrZXkgPSAnYXJpYScpIHtcclxuICAgIHN3aXRjaCAoa2V5KSB7XHJcbiAgICAgICAgY2FzZSAnYXJpYSc6XHJcbiAgICAgICAgICAgIHJldHVybiBBcmlhT3V0cHV0O1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICBjYXNlICd3ZWJ0dHMnOlxyXG4gICAgICAgICAgICByZXR1cm4gV2ViVFRTT3V0cHV0O1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICByZXR1cm4gQXJpYU91dHB1dDtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICB9XHJcbn1cclxuZXhwb3J0IHsgV2ViVFRTT3V0cHV0LCBBcmlhT3V0cHV0LCBCYXNlT3V0cHV0IH07XHJcbiIsImltcG9ydCB7IFRUUyB9IGZyb20gJy4uL2ZyYW1ld29yay90dHMnO1xyXG5pbXBvcnQgeyBBcmlhT3V0cHV0IH0gZnJvbSAnLi4vZnJhbWV3b3JrL3R0cy9vdXRwdXRzL2FyaWEnO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgT3V0cHV0IHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMudHRzID0gbmV3IFRUUyhuZXcgQXJpYU91dHB1dCgpKTtcclxuICAgICAgICB0aGlzLmhpc3RvcnkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcIm91dHB1dC1hcmVhXCIpO1xyXG4gICAgfVxyXG5cclxuICAgIHNheShzdHJpbmcpIHtcclxuICAgICAgICBjb25zdCBub2RlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInBcIik7XHJcbiAgICAgICAgbm9kZS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShzdHJpbmcpKTtcclxuICAgICAgICB0aGlzLmhpc3RvcnkuYXBwZW5kQ2hpbGQobm9kZSk7XHJcbiAgICAgICAgLy8gdGhpcy50dHMuc3BlYWsoc3RyaW5nKTtcclxuICAgIH1cclxufSIsImV4cG9ydCBkZWZhdWx0IGNsYXNzIElucHV0IHtcclxuICAgIGNvbnN0cnVjdG9yKGNvbW1hbmRIYW5kbGVyKSB7XHJcbiAgICAgICAgdGhpcy5oYW5kbGVyID0gY29tbWFuZEhhbmRsZXI7XHJcbiAgICAgICAgdGhpcy5pbnB1dEZpZWxkID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJpbnB1dC1hcmVhXCIpO1xyXG4gICAgICAgIHRoaXMuaW5pdCgpO1xyXG4gICAgfVxyXG5cclxuICAgIGluaXQoKSB7XHJcbiAgICAgICAgdGhpcy5pbnB1dEZpZWxkLmFkZEV2ZW50TGlzdGVuZXIoXCJrZXlkb3duXCIsIChlKSA9PiB7XHJcbiAgICAgICAgICAgIGlmIChlLndoaWNoID09IDEzKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCB2YWwgPSB0aGlzLmlucHV0RmllbGQudmFsdWU7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmlucHV0RmllbGQudmFsdWUgPSBcIlwiO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5oYW5kbGVyLmRvQ29tbWFuZCh2YWwpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSlcclxuICAgIH1cclxufSIsImltcG9ydCBMb29rQ29tbWFuZCBmcm9tIFwiLi9jb21tYW5kcy9sb29rXCI7XHJcblxyXG5jb25zdCBkZWZhdWx0Q29tbWFuZHMgPSBbXHJcbiAgICBbW1wibG9va1wiLCBcImxcIl0sIExvb2tDb21tYW5kXVxyXG5dO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ29tbWFuZHMge1xyXG4gICAgY29uc3RydWN0b3IoY29udGV4dCwgY29tbWFuZHMpIHtcclxuICAgICAgICB0aGlzLmNvbnRleHQgPSBjb250ZXh0O1xyXG4gICAgICAgIHRoaXMuY29tbWFuZHMgPSBjb21tYW5kcyB8fCBuZXcgTWFwKCk7XHJcbiAgICAgICAgdGhpcy5hZGREZWZhdWx0Q29tbWFuZHMoKTtcclxuICAgIH1cclxuXHJcbiAgICBkb0NvbW1hbmQoc3RyKSB7XHJcbiAgICAgICAgY29uc3Qgcm9vbSA9IHRoaXMuY29udGV4dC5nZXRSb29tKHRoaXMuY29udGV4dC5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIGNvbnN0IHNwbGl0ID0gc3RyLnNwbGl0KFwiIFwiKTtcclxuICAgICAgICBpZiAodGhpcy5jb21tYW5kcy5nZXQoc3BsaXRbMF0pKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY29tbWFuZHMuZ2V0KHNwbGl0WzBdKShzcGxpdCwgdGhpcy5jb250ZXh0KTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKHJvb20uZ2V0RXhpdChzcGxpdFswXSkpIHtcclxuICAgICAgICAgICAgdGhpcy5jb250ZXh0Lm1vdmUocm9vbS5nZXRFeGl0KHNwbGl0WzBdKSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGFkZENvbW1hbmQobmFtZSwgZnVuYykge1xyXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KG5hbWUpKSB7XHJcbiAgICAgICAgICAgIG5hbWUuZm9yRWFjaCgoY29tbWFuZCkgPT4gdGhpcy5jb21tYW5kcy5zZXQoY29tbWFuZCwgZnVuYykpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMuY29tbWFuZHMuc2V0KG5hbWUsIGZ1bmMpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBhZGRDb21tYW5kcyhjb21tYW5kcykge1xyXG4gICAgICAgIGNvbW1hbmRzLmZvckVhY2goKGNvbW1hbmQpID0+IHtcclxuICAgICAgICAgICAgdGhpcy5hZGRDb21tYW5kKGNvbW1hbmRbMF0sIGNvbW1hbmRbMV0pO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZERlZmF1bHRDb21tYW5kcygpIHtcclxuICAgICAgICB0aGlzLmFkZENvbW1hbmRzKGRlZmF1bHRDb21tYW5kcyk7XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBMb29rQ29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LmV4YW1pbmVSb29tKCk7XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBjbGFzcyBSb29tIHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMuaWQgPSBcInJvb21cIjtcclxuICAgICAgICB0aGlzLnRpdGxlID0gXCJBIHJvb21cIjtcclxuICAgICAgICB0aGlzLmRlc2NyaXB0aW9uID0gXCJZb3Ugc2VlIG5vdGhpbmcgc3BlY2lhbFwiO1xyXG4gICAgICAgIHRoaXMuZmlyc3REZXNjcmlwdGlvbiA9IFwiQXMgeW91IHdhbGsgaW50byB0aGUgcm9vbSwgeW91IG5vdGljZSBub3RoaW5nIHNwZWNpYWxcIjtcclxuICAgICAgICB0aGlzLm9iamVjdHMgPSBbXTtcclxuICAgICAgICB0aGlzLmV4aXRzID0gbmV3IE1hcCgpO1xyXG4gICAgICAgIHRoaXMuZW50ZXJDYWxsYmFjayA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5leGl0Q2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuY2FuRW50ZXJMb2dpYyA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5jYW5FeGl0TG9naWMgPSBudWxsO1xyXG4gICAgICAgIHRoaXMudGlja0NhbGxiYWNrID0gbnVsbDtcclxuICAgICAgICB0aGlzLmNvbnRleHQgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uRW50ZXIoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZW50ZXJDYWxsYmFjaykgcmV0dXJuIHRoaXMuZW50ZXJDYWxsYmFjayh0aGlzLmNvbnRleHQpO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uRXhpdCgpIHtcclxuICAgICAgICBpZiAodGhpcy5leGl0Q2FsbGJhY2spIHJldHVybiB0aGlzLmV4aXRDYWxsYmFjayh0aGlzLmNvbnRleHQpO1xyXG4gICAgfVxyXG5cclxuICAgIGNhbkVudGVyKCkge1xyXG4gICAgICAgIGlmICh0aGlzLmNhbkVudGVyTG9naWMpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2FuRW50ZXJMb2dpYyh0aGlzLmNvbnRleHQpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICBjYW5FeGl0KCkge1xyXG4gICAgICAgIGlmICh0aGlzLmNhbkV4aXRMb2dpYykge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jYW5FeGl0TG9naWModGhpcy5jb250ZXh0KTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkRXhpdChkaXJlY3Rpb24sIHJvb21JRCkge1xyXG4gICAgICAgIHRoaXMuZXhpdHMuc2V0KGRpcmVjdGlvbiwgcm9vbUlEKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICBnZXRFeGl0KGRpcmVjdGlvbikge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmV4aXRzLmdldChkaXJlY3Rpb24pO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZEl0ZW0oaXRlbSkge1xyXG4gICAgICAgIHRoaXMub2JqZWN0cy5wdXNoKGl0ZW0pO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZEVudGVyQ2FsbGJhY2soY2FsbGJhY2spIHtcclxuICAgICAgICB0aGlzLmVudGVyQ2FsbGJhY2sgPSBjYWxsYmFjaztcclxuICAgIH1cclxuXHJcbiAgICBhZGRFeGl0Q2FsbGJhY2soY2FsbGJhY2spIHtcclxuICAgICAgICB0aGlzLmV4aXRDYWxsYmFjayA9IGNhbGxiYWNrO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZEVudGVyTG9naWMoZnVuYykge1xyXG4gICAgICAgIHRoaXMuY2FuRW50ZXJMb2dpYyA9IGZ1bmM7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkRXhpdExvZ2ljKGZ1bmMpIHtcclxuICAgICAgICB0aGlzLmNhbkV4aXRMb2dpYyA9IGZ1bmM7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkVGlja0NhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy50aWNrQ2FsbGJhY2sgPSBjYWxsYmFjaztcclxuICAgIH1cclxufSIsImltcG9ydCBSb29tIGZyb20gJy4uL3Jvb20nO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUm9vbUJ1aWxkZXIge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5yb29tID0gbmV3IFJvb20oKTtcclxuICAgIH1cclxuXHJcbiAgICB3aXRoSUQoSUQpIHtcclxuICAgICAgICB0aGlzLnJvb20uaWQgPSBJRDtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIFxyXG4gICAgd2l0aFRpdGxlKHRpdGxlKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLnRpdGxlID0gdGl0bGU7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aEZpcnN0RGVzY3JpcHRpb24oZGVzY3JpcHRpb24pIHtcclxuICAgICAgICB0aGlzLnJvb20uZmlyc3REZXNjcmlwdGlvbiA9IGRlc2NyaXB0aW9uO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhEZXNjcmlwdGlvbihkZXNjcmlwdGlvbikge1xyXG4gICAgICAgIHRoaXMucm9vbS5kZXNjcmlwdGlvbiA9IGRlc2NyaXB0aW9uO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhFeGl0KGRpcmVjdGlvbiwgcm9vbUlEKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmFkZEV4aXQoZGlyZWN0aW9uLCByb29tSUQpO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhJdGVtKGl0ZW1JRCkge1xyXG4gICAgICAgIHRoaXMucm9vbS5hZGRJdGVtKGl0ZW1JRCk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aEVudGVyQ2FsbGJhY2soY2FsbGJhY2spIHtcclxuICAgICAgICB0aGlzLnJvb20uYWRkRW50ZXJDYWxsYmFjayhjYWxsYmFjayk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aEV4aXRDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMucm9vbS5hZGRFeGl0Q2FsbGJhY2soY2FsbGJhY2spO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhFbnRlckxvZ2ljKGZ1bmMpIHtcclxuICAgICAgICB0aGlzLnJvb20uYWRkRW50ZXJMb2dpYyhmdW5jKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoRXhpdExvZ2ljKGZ1bmMpIHtcclxuICAgICAgICB0aGlzLnJvb20uYWRkRXhpdExvZ2ljKGZ1bmMpO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhUaWNrKGZ1bmMpIHtcclxuICAgICAgICB0aGlzLnJvb20uYWRkVGlja0NhbGxiYWNrKGZ1bmMpO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIGNyZWF0ZSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5yb29tO1xyXG4gICAgfVxyXG59IiwiaW1wb3J0IFJvb21CdWlsZGVyIGZyb20gJy4uLy4uL2VuZ2luZS9idWlsZGVycy9yb29tJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBSb29tQnVpbGRlcigpXHJcbi53aXRoSUQoXCJzdGFydFwiKVxyXG4ud2l0aFRpdGxlKFwiVGhlIHN0YXJ0aW5nIHJvb21cIilcclxuLndpdGhGaXJzdERlc2NyaXB0aW9uKFwiWW91IHNldCBmb290IGluIHlvdXIgdmVyeSBmaXJzdCByb29tXCIpXHJcbi53aXRoRGVzY3JpcHRpb24oXCJUaGUgZmlyc3Qgcm9vbS4gTm90aGluZyBzcGVjaWFsIGFib3V0IGl0LlwiKVxyXG4ud2l0aEV4aXQoXCJub3J0aFwiLCBcInR1bm5lbF8xXCIpXHJcbi53aXRoRW50ZXJDYWxsYmFjayhhc3luYyBmdW5jdGlvbihjb250ZXh0KSB7XHJcbiAgICBjb25zdCB7IG91dHB1dCwgd2FpdCB9ID0gY29udGV4dDtcclxuICAgIG91dHB1dC5zYXkoXCJZb3Ugc2xvd2x5IHdha2UgdXBcIik7XHJcbiAgICBhd2FpdCB3YWl0KDUwMDApO1xyXG4gICAgb3V0cHV0LnNheShcIkl0J3Mgc3RyYW5nZS4gWW91IG5ldmVyIHVzZWQgdG8gYmUgYWJsZSB0byBiZSBjb25zY2lvdXMgYWJvdXQgdGhlIGZhY3QgdGhhdCB5b3Ugd2VyZSB3YWtpbmcgdXAuXCIpO1xyXG4gICAgYXdhaXQgd2FpdCg1MDAwKTtcclxuICAgIG91dHB1dC5zYXkoXCJZZXQgaGVyZSB3ZSBhcmUuXCIpO1xyXG59KVxyXG4uY3JlYXRlKCk7IiwiaW1wb3J0IFN0YXJ0IGZyb20gJy4vc3RhcnQnO1xyXG5pbXBvcnQgVHVubmVsMSBmcm9tICcuL3R1bm5lbDEnO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgW1xyXG4gICAgU3RhcnQsXHJcbiAgICBUdW5uZWwxXHJcbl07IiwiaW1wb3J0IFJvb21CdWlsZGVyIGZyb20gJy4uLy4uL2VuZ2luZS9idWlsZGVycy9yb29tJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBSb29tQnVpbGRlcigpXHJcbi53aXRoSUQoXCJ0dW5uZWxfMVwiKVxyXG4ud2l0aFRpdGxlKFwiQSBsb25nIGRhcmsgdHVubmVsXCIpXHJcbi53aXRoRmlyc3REZXNjcmlwdGlvbihcIllvdSBmaXJzdCBzdGVwIGZvb3QgaW4gdGhpcyBkYXJrIGxvb215IHR1bm5lbC5cIilcclxuLndpdGhEZXNjcmlwdGlvbihcIlRoZSB3YWxscyBhcmUgd2V0LiBFdmVyeXRoaW5nIGlzIHdldC4gVWdoLiBXaHkgZG8geW91IGV2ZW4uXCIpXHJcbi53aXRoRXhpdChcInNvdXRoXCIsIFwic3RhcnRcIilcclxuLmNyZWF0ZSgpOyIsImltcG9ydCBHYW1lIGZyb20gJy4uL2VuZ2luZSc7XHJcbmltcG9ydCBSb29tcyBmcm9tICcuL3Jvb21zJztcclxuaW1wb3J0IE1lb3dDb21tYW5kIGZyb20gJy4vY29tbWFuZHMvbWVvdyc7XHJcblxyXG5jb25zdCBnYW1lID0gbmV3IEdhbWUoKTtcclxuXHJcblxyXG5nYW1lLmluaXQoe1xyXG4gICAgcm9vbXM6IFJvb21zLFxyXG4gICAgY29tbWFuZHM6IFtcclxuICAgICAgICBbW1wibWVvd1wiLCBcIm1ld1wiXSwgTWVvd0NvbW1hbmRdXHJcbiAgICBdLFxyXG4gICAgaXRlbXM6IFtdXHJcbn0pOyIsImltcG9ydCBTdGF0ZSBmcm9tICcuL3N0YXRlJztcclxuaW1wb3J0IFJvb20gZnJvbSAnLi9yb29tJztcclxuaW1wb3J0IFBsYXllciBmcm9tICcuL3BsYXllcic7XHJcbmltcG9ydCBPdXRwdXQgZnJvbSAnLi9vdXRwdXQnO1xyXG5pbXBvcnQgSW5wdXQgZnJvbSAnLi9pbnB1dCc7XHJcbmltcG9ydCBDb21tYW5kcyBmcm9tICcuL2NvbW1hbmRzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEdhbWUge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5wbGF5ZXIgPSBuZXcgUGxheWVyKCk7XHJcbiAgICAgICAgdGhpcy5zdGF0ZSA9IFN0YXRlO1xyXG4gICAgICAgIHRoaXMucm9vbXMgPSBbXTtcclxuICAgICAgICB0aGlzLml0ZW1zID0gW107XHJcbiAgICAgICAgdGhpcy5vdXRwdXQgPSBuZXcgT3V0cHV0KCk7XHJcbiAgICAgICAgdGhpcy5jb21tYW5kSGFuZGxlciA9IG5ldyBDb21tYW5kcyh0aGlzKTtcclxuICAgICAgICB0aGlzLmlucHV0ID0gbmV3IElucHV0KHRoaXMuY29tbWFuZEhhbmRsZXIpO1xyXG4gICAgICAgIHRoaXMudmlzaXRlZFJvb21zID0gbmV3IE1hcCgpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaW50KHN0cmluZykge1xyXG4gICAgICAgIHRoaXMub3V0cHV0LnNheShzdHJpbmcpO1xyXG4gICAgfVxyXG5cclxuICAgIGluaXQoZGF0YSkge1xyXG4gICAgICAgIHRoaXMucm9vbXMgPSBkYXRhLnJvb21zLm1hcCgocm9vbSkgPT4ge1xyXG4gICAgICAgICAgICByb29tLmNvbnRleHQgPSB0aGlzO1xyXG4gICAgICAgICAgICByZXR1cm4gcm9vbTtcclxuICAgICAgICB9KTtcclxuICAgICAgICB0aGlzLml0ZW1zID0gZGF0YS5pdGVtcy5tYXAoKGl0ZW0pID0+IHtcclxuICAgICAgICAgICAgaXRlbS5jb250ZXh0ID0gdGhpcztcclxuICAgICAgICAgICAgcmV0dXJuIGl0ZW07XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgdGhpcy5zdGF0ZSA9IGRhdGEuc3RhdGU7XHJcbiAgICAgICAgdGhpcy5jb21tYW5kSGFuZGxlci5hZGRDb21tYW5kcyhkYXRhLmNvbW1hbmRzKTtcclxuICAgICAgICB0aGlzLnBsYXllciA9IG5ldyBQbGF5ZXIoKTtcclxuICAgICAgICB0aGlzLm1vdmUodGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgfVxyXG5cclxuICAgIGV4YW1pbmVSb29tKCkge1xyXG4gICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLmdldFJvb20odGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIHRoaXMub3V0cHV0LnNheShyb29tLnRpdGxlKTtcclxuICAgICAgICBpZiAoIXRoaXMudmlzaXRlZFJvb21zLmdldCh0aGlzLnBsYXllci5jdXJyZW50Um9vbSkgJiYgcm9vbS5maXJzdERlc2NyaXB0aW9uICE9IFwiXCIpIHtcclxuICAgICAgICAgICAgdGhpcy5vdXRwdXQuc2F5KHJvb20uZmlyc3REZXNjcmlwdGlvbik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5vdXRwdXQuc2F5KHJvb20uZGVzY3JpcHRpb24pO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBnZXRSb29tKGlkKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMucm9vbXMuZmluZCgocm9vbSkgPT4gcm9vbS5pZCA9PSBpZCk7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0SXRlbShpZCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLml0ZW1zLmZpbmQoKGl0ZW0pID0+IGl0ZW0uaWQgPT0gaWQpO1xyXG4gICAgfVxyXG5cclxuICAgIHdhaXQobXMpIHtcclxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBtb3ZlKHJvb21JRCkge1xyXG4gICAgICAgIGNvbnN0IGN1cnJlbnRSb29tID0gdGhpcy5nZXRSb29tKHRoaXMucGxheWVyLmN1cnJlbnRSb29tKTtcclxuICAgICAgICBjb25zdCBuZXdSb29tID0gdGhpcy5nZXRSb29tKHJvb21JRCk7XHJcbiAgICAgICAgaWYgKGN1cnJlbnRSb29tLmNhbkV4aXQoKSAmJiBuZXdSb29tLmNhbkVudGVyKCkpIHtcclxuICAgICAgICAgICAgYXdhaXQgY3VycmVudFJvb20ub25FeGl0KCk7XHJcbiAgICAgICAgICAgIGF3YWl0IG5ld1Jvb20ub25FbnRlcigpO1xyXG4gICAgICAgICAgICB0aGlzLnBsYXllci5jdXJyZW50Um9vbSA9IHJvb21JRDtcclxuICAgICAgICAgICAgdGhpcy5leGFtaW5lUm9vbSgpO1xyXG4gICAgICAgICAgICB0aGlzLnZpc2l0ZWRSb29tcy5zZXQocm9vbUlELCB0cnVlKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBNZW93Q29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBZb3UgbWVvdy5gKTtcclxufSJdLCJuYW1lcyI6WyJjb25zdHJ1Y3RvciIsInRoaXMiLCJzdGF0ZXMiLCJNYXAiLCJnZXQiLCJrZXkiLCJzZXQiLCJ2YWx1ZSIsIlBsYXllciIsImludmVudG9yeSIsImN1cnJlbnRSb29tIiwiQmFzZU91dHB1dCIsInNwZWFrIiwidGV4dCIsInN0b3AiLCJzZXRPcHRpb25zIiwib3B0aW9ucyIsIkFyaWFPdXRwdXQiLCJzdXBlciIsInRpbWVvdXQiLCJpbml0IiwiY29udGFpbmVyIiwiZG9jdW1lbnQiLCJjcmVhdGVFbGVtZW50Iiwic2V0QXR0cmlidXRlIiwic3BlZWNoRGlzcGxheSIsImFwcGVuZCIsImJvZHkiLCJhcHBlbmRDaGlsZCIsImluc2VydEJlZm9yZSIsImZpcnN0Q2hpbGQiLCJjbGVhckRpc3BsYXkiLCJub2RlIiwiY3JlYXRlVGV4dE5vZGUiLCJwYXJhIiwic2V0VGltZW91dCIsImJpbmQiLCJpbm5lckhUTUwiLCJXZWJUVFNPdXRwdXQiLCJUVFMiLCJvdXRwdXQiLCJjcmVhdGVPdXRwdXQiLCJPdXRwdXQiLCJ0dHMiLCJoaXN0b3J5IiwiZ2V0RWxlbWVudEJ5SWQiLCJzYXkiLCJzdHJpbmciLCJJbnB1dCIsImNvbW1hbmRIYW5kbGVyIiwiaGFuZGxlciIsImlucHV0RmllbGQiLCJhZGRFdmVudExpc3RlbmVyIiwiZSIsIndoaWNoIiwidmFsIiwiZG9Db21tYW5kIiwiZGVmYXVsdENvbW1hbmRzIiwiYXJncyIsImNvbnRleHQiLCJleGFtaW5lUm9vbSIsIkNvbW1hbmRzIiwiY29tbWFuZHMiLCJhZGREZWZhdWx0Q29tbWFuZHMiLCJzdHIiLCJyb29tIiwiZ2V0Um9vbSIsInBsYXllciIsInNwbGl0IiwiZ2V0RXhpdCIsIm1vdmUiLCJhZGRDb21tYW5kIiwibmFtZSIsImZ1bmMiLCJBcnJheSIsImlzQXJyYXkiLCJmb3JFYWNoIiwiY29tbWFuZCIsImFkZENvbW1hbmRzIiwiUm9vbSIsImlkIiwidGl0bGUiLCJkZXNjcmlwdGlvbiIsImZpcnN0RGVzY3JpcHRpb24iLCJvYmplY3RzIiwiZXhpdHMiLCJlbnRlckNhbGxiYWNrIiwiZXhpdENhbGxiYWNrIiwiY2FuRW50ZXJMb2dpYyIsImNhbkV4aXRMb2dpYyIsInRpY2tDYWxsYmFjayIsImFzeW5jIiwiY2FuRW50ZXIiLCJjYW5FeGl0IiwiYWRkRXhpdCIsImRpcmVjdGlvbiIsInJvb21JRCIsImFkZEl0ZW0iLCJpdGVtIiwicHVzaCIsImFkZEVudGVyQ2FsbGJhY2siLCJjYWxsYmFjayIsImFkZEV4aXRDYWxsYmFjayIsImFkZEVudGVyTG9naWMiLCJhZGRFeGl0TG9naWMiLCJhZGRUaWNrQ2FsbGJhY2siLCJSb29tQnVpbGRlciIsIndpdGhJRCIsIklEIiwid2l0aFRpdGxlIiwid2l0aEZpcnN0RGVzY3JpcHRpb24iLCJ3aXRoRGVzY3JpcHRpb24iLCJ3aXRoRXhpdCIsIndpdGhJdGVtIiwiaXRlbUlEIiwid2l0aEVudGVyQ2FsbGJhY2siLCJ3aXRoRXhpdENhbGxiYWNrIiwid2l0aEVudGVyTG9naWMiLCJ3aXRoRXhpdExvZ2ljIiwid2l0aFRpY2siLCJjcmVhdGUiLCJ3YWl0Iiwic3RhdGUiLCJyb29tcyIsIml0ZW1zIiwiaW5wdXQiLCJ2aXNpdGVkUm9vbXMiLCJwcmludCIsImRhdGEiLCJtYXAiLCJmaW5kIiwiZ2V0SXRlbSIsIm1zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJuZXdSb29tIiwib25FeGl0Iiwib25FbnRlciJdLCJzb3VyY2VSb290IjoiIn0=
\ No newline at end of file
diff --git a/app_web/index.html b/app_web/index.html
new file mode 100644
index 0000000..88fc593
--- /dev/null
+++ b/app_web/index.html
@@ -0,0 +1 @@
+
Assassin bug
Assassin bug
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 5e2c506..8ac2208 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,9 +9,12 @@
"license": "ISC",
"dependencies": {
"copy-webpack-plugin": "^9.0.1",
+ "eventemitter3": "^4.0.7",
"html-webpack-plugin": "^5.5.0",
+ "terser-webpack-plugin": "^5.2.4",
"webpack": "^5.61.0",
- "webpack-dev-server": "^4.4.0"
+ "webpack-dev-server": "^4.4.0",
+ "yaml": "^1.10.2"
},
"devDependencies": {
"webpack-cli": "^4.9.1"
@@ -3655,6 +3658,14 @@
}
}
},
+ "node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -6374,6 +6385,11 @@
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
"requires": {}
},
+ "yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
+ },
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index 3e69299..2ec8713 100644
--- a/package.json
+++ b/package.json
@@ -16,9 +16,12 @@
"license": "ISC",
"dependencies": {
"copy-webpack-plugin": "^9.0.1",
+ "eventemitter3": "^4.0.7",
"html-webpack-plugin": "^5.5.0",
+ "terser-webpack-plugin": "^5.2.4",
"webpack": "^5.61.0",
- "webpack-dev-server": "^4.4.0"
+ "webpack-dev-server": "^4.4.0",
+ "yaml": "^1.10.2"
},
"devDependencies": {
"webpack-cli": "^4.9.1"
diff --git a/src/engine/builders/item.js b/src/engine/builders/item.js
new file mode 100644
index 0000000..7221606
--- /dev/null
+++ b/src/engine/builders/item.js
@@ -0,0 +1,46 @@
+import Item from '../item';
+
+export default class ItemBuilder {
+ constructor() {
+ this.item = new Item();
+ }
+
+ withID(ID) {
+ this.item.id = ID;
+ return this;
+ }
+
+ withName(name) {
+ this.item.name = name;
+ return this;
+ }
+
+ withDescription(description) {
+ this.item.description = description;
+ return this;
+ }
+
+ isUsable(value) {
+ this.item.usable = value;
+ return this;
+ }
+
+ isTakeable(value) {
+ this.item.takeable = value;
+ return this;
+ }
+
+ withUseCallback(callback) {
+ this.item.useCallback = callback;
+ return this;
+ }
+
+ withTakeCallback(callback) {
+ this.item.takeCallback = callback;
+ return this;
+ }
+
+ create() {
+ return this.item;
+ }
+}
\ No newline at end of file
diff --git a/src/engine/builders/room.js b/src/engine/builders/room.js
new file mode 100644
index 0000000..e7e4698
--- /dev/null
+++ b/src/engine/builders/room.js
@@ -0,0 +1,66 @@
+import Room from '../room';
+
+export default class RoomBuilder {
+ constructor() {
+ this.room = new Room();
+ }
+
+ withID(ID) {
+ this.room.id = ID;
+ return this;
+ }
+
+ withTitle(title) {
+ this.room.title = title;
+ return this;
+ }
+
+ withFirstDescription(description) {
+ this.room.firstDescription = description;
+ return this;
+ }
+
+ withDescription(description) {
+ this.room.description = description;
+ return this;
+ }
+
+ withExit(direction, roomID) {
+ this.room.addExit(direction, roomID);
+ return this;
+ }
+
+ withItem(itemID) {
+ this.room.addItem(itemID);
+ return this;
+ }
+
+ withEnterCallback(callback) {
+ this.room.addEnterCallback(callback);
+ return this;
+ }
+
+ withExitCallback(callback) {
+ this.room.addExitCallback(callback);
+ return this;
+ }
+
+ withEnterLogic(func) {
+ this.room.addEnterLogic(func);
+ return this;
+ }
+
+ withExitLogic(func) {
+ this.room.addExitLogic(func);
+ return this;
+ }
+
+ withTick(func) {
+ this.room.addTickCallback(func);
+ return this;
+ }
+
+ create() {
+ return this.room;
+ }
+}
\ No newline at end of file
diff --git a/src/engine/commands.js b/src/engine/commands.js
new file mode 100644
index 0000000..0f23e32
--- /dev/null
+++ b/src/engine/commands.js
@@ -0,0 +1,43 @@
+import LookCommand from "./commands/look";
+import UseCommand from "./commands/use";
+const defaultCommands = [
+ [["look", "l"], LookCommand],
+ [["use", "interact"], UseCommand]
+];
+
+export default class Commands {
+ constructor(context, commands) {
+ this.context = context;
+ this.commands = commands || new Map();
+ this.addDefaultCommands();
+ }
+
+ doCommand(str) {
+ const room = this.context.getRoom(this.context.player.currentRoom);
+ const split = str.split(" ");
+ if (this.commands.get(split[0])) {
+ this.commands.get(split[0])(split, this.context);
+ }
+ if (room.getExit(split[0])) {
+ this.context.move(room.getExit(split[0]));
+ }
+ }
+
+ addCommand(name, func) {
+ if (Array.isArray(name)) {
+ name.forEach((command) => this.commands.set(command, func));
+ } else {
+ this.commands.set(name, func);
+ }
+ }
+
+ addCommands(commands) {
+ commands.forEach((command) => {
+ this.addCommand(command[0], command[1]);
+ });
+ }
+
+ addDefaultCommands() {
+ this.addCommands(defaultCommands);
+ }
+}
\ No newline at end of file
diff --git a/src/engine/commands/look.js b/src/engine/commands/look.js
new file mode 100644
index 0000000..9c0a0bc
--- /dev/null
+++ b/src/engine/commands/look.js
@@ -0,0 +1,21 @@
+export default function LookCommand(args, context) {
+ if (args.length == 0) {
+ context.examineRoom();
+ } else {
+ const room = context.getRoom(context.player.currentRoom);
+ const items = room.getItems();
+ let item = null;
+ for (let i of items) {
+ if (i.name.includes(args[1])) {
+ item = i;
+ break;
+ }
+ }
+ if (!item) {
+ context.output.say(`I could not find a ${args[1]}`);
+ } else {
+ context.output.say(item.name);
+ context.output.say(item.description);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/engine/commands/take.js b/src/engine/commands/take.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/engine/commands/use.js b/src/engine/commands/use.js
new file mode 100644
index 0000000..ff6d0b1
--- /dev/null
+++ b/src/engine/commands/use.js
@@ -0,0 +1,16 @@
+export default async function UseCommand(args, context) {
+ const room = context.getRoom(context.player.currentRoom);
+ const items = room.getItems();
+ let item = null;
+ for (let i of items) {
+ if (i.name.includes(args[1])) {
+ item = i;
+ break;
+ }
+ }
+ if (!item) {
+ context.output.say(`I could not find a ${args[1]}`);
+ } else {
+ await item.onUse();
+ }
+}
\ No newline at end of file
diff --git a/src/engine/index.js b/src/engine/index.js
new file mode 100644
index 0000000..b8d28f5
--- /dev/null
+++ b/src/engine/index.js
@@ -0,0 +1,92 @@
+import State from './state';
+import Room from './room';
+import Player from './player';
+import Output from './output';
+import Input from './input';
+import Commands from './commands';
+
+export default class Game {
+ constructor() {
+ this.player = new Player();
+ this.state = State;
+ this.rooms = [];
+ this.items = [];
+ this.output = new Output();
+ this.commandHandler = new Commands(this);
+ this.input = new Input(this.commandHandler);
+ this.visitedRooms = new Map();
+ }
+
+ print(string) {
+ this.output.say(string);
+ }
+
+ init(data) {
+ console.log(data);
+ this.rooms = data.rooms.map((room) => {
+ room.context = this;
+ return room;
+ });
+ this.items = data.items.map((item) => {
+ item.context = this;
+ return item;
+ });
+ this.state = data.state;
+ this.commandHandler.addCommands(data.commands);
+ this.player = new Player();
+ this.move(this.player.currentRoom);
+ }
+
+ examineRoom() {
+ const room = this.getRoom(this.player.currentRoom);
+ this.output.say(room.title);
+ if (!this.visitedRooms.get(this.player.currentRoom) && room.firstDescription != "") {
+ this.output.say(room.firstDescription);
+ } else {
+ this.output.say(room.description);
+ }
+ this.examineItems();
+ this.examineExits();
+ }
+
+ examineItems() {
+ const room = this.getRoom(this.player.currentRoom);
+ const items = room.getItems();
+ items.forEach((item) => this.output.say(item.name));
+ }
+
+ examineExits() {
+ const room = this.getRoom(this.player.currentRoom);
+ let exitDescription = "You can go ";
+ for (let exit of room.exits.keys()) {
+ exitDescription += " " + exit;
+ }
+ this.output.say(exitDescription);
+ }
+
+ getRoom(id) {
+ return this.rooms.find((room) => room.id == id);
+ }
+
+ getItem(id) {
+ return this.items.find((item) => item.id == id);
+ }
+
+ wait(ms) {
+ return new Promise((resolve, reject) => {
+ setTimeout(resolve, ms);
+ });
+ }
+
+ async move(roomID) {
+ const currentRoom = this.getRoom(this.player.currentRoom);
+ const newRoom = this.getRoom(roomID);
+ if (currentRoom.canExit() && newRoom.canEnter()) {
+ await currentRoom.onExit();
+ await newRoom.onEnter();
+ this.player.currentRoom = roomID;
+ this.examineRoom();
+ this.visitedRooms.set(roomID, true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/engine/input.js b/src/engine/input.js
new file mode 100644
index 0000000..b17f7b0
--- /dev/null
+++ b/src/engine/input.js
@@ -0,0 +1,17 @@
+export default class Input {
+ constructor(commandHandler) {
+ this.handler = commandHandler;
+ this.inputField = document.getElementById("input-area");
+ this.init();
+ }
+
+ init() {
+ this.inputField.addEventListener("keydown", (e) => {
+ if (e.which == 13) {
+ const val = this.inputField.value;
+ this.inputField.value = "";
+ this.handler.doCommand(val);
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/src/engine/item.js b/src/engine/item.js
new file mode 100644
index 0000000..59ccc98
--- /dev/null
+++ b/src/engine/item.js
@@ -0,0 +1,20 @@
+export default class Item {
+ constructor() {
+ this.id = "item";
+ this.name = "An item";
+ this.description = "You see nothing special about this item";
+ this.usable = true;
+ this.takeable = true;
+ this.useCallback = null;
+ this.takeCallback = null;
+ this.context = null;
+ }
+
+ async onUse() {
+ if (this.useCallback) return this.useCallback(this.context);
+ }
+
+ async onTake() {
+ if (this.takeCallback) return this.takeCallback();
+ }
+}
\ No newline at end of file
diff --git a/src/engine/output.js b/src/engine/output.js
new file mode 100644
index 0000000..e9c1ee1
--- /dev/null
+++ b/src/engine/output.js
@@ -0,0 +1,16 @@
+import { TTS } from '../framework/tts';
+import { AriaOutput } from '../framework/tts/outputs/aria';
+
+export default class Output {
+ constructor() {
+ this.tts = new TTS(new AriaOutput());
+ this.history = document.getElementById("output-area");
+ }
+
+ say(string) {
+ const node = document.createElement("p");
+ node.appendChild(document.createTextNode(string));
+ this.history.appendChild(node);
+ // this.tts.speak(string);
+ }
+}
\ No newline at end of file
diff --git a/src/engine/player.js b/src/engine/player.js
new file mode 100644
index 0000000..c4d3485
--- /dev/null
+++ b/src/engine/player.js
@@ -0,0 +1,6 @@
+export default class Player {
+ constructor() {
+ this.inventory = [];
+ this.currentRoom = "start";
+ }
+}
\ No newline at end of file
diff --git a/src/engine/room.js b/src/engine/room.js
new file mode 100644
index 0000000..100e0d2
--- /dev/null
+++ b/src/engine/room.js
@@ -0,0 +1,75 @@
+export default class Room {
+ constructor() {
+ this.id = "room";
+ this.title = "A room";
+ this.description = "You see nothing special";
+ this.firstDescription = "As you walk into the room, you notice nothing special";
+ this.objects = [];
+ this.exits = new Map();
+ this.enterCallback = null;
+ this.exitCallback = null;
+ this.canEnterLogic = null;
+ this.canExitLogic = null;
+ this.tickCallback = null;
+ this.context = null;
+ }
+
+ async onEnter() {
+ if (this.enterCallback) return this.enterCallback(this.context);
+ }
+
+ async onExit() {
+ if (this.exitCallback) return this.exitCallback(this.context);
+ }
+
+ canEnter() {
+ if (this.canEnterLogic) {
+ return this.canEnterLogic(this.context);
+ }
+ return true;
+ }
+
+ canExit() {
+ if (this.canExitLogic) {
+ return this.canExitLogic(this.context);
+ }
+ return true;
+ }
+
+ addExit(direction, roomID) {
+ this.exits.set(direction, roomID);
+ return this;
+ }
+
+ getExit(direction) {
+ return this.exits.get(direction);
+ }
+
+ addItem(item) {
+ this.objects.push(item);
+ }
+
+ addEnterCallback(callback) {
+ this.enterCallback = callback;
+ }
+
+ addExitCallback(callback) {
+ this.exitCallback = callback;
+ }
+
+ addEnterLogic(func) {
+ this.canEnterLogic = func;
+ }
+
+ addExitLogic(func) {
+ this.canExitLogic = func;
+ }
+
+ addTickCallback(callback) {
+ this.tickCallback = callback;
+ }
+
+ getItems() {
+ return this.objects.map((item) => this.context.getItem(item));
+ }
+}
\ No newline at end of file
diff --git a/src/engine/state.js b/src/engine/state.js
new file mode 100644
index 0000000..ad89a66
--- /dev/null
+++ b/src/engine/state.js
@@ -0,0 +1,15 @@
+class State {
+ constructor() {
+ this.states = new Map();
+ }
+
+ get(key) {
+ return this.states.get(key);
+ }
+
+ set(key, value) {
+ return this.states.set(key, value);
+ }
+}
+
+export default new State();
\ No newline at end of file
diff --git a/src/framework/asset-manager/downloader.d.ts b/src/framework/asset-manager/downloader.d.ts
new file mode 100644
index 0000000..e29dacb
--- /dev/null
+++ b/src/framework/asset-manager/downloader.d.ts
@@ -0,0 +1,12 @@
+import EventEmitter from 'eventemitter3';
+import { Queue } from './queue';
+import { AssetStorage } from './storage';
+export declare class Downloader extends EventEmitter {
+ private storage;
+ private queue;
+ private basePath;
+ constructor(storage: AssetStorage, queue: Queue, basePath?: string);
+ setBasePath(path: string): void;
+ download(): Promise;
+ downloadItem(path: string): Promise;
+}
diff --git a/src/framework/asset-manager/downloader.js b/src/framework/asset-manager/downloader.js
new file mode 100644
index 0000000..735fc35
--- /dev/null
+++ b/src/framework/asset-manager/downloader.js
@@ -0,0 +1,50 @@
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+import EventEmitter from 'eventemitter3';
+import { buildPath } from './utils';
+export class Downloader extends EventEmitter {
+ constructor(storage, queue, basePath = '') {
+ super();
+ this.storage = storage;
+ this.queue = queue;
+ this.basePath = basePath;
+ }
+ setBasePath(path) {
+ this.basePath = this.basePath;
+ }
+ download() {
+ return __awaiter(this, void 0, void 0, function* () {
+ const downloaded = new Map();
+ let numDownloaded = 0;
+ while (this.queue.length() > 0) {
+ const path = this.queue.pop();
+ const item = yield this.downloadItem(buildPath(this.basePath, path));
+ downloaded.set(path, item);
+ numDownloaded++;
+ this.emit('download.progress', {
+ downloaded: numDownloaded,
+ remaining: this.queue.length()
+ });
+ }
+ return downloaded;
+ });
+ }
+ downloadItem(path) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const inCache = yield this.storage.get(path);
+ if (inCache) {
+ return inCache;
+ }
+ const response = yield fetch(path);
+ this.storage.add(path, response);
+ return response;
+ });
+ }
+}
diff --git a/src/framework/asset-manager/index.d.ts b/src/framework/asset-manager/index.d.ts
new file mode 100644
index 0000000..a5207df
--- /dev/null
+++ b/src/framework/asset-manager/index.d.ts
@@ -0,0 +1,18 @@
+import EventEmitter from 'eventemitter3';
+export declare class AssetManager extends EventEmitter {
+ private name;
+ private basePath;
+ private downloader;
+ private queue;
+ private storage;
+ private manifest;
+ constructor(name: string, basePath: string);
+ init(): Promise;
+ setManifest(path: string): Promise;
+ enqueue(path: string): void;
+ download(): Promise;
+ downloadFromManifest(key: string): Promise;
+ downloadFile(path: string): Promise;
+ setBasePath(path: string): void;
+ clearCache(): void;
+}
diff --git a/src/framework/asset-manager/index.js b/src/framework/asset-manager/index.js
new file mode 100644
index 0000000..2428bea
--- /dev/null
+++ b/src/framework/asset-manager/index.js
@@ -0,0 +1,71 @@
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+import { Downloader } from './downloader';
+import { Queue } from './queue';
+import { Manifest } from './manifest';
+import { AssetStorage } from './storage';
+import EventEmitter from 'eventemitter3';
+import { buildPath } from './utils';
+export class AssetManager extends EventEmitter {
+ constructor(name, basePath) {
+ super();
+ this.name = name;
+ this.basePath = basePath;
+ this.queue = new Queue();
+ this.storage = new AssetStorage(name);
+ this.downloader = new Downloader(this.storage, this.queue, this.basePath);
+ console.log(`Asset manager initialized`);
+ }
+ init() {
+ return __awaiter(this, void 0, void 0, function* () {
+ yield this.storage.init();
+ return true;
+ });
+ }
+ setManifest(path) {
+ return __awaiter(this, void 0, void 0, function* () {
+ this.manifest = yield Manifest(`${this.basePath}/${path}`);
+ this.storage.setManifest(this.manifest);
+ return this.manifest;
+ });
+ }
+ enqueue(path) {
+ this.queue.add(path);
+ }
+ download() {
+ return __awaiter(this, void 0, void 0, function* () {
+ const result = yield this.downloader.download();
+ return result;
+ });
+ }
+ downloadFromManifest(key) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const paths = this.manifest[key];
+ paths.forEach((path) => this.enqueue(path));
+ this.downloader.on('download.progress', (info) => this.emit('progress', info));
+ const files = yield this.downloader.download();
+ this.downloader.off('download.progress');
+ return files;
+ });
+ }
+ downloadFile(path) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const result = yield this.downloader.downloadItem(buildPath(this.basePath, path));
+ return result;
+ });
+ }
+ setBasePath(path) {
+ this.basePath = this.basePath;
+ this.downloader.setBasePath(this.basePath);
+ }
+ clearCache() {
+ this.storage.clear();
+ }
+}
diff --git a/src/framework/asset-manager/manifest.d.ts b/src/framework/asset-manager/manifest.d.ts
new file mode 100644
index 0000000..f4a36bf
--- /dev/null
+++ b/src/framework/asset-manager/manifest.d.ts
@@ -0,0 +1,2 @@
+export declare function Manifest(manifestPath: string): Promise;
+export declare function CheckManifest(manifest: any): boolean;
diff --git a/src/framework/asset-manager/manifest.js b/src/framework/asset-manager/manifest.js
new file mode 100644
index 0000000..d8c3f61
--- /dev/null
+++ b/src/framework/asset-manager/manifest.js
@@ -0,0 +1,40 @@
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+import * as yaml from 'yaml';
+export function Manifest(manifestPath) {
+ return __awaiter(this, void 0, void 0, function* () {
+ try {
+ const response = yield fetch(manifestPath);
+ console.log(response);
+ const data = yield response.text();
+ console.log(`Parsing: `, data);
+ const manifest = yaml.parse(data);
+ return manifest;
+ }
+ catch (error) {
+ alert(`Error occured: ${error.toString()}`);
+ }
+ });
+}
+export function CheckManifest(manifest) {
+ const prevManifestStr = localStorage.getItem('manifest');
+ if (!prevManifestStr) {
+ localStorage.setItem('manifest', JSON.stringify(manifest));
+ return false;
+ }
+ const prevManifest = JSON.parse(prevManifestStr);
+ if (prevManifest.version === manifest.version) {
+ return true;
+ }
+ else {
+ localStorage.setItem('manifest', manifest);
+ return false;
+ }
+}
diff --git a/src/framework/asset-manager/queue.d.ts b/src/framework/asset-manager/queue.d.ts
new file mode 100644
index 0000000..c3c0026
--- /dev/null
+++ b/src/framework/asset-manager/queue.d.ts
@@ -0,0 +1,8 @@
+export declare class Queue {
+ private items;
+ constructor();
+ add(file: string): string[];
+ remove(file: string): string[];
+ pop(): string;
+ length(): number;
+}
diff --git a/src/framework/asset-manager/queue.js b/src/framework/asset-manager/queue.js
new file mode 100644
index 0000000..05380a3
--- /dev/null
+++ b/src/framework/asset-manager/queue.js
@@ -0,0 +1,19 @@
+export class Queue {
+ constructor() {
+ this.items = [];
+ }
+ add(file) {
+ this.items.push(file);
+ return this.items;
+ }
+ remove(file) {
+ this.items = this.items.filter((item) => item !== file);
+ return this.items;
+ }
+ pop() {
+ return this.items.pop();
+ }
+ length() {
+ return this.items.length;
+ }
+}
diff --git a/src/framework/asset-manager/storage.d.ts b/src/framework/asset-manager/storage.d.ts
new file mode 100644
index 0000000..36a491f
--- /dev/null
+++ b/src/framework/asset-manager/storage.d.ts
@@ -0,0 +1,11 @@
+export declare class AssetStorage {
+ private id;
+ private cache;
+ private manifest;
+ constructor(id: string);
+ init(): Promise;
+ add(request: RequestInfo, response: Response): Promise;
+ get(request: RequestInfo): Promise;
+ setManifest(manifest: any): Promise;
+ clear(): Promise;
+}
diff --git a/src/framework/asset-manager/storage.js b/src/framework/asset-manager/storage.js
new file mode 100644
index 0000000..48b2ebd
--- /dev/null
+++ b/src/framework/asset-manager/storage.js
@@ -0,0 +1,48 @@
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+import { CheckManifest } from './manifest';
+export class AssetStorage {
+ constructor(id) {
+ this.id = id;
+ }
+ init() {
+ return __awaiter(this, void 0, void 0, function* () {
+ this.cache = yield caches.open(this.id);
+ });
+ }
+ add(request, response) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const result = yield this.cache.put(request, response);
+ return true;
+ });
+ }
+ get(request) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const result = yield this.cache.match(request);
+ return result;
+ });
+ }
+ setManifest(manifest) {
+ return __awaiter(this, void 0, void 0, function* () {
+ this.manifest = manifest;
+ if (!CheckManifest(this.manifest)) {
+ yield this.clear();
+ }
+ });
+ }
+ clear() {
+ return __awaiter(this, void 0, void 0, function* () {
+ const keys = yield this.cache.keys();
+ keys.forEach((key) => __awaiter(this, void 0, void 0, function* () {
+ const result = yield this.cache.delete(key);
+ }));
+ });
+ }
+}
diff --git a/src/framework/asset-manager/test/index.d.ts b/src/framework/asset-manager/test/index.d.ts
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/src/framework/asset-manager/test/index.d.ts
@@ -0,0 +1 @@
+export {};
diff --git a/src/framework/asset-manager/test/index.js b/src/framework/asset-manager/test/index.js
new file mode 100644
index 0000000..92d3bd5
--- /dev/null
+++ b/src/framework/asset-manager/test/index.js
@@ -0,0 +1,5 @@
+const yaml = require('yaml');
+const fs = require('fs');
+const data = fs.readFileSync('manifest.yaml');
+const parsed = yaml.parse(data.toString());
+console.log(parsed);
diff --git a/src/framework/asset-manager/utils.d.ts b/src/framework/asset-manager/utils.d.ts
new file mode 100644
index 0000000..c8f1ef4
--- /dev/null
+++ b/src/framework/asset-manager/utils.d.ts
@@ -0,0 +1 @@
+export declare function buildPath(basePath: string, path: string): string;
diff --git a/src/framework/asset-manager/utils.js b/src/framework/asset-manager/utils.js
new file mode 100644
index 0000000..12e628a
--- /dev/null
+++ b/src/framework/asset-manager/utils.js
@@ -0,0 +1,8 @@
+export function buildPath(basePath, path) {
+ if (!basePath) {
+ return path;
+ }
+ else {
+ return `${basePath}/${path}`;
+ }
+}
diff --git a/src/framework/ecs/component.d.ts b/src/framework/ecs/component.d.ts
new file mode 100644
index 0000000..6617706
--- /dev/null
+++ b/src/framework/ecs/component.d.ts
@@ -0,0 +1,12 @@
+export declare class BaseComponent {
+ id: number;
+ properties: any;
+ constructor();
+ clone(): BaseComponent;
+}
+export interface Component {
+ id: number;
+ properties: any;
+ clone(): BaseComponent;
+ new (): BaseComponent;
+}
diff --git a/src/framework/ecs/component.js b/src/framework/ecs/component.js
new file mode 100644
index 0000000..a9ea06b
--- /dev/null
+++ b/src/framework/ecs/component.js
@@ -0,0 +1,11 @@
+export class BaseComponent {
+ constructor() {
+ this.id = 0;
+ this.properties = {};
+ }
+ clone() {
+ const comp = new BaseComponent();
+ comp.properties = this.properties;
+ return comp;
+ }
+}
diff --git a/src/framework/ecs/entity.d.ts b/src/framework/ecs/entity.d.ts
new file mode 100644
index 0000000..800738c
--- /dev/null
+++ b/src/framework/ecs/entity.d.ts
@@ -0,0 +1,19 @@
+import { BaseComponent, Component } from './component';
+export declare class BaseEntity {
+ id: number;
+ components: Map;
+ constructor();
+ addComponent(component: Component): void;
+ removeComponent(component: BaseComponent): void;
+ getComponentIDs(): number[];
+ getComponent(component: BaseComponent): BaseComponent;
+ getComponentByID(id: number): BaseComponent;
+}
+export interface Entity {
+ new (): BaseComponent;
+ addComponent(component: Component): any;
+ removeComponent(component: BaseComponent): any;
+ getComponentIDs(): number[];
+ getComponent(component: BaseComponent): any;
+ getComponentByID(id: number): BaseComponent;
+}
diff --git a/src/framework/ecs/entity.js b/src/framework/ecs/entity.js
new file mode 100644
index 0000000..2732635
--- /dev/null
+++ b/src/framework/ecs/entity.js
@@ -0,0 +1,23 @@
+export class BaseEntity {
+ constructor() {
+ this.components = new Map();
+ this.id = 0;
+ }
+ addComponent(component) {
+ let comp = new component();
+ comp.id = component.id;
+ this.components.set(component.id, comp);
+ }
+ removeComponent(component) {
+ this.components.delete(component.id);
+ }
+ getComponentIDs() {
+ return [...this.components.keys()];
+ }
+ getComponent(component) {
+ return this.components.get(component.id);
+ }
+ getComponentByID(id) {
+ return this.components.get(id);
+ }
+}
diff --git a/src/framework/ecs/index.d.ts b/src/framework/ecs/index.d.ts
new file mode 100644
index 0000000..7a8314e
--- /dev/null
+++ b/src/framework/ecs/index.d.ts
@@ -0,0 +1,28 @@
+import { Component } from './component';
+import { BaseEntity, Entity } from './entity';
+import { EventBus } from '../event-bus';
+import { Query } from './query';
+import { System } from './system';
+export declare class World {
+ entities: Array;
+ components: Map;
+ componentNamesToIDs: Map;
+ systems: Set;
+ nextEntityID: number;
+ nextComponentID: number;
+ nextQueryID: number;
+ queryCache: Array;
+ eventBus: EventBus;
+ constructor();
+ run(): void;
+ createSystem(systemExecutor: Function): void;
+ addSystem(system: System): void;
+ addEntity(entity: BaseEntity): void;
+ removeEntity(entityToRemove: BaseEntity): void;
+ createEntity(components: Array): BaseEntity;
+ extendEntity(entity: Entity, components: Array): BaseEntity;
+ createComponent(component: Component): Component;
+ query(include: Array, exclude: Array): Array;
+ createQuery(include: Array, exclude: Array): Query;
+ markQueriesDirty(): void;
+}
diff --git a/src/framework/ecs/index.js b/src/framework/ecs/index.js
new file mode 100644
index 0000000..7a7ef26
--- /dev/null
+++ b/src/framework/ecs/index.js
@@ -0,0 +1,105 @@
+import { BaseEntity } from './entity';
+import { EventBus } from '../event-bus';
+import { Query } from './query';
+import { System } from './system';
+export class World {
+ constructor() {
+ this.nextEntityID = 0;
+ this.nextComponentID = 0;
+ this.nextQueryID = 0;
+ this.entities = new Array();
+ this.systems = new Set();
+ this.components = new Map();
+ this.componentNamesToIDs = new Map();
+ this.queryCache = new Array();
+ this.eventBus = new EventBus();
+ }
+ run() {
+ this.systems.forEach((system) => {
+ system.execute(this);
+ });
+ }
+ createSystem(systemExecutor) {
+ const newSystem = new System(systemExecutor);
+ this.systems.add(newSystem);
+ }
+ addSystem(system) {
+ this.systems.add(system);
+ }
+ addEntity(entity) {
+ this.entities.push(entity);
+ this.markQueriesDirty();
+ }
+ removeEntity(entityToRemove) {
+ this.entities = this.entities.filter((entity) => entity !== entityToRemove);
+ this.markQueriesDirty();
+ }
+ createEntity(components) {
+ const newEntity = new BaseEntity();
+ newEntity.id = this.nextEntityID;
+ this.nextEntityID++;
+ components.forEach((component) => {
+ if (this.componentNamesToIDs.has(component.name)) {
+ component.id = this.componentNamesToIDs.get(component.name);
+ }
+ else {
+ this.componentNamesToIDs.set(component.name, this.nextComponentID);
+ component.id = this.nextComponentID;
+ this.nextComponentID++;
+ }
+ newEntity.addComponent(component);
+ });
+ this.entities.push(newEntity);
+ this.markQueriesDirty();
+ return newEntity;
+ }
+ extendEntity(entity, components) {
+ const toClone = this.entities.find((found) => entity.name === found.constructor.name);
+ const cloned = new BaseEntity();
+ cloned.id = this.nextEntityID;
+ this.nextEntityID++;
+ toClone.components.forEach((component) => {
+ cloned.addComponent(this.components.get(component.id));
+ });
+ components.forEach((component) => {
+ if (this.componentNamesToIDs.has(component.name)) {
+ component.id = this.componentNamesToIDs.get(component.name);
+ }
+ else {
+ this.componentNamesToIDs.set(component.name, this.nextComponentID);
+ component.id = this.nextComponentID;
+ this.nextComponentID++;
+ }
+ cloned.addComponent(component);
+ });
+ this.entities.push(cloned);
+ return cloned;
+ }
+ createComponent(component) {
+ const newComponent = component;
+ newComponent.id = this.nextComponentID;
+ this.nextComponentID++;
+ this.components.set(newComponent.id, newComponent);
+ this.componentNamesToIDs.set(component.name, component.id);
+ return newComponent;
+ }
+ query(include, exclude) {
+ const query = new Query(include, exclude, this);
+ const cache = this.queryCache.find((item) => item.include == include && item.exclude == exclude);
+ if (cache) {
+ return cache.execute();
+ }
+ this.queryCache.push(query);
+ return query.execute();
+ }
+ createQuery(include, exclude) {
+ const newQuery = new Query(include, exclude, this);
+ newQuery.id = this.nextQueryID;
+ this.nextQueryID++;
+ this.queryCache.push(newQuery);
+ return newQuery;
+ }
+ markQueriesDirty() {
+ this.queryCache.forEach((query) => (query.isDirty = true));
+ }
+}
diff --git a/src/framework/ecs/query.d.ts b/src/framework/ecs/query.d.ts
new file mode 100644
index 0000000..37c4901
--- /dev/null
+++ b/src/framework/ecs/query.d.ts
@@ -0,0 +1,15 @@
+import { World } from '.';
+import { Component } from './component';
+import { BaseEntity } from './entity';
+export declare class Query {
+ include: Array;
+ exclude: Array;
+ world: World;
+ id: number;
+ private results;
+ isDirty: boolean;
+ includeComponentIds: number[];
+ excludeComponentIds: number[];
+ constructor(include: Array, exclude: Array, world: World);
+ execute(): Array;
+}
diff --git a/src/framework/ecs/query.js b/src/framework/ecs/query.js
new file mode 100644
index 0000000..1ae868f
--- /dev/null
+++ b/src/framework/ecs/query.js
@@ -0,0 +1,34 @@
+export class Query {
+ constructor(include, exclude, world) {
+ this.include = include;
+ this.exclude = exclude;
+ this.world = world;
+ this.isDirty = true;
+ this.results = new Array();
+ this.includeComponentIds = include.map((component) => component.id);
+ this.excludeComponentIds = exclude.map((component) => component.id);
+ this.id = 0;
+ }
+ execute() {
+ if (!this.isDirty && this.results) {
+ return this.results;
+ }
+ let filtered;
+ this.includeComponentIds = this.include.map((component) => this.world.componentNamesToIDs.get(component.name));
+ this.excludeComponentIds = this.exclude.map((component) => this.world.componentNamesToIDs.get(component.name));
+ const entities = this.world.entities.filter((entity) => {
+ let ids = entity.getComponentIDs();
+ // let includes = ids.map(id => this.includeComponentIds.includes(id)).includes(true);
+ let excludes = ids
+ .map((id) => this.excludeComponentIds.includes(id))
+ .includes(true);
+ let includes = ids.filter((id) => this.includeComponentIds.includes(id));
+ return includes.length === this.includeComponentIds.length && !excludes;
+ });
+ if (entities.length > 0) {
+ this.isDirty = false;
+ this.results = entities;
+ }
+ return entities;
+ }
+}
diff --git a/src/framework/ecs/system.d.ts b/src/framework/ecs/system.d.ts
new file mode 100644
index 0000000..65af5de
--- /dev/null
+++ b/src/framework/ecs/system.d.ts
@@ -0,0 +1,6 @@
+import { World } from '.';
+export declare class System {
+ executor: Function;
+ constructor(executor: Function);
+ execute(world: World): void;
+}
diff --git a/src/framework/ecs/system.js b/src/framework/ecs/system.js
new file mode 100644
index 0000000..dbccaa4
--- /dev/null
+++ b/src/framework/ecs/system.js
@@ -0,0 +1,10 @@
+export class System {
+ constructor(executor) {
+ this.executor = executor;
+ }
+ execute(world) {
+ if (this.executor) {
+ this.executor(world);
+ }
+ }
+}
diff --git a/src/framework/engine.js b/src/framework/engine.js
new file mode 100644
index 0000000..5a7acad
--- /dev/null
+++ b/src/framework/engine.js
@@ -0,0 +1,2 @@
+var Engine;(()=>{"use strict";var t={729:t=>{var e=Object.prototype.hasOwnProperty,s="~";function i(){}function n(t,e,s){this.fn=t,this.context=e,this.once=s||!1}function h(t,e,i,h,a){if("function"!=typeof i)throw new TypeError("The listener must be a function");var u=new n(i,h||t,a),r=s?s+e:e;return t._events[r]?t._events[r].fn?t._events[r]=[t._events[r],u]:t._events[r].push(u):(t._events[r]=u,t._eventsCount++),t}function a(t,e){0==--t._eventsCount?t._events=new i:delete t._events[e]}function u(){this._events=new i,this._eventsCount=0}Object.create&&(i.prototype=Object.create(null),(new i).__proto__||(s=!1)),u.prototype.eventNames=function(){var t,i,n=[];if(0===this._eventsCount)return n;for(i in t=this._events)e.call(t,i)&&n.push(s?i.slice(1):i);return Object.getOwnPropertySymbols?n.concat(Object.getOwnPropertySymbols(t)):n},u.prototype.listeners=function(t){var e=s?s+t:t,i=this._events[e];if(!i)return[];if(i.fn)return[i.fn];for(var n=0,h=i.length,a=new Array(h);n{var e=t&&t.__esModule?()=>t.default:()=>t;return s.d(e,{a:e}),e},s.d=(t,e)=>{for(var i in e)s.o(e,i)&&!s.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},s.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),s.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var i={};(()=>{s.r(i),s.d(i,{AssetManager:()=>v,BaseItem:()=>T,CheckboxItem:()=>R,EditItem:()=>B,EventBus:()=>m,EventItem:()=>p,Input:()=>I,Menu:()=>Q,MenuItem:()=>$,SelectorItem:()=>V,SliderItem:()=>U,TTS:()=>F,World:()=>f});var t=s(729),e=s.n(t);function n(t,e){return t?`${t}/${e}`:e}var h=function(t,e,s,i){return new(s||(s=Promise))((function(n,h){function a(t){try{r(i.next(t))}catch(t){h(t)}}function u(t){try{r(i.throw(t))}catch(t){h(t)}}function r(t){var e;t.done?n(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(a,u)}r((i=i.apply(t,e||[])).next())}))};class a extends(e()){constructor(t,e,s=""){super(),this.storage=t,this.queue=e,this.basePath=s}setBasePath(t){this.basePath=this.basePath}download(){return h(this,void 0,void 0,(function*(){const t=new Map;let e=0;for(;this.queue.length()>0;){const s=this.queue.pop(),i=yield this.downloadItem(n(this.basePath,s));t.set(s,i),e++,this.emit("download.progress",{downloaded:e,remaining:this.queue.length()})}return t}))}downloadItem(t){return h(this,void 0,void 0,(function*(){const e=yield this.storage.get(t);if(e)return e;const s=yield fetch(t);return this.storage.add(t,s),s}))}}class u{constructor(){this.items=[]}add(t){return this.items.push(t),this.items}remove(t){return this.items=this.items.filter((e=>e!==t)),this.items}pop(){return this.items.pop()}length(){return this.items.length}}var r=function(t,e,s,i){return new(s||(s=Promise))((function(n,h){function a(t){try{r(i.next(t))}catch(t){h(t)}}function u(t){try{r(i.throw(t))}catch(t){h(t)}}function r(t){var e;t.done?n(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(a,u)}r((i=i.apply(t,e||[])).next())}))};class l{constructor(t){this.id=t}init(){return r(this,void 0,void 0,(function*(){this.cache=yield caches.open(this.id)}))}add(t,e){return r(this,void 0,void 0,(function*(){return yield this.cache.put(t,e),!0}))}get(t){return r(this,void 0,void 0,(function*(){return yield this.cache.match(t)}))}setManifest(t){return r(this,void 0,void 0,(function*(){this.manifest=t,function(t){const e=localStorage.getItem("manifest");return e?JSON.parse(e).version===t.version||(localStorage.setItem("manifest",t),!1):(localStorage.setItem("manifest",JSON.stringify(t)),!1)}(this.manifest)||(yield this.clear())}))}clear(){return r(this,void 0,void 0,(function*(){(yield this.cache.keys()).forEach((t=>r(this,void 0,void 0,(function*(){yield this.cache.delete(t)}))))}))}}var o,c,d=function(t,e,s,i){return new(s||(s=Promise))((function(n,h){function a(t){try{r(i.next(t))}catch(t){h(t)}}function u(t){try{r(i.throw(t))}catch(t){h(t)}}function r(t){var e;t.done?n(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(a,u)}r((i=i.apply(t,e||[])).next())}))};class v extends(e()){constructor(t,e){super(),this.name=t,this.basePath=e,this.queue=new u,this.storage=new l(t),this.downloader=new a(this.storage,this.queue,this.basePath),console.log("Asset manager initialized")}init(){return d(this,void 0,void 0,(function*(){return yield this.storage.init(),!0}))}setManifest(t){return d(this,void 0,void 0,(function*(){return this.manifest=yield function(t){return e=this,s=void 0,n=function*(){try{const e=yield fetch(t);console.log(e);const s=yield e.text();return console.log("Parsing: ",s),(void 0).parse(s)}catch(t){alert(`Error occured: ${t.toString()}`)}},new((i=void 0)||(i=Promise))((function(t,h){function a(t){try{r(n.next(t))}catch(t){h(t)}}function u(t){try{r(n.throw(t))}catch(t){h(t)}}function r(e){var s;e.done?t(e.value):(s=e.value,s instanceof i?s:new i((function(t){t(s)}))).then(a,u)}r((n=n.apply(e,s||[])).next())}));var e,s,i,n}(`${this.basePath}/${t}`),this.storage.setManifest(this.manifest),this.manifest}))}enqueue(t){this.queue.add(t)}download(){return d(this,void 0,void 0,(function*(){return yield this.downloader.download()}))}downloadFromManifest(t){return d(this,void 0,void 0,(function*(){this.manifest[t].forEach((t=>this.enqueue(t))),this.downloader.on("download.progress",(t=>this.emit("progress",t)));const e=yield this.downloader.download();return this.downloader.off("download.progress"),e}))}downloadFile(t){return d(this,void 0,void 0,(function*(){return yield this.downloader.downloadItem(n(this.basePath,t))}))}setBasePath(t){this.basePath=this.basePath,this.downloader.setBasePath(this.basePath)}clearCache(){this.storage.clear()}}class y{constructor(){this.components=new Map,this.id=0}addComponent(t){let e=new t;e.id=t.id,this.components.set(t.id,e)}removeComponent(t){this.components.delete(t.id)}getComponentIDs(){return[...this.components.keys()]}getComponent(t){return this.components.get(t.id)}getComponentByID(t){return this.components.get(t)}}class m{constructor(){this.events=new Map}emit(t,e={}){let s=this.events.get(t);if(s)s.subscribers.forEach((t=>{t(e)}));else{let e=new p(t);this.events.set(t,e)}}subscribe(t,e){let s=this.events.get(t);s||(s=new p(t),this.events.set(t,s)),s.subscribers.push(e)}unsubscribe(t,e){if(this.events.has(t)){let s=this.events.get(t);s.subscribers=s.subscribers.filter((t=>t!==e)),s.subscribers.length<1&&this.events.delete(t)}}unsubscribeAll(t){this.events.has(t)&&this.events.delete(t)}}class p{constructor(t){this.id=t,this.subscribers=[]}}class x{constructor(t,e,s){this.include=t,this.exclude=e,this.world=s,this.isDirty=!0,this.results=new Array,this.includeComponentIds=t.map((t=>t.id)),this.excludeComponentIds=e.map((t=>t.id)),this.id=0}execute(){if(!this.isDirty&&this.results)return this.results;this.includeComponentIds=this.include.map((t=>this.world.componentNamesToIDs.get(t.name))),this.excludeComponentIds=this.exclude.map((t=>this.world.componentNamesToIDs.get(t.name)));const t=this.world.entities.filter((t=>{let e=t.getComponentIDs(),s=e.map((t=>this.excludeComponentIds.includes(t))).includes(!0);return e.filter((t=>this.includeComponentIds.includes(t))).length===this.includeComponentIds.length&&!s}));return t.length>0&&(this.isDirty=!1,this.results=t),t}}class w{constructor(t){this.executor=t}execute(t){this.executor&&this.executor(t)}}class f{constructor(){this.nextEntityID=0,this.nextComponentID=0,this.nextQueryID=0,this.entities=new Array,this.systems=new Set,this.components=new Map,this.componentNamesToIDs=new Map,this.queryCache=new Array,this.eventBus=new m}run(){this.systems.forEach((t=>{t.execute(this)}))}createSystem(t){const e=new w(t);this.systems.add(e)}addSystem(t){this.systems.add(t)}addEntity(t){this.entities.push(t),this.markQueriesDirty()}removeEntity(t){this.entities=this.entities.filter((e=>e!==t)),this.markQueriesDirty()}createEntity(t){const e=new y;return e.id=this.nextEntityID,this.nextEntityID++,t.forEach((t=>{this.componentNamesToIDs.has(t.name)?t.id=this.componentNamesToIDs.get(t.name):(this.componentNamesToIDs.set(t.name,this.nextComponentID),t.id=this.nextComponentID,this.nextComponentID++),e.addComponent(t)})),this.entities.push(e),this.markQueriesDirty(),e}extendEntity(t,e){const s=this.entities.find((e=>t.name===e.constructor.name)),i=new y;return i.id=this.nextEntityID,this.nextEntityID++,s.components.forEach((t=>{i.addComponent(this.components.get(t.id))})),e.forEach((t=>{this.componentNamesToIDs.has(t.name)?t.id=this.componentNamesToIDs.get(t.name):(this.componentNamesToIDs.set(t.name,this.nextComponentID),t.id=this.nextComponentID,this.nextComponentID++),i.addComponent(t)})),this.entities.push(i),i}createComponent(t){const e=t;return e.id=this.nextComponentID,this.nextComponentID++,this.components.set(e.id,e),this.componentNamesToIDs.set(t.name,t.id),e}query(t,e){const s=new x(t,e,this),i=this.queryCache.find((s=>s.include==t&&s.exclude==e));return i?i.execute():(this.queryCache.push(s),s.execute())}createQuery(t,e){const s=new x(t,e,this);return s.id=this.nextQueryID,this.nextQueryID++,this.queryCache.push(s),s}markQueriesDirty(){this.queryCache.forEach((t=>t.isDirty=!0))}}class g{constructor(t){this.element=t}getState(){}capture(t){}release(){}}class z extends g{constructor(t){super(t),this.keysDown=new Map,this.keysJustPressed=new Map,this.keysJustReleased=new Map,this.handleKeyDown=this.handleKeyDown.bind(this),this.handleKeyUp=this.handleKeyUp.bind(this)}capture(t){this.active=!0,this.preventDefault=t,this.element.addEventListener("keydown",this.handleKeyDown),this.element.addEventListener("keyup",this.handleKeyUp)}release(){this.active=!1,this.element.removeEventListener("keydown",this.handleKeyDown),this.element.removeEventListener("keyup",this.handleKeyUp)}getState(){const t={keysDown:new Map(this.keysDown),keysJustPressed:new Map(this.keysJustPressed),keysJustReleased:new Map(this.keysJustReleased)};return this.keysJustPressed.clear(),this.keysJustReleased.clear(),t}handleKeyDown(t){this.active&&this.preventDefault&&t.preventDefault(),this.keysDown.get(t.keyCode)||(this.keysDown.set(t.keyCode,!0),this.keysJustPressed.set(t.keyCode,!0),this.keysJustReleased.set(t.keyCode,!1))}handleKeyUp(t){this.active&&this.preventDefault&&t.preventDefault(),this.keysDown.get(t.keyCode)&&(this.keysDown.set(t.keyCode,!1),this.keysJustPressed.set(t.keyCode,!1),this.keysJustReleased.set(t.keyCode,!0))}}class b extends g{constructor(t){super(t),this.mousePosition=new M,this.mouseDelta=new C,this.mouseWheel=new C,this.mouseButtons=new k}capture(){this.handleMouseDown=this.handleMouseDown.bind(this),this.handleMouseMove=this.handleMouseMove.bind(this),this.handleMouseUp=this.handleMouseUp.bind(this),this.handlePointerChange=this.handlePointerChange.bind(this),this.active=!0,this.element.addEventListener("mousedown",this.handleMouseDown),this.element.addEventListener("mousemove",this.handleMouseMove),this.element.addEventListener("mouseup",this.handleMouseUp),document.addEventListener("pointerlockchange",this.handlePointerChange)}release(){this.active=!1,this.element.removeEventListener("mousedown",this.handleMouseDown),this.element.removeEventListener("mousemove",this.handleMouseMove),this.element.removeEventListener("mouseup",this.handleMouseUp)}getState(){const{mouseButtons:t,mouseDelta:e,mousePosition:s,mouseWheel:i}=this,n={mouseButtons:{keysDown:new Map(this.mouseButtons.keysDown),keysJustPressed:new Map(this.mouseButtons.keysJustPressed),keysJustReleased:new Map(this.mouseButtons.keysJustReleased)},mouseDelta:e,mousePosition:s,mouseWheel:i};return this.mouseButtons.keysJustPressed.clear(),this.mouseButtons.keysJustReleased.clear(),this.mouseDelta.x=0,this.mouseDelta.y=0,n}handleMouseDown(t){this.active&&t.preventDefault(),this.mouseButtons.keysDown.set(t.button,!0),this.mouseButtons.keysJustPressed.set(t.button,!0),this.mouseButtons.keysJustReleased.set(t.button,!1)}handleMouseMove(t){this.active&&t.preventDefault(),this.mousePosition.x=t.clientX,this.mousePosition.y=t.clientY,this.mouseDelta.x=t.movementX,this.mouseDelta.y=t.movementY}handleMouseUp(t){this.active&&t.preventDefault(),this.mouseButtons.keysJustReleased.set(t.button,!0),this.mouseButtons.keysDown.set(t.button,!1),this.mouseButtons.keysJustPressed.set(t.button,!1)}handlePointerChange(){document.pointerLockElement!==this.element&&this.element.addEventListener("click",(()=>{this.element.requestPointerLock()}),{once:!0})}}class M{}class k{constructor(){this.keysDown=new Map,this.keysJustPressed=new Map,this.keysJustReleased=new Map}}class C{}class I{constructor(t,e){this.InputIDs=t,this.element=e,this.inputs=new Map,this.init()}init(){this.InputIDs.forEach((t=>{const e=new(function(t){switch(t){case"keyboard":return z;case"mouse":return b}}(t))(this.element);this.inputs.set(t,e)}))}addInput(t,e){return this.inputs.set(t,e),this}capture(t=!0){this.inputs.forEach((e=>e.capture(t)))}release(){this.inputs.forEach((t=>t.release()))}getState(){const t={};return this.inputs.forEach(((e,s)=>{e&&(t[s]=e.getState())})),t}}class D{constructor(t){this.values=new Float32Array(4),void 0!==t&&(this.xyzw=t)}get x(){return this.values[0]}get y(){return this.values[1]}get z(){return this.values[2]}get w(){return this.values[3]}get xy(){return[this.values[0],this.values[1]]}get xyz(){return[this.values[0],this.values[1],this.values[2]]}get xyzw(){return[this.values[0],this.values[1],this.values[2],this.values[3]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set z(t){this.values[2]=t}set w(t){this.values[3]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}set xyz(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}set xyzw(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2],this.values[3]=t[3]}get r(){return this.values[0]}get g(){return this.values[1]}get b(){return this.values[2]}get a(){return this.values[3]}get rg(){return[this.values[0],this.values[1]]}get rgb(){return[this.values[0],this.values[1],this.values[2]]}get rgba(){return[this.values[0],this.values[1],this.values[2],this.values[3]]}set r(t){this.values[0]=t}set g(t){this.values[1]=t}set b(t){this.values[2]=t}set a(t){this.values[3]=t}set rg(t){this.values[0]=t[0],this.values[1]=t[1]}set rgb(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}set rgba(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2],this.values[3]=t[3]}at(t){return this.values[t]}reset(){this.x=0,this.y=0,this.z=0,this.w=0}copy(t){return t||(t=new D),t.x=this.x,t.y=this.y,t.z=this.z,t.w=this.w,t}negate(t){return t||(t=this),t.x=-this.x,t.y=-this.y,t.z=-this.z,t.w=-this.w,t}equals(t,e=1e-5){return!(Math.abs(this.x-t.x)>e||Math.abs(this.y-t.y)>e||Math.abs(this.z-t.z)>e||Math.abs(this.w-t.w)>e)}length(){return Math.sqrt(this.squaredLength())}squaredLength(){const t=this.x,e=this.y,s=this.z,i=this.w;return t*t+e*e+s*s+i*i}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this}subtract(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this.w/=t.w,this}scale(t,e){return e||(e=this),e.x*=t,e.y*=t,e.z*=t,e.w*=t,e}normalize(t){t||(t=this);let e=this.length();return 1===e?this:0===e?(t.x*=0,t.y*=0,t.z*=0,t.w*=0,t):(e=1/e,t.x*=e,t.y*=e,t.z*=e,t.w*=e,t)}multiplyMat4(t,e){return e||(e=this),t.multiplyVec4(this,e)}static mix(t,e,s,i){return i||(i=new D),i.x=t.x+s*(e.x-t.x),i.y=t.y+s*(e.y-t.y),i.z=t.z+s*(e.z-t.z),i.w=t.w+s*(e.w-t.w),i}static sum(t,e,s){return s||(s=new D),s.x=t.x+e.x,s.y=t.y+e.y,s.z=t.z+e.z,s.w=t.w+e.w,s}static difference(t,e,s){return s||(s=new D),s.x=t.x-e.x,s.y=t.y-e.y,s.z=t.z-e.z,s.w=t.w-e.w,s}static product(t,e,s){return s||(s=new D),s.x=t.x*e.x,s.y=t.y*e.y,s.z=t.z*e.z,s.w=t.w*e.w,s}static quotient(t,e,s){return s||(s=new D),s.x=t.x/e.x,s.y=t.y/e.y,s.z=t.z/e.z,s.w=t.w/e.w,s}}D.zero=new D([0,0,0,1]),D.one=new D([1,1,1,1]);class S{constructor(t){this.values=new Float32Array(16),void 0!==t&&this.init(t)}at(t){return this.values[t]}init(t){for(let e=0;e<16;e++)this.values[e]=t[e];return this}reset(){for(let t=0;t<16;t++)this.values[t]=0}copy(t){t||(t=new S);for(let e=0;e<16;e++)t.values[e]=this.values[e];return t}all(){const t=[];for(let e=0;e<16;e++)t[e]=this.values[e];return t}row(t){return[this.values[4*t+0],this.values[4*t+1],this.values[4*t+2],this.values[4*t+3]]}col(t){return[this.values[t],this.values[t+4],this.values[t+8],this.values[t+12]]}equals(t,e=1e-5){for(let s=0;s<16;s++)if(Math.abs(this.values[s]-t.at(s))>e)return!1;return!0}determinant(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],n=this.values[4],h=this.values[5],a=this.values[6],u=this.values[7],r=this.values[8],l=this.values[9],o=this.values[10],c=this.values[11],d=this.values[12],v=this.values[13],y=this.values[14],m=this.values[15];return(t*h-e*n)*(o*m-c*y)-(t*a-s*n)*(l*m-c*v)+(t*u-i*n)*(l*y-o*v)+(e*a-s*h)*(r*m-c*d)-(e*u-i*h)*(r*y-o*d)+(s*u-i*a)*(r*v-l*d)}setIdentity(){return this.values[0]=1,this.values[1]=0,this.values[2]=0,this.values[3]=0,this.values[4]=0,this.values[5]=1,this.values[6]=0,this.values[7]=0,this.values[8]=0,this.values[9]=0,this.values[10]=1,this.values[11]=0,this.values[12]=0,this.values[13]=0,this.values[14]=0,this.values[15]=1,this}transpose(){const t=this.values[1],e=this.values[2],s=this.values[3],i=this.values[6],n=this.values[7],h=this.values[11];return this.values[1]=this.values[4],this.values[2]=this.values[8],this.values[3]=this.values[12],this.values[4]=t,this.values[6]=this.values[9],this.values[7]=this.values[13],this.values[8]=e,this.values[9]=i,this.values[11]=this.values[14],this.values[12]=s,this.values[13]=n,this.values[14]=h,this}inverse(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],n=this.values[4],h=this.values[5],a=this.values[6],u=this.values[7],r=this.values[8],l=this.values[9],o=this.values[10],c=this.values[11],d=this.values[12],v=this.values[13],y=this.values[14],m=this.values[15],p=t*h-e*n,x=t*a-s*n,w=t*u-i*n,f=e*a-s*h,g=e*u-i*h,z=s*u-i*a,b=r*v-l*d,M=r*y-o*d,k=r*m-c*d,C=l*y-o*v,I=l*m-c*v,D=o*m-c*y;let S=p*D-x*I+w*C+f*k-g*M+z*b;return S?(S=1/S,this.values[0]=(h*D-a*I+u*C)*S,this.values[1]=(-e*D+s*I-i*C)*S,this.values[2]=(v*z-y*g+m*f)*S,this.values[3]=(-l*z+o*g-c*f)*S,this.values[4]=(-n*D+a*k-u*M)*S,this.values[5]=(t*D-s*k+i*M)*S,this.values[6]=(-d*z+y*w-m*x)*S,this.values[7]=(r*z-o*w+c*x)*S,this.values[8]=(n*I-h*k+u*b)*S,this.values[9]=(-t*I+e*k-i*b)*S,this.values[10]=(d*g-v*w+m*p)*S,this.values[11]=(-r*g+l*w-c*p)*S,this.values[12]=(-n*C+h*M-a*b)*S,this.values[13]=(t*C-e*M+s*b)*S,this.values[14]=(-d*f+v*x-y*p)*S,this.values[15]=(r*f-l*x+o*p)*S,this):null}multiply(t){const e=this.values[0],s=this.values[1],i=this.values[2],n=this.values[3],h=this.values[4],a=this.values[5],u=this.values[6],r=this.values[7],l=this.values[8],o=this.values[9],c=this.values[10],d=this.values[11],v=this.values[12],y=this.values[13],m=this.values[14],p=this.values[15];let x=t.at(0),w=t.at(1),f=t.at(2),g=t.at(3);return this.values[0]=x*e+w*h+f*l+g*v,this.values[1]=x*s+w*a+f*o+g*y,this.values[2]=x*i+w*u+f*c+g*m,this.values[3]=x*n+w*r+f*d+g*p,x=t.at(4),w=t.at(5),f=t.at(6),g=t.at(7),this.values[4]=x*e+w*h+f*l+g*v,this.values[5]=x*s+w*a+f*o+g*y,this.values[6]=x*i+w*u+f*c+g*m,this.values[7]=x*n+w*r+f*d+g*p,x=t.at(8),w=t.at(9),f=t.at(10),g=t.at(11),this.values[8]=x*e+w*h+f*l+g*v,this.values[9]=x*s+w*a+f*o+g*y,this.values[10]=x*i+w*u+f*c+g*m,this.values[11]=x*n+w*r+f*d+g*p,x=t.at(12),w=t.at(13),f=t.at(14),g=t.at(15),this.values[12]=x*e+w*h+f*l+g*v,this.values[13]=x*s+w*a+f*o+g*y,this.values[14]=x*i+w*u+f*c+g*m,this.values[15]=x*n+w*r+f*d+g*p,this}multiplyVec3(t){const e=t.x,s=t.y,i=t.z;return new A([this.values[0]*e+this.values[4]*s+this.values[8]*i+this.values[12],this.values[1]*e+this.values[5]*s+this.values[9]*i+this.values[13],this.values[2]*e+this.values[6]*s+this.values[10]*i+this.values[14]])}multiplyVec4(t,e){e||(e=new D);const s=t.x,i=t.y,n=t.z,h=t.w;return e.x=this.values[0]*s+this.values[4]*i+this.values[8]*n+this.values[12]*h,e.y=this.values[1]*s+this.values[5]*i+this.values[9]*n+this.values[13]*h,e.z=this.values[2]*s+this.values[6]*i+this.values[10]*n+this.values[14]*h,e.w=this.values[3]*s+this.values[7]*i+this.values[11]*n+this.values[15]*h,e}toMat3(){return new P([this.values[0],this.values[1],this.values[2],this.values[4],this.values[5],this.values[6],this.values[8],this.values[9],this.values[10]])}toInverseMat3(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[4],n=this.values[5],h=this.values[6],a=this.values[8],u=this.values[9],r=this.values[10],l=r*n-h*u,o=-r*i+h*a,c=u*i-n*a;let d=t*l+e*o+s*c;return d?(d=1/d,new P([l*d,(-r*e+s*u)*d,(h*e-s*n)*d,o*d,(r*t-s*a)*d,(-h*t+s*i)*d,c*d,(-u*t+e*a)*d,(n*t-e*i)*d])):null}translate(t){const e=t.x,s=t.y,i=t.z;return this.values[12]+=this.values[0]*e+this.values[4]*s+this.values[8]*i,this.values[13]+=this.values[1]*e+this.values[5]*s+this.values[9]*i,this.values[14]+=this.values[2]*e+this.values[6]*s+this.values[10]*i,this.values[15]+=this.values[3]*e+this.values[7]*s+this.values[11]*i,this}scale(t){const e=t.x,s=t.y,i=t.z;return this.values[0]*=e,this.values[1]*=e,this.values[2]*=e,this.values[3]*=e,this.values[4]*=s,this.values[5]*=s,this.values[6]*=s,this.values[7]*=s,this.values[8]*=i,this.values[9]*=i,this.values[10]*=i,this.values[11]*=i,this}rotate(t,e){let s=e.x,i=e.y,n=e.z,h=Math.sqrt(s*s+i*i+n*n);if(!h)return null;1!==h&&(h=1/h,s*=h,i*=h,n*=h);const a=Math.sin(t),u=Math.cos(t),r=1-u,l=this.values[0],o=this.values[1],c=this.values[2],d=this.values[3],v=this.values[4],y=this.values[5],m=this.values[6],p=this.values[7],x=this.values[8],w=this.values[9],f=this.values[10],g=this.values[11],z=s*s*r+u,b=i*s*r+n*a,M=n*s*r-i*a,k=s*i*r-n*a,C=i*i*r+u,I=n*i*r+s*a,D=s*n*r+i*a,S=i*n*r-s*a,E=n*n*r+u;return this.values[0]=l*z+v*b+x*M,this.values[1]=o*z+y*b+w*M,this.values[2]=c*z+m*b+f*M,this.values[3]=d*z+p*b+g*M,this.values[4]=l*k+v*C+x*I,this.values[5]=o*k+y*C+w*I,this.values[6]=c*k+m*C+f*I,this.values[7]=d*k+p*C+g*I,this.values[8]=l*D+v*S+x*E,this.values[9]=o*D+y*S+w*E,this.values[10]=c*D+m*S+f*E,this.values[11]=d*D+p*S+g*E,this}static frustum(t,e,s,i,n,h){const a=e-t,u=i-s,r=h-n;return new S([2*n/a,0,0,0,0,2*n/u,0,0,(e+t)/a,(i+s)/u,-(h+n)/r,-1,0,0,-h*n*2/r,0])}static perspective(t,e,s,i){const n=s*Math.tan(t*Math.PI/360),h=n*e;return S.frustum(-h,h,-n,n,s,i)}static orthographic(t,e,s,i,n,h){const a=e-t,u=i-s,r=h-n;return new S([2/a,0,0,0,0,2/u,0,0,0,0,-2/r,0,-(t+e)/a,-(i+s)/u,-(h+n)/r,1])}static lookAt(t,e,s=A.up){if(t.equals(e))return this.identity;const i=A.difference(t,e).normalize(),n=A.cross(s,i).normalize(),h=A.cross(i,n).normalize();return new S([n.x,h.x,i.x,0,n.y,h.y,i.y,0,n.z,h.z,i.z,0,-A.dot(n,t),-A.dot(h,t),-A.dot(i,t),1])}static product(t,e,s){const i=t.at(0),n=t.at(1),h=t.at(2),a=t.at(3),u=t.at(4),r=t.at(5),l=t.at(6),o=t.at(7),c=t.at(8),d=t.at(9),v=t.at(10),y=t.at(11),m=t.at(12),p=t.at(13),x=t.at(14),w=t.at(15),f=e.at(0),g=e.at(1),z=e.at(2),b=e.at(3),M=e.at(4),k=e.at(5),C=e.at(6),I=e.at(7),D=e.at(8),E=e.at(9),P=e.at(10),q=e.at(11),A=e.at(12),L=e.at(13),_=e.at(14),O=e.at(15);return s?(s.init([f*i+g*u+z*c+b*m,f*n+g*r+z*d+b*p,f*h+g*l+z*v+b*x,f*a+g*o+z*y+b*w,M*i+k*u+C*c+I*m,M*n+k*r+C*d+I*p,M*h+k*l+C*v+I*x,M*a+k*o+C*y+I*w,D*i+E*u+P*c+q*m,D*n+E*r+P*d+q*p,D*h+E*l+P*v+q*x,D*a+E*o+P*y+q*w,A*i+L*u+_*c+O*m,A*n+L*r+_*d+O*p,A*h+L*l+_*v+O*x,A*a+L*o+_*y+O*w]),s):new S([f*i+g*u+z*c+b*m,f*n+g*r+z*d+b*p,f*h+g*l+z*v+b*x,f*a+g*o+z*y+b*w,M*i+k*u+C*c+I*m,M*n+k*r+C*d+I*p,M*h+k*l+C*v+I*x,M*a+k*o+C*y+I*w,D*i+E*u+P*c+q*m,D*n+E*r+P*d+q*p,D*h+E*l+P*v+q*x,D*a+E*o+P*y+q*w,A*i+L*u+_*c+O*m,A*n+L*r+_*d+O*p,A*h+L*l+_*v+O*x,A*a+L*o+_*y+O*w])}}S.identity=(new S).setIdentity();class E{constructor(t){this.values=new Float32Array(2),void 0!==t&&(this.xy=t)}get x(){return this.values[0]}get y(){return this.values[1]}get xy(){return[this.values[0],this.values[1]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}at(t){return this.values[t]}reset(){this.x=0,this.y=0}copy(t){return t||(t=new E),t.x=this.x,t.y=this.y,t}negate(t){return t||(t=this),t.x=-this.x,t.y=-this.y,t}equals(t,e=1e-5){return!(Math.abs(this.x-t.x)>e||Math.abs(this.y-t.y)>e)}length(){return Math.sqrt(this.squaredLength())}squaredLength(){const t=this.x,e=this.y;return t*t+e*e}add(t){return this.x+=t.x,this.y+=t.y,this}subtract(t){return this.x-=t.x,this.y-=t.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}divide(t){return this.x/=t.x,this.y/=t.y,this}scale(t,e){return e||(e=this),e.x*=t,e.y*=t,e}normalize(t){t||(t=this);let e=this.length();return 1===e?this:0===e?(t.x=0,t.y=0,t):(e=1/e,t.x*=e,t.y*=e,t)}multiplyMat2(t,e){return e||(e=this),t.multiplyVec2(this,e)}multiplyMat3(t,e){return e||(e=this),t.multiplyVec2(this,e)}static cross(t,e,s){s||(s=new A);const i=t.x,n=t.y,h=e.x,a=i*e.y-n*h;return s.x=0,s.y=0,s.z=a,s}static dot(t,e){return t.x*e.x+t.y*e.y}static distance(t,e){return Math.sqrt(this.squaredDistance(t,e))}static squaredDistance(t,e){const s=e.x-t.x,i=e.y-t.y;return s*s+i*i}static direction(t,e,s){s||(s=new E);const i=t.x-e.x,n=t.y-e.y;let h=Math.sqrt(i*i+n*n);return 0===h?(s.x=0,s.y=0,s):(h=1/h,s.x=i*h,s.y=n*h,s)}static mix(t,e,s,i){i||(i=new E);const n=t.x,h=t.y,a=e.x,u=e.y;return i.x=n+s*(a-n),i.y=h+s*(u-h),i}static sum(t,e,s){return s||(s=new E),s.x=t.x+e.x,s.y=t.y+e.y,s}static difference(t,e,s){return s||(s=new E),s.x=t.x-e.x,s.y=t.y-e.y,s}static product(t,e,s){return s||(s=new E),s.x=t.x*e.x,s.y=t.y*e.y,s}static quotient(t,e,s){return s||(s=new E),s.x=t.x/e.x,s.y=t.y/e.y,s}}E.zero=new E([0,0]),E.one=new E([1,1]);class P{constructor(t){this.values=new Float32Array(9),void 0!==t&&this.init(t)}at(t){return this.values[t]}init(t){for(let e=0;e<9;e++)this.values[e]=t[e];return this}reset(){for(let t=0;t<9;t++)this.values[t]=0}copy(t){t||(t=new P);for(let e=0;e<9;e++)t.values[e]=this.values[e];return t}all(){const t=[];for(let e=0;e<9;e++)t[e]=this.values[e];return t}row(t){return[this.values[3*t+0],this.values[3*t+1],this.values[3*t+2]]}col(t){return[this.values[t],this.values[t+3],this.values[t+6]]}equals(t,e=1e-5){for(let s=0;s<9;s++)if(Math.abs(this.values[s]-t.at(s))>e)return!1;return!0}determinant(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],n=this.values[4],h=this.values[5],a=this.values[6],u=this.values[7],r=this.values[8];return t*(r*n-h*u)+e*(-r*i+h*a)+s*(u*i-n*a)}setIdentity(){return this.values[0]=1,this.values[1]=0,this.values[2]=0,this.values[3]=0,this.values[4]=1,this.values[5]=0,this.values[6]=0,this.values[7]=0,this.values[8]=1,this}transpose(){const t=this.values[1],e=this.values[2],s=this.values[5];return this.values[1]=this.values[3],this.values[2]=this.values[6],this.values[3]=t,this.values[5]=this.values[7],this.values[6]=e,this.values[7]=s,this}inverse(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],n=this.values[4],h=this.values[5],a=this.values[6],u=this.values[7],r=this.values[8],l=r*n-h*u,o=-r*i+h*a,c=u*i-n*a;let d=t*l+e*o+s*c;return d?(d=1/d,this.values[0]=l*d,this.values[1]=(-r*e+s*u)*d,this.values[2]=(h*e-s*n)*d,this.values[3]=o*d,this.values[4]=(r*t-s*a)*d,this.values[5]=(-h*t+s*i)*d,this.values[6]=c*d,this.values[7]=(-u*t+e*a)*d,this.values[8]=(n*t-e*i)*d,this):null}multiply(t){const e=this.values[0],s=this.values[1],i=this.values[2],n=this.values[3],h=this.values[4],a=this.values[5],u=this.values[6],r=this.values[7],l=this.values[8],o=t.at(0),c=t.at(1),d=t.at(2),v=t.at(3),y=t.at(4),m=t.at(5),p=t.at(6),x=t.at(7),w=t.at(8);return this.values[0]=o*e+c*n+d*u,this.values[1]=o*s+c*h+d*r,this.values[2]=o*i+c*a+d*l,this.values[3]=v*e+y*n+m*u,this.values[4]=v*s+y*h+m*r,this.values[5]=v*i+y*a+m*l,this.values[6]=p*e+x*n+w*u,this.values[7]=p*s+x*h+w*r,this.values[8]=p*i+x*a+w*l,this}multiplyVec2(t,e){const s=t.x,i=t.y;return e?(e.xy=[s*this.values[0]+i*this.values[3]+this.values[6],s*this.values[1]+i*this.values[4]+this.values[7]],e):new E([s*this.values[0]+i*this.values[3]+this.values[6],s*this.values[1]+i*this.values[4]+this.values[7]])}multiplyVec3(t,e){const s=t.x,i=t.y,n=t.z;return e?(e.xyz=[s*this.values[0]+i*this.values[3]+n*this.values[6],s*this.values[1]+i*this.values[4]+n*this.values[7],s*this.values[2]+i*this.values[5]+n*this.values[8]],e):new A([s*this.values[0]+i*this.values[3]+n*this.values[6],s*this.values[1]+i*this.values[4]+n*this.values[7],s*this.values[2]+i*this.values[5]+n*this.values[8]])}toMat4(t){return t?(t.init([this.values[0],this.values[1],this.values[2],0,this.values[3],this.values[4],this.values[5],0,this.values[6],this.values[7],this.values[8],0,0,0,0,1]),t):new S([this.values[0],this.values[1],this.values[2],0,this.values[3],this.values[4],this.values[5],0,this.values[6],this.values[7],this.values[8],0,0,0,0,1])}toQuat(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],n=this.values[4],h=this.values[5],a=this.values[6],u=this.values[7],r=this.values[8],l=t-n-r,o=n-t-r,c=r-t-n;let d=0,v=t+n+r;l>v&&(v=l,d=1),o>v&&(v=o,d=2),c>v&&(v=c,d=3);const y=.5*Math.sqrt(v+1),m=.25/y,p=new q;switch(d){case 0:p.w=y,p.x=(h-u)*m,p.y=(a-s)*m,p.z=(e-i)*m;break;case 1:p.w=(h-u)*m,p.x=y,p.y=(e+i)*m,p.z=(a+s)*m;break;case 2:p.w=(a-s)*m,p.x=(e+i)*m,p.y=y,p.z=(h+u)*m;break;case 3:p.w=(e-i)*m,p.x=(a+s)*m,p.y=(h+u)*m,p.z=y}return p}rotate(t,e){let s=e.x,i=e.y,n=e.z,h=Math.sqrt(s*s+i*i+n*n);if(!h)return null;1!==h&&(h=1/h,s*=h,i*=h,n*=h);const a=Math.sin(t),u=Math.cos(t),r=1-u,l=this.values[0],o=this.values[1],c=this.values[2],d=this.values[4],v=this.values[5],y=this.values[6],m=this.values[8],p=this.values[9],x=this.values[10],w=s*s*r+u,f=i*s*r+n*a,g=n*s*r-i*a,z=s*i*r-n*a,b=i*i*r+u,M=n*i*r+s*a,k=s*n*r+i*a,C=i*n*r-s*a,I=n*n*r+u;return this.values[0]=l*w+d*f+m*g,this.values[1]=o*w+v*f+p*g,this.values[2]=c*w+y*f+x*g,this.values[3]=l*z+d*b+m*M,this.values[4]=o*z+v*b+p*M,this.values[5]=c*z+y*b+x*M,this.values[6]=l*k+d*C+m*I,this.values[7]=o*k+v*C+p*I,this.values[8]=c*k+y*C+x*I,this}static product(t,e,s){const i=t.at(0),n=t.at(1),h=t.at(2),a=t.at(3),u=t.at(4),r=t.at(5),l=t.at(6),o=t.at(7),c=t.at(8),d=e.at(0),v=e.at(1),y=e.at(2),m=e.at(3),p=e.at(4),x=e.at(5),w=e.at(6),f=e.at(7),g=e.at(8);return s?(s.init([d*i+v*a+y*l,d*n+v*u+y*o,d*h+v*r+y*c,m*i+p*a+x*l,m*n+p*u+x*o,m*h+p*r+x*c,w*i+f*a+g*l,w*n+f*u+g*o,w*h+f*r+g*c]),s):new P([d*i+v*a+y*l,d*n+v*u+y*o,d*h+v*r+y*c,m*i+p*a+x*l,m*n+p*u+x*o,m*h+p*r+x*c,w*i+f*a+g*l,w*n+f*u+g*o,w*h+f*r+g*c])}}P.identity=(new P).setIdentity();class q{constructor(t){this.values=new Float32Array(4),void 0!==t&&(this.xyzw=t)}get x(){return this.values[0]}get y(){return this.values[1]}get z(){return this.values[2]}get w(){return this.values[3]}get xy(){return[this.values[0],this.values[1]]}get xyz(){return[this.values[0],this.values[1],this.values[2]]}get xyzw(){return[this.values[0],this.values[1],this.values[2],this.values[3]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set z(t){this.values[2]=t}set w(t){this.values[3]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}set xyz(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}set xyzw(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2],this.values[3]=t[3]}at(t){return this.values[t]}reset(){for(let t=0;t<4;t++)this.values[t]=0}copy(t){t||(t=new q);for(let e=0;e<4;e++)t.values[e]=this.values[e];return t}roll(){const t=this.x,e=this.y,s=this.z,i=this.w;return Math.atan2(2*(t*e+i*s),i*i+t*t-e*e-s*s)}pitch(){const t=this.x,e=this.y,s=this.z,i=this.w;return Math.atan2(2*(e*s+i*t),i*i-t*t-e*e+s*s)}yaw(){return Math.asin(2*(this.x*this.z-this.w*this.y))}equals(t,e=1e-5){for(let s=0;s<4;s++)if(Math.abs(this.values[s]-t.at(s))>e)return!1;return!0}setIdentity(){return this.x=0,this.y=0,this.z=0,this.w=1,this}calculateW(){const t=this.x,e=this.y,s=this.z;return this.w=-Math.sqrt(Math.abs(1-t*t-e*e-s*s)),this}inverse(){const t=q.dot(this,this);if(!t)return this.xyzw=[0,0,0,0],this;const e=t?1/t:0;return this.x*=-e,this.y*=-e,this.z*=-e,this.w*=e,this}conjugate(){return this.values[0]*=-1,this.values[1]*=-1,this.values[2]*=-1,this}length(){const t=this.x,e=this.y,s=this.z,i=this.w;return Math.sqrt(t*t+e*e+s*s+i*i)}normalize(t){t||(t=this);const e=this.x,s=this.y,i=this.z,n=this.w;let h=Math.sqrt(e*e+s*s+i*i+n*n);return h?(h=1/h,t.x=e*h,t.y=s*h,t.z=i*h,t.w=n*h,t):(t.x=0,t.y=0,t.z=0,t.w=0,t)}add(t){for(let e=0;e<4;e++)this.values[e]+=t.at(e);return this}multiply(t){const e=this.values[0],s=this.values[1],i=this.values[2],n=this.values[3],h=t.x,a=t.y,u=t.z,r=t.w;return this.x=e*r+n*h+s*u-i*a,this.y=s*r+n*a+i*h-e*u,this.z=i*r+n*u+e*a-s*h,this.w=n*r-e*h-s*a-i*u,this}multiplyVec3(t,e){e||(e=new A);const s=t.x,i=t.y,n=t.z,h=this.x,a=this.y,u=this.z,r=this.w,l=r*s+a*n-u*i,o=r*i+u*s-h*n,c=r*n+h*i-a*s,d=-h*s-a*i-u*n;return e.x=l*r+d*-h+o*-u-c*-a,e.y=o*r+d*-a+c*-h-l*-u,e.z=c*r+d*-u+l*-a-o*-h,e}toMat3(t){t||(t=new P);const e=this.x,s=this.y,i=this.z,n=this.w,h=e+e,a=s+s,u=i+i,r=e*h,l=e*a,o=e*u,c=s*a,d=s*u,v=i*u,y=n*h,m=n*a,p=n*u;return t.init([1-(c+v),l+p,o-m,l-p,1-(r+v),d+y,o+m,d-y,1-(r+c)]),t}toMat4(t){t||(t=new S);const e=this.x,s=this.y,i=this.z,n=this.w,h=e+e,a=s+s,u=i+i,r=e*h,l=e*a,o=e*u,c=s*a,d=s*u,v=i*u,y=n*h,m=n*a,p=n*u;return t.init([1-(c+v),l+p,o-m,0,l-p,1-(r+v),d+y,0,o+m,d-y,1-(r+c),0,0,0,0,1]),t}static dot(t,e){return t.x*e.x+t.y*e.y+t.z*e.z+t.w*e.w}static sum(t,e,s){return s||(s=new q),s.x=t.x+e.x,s.y=t.y+e.y,s.z=t.z+e.z,s.w=t.w+e.w,s}static product(t,e,s){s||(s=new q);const i=t.x,n=t.y,h=t.z,a=t.w,u=e.x,r=e.y,l=e.z,o=e.w;return s.x=i*o+a*u+n*l-h*r,s.y=n*o+a*r+h*u-i*l,s.z=h*o+a*l+i*r-n*u,s.w=a*o-i*u-n*r-h*l,s}static cross(t,e,s){s||(s=new q);const i=t.x,n=t.y,h=t.z,a=t.w,u=e.x,r=e.y,l=e.z,o=e.w;return s.x=a*l+h*o+i*r-n*u,s.y=a*o-i*u-n*r-h*l,s.z=a*u+i*o+n*l-h*r,s.w=a*r+n*o+h*u-i*l,s}static shortMix(t,e,s,i){if(i||(i=new q),s<=0)return i.xyzw=t.xyzw,i;if(s>=1)return i.xyzw=e.xyzw,i;let n=q.dot(t,e);const h=e.copy();let a,u;if(n<0&&(h.inverse(),n=-n),n>.9999)a=1-s,u=0+s;else{const t=Math.sqrt(1-n*n),e=Math.atan2(t,n),i=1/t;a=Math.sin((1-s)*e)*i,u=Math.sin((0+s)*e)*i}return i.x=a*t.x+u*h.x,i.y=a*t.y+u*h.y,i.z=a*t.z+u*h.z,i.w=a*t.w+u*h.w,i}static mix(t,e,s,i){i||(i=new q);const n=t.x*e.x+t.y*e.y+t.z*e.z+t.w*e.w;if(Math.abs(n)>=1)return i.xyzw=t.xyzw,i;const h=Math.acos(n),a=Math.sqrt(1-n*n);if(Math.abs(a)<.001)return i.x=.5*t.x+.5*e.x,i.y=.5*t.y+.5*e.y,i.z=.5*t.z+.5*e.z,i.w=.5*t.w+.5*e.w,i;const u=Math.sin((1-s)*h)/a,r=Math.sin(s*h)/a;return i.x=t.x*u+e.x*r,i.y=t.y*u+e.y*r,i.z=t.z*u+e.z*r,i.w=t.w*u+e.w*r,i}static fromAxisAngle(t,e,s){s||(s=new q),e*=.5;const i=Math.sin(e);return s.x=t.x*i,s.y=t.y*i,s.z=t.z*i,s.w=Math.cos(e),s}}q.identity=(new q).setIdentity();class A{constructor(t){this.values=new Float32Array(3),void 0!==t&&(this.xyz=t)}get x(){return this.values[0]}get y(){return this.values[1]}get z(){return this.values[2]}get xy(){return[this.values[0],this.values[1]]}get xyz(){return[this.values[0],this.values[1],this.values[2]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set z(t){this.values[2]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}set xyz(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}at(t){return this.values[t]}reset(){this.x=0,this.y=0,this.z=0}copy(t){return t||(t=new A),t.x=this.x,t.y=this.y,t.z=this.z,t}negate(t){return t||(t=this),t.x=-this.x,t.y=-this.y,t.z=-this.z,t}equals(t,e=1e-5){return!(Math.abs(this.x-t.x)>e||Math.abs(this.y-t.y)>e||Math.abs(this.z-t.z)>e)}length(){return Math.sqrt(this.squaredLength())}squaredLength(){const t=this.x,e=this.y,s=this.z;return t*t+e*e+s*s}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}subtract(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}scale(t,e){return e||(e=this),e.x*=t,e.y*=t,e.z*=t,e}normalize(t){t||(t=this);let e=this.length();return 1===e?this:0===e?(t.x=0,t.y=0,t.z=0,t):(e=1/e,t.x*=e,t.y*=e,t.z*=e,t)}multiplyByMat3(t,e){return e||(e=this),t.multiplyVec3(this,e)}multiplyByQuat(t,e){return e||(e=this),t.multiplyVec3(this,e)}toQuat(t){t||(t=new q);const e=new A,s=new A;return e.x=Math.cos(.5*this.x),s.x=Math.sin(.5*this.x),e.y=Math.cos(.5*this.y),s.y=Math.sin(.5*this.y),e.z=Math.cos(.5*this.z),s.z=Math.sin(.5*this.z),t.x=s.x*e.y*e.z-e.x*s.y*s.z,t.y=e.x*s.y*e.z+s.x*e.y*s.z,t.z=e.x*e.y*s.z-s.x*s.y*e.z,t.w=e.x*e.y*e.z+s.x*s.y*s.z,t}static cross(t,e,s){s||(s=new A);const i=t.x,n=t.y,h=t.z,a=e.x,u=e.y,r=e.z;return s.x=n*r-h*u,s.y=h*a-i*r,s.z=i*u-n*a,s}static dot(t,e){const s=t.x,i=t.y,n=t.z;return s*e.x+i*e.y+n*e.z}static distance(t,e){return e.x,t.x,e.y,t.y,e.z,t.z,Math.sqrt(this.squaredDistance(t,e))}static squaredDistance(t,e){const s=e.x-t.x,i=e.y-t.y,n=e.z-t.z;return s*s+i*i+n*n}static direction(t,e,s){s||(s=new A);const i=t.x-e.x,n=t.y-e.y,h=t.z-e.z;let a=Math.sqrt(i*i+n*n+h*h);return 0===a?(s.x=0,s.y=0,s.z=0,s):(a=1/a,s.x=i*a,s.y=n*a,s.z=h*a,s)}static mix(t,e,s,i){return i||(i=new A),i.x=t.x+s*(e.x-t.x),i.y=t.y+s*(e.y-t.y),i.z=t.z+s*(e.z-t.z),i}static sum(t,e,s){return s||(s=new A),s.x=t.x+e.x,s.y=t.y+e.y,s.z=t.z+e.z,s}static difference(t,e,s){return s||(s=new A),s.x=t.x-e.x,s.y=t.y-e.y,s.z=t.z-e.z,s}static product(t,e,s){return s||(s=new A),s.x=t.x*e.x,s.y=t.y*e.y,s.z=t.z*e.z,s}static quotient(t,e,s){return s||(s=new A),s.x=t.x/e.x,s.y=t.y/e.y,s.z=t.z/e.z,s}}A.zero=new A([0,0,0]),A.one=new A([1,1,1]),A.up=new A([0,1,0]),A.right=new A([1,0,0]),A.forward=new A([0,0,1]),(c=o||(o={}))[c.WorldSource=0]="WorldSource",c[c.UISource=1]="UISource",c[c.MasterSource=2]="MasterSource";class L{speak(t){}stop(){}setOptions(t){}}class _ extends L{constructor(t={}){super(),this.timeout=100,this.timeout=t.timeout||100,this.init()}init(){this.container=document.createElement("div"),this.container.setAttribute("aria-live","polite"),this.speechDisplay=document.createElement("div"),this.speechDisplay.setAttribute("aria-live","polite"),this.container.append(this.speechDisplay),document.body.appendChild(this.container),document.body.insertBefore(this.container,document.body.firstChild)}speak(t){this.clearDisplay();const e=document.createTextNode(t),s=document.createElement("p");s.appendChild(e),this.speechDisplay.appendChild(s),setTimeout(this.clearDisplay.bind(this),this.timeout)}stop(){this.clearDisplay()}clearDisplay(){this.speechDisplay.innerHTML=""}}class O extends L{}class F{constructor(t=function(t="aria"){return"webtts"===t?O:_}()){this.output=t}speak(t){this.output.speak(t)}stop(){this.output.stop()}}class N{constructor(t=null){this.soundSet=null,this.data=new Map,this.soundSet=t}setSoundSet(t){this.soundSet=t}handleSound(t,e=null){switch(t){case"edit":this.handleEditSound(e);break;case"slider":this.handleSliderSound(e);break;case"selector":this.handleSelectorSound(e);break;case"checkbox":this.handleCheckboxSound(e);break;case"focus":this.handleFocusSound();break;case"choose":this.handleChooseSound();break;case"open":this.handleOpenSound();break;case"close":this.handleCloseSound();break;default:return}}handleEditSound(t){const e=this.data.get("edit")||"";t.length<=e.length?this.soundSet.delete&&this.soundSet.delete.play():this.soundSet.char&&this.soundSet.char.play(),this.data.set("edit",t)}handleSelectorSound(t){this.soundSet.scroller&&this.soundSet.scroller.play()}handleSliderSound(t){tthis.menu.clickCancelAction()}handler(t){switch(t.key){case"ArrowDown":t.preventDefault(),this.menu.focusNext();break;case"ArrowUp":t.preventDefault(),this.menu.focusPrevious();break;case"Enter":t.preventDefault(),this.menu.clickDefaultAction();break;case"Escape":t.preventDefault(),this.menu.clickCancelAction()}}release(){this.menu.getContainer().removeEventListener("keydown",this.handler.bind(this)),window.onpopstate=null}}class T extends t{constructor(t,e){super(),this.id=t,this.title=e}getDOMNode(){let t=document.createTextNode(this.title),e=document.createElement("div");return e.appendChild(t),e}getContents(){}onFocus(t){this.emit("focus",this.id)}focus(){this.container&&this.container.focus()}click(){}getID(){return this.id}}class B extends T{constructor(t,e,s,i=!1){super(t,e),this.initialText=s,this.isPassword=i,this.contents=s}getDOMNode(){const t=document.createElement("div"),e=document.createElement("label");e.setAttribute("for",`edit_${this.id}`),e.textContent=this.title;const s=document.createElement("input");return s.id=`edit_${this.id}`,s.value=this.contents,s.addEventListener("keydown",this.onChange.bind(this)),s.addEventListener("focus",this.onFocus.bind(this)),this.isPassword&&(s.type="password"),t.appendChild(e),t.appendChild(s),t.addEventListener("focus",this.onFocus.bind(this)),this.editField=s,this.label=e,this.container=t,t}getContents(){return this.editField.value}onChange(t){this.emit("update",{type:"edit",value:this.editField.value})}focus(){this.editField&&this.editField.focus()}}class $ extends T{constructor(t,e){super(t,e)}getDOMNode(){const t=document.createElement("div"),e=document.createElement("button");return e.textContent=this.title,e.addEventListener("click",this.handleClick.bind(this)),e.addEventListener("focus",this.onFocus.bind(this)),t.appendChild(e),this.container=t,this.button=e,t}getContents(){return this.id}handleClick(t){this.emit("choose",this.id)}focus(){this.button&&this.button.focus()}click(){this.button.click()}}class V extends T{constructor(t,e,s){super(t,e),this.items=s,this.entries=[]}getDOMNode(){this.container=document.createElement("div"),this.listContainer=document.createElement("ul"),this.label=document.createElement("legend"),this.fieldSet=document.createElement("fieldset"),this.fieldSet.setAttribute("class","radiogroup"),this.fieldSet.id=`fs_selector_${this.id}`;const t=document.createTextNode(this.title);return this.label.appendChild(t),this.fieldSet.appendChild(this.label),this.buildEntries(),this.container.appendChild(this.fieldSet),this.container.addEventListener("focus",this.onFocus.bind(this)),this.container}buildEntries(){this.items.forEach(((t,e)=>{const s=document.createElement("input");s.type="radio",s.id=`${this.id}_${t.id}`,s.name=this.id,s.value=t.id||`${e}`,s.addEventListener("focus",this.onItemFocus.bind(this)),s.addEventListener("select",this.onSelectItem.bind(this)),s.addEventListener("change",this.onChangeItem.bind(this)),this.entries.push(s);const i=document.createElement("label");i.setAttribute("for",`${this.id}_${t.id}`),i.textContent=t.title,this.fieldSet.append(s),this.fieldSet.append(i)}))}onItemFocus(t){console.log("Item focused: ",t),this.emit("focus",this.id)}getContents(){return this.currentValue}onSelectItem(t){}onChangeItem(t){const e=document.querySelector(`input[name = "${this.id}"]:checked`);this.currentValue=this.items.find((t=>`${this.id}_${t.id}`===e.id)),this.emit("update",{type:"selector",value:this.currentValue})}focus(){(document.querySelector(`input[name = "${this.id}"]:checked`)||this.entries[0]).focus()}}class U extends T{constructor(t,e,s,i,n,h=null){super(t,e),this.min=s,this.max=i,this.step=n,this.defaultValue=h}getDOMNode(){return this.container=document.createElement("div"),this.label=document.createElement("label"),this.label.textContent=this.title,this.label.setAttribute("for",`slider_${this.id}`),this.slider=document.createElement("input"),this.slider.id=`slider_${this.id}`,this.slider.type="range",this.slider.setAttribute("min",this.min.toString()),this.slider.setAttribute("max",this.max.toString()),this.slider.setAttribute("step",this.step.toString()),this.defaultValue&&(this.slider.value=this.defaultValue.toString()),this.slider.addEventListener("change",this.onChange.bind(this)),this.slider.addEventListener("focus",this.onFocus.bind(this)),this.container.appendChild(this.label),this.container.appendChild(this.slider),this.container.addEventListener("focus",this.onFocus.bind(this)),this.container}getContents(){return this.slider.value}onChange(t){this.emit("update",{type:"slider",value:this.slider.value})}focus(){this.slider&&this.slider.focus()}}class R extends T{constructor(t,e){super(t,e)}getDOMNode(){return this.container=document.createElement("div"),this.label=document.createElement("label"),this.label.setAttribute("for",`chkbx_${this.id}`),this.label.textContent=this.title,this.checkboxElement=document.createElement("input"),this.checkboxElement.setAttribute("type","checkbox"),this.checkboxElement.setAttribute("id",`chkbx_${this.id}`),this.checkboxElement.addEventListener("focus",this.onFocus.bind(this)),this.checkboxElement.addEventListener("change",this.onChange.bind(this)),this.container.appendChild(this.label),this.container.appendChild(this.checkboxElement),this.container}getContents(){return this.checkboxElement.checked}onChange(t){this.emit("update",{type:"checkbox",value:this.checkboxElement.checked})}focus(){this.checkboxElement.focus()}}class Q extends t{constructor(t="Menu",e=[],s=null,i=null,n=null){super(),this.title=t,this.menuItems=e,this.soundSet=s,this.defaultAction=i,this.cancelAction=n,this.currentIndex=0,this.DOMNodes=[],this.currentIndex=0,this.currentItem=null,this.soundManager=new N(s),this.keyboardManager=new J(this),this.init()}init(){this.menuItems[this.currentIndex]&&this.menuItems[this.currentIndex].focus(),this.emit("init")}addItem(t){return this.menuItems.push(t),this.emit("item.add",t),this}setTitle(t){return this.title=t,this}setSoundSet(t){return this.soundSet=t,this.soundManager.setSoundSet(this.soundSet),this}setDefaultAction(t){return this.defaultAction=t,this}setCancelAction(t){return this.cancelAction=t,this}run(t){return e=this,s=void 0,n=function*(){return new Promise(((e,s)=>{this.element=t,this.container=document.createElement("div"),this.titleContainer=document.createElement("h1"),this.titleContainer.textContent=this.title,this.container.appendChild(this.titleContainer),this.menuItems.forEach((t=>{this.appendToContainer(t.getDOMNode()),t.on("update",this.handleItemUpdate.bind(this)),t.on("focus",this.onItemFocus.bind(this)),t.on("choose",(t=>{const s=this.compile();this.soundManager.handleSound("choose"),this.emit("choose",s),e(s)}))})),t.appendChild(this.container),this.soundManager.handleSound("open"),this.keyboardManager.init(),history.pushState({menu:!0},null,null)}))},new((i=void 0)||(i=Promise))((function(t,h){function a(t){try{r(n.next(t))}catch(t){h(t)}}function u(t){try{r(n.throw(t))}catch(t){h(t)}}function r(e){var s;e.done?t(e.value):(s=e.value,s instanceof i?s:new i((function(t){t(s)}))).then(a,u)}r((n=n.apply(e,s||[])).next())}));var e,s,i,n}close(){this.container.remove(),this.soundManager.handleSound("close"),this.keyboardManager.release(),this.DOMNodes.forEach((t=>{this.container.removeChild(t)})),this.emit("close")}appendToContainer(t){this.container.appendChild(t),this.DOMNodes.push(t)}handleItemUpdate(t){this.soundManager.handleSound(t.type,t.value),this.emit("update",this.compile())}onItemFocus(t){this.soundManager.handleSound("focus"),this.currentIndex=this.menuItems.indexOf(this.menuItems.find((e=>e.getID()==t))),this.emit("focus",this.menuItems[this.currentIndex])}focusNext(){this.currentIndex0&&this.currentIndex--,this.focusCurrentIndex()}focusCurrentIndex(){this.menuItems[this.currentIndex].focus()}getCurrentFocus(){return this.menuItems[this.currentIndex]}getContainer(){return this.container}clickDefaultAction(){this.defaultAction&&this.menuItems.find((t=>t.getID()===this.defaultAction)).click()}clickCancelAction(){this.cancelAction&&this.menuItems.find((t=>t.getID()===this.cancelAction)).click()}compile(){const t=new Map;return this.menuItems.forEach((e=>t.set(e.getID(),e.getContents()))),t.set("selected",this.menuItems[this.currentIndex].getID()),t}}})(),Engine=i})();
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,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aEMsU0FDbkQ0QyxLIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vRW5naW5lLy4vbm9kZV9tb2R1bGVzL2V2ZW50ZW1pdHRlcjMvaW5kZXguanMiLCJ3ZWJwYWNrOi8vRW5naW5lL3dlYnBhY2svYm9vdHN0cmFwIiwid2VicGFjazovL0VuZ2luZS93ZWJwYWNrL3J1bnRpbWUvY29tcGF0IGdldCBkZWZhdWx0IGV4cG9ydCIsIndlYnBhY2s6Ly9FbmdpbmUvd2VicGFjay9ydW50aW1lL2RlZmluZSBwcm9wZXJ0eSBnZXR0ZXJzIiwid2VicGFjazovL0VuZ2luZS93ZWJwYWNrL3J1bnRpbWUvaGFzT3duUHJvcGVydHkgc2hvcnRoYW5kIiwid2VicGFjazovL0VuZ2luZS93ZWJwYWNrL3J1bnRpbWUvbWFrZSBuYW1lc3BhY2Ugb2JqZWN0Iiwid2VicGFjazovL0VuZ2luZS8uL2Rpc3QvYXNzZXQtbWFuYWdlci91dGlscy5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L2Fzc2V0LW1hbmFnZXIvZG93bmxvYWRlci5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L2Fzc2V0LW1hbmFnZXIvcXVldWUuanMiLCJ3ZWJwYWNrOi8vRW5naW5lLy4vZGlzdC9hc3NldC1tYW5hZ2VyL21hbmlmZXN0LmpzIiwid2VicGFjazovL0VuZ2luZS8uL2Rpc3QvYXNzZXQtbWFuYWdlci9zdG9yYWdlLmpzIiwid2VicGFjazovL0VuZ2luZS8uL2Rpc3QvYXNzZXQtbWFuYWdlci9pbmRleC5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3Jlc29uYXRvci9zb3VyY2VzL3NvdXJjZS10eXBlLmpzIiwid2VicGFjazovL0VuZ2luZS9leHRlcm5hbCB2YXIge1wiY29tbW9uanNcIjpcInlhbWxcIixcImNvbW1vbmpzMlwiOlwieWFtbFwiLFwiYW1kXCI6XCJ5YW1sXCIsXCJyb290XCI6XCJfXCJ9Iiwid2VicGFjazovL0VuZ2luZS8uL2Rpc3QvZWNzL2VudGl0eS5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L2V2ZW50LWJ1cy9pbmRleC5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L2Vjcy9xdWVyeS5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L2Vjcy9zeXN0ZW0uanMiLCJ3ZWJwYWNrOi8vRW5naW5lLy4vZGlzdC9lY3MvaW5kZXguanMiLCJ3ZWJwYWNrOi8vRW5naW5lLy4vZGlzdC9pbnB1dC9pbnB1dHMvYmFzZS1pbnB1dC5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L2lucHV0L2lucHV0cy9rZXlib2FyZC5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L2lucHV0L2lucHV0cy9tb3VzZS5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L2lucHV0L2luZGV4LmpzIiwid2VicGFjazovL0VuZ2luZS8uL2Rpc3QvaW5wdXQvaW5wdXQtZmFjdG9yeS5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3RzbS92ZWM0LmpzIiwid2VicGFjazovL0VuZ2luZS8uL2Rpc3QvdHNtL21hdDQuanMiLCJ3ZWJwYWNrOi8vRW5naW5lLy4vZGlzdC90c20vdmVjMi5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3RzbS9tYXQzLmpzIiwid2VicGFjazovL0VuZ2luZS8uL2Rpc3QvdHNtL3F1YXQuanMiLCJ3ZWJwYWNrOi8vRW5naW5lLy4vZGlzdC90c20vdmVjMy5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3R0cy9vdXRwdXRzL2Jhc2Utb3V0cHV0LmpzIiwid2VicGFjazovL0VuZ2luZS8uL2Rpc3QvdHRzL291dHB1dHMvYXJpYS5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3R0cy9vdXRwdXRzL3dlYnR0cy5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3R0cy9pbmRleC5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3R0cy9vdXRwdXQtZmFjdG9yeS5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3VpL21lbnUvc291bmQtbWFuYWdlci5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3VpL21lbnUva2V5Ym9hcmQtbWFuYWdlci5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3VpL21lbnUvaXRlbXMvYmFzZS1pdGVtLmpzIiwid2VicGFjazovL0VuZ2luZS8uL2Rpc3QvdWkvbWVudS9pdGVtcy9lZGl0LWl0ZW0uanMiLCJ3ZWJwYWNrOi8vRW5naW5lLy4vZGlzdC91aS9tZW51L2l0ZW1zL21lbnUtaXRlbS5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3VpL21lbnUvaXRlbXMvc2VsZWN0b3ItaXRlbS5qcyIsIndlYnBhY2s6Ly9FbmdpbmUvLi9kaXN0L3VpL21lbnUvaXRlbXMvc2xpZGVyLWl0ZW0uanMiLCJ3ZWJwYWNrOi8vRW5naW5lLy4vZGlzdC91aS9tZW51L2l0ZW1zL2NoZWNrYm94LWl0ZW0uanMiLCJ3ZWJwYWNrOi8vRW5naW5lLy4vZGlzdC91aS9tZW51L2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIid1c2Ugc3RyaWN0JztcblxudmFyIGhhcyA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHlcbiAgLCBwcmVmaXggPSAnfic7XG5cbi8qKlxuICogQ29uc3RydWN0b3IgdG8gY3JlYXRlIGEgc3RvcmFnZSBmb3Igb3VyIGBFRWAgb2JqZWN0cy5cbiAqIEFuIGBFdmVudHNgIGluc3RhbmNlIGlzIGEgcGxhaW4gb2JqZWN0IHdob3NlIHByb3BlcnRpZXMgYXJlIGV2ZW50IG5hbWVzLlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gRXZlbnRzKCkge31cblxuLy9cbi8vIFdlIHRyeSB0byBub3QgaW5oZXJpdCBmcm9tIGBPYmplY3QucHJvdG90eXBlYC4gSW4gc29tZSBlbmdpbmVzIGNyZWF0aW5nIGFuXG4vLyBpbnN0YW5jZSBpbiB0aGlzIHdheSBpcyBmYXN0ZXIgdGhhbiBjYWxsaW5nIGBPYmplY3QuY3JlYXRlKG51bGwpYCBkaXJlY3RseS5cbi8vIElmIGBPYmplY3QuY3JlYXRlKG51bGwpYCBpcyBub3Qgc3VwcG9ydGVkIHdlIHByZWZpeCB0aGUgZXZlbnQgbmFtZXMgd2l0aCBhXG4vLyBjaGFyYWN0ZXIgdG8gbWFrZSBzdXJlIHRoYXQgdGhlIGJ1aWx0LWluIG9iamVjdCBwcm9wZXJ0aWVzIGFyZSBub3Rcbi8vIG92ZXJyaWRkZW4gb3IgdXNlZCBhcyBhbiBhdHRhY2sgdmVjdG9yLlxuLy9cbmlmIChPYmplY3QuY3JlYXRlKSB7XG4gIEV2ZW50cy5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuXG4gIC8vXG4gIC8vIFRoaXMgaGFjayBpcyBuZWVkZWQgYmVjYXVzZSB0aGUgYF9fcHJvdG9fX2AgcHJvcGVydHkgaXMgc3RpbGwgaW5oZXJpdGVkIGluXG4gIC8vIHNvbWUgb2xkIGJyb3dzZXJzIGxpa2UgQW5kcm9pZCA0LCBpUGhvbmUgNS4xLCBPcGVyYSAxMSBhbmQgU2FmYXJpIDUuXG4gIC8vXG4gIGlmICghbmV3IEV2ZW50cygpLl9fcHJvdG9fXykgcHJlZml4ID0gZmFsc2U7XG59XG5cbi8qKlxuICogUmVwcmVzZW50YXRpb24gb2YgYSBzaW5nbGUgZXZlbnQgbGlzdGVuZXIuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uLlxuICogQHBhcmFtIHsqfSBjb250ZXh0IFRoZSBjb250ZXh0IHRvIGludm9rZSB0aGUgbGlzdGVuZXIgd2l0aC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gW29uY2U9ZmFsc2VdIFNwZWNpZnkgaWYgdGhlIGxpc3RlbmVyIGlzIGEgb25lLXRpbWUgbGlzdGVuZXIuXG4gKiBAY29uc3RydWN0b3JcbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIEVFKGZuLCBjb250ZXh0LCBvbmNlKSB7XG4gIHRoaXMuZm4gPSBmbjtcbiAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcbiAgdGhpcy5vbmNlID0gb25jZSB8fCBmYWxzZTtcbn1cblxuLyoqXG4gKiBBZGQgYSBsaXN0ZW5lciBmb3IgYSBnaXZlbiBldmVudC5cbiAqXG4gKiBAcGFyYW0ge0V2ZW50RW1pdHRlcn0gZW1pdHRlciBSZWZlcmVuY2UgdG8gdGhlIGBFdmVudEVtaXR0ZXJgIGluc3RhbmNlLlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uLlxuICogQHBhcmFtIHsqfSBjb250ZXh0IFRoZSBjb250ZXh0IHRvIGludm9rZSB0aGUgbGlzdGVuZXIgd2l0aC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gb25jZSBTcGVjaWZ5IGlmIHRoZSBsaXN0ZW5lciBpcyBhIG9uZS10aW1lIGxpc3RlbmVyLlxuICogQHJldHVybnMge0V2ZW50RW1pdHRlcn1cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGFkZExpc3RlbmVyKGVtaXR0ZXIsIGV2ZW50LCBmbiwgY29udGV4dCwgb25jZSkge1xuICBpZiAodHlwZW9mIGZuICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVGhlIGxpc3RlbmVyIG11c3QgYmUgYSBmdW5jdGlvbicpO1xuICB9XG5cbiAgdmFyIGxpc3RlbmVyID0gbmV3IEVFKGZuLCBjb250ZXh0IHx8IGVtaXR0ZXIsIG9uY2UpXG4gICAgLCBldnQgPSBwcmVmaXggPyBwcmVmaXggKyBldmVudCA6IGV2ZW50O1xuXG4gIGlmICghZW1pdHRlci5fZXZlbnRzW2V2dF0pIGVtaXR0ZXIuX2V2ZW50c1tldnRdID0gbGlzdGVuZXIsIGVtaXR0ZXIuX2V2ZW50c0NvdW50Kys7XG4gIGVsc2UgaWYgKCFlbWl0dGVyLl9ldmVudHNbZXZ0XS5mbikgZW1pdHRlci5fZXZlbnRzW2V2dF0ucHVzaChsaXN0ZW5lcik7XG4gIGVsc2UgZW1pdHRlci5fZXZlbnRzW2V2dF0gPSBbZW1pdHRlci5fZXZlbnRzW2V2dF0sIGxpc3RlbmVyXTtcblxuICByZXR1cm4gZW1pdHRlcjtcbn1cblxuLyoqXG4gKiBDbGVhciBldmVudCBieSBuYW1lLlxuICpcbiAqIEBwYXJhbSB7RXZlbnRFbWl0dGVyfSBlbWl0dGVyIFJlZmVyZW5jZSB0byB0aGUgYEV2ZW50RW1pdHRlcmAgaW5zdGFuY2UuXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZ0IFRoZSBFdmVudCBuYW1lLlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gY2xlYXJFdmVudChlbWl0dGVyLCBldnQpIHtcbiAgaWYgKC0tZW1pdHRlci5fZXZlbnRzQ291bnQgPT09IDApIGVtaXR0ZXIuX2V2ZW50cyA9IG5ldyBFdmVudHMoKTtcbiAgZWxzZSBkZWxldGUgZW1pdHRlci5fZXZlbnRzW2V2dF07XG59XG5cbi8qKlxuICogTWluaW1hbCBgRXZlbnRFbWl0dGVyYCBpbnRlcmZhY2UgdGhhdCBpcyBtb2xkZWQgYWdhaW5zdCB0aGUgTm9kZS5qc1xuICogYEV2ZW50RW1pdHRlcmAgaW50ZXJmYWNlLlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQHB1YmxpY1xuICovXG5mdW5jdGlvbiBFdmVudEVtaXR0ZXIoKSB7XG4gIHRoaXMuX2V2ZW50cyA9IG5ldyBFdmVudHMoKTtcbiAgdGhpcy5fZXZlbnRzQ291bnQgPSAwO1xufVxuXG4vKipcbiAqIFJldHVybiBhbiBhcnJheSBsaXN0aW5nIHRoZSBldmVudHMgZm9yIHdoaWNoIHRoZSBlbWl0dGVyIGhhcyByZWdpc3RlcmVkXG4gKiBsaXN0ZW5lcnMuXG4gKlxuICogQHJldHVybnMge0FycmF5fVxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmV2ZW50TmFtZXMgPSBmdW5jdGlvbiBldmVudE5hbWVzKCkge1xuICB2YXIgbmFtZXMgPSBbXVxuICAgICwgZXZlbnRzXG4gICAgLCBuYW1lO1xuXG4gIGlmICh0aGlzLl9ldmVudHNDb3VudCA9PT0gMCkgcmV0dXJuIG5hbWVzO1xuXG4gIGZvciAobmFtZSBpbiAoZXZlbnRzID0gdGhpcy5fZXZlbnRzKSkge1xuICAgIGlmIChoYXMuY2FsbChldmVudHMsIG5hbWUpKSBuYW1lcy5wdXNoKHByZWZpeCA/IG5hbWUuc2xpY2UoMSkgOiBuYW1lKTtcbiAgfVxuXG4gIGlmIChPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKSB7XG4gICAgcmV0dXJuIG5hbWVzLmNvbmNhdChPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKGV2ZW50cykpO1xuICB9XG5cbiAgcmV0dXJuIG5hbWVzO1xufTtcblxuLyoqXG4gKiBSZXR1cm4gdGhlIGxpc3RlbmVycyByZWdpc3RlcmVkIGZvciBhIGdpdmVuIGV2ZW50LlxuICpcbiAqIEBwYXJhbSB7KFN0cmluZ3xTeW1ib2wpfSBldmVudCBUaGUgZXZlbnQgbmFtZS5cbiAqIEByZXR1cm5zIHtBcnJheX0gVGhlIHJlZ2lzdGVyZWQgbGlzdGVuZXJzLlxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmxpc3RlbmVycyA9IGZ1bmN0aW9uIGxpc3RlbmVycyhldmVudCkge1xuICB2YXIgZXZ0ID0gcHJlZml4ID8gcHJlZml4ICsgZXZlbnQgOiBldmVudFxuICAgICwgaGFuZGxlcnMgPSB0aGlzLl9ldmVudHNbZXZ0XTtcblxuICBpZiAoIWhhbmRsZXJzKSByZXR1cm4gW107XG4gIGlmIChoYW5kbGVycy5mbikgcmV0dXJuIFtoYW5kbGVycy5mbl07XG5cbiAgZm9yICh2YXIgaSA9IDAsIGwgPSBoYW5kbGVycy5sZW5ndGgsIGVlID0gbmV3IEFycmF5KGwpOyBpIDwgbDsgaSsrKSB7XG4gICAgZWVbaV0gPSBoYW5kbGVyc1tpXS5mbjtcbiAgfVxuXG4gIHJldHVybiBlZTtcbn07XG5cbi8qKlxuICogUmV0dXJuIHRoZSBudW1iZXIgb2YgbGlzdGVuZXJzIGxpc3RlbmluZyB0byBhIGdpdmVuIGV2ZW50LlxuICpcbiAqIEBwYXJhbSB7KFN0cmluZ3xTeW1ib2wpfSBldmVudCBUaGUgZXZlbnQgbmFtZS5cbiAqIEByZXR1cm5zIHtOdW1iZXJ9IFRoZSBudW1iZXIgb2YgbGlzdGVuZXJzLlxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmxpc3RlbmVyQ291bnQgPSBmdW5jdGlvbiBsaXN0ZW5lckNvdW50KGV2ZW50KSB7XG4gIHZhciBldnQgPSBwcmVmaXggPyBwcmVmaXggKyBldmVudCA6IGV2ZW50XG4gICAgLCBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbZXZ0XTtcblxuICBpZiAoIWxpc3RlbmVycykgcmV0dXJuIDA7XG4gIGlmIChsaXN0ZW5lcnMuZm4pIHJldHVybiAxO1xuICByZXR1cm4gbGlzdGVuZXJzLmxlbmd0aDtcbn07XG5cbi8qKlxuICogQ2FsbHMgZWFjaCBvZiB0aGUgbGlzdGVuZXJzIHJlZ2lzdGVyZWQgZm9yIGEgZ2l2ZW4gZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHJldHVybnMge0Jvb2xlYW59IGB0cnVlYCBpZiB0aGUgZXZlbnQgaGFkIGxpc3RlbmVycywgZWxzZSBgZmFsc2VgLlxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmVtaXQgPSBmdW5jdGlvbiBlbWl0KGV2ZW50LCBhMSwgYTIsIGEzLCBhNCwgYTUpIHtcbiAgdmFyIGV2dCA9IHByZWZpeCA/IHByZWZpeCArIGV2ZW50IDogZXZlbnQ7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHNbZXZ0XSkgcmV0dXJuIGZhbHNlO1xuXG4gIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbZXZ0XVxuICAgICwgbGVuID0gYXJndW1lbnRzLmxlbmd0aFxuICAgICwgYXJnc1xuICAgICwgaTtcblxuICBpZiAobGlzdGVuZXJzLmZuKSB7XG4gICAgaWYgKGxpc3RlbmVycy5vbmNlKSB0aGlzLnJlbW92ZUxpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcnMuZm4sIHVuZGVmaW5lZCwgdHJ1ZSk7XG5cbiAgICBzd2l0Y2ggKGxlbikge1xuICAgICAgY2FzZSAxOiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQpLCB0cnVlO1xuICAgICAgY2FzZSAyOiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQsIGExKSwgdHJ1ZTtcbiAgICAgIGNhc2UgMzogcmV0dXJuIGxpc3RlbmVycy5mbi5jYWxsKGxpc3RlbmVycy5jb250ZXh0LCBhMSwgYTIpLCB0cnVlO1xuICAgICAgY2FzZSA0OiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQsIGExLCBhMiwgYTMpLCB0cnVlO1xuICAgICAgY2FzZSA1OiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQsIGExLCBhMiwgYTMsIGE0KSwgdHJ1ZTtcbiAgICAgIGNhc2UgNjogcmV0dXJuIGxpc3RlbmVycy5mbi5jYWxsKGxpc3RlbmVycy5jb250ZXh0LCBhMSwgYTIsIGEzLCBhNCwgYTUpLCB0cnVlO1xuICAgIH1cblxuICAgIGZvciAoaSA9IDEsIGFyZ3MgPSBuZXcgQXJyYXkobGVuIC0xKTsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcbiAgICB9XG5cbiAgICBsaXN0ZW5lcnMuZm4uYXBwbHkobGlzdGVuZXJzLmNvbnRleHQsIGFyZ3MpO1xuICB9IGVsc2Uge1xuICAgIHZhciBsZW5ndGggPSBsaXN0ZW5lcnMubGVuZ3RoXG4gICAgICAsIGo7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChsaXN0ZW5lcnNbaV0ub25jZSkgdGhpcy5yZW1vdmVMaXN0ZW5lcihldmVudCwgbGlzdGVuZXJzW2ldLmZuLCB1bmRlZmluZWQsIHRydWUpO1xuXG4gICAgICBzd2l0Y2ggKGxlbikge1xuICAgICAgICBjYXNlIDE6IGxpc3RlbmVyc1tpXS5mbi5jYWxsKGxpc3RlbmVyc1tpXS5jb250ZXh0KTsgYnJlYWs7XG4gICAgICAgIGNhc2UgMjogbGlzdGVuZXJzW2ldLmZuLmNhbGwobGlzdGVuZXJzW2ldLmNvbnRleHQsIGExKTsgYnJlYWs7XG4gICAgICAgIGNhc2UgMzogbGlzdGVuZXJzW2ldLmZuLmNhbGwobGlzdGVuZXJzW2ldLmNvbnRleHQsIGExLCBhMik7IGJyZWFrO1xuICAgICAgICBjYXNlIDQ6IGxpc3RlbmVyc1tpXS5mbi5jYWxsKGxpc3RlbmVyc1tpXS5jb250ZXh0LCBhMSwgYTIsIGEzKTsgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgaWYgKCFhcmdzKSBmb3IgKGogPSAxLCBhcmdzID0gbmV3IEFycmF5KGxlbiAtMSk7IGogPCBsZW47IGorKykge1xuICAgICAgICAgICAgYXJnc1tqIC0gMV0gPSBhcmd1bWVudHNbal07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgbGlzdGVuZXJzW2ldLmZuLmFwcGx5KGxpc3RlbmVyc1tpXS5jb250ZXh0LCBhcmdzKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbi8qKlxuICogQWRkIGEgbGlzdGVuZXIgZm9yIGEgZ2l2ZW4gZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uLlxuICogQHBhcmFtIHsqfSBbY29udGV4dD10aGlzXSBUaGUgY29udGV4dCB0byBpbnZva2UgdGhlIGxpc3RlbmVyIHdpdGguXG4gKiBAcmV0dXJucyB7RXZlbnRFbWl0dGVyfSBgdGhpc2AuXG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub24gPSBmdW5jdGlvbiBvbihldmVudCwgZm4sIGNvbnRleHQpIHtcbiAgcmV0dXJuIGFkZExpc3RlbmVyKHRoaXMsIGV2ZW50LCBmbiwgY29udGV4dCwgZmFsc2UpO1xufTtcblxuLyoqXG4gKiBBZGQgYSBvbmUtdGltZSBsaXN0ZW5lciBmb3IgYSBnaXZlbiBldmVudC5cbiAqXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZlbnQgVGhlIGV2ZW50IG5hbWUuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgbGlzdGVuZXIgZnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IFtjb250ZXh0PXRoaXNdIFRoZSBjb250ZXh0IHRvIGludm9rZSB0aGUgbGlzdGVuZXIgd2l0aC5cbiAqIEByZXR1cm5zIHtFdmVudEVtaXR0ZXJ9IGB0aGlzYC5cbiAqIEBwdWJsaWNcbiAqL1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbmNlID0gZnVuY3Rpb24gb25jZShldmVudCwgZm4sIGNvbnRleHQpIHtcbiAgcmV0dXJuIGFkZExpc3RlbmVyKHRoaXMsIGV2ZW50LCBmbiwgY29udGV4dCwgdHJ1ZSk7XG59O1xuXG4vKipcbiAqIFJlbW92ZSB0aGUgbGlzdGVuZXJzIG9mIGEgZ2l2ZW4gZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gT25seSByZW1vdmUgdGhlIGxpc3RlbmVycyB0aGF0IG1hdGNoIHRoaXMgZnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IGNvbnRleHQgT25seSByZW1vdmUgdGhlIGxpc3RlbmVycyB0aGF0IGhhdmUgdGhpcyBjb250ZXh0LlxuICogQHBhcmFtIHtCb29sZWFufSBvbmNlIE9ubHkgcmVtb3ZlIG9uZS10aW1lIGxpc3RlbmVycy5cbiAqIEByZXR1cm5zIHtFdmVudEVtaXR0ZXJ9IGB0aGlzYC5cbiAqIEBwdWJsaWNcbiAqL1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVMaXN0ZW5lciA9IGZ1bmN0aW9uIHJlbW92ZUxpc3RlbmVyKGV2ZW50LCBmbiwgY29udGV4dCwgb25jZSkge1xuICB2YXIgZXZ0ID0gcHJlZml4ID8gcHJlZml4ICsgZXZlbnQgOiBldmVudDtcblxuICBpZiAoIXRoaXMuX2V2ZW50c1tldnRdKSByZXR1cm4gdGhpcztcbiAgaWYgKCFmbikge1xuICAgIGNsZWFyRXZlbnQodGhpcywgZXZ0KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbZXZ0XTtcblxuICBpZiAobGlzdGVuZXJzLmZuKSB7XG4gICAgaWYgKFxuICAgICAgbGlzdGVuZXJzLmZuID09PSBmbiAmJlxuICAgICAgKCFvbmNlIHx8IGxpc3RlbmVycy5vbmNlKSAmJlxuICAgICAgKCFjb250ZXh0IHx8IGxpc3RlbmVycy5jb250ZXh0ID09PSBjb250ZXh0KVxuICAgICkge1xuICAgICAgY2xlYXJFdmVudCh0aGlzLCBldnQpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBmb3IgKHZhciBpID0gMCwgZXZlbnRzID0gW10sIGxlbmd0aCA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgaWYgKFxuICAgICAgICBsaXN0ZW5lcnNbaV0uZm4gIT09IGZuIHx8XG4gICAgICAgIChvbmNlICYmICFsaXN0ZW5lcnNbaV0ub25jZSkgfHxcbiAgICAgICAgKGNvbnRleHQgJiYgbGlzdGVuZXJzW2ldLmNvbnRleHQgIT09IGNvbnRleHQpXG4gICAgICApIHtcbiAgICAgICAgZXZlbnRzLnB1c2gobGlzdGVuZXJzW2ldKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvL1xuICAgIC8vIFJlc2V0IHRoZSBhcnJheSwgb3IgcmVtb3ZlIGl0IGNvbXBsZXRlbHkgaWYgd2UgaGF2ZSBubyBtb3JlIGxpc3RlbmVycy5cbiAgICAvL1xuICAgIGlmIChldmVudHMubGVuZ3RoKSB0aGlzLl9ldmVudHNbZXZ0XSA9IGV2ZW50cy5sZW5ndGggPT09IDEgPyBldmVudHNbMF0gOiBldmVudHM7XG4gICAgZWxzZSBjbGVhckV2ZW50KHRoaXMsIGV2dCk7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogUmVtb3ZlIGFsbCBsaXN0ZW5lcnMsIG9yIHRob3NlIG9mIHRoZSBzcGVjaWZpZWQgZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IFtldmVudF0gVGhlIGV2ZW50IG5hbWUuXG4gKiBAcmV0dXJucyB7RXZlbnRFbWl0dGVyfSBgdGhpc2AuXG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlQWxsTGlzdGVuZXJzID0gZnVuY3Rpb24gcmVtb3ZlQWxsTGlzdGVuZXJzKGV2ZW50KSB7XG4gIHZhciBldnQ7XG5cbiAgaWYgKGV2ZW50KSB7XG4gICAgZXZ0ID0gcHJlZml4ID8gcHJlZml4ICsgZXZlbnQgOiBldmVudDtcbiAgICBpZiAodGhpcy5fZXZlbnRzW2V2dF0pIGNsZWFyRXZlbnQodGhpcywgZXZ0KTtcbiAgfSBlbHNlIHtcbiAgICB0aGlzLl9ldmVudHMgPSBuZXcgRXZlbnRzKCk7XG4gICAgdGhpcy5fZXZlbnRzQ291bnQgPSAwO1xuICB9XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG4vL1xuLy8gQWxpYXMgbWV0aG9kcyBuYW1lcyBiZWNhdXNlIHBlb3BsZSByb2xsIGxpa2UgdGhhdC5cbi8vXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9mZiA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlTGlzdGVuZXI7XG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmFkZExpc3RlbmVyID0gRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbjtcblxuLy9cbi8vIEV4cG9zZSB0aGUgcHJlZml4LlxuLy9cbkV2ZW50RW1pdHRlci5wcmVmaXhlZCA9IHByZWZpeDtcblxuLy9cbi8vIEFsbG93IGBFdmVudEVtaXR0ZXJgIHRvIGJlIGltcG9ydGVkIGFzIG1vZHVsZSBuYW1lc3BhY2UuXG4vL1xuRXZlbnRFbWl0dGVyLkV2ZW50RW1pdHRlciA9IEV2ZW50RW1pdHRlcjtcblxuLy9cbi8vIEV4cG9zZSB0aGUgbW9kdWxlLlxuLy9cbmlmICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIG1vZHVsZSkge1xuICBtb2R1bGUuZXhwb3J0cyA9IEV2ZW50RW1pdHRlcjtcbn1cbiIsIi8vIFRoZSBtb2R1bGUgY2FjaGVcbnZhciBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX18gPSB7fTtcblxuLy8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbmZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG5cdHZhciBjYWNoZWRNb2R1bGUgPSBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX19bbW9kdWxlSWRdO1xuXHRpZiAoY2FjaGVkTW9kdWxlICE9PSB1bmRlZmluZWQpIHtcblx0XHRyZXR1cm4gY2FjaGVkTW9kdWxlLmV4cG9ydHM7XG5cdH1cblx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcblx0dmFyIG1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF0gPSB7XG5cdFx0Ly8gbm8gbW9kdWxlLmlkIG5lZWRlZFxuXHRcdC8vIG5vIG1vZHVsZS5sb2FkZWQgbmVlZGVkXG5cdFx0ZXhwb3J0czoge31cblx0fTtcblxuXHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cblx0X193ZWJwYWNrX21vZHVsZXNfX1ttb2R1bGVJZF0obW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cblx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcblx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xufVxuXG4iLCIvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuX193ZWJwYWNrX3JlcXVpcmVfXy5uID0gKG1vZHVsZSkgPT4ge1xuXHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cblx0XHQoKSA9PiAobW9kdWxlWydkZWZhdWx0J10pIDpcblx0XHQoKSA9PiAobW9kdWxlKTtcblx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgeyBhOiBnZXR0ZXIgfSk7XG5cdHJldHVybiBnZXR0ZXI7XG59OyIsIi8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb25zIGZvciBoYXJtb255IGV4cG9ydHNcbl9fd2VicGFja19yZXF1aXJlX18uZCA9IChleHBvcnRzLCBkZWZpbml0aW9uKSA9PiB7XG5cdGZvcih2YXIga2V5IGluIGRlZmluaXRpb24pIHtcblx0XHRpZihfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZGVmaW5pdGlvbiwga2V5KSAmJiAhX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIGtleSkpIHtcblx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBrZXksIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBkZWZpbml0aW9uW2tleV0gfSk7XG5cdFx0fVxuXHR9XG59OyIsIl9fd2VicGFja19yZXF1aXJlX18ubyA9IChvYmosIHByb3ApID0+IChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBwcm9wKSkiLCIvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG5fX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSAoZXhwb3J0cykgPT4ge1xuXHRpZih0eXBlb2YgU3ltYm9sICE9PSAndW5kZWZpbmVkJyAmJiBTeW1ib2wudG9TdHJpbmdUYWcpIHtcblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgU3ltYm9sLnRvU3RyaW5nVGFnLCB7IHZhbHVlOiAnTW9kdWxlJyB9KTtcblx0fVxuXHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xufTsiLCJleHBvcnQgZnVuY3Rpb24gYnVpbGRQYXRoKGJhc2VQYXRoLCBwYXRoKSB7XHJcbiAgICBpZiAoIWJhc2VQYXRoKSB7XHJcbiAgICAgICAgcmV0dXJuIHBhdGg7XHJcbiAgICB9XHJcbiAgICBlbHNlIHtcclxuICAgICAgICByZXR1cm4gYCR7YmFzZVBhdGh9LyR7cGF0aH1gO1xyXG4gICAgfVxyXG59XHJcbiIsInZhciBfX2F3YWl0ZXIgPSAodGhpcyAmJiB0aGlzLl9fYXdhaXRlcikgfHwgZnVuY3Rpb24gKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xyXG4gICAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHsgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgUCA/IHZhbHVlIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHsgcmVzb2x2ZSh2YWx1ZSk7IH0pOyB9XHJcbiAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHsgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7IH1cclxuICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XHJcbiAgICB9KTtcclxufTtcclxuaW1wb3J0IEV2ZW50RW1pdHRlciBmcm9tICdldmVudGVtaXR0ZXIzJztcclxuaW1wb3J0IHsgYnVpbGRQYXRoIH0gZnJvbSAnLi91dGlscyc7XHJcbmV4cG9ydCBjbGFzcyBEb3dubG9hZGVyIGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcclxuICAgIGNvbnN0cnVjdG9yKHN0b3JhZ2UsIHF1ZXVlLCBiYXNlUGF0aCA9ICcnKSB7XHJcbiAgICAgICAgc3VwZXIoKTtcclxuICAgICAgICB0aGlzLnN0b3JhZ2UgPSBzdG9yYWdlO1xyXG4gICAgICAgIHRoaXMucXVldWUgPSBxdWV1ZTtcclxuICAgICAgICB0aGlzLmJhc2VQYXRoID0gYmFzZVBhdGg7XHJcbiAgICB9XHJcbiAgICBzZXRCYXNlUGF0aChwYXRoKSB7XHJcbiAgICAgICAgdGhpcy5iYXNlUGF0aCA9IHRoaXMuYmFzZVBhdGg7XHJcbiAgICB9XHJcbiAgICBkb3dubG9hZCgpIHtcclxuICAgICAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xyXG4gICAgICAgICAgICBjb25zdCBkb3dubG9hZGVkID0gbmV3IE1hcCgpO1xyXG4gICAgICAgICAgICBsZXQgbnVtRG93bmxvYWRlZCA9IDA7XHJcbiAgICAgICAgICAgIHdoaWxlICh0aGlzLnF1ZXVlLmxlbmd0aCgpID4gMCkge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgcGF0aCA9IHRoaXMucXVldWUucG9wKCk7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBpdGVtID0geWllbGQgdGhpcy5kb3dubG9hZEl0ZW0oYnVpbGRQYXRoKHRoaXMuYmFzZVBhdGgsIHBhdGgpKTtcclxuICAgICAgICAgICAgICAgIGRvd25sb2FkZWQuc2V0KHBhdGgsIGl0ZW0pO1xyXG4gICAgICAgICAgICAgICAgbnVtRG93bmxvYWRlZCsrO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdkb3dubG9hZC5wcm9ncmVzcycsIHtcclxuICAgICAgICAgICAgICAgICAgICBkb3dubG9hZGVkOiBudW1Eb3dubG9hZGVkLFxyXG4gICAgICAgICAgICAgICAgICAgIHJlbWFpbmluZzogdGhpcy5xdWV1ZS5sZW5ndGgoKVxyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgcmV0dXJuIGRvd25sb2FkZWQ7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBkb3dubG9hZEl0ZW0ocGF0aCkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGluQ2FjaGUgPSB5aWVsZCB0aGlzLnN0b3JhZ2UuZ2V0KHBhdGgpO1xyXG4gICAgICAgICAgICBpZiAoaW5DYWNoZSkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGluQ2FjaGU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgY29uc3QgcmVzcG9uc2UgPSB5aWVsZCBmZXRjaChwYXRoKTtcclxuICAgICAgICAgICAgdGhpcy5zdG9yYWdlLmFkZChwYXRoLCByZXNwb25zZSk7XHJcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxufVxyXG4iLCJleHBvcnQgY2xhc3MgUXVldWUge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5pdGVtcyA9IFtdO1xyXG4gICAgfVxyXG4gICAgYWRkKGZpbGUpIHtcclxuICAgICAgICB0aGlzLml0ZW1zLnB1c2goZmlsZSk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuaXRlbXM7XHJcbiAgICB9XHJcbiAgICByZW1vdmUoZmlsZSkge1xyXG4gICAgICAgIHRoaXMuaXRlbXMgPSB0aGlzLml0ZW1zLmZpbHRlcigoaXRlbSkgPT4gaXRlbSAhPT0gZmlsZSk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuaXRlbXM7XHJcbiAgICB9XHJcbiAgICBwb3AoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuaXRlbXMucG9wKCk7XHJcbiAgICB9XHJcbiAgICBsZW5ndGgoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuaXRlbXMubGVuZ3RoO1xyXG4gICAgfVxyXG59XHJcbiIsInZhciBfX2F3YWl0ZXIgPSAodGhpcyAmJiB0aGlzLl9fYXdhaXRlcikgfHwgZnVuY3Rpb24gKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xyXG4gICAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHsgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgUCA/IHZhbHVlIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHsgcmVzb2x2ZSh2YWx1ZSk7IH0pOyB9XHJcbiAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHsgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7IH1cclxuICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XHJcbiAgICB9KTtcclxufTtcclxuaW1wb3J0ICogYXMgeWFtbCBmcm9tICd5YW1sJztcclxuZXhwb3J0IGZ1bmN0aW9uIE1hbmlmZXN0KG1hbmlmZXN0UGF0aCkge1xyXG4gICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IHlpZWxkIGZldGNoKG1hbmlmZXN0UGF0aCk7XHJcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKHJlc3BvbnNlKTtcclxuICAgICAgICAgICAgY29uc3QgZGF0YSA9IHlpZWxkIHJlc3BvbnNlLnRleHQoKTtcclxuICAgICAgICAgICAgY29uc29sZS5sb2coYFBhcnNpbmc6IGAsIGRhdGEpO1xyXG4gICAgICAgICAgICBjb25zdCBtYW5pZmVzdCA9IHlhbWwucGFyc2UoZGF0YSk7XHJcbiAgICAgICAgICAgIHJldHVybiBtYW5pZmVzdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIGFsZXJ0KGBFcnJvciBvY2N1cmVkOiAke2Vycm9yLnRvU3RyaW5nKCl9YCk7XHJcbiAgICAgICAgfVxyXG4gICAgfSk7XHJcbn1cclxuZXhwb3J0IGZ1bmN0aW9uIENoZWNrTWFuaWZlc3QobWFuaWZlc3QpIHtcclxuICAgIGNvbnN0IHByZXZNYW5pZmVzdFN0ciA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdtYW5pZmVzdCcpO1xyXG4gICAgaWYgKCFwcmV2TWFuaWZlc3RTdHIpIHtcclxuICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSgnbWFuaWZlc3QnLCBKU09OLnN0cmluZ2lmeShtYW5pZmVzdCkpO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIGNvbnN0IHByZXZNYW5pZmVzdCA9IEpTT04ucGFyc2UocHJldk1hbmlmZXN0U3RyKTtcclxuICAgIGlmIChwcmV2TWFuaWZlc3QudmVyc2lvbiA9PT0gbWFuaWZlc3QudmVyc2lvbikge1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gICAgZWxzZSB7XHJcbiAgICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oJ21hbmlmZXN0JywgbWFuaWZlc3QpO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxufVxyXG4iLCJ2YXIgX19hd2FpdGVyID0gKHRoaXMgJiYgdGhpcy5fX2F3YWl0ZXIpIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcclxuICAgIGZ1bmN0aW9uIGFkb3B0KHZhbHVlKSB7IHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFAgPyB2YWx1ZSA6IG5ldyBQKGZ1bmN0aW9uIChyZXNvbHZlKSB7IHJlc29sdmUodmFsdWUpOyB9KTsgfVxyXG4gICAgcmV0dXJuIG5ldyAoUCB8fCAoUCA9IFByb21pc2UpKShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XHJcbiAgICAgICAgZnVuY3Rpb24gZnVsZmlsbGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7IHJlc3VsdC5kb25lID8gcmVzb2x2ZShyZXN1bHQudmFsdWUpIDogYWRvcHQocmVzdWx0LnZhbHVlKS50aGVuKGZ1bGZpbGxlZCwgcmVqZWN0ZWQpOyB9XHJcbiAgICAgICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xyXG4gICAgfSk7XHJcbn07XHJcbmltcG9ydCB7IENoZWNrTWFuaWZlc3QgfSBmcm9tICcuL21hbmlmZXN0JztcclxuZXhwb3J0IGNsYXNzIEFzc2V0U3RvcmFnZSB7XHJcbiAgICBjb25zdHJ1Y3RvcihpZCkge1xyXG4gICAgICAgIHRoaXMuaWQgPSBpZDtcclxuICAgIH1cclxuICAgIGluaXQoKSB7XHJcbiAgICAgICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcclxuICAgICAgICAgICAgdGhpcy5jYWNoZSA9IHlpZWxkIGNhY2hlcy5vcGVuKHRoaXMuaWQpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgYWRkKHJlcXVlc3QsIHJlc3BvbnNlKSB7XHJcbiAgICAgICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcclxuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0geWllbGQgdGhpcy5jYWNoZS5wdXQocmVxdWVzdCwgcmVzcG9uc2UpO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuICAgIGdldChyZXF1ZXN0KSB7XHJcbiAgICAgICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcclxuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0geWllbGQgdGhpcy5jYWNoZS5tYXRjaChyZXF1ZXN0KTtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuICAgIHNldE1hbmlmZXN0KG1hbmlmZXN0KSB7XHJcbiAgICAgICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcclxuICAgICAgICAgICAgdGhpcy5tYW5pZmVzdCA9IG1hbmlmZXN0O1xyXG4gICAgICAgICAgICBpZiAoIUNoZWNrTWFuaWZlc3QodGhpcy5tYW5pZmVzdCkpIHtcclxuICAgICAgICAgICAgICAgIHlpZWxkIHRoaXMuY2xlYXIoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgY2xlYXIoKSB7XHJcbiAgICAgICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcclxuICAgICAgICAgICAgY29uc3Qga2V5cyA9IHlpZWxkIHRoaXMuY2FjaGUua2V5cygpO1xyXG4gICAgICAgICAgICBrZXlzLmZvckVhY2goKGtleSkgPT4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0geWllbGQgdGhpcy5jYWNoZS5kZWxldGUoa2V5KTtcclxuICAgICAgICAgICAgfSkpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG59XHJcbiIsInZhciBfX2F3YWl0ZXIgPSAodGhpcyAmJiB0aGlzLl9fYXdhaXRlcikgfHwgZnVuY3Rpb24gKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xyXG4gICAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHsgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgUCA/IHZhbHVlIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHsgcmVzb2x2ZSh2YWx1ZSk7IH0pOyB9XHJcbiAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHsgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7IH1cclxuICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XHJcbiAgICB9KTtcclxufTtcclxuaW1wb3J0IHsgRG93bmxvYWRlciB9IGZyb20gJy4vZG93bmxvYWRlcic7XHJcbmltcG9ydCB7IFF1ZXVlIH0gZnJvbSAnLi9xdWV1ZSc7XHJcbmltcG9ydCB7IE1hbmlmZXN0IH0gZnJvbSAnLi9tYW5pZmVzdCc7XHJcbmltcG9ydCB7IEFzc2V0U3RvcmFnZSB9IGZyb20gJy4vc3RvcmFnZSc7XHJcbmltcG9ydCBFdmVudEVtaXR0ZXIgZnJvbSAnZXZlbnRlbWl0dGVyMyc7XHJcbmltcG9ydCB7IGJ1aWxkUGF0aCB9IGZyb20gJy4vdXRpbHMnO1xyXG5leHBvcnQgY2xhc3MgQXNzZXRNYW5hZ2VyIGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcclxuICAgIGNvbnN0cnVjdG9yKG5hbWUsIGJhc2VQYXRoKSB7XHJcbiAgICAgICAgc3VwZXIoKTtcclxuICAgICAgICB0aGlzLm5hbWUgPSBuYW1lO1xyXG4gICAgICAgIHRoaXMuYmFzZVBhdGggPSBiYXNlUGF0aDtcclxuICAgICAgICB0aGlzLnF1ZXVlID0gbmV3IFF1ZXVlKCk7XHJcbiAgICAgICAgdGhpcy5zdG9yYWdlID0gbmV3IEFzc2V0U3RvcmFnZShuYW1lKTtcclxuICAgICAgICB0aGlzLmRvd25sb2FkZXIgPSBuZXcgRG93bmxvYWRlcih0aGlzLnN0b3JhZ2UsIHRoaXMucXVldWUsIHRoaXMuYmFzZVBhdGgpO1xyXG4gICAgICAgIGNvbnNvbGUubG9nKGBBc3NldCBtYW5hZ2VyIGluaXRpYWxpemVkYCk7XHJcbiAgICB9XHJcbiAgICBpbml0KCkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIHlpZWxkIHRoaXMuc3RvcmFnZS5pbml0KCk7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgc2V0TWFuaWZlc3QocGF0aCkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIHRoaXMubWFuaWZlc3QgPSB5aWVsZCBNYW5pZmVzdChgJHt0aGlzLmJhc2VQYXRofS8ke3BhdGh9YCk7XHJcbiAgICAgICAgICAgIHRoaXMuc3RvcmFnZS5zZXRNYW5pZmVzdCh0aGlzLm1hbmlmZXN0KTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMubWFuaWZlc3Q7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBlbnF1ZXVlKHBhdGgpIHtcclxuICAgICAgICB0aGlzLnF1ZXVlLmFkZChwYXRoKTtcclxuICAgIH1cclxuICAgIGRvd25sb2FkKCkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHlpZWxkIHRoaXMuZG93bmxvYWRlci5kb3dubG9hZCgpO1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgZG93bmxvYWRGcm9tTWFuaWZlc3Qoa2V5KSB7XHJcbiAgICAgICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcclxuICAgICAgICAgICAgY29uc3QgcGF0aHMgPSB0aGlzLm1hbmlmZXN0W2tleV07XHJcbiAgICAgICAgICAgIHBhdGhzLmZvckVhY2goKHBhdGgpID0+IHRoaXMuZW5xdWV1ZShwYXRoKSk7XHJcbiAgICAgICAgICAgIHRoaXMuZG93bmxvYWRlci5vbignZG93bmxvYWQucHJvZ3Jlc3MnLCAoaW5mbykgPT4gdGhpcy5lbWl0KCdwcm9ncmVzcycsIGluZm8pKTtcclxuICAgICAgICAgICAgY29uc3QgZmlsZXMgPSB5aWVsZCB0aGlzLmRvd25sb2FkZXIuZG93bmxvYWQoKTtcclxuICAgICAgICAgICAgdGhpcy5kb3dubG9hZGVyLm9mZignZG93bmxvYWQucHJvZ3Jlc3MnKTtcclxuICAgICAgICAgICAgcmV0dXJuIGZpbGVzO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgZG93bmxvYWRGaWxlKHBhdGgpIHtcclxuICAgICAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xyXG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSB5aWVsZCB0aGlzLmRvd25sb2FkZXIuZG93bmxvYWRJdGVtKGJ1aWxkUGF0aCh0aGlzLmJhc2VQYXRoLCBwYXRoKSk7XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBzZXRCYXNlUGF0aChwYXRoKSB7XHJcbiAgICAgICAgdGhpcy5iYXNlUGF0aCA9IHRoaXMuYmFzZVBhdGg7XHJcbiAgICAgICAgdGhpcy5kb3dubG9hZGVyLnNldEJhc2VQYXRoKHRoaXMuYmFzZVBhdGgpO1xyXG4gICAgfVxyXG4gICAgY2xlYXJDYWNoZSgpIHtcclxuICAgICAgICB0aGlzLnN0b3JhZ2UuY2xlYXIoKTtcclxuICAgIH1cclxufVxyXG4iLCJleHBvcnQgdmFyIFNvdXJjZVR5cGU7XHJcbihmdW5jdGlvbiAoU291cmNlVHlwZSkge1xyXG4gICAgU291cmNlVHlwZVtTb3VyY2VUeXBlW1wiV29ybGRTb3VyY2VcIl0gPSAwXSA9IFwiV29ybGRTb3VyY2VcIjtcclxuICAgIFNvdXJjZVR5cGVbU291cmNlVHlwZVtcIlVJU291cmNlXCJdID0gMV0gPSBcIlVJU291cmNlXCI7XHJcbiAgICBTb3VyY2VUeXBlW1NvdXJjZVR5cGVbXCJNYXN0ZXJTb3VyY2VcIl0gPSAyXSA9IFwiTWFzdGVyU291cmNlXCI7XHJcbn0pKFNvdXJjZVR5cGUgfHwgKFNvdXJjZVR5cGUgPSB7fSkpO1xyXG4iLCJjb25zdCBfX1dFQlBBQ0tfTkFNRVNQQUNFX09CSkVDVF9fID0gdW5kZWZpbmVkOyIsImV4cG9ydCBjbGFzcyBCYXNlRW50aXR5IHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMuY29tcG9uZW50cyA9IG5ldyBNYXAoKTtcclxuICAgICAgICB0aGlzLmlkID0gMDtcclxuICAgIH1cclxuICAgIGFkZENvbXBvbmVudChjb21wb25lbnQpIHtcclxuICAgICAgICBsZXQgY29tcCA9IG5ldyBjb21wb25lbnQoKTtcclxuICAgICAgICBjb21wLmlkID0gY29tcG9uZW50LmlkO1xyXG4gICAgICAgIHRoaXMuY29tcG9uZW50cy5zZXQoY29tcG9uZW50LmlkLCBjb21wKTtcclxuICAgIH1cclxuICAgIHJlbW92ZUNvbXBvbmVudChjb21wb25lbnQpIHtcclxuICAgICAgICB0aGlzLmNvbXBvbmVudHMuZGVsZXRlKGNvbXBvbmVudC5pZCk7XHJcbiAgICB9XHJcbiAgICBnZXRDb21wb25lbnRJRHMoKSB7XHJcbiAgICAgICAgcmV0dXJuIFsuLi50aGlzLmNvbXBvbmVudHMua2V5cygpXTtcclxuICAgIH1cclxuICAgIGdldENvbXBvbmVudChjb21wb25lbnQpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb21wb25lbnRzLmdldChjb21wb25lbnQuaWQpO1xyXG4gICAgfVxyXG4gICAgZ2V0Q29tcG9uZW50QnlJRChpZCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbXBvbmVudHMuZ2V0KGlkKTtcclxuICAgIH1cclxufVxyXG4iLCJleHBvcnQgY2xhc3MgRXZlbnRCdXMge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5ldmVudHMgPSBuZXcgTWFwKCk7XHJcbiAgICB9XHJcbiAgICBlbWl0KGlkLCBkYXRhID0ge30pIHtcclxuICAgICAgICBsZXQgZXYgPSB0aGlzLmV2ZW50cy5nZXQoaWQpO1xyXG4gICAgICAgIGlmICghZXYpIHtcclxuICAgICAgICAgICAgbGV0IGV2ID0gbmV3IEV2ZW50SXRlbShpZCk7XHJcbiAgICAgICAgICAgIHRoaXMuZXZlbnRzLnNldChpZCwgZXYpO1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGV2LnN1YnNjcmliZXJzLmZvckVhY2goKHN1YnNjcmliZXIpID0+IHtcclxuICAgICAgICAgICAgc3Vic2NyaWJlcihkYXRhKTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuICAgIHN1YnNjcmliZShpZCwgc3Vic2NyaWJlcikge1xyXG4gICAgICAgIGxldCBldiA9IHRoaXMuZXZlbnRzLmdldChpZCk7XHJcbiAgICAgICAgaWYgKCFldikge1xyXG4gICAgICAgICAgICBldiA9IG5ldyBFdmVudEl0ZW0oaWQpO1xyXG4gICAgICAgICAgICB0aGlzLmV2ZW50cy5zZXQoaWQsIGV2KTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZXYuc3Vic2NyaWJlcnMucHVzaChzdWJzY3JpYmVyKTtcclxuICAgIH1cclxuICAgIHVuc3Vic2NyaWJlKGlkLCBzdWJzY3JpYmVyKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZXZlbnRzLmhhcyhpZCkpIHtcclxuICAgICAgICAgICAgbGV0IGV2ID0gdGhpcy5ldmVudHMuZ2V0KGlkKTtcclxuICAgICAgICAgICAgZXYuc3Vic2NyaWJlcnMgPSBldi5zdWJzY3JpYmVycy5maWx0ZXIoKGZuKSA9PiBmbiAhPT0gc3Vic2NyaWJlcik7XHJcbiAgICAgICAgICAgIGlmIChldi5zdWJzY3JpYmVycy5sZW5ndGggPCAxKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmV2ZW50cy5kZWxldGUoaWQpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgdW5zdWJzY3JpYmVBbGwoaWQpIHtcclxuICAgICAgICBpZiAodGhpcy5ldmVudHMuaGFzKGlkKSkge1xyXG4gICAgICAgICAgICB0aGlzLmV2ZW50cy5kZWxldGUoaWQpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG5leHBvcnQgY2xhc3MgRXZlbnRJdGVtIHtcclxuICAgIGNvbnN0cnVjdG9yKGlkKSB7XHJcbiAgICAgICAgdGhpcy5pZCA9IGlkO1xyXG4gICAgICAgIHRoaXMuc3Vic2NyaWJlcnMgPSBbXTtcclxuICAgIH1cclxufVxyXG4iLCJleHBvcnQgY2xhc3MgUXVlcnkge1xyXG4gICAgY29uc3RydWN0b3IoaW5jbHVkZSwgZXhjbHVkZSwgd29ybGQpIHtcclxuICAgICAgICB0aGlzLmluY2x1ZGUgPSBpbmNsdWRlO1xyXG4gICAgICAgIHRoaXMuZXhjbHVkZSA9IGV4Y2x1ZGU7XHJcbiAgICAgICAgdGhpcy53b3JsZCA9IHdvcmxkO1xyXG4gICAgICAgIHRoaXMuaXNEaXJ0eSA9IHRydWU7XHJcbiAgICAgICAgdGhpcy5yZXN1bHRzID0gbmV3IEFycmF5KCk7XHJcbiAgICAgICAgdGhpcy5pbmNsdWRlQ29tcG9uZW50SWRzID0gaW5jbHVkZS5tYXAoKGNvbXBvbmVudCkgPT4gY29tcG9uZW50LmlkKTtcclxuICAgICAgICB0aGlzLmV4Y2x1ZGVDb21wb25lbnRJZHMgPSBleGNsdWRlLm1hcCgoY29tcG9uZW50KSA9PiBjb21wb25lbnQuaWQpO1xyXG4gICAgICAgIHRoaXMuaWQgPSAwO1xyXG4gICAgfVxyXG4gICAgZXhlY3V0ZSgpIHtcclxuICAgICAgICBpZiAoIXRoaXMuaXNEaXJ0eSAmJiB0aGlzLnJlc3VsdHMpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVzdWx0cztcclxuICAgICAgICB9XHJcbiAgICAgICAgbGV0IGZpbHRlcmVkO1xyXG4gICAgICAgIHRoaXMuaW5jbHVkZUNvbXBvbmVudElkcyA9IHRoaXMuaW5jbHVkZS5tYXAoKGNvbXBvbmVudCkgPT4gdGhpcy53b3JsZC5jb21wb25lbnROYW1lc1RvSURzLmdldChjb21wb25lbnQubmFtZSkpO1xyXG4gICAgICAgIHRoaXMuZXhjbHVkZUNvbXBvbmVudElkcyA9IHRoaXMuZXhjbHVkZS5tYXAoKGNvbXBvbmVudCkgPT4gdGhpcy53b3JsZC5jb21wb25lbnROYW1lc1RvSURzLmdldChjb21wb25lbnQubmFtZSkpO1xyXG4gICAgICAgIGNvbnN0IGVudGl0aWVzID0gdGhpcy53b3JsZC5lbnRpdGllcy5maWx0ZXIoKGVudGl0eSkgPT4ge1xyXG4gICAgICAgICAgICBsZXQgaWRzID0gZW50aXR5LmdldENvbXBvbmVudElEcygpO1xyXG4gICAgICAgICAgICAvLyBsZXQgaW5jbHVkZXMgPSBpZHMubWFwKGlkID0+IHRoaXMuaW5jbHVkZUNvbXBvbmVudElkcy5pbmNsdWRlcyhpZCkpLmluY2x1ZGVzKHRydWUpO1xyXG4gICAgICAgICAgICBsZXQgZXhjbHVkZXMgPSBpZHNcclxuICAgICAgICAgICAgICAgIC5tYXAoKGlkKSA9PiB0aGlzLmV4Y2x1ZGVDb21wb25lbnRJZHMuaW5jbHVkZXMoaWQpKVxyXG4gICAgICAgICAgICAgICAgLmluY2x1ZGVzKHRydWUpO1xyXG4gICAgICAgICAgICBsZXQgaW5jbHVkZXMgPSBpZHMuZmlsdGVyKChpZCkgPT4gdGhpcy5pbmNsdWRlQ29tcG9uZW50SWRzLmluY2x1ZGVzKGlkKSk7XHJcbiAgICAgICAgICAgIHJldHVybiBpbmNsdWRlcy5sZW5ndGggPT09IHRoaXMuaW5jbHVkZUNvbXBvbmVudElkcy5sZW5ndGggJiYgIWV4Y2x1ZGVzO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIGlmIChlbnRpdGllcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgIHRoaXMuaXNEaXJ0eSA9IGZhbHNlO1xyXG4gICAgICAgICAgICB0aGlzLnJlc3VsdHMgPSBlbnRpdGllcztcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGVudGl0aWVzO1xyXG4gICAgfVxyXG59XHJcbiIsImV4cG9ydCBjbGFzcyBTeXN0ZW0ge1xyXG4gICAgY29uc3RydWN0b3IoZXhlY3V0b3IpIHtcclxuICAgICAgICB0aGlzLmV4ZWN1dG9yID0gZXhlY3V0b3I7XHJcbiAgICB9XHJcbiAgICBleGVjdXRlKHdvcmxkKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZXhlY3V0b3IpIHtcclxuICAgICAgICAgICAgdGhpcy5leGVjdXRvcih3b3JsZCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCB7IEJhc2VFbnRpdHkgfSBmcm9tICcuL2VudGl0eSc7XHJcbmltcG9ydCB7IEV2ZW50QnVzIH0gZnJvbSAnLi4vZXZlbnQtYnVzJztcclxuaW1wb3J0IHsgUXVlcnkgfSBmcm9tICcuL3F1ZXJ5JztcclxuaW1wb3J0IHsgU3lzdGVtIH0gZnJvbSAnLi9zeXN0ZW0nO1xyXG5leHBvcnQgY2xhc3MgV29ybGQge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5uZXh0RW50aXR5SUQgPSAwO1xyXG4gICAgICAgIHRoaXMubmV4dENvbXBvbmVudElEID0gMDtcclxuICAgICAgICB0aGlzLm5leHRRdWVyeUlEID0gMDtcclxuICAgICAgICB0aGlzLmVudGl0aWVzID0gbmV3IEFycmF5KCk7XHJcbiAgICAgICAgdGhpcy5zeXN0ZW1zID0gbmV3IFNldCgpO1xyXG4gICAgICAgIHRoaXMuY29tcG9uZW50cyA9IG5ldyBNYXAoKTtcclxuICAgICAgICB0aGlzLmNvbXBvbmVudE5hbWVzVG9JRHMgPSBuZXcgTWFwKCk7XHJcbiAgICAgICAgdGhpcy5xdWVyeUNhY2hlID0gbmV3IEFycmF5KCk7XHJcbiAgICAgICAgdGhpcy5ldmVudEJ1cyA9IG5ldyBFdmVudEJ1cygpO1xyXG4gICAgfVxyXG4gICAgcnVuKCkge1xyXG4gICAgICAgIHRoaXMuc3lzdGVtcy5mb3JFYWNoKChzeXN0ZW0pID0+IHtcclxuICAgICAgICAgICAgc3lzdGVtLmV4ZWN1dGUodGhpcyk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBjcmVhdGVTeXN0ZW0oc3lzdGVtRXhlY3V0b3IpIHtcclxuICAgICAgICBjb25zdCBuZXdTeXN0ZW0gPSBuZXcgU3lzdGVtKHN5c3RlbUV4ZWN1dG9yKTtcclxuICAgICAgICB0aGlzLnN5c3RlbXMuYWRkKG5ld1N5c3RlbSk7XHJcbiAgICB9XHJcbiAgICBhZGRTeXN0ZW0oc3lzdGVtKSB7XHJcbiAgICAgICAgdGhpcy5zeXN0ZW1zLmFkZChzeXN0ZW0pO1xyXG4gICAgfVxyXG4gICAgYWRkRW50aXR5KGVudGl0eSkge1xyXG4gICAgICAgIHRoaXMuZW50aXRpZXMucHVzaChlbnRpdHkpO1xyXG4gICAgICAgIHRoaXMubWFya1F1ZXJpZXNEaXJ0eSgpO1xyXG4gICAgfVxyXG4gICAgcmVtb3ZlRW50aXR5KGVudGl0eVRvUmVtb3ZlKSB7XHJcbiAgICAgICAgdGhpcy5lbnRpdGllcyA9IHRoaXMuZW50aXRpZXMuZmlsdGVyKChlbnRpdHkpID0+IGVudGl0eSAhPT0gZW50aXR5VG9SZW1vdmUpO1xyXG4gICAgICAgIHRoaXMubWFya1F1ZXJpZXNEaXJ0eSgpO1xyXG4gICAgfVxyXG4gICAgY3JlYXRlRW50aXR5KGNvbXBvbmVudHMpIHtcclxuICAgICAgICBjb25zdCBuZXdFbnRpdHkgPSBuZXcgQmFzZUVudGl0eSgpO1xyXG4gICAgICAgIG5ld0VudGl0eS5pZCA9IHRoaXMubmV4dEVudGl0eUlEO1xyXG4gICAgICAgIHRoaXMubmV4dEVudGl0eUlEKys7XHJcbiAgICAgICAgY29tcG9uZW50cy5mb3JFYWNoKChjb21wb25lbnQpID0+IHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuY29tcG9uZW50TmFtZXNUb0lEcy5oYXMoY29tcG9uZW50Lm5hbWUpKSB7XHJcbiAgICAgICAgICAgICAgICBjb21wb25lbnQuaWQgPSB0aGlzLmNvbXBvbmVudE5hbWVzVG9JRHMuZ2V0KGNvbXBvbmVudC5uYW1lKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgIHRoaXMuY29tcG9uZW50TmFtZXNUb0lEcy5zZXQoY29tcG9uZW50Lm5hbWUsIHRoaXMubmV4dENvbXBvbmVudElEKTtcclxuICAgICAgICAgICAgICAgIGNvbXBvbmVudC5pZCA9IHRoaXMubmV4dENvbXBvbmVudElEO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5uZXh0Q29tcG9uZW50SUQrKztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBuZXdFbnRpdHkuYWRkQ29tcG9uZW50KGNvbXBvbmVudCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgdGhpcy5lbnRpdGllcy5wdXNoKG5ld0VudGl0eSk7XHJcbiAgICAgICAgdGhpcy5tYXJrUXVlcmllc0RpcnR5KCk7XHJcbiAgICAgICAgcmV0dXJuIG5ld0VudGl0eTtcclxuICAgIH1cclxuICAgIGV4dGVuZEVudGl0eShlbnRpdHksIGNvbXBvbmVudHMpIHtcclxuICAgICAgICBjb25zdCB0b0Nsb25lID0gdGhpcy5lbnRpdGllcy5maW5kKChmb3VuZCkgPT4gZW50aXR5Lm5hbWUgPT09IGZvdW5kLmNvbnN0cnVjdG9yLm5hbWUpO1xyXG4gICAgICAgIGNvbnN0IGNsb25lZCA9IG5ldyBCYXNlRW50aXR5KCk7XHJcbiAgICAgICAgY2xvbmVkLmlkID0gdGhpcy5uZXh0RW50aXR5SUQ7XHJcbiAgICAgICAgdGhpcy5uZXh0RW50aXR5SUQrKztcclxuICAgICAgICB0b0Nsb25lLmNvbXBvbmVudHMuZm9yRWFjaCgoY29tcG9uZW50KSA9PiB7XHJcbiAgICAgICAgICAgIGNsb25lZC5hZGRDb21wb25lbnQodGhpcy5jb21wb25lbnRzLmdldChjb21wb25lbnQuaWQpKTtcclxuICAgICAgICB9KTtcclxuICAgICAgICBjb21wb25lbnRzLmZvckVhY2goKGNvbXBvbmVudCkgPT4ge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5jb21wb25lbnROYW1lc1RvSURzLmhhcyhjb21wb25lbnQubmFtZSkpIHtcclxuICAgICAgICAgICAgICAgIGNvbXBvbmVudC5pZCA9IHRoaXMuY29tcG9uZW50TmFtZXNUb0lEcy5nZXQoY29tcG9uZW50Lm5hbWUpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5jb21wb25lbnROYW1lc1RvSURzLnNldChjb21wb25lbnQubmFtZSwgdGhpcy5uZXh0Q29tcG9uZW50SUQpO1xyXG4gICAgICAgICAgICAgICAgY29tcG9uZW50LmlkID0gdGhpcy5uZXh0Q29tcG9uZW50SUQ7XHJcbiAgICAgICAgICAgICAgICB0aGlzLm5leHRDb21wb25lbnRJRCsrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGNsb25lZC5hZGRDb21wb25lbnQoY29tcG9uZW50KTtcclxuICAgICAgICB9KTtcclxuICAgICAgICB0aGlzLmVudGl0aWVzLnB1c2goY2xvbmVkKTtcclxuICAgICAgICByZXR1cm4gY2xvbmVkO1xyXG4gICAgfVxyXG4gICAgY3JlYXRlQ29tcG9uZW50KGNvbXBvbmVudCkge1xyXG4gICAgICAgIGNvbnN0IG5ld0NvbXBvbmVudCA9IGNvbXBvbmVudDtcclxuICAgICAgICBuZXdDb21wb25lbnQuaWQgPSB0aGlzLm5leHRDb21wb25lbnRJRDtcclxuICAgICAgICB0aGlzLm5leHRDb21wb25lbnRJRCsrO1xyXG4gICAgICAgIHRoaXMuY29tcG9uZW50cy5zZXQobmV3Q29tcG9uZW50LmlkLCBuZXdDb21wb25lbnQpO1xyXG4gICAgICAgIHRoaXMuY29tcG9uZW50TmFtZXNUb0lEcy5zZXQoY29tcG9uZW50Lm5hbWUsIGNvbXBvbmVudC5pZCk7XHJcbiAgICAgICAgcmV0dXJuIG5ld0NvbXBvbmVudDtcclxuICAgIH1cclxuICAgIHF1ZXJ5KGluY2x1ZGUsIGV4Y2x1ZGUpIHtcclxuICAgICAgICBjb25zdCBxdWVyeSA9IG5ldyBRdWVyeShpbmNsdWRlLCBleGNsdWRlLCB0aGlzKTtcclxuICAgICAgICBjb25zdCBjYWNoZSA9IHRoaXMucXVlcnlDYWNoZS5maW5kKChpdGVtKSA9PiBpdGVtLmluY2x1ZGUgPT0gaW5jbHVkZSAmJiBpdGVtLmV4Y2x1ZGUgPT0gZXhjbHVkZSk7XHJcbiAgICAgICAgaWYgKGNhY2hlKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBjYWNoZS5leGVjdXRlKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMucXVlcnlDYWNoZS5wdXNoKHF1ZXJ5KTtcclxuICAgICAgICByZXR1cm4gcXVlcnkuZXhlY3V0ZSgpO1xyXG4gICAgfVxyXG4gICAgY3JlYXRlUXVlcnkoaW5jbHVkZSwgZXhjbHVkZSkge1xyXG4gICAgICAgIGNvbnN0IG5ld1F1ZXJ5ID0gbmV3IFF1ZXJ5KGluY2x1ZGUsIGV4Y2x1ZGUsIHRoaXMpO1xyXG4gICAgICAgIG5ld1F1ZXJ5LmlkID0gdGhpcy5uZXh0UXVlcnlJRDtcclxuICAgICAgICB0aGlzLm5leHRRdWVyeUlEKys7XHJcbiAgICAgICAgdGhpcy5xdWVyeUNhY2hlLnB1c2gobmV3UXVlcnkpO1xyXG4gICAgICAgIHJldHVybiBuZXdRdWVyeTtcclxuICAgIH1cclxuICAgIG1hcmtRdWVyaWVzRGlydHkoKSB7XHJcbiAgICAgICAgdGhpcy5xdWVyeUNhY2hlLmZvckVhY2goKHF1ZXJ5KSA9PiAocXVlcnkuaXNEaXJ0eSA9IHRydWUpKTtcclxuICAgIH1cclxufVxyXG4iLCJleHBvcnQgY2xhc3MgQmFzZUlucHV0IHtcclxuICAgIGNvbnN0cnVjdG9yKGVsZW1lbnQpIHtcclxuICAgICAgICB0aGlzLmVsZW1lbnQgPSBlbGVtZW50O1xyXG4gICAgfVxyXG4gICAgZ2V0U3RhdGUoKSB7IH1cclxuICAgIGNhcHR1cmUocHJldmVudERlZmF1bHQpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICByZWxlYXNlKCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBCYXNlSW5wdXQgfSBmcm9tICcuL2Jhc2UtaW5wdXQnO1xyXG5leHBvcnQgY2xhc3MgS2V5Ym9hcmQgZXh0ZW5kcyBCYXNlSW5wdXQge1xyXG4gICAgY29uc3RydWN0b3IoZWxlbWVudCkge1xyXG4gICAgICAgIHN1cGVyKGVsZW1lbnQpO1xyXG4gICAgICAgIHRoaXMua2V5c0Rvd24gPSBuZXcgTWFwKCk7XHJcbiAgICAgICAgdGhpcy5rZXlzSnVzdFByZXNzZWQgPSBuZXcgTWFwKCk7XHJcbiAgICAgICAgdGhpcy5rZXlzSnVzdFJlbGVhc2VkID0gbmV3IE1hcCgpO1xyXG4gICAgICAgIHRoaXMuaGFuZGxlS2V5RG93biA9IHRoaXMuaGFuZGxlS2V5RG93bi5iaW5kKHRoaXMpO1xyXG4gICAgICAgIHRoaXMuaGFuZGxlS2V5VXAgPSB0aGlzLmhhbmRsZUtleVVwLmJpbmQodGhpcyk7XHJcbiAgICB9XHJcbiAgICBjYXB0dXJlKHByZXZlbnREZWZhdWx0KSB7XHJcbiAgICAgICAgdGhpcy5hY3RpdmUgPSB0cnVlO1xyXG4gICAgICAgIHRoaXMucHJldmVudERlZmF1bHQgPSBwcmV2ZW50RGVmYXVsdDtcclxuICAgICAgICB0aGlzLmVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIHRoaXMuaGFuZGxlS2V5RG93bik7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2tleXVwJywgdGhpcy5oYW5kbGVLZXlVcCk7XHJcbiAgICB9XHJcbiAgICByZWxlYXNlKCkge1xyXG4gICAgICAgIHRoaXMuYWN0aXZlID0gZmFsc2U7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCB0aGlzLmhhbmRsZUtleURvd24pO1xyXG4gICAgICAgIHRoaXMuZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdrZXl1cCcsIHRoaXMuaGFuZGxlS2V5VXApO1xyXG4gICAgfVxyXG4gICAgZ2V0U3RhdGUoKSB7XHJcbiAgICAgICAgY29uc3Qgc3RhdGUgPSB7XHJcbiAgICAgICAgICAgIGtleXNEb3duOiBuZXcgTWFwKHRoaXMua2V5c0Rvd24pLFxyXG4gICAgICAgICAgICBrZXlzSnVzdFByZXNzZWQ6IG5ldyBNYXAodGhpcy5rZXlzSnVzdFByZXNzZWQpLFxyXG4gICAgICAgICAgICBrZXlzSnVzdFJlbGVhc2VkOiBuZXcgTWFwKHRoaXMua2V5c0p1c3RSZWxlYXNlZClcclxuICAgICAgICB9O1xyXG4gICAgICAgIHRoaXMua2V5c0p1c3RQcmVzc2VkLmNsZWFyKCk7XHJcbiAgICAgICAgdGhpcy5rZXlzSnVzdFJlbGVhc2VkLmNsZWFyKCk7XHJcbiAgICAgICAgcmV0dXJuIHN0YXRlO1xyXG4gICAgfVxyXG4gICAgaGFuZGxlS2V5RG93bihldmVudCkge1xyXG4gICAgICAgIGlmICh0aGlzLmFjdGl2ZSAmJiB0aGlzLnByZXZlbnREZWZhdWx0KVxyXG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIGlmICh0aGlzLmtleXNEb3duLmdldChldmVudC5rZXlDb2RlKSlcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIHRoaXMua2V5c0Rvd24uc2V0KGV2ZW50LmtleUNvZGUsIHRydWUpO1xyXG4gICAgICAgIHRoaXMua2V5c0p1c3RQcmVzc2VkLnNldChldmVudC5rZXlDb2RlLCB0cnVlKTtcclxuICAgICAgICB0aGlzLmtleXNKdXN0UmVsZWFzZWQuc2V0KGV2ZW50LmtleUNvZGUsIGZhbHNlKTtcclxuICAgIH1cclxuICAgIGhhbmRsZUtleVVwKGV2ZW50KSB7XHJcbiAgICAgICAgaWYgKHRoaXMuYWN0aXZlICYmIHRoaXMucHJldmVudERlZmF1bHQpXHJcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgaWYgKCF0aGlzLmtleXNEb3duLmdldChldmVudC5rZXlDb2RlKSlcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIHRoaXMua2V5c0Rvd24uc2V0KGV2ZW50LmtleUNvZGUsIGZhbHNlKTtcclxuICAgICAgICB0aGlzLmtleXNKdXN0UHJlc3NlZC5zZXQoZXZlbnQua2V5Q29kZSwgZmFsc2UpO1xyXG4gICAgICAgIHRoaXMua2V5c0p1c3RSZWxlYXNlZC5zZXQoZXZlbnQua2V5Q29kZSwgdHJ1ZSk7XHJcbiAgICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgQmFzZUlucHV0IH0gZnJvbSAnLi9iYXNlLWlucHV0JztcclxuZXhwb3J0IGNsYXNzIE1vdXNlIGV4dGVuZHMgQmFzZUlucHV0IHtcclxuICAgIGNvbnN0cnVjdG9yKGVsZW1lbnQpIHtcclxuICAgICAgICBzdXBlcihlbGVtZW50KTtcclxuICAgICAgICB0aGlzLm1vdXNlUG9zaXRpb24gPSBuZXcgUG9zaXRpb24oKTtcclxuICAgICAgICB0aGlzLm1vdXNlRGVsdGEgPSBuZXcgRGVsdGEoKTtcclxuICAgICAgICB0aGlzLm1vdXNlV2hlZWwgPSBuZXcgRGVsdGEoKTtcclxuICAgICAgICB0aGlzLm1vdXNlQnV0dG9ucyA9IG5ldyBNb3VzZUJ1dHRvbnMoKTtcclxuICAgIH1cclxuICAgIGNhcHR1cmUoKSB7XHJcbiAgICAgICAgdGhpcy5oYW5kbGVNb3VzZURvd24gPSB0aGlzLmhhbmRsZU1vdXNlRG93bi5iaW5kKHRoaXMpO1xyXG4gICAgICAgIHRoaXMuaGFuZGxlTW91c2VNb3ZlID0gdGhpcy5oYW5kbGVNb3VzZU1vdmUuYmluZCh0aGlzKTtcclxuICAgICAgICB0aGlzLmhhbmRsZU1vdXNlVXAgPSB0aGlzLmhhbmRsZU1vdXNlVXAuYmluZCh0aGlzKTtcclxuICAgICAgICB0aGlzLmhhbmRsZVBvaW50ZXJDaGFuZ2UgPSB0aGlzLmhhbmRsZVBvaW50ZXJDaGFuZ2UuYmluZCh0aGlzKTtcclxuICAgICAgICB0aGlzLmFjdGl2ZSA9IHRydWU7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIHRoaXMuaGFuZGxlTW91c2VEb3duKTtcclxuICAgICAgICB0aGlzLmVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5oYW5kbGVNb3VzZU1vdmUpO1xyXG4gICAgICAgIHRoaXMuZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgdGhpcy5oYW5kbGVNb3VzZVVwKTtcclxuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVybG9ja2NoYW5nZScsIHRoaXMuaGFuZGxlUG9pbnRlckNoYW5nZSk7XHJcbiAgICB9XHJcbiAgICByZWxlYXNlKCkge1xyXG4gICAgICAgIHRoaXMuYWN0aXZlID0gZmFsc2U7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIHRoaXMuaGFuZGxlTW91c2VEb3duKTtcclxuICAgICAgICB0aGlzLmVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5oYW5kbGVNb3VzZU1vdmUpO1xyXG4gICAgICAgIHRoaXMuZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgdGhpcy5oYW5kbGVNb3VzZVVwKTtcclxuICAgIH1cclxuICAgIGdldFN0YXRlKCkge1xyXG4gICAgICAgIGNvbnN0IHsgbW91c2VCdXR0b25zLCBtb3VzZURlbHRhLCBtb3VzZVBvc2l0aW9uLCBtb3VzZVdoZWVsIH0gPSB0aGlzO1xyXG4gICAgICAgIGNvbnN0IHN0YXRlID0ge1xyXG4gICAgICAgICAgICBtb3VzZUJ1dHRvbnM6IHtcclxuICAgICAgICAgICAgICAgIGtleXNEb3duOiBuZXcgTWFwKHRoaXMubW91c2VCdXR0b25zLmtleXNEb3duKSxcclxuICAgICAgICAgICAgICAgIGtleXNKdXN0UHJlc3NlZDogbmV3IE1hcCh0aGlzLm1vdXNlQnV0dG9ucy5rZXlzSnVzdFByZXNzZWQpLFxyXG4gICAgICAgICAgICAgICAga2V5c0p1c3RSZWxlYXNlZDogbmV3IE1hcCh0aGlzLm1vdXNlQnV0dG9ucy5rZXlzSnVzdFJlbGVhc2VkKVxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBtb3VzZURlbHRhLFxyXG4gICAgICAgICAgICBtb3VzZVBvc2l0aW9uLFxyXG4gICAgICAgICAgICBtb3VzZVdoZWVsXHJcbiAgICAgICAgfTtcclxuICAgICAgICB0aGlzLm1vdXNlQnV0dG9ucy5rZXlzSnVzdFByZXNzZWQuY2xlYXIoKTtcclxuICAgICAgICB0aGlzLm1vdXNlQnV0dG9ucy5rZXlzSnVzdFJlbGVhc2VkLmNsZWFyKCk7XHJcbiAgICAgICAgdGhpcy5tb3VzZURlbHRhLnggPSAwO1xyXG4gICAgICAgIHRoaXMubW91c2VEZWx0YS55ID0gMDtcclxuICAgICAgICByZXR1cm4gc3RhdGU7XHJcbiAgICB9XHJcbiAgICBoYW5kbGVNb3VzZURvd24oZXZlbnQpIHtcclxuICAgICAgICBpZiAodGhpcy5hY3RpdmUpXHJcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgdGhpcy5tb3VzZUJ1dHRvbnMua2V5c0Rvd24uc2V0KGV2ZW50LmJ1dHRvbiwgdHJ1ZSk7XHJcbiAgICAgICAgdGhpcy5tb3VzZUJ1dHRvbnMua2V5c0p1c3RQcmVzc2VkLnNldChldmVudC5idXR0b24sIHRydWUpO1xyXG4gICAgICAgIHRoaXMubW91c2VCdXR0b25zLmtleXNKdXN0UmVsZWFzZWQuc2V0KGV2ZW50LmJ1dHRvbiwgZmFsc2UpO1xyXG4gICAgfVxyXG4gICAgaGFuZGxlTW91c2VNb3ZlKGV2ZW50KSB7XHJcbiAgICAgICAgaWYgKHRoaXMuYWN0aXZlKVxyXG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIHRoaXMubW91c2VQb3NpdGlvbi54ID0gZXZlbnQuY2xpZW50WDtcclxuICAgICAgICB0aGlzLm1vdXNlUG9zaXRpb24ueSA9IGV2ZW50LmNsaWVudFk7XHJcbiAgICAgICAgdGhpcy5tb3VzZURlbHRhLnggPSBldmVudC5tb3ZlbWVudFg7XHJcbiAgICAgICAgdGhpcy5tb3VzZURlbHRhLnkgPSBldmVudC5tb3ZlbWVudFk7XHJcbiAgICB9XHJcbiAgICBoYW5kbGVNb3VzZVVwKGV2ZW50KSB7XHJcbiAgICAgICAgaWYgKHRoaXMuYWN0aXZlKVxyXG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIHRoaXMubW91c2VCdXR0b25zLmtleXNKdXN0UmVsZWFzZWQuc2V0KGV2ZW50LmJ1dHRvbiwgdHJ1ZSk7XHJcbiAgICAgICAgdGhpcy5tb3VzZUJ1dHRvbnMua2V5c0Rvd24uc2V0KGV2ZW50LmJ1dHRvbiwgZmFsc2UpO1xyXG4gICAgICAgIHRoaXMubW91c2VCdXR0b25zLmtleXNKdXN0UHJlc3NlZC5zZXQoZXZlbnQuYnV0dG9uLCBmYWxzZSk7XHJcbiAgICB9XHJcbiAgICBoYW5kbGVQb2ludGVyQ2hhbmdlKCkge1xyXG4gICAgICAgIGlmIChkb2N1bWVudC5wb2ludGVyTG9ja0VsZW1lbnQgIT09IHRoaXMuZWxlbWVudCkge1xyXG4gICAgICAgICAgICB0aGlzLmVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmVsZW1lbnQucmVxdWVzdFBvaW50ZXJMb2NrKCk7XHJcbiAgICAgICAgICAgIH0sIHtcclxuICAgICAgICAgICAgICAgIG9uY2U6IHRydWVcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbmV4cG9ydCBjbGFzcyBQb3NpdGlvbiB7XHJcbn1cclxuZXhwb3J0IGNsYXNzIE1vdXNlQnV0dG9ucyB7XHJcbiAgICBjb25zdHJ1Y3RvcigpIHtcclxuICAgICAgICB0aGlzLmtleXNEb3duID0gbmV3IE1hcCgpO1xyXG4gICAgICAgIHRoaXMua2V5c0p1c3RQcmVzc2VkID0gbmV3IE1hcCgpO1xyXG4gICAgICAgIHRoaXMua2V5c0p1c3RSZWxlYXNlZCA9IG5ldyBNYXAoKTtcclxuICAgIH1cclxufVxyXG5leHBvcnQgY2xhc3MgRGVsdGEge1xyXG59XHJcbiIsImltcG9ydCB7IGNyZWF0ZUlucHV0IH0gZnJvbSAnLi9pbnB1dC1mYWN0b3J5JztcclxuZXhwb3J0IGNsYXNzIElucHV0IHtcclxuICAgIGNvbnN0cnVjdG9yKElucHV0SURzLCBlbGVtZW50KSB7XHJcbiAgICAgICAgdGhpcy5JbnB1dElEcyA9IElucHV0SURzO1xyXG4gICAgICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XHJcbiAgICAgICAgdGhpcy5pbnB1dHMgPSBuZXcgTWFwKCk7XHJcbiAgICAgICAgdGhpcy5pbml0KCk7XHJcbiAgICB9XHJcbiAgICBpbml0KCkge1xyXG4gICAgICAgIHRoaXMuSW5wdXRJRHMuZm9yRWFjaCgoaW5wdXRJRCkgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCB0aGluZyA9IGNyZWF0ZUlucHV0KGlucHV0SUQpO1xyXG4gICAgICAgICAgICBjb25zdCBpbnN0YW5jZSA9IG5ldyB0aGluZyh0aGlzLmVsZW1lbnQpO1xyXG4gICAgICAgICAgICB0aGlzLmlucHV0cy5zZXQoaW5wdXRJRCwgaW5zdGFuY2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgYWRkSW5wdXQoaWQsIGlucHV0KSB7XHJcbiAgICAgICAgdGhpcy5pbnB1dHMuc2V0KGlkLCBpbnB1dCk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBjYXB0dXJlKHByZXZlbnREZWZhdWx0ID0gdHJ1ZSkge1xyXG4gICAgICAgIHRoaXMuaW5wdXRzLmZvckVhY2goKGlucHV0KSA9PiBpbnB1dC5jYXB0dXJlKHByZXZlbnREZWZhdWx0KSk7XHJcbiAgICB9XHJcbiAgICByZWxlYXNlKCkge1xyXG4gICAgICAgIHRoaXMuaW5wdXRzLmZvckVhY2goKGlucHV0KSA9PiBpbnB1dC5yZWxlYXNlKCkpO1xyXG4gICAgfVxyXG4gICAgZ2V0U3RhdGUoKSB7XHJcbiAgICAgICAgY29uc3Qgc3RhdGUgPSB7fTtcclxuICAgICAgICB0aGlzLmlucHV0cy5mb3JFYWNoKChpbnB1dCwgaW5wdXRJRCkgPT4ge1xyXG4gICAgICAgICAgICBpZiAoaW5wdXQpXHJcbiAgICAgICAgICAgICAgICBzdGF0ZVtpbnB1dElEXSA9IGlucHV0LmdldFN0YXRlKCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgcmV0dXJuIHN0YXRlO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCB7IEtleWJvYXJkIH0gZnJvbSAnLi9pbnB1dHMva2V5Ym9hcmQnO1xyXG5pbXBvcnQgeyBNb3VzZSB9IGZyb20gJy4vaW5wdXRzL21vdXNlJztcclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUlucHV0KGtleSkge1xyXG4gICAgc3dpdGNoIChrZXkpIHtcclxuICAgICAgICBjYXNlICdrZXlib2FyZCc6XHJcbiAgICAgICAgICAgIHJldHVybiBLZXlib2FyZDtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgY2FzZSAnbW91c2UnOlxyXG4gICAgICAgICAgICByZXR1cm4gTW91c2U7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCB7IGVwc2lsb24gfSBmcm9tICcuL2NvbnN0YW50cyc7XHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIHZlYzQge1xyXG4gICAgY29uc3RydWN0b3IodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXMgPSBuZXcgRmxvYXQzMkFycmF5KDQpO1xyXG4gICAgICAgIGlmICh2YWx1ZXMgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgICB0aGlzLnh5encgPSB2YWx1ZXM7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgZ2V0IHgoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzBdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHkoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzFdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHooKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzJdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHcoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzNdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHh5KCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdXTtcclxuICAgIH1cclxuICAgIGdldCB4eXooKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV0sIHRoaXMudmFsdWVzWzJdXTtcclxuICAgIH1cclxuICAgIGdldCB4eXp3KCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdLCB0aGlzLnZhbHVlc1syXSwgdGhpcy52YWx1ZXNbM11dO1xyXG4gICAgfVxyXG4gICAgc2V0IHgodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHkodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHoodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHcodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHh5KHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgfVxyXG4gICAgc2V0IHh5eih2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHZhbHVlc1syXTtcclxuICAgIH1cclxuICAgIHNldCB4eXp3KHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWVzWzJdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gdmFsdWVzWzNdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHIoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzBdO1xyXG4gICAgfVxyXG4gICAgZ2V0IGcoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzFdO1xyXG4gICAgfVxyXG4gICAgZ2V0IGIoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzJdO1xyXG4gICAgfVxyXG4gICAgZ2V0IGEoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzNdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHJnKCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdXTtcclxuICAgIH1cclxuICAgIGdldCByZ2IoKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV0sIHRoaXMudmFsdWVzWzJdXTtcclxuICAgIH1cclxuICAgIGdldCByZ2JhKCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdLCB0aGlzLnZhbHVlc1syXSwgdGhpcy52YWx1ZXNbM11dO1xyXG4gICAgfVxyXG4gICAgc2V0IHIodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IGcodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IGIodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IGEodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHJnKHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgfVxyXG4gICAgc2V0IHJnYih2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHZhbHVlc1syXTtcclxuICAgIH1cclxuICAgIHNldCByZ2JhKHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWVzWzJdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gdmFsdWVzWzNdO1xyXG4gICAgfVxyXG4gICAgYXQoaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbaW5kZXhdO1xyXG4gICAgfVxyXG4gICAgcmVzZXQoKSB7XHJcbiAgICAgICAgdGhpcy54ID0gMDtcclxuICAgICAgICB0aGlzLnkgPSAwO1xyXG4gICAgICAgIHRoaXMueiA9IDA7XHJcbiAgICAgICAgdGhpcy53ID0gMDtcclxuICAgIH1cclxuICAgIGNvcHkoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdGhpcy54O1xyXG4gICAgICAgIGRlc3QueSA9IHRoaXMueTtcclxuICAgICAgICBkZXN0LnogPSB0aGlzLno7XHJcbiAgICAgICAgZGVzdC53ID0gdGhpcy53O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgbmVnYXRlKGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IC10aGlzLng7XHJcbiAgICAgICAgZGVzdC55ID0gLXRoaXMueTtcclxuICAgICAgICBkZXN0LnogPSAtdGhpcy56O1xyXG4gICAgICAgIGRlc3QudyA9IC10aGlzLnc7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBlcXVhbHModmVjdG9yLCB0aHJlc2hvbGQgPSBlcHNpbG9uKSB7XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMueCAtIHZlY3Rvci54KSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnkgLSB2ZWN0b3IueSkgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoTWF0aC5hYnModGhpcy56IC0gdmVjdG9yLnopID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMudyAtIHZlY3Rvci53KSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gICAgbGVuZ3RoKCkge1xyXG4gICAgICAgIHJldHVybiBNYXRoLnNxcnQodGhpcy5zcXVhcmVkTGVuZ3RoKCkpO1xyXG4gICAgfVxyXG4gICAgc3F1YXJlZExlbmd0aCgpIHtcclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuejtcclxuICAgICAgICBjb25zdCB3ID0gdGhpcy53O1xyXG4gICAgICAgIHJldHVybiB4ICogeCArIHkgKiB5ICsgeiAqIHogKyB3ICogdztcclxuICAgIH1cclxuICAgIGFkZCh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggKz0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55ICs9IHZlY3Rvci55O1xyXG4gICAgICAgIHRoaXMueiArPSB2ZWN0b3IuejtcclxuICAgICAgICB0aGlzLncgKz0gdmVjdG9yLnc7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBzdWJ0cmFjdCh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggLT0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55IC09IHZlY3Rvci55O1xyXG4gICAgICAgIHRoaXMueiAtPSB2ZWN0b3IuejtcclxuICAgICAgICB0aGlzLncgLT0gdmVjdG9yLnc7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseSh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggKj0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55ICo9IHZlY3Rvci55O1xyXG4gICAgICAgIHRoaXMueiAqPSB2ZWN0b3IuejtcclxuICAgICAgICB0aGlzLncgKj0gdmVjdG9yLnc7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBkaXZpZGUodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54IC89IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSAvPSB2ZWN0b3IueTtcclxuICAgICAgICB0aGlzLnogLz0gdmVjdG9yLno7XHJcbiAgICAgICAgdGhpcy53IC89IHZlY3Rvci53O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc2NhbGUodmFsdWUsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCAqPSB2YWx1ZTtcclxuICAgICAgICBkZXN0LnkgKj0gdmFsdWU7XHJcbiAgICAgICAgZGVzdC56ICo9IHZhbHVlO1xyXG4gICAgICAgIGRlc3QudyAqPSB2YWx1ZTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIG5vcm1hbGl6ZShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZXQgbGVuZ3RoID0gdGhpcy5sZW5ndGgoKTtcclxuICAgICAgICBpZiAobGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAobGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIGRlc3QueCAqPSAwO1xyXG4gICAgICAgICAgICBkZXN0LnkgKj0gMDtcclxuICAgICAgICAgICAgZGVzdC56ICo9IDA7XHJcbiAgICAgICAgICAgIGRlc3QudyAqPSAwO1xyXG4gICAgICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgbGVuZ3RoID0gMS4wIC8gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueCAqPSBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC55ICo9IGxlbmd0aDtcclxuICAgICAgICBkZXN0LnogKj0gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QudyAqPSBsZW5ndGg7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseU1hdDQobWF0cml4LCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gbWF0cml4Lm11bHRpcGx5VmVjNCh0aGlzLCBkZXN0KTtcclxuICAgIH1cclxuICAgIHN0YXRpYyBtaXgodmVjdG9yLCB2ZWN0b3IyLCB0aW1lLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjNCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCArIHRpbWUgKiAodmVjdG9yMi54IC0gdmVjdG9yLngpO1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55ICsgdGltZSAqICh2ZWN0b3IyLnkgLSB2ZWN0b3IueSk7XHJcbiAgICAgICAgZGVzdC56ID0gdmVjdG9yLnogKyB0aW1lICogKHZlY3RvcjIueiAtIHZlY3Rvci56KTtcclxuICAgICAgICBkZXN0LncgPSB2ZWN0b3IudyArIHRpbWUgKiAodmVjdG9yMi53IC0gdmVjdG9yLncpO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHN1bSh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWM0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54ICsgdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55ICsgdmVjdG9yMi55O1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56ICsgdmVjdG9yMi56O1xyXG4gICAgICAgIGRlc3QudyA9IHZlY3Rvci53ICsgdmVjdG9yMi53O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGRpZmZlcmVuY2UodmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjNCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCAtIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSAtIHZlY3RvcjIueTtcclxuICAgICAgICBkZXN0LnogPSB2ZWN0b3IueiAtIHZlY3RvcjIuejtcclxuICAgICAgICBkZXN0LncgPSB2ZWN0b3IudyAtIHZlY3RvcjIudztcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBwcm9kdWN0KHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggKiB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgKiB2ZWN0b3IyLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdmVjdG9yLnogKiB2ZWN0b3IyLno7XHJcbiAgICAgICAgZGVzdC53ID0gdmVjdG9yLncgKiB2ZWN0b3IyLnc7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgcXVvdGllbnQodmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjNCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCAvIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSAvIHZlY3RvcjIueTtcclxuICAgICAgICBkZXN0LnogPSB2ZWN0b3IueiAvIHZlY3RvcjIuejtcclxuICAgICAgICBkZXN0LncgPSB2ZWN0b3IudyAvIHZlY3RvcjIudztcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxufVxyXG52ZWM0Lnplcm8gPSBuZXcgdmVjNChbMCwgMCwgMCwgMV0pO1xyXG52ZWM0Lm9uZSA9IG5ldyB2ZWM0KFsxLCAxLCAxLCAxXSk7XHJcbiIsImltcG9ydCBtYXQzIGZyb20gJy4vbWF0Myc7XHJcbmltcG9ydCB2ZWMzIGZyb20gJy4vdmVjMyc7XHJcbmltcG9ydCB2ZWM0IGZyb20gJy4vdmVjNCc7XHJcbmltcG9ydCB7IGVwc2lsb24gfSBmcm9tICcuL2NvbnN0YW50cyc7XHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIG1hdDQge1xyXG4gICAgY29uc3RydWN0b3IodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXMgPSBuZXcgRmxvYXQzMkFycmF5KDE2KTtcclxuICAgICAgICBpZiAodmFsdWVzICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgdGhpcy5pbml0KHZhbHVlcyk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgYXQoaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbaW5kZXhdO1xyXG4gICAgfVxyXG4gICAgaW5pdCh2YWx1ZXMpIHtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDE2OyBpKyspIHtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaV0gPSB2YWx1ZXNbaV07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgcmVzZXQoKSB7XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCAxNjsgaSsrKSB7XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2ldID0gMDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBjb3B5KGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBtYXQ0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMTY7IGkrKykge1xyXG4gICAgICAgICAgICBkZXN0LnZhbHVlc1tpXSA9IHRoaXMudmFsdWVzW2ldO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIGFsbCgpIHtcclxuICAgICAgICBjb25zdCBkYXRhID0gW107XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCAxNjsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRhdGFbaV0gPSB0aGlzLnZhbHVlc1tpXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGRhdGE7XHJcbiAgICB9XHJcbiAgICByb3coaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gW1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleCAqIDQgKyAwXSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXggKiA0ICsgMV0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4ICogNCArIDJdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleCAqIDQgKyAzXVxyXG4gICAgICAgIF07XHJcbiAgICB9XHJcbiAgICBjb2woaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gW1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleF0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4ICsgNF0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4ICsgOF0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4ICsgMTJdXHJcbiAgICAgICAgXTtcclxuICAgIH1cclxuICAgIGVxdWFscyhtYXRyaXgsIHRocmVzaG9sZCA9IGVwc2lsb24pIHtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDE2OyBpKyspIHtcclxuICAgICAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMudmFsdWVzW2ldIC0gbWF0cml4LmF0KGkpKSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gICAgZGV0ZXJtaW5hbnQoKSB7XHJcbiAgICAgICAgY29uc3QgYTAwID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgYTAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgYTAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgYTAzID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgY29uc3QgYTEwID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgY29uc3QgYTExID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgY29uc3QgYTEyID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgYTEzID0gdGhpcy52YWx1ZXNbN107XHJcbiAgICAgICAgY29uc3QgYTIwID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgY29uc3QgYTIxID0gdGhpcy52YWx1ZXNbOV07XHJcbiAgICAgICAgY29uc3QgYTIyID0gdGhpcy52YWx1ZXNbMTBdO1xyXG4gICAgICAgIGNvbnN0IGEyMyA9IHRoaXMudmFsdWVzWzExXTtcclxuICAgICAgICBjb25zdCBhMzAgPSB0aGlzLnZhbHVlc1sxMl07XHJcbiAgICAgICAgY29uc3QgYTMxID0gdGhpcy52YWx1ZXNbMTNdO1xyXG4gICAgICAgIGNvbnN0IGEzMiA9IHRoaXMudmFsdWVzWzE0XTtcclxuICAgICAgICBjb25zdCBhMzMgPSB0aGlzLnZhbHVlc1sxNV07XHJcbiAgICAgICAgY29uc3QgZGV0MDAgPSBhMDAgKiBhMTEgLSBhMDEgKiBhMTA7XHJcbiAgICAgICAgY29uc3QgZGV0MDEgPSBhMDAgKiBhMTIgLSBhMDIgKiBhMTA7XHJcbiAgICAgICAgY29uc3QgZGV0MDIgPSBhMDAgKiBhMTMgLSBhMDMgKiBhMTA7XHJcbiAgICAgICAgY29uc3QgZGV0MDMgPSBhMDEgKiBhMTIgLSBhMDIgKiBhMTE7XHJcbiAgICAgICAgY29uc3QgZGV0MDQgPSBhMDEgKiBhMTMgLSBhMDMgKiBhMTE7XHJcbiAgICAgICAgY29uc3QgZGV0MDUgPSBhMDIgKiBhMTMgLSBhMDMgKiBhMTI7XHJcbiAgICAgICAgY29uc3QgZGV0MDYgPSBhMjAgKiBhMzEgLSBhMjEgKiBhMzA7XHJcbiAgICAgICAgY29uc3QgZGV0MDcgPSBhMjAgKiBhMzIgLSBhMjIgKiBhMzA7XHJcbiAgICAgICAgY29uc3QgZGV0MDggPSBhMjAgKiBhMzMgLSBhMjMgKiBhMzA7XHJcbiAgICAgICAgY29uc3QgZGV0MDkgPSBhMjEgKiBhMzIgLSBhMjIgKiBhMzE7XHJcbiAgICAgICAgY29uc3QgZGV0MTAgPSBhMjEgKiBhMzMgLSBhMjMgKiBhMzE7XHJcbiAgICAgICAgY29uc3QgZGV0MTEgPSBhMjIgKiBhMzMgLSBhMjMgKiBhMzI7XHJcbiAgICAgICAgcmV0dXJuIChkZXQwMCAqIGRldDExIC1cclxuICAgICAgICAgICAgZGV0MDEgKiBkZXQxMCArXHJcbiAgICAgICAgICAgIGRldDAyICogZGV0MDkgK1xyXG4gICAgICAgICAgICBkZXQwMyAqIGRldDA4IC1cclxuICAgICAgICAgICAgZGV0MDQgKiBkZXQwNyArXHJcbiAgICAgICAgICAgIGRldDA1ICogZGV0MDYpO1xyXG4gICAgfVxyXG4gICAgc2V0SWRlbnRpdHkoKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSAxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzRdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s1XSA9IDE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s4XSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOV0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEwXSA9IDE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTFdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMl0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEzXSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTRdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxNV0gPSAxO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgdHJhbnNwb3NlKCkge1xyXG4gICAgICAgIGNvbnN0IHRlbXAwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IHRlbXAwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IHRlbXAwMyA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIGNvbnN0IHRlbXAxMiA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IHRlbXAxMyA9IHRoaXMudmFsdWVzWzddO1xyXG4gICAgICAgIGNvbnN0IHRlbXAyMyA9IHRoaXMudmFsdWVzWzExXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSB0aGlzLnZhbHVlc1sxMl07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNF0gPSB0ZW1wMDE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gPSB0aGlzLnZhbHVlc1s5XTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSA9IHRoaXMudmFsdWVzWzEzXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s4XSA9IHRlbXAwMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s5XSA9IHRlbXAxMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMV0gPSB0aGlzLnZhbHVlc1sxNF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTJdID0gdGVtcDAzO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEzXSA9IHRlbXAxMztcclxuICAgICAgICB0aGlzLnZhbHVlc1sxNF0gPSB0ZW1wMjM7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBpbnZlcnNlKCkge1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IGEwMyA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IGExMyA9IHRoaXMudmFsdWVzWzddO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IHRoaXMudmFsdWVzWzldO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IHRoaXMudmFsdWVzWzEwXTtcclxuICAgICAgICBjb25zdCBhMjMgPSB0aGlzLnZhbHVlc1sxMV07XHJcbiAgICAgICAgY29uc3QgYTMwID0gdGhpcy52YWx1ZXNbMTJdO1xyXG4gICAgICAgIGNvbnN0IGEzMSA9IHRoaXMudmFsdWVzWzEzXTtcclxuICAgICAgICBjb25zdCBhMzIgPSB0aGlzLnZhbHVlc1sxNF07XHJcbiAgICAgICAgY29uc3QgYTMzID0gdGhpcy52YWx1ZXNbMTVdO1xyXG4gICAgICAgIGNvbnN0IGRldDAwID0gYTAwICogYTExIC0gYTAxICogYTEwO1xyXG4gICAgICAgIGNvbnN0IGRldDAxID0gYTAwICogYTEyIC0gYTAyICogYTEwO1xyXG4gICAgICAgIGNvbnN0IGRldDAyID0gYTAwICogYTEzIC0gYTAzICogYTEwO1xyXG4gICAgICAgIGNvbnN0IGRldDAzID0gYTAxICogYTEyIC0gYTAyICogYTExO1xyXG4gICAgICAgIGNvbnN0IGRldDA0ID0gYTAxICogYTEzIC0gYTAzICogYTExO1xyXG4gICAgICAgIGNvbnN0IGRldDA1ID0gYTAyICogYTEzIC0gYTAzICogYTEyO1xyXG4gICAgICAgIGNvbnN0IGRldDA2ID0gYTIwICogYTMxIC0gYTIxICogYTMwO1xyXG4gICAgICAgIGNvbnN0IGRldDA3ID0gYTIwICogYTMyIC0gYTIyICogYTMwO1xyXG4gICAgICAgIGNvbnN0IGRldDA4ID0gYTIwICogYTMzIC0gYTIzICogYTMwO1xyXG4gICAgICAgIGNvbnN0IGRldDA5ID0gYTIxICogYTMyIC0gYTIyICogYTMxO1xyXG4gICAgICAgIGNvbnN0IGRldDEwID0gYTIxICogYTMzIC0gYTIzICogYTMxO1xyXG4gICAgICAgIGNvbnN0IGRldDExID0gYTIyICogYTMzIC0gYTIzICogYTMyO1xyXG4gICAgICAgIGxldCBkZXQgPSBkZXQwMCAqIGRldDExIC1cclxuICAgICAgICAgICAgZGV0MDEgKiBkZXQxMCArXHJcbiAgICAgICAgICAgIGRldDAyICogZGV0MDkgK1xyXG4gICAgICAgICAgICBkZXQwMyAqIGRldDA4IC1cclxuICAgICAgICAgICAgZGV0MDQgKiBkZXQwNyArXHJcbiAgICAgICAgICAgIGRldDA1ICogZGV0MDY7XHJcbiAgICAgICAgaWYgKCFkZXQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRldCA9IDEuMCAvIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IChhMTEgKiBkZXQxMSAtIGExMiAqIGRldDEwICsgYTEzICogZGV0MDkpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gKC1hMDEgKiBkZXQxMSArIGEwMiAqIGRldDEwIC0gYTAzICogZGV0MDkpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gKGEzMSAqIGRldDA1IC0gYTMyICogZGV0MDQgKyBhMzMgKiBkZXQwMykgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSAoLWEyMSAqIGRldDA1ICsgYTIyICogZGV0MDQgLSBhMjMgKiBkZXQwMykgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNF0gPSAoLWExMCAqIGRldDExICsgYTEyICogZGV0MDggLSBhMTMgKiBkZXQwNykgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNV0gPSAoYTAwICogZGV0MTEgLSBhMDIgKiBkZXQwOCArIGEwMyAqIGRldDA3KSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSA9ICgtYTMwICogZGV0MDUgKyBhMzIgKiBkZXQwMiAtIGEzMyAqIGRldDAxKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSA9IChhMjAgKiBkZXQwNSAtIGEyMiAqIGRldDAyICsgYTIzICogZGV0MDEpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzhdID0gKGExMCAqIGRldDEwIC0gYTExICogZGV0MDggKyBhMTMgKiBkZXQwNikgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOV0gPSAoLWEwMCAqIGRldDEwICsgYTAxICogZGV0MDggLSBhMDMgKiBkZXQwNikgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTBdID0gKGEzMCAqIGRldDA0IC0gYTMxICogZGV0MDIgKyBhMzMgKiBkZXQwMCkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTFdID0gKC1hMjAgKiBkZXQwNCArIGEyMSAqIGRldDAyIC0gYTIzICogZGV0MDApICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEyXSA9ICgtYTEwICogZGV0MDkgKyBhMTEgKiBkZXQwNyAtIGExMiAqIGRldDA2KSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxM10gPSAoYTAwICogZGV0MDkgLSBhMDEgKiBkZXQwNyArIGEwMiAqIGRldDA2KSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxNF0gPSAoLWEzMCAqIGRldDAzICsgYTMxICogZGV0MDEgLSBhMzIgKiBkZXQwMCkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTVdID0gKGEyMCAqIGRldDAzIC0gYTIxICogZGV0MDEgKyBhMjIgKiBkZXQwMCkgKiBkZXQ7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseShtYXRyaXgpIHtcclxuICAgICAgICBjb25zdCBhMDAgPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBhMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBhMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBhMDMgPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICBjb25zdCBhMTAgPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICBjb25zdCBhMTEgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICBjb25zdCBhMTIgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCBhMTMgPSB0aGlzLnZhbHVlc1s3XTtcclxuICAgICAgICBjb25zdCBhMjAgPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICBjb25zdCBhMjEgPSB0aGlzLnZhbHVlc1s5XTtcclxuICAgICAgICBjb25zdCBhMjIgPSB0aGlzLnZhbHVlc1sxMF07XHJcbiAgICAgICAgY29uc3QgYTIzID0gdGhpcy52YWx1ZXNbMTFdO1xyXG4gICAgICAgIGNvbnN0IGEzMCA9IHRoaXMudmFsdWVzWzEyXTtcclxuICAgICAgICBjb25zdCBhMzEgPSB0aGlzLnZhbHVlc1sxM107XHJcbiAgICAgICAgY29uc3QgYTMyID0gdGhpcy52YWx1ZXNbMTRdO1xyXG4gICAgICAgIGNvbnN0IGEzMyA9IHRoaXMudmFsdWVzWzE1XTtcclxuICAgICAgICBsZXQgYjAgPSBtYXRyaXguYXQoMCk7XHJcbiAgICAgICAgbGV0IGIxID0gbWF0cml4LmF0KDEpO1xyXG4gICAgICAgIGxldCBiMiA9IG1hdHJpeC5hdCgyKTtcclxuICAgICAgICBsZXQgYjMgPSBtYXRyaXguYXQoMyk7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSBiMCAqIGEwMCArIGIxICogYTEwICsgYjIgKiBhMjAgKyBiMyAqIGEzMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gYjAgKiBhMDIgKyBiMSAqIGExMiArIGIyICogYTIyICsgYjMgKiBhMzI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSBiMCAqIGEwMyArIGIxICogYTEzICsgYjIgKiBhMjMgKyBiMyAqIGEzMztcclxuICAgICAgICBiMCA9IG1hdHJpeC5hdCg0KTtcclxuICAgICAgICBiMSA9IG1hdHJpeC5hdCg1KTtcclxuICAgICAgICBiMiA9IG1hdHJpeC5hdCg2KTtcclxuICAgICAgICBiMyA9IG1hdHJpeC5hdCg3KTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s0XSA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzVdID0gYjAgKiBhMDEgKyBiMSAqIGExMSArIGIyICogYTIxICsgYjMgKiBhMzE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gPSBiMCAqIGEwMiArIGIxICogYTEyICsgYjIgKiBhMjIgKyBiMyAqIGEzMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzO1xyXG4gICAgICAgIGIwID0gbWF0cml4LmF0KDgpO1xyXG4gICAgICAgIGIxID0gbWF0cml4LmF0KDkpO1xyXG4gICAgICAgIGIyID0gbWF0cml4LmF0KDEwKTtcclxuICAgICAgICBiMyA9IG1hdHJpeC5hdCgxMSk7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOF0gPSBiMCAqIGEwMCArIGIxICogYTEwICsgYjIgKiBhMjAgKyBiMyAqIGEzMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s5XSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEwXSA9IGIwICogYTAyICsgYjEgKiBhMTIgKyBiMiAqIGEyMiArIGIzICogYTMyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzExXSA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzO1xyXG4gICAgICAgIGIwID0gbWF0cml4LmF0KDEyKTtcclxuICAgICAgICBiMSA9IG1hdHJpeC5hdCgxMyk7XHJcbiAgICAgICAgYjIgPSBtYXRyaXguYXQoMTQpO1xyXG4gICAgICAgIGIzID0gbWF0cml4LmF0KDE1KTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMl0gPSBiMCAqIGEwMCArIGIxICogYTEwICsgYjIgKiBhMjAgKyBiMyAqIGEzMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxM10gPSBiMCAqIGEwMSArIGIxICogYTExICsgYjIgKiBhMjEgKyBiMyAqIGEzMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxNF0gPSBiMCAqIGEwMiArIGIxICogYTEyICsgYjIgKiBhMjIgKyBiMyAqIGEzMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxNV0gPSBiMCAqIGEwMyArIGIxICogYTEzICsgYjIgKiBhMjMgKyBiMyAqIGEzMztcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIG11bHRpcGx5VmVjMyh2ZWN0b3IpIHtcclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGNvbnN0IHogPSB2ZWN0b3IuejtcclxuICAgICAgICByZXR1cm4gbmV3IHZlYzMoW1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1swXSAqIHggK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNF0gKiB5ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzhdICogeiArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxMl0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzFdICogeCArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s1XSAqIHkgK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbOV0gKiB6ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzEzXSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMl0gKiB4ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzZdICogeSArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxMF0gKiB6ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzE0XVxyXG4gICAgICAgIF0pO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHlWZWM0KHZlY3RvciwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yLno7XHJcbiAgICAgICAgY29uc3QgdyA9IHZlY3Rvci53O1xyXG4gICAgICAgIGRlc3QueCA9XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzBdICogeCArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s0XSAqIHkgK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbOF0gKiB6ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzEyXSAqIHc7XHJcbiAgICAgICAgZGVzdC55ID1cclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMV0gKiB4ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzVdICogeSArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s5XSAqIHogK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTNdICogdztcclxuICAgICAgICBkZXN0LnogPVxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1syXSAqIHggK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNl0gKiB5ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzEwXSAqIHogK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTRdICogdztcclxuICAgICAgICBkZXN0LncgPVxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1szXSAqIHggK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbN10gKiB5ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzExXSAqIHogK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTVdICogdztcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHRvTWF0MygpIHtcclxuICAgICAgICByZXR1cm4gbmV3IG1hdDMoW1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1swXSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMV0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzJdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1s0XSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbNV0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzZdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1s4XSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbOV0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzEwXVxyXG4gICAgICAgIF0pO1xyXG4gICAgfVxyXG4gICAgdG9JbnZlcnNlTWF0MygpIHtcclxuICAgICAgICBjb25zdCBhMDAgPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBhMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBhMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBhMTAgPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICBjb25zdCBhMTEgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICBjb25zdCBhMTIgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCBhMjAgPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICBjb25zdCBhMjEgPSB0aGlzLnZhbHVlc1s5XTtcclxuICAgICAgICBjb25zdCBhMjIgPSB0aGlzLnZhbHVlc1sxMF07XHJcbiAgICAgICAgY29uc3QgZGV0MDEgPSBhMjIgKiBhMTEgLSBhMTIgKiBhMjE7XHJcbiAgICAgICAgY29uc3QgZGV0MTEgPSAtYTIyICogYTEwICsgYTEyICogYTIwO1xyXG4gICAgICAgIGNvbnN0IGRldDIxID0gYTIxICogYTEwIC0gYTExICogYTIwO1xyXG4gICAgICAgIGxldCBkZXQgPSBhMDAgKiBkZXQwMSArIGEwMSAqIGRldDExICsgYTAyICogZGV0MjE7XHJcbiAgICAgICAgaWYgKCFkZXQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRldCA9IDEuMCAvIGRldDtcclxuICAgICAgICByZXR1cm4gbmV3IG1hdDMoW1xyXG4gICAgICAgICAgICBkZXQwMSAqIGRldCxcclxuICAgICAgICAgICAgKC1hMjIgKiBhMDEgKyBhMDIgKiBhMjEpICogZGV0LFxyXG4gICAgICAgICAgICAoYTEyICogYTAxIC0gYTAyICogYTExKSAqIGRldCxcclxuICAgICAgICAgICAgZGV0MTEgKiBkZXQsXHJcbiAgICAgICAgICAgIChhMjIgKiBhMDAgLSBhMDIgKiBhMjApICogZGV0LFxyXG4gICAgICAgICAgICAoLWExMiAqIGEwMCArIGEwMiAqIGExMCkgKiBkZXQsXHJcbiAgICAgICAgICAgIGRldDIxICogZGV0LFxyXG4gICAgICAgICAgICAoLWEyMSAqIGEwMCArIGEwMSAqIGEyMCkgKiBkZXQsXHJcbiAgICAgICAgICAgIChhMTEgKiBhMDAgLSBhMDEgKiBhMTApICogZGV0XHJcbiAgICAgICAgXSk7XHJcbiAgICB9XHJcbiAgICB0cmFuc2xhdGUodmVjdG9yKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yLno7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTJdICs9XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzBdICogeCArIHRoaXMudmFsdWVzWzRdICogeSArIHRoaXMudmFsdWVzWzhdICogejtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxM10gKz1cclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMV0gKiB4ICsgdGhpcy52YWx1ZXNbNV0gKiB5ICsgdGhpcy52YWx1ZXNbOV0gKiB6O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzE0XSArPVxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1syXSAqIHggKyB0aGlzLnZhbHVlc1s2XSAqIHkgKyB0aGlzLnZhbHVlc1sxMF0gKiB6O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzE1XSArPVxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1szXSAqIHggKyB0aGlzLnZhbHVlc1s3XSAqIHkgKyB0aGlzLnZhbHVlc1sxMV0gKiB6O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc2NhbGUodmVjdG9yKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yLno7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gKj0geDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSAqPSB4O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdICo9IHg7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gKj0geDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s0XSAqPSB5O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzVdICo9IHk7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gKj0geTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSAqPSB5O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzhdICo9IHo7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOV0gKj0gejtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMF0gKj0gejtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMV0gKj0gejtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHJvdGF0ZShhbmdsZSwgYXhpcykge1xyXG4gICAgICAgIGxldCB4ID0gYXhpcy54O1xyXG4gICAgICAgIGxldCB5ID0gYXhpcy55O1xyXG4gICAgICAgIGxldCB6ID0gYXhpcy56O1xyXG4gICAgICAgIGxldCBsZW5ndGggPSBNYXRoLnNxcnQoeCAqIHggKyB5ICogeSArIHogKiB6KTtcclxuICAgICAgICBpZiAoIWxlbmd0aCkge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGxlbmd0aCAhPT0gMSkge1xyXG4gICAgICAgICAgICBsZW5ndGggPSAxIC8gbGVuZ3RoO1xyXG4gICAgICAgICAgICB4ICo9IGxlbmd0aDtcclxuICAgICAgICAgICAgeSAqPSBsZW5ndGg7XHJcbiAgICAgICAgICAgIHogKj0gbGVuZ3RoO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBzID0gTWF0aC5zaW4oYW5nbGUpO1xyXG4gICAgICAgIGNvbnN0IGMgPSBNYXRoLmNvcyhhbmdsZSk7XHJcbiAgICAgICAgY29uc3QgdCA9IDEuMCAtIGM7XHJcbiAgICAgICAgY29uc3QgYTAwID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgYTAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgYTAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgYTAzID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgY29uc3QgYTEwID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgY29uc3QgYTExID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgY29uc3QgYTEyID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgYTEzID0gdGhpcy52YWx1ZXNbN107XHJcbiAgICAgICAgY29uc3QgYTIwID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgY29uc3QgYTIxID0gdGhpcy52YWx1ZXNbOV07XHJcbiAgICAgICAgY29uc3QgYTIyID0gdGhpcy52YWx1ZXNbMTBdO1xyXG4gICAgICAgIGNvbnN0IGEyMyA9IHRoaXMudmFsdWVzWzExXTtcclxuICAgICAgICBjb25zdCBiMDAgPSB4ICogeCAqIHQgKyBjO1xyXG4gICAgICAgIGNvbnN0IGIwMSA9IHkgKiB4ICogdCArIHogKiBzO1xyXG4gICAgICAgIGNvbnN0IGIwMiA9IHogKiB4ICogdCAtIHkgKiBzO1xyXG4gICAgICAgIGNvbnN0IGIxMCA9IHggKiB5ICogdCAtIHogKiBzO1xyXG4gICAgICAgIGNvbnN0IGIxMSA9IHkgKiB5ICogdCArIGM7XHJcbiAgICAgICAgY29uc3QgYjEyID0geiAqIHkgKiB0ICsgeCAqIHM7XHJcbiAgICAgICAgY29uc3QgYjIwID0geCAqIHogKiB0ICsgeSAqIHM7XHJcbiAgICAgICAgY29uc3QgYjIxID0geSAqIHogKiB0IC0geCAqIHM7XHJcbiAgICAgICAgY29uc3QgYjIyID0geiAqIHogKiB0ICsgYztcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IGEwMCAqIGIwMCArIGExMCAqIGIwMSArIGEyMCAqIGIwMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IGEwMSAqIGIwMCArIGExMSAqIGIwMSArIGEyMSAqIGIwMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IGEwMiAqIGIwMCArIGExMiAqIGIwMSArIGEyMiAqIGIwMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IGEwMyAqIGIwMCArIGExMyAqIGIwMSArIGEyMyAqIGIwMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s0XSA9IGEwMCAqIGIxMCArIGExMCAqIGIxMSArIGEyMCAqIGIxMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s1XSA9IGEwMSAqIGIxMCArIGExMSAqIGIxMSArIGEyMSAqIGIxMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSA9IGEwMiAqIGIxMCArIGExMiAqIGIxMSArIGEyMiAqIGIxMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSA9IGEwMyAqIGIxMCArIGExMyAqIGIxMSArIGEyMyAqIGIxMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s4XSA9IGEwMCAqIGIyMCArIGExMCAqIGIyMSArIGEyMCAqIGIyMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s5XSA9IGEwMSAqIGIyMCArIGExMSAqIGIyMSArIGEyMSAqIGIyMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMF0gPSBhMDIgKiBiMjAgKyBhMTIgKiBiMjEgKyBhMjIgKiBiMjI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTFdID0gYTAzICogYjIwICsgYTEzICogYjIxICsgYTIzICogYjIyO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGZydXN0dW0obGVmdCwgcmlnaHQsIGJvdHRvbSwgdG9wLCBuZWFyLCBmYXIpIHtcclxuICAgICAgICBjb25zdCBybCA9IHJpZ2h0IC0gbGVmdDtcclxuICAgICAgICBjb25zdCB0YiA9IHRvcCAtIGJvdHRvbTtcclxuICAgICAgICBjb25zdCBmbiA9IGZhciAtIG5lYXI7XHJcbiAgICAgICAgcmV0dXJuIG5ldyBtYXQ0KFtcclxuICAgICAgICAgICAgKG5lYXIgKiAyKSAvIHJsLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAobmVhciAqIDIpIC8gdGIsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIChyaWdodCArIGxlZnQpIC8gcmwsXHJcbiAgICAgICAgICAgICh0b3AgKyBib3R0b20pIC8gdGIsXHJcbiAgICAgICAgICAgIC0oZmFyICsgbmVhcikgLyBmbixcclxuICAgICAgICAgICAgLTEsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIC0oZmFyICogbmVhciAqIDIpIC8gZm4sXHJcbiAgICAgICAgICAgIDBcclxuICAgICAgICBdKTtcclxuICAgIH1cclxuICAgIHN0YXRpYyBwZXJzcGVjdGl2ZShmb3YsIGFzcGVjdCwgbmVhciwgZmFyKSB7XHJcbiAgICAgICAgY29uc3QgdG9wID0gbmVhciAqIE1hdGgudGFuKChmb3YgKiBNYXRoLlBJKSAvIDM2MC4wKTtcclxuICAgICAgICBjb25zdCByaWdodCA9IHRvcCAqIGFzcGVjdDtcclxuICAgICAgICByZXR1cm4gbWF0NC5mcnVzdHVtKC1yaWdodCwgcmlnaHQsIC10b3AsIHRvcCwgbmVhciwgZmFyKTtcclxuICAgIH1cclxuICAgIHN0YXRpYyBvcnRob2dyYXBoaWMobGVmdCwgcmlnaHQsIGJvdHRvbSwgdG9wLCBuZWFyLCBmYXIpIHtcclxuICAgICAgICBjb25zdCBybCA9IHJpZ2h0IC0gbGVmdDtcclxuICAgICAgICBjb25zdCB0YiA9IHRvcCAtIGJvdHRvbTtcclxuICAgICAgICBjb25zdCBmbiA9IGZhciAtIG5lYXI7XHJcbiAgICAgICAgcmV0dXJuIG5ldyBtYXQ0KFtcclxuICAgICAgICAgICAgMiAvIHJsLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAyIC8gdGIsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIC0yIC8gZm4sXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIC0obGVmdCArIHJpZ2h0KSAvIHJsLFxyXG4gICAgICAgICAgICAtKHRvcCArIGJvdHRvbSkgLyB0YixcclxuICAgICAgICAgICAgLShmYXIgKyBuZWFyKSAvIGZuLFxyXG4gICAgICAgICAgICAxXHJcbiAgICAgICAgXSk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgbG9va0F0KHBvc2l0aW9uLCB0YXJnZXQsIHVwID0gdmVjMy51cCkge1xyXG4gICAgICAgIGlmIChwb3NpdGlvbi5lcXVhbHModGFyZ2V0KSkge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5pZGVudGl0eTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeiA9IHZlYzMuZGlmZmVyZW5jZShwb3NpdGlvbiwgdGFyZ2V0KS5ub3JtYWxpemUoKTtcclxuICAgICAgICBjb25zdCB4ID0gdmVjMy5jcm9zcyh1cCwgeikubm9ybWFsaXplKCk7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlYzMuY3Jvc3MoeiwgeCkubm9ybWFsaXplKCk7XHJcbiAgICAgICAgcmV0dXJuIG5ldyBtYXQ0KFtcclxuICAgICAgICAgICAgeC54LFxyXG4gICAgICAgICAgICB5LngsXHJcbiAgICAgICAgICAgIHoueCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgeC55LFxyXG4gICAgICAgICAgICB5LnksXHJcbiAgICAgICAgICAgIHoueSxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgeC56LFxyXG4gICAgICAgICAgICB5LnosXHJcbiAgICAgICAgICAgIHoueixcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgLXZlYzMuZG90KHgsIHBvc2l0aW9uKSxcclxuICAgICAgICAgICAgLXZlYzMuZG90KHksIHBvc2l0aW9uKSxcclxuICAgICAgICAgICAgLXZlYzMuZG90KHosIHBvc2l0aW9uKSxcclxuICAgICAgICAgICAgMVxyXG4gICAgICAgIF0pO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHByb2R1Y3QobTEsIG0yLCByZXN1bHQpIHtcclxuICAgICAgICBjb25zdCBhMDAgPSBtMS5hdCgwKTtcclxuICAgICAgICBjb25zdCBhMDEgPSBtMS5hdCgxKTtcclxuICAgICAgICBjb25zdCBhMDIgPSBtMS5hdCgyKTtcclxuICAgICAgICBjb25zdCBhMDMgPSBtMS5hdCgzKTtcclxuICAgICAgICBjb25zdCBhMTAgPSBtMS5hdCg0KTtcclxuICAgICAgICBjb25zdCBhMTEgPSBtMS5hdCg1KTtcclxuICAgICAgICBjb25zdCBhMTIgPSBtMS5hdCg2KTtcclxuICAgICAgICBjb25zdCBhMTMgPSBtMS5hdCg3KTtcclxuICAgICAgICBjb25zdCBhMjAgPSBtMS5hdCg4KTtcclxuICAgICAgICBjb25zdCBhMjEgPSBtMS5hdCg5KTtcclxuICAgICAgICBjb25zdCBhMjIgPSBtMS5hdCgxMCk7XHJcbiAgICAgICAgY29uc3QgYTIzID0gbTEuYXQoMTEpO1xyXG4gICAgICAgIGNvbnN0IGEzMCA9IG0xLmF0KDEyKTtcclxuICAgICAgICBjb25zdCBhMzEgPSBtMS5hdCgxMyk7XHJcbiAgICAgICAgY29uc3QgYTMyID0gbTEuYXQoMTQpO1xyXG4gICAgICAgIGNvbnN0IGEzMyA9IG0xLmF0KDE1KTtcclxuICAgICAgICBjb25zdCBiMDAgPSBtMi5hdCgwKTtcclxuICAgICAgICBjb25zdCBiMDEgPSBtMi5hdCgxKTtcclxuICAgICAgICBjb25zdCBiMDIgPSBtMi5hdCgyKTtcclxuICAgICAgICBjb25zdCBiMDMgPSBtMi5hdCgzKTtcclxuICAgICAgICBjb25zdCBiMTAgPSBtMi5hdCg0KTtcclxuICAgICAgICBjb25zdCBiMTEgPSBtMi5hdCg1KTtcclxuICAgICAgICBjb25zdCBiMTIgPSBtMi5hdCg2KTtcclxuICAgICAgICBjb25zdCBiMTMgPSBtMi5hdCg3KTtcclxuICAgICAgICBjb25zdCBiMjAgPSBtMi5hdCg4KTtcclxuICAgICAgICBjb25zdCBiMjEgPSBtMi5hdCg5KTtcclxuICAgICAgICBjb25zdCBiMjIgPSBtMi5hdCgxMCk7XHJcbiAgICAgICAgY29uc3QgYjIzID0gbTIuYXQoMTEpO1xyXG4gICAgICAgIGNvbnN0IGIzMCA9IG0yLmF0KDEyKTtcclxuICAgICAgICBjb25zdCBiMzEgPSBtMi5hdCgxMyk7XHJcbiAgICAgICAgY29uc3QgYjMyID0gbTIuYXQoMTQpO1xyXG4gICAgICAgIGNvbnN0IGIzMyA9IG0yLmF0KDE1KTtcclxuICAgICAgICBpZiAocmVzdWx0KSB7XHJcbiAgICAgICAgICAgIHJlc3VsdC5pbml0KFtcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMCArIGIwMSAqIGExMCArIGIwMiAqIGEyMCArIGIwMyAqIGEzMCxcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMSArIGIwMSAqIGExMSArIGIwMiAqIGEyMSArIGIwMyAqIGEzMSxcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMiArIGIwMSAqIGExMiArIGIwMiAqIGEyMiArIGIwMyAqIGEzMixcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMyArIGIwMSAqIGExMyArIGIwMiAqIGEyMyArIGIwMyAqIGEzMyxcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMCArIGIxMSAqIGExMCArIGIxMiAqIGEyMCArIGIxMyAqIGEzMCxcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMSArIGIxMSAqIGExMSArIGIxMiAqIGEyMSArIGIxMyAqIGEzMSxcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMiArIGIxMSAqIGExMiArIGIxMiAqIGEyMiArIGIxMyAqIGEzMixcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMyArIGIxMSAqIGExMyArIGIxMiAqIGEyMyArIGIxMyAqIGEzMyxcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMCArIGIyMSAqIGExMCArIGIyMiAqIGEyMCArIGIyMyAqIGEzMCxcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMSArIGIyMSAqIGExMSArIGIyMiAqIGEyMSArIGIyMyAqIGEzMSxcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMiArIGIyMSAqIGExMiArIGIyMiAqIGEyMiArIGIyMyAqIGEzMixcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMyArIGIyMSAqIGExMyArIGIyMiAqIGEyMyArIGIyMyAqIGEzMyxcclxuICAgICAgICAgICAgICAgIGIzMCAqIGEwMCArIGIzMSAqIGExMCArIGIzMiAqIGEyMCArIGIzMyAqIGEzMCxcclxuICAgICAgICAgICAgICAgIGIzMCAqIGEwMSArIGIzMSAqIGExMSArIGIzMiAqIGEyMSArIGIzMyAqIGEzMSxcclxuICAgICAgICAgICAgICAgIGIzMCAqIGEwMiArIGIzMSAqIGExMiArIGIzMiAqIGEyMiArIGIzMyAqIGEzMixcclxuICAgICAgICAgICAgICAgIGIzMCAqIGEwMyArIGIzMSAqIGExMyArIGIzMiAqIGEyMyArIGIzMyAqIGEzM1xyXG4gICAgICAgICAgICBdKTtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgIHJldHVybiBuZXcgbWF0NChbXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDAgKyBiMDEgKiBhMTAgKyBiMDIgKiBhMjAgKyBiMDMgKiBhMzAsXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDEgKyBiMDEgKiBhMTEgKyBiMDIgKiBhMjEgKyBiMDMgKiBhMzEsXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDIgKyBiMDEgKiBhMTIgKyBiMDIgKiBhMjIgKyBiMDMgKiBhMzIsXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDMgKyBiMDEgKiBhMTMgKyBiMDIgKiBhMjMgKyBiMDMgKiBhMzMsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDAgKyBiMTEgKiBhMTAgKyBiMTIgKiBhMjAgKyBiMTMgKiBhMzAsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDEgKyBiMTEgKiBhMTEgKyBiMTIgKiBhMjEgKyBiMTMgKiBhMzEsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDIgKyBiMTEgKiBhMTIgKyBiMTIgKiBhMjIgKyBiMTMgKiBhMzIsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDMgKyBiMTEgKiBhMTMgKyBiMTIgKiBhMjMgKyBiMTMgKiBhMzMsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDAgKyBiMjEgKiBhMTAgKyBiMjIgKiBhMjAgKyBiMjMgKiBhMzAsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDEgKyBiMjEgKiBhMTEgKyBiMjIgKiBhMjEgKyBiMjMgKiBhMzEsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDIgKyBiMjEgKiBhMTIgKyBiMjIgKiBhMjIgKyBiMjMgKiBhMzIsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDMgKyBiMjEgKiBhMTMgKyBiMjIgKiBhMjMgKyBiMjMgKiBhMzMsXHJcbiAgICAgICAgICAgICAgICBiMzAgKiBhMDAgKyBiMzEgKiBhMTAgKyBiMzIgKiBhMjAgKyBiMzMgKiBhMzAsXHJcbiAgICAgICAgICAgICAgICBiMzAgKiBhMDEgKyBiMzEgKiBhMTEgKyBiMzIgKiBhMjEgKyBiMzMgKiBhMzEsXHJcbiAgICAgICAgICAgICAgICBiMzAgKiBhMDIgKyBiMzEgKiBhMTIgKyBiMzIgKiBhMjIgKyBiMzMgKiBhMzIsXHJcbiAgICAgICAgICAgICAgICBiMzAgKiBhMDMgKyBiMzEgKiBhMTMgKyBiMzIgKiBhMjMgKyBiMzMgKiBhMzNcclxuICAgICAgICAgICAgXSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbm1hdDQuaWRlbnRpdHkgPSBuZXcgbWF0NCgpLnNldElkZW50aXR5KCk7XHJcbiIsImltcG9ydCB2ZWMzIGZyb20gJy4vdmVjMyc7XHJcbmltcG9ydCB7IGVwc2lsb24gfSBmcm9tICcuL2NvbnN0YW50cyc7XHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIHZlYzIge1xyXG4gICAgY29uc3RydWN0b3IodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXMgPSBuZXcgRmxvYXQzMkFycmF5KDIpO1xyXG4gICAgICAgIGlmICh2YWx1ZXMgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgICB0aGlzLnh5ID0gdmFsdWVzO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGdldCB4KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1swXTtcclxuICAgIH1cclxuICAgIGdldCB5KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIGdldCB4eSgpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXV07XHJcbiAgICB9XHJcbiAgICBzZXQgeCh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeSh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeHkodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICB9XHJcbiAgICBhdChpbmRleCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1tpbmRleF07XHJcbiAgICB9XHJcbiAgICByZXNldCgpIHtcclxuICAgICAgICB0aGlzLnggPSAwO1xyXG4gICAgICAgIHRoaXMueSA9IDA7XHJcbiAgICB9XHJcbiAgICBjb3B5KGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMyKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHRoaXMueDtcclxuICAgICAgICBkZXN0LnkgPSB0aGlzLnk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBuZWdhdGUoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gLXRoaXMueDtcclxuICAgICAgICBkZXN0LnkgPSAtdGhpcy55O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgZXF1YWxzKHZlY3RvciwgdGhyZXNob2xkID0gZXBzaWxvbikge1xyXG4gICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnggLSB2ZWN0b3IueCkgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoTWF0aC5hYnModGhpcy55IC0gdmVjdG9yLnkpID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgICBsZW5ndGgoKSB7XHJcbiAgICAgICAgcmV0dXJuIE1hdGguc3FydCh0aGlzLnNxdWFyZWRMZW5ndGgoKSk7XHJcbiAgICB9XHJcbiAgICBzcXVhcmVkTGVuZ3RoKCkge1xyXG4gICAgICAgIGNvbnN0IHggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHRoaXMueTtcclxuICAgICAgICByZXR1cm4geCAqIHggKyB5ICogeTtcclxuICAgIH1cclxuICAgIGFkZCh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggKz0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55ICs9IHZlY3Rvci55O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc3VidHJhY3QodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54IC09IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSAtPSB2ZWN0b3IueTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIG11bHRpcGx5KHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCAqPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgKj0gdmVjdG9yLnk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBkaXZpZGUodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54IC89IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSAvPSB2ZWN0b3IueTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHNjYWxlKHZhbHVlLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggKj0gdmFsdWU7XHJcbiAgICAgICAgZGVzdC55ICo9IHZhbHVlO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgbm9ybWFsaXplKGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBsZW5ndGggPSB0aGlzLmxlbmd0aCgpO1xyXG4gICAgICAgIGlmIChsZW5ndGggPT09IDEpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChsZW5ndGggPT09IDApIHtcclxuICAgICAgICAgICAgZGVzdC54ID0gMDtcclxuICAgICAgICAgICAgZGVzdC55ID0gMDtcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxlbmd0aCA9IDEuMCAvIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnggKj0gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueSAqPSBsZW5ndGg7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseU1hdDIobWF0cml4LCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gbWF0cml4Lm11bHRpcGx5VmVjMih0aGlzLCBkZXN0KTtcclxuICAgIH1cclxuICAgIG11bHRpcGx5TWF0MyhtYXRyaXgsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBtYXRyaXgubXVsdGlwbHlWZWMyKHRoaXMsIGRlc3QpO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGNyb3NzKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB4MiA9IHZlY3RvcjIueDtcclxuICAgICAgICBjb25zdCB5MiA9IHZlY3RvcjIueTtcclxuICAgICAgICBjb25zdCB6ID0geCAqIHkyIC0geSAqIHgyO1xyXG4gICAgICAgIGRlc3QueCA9IDA7XHJcbiAgICAgICAgZGVzdC55ID0gMDtcclxuICAgICAgICBkZXN0LnogPSB6O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGRvdCh2ZWN0b3IsIHZlY3RvcjIpIHtcclxuICAgICAgICByZXR1cm4gdmVjdG9yLnggKiB2ZWN0b3IyLnggKyB2ZWN0b3IueSAqIHZlY3RvcjIueTtcclxuICAgIH1cclxuICAgIHN0YXRpYyBkaXN0YW5jZSh2ZWN0b3IsIHZlY3RvcjIpIHtcclxuICAgICAgICByZXR1cm4gTWF0aC5zcXJ0KHRoaXMuc3F1YXJlZERpc3RhbmNlKHZlY3RvciwgdmVjdG9yMikpO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHNxdWFyZWREaXN0YW5jZSh2ZWN0b3IsIHZlY3RvcjIpIHtcclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yMi54IC0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3RvcjIueSAtIHZlY3Rvci55O1xyXG4gICAgICAgIHJldHVybiB4ICogeCArIHkgKiB5O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGRpcmVjdGlvbih2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMyKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueCAtIHZlY3RvcjIueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnkgLSB2ZWN0b3IyLnk7XHJcbiAgICAgICAgbGV0IGxlbmd0aCA9IE1hdGguc3FydCh4ICogeCArIHkgKiB5KTtcclxuICAgICAgICBpZiAobGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIGRlc3QueCA9IDA7XHJcbiAgICAgICAgICAgIGRlc3QueSA9IDA7XHJcbiAgICAgICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZW5ndGggPSAxIC8gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueCA9IHggKiBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC55ID0geSAqIGxlbmd0aDtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBtaXgodmVjdG9yLCB2ZWN0b3IyLCB0aW1lLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMigpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGNvbnN0IHgyID0gdmVjdG9yMi54O1xyXG4gICAgICAgIGNvbnN0IHkyID0gdmVjdG9yMi55O1xyXG4gICAgICAgIGRlc3QueCA9IHggKyB0aW1lICogKHgyIC0geCk7XHJcbiAgICAgICAgZGVzdC55ID0geSArIHRpbWUgKiAoeTIgLSB5KTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBzdW0odmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMigpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCArIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSArIHZlY3RvcjIueTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBkaWZmZXJlbmNlKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzIoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggLSB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgLSB2ZWN0b3IyLnk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgcHJvZHVjdCh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMyKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54ICogdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55ICogdmVjdG9yMi55O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHF1b3RpZW50KHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzIoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggLyB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgLyB2ZWN0b3IyLnk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbn1cclxudmVjMi56ZXJvID0gbmV3IHZlYzIoWzAsIDBdKTtcclxudmVjMi5vbmUgPSBuZXcgdmVjMihbMSwgMV0pO1xyXG4iLCJpbXBvcnQgbWF0NCBmcm9tICcuL21hdDQnO1xyXG5pbXBvcnQgcXVhdCBmcm9tICcuL3F1YXQnO1xyXG5pbXBvcnQgdmVjMiBmcm9tICcuL3ZlYzInO1xyXG5pbXBvcnQgdmVjMyBmcm9tICcuL3ZlYzMnO1xyXG5pbXBvcnQgeyBlcHNpbG9uIH0gZnJvbSAnLi9jb25zdGFudHMnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBtYXQzIHtcclxuICAgIGNvbnN0cnVjdG9yKHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzID0gbmV3IEZsb2F0MzJBcnJheSg5KTtcclxuICAgICAgICBpZiAodmFsdWVzICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgdGhpcy5pbml0KHZhbHVlcyk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgYXQoaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbaW5kZXhdO1xyXG4gICAgfVxyXG4gICAgaW5pdCh2YWx1ZXMpIHtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDk7IGkrKykge1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpXSA9IHZhbHVlc1tpXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICByZXNldCgpIHtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDk7IGkrKykge1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpXSA9IDA7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgY29weShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgbWF0MygpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDk7IGkrKykge1xyXG4gICAgICAgICAgICBkZXN0LnZhbHVlc1tpXSA9IHRoaXMudmFsdWVzW2ldO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIGFsbCgpIHtcclxuICAgICAgICBjb25zdCBkYXRhID0gW107XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA5OyBpKyspIHtcclxuICAgICAgICAgICAgZGF0YVtpXSA9IHRoaXMudmFsdWVzW2ldO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gZGF0YTtcclxuICAgIH1cclxuICAgIHJvdyhpbmRleCkge1xyXG4gICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4ICogMyArIDBdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleCAqIDMgKyAxXSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXggKiAzICsgMl1cclxuICAgICAgICBdO1xyXG4gICAgfVxyXG4gICAgY29sKGluZGV4KSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1tpbmRleF0sIHRoaXMudmFsdWVzW2luZGV4ICsgM10sIHRoaXMudmFsdWVzW2luZGV4ICsgNl1dO1xyXG4gICAgfVxyXG4gICAgZXF1YWxzKG1hdHJpeCwgdGhyZXNob2xkID0gZXBzaWxvbikge1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgOTsgaSsrKSB7XHJcbiAgICAgICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnZhbHVlc1tpXSAtIG1hdHJpeC5hdChpKSkgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICAgIGRldGVybWluYW50KCkge1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IHRoaXMudmFsdWVzWzddO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIGNvbnN0IGRldDAxID0gYTIyICogYTExIC0gYTEyICogYTIxO1xyXG4gICAgICAgIGNvbnN0IGRldDExID0gLWEyMiAqIGExMCArIGExMiAqIGEyMDtcclxuICAgICAgICBjb25zdCBkZXQyMSA9IGEyMSAqIGExMCAtIGExMSAqIGEyMDtcclxuICAgICAgICByZXR1cm4gYTAwICogZGV0MDEgKyBhMDEgKiBkZXQxMSArIGEwMiAqIGRldDIxO1xyXG4gICAgfVxyXG4gICAgc2V0SWRlbnRpdHkoKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSAxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzRdID0gMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s1XSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s4XSA9IDE7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICB0cmFuc3Bvc2UoKSB7XHJcbiAgICAgICAgY29uc3QgdGVtcDAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgdGVtcDAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgdGVtcDEyID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gdGVtcDAxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzVdID0gdGhpcy52YWx1ZXNbN107XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gPSB0ZW1wMDI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gPSB0ZW1wMTI7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBpbnZlcnNlKCkge1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IHRoaXMudmFsdWVzWzddO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIGNvbnN0IGRldDAxID0gYTIyICogYTExIC0gYTEyICogYTIxO1xyXG4gICAgICAgIGNvbnN0IGRldDExID0gLWEyMiAqIGExMCArIGExMiAqIGEyMDtcclxuICAgICAgICBjb25zdCBkZXQyMSA9IGEyMSAqIGExMCAtIGExMSAqIGEyMDtcclxuICAgICAgICBsZXQgZGV0ID0gYTAwICogZGV0MDEgKyBhMDEgKiBkZXQxMSArIGEwMiAqIGRldDIxO1xyXG4gICAgICAgIGlmICghZGV0KSB7XHJcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXQgPSAxLjAgLyBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSBkZXQwMSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9ICgtYTIyICogYTAxICsgYTAyICogYTIxKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IChhMTIgKiBhMDEgLSBhMDIgKiBhMTEpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gZGV0MTEgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNF0gPSAoYTIyICogYTAwIC0gYTAyICogYTIwKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s1XSA9ICgtYTEyICogYTAwICsgYTAyICogYTEwKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSA9IGRldDIxICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddID0gKC1hMjEgKiBhMDAgKyBhMDEgKiBhMjApICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzhdID0gKGExMSAqIGEwMCAtIGEwMSAqIGExMCkgKiBkZXQ7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseShtYXRyaXgpIHtcclxuICAgICAgICBjb25zdCBhMDAgPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBhMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBhMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBhMTAgPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICBjb25zdCBhMTEgPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICBjb25zdCBhMTIgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICBjb25zdCBhMjAgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCBhMjEgPSB0aGlzLnZhbHVlc1s3XTtcclxuICAgICAgICBjb25zdCBhMjIgPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICBjb25zdCBiMDAgPSBtYXRyaXguYXQoMCk7XHJcbiAgICAgICAgY29uc3QgYjAxID0gbWF0cml4LmF0KDEpO1xyXG4gICAgICAgIGNvbnN0IGIwMiA9IG1hdHJpeC5hdCgyKTtcclxuICAgICAgICBjb25zdCBiMTAgPSBtYXRyaXguYXQoMyk7XHJcbiAgICAgICAgY29uc3QgYjExID0gbWF0cml4LmF0KDQpO1xyXG4gICAgICAgIGNvbnN0IGIxMiA9IG1hdHJpeC5hdCg1KTtcclxuICAgICAgICBjb25zdCBiMjAgPSBtYXRyaXguYXQoNik7XHJcbiAgICAgICAgY29uc3QgYjIxID0gbWF0cml4LmF0KDcpO1xyXG4gICAgICAgIGNvbnN0IGIyMiA9IG1hdHJpeC5hdCg4KTtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IGIwMCAqIGEwMCArIGIwMSAqIGExMCArIGIwMiAqIGEyMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IGIwMCAqIGEwMSArIGIwMSAqIGExMSArIGIwMiAqIGEyMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IGIwMCAqIGEwMiArIGIwMSAqIGExMiArIGIwMiAqIGEyMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IGIxMCAqIGEwMCArIGIxMSAqIGExMCArIGIxMiAqIGEyMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s0XSA9IGIxMCAqIGEwMSArIGIxMSAqIGExMSArIGIxMiAqIGEyMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s1XSA9IGIxMCAqIGEwMiArIGIxMSAqIGExMiArIGIxMiAqIGEyMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSA9IGIyMCAqIGEwMCArIGIyMSAqIGExMCArIGIyMiAqIGEyMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSA9IGIyMCAqIGEwMSArIGIyMSAqIGExMSArIGIyMiAqIGEyMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s4XSA9IGIyMCAqIGEwMiArIGIyMSAqIGExMiArIGIyMiAqIGEyMjtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIG11bHRpcGx5VmVjMih2ZWN0b3IsIHJlc3VsdCkge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgaWYgKHJlc3VsdCkge1xyXG4gICAgICAgICAgICByZXN1bHQueHkgPSBbXHJcbiAgICAgICAgICAgICAgICB4ICogdGhpcy52YWx1ZXNbMF0gKyB5ICogdGhpcy52YWx1ZXNbM10gKyB0aGlzLnZhbHVlc1s2XSxcclxuICAgICAgICAgICAgICAgIHggKiB0aGlzLnZhbHVlc1sxXSArIHkgKiB0aGlzLnZhbHVlc1s0XSArIHRoaXMudmFsdWVzWzddXHJcbiAgICAgICAgICAgIF07XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICByZXR1cm4gbmV3IHZlYzIoW1xyXG4gICAgICAgICAgICAgICAgeCAqIHRoaXMudmFsdWVzWzBdICsgeSAqIHRoaXMudmFsdWVzWzNdICsgdGhpcy52YWx1ZXNbNl0sXHJcbiAgICAgICAgICAgICAgICB4ICogdGhpcy52YWx1ZXNbMV0gKyB5ICogdGhpcy52YWx1ZXNbNF0gKyB0aGlzLnZhbHVlc1s3XVxyXG4gICAgICAgICAgICBdKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseVZlYzModmVjdG9yLCByZXN1bHQpIHtcclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGNvbnN0IHogPSB2ZWN0b3IuejtcclxuICAgICAgICBpZiAocmVzdWx0KSB7XHJcbiAgICAgICAgICAgIHJlc3VsdC54eXogPSBbXHJcbiAgICAgICAgICAgICAgICB4ICogdGhpcy52YWx1ZXNbMF0gKyB5ICogdGhpcy52YWx1ZXNbM10gKyB6ICogdGhpcy52YWx1ZXNbNl0sXHJcbiAgICAgICAgICAgICAgICB4ICogdGhpcy52YWx1ZXNbMV0gKyB5ICogdGhpcy52YWx1ZXNbNF0gKyB6ICogdGhpcy52YWx1ZXNbN10sXHJcbiAgICAgICAgICAgICAgICB4ICogdGhpcy52YWx1ZXNbMl0gKyB5ICogdGhpcy52YWx1ZXNbNV0gKyB6ICogdGhpcy52YWx1ZXNbOF1cclxuICAgICAgICAgICAgXTtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgIHJldHVybiBuZXcgdmVjMyhbXHJcbiAgICAgICAgICAgICAgICB4ICogdGhpcy52YWx1ZXNbMF0gKyB5ICogdGhpcy52YWx1ZXNbM10gKyB6ICogdGhpcy52YWx1ZXNbNl0sXHJcbiAgICAgICAgICAgICAgICB4ICogdGhpcy52YWx1ZXNbMV0gKyB5ICogdGhpcy52YWx1ZXNbNF0gKyB6ICogdGhpcy52YWx1ZXNbN10sXHJcbiAgICAgICAgICAgICAgICB4ICogdGhpcy52YWx1ZXNbMl0gKyB5ICogdGhpcy52YWx1ZXNbNV0gKyB6ICogdGhpcy52YWx1ZXNbOF1cclxuICAgICAgICAgICAgXSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgdG9NYXQ0KHJlc3VsdCkge1xyXG4gICAgICAgIGlmIChyZXN1bHQpIHtcclxuICAgICAgICAgICAgcmVzdWx0LmluaXQoW1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMF0sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxXSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzJdLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzNdLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNF0sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s1XSxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s2XSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzddLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbOF0sXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMVxyXG4gICAgICAgICAgICBdKTtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgIHJldHVybiBuZXcgbWF0NChbXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1swXSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzFdLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMl0sXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbM10sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s0XSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzVdLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzZdLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbN10sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s4XSxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICAxXHJcbiAgICAgICAgICAgIF0pO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHRvUXVhdCgpIHtcclxuICAgICAgICBjb25zdCBtMDAgPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBtMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBtMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBtMTAgPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICBjb25zdCBtMTEgPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICBjb25zdCBtMTIgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICBjb25zdCBtMjAgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCBtMjEgPSB0aGlzLnZhbHVlc1s3XTtcclxuICAgICAgICBjb25zdCBtMjIgPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICBjb25zdCBmb3VyWFNxdWFyZWRNaW51czEgPSBtMDAgLSBtMTEgLSBtMjI7XHJcbiAgICAgICAgY29uc3QgZm91cllTcXVhcmVkTWludXMxID0gbTExIC0gbTAwIC0gbTIyO1xyXG4gICAgICAgIGNvbnN0IGZvdXJaU3F1YXJlZE1pbnVzMSA9IG0yMiAtIG0wMCAtIG0xMTtcclxuICAgICAgICBjb25zdCBmb3VyV1NxdWFyZWRNaW51czEgPSBtMDAgKyBtMTEgKyBtMjI7XHJcbiAgICAgICAgbGV0IGJpZ2dlc3RJbmRleCA9IDA7XHJcbiAgICAgICAgbGV0IGZvdXJCaWdnZXN0U3F1YXJlZE1pbnVzMSA9IGZvdXJXU3F1YXJlZE1pbnVzMTtcclxuICAgICAgICBpZiAoZm91clhTcXVhcmVkTWludXMxID4gZm91ckJpZ2dlc3RTcXVhcmVkTWludXMxKSB7XHJcbiAgICAgICAgICAgIGZvdXJCaWdnZXN0U3F1YXJlZE1pbnVzMSA9IGZvdXJYU3F1YXJlZE1pbnVzMTtcclxuICAgICAgICAgICAgYmlnZ2VzdEluZGV4ID0gMTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGZvdXJZU3F1YXJlZE1pbnVzMSA+IGZvdXJCaWdnZXN0U3F1YXJlZE1pbnVzMSkge1xyXG4gICAgICAgICAgICBmb3VyQmlnZ2VzdFNxdWFyZWRNaW51czEgPSBmb3VyWVNxdWFyZWRNaW51czE7XHJcbiAgICAgICAgICAgIGJpZ2dlc3RJbmRleCA9IDI7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChmb3VyWlNxdWFyZWRNaW51czEgPiBmb3VyQmlnZ2VzdFNxdWFyZWRNaW51czEpIHtcclxuICAgICAgICAgICAgZm91ckJpZ2dlc3RTcXVhcmVkTWludXMxID0gZm91clpTcXVhcmVkTWludXMxO1xyXG4gICAgICAgICAgICBiaWdnZXN0SW5kZXggPSAzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBiaWdnZXN0VmFsID0gTWF0aC5zcXJ0KGZvdXJCaWdnZXN0U3F1YXJlZE1pbnVzMSArIDEpICogMC41O1xyXG4gICAgICAgIGNvbnN0IG11bHQgPSAwLjI1IC8gYmlnZ2VzdFZhbDtcclxuICAgICAgICBjb25zdCByZXN1bHQgPSBuZXcgcXVhdCgpO1xyXG4gICAgICAgIHN3aXRjaCAoYmlnZ2VzdEluZGV4KSB7XHJcbiAgICAgICAgICAgIGNhc2UgMDpcclxuICAgICAgICAgICAgICAgIHJlc3VsdC53ID0gYmlnZ2VzdFZhbDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC54ID0gKG0xMiAtIG0yMSkgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnkgPSAobTIwIC0gbTAyKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueiA9IChtMDEgLSBtMTApICogbXVsdDtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICBjYXNlIDE6XHJcbiAgICAgICAgICAgICAgICByZXN1bHQudyA9IChtMTIgLSBtMjEpICogbXVsdDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC54ID0gYmlnZ2VzdFZhbDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC55ID0gKG0wMSArIG0xMCkgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnogPSAobTIwICsgbTAyKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgY2FzZSAyOlxyXG4gICAgICAgICAgICAgICAgcmVzdWx0LncgPSAobTIwIC0gbTAyKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueCA9IChtMDEgKyBtMTApICogbXVsdDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC55ID0gYmlnZ2VzdFZhbDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC56ID0gKG0xMiArIG0yMSkgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGNhc2UgMzpcclxuICAgICAgICAgICAgICAgIHJlc3VsdC53ID0gKG0wMSAtIG0xMCkgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnggPSAobTIwICsgbTAyKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueSA9IChtMTIgKyBtMjEpICogbXVsdDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC56ID0gYmlnZ2VzdFZhbDtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfVxyXG4gICAgcm90YXRlKGFuZ2xlLCBheGlzKSB7XHJcbiAgICAgICAgbGV0IHggPSBheGlzLng7XHJcbiAgICAgICAgbGV0IHkgPSBheGlzLnk7XHJcbiAgICAgICAgbGV0IHogPSBheGlzLno7XHJcbiAgICAgICAgbGV0IGxlbmd0aCA9IE1hdGguc3FydCh4ICogeCArIHkgKiB5ICsgeiAqIHopO1xyXG4gICAgICAgIGlmICghbGVuZ3RoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAobGVuZ3RoICE9PSAxKSB7XHJcbiAgICAgICAgICAgIGxlbmd0aCA9IDEgLyBsZW5ndGg7XHJcbiAgICAgICAgICAgIHggKj0gbGVuZ3RoO1xyXG4gICAgICAgICAgICB5ICo9IGxlbmd0aDtcclxuICAgICAgICAgICAgeiAqPSBsZW5ndGg7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHMgPSBNYXRoLnNpbihhbmdsZSk7XHJcbiAgICAgICAgY29uc3QgYyA9IE1hdGguY29zKGFuZ2xlKTtcclxuICAgICAgICBjb25zdCB0ID0gMS4wIC0gYztcclxuICAgICAgICBjb25zdCBhMDAgPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBhMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBhMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBhMTAgPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICBjb25zdCBhMTEgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICBjb25zdCBhMTIgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCBhMjAgPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICBjb25zdCBhMjEgPSB0aGlzLnZhbHVlc1s5XTtcclxuICAgICAgICBjb25zdCBhMjIgPSB0aGlzLnZhbHVlc1sxMF07XHJcbiAgICAgICAgY29uc3QgYjAwID0geCAqIHggKiB0ICsgYztcclxuICAgICAgICBjb25zdCBiMDEgPSB5ICogeCAqIHQgKyB6ICogcztcclxuICAgICAgICBjb25zdCBiMDIgPSB6ICogeCAqIHQgLSB5ICogcztcclxuICAgICAgICBjb25zdCBiMTAgPSB4ICogeSAqIHQgLSB6ICogcztcclxuICAgICAgICBjb25zdCBiMTEgPSB5ICogeSAqIHQgKyBjO1xyXG4gICAgICAgIGNvbnN0IGIxMiA9IHogKiB5ICogdCArIHggKiBzO1xyXG4gICAgICAgIGNvbnN0IGIyMCA9IHggKiB6ICogdCArIHkgKiBzO1xyXG4gICAgICAgIGNvbnN0IGIyMSA9IHkgKiB6ICogdCAtIHggKiBzO1xyXG4gICAgICAgIGNvbnN0IGIyMiA9IHogKiB6ICogdCArIGM7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSBhMDAgKiBiMDAgKyBhMTAgKiBiMDEgKyBhMjAgKiBiMDI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSBhMDEgKiBiMDAgKyBhMTEgKiBiMDEgKyBhMjEgKiBiMDI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSBhMDIgKiBiMDAgKyBhMTIgKiBiMDEgKyBhMjIgKiBiMDI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSBhMDAgKiBiMTAgKyBhMTAgKiBiMTEgKyBhMjAgKiBiMTI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNF0gPSBhMDEgKiBiMTAgKyBhMTEgKiBiMTEgKyBhMjEgKiBiMTI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNV0gPSBhMDIgKiBiMTAgKyBhMTIgKiBiMTEgKyBhMjIgKiBiMTI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gPSBhMDAgKiBiMjAgKyBhMTAgKiBiMjEgKyBhMjAgKiBiMjI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gPSBhMDEgKiBiMjAgKyBhMTEgKiBiMjEgKyBhMjEgKiBiMjI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOF0gPSBhMDIgKiBiMjAgKyBhMTIgKiBiMjEgKyBhMjIgKiBiMjI7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgcHJvZHVjdChtMSwgbTIsIHJlc3VsdCkge1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IG0xLmF0KDApO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IG0xLmF0KDEpO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IG0xLmF0KDIpO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IG0xLmF0KDMpO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IG0xLmF0KDQpO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IG0xLmF0KDUpO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IG0xLmF0KDYpO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IG0xLmF0KDcpO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IG0xLmF0KDgpO1xyXG4gICAgICAgIGNvbnN0IGIwMCA9IG0yLmF0KDApO1xyXG4gICAgICAgIGNvbnN0IGIwMSA9IG0yLmF0KDEpO1xyXG4gICAgICAgIGNvbnN0IGIwMiA9IG0yLmF0KDIpO1xyXG4gICAgICAgIGNvbnN0IGIxMCA9IG0yLmF0KDMpO1xyXG4gICAgICAgIGNvbnN0IGIxMSA9IG0yLmF0KDQpO1xyXG4gICAgICAgIGNvbnN0IGIxMiA9IG0yLmF0KDUpO1xyXG4gICAgICAgIGNvbnN0IGIyMCA9IG0yLmF0KDYpO1xyXG4gICAgICAgIGNvbnN0IGIyMSA9IG0yLmF0KDcpO1xyXG4gICAgICAgIGNvbnN0IGIyMiA9IG0yLmF0KDgpO1xyXG4gICAgICAgIGlmIChyZXN1bHQpIHtcclxuICAgICAgICAgICAgcmVzdWx0LmluaXQoW1xyXG4gICAgICAgICAgICAgICAgYjAwICogYTAwICsgYjAxICogYTEwICsgYjAyICogYTIwLFxyXG4gICAgICAgICAgICAgICAgYjAwICogYTAxICsgYjAxICogYTExICsgYjAyICogYTIxLFxyXG4gICAgICAgICAgICAgICAgYjAwICogYTAyICsgYjAxICogYTEyICsgYjAyICogYTIyLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAwICsgYjExICogYTEwICsgYjEyICogYTIwLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAxICsgYjExICogYTExICsgYjEyICogYTIxLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAyICsgYjExICogYTEyICsgYjEyICogYTIyLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAwICsgYjIxICogYTEwICsgYjIyICogYTIwLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAxICsgYjIxICogYTExICsgYjIyICogYTIxLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAyICsgYjIxICogYTEyICsgYjIyICogYTIyXHJcbiAgICAgICAgICAgIF0pO1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIG5ldyBtYXQzKFtcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMCArIGIwMSAqIGExMCArIGIwMiAqIGEyMCxcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMSArIGIwMSAqIGExMSArIGIwMiAqIGEyMSxcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMiArIGIwMSAqIGExMiArIGIwMiAqIGEyMixcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMCArIGIxMSAqIGExMCArIGIxMiAqIGEyMCxcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMSArIGIxMSAqIGExMSArIGIxMiAqIGEyMSxcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMiArIGIxMSAqIGExMiArIGIxMiAqIGEyMixcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMCArIGIyMSAqIGExMCArIGIyMiAqIGEyMCxcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMSArIGIyMSAqIGExMSArIGIyMiAqIGEyMSxcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMiArIGIyMSAqIGExMiArIGIyMiAqIGEyMlxyXG4gICAgICAgICAgICBdKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn1cclxubWF0My5pZGVudGl0eSA9IG5ldyBtYXQzKCkuc2V0SWRlbnRpdHkoKTtcclxuIiwiaW1wb3J0IG1hdDMgZnJvbSAnLi9tYXQzJztcclxuaW1wb3J0IG1hdDQgZnJvbSAnLi9tYXQ0JztcclxuaW1wb3J0IHZlYzMgZnJvbSAnLi92ZWMzJztcclxuaW1wb3J0IHsgZXBzaWxvbiB9IGZyb20gJy4vY29uc3RhbnRzJztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgcXVhdCB7XHJcbiAgICBjb25zdHJ1Y3Rvcih2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkoNCk7XHJcbiAgICAgICAgaWYgKHZhbHVlcyAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMueHl6dyA9IHZhbHVlcztcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBnZXQgeCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMF07XHJcbiAgICB9XHJcbiAgICBnZXQgeSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMV07XHJcbiAgICB9XHJcbiAgICBnZXQgeigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMl07XHJcbiAgICB9XHJcbiAgICBnZXQgdygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbM107XHJcbiAgICB9XHJcbiAgICBnZXQgeHkoKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV1dO1xyXG4gICAgfVxyXG4gICAgZ2V0IHh5eigpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXSwgdGhpcy52YWx1ZXNbMl1dO1xyXG4gICAgfVxyXG4gICAgZ2V0IHh5encoKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV0sIHRoaXMudmFsdWVzWzJdLCB0aGlzLnZhbHVlc1szXV07XHJcbiAgICB9XHJcbiAgICBzZXQgeCh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeSh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeih2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgdyh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeHkodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICB9XHJcbiAgICBzZXQgeHl6KHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWVzWzJdO1xyXG4gICAgfVxyXG4gICAgc2V0IHh5encodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZXNbMl07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSB2YWx1ZXNbM107XHJcbiAgICB9XHJcbiAgICBhdChpbmRleCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1tpbmRleF07XHJcbiAgICB9XHJcbiAgICByZXNldCgpIHtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDQ7IGkrKykge1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpXSA9IDA7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgY29weShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgcXVhdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDQ7IGkrKykge1xyXG4gICAgICAgICAgICBkZXN0LnZhbHVlc1tpXSA9IHRoaXMudmFsdWVzW2ldO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHJvbGwoKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHRoaXMueDtcclxuICAgICAgICBjb25zdCB5ID0gdGhpcy55O1xyXG4gICAgICAgIGNvbnN0IHogPSB0aGlzLno7XHJcbiAgICAgICAgY29uc3QgdyA9IHRoaXMudztcclxuICAgICAgICByZXR1cm4gTWF0aC5hdGFuMigyLjAgKiAoeCAqIHkgKyB3ICogeiksIHcgKiB3ICsgeCAqIHggLSB5ICogeSAtIHogKiB6KTtcclxuICAgIH1cclxuICAgIHBpdGNoKCkge1xyXG4gICAgICAgIGNvbnN0IHggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHRoaXMueTtcclxuICAgICAgICBjb25zdCB6ID0gdGhpcy56O1xyXG4gICAgICAgIGNvbnN0IHcgPSB0aGlzLnc7XHJcbiAgICAgICAgcmV0dXJuIE1hdGguYXRhbjIoMi4wICogKHkgKiB6ICsgdyAqIHgpLCB3ICogdyAtIHggKiB4IC0geSAqIHkgKyB6ICogeik7XHJcbiAgICB9XHJcbiAgICB5YXcoKSB7XHJcbiAgICAgICAgcmV0dXJuIE1hdGguYXNpbigyLjAgKiAodGhpcy54ICogdGhpcy56IC0gdGhpcy53ICogdGhpcy55KSk7XHJcbiAgICB9XHJcbiAgICBlcXVhbHModmVjdG9yLCB0aHJlc2hvbGQgPSBlcHNpbG9uKSB7XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA0OyBpKyspIHtcclxuICAgICAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMudmFsdWVzW2ldIC0gdmVjdG9yLmF0KGkpKSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gICAgc2V0SWRlbnRpdHkoKSB7XHJcbiAgICAgICAgdGhpcy54ID0gMDtcclxuICAgICAgICB0aGlzLnkgPSAwO1xyXG4gICAgICAgIHRoaXMueiA9IDA7XHJcbiAgICAgICAgdGhpcy53ID0gMTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIGNhbGN1bGF0ZVcoKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHRoaXMueDtcclxuICAgICAgICBjb25zdCB5ID0gdGhpcy55O1xyXG4gICAgICAgIGNvbnN0IHogPSB0aGlzLno7XHJcbiAgICAgICAgdGhpcy53ID0gLU1hdGguc3FydChNYXRoLmFicygxLjAgLSB4ICogeCAtIHkgKiB5IC0geiAqIHopKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIGludmVyc2UoKSB7XHJcbiAgICAgICAgY29uc3QgZG90ID0gcXVhdC5kb3QodGhpcywgdGhpcyk7XHJcbiAgICAgICAgaWYgKCFkb3QpIHtcclxuICAgICAgICAgICAgdGhpcy54eXp3ID0gWzAsIDAsIDAsIDBdO1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgaW52RG90ID0gZG90ID8gMS4wIC8gZG90IDogMDtcclxuICAgICAgICB0aGlzLnggKj0gLWludkRvdDtcclxuICAgICAgICB0aGlzLnkgKj0gLWludkRvdDtcclxuICAgICAgICB0aGlzLnogKj0gLWludkRvdDtcclxuICAgICAgICB0aGlzLncgKj0gaW52RG90O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgY29uanVnYXRlKCkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdICo9IC0xO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdICo9IC0xO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdICo9IC0xO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgbGVuZ3RoKCkge1xyXG4gICAgICAgIGNvbnN0IHggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHRoaXMueTtcclxuICAgICAgICBjb25zdCB6ID0gdGhpcy56O1xyXG4gICAgICAgIGNvbnN0IHcgPSB0aGlzLnc7XHJcbiAgICAgICAgcmV0dXJuIE1hdGguc3FydCh4ICogeCArIHkgKiB5ICsgeiAqIHogKyB3ICogdyk7XHJcbiAgICB9XHJcbiAgICBub3JtYWxpemUoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHRoaXMueDtcclxuICAgICAgICBjb25zdCB5ID0gdGhpcy55O1xyXG4gICAgICAgIGNvbnN0IHogPSB0aGlzLno7XHJcbiAgICAgICAgY29uc3QgdyA9IHRoaXMudztcclxuICAgICAgICBsZXQgbGVuZ3RoID0gTWF0aC5zcXJ0KHggKiB4ICsgeSAqIHkgKyB6ICogeiArIHcgKiB3KTtcclxuICAgICAgICBpZiAoIWxlbmd0aCkge1xyXG4gICAgICAgICAgICBkZXN0LnggPSAwO1xyXG4gICAgICAgICAgICBkZXN0LnkgPSAwO1xyXG4gICAgICAgICAgICBkZXN0LnogPSAwO1xyXG4gICAgICAgICAgICBkZXN0LncgPSAwO1xyXG4gICAgICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgbGVuZ3RoID0gMSAvIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnggPSB4ICogbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueSA9IHkgKiBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC56ID0geiAqIGxlbmd0aDtcclxuICAgICAgICBkZXN0LncgPSB3ICogbGVuZ3RoO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgYWRkKG90aGVyKSB7XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA0OyBpKyspIHtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaV0gKz0gb3RoZXIuYXQoaSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHkob3RoZXIpIHtcclxuICAgICAgICBjb25zdCBxMXggPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBxMXkgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBxMXogPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBxMXcgPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICBjb25zdCBxMnggPSBvdGhlci54O1xyXG4gICAgICAgIGNvbnN0IHEyeSA9IG90aGVyLnk7XHJcbiAgICAgICAgY29uc3QgcTJ6ID0gb3RoZXIuejtcclxuICAgICAgICBjb25zdCBxMncgPSBvdGhlci53O1xyXG4gICAgICAgIHRoaXMueCA9IHExeCAqIHEydyArIHExdyAqIHEyeCArIHExeSAqIHEyeiAtIHExeiAqIHEyeTtcclxuICAgICAgICB0aGlzLnkgPSBxMXkgKiBxMncgKyBxMXcgKiBxMnkgKyBxMXogKiBxMnggLSBxMXggKiBxMno7XHJcbiAgICAgICAgdGhpcy56ID0gcTF6ICogcTJ3ICsgcTF3ICogcTJ6ICsgcTF4ICogcTJ5IC0gcTF5ICogcTJ4O1xyXG4gICAgICAgIHRoaXMudyA9IHExdyAqIHEydyAtIHExeCAqIHEyeCAtIHExeSAqIHEyeSAtIHExeiAqIHEyejtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIG11bHRpcGx5VmVjMyh2ZWN0b3IsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3Rvci56O1xyXG4gICAgICAgIGNvbnN0IHF4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHF5ID0gdGhpcy55O1xyXG4gICAgICAgIGNvbnN0IHF6ID0gdGhpcy56O1xyXG4gICAgICAgIGNvbnN0IHF3ID0gdGhpcy53O1xyXG4gICAgICAgIGNvbnN0IGl4ID0gcXcgKiB4ICsgcXkgKiB6IC0gcXogKiB5O1xyXG4gICAgICAgIGNvbnN0IGl5ID0gcXcgKiB5ICsgcXogKiB4IC0gcXggKiB6O1xyXG4gICAgICAgIGNvbnN0IGl6ID0gcXcgKiB6ICsgcXggKiB5IC0gcXkgKiB4O1xyXG4gICAgICAgIGNvbnN0IGl3ID0gLXF4ICogeCAtIHF5ICogeSAtIHF6ICogejtcclxuICAgICAgICBkZXN0LnggPSBpeCAqIHF3ICsgaXcgKiAtcXggKyBpeSAqIC1xeiAtIGl6ICogLXF5O1xyXG4gICAgICAgIGRlc3QueSA9IGl5ICogcXcgKyBpdyAqIC1xeSArIGl6ICogLXF4IC0gaXggKiAtcXo7XHJcbiAgICAgICAgZGVzdC56ID0gaXogKiBxdyArIGl3ICogLXF6ICsgaXggKiAtcXkgLSBpeSAqIC1xeDtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHRvTWF0MyhkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgbWF0MygpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuejtcclxuICAgICAgICBjb25zdCB3ID0gdGhpcy53O1xyXG4gICAgICAgIGNvbnN0IHgyID0geCArIHg7XHJcbiAgICAgICAgY29uc3QgeTIgPSB5ICsgeTtcclxuICAgICAgICBjb25zdCB6MiA9IHogKyB6O1xyXG4gICAgICAgIGNvbnN0IHh4ID0geCAqIHgyO1xyXG4gICAgICAgIGNvbnN0IHh5ID0geCAqIHkyO1xyXG4gICAgICAgIGNvbnN0IHh6ID0geCAqIHoyO1xyXG4gICAgICAgIGNvbnN0IHl5ID0geSAqIHkyO1xyXG4gICAgICAgIGNvbnN0IHl6ID0geSAqIHoyO1xyXG4gICAgICAgIGNvbnN0IHp6ID0geiAqIHoyO1xyXG4gICAgICAgIGNvbnN0IHd4ID0gdyAqIHgyO1xyXG4gICAgICAgIGNvbnN0IHd5ID0gdyAqIHkyO1xyXG4gICAgICAgIGNvbnN0IHd6ID0gdyAqIHoyO1xyXG4gICAgICAgIGRlc3QuaW5pdChbXHJcbiAgICAgICAgICAgIDEgLSAoeXkgKyB6eiksXHJcbiAgICAgICAgICAgIHh5ICsgd3osXHJcbiAgICAgICAgICAgIHh6IC0gd3ksXHJcbiAgICAgICAgICAgIHh5IC0gd3osXHJcbiAgICAgICAgICAgIDEgLSAoeHggKyB6eiksXHJcbiAgICAgICAgICAgIHl6ICsgd3gsXHJcbiAgICAgICAgICAgIHh6ICsgd3ksXHJcbiAgICAgICAgICAgIHl6IC0gd3gsXHJcbiAgICAgICAgICAgIDEgLSAoeHggKyB5eSlcclxuICAgICAgICBdKTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHRvTWF0NChkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgbWF0NCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuejtcclxuICAgICAgICBjb25zdCB3ID0gdGhpcy53O1xyXG4gICAgICAgIGNvbnN0IHgyID0geCArIHg7XHJcbiAgICAgICAgY29uc3QgeTIgPSB5ICsgeTtcclxuICAgICAgICBjb25zdCB6MiA9IHogKyB6O1xyXG4gICAgICAgIGNvbnN0IHh4ID0geCAqIHgyO1xyXG4gICAgICAgIGNvbnN0IHh5ID0geCAqIHkyO1xyXG4gICAgICAgIGNvbnN0IHh6ID0geCAqIHoyO1xyXG4gICAgICAgIGNvbnN0IHl5ID0geSAqIHkyO1xyXG4gICAgICAgIGNvbnN0IHl6ID0geSAqIHoyO1xyXG4gICAgICAgIGNvbnN0IHp6ID0geiAqIHoyO1xyXG4gICAgICAgIGNvbnN0IHd4ID0gdyAqIHgyO1xyXG4gICAgICAgIGNvbnN0IHd5ID0gdyAqIHkyO1xyXG4gICAgICAgIGNvbnN0IHd6ID0gdyAqIHoyO1xyXG4gICAgICAgIGRlc3QuaW5pdChbXHJcbiAgICAgICAgICAgIDEgLSAoeXkgKyB6eiksXHJcbiAgICAgICAgICAgIHh5ICsgd3osXHJcbiAgICAgICAgICAgIHh6IC0gd3ksXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIHh5IC0gd3osXHJcbiAgICAgICAgICAgIDEgLSAoeHggKyB6eiksXHJcbiAgICAgICAgICAgIHl6ICsgd3gsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIHh6ICsgd3ksXHJcbiAgICAgICAgICAgIHl6IC0gd3gsXHJcbiAgICAgICAgICAgIDEgLSAoeHggKyB5eSksXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDFcclxuICAgICAgICBdKTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBkb3QocTEsIHEyKSB7XHJcbiAgICAgICAgcmV0dXJuIHExLnggKiBxMi54ICsgcTEueSAqIHEyLnkgKyBxMS56ICogcTIueiArIHExLncgKiBxMi53O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHN1bShxMSwgcTIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHExLnggKyBxMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHExLnkgKyBxMi55O1xyXG4gICAgICAgIGRlc3QueiA9IHExLnogKyBxMi56O1xyXG4gICAgICAgIGRlc3QudyA9IHExLncgKyBxMi53O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHByb2R1Y3QocTEsIHEyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgcXVhdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBxMXggPSBxMS54O1xyXG4gICAgICAgIGNvbnN0IHExeSA9IHExLnk7XHJcbiAgICAgICAgY29uc3QgcTF6ID0gcTEuejtcclxuICAgICAgICBjb25zdCBxMXcgPSBxMS53O1xyXG4gICAgICAgIGNvbnN0IHEyeCA9IHEyLng7XHJcbiAgICAgICAgY29uc3QgcTJ5ID0gcTIueTtcclxuICAgICAgICBjb25zdCBxMnogPSBxMi56O1xyXG4gICAgICAgIGNvbnN0IHEydyA9IHEyLnc7XHJcbiAgICAgICAgZGVzdC54ID0gcTF4ICogcTJ3ICsgcTF3ICogcTJ4ICsgcTF5ICogcTJ6IC0gcTF6ICogcTJ5O1xyXG4gICAgICAgIGRlc3QueSA9IHExeSAqIHEydyArIHExdyAqIHEyeSArIHExeiAqIHEyeCAtIHExeCAqIHEyejtcclxuICAgICAgICBkZXN0LnogPSBxMXogKiBxMncgKyBxMXcgKiBxMnogKyBxMXggKiBxMnkgLSBxMXkgKiBxMng7XHJcbiAgICAgICAgZGVzdC53ID0gcTF3ICogcTJ3IC0gcTF4ICogcTJ4IC0gcTF5ICogcTJ5IC0gcTF6ICogcTJ6O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGNyb3NzKHExLCBxMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHF1YXQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgcTF4ID0gcTEueDtcclxuICAgICAgICBjb25zdCBxMXkgPSBxMS55O1xyXG4gICAgICAgIGNvbnN0IHExeiA9IHExLno7XHJcbiAgICAgICAgY29uc3QgcTF3ID0gcTEudztcclxuICAgICAgICBjb25zdCBxMnggPSBxMi54O1xyXG4gICAgICAgIGNvbnN0IHEyeSA9IHEyLnk7XHJcbiAgICAgICAgY29uc3QgcTJ6ID0gcTIuejtcclxuICAgICAgICBjb25zdCBxMncgPSBxMi53O1xyXG4gICAgICAgIGRlc3QueCA9IHExdyAqIHEyeiArIHExeiAqIHEydyArIHExeCAqIHEyeSAtIHExeSAqIHEyeDtcclxuICAgICAgICBkZXN0LnkgPSBxMXcgKiBxMncgLSBxMXggKiBxMnggLSBxMXkgKiBxMnkgLSBxMXogKiBxMno7XHJcbiAgICAgICAgZGVzdC56ID0gcTF3ICogcTJ4ICsgcTF4ICogcTJ3ICsgcTF5ICogcTJ6IC0gcTF6ICogcTJ5O1xyXG4gICAgICAgIGRlc3QudyA9IHExdyAqIHEyeSArIHExeSAqIHEydyArIHExeiAqIHEyeCAtIHExeCAqIHEyejtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBzaG9ydE1peChxMSwgcTIsIHRpbWUsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICh0aW1lIDw9IDAuMCkge1xyXG4gICAgICAgICAgICBkZXN0Lnh5encgPSBxMS54eXp3O1xyXG4gICAgICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSBpZiAodGltZSA+PSAxLjApIHtcclxuICAgICAgICAgICAgZGVzdC54eXp3ID0gcTIueHl6dztcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBjb3MgPSBxdWF0LmRvdChxMSwgcTIpO1xyXG4gICAgICAgIGNvbnN0IHEyYSA9IHEyLmNvcHkoKTtcclxuICAgICAgICBpZiAoY29zIDwgMC4wKSB7XHJcbiAgICAgICAgICAgIHEyYS5pbnZlcnNlKCk7XHJcbiAgICAgICAgICAgIGNvcyA9IC1jb3M7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBrMDtcclxuICAgICAgICBsZXQgazE7XHJcbiAgICAgICAgaWYgKGNvcyA+IDAuOTk5OSkge1xyXG4gICAgICAgICAgICBrMCA9IDEgLSB0aW1lO1xyXG4gICAgICAgICAgICBrMSA9IDAgKyB0aW1lO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgY29uc3Qgc2luID0gTWF0aC5zcXJ0KDEgLSBjb3MgKiBjb3MpO1xyXG4gICAgICAgICAgICBjb25zdCBhbmdsZSA9IE1hdGguYXRhbjIoc2luLCBjb3MpO1xyXG4gICAgICAgICAgICBjb25zdCBvbmVPdmVyU2luID0gMSAvIHNpbjtcclxuICAgICAgICAgICAgazAgPSBNYXRoLnNpbigoMSAtIHRpbWUpICogYW5nbGUpICogb25lT3ZlclNpbjtcclxuICAgICAgICAgICAgazEgPSBNYXRoLnNpbigoMCArIHRpbWUpICogYW5nbGUpICogb25lT3ZlclNpbjtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gazAgKiBxMS54ICsgazEgKiBxMmEueDtcclxuICAgICAgICBkZXN0LnkgPSBrMCAqIHExLnkgKyBrMSAqIHEyYS55O1xyXG4gICAgICAgIGRlc3QueiA9IGswICogcTEueiArIGsxICogcTJhLno7XHJcbiAgICAgICAgZGVzdC53ID0gazAgKiBxMS53ICsgazEgKiBxMmEudztcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBtaXgocTEsIHEyLCB0aW1lLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgcXVhdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBjb3NIYWxmVGhldGEgPSBxMS54ICogcTIueCArIHExLnkgKiBxMi55ICsgcTEueiAqIHEyLnogKyBxMS53ICogcTIudztcclxuICAgICAgICBpZiAoTWF0aC5hYnMoY29zSGFsZlRoZXRhKSA+PSAxLjApIHtcclxuICAgICAgICAgICAgZGVzdC54eXp3ID0gcTEueHl6dztcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IGhhbGZUaGV0YSA9IE1hdGguYWNvcyhjb3NIYWxmVGhldGEpO1xyXG4gICAgICAgIGNvbnN0IHNpbkhhbGZUaGV0YSA9IE1hdGguc3FydCgxLjAgLSBjb3NIYWxmVGhldGEgKiBjb3NIYWxmVGhldGEpO1xyXG4gICAgICAgIGlmIChNYXRoLmFicyhzaW5IYWxmVGhldGEpIDwgMC4wMDEpIHtcclxuICAgICAgICAgICAgZGVzdC54ID0gcTEueCAqIDAuNSArIHEyLnggKiAwLjU7XHJcbiAgICAgICAgICAgIGRlc3QueSA9IHExLnkgKiAwLjUgKyBxMi55ICogMC41O1xyXG4gICAgICAgICAgICBkZXN0LnogPSBxMS56ICogMC41ICsgcTIueiAqIDAuNTtcclxuICAgICAgICAgICAgZGVzdC53ID0gcTEudyAqIDAuNSArIHEyLncgKiAwLjU7XHJcbiAgICAgICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCByYXRpb0EgPSBNYXRoLnNpbigoMSAtIHRpbWUpICogaGFsZlRoZXRhKSAvIHNpbkhhbGZUaGV0YTtcclxuICAgICAgICBjb25zdCByYXRpb0IgPSBNYXRoLnNpbih0aW1lICogaGFsZlRoZXRhKSAvIHNpbkhhbGZUaGV0YTtcclxuICAgICAgICBkZXN0LnggPSBxMS54ICogcmF0aW9BICsgcTIueCAqIHJhdGlvQjtcclxuICAgICAgICBkZXN0LnkgPSBxMS55ICogcmF0aW9BICsgcTIueSAqIHJhdGlvQjtcclxuICAgICAgICBkZXN0LnogPSBxMS56ICogcmF0aW9BICsgcTIueiAqIHJhdGlvQjtcclxuICAgICAgICBkZXN0LncgPSBxMS53ICogcmF0aW9BICsgcTIudyAqIHJhdGlvQjtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBmcm9tQXhpc0FuZ2xlKGF4aXMsIGFuZ2xlLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgcXVhdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBhbmdsZSAqPSAwLjU7XHJcbiAgICAgICAgY29uc3Qgc2luID0gTWF0aC5zaW4oYW5nbGUpO1xyXG4gICAgICAgIGRlc3QueCA9IGF4aXMueCAqIHNpbjtcclxuICAgICAgICBkZXN0LnkgPSBheGlzLnkgKiBzaW47XHJcbiAgICAgICAgZGVzdC56ID0gYXhpcy56ICogc2luO1xyXG4gICAgICAgIGRlc3QudyA9IE1hdGguY29zKGFuZ2xlKTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxufVxyXG5xdWF0LmlkZW50aXR5ID0gbmV3IHF1YXQoKS5zZXRJZGVudGl0eSgpO1xyXG4iLCJpbXBvcnQgcXVhdCBmcm9tICcuL3F1YXQnO1xyXG5pbXBvcnQgeyBlcHNpbG9uIH0gZnJvbSAnLi9jb25zdGFudHMnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyB2ZWMzIHtcclxuICAgIGNvbnN0cnVjdG9yKHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzID0gbmV3IEZsb2F0MzJBcnJheSgzKTtcclxuICAgICAgICBpZiAodmFsdWVzICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgdGhpcy54eXogPSB2YWx1ZXM7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgZ2V0IHgoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzBdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHkoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzFdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHooKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzJdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHh5KCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdXTtcclxuICAgIH1cclxuICAgIGdldCB4eXooKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV0sIHRoaXMudmFsdWVzWzJdXTtcclxuICAgIH1cclxuICAgIHNldCB4KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB5KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB6KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB4eSh2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIHNldCB4eXoodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZXNbMl07XHJcbiAgICB9XHJcbiAgICBhdChpbmRleCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1tpbmRleF07XHJcbiAgICB9XHJcbiAgICByZXNldCgpIHtcclxuICAgICAgICB0aGlzLnggPSAwO1xyXG4gICAgICAgIHRoaXMueSA9IDA7XHJcbiAgICAgICAgdGhpcy56ID0gMDtcclxuICAgIH1cclxuICAgIGNvcHkoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdGhpcy54O1xyXG4gICAgICAgIGRlc3QueSA9IHRoaXMueTtcclxuICAgICAgICBkZXN0LnogPSB0aGlzLno7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBuZWdhdGUoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gLXRoaXMueDtcclxuICAgICAgICBkZXN0LnkgPSAtdGhpcy55O1xyXG4gICAgICAgIGRlc3QueiA9IC10aGlzLno7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBlcXVhbHModmVjdG9yLCB0aHJlc2hvbGQgPSBlcHNpbG9uKSB7XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMueCAtIHZlY3Rvci54KSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnkgLSB2ZWN0b3IueSkgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoTWF0aC5hYnModGhpcy56IC0gdmVjdG9yLnopID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgICBsZW5ndGgoKSB7XHJcbiAgICAgICAgcmV0dXJuIE1hdGguc3FydCh0aGlzLnNxdWFyZWRMZW5ndGgoKSk7XHJcbiAgICB9XHJcbiAgICBzcXVhcmVkTGVuZ3RoKCkge1xyXG4gICAgICAgIGNvbnN0IHggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHRoaXMueTtcclxuICAgICAgICBjb25zdCB6ID0gdGhpcy56O1xyXG4gICAgICAgIHJldHVybiB4ICogeCArIHkgKiB5ICsgeiAqIHo7XHJcbiAgICB9XHJcbiAgICBhZGQodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54ICs9IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSArPSB2ZWN0b3IueTtcclxuICAgICAgICB0aGlzLnogKz0gdmVjdG9yLno7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBzdWJ0cmFjdCh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggLT0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55IC09IHZlY3Rvci55O1xyXG4gICAgICAgIHRoaXMueiAtPSB2ZWN0b3IuejtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIG11bHRpcGx5KHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCAqPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgKj0gdmVjdG9yLnk7XHJcbiAgICAgICAgdGhpcy56ICo9IHZlY3Rvci56O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgZGl2aWRlKHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCAvPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgLz0gdmVjdG9yLnk7XHJcbiAgICAgICAgdGhpcy56IC89IHZlY3Rvci56O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc2NhbGUodmFsdWUsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCAqPSB2YWx1ZTtcclxuICAgICAgICBkZXN0LnkgKj0gdmFsdWU7XHJcbiAgICAgICAgZGVzdC56ICo9IHZhbHVlO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgbm9ybWFsaXplKGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBsZW5ndGggPSB0aGlzLmxlbmd0aCgpO1xyXG4gICAgICAgIGlmIChsZW5ndGggPT09IDEpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChsZW5ndGggPT09IDApIHtcclxuICAgICAgICAgICAgZGVzdC54ID0gMDtcclxuICAgICAgICAgICAgZGVzdC55ID0gMDtcclxuICAgICAgICAgICAgZGVzdC56ID0gMDtcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxlbmd0aCA9IDEuMCAvIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnggKj0gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueSAqPSBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC56ICo9IGxlbmd0aDtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIG11bHRpcGx5QnlNYXQzKG1hdHJpeCwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIG1hdHJpeC5tdWx0aXBseVZlYzModGhpcywgZGVzdCk7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseUJ5UXVhdChxdWF0ZXJuaW9uLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gcXVhdGVybmlvbi5tdWx0aXBseVZlYzModGhpcywgZGVzdCk7XHJcbiAgICB9XHJcbiAgICB0b1F1YXQoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHF1YXQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgYyA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgY29uc3QgcyA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgYy54ID0gTWF0aC5jb3ModGhpcy54ICogMC41KTtcclxuICAgICAgICBzLnggPSBNYXRoLnNpbih0aGlzLnggKiAwLjUpO1xyXG4gICAgICAgIGMueSA9IE1hdGguY29zKHRoaXMueSAqIDAuNSk7XHJcbiAgICAgICAgcy55ID0gTWF0aC5zaW4odGhpcy55ICogMC41KTtcclxuICAgICAgICBjLnogPSBNYXRoLmNvcyh0aGlzLnogKiAwLjUpO1xyXG4gICAgICAgIHMueiA9IE1hdGguc2luKHRoaXMueiAqIDAuNSk7XHJcbiAgICAgICAgZGVzdC54ID0gcy54ICogYy55ICogYy56IC0gYy54ICogcy55ICogcy56O1xyXG4gICAgICAgIGRlc3QueSA9IGMueCAqIHMueSAqIGMueiArIHMueCAqIGMueSAqIHMuejtcclxuICAgICAgICBkZXN0LnogPSBjLnggKiBjLnkgKiBzLnogLSBzLnggKiBzLnkgKiBjLno7XHJcbiAgICAgICAgZGVzdC53ID0gYy54ICogYy55ICogYy56ICsgcy54ICogcy55ICogcy56O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGNyb3NzKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yLno7XHJcbiAgICAgICAgY29uc3QgeDIgPSB2ZWN0b3IyLng7XHJcbiAgICAgICAgY29uc3QgeTIgPSB2ZWN0b3IyLnk7XHJcbiAgICAgICAgY29uc3QgejIgPSB2ZWN0b3IyLno7XHJcbiAgICAgICAgZGVzdC54ID0geSAqIHoyIC0geiAqIHkyO1xyXG4gICAgICAgIGRlc3QueSA9IHogKiB4MiAtIHggKiB6MjtcclxuICAgICAgICBkZXN0LnogPSB4ICogeTIgLSB5ICogeDI7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZG90KHZlY3RvciwgdmVjdG9yMikge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3Rvci56O1xyXG4gICAgICAgIGNvbnN0IHgyID0gdmVjdG9yMi54O1xyXG4gICAgICAgIGNvbnN0IHkyID0gdmVjdG9yMi55O1xyXG4gICAgICAgIGNvbnN0IHoyID0gdmVjdG9yMi56O1xyXG4gICAgICAgIHJldHVybiB4ICogeDIgKyB5ICogeTIgKyB6ICogejI7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZGlzdGFuY2UodmVjdG9yLCB2ZWN0b3IyKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3RvcjIueCAtIHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IyLnkgLSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yMi56IC0gdmVjdG9yLno7XHJcbiAgICAgICAgcmV0dXJuIE1hdGguc3FydCh0aGlzLnNxdWFyZWREaXN0YW5jZSh2ZWN0b3IsIHZlY3RvcjIpKTtcclxuICAgIH1cclxuICAgIHN0YXRpYyBzcXVhcmVkRGlzdGFuY2UodmVjdG9yLCB2ZWN0b3IyKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3RvcjIueCAtIHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IyLnkgLSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yMi56IC0gdmVjdG9yLno7XHJcbiAgICAgICAgcmV0dXJuIHggKiB4ICsgeSAqIHkgKyB6ICogejtcclxuICAgIH1cclxuICAgIHN0YXRpYyBkaXJlY3Rpb24odmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLnggLSB2ZWN0b3IyLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55IC0gdmVjdG9yMi55O1xyXG4gICAgICAgIGNvbnN0IHogPSB2ZWN0b3IueiAtIHZlY3RvcjIuejtcclxuICAgICAgICBsZXQgbGVuZ3RoID0gTWF0aC5zcXJ0KHggKiB4ICsgeSAqIHkgKyB6ICogeik7XHJcbiAgICAgICAgaWYgKGxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICBkZXN0LnggPSAwO1xyXG4gICAgICAgICAgICBkZXN0LnkgPSAwO1xyXG4gICAgICAgICAgICBkZXN0LnogPSAwO1xyXG4gICAgICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgbGVuZ3RoID0gMSAvIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnggPSB4ICogbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueSA9IHkgKiBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC56ID0geiAqIGxlbmd0aDtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBtaXgodmVjdG9yLCB2ZWN0b3IyLCB0aW1lLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCArIHRpbWUgKiAodmVjdG9yMi54IC0gdmVjdG9yLngpO1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55ICsgdGltZSAqICh2ZWN0b3IyLnkgLSB2ZWN0b3IueSk7XHJcbiAgICAgICAgZGVzdC56ID0gdmVjdG9yLnogKyB0aW1lICogKHZlY3RvcjIueiAtIHZlY3Rvci56KTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBzdW0odmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCArIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSArIHZlY3RvcjIueTtcclxuICAgICAgICBkZXN0LnogPSB2ZWN0b3IueiArIHZlY3RvcjIuejtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBkaWZmZXJlbmNlKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggLSB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgLSB2ZWN0b3IyLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdmVjdG9yLnogLSB2ZWN0b3IyLno7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgcHJvZHVjdCh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54ICogdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55ICogdmVjdG9yMi55O1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56ICogdmVjdG9yMi56O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHF1b3RpZW50KHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggLyB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgLyB2ZWN0b3IyLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdmVjdG9yLnogLyB2ZWN0b3IyLno7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbn1cclxudmVjMy56ZXJvID0gbmV3IHZlYzMoWzAsIDAsIDBdKTtcclxudmVjMy5vbmUgPSBuZXcgdmVjMyhbMSwgMSwgMV0pO1xyXG52ZWMzLnVwID0gbmV3IHZlYzMoWzAsIDEsIDBdKTtcclxudmVjMy5yaWdodCA9IG5ldyB2ZWMzKFsxLCAwLCAwXSk7XHJcbnZlYzMuZm9yd2FyZCA9IG5ldyB2ZWMzKFswLCAwLCAxXSk7XHJcbiIsImV4cG9ydCBjbGFzcyBCYXNlT3V0cHV0IHtcclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBzdG9wKCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIHNldE9wdGlvbnMob3B0aW9ucykge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBCYXNlT3V0cHV0IH0gZnJvbSAnLi9iYXNlLW91dHB1dCc7XHJcbmV4cG9ydCBjbGFzcyBBcmlhT3V0cHV0IGV4dGVuZHMgQmFzZU91dHB1dCB7XHJcbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zID0ge30pIHtcclxuICAgICAgICBzdXBlcigpO1xyXG4gICAgICAgIHRoaXMudGltZW91dCA9IDEwMDtcclxuICAgICAgICB0aGlzLnRpbWVvdXQgPSBvcHRpb25zLnRpbWVvdXQgfHwgMTAwO1xyXG4gICAgICAgIHRoaXMuaW5pdCgpO1xyXG4gICAgfVxyXG4gICAgaW5pdCgpIHtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyLnNldEF0dHJpYnV0ZSgnYXJpYS1saXZlJywgJ3BvbGl0ZScpO1xyXG4gICAgICAgIHRoaXMuc3BlZWNoRGlzcGxheSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgICAgIHRoaXMuc3BlZWNoRGlzcGxheS5zZXRBdHRyaWJ1dGUoJ2FyaWEtbGl2ZScsICdwb2xpdGUnKTtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lci5hcHBlbmQodGhpcy5zcGVlY2hEaXNwbGF5KTtcclxuICAgICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHRoaXMuY29udGFpbmVyKTtcclxuICAgICAgICBkb2N1bWVudC5ib2R5Lmluc2VydEJlZm9yZSh0aGlzLmNvbnRhaW5lciwgZG9jdW1lbnQuYm9keS5maXJzdENoaWxkKTtcclxuICAgIH1cclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICB0aGlzLmNsZWFyRGlzcGxheSgpO1xyXG4gICAgICAgIGNvbnN0IG5vZGUgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSh0ZXh0KTtcclxuICAgICAgICBjb25zdCBwYXJhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgncCcpO1xyXG4gICAgICAgIHBhcmEuYXBwZW5kQ2hpbGQobm9kZSk7XHJcbiAgICAgICAgdGhpcy5zcGVlY2hEaXNwbGF5LmFwcGVuZENoaWxkKHBhcmEpO1xyXG4gICAgICAgIHNldFRpbWVvdXQodGhpcy5jbGVhckRpc3BsYXkuYmluZCh0aGlzKSwgdGhpcy50aW1lb3V0KTtcclxuICAgIH1cclxuICAgIHN0b3AoKSB7XHJcbiAgICAgICAgdGhpcy5jbGVhckRpc3BsYXkoKTtcclxuICAgIH1cclxuICAgIGNsZWFyRGlzcGxheSgpIHtcclxuICAgICAgICB0aGlzLnNwZWVjaERpc3BsYXkuaW5uZXJIVE1MID0gJyc7XHJcbiAgICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgQmFzZU91dHB1dCB9IGZyb20gJy4vYmFzZS1vdXRwdXQnO1xyXG5leHBvcnQgY2xhc3MgV2ViVFRTT3V0cHV0IGV4dGVuZHMgQmFzZU91dHB1dCB7XHJcbn1cclxuIiwiaW1wb3J0IHsgY3JlYXRlT3V0cHV0IH0gZnJvbSAnLi9vdXRwdXQtZmFjdG9yeSc7XHJcbmV4cG9ydCBjbGFzcyBUVFMge1xyXG4gICAgY29uc3RydWN0b3Iob3V0cHV0ID0gY3JlYXRlT3V0cHV0KCkpIHtcclxuICAgICAgICB0aGlzLm91dHB1dCA9IG91dHB1dDtcclxuICAgIH1cclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICB0aGlzLm91dHB1dC5zcGVhayh0ZXh0KTtcclxuICAgIH1cclxuICAgIHN0b3AoKSB7XHJcbiAgICAgICAgdGhpcy5vdXRwdXQuc3RvcCgpO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCB7IEJhc2VPdXRwdXQgfSBmcm9tICcuL291dHB1dHMvYmFzZS1vdXRwdXQnO1xyXG5pbXBvcnQgeyBBcmlhT3V0cHV0IH0gZnJvbSAnLi9vdXRwdXRzL2FyaWEnO1xyXG5pbXBvcnQgeyBXZWJUVFNPdXRwdXQgfSBmcm9tICcuL291dHB1dHMvd2VidHRzJztcclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU91dHB1dChrZXkgPSAnYXJpYScpIHtcclxuICAgIHN3aXRjaCAoa2V5KSB7XHJcbiAgICAgICAgY2FzZSAnYXJpYSc6XHJcbiAgICAgICAgICAgIHJldHVybiBBcmlhT3V0cHV0O1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICBjYXNlICd3ZWJ0dHMnOlxyXG4gICAgICAgICAgICByZXR1cm4gV2ViVFRTT3V0cHV0O1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICByZXR1cm4gQXJpYU91dHB1dDtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICB9XHJcbn1cclxuZXhwb3J0IHsgV2ViVFRTT3V0cHV0LCBBcmlhT3V0cHV0LCBCYXNlT3V0cHV0IH07XHJcbiIsImV4cG9ydCBjbGFzcyBTb3VuZE1hbmFnZXIge1xyXG4gICAgY29uc3RydWN0b3Ioc291bmRTZXQgPSBudWxsKSB7XHJcbiAgICAgICAgdGhpcy5zb3VuZFNldCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5kYXRhID0gbmV3IE1hcCgpO1xyXG4gICAgICAgIHRoaXMuc291bmRTZXQgPSBzb3VuZFNldDtcclxuICAgIH1cclxuICAgIHNldFNvdW5kU2V0KHNvdW5kU2V0KSB7XHJcbiAgICAgICAgdGhpcy5zb3VuZFNldCA9IHNvdW5kU2V0O1xyXG4gICAgfVxyXG4gICAgaGFuZGxlU291bmQodHlwZSwgZGF0YSA9IG51bGwpIHtcclxuICAgICAgICBzd2l0Y2ggKHR5cGUpIHtcclxuICAgICAgICAgICAgY2FzZSAnZWRpdCc6XHJcbiAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZUVkaXRTb3VuZChkYXRhKTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICBjYXNlICdzbGlkZXInOlxyXG4gICAgICAgICAgICAgICAgdGhpcy5oYW5kbGVTbGlkZXJTb3VuZChkYXRhKTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICBjYXNlICdzZWxlY3Rvcic6XHJcbiAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZVNlbGVjdG9yU291bmQoZGF0YSk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgY2FzZSAnY2hlY2tib3gnOlxyXG4gICAgICAgICAgICAgICAgdGhpcy5oYW5kbGVDaGVja2JveFNvdW5kKGRhdGEpO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGNhc2UgJ2ZvY3VzJzpcclxuICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlRm9jdXNTb3VuZCgpO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGNhc2UgJ2Nob29zZSc6XHJcbiAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZUNob29zZVNvdW5kKCk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgY2FzZSAnb3Blbic6XHJcbiAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZU9wZW5Tb3VuZCgpO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGNhc2UgJ2Nsb3NlJzpcclxuICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlQ2xvc2VTb3VuZCgpO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBoYW5kbGVFZGl0U291bmQoZGF0YSkge1xyXG4gICAgICAgIGNvbnN0IHByZXZEYXRhID0gdGhpcy5kYXRhLmdldCgnZWRpdCcpIHx8ICcnO1xyXG4gICAgICAgIGlmIChkYXRhLmxlbmd0aCA8PSBwcmV2RGF0YS5sZW5ndGgpIHtcclxuICAgICAgICAgICAgdGhpcy5zb3VuZFNldC5kZWxldGUgJiYgdGhpcy5zb3VuZFNldC5kZWxldGUucGxheSgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5zb3VuZFNldC5jaGFyICYmIHRoaXMuc291bmRTZXQuY2hhci5wbGF5KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuZGF0YS5zZXQoJ2VkaXQnLCBkYXRhKTtcclxuICAgIH1cclxuICAgIGhhbmRsZVNlbGVjdG9yU291bmQoZGF0YSkge1xyXG4gICAgICAgIHRoaXMuc291bmRTZXQuc2Nyb2xsZXIgJiYgdGhpcy5zb3VuZFNldC5zY3JvbGxlci5wbGF5KCk7XHJcbiAgICB9XHJcbiAgICBoYW5kbGVTbGlkZXJTb3VuZChkYXRhKSB7XHJcbiAgICAgICAgY29uc3QgcHJldkRhdGEgPSB0aGlzLmRhdGEuZ2V0KCdzbGlkZXInKTtcclxuICAgICAgICBpZiAoZGF0YSA8IHByZXZEYXRhKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc291bmRTZXQuc2xpZGVyTGVmdCAmJiB0aGlzLnNvdW5kU2V0LnNsaWRlckxlZnQucGxheSgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5zb3VuZFNldC5zbGlkZXJSaWdodCAmJiB0aGlzLnNvdW5kU2V0LnNsaWRlclJpZ2h0LnBsYXkoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5kYXRhLnNldCgnc2xpZGVyJywgZGF0YSk7XHJcbiAgICB9XHJcbiAgICBoYW5kbGVGb2N1c1NvdW5kKCkge1xyXG4gICAgICAgIHRoaXMuc291bmRTZXQubW92ZSAmJiB0aGlzLnNvdW5kU2V0Lm1vdmUucGxheSgpO1xyXG4gICAgfVxyXG4gICAgaGFuZGxlT3BlblNvdW5kKCkge1xyXG4gICAgICAgIHRoaXMuc291bmRTZXQub3BlbiAmJiB0aGlzLnNvdW5kU2V0Lm9wZW4ucGxheSgpO1xyXG4gICAgfVxyXG4gICAgaGFuZGxlQ2xvc2VTb3VuZCgpIHtcclxuICAgICAgICB0aGlzLnNvdW5kU2V0LmNsb3NlICYmIHRoaXMuc291bmRTZXQuY2xvc2UucGxheSgpO1xyXG4gICAgfVxyXG4gICAgaGFuZGxlQ2hvb3NlU291bmQoKSB7XHJcbiAgICAgICAgdGhpcy5zb3VuZFNldC5jaG9vc2UgJiYgdGhpcy5zb3VuZFNldC5jaG9vc2UucGxheSgpO1xyXG4gICAgfVxyXG4gICAgaGFuZGxlQ2hlY2tib3hTb3VuZChkYXRhKSB7XHJcbiAgICAgICAgaWYgKGRhdGEgPT09IHRydWUpIHtcclxuICAgICAgICAgICAgdGhpcy5zb3VuZFNldC5jaGVja2VkICYmIHRoaXMuc291bmRTZXQuY2hlY2tlZC5wbGF5KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICB0aGlzLnNvdW5kU2V0LnVuY2hlY2tlZCAmJiB0aGlzLnNvdW5kU2V0LnVuY2hlY2tlZC5wbGF5KCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbiIsImV4cG9ydCBjbGFzcyBLZXlib2FyZE1hbmFnZXIge1xyXG4gICAgY29uc3RydWN0b3IobWVudSkge1xyXG4gICAgICAgIHRoaXMubWVudSA9IG1lbnU7XHJcbiAgICB9XHJcbiAgICBpbml0KCkge1xyXG4gICAgICAgIHRoaXMubWVudVxyXG4gICAgICAgICAgICAuZ2V0Q29udGFpbmVyKClcclxuICAgICAgICAgICAgLmFkZEV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCB0aGlzLmhhbmRsZXIuYmluZCh0aGlzKSk7XHJcbiAgICAgICAgLy8gVGhpcyB0cmljayBsZXQncyB1cyBkZXRlY3QgdGhlIHByZXNzIG9mIHRoZSBiYWNrIG9yIGZvcndhcmQgYnV0dG9ucyB0byBleGl0IG91dCBvZiB0aGUgbWVudS5cclxuICAgICAgICB3aW5kb3cub25wb3BzdGF0ZSA9ICgpID0+IHRoaXMubWVudS5jbGlja0NhbmNlbEFjdGlvbigpO1xyXG4gICAgfVxyXG4gICAgaGFuZGxlcihldmVudCkge1xyXG4gICAgICAgIHN3aXRjaCAoZXZlbnQua2V5KSB7XHJcbiAgICAgICAgICAgIGNhc2UgJ0Fycm93RG93bic6XHJcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5tZW51LmZvY3VzTmV4dCgpO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGNhc2UgJ0Fycm93VXAnOlxyXG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICAgICAgICAgIHRoaXMubWVudS5mb2N1c1ByZXZpb3VzKCk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgY2FzZSAnRW50ZXInOlxyXG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICAgICAgICAgIHRoaXMubWVudS5jbGlja0RlZmF1bHRBY3Rpb24oKTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICBjYXNlICdFc2NhcGUnOlxyXG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICAgICAgICAgIHRoaXMubWVudS5jbGlja0NhbmNlbEFjdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICByZWxlYXNlKCkge1xyXG4gICAgICAgIHRoaXMubWVudVxyXG4gICAgICAgICAgICAuZ2V0Q29udGFpbmVyKClcclxuICAgICAgICAgICAgLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCB0aGlzLmhhbmRsZXIuYmluZCh0aGlzKSk7XHJcbiAgICAgICAgd2luZG93Lm9ucG9wc3RhdGUgPSBudWxsO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCAqIGFzIEV2ZW50RW1pdHRlciBmcm9tICdldmVudGVtaXR0ZXIzJztcclxuZXhwb3J0IGNsYXNzIEJhc2VJdGVtIGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcclxuICAgIGNvbnN0cnVjdG9yKGlkLCB0aXRsZSkge1xyXG4gICAgICAgIHN1cGVyKCk7XHJcbiAgICAgICAgdGhpcy5pZCA9IGlkO1xyXG4gICAgICAgIHRoaXMudGl0bGUgPSB0aXRsZTtcclxuICAgIH1cclxuICAgIGdldERPTU5vZGUoKSB7XHJcbiAgICAgICAgbGV0IG5vZGUgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSh0aGlzLnRpdGxlKTtcclxuICAgICAgICBsZXQgZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgICAgIGVsZW1lbnQuYXBwZW5kQ2hpbGQobm9kZSk7XHJcbiAgICAgICAgcmV0dXJuIGVsZW1lbnQ7XHJcbiAgICB9XHJcbiAgICBnZXRDb250ZW50cygpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBvbkZvY3VzKGV2ZW50KSB7XHJcbiAgICAgICAgdGhpcy5lbWl0KCdmb2N1cycsIHRoaXMuaWQpO1xyXG4gICAgfVxyXG4gICAgZm9jdXMoKSB7XHJcbiAgICAgICAgdGhpcy5jb250YWluZXIgJiYgdGhpcy5jb250YWluZXIuZm9jdXMoKTtcclxuICAgIH1cclxuICAgIGNsaWNrKCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIGdldElEKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmlkO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCB7IEJhc2VJdGVtIH0gZnJvbSAnLi9iYXNlLWl0ZW0nO1xyXG5leHBvcnQgY2xhc3MgRWRpdEl0ZW0gZXh0ZW5kcyBCYXNlSXRlbSB7XHJcbiAgICBjb25zdHJ1Y3RvcihpZCwgdGl0bGUsIGluaXRpYWxUZXh0LCBpc1Bhc3N3b3JkID0gZmFsc2UpIHtcclxuICAgICAgICBzdXBlcihpZCwgdGl0bGUpO1xyXG4gICAgICAgIHRoaXMuaW5pdGlhbFRleHQgPSBpbml0aWFsVGV4dDtcclxuICAgICAgICB0aGlzLmlzUGFzc3dvcmQgPSBpc1Bhc3N3b3JkO1xyXG4gICAgICAgIHRoaXMuY29udGVudHMgPSBpbml0aWFsVGV4dDtcclxuICAgIH1cclxuICAgIGdldERPTU5vZGUoKSB7XHJcbiAgICAgICAgY29uc3Qgbm9kZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgICAgIGNvbnN0IGxhYmVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnbGFiZWwnKTtcclxuICAgICAgICBsYWJlbC5zZXRBdHRyaWJ1dGUoJ2ZvcicsIGBlZGl0XyR7dGhpcy5pZH1gKTtcclxuICAgICAgICBsYWJlbC50ZXh0Q29udGVudCA9IHRoaXMudGl0bGU7XHJcbiAgICAgICAgY29uc3QgZWRpdEZpZWxkID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW5wdXQnKTtcclxuICAgICAgICBlZGl0RmllbGQuaWQgPSBgZWRpdF8ke3RoaXMuaWR9YDtcclxuICAgICAgICBlZGl0RmllbGQudmFsdWUgPSB0aGlzLmNvbnRlbnRzO1xyXG4gICAgICAgIGVkaXRGaWVsZC5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgdGhpcy5vbkNoYW5nZS5iaW5kKHRoaXMpKTtcclxuICAgICAgICBlZGl0RmllbGQuYWRkRXZlbnRMaXN0ZW5lcignZm9jdXMnLCB0aGlzLm9uRm9jdXMuYmluZCh0aGlzKSk7XHJcbiAgICAgICAgaWYgKHRoaXMuaXNQYXNzd29yZCkge1xyXG4gICAgICAgICAgICBlZGl0RmllbGQudHlwZSA9ICdwYXNzd29yZCc7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIG5vZGUuYXBwZW5kQ2hpbGQobGFiZWwpO1xyXG4gICAgICAgIG5vZGUuYXBwZW5kQ2hpbGQoZWRpdEZpZWxkKTtcclxuICAgICAgICBub2RlLmFkZEV2ZW50TGlzdGVuZXIoJ2ZvY3VzJywgdGhpcy5vbkZvY3VzLmJpbmQodGhpcykpO1xyXG4gICAgICAgIHRoaXMuZWRpdEZpZWxkID0gZWRpdEZpZWxkO1xyXG4gICAgICAgIHRoaXMubGFiZWwgPSBsYWJlbDtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lciA9IG5vZGU7XHJcbiAgICAgICAgcmV0dXJuIG5vZGU7XHJcbiAgICB9XHJcbiAgICBnZXRDb250ZW50cygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5lZGl0RmllbGQudmFsdWU7XHJcbiAgICB9XHJcbiAgICBvbkNoYW5nZShldmVudCkge1xyXG4gICAgICAgIHRoaXMuZW1pdCgndXBkYXRlJywge1xyXG4gICAgICAgICAgICB0eXBlOiAnZWRpdCcsXHJcbiAgICAgICAgICAgIHZhbHVlOiB0aGlzLmVkaXRGaWVsZC52YWx1ZVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgZm9jdXMoKSB7XHJcbiAgICAgICAgdGhpcy5lZGl0RmllbGQgJiYgdGhpcy5lZGl0RmllbGQuZm9jdXMoKTtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBCYXNlSXRlbSB9IGZyb20gJy4vYmFzZS1pdGVtJztcclxuZXhwb3J0IGNsYXNzIE1lbnVJdGVtIGV4dGVuZHMgQmFzZUl0ZW0ge1xyXG4gICAgY29uc3RydWN0b3IoaWQsIHRpdGxlKSB7XHJcbiAgICAgICAgc3VwZXIoaWQsIHRpdGxlKTtcclxuICAgIH1cclxuICAgIGdldERPTU5vZGUoKSB7XHJcbiAgICAgICAgY29uc3QgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XHJcbiAgICAgICAgY29uc3QgYnV0dG9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYnV0dG9uJyk7XHJcbiAgICAgICAgYnV0dG9uLnRleHRDb250ZW50ID0gdGhpcy50aXRsZTtcclxuICAgICAgICBidXR0b24uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCB0aGlzLmhhbmRsZUNsaWNrLmJpbmQodGhpcykpO1xyXG4gICAgICAgIGJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCdmb2N1cycsIHRoaXMub25Gb2N1cy5iaW5kKHRoaXMpKTtcclxuICAgICAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQoYnV0dG9uKTtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lciA9IGNvbnRhaW5lcjtcclxuICAgICAgICB0aGlzLmJ1dHRvbiA9IGJ1dHRvbjtcclxuICAgICAgICByZXR1cm4gY29udGFpbmVyO1xyXG4gICAgfVxyXG4gICAgZ2V0Q29udGVudHMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuaWQ7XHJcbiAgICB9XHJcbiAgICBoYW5kbGVDbGljayhldmVudCkge1xyXG4gICAgICAgIHRoaXMuZW1pdCgnY2hvb3NlJywgdGhpcy5pZCk7XHJcbiAgICB9XHJcbiAgICBmb2N1cygpIHtcclxuICAgICAgICB0aGlzLmJ1dHRvbiAmJiB0aGlzLmJ1dHRvbi5mb2N1cygpO1xyXG4gICAgfVxyXG4gICAgY2xpY2soKSB7XHJcbiAgICAgICAgdGhpcy5idXR0b24uY2xpY2soKTtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBCYXNlSXRlbSB9IGZyb20gJy4vYmFzZS1pdGVtJztcclxuZXhwb3J0IGNsYXNzIFNlbGVjdG9ySXRlbSBleHRlbmRzIEJhc2VJdGVtIHtcclxuICAgIGNvbnN0cnVjdG9yKGlkLCB0aXRsZSwgaXRlbXMpIHtcclxuICAgICAgICBzdXBlcihpZCwgdGl0bGUpO1xyXG4gICAgICAgIHRoaXMuaXRlbXMgPSBpdGVtcztcclxuICAgICAgICB0aGlzLmVudHJpZXMgPSBbXTtcclxuICAgIH1cclxuICAgIGdldERPTU5vZGUoKSB7XHJcbiAgICAgICAgdGhpcy5jb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuICAgICAgICB0aGlzLmxpc3RDb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd1bCcpO1xyXG4gICAgICAgIHRoaXMubGFiZWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsZWdlbmQnKTtcclxuICAgICAgICB0aGlzLmZpZWxkU2V0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZmllbGRzZXQnKTtcclxuICAgICAgICB0aGlzLmZpZWxkU2V0LnNldEF0dHJpYnV0ZSgnY2xhc3MnLCAncmFkaW9ncm91cCcpO1xyXG4gICAgICAgIHRoaXMuZmllbGRTZXQuaWQgPSBgZnNfc2VsZWN0b3JfJHt0aGlzLmlkfWA7XHJcbiAgICAgICAgY29uc3QgbmFtZSA9IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHRoaXMudGl0bGUpO1xyXG4gICAgICAgIHRoaXMubGFiZWwuYXBwZW5kQ2hpbGQobmFtZSk7XHJcbiAgICAgICAgdGhpcy5maWVsZFNldC5hcHBlbmRDaGlsZCh0aGlzLmxhYmVsKTtcclxuICAgICAgICB0aGlzLmJ1aWxkRW50cmllcygpO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMuZmllbGRTZXQpO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoJ2ZvY3VzJywgdGhpcy5vbkZvY3VzLmJpbmQodGhpcykpO1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbnRhaW5lcjtcclxuICAgIH1cclxuICAgIGJ1aWxkRW50cmllcygpIHtcclxuICAgICAgICB0aGlzLml0ZW1zLmZvckVhY2goKGl0ZW0sIGluZGV4KSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IG5vZGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbnB1dCcpO1xyXG4gICAgICAgICAgICBub2RlLnR5cGUgPSAncmFkaW8nO1xyXG4gICAgICAgICAgICBub2RlLmlkID0gYCR7dGhpcy5pZH1fJHtpdGVtLmlkfWA7XHJcbiAgICAgICAgICAgIG5vZGUubmFtZSA9IHRoaXMuaWQ7XHJcbiAgICAgICAgICAgIG5vZGUudmFsdWUgPSBpdGVtLmlkIHx8IGAke2luZGV4fWA7XHJcbiAgICAgICAgICAgIG5vZGUuYWRkRXZlbnRMaXN0ZW5lcignZm9jdXMnLCB0aGlzLm9uSXRlbUZvY3VzLmJpbmQodGhpcykpO1xyXG4gICAgICAgICAgICBub2RlLmFkZEV2ZW50TGlzdGVuZXIoJ3NlbGVjdCcsIHRoaXMub25TZWxlY3RJdGVtLmJpbmQodGhpcykpO1xyXG4gICAgICAgICAgICBub2RlLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIHRoaXMub25DaGFuZ2VJdGVtLmJpbmQodGhpcykpO1xyXG4gICAgICAgICAgICB0aGlzLmVudHJpZXMucHVzaChub2RlKTtcclxuICAgICAgICAgICAgY29uc3QgbGFiZWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsYWJlbCcpO1xyXG4gICAgICAgICAgICBsYWJlbC5zZXRBdHRyaWJ1dGUoJ2ZvcicsIGAke3RoaXMuaWR9XyR7aXRlbS5pZH1gKTtcclxuICAgICAgICAgICAgbGFiZWwudGV4dENvbnRlbnQgPSBpdGVtLnRpdGxlO1xyXG4gICAgICAgICAgICB0aGlzLmZpZWxkU2V0LmFwcGVuZChub2RlKTtcclxuICAgICAgICAgICAgdGhpcy5maWVsZFNldC5hcHBlbmQobGFiZWwpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgb25JdGVtRm9jdXMoZXZlbnQpIHtcclxuICAgICAgICBjb25zb2xlLmxvZyhgSXRlbSBmb2N1c2VkOiBgLCBldmVudCk7XHJcbiAgICAgICAgdGhpcy5lbWl0KCdmb2N1cycsIHRoaXMuaWQpO1xyXG4gICAgfVxyXG4gICAgZ2V0Q29udGVudHMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY3VycmVudFZhbHVlO1xyXG4gICAgfVxyXG4gICAgb25TZWxlY3RJdGVtKGV2ZW50KSB7IH1cclxuICAgIG9uQ2hhbmdlSXRlbShldmVudCkge1xyXG4gICAgICAgIGNvbnN0IG5vZGUgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGBpbnB1dFtuYW1lID0gXCIke3RoaXMuaWR9XCJdOmNoZWNrZWRgKTtcclxuICAgICAgICB0aGlzLmN1cnJlbnRWYWx1ZSA9IHRoaXMuaXRlbXMuZmluZCgoaXRlbSkgPT4gYCR7dGhpcy5pZH1fJHtpdGVtLmlkfWAgPT09IG5vZGUuaWQpO1xyXG4gICAgICAgIHRoaXMuZW1pdCgndXBkYXRlJywge1xyXG4gICAgICAgICAgICB0eXBlOiAnc2VsZWN0b3InLFxyXG4gICAgICAgICAgICB2YWx1ZTogdGhpcy5jdXJyZW50VmFsdWVcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuICAgIGZvY3VzKCkge1xyXG4gICAgICAgIGNvbnN0IG5vZGUgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGBpbnB1dFtuYW1lID0gXCIke3RoaXMuaWR9XCJdOmNoZWNrZWRgKSB8fFxyXG4gICAgICAgICAgICB0aGlzLmVudHJpZXNbMF07XHJcbiAgICAgICAgbm9kZS5mb2N1cygpO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCB7IEJhc2VJdGVtIH0gZnJvbSAnLi9iYXNlLWl0ZW0nO1xyXG5leHBvcnQgY2xhc3MgU2xpZGVySXRlbSBleHRlbmRzIEJhc2VJdGVtIHtcclxuICAgIGNvbnN0cnVjdG9yKGlkLCB0aXRsZSwgbWluLCBtYXgsIHN0ZXAsIGRlZmF1bHRWYWx1ZSA9IG51bGwpIHtcclxuICAgICAgICBzdXBlcihpZCwgdGl0bGUpO1xyXG4gICAgICAgIHRoaXMubWluID0gbWluO1xyXG4gICAgICAgIHRoaXMubWF4ID0gbWF4O1xyXG4gICAgICAgIHRoaXMuc3RlcCA9IHN0ZXA7XHJcbiAgICAgICAgdGhpcy5kZWZhdWx0VmFsdWUgPSBkZWZhdWx0VmFsdWU7XHJcbiAgICB9XHJcbiAgICBnZXRET01Ob2RlKCkge1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XHJcbiAgICAgICAgdGhpcy5sYWJlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xhYmVsJyk7XHJcbiAgICAgICAgdGhpcy5sYWJlbC50ZXh0Q29udGVudCA9IHRoaXMudGl0bGU7XHJcbiAgICAgICAgdGhpcy5sYWJlbC5zZXRBdHRyaWJ1dGUoJ2ZvcicsIGBzbGlkZXJfJHt0aGlzLmlkfWApO1xyXG4gICAgICAgIHRoaXMuc2xpZGVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW5wdXQnKTtcclxuICAgICAgICB0aGlzLnNsaWRlci5pZCA9IGBzbGlkZXJfJHt0aGlzLmlkfWA7XHJcbiAgICAgICAgdGhpcy5zbGlkZXIudHlwZSA9ICdyYW5nZSc7XHJcbiAgICAgICAgdGhpcy5zbGlkZXIuc2V0QXR0cmlidXRlKCdtaW4nLCB0aGlzLm1pbi50b1N0cmluZygpKTtcclxuICAgICAgICB0aGlzLnNsaWRlci5zZXRBdHRyaWJ1dGUoJ21heCcsIHRoaXMubWF4LnRvU3RyaW5nKCkpO1xyXG4gICAgICAgIHRoaXMuc2xpZGVyLnNldEF0dHJpYnV0ZSgnc3RlcCcsIHRoaXMuc3RlcC50b1N0cmluZygpKTtcclxuICAgICAgICBpZiAodGhpcy5kZWZhdWx0VmFsdWUpXHJcbiAgICAgICAgICAgIHRoaXMuc2xpZGVyLnZhbHVlID0gdGhpcy5kZWZhdWx0VmFsdWUudG9TdHJpbmcoKTtcclxuICAgICAgICB0aGlzLnNsaWRlci5hZGRFdmVudExpc3RlbmVyKCdjaGFuZ2UnLCB0aGlzLm9uQ2hhbmdlLmJpbmQodGhpcykpO1xyXG4gICAgICAgIHRoaXMuc2xpZGVyLmFkZEV2ZW50TGlzdGVuZXIoJ2ZvY3VzJywgdGhpcy5vbkZvY3VzLmJpbmQodGhpcykpO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMubGFiZWwpO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMuc2xpZGVyKTtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lci5hZGRFdmVudExpc3RlbmVyKCdmb2N1cycsIHRoaXMub25Gb2N1cy5iaW5kKHRoaXMpKTtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb250YWluZXI7XHJcbiAgICB9XHJcbiAgICBnZXRDb250ZW50cygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5zbGlkZXIudmFsdWU7XHJcbiAgICB9XHJcbiAgICBvbkNoYW5nZShldmVudCkge1xyXG4gICAgICAgIHRoaXMuZW1pdCgndXBkYXRlJywge1xyXG4gICAgICAgICAgICB0eXBlOiAnc2xpZGVyJyxcclxuICAgICAgICAgICAgdmFsdWU6IHRoaXMuc2xpZGVyLnZhbHVlXHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBmb2N1cygpIHtcclxuICAgICAgICB0aGlzLnNsaWRlciAmJiB0aGlzLnNsaWRlci5mb2N1cygpO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCB7IEJhc2VJdGVtIH0gZnJvbSAnLi9iYXNlLWl0ZW0nO1xyXG5leHBvcnQgY2xhc3MgQ2hlY2tib3hJdGVtIGV4dGVuZHMgQmFzZUl0ZW0ge1xyXG4gICAgY29uc3RydWN0b3IoaWQsIHRpdGxlKSB7XHJcbiAgICAgICAgc3VwZXIoaWQsIHRpdGxlKTtcclxuICAgIH1cclxuICAgIGdldERPTU5vZGUoKSB7XHJcbiAgICAgICAgdGhpcy5jb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuICAgICAgICB0aGlzLmxhYmVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnbGFiZWwnKTtcclxuICAgICAgICB0aGlzLmxhYmVsLnNldEF0dHJpYnV0ZSgnZm9yJywgYGNoa2J4XyR7dGhpcy5pZH1gKTtcclxuICAgICAgICB0aGlzLmxhYmVsLnRleHRDb250ZW50ID0gdGhpcy50aXRsZTtcclxuICAgICAgICB0aGlzLmNoZWNrYm94RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lucHV0Jyk7XHJcbiAgICAgICAgdGhpcy5jaGVja2JveEVsZW1lbnQuc2V0QXR0cmlidXRlKCd0eXBlJywgJ2NoZWNrYm94Jyk7XHJcbiAgICAgICAgdGhpcy5jaGVja2JveEVsZW1lbnQuc2V0QXR0cmlidXRlKCdpZCcsIGBjaGtieF8ke3RoaXMuaWR9YCk7XHJcbiAgICAgICAgdGhpcy5jaGVja2JveEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignZm9jdXMnLCB0aGlzLm9uRm9jdXMuYmluZCh0aGlzKSk7XHJcbiAgICAgICAgdGhpcy5jaGVja2JveEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgdGhpcy5vbkNoYW5nZS5iaW5kKHRoaXMpKTtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLmxhYmVsKTtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLmNoZWNrYm94RWxlbWVudCk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGFpbmVyO1xyXG4gICAgfVxyXG4gICAgZ2V0Q29udGVudHMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY2hlY2tib3hFbGVtZW50LmNoZWNrZWQ7XHJcbiAgICB9XHJcbiAgICBvbkNoYW5nZShldmVudCkge1xyXG4gICAgICAgIHRoaXMuZW1pdCgndXBkYXRlJywge1xyXG4gICAgICAgICAgICB0eXBlOiAnY2hlY2tib3gnLFxyXG4gICAgICAgICAgICB2YWx1ZTogdGhpcy5jaGVja2JveEVsZW1lbnQuY2hlY2tlZFxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgZm9jdXMoKSB7XHJcbiAgICAgICAgdGhpcy5jaGVja2JveEVsZW1lbnQuZm9jdXMoKTtcclxuICAgIH1cclxufVxyXG4iLCJ2YXIgX19hd2FpdGVyID0gKHRoaXMgJiYgdGhpcy5fX2F3YWl0ZXIpIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcclxuICAgIGZ1bmN0aW9uIGFkb3B0KHZhbHVlKSB7IHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFAgPyB2YWx1ZSA6IG5ldyBQKGZ1bmN0aW9uIChyZXNvbHZlKSB7IHJlc29sdmUodmFsdWUpOyB9KTsgfVxyXG4gICAgcmV0dXJuIG5ldyAoUCB8fCAoUCA9IFByb21pc2UpKShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XHJcbiAgICAgICAgZnVuY3Rpb24gZnVsZmlsbGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7IHJlc3VsdC5kb25lID8gcmVzb2x2ZShyZXN1bHQudmFsdWUpIDogYWRvcHQocmVzdWx0LnZhbHVlKS50aGVuKGZ1bGZpbGxlZCwgcmVqZWN0ZWQpOyB9XHJcbiAgICAgICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xyXG4gICAgfSk7XHJcbn07XHJcbmltcG9ydCAqIGFzIEV2ZW50RW1pdHRlciBmcm9tICdldmVudGVtaXR0ZXIzJztcclxuaW1wb3J0IHsgU291bmRNYW5hZ2VyIH0gZnJvbSAnLi9zb3VuZC1tYW5hZ2VyJztcclxuaW1wb3J0IHsgS2V5Ym9hcmRNYW5hZ2VyIH0gZnJvbSAnLi9rZXlib2FyZC1tYW5hZ2VyJztcclxuZXhwb3J0IGNsYXNzIE1lbnUgZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xyXG4gICAgY29uc3RydWN0b3IodGl0bGUgPSAnTWVudScsIG1lbnVJdGVtcyA9IFtdLCBzb3VuZFNldCA9IG51bGwsIGRlZmF1bHRBY3Rpb24gPSBudWxsLCBjYW5jZWxBY3Rpb24gPSBudWxsKSB7XHJcbiAgICAgICAgc3VwZXIoKTtcclxuICAgICAgICB0aGlzLnRpdGxlID0gdGl0bGU7XHJcbiAgICAgICAgdGhpcy5tZW51SXRlbXMgPSBtZW51SXRlbXM7XHJcbiAgICAgICAgdGhpcy5zb3VuZFNldCA9IHNvdW5kU2V0O1xyXG4gICAgICAgIHRoaXMuZGVmYXVsdEFjdGlvbiA9IGRlZmF1bHRBY3Rpb247XHJcbiAgICAgICAgdGhpcy5jYW5jZWxBY3Rpb24gPSBjYW5jZWxBY3Rpb247XHJcbiAgICAgICAgdGhpcy5jdXJyZW50SW5kZXggPSAwO1xyXG4gICAgICAgIHRoaXMuRE9NTm9kZXMgPSBbXTtcclxuICAgICAgICB0aGlzLmN1cnJlbnRJbmRleCA9IDA7XHJcbiAgICAgICAgdGhpcy5jdXJyZW50SXRlbSA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5zb3VuZE1hbmFnZXIgPSBuZXcgU291bmRNYW5hZ2VyKHNvdW5kU2V0KTtcclxuICAgICAgICB0aGlzLmtleWJvYXJkTWFuYWdlciA9IG5ldyBLZXlib2FyZE1hbmFnZXIodGhpcyk7XHJcbiAgICAgICAgdGhpcy5pbml0KCk7XHJcbiAgICB9XHJcbiAgICBpbml0KCkge1xyXG4gICAgICAgIHRoaXMubWVudUl0ZW1zW3RoaXMuY3VycmVudEluZGV4XSAmJlxyXG4gICAgICAgICAgICB0aGlzLm1lbnVJdGVtc1t0aGlzLmN1cnJlbnRJbmRleF0uZm9jdXMoKTtcclxuICAgICAgICB0aGlzLmVtaXQoJ2luaXQnKTtcclxuICAgIH1cclxuICAgIGFkZEl0ZW0oaXRlbSkge1xyXG4gICAgICAgIHRoaXMubWVudUl0ZW1zLnB1c2goaXRlbSk7XHJcbiAgICAgICAgdGhpcy5lbWl0KCdpdGVtLmFkZCcsIGl0ZW0pO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc2V0VGl0bGUodGl0bGUpIHtcclxuICAgICAgICB0aGlzLnRpdGxlID0gdGl0bGU7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBzZXRTb3VuZFNldChzb3VuZFNldCkge1xyXG4gICAgICAgIHRoaXMuc291bmRTZXQgPSBzb3VuZFNldDtcclxuICAgICAgICB0aGlzLnNvdW5kTWFuYWdlci5zZXRTb3VuZFNldCh0aGlzLnNvdW5kU2V0KTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHNldERlZmF1bHRBY3Rpb24oaWQpIHtcclxuICAgICAgICB0aGlzLmRlZmF1bHRBY3Rpb24gPSBpZDtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHNldENhbmNlbEFjdGlvbihpZCkge1xyXG4gICAgICAgIHRoaXMuY2FuY2VsQWN0aW9uID0gaWQ7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBydW4oZWxlbWVudCkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmVsZW1lbnQgPSBlbGVtZW50O1xyXG4gICAgICAgICAgICAgICAgdGhpcy5jb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuICAgICAgICAgICAgICAgIHRoaXMudGl0bGVDb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdoMScpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy50aXRsZUNvbnRhaW5lci50ZXh0Q29udGVudCA9IHRoaXMudGl0bGU7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLnRpdGxlQ29udGFpbmVyKTtcclxuICAgICAgICAgICAgICAgIHRoaXMubWVudUl0ZW1zLmZvckVhY2goKGl0ZW0pID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmFwcGVuZFRvQ29udGFpbmVyKGl0ZW0uZ2V0RE9NTm9kZSgpKTtcclxuICAgICAgICAgICAgICAgICAgICBpdGVtLm9uKCd1cGRhdGUnLCB0aGlzLmhhbmRsZUl0ZW1VcGRhdGUuYmluZCh0aGlzKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgaXRlbS5vbignZm9jdXMnLCB0aGlzLm9uSXRlbUZvY3VzLmJpbmQodGhpcykpO1xyXG4gICAgICAgICAgICAgICAgICAgIGl0ZW0ub24oJ2Nob29zZScsIChldmVudCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBtZW51TWFwID0gdGhpcy5jb21waWxlKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc291bmRNYW5hZ2VyLmhhbmRsZVNvdW5kKCdjaG9vc2UnKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdjaG9vc2UnLCBtZW51TWFwKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShtZW51TWFwKTtcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgZWxlbWVudC5hcHBlbmRDaGlsZCh0aGlzLmNvbnRhaW5lcik7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnNvdW5kTWFuYWdlci5oYW5kbGVTb3VuZCgnb3BlbicpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5rZXlib2FyZE1hbmFnZXIuaW5pdCgpO1xyXG4gICAgICAgICAgICAgICAgLy8gcHVzaCBzb21lIGRhdGEgb250byB0aGUgaGlzdG9yeSBzdGFjayBzbyB0aGF0IHdlIGNhbiB1c2UgdGhlIGJyb3dzZXIncyBiYWNrIGJ1dHRvbiB0byBleGl0IG91dCBvZiB0aGUgbWVudS5cclxuICAgICAgICAgICAgICAgIGhpc3RvcnkucHVzaFN0YXRlKHsgbWVudTogdHJ1ZSB9LCBudWxsLCBudWxsKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBjbG9zZSgpIHtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lci5yZW1vdmUoKTtcclxuICAgICAgICB0aGlzLnNvdW5kTWFuYWdlci5oYW5kbGVTb3VuZCgnY2xvc2UnKTtcclxuICAgICAgICB0aGlzLmtleWJvYXJkTWFuYWdlci5yZWxlYXNlKCk7XHJcbiAgICAgICAgdGhpcy5ET01Ob2Rlcy5mb3JFYWNoKChpdGVtKSA9PiB7XHJcbiAgICAgICAgICAgIHRoaXMuY29udGFpbmVyLnJlbW92ZUNoaWxkKGl0ZW0pO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMuZW1pdCgnY2xvc2UnKTtcclxuICAgIH1cclxuICAgIGFwcGVuZFRvQ29udGFpbmVyKG5vZGUpIHtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lci5hcHBlbmRDaGlsZChub2RlKTtcclxuICAgICAgICB0aGlzLkRPTU5vZGVzLnB1c2gobm9kZSk7XHJcbiAgICB9XHJcbiAgICBoYW5kbGVJdGVtVXBkYXRlKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy5zb3VuZE1hbmFnZXIuaGFuZGxlU291bmQodmFsdWUudHlwZSwgdmFsdWUudmFsdWUpO1xyXG4gICAgICAgIHRoaXMuZW1pdCgndXBkYXRlJywgdGhpcy5jb21waWxlKCkpO1xyXG4gICAgfVxyXG4gICAgb25JdGVtRm9jdXMoaWQpIHtcclxuICAgICAgICB0aGlzLnNvdW5kTWFuYWdlci5oYW5kbGVTb3VuZCgnZm9jdXMnKTtcclxuICAgICAgICB0aGlzLmN1cnJlbnRJbmRleCA9IHRoaXMubWVudUl0ZW1zLmluZGV4T2YodGhpcy5tZW51SXRlbXMuZmluZCgoaXRlbSkgPT4gaXRlbS5nZXRJRCgpID09IGlkKSk7XHJcbiAgICAgICAgdGhpcy5lbWl0KCdmb2N1cycsIHRoaXMubWVudUl0ZW1zW3RoaXMuY3VycmVudEluZGV4XSk7XHJcbiAgICB9XHJcbiAgICBmb2N1c05leHQoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudEluZGV4IDwgdGhpcy5tZW51SXRlbXMubGVuZ3RoIC0gMSkge1xyXG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRJbmRleCsrO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmZvY3VzQ3VycmVudEluZGV4KCk7XHJcbiAgICB9XHJcbiAgICBmb2N1c1ByZXZpb3VzKCkge1xyXG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRJbmRleCA+IDApIHtcclxuICAgICAgICAgICAgdGhpcy5jdXJyZW50SW5kZXgtLTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5mb2N1c0N1cnJlbnRJbmRleCgpO1xyXG4gICAgfVxyXG4gICAgZm9jdXNDdXJyZW50SW5kZXgoKSB7XHJcbiAgICAgICAgdGhpcy5tZW51SXRlbXNbdGhpcy5jdXJyZW50SW5kZXhdLmZvY3VzKCk7XHJcbiAgICB9XHJcbiAgICBnZXRDdXJyZW50Rm9jdXMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMubWVudUl0ZW1zW3RoaXMuY3VycmVudEluZGV4XTtcclxuICAgIH1cclxuICAgIGdldENvbnRhaW5lcigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb250YWluZXI7XHJcbiAgICB9XHJcbiAgICBjbGlja0RlZmF1bHRBY3Rpb24oKSB7XHJcbiAgICAgICAgaWYgKCF0aGlzLmRlZmF1bHRBY3Rpb24pXHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICBjb25zdCBpdGVtID0gdGhpcy5tZW51SXRlbXMuZmluZCgoaXRlbSkgPT4gaXRlbS5nZXRJRCgpID09PSB0aGlzLmRlZmF1bHRBY3Rpb24pO1xyXG4gICAgICAgIGl0ZW0uY2xpY2soKTtcclxuICAgIH1cclxuICAgIGNsaWNrQ2FuY2VsQWN0aW9uKCkge1xyXG4gICAgICAgIGlmICghdGhpcy5jYW5jZWxBY3Rpb24pXHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICBjb25zdCBub2RlID0gdGhpcy5tZW51SXRlbXMuZmluZCgoaXRlbSkgPT4gaXRlbS5nZXRJRCgpID09PSB0aGlzLmNhbmNlbEFjdGlvbik7XHJcbiAgICAgICAgbm9kZS5jbGljaygpO1xyXG4gICAgfVxyXG4gICAgY29tcGlsZSgpIHtcclxuICAgICAgICBjb25zdCBtZW51TWFwID0gbmV3IE1hcCgpO1xyXG4gICAgICAgIHRoaXMubWVudUl0ZW1zLmZvckVhY2goKGl0ZW0pID0+IG1lbnVNYXAuc2V0KGl0ZW0uZ2V0SUQoKSwgaXRlbS5nZXRDb250ZW50cygpKSk7XHJcbiAgICAgICAgbWVudU1hcC5zZXQoJ3NlbGVjdGVkJywgdGhpcy5tZW51SXRlbXNbdGhpcy5jdXJyZW50SW5kZXhdLmdldElEKCkpO1xyXG4gICAgICAgIHJldHVybiBtZW51TWFwO1xyXG4gICAgfVxyXG59XHJcbmV4cG9ydCAqIGZyb20gJy4vaXRlbXMnO1xyXG4iXSwibmFtZXMiOlsiaGFzIiwiT2JqZWN0IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJwcmVmaXgiLCJFdmVudHMiLCJFRSIsImZuIiwiY29udGV4dCIsIm9uY2UiLCJ0aGlzIiwiYWRkTGlzdGVuZXIiLCJlbWl0dGVyIiwiZXZlbnQiLCJUeXBlRXJyb3IiLCJsaXN0ZW5lciIsImV2dCIsIl9ldmVudHMiLCJwdXNoIiwiX2V2ZW50c0NvdW50IiwiY2xlYXJFdmVudCIsIkV2ZW50RW1pdHRlciIsImNyZWF0ZSIsIl9fcHJvdG9fXyIsImV2ZW50TmFtZXMiLCJldmVudHMiLCJuYW1lIiwibmFtZXMiLCJjYWxsIiwic2xpY2UiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJjb25jYXQiLCJsaXN0ZW5lcnMiLCJoYW5kbGVycyIsImkiLCJsIiwibGVuZ3RoIiwiZWUiLCJBcnJheSIsImxpc3RlbmVyQ291bnQiLCJlbWl0IiwiYTEiLCJhMiIsImEzIiwiYTQiLCJhNSIsImFyZ3MiLCJsZW4iLCJhcmd1bWVudHMiLCJyZW1vdmVMaXN0ZW5lciIsInVuZGVmaW5lZCIsImFwcGx5IiwiaiIsIm9uIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwib2ZmIiwicHJlZml4ZWQiLCJtb2R1bGUiLCJleHBvcnRzIiwiX193ZWJwYWNrX21vZHVsZV9jYWNoZV9fIiwiX193ZWJwYWNrX3JlcXVpcmVfXyIsIm1vZHVsZUlkIiwiY2FjaGVkTW9kdWxlIiwiX193ZWJwYWNrX21vZHVsZXNfXyIsIm4iLCJnZXR0ZXIiLCJfX2VzTW9kdWxlIiwiZCIsImEiLCJkZWZpbml0aW9uIiwia2V5IiwibyIsImRlZmluZVByb3BlcnR5IiwiZW51bWVyYWJsZSIsImdldCIsIm9iaiIsInByb3AiLCJyIiwiU3ltYm9sIiwidG9TdHJpbmdUYWciLCJ2YWx1ZSIsImJ1aWxkUGF0aCIsImJhc2VQYXRoIiwicGF0aCIsIl9fYXdhaXRlciIsInRoaXNBcmciLCJfYXJndW1lbnRzIiwiUCIsImdlbmVyYXRvciIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwiZnVsZmlsbGVkIiwic3RlcCIsIm5leHQiLCJlIiwicmVqZWN0ZWQiLCJyZXN1bHQiLCJkb25lIiwidGhlbiIsIkRvd25sb2FkZXIiLCJjb25zdHJ1Y3RvciIsInN0b3JhZ2UiLCJxdWV1ZSIsInN1cGVyIiwic2V0QmFzZVBhdGgiLCJkb3dubG9hZCIsImRvd25sb2FkZWQiLCJNYXAiLCJudW1Eb3dubG9hZGVkIiwicG9wIiwiaXRlbSIsImRvd25sb2FkSXRlbSIsInNldCIsInJlbWFpbmluZyIsImluQ2FjaGUiLCJyZXNwb25zZSIsImZldGNoIiwiYWRkIiwiUXVldWUiLCJpdGVtcyIsImZpbGUiLCJyZW1vdmUiLCJmaWx0ZXIiLCJBc3NldFN0b3JhZ2UiLCJpZCIsImluaXQiLCJjYWNoZSIsImNhY2hlcyIsIm9wZW4iLCJyZXF1ZXN0IiwicHV0IiwibWF0Y2giLCJzZXRNYW5pZmVzdCIsIm1hbmlmZXN0IiwicHJldk1hbmlmZXN0U3RyIiwibG9jYWxTdG9yYWdlIiwiZ2V0SXRlbSIsIkpTT04iLCJwYXJzZSIsInZlcnNpb24iLCJzZXRJdGVtIiwic3RyaW5naWZ5IiwiQ2hlY2tNYW5pZmVzdCIsImNsZWFyIiwia2V5cyIsImZvckVhY2giLCJkZWxldGUiLCJTb3VyY2VUeXBlIiwiQXNzZXRNYW5hZ2VyIiwiZG93bmxvYWRlciIsImNvbnNvbGUiLCJsb2ciLCJtYW5pZmVzdFBhdGgiLCJkYXRhIiwidGV4dCIsImVycm9yIiwiYWxlcnQiLCJ0b1N0cmluZyIsIk1hbmlmZXN0IiwiZW5xdWV1ZSIsImRvd25sb2FkRnJvbU1hbmlmZXN0IiwiaW5mbyIsImZpbGVzIiwiZG93bmxvYWRGaWxlIiwiY2xlYXJDYWNoZSIsIkJhc2VFbnRpdHkiLCJjb21wb25lbnRzIiwiYWRkQ29tcG9uZW50IiwiY29tcG9uZW50IiwiY29tcCIsInJlbW92ZUNvbXBvbmVudCIsImdldENvbXBvbmVudElEcyIsImdldENvbXBvbmVudCIsImdldENvbXBvbmVudEJ5SUQiLCJFdmVudEJ1cyIsImV2Iiwic3Vic2NyaWJlcnMiLCJzdWJzY3JpYmVyIiwiRXZlbnRJdGVtIiwic3Vic2NyaWJlIiwidW5zdWJzY3JpYmUiLCJ1bnN1YnNjcmliZUFsbCIsIlF1ZXJ5IiwiaW5jbHVkZSIsImV4Y2x1ZGUiLCJ3b3JsZCIsImlzRGlydHkiLCJyZXN1bHRzIiwiaW5jbHVkZUNvbXBvbmVudElkcyIsIm1hcCIsImV4Y2x1ZGVDb21wb25lbnRJZHMiLCJleGVjdXRlIiwiY29tcG9uZW50TmFtZXNUb0lEcyIsImVudGl0aWVzIiwiZW50aXR5IiwiaWRzIiwiZXhjbHVkZXMiLCJpbmNsdWRlcyIsIlN5c3RlbSIsImV4ZWN1dG9yIiwiV29ybGQiLCJuZXh0RW50aXR5SUQiLCJuZXh0Q29tcG9uZW50SUQiLCJuZXh0UXVlcnlJRCIsInN5c3RlbXMiLCJTZXQiLCJxdWVyeUNhY2hlIiwiZXZlbnRCdXMiLCJydW4iLCJzeXN0ZW0iLCJjcmVhdGVTeXN0ZW0iLCJzeXN0ZW1FeGVjdXRvciIsIm5ld1N5c3RlbSIsImFkZFN5c3RlbSIsImFkZEVudGl0eSIsIm1hcmtRdWVyaWVzRGlydHkiLCJyZW1vdmVFbnRpdHkiLCJlbnRpdHlUb1JlbW92ZSIsImNyZWF0ZUVudGl0eSIsIm5ld0VudGl0eSIsImV4dGVuZEVudGl0eSIsInRvQ2xvbmUiLCJmaW5kIiwiZm91bmQiLCJjbG9uZWQiLCJjcmVhdGVDb21wb25lbnQiLCJuZXdDb21wb25lbnQiLCJxdWVyeSIsImNyZWF0ZVF1ZXJ5IiwibmV3UXVlcnkiLCJCYXNlSW5wdXQiLCJlbGVtZW50IiwiZ2V0U3RhdGUiLCJjYXB0dXJlIiwicHJldmVudERlZmF1bHQiLCJyZWxlYXNlIiwiS2V5Ym9hcmQiLCJrZXlzRG93biIsImtleXNKdXN0UHJlc3NlZCIsImtleXNKdXN0UmVsZWFzZWQiLCJoYW5kbGVLZXlEb3duIiwiYmluZCIsImhhbmRsZUtleVVwIiwiYWN0aXZlIiwiYWRkRXZlbnRMaXN0ZW5lciIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJzdGF0ZSIsImtleUNvZGUiLCJNb3VzZSIsIm1vdXNlUG9zaXRpb24iLCJQb3NpdGlvbiIsIm1vdXNlRGVsdGEiLCJEZWx0YSIsIm1vdXNlV2hlZWwiLCJtb3VzZUJ1dHRvbnMiLCJNb3VzZUJ1dHRvbnMiLCJoYW5kbGVNb3VzZURvd24iLCJoYW5kbGVNb3VzZU1vdmUiLCJoYW5kbGVNb3VzZVVwIiwiaGFuZGxlUG9pbnRlckNoYW5nZSIsImRvY3VtZW50IiwieCIsInkiLCJidXR0b24iLCJjbGllbnRYIiwiY2xpZW50WSIsIm1vdmVtZW50WCIsIm1vdmVtZW50WSIsInBvaW50ZXJMb2NrRWxlbWVudCIsInJlcXVlc3RQb2ludGVyTG9jayIsIklucHV0IiwiSW5wdXRJRHMiLCJpbnB1dHMiLCJpbnB1dElEIiwiaW5zdGFuY2UiLCJjcmVhdGVJbnB1dCIsImFkZElucHV0IiwiaW5wdXQiLCJ2ZWM0IiwidmFsdWVzIiwiRmxvYXQzMkFycmF5IiwieHl6dyIsInoiLCJ3IiwieHkiLCJ4eXoiLCJnIiwiYiIsInJnIiwicmdiIiwicmdiYSIsImF0IiwiaW5kZXgiLCJyZXNldCIsImNvcHkiLCJkZXN0IiwibmVnYXRlIiwiZXF1YWxzIiwidmVjdG9yIiwidGhyZXNob2xkIiwiZXBzaWxvbiIsIk1hdGgiLCJhYnMiLCJzcXJ0Iiwic3F1YXJlZExlbmd0aCIsInN1YnRyYWN0IiwibXVsdGlwbHkiLCJkaXZpZGUiLCJzY2FsZSIsIm5vcm1hbGl6ZSIsIm11bHRpcGx5TWF0NCIsIm1hdHJpeCIsIm11bHRpcGx5VmVjNCIsInN0YXRpYyIsInZlY3RvcjIiLCJ0aW1lIiwiemVybyIsIm9uZSIsIm1hdDQiLCJhbGwiLCJyb3ciLCJjb2wiLCJkZXRlcm1pbmFudCIsImEwMCIsImEwMSIsImEwMiIsImEwMyIsImExMCIsImExMSIsImExMiIsImExMyIsImEyMCIsImEyMSIsImEyMiIsImEyMyIsImEzMCIsImEzMSIsImEzMiIsImEzMyIsInNldElkZW50aXR5IiwidHJhbnNwb3NlIiwidGVtcDAxIiwidGVtcDAyIiwidGVtcDAzIiwidGVtcDEyIiwidGVtcDEzIiwidGVtcDIzIiwiaW52ZXJzZSIsImRldDAwIiwiZGV0MDEiLCJkZXQwMiIsImRldDAzIiwiZGV0MDQiLCJkZXQwNSIsImRldDA2IiwiZGV0MDciLCJkZXQwOCIsImRldDA5IiwiZGV0MTAiLCJkZXQxMSIsImRldCIsImIwIiwiYjEiLCJiMiIsImIzIiwibXVsdGlwbHlWZWMzIiwidG9NYXQzIiwibWF0MyIsInRvSW52ZXJzZU1hdDMiLCJkZXQyMSIsInRyYW5zbGF0ZSIsInJvdGF0ZSIsImFuZ2xlIiwiYXhpcyIsInMiLCJzaW4iLCJjIiwiY29zIiwidCIsImIwMCIsImIwMSIsImIwMiIsImIxMCIsImIxMSIsImIxMiIsImIyMCIsImIyMSIsImIyMiIsImxlZnQiLCJyaWdodCIsImJvdHRvbSIsInRvcCIsIm5lYXIiLCJmYXIiLCJybCIsInRiIiwiZm92IiwiYXNwZWN0IiwidGFuIiwiUEkiLCJmcnVzdHVtIiwicG9zaXRpb24iLCJ0YXJnZXQiLCJ1cCIsImlkZW50aXR5IiwibTEiLCJtMiIsImIwMyIsImIxMyIsImIyMyIsImIzMCIsImIzMSIsImIzMiIsImIzMyIsInZlYzIiLCJtdWx0aXBseU1hdDIiLCJtdWx0aXBseVZlYzIiLCJtdWx0aXBseU1hdDMiLCJ4MiIsInNxdWFyZWREaXN0YW5jZSIsInkyIiwidG9NYXQ0IiwidG9RdWF0IiwibTAwIiwibTAxIiwibTAyIiwibTEwIiwibTExIiwibTEyIiwibTIwIiwibTIxIiwibTIyIiwiZm91clhTcXVhcmVkTWludXMxIiwiZm91cllTcXVhcmVkTWludXMxIiwiZm91clpTcXVhcmVkTWludXMxIiwiYmlnZ2VzdEluZGV4IiwiZm91ckJpZ2dlc3RTcXVhcmVkTWludXMxIiwiYmlnZ2VzdFZhbCIsIm11bHQiLCJxdWF0Iiwicm9sbCIsImF0YW4yIiwicGl0Y2giLCJ5YXciLCJhc2luIiwiY2FsY3VsYXRlVyIsImRvdCIsImludkRvdCIsImNvbmp1Z2F0ZSIsIm90aGVyIiwicTF4IiwicTF5IiwicTF6IiwicTF3IiwicTJ4IiwicTJ5IiwicTJ6IiwicTJ3IiwicXgiLCJxeSIsInF6IiwicXciLCJpeCIsIml5IiwiaXoiLCJpdyIsInoyIiwieHgiLCJ4eiIsInl5IiwieXoiLCJ6eiIsInd4Iiwid3kiLCJ3eiIsInExIiwicTIiLCJxMmEiLCJrMCIsImsxIiwib25lT3ZlclNpbiIsImNvc0hhbGZUaGV0YSIsImhhbGZUaGV0YSIsImFjb3MiLCJzaW5IYWxmVGhldGEiLCJyYXRpb0EiLCJyYXRpb0IiLCJtdWx0aXBseUJ5TWF0MyIsIm11bHRpcGx5QnlRdWF0IiwicXVhdGVybmlvbiIsImZvcndhcmQiLCJCYXNlT3V0cHV0Iiwic3BlYWsiLCJzdG9wIiwic2V0T3B0aW9ucyIsIm9wdGlvbnMiLCJBcmlhT3V0cHV0IiwidGltZW91dCIsImNvbnRhaW5lciIsImNyZWF0ZUVsZW1lbnQiLCJzZXRBdHRyaWJ1dGUiLCJzcGVlY2hEaXNwbGF5IiwiYXBwZW5kIiwiYm9keSIsImFwcGVuZENoaWxkIiwiaW5zZXJ0QmVmb3JlIiwiZmlyc3RDaGlsZCIsImNsZWFyRGlzcGxheSIsIm5vZGUiLCJjcmVhdGVUZXh0Tm9kZSIsInBhcmEiLCJzZXRUaW1lb3V0IiwiaW5uZXJIVE1MIiwiV2ViVFRTT3V0cHV0IiwiVFRTIiwib3V0cHV0IiwiY3JlYXRlT3V0cHV0IiwiU291bmRNYW5hZ2VyIiwic291bmRTZXQiLCJzZXRTb3VuZFNldCIsImhhbmRsZVNvdW5kIiwidHlwZSIsImhhbmRsZUVkaXRTb3VuZCIsImhhbmRsZVNsaWRlclNvdW5kIiwiaGFuZGxlU2VsZWN0b3JTb3VuZCIsImhhbmRsZUNoZWNrYm94U291bmQiLCJoYW5kbGVGb2N1c1NvdW5kIiwiaGFuZGxlQ2hvb3NlU291bmQiLCJoYW5kbGVPcGVuU291bmQiLCJoYW5kbGVDbG9zZVNvdW5kIiwicHJldkRhdGEiLCJwbGF5IiwiY2hhciIsInNjcm9sbGVyIiwic2xpZGVyTGVmdCIsInNsaWRlclJpZ2h0IiwibW92ZSIsImNsb3NlIiwiY2hvb3NlIiwiY2hlY2tlZCIsInVuY2hlY2tlZCIsIktleWJvYXJkTWFuYWdlciIsIm1lbnUiLCJnZXRDb250YWluZXIiLCJoYW5kbGVyIiwid2luZG93Iiwib25wb3BzdGF0ZSIsImNsaWNrQ2FuY2VsQWN0aW9uIiwiZm9jdXNOZXh0IiwiZm9jdXNQcmV2aW91cyIsImNsaWNrRGVmYXVsdEFjdGlvbiIsIkJhc2VJdGVtIiwidGl0bGUiLCJnZXRET01Ob2RlIiwiZ2V0Q29udGVudHMiLCJvbkZvY3VzIiwiZm9jdXMiLCJjbGljayIsImdldElEIiwiRWRpdEl0ZW0iLCJpbml0aWFsVGV4dCIsImlzUGFzc3dvcmQiLCJjb250ZW50cyIsImxhYmVsIiwidGV4dENvbnRlbnQiLCJlZGl0RmllbGQiLCJvbkNoYW5nZSIsIk1lbnVJdGVtIiwiaGFuZGxlQ2xpY2siLCJTZWxlY3Rvckl0ZW0iLCJlbnRyaWVzIiwibGlzdENvbnRhaW5lciIsImZpZWxkU2V0IiwiYnVpbGRFbnRyaWVzIiwib25JdGVtRm9jdXMiLCJvblNlbGVjdEl0ZW0iLCJvbkNoYW5nZUl0ZW0iLCJjdXJyZW50VmFsdWUiLCJxdWVyeVNlbGVjdG9yIiwiU2xpZGVySXRlbSIsIm1pbiIsIm1heCIsImRlZmF1bHRWYWx1ZSIsInNsaWRlciIsIkNoZWNrYm94SXRlbSIsImNoZWNrYm94RWxlbWVudCIsIk1lbnUiLCJtZW51SXRlbXMiLCJkZWZhdWx0QWN0aW9uIiwiY2FuY2VsQWN0aW9uIiwiY3VycmVudEluZGV4IiwiRE9NTm9kZXMiLCJjdXJyZW50SXRlbSIsInNvdW5kTWFuYWdlciIsImtleWJvYXJkTWFuYWdlciIsImFkZEl0ZW0iLCJzZXRUaXRsZSIsInNldERlZmF1bHRBY3Rpb24iLCJzZXRDYW5jZWxBY3Rpb24iLCJ0aXRsZUNvbnRhaW5lciIsImFwcGVuZFRvQ29udGFpbmVyIiwiaGFuZGxlSXRlbVVwZGF0ZSIsIm1lbnVNYXAiLCJjb21waWxlIiwiaGlzdG9yeSIsInB1c2hTdGF0ZSIsInJlbW92ZUNoaWxkIiwiaW5kZXhPZiIsImZvY3VzQ3VycmVudEluZGV4IiwiZ2V0Q3VycmVudEZvY3VzIl0sInNvdXJjZVJvb3QiOiIifQ==
\ No newline at end of file
diff --git a/src/framework/event-bus/event-bus.d.ts b/src/framework/event-bus/event-bus.d.ts
new file mode 100644
index 0000000..24b52fb
--- /dev/null
+++ b/src/framework/event-bus/event-bus.d.ts
@@ -0,0 +1,11 @@
+export declare class EventBus {
+ private events;
+ constructor();
+ emit(id: string, data: any): void;
+ subscribe(id: string, subscriber: Function): void;
+}
+export declare class EventItem {
+ id: string;
+ subscribers: Function[];
+ constructor(id: string);
+}
diff --git a/src/framework/event-bus/event-bus.js b/src/framework/event-bus/event-bus.js
new file mode 100644
index 0000000..11ee12b
--- /dev/null
+++ b/src/framework/event-bus/event-bus.js
@@ -0,0 +1,30 @@
+export class EventBus {
+ constructor() {
+ this.events = new Map();
+ }
+ emit(id, data) {
+ let ev = this.events.get(id);
+ if (!ev) {
+ let ev = new EventItem(id);
+ this.events.set(id, ev);
+ return;
+ }
+ ev.subscribers.forEach((subscriber) => {
+ subscriber(data);
+ });
+ }
+ subscribe(id, subscriber) {
+ let ev = this.events.get(id);
+ if (!ev) {
+ ev = new EventItem(id);
+ this.events.set(id, ev);
+ }
+ ev.subscribers.push(subscriber);
+ }
+}
+export class EventItem {
+ constructor(id) {
+ this.id = id;
+ this.subscribers = [];
+ }
+}
diff --git a/src/framework/event-bus/index.d.ts b/src/framework/event-bus/index.d.ts
new file mode 100644
index 0000000..a3d66e5
--- /dev/null
+++ b/src/framework/event-bus/index.d.ts
@@ -0,0 +1,13 @@
+export declare class EventBus {
+ private events;
+ constructor();
+ emit(id: string, data?: any): void;
+ subscribe(id: string, subscriber: Function): void;
+ unsubscribe(id: string, subscriber: Function): void;
+ unsubscribeAll(id: string): void;
+}
+export declare class EventItem {
+ id: string;
+ subscribers: Function[];
+ constructor(id: string);
+}
diff --git a/src/framework/event-bus/index.js b/src/framework/event-bus/index.js
new file mode 100644
index 0000000..20afbae
--- /dev/null
+++ b/src/framework/event-bus/index.js
@@ -0,0 +1,44 @@
+export class EventBus {
+ constructor() {
+ this.events = new Map();
+ }
+ emit(id, data = {}) {
+ let ev = this.events.get(id);
+ if (!ev) {
+ let ev = new EventItem(id);
+ this.events.set(id, ev);
+ return;
+ }
+ ev.subscribers.forEach((subscriber) => {
+ subscriber(data);
+ });
+ }
+ subscribe(id, subscriber) {
+ let ev = this.events.get(id);
+ if (!ev) {
+ ev = new EventItem(id);
+ this.events.set(id, ev);
+ }
+ ev.subscribers.push(subscriber);
+ }
+ unsubscribe(id, subscriber) {
+ if (this.events.has(id)) {
+ let ev = this.events.get(id);
+ ev.subscribers = ev.subscribers.filter((fn) => fn !== subscriber);
+ if (ev.subscribers.length < 1) {
+ this.events.delete(id);
+ }
+ }
+ }
+ unsubscribeAll(id) {
+ if (this.events.has(id)) {
+ this.events.delete(id);
+ }
+ }
+}
+export class EventItem {
+ constructor(id) {
+ this.id = id;
+ this.subscribers = [];
+ }
+}
diff --git a/src/framework/game/game.d.ts b/src/framework/game/game.d.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/framework/game/game.js b/src/framework/game/game.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/framework/game/index.d.ts b/src/framework/game/index.d.ts
new file mode 100644
index 0000000..0de492c
--- /dev/null
+++ b/src/framework/game/index.d.ts
@@ -0,0 +1,26 @@
+import { AssetManager } from '../asset-manager';
+import { Input } from '../input';
+import Resonator from '../resonator';
+import { Scene } from '../scene/scene';
+import { SceneManager } from '../scene/manager';
+import { Scheduler } from '../scheduler';
+import { TTS } from '../tts';
+import { HTTPLoader } from '../resonator/loaders/http-loader';
+import { EventBus } from '../event-bus';
+import { World } from '../world';
+export declare class Game extends EventBus {
+ assetLoader: HTTPLoader;
+ assetManager: AssetManager;
+ resonator: Resonator;
+ input: Input;
+ tts: TTS;
+ sceneManager: SceneManager;
+ scheduler: Scheduler;
+ world: World;
+ constructor();
+ init(): void;
+ start(): void;
+ addScene(scene: Scene): void;
+ addDefaultScene(scene: Scene): void;
+ setWorld(world: World): void;
+}
diff --git a/src/framework/game/index.js b/src/framework/game/index.js
new file mode 100644
index 0000000..91b4aa7
--- /dev/null
+++ b/src/framework/game/index.js
@@ -0,0 +1,44 @@
+import { AssetManager } from '../asset-manager';
+import { Input } from '../input';
+import Resonator from '../resonator';
+import { SceneManager } from '../scene/manager';
+import { Scheduler } from '../scheduler';
+import { TTS } from '../tts';
+import { AriaOutput } from '../tts/outputs/aria';
+import { HTTPLoader } from '../resonator/loaders/http-loader';
+import { EventBus } from '../event-bus';
+export class Game extends EventBus {
+ constructor() {
+ super();
+ this.init();
+ }
+ init() {
+ this.assetManager = new AssetManager('game', '');
+ this.assetLoader = new HTTPLoader();
+ this.resonator = new Resonator(this.assetLoader);
+ this.input = new Input(['keyboard'], document.body);
+ this.tts = new TTS(new AriaOutput());
+ this.sceneManager = new SceneManager();
+ this.scheduler = new Scheduler(60);
+ this.emit('ready');
+ }
+ start() {
+ this.scheduler.start();
+ this.scheduler.subscribe('update.logic', (dt) => {
+ this.sceneManager.currentScene.update(dt);
+ this.world.update(dt);
+ });
+ this.scheduler.subscribe('update.draw', (dt) => this.sceneManager.currentScene.updateDraw());
+ this.sceneManager.init();
+ }
+ addScene(scene) {
+ this.sceneManager.addScene(scene);
+ }
+ addDefaultScene(scene) {
+ this.sceneManager.addScene(scene);
+ this.sceneManager.setDefaultScene(scene);
+ }
+ setWorld(world) {
+ this.world = world;
+ }
+}
diff --git a/src/framework/game/scenes/ecs-scene.d.ts b/src/framework/game/scenes/ecs-scene.d.ts
new file mode 100644
index 0000000..6cee437
--- /dev/null
+++ b/src/framework/game/scenes/ecs-scene.d.ts
@@ -0,0 +1,29 @@
+import { Scene } from '../../scene/scene';
+import { World } from '../../ecs/index';
+import { Game } from '..';
+import { Component } from '../../ecs/component';
+import { System } from '../../ecs/system';
+import { Entity } from '../../ecs/entity';
+import { Query } from '../../ecs/query';
+import { SceneManager } from '../../scene/manager';
+export declare class ECSScene implements Scene {
+ instance: Game;
+ id: string;
+ world: World;
+ running: boolean;
+ data: any;
+ constructor(instance: Game);
+ update(): void;
+ updateDraw(): boolean;
+ onActivate(manager: SceneManager): void;
+ onDeactivate(): void;
+ onSwitch(): void;
+ createEntity(components: Array>): Entity;
+ createComponent(props: T): Component;
+ createSystem(systemExecutor: Function): void;
+ addSystem(system: System): void;
+ addEntity(entity: Entity): void;
+ removeEntity(entity: Entity): void;
+ createQuery(include: Array>, exclude: Array>): Query;
+ extendEntity(entity: Entity, components: Array>): Entity;
+}
diff --git a/src/framework/game/scenes/ecs-scene.js b/src/framework/game/scenes/ecs-scene.js
new file mode 100644
index 0000000..4ac7412
--- /dev/null
+++ b/src/framework/game/scenes/ecs-scene.js
@@ -0,0 +1,49 @@
+import { World } from '../../ecs/index';
+export class ECSScene {
+ constructor(instance) {
+ this.instance = instance;
+ this.running = true;
+ this.id = 'ECSScene';
+ this.world = new World();
+ }
+ update() {
+ if (this.running)
+ this.world.run();
+ }
+ updateDraw() {
+ return true;
+ }
+ onActivate(manager) {
+ this.running = true;
+ }
+ onDeactivate() {
+ this.running = false;
+ }
+ onSwitch() {
+ return;
+ }
+ createEntity(components) {
+ return this.world.createEntity(components);
+ }
+ createComponent(props) {
+ return this.world.createComponent(props);
+ }
+ createSystem(systemExecutor) {
+ return this.world.createSystem(systemExecutor);
+ }
+ addSystem(system) {
+ return this.world.addSystem(system);
+ }
+ addEntity(entity) {
+ return this.world.addEntity(entity);
+ }
+ removeEntity(entity) {
+ return this.world.removeEntity(entity);
+ }
+ createQuery(include, exclude) {
+ return this.world.createQuery(include, exclude);
+ }
+ extendEntity(entity, components) {
+ return this.world.extendEntity(entity, components);
+ }
+}
diff --git a/src/framework/index.d.ts b/src/framework/index.d.ts
new file mode 100644
index 0000000..513af72
--- /dev/null
+++ b/src/framework/index.d.ts
@@ -0,0 +1,7 @@
+export * from './asset-manager';
+export * from './ecs';
+export * from './event-bus';
+export * from './input';
+export * from './resonator';
+export * from './tts';
+export * from './ui';
diff --git a/src/framework/index.js b/src/framework/index.js
new file mode 100644
index 0000000..513af72
--- /dev/null
+++ b/src/framework/index.js
@@ -0,0 +1,7 @@
+export * from './asset-manager';
+export * from './ecs';
+export * from './event-bus';
+export * from './input';
+export * from './resonator';
+export * from './tts';
+export * from './ui';
diff --git a/src/framework/input/index.d.ts b/src/framework/input/index.d.ts
new file mode 100644
index 0000000..fe7e744
--- /dev/null
+++ b/src/framework/input/index.d.ts
@@ -0,0 +1,13 @@
+import { BaseInput } from './inputs/base-input';
+import { State } from './interfaces/state';
+export declare class Input {
+ private InputIDs;
+ private element;
+ private inputs;
+ constructor(InputIDs: string[], element: HTMLElement);
+ private init;
+ addInput(id: string, input: BaseInput): this;
+ capture(preventDefault?: boolean): void;
+ release(): void;
+ getState(): State;
+}
diff --git a/src/framework/input/index.js b/src/framework/input/index.js
new file mode 100644
index 0000000..595d456
--- /dev/null
+++ b/src/framework/input/index.js
@@ -0,0 +1,34 @@
+import { createInput } from './input-factory';
+export class Input {
+ constructor(InputIDs, element) {
+ this.InputIDs = InputIDs;
+ this.element = element;
+ this.inputs = new Map();
+ this.init();
+ }
+ init() {
+ this.InputIDs.forEach((inputID) => {
+ const thing = createInput(inputID);
+ const instance = new thing(this.element);
+ this.inputs.set(inputID, instance);
+ });
+ }
+ addInput(id, input) {
+ this.inputs.set(id, input);
+ return this;
+ }
+ capture(preventDefault = true) {
+ this.inputs.forEach((input) => input.capture(preventDefault));
+ }
+ release() {
+ this.inputs.forEach((input) => input.release());
+ }
+ getState() {
+ const state = {};
+ this.inputs.forEach((input, inputID) => {
+ if (input)
+ state[inputID] = input.getState();
+ });
+ return state;
+ }
+}
diff --git a/src/framework/input/input-factory.d.ts b/src/framework/input/input-factory.d.ts
new file mode 100644
index 0000000..a7e84d2
--- /dev/null
+++ b/src/framework/input/input-factory.d.ts
@@ -0,0 +1 @@
+export declare function createInput(key: string): any;
diff --git a/src/framework/input/input-factory.js b/src/framework/input/input-factory.js
new file mode 100644
index 0000000..fe7e98b
--- /dev/null
+++ b/src/framework/input/input-factory.js
@@ -0,0 +1,14 @@
+import { Keyboard } from './inputs/keyboard';
+import { Mouse } from './inputs/mouse';
+export function createInput(key) {
+ switch (key) {
+ case 'keyboard':
+ return Keyboard;
+ break;
+ case 'mouse':
+ return Mouse;
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/framework/input/inputs/base-input.d.ts b/src/framework/input/inputs/base-input.d.ts
new file mode 100644
index 0000000..661de29
--- /dev/null
+++ b/src/framework/input/inputs/base-input.d.ts
@@ -0,0 +1,10 @@
+export declare class BaseInput {
+ protected element: HTMLElement;
+ protected active: boolean;
+ constructor(element: HTMLElement);
+ getState(): any;
+ capture(preventDefault: boolean): void;
+ release(): void;
+}
+export interface IBaseInput {
+}
diff --git a/src/framework/input/inputs/base-input.js b/src/framework/input/inputs/base-input.js
new file mode 100644
index 0000000..dc21706
--- /dev/null
+++ b/src/framework/input/inputs/base-input.js
@@ -0,0 +1,12 @@
+export class BaseInput {
+ constructor(element) {
+ this.element = element;
+ }
+ getState() { }
+ capture(preventDefault) {
+ return;
+ }
+ release() {
+ return;
+ }
+}
diff --git a/src/framework/input/inputs/joystick.d.ts b/src/framework/input/inputs/joystick.d.ts
new file mode 100644
index 0000000..1c4cdd8
--- /dev/null
+++ b/src/framework/input/inputs/joystick.d.ts
@@ -0,0 +1,6 @@
+import { BaseInput } from './base-input';
+export declare class Joystick extends BaseInput {
+ constructor(element: HTMLElement);
+}
+export interface IJoystick {
+}
diff --git a/src/framework/input/inputs/joystick.js b/src/framework/input/inputs/joystick.js
new file mode 100644
index 0000000..76e4e7b
--- /dev/null
+++ b/src/framework/input/inputs/joystick.js
@@ -0,0 +1,6 @@
+import { BaseInput } from './base-input';
+export class Joystick extends BaseInput {
+ constructor(element) {
+ super(element);
+ }
+}
diff --git a/src/framework/input/inputs/keyboard.d.ts b/src/framework/input/inputs/keyboard.d.ts
new file mode 100644
index 0000000..915d9c9
--- /dev/null
+++ b/src/framework/input/inputs/keyboard.d.ts
@@ -0,0 +1,18 @@
+import { BaseInput } from './base-input';
+export declare class Keyboard extends BaseInput {
+ private keysDown;
+ private keysJustPressed;
+ private keysJustReleased;
+ private preventDefault;
+ constructor(element: HTMLElement);
+ capture(preventDefault: boolean): void;
+ release(): void;
+ getState(): IKeyboard;
+ private handleKeyDown;
+ private handleKeyUp;
+}
+export interface IKeyboard {
+ keysDown: Map;
+ keysJustPressed: Map;
+ keysJustReleased: Map;
+}
diff --git a/src/framework/input/inputs/keyboard.js b/src/framework/input/inputs/keyboard.js
new file mode 100644
index 0000000..7ea29c7
--- /dev/null
+++ b/src/framework/input/inputs/keyboard.js
@@ -0,0 +1,50 @@
+import { BaseInput } from './base-input';
+export class Keyboard extends BaseInput {
+ constructor(element) {
+ super(element);
+ this.keysDown = new Map();
+ this.keysJustPressed = new Map();
+ this.keysJustReleased = new Map();
+ this.handleKeyDown = this.handleKeyDown.bind(this);
+ this.handleKeyUp = this.handleKeyUp.bind(this);
+ }
+ capture(preventDefault) {
+ this.active = true;
+ this.preventDefault = preventDefault;
+ this.element.addEventListener('keydown', this.handleKeyDown);
+ this.element.addEventListener('keyup', this.handleKeyUp);
+ }
+ release() {
+ this.active = false;
+ this.element.removeEventListener('keydown', this.handleKeyDown);
+ this.element.removeEventListener('keyup', this.handleKeyUp);
+ }
+ getState() {
+ const state = {
+ keysDown: new Map(this.keysDown),
+ keysJustPressed: new Map(this.keysJustPressed),
+ keysJustReleased: new Map(this.keysJustReleased)
+ };
+ this.keysJustPressed.clear();
+ this.keysJustReleased.clear();
+ return state;
+ }
+ handleKeyDown(event) {
+ if (this.active && this.preventDefault)
+ event.preventDefault();
+ if (this.keysDown.get(event.keyCode))
+ return;
+ this.keysDown.set(event.keyCode, true);
+ this.keysJustPressed.set(event.keyCode, true);
+ this.keysJustReleased.set(event.keyCode, false);
+ }
+ handleKeyUp(event) {
+ if (this.active && this.preventDefault)
+ event.preventDefault();
+ if (!this.keysDown.get(event.keyCode))
+ return;
+ this.keysDown.set(event.keyCode, false);
+ this.keysJustPressed.set(event.keyCode, false);
+ this.keysJustReleased.set(event.keyCode, true);
+ }
+}
diff --git a/src/framework/input/inputs/mouse.d.ts b/src/framework/input/inputs/mouse.d.ts
new file mode 100644
index 0000000..51ad7ea
--- /dev/null
+++ b/src/framework/input/inputs/mouse.d.ts
@@ -0,0 +1,34 @@
+import { BaseInput } from './base-input';
+export declare class Mouse extends BaseInput {
+ private mousePosition;
+ private mouseDelta;
+ private mouseWheel;
+ private mouseButtons;
+ constructor(element: HTMLElement);
+ capture(): void;
+ release(): void;
+ getState(): IMouse;
+ private handleMouseDown;
+ private handleMouseMove;
+ private handleMouseUp;
+ private handlePointerChange;
+}
+export declare class Position {
+ x: number;
+ y: number;
+}
+export declare class MouseButtons {
+ keysDown: Map;
+ keysJustPressed: Map;
+ keysJustReleased: Map;
+}
+export declare class Delta {
+ x: number;
+ y: number;
+}
+export interface IMouse {
+ mouseButtons: MouseButtons;
+ mousePosition: Position;
+ mouseWheel: Delta;
+ mouseDelta: Delta;
+}
diff --git a/src/framework/input/inputs/mouse.js b/src/framework/input/inputs/mouse.js
new file mode 100644
index 0000000..e14b4e9
--- /dev/null
+++ b/src/framework/input/inputs/mouse.js
@@ -0,0 +1,87 @@
+import { BaseInput } from './base-input';
+export class Mouse extends BaseInput {
+ constructor(element) {
+ super(element);
+ this.mousePosition = new Position();
+ this.mouseDelta = new Delta();
+ this.mouseWheel = new Delta();
+ this.mouseButtons = new MouseButtons();
+ }
+ capture() {
+ this.handleMouseDown = this.handleMouseDown.bind(this);
+ this.handleMouseMove = this.handleMouseMove.bind(this);
+ this.handleMouseUp = this.handleMouseUp.bind(this);
+ this.handlePointerChange = this.handlePointerChange.bind(this);
+ this.active = true;
+ this.element.addEventListener('mousedown', this.handleMouseDown);
+ this.element.addEventListener('mousemove', this.handleMouseMove);
+ this.element.addEventListener('mouseup', this.handleMouseUp);
+ document.addEventListener('pointerlockchange', this.handlePointerChange);
+ }
+ release() {
+ this.active = false;
+ this.element.removeEventListener('mousedown', this.handleMouseDown);
+ this.element.removeEventListener('mousemove', this.handleMouseMove);
+ this.element.removeEventListener('mouseup', this.handleMouseUp);
+ }
+ getState() {
+ const { mouseButtons, mouseDelta, mousePosition, mouseWheel } = this;
+ const state = {
+ mouseButtons: {
+ keysDown: new Map(this.mouseButtons.keysDown),
+ keysJustPressed: new Map(this.mouseButtons.keysJustPressed),
+ keysJustReleased: new Map(this.mouseButtons.keysJustReleased)
+ },
+ mouseDelta,
+ mousePosition,
+ mouseWheel
+ };
+ this.mouseButtons.keysJustPressed.clear();
+ this.mouseButtons.keysJustReleased.clear();
+ this.mouseDelta.x = 0;
+ this.mouseDelta.y = 0;
+ return state;
+ }
+ handleMouseDown(event) {
+ if (this.active)
+ event.preventDefault();
+ this.mouseButtons.keysDown.set(event.button, true);
+ this.mouseButtons.keysJustPressed.set(event.button, true);
+ this.mouseButtons.keysJustReleased.set(event.button, false);
+ }
+ handleMouseMove(event) {
+ if (this.active)
+ event.preventDefault();
+ this.mousePosition.x = event.clientX;
+ this.mousePosition.y = event.clientY;
+ this.mouseDelta.x = event.movementX;
+ this.mouseDelta.y = event.movementY;
+ }
+ handleMouseUp(event) {
+ if (this.active)
+ event.preventDefault();
+ this.mouseButtons.keysJustReleased.set(event.button, true);
+ this.mouseButtons.keysDown.set(event.button, false);
+ this.mouseButtons.keysJustPressed.set(event.button, false);
+ }
+ handlePointerChange() {
+ if (document.pointerLockElement !== this.element) {
+ this.element.addEventListener('click', () => {
+ this.element.requestPointerLock();
+ }, {
+ once: true
+ });
+ }
+ }
+}
+export class Position {
+}
+export class MouseButtons {
+ constructor() {
+ this.keysDown = new Map();
+ this.keysJustPressed = new Map();
+ this.keysJustReleased = new Map();
+ }
+}
+export class Delta {
+}
diff --git a/src/framework/input/interfaces/state.d.ts b/src/framework/input/interfaces/state.d.ts
new file mode 100644
index 0000000..55fe5d4
--- /dev/null
+++ b/src/framework/input/interfaces/state.d.ts
@@ -0,0 +1,4 @@
+import { IKeyboard } from '../inputs/keyboard';
+export interface State {
+ keyboard?: IKeyboard;
+}
diff --git a/src/framework/input/interfaces/state.js b/src/framework/input/interfaces/state.js
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/src/framework/input/interfaces/state.js
@@ -0,0 +1 @@
+export {};
diff --git a/src/framework/input/keycodes.d.ts b/src/framework/input/keycodes.d.ts
new file mode 100644
index 0000000..3e0ca85
--- /dev/null
+++ b/src/framework/input/keycodes.d.ts
@@ -0,0 +1,122 @@
+export declare let KeyCodes: {
+ CANCEL: number;
+ HELP: number;
+ BACK_SPACE: number;
+ TAB: number;
+ CLEAR: number;
+ RETURN: number;
+ ENTER: number;
+ SHIFT: number;
+ CONTROL: number;
+ ALT: number;
+ PAUSE: number;
+ CAPS_LOCK: number;
+ ESCAPE: number;
+ SPACE: number;
+ PAGE_UP: number;
+ PAGE_DOWN: number;
+ END: number;
+ HOME: number;
+ LEFT: number;
+ UP: number;
+ RIGHT: number;
+ DOWN: number;
+ PRINTSCREEN: number;
+ INSERT: number;
+ DELETE: number;
+ 0: number;
+ 1: number;
+ 2: number;
+ 3: number;
+ 4: number;
+ 5: number;
+ 6: number;
+ 7: number;
+ 8: number;
+ 9: number;
+ SEMICOLON: number;
+ EQUALS: number;
+ A: number;
+ B: number;
+ C: number;
+ D: number;
+ E: number;
+ F: number;
+ G: number;
+ H: number;
+ I: number;
+ J: number;
+ K: number;
+ L: number;
+ M: number;
+ N: number;
+ O: number;
+ P: number;
+ Q: number;
+ R: number;
+ S: number;
+ T: number;
+ U: number;
+ V: number;
+ W: number;
+ X: number;
+ Y: number;
+ Z: number;
+ CONTEXT_MENU: number;
+ NUMPAD0: number;
+ NUMPAD1: number;
+ NUMPAD2: number;
+ NUMPAD3: number;
+ NUMPAD4: number;
+ NUMPAD5: number;
+ NUMPAD6: number;
+ NUMPAD7: number;
+ NUMPAD8: number;
+ NUMPAD9: number;
+ MULTIPLY: number;
+ ADD: number;
+ SEPARATOR: number;
+ SUBTRACT: number;
+ DECIMAL: number;
+ DIVIDE: number;
+ F1: number;
+ F2: number;
+ F3: number;
+ F4: number;
+ F5: number;
+ F6: number;
+ F7: number;
+ F8: number;
+ F9: number;
+ F10: number;
+ F11: number;
+ F12: number;
+ F13: number;
+ F14: number;
+ F15: number;
+ F16: number;
+ F17: number;
+ F18: number;
+ F19: number;
+ F20: number;
+ F21: number;
+ F22: number;
+ F23: number;
+ F24: number;
+ NUM_LOCK: number;
+ SCROLL_LOCK: number;
+ COMMA: number;
+ PERIOD: number;
+ SLASH: number;
+ BACK_QUOTE: number;
+ OPEN_BRACKET: number;
+ BACK_SLASH: number;
+ CLOSE_BRACKET: number;
+ QUOTE: number;
+ META: number;
+};
+export declare let MouseCodes: {
+ LEFT: number;
+ RIGHT: number;
+ MIDDLE: number;
+};
diff --git a/src/framework/input/keycodes.js b/src/framework/input/keycodes.js
new file mode 100644
index 0000000..6984435
--- /dev/null
+++ b/src/framework/input/keycodes.js
@@ -0,0 +1,122 @@
+export let KeyCodes = {
+ CANCEL: 3,
+ HELP: 6,
+ BACK_SPACE: 8,
+ TAB: 9,
+ CLEAR: 12,
+ RETURN: 13,
+ ENTER: 14,
+ SHIFT: 16,
+ CONTROL: 17,
+ ALT: 18,
+ PAUSE: 19,
+ CAPS_LOCK: 20,
+ ESCAPE: 27,
+ SPACE: 32,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ END: 35,
+ HOME: 36,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+ PRINTSCREEN: 44,
+ INSERT: 45,
+ DELETE: 46,
+ 0: 48,
+ 1: 49,
+ 2: 50,
+ 3: 51,
+ 4: 52,
+ 5: 53,
+ 6: 54,
+ 7: 55,
+ 8: 56,
+ 9: 57,
+ SEMICOLON: 59,
+ EQUALS: 61,
+ A: 65,
+ B: 66,
+ C: 67,
+ D: 68,
+ E: 69,
+ F: 70,
+ G: 71,
+ H: 72,
+ I: 73,
+ J: 74,
+ K: 75,
+ L: 76,
+ M: 77,
+ N: 78,
+ O: 79,
+ P: 80,
+ Q: 81,
+ R: 82,
+ S: 83,
+ T: 84,
+ U: 85,
+ V: 86,
+ W: 87,
+ X: 88,
+ Y: 89,
+ Z: 90,
+ CONTEXT_MENU: 93,
+ NUMPAD0: 96,
+ NUMPAD1: 97,
+ NUMPAD2: 98,
+ NUMPAD3: 99,
+ NUMPAD4: 100,
+ NUMPAD5: 101,
+ NUMPAD6: 102,
+ NUMPAD7: 103,
+ NUMPAD8: 104,
+ NUMPAD9: 105,
+ MULTIPLY: 106,
+ ADD: 107,
+ SEPARATOR: 108,
+ SUBTRACT: 109,
+ DECIMAL: 110,
+ DIVIDE: 111,
+ F1: 112,
+ F2: 113,
+ F3: 114,
+ F4: 115,
+ F5: 116,
+ F6: 117,
+ F7: 118,
+ F8: 119,
+ F9: 120,
+ F10: 121,
+ F11: 122,
+ F12: 123,
+ F13: 124,
+ F14: 125,
+ F15: 126,
+ F16: 127,
+ F17: 128,
+ F18: 129,
+ F19: 130,
+ F20: 131,
+ F21: 132,
+ F22: 133,
+ F23: 134,
+ F24: 135,
+ NUM_LOCK: 144,
+ SCROLL_LOCK: 145,
+ COMMA: 188,
+ PERIOD: 190,
+ SLASH: 191,
+ BACK_QUOTE: 192,
+ OPEN_BRACKET: 219,
+ BACK_SLASH: 220,
+ CLOSE_BRACKET: 221,
+ QUOTE: 222,
+ META: 224
+};
+export let MouseCodes = {
+ LEFT: 0,
+ RIGHT: 1,
+ MIDDLE: 2
+};
diff --git a/src/framework/package.json b/src/framework/package.json
new file mode 100644
index 0000000..f3248d1
--- /dev/null
+++ b/src/framework/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "audiogame-tools",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "lint": "eslint . --ext .ts",
+ "format": "prettier --config .prettierrc engine/**/*.ts --write",
+ "compile:engine": "tsc",
+ "watch:engine": "tsc -w",
+ "bundle:engine": "webpack --config webpack.engine.js"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "eventemitter3": "^4.0.7",
+ "yaml": "^1.10.0"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.12.3",
+ "@babel/preset-env": "^7.12.1",
+ "@typescript-eslint/eslint-plugin": "^4.7.0",
+ "@typescript-eslint/parser": "^4.7.0",
+ "eslint": "^7.13.0",
+ "prettier": "^2.1.2",
+ "ts-loader": "^8.0.11",
+ "typescript": "^4.0.5",
+ "webpack": "^5.4.0",
+ "webpack-cli": "^4.2.0"
+ }
+}
diff --git a/src/framework/physics/aabb.d.ts b/src/framework/physics/aabb.d.ts
new file mode 100644
index 0000000..31fa46c
--- /dev/null
+++ b/src/framework/physics/aabb.d.ts
@@ -0,0 +1,2 @@
+import { PhysicsObject } from './object';
+export declare function AABB(obj1: PhysicsObject, obj2: PhysicsObject): boolean;
diff --git a/src/framework/physics/aabb.js b/src/framework/physics/aabb.js
new file mode 100644
index 0000000..d9c5ab0
--- /dev/null
+++ b/src/framework/physics/aabb.js
@@ -0,0 +1,17 @@
+export function AABB(obj1, obj2) {
+ if (checkOverlap(obj1.position.x, obj1.dimensions.x, obj2.position.x, obj2.dimensions.x)) {
+ return true;
+ }
+ else if (checkOverlap(obj1.position.y, obj1.dimensions.y, obj2.position.y, obj2.dimensions.y)) {
+ return true;
+ }
+ else if (checkOverlap(obj1.position.z, obj1.dimensions.z, obj2.position.z, obj2.dimensions.z)) {
+ return true;
+ }
+ return false;
+}
+function checkOverlap(x, w, yx, yw) {
+ if (x > yx || x < yx + yw || x + w > x || x + w < yx + yw) {
+ return true;
+ }
+}
diff --git a/src/framework/physics/index.d.ts b/src/framework/physics/index.d.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/framework/physics/index.js b/src/framework/physics/index.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/framework/physics/object.d.ts b/src/framework/physics/object.d.ts
new file mode 100644
index 0000000..564fa43
--- /dev/null
+++ b/src/framework/physics/object.d.ts
@@ -0,0 +1,7 @@
+import { Vec3 } from './vec3';
+export declare class PhysicsObject {
+ position: Vec3;
+ dimensions: Vec3;
+ velocity: Vec3;
+ affectedByGravity: boolean;
+}
diff --git a/src/framework/physics/object.js b/src/framework/physics/object.js
new file mode 100644
index 0000000..01da65f
--- /dev/null
+++ b/src/framework/physics/object.js
@@ -0,0 +1,2 @@
+export class PhysicsObject {
+}
diff --git a/src/framework/physics/octree.d.ts b/src/framework/physics/octree.d.ts
new file mode 100644
index 0000000..7da8ee5
--- /dev/null
+++ b/src/framework/physics/octree.d.ts
@@ -0,0 +1,39 @@
+import { PhysicsObject } from './object';
+import { Vec3 } from './vec3';
+export declare class Octree {
+ private dimensions;
+ private maxObjects;
+ private maxLevels;
+ root: OcTreeNode;
+ constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number);
+ insert(obj: PhysicsObject): void;
+ find(position: Vec3, dimensions: Vec3): PhysicsObject[];
+}
+export declare class OcTreeNode {
+ private position;
+ private dimensions;
+ private maxLevels;
+ private maxObjects;
+ private currentLevel;
+ objects: PhysicsObject[];
+ nodes: OcTreeNode[];
+ constructor(position: Vec3, dimensions: Vec3, maxLevels: number, maxObjects: number, currentLevel?: number);
+ insert(obj: PhysicsObject): any;
+ find(x: number, y: number, z: number, xw: number, yh: number, zd: number): PhysicsObject[];
+ split(): void;
+ private distributeObjectsToNodes;
+ getIndex(x: number, y: number, z: number): Direction;
+ getIndeciesForRect(x: number, y: number, z: number, xw: number, yh: number, zd: number): Direction[];
+}
+declare enum Direction {
+ AboveUpperLeft = 0,
+ AboveUpperRight = 1,
+ AboveLowerRight = 2,
+ AboveLowerLeft = 3,
+ BelowUpperLeft = 4,
+ BelowUpperRight = 5,
+ BelowLowerRight = 6,
+ BelowLowerLeft = 7,
+ Here = 8
+}
+export {};
diff --git a/src/framework/physics/octree.js b/src/framework/physics/octree.js
new file mode 100644
index 0000000..8e1c511
--- /dev/null
+++ b/src/framework/physics/octree.js
@@ -0,0 +1,206 @@
+import { Vec3 } from './vec3';
+export class Octree {
+ constructor(dimensions, maxObjects = 10, maxLevels = 10) {
+ this.dimensions = dimensions;
+ this.maxObjects = maxObjects;
+ this.maxLevels = maxLevels;
+ this.root = new OcTreeNode(new Vec3({
+ x: 0,
+ y: 0,
+ z: 0
+ }), this.dimensions, maxLevels, maxObjects, 0);
+ }
+ insert(obj) {
+ this.root.insert(obj);
+ }
+ find(position, dimensions) {
+ return this.root.find(position.x, position.y, position.z, dimensions.x, dimensions.y, dimensions.z);
+ }
+}
+export class OcTreeNode {
+ constructor(position, dimensions, maxLevels, maxObjects, currentLevel = 0) {
+ this.position = position;
+ this.dimensions = dimensions;
+ this.maxLevels = maxLevels;
+ this.maxObjects = maxObjects;
+ this.currentLevel = currentLevel;
+ this.objects = [];
+ this.nodes = [];
+ }
+ insert(obj) {
+ const index = this.getIndex(obj.position.x, obj.position.y, obj.position.z);
+ if (index === Direction.Here) {
+ this.objects.push(obj);
+ }
+ else {
+ return this.nodes[index].insert(obj);
+ }
+ if (this.objects.length > this.maxObjects &&
+ this.currentLevel < this.maxLevels) {
+ this.split();
+ }
+ }
+ find(x, y, z, xw, yh, zd) {
+ if (this.nodes.length < 1) {
+ return this.objects;
+ }
+ const indecies = this.getIndeciesForRect(x, y, z, xw, yh, zd);
+ let results = [];
+ for (let i = 0; i < indecies.length - 1; i++) {
+ let res = this.nodes[indecies[i]].find(x, y, z, xw, yh, zd);
+ results.push([...res]);
+ }
+ return results;
+ }
+ split() {
+ const halfWidth = this.dimensions.x / 2;
+ const halfHeight = this.dimensions.y / 2;
+ const halfDepth = this.dimensions.z / 2;
+ this.nodes[Direction.AboveUpperLeft] = new OcTreeNode(new Vec3({
+ x: this.position.x,
+ y: this.position.y,
+ z: this.position.z + halfDepth
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects, this.currentLevel++);
+ this.nodes[Direction.AboveUpperRight] = new OcTreeNode(new Vec3({
+ x: this.position.x + halfWidth,
+ y: this.position.y,
+ z: this.position.z + halfDepth
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects, this.currentLevel++);
+ this.nodes[Direction.AboveLowerRight] = new OcTreeNode(new Vec3({
+ x: this.position.x + halfWidth,
+ y: this.position.y + halfHeight,
+ z: this.position.z + halfDepth
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects, this.currentLevel++);
+ this.nodes[Direction.AboveLowerLeft] = new OcTreeNode(new Vec3({
+ x: this.position.x,
+ y: this.position.y + halfHeight,
+ z: this.position.z + halfDepth
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects, this.currentLevel++);
+ this.nodes[Direction.BelowUpperLeft] = new OcTreeNode(new Vec3({
+ x: this.position.x,
+ y: this.position.y,
+ z: this.position.z
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects, this.currentLevel++);
+ this.nodes[Direction.BelowUpperRight] = new OcTreeNode(new Vec3({
+ x: this.position.x + halfWidth,
+ y: this.position.y,
+ z: this.position.z
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects, this.currentLevel++);
+ this.nodes[Direction.BelowLowerRight] = new OcTreeNode(new Vec3({
+ x: this.position.x + halfWidth,
+ y: this.position.y + halfHeight,
+ z: this.position.z
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects, this.currentLevel++);
+ this.nodes[Direction.BelowLowerLeft] = new OcTreeNode(new Vec3({
+ x: this.position.x,
+ y: this.position.y + halfHeight,
+ z: this.position.z
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects, this.currentLevel++);
+ this.distributeObjectsToNodes();
+ }
+ distributeObjectsToNodes() {
+ if (this.nodes.length < 8) {
+ this.split();
+ return;
+ }
+ this.objects.forEach((obj) => {
+ const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z);
+ this.nodes[direction].insert(obj);
+ });
+ this.objects = [];
+ }
+ getIndex(x, y, z) {
+ if (this.nodes.length === 0) {
+ return Direction.Here;
+ }
+ const halfWidth = this.dimensions.x / 2;
+ const halfHeight = this.dimensions.y / 2;
+ const halfDepth = this.dimensions.z / 2;
+ const isBelow = z < this.position.z + halfDepth;
+ const isLeft = x < this.position.x + halfWidth;
+ const isUpper = y > this.position.y + halfHeight;
+ if (isBelow) {
+ if (isLeft) {
+ if (isUpper)
+ return Direction.AboveUpperLeft;
+ else
+ return Direction.AboveLowerLeft;
+ }
+ else {
+ if (isUpper)
+ return Direction.AboveUpperRight;
+ else
+ return Direction.AboveLowerRight;
+ }
+ }
+ else {
+ if (isLeft) {
+ if (isUpper)
+ return Direction.BelowUpperLeft;
+ else
+ return Direction.BelowLowerLeft;
+ }
+ else {
+ if (isUpper)
+ return Direction.BelowUpperRight;
+ else
+ return Direction.BelowLowerRight;
+ }
+ }
+ }
+ getIndeciesForRect(x, y, z, xw, yh, zd) {
+ if (!(x > this.position.x && x < this.position.x + this.dimensions.x) ||
+ !(y > this.position.y && y < this.position.y + this.dimensions.y) ||
+ !(z > this.position.z && z < this.position.z + this.dimensions.z)) {
+ return [];
+ }
+ let indecies = [];
+ indecies.push(this.getIndex(x, y, z));
+ indecies.push(this.getIndex(x + xw, y + yh, z + zd));
+ return indecies;
+ }
+}
+var Direction;
+(function (Direction) {
+ Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft";
+ Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight";
+ Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight";
+ Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft";
+ Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft";
+ Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight";
+ Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight";
+ Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft";
+ Direction[Direction["Here"] = 8] = "Here";
+})(Direction || (Direction = {}));
diff --git a/src/framework/physics/octtree.d.ts b/src/framework/physics/octtree.d.ts
new file mode 100644
index 0000000..17b248d
--- /dev/null
+++ b/src/framework/physics/octtree.d.ts
@@ -0,0 +1,38 @@
+import { PhysicsObject } from "./object";
+import { Vec3 } from "./vec3";
+export declare class Octtree {
+ private dimensions;
+ private maxObjects;
+ private maxLevels;
+ root: OctTreeNode;
+ constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number);
+ insert(obj: PhysicsObject): void;
+ find(position: Vec3, dimensions: Vec3): PhysicsObject[];
+}
+export declare class OctTreeNode {
+ private position;
+ private dimensions;
+ private maxLevels;
+ private maxObjects;
+ objects: PhysicsObject[];
+ nodes: OctTreeNode[];
+ constructor(position: Vec3, dimensions: Vec3, maxLevels: number, maxObjects: number);
+ insert(obj: PhysicsObject): void;
+ find(position: Vec3, dimensions: Vec3): PhysicsObject[];
+ split(): void;
+ private distributeObjectsToNodes;
+ getIndex(x: number, y: number, z: number): Direction;
+ getIndeciesForRect(position: Vec3, dimensions: Vec3): Set;
+}
+declare enum Direction {
+ AboveUpperLeft = 0,
+ AboveUpperRight = 1,
+ AboveLowerRight = 2,
+ AboveLowerLeft = 3,
+ BelowUpperLeft = 4,
+ BelowUpperRight = 5,
+ BelowLowerRight = 6,
+ BelowLowerLeft = 7,
+ Here = 8
+}
+export {};
diff --git a/src/framework/physics/octtree.js b/src/framework/physics/octtree.js
new file mode 100644
index 0000000..46feed5
--- /dev/null
+++ b/src/framework/physics/octtree.js
@@ -0,0 +1,193 @@
+import { Vec3 } from "./vec3";
+export class Octtree {
+ constructor(dimensions, maxObjects = 10, maxLevels = 10) {
+ this.dimensions = dimensions;
+ this.maxObjects = maxObjects;
+ this.maxLevels = maxLevels;
+ this.root = new OctTreeNode(new Vec3({
+ x: 0,
+ y: 0,
+ z: 0
+ }), this.dimensions, maxLevels, maxObjects);
+ }
+ insert(obj) {
+ this.root.insert(obj);
+ }
+ find(position, dimensions) {
+ return this.root.find(position, dimensions);
+ }
+}
+export class OctTreeNode {
+ constructor(position, dimensions, maxLevels, maxObjects) {
+ this.position = position;
+ this.dimensions = dimensions;
+ this.maxLevels = maxLevels;
+ this.maxObjects = maxObjects;
+ this.objects = [];
+ this.nodes = [];
+ }
+ insert(obj) {
+ this.objects.push(obj);
+ if (this.objects.length > this.maxObjects) {
+ this.split();
+ }
+ }
+ find(position, dimensions) {
+ if (!this.nodes.length) {
+ return this.objects;
+ }
+ const indecies = this.getIndeciesForRect(position, dimensions);
+ let results = [];
+ indecies.forEach((index) => {
+ let res = this.nodes[index].find(position, dimensions);
+ res.forEach((obj) => results.push(obj));
+ });
+ return results;
+ }
+ split() {
+ const halfWidth = this.dimensions.x / 2;
+ const halfHeight = this.dimensions.y / 2;
+ const halfDepth = this.dimensions.z / 2;
+ this.nodes[Direction.AboveUpperLeft] = new OctTreeNode(new Vec3({
+ x: this.position.x,
+ y: this.position.y,
+ z: this.position.z + halfDepth
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects);
+ this.nodes[Direction.AboveUpperRight] = new OctTreeNode(new Vec3({
+ x: this.position.x + halfWidth,
+ y: this.position.y,
+ z: this.position.z + halfDepth
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects);
+ this.nodes[Direction.AboveLowerRight] = new OctTreeNode(new Vec3({
+ x: this.position.x + halfWidth,
+ y: this.position.y + halfHeight,
+ z: this.position.z + halfDepth
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects);
+ this.nodes[Direction.AboveLowerLeft] = new OctTreeNode(new Vec3({
+ x: this.position.x,
+ y: this.position.y + halfHeight,
+ z: this.position.z + halfDepth
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects);
+ this.nodes[Direction.BelowUpperLeft] = new OctTreeNode(new Vec3({
+ x: this.position.x,
+ y: this.position.y,
+ z: this.position.z
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects);
+ this.nodes[Direction.BelowUpperRight] = new OctTreeNode(new Vec3({
+ x: this.position.x + halfWidth,
+ y: this.position.y,
+ z: this.position.z
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects);
+ this.nodes[Direction.BelowLowerRight] = new OctTreeNode(new Vec3({
+ x: this.position.x + halfWidth,
+ y: this.position.y + halfHeight,
+ z: this.position.z
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects);
+ this.nodes[Direction.BelowLowerLeft] = new OctTreeNode(new Vec3({
+ x: this.position.x,
+ y: this.position.y + halfHeight,
+ z: this.position.z
+ }), new Vec3({
+ x: halfWidth,
+ y: halfHeight,
+ z: halfDepth
+ }), this.maxLevels, this.maxObjects);
+ this.distributeObjectsToNodes();
+ }
+ distributeObjectsToNodes() {
+ if (this.nodes.length < 8) {
+ this.split();
+ return;
+ }
+ this.objects.forEach((obj) => {
+ const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z);
+ this.nodes[direction].insert(obj);
+ });
+ this.objects = [];
+ }
+ getIndex(x, y, z) {
+ if (this.nodes.length === 0) {
+ return Direction.Here;
+ }
+ const halfWidth = this.dimensions.x / 2;
+ const halfHeight = this.dimensions.y / 2;
+ const halfDepth = this.dimensions.z / 2;
+ const isBelow = (z < this.position.z + halfDepth);
+ const isLeft = (x < this.position.x + halfWidth);
+ const isUpper = (y > this.position.y + halfHeight);
+ if (isBelow) {
+ if (isLeft) {
+ if (isUpper)
+ return Direction.AboveUpperLeft;
+ else
+ return Direction.AboveLowerLeft;
+ }
+ else {
+ if (isUpper)
+ return Direction.AboveUpperRight;
+ else
+ return Direction.AboveLowerRight;
+ }
+ }
+ else {
+ if (isLeft) {
+ if (isUpper)
+ return Direction.BelowUpperLeft;
+ else
+ return Direction.BelowLowerLeft;
+ }
+ else {
+ if (isUpper)
+ return Direction.BelowUpperRight;
+ else
+ return Direction.BelowLowerRight;
+ }
+ }
+ }
+ getIndeciesForRect(position, dimensions) {
+ let indecies = new Set();
+ indecies.add(this.getIndex(position.x, position.y, position.z));
+ indecies.add(this.getIndex(position.x + dimensions.x, position.y + dimensions.y, position.z + dimensions.z));
+ return indecies;
+ }
+}
+var Direction;
+(function (Direction) {
+ Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft";
+ Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight";
+ Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight";
+ Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft";
+ Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft";
+ Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight";
+ Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight";
+ Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft";
+ Direction[Direction["Here"] = 8] = "Here";
+})(Direction || (Direction = {}));
diff --git a/src/framework/physics/quadtree.d.ts b/src/framework/physics/quadtree.d.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/framework/physics/quadtree.js b/src/framework/physics/quadtree.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/framework/physics/vec3.d.ts b/src/framework/physics/vec3.d.ts
new file mode 100644
index 0000000..f7f50a3
--- /dev/null
+++ b/src/framework/physics/vec3.d.ts
@@ -0,0 +1,13 @@
+export declare class Vec3 {
+ x: number;
+ y: number;
+ z: number;
+ constructor(values?: {
+ x: number;
+ y: number;
+ z: number;
+ });
+ add(vector: Vec3): void;
+ multiply(vector: Vec3): void;
+ clone(): Vec3;
+}
diff --git a/src/framework/physics/vec3.js b/src/framework/physics/vec3.js
new file mode 100644
index 0000000..abcc389
--- /dev/null
+++ b/src/framework/physics/vec3.js
@@ -0,0 +1,28 @@
+export class Vec3 {
+ constructor(values = {
+ x: 0,
+ y: 0,
+ z: 0
+ }) {
+ this.x = values.x;
+ this.y = values.y;
+ this.z = values.z;
+ }
+ add(vector) {
+ this.x += vector.x;
+ this.y += vector.y;
+ this.z += vector.z;
+ }
+ multiply(vector) {
+ this.x *= vector.x;
+ this.y *= vector.y;
+ this.z *= vector.z;
+ }
+ clone() {
+ return new Vec3({
+ x: this.x,
+ y: this.y,
+ z: this.z
+ });
+ }
+}
diff --git a/src/framework/physics/world.d.ts b/src/framework/physics/world.d.ts
new file mode 100644
index 0000000..4366f98
--- /dev/null
+++ b/src/framework/physics/world.d.ts
@@ -0,0 +1,23 @@
+import { Octree } from './octree';
+import { EventBus } from '../event-bus';
+import { PhysicsObject } from './object';
+import { Vec3 } from './vec3';
+export declare class World extends EventBus {
+ objects: PhysicsObject[];
+ gravity: Vec3;
+ dimensions: Vec3;
+ octreeOptions: OctreeOptions;
+ constructor(dimensions: Vec3, octreeOptions: OctreeOptions);
+ setGravity(grav: Vec3): void;
+ addObject(obj: PhysicsObject): void;
+ removeObject(obj: PhysicsObject): void;
+ step(dt: number): void;
+ checkCollisions(obj: PhysicsObject, octree: Octree): void;
+}
+interface OctreeOptions {
+ position: Vec3;
+ dimensions: Vec3;
+ maxObjects: number;
+ maxLevels: number;
+}
+export {};
diff --git a/src/framework/physics/world.js b/src/framework/physics/world.js
new file mode 100644
index 0000000..445a17c
--- /dev/null
+++ b/src/framework/physics/world.js
@@ -0,0 +1,54 @@
+import { Octree } from './octree';
+import { EventBus } from '../event-bus';
+import { Vec3 } from './vec3';
+import { AABB } from './aabb';
+export class World extends EventBus {
+ constructor(dimensions, octreeOptions) {
+ super();
+ if (!octreeOptions) {
+ this.octreeOptions = {
+ position: new Vec3({ x: 0, y: 0, z: 0 }),
+ dimensions: new Vec3(this.dimensions),
+ maxLevels: 50,
+ maxObjects: 50
+ };
+ }
+ else {
+ this.octreeOptions = octreeOptions;
+ }
+ this.dimensions = dimensions;
+ this.objects = [];
+ }
+ setGravity(grav) {
+ this.gravity = grav;
+ }
+ addObject(obj) {
+ this.objects.push(obj);
+ }
+ removeObject(obj) {
+ this.objects = this.objects.filter((val) => val !== obj);
+ }
+ step(dt) {
+ const octree = new Octree(this.octreeOptions.dimensions, this.octreeOptions.maxObjects, this.octreeOptions.maxLevels);
+ this.objects.forEach((obj) => octree.insert(obj));
+ this.objects.forEach((obj) => {
+ let velocity = obj.velocity.clone();
+ velocity.multiply(new Vec3({ x: dt, y: dt, z: dt }));
+ let gravity = this.gravity.clone();
+ gravity.multiply(new Vec3({ x: dt, y: dt, z: dt }));
+ obj.position.add(velocity);
+ if (obj.affectedByGravity) {
+ obj.velocity.add(gravity);
+ }
+ this.checkCollisions(obj, octree);
+ });
+ }
+ checkCollisions(obj, octree) {
+ const potentialCandidates = octree.find(obj.position, obj.dimensions);
+ potentialCandidates.forEach((candidate) => {
+ if (AABB(obj, candidate)) {
+ this.emit('collision', [obj, candidate]);
+ }
+ });
+ }
+}
diff --git a/src/framework/resonator/audio-context.d.ts b/src/framework/resonator/audio-context.d.ts
new file mode 100644
index 0000000..b88251b
--- /dev/null
+++ b/src/framework/resonator/audio-context.d.ts
@@ -0,0 +1,11 @@
+export default class ResonatorAudioContext {
+ private context;
+ constructor();
+ getContext(): AudioContext;
+ createGain(): any;
+ getOutputDestination(): AudioNode;
+ createBufferSource(): AudioBufferSourceNode;
+ decodeAudioData(data: ArrayBuffer): Promise;
+ createPanner(): any;
+ createMediaElementSource(element: HTMLMediaElement): MediaElementAudioSourceNode;
+}
diff --git a/src/framework/resonator/audio-context.js b/src/framework/resonator/audio-context.js
new file mode 100644
index 0000000..fbe0d3b
--- /dev/null
+++ b/src/framework/resonator/audio-context.js
@@ -0,0 +1,39 @@
+// simple wrapper around the AudioContext
+// eventually will be used to deal with cross browser issues
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+export default class ResonatorAudioContext {
+ constructor() {
+ this.context = new AudioContext();
+ }
+ getContext() {
+ return this.context;
+ }
+ createGain() {
+ return this.context.createGain();
+ }
+ getOutputDestination() {
+ return this.context.destination;
+ }
+ createBufferSource() {
+ return this.context.createBufferSource();
+ }
+ decodeAudioData(data) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return yield this.context.decodeAudioData(data);
+ });
+ }
+ createPanner() {
+ return this.context.createPanner();
+ }
+ createMediaElementSource(element) {
+ return this.context.createMediaElementSource(element);
+ }
+}
diff --git a/src/framework/resonator/audio-graph.d.ts b/src/framework/resonator/audio-graph.d.ts
new file mode 100644
index 0000000..22bef61
--- /dev/null
+++ b/src/framework/resonator/audio-graph.d.ts
@@ -0,0 +1,21 @@
+import ResonatorScene from './scenes/webaudio-scene';
+import ResonatorAudioContext from './audio-context';
+import BaseEffect from './effects/base-effect';
+export default class AudioGraph {
+ private master;
+ private effectsBus;
+ private worldBus;
+ private secondaryBus;
+ private effects;
+ private scene;
+ private context;
+ private swapChannels;
+ private channelSplitter;
+ private channelMerger;
+ constructor(scene: ResonatorScene, context: ResonatorAudioContext, swapChannels?: boolean);
+ init(): void;
+ connectToMaster(input: any): void;
+ connectToUI(input: AudioNode): void;
+ applyEffect(effect: BaseEffect): void;
+ removeEffect(effect: BaseEffect): void;
+}
diff --git a/src/framework/resonator/audio-graph.js b/src/framework/resonator/audio-graph.js
new file mode 100644
index 0000000..2d72be1
--- /dev/null
+++ b/src/framework/resonator/audio-graph.js
@@ -0,0 +1,46 @@
+// this is the mixer that takes all the different outputs and mixes them into the 2 busses:
+// WorldBus: The directional audio
+// SecondaryBus: All the UI and things that are non directional
+import EffectChain from './effect-chain';
+export default class AudioGraph {
+ constructor(scene, context, swapChannels = false) {
+ this.scene = scene;
+ this.context = context;
+ this.swapChannels = swapChannels;
+ this.init();
+ }
+ init() {
+ this.effectsBus = this.context.createGain();
+ this.worldBus = this.context.createGain();
+ this.secondaryBus = this.context.createGain();
+ this.master = this.context.createGain();
+ this.scene.getOutput().connect(this.worldBus);
+ // this.worldBus.connect(this.master);
+ this.worldBus.connect(this.effectsBus);
+ this.effects = new EffectChain(this.context, this, this.effectsBus, this.master);
+ this.secondaryBus.connect(this.master);
+ if (this.swapChannels) {
+ this.channelSplitter = this.context.getContext().createChannelSplitter(2);
+ this.channelMerger = this.context.getContext().createChannelMerger(2);
+ this.master.connect(this.channelSplitter);
+ this.channelSplitter.connect(this.channelMerger, 0, 1);
+ this.channelSplitter.connect(this.channelMerger, 1, 0);
+ this.channelMerger.connect(this.context.getOutputDestination());
+ }
+ else {
+ this.master.connect(this.context.getOutputDestination());
+ }
+ }
+ connectToMaster(input) {
+ input.connect(this.master);
+ }
+ connectToUI(input) {
+ input.connect(this.secondaryBus);
+ }
+ applyEffect(effect) {
+ this.effects.applyEffect(effect);
+ }
+ removeEffect(effect) {
+ this.effects.removeEffect(effect);
+ }
+}
diff --git a/src/framework/resonator/data-pool-item.d.ts b/src/framework/resonator/data-pool-item.d.ts
new file mode 100644
index 0000000..3dd2f4f
--- /dev/null
+++ b/src/framework/resonator/data-pool-item.d.ts
@@ -0,0 +1,12 @@
+export default class DataPoolItem {
+ private name;
+ private data;
+ private decodedData;
+ constructor(name: string, data?: any, decodedData?: any);
+ getData(): any;
+ setData(data: any): void;
+ getDecodedData(): any;
+ setDecodedData(data: any): void;
+ getName(): string;
+ setName(name: string): void;
+}
diff --git a/src/framework/resonator/data-pool-item.js b/src/framework/resonator/data-pool-item.js
new file mode 100644
index 0000000..03b6099
--- /dev/null
+++ b/src/framework/resonator/data-pool-item.js
@@ -0,0 +1,26 @@
+// An item in the data pool
+export default class DataPoolItem {
+ constructor(name, data = null, decodedData = null) {
+ this.name = name;
+ this.data = data;
+ this.decodedData = decodedData;
+ }
+ getData() {
+ return this.data;
+ }
+ setData(data) {
+ this.data = data;
+ }
+ getDecodedData() {
+ return this.decodedData;
+ }
+ setDecodedData(data) {
+ this.decodedData = this.decodedData;
+ }
+ getName() {
+ return this.name;
+ }
+ setName(name) {
+ this.name = name;
+ }
+}
diff --git a/src/framework/resonator/data-pool.d.ts b/src/framework/resonator/data-pool.d.ts
new file mode 100644
index 0000000..6478e98
--- /dev/null
+++ b/src/framework/resonator/data-pool.d.ts
@@ -0,0 +1,12 @@
+import EventEmitter from 'eventemitter3';
+import ResonatorAudioContext from './audio-context';
+import { BaseLoader } from './loaders/base-loader';
+export default class DataPool extends EventEmitter {
+ private loader;
+ private data;
+ private maxData;
+ private context;
+ constructor(context: ResonatorAudioContext, loader?: BaseLoader, maxData?: number);
+ get(path: string): Promise;
+ clear(): void;
+}
diff --git a/src/framework/resonator/data-pool.js b/src/framework/resonator/data-pool.js
new file mode 100644
index 0000000..c8109f8
--- /dev/null
+++ b/src/framework/resonator/data-pool.js
@@ -0,0 +1,48 @@
+// a data pool holds frequently played sounds in memory together with decoded audio data to no longer have to decode them from the cache when loaded again
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+import EventEmitter from 'eventemitter3';
+import DataPoolItem from './data-pool-item';
+import { HTTPLoader } from './loaders/http-loader';
+export default class DataPool extends EventEmitter {
+ constructor(context, loader = new HTTPLoader(), maxData = 512) {
+ super();
+ this.loader = loader;
+ this.data = {};
+ this.maxData = maxData;
+ this.context = context;
+ }
+ get(path) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (this.data[path]) {
+ return this.data[path].getDecodedData();
+ }
+ else {
+ const buffer = yield this.loader.get(path);
+ const decoded = yield this.context.decodeAudioData(buffer);
+ const item = new DataPoolItem(path, buffer, decoded);
+ const length = Object.keys(this.data).length;
+ if (length < this.maxData) {
+ this.data[path] = item;
+ }
+ else {
+ // TODO: figure out a more clever solution than just removing the first loaded data. Like tracking how much certain data is needed and prioritize them.
+ // const paths: string[] = Object.keys(this.data);
+ // delete this.data[paths[0]];
+ this.data[path] = item;
+ }
+ return item.getDecodedData();
+ }
+ });
+ }
+ clear() {
+ this.data = {};
+ }
+}
diff --git a/src/framework/resonator/effect-bus.d.ts b/src/framework/resonator/effect-bus.d.ts
new file mode 100644
index 0000000..c940477
--- /dev/null
+++ b/src/framework/resonator/effect-bus.d.ts
@@ -0,0 +1,8 @@
+import ResonatorAudioContext from './audio-context';
+export default class EffectBus {
+ private context;
+ private inputNode;
+ private channelMerger;
+ constructor(context: ResonatorAudioContext, input: AudioNode, output: AudioNode);
+ connect(node: AudioNode): void;
+}
diff --git a/src/framework/resonator/effect-bus.js b/src/framework/resonator/effect-bus.js
new file mode 100644
index 0000000..48c0fe5
--- /dev/null
+++ b/src/framework/resonator/effect-bus.js
@@ -0,0 +1,12 @@
+// Currently unused, but eventually all the effect stuff will be moved from audio graph to here to make it easier to work on
+export default class EffectBus {
+ constructor(context, input, output) {
+ this.context = context;
+ this.inputNode = input;
+ this.channelMerger = this.context.getContext().createChannelMerger(1);
+ this.inputNode.connect(this.channelMerger);
+ }
+ connect(node) {
+ this.channelMerger.connect(node);
+ }
+}
diff --git a/src/framework/resonator/effect-chain.d.ts b/src/framework/resonator/effect-chain.d.ts
new file mode 100644
index 0000000..7eab8de
--- /dev/null
+++ b/src/framework/resonator/effect-chain.d.ts
@@ -0,0 +1,14 @@
+import ResonatorAudioContext from './audio-context';
+import AudioGraph from './audio-graph';
+import BaseEffect from './effects/base-effect';
+export default class EffectChain {
+ private context;
+ private graph;
+ private effects;
+ private inputNode;
+ private outputNode;
+ constructor(context: ResonatorAudioContext, graph: AudioGraph, input: AudioNode, output: AudioNode);
+ applyEffect(effect: BaseEffect): void;
+ removeEffect(effect: BaseEffect): void;
+ private updateConnections;
+}
diff --git a/src/framework/resonator/effect-chain.js b/src/framework/resonator/effect-chain.js
new file mode 100644
index 0000000..7e61834
--- /dev/null
+++ b/src/framework/resonator/effect-chain.js
@@ -0,0 +1,45 @@
+// A chain of effects that connect to the effect bus
+export default class EffectChain {
+ constructor(context, graph, input, output) {
+ this.effects = [];
+ this.context = context;
+ this.graph = graph;
+ this.inputNode = input;
+ this.outputNode = output;
+ this.updateConnections();
+ }
+ applyEffect(effect) {
+ this.effects.push(effect);
+ this.updateConnections();
+ }
+ removeEffect(effect) {
+ this.effects.forEach((currEffect) => {
+ if (effect === currEffect) {
+ currEffect.disconnect();
+ }
+ });
+ this.effects = this.effects.filter((currEffect) => effect !== currEffect);
+ this.updateConnections();
+ }
+ updateConnections() {
+ if (this.effects.length == 0) {
+ this.inputNode.connect(this.outputNode);
+ return;
+ }
+ let current = null;
+ let previous = null;
+ this.effects.forEach((effect) => {
+ current = effect;
+ if (previous) {
+ current.connectInput(previous.getOutput());
+ }
+ else {
+ current.connectInput(this.inputNode);
+ }
+ previous = current;
+ });
+ if (current) {
+ current.connectOutput(this.outputNode);
+ }
+ }
+}
diff --git a/src/framework/resonator/effects/base-effect.d.ts b/src/framework/resonator/effects/base-effect.d.ts
new file mode 100644
index 0000000..3a163ff
--- /dev/null
+++ b/src/framework/resonator/effects/base-effect.d.ts
@@ -0,0 +1,15 @@
+import ResonatorAudioContext from '../audio-context';
+import AudioGraph from '../audio-graph';
+export default class BaseEffect {
+ protected ready: boolean;
+ protected effectNode: any;
+ protected effectParams: any;
+ protected context: ResonatorAudioContext;
+ protected graph: AudioGraph;
+ protected inputNode: AudioNode;
+ constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any);
+ connectOutput(node: AudioNode): void;
+ connectInput(node: AudioNode): void;
+ getOutput(): AudioNode;
+ disconnect(): void;
+}
diff --git a/src/framework/resonator/effects/base-effect.js b/src/framework/resonator/effects/base-effect.js
new file mode 100644
index 0000000..2622e95
--- /dev/null
+++ b/src/framework/resonator/effects/base-effect.js
@@ -0,0 +1,23 @@
+export default class BaseEffect {
+ constructor(context, graph, params) {
+ this.graph = graph;
+ this.context = context;
+ this.effectParams = params;
+ }
+ connectOutput(node) {
+ this.effectNode.connect(node);
+ }
+ connectInput(node) {
+ this.inputNode = node;
+ if (this.effectNode) {
+ this.inputNode.connect(this.effectNode);
+ }
+ }
+ getOutput() {
+ return this.effectNode;
+ }
+ disconnect() {
+ this.inputNode.disconnect();
+ this.effectNode.disconnect();
+ }
+}
diff --git a/src/framework/resonator/effects/convolver.d.ts b/src/framework/resonator/effects/convolver.d.ts
new file mode 100644
index 0000000..b61a265
--- /dev/null
+++ b/src/framework/resonator/effects/convolver.d.ts
@@ -0,0 +1,10 @@
+import BaseEffect from './base-effect';
+import ResonatorAudioContext from '../audio-context';
+import AudioGraph from '../audio-graph';
+export default class Convolver extends BaseEffect {
+ private buffer;
+ private channelSplitter;
+ private channelMerger;
+ constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any);
+ connectInput(node: AudioNode): void;
+}
diff --git a/src/framework/resonator/effects/convolver.js b/src/framework/resonator/effects/convolver.js
new file mode 100644
index 0000000..b36cbec
--- /dev/null
+++ b/src/framework/resonator/effects/convolver.js
@@ -0,0 +1,19 @@
+import BaseEffect from './base-effect';
+export default class Convolver extends BaseEffect {
+ constructor(context, graph, params) {
+ super(context, graph, params);
+ console.log(`Creating convolver`);
+ this.effectNode = this.context.getContext().createConvolver();
+ this.effectNode.buffer = this.effectParams.buffer;
+ }
+ connectInput(node) {
+ this.channelSplitter = this.context.getContext().createChannelSplitter(2);
+ this.channelMerger = this.context.getContext().createChannelMerger(2);
+ this.channelSplitter.connect(this.channelMerger, 0, 0);
+ this.channelSplitter.connect(this.channelMerger, 1, 0);
+ this.channelSplitter.connect(this.channelMerger, 0, 1);
+ this.channelSplitter.connect(this.channelMerger, 1, 1);
+ node.connect(this.channelSplitter);
+ this.channelMerger.connect(this.effectNode);
+ }
+}
diff --git a/src/framework/resonator/index.d.ts b/src/framework/resonator/index.d.ts
new file mode 100644
index 0000000..7de5ff4
--- /dev/null
+++ b/src/framework/resonator/index.d.ts
@@ -0,0 +1,22 @@
+import AudioSource from './sources/audio-source';
+import { BaseLoader } from './loaders/base-loader';
+import { BaseSource } from './sources/base-source';
+import { SourceType } from './sources/source-type';
+import { StreamingSource } from './sources/streaming-source';
+export default class Resonator {
+ private loader;
+ private context;
+ private scene;
+ private graph;
+ private dataPool;
+ private environmentImpulse;
+ constructor(loader?: BaseLoader);
+ load(path: string, type?: SourceType): Promise;
+ loadImmediate(path: string, type?: SourceType): AudioSource;
+ stream(path: string, type?: SourceType): StreamingSource;
+ private createSource;
+ setEnvironmentImpulse(file: string): Promise;
+ setListenerPosition(x: number, y: number, z: number): void;
+ setListenerOrientation(forward: any, up: any): void;
+ clearDataPool(): void;
+}
diff --git a/src/framework/resonator/index.js b/src/framework/resonator/index.js
new file mode 100644
index 0000000..0bade61
--- /dev/null
+++ b/src/framework/resonator/index.js
@@ -0,0 +1,77 @@
+// the main module for Resonator
+// API, etc.
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+import ResonatorAudioContext from './audio-context';
+import ResonatorScene from './scenes/webaudio-scene';
+import AudioGraph from './audio-graph';
+import AudioSource from './sources/audio-source';
+import DataPool from './data-pool';
+import Convolver from './effects/convolver';
+import { HTTPLoader } from './loaders/http-loader';
+import { SourceType } from './sources/source-type';
+import { StreamingSource } from './sources/streaming-source';
+export default class Resonator {
+ constructor(loader = new HTTPLoader()) {
+ this.loader = loader;
+ this.environmentImpulse = null;
+ this.context = new ResonatorAudioContext();
+ this.scene = new ResonatorScene(this.context);
+ this.graph = new AudioGraph(this.scene, this.context, false);
+ this.dataPool = new DataPool(this.context, this.loader);
+ }
+ load(path, type = SourceType.WorldSource) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = yield this.dataPool.get(path);
+ const source = this.createSource(type, data);
+ return source;
+ });
+ }
+ loadImmediate(path, type = SourceType.WorldSource) {
+ const source = new AudioSource(this.graph, this.scene, this.context, null, type);
+ this.dataPool.get(path).then((data) => {
+ source.setBuffer(data);
+ });
+ return source;
+ }
+ stream(path, type = SourceType.MasterSource) {
+ const element = new Audio(path);
+ element.crossOrigin = 'anonymous';
+ const source = new StreamingSource(this.graph, this.scene, this.context, element, type);
+ return source;
+ }
+ createSource(type, data) {
+ return new AudioSource(this.graph, this.scene, this.context, data);
+ }
+ setEnvironmentImpulse(file) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (this.environmentImpulse) {
+ this.graph.removeEffect(this.environmentImpulse);
+ }
+ if (file === null) {
+ return;
+ }
+ const buffer = yield this.dataPool.get(file);
+ this.environmentImpulse = new Convolver(this.context, this.graph, {
+ buffer
+ });
+ this.graph.applyEffect(this.environmentImpulse);
+ });
+ }
+ setListenerPosition(x, y, z) {
+ this.scene.setListenerPosition(x, y, z);
+ }
+ setListenerOrientation(forward, up) {
+ this.scene.setListenerOrientation(forward, up);
+ }
+ clearDataPool() {
+ this.dataPool.clear();
+ }
+}
diff --git a/src/framework/resonator/loaders/asset-loader.d.ts b/src/framework/resonator/loaders/asset-loader.d.ts
new file mode 100644
index 0000000..012be16
--- /dev/null
+++ b/src/framework/resonator/loaders/asset-loader.d.ts
@@ -0,0 +1,10 @@
+import { AssetManager } from '../../asset-manager';
+import { BaseLoader } from './base-loader';
+export declare class AssetLoader implements BaseLoader {
+ private name;
+ private manager;
+ private assetManager;
+ constructor(name: string, manager?: AssetManager);
+ init(): Promise;
+ get(path: string): Promise;
+}
diff --git a/src/framework/resonator/loaders/asset-loader.js b/src/framework/resonator/loaders/asset-loader.js
new file mode 100644
index 0000000..4b6920e
--- /dev/null
+++ b/src/framework/resonator/loaders/asset-loader.js
@@ -0,0 +1,36 @@
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+// TODO fix path when actually properly linking the packages together
+import { AssetManager } from '../../asset-manager';
+export class AssetLoader {
+ constructor(name, manager = null) {
+ this.name = name;
+ this.manager = manager;
+ if (manager) {
+ this.assetManager = manager;
+ }
+ else {
+ this.assetManager = new AssetManager(name, '');
+ }
+ }
+ init() {
+ return __awaiter(this, void 0, void 0, function* () {
+ yield this.assetManager.init();
+ });
+ }
+ get(path) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const result = yield this.assetManager.downloadFile(path);
+ console.log(result);
+ const buffer = yield result.arrayBuffer();
+ return buffer;
+ });
+ }
+}
diff --git a/src/framework/resonator/loaders/base-loader.d.ts b/src/framework/resonator/loaders/base-loader.d.ts
new file mode 100644
index 0000000..c586898
--- /dev/null
+++ b/src/framework/resonator/loaders/base-loader.d.ts
@@ -0,0 +1,3 @@
+export interface BaseLoader {
+ get(path: string): Promise;
+}
diff --git a/src/framework/resonator/loaders/base-loader.js b/src/framework/resonator/loaders/base-loader.js
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/src/framework/resonator/loaders/base-loader.js
@@ -0,0 +1 @@
+export {};
diff --git a/src/framework/resonator/loaders/http-loader.d.ts b/src/framework/resonator/loaders/http-loader.d.ts
new file mode 100644
index 0000000..a3ff342
--- /dev/null
+++ b/src/framework/resonator/loaders/http-loader.d.ts
@@ -0,0 +1,4 @@
+import { BaseLoader } from './base-loader';
+export declare class HTTPLoader implements BaseLoader {
+ get(path: string): Promise;
+}
diff --git a/src/framework/resonator/loaders/http-loader.js b/src/framework/resonator/loaders/http-loader.js
new file mode 100644
index 0000000..de67b13
--- /dev/null
+++ b/src/framework/resonator/loaders/http-loader.js
@@ -0,0 +1,18 @@
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+export class HTTPLoader {
+ get(path) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const result = yield fetch(path);
+ const buffer = yield result.arrayBuffer();
+ return buffer;
+ });
+ }
+}
diff --git a/src/framework/resonator/scenes/resonance-scene.d.ts b/src/framework/resonator/scenes/resonance-scene.d.ts
new file mode 100644
index 0000000..967d131
--- /dev/null
+++ b/src/framework/resonator/scenes/resonance-scene.d.ts
@@ -0,0 +1,14 @@
+import ResonatorAudioContext from '../audio-context';
+import EventEmitter from 'eventemitter3';
+export default class Scene extends EventEmitter {
+ scene: any;
+ context: ResonatorAudioContext;
+ listener: AudioListener;
+ constructor(context: ResonatorAudioContext);
+ init(): void;
+ createSource(): any;
+ getOutput(): any;
+ getInput(): any;
+ setListenerPosition(x: number, y: number, z: number): void;
+ setListenerOrientation(forward: any, rawup: any): void;
+}
diff --git a/src/framework/resonator/scenes/resonance-scene.js b/src/framework/resonator/scenes/resonance-scene.js
new file mode 100644
index 0000000..f885e91
--- /dev/null
+++ b/src/framework/resonator/scenes/resonance-scene.js
@@ -0,0 +1,40 @@
+// The code that deals with 3d audio
+import ResonanceAudio from '../vendor/resonance-es6/main';
+import EventEmitter from 'eventemitter3';
+import vec3 from '../../tsm/vec3';
+export default class Scene extends EventEmitter {
+ constructor(context) {
+ super();
+ this.context = context;
+ this.scene = new ResonanceAudio(this.context.getContext(), {
+ ambisonicOrder: 3
+ });
+ this.listener = this.context.getContext().listener;
+ this.init();
+ }
+ init() {
+ // this.scene.output.connect(this.context.getOutputDestination());
+ }
+ createSource() {
+ const source = this.scene.createSource();
+ return Object.assign(Object.assign({}, source), { getInput: () => source.input });
+ }
+ getOutput() {
+ return this.scene.output;
+ }
+ getInput() {
+ return this.scene.input;
+ }
+ setListenerPosition(x, y, z) {
+ this.scene.setListenerPosition(x, y, z);
+ }
+ setListenerOrientation(forward, rawup) {
+ let fwd = new vec3([forward.x, forward.y, forward.z]);
+ let up = fwd.copy();
+ vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up);
+ vec3.cross(up, fwd, up);
+ fwd.normalize();
+ up.normalize();
+ this.scene.setListenerOrientation(forward.x, forward.y, forward.z, rawup.x, rawup.y, rawup.z);
+ }
+}
diff --git a/src/framework/resonator/scenes/webaudio-scene.d.ts b/src/framework/resonator/scenes/webaudio-scene.d.ts
new file mode 100644
index 0000000..6ae3a1f
--- /dev/null
+++ b/src/framework/resonator/scenes/webaudio-scene.d.ts
@@ -0,0 +1,14 @@
+import ResonatorAudioContext from '../audio-context';
+import EventEmitter from 'eventemitter3';
+export default class ResonatorScene extends EventEmitter {
+ scene: GainNode;
+ context: ResonatorAudioContext;
+ listener: AudioListener;
+ constructor(context: ResonatorAudioContext);
+ init(): void;
+ createSource(): any;
+ getOutput(): any;
+ getInput(): any;
+ setListenerPosition(x: number, y: number, z: number): void;
+ setListenerOrientation(forward: any, rawup: any): void;
+}
diff --git a/src/framework/resonator/scenes/webaudio-scene.js b/src/framework/resonator/scenes/webaudio-scene.js
new file mode 100644
index 0000000..19fb5a4
--- /dev/null
+++ b/src/framework/resonator/scenes/webaudio-scene.js
@@ -0,0 +1,42 @@
+// The code that deals with 3d audio
+import EventEmitter from 'eventemitter3';
+import vec3 from '../../tsm/vec3';
+export default class ResonatorScene extends EventEmitter {
+ constructor(context) {
+ super();
+ this.context = context;
+ this.scene = this.context.getContext().createGain();
+ this.listener = this.context.getContext().listener;
+ this.init();
+ }
+ init() {
+ // this.scene.output.connect(this.context.getOutputDestination());
+ }
+ createSource() {
+ const node = this.context.getContext().createPanner();
+ node.panningModel = 'HRTF';
+ node.distanceModel = 'linear';
+ node.maxDistance = 20;
+ node.refDistance = 2;
+ node.connect(this.scene);
+ return node;
+ }
+ getOutput() {
+ return this.scene;
+ }
+ getInput() {
+ return this.scene;
+ }
+ setListenerPosition(x, y, z) {
+ this.listener.setPosition(x, y, z);
+ }
+ setListenerOrientation(forward, rawup) {
+ let fwd = new vec3([forward.x, forward.y, forward.z]);
+ let up = fwd.copy();
+ vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up);
+ vec3.cross(up, fwd, up);
+ fwd.normalize();
+ up.normalize();
+ this.listener.setOrientation(fwd.x, fwd.y, fwd.z, up.x, up.y, up.z);
+ }
+}
diff --git a/src/framework/resonator/sources/audio-source.d.ts b/src/framework/resonator/sources/audio-source.d.ts
new file mode 100644
index 0000000..66dab95
--- /dev/null
+++ b/src/framework/resonator/sources/audio-source.d.ts
@@ -0,0 +1,35 @@
+import ResonatorAudioContext from '../audio-context';
+import AudioGraph from '../audio-graph';
+import ResonatorScene from '../scenes/webaudio-scene';
+import { BaseSource } from './base-source';
+import { SourceType } from './source-type';
+export default class AudioSource implements BaseSource {
+ playing: boolean;
+ looping: boolean;
+ private node;
+ private sceneNode;
+ private buffer;
+ private context;
+ private graph;
+ private scene;
+ private playOnLoad;
+ private position;
+ private playbackRate;
+ private volume;
+ private gain;
+ private type;
+ constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, buffer?: AudioBuffer, type?: SourceType);
+ init(): void;
+ getBuffer(): AudioBuffer;
+ setBuffer(data: AudioBuffer): void;
+ play(when?: number, offset?: number, duration?: number): void;
+ setPosition(x: number, y: number, z: number): void;
+ setPlaybackRate(rate: number): void;
+ getPlaybackRate(): number;
+ setVolume(volume: number): void;
+ getVolume(): number;
+ private createConnections;
+ stop(): void;
+ destroy(): void;
+ loop(value: boolean): void;
+}
diff --git a/src/framework/resonator/sources/audio-source.js b/src/framework/resonator/sources/audio-source.js
new file mode 100644
index 0000000..3c3c961
--- /dev/null
+++ b/src/framework/resonator/sources/audio-source.js
@@ -0,0 +1,132 @@
+// an audio source
+// This is the actual sound
+import { SourceType } from './source-type';
+export default class AudioSource {
+ constructor(graph, scene, context, buffer = null, type = SourceType.WorldSource) {
+ this.position = {
+ x: 0,
+ y: 0,
+ z: 0
+ };
+ this.buffer = buffer;
+ this.context = context;
+ this.scene = scene;
+ this.graph = graph;
+ this.type = type;
+ this.playbackRate = 1;
+ this.init();
+ }
+ init() {
+ this.gain = this.context.createGain();
+ // bind methods so we can add and removve them from event listeners
+ this.stop = this.stop.bind(this);
+ }
+ getBuffer() {
+ return this.buffer;
+ }
+ setBuffer(data) {
+ this.buffer = data;
+ if (this.playOnLoad) {
+ this.play();
+ this.playOnLoad = false;
+ }
+ }
+ play(when = 0, offset = 0, duration = this.buffer ? this.buffer.duration : 0) {
+ if (this.playing && this.node) {
+ this.stop();
+ }
+ if (!this.buffer) {
+ this.playOnLoad = true;
+ return;
+ }
+ if (!this.node) {
+ this.node = this.context.createBufferSource();
+ this.node.buffer = this.buffer;
+ this.createConnections();
+ }
+ if (this.node) {
+ this.node.playbackRate.value = this.playbackRate;
+ this.node.start(when, offset, duration);
+ this.node.loop = this.looping;
+ this.playing = true;
+ if (this.sceneNode) {
+ this.sceneNode.setPosition(this.position.x, this.position.y, this.position.z);
+ }
+ this.node.addEventListener('ended', this.stop);
+ }
+ }
+ setPosition(x, y, z) {
+ this.position = {
+ x,
+ y,
+ z
+ };
+ if (this.sceneNode)
+ this.sceneNode.setPosition(x, y, z);
+ }
+ setPlaybackRate(rate) {
+ this.playbackRate = rate;
+ if (this.node)
+ this.node.playbackRate.value = rate;
+ }
+ getPlaybackRate() {
+ return this.playbackRate;
+ }
+ setVolume(volume) {
+ this.volume = volume;
+ if (this.gain)
+ this.gain.gain.value = volume;
+ }
+ getVolume() {
+ return this.volume;
+ }
+ createConnections() {
+ switch (this.type) {
+ case SourceType.WorldSource:
+ if (!this.sceneNode) {
+ this.sceneNode = this.scene.createSource();
+ }
+ this.node.connect(this.gain);
+ this.gain.connect(this.sceneNode);
+ break;
+ case SourceType.UISource:
+ this.node.connect(this.gain);
+ this.graph.connectToUI(this.gain);
+ break;
+ default:
+ this.node.connect(this.gain);
+ this.graph.connectToMaster(this.gain);
+ break;
+ }
+ }
+ stop() {
+ this.playing = false;
+ if (this.node) {
+ this.node.removeEventListener('ended', this.stop);
+ this.node.stop();
+ this.node.disconnect();
+ this.node = null;
+ this.playing = false;
+ if (this.sceneNode) {
+ this.sceneNode.disconnect();
+ this.sceneNode = null;
+ }
+ }
+ }
+ destroy() {
+ this.stop();
+ // set all refs to null to encourage gc
+ this.node = null;
+ this.sceneNode = null;
+ this.buffer = null;
+ this.context = null;
+ this.graph = null;
+ this.scene = null;
+ }
+ loop(value) {
+ this.looping = value;
+ if (this.node) {
+ this.node.loop = value;
+ }
+ }
+}
diff --git a/src/framework/resonator/sources/base-source.d.ts b/src/framework/resonator/sources/base-source.d.ts
new file mode 100644
index 0000000..a1615fc
--- /dev/null
+++ b/src/framework/resonator/sources/base-source.d.ts
@@ -0,0 +1,10 @@
+export interface BaseSource {
+ play(when: number, offset: number, duration: number): void;
+ stop(): void;
+ setPlaybackRate(value: number): void;
+ getPlaybackRate(): number;
+ setVolume(value: number): void;
+ getVolume(): number;
+ loop(value: boolean): void;
+ destroy(): void;
+}
diff --git a/src/framework/resonator/sources/base-source.js b/src/framework/resonator/sources/base-source.js
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/src/framework/resonator/sources/base-source.js
@@ -0,0 +1 @@
+export {};
diff --git a/src/framework/resonator/sources/source-type.d.ts b/src/framework/resonator/sources/source-type.d.ts
new file mode 100644
index 0000000..c0304b1
--- /dev/null
+++ b/src/framework/resonator/sources/source-type.d.ts
@@ -0,0 +1,5 @@
+export declare enum SourceType {
+ WorldSource = 0,
+ UISource = 1,
+ MasterSource = 2
+}
diff --git a/src/framework/resonator/sources/source-type.js b/src/framework/resonator/sources/source-type.js
new file mode 100644
index 0000000..2d58552
--- /dev/null
+++ b/src/framework/resonator/sources/source-type.js
@@ -0,0 +1,6 @@
+export var SourceType;
+(function (SourceType) {
+ SourceType[SourceType["WorldSource"] = 0] = "WorldSource";
+ SourceType[SourceType["UISource"] = 1] = "UISource";
+ SourceType[SourceType["MasterSource"] = 2] = "MasterSource";
+})(SourceType || (SourceType = {}));
diff --git a/src/framework/resonator/sources/streaming-source.d.ts b/src/framework/resonator/sources/streaming-source.d.ts
new file mode 100644
index 0000000..7403688
--- /dev/null
+++ b/src/framework/resonator/sources/streaming-source.d.ts
@@ -0,0 +1,30 @@
+import { BaseSource } from './base-source';
+import AudioGraph from '../audio-graph';
+import ResonatorScene from '../scenes/webaudio-scene';
+import ResonatorAudioContext from '../audio-context';
+import { SourceType } from './source-type';
+export declare class StreamingSource implements BaseSource {
+ private graph;
+ private scene;
+ private context;
+ private element;
+ private type;
+ playing: boolean;
+ private playOnAvailable;
+ private node;
+ private canPlay;
+ private sceneNode;
+ private position;
+ constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, element: HTMLAudioElement, type?: SourceType);
+ private init;
+ play(when?: number, offset?: number, duration?: number): void;
+ stop(): void;
+ getVolume(): number;
+ setVolume(value: number): void;
+ getPlaybackRate(): number;
+ setPlaybackRate(value: number): void;
+ private createConnections;
+ setPosition(x: number, y: number, z: number): void;
+ destroy(): void;
+ loop(value: boolean): void;
+}
diff --git a/src/framework/resonator/sources/streaming-source.js b/src/framework/resonator/sources/streaming-source.js
new file mode 100644
index 0000000..7ff3302
--- /dev/null
+++ b/src/framework/resonator/sources/streaming-source.js
@@ -0,0 +1,81 @@
+import { SourceType } from './source-type';
+export class StreamingSource {
+ constructor(graph, scene, context, element, type = SourceType.MasterSource) {
+ this.graph = graph;
+ this.scene = scene;
+ this.context = context;
+ this.element = element;
+ this.type = type;
+ this.position = {
+ x: 0,
+ y: 0,
+ z: 0
+ };
+ this.init();
+ }
+ init() {
+ this.node = this.context.createMediaElementSource(this.element);
+ this.createConnections();
+ this.element.addEventListener('canplay', (event) => {
+ this.canPlay = true;
+ if (this.playOnAvailable) {
+ this.play();
+ }
+ });
+ }
+ play(when = 0, offset = 0, duration = 0) {
+ if (this.canPlay) {
+ this.element.play();
+ }
+ this.playOnAvailable = true;
+ }
+ stop() {
+ this.element.pause();
+ }
+ getVolume() {
+ return this.element.volume;
+ }
+ setVolume(value) {
+ this.element.volume = value;
+ }
+ getPlaybackRate() {
+ return this.element.playbackRate;
+ }
+ setPlaybackRate(value) {
+ this.element.playbackRate = value;
+ }
+ createConnections() {
+ switch (this.type) {
+ case SourceType.WorldSource:
+ if (!this.sceneNode) {
+ this.sceneNode = this.scene.createSource();
+ }
+ this.node.connect(this.sceneNode);
+ break;
+ default:
+ this.graph.connectToMaster(this.node);
+ break;
+ }
+ }
+ setPosition(x, y, z) {
+ this.position = {
+ x,
+ y,
+ z
+ };
+ if (this.sceneNode)
+ this.sceneNode.setPosition(x, y, z);
+ }
+ destroy() {
+ this.stop();
+ this.element = null;
+ this.graph = null;
+ this.context = null;
+ this.node = null;
+ this.sceneNode = null;
+ this.scene = null;
+ }
+ loop(value) {
+ this.element.loop = true;
+ }
+}
diff --git a/src/framework/resonator/vendor/resonance-es6/attenuation.d.ts b/src/framework/resonator/vendor/resonance-es6/attenuation.d.ts
new file mode 100644
index 0000000..e42c1c0
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/attenuation.d.ts
@@ -0,0 +1,40 @@
+export default Attenuation;
+/**
+ * @class Attenuation
+ * @description Distance-based attenuation filter.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Number} options.minDistance
+ * Min. distance (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}.
+ * @param {Number} options.maxDistance
+ * Max. distance (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}.
+ * @param {string} options.rolloff
+ * Rolloff model to use, chosen from options in
+ * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to
+ * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}.
+ */
+declare class Attenuation {
+ constructor(context: any, options: any);
+ minDistance: any;
+ maxDistance: any;
+ _gainNode: any;
+ input: any;
+ output: any;
+ /**
+ * Set distance from the listener.
+ * @param {Number} distance Distance (in meters).
+ */
+ setDistance(distance: number): void;
+ /**
+ * Set rolloff.
+ * @param {string} rolloff
+ * Rolloff model to use, chosen from options in
+ * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}.
+ */
+ setRolloff(rolloff: string): void;
+ _rolloff: string;
+}
diff --git a/src/framework/resonator/vendor/resonance-es6/attenuation.js b/src/framework/resonator/vendor/resonance-es6/attenuation.js
new file mode 100644
index 0000000..abb8584
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/attenuation.js
@@ -0,0 +1,151 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file Distance-based attenuation filter.
+ * @author Andrew Allen
+ */
+'use strict';
+// Internal dependencies.
+import Utils from './utils.js';
+/**
+ * @class Attenuation
+ * @description Distance-based attenuation filter.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Number} options.minDistance
+ * Min. distance (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}.
+ * @param {Number} options.maxDistance
+ * Max. distance (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}.
+ * @param {string} options.rolloff
+ * Rolloff model to use, chosen from options in
+ * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to
+ * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}.
+ */
+class Attenuation {
+ constructor(context, options) {
+ // Public variables.
+ /**
+ * Min. distance (in meters).
+ * @member {Number} minDistance
+ * @memberof Attenuation
+ * @instance
+ */
+ /**
+ * Max. distance (in meters).
+ * @member {Number} maxDistance
+ * @memberof Attenuation
+ * @instance
+ */
+ /**
+ * Mono (1-channel) input {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} input
+ * @memberof Attenuation
+ * @instance
+ */
+ /**
+ * Mono (1-channel) output {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} output
+ * @memberof Attenuation
+ * @instance
+ */
+ // Use defaults for undefined arguments.
+ if (options == undefined) {
+ options = {};
+ }
+ if (options.minDistance == undefined) {
+ options.minDistance = Utils.DEFAULT_MIN_DISTANCE;
+ }
+ if (options.maxDistance == undefined) {
+ options.maxDistance = Utils.DEFAULT_MAX_DISTANCE;
+ }
+ if (options.rolloff == undefined) {
+ options.rolloff = Utils.DEFAULT_ATTENUATION_ROLLOFF;
+ }
+ // Assign values.
+ this.minDistance = options.minDistance;
+ this.maxDistance = options.maxDistance;
+ this.setRolloff(options.rolloff);
+ // Create node.
+ this._gainNode = context.createGain();
+ // Initialize distance to max distance.
+ this.setDistance(options.maxDistance);
+ // Input/Output proxy.
+ this.input = this._gainNode;
+ this.output = this._gainNode;
+ }
+ /**
+ * Set distance from the listener.
+ * @param {Number} distance Distance (in meters).
+ */
+ setDistance(distance) {
+ let gain = 1;
+ if (this._rolloff == 'logarithmic') {
+ if (distance > this.maxDistance) {
+ gain = 0;
+ }
+ else if (distance > this.minDistance) {
+ let range = this.maxDistance - this.minDistance;
+ if (range > Utils.EPSILON_FLOAT) {
+ // Compute the distance attenuation value by the logarithmic curve
+ // "1 / (d + 1)" with an offset of |minDistance|.
+ let relativeDistance = distance - this.minDistance;
+ let attenuation = 1 / (relativeDistance + 1);
+ let attenuationMax = 1 / (range + 1);
+ gain = (attenuation - attenuationMax) / (1 - attenuationMax);
+ }
+ }
+ }
+ else if (this._rolloff == 'linear') {
+ if (distance > this.maxDistance) {
+ gain = 0;
+ }
+ else if (distance > this.minDistance) {
+ let range = this.maxDistance - this.minDistance;
+ if (range > Utils.EPSILON_FLOAT) {
+ gain = (this.maxDistance - distance) / range;
+ }
+ }
+ }
+ this._gainNode.gain.value = gain;
+ }
+ /**
+ * Set rolloff.
+ * @param {string} rolloff
+ * Rolloff model to use, chosen from options in
+ * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}.
+ */
+ setRolloff(rolloff) {
+ let isValidModel = ~Utils.ATTENUATION_ROLLOFFS.indexOf(rolloff);
+ if (rolloff == undefined || !isValidModel) {
+ if (!isValidModel) {
+ Utils.log('Invalid rolloff model (\"' + rolloff +
+ '\"). Using default: \"' + Utils.DEFAULT_ATTENUATION_ROLLOFF + '\".');
+ }
+ rolloff = Utils.DEFAULT_ATTENUATION_ROLLOFF;
+ }
+ else {
+ rolloff = rolloff.toString().toLowerCase();
+ }
+ this._rolloff = rolloff;
+ }
+}
+export default Attenuation;
diff --git a/src/framework/resonator/vendor/resonance-es6/d.d.ts b/src/framework/resonator/vendor/resonance-es6/d.d.ts
new file mode 100644
index 0000000..cba0b49
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/d.d.ts
@@ -0,0 +1,217 @@
+declare module 'resonance-audio' {
+ namespace ResonanceAudio {
+ /** Options for constructing a new ResonanceAudio scene */
+ interface Options {
+ /** Desired ambisonic Order */
+ ambisonicOrder?: number;
+ /** The listener's initial position (in meters), where origin is the center of
+ * the room */
+ listenerPosition?: Float32Array;
+ /** The listener's initial forward vector */
+ listenerForward?: Float32Array;
+ /** The listener's initial up vector */
+ listenerUp?: Float32Array;
+ /** Room dimensions (in meters) */
+ dimensions?: Utils.RoomDimensions;
+ /** Named acoustic materials per wall */
+ materials?: Utils.RoomMaterials;
+ /** (in meters/second) */
+ speedOfSound?: number;
+ }
+ }
+ /** Main class for managing sources, room and listener models */
+ class ResonanceAudio {
+ /** Binaurally-rendered stereo (2-channel) output */
+ output: AudioNode;
+ /** Ambisonic (multichannel) input */
+ ambisonicInput: AudioNode;
+ /** Ambisonic (multichannel) output */
+ ambisonicOutput: AudioNode;
+ constructor(context: AudioContext, options?: ResonanceAudio.Options);
+ /**
+ * Create a new source for the scene.
+ * @param options
+ * Options for constructing a new Source.
+ */
+ createSource(options?: Source.Options): Source;
+ /**
+ * Set the scene's desired ambisonic order.
+ * @param ambisonicOrder Desired ambisonic order.
+ */
+ setAmbisonicOrder(ambisonicOrder: any): void;
+ /**
+ * Set the room's dimensions and wall materials.
+ * @param dimensions Room dimensions (in meters).
+ * @param materials Named acoustic materials per wall.
+ */
+ setRoomProperties(dimensions: Utils.RoomDimensions, materials: Utils.RoomMaterials): void;
+ /**
+ * Set the listener's position (in meters), where origin is the center of
+ * the room.
+ */
+ setListenerPosition(x: number, y: number, z: number): any;
+ /** Set the source's orientation using forward and up vectors. */
+ setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
+ /**
+ * Set the listener's position and orientation using a Three.js Matrix4 object.
+ * @param matrix
+ * The Three.js Matrix4 object representing the listener's world transform.
+ */
+ setListenerFromMatrix(matrix4: Float32Array): void;
+ /**
+ * Set the speed of sound.
+ */
+ setSpeedOfSound(speedOfSound: number): void;
+ }
+ namespace Source {
+ /** Options for constructing a new Source. */
+ interface Options {
+ /** The source's initial position (in meters), where origin is the center of
+ * the room */
+ position?: Float32Array;
+ /** The source's initial forward vector */
+ forward?: Float32Array;
+ /** The source's initial up vector */
+ up?: Float32Array;
+ /** Min. distance (in meters) */
+ minDistance?: number;
+ /** Max. distance (in meters) */
+ maxDistance?: number;
+ /** Rolloff model to use */
+ rolloff?: string;
+ /** Input gain (linear) */
+ gain?: number;
+ /** Directivity alpha */
+ alpha?: number;
+ /** Directivity sharpness */
+ sharpness?: number;
+ /** Source width (in degrees). Where 0 degrees is a point source and 360 degrees
+ * is an omnidirectional source */
+ sourceWidth?: number;
+ }
+ }
+ /**
+ * Source model to spatialize an audio buffer.
+ */
+ class Source {
+ constructor(scene: ResonanceAudio, options?: Source.Options);
+ /** Mono (1-channel) input */
+ input: AudioNode;
+ /**
+ * Set source's position (in meters), where origin is the center of
+ * the room.
+ */
+ setPosition(x: number, y: number, z: number): void;
+ /** Set source's rolloff. */
+ setRolloff(rolloff: string): void;
+ /** Set source's minimum distance (in meters). */
+ setMinDistance(minDistance: number): void;
+ /** Set source's maximum distance (in meters). */
+ setMaxDistance(maxDistance: number): void;
+ /** Set source's gain (linear). */
+ setGain(gain: number): void;
+ /** Set the source's orientation using forward and up vectors. */
+ setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
+ /** Set source's position and orientation using a
+ * Three.js modelViewMatrix object */
+ setFromMatrix(matrix4: Float32Array): void;
+ /** Set the source width (in degrees). Where 0 degrees is a point source and 360
+ * degrees is an omnidirectional source */
+ setSourceWidth(sourceWidth: number): void;
+ /**
+ * Set source's directivity pattern (defined by alpha), where 0 is an
+ * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
+ * pattern. The sharpness of the pattern is increased exponentially
+ * @param alpha
+ * Determines directivity pattern (0 to 1).
+ * @param sharpness
+ * Determines the sharpness of the directivity pattern (1 to Inf).
+ */
+ setDirectivityPattern(alpha: number, sharpness: number): void;
+ }
+ namespace Room {
+ interface Options {
+ /** The listener's initial position (in meters), where origin is the center of
+ * the room */
+ listenerPosition?: Float32Array;
+ /** Room dimensions (in meters) */
+ dimensions?: Utils.RoomDimensions;
+ /** Named acoustic materials per wall */
+ materials?: Utils.RoomMaterials;
+ /** (in meters/second) */
+ speedOfSound?: number;
+ }
+ }
+ /**
+ * Model that manages early and late reflections using acoustic
+ * properties and listener position relative to a rectangular room.
+ */
+ class Room {
+ constructor(context: AudioContext, options?: Room.Options);
+ /**
+ * Set the room's dimensions and wall materials.
+ * @param dimensions Room dimensions (in meters)
+ * @param materials Named acoustic materials per wall
+ */
+ setProperties(dimensions: Utils.RoomDimensions, materials: Utils.RoomMaterials): void;
+ /**
+ * Set the listener's position (in meters), where origin is the center of
+ * the room.
+ */
+ setListenerPosition(x: number, y: number, z: number): void;
+ /**
+ * Compute distance outside room of provided position (in meters).
+ * @return
+ * Distance outside room (in meters). Returns 0 if inside room.
+ */
+ getDistanceOutsideRoom(x: number, y: number, z: number): number;
+ }
+ namespace Listener {
+ interface Options {
+ /** Desired ambisonic order */
+ ambisonicOrder: number;
+ /** Initial position (in meters), where origin is the center of
+ * the room */
+ position?: Float32Array;
+ /** The listener's initial forward vector */
+ forward?: Float32Array;
+ /** The listener's initial up vector */
+ up?: Float32Array;
+ }
+ }
+ /** Listener model to spatialize sources in an environment */
+ class Listener {
+ /** Position (in meters) */
+ position: Float32Array;
+ /** Ambisonic (multichannel) input */
+ input: AudioNode;
+ /** Binaurally-rendered stereo (2-channel) output */
+ output: AudioNode;
+ /** Ambisonic (multichannel) output */
+ ambisonicOutput: AudioNode;
+ /**
+ * Set the listener's orientation using forward and up vectors.
+ */
+ setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
+ /** Set listener's position and orientation using a
+ * Three.js modelViewMatrix object */
+ setFromMatrix(matrix4: Float32Array): void;
+ }
+ namespace Utils {
+ /** Properties describing the geometry of a room. */
+ interface RoomDimensions {
+ width: number;
+ height: number;
+ depth: number;
+ }
+ /** Properties describing the wall materials */
+ interface RoomMaterials {
+ left: string;
+ right: string;
+ front: string;
+ back: string;
+ down: string;
+ up: string;
+ }
+ }
+}
diff --git a/src/framework/resonator/vendor/resonance-es6/d.js b/src/framework/resonator/vendor/resonance-es6/d.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/framework/resonator/vendor/resonance-es6/directivity.d.ts b/src/framework/resonator/vendor/resonance-es6/directivity.d.ts
new file mode 100644
index 0000000..a280dec
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/directivity.d.ts
@@ -0,0 +1,47 @@
+export default Directivity;
+/**
+ * @class Directivity
+ * @description Directivity/occlusion filter.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Number} options.alpha
+ * Determines directivity pattern (0 to 1). See
+ * {@link Directivity#setPattern setPattern} for more details. Defaults to
+ * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
+ * @param {Number} options.sharpness
+ * Determines the sharpness of the directivity pattern (1 to Inf). See
+ * {@link Directivity#setPattern setPattern} for more details. Defaults to
+ * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS
+ * DEFAULT_DIRECTIVITY_SHARPNESS}.
+ */
+declare class Directivity {
+ constructor(context: any, options: any);
+ _context: any;
+ _lowpass: any;
+ _cosTheta: number;
+ input: any;
+ output: any;
+ /**
+ * Compute the filter using the source's forward orientation and the listener's
+ * position.
+ * @param {Float32Array} forward The source's forward vector.
+ * @param {Float32Array} direction The direction from the source to the
+ * listener.
+ */
+ computeAngle(forward: Float32Array, direction: Float32Array): void;
+ /**
+ * Set source's directivity pattern (defined by alpha), where 0 is an
+ * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
+ * pattern. The sharpness of the pattern is increased exponenentially.
+ * @param {Number} alpha
+ * Determines directivity pattern (0 to 1).
+ * @param {Number} sharpness
+ * Determines the sharpness of the directivity pattern (1 to Inf).
+ * DEFAULT_DIRECTIVITY_SHARPNESS}.
+ */
+ setPattern(alpha: number, sharpness: number): void;
+ _alpha: number;
+ _sharpness: number;
+}
diff --git a/src/framework/resonator/vendor/resonance-es6/directivity.js b/src/framework/resonator/vendor/resonance-es6/directivity.js
new file mode 100644
index 0000000..3a29d74
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/directivity.js
@@ -0,0 +1,117 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file Directivity/occlusion filter.
+ * @author Andrew Allen
+ */
+'use strict';
+// Internal dependencies.
+import Utils from './utils.js';
+/**
+ * @class Directivity
+ * @description Directivity/occlusion filter.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Number} options.alpha
+ * Determines directivity pattern (0 to 1). See
+ * {@link Directivity#setPattern setPattern} for more details. Defaults to
+ * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
+ * @param {Number} options.sharpness
+ * Determines the sharpness of the directivity pattern (1 to Inf). See
+ * {@link Directivity#setPattern setPattern} for more details. Defaults to
+ * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS
+ * DEFAULT_DIRECTIVITY_SHARPNESS}.
+ */
+class Directivity {
+ constructor(context, options) {
+ // Public variables.
+ /**
+ * Mono (1-channel) input {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} input
+ * @memberof Directivity
+ * @instance
+ */
+ /**
+ * Mono (1-channel) output {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} output
+ * @memberof Directivity
+ * @instance
+ */
+ // Use defaults for undefined arguments.
+ if (options == undefined) {
+ options = {};
+ }
+ if (options.alpha == undefined) {
+ options.alpha = Utils.DEFAULT_DIRECTIVITY_ALPHA;
+ }
+ if (options.sharpness == undefined) {
+ options.sharpness = Utils.DEFAULT_DIRECTIVITY_SHARPNESS;
+ }
+ // Create audio node.
+ this._context = context;
+ this._lowpass = context.createBiquadFilter();
+ // Initialize filter coefficients.
+ this._lowpass.type = 'lowpass';
+ this._lowpass.Q.value = 0;
+ this._lowpass.frequency.value = context.sampleRate * 0.5;
+ this._cosTheta = 0;
+ this.setPattern(options.alpha, options.sharpness);
+ // Input/Output proxy.
+ this.input = this._lowpass;
+ this.output = this._lowpass;
+ }
+ /**
+ * Compute the filter using the source's forward orientation and the listener's
+ * position.
+ * @param {Float32Array} forward The source's forward vector.
+ * @param {Float32Array} direction The direction from the source to the
+ * listener.
+ */
+ computeAngle(forward, direction) {
+ let forwardNorm = Utils.normalizeVector(forward);
+ let directionNorm = Utils.normalizeVector(direction);
+ let coeff = 1;
+ if (this._alpha > Utils.EPSILON_FLOAT) {
+ let cosTheta = forwardNorm[0] * directionNorm[0] +
+ forwardNorm[1] * directionNorm[1] + forwardNorm[2] * directionNorm[2];
+ coeff = (1 - this._alpha) + this._alpha * cosTheta;
+ coeff = Math.pow(Math.abs(coeff), this._sharpness);
+ }
+ this._lowpass.frequency.value = this._context.sampleRate * 0.5 * coeff;
+ }
+ /**
+ * Set source's directivity pattern (defined by alpha), where 0 is an
+ * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
+ * pattern. The sharpness of the pattern is increased exponenentially.
+ * @param {Number} alpha
+ * Determines directivity pattern (0 to 1).
+ * @param {Number} sharpness
+ * Determines the sharpness of the directivity pattern (1 to Inf).
+ * DEFAULT_DIRECTIVITY_SHARPNESS}.
+ */
+ setPattern(alpha, sharpness) {
+ // Clamp and set values.
+ this._alpha = Math.min(1, Math.max(0, alpha));
+ this._sharpness = Math.max(1, sharpness);
+ // Update angle calculation using new values.
+ this.computeAngle([this._cosTheta * this._cosTheta, 0, 0], [1, 0, 0]);
+ }
+}
+export default Directivity;
diff --git a/src/framework/resonator/vendor/resonance-es6/early-reflections.d.ts b/src/framework/resonator/vendor/resonance-es6/early-reflections.d.ts
new file mode 100644
index 0000000..847009d
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/early-reflections.d.ts
@@ -0,0 +1,56 @@
+export default EarlyReflections;
+/**
+ * @class EarlyReflections
+ * @description Ray-tracing-based early reflections model.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Utils~RoomDimensions} options.dimensions
+ * Room dimensions (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ * @param {Object} options.coefficients
+ * Frequency-independent reflection coeffs per wall. Defaults to
+ * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS
+ * DEFAULT_REFLECTION_COEFFICIENTS}.
+ * @param {Number} options.speedOfSound
+ * (in meters / second). Defaults to {@linkcode Utils.DEFAULT_SPEED_OF_SOUND
+ * DEFAULT_SPEED_OF_SOUND}.
+ * @param {Float32Array} options.listenerPosition
+ * (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ */
+declare class EarlyReflections {
+ constructor(context: any, options: any);
+ speedOfSound: any;
+ input: any;
+ output: any;
+ _lowpass: any;
+ _delays: {};
+ _gains: {};
+ _inverters: {};
+ _merger: any;
+ _listenerPosition: any;
+ /**
+ * Set the listener's position (in meters),
+ * where [0,0,0] is the center of the room.
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ */
+ setListenerPosition(x: number, y: number, z: number): void;
+ /**
+ * Set the room's properties which determines the characteristics of
+ * reflections.
+ * @param {Utils~RoomDimensions} dimensions
+ * Room dimensions (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ * @param {Object} coefficients
+ * Frequency-independent reflection coeffs per wall. Defaults to
+ * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS
+ * DEFAULT_REFLECTION_COEFFICIENTS}.
+ */
+ setRoomProperties(dimensions: any, coefficients: any): void;
+ _coefficients: any;
+ _halfDimensions: {};
+}
diff --git a/src/framework/resonator/vendor/resonance-es6/early-reflections.js b/src/framework/resonator/vendor/resonance-es6/early-reflections.js
new file mode 100644
index 0000000..c3c2919
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/early-reflections.js
@@ -0,0 +1,212 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file Ray-tracing-based early reflections model.
+ * @author Andrew Allen
+ */
+'use strict';
+// Internal dependencies.
+import Utils from './utils.js';
+/**
+ * @class EarlyReflections
+ * @description Ray-tracing-based early reflections model.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Utils~RoomDimensions} options.dimensions
+ * Room dimensions (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ * @param {Object} options.coefficients
+ * Frequency-independent reflection coeffs per wall. Defaults to
+ * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS
+ * DEFAULT_REFLECTION_COEFFICIENTS}.
+ * @param {Number} options.speedOfSound
+ * (in meters / second). Defaults to {@linkcode Utils.DEFAULT_SPEED_OF_SOUND
+ * DEFAULT_SPEED_OF_SOUND}.
+ * @param {Float32Array} options.listenerPosition
+ * (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ */
+class EarlyReflections {
+ constructor(context, options) {
+ // Public variables.
+ /**
+ * The room's speed of sound (in meters/second).
+ * @member {Number} speedOfSound
+ * @memberof EarlyReflections
+ * @instance
+ */
+ /**
+ * Mono (1-channel) input {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} input
+ * @memberof EarlyReflections
+ * @instance
+ */
+ /**
+ * First-order ambisonic (4-channel) output {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} output
+ * @memberof EarlyReflections
+ * @instance
+ */
+ // Use defaults for undefined arguments.
+ if (options == undefined) {
+ options = {};
+ }
+ if (options.speedOfSound == undefined) {
+ options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND;
+ }
+ if (options.listenerPosition == undefined) {
+ options.listenerPosition = Utils.DEFAULT_POSITION.slice();
+ }
+ if (options.coefficients == undefined) {
+ options.coefficients = {};
+ Object.assign(options.coefficients, Utils.DEFAULT_REFLECTION_COEFFICIENTS);
+ }
+ // Assign room's speed of sound.
+ this.speedOfSound = options.speedOfSound;
+ // Create nodes.
+ this.input = context.createGain();
+ this.output = context.createGain();
+ this._lowpass = context.createBiquadFilter();
+ this._delays = {};
+ this._gains = {}; // gainPerWall = (ReflectionCoeff / Attenuation)
+ this._inverters = {}; // 3 of these are needed for right/back/down walls.
+ this._merger = context.createChannelMerger(4); // First-order encoding only.
+ // Connect audio graph for each wall reflection.
+ for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) {
+ if (Utils.DEFAULT_REFLECTION_COEFFICIENTS
+ .hasOwnProperty(property)) {
+ this._delays[property] =
+ context.createDelay(Utils.MAX_DURATION);
+ this._gains[property] = context.createGain();
+ }
+ }
+ this._inverters.right = context.createGain();
+ this._inverters.down = context.createGain();
+ this._inverters.back = context.createGain();
+ // Initialize lowpass filter.
+ this._lowpass.type = 'lowpass';
+ this._lowpass.frequency.value = Utils.DEFAULT_REFLECTION_CUTOFF_FREQUENCY;
+ this._lowpass.Q.value = 0;
+ // Initialize encoder directions, set delay times and gains to 0.
+ for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) {
+ if (Utils.DEFAULT_REFLECTION_COEFFICIENTS
+ .hasOwnProperty(property)) {
+ this._delays[property].delayTime.value = 0;
+ this._gains[property].gain.value = 0;
+ }
+ }
+ // Initialize inverters for opposite walls ('right', 'down', 'back' only).
+ this._inverters.right.gain.value = -1;
+ this._inverters.down.gain.value = -1;
+ this._inverters.back.gain.value = -1;
+ // Connect nodes.
+ this.input.connect(this._lowpass);
+ for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) {
+ if (Utils.DEFAULT_REFLECTION_COEFFICIENTS
+ .hasOwnProperty(property)) {
+ this._lowpass.connect(this._delays[property]);
+ this._delays[property].connect(this._gains[property]);
+ this._gains[property].connect(this._merger, 0, 0);
+ }
+ }
+ // Connect gains to ambisonic channel output.
+ // Left: [1 1 0 0]
+ // Right: [1 -1 0 0]
+ // Up: [1 0 1 0]
+ // Down: [1 0 -1 0]
+ // Front: [1 0 0 1]
+ // Back: [1 0 0 -1]
+ this._gains.left.connect(this._merger, 0, 1);
+ this._gains.right.connect(this._inverters.right);
+ this._inverters.right.connect(this._merger, 0, 1);
+ this._gains.up.connect(this._merger, 0, 2);
+ this._gains.down.connect(this._inverters.down);
+ this._inverters.down.connect(this._merger, 0, 2);
+ this._gains.front.connect(this._merger, 0, 3);
+ this._gains.back.connect(this._inverters.back);
+ this._inverters.back.connect(this._merger, 0, 3);
+ this._merger.connect(this.output);
+ // Initialize.
+ this._listenerPosition = options.listenerPosition;
+ this.setRoomProperties(options.dimensions, options.coefficients);
+ }
+ /**
+ * Set the listener's position (in meters),
+ * where [0,0,0] is the center of the room.
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ */
+ setListenerPosition(x, y, z) {
+ // Assign listener position.
+ this._listenerPosition = [x, y, z];
+ // Determine distances to each wall.
+ let distances = {
+ left: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.width + x) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
+ right: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.width - x) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
+ front: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.depth + z) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
+ back: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.depth - z) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
+ down: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.height + y) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
+ up: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.height - y) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
+ };
+ // Assign delay & attenuation values using distances.
+ for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) {
+ if (Utils.DEFAULT_REFLECTION_COEFFICIENTS
+ .hasOwnProperty(property)) {
+ // Compute and assign delay (in seconds).
+ let delayInSecs = distances[property] / this.speedOfSound;
+ this._delays[property].delayTime.value = delayInSecs;
+ // Compute and assign gain, uses logarithmic rolloff: "g = R / (d + 1)"
+ let attenuation = this._coefficients[property] / distances[property];
+ this._gains[property].gain.value = attenuation;
+ }
+ }
+ }
+ /**
+ * Set the room's properties which determines the characteristics of
+ * reflections.
+ * @param {Utils~RoomDimensions} dimensions
+ * Room dimensions (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ * @param {Object} coefficients
+ * Frequency-independent reflection coeffs per wall. Defaults to
+ * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS
+ * DEFAULT_REFLECTION_COEFFICIENTS}.
+ */
+ setRoomProperties(dimensions, coefficients) {
+ if (dimensions == undefined) {
+ dimensions = {};
+ Object.assign(dimensions, Utils.DEFAULT_ROOM_DIMENSIONS);
+ }
+ if (coefficients == undefined) {
+ coefficients = {};
+ Object.assign(coefficients, Utils.DEFAULT_REFLECTION_COEFFICIENTS);
+ }
+ this._coefficients = coefficients;
+ // Sanitize dimensions and store half-dimensions.
+ this._halfDimensions = {};
+ this._halfDimensions.width = dimensions.width * 0.5;
+ this._halfDimensions.height = dimensions.height * 0.5;
+ this._halfDimensions.depth = dimensions.depth * 0.5;
+ // Update listener position with new room properties.
+ this.setListenerPosition(this._listenerPosition[0], this._listenerPosition[1], this._listenerPosition[2]);
+ }
+}
+export default EarlyReflections;
diff --git a/src/framework/resonator/vendor/resonance-es6/encoder.d.ts b/src/framework/resonator/vendor/resonance-es6/encoder.d.ts
new file mode 100644
index 0000000..059f638
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/encoder.d.ts
@@ -0,0 +1,64 @@
+export default Encoder;
+/**
+ * @class Encoder
+ * @description Spatially encodes input using weighted spherical harmonics.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Number} options.ambisonicOrder
+ * Desired ambisonic order. Defaults to
+ * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
+ * @param {Number} options.azimuth
+ * Azimuth (in degrees). Defaults to
+ * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}.
+ * @param {Number} options.elevation
+ * Elevation (in degrees). Defaults to
+ * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}.
+ * @param {Number} options.sourceWidth
+ * Source width (in degrees). Where 0 degrees is a point source and 360 degrees
+ * is an omnidirectional source. Defaults to
+ * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
+ */
+declare class Encoder {
+ constructor(context: any, options: any);
+ _context: any;
+ input: any;
+ _channelGain: any[];
+ _merger: any;
+ output: any;
+ _azimuth: any;
+ _elevation: any;
+ /**
+ * Set the desired ambisonic order.
+ * @param {Number} ambisonicOrder Desired ambisonic order.
+ */
+ setAmbisonicOrder(ambisonicOrder: number): void;
+ _ambisonicOrder: number;
+ /**
+ * Set the direction of the encoded source signal.
+ * @param {Number} azimuth
+ * Azimuth (in degrees). Defaults to
+ * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}.
+ * @param {Number} elevation
+ * Elevation (in degrees). Defaults to
+ * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}.
+ */
+ setDirection(azimuth: number, elevation: number): void;
+ /**
+ * Set the source width (in degrees). Where 0 degrees is a point source and 360
+ * degrees is an omnidirectional source.
+ * @param {Number} sourceWidth (in degrees).
+ */
+ setSourceWidth(sourceWidth: number): void;
+ _spreadIndex: number;
+}
+declare namespace Encoder {
+ /**
+ * Validate the provided ambisonic order.
+ * @param {Number} ambisonicOrder Desired ambisonic order.
+ * @return {Number} Validated/adjusted ambisonic order.
+ * @private
+ */
+ function validateAmbisonicOrder(ambisonicOrder: number): number;
+}
diff --git a/src/framework/resonator/vendor/resonance-es6/encoder.js b/src/framework/resonator/vendor/resonance-es6/encoder.js
new file mode 100644
index 0000000..2fdaf3d
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/encoder.js
@@ -0,0 +1,194 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file Spatially encodes input using weighted spherical harmonics.
+ * @author Andrew Allen
+ */
+'use strict';
+// Internal dependencies.
+import Tables from './tables.js';
+import Utils from './utils.js';
+/**
+ * @class Encoder
+ * @description Spatially encodes input using weighted spherical harmonics.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Number} options.ambisonicOrder
+ * Desired ambisonic order. Defaults to
+ * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
+ * @param {Number} options.azimuth
+ * Azimuth (in degrees). Defaults to
+ * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}.
+ * @param {Number} options.elevation
+ * Elevation (in degrees). Defaults to
+ * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}.
+ * @param {Number} options.sourceWidth
+ * Source width (in degrees). Where 0 degrees is a point source and 360 degrees
+ * is an omnidirectional source. Defaults to
+ * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
+ */
+class Encoder {
+ constructor(context, options) {
+ // Public variables.
+ /**
+ * Mono (1-channel) input {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} input
+ * @memberof Encoder
+ * @instance
+ */
+ /**
+ * Ambisonic (multichannel) output {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} output
+ * @memberof Encoder
+ * @instance
+ */
+ // Use defaults for undefined arguments.
+ if (options == undefined) {
+ options = {};
+ }
+ if (options.ambisonicOrder == undefined) {
+ options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER;
+ }
+ if (options.azimuth == undefined) {
+ options.azimuth = Utils.DEFAULT_AZIMUTH;
+ }
+ if (options.elevation == undefined) {
+ options.elevation = Utils.DEFAULT_ELEVATION;
+ }
+ if (options.sourceWidth == undefined) {
+ options.sourceWidth = Utils.DEFAULT_SOURCE_WIDTH;
+ }
+ this._context = context;
+ // Create I/O nodes.
+ this.input = context.createGain();
+ this._channelGain = [];
+ this._merger = undefined;
+ this.output = context.createGain();
+ // Set initial order, angle and source width.
+ this.setAmbisonicOrder(options.ambisonicOrder);
+ this._azimuth = options.azimuth;
+ this._elevation = options.elevation;
+ this.setSourceWidth(options.sourceWidth);
+ }
+ /**
+ * Set the desired ambisonic order.
+ * @param {Number} ambisonicOrder Desired ambisonic order.
+ */
+ setAmbisonicOrder(ambisonicOrder) {
+ this._ambisonicOrder = Encoder.validateAmbisonicOrder(ambisonicOrder);
+ this.input.disconnect();
+ for (let i = 0; i < this._channelGain.length; i++) {
+ this._channelGain[i].disconnect();
+ }
+ if (this._merger != undefined) {
+ this._merger.disconnect();
+ }
+ delete this._channelGain;
+ delete this._merger;
+ // Create audio graph.
+ let numChannels = (this._ambisonicOrder + 1) * (this._ambisonicOrder + 1);
+ this._merger = this._context.createChannelMerger(numChannels);
+ this._channelGain = new Array(numChannels);
+ for (let i = 0; i < numChannels; i++) {
+ this._channelGain[i] = this._context.createGain();
+ this.input.connect(this._channelGain[i]);
+ this._channelGain[i].connect(this._merger, 0, i);
+ }
+ this._merger.connect(this.output);
+ }
+ /**
+ * Set the direction of the encoded source signal.
+ * @param {Number} azimuth
+ * Azimuth (in degrees). Defaults to
+ * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}.
+ * @param {Number} elevation
+ * Elevation (in degrees). Defaults to
+ * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}.
+ */
+ setDirection(azimuth, elevation) {
+ // Format input direction to nearest indices.
+ if (azimuth == undefined || isNaN(azimuth)) {
+ azimuth = Utils.DEFAULT_AZIMUTH;
+ }
+ if (elevation == undefined || isNaN(elevation)) {
+ elevation = Utils.DEFAULT_ELEVATION;
+ }
+ // Store the formatted input (for updating source width).
+ this._azimuth = azimuth;
+ this._elevation = elevation;
+ // Format direction for index lookups.
+ azimuth = Math.round(azimuth % 360);
+ if (azimuth < 0) {
+ azimuth += 360;
+ }
+ elevation = Math.round(Math.min(90, Math.max(-90, elevation))) + 90;
+ // Assign gains to each output.
+ this._channelGain[0].gain.value = Tables.MAX_RE_WEIGHTS[this._spreadIndex][0];
+ for (let i = 1; i <= this._ambisonicOrder; i++) {
+ let degreeWeight = Tables.MAX_RE_WEIGHTS[this._spreadIndex][i];
+ for (let j = -i; j <= i; j++) {
+ let acnChannel = (i * i) + i + j;
+ let elevationIndex = i * (i + 1) / 2 + Math.abs(j) - 1;
+ let val = Tables.SPHERICAL_HARMONICS[1][elevation][elevationIndex];
+ if (j != 0) {
+ let azimuthIndex = Tables.SPHERICAL_HARMONICS_MAX_ORDER + j - 1;
+ if (j < 0) {
+ azimuthIndex = Tables.SPHERICAL_HARMONICS_MAX_ORDER + j;
+ }
+ val *= Tables.SPHERICAL_HARMONICS[0][azimuth][azimuthIndex];
+ }
+ this._channelGain[acnChannel].gain.value = val * degreeWeight;
+ }
+ }
+ }
+ /**
+ * Set the source width (in degrees). Where 0 degrees is a point source and 360
+ * degrees is an omnidirectional source.
+ * @param {Number} sourceWidth (in degrees).
+ */
+ setSourceWidth(sourceWidth) {
+ // The MAX_RE_WEIGHTS is a 360 x (Tables.SPHERICAL_HARMONICS_MAX_ORDER+1)
+ // size table.
+ this._spreadIndex = Math.min(359, Math.max(0, Math.round(sourceWidth)));
+ this.setDirection(this._azimuth, this._elevation);
+ }
+}
+/**
+ * Validate the provided ambisonic order.
+ * @param {Number} ambisonicOrder Desired ambisonic order.
+ * @return {Number} Validated/adjusted ambisonic order.
+ * @private
+ */
+Encoder.validateAmbisonicOrder = ambisonicOrder => {
+ if (isNaN(ambisonicOrder) || ambisonicOrder == undefined) {
+ Utils.log('Error: Invalid ambisonic order', options.ambisonicOrder, '\nUsing ambisonicOrder=1 instead.');
+ ambisonicOrder = 1;
+ }
+ else if (ambisonicOrder < 1) {
+ Utils.log('Error: Unable to render ambisonic order', options.ambisonicOrder, '(Min order is 1)', '\nUsing min order instead.');
+ ambisonicOrder = 1;
+ }
+ else if (ambisonicOrder > Tables.SPHERICAL_HARMONICS_MAX_ORDER) {
+ Utils.log('Error: Unable to render ambisonic order', options.ambisonicOrder, '(Max order is', Tables.SPHERICAL_HARMONICS_MAX_ORDER, ')\nUsing max order instead.');
+ options.ambisonicOrder = Tables.SPHERICAL_HARMONICS_MAX_ORDER;
+ }
+ return ambisonicOrder;
+};
+export default Encoder;
diff --git a/src/framework/resonator/vendor/resonance-es6/late-reflections.d.ts b/src/framework/resonator/vendor/resonance-es6/late-reflections.d.ts
new file mode 100644
index 0000000..e91ca38
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/late-reflections.d.ts
@@ -0,0 +1,42 @@
+export default LateReflections;
+/**
+ * @class LateReflections
+ * @description Late-reflections reverberation filter for Ambisonic content.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Array} options.durations
+ * Multiband RT60 durations (in seconds) for each frequency band, listed as
+ * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS
+ * FREQUDEFAULT_REVERB_FREQUENCY_BANDSENCY_BANDS}. Defaults to
+ * {@linkcode Utils.DEFAULT_REVERB_DURATIONS DEFAULT_REVERB_DURATIONS}.
+ * @param {Number} options.predelay Pre-delay (in milliseconds). Defaults to
+ * {@linkcode Utils.DEFAULT_REVERB_PREDELAY DEFAULT_REVERB_PREDELAY}.
+ * @param {Number} options.gain Output gain (linear). Defaults to
+ * {@linkcode Utils.DEFAULT_REVERB_GAIN DEFAULT_REVERB_GAIN}.
+ * @param {Number} options.bandwidth Bandwidth (in octaves) for each frequency
+ * band. Defaults to
+ * {@linkcode Utils.DEFAULT_REVERB_BANDWIDTH DEFAULT_REVERB_BANDWIDTH}.
+ * @param {Number} options.tailonset Length (in milliseconds) of impulse
+ * response to apply a half-Hann window. Defaults to
+ * {@linkcode Utils.DEFAULT_REVERB_TAIL_ONSET DEFAULT_REVERB_TAIL_ONSET}.
+ */
+declare class LateReflections {
+ constructor(context: any, options: any);
+ _bandwidthCoeff: number;
+ _tailonsetSamples: number;
+ _context: any;
+ input: any;
+ _predelay: any;
+ _convolver: any;
+ output: any;
+ /**
+ * Re-compute a new impulse response by providing Multiband RT60 durations.
+ * @param {Array} durations
+ * Multiband RT60 durations (in seconds) for each frequency band, listed as
+ * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS
+ * DEFAULT_REVERB_FREQUENCY_BANDS}.
+ */
+ setDurations(durations: any[]): void;
+}
diff --git a/src/framework/resonator/vendor/resonance-es6/late-reflections.js b/src/framework/resonator/vendor/resonance-es6/late-reflections.js
new file mode 100644
index 0000000..3ed0d00
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/late-reflections.js
@@ -0,0 +1,187 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file Late reverberation filter for Ambisonic content.
+ * @author Andrew Allen
+ */
+'use strict';
+// Internal dependencies.
+import Utils from './utils.js';
+/**
+ * @class LateReflections
+ * @description Late-reflections reverberation filter for Ambisonic content.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Array} options.durations
+ * Multiband RT60 durations (in seconds) for each frequency band, listed as
+ * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS
+ * FREQUDEFAULT_REVERB_FREQUENCY_BANDSENCY_BANDS}. Defaults to
+ * {@linkcode Utils.DEFAULT_REVERB_DURATIONS DEFAULT_REVERB_DURATIONS}.
+ * @param {Number} options.predelay Pre-delay (in milliseconds). Defaults to
+ * {@linkcode Utils.DEFAULT_REVERB_PREDELAY DEFAULT_REVERB_PREDELAY}.
+ * @param {Number} options.gain Output gain (linear). Defaults to
+ * {@linkcode Utils.DEFAULT_REVERB_GAIN DEFAULT_REVERB_GAIN}.
+ * @param {Number} options.bandwidth Bandwidth (in octaves) for each frequency
+ * band. Defaults to
+ * {@linkcode Utils.DEFAULT_REVERB_BANDWIDTH DEFAULT_REVERB_BANDWIDTH}.
+ * @param {Number} options.tailonset Length (in milliseconds) of impulse
+ * response to apply a half-Hann window. Defaults to
+ * {@linkcode Utils.DEFAULT_REVERB_TAIL_ONSET DEFAULT_REVERB_TAIL_ONSET}.
+ */
+class LateReflections {
+ constructor(context, options) {
+ // Public variables.
+ /**
+ * Mono (1-channel) input {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} input
+ * @memberof LateReflections
+ * @instance
+ */
+ /**
+ * Mono (1-channel) output {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} output
+ * @memberof LateReflections
+ * @instance
+ */
+ // Use defaults for undefined arguments.
+ if (options == undefined) {
+ options = {};
+ }
+ if (options.durations == undefined) {
+ options.durations = Utils.DEFAULT_REVERB_DURATIONS.slice();
+ }
+ if (options.predelay == undefined) {
+ options.predelay = Utils.DEFAULT_REVERB_PREDELAY;
+ }
+ if (options.gain == undefined) {
+ options.gain = Utils.DEFAULT_REVERB_GAIN;
+ }
+ if (options.bandwidth == undefined) {
+ options.bandwidth = Utils.DEFAULT_REVERB_BANDWIDTH;
+ }
+ if (options.tailonset == undefined) {
+ options.tailonset = Utils.DEFAULT_REVERB_TAIL_ONSET;
+ }
+ // Assign pre-computed variables.
+ let delaySecs = options.predelay / 1000;
+ this._bandwidthCoeff = options.bandwidth * Utils.LOG2_DIV2;
+ this._tailonsetSamples = options.tailonset / 1000;
+ // Create nodes.
+ this._context = context;
+ this.input = context.createGain();
+ this._predelay = context.createDelay(delaySecs);
+ this._convolver = context.createConvolver();
+ this.output = context.createGain();
+ // Set reverb attenuation.
+ this.output.gain.value = options.gain;
+ // Disable normalization.
+ this._convolver.normalize = false;
+ // Connect nodes.
+ this.input.connect(this._predelay);
+ this._predelay.connect(this._convolver);
+ this._convolver.connect(this.output);
+ // Compute IR using RT60 values.
+ this.setDurations(options.durations);
+ }
+ /**
+ * Re-compute a new impulse response by providing Multiband RT60 durations.
+ * @param {Array} durations
+ * Multiband RT60 durations (in seconds) for each frequency band, listed as
+ * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS
+ * DEFAULT_REVERB_FREQUENCY_BANDS}.
+ */
+ setDurations(durations) {
+ if (durations.length !== Utils.NUMBER_REVERB_FREQUENCY_BANDS) {
+ Utils.log('Warning: invalid number of RT60 values provided to reverb.');
+ return;
+ }
+ // Compute impulse response.
+ let durationsSamples = new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS);
+ let sampleRate = this._context.sampleRate;
+ for (let i = 0; i < durations.length; i++) {
+ // Clamp within suitable range.
+ durations[i] =
+ Math.max(0, Math.min(Utils.DEFAULT_REVERB_MAX_DURATION, durations[i]));
+ // Convert seconds to samples.
+ durationsSamples[i] = Math.round(durations[i] * sampleRate *
+ Utils.DEFAULT_REVERB_DURATION_MULTIPLIER);
+ }
+ ;
+ // Determine max RT60 length in samples.
+ let durationsSamplesMax = 0;
+ for (let i = 0; i < durationsSamples.length; i++) {
+ if (durationsSamples[i] > durationsSamplesMax) {
+ durationsSamplesMax = durationsSamples[i];
+ }
+ }
+ // Skip this step if there is no reverberation to compute.
+ if (durationsSamplesMax < 1) {
+ durationsSamplesMax = 1;
+ }
+ // Create impulse response buffer.
+ let buffer = this._context.createBuffer(1, durationsSamplesMax, sampleRate);
+ let bufferData = buffer.getChannelData(0);
+ // Create noise signal (computed once, referenced in each band's routine).
+ let noiseSignal = new Float32Array(durationsSamplesMax);
+ for (let i = 0; i < durationsSamplesMax; i++) {
+ noiseSignal[i] = Math.random() * 2 - 1;
+ }
+ // Compute the decay rate per-band and filter the decaying noise signal.
+ for (let i = 0; i < Utils.NUMBER_REVERB_FREQUENCY_BANDS; i++) {
+ // Compute decay rate.
+ let decayRate = -Utils.LOG1000 / durationsSamples[i];
+ // Construct a standard one-zero, two-pole bandpass filter:
+ // H(z) = (b0 * z^0 + b1 * z^-1 + b2 * z^-2) / (1 + a1 * z^-1 + a2 * z^-2)
+ let omega = Utils.TWO_PI *
+ Utils.DEFAULT_REVERB_FREQUENCY_BANDS[i] / sampleRate;
+ let sinOmega = Math.sin(omega);
+ let alpha = sinOmega * Math.sinh(this._bandwidthCoeff * omega / sinOmega);
+ let a0CoeffReciprocal = 1 / (1 + alpha);
+ let b0Coeff = alpha * a0CoeffReciprocal;
+ let a1Coeff = -2 * Math.cos(omega) * a0CoeffReciprocal;
+ let a2Coeff = (1 - alpha) * a0CoeffReciprocal;
+ // We optimize since b2 = -b0, b1 = 0.
+ // Update equation for two-pole bandpass filter:
+ // u[n] = x[n] - a1 * x[n-1] - a2 * x[n-2]
+ // y[n] = b0 * (u[n] - u[n-2])
+ let um1 = 0;
+ let um2 = 0;
+ for (let j = 0; j < durationsSamples[i]; j++) {
+ // Exponentially-decaying white noise.
+ let x = noiseSignal[j] * Math.exp(decayRate * j);
+ // Filter signal with bandpass filter and add to output.
+ let u = x - a1Coeff * um1 - a2Coeff * um2;
+ bufferData[j] += b0Coeff * (u - um2);
+ // Update coefficients.
+ um2 = um1;
+ um1 = u;
+ }
+ }
+ // Create and apply half of a Hann window to the beginning of the
+ // impulse response.
+ let halfHannLength = Math.round(this._tailonsetSamples);
+ for (let i = 0; i < Math.min(bufferData.length, halfHannLength); i++) {
+ let halfHann = 0.5 * (1 - Math.cos(Utils.TWO_PI * i / (2 * halfHannLength - 1)));
+ bufferData[i] *= halfHann;
+ }
+ this._convolver.buffer = buffer;
+ }
+}
+export default LateReflections;
diff --git a/src/framework/resonator/vendor/resonance-es6/listener.d.ts b/src/framework/resonator/vendor/resonance-es6/listener.d.ts
new file mode 100644
index 0000000..2b98e59
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/listener.d.ts
@@ -0,0 +1,49 @@
+export default Listener;
+/**
+ * @class Listener
+ * @description Listener model to spatialize sources in an environment.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Number} options.ambisonicOrder
+ * Desired ambisonic order. Defaults to
+ * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
+ * @param {Float32Array} options.position
+ * Initial position (in meters), where origin is the center of
+ * the room. Defaults to
+ * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ * @param {Float32Array} options.forward
+ * The listener's initial forward vector. Defaults to
+ * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
+ * @param {Float32Array} options.up
+ * The listener's initial up vector. Defaults to
+ * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
+ */
+declare class Listener {
+ constructor(context: any, options: any);
+ position: Float32Array;
+ _tempMatrix3: Float32Array;
+ _ambisonicOrder: number;
+ _context: any;
+ _renderer: any;
+ input: any;
+ output: any;
+ ambisonicOutput: any;
+ /**
+ * Set the source's orientation using forward and up vectors.
+ * @param {Number} forwardX
+ * @param {Number} forwardY
+ * @param {Number} forwardZ
+ * @param {Number} upX
+ * @param {Number} upY
+ * @param {Number} upZ
+ */
+ setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
+ /**
+ * Set the listener's position and orientation using a Three.js Matrix4 object.
+ * @param {Object} matrix4
+ * The Three.js Matrix4 object representing the listener's world transform.
+ */
+ setFromMatrix(matrix4: any): void;
+}
diff --git a/src/framework/resonator/vendor/resonance-es6/listener.js b/src/framework/resonator/vendor/resonance-es6/listener.js
new file mode 100644
index 0000000..2e6b15a
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/listener.js
@@ -0,0 +1,168 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file Listener model to spatialize sources in an environment.
+ * @author Andrew Allen
+ */
+'use strict';
+// Internal dependencies.
+import Omnitone from 'omnitone/build/omnitone.esm';
+import Encoder from './encoder.js';
+import Utils from './utils.js';
+/**
+ * @class Listener
+ * @description Listener model to spatialize sources in an environment.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Number} options.ambisonicOrder
+ * Desired ambisonic order. Defaults to
+ * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
+ * @param {Float32Array} options.position
+ * Initial position (in meters), where origin is the center of
+ * the room. Defaults to
+ * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ * @param {Float32Array} options.forward
+ * The listener's initial forward vector. Defaults to
+ * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
+ * @param {Float32Array} options.up
+ * The listener's initial up vector. Defaults to
+ * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
+ */
+class Listener {
+ constructor(context, options) {
+ // Public variables.
+ /**
+ * Position (in meters).
+ * @member {Float32Array} position
+ * @memberof Listener
+ * @instance
+ */
+ /**
+ * Ambisonic (multichannel) input {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} input
+ * @memberof Listener
+ * @instance
+ */
+ /**
+ * Binaurally-rendered stereo (2-channel) output {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} output
+ * @memberof Listener
+ * @instance
+ */
+ /**
+ * Ambisonic (multichannel) output {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} ambisonicOutput
+ * @memberof Listener
+ * @instance
+ */
+ // Use defaults for undefined arguments.
+ if (options == undefined) {
+ options = {};
+ }
+ if (options.ambisonicOrder == undefined) {
+ options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER;
+ }
+ if (options.position == undefined) {
+ options.position = Utils.DEFAULT_POSITION.slice();
+ }
+ if (options.forward == undefined) {
+ options.forward = Utils.DEFAULT_FORWARD.slice();
+ }
+ if (options.up == undefined) {
+ options.up = Utils.DEFAULT_UP.slice();
+ }
+ // Member variables.
+ this.position = new Float32Array(3);
+ this._tempMatrix3 = new Float32Array(9);
+ // Select the appropriate HRIR filters using 2-channel chunks since
+ // multichannel audio is not yet supported by a majority of browsers.
+ this._ambisonicOrder =
+ Encoder.validateAmbisonicOrder(options.ambisonicOrder);
+ // Create audio nodes.
+ this._context = context;
+ if (this._ambisonicOrder == 1) {
+ this._renderer = Omnitone.createFOARenderer(context, {});
+ }
+ else if (this._ambisonicOrder > 1) {
+ this._renderer = Omnitone.createHOARenderer(context, {
+ ambisonicOrder: this._ambisonicOrder,
+ });
+ }
+ // These nodes are created in order to safely asynchronously load Omnitone
+ // while the rest of the scene is being created.
+ this.input = context.createGain();
+ this.output = context.createGain();
+ this.ambisonicOutput = context.createGain();
+ // Initialize Omnitone (async) and connect to audio graph when complete.
+ let that = this;
+ this._renderer.initialize().then(() => {
+ // Connect pre-rotated soundfield to renderer.
+ that.input.connect(that._renderer.input);
+ // Connect rotated soundfield to ambisonic output.
+ if (that._ambisonicOrder > 1) {
+ that._renderer._hoaRotator.output.connect(that.ambisonicOutput);
+ }
+ else {
+ that._renderer._foaRotator.output.connect(that.ambisonicOutput);
+ }
+ // Connect binaurally-rendered soundfield to binaural output.
+ that._renderer.output.connect(that.output);
+ });
+ // Set orientation and update rotation matrix accordingly.
+ this.setOrientation(options.forward[0], options.forward[1], options.forward[2], options.up[0], options.up[1], options.up[2]);
+ }
+ /**
+ * Set the source's orientation using forward and up vectors.
+ * @param {Number} forwardX
+ * @param {Number} forwardY
+ * @param {Number} forwardZ
+ * @param {Number} upX
+ * @param {Number} upY
+ * @param {Number} upZ
+ */
+ setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) {
+ let right = Utils.crossProduct([forwardX, forwardY, forwardZ], [upX, upY, upZ]);
+ this._tempMatrix3[0] = right[0];
+ this._tempMatrix3[1] = right[1];
+ this._tempMatrix3[2] = right[2];
+ this._tempMatrix3[3] = upX;
+ this._tempMatrix3[4] = upY;
+ this._tempMatrix3[5] = upZ;
+ this._tempMatrix3[6] = forwardX;
+ this._tempMatrix3[7] = forwardY;
+ this._tempMatrix3[8] = forwardZ;
+ this._renderer.setRotationMatrix3(this._tempMatrix3);
+ }
+ /**
+ * Set the listener's position and orientation using a Three.js Matrix4 object.
+ * @param {Object} matrix4
+ * The Three.js Matrix4 object representing the listener's world transform.
+ */
+ setFromMatrix(matrix4) {
+ // Update ambisonic rotation matrix internally.
+ this._renderer.setRotationMatrix4(matrix4.elements);
+ // Extract position from matrix.
+ this.position[0] = matrix4.elements[12];
+ this.position[1] = matrix4.elements[13];
+ this.position[2] = matrix4.elements[14];
+ }
+}
+export default Listener;
diff --git a/src/framework/resonator/vendor/resonance-es6/main.d.ts b/src/framework/resonator/vendor/resonance-es6/main.d.ts
new file mode 100644
index 0000000..384e86e
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/main.d.ts
@@ -0,0 +1,2 @@
+export default ResonanceAudio;
+import ResonanceAudio from "./resonance-audio";
diff --git a/src/framework/resonator/vendor/resonance-es6/main.js b/src/framework/resonator/vendor/resonance-es6/main.js
new file mode 100644
index 0000000..8afdc68
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/main.js
@@ -0,0 +1,23 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file Primary namespace for ResonanceAudio library.
+ * @author Andrew Allen
+ */
+'use strict';
+import ResonanceAudio from './resonance-audio';
+// Main module.
+export default ResonanceAudio;
diff --git a/src/framework/resonator/vendor/resonance-es6/resonance-audio.d.ts b/src/framework/resonator/vendor/resonance-es6/resonance-audio.d.ts
new file mode 100644
index 0000000..7c2194e
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/resonance-audio.d.ts
@@ -0,0 +1,130 @@
+export default ResonanceAudio;
+/**
+ * ~ResonanceAudioOptions
+ */
+export type ResonanceAudio = {
+ /**
+ * Desired ambisonic Order. Defaults to
+ * {@link Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
+ */
+ ambisonicOrder: number;
+ /**
+ * The listener's initial position (in meters), where origin is the center of
+ * the room. Defaults to {@link Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ */
+ listenerPosition: Float32Array;
+ /**
+ * The listener's initial forward vector.
+ * Defaults to {@link Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
+ */
+ listenerForward: Float32Array;
+ /**
+ * The listener's initial up vector.
+ * Defaults to {@link Utils.DEFAULT_UP DEFAULT_UP}.
+ */
+ listenerUp: Float32Array;
+ /**
+ * ~RoomDimensions} dimensions Room dimensions (in meters). Defaults to
+ * {@link Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ */
+ "": Utils;
+ /**
+ * (in meters/second). Defaults to
+ * {@link Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}.
+ */
+ speedOfSound: number;
+};
+/**
+ * Options for constructing a new ResonanceAudio scene.
+ * @typedef {Object} ResonanceAudio~ResonanceAudioOptions
+ * @property {Number} ambisonicOrder
+ * Desired ambisonic Order. Defaults to
+ * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
+ * @property {Float32Array} listenerPosition
+ * The listener's initial position (in meters), where origin is the center of
+ * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ * @property {Float32Array} listenerForward
+ * The listener's initial forward vector.
+ * Defaults to {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
+ * @property {Float32Array} listenerUp
+ * The listener's initial up vector.
+ * Defaults to {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
+ * @property {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ * @property {Utils~RoomMaterials} materials Named acoustic materials per wall.
+ * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
+ * @property {Number} speedOfSound
+ * (in meters/second). Defaults to
+ * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}.
+ */
+/**
+ * @class ResonanceAudio
+ * @description Main class for managing sources, room and listener models.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {ResonanceAudio~ResonanceAudioOptions} options
+ * Options for constructing a new ResonanceAudio scene.
+ */
+declare class ResonanceAudio {
+ constructor(context: any, options: any);
+ _ambisonicOrder: number;
+ _sources: any[];
+ _room: Room;
+ _listener: Listener;
+ _context: any;
+ output: any;
+ ambisonicOutput: any;
+ ambisonicInput: any;
+ /**
+ * Create a new source for the scene.
+ * @param {Source~SourceOptions} options
+ * Options for constructing a new Source.
+ * @return {Source}
+ */
+ createSource(options: any): Source;
+ /**
+ * Set the scene's desired ambisonic order.
+ * @param {Number} ambisonicOrder Desired ambisonic order.
+ */
+ setAmbisonicOrder(ambisonicOrder: number): void;
+ /**
+ * Set the room's dimensions and wall materials.
+ * @param {Object} dimensions Room dimensions (in meters).
+ * @param {Object} materials Named acoustic materials per wall.
+ */
+ setRoomProperties(dimensions: any, materials: any): void;
+ /**
+ * Set the listener's position (in meters), where origin is the center of
+ * the room.
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ */
+ setListenerPosition(x: number, y: number, z: number): void;
+ /**
+ * Set the source's orientation using forward and up vectors.
+ * @param {Number} forwardX
+ * @param {Number} forwardY
+ * @param {Number} forwardZ
+ * @param {Number} upX
+ * @param {Number} upY
+ * @param {Number} upZ
+ */
+ setListenerOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
+ /**
+ * Set the listener's position and orientation using a Three.js Matrix4 object.
+ * @param {Object} matrix
+ * The Three.js Matrix4 object representing the listener's world transform.
+ */
+ setListenerFromMatrix(matrix: any): void;
+ /**
+ * Set the speed of sound.
+ * @param {Number} speedOfSound
+ */
+ setSpeedOfSound(speedOfSound: number): void;
+}
+import Utils from "./utils.js";
+import Room from "./room.js";
+import Listener from "./listener.js";
+import Source from "./source.js";
diff --git a/src/framework/resonator/vendor/resonance-es6/resonance-audio.js b/src/framework/resonator/vendor/resonance-es6/resonance-audio.js
new file mode 100644
index 0000000..32d14f3
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/resonance-audio.js
@@ -0,0 +1,213 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file ResonanceAudio library name space and common utilities.
+ * @author Andrew Allen
+ */
+'use strict';
+// Internal dependencies.
+import Listener from './listener.js';
+import Source from './source.js';
+import Room from './room.js';
+import Encoder from './encoder.js';
+import Utils from './utils.js';
+/**
+ * Options for constructing a new ResonanceAudio scene.
+ * @typedef {Object} ResonanceAudio~ResonanceAudioOptions
+ * @property {Number} ambisonicOrder
+ * Desired ambisonic Order. Defaults to
+ * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
+ * @property {Float32Array} listenerPosition
+ * The listener's initial position (in meters), where origin is the center of
+ * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ * @property {Float32Array} listenerForward
+ * The listener's initial forward vector.
+ * Defaults to {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
+ * @property {Float32Array} listenerUp
+ * The listener's initial up vector.
+ * Defaults to {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
+ * @property {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ * @property {Utils~RoomMaterials} materials Named acoustic materials per wall.
+ * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
+ * @property {Number} speedOfSound
+ * (in meters/second). Defaults to
+ * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}.
+ */
+/**
+ * @class ResonanceAudio
+ * @description Main class for managing sources, room and listener models.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {ResonanceAudio~ResonanceAudioOptions} options
+ * Options for constructing a new ResonanceAudio scene.
+ */
+class ResonanceAudio {
+ constructor(context, options) {
+ // Public variables.
+ /**
+ * Binaurally-rendered stereo (2-channel) output {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} output
+ * @memberof ResonanceAudio
+ * @instance
+ */
+ /**
+ * Ambisonic (multichannel) input {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}
+ * (For rendering input soundfields).
+ * @member {AudioNode} ambisonicInput
+ * @memberof ResonanceAudio
+ * @instance
+ */
+ /**
+ * Ambisonic (multichannel) output {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}
+ * (For allowing external rendering / post-processing).
+ * @member {AudioNode} ambisonicOutput
+ * @memberof ResonanceAudio
+ * @instance
+ */
+ // Use defaults for undefined arguments.
+ if (options == undefined) {
+ options = {};
+ }
+ if (options.ambisonicOrder == undefined) {
+ options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER;
+ }
+ if (options.listenerPosition == undefined) {
+ options.listenerPosition = Utils.DEFAULT_POSITION.slice();
+ }
+ if (options.listenerForward == undefined) {
+ options.listenerForward = Utils.DEFAULT_FORWARD.slice();
+ }
+ if (options.listenerUp == undefined) {
+ options.listenerUp = Utils.DEFAULT_UP.slice();
+ }
+ if (options.dimensions == undefined) {
+ options.dimensions = {};
+ Object.assign(options.dimensions, Utils.DEFAULT_ROOM_DIMENSIONS);
+ }
+ if (options.materials == undefined) {
+ options.materials = {};
+ Object.assign(options.materials, Utils.DEFAULT_ROOM_MATERIALS);
+ }
+ if (options.speedOfSound == undefined) {
+ options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND;
+ }
+ // Create member submodules.
+ this._ambisonicOrder = Encoder.validateAmbisonicOrder(options.ambisonicOrder);
+ this._sources = [];
+ this._room = new Room(context, {
+ listenerPosition: options.listenerPosition,
+ dimensions: options.dimensions,
+ materials: options.materials,
+ speedOfSound: options.speedOfSound,
+ });
+ this._listener = new Listener(context, {
+ ambisonicOrder: options.ambisonicOrder,
+ position: options.listenerPosition,
+ forward: options.listenerForward,
+ up: options.listenerUp,
+ });
+ // Create auxillary audio nodes.
+ this._context = context;
+ this.output = context.createGain();
+ this.ambisonicOutput = context.createGain();
+ this.ambisonicInput = this._listener.input;
+ // Connect audio graph.
+ this._room.output.connect(this._listener.input);
+ this._listener.output.connect(this.output);
+ this._listener.ambisonicOutput.connect(this.ambisonicOutput);
+ }
+ /**
+ * Create a new source for the scene.
+ * @param {Source~SourceOptions} options
+ * Options for constructing a new Source.
+ * @return {Source}
+ */
+ createSource(options) {
+ // Create a source and push it to the internal sources array, returning
+ // the object's reference to the user.
+ let source = new Source(this, options);
+ this._sources[this._sources.length] = source;
+ return source;
+ }
+ /**
+ * Set the scene's desired ambisonic order.
+ * @param {Number} ambisonicOrder Desired ambisonic order.
+ */
+ setAmbisonicOrder(ambisonicOrder) {
+ this._ambisonicOrder = Encoder.validateAmbisonicOrder(ambisonicOrder);
+ }
+ /**
+ * Set the room's dimensions and wall materials.
+ * @param {Object} dimensions Room dimensions (in meters).
+ * @param {Object} materials Named acoustic materials per wall.
+ */
+ setRoomProperties(dimensions, materials) {
+ this._room.setProperties(dimensions, materials);
+ }
+ /**
+ * Set the listener's position (in meters), where origin is the center of
+ * the room.
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ */
+ setListenerPosition(x, y, z) {
+ // Update listener position.
+ this._listener.position[0] = x;
+ this._listener.position[1] = y;
+ this._listener.position[2] = z;
+ this._room.setListenerPosition(x, y, z);
+ // Update sources with new listener position.
+ this._sources.forEach(element => {
+ element._update();
+ });
+ }
+ /**
+ * Set the source's orientation using forward and up vectors.
+ * @param {Number} forwardX
+ * @param {Number} forwardY
+ * @param {Number} forwardZ
+ * @param {Number} upX
+ * @param {Number} upY
+ * @param {Number} upZ
+ */
+ setListenerOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) {
+ this._listener.setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ);
+ }
+ /**
+ * Set the listener's position and orientation using a Three.js Matrix4 object.
+ * @param {Object} matrix
+ * The Three.js Matrix4 object representing the listener's world transform.
+ */
+ setListenerFromMatrix(matrix) {
+ this._listener.setFromMatrix(matrix);
+ // Update the rest of the scene using new listener position.
+ this.setListenerPosition(this._listener.position[0], this._listener.position[1], this._listener.position[2]);
+ }
+ /**
+ * Set the speed of sound.
+ * @param {Number} speedOfSound
+ */
+ setSpeedOfSound(speedOfSound) {
+ this._room.speedOfSound = speedOfSound;
+ }
+}
+export default ResonanceAudio;
diff --git a/src/framework/resonator/vendor/resonance-es6/room.d.ts b/src/framework/resonator/vendor/resonance-es6/room.d.ts
new file mode 100644
index 0000000..a04788c
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/room.d.ts
@@ -0,0 +1,55 @@
+export default Room;
+/**
+ * @class Room
+ * @description Model that manages early and late reflections using acoustic
+ * properties and listener position relative to a rectangular room.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Float32Array} options.listenerPosition
+ * The listener's initial position (in meters), where origin is the center of
+ * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ * @param {Utils~RoomDimensions} options.dimensions Room dimensions (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ * @param {Utils~RoomMaterials} options.materials Named acoustic materials per wall.
+ * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
+ * @param {Number} options.speedOfSound
+ * (in meters/second). Defaults to
+ * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}.
+ */
+declare class Room {
+ constructor(context: any, options: any);
+ early: EarlyReflections;
+ late: LateReflections;
+ speedOfSound: any;
+ output: any;
+ _merger: any;
+ /**
+ * Set the room's dimensions and wall materials.
+ * @param {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ * @param {Utils~RoomMaterials} materials Named acoustic materials per wall. Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
+ */
+ setProperties(dimensions: any, materials: any): void;
+ /**
+ * Set the listener's position (in meters), where origin is the center of
+ * the room.
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ */
+ setListenerPosition(x: number, y: number, z: number): void;
+ /**
+ * Compute distance outside room of provided position (in meters).
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ * @return {Number}
+ * Distance outside room (in meters). Returns 0 if inside room.
+ */
+ getDistanceOutsideRoom(x: number, y: number, z: number): number;
+}
+import EarlyReflections from "./early-reflections.js";
+import LateReflections from "./late-reflections.js";
diff --git a/src/framework/resonator/vendor/resonance-es6/room.js b/src/framework/resonator/vendor/resonance-es6/room.js
new file mode 100644
index 0000000..e2a54c5
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/room.js
@@ -0,0 +1,300 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file Complete room model with early and late reflections.
+ * @author Andrew Allen
+ */
+'use strict';
+// Internal dependencies.
+import LateReflections from './late-reflections.js';
+import EarlyReflections from './early-reflections.js';
+import Utils from './utils.js';
+/**
+ * Generate absorption coefficients from material names.
+ * @param {Object} materials
+ * @return {Object}
+ */
+function _getCoefficientsFromMaterials(materials) {
+ // Initialize coefficients to use defaults.
+ let coefficients = {};
+ for (let property in Utils.DEFAULT_ROOM_MATERIALS) {
+ if (Utils.DEFAULT_ROOM_MATERIALS.hasOwnProperty(property)) {
+ coefficients[property] = Utils.ROOM_MATERIAL_COEFFICIENTS[Utils.DEFAULT_ROOM_MATERIALS[property]];
+ }
+ }
+ // Sanitize materials.
+ if (materials == undefined) {
+ materials = {};
+ Object.assign(materials, Utils.DEFAULT_ROOM_MATERIALS);
+ }
+ // Assign coefficients using provided materials.
+ for (let property in Utils.DEFAULT_ROOM_MATERIALS) {
+ if (Utils.DEFAULT_ROOM_MATERIALS.hasOwnProperty(property) &&
+ materials.hasOwnProperty(property)) {
+ if (materials[property] in Utils.ROOM_MATERIAL_COEFFICIENTS) {
+ coefficients[property] =
+ Utils.ROOM_MATERIAL_COEFFICIENTS[materials[property]];
+ }
+ else {
+ Utils.log('Material \"' + materials[property] + '\" on wall \"' +
+ property + '\" not found. Using \"' +
+ Utils.DEFAULT_ROOM_MATERIALS[property] + '\".');
+ }
+ }
+ else {
+ Utils.log('Wall \"' + property + '\" is not defined. Default used.');
+ }
+ }
+ return coefficients;
+}
+/**
+ * Sanitize coefficients.
+ * @param {Object} coefficients
+ * @return {Object}
+ */
+function _sanitizeCoefficients(coefficients) {
+ if (coefficients == undefined) {
+ coefficients = {};
+ }
+ for (let property in Utils.DEFAULT_ROOM_MATERIALS) {
+ if (!(coefficients.hasOwnProperty(property))) {
+ // If element is not present, use default coefficients.
+ coefficients[property] = Utils.ROOM_MATERIAL_COEFFICIENTS[Utils.DEFAULT_ROOM_MATERIALS[property]];
+ }
+ }
+ return coefficients;
+}
+/**
+ * Sanitize dimensions.
+ * @param {Utils~RoomDimensions} dimensions
+ * @return {Utils~RoomDimensions}
+ */
+function _sanitizeDimensions(dimensions) {
+ if (dimensions == undefined) {
+ dimensions = {};
+ }
+ for (let property in Utils.DEFAULT_ROOM_DIMENSIONS) {
+ if (!(dimensions.hasOwnProperty(property))) {
+ dimensions[property] = Utils.DEFAULT_ROOM_DIMENSIONS[property];
+ }
+ }
+ return dimensions;
+}
+/**
+ * Compute frequency-dependent reverb durations.
+ * @param {Utils~RoomDimensions} dimensions
+ * @param {Object} coefficients
+ * @param {Number} speedOfSound
+ * @return {Array}
+ */
+function _getDurationsFromProperties(dimensions, coefficients, speedOfSound) {
+ let durations = new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS);
+ // Sanitize inputs.
+ dimensions = _sanitizeDimensions(dimensions);
+ coefficients = _sanitizeCoefficients(coefficients);
+ if (speedOfSound == undefined) {
+ speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND;
+ }
+ // Acoustic constant.
+ let k = Utils.TWENTY_FOUR_LOG10 / speedOfSound;
+ // Compute volume, skip if room is not present.
+ let volume = dimensions.width * dimensions.height * dimensions.depth;
+ if (volume < Utils.ROOM_MIN_VOLUME) {
+ return durations;
+ }
+ // Room surface area.
+ let leftRightArea = dimensions.width * dimensions.height;
+ let floorCeilingArea = dimensions.width * dimensions.depth;
+ let frontBackArea = dimensions.depth * dimensions.height;
+ let totalArea = 2 * (leftRightArea + floorCeilingArea + frontBackArea);
+ for (let i = 0; i < Utils.NUMBER_REVERB_FREQUENCY_BANDS; i++) {
+ // Effective absorptive area.
+ let absorbtionArea = (coefficients.left[i] + coefficients.right[i]) * leftRightArea +
+ (coefficients.down[i] + coefficients.up[i]) * floorCeilingArea +
+ (coefficients.front[i] + coefficients.back[i]) * frontBackArea;
+ let meanAbsorbtionArea = absorbtionArea / totalArea;
+ // Compute reverberation using Eyring equation [1].
+ // [1] Beranek, Leo L. "Analysis of Sabine and Eyring equations and their
+ // application to concert hall audience and chair absorption." The
+ // Journal of the Acoustical Society of America, Vol. 120, No. 3.
+ // (2006), pp. 1399-1399.
+ durations[i] = Utils.ROOM_EYRING_CORRECTION_COEFFICIENT * k * volume /
+ (-totalArea * Math.log(1 - meanAbsorbtionArea) + 4 *
+ Utils.ROOM_AIR_ABSORPTION_COEFFICIENTS[i] * volume);
+ }
+ return durations;
+}
+/**
+ * Compute reflection coefficients from absorption coefficients.
+ * @param {Object} absorptionCoefficients
+ * @return {Object}
+ */
+function _computeReflectionCoefficients(absorptionCoefficients) {
+ let reflectionCoefficients = [];
+ for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) {
+ if (Utils.DEFAULT_REFLECTION_COEFFICIENTS
+ .hasOwnProperty(property)) {
+ // Compute average absorption coefficient (per wall).
+ reflectionCoefficients[property] = 0;
+ for (let j = 0; j < Utils.NUMBER_REFLECTION_AVERAGING_BANDS; j++) {
+ let bandIndex = j + Utils.ROOM_STARTING_AVERAGING_BAND;
+ reflectionCoefficients[property] +=
+ absorptionCoefficients[property][bandIndex];
+ }
+ reflectionCoefficients[property] /=
+ Utils.NUMBER_REFLECTION_AVERAGING_BANDS;
+ // Convert absorption coefficient to reflection coefficient.
+ reflectionCoefficients[property] =
+ Math.sqrt(1 - reflectionCoefficients[property]);
+ }
+ }
+ return reflectionCoefficients;
+}
+/**
+ * @class Room
+ * @description Model that manages early and late reflections using acoustic
+ * properties and listener position relative to a rectangular room.
+ * @param {AudioContext} context
+ * Associated {@link
+https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
+ * @param {Object} options
+ * @param {Float32Array} options.listenerPosition
+ * The listener's initial position (in meters), where origin is the center of
+ * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ * @param {Utils~RoomDimensions} options.dimensions Room dimensions (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ * @param {Utils~RoomMaterials} options.materials Named acoustic materials per wall.
+ * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
+ * @param {Number} options.speedOfSound
+ * (in meters/second). Defaults to
+ * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}.
+ */
+class Room {
+ constructor(context, options) {
+ // Public variables.
+ /**
+ * EarlyReflections {@link EarlyReflections EarlyReflections} submodule.
+ * @member {AudioNode} early
+ * @memberof Room
+ * @instance
+ */
+ /**
+ * LateReflections {@link LateReflections LateReflections} submodule.
+ * @member {AudioNode} late
+ * @memberof Room
+ * @instance
+ */
+ /**
+ * Ambisonic (multichannel) output {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} output
+ * @memberof Room
+ * @instance
+ */
+ // Use defaults for undefined arguments.
+ if (options == undefined) {
+ options = {};
+ }
+ if (options.listenerPosition == undefined) {
+ options.listenerPosition = Utils.DEFAULT_POSITION.slice();
+ }
+ if (options.dimensions == undefined) {
+ options.dimensions = {};
+ Object.assign(options.dimensions, Utils.DEFAULT_ROOM_DIMENSIONS);
+ }
+ if (options.materials == undefined) {
+ options.materials = {};
+ Object.assign(options.materials, Utils.DEFAULT_ROOM_MATERIALS);
+ }
+ if (options.speedOfSound == undefined) {
+ options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND;
+ }
+ // Sanitize room-properties-related arguments.
+ options.dimensions = _sanitizeDimensions(options.dimensions);
+ let absorptionCoefficients = _getCoefficientsFromMaterials(options.materials);
+ let reflectionCoefficients = _computeReflectionCoefficients(absorptionCoefficients);
+ let durations = _getDurationsFromProperties(options.dimensions, absorptionCoefficients, options.speedOfSound);
+ // Construct submodules for early and late reflections.
+ this.early = new EarlyReflections(context, {
+ dimensions: options.dimensions,
+ coefficients: reflectionCoefficients,
+ speedOfSound: options.speedOfSound,
+ listenerPosition: options.listenerPosition,
+ });
+ this.late = new LateReflections(context, {
+ durations: durations,
+ });
+ this.speedOfSound = options.speedOfSound;
+ // Construct auxillary audio nodes.
+ this.output = context.createGain();
+ this.early.output.connect(this.output);
+ this._merger = context.createChannelMerger(4);
+ this.late.output.connect(this._merger, 0, 0);
+ this._merger.connect(this.output);
+ }
+ /**
+ * Set the room's dimensions and wall materials.
+ * @param {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
+ * @param {Utils~RoomMaterials} materials Named acoustic materials per wall. Defaults to
+ * {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
+ */
+ setProperties(dimensions, materials) {
+ // Compute late response.
+ let absorptionCoefficients = _getCoefficientsFromMaterials(materials);
+ let durations = _getDurationsFromProperties(dimensions, absorptionCoefficients, this.speedOfSound);
+ this.late.setDurations(durations);
+ // Compute early response.
+ this.early.speedOfSound = this.speedOfSound;
+ let reflectionCoefficients = _computeReflectionCoefficients(absorptionCoefficients);
+ this.early.setRoomProperties(dimensions, reflectionCoefficients);
+ }
+ /**
+ * Set the listener's position (in meters), where origin is the center of
+ * the room.
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ */
+ setListenerPosition(x, y, z) {
+ this.early.speedOfSound = this.speedOfSound;
+ this.early.setListenerPosition(x, y, z);
+ // Disable room effects if the listener is outside the room boundaries.
+ let distance = this.getDistanceOutsideRoom(x, y, z);
+ let gain = 1;
+ if (distance > Utils.EPSILON_FLOAT) {
+ gain = 1 - distance / Utils.LISTENER_MAX_OUTSIDE_ROOM_DISTANCE;
+ // Clamp gain between 0 and 1.
+ gain = Math.max(0, Math.min(1, gain));
+ }
+ this.output.gain.value = gain;
+ }
+ /**
+ * Compute distance outside room of provided position (in meters).
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ * @return {Number}
+ * Distance outside room (in meters). Returns 0 if inside room.
+ */
+ getDistanceOutsideRoom(x, y, z) {
+ let dx = Math.max(0, -this.early._halfDimensions.width - x, x - this.early._halfDimensions.width);
+ let dy = Math.max(0, -this.early._halfDimensions.height - y, y - this.early._halfDimensions.height);
+ let dz = Math.max(0, -this.early._halfDimensions.depth - z, z - this.early._halfDimensions.depth);
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
+ }
+}
+export default Room;
diff --git a/src/framework/resonator/vendor/resonance-es6/source.d.ts b/src/framework/resonator/vendor/resonance-es6/source.d.ts
new file mode 100644
index 0000000..bf24786
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/source.d.ts
@@ -0,0 +1,182 @@
+export default Source;
+/**
+ * ~SourceOptions
+ */
+export type Source = {
+ /**
+ * The source's initial position (in meters), where origin is the center of
+ * the room. Defaults to {@link Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ */
+ position: Float32Array;
+ /**
+ * The source's initial forward vector. Defaults to
+ * {@link Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
+ */
+ forward: Float32Array;
+ /**
+ * The source's initial up vector. Defaults to
+ * {@link Utils.DEFAULT_UP DEFAULT_UP}.
+ */
+ up: Float32Array;
+ /**
+ * Min. distance (in meters). Defaults to
+ * {@link Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}.
+ */
+ minDistance: number;
+ /**
+ * Max. distance (in meters). Defaults to
+ * {@link Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}.
+ */
+ maxDistance: number;
+ /**
+ * Rolloff model to use, chosen from options in
+ * {@link Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to
+ * {@link Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}.
+ */
+ rolloff: string;
+ /**
+ * Input gain (linear). Defaults to
+ * {@link Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}.
+ */
+ gain: number;
+ /**
+ * Directivity alpha. Defaults to
+ * {@link Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
+ */
+ alpha: number;
+ /**
+ * Directivity sharpness. Defaults to
+ * {@link Utils.DEFAULT_DIRECTIVITY_SHARPNESS * DEFAULT_DIRECTIVITY_SHARPNESS}.
+ */
+ sharpness: number;
+ /**
+ * Source width (in degrees). Where 0 degrees is a point source and 360 degrees
+ * is an omnidirectional source. Defaults to
+ * {@link Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
+ */
+ sourceWidth: number;
+};
+/**
+ * Options for constructing a new Source.
+ * @typedef {Object} Source~SourceOptions
+ * @property {Float32Array} position
+ * The source's initial position (in meters), where origin is the center of
+ * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ * @property {Float32Array} forward
+ * The source's initial forward vector. Defaults to
+ * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
+ * @property {Float32Array} up
+ * The source's initial up vector. Defaults to
+ * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
+ * @property {Number} minDistance
+ * Min. distance (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}.
+ * @property {Number} maxDistance
+ * Max. distance (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}.
+ * @property {string} rolloff
+ * Rolloff model to use, chosen from options in
+ * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to
+ * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}.
+ * @property {Number} gain Input gain (linear). Defaults to
+ * {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}.
+ * @property {Number} alpha Directivity alpha. Defaults to
+ * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
+ * @property {Number} sharpness Directivity sharpness. Defaults to
+ * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS
+ * DEFAULT_DIRECTIVITY_SHARPNESS}.
+ * @property {Number} sourceWidth
+ * Source width (in degrees). Where 0 degrees is a point source and 360 degrees
+ * is an omnidirectional source. Defaults to
+ * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
+ */
+/**
+ * @class Source
+ * @description Source model to spatialize an audio buffer.
+ * @param {ResonanceAudio} scene Associated {@link ResonanceAudio
+ * ResonanceAudio} instance.
+ * @param {Source~SourceOptions} options
+ * Options for constructing a new Source.
+ */
+declare class Source {
+ constructor(scene: any, options: any);
+ _scene: any;
+ _position: any;
+ _forward: any;
+ _up: any;
+ _dx: Float32Array;
+ _right: Float32Array;
+ input: any;
+ _directivity: Directivity;
+ _toEarly: any;
+ _toLate: any;
+ _attenuation: Attenuation;
+ _encoder: Encoder;
+ /**
+ * Set source's position (in meters), where origin is the center of
+ * the room.
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ */
+ setPosition(x: number, y: number, z: number): void;
+ _update(): void;
+ /**
+ * Set source's rolloff.
+ * @param {string} rolloff
+ * Rolloff model to use, chosen from options in
+ * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}.
+ */
+ setRolloff(rolloff: string): void;
+ /**
+ * Set source's minimum distance (in meters).
+ * @param {Number} minDistance
+ */
+ setMinDistance(minDistance: number): void;
+ /**
+ * Set source's maximum distance (in meters).
+ * @param {Number} maxDistance
+ */
+ setMaxDistance(maxDistance: number): void;
+ /**
+ * Set source's gain (linear).
+ * @param {Number} gain
+ */
+ setGain(gain: number): void;
+ /**
+ * Set the source's orientation using forward and up vectors.
+ * @param {Number} forwardX
+ * @param {Number} forwardY
+ * @param {Number} forwardZ
+ * @param {Number} upX
+ * @param {Number} upY
+ * @param {Number} upZ
+ */
+ setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
+ /**
+ * Set source's position and orientation using a
+ * Three.js modelViewMatrix object.
+ * @param {Float32Array} matrix4
+ * The Matrix4 representing the object position and rotation in world space.
+ */
+ setFromMatrix(matrix4: Float32Array): void;
+ /**
+ * Set the source width (in degrees). Where 0 degrees is a point source and 360
+ * degrees is an omnidirectional source.
+ * @param {Number} sourceWidth (in degrees).
+ */
+ setSourceWidth(sourceWidth: number): void;
+ /**
+ * Set source's directivity pattern (defined by alpha), where 0 is an
+ * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
+ * pattern. The sharpness of the pattern is increased exponentially.
+ * @param {Number} alpha
+ * Determines directivity pattern (0 to 1).
+ * @param {Number} sharpness
+ * Determines the sharpness of the directivity pattern (1 to Inf).
+ */
+ setDirectivityPattern(alpha: number, sharpness: number): void;
+}
+import Directivity from "./directivity.js";
+import Attenuation from "./attenuation.js";
+import Encoder from "./encoder.js";
diff --git a/src/framework/resonator/vendor/resonance-es6/source.js b/src/framework/resonator/vendor/resonance-es6/source.js
new file mode 100644
index 0000000..510a9ca
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/source.js
@@ -0,0 +1,308 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file Source model to spatialize an audio buffer.
+ * @author Andrew Allen
+ */
+'use strict';
+// Internal dependencies.
+import Directivity from './directivity.js';
+import Attenuation from './attenuation.js';
+import Encoder from './encoder.js';
+import Utils from './utils.js';
+/**
+ * Options for constructing a new Source.
+ * @typedef {Object} Source~SourceOptions
+ * @property {Float32Array} position
+ * The source's initial position (in meters), where origin is the center of
+ * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
+ * @property {Float32Array} forward
+ * The source's initial forward vector. Defaults to
+ * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
+ * @property {Float32Array} up
+ * The source's initial up vector. Defaults to
+ * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
+ * @property {Number} minDistance
+ * Min. distance (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}.
+ * @property {Number} maxDistance
+ * Max. distance (in meters). Defaults to
+ * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}.
+ * @property {string} rolloff
+ * Rolloff model to use, chosen from options in
+ * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to
+ * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}.
+ * @property {Number} gain Input gain (linear). Defaults to
+ * {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}.
+ * @property {Number} alpha Directivity alpha. Defaults to
+ * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
+ * @property {Number} sharpness Directivity sharpness. Defaults to
+ * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS
+ * DEFAULT_DIRECTIVITY_SHARPNESS}.
+ * @property {Number} sourceWidth
+ * Source width (in degrees). Where 0 degrees is a point source and 360 degrees
+ * is an omnidirectional source. Defaults to
+ * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
+ */
+/**
+ * @class Source
+ * @description Source model to spatialize an audio buffer.
+ * @param {ResonanceAudio} scene Associated {@link ResonanceAudio
+ * ResonanceAudio} instance.
+ * @param {Source~SourceOptions} options
+ * Options for constructing a new Source.
+ */
+class Source {
+ constructor(scene, options) {
+ // Public variables.
+ /**
+ * Mono (1-channel) input {@link
+ * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
+ * @member {AudioNode} input
+ * @memberof Source
+ * @instance
+ */
+ /**
+ *
+ */
+ // Use defaults for undefined arguments.
+ if (options == undefined) {
+ options = {};
+ }
+ if (options.position == undefined) {
+ options.position = Utils.DEFAULT_POSITION.slice();
+ }
+ if (options.forward == undefined) {
+ options.forward = Utils.DEFAULT_FORWARD.slice();
+ }
+ if (options.up == undefined) {
+ options.up = Utils.DEFAULT_UP.slice();
+ }
+ if (options.minDistance == undefined) {
+ options.minDistance = Utils.DEFAULT_MIN_DISTANCE;
+ }
+ if (options.maxDistance == undefined) {
+ options.maxDistance = Utils.DEFAULT_MAX_DISTANCE;
+ }
+ if (options.rolloff == undefined) {
+ options.rolloff = Utils.DEFAULT_ROLLOFF;
+ }
+ if (options.gain == undefined) {
+ options.gain = Utils.DEFAULT_SOURCE_GAIN;
+ }
+ if (options.alpha == undefined) {
+ options.alpha = Utils.DEFAULT_DIRECTIVITY_ALPHA;
+ }
+ if (options.sharpness == undefined) {
+ options.sharpness = Utils.DEFAULT_DIRECTIVITY_SHARPNESS;
+ }
+ if (options.sourceWidth == undefined) {
+ options.sourceWidth = Utils.DEFAULT_SOURCE_WIDTH;
+ }
+ // Member variables.
+ this._scene = scene;
+ this._position = options.position;
+ this._forward = options.forward;
+ this._up = options.up;
+ this._dx = new Float32Array(3);
+ this._right = Utils.crossProduct(this._forward, this._up);
+ // Create audio nodes.
+ let context = scene._context;
+ this.input = context.createGain();
+ this._directivity = new Directivity(context, {
+ alpha: options.alpha,
+ sharpness: options.sharpness,
+ });
+ this._toEarly = context.createGain();
+ this._toLate = context.createGain();
+ this._attenuation = new Attenuation(context, {
+ minDistance: options.minDistance,
+ maxDistance: options.maxDistance,
+ rolloff: options.rolloff,
+ });
+ this._encoder = new Encoder(context, {
+ ambisonicOrder: scene._ambisonicOrder,
+ sourceWidth: options.sourceWidth,
+ });
+ // Connect nodes.
+ this.input.connect(this._toLate);
+ this._toLate.connect(scene._room.late.input);
+ this.input.connect(this._attenuation.input);
+ this._attenuation.output.connect(this._toEarly);
+ this._toEarly.connect(scene._room.early.input);
+ this._attenuation.output.connect(this._directivity.input);
+ this._directivity.output.connect(this._encoder.input);
+ this._encoder.output.connect(scene._listener.input);
+ // Assign initial conditions.
+ this.setPosition(options.position[0], options.position[1], options.position[2]);
+ this.input.gain.value = options.gain;
+ }
+ /**
+ * Set source's position (in meters), where origin is the center of
+ * the room.
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} z
+ */
+ setPosition(x, y, z) {
+ // Assign new position.
+ this._position[0] = x;
+ this._position[1] = y;
+ this._position[2] = z;
+ // Handle far-field effect.
+ let distance = this._scene._room.getDistanceOutsideRoom(this._position[0], this._position[1], this._position[2]);
+ let gain = _computeDistanceOutsideRoom(distance);
+ this._toLate.gain.value = gain;
+ this._toEarly.gain.value = gain;
+ this._update();
+ }
+ // Update the source when changing the listener's position.
+ _update() {
+ // Compute distance to listener.
+ for (let i = 0; i < 3; i++) {
+ this._dx[i] = this._position[i] - this._scene._listener.position[i];
+ }
+ let distance = Math.sqrt(this._dx[0] * this._dx[0] +
+ this._dx[1] * this._dx[1] + this._dx[2] * this._dx[2]);
+ if (distance > 0) {
+ // Normalize direction vector.
+ this._dx[0] /= distance;
+ this._dx[1] /= distance;
+ this._dx[2] /= distance;
+ }
+ // Compuete angle of direction vector.
+ let azimuth = Math.atan2(-this._dx[0], this._dx[2]) *
+ Utils.RADIANS_TO_DEGREES;
+ let elevation = Math.atan2(this._dx[1], Math.sqrt(this._dx[0] * this._dx[0] +
+ this._dx[2] * this._dx[2])) * Utils.RADIANS_TO_DEGREES;
+ // Set distance/directivity/direction values.
+ this._attenuation.setDistance(distance);
+ this._directivity.computeAngle(this._forward, this._dx);
+ this._encoder.setDirection(azimuth, elevation);
+ }
+ /**
+ * Set source's rolloff.
+ * @param {string} rolloff
+ * Rolloff model to use, chosen from options in
+ * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}.
+ */
+ setRolloff(rolloff) {
+ this._attenuation.setRolloff(rolloff);
+ }
+ /**
+ * Set source's minimum distance (in meters).
+ * @param {Number} minDistance
+ */
+ setMinDistance(minDistance) {
+ this._attenuation.minDistance = minDistance;
+ }
+ /**
+ * Set source's maximum distance (in meters).
+ * @param {Number} maxDistance
+ */
+ setMaxDistance(maxDistance) {
+ this._attenuation.maxDistance = maxDistance;
+ }
+ /**
+ * Set source's gain (linear).
+ * @param {Number} gain
+ */
+ setGain(gain) {
+ this.input.gain.value = gain;
+ }
+ /**
+ * Set the source's orientation using forward and up vectors.
+ * @param {Number} forwardX
+ * @param {Number} forwardY
+ * @param {Number} forwardZ
+ * @param {Number} upX
+ * @param {Number} upY
+ * @param {Number} upZ
+ */
+ setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) {
+ this._forward[0] = forwardX;
+ this._forward[1] = forwardY;
+ this._forward[2] = forwardZ;
+ this._up[0] = upX;
+ this._up[1] = upY;
+ this._up[2] = upZ;
+ this._right = Utils.crossProduct(this._forward, this._up);
+ }
+ // TODO(bitllama): Make sure this works with Three.js as intended.
+ /**
+ * Set source's position and orientation using a
+ * Three.js modelViewMatrix object.
+ * @param {Float32Array} matrix4
+ * The Matrix4 representing the object position and rotation in world space.
+ */
+ setFromMatrix(matrix4) {
+ this._right[0] = matrix4.elements[0];
+ this._right[1] = matrix4.elements[1];
+ this._right[2] = matrix4.elements[2];
+ this._up[0] = matrix4.elements[4];
+ this._up[1] = matrix4.elements[5];
+ this._up[2] = matrix4.elements[6];
+ this._forward[0] = matrix4.elements[8];
+ this._forward[1] = matrix4.elements[9];
+ this._forward[2] = matrix4.elements[10];
+ // Normalize to remove scaling.
+ this._right = Utils.normalizeVector(this._right);
+ this._up = Utils.normalizeVector(this._up);
+ this._forward = Utils.normalizeVector(this._forward);
+ // Update position.
+ this.setPosition(matrix4.elements[12], matrix4.elements[13], matrix4.elements[14]);
+ }
+ /**
+ * Set the source width (in degrees). Where 0 degrees is a point source and 360
+ * degrees is an omnidirectional source.
+ * @param {Number} sourceWidth (in degrees).
+ */
+ setSourceWidth(sourceWidth) {
+ this._encoder.setSourceWidth(sourceWidth);
+ this.setPosition(this._position[0], this._position[1], this._position[2]);
+ }
+ /**
+ * Set source's directivity pattern (defined by alpha), where 0 is an
+ * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
+ * pattern. The sharpness of the pattern is increased exponentially.
+ * @param {Number} alpha
+ * Determines directivity pattern (0 to 1).
+ * @param {Number} sharpness
+ * Determines the sharpness of the directivity pattern (1 to Inf).
+ */
+ setDirectivityPattern(alpha, sharpness) {
+ this._directivity.setPattern(alpha, sharpness);
+ this.setPosition(this._position[0], this._position[1], this._position[2]);
+ }
+}
+/**
+ * Determine the distance a source is outside of a room. Attenuate gain going
+ * to the reflections and reverb when the source is outside of the room.
+ * @param {Number} distance Distance in meters.
+ * @return {Number} Gain (linear) of source.
+ * @private
+ */
+function _computeDistanceOutsideRoom(distance) {
+ // We apply a linear ramp from 1 to 0 as the source is up to 1m outside.
+ let gain = 1;
+ if (distance > Utils.EPSILON_FLOAT) {
+ gain = 1 - distance / Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE;
+ // Clamp gain between 0 and 1.
+ gain = Math.max(0, Math.min(1, gain));
+ }
+ return gain;
+}
+export default Source;
diff --git a/src/framework/resonator/vendor/resonance-es6/tables.d.ts b/src/framework/resonator/vendor/resonance-es6/tables.d.ts
new file mode 100644
index 0000000..4116808
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/tables.d.ts
@@ -0,0 +1,38 @@
+declare namespace _default {
+ export { SPHERICAL_HARMONICS };
+ export { SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION };
+ export { SPHERICAL_HARMONICS_ELEVATION_RESOLUTION };
+ export { SPHERICAL_HARMONICS_MAX_ORDER };
+ export { MAX_RE_WEIGHTS };
+ export { MAX_RE_WEIGHTS_RESOLUTION };
+}
+export default _default;
+/**
+ * Pre-computed Spherical Harmonics Coefficients.
+ *
+ * This function generates an efficient lookup table of SH coefficients. It
+ * exploits the way SHs are generated (i.e. Ylm = Nlm * Plm * Em). Since Nlm
+ * & Plm coefficients only depend on theta, and Em only depends on phi, we
+ * can separate the equation along these lines. Em does not depend on
+ * degree, so we only need to compute (2 * l) per azimuth Em total and
+ * Nlm * Plm is symmetrical across indexes, so only positive indexes are
+ * computed ((l + 1) * (l + 2) / 2 - 1) per elevation.
+ * @type {Float32Array}
+ */
+declare const SPHERICAL_HARMONICS: Float32Array;
+/** @type {Number} */
+declare const SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION: number;
+/** @type {Number} */
+declare const SPHERICAL_HARMONICS_ELEVATION_RESOLUTION: number;
+/**
+ * The maximum allowed ambisonic order.
+ * @type {Number}
+ */
+declare const SPHERICAL_HARMONICS_MAX_ORDER: number;
+/**
+ * Pre-computed per-band weighting coefficients for producing energy-preserving
+ * Max-Re sources.
+ */
+declare const MAX_RE_WEIGHTS: number[][];
+/** @type {Number} */
+declare const MAX_RE_WEIGHTS_RESOLUTION: number;
diff --git a/src/framework/resonator/vendor/resonance-es6/tables.js b/src/framework/resonator/vendor/resonance-es6/tables.js
new file mode 100644
index 0000000..90117bf
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/tables.js
@@ -0,0 +1,1144 @@
+/**
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file Pre-computed lookup tables for encoding ambisonic sources.
+ * @author Andrew Allen
+ */
+'use strict';
+/**
+ * Pre-computed Spherical Harmonics Coefficients.
+ *
+ * This function generates an efficient lookup table of SH coefficients. It
+ * exploits the way SHs are generated (i.e. Ylm = Nlm * Plm * Em). Since Nlm
+ * & Plm coefficients only depend on theta, and Em only depends on phi, we
+ * can separate the equation along these lines. Em does not depend on
+ * degree, so we only need to compute (2 * l) per azimuth Em total and
+ * Nlm * Plm is symmetrical across indexes, so only positive indexes are
+ * computed ((l + 1) * (l + 2) / 2 - 1) per elevation.
+ * @type {Float32Array}
+ */
+const SPHERICAL_HARMONICS = [
+ [
+ [0.000000, 0.000000, 0.000000, 1.000000, 1.000000, 1.000000],
+ [0.052336, 0.034899, 0.017452, 0.999848, 0.999391, 0.998630],
+ [0.104528, 0.069756, 0.034899, 0.999391, 0.997564, 0.994522],
+ [0.156434, 0.104528, 0.052336, 0.998630, 0.994522, 0.987688],
+ [0.207912, 0.139173, 0.069756, 0.997564, 0.990268, 0.978148],
+ [0.258819, 0.173648, 0.087156, 0.996195, 0.984808, 0.965926],
+ [0.309017, 0.207912, 0.104528, 0.994522, 0.978148, 0.951057],
+ [0.358368, 0.241922, 0.121869, 0.992546, 0.970296, 0.933580],
+ [0.406737, 0.275637, 0.139173, 0.990268, 0.961262, 0.913545],
+ [0.453990, 0.309017, 0.156434, 0.987688, 0.951057, 0.891007],
+ [0.500000, 0.342020, 0.173648, 0.984808, 0.939693, 0.866025],
+ [0.544639, 0.374607, 0.190809, 0.981627, 0.927184, 0.838671],
+ [0.587785, 0.406737, 0.207912, 0.978148, 0.913545, 0.809017],
+ [0.629320, 0.438371, 0.224951, 0.974370, 0.898794, 0.777146],
+ [0.669131, 0.469472, 0.241922, 0.970296, 0.882948, 0.743145],
+ [0.707107, 0.500000, 0.258819, 0.965926, 0.866025, 0.707107],
+ [0.743145, 0.529919, 0.275637, 0.961262, 0.848048, 0.669131],
+ [0.777146, 0.559193, 0.292372, 0.956305, 0.829038, 0.629320],
+ [0.809017, 0.587785, 0.309017, 0.951057, 0.809017, 0.587785],
+ [0.838671, 0.615661, 0.325568, 0.945519, 0.788011, 0.544639],
+ [0.866025, 0.642788, 0.342020, 0.939693, 0.766044, 0.500000],
+ [0.891007, 0.669131, 0.358368, 0.933580, 0.743145, 0.453990],
+ [0.913545, 0.694658, 0.374607, 0.927184, 0.719340, 0.406737],
+ [0.933580, 0.719340, 0.390731, 0.920505, 0.694658, 0.358368],
+ [0.951057, 0.743145, 0.406737, 0.913545, 0.669131, 0.309017],
+ [0.965926, 0.766044, 0.422618, 0.906308, 0.642788, 0.258819],
+ [0.978148, 0.788011, 0.438371, 0.898794, 0.615661, 0.207912],
+ [0.987688, 0.809017, 0.453990, 0.891007, 0.587785, 0.156434],
+ [0.994522, 0.829038, 0.469472, 0.882948, 0.559193, 0.104528],
+ [0.998630, 0.848048, 0.484810, 0.874620, 0.529919, 0.052336],
+ [1.000000, 0.866025, 0.500000, 0.866025, 0.500000, 0.000000],
+ [0.998630, 0.882948, 0.515038, 0.857167, 0.469472, -0.052336],
+ [0.994522, 0.898794, 0.529919, 0.848048, 0.438371, -0.104528],
+ [0.987688, 0.913545, 0.544639, 0.838671, 0.406737, -0.156434],
+ [0.978148, 0.927184, 0.559193, 0.829038, 0.374607, -0.207912],
+ [0.965926, 0.939693, 0.573576, 0.819152, 0.342020, -0.258819],
+ [0.951057, 0.951057, 0.587785, 0.809017, 0.309017, -0.309017],
+ [0.933580, 0.961262, 0.601815, 0.798636, 0.275637, -0.358368],
+ [0.913545, 0.970296, 0.615661, 0.788011, 0.241922, -0.406737],
+ [0.891007, 0.978148, 0.629320, 0.777146, 0.207912, -0.453990],
+ [0.866025, 0.984808, 0.642788, 0.766044, 0.173648, -0.500000],
+ [0.838671, 0.990268, 0.656059, 0.754710, 0.139173, -0.544639],
+ [0.809017, 0.994522, 0.669131, 0.743145, 0.104528, -0.587785],
+ [0.777146, 0.997564, 0.681998, 0.731354, 0.069756, -0.629320],
+ [0.743145, 0.999391, 0.694658, 0.719340, 0.034899, -0.669131],
+ [0.707107, 1.000000, 0.707107, 0.707107, 0.000000, -0.707107],
+ [0.669131, 0.999391, 0.719340, 0.694658, -0.034899, -0.743145],
+ [0.629320, 0.997564, 0.731354, 0.681998, -0.069756, -0.777146],
+ [0.587785, 0.994522, 0.743145, 0.669131, -0.104528, -0.809017],
+ [0.544639, 0.990268, 0.754710, 0.656059, -0.139173, -0.838671],
+ [0.500000, 0.984808, 0.766044, 0.642788, -0.173648, -0.866025],
+ [0.453990, 0.978148, 0.777146, 0.629320, -0.207912, -0.891007],
+ [0.406737, 0.970296, 0.788011, 0.615661, -0.241922, -0.913545],
+ [0.358368, 0.961262, 0.798636, 0.601815, -0.275637, -0.933580],
+ [0.309017, 0.951057, 0.809017, 0.587785, -0.309017, -0.951057],
+ [0.258819, 0.939693, 0.819152, 0.573576, -0.342020, -0.965926],
+ [0.207912, 0.927184, 0.829038, 0.559193, -0.374607, -0.978148],
+ [0.156434, 0.913545, 0.838671, 0.544639, -0.406737, -0.987688],
+ [0.104528, 0.898794, 0.848048, 0.529919, -0.438371, -0.994522],
+ [0.052336, 0.882948, 0.857167, 0.515038, -0.469472, -0.998630],
+ [0.000000, 0.866025, 0.866025, 0.500000, -0.500000, -1.000000],
+ [-0.052336, 0.848048, 0.874620, 0.484810, -0.529919, -0.998630],
+ [-0.104528, 0.829038, 0.882948, 0.469472, -0.559193, -0.994522],
+ [-0.156434, 0.809017, 0.891007, 0.453990, -0.587785, -0.987688],
+ [-0.207912, 0.788011, 0.898794, 0.438371, -0.615661, -0.978148],
+ [-0.258819, 0.766044, 0.906308, 0.422618, -0.642788, -0.965926],
+ [-0.309017, 0.743145, 0.913545, 0.406737, -0.669131, -0.951057],
+ [-0.358368, 0.719340, 0.920505, 0.390731, -0.694658, -0.933580],
+ [-0.406737, 0.694658, 0.927184, 0.374607, -0.719340, -0.913545],
+ [-0.453990, 0.669131, 0.933580, 0.358368, -0.743145, -0.891007],
+ [-0.500000, 0.642788, 0.939693, 0.342020, -0.766044, -0.866025],
+ [-0.544639, 0.615661, 0.945519, 0.325568, -0.788011, -0.838671],
+ [-0.587785, 0.587785, 0.951057, 0.309017, -0.809017, -0.809017],
+ [-0.629320, 0.559193, 0.956305, 0.292372, -0.829038, -0.777146],
+ [-0.669131, 0.529919, 0.961262, 0.275637, -0.848048, -0.743145],
+ [-0.707107, 0.500000, 0.965926, 0.258819, -0.866025, -0.707107],
+ [-0.743145, 0.469472, 0.970296, 0.241922, -0.882948, -0.669131],
+ [-0.777146, 0.438371, 0.974370, 0.224951, -0.898794, -0.629320],
+ [-0.809017, 0.406737, 0.978148, 0.207912, -0.913545, -0.587785],
+ [-0.838671, 0.374607, 0.981627, 0.190809, -0.927184, -0.544639],
+ [-0.866025, 0.342020, 0.984808, 0.173648, -0.939693, -0.500000],
+ [-0.891007, 0.309017, 0.987688, 0.156434, -0.951057, -0.453990],
+ [-0.913545, 0.275637, 0.990268, 0.139173, -0.961262, -0.406737],
+ [-0.933580, 0.241922, 0.992546, 0.121869, -0.970296, -0.358368],
+ [-0.951057, 0.207912, 0.994522, 0.104528, -0.978148, -0.309017],
+ [-0.965926, 0.173648, 0.996195, 0.087156, -0.984808, -0.258819],
+ [-0.978148, 0.139173, 0.997564, 0.069756, -0.990268, -0.207912],
+ [-0.987688, 0.104528, 0.998630, 0.052336, -0.994522, -0.156434],
+ [-0.994522, 0.069756, 0.999391, 0.034899, -0.997564, -0.104528],
+ [-0.998630, 0.034899, 0.999848, 0.017452, -0.999391, -0.052336],
+ [-1.000000, 0.000000, 1.000000, 0.000000, -1.000000, -0.000000],
+ [-0.998630, -0.034899, 0.999848, -0.017452, -0.999391, 0.052336],
+ [-0.994522, -0.069756, 0.999391, -0.034899, -0.997564, 0.104528],
+ [-0.987688, -0.104528, 0.998630, -0.052336, -0.994522, 0.156434],
+ [-0.978148, -0.139173, 0.997564, -0.069756, -0.990268, 0.207912],
+ [-0.965926, -0.173648, 0.996195, -0.087156, -0.984808, 0.258819],
+ [-0.951057, -0.207912, 0.994522, -0.104528, -0.978148, 0.309017],
+ [-0.933580, -0.241922, 0.992546, -0.121869, -0.970296, 0.358368],
+ [-0.913545, -0.275637, 0.990268, -0.139173, -0.961262, 0.406737],
+ [-0.891007, -0.309017, 0.987688, -0.156434, -0.951057, 0.453990],
+ [-0.866025, -0.342020, 0.984808, -0.173648, -0.939693, 0.500000],
+ [-0.838671, -0.374607, 0.981627, -0.190809, -0.927184, 0.544639],
+ [-0.809017, -0.406737, 0.978148, -0.207912, -0.913545, 0.587785],
+ [-0.777146, -0.438371, 0.974370, -0.224951, -0.898794, 0.629320],
+ [-0.743145, -0.469472, 0.970296, -0.241922, -0.882948, 0.669131],
+ [-0.707107, -0.500000, 0.965926, -0.258819, -0.866025, 0.707107],
+ [-0.669131, -0.529919, 0.961262, -0.275637, -0.848048, 0.743145],
+ [-0.629320, -0.559193, 0.956305, -0.292372, -0.829038, 0.777146],
+ [-0.587785, -0.587785, 0.951057, -0.309017, -0.809017, 0.809017],
+ [-0.544639, -0.615661, 0.945519, -0.325568, -0.788011, 0.838671],
+ [-0.500000, -0.642788, 0.939693, -0.342020, -0.766044, 0.866025],
+ [-0.453990, -0.669131, 0.933580, -0.358368, -0.743145, 0.891007],
+ [-0.406737, -0.694658, 0.927184, -0.374607, -0.719340, 0.913545],
+ [-0.358368, -0.719340, 0.920505, -0.390731, -0.694658, 0.933580],
+ [-0.309017, -0.743145, 0.913545, -0.406737, -0.669131, 0.951057],
+ [-0.258819, -0.766044, 0.906308, -0.422618, -0.642788, 0.965926],
+ [-0.207912, -0.788011, 0.898794, -0.438371, -0.615661, 0.978148],
+ [-0.156434, -0.809017, 0.891007, -0.453990, -0.587785, 0.987688],
+ [-0.104528, -0.829038, 0.882948, -0.469472, -0.559193, 0.994522],
+ [-0.052336, -0.848048, 0.874620, -0.484810, -0.529919, 0.998630],
+ [-0.000000, -0.866025, 0.866025, -0.500000, -0.500000, 1.000000],
+ [0.052336, -0.882948, 0.857167, -0.515038, -0.469472, 0.998630],
+ [0.104528, -0.898794, 0.848048, -0.529919, -0.438371, 0.994522],
+ [0.156434, -0.913545, 0.838671, -0.544639, -0.406737, 0.987688],
+ [0.207912, -0.927184, 0.829038, -0.559193, -0.374607, 0.978148],
+ [0.258819, -0.939693, 0.819152, -0.573576, -0.342020, 0.965926],
+ [0.309017, -0.951057, 0.809017, -0.587785, -0.309017, 0.951057],
+ [0.358368, -0.961262, 0.798636, -0.601815, -0.275637, 0.933580],
+ [0.406737, -0.970296, 0.788011, -0.615661, -0.241922, 0.913545],
+ [0.453990, -0.978148, 0.777146, -0.629320, -0.207912, 0.891007],
+ [0.500000, -0.984808, 0.766044, -0.642788, -0.173648, 0.866025],
+ [0.544639, -0.990268, 0.754710, -0.656059, -0.139173, 0.838671],
+ [0.587785, -0.994522, 0.743145, -0.669131, -0.104528, 0.809017],
+ [0.629320, -0.997564, 0.731354, -0.681998, -0.069756, 0.777146],
+ [0.669131, -0.999391, 0.719340, -0.694658, -0.034899, 0.743145],
+ [0.707107, -1.000000, 0.707107, -0.707107, -0.000000, 0.707107],
+ [0.743145, -0.999391, 0.694658, -0.719340, 0.034899, 0.669131],
+ [0.777146, -0.997564, 0.681998, -0.731354, 0.069756, 0.629320],
+ [0.809017, -0.994522, 0.669131, -0.743145, 0.104528, 0.587785],
+ [0.838671, -0.990268, 0.656059, -0.754710, 0.139173, 0.544639],
+ [0.866025, -0.984808, 0.642788, -0.766044, 0.173648, 0.500000],
+ [0.891007, -0.978148, 0.629320, -0.777146, 0.207912, 0.453990],
+ [0.913545, -0.970296, 0.615661, -0.788011, 0.241922, 0.406737],
+ [0.933580, -0.961262, 0.601815, -0.798636, 0.275637, 0.358368],
+ [0.951057, -0.951057, 0.587785, -0.809017, 0.309017, 0.309017],
+ [0.965926, -0.939693, 0.573576, -0.819152, 0.342020, 0.258819],
+ [0.978148, -0.927184, 0.559193, -0.829038, 0.374607, 0.207912],
+ [0.987688, -0.913545, 0.544639, -0.838671, 0.406737, 0.156434],
+ [0.994522, -0.898794, 0.529919, -0.848048, 0.438371, 0.104528],
+ [0.998630, -0.882948, 0.515038, -0.857167, 0.469472, 0.052336],
+ [1.000000, -0.866025, 0.500000, -0.866025, 0.500000, 0.000000],
+ [0.998630, -0.848048, 0.484810, -0.874620, 0.529919, -0.052336],
+ [0.994522, -0.829038, 0.469472, -0.882948, 0.559193, -0.104528],
+ [0.987688, -0.809017, 0.453990, -0.891007, 0.587785, -0.156434],
+ [0.978148, -0.788011, 0.438371, -0.898794, 0.615661, -0.207912],
+ [0.965926, -0.766044, 0.422618, -0.906308, 0.642788, -0.258819],
+ [0.951057, -0.743145, 0.406737, -0.913545, 0.669131, -0.309017],
+ [0.933580, -0.719340, 0.390731, -0.920505, 0.694658, -0.358368],
+ [0.913545, -0.694658, 0.374607, -0.927184, 0.719340, -0.406737],
+ [0.891007, -0.669131, 0.358368, -0.933580, 0.743145, -0.453990],
+ [0.866025, -0.642788, 0.342020, -0.939693, 0.766044, -0.500000],
+ [0.838671, -0.615661, 0.325568, -0.945519, 0.788011, -0.544639],
+ [0.809017, -0.587785, 0.309017, -0.951057, 0.809017, -0.587785],
+ [0.777146, -0.559193, 0.292372, -0.956305, 0.829038, -0.629320],
+ [0.743145, -0.529919, 0.275637, -0.961262, 0.848048, -0.669131],
+ [0.707107, -0.500000, 0.258819, -0.965926, 0.866025, -0.707107],
+ [0.669131, -0.469472, 0.241922, -0.970296, 0.882948, -0.743145],
+ [0.629320, -0.438371, 0.224951, -0.974370, 0.898794, -0.777146],
+ [0.587785, -0.406737, 0.207912, -0.978148, 0.913545, -0.809017],
+ [0.544639, -0.374607, 0.190809, -0.981627, 0.927184, -0.838671],
+ [0.500000, -0.342020, 0.173648, -0.984808, 0.939693, -0.866025],
+ [0.453990, -0.309017, 0.156434, -0.987688, 0.951057, -0.891007],
+ [0.406737, -0.275637, 0.139173, -0.990268, 0.961262, -0.913545],
+ [0.358368, -0.241922, 0.121869, -0.992546, 0.970296, -0.933580],
+ [0.309017, -0.207912, 0.104528, -0.994522, 0.978148, -0.951057],
+ [0.258819, -0.173648, 0.087156, -0.996195, 0.984808, -0.965926],
+ [0.207912, -0.139173, 0.069756, -0.997564, 0.990268, -0.978148],
+ [0.156434, -0.104528, 0.052336, -0.998630, 0.994522, -0.987688],
+ [0.104528, -0.069756, 0.034899, -0.999391, 0.997564, -0.994522],
+ [0.052336, -0.034899, 0.017452, -0.999848, 0.999391, -0.998630],
+ [0.000000, -0.000000, 0.000000, -1.000000, 1.000000, -1.000000],
+ [-0.052336, 0.034899, -0.017452, -0.999848, 0.999391, -0.998630],
+ [-0.104528, 0.069756, -0.034899, -0.999391, 0.997564, -0.994522],
+ [-0.156434, 0.104528, -0.052336, -0.998630, 0.994522, -0.987688],
+ [-0.207912, 0.139173, -0.069756, -0.997564, 0.990268, -0.978148],
+ [-0.258819, 0.173648, -0.087156, -0.996195, 0.984808, -0.965926],
+ [-0.309017, 0.207912, -0.104528, -0.994522, 0.978148, -0.951057],
+ [-0.358368, 0.241922, -0.121869, -0.992546, 0.970296, -0.933580],
+ [-0.406737, 0.275637, -0.139173, -0.990268, 0.961262, -0.913545],
+ [-0.453990, 0.309017, -0.156434, -0.987688, 0.951057, -0.891007],
+ [-0.500000, 0.342020, -0.173648, -0.984808, 0.939693, -0.866025],
+ [-0.544639, 0.374607, -0.190809, -0.981627, 0.927184, -0.838671],
+ [-0.587785, 0.406737, -0.207912, -0.978148, 0.913545, -0.809017],
+ [-0.629320, 0.438371, -0.224951, -0.974370, 0.898794, -0.777146],
+ [-0.669131, 0.469472, -0.241922, -0.970296, 0.882948, -0.743145],
+ [-0.707107, 0.500000, -0.258819, -0.965926, 0.866025, -0.707107],
+ [-0.743145, 0.529919, -0.275637, -0.961262, 0.848048, -0.669131],
+ [-0.777146, 0.559193, -0.292372, -0.956305, 0.829038, -0.629320],
+ [-0.809017, 0.587785, -0.309017, -0.951057, 0.809017, -0.587785],
+ [-0.838671, 0.615661, -0.325568, -0.945519, 0.788011, -0.544639],
+ [-0.866025, 0.642788, -0.342020, -0.939693, 0.766044, -0.500000],
+ [-0.891007, 0.669131, -0.358368, -0.933580, 0.743145, -0.453990],
+ [-0.913545, 0.694658, -0.374607, -0.927184, 0.719340, -0.406737],
+ [-0.933580, 0.719340, -0.390731, -0.920505, 0.694658, -0.358368],
+ [-0.951057, 0.743145, -0.406737, -0.913545, 0.669131, -0.309017],
+ [-0.965926, 0.766044, -0.422618, -0.906308, 0.642788, -0.258819],
+ [-0.978148, 0.788011, -0.438371, -0.898794, 0.615661, -0.207912],
+ [-0.987688, 0.809017, -0.453990, -0.891007, 0.587785, -0.156434],
+ [-0.994522, 0.829038, -0.469472, -0.882948, 0.559193, -0.104528],
+ [-0.998630, 0.848048, -0.484810, -0.874620, 0.529919, -0.052336],
+ [-1.000000, 0.866025, -0.500000, -0.866025, 0.500000, 0.000000],
+ [-0.998630, 0.882948, -0.515038, -0.857167, 0.469472, 0.052336],
+ [-0.994522, 0.898794, -0.529919, -0.848048, 0.438371, 0.104528],
+ [-0.987688, 0.913545, -0.544639, -0.838671, 0.406737, 0.156434],
+ [-0.978148, 0.927184, -0.559193, -0.829038, 0.374607, 0.207912],
+ [-0.965926, 0.939693, -0.573576, -0.819152, 0.342020, 0.258819],
+ [-0.951057, 0.951057, -0.587785, -0.809017, 0.309017, 0.309017],
+ [-0.933580, 0.961262, -0.601815, -0.798636, 0.275637, 0.358368],
+ [-0.913545, 0.970296, -0.615661, -0.788011, 0.241922, 0.406737],
+ [-0.891007, 0.978148, -0.629320, -0.777146, 0.207912, 0.453990],
+ [-0.866025, 0.984808, -0.642788, -0.766044, 0.173648, 0.500000],
+ [-0.838671, 0.990268, -0.656059, -0.754710, 0.139173, 0.544639],
+ [-0.809017, 0.994522, -0.669131, -0.743145, 0.104528, 0.587785],
+ [-0.777146, 0.997564, -0.681998, -0.731354, 0.069756, 0.629320],
+ [-0.743145, 0.999391, -0.694658, -0.719340, 0.034899, 0.669131],
+ [-0.707107, 1.000000, -0.707107, -0.707107, 0.000000, 0.707107],
+ [-0.669131, 0.999391, -0.719340, -0.694658, -0.034899, 0.743145],
+ [-0.629320, 0.997564, -0.731354, -0.681998, -0.069756, 0.777146],
+ [-0.587785, 0.994522, -0.743145, -0.669131, -0.104528, 0.809017],
+ [-0.544639, 0.990268, -0.754710, -0.656059, -0.139173, 0.838671],
+ [-0.500000, 0.984808, -0.766044, -0.642788, -0.173648, 0.866025],
+ [-0.453990, 0.978148, -0.777146, -0.629320, -0.207912, 0.891007],
+ [-0.406737, 0.970296, -0.788011, -0.615661, -0.241922, 0.913545],
+ [-0.358368, 0.961262, -0.798636, -0.601815, -0.275637, 0.933580],
+ [-0.309017, 0.951057, -0.809017, -0.587785, -0.309017, 0.951057],
+ [-0.258819, 0.939693, -0.819152, -0.573576, -0.342020, 0.965926],
+ [-0.207912, 0.927184, -0.829038, -0.559193, -0.374607, 0.978148],
+ [-0.156434, 0.913545, -0.838671, -0.544639, -0.406737, 0.987688],
+ [-0.104528, 0.898794, -0.848048, -0.529919, -0.438371, 0.994522],
+ [-0.052336, 0.882948, -0.857167, -0.515038, -0.469472, 0.998630],
+ [-0.000000, 0.866025, -0.866025, -0.500000, -0.500000, 1.000000],
+ [0.052336, 0.848048, -0.874620, -0.484810, -0.529919, 0.998630],
+ [0.104528, 0.829038, -0.882948, -0.469472, -0.559193, 0.994522],
+ [0.156434, 0.809017, -0.891007, -0.453990, -0.587785, 0.987688],
+ [0.207912, 0.788011, -0.898794, -0.438371, -0.615661, 0.978148],
+ [0.258819, 0.766044, -0.906308, -0.422618, -0.642788, 0.965926],
+ [0.309017, 0.743145, -0.913545, -0.406737, -0.669131, 0.951057],
+ [0.358368, 0.719340, -0.920505, -0.390731, -0.694658, 0.933580],
+ [0.406737, 0.694658, -0.927184, -0.374607, -0.719340, 0.913545],
+ [0.453990, 0.669131, -0.933580, -0.358368, -0.743145, 0.891007],
+ [0.500000, 0.642788, -0.939693, -0.342020, -0.766044, 0.866025],
+ [0.544639, 0.615661, -0.945519, -0.325568, -0.788011, 0.838671],
+ [0.587785, 0.587785, -0.951057, -0.309017, -0.809017, 0.809017],
+ [0.629320, 0.559193, -0.956305, -0.292372, -0.829038, 0.777146],
+ [0.669131, 0.529919, -0.961262, -0.275637, -0.848048, 0.743145],
+ [0.707107, 0.500000, -0.965926, -0.258819, -0.866025, 0.707107],
+ [0.743145, 0.469472, -0.970296, -0.241922, -0.882948, 0.669131],
+ [0.777146, 0.438371, -0.974370, -0.224951, -0.898794, 0.629320],
+ [0.809017, 0.406737, -0.978148, -0.207912, -0.913545, 0.587785],
+ [0.838671, 0.374607, -0.981627, -0.190809, -0.927184, 0.544639],
+ [0.866025, 0.342020, -0.984808, -0.173648, -0.939693, 0.500000],
+ [0.891007, 0.309017, -0.987688, -0.156434, -0.951057, 0.453990],
+ [0.913545, 0.275637, -0.990268, -0.139173, -0.961262, 0.406737],
+ [0.933580, 0.241922, -0.992546, -0.121869, -0.970296, 0.358368],
+ [0.951057, 0.207912, -0.994522, -0.104528, -0.978148, 0.309017],
+ [0.965926, 0.173648, -0.996195, -0.087156, -0.984808, 0.258819],
+ [0.978148, 0.139173, -0.997564, -0.069756, -0.990268, 0.207912],
+ [0.987688, 0.104528, -0.998630, -0.052336, -0.994522, 0.156434],
+ [0.994522, 0.069756, -0.999391, -0.034899, -0.997564, 0.104528],
+ [0.998630, 0.034899, -0.999848, -0.017452, -0.999391, 0.052336],
+ [1.000000, 0.000000, -1.000000, -0.000000, -1.000000, 0.000000],
+ [0.998630, -0.034899, -0.999848, 0.017452, -0.999391, -0.052336],
+ [0.994522, -0.069756, -0.999391, 0.034899, -0.997564, -0.104528],
+ [0.987688, -0.104528, -0.998630, 0.052336, -0.994522, -0.156434],
+ [0.978148, -0.139173, -0.997564, 0.069756, -0.990268, -0.207912],
+ [0.965926, -0.173648, -0.996195, 0.087156, -0.984808, -0.258819],
+ [0.951057, -0.207912, -0.994522, 0.104528, -0.978148, -0.309017],
+ [0.933580, -0.241922, -0.992546, 0.121869, -0.970296, -0.358368],
+ [0.913545, -0.275637, -0.990268, 0.139173, -0.961262, -0.406737],
+ [0.891007, -0.309017, -0.987688, 0.156434, -0.951057, -0.453990],
+ [0.866025, -0.342020, -0.984808, 0.173648, -0.939693, -0.500000],
+ [0.838671, -0.374607, -0.981627, 0.190809, -0.927184, -0.544639],
+ [0.809017, -0.406737, -0.978148, 0.207912, -0.913545, -0.587785],
+ [0.777146, -0.438371, -0.974370, 0.224951, -0.898794, -0.629320],
+ [0.743145, -0.469472, -0.970296, 0.241922, -0.882948, -0.669131],
+ [0.707107, -0.500000, -0.965926, 0.258819, -0.866025, -0.707107],
+ [0.669131, -0.529919, -0.961262, 0.275637, -0.848048, -0.743145],
+ [0.629320, -0.559193, -0.956305, 0.292372, -0.829038, -0.777146],
+ [0.587785, -0.587785, -0.951057, 0.309017, -0.809017, -0.809017],
+ [0.544639, -0.615661, -0.945519, 0.325568, -0.788011, -0.838671],
+ [0.500000, -0.642788, -0.939693, 0.342020, -0.766044, -0.866025],
+ [0.453990, -0.669131, -0.933580, 0.358368, -0.743145, -0.891007],
+ [0.406737, -0.694658, -0.927184, 0.374607, -0.719340, -0.913545],
+ [0.358368, -0.719340, -0.920505, 0.390731, -0.694658, -0.933580],
+ [0.309017, -0.743145, -0.913545, 0.406737, -0.669131, -0.951057],
+ [0.258819, -0.766044, -0.906308, 0.422618, -0.642788, -0.965926],
+ [0.207912, -0.788011, -0.898794, 0.438371, -0.615661, -0.978148],
+ [0.156434, -0.809017, -0.891007, 0.453990, -0.587785, -0.987688],
+ [0.104528, -0.829038, -0.882948, 0.469472, -0.559193, -0.994522],
+ [0.052336, -0.848048, -0.874620, 0.484810, -0.529919, -0.998630],
+ [0.000000, -0.866025, -0.866025, 0.500000, -0.500000, -1.000000],
+ [-0.052336, -0.882948, -0.857167, 0.515038, -0.469472, -0.998630],
+ [-0.104528, -0.898794, -0.848048, 0.529919, -0.438371, -0.994522],
+ [-0.156434, -0.913545, -0.838671, 0.544639, -0.406737, -0.987688],
+ [-0.207912, -0.927184, -0.829038, 0.559193, -0.374607, -0.978148],
+ [-0.258819, -0.939693, -0.819152, 0.573576, -0.342020, -0.965926],
+ [-0.309017, -0.951057, -0.809017, 0.587785, -0.309017, -0.951057],
+ [-0.358368, -0.961262, -0.798636, 0.601815, -0.275637, -0.933580],
+ [-0.406737, -0.970296, -0.788011, 0.615661, -0.241922, -0.913545],
+ [-0.453990, -0.978148, -0.777146, 0.629320, -0.207912, -0.891007],
+ [-0.500000, -0.984808, -0.766044, 0.642788, -0.173648, -0.866025],
+ [-0.544639, -0.990268, -0.754710, 0.656059, -0.139173, -0.838671],
+ [-0.587785, -0.994522, -0.743145, 0.669131, -0.104528, -0.809017],
+ [-0.629320, -0.997564, -0.731354, 0.681998, -0.069756, -0.777146],
+ [-0.669131, -0.999391, -0.719340, 0.694658, -0.034899, -0.743145],
+ [-0.707107, -1.000000, -0.707107, 0.707107, -0.000000, -0.707107],
+ [-0.743145, -0.999391, -0.694658, 0.719340, 0.034899, -0.669131],
+ [-0.777146, -0.997564, -0.681998, 0.731354, 0.069756, -0.629320],
+ [-0.809017, -0.994522, -0.669131, 0.743145, 0.104528, -0.587785],
+ [-0.838671, -0.990268, -0.656059, 0.754710, 0.139173, -0.544639],
+ [-0.866025, -0.984808, -0.642788, 0.766044, 0.173648, -0.500000],
+ [-0.891007, -0.978148, -0.629320, 0.777146, 0.207912, -0.453990],
+ [-0.913545, -0.970296, -0.615661, 0.788011, 0.241922, -0.406737],
+ [-0.933580, -0.961262, -0.601815, 0.798636, 0.275637, -0.358368],
+ [-0.951057, -0.951057, -0.587785, 0.809017, 0.309017, -0.309017],
+ [-0.965926, -0.939693, -0.573576, 0.819152, 0.342020, -0.258819],
+ [-0.978148, -0.927184, -0.559193, 0.829038, 0.374607, -0.207912],
+ [-0.987688, -0.913545, -0.544639, 0.838671, 0.406737, -0.156434],
+ [-0.994522, -0.898794, -0.529919, 0.848048, 0.438371, -0.104528],
+ [-0.998630, -0.882948, -0.515038, 0.857167, 0.469472, -0.052336],
+ [-1.000000, -0.866025, -0.500000, 0.866025, 0.500000, -0.000000],
+ [-0.998630, -0.848048, -0.484810, 0.874620, 0.529919, 0.052336],
+ [-0.994522, -0.829038, -0.469472, 0.882948, 0.559193, 0.104528],
+ [-0.987688, -0.809017, -0.453990, 0.891007, 0.587785, 0.156434],
+ [-0.978148, -0.788011, -0.438371, 0.898794, 0.615661, 0.207912],
+ [-0.965926, -0.766044, -0.422618, 0.906308, 0.642788, 0.258819],
+ [-0.951057, -0.743145, -0.406737, 0.913545, 0.669131, 0.309017],
+ [-0.933580, -0.719340, -0.390731, 0.920505, 0.694658, 0.358368],
+ [-0.913545, -0.694658, -0.374607, 0.927184, 0.719340, 0.406737],
+ [-0.891007, -0.669131, -0.358368, 0.933580, 0.743145, 0.453990],
+ [-0.866025, -0.642788, -0.342020, 0.939693, 0.766044, 0.500000],
+ [-0.838671, -0.615661, -0.325568, 0.945519, 0.788011, 0.544639],
+ [-0.809017, -0.587785, -0.309017, 0.951057, 0.809017, 0.587785],
+ [-0.777146, -0.559193, -0.292372, 0.956305, 0.829038, 0.629320],
+ [-0.743145, -0.529919, -0.275637, 0.961262, 0.848048, 0.669131],
+ [-0.707107, -0.500000, -0.258819, 0.965926, 0.866025, 0.707107],
+ [-0.669131, -0.469472, -0.241922, 0.970296, 0.882948, 0.743145],
+ [-0.629320, -0.438371, -0.224951, 0.974370, 0.898794, 0.777146],
+ [-0.587785, -0.406737, -0.207912, 0.978148, 0.913545, 0.809017],
+ [-0.544639, -0.374607, -0.190809, 0.981627, 0.927184, 0.838671],
+ [-0.500000, -0.342020, -0.173648, 0.984808, 0.939693, 0.866025],
+ [-0.453990, -0.309017, -0.156434, 0.987688, 0.951057, 0.891007],
+ [-0.406737, -0.275637, -0.139173, 0.990268, 0.961262, 0.913545],
+ [-0.358368, -0.241922, -0.121869, 0.992546, 0.970296, 0.933580],
+ [-0.309017, -0.207912, -0.104528, 0.994522, 0.978148, 0.951057],
+ [-0.258819, -0.173648, -0.087156, 0.996195, 0.984808, 0.965926],
+ [-0.207912, -0.139173, -0.069756, 0.997564, 0.990268, 0.978148],
+ [-0.156434, -0.104528, -0.052336, 0.998630, 0.994522, 0.987688],
+ [-0.104528, -0.069756, -0.034899, 0.999391, 0.997564, 0.994522],
+ [-0.052336, -0.034899, -0.017452, 0.999848, 0.999391, 0.998630],
+ ],
+ [
+ [-1.000000, -0.000000, 1.000000, -0.000000, 0.000000,
+ -1.000000, -0.000000, 0.000000, -0.000000],
+ [-0.999848, 0.017452, 0.999543, -0.030224, 0.000264,
+ -0.999086, 0.042733, -0.000590, 0.000004],
+ [-0.999391, 0.034899, 0.998173, -0.060411, 0.001055,
+ -0.996348, 0.085356, -0.002357, 0.000034],
+ [-0.998630, 0.052336, 0.995891, -0.090524, 0.002372,
+ -0.991791, 0.127757, -0.005297, 0.000113],
+ [-0.997564, 0.069756, 0.992701, -0.120527, 0.004214,
+ -0.985429, 0.169828, -0.009400, 0.000268],
+ [-0.996195, 0.087156, 0.988606, -0.150384, 0.006578,
+ -0.977277, 0.211460, -0.014654, 0.000523],
+ [-0.994522, 0.104528, 0.983611, -0.180057, 0.009462,
+ -0.967356, 0.252544, -0.021043, 0.000903],
+ [-0.992546, 0.121869, 0.977722, -0.209511, 0.012862,
+ -0.955693, 0.292976, -0.028547, 0.001431],
+ [-0.990268, 0.139173, 0.970946, -0.238709, 0.016774,
+ -0.942316, 0.332649, -0.037143, 0.002131],
+ [-0.987688, 0.156434, 0.963292, -0.267617, 0.021193,
+ -0.927262, 0.371463, -0.046806, 0.003026],
+ [-0.984808, 0.173648, 0.954769, -0.296198, 0.026114,
+ -0.910569, 0.409317, -0.057505, 0.004140],
+ [-0.981627, 0.190809, 0.945388, -0.324419, 0.031530,
+ -0.892279, 0.446114, -0.069209, 0.005492],
+ [-0.978148, 0.207912, 0.935159, -0.352244, 0.037436,
+ -0.872441, 0.481759, -0.081880, 0.007105],
+ [-0.974370, 0.224951, 0.924096, -0.379641, 0.043823,
+ -0.851105, 0.516162, -0.095481, 0.008999],
+ [-0.970296, 0.241922, 0.912211, -0.406574, 0.050685,
+ -0.828326, 0.549233, -0.109969, 0.011193],
+ [-0.965926, 0.258819, 0.899519, -0.433013, 0.058013,
+ -0.804164, 0.580889, -0.125300, 0.013707],
+ [-0.961262, 0.275637, 0.886036, -0.458924, 0.065797,
+ -0.778680, 0.611050, -0.141427, 0.016556],
+ [-0.956305, 0.292372, 0.871778, -0.484275, 0.074029,
+ -0.751940, 0.639639, -0.158301, 0.019758],
+ [-0.951057, 0.309017, 0.856763, -0.509037, 0.082698,
+ -0.724012, 0.666583, -0.175868, 0.023329],
+ [-0.945519, 0.325568, 0.841008, -0.533178, 0.091794,
+ -0.694969, 0.691816, -0.194075, 0.027281],
+ [-0.939693, 0.342020, 0.824533, -0.556670, 0.101306,
+ -0.664885, 0.715274, -0.212865, 0.031630],
+ [-0.933580, 0.358368, 0.807359, -0.579484, 0.111222,
+ -0.633837, 0.736898, -0.232180, 0.036385],
+ [-0.927184, 0.374607, 0.789505, -0.601592, 0.121529,
+ -0.601904, 0.756637, -0.251960, 0.041559],
+ [-0.920505, 0.390731, 0.770994, -0.622967, 0.132217,
+ -0.569169, 0.774442, -0.272143, 0.047160],
+ [-0.913545, 0.406737, 0.751848, -0.643582, 0.143271,
+ -0.535715, 0.790270, -0.292666, 0.053196],
+ [-0.906308, 0.422618, 0.732091, -0.663414, 0.154678,
+ -0.501627, 0.804083, -0.313464, 0.059674],
+ [-0.898794, 0.438371, 0.711746, -0.682437, 0.166423,
+ -0.466993, 0.815850, -0.334472, 0.066599],
+ [-0.891007, 0.453990, 0.690839, -0.700629, 0.178494,
+ -0.431899, 0.825544, -0.355623, 0.073974],
+ [-0.882948, 0.469472, 0.669395, -0.717968, 0.190875,
+ -0.396436, 0.833145, -0.376851, 0.081803],
+ [-0.874620, 0.484810, 0.647439, -0.734431, 0.203551,
+ -0.360692, 0.838638, -0.398086, 0.090085],
+ [-0.866025, 0.500000, 0.625000, -0.750000, 0.216506,
+ -0.324760, 0.842012, -0.419263, 0.098821],
+ [-0.857167, 0.515038, 0.602104, -0.764655, 0.229726,
+ -0.288728, 0.843265, -0.440311, 0.108009],
+ [-0.848048, 0.529919, 0.578778, -0.778378, 0.243192,
+ -0.252688, 0.842399, -0.461164, 0.117644],
+ [-0.838671, 0.544639, 0.555052, -0.791154, 0.256891,
+ -0.216730, 0.839422, -0.481753, 0.127722],
+ [-0.829038, 0.559193, 0.530955, -0.802965, 0.270803,
+ -0.180944, 0.834347, -0.502011, 0.138237],
+ [-0.819152, 0.573576, 0.506515, -0.813798, 0.284914,
+ -0.145420, 0.827194, -0.521871, 0.149181],
+ [-0.809017, 0.587785, 0.481763, -0.823639, 0.299204,
+ -0.110246, 0.817987, -0.541266, 0.160545],
+ [-0.798636, 0.601815, 0.456728, -0.832477, 0.313658,
+ -0.075508, 0.806757, -0.560132, 0.172317],
+ [-0.788011, 0.615661, 0.431441, -0.840301, 0.328257,
+ -0.041294, 0.793541, -0.578405, 0.184487],
+ [-0.777146, 0.629320, 0.405934, -0.847101, 0.342984,
+ -0.007686, 0.778379, -0.596021, 0.197040],
+ [-0.766044, 0.642788, 0.380236, -0.852869, 0.357821,
+ 0.025233, 0.761319, -0.612921, 0.209963],
+ [-0.754710, 0.656059, 0.354380, -0.857597, 0.372749,
+ 0.057383, 0.742412, -0.629044, 0.223238],
+ [-0.743145, 0.669131, 0.328396, -0.861281, 0.387751,
+ 0.088686, 0.721714, -0.644334, 0.236850],
+ [-0.731354, 0.681998, 0.302317, -0.863916, 0.402807,
+ 0.119068, 0.699288, -0.658734, 0.250778],
+ [-0.719340, 0.694658, 0.276175, -0.865498, 0.417901,
+ 0.148454, 0.675199, -0.672190, 0.265005],
+ [-0.707107, 0.707107, 0.250000, -0.866025, 0.433013,
+ 0.176777, 0.649519, -0.684653, 0.279508],
+ [-0.694658, 0.719340, 0.223825, -0.865498, 0.448125,
+ 0.203969, 0.622322, -0.696073, 0.294267],
+ [-0.681998, 0.731354, 0.197683, -0.863916, 0.463218,
+ 0.229967, 0.593688, -0.706405, 0.309259],
+ [-0.669131, 0.743145, 0.171604, -0.861281, 0.478275,
+ 0.254712, 0.563700, -0.715605, 0.324459],
+ [-0.656059, 0.754710, 0.145620, -0.857597, 0.493276,
+ 0.278147, 0.532443, -0.723633, 0.339844],
+ [-0.642788, 0.766044, 0.119764, -0.852869, 0.508205,
+ 0.300221, 0.500009, -0.730451, 0.355387],
+ [-0.629320, 0.777146, 0.094066, -0.847101, 0.523041,
+ 0.320884, 0.466490, -0.736025, 0.371063],
+ [-0.615661, 0.788011, 0.068559, -0.840301, 0.537768,
+ 0.340093, 0.431982, -0.740324, 0.386845],
+ [-0.601815, 0.798636, 0.043272, -0.832477, 0.552367,
+ 0.357807, 0.396584, -0.743320, 0.402704],
+ [-0.587785, 0.809017, 0.018237, -0.823639, 0.566821,
+ 0.373991, 0.360397, -0.744989, 0.418613],
+ [-0.573576, 0.819152, -0.006515, -0.813798, 0.581112,
+ 0.388612, 0.323524, -0.745308, 0.434544],
+ [-0.559193, 0.829038, -0.030955, -0.802965, 0.595222,
+ 0.401645, 0.286069, -0.744262, 0.450467],
+ [-0.544639, 0.838671, -0.055052, -0.791154, 0.609135,
+ 0.413066, 0.248140, -0.741835, 0.466352],
+ [-0.529919, 0.848048, -0.078778, -0.778378, 0.622833,
+ 0.422856, 0.209843, -0.738017, 0.482171],
+ [-0.515038, 0.857167, -0.102104, -0.764655, 0.636300,
+ 0.431004, 0.171288, -0.732801, 0.497894],
+ [-0.500000, 0.866025, -0.125000, -0.750000, 0.649519,
+ 0.437500, 0.132583, -0.726184, 0.513490],
+ [-0.484810, 0.874620, -0.147439, -0.734431, 0.662474,
+ 0.442340, 0.093837, -0.718167, 0.528929],
+ [-0.469472, 0.882948, -0.169395, -0.717968, 0.675150,
+ 0.445524, 0.055160, -0.708753, 0.544183],
+ [-0.453990, 0.891007, -0.190839, -0.700629, 0.687531,
+ 0.447059, 0.016662, -0.697950, 0.559220],
+ [-0.438371, 0.898794, -0.211746, -0.682437, 0.699602,
+ 0.446953, -0.021550, -0.685769, 0.574011],
+ [-0.422618, 0.906308, -0.232091, -0.663414, 0.711348,
+ 0.445222, -0.059368, -0.672226, 0.588528],
+ [-0.406737, 0.913545, -0.251848, -0.643582, 0.722755,
+ 0.441884, -0.096684, -0.657339, 0.602741],
+ [-0.390731, 0.920505, -0.270994, -0.622967, 0.733809,
+ 0.436964, -0.133395, -0.641130, 0.616621],
+ [-0.374607, 0.927184, -0.289505, -0.601592, 0.744496,
+ 0.430488, -0.169397, -0.623624, 0.630141],
+ [-0.358368, 0.933580, -0.307359, -0.579484, 0.754804,
+ 0.422491, -0.204589, -0.604851, 0.643273],
+ [-0.342020, 0.939693, -0.324533, -0.556670, 0.764720,
+ 0.413008, -0.238872, -0.584843, 0.655990],
+ [-0.325568, 0.945519, -0.341008, -0.533178, 0.774231,
+ 0.402081, -0.272150, -0.563635, 0.668267],
+ [-0.309017, 0.951057, -0.356763, -0.509037, 0.783327,
+ 0.389754, -0.304329, -0.541266, 0.680078],
+ [-0.292372, 0.956305, -0.371778, -0.484275, 0.791997,
+ 0.376077, -0.335319, -0.517778, 0.691399],
+ [-0.275637, 0.961262, -0.386036, -0.458924, 0.800228,
+ 0.361102, -0.365034, -0.493216, 0.702207],
+ [-0.258819, 0.965926, -0.399519, -0.433013, 0.808013,
+ 0.344885, -0.393389, -0.467627, 0.712478],
+ [-0.241922, 0.970296, -0.412211, -0.406574, 0.815340,
+ 0.327486, -0.420306, -0.441061, 0.722191],
+ [-0.224951, 0.974370, -0.424096, -0.379641, 0.822202,
+ 0.308969, -0.445709, -0.413572, 0.731327],
+ [-0.207912, 0.978148, -0.435159, -0.352244, 0.828589,
+ 0.289399, -0.469527, -0.385215, 0.739866],
+ [-0.190809, 0.981627, -0.445388, -0.324419, 0.834495,
+ 0.268846, -0.491693, -0.356047, 0.747790],
+ [-0.173648, 0.984808, -0.454769, -0.296198, 0.839912,
+ 0.247382, -0.512145, -0.326129, 0.755082],
+ [-0.156434, 0.987688, -0.463292, -0.267617, 0.844832,
+ 0.225081, -0.530827, -0.295521, 0.761728],
+ [-0.139173, 0.990268, -0.470946, -0.238709, 0.849251,
+ 0.202020, -0.547684, -0.264287, 0.767712],
+ [-0.121869, 0.992546, -0.477722, -0.209511, 0.853163,
+ 0.178279, -0.562672, -0.232494, 0.773023],
+ [-0.104528, 0.994522, -0.483611, -0.180057, 0.856563,
+ 0.153937, -0.575747, -0.200207, 0.777648],
+ [-0.087156, 0.996195, -0.488606, -0.150384, 0.859447,
+ 0.129078, -0.586872, -0.167494, 0.781579],
+ [-0.069756, 0.997564, -0.492701, -0.120527, 0.861811,
+ 0.103786, -0.596018, -0.134426, 0.784806],
+ [-0.052336, 0.998630, -0.495891, -0.090524, 0.863653,
+ 0.078146, -0.603158, -0.101071, 0.787324],
+ [-0.034899, 0.999391, -0.498173, -0.060411, 0.864971,
+ 0.052243, -0.608272, -0.067500, 0.789126],
+ [-0.017452, 0.999848, -0.499543, -0.030224, 0.865762,
+ 0.026165, -0.611347, -0.033786, 0.790208],
+ [0.000000, 1.000000, -0.500000, 0.000000, 0.866025,
+ -0.000000, -0.612372, 0.000000, 0.790569],
+ [0.017452, 0.999848, -0.499543, 0.030224, 0.865762,
+ -0.026165, -0.611347, 0.033786, 0.790208],
+ [0.034899, 0.999391, -0.498173, 0.060411, 0.864971,
+ -0.052243, -0.608272, 0.067500, 0.789126],
+ [0.052336, 0.998630, -0.495891, 0.090524, 0.863653,
+ -0.078146, -0.603158, 0.101071, 0.787324],
+ [0.069756, 0.997564, -0.492701, 0.120527, 0.861811,
+ -0.103786, -0.596018, 0.134426, 0.784806],
+ [0.087156, 0.996195, -0.488606, 0.150384, 0.859447,
+ -0.129078, -0.586872, 0.167494, 0.781579],
+ [0.104528, 0.994522, -0.483611, 0.180057, 0.856563,
+ -0.153937, -0.575747, 0.200207, 0.777648],
+ [0.121869, 0.992546, -0.477722, 0.209511, 0.853163,
+ -0.178279, -0.562672, 0.232494, 0.773023],
+ [0.139173, 0.990268, -0.470946, 0.238709, 0.849251,
+ -0.202020, -0.547684, 0.264287, 0.767712],
+ [0.156434, 0.987688, -0.463292, 0.267617, 0.844832,
+ -0.225081, -0.530827, 0.295521, 0.761728],
+ [0.173648, 0.984808, -0.454769, 0.296198, 0.839912,
+ -0.247382, -0.512145, 0.326129, 0.755082],
+ [0.190809, 0.981627, -0.445388, 0.324419, 0.834495,
+ -0.268846, -0.491693, 0.356047, 0.747790],
+ [0.207912, 0.978148, -0.435159, 0.352244, 0.828589,
+ -0.289399, -0.469527, 0.385215, 0.739866],
+ [0.224951, 0.974370, -0.424096, 0.379641, 0.822202,
+ -0.308969, -0.445709, 0.413572, 0.731327],
+ [0.241922, 0.970296, -0.412211, 0.406574, 0.815340,
+ -0.327486, -0.420306, 0.441061, 0.722191],
+ [0.258819, 0.965926, -0.399519, 0.433013, 0.808013,
+ -0.344885, -0.393389, 0.467627, 0.712478],
+ [0.275637, 0.961262, -0.386036, 0.458924, 0.800228,
+ -0.361102, -0.365034, 0.493216, 0.702207],
+ [0.292372, 0.956305, -0.371778, 0.484275, 0.791997,
+ -0.376077, -0.335319, 0.517778, 0.691399],
+ [0.309017, 0.951057, -0.356763, 0.509037, 0.783327,
+ -0.389754, -0.304329, 0.541266, 0.680078],
+ [0.325568, 0.945519, -0.341008, 0.533178, 0.774231,
+ -0.402081, -0.272150, 0.563635, 0.668267],
+ [0.342020, 0.939693, -0.324533, 0.556670, 0.764720,
+ -0.413008, -0.238872, 0.584843, 0.655990],
+ [0.358368, 0.933580, -0.307359, 0.579484, 0.754804,
+ -0.422491, -0.204589, 0.604851, 0.643273],
+ [0.374607, 0.927184, -0.289505, 0.601592, 0.744496,
+ -0.430488, -0.169397, 0.623624, 0.630141],
+ [0.390731, 0.920505, -0.270994, 0.622967, 0.733809,
+ -0.436964, -0.133395, 0.641130, 0.616621],
+ [0.406737, 0.913545, -0.251848, 0.643582, 0.722755,
+ -0.441884, -0.096684, 0.657339, 0.602741],
+ [0.422618, 0.906308, -0.232091, 0.663414, 0.711348,
+ -0.445222, -0.059368, 0.672226, 0.588528],
+ [0.438371, 0.898794, -0.211746, 0.682437, 0.699602,
+ -0.446953, -0.021550, 0.685769, 0.574011],
+ [0.453990, 0.891007, -0.190839, 0.700629, 0.687531,
+ -0.447059, 0.016662, 0.697950, 0.559220],
+ [0.469472, 0.882948, -0.169395, 0.717968, 0.675150,
+ -0.445524, 0.055160, 0.708753, 0.544183],
+ [0.484810, 0.874620, -0.147439, 0.734431, 0.662474,
+ -0.442340, 0.093837, 0.718167, 0.528929],
+ [0.500000, 0.866025, -0.125000, 0.750000, 0.649519,
+ -0.437500, 0.132583, 0.726184, 0.513490],
+ [0.515038, 0.857167, -0.102104, 0.764655, 0.636300,
+ -0.431004, 0.171288, 0.732801, 0.497894],
+ [0.529919, 0.848048, -0.078778, 0.778378, 0.622833,
+ -0.422856, 0.209843, 0.738017, 0.482171],
+ [0.544639, 0.838671, -0.055052, 0.791154, 0.609135,
+ -0.413066, 0.248140, 0.741835, 0.466352],
+ [0.559193, 0.829038, -0.030955, 0.802965, 0.595222,
+ -0.401645, 0.286069, 0.744262, 0.450467],
+ [0.573576, 0.819152, -0.006515, 0.813798, 0.581112,
+ -0.388612, 0.323524, 0.745308, 0.434544],
+ [0.587785, 0.809017, 0.018237, 0.823639, 0.566821,
+ -0.373991, 0.360397, 0.744989, 0.418613],
+ [0.601815, 0.798636, 0.043272, 0.832477, 0.552367,
+ -0.357807, 0.396584, 0.743320, 0.402704],
+ [0.615661, 0.788011, 0.068559, 0.840301, 0.537768,
+ -0.340093, 0.431982, 0.740324, 0.386845],
+ [0.629320, 0.777146, 0.094066, 0.847101, 0.523041,
+ -0.320884, 0.466490, 0.736025, 0.371063],
+ [0.642788, 0.766044, 0.119764, 0.852869, 0.508205,
+ -0.300221, 0.500009, 0.730451, 0.355387],
+ [0.656059, 0.754710, 0.145620, 0.857597, 0.493276,
+ -0.278147, 0.532443, 0.723633, 0.339844],
+ [0.669131, 0.743145, 0.171604, 0.861281, 0.478275,
+ -0.254712, 0.563700, 0.715605, 0.324459],
+ [0.681998, 0.731354, 0.197683, 0.863916, 0.463218,
+ -0.229967, 0.593688, 0.706405, 0.309259],
+ [0.694658, 0.719340, 0.223825, 0.865498, 0.448125,
+ -0.203969, 0.622322, 0.696073, 0.294267],
+ [0.707107, 0.707107, 0.250000, 0.866025, 0.433013,
+ -0.176777, 0.649519, 0.684653, 0.279508],
+ [0.719340, 0.694658, 0.276175, 0.865498, 0.417901,
+ -0.148454, 0.675199, 0.672190, 0.265005],
+ [0.731354, 0.681998, 0.302317, 0.863916, 0.402807,
+ -0.119068, 0.699288, 0.658734, 0.250778],
+ [0.743145, 0.669131, 0.328396, 0.861281, 0.387751,
+ -0.088686, 0.721714, 0.644334, 0.236850],
+ [0.754710, 0.656059, 0.354380, 0.857597, 0.372749,
+ -0.057383, 0.742412, 0.629044, 0.223238],
+ [0.766044, 0.642788, 0.380236, 0.852869, 0.357821,
+ -0.025233, 0.761319, 0.612921, 0.209963],
+ [0.777146, 0.629320, 0.405934, 0.847101, 0.342984,
+ 0.007686, 0.778379, 0.596021, 0.197040],
+ [0.788011, 0.615661, 0.431441, 0.840301, 0.328257,
+ 0.041294, 0.793541, 0.578405, 0.184487],
+ [0.798636, 0.601815, 0.456728, 0.832477, 0.313658,
+ 0.075508, 0.806757, 0.560132, 0.172317],
+ [0.809017, 0.587785, 0.481763, 0.823639, 0.299204,
+ 0.110246, 0.817987, 0.541266, 0.160545],
+ [0.819152, 0.573576, 0.506515, 0.813798, 0.284914,
+ 0.145420, 0.827194, 0.521871, 0.149181],
+ [0.829038, 0.559193, 0.530955, 0.802965, 0.270803,
+ 0.180944, 0.834347, 0.502011, 0.138237],
+ [0.838671, 0.544639, 0.555052, 0.791154, 0.256891,
+ 0.216730, 0.839422, 0.481753, 0.127722],
+ [0.848048, 0.529919, 0.578778, 0.778378, 0.243192,
+ 0.252688, 0.842399, 0.461164, 0.117644],
+ [0.857167, 0.515038, 0.602104, 0.764655, 0.229726,
+ 0.288728, 0.843265, 0.440311, 0.108009],
+ [0.866025, 0.500000, 0.625000, 0.750000, 0.216506,
+ 0.324760, 0.842012, 0.419263, 0.098821],
+ [0.874620, 0.484810, 0.647439, 0.734431, 0.203551,
+ 0.360692, 0.838638, 0.398086, 0.090085],
+ [0.882948, 0.469472, 0.669395, 0.717968, 0.190875,
+ 0.396436, 0.833145, 0.376851, 0.081803],
+ [0.891007, 0.453990, 0.690839, 0.700629, 0.178494,
+ 0.431899, 0.825544, 0.355623, 0.073974],
+ [0.898794, 0.438371, 0.711746, 0.682437, 0.166423,
+ 0.466993, 0.815850, 0.334472, 0.066599],
+ [0.906308, 0.422618, 0.732091, 0.663414, 0.154678,
+ 0.501627, 0.804083, 0.313464, 0.059674],
+ [0.913545, 0.406737, 0.751848, 0.643582, 0.143271,
+ 0.535715, 0.790270, 0.292666, 0.053196],
+ [0.920505, 0.390731, 0.770994, 0.622967, 0.132217,
+ 0.569169, 0.774442, 0.272143, 0.047160],
+ [0.927184, 0.374607, 0.789505, 0.601592, 0.121529,
+ 0.601904, 0.756637, 0.251960, 0.041559],
+ [0.933580, 0.358368, 0.807359, 0.579484, 0.111222,
+ 0.633837, 0.736898, 0.232180, 0.036385],
+ [0.939693, 0.342020, 0.824533, 0.556670, 0.101306,
+ 0.664885, 0.715274, 0.212865, 0.031630],
+ [0.945519, 0.325568, 0.841008, 0.533178, 0.091794,
+ 0.694969, 0.691816, 0.194075, 0.027281],
+ [0.951057, 0.309017, 0.856763, 0.509037, 0.082698,
+ 0.724012, 0.666583, 0.175868, 0.023329],
+ [0.956305, 0.292372, 0.871778, 0.484275, 0.074029,
+ 0.751940, 0.639639, 0.158301, 0.019758],
+ [0.961262, 0.275637, 0.886036, 0.458924, 0.065797,
+ 0.778680, 0.611050, 0.141427, 0.016556],
+ [0.965926, 0.258819, 0.899519, 0.433013, 0.058013,
+ 0.804164, 0.580889, 0.125300, 0.013707],
+ [0.970296, 0.241922, 0.912211, 0.406574, 0.050685,
+ 0.828326, 0.549233, 0.109969, 0.011193],
+ [0.974370, 0.224951, 0.924096, 0.379641, 0.043823,
+ 0.851105, 0.516162, 0.095481, 0.008999],
+ [0.978148, 0.207912, 0.935159, 0.352244, 0.037436,
+ 0.872441, 0.481759, 0.081880, 0.007105],
+ [0.981627, 0.190809, 0.945388, 0.324419, 0.031530,
+ 0.892279, 0.446114, 0.069209, 0.005492],
+ [0.984808, 0.173648, 0.954769, 0.296198, 0.026114,
+ 0.910569, 0.409317, 0.057505, 0.004140],
+ [0.987688, 0.156434, 0.963292, 0.267617, 0.021193,
+ 0.927262, 0.371463, 0.046806, 0.003026],
+ [0.990268, 0.139173, 0.970946, 0.238709, 0.016774,
+ 0.942316, 0.332649, 0.037143, 0.002131],
+ [0.992546, 0.121869, 0.977722, 0.209511, 0.012862,
+ 0.955693, 0.292976, 0.028547, 0.001431],
+ [0.994522, 0.104528, 0.983611, 0.180057, 0.009462,
+ 0.967356, 0.252544, 0.021043, 0.000903],
+ [0.996195, 0.087156, 0.988606, 0.150384, 0.006578,
+ 0.977277, 0.211460, 0.014654, 0.000523],
+ [0.997564, 0.069756, 0.992701, 0.120527, 0.004214,
+ 0.985429, 0.169828, 0.009400, 0.000268],
+ [0.998630, 0.052336, 0.995891, 0.090524, 0.002372,
+ 0.991791, 0.127757, 0.005297, 0.000113],
+ [0.999391, 0.034899, 0.998173, 0.060411, 0.001055,
+ 0.996348, 0.085356, 0.002357, 0.000034],
+ [0.999848, 0.017452, 0.999543, 0.030224, 0.000264,
+ 0.999086, 0.042733, 0.000590, 0.000004],
+ [1.000000, -0.000000, 1.000000, -0.000000, 0.000000,
+ 1.000000, -0.000000, 0.000000, -0.000000],
+ ],
+];
+/** @type {Number} */
+const SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION = SPHERICAL_HARMONICS[0].length;
+/** @type {Number} */
+const SPHERICAL_HARMONICS_ELEVATION_RESOLUTION = SPHERICAL_HARMONICS[1].length;
+/**
+ * The maximum allowed ambisonic order.
+ * @type {Number}
+ */
+const SPHERICAL_HARMONICS_MAX_ORDER = SPHERICAL_HARMONICS[0][0].length / 2;
+/**
+ * Pre-computed per-band weighting coefficients for producing energy-preserving
+ * Max-Re sources.
+ */
+const MAX_RE_WEIGHTS = [
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.000000, 1.000000, 1.000000, 1.000000],
+ [1.003236, 1.002156, 0.999152, 0.990038],
+ [1.032370, 1.021194, 0.990433, 0.898572],
+ [1.062694, 1.040231, 0.979161, 0.799806],
+ [1.093999, 1.058954, 0.964976, 0.693603],
+ [1.126003, 1.077006, 0.947526, 0.579890],
+ [1.158345, 1.093982, 0.926474, 0.458690],
+ [1.190590, 1.109437, 0.901512, 0.330158],
+ [1.222228, 1.122890, 0.872370, 0.194621],
+ [1.252684, 1.133837, 0.838839, 0.052614],
+ [1.281987, 1.142358, 0.801199, 0.000000],
+ [1.312073, 1.150207, 0.760839, 0.000000],
+ [1.343011, 1.157424, 0.717799, 0.000000],
+ [1.374649, 1.163859, 0.671999, 0.000000],
+ [1.406809, 1.169354, 0.623371, 0.000000],
+ [1.439286, 1.173739, 0.571868, 0.000000],
+ [1.471846, 1.176837, 0.517465, 0.000000],
+ [1.504226, 1.178465, 0.460174, 0.000000],
+ [1.536133, 1.178438, 0.400043, 0.000000],
+ [1.567253, 1.176573, 0.337165, 0.000000],
+ [1.597247, 1.172695, 0.271688, 0.000000],
+ [1.625766, 1.166645, 0.203815, 0.000000],
+ [1.652455, 1.158285, 0.133806, 0.000000],
+ [1.676966, 1.147506, 0.061983, 0.000000],
+ [1.699006, 1.134261, 0.000000, 0.000000],
+ [1.720224, 1.119789, 0.000000, 0.000000],
+ [1.741631, 1.104810, 0.000000, 0.000000],
+ [1.763183, 1.089330, 0.000000, 0.000000],
+ [1.784837, 1.073356, 0.000000, 0.000000],
+ [1.806548, 1.056898, 0.000000, 0.000000],
+ [1.828269, 1.039968, 0.000000, 0.000000],
+ [1.849952, 1.022580, 0.000000, 0.000000],
+ [1.871552, 1.004752, 0.000000, 0.000000],
+ [1.893018, 0.986504, 0.000000, 0.000000],
+ [1.914305, 0.967857, 0.000000, 0.000000],
+ [1.935366, 0.948837, 0.000000, 0.000000],
+ [1.956154, 0.929471, 0.000000, 0.000000],
+ [1.976625, 0.909790, 0.000000, 0.000000],
+ [1.996736, 0.889823, 0.000000, 0.000000],
+ [2.016448, 0.869607, 0.000000, 0.000000],
+ [2.035721, 0.849175, 0.000000, 0.000000],
+ [2.054522, 0.828565, 0.000000, 0.000000],
+ [2.072818, 0.807816, 0.000000, 0.000000],
+ [2.090581, 0.786964, 0.000000, 0.000000],
+ [2.107785, 0.766051, 0.000000, 0.000000],
+ [2.124411, 0.745115, 0.000000, 0.000000],
+ [2.140439, 0.724196, 0.000000, 0.000000],
+ [2.155856, 0.703332, 0.000000, 0.000000],
+ [2.170653, 0.682561, 0.000000, 0.000000],
+ [2.184823, 0.661921, 0.000000, 0.000000],
+ [2.198364, 0.641445, 0.000000, 0.000000],
+ [2.211275, 0.621169, 0.000000, 0.000000],
+ [2.223562, 0.601125, 0.000000, 0.000000],
+ [2.235230, 0.581341, 0.000000, 0.000000],
+ [2.246289, 0.561847, 0.000000, 0.000000],
+ [2.256751, 0.542667, 0.000000, 0.000000],
+ [2.266631, 0.523826, 0.000000, 0.000000],
+ [2.275943, 0.505344, 0.000000, 0.000000],
+ [2.284707, 0.487239, 0.000000, 0.000000],
+ [2.292939, 0.469528, 0.000000, 0.000000],
+ [2.300661, 0.452225, 0.000000, 0.000000],
+ [2.307892, 0.435342, 0.000000, 0.000000],
+ [2.314654, 0.418888, 0.000000, 0.000000],
+ [2.320969, 0.402870, 0.000000, 0.000000],
+ [2.326858, 0.387294, 0.000000, 0.000000],
+ [2.332343, 0.372164, 0.000000, 0.000000],
+ [2.337445, 0.357481, 0.000000, 0.000000],
+ [2.342186, 0.343246, 0.000000, 0.000000],
+ [2.346585, 0.329458, 0.000000, 0.000000],
+ [2.350664, 0.316113, 0.000000, 0.000000],
+ [2.354442, 0.303208, 0.000000, 0.000000],
+ [2.357937, 0.290738, 0.000000, 0.000000],
+ [2.361168, 0.278698, 0.000000, 0.000000],
+ [2.364152, 0.267080, 0.000000, 0.000000],
+ [2.366906, 0.255878, 0.000000, 0.000000],
+ [2.369446, 0.245082, 0.000000, 0.000000],
+ [2.371786, 0.234685, 0.000000, 0.000000],
+ [2.373940, 0.224677, 0.000000, 0.000000],
+ [2.375923, 0.215048, 0.000000, 0.000000],
+ [2.377745, 0.205790, 0.000000, 0.000000],
+ [2.379421, 0.196891, 0.000000, 0.000000],
+ [2.380959, 0.188342, 0.000000, 0.000000],
+ [2.382372, 0.180132, 0.000000, 0.000000],
+ [2.383667, 0.172251, 0.000000, 0.000000],
+ [2.384856, 0.164689, 0.000000, 0.000000],
+ [2.385945, 0.157435, 0.000000, 0.000000],
+ [2.386943, 0.150479, 0.000000, 0.000000],
+ [2.387857, 0.143811, 0.000000, 0.000000],
+ [2.388694, 0.137421, 0.000000, 0.000000],
+ [2.389460, 0.131299, 0.000000, 0.000000],
+ [2.390160, 0.125435, 0.000000, 0.000000],
+ [2.390801, 0.119820, 0.000000, 0.000000],
+ [2.391386, 0.114445, 0.000000, 0.000000],
+ [2.391921, 0.109300, 0.000000, 0.000000],
+ [2.392410, 0.104376, 0.000000, 0.000000],
+ [2.392857, 0.099666, 0.000000, 0.000000],
+ [2.393265, 0.095160, 0.000000, 0.000000],
+ [2.393637, 0.090851, 0.000000, 0.000000],
+ [2.393977, 0.086731, 0.000000, 0.000000],
+ [2.394288, 0.082791, 0.000000, 0.000000],
+ [2.394571, 0.079025, 0.000000, 0.000000],
+ [2.394829, 0.075426, 0.000000, 0.000000],
+ [2.395064, 0.071986, 0.000000, 0.000000],
+ [2.395279, 0.068699, 0.000000, 0.000000],
+ [2.395475, 0.065558, 0.000000, 0.000000],
+ [2.395653, 0.062558, 0.000000, 0.000000],
+ [2.395816, 0.059693, 0.000000, 0.000000],
+ [2.395964, 0.056955, 0.000000, 0.000000],
+ [2.396099, 0.054341, 0.000000, 0.000000],
+ [2.396222, 0.051845, 0.000000, 0.000000],
+ [2.396334, 0.049462, 0.000000, 0.000000],
+ [2.396436, 0.047186, 0.000000, 0.000000],
+ [2.396529, 0.045013, 0.000000, 0.000000],
+ [2.396613, 0.042939, 0.000000, 0.000000],
+ [2.396691, 0.040959, 0.000000, 0.000000],
+ [2.396761, 0.039069, 0.000000, 0.000000],
+ [2.396825, 0.037266, 0.000000, 0.000000],
+ [2.396883, 0.035544, 0.000000, 0.000000],
+ [2.396936, 0.033901, 0.000000, 0.000000],
+ [2.396984, 0.032334, 0.000000, 0.000000],
+ [2.397028, 0.030838, 0.000000, 0.000000],
+ [2.397068, 0.029410, 0.000000, 0.000000],
+ [2.397104, 0.028048, 0.000000, 0.000000],
+ [2.397137, 0.026749, 0.000000, 0.000000],
+ [2.397167, 0.025509, 0.000000, 0.000000],
+ [2.397194, 0.024326, 0.000000, 0.000000],
+ [2.397219, 0.023198, 0.000000, 0.000000],
+ [2.397242, 0.022122, 0.000000, 0.000000],
+ [2.397262, 0.021095, 0.000000, 0.000000],
+ [2.397281, 0.020116, 0.000000, 0.000000],
+ [2.397298, 0.019181, 0.000000, 0.000000],
+ [2.397314, 0.018290, 0.000000, 0.000000],
+ [2.397328, 0.017441, 0.000000, 0.000000],
+ [2.397341, 0.016630, 0.000000, 0.000000],
+ [2.397352, 0.015857, 0.000000, 0.000000],
+ [2.397363, 0.015119, 0.000000, 0.000000],
+ [2.397372, 0.014416, 0.000000, 0.000000],
+ [2.397381, 0.013745, 0.000000, 0.000000],
+ [2.397389, 0.013106, 0.000000, 0.000000],
+ [2.397396, 0.012496, 0.000000, 0.000000],
+ [2.397403, 0.011914, 0.000000, 0.000000],
+ [2.397409, 0.011360, 0.000000, 0.000000],
+ [2.397414, 0.010831, 0.000000, 0.000000],
+ [2.397419, 0.010326, 0.000000, 0.000000],
+ [2.397424, 0.009845, 0.000000, 0.000000],
+ [2.397428, 0.009387, 0.000000, 0.000000],
+ [2.397432, 0.008949, 0.000000, 0.000000],
+ [2.397435, 0.008532, 0.000000, 0.000000],
+ [2.397438, 0.008135, 0.000000, 0.000000],
+ [2.397441, 0.007755, 0.000000, 0.000000],
+ [2.397443, 0.007394, 0.000000, 0.000000],
+ [2.397446, 0.007049, 0.000000, 0.000000],
+ [2.397448, 0.006721, 0.000000, 0.000000],
+ [2.397450, 0.006407, 0.000000, 0.000000],
+ [2.397451, 0.006108, 0.000000, 0.000000],
+ [2.397453, 0.005824, 0.000000, 0.000000],
+ [2.397454, 0.005552, 0.000000, 0.000000],
+ [2.397456, 0.005293, 0.000000, 0.000000],
+ [2.397457, 0.005046, 0.000000, 0.000000],
+ [2.397458, 0.004811, 0.000000, 0.000000],
+ [2.397459, 0.004586, 0.000000, 0.000000],
+ [2.397460, 0.004372, 0.000000, 0.000000],
+ [2.397461, 0.004168, 0.000000, 0.000000],
+ [2.397461, 0.003974, 0.000000, 0.000000],
+ [2.397462, 0.003788, 0.000000, 0.000000],
+ [2.397463, 0.003611, 0.000000, 0.000000],
+ [2.397463, 0.003443, 0.000000, 0.000000],
+ [2.397464, 0.003282, 0.000000, 0.000000],
+ [2.397464, 0.003129, 0.000000, 0.000000],
+ [2.397465, 0.002983, 0.000000, 0.000000],
+ [2.397465, 0.002844, 0.000000, 0.000000],
+ [2.397465, 0.002711, 0.000000, 0.000000],
+ [2.397466, 0.002584, 0.000000, 0.000000],
+ [2.397466, 0.002464, 0.000000, 0.000000],
+ [2.397466, 0.002349, 0.000000, 0.000000],
+ [2.397466, 0.002239, 0.000000, 0.000000],
+ [2.397467, 0.002135, 0.000000, 0.000000],
+ [2.397467, 0.002035, 0.000000, 0.000000],
+ [2.397467, 0.001940, 0.000000, 0.000000],
+ [2.397467, 0.001849, 0.000000, 0.000000],
+ [2.397467, 0.001763, 0.000000, 0.000000],
+ [2.397467, 0.001681, 0.000000, 0.000000],
+ [2.397468, 0.001602, 0.000000, 0.000000],
+ [2.397468, 0.001527, 0.000000, 0.000000],
+ [2.397468, 0.001456, 0.000000, 0.000000],
+ [2.397468, 0.001388, 0.000000, 0.000000],
+ [2.397468, 0.001323, 0.000000, 0.000000],
+ [2.397468, 0.001261, 0.000000, 0.000000],
+ [2.397468, 0.001202, 0.000000, 0.000000],
+ [2.397468, 0.001146, 0.000000, 0.000000],
+ [2.397468, 0.001093, 0.000000, 0.000000],
+ [2.397468, 0.001042, 0.000000, 0.000000],
+ [2.397468, 0.000993, 0.000000, 0.000000],
+ [2.397468, 0.000947, 0.000000, 0.000000],
+ [2.397468, 0.000902, 0.000000, 0.000000],
+ [2.397468, 0.000860, 0.000000, 0.000000],
+ [2.397468, 0.000820, 0.000000, 0.000000],
+ [2.397469, 0.000782, 0.000000, 0.000000],
+ [2.397469, 0.000745, 0.000000, 0.000000],
+ [2.397469, 0.000710, 0.000000, 0.000000],
+ [2.397469, 0.000677, 0.000000, 0.000000],
+ [2.397469, 0.000646, 0.000000, 0.000000],
+ [2.397469, 0.000616, 0.000000, 0.000000],
+ [2.397469, 0.000587, 0.000000, 0.000000],
+ [2.397469, 0.000559, 0.000000, 0.000000],
+ [2.397469, 0.000533, 0.000000, 0.000000],
+ [2.397469, 0.000508, 0.000000, 0.000000],
+ [2.397469, 0.000485, 0.000000, 0.000000],
+ [2.397469, 0.000462, 0.000000, 0.000000],
+ [2.397469, 0.000440, 0.000000, 0.000000],
+ [2.397469, 0.000420, 0.000000, 0.000000],
+ [2.397469, 0.000400, 0.000000, 0.000000],
+ [2.397469, 0.000381, 0.000000, 0.000000],
+ [2.397469, 0.000364, 0.000000, 0.000000],
+ [2.397469, 0.000347, 0.000000, 0.000000],
+ [2.397469, 0.000330, 0.000000, 0.000000],
+ [2.397469, 0.000315, 0.000000, 0.000000],
+ [2.397469, 0.000300, 0.000000, 0.000000],
+ [2.397469, 0.000286, 0.000000, 0.000000],
+ [2.397469, 0.000273, 0.000000, 0.000000],
+ [2.397469, 0.000260, 0.000000, 0.000000],
+ [2.397469, 0.000248, 0.000000, 0.000000],
+ [2.397469, 0.000236, 0.000000, 0.000000],
+ [2.397469, 0.000225, 0.000000, 0.000000],
+ [2.397469, 0.000215, 0.000000, 0.000000],
+ [2.397469, 0.000205, 0.000000, 0.000000],
+ [2.397469, 0.000195, 0.000000, 0.000000],
+ [2.397469, 0.000186, 0.000000, 0.000000],
+ [2.397469, 0.000177, 0.000000, 0.000000],
+ [2.397469, 0.000169, 0.000000, 0.000000],
+ [2.397469, 0.000161, 0.000000, 0.000000],
+ [2.397469, 0.000154, 0.000000, 0.000000],
+ [2.397469, 0.000147, 0.000000, 0.000000],
+ [2.397469, 0.000140, 0.000000, 0.000000],
+ [2.397469, 0.000133, 0.000000, 0.000000],
+ [2.397469, 0.000127, 0.000000, 0.000000],
+ [2.397469, 0.000121, 0.000000, 0.000000],
+ [2.397469, 0.000115, 0.000000, 0.000000],
+ [2.397469, 0.000110, 0.000000, 0.000000],
+ [2.397469, 0.000105, 0.000000, 0.000000],
+ [2.397469, 0.000100, 0.000000, 0.000000],
+ [2.397469, 0.000095, 0.000000, 0.000000],
+ [2.397469, 0.000091, 0.000000, 0.000000],
+ [2.397469, 0.000087, 0.000000, 0.000000],
+ [2.397469, 0.000083, 0.000000, 0.000000],
+ [2.397469, 0.000079, 0.000000, 0.000000],
+ [2.397469, 0.000075, 0.000000, 0.000000],
+ [2.397469, 0.000071, 0.000000, 0.000000],
+ [2.397469, 0.000068, 0.000000, 0.000000],
+ [2.397469, 0.000065, 0.000000, 0.000000],
+ [2.397469, 0.000062, 0.000000, 0.000000],
+ [2.397469, 0.000059, 0.000000, 0.000000],
+ [2.397469, 0.000056, 0.000000, 0.000000],
+ [2.397469, 0.000054, 0.000000, 0.000000],
+ [2.397469, 0.000051, 0.000000, 0.000000],
+ [2.397469, 0.000049, 0.000000, 0.000000],
+ [2.397469, 0.000046, 0.000000, 0.000000],
+ [2.397469, 0.000044, 0.000000, 0.000000],
+ [2.397469, 0.000042, 0.000000, 0.000000],
+ [2.397469, 0.000040, 0.000000, 0.000000],
+ [2.397469, 0.000038, 0.000000, 0.000000],
+ [2.397469, 0.000037, 0.000000, 0.000000],
+ [2.397469, 0.000035, 0.000000, 0.000000],
+ [2.397469, 0.000033, 0.000000, 0.000000],
+ [2.397469, 0.000032, 0.000000, 0.000000],
+ [2.397469, 0.000030, 0.000000, 0.000000],
+ [2.397469, 0.000029, 0.000000, 0.000000],
+ [2.397469, 0.000027, 0.000000, 0.000000],
+ [2.397469, 0.000026, 0.000000, 0.000000],
+ [2.397469, 0.000025, 0.000000, 0.000000],
+ [2.397469, 0.000024, 0.000000, 0.000000],
+ [2.397469, 0.000023, 0.000000, 0.000000],
+ [2.397469, 0.000022, 0.000000, 0.000000],
+ [2.397469, 0.000021, 0.000000, 0.000000],
+ [2.397469, 0.000020, 0.000000, 0.000000],
+ [2.397469, 0.000019, 0.000000, 0.000000],
+ [2.397469, 0.000018, 0.000000, 0.000000],
+ [2.397469, 0.000017, 0.000000, 0.000000],
+ [2.397469, 0.000016, 0.000000, 0.000000],
+ [2.397469, 0.000015, 0.000000, 0.000000],
+ [2.397469, 0.000015, 0.000000, 0.000000],
+ [2.397469, 0.000014, 0.000000, 0.000000],
+ [2.397469, 0.000013, 0.000000, 0.000000],
+ [2.397469, 0.000013, 0.000000, 0.000000],
+ [2.397469, 0.000012, 0.000000, 0.000000],
+ [2.397469, 0.000012, 0.000000, 0.000000],
+ [2.397469, 0.000011, 0.000000, 0.000000],
+ [2.397469, 0.000011, 0.000000, 0.000000],
+ [2.397469, 0.000010, 0.000000, 0.000000],
+ [2.397469, 0.000010, 0.000000, 0.000000],
+ [2.397469, 0.000009, 0.000000, 0.000000],
+ [2.397469, 0.000009, 0.000000, 0.000000],
+ [2.397469, 0.000008, 0.000000, 0.000000],
+ [2.397469, 0.000008, 0.000000, 0.000000],
+ [2.397469, 0.000008, 0.000000, 0.000000],
+ [2.397469, 0.000007, 0.000000, 0.000000],
+ [2.397469, 0.000007, 0.000000, 0.000000],
+ [2.397469, 0.000007, 0.000000, 0.000000],
+ [2.397469, 0.000006, 0.000000, 0.000000],
+ [2.397469, 0.000006, 0.000000, 0.000000],
+ [2.397469, 0.000006, 0.000000, 0.000000],
+ [2.397469, 0.000005, 0.000000, 0.000000],
+ [2.397469, 0.000005, 0.000000, 0.000000],
+ [2.397469, 0.000005, 0.000000, 0.000000],
+ [2.397469, 0.000005, 0.000000, 0.000000],
+ [2.397469, 0.000004, 0.000000, 0.000000],
+ [2.397469, 0.000004, 0.000000, 0.000000],
+ [2.397469, 0.000004, 0.000000, 0.000000],
+ [2.397469, 0.000004, 0.000000, 0.000000],
+ [2.397469, 0.000004, 0.000000, 0.000000],
+ [2.397469, 0.000004, 0.000000, 0.000000],
+ [2.397469, 0.000003, 0.000000, 0.000000],
+ [2.397469, 0.000003, 0.000000, 0.000000],
+ [2.397469, 0.000003, 0.000000, 0.000000],
+ [2.397469, 0.000003, 0.000000, 0.000000],
+ [2.397469, 0.000003, 0.000000, 0.000000],
+ [2.397469, 0.000003, 0.000000, 0.000000],
+ [2.397469, 0.000003, 0.000000, 0.000000],
+ [2.397469, 0.000002, 0.000000, 0.000000],
+ [2.397469, 0.000002, 0.000000, 0.000000],
+ [2.397469, 0.000002, 0.000000, 0.000000],
+ [2.397469, 0.000002, 0.000000, 0.000000],
+ [2.397469, 0.000002, 0.000000, 0.000000],
+ [2.397469, 0.000002, 0.000000, 0.000000],
+ [2.397469, 0.000002, 0.000000, 0.000000],
+ [2.397469, 0.000002, 0.000000, 0.000000],
+ [2.397469, 0.000002, 0.000000, 0.000000],
+ [2.397469, 0.000002, 0.000000, 0.000000],
+ [2.397469, 0.000001, 0.000000, 0.000000],
+ [2.397469, 0.000001, 0.000000, 0.000000],
+ [2.397469, 0.000001, 0.000000, 0.000000],
+];
+/** @type {Number} */
+const MAX_RE_WEIGHTS_RESOLUTION = MAX_RE_WEIGHTS.length;
+export default {
+ SPHERICAL_HARMONICS,
+ SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION,
+ SPHERICAL_HARMONICS_ELEVATION_RESOLUTION,
+ SPHERICAL_HARMONICS_MAX_ORDER,
+ MAX_RE_WEIGHTS,
+ MAX_RE_WEIGHTS_RESOLUTION
+};
diff --git a/src/framework/resonator/vendor/resonance-es6/utils.d.ts b/src/framework/resonator/vendor/resonance-es6/utils.d.ts
new file mode 100644
index 0000000..48d24d2
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/utils.d.ts
@@ -0,0 +1,98 @@
+export default Utils;
+/**
+ * @class Utils
+ * @description A set of defaults, constants and utility functions.
+ */
+declare class Utils {
+ /**
+ * Properties describing the geometry of a room.
+ * @typedef {Object} Utils~RoomDimensions
+ * @property {Number} width (in meters).
+ * @property {Number} height (in meters).
+ * @property {Number} depth (in meters).
+ */
+ /**
+ * Properties describing the wall materials (from
+ * {@linkcode Utils.ROOM_MATERIAL_COEFFICIENTS ROOM_MATERIAL_COEFFICIENTS})
+ * of a room.
+ * @typedef {Object} Utils~RoomMaterials
+ * @property {String} left Left-wall material name.
+ * @property {String} right Right-wall material name.
+ * @property {String} front Front-wall material name.
+ * @property {String} back Back-wall material name.
+ * @property {String} up Up-wall material name.
+ * @property {String} down Down-wall material name.
+ */
+ /**
+ * ResonanceAudio library logging function.
+ * @type {Function}
+ * @param {any} Message to be printed out.
+ * @private
+ */
+ private static log;
+}
+declare namespace Utils {
+ const DEFAULT_SOURCE_GAIN: number;
+ const LISTENER_MAX_OUTSIDE_ROOM_DISTANCE: number;
+ const SOURCE_MAX_OUTSIDE_ROOM_DISTANCE: number;
+ const DEFAULT_SOURCE_DISTANCE: number;
+ const DEFAULT_POSITION: Float32Array;
+ const DEFAULT_FORWARD: Float32Array;
+ const DEFAULT_UP: Float32Array;
+ const DEFAULT_RIGHT: Float32Array;
+ const DEFAULT_SPEED_OF_SOUND: number;
+ const ATTENUATION_ROLLOFFS: any[];
+ const DEFAULT_ATTENUATION_ROLLOFF: string;
+ const DEFAULT_MIN_DISTANCE: number;
+ const DEFAULT_MAX_DISTANCE: number;
+ const DEFAULT_DIRECTIVITY_ALPHA: number;
+ const DEFAULT_DIRECTIVITY_SHARPNESS: number;
+ const DEFAULT_AZIMUTH: number;
+ const DEFAULT_ELEVATION: number;
+ const DEFAULT_AMBISONIC_ORDER: number;
+ const DEFAULT_SOURCE_WIDTH: number;
+ const DEFAULT_REFLECTION_MAX_DURATION: number;
+ const DEFAULT_REFLECTION_CUTOFF_FREQUENCY: number;
+ const DEFAULT_REFLECTION_COEFFICIENTS: any;
+ const DEFAULT_REFLECTION_MIN_DISTANCE: number;
+ const DEFAULT_ROOM_DIMENSIONS: any;
+ const DEFAULT_REFLECTION_MULTIPLIER: number;
+ const DEFAULT_REVERB_BANDWIDTH: number;
+ const DEFAULT_REVERB_DURATION_MULTIPLIER: number;
+ const DEFAULT_REVERB_PREDELAY: number;
+ const DEFAULT_REVERB_TAIL_ONSET: number;
+ const DEFAULT_REVERB_GAIN: number;
+ const DEFAULT_REVERB_MAX_DURATION: number;
+ const DEFAULT_REVERB_FREQUENCY_BANDS: any[];
+ const NUMBER_REVERB_FREQUENCY_BANDS: number;
+ const DEFAULT_REVERB_DURATIONS: Float32Array;
+ const ROOM_MATERIAL_COEFFICIENTS: any;
+ const DEFAULT_ROOM_MATERIALS: any;
+ const NUMBER_REFLECTION_AVERAGING_BANDS: number;
+ const ROOM_STARTING_AVERAGING_BAND: number;
+ const ROOM_MIN_VOLUME: number;
+ const ROOM_AIR_ABSORPTION_COEFFICIENTS: Float32Array;
+ const ROOM_EYRING_CORRECTION_COEFFICIENT: number;
+ const TWO_PI: number;
+ const TWENTY_FOUR_LOG10: number;
+ const LOG1000: number;
+ const LOG2_DIV2: number;
+ const DEGREES_TO_RADIANS: number;
+ const RADIANS_TO_DEGREES: number;
+ const EPSILON_FLOAT: number;
+ /**
+ * Normalize a 3-d vector.
+ * @param {Float32Array} v 3-element vector.
+ * @return {Float32Array} 3-element vector.
+ * @private
+ */
+ function normalizeVector(v: Float32Array): Float32Array;
+ /**
+ * Cross-product between two 3-d vectors.
+ * @param {Float32Array} a 3-element vector.
+ * @param {Float32Array} b 3-element vector.
+ * @return {Float32Array}
+ * @private
+ */
+ function crossProduct(a: Float32Array, b: Float32Array): Float32Array;
+}
diff --git a/src/framework/resonator/vendor/resonance-es6/utils.js b/src/framework/resonator/vendor/resonance-es6/utils.js
new file mode 100644
index 0000000..5299f0c
--- /dev/null
+++ b/src/framework/resonator/vendor/resonance-es6/utils.js
@@ -0,0 +1,379 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file ResonanceAudio library common utilities, mathematical constants,
+ * and default values.
+ * @author Andrew Allen
+ */
+'use strict';
+/**
+ * @class Utils
+ * @description A set of defaults, constants and utility functions.
+ */
+class Utils {
+ /**
+ * Properties describing the geometry of a room.
+ * @typedef {Object} Utils~RoomDimensions
+ * @property {Number} width (in meters).
+ * @property {Number} height (in meters).
+ * @property {Number} depth (in meters).
+ */
+ /**
+ * Properties describing the wall materials (from
+ * {@linkcode Utils.ROOM_MATERIAL_COEFFICIENTS ROOM_MATERIAL_COEFFICIENTS})
+ * of a room.
+ * @typedef {Object} Utils~RoomMaterials
+ * @property {String} left Left-wall material name.
+ * @property {String} right Right-wall material name.
+ * @property {String} front Front-wall material name.
+ * @property {String} back Back-wall material name.
+ * @property {String} up Up-wall material name.
+ * @property {String} down Down-wall material name.
+ */
+ /**
+ * ResonanceAudio library logging function.
+ * @type {Function}
+ * @param {any} Message to be printed out.
+ * @private
+ */
+ static log() {
+ window.console.log.apply(window.console, [
+ '%c[ResonanceAudio]%c '
+ + Array.prototype.slice.call(arguments).join(' ') + ' %c(@'
+ + performance.now().toFixed(2) + 'ms)',
+ 'background: #BBDEFB; color: #FF5722; font-weight: 700',
+ 'font-weight: 400',
+ 'color: #AAA',
+ ]);
+ }
+}
+/**
+ * Default input gain (linear).
+ * @type {Number}
+ */
+Utils.DEFAULT_SOURCE_GAIN = 1;
+/**
+ * Maximum outside-the-room distance to attenuate far-field listener by.
+ * @type {Number}
+ */
+Utils.LISTENER_MAX_OUTSIDE_ROOM_DISTANCE = 1;
+/**
+ * Maximum outside-the-room distance to attenuate far-field sources by.
+ * @type {Number}
+ */
+Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE = 1;
+/**
+ * Default distance from listener when setting angle.
+ * @type {Number}
+ */
+Utils.DEFAULT_SOURCE_DISTANCE = 1;
+/** @type {Float32Array} */
+Utils.DEFAULT_POSITION = [0, 0, 0];
+/** @type {Float32Array} */
+Utils.DEFAULT_FORWARD = [0, 0, -1];
+/** @type {Float32Array} */
+Utils.DEFAULT_UP = [0, 1, 0];
+/** @type {Float32Array} */
+Utils.DEFAULT_RIGHT = [1, 0, 0];
+/**
+ * @type {Number}
+ */
+Utils.DEFAULT_SPEED_OF_SOUND = 343;
+/** Rolloff models (e.g. 'logarithmic', 'linear', or 'none').
+ * @type {Array}
+ */
+Utils.ATTENUATION_ROLLOFFS = ['logarithmic', 'linear', 'none'];
+/** Default rolloff model ('logarithmic').
+ * @type {string}
+ */
+Utils.DEFAULT_ATTENUATION_ROLLOFF = 'logarithmic';
+/** @type {Number} */
+Utils.DEFAULT_MIN_DISTANCE = 1;
+/** @type {Number} */
+Utils.DEFAULT_MAX_DISTANCE = 1000;
+/**
+ * The default alpha (i.e. microphone pattern).
+ * @type {Number}
+ */
+Utils.DEFAULT_DIRECTIVITY_ALPHA = 0;
+/**
+ * The default pattern sharpness (i.e. pattern exponent).
+ * @type {Number}
+ */
+Utils.DEFAULT_DIRECTIVITY_SHARPNESS = 1;
+/**
+ * Default azimuth (in degrees). Suitable range is 0 to 360.
+ * @type {Number}
+ */
+Utils.DEFAULT_AZIMUTH = 0;
+/**
+ * Default elevation (in degres).
+ * Suitable range is from -90 (below) to 90 (above).
+ * @type {Number}
+ */
+Utils.DEFAULT_ELEVATION = 0;
+/**
+ * The default ambisonic order.
+ * @type {Number}
+ */
+Utils.DEFAULT_AMBISONIC_ORDER = 1;
+/**
+ * The default source width.
+ * @type {Number}
+ */
+Utils.DEFAULT_SOURCE_WIDTH = 0;
+/**
+ * The maximum delay (in seconds) of a single wall reflection.
+ * @type {Number}
+ */
+Utils.DEFAULT_REFLECTION_MAX_DURATION = 0.5;
+/**
+ * The -12dB cutoff frequency (in Hertz) for the lowpass filter applied to
+ * all reflections.
+ * @type {Number}
+ */
+Utils.DEFAULT_REFLECTION_CUTOFF_FREQUENCY = 6400; // Uses -12dB cutoff.
+/**
+ * The default reflection coefficients (where 0 = no reflection, 1 = perfect
+ * reflection, -1 = mirrored reflection (180-degrees out of phase)).
+ * @type {Object}
+ */
+Utils.DEFAULT_REFLECTION_COEFFICIENTS = {
+ left: 0, right: 0, front: 0, back: 0, down: 0, up: 0,
+};
+/**
+ * The minimum distance we consider the listener to be to any given wall.
+ * @type {Number}
+ */
+Utils.DEFAULT_REFLECTION_MIN_DISTANCE = 1;
+/**
+ * Default room dimensions (in meters).
+ * @type {Object}
+ */
+Utils.DEFAULT_ROOM_DIMENSIONS = {
+ width: 0, height: 0, depth: 0,
+};
+/**
+ * The multiplier to apply to distances from the listener to each wall.
+ * @type {Number}
+ */
+Utils.DEFAULT_REFLECTION_MULTIPLIER = 1;
+/** The default bandwidth (in octaves) of the center frequencies.
+ * @type {Number}
+ */
+Utils.DEFAULT_REVERB_BANDWIDTH = 1;
+/** The default multiplier applied when computing tail lengths.
+ * @type {Number}
+ */
+Utils.DEFAULT_REVERB_DURATION_MULTIPLIER = 1;
+/**
+ * The late reflections pre-delay (in milliseconds).
+ * @type {Number}
+ */
+Utils.DEFAULT_REVERB_PREDELAY = 1.5;
+/**
+ * The length of the beginning of the impulse response to apply a
+ * half-Hann window to.
+ * @type {Number}
+ */
+Utils.DEFAULT_REVERB_TAIL_ONSET = 3.8;
+/**
+ * The default gain (linear).
+ * @type {Number}
+ */
+Utils.DEFAULT_REVERB_GAIN = 0.01;
+/**
+ * The maximum impulse response length (in seconds).
+ * @type {Number}
+ */
+Utils.DEFAULT_REVERB_MAX_DURATION = 3;
+/**
+ * Center frequencies of the multiband late reflections.
+ * Nine bands are computed by: 31.25 * 2^(0:8).
+ * @type {Array}
+ */
+Utils.DEFAULT_REVERB_FREQUENCY_BANDS = [
+ 31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000,
+];
+/**
+ * The number of frequency bands.
+ */
+Utils.NUMBER_REVERB_FREQUENCY_BANDS =
+ Utils.DEFAULT_REVERB_FREQUENCY_BANDS.length;
+/**
+ * The default multiband RT60 durations (in seconds).
+ * @type {Float32Array}
+ */
+Utils.DEFAULT_REVERB_DURATIONS =
+ new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS);
+/**
+ * Pre-defined frequency-dependent absorption coefficients for listed materials.
+ * Currently supported materials are:
+ *