Nuke trailing whitespace (#35)

master
Anna-Maria Meriniemi 7 years ago committed by Will
parent 287e95121f
commit a225a103b1
  1. 2
      gulpfile.js
  2. 4
      index.html
  3. 50
      src/js/HuesCanvas.js
  4. 84
      src/js/HuesCore.js
  5. 206
      src/js/HuesEditor.js
  6. 14
      src/js/HuesInfo.js
  7. 30
      src/js/HuesSettings.js
  8. 72
      src/js/HuesUI.js
  9. 28
      src/js/HuesWindow.js
  10. 36
      src/js/ResourceManager.js
  11. 4
      src/js/ResourcePack.js
  12. 68
      src/js/SoundManager.js

@ -96,7 +96,7 @@ gulp.task('release', ['default', 'lint'], function() {
'favicon.ico'], { 'favicon.ico'], {
base: '.' base: '.'
}).pipe(gulp.dest('release')); }).pipe(gulp.dest('release'));
gulp.src(['lib/workers/**/*','lib/zip*'], {base: 'lib'}) gulp.src(['lib/workers/**/*','lib/zip*'], {base: 'lib'})
.pipe(uglify()) .pipe(uglify())
.pipe(gulp.dest("release/lib")); .pipe(gulp.dest("release/lib"));

@ -12,8 +12,8 @@
window.addEventListener("load", function() { window.addEventListener("load", function() {
var defaults = { var defaults = {
workersPath : "lib/workers/", workersPath : "lib/workers/",
respacks : ["./respacks/Defaults_v5.0.zip", respacks : ["./respacks/Defaults_v5.0.zip",
"./respacks/CharPackagev0.03.zip", "./respacks/CharPackagev0.03.zip",
"./respacks/HuesMixA.zip" "./respacks/HuesMixA.zip"
], ],
firstSong : "Nhato - Miss You", firstSong : "Nhato - Miss You",

@ -58,14 +58,14 @@ class HuesCanvas {
this.blurDistance = 0; this.blurDistance = 0;
this.xBlur = false; this.xBlur = false;
this.yBlur = false; this.yBlur = false;
this.sliceDistance = 0; this.sliceDistance = 0;
this.sliceStart = 0; this.sliceStart = 0;
this.slices = { this.slices = {
x : this.makeSliceObj(25), x : this.makeSliceObj(25),
y : this.makeSliceObj(15) y : this.makeSliceObj(15)
}; };
// trippy mode // trippy mode
this.trippyStart = [0, 0]; // x, y this.trippyStart = [0, 0]; // x, y
this.trippyRadii = [0, 0]; // x, y this.trippyRadii = [0, 0]; // x, y
@ -80,7 +80,7 @@ class HuesCanvas {
this.lastBlackout = 0; this.lastBlackout = 0;
this.currentBlackout = -1; this.currentBlackout = -1;
this.lastFrameBlack = false; this.lastFrameBlack = false;
this.invert = false; this.invert = false;
this.colourFade = false; this.colourFade = false;
@ -94,21 +94,21 @@ class HuesCanvas {
this.setBlurAmount("medium"); this.setBlurAmount("medium");
this.setBlurQuality("high"); this.setBlurQuality("high");
this.setBlurDecay("fast"); this.setBlurDecay("fast");
this.canvas = document.createElement('canvas'); this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext("2d"); this.context = this.canvas.getContext("2d");
this.canvas.width = 1280; this.canvas.width = 1280;
this.canvas.height = 720; this.canvas.height = 720;
this.canvas.className = "hues-canvas"; this.canvas.className = "hues-canvas";
root.appendChild(this.canvas); root.appendChild(this.canvas);
this.offCanvas = document.createElement('canvas'); this.offCanvas = document.createElement('canvas');
this.offContext = this.offCanvas.getContext('2d'); this.offContext = this.offCanvas.getContext('2d');
window.addEventListener('resize', this.resize.bind(this)); window.addEventListener('resize', this.resize.bind(this));
this.resize(); this.resize();
} }
makeSliceObj(avgSegments) { makeSliceObj(avgSegments) {
return { return {
count : 0, count : 0,
@ -130,7 +130,7 @@ class HuesCanvas {
this.setBlurQuality(this.core.settings.blurQuality); this.setBlurQuality(this.core.settings.blurQuality);
this.trippyOn = this.core.settings.trippyMode == "on"; this.trippyOn = this.core.settings.trippyMode == "on";
} }
resetEffects() { resetEffects() {
this.colourFadeStart = 0; this.colourFadeStart = 0;
this.colourFade = false; this.colourFade = false;
@ -211,13 +211,13 @@ class HuesCanvas {
} else { } else {
offset = width/2 - drawWidth/2; offset = width/2 - drawWidth/2;
} }
if(this.sliceStart) { if(this.sliceStart) {
bitmap = this.drawSlice(bitmap, drawWidth, drawHeight, width, height); bitmap = this.drawSlice(bitmap, drawWidth, drawHeight, width, height);
drawWidth = width; drawWidth = width;
drawHeight = height; drawHeight = height;
} }
if(this.xBlur || this.yBlur) { if(this.xBlur || this.yBlur) {
this.drawBlur(bitmap, offset, drawWidth, drawHeight); this.drawBlur(bitmap, offset, drawWidth, drawHeight);
}else { }else {
@ -225,7 +225,7 @@ class HuesCanvas {
this.context.drawImage(bitmap, offset, 0, drawWidth, drawHeight); this.context.drawImage(bitmap, offset, 0, drawWidth, drawHeight);
} }
} }
if(this.trippyStart[0] || this.trippyStart[1]) { if(this.trippyStart[0] || this.trippyStart[1]) {
this.drawTrippy(width, height); this.drawTrippy(width, height);
} else { } else {
@ -287,10 +287,10 @@ class HuesCanvas {
bitmapXOffset += segmentBitmapWidth; bitmapXOffset += segmentBitmapWidth;
drawXOffset += segmentDrawWidth; drawXOffset += segmentDrawWidth;
} }
return this.offCanvas; return this.offCanvas;
} }
drawBlur(bitmap, offset, drawWidth, drawHeight) { drawBlur(bitmap, offset, drawWidth, drawHeight) {
this.context.globalAlpha = this.blurAlpha; this.context.globalAlpha = this.blurAlpha;
if(this.xBlur) { if(this.xBlur) {
@ -326,12 +326,12 @@ class HuesCanvas {
let normalC = this.intToHex(this.colour); let normalC = this.intToHex(this.colour);
this.offContext.fillStyle = baseInvert ? invertC : normalC; this.offContext.fillStyle = baseInvert ? invertC : normalC;
this.offContext.fillRect(0,0,width,height); this.offContext.fillRect(0,0,width,height);
// sort high to low // sort high to low
this.trippyRadii.sort(function(a,b) { this.trippyRadii.sort(function(a,b) {
return b - a; return b - a;
}); });
let invert = !baseInvert; let invert = !baseInvert;
for(let i = 0; i < 2; i++) { for(let i = 0; i < 2; i++) {
if(this.trippyRadii[i] === 0) { if(this.trippyRadii[i] === 0) {
@ -390,7 +390,7 @@ class HuesCanvas {
// flash offsets blur gen by a frame // flash offsets blur gen by a frame
let delta = this.audio.currentTime - this.blurStart + (1/30); let delta = this.audio.currentTime - this.blurStart + (1/30);
this.blurDistance = this.blurAmount * Math.exp(-this.blurDecay * delta); this.blurDistance = this.blurAmount * Math.exp(-this.blurDecay * delta);
// Update UI // Update UI
let dist = this.blurDistance / this.blurAmount; let dist = this.blurDistance / this.blurAmount;
if(this.xBlur) if(this.xBlur)
@ -436,7 +436,7 @@ class HuesCanvas {
} }
} }
} }
if(this.blurStart && this.blurDistance < 1) { if(this.blurStart && this.blurDistance < 1) {
this.core.blurUpdated(0, 0); this.core.blurUpdated(0, 0);
this.blurDistance = 0; this.blurDistance = 0;
@ -544,7 +544,7 @@ class HuesCanvas {
this.blackoutTimeout = this.audio.currentTime + beatTime / 1.7; this.blackoutTimeout = this.audio.currentTime + beatTime / 1.7;
this.currentBlackout++; this.currentBlackout++;
} }
doInstantBlackout() { doInstantBlackout() {
this.doBlackout(); this.doBlackout();
// sufficiently negative // sufficiently negative
@ -613,15 +613,15 @@ class HuesCanvas {
this.doYBlur(); this.doYBlur();
this.trippyOn = saveTrippy; this.trippyOn = saveTrippy;
} }
doSlice(beatLength, beatCount, sliceX, sliceY) { doSlice(beatLength, beatCount, sliceX, sliceY) {
let transitionTime = Math.min(0.06, beatLength); let transitionTime = Math.min(0.06, beatLength);
this.sliceStart = this.audio.currentTime; this.sliceStart = this.audio.currentTime;
this.sliceRampUp = this.sliceStart + transitionTime; this.sliceRampUp = this.sliceStart + transitionTime;
this.sliceRampDown = this.sliceStart + (beatLength * beatCount) - transitionTime; this.sliceRampDown = this.sliceStart + (beatLength * beatCount) - transitionTime;
this.sliceTransitionTime = transitionTime; this.sliceTransitionTime = transitionTime;
if (sliceX) if (sliceX)
this.generateSliceSegments('x'); this.generateSliceSegments('x');
else else
@ -633,7 +633,7 @@ class HuesCanvas {
this.needsRedraw = true; this.needsRedraw = true;
} }
generateSliceSegments(direction) { generateSliceSegments(direction) {
let even = 1.0 / this.slices[direction].avgSegments; let even = 1.0 / this.slices[direction].avgSegments;
let spread = even / 2; let spread = even / 2;
@ -643,16 +643,16 @@ class HuesCanvas {
let rando = even + Math.random() * spread * 2 - spread; let rando = even + Math.random() * spread * 2 - spread;
this.slices[direction].segments[i] = rando; this.slices[direction].segments[i] = rando;
total += rando; total += rando;
this.slices[direction].distances[i] = this.slices[direction].distances[i] =
Math.random() * this.blurAmount - this.blurAmount / 2; Math.random() * this.blurAmount - this.blurAmount / 2;
if(total > 1.0) { if(total > 1.0) {
this.slices[direction].segments[i] -= total - 1.0; this.slices[direction].segments[i] -= total - 1.0;
break; break;
} }
} }
this.slices[direction].count = i + 1; this.slices[direction].count = i + 1;
} }

@ -30,34 +30,34 @@ class HuesCore {
* When everything has completely loaded and we're ready to go * When everything has completely loaded and we're ready to go
*/ */
loaded : [], loaded : [],
/* callback time(seconds) /* callback time(seconds)
* *
* When the song time is updated - negative for buildup * When the song time is updated - negative for buildup
* Returns a floating point number denoting seconds * Returns a floating point number denoting seconds
*/ */
time : [], time : [],
/* callback blurUpdate(xPercent, yPercent) /* callback blurUpdate(xPercent, yPercent)
* *
* The current blur amounts, in percent of full blur * The current blur amounts, in percent of full blur
*/ */
blurupdate : [], blurupdate : [],
/* callback newsong(song) /* callback newsong(song)
* *
* Called on song change, whether user triggered or autosong. * Called on song change, whether user triggered or autosong.
* Song object is passed. * Song object is passed.
*/ */
newsong : [], newsong : [],
/* callback newimage(image) /* callback newimage(image)
* *
* Called on image change, whether user triggered or FULL AUTO mode. * Called on image change, whether user triggered or FULL AUTO mode.
* Image object is passed. * Image object is passed.
*/ */
newimage : [], newimage : [],
/* callback newcolour(colour, isFade) /* callback newcolour(colour, isFade)
* *
* Called on colour change. * Called on colour change.
@ -65,14 +65,14 @@ class HuesCore {
* isFade: if the colour is fading from the previous value * isFade: if the colour is fading from the previous value
*/ */
newcolour : [], newcolour : [],
/* callback newmode(mode) /* callback newmode(mode)
* *
* Called on mode change. * Called on mode change.
* Mode is passed as a boolean. * Mode is passed as a boolean.
*/ */
newmode : [], newmode : [],
/* callback beat(beatString, beatIndex) /* callback beat(beatString, beatIndex)
* *
* Called on every new beat. * Called on every new beat.
@ -80,27 +80,27 @@ class HuesCore {
* beatIndex is the beat index. Negative during buildups * beatIndex is the beat index. Negative during buildups
*/ */
beat : [], beat : [],
/* callback invert(isInverted) /* callback invert(isInverted)
* *
* Called whenever the invert state changes. * Called whenever the invert state changes.
* Invert state is passed as a boolean. * Invert state is passed as a boolean.
*/ */
invert : [], invert : [],
/* callback frame() /* callback frame()
* *
* Called on each new frame, at the end of all other frame processing * Called on each new frame, at the end of all other frame processing
*/ */
frame : [], frame : [],
/* callback songstarted(song) /* callback songstarted(song)
* *
* Called when the song actually begins to play, not just when the * Called when the song actually begins to play, not just when the
* new song processing begins. Song object passed. * new song processing begins. Song object passed.
*/ */
songstarted : [], songstarted : [],
/* callback settingsupdated() /* callback settingsupdated()
* *
* Called when settings are updated and should be re-read from the settings object * Called when settings are updated and should be re-read from the settings object
@ -113,30 +113,30 @@ class HuesCore {
this.versionStr = (this.version/10).toFixed(1); this.versionStr = (this.version/10).toFixed(1);
this.versionHex = this.version.toString(16); this.versionHex = this.version.toString(16);
this.beatIndex = 0; this.beatIndex = 0;
// How long a beat lasts for in each section // How long a beat lasts for in each section
this.buildLength = -1; this.buildLength = -1;
this.loopLength = -1; this.loopLength = -1;
this.currentSong = null; this.currentSong = null;
this.currentImage = null; this.currentImage = null;
this.songIndex = -1; this.songIndex = -1;
this.imageIndex = -1; this.imageIndex = -1;
this.lastSongArray = []; this.lastSongArray = [];
this.lastImageArray = []; this.lastImageArray = [];
this.colourIndex = 0x3f; this.colourIndex = 0x3f;
this.colours = HuesCore.oldColours; this.colours = HuesCore.oldColours;
this.invert = false; this.invert = false;
this.loopCount = 0; this.loopCount = 0;
this.doBuildup = true; this.doBuildup = true;
this.userInterface = null; this.userInterface = null;
this.uiArray = []; this.uiArray = [];
this.settings = new HuesSettings(defaults); this.settings = new HuesSettings(defaults);
zip.workerScriptsPath = this.settings.workersPath; zip.workerScriptsPath = this.settings.workersPath;
// What's our root element? // What's our root element?
this.root = null; this.root = null;
if(!this.settings.root) { if(!this.settings.root) {
@ -157,7 +157,7 @@ class HuesCore {
} }
// Yes, we do indeed have Javascript // Yes, we do indeed have Javascript
this.root.innerHTML = ""; this.root.innerHTML = "";
this.makePreloader(this.root); this.makePreloader(this.root);
window.onerror = (msg, url, line, col, error) => { window.onerror = (msg, url, line, col, error) => {
@ -165,16 +165,16 @@ class HuesCore {
// Get more info in console // Get more info in console
return false; return false;
}; };
this.window = new HuesWindow(this.root, this.settings); this.window = new HuesWindow(this.root, this.settings);
console.log("0x40 Hues v" + this.versionStr + " - start your engines!"); console.log("0x40 Hues v" + this.versionStr + " - start your engines!");
this.resourceManager = new Resources(this, this.window); this.resourceManager = new Resources(this, this.window);
this.editor = new HuesEditor(this, this.window); this.editor = new HuesEditor(this, this.window);
this.settings.initUI(this.window); this.settings.initUI(this.window);
populateHuesInfo(this.versionStr, this.window, this.settings); populateHuesInfo(this.versionStr, this.window, this.settings);
this.window.selectTab(this.settings.firstWindow, true); this.window.selectTab(this.settings.firstWindow, true);
let ui = document.createElement("div"); let ui = document.createElement("div");
@ -182,16 +182,16 @@ class HuesCore {
this.root.appendChild(ui); this.root.appendChild(ui);
this.uiArray.push(new RetroUI(ui), new WeedUI(ui), new ModernUI(ui), this.uiArray.push(new RetroUI(ui), new WeedUI(ui), new ModernUI(ui),
new XmasUI(ui), new HalloweenUI(ui), new MinimalUI(ui)); new XmasUI(ui), new HalloweenUI(ui), new MinimalUI(ui));
this.autoSong = this.settings.autoSong; this.autoSong = this.settings.autoSong;
this.visualiser = document.createElement("canvas"); this.visualiser = document.createElement("canvas");
this.visualiser.className = "hues-visualiser"; this.visualiser.className = "hues-visualiser";
this.visualiser.height = "64"; this.visualiser.height = "64";
this.vCtx = this.visualiser.getContext("2d"); this.vCtx = this.visualiser.getContext("2d");
this.soundManager = new SoundManager(this); this.soundManager = new SoundManager(this);
this.soundManager.init().then(() => { this.soundManager.init().then(() => {
if(!this.soundManager.locked && this.settings.skipPreloader == "on") { if(!this.soundManager.locked && this.settings.skipPreloader == "on") {
return null; return null;
@ -202,7 +202,7 @@ class HuesCore {
if(sizes === null) { if(sizes === null) {
return; return;
} }
let size = sizes.reduce( (prev, curr) => { let size = sizes.reduce( (prev, curr) => {
return typeof curr === 'number' ? prev + curr : null; return typeof curr === 'number' ? prev + curr : null;
}, 0); }, 0);
@ -211,11 +211,11 @@ class HuesCore {
} else { } else {
size = '<abbr title="Content-Length header not present for respack URLs">???</abbr>'; size = '<abbr title="Content-Length header not present for respack URLs">???</abbr>';
} }
let warning = size + "MB of music/images.<br />" + let warning = size + "MB of music/images.<br />" +
"Flashing lights.<br />" + "Flashing lights.<br />" +
"<b>Tap or click to start</b>"; "<b>Tap or click to start</b>";
if(!this.soundManager.locked) { if(!this.soundManager.locked) {
warning += "<br /><span>Skip this screen from Options</span>"; warning += "<br /><span>Skip this screen from Options</span>";
} }
@ -231,7 +231,7 @@ class HuesCore {
this.settingsUpdated(); this.settingsUpdated();
this.setColour(this.colourIndex); this.setColour(this.colourIndex);
this.animationLoop(); this.animationLoop();
if(this.settings.load) { if(this.settings.load) {
return this.resourceManager.addAll(this.settings.respacks, progress => { return this.resourceManager.addAll(this.settings.respacks, progress => {
this.preloader.style.backgroundPosition = (100 - progress*100) + "% 0%"; this.preloader.style.backgroundPosition = (100 - progress*100) + "% 0%";
@ -316,19 +316,19 @@ class HuesCore {
this.preloader = document.createElement("div"); this.preloader = document.createElement("div");
this.preloader.className = "hues-preloader"; this.preloader.className = "hues-preloader";
root.appendChild(this.preloader); root.appendChild(this.preloader);
if(this.settings.preloadTitle) { if(this.settings.preloadTitle) {
this.preloadTitle = document.createElement("div"); this.preloadTitle = document.createElement("div");
this.preloadTitle.className = "hues-preloader__title"; this.preloadTitle.className = "hues-preloader__title";
this.preloadTitle.textContent = this.settings.preloadTitle; this.preloadTitle.textContent = this.settings.preloadTitle;
this.preloader.appendChild(this.preloadTitle); this.preloader.appendChild(this.preloadTitle);
} }
this.preloadMsg = document.createElement("div"); this.preloadMsg = document.createElement("div");
this.preloadMsg.className = "hues-preloader__text"; this.preloadMsg.className = "hues-preloader__text";
this.preloadMsg.textContent = "Initialising..."; this.preloadMsg.textContent = "Initialising...";
this.preloader.appendChild(this.preloadMsg); this.preloader.appendChild(this.preloadMsg);
this.preloadSubMsg = document.createElement("div"); this.preloadSubMsg = document.createElement("div");
this.preloadSubMsg.className = "hues-preloader__subtext"; this.preloadSubMsg.className = "hues-preloader__subtext";
this.preloader.appendChild(this.preloadSubMsg); this.preloader.appendChild(this.preloadSubMsg);
@ -342,14 +342,14 @@ class HuesCore {
if(this.settings.visualiser != "on") { if(this.settings.visualiser != "on") {
return; return;
} }
let logArrays = this.soundManager.getVisualiserData(); let logArrays = this.soundManager.getVisualiserData();
if(!logArrays) { if(!logArrays) {
return; return;
} }
this.vCtx.clearRect(0, 0, this.vCtx.canvas.width, this.vCtx.canvas.height); this.vCtx.clearRect(0, 0, this.vCtx.canvas.width, this.vCtx.canvas.height);
let gradient=this.vCtx.createLinearGradient(0,64,0,0); let gradient=this.vCtx.createLinearGradient(0,64,0,0);
if(this.invert) { if(this.invert) {
gradient.addColorStop(1,"rgba(20,20,20,0.6)"); gradient.addColorStop(1,"rgba(20,20,20,0.6)");
@ -359,7 +359,7 @@ class HuesCore {
gradient.addColorStop(0,"rgba(20,20,20,0.6)"); gradient.addColorStop(0,"rgba(20,20,20,0.6)");
} }
this.vCtx.fillStyle = gradient; this.vCtx.fillStyle = gradient;
let barWidth = 2; let barWidth = 2;
let barHeight; let barHeight;
let x = 0; let x = 0;
@ -373,7 +373,7 @@ class HuesCore {
index = i; index = i;
} }
barHeight = vals[index]/4; barHeight = vals[index]/4;
this.vCtx.fillRect(x,this.vCtx.canvas.height-barHeight,barWidth,barHeight); this.vCtx.fillRect(x,this.vCtx.canvas.height-barHeight,barWidth,barHeight);
x += barWidth; x += barWidth;
@ -410,7 +410,7 @@ class HuesCore {
this.setInvert(false); this.setInvert(false);
return; return;
} }
// We should sync up to how many inverts there are // We should sync up to how many inverts there are
let build = this.currentSong.buildupRhythm; let build = this.currentSong.buildupRhythm;
let rhythm = this.currentSong.rhythm; let rhythm = this.currentSong.rhythm;
@ -820,8 +820,8 @@ class HuesCore {
} }
} }
} }
charsToNextBeat() { charsToNextBeat() {
// case: fade in build, not in rhythm. Must max out fade timer. // case: fade in build, not in rhythm. Must max out fade timer.
let maxSearch = this.currentSong.rhythm.length; let maxSearch = this.currentSong.rhythm.length;
@ -836,7 +836,7 @@ class HuesCore {
} }
return nextBeat; return nextBeat;
} }
timeToNextBeat() { timeToNextBeat() {
return (this.charsToNextBeat() * this.getBeatLength()) / this.soundManager.playbackRate; return (this.charsToNextBeat() * this.getBeatLength()) / this.soundManager.playbackRate;
} }
@ -1290,7 +1290,7 @@ HuesCore.weedColours =
{'c': 0xB62084, 'n': "Harold's Crayon"}, {'c': 0xB62084, 'n': "Harold's Crayon"},
{'c': 0x694489, 'n': 'Purple Rain'}, {'c': 0x694489, 'n': 'Purple Rain'},
{'c': 0xFFD700, 'n': 'Gold'}]; {'c': 0xFFD700, 'n': 'Gold'}];
window.HuesCore = HuesCore; window.HuesCore = HuesCore;
})(window, document); })(window, document);

@ -18,7 +18,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
(function(window, document) { (function(window, document) {
"use strict"; "use strict";
@ -32,15 +32,15 @@ class HuesEditor {
this.loopEdit = null; this.loopEdit = null;
this.editArea = null; this.editArea = null;
this.wrapAt = 32; this.wrapAt = 32;
this.hilightWidth = 0; this.hilightWidth = 0;
this.hilightHeight = 0; this.hilightHeight = 0;
this.undoBuffer = []; this.undoBuffer = [];
this.redoBuffer = []; this.redoBuffer = [];
// Will be an array if many actions are performed in one undo // Will be an array if many actions are performed in one undo
this.batchUndoArray = null; this.batchUndoArray = null;
// For rendering the waveform // For rendering the waveform
this.buildWave = null; this.buildWave = null;
this.loopWave = null; this.loopWave = null;
@ -48,12 +48,12 @@ class HuesEditor {
this.loopWaveBuff = null; this.loopWaveBuff = null;
this.waveContext = null; this.waveContext = null;
this.waveCanvas = null; this.waveCanvas = null;
// for storing respacks created with "new" // for storing respacks created with "new"
this.respack = null; this.respack = null;
// when we're actually following the playing song // when we're actually following the playing song
this.linked = false; this.linked = false;
this.core = core; this.core = core;
if(core.settings.enableWindow) { if(core.settings.enableWindow) {
this.initUI(); this.initUI();
@ -82,29 +82,29 @@ class HuesEditor {
help.addEventListener("click", () => { help.addEventListener("click", () => {
window.open("https://github.com/mon/0x40-web/tree/master/docs/Editor.md", '_blank'); window.open("https://github.com/mon/0x40-web/tree/master/docs/Editor.md", '_blank');
}); });
this.statusMsg = document.createElement("span"); this.statusMsg = document.createElement("span");
this.statusMsg.className = "editor__status-msg"; this.statusMsg.className = "editor__status-msg";
titleButtons.appendChild(this.statusMsg); titleButtons.appendChild(this.statusMsg);
this.topBar = document.createElement("div"); this.topBar = document.createElement("div");
this.topBar.className = "editor__top-bar"; this.topBar.className = "editor__top-bar";
this.root.appendChild(this.topBar); this.root.appendChild(this.topBar);
this.uiCreateInfo(); this.uiCreateInfo();
this.uiCreateImport(); this.uiCreateImport();
this.root.appendChild(document.createElement("hr")); this.root.appendChild(document.createElement("hr"));
this.uiCreateEditArea(); this.uiCreateEditArea();
this.uiCreateControls(); this.uiCreateControls();
this.uiCreateVisualiser(); this.uiCreateVisualiser();
document.addEventListener("keydown", e => { document.addEventListener("keydown", e => {
e = e || window.event; e = e || window.event;
if(e.defaultPrevented) { if(e.defaultPrevented) {
return true; return true;
} }
let key = e.keyCode || e.which; let key = e.keyCode || e.which;
if (e.ctrlKey) { if (e.ctrlKey) {
if(key == 90) { // Z if(key == 90) { // Z
this.undo(); this.undo();
@ -118,7 +118,7 @@ class HuesEditor {
} }
return true; return true;
}); });
window.addEventListener('resize', this.resize.bind(this)); window.addEventListener('resize', this.resize.bind(this));
// Fix Chrome rendering - redraw on tab load // Fix Chrome rendering - redraw on tab load
// tabselected passes the name of the selected tab, we force noHilightCalc to false // tabselected passes the name of the selected tab, we force noHilightCalc to false
@ -140,15 +140,15 @@ class HuesEditor {
let loopHeight = maxHeight - buildHeight + lHeadHeight; let loopHeight = maxHeight - buildHeight + lHeadHeight;
this.loopEdit.style.height = loopHeight + "px"; this.loopEdit.style.height = loopHeight + "px";
this.loopEdit._box.style.height = (loopHeight - lHeadHeight) + "px"; this.loopEdit._box.style.height = (loopHeight - lHeadHeight) + "px";
// For window resizing down situation // For window resizing down situation
if(this.editArea.offsetHeight != boxHeight) { if(this.editArea.offsetHeight != boxHeight) {
this.resize(); this.resize();
} }
// Resize the time lock // Resize the time lock
this.timeLock.style.height = (buildHeight + handleHeight) + "px"; this.timeLock.style.height = (buildHeight + handleHeight) + "px";
// Save to fix Chrome rendering and to enable right click to seek // Save to fix Chrome rendering and to enable right click to seek
// We only resize on a window resize event, not when dragging the handle // We only resize on a window resize event, not when dragging the handle
if(!noHilightCalc) { if(!noHilightCalc) {
@ -169,7 +169,7 @@ class HuesEditor {
this.hilightWidth = hilight.clientWidth / 100; this.hilightWidth = hilight.clientWidth / 100;
this.hilightHeight = hilight.clientHeight / 100; this.hilightHeight = hilight.clientHeight / 100;
this.loopEdit.removeChild(hilight); this.loopEdit.removeChild(hilight);
this.waveCanvas.width = this.waveCanvas.clientWidth; this.waveCanvas.width = this.waveCanvas.clientWidth;
} }
} }
@ -249,14 +249,14 @@ class HuesEditor {
this.copyBtn.classList.add("hues-button--disabled"); this.copyBtn.classList.add("hues-button--disabled");
this.buildEdit._removeBtn.classList.add("hues-button--disabled"); this.buildEdit._removeBtn.classList.add("hues-button--disabled");
this.loopEdit._removeBtn.classList.add("hues-button--disabled"); this.loopEdit._removeBtn.classList.add("hues-button--disabled");
if(!this.song) { if(!this.song) {
return; return;
} }
this.saveBtn.classList.remove("hues-button--disabled"); this.saveBtn.classList.remove("hues-button--disabled");
this.copyBtn.classList.remove("hues-button--disabled"); this.copyBtn.classList.remove("hues-button--disabled");
if(this.song.independentBuild) { if(this.song.independentBuild) {
this.timeLock._locker.innerHTML = "&#xe904;"; this.timeLock._locker.innerHTML = "&#xe904;";
this.timeLock.classList.add("edit-area__timelock--unlocked"); this.timeLock.classList.add("edit-area__timelock--unlocked");
@ -272,15 +272,15 @@ class HuesEditor {
this.seekStart.classList.remove("hues-button--disabled"); this.seekStart.classList.remove("hues-button--disabled");
this.buildEdit._removeBtn.classList.remove("hues-button--disabled"); this.buildEdit._removeBtn.classList.remove("hues-button--disabled");
} }
if(!this.linked) { if(!this.linked) {
return; return;
} }
let loopLen = this.core.soundManager.loopLength; let loopLen = this.core.soundManager.loopLength;
let buildLen = this.core.soundManager.buildLength; let buildLen = this.core.soundManager.buildLength;
let beatLen = (loopLen / this.song.rhythm.length) * 1000; let beatLen = (loopLen / this.song.rhythm.length) * 1000;
this.loopLen.textContent = loopLen.toFixed(2); this.loopLen.textContent = loopLen.toFixed(2);
this.buildLen.textContent = buildLen.toFixed(2); this.buildLen.textContent = buildLen.toFixed(2);
this.beatLen.textContent = beatLen.toFixed(2); this.beatLen.textContent = beatLen.toFixed(2);
@ -292,14 +292,14 @@ class HuesEditor {
} }
// If first load, this makes fresh, gets the core synced up // If first load, this makes fresh, gets the core synced up
this.newSong(this.song); this.newSong(this.song);
// Have we just added a build to a song with a rhythm, or vice versa? // Have we just added a build to a song with a rhythm, or vice versa?
// If so, link their lengths // If so, link their lengths
let newlyLinked = !this.song[editor._sound] && !!this.song[this.getOther(editor)._sound]; let newlyLinked = !this.song[editor._sound] && !!this.song[this.getOther(editor)._sound];
// Disable load button TODO // Disable load button TODO
let file = editor._fileInput.files[0]; let file = editor._fileInput.files[0];
// load audio // load audio
this.blobToArrayBuffer(file) this.blobToArrayBuffer(file)
.then(buffer => { .then(buffer => {
@ -348,7 +348,7 @@ class HuesEditor {
if(!this.song) { if(!this.song) {
return; return;
} }
this.song[editor._sound] = null; this.song[editor._sound] = null;
this.song[editor._rhythm] = ""; this.song[editor._rhythm] = "";
this.setIndependentBuild(true); this.setIndependentBuild(true);
@ -407,30 +407,30 @@ class HuesEditor {
// Clear instructions // Clear instructions
this.buildEdit._hilight.className = "beat-hilight invisible"; this.buildEdit._hilight.className = "beat-hilight invisible";
this.loopEdit._hilight.className = "beat-hilight invisible"; this.loopEdit._hilight.className = "beat-hilight invisible";
// Clear helpful glows // Clear helpful glows
this.newSongBtn.classList.remove("hues-button--glow"); this.newSongBtn.classList.remove("hues-button--glow");
this.fromSongBtn.classList.remove("hues-button--glow"); this.fromSongBtn.classList.remove("hues-button--glow");
// Enable title edits // Enable title edits
this.title.disabled = false; this.title.disabled = false;
this.source.disabled = false; this.source.disabled = false;
this.clearUndoRedo(); this.clearUndoRedo();
this.song = song; this.song = song;
this.reflow(this.buildEdit, song.buildupRhythm); this.reflow(this.buildEdit, song.buildupRhythm);
this.reflow(this.loopEdit, song.rhythm); this.reflow(this.loopEdit, song.rhythm);
this.title.value = song.title; this.title.value = song.title;
this.source.value = song.source; this.source.value = song.source;
// Force independent build if only 1 source is present // Force independent build if only 1 source is present
this.updateIndependentBuild(); this.updateIndependentBuild();
// Unlock beatmap lengths // Unlock beatmap lengths
this.setLocked(this.buildEdit, 0); this.setLocked(this.buildEdit, 0);
this.setLocked(this.loopEdit, 0); this.setLocked(this.loopEdit, 0);
this.linked = true; this.linked = true;
this.updateInfo(); this.updateInfo();
this.updateWaveform(); this.updateWaveform();
@ -438,7 +438,7 @@ class HuesEditor {
updateIndependentBuild() { updateIndependentBuild() {
// Force independent build if only 1 source is present // Force independent build if only 1 source is present
// Effectively buildup XOR loop - does only 1 exist? // Effectively buildup XOR loop - does only 1 exist?
let hasBuild = !!this.song.buildup; let hasBuild = !!this.song.buildup;
let hasLoop = !!this.song.sound; let hasLoop = !!this.song.sound;
@ -485,7 +485,7 @@ class HuesEditor {
return; return;
} }
this.redoBuffer = []; this.redoBuffer = [];
let undoObj = {songVar: name, let undoObj = {songVar: name,
editor: editor, editor: editor,
text: oldText, text: oldText,
@ -554,7 +554,7 @@ class HuesEditor {
updateUndoUI() { updateUndoUI() {
this.undoBtn.className = "hues-button hues-button--disabled"; this.undoBtn.className = "hues-button hues-button--disabled";
this.redoBtn.className = "hues-button hues-button--disabled"; this.redoBtn.className = "hues-button hues-button--disabled";
if(this.undoBuffer.length > 0) { if(this.undoBuffer.length > 0) {
this.undoBtn.classList.remove("hues-button--disabled"); this.undoBtn.classList.remove("hues-button--disabled");
} }
@ -632,9 +632,9 @@ class HuesEditor {
input.value = subtitle; input.value = subtitle;
container.appendChild(input); container.appendChild(input);
div.appendChild(container); div.appendChild(container);
parent.appendChild(div); parent.appendChild(div);
return input; return input;
} }
@ -667,7 +667,7 @@ class HuesEditor {
let info = document.createElement("div"); let info = document.createElement("div");
this.topBar.appendChild(info); this.topBar.appendChild(info);
info.className = "editor__info"; info.className = "editor__info";
let songUpdate = function(name) { let songUpdate = function(name) {
if(!this.song ) { if(!this.song ) {
return; return;
@ -678,7 +678,7 @@ class HuesEditor {
} }
this.core.callEventListeners("newsong", this.song); this.core.callEventListeners("newsong", this.song);
}; };
this.title = this.createTextInput("Title:", "Song name", info); this.title = this.createTextInput("Title:", "Song name", info);
this.title.oninput = songUpdate.bind(this, "title"); this.title.oninput = songUpdate.bind(this, "title");
this.title.disabled = true; this.title.disabled = true;
@ -691,7 +691,7 @@ class HuesEditor {
let imports = document.createElement("div"); let imports = document.createElement("div");
this.topBar.appendChild(imports); this.topBar.appendChild(imports);
imports.className = "editor__imports"; imports.className = "editor__imports";
let songEdits = document.createElement("div"); let songEdits = document.createElement("div");
imports.appendChild(songEdits); imports.appendChild(songEdits);
let newSongBtn = this.createButton("New song", songEdits, false, "hues-button--glow"); let newSongBtn = this.createButton("New song", songEdits, false, "hues-button--glow");
@ -706,11 +706,11 @@ class HuesEditor {
} }
}); });
this.fromSongBtn = fromSong; this.fromSongBtn = fromSong;
let songInfos = document.createElement("div"); let songInfos = document.createElement("div");
songInfos.className = "settings-individual editor__song-stats"; songInfos.className = "settings-individual editor__song-stats";
imports.appendChild(songInfos); imports.appendChild(songInfos);
this.loopLen = this.uiCreateSongStat("Loop length (s):", "0.00", songInfos); this.loopLen = this.uiCreateSongStat("Loop length (s):", "0.00", songInfos);
this.buildLen = this.uiCreateSongStat("Build length (s):", "0.00", songInfos); this.buildLen = this.uiCreateSongStat("Build length (s):", "0.00", songInfos);
this.beatLen = this.uiCreateSongStat("Beat length (ms):", "0.00", songInfos); this.beatLen = this.uiCreateSongStat("Beat length (ms):", "0.00", songInfos);
@ -734,7 +734,7 @@ class HuesEditor {
this.editArea = editArea; this.editArea = editArea;
editArea.className = "edit-area"; editArea.className = "edit-area";
this.root.appendChild(editArea); this.root.appendChild(editArea);
// Lock build/loop lengths // Lock build/loop lengths
this.timeLock = document.createElement("div"); this.timeLock = document.createElement("div");
editArea.appendChild(this.timeLock); editArea.appendChild(this.timeLock);
@ -749,7 +749,7 @@ class HuesEditor {
this.setIndependentBuild(!this.song.independentBuild); this.setIndependentBuild(!this.song.independentBuild);
}); });
this.timeLock._locker = locker; this.timeLock._locker = locker;
this.buildEdit = this.uiCreateSingleEditor("Buildup", "buildup", "buildupRhythm", editArea); this.buildEdit = this.uiCreateSingleEditor("Buildup", "buildup", "buildupRhythm", editArea);
this.seekStart = this.buildEdit._seek; this.seekStart = this.buildEdit._seek;
// FIRST |<< // FIRST |<<
@ -757,7 +757,7 @@ class HuesEditor {
this.seekStart.addEventListener("click", () => { this.seekStart.addEventListener("click", () => {
this.core.soundManager.seek(-this.core.soundManager.buildLength); this.core.soundManager.seek(-this.core.soundManager.buildLength);
}); });
// drag handle // drag handle
let handleContainer = document.createElement("div"); let handleContainer = document.createElement("div");
handleContainer.className = "resize-handle"; handleContainer.className = "resize-handle";
@ -767,22 +767,22 @@ class HuesEditor {
handle.innerHTML = "&#xe908;"; // DRAG HANDLE handle.innerHTML = "&#xe908;"; // DRAG HANDLE
handleContainer.appendChild(handle); handleContainer.appendChild(handle);
this.resizeHandle = handleContainer; this.resizeHandle = handleContainer;
handleContainer.addEventListener("mousedown", (e) => { handleContainer.addEventListener("mousedown", (e) => {
e.preventDefault(); e.preventDefault();
let editTop = this.editArea.getBoundingClientRect().top; let editTop = this.editArea.getBoundingClientRect().top;
let handleSize = this.resizeHandle.clientHeight; let handleSize = this.resizeHandle.clientHeight;
let resizer = (e) => { let resizer = (e) => {
this.buildEditSize = Math.floor(e.clientY - editTop + handleSize/2); this.buildEditSize = Math.floor(e.clientY - editTop + handleSize/2);
this.resize(true); this.resize(true);
}; };
let mouseup = function(e) { let mouseup = function(e) {
document.removeEventListener("mousemove", resizer); document.removeEventListener("mousemove", resizer);
document.removeEventListener("mouseup", mouseup); document.removeEventListener("mouseup", mouseup);
}; };
document.addEventListener("mousemove", resizer); document.addEventListener("mousemove", resizer);
document.addEventListener("mouseup", mouseup); document.addEventListener("mouseup", mouseup);
}); });
@ -794,11 +794,11 @@ class HuesEditor {
this.seekLoop.addEventListener("click", () => { this.seekLoop.addEventListener("click", () => {
this.core.soundManager.seek(0); this.core.soundManager.seek(0);
}); });
this.buildEdit._hilight.textContent = "[none]"; this.buildEdit._hilight.textContent = "[none]";
this.loopEdit._hilight.innerHTML = this.loopEdit._hilight.innerHTML =
'<br />' + '<br />' +
'Click [LOAD RHYTHM] to load a loop! LAME encoded MP3s work best.<br />' + 'Click [LOAD RHYTHM] to load a loop! LAME encoded MP3s work best.<br />' +
'(LAME is important for seamless MP3 loops)<br />' + '(LAME is important for seamless MP3 loops)<br />' +
'<br />' + '<br />' +
'[DOUBLE] doubles the selected map length by padding it with "."s.<br />' + '[DOUBLE] doubles the selected map length by padding it with "."s.<br />' +
@ -817,19 +817,19 @@ class HuesEditor {
uiCreateSingleEditor(title, soundName, rhythmName, parent) { uiCreateSingleEditor(title, soundName, rhythmName, parent) {
let container = document.createElement("div"); let container = document.createElement("div");
parent.appendChild(container); parent.appendChild(container);
let header = document.createElement("div"); let header = document.createElement("div");
header.className = "edit-area__header"; header.className = "edit-area__header";
container.appendChild(header); container.appendChild(header);
let nameLabel = document.createElement("span"); let nameLabel = document.createElement("span");
header.appendChild(nameLabel); header.appendChild(nameLabel);
nameLabel.innerHTML = title; nameLabel.innerHTML = title;
let seek = this.createButton("", header, true, "hues-icon"); let seek = this.createButton("", header, true, "hues-icon");
header.appendChild(seek); header.appendChild(seek);
container._seek = seek; container._seek = seek;
let beatCount = document.createElement("span"); let beatCount = document.createElement("span");
header.appendChild(beatCount); header.appendChild(beatCount);
beatCount.className = "edit-area__beat-count"; beatCount.className = "edit-area__beat-count";
@ -843,16 +843,16 @@ class HuesEditor {
this.setLocked(container, textLen); this.setLocked(container, textLen);
} }
}); });
let rightHeader = document.createElement("span"); let rightHeader = document.createElement("span");
rightHeader.className = "edit-area__header__right"; rightHeader.className = "edit-area__header__right";
header.appendChild(rightHeader); header.appendChild(rightHeader);
container._halveBtn = this.createButton("Halve", rightHeader, true); container._halveBtn = this.createButton("Halve", rightHeader, true);
container._halveBtn.addEventListener("click", this.halveBeats.bind(this, container)); container._halveBtn.addEventListener("click", this.halveBeats.bind(this, container));
container._doubleBtn = this.createButton("Double", rightHeader, true); container._doubleBtn = this.createButton("Double", rightHeader, true);
container._doubleBtn.addEventListener("click", this.doubleBeats.bind(this, container)); container._doubleBtn.addEventListener("click", this.doubleBeats.bind(this, container));
let fileInput = document.createElement("input"); let fileInput = document.createElement("input");
fileInput.type ="file"; fileInput.type ="file";
fileInput.accept=".mp3, .wav, .ogg"; fileInput.accept=".mp3, .wav, .ogg";
@ -860,10 +860,10 @@ class HuesEditor {
fileInput.onchange = this.loadAudio.bind(this, container); fileInput.onchange = this.loadAudio.bind(this, container);
let load = this.createButton("Load " + title.replace(/&nbsp;/g,""), rightHeader); let load = this.createButton("Load " + title.replace(/&nbsp;/g,""), rightHeader);
load.addEventListener("click", () => {fileInput.click();}); load.addEventListener("click", () => {fileInput.click();});
container._removeBtn = this.createButton("Remove", rightHeader, true); container._removeBtn = this.createButton("Remove", rightHeader, true);
container._removeBtn.addEventListener("click", this.removeAudio.bind(this, container)); container._removeBtn.addEventListener("click", this.removeAudio.bind(this, container));
let editBox = document.createElement("div"); let editBox = document.createElement("div");
editBox.className = "edit-area__box"; editBox.className = "edit-area__box";
let beatmap = document.createElement("div"); let beatmap = document.createElement("div");
@ -872,27 +872,27 @@ class HuesEditor {
beatmap.spellcheck = false; beatmap.spellcheck = false;
beatmap.oninput = this.textUpdated.bind(this, container); beatmap.oninput = this.textUpdated.bind(this, container);
beatmap.oncontextmenu = this.rightClick.bind(this, container); beatmap.oncontextmenu = this.rightClick.bind(this, container);
let beatHilight = document.createElement("div"); let beatHilight = document.createElement("div");
beatHilight.className = "beat-hilight"; beatHilight.className = "beat-hilight";
editBox.appendChild(beatHilight); editBox.appendChild(beatHilight);
editBox.appendChild(beatmap); editBox.appendChild(beatmap);
container.appendChild(editBox); container.appendChild(editBox);
container._header = header; container._header = header;
container._beatCount = beatCount; container._beatCount = beatCount;
container._box = editBox; container._box = editBox;
container._beatmap = beatmap; container._beatmap = beatmap;
container._hilight = beatHilight; container._hilight = beatHilight;
container._fileInput = fileInput; container._fileInput = fileInput;
container._sound = soundName; container._sound = soundName;
container._rhythm = rhythmName; container._rhythm = rhythmName;
// Are we in insert mode? Default = no // Are we in insert mode? Default = no
container._locked = 0; container._locked = 0;
return container; return container;
} }
@ -900,7 +900,7 @@ class HuesEditor {
let controls = document.createElement("div"); let controls = document.createElement("div");
controls.className = "edit__controls"; controls.className = "edit__controls";
this.root.appendChild(controls); this.root.appendChild(controls);
let changeRate = function(change) { let changeRate = function(change) {
let rate = this.core.soundManager.playbackRate; let rate = this.core.soundManager.playbackRate;
rate += change; rate += change;
@ -909,30 +909,30 @@ class HuesEditor {
let newRate = this.core.soundManager.playbackRate; let newRate = this.core.soundManager.playbackRate;
playRateLab.textContent = newRate.toFixed(2) + "x"; playRateLab.textContent = newRate.toFixed(2) + "x";
}; };
let speedControl = document.createElement("div"); let speedControl = document.createElement("div");
controls.appendChild(speedControl); controls.appendChild(speedControl);
// BACKWARD // BACKWARD
let speedDown = this.createButton("&#xe909;", speedControl, false, "hues-icon"); let speedDown = this.createButton("&#xe909;", speedControl, false, "hues-icon");
speedDown.addEventListener("click", changeRate.bind(this, -0.25)); speedDown.addEventListener("click", changeRate.bind(this, -0.25));
// FORWARD // FORWARD
let speedUp = this.createButton("&#xe90a;", speedControl, false, "hues-icon"); let speedUp = this.createButton("&#xe90a;", speedControl, false, "hues-icon");
speedUp.addEventListener("click", changeRate.bind(this, 0.25)); speedUp.addEventListener("click", changeRate.bind(this, 0.25));
let playRateLab = document.createElement("span"); let playRateLab = document.createElement("span");
playRateLab.className = "settings-individual"; playRateLab.className = "settings-individual";
playRateLab.textContent = "1.00x"; playRateLab.textContent = "1.00x";
speedControl.appendChild(playRateLab); speedControl.appendChild(playRateLab);
let wrapControl = document.createElement("div"); let wrapControl = document.createElement("div");
controls.appendChild(wrapControl); controls.appendChild(wrapControl);
let wrapLab = document.createElement("span"); let wrapLab = document.createElement("span");
wrapLab.className = "settings-individual"; wrapLab.className = "settings-individual";
wrapLab.textContent = "New line at beat "; wrapLab.textContent = "New line at beat ";
wrapControl.appendChild(wrapLab); wrapControl.appendChild(wrapLab);
let wrapAt = document.createElement("input"); let wrapAt = document.createElement("input");
wrapAt.className = "settings-input"; wrapAt.className = "settings-input";
wrapAt.value = this.wrapAt; wrapAt.value = this.wrapAt;
@ -946,7 +946,7 @@ class HuesEditor {
this.wrapAt = parseInt(wrapAt.value); this.wrapAt = parseInt(wrapAt.value);
this.reflow(this.buildEdit, this.song.buildupRhythm); this.reflow(this.buildEdit, this.song.buildupRhythm);
this.reflow(this.loopEdit, this.song.rhythm); this.reflow(this.loopEdit, this.song.rhythm);
}; };
wrapControl.appendChild(wrapAt); wrapControl.appendChild(wrapAt);
} }
@ -958,7 +958,7 @@ class HuesEditor {
this.root.appendChild(wave); this.root.appendChild(wave);
this.waveCanvas = wave; this.waveCanvas = wave;
this.waveContext = wave.getContext("2d"); this.waveContext = wave.getContext("2d");
this.core.addEventListener("frame", this.drawWave.bind(this)); this.core.addEventListener("frame", this.drawWave.bind(this));
} }
@ -968,7 +968,7 @@ class HuesEditor {
} }
// If the right click is also a focus event, caret doesn't move, so we have to use coords // If the right click is also a focus event, caret doesn't move, so we have to use coords
let coords = this.getTextCoords(event); let coords = this.getTextCoords(event);
if(coords.x > this.wrapAt) if(coords.x > this.wrapAt)
return true; return true;
@ -976,7 +976,7 @@ class HuesEditor {
let totalLen = this.getText(editor).length; let totalLen = this.getText(editor).length;
if(caret > totalLen) if(caret > totalLen)
return true; return true;
// in case of focus event // in case of focus event
this.setCaret(editor._beatmap, caret); this.setCaret(editor._beatmap, caret);
let percent = caret / totalLen; let percent = caret / totalLen;
@ -988,7 +988,7 @@ class HuesEditor {
seekTime = -bLen + bLen * percent; seekTime = -bLen + bLen * percent;
} }
this.core.soundManager.seek(seekTime); this.core.soundManager.seek(seekTime);
event.preventDefault(); event.preventDefault();
return false; return false;
} }
@ -1007,7 +1007,7 @@ class HuesEditor {
x = Math.floor((event.clientX - x) / this.hilightWidth); x = Math.floor((event.clientX - x) / this.hilightWidth);
y = Math.floor((event.clientY - y) / this.hilightHeight); y = Math.floor((event.clientY - y) / this.hilightHeight);
return {x: x, y: y}; return {x: x, y: y};
} }
@ -1094,7 +1094,7 @@ class HuesEditor {
this.reflow(editor, this.song[editor._rhythm]); this.reflow(editor, this.song[editor._rhythm]);
this.setCaret(editor._beatmap, caret); this.setCaret(editor._beatmap, caret);
this.updateHalveDoubleButtons(editor); this.updateHalveDoubleButtons(editor);
this.core.updateBeatLength(); this.core.updateBeatLength();
// We may have to go backwards in time // We may have to go backwards in time
this.core.recalcBeatIndex(); this.core.recalcBeatIndex();
@ -1174,10 +1174,10 @@ class HuesEditor {
// The individual wave section // The individual wave section
let wave = document.createElement("canvas"); let wave = document.createElement("canvas");
let waveContext = wave.getContext("2d"); let waveContext = wave.getContext("2d");
wave.height = WAVE_HEIGHT_PIXELS; wave.height = WAVE_HEIGHT_PIXELS;
wave.width = Math.floor(WAVE_PIXELS_PER_SECOND * length); wave.width = Math.floor(WAVE_PIXELS_PER_SECOND * length);
let samplesPerPixel = Math.floor(buffer.sampleRate / WAVE_PIXELS_PER_SECOND); let samplesPerPixel = Math.floor(buffer.sampleRate / WAVE_PIXELS_PER_SECOND);
let waveData = []; let waveData = [];
for(let i = 0; i < buffer.numberOfChannels; i++) { for(let i = 0; i < buffer.numberOfChannels; i++) {
@ -1211,7 +1211,7 @@ class HuesEditor {
waveContext.moveTo(pixel, maxPix); waveContext.moveTo(pixel, maxPix);
waveContext.lineTo(pixel, minPix); waveContext.lineTo(pixel, minPix);
waveContext.stroke(); waveContext.stroke();
// Draw the average too, gives a better feel for the wave // Draw the average too, gives a better feel for the wave
avgHi /= j * channels; avgHi /= j * channels;
avgLo /= j * channels; avgLo /= j * channels;
@ -1223,26 +1223,26 @@ class HuesEditor {
waveContext.moveTo(pixel, maxAvg); waveContext.moveTo(pixel, maxAvg);
waveContext.lineTo(pixel, minAvg); waveContext.lineTo(pixel, minAvg);
waveContext.stroke(); waveContext.stroke();
pixel+=1; pixel+=1;
} }
return wave; return wave;
} }
drawWave() { drawWave() {
if((!this.buildWave && !this.loopWave) || !this.linked) if((!this.buildWave && !this.loopWave) || !this.linked)
return; return;
let width = this.waveCanvas.width; let width = this.waveCanvas.width;
let now = this.core.soundManager.currentTime; let now = this.core.soundManager.currentTime;
let timespan = width / WAVE_PIXELS_PER_SECOND / 2; let timespan = width / WAVE_PIXELS_PER_SECOND / 2;
let minTime = now - timespan; let minTime = now - timespan;
let maxTime = now + timespan; let maxTime = now + timespan;
let bLen = this.core.soundManager.buildLength; let bLen = this.core.soundManager.buildLength;
let loopLen = this.core.soundManager.loopLength; let loopLen = this.core.soundManager.loopLength;
let drawTime, drawOffset; let drawTime, drawOffset;
if(bLen) { if(bLen) {
drawTime = Math.max(minTime, -bLen); drawTime = Math.max(minTime, -bLen);
@ -1251,9 +1251,9 @@ class HuesEditor {
} }
// drawOffset is "pixels from the left" // drawOffset is "pixels from the left"
drawOffset = Math.floor((drawTime - minTime) * WAVE_PIXELS_PER_SECOND); drawOffset = Math.floor((drawTime - minTime) * WAVE_PIXELS_PER_SECOND);
this.waveContext.clearRect(0, 0, width, WAVE_HEIGHT_PIXELS); this.waveContext.clearRect(0, 0, width, WAVE_HEIGHT_PIXELS);
if(this.buildWave && bLen && minTime < 0) { if(this.buildWave && bLen && minTime < 0) {
// Bit of legwork to convert negative to positive // Bit of legwork to convert negative to positive
let waveOffset = Math.floor((1 - drawTime / -bLen) * (this.buildWave.width-1)); let waveOffset = Math.floor((1 - drawTime / -bLen) * (this.buildWave.width-1));
@ -1265,21 +1265,21 @@ class HuesEditor {
// If there's more to draw after the build, it'll be from the start of the wave // If there's more to draw after the build, it'll be from the start of the wave
drawTime = 0; drawTime = 0;
} }
let loopPoints = []; let loopPoints = [];
if(this.loopWave && loopLen && maxTime > 0) { if(this.loopWave && loopLen && maxTime > 0) {
while(drawOffset < width) { while(drawOffset < width) {
if(drawTime === 0) { if(drawTime === 0) {
loopPoints.push(drawOffset); loopPoints.push(drawOffset);
} }
let waveOffset = Math.floor((drawTime / loopLen) * (this.loopWave.width-1)); let waveOffset = Math.floor((drawTime / loopLen) * (this.loopWave.width-1));
drawOffset = this.drawOneWave(this.loopWave, waveOffset, drawOffset, width); drawOffset = this.drawOneWave(this.loopWave, waveOffset, drawOffset, width);
// If we're drawing more than 1 loop it's starting at 0 // If we're drawing more than 1 loop it's starting at 0
drawTime = 0; drawTime = 0;
} }
} }
// trackbar // trackbar
this.drawWaveBar("red", width/2); this.drawWaveBar("red", width/2);
// Signify loop point with a green bar, drawing over the wave // Signify loop point with a green bar, drawing over the wave
@ -1350,7 +1350,7 @@ class HuesEditor {
let result = "<songs>\n"; let result = "<songs>\n";
result += xml; result += xml;
result += "</songs>\n"; result += "</songs>\n";
// http://stackoverflow.com/a/18197341 // http://stackoverflow.com/a/18197341
let element = document.createElement('a'); let element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result)); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
@ -1362,19 +1362,19 @@ class HuesEditor {
element.click(); element.click();
document.body.removeChild(element); document.body.removeChild(element);
window.onbeforeunload = null; window.onbeforeunload = null;
} }
// http://stackoverflow.com/a/30810322 // http://stackoverflow.com/a/30810322
copyXML() { copyXML() {
let text = this.generateXML(); let text = this.generateXML();
// Clicking when disabled // Clicking when disabled
if(!text) { if(!text) {
return; return;
} }
let textArea = document.createElement("textarea"); let textArea = document.createElement("textarea");
textArea.className = "copybox"; textArea.className = "copybox";
@ -1383,7 +1383,7 @@ class HuesEditor {
document.body.appendChild(textArea); document.body.appendChild(textArea);
textArea.select(); textArea.select();
let success; let success;
try { try {
@ -1391,7 +1391,7 @@ class HuesEditor {
} catch (err) { } catch (err) {
success = false; success = false;
} }
document.body.removeChild(textArea); document.body.removeChild(textArea);
if(success) { if(success) {
this.alert("Beatmap XML copied to clipboard!"); this.alert("Beatmap XML copied to clipboard!");
@ -1400,7 +1400,7 @@ class HuesEditor {
} }
} }
} }
window.HuesEditor = HuesEditor; window.HuesEditor = HuesEditor;
})(window, document); })(window, document);

@ -21,7 +21,7 @@
*/ */
(function(window, document) { (function(window, document) {
"use strict"; "use strict";
/* HuesInfo.js populates the INFO tab in the Hues Window. /* HuesInfo.js populates the INFO tab in the Hues Window.
*/ */
@ -74,10 +74,10 @@ function populateHuesInfo(version, huesWin, settings) {
return; return;
} }
let verString = (parseInt(version)/10).toFixed(1); let verString = (parseInt(version)/10).toFixed(1);
let info = document.createElement("div"); let info = document.createElement("div");
info.className = "hues-ref"; info.className = "hues-ref";
let huesName = settings.huesName.replace("%VERSION%", version); let huesName = settings.huesName.replace("%VERSION%", version);
let about = document.createElement("div"); let about = document.createElement("div");
about.className = "hues-about"; about.className = "hues-about";
@ -86,10 +86,10 @@ function populateHuesInfo(version, huesWin, settings) {
'<h2>Web-ified by <a target="_blank" href="https://github.com/mon">mon</a></h2>' + '<h2>Web-ified by <a target="_blank" href="https://github.com/mon">mon</a></h2>' +
'<h3>With help from <a target="_blank" href="https://github.com/kepstin/0x40hues-html5">Kepstin</a></h3>'; '<h3>With help from <a target="_blank" href="https://github.com/kepstin/0x40hues-html5">Kepstin</a></h3>';
info.appendChild(about); info.appendChild(about);
addReference(info, "Beat glossary", beatGlossary); addReference(info, "Beat glossary", beatGlossary);
addReference(info, "Keyboard shortcuts", shortcuts); addReference(info, "Keyboard shortcuts", shortcuts);
huesWin.addTab("INFO", info); huesWin.addTab("INFO", info);
} }
@ -97,11 +97,11 @@ let addReference = function(root, titleText, list) {
let ref = document.createElement("div"); let ref = document.createElement("div");
ref.className = "hues-ref__info"; ref.className = "hues-ref__info";
root.appendChild(ref); root.appendChild(ref);
let title = document.createElement("h3"); let title = document.createElement("h3");
title.textContent = titleText; title.textContent = titleText;
ref.appendChild(title); ref.appendChild(title);
let listElem = document.createElement("ul"); let listElem = document.createElement("ul");
list.forEach(function(elem) { list.forEach(function(elem) {
let item = document.createElement("li"); let item = document.createElement("li");

@ -153,11 +153,11 @@ const settingsOptions = {
}, },
autoSong : { autoSong : {
name : "AutoSong", name : "AutoSong",
options : ["off", "loop", "time", options : ["off", "loop", "time",
{type:"varText", text:function() { {type:"varText", text:function() {
// only display if autosong is on // only display if autosong is on
return this.autoSong == "off" ? "" : "after"; return this.autoSong == "off" ? "" : "after";
}}, }},
{type:"input", variable:"autoSongDelay", inputType:"int", {type:"input", variable:"autoSongDelay", inputType:"int",
visiblity:function() { visiblity:function() {
return this.autoSong != "off"; return this.autoSong != "off";
@ -215,22 +215,22 @@ class HuesSettings {
*/ */
updated : [] updated : []
}; };
let settingsVersion = "1"; let settingsVersion = "1";
if(localStorage.settingsVersion != settingsVersion) { if(localStorage.settingsVersion != settingsVersion) {
localStorage.clear(); localStorage.clear();
localStorage.settingsVersion = settingsVersion; localStorage.settingsVersion = settingsVersion;
} }
this.hasUI = false; this.hasUI = false;
this.settingCheckboxes = {}; this.settingCheckboxes = {};
this.textCallbacks = []; this.textCallbacks = [];
this.visCallbacks = []; this.visCallbacks = [];
this.ephemerals = {}; this.ephemerals = {};
for(let attr in defaultSettings) { for(let attr in defaultSettings) {
if(!defaultSettings.hasOwnProperty(attr)) { if(!defaultSettings.hasOwnProperty(attr)) {
continue; continue;
@ -238,7 +238,7 @@ class HuesSettings {
Object.defineProperty(this, attr, { Object.defineProperty(this, attr, {
set: this.makeSetter(attr), get: this.makeGetter(attr) set: this.makeSetter(attr), get: this.makeGetter(attr)
}); });
if(defaults[attr] !== undefined) { if(defaults[attr] !== undefined) {
if(defaults.overwriteLocal) { if(defaults.overwriteLocal) {
this[attr] = defaults[attr]; this[attr] = defaults[attr];
@ -247,9 +247,9 @@ class HuesSettings {
} }
} }
} }
let querySettings = this.getQuerySettings(); let querySettings = this.getQuerySettings();
for(let attr in defaultSettings) { for(let attr in defaultSettings) {
// query string overrides, finally // query string overrides, finally
if(querySettings[attr] !== undefined && attr != 'respacks') { if(querySettings[attr] !== undefined && attr != 'respacks') {
@ -259,7 +259,7 @@ class HuesSettings {
this.respacks = this.respacks.concat(querySettings.respacks); this.respacks = this.respacks.concat(querySettings.respacks);
} }
getQuerySettings() { getQuerySettings() {
let results = {}; let results = {};
results.respacks = []; results.respacks = [];
@ -288,7 +288,7 @@ class HuesSettings {
initUI(huesWin) { initUI(huesWin) {
let root = document.createElement("div"); let root = document.createElement("div");
root.className = "hues-options"; root.className = "hues-options";
// Don't make in every loop // Don't make in every loop
let intValidator = function(self, variable) { let intValidator = function(self, variable) {
this.value = this.value.replace(/\D/g,''); this.value = this.value.replace(/\D/g,'');
@ -316,7 +316,7 @@ class HuesSettings {
setContainer.className = "settings-individual"; setContainer.className = "settings-individual";
let buttonContainer = document.createElement("div"); let buttonContainer = document.createElement("div");
buttonContainer.className = "settings-buttons"; buttonContainer.className = "settings-buttons";
for(let j = 0; j < setting.options.length; j++) { for(let j = 0; j < setting.options.length; j++) {
let option = setting.options[j]; let option = setting.options[j];
if(typeof option === "string") { if(typeof option === "string") {
@ -421,7 +421,7 @@ class HuesSettings {
return true; return true;
}; };
} }
isEphemeral(setting) { isEphemeral(setting) {
return settingsOptions[setting] === undefined; return settingsOptions[setting] === undefined;
} }

@ -28,7 +28,7 @@
underneath so it can be entirely hidden. underneath so it can be entirely hidden.
*/ */
class HuesUI { class HuesUI {
constructor(parent, name) { constructor(parent, name) {
if(!parent) { if(!parent) {
return; return;
@ -60,7 +60,7 @@ class HuesUI {
this.settingsToggle = null; this.settingsToggle = null;
this.hideToggle = null; this.hideToggle = null;
// To deregister on UI hide we need to keep track of these // To deregister on UI hide we need to keep track of these
// Each callback is { name : "callbackname", func : function } // Each callback is { name : "callbackname", func : function }
// Add using this.addCoreCallback // Add using this.addCoreCallback
@ -362,10 +362,10 @@ class RetroUI extends HuesUI {
this.listContainer.className = "hues-r-listcontainer"; this.listContainer.className = "hues-r-listcontainer";
this.root.appendChild(this.listContainer); this.root.appendChild(this.listContainer);
this.visualiserContainer.className = "hues-r-visualisercontainer"; this.visualiserContainer.className = "hues-r-visualisercontainer";
this.root.appendChild(this.visualiserContainer); this.root.appendChild(this.visualiserContainer);
this.addCoreCallback("beat", this.beat.bind(this)); this.addCoreCallback("beat", this.beat.bind(this));
this.addCoreCallback("newmode", this.newMode.bind(this)); this.addCoreCallback("newmode", this.newMode.bind(this));
} }
@ -429,7 +429,7 @@ class MinimalUI extends RetroUI {
initUI() { initUI() {
super.initUI(); super.initUI();
this.root.removeChild(this.controls); this.root.removeChild(this.controls);
this.root.removeChild(this.subControls); this.root.removeChild(this.subControls);
this.container.removeChild(this.beatBar); this.container.removeChild(this.beatBar);
@ -471,7 +471,7 @@ class WeedUI extends RetroUI {
this.imageModeManual.textContent = "ONE"; this.imageModeManual.textContent = "ONE";
this.imageModeAuto.textContent = "MANY"; this.imageModeAuto.textContent = "MANY";
this.visualiserContainer.className += " hues-w-visualisercontainer"; this.visualiserContainer.className += " hues-w-visualisercontainer";
} }
@ -489,7 +489,7 @@ class WeedUI extends RetroUI {
this.beatLeft.textContent = rest; this.beatLeft.textContent = rest;
this.beatRight.textContent = rest; this.beatRight.textContent = rest;
this.beatCount.textContent = "B=" + this.intToHex(index, 4); this.beatCount.textContent = "B=" + this.intToHex(index, 4);
if(["x", "o", "X", "O"].indexOf(beats[0]) != -1) { if(["x", "o", "X", "O"].indexOf(beats[0]) != -1) {
@ -520,7 +520,7 @@ class WeedUI extends RetroUI {
class ModernUI extends HuesUI { class ModernUI extends HuesUI {
constructor(parent, name) { constructor(parent, name) {
super(parent, name ? name : "ModernUI"); super(parent, name ? name : "ModernUI");
this.textSize_normal = 0; this.textSize_normal = 0;
this.textSize_small = 0; this.textSize_small = 0;
this.songLink_size = 0; this.songLink_size = 0;
@ -655,7 +655,7 @@ class ModernUI extends HuesUI {
this.leftInfo = leftInfo; this.leftInfo = leftInfo;
controls.appendChild(leftInfo); controls.appendChild(leftInfo);
controls.appendChild(rightInfo); controls.appendChild(rightInfo);
this.visualiserContainer.className = "hues-m-visualisercontainer"; this.visualiserContainer.className = "hues-m-visualisercontainer";
controls.appendChild(this.visualiserContainer); controls.appendChild(this.visualiserContainer);
@ -688,7 +688,7 @@ class ModernUI extends HuesUI {
this.listContainer.className = "hues-m-listcontainer"; this.listContainer.className = "hues-m-listcontainer";
this.root.appendChild(this.listContainer); this.root.appendChild(this.listContainer);
this.addCoreCallback("beat", this.beat.bind(this)); this.addCoreCallback("beat", this.beat.bind(this));
this.addCoreCallback("newmode", this.newMode.bind(this)); this.addCoreCallback("newmode", this.newMode.bind(this));
} }
@ -762,9 +762,9 @@ class ModernUI extends HuesUI {
// We override this just after so don't bother to restore it // We override this just after so don't bother to restore it
el.className = className; el.className = className;
let size = el.offsetWidth / 100; let size = el.offsetWidth / 100;
el.innerHTML = oldContent; el.innerHTML = oldContent;
return size; return size;
} }
@ -824,10 +824,10 @@ class XmasUI extends ModernUI {
constructor(parent, name) { constructor(parent, name) {
super(parent, name ? name : "XmasUI"); super(parent, name ? name : "XmasUI");
this.initSnow(); this.initSnow();
// This will cache our inverted lights images // This will cache our inverted lights images
this.invert(true); this.invert(true);
this.controls.removeChild(this.leftBox); this.controls.removeChild(this.leftBox);
this.controls.removeChild(this.rightBox); this.controls.removeChild(this.rightBox);
this.controls.removeChild(this.rightInfo); this.controls.removeChild(this.rightInfo);
@ -885,15 +885,15 @@ class XmasUI extends ModernUI {
bottomHelper.appendChild(bottom); bottomHelper.appendChild(bottom);
wires.appendChild(bottomHelper); wires.appendChild(bottomHelper);
this.root.appendChild(wires); this.root.appendChild(wires);
this.visualiserContainer.className = "hues-x-visualisercontainer"; this.visualiserContainer.className = "hues-x-visualisercontainer";
this.controls.removeChild(this.visualiserContainer); this.controls.removeChild(this.visualiserContainer);
this.beatBar.appendChild(this.visualiserContainer); this.beatBar.appendChild(this.visualiserContainer);
} }
invert(invert) { invert(invert) {
super.invert(invert); super.invert(invert);
if(invert) { if(invert) {
this.snowContext.fillStyle = "rgba(0, 0, 0, 0.8)"; this.snowContext.fillStyle = "rgba(0, 0, 0, 0.8)";
} else { } else {
@ -963,11 +963,11 @@ class XmasUI extends ModernUI {
if(this.currentBeat != ".") { if(this.currentBeat != ".") {
this.lights.forEach(function(light, i, a) { this.lights.forEach(function(light, i, a) {
switch(this.currentBeat) { switch(this.currentBeat) {
case ":": case ":":
this.lightOn(light); this.lightOn(light);
this.lightRecolour(light); this.lightRecolour(light);
break; break;
case "+": case "+":
this.lightFadeOut(light); this.lightFadeOut(light);
break; break;
default: default:
@ -984,7 +984,7 @@ class XmasUI extends ModernUI {
this.snowCanvas.height = 720; this.snowCanvas.height = 720;
this.snowCanvas.style.display = "none"; this.snowCanvas.style.display = "none";
this.snowCanvas.className = "hues-canvas hues-x-snow"; this.snowCanvas.className = "hues-canvas hues-x-snow";
this.root.appendChild(this.snowCanvas); this.root.appendChild(this.snowCanvas);
this.snowing = false; this.snowing = false;
@ -992,7 +992,7 @@ class XmasUI extends ModernUI {
this.snowAngle = 0; this.snowAngle = 0;
this.lastSnow = 0; this.lastSnow = 0;
this.snowflakes = []; this.snowflakes = [];
this.addCoreCallback("frame", this.drawSnow.bind(this)); this.addCoreCallback("frame", this.drawSnow.bind(this));
} }
@ -1070,7 +1070,7 @@ class XmasUI extends ModernUI {
resize() { resize() {
super.resize(); super.resize();
let ratio = window.innerWidth / window.innerHeight; let ratio = window.innerWidth / window.innerHeight;
// cleared on resize // cleared on resize
let savedFill = this.snowContext.fillStyle; let savedFill = this.snowContext.fillStyle;
@ -1092,13 +1092,13 @@ class HalloweenUI extends ModernUI {
initUI() { initUI() {
super.initUI(); super.initUI();
this.controls.className += " hues-h-controls"; this.controls.className += " hues-h-controls";
this.beatBar.className += " hues-h-beatbar"; this.beatBar.className += " hues-h-beatbar";
this.leftBox.className += " hues-h-leftbox"; this.leftBox.className += " hues-h-leftbox";
this.rightBox.className += " hues-h-rightbox"; this.rightBox.className += " hues-h-rightbox";
this.volBar.className += " hues-h-vol-bar"; this.volBar.className += " hues-h-vol-bar";
this.beatLeft.className += " hues-h-text"; this.beatLeft.className += " hues-h-text";
this.beatRight.className += " hues-h-text"; this.beatRight.className += " hues-h-text";
this.beatCenter.className += " hues-h-text"; this.beatCenter.className += " hues-h-text";
@ -1113,47 +1113,47 @@ class HalloweenUI extends ModernUI {
this.imageList.className += " hues-h-text"; this.imageList.className += " hues-h-text";
this.imageName.className += " hues-h-text"; this.imageName.className += " hues-h-text";
this.hueName.className += " hues-h-text"; this.hueName.className += " hues-h-text";
this.settingsToggle.className += " hues-h-text"; this.settingsToggle.className += " hues-h-text";
this.hideToggle.className += " hues-h-text"; this.hideToggle.className += " hues-h-text";
this.infoToggle.className += " hues-h-text"; this.infoToggle.className += " hues-h-text";
this.volLabel.className += " hues-h-text"; this.volLabel.className += " hues-h-text";
this.timer.className = "hues-h-textfade"; this.timer.className = "hues-h-textfade";
this.beatCount.className = "hues-h-textfade"; this.beatCount.className = "hues-h-textfade";
this.xBlur.className = "hues-h-textfade"; this.xBlur.className = "hues-h-textfade";
this.yBlur.className = "hues-h-textfade"; this.yBlur.className = "hues-h-textfade";
let leftBoxTomb = document.createElement("div"); let leftBoxTomb = document.createElement("div");
leftBoxTomb.className = "hues-h-tombstone"; leftBoxTomb.className = "hues-h-tombstone";
this.leftBox.appendChild(leftBoxTomb); this.leftBox.appendChild(leftBoxTomb);
let songTomb = document.createElement("div"); let songTomb = document.createElement("div");
songTomb.className = "hues-h-tombstone"; songTomb.className = "hues-h-tombstone";
this.songBlock.insertBefore(songTomb,this.songBlock.firstChild); this.songBlock.insertBefore(songTomb,this.songBlock.firstChild);
let imageTomb = document.createElement("div"); let imageTomb = document.createElement("div");
imageTomb.className = "hues-h-tombstone"; imageTomb.className = "hues-h-tombstone";
this.imageBlock.insertBefore(imageTomb,this.imageBlock.firstChild); this.imageBlock.insertBefore(imageTomb,this.imageBlock.firstChild);
let topLeft = document.createElement("div"); let topLeft = document.createElement("div");
topLeft.className = "hues-h-topleft"; topLeft.className = "hues-h-topleft";
let topRight = document.createElement("div"); let topRight = document.createElement("div");
topRight.className = "hues-h-topright"; topRight.className = "hues-h-topright";
let bottomRight = document.createElement("div"); let bottomRight = document.createElement("div");
bottomRight.className = "hues-h-bottomright"; bottomRight.className = "hues-h-bottomright";
this.root.appendChild(topLeft); this.root.appendChild(topLeft);
this.root.appendChild(topRight); this.root.appendChild(topRight);
this.root.appendChild(bottomRight); this.root.appendChild(bottomRight);
let leftHand = document.createElement("div"); let leftHand = document.createElement("div");
leftHand.className = "hues-h-left-hand"; leftHand.className = "hues-h-left-hand";
this.beatBar.appendChild(leftHand); this.beatBar.appendChild(leftHand);
let rightHand = document.createElement("div"); let rightHand = document.createElement("div");
rightHand.className = "hues-h-right-hand"; rightHand.className = "hues-h-right-hand";
this.beatBar.appendChild(rightHand); this.beatBar.appendChild(rightHand);
this.vignette = document.createElement("div"); this.vignette = document.createElement("div");
this.vignette.className = "hues-h-vignette"; this.vignette.className = "hues-h-vignette";
this.root.appendChild(this.vignette); this.root.appendChild(this.vignette);
@ -1161,7 +1161,7 @@ class HalloweenUI extends ModernUI {
beat(beats, index) { beat(beats, index) {
super.beat(beats, index); super.beat(beats, index);
if (this.currentBeat != ".") { if (this.currentBeat != ".") {
let eyes = this.beatCenter.ownerDocument.createElement("div"); let eyes = this.beatCenter.ownerDocument.createElement("div");
eyes.className = "hues-m-beatcenter hues-h-eyes"; eyes.className = "hues-m-beatcenter hues-h-eyes";
@ -1171,13 +1171,13 @@ class HalloweenUI extends ModernUI {
connectCore(core) { connectCore(core) {
super.connectCore(core); super.connectCore(core);
this.core.preloader.classList.add("hues-h-text"); this.core.preloader.classList.add("hues-h-text");
} }
disconnect() { disconnect() {
this.core.preloader.classList.remove("hues-h-text"); this.core.preloader.classList.remove("hues-h-text");
super.disconnect(); super.disconnect();
} }
} }

@ -20,7 +20,7 @@
*/ */
(function(window, document) { (function(window, document) {
"use strict"; "use strict";
class HuesWindow { class HuesWindow {
constructor(root, settings) { constructor(root, settings) {
@ -37,38 +37,38 @@ class HuesWindow {
*/ */
tabselected : [] tabselected : []
}; };
this.hasUI = settings.enableWindow; this.hasUI = settings.enableWindow;
if(!this.hasUI) if(!this.hasUI)
return; return;
this.window = document.createElement("div"); this.window = document.createElement("div");
this.window.className = "hues-win-helper"; this.window.className = "hues-win-helper";
root.appendChild(this.window); root.appendChild(this.window);
let actualWindow = document.createElement("div"); let actualWindow = document.createElement("div");
actualWindow.className = "hues-win"; actualWindow.className = "hues-win";
this.window.appendChild(actualWindow); this.window.appendChild(actualWindow);
let closeButton = document.createElement("div"); let closeButton = document.createElement("div");
closeButton.className = "hues-win__closebtn"; closeButton.className = "hues-win__closebtn";
closeButton.onclick = this.hide.bind(this); closeButton.onclick = this.hide.bind(this);
actualWindow.appendChild(closeButton); actualWindow.appendChild(closeButton);
this.tabContainer = document.createElement("div"); this.tabContainer = document.createElement("div");
this.tabContainer.className = "hues-win__tabs"; this.tabContainer.className = "hues-win__tabs";
actualWindow.appendChild(this.tabContainer); actualWindow.appendChild(this.tabContainer);
this.contentContainer = document.createElement("div"); this.contentContainer = document.createElement("div");
this.contentContainer.className = "hues-win__content"; this.contentContainer.className = "hues-win__content";
actualWindow.appendChild(this.contentContainer); actualWindow.appendChild(this.contentContainer);
this.contents = []; this.contents = [];
this.tabs = []; this.tabs = [];
this.tabNames = []; this.tabNames = [];
if(settings.showWindow) { if(settings.showWindow) {
this.show(); this.show();
} else { } else {
@ -79,7 +79,7 @@ class HuesWindow {
addTab(tabName, tabContent) { addTab(tabName, tabContent) {
if(!this.hasUI) if(!this.hasUI)
return; return;
let label = document.createElement("div"); let label = document.createElement("div");
label.textContent = tabName; label.textContent = tabName;
label.className = "tab-label"; label.className = "tab-label";
@ -87,7 +87,7 @@ class HuesWindow {
this.tabContainer.appendChild(label); this.tabContainer.appendChild(label);
this.tabs.push(label); this.tabs.push(label);
this.tabNames.push(tabName); this.tabNames.push(tabName);
let content = document.createElement("div"); let content = document.createElement("div");
content.className = "tab-content"; content.className = "tab-content";
content.appendChild(tabContent); content.appendChild(tabContent);
@ -117,7 +117,7 @@ class HuesWindow {
hide() { hide() {
if(!this.hasUI) if(!this.hasUI)
return; return;
this.window.classList.add("hidden"); this.window.classList.add("hidden");
this.callEventListeners("windowshown", false); this.callEventListeners("windowshown", false);
} }
@ -125,7 +125,7 @@ class HuesWindow {
show() { show() {
if(!this.hasUI) if(!this.hasUI)
return; return;
this.window.classList.remove("hidden"); this.window.classList.remove("hidden");
this.callEventListeners("windowshown", true); this.callEventListeners("windowshown", true);
} }

@ -92,7 +92,7 @@ class Resources {
Returns an Promise.all which will resolve to an array of sizes */ Returns an Promise.all which will resolve to an array of sizes */
getSizes(urls) { getSizes(urls) {
let promises = []; let promises = [];
urls.forEach(url => { urls.forEach(url => {
let p = new Promise((resolve, reject) => { let p = new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest(); let xhr = new XMLHttpRequest();
@ -117,7 +117,7 @@ class Resources {
}); });
promises.push(p); promises.push(p);
}); });
return Promise.all(promises); return Promise.all(promises);
} }
@ -128,14 +128,14 @@ class Resources {
this.progressCallback = progressCallback; this.progressCallback = progressCallback;
this.progressState = Array.apply(null, Array(urls.length)).map(Number.prototype.valueOf,0); this.progressState = Array.apply(null, Array(urls.length)).map(Number.prototype.valueOf,0);
} }
let respackPromises = []; let respackPromises = [];
let progressFunc = function(index, progress, pack) { let progressFunc = function(index, progress, pack) {
this.progressState[index] = progress; this.progressState[index] = progress;
this.updateProgress(pack); this.updateProgress(pack);
}; };
for(let i = 0; i < urls.length; i++) { for(let i = 0; i < urls.length; i++) {
let r = new Respack(); let r = new Respack();
respackPromises.push(r.loadFromURL(urls[i], progressFunc.bind(this, i))); respackPromises.push(r.loadFromURL(urls[i], progressFunc.bind(this, i)));
@ -266,7 +266,7 @@ class Resources {
loadLocal() { loadLocal() {
console.log("Loading local zip(s)"); console.log("Loading local zip(s)");
let files = this.fileInput.files; let files = this.fileInput.files;
let p = Promise.resolve(); let p = Promise.resolve();
for(let i = 0; i < files.length; i++) { for(let i = 0; i < files.length; i++) {
@ -310,7 +310,7 @@ class Resources {
initUI() { initUI() {
this.root = document.createElement("div"); this.root = document.createElement("div");
this.root.className = "respacks"; this.root.className = "respacks";
let packsContainer = document.createElement("div"); let packsContainer = document.createElement("div");
packsContainer.className = "respacks__manager"; packsContainer.className = "respacks__manager";
@ -415,10 +415,10 @@ class Resources {
let packDesc = document.createElement("div"); let packDesc = document.createElement("div");
packDesc.className = "respack-description"; packDesc.className = "respack-description";
packDesc.textContent = "<no description>"; packDesc.textContent = "<no description>";
let tabContainer = document.createElement("div"); let tabContainer = document.createElement("div");
tabContainer.className = "respack-tab-container"; tabContainer.className = "respack-tab-container";
let songCount = document.createElement("div"); let songCount = document.createElement("div");
songCount.textContent = "Songs:"; songCount.textContent = "Songs:";
songCount.className = "respack-tab respack-tab--checked"; songCount.className = "respack-tab respack-tab--checked";
@ -431,24 +431,24 @@ class Resources {
songList.className = "resource-list respack-tab__content respack-tab__content--checked"; songList.className = "resource-list respack-tab__content respack-tab__content--checked";
let imageList = document.createElement("div"); let imageList = document.createElement("div");
imageList.className = "resource-list respack-tab__content"; imageList.className = "resource-list respack-tab__content";
songCount.onclick = () => { songCount.onclick = () => {
songCount.classList.add("respack-tab--checked"); songCount.classList.add("respack-tab--checked");
imageCount.classList.remove("respack-tab--checked"); imageCount.classList.remove("respack-tab--checked");
songList.classList.add("respack-tab__content--checked"); songList.classList.add("respack-tab__content--checked");
imageList.classList.remove("respack-tab__content--checked"); imageList.classList.remove("respack-tab__content--checked");
this.currentTab = TAB_SONGS; this.currentTab = TAB_SONGS;
}; };
imageCount.onclick = () => { imageCount.onclick = () => {
imageCount.classList.add("respack-tab--checked"); imageCount.classList.add("respack-tab--checked");
songCount.classList.remove("respack-tab--checked"); songCount.classList.remove("respack-tab--checked");
imageList.classList.add("respack-tab__content--checked"); imageList.classList.add("respack-tab__content--checked");
songList.classList.remove("respack-tab__content--checked"); songList.classList.remove("respack-tab__content--checked");
this.currentTab = TAB_IMAGES; this.currentTab = TAB_IMAGES;
}; };
@ -509,13 +509,13 @@ class Resources {
indivView.appendChild(packName); indivView.appendChild(packName);
indivView.appendChild(packInfo); indivView.appendChild(packInfo);
indivView.appendChild(packDesc); indivView.appendChild(packDesc);
tabContainer.appendChild(songCount); tabContainer.appendChild(songCount);
tabContainer.appendChild(imageCount); tabContainer.appendChild(imageCount);
indivView.appendChild(tabContainer); indivView.appendChild(tabContainer);
indivView.appendChild(songList); indivView.appendChild(songList);
indivView.appendChild(imageList); indivView.appendChild(imageList);
indivView.appendChild(packButtons); indivView.appendChild(packButtons);
indivView.appendChild(totalCounts); indivView.appendChild(totalCounts);
@ -530,7 +530,7 @@ class Resources {
this.listView.appendChild(this.enabledSongList); this.listView.appendChild(this.enabledSongList);
this.listView.appendChild(this.enabledImageList); this.listView.appendChild(this.enabledImageList);
this.hasUI = true; this.hasUI = true;
} }

@ -287,7 +287,7 @@ class Respack {
console.log("WARNING: Image", name, "already exists! Conflict with", file.name, "and", existing.name); console.log("WARNING: Image", name, "already exists! Conflict with", file.name, "and", existing.name);
return; return;
} }
return this.loadImage(file, img); return this.loadImage(file, img);
} }
@ -420,7 +420,7 @@ class Respack {
newSongs.push(song); newSongs.push(song);
debug(" [I] " + song.name, ": '" + song.title + "' added to songs"); debug(" [I] " + song.name, ": '" + song.title + "' added to songs");
} else { } else {
debug(" WARNING!", "songs.xml: <song> element", debug(" WARNING!", "songs.xml: <song> element",
+ el.attributes[0].value + "- no song found"); + el.attributes[0].value + "- no song found");
} }
} }

@ -32,12 +32,12 @@ class SoundManager {
*/ */
seek : [] seek : []
}; };
this.core = core; this.core = core;
this.playing = false; this.playing = false;
this.playbackRate = 1; this.playbackRate = 1;
this.song = null; this.song = null;
this.initPromise = null; this.initPromise = null;
this.lockedPromise = null; this.lockedPromise = null;
this.locked = true; this.locked = true;
@ -57,7 +57,7 @@ class SoundManager {
this.gainNode = null; this.gainNode = null;
this.mute = false; this.mute = false;
this.lastVol = 1; this.lastVol = 1;
// Visualiser // Visualiser
this.vReady = false; this.vReady = false;
this.vBars = 0; this.vBars = 0;
@ -71,7 +71,7 @@ class SoundManager {
this.logBins = 0; this.logBins = 0;
this.maxBinLin = 0; this.maxBinLin = 0;
} }
callEventListeners(ev) { callEventListeners(ev) {
let args = Array.prototype.slice.call(arguments, 1); let args = Array.prototype.slice.call(arguments, 1);
this.eventListeners[ev].forEach(function(callback) { this.eventListeners[ev].forEach(function(callback) {
@ -109,7 +109,7 @@ class SoundManager {
// These don't always exist // These don't always exist
AudioContext.prototype.suspend = AudioContext.prototype.suspend || (() => {return Promise.resolve();}); AudioContext.prototype.suspend = AudioContext.prototype.suspend || (() => {return Promise.resolve();});
AudioContext.prototype.resume = AudioContext.prototype.resume || (() => {return Promise.resolve();}); AudioContext.prototype.resume = AudioContext.prototype.resume || (() => {return Promise.resolve();});
this.context = new window.AudioContext(); this.context = new window.AudioContext();
this.gainNode = this.context.createGain(); this.gainNode = this.context.createGain();
this.gainNode.connect(this.context.destination); this.gainNode.connect(this.context.destination);
@ -130,7 +130,7 @@ class SoundManager {
}); });
}); });
}).then(() => { }).then(() => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// See if our audio decoder is working // See if our audio decoder is working
let audioWorker; let audioWorker;
try { try {
@ -175,7 +175,7 @@ class SoundManager {
// play the file // play the file
source.start(0); source.start(0);
window.removeEventListener('touchend', unlocker); window.removeEventListener('touchend', unlocker);
window.removeEventListener('click', unlocker); window.removeEventListener('click', unlocker);
this.core.clearMessage(); this.core.clearMessage();
@ -198,7 +198,7 @@ class SoundManager {
if(!song || (!song.sound)) { // null song if(!song || (!song.sound)) { // null song
return p; return p;
} }
// if there's a fadeout happening from AutoSong, kill it // if there's a fadeout happening from AutoSong, kill it
this.gainNode.gain.cancelScheduledValues(0); this.gainNode.gain.cancelScheduledValues(0);
// Reset original volume // Reset original volume
@ -214,7 +214,7 @@ class SoundManager {
if(song != this.song) { if(song != this.song) {
return Promise.reject("Song changed between load and play - this message can be ignored"); return Promise.reject("Song changed between load and play - this message can be ignored");
} }
this.buildup = buffers.buildup; this.buildup = buffers.buildup;
this.buildLength = this.buildup ? this.buildup.duration : 0; this.buildLength = this.buildup ? this.buildup.duration : 0;
this.loop = buffers.loop; this.loop = buffers.loop;
@ -228,7 +228,7 @@ class SoundManager {
} else { } else {
this.seek(0, true); this.seek(0, true);
} }
return this.context.resume(); return this.context.resume();
}).then(() => { }).then(() => {
this.playing = true; this.playing = true;
@ -244,7 +244,7 @@ class SoundManager {
this.buildSource = null; this.buildSource = null;
if(!dontDeleteBuffers) if(!dontDeleteBuffers)
this.buildup = null; this.buildup = null;
} }
// arg required for mobile webkit // arg required for mobile webkit
this.loopSource.stop(0); this.loopSource.stop(0);
// TODO needed? // TODO needed?
@ -261,7 +261,7 @@ class SoundManager {
setRate(rate) { setRate(rate) {
// Double speed is more than enough. Famous last words? // Double speed is more than enough. Famous last words?
rate = Math.max(Math.min(rate, 2), 0.25); rate = Math.max(Math.min(rate, 2), 0.25);
let time = this.clampedTime; let time = this.clampedTime;
this.playbackRate = rate; this.playbackRate = rate;
this.seek(time); this.seek(time);
@ -271,19 +271,19 @@ class SoundManager {
if(!this.song) { if(!this.song) {
return; return;
} }
this.callEventListeners("seek"); this.callEventListeners("seek");
//console.log("Seeking to " + time); //console.log("Seeking to " + time);
// Clamp the blighter // Clamp the blighter
time = Math.min(Math.max(time, -this.buildLength), this.loopLength); time = Math.min(Math.max(time, -this.buildLength), this.loopLength);
this.stop(true); this.stop(true);
if(!this.loop) { if(!this.loop) {
return; return;
} }
this.loopSource = this.context.createBufferSource(); this.loopSource = this.context.createBufferSource();
this.loopSource.buffer = this.loop; this.loopSource.buffer = this.loop;
this.loopSource.playbackRate.value = this.playbackRate; this.loopSource.playbackRate.value = this.playbackRate;
@ -291,7 +291,7 @@ class SoundManager {
this.loopSource.loopStart = 0; this.loopSource.loopStart = 0;
this.loopSource.loopEnd = this.loopLength; this.loopSource.loopEnd = this.loopLength;
this.loopSource.connect(this.gainNode); this.loopSource.connect(this.gainNode);
if(time < 0 && this.buildup) { if(time < 0 && this.buildup) {
this.buildSource = this.context.createBufferSource(); this.buildSource = this.context.createBufferSource();
this.buildSource.buffer = this.buildup; this.buildSource.buffer = this.buildup;
@ -302,7 +302,7 @@ class SoundManager {
} else { } else {
this.loopSource.start(0, time); this.loopSource.start(0, time);
} }
this.startTime = this.context.currentTime - (time / this.playbackRate); this.startTime = this.context.currentTime - (time / this.playbackRate);
if(!noPlayingUpdate) { if(!noPlayingUpdate) {
this.playing = true; this.playing = true;
@ -321,7 +321,7 @@ class SoundManager {
get clampedTime() { get clampedTime() {
let time = this.currentTime; let time = this.currentTime;
if(time > 0) { if(time > 0) {
time %= this.loopLength; time %= this.loopLength;
} }
@ -336,9 +336,9 @@ class SoundManager {
NOTE: If anything but playSong calls loadSong, this idea is broken. */ NOTE: If anything but playSong calls loadSong, this idea is broken. */
return Promise.reject("Song changed between load and play - this message can be ignored"); return Promise.reject("Song changed between load and play - this message can be ignored");
} }
let buffers = {loop: null, buildup: null}; let buffers = {loop: null, buildup: null};
let promises = [this.loadBuffer(song, "sound").then(buffer => { let promises = [this.loadBuffer(song, "sound").then(buffer => {
buffers.loop = buffer; buffers.loop = buffer;
})]; })];
@ -359,7 +359,7 @@ class SoundManager {
loadBuffer(song, soundName) { loadBuffer(song, soundName) {
let buffer = song[soundName]; let buffer = song[soundName];
// Is this an ogg file? // Is this an ogg file?
let view = new Uint8Array(buffer); let view = new Uint8Array(buffer);
// Signature for ogg file: OggS // Signature for ogg file: OggS
@ -380,15 +380,15 @@ class SoundManager {
} else { // Use our JS decoder } else { // Use our JS decoder
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let audioWorker = this.createWorker(); let audioWorker = this.createWorker();
audioWorker.addEventListener('error', () => { audioWorker.addEventListener('error', () => {
reject(Error("Audio Worker failed to convert track")); reject(Error("Audio Worker failed to convert track"));
}, false); }, false);
audioWorker.addEventListener('message', e => { audioWorker.addEventListener('message', e => {
let decoded = e.data; let decoded = e.data;
audioWorker.terminate(); audioWorker.terminate();
// restore transferred buffer // restore transferred buffer
song[soundName] = decoded.arrayBuffer; song[soundName] = decoded.arrayBuffer;
if(decoded.error) { if(decoded.error) {
@ -399,7 +399,7 @@ class SoundManager {
let audio = this.audioBufFromRaw(decoded.rawAudio); let audio = this.audioBufFromRaw(decoded.rawAudio);
resolve(audio); resolve(audio);
}, false); }, false);
// transfer the buffer to save time // transfer the buffer to save time
audioWorker.postMessage({buffer: buffer, ogg: this.oggSupport}, [buffer]); audioWorker.postMessage({buffer: buffer, ogg: this.oggSupport}, [buffer]);
}); });
@ -448,11 +448,11 @@ class SoundManager {
this.analyserArrays = []; this.analyserArrays = [];
this.logArrays = []; this.logArrays = [];
this.binCutoffs = []; this.binCutoffs = [];
this.linBins = 0; this.linBins = 0;
this.logBins = 0; this.logBins = 0;
this.maxBinLin = 0; this.maxBinLin = 0;
this.attachVisualiser(); this.attachVisualiser();
} }
@ -472,7 +472,7 @@ class SoundManager {
} }
// Split display up into each channel // Split display up into each channel
this.vBars = Math.floor(this.vTotalBars/channels); this.vBars = Math.floor(this.vTotalBars/channels);
for(let i = 0; i < channels; i++) { for(let i = 0; i < channels; i++) {
let analyser = this.context.createAnalyser(); let analyser = this.context.createAnalyser();
// big fft buffers are new-ish // big fft buffers are new-ish
@ -487,7 +487,7 @@ class SoundManager {
analyser.maxDecibels = -25; analyser.maxDecibels = -25;
this.analyserArrays.push(new Uint8Array(analyser.frequencyBinCount)); this.analyserArrays.push(new Uint8Array(analyser.frequencyBinCount));
analyser.getByteTimeDomainData(this.analyserArrays[i]); analyser.getByteTimeDomainData(this.analyserArrays[i]);
this.splitter.connect(analyser, i); this.splitter.connect(analyser, i);
this.analysers.push(analyser); this.analysers.push(analyser);
this.logArrays.push(new Uint8Array(this.vBars)); this.logArrays.push(new Uint8Array(this.vBars));
} }
@ -528,7 +528,7 @@ class SoundManager {
let data = this.analyserArrays[a]; let data = this.analyserArrays[a];
let result = this.logArrays[a]; let result = this.logArrays[a];
this.analysers[a].getByteFrequencyData(data); this.analysers[a].getByteFrequencyData(data);
for(let i = 0; i < this.linBins; i++) { for(let i = 0; i < this.linBins; i++) {
let scaled = Math.round(i * this.maxBinLin / this.linBins); let scaled = Math.round(i * this.maxBinLin / this.linBins);
result[i] = data[scaled]; result[i] = data[scaled];
@ -536,7 +536,7 @@ class SoundManager {
result[this.linBins] = data[this.binCutoffs[0]]; result[this.linBins] = data[this.binCutoffs[0]];
for(let i = this.linBins+1; i < this.vBars; i++) { for(let i = this.linBins+1; i < this.vBars; i++) {
let cutoff = i - this.linBins; let cutoff = i - this.linBins;
result[i] = this.sumArray(data, this.binCutoffs[cutoff-1], result[i] = this.sumArray(data, this.binCutoffs[cutoff-1],
this.binCutoffs[cutoff]); this.binCutoffs[cutoff]);
} }
} }
@ -589,7 +589,7 @@ class SoundManager {
} }
} }
let miniOggRaw = let miniOggRaw =
"T2dnUwACAAAAAAAAAADFYgAAAAAAAMLKRdwBHgF2b3JiaXMAAAAAAUSsAAAA" + "T2dnUwACAAAAAAAAAADFYgAAAAAAAMLKRdwBHgF2b3JiaXMAAAAAAUSsAAAA" +
"AAAAgLsAAAAAAAC4AU9nZ1MAAAAAAAAAAAAAxWIAAAEAAACcKCV2Dzv/////" + "AAAAgLsAAAAAAAC4AU9nZ1MAAAAAAAAAAAAAxWIAAAEAAACcKCV2Dzv/////" +
"////////////MgN2b3JiaXMrAAAAWGlwaC5PcmcgbGliVm9yYmlzIEkgMjAx" + "////////////MgN2b3JiaXMrAAAAWGlwaC5PcmcgbGliVm9yYmlzIEkgMjAx" +

Loading…
Cancel
Save