cacophony 0.5.8 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cacophony.cjs.js.map +1 -1
- package/dist/cacophony.es.js +7 -0
- package/dist/cacophony.es.js.map +1 -1
- package/dist/cacophony.iife.js.map +1 -1
- package/dist/cacophony.umd.js.map +1 -1
- package/dist/playback.d.ts +1 -1
- package/dist/sound.d.ts +7 -0
- package/docs/classes/Cacophony.html +5 -5
- package/docs/classes/Group.html +3 -3
- package/docs/classes/MicrophonePlayback.html +2 -2
- package/docs/classes/MicrophoneStream.html +3 -3
- package/docs/classes/Playback.html +29 -29
- package/docs/classes/Sound.html +19 -16
- package/docs/enums/SoundType.html +2 -2
- package/docs/interfaces/BaseSound.html +2 -2
- package/docs/types/FadeType.html +1 -1
- package/docs/types/LoopCount.html +1 -1
- package/docs/types/Orientation.html +1 -1
- package/docs/types/PanType.html +1 -1
- package/docs/types/Position.html +1 -1
- package/package.json +1 -1
- package/src/playback.ts +1 -4
- package/src/sound.ts +9 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cacophony.cjs.js","sources":["../src/bundles/phase-vocoder-bundle.js?url","../src/cache.ts","../src/filters.ts","../src/group.ts","../src/playback.ts","../src/sound.ts","../src/stream.ts","../src/cacophony.ts"],"sourcesContent":["export default \"data:application/javascript;base64,KGZ1bmN0aW9uIChleHBvcnRzKSB7CiAgICAndXNlIHN0cmljdCc7CgogICAgY29uc3QgV0VCQVVESU9fQkxPQ0tfU0laRSA9IDEyODsKICAgIGNvbnN0IERFRkFVTFRfQkxPQ0tfU0laRSA9IDEwMjQ7IC8vIERlZmF1bHQgYmxvY2sgc2l6ZSBpZiBub3QgcHJvdmlkZWQgaW4gb3B0aW9ucwogICAgLyoqIE92ZXJsYXAtQWRkIE5vZGUgKi8KICAgIGNsYXNzIE9MQVByb2Nlc3NvciBleHRlbmRzIEF1ZGlvV29ya2xldFByb2Nlc3NvciB7CiAgICAgICAgbmJJbnB1dHM7CiAgICAgICAgbmJPdXRwdXRzOwogICAgICAgIGJsb2NrU2l6ZTsKICAgICAgICBob3BTaXplOwogICAgICAgIG5iT3ZlcmxhcHM7CiAgICAgICAgaW5wdXRCdWZmZXJzID0gW107CiAgICAgICAgaW5wdXRCdWZmZXJzSGVhZCA9IFtdOwogICAgICAgIGlucHV0QnVmZmVyc1RvU2VuZCA9IFtdOwogICAgICAgIG91dHB1dEJ1ZmZlcnMgPSBbXTsKICAgICAgICBvdXRwdXRCdWZmZXJzVG9SZXRyaWV2ZSA9IFtdOwogICAgICAgIGNvbnN0cnVjdG9yKG9wdGlvbnMpIHsKICAgICAgICAgICAgc3VwZXIob3B0aW9ucyk7CiAgICAgICAgICAgIHRoaXMubmJJbnB1dHMgPSBvcHRpb25zLm51bWJlck9mSW5wdXRzIHx8IDE7CiAgICAgICAgICAgIHRoaXMubmJPdXRwdXRzID0gb3B0aW9ucy5udW1iZXJPZk91dHB1dHMgfHwgMTsKICAgICAgICAgICAgdGhpcy5ibG9ja1NpemUgPSBvcHRpb25zLnByb2Nlc3Nvck9wdGlvbnMuYmxvY2tTaXplIHx8IERFRkFVTFRfQkxPQ0tfU0laRTsKICAgICAgICAgICAgdGhpcy5ob3BTaXplID0gV0VCQVVESU9fQkxPQ0tfU0laRTsKICAgICAgICAgICAgdGhpcy5uYk92ZXJsYXBzID0gTWF0aC5mbG9vcih0aGlzLmJsb2NrU2l6ZSAvIHRoaXMuaG9wU2l6ZSk7CiAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUJ1ZmZlcnMoKTsKICAgICAgICB9CiAgICAgICAgaW5pdGlhbGl6ZUJ1ZmZlcnMoKSB7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzID0gbmV3IEFycmF5KHRoaXMubmJJbnB1dHMpOwogICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc0hlYWQgPSBuZXcgQXJyYXkodGhpcy5uYklucHV0cyk7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kID0gbmV3IEFycmF5KHRoaXMubmJJbnB1dHMpOwogICAgICAgICAgICB0aGlzLm91dHB1dEJ1ZmZlcnMgPSBuZXcgQXJyYXkodGhpcy5uYk91dHB1dHMpOwogICAgICAgICAgICB0aGlzLm91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlID0gbmV3IEFycmF5KHRoaXMubmJPdXRwdXRzKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iSW5wdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIHRoaXMuYWxsb2NhdGVJbnB1dENoYW5uZWxzKGksIDEpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5uYk91dHB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5hbGxvY2F0ZU91dHB1dENoYW5uZWxzKGksIDEpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGFsbG9jYXRlSW5wdXRDaGFubmVscyhpbnB1dEluZGV4LCBuYkNoYW5uZWxzKSB7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2lucHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc0hlYWRbaW5wdXRJbmRleF0gPSBuZXcgQXJyYXkobmJDaGFubmVscyk7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kW2lucHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5iQ2hhbm5lbHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNbaW5wdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplICsgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc1tpbnB1dEluZGV4XVtpXS5maWxsKDApOwogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNIZWFkW2lucHV0SW5kZXhdW2ldID0gdGhpcy5pbnB1dEJ1ZmZlcnNbaW5wdXRJbmRleF1baV0uc3ViYXJyYXkoMCwgdGhpcy5ibG9ja1NpemUpOwogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNUb1NlbmRbaW5wdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBhbGxvY2F0ZU91dHB1dENoYW5uZWxzKG91dHB1dEluZGV4LCBuYkNoYW5uZWxzKSB7CiAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1tvdXRwdXRJbmRleF0gPSBuZXcgQXJyYXkobmJDaGFubmVscyk7CiAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1RvUmV0cmlldmVbb3V0cHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5iQ2hhbm5lbHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW291dHB1dEluZGV4XVtpXSA9IG5ldyBGbG9hdDMyQXJyYXkodGhpcy5ibG9ja1NpemUpOwogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW291dHB1dEluZGV4XVtpXS5maWxsKDApOwogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzVG9SZXRyaWV2ZVtvdXRwdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZWFsbG9jYXRlQ2hhbm5lbHNJZk5lZWRlZChpbnB1dHMsIG91dHB1dHMpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iSW5wdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGxldCBuYkNoYW5uZWxzID0gaW5wdXRzW2ldLmxlbmd0aDsKICAgICAgICAgICAgICAgIGlmIChuYkNoYW5uZWxzICE9PSB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmFsbG9jYXRlSW5wdXRDaGFubmVscyhpLCBuYkNoYW5uZWxzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGxldCBuYkNoYW5uZWxzID0gb3V0cHV0c1tpXS5sZW5ndGg7CiAgICAgICAgICAgICAgICBpZiAobmJDaGFubmVscyAhPT0gdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aCkgewogICAgICAgICAgICAgICAgICAgIHRoaXMuYWxsb2NhdGVPdXRwdXRDaGFubmVscyhpLCBuYkNoYW5uZWxzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZWFkSW5wdXRzKGlucHV0cykgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIGxldCB3ZWJBdWRpb0Jsb2NrID0gaW5wdXRzW2ldW2pdOwogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2ldW2pdLnNldCh3ZWJBdWRpb0Jsb2NrLCB0aGlzLmJsb2NrU2l6ZSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgd3JpdGVPdXRwdXRzKG91dHB1dHMpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iT3V0cHV0czsgaSsrKSB7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMub3V0cHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIGxldCB3ZWJBdWRpb0Jsb2NrID0gb3V0cHV0c1tpXVtqXTsKICAgICAgICAgICAgICAgICAgICB3ZWJBdWRpb0Jsb2NrLnNldCh0aGlzLm91dHB1dEJ1ZmZlcnNbaV1bal0uc3ViYXJyYXkoMCwgV0VCQVVESU9fQkxPQ0tfU0laRSkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHNoaWZ0SW5wdXRCdWZmZXJzKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2ldW2pdLmNvcHlXaXRoaW4oMCwgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgc2hpZnRPdXRwdXRCdWZmZXJzKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aDsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW2ldW2pdLmNvcHlXaXRoaW4oMCwgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW2ldW2pdLmZpbGwoMCwgdGhpcy5ibG9ja1NpemUgLSBXRUJBVURJT19CTE9DS19TSVpFKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcmVwYXJlSW5wdXRCdWZmZXJzVG9TZW5kKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kW2ldW2pdLnNldCh0aGlzLmlucHV0QnVmZmVyc0hlYWRbaV1bal0pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGhhbmRsZU91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aDsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgayA9IDA7IGsgPCB0aGlzLmJsb2NrU2l6ZTsgaysrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1tpXVtqXVtrXSArPSB0aGlzLm91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlW2ldW2pdW2tdIC8gdGhpcy5uYk92ZXJsYXBzOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzKGlucHV0cywgb3V0cHV0cywgcGFyYW1ldGVycykgewogICAgICAgICAgICB0aGlzLnJlYWxsb2NhdGVDaGFubmVsc0lmTmVlZGVkKGlucHV0cywgb3V0cHV0cyk7CiAgICAgICAgICAgIHRoaXMucmVhZElucHV0cyhpbnB1dHMpOwogICAgICAgICAgICB0aGlzLnNoaWZ0SW5wdXRCdWZmZXJzKCk7CiAgICAgICAgICAgIHRoaXMucHJlcGFyZUlucHV0QnVmZmVyc1RvU2VuZCgpOwogICAgICAgICAgICB0aGlzLnByb2Nlc3NPTEEodGhpcy5pbnB1dEJ1ZmZlcnNUb1NlbmQsIHRoaXMub3V0cHV0QnVmZmVyc1RvUmV0cmlldmUsIHBhcmFtZXRlcnMpOwogICAgICAgICAgICB0aGlzLmhhbmRsZU91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlKCk7CiAgICAgICAgICAgIHRoaXMud3JpdGVPdXRwdXRzKG91dHB1dHMpOwogICAgICAgICAgICB0aGlzLnNoaWZ0T3V0cHV0QnVmZmVycygpOwogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMgKHgpIHsKICAgIAlyZXR1cm4geCAmJiB4Ll9fZXNNb2R1bGUgJiYgT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHgsICdkZWZhdWx0JykgPyB4WydkZWZhdWx0J10gOiB4OwogICAgfQoKICAgIGZ1bmN0aW9uIEZGVChzaXplKSB7CiAgICAgIHRoaXMuc2l6ZSA9IHNpemUgfCAwOwogICAgICBpZiAodGhpcy5zaXplIDw9IDEgfHwgKHRoaXMuc2l6ZSAmICh0aGlzLnNpemUgLSAxKSkgIT09IDApCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdGRlQgc2l6ZSBtdXN0IGJlIGEgcG93ZXIgb2YgdHdvIGFuZCBiaWdnZXIgdGhhbiAxJyk7CgogICAgICB0aGlzLl9jc2l6ZSA9IHNpemUgPDwgMTsKCiAgICAgIC8vIE5PVEU6IFVzZSBvZiBgdmFyYCBpcyBpbnRlbnRpb25hbCBmb3Igb2xkIFY4IHZlcnNpb25zCiAgICAgIHZhciB0YWJsZSA9IG5ldyBBcnJheSh0aGlzLnNpemUgKiAyKTsKICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0YWJsZS5sZW5ndGg7IGkgKz0gMikgewogICAgICAgIGNvbnN0IGFuZ2xlID0gTWF0aC5QSSAqIGkgLyB0aGlzLnNpemU7CiAgICAgICAgdGFibGVbaV0gPSBNYXRoLmNvcyhhbmdsZSk7CiAgICAgICAgdGFibGVbaSArIDFdID0gLU1hdGguc2luKGFuZ2xlKTsKICAgICAgfQogICAgICB0aGlzLnRhYmxlID0gdGFibGU7CgogICAgICAvLyBGaW5kIHNpemUncyBwb3dlciBvZiB0d28KICAgICAgdmFyIHBvd2VyID0gMDsKICAgICAgZm9yICh2YXIgdCA9IDE7IHRoaXMuc2l6ZSA+IHQ7IHQgPDw9IDEpCiAgICAgICAgcG93ZXIrKzsKCiAgICAgIC8vIENhbGN1bGF0ZSBpbml0aWFsIHN0ZXAncyB3aWR0aDoKICAgICAgLy8gICAqIElmIHdlIGFyZSBmdWxsIHJhZGl4LTQgLSBpdCBpcyAyeCBzbWFsbGVyIHRvIGdpdmUgaW5pdGFsIGxlbj04CiAgICAgIC8vICAgKiBPdGhlcndpc2UgaXQgaXMgdGhlIHNhbWUgYXMgYHBvd2VyYCB0byBnaXZlIGxlbj00CiAgICAgIHRoaXMuX3dpZHRoID0gcG93ZXIgJSAyID09PSAwID8gcG93ZXIgLSAxIDogcG93ZXI7CgogICAgICAvLyBQcmUtY29tcHV0ZSBiaXQtcmV2ZXJzYWwgcGF0dGVybnMKICAgICAgdGhpcy5fYml0cmV2ID0gbmV3IEFycmF5KDEgPDwgdGhpcy5fd2lkdGgpOwogICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHRoaXMuX2JpdHJldi5sZW5ndGg7IGorKykgewogICAgICAgIHRoaXMuX2JpdHJldltqXSA9IDA7CiAgICAgICAgZm9yICh2YXIgc2hpZnQgPSAwOyBzaGlmdCA8IHRoaXMuX3dpZHRoOyBzaGlmdCArPSAyKSB7CiAgICAgICAgICB2YXIgcmV2U2hpZnQgPSB0aGlzLl93aWR0aCAtIHNoaWZ0IC0gMjsKICAgICAgICAgIHRoaXMuX2JpdHJldltqXSB8PSAoKGogPj4+IHNoaWZ0KSAmIDMpIDw8IHJldlNoaWZ0OwogICAgICAgIH0KICAgICAgfQoKICAgICAgdGhpcy5fb3V0ID0gbnVsbDsKICAgICAgdGhpcy5fZGF0YSA9IG51bGw7CiAgICAgIHRoaXMuX2ludiA9IDA7CiAgICB9CiAgICB2YXIgZmZ0ID0gRkZUOwoKICAgIEZGVC5wcm90b3R5cGUuZnJvbUNvbXBsZXhBcnJheSA9IGZ1bmN0aW9uIGZyb21Db21wbGV4QXJyYXkoY29tcGxleCwgc3RvcmFnZSkgewogICAgICB2YXIgcmVzID0gc3RvcmFnZSB8fCBuZXcgQXJyYXkoY29tcGxleC5sZW5ndGggPj4+IDEpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvbXBsZXgubGVuZ3RoOyBpICs9IDIpCiAgICAgICAgcmVzW2kgPj4+IDFdID0gY29tcGxleFtpXTsKICAgICAgcmV0dXJuIHJlczsKICAgIH07CgogICAgRkZULnByb3RvdHlwZS5jcmVhdGVDb21wbGV4QXJyYXkgPSBmdW5jdGlvbiBjcmVhdGVDb21wbGV4QXJyYXkoKSB7CiAgICAgIGNvbnN0IHJlcyA9IG5ldyBBcnJheSh0aGlzLl9jc2l6ZSk7CiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmVzLmxlbmd0aDsgaSsrKQogICAgICAgIHJlc1tpXSA9IDA7CiAgICAgIHJldHVybiByZXM7CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUudG9Db21wbGV4QXJyYXkgPSBmdW5jdGlvbiB0b0NvbXBsZXhBcnJheShpbnB1dCwgc3RvcmFnZSkgewogICAgICB2YXIgcmVzID0gc3RvcmFnZSB8fCB0aGlzLmNyZWF0ZUNvbXBsZXhBcnJheSgpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJlcy5sZW5ndGg7IGkgKz0gMikgewogICAgICAgIHJlc1tpXSA9IGlucHV0W2kgPj4+IDFdOwogICAgICAgIHJlc1tpICsgMV0gPSAwOwogICAgICB9CiAgICAgIHJldHVybiByZXM7CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUuY29tcGxldGVTcGVjdHJ1bSA9IGZ1bmN0aW9uIGNvbXBsZXRlU3BlY3RydW0oc3BlY3RydW0pIHsKICAgICAgdmFyIHNpemUgPSB0aGlzLl9jc2l6ZTsKICAgICAgdmFyIGhhbGYgPSBzaXplID4+PiAxOwogICAgICBmb3IgKHZhciBpID0gMjsgaSA8IGhhbGY7IGkgKz0gMikgewogICAgICAgIHNwZWN0cnVtW3NpemUgLSBpXSA9IHNwZWN0cnVtW2ldOwogICAgICAgIHNwZWN0cnVtW3NpemUgLSBpICsgMV0gPSAtc3BlY3RydW1baSArIDFdOwogICAgICB9CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUudHJhbnNmb3JtID0gZnVuY3Rpb24gdHJhbnNmb3JtKG91dCwgZGF0YSkgewogICAgICBpZiAob3V0ID09PSBkYXRhKQogICAgICAgIHRocm93IG5ldyBFcnJvcignSW5wdXQgYW5kIG91dHB1dCBidWZmZXJzIG11c3QgYmUgZGlmZmVyZW50Jyk7CgogICAgICB0aGlzLl9vdXQgPSBvdXQ7CiAgICAgIHRoaXMuX2RhdGEgPSBkYXRhOwogICAgICB0aGlzLl9pbnYgPSAwOwogICAgICB0aGlzLl90cmFuc2Zvcm00KCk7CiAgICAgIHRoaXMuX291dCA9IG51bGw7CiAgICAgIHRoaXMuX2RhdGEgPSBudWxsOwogICAgfTsKCiAgICBGRlQucHJvdG90eXBlLnJlYWxUcmFuc2Zvcm0gPSBmdW5jdGlvbiByZWFsVHJhbnNmb3JtKG91dCwgZGF0YSkgewogICAgICBpZiAob3V0ID09PSBkYXRhKQogICAgICAgIHRocm93IG5ldyBFcnJvcignSW5wdXQgYW5kIG91dHB1dCBidWZmZXJzIG11c3QgYmUgZGlmZmVyZW50Jyk7CgogICAgICB0aGlzLl9vdXQgPSBvdXQ7CiAgICAgIHRoaXMuX2RhdGEgPSBkYXRhOwogICAgICB0aGlzLl9pbnYgPSAwOwogICAgICB0aGlzLl9yZWFsVHJhbnNmb3JtNCgpOwogICAgICB0aGlzLl9vdXQgPSBudWxsOwogICAgICB0aGlzLl9kYXRhID0gbnVsbDsKICAgIH07CgogICAgRkZULnByb3RvdHlwZS5pbnZlcnNlVHJhbnNmb3JtID0gZnVuY3Rpb24gaW52ZXJzZVRyYW5zZm9ybShvdXQsIGRhdGEpIHsKICAgICAgaWYgKG91dCA9PT0gZGF0YSkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0lucHV0IGFuZCBvdXRwdXQgYnVmZmVycyBtdXN0IGJlIGRpZmZlcmVudCcpOwoKICAgICAgdGhpcy5fb3V0ID0gb3V0OwogICAgICB0aGlzLl9kYXRhID0gZGF0YTsKICAgICAgdGhpcy5faW52ID0gMTsKICAgICAgdGhpcy5fdHJhbnNmb3JtNCgpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG91dC5sZW5ndGg7IGkrKykKICAgICAgICBvdXRbaV0gLz0gdGhpcy5zaXplOwogICAgICB0aGlzLl9vdXQgPSBudWxsOwogICAgICB0aGlzLl9kYXRhID0gbnVsbDsKICAgIH07CgogICAgLy8gcmFkaXgtNCBpbXBsZW1lbnRhdGlvbgogICAgLy8KICAgIC8vIE5PVEU6IFVzZXMgb2YgYHZhcmAgYXJlIGludGVudGlvbmFsIGZvciBvbGRlciBWOCB2ZXJzaW9uIHRoYXQgZG8gbm90CiAgICAvLyBzdXBwb3J0IGJvdGggYGxldCBjb21wb3VuZCBhc3NpZ25tZW50c2AgYW5kIGBjb25zdCBwaGlgCiAgICBGRlQucHJvdG90eXBlLl90cmFuc2Zvcm00ID0gZnVuY3Rpb24gX3RyYW5zZm9ybTQoKSB7CiAgICAgIHZhciBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIHZhciBzaXplID0gdGhpcy5fY3NpemU7CgogICAgICAvLyBJbml0aWFsIHN0ZXAgKHBlcm11dGUgYW5kIHRyYW5zZm9ybSkKICAgICAgdmFyIHdpZHRoID0gdGhpcy5fd2lkdGg7CiAgICAgIHZhciBzdGVwID0gMSA8PCB3aWR0aDsKICAgICAgdmFyIGxlbiA9IChzaXplIC8gc3RlcCkgPDwgMTsKCiAgICAgIHZhciBvdXRPZmY7CiAgICAgIHZhciB0OwogICAgICB2YXIgYml0cmV2ID0gdGhpcy5fYml0cmV2OwogICAgICBpZiAobGVuID09PSA0KSB7CiAgICAgICAgZm9yIChvdXRPZmYgPSAwLCB0ID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbiwgdCsrKSB7CiAgICAgICAgICBjb25zdCBvZmYgPSBiaXRyZXZbdF07CiAgICAgICAgICB0aGlzLl9zaW5nbGVUcmFuc2Zvcm0yKG91dE9mZiwgb2ZmLCBzdGVwKTsKICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgLy8gbGVuID09PSA4CiAgICAgICAgZm9yIChvdXRPZmYgPSAwLCB0ID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbiwgdCsrKSB7CiAgICAgICAgICBjb25zdCBvZmYgPSBiaXRyZXZbdF07CiAgICAgICAgICB0aGlzLl9zaW5nbGVUcmFuc2Zvcm00KG91dE9mZiwgb2ZmLCBzdGVwKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8vIExvb3AgdGhyb3VnaCBzdGVwcyBpbiBkZWNyZWFzaW5nIG9yZGVyCiAgICAgIHZhciBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIHZhciB0YWJsZSA9IHRoaXMudGFibGU7CiAgICAgIGZvciAoc3RlcCA+Pj0gMjsgc3RlcCA+PSAyOyBzdGVwID4+PSAyKSB7CiAgICAgICAgbGVuID0gKHNpemUgLyBzdGVwKSA8PCAxOwogICAgICAgIHZhciBxdWFydGVyTGVuID0gbGVuID4+PiAyOwoKICAgICAgICAvLyBMb29wIHRocm91Z2ggb2Zmc2V0cyBpbiB0aGUgZGF0YQogICAgICAgIGZvciAob3V0T2ZmID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbikgewogICAgICAgICAgLy8gRnVsbCBjYXNlCiAgICAgICAgICB2YXIgbGltaXQgPSBvdXRPZmYgKyBxdWFydGVyTGVuOwogICAgICAgICAgZm9yICh2YXIgaSA9IG91dE9mZiwgayA9IDA7IGkgPCBsaW1pdDsgaSArPSAyLCBrICs9IHN0ZXApIHsKICAgICAgICAgICAgY29uc3QgQSA9IGk7CiAgICAgICAgICAgIGNvbnN0IEIgPSBBICsgcXVhcnRlckxlbjsKICAgICAgICAgICAgY29uc3QgQyA9IEIgKyBxdWFydGVyTGVuOwogICAgICAgICAgICBjb25zdCBEID0gQyArIHF1YXJ0ZXJMZW47CgogICAgICAgICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgQXIgPSBvdXRbQV07CiAgICAgICAgICAgIGNvbnN0IEFpID0gb3V0W0EgKyAxXTsKICAgICAgICAgICAgY29uc3QgQnIgPSBvdXRbQl07CiAgICAgICAgICAgIGNvbnN0IEJpID0gb3V0W0IgKyAxXTsKICAgICAgICAgICAgY29uc3QgQ3IgPSBvdXRbQ107CiAgICAgICAgICAgIGNvbnN0IENpID0gb3V0W0MgKyAxXTsKICAgICAgICAgICAgY29uc3QgRHIgPSBvdXRbRF07CiAgICAgICAgICAgIGNvbnN0IERpID0gb3V0W0QgKyAxXTsKCiAgICAgICAgICAgIC8vIE1pZGRsZSB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgTUFyID0gQXI7CiAgICAgICAgICAgIGNvbnN0IE1BaSA9IEFpOwoKICAgICAgICAgICAgY29uc3QgdGFibGVCciA9IHRhYmxlW2tdOwogICAgICAgICAgICBjb25zdCB0YWJsZUJpID0gaW52ICogdGFibGVbayArIDFdOwogICAgICAgICAgICBjb25zdCBNQnIgPSBCciAqIHRhYmxlQnIgLSBCaSAqIHRhYmxlQmk7CiAgICAgICAgICAgIGNvbnN0IE1CaSA9IEJyICogdGFibGVCaSArIEJpICogdGFibGVCcjsKCiAgICAgICAgICAgIGNvbnN0IHRhYmxlQ3IgPSB0YWJsZVsyICoga107CiAgICAgICAgICAgIGNvbnN0IHRhYmxlQ2kgPSBpbnYgKiB0YWJsZVsyICogayArIDFdOwogICAgICAgICAgICBjb25zdCBNQ3IgPSBDciAqIHRhYmxlQ3IgLSBDaSAqIHRhYmxlQ2k7CiAgICAgICAgICAgIGNvbnN0IE1DaSA9IENyICogdGFibGVDaSArIENpICogdGFibGVDcjsKCiAgICAgICAgICAgIGNvbnN0IHRhYmxlRHIgPSB0YWJsZVszICoga107CiAgICAgICAgICAgIGNvbnN0IHRhYmxlRGkgPSBpbnYgKiB0YWJsZVszICogayArIDFdOwogICAgICAgICAgICBjb25zdCBNRHIgPSBEciAqIHRhYmxlRHIgLSBEaSAqIHRhYmxlRGk7CiAgICAgICAgICAgIGNvbnN0IE1EaSA9IERyICogdGFibGVEaSArIERpICogdGFibGVEcjsKCiAgICAgICAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgVDByID0gTUFyICsgTUNyOwogICAgICAgICAgICBjb25zdCBUMGkgPSBNQWkgKyBNQ2k7CiAgICAgICAgICAgIGNvbnN0IFQxciA9IE1BciAtIE1DcjsKICAgICAgICAgICAgY29uc3QgVDFpID0gTUFpIC0gTUNpOwogICAgICAgICAgICBjb25zdCBUMnIgPSBNQnIgKyBNRHI7CiAgICAgICAgICAgIGNvbnN0IFQyaSA9IE1CaSArIE1EaTsKICAgICAgICAgICAgY29uc3QgVDNyID0gaW52ICogKE1CciAtIE1Ecik7CiAgICAgICAgICAgIGNvbnN0IFQzaSA9IGludiAqIChNQmkgLSBNRGkpOwoKICAgICAgICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgICAgICAgIGNvbnN0IEZBciA9IFQwciArIFQycjsKICAgICAgICAgICAgY29uc3QgRkFpID0gVDBpICsgVDJpOwoKICAgICAgICAgICAgY29uc3QgRkNyID0gVDByIC0gVDJyOwogICAgICAgICAgICBjb25zdCBGQ2kgPSBUMGkgLSBUMmk7CgogICAgICAgICAgICBjb25zdCBGQnIgPSBUMXIgKyBUM2k7CiAgICAgICAgICAgIGNvbnN0IEZCaSA9IFQxaSAtIFQzcjsKCiAgICAgICAgICAgIGNvbnN0IEZEciA9IFQxciAtIFQzaTsKICAgICAgICAgICAgY29uc3QgRkRpID0gVDFpICsgVDNyOwoKICAgICAgICAgICAgb3V0W0FdID0gRkFyOwogICAgICAgICAgICBvdXRbQSArIDFdID0gRkFpOwogICAgICAgICAgICBvdXRbQl0gPSBGQnI7CiAgICAgICAgICAgIG91dFtCICsgMV0gPSBGQmk7CiAgICAgICAgICAgIG91dFtDXSA9IEZDcjsKICAgICAgICAgICAgb3V0W0MgKyAxXSA9IEZDaTsKICAgICAgICAgICAgb3V0W0RdID0gRkRyOwogICAgICAgICAgICBvdXRbRCArIDFdID0gRkRpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfTsKCiAgICAvLyByYWRpeC0yIGltcGxlbWVudGF0aW9uCiAgICAvLwogICAgLy8gTk9URTogT25seSBjYWxsZWQgZm9yIGxlbj00CiAgICBGRlQucHJvdG90eXBlLl9zaW5nbGVUcmFuc2Zvcm0yID0gZnVuY3Rpb24gX3NpbmdsZVRyYW5zZm9ybTIob3V0T2ZmLCBvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwoKICAgICAgY29uc3QgZXZlblIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IGV2ZW5JID0gZGF0YVtvZmYgKyAxXTsKICAgICAgY29uc3Qgb2RkUiA9IGRhdGFbb2ZmICsgc3RlcF07CiAgICAgIGNvbnN0IG9kZEkgPSBkYXRhW29mZiArIHN0ZXAgKyAxXTsKCiAgICAgIGNvbnN0IGxlZnRSID0gZXZlblIgKyBvZGRSOwogICAgICBjb25zdCBsZWZ0SSA9IGV2ZW5JICsgb2RkSTsKICAgICAgY29uc3QgcmlnaHRSID0gZXZlblIgLSBvZGRSOwogICAgICBjb25zdCByaWdodEkgPSBldmVuSSAtIG9kZEk7CgogICAgICBvdXRbb3V0T2ZmXSA9IGxlZnRSOwogICAgICBvdXRbb3V0T2ZmICsgMV0gPSBsZWZ0STsKICAgICAgb3V0W291dE9mZiArIDJdID0gcmlnaHRSOwogICAgICBvdXRbb3V0T2ZmICsgM10gPSByaWdodEk7CiAgICB9OwoKICAgIC8vIHJhZGl4LTQKICAgIC8vCiAgICAvLyBOT1RFOiBPbmx5IGNhbGxlZCBmb3IgbGVuPTgKICAgIEZGVC5wcm90b3R5cGUuX3NpbmdsZVRyYW5zZm9ybTQgPSBmdW5jdGlvbiBfc2luZ2xlVHJhbnNmb3JtNChvdXRPZmYsIG9mZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwKSB7CiAgICAgIGNvbnN0IG91dCA9IHRoaXMuX291dDsKICAgICAgY29uc3QgZGF0YSA9IHRoaXMuX2RhdGE7CiAgICAgIGNvbnN0IGludiA9IHRoaXMuX2ludiA/IC0xIDogMTsKICAgICAgY29uc3Qgc3RlcDIgPSBzdGVwICogMjsKICAgICAgY29uc3Qgc3RlcDMgPSBzdGVwICogMzsKCiAgICAgIC8vIE9yaWdpbmFsIHZhbHVlcwogICAgICBjb25zdCBBciA9IGRhdGFbb2ZmXTsKICAgICAgY29uc3QgQWkgPSBkYXRhW29mZiArIDFdOwogICAgICBjb25zdCBCciA9IGRhdGFbb2ZmICsgc3RlcF07CiAgICAgIGNvbnN0IEJpID0gZGF0YVtvZmYgKyBzdGVwICsgMV07CiAgICAgIGNvbnN0IENyID0gZGF0YVtvZmYgKyBzdGVwMl07CiAgICAgIGNvbnN0IENpID0gZGF0YVtvZmYgKyBzdGVwMiArIDFdOwogICAgICBjb25zdCBEciA9IGRhdGFbb2ZmICsgc3RlcDNdOwogICAgICBjb25zdCBEaSA9IGRhdGFbb2ZmICsgc3RlcDMgKyAxXTsKCiAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgVDByID0gQXIgKyBDcjsKICAgICAgY29uc3QgVDBpID0gQWkgKyBDaTsKICAgICAgY29uc3QgVDFyID0gQXIgLSBDcjsKICAgICAgY29uc3QgVDFpID0gQWkgLSBDaTsKICAgICAgY29uc3QgVDJyID0gQnIgKyBEcjsKICAgICAgY29uc3QgVDJpID0gQmkgKyBEaTsKICAgICAgY29uc3QgVDNyID0gaW52ICogKEJyIC0gRHIpOwogICAgICBjb25zdCBUM2kgPSBpbnYgKiAoQmkgLSBEaSk7CgogICAgICAvLyBGaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgRkFyID0gVDByICsgVDJyOwogICAgICBjb25zdCBGQWkgPSBUMGkgKyBUMmk7CgogICAgICBjb25zdCBGQnIgPSBUMXIgKyBUM2k7CiAgICAgIGNvbnN0IEZCaSA9IFQxaSAtIFQzcjsKCiAgICAgIGNvbnN0IEZDciA9IFQwciAtIFQycjsKICAgICAgY29uc3QgRkNpID0gVDBpIC0gVDJpOwoKICAgICAgY29uc3QgRkRyID0gVDFyIC0gVDNpOwogICAgICBjb25zdCBGRGkgPSBUMWkgKyBUM3I7CgogICAgICBvdXRbb3V0T2ZmXSA9IEZBcjsKICAgICAgb3V0W291dE9mZiArIDFdID0gRkFpOwogICAgICBvdXRbb3V0T2ZmICsgMl0gPSBGQnI7CiAgICAgIG91dFtvdXRPZmYgKyAzXSA9IEZCaTsKICAgICAgb3V0W291dE9mZiArIDRdID0gRkNyOwogICAgICBvdXRbb3V0T2ZmICsgNV0gPSBGQ2k7CiAgICAgIG91dFtvdXRPZmYgKyA2XSA9IEZEcjsKICAgICAgb3V0W291dE9mZiArIDddID0gRkRpOwogICAgfTsKCiAgICAvLyBSZWFsIGlucHV0IHJhZGl4LTQgaW1wbGVtZW50YXRpb24KICAgIEZGVC5wcm90b3R5cGUuX3JlYWxUcmFuc2Zvcm00ID0gZnVuY3Rpb24gX3JlYWxUcmFuc2Zvcm00KCkgewogICAgICB2YXIgb3V0ID0gdGhpcy5fb3V0OwogICAgICB2YXIgc2l6ZSA9IHRoaXMuX2NzaXplOwoKICAgICAgLy8gSW5pdGlhbCBzdGVwIChwZXJtdXRlIGFuZCB0cmFuc2Zvcm0pCiAgICAgIHZhciB3aWR0aCA9IHRoaXMuX3dpZHRoOwogICAgICB2YXIgc3RlcCA9IDEgPDwgd2lkdGg7CiAgICAgIHZhciBsZW4gPSAoc2l6ZSAvIHN0ZXApIDw8IDE7CgogICAgICB2YXIgb3V0T2ZmOwogICAgICB2YXIgdDsKICAgICAgdmFyIGJpdHJldiA9IHRoaXMuX2JpdHJldjsKICAgICAgaWYgKGxlbiA9PT0gNCkgewogICAgICAgIGZvciAob3V0T2ZmID0gMCwgdCA9IDA7IG91dE9mZiA8IHNpemU7IG91dE9mZiArPSBsZW4sIHQrKykgewogICAgICAgICAgY29uc3Qgb2ZmID0gYml0cmV2W3RdOwogICAgICAgICAgdGhpcy5fc2luZ2xlUmVhbFRyYW5zZm9ybTIob3V0T2ZmLCBvZmYgPj4+IDEsIHN0ZXAgPj4+IDEpOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICAvLyBsZW4gPT09IDgKICAgICAgICBmb3IgKG91dE9mZiA9IDAsIHQgPSAwOyBvdXRPZmYgPCBzaXplOyBvdXRPZmYgKz0gbGVuLCB0KyspIHsKICAgICAgICAgIGNvbnN0IG9mZiA9IGJpdHJldlt0XTsKICAgICAgICAgIHRoaXMuX3NpbmdsZVJlYWxUcmFuc2Zvcm00KG91dE9mZiwgb2ZmID4+PiAxLCBzdGVwID4+PiAxKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8vIExvb3AgdGhyb3VnaCBzdGVwcyBpbiBkZWNyZWFzaW5nIG9yZGVyCiAgICAgIHZhciBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIHZhciB0YWJsZSA9IHRoaXMudGFibGU7CiAgICAgIGZvciAoc3RlcCA+Pj0gMjsgc3RlcCA+PSAyOyBzdGVwID4+PSAyKSB7CiAgICAgICAgbGVuID0gKHNpemUgLyBzdGVwKSA8PCAxOwogICAgICAgIHZhciBoYWxmTGVuID0gbGVuID4+PiAxOwogICAgICAgIHZhciBxdWFydGVyTGVuID0gaGFsZkxlbiA+Pj4gMTsKICAgICAgICB2YXIgaHF1YXJ0ZXJMZW4gPSBxdWFydGVyTGVuID4+PiAxOwoKICAgICAgICAvLyBMb29wIHRocm91Z2ggb2Zmc2V0cyBpbiB0aGUgZGF0YQogICAgICAgIGZvciAob3V0T2ZmID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbikgewogICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGsgPSAwOyBpIDw9IGhxdWFydGVyTGVuOyBpICs9IDIsIGsgKz0gc3RlcCkgewogICAgICAgICAgICB2YXIgQSA9IG91dE9mZiArIGk7CiAgICAgICAgICAgIHZhciBCID0gQSArIHF1YXJ0ZXJMZW47CiAgICAgICAgICAgIHZhciBDID0gQiArIHF1YXJ0ZXJMZW47CiAgICAgICAgICAgIHZhciBEID0gQyArIHF1YXJ0ZXJMZW47CgogICAgICAgICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgICAgICAgdmFyIEFyID0gb3V0W0FdOwogICAgICAgICAgICB2YXIgQWkgPSBvdXRbQSArIDFdOwogICAgICAgICAgICB2YXIgQnIgPSBvdXRbQl07CiAgICAgICAgICAgIHZhciBCaSA9IG91dFtCICsgMV07CiAgICAgICAgICAgIHZhciBDciA9IG91dFtDXTsKICAgICAgICAgICAgdmFyIENpID0gb3V0W0MgKyAxXTsKICAgICAgICAgICAgdmFyIERyID0gb3V0W0RdOwogICAgICAgICAgICB2YXIgRGkgPSBvdXRbRCArIDFdOwoKICAgICAgICAgICAgLy8gTWlkZGxlIHZhbHVlcwogICAgICAgICAgICB2YXIgTUFyID0gQXI7CiAgICAgICAgICAgIHZhciBNQWkgPSBBaTsKCiAgICAgICAgICAgIHZhciB0YWJsZUJyID0gdGFibGVba107CiAgICAgICAgICAgIHZhciB0YWJsZUJpID0gaW52ICogdGFibGVbayArIDFdOwogICAgICAgICAgICB2YXIgTUJyID0gQnIgKiB0YWJsZUJyIC0gQmkgKiB0YWJsZUJpOwogICAgICAgICAgICB2YXIgTUJpID0gQnIgKiB0YWJsZUJpICsgQmkgKiB0YWJsZUJyOwoKICAgICAgICAgICAgdmFyIHRhYmxlQ3IgPSB0YWJsZVsyICoga107CiAgICAgICAgICAgIHZhciB0YWJsZUNpID0gaW52ICogdGFibGVbMiAqIGsgKyAxXTsKICAgICAgICAgICAgdmFyIE1DciA9IENyICogdGFibGVDciAtIENpICogdGFibGVDaTsKICAgICAgICAgICAgdmFyIE1DaSA9IENyICogdGFibGVDaSArIENpICogdGFibGVDcjsKCiAgICAgICAgICAgIHZhciB0YWJsZURyID0gdGFibGVbMyAqIGtdOwogICAgICAgICAgICB2YXIgdGFibGVEaSA9IGludiAqIHRhYmxlWzMgKiBrICsgMV07CiAgICAgICAgICAgIHZhciBNRHIgPSBEciAqIHRhYmxlRHIgLSBEaSAqIHRhYmxlRGk7CiAgICAgICAgICAgIHZhciBNRGkgPSBEciAqIHRhYmxlRGkgKyBEaSAqIHRhYmxlRHI7CgogICAgICAgICAgICAvLyBQcmUtRmluYWwgdmFsdWVzCiAgICAgICAgICAgIHZhciBUMHIgPSBNQXIgKyBNQ3I7CiAgICAgICAgICAgIHZhciBUMGkgPSBNQWkgKyBNQ2k7CiAgICAgICAgICAgIHZhciBUMXIgPSBNQXIgLSBNQ3I7CiAgICAgICAgICAgIHZhciBUMWkgPSBNQWkgLSBNQ2k7CiAgICAgICAgICAgIHZhciBUMnIgPSBNQnIgKyBNRHI7CiAgICAgICAgICAgIHZhciBUMmkgPSBNQmkgKyBNRGk7CiAgICAgICAgICAgIHZhciBUM3IgPSBpbnYgKiAoTUJyIC0gTURyKTsKICAgICAgICAgICAgdmFyIFQzaSA9IGludiAqIChNQmkgLSBNRGkpOwoKICAgICAgICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgICAgICAgIHZhciBGQXIgPSBUMHIgKyBUMnI7CiAgICAgICAgICAgIHZhciBGQWkgPSBUMGkgKyBUMmk7CgogICAgICAgICAgICB2YXIgRkJyID0gVDFyICsgVDNpOwogICAgICAgICAgICB2YXIgRkJpID0gVDFpIC0gVDNyOwoKICAgICAgICAgICAgb3V0W0FdID0gRkFyOwogICAgICAgICAgICBvdXRbQSArIDFdID0gRkFpOwogICAgICAgICAgICBvdXRbQl0gPSBGQnI7CiAgICAgICAgICAgIG91dFtCICsgMV0gPSBGQmk7CgogICAgICAgICAgICAvLyBPdXRwdXQgZmluYWwgbWlkZGxlIHBvaW50CiAgICAgICAgICAgIGlmIChpID09PSAwKSB7CiAgICAgICAgICAgICAgdmFyIEZDciA9IFQwciAtIFQycjsKICAgICAgICAgICAgICB2YXIgRkNpID0gVDBpIC0gVDJpOwogICAgICAgICAgICAgIG91dFtDXSA9IEZDcjsKICAgICAgICAgICAgICBvdXRbQyArIDFdID0gRkNpOwogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBEbyBub3Qgb3ZlcndyaXRlIG91cnNlbHZlcwogICAgICAgICAgICBpZiAoaSA9PT0gaHF1YXJ0ZXJMZW4pCiAgICAgICAgICAgICAgY29udGludWU7CgogICAgICAgICAgICAvLyBJbiB0aGUgZmxpcHBlZCBjYXNlOgogICAgICAgICAgICAvLyBNQWkgPSAtTUFpCiAgICAgICAgICAgIC8vIE1Ccj0tTUJpLCBNQmk9LU1CcgogICAgICAgICAgICAvLyBNQ3I9LU1DcgogICAgICAgICAgICAvLyBNRHI9TURpLCBNRGk9TURyCiAgICAgICAgICAgIHZhciBTVDByID0gVDFyOwogICAgICAgICAgICB2YXIgU1QwaSA9IC1UMWk7CiAgICAgICAgICAgIHZhciBTVDFyID0gVDByOwogICAgICAgICAgICB2YXIgU1QxaSA9IC1UMGk7CiAgICAgICAgICAgIHZhciBTVDJyID0gLWludiAqIFQzaTsKICAgICAgICAgICAgdmFyIFNUMmkgPSAtaW52ICogVDNyOwogICAgICAgICAgICB2YXIgU1QzciA9IC1pbnYgKiBUMmk7CiAgICAgICAgICAgIHZhciBTVDNpID0gLWludiAqIFQycjsKCiAgICAgICAgICAgIHZhciBTRkFyID0gU1QwciArIFNUMnI7CiAgICAgICAgICAgIHZhciBTRkFpID0gU1QwaSArIFNUMmk7CgogICAgICAgICAgICB2YXIgU0ZCciA9IFNUMXIgKyBTVDNpOwogICAgICAgICAgICB2YXIgU0ZCaSA9IFNUMWkgLSBTVDNyOwoKICAgICAgICAgICAgdmFyIFNBID0gb3V0T2ZmICsgcXVhcnRlckxlbiAtIGk7CiAgICAgICAgICAgIHZhciBTQiA9IG91dE9mZiArIGhhbGZMZW4gLSBpOwoKICAgICAgICAgICAgb3V0W1NBXSA9IFNGQXI7CiAgICAgICAgICAgIG91dFtTQSArIDFdID0gU0ZBaTsKICAgICAgICAgICAgb3V0W1NCXSA9IFNGQnI7CiAgICAgICAgICAgIG91dFtTQiArIDFdID0gU0ZCaTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH07CgogICAgLy8gcmFkaXgtMiBpbXBsZW1lbnRhdGlvbgogICAgLy8KICAgIC8vIE5PVEU6IE9ubHkgY2FsbGVkIGZvciBsZW49NAogICAgRkZULnByb3RvdHlwZS5fc2luZ2xlUmVhbFRyYW5zZm9ybTIgPSBmdW5jdGlvbiBfc2luZ2xlUmVhbFRyYW5zZm9ybTIob3V0T2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwoKICAgICAgY29uc3QgZXZlblIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IG9kZFIgPSBkYXRhW29mZiArIHN0ZXBdOwoKICAgICAgY29uc3QgbGVmdFIgPSBldmVuUiArIG9kZFI7CiAgICAgIGNvbnN0IHJpZ2h0UiA9IGV2ZW5SIC0gb2RkUjsKCiAgICAgIG91dFtvdXRPZmZdID0gbGVmdFI7CiAgICAgIG91dFtvdXRPZmYgKyAxXSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyAyXSA9IHJpZ2h0UjsKICAgICAgb3V0W291dE9mZiArIDNdID0gMDsKICAgIH07CgogICAgLy8gcmFkaXgtNAogICAgLy8KICAgIC8vIE5PVEU6IE9ubHkgY2FsbGVkIGZvciBsZW49OAogICAgRkZULnByb3RvdHlwZS5fc2luZ2xlUmVhbFRyYW5zZm9ybTQgPSBmdW5jdGlvbiBfc2luZ2xlUmVhbFRyYW5zZm9ybTQob3V0T2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwogICAgICBjb25zdCBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIGNvbnN0IHN0ZXAyID0gc3RlcCAqIDI7CiAgICAgIGNvbnN0IHN0ZXAzID0gc3RlcCAqIDM7CgogICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgQXIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IEJyID0gZGF0YVtvZmYgKyBzdGVwXTsKICAgICAgY29uc3QgQ3IgPSBkYXRhW29mZiArIHN0ZXAyXTsKICAgICAgY29uc3QgRHIgPSBkYXRhW29mZiArIHN0ZXAzXTsKCiAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgVDByID0gQXIgKyBDcjsKICAgICAgY29uc3QgVDFyID0gQXIgLSBDcjsKICAgICAgY29uc3QgVDJyID0gQnIgKyBEcjsKICAgICAgY29uc3QgVDNyID0gaW52ICogKEJyIC0gRHIpOwoKICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgIGNvbnN0IEZBciA9IFQwciArIFQycjsKCiAgICAgIGNvbnN0IEZCciA9IFQxcjsKICAgICAgY29uc3QgRkJpID0gLVQzcjsKCiAgICAgIGNvbnN0IEZDciA9IFQwciAtIFQycjsKCiAgICAgIGNvbnN0IEZEciA9IFQxcjsKICAgICAgY29uc3QgRkRpID0gVDNyOwoKICAgICAgb3V0W291dE9mZl0gPSBGQXI7CiAgICAgIG91dFtvdXRPZmYgKyAxXSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyAyXSA9IEZCcjsKICAgICAgb3V0W291dE9mZiArIDNdID0gRkJpOwogICAgICBvdXRbb3V0T2ZmICsgNF0gPSBGQ3I7CiAgICAgIG91dFtvdXRPZmYgKyA1XSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyA2XSA9IEZEcjsKICAgICAgb3V0W291dE9mZiArIDddID0gRkRpOwogICAgfTsKCiAgICB2YXIgRkZUJDEgPSAvKkBfX1BVUkVfXyovZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMoZmZ0KTsKCiAgICBjb25zdCBCVUZGRVJFRF9CTE9DS19TSVpFID0gMjA0ODsKICAgIGZ1bmN0aW9uIGdlbkhhbm5XaW5kb3cobGVuZ3RoKSB7CiAgICAgICAgbGV0IHdpbiA9IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoKTsKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIHdpbltpXSA9IDAuNSAqICgxIC0gTWF0aC5jb3MoMiAqIE1hdGguUEkgKiBpIC8gbGVuZ3RoKSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB3aW47CiAgICB9CiAgICBjbGFzcyBQaGFzZVZvY29kZXJQcm9jZXNzb3IgZXh0ZW5kcyBPTEFQcm9jZXNzb3IgewogICAgICAgIGZmdFNpemU7CiAgICAgICAgdGltZUN1cnNvcjsKICAgICAgICBoYW5uV2luZG93OwogICAgICAgIGZmdDsKICAgICAgICBmcmVxQ29tcGxleEJ1ZmZlcjsKICAgICAgICBmcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQ7CiAgICAgICAgdGltZUNvbXBsZXhCdWZmZXI7CiAgICAgICAgbWFnbml0dWRlczsKICAgICAgICBwZWFrSW5kZXhlczsKICAgICAgICBuYlBlYWtzOwogICAgICAgIHN0YXRpYyBnZXQgcGFyYW1ldGVyRGVzY3JpcHRvcnMoKSB7CiAgICAgICAgICAgIHJldHVybiBbewogICAgICAgICAgICAgICAgICAgIG5hbWU6ICdwaXRjaEZhY3RvcicsCiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdFZhbHVlOiAxLjAKICAgICAgICAgICAgICAgIH1dOwogICAgICAgIH0KICAgICAgICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7CiAgICAgICAgICAgIG9wdGlvbnMucHJvY2Vzc29yT3B0aW9ucyA9IHsKICAgICAgICAgICAgICAgIGJsb2NrU2l6ZTogQlVGRkVSRURfQkxPQ0tfU0laRSwKICAgICAgICAgICAgfTsKICAgICAgICAgICAgc3VwZXIob3B0aW9ucyk7CiAgICAgICAgICAgIHRoaXMuZmZ0U2l6ZSA9IHRoaXMuYmxvY2tTaXplOwogICAgICAgICAgICB0aGlzLnRpbWVDdXJzb3IgPSAwOwogICAgICAgICAgICB0aGlzLmhhbm5XaW5kb3cgPSBnZW5IYW5uV2luZG93KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgLy8gcHJlcGFyZSBGRlQgYW5kIHByZS1hbGxvY2F0ZSBidWZmZXJzCiAgICAgICAgICAgIHRoaXMuZmZ0ID0gbmV3IEZGVCQxKHRoaXMuZmZ0U2l6ZSk7CiAgICAgICAgICAgIHRoaXMuZnJlcUNvbXBsZXhCdWZmZXIgPSB0aGlzLmZmdC5jcmVhdGVDb21wbGV4QXJyYXkoKTsKICAgICAgICAgICAgdGhpcy5mcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQgPSB0aGlzLmZmdC5jcmVhdGVDb21wbGV4QXJyYXkoKTsKICAgICAgICAgICAgdGhpcy50aW1lQ29tcGxleEJ1ZmZlciA9IHRoaXMuZmZ0LmNyZWF0ZUNvbXBsZXhBcnJheSgpOwogICAgICAgICAgICB0aGlzLm1hZ25pdHVkZXMgPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuZmZ0U2l6ZSAvIDIgKyAxKTsKICAgICAgICAgICAgdGhpcy5wZWFrSW5kZXhlcyA9IG5ldyBJbnQzMkFycmF5KHRoaXMubWFnbml0dWRlcy5sZW5ndGgpOwogICAgICAgICAgICB0aGlzLm5iUGVha3MgPSAwOwogICAgICAgIH0KICAgICAgICBwcm9jZXNzT0xBKGlucHV0cywgb3V0cHV0cywgcGFyYW1ldGVycykgewogICAgICAgICAgICAvLyBAdHMtaWdub3JlCiAgICAgICAgICAgIGNvbnN0IHBpdGNoRmFjdG9yID0gcGFyYW1ldGVycy5waXRjaEZhY3RvcltwYXJhbWV0ZXJzLnBpdGNoRmFjdG9yLmxlbmd0aCAtIDFdOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBpbnB1dHNbaV0ubGVuZ3RoOyBqKyspIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaW5wdXQgPSBpbnB1dHNbaV1bal07CiAgICAgICAgICAgICAgICAgICAgdmFyIG91dHB1dCA9IG91dHB1dHNbaV1bal07CiAgICAgICAgICAgICAgICAgICAgdGhpcy5hcHBseUhhbm5XaW5kb3coaW5wdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZmZ0LnJlYWxUcmFuc2Zvcm0odGhpcy5mcmVxQ29tcGxleEJ1ZmZlciwgaW5wdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuY29tcHV0ZU1hZ25pdHVkZXMoKTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbmRQZWFrcygpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuc2hpZnRQZWFrcyhwaXRjaEZhY3Rvcik7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuY29tcGxldGVTcGVjdHJ1bSh0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZCk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuaW52ZXJzZVRyYW5zZm9ybSh0aGlzLnRpbWVDb21wbGV4QnVmZmVyLCB0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZCk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuZnJvbUNvbXBsZXhBcnJheSh0aGlzLnRpbWVDb21wbGV4QnVmZmVyLCBvdXRwdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuYXBwbHlIYW5uV2luZG93KG91dHB1dCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy50aW1lQ3Vyc29yICs9IHRoaXMuaG9wU2l6ZTsKICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQogICAgICAgIGFwcGx5SGFubldpbmRvdyhpbnB1dCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuYmxvY2tTaXplOyBpKyspIHsKICAgICAgICAgICAgICAgIGlucHV0W2ldICo9IHRoaXMuaGFubldpbmRvd1tpXTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb21wdXRlTWFnbml0dWRlcygpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDAsIGogPSAwOyBpIDwgdGhpcy5tYWduaXR1ZGVzLmxlbmd0aDsgaSsrLCBqICs9IDIpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHJlYWwgPSB0aGlzLmZyZXFDb21wbGV4QnVmZmVyW2pdOwogICAgICAgICAgICAgICAgY29uc3QgaW1hZyA9IHRoaXMuZnJlcUNvbXBsZXhCdWZmZXJbaiArIDFdOwogICAgICAgICAgICAgICAgdGhpcy5tYWduaXR1ZGVzW2ldID0gcmVhbCAqKiAyICsgaW1hZyAqKiAyOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGZpbmRQZWFrcygpIHsKICAgICAgICAgICAgdGhpcy5uYlBlYWtzID0gMDsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDIsIGVuZCA9IHRoaXMubWFnbml0dWRlcy5sZW5ndGggLSAyOyBpIDwgZW5kOyBpKyspIHsKICAgICAgICAgICAgICAgIGNvbnN0IG1hZyA9IHRoaXMubWFnbml0dWRlc1tpXTsKICAgICAgICAgICAgICAgIGlmICh0aGlzLm1hZ25pdHVkZXNbaSAtIDFdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSAtIDJdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSArIDFdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSArIDJdID49IG1hZykgewogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdGhpcy5wZWFrSW5kZXhlc1t0aGlzLm5iUGVha3MrK10gPSBpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHNoaWZ0UGVha3MocGl0Y2hGYWN0b3IpIHsKICAgICAgICAgICAgdGhpcy5mcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQuZmlsbCgwKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iUGVha3M7IGkrKykgewogICAgICAgICAgICAgICAgY29uc3QgcGVha0luZGV4ID0gdGhpcy5wZWFrSW5kZXhlc1tpXTsKICAgICAgICAgICAgICAgIGNvbnN0IHBlYWtJbmRleFNoaWZ0ZWQgPSBNYXRoLnJvdW5kKHBlYWtJbmRleCAqIHBpdGNoRmFjdG9yKTsKICAgICAgICAgICAgICAgIGlmIChwZWFrSW5kZXhTaGlmdGVkID4gdGhpcy5tYWduaXR1ZGVzLmxlbmd0aCkgewogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgbGV0IHN0YXJ0SW5kZXggPSAoaSA+IDApID8gcGVha0luZGV4IC0gTWF0aC5mbG9vcigocGVha0luZGV4IC0gdGhpcy5wZWFrSW5kZXhlc1tpIC0gMV0pIC8gMikgOiAwOwogICAgICAgICAgICAgICAgbGV0IGVuZEluZGV4ID0gKGkgPCB0aGlzLm5iUGVha3MgLSAxKSA/IHBlYWtJbmRleCArIE1hdGguY2VpbCgodGhpcy5wZWFrSW5kZXhlc1tpICsgMV0gLSBwZWFrSW5kZXgpIC8gMikgOiB0aGlzLmZmdFNpemU7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gc3RhcnRJbmRleCAtIHBlYWtJbmRleDsgaiA8IGVuZEluZGV4IC0gcGVha0luZGV4OyBqKyspIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBiaW5JbmRleCA9IHBlYWtJbmRleCArIGo7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgYmluSW5kZXhTaGlmdGVkID0gcGVha0luZGV4U2hpZnRlZCArIGo7CiAgICAgICAgICAgICAgICAgICAgaWYgKGJpbkluZGV4U2hpZnRlZCA+PSB0aGlzLm1hZ25pdHVkZXMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBjb25zdCBvbWVnYURlbHRhID0gMiAqIE1hdGguUEkgKiAoYmluSW5kZXhTaGlmdGVkIC0gYmluSW5kZXgpIC8gdGhpcy5mZnRTaXplOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHBoYXNlU2hpZnRSZWFsID0gTWF0aC5jb3Mob21lZ2FEZWx0YSAqIHRoaXMudGltZUN1cnNvcik7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGhhc2VTaGlmdEltYWcgPSBNYXRoLnNpbihvbWVnYURlbHRhICogdGhpcy50aW1lQ3Vyc29yKTsKICAgICAgICAgICAgICAgICAgICBjb25zdCBpbmRleFJlYWwgPSBiaW5JbmRleCAqIDI7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5kZXhJbWFnID0gaW5kZXhSZWFsICsgMTsKICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZVJlYWwgPSB0aGlzLmZyZXFDb21wbGV4QnVmZmVyW2luZGV4UmVhbF07CiAgICAgICAgICAgICAgICAgICAgY29uc3QgdmFsdWVJbWFnID0gdGhpcy5mcmVxQ29tcGxleEJ1ZmZlcltpbmRleEltYWddOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlU2hpZnRlZFJlYWwgPSB2YWx1ZVJlYWwgKiBwaGFzZVNoaWZ0UmVhbCAtIHZhbHVlSW1hZyAqIHBoYXNlU2hpZnRJbWFnOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlU2hpZnRlZEltYWcgPSB2YWx1ZVJlYWwgKiBwaGFzZVNoaWZ0SW1hZyArIHZhbHVlSW1hZyAqIHBoYXNlU2hpZnRSZWFsOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4U2hpZnRlZFJlYWwgPSBiaW5JbmRleFNoaWZ0ZWQgKiAyOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4U2hpZnRlZEltYWcgPSBpbmRleFNoaWZ0ZWRSZWFsICsgMTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZFtpbmRleFNoaWZ0ZWRSZWFsXSArPSB2YWx1ZVNoaWZ0ZWRSZWFsOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZnJlcUNvbXBsZXhCdWZmZXJTaGlmdGVkW2luZGV4U2hpZnRlZEltYWddICs9IHZhbHVlU2hpZnRlZEltYWc7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICAvLyBAdHMtaWdub3JlCiAgICByZWdpc3RlclByb2Nlc3NvcigicGhhc2Utdm9jb2RlciIsIFBoYXNlVm9jb2RlclByb2Nlc3Nvcik7CiAgICBjb25zb2xlLmxvZygiUGhhc2VWb2NvZGVyUHJvY2Vzc29yIHJlZ2lzdGVyZWQiKTsKCiAgICBleHBvcnRzLlBoYXNlVm9jb2RlclByb2Nlc3NvciA9IFBoYXNlVm9jb2RlclByb2Nlc3NvcjsKCiAgICByZXR1cm4gZXhwb3J0czsKCn0pKHt9KTsK\"","import { IAudioContext } from \"standardized-audio-context\";\n\nexport class CacheManager {\n private static pendingRequests = new Map<string, Promise<AudioBuffer>>();\n\n private static async openCache(): Promise<Cache> {\n try {\n return await caches.open('audio-cache');\n } catch (error) {\n console.error('Failed to open cache:', error);\n throw error;\n }\n }\n\n private static async getAudioBufferFromCache(url: string, cache: Cache, context: IAudioContext): Promise<AudioBuffer | null> {\n try {\n const response = await cache.match(url);\n if (response) {\n const arrayBuffer = await response.arrayBuffer();\n return context.decodeAudioData(arrayBuffer);\n }\n return null;\n } catch (error) {\n console.error('Failed to get audio data from cache:', error);\n throw error;\n }\n }\n\n private static async fetchAndCacheAudioBuffer(url: string, cache: Cache, context: IAudioContext): Promise<AudioBuffer> {\n try {\n const fetchResponse = await fetch(url);\n const responseClone = fetchResponse.clone();\n cache.put(url, responseClone);\n const arrayBuffer = await fetchResponse.arrayBuffer();\n return context.decodeAudioData(arrayBuffer);\n } catch (error) {\n console.error('Failed to fetch and cache audio data:', error);\n throw error;\n }\n }\n\n public static async getAudioBuffer(url: string, context: IAudioContext): Promise<AudioBuffer> {\n // handle data: urls\n if (url.startsWith('data:')) {\n // Extract the base64-encoded audio data from the url.\n const base64Data = url.split(',')[1];\n const buffer = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));\n return context.decodeAudioData(buffer.buffer);\n }\n\n const cache = await this.openCache();\n\n // First, check if there's a pending request.\n let pendingRequest = this.pendingRequests.get(url);\n if (pendingRequest) {\n return pendingRequest;\n }\n\n // Try getting the buffer from cache.\n const bufferFromCache = await this.getAudioBufferFromCache(url, cache, context);\n if (bufferFromCache) {\n return bufferFromCache;\n }\n\n // If it's not in the cache, fetch and cache it.\n pendingRequest = this.fetchAndCacheAudioBuffer(url, cache, context);\n this.pendingRequests.set(url, pendingRequest);\n\n return pendingRequest;\n }\n}\n","import { BiquadFilterNode } from './context'\n\nexport abstract class FilterManager {\n protected filters: BiquadFilterNode[] = [];\n\n addFilter(filter: BiquadFilterNode) {\n this.filters.push(filter);\n }\n\n removeFilter(filter: BiquadFilterNode) {\n this.filters = this.filters.filter(f => f !== filter);\n }\n\n applyFilters(connection: any): any {\n this.filters.reduce((prevConnection, filter) => {\n prevConnection.connect(filter);\n return filter;\n }, connection);\n return this.filters.length > 0 ? this.filters[this.filters.length - 1] : connection;\n }\n}\n\n","import { BaseSound, LoopCount, Position } from './cacophony';\n\nimport { BiquadFilterNode } from './context';\nimport { Playback } from './playback';\nimport { Sound } from './sound';\n\n\nexport class Group implements BaseSound {\n sounds: Sound[] = [];\n private _position: Position = [0, 0, 0];\n loopCount: LoopCount = 0;\n private playIndex: number = 0;\n\n playRandom(): Playback {\n if (this.sounds.length === 0) {\n throw new Error('Cannot play a random sound from an empty group');\n }\n const randomIndex = Math.floor(Math.random() * this.sounds.length);\n const randomSound = this.sounds[randomIndex] as Sound;\n const playback = randomSound.preplay();\n playback.forEach(p => p.play());\n return playback[0];\n }\n\n playOrdered(shouldLoop: boolean = true): Playback {\n if (this.sounds.length === 0) {\n throw new Error('Cannot play an ordered sound from an empty group');\n }\n const sound = this.sounds[this.playIndex] as Sound;\n const playback = sound.preplay();\n playback.forEach(p => p.play());\n this.playIndex++;\n if (this.playIndex >= this.sounds.length) {\n if (shouldLoop) {\n this.playIndex = 0;\n } else {\n this.playIndex = this.sounds.length; // Set to length to indicate end of list\n }\n }\n return playback[0];\n }\n\n get duration() {\n return this.sounds.map(sound => sound.duration).reduce((a, b) => Math.max(a, b), 0);\n }\n\n seek(time: number): void {\n this.sounds.forEach(sound => sound.seek && sound.seek(time));\n }\n\n addSound(sound: Sound): void {\n this.sounds.push(sound);\n }\n\n preplay(): Playback[] {\n return (this.sounds as Sound[]).reduce<Playback[]>((playbacks, sound) => {\n sound.loop && sound.loop(this.loopCount);\n return playbacks.concat(sound.preplay());\n }, []);\n }\n\n play(): Playback[] {\n return this.preplay().map(playback => {\n playback.play();\n return playback;\n });\n }\n\n /**\n * Returns a boolean indicating whether the sound is currently playing.\n * @returns {boolean} True if the sound is playing, false otherwise.\n */\n isPlaying(): boolean {\n return this.sounds.some(sound => sound.isPlaying());\n }\n\n stop(): void {\n this.sounds.forEach(sound => sound.stop());\n }\n\n pause(): void {\n this.sounds.forEach(sound => sound.pause());\n }\n\n resume(): void {\n this.sounds.forEach(sound => sound.resume());\n }\n\n loop(loopCount?: LoopCount): LoopCount {\n if (loopCount === undefined) {\n return this.loopCount;\n }\n this.loopCount = loopCount;\n this.sounds.forEach(sound => sound.loop && sound.loop(loopCount));\n return this.loopCount;\n }\n\n addFilter(filter: BiquadFilterNode): void {\n this.sounds.forEach(sound => sound.addFilter(filter));\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n this.sounds.forEach(sound => sound.removeFilter(filter));\n }\n\n set position(position: [number, number, number]) {\n this._position = position;\n this.sounds.forEach(sound => sound.position = this._position);\n }\n\n get position(): [number, number, number] {\n return this._position;\n }\n\n get volume(): number {\n return this.sounds.map(sound => sound.volume).reduce((a, b) => a + b, 0) / this.sounds.length;\n }\n\n set volume(volume: number) {\n this.sounds.forEach(sound => sound.volume = volume);\n }\n\n get playbackRate(): number {\n if (this.sounds.length === 0) {\n return 1;\n }\n return this.sounds[0].playbackRate;\n }\n\n set playbackRate(rate: number) {\n this.sounds.forEach(sound => sound.playbackRate = rate);\n }\n\n\n}\n","/**\n * The Playback class encapsulates the functionality for playing audio in a web application.\n * It integrates with the standardized-audio-context library to provide a cross-browser way to handle audio.\n * This class allows for the manipulation of audio playback through various features such as:\n * - Playing and stopping audio\n * - Looping audio a specific number of times or infinitely\n * - Adjusting volume and playback rate\n * - Applying stereo or 3D (HRTF) panning\n * - Adding and removing filters to modify the audio output\n * - Handling audio looping with custom logic\n * - Fading audio in and out linearly or exponentially\n * - Seeking to specific points in the audio\n * - Checking if the audio is currently playing\n * - Cleaning up resources when the audio is no longer needed\n * \n * The class is designed to be flexible and can be used with different types of audio sources,\n * including buffer sources and media elements. It also provides detailed control over the audio's\n * spatial characteristics when using 3D audio.\n */\n\n\nimport { BaseSound, FadeType, LoopCount, PanType, Position } from \"./cacophony\";\nimport { AudioBuffer, AudioContext, BiquadFilterNode, GainNode, IPannerOptions, PannerNode, SourceNode, StereoPannerNode } from \"./context\";\nimport { FilterManager } from \"./filters\";\n\n\n\n\nexport class Playback extends FilterManager implements BaseSound {\n private context: AudioContext;\n private source?: SourceNode;\n private gainNode?: GainNode;\n private panner?: PannerNode | StereoPannerNode;\n loopCount: LoopCount = 0;\n currentLoop: number = 0;\n private buffer?: AudioBuffer;\n private playing: boolean = false;\n\n /**\n * Creates an instance of the Playback class.\n * @param {SourceNode} source - The audio source node.\n * @param {GainNode} gainNode - The gain node for controlling volume.\n * @param {AudioContext} context - The audio context.\n * @param {LoopCount} loopCount - The number of times the audio should loop. 'infinite' for endless looping.\n * @param {PanType} panType - The type of panning to use ('HRTF' for 3D audio or 'stereo' for stereo panning).\n * @throws {Error} Throws an error if an invalid pan type is provided.\n */\n constructor(source: SourceNode, gainNode: GainNode, context: AudioContext, loopCount: LoopCount = 0, public panType: PanType = 'HRTF') {\n super();\n this.loopCount = loopCount;\n this.panType = panType;\n this.source = source;\n if ('buffer' in source && source.buffer) {\n this.buffer = source.buffer;\n }\n if ('mediaElement' in source && source.mediaElement) {\n source.mediaElement.onended = this.handleLoop.bind(this);\n } else if ('onended' in source) {\n source.onended = this.handleLoop.bind(this);\n }\n this.gainNode = gainNode;\n this.context = context;\n if (this.panType === 'HRTF') {\n this.panner = context.createPanner();\n } else if (this.panType === 'stereo') {\n this.panner = context.createStereoPanner();\n } else {\n throw new Error('Invalid pan type');\n }\n source.connect(this.panner);\n this.panner.connect(this.gainNode);\n this.refreshFilters();\n }\n\n /**\n * Gets the stereo panning value.\n * @returns {number | null} The current stereo pan value, or null if stereo panning is not applicable.\n * @throws {Error} Throws an error if stereo panning is not available or if the sound has been cleaned up.\n */\n get stereoPan(): number | null {\n if (this.panType === 'stereo') {\n return (this.panner as StereoPannerNode).pan.value;\n }\n return null;\n }\n\n /**\n * Sets the stereo panning value.\n * @param {number} value - The stereo pan value to set, between -1 (left) and 1 (right).\n * @throws {Error} Throws an error if stereo panning is not available, if the sound has been cleaned up, or if the value is out of bounds.\n */\n set stereoPan(value: number) {\n if (this.panType !== 'stereo') {\n throw new Error('Stereo panning is not available when using HRTF.');\n }\n if (!this.panner) {\n throw new Error('Cannot set stereo pan of a sound that has been cleaned up');\n }\n (this.panner as StereoPannerNode).pan.setValueAtTime(clamp(value, -1, 1), this.context.currentTime);\n }\n\n /**\n * Gets the duration of the audio in seconds.\n * @returns {number} The duration of the audio.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n get duration() {\n if (!this.buffer) {\n throw new Error('Cannot get duration of a sound that has been cleaned up');\n }\n return this.buffer.duration;\n }\n\n /**\n * Gets the current playback rate of the audio.\n * @returns {number} The current playback rate.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n get playbackRate() {\n if (!this.source) {\n throw new Error('Cannot get playback rate of a sound that has been cleaned up');\n }\n if ('playbackRate' in this.source) {\n return this.source.playbackRate.value;\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n return this.source.mediaElement.playbackRate;\n }\n throw new Error('Unsupported source type');\n }\n\n /**\n * Sets the playback rate of the audio.\n * @param {number} rate - The playback rate to set.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n set playbackRate(rate: number) {\n if (!this.source) {\n throw new Error('Cannot set playback rate of a sound that has been cleaned up');\n }\n if ('playbackRate' in this.source) {\n this.source.playbackRate.value = rate;\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.playbackRate = rate;\n }\n }\n\n /**\n * Handles the loop event when the audio ends.\n * This method is bound to the 'onended' event of the audio source.\n * It manages looping logic and restarts playback if necessary.\n */\n handleLoop = () => {\n if (this.buffer) {\n this.source = this.context.createBufferSource();\n this.source.buffer = this.buffer;\n } else {\n this.seek(0);\n }\n if (this.loopCount === 'infinite' || this.currentLoop < this.loopCount) {\n this.currentLoop++;\n if (this.playing) {\n this.play();\n }\n } else {\n this.playing = false;\n }\n }\n\n /**\n * Starts playing the audio.\n * @returns {[this]} Returns the instance of the Playback class for chaining.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n play(): [this] {\n if (!this.source) {\n throw new Error('Cannot play a sound that has been cleaned up');\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.play();\n } else if ('start' in this.source && this.source.start) {\n this.source.start();\n }\n this.playing = true;\n return [this];\n }\n\n /**\n * Gets the 3D audio options if HRTF panning is used.\n * @returns {IPannerOptions} The current 3D audio options.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n get threeDOptions(): IPannerOptions {\n if (!this.panner) {\n throw new Error('Cannot get 3D options of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot get 3D options of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n return {\n coneInnerAngle: panner.coneInnerAngle,\n coneOuterAngle: panner.coneOuterAngle,\n coneOuterGain: panner.coneOuterGain,\n distanceModel: panner.distanceModel,\n maxDistance: panner.maxDistance,\n channelCount: this.panner.channelCount,\n channelCountMode: panner.channelCountMode,\n channelInterpretation: panner.channelInterpretation,\n panningModel: panner.panningModel,\n refDistance: panner.refDistance,\n rolloffFactor: panner.rolloffFactor,\n positionX: panner.positionX.value,\n positionY: panner.positionY.value,\n positionZ: panner.positionZ.value,\n orientationX: panner.orientationX.value,\n orientationY: panner.orientationY.value,\n orientationZ: panner.orientationZ.value\n }\n }\n\n /**\n * Sets the 3D audio options for HRTF panning.\n * @param {Partial<IPannerOptions>} options - The 3D audio options to set.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n set threeDOptions(options: Partial<IPannerOptions>) {\n if (!this.panner) {\n throw new Error('Cannot set 3D options of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot set 3D options of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n panner.coneInnerAngle = options.coneInnerAngle || panner.coneInnerAngle;\n panner.coneOuterAngle = options.coneOuterAngle || panner.coneOuterAngle;\n panner.coneOuterGain = options.coneOuterGain || panner.coneOuterGain;\n panner.distanceModel = options.distanceModel || panner.distanceModel;\n panner.maxDistance = options.maxDistance || panner.maxDistance;\n panner.channelCount = options.channelCount || panner.channelCount;\n panner.channelCountMode = options.channelCountMode || panner.channelCountMode;\n panner.channelInterpretation = options.channelInterpretation || panner.channelInterpretation;\n panner.panningModel = options.panningModel || panner.panningModel;\n panner.refDistance = options.refDistance || panner.refDistance;\n panner.rolloffFactor = options.rolloffFactor || panner.rolloffFactor;\n panner.positionX.value = options.positionX || panner.positionX.value;\n panner.positionY.value = options.positionY || panner.positionY.value;\n panner.positionZ.value = options.positionZ || panner.positionZ.value;\n panner.orientationX.value = options.orientationX || panner.orientationX.value;\n panner.orientationY.value = options.orientationY || panner.orientationY.value;\n panner.orientationZ.value = options.orientationZ || panner.orientationZ.value;\n }\n\n /**\n * Seeks to a specific time in the audio.\n * @param {number} time - The time in seconds to seek to.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n seek(time: number): void {\n if (!this.source || !this.gainNode || !this.panner) {\n throw new Error('Cannot seek a sound that has been cleaned up');\n }\n const playing = this.isPlaying();\n this.stop();\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.currentTime = time;\n if (playing) {\n this.source.mediaElement.play();\n }\n } else if (this.buffer) {\n // Create a new source to start from the desired time\n this.source = this.context.createBufferSource();\n this.source.buffer = this.buffer;\n this.refreshFilters();\n this.source.connect(this.panner).connect(this.gainNode);\n if (playing) {\n this.source.start(0, time);\n }\n } else {\n throw new Error('Unsupported source type for seeking');\n }\n }\n\n /**\n * Gets the current volume of the audio.\n * @returns {number} The current volume.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n get volume(): number {\n if (!this.gainNode) {\n throw new Error('Cannot get volume of a sound that has been cleaned up');\n }\n return this.gainNode.gain.value;\n }\n\n /**\n * Sets the volume of the audio.\n * @param {number} v - The volume to set.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n set volume(v: number) {\n if (!this.gainNode) {\n throw new Error('Cannot set volume of a sound that has been cleaned up');\n }\n this.gainNode.gain.value = v;\n }\n\n /**\n * Sets whether the audio source should loop.\n * @param {boolean} loop - Whether the audio should loop.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n set sourceLoop(loop: boolean) {\n if (!this.source) {\n throw new Error('Cannot set loop on a sound that has been cleaned up');\n }\n if ('loop' in this.source) {\n this.source.loop = loop;\n }\n if (\"mediaElement\" in this.source && this.source.mediaElement) {\n this.source.mediaElement.loop = loop;\n }\n }\n\n /**\n * Gradually increases the volume of the sound from silence to its current volume level over the specified duration.\n * @param {number} time - The duration in seconds over which the volume will increase.\n * @param {FadeType} fadeType - The type of fade curve to apply, either 'linear' or 'exponential'.\n * @returns {Promise<void>} A promise that resolves when the fade-in effect is complete.\n */\n /**\n * Fades in the audio from silence to its current volume level over a specified duration.\n * @param {number} time - The duration in seconds for the fade-in.\n * @param {FadeType} fadeType - The type of fade curve ('linear' or 'exponential').\n * @returns {Promise<void>} A promise that resolves when the fade-in is complete.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n fadeIn(time: number, fadeType: FadeType = 'linear'): Promise<void> {\n return new Promise(resolve => {\n if (!this.gainNode) {\n throw new Error('Cannot fade in a sound that has been cleaned up');\n }\n\n const initialVolume = this.gainNode.gain.value;\n const targetVolume = 1; // Assuming the target volume after fade-in is 1 (full volume)\n\n // Reset volume to 0 to start the fade-in process\n this.gainNode.gain.value = 0;\n\n switch (fadeType) {\n case 'exponential':\n // Start at a low value (0.01) because exponentialRampToValueAtTime cannot ramp from 0\n this.gainNode.gain.setValueAtTime(0.01, this.context.currentTime);\n this.gainNode.gain.exponentialRampToValueAtTime(targetVolume, this.context.currentTime + time);\n break;\n case 'linear':\n this.gainNode.gain.linearRampToValueAtTime(targetVolume, this.context.currentTime + time);\n break;\n }\n\n // Resolve the Promise after the fade-in time\n setTimeout(() => {\n // Ensure the final volume is set to the target volume\n if (!this.gainNode) {\n throw new Error('Cannot fade in a sound that has been cleaned up');\n }\n this.gainNode.gain.value = targetVolume;\n resolve();\n }, time * 1000);\n });\n }\n\n /**\n * Gradually decreases the volume of the sound from its current volume level to silence over the specified duration.\n * @param {number} time - The duration in seconds over which the volume will decrease.\n * @param {FadeType} fadeType - The type of fade curve to apply, either 'linear' or 'exponential'.\n * @returns {Promise<void>} A promise that resolves when the fade-out effect is complete.\n */\n /**\n * Fades out the audio to silence over a specified duration.\n * @param {number} time - The duration in seconds for the fade-out.\n * @param {FadeType} fadeType - The type of fade curve ('linear' or 'exponential').\n * @returns {Promise<void>} A promise that resolves when the fade-out is complete.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n fadeOut(time: number, fadeType: FadeType = 'linear'): Promise<void> {\n return new Promise(resolve => {\n // Storing the current gain value\n if (!this.gainNode) {\n throw new Error('Cannot fade out a sound that has been cleaned up');\n }\n const initialVolume = this.gainNode.gain.value;\n switch (fadeType) {\n case 'exponential':\n // Scheduling an exponential fade down\n this.gainNode.gain.exponentialRampToValueAtTime(0.01, this.context.currentTime + time);\n break;\n case 'linear':\n\n // Scheduling a linear ramp to 0 over the given duration\n this.gainNode.gain.linearRampToValueAtTime(0, this.context.currentTime + time);\n }\n // Resolving the Promise after the fade-out time\n setTimeout(() => resolve(), time * 1000);\n });\n }\n\n /**\n * Returns a boolean indicating whether the sound is currently playing.\n * @returns {boolean} True if the sound is playing, false otherwise.\n */\n /**\n * Checks if the audio is currently playing.\n * @returns {boolean} True if the audio is playing, false otherwise.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n isPlaying(): boolean {\n if (!this.source) {\n throw new Error('Cannot check if a sound is playing that has been cleaned up');\n }\n return this.playing;\n }\n\n /**\n * Cleans up resources used by the Playback instance.\n * This method should be called when the audio is no longer needed to free up resources.\n */\n cleanup(): void {\n // Ensure cleanup is idempotent\n if (this.source) {\n this.source.disconnect();\n this.source = undefined;\n }\n if (this.gainNode) {\n this.gainNode.disconnect();\n this.gainNode = undefined;\n }\n this.filters.forEach(filter => {\n if (filter) {\n filter.disconnect();\n }\n });\n this.filters = [];\n // Additional cleanup logic if needed\n }\n\n /**\n * Sets or gets the loop count for the audio.\n * @param {LoopCount} loopCount - The number of times the audio should loop. 'infinite' for endless looping.\n * @returns {LoopCount} The loop count if no parameter is provided.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n loop(loopCount?: LoopCount): LoopCount {\n if (!this.source) {\n throw new Error('Cannot loop a sound that has been cleaned up');\n }\n\n // Check if the source is an AudioBufferSourceNode\n if (this.source instanceof AudioBufferSourceNode) {\n if (loopCount === undefined) {\n return this.source.loop === true ? 'infinite' : 0;\n }\n this.source.loop = true;\n this.source.loopEnd = this.source.buffer?.duration || 0;\n this.source.loopStart = 0;\n return this.source.loop === true ? 'infinite' : 0;\n }\n // Check if the source is a MediaElementSourceNode\n if (\"mediaElement\" in this.source && this.source.mediaElement) {\n const mediaElement = this.source.mediaElement;\n if (loopCount === undefined) {\n return mediaElement.loop === true ? 'infinite' : 0;\n }\n mediaElement.loop = true;\n // Looping for HTMLMediaElement is controlled by the 'loop' attribute, no need for loopStart or loopEnd\n return mediaElement.loop === true ? 'infinite' : 0;\n }\n\n throw new Error('Unsupported source type');\n }\n\n /**\n * Stops the audio playback immediately.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n stop(): void {\n if (!this.source) {\n throw new Error('Cannot stop a sound that has been cleaned up');\n }\n if (!this.isPlaying()) {\n return;\n }\n if ('stop' in this.source) {\n this.source.stop();\n }\n if (\"mediaElement\" in this.source && this.source.mediaElement) {\n this.source.mediaElement.pause();\n this.source.mediaElement.currentTime = 0;\n }\n this.playing = false;\n }\n\n /**\n * Pauses the audio playback.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n pause(): void {\n if (!this.source) {\n throw new Error('Cannot pause a sound that has been cleaned up');\n }\n if ('suspend' in this.source.context) {\n this.source.context.suspend();\n }\n }\n\n /**\n * Resumes the audio playback if it was previously paused.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n resume(): void {\n if (!this.source) {\n throw new Error('Cannot resume a sound that has been cleaned up');\n }\n if ('resume' in this.source.context) {\n this.source.context.resume();\n }\n }\n\n /**\n * Adds a filter to the audio signal chain.\n * @param {BiquadFilterNode} filter - The filter to add.\n */\n addFilter(filter: BiquadFilterNode): void {\n super.addFilter(filter);\n this.refreshFilters();\n }\n\n /**\n * Removes a filter from the audio signal chain.\n * @param {BiquadFilterNode} filter - The filter to remove.\n */\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.refreshFilters();\n }\n\n /**\n * Sets the position of the audio source in 3D space (HRTF panning only).\n * @param {Position} position - The [x, y, z] coordinates of the audio source.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n\n set position(position: Position) {\n if (!this.panner) {\n throw new Error('Cannot move a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot move a sound that is not using HRTF');\n }\n const [x, y, z] = position;\n const panner = this.panner as PannerNode;\n panner.positionX.value = x;\n panner.positionY.value = y;\n panner.positionZ.value = z;\n }\n\n /**\n * Gets the position of the audio source in 3D space (HRTF panning only).\n * @returns {Position} The [x, y, z] coordinates of the audio source.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n\n get position(): Position {\n if (!this.panner) {\n throw new Error('Cannot get position of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot get position of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n return [panner.positionX.value, panner.positionY.value, panner.positionZ.value];\n }\n\n /**\n * Refreshes the audio filters by re-applying them to the audio signal chain.\n * This method is called internally whenever filters are added or removed.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n private refreshFilters(): void {\n if (!this.panner || !this.gainNode) {\n throw new Error('Cannot update filters on a sound that has been cleaned up');\n }\n let connection = this.panner;\n connection.disconnect();\n connection = this.applyFilters(connection);\n connection.connect(this.gainNode);\n }\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n","/**\n * The Sound class represents an audio asset within a web application, providing a high-level interface\n * for loading, manipulating, and playing audio. It supports both buffer-based and media element-based audio,\n * allowing for efficient playback and manipulation of sound resources.\n *\n * A Sound instance can manage multiple Playback instances, which represent individual playbacks of the sound.\n * This allows for the same sound to be played multiple times simultaneously or with different settings (e.g., volume,\n * playback rate, spatial positioning). The Sound class provides methods to control these playbacks collectively or individually.\n *\n * Key features include:\n * - Loading audio from a URL or using a pre-loaded buffer.\n * - Playing, pausing, resuming, and stopping audio playback.\n * - Looping audio a specific number of times or infinitely.\n * - Adjusting volume, playback rate, and spatial positioning (for 3D audio).\n * - Applying audio filters for effects like reverb, equalization, etc.\n * - Cloning the Sound instance for independent manipulation and playback.\n *\n * The relationship between Sound and Playback is central to the design of the audio system. A Sound object acts as a container\n * and manager for one or more Playback objects. Each Playback object represents a single instance of the sound being played,\n * and can be controlled individually. This architecture allows for complex audio behaviors, such as playing multiple overlapping\n * instances of a sound with different settings, without requiring the user to manually manage each playback instance.\n */\nimport { BaseSound, LoopCount, PanType, Position, SoundType } from \"./cacophony\";\nimport { BiquadFilterNode, GainNode, SourceNode, } from './context';\nimport { FilterManager } from \"./filters\";\nimport { Playback } from \"./playback\";\nimport { AudioContext, IAudioBuffer, IPannerOptions } from \"standardized-audio-context\";\n\n\nexport class Sound extends FilterManager implements BaseSound {\n buffer?: IAudioBuffer;\n context: AudioContext;\n playbacks: Playback[] = [];\n private globalGainNode: GainNode;\n private _position: Position = [0, 0, 0];\n private _stereoPan: number = 0;\n private _threeDOptions: IPannerOptions = {\n coneInnerAngle: 360,\n coneOuterAngle: 360,\n coneOuterGain: 0,\n distanceModel: 'inverse',\n maxDistance: 10000,\n channelCount: 2,\n channelCountMode: 'clamped-max',\n channelInterpretation: 'speakers',\n panningModel: 'HRTF',\n refDistance: 1,\n rolloffFactor: 1,\n positionX: 0,\n positionY: 0,\n positionZ: 0,\n orientationX: 0,\n orientationY: 0,\n orientationZ: 0\n };\n loopCount: LoopCount = 0;\n private _playbackRate: number = 1;\n private _volume: number = 1;\n\n constructor(public url: string, buffer: AudioBuffer | undefined, context: AudioContext, globalGainNode: GainNode, public type: SoundType = SoundType.Buffer, public panType: PanType = 'HRTF'\n ) {\n super();\n this.buffer = buffer;\n this.context = context;\n this.globalGainNode = globalGainNode;\n }\n\n /**\n * Creates a deep copy of the current Sound instance, including all its properties and filters.\n * The cloned sound can be played and manipulated independently of the original.\n * @returns {Sound} A new Sound instance that is a clone of the current sound.\n */\n\n clone(): Sound {\n const clone = new Sound(this.url, this.buffer, this.context, this.globalGainNode, this.type);\n clone.loopCount = this.loopCount;\n clone._playbackRate = this._playbackRate;\n clone._volume = this._volume;\n clone._position = this._position;\n clone._threeDOptions = this._threeDOptions;\n clone.filters = this.filters;\n clone.panType = this.panType;\n clone._stereoPan = this._stereoPan;\n return clone;\n }\n\n /**\n * Generates a Playback instance for the sound without starting playback.\n * This allows for pre-configuration of playback properties such as volume and position before the sound is actually played.\n * @returns {Playback[]} An array of Playback instances that are ready to be played.\n */\n\n preplay(): Playback[] {\n let source: SourceNode;\n if (this.buffer) {\n source = this.context.createBufferSource();\n source.buffer = this.buffer;\n } else {\n const audio = new Audio();\n audio.crossOrigin = 'anonymous';\n audio.src = this.url;\n audio.preload = \"auto\"\n // we have the audio, let's make a buffer source node out of it\n source = this.context.createMediaElementSource(audio);\n }\n const gainNode = this.context.createGain();\n gainNode.connect(this.globalGainNode);\n const playback = new Playback(source, gainNode, this.context, this.loopCount, this.panType);\n // this.finalizationRegistry.register(playback, playback);\n playback.volume = this.volume;\n playback.playbackRate = this.playbackRate;\n this.filters.forEach(filter => playback.addFilter(filter));\n if (this.panType === 'HRTF') {\n playback.threeDOptions = this.threeDOptions;\n playback.position = this.position;\n } else if (this.panType === 'stereo') {\n playback.stereoPan = this.stereoPan as number;\n }\n this.playbacks.push(playback);\n return [playback];\n }\n\n /**\n * Starts playback of the sound and returns a Playback instance representing this particular playback.\n * Multiple Playback instances can be created by calling this method multiple times,\n * allowing for the same sound to be played concurrently with different settings.\n * @returns {Playback[]} An array containing the Playback instances that have been started.\n */\n\n play(): Playback[] {\n const playback = this.preplay();\n playback.forEach(p => p.play());\n return playback;\n }\n\n /**\n * Stops all current playbacks of the sound immediately. This will halt the sound regardless of how many times it has been played.\n */\n\n stop() {\n this.playbacks.forEach(p => p.stop());\n }\n\n /**\n * Pauses all current playbacks of the sound.\n */\n\n pause(): void {\n this.playbacks.forEach(playback => playback.pause());\n }\n\n /**\n * Resumes all current playbacks of the sound that were previously paused.\n */\n\n resume(): void {\n this.playbacks.forEach(playback => playback.resume());\n }\n\n /**\n * Seeks to a specific time within the sound's playback.\n * @param { number } time - The time in seconds to seek to.\n * This method iterates through all active `Playback` instances and calls their `seek()` method with the specified time.\n */\n\n seek(time: number): void {\n this.playbacks.forEach(playback => playback.seek(time));\n }\n\n /**\n * Retrieves the duration of the sound in seconds.\n * If the sound is based on an AudioBuffer, it returns the duration of the buffer.\n * Otherwise, it returns 0, indicating that the duration is unknown or not applicable.\n * @returns { number } The duration of the sound in seconds.\n */\n\n get duration() {\n return this.buffer?.duration || 0;\n }\n\n /**\n * Retrieves the current 3D spatial position of the sound in the audio context.\n * The position is returned as an array of three values[x, y, z].\n * @returns { Position } The current position of the sound.\n */\n\n get position(): Position {\n return [this._threeDOptions.positionX, this._threeDOptions.positionY, this._threeDOptions.positionZ]\n }\n\n /**\n * Sets the 3D spatial position of the sound in the audio context.\n * The position is an array of three values[x, y, z].\n * This method updates the position of all active playbacks of the sound.\n * @param { Position } position - The new position of the sound.\n */\n\n set position(position: Position) {\n this._threeDOptions.positionX = position[0];\n this._threeDOptions.positionY = position[1];\n this._threeDOptions.positionZ = position[2];\n this.playbacks.forEach(p => p.position = position);\n }\n\n\n get threeDOptions(): IPannerOptions {\n return this._threeDOptions;\n }\n\n set threeDOptions(options: Partial<IPannerOptions>) {\n this._threeDOptions = { ...this._threeDOptions, ...options };\n this.playbacks.forEach(p => p.threeDOptions = this._threeDOptions);\n }\n\n get stereoPan(): number | null {\n return this._stereoPan;\n }\n\n set stereoPan(value: number) {\n this._stereoPan = value;\n this.playbacks.forEach(p => p.stereoPan = value);\n }\n\n /**\n * Sets or retrieves the loop behavior for the sound.\n * If loopCount is provided, the sound will loop the specified number of times.\n * If loopCount is 'infinite', the sound will loop indefinitely until stopped.\n * If no argument is provided, the method returns the current loop count setting.\n * @param { LoopCount } [loopCount] - The number of times to loop or 'infinite' for indefinite looping.\n * @returns { LoopCount } The current loop count setting if no argument is provided.\n */\n\n loop(loopCount?: LoopCount): LoopCount {\n if (loopCount === undefined) {\n return this.loopCount;\n }\n this.loopCount = loopCount;\n this.playbacks.forEach(p => p.loop(loopCount));\n return this.loopCount;\n }\n\n /**\n * Adds a BiquadFilterNode to the sound's filter chain.\n * Filters are applied in the order they are added.\n * @param { BiquadFilterNode } filter - The filter to add to the chain.\n */\n\n addFilter(filter: BiquadFilterNode): void {\n super.addFilter(filter);\n this.playbacks.forEach(p => p.addFilter(filter));\n }\n\n /**\n * Removes a BiquadFilterNode from the sound's filter chain.\n * If the filter is not part of the chain, the method has no effect.\n * @param { BiquadFilterNode } filter - The filter to remove from the chain.\n */\n\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.playbacks.forEach(p => p.removeFilter(filter));\n }\n\n get volume(): number {\n return this._volume;\n }\n\n set volume(volume: number) {\n this._volume = volume;\n this.playbacks.forEach(p => p.volume = volume);\n }\n\n /**\n * Returns a boolean indicating whether the sound is currently playing.\n * @returns {boolean} True if the sound is playing, false otherwise.\n */\n isPlaying(): boolean {\n return this.playbacks.some(p => p.isPlaying());\n }\n\n get playbackRate(): number {\n return this._playbackRate;\n }\n\n set playbackRate(rate: number) {\n this._playbackRate = rate;\n this.playbacks.forEach(p => p.playbackRate = rate);\n }\n\n}\n\n","import { AudioContext, IAudioBuffer, IAudioBufferSourceNode, IAudioListener, IBiquadFilterNode, IGainNode, IMediaElementAudioSourceNode, IMediaStreamAudioSourceNode, IPannerNode, IPannerOptions } from 'standardized-audio-context';\n\n\nconst appendBuffer = (buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBuffer => {\n var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);\n tmp.set(new Uint8Array(buffer1), 0);\n tmp.set(new Uint8Array(buffer2), buffer1.byteLength);\n return tmp.buffer;\n}\n\n\nexport function createStream(url: string, context: AudioContext) {\n const audioStack: IAudioBuffer[] = [];\n let nextTime = 0;\n\n fetch(url).then(function (response) {\n if (!response.ok) {\n throw new Error('HTTP error, status = ' + response.status);\n }\n if (!response.body) {\n throw new Error('Missing body');\n }\n\n var reader = response.body.getReader();\n let header = new ArrayBuffer(0);//first 44bytes\n\n function read() {\n return reader.read().then(({ value, done }) => {\n let audioBuffer = null;\n if (!value) {\n return;\n }\n\n if (!header.byteLength) {\n //copy first 44 bytes (wav header)\n header = value.buffer.slice(0, 44);\n audioBuffer = value.buffer;\n } else {\n audioBuffer = appendBuffer(header, value.buffer);\n }\n\n context.decodeAudioData(audioBuffer, function (buffer) {\n\n audioStack.push(buffer);\n if (audioStack.length) {\n scheduleBuffers();\n }\n }, function (err) {\n console.log(\"err(decodeAudioData): \" + err);\n });\n if (done) {\n console.log('done');\n return;\n }\n //read next buffer\n read();\n });\n }\n read();\n })\n\n function scheduleBuffers() {\n while (audioStack.length) {\n let buffer = audioStack.shift();\n const source = context.createBufferSource();\n if (!buffer) {\n return;\n }\n source.buffer = buffer;\n source.connect(context.destination);\n if (nextTime == 0)\n nextTime = context.currentTime + 0.02; /// add 50ms latency to work well across systems - tune this if you like\n source.start(nextTime);\n nextTime += source.buffer.duration; // Make the next buffer wait the length of the last buffer before being played\n };\n }\n}\n\n","import { AudioContext, AudioWorkletNode, IAudioListener, IMediaStreamAudioSourceNode, IPannerNode, IPannerOptions } from 'standardized-audio-context';\nimport phaseVocoderProcessorWorkletUrl from './bundles/phase-vocoder-bundle.js?url';\nimport { CacheManager } from './cache';\nimport { BiquadFilterNode, GainNode } from './context';\nimport { FilterManager } from './filters';\nimport { Group } from './group';\nimport { Playback } from './playback';\nimport { Sound } from './sound';\nimport { createStream } from './stream';\n\n\nexport enum SoundType {\n HTML = 'HTML',\n Streaming = 'Streaming',\n Buffer = 'Buffer'\n}\n\n\n\ntype PannerNode = IPannerNode<AudioContext>;\n\n\n\ntype MediaStreamAudioSourceNode = IMediaStreamAudioSourceNode<AudioContext>;\n\n\n/**\n * Represents a 3D position in space.\n * @typedef {Array<number>} Position - An array of three numbers representing the x, y, and z coordinates.\n */\nexport type Position = [x: number, y: number, z: number];\n\n/**\n * Represents the orientation of an object in 3D space.\n * @typedef {Object} Orientation - An object containing two positions: forward and up.\n * @property {Position} forward - The forward direction of the object.\n * @property {Position} up - The up direction of the object.\n */\nexport type Orientation = {\n forward: Position;\n up: Position;\n}\n\n/**\n * Represents the number of times a sound should loop.\n * @typedef {number | 'infinite'} LoopCount - The number of loops, or 'infinite' for endless looping.\n */\nexport type LoopCount = number | 'infinite';\n\n/**\n * Represents the type of fade effect to apply.\n * @typedef {'linear' | 'exponential'} FadeType - The fade type, either 'linear' or 'exponential'.\n */\nexport type FadeType = 'linear' | 'exponential';\n\n/**\n * Represents the type of panning effect to apply.\n * @typedef {'HRTF' | 'stereo'} PanType - The pan type, either 'HRTF' for 3D audio or 'stereo' for traditional stereo panning.\n */\nexport type PanType = 'HRTF' | 'stereo';\n\n/**\n * The base interface for any sound-producing entity, including individual sounds, groups, and playbacks.\n * @interface BaseSound\n */\nexport interface BaseSound {\n isPlaying(): boolean;\n play(): BaseSound[];\n seek?(time: number): void;\n stop(): void;\n pause(): void;\n resume(): void;\n addFilter(filter: BiquadFilterNode): void;\n removeFilter(filter: BiquadFilterNode): void;\n volume: number;\n playbackRate: number;\n loop?(loopCount?: LoopCount): LoopCount;\n duration: number;\n}\n\n\n\n\n\nexport class Cacophony {\n context: AudioContext;\n globalGainNode: GainNode;\n listener: IAudioListener;\n private prevVolume: number = 1;\n private finalizationRegistry: FinalizationRegistry<Playback>;\n\n constructor(context?: AudioContext) {\n this.context = context || new AudioContext();\n this.listener = this.context.listener;\n this.globalGainNode = this.context.createGain();\n this.globalGainNode.connect(this.context.destination);\n\n this.finalizationRegistry = new FinalizationRegistry((heldValue) => {\n // Cleanup callback for Playbacks\n heldValue.cleanup();\n });\n }\n\n async loadWorklets() {\n if (this.context.audioWorklet) {\n await this.createWorkletNode('phase-vocoder', phaseVocoderProcessorWorkletUrl);\n }\n else {\n console.warn('AudioWorklet not supported');\n }\n }\n\n\n async createWorkletNode(\n name: string,\n url: string\n ) {\n // ensure audioWorklet has been loaded\n if (!this.context.audioWorklet) {\n throw new Error('AudioWorklet not supported');\n }\n try {\n return new AudioWorkletNode!(this.context, name);\n } catch (err) {\n console.error(err)\n console.log(\"Loading worklet from url\", url);\n try {\n await this.context.audioWorklet.addModule(url);\n } catch (err) {\n console.error(err);\n throw new Error(`Could not load worklet from url ${url}`);\n }\n\n return new AudioWorkletNode!(this.context, name);\n }\n }\n\n createOscillator = ({ frequency, type, periodicWave }: OscillatorOptions) => {\n if (frequency === undefined) {\n frequency = 440;\n }\n const oscillator = this.context.createOscillator();\n oscillator.type = type || 'sine';\n if (periodicWave) {\n oscillator.setPeriodicWave(periodicWave);\n }\n oscillator.frequency.setValueAtTime(frequency, this.context.currentTime);\n oscillator.connect(this.globalGainNode);\n return oscillator\n }\n\n\n async createSound(buffer: AudioBuffer, soundType?: SoundType, panType?: PanType): Promise<Sound>\n\n async createSound(url: string, soundType?: SoundType, panType?: PanType): Promise<Sound>\n\n async createSound(bufferOrUrl: AudioBuffer | string, soundType: SoundType = SoundType.Buffer, panType: PanType = 'HRTF'): Promise<Sound> {\n if (bufferOrUrl instanceof AudioBuffer) {\n return Promise.resolve(new Sound(\"\", bufferOrUrl, this.context, this.globalGainNode, SoundType.Buffer, panType));\n }\n const url = bufferOrUrl;\n if (soundType === SoundType.HTML) {\n const audio = new Audio();\n audio.src = url;\n audio.crossOrigin = 'anonymous';\n return new Sound(url, undefined, this.context, this.globalGainNode, SoundType.HTML, panType);\n }\n return CacheManager.getAudioBuffer(url, this.context).then(buffer => new Sound(url, buffer, this.context, this.globalGainNode, soundType, panType));\n }\n\n async createGroup(sounds: Sound[]): Promise<Group> {\n const group = new Group();\n sounds.forEach(sound => group.addSound(sound));\n return group;\n }\n\n async createGroupFromUrls(urls: string[], soundType: SoundType = SoundType.Buffer, panType: PanType = 'HRTF'): Promise<Group> {\n const group = new Group();\n const sounds = await Promise.all(urls.map(url => this.createSound(url, soundType, panType)));\n sounds.forEach(sound => group.addSound(sound));\n return group;\n }\n\n async createStream(url: string): Promise<Sound> {\n const stream = await createStream(url, this.context);\n const sound = new Sound(url, undefined, this.context, this.globalGainNode, SoundType.Streaming);\n return sound;\n }\n\n createBiquadFilter = ({ type, frequency, gain, Q }: BiquadFilterOptions): BiquadFilterNode => {\n if (frequency === undefined) {\n frequency = 350;\n }\n const filter = this.context.createBiquadFilter();\n filter.type = type || 'lowpass';\n filter.frequency.value = frequency;\n filter.gain.value = gain || 0;\n filter.Q.value = Q || 1;\n return filter;\n }\n\n /**\n * Creates a PannerNode with the specified options.\n * @param {IPannerOptions} options - An object containing the options to use when creating the PannerNode.\n * @returns {PannerNode} A new PannerNode instance with the specified options.\n * @example\n * const panner = audio.createPanner({\n * positionX: 0,\n * positionY: 0,\n * positionZ: 0,\n * orientationX: 0,\n * orientationY: 0,\n * orientationZ: 0,\n * });\n */\n\n createPanner({ coneInnerAngle, coneOuterAngle, coneOuterGain, distanceModel, maxDistance, channelCount, channelCountMode, channelInterpretation, panningModel, refDistance, rolloffFactor, positionX, positionY, positionZ, orientationX, orientationY, orientationZ }: Partial<IPannerOptions>): PannerNode {\n const panner = this.context.createPanner();\n panner.coneInnerAngle = coneInnerAngle || 360;\n panner.coneOuterAngle = coneOuterAngle || 360;\n panner.coneOuterGain = coneOuterGain || 0;\n panner.distanceModel = distanceModel || 'inverse';\n panner.maxDistance = maxDistance || 10000;\n panner.channelCount = channelCount || 2;\n panner.channelCountMode = channelCountMode || 'clamped-max';\n panner.channelInterpretation = channelInterpretation || 'speakers';\n panner.panningModel = panningModel || 'HRTF';\n panner.refDistance = refDistance || 1;\n panner.rolloffFactor = rolloffFactor || 1;\n panner.positionX.value = positionX || 0;\n panner.positionY.value = positionY || 0;\n panner.positionZ.value = positionZ || 0;\n panner.orientationX.value = orientationX || 0;\n panner.orientationY.value = orientationY || 0;\n panner.orientationZ.value = orientationZ || 0;\n return panner;\n }\n\n /**\n * Suspends the audio context.\n */\n pause(): void {\n if ('suspend' in this.context) {\n this.context.suspend();\n }\n }\n\n /**\n * Resumes the audio context.\n * This method is required to resume the audio context on mobile devices.\n * On desktop, the audio context will automatically resume when a sound is played.\n */\n resume() {\n if ('resume' in this.context) {\n this.context.resume();\n }\n }\n\n setGlobalVolume(volume: number) {\n this.globalGainNode.gain.value = volume;\n }\n\n get volume(): number {\n return this.globalGainNode.gain.value;\n }\n\n set volume(volume: number) {\n if (this.muted) {\n this.prevVolume = volume;\n return;\n }\n this.setGlobalVolume(volume);\n }\n\n mute() {\n if (!this.muted) {\n this.prevVolume = this.globalGainNode.gain.value;\n this.setGlobalVolume(0);\n }\n }\n\n unmute() {\n if (this.muted) {\n this.setGlobalVolume(this.prevVolume);\n }\n }\n\n get muted(): boolean {\n return this.globalGainNode.gain.value === 0;\n }\n\n set muted(muted: boolean) {\n if (muted !== this.muted) {\n if (muted) {\n this.mute();\n } else {\n this.unmute();\n }\n }\n }\n\n getMicrophoneStream(): Promise<MicrophoneStream> {\n return new Promise((resolve, reject) => {\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(stream => {\n const microphoneStream = new MicrophoneStream(this.context);\n microphoneStream.play();\n resolve(microphoneStream);\n })\n .catch(err => {\n reject(err);\n });\n });\n }\n\n get listenerOrientation(): Orientation {\n return {\n forward: [this.listener.forwardX.value, this.listener.forwardY.value, this.listener.forwardZ.value],\n up: [this.listener.upX.value, this.listener.upY.value, this.listener.upZ.value]\n };\n }\n\n set listenerOrientation(orientation: Orientation) {\n const { forward, up } = orientation;\n const [forwardX, forwardY, forwardZ] = forward;\n const [upX, upY, upZ] = up;\n this.listener.forwardX.value = forwardX;\n this.listener.forwardY.value = forwardY;\n this.listener.forwardZ.value = forwardZ;\n this.listener.upX.value = upX;\n this.listener.upY.value = upY;\n this.listener.upZ.value = upZ;\n }\n\n get listenerUpOrientation(): Position {\n return [this.listener.upX.value, this.listener.upY.value, this.listener.upZ.value];\n }\n\n set listenerUpOrientation(up: Position) {\n const [x, y, z] = up;\n this.listener.upX.value = x;\n this.listener.upY.value = y;\n this.listener.upZ.value = z;\n }\n\n get listenerForwardOrientation(): Position {\n return [this.listener.forwardX.value, this.listener.forwardY.value, this.listener.forwardZ.value];\n }\n\n set listenerForwardOrientation(forward: Position) {\n const [x, y, z] = forward;\n this.listener.forwardX.value = x;\n this.listener.forwardY.value = y;\n this.listener.forwardZ.value = z;\n }\n\n get listenerPosition(): Position {\n return [this.listener.positionX.value, this.listener.positionY.value, this.listener.positionZ.value];\n }\n\n set listenerPosition(position: Position) {\n const [x, y, z] = position;\n const currentTime = this.context.currentTime;\n this.listener.positionX.setValueAtTime(x, currentTime);\n this.listener.positionY.setValueAtTime(y, currentTime);\n this.listener.positionZ.setValueAtTime(z, currentTime);\n }\n\n}\n\n\nexport class MicrophonePlayback extends FilterManager {\n private context: AudioContext;\n private source?: MediaStreamAudioSourceNode;\n private gainNode?: GainNode;\n private panner?: PannerNode;\n\n\n constructor(source: MediaStreamAudioSourceNode, gainNode: GainNode, context: AudioContext, loopCount: LoopCount = 0) {\n super();\n this.source = source;\n this.gainNode = gainNode;\n this.context = context;\n this.panner = context.createPanner();\n source.connect(this.panner).connect(this.gainNode);\n this.refreshFilters();\n }\n\n get duration() {\n return 0;\n }\n\n play() {\n if (!this.source) {\n throw new Error('Cannot play a sound that has been cleaned up');\n }\n return [this];\n }\n\n isPlaying() {\n return Boolean(this.source);\n }\n\n get volume(): number {\n if (!this.gainNode) {\n throw new Error('Cannot get volume of a sound that has been cleaned up');\n }\n return this.gainNode.gain.value;\n }\n\n set volume(v: number) {\n if (!this.gainNode) {\n throw new Error('Cannot set volume of a sound that has been cleaned up');\n }\n this.gainNode.gain.value = v;\n }\n\n stop(): void {\n if (!this.source) {\n throw new Error('Cannot stop a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.stop());\n }\n\n pause(): void {\n if (!this.source) {\n throw new Error('Cannot pause a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.enabled = false);\n }\n\n resume(): void {\n if (!this.source) {\n throw new Error('Cannot resume a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.enabled = true);\n }\n\n addFilter(filter: BiquadFilterNode): void {\n super.addFilter(filter);\n this.refreshFilters();\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.refreshFilters();\n }\n\n set position(position: Position) {\n if (!this.panner) {\n throw new Error('Cannot move a sound that has been cleaned up');\n }\n const [x, y, z] = position;\n this.panner.positionX.value = x;\n this.panner.positionY.value = y;\n this.panner.positionZ.value = z;\n }\n\n get position(): Position {\n if (!this.panner) {\n throw new Error('Cannot get position of a sound that has been cleaned up');\n }\n return [this.panner.positionX.value, this.panner.positionY.value, this.panner.positionZ.value];\n }\n\n private refreshFilters(): void {\n if (!this.source || !this.gainNode) {\n throw new Error('Cannot update filters on a sound that has been cleaned up');\n }\n let connection = this.source;\n this.source.disconnect();\n connection = this.applyFilters(connection);\n connection.connect(this.gainNode);\n }\n\n get playbackRate(): number {\n // Playback rate is not applicable for live microphone stream\n return 1;\n }\n\n set playbackRate(rate: number) {\n }\n\n\n\n}\n\nexport class MicrophoneStream extends FilterManager implements BaseSound {\n context: AudioContext;\n private _position: Position = [0, 0, 0];\n loopCount: LoopCount = 0;\n private prevVolume: number = 1;\n private microphoneGainNode: GainNode;\n private streamPlayback?: MicrophonePlayback;\n private stream: MediaStream | undefined;\n private streamSource?: MediaStreamAudioSourceNode;\n\n constructor(context: AudioContext) {\n super();\n this.context = context;\n this.microphoneGainNode = this.context.createGain();\n }\n\n play(): MicrophonePlayback[] {\n if (!this.stream) {\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(stream => {\n this.stream = stream;\n this.streamSource = this.context.createMediaStreamSource(this.stream);\n this.streamPlayback = new MicrophonePlayback(this.streamSource, this.microphoneGainNode, this.context);\n this.streamPlayback.play();\n })\n .catch(err => {\n console.error('Error initializing microphone stream:', err);\n });\n }\n return this.streamPlayback ? [this.streamPlayback] : [];\n }\n\n get duration() {\n return 0;\n }\n\n\n seek(time: number) {\n // Seeking is not applicable for live microphone stream\n }\n\n /**\n * Returns a boolean indicating whether the sound is currently playing.\n * @returns {boolean} True if the sound is playing, false otherwise.\n */\n isPlaying(): boolean {\n return Boolean(this.streamPlayback);\n }\n\n stop() {\n if (this.streamPlayback) {\n this.streamPlayback.stop();\n this.streamPlayback = undefined;\n }\n }\n\n pause() {\n if (this.streamPlayback) {\n this.streamPlayback.pause();\n }\n }\n\n resume() {\n if (this.streamPlayback) {\n this.streamPlayback.resume();\n }\n }\n\n addFilter(filter: BiquadFilterNode): void {\n if (this.streamPlayback) {\n this.streamPlayback.addFilter(filter);\n }\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n if (this.streamPlayback) {\n this.streamPlayback.removeFilter(filter);\n }\n }\n\n get volume(): number {\n return this.streamPlayback ? this.streamPlayback.volume : 0;\n }\n\n set volume(volume: number) {\n if (this.streamPlayback) {\n this.streamPlayback.volume = volume;\n }\n }\n\n get position(): Position {\n // Position is not applicable for live microphone stream\n return [0, 0, 0];\n }\n\n set position(position: Position) {\n // Position is not applicable for live microphone stream\n }\n\n loop(loopCount?: LoopCount): LoopCount {\n // Looping is not applicable for live microphone stream\n return 0;\n }\n\n\n get playbackRate(): number {\n // Playback rate is not applicable for live microphone stream\n return 1;\n }\n\n set playbackRate(rate: number) {\n }\n\n}\n"],"names":["phaseVocoderProcessorWorkletUrl","CacheManager","error","url","cache","context","response","arrayBuffer","fetchResponse","responseClone","base64Data","buffer","c","pendingRequest","bufferFromCache","FilterManager","filter","f","connection","prevConnection","Group","randomIndex","playback","p","shouldLoop","sound","a","b","time","playbacks","loopCount","position","volume","rate","Playback","source","gainNode","panType","value","clamp","panner","options","playing","v","loop","fadeType","resolve","targetVolume","mediaElement","x","y","z","min","max","Sound","globalGainNode","type","SoundType","clone","audio","appendBuffer","buffer1","buffer2","tmp","createStream","audioStack","nextTime","reader","header","read","done","audioBuffer","scheduleBuffers","err","Cacophony","AudioContext","heldValue","name","AudioWorkletNode","frequency","periodicWave","oscillator","bufferOrUrl","soundType","sounds","group","urls","gain","Q","coneInnerAngle","coneOuterAngle","coneOuterGain","distanceModel","maxDistance","channelCount","channelCountMode","channelInterpretation","panningModel","refDistance","rolloffFactor","positionX","positionY","positionZ","orientationX","orientationY","orientationZ","muted","reject","stream","microphoneStream","MicrophoneStream","orientation","forward","up","forwardX","forwardY","forwardZ","upX","upY","upZ","currentTime","MicrophonePlayback","track"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cacophony.cjs.js","sources":["../src/bundles/phase-vocoder-bundle.js?url","../src/cache.ts","../src/filters.ts","../src/group.ts","../src/playback.ts","../src/sound.ts","../src/stream.ts","../src/cacophony.ts"],"sourcesContent":["export default \"data:application/javascript;base64,KGZ1bmN0aW9uIChleHBvcnRzKSB7CiAgICAndXNlIHN0cmljdCc7CgogICAgY29uc3QgV0VCQVVESU9fQkxPQ0tfU0laRSA9IDEyODsKICAgIGNvbnN0IERFRkFVTFRfQkxPQ0tfU0laRSA9IDEwMjQ7IC8vIERlZmF1bHQgYmxvY2sgc2l6ZSBpZiBub3QgcHJvdmlkZWQgaW4gb3B0aW9ucwogICAgLyoqIE92ZXJsYXAtQWRkIE5vZGUgKi8KICAgIGNsYXNzIE9MQVByb2Nlc3NvciBleHRlbmRzIEF1ZGlvV29ya2xldFByb2Nlc3NvciB7CiAgICAgICAgbmJJbnB1dHM7CiAgICAgICAgbmJPdXRwdXRzOwogICAgICAgIGJsb2NrU2l6ZTsKICAgICAgICBob3BTaXplOwogICAgICAgIG5iT3ZlcmxhcHM7CiAgICAgICAgaW5wdXRCdWZmZXJzID0gW107CiAgICAgICAgaW5wdXRCdWZmZXJzSGVhZCA9IFtdOwogICAgICAgIGlucHV0QnVmZmVyc1RvU2VuZCA9IFtdOwogICAgICAgIG91dHB1dEJ1ZmZlcnMgPSBbXTsKICAgICAgICBvdXRwdXRCdWZmZXJzVG9SZXRyaWV2ZSA9IFtdOwogICAgICAgIGNvbnN0cnVjdG9yKG9wdGlvbnMpIHsKICAgICAgICAgICAgc3VwZXIob3B0aW9ucyk7CiAgICAgICAgICAgIHRoaXMubmJJbnB1dHMgPSBvcHRpb25zLm51bWJlck9mSW5wdXRzIHx8IDE7CiAgICAgICAgICAgIHRoaXMubmJPdXRwdXRzID0gb3B0aW9ucy5udW1iZXJPZk91dHB1dHMgfHwgMTsKICAgICAgICAgICAgdGhpcy5ibG9ja1NpemUgPSBvcHRpb25zLnByb2Nlc3Nvck9wdGlvbnMuYmxvY2tTaXplIHx8IERFRkFVTFRfQkxPQ0tfU0laRTsKICAgICAgICAgICAgdGhpcy5ob3BTaXplID0gV0VCQVVESU9fQkxPQ0tfU0laRTsKICAgICAgICAgICAgdGhpcy5uYk92ZXJsYXBzID0gTWF0aC5mbG9vcih0aGlzLmJsb2NrU2l6ZSAvIHRoaXMuaG9wU2l6ZSk7CiAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUJ1ZmZlcnMoKTsKICAgICAgICB9CiAgICAgICAgaW5pdGlhbGl6ZUJ1ZmZlcnMoKSB7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzID0gbmV3IEFycmF5KHRoaXMubmJJbnB1dHMpOwogICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc0hlYWQgPSBuZXcgQXJyYXkodGhpcy5uYklucHV0cyk7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kID0gbmV3IEFycmF5KHRoaXMubmJJbnB1dHMpOwogICAgICAgICAgICB0aGlzLm91dHB1dEJ1ZmZlcnMgPSBuZXcgQXJyYXkodGhpcy5uYk91dHB1dHMpOwogICAgICAgICAgICB0aGlzLm91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlID0gbmV3IEFycmF5KHRoaXMubmJPdXRwdXRzKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iSW5wdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIHRoaXMuYWxsb2NhdGVJbnB1dENoYW5uZWxzKGksIDEpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5uYk91dHB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5hbGxvY2F0ZU91dHB1dENoYW5uZWxzKGksIDEpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGFsbG9jYXRlSW5wdXRDaGFubmVscyhpbnB1dEluZGV4LCBuYkNoYW5uZWxzKSB7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2lucHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc0hlYWRbaW5wdXRJbmRleF0gPSBuZXcgQXJyYXkobmJDaGFubmVscyk7CiAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kW2lucHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5iQ2hhbm5lbHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNbaW5wdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplICsgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICB0aGlzLmlucHV0QnVmZmVyc1tpbnB1dEluZGV4XVtpXS5maWxsKDApOwogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNIZWFkW2lucHV0SW5kZXhdW2ldID0gdGhpcy5pbnB1dEJ1ZmZlcnNbaW5wdXRJbmRleF1baV0uc3ViYXJyYXkoMCwgdGhpcy5ibG9ja1NpemUpOwogICAgICAgICAgICAgICAgdGhpcy5pbnB1dEJ1ZmZlcnNUb1NlbmRbaW5wdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBhbGxvY2F0ZU91dHB1dENoYW5uZWxzKG91dHB1dEluZGV4LCBuYkNoYW5uZWxzKSB7CiAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1tvdXRwdXRJbmRleF0gPSBuZXcgQXJyYXkobmJDaGFubmVscyk7CiAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1RvUmV0cmlldmVbb3V0cHV0SW5kZXhdID0gbmV3IEFycmF5KG5iQ2hhbm5lbHMpOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5iQ2hhbm5lbHM7IGkrKykgewogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW291dHB1dEluZGV4XVtpXSA9IG5ldyBGbG9hdDMyQXJyYXkodGhpcy5ibG9ja1NpemUpOwogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW291dHB1dEluZGV4XVtpXS5maWxsKDApOwogICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzVG9SZXRyaWV2ZVtvdXRwdXRJbmRleF1baV0gPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZWFsbG9jYXRlQ2hhbm5lbHNJZk5lZWRlZChpbnB1dHMsIG91dHB1dHMpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iSW5wdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGxldCBuYkNoYW5uZWxzID0gaW5wdXRzW2ldLmxlbmd0aDsKICAgICAgICAgICAgICAgIGlmIChuYkNoYW5uZWxzICE9PSB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmFsbG9jYXRlSW5wdXRDaGFubmVscyhpLCBuYkNoYW5uZWxzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGxldCBuYkNoYW5uZWxzID0gb3V0cHV0c1tpXS5sZW5ndGg7CiAgICAgICAgICAgICAgICBpZiAobmJDaGFubmVscyAhPT0gdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aCkgewogICAgICAgICAgICAgICAgICAgIHRoaXMuYWxsb2NhdGVPdXRwdXRDaGFubmVscyhpLCBuYkNoYW5uZWxzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZWFkSW5wdXRzKGlucHV0cykgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIGxldCB3ZWJBdWRpb0Jsb2NrID0gaW5wdXRzW2ldW2pdOwogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2ldW2pdLnNldCh3ZWJBdWRpb0Jsb2NrLCB0aGlzLmJsb2NrU2l6ZSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgd3JpdGVPdXRwdXRzKG91dHB1dHMpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iT3V0cHV0czsgaSsrKSB7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMub3V0cHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIGxldCB3ZWJBdWRpb0Jsb2NrID0gb3V0cHV0c1tpXVtqXTsKICAgICAgICAgICAgICAgICAgICB3ZWJBdWRpb0Jsb2NrLnNldCh0aGlzLm91dHB1dEJ1ZmZlcnNbaV1bal0uc3ViYXJyYXkoMCwgV0VCQVVESU9fQkxPQ0tfU0laRSkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHNoaWZ0SW5wdXRCdWZmZXJzKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzW2ldW2pdLmNvcHlXaXRoaW4oMCwgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgc2hpZnRPdXRwdXRCdWZmZXJzKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aDsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW2ldW2pdLmNvcHlXaXRoaW4oMCwgV0VCQVVESU9fQkxPQ0tfU0laRSk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5vdXRwdXRCdWZmZXJzW2ldW2pdLmZpbGwoMCwgdGhpcy5ibG9ja1NpemUgLSBXRUJBVURJT19CTE9DS19TSVpFKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcmVwYXJlSW5wdXRCdWZmZXJzVG9TZW5kKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmlucHV0QnVmZmVyc1tpXS5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRCdWZmZXJzVG9TZW5kW2ldW2pdLnNldCh0aGlzLmlucHV0QnVmZmVyc0hlYWRbaV1bal0pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGhhbmRsZU91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlKCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJPdXRwdXRzOyBpKyspIHsKICAgICAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgdGhpcy5vdXRwdXRCdWZmZXJzW2ldLmxlbmd0aDsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgayA9IDA7IGsgPCB0aGlzLmJsb2NrU2l6ZTsgaysrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMub3V0cHV0QnVmZmVyc1tpXVtqXVtrXSArPSB0aGlzLm91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlW2ldW2pdW2tdIC8gdGhpcy5uYk92ZXJsYXBzOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzKGlucHV0cywgb3V0cHV0cywgcGFyYW1ldGVycykgewogICAgICAgICAgICB0aGlzLnJlYWxsb2NhdGVDaGFubmVsc0lmTmVlZGVkKGlucHV0cywgb3V0cHV0cyk7CiAgICAgICAgICAgIHRoaXMucmVhZElucHV0cyhpbnB1dHMpOwogICAgICAgICAgICB0aGlzLnNoaWZ0SW5wdXRCdWZmZXJzKCk7CiAgICAgICAgICAgIHRoaXMucHJlcGFyZUlucHV0QnVmZmVyc1RvU2VuZCgpOwogICAgICAgICAgICB0aGlzLnByb2Nlc3NPTEEodGhpcy5pbnB1dEJ1ZmZlcnNUb1NlbmQsIHRoaXMub3V0cHV0QnVmZmVyc1RvUmV0cmlldmUsIHBhcmFtZXRlcnMpOwogICAgICAgICAgICB0aGlzLmhhbmRsZU91dHB1dEJ1ZmZlcnNUb1JldHJpZXZlKCk7CiAgICAgICAgICAgIHRoaXMud3JpdGVPdXRwdXRzKG91dHB1dHMpOwogICAgICAgICAgICB0aGlzLnNoaWZ0T3V0cHV0QnVmZmVycygpOwogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMgKHgpIHsKICAgIAlyZXR1cm4geCAmJiB4Ll9fZXNNb2R1bGUgJiYgT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHgsICdkZWZhdWx0JykgPyB4WydkZWZhdWx0J10gOiB4OwogICAgfQoKICAgIGZ1bmN0aW9uIEZGVChzaXplKSB7CiAgICAgIHRoaXMuc2l6ZSA9IHNpemUgfCAwOwogICAgICBpZiAodGhpcy5zaXplIDw9IDEgfHwgKHRoaXMuc2l6ZSAmICh0aGlzLnNpemUgLSAxKSkgIT09IDApCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdGRlQgc2l6ZSBtdXN0IGJlIGEgcG93ZXIgb2YgdHdvIGFuZCBiaWdnZXIgdGhhbiAxJyk7CgogICAgICB0aGlzLl9jc2l6ZSA9IHNpemUgPDwgMTsKCiAgICAgIC8vIE5PVEU6IFVzZSBvZiBgdmFyYCBpcyBpbnRlbnRpb25hbCBmb3Igb2xkIFY4IHZlcnNpb25zCiAgICAgIHZhciB0YWJsZSA9IG5ldyBBcnJheSh0aGlzLnNpemUgKiAyKTsKICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0YWJsZS5sZW5ndGg7IGkgKz0gMikgewogICAgICAgIGNvbnN0IGFuZ2xlID0gTWF0aC5QSSAqIGkgLyB0aGlzLnNpemU7CiAgICAgICAgdGFibGVbaV0gPSBNYXRoLmNvcyhhbmdsZSk7CiAgICAgICAgdGFibGVbaSArIDFdID0gLU1hdGguc2luKGFuZ2xlKTsKICAgICAgfQogICAgICB0aGlzLnRhYmxlID0gdGFibGU7CgogICAgICAvLyBGaW5kIHNpemUncyBwb3dlciBvZiB0d28KICAgICAgdmFyIHBvd2VyID0gMDsKICAgICAgZm9yICh2YXIgdCA9IDE7IHRoaXMuc2l6ZSA+IHQ7IHQgPDw9IDEpCiAgICAgICAgcG93ZXIrKzsKCiAgICAgIC8vIENhbGN1bGF0ZSBpbml0aWFsIHN0ZXAncyB3aWR0aDoKICAgICAgLy8gICAqIElmIHdlIGFyZSBmdWxsIHJhZGl4LTQgLSBpdCBpcyAyeCBzbWFsbGVyIHRvIGdpdmUgaW5pdGFsIGxlbj04CiAgICAgIC8vICAgKiBPdGhlcndpc2UgaXQgaXMgdGhlIHNhbWUgYXMgYHBvd2VyYCB0byBnaXZlIGxlbj00CiAgICAgIHRoaXMuX3dpZHRoID0gcG93ZXIgJSAyID09PSAwID8gcG93ZXIgLSAxIDogcG93ZXI7CgogICAgICAvLyBQcmUtY29tcHV0ZSBiaXQtcmV2ZXJzYWwgcGF0dGVybnMKICAgICAgdGhpcy5fYml0cmV2ID0gbmV3IEFycmF5KDEgPDwgdGhpcy5fd2lkdGgpOwogICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHRoaXMuX2JpdHJldi5sZW5ndGg7IGorKykgewogICAgICAgIHRoaXMuX2JpdHJldltqXSA9IDA7CiAgICAgICAgZm9yICh2YXIgc2hpZnQgPSAwOyBzaGlmdCA8IHRoaXMuX3dpZHRoOyBzaGlmdCArPSAyKSB7CiAgICAgICAgICB2YXIgcmV2U2hpZnQgPSB0aGlzLl93aWR0aCAtIHNoaWZ0IC0gMjsKICAgICAgICAgIHRoaXMuX2JpdHJldltqXSB8PSAoKGogPj4+IHNoaWZ0KSAmIDMpIDw8IHJldlNoaWZ0OwogICAgICAgIH0KICAgICAgfQoKICAgICAgdGhpcy5fb3V0ID0gbnVsbDsKICAgICAgdGhpcy5fZGF0YSA9IG51bGw7CiAgICAgIHRoaXMuX2ludiA9IDA7CiAgICB9CiAgICB2YXIgZmZ0ID0gRkZUOwoKICAgIEZGVC5wcm90b3R5cGUuZnJvbUNvbXBsZXhBcnJheSA9IGZ1bmN0aW9uIGZyb21Db21wbGV4QXJyYXkoY29tcGxleCwgc3RvcmFnZSkgewogICAgICB2YXIgcmVzID0gc3RvcmFnZSB8fCBuZXcgQXJyYXkoY29tcGxleC5sZW5ndGggPj4+IDEpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvbXBsZXgubGVuZ3RoOyBpICs9IDIpCiAgICAgICAgcmVzW2kgPj4+IDFdID0gY29tcGxleFtpXTsKICAgICAgcmV0dXJuIHJlczsKICAgIH07CgogICAgRkZULnByb3RvdHlwZS5jcmVhdGVDb21wbGV4QXJyYXkgPSBmdW5jdGlvbiBjcmVhdGVDb21wbGV4QXJyYXkoKSB7CiAgICAgIGNvbnN0IHJlcyA9IG5ldyBBcnJheSh0aGlzLl9jc2l6ZSk7CiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmVzLmxlbmd0aDsgaSsrKQogICAgICAgIHJlc1tpXSA9IDA7CiAgICAgIHJldHVybiByZXM7CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUudG9Db21wbGV4QXJyYXkgPSBmdW5jdGlvbiB0b0NvbXBsZXhBcnJheShpbnB1dCwgc3RvcmFnZSkgewogICAgICB2YXIgcmVzID0gc3RvcmFnZSB8fCB0aGlzLmNyZWF0ZUNvbXBsZXhBcnJheSgpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJlcy5sZW5ndGg7IGkgKz0gMikgewogICAgICAgIHJlc1tpXSA9IGlucHV0W2kgPj4+IDFdOwogICAgICAgIHJlc1tpICsgMV0gPSAwOwogICAgICB9CiAgICAgIHJldHVybiByZXM7CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUuY29tcGxldGVTcGVjdHJ1bSA9IGZ1bmN0aW9uIGNvbXBsZXRlU3BlY3RydW0oc3BlY3RydW0pIHsKICAgICAgdmFyIHNpemUgPSB0aGlzLl9jc2l6ZTsKICAgICAgdmFyIGhhbGYgPSBzaXplID4+PiAxOwogICAgICBmb3IgKHZhciBpID0gMjsgaSA8IGhhbGY7IGkgKz0gMikgewogICAgICAgIHNwZWN0cnVtW3NpemUgLSBpXSA9IHNwZWN0cnVtW2ldOwogICAgICAgIHNwZWN0cnVtW3NpemUgLSBpICsgMV0gPSAtc3BlY3RydW1baSArIDFdOwogICAgICB9CiAgICB9OwoKICAgIEZGVC5wcm90b3R5cGUudHJhbnNmb3JtID0gZnVuY3Rpb24gdHJhbnNmb3JtKG91dCwgZGF0YSkgewogICAgICBpZiAob3V0ID09PSBkYXRhKQogICAgICAgIHRocm93IG5ldyBFcnJvcignSW5wdXQgYW5kIG91dHB1dCBidWZmZXJzIG11c3QgYmUgZGlmZmVyZW50Jyk7CgogICAgICB0aGlzLl9vdXQgPSBvdXQ7CiAgICAgIHRoaXMuX2RhdGEgPSBkYXRhOwogICAgICB0aGlzLl9pbnYgPSAwOwogICAgICB0aGlzLl90cmFuc2Zvcm00KCk7CiAgICAgIHRoaXMuX291dCA9IG51bGw7CiAgICAgIHRoaXMuX2RhdGEgPSBudWxsOwogICAgfTsKCiAgICBGRlQucHJvdG90eXBlLnJlYWxUcmFuc2Zvcm0gPSBmdW5jdGlvbiByZWFsVHJhbnNmb3JtKG91dCwgZGF0YSkgewogICAgICBpZiAob3V0ID09PSBkYXRhKQogICAgICAgIHRocm93IG5ldyBFcnJvcignSW5wdXQgYW5kIG91dHB1dCBidWZmZXJzIG11c3QgYmUgZGlmZmVyZW50Jyk7CgogICAgICB0aGlzLl9vdXQgPSBvdXQ7CiAgICAgIHRoaXMuX2RhdGEgPSBkYXRhOwogICAgICB0aGlzLl9pbnYgPSAwOwogICAgICB0aGlzLl9yZWFsVHJhbnNmb3JtNCgpOwogICAgICB0aGlzLl9vdXQgPSBudWxsOwogICAgICB0aGlzLl9kYXRhID0gbnVsbDsKICAgIH07CgogICAgRkZULnByb3RvdHlwZS5pbnZlcnNlVHJhbnNmb3JtID0gZnVuY3Rpb24gaW52ZXJzZVRyYW5zZm9ybShvdXQsIGRhdGEpIHsKICAgICAgaWYgKG91dCA9PT0gZGF0YSkKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0lucHV0IGFuZCBvdXRwdXQgYnVmZmVycyBtdXN0IGJlIGRpZmZlcmVudCcpOwoKICAgICAgdGhpcy5fb3V0ID0gb3V0OwogICAgICB0aGlzLl9kYXRhID0gZGF0YTsKICAgICAgdGhpcy5faW52ID0gMTsKICAgICAgdGhpcy5fdHJhbnNmb3JtNCgpOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG91dC5sZW5ndGg7IGkrKykKICAgICAgICBvdXRbaV0gLz0gdGhpcy5zaXplOwogICAgICB0aGlzLl9vdXQgPSBudWxsOwogICAgICB0aGlzLl9kYXRhID0gbnVsbDsKICAgIH07CgogICAgLy8gcmFkaXgtNCBpbXBsZW1lbnRhdGlvbgogICAgLy8KICAgIC8vIE5PVEU6IFVzZXMgb2YgYHZhcmAgYXJlIGludGVudGlvbmFsIGZvciBvbGRlciBWOCB2ZXJzaW9uIHRoYXQgZG8gbm90CiAgICAvLyBzdXBwb3J0IGJvdGggYGxldCBjb21wb3VuZCBhc3NpZ25tZW50c2AgYW5kIGBjb25zdCBwaGlgCiAgICBGRlQucHJvdG90eXBlLl90cmFuc2Zvcm00ID0gZnVuY3Rpb24gX3RyYW5zZm9ybTQoKSB7CiAgICAgIHZhciBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIHZhciBzaXplID0gdGhpcy5fY3NpemU7CgogICAgICAvLyBJbml0aWFsIHN0ZXAgKHBlcm11dGUgYW5kIHRyYW5zZm9ybSkKICAgICAgdmFyIHdpZHRoID0gdGhpcy5fd2lkdGg7CiAgICAgIHZhciBzdGVwID0gMSA8PCB3aWR0aDsKICAgICAgdmFyIGxlbiA9IChzaXplIC8gc3RlcCkgPDwgMTsKCiAgICAgIHZhciBvdXRPZmY7CiAgICAgIHZhciB0OwogICAgICB2YXIgYml0cmV2ID0gdGhpcy5fYml0cmV2OwogICAgICBpZiAobGVuID09PSA0KSB7CiAgICAgICAgZm9yIChvdXRPZmYgPSAwLCB0ID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbiwgdCsrKSB7CiAgICAgICAgICBjb25zdCBvZmYgPSBiaXRyZXZbdF07CiAgICAgICAgICB0aGlzLl9zaW5nbGVUcmFuc2Zvcm0yKG91dE9mZiwgb2ZmLCBzdGVwKTsKICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgLy8gbGVuID09PSA4CiAgICAgICAgZm9yIChvdXRPZmYgPSAwLCB0ID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbiwgdCsrKSB7CiAgICAgICAgICBjb25zdCBvZmYgPSBiaXRyZXZbdF07CiAgICAgICAgICB0aGlzLl9zaW5nbGVUcmFuc2Zvcm00KG91dE9mZiwgb2ZmLCBzdGVwKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8vIExvb3AgdGhyb3VnaCBzdGVwcyBpbiBkZWNyZWFzaW5nIG9yZGVyCiAgICAgIHZhciBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIHZhciB0YWJsZSA9IHRoaXMudGFibGU7CiAgICAgIGZvciAoc3RlcCA+Pj0gMjsgc3RlcCA+PSAyOyBzdGVwID4+PSAyKSB7CiAgICAgICAgbGVuID0gKHNpemUgLyBzdGVwKSA8PCAxOwogICAgICAgIHZhciBxdWFydGVyTGVuID0gbGVuID4+PiAyOwoKICAgICAgICAvLyBMb29wIHRocm91Z2ggb2Zmc2V0cyBpbiB0aGUgZGF0YQogICAgICAgIGZvciAob3V0T2ZmID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbikgewogICAgICAgICAgLy8gRnVsbCBjYXNlCiAgICAgICAgICB2YXIgbGltaXQgPSBvdXRPZmYgKyBxdWFydGVyTGVuOwogICAgICAgICAgZm9yICh2YXIgaSA9IG91dE9mZiwgayA9IDA7IGkgPCBsaW1pdDsgaSArPSAyLCBrICs9IHN0ZXApIHsKICAgICAgICAgICAgY29uc3QgQSA9IGk7CiAgICAgICAgICAgIGNvbnN0IEIgPSBBICsgcXVhcnRlckxlbjsKICAgICAgICAgICAgY29uc3QgQyA9IEIgKyBxdWFydGVyTGVuOwogICAgICAgICAgICBjb25zdCBEID0gQyArIHF1YXJ0ZXJMZW47CgogICAgICAgICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgQXIgPSBvdXRbQV07CiAgICAgICAgICAgIGNvbnN0IEFpID0gb3V0W0EgKyAxXTsKICAgICAgICAgICAgY29uc3QgQnIgPSBvdXRbQl07CiAgICAgICAgICAgIGNvbnN0IEJpID0gb3V0W0IgKyAxXTsKICAgICAgICAgICAgY29uc3QgQ3IgPSBvdXRbQ107CiAgICAgICAgICAgIGNvbnN0IENpID0gb3V0W0MgKyAxXTsKICAgICAgICAgICAgY29uc3QgRHIgPSBvdXRbRF07CiAgICAgICAgICAgIGNvbnN0IERpID0gb3V0W0QgKyAxXTsKCiAgICAgICAgICAgIC8vIE1pZGRsZSB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgTUFyID0gQXI7CiAgICAgICAgICAgIGNvbnN0IE1BaSA9IEFpOwoKICAgICAgICAgICAgY29uc3QgdGFibGVCciA9IHRhYmxlW2tdOwogICAgICAgICAgICBjb25zdCB0YWJsZUJpID0gaW52ICogdGFibGVbayArIDFdOwogICAgICAgICAgICBjb25zdCBNQnIgPSBCciAqIHRhYmxlQnIgLSBCaSAqIHRhYmxlQmk7CiAgICAgICAgICAgIGNvbnN0IE1CaSA9IEJyICogdGFibGVCaSArIEJpICogdGFibGVCcjsKCiAgICAgICAgICAgIGNvbnN0IHRhYmxlQ3IgPSB0YWJsZVsyICoga107CiAgICAgICAgICAgIGNvbnN0IHRhYmxlQ2kgPSBpbnYgKiB0YWJsZVsyICogayArIDFdOwogICAgICAgICAgICBjb25zdCBNQ3IgPSBDciAqIHRhYmxlQ3IgLSBDaSAqIHRhYmxlQ2k7CiAgICAgICAgICAgIGNvbnN0IE1DaSA9IENyICogdGFibGVDaSArIENpICogdGFibGVDcjsKCiAgICAgICAgICAgIGNvbnN0IHRhYmxlRHIgPSB0YWJsZVszICoga107CiAgICAgICAgICAgIGNvbnN0IHRhYmxlRGkgPSBpbnYgKiB0YWJsZVszICogayArIDFdOwogICAgICAgICAgICBjb25zdCBNRHIgPSBEciAqIHRhYmxlRHIgLSBEaSAqIHRhYmxlRGk7CiAgICAgICAgICAgIGNvbnN0IE1EaSA9IERyICogdGFibGVEaSArIERpICogdGFibGVEcjsKCiAgICAgICAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgICAgICAgY29uc3QgVDByID0gTUFyICsgTUNyOwogICAgICAgICAgICBjb25zdCBUMGkgPSBNQWkgKyBNQ2k7CiAgICAgICAgICAgIGNvbnN0IFQxciA9IE1BciAtIE1DcjsKICAgICAgICAgICAgY29uc3QgVDFpID0gTUFpIC0gTUNpOwogICAgICAgICAgICBjb25zdCBUMnIgPSBNQnIgKyBNRHI7CiAgICAgICAgICAgIGNvbnN0IFQyaSA9IE1CaSArIE1EaTsKICAgICAgICAgICAgY29uc3QgVDNyID0gaW52ICogKE1CciAtIE1Ecik7CiAgICAgICAgICAgIGNvbnN0IFQzaSA9IGludiAqIChNQmkgLSBNRGkpOwoKICAgICAgICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgICAgICAgIGNvbnN0IEZBciA9IFQwciArIFQycjsKICAgICAgICAgICAgY29uc3QgRkFpID0gVDBpICsgVDJpOwoKICAgICAgICAgICAgY29uc3QgRkNyID0gVDByIC0gVDJyOwogICAgICAgICAgICBjb25zdCBGQ2kgPSBUMGkgLSBUMmk7CgogICAgICAgICAgICBjb25zdCBGQnIgPSBUMXIgKyBUM2k7CiAgICAgICAgICAgIGNvbnN0IEZCaSA9IFQxaSAtIFQzcjsKCiAgICAgICAgICAgIGNvbnN0IEZEciA9IFQxciAtIFQzaTsKICAgICAgICAgICAgY29uc3QgRkRpID0gVDFpICsgVDNyOwoKICAgICAgICAgICAgb3V0W0FdID0gRkFyOwogICAgICAgICAgICBvdXRbQSArIDFdID0gRkFpOwogICAgICAgICAgICBvdXRbQl0gPSBGQnI7CiAgICAgICAgICAgIG91dFtCICsgMV0gPSBGQmk7CiAgICAgICAgICAgIG91dFtDXSA9IEZDcjsKICAgICAgICAgICAgb3V0W0MgKyAxXSA9IEZDaTsKICAgICAgICAgICAgb3V0W0RdID0gRkRyOwogICAgICAgICAgICBvdXRbRCArIDFdID0gRkRpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfTsKCiAgICAvLyByYWRpeC0yIGltcGxlbWVudGF0aW9uCiAgICAvLwogICAgLy8gTk9URTogT25seSBjYWxsZWQgZm9yIGxlbj00CiAgICBGRlQucHJvdG90eXBlLl9zaW5nbGVUcmFuc2Zvcm0yID0gZnVuY3Rpb24gX3NpbmdsZVRyYW5zZm9ybTIob3V0T2ZmLCBvZmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwoKICAgICAgY29uc3QgZXZlblIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IGV2ZW5JID0gZGF0YVtvZmYgKyAxXTsKICAgICAgY29uc3Qgb2RkUiA9IGRhdGFbb2ZmICsgc3RlcF07CiAgICAgIGNvbnN0IG9kZEkgPSBkYXRhW29mZiArIHN0ZXAgKyAxXTsKCiAgICAgIGNvbnN0IGxlZnRSID0gZXZlblIgKyBvZGRSOwogICAgICBjb25zdCBsZWZ0SSA9IGV2ZW5JICsgb2RkSTsKICAgICAgY29uc3QgcmlnaHRSID0gZXZlblIgLSBvZGRSOwogICAgICBjb25zdCByaWdodEkgPSBldmVuSSAtIG9kZEk7CgogICAgICBvdXRbb3V0T2ZmXSA9IGxlZnRSOwogICAgICBvdXRbb3V0T2ZmICsgMV0gPSBsZWZ0STsKICAgICAgb3V0W291dE9mZiArIDJdID0gcmlnaHRSOwogICAgICBvdXRbb3V0T2ZmICsgM10gPSByaWdodEk7CiAgICB9OwoKICAgIC8vIHJhZGl4LTQKICAgIC8vCiAgICAvLyBOT1RFOiBPbmx5IGNhbGxlZCBmb3IgbGVuPTgKICAgIEZGVC5wcm90b3R5cGUuX3NpbmdsZVRyYW5zZm9ybTQgPSBmdW5jdGlvbiBfc2luZ2xlVHJhbnNmb3JtNChvdXRPZmYsIG9mZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwKSB7CiAgICAgIGNvbnN0IG91dCA9IHRoaXMuX291dDsKICAgICAgY29uc3QgZGF0YSA9IHRoaXMuX2RhdGE7CiAgICAgIGNvbnN0IGludiA9IHRoaXMuX2ludiA/IC0xIDogMTsKICAgICAgY29uc3Qgc3RlcDIgPSBzdGVwICogMjsKICAgICAgY29uc3Qgc3RlcDMgPSBzdGVwICogMzsKCiAgICAgIC8vIE9yaWdpbmFsIHZhbHVlcwogICAgICBjb25zdCBBciA9IGRhdGFbb2ZmXTsKICAgICAgY29uc3QgQWkgPSBkYXRhW29mZiArIDFdOwogICAgICBjb25zdCBCciA9IGRhdGFbb2ZmICsgc3RlcF07CiAgICAgIGNvbnN0IEJpID0gZGF0YVtvZmYgKyBzdGVwICsgMV07CiAgICAgIGNvbnN0IENyID0gZGF0YVtvZmYgKyBzdGVwMl07CiAgICAgIGNvbnN0IENpID0gZGF0YVtvZmYgKyBzdGVwMiArIDFdOwogICAgICBjb25zdCBEciA9IGRhdGFbb2ZmICsgc3RlcDNdOwogICAgICBjb25zdCBEaSA9IGRhdGFbb2ZmICsgc3RlcDMgKyAxXTsKCiAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgVDByID0gQXIgKyBDcjsKICAgICAgY29uc3QgVDBpID0gQWkgKyBDaTsKICAgICAgY29uc3QgVDFyID0gQXIgLSBDcjsKICAgICAgY29uc3QgVDFpID0gQWkgLSBDaTsKICAgICAgY29uc3QgVDJyID0gQnIgKyBEcjsKICAgICAgY29uc3QgVDJpID0gQmkgKyBEaTsKICAgICAgY29uc3QgVDNyID0gaW52ICogKEJyIC0gRHIpOwogICAgICBjb25zdCBUM2kgPSBpbnYgKiAoQmkgLSBEaSk7CgogICAgICAvLyBGaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgRkFyID0gVDByICsgVDJyOwogICAgICBjb25zdCBGQWkgPSBUMGkgKyBUMmk7CgogICAgICBjb25zdCBGQnIgPSBUMXIgKyBUM2k7CiAgICAgIGNvbnN0IEZCaSA9IFQxaSAtIFQzcjsKCiAgICAgIGNvbnN0IEZDciA9IFQwciAtIFQycjsKICAgICAgY29uc3QgRkNpID0gVDBpIC0gVDJpOwoKICAgICAgY29uc3QgRkRyID0gVDFyIC0gVDNpOwogICAgICBjb25zdCBGRGkgPSBUMWkgKyBUM3I7CgogICAgICBvdXRbb3V0T2ZmXSA9IEZBcjsKICAgICAgb3V0W291dE9mZiArIDFdID0gRkFpOwogICAgICBvdXRbb3V0T2ZmICsgMl0gPSBGQnI7CiAgICAgIG91dFtvdXRPZmYgKyAzXSA9IEZCaTsKICAgICAgb3V0W291dE9mZiArIDRdID0gRkNyOwogICAgICBvdXRbb3V0T2ZmICsgNV0gPSBGQ2k7CiAgICAgIG91dFtvdXRPZmYgKyA2XSA9IEZEcjsKICAgICAgb3V0W291dE9mZiArIDddID0gRkRpOwogICAgfTsKCiAgICAvLyBSZWFsIGlucHV0IHJhZGl4LTQgaW1wbGVtZW50YXRpb24KICAgIEZGVC5wcm90b3R5cGUuX3JlYWxUcmFuc2Zvcm00ID0gZnVuY3Rpb24gX3JlYWxUcmFuc2Zvcm00KCkgewogICAgICB2YXIgb3V0ID0gdGhpcy5fb3V0OwogICAgICB2YXIgc2l6ZSA9IHRoaXMuX2NzaXplOwoKICAgICAgLy8gSW5pdGlhbCBzdGVwIChwZXJtdXRlIGFuZCB0cmFuc2Zvcm0pCiAgICAgIHZhciB3aWR0aCA9IHRoaXMuX3dpZHRoOwogICAgICB2YXIgc3RlcCA9IDEgPDwgd2lkdGg7CiAgICAgIHZhciBsZW4gPSAoc2l6ZSAvIHN0ZXApIDw8IDE7CgogICAgICB2YXIgb3V0T2ZmOwogICAgICB2YXIgdDsKICAgICAgdmFyIGJpdHJldiA9IHRoaXMuX2JpdHJldjsKICAgICAgaWYgKGxlbiA9PT0gNCkgewogICAgICAgIGZvciAob3V0T2ZmID0gMCwgdCA9IDA7IG91dE9mZiA8IHNpemU7IG91dE9mZiArPSBsZW4sIHQrKykgewogICAgICAgICAgY29uc3Qgb2ZmID0gYml0cmV2W3RdOwogICAgICAgICAgdGhpcy5fc2luZ2xlUmVhbFRyYW5zZm9ybTIob3V0T2ZmLCBvZmYgPj4+IDEsIHN0ZXAgPj4+IDEpOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICAvLyBsZW4gPT09IDgKICAgICAgICBmb3IgKG91dE9mZiA9IDAsIHQgPSAwOyBvdXRPZmYgPCBzaXplOyBvdXRPZmYgKz0gbGVuLCB0KyspIHsKICAgICAgICAgIGNvbnN0IG9mZiA9IGJpdHJldlt0XTsKICAgICAgICAgIHRoaXMuX3NpbmdsZVJlYWxUcmFuc2Zvcm00KG91dE9mZiwgb2ZmID4+PiAxLCBzdGVwID4+PiAxKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8vIExvb3AgdGhyb3VnaCBzdGVwcyBpbiBkZWNyZWFzaW5nIG9yZGVyCiAgICAgIHZhciBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIHZhciB0YWJsZSA9IHRoaXMudGFibGU7CiAgICAgIGZvciAoc3RlcCA+Pj0gMjsgc3RlcCA+PSAyOyBzdGVwID4+PSAyKSB7CiAgICAgICAgbGVuID0gKHNpemUgLyBzdGVwKSA8PCAxOwogICAgICAgIHZhciBoYWxmTGVuID0gbGVuID4+PiAxOwogICAgICAgIHZhciBxdWFydGVyTGVuID0gaGFsZkxlbiA+Pj4gMTsKICAgICAgICB2YXIgaHF1YXJ0ZXJMZW4gPSBxdWFydGVyTGVuID4+PiAxOwoKICAgICAgICAvLyBMb29wIHRocm91Z2ggb2Zmc2V0cyBpbiB0aGUgZGF0YQogICAgICAgIGZvciAob3V0T2ZmID0gMDsgb3V0T2ZmIDwgc2l6ZTsgb3V0T2ZmICs9IGxlbikgewogICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGsgPSAwOyBpIDw9IGhxdWFydGVyTGVuOyBpICs9IDIsIGsgKz0gc3RlcCkgewogICAgICAgICAgICB2YXIgQSA9IG91dE9mZiArIGk7CiAgICAgICAgICAgIHZhciBCID0gQSArIHF1YXJ0ZXJMZW47CiAgICAgICAgICAgIHZhciBDID0gQiArIHF1YXJ0ZXJMZW47CiAgICAgICAgICAgIHZhciBEID0gQyArIHF1YXJ0ZXJMZW47CgogICAgICAgICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgICAgICAgdmFyIEFyID0gb3V0W0FdOwogICAgICAgICAgICB2YXIgQWkgPSBvdXRbQSArIDFdOwogICAgICAgICAgICB2YXIgQnIgPSBvdXRbQl07CiAgICAgICAgICAgIHZhciBCaSA9IG91dFtCICsgMV07CiAgICAgICAgICAgIHZhciBDciA9IG91dFtDXTsKICAgICAgICAgICAgdmFyIENpID0gb3V0W0MgKyAxXTsKICAgICAgICAgICAgdmFyIERyID0gb3V0W0RdOwogICAgICAgICAgICB2YXIgRGkgPSBvdXRbRCArIDFdOwoKICAgICAgICAgICAgLy8gTWlkZGxlIHZhbHVlcwogICAgICAgICAgICB2YXIgTUFyID0gQXI7CiAgICAgICAgICAgIHZhciBNQWkgPSBBaTsKCiAgICAgICAgICAgIHZhciB0YWJsZUJyID0gdGFibGVba107CiAgICAgICAgICAgIHZhciB0YWJsZUJpID0gaW52ICogdGFibGVbayArIDFdOwogICAgICAgICAgICB2YXIgTUJyID0gQnIgKiB0YWJsZUJyIC0gQmkgKiB0YWJsZUJpOwogICAgICAgICAgICB2YXIgTUJpID0gQnIgKiB0YWJsZUJpICsgQmkgKiB0YWJsZUJyOwoKICAgICAgICAgICAgdmFyIHRhYmxlQ3IgPSB0YWJsZVsyICoga107CiAgICAgICAgICAgIHZhciB0YWJsZUNpID0gaW52ICogdGFibGVbMiAqIGsgKyAxXTsKICAgICAgICAgICAgdmFyIE1DciA9IENyICogdGFibGVDciAtIENpICogdGFibGVDaTsKICAgICAgICAgICAgdmFyIE1DaSA9IENyICogdGFibGVDaSArIENpICogdGFibGVDcjsKCiAgICAgICAgICAgIHZhciB0YWJsZURyID0gdGFibGVbMyAqIGtdOwogICAgICAgICAgICB2YXIgdGFibGVEaSA9IGludiAqIHRhYmxlWzMgKiBrICsgMV07CiAgICAgICAgICAgIHZhciBNRHIgPSBEciAqIHRhYmxlRHIgLSBEaSAqIHRhYmxlRGk7CiAgICAgICAgICAgIHZhciBNRGkgPSBEciAqIHRhYmxlRGkgKyBEaSAqIHRhYmxlRHI7CgogICAgICAgICAgICAvLyBQcmUtRmluYWwgdmFsdWVzCiAgICAgICAgICAgIHZhciBUMHIgPSBNQXIgKyBNQ3I7CiAgICAgICAgICAgIHZhciBUMGkgPSBNQWkgKyBNQ2k7CiAgICAgICAgICAgIHZhciBUMXIgPSBNQXIgLSBNQ3I7CiAgICAgICAgICAgIHZhciBUMWkgPSBNQWkgLSBNQ2k7CiAgICAgICAgICAgIHZhciBUMnIgPSBNQnIgKyBNRHI7CiAgICAgICAgICAgIHZhciBUMmkgPSBNQmkgKyBNRGk7CiAgICAgICAgICAgIHZhciBUM3IgPSBpbnYgKiAoTUJyIC0gTURyKTsKICAgICAgICAgICAgdmFyIFQzaSA9IGludiAqIChNQmkgLSBNRGkpOwoKICAgICAgICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgICAgICAgIHZhciBGQXIgPSBUMHIgKyBUMnI7CiAgICAgICAgICAgIHZhciBGQWkgPSBUMGkgKyBUMmk7CgogICAgICAgICAgICB2YXIgRkJyID0gVDFyICsgVDNpOwogICAgICAgICAgICB2YXIgRkJpID0gVDFpIC0gVDNyOwoKICAgICAgICAgICAgb3V0W0FdID0gRkFyOwogICAgICAgICAgICBvdXRbQSArIDFdID0gRkFpOwogICAgICAgICAgICBvdXRbQl0gPSBGQnI7CiAgICAgICAgICAgIG91dFtCICsgMV0gPSBGQmk7CgogICAgICAgICAgICAvLyBPdXRwdXQgZmluYWwgbWlkZGxlIHBvaW50CiAgICAgICAgICAgIGlmIChpID09PSAwKSB7CiAgICAgICAgICAgICAgdmFyIEZDciA9IFQwciAtIFQycjsKICAgICAgICAgICAgICB2YXIgRkNpID0gVDBpIC0gVDJpOwogICAgICAgICAgICAgIG91dFtDXSA9IEZDcjsKICAgICAgICAgICAgICBvdXRbQyArIDFdID0gRkNpOwogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBEbyBub3Qgb3ZlcndyaXRlIG91cnNlbHZlcwogICAgICAgICAgICBpZiAoaSA9PT0gaHF1YXJ0ZXJMZW4pCiAgICAgICAgICAgICAgY29udGludWU7CgogICAgICAgICAgICAvLyBJbiB0aGUgZmxpcHBlZCBjYXNlOgogICAgICAgICAgICAvLyBNQWkgPSAtTUFpCiAgICAgICAgICAgIC8vIE1Ccj0tTUJpLCBNQmk9LU1CcgogICAgICAgICAgICAvLyBNQ3I9LU1DcgogICAgICAgICAgICAvLyBNRHI9TURpLCBNRGk9TURyCiAgICAgICAgICAgIHZhciBTVDByID0gVDFyOwogICAgICAgICAgICB2YXIgU1QwaSA9IC1UMWk7CiAgICAgICAgICAgIHZhciBTVDFyID0gVDByOwogICAgICAgICAgICB2YXIgU1QxaSA9IC1UMGk7CiAgICAgICAgICAgIHZhciBTVDJyID0gLWludiAqIFQzaTsKICAgICAgICAgICAgdmFyIFNUMmkgPSAtaW52ICogVDNyOwogICAgICAgICAgICB2YXIgU1QzciA9IC1pbnYgKiBUMmk7CiAgICAgICAgICAgIHZhciBTVDNpID0gLWludiAqIFQycjsKCiAgICAgICAgICAgIHZhciBTRkFyID0gU1QwciArIFNUMnI7CiAgICAgICAgICAgIHZhciBTRkFpID0gU1QwaSArIFNUMmk7CgogICAgICAgICAgICB2YXIgU0ZCciA9IFNUMXIgKyBTVDNpOwogICAgICAgICAgICB2YXIgU0ZCaSA9IFNUMWkgLSBTVDNyOwoKICAgICAgICAgICAgdmFyIFNBID0gb3V0T2ZmICsgcXVhcnRlckxlbiAtIGk7CiAgICAgICAgICAgIHZhciBTQiA9IG91dE9mZiArIGhhbGZMZW4gLSBpOwoKICAgICAgICAgICAgb3V0W1NBXSA9IFNGQXI7CiAgICAgICAgICAgIG91dFtTQSArIDFdID0gU0ZBaTsKICAgICAgICAgICAgb3V0W1NCXSA9IFNGQnI7CiAgICAgICAgICAgIG91dFtTQiArIDFdID0gU0ZCaTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH07CgogICAgLy8gcmFkaXgtMiBpbXBsZW1lbnRhdGlvbgogICAgLy8KICAgIC8vIE5PVEU6IE9ubHkgY2FsbGVkIGZvciBsZW49NAogICAgRkZULnByb3RvdHlwZS5fc2luZ2xlUmVhbFRyYW5zZm9ybTIgPSBmdW5jdGlvbiBfc2luZ2xlUmVhbFRyYW5zZm9ybTIob3V0T2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwoKICAgICAgY29uc3QgZXZlblIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IG9kZFIgPSBkYXRhW29mZiArIHN0ZXBdOwoKICAgICAgY29uc3QgbGVmdFIgPSBldmVuUiArIG9kZFI7CiAgICAgIGNvbnN0IHJpZ2h0UiA9IGV2ZW5SIC0gb2RkUjsKCiAgICAgIG91dFtvdXRPZmZdID0gbGVmdFI7CiAgICAgIG91dFtvdXRPZmYgKyAxXSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyAyXSA9IHJpZ2h0UjsKICAgICAgb3V0W291dE9mZiArIDNdID0gMDsKICAgIH07CgogICAgLy8gcmFkaXgtNAogICAgLy8KICAgIC8vIE5PVEU6IE9ubHkgY2FsbGVkIGZvciBsZW49OAogICAgRkZULnByb3RvdHlwZS5fc2luZ2xlUmVhbFRyYW5zZm9ybTQgPSBmdW5jdGlvbiBfc2luZ2xlUmVhbFRyYW5zZm9ybTQob3V0T2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcCkgewogICAgICBjb25zdCBvdXQgPSB0aGlzLl9vdXQ7CiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9kYXRhOwogICAgICBjb25zdCBpbnYgPSB0aGlzLl9pbnYgPyAtMSA6IDE7CiAgICAgIGNvbnN0IHN0ZXAyID0gc3RlcCAqIDI7CiAgICAgIGNvbnN0IHN0ZXAzID0gc3RlcCAqIDM7CgogICAgICAvLyBPcmlnaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgQXIgPSBkYXRhW29mZl07CiAgICAgIGNvbnN0IEJyID0gZGF0YVtvZmYgKyBzdGVwXTsKICAgICAgY29uc3QgQ3IgPSBkYXRhW29mZiArIHN0ZXAyXTsKICAgICAgY29uc3QgRHIgPSBkYXRhW29mZiArIHN0ZXAzXTsKCiAgICAgIC8vIFByZS1GaW5hbCB2YWx1ZXMKICAgICAgY29uc3QgVDByID0gQXIgKyBDcjsKICAgICAgY29uc3QgVDFyID0gQXIgLSBDcjsKICAgICAgY29uc3QgVDJyID0gQnIgKyBEcjsKICAgICAgY29uc3QgVDNyID0gaW52ICogKEJyIC0gRHIpOwoKICAgICAgLy8gRmluYWwgdmFsdWVzCiAgICAgIGNvbnN0IEZBciA9IFQwciArIFQycjsKCiAgICAgIGNvbnN0IEZCciA9IFQxcjsKICAgICAgY29uc3QgRkJpID0gLVQzcjsKCiAgICAgIGNvbnN0IEZDciA9IFQwciAtIFQycjsKCiAgICAgIGNvbnN0IEZEciA9IFQxcjsKICAgICAgY29uc3QgRkRpID0gVDNyOwoKICAgICAgb3V0W291dE9mZl0gPSBGQXI7CiAgICAgIG91dFtvdXRPZmYgKyAxXSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyAyXSA9IEZCcjsKICAgICAgb3V0W291dE9mZiArIDNdID0gRkJpOwogICAgICBvdXRbb3V0T2ZmICsgNF0gPSBGQ3I7CiAgICAgIG91dFtvdXRPZmYgKyA1XSA9IDA7CiAgICAgIG91dFtvdXRPZmYgKyA2XSA9IEZEcjsKICAgICAgb3V0W291dE9mZiArIDddID0gRkRpOwogICAgfTsKCiAgICB2YXIgRkZUJDEgPSAvKkBfX1BVUkVfXyovZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMoZmZ0KTsKCiAgICBjb25zdCBCVUZGRVJFRF9CTE9DS19TSVpFID0gMjA0ODsKICAgIGZ1bmN0aW9uIGdlbkhhbm5XaW5kb3cobGVuZ3RoKSB7CiAgICAgICAgbGV0IHdpbiA9IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoKTsKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIHdpbltpXSA9IDAuNSAqICgxIC0gTWF0aC5jb3MoMiAqIE1hdGguUEkgKiBpIC8gbGVuZ3RoKSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB3aW47CiAgICB9CiAgICBjbGFzcyBQaGFzZVZvY29kZXJQcm9jZXNzb3IgZXh0ZW5kcyBPTEFQcm9jZXNzb3IgewogICAgICAgIGZmdFNpemU7CiAgICAgICAgdGltZUN1cnNvcjsKICAgICAgICBoYW5uV2luZG93OwogICAgICAgIGZmdDsKICAgICAgICBmcmVxQ29tcGxleEJ1ZmZlcjsKICAgICAgICBmcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQ7CiAgICAgICAgdGltZUNvbXBsZXhCdWZmZXI7CiAgICAgICAgbWFnbml0dWRlczsKICAgICAgICBwZWFrSW5kZXhlczsKICAgICAgICBuYlBlYWtzOwogICAgICAgIHN0YXRpYyBnZXQgcGFyYW1ldGVyRGVzY3JpcHRvcnMoKSB7CiAgICAgICAgICAgIHJldHVybiBbewogICAgICAgICAgICAgICAgICAgIG5hbWU6ICdwaXRjaEZhY3RvcicsCiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdFZhbHVlOiAxLjAKICAgICAgICAgICAgICAgIH1dOwogICAgICAgIH0KICAgICAgICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7CiAgICAgICAgICAgIG9wdGlvbnMucHJvY2Vzc29yT3B0aW9ucyA9IHsKICAgICAgICAgICAgICAgIGJsb2NrU2l6ZTogQlVGRkVSRURfQkxPQ0tfU0laRSwKICAgICAgICAgICAgfTsKICAgICAgICAgICAgc3VwZXIob3B0aW9ucyk7CiAgICAgICAgICAgIHRoaXMuZmZ0U2l6ZSA9IHRoaXMuYmxvY2tTaXplOwogICAgICAgICAgICB0aGlzLnRpbWVDdXJzb3IgPSAwOwogICAgICAgICAgICB0aGlzLmhhbm5XaW5kb3cgPSBnZW5IYW5uV2luZG93KHRoaXMuYmxvY2tTaXplKTsKICAgICAgICAgICAgLy8gcHJlcGFyZSBGRlQgYW5kIHByZS1hbGxvY2F0ZSBidWZmZXJzCiAgICAgICAgICAgIHRoaXMuZmZ0ID0gbmV3IEZGVCQxKHRoaXMuZmZ0U2l6ZSk7CiAgICAgICAgICAgIHRoaXMuZnJlcUNvbXBsZXhCdWZmZXIgPSB0aGlzLmZmdC5jcmVhdGVDb21wbGV4QXJyYXkoKTsKICAgICAgICAgICAgdGhpcy5mcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQgPSB0aGlzLmZmdC5jcmVhdGVDb21wbGV4QXJyYXkoKTsKICAgICAgICAgICAgdGhpcy50aW1lQ29tcGxleEJ1ZmZlciA9IHRoaXMuZmZ0LmNyZWF0ZUNvbXBsZXhBcnJheSgpOwogICAgICAgICAgICB0aGlzLm1hZ25pdHVkZXMgPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuZmZ0U2l6ZSAvIDIgKyAxKTsKICAgICAgICAgICAgdGhpcy5wZWFrSW5kZXhlcyA9IG5ldyBJbnQzMkFycmF5KHRoaXMubWFnbml0dWRlcy5sZW5ndGgpOwogICAgICAgICAgICB0aGlzLm5iUGVha3MgPSAwOwogICAgICAgIH0KICAgICAgICBwcm9jZXNzT0xBKGlucHV0cywgb3V0cHV0cywgcGFyYW1ldGVycykgewogICAgICAgICAgICAvLyBAdHMtaWdub3JlCiAgICAgICAgICAgIGNvbnN0IHBpdGNoRmFjdG9yID0gcGFyYW1ldGVycy5waXRjaEZhY3RvcltwYXJhbWV0ZXJzLnBpdGNoRmFjdG9yLmxlbmd0aCAtIDFdOwogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubmJJbnB1dHM7IGkrKykgewogICAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBpbnB1dHNbaV0ubGVuZ3RoOyBqKyspIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaW5wdXQgPSBpbnB1dHNbaV1bal07CiAgICAgICAgICAgICAgICAgICAgdmFyIG91dHB1dCA9IG91dHB1dHNbaV1bal07CiAgICAgICAgICAgICAgICAgICAgdGhpcy5hcHBseUhhbm5XaW5kb3coaW5wdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZmZ0LnJlYWxUcmFuc2Zvcm0odGhpcy5mcmVxQ29tcGxleEJ1ZmZlciwgaW5wdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuY29tcHV0ZU1hZ25pdHVkZXMoKTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbmRQZWFrcygpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuc2hpZnRQZWFrcyhwaXRjaEZhY3Rvcik7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuY29tcGxldGVTcGVjdHJ1bSh0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZCk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuaW52ZXJzZVRyYW5zZm9ybSh0aGlzLnRpbWVDb21wbGV4QnVmZmVyLCB0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZCk7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5mZnQuZnJvbUNvbXBsZXhBcnJheSh0aGlzLnRpbWVDb21wbGV4QnVmZmVyLCBvdXRwdXQpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuYXBwbHlIYW5uV2luZG93KG91dHB1dCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy50aW1lQ3Vyc29yICs9IHRoaXMuaG9wU2l6ZTsKICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQogICAgICAgIGFwcGx5SGFubldpbmRvdyhpbnB1dCkgewogICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuYmxvY2tTaXplOyBpKyspIHsKICAgICAgICAgICAgICAgIGlucHV0W2ldICo9IHRoaXMuaGFubldpbmRvd1tpXTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb21wdXRlTWFnbml0dWRlcygpIHsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDAsIGogPSAwOyBpIDwgdGhpcy5tYWduaXR1ZGVzLmxlbmd0aDsgaSsrLCBqICs9IDIpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHJlYWwgPSB0aGlzLmZyZXFDb21wbGV4QnVmZmVyW2pdOwogICAgICAgICAgICAgICAgY29uc3QgaW1hZyA9IHRoaXMuZnJlcUNvbXBsZXhCdWZmZXJbaiArIDFdOwogICAgICAgICAgICAgICAgdGhpcy5tYWduaXR1ZGVzW2ldID0gcmVhbCAqKiAyICsgaW1hZyAqKiAyOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGZpbmRQZWFrcygpIHsKICAgICAgICAgICAgdGhpcy5uYlBlYWtzID0gMDsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDIsIGVuZCA9IHRoaXMubWFnbml0dWRlcy5sZW5ndGggLSAyOyBpIDwgZW5kOyBpKyspIHsKICAgICAgICAgICAgICAgIGNvbnN0IG1hZyA9IHRoaXMubWFnbml0dWRlc1tpXTsKICAgICAgICAgICAgICAgIGlmICh0aGlzLm1hZ25pdHVkZXNbaSAtIDFdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSAtIDJdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSArIDFdID49IG1hZyB8fCB0aGlzLm1hZ25pdHVkZXNbaSArIDJdID49IG1hZykgewogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdGhpcy5wZWFrSW5kZXhlc1t0aGlzLm5iUGVha3MrK10gPSBpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHNoaWZ0UGVha3MocGl0Y2hGYWN0b3IpIHsKICAgICAgICAgICAgdGhpcy5mcmVxQ29tcGxleEJ1ZmZlclNoaWZ0ZWQuZmlsbCgwKTsKICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm5iUGVha3M7IGkrKykgewogICAgICAgICAgICAgICAgY29uc3QgcGVha0luZGV4ID0gdGhpcy5wZWFrSW5kZXhlc1tpXTsKICAgICAgICAgICAgICAgIGNvbnN0IHBlYWtJbmRleFNoaWZ0ZWQgPSBNYXRoLnJvdW5kKHBlYWtJbmRleCAqIHBpdGNoRmFjdG9yKTsKICAgICAgICAgICAgICAgIGlmIChwZWFrSW5kZXhTaGlmdGVkID4gdGhpcy5tYWduaXR1ZGVzLmxlbmd0aCkgewogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgbGV0IHN0YXJ0SW5kZXggPSAoaSA+IDApID8gcGVha0luZGV4IC0gTWF0aC5mbG9vcigocGVha0luZGV4IC0gdGhpcy5wZWFrSW5kZXhlc1tpIC0gMV0pIC8gMikgOiAwOwogICAgICAgICAgICAgICAgbGV0IGVuZEluZGV4ID0gKGkgPCB0aGlzLm5iUGVha3MgLSAxKSA/IHBlYWtJbmRleCArIE1hdGguY2VpbCgodGhpcy5wZWFrSW5kZXhlc1tpICsgMV0gLSBwZWFrSW5kZXgpIC8gMikgOiB0aGlzLmZmdFNpemU7CiAgICAgICAgICAgICAgICBmb3IgKGxldCBqID0gc3RhcnRJbmRleCAtIHBlYWtJbmRleDsgaiA8IGVuZEluZGV4IC0gcGVha0luZGV4OyBqKyspIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBiaW5JbmRleCA9IHBlYWtJbmRleCArIGo7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgYmluSW5kZXhTaGlmdGVkID0gcGVha0luZGV4U2hpZnRlZCArIGo7CiAgICAgICAgICAgICAgICAgICAgaWYgKGJpbkluZGV4U2hpZnRlZCA+PSB0aGlzLm1hZ25pdHVkZXMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBjb25zdCBvbWVnYURlbHRhID0gMiAqIE1hdGguUEkgKiAoYmluSW5kZXhTaGlmdGVkIC0gYmluSW5kZXgpIC8gdGhpcy5mZnRTaXplOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHBoYXNlU2hpZnRSZWFsID0gTWF0aC5jb3Mob21lZ2FEZWx0YSAqIHRoaXMudGltZUN1cnNvcik7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGhhc2VTaGlmdEltYWcgPSBNYXRoLnNpbihvbWVnYURlbHRhICogdGhpcy50aW1lQ3Vyc29yKTsKICAgICAgICAgICAgICAgICAgICBjb25zdCBpbmRleFJlYWwgPSBiaW5JbmRleCAqIDI7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5kZXhJbWFnID0gaW5kZXhSZWFsICsgMTsKICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZVJlYWwgPSB0aGlzLmZyZXFDb21wbGV4QnVmZmVyW2luZGV4UmVhbF07CiAgICAgICAgICAgICAgICAgICAgY29uc3QgdmFsdWVJbWFnID0gdGhpcy5mcmVxQ29tcGxleEJ1ZmZlcltpbmRleEltYWddOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlU2hpZnRlZFJlYWwgPSB2YWx1ZVJlYWwgKiBwaGFzZVNoaWZ0UmVhbCAtIHZhbHVlSW1hZyAqIHBoYXNlU2hpZnRJbWFnOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlU2hpZnRlZEltYWcgPSB2YWx1ZVJlYWwgKiBwaGFzZVNoaWZ0SW1hZyArIHZhbHVlSW1hZyAqIHBoYXNlU2hpZnRSZWFsOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4U2hpZnRlZFJlYWwgPSBiaW5JbmRleFNoaWZ0ZWQgKiAyOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4U2hpZnRlZEltYWcgPSBpbmRleFNoaWZ0ZWRSZWFsICsgMTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmZyZXFDb21wbGV4QnVmZmVyU2hpZnRlZFtpbmRleFNoaWZ0ZWRSZWFsXSArPSB2YWx1ZVNoaWZ0ZWRSZWFsOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZnJlcUNvbXBsZXhCdWZmZXJTaGlmdGVkW2luZGV4U2hpZnRlZEltYWddICs9IHZhbHVlU2hpZnRlZEltYWc7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICAvLyBAdHMtaWdub3JlCiAgICByZWdpc3RlclByb2Nlc3NvcigicGhhc2Utdm9jb2RlciIsIFBoYXNlVm9jb2RlclByb2Nlc3Nvcik7CiAgICBjb25zb2xlLmxvZygiUGhhc2VWb2NvZGVyUHJvY2Vzc29yIHJlZ2lzdGVyZWQiKTsKCiAgICBleHBvcnRzLlBoYXNlVm9jb2RlclByb2Nlc3NvciA9IFBoYXNlVm9jb2RlclByb2Nlc3NvcjsKCiAgICByZXR1cm4gZXhwb3J0czsKCn0pKHt9KTsK\"","import { IAudioContext } from \"standardized-audio-context\";\n\nexport class CacheManager {\n private static pendingRequests = new Map<string, Promise<AudioBuffer>>();\n\n private static async openCache(): Promise<Cache> {\n try {\n return await caches.open('audio-cache');\n } catch (error) {\n console.error('Failed to open cache:', error);\n throw error;\n }\n }\n\n private static async getAudioBufferFromCache(url: string, cache: Cache, context: IAudioContext): Promise<AudioBuffer | null> {\n try {\n const response = await cache.match(url);\n if (response) {\n const arrayBuffer = await response.arrayBuffer();\n return context.decodeAudioData(arrayBuffer);\n }\n return null;\n } catch (error) {\n console.error('Failed to get audio data from cache:', error);\n throw error;\n }\n }\n\n private static async fetchAndCacheAudioBuffer(url: string, cache: Cache, context: IAudioContext): Promise<AudioBuffer> {\n try {\n const fetchResponse = await fetch(url);\n const responseClone = fetchResponse.clone();\n cache.put(url, responseClone);\n const arrayBuffer = await fetchResponse.arrayBuffer();\n return context.decodeAudioData(arrayBuffer);\n } catch (error) {\n console.error('Failed to fetch and cache audio data:', error);\n throw error;\n }\n }\n\n public static async getAudioBuffer(url: string, context: IAudioContext): Promise<AudioBuffer> {\n // handle data: urls\n if (url.startsWith('data:')) {\n // Extract the base64-encoded audio data from the url.\n const base64Data = url.split(',')[1];\n const buffer = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));\n return context.decodeAudioData(buffer.buffer);\n }\n\n const cache = await this.openCache();\n\n // First, check if there's a pending request.\n let pendingRequest = this.pendingRequests.get(url);\n if (pendingRequest) {\n return pendingRequest;\n }\n\n // Try getting the buffer from cache.\n const bufferFromCache = await this.getAudioBufferFromCache(url, cache, context);\n if (bufferFromCache) {\n return bufferFromCache;\n }\n\n // If it's not in the cache, fetch and cache it.\n pendingRequest = this.fetchAndCacheAudioBuffer(url, cache, context);\n this.pendingRequests.set(url, pendingRequest);\n\n return pendingRequest;\n }\n}\n","import { BiquadFilterNode } from './context'\n\nexport abstract class FilterManager {\n protected filters: BiquadFilterNode[] = [];\n\n addFilter(filter: BiquadFilterNode) {\n this.filters.push(filter);\n }\n\n removeFilter(filter: BiquadFilterNode) {\n this.filters = this.filters.filter(f => f !== filter);\n }\n\n applyFilters(connection: any): any {\n this.filters.reduce((prevConnection, filter) => {\n prevConnection.connect(filter);\n return filter;\n }, connection);\n return this.filters.length > 0 ? this.filters[this.filters.length - 1] : connection;\n }\n}\n\n","import { BaseSound, LoopCount, Position } from './cacophony';\n\nimport { BiquadFilterNode } from './context';\nimport { Playback } from './playback';\nimport { Sound } from './sound';\n\n\nexport class Group implements BaseSound {\n sounds: Sound[] = [];\n private _position: Position = [0, 0, 0];\n loopCount: LoopCount = 0;\n private playIndex: number = 0;\n\n playRandom(): Playback {\n if (this.sounds.length === 0) {\n throw new Error('Cannot play a random sound from an empty group');\n }\n const randomIndex = Math.floor(Math.random() * this.sounds.length);\n const randomSound = this.sounds[randomIndex] as Sound;\n const playback = randomSound.preplay();\n playback.forEach(p => p.play());\n return playback[0];\n }\n\n playOrdered(shouldLoop: boolean = true): Playback {\n if (this.sounds.length === 0) {\n throw new Error('Cannot play an ordered sound from an empty group');\n }\n const sound = this.sounds[this.playIndex] as Sound;\n const playback = sound.preplay();\n playback.forEach(p => p.play());\n this.playIndex++;\n if (this.playIndex >= this.sounds.length) {\n if (shouldLoop) {\n this.playIndex = 0;\n } else {\n this.playIndex = this.sounds.length; // Set to length to indicate end of list\n }\n }\n return playback[0];\n }\n\n get duration() {\n return this.sounds.map(sound => sound.duration).reduce((a, b) => Math.max(a, b), 0);\n }\n\n seek(time: number): void {\n this.sounds.forEach(sound => sound.seek && sound.seek(time));\n }\n\n addSound(sound: Sound): void {\n this.sounds.push(sound);\n }\n\n preplay(): Playback[] {\n return (this.sounds as Sound[]).reduce<Playback[]>((playbacks, sound) => {\n sound.loop && sound.loop(this.loopCount);\n return playbacks.concat(sound.preplay());\n }, []);\n }\n\n play(): Playback[] {\n return this.preplay().map(playback => {\n playback.play();\n return playback;\n });\n }\n\n /**\n * Returns a boolean indicating whether the sound is currently playing.\n * @returns {boolean} True if the sound is playing, false otherwise.\n */\n isPlaying(): boolean {\n return this.sounds.some(sound => sound.isPlaying());\n }\n\n stop(): void {\n this.sounds.forEach(sound => sound.stop());\n }\n\n pause(): void {\n this.sounds.forEach(sound => sound.pause());\n }\n\n resume(): void {\n this.sounds.forEach(sound => sound.resume());\n }\n\n loop(loopCount?: LoopCount): LoopCount {\n if (loopCount === undefined) {\n return this.loopCount;\n }\n this.loopCount = loopCount;\n this.sounds.forEach(sound => sound.loop && sound.loop(loopCount));\n return this.loopCount;\n }\n\n addFilter(filter: BiquadFilterNode): void {\n this.sounds.forEach(sound => sound.addFilter(filter));\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n this.sounds.forEach(sound => sound.removeFilter(filter));\n }\n\n set position(position: [number, number, number]) {\n this._position = position;\n this.sounds.forEach(sound => sound.position = this._position);\n }\n\n get position(): [number, number, number] {\n return this._position;\n }\n\n get volume(): number {\n return this.sounds.map(sound => sound.volume).reduce((a, b) => a + b, 0) / this.sounds.length;\n }\n\n set volume(volume: number) {\n this.sounds.forEach(sound => sound.volume = volume);\n }\n\n get playbackRate(): number {\n if (this.sounds.length === 0) {\n return 1;\n }\n return this.sounds[0].playbackRate;\n }\n\n set playbackRate(rate: number) {\n this.sounds.forEach(sound => sound.playbackRate = rate);\n }\n\n\n}\n","/**\n * The Playback class encapsulates the functionality for playing audio in a web application.\n * It integrates with the standardized-audio-context library to provide a cross-browser way to handle audio.\n * This class allows for the manipulation of audio playback through various features such as:\n * - Playing and stopping audio\n * - Looping audio a specific number of times or infinitely\n * - Adjusting volume and playback rate\n * - Applying stereo or 3D (HRTF) panning\n * - Adding and removing filters to modify the audio output\n * - Handling audio looping with custom logic\n * - Fading audio in and out linearly or exponentially\n * - Seeking to specific points in the audio\n * - Checking if the audio is currently playing\n * - Cleaning up resources when the audio is no longer needed\n * \n * The class is designed to be flexible and can be used with different types of audio sources,\n * including buffer sources and media elements. It also provides detailed control over the audio's\n * spatial characteristics when using 3D audio.\n */\n\n\nimport { BaseSound, FadeType, LoopCount, PanType, Position } from \"./cacophony\";\nimport type { AudioBuffer, AudioBufferSourceNode, AudioContext, BiquadFilterNode, GainNode, IPannerOptions, PannerNode, SourceNode, StereoPannerNode } from \"./context\";\nimport { FilterManager } from \"./filters\";\n\n\n\nexport class Playback extends FilterManager implements BaseSound {\n private context: AudioContext;\n private source?: SourceNode;\n private gainNode?: GainNode;\n private panner?: PannerNode | StereoPannerNode;\n loopCount: LoopCount = 0;\n currentLoop: number = 0;\n private buffer?: AudioBuffer;\n private playing: boolean = false;\n\n /**\n * Creates an instance of the Playback class.\n * @param {SourceNode} source - The audio source node.\n * @param {GainNode} gainNode - The gain node for controlling volume.\n * @param {AudioContext} context - The audio context.\n * @param {LoopCount} loopCount - The number of times the audio should loop. 'infinite' for endless looping.\n * @param {PanType} panType - The type of panning to use ('HRTF' for 3D audio or 'stereo' for stereo panning).\n * @throws {Error} Throws an error if an invalid pan type is provided.\n */\n constructor(source: SourceNode, gainNode: GainNode, context: AudioContext, loopCount: LoopCount = 0, public panType: PanType = 'HRTF') {\n super();\n this.loopCount = loopCount;\n this.panType = panType;\n this.source = source;\n if ('buffer' in source && source.buffer) {\n this.buffer = source.buffer;\n }\n if ('mediaElement' in source && source.mediaElement) {\n source.mediaElement.onended = this.handleLoop.bind(this);\n } else if ('onended' in source) {\n source.onended = this.handleLoop.bind(this);\n }\n this.gainNode = gainNode;\n this.context = context;\n if (this.panType === 'HRTF') {\n this.panner = context.createPanner();\n } else if (this.panType === 'stereo') {\n this.panner = context.createStereoPanner();\n } else {\n throw new Error('Invalid pan type');\n }\n source.connect(this.panner);\n this.panner.connect(this.gainNode);\n this.refreshFilters();\n }\n\n /**\n * Gets the stereo panning value.\n * @returns {number | null} The current stereo pan value, or null if stereo panning is not applicable.\n * @throws {Error} Throws an error if stereo panning is not available or if the sound has been cleaned up.\n */\n get stereoPan(): number | null {\n if (this.panType === 'stereo') {\n return (this.panner as StereoPannerNode).pan.value;\n }\n return null;\n }\n\n /**\n * Sets the stereo panning value.\n * @param {number} value - The stereo pan value to set, between -1 (left) and 1 (right).\n * @throws {Error} Throws an error if stereo panning is not available, if the sound has been cleaned up, or if the value is out of bounds.\n */\n set stereoPan(value: number) {\n if (this.panType !== 'stereo') {\n throw new Error('Stereo panning is not available when using HRTF.');\n }\n if (!this.panner) {\n throw new Error('Cannot set stereo pan of a sound that has been cleaned up');\n }\n (this.panner as StereoPannerNode).pan.setValueAtTime(clamp(value, -1, 1), this.context.currentTime);\n }\n\n /**\n * Gets the duration of the audio in seconds.\n * @returns {number} The duration of the audio.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n get duration() {\n if (!this.buffer) {\n throw new Error('Cannot get duration of a sound that has been cleaned up');\n }\n return this.buffer.duration;\n }\n\n /**\n * Gets the current playback rate of the audio.\n * @returns {number} The current playback rate.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n get playbackRate() {\n if (!this.source) {\n throw new Error('Cannot get playback rate of a sound that has been cleaned up');\n }\n if ('playbackRate' in this.source) {\n return this.source.playbackRate.value;\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n return this.source.mediaElement.playbackRate;\n }\n throw new Error('Unsupported source type');\n }\n\n /**\n * Sets the playback rate of the audio.\n * @param {number} rate - The playback rate to set.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n set playbackRate(rate: number) {\n if (!this.source) {\n throw new Error('Cannot set playback rate of a sound that has been cleaned up');\n }\n if ('playbackRate' in this.source) {\n this.source.playbackRate.value = rate;\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.playbackRate = rate;\n }\n }\n\n /**\n * Handles the loop event when the audio ends.\n * This method is bound to the 'onended' event of the audio source.\n * It manages looping logic and restarts playback if necessary.\n */\n handleLoop = () => {\n if (this.buffer) {\n this.source = this.context.createBufferSource();\n this.source.buffer = this.buffer;\n } else {\n this.seek(0);\n }\n if (this.loopCount === 'infinite' || this.currentLoop < this.loopCount) {\n this.currentLoop++;\n if (this.playing) {\n this.play();\n }\n } else {\n this.playing = false;\n }\n }\n\n /**\n * Starts playing the audio.\n * @returns {[this]} Returns the instance of the Playback class for chaining.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n play(): [this] {\n if (!this.source) {\n throw new Error('Cannot play a sound that has been cleaned up');\n }\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.play();\n } else if ('start' in this.source && this.source.start) {\n this.source.start();\n }\n this.playing = true;\n return [this];\n }\n\n /**\n * Gets the 3D audio options if HRTF panning is used.\n * @returns {IPannerOptions} The current 3D audio options.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n get threeDOptions(): IPannerOptions {\n if (!this.panner) {\n throw new Error('Cannot get 3D options of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot get 3D options of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n return {\n coneInnerAngle: panner.coneInnerAngle,\n coneOuterAngle: panner.coneOuterAngle,\n coneOuterGain: panner.coneOuterGain,\n distanceModel: panner.distanceModel,\n maxDistance: panner.maxDistance,\n channelCount: this.panner.channelCount,\n channelCountMode: panner.channelCountMode,\n channelInterpretation: panner.channelInterpretation,\n panningModel: panner.panningModel,\n refDistance: panner.refDistance,\n rolloffFactor: panner.rolloffFactor,\n positionX: panner.positionX.value,\n positionY: panner.positionY.value,\n positionZ: panner.positionZ.value,\n orientationX: panner.orientationX.value,\n orientationY: panner.orientationY.value,\n orientationZ: panner.orientationZ.value\n }\n }\n\n /**\n * Sets the 3D audio options for HRTF panning.\n * @param {Partial<IPannerOptions>} options - The 3D audio options to set.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n set threeDOptions(options: Partial<IPannerOptions>) {\n if (!this.panner) {\n throw new Error('Cannot set 3D options of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot set 3D options of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n panner.coneInnerAngle = options.coneInnerAngle || panner.coneInnerAngle;\n panner.coneOuterAngle = options.coneOuterAngle || panner.coneOuterAngle;\n panner.coneOuterGain = options.coneOuterGain || panner.coneOuterGain;\n panner.distanceModel = options.distanceModel || panner.distanceModel;\n panner.maxDistance = options.maxDistance || panner.maxDistance;\n panner.channelCount = options.channelCount || panner.channelCount;\n panner.channelCountMode = options.channelCountMode || panner.channelCountMode;\n panner.channelInterpretation = options.channelInterpretation || panner.channelInterpretation;\n panner.panningModel = options.panningModel || panner.panningModel;\n panner.refDistance = options.refDistance || panner.refDistance;\n panner.rolloffFactor = options.rolloffFactor || panner.rolloffFactor;\n panner.positionX.value = options.positionX || panner.positionX.value;\n panner.positionY.value = options.positionY || panner.positionY.value;\n panner.positionZ.value = options.positionZ || panner.positionZ.value;\n panner.orientationX.value = options.orientationX || panner.orientationX.value;\n panner.orientationY.value = options.orientationY || panner.orientationY.value;\n panner.orientationZ.value = options.orientationZ || panner.orientationZ.value;\n }\n\n /**\n * Seeks to a specific time in the audio.\n * @param {number} time - The time in seconds to seek to.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n seek(time: number): void {\n if (!this.source || !this.gainNode || !this.panner) {\n throw new Error('Cannot seek a sound that has been cleaned up');\n }\n const playing = this.isPlaying();\n this.stop();\n if ('mediaElement' in this.source && this.source.mediaElement) {\n this.source.mediaElement.currentTime = time;\n if (playing) {\n this.source.mediaElement.play();\n }\n } else if (this.buffer) {\n // Create a new source to start from the desired time\n this.source = this.context.createBufferSource();\n this.source.buffer = this.buffer;\n this.refreshFilters();\n this.source.connect(this.panner).connect(this.gainNode);\n if (playing) {\n this.source.start(0, time);\n }\n } else {\n throw new Error('Unsupported source type for seeking');\n }\n }\n\n /**\n * Gets the current volume of the audio.\n * @returns {number} The current volume.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n get volume(): number {\n if (!this.gainNode) {\n throw new Error('Cannot get volume of a sound that has been cleaned up');\n }\n return this.gainNode.gain.value;\n }\n\n /**\n * Sets the volume of the audio.\n * @param {number} v - The volume to set.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n set volume(v: number) {\n if (!this.gainNode) {\n throw new Error('Cannot set volume of a sound that has been cleaned up');\n }\n this.gainNode.gain.value = v;\n }\n\n /**\n * Sets whether the audio source should loop.\n * @param {boolean} loop - Whether the audio should loop.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n set sourceLoop(loop: boolean) {\n if (!this.source) {\n throw new Error('Cannot set loop on a sound that has been cleaned up');\n }\n if ('loop' in this.source) {\n this.source.loop = loop;\n }\n if (\"mediaElement\" in this.source && this.source.mediaElement) {\n this.source.mediaElement.loop = loop;\n }\n }\n\n /**\n * Gradually increases the volume of the sound from silence to its current volume level over the specified duration.\n * @param {number} time - The duration in seconds over which the volume will increase.\n * @param {FadeType} fadeType - The type of fade curve to apply, either 'linear' or 'exponential'.\n * @returns {Promise<void>} A promise that resolves when the fade-in effect is complete.\n */\n /**\n * Fades in the audio from silence to its current volume level over a specified duration.\n * @param {number} time - The duration in seconds for the fade-in.\n * @param {FadeType} fadeType - The type of fade curve ('linear' or 'exponential').\n * @returns {Promise<void>} A promise that resolves when the fade-in is complete.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n fadeIn(time: number, fadeType: FadeType = 'linear'): Promise<void> {\n return new Promise(resolve => {\n if (!this.gainNode) {\n throw new Error('Cannot fade in a sound that has been cleaned up');\n }\n\n const initialVolume = this.gainNode.gain.value;\n const targetVolume = 1; // Assuming the target volume after fade-in is 1 (full volume)\n\n // Reset volume to 0 to start the fade-in process\n this.gainNode.gain.value = 0;\n\n switch (fadeType) {\n case 'exponential':\n // Start at a low value (0.01) because exponentialRampToValueAtTime cannot ramp from 0\n this.gainNode.gain.setValueAtTime(0.01, this.context.currentTime);\n this.gainNode.gain.exponentialRampToValueAtTime(targetVolume, this.context.currentTime + time);\n break;\n case 'linear':\n this.gainNode.gain.linearRampToValueAtTime(targetVolume, this.context.currentTime + time);\n break;\n }\n\n // Resolve the Promise after the fade-in time\n setTimeout(() => {\n // Ensure the final volume is set to the target volume\n if (!this.gainNode) {\n throw new Error('Cannot fade in a sound that has been cleaned up');\n }\n this.gainNode.gain.value = targetVolume;\n resolve();\n }, time * 1000);\n });\n }\n\n /**\n * Gradually decreases the volume of the sound from its current volume level to silence over the specified duration.\n * @param {number} time - The duration in seconds over which the volume will decrease.\n * @param {FadeType} fadeType - The type of fade curve to apply, either 'linear' or 'exponential'.\n * @returns {Promise<void>} A promise that resolves when the fade-out effect is complete.\n */\n /**\n * Fades out the audio to silence over a specified duration.\n * @param {number} time - The duration in seconds for the fade-out.\n * @param {FadeType} fadeType - The type of fade curve ('linear' or 'exponential').\n * @returns {Promise<void>} A promise that resolves when the fade-out is complete.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n fadeOut(time: number, fadeType: FadeType = 'linear'): Promise<void> {\n return new Promise(resolve => {\n // Storing the current gain value\n if (!this.gainNode) {\n throw new Error('Cannot fade out a sound that has been cleaned up');\n }\n const initialVolume = this.gainNode.gain.value;\n switch (fadeType) {\n case 'exponential':\n // Scheduling an exponential fade down\n this.gainNode.gain.exponentialRampToValueAtTime(0.01, this.context.currentTime + time);\n break;\n case 'linear':\n\n // Scheduling a linear ramp to 0 over the given duration\n this.gainNode.gain.linearRampToValueAtTime(0, this.context.currentTime + time);\n }\n // Resolving the Promise after the fade-out time\n setTimeout(() => resolve(), time * 1000);\n });\n }\n\n /**\n * Returns a boolean indicating whether the sound is currently playing.\n * @returns {boolean} True if the sound is playing, false otherwise.\n */\n /**\n * Checks if the audio is currently playing.\n * @returns {boolean} True if the audio is playing, false otherwise.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n isPlaying(): boolean {\n if (!this.source) {\n throw new Error('Cannot check if a sound is playing that has been cleaned up');\n }\n return this.playing;\n }\n\n /**\n * Cleans up resources used by the Playback instance.\n * This method should be called when the audio is no longer needed to free up resources.\n */\n cleanup(): void {\n // Ensure cleanup is idempotent\n if (this.source) {\n this.source.disconnect();\n this.source = undefined;\n }\n if (this.gainNode) {\n this.gainNode.disconnect();\n this.gainNode = undefined;\n }\n this.filters.forEach(filter => {\n if (filter) {\n filter.disconnect();\n }\n });\n this.filters = [];\n // Additional cleanup logic if needed\n }\n\n /**\n * Sets or gets the loop count for the audio.\n * @param {LoopCount} loopCount - The number of times the audio should loop. 'infinite' for endless looping.\n * @returns {LoopCount} The loop count if no parameter is provided.\n * @throws {Error} Throws an error if the sound has been cleaned up or if the source type is unsupported.\n */\n loop(loopCount?: LoopCount): LoopCount {\n if (!this.source) {\n throw new Error('Cannot loop a sound that has been cleaned up');\n }\n if (this.source instanceof AudioBufferSourceNode) {\n if (loopCount === undefined) {\n return this.source.loop === true ? 'infinite' : 0;\n }\n this.source.loop = true;\n this.source.loopEnd = this.source.buffer?.duration || 0;\n this.source.loopStart = 0;\n return this.source.loop === true ? 'infinite' : 0;\n }\n // Check if the source is a MediaElementSourceNode\n if (\"mediaElement\" in this.source && this.source.mediaElement) {\n const mediaElement = this.source.mediaElement;\n if (loopCount === undefined) {\n return mediaElement.loop === true ? 'infinite' : 0;\n }\n mediaElement.loop = true;\n // Looping for HTMLMediaElement is controlled by the 'loop' attribute, no need for loopStart or loopEnd\n return mediaElement.loop === true ? 'infinite' : 0;\n }\n\n throw new Error('Unsupported source type');\n }\n\n /**\n * Stops the audio playback immediately.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n stop(): void {\n if (!this.source) {\n throw new Error('Cannot stop a sound that has been cleaned up');\n }\n if (!this.isPlaying()) {\n return;\n }\n if ('stop' in this.source) {\n this.source.stop();\n }\n if (\"mediaElement\" in this.source && this.source.mediaElement) {\n this.source.mediaElement.pause();\n this.source.mediaElement.currentTime = 0;\n }\n this.playing = false;\n }\n\n /**\n * Pauses the audio playback.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n pause(): void {\n if (!this.source) {\n throw new Error('Cannot pause a sound that has been cleaned up');\n }\n if ('suspend' in this.source.context) {\n this.source.context.suspend();\n }\n }\n\n /**\n * Resumes the audio playback if it was previously paused.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n resume(): void {\n if (!this.source) {\n throw new Error('Cannot resume a sound that has been cleaned up');\n }\n if ('resume' in this.source.context) {\n this.source.context.resume();\n }\n }\n\n /**\n * Adds a filter to the audio signal chain.\n * @param {BiquadFilterNode} filter - The filter to add.\n */\n addFilter(filter: BiquadFilterNode): void {\n super.addFilter(filter);\n this.refreshFilters();\n }\n\n /**\n * Removes a filter from the audio signal chain.\n * @param {BiquadFilterNode} filter - The filter to remove.\n */\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.refreshFilters();\n }\n\n /**\n * Sets the position of the audio source in 3D space (HRTF panning only).\n * @param {Position} position - The [x, y, z] coordinates of the audio source.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n\n set position(position: Position) {\n if (!this.panner) {\n throw new Error('Cannot move a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot move a sound that is not using HRTF');\n }\n const [x, y, z] = position;\n const panner = this.panner as PannerNode;\n panner.positionX.value = x;\n panner.positionY.value = y;\n panner.positionZ.value = z;\n }\n\n /**\n * Gets the position of the audio source in 3D space (HRTF panning only).\n * @returns {Position} The [x, y, z] coordinates of the audio source.\n * @throws {Error} Throws an error if the sound has been cleaned up or if HRTF panning is not used.\n */\n\n get position(): Position {\n if (!this.panner) {\n throw new Error('Cannot get position of a sound that has been cleaned up');\n }\n if (this.panType !== 'HRTF') {\n throw new Error('Cannot get position of a sound that is not using HRTF');\n }\n const panner = this.panner as PannerNode;\n return [panner.positionX.value, panner.positionY.value, panner.positionZ.value];\n }\n\n /**\n * Refreshes the audio filters by re-applying them to the audio signal chain.\n * This method is called internally whenever filters are added or removed.\n * @throws {Error} Throws an error if the sound has been cleaned up.\n */\n private refreshFilters(): void {\n if (!this.panner || !this.gainNode) {\n throw new Error('Cannot update filters on a sound that has been cleaned up');\n }\n let connection = this.panner;\n connection.disconnect();\n connection = this.applyFilters(connection);\n connection.connect(this.gainNode);\n }\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n","/**\n * The Sound class represents an audio asset within a web application, providing a high-level interface\n * for loading, manipulating, and playing audio. It supports both buffer-based and media element-based audio,\n * allowing for efficient playback and manipulation of sound resources.\n *\n * A Sound instance can manage multiple Playback instances, which represent individual playbacks of the sound.\n * This allows for the same sound to be played multiple times simultaneously or with different settings (e.g., volume,\n * playback rate, spatial positioning). The Sound class provides methods to control these playbacks collectively or individually.\n *\n * Key features include:\n * - Loading audio from a URL or using a pre-loaded buffer.\n * - Playing, pausing, resuming, and stopping audio playback.\n * - Looping audio a specific number of times or infinitely.\n * - Adjusting volume, playback rate, and spatial positioning (for 3D audio).\n * - Applying audio filters for effects like reverb, equalization, etc.\n * - Cloning the Sound instance for independent manipulation and playback.\n *\n * The relationship between Sound and Playback is central to the design of the audio system. A Sound object acts as a container\n * and manager for one or more Playback objects. Each Playback object represents a single instance of the sound being played,\n * and can be controlled individually. This architecture allows for complex audio behaviors, such as playing multiple overlapping\n * instances of a sound with different settings, without requiring the user to manually manage each playback instance.\n */\nimport { BaseSound, LoopCount, PanType, Position, SoundType } from \"./cacophony\";\nimport { BiquadFilterNode, GainNode, SourceNode, } from './context';\nimport { FilterManager } from \"./filters\";\nimport { Playback } from \"./playback\";\nimport { AudioContext, IAudioBuffer, IPannerOptions } from \"standardized-audio-context\";\n\n\nexport class Sound extends FilterManager implements BaseSound {\n buffer?: IAudioBuffer;\n context: AudioContext;\n playbacks: Playback[] = [];\n private globalGainNode: GainNode;\n private _position: Position = [0, 0, 0];\n private _stereoPan: number = 0;\n private _threeDOptions: IPannerOptions = {\n coneInnerAngle: 360,\n coneOuterAngle: 360,\n coneOuterGain: 0,\n distanceModel: 'inverse',\n maxDistance: 10000,\n channelCount: 2,\n channelCountMode: 'clamped-max',\n channelInterpretation: 'speakers',\n panningModel: 'HRTF',\n refDistance: 1,\n rolloffFactor: 1,\n positionX: 0,\n positionY: 0,\n positionZ: 0,\n orientationX: 0,\n orientationY: 0,\n orientationZ: 0\n };\n loopCount: LoopCount = 0;\n private _playbackRate: number = 1;\n private _volume: number = 1;\n\n constructor(public url: string, buffer: AudioBuffer | undefined, context: AudioContext, globalGainNode: GainNode, public type: SoundType = SoundType.Buffer, public panType: PanType = 'HRTF'\n ) {\n super();\n this.buffer = buffer;\n this.context = context;\n this.globalGainNode = globalGainNode;\n }\n\n /**\n * Creates a deep copy of the current Sound instance, including all its properties and filters.\n * The cloned sound can be played and manipulated independently of the original.\n * @returns {Sound} A new Sound instance that is a clone of the current sound.\n */\n\n clone(): Sound {\n const clone = new Sound(this.url, this.buffer, this.context, this.globalGainNode, this.type);\n clone.loopCount = this.loopCount;\n clone._playbackRate = this._playbackRate;\n clone._volume = this._volume;\n clone._position = this._position;\n clone._threeDOptions = this._threeDOptions;\n clone.filters = this.filters;\n clone.panType = this.panType;\n clone._stereoPan = this._stereoPan;\n return clone;\n }\n\n /**\n * Generates a Playback instance for the sound without starting playback.\n * This allows for pre-configuration of playback properties such as volume and position before the sound is actually played.\n * @returns {Playback[]} An array of Playback instances that are ready to be played.\n */\n\n preplay(): Playback[] {\n let source: SourceNode;\n if (this.buffer) {\n source = this.context.createBufferSource();\n source.buffer = this.buffer;\n } else {\n const audio = new Audio();\n audio.crossOrigin = 'anonymous';\n audio.src = this.url;\n audio.preload = \"auto\"\n // we have the audio, let's make a buffer source node out of it\n source = this.context.createMediaElementSource(audio);\n }\n const gainNode = this.context.createGain();\n gainNode.connect(this.globalGainNode);\n const playback = new Playback(source, gainNode, this.context, this.loopCount, this.panType);\n // this.finalizationRegistry.register(playback, playback);\n playback.volume = this.volume;\n playback.playbackRate = this.playbackRate;\n this.filters.forEach(filter => playback.addFilter(filter));\n if (this.panType === 'HRTF') {\n playback.threeDOptions = this.threeDOptions;\n playback.position = this.position;\n } else if (this.panType === 'stereo') {\n playback.stereoPan = this.stereoPan as number;\n }\n this.playbacks.push(playback);\n return [playback];\n }\n\n /**\n * Starts playback of the sound and returns a Playback instance representing this particular playback.\n * Multiple Playback instances can be created by calling this method multiple times,\n * allowing for the same sound to be played concurrently with different settings.\n * @returns {Playback[]} An array containing the Playback instances that have been started.\n */\n\n play(): Playback[] {\n const playback = this.preplay();\n playback.forEach(p => p.play());\n return playback;\n }\n\n /**\n * Stops all current playbacks of the sound immediately. This will halt the sound regardless of how many times it has been played.\n */\n\n stop() {\n this.playbacks.forEach(p => p.stop());\n }\n\n /**\n * Pauses all current playbacks of the sound.\n */\n\n pause(): void {\n this.playbacks.forEach(playback => playback.pause());\n }\n\n /**\n * Resumes all current playbacks of the sound that were previously paused.\n */\n\n resume(): void {\n this.playbacks.forEach(playback => playback.resume());\n }\n\n /**\n * Seeks to a specific time within the sound's playback.\n * @param { number } time - The time in seconds to seek to.\n * This method iterates through all active `Playback` instances and calls their `seek()` method with the specified time.\n */\n\n seek(time: number): void {\n this.playbacks.forEach(playback => playback.seek(time));\n }\n\n /**\n * Retrieves the duration of the sound in seconds.\n * If the sound is based on an AudioBuffer, it returns the duration of the buffer.\n * Otherwise, it returns 0, indicating that the duration is unknown or not applicable.\n * @returns { number } The duration of the sound in seconds.\n */\n\n get duration() {\n return this.buffer?.duration || 0;\n }\n\n /**\n * Retrieves the current 3D spatial position of the sound in the audio context.\n * The position is returned as an array of three values[x, y, z].\n * @returns { Position } The current position of the sound.\n */\n\n get position(): Position {\n return [this._threeDOptions.positionX, this._threeDOptions.positionY, this._threeDOptions.positionZ]\n }\n\n /**\n * Sets the 3D spatial position of the sound in the audio context.\n * The position is an array of three values[x, y, z].\n * This method updates the position of all active playbacks of the sound.\n * @param { Position } position - The new position of the sound.\n */\n\n set position(position: Position) {\n this._threeDOptions.positionX = position[0];\n this._threeDOptions.positionY = position[1];\n this._threeDOptions.positionZ = position[2];\n this.playbacks.forEach(p => p.position = position);\n }\n\n\n get threeDOptions(): IPannerOptions {\n return this._threeDOptions;\n }\n\n set threeDOptions(options: Partial<IPannerOptions>) {\n this._threeDOptions = { ...this._threeDOptions, ...options };\n this.playbacks.forEach(p => p.threeDOptions = this._threeDOptions);\n }\n\n get stereoPan(): number | null {\n return this._stereoPan;\n }\n\n set stereoPan(value: number) {\n this._stereoPan = value;\n this.playbacks.forEach(p => p.stereoPan = value);\n }\n\n /**\n * Sets or retrieves the loop behavior for the sound.\n * If loopCount is provided, the sound will loop the specified number of times.\n * If loopCount is 'infinite', the sound will loop indefinitely until stopped.\n * If no argument is provided, the method returns the current loop count setting.\n * @param { LoopCount } [loopCount] - The number of times to loop or 'infinite' for indefinite looping.\n * @returns { LoopCount } The current loop count setting if no argument is provided.\n */\n\n loop(loopCount?: LoopCount): LoopCount {\n if (loopCount === undefined) {\n return this.loopCount;\n }\n this.loopCount = loopCount;\n this.playbacks.forEach(p => p.loop(loopCount));\n return this.loopCount;\n }\n\n /**\n * Adds a BiquadFilterNode to the sound's filter chain.\n * Filters are applied in the order they are added.\n * @param { BiquadFilterNode } filter - The filter to add to the chain.\n */\n\n addFilter(filter: BiquadFilterNode): void {\n super.addFilter(filter);\n this.playbacks.forEach(p => p.addFilter(filter));\n }\n\n /**\n * Removes a BiquadFilterNode from the sound's filter chain.\n * If the filter is not part of the chain, the method has no effect.\n * @param { BiquadFilterNode } filter - The filter to remove from the chain.\n */\n\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.playbacks.forEach(p => p.removeFilter(filter));\n }\n\n\n /*** \n * Gets or sets the volume of the sound. This volume level affects all current and future playbacks of this sound instance.\n * The volume is specified as a linear value between 0 (silent) and 1 (full volume).\n * \n * @returns {number} The current volume of the sound.\n * @param {number} volume - The new volume level to set, must be between 0 and 1.\n */\n\n get volume(): number {\n return this._volume;\n }\n\n set volume(volume: number) {\n this._volume = volume;\n this.playbacks.forEach(p => p.volume = volume);\n }\n\n /**\n * Returns a boolean indicating whether the sound is currently playing.\n * @returns {boolean} True if the sound is playing, false otherwise.\n */\n isPlaying(): boolean {\n return this.playbacks.some(p => p.isPlaying());\n }\n\n get playbackRate(): number {\n return this._playbackRate;\n }\n\n set playbackRate(rate: number) {\n this._playbackRate = rate;\n this.playbacks.forEach(p => p.playbackRate = rate);\n }\n\n}\n\n","import { AudioContext, IAudioBuffer, IAudioBufferSourceNode, IAudioListener, IBiquadFilterNode, IGainNode, IMediaElementAudioSourceNode, IMediaStreamAudioSourceNode, IPannerNode, IPannerOptions } from 'standardized-audio-context';\n\n\nconst appendBuffer = (buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBuffer => {\n var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);\n tmp.set(new Uint8Array(buffer1), 0);\n tmp.set(new Uint8Array(buffer2), buffer1.byteLength);\n return tmp.buffer;\n}\n\n\nexport function createStream(url: string, context: AudioContext) {\n const audioStack: IAudioBuffer[] = [];\n let nextTime = 0;\n\n fetch(url).then(function (response) {\n if (!response.ok) {\n throw new Error('HTTP error, status = ' + response.status);\n }\n if (!response.body) {\n throw new Error('Missing body');\n }\n\n var reader = response.body.getReader();\n let header = new ArrayBuffer(0);//first 44bytes\n\n function read() {\n return reader.read().then(({ value, done }) => {\n let audioBuffer = null;\n if (!value) {\n return;\n }\n\n if (!header.byteLength) {\n //copy first 44 bytes (wav header)\n header = value.buffer.slice(0, 44);\n audioBuffer = value.buffer;\n } else {\n audioBuffer = appendBuffer(header, value.buffer);\n }\n\n context.decodeAudioData(audioBuffer, function (buffer) {\n\n audioStack.push(buffer);\n if (audioStack.length) {\n scheduleBuffers();\n }\n }, function (err) {\n console.log(\"err(decodeAudioData): \" + err);\n });\n if (done) {\n console.log('done');\n return;\n }\n //read next buffer\n read();\n });\n }\n read();\n })\n\n function scheduleBuffers() {\n while (audioStack.length) {\n let buffer = audioStack.shift();\n const source = context.createBufferSource();\n if (!buffer) {\n return;\n }\n source.buffer = buffer;\n source.connect(context.destination);\n if (nextTime == 0)\n nextTime = context.currentTime + 0.02; /// add 50ms latency to work well across systems - tune this if you like\n source.start(nextTime);\n nextTime += source.buffer.duration; // Make the next buffer wait the length of the last buffer before being played\n };\n }\n}\n\n","import { AudioContext, AudioWorkletNode, IAudioListener, IMediaStreamAudioSourceNode, IPannerNode, IPannerOptions } from 'standardized-audio-context';\nimport phaseVocoderProcessorWorkletUrl from './bundles/phase-vocoder-bundle.js?url';\nimport { CacheManager } from './cache';\nimport { BiquadFilterNode, GainNode } from './context';\nimport { FilterManager } from './filters';\nimport { Group } from './group';\nimport { Playback } from './playback';\nimport { Sound } from './sound';\nimport { createStream } from './stream';\n\n\nexport enum SoundType {\n HTML = 'HTML',\n Streaming = 'Streaming',\n Buffer = 'Buffer'\n}\n\n\n\ntype PannerNode = IPannerNode<AudioContext>;\n\n\n\ntype MediaStreamAudioSourceNode = IMediaStreamAudioSourceNode<AudioContext>;\n\n\n/**\n * Represents a 3D position in space.\n * @typedef {Array<number>} Position - An array of three numbers representing the x, y, and z coordinates.\n */\nexport type Position = [x: number, y: number, z: number];\n\n/**\n * Represents the orientation of an object in 3D space.\n * @typedef {Object} Orientation - An object containing two positions: forward and up.\n * @property {Position} forward - The forward direction of the object.\n * @property {Position} up - The up direction of the object.\n */\nexport type Orientation = {\n forward: Position;\n up: Position;\n}\n\n/**\n * Represents the number of times a sound should loop.\n * @typedef {number | 'infinite'} LoopCount - The number of loops, or 'infinite' for endless looping.\n */\nexport type LoopCount = number | 'infinite';\n\n/**\n * Represents the type of fade effect to apply.\n * @typedef {'linear' | 'exponential'} FadeType - The fade type, either 'linear' or 'exponential'.\n */\nexport type FadeType = 'linear' | 'exponential';\n\n/**\n * Represents the type of panning effect to apply.\n * @typedef {'HRTF' | 'stereo'} PanType - The pan type, either 'HRTF' for 3D audio or 'stereo' for traditional stereo panning.\n */\nexport type PanType = 'HRTF' | 'stereo';\n\n/**\n * The base interface for any sound-producing entity, including individual sounds, groups, and playbacks.\n * @interface BaseSound\n */\nexport interface BaseSound {\n isPlaying(): boolean;\n play(): BaseSound[];\n seek?(time: number): void;\n stop(): void;\n pause(): void;\n resume(): void;\n addFilter(filter: BiquadFilterNode): void;\n removeFilter(filter: BiquadFilterNode): void;\n volume: number;\n playbackRate: number;\n loop?(loopCount?: LoopCount): LoopCount;\n duration: number;\n}\n\n\n\n\n\nexport class Cacophony {\n context: AudioContext;\n globalGainNode: GainNode;\n listener: IAudioListener;\n private prevVolume: number = 1;\n private finalizationRegistry: FinalizationRegistry<Playback>;\n\n constructor(context?: AudioContext) {\n this.context = context || new AudioContext();\n this.listener = this.context.listener;\n this.globalGainNode = this.context.createGain();\n this.globalGainNode.connect(this.context.destination);\n\n this.finalizationRegistry = new FinalizationRegistry((heldValue) => {\n // Cleanup callback for Playbacks\n heldValue.cleanup();\n });\n }\n\n async loadWorklets() {\n if (this.context.audioWorklet) {\n await this.createWorkletNode('phase-vocoder', phaseVocoderProcessorWorkletUrl);\n }\n else {\n console.warn('AudioWorklet not supported');\n }\n }\n\n\n async createWorkletNode(\n name: string,\n url: string\n ) {\n // ensure audioWorklet has been loaded\n if (!this.context.audioWorklet) {\n throw new Error('AudioWorklet not supported');\n }\n try {\n return new AudioWorkletNode!(this.context, name);\n } catch (err) {\n console.error(err)\n console.log(\"Loading worklet from url\", url);\n try {\n await this.context.audioWorklet.addModule(url);\n } catch (err) {\n console.error(err);\n throw new Error(`Could not load worklet from url ${url}`);\n }\n\n return new AudioWorkletNode!(this.context, name);\n }\n }\n\n createOscillator = ({ frequency, type, periodicWave }: OscillatorOptions) => {\n if (frequency === undefined) {\n frequency = 440;\n }\n const oscillator = this.context.createOscillator();\n oscillator.type = type || 'sine';\n if (periodicWave) {\n oscillator.setPeriodicWave(periodicWave);\n }\n oscillator.frequency.setValueAtTime(frequency, this.context.currentTime);\n oscillator.connect(this.globalGainNode);\n return oscillator\n }\n\n\n async createSound(buffer: AudioBuffer, soundType?: SoundType, panType?: PanType): Promise<Sound>\n\n async createSound(url: string, soundType?: SoundType, panType?: PanType): Promise<Sound>\n\n async createSound(bufferOrUrl: AudioBuffer | string, soundType: SoundType = SoundType.Buffer, panType: PanType = 'HRTF'): Promise<Sound> {\n if (bufferOrUrl instanceof AudioBuffer) {\n return Promise.resolve(new Sound(\"\", bufferOrUrl, this.context, this.globalGainNode, SoundType.Buffer, panType));\n }\n const url = bufferOrUrl;\n if (soundType === SoundType.HTML) {\n const audio = new Audio();\n audio.src = url;\n audio.crossOrigin = 'anonymous';\n return new Sound(url, undefined, this.context, this.globalGainNode, SoundType.HTML, panType);\n }\n return CacheManager.getAudioBuffer(url, this.context).then(buffer => new Sound(url, buffer, this.context, this.globalGainNode, soundType, panType));\n }\n\n async createGroup(sounds: Sound[]): Promise<Group> {\n const group = new Group();\n sounds.forEach(sound => group.addSound(sound));\n return group;\n }\n\n async createGroupFromUrls(urls: string[], soundType: SoundType = SoundType.Buffer, panType: PanType = 'HRTF'): Promise<Group> {\n const group = new Group();\n const sounds = await Promise.all(urls.map(url => this.createSound(url, soundType, panType)));\n sounds.forEach(sound => group.addSound(sound));\n return group;\n }\n\n async createStream(url: string): Promise<Sound> {\n const stream = await createStream(url, this.context);\n const sound = new Sound(url, undefined, this.context, this.globalGainNode, SoundType.Streaming);\n return sound;\n }\n\n createBiquadFilter = ({ type, frequency, gain, Q }: BiquadFilterOptions): BiquadFilterNode => {\n if (frequency === undefined) {\n frequency = 350;\n }\n const filter = this.context.createBiquadFilter();\n filter.type = type || 'lowpass';\n filter.frequency.value = frequency;\n filter.gain.value = gain || 0;\n filter.Q.value = Q || 1;\n return filter;\n }\n\n /**\n * Creates a PannerNode with the specified options.\n * @param {IPannerOptions} options - An object containing the options to use when creating the PannerNode.\n * @returns {PannerNode} A new PannerNode instance with the specified options.\n * @example\n * const panner = audio.createPanner({\n * positionX: 0,\n * positionY: 0,\n * positionZ: 0,\n * orientationX: 0,\n * orientationY: 0,\n * orientationZ: 0,\n * });\n */\n\n createPanner({ coneInnerAngle, coneOuterAngle, coneOuterGain, distanceModel, maxDistance, channelCount, channelCountMode, channelInterpretation, panningModel, refDistance, rolloffFactor, positionX, positionY, positionZ, orientationX, orientationY, orientationZ }: Partial<IPannerOptions>): PannerNode {\n const panner = this.context.createPanner();\n panner.coneInnerAngle = coneInnerAngle || 360;\n panner.coneOuterAngle = coneOuterAngle || 360;\n panner.coneOuterGain = coneOuterGain || 0;\n panner.distanceModel = distanceModel || 'inverse';\n panner.maxDistance = maxDistance || 10000;\n panner.channelCount = channelCount || 2;\n panner.channelCountMode = channelCountMode || 'clamped-max';\n panner.channelInterpretation = channelInterpretation || 'speakers';\n panner.panningModel = panningModel || 'HRTF';\n panner.refDistance = refDistance || 1;\n panner.rolloffFactor = rolloffFactor || 1;\n panner.positionX.value = positionX || 0;\n panner.positionY.value = positionY || 0;\n panner.positionZ.value = positionZ || 0;\n panner.orientationX.value = orientationX || 0;\n panner.orientationY.value = orientationY || 0;\n panner.orientationZ.value = orientationZ || 0;\n return panner;\n }\n\n /**\n * Suspends the audio context.\n */\n pause(): void {\n if ('suspend' in this.context) {\n this.context.suspend();\n }\n }\n\n /**\n * Resumes the audio context.\n * This method is required to resume the audio context on mobile devices.\n * On desktop, the audio context will automatically resume when a sound is played.\n */\n resume() {\n if ('resume' in this.context) {\n this.context.resume();\n }\n }\n\n setGlobalVolume(volume: number) {\n this.globalGainNode.gain.value = volume;\n }\n\n get volume(): number {\n return this.globalGainNode.gain.value;\n }\n\n set volume(volume: number) {\n if (this.muted) {\n this.prevVolume = volume;\n return;\n }\n this.setGlobalVolume(volume);\n }\n\n mute() {\n if (!this.muted) {\n this.prevVolume = this.globalGainNode.gain.value;\n this.setGlobalVolume(0);\n }\n }\n\n unmute() {\n if (this.muted) {\n this.setGlobalVolume(this.prevVolume);\n }\n }\n\n get muted(): boolean {\n return this.globalGainNode.gain.value === 0;\n }\n\n set muted(muted: boolean) {\n if (muted !== this.muted) {\n if (muted) {\n this.mute();\n } else {\n this.unmute();\n }\n }\n }\n\n getMicrophoneStream(): Promise<MicrophoneStream> {\n return new Promise((resolve, reject) => {\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(stream => {\n const microphoneStream = new MicrophoneStream(this.context);\n microphoneStream.play();\n resolve(microphoneStream);\n })\n .catch(err => {\n reject(err);\n });\n });\n }\n\n get listenerOrientation(): Orientation {\n return {\n forward: [this.listener.forwardX.value, this.listener.forwardY.value, this.listener.forwardZ.value],\n up: [this.listener.upX.value, this.listener.upY.value, this.listener.upZ.value]\n };\n }\n\n set listenerOrientation(orientation: Orientation) {\n const { forward, up } = orientation;\n const [forwardX, forwardY, forwardZ] = forward;\n const [upX, upY, upZ] = up;\n this.listener.forwardX.value = forwardX;\n this.listener.forwardY.value = forwardY;\n this.listener.forwardZ.value = forwardZ;\n this.listener.upX.value = upX;\n this.listener.upY.value = upY;\n this.listener.upZ.value = upZ;\n }\n\n get listenerUpOrientation(): Position {\n return [this.listener.upX.value, this.listener.upY.value, this.listener.upZ.value];\n }\n\n set listenerUpOrientation(up: Position) {\n const [x, y, z] = up;\n this.listener.upX.value = x;\n this.listener.upY.value = y;\n this.listener.upZ.value = z;\n }\n\n get listenerForwardOrientation(): Position {\n return [this.listener.forwardX.value, this.listener.forwardY.value, this.listener.forwardZ.value];\n }\n\n set listenerForwardOrientation(forward: Position) {\n const [x, y, z] = forward;\n this.listener.forwardX.value = x;\n this.listener.forwardY.value = y;\n this.listener.forwardZ.value = z;\n }\n\n get listenerPosition(): Position {\n return [this.listener.positionX.value, this.listener.positionY.value, this.listener.positionZ.value];\n }\n\n set listenerPosition(position: Position) {\n const [x, y, z] = position;\n const currentTime = this.context.currentTime;\n this.listener.positionX.setValueAtTime(x, currentTime);\n this.listener.positionY.setValueAtTime(y, currentTime);\n this.listener.positionZ.setValueAtTime(z, currentTime);\n }\n\n}\n\n\nexport class MicrophonePlayback extends FilterManager {\n private context: AudioContext;\n private source?: MediaStreamAudioSourceNode;\n private gainNode?: GainNode;\n private panner?: PannerNode;\n\n\n constructor(source: MediaStreamAudioSourceNode, gainNode: GainNode, context: AudioContext, loopCount: LoopCount = 0) {\n super();\n this.source = source;\n this.gainNode = gainNode;\n this.context = context;\n this.panner = context.createPanner();\n source.connect(this.panner).connect(this.gainNode);\n this.refreshFilters();\n }\n\n get duration() {\n return 0;\n }\n\n play() {\n if (!this.source) {\n throw new Error('Cannot play a sound that has been cleaned up');\n }\n return [this];\n }\n\n isPlaying() {\n return Boolean(this.source);\n }\n\n get volume(): number {\n if (!this.gainNode) {\n throw new Error('Cannot get volume of a sound that has been cleaned up');\n }\n return this.gainNode.gain.value;\n }\n\n set volume(v: number) {\n if (!this.gainNode) {\n throw new Error('Cannot set volume of a sound that has been cleaned up');\n }\n this.gainNode.gain.value = v;\n }\n\n stop(): void {\n if (!this.source) {\n throw new Error('Cannot stop a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.stop());\n }\n\n pause(): void {\n if (!this.source) {\n throw new Error('Cannot pause a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.enabled = false);\n }\n\n resume(): void {\n if (!this.source) {\n throw new Error('Cannot resume a sound that has been cleaned up');\n }\n this.source.mediaStream.getTracks().forEach(track => track.enabled = true);\n }\n\n addFilter(filter: BiquadFilterNode): void {\n super.addFilter(filter);\n this.refreshFilters();\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n super.removeFilter(filter);\n this.refreshFilters();\n }\n\n set position(position: Position) {\n if (!this.panner) {\n throw new Error('Cannot move a sound that has been cleaned up');\n }\n const [x, y, z] = position;\n this.panner.positionX.value = x;\n this.panner.positionY.value = y;\n this.panner.positionZ.value = z;\n }\n\n get position(): Position {\n if (!this.panner) {\n throw new Error('Cannot get position of a sound that has been cleaned up');\n }\n return [this.panner.positionX.value, this.panner.positionY.value, this.panner.positionZ.value];\n }\n\n private refreshFilters(): void {\n if (!this.source || !this.gainNode) {\n throw new Error('Cannot update filters on a sound that has been cleaned up');\n }\n let connection = this.source;\n this.source.disconnect();\n connection = this.applyFilters(connection);\n connection.connect(this.gainNode);\n }\n\n get playbackRate(): number {\n // Playback rate is not applicable for live microphone stream\n return 1;\n }\n\n set playbackRate(rate: number) {\n }\n\n\n\n}\n\nexport class MicrophoneStream extends FilterManager implements BaseSound {\n context: AudioContext;\n private _position: Position = [0, 0, 0];\n loopCount: LoopCount = 0;\n private prevVolume: number = 1;\n private microphoneGainNode: GainNode;\n private streamPlayback?: MicrophonePlayback;\n private stream: MediaStream | undefined;\n private streamSource?: MediaStreamAudioSourceNode;\n\n constructor(context: AudioContext) {\n super();\n this.context = context;\n this.microphoneGainNode = this.context.createGain();\n }\n\n play(): MicrophonePlayback[] {\n if (!this.stream) {\n navigator.mediaDevices.getUserMedia({ audio: true })\n .then(stream => {\n this.stream = stream;\n this.streamSource = this.context.createMediaStreamSource(this.stream);\n this.streamPlayback = new MicrophonePlayback(this.streamSource, this.microphoneGainNode, this.context);\n this.streamPlayback.play();\n })\n .catch(err => {\n console.error('Error initializing microphone stream:', err);\n });\n }\n return this.streamPlayback ? [this.streamPlayback] : [];\n }\n\n get duration() {\n return 0;\n }\n\n\n seek(time: number) {\n // Seeking is not applicable for live microphone stream\n }\n\n /**\n * Returns a boolean indicating whether the sound is currently playing.\n * @returns {boolean} True if the sound is playing, false otherwise.\n */\n isPlaying(): boolean {\n return Boolean(this.streamPlayback);\n }\n\n stop() {\n if (this.streamPlayback) {\n this.streamPlayback.stop();\n this.streamPlayback = undefined;\n }\n }\n\n pause() {\n if (this.streamPlayback) {\n this.streamPlayback.pause();\n }\n }\n\n resume() {\n if (this.streamPlayback) {\n this.streamPlayback.resume();\n }\n }\n\n addFilter(filter: BiquadFilterNode): void {\n if (this.streamPlayback) {\n this.streamPlayback.addFilter(filter);\n }\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n if (this.streamPlayback) {\n this.streamPlayback.removeFilter(filter);\n }\n }\n\n get volume(): number {\n return this.streamPlayback ? this.streamPlayback.volume : 0;\n }\n\n set volume(volume: number) {\n if (this.streamPlayback) {\n this.streamPlayback.volume = volume;\n }\n }\n\n get position(): Position {\n // Position is not applicable for live microphone stream\n return [0, 0, 0];\n }\n\n set position(position: Position) {\n // Position is not applicable for live microphone stream\n }\n\n loop(loopCount?: LoopCount): LoopCount {\n // Looping is not applicable for live microphone stream\n return 0;\n }\n\n\n get playbackRate(): number {\n // Playback rate is not applicable for live microphone stream\n return 1;\n }\n\n set playbackRate(rate: number) {\n }\n\n}\n"],"names":["phaseVocoderProcessorWorkletUrl","CacheManager","error","url","cache","context","response","arrayBuffer","fetchResponse","responseClone","base64Data","buffer","c","pendingRequest","bufferFromCache","FilterManager","filter","f","connection","prevConnection","Group","randomIndex","playback","p","shouldLoop","sound","a","b","time","playbacks","loopCount","position","volume","rate","Playback","source","gainNode","panType","value","clamp","panner","options","playing","v","loop","fadeType","resolve","targetVolume","mediaElement","x","y","z","min","max","Sound","globalGainNode","type","SoundType","clone","audio","appendBuffer","buffer1","buffer2","tmp","createStream","audioStack","nextTime","reader","header","read","done","audioBuffer","scheduleBuffers","err","Cacophony","AudioContext","heldValue","name","AudioWorkletNode","frequency","periodicWave","oscillator","bufferOrUrl","soundType","sounds","group","urls","gain","Q","coneInnerAngle","coneOuterAngle","coneOuterGain","distanceModel","maxDistance","channelCount","channelCountMode","channelInterpretation","panningModel","refDistance","rolloffFactor","positionX","positionY","positionZ","orientationX","orientationY","orientationZ","muted","reject","stream","microphoneStream","MicrophoneStream","orientation","forward","up","forwardX","forwardY","forwardZ","upX","upY","upZ","currentTime","MicrophonePlayback","track"],"mappings":"8HAAeA,EAAA,0wlCCER,MAAMC,CAAa,CACtB,OAAe,gBAAkB,IAAI,IAErC,aAAqB,WAA4B,CACzC,GAAA,CACO,OAAA,MAAM,OAAO,KAAK,aAAa,QACjCC,EAAO,CACJ,cAAA,MAAM,wBAAyBA,CAAK,EACtCA,CACV,CACJ,CAEA,aAAqB,wBAAwBC,EAAaC,EAAcC,EAAqD,CACrH,GAAA,CACA,MAAMC,EAAW,MAAMF,EAAM,MAAMD,CAAG,EACtC,GAAIG,EAAU,CACJ,MAAAC,EAAc,MAAMD,EAAS,cAC5B,OAAAD,EAAQ,gBAAgBE,CAAW,CAC9C,CACO,OAAA,WACFL,EAAO,CACJ,cAAA,MAAM,uCAAwCA,CAAK,EACrDA,CACV,CACJ,CAEA,aAAqB,yBAAyBC,EAAaC,EAAcC,EAA8C,CAC/G,GAAA,CACM,MAAAG,EAAgB,MAAM,MAAML,CAAG,EAC/BM,EAAgBD,EAAc,QAC9BJ,EAAA,IAAID,EAAKM,CAAa,EACtB,MAAAF,EAAc,MAAMC,EAAc,cACjC,OAAAH,EAAQ,gBAAgBE,CAAW,QACrCL,EAAO,CACJ,cAAA,MAAM,wCAAyCA,CAAK,EACtDA,CACV,CACJ,CAEA,aAAoB,eAAeC,EAAaE,EAA8C,CAEtF,GAAAF,EAAI,WAAW,OAAO,EAAG,CAEzB,MAAMO,EAAaP,EAAI,MAAM,GAAG,EAAE,CAAC,EAC7BQ,EAAS,WAAW,KAAK,KAAKD,CAAU,EAAQE,GAAAA,EAAE,WAAW,CAAC,CAAC,EAC9D,OAAAP,EAAQ,gBAAgBM,EAAO,MAAM,CAChD,CAEM,MAAAP,EAAQ,MAAM,KAAK,YAGzB,IAAIS,EAAiB,KAAK,gBAAgB,IAAIV,CAAG,EACjD,GAAIU,EACO,OAAAA,EAIX,MAAMC,EAAkB,MAAM,KAAK,wBAAwBX,EAAKC,EAAOC,CAAO,EAC9E,OAAIS,IAKJD,EAAiB,KAAK,yBAAyBV,EAAKC,EAAOC,CAAO,EAC7D,KAAA,gBAAgB,IAAIF,EAAKU,CAAc,EAErCA,EACX,CACJ,CCpEO,MAAeE,CAAc,CACtB,QAA8B,CAAA,EAExC,UAAUC,EAA0B,CAC3B,KAAA,QAAQ,KAAKA,CAAM,CAC5B,CAEA,aAAaA,EAA0B,CACnC,KAAK,QAAU,KAAK,QAAQ,OAAOC,GAAKA,IAAMD,CAAM,CACxD,CAEA,aAAaE,EAAsB,CAC/B,YAAK,QAAQ,OAAO,CAACC,EAAgBH,KACjCG,EAAe,QAAQH,CAAM,EACtBA,GACRE,CAAU,EACN,KAAK,QAAQ,OAAS,EAAI,KAAK,QAAQ,KAAK,QAAQ,OAAS,CAAC,EAAIA,CAC7E,CACJ,CCbO,MAAME,CAA2B,CACpC,OAAkB,CAAA,EACV,UAAsB,CAAC,EAAG,EAAG,CAAC,EACtC,UAAuB,EACf,UAAoB,EAE5B,YAAuB,CACf,GAAA,KAAK,OAAO,SAAW,EACjB,MAAA,IAAI,MAAM,gDAAgD,EAE9D,MAAAC,EAAc,KAAK,MAAM,KAAK,SAAW,KAAK,OAAO,MAAM,EAE3DC,EADc,KAAK,OAAOD,CAAW,EACd,UAC7B,OAAAC,EAAS,QAAQC,GAAKA,EAAE,KAAM,CAAA,EACvBD,EAAS,CAAC,CACrB,CAEA,YAAYE,EAAsB,GAAgB,CAC1C,GAAA,KAAK,OAAO,SAAW,EACjB,MAAA,IAAI,MAAM,kDAAkD,EAGhE,MAAAF,EADQ,KAAK,OAAO,KAAK,SAAS,EACjB,UACvB,OAAAA,EAAS,QAAQC,GAAKA,EAAE,KAAM,CAAA,EACzB,KAAA,YACD,KAAK,WAAa,KAAK,OAAO,SAC1BC,EACA,KAAK,UAAY,EAEZ,KAAA,UAAY,KAAK,OAAO,QAG9BF,EAAS,CAAC,CACrB,CAEA,IAAI,UAAW,CACX,OAAO,KAAK,OAAO,IAAaG,GAAAA,EAAM,QAAQ,EAAE,OAAO,CAACC,EAAGC,IAAM,KAAK,IAAID,EAAGC,CAAC,EAAG,CAAC,CACtF,CAEA,KAAKC,EAAoB,CAChB,KAAA,OAAO,QAAiBH,GAAAA,EAAM,MAAQA,EAAM,KAAKG,CAAI,CAAC,CAC/D,CAEA,SAASH,EAAoB,CACpB,KAAA,OAAO,KAAKA,CAAK,CAC1B,CAEA,SAAsB,CAClB,OAAQ,KAAK,OAAmB,OAAmB,CAACI,EAAWJ,KAC3DA,EAAM,MAAQA,EAAM,KAAK,KAAK,SAAS,EAChCI,EAAU,OAAOJ,EAAM,QAAS,CAAA,GACxC,CAAE,CAAA,CACT,CAEA,MAAmB,CACf,OAAO,KAAK,QAAA,EAAU,IAAgBH,IAClCA,EAAS,KAAK,EACPA,EACV,CACL,CAMA,WAAqB,CACjB,OAAO,KAAK,OAAO,KAAcG,GAAAA,EAAM,WAAW,CACtD,CAEA,MAAa,CACT,KAAK,OAAO,QAAiBA,GAAAA,EAAM,MAAM,CAC7C,CAEA,OAAc,CACV,KAAK,OAAO,QAAiBA,GAAAA,EAAM,OAAO,CAC9C,CAEA,QAAe,CACX,KAAK,OAAO,QAAiBA,GAAAA,EAAM,QAAQ,CAC/C,CAEA,KAAKK,EAAkC,CACnC,OAAIA,IAAc,OACP,KAAK,WAEhB,KAAK,UAAYA,EACZ,KAAA,OAAO,QAAiBL,GAAAA,EAAM,MAAQA,EAAM,KAAKK,CAAS,CAAC,EACzD,KAAK,UAChB,CAEA,UAAUd,EAAgC,CACtC,KAAK,OAAO,QAAQS,GAASA,EAAM,UAAUT,CAAM,CAAC,CACxD,CAEA,aAAaA,EAAgC,CACzC,KAAK,OAAO,QAAQS,GAASA,EAAM,aAAaT,CAAM,CAAC,CAC3D,CAEA,IAAI,SAASe,EAAoC,CAC7C,KAAK,UAAYA,EACjB,KAAK,OAAO,QAAQN,GAASA,EAAM,SAAW,KAAK,SAAS,CAChE,CAEA,IAAI,UAAqC,CACrC,OAAO,KAAK,SAChB,CAEA,IAAI,QAAiB,CACjB,OAAO,KAAK,OAAO,IAAaA,GAAAA,EAAM,MAAM,EAAE,OAAO,CAACC,EAAGC,IAAMD,EAAIC,EAAG,CAAC,EAAI,KAAK,OAAO,MAC3F,CAEA,IAAI,OAAOK,EAAgB,CACvB,KAAK,OAAO,QAAiBP,GAAAA,EAAM,OAASO,CAAM,CACtD,CAEA,IAAI,cAAuB,CACnB,OAAA,KAAK,OAAO,SAAW,EAChB,EAEJ,KAAK,OAAO,CAAC,EAAE,YAC1B,CAEA,IAAI,aAAaC,EAAc,CAC3B,KAAK,OAAO,QAAiBR,GAAAA,EAAM,aAAeQ,CAAI,CAC1D,CAGJ,CC3GO,MAAMC,UAAiBnB,CAAmC,CAmB7D,YAAYoB,EAAoBC,EAAoB/B,EAAuByB,EAAuB,EAAUO,EAAmB,OAAQ,CAe/H,GAdE,QADkG,KAAA,QAAAA,EAExG,KAAK,UAAYP,EACjB,KAAK,QAAUO,EACf,KAAK,OAASF,EACV,WAAYA,GAAUA,EAAO,SAC7B,KAAK,OAASA,EAAO,QAErB,iBAAkBA,GAAUA,EAAO,aACnCA,EAAO,aAAa,QAAU,KAAK,WAAW,KAAK,IAAI,EAChD,YAAaA,IACpBA,EAAO,QAAU,KAAK,WAAW,KAAK,IAAI,GAE9C,KAAK,SAAWC,EAChB,KAAK,QAAU/B,EACX,KAAK,UAAY,OACZ,KAAA,OAASA,EAAQ,uBACf,KAAK,UAAY,SACnB,KAAA,OAASA,EAAQ,yBAEhB,OAAA,IAAI,MAAM,kBAAkB,EAE/B8B,EAAA,QAAQ,KAAK,MAAM,EACrB,KAAA,OAAO,QAAQ,KAAK,QAAQ,EACjC,KAAK,eAAe,CACxB,CA3CQ,QACA,OACA,SACA,OACR,UAAuB,EACvB,YAAsB,EACd,OACA,QAAmB,GA2C3B,IAAI,WAA2B,CACvB,OAAA,KAAK,UAAY,SACT,KAAK,OAA4B,IAAI,MAE1C,IACX,CAOA,IAAI,UAAUG,EAAe,CACrB,GAAA,KAAK,UAAY,SACX,MAAA,IAAI,MAAM,kDAAkD,EAElE,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,2DAA2D,EAE9E,KAAK,OAA4B,IAAI,eAAeC,EAAMD,EAAO,GAAI,CAAC,EAAG,KAAK,QAAQ,WAAW,CACtG,CAOA,IAAI,UAAW,CACP,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,yDAAyD,EAE7E,OAAO,KAAK,OAAO,QACvB,CAOA,IAAI,cAAe,CACX,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,8DAA8D,EAE9E,GAAA,iBAAkB,KAAK,OAChB,OAAA,KAAK,OAAO,aAAa,MAEpC,GAAI,iBAAkB,KAAK,QAAU,KAAK,OAAO,aACtC,OAAA,KAAK,OAAO,aAAa,aAE9B,MAAA,IAAI,MAAM,yBAAyB,CAC7C,CAOA,IAAI,aAAaL,EAAc,CACvB,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,8DAA8D,EAE9E,iBAAkB,KAAK,SAClB,KAAA,OAAO,aAAa,MAAQA,GAEjC,iBAAkB,KAAK,QAAU,KAAK,OAAO,eACxC,KAAA,OAAO,aAAa,aAAeA,EAEhD,CAOA,WAAa,IAAM,CACX,KAAK,QACA,KAAA,OAAS,KAAK,QAAQ,mBAAmB,EACzC,KAAA,OAAO,OAAS,KAAK,QAE1B,KAAK,KAAK,CAAC,EAEX,KAAK,YAAc,YAAc,KAAK,YAAc,KAAK,WACpD,KAAA,cACD,KAAK,SACL,KAAK,KAAK,GAGd,KAAK,QAAU,EACnB,EAQJ,MAAe,CACP,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,8CAA8C,EAElE,MAAI,iBAAkB,KAAK,QAAU,KAAK,OAAO,aACxC,KAAA,OAAO,aAAa,OAClB,UAAW,KAAK,QAAU,KAAK,OAAO,OAC7C,KAAK,OAAO,QAEhB,KAAK,QAAU,GACR,CAAC,IAAI,CAChB,CAOA,IAAI,eAAgC,CAC5B,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,2DAA2D,EAE3E,GAAA,KAAK,UAAY,OACX,MAAA,IAAI,MAAM,yDAAyD,EAE7E,MAAMO,EAAS,KAAK,OACb,MAAA,CACH,eAAgBA,EAAO,eACvB,eAAgBA,EAAO,eACvB,cAAeA,EAAO,cACtB,cAAeA,EAAO,cACtB,YAAaA,EAAO,YACpB,aAAc,KAAK,OAAO,aAC1B,iBAAkBA,EAAO,iBACzB,sBAAuBA,EAAO,sBAC9B,aAAcA,EAAO,aACrB,YAAaA,EAAO,YACpB,cAAeA,EAAO,cACtB,UAAWA,EAAO,UAAU,MAC5B,UAAWA,EAAO,UAAU,MAC5B,UAAWA,EAAO,UAAU,MAC5B,aAAcA,EAAO,aAAa,MAClC,aAAcA,EAAO,aAAa,MAClC,aAAcA,EAAO,aAAa,KAAA,CAE1C,CAOA,IAAI,cAAcC,EAAkC,CAC5C,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,2DAA2D,EAE3E,GAAA,KAAK,UAAY,OACX,MAAA,IAAI,MAAM,yDAAyD,EAE7E,MAAMD,EAAS,KAAK,OACbA,EAAA,eAAiBC,EAAQ,gBAAkBD,EAAO,eAClDA,EAAA,eAAiBC,EAAQ,gBAAkBD,EAAO,eAClDA,EAAA,cAAgBC,EAAQ,eAAiBD,EAAO,cAChDA,EAAA,cAAgBC,EAAQ,eAAiBD,EAAO,cAChDA,EAAA,YAAcC,EAAQ,aAAeD,EAAO,YAC5CA,EAAA,aAAeC,EAAQ,cAAgBD,EAAO,aAC9CA,EAAA,iBAAmBC,EAAQ,kBAAoBD,EAAO,iBACtDA,EAAA,sBAAwBC,EAAQ,uBAAyBD,EAAO,sBAChEA,EAAA,aAAeC,EAAQ,cAAgBD,EAAO,aAC9CA,EAAA,YAAcC,EAAQ,aAAeD,EAAO,YAC5CA,EAAA,cAAgBC,EAAQ,eAAiBD,EAAO,cACvDA,EAAO,UAAU,MAAQC,EAAQ,WAAaD,EAAO,UAAU,MAC/DA,EAAO,UAAU,MAAQC,EAAQ,WAAaD,EAAO,UAAU,MAC/DA,EAAO,UAAU,MAAQC,EAAQ,WAAaD,EAAO,UAAU,MAC/DA,EAAO,aAAa,MAAQC,EAAQ,cAAgBD,EAAO,aAAa,MACxEA,EAAO,aAAa,MAAQC,EAAQ,cAAgBD,EAAO,aAAa,MACxEA,EAAO,aAAa,MAAQC,EAAQ,cAAgBD,EAAO,aAAa,KAC5E,CAOA,KAAKZ,EAAoB,CACjB,GAAA,CAAC,KAAK,QAAU,CAAC,KAAK,UAAY,CAAC,KAAK,OAClC,MAAA,IAAI,MAAM,8CAA8C,EAE5D,MAAAc,EAAU,KAAK,YAErB,GADA,KAAK,KAAK,EACN,iBAAkB,KAAK,QAAU,KAAK,OAAO,aACxC,KAAA,OAAO,aAAa,YAAcd,EACnCc,GACK,KAAA,OAAO,aAAa,eAEtB,KAAK,OAEP,KAAA,OAAS,KAAK,QAAQ,mBAAmB,EACzC,KAAA,OAAO,OAAS,KAAK,OAC1B,KAAK,eAAe,EACpB,KAAK,OAAO,QAAQ,KAAK,MAAM,EAAE,QAAQ,KAAK,QAAQ,EAClDA,GACK,KAAA,OAAO,MAAM,EAAGd,CAAI,MAGvB,OAAA,IAAI,MAAM,qCAAqC,CAE7D,CAOA,IAAI,QAAiB,CACb,GAAA,CAAC,KAAK,SACA,MAAA,IAAI,MAAM,uDAAuD,EAEpE,OAAA,KAAK,SAAS,KAAK,KAC9B,CAOA,IAAI,OAAOe,EAAW,CACd,GAAA,CAAC,KAAK,SACA,MAAA,IAAI,MAAM,uDAAuD,EAEtE,KAAA,SAAS,KAAK,MAAQA,CAC/B,CAOA,IAAI,WAAWC,EAAe,CACtB,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,qDAAqD,EAErE,SAAU,KAAK,SACf,KAAK,OAAO,KAAOA,GAEnB,iBAAkB,KAAK,QAAU,KAAK,OAAO,eACxC,KAAA,OAAO,aAAa,KAAOA,EAExC,CAeA,OAAOhB,EAAciB,EAAqB,SAAyB,CACxD,OAAA,IAAI,QAAmBC,GAAA,CACtB,GAAA,CAAC,KAAK,SACA,MAAA,IAAI,MAAM,iDAAiD,EAG/C,KAAK,SAAS,KAAK,MACzC,MAAMC,EAAe,EAKrB,OAFK,KAAA,SAAS,KAAK,MAAQ,EAEnBF,EAAU,CACd,IAAK,cAED,KAAK,SAAS,KAAK,eAAe,IAAM,KAAK,QAAQ,WAAW,EAChE,KAAK,SAAS,KAAK,6BAA6BE,EAAc,KAAK,QAAQ,YAAcnB,CAAI,EAC7F,MACJ,IAAK,SACD,KAAK,SAAS,KAAK,wBAAwBmB,EAAc,KAAK,QAAQ,YAAcnB,CAAI,EACxF,KACR,CAGA,WAAW,IAAM,CAET,GAAA,CAAC,KAAK,SACA,MAAA,IAAI,MAAM,iDAAiD,EAEhE,KAAA,SAAS,KAAK,MAAQmB,EACnBD,GAAA,EACTlB,EAAO,GAAI,CAAA,CACjB,CACL,CAeA,QAAQA,EAAciB,EAAqB,SAAyB,CACzD,OAAA,IAAI,QAAmBC,GAAA,CAEtB,GAAA,CAAC,KAAK,SACA,MAAA,IAAI,MAAM,kDAAkD,EAGtE,OADsB,KAAK,SAAS,KAAK,MACjCD,EAAU,CACd,IAAK,cAED,KAAK,SAAS,KAAK,6BAA6B,IAAM,KAAK,QAAQ,YAAcjB,CAAI,EACrF,MACJ,IAAK,SAGD,KAAK,SAAS,KAAK,wBAAwB,EAAG,KAAK,QAAQ,YAAcA,CAAI,CACrF,CAEA,WAAW,IAAMkB,EAAA,EAAWlB,EAAO,GAAI,CAAA,CAC1C,CACL,CAWA,WAAqB,CACb,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,6DAA6D,EAEjF,OAAO,KAAK,OAChB,CAMA,SAAgB,CAER,KAAK,SACL,KAAK,OAAO,aACZ,KAAK,OAAS,QAEd,KAAK,WACL,KAAK,SAAS,aACd,KAAK,SAAW,QAEf,KAAA,QAAQ,QAAkBZ,GAAA,CACvBA,GACAA,EAAO,WAAW,CACtB,CACH,EACD,KAAK,QAAU,EAEnB,CAQA,KAAKc,EAAkC,CAC/B,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,8CAA8C,EAE9D,GAAA,KAAK,kBAAkB,sBACvB,OAAIA,IAAc,OACP,KAAK,OAAO,OAAS,GAAO,WAAa,GAEpD,KAAK,OAAO,KAAO,GACnB,KAAK,OAAO,QAAU,KAAK,OAAO,QAAQ,UAAY,EACtD,KAAK,OAAO,UAAY,EACjB,KAAK,OAAO,OAAS,GAAO,WAAa,GAGpD,GAAI,iBAAkB,KAAK,QAAU,KAAK,OAAO,aAAc,CACrD,MAAAkB,EAAe,KAAK,OAAO,aACjC,OAAIlB,IAAc,SAGlBkB,EAAa,KAAO,IAEbA,EAAa,OAAS,GAAO,WAAa,CACrD,CAEM,MAAA,IAAI,MAAM,yBAAyB,CAC7C,CAMA,MAAa,CACL,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,8CAA8C,EAE7D,KAAK,cAGN,SAAU,KAAK,QACf,KAAK,OAAO,OAEZ,iBAAkB,KAAK,QAAU,KAAK,OAAO,eACxC,KAAA,OAAO,aAAa,QACpB,KAAA,OAAO,aAAa,YAAc,GAE3C,KAAK,QAAU,GACnB,CAMA,OAAc,CACN,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,+CAA+C,EAE/D,YAAa,KAAK,OAAO,SACpB,KAAA,OAAO,QAAQ,SAE5B,CAMA,QAAe,CACP,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,gDAAgD,EAEhE,WAAY,KAAK,OAAO,SACnB,KAAA,OAAO,QAAQ,QAE5B,CAMA,UAAUhC,EAAgC,CACtC,MAAM,UAAUA,CAAM,EACtB,KAAK,eAAe,CACxB,CAMA,aAAaA,EAAgC,CACzC,MAAM,aAAaA,CAAM,EACzB,KAAK,eAAe,CACxB,CAQA,IAAI,SAASe,EAAoB,CACzB,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,8CAA8C,EAE9D,GAAA,KAAK,UAAY,OACX,MAAA,IAAI,MAAM,4CAA4C,EAEhE,KAAM,CAACkB,EAAGC,EAAGC,CAAC,EAAIpB,EACZS,EAAS,KAAK,OACpBA,EAAO,UAAU,MAAQS,EACzBT,EAAO,UAAU,MAAQU,EACzBV,EAAO,UAAU,MAAQW,CAC7B,CAQA,IAAI,UAAqB,CACjB,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,yDAAyD,EAEzE,GAAA,KAAK,UAAY,OACX,MAAA,IAAI,MAAM,uDAAuD,EAE3E,MAAMX,EAAS,KAAK,OACb,MAAA,CAACA,EAAO,UAAU,MAAOA,EAAO,UAAU,MAAOA,EAAO,UAAU,KAAK,CAClF,CAOQ,gBAAuB,CAC3B,GAAI,CAAC,KAAK,QAAU,CAAC,KAAK,SAChB,MAAA,IAAI,MAAM,2DAA2D,EAE/E,IAAItB,EAAa,KAAK,OACtBA,EAAW,WAAW,EACTA,EAAA,KAAK,aAAaA,CAAU,EAC9BA,EAAA,QAAQ,KAAK,QAAQ,CACpC,CACJ,CAEA,SAASqB,EAAMD,EAAec,EAAaC,EAAqB,CAC5D,OAAO,KAAK,IAAI,KAAK,IAAIf,EAAOc,CAAG,EAAGC,CAAG,CAC7C,CC1jBO,MAAMC,UAAcvC,CAAmC,CA8B1D,YAAmBZ,EAAaQ,EAAiCN,EAAuBkD,EAAiCC,EAAkBC,EAAU,OAAepB,EAAmB,OACrL,CACQ,QAFS,KAAA,IAAAlC,EAAsG,KAAA,KAAAqD,EAA2C,KAAA,QAAAnB,EAGhK,KAAK,OAAS1B,EACd,KAAK,QAAUN,EACf,KAAK,eAAiBkD,CAC1B,CAnCA,OACA,QACA,UAAwB,CAAA,EAChB,eACA,UAAsB,CAAC,EAAG,EAAG,CAAC,EAC9B,WAAqB,EACrB,eAAiC,CACrC,eAAgB,IAChB,eAAgB,IAChB,cAAe,EACf,cAAe,UACf,YAAa,IACb,aAAc,EACd,iBAAkB,cAClB,sBAAuB,WACvB,aAAc,OACd,YAAa,EACb,cAAe,EACf,UAAW,EACX,UAAW,EACX,UAAW,EACX,aAAc,EACd,aAAc,EACd,aAAc,CAAA,EAElB,UAAuB,EACf,cAAwB,EACxB,QAAkB,EAgB1B,OAAe,CACX,MAAMG,EAAQ,IAAIJ,EAAM,KAAK,IAAK,KAAK,OAAQ,KAAK,QAAS,KAAK,eAAgB,KAAK,IAAI,EAC3F,OAAAI,EAAM,UAAY,KAAK,UACvBA,EAAM,cAAgB,KAAK,cAC3BA,EAAM,QAAU,KAAK,QACrBA,EAAM,UAAY,KAAK,UACvBA,EAAM,eAAiB,KAAK,eAC5BA,EAAM,QAAU,KAAK,QACrBA,EAAM,QAAU,KAAK,QACrBA,EAAM,WAAa,KAAK,WACjBA,CACX,CAQA,SAAsB,CACd,IAAAvB,EACJ,GAAI,KAAK,OACIA,EAAA,KAAK,QAAQ,qBACtBA,EAAO,OAAS,KAAK,WAClB,CACG,MAAAwB,EAAQ,IAAI,MAClBA,EAAM,YAAc,YACpBA,EAAM,IAAM,KAAK,IACjBA,EAAM,QAAU,OAEPxB,EAAA,KAAK,QAAQ,yBAAyBwB,CAAK,CACxD,CACM,MAAAvB,EAAW,KAAK,QAAQ,WAAW,EAChCA,EAAA,QAAQ,KAAK,cAAc,EAC9B,MAAAd,EAAW,IAAIY,EAASC,EAAQC,EAAU,KAAK,QAAS,KAAK,UAAW,KAAK,OAAO,EAE1F,OAAAd,EAAS,OAAS,KAAK,OACvBA,EAAS,aAAe,KAAK,aAC7B,KAAK,QAAQ,QAAQN,GAAUM,EAAS,UAAUN,CAAM,CAAC,EACrD,KAAK,UAAY,QACjBM,EAAS,cAAgB,KAAK,cAC9BA,EAAS,SAAW,KAAK,UAClB,KAAK,UAAY,WACxBA,EAAS,UAAY,KAAK,WAEzB,KAAA,UAAU,KAAKA,CAAQ,EACrB,CAACA,CAAQ,CACpB,CASA,MAAmB,CACT,MAAAA,EAAW,KAAK,UACtB,OAAAA,EAAS,QAAQC,GAAKA,EAAE,KAAM,CAAA,EACvBD,CACX,CAMA,MAAO,CACH,KAAK,UAAU,QAAaC,GAAAA,EAAE,MAAM,CACxC,CAMA,OAAc,CACV,KAAK,UAAU,QAAoBD,GAAAA,EAAS,OAAO,CACvD,CAMA,QAAe,CACX,KAAK,UAAU,QAAoBA,GAAAA,EAAS,QAAQ,CACxD,CAQA,KAAKM,EAAoB,CACrB,KAAK,UAAU,QAAQN,GAAYA,EAAS,KAAKM,CAAI,CAAC,CAC1D,CASA,IAAI,UAAW,CACJ,OAAA,KAAK,QAAQ,UAAY,CACpC,CAQA,IAAI,UAAqB,CACd,MAAA,CAAC,KAAK,eAAe,UAAW,KAAK,eAAe,UAAW,KAAK,eAAe,SAAS,CACvG,CASA,IAAI,SAASG,EAAoB,CACxB,KAAA,eAAe,UAAYA,EAAS,CAAC,EACrC,KAAA,eAAe,UAAYA,EAAS,CAAC,EACrC,KAAA,eAAe,UAAYA,EAAS,CAAC,EAC1C,KAAK,UAAU,QAAaR,GAAAA,EAAE,SAAWQ,CAAQ,CACrD,CAGA,IAAI,eAAgC,CAChC,OAAO,KAAK,cAChB,CAEA,IAAI,cAAcU,EAAkC,CAChD,KAAK,eAAiB,CAAE,GAAG,KAAK,eAAgB,GAAGA,GACnD,KAAK,UAAU,QAAQlB,GAAKA,EAAE,cAAgB,KAAK,cAAc,CACrE,CAEA,IAAI,WAA2B,CAC3B,OAAO,KAAK,UAChB,CAEA,IAAI,UAAUe,EAAe,CACzB,KAAK,WAAaA,EAClB,KAAK,UAAU,QAAaf,GAAAA,EAAE,UAAYe,CAAK,CACnD,CAWA,KAAKR,EAAkC,CACnC,OAAIA,IAAc,OACP,KAAK,WAEhB,KAAK,UAAYA,EACjB,KAAK,UAAU,QAAQP,GAAKA,EAAE,KAAKO,CAAS,CAAC,EACtC,KAAK,UAChB,CAQA,UAAUd,EAAgC,CACtC,MAAM,UAAUA,CAAM,EACtB,KAAK,UAAU,QAAQO,GAAKA,EAAE,UAAUP,CAAM,CAAC,CACnD,CAQA,aAAaA,EAAgC,CACzC,MAAM,aAAaA,CAAM,EACzB,KAAK,UAAU,QAAQO,GAAKA,EAAE,aAAaP,CAAM,CAAC,CACtD,CAWA,IAAI,QAAiB,CACjB,OAAO,KAAK,OAChB,CAEA,IAAI,OAAOgB,EAAgB,CACvB,KAAK,QAAUA,EACf,KAAK,UAAU,QAAaT,GAAAA,EAAE,OAASS,CAAM,CACjD,CAMA,WAAqB,CACjB,OAAO,KAAK,UAAU,KAAUT,GAAAA,EAAE,WAAW,CACjD,CAEA,IAAI,cAAuB,CACvB,OAAO,KAAK,aAChB,CAEA,IAAI,aAAaU,EAAc,CAC3B,KAAK,cAAgBA,EACrB,KAAK,UAAU,QAAaV,GAAAA,EAAE,aAAeU,CAAI,CACrD,CAEJ,CCvSA,MAAM2B,EAAe,CAACC,EAAsBC,IAAsC,CAC9E,IAAIC,EAAM,IAAI,WAAWF,EAAQ,WAAaC,EAAQ,UAAU,EAChE,OAAAC,EAAI,IAAI,IAAI,WAAWF,CAAO,EAAG,CAAC,EAClCE,EAAI,IAAI,IAAI,WAAWD,CAAO,EAAGD,EAAQ,UAAU,EAC5CE,EAAI,MACf,EAGgB,SAAAC,EAAa7D,EAAaE,EAAuB,CAC7D,MAAM4D,EAA6B,CAAA,EACnC,IAAIC,EAAW,EAEf,MAAM/D,CAAG,EAAE,KAAK,SAAUG,EAAU,CAC5B,GAAA,CAACA,EAAS,GACV,MAAM,IAAI,MAAM,wBAA0BA,EAAS,MAAM,EAEzD,GAAA,CAACA,EAAS,KACJ,MAAA,IAAI,MAAM,cAAc,EAG9B,IAAA6D,EAAS7D,EAAS,KAAK,UAAU,EACjC,IAAA8D,EAAS,IAAI,YAAY,CAAC,EAE9B,SAASC,GAAO,CACL,OAAAF,EAAO,OAAO,KAAK,CAAC,CAAE,MAAA7B,EAAO,KAAAgC,KAAW,CAC3C,IAAIC,EAAc,KAClB,GAAKjC,EAqBL,IAjBK8B,EAAO,WAKMG,EAAAX,EAAaQ,EAAQ9B,EAAM,MAAM,GAH/C8B,EAAS9B,EAAM,OAAO,MAAM,EAAG,EAAE,EACjCiC,EAAcjC,EAAM,QAKhBjC,EAAA,gBAAgBkE,EAAa,SAAU5D,EAAQ,CAEnDsD,EAAW,KAAKtD,CAAM,EAClBsD,EAAW,QACKO,GAExB,EAAG,SAAUC,EAAK,CACN,QAAA,IAAI,yBAA2BA,CAAG,CAAA,CAC7C,EACGH,EAAM,CACN,QAAQ,IAAI,MAAM,EAClB,MACJ,CAEKD,IAAA,CACR,CACL,CACKA,GAAA,CACR,EAED,SAASG,GAAkB,CACvB,KAAOP,EAAW,QAAQ,CAClB,IAAAtD,EAASsD,EAAW,QAClB,MAAA9B,EAAS9B,EAAQ,qBACvB,GAAI,CAACM,EACD,OAEJwB,EAAO,OAASxB,EACTwB,EAAA,QAAQ9B,EAAQ,WAAW,EAC9B6D,GAAY,IACZA,EAAW7D,EAAQ,YAAc,KACrC8B,EAAO,MAAM+B,CAAQ,EACrBA,GAAY/B,EAAO,OAAO,QAC9B,CACJ,CACJ,CCjEY,IAAAsB,GAAAA,IACRA,EAAA,KAAO,OACPA,EAAA,UAAY,YACZA,EAAA,OAAS,SAHDA,IAAAA,GAAA,CAAA,CAAA,EAyEL,MAAMiB,CAAU,CACnB,QACA,eACA,SACQ,WAAqB,EACrB,qBAER,YAAYrE,EAAwB,CAC3B,KAAA,QAAUA,GAAW,IAAIsE,EAAa,aACtC,KAAA,SAAW,KAAK,QAAQ,SACxB,KAAA,eAAiB,KAAK,QAAQ,WAAW,EAC9C,KAAK,eAAe,QAAQ,KAAK,QAAQ,WAAW,EAEpD,KAAK,qBAAuB,IAAI,qBAAsBC,GAAc,CAEhEA,EAAU,QAAQ,CAAA,CACrB,CACL,CAEA,MAAM,cAAe,CACb,KAAK,QAAQ,aACP,MAAA,KAAK,kBAAkB,gBAAiB5E,CAA+B,EAG7E,QAAQ,KAAK,4BAA4B,CAEjD,CAGA,MAAM,kBACF6E,EACA1E,EACF,CAEM,GAAA,CAAC,KAAK,QAAQ,aACR,MAAA,IAAI,MAAM,4BAA4B,EAE5C,GAAA,CACA,OAAO,IAAI2E,EAAAA,iBAAkB,KAAK,QAASD,CAAI,QAC1CJ,EAAK,CACV,QAAQ,MAAMA,CAAG,EACT,QAAA,IAAI,2BAA4BtE,CAAG,EACvC,GAAA,CACA,MAAM,KAAK,QAAQ,aAAa,UAAUA,CAAG,QACxCsE,EAAK,CACV,cAAQ,MAAMA,CAAG,EACX,IAAI,MAAM,mCAAmCtE,CAAG,EAAE,CAC5D,CAEA,OAAO,IAAI2E,EAAAA,iBAAkB,KAAK,QAASD,CAAI,CACnD,CACJ,CAEA,iBAAmB,CAAC,CAAE,UAAAE,EAAW,KAAAvB,EAAM,aAAAwB,KAAsC,CACrED,IAAc,SACFA,EAAA,KAEV,MAAAE,EAAa,KAAK,QAAQ,iBAAiB,EACjD,OAAAA,EAAW,KAAOzB,GAAQ,OACtBwB,GACAC,EAAW,gBAAgBD,CAAY,EAE3CC,EAAW,UAAU,eAAeF,EAAW,KAAK,QAAQ,WAAW,EAC5DE,EAAA,QAAQ,KAAK,cAAc,EAC/BA,CAAA,EAQX,MAAM,YAAYC,EAAmCC,EAAuB,SAAkB9C,EAAmB,OAAwB,CACrI,GAAI6C,aAAuB,YACvB,OAAO,QAAQ,QAAQ,IAAI5B,EAAM,GAAI4B,EAAa,KAAK,QAAS,KAAK,eAAgB,SAAkB7C,CAAO,CAAC,EAEnH,MAAMlC,EAAM+E,EACZ,GAAIC,IAAc,OAAgB,CACxB,MAAAxB,EAAQ,IAAI,MAClB,OAAAA,EAAM,IAAMxD,EACZwD,EAAM,YAAc,YACb,IAAIL,EAAMnD,EAAK,OAAW,KAAK,QAAS,KAAK,eAAgB,OAAgBkC,CAAO,CAC/F,CACA,OAAOpC,EAAa,eAAeE,EAAK,KAAK,OAAO,EAAE,KAAeQ,GAAA,IAAI2C,EAAMnD,EAAKQ,EAAQ,KAAK,QAAS,KAAK,eAAgBwE,EAAW9C,CAAO,CAAC,CACtJ,CAEA,MAAM,YAAY+C,EAAiC,CACzC,MAAAC,EAAQ,IAAIjE,EAClB,OAAAgE,EAAO,QAAQ3D,GAAS4D,EAAM,SAAS5D,CAAK,CAAC,EACtC4D,CACX,CAEA,MAAM,oBAAoBC,EAAgBH,EAAuB,SAAkB9C,EAAmB,OAAwB,CACpH,MAAAgD,EAAQ,IAAIjE,EAElB,OADe,MAAM,QAAQ,IAAIkE,EAAK,IAAWnF,GAAA,KAAK,YAAYA,EAAKgF,EAAW9C,CAAO,CAAC,CAAC,GACpF,QAAQZ,GAAS4D,EAAM,SAAS5D,CAAK,CAAC,EACtC4D,CACX,CAEA,MAAM,aAAalF,EAA6B,CAC7B,aAAM6D,EAAa7D,EAAK,KAAK,OAAO,EACrC,IAAImD,EAAMnD,EAAK,OAAW,KAAK,QAAS,KAAK,eAAgB,WAAmB,CAElG,CAEA,mBAAqB,CAAC,CAAE,KAAAqD,EAAM,UAAAuB,EAAW,KAAAQ,EAAM,EAAAC,KAA+C,CACtFT,IAAc,SACFA,EAAA,KAEV,MAAA/D,EAAS,KAAK,QAAQ,mBAAmB,EAC/C,OAAAA,EAAO,KAAOwC,GAAQ,UACtBxC,EAAO,UAAU,MAAQ+D,EAClB/D,EAAA,KAAK,MAAQuE,GAAQ,EACrBvE,EAAA,EAAE,MAAQwE,GAAK,EACfxE,CAAA,EAkBX,aAAa,CAAE,eAAAyE,EAAgB,eAAAC,EAAgB,cAAAC,EAAe,cAAAC,EAAe,YAAAC,EAAa,aAAAC,EAAc,iBAAAC,EAAkB,sBAAAC,EAAuB,aAAAC,EAAc,YAAAC,EAAa,cAAAC,EAAe,UAAAC,EAAW,UAAAC,EAAW,UAAAC,EAAW,aAAAC,EAAc,aAAAC,EAAc,aAAAC,GAAqD,CACnS,MAAAjE,EAAS,KAAK,QAAQ,aAAa,EACzC,OAAAA,EAAO,eAAiBiD,GAAkB,IAC1CjD,EAAO,eAAiBkD,GAAkB,IAC1ClD,EAAO,cAAgBmD,GAAiB,EACxCnD,EAAO,cAAgBoD,GAAiB,UACxCpD,EAAO,YAAcqD,GAAe,IACpCrD,EAAO,aAAesD,GAAgB,EACtCtD,EAAO,iBAAmBuD,GAAoB,cAC9CvD,EAAO,sBAAwBwD,GAAyB,WACxDxD,EAAO,aAAeyD,GAAgB,OACtCzD,EAAO,YAAc0D,GAAe,EACpC1D,EAAO,cAAgB2D,GAAiB,EACjC3D,EAAA,UAAU,MAAQ4D,GAAa,EAC/B5D,EAAA,UAAU,MAAQ6D,GAAa,EAC/B7D,EAAA,UAAU,MAAQ8D,GAAa,EAC/B9D,EAAA,aAAa,MAAQ+D,GAAgB,EACrC/D,EAAA,aAAa,MAAQgE,GAAgB,EACrChE,EAAA,aAAa,MAAQiE,GAAgB,EACrCjE,CACX,CAKA,OAAc,CACN,YAAa,KAAK,SAClB,KAAK,QAAQ,SAErB,CAOA,QAAS,CACD,WAAY,KAAK,SACjB,KAAK,QAAQ,QAErB,CAEA,gBAAgBR,EAAgB,CACvB,KAAA,eAAe,KAAK,MAAQA,CACrC,CAEA,IAAI,QAAiB,CACV,OAAA,KAAK,eAAe,KAAK,KACpC,CAEA,IAAI,OAAOA,EAAgB,CACvB,GAAI,KAAK,MAAO,CACZ,KAAK,WAAaA,EAClB,MACJ,CACA,KAAK,gBAAgBA,CAAM,CAC/B,CAEA,MAAO,CACE,KAAK,QACD,KAAA,WAAa,KAAK,eAAe,KAAK,MAC3C,KAAK,gBAAgB,CAAC,EAE9B,CAEA,QAAS,CACD,KAAK,OACA,KAAA,gBAAgB,KAAK,UAAU,CAE5C,CAEA,IAAI,OAAiB,CACV,OAAA,KAAK,eAAe,KAAK,QAAU,CAC9C,CAEA,IAAI,MAAM0E,EAAgB,CAClBA,IAAU,KAAK,QACXA,EACA,KAAK,KAAK,EAEV,KAAK,OAAO,EAGxB,CAEA,qBAAiD,CAC7C,OAAO,IAAI,QAAQ,CAAC5D,EAAS6D,IAAW,CAC1B,UAAA,aAAa,aAAa,CAAE,MAAO,GAAM,EAC9C,KAAeC,GAAA,CACZ,MAAMC,EAAmB,IAAIC,EAAiB,KAAK,OAAO,EAC1DD,EAAiB,KAAK,EACtB/D,EAAQ+D,CAAgB,CAAA,CAC3B,EACA,MAAapC,GAAA,CACVkC,EAAOlC,CAAG,CAAA,CACb,CAAA,CACR,CACL,CAEA,IAAI,qBAAmC,CAC5B,MAAA,CACH,QAAS,CAAC,KAAK,SAAS,SAAS,MAAO,KAAK,SAAS,SAAS,MAAO,KAAK,SAAS,SAAS,KAAK,EAClG,GAAI,CAAC,KAAK,SAAS,IAAI,MAAO,KAAK,SAAS,IAAI,MAAO,KAAK,SAAS,IAAI,KAAK,CAAA,CAEtF,CAEA,IAAI,oBAAoBsC,EAA0B,CACxC,KAAA,CAAE,QAAAC,EAAS,GAAAC,CAAO,EAAAF,EAClB,CAACG,EAAUC,EAAUC,CAAQ,EAAIJ,EACjC,CAACK,EAAKC,EAAKC,CAAG,EAAIN,EACnB,KAAA,SAAS,SAAS,MAAQC,EAC1B,KAAA,SAAS,SAAS,MAAQC,EAC1B,KAAA,SAAS,SAAS,MAAQC,EAC1B,KAAA,SAAS,IAAI,MAAQC,EACrB,KAAA,SAAS,IAAI,MAAQC,EACrB,KAAA,SAAS,IAAI,MAAQC,CAC9B,CAEA,IAAI,uBAAkC,CAClC,MAAO,CAAC,KAAK,SAAS,IAAI,MAAO,KAAK,SAAS,IAAI,MAAO,KAAK,SAAS,IAAI,KAAK,CACrF,CAEA,IAAI,sBAAsBN,EAAc,CACpC,KAAM,CAAChE,EAAGC,EAAGC,CAAC,EAAI8D,EACb,KAAA,SAAS,IAAI,MAAQhE,EACrB,KAAA,SAAS,IAAI,MAAQC,EACrB,KAAA,SAAS,IAAI,MAAQC,CAC9B,CAEA,IAAI,4BAAuC,CACvC,MAAO,CAAC,KAAK,SAAS,SAAS,MAAO,KAAK,SAAS,SAAS,MAAO,KAAK,SAAS,SAAS,KAAK,CACpG,CAEA,IAAI,2BAA2B6D,EAAmB,CAC9C,KAAM,CAAC/D,EAAGC,EAAGC,CAAC,EAAI6D,EACb,KAAA,SAAS,SAAS,MAAQ/D,EAC1B,KAAA,SAAS,SAAS,MAAQC,EAC1B,KAAA,SAAS,SAAS,MAAQC,CACnC,CAEA,IAAI,kBAA6B,CAC7B,MAAO,CAAC,KAAK,SAAS,UAAU,MAAO,KAAK,SAAS,UAAU,MAAO,KAAK,SAAS,UAAU,KAAK,CACvG,CAEA,IAAI,iBAAiBpB,EAAoB,CACrC,KAAM,CAACkB,EAAGC,EAAGC,CAAC,EAAIpB,EACZyF,EAAc,KAAK,QAAQ,YACjC,KAAK,SAAS,UAAU,eAAevE,EAAGuE,CAAW,EACrD,KAAK,SAAS,UAAU,eAAetE,EAAGsE,CAAW,EACrD,KAAK,SAAS,UAAU,eAAerE,EAAGqE,CAAW,CACzD,CAEJ,CAGO,MAAMC,UAA2B1G,CAAc,CAC1C,QACA,OACA,SACA,OAGR,YAAYoB,EAAoCC,EAAoB/B,EAAuByB,EAAuB,EAAG,CAC3G,QACN,KAAK,OAASK,EACd,KAAK,SAAWC,EAChB,KAAK,QAAU/B,EACV,KAAA,OAASA,EAAQ,eACtB8B,EAAO,QAAQ,KAAK,MAAM,EAAE,QAAQ,KAAK,QAAQ,EACjD,KAAK,eAAe,CACxB,CAEA,IAAI,UAAW,CACJ,MAAA,EACX,CAEA,MAAO,CACC,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,8CAA8C,EAElE,MAAO,CAAC,IAAI,CAChB,CAEA,WAAY,CACD,MAAA,EAAQ,KAAK,MACxB,CAEA,IAAI,QAAiB,CACb,GAAA,CAAC,KAAK,SACA,MAAA,IAAI,MAAM,uDAAuD,EAEpE,OAAA,KAAK,SAAS,KAAK,KAC9B,CAEA,IAAI,OAAOQ,EAAW,CACd,GAAA,CAAC,KAAK,SACA,MAAA,IAAI,MAAM,uDAAuD,EAEtE,KAAA,SAAS,KAAK,MAAQA,CAC/B,CAEA,MAAa,CACL,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,8CAA8C,EAE7D,KAAA,OAAO,YAAY,UAAU,EAAE,QAAiB+E,GAAAA,EAAM,MAAM,CACrE,CAEA,OAAc,CACN,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,+CAA+C,EAE9D,KAAA,OAAO,YAAY,YAAY,QAAiBA,GAAAA,EAAM,QAAU,EAAK,CAC9E,CAEA,QAAe,CACP,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,gDAAgD,EAE/D,KAAA,OAAO,YAAY,YAAY,QAAiBA,GAAAA,EAAM,QAAU,EAAI,CAC7E,CAEA,UAAU1G,EAAgC,CACtC,MAAM,UAAUA,CAAM,EACtB,KAAK,eAAe,CACxB,CAEA,aAAaA,EAAgC,CACzC,MAAM,aAAaA,CAAM,EACzB,KAAK,eAAe,CACxB,CAEA,IAAI,SAASe,EAAoB,CACzB,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,8CAA8C,EAElE,KAAM,CAACkB,EAAGC,EAAGC,CAAC,EAAIpB,EACb,KAAA,OAAO,UAAU,MAAQkB,EACzB,KAAA,OAAO,UAAU,MAAQC,EACzB,KAAA,OAAO,UAAU,MAAQC,CAClC,CAEA,IAAI,UAAqB,CACjB,GAAA,CAAC,KAAK,OACA,MAAA,IAAI,MAAM,yDAAyD,EAE7E,MAAO,CAAC,KAAK,OAAO,UAAU,MAAO,KAAK,OAAO,UAAU,MAAO,KAAK,OAAO,UAAU,KAAK,CACjG,CAEQ,gBAAuB,CAC3B,GAAI,CAAC,KAAK,QAAU,CAAC,KAAK,SAChB,MAAA,IAAI,MAAM,2DAA2D,EAE/E,IAAIjC,EAAa,KAAK,OACtB,KAAK,OAAO,aACCA,EAAA,KAAK,aAAaA,CAAU,EAC9BA,EAAA,QAAQ,KAAK,QAAQ,CACpC,CAEA,IAAI,cAAuB,CAEhB,MAAA,EACX,CAEA,IAAI,aAAae,EAAc,CAC/B,CAIJ,CAEO,MAAM6E,UAAyB/F,CAAmC,CACrE,QACQ,UAAsB,CAAC,EAAG,EAAG,CAAC,EACtC,UAAuB,EACf,WAAqB,EACrB,mBACA,eACA,OACA,aAER,YAAYV,EAAuB,CACzB,QACN,KAAK,QAAUA,EACV,KAAA,mBAAqB,KAAK,QAAQ,WAAW,CACtD,CAEA,MAA6B,CACrB,OAAC,KAAK,QACI,UAAA,aAAa,aAAa,CAAE,MAAO,GAAM,EAC9C,KAAeuG,GAAA,CACZ,KAAK,OAASA,EACd,KAAK,aAAe,KAAK,QAAQ,wBAAwB,KAAK,MAAM,EAC/D,KAAA,eAAiB,IAAIa,EAAmB,KAAK,aAAc,KAAK,mBAAoB,KAAK,OAAO,EACrG,KAAK,eAAe,MAAK,CAC5B,EACA,MAAahD,GAAA,CACF,QAAA,MAAM,wCAAyCA,CAAG,CAAA,CAC7D,EAEF,KAAK,eAAiB,CAAC,KAAK,cAAc,EAAI,CAAA,CACzD,CAEA,IAAI,UAAW,CACJ,MAAA,EACX,CAGA,KAAK7C,EAAc,CAEnB,CAMA,WAAqB,CACV,MAAA,EAAQ,KAAK,cACxB,CAEA,MAAO,CACC,KAAK,iBACL,KAAK,eAAe,OACpB,KAAK,eAAiB,OAE9B,CAEA,OAAQ,CACA,KAAK,gBACL,KAAK,eAAe,OAE5B,CAEA,QAAS,CACD,KAAK,gBACL,KAAK,eAAe,QAE5B,CAEA,UAAUZ,EAAgC,CAClC,KAAK,gBACA,KAAA,eAAe,UAAUA,CAAM,CAE5C,CAEA,aAAaA,EAAgC,CACrC,KAAK,gBACA,KAAA,eAAe,aAAaA,CAAM,CAE/C,CAEA,IAAI,QAAiB,CACjB,OAAO,KAAK,eAAiB,KAAK,eAAe,OAAS,CAC9D,CAEA,IAAI,OAAOgB,EAAgB,CACnB,KAAK,iBACL,KAAK,eAAe,OAASA,EAErC,CAEA,IAAI,UAAqB,CAEd,MAAA,CAAC,EAAG,EAAG,CAAC,CACnB,CAEA,IAAI,SAASD,EAAoB,CAEjC,CAEA,KAAKD,EAAkC,CAE5B,MAAA,EACX,CAGA,IAAI,cAAuB,CAEhB,MAAA,EACX,CAEA,IAAI,aAAaG,EAAc,CAC/B,CAEJ"}
|