From 55cac0a454082ab90bd691b1461c1841f39904d5 Mon Sep 17 00:00:00 2001
From: EnderDragonneau <30511303+EnderDragonneau@users.noreply.github.com>
Date: Mon, 22 Jul 2019 22:51:29 +0200
Subject: [PATCH] Complete rewrite of the script
---
.eslintignore | 1 +
.eslintrc | 61 +
.gitignore | 3 +
.prettierrc | 18 +
README.md | 8 +-
build/drawception-anbt.user.js | 2312 ++++++++++++
build/index.html | 174 +
build/newcanvas/index.html | 170 +
build/newcanvas/pako.js | 1 +
build/newcanvas/pathseg.js | 1 +
build/newcanvas/script.js | 1 +
build/newcanvas/style.css | 1 +
copypost.py | 2 +-
drawception-anbt.user.js | 2847 --------------
newcanvas/drawit.css | 526 ---
newcanvas/drawit.js | 2761 --------------
newcanvas/favicon.png | Bin 323 -> 0 bytes
newcanvas/index.html | 138 -
newcanvas/newcanvasicons.png | Bin 3810 -> 0 bytes
newcanvas/nunito.woff | Bin 27584 -> 0 bytes
newcanvas/pako.min.js | 3 -
newcanvas/pathseg.min.js | 173 -
newcanvas/whammy.min.js | 39 -
newcanvas/yanone.woff | Bin 34460 -> 0 bytes
newcanvas_embedding.html | 3255 -----------------
package.json | 31 +
rollup.config.js | 125 +
src/extension.js | 25 +
src/extension/banner.js | 17 +
src/extension/betterPages.js | 17 +
src/extension/functions/addMarkdownTools.js | 24 +
src/extension/functions/addStyle.js | 10 +
src/extension/functions/base62ToDecimal.js | 19 +
.../functions/betterPages/betterCreate.js | 13 +
.../functions/betterPages/betterForums.js | 151 +
.../functions/betterPages/betterGame.js | 88 +
.../functions/betterPages/betterPanel.js | 108 +
.../functions/betterPages/betterPlayer.js | 118 +
.../functions/betterPages/betterSettings.js | 150 +
.../functions/comment/betterComments.js | 123 +
.../functions/comment/waitForComments.js | 16 +
src/extension/functions/cookie/getCookie.js | 4 +
src/extension/functions/cookie/setCookie.js | 12 +
.../functions/darkMode/addDarkCSS.js | 53 +
.../functions/darkMode/setDarkMode.js | 25 +
.../functions/darkMode/toggleLight.js | 31 +
src/extension/functions/decimalToBase62.js | 13 +
src/extension/functions/fade/fadeIn.js | 14 +
src/extension/functions/fade/fadeOut.js | 15 +
.../functions/getLocalStorageItem.js | 10 +
src/extension/functions/getNotifications.js | 22 +
src/extension/functions/getPanelId.js | 6 +
src/extension/functions/getSelectedText.js | 19 +
.../functions/linkifyDrawingPanels.js | 33 +
src/extension/functions/linkifyNodeText.js | 9 +
src/extension/functions/markdown/bold.js | 58 +
src/extension/functions/markdown/code.js | 38 +
src/extension/functions/markdown/heading.js | 42 +
.../functions/markdown/highlighter.js | 52 +
src/extension/functions/markdown/image.js | 57 +
src/extension/functions/markdown/italic.js | 57 +
src/extension/functions/markdown/link.js | 54 +
src/extension/functions/markdown/listOl.js | 68 +
src/extension/functions/markdown/listUl.js | 57 +
.../functions/markdown/quoteRight.js | 57 +
.../functions/markdown/strikethrough.js | 63 +
src/extension/functions/pageEnhancements.js | 197 +
src/extension/functions/randomGreeting.js | 13 +
.../functions/replay/addReplayButton.js | 27 +
.../functions/replay/addReplaySign.js | 24 +
.../functions/replay/checkForRecording.js | 31 +
src/extension/functions/reversePanels.js | 10 +
src/extension/functions/rot13.js | 11 +
src/extension/functions/scrambleID.js | 10 +
src/extension/functions/selector.js | 8 +
src/extension/functions/settings/addGroup.js | 44 +
.../functions/settings/escapeHTML.js | 10 +
.../functions/settings/loadScriptSettings.js | 9 +
.../settings/updateScriptSettings.js | 23 +
src/extension/functions/setupNewCanvas.js | 116 +
src/extension/functions/simpleHash.js | 10 +
.../functions/time/convertForumTime.js | 11 +
.../functions/time/formatTimestamp.js | 14 +
src/extension/functions/time/isFloridaDST.js | 23 +
src/extension/functions/unscrambleID.js | 6 +
.../functions/viewMyGameBookmarks.js | 87 +
.../functions/viewMyPanelFavorites.js | 52 +
src/extension/globals.js | 50 +
src/extension/markdown.js | 60 +
src/extension/options.js | 32 +
src/extension/versions.js | 7 +
src/extension/wrapper.js | 21 +
src/newcanvas.js | 15 +
src/newcanvas/css/style.scss | 832 +++++
src/newcanvas/html/index.html | 170 +
src/newcanvas/js/anbt.js | 120 +
src/newcanvas/js/functions/anbt/addToSvg.js | 19 +
.../js/functions/anbt/bindContainer.js | 31 +
.../js/functions/anbt/clearWithColor.js | 19 +
.../cutHistoryBeforeClearAndAfterPosition.js | 17 +
.../js/functions/anbt/drawDispLine.js | 15 +
.../js/functions/anbt/drawDispLinePresto.js | 7 +
.../js/functions/anbt/drawSvgElement.js | 35 +
src/newcanvas/js/functions/anbt/eyedropper.js | 11 +
.../js/functions/anbt/findLastRect.js | 12 +
.../js/functions/anbt/fromLocalFile.js | 26 +
src/newcanvas/js/functions/anbt/fromPng.js | 36 +
src/newcanvas/js/functions/anbt/fromUrl.js | 12 +
src/newcanvas/js/functions/anbt/getSeekMax.js | 5 +
src/newcanvas/js/functions/anbt/lock.js | 11 +
src/newcanvas/js/functions/anbt/makePng.js | 54 +
src/newcanvas/js/functions/anbt/moveCursor.js | 44 +
.../js/functions/anbt/moveSeekbar.js | 7 +
.../js/functions/anbt/packPlayback.js | 63 +
src/newcanvas/js/functions/anbt/pause.js | 19 +
src/newcanvas/js/functions/anbt/play.js | 20 +
src/newcanvas/js/functions/anbt/playTimer.js | 71 +
src/newcanvas/js/functions/anbt/redo.js | 14 +
.../js/functions/anbt/requestSave.js | 33 +
src/newcanvas/js/functions/anbt/seek.js | 46 +
.../js/functions/anbt/setBackground.js | 18 +
src/newcanvas/js/functions/anbt/setColor.js | 5 +
.../js/functions/anbt/setSeekbarMove.js | 5 +
src/newcanvas/js/functions/anbt/setSize.js | 9 +
.../js/functions/anbt/showEyedropperCursor.js | 12 +
src/newcanvas/js/functions/anbt/strokeAdd.js | 20 +
.../js/functions/anbt/strokeBegin.js | 36 +
src/newcanvas/js/functions/anbt/strokeEnd.js | 18 +
src/newcanvas/js/functions/anbt/undo.js | 14 +
src/newcanvas/js/functions/anbt/unlock.js | 5 +
.../js/functions/anbt/unpackPlayback.js | 117 +
src/newcanvas/js/functions/anbt/updateView.js | 9 +
.../js/functions/anbt/uploadToImgur.js | 44 +
src/newcanvas/js/functions/bindEvents.js | 72 +
.../functions/bindEvents/changeBrushSize.js | 22 +
.../bindEvents/checkPlayingAndStop.js | 13 +
.../js/functions/bindEvents/clickRedo.js | 10 +
.../bindEvents/clickSetBackground.js | 9 +
.../js/functions/bindEvents/clickTrash.js | 12 +
.../js/functions/bindEvents/clickUndo.js | 10 +
.../js/functions/bindEvents/colorClick.js | 26 +
.../js/functions/bindEvents/doExport.js | 12 +
.../js/functions/bindEvents/doImport.js | 11 +
.../bindEvents/documentEvents/keyDown.js | 140 +
.../bindEvents/documentEvents/keyUp.js | 10 +
.../js/functions/bindEvents/exportToImgur.js | 40 +
.../js/functions/bindEvents/getPointerType.js | 8 +
.../functions/bindEvents/knob/knobCommoUp.js | 13 +
.../bindEvents/knob/knobCommomDown.js | 17 +
.../bindEvents/knob/knobCommonMove.js | 21 +
.../js/functions/bindEvents/knob/knobMove.js | 16 +
.../js/functions/bindEvents/noDefault.js | 3 +
.../bindEvents/palette/choosePalette.js | 11 +
.../bindEvents/palette/closePaletteList.js | 11 +
.../bindEvents/palette/openPaletteList.js | 45 +
.../bindEvents/palette/setPaletteByName.js | 28 +
.../js/functions/bindEvents/playCommonDown.js | 18 +
.../js/functions/bindEvents/popupClose.js | 8 +
.../functions/bindEvents/removeEyedropper.js | 10 +
.../bindEvents/simulateSingleTouchStart.js | 12 +
.../svgContainerEvents/contextMenu.js | 3 +
.../svgContainerEvents/mouseDown.js | 37 +
.../svgContainerEvents/mouseLeave.js | 5 +
.../svgContainerEvents/mouseMove.js | 29 +
.../bindEvents/svgContainerEvents/mouseUp.js | 17 +
.../svgContainerEvents/touchStart.js | 36 +
.../bindEvents/updateChooseBackground.js | 15 +
.../bindEvents/updateColorIndicators.js | 17 +
.../bindEvents/warnStrokesAfterPosition.js | 11 +
.../bindEvents/windowEvents/beforeUnload.js | 10 +
.../bindEvents/windowEvents/contextMenu.js | 7 +
.../bindEvents/windowEvents/error.js | 3 +
.../bindEvents/windowEvents/mouseMove.js | 13 +
.../bindEvents/windowEvents/touchEnd.js | 14 +
.../bindEvents/windowEvents/touchMove.js | 15 +
.../bindEvents/windowEvents/touchUndoRedo.js | 21 +
src/newcanvas/js/functions/buildSmoothPath.js | 72 +
.../js/functions/conversions/base64ToBytes.js | 5 +
.../functions/conversions/bytesToStrings.js | 4 +
.../js/functions/conversions/colorToDword.js | 8 +
.../js/functions/conversions/colorToHex.js | 6 +
.../js/functions/conversions/colorToRgba.js | 19 +
.../js/functions/conversions/rgbToHex.js | 4 +
.../js/functions/conversions/rgbToLab.js | 17 +
.../js/functions/conversions/stringToBytes.js | 4 +
src/newcanvas/js/functions/crc32.js | 15 +
.../js/functions/createSvgElement.js | 11 +
.../js/functions/fixTabletPluginGoingAwol.js | 14 +
src/newcanvas/js/functions/getClosestColor.js | 22 +
.../js/functions/getColorDistance.js | 12 +
src/newcanvas/js/functions/getSqSegDist.js | 20 +
src/newcanvas/js/functions/idSelector.js | 3 +
src/newcanvas/js/functions/int16be.js | 6 +
src/newcanvas/js/functions/makeCRCTable.js | 11 +
src/newcanvas/js/functions/needToGoDeeper.js | 85 +
.../js/functions/needToGoDeeper/ajax.js | 47 +
.../needToGoDeeper/bindCanvasEvents.js | 41 +
.../js/functions/needToGoDeeper/decodeHTML.js | 7 +
.../needToGoDeeper/events/backToForum.js | 8 +
.../needToGoDeeper/events/bookmark.js | 16 +
.../needToGoDeeper/events/caption.js | 9 +
.../functions/needToGoDeeper/events/exit.js | 57 +
.../functions/needToGoDeeper/events/quit.js | 6 +
.../functions/needToGoDeeper/events/report.js | 18 +
.../functions/needToGoDeeper/events/skip.js | 21 +
.../functions/needToGoDeeper/events/start.js | 11 +
.../needToGoDeeper/events/submitCaption.js | 54 +
.../needToGoDeeper/events/submitDrawing.js | 59 +
.../needToGoDeeper/events/timePlus.js | 38 +
.../needToGoDeeper/events/updateUsedChars.js | 7 +
.../functions/needToGoDeeper/exitToSandbox.js | 39 +
.../needToGoDeeper/extractInfoFromHTML.js | 43 +
.../js/functions/needToGoDeeper/getPalData.js | 21 +
.../needToGoDeeper/getParametersFromPlay.js | 33 +
.../needToGoDeeper/handleCommonParameters.js | 17 +
.../needToGoDeeper/handlePlayParameters.js | 113 +
.../needToGoDeeper/handleSandboxParameters.js | 29 +
.../needToGoDeeper/onCaptionSuccess.js | 13 +
.../functions/needToGoDeeper/timerCallback.js | 40 +
.../needToGoDeeper/unsavedStopAction.js | 6 +
.../js/functions/pack/packUint16be.js | 4 +
.../js/functions/pack/packUint32be.js | 9 +
src/newcanvas/js/functions/randomBase.js | 15 +
src/newcanvas/js/functions/randomItem.js | 3 +
src/newcanvas/js/functions/randomPhrase.js | 8 +
.../js/functions/simplifyDouglasPeucker.js | 33 +
src/newcanvas/js/functions/updateTimer.js | 15 +
src/newcanvas/js/globals.js | 12 +
src/newcanvas/js/pako.js | 2 +
src/newcanvas/js/palettemap.js | 36 +
src/newcanvas/js/palettes.js | 68 +
src/newcanvas/js/pathseg.js | 1 +
src/newcanvas/js/random.js | 34 +
233 files changed, 9826 insertions(+), 9747 deletions(-)
create mode 100644 .eslintignore
create mode 100644 .eslintrc
create mode 100644 .gitignore
create mode 100644 .prettierrc
create mode 100644 build/drawception-anbt.user.js
create mode 100644 build/index.html
create mode 100644 build/newcanvas/index.html
create mode 100644 build/newcanvas/pako.js
create mode 100644 build/newcanvas/pathseg.js
create mode 100644 build/newcanvas/script.js
create mode 100644 build/newcanvas/style.css
delete mode 100644 drawception-anbt.user.js
delete mode 100644 newcanvas/drawit.css
delete mode 100644 newcanvas/drawit.js
delete mode 100644 newcanvas/favicon.png
delete mode 100644 newcanvas/index.html
delete mode 100644 newcanvas/newcanvasicons.png
delete mode 100644 newcanvas/nunito.woff
delete mode 100644 newcanvas/pako.min.js
delete mode 100644 newcanvas/pathseg.min.js
delete mode 100644 newcanvas/whammy.min.js
delete mode 100644 newcanvas/yanone.woff
delete mode 100644 newcanvas_embedding.html
create mode 100644 package.json
create mode 100644 rollup.config.js
create mode 100644 src/extension.js
create mode 100644 src/extension/banner.js
create mode 100644 src/extension/betterPages.js
create mode 100644 src/extension/functions/addMarkdownTools.js
create mode 100644 src/extension/functions/addStyle.js
create mode 100644 src/extension/functions/base62ToDecimal.js
create mode 100644 src/extension/functions/betterPages/betterCreate.js
create mode 100644 src/extension/functions/betterPages/betterForums.js
create mode 100644 src/extension/functions/betterPages/betterGame.js
create mode 100644 src/extension/functions/betterPages/betterPanel.js
create mode 100644 src/extension/functions/betterPages/betterPlayer.js
create mode 100644 src/extension/functions/betterPages/betterSettings.js
create mode 100644 src/extension/functions/comment/betterComments.js
create mode 100644 src/extension/functions/comment/waitForComments.js
create mode 100644 src/extension/functions/cookie/getCookie.js
create mode 100644 src/extension/functions/cookie/setCookie.js
create mode 100644 src/extension/functions/darkMode/addDarkCSS.js
create mode 100644 src/extension/functions/darkMode/setDarkMode.js
create mode 100644 src/extension/functions/darkMode/toggleLight.js
create mode 100644 src/extension/functions/decimalToBase62.js
create mode 100644 src/extension/functions/fade/fadeIn.js
create mode 100644 src/extension/functions/fade/fadeOut.js
create mode 100644 src/extension/functions/getLocalStorageItem.js
create mode 100644 src/extension/functions/getNotifications.js
create mode 100644 src/extension/functions/getPanelId.js
create mode 100644 src/extension/functions/getSelectedText.js
create mode 100644 src/extension/functions/linkifyDrawingPanels.js
create mode 100644 src/extension/functions/linkifyNodeText.js
create mode 100644 src/extension/functions/markdown/bold.js
create mode 100644 src/extension/functions/markdown/code.js
create mode 100644 src/extension/functions/markdown/heading.js
create mode 100644 src/extension/functions/markdown/highlighter.js
create mode 100644 src/extension/functions/markdown/image.js
create mode 100644 src/extension/functions/markdown/italic.js
create mode 100644 src/extension/functions/markdown/link.js
create mode 100644 src/extension/functions/markdown/listOl.js
create mode 100644 src/extension/functions/markdown/listUl.js
create mode 100644 src/extension/functions/markdown/quoteRight.js
create mode 100644 src/extension/functions/markdown/strikethrough.js
create mode 100644 src/extension/functions/pageEnhancements.js
create mode 100644 src/extension/functions/randomGreeting.js
create mode 100644 src/extension/functions/replay/addReplayButton.js
create mode 100644 src/extension/functions/replay/addReplaySign.js
create mode 100644 src/extension/functions/replay/checkForRecording.js
create mode 100644 src/extension/functions/reversePanels.js
create mode 100644 src/extension/functions/rot13.js
create mode 100644 src/extension/functions/scrambleID.js
create mode 100644 src/extension/functions/selector.js
create mode 100644 src/extension/functions/settings/addGroup.js
create mode 100644 src/extension/functions/settings/escapeHTML.js
create mode 100644 src/extension/functions/settings/loadScriptSettings.js
create mode 100644 src/extension/functions/settings/updateScriptSettings.js
create mode 100644 src/extension/functions/setupNewCanvas.js
create mode 100644 src/extension/functions/simpleHash.js
create mode 100644 src/extension/functions/time/convertForumTime.js
create mode 100644 src/extension/functions/time/formatTimestamp.js
create mode 100644 src/extension/functions/time/isFloridaDST.js
create mode 100644 src/extension/functions/unscrambleID.js
create mode 100644 src/extension/functions/viewMyGameBookmarks.js
create mode 100644 src/extension/functions/viewMyPanelFavorites.js
create mode 100644 src/extension/globals.js
create mode 100644 src/extension/markdown.js
create mode 100644 src/extension/options.js
create mode 100644 src/extension/versions.js
create mode 100644 src/extension/wrapper.js
create mode 100644 src/newcanvas.js
create mode 100644 src/newcanvas/css/style.scss
create mode 100644 src/newcanvas/html/index.html
create mode 100644 src/newcanvas/js/anbt.js
create mode 100644 src/newcanvas/js/functions/anbt/addToSvg.js
create mode 100644 src/newcanvas/js/functions/anbt/bindContainer.js
create mode 100644 src/newcanvas/js/functions/anbt/clearWithColor.js
create mode 100644 src/newcanvas/js/functions/anbt/cutHistoryBeforeClearAndAfterPosition.js
create mode 100644 src/newcanvas/js/functions/anbt/drawDispLine.js
create mode 100644 src/newcanvas/js/functions/anbt/drawDispLinePresto.js
create mode 100644 src/newcanvas/js/functions/anbt/drawSvgElement.js
create mode 100644 src/newcanvas/js/functions/anbt/eyedropper.js
create mode 100644 src/newcanvas/js/functions/anbt/findLastRect.js
create mode 100644 src/newcanvas/js/functions/anbt/fromLocalFile.js
create mode 100644 src/newcanvas/js/functions/anbt/fromPng.js
create mode 100644 src/newcanvas/js/functions/anbt/fromUrl.js
create mode 100644 src/newcanvas/js/functions/anbt/getSeekMax.js
create mode 100644 src/newcanvas/js/functions/anbt/lock.js
create mode 100644 src/newcanvas/js/functions/anbt/makePng.js
create mode 100644 src/newcanvas/js/functions/anbt/moveCursor.js
create mode 100644 src/newcanvas/js/functions/anbt/moveSeekbar.js
create mode 100644 src/newcanvas/js/functions/anbt/packPlayback.js
create mode 100644 src/newcanvas/js/functions/anbt/pause.js
create mode 100644 src/newcanvas/js/functions/anbt/play.js
create mode 100644 src/newcanvas/js/functions/anbt/playTimer.js
create mode 100644 src/newcanvas/js/functions/anbt/redo.js
create mode 100644 src/newcanvas/js/functions/anbt/requestSave.js
create mode 100644 src/newcanvas/js/functions/anbt/seek.js
create mode 100644 src/newcanvas/js/functions/anbt/setBackground.js
create mode 100644 src/newcanvas/js/functions/anbt/setColor.js
create mode 100644 src/newcanvas/js/functions/anbt/setSeekbarMove.js
create mode 100644 src/newcanvas/js/functions/anbt/setSize.js
create mode 100644 src/newcanvas/js/functions/anbt/showEyedropperCursor.js
create mode 100644 src/newcanvas/js/functions/anbt/strokeAdd.js
create mode 100644 src/newcanvas/js/functions/anbt/strokeBegin.js
create mode 100644 src/newcanvas/js/functions/anbt/strokeEnd.js
create mode 100644 src/newcanvas/js/functions/anbt/undo.js
create mode 100644 src/newcanvas/js/functions/anbt/unlock.js
create mode 100644 src/newcanvas/js/functions/anbt/unpackPlayback.js
create mode 100644 src/newcanvas/js/functions/anbt/updateView.js
create mode 100644 src/newcanvas/js/functions/anbt/uploadToImgur.js
create mode 100644 src/newcanvas/js/functions/bindEvents.js
create mode 100644 src/newcanvas/js/functions/bindEvents/changeBrushSize.js
create mode 100644 src/newcanvas/js/functions/bindEvents/checkPlayingAndStop.js
create mode 100644 src/newcanvas/js/functions/bindEvents/clickRedo.js
create mode 100644 src/newcanvas/js/functions/bindEvents/clickSetBackground.js
create mode 100644 src/newcanvas/js/functions/bindEvents/clickTrash.js
create mode 100644 src/newcanvas/js/functions/bindEvents/clickUndo.js
create mode 100644 src/newcanvas/js/functions/bindEvents/colorClick.js
create mode 100644 src/newcanvas/js/functions/bindEvents/doExport.js
create mode 100644 src/newcanvas/js/functions/bindEvents/doImport.js
create mode 100644 src/newcanvas/js/functions/bindEvents/documentEvents/keyDown.js
create mode 100644 src/newcanvas/js/functions/bindEvents/documentEvents/keyUp.js
create mode 100644 src/newcanvas/js/functions/bindEvents/exportToImgur.js
create mode 100644 src/newcanvas/js/functions/bindEvents/getPointerType.js
create mode 100644 src/newcanvas/js/functions/bindEvents/knob/knobCommoUp.js
create mode 100644 src/newcanvas/js/functions/bindEvents/knob/knobCommomDown.js
create mode 100644 src/newcanvas/js/functions/bindEvents/knob/knobCommonMove.js
create mode 100644 src/newcanvas/js/functions/bindEvents/knob/knobMove.js
create mode 100644 src/newcanvas/js/functions/bindEvents/noDefault.js
create mode 100644 src/newcanvas/js/functions/bindEvents/palette/choosePalette.js
create mode 100644 src/newcanvas/js/functions/bindEvents/palette/closePaletteList.js
create mode 100644 src/newcanvas/js/functions/bindEvents/palette/openPaletteList.js
create mode 100644 src/newcanvas/js/functions/bindEvents/palette/setPaletteByName.js
create mode 100644 src/newcanvas/js/functions/bindEvents/playCommonDown.js
create mode 100644 src/newcanvas/js/functions/bindEvents/popupClose.js
create mode 100644 src/newcanvas/js/functions/bindEvents/removeEyedropper.js
create mode 100644 src/newcanvas/js/functions/bindEvents/simulateSingleTouchStart.js
create mode 100644 src/newcanvas/js/functions/bindEvents/svgContainerEvents/contextMenu.js
create mode 100644 src/newcanvas/js/functions/bindEvents/svgContainerEvents/mouseDown.js
create mode 100644 src/newcanvas/js/functions/bindEvents/svgContainerEvents/mouseLeave.js
create mode 100644 src/newcanvas/js/functions/bindEvents/svgContainerEvents/mouseMove.js
create mode 100644 src/newcanvas/js/functions/bindEvents/svgContainerEvents/mouseUp.js
create mode 100644 src/newcanvas/js/functions/bindEvents/svgContainerEvents/touchStart.js
create mode 100644 src/newcanvas/js/functions/bindEvents/updateChooseBackground.js
create mode 100644 src/newcanvas/js/functions/bindEvents/updateColorIndicators.js
create mode 100644 src/newcanvas/js/functions/bindEvents/warnStrokesAfterPosition.js
create mode 100644 src/newcanvas/js/functions/bindEvents/windowEvents/beforeUnload.js
create mode 100644 src/newcanvas/js/functions/bindEvents/windowEvents/contextMenu.js
create mode 100644 src/newcanvas/js/functions/bindEvents/windowEvents/error.js
create mode 100644 src/newcanvas/js/functions/bindEvents/windowEvents/mouseMove.js
create mode 100644 src/newcanvas/js/functions/bindEvents/windowEvents/touchEnd.js
create mode 100644 src/newcanvas/js/functions/bindEvents/windowEvents/touchMove.js
create mode 100644 src/newcanvas/js/functions/bindEvents/windowEvents/touchUndoRedo.js
create mode 100644 src/newcanvas/js/functions/buildSmoothPath.js
create mode 100644 src/newcanvas/js/functions/conversions/base64ToBytes.js
create mode 100644 src/newcanvas/js/functions/conversions/bytesToStrings.js
create mode 100644 src/newcanvas/js/functions/conversions/colorToDword.js
create mode 100644 src/newcanvas/js/functions/conversions/colorToHex.js
create mode 100644 src/newcanvas/js/functions/conversions/colorToRgba.js
create mode 100644 src/newcanvas/js/functions/conversions/rgbToHex.js
create mode 100644 src/newcanvas/js/functions/conversions/rgbToLab.js
create mode 100644 src/newcanvas/js/functions/conversions/stringToBytes.js
create mode 100644 src/newcanvas/js/functions/crc32.js
create mode 100644 src/newcanvas/js/functions/createSvgElement.js
create mode 100644 src/newcanvas/js/functions/fixTabletPluginGoingAwol.js
create mode 100644 src/newcanvas/js/functions/getClosestColor.js
create mode 100644 src/newcanvas/js/functions/getColorDistance.js
create mode 100644 src/newcanvas/js/functions/getSqSegDist.js
create mode 100644 src/newcanvas/js/functions/idSelector.js
create mode 100644 src/newcanvas/js/functions/int16be.js
create mode 100644 src/newcanvas/js/functions/makeCRCTable.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/ajax.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/bindCanvasEvents.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/decodeHTML.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/backToForum.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/bookmark.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/caption.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/exit.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/quit.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/report.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/skip.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/start.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/submitCaption.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/submitDrawing.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/timePlus.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/events/updateUsedChars.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/exitToSandbox.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/extractInfoFromHTML.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/getPalData.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/getParametersFromPlay.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/handleCommonParameters.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/handlePlayParameters.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/handleSandboxParameters.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/onCaptionSuccess.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/timerCallback.js
create mode 100644 src/newcanvas/js/functions/needToGoDeeper/unsavedStopAction.js
create mode 100644 src/newcanvas/js/functions/pack/packUint16be.js
create mode 100644 src/newcanvas/js/functions/pack/packUint32be.js
create mode 100644 src/newcanvas/js/functions/randomBase.js
create mode 100644 src/newcanvas/js/functions/randomItem.js
create mode 100644 src/newcanvas/js/functions/randomPhrase.js
create mode 100644 src/newcanvas/js/functions/simplifyDouglasPeucker.js
create mode 100644 src/newcanvas/js/functions/updateTimer.js
create mode 100644 src/newcanvas/js/globals.js
create mode 100644 src/newcanvas/js/pako.js
create mode 100644 src/newcanvas/js/palettemap.js
create mode 100644 src/newcanvas/js/palettes.js
create mode 100644 src/newcanvas/js/pathseg.js
create mode 100644 src/newcanvas/js/random.js
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..5636f38
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1 @@
+/build/*.js
\ No newline at end of file
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..1a76640
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,61 @@
+{
+ "parserOptions": {
+ "ecmaVersion": 9,
+ "sourceType": "module",
+ "ecmaFeatures": {}
+ },
+ "rules": {
+ "constructor-super": 2,
+ "for-direction": 2,
+ "getter-return": 2,
+ "no-case-declarations": 2,
+ "no-class-assign": 2,
+ "no-compare-neg-zero": 2,
+ "no-cond-assign": 2,
+ "no-const-assign": 2,
+ "no-constant-condition": 2,
+ "no-control-regex": 2,
+ "no-debugger": 2,
+ "no-delete-var": 2,
+ "no-dupe-args": 2,
+ "no-dupe-class-members": 2,
+ "no-dupe-keys": 2,
+ "no-duplicate-case": 2,
+ "no-empty-character-class": 2,
+ "no-empty-pattern": 2,
+ "no-ex-assign": 2,
+ "no-extra-boolean-cast": 2,
+ "no-extra-semi": 2,
+ "no-fallthrough": 2,
+ "no-func-assign": 2,
+ "no-global-assign": 2,
+ "no-inner-declarations": 2,
+ "no-invalid-regexp": 2,
+ "no-irregular-whitespace": 2,
+ "no-mixed-spaces-and-tabs": 2,
+ "no-new-symbol": 2,
+ "no-obj-calls": 2,
+ "no-octal": 2,
+ "no-redeclare": 2,
+ "no-regex-spaces": 2,
+ "no-self-assign": 2,
+ "no-sparse-arrays": 2,
+ "no-this-before-super": 2,
+ "no-unexpected-multiline": 2,
+ "no-unreachable": 2,
+ "no-unsafe-finally": 2,
+ "no-unsafe-negation": 2,
+ "no-unused-labels": 2,
+ "no-unused-vars": 2,
+ "require-yield": 2,
+ "use-isnan": 2,
+ "valid-typeof": 2,
+ "no-undefined": 2,
+ "no-undef": 2
+ },
+ "env": {
+ "browser": true,
+ "node": true,
+ "es6": true
+ }
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..deefaba
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/node_modules
+/.vscode
+package-lock.json
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..529887e
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,18 @@
+{
+ "arrowParens": "avoid",
+ "bracketSpacing": true,
+ "htmlWhitespaceSensitivity": "css",
+ "insertPragma": false,
+ "jsxBracketSameLine": true,
+ "jsxSingleQuote": true,
+ "parser": "flow",
+ "printWidth": 80,
+ "proseWrap": "preserve",
+ "quoteProps": "as-needed",
+ "requirePragma": false,
+ "semi": false,
+ "singleQuote": true,
+ "tabWidth": 2,
+ "trailingComma": "none",
+ "useTabs": false
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 6e70d3d..f34072d 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@ Drawception ANBT [ (use to install/update manually, or "save as...")
+[**Direct script link**](https://raw.github.com/EnderDragonneau/Drawception-ANBT/master/build/drawception-anbt.user.js) (use to install/update manually, or "save as...")
[New canvas with recording and playback, standalone version](http://grompe.org.ru/drawit/)
@@ -22,13 +22,13 @@ A userscript to make Drawception.com better: more drawing tools, tablet support,
- Opera 15+: add the script in [Violentmonkey add-on](https://addons.opera.com/en/extensions/details/violent-monkey/?display=en)
- Maxthon: add the script in [Violentmonkey add-on](http://extension.maxthon.com/detail/index.php?view_id=1680)
- Mobile browsers / other / single use:
- - create a bookmark with the following URL:
+ - create a bookmark with the following URL (be careful, the "javascript:" at the beginning may not be copied with the rest in some browsers, don’t forget to check before executing the code):
- `javascript:(()=>(x=new XMLHttpRequest,x.open('GET','https://raw.githubusercontent.com/EnderDragonneau/Drawception-ANBT/master/drawception-anbt.user.js'),x.onload=()=>eval(x.responseText),x.send()))()`
+ `javascript:(()=>(x=new XMLHttpRequest,x.open('GET','https://raw.githubusercontent.com/EnderDragonneau/Drawception-ANBT/master/build/drawception-anbt.user.js'),x.onload=()=>eval(x.responseText),x.send()))()`
and follow it while being on drawception.com site; if that doesn't work, try pasting it in the address bar.
-After installing script management add-on, just click on the [**Direct script link**](https://raw.github.com/EnderDragonneau/Drawception-ANBT/master/drawception-anbt.user.js).
+After installing script management add-on, just click on the [**Direct script link**](https://raw.github.com/EnderDragonneau/Drawception-ANBT/master/build/drawception-anbt.user.js).
## FEATURES
diff --git a/build/drawception-anbt.user.js b/build/drawception-anbt.user.js
new file mode 100644
index 0000000..9ad8867
--- /dev/null
+++ b/build/drawception-anbt.user.js
@@ -0,0 +1,2312 @@
+// ==UserScript==
+// @name Drawception ANBT
+// @author Grom PE
+// @namespace http://grompe.org.ru/
+// @version 1.156.2019.06
+// @description Enhancement script for Drawception.com - Artists Need Better Tools
+// @downloadURL https://raw.github.com/EnderDragonneau/Drawception-ANBT/master/build/drawception-anbt.user.js
+// @match http://drawception.com/*
+// @match https://drawception.com/*
+// @grant none
+// @run-at document-start
+// @license Public domain
+// ==/UserScript==
+;(function() {
+ 'use strict'
+
+ const addDarkCSS = () =>
+ localStorage.setItem(
+ 'gpe_darkCSS',
+ (
+ 'a{color:#77c0ff$}.wrapper{~#444$}#nav-drag{~#353535$}.btn-default{~#7f7f7f$;border-bottom-color:#666$;border-left-color:#666$;border-right-color:#666$;border-top-color:#666$;color:#CCC$}' +
+ '.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{~#757575$;border-bottom-color:#565656$;border-left-color:#565656$;border-right-color:#565656$;border-top-color:#565656$;color:#DDD$}' +
+ '.btn-success{~#2e2e2e$;border-bottom-color:#262626$;border-left-color:#262626$;border-right-color:#262626$;border-top-color:#262626$;color:#CCC$}' +
+ '.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{~#232323$;border-bottom-color:#1c1c1c$;border-left-color:#1c1c1c$;border-right-color:#1c1c1c$;border-top-color:#1c1c1c$;color:#DDD$}' +
+ '.btn-primary{~#213184$;border-bottom-color:#1a1a68$;border-left-color:#1a1a68$;border-right-color:#1a1a68$;border-top-color:#1a1a68$;color:#CCC$}' +
+ '.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{~#191964$;border-bottom-color:#141450$;border-left-color:#141450$;border-right-color:#141450$;border-top-color:#141450$;color:#DDD$}' +
+ '.btn-info{~#2d7787$;border-bottom-color:#236969$;border-left-color:#236969$;border-right-color:#236969$;border-top-color:#236969$;color:#CCC$}' +
+ '.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{~#1c5454$;border-bottom-color:#133939$;border-left-color:#133939$;border-right-color:#133939$;border-top-color:#133939$;color:#DDD$}' +
+ '.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{~#3b3b3b$}.navbar-toggle{~#393939$}.navbar{border-bottom:1px solid #000$}.forum-thread-starter,.breadcrumb,.regForm{~#555$}' +
+ '.form-control{~#666$;border:1px solid #333$;color:#EEE$}code,pre{~#656$;color:#FCC$}body{color:#EEE$}footer{~#333$;border-top:1px solid #000$}' +
+ '.pagination>li:not(.disabled):not(.active),.pagination>li:not(.disabled):not(.active)>a:hover,.pagination>li:not(.disabled):not(.active)>span:hover,.pagination>li:not(.disabled):not(.active)>a:focus,.pagination>li:not(.disabled):not(.active)>span:focus{~#444$}.pagination>li>a,.pagination>li>span{~#555$;border:1px solid #000$}' +
+ '.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{~#666$;border-top:1px solid #444$;border-bottom:1px solid #444$}' +
+ '.drawingForm{~#555$}.well{~#666$;border:1px solid #333$}#timeleft{color:#AAA$}legend{border-bottom:1px solid #000$}.thumbpanel{color:#EEE;~#555$}.thumbpanel img{~#fffdc9$}.panel-number,.modal-content,.profile-user-header{~#555$}' +
+ '#commentForm{~#555$;border:1px solid #000$}.modal-header,.nav-tabs{border-bottom:1px solid #000$}hr,.modal-footer{border-top:1px solid #000$}' +
+ '.store-item{background:#666$;~-moz-linear-gradient(top,#666 0,#333 100%)$;~-webkit-gradient(linear,left top,left bottom,color-stop(0,#666),color-stop(100%,#333))$;~-webkit-linear-gradient(top,#666 0,#333 100%)$;~-o-linear-gradient(top,#666 0,#333 100%)$;~-ms-linear-gradient(top,#666 0,#333 100%)$;~linear-gradient(to bottom,#666 0,#333 100%)$;border:1px solid #222$}' +
+ '.store-item:hover{border:1px solid #000$}.store-item-title{~#222$;color:#DDD$}.store-title-link{color:#DDD$}.profile-award{~#222$}.profile-award-unlocked{~#888$}.progress-bar{color:#CCC$;~#214565$}.progress{~#333$}' +
+ '.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(.25,rgba(0,0,0,0.15)),color-stop(.25,transparent),color-stop(.5,transparent),color-stop(.5,rgba(0,0,0,0.15)),color-stop(.75,rgba(0,0,0,0.15)),color-stop(.75,transparent),to(transparent))$;background-image:-webkit-linear-gradient(45deg,rgba(0,0,0,0.15) 25%,transparent 25%,transparent 50%,rgba(0,0,0,0.15) 50%,rgba(0,0,0,0.15) 75%,transparent 75%,transparent)$;background-image:-moz-linear-gradient(45deg,rgba(0,0,0,0.15) 25%,transparent 25%,transparent 50%,rgba(0,0,0,0.15) 50%,rgba(0,0,0,0.15) 75%,transparent 75%,transparent)$;background-image:linear-gradient(45deg,rgba(0,0,0,0.15) 25%,transparent 25%,transparent 50%,rgba(0,0,0,0.15) 50%,rgba(0,0,0,0.15) 75%,transparent 75%,transparent)$}' +
+ '.progress-bar-success{~#363$}.progress-bar-info{~#367$}.progress-bar-warning{~#863$}.progress-bar-danger{~#733$}' +
+ '.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#DDD$;~#555$;border:1px solid #222$}.nav>li>a:hover,.nav>li>a:focus{~#333$;border-bottom-color:#222$;border-left-color:#111$;border-right-color:#111$;border-top-color:#111$}' +
+ '.nav>li.disabled>a,.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#555$}.table-striped>tbody>tr:nth-child(2n+1)>td,.table-striped>tbody>tr:nth-child(2n+1)>th{~#333$}' +
+ '.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{~#555$}.table thead>tr>th,.table tbody>tr>th,.table tfoot>tr>th,.table thead>tr>td,.table tbody>tr>td,.table tfoot>tr>td{border-top:1px solid #333$}.news-alert{~#555$;border:2px solid #444$}' +
+ '.btn-menu{~#2e2e2e$}.btn-menu:hover{~#232323$}.btn-yellow{~#8a874e$}.btn-yellow:hover{~#747034$}' +
+ 'a.label{color:#fff$}.text-muted,a.text-muted{color:#999$}a.wrong-order{color:#F99$}div.comment-holder:target{~#454$}' +
+ '.popover{~#777$}.popover-title{~#666$;border-bottom:1px solid #444$}.popover.top .arrow:after{border-top-color:#777$}.popover.right .arrow:after{border-right-color:#777$}.popover.bottom .arrow:after{border-bottom-color:#777$}.popover.left .arrow:after{border-left-color:#777$}' +
+ '.label-fancy{~#444$;border-color:#333$;color:#FFF$}' +
+ '.avatar,.profile-avatar{~#444$;border:1px solid #777$;}' +
+ '.bg-lifesupport{~#444$}body{~#555$}.snap-content{~#333$}' +
+ 'select,textarea{color:#000$}.help-block{color:#ddd$}.jumbotron{~#444$}' +
+ '.navbar-dropdown{~#444$}a.list-group-item{~#444$;color:#fff$;border:1px solid #222$}a.list-group-item:hover,a.list-group-item:focus{~#222$}' +
+ '.likebutton.btn-success{color:#050$;~#5A5$}.likebutton.btn-success:hover{~#494$}' +
+ ".thumbnail[style*='background-color: rgb(255, 255, 255)']{~#555$}" +
+ '.popup,.v--modal{~#666$;border:1px solid #222$}.btn-reaction{~#666$;border:none$;color:#AAA$}@media(min-width:625px){.create-game-wrapper{~#555$}}' +
+ '.profile-header{~#555$}.profile-nav > li > a{~#333$}.profile-nav>li.active>a,.profile-nav>li>a:hover{~#555$}' +
+ '.gsc-control-cse{~#444$;border-color:#333$}.gsc-above-wrapper-area,.gsc-result{border:none$}.gs-snippet{color:#AAA$}.gs-visibleUrl{color:#8A8$}a.gs-title b,.gs-visibleUrl b{color:#EEE$}.gsc-adBlock{display:none$}.gsc-input{~#444$;border-color:#333$;color:#EEE$}' +
+ '.comment-highlight{border:none$;background:#454$}#header-emotes{~#555$}#header-bar-container{border:none$}.paypal-button-tag-content{color:#EEE$}.numlikes{color:#EEE$}.gsc-input-box{~#444$;border-color:#333$}.gsc-completion-container{~#333$;border-color:#000$}.gsc-completion-selected{~#222$}.gsc-completion-container b{color:#AAA$}.alert-nice{~#4a4a4a$}.store-buy-coins{~#777$}.store-buy-coins:hover{~#666$}.store-buy-coins>h2,.store-buy-coins>h2>small{color:#EEE$}.store-package-selector{~#888$}.store-package-selector>label{color:#EEE$}.label-stat{~#444$;color:#EEE$;border:1px solid #555$}.label-stat.disabled{~#333$}.option{padding:4px 8px$;~#666$;color:#EEE$;border-color:#333$}.option.selected{border-color:#EEE$}.sleek-select{~#666$;border-color:#333$}select{color:#EEE$}.modal-note{color:#EEE$}.vue-dialog-button{~#555$;border:none$}.vue-dialog-button:hover{~#5a5a5a$}.vue-dialog-buttons{border-top:1px solid #222$}.dashboard-item{~#333$}legend{color:#EEE$}.list-group-item{~#444$;color:#EEE$;border:1px solid #222$}.alert-warning{color:#EEE$;~#555$;border-color:#555$}.btn-reaction.active{border:1px solid #EEE$}.bg-shadow-box{~#333$}.btn-gray{~#222$;border:none$}.btn-gray:hover{color:#EEE$;~#1a1a1a$}.btn-bright{~#333$;color:#EEE$}' +
+ '.player-name-new{color:#33b73f$}.gsc-tabsArea>div{overflow:hidden$}.gs-image-popup-box{~#333$;border-color:#222$}.gs-size{color:#6f6f6f$}.gsc-result-info{color:#EEE$}.gsc-refinementsArea{border:none$}.gsc-tabsArea{border-bottom-color:#333$}.gsc-cursor-page{color:#EEE$}.gsc-cursor-current-page{color:#AAA$}.profile-nav>.disabled>a{color:#555$;~#3a3a3a$}.profile-nav>.disabled>a:hover{~#3a3a3a$}.sleek-select:hover{border-color:#EEE$}' +
+ '.btn-menu{border-color:#1e1e1e$;text-shadow:0px 0px 3px #777$}.btn-menu:hover{border-color:#1e1e1e$}.pagination>.active>span{color:#EEE$}#btn-notifications{color:#EEE$}.btn-warning{color:#EEE$}.alert-nice{color:#EEE$}.emotes-popup{~#2e2e2e$}.navbar-toggle{~#2e2e2e$;border-color:#1e1e1e$}.navbar-toggle .icon-bar{~#EEE$}' +
+ '.gamepanel-highlight{box-shadow:0 0 20px #111$;~#222$}' +
+ 'a.anbt_replaypanel:hover{color:#8af$}' +
+ '.anbt_favedpanel{color:#d9534f$}' +
+ ''
+ )
+ .replace(/~/g, 'background-color:')
+ .replace(/\$/g, ' !important')
+ )
+
+ const getLocalStorageItem = (name, empty) => {
+ const item = localStorage.getItem(name)
+ try {
+ return item ? JSON.parse(item) : empty || ''
+ } catch (e) {
+ return item ? item : empty || ''
+ }
+ }
+
+ const setDarkMode = () => {
+ const settings = getLocalStorageItem('gpe_anbtSettings', {})
+ if (settings.anbtDarkMode || typeof settings.anbtDarkMode === 'undefined') {
+ if (getLocalStorageItem('gpe_inDark', 0)) {
+ const css = document.createElement('style')
+ css.id = 'darkgraycss'
+ css.type = 'text/css'
+ css.appendChild(
+ document.createTextNode(getLocalStorageItem('gpe_darkCSS'))
+ )
+ if (document.head) document.head.appendChild(css)
+ else {
+ const darkLoad = setInterval(() => {
+ if (!document.head) return
+ document.head.appendChild(css)
+ clearInterval(darkLoad)
+ }, 100)
+ }
+ }
+ }
+ }
+
+ const options = {
+ enableWacom: 0,
+ fixTabletPluginGoingAWOL: 1,
+ hideCross: 0,
+ enterToCaption: 0,
+ pressureExponent: 0.5,
+ backup: 1,
+ timeoutSound: 0,
+ timeoutSoundBlitz: 0,
+ timeoutSoundVolume: 100,
+ newCanvas: 1,
+ proxyImgur: 0,
+ ajaxRetry: 1,
+ localeTimestamp: 0,
+ autoplay: 1,
+ submitConfirm: 1,
+ smoothening: 1,
+ autoBypassNSFW: 0,
+ colorNumberShortcuts: 1,
+ colorUnderCursorHint: 1,
+ bookmarkOwnCaptions: 0,
+ colorDoublePress: 0,
+ newCanvasCSS: '',
+ forumHiddenUsers: '',
+ maxCommentHeight: 1000,
+ useOldFont: true,
+ useOldFontSize: true,
+ markdownTools: 1,
+ anbtDarkMode: 1
+ }
+
+ const $ = (selector, array = false) => {
+ const elements = selector.startsWith('<')
+ ? [
+ ...new DOMParser().parseFromString(selector, 'text/html').body
+ .children
+ ]
+ : [...document.querySelectorAll(selector)]
+ return elements.length > 1 || array ? elements : elements[0]
+ }
+
+ const betterCreate = () => {
+ if (!options.enterToCaption) {
+ if ($('#prompt'))
+ $('#prompt').addEventListener('keydown', event => {
+ if (event.keyCode === 13) event.preventDefault()
+ })
+ }
+ }
+
+ const addStyle = css => {
+ const parent =
+ document.getElementsByTagName('head')[0] || document.documentElement
+ const style = document.createElement('style')
+ style.type = 'text/css'
+ style.appendChild(document.createTextNode(css))
+ parent.appendChild(style)
+ }
+
+ const globals = {
+ userId: getLocalStorageItem(
+ 'gpe_lastSeenId',
+ $('.player-dropdown a[href^="/player/"]') &&
+ $('.player-dropdown a[href^="/player/"]').href.match(
+ /\/player\/(\d+)\//
+ )[1]
+ ),
+ months: [
+ 'Jan',
+ 'Feb',
+ 'Mar',
+ 'Apr',
+ 'May',
+ 'Jun',
+ 'Jul',
+ 'Aug',
+ 'Sep',
+ 'Oct',
+ 'Nov',
+ 'Dec'
+ ],
+ alphabet: '36QtfkmuFds0UjlvCGIXZ125bEMhz48JSYgipwKn7OVHRBPoy9DLWaceqxANTr',
+ greetings: [
+ 'Oruvaq lbh!',
+ "Ubcr vg'f abg envavat gbqnl.",
+ 'Jurer vf lbhe tbq abj?',
+ 'Lbh fubhyq srry 5% zber cbjreshy abj.',
+ 'Fhqqrayl, abguvat unccrarq!',
+ '^_^',
+ 'Guvf gnxrf fb ybat gb svavfu...',
+ "Jungrire lbh qb, qba'g ernq guvf grkg.",
+ 'Pyvpx urer sbe 1 serr KC',
+ 'Or cngvrag.',
+ "Whfg qba'g fgneg nal qenzn nobhg vg.",
+ '47726S6Q2069732074686520677265617465737421',
+ 'Cynl fzneg.',
+ 'Cynl avpr.',
+ 'Fzvyr!',
+ "Qba'g sbetrg gb rng.",
+ "V xabj jung lbh'ir qbar.",
+ 'Fpvrapr!',
+ 'Gbqnl vf n tbbq qnl.'
+ ]
+ }
+
+ const decimalToBase62 = number => {
+ let result = ''
+ while (number !== 0) {
+ const quotient = number % 62
+ result = globals.alphabet[quotient] + result
+ number = (number - quotient) / 62
+ }
+ return result
+ }
+
+ const scrambleID = number => {
+ if (isNaN(number)) throw new Error('Invalid panel ID')
+ return [...decimalToBase62(parseInt(number, 10) + 3521614606208)]
+ .reverse()
+ .join('')
+ }
+
+ const linkifyDrawingPanels = img => {
+ if (img.parentNode.nodeName !== 'A') {
+ if (
+ img.src.match(/\/images\/panels\//) ||
+ img.src.match(/\/pub\/panels\//)
+ )
+ img.outerHTML = `${img.outerHTML}`
+ if (img.src.match(/\/drawings\//))
+ img.outerHTML = `${img.outerHTML}`
+ if (img.src.match(/\/panel\//))
+ img.outerHTML = `${img.outerHTML}`
+ if (img.src.match(/\/images\/games\//) || img.src.match(/\/pub\/games\//))
+ img.outerHTML = `${img.outerHTML}`
+ if (img.src.match(/\/display-panel.php?/)) {
+ const newsrc = `/panel/drawing/${scrambleID(
+ img.src.match(/x=(\d+)/)[1]
+ )}/`
+ img.setAttribute('src', newsrc)
+ img.outerHTML = `${img.outerHTML}`
+ }
+ }
+ }
+
+ const linkifyNodeText = node => {
+ if (node.textContent.includes('://'))
+ node.innerHTML = node.innerHTML.replace(
+ /([^"]|^)(https?:\/\/(?:(?:(?:[^\s<()]*\([^\s<()]*\))+)|(?:[^\s<()]+)))/g,
+ '$1$2'
+ )
+ }
+
+ const versions = {
+ scriptVersion: '1.156.2019.06',
+ newCanvasVersion: 53,
+ siteVersion: 'f6b35cce',
+ runtimeVersion: '1ba6bf05'
+ }
+
+ const setupNewCanvas = (insandbox, url) => {
+ const canvasHTML = localStorage.getItem('anbt_canvasHTML')
+ const canvasHTMLver = localStorage.getItem('anbt_canvasHTMLver')
+ if (
+ !canvasHTML ||
+ canvasHTMLver < versions.newCanvasVersion ||
+ canvasHTML.length < 10000
+ ) {
+ const request = new XMLHttpRequest()
+ request.open(
+ 'GET',
+ 'https://api.github.com/repos/EnderDragonneau/Drawception-ANBT/contents/build/index.html'
+ )
+ request.setRequestHeader('Accept', 'application/vnd.github.3.raw')
+ request.onload = () => {
+ if (request.responseText.length < 10000) {
+ alert(
+ `Error: instead of new canvas code, got this response from GitHub:\n${request.responseText}`
+ )
+ location.pathname = '/'
+ } else {
+ localStorage.setItem('anbt_canvasHTML', request.responseText)
+ localStorage.setItem('anbt_canvasHTMLver', versions.newCanvasVersion)
+ setupNewCanvas(insandbox, url)
+ }
+ }
+ request.onerror = () => {
+ alert('Error loading the new canvas code. Please try again.')
+ location.pathname = '/'
+ }
+ request.send()
+ return
+ }
+ const inforum = url.match(/forums\//)
+ const friendgameid = url.match(/play\/(.+)\//)
+ const panelid = url.match(/sandbox\/#?([^/]+)/)
+ const incontest =
+ url.match(/contests\/play\//) && document.getElementById('canvas-holder')
+ const vertitle = `ANBT v${versions.scriptVersion}`
+ if (incontest) window.onbeforeunload = () => {}
+ const normalurl =
+ insandbox && !inforum
+ ? `/sandbox/${panelid ? `#${panelid[1]}` : ''}`
+ : incontest
+ ? '/contests/play/'
+ : inforum
+ ? url.match(/\/forums\/?.+/)
+ : `/play/${friendgameid ? `${friendgameid[1]}/` : ''}`
+ try {
+ if (location.pathname + location.hash !== normalurl)
+ history.pushState({}, document.title, normalurl)
+ } catch (e) {}
+ const alarmSoundOgg =
+ 'data:audio/ogg;base64,T2dnUwACAAAAAAAAAABnHAAAAAAAAHQUSFoBHgF2b3JiaXMAAAAAAUSsAAAAAAAAYG0AAAAAAADJAU9nZ1MAAAAAAAAAAAAAZxwAAAEAAABq35G0DxD/////////////////NQN2b3JiaXMAAAAAAAAAAAEFdm9yYmlzH0JDVgEAAAEAFGNWKWaZUpJbihlzmDFnGWPUWoolhBRCKKVzVlurKbWaWsq5xZxzzpViUilFmVJQW4oZY1IpBhlTEltpIYQUQgehcxJbaa2l2FpqObacc62VUk4ppBhTiEromFJMKaQYU4pK6Jxz0DnmnFOMSgg1lVpTyTGFlFtLKXROQgephM5SS7F0kEoHJXRQOms5lRJTKZ1jVkJquaUcU8qtpphzjIHQkFUAAAEAwEAQGrIKAFAAABCGoSiKAoSGrAIAMgAABOAojuIokiI5kmM5FhAasgoAAAIAEAAAwHAUSZEUy9EcTdIszdI8U5ZlWZZlWZZlWZZd13VdIDRkFQAAAQBAKAcZxRgQhJSyEggNWQUAIAAAAIIowxADQkNWAQAAAQAIUR4h5qGj3nvvEXIeIeYdg9577yG0XjnqoaTee++99x5777n33nvvkWFeIeehk9577xFiHBnFmXLee+8hpJwx6J2D3nvvvfeec+451957752j3kHpqdTee++Vk14x6Z2jXnvvJdUeQuqlpN5777333nvvvffee++9955777333nvvrefeau+9995777333nvvvffee++9995777333nvvgdCQVQAAEAAAYRg2iHHHpPfae2GYJ4Zp56T3nnvlqGcMegqx9557773X3nvvvffeeyA0ZBUAAAgAACGEEFJIIYUUUkghhhhiyCGHHIIIKqmkoooqqqiiiiqqLKOMMsook4wyyiyjjjrqqMPOQgoppNJKC620VFtvLdUehBBCCCGEEEIIIYQQvvceCA1ZBQCAAAAwxhhjjEEIIYQQQkgppZRiiimmmAJCQ1YBAIAAAAIAAAAsSZM0R3M8x3M8x1M8R3RER3RER5RESbRETfREUTRFVbRF3dRN3dRNXdVN27VVW7ZlXdddXddlXdZlXdd1Xdd1Xdd1Xdd1XbeB0JBVAAAIAABhkEEGGYQQQkghhZRSijHGGHPOOSA0ZBUAAAgAIAAAAEBxFEdxHMmRJMmyLM3yLM8SNVMzNVNzNVdzRVd1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'
+ if (inforum) {
+ if (document.querySelector('.v--modal-overlay'))
+ document.querySelector('.v--modal-overlay').outerHTML = ''
+ const div = document.querySelector('.wrapper').children[1]
+ const iframe = document.createElement('iframe')
+ const modalOverlay = document.createElement('div')
+ modalOverlay.setAttribute('class', 'v--modal-overlay')
+ iframe.id = 'iframe'
+ iframe.setAttribute('class', 'v--modal-background-click')
+ modalOverlay.appendChild(iframe)
+ div.appendChild(modalOverlay)
+ iframe.contentWindow.document.open()
+ iframe.contentWindow.anbtReady = () => {
+ iframe.contentWindow.inforum = inforum
+ iframe.contentWindow.insandbox = insandbox
+ iframe.contentWindow.incontest = incontest
+ iframe.contentWindow.options = options
+ iframe.contentWindow.alarmSoundOgg = alarmSoundOgg
+ iframe.contentWindow.vertitle = vertitle
+ iframe.contentWindow.getLocalStorageItem = getLocalStorageItem
+ iframe.contentWindow.needToGoDeeper()
+ }
+ iframe.contentWindow.document.write(canvasHTML)
+ iframe.contentWindow.document.close()
+ return
+ }
+ document.open()
+ window.anbtReady = () => {
+ if (friendgameid) window.friendgameid = friendgameid[1]
+ if (panelid) window.panelid = panelid[1]
+ window.inforum = inforum
+ window.insandbox = insandbox
+ window.incontest = incontest
+ window.options = options
+ window.alarmSoundOgg = alarmSoundOgg
+ window.vertitle = vertitle
+ window.getLocalStorageItem = getLocalStorageItem
+ window.needToGoDeeper()
+ }
+ document.write(canvasHTML)
+ document.close()
+ }
+
+ const formatTimestamp = date => {
+ if (typeof date === 'number') date = new Date(date)
+ if (options.localeTimestamp) return date.toLocaleString()
+ return `${('0' + date.getDate()).slice(-2)} ${
+ globals.months[date.getMonth()]
+ } ${date.getFullYear()} ${('0' + date.getHours()).slice(-2)}:${(
+ '0' + date.getMinutes()
+ ).slice(-2)}`
+ }
+
+ const betterForums = () => {
+ $('.comment-body *', true).forEach(comment => linkifyNodeText(comment))
+ $('img', true).forEach(img => linkifyDrawingPanels(img))
+ if (document.location.pathname.match(/\/forums\/(\w+|-)\/.+/)) {
+ const hideUserIds = options.forumHiddenUsers
+ ? options.forumHiddenUsers.split(',')
+ : ''
+ if (hideUserIds)
+ addStyle(
+ '.anbt_hideUserPost:not(:target) {opacity: 0.4; margin-bottom: 10px}' +
+ '.anbt_hideUserPost:not(:target) .comment-body, .anbt_hideUserPost:not(:target) .avatar {display: none}' +
+ ''
+ )
+ let lastid = 0
+ $('.comment-avatar', true).forEach(({ parentNode }) => {
+ const commentHolder = parentNode.parentNode.parentNode
+ const anch = commentHolder.id || ''
+ commentHolder.classList.add('comment-holder')
+ const textMuted = commentHolder.querySelector('a.text-muted')
+ const vue = commentHolder.childNodes[0].__vue__
+ if (vue) {
+ textMuted.textContent = `${textMuted.textContent.trim()}, ${formatTimestamp(
+ vue.comment_date * 1000
+ )}`
+ if (vue.edit_date > 0) {
+ const el = textMuted.parentNode.querySelector('span[rel="tooltip"]')
+ const text = `${el.title}, ${formatTimestamp(
+ vue.edit_date * 1000
+ ).replace(/ /g, '\u00A0')}`
+ el.setAttribute('title', text)
+ }
+ }
+ if (anch) {
+ const id = parseInt(anch.substring(1), 10)
+ const text = textMuted.textContent.trim()
+ textMuted.textContent = `${text} #${id}`
+ textMuted.setAttribute('title', 'Link to post')
+ if (id < lastid) textMuted.classList.add('wrong-order')
+ try {
+ const { href } = commentHolder.querySelector('a[href^="/player/"]')
+ if (href) {
+ const userId = href.match(/\d+/)[0]
+ if (hideUserIds.includes(userId))
+ commentHolder.classList.add('anbt_hideUserPost')
+ }
+ } catch (e) {}
+ lastid = id
+ }
+ })
+ if (
+ $('.comment-holder') &&
+ $('.comment-holder').length === 20 &&
+ $('#comment-form .btn-primary')
+ )
+ $('#comment-form .btn-primary').insertAdjacentHTML(
+ 'afterend',
+ '
Note: posting to another page
'
+ )
+ }
+ if (options.proxyImgur)
+ $('img[src*="imgur.com/"]', true).forEach(img =>
+ img.setAttribute(
+ 'src',
+ img.src.replace('imgur.com', 'filmot.com').replace('https', 'http')
+ )
+ )
+ const pagination = $('.pagination', true)
+ if (pagination.length)
+ $('.breadcrumb').insertAdjacentHTML(
+ 'afterend',
+ `${pagination[0].outerHTML}
`
+ )
+ if (document.location.pathname.match(/\/forums\/(\w+)\/$/)) {
+ const hiddenTopics = getLocalStorageItem('gpe_forumHiddenTopics', [])
+ let hidden = 0
+ const tempUnhideLink = $('')
+ $('.forum-thread', true).forEach(thread => {
+ const href = thread
+ .querySelector('a:first-child')
+ .href.match(/\/forums\/\w+\/(\d+)\//)
+ if (!href || !href[1] || href[1] === 11830) return
+ const id = href[1]
+ if (hiddenTopics.includes(id)) {
+ thread.classList.add('anbt_hidden')
+ hidden++
+ }
+ const hideLink = $('')
+ hideLink.addEventListener('click', () => {
+ const hiddenTopics = getLocalStorageItem('gpe_forumHiddenTopics', [])
+ if (hiddenTopics.includes(id)) {
+ if (hiddenTopics.includes(id))
+ hiddenTopics.splice(hiddenTopics.indexOf(id), 1)
+ hiddenTopics.splice(hiddenTopics.indexOf(id), 1)
+ thread.classList.remove('anbt_hidden')
+ hidden--
+ } else {
+ if (!hiddenTopics.includes(id)) hiddenTopics.push(id)
+ hiddenTopics.push(id)
+ thread.classList.add('anbt_hidden')
+ hidden++
+ tempUnhideLink.style.display = ''
+ }
+ tempUnhideLink.textContent = hidden
+ localStorage.setItem(
+ 'gpe_forumHiddenTopics',
+ JSON.stringify(hiddenTopics)
+ )
+ })
+ thread.querySelector('p:nth-child(2)').appendChild(hideLink)
+ })
+ tempUnhideLink.textContent = hidden
+ tempUnhideLink.addEventListener('click', () => {
+ $('#main').classList.toggle('anbt_showt')
+ })
+ if (!hidden) tempUnhideLink.style.display = 'none'
+ if ($('#js-btn-toggle-thread'))
+ $('#js-btn-toggle-thread').parentNode.appendChild(tempUnhideLink)
+ }
+ $('.btn.btn-default', true).forEach(button =>
+ button.addEventListener('click', () => {
+ if (button.textContent === 'Draw')
+ setupNewCanvas(true, document.location.href)
+ })
+ )
+ }
+
+ const betterComments = () => {
+ const comments = [...$('#comments').nextElementSibling.children].slice(1)
+ comments.forEach(x => {
+ x.parentNode.parentNode.classList.add('comment-holder')
+ })
+ const gamePlayers = []
+ const playerdata = {}
+ $('.gamepanel-holder', true).forEach((gamePanel, index) => {
+ const detail = gamePanel.querySelector('.panel-details')
+ const gamepanel = gamePanel.querySelector('.gamepanel')
+ const playerLink = detail.querySelector('.panel-user a')
+ if (!playerLink) return
+ const id = playerLink.href.match(/\/player\/(\d+)\//)[1]
+ playerdata[id] = {
+ panel_number: index + 1,
+ player_anchor: playerLink,
+ panel_id: gamepanel.id,
+ drew: gamepanel.querySelector('img') !== null,
+ comments: 0
+ }
+ gamePlayers.push(id)
+ })
+ const seenComments = getLocalStorageItem('gpe_seenComments', {})
+ const gameid = document.location.href.match(/game\/([^/]+)\//)[1]
+ if (comments) {
+ const hour = Math.floor(Date.now() / (1000 * 60 * 60))
+ for (const tempgame in seenComments)
+ if (seenComments[tempgame].h + 24 * 7 < hour)
+ delete seenComments[tempgame]
+ let maxseenid = 0
+ comments.forEach(holder => {
+ const dateElement = holder.querySelector('a.text-muted')
+ const vue = holder.__vue__
+ if (vue) {
+ const text = dateElement.textContent.trim()
+ dateElement.textContent = `${text}, ${formatTimestamp(
+ vue.comment_date * 1000
+ )}`
+ if (vue.edit_date > 0) {
+ const element = dateElement.parentNode.querySelector(
+ 'span[rel="tooltip"]'
+ )
+ const title = `${element.title}, ${formatTimestamp(
+ vue.edit_date * 1000
+ ).replace(/ /g, '\u00A0')}`
+ element.setAttribute('title', title)
+ }
+ }
+ const ago = dateElement.textContent
+ const commentid = parseInt(holder.id.slice(1), 10)
+ dateElement.setAttribute('title', 'Link to comment')
+ dateElement.textContent = `${dateElement.textContent.trim()} #${commentid}`
+ if (ago.match(/just now|min|hour|a day| [1-7] day/)) {
+ if (!(seenComments[gameid] && seenComments[gameid].id >= commentid)) {
+ holder.classList.add('comment-new')
+ if (maxseenid < commentid) maxseenid = commentid
+ }
+ }
+ const link = holder.querySelector('.text-bold a')
+ ? holder.querySelector('.text-bold a').href.match(/\/player\/(\d+)\//)
+ : ''
+ if (link) {
+ const id = link[1]
+ if (gamePlayers.includes(id)) {
+ const drew = playerdata[id].drew ? 'drew' : 'wrote'
+ dateElement.insertAdjacentHTML(
+ 'beforebegin',
+ `(${drew} #${playerdata[id].panel_number}) `
+ )
+ playerdata[id].comments++
+ }
+ }
+ })
+ if (maxseenid)
+ seenComments[gameid] = {
+ h: hour,
+ id: maxseenid
+ }
+ localStorage.setItem('gpe_seenComments', JSON.stringify(seenComments))
+ }
+ for (const playerId in gamePlayers) {
+ const data = playerdata[playerId]
+ if (data && data.comments) {
+ const cmt2 = `Player left ${data.comments} comment${
+ data.comments > 1 ? 's' : ''
+ }`
+ data.player_anchor.title = cmt2
+ data.player_anchor.insertAdjacentHTML(
+ 'afterend',
+ `${data.comments}`
+ )
+ }
+ }
+ if (options.maxCommentHeight) {
+ const h = options.maxCommentHeight
+ comments.forEach(comment =>
+ comment.addEventListener('click', () => {
+ if (
+ comment.clientHeight > h - 50 &&
+ !$(location.hash).has(comment).length
+ )
+ location.hash = `#${comment.parentNode.parentNode.id}`
+ })
+ )
+ }
+ }
+
+ const waitForComments = () => {
+ const comments = $('#comments')
+ ? [...$('#comments').nextElementSibling.children].slice(1)
+ : ''
+ if (comments.length && !comments[0].classList.contains('spinner'))
+ betterComments()
+ else {
+ if (comments.length === 0) return
+ setTimeout(waitForComments, 1000)
+ }
+ }
+
+ const checkForRecording = (url, success, retrying) => {
+ const request = new XMLHttpRequest()
+ request.open('GET', `${url}?anbt`, true)
+ request.responseType = 'arraybuffer'
+ request.onload = () => {
+ const buffer = request.response
+ const dataView = new window.DataView(buffer)
+ const magic = dataView.getUint32(0)
+ if (magic != 0x89504e47) return request.onerror()
+ for (let i = 8; i < buffer.byteLength; i += 4) {
+ const chunklen = dataView.getUint32(i)
+ i += 4
+ const chunkname = dataView.getUint32(i)
+ i += 4
+ if (chunkname === 0x73764762) return success()
+ else {
+ if (chunkname === 0x49454e44) break
+ i += chunklen
+ }
+ }
+ }
+ request.onerror = () => {
+ console.log(
+ 'checkForRecording fail (likely due to cache without CORS), retrying'
+ )
+ if (!retrying) checkForRecording(`${url}?anbt`, success, true)
+ }
+ request.send()
+ }
+
+ const addReplayButton = drawing => {
+ if (drawing.replayAdded) return
+ drawing.replayAdded = true
+ const { parentNode, src } = drawing
+ checkForRecording(src, () => {
+ const newid = $(`img[src='${src}']`)
+ .parentNode.querySelector('a[href^="/panel/"]')
+ .href.match(/\/panel\/[^/]+\/([^/]+)/)[1]
+ const id = newid.length >= 8 ? newid : scrambleID(parentNode.id.slice(6))
+ const replayButton = $(
+ ``
+ )
+ replayButton.addEventListener('click', event => {
+ if (event.which === 2) return
+ event.preventDefault()
+ setupNewCanvas(true, `/sandbox/#${id}`)
+ })
+ parentNode.insertAdjacentHTML('beforebegin', replayButton.outerHTML)
+ })
+ }
+
+ const reversePanels = () => {
+ const element = $('.gamepanel-holder')[0].parentNode.parentNode
+ ;[...element.childNodes]
+ .reverse()
+ .forEach(child => element.appendChild(child))
+ }
+
+ const betterGame = () => {
+ if (document.title === 'Not Safe For Work (18+) Gate') {
+ if (options.autoBypassNSFW) window.DrawceptionPlay.bypassNsfwGate()
+ return
+ }
+ const drawings = $(
+ 'img[src^="https://cdn.drawception.com/images/panels/"],img[src^="https://cdn.drawception.com/drawings/"]'
+ )
+ if ($('#btn-copy-url'))
+ $('#btn-copy-url').insertAdjacentHTML(
+ 'afterend',
+ ' Reverse'
+ )
+ $('.reversePanels').addEventListener('click', reversePanels)
+ const favButton = $(
+ ''
+ )
+ $('.panel-number', true).forEach(panelNumber =>
+ panelNumber.insertAdjacentHTML('afterend', favButton.outerHTML)
+ )
+ $('.gamepanel', true).forEach(({ parentNode }) => {
+ if (parentNode.querySelector('.gamepanel-tools>a:last-child') === null)
+ return
+ const panels = getLocalStorageItem('gpe_panelFavorites', {})
+ const id = parentNode
+ .querySelector('.gamepanel-tools>a:last-child')
+ .href.match(/\/panel\/[^/]+\/([^/]+)\/[^/]+\//)[1]
+ if (panels[id])
+ parentNode
+ .querySelector('.anbt_favpanel')
+ .classList.add('anbt_favedpanel')
+ })
+ $('.anbt_favpanel', true).forEach(favPanelButton => {
+ favPanelButton.addEventListener('click', () => {
+ if (favPanelButton.classList.contains('anbt_favedpanel')) return
+ const { parentNode } = favPanelButton
+ const id = parentNode
+ .querySelector('.gamepanel-tools>a:last-child')
+ .href.match(/\/panel\/[^/]+\/([^/]+)\/[^/]+\//)[1]
+ const panels = getLocalStorageItem('gpe_panelFavorites', {})
+ const panel = {
+ time: Date.now(),
+ by: parentNode.querySelector('.panel-user a').textContent
+ }
+ panel.userLink = parentNode
+ .querySelector('.panel-user a')
+ .href.match(/\/player\/[^/]+\/[^/]+\//)[0]
+ const img = parentNode.querySelector('.gamepanel img')
+ if (img) {
+ panel.image = img.src
+ panel.caption = img.alt
+ } else {
+ panel.caption = parentNode
+ .querySelector('.gamepanel')
+ .textContent.trim()
+ }
+ panels[id] = panel
+ localStorage.setItem('gpe_panelFavorites', JSON.stringify(panels))
+ favPanelButton.classList.add('anbt_favedpanel')
+ })
+ })
+ if (options.newCanvas) {
+ if (drawings)
+ drawings.forEach(drawing =>
+ drawing.addEventListener('load', addReplayButton(drawing))
+ )
+ }
+ setTimeout(waitForComments, 200)
+ }
+
+ const getCookie = name =>
+ document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`))[2] || null
+
+ const setCookie = (name, value, expire) => {
+ if (expire) {
+ const time = new Date()
+ time.setTime(time.getTime() + 24 * expire * 60 * 60 * 1e3)
+ expire = time.toUTCString()
+ }
+ document.cookie = `${name}=${value ? JSON.stringify(value) : ''}; expires=${
+ expire ? expire : 'Thu, 01 Jan 1970 00:00:00 UTC'
+ }; path=/`
+ }
+
+ const getPanelId = url => {
+ const match = url.match(/\/panel\/[^/]+\/(\w+)\//)
+ if (match) return match[1]
+ }
+
+ const base62ToDecimal = number => {
+ number = number.toString()
+ const cachePosition = {}
+ let result = 0
+ let pow = 1
+ for (let i = number.length - 1; i >= 0; i--) {
+ const character = number[i]
+ if (typeof cachePosition[character] === 'undefined') {
+ cachePosition[character] = globals.alphabet.indexOf(character)
+ }
+ result += pow * cachePosition[character]
+ pow *= 62
+ }
+ return result
+ }
+
+ const unscrambleID = string =>
+ base62ToDecimal([...string].reverse().join('')) - 3521614606208
+
+ const betterPanel = () => {
+ const favButton = $(
+ ''
+ )
+ const gamePanel = $(
+ '.panel-caption-display>.flex,.gamepanel-holder>.gamepanel'
+ )
+ if (gamePanel) gamePanel.insertAdjacentHTML('afterend', favButton.outerHTML)
+ const favBtn = $('.btn.btn-info')
+ if (favBtn) {
+ favBtn.addEventListener('click', event => {
+ event.preventDefault()
+ const panels = getLocalStorageItem('gpe_panelFavorites', {})
+ const panel = {
+ time: Date.now(),
+ by: $('.lead a', true)[0].textContent,
+ userLink: $('.lead a', true)[0].href.match(
+ /\/player\/[^/]+\/[^/]+\//
+ )[0]
+ }
+ const id = document.location.href.match(/\/panel\/[^/]+\/([^/]+)\//)[1]
+ const img = $('.gamepanel img')
+ if (img) {
+ panel.image = img.src
+ panel.caption = img.alt
+ } else {
+ panel.caption = $('.gamepanel').textContent.trim()
+ }
+ panels[id] = panel
+ localStorage.setItem('gpe_panelFavorites', JSON.stringify(panels))
+ favBtn.setAttribute('disabled', 'disabled')
+ favBtn.querySelector('b').textContent = 'Favorited!'
+ })
+ }
+ const panels = getLocalStorageItem('gpe_panelFavorites', {})
+ if (
+ document.location.href.match(/\/panel\/[^/]+\/([^/]+)\//) &&
+ panels[document.location.href.match(/\/panel\/[^/]+\/([^/]+)\//)[1]]
+ ) {
+ favBtn.setAttribute('disabled', 'disabled')
+ favBtn.querySelector('b').textContent = 'Favorited!'
+ }
+ const panelId = getPanelId(location.pathname)
+ if (options.newCanvas && panelId && unscrambleID(panelId) >= 14924553) {
+ const img = $('.gamepanel img')
+ if (img)
+ checkForRecording(img.src, () => {
+ const replayLink = $(
+ ` Replay `
+ )
+ replayLink.addEventListener('click', event => {
+ if (event.which === 2) return
+ event.preventDefault()
+ setupNewCanvas(true, `/sandbox/#${panelId}`)
+ })
+ $('.gamepanel').insertAdjacentHTML('afterend', replayLink.outerHTML)
+ })
+ }
+ if (
+ $('.btn-primary').length > 1 &&
+ $('.btn-primary')[1].textContent === 'Play again'
+ ) {
+ const ccButton = $(
+ ''
+ )
+ ccButton.addEventListener('click', event => {
+ event.preventDefault()
+ const id = unscrambleID(panelId)
+ const cookie = getCookie('covercreatorids')
+ const ids = cookie ? JSON.parse(cookie) : []
+ if (!ids.includes(id)) {
+ if (ids.length > 98) {
+ window.apprise(
+ 'Max cover creator drawings selected. Please remove some before adding more.'
+ )
+ return
+ } else ids.push(id.toString())
+ } else {
+ ccButton
+ .setAttribute('disabled', 'disabled')
+ .querySelector('b').textContent = 'Already added!'
+ return
+ }
+ setCookie('covercreatorids', JSON.stringify(ids))
+ ccButton
+ .setAttribute('disabled', 'disabled')
+ .querySelector('b').textContent = 'Added!'
+ })
+ $('.gamepanel').insertAdjacentHTML('afterend', ccButton.outerHTML)
+ }
+ }
+
+ const rot13 = number =>
+ [...number.toString()]
+ .map(character => {
+ character = character.charCodeAt(0)
+ if (character >= 97 && character <= 122)
+ character = ((character - 97 + 13) % 26) + 97
+ if (character >= 65 && character <= 90)
+ character = ((character - 65 + 13) % 26) + 65
+ return String.fromCharCode(character)
+ })
+ .join('')
+
+ const simpleHash = number =>
+ number
+ .toString()
+ .split('')
+ .reduce((a, b) => {
+ a = (a << 5) - a + b.charCodeAt(0)
+ return a & a
+ }, 0)
+
+ const randomGreeting = () => {
+ const change_every_half_day = Math.floor(Date.now() / (1000 * 60 * 60 * 12))
+ const rnddata = simpleHash(
+ change_every_half_day + parseInt(globals.userid, 10) + 178889
+ )
+ return rot13(globals.greetings[rnddata % globals.greetings.length])
+ }
+
+ const addReplaySign = drawing => {
+ if (drawing.replayAdded) return
+ drawing.replayAdded = true
+ const panel = drawing.parentNode.parentNode
+ const { src } = drawing
+ checkForRecording(src, () => {
+ const newid = src.match(/(\w+).png$/)[1]
+ const replaySign =
+ newid.length >= 8
+ ? $(
+ ``
+ )
+ : $(
+ ''
+ )
+ panel.appendChild(replaySign)
+ })
+ }
+
+ const fadeOut = (element, duration = 400) => {
+ duration = duration === 'slow' ? 600 : duration
+ element.style.opacity = element.style.opacity
+ ? parseFloat(element.style.opacity) - 0.1
+ : 1
+ if (parseFloat(element.style.opacity) < 0) {
+ element.style.opacity = 0
+ element.style.display = 'none'
+ } else
+ setTimeout(() => {
+ fadeOut(element, duration)
+ }, duration / 10)
+ }
+
+ const viewMyGameBookmarks = () => {
+ const removeButtonHTML =
+ ''
+ const games = getLocalStorageItem('gpe_gameBookmarks', {})
+ const result = []
+ for (let id in games) {
+ const extraClass = games[id].own ? ' anbt_owncaption' : ''
+ if (id.length > 10) {
+ result.push(
+ ``
+ )
+ const xhr = new XMLHttpRequest()
+ xhr.open('GET', `/play/${id}`)
+ xhr.onload = () => {
+ const { responseText, status } = xhr
+ if (status === 200) {
+ const m =
+ responseText.match(/Game is not private/) ||
+ (responseText.match(/Problem loading game/) && 'del')
+ if (m) {
+ const gamename =
+ `${
+ games[id].own
+ ? ` with your caption${
+ games[id].caption ? ` ${games[id].caption}` : ''
+ }`
+ : ''
+ }${
+ games[id].time
+ ? ` bookmarked on ${formatTimestamp(games[id].time)}`
+ : ''
+ }` || id
+ const status = m === 'del' ? 'Deleted' : 'Unfinished public'
+ $(`#${id}`).querySelector(
+ 'span'
+ ).textContent = `${status} game${gamename}`
+ return
+ }
+ const title = responseText.match(/(.+)<\/title>/)[1]
+ const [url, gameId] = responseText.match(/\/game\/([^/]+)\/[^/]+\//)
+ delete games[id]
+ games[gameId] = {
+ title,
+ url
+ }
+ $(`#${id}`).id = gameId
+ const spanId = $(`#${gameId}`).querySelector('span')
+ spanId.parentNode.replaceChild(
+ $(`${title}`),
+ spanId
+ )
+ localStorage.setItem('gpe_gameBookmarks', JSON.stringify(games))
+ } else {
+ $(`#${id}`).querySelector(
+ 'span'
+ ).textContent = `Error while retrieving game: ${responseText}`
+ }
+ }
+ xhr.send()
+ } else if (id.length === 10)
+ result.push(
+ ``
+ )
+ }
+ $('#anbt_userpage').innerHTML = result.length
+ ? result.join('')
+ : "You don't have any bookmarked games."
+ $('#anbt_userpage .anbt_gamedel', true).forEach(gameDelete =>
+ gameDelete.addEventListener('click', event => {
+ event.preventDefault()
+ const { id } = gameDelete.parentNode
+ fadeOut($(`#${id}`))
+ delete games[id]
+ localStorage.setItem('gpe_gameBookmarks', JSON.stringify(games))
+ })
+ )
+ }
+
+ const viewMyPanelFavorites = () => {
+ const panels = getLocalStorageItem('gpe_panelFavorites', {})
+ let result = ''
+ let needsUpdate = false
+ for (const id in panels) {
+ if (panels[id].image && panels[id].image.match(/^\/pub\/panels\//)) {
+ needsUpdate = true
+ panels[id].image = panels[id].image.replace(
+ '/pub/panels/',
+ 'https://cdn.drawception.com/images/panels/'
+ )
+ }
+ result += ``
+ }
+ if (needsUpdate)
+ localStorage.setItem('gpe_panelFavorites', JSON.stringify(panels))
+ result = result
+ ? `${result}`
+ : "You don't have any favorited panels."
+ $('#anbt_userpage').innerHTML = result
+ $('#anbt_userpage .anbt_paneldel', true).forEach(panelDelete =>
+ panelDelete.addEventListener('click', event => {
+ event.preventDefault()
+ const { id } = panelDelete.parentNode.parentNode
+ fadeOut($(`#${CSS.escape(id)}`))
+ delete panels[id]
+ localStorage.setItem('gpe_panelFavorites', JSON.stringify(panels))
+ })
+ )
+ }
+
+ const betterPlayer = () => {
+ const pubinfo = $('.profile-header-info .text-muted > span:last-child')
+ if (pubinfo) linkifyNodeText(pubinfo.parentNode)
+ const loc = document.location.href
+ if (loc.match(new RegExp(`/player/${globals.userId}/[^/]+/(?:$|#)`))) {
+ const anbtSection = $('ANBT stuff:
')
+ const panelFavoritesButton = $(
+ 'Panel Favorites'
+ )
+ const gameBookmarks = $(
+ 'Game Bookmarks'
+ )
+ anbtSection.appendChild(panelFavoritesButton)
+ anbtSection.appendChild(gameBookmarks)
+ const profilemain = $('.profile-layout-content').firstChild
+ profilemain.insertAdjacentHTML(
+ 'afterbegin',
+ `${randomGreeting()}
`
+ )
+ profilemain.insertAdjacentHTML('afterbegin', anbtSection.outerHTML)
+ $('.viewFavorites').addEventListener('click', event => {
+ event.preventDefault()
+ viewMyPanelFavorites()
+ })
+ $('.viewBookmarks').addEventListener('click', event => {
+ event.preventDefault()
+ viewMyGameBookmarks()
+ })
+ if (document.location.hash.includes('#anbt_panelfavorites'))
+ viewMyPanelFavorites()
+ if (document.location.hash.includes('#anbt_gamebookmarks'))
+ viewMyGameBookmarks()
+ if (window.date) {
+ const pubinfo = $('.profile-user-header>div.row>div>h1+p')
+ if (pubinfo)
+ [...pubinfo.childNodes][4].nodeValue = ` ${formatTimestamp(
+ window.date
+ )} \xa0`
+ }
+ } else {
+ const drawings = $(
+ 'img[src^="https://cdn.drawception.com/images/panels/"],img[src^="https://cdn.drawception.com/drawings/"]',
+ true
+ )
+ if (options.newCanvas)
+ drawings.forEach(drawing =>
+ drawing.addEventListener('load', addReplaySign(drawing))
+ )
+ drawings.forEach(({ src, parentNode }) => {
+ if (src.match(/-1\.png$/))
+ parentNode.parentNode.appendChild(
+ $(
+ '
'
+ )
+ )
+ })
+ }
+ if (loc.match(/player\/\d+\/[^/]+\/(posts)|(comments)\//)) {
+ $('.forum-thread-starter', true).forEach(threadStarter => {
+ const vue = threadStarter.childNodes[0].__vue__
+ if (vue) {
+ const ts = threadStarter.querySelector('a.text-muted').firstChild
+ ts.textContent = `${ts.textContent.trim()}, ${formatTimestamp(
+ vue.comment_date * 1000
+ )}`
+ if (vue.edit_date > 0) {
+ const el = ts.parentNode.parentNode.querySelector(
+ 'span[rel="tooltip"]'
+ )
+ const text = `${el.title}, ${formatTimestamp(
+ vue.edit_date * 1000
+ ).replace(/ /g, '\u00A0')}`
+ el.setAttribute('title', text)
+ }
+ }
+ const postlink = threadStarter.querySelector(
+ '.add-margin-top small.text-muted'
+ )
+ const created = postlink.textContent.match(/^\s*Created/)
+ const commented = postlink.textContent.match(/^\s*Commented/)
+ const prefix = commented
+ ? 'Comment in the game'
+ : created
+ ? 'New thread'
+ : 'Reply in'
+ const n = $(`${prefix}:
`)
+ const thread = postlink.querySelector('a')
+ n.appendChild(thread)
+ threadStarter.insertAdjacentHTML('afterbegin', n.outerHTML)
+ postlink.parentNode.parentNode.removeChild(postlink.parentNode)
+ })
+ }
+ }
+
+ const escapeHTML = value =>
+ value
+ .toString()
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''')
+
+ const addGroup = (name, settings) => {
+ const controlGroup = $('')
+ controlGroup.appendChild($(``))
+ settings.forEach(setting => {
+ const value = options[setting[0]]
+ const [name, type, description] = setting
+ const controls = $('')
+ if (type === 'boolean') {
+ controls.appendChild(
+ $(
+ ``
+ )
+ )
+ } else if (type === 'number') {
+ $(
+ `${description}:`
+ ).forEach(node => controls.appendChild(node))
+ } else if (type === 'longstr') {
+ $(
+ `${description}:`
+ ).forEach(node => controls.appendChild(node))
+ } else {
+ $(
+ `${description}:`
+ ).forEach(node => controls.appendChild(node))
+ }
+ controlGroup.appendChild(controls)
+ })
+ return controlGroup
+ }
+
+ const fadeIn = (element, duration = 400) => {
+ element.style.display = 'inline'
+ duration = duration === 'slow' ? 600 : duration
+ element.style.opacity = element.style.opacity
+ ? parseFloat(element.style.opacity) + 0.1
+ : 0.2
+ if (parseFloat(element.style.opacity) > 1) element.style.opacity = 1
+ else
+ setTimeout(() => {
+ fadeIn(element, duration)
+ }, duration / 10)
+ }
+
+ const loadScriptSettings = () => {
+ const result = getLocalStorageItem('gpe_anbtSettings', null)
+ if (!result) return
+ for (const i in result) window.options[i] = result[i]
+ }
+
+ const updateScriptSettings = ({ currentTarget: theForm }) => {
+ const result = {}
+ theForm.querySelectorAll('input,textarea').forEach(fromField => {
+ if (fromField.type === 'checkbox')
+ result[fromField.name] = fromField.checked ? 1 : 0
+ else if (fromField.getAttribute('data-subtype') === 'number')
+ result[fromField.name] = parseFloat(fromField.value) || 0
+ else result[fromField.name] = fromField.value
+ })
+ localStorage.setItem('gpe_anbtSettings', JSON.stringify(result))
+ loadScriptSettings()
+ fadeIn($('#anbtSettingsOK'), 'slow')
+ setTimeout(() => {
+ fadeOut($('#anbtSettingsOK'), 'slow')
+ }, 800)
+ }
+
+ const betterSettings = () => {
+ const theForm = $(
+ ''
+ )
+ theForm.appendChild($(''))
+ theForm.appendChild(
+ addGroup('Pen Tablet (unavailable for the moment...)', [
+ [
+ 'enableWacom',
+ 'boolean',
+ 'Enable Wacom plugin / pressure sensitivity support'
+ ],
+ [
+ 'fixTabletPluginGoingAWOL',
+ 'boolean',
+ 'Try to prevent Wacom plugin from disappearing'
+ ]
+ ])
+ )
+ theForm.appendChild(
+ addGroup('Play (most settings are for the new canvas only)', [
+ [
+ 'newCanvas',
+ 'boolean',
+ 'New drawing canvas (also allows watching playback)'
+ ],
+ [
+ 'submitConfirm',
+ 'boolean',
+ 'Confirm submitting if more than a minute is left'
+ ],
+ ['smoothening', 'boolean', 'Smoothing of strokes'],
+ ['hideCross', 'boolean', 'Hide the cross when drawing'],
+ [
+ 'enterToCaption',
+ 'boolean',
+ 'Submit captions (and start games) by pressing Enter'
+ ],
+ [
+ 'backup',
+ 'boolean',
+ 'Save the drawing in case of error and restore it in sandbox'
+ ],
+ [
+ 'timeoutSound',
+ 'boolean',
+ 'Warning sound when only a minute is left (normal games)'
+ ],
+ [
+ 'timeoutSoundBlitz',
+ 'boolean',
+ 'Warning sound when only 5 seconds left (blitz)'
+ ],
+ ['timeoutSoundVolume', 'number', 'Volume of the warning sound, in %'],
+ [
+ 'rememberPosition',
+ 'boolean',
+ 'Show your panel position and track changes in unfinished games list'
+ ],
+ ['colorNumberShortcuts', 'boolean', 'Use 0-9 keys to select the color'],
+ [
+ 'colorUnderCursorHint',
+ 'boolean',
+ 'Show the color under the cursor in the palette'
+ ],
+ [
+ 'colorDoublePress',
+ 'boolean',
+ 'Double press 0-9 keys to select color without pressing shift'
+ ],
+ [
+ 'bookmarkOwnCaptions',
+ 'boolean',
+ 'Automatically bookmark your own captions in case of dustcatchers'
+ ]
+ ])
+ )
+ theForm.appendChild(
+ addGroup('Miscellaneous', [
+ [
+ 'localeTimestamp',
+ 'boolean',
+ `Format timestamps as your system locale (${new Date().toLocaleString()})`
+ ],
+ [
+ 'proxyImgur',
+ 'boolean',
+ 'Replace imgur.com links to filmot.com to load, in case your ISP blocks them'
+ ],
+ ['ajaxRetry', 'boolean', 'Retry failed AJAX requests'],
+ [
+ 'autoplay',
+ 'boolean',
+ 'Automatically start replay when watching playback'
+ ],
+ ['autoBypassNSFW', 'boolean', 'Automatically bypass NSFW game warning'],
+ ['markStalePosts', 'boolean', 'Mark stale forum posts'],
+ [
+ 'maxCommentHeight',
+ 'number',
+ 'Maximum comments and posts height until directly linked (px, 0 = no limit)'
+ ],
+ [
+ 'useOldFont',
+ 'boolean',
+ 'Use old Nunito font (which is usually bolder and less wiggly)'
+ ],
+ ['useOldFontSize', 'boolean', 'Use old, smaller font size'],
+ ['markdownTools', 'boolean', 'Markdown tools for messages'],
+ [
+ 'anbtDarkMode',
+ 'boolean',
+ "Switch between ANBT's and Drawception's dark mode"
+ ]
+ ])
+ )
+ theForm.appendChild(
+ addGroup('Advanced', [
+ [
+ 'newCanvasCSS',
+ 'longstr',
+ 'Custom CSS for new canvas (experimental, get styles here)'
+ ],
+ [
+ 'forumHiddenUsers',
+ 'longstr',
+ 'Comma-separated list of user IDs whose forum posts are hidden'
+ ]
+ ])
+ )
+ $(
+ '
'
+ ).forEach(node => theForm.appendChild(node))
+ $('#main').insertAdjacentHTML('afterbegin', theForm.outerHTML)
+ $('.settingsForm').addEventListener(
+ 'submit',
+ form => updateScriptSettings(form) && false
+ )
+ if ($('input[name="location"]'))
+ $('input[name="location"]').setAttribute('maxlength', '65')
+ }
+
+ const betterPages = {
+ betterCreate,
+ betterForums,
+ betterGame,
+ betterPanel,
+ betterPlayer,
+ betterSettings
+ }
+
+ const bold = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = new RegExp(`\\*\\*(${selection.replace(/\*/g, '')})\\*\\*`)
+ if (selection.match(selRegex)) selection = selection.replace(selRegex, '$1')
+ else if (selectionStart > 0 && selectionEnd < length) {
+ if (
+ value.substring(selectionStart - 1, selectionEnd + 1).match(selRegex)
+ ) {
+ selectionStart--
+ selectionEnd++
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else if (
+ value.substring(selectionStart - 2, selectionEnd + 2).match(selRegex)
+ ) {
+ selectionStart -= 2
+ selectionEnd += 2
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else
+ selection = selection.match(/\*\*.+\*\*/g)
+ ? selection.replace(/\*\*/g, '')
+ : `**${selection.replace(/\n/g, '**\n**')}**`
+ } else {
+ if (
+ !selectionStart &&
+ value.substring(selectionStart, selectionEnd + 1).match(selRegex)
+ ) {
+ selectionEnd++
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else if (
+ selectionEnd === length &&
+ value.substring(selectionStart - 1, selectionEnd).match(selRegex)
+ ) {
+ selectionStart--
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else
+ selection = selection.match(/\*\*.+\*\*/g)
+ ? selection.replace(/\*\*/g, '')
+ : `**${selection.replace(/\n/g, '**\n**')}**`
+ }
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection +
+ value.substring(selectionEnd, length)
+ }
+
+ const code = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = /^ {4}(.*)/gm
+ if (selection.match(selRegex)) selection = selection.replace(/^ {4}/gm, '')
+ else if (
+ selectionStart === 0 ||
+ value.substring(selectionStart - 1, selectionEnd).match(/\n.*/gm)
+ ) {
+ if (selection.match(/^ {4}/gm))
+ selection = selection.replace(/^ {4}/gm, '')
+ else
+ selection = `${
+ selectionStart === 0
+ ? ''
+ : value.substring(selectionStart - 1, selectionEnd).match(/^\n/)
+ ? '\n'
+ : '\n\n'
+ } ${selection.replace(/\n/g, '\n ')}`
+ } else
+ selection = `${
+ value.substring(selectionStart - 1, selectionEnd).match(/^\n/)
+ ? '\n'
+ : '\n\n'
+ } ${selection.replace(/\n^(.*)/gm, '\n $1')}${
+ value.substring(selectionEnd, selectionEnd + 1).match(/\n/) ? '' : '\n'
+ }`
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection +
+ value.substring(selectionEnd, length)
+ }
+
+ const heading = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = /^#+ .*/gm
+ if (selection.match(selRegex)) {
+ selection = selection.replace(/^# /gm, '')
+ if (selection.match(/^#{2,} /gm)) selection.replace(/(^#*)# /gm, '$1 ')
+ } else if (
+ !selectionStart ||
+ value.substring(selectionStart - 1, selectionEnd).match(/\n.*/gm)
+ )
+ selection = `${
+ value.substring(selectionStart - 1, selectionEnd).match(/\n^.*/gm) ||
+ !selectionStart
+ ? ''
+ : '\n'
+ }###### ${selection.replace(/\n/g, '\n###### ')}`
+ else if (
+ value.substring(selectionStart - 1, selectionEnd).match(selRegex)
+ ) {
+ selectionStart -= 4
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(/(^#*)# /gm, '$1 ')
+ } else if (
+ value.substring(selectionStart - 2, selectionEnd).match(selRegex)
+ ) {
+ selectionStart -= 5
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(/(^#*)# /gm, '$1 ')
+ } else selection = `\n###### ${selection.replace(/\n/g, '\n###### ')}`
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection +
+ value.substring(selectionEnd, length)
+ }
+
+ const highlighter = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = new RegExp(`\`(${selection.replace(/`/g, '')})\``)
+ if (selection.match(selRegex)) selection = selection.replace(selRegex, '$1')
+ else if (selectionStart > 0 && selectionEnd < length) {
+ if (
+ value.substring(selectionStart - 1, selectionEnd + 1).match(selRegex)
+ ) {
+ selectionStart--
+ selectionEnd++
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else {
+ selection = selection.match(/`.+`/g)
+ ? selection.replace(/`/g, '')
+ : `\`${selection.replace(/\n/g, '`\n`')}\``
+ }
+ } else {
+ if (
+ !selectionStart &&
+ value.substring(selectionStart, selectionEnd + 1).match(selRegex)
+ ) {
+ selectionEnd++
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else if (
+ selectionEnd === length &&
+ value.substring(selectionStart - 1, selectionEnd).match(selRegex)
+ ) {
+ selectionStart--
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else {
+ selection = selection.match(/`.+`/g)
+ ? selection.replace(/`/g, '')
+ : `\`${selection.replace(/\n/g, '`\n`')}\``
+ }
+ }
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection +
+ value.substring(selectionEnd, length)
+ }
+
+ const image = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = /!\[(.*)\]\((\S*)( ".*")?\)/
+ if (selection.match(selRegex))
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection.replace(selRegex, '$1 $2') +
+ value.substring(selectionEnd, length)
+ else {
+ let link = ''
+ if (!selection.match(/\[(.*)\]\((\S*)( ".*")?\)/)) {
+ link = selection.match(/https?:\/\/\S*/) || ''
+ selection = selection
+ .replace(link[0], '')
+ .replace(/ +/g, ' ')
+ .trim()
+ } else selection = ''
+ const divModal = $(
+ ``
+ )
+ $('.navbar-header>div:last-child').append(divModal)
+ setTimeout(() => {
+ document.body.classList.add('v--modal-block-scroll')
+ $('#markdown').style.opacity = 1
+ }, 1)
+ $('#markdown-text').value = selection ? selection : ''
+ $('#markdown-link').value = link ? link[0] : ''
+ $('.close').addEventListener('click', () => {
+ document.body.classList.remove('v--modal-block-scroll')
+ $('#markdown').outerHTML = ''
+ })
+ $('#markdown-done').addEventListener('click', () => {
+ const tag = `.value
+ }${
+ $('#markdown-hover').value ? ` "${$('#markdown-hover').value}"` : ''
+ })`
+ selection = value.substring(selectionStart, selectionEnd)
+ textarea.value =
+ value.substring(0, selectionStart) +
+ (selection.match(/\[(.*)\]\((\S*)( ".*")?\)/)
+ ? selection.replace(/\[.*\]/, `[${tag}]`)
+ : tag) +
+ value.substring(selectionEnd, length)
+ document.body.classList.remove('v--modal-block-scroll')
+ $('#markdown').outerHTML = ''
+ })
+ }
+ }
+
+ const italic = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = new RegExp(
+ `\\*(?=\\S*${selection.replace(
+ /(.*)\*(.*)/g,
+ ''
+ )})((?:\\*\\*|\\\\[\\s\\S]|\\s+(?:\\\\[\\s\\S]|[^\\s\\*\\\\]|\\*\\*)|[^\\s\\*\\\\])+?)\\*(?!\\*)`
+ )
+ const italicRegex = /\*(?=\S)((?:\*\*|\\[\s\S]|\s+(?:\\[\s\S]|[^\s\*\\]|\*\*)|[^\s\*\\])+?)\*(?!\*)/g
+ if (selection.match(selRegex)) selection = selection.replace(selRegex, '$1')
+ else if (selectionStart > 0 && selectionEnd < length) {
+ if (
+ value.substring(selectionStart - 1, selectionEnd + 1).match(selRegex)
+ ) {
+ selectionStart--
+ selectionEnd++
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else {
+ selection = selection.match(italicRegex)
+ ? selection.replace(italicRegex, '$1')
+ : `*${selection.replace(/\n/g, '*\n*')}*`
+ }
+ } else {
+ if (
+ !selectionStart &&
+ value.substring(selectionStart, selectionEnd + 1).match(selRegex)
+ ) {
+ selectionEnd++
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else if (
+ selectionEnd === length &&
+ value.substring(selectionStart - 1, selectionEnd).match(selRegex)
+ ) {
+ selectionStart--
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else
+ selection = selection.match(italicRegex)
+ ? selection.replace(italicRegex, '$1')
+ : `*${selection.replace(/\n/g, '*\n*')}*`
+ }
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection +
+ value.substring(selectionEnd, length)
+ }
+
+ const link = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = /^(?!!)\[(.*)\]\((\S*)( ".*")?\)/
+ if (selection.match(selRegex))
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection.replace(selRegex, '$1 $2') +
+ value.substring(selectionEnd, length)
+ else {
+ let imageLink = ''
+ if (!selection.match(/!\[(.*)\]\((\S*)( ".*")?\)/)) {
+ imageLink = selection.match(/https?:\/\/\S*/) || ''
+ selection = selection
+ .replace(imageLink[0], '')
+ .replace(/ +/g, ' ')
+ .trim()
+ }
+ const divModal = $(
+ ``
+ )
+ $('.navbar-header>div:last-child').append(divModal)
+ setTimeout(() => {
+ document.body.classList.add('v--modal-block-scroll')
+ $('#markdown').style.opacity = 1
+ }, 1)
+ $('#markdown-text').value = selection ? selection : ''
+ $('#markdown-link').value = imageLink ? imageLink[0] : ''
+ $('.close').addEventListener('click', () => {
+ document.body.classList.remove('v--modal-block-scroll')
+ $('#markdown').outerHTML = ''
+ })
+ $('#markdown-done').addEventListener('click', () => {
+ selection = `[${$('#markdown-text').value}](${
+ $('#markdown-link').value
+ }${
+ $('#markdown-hover').value ? ` "${$('#markdown-hover').value}"` : ''
+ })`
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection +
+ value.substring(selectionEnd, length)
+ document.body.classList.remove('v--modal-block-scroll')
+ $('#markdown').outerHTML = ''
+ })
+ }
+ }
+
+ const listOl = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = /^( {3})*\d+\. (.*)/gm
+ if (selection.match(selRegex)) {
+ selection = selection.match(/^ {3}/)
+ ? selection.replace(/^ {3}/gm, '')
+ : selection.replace(/^\d+\. /gm, '')
+ } else if (
+ !selectionStart ||
+ value.substring(selectionStart - 1, selectionEnd).match(/^\n.*/)
+ ) {
+ let countOl = 0
+ selection = `${
+ value.substring(selectionStart - 1, selectionEnd).match(/\n^.*/gm) ||
+ !selectionStart
+ ? ''
+ : '\n'
+ }0. ${selection.replace(/\n/g, () => {
+ countOl++
+ return `\n${countOl}. `
+ })}${
+ value.substring(selectionEnd, selectionEnd + 2).match(/\n\n/)
+ ? ''
+ : value.substring(selectionEnd, selectionEnd + 1).match(/\n/)
+ ? '\n'
+ : '\n\n'
+ }`
+ } else if (
+ value
+ .substring(selectionStart - 4, selectionEnd)
+ .match(/( {3})*\d+\. (.*)/)
+ ) {
+ selectionStart -= 4
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(/( {3})*(\d+\.) /g, ' $1$2 ')
+ } else if (
+ value
+ .substring(selectionStart - 5, selectionEnd)
+ .match(/( {3})*\d+\. (.*)/)
+ ) {
+ selectionStart -= 5
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(/( {3})*(\d+\.) /g, ' $1$2 ')
+ } else {
+ let countOl = 0
+ selection = `\n0. ${selection.replace(/\n/g, () => {
+ countOl++
+ return `\n${countOl}. `
+ })}${
+ value.substring(selectionEnd, selectionEnd + 2).match(/\n\n/) ||
+ selectionEnd === length
+ ? ''
+ : value.substring(selectionEnd, selectionEnd + 1).match(/\n/)
+ ? '\n'
+ : '\n\n'
+ }`
+ }
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection +
+ value.substring(selectionEnd, length)
+ }
+
+ const listUl = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = /^( {3})*- (.*)/
+ if (selection.match(selRegex))
+ selection = selection.match(/^ {3}/)
+ ? selection.replace(/^ {3}/gm, '')
+ : selection.replace(/^- /gm, '')
+ else if (
+ !selectionStart ||
+ value.substring(selectionStart - 1, selectionEnd).match(/^\n.*/)
+ )
+ selection = `${
+ value.substring(selectionStart - 1, selectionEnd).match(/\n^.*/gm) ||
+ !selectionStart
+ ? ''
+ : '\n'
+ }- ${selection.replace(/\n/g, '\n- ')}${
+ value.substring(selectionEnd, selectionEnd + 2).match(/\n\n/)
+ ? ''
+ : value.substring(selectionEnd, selectionEnd + 1).match(/\n/)
+ ? '\n'
+ : '\n\n'
+ }`
+ else if (
+ value.substring(selectionStart - 1, selectionEnd).match(selRegex)
+ ) {
+ selectionStart--
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(/( {3})*- /g, '$1 - ')
+ } else if (
+ value.substring(selectionStart - 2, selectionEnd).match(selRegex)
+ ) {
+ selectionStart -= 2
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(/( {3})*- /g, '$1 - ')
+ } else
+ selection = `\n- ${selection.replace(/\n/g, '\n- ')}${
+ value.substring(selectionEnd, selectionEnd + 2).match(/\n\n/) ||
+ selectionEnd === length
+ ? ''
+ : value.substring(selectionEnd, selectionEnd + 1).match(/\n/)
+ ? '\n'
+ : '\n\n'
+ }`
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection +
+ value.substring(selectionEnd, length)
+ }
+
+ const quoteRight = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = /^>+\s.*/gm
+ if (selection.match(selRegex))
+ selection = selection.match(/^> /gm)
+ ? selection.replace(/^> /gm, '')
+ : selection.replace(/(^>*)> /gm, '$1 ')
+ else if (
+ !selectionStart ||
+ value.substring(selectionStart - 1, selectionEnd).match(/^\n.*/)
+ )
+ selection = `${
+ value.substring(selectionStart - 1, selectionEnd).match(/\n^.*/gm) ||
+ !selectionStart
+ ? ''
+ : '\n'
+ }> ${selection.replace(/\n/g, '\n> ')}${
+ value.substring(selectionEnd, selectionEnd + 2).match(/\n\n/)
+ ? ''
+ : value.substring(selectionEnd, selectionEnd + 1).match(/\n/)
+ ? '\n'
+ : '\n\n'
+ }`
+ else if (
+ value.substring(selectionStart - 1, selectionEnd).match(selRegex)
+ ) {
+ selectionStart--
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(/(^>*)\s/gm, '$1> ')
+ } else if (
+ value.substring(selectionStart - 2, selectionEnd).match(selRegex)
+ ) {
+ selectionStart -= 2
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(/(^>*)\s/gm, '$1> ')
+ } else
+ selection = `\n> ${selection.replace(/\n/g, '\n> ')}${
+ value.substring(selectionEnd, selectionEnd + 2).match(/\n\n/) ||
+ selectionEnd === length
+ ? ''
+ : value.substring(selectionEnd, selectionEnd + 1).match(/\n/)
+ ? '\n'
+ : '\n\n'
+ }`
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection +
+ value.substring(selectionEnd, length)
+ }
+
+ const strikethrough = (
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ ) => {
+ const selRegex = /~~((.*\W?)*)~~/
+ if (selection.match(selRegex)) selection = selection.replace(selRegex, '$1')
+ else if (selectionStart > 0 && selectionEnd < length) {
+ if (selection.match(selRegex)) selection.replace(selRegex, '$1')
+ else if (
+ value.substring(selectionStart - 1, selectionEnd + 1).match(selRegex)
+ ) {
+ selectionStart--
+ selectionEnd++
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else if (
+ value.substring(selectionStart - 2, selectionEnd + 2).match(selRegex)
+ ) {
+ selectionStart -= 2
+ selectionEnd += 2
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else {
+ selection = selection.match(/~~.+~~/g)
+ ? selection.replace(/~~/g, '')
+ : `~~${selection}~~`
+ }
+ } else {
+ if (
+ !selectionStart &&
+ value.substring(selectionStart, selectionEnd + 1).match(selRegex)
+ ) {
+ selectionEnd++
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else if (
+ selectionEnd === length &&
+ value.substring(selectionStart - 1, selectionEnd).match(selRegex)
+ ) {
+ selectionStart--
+ selection = value
+ .substring(selectionStart, selectionEnd)
+ .replace(selRegex, '$1')
+ } else {
+ selection = selection.match(/~~.+~~/g)
+ ? selection.replace(/~~/g, '')
+ : `~~${selection}~~`
+ }
+ }
+ textarea.value =
+ value.substring(0, selectionStart) +
+ selection +
+ value.substring(selectionEnd, length)
+ }
+
+ const markdown = {
+ bold: {
+ title: 'bold text',
+ replaceFunc: bold
+ },
+ italic: {
+ title: 'italic text',
+ replaceFunc: italic
+ },
+ heading: {
+ title: 'enlarges/reduces the text',
+ replaceFunc: heading
+ },
+ strikethrough: {
+ title: 'strikethrough text',
+ replaceFunc: strikethrough
+ },
+ highlighter: {
+ title: 'highlighted text',
+ replaceFunc: highlighter
+ },
+ 'list-ul': {
+ title: 'unordered list',
+ replaceFunc: listUl
+ },
+ 'list-ol': {
+ title: 'ordered list',
+ replaceFunc: listOl
+ },
+ 'quote-right': {
+ title: 'quote',
+ replaceFunc: quoteRight
+ },
+ code: {
+ title: 'block of code',
+ replaceFunc: code
+ },
+ link: {
+ title: 'insert link',
+ replaceFunc: link
+ },
+ image: {
+ title: 'insert image',
+ replaceFunc: image
+ }
+ }
+
+ const getSelectedText = event => {
+ const textarea = $('#input-comment')
+ const { value, selectionStart, selectionEnd } = textarea
+ const { length } = value
+ const selection = value.substring(selectionStart, selectionEnd)
+ markdown[`${event.currentTarget.id}`].replaceFunc(
+ value,
+ length,
+ selectionStart,
+ selectionEnd,
+ selection,
+ textarea
+ )
+ }
+
+ const addMarkdownTools = () => {
+ const textarea = $('#input-comment')
+ if (!textarea) return
+ const markdownDiv = $('')
+ Object.keys(markdown).forEach(toolName =>
+ markdownDiv.appendChild(
+ $(
+ ``
+ )
+ )
+ )
+ textarea.insertAdjacentHTML('beforebegin', markdownDiv.outerHTML)
+ ;[...$('#markdown-editor').children].forEach(children =>
+ children.addEventListener('click', getSelectedText)
+ )
+ }
+
+ const getNotifications = () => {
+ if (!window.notificationsOpened) {
+ $('#user-notify-list').innerHTML =
+ '
'
+ const xhr = new XMLHttpRequest()
+ xhr.open('GET', '/notification/view/')
+ xhr.onload = () => {
+ if (xhr.status === 200) {
+ $('#user-notify-list').innerHTML = xhr.responseText
+ $('#user-notify-count').textContent = '0'
+ window.notificationsOpened = true
+ } else {
+ $('#user-notify-list').innerHTML = xhr.responseText
+ window.notificationsOpened = true
+ }
+ }
+ }
+ }
+
+ const pageEnhancements = () => {
+ loadScriptSettings()
+ if (typeof DrawceptionPlay === 'undefined') return
+ if (document.getElementById('newcanvasyo')) return
+ try {
+ const tmpuserlink = $('.player-dropdown a[href^="/player/"]')
+ const username = tmpuserlink.querySelector('strong').textContent
+ const userid = tmpuserlink.href.match(/\/player\/(\d+)\//)[1]
+ localStorage.setItem('gpe_lastSeenName', username)
+ localStorage.setItem('gpe_lastSeenId', userid)
+ } catch (e) {}
+ const currentPage = location.href.match(/drawception\.com\/([^/]+)/)
+ if (currentPage) {
+ const page = currentPage[1]
+ const functionName = `better${page.replace(
+ page[0],
+ page[0].toUpperCase()
+ )}`
+ if (betterPages[functionName]) betterPages[functionName]()
+ }
+ addStyle(
+ '.panel-user {width: auto} .panel-details img.loading {display: none}' +
+ '.gpe-wide, .gpe-wide-block {display: none}' +
+ '.gpe-btn {padding: 5px 8px; height: 28px}' +
+ '.gpe-spacer {margin-right: 7px; float:left}' +
+ '@media (min-width:992px) {.navbar-toggle,.btn-menu-player {display: none} .gpe-wide {display: inline} .gpe-wide-block {display: block}}' +
+ '@media (min-width:1200px) {.gpe-btn {padding: 5px 16px;} .gpe-spacer {margin-right: 20px;} .panel-number {left: -30px}}' +
+ '#anbtver {font-size: 10px; position:absolute; opacity:0.3; right:10px; top: 0;}' +
+ '.anbt_paneldel {position:absolute; padding:1px 6px; color:#FFF; background:#d9534f; text-decoration: none !important; right: 18px; border-radius: 5px}' +
+ '.anbt_paneldel:hover {background:#d2322d}' +
+ '.anbt_favpanel {top: 20px; font-weight: normal; padding: 0 2px}' +
+ '.anbt_favpanel:hover {color: #d9534f; cursor:pointer}' +
+ '.anbt_favedpanel {color: #d9534f; border-color: #d9534f}' +
+ '.anbt_replaypanel {top: 55px; font-weight: normal; padding: 0 8px}' +
+ '.anbt_replaypanel:hover {color: #8af; text-decoration: none}' +
+ ".anbt_owncaption:before {content: ''; display: inline-block; background: #5C5; border: 1px solid #080; width: 10px; height: 10px; border-radius: 10px; margin-right: 10px;}" +
+ '.gamepanel, .thumbpanel, .comment-body {word-wrap: break-word}' +
+ '.comment-body img {max-width: 100%}' +
+ '.forum-thread.anbt_hidden {display: none}' +
+ '.anbt_showt .forum-thread.anbt_hidden {display: block; opacity: 0.6}' +
+ ".anbt_unhidet:after {content: ' threads hidden. Show'}" +
+ ".anbt_showt .anbt_unhidet:after {content: ' threads hidden. Hide'}" +
+ ".anbt_hft:after {content: '[hide]'}" +
+ '.anbt_hft, .anbt_unhidet {padding-left: 0.4em; cursor:pointer}' +
+ ".forum-thread.anbt_hidden .anbt_hft:after {content: '[show]'}" +
+ '.anbt_threadtitle {margin: 0 0 10px}' +
+ '.avatar {box-sizing: content-box}' +
+ '.pagination {margin: 0px}' +
+ '#nav-drag {position: fixed; width: 100%; z-index: 2000}' +
+ '#header-bar-container {position: relative; width: 100%; top: 6rem}' +
+ '.wrapper {position: relative; top: 6rem}' +
+ 'footer {position: relative; top: 6rem}' +
+ '.option span:first-child {display: flex; flex-direction: row; justify-content: space-between}' +
+ '.grid-settings div[class^="grid-"] label {display: inline-flex}' +
+ 'input[type="checkbox"], input[type="radio"] {margin:4px 4px 0 0}' +
+ '@-moz-document url-prefix() {input[type="checkbox"], input[type="radio"] {margin:0 4px 0 0}}' +
+ '.tooltip {z-index: 3000;}'
+ )
+ if (options.maxCommentHeight) {
+ const maxHeight = options.maxCommentHeight
+ addStyle(
+ `.comment-holder[id]:not(:target) .comment-body {overflow-y: hidden; max-height: ${maxHeight}px; position:relative}.comment-holder[id]:not(:target) .comment-body:before{content: 'Click to read more'; position:absolute; width:100%; height:50px; left:0; top:${maxHeight -
+ 50}px;text-align: center; font-weight: bold; color: #fff; text-shadow: 0 0 2px #000; padding-top: 20px; background:linear-gradient(transparent, rgba(0,0,0,0.4))}`
+ )
+ $('.comment-body', true).forEach(comment =>
+ comment.addEventListener('click', () => {
+ if (
+ comment.clientHeight > maxHeight - 50 &&
+ location.hash.indexOf(comment) === -1
+ )
+ location.hash = `#${comment.parentNode.parentNode.id}`
+ })
+ )
+ }
+ if (options.useOldFontSize) document.body.style.fontSize = '15px'
+ if (options.useOldFont) {
+ const nunito = $("link[href*='Nunito']")
+ nunito.parentNode.removeChild(nunito)
+ addStyle(
+ "@import url('https://fonts.googleapis.com/css?family=Nunito&display=swap')"
+ )
+ }
+ if (options.anbtDarkMode) {
+ if (document.body.classList.contains('theme-night')) {
+ document.body.classList.remove('theme-night')
+ setCookie('theme-night')
+ }
+ }
+ if (options.markdownTools) addMarkdownTools()
+ if (options.newCanvas) {
+ const inSandbox = location.href.match(/drawception\.com\/sandbox\/#?(.*)/)
+ const inPlay = location.href.match(
+ /drawception\.com\/(:?contests\/)?play\/(.*)/
+ )
+ const hasCanvas = document.getElementById('canvas-holder')
+ const hasCanvasOrGameForm = document.querySelector('.playtimer')
+ const captionContest =
+ location.href.match(/contests\/play\//) && !hasCanvas
+ if (!captionContest && (inSandbox || (inPlay && hasCanvasOrGameForm))) {
+ setTimeout(() => setupNewCanvas(inSandbox, location.href), 1)
+ return
+ }
+ $('a[href^="/sandbox/"]', true).forEach(sandboxButton =>
+ sandboxButton.addEventListener('click', event => {
+ if (event.which === 2) return
+ event.preventDefault()
+ setupNewCanvas(true, event.currentTarget.href)
+ })
+ )
+ $('a[href="/play/"]', true).forEach(playButton =>
+ playButton.addEventListener('click', event => {
+ if (event.which === 2) return
+ event.preventDefault()
+ setupNewCanvas(false, event.currentTarget.href)
+ })
+ )
+ }
+ if ($('.navbar-toggle')) {
+ const navbarToggle = $('.navbar-toggle').parentNode
+ const navbarButtonsList = [
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ ''
+ ]
+ navbarButtonsList.forEach(button => navbarToggle.appendChild($(button)))
+ $('#main-menu').insertAdjacentHTML(
+ 'afterbegin',
+ ' Toggle light'
+ )
+ }
+ const menuPlayer = $('.btn-menu-player')
+ if (menuPlayer) {
+ const userlink = $('.player-dropdown a[href^="/player/"]').href
+ const useravatar = $('.btn-menu-player').innerHTML
+ const element = $(
+ `${useravatar}`
+ )
+ menuPlayer.parentNode.appendChild(element)
+ }
+ const num =
+ $('#user-notify-count') && $('#user-notify-count').textContent.trim()
+ addStyle(
+ `#user-notify-list .list-group .list-group-item .fas {color: #888}#user-notify-list .list-group .list-group-item:nth-child(-n+${num}) .fas {color: #2F5}a.wrong-order {color: #F99} div.comment-holder:target {background-color: #DFD}.comment-new a.text-muted:last-child:after {content: 'New'; color: #2F5; font-weight: bold; background-color: #183; border-radius: 9px; display: inline-block; padding: 0px 6px; margin-left: 10px;}`
+ )
+ window.getNotifications = getNotifications
+ let versionDisplay = `ANBT v${versions.scriptVersion}`
+ try {
+ const appver = $('script[src^="/build/app"]').src.match(/(\w+)\.js$/)[1]
+ const runtimever = $('script[src^="/build/runtime"]').src.match(
+ /(\w+)\.js$/
+ )[1]
+ versionDisplay += ` | app ${appver}`
+ if (appver !== versions.siteVersion) versionDisplay += '*'
+ versionDisplay += ` | runtime ${runtimever}`
+ if (runtimever !== versions.runtimeVersion) versionDisplay += '*!!!'
+ } catch (e) {}
+ const wrapperSection = $('.wrapper')
+ if (wrapperSection)
+ wrapperSection.appendChild($(`${versionDisplay}
`))
+ const linkList = [
+ 'ANBT script',
+ 'Wiki',
+ 'Chat (Discord)'
+ ]
+ $('.footer-main .list-unstyled').forEach((list, index) =>
+ list.appendChild($(linkList[index]))
+ )
+ }
+
+ const wrapper = () => {
+ window.options = options
+ const mark = document.createElement('b')
+ mark.id = '_anbt_'
+ mark.style.display = 'none'
+ document.body.appendChild(mark)
+ if (!window.DrawceptionPlay) {
+ const loader = setInterval(() => {
+ if (!window.DrawceptionPlay) return
+ pageEnhancements()
+ clearInterval(loader)
+ }, 100)
+ } else pageEnhancements()
+ }
+
+ addDarkCSS()
+ setDarkMode()
+ if (document && document.body) {
+ if (!document.getElementById('_anbt_')) wrapper()
+ if (window.opera && !getLocalStorageItem('gpe_operaWarning', 0)) {
+ const anbtTitle = document.createElement('h2')
+ anbtTitle.innerHTML =
+ 'ANBT speaking:
Rename your script file so it doesn\'t contain ".user." part for smoother loading!
This warning is only shown once.'
+ const mainSection = document.getElementById('main')
+ mainSection.insertBefore(anbtTitle, mainSection.firstChild)
+ localStorage.setItem('gpe_operaWarning', 1)
+ }
+ }
+ document.addEventListener(
+ 'DOMContentLoaded',
+ () => {
+ if (!document.getElementById('_anbt_')) wrapper()
+ },
+ false
+ )
+})()
diff --git a/build/index.html b/build/index.html
new file mode 100644
index 0000000..9fe71c5
--- /dev/null
+++ b/build/index.html
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+ New Canvas - Drawception
+
+
+
+
+
+ Fetching your Drawception game...
+
+
+
+
+
Time's up!
Submit now or miss the game!
+
+
+
![]()
+
+
+
46
+
+
+
+
+ Sandbox
+ Public safe for work game
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Guidelines
+
+ - Simple drawings are welcome! Just give it your best shot
+ - If the phrase is too difficult, use the skip button
+ - Don't draw text - always draw a picture
+ - Explicit (NSFW) drawings will get you banned
+
+
+
Tips
+
+ - No explicit language allowed
+ - Keep descriptions short and simple!
+ - Avoid unnecessary detail, just describe the main subject
+ - No metacommentary (e.g., don't comment on drawing quality)
+ - No idea? Use the skip button
+
+
+
Sandbox
+
+ - Welcome to the sandbox! Here you can play with all the palettes and drawing tools.
+ - Saved drawings will contain your drawing process in PNG format.
+ - After loading a drawing you can continue to draw or watch its playback.
+ - Note that editing the PNG with playback with other programs will likely destroy the playback data.
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/newcanvas/index.html b/build/newcanvas/index.html
new file mode 100644
index 0000000..3140894
--- /dev/null
+++ b/build/newcanvas/index.html
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+ New Canvas - Drawception
+
+
+
+
+
+ Fetching your Drawception game...
+
+
+
+
+
Time's up!
Submit now or miss the game!
+
+
+
![]()
+
+
+
46
+
+
+
+
+ Sandbox
+ Public safe for work game
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Guidelines
+
+ - Simple drawings are welcome! Just give it your best shot
+ - If the phrase is too difficult, use the skip button
+ - Don't draw text - always draw a picture
+ - Explicit (NSFW) drawings will get you banned
+
+
+
Tips
+
+ - No explicit language allowed
+ - Keep descriptions short and simple!
+ - Avoid unnecessary detail, just describe the main subject
+ - No metacommentary (e.g., don't comment on drawing quality)
+ - No idea? Use the skip button
+
+
+
Sandbox
+
+ - Welcome to the sandbox! Here you can play with all the palettes and drawing tools.
+ - Saved drawings will contain your drawing process in PNG format.
+ - After loading a drawing you can continue to draw or watch its playback.
+ - Note that editing the PNG with playback with other programs will likely destroy the playback data.
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/newcanvas/pako.js b/build/newcanvas/pako.js
new file mode 100644
index 0000000..95f74ab
--- /dev/null
+++ b/build/newcanvas/pako.js
@@ -0,0 +1 @@
+!function(){"use strict";var t,e=(function(t,e){var a="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;function i(t,e){return Object.prototype.hasOwnProperty.call(t,e)}e.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var a=e.shift();if(a){if("object"!=typeof a)throw new TypeError(a+"must be non-object");for(var n in a)i(a,n)&&(t[n]=a[n])}}return t},e.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var n={arraySet:function(t,e,a,i,n){if(e.subarray&&t.subarray)t.set(e.subarray(a,a+i),n);else for(var r=0;r=0;)t[e]=0}var o=0,h=1,l=2,d=29,_=256,f=_+1+d,u=30,c=19,w=2*f+1,g=15,b=16,m=7,p=256,v=16,k=17,y=18,x=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],z=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],B=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],E=new Array(2*(f+2));s(E);var A=new Array(2*u);s(A);var Z=new Array(512);s(Z);var R=new Array(256);s(R);var C=new Array(d);s(C);var N,I,O,D=new Array(u);function T(t,e,a,i,n){this.static_tree=t,this.extra_bits=e,this.extra_base=a,this.elems=i,this.max_length=n,this.has_stree=t&&t.length}function U(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}function F(t){return t<256?Z[t]:Z[256+(t>>>7)]}function L(t,e){t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255}function H(t,e,a){t.bi_valid>b-a?(t.bi_buf|=e<>b-t.bi_valid,t.bi_valid+=a-b):(t.bi_buf|=e<>>=1,a<<=1}while(--e>0);return a>>>1}function M(t,e,a){var i,n,r=new Array(g+1),s=0;for(i=1;i<=g;i++)r[i]=s=s+a[i-1]<<1;for(n=0;n<=e;n++){var o=t[2*n+1];0!==o&&(t[2*n]=K(r[o]++,o))}}function P(t){var e;for(e=0;e8?L(t,t.bi_buf):t.bi_valid>0&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0}function G(t,e,a,i){var n=2*e,r=2*a;return t[n]>1;a>=1;a--)X(t,r,a);n=h;do{a=t.heap[1],t.heap[1]=t.heap[t.heap_len--],X(t,r,1),i=t.heap[1],t.heap[--t.heap_max]=a,t.heap[--t.heap_max]=i,r[2*n]=r[2*a]+r[2*i],t.depth[n]=(t.depth[a]>=t.depth[i]?t.depth[a]:t.depth[i])+1,r[2*a+1]=r[2*i+1]=n,t.heap[1]=n++,X(t,r,1)}while(t.heap_len>=2);t.heap[--t.heap_max]=t.heap[1],function(t,e){var a,i,n,r,s,o,h=e.dyn_tree,l=e.max_code,d=e.stat_desc.static_tree,_=e.stat_desc.has_stree,f=e.stat_desc.extra_bits,u=e.stat_desc.extra_base,c=e.stat_desc.max_length,b=0;for(r=0;r<=g;r++)t.bl_count[r]=0;for(h[2*t.heap[t.heap_max]+1]=0,a=t.heap_max+1;ac&&(r=c,b++),h[2*i+1]=r,i>l||(t.bl_count[r]++,s=0,i>=u&&(s=f[i-u]),o=h[2*i],t.opt_len+=o*(r+s),_&&(t.static_len+=o*(d[2*i+1]+s)));if(0!==b){do{for(r=c-1;0===t.bl_count[r];)r--;t.bl_count[r]--,t.bl_count[r+1]+=2,t.bl_count[c]--,b-=2}while(b>0);for(r=c;0!==r;r--)for(i=t.bl_count[r];0!==i;)(n=t.heap[--a])>l||(h[2*n+1]!==r&&(t.opt_len+=(r-h[2*n+1])*h[2*n],h[2*n+1]=r),i--)}}(t,e),M(r,l,t.bl_count)}function J(t,e,a){var i,n,r=-1,s=e[1],o=0,h=7,l=4;for(0===s&&(h=138,l=3),e[2*(a+1)+1]=65535,i=0;i<=a;i++)n=s,s=e[2*(i+1)+1],++o>=7;i0?(t.strm.data_type===r&&(t.strm.data_type=function(t){var e,a=4093624447;for(e=0;e<=31;e++,a>>>=1)if(1&a&&0!==t.dyn_ltree[2*e])return i;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return n;for(e=32;e<_;e++)if(0!==t.dyn_ltree[2*e])return n;return i}(t)),q(t,t.l_desc),q(t,t.d_desc),u=function(t){var e;for(J(t,t.dyn_ltree,t.l_desc.max_code),J(t,t.dyn_dtree,t.d_desc.max_code),q(t,t.bl_desc),e=c-1;e>=3&&0===t.bl_tree[2*S[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}(t),d=t.opt_len+3+7>>>3,(f=t.static_len+3+7>>>3)<=d&&(d=f)):d=f=s+5,s+4<=d&&-1!==e?$(t,e,s,o):t.strategy===a||f===d?(H(t,(h<<1)+(o?1:0),3),W(t,E,A)):(H(t,(l<<1)+(o?1:0),3),function(t,e,a,i){var n;for(H(t,e-257,5),H(t,a-1,5),H(t,i-4,4),n=0;n>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&a,t.last_lit++,0===e?t.dyn_ltree[2*a]++:(t.matches++,e--,t.dyn_ltree[2*(R[a]+_+1)]++,t.dyn_dtree[2*F(e)]++),t.last_lit===t.lit_bufsize-1},_tr_align:function(t){H(t,h<<1,3),j(t,p,E),function(t){16===t.bi_valid?(L(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):t.bi_valid>=8&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}(t)}};var et=function(t,e,a,i){for(var n=65535&t|0,r=t>>>16&65535|0,s=0;0!==a;){a-=s=a>2e3?2e3:a;do{r=r+(n=n+e[i++]|0)|0}while(--s);n%=65521,r%=65521}return n|r<<16|0};var at=function(){for(var t,e=[],a=0;a<256;a++){t=a;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[a]=t}return e}();var it,nt=function(t,e,a,i){var n=at,r=i+a;t^=-1;for(var s=i;s>>8^n[255&(t^e[s])];return-1^t},rt={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"},st=0,ot=1,ht=3,lt=4,dt=5,_t=0,ft=1,ut=-2,ct=-3,wt=-5,gt=-1,bt=1,mt=2,pt=3,vt=4,kt=0,yt=2,xt=8,zt=9,Bt=15,St=8,Et=286,At=30,Zt=19,Rt=2*Et+1,Ct=15,Nt=3,It=258,Ot=It+Nt+1,Dt=32,Tt=42,Ut=69,Ft=73,Lt=91,Ht=103,jt=113,Kt=666,Mt=1,Pt=2,Yt=3,Gt=4,Xt=3;function Wt(t,e){return t.msg=rt[e],e}function qt(t){return(t<<1)-(t>4?9:0)}function Jt(t){for(var e=t.length;--e>=0;)t[e]=0}function Qt(t){var a=t.state,i=a.pending;i>t.avail_out&&(i=t.avail_out),0!==i&&(e.arraySet(t.output,a.pending_buf,a.pending_out,i,t.next_out),t.next_out+=i,a.pending_out+=i,t.total_out+=i,t.avail_out-=i,a.pending-=i,0===a.pending&&(a.pending_out=0))}function Vt(t,e){tt._tr_flush_block(t,t.block_start>=0?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,Qt(t.strm)}function $t(t,e){t.pending_buf[t.pending++]=e}function te(t,e){t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e}function ee(t,e){var a,i,n=t.max_chain_length,r=t.strstart,s=t.prev_length,o=t.nice_match,h=t.strstart>t.w_size-Ot?t.strstart-(t.w_size-Ot):0,l=t.window,d=t.w_mask,_=t.prev,f=t.strstart+It,u=l[r+s-1],c=l[r+s];t.prev_length>=t.good_match&&(n>>=2),o>t.lookahead&&(o=t.lookahead);do{if(l[(a=e)+s]===c&&l[a+s-1]===u&&l[a]===l[r]&&l[++a]===l[r+1]){r+=2,a++;do{}while(l[++r]===l[++a]&&l[++r]===l[++a]&&l[++r]===l[++a]&&l[++r]===l[++a]&&l[++r]===l[++a]&&l[++r]===l[++a]&&l[++r]===l[++a]&&l[++r]===l[++a]&&rs){if(t.match_start=e,s=i,i>=o)break;u=l[r+s-1],c=l[r+s]}}}while((e=_[e&d])>h&&0!=--n);return s<=t.lookahead?s:t.lookahead}function ae(t){var a,i,n,r,s,o,h,l,d,_,f=t.w_size;do{if(r=t.window_size-t.lookahead-t.strstart,t.strstart>=f+(f-Ot)){e.arraySet(t.window,t.window,f,f,0),t.match_start-=f,t.strstart-=f,t.block_start-=f,a=i=t.hash_size;do{n=t.head[--a],t.head[a]=n>=f?n-f:0}while(--i);a=i=f;do{n=t.prev[--a],t.prev[a]=n>=f?n-f:0}while(--i);r+=f}if(0===t.strm.avail_in)break;if(o=t.strm,h=t.window,l=t.strstart+t.lookahead,d=r,_=void 0,(_=o.avail_in)>d&&(_=d),i=0===_?0:(o.avail_in-=_,e.arraySet(h,o.input,o.next_in,_,l),1===o.state.wrap?o.adler=et(o.adler,h,_,l):2===o.state.wrap&&(o.adler=nt(o.adler,h,_,l)),o.next_in+=_,o.total_in+=_,_),t.lookahead+=i,t.lookahead+t.insert>=Nt)for(s=t.strstart-t.insert,t.ins_h=t.window[s],t.ins_h=(t.ins_h<=Nt&&(t.ins_h=(t.ins_h<=Nt)if(i=tt._tr_tally(t,t.strstart-t.match_start,t.match_length-Nt),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=Nt){t.match_length--;do{t.strstart++,t.ins_h=(t.ins_h<=Nt&&(t.ins_h=(t.ins_h<4096)&&(t.match_length=Nt-1)),t.prev_length>=Nt&&t.match_length<=t.prev_length){n=t.strstart+t.lookahead-Nt,i=tt._tr_tally(t,t.strstart-1-t.prev_match,t.prev_length-Nt),t.lookahead-=t.prev_length-1,t.prev_length-=2;do{++t.strstart<=n&&(t.ins_h=(t.ins_h<15&&(o=2,n-=16),r<1||r>zt||i!==xt||n<8||n>15||a<0||a>9||s<0||s>vt)return Wt(t,ut);8===n&&(n=9);var h=new se;return t.state=h,h.strm=t,h.wrap=o,h.gzhead=null,h.w_bits=n,h.w_size=1<t.pending_buf_size-5&&(a=t.pending_buf_size-5);;){if(t.lookahead<=1){if(ae(t),0===t.lookahead&&e===st)return Mt;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;var i=t.block_start+a;if((0===t.strstart||t.strstart>=i)&&(t.lookahead=t.strstart-i,t.strstart=i,Vt(t,!1),0===t.strm.avail_out))return Mt;if(t.strstart-t.block_start>=t.w_size-Ot&&(Vt(t,!1),0===t.strm.avail_out))return Mt}return t.insert=0,e===lt?(Vt(t,!0),0===t.strm.avail_out?Yt:Gt):(t.strstart>t.block_start&&(Vt(t,!1),t.strm.avail_out),Mt)}),new re(4,4,8,4,ie),new re(4,5,16,8,ie),new re(4,6,32,32,ie),new re(4,4,16,16,ne),new re(8,16,32,32,ne),new re(8,16,128,128,ne),new re(8,32,128,256,ne),new re(32,128,258,1024,ne),new re(32,258,258,4096,ne)];var de={deflateInit:function(t,e){return le(t,e,xt,Bt,St,kt)},deflateInit2:le,deflateReset:he,deflateResetKeep:oe,deflateSetHeader:function(t,e){return t&&t.state?2!==t.state.wrap?ut:(t.state.gzhead=e,_t):ut},deflate:function(t,e){var a,i,n,r;if(!t||!t.state||e>dt||e<0)return t?Wt(t,ut):ut;if(i=t.state,!t.output||!t.input&&0!==t.avail_in||i.status===Kt&&e!==lt)return Wt(t,0===t.avail_out?wt:ut);if(i.strm=t,a=i.last_flush,i.last_flush=e,i.status===Tt)if(2===i.wrap)t.adler=0,$t(i,31),$t(i,139),$t(i,8),i.gzhead?($t(i,(i.gzhead.text?1:0)+(i.gzhead.hcrc?2:0)+(i.gzhead.extra?4:0)+(i.gzhead.name?8:0)+(i.gzhead.comment?16:0)),$t(i,255&i.gzhead.time),$t(i,i.gzhead.time>>8&255),$t(i,i.gzhead.time>>16&255),$t(i,i.gzhead.time>>24&255),$t(i,9===i.level?2:i.strategy>=mt||i.level<2?4:0),$t(i,255&i.gzhead.os),i.gzhead.extra&&i.gzhead.extra.length&&($t(i,255&i.gzhead.extra.length),$t(i,i.gzhead.extra.length>>8&255)),i.gzhead.hcrc&&(t.adler=nt(t.adler,i.pending_buf,i.pending,0)),i.gzindex=0,i.status=Ut):($t(i,0),$t(i,0),$t(i,0),$t(i,0),$t(i,0),$t(i,9===i.level?2:i.strategy>=mt||i.level<2?4:0),$t(i,Xt),i.status=jt);else{var s=xt+(i.w_bits-8<<4)<<8;s|=(i.strategy>=mt||i.level<2?0:i.level<6?1:6===i.level?2:3)<<6,0!==i.strstart&&(s|=Dt),s+=31-s%31,i.status=jt,te(i,s),0!==i.strstart&&(te(i,t.adler>>>16),te(i,65535&t.adler)),t.adler=1}if(i.status===Ut)if(i.gzhead.extra){for(n=i.pending;i.gzindex<(65535&i.gzhead.extra.length)&&(i.pending!==i.pending_buf_size||(i.gzhead.hcrc&&i.pending>n&&(t.adler=nt(t.adler,i.pending_buf,i.pending-n,n)),Qt(t),n=i.pending,i.pending!==i.pending_buf_size));)$t(i,255&i.gzhead.extra[i.gzindex]),i.gzindex++;i.gzhead.hcrc&&i.pending>n&&(t.adler=nt(t.adler,i.pending_buf,i.pending-n,n)),i.gzindex===i.gzhead.extra.length&&(i.gzindex=0,i.status=Ft)}else i.status=Ft;if(i.status===Ft)if(i.gzhead.name){n=i.pending;do{if(i.pending===i.pending_buf_size&&(i.gzhead.hcrc&&i.pending>n&&(t.adler=nt(t.adler,i.pending_buf,i.pending-n,n)),Qt(t),n=i.pending,i.pending===i.pending_buf_size)){r=1;break}r=i.gzindexn&&(t.adler=nt(t.adler,i.pending_buf,i.pending-n,n)),0===r&&(i.gzindex=0,i.status=Lt)}else i.status=Lt;if(i.status===Lt)if(i.gzhead.comment){n=i.pending;do{if(i.pending===i.pending_buf_size&&(i.gzhead.hcrc&&i.pending>n&&(t.adler=nt(t.adler,i.pending_buf,i.pending-n,n)),Qt(t),n=i.pending,i.pending===i.pending_buf_size)){r=1;break}r=i.gzindexn&&(t.adler=nt(t.adler,i.pending_buf,i.pending-n,n)),0===r&&(i.status=Ht)}else i.status=Ht;if(i.status===Ht&&(i.gzhead.hcrc?(i.pending+2>i.pending_buf_size&&Qt(t),i.pending+2<=i.pending_buf_size&&($t(i,255&t.adler),$t(i,t.adler>>8&255),t.adler=0,i.status=jt)):i.status=jt),0!==i.pending){if(Qt(t),0===t.avail_out)return i.last_flush=-1,_t}else if(0===t.avail_in&&qt(e)<=qt(a)&&e!==lt)return Wt(t,wt);if(i.status===Kt&&0!==t.avail_in)return Wt(t,wt);if(0!==t.avail_in||0!==i.lookahead||e!==st&&i.status!==Kt){var o=i.strategy===mt?function(t,e){for(var a;;){if(0===t.lookahead&&(ae(t),0===t.lookahead)){if(e===st)return Mt;break}if(t.match_length=0,a=tt._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,a&&(Vt(t,!1),0===t.strm.avail_out))return Mt}return t.insert=0,e===lt?(Vt(t,!0),0===t.strm.avail_out?Yt:Gt):t.last_lit&&(Vt(t,!1),0===t.strm.avail_out)?Mt:Pt}(i,e):i.strategy===pt?function(t,e){for(var a,i,n,r,s=t.window;;){if(t.lookahead<=It){if(ae(t),t.lookahead<=It&&e===st)return Mt;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=Nt&&t.strstart>0&&(i=s[n=t.strstart-1])===s[++n]&&i===s[++n]&&i===s[++n]){r=t.strstart+It;do{}while(i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&nt.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=Nt?(a=tt._tr_tally(t,1,t.match_length-Nt),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(a=tt._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),a&&(Vt(t,!1),0===t.strm.avail_out))return Mt}return t.insert=0,e===lt?(Vt(t,!0),0===t.strm.avail_out?Yt:Gt):t.last_lit&&(Vt(t,!1),0===t.strm.avail_out)?Mt:Pt}(i,e):it[i.level].func(i,e);if(o!==Yt&&o!==Gt||(i.status=Kt),o===Mt||o===Yt)return 0===t.avail_out&&(i.last_flush=-1),_t;if(o===Pt&&(e===ot?tt._tr_align(i):e!==dt&&(tt._tr_stored_block(i,0,0,!1),e===ht&&(Jt(i.head),0===i.lookahead&&(i.strstart=0,i.block_start=0,i.insert=0))),Qt(t),0===t.avail_out))return i.last_flush=-1,_t}return e!==lt?_t:i.wrap<=0?ft:(2===i.wrap?($t(i,255&t.adler),$t(i,t.adler>>8&255),$t(i,t.adler>>16&255),$t(i,t.adler>>24&255),$t(i,255&t.total_in),$t(i,t.total_in>>8&255),$t(i,t.total_in>>16&255),$t(i,t.total_in>>24&255)):(te(i,t.adler>>>16),te(i,65535&t.adler)),Qt(t),i.wrap>0&&(i.wrap=-i.wrap),0!==i.pending?_t:ft)},deflateEnd:function(t){var e;return t&&t.state?(e=t.state.status)!==Tt&&e!==Ut&&e!==Ft&&e!==Lt&&e!==Ht&&e!==jt&&e!==Kt?Wt(t,ut):(t.state=null,e===jt?Wt(t,ct):_t):ut},deflateSetDictionary:function(t,a){var i,n,r,s,o,h,l,d,_=a.length;if(!t||!t.state)return ut;if(2===(s=(i=t.state).wrap)||1===s&&i.status!==Tt||i.lookahead)return ut;for(1===s&&(t.adler=et(t.adler,a,_,0)),i.wrap=0,_>=i.w_size&&(0===s&&(Jt(i.head),i.strstart=0,i.block_start=0,i.insert=0),d=new e.Buf8(i.w_size),e.arraySet(d,a,_-i.w_size,i.w_size,0),a=d,_=i.w_size),o=t.avail_in,h=t.next_in,l=t.input,t.avail_in=_,t.next_in=0,t.input=a,ae(i);i.lookahead>=Nt;){n=i.strstart,r=i.lookahead-(Nt-1);do{i.ins_h=(i.ins_h<=252?6:ce>=248?5:ce>=240?4:ce>=224?3:ce>=192?2:1;ue[254]=ue[254]=1;function we(t,a){if(a<65534&&(t.subarray&&fe||!t.subarray&&_e))return String.fromCharCode.apply(null,e.shrinkBuf(t,a));for(var i="",n=0;n>>6,a[s++]=128|63&i):i<65536?(a[s++]=224|i>>>12,a[s++]=128|i>>>6&63,a[s++]=128|63&i):(a[s++]=240|i>>>18,a[s++]=128|i>>>12&63,a[s++]=128|i>>>6&63,a[s++]=128|63&i);return a},buf2binstring:function(t){return we(t,t.length)},binstring2buf:function(t){for(var a=new e.Buf8(t.length),i=0,n=a.length;i4)o[i++]=65533,a+=r-1;else{for(n&=2===r?31:3===r?15:7;r>1&&a1?o[i++]=65533:n<65536?o[i++]=n:(n-=65536,o[i++]=55296|n>>10&1023,o[i++]=56320|1023&n)}return we(o,i)},utf8border:function(t,e){var a;for((e=e||t.length)>t.length&&(e=t.length),a=e-1;a>=0&&128==(192&t[a]);)a--;return a<0?e:0===a?e:a+ue[t[a]]>e?a:e}};var be=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0},me=Object.prototype.toString,pe=0,ve=-1,ke=0,ye=8;function xe(t){if(!(this instanceof xe))return new xe(t);this.options=e.assign({level:ve,method:ye,chunkSize:16384,windowBits:15,memLevel:8,strategy:ke,to:""},t||{});var a=this.options;a.raw&&a.windowBits>0?a.windowBits=-a.windowBits:a.gzip&&a.windowBits>0&&a.windowBits<16&&(a.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new be,this.strm.avail_out=0;var i=de.deflateInit2(this.strm,a.level,a.method,a.windowBits,a.memLevel,a.strategy);if(i!==pe)throw new Error(rt[i]);if(a.header&&de.deflateSetHeader(this.strm,a.header),a.dictionary){var n;if(n="string"==typeof a.dictionary?ge.string2buf(a.dictionary):"[object ArrayBuffer]"===me.call(a.dictionary)?new Uint8Array(a.dictionary):a.dictionary,(i=de.deflateSetDictionary(this.strm,n))!==pe)throw new Error(rt[i]);this._dict_set=!0}}function ze(t,e){var a=new xe(e);if(a.push(t,!0),a.err)throw a.msg||rt[a.err];return a.result}xe.prototype.push=function(t,a){var i,n,r=this.strm,s=this.options.chunkSize;if(this.ended)return!1;n=a===~~a?a:!0===a?4:0,"string"==typeof t?r.input=ge.string2buf(t):"[object ArrayBuffer]"===me.call(t)?r.input=new Uint8Array(t):r.input=t,r.next_in=0,r.avail_in=r.input.length;do{if(0===r.avail_out&&(r.output=new e.Buf8(s),r.next_out=0,r.avail_out=s),1!==(i=de.deflate(r,n))&&i!==pe)return this.onEnd(i),this.ended=!0,!1;0!==r.avail_out&&(0!==r.avail_in||4!==n&&2!==n)||("string"===this.options.to?this.onData(ge.buf2binstring(e.shrinkBuf(r.output,r.next_out))):this.onData(e.shrinkBuf(r.output,r.next_out)))}while((r.avail_in>0||0===r.avail_out)&&1!==i);return 4===n?(i=de.deflateEnd(this.strm),this.onEnd(i),this.ended=!0,i===pe):2!==n||(this.onEnd(pe),r.avail_out=0,!0)},xe.prototype.onData=function(t){this.chunks.push(t)},xe.prototype.onEnd=function(t){t===pe&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=e.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg};var Be={Deflate:xe,deflate:ze,deflateRaw:function(t,e){return(e=e||{}).raw=!0,ze(t,e)},gzip:function(t,e){return(e=e||{}).gzip=!0,ze(t,e)}},Se=function(t,e){var a,i,n,r,s,o,h,l,d,_,f,u,c,w,g,b,m,p,v,k,y,x,z,B,S;a=t.state,i=t.next_in,B=t.input,n=i+(t.avail_in-5),r=t.next_out,S=t.output,s=r-(e-t.avail_out),o=r+(t.avail_out-257),h=a.dmax,l=a.wsize,d=a.whave,_=a.wnext,f=a.window,u=a.hold,c=a.bits,w=a.lencode,g=a.distcode,b=(1<>>=v=p>>>24,c-=v,0===(v=p>>>16&255))S[r++]=65535&p;else{if(!(16&v)){if(0==(64&v)){p=w[(65535&p)+(u&(1<>>=v,c-=v),c<15&&(u+=B[i++]<>>=v=p>>>24,c-=v,!(16&(v=p>>>16&255))){if(0==(64&v)){p=g[(65535&p)+(u&(1<h){t.msg="invalid distance too far back",a.mode=30;break t}if(u>>>=v,c-=v,y>(v=r-s)){if((v=y-v)>d&&a.sane){t.msg="invalid distance too far back",a.mode=30;break t}if(x=0,z=f,0===_){if(x+=l-v,v2;)S[r++]=z[x++],S[r++]=z[x++],S[r++]=z[x++],k-=3;k&&(S[r++]=z[x++],k>1&&(S[r++]=z[x++]))}else{x=r-y;do{S[r++]=S[x++],S[r++]=S[x++],S[r++]=S[x++],k-=3}while(k>2);k&&(S[r++]=S[x++],k>1&&(S[r++]=S[x++]))}break}}break}}while(i>3,u&=(1<<(c-=k<<3))-1,t.next_in=i,t.next_out=r,t.avail_in=i=1&&0===C[y];y--);if(x>y&&(x=y),0===y)return r[s++]=20971520,r[s++]=20971520,h.bits=1,0;for(k=1;k0&&(0===t||1!==y))return-1;for(N[1]=0,p=1;p<15;p++)N[p+1]=N[p]+C[p];for(v=0;v852||2===t&&E>592)return 1;for(;;){w=p-B,o[v]c?(g=I[O+o[v]],b=Z[R+o[v]]):(g=96,b=0),l=1<>B)+(d-=l)]=w<<24|g<<16|b|0}while(0!==d);for(l=1<>=1;if(0!==l?(A&=l-1,A+=l):A=0,v++,0==--C[p]){if(p===y)break;p=a[i+o[v]]}if(p>x&&(A&f)!==_){for(0===B&&(B=x),u+=k,S=1<<(z=p-B);z+B852||2===t&&E>592)return 1;r[_=A&f]=x<<24|z<<16|u-s|0}}return 0!==A&&(r[u+A]=p-B<<24|64<<16|0),h.bits=x,0},Ne=0,Ie=1,Oe=2,De=4,Te=5,Ue=6,Fe=0,Le=1,He=2,je=-2,Ke=-3,Me=-4,Pe=-5,Ye=8,Ge=1,Xe=2,We=3,qe=4,Je=5,Qe=6,Ve=7,$e=8,ta=9,ea=10,aa=11,ia=12,na=13,ra=14,sa=15,oa=16,ha=17,la=18,da=19,_a=20,fa=21,ua=22,ca=23,wa=24,ga=25,ba=26,ma=27,pa=28,va=29,ka=30,ya=31,xa=32,za=852,Ba=592,Sa=15;function Ea(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function Aa(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new e.Buf16(320),this.work=new e.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function Za(t){var a;return t&&t.state?(a=t.state,t.total_in=t.total_out=a.total=0,t.msg="",a.wrap&&(t.adler=1&a.wrap),a.mode=Ge,a.last=0,a.havedict=0,a.dmax=32768,a.head=null,a.hold=0,a.bits=0,a.lencode=a.lendyn=new e.Buf32(za),a.distcode=a.distdyn=new e.Buf32(Ba),a.sane=1,a.back=-1,Fe):je}function Ra(t){var e;return t&&t.state?((e=t.state).wsize=0,e.whave=0,e.wnext=0,Za(t)):je}function Ca(t,e){var a,i;return t&&t.state?(i=t.state,e<0?(a=0,e=-e):(a=1+(e>>4),e<48&&(e&=15)),e&&(e<8||e>15)?je:(null!==i.window&&i.wbits!==e&&(i.window=null),i.wrap=a,i.wbits=e,Ra(t))):je}function Na(t,e){var a,i;return t?(i=new Aa,t.state=i,i.window=null,(a=Ca(t,e))!==Fe&&(t.state=null),a):je}var Ia,Oa,Da=!0;function Ta(t){if(Da){var a;for(Ia=new e.Buf32(512),Oa=new e.Buf32(32),a=0;a<144;)t.lens[a++]=8;for(;a<256;)t.lens[a++]=9;for(;a<280;)t.lens[a++]=7;for(;a<288;)t.lens[a++]=8;for(Ce(Ie,t.lens,0,288,Ia,0,t.work,{bits:9}),a=0;a<32;)t.lens[a++]=5;Ce(Oe,t.lens,0,32,Oa,0,t.work,{bits:5}),Da=!1}t.lencode=Ia,t.lenbits=9,t.distcode=Oa,t.distbits=5}function Ua(t,a,i,n){var r,s=t.state;return null===s.window&&(s.wsize=1<=s.wsize?(e.arraySet(s.window,a,i-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):((r=s.wsize-s.wnext)>n&&(r=n),e.arraySet(s.window,a,i-n,r,s.wnext),(n-=r)?(e.arraySet(s.window,a,i-n,n,0),s.wnext=n,s.whave=s.wsize):(s.wnext+=r,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,i.check=nt(i.check,A,2,0),d=0,_=0,i.mode=Xe;break}if(i.flags=0,i.head&&(i.head.done=!1),!(1&i.wrap)||(((255&d)<<8)+(d>>8))%31){t.msg="incorrect header check",i.mode=ka;break}if((15&d)!==Ye){t.msg="unknown compression method",i.mode=ka;break}if(_-=4,x=8+(15&(d>>>=4)),0===i.wbits)i.wbits=x;else if(x>i.wbits){t.msg="invalid window size",i.mode=ka;break}i.dmax=1<>8&1),512&i.flags&&(A[0]=255&d,A[1]=d>>>8&255,i.check=nt(i.check,A,2,0)),d=0,_=0,i.mode=We;case We:for(;_<32;){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}i.head&&(i.head.time=d),512&i.flags&&(A[0]=255&d,A[1]=d>>>8&255,A[2]=d>>>16&255,A[3]=d>>>24&255,i.check=nt(i.check,A,4,0)),d=0,_=0,i.mode=qe;case qe:for(;_<16;){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}i.head&&(i.head.xflags=255&d,i.head.os=d>>8),512&i.flags&&(A[0]=255&d,A[1]=d>>>8&255,i.check=nt(i.check,A,2,0)),d=0,_=0,i.mode=Je;case Je:if(1024&i.flags){for(;_<16;){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}i.length=d,i.head&&(i.head.extra_len=d),512&i.flags&&(A[0]=255&d,A[1]=d>>>8&255,i.check=nt(i.check,A,2,0)),d=0,_=0}else i.head&&(i.head.extra=null);i.mode=Qe;case Qe:if(1024&i.flags&&((c=i.length)>h&&(c=h),c&&(i.head&&(x=i.head.extra_len-i.length,i.head.extra||(i.head.extra=new Array(i.head.extra_len)),e.arraySet(i.head.extra,n,s,c,x)),512&i.flags&&(i.check=nt(i.check,n,c,s)),h-=c,s+=c,i.length-=c),i.length))break t;i.length=0,i.mode=Ve;case Ve:if(2048&i.flags){if(0===h)break t;c=0;do{x=n[s+c++],i.head&&x&&i.length<65536&&(i.head.name+=String.fromCharCode(x))}while(x&&c>9&1,i.head.done=!0),t.adler=i.check=0,i.mode=ia;break;case ea:for(;_<32;){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}t.adler=i.check=Ea(d),d=0,_=0,i.mode=aa;case aa:if(0===i.havedict)return t.next_out=o,t.avail_out=l,t.next_in=s,t.avail_in=h,i.hold=d,i.bits=_,He;t.adler=i.check=1,i.mode=ia;case ia:if(a===Te||a===Ue)break t;case na:if(i.last){d>>>=7&_,_-=7&_,i.mode=ma;break}for(;_<3;){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}switch(i.last=1&d,_-=1,3&(d>>>=1)){case 0:i.mode=ra;break;case 1:if(Ta(i),i.mode=_a,a===Ue){d>>>=2,_-=2;break t}break;case 2:i.mode=ha;break;case 3:t.msg="invalid block type",i.mode=ka}d>>>=2,_-=2;break;case ra:for(d>>>=7&_,_-=7&_;_<32;){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}if((65535&d)!=(d>>>16^65535)){t.msg="invalid stored block lengths",i.mode=ka;break}if(i.length=65535&d,d=0,_=0,i.mode=sa,a===Ue)break t;case sa:i.mode=oa;case oa:if(c=i.length){if(c>h&&(c=h),c>l&&(c=l),0===c)break t;e.arraySet(r,n,s,c,o),h-=c,s+=c,l-=c,o+=c,i.length-=c;break}i.mode=ia;break;case ha:for(;_<14;){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}if(i.nlen=257+(31&d),d>>>=5,_-=5,i.ndist=1+(31&d),d>>>=5,_-=5,i.ncode=4+(15&d),d>>>=4,_-=4,i.nlen>286||i.ndist>30){t.msg="too many length or distance symbols",i.mode=ka;break}i.have=0,i.mode=la;case la:for(;i.have>>=3,_-=3}for(;i.have<19;)i.lens[Z[i.have++]]=0;if(i.lencode=i.lendyn,i.lenbits=7,B={bits:i.lenbits},z=Ce(Ne,i.lens,0,19,i.lencode,0,i.work,B),i.lenbits=B.bits,z){t.msg="invalid code lengths set",i.mode=ka;break}i.have=0,i.mode=da;case da:for(;i.have>>16&255,p=65535&E,!((b=E>>>24)<=_);){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}if(p<16)d>>>=b,_-=b,i.lens[i.have++]=p;else{if(16===p){for(S=b+2;_>>=b,_-=b,0===i.have){t.msg="invalid bit length repeat",i.mode=ka;break}x=i.lens[i.have-1],c=3+(3&d),d>>>=2,_-=2}else if(17===p){for(S=b+3;_>>=b)),d>>>=3,_-=3}else{for(S=b+7;_>>=b)),d>>>=7,_-=7}if(i.have+c>i.nlen+i.ndist){t.msg="invalid bit length repeat",i.mode=ka;break}for(;c--;)i.lens[i.have++]=x}}if(i.mode===ka)break;if(0===i.lens[256]){t.msg="invalid code -- missing end-of-block",i.mode=ka;break}if(i.lenbits=9,B={bits:i.lenbits},z=Ce(Ie,i.lens,0,i.nlen,i.lencode,0,i.work,B),i.lenbits=B.bits,z){t.msg="invalid literal/lengths set",i.mode=ka;break}if(i.distbits=6,i.distcode=i.distdyn,B={bits:i.distbits},z=Ce(Oe,i.lens,i.nlen,i.ndist,i.distcode,0,i.work,B),i.distbits=B.bits,z){t.msg="invalid distances set",i.mode=ka;break}if(i.mode=_a,a===Ue)break t;case _a:i.mode=fa;case fa:if(h>=6&&l>=258){t.next_out=o,t.avail_out=l,t.next_in=s,t.avail_in=h,i.hold=d,i.bits=_,Se(t,u),o=t.next_out,r=t.output,l=t.avail_out,s=t.next_in,n=t.input,h=t.avail_in,d=i.hold,_=i.bits,i.mode===ia&&(i.back=-1);break}for(i.back=0;m=(E=i.lencode[d&(1<>>16&255,p=65535&E,!((b=E>>>24)<=_);){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}if(m&&0==(240&m)){for(v=b,k=m,y=p;m=(E=i.lencode[y+((d&(1<>v)])>>>16&255,p=65535&E,!(v+(b=E>>>24)<=_);){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}d>>>=v,_-=v,i.back+=v}if(d>>>=b,_-=b,i.back+=b,i.length=p,0===m){i.mode=ba;break}if(32&m){i.back=-1,i.mode=ia;break}if(64&m){t.msg="invalid literal/length code",i.mode=ka;break}i.extra=15&m,i.mode=ua;case ua:if(i.extra){for(S=i.extra;_>>=i.extra,_-=i.extra,i.back+=i.extra}i.was=i.length,i.mode=ca;case ca:for(;m=(E=i.distcode[d&(1<>>16&255,p=65535&E,!((b=E>>>24)<=_);){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}if(0==(240&m)){for(v=b,k=m,y=p;m=(E=i.distcode[y+((d&(1<>v)])>>>16&255,p=65535&E,!(v+(b=E>>>24)<=_);){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}d>>>=v,_-=v,i.back+=v}if(d>>>=b,_-=b,i.back+=b,64&m){t.msg="invalid distance code",i.mode=ka;break}i.offset=p,i.extra=15&m,i.mode=wa;case wa:if(i.extra){for(S=i.extra;_>>=i.extra,_-=i.extra,i.back+=i.extra}if(i.offset>i.dmax){t.msg="invalid distance too far back",i.mode=ka;break}i.mode=ga;case ga:if(0===l)break t;if(c=u-l,i.offset>c){if((c=i.offset-c)>i.whave&&i.sane){t.msg="invalid distance too far back",i.mode=ka;break}c>i.wnext?(c-=i.wnext,w=i.wsize-c):w=i.wnext-c,c>i.length&&(c=i.length),g=i.window}else g=r,w=o-i.offset,c=i.length;c>l&&(c=l),l-=c,i.length-=c;do{r[o++]=g[w++]}while(--c);0===i.length&&(i.mode=fa);break;case ba:if(0===l)break t;r[o++]=i.length,l--,i.mode=fa;break;case ma:if(i.wrap){for(;_<32;){if(0===h)break t;h--,d|=n[s++]<<_,_+=8}if(u-=l,t.total_out+=u,i.total+=u,u&&(t.adler=i.check=i.flags?nt(i.check,r,u,o-u):et(i.check,r,u,o-u)),u=l,(i.flags?d:Ea(d))!==i.check){t.msg="incorrect data check",i.mode=ka;break}d=0,_=0}i.mode=pa;case pa:if(i.wrap&&i.flags){for(;_<32;){if(0===h)break t;h--,d+=n[s++]<<_,_+=8}if(d!==(4294967295&i.total)){t.msg="incorrect length check",i.mode=ka;break}d=0,_=0}i.mode=va;case va:z=Le;break t;case ka:z=Ke;break t;case ya:return Me;case xa:default:return je}return t.next_out=o,t.avail_out=l,t.next_in=s,t.avail_in=h,i.hold=d,i.bits=_,(i.wsize||u!==t.avail_out&&i.mode=0&&a.windowBits<16&&(a.windowBits=-a.windowBits,0===a.windowBits&&(a.windowBits=-15)),!(a.windowBits>=0&&a.windowBits<16)||t&&t.windowBits||(a.windowBits+=32),a.windowBits>15&&a.windowBits<48&&0==(15&a.windowBits)&&(a.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new be,this.strm.avail_out=0;var i=Fa.inflateInit2(this.strm,a.windowBits);if(i!==La.Z_OK)throw new Error(rt[i]);if(this.header=new Ha,Fa.inflateGetHeader(this.strm,this.header),a.dictionary&&("string"==typeof a.dictionary?a.dictionary=ge.string2buf(a.dictionary):"[object ArrayBuffer]"===ja.call(a.dictionary)&&(a.dictionary=new Uint8Array(a.dictionary)),a.raw&&(i=Fa.inflateSetDictionary(this.strm,a.dictionary))!==La.Z_OK))throw new Error(rt[i])}function Ma(t,e){var a=new Ka(e);if(a.push(t,!0),a.err)throw a.msg||rt[a.err];return a.result}Ka.prototype.push=function(t,a){var i,n,r,s,o,h=this.strm,l=this.options.chunkSize,d=this.options.dictionary,_=!1;if(this.ended)return!1;n=a===~~a?a:!0===a?La.Z_FINISH:La.Z_NO_FLUSH,"string"==typeof t?h.input=ge.binstring2buf(t):"[object ArrayBuffer]"===ja.call(t)?h.input=new Uint8Array(t):h.input=t,h.next_in=0,h.avail_in=h.input.length;do{if(0===h.avail_out&&(h.output=new e.Buf8(l),h.next_out=0,h.avail_out=l),(i=Fa.inflate(h,La.Z_NO_FLUSH))===La.Z_NEED_DICT&&d&&(i=Fa.inflateSetDictionary(this.strm,d)),i===La.Z_BUF_ERROR&&!0===_&&(i=La.Z_OK,_=!1),i!==La.Z_STREAM_END&&i!==La.Z_OK)return this.onEnd(i),this.ended=!0,!1;h.next_out&&(0!==h.avail_out&&i!==La.Z_STREAM_END&&(0!==h.avail_in||n!==La.Z_FINISH&&n!==La.Z_SYNC_FLUSH)||("string"===this.options.to?(r=ge.utf8border(h.output,h.next_out),s=h.next_out-r,o=ge.buf2string(h.output,r),h.next_out=s,h.avail_out=l-s,s&&e.arraySet(h.output,h.output,r,s,0),this.onData(o)):this.onData(e.shrinkBuf(h.output,h.next_out)))),0===h.avail_in&&0===h.avail_out&&(_=!0)}while((h.avail_in>0||0===h.avail_out)&&i!==La.Z_STREAM_END);return i===La.Z_STREAM_END&&(n=La.Z_FINISH),n===La.Z_FINISH?(i=Fa.inflateEnd(this.strm),this.onEnd(i),this.ended=!0,i===La.Z_OK):n!==La.Z_SYNC_FLUSH||(this.onEnd(La.Z_OK),h.avail_out=0,!0)},Ka.prototype.onData=function(t){this.chunks.push(t)},Ka.prototype.onEnd=function(t){t===La.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=e.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg};var Pa={Inflate:Ka,inflate:Ma,inflateRaw:function(t,e){return(e=e||{}).raw=!0,Ma(t,e)},ungzip:Ma},Ya={};(0,e.assign)(Ya,Be,Pa,La);var Ga=Ya;window.pako=Ga}();
diff --git a/build/newcanvas/pathseg.js b/build/newcanvas/pathseg.js
new file mode 100644
index 0000000..b369b23
--- /dev/null
+++ b/build/newcanvas/pathseg.js
@@ -0,0 +1 @@
+!function(){"use strict";"SVGPathSeg"in window||(window.SVGPathSeg=function(t,e,n){this.pathSegType=t,this.pathSegTypeAsLetter=e,this._owningPathSegList=n},window.SVGPathSeg.prototype.classname="SVGPathSeg",window.SVGPathSeg.PATHSEG_UNKNOWN=0,window.SVGPathSeg.PATHSEG_CLOSEPATH=1,window.SVGPathSeg.PATHSEG_MOVETO_ABS=2,window.SVGPathSeg.PATHSEG_MOVETO_REL=3,window.SVGPathSeg.PATHSEG_LINETO_ABS=4,window.SVGPathSeg.PATHSEG_LINETO_REL=5,window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS=6,window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL=7,window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS=8,window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL=9,window.SVGPathSeg.PATHSEG_ARC_ABS=10,window.SVGPathSeg.PATHSEG_ARC_REL=11,window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS=12,window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL=13,window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS=14,window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL=15,window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS=16,window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL=17,window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS=18,window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL=19,window.SVGPathSeg.prototype._segmentChanged=function(){this._owningPathSegList&&this._owningPathSegList.segmentChanged(this)},window.SVGPathSegClosePath=function(t){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_CLOSEPATH,"z",t)},window.SVGPathSegClosePath.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegClosePath.prototype.toString=function(){return"[object SVGPathSegClosePath]"},window.SVGPathSegClosePath.prototype._asPathString=function(){return this.pathSegTypeAsLetter},window.SVGPathSegClosePath.prototype.clone=function(){return new window.SVGPathSegClosePath(void 0)},window.SVGPathSegMovetoAbs=function(t,e,n){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_MOVETO_ABS,"M",t),this._x=e,this._y=n},window.SVGPathSegMovetoAbs.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegMovetoAbs.prototype.toString=function(){return"[object SVGPathSegMovetoAbs]"},window.SVGPathSegMovetoAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},window.SVGPathSegMovetoAbs.prototype.clone=function(){return new window.SVGPathSegMovetoAbs(void 0,this._x,this._y)},Object.defineProperty(window.SVGPathSegMovetoAbs.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegMovetoAbs.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegMovetoRel=function(t,e,n){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_MOVETO_REL,"m",t),this._x=e,this._y=n},window.SVGPathSegMovetoRel.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegMovetoRel.prototype.toString=function(){return"[object SVGPathSegMovetoRel]"},window.SVGPathSegMovetoRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},window.SVGPathSegMovetoRel.prototype.clone=function(){return new window.SVGPathSegMovetoRel(void 0,this._x,this._y)},Object.defineProperty(window.SVGPathSegMovetoRel.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegMovetoRel.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegLinetoAbs=function(t,e,n){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_LINETO_ABS,"L",t),this._x=e,this._y=n},window.SVGPathSegLinetoAbs.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegLinetoAbs.prototype.toString=function(){return"[object SVGPathSegLinetoAbs]"},window.SVGPathSegLinetoAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},window.SVGPathSegLinetoAbs.prototype.clone=function(){return new window.SVGPathSegLinetoAbs(void 0,this._x,this._y)},Object.defineProperty(window.SVGPathSegLinetoAbs.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegLinetoAbs.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegLinetoRel=function(t,e,n){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_LINETO_REL,"l",t),this._x=e,this._y=n},window.SVGPathSegLinetoRel.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegLinetoRel.prototype.toString=function(){return"[object SVGPathSegLinetoRel]"},window.SVGPathSegLinetoRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},window.SVGPathSegLinetoRel.prototype.clone=function(){return new window.SVGPathSegLinetoRel(void 0,this._x,this._y)},Object.defineProperty(window.SVGPathSegLinetoRel.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegLinetoRel.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegCurvetoCubicAbs=function(t,e,n,i,o,r,h){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS,"C",t),this._x=e,this._y=n,this._x1=i,this._y1=o,this._x2=r,this._y2=h},window.SVGPathSegCurvetoCubicAbs.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegCurvetoCubicAbs.prototype.toString=function(){return"[object SVGPathSegCurvetoCubicAbs]"},window.SVGPathSegCurvetoCubicAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x1+" "+this._y1+" "+this._x2+" "+this._y2+" "+this._x+" "+this._y},window.SVGPathSegCurvetoCubicAbs.prototype.clone=function(){return new window.SVGPathSegCurvetoCubicAbs(void 0,this._x,this._y,this._x1,this._y1,this._x2,this._y2)},Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype,"x1",{get:function(){return this._x1},set:function(t){this._x1=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype,"y1",{get:function(){return this._y1},set:function(t){this._y1=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype,"x2",{get:function(){return this._x2},set:function(t){this._x2=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype,"y2",{get:function(){return this._y2},set:function(t){this._y2=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegCurvetoCubicRel=function(t,e,n,i,o,r,h){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL,"c",t),this._x=e,this._y=n,this._x1=i,this._y1=o,this._x2=r,this._y2=h},window.SVGPathSegCurvetoCubicRel.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegCurvetoCubicRel.prototype.toString=function(){return"[object SVGPathSegCurvetoCubicRel]"},window.SVGPathSegCurvetoCubicRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x1+" "+this._y1+" "+this._x2+" "+this._y2+" "+this._x+" "+this._y},window.SVGPathSegCurvetoCubicRel.prototype.clone=function(){return new window.SVGPathSegCurvetoCubicRel(void 0,this._x,this._y,this._x1,this._y1,this._x2,this._y2)},Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype,"x1",{get:function(){return this._x1},set:function(t){this._x1=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype,"y1",{get:function(){return this._y1},set:function(t){this._y1=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype,"x2",{get:function(){return this._x2},set:function(t){this._x2=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype,"y2",{get:function(){return this._y2},set:function(t){this._y2=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegCurvetoQuadraticAbs=function(t,e,n,i,o){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS,"Q",t),this._x=e,this._y=n,this._x1=i,this._y1=o},window.SVGPathSegCurvetoQuadraticAbs.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegCurvetoQuadraticAbs.prototype.toString=function(){return"[object SVGPathSegCurvetoQuadraticAbs]"},window.SVGPathSegCurvetoQuadraticAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x1+" "+this._y1+" "+this._x+" "+this._y},window.SVGPathSegCurvetoQuadraticAbs.prototype.clone=function(){return new window.SVGPathSegCurvetoQuadraticAbs(void 0,this._x,this._y,this._x1,this._y1)},Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype,"x1",{get:function(){return this._x1},set:function(t){this._x1=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype,"y1",{get:function(){return this._y1},set:function(t){this._y1=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegCurvetoQuadraticRel=function(t,e,n,i,o){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL,"q",t),this._x=e,this._y=n,this._x1=i,this._y1=o},window.SVGPathSegCurvetoQuadraticRel.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegCurvetoQuadraticRel.prototype.toString=function(){return"[object SVGPathSegCurvetoQuadraticRel]"},window.SVGPathSegCurvetoQuadraticRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x1+" "+this._y1+" "+this._x+" "+this._y},window.SVGPathSegCurvetoQuadraticRel.prototype.clone=function(){return new window.SVGPathSegCurvetoQuadraticRel(void 0,this._x,this._y,this._x1,this._y1)},Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype,"x1",{get:function(){return this._x1},set:function(t){this._x1=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype,"y1",{get:function(){return this._y1},set:function(t){this._y1=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegArcAbs=function(t,e,n,i,o,r,h,s){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_ARC_ABS,"A",t),this._x=e,this._y=n,this._r1=i,this._r2=o,this._angle=r,this._largeArcFlag=h,this._sweepFlag=s},window.SVGPathSegArcAbs.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegArcAbs.prototype.toString=function(){return"[object SVGPathSegArcAbs]"},window.SVGPathSegArcAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._r1+" "+this._r2+" "+this._angle+" "+(this._largeArcFlag?"1":"0")+" "+(this._sweepFlag?"1":"0")+" "+this._x+" "+this._y},window.SVGPathSegArcAbs.prototype.clone=function(){return new window.SVGPathSegArcAbs(void 0,this._x,this._y,this._r1,this._r2,this._angle,this._largeArcFlag,this._sweepFlag)},Object.defineProperty(window.SVGPathSegArcAbs.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcAbs.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcAbs.prototype,"r1",{get:function(){return this._r1},set:function(t){this._r1=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcAbs.prototype,"r2",{get:function(){return this._r2},set:function(t){this._r2=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcAbs.prototype,"angle",{get:function(){return this._angle},set:function(t){this._angle=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcAbs.prototype,"largeArcFlag",{get:function(){return this._largeArcFlag},set:function(t){this._largeArcFlag=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcAbs.prototype,"sweepFlag",{get:function(){return this._sweepFlag},set:function(t){this._sweepFlag=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegArcRel=function(t,e,n,i,o,r,h,s){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_ARC_REL,"a",t),this._x=e,this._y=n,this._r1=i,this._r2=o,this._angle=r,this._largeArcFlag=h,this._sweepFlag=s},window.SVGPathSegArcRel.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegArcRel.prototype.toString=function(){return"[object SVGPathSegArcRel]"},window.SVGPathSegArcRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._r1+" "+this._r2+" "+this._angle+" "+(this._largeArcFlag?"1":"0")+" "+(this._sweepFlag?"1":"0")+" "+this._x+" "+this._y},window.SVGPathSegArcRel.prototype.clone=function(){return new window.SVGPathSegArcRel(void 0,this._x,this._y,this._r1,this._r2,this._angle,this._largeArcFlag,this._sweepFlag)},Object.defineProperty(window.SVGPathSegArcRel.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcRel.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcRel.prototype,"r1",{get:function(){return this._r1},set:function(t){this._r1=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcRel.prototype,"r2",{get:function(){return this._r2},set:function(t){this._r2=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcRel.prototype,"angle",{get:function(){return this._angle},set:function(t){this._angle=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcRel.prototype,"largeArcFlag",{get:function(){return this._largeArcFlag},set:function(t){this._largeArcFlag=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegArcRel.prototype,"sweepFlag",{get:function(){return this._sweepFlag},set:function(t){this._sweepFlag=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegLinetoHorizontalAbs=function(t,e){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS,"H",t),this._x=e},window.SVGPathSegLinetoHorizontalAbs.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegLinetoHorizontalAbs.prototype.toString=function(){return"[object SVGPathSegLinetoHorizontalAbs]"},window.SVGPathSegLinetoHorizontalAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x},window.SVGPathSegLinetoHorizontalAbs.prototype.clone=function(){return new window.SVGPathSegLinetoHorizontalAbs(void 0,this._x)},Object.defineProperty(window.SVGPathSegLinetoHorizontalAbs.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegLinetoHorizontalRel=function(t,e){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL,"h",t),this._x=e},window.SVGPathSegLinetoHorizontalRel.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegLinetoHorizontalRel.prototype.toString=function(){return"[object SVGPathSegLinetoHorizontalRel]"},window.SVGPathSegLinetoHorizontalRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x},window.SVGPathSegLinetoHorizontalRel.prototype.clone=function(){return new window.SVGPathSegLinetoHorizontalRel(void 0,this._x)},Object.defineProperty(window.SVGPathSegLinetoHorizontalRel.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegLinetoVerticalAbs=function(t,e){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS,"V",t),this._y=e},window.SVGPathSegLinetoVerticalAbs.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegLinetoVerticalAbs.prototype.toString=function(){return"[object SVGPathSegLinetoVerticalAbs]"},window.SVGPathSegLinetoVerticalAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._y},window.SVGPathSegLinetoVerticalAbs.prototype.clone=function(){return new window.SVGPathSegLinetoVerticalAbs(void 0,this._y)},Object.defineProperty(window.SVGPathSegLinetoVerticalAbs.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegLinetoVerticalRel=function(t,e){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL,"v",t),this._y=e},window.SVGPathSegLinetoVerticalRel.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegLinetoVerticalRel.prototype.toString=function(){return"[object SVGPathSegLinetoVerticalRel]"},window.SVGPathSegLinetoVerticalRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._y},window.SVGPathSegLinetoVerticalRel.prototype.clone=function(){return new window.SVGPathSegLinetoVerticalRel(void 0,this._y)},Object.defineProperty(window.SVGPathSegLinetoVerticalRel.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegCurvetoCubicSmoothAbs=function(t,e,n,i,o){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS,"S",t),this._x=e,this._y=n,this._x2=i,this._y2=o},window.SVGPathSegCurvetoCubicSmoothAbs.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegCurvetoCubicSmoothAbs.prototype.toString=function(){return"[object SVGPathSegCurvetoCubicSmoothAbs]"},window.SVGPathSegCurvetoCubicSmoothAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x2+" "+this._y2+" "+this._x+" "+this._y},window.SVGPathSegCurvetoCubicSmoothAbs.prototype.clone=function(){return new window.SVGPathSegCurvetoCubicSmoothAbs(void 0,this._x,this._y,this._x2,this._y2)},Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype,"x2",{get:function(){return this._x2},set:function(t){this._x2=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype,"y2",{get:function(){return this._y2},set:function(t){this._y2=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegCurvetoCubicSmoothRel=function(t,e,n,i,o){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL,"s",t),this._x=e,this._y=n,this._x2=i,this._y2=o},window.SVGPathSegCurvetoCubicSmoothRel.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegCurvetoCubicSmoothRel.prototype.toString=function(){return"[object SVGPathSegCurvetoCubicSmoothRel]"},window.SVGPathSegCurvetoCubicSmoothRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x2+" "+this._y2+" "+this._x+" "+this._y},window.SVGPathSegCurvetoCubicSmoothRel.prototype.clone=function(){return new window.SVGPathSegCurvetoCubicSmoothRel(void 0,this._x,this._y,this._x2,this._y2)},Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype,"x2",{get:function(){return this._x2},set:function(t){this._x2=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype,"y2",{get:function(){return this._y2},set:function(t){this._y2=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegCurvetoQuadraticSmoothAbs=function(t,e,n){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS,"T",t),this._x=e,this._y=n},window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.toString=function(){return"[object SVGPathSegCurvetoQuadraticSmoothAbs]"},window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.clone=function(){return new window.SVGPathSegCurvetoQuadraticSmoothAbs(void 0,this._x,this._y)},Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),window.SVGPathSegCurvetoQuadraticSmoothRel=function(t,e,n){window.SVGPathSeg.call(this,window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL,"t",t),this._x=e,this._y=n},window.SVGPathSegCurvetoQuadraticSmoothRel.prototype=Object.create(window.SVGPathSeg.prototype),window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.toString=function(){return"[object SVGPathSegCurvetoQuadraticSmoothRel]"},window.SVGPathSegCurvetoQuadraticSmoothRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.clone=function(){return new window.SVGPathSegCurvetoQuadraticSmoothRel(void 0,this._x,this._y)},Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype,"x",{get:function(){return this._x},set:function(t){this._x=t,this._segmentChanged()},enumerable:!0}),Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype,"y",{get:function(){return this._y},set:function(t){this._y=t,this._segmentChanged()},enumerable:!0}),window.SVGPathElement.prototype.createSVGPathSegClosePath=function(){return new window.SVGPathSegClosePath(void 0)},window.SVGPathElement.prototype.createSVGPathSegMovetoAbs=function(t,e){return new window.SVGPathSegMovetoAbs(void 0,t,e)},window.SVGPathElement.prototype.createSVGPathSegMovetoRel=function(t,e){return new window.SVGPathSegMovetoRel(void 0,t,e)},window.SVGPathElement.prototype.createSVGPathSegLinetoAbs=function(t,e){return new window.SVGPathSegLinetoAbs(void 0,t,e)},window.SVGPathElement.prototype.createSVGPathSegLinetoRel=function(t,e){return new window.SVGPathSegLinetoRel(void 0,t,e)},window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs=function(t,e,n,i,o,r){return new window.SVGPathSegCurvetoCubicAbs(void 0,t,e,n,i,o,r)},window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel=function(t,e,n,i,o,r){return new window.SVGPathSegCurvetoCubicRel(void 0,t,e,n,i,o,r)},window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs=function(t,e,n,i){return new window.SVGPathSegCurvetoQuadraticAbs(void 0,t,e,n,i)},window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel=function(t,e,n,i){return new window.SVGPathSegCurvetoQuadraticRel(void 0,t,e,n,i)},window.SVGPathElement.prototype.createSVGPathSegArcAbs=function(t,e,n,i,o,r,h){return new window.SVGPathSegArcAbs(void 0,t,e,n,i,o,r,h)},window.SVGPathElement.prototype.createSVGPathSegArcRel=function(t,e,n,i,o,r,h){return new window.SVGPathSegArcRel(void 0,t,e,n,i,o,r,h)},window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs=function(t){return new window.SVGPathSegLinetoHorizontalAbs(void 0,t)},window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel=function(t){return new window.SVGPathSegLinetoHorizontalRel(void 0,t)},window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs=function(t){return new window.SVGPathSegLinetoVerticalAbs(void 0,t)},window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel=function(t){return new window.SVGPathSegLinetoVerticalRel(void 0,t)},window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs=function(t,e,n,i){return new window.SVGPathSegCurvetoCubicSmoothAbs(void 0,t,e,n,i)},window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel=function(t,e,n,i){return new window.SVGPathSegCurvetoCubicSmoothRel(void 0,t,e,n,i)},window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs=function(t,e){return new window.SVGPathSegCurvetoQuadraticSmoothAbs(void 0,t,e)},window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel=function(t,e){return new window.SVGPathSegCurvetoQuadraticSmoothRel(void 0,t,e)},"getPathSegAtLength"in window.SVGPathElement.prototype||(window.SVGPathElement.prototype.getPathSegAtLength=function(t){if(void 0===t||!isFinite(t))throw"Invalid arguments.";var e=document.createElementNS("http://www.w3.org/2000/svg","path");e.setAttribute("d",this.getAttribute("d"));var n=e.pathSegList.numberOfItems-1;if(n<=0)return 0;do{if(e.pathSegList.removeItem(n),t>e.getTotalLength())break;n--}while(n>0);return n})),"SVGPathSegList"in window&&"appendItem"in window.SVGPathSegList.prototype||(window.SVGPathSegList=function(t){this._pathElement=t,this._list=this._parsePath(this._pathElement.getAttribute("d")),this._mutationObserverConfig={attributes:!0,attributeFilter:["d"]},this._pathElementMutationObserver=new MutationObserver(this._updateListFromPathMutations.bind(this)),this._pathElementMutationObserver.observe(this._pathElement,this._mutationObserverConfig)},window.SVGPathSegList.prototype.classname="SVGPathSegList",Object.defineProperty(window.SVGPathSegList.prototype,"numberOfItems",{get:function(){return this._checkPathSynchronizedToList(),this._list.length},enumerable:!0}),Object.defineProperty(window.SVGPathElement.prototype,"pathSegList",{get:function(){return this._pathSegList||(this._pathSegList=new window.SVGPathSegList(this)),this._pathSegList},enumerable:!0}),Object.defineProperty(window.SVGPathElement.prototype,"normalizedPathSegList",{get:function(){return this.pathSegList},enumerable:!0}),Object.defineProperty(window.SVGPathElement.prototype,"animatedPathSegList",{get:function(){return this.pathSegList},enumerable:!0}),Object.defineProperty(window.SVGPathElement.prototype,"animatedNormalizedPathSegList",{get:function(){return this.pathSegList},enumerable:!0}),window.SVGPathSegList.prototype._checkPathSynchronizedToList=function(){this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords())},window.SVGPathSegList.prototype._updateListFromPathMutations=function(t){if(this._pathElement){var e=!1;t.forEach(function(t){"d"==t.attributeName&&(e=!0)}),e&&(this._list=this._parsePath(this._pathElement.getAttribute("d")))}},window.SVGPathSegList.prototype._writeListToPath=function(){this._pathElementMutationObserver.disconnect(),this._pathElement.setAttribute("d",window.SVGPathSegList._pathSegArrayAsString(this._list)),this._pathElementMutationObserver.observe(this._pathElement,this._mutationObserverConfig)},window.SVGPathSegList.prototype.segmentChanged=function(t){this._writeListToPath()},window.SVGPathSegList.prototype.clear=function(){this._checkPathSynchronizedToList(),this._list.forEach(function(t){t._owningPathSegList=null}),this._list=[],this._writeListToPath()},window.SVGPathSegList.prototype.initialize=function(t){return this._checkPathSynchronizedToList(),this._list=[t],t._owningPathSegList=this,this._writeListToPath(),t},window.SVGPathSegList.prototype._checkValidIndex=function(t){if(isNaN(t)||t<0||t>=this.numberOfItems)throw"INDEX_SIZE_ERR"},window.SVGPathSegList.prototype.getItem=function(t){return this._checkPathSynchronizedToList(),this._checkValidIndex(t),this._list[t]},window.SVGPathSegList.prototype.insertItemBefore=function(t,e){return this._checkPathSynchronizedToList(),e>this.numberOfItems&&(e=this.numberOfItems),t._owningPathSegList&&(t=t.clone()),this._list.splice(e,0,t),t._owningPathSegList=this,this._writeListToPath(),t},window.SVGPathSegList.prototype.replaceItem=function(t,e){return this._checkPathSynchronizedToList(),t._owningPathSegList&&(t=t.clone()),this._checkValidIndex(e),this._list[e]=t,t._owningPathSegList=this,this._writeListToPath(),t},window.SVGPathSegList.prototype.removeItem=function(t){this._checkPathSynchronizedToList(),this._checkValidIndex(t);var e=this._list[t];return this._list.splice(t,1),this._writeListToPath(),e},window.SVGPathSegList.prototype.appendItem=function(t){return this._checkPathSynchronizedToList(),t._owningPathSegList&&(t=t.clone()),this._list.push(t),t._owningPathSegList=this,this._writeListToPath(),t},window.SVGPathSegList._pathSegArrayAsString=function(t){var e="",n=!0;return t.forEach(function(t){n?(n=!1,e+=t._asPathString()):e+=" "+t._asPathString()}),e},window.SVGPathSegList.prototype._parsePath=function(t){if(!t||0==t.length)return[];var e=this,n=function(){this.pathSegList=[]};n.prototype.appendSegment=function(t){this.pathSegList.push(t)};var i=function(t){this._string=t,this._currentIndex=0,this._endIndex=this._string.length,this._previousCommand=window.SVGPathSeg.PATHSEG_UNKNOWN,this._skipOptionalSpaces()};i.prototype._isCurrentSpace=function(){var t=this._string[this._currentIndex];return t<=" "&&(" "==t||"\n"==t||"\t"==t||"\r"==t||"\f"==t)},i.prototype._skipOptionalSpaces=function(){for(;this._currentIndex="0"&&t<="9")&&e!=window.SVGPathSeg.PATHSEG_CLOSEPATH?e==window.SVGPathSeg.PATHSEG_MOVETO_ABS?window.SVGPathSeg.PATHSEG_LINETO_ABS:e==window.SVGPathSeg.PATHSEG_MOVETO_REL?window.SVGPathSeg.PATHSEG_LINETO_REL:e:window.SVGPathSeg.PATHSEG_UNKNOWN},i.prototype.initialCommandIsMoveTo=function(){if(!this.hasMoreData())return!0;var t=this.peekSegmentType();return t==window.SVGPathSeg.PATHSEG_MOVETO_ABS||t==window.SVGPathSeg.PATHSEG_MOVETO_REL},i.prototype._parseNumber=function(){var t=0,e=0,n=1,i=0,o=1,r=1,h=this._currentIndex;if(this._skipOptionalSpaces(),this._currentIndex"9")&&"."!=this._string.charAt(this._currentIndex))){for(var s=this._currentIndex;this._currentIndex="0"&&this._string.charAt(this._currentIndex)<="9";)this._currentIndex++;if(this._currentIndex!=s)for(var a=this._currentIndex-1,S=1;a>=s;)e+=S*(this._string.charAt(a--)-"0"),S*=10;if(this._currentIndex=this._endIndex||this._string.charAt(this._currentIndex)<"0"||this._string.charAt(this._currentIndex)>"9")return;for(;this._currentIndex="0"&&this._string.charAt(this._currentIndex)<="9";)n*=10,i+=(this._string.charAt(this._currentIndex)-"0")/n,this._currentIndex+=1}if(this._currentIndex!=h&&this._currentIndex+1=this._endIndex||this._string.charAt(this._currentIndex)<"0"||this._string.charAt(this._currentIndex)>"9")return;for(;this._currentIndex="0"&&this._string.charAt(this._currentIndex)<="9";)t*=10,t+=this._string.charAt(this._currentIndex)-"0",this._currentIndex++}var u=e+i;if(u*=o,t&&(u*=Math.pow(10,r*t)),h!=this._currentIndex)return this._skipOptionalSpacesOrDelimiter(),u}},i.prototype._parseArcFlag=function(){if(!(this._currentIndex>=this._endIndex)){var t=!1,e=this._string.charAt(this._currentIndex++);if("0"==e)t=!1;else{if("1"!=e)return;t=!0}return this._skipOptionalSpacesOrDelimiter(),t}},i.prototype.parseSegment=function(){var t=this._string[this._currentIndex],n=this._pathSegTypeFromChar(t);if(n==window.SVGPathSeg.PATHSEG_UNKNOWN){if(this._previousCommand==window.SVGPathSeg.PATHSEG_UNKNOWN)return null;if((n=this._nextCommandHelper(t,this._previousCommand))==window.SVGPathSeg.PATHSEG_UNKNOWN)return null}else this._currentIndex++;switch(this._previousCommand=n,n){case window.SVGPathSeg.PATHSEG_MOVETO_REL:return new window.SVGPathSegMovetoRel(e,this._parseNumber(),this._parseNumber());case window.SVGPathSeg.PATHSEG_MOVETO_ABS:return new window.SVGPathSegMovetoAbs(e,this._parseNumber(),this._parseNumber());case window.SVGPathSeg.PATHSEG_LINETO_REL:return new window.SVGPathSegLinetoRel(e,this._parseNumber(),this._parseNumber());case window.SVGPathSeg.PATHSEG_LINETO_ABS:return new window.SVGPathSegLinetoAbs(e,this._parseNumber(),this._parseNumber());case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:return new window.SVGPathSegLinetoHorizontalRel(e,this._parseNumber());case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:return new window.SVGPathSegLinetoHorizontalAbs(e,this._parseNumber());case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:return new window.SVGPathSegLinetoVerticalRel(e,this._parseNumber());case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:return new window.SVGPathSegLinetoVerticalAbs(e,this._parseNumber());case window.SVGPathSeg.PATHSEG_CLOSEPATH:return this._skipOptionalSpaces(),new window.SVGPathSegClosePath(e);case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:var i={x1:this._parseNumber(),y1:this._parseNumber(),x2:this._parseNumber(),y2:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()};return new window.SVGPathSegCurvetoCubicRel(e,i.x,i.y,i.x1,i.y1,i.x2,i.y2);case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:return i={x1:this._parseNumber(),y1:this._parseNumber(),x2:this._parseNumber(),y2:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()},new window.SVGPathSegCurvetoCubicAbs(e,i.x,i.y,i.x1,i.y1,i.x2,i.y2);case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:return i={x2:this._parseNumber(),y2:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()},new window.SVGPathSegCurvetoCubicSmoothRel(e,i.x,i.y,i.x2,i.y2);case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:return i={x2:this._parseNumber(),y2:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()},new window.SVGPathSegCurvetoCubicSmoothAbs(e,i.x,i.y,i.x2,i.y2);case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:return i={x1:this._parseNumber(),y1:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()},new window.SVGPathSegCurvetoQuadraticRel(e,i.x,i.y,i.x1,i.y1);case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:return i={x1:this._parseNumber(),y1:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()},new window.SVGPathSegCurvetoQuadraticAbs(e,i.x,i.y,i.x1,i.y1);case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:return new window.SVGPathSegCurvetoQuadraticSmoothRel(e,this._parseNumber(),this._parseNumber());case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:return new window.SVGPathSegCurvetoQuadraticSmoothAbs(e,this._parseNumber(),this._parseNumber());case window.SVGPathSeg.PATHSEG_ARC_REL:return i={x1:this._parseNumber(),y1:this._parseNumber(),arcAngle:this._parseNumber(),arcLarge:this._parseArcFlag(),arcSweep:this._parseArcFlag(),x:this._parseNumber(),y:this._parseNumber()},new window.SVGPathSegArcRel(e,i.x,i.y,i.x1,i.y1,i.arcAngle,i.arcLarge,i.arcSweep);case window.SVGPathSeg.PATHSEG_ARC_ABS:return i={x1:this._parseNumber(),y1:this._parseNumber(),arcAngle:this._parseNumber(),arcLarge:this._parseArcFlag(),arcSweep:this._parseArcFlag(),x:this._parseNumber(),y:this._parseNumber()},new window.SVGPathSegArcAbs(e,i.x,i.y,i.x1,i.y1,i.arcAngle,i.arcLarge,i.arcSweep);default:throw"Unknown path seg type."}};var o=new n,r=new i(t);if(!r.initialCommandIsMoveTo())return[];for(;r.hasMoreData();){var h=r.parseSegment();if(!h)return[];o.appendSegment(h)}return o.pathSegList})}();
diff --git a/build/newcanvas/script.js b/build/newcanvas/script.js
new file mode 100644
index 0000000..46dfb89
--- /dev/null
+++ b/build/newcanvas/script.js
@@ -0,0 +1 @@
+!function(){"use strict";const e=(e,t)=>{if(t||(t=Z.ctx),t.globalCompositeOperation="eraser"===e.getAttribute("class")?"destination-out":"source-over","path"===e.nodeName){t.strokeStyle=e.getAttribute("stroke"),t.lineWidth=e.getAttribute("stroke-width"),t.beginPath();for(let o=0;o{Z.seekbarMove&&Z.seekbarMove(e)},o=o=>{if(Z.rewindCache.length>=Z.fastUndoLevels&&Z.rewindCache.pop(),Z.rewindCache.unshift(Z.ctx.getImageData(0,0,600,500)),e(o),Z.timeedit&&Z.position!==Z.svg.childNodes.length-1)Z.svg.insertBefore(o,Z.svg.childNodes[Z.position+1]);else{for(let e=Z.svg.childNodes.length-1;e>Z.position;e--)Z.svg.removeChild(Z.svg.childNodes[e]);Z.svg.appendChild(o),Z.position=Z.svg.childNodes.length-1,t(1)}},n=(e,t)=>{const o=document.createElementNS("http://www.w3.org/2000/svg",e);return t&&Object.keys(t).forEach(e=>{t[e]&&o.setAttribute(e,t[e])}),o},a=e=>{o(n("rect",{class:e,x:0,y:0,width:600,height:500,fill:Z.background})),Z.lastrect=Z.position},r=()=>{let e=!1;for(let t=Z.svg.childNodes.length-1;t>0;t--){const o=Z.svg.childNodes[t];e||t>Z.position?Z.svg.removeChild(o):"rect"===o.nodeName&&t<=Z.position&&(e=!0,"eraser"===o.getAttribute("class")&&Z.svg.removeChild(o))}},i=(e,t,o,n)=>{const{ctxDisp:a}=Z;a.strokeStyle=Z.lastcolor,a.lineWidth=Z.size,a.beginPath(),a.moveTo(e,t),a.lineTo(o,n),a.stroke()},s=e=>{e&&Z.svgDisp.insertBefore(Z.path,Z.svgDisp.firstChild)},d=e=>"#"===e[0]?4===e.length?[...e.substr(1,3)+"F"].map(e=>parseInt(e+e,16)):(e+"FF").substr(1,8).match(/.{2}/g).map(e=>parseInt(e,16)):"rgba"===e.substr(0,4)?e.match(/[\d\.]+/g).map((e,t)=>3===t?Math.floor(255*parseFloat(e)):parseInt(e,10)):"rgb"===e.substr(0,3)?(e+255).match(/[\d\.]+/g).map(e=>parseInt(e,10)):[0,0,0,255],l=e=>"#"+e.map((e,t)=>t<3?("0"+e.toString(16)).slice(-2):"").join(""),c=e=>l(d(e)),f=e=>{const[t,o,n]=e.map(e=>e>10?Math.pow((e/255+.055)/1.055,2.4):e/255/12.92),[a,r,i]=[(.4124*t+.3576*o+.1805*n)/.95047,.2126*t+.7152*o+.0722*n,(.0193*t+.1192*o+.9505*n)/1.08883].map(e=>e>.008856?Math.pow(e,1/3):7.787*e+16/116);return[116*r-16,500*(a-r),200*(r-i)]},u=e=>document.getElementById(e),p=(e,t)=>{if(u("newcanvasyo").classList.contains("sandbox")||window.gameInfo&&window.gameInfo.friend)return l([...e]);const o=t.slice(0).map(t=>((e,t)=>{const o=f(e),n=f(t),a=n[0]-o[0],r=n[1]-o[1],i=n[2]-o[2];return Math.sqrt(a**2*2+r**2+i**2)})([...e],d(t))),n=Math.min(...o),a=t[o.indexOf(n)];return c(a)},g=(e,t)=>{const o=Z.ctx.getImageData(e,t,1,1).data;return o[3]>0?p(o,Z.palette):Z.background},h=e=>{e||(e=Z.svg.childNodes.length-1);for(let t=e;t>0;t--){if("rect"===Z.svg.childNodes[t].nodeName)return t}return 0},m=e=>String.fromCharCode(e>>24&255,e>>16&255,e>>8&255,255&e),b=e=>{const t="eraser"===e;Z.transparent=t,Z.canvas.style.background=t?"none":e,e=t?"#ffffff":c(e),Z.background=e,Z.svg.querySelectorAll(".eraser").forEach(t=>t.setAttribute("path"===t.nodeName?"stroke":"fill",e))},w=(e,t)=>{const{length:o}=e;if(o<2)return;if(t.pathSegList.initialize(t.createSVGPathSegMovetoAbs(e[0].x,e[0].y)),!window.options.smoothening){for(let o=1;o1){let e=!1;if(Math.abs(p-l)>=Math.PI/4)t.pathSegList.appendItem(t.createSVGPathSegLinetoAbs(r.x,r.y));else if(e&&c/g>=.4&&c/g<=2.5){const e={x:o.x+Math.cos(n)*c*.4,y:o.y+Math.sin(n)*c*.4},a={x:r.x-Math.cos(h)*g*.4,y:r.y-Math.sin(h)*g*.4};t.pathSegList.appendItem(t.createSVGPathSegCurvetoCubicAbs(r.x,r.y,e.x,e.y,a.x,a.y))}else t.pathSegList.appendItem(t.createSVGPathSegLinetoAbs(r.x,r.y)),e=!0}n=h}const a=e[o-1];t.pathSegList.appendItem(t.createSVGPathSegLinetoAbs(a.x,a.y))},v=e=>new Uint8Array([...e].map(e=>e.charCodeAt(0))),y=(e,t)=>{const o=e<<8|t;return o>32767?o-65536:o},k=e=>{const{pako:t}=window,o=e[0];let a;if(4===o)e=t.inflate(e.subarray(1)),a=0;else if(3===o)e=v(t.inflate(e.subarray(1),{to:"string"})),a=0;else{if(2!==o)throw new Error(`Unsupported version: ${o}`);a=1}const r=n("svg",{xmlns:"http://www.w3.org/2000/svg",version:"1.1",width:600,height:500}),i={color:"#000000",size:14,x:0,y:0,pattern:0},s=[],d=`rgb(${e[a]}, ${e[a+1]}, ${e[a+2]})`;r.background=d,r.appendChild(n("rect",{class:"eraser",x:0,y:0,width:600,height:500,fill:d}));for(let t=a+4;t[...Z.svg.childNodes].splice(Z.lastrecte(t)),S=e=>{const o=new DataView(e),n=o.getUint32(0);if(2303741511!==n)throw new Error(`Invalid PNG format: ${m(n)}`);for(let n=8;n{Z.fileInput||(Z.fileInput=document.createElement("input"),Z.fileInput.style.position="absolute",Z.fileInput.style.top="-1000px",Z.fileInput.type="file",Z.fileInput.accept=".png",document.body.appendChild(Z.fileInput),Z.fileInput.addEventListener("change",e=>{const t=new FileReader;t.onload=()=>S(t.result),e.currentTarget.files[0]&&t.readAsArrayBuffer(e.currentTarget.files[0])},!1)),Z.fileInput.click()},A=e=>{const t=new XMLHttpRequest;if(t.open("GET",e,!0),!("responseType"in t))return alert("Your browser is too old for this");t.responseType="arraybuffer",t.onload=()=>S(t.response),t.send()},x=()=>Z.svg.childNodes.length-1,E=(e,t)=>{Z.locked||(Z.brushCursor||(Z.brushCursor=n("circle",{"stroke-width":"1",stroke:"#000",fill:"none"}),Z.svgDisp.appendChild(Z.brushCursor),Z.brushCursor2=n("circle",{"stroke-width":"1",stroke:"#fff",fill:"none"}),Z.svgDisp.appendChild(Z.brushCursor2),Z.eyedropperCursor=n("image",{width:16,height:16,visibility:"hidden"}),Z.eyedropperCursor.setAttributeNS("http://www.w3.org/1999/xlink","href","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAARklEQVR4XoXRwQoAIAgEUf//pzeGDgq5G3PrCQqVbIAqsDz9WM2qhTX4GZgPV+JpSFxAC0PwbeVZZIpMgXvAMwoj4U9B3wGySxvzk6ZjvwAAAABJRU5ErkJggg=="),Z.svgDisp.appendChild(Z.eyedropperCursor)),void 0!==e&&(Z.brushCursor.setAttribute("cx",e),Z.brushCursor.setAttribute("cy",t),Z.brushCursor2.setAttribute("cx",e),Z.brushCursor2.setAttribute("cy",t),Z.eyedropperCursor.setAttribute("x",e-1),Z.eyedropperCursor.setAttribute("y",t-15)),Z.brushCursor.setAttribute("r",Z.size/2+.5),Z.brushCursor2.setAttribute("r",Z.size/2-.5))},D=(e,t,o)=>{let{x:n,y:a}=t,r=o.x-n,i=o.y-a;if(0!==r||0!==i){var s=((e.x-n)*r+(e.y-a)*i)/(r*r+i*i);s>1?(n=o.x,a=o.y):s>0&&(n+=r*s,a+=i*s)}return(r=e.x-n)*r+(i=e.y-a)*i},T=()=>{if(Z.locked)return;Z.unsaved=!0;const e=Z.points.length>2?(({points:e,smoothening:t})=>{const o=e.length,n=new("undefined"!=typeof Uint8Array?Uint8Array:Array)(o);let a=0,r=o-1;const i=[],s=[];for(n[a]=n[r]=1;r;){let o,s=0;for(let t=a+1;ts&&(o=t,s=n)}s>t&&(n[o]=1,i.push(a,o,o,r)),r=i.pop(),a=i.pop()}for(let t=0;t{Z.isStroking&&T(),Z.locked=!0,E(-100,-100)},N=(e,t)=>{const o=(()=>{const e=[];for(let t=0;t<256;t++){let o=t;for(let e=0;e<8;e++)o=1&o?3988292384^o>>>1:o>>>1;e.push(o)}return e})();let n=-1;for(let t=0;t>>8^o[255&(n^e.charCodeAt(t))];if(t)for(let e=0;e>>8^o[255&(n^t.charCodeAt(e))];return(-1^n)>>>0},P=e=>d(e).map(e=>String.fromCharCode(e)).join(""),M=e=>String.fromCharCode(e>>8&255,255&e),_=e=>{const{pako:t}=window,o=[P(Z.background)],n={color:P("#000000"),size:14,x:-1,y:-1,pattern:0};return e.childNodes.forEach(e=>{if("path"===e.nodeName){const t="eraser"===e.getAttribute("class")?"ÿÿÿ\0":P(e.getAttribute("stroke")),a=e.getAttribute("stroke-width"),r=e.pattern||0;t===n.color&&a===n.size||(o.push(M(-1)),o.push(M(100*a)),o.push(t),n.color=t,n.size=a),r!==n.pattern&&(o.push(M(-3)),o.push(M(r)),o.push("\0\0\0\0"),n.pattern=r),n.x=e.orig[0].x,n.y=e.orig[0].y,o.push(M(n.x)),o.push(M(n.y));for(let t=1;t[...e].map(e=>String.fromCharCode(e)).join(""))(t.deflate(v(o.join(""))))},B=(o,n,a)=>{r(),t(1);const i=document.createElement("canvas");i.width=o,i.height=n;const s=i.getContext("2d");if(Z.transparent||(s.fillStyle=Z.background,s.fillRect(0,0,o,n)),a)s.drawImage(Z.canvas,0,0,o,n);else{s.lineJoin=s.lineCap="round",s.scale(o/600,n/500);for(let t=0;t{Z.isPlaying&&(Z.isAnimating&&(Z.isAnimating=!1,Z.svgDisp.removeChild(Z.path),e(Z.animatePath),Z.position++,o||t(Z.position/(Z.svg.childNodes.length-1))),Z.isPlaying=!1)},j=()=>{if(!Z.isPlaying)return;const o=Z.svg.childNodes.length-1;let{delay:n}=Z,a=0;if(Z.position{if(!Z.locked){if(Z.rewindCache.length=0,Z.position===Z.svg.childNodes.length-1){if(0===Z.position)return t(1);Z.position=0,t(0),e(Z.svg.childNodes[0])}Z.isPlaying=!0,j()}},G=t=>{if(Z.locked)return;let o=-1;if($(!0),t!==Z.position){if(tZ.position&&(o=Z.position);if(-1!==o){if(t-o>=Z.fastUndoLevels)Z.rewindCache.length=0;else{const{length:e}=Z.rewindCache,n=Math.min(e,t-o+e-Z.fastUndoLevels);Z.rewindCache.splice(e-n,n)}for(let n=o+1;n<=t;n++)t-n{if(!Z.locked){var e=Z.svg.childNodes.length-1;Z.position{if(e||(e=Z.pngBase64,t=".png",Z.unsaved=!1),Z.saveLink||(Z.saveLink=document.createElement("a"),document.body.appendChild(Z.saveLink)),"download"in Z.saveLink){Z.saveLink.href=e;const o=new Date;Z.saveLink.download=["DrawingInTime_",o.getFullYear(),"_",(101+o.getMonth()+"").slice(-2),(100+o.getDate()+"").slice(-2),"_",(100+o.getHours()+"").slice(-2),(100+o.getMinutes()+"").slice(-2),(100+o.getSeconds()+"").slice(-2),t].join(""),Z.saveLink.click()}else window.open(e);return!0},H=(e,t)=>Z.colors[e]=t,V=e=>Z.seekbarMove=e,U=e=>{Z.size=e,E()},q=e=>{if(!Z.brushCursor)return;const t=e?"hidden":"visible",o=e?"visible":"hidden";Z.brushCursor.setAttribute("visibility",t),Z.brushCursor2.setAttribute("visibility",t),Z.eyedropperCursor.setAttribute("visibility",o)},K=(e,t)=>{if(Z.locked)return;if(!Z.isStroking)throw new Error("StrokeAdd without StrokeBegin!");const o=Z.points[Z.points.length-1];o.x===e&&o.y===t||(Z.blot&&(Z.path.pathSegList.removeItem(1),Z.blot=!1),Z.path.pathSegList.appendItem(Z.path.createSVGPathSegLinetoAbs(e,t)),navigator.userAgent.match(/\bPresto\b/)?s(!1):i(o.x,o.y,e,t),Z.points.push({x:e,y:t}))},Y=(e,t,o)=>{if(Z.locked)return;o?Z.lastleft=o:o=Z.lastleft;let a=o?Z.colors[0]:Z.colors[1];const r="eraser"===a?a:null;a="eraser"===a?Z.background:a,Z.path=n("path",{class:r,stroke:a,"stroke-width":Z.size,"stroke-linejoin":"round","stroke-linecap":"round",fill:"none"}),Z.lastcolor=a,Z.path.pattern=Z.pattern,Z.path.pathSegList.appendItem(Z.path.createSVGPathSegMovetoAbs(e,t)),Z.path.pathSegList.appendItem(Z.path.createSVGPathSegLinetoAbs(e,t+.001)),navigator.userAgent.match(/\bPresto\b/)?s(!0):i(e,t,e,t+.001),Z.points=[],Z.points.push({x:e,y:t}),Z.blot=!0,Z.isStroking=!0},X=()=>{Z.locked||Z.position>0&&(G(Z.position-1),t(Z.position/(Z.svg.childNodes.length-1)))},F=()=>Z.locked=!1,J=e=>v(atob(e)),W=e=>{const t=new XMLHttpRequest;t.open("POST","https://api.imgur.com/3/image"),t.onload=()=>{let o=t.responseText;try{o=JSON.parse(o)}catch(e){}if(o.success){const e=new XMLHttpRequest;e.open("POST","https://api.imgur.com/3/image/"+o.data.deletehash),e.setRequestHeader("Authorization","Client-ID 4809db83c8897af");const t=new FormData;t.append("description","Playback: http://grompe.org.ru/drawit/#"+o.data.id),e.send(t)}e(o)},t.onerror=t=>e(`error: ${t}`),t.setRequestHeader("Authorization","Client-ID 4809db83c8897af");const o=new FormData;o.append("image",new Blob([J(Z.pngBase64.substr(22)).buffer],{type:"image/png"})),o.append("type","file"),o.append("title","Made with Drawing in Time"),o.append("description","http://grompe.org.ru/drawit/"),t.send(o)},Q={Normal:["#000000","#444444","#999999","#ffffff","#603913","#c69c6d","#ffdab9","#ff0000","#ffd700","#ff6600","#16ff00","#0fad00","#00ffff","#0247fe","#ec008c","#8601af","#fffdc9"],Sepia:["#402305","#503315","#604325","#705335","#806345","#907355","#a08365","#b09375","#bfa284","#cfb294","#dfc2a4","#ffe2c4"],Grayscale:["#000000","#ffffff","#151515","#2a2a2a","#3f3f3f","#555555","#6a6a6a","#7f7f7f","#949494","#aaaaaa","#bfbfbf","#d4d4d4","#e9e9e9"],"Black and white":["#ffffff","#000000"],CGA:["#555555","#000000","#0000aa","#5555ff","#00aa00","#55ff55","#00aaaa","#55ffff","#aa0000","#ff5555","#aa00aa","#ff55ff","#aa5500","#ffff55","#aaaaaa","#ffffff"],Gameboy:["#8bac0f","#9bbc0f","#306230","#0f380f"],Neon:["#ffffff","#000000","#adfd09","#f3f315","#feac09","#fe0bab","#ad0bfb","#00abff"],Thanksgiving:["#673718","#3c2d27","#c23322","#850005","#c67200","#77785b","#5e6524","#cfb178","#f5e9ce"],Holiday_old:["#3d9949","#7bbd82","#7d1a0c","#bf2a23","#fdd017","#00b7f1","#bababa","#ffffff"],"Valentine's":["#2d1014","#ffffff","#600d17","#c2113a","#b71d1d","#e54d5a","#ff7d63","#fd8647","#fed067","#ffe4b7","#fdc0c6"],Halloween:["#444444","#000000","#999999","#ffffff","#603913","#c69c6d","#7a0e0e","#b40528","#fd2119","#fa5b11","#faa611","#ffd700","#602749","#724b97","#bef202","#519548","#b2bb1e"],"the blues":["#b6cbe4","#618abc","#d0d5ce","#82a2a1","#92b8c1","#607884","#c19292","#8c2c2c","#295c6f"],Spring:["#9ed396","#57b947","#4d7736","#365431","#231302","#3e2409","#a66621","#a67e21","#ebbb49","#ffc0cb","#ffffff"],Beach:["#1ca4d2","#65bbe2","#6ab7bf","#94cbda","#9cbf80","#d2e1ab","#b8a593","#d7cfb9","#dc863e","#f7dca2"],"Tide Pool":["#ffe8b9","#fad489","#ffb44c","#d6b1de","#b197a8","#e5f2ff","#a1ffb8","#53e6ef","#3ad3a8","#1ca4d2","#2271a2"],"Colors of 2016":["#91a7d0","#f6cac9","#eb9587","#776a5f","#d1c2ab","#a39d9d","#648589"],Bee:["#000000","#7a5c00","#b58800","#eab618","#f6de97","#ffffff"],"Colors of 2017":["#86af49","#44883d","#1f4478","#0062a3","#00939a","#59c9d5","#8a9a9a","#5f7278"],"Fire and Ice":["#520909","#b40528","#fd2119","#faa611","#ffe96a","#ffffff","#69ddff","#1c8ae5","#0a3fa9","#040526"],"Canyon Sunset":["#fce3ca","#feb789","#f27c8a","#af5081","#8e6dae","#5f4a8b","#2e1b50"],Juice:["#f3ab54","#ec5e66","#ab5871","#f2a19b","#f9f4d4","#fadfb7","#869e3c","#cbdd7e","#fced95"],Tropical:["#f68357","#fbc040","#fefa56","#fef0f5","#90fc51","#07f182","#1d6ab2","#12041b","#2f0946"],"Grimby Grays":["#000000","#ffffff","#2f3032","#252422","#545758","#4b4a46","#797d80","#71706c","#9ea1a4","#979692","#c4c8cb","#d7d6d2","#dee1e4","#f0efeb"],"DawnBringer 16":["#140c1c","#442434","#30346d","#4e4a4e","#854c30","#346524","#d04648","#757161","#597dce","#d27d2c","#8595a1","#6daa2c","#d2aa99","#6dc2ca","#dad45e","#deeed6"],"Fury Road":["#020c16","#023745","#08616d","#36d4b6","#0afef6","#fce173","#e29f30","#b56942","#ad3f16","#893f1d"],Candy:["#06063c","#4f95ff","#68f9ff","#fffef9","#ff96f8","#ff44d3","#793abd"],Holiday:["#e91434","#97200a","#c66a20","#fdbe30","#688625","#004f28","#112825","#1c69bf","#6096d3","#a5c4e6","#f7d9f0","#f6f6f6"],Blues:["#929aa8","#896868","#546c7d","#633d3d","#284660","#421f29","#232e3f","#0f1328"],"Sin City":["#ffffff","#ff0000","#000000"],"Lucky Clover":["#ffffff","#fcf4c4","#f7b307","#fc8404","#cd7a14","#9bf23e","#40d910","#34900b","#0c442c"],"D's Exclusive":["#000000","#717474","#ffffff","#f25b99","#e4965e","#ffc416","#ffe38f","#0074d9","#09a3ec","#12d1ff","#bcf5ff","#0ee446"],"Retina Burn":["#bc0bff","#ff0b11"],Easter:["#9678ba","#bc9ff0","#e4ccff","#ffa1f1","#fbd0ee","#e6f2ff","#aaedfb","#f4dc7b","#fdfabd","#a1ef85","#ddf7a8"],Neapolitan:["#3f3245","#ff5c98","#ecb2a4","#fff7e1"]},Z={container:null,svg:n("svg",{xmlns:"http://www.w3.org/2000/svg",version:"1.1",width:"600",height:"500"}),canvas:document.createElement("canvas"),canvasDisp:document.createElement("canvas"),svgDisp:n("svg",{version:"1.1",width:"600",height:"500","pointer-events":"none"}),svgHist:null,path:null,points:null,pngBase64:null,lastrect:0,position:0,isStroking:!1,isPlaying:!1,size:14,smoothening:1,palette:Q.Normal,patternCache:{},delay:100,unsaved:!1,background:"#fffdc9",transparent:!1,colors:["#000000","eraser"],fastUndoLevels:10,rewindCache:[],bindContainer:e=>{Z.container=e,Z.canvas.width=600,Z.canvas.height=500,Z.canvas.style.background=Z.background,Z.ctx=Z.canvas.getContext("2d"),Z.ctx.lineJoin=Z.ctx.lineCap="round",Z.container.appendChild(Z.canvas),navigator.userAgent.match(/\bPresto\b/)?Z.DrawDispLine=Z.DrawDispLinePresto:(Z.canvasDisp.width=600,Z.canvasDisp.height=500,Z.ctxDisp=Z.canvasDisp.getContext("2d"),Z.ctxDisp.lineJoin=Z.ctxDisp.lineCap="round",Z.container.appendChild(Z.canvasDisp)),Z.container.appendChild(Z.svgDisp);const t=n("rect",{class:"eraser",x:0,y:0,width:600,height:500,fill:Z.background});Z.svg.appendChild(t)},packPlayback:_,unpackPlayback:k,findLastRect:h,cutHistoryBeforeClearAndAfterPosition:r,makePng:B,fromPng:S,fromUrl:A,fromLocalFile:C,setBackground:b,setColor:H,setSize:U,drawSvgElement:e,updateView:L,drawDispLinePresto:s,drawDispLine:i,strokeBegin:Y,strokeEnd:T,strokeAdd:K,clearWithColor:a,addToSvg:o,undo:X,redo:z,moveSeekbar:t,setSeekbarMove:V,getSeekMax:x,seek:G,play:O,playTimer:j,pause:$,moveCursor:E,showEyedropperCursor:q,eyedropper:g,requestSave:R,uploadToImgur:W,lock:I,unlock:F},ee={rectangle:{},touchSingle:!1,lastTouch:{},lastSeenColorToHighlight:Z.background,brushSizes:[2,6,14,42],timerStart:0},te=e=>{e.preventDefault();const t=[...e.currentTarget.classList].filter(e=>e.startsWith("size-"))[0].match(/\d+/)[0];U(t);const o=u("tools").querySelector(".sel");if(o&&o.classList.remove("sel"),e.currentTarget.classList.add("sel"),!Z.isStroking)return;T();const n=Z.points[Z.points.length-1];Y(n.x,n.y)},oe=e=>{e.preventDefault(),u("play").classList.remove("pause"),z()},ne=e=>{ee.chooseBackground=e,e?(u("colors").classList.add("setbackground"),u("setbackground").classList.add("sel")):(u("colors").classList.remove("setbackground"),u("setbackground").classList.remove("sel"))},ae=e=>{e.preventDefault(),ne(!ee.chooseBackground)},re=e=>{e.preventDefault(),a("eraser"),u("newcanvasyo").classList.contains("sandbox")&&(ee.timerStart=Date.now())},ie=e=>{e.preventDefault(),u("play").classList.remove("pause"),X()},se=()=>u("wacom")&&u("wacom").penAPI&&u("wacom").penAPI.isWacom?u("wacom").penAPI.pointerType:0,de=()=>{const{colors:e}=Z;["primary","secondary"].forEach((t,o)=>{"eraser"===e[o]?(u(t).style.backgroundColor="pink",u(t).classList.add("eraser")):(u(t).style.backgroundColor=e[o],u(t).classList.remove("eraser"))})},le=e=>{if(e.touches||0===e.button||2===e.button){e.preventDefault();const t=e.currentTarget;let o=t.style.backgroundColor;ee.chooseBackground?("eraser"!==t.id&&b(o),ne(!1)):("eraser"===t.id&&(o="eraser"),2===e.button||3===se()?H(1,o):H(0,o),de())}},ce=e=>{e.stopPropagation(),e.preventDefault(),Z.isPlaying?(u("play").classList.remove("pause"),$()):(u("play").classList.add("pause"),O())},fe=e=>{e.altKey||(e.currentTarget.classList.remove("hidecursor"),q(!1),e.currentTarget.removeEventListener("mousemove",fe))},ue=e=>{const{options:t}=window;if(document.activeElement instanceof HTMLInputElement)return!0;if(18===e.keyCode)navigator.userAgent.match(/\bPresto\b/)||u("svgContainer").classList.add("hidecursor"),q(!0),u("svgContainer").addEventListener("mousemove",fe);else if(e.keyCode==="Q".charCodeAt(0))e.preventDefault(),t.colorDoublePress=!t.colorDoublePress;else if(e.keyCode==="Z".charCodeAt(0)||8===e.keyCode&&Z.unsaved)e.preventDefault(),u("play").classList.remove("pause"),X();else if(e.keyCode==="Y".charCodeAt(0))e.preventDefault(),u("play").classList.remove("pause"),z();else if(e.keyCode==="X".charCodeAt(0)){e.preventDefault();const[t,o]=Z.color;H(0,o),H(1,t),de()}else if(e.keyCode==="B".charCodeAt(0)){if(u("setbackground").hidden)return;e.preventDefault(),ne(!ee.chooseBackground)}else if(e.keyCode!=="E".charCodeAt(0)||e.ctrlKey||e.metaKey)if(e.keyCode>=48&&e.keyCode<=57&&!e.ctrlKey&&!e.metaKey&&t.colorNumberShortcuts){e.preventDefault();let o=48===e.keyCode?9:e.keyCode-49;(e.shiftKey||t.colorDoublePress&&Z.prevColorKey===o)&&(o+=8),Z.prevColorKey=o,t.colorDoublePress&&(Z.prevColorKeyTimer&&clearTimeout(Z.prevColorKeyTimer),Z.prevColorKeyTimer=setTimeout(()=>Z.prevColorKey=-1,500));const n=u("colors").querySelectorAll("b");if(o=49&&e.keyCode<=52&&(e.ctrlKey||e.metaKey)?(e.preventDefault(),u("brush"+(e.keyCode-49)).click()):32!==e.keyCode||!e.ctrlKey&&!e.metaKey||e.altKey||e.shiftKey||ce(e);else{e.preventDefault();for(let e=0;e{18===e.keyCode&&(u("svgContainer").classList.remove("hidecursor"),q(!1))},ge=()=>{if(Z.position{e.preventDefault(),ge()||(B(600,500,!0),R())},me=e=>{e.preventDefault(),u("svgContainer").classList.add("loading"),C(),u("svgContainer").classList.remove("loading")},be=e=>{e.preventDefault(),ge()||(u("imgur").childNodes[0].nodeValue="Uploading...",u("imgur").disabled=!0,B(600,500,!0),W(e=>{if(u("imgur").childNodes[0].nodeValue="Upload to imgur",u("popup").classList.add("show"),u("popuptitle").childNodes[0].nodeValue="Imgur upload result",e&&e.success)Z.unsaved=!1,u("imgururl").href=`http://imgur.com/${e.data.id}`,u("imgururl").childNodes[0].nodeValue="Uploaded image",u("imgurdelete").href=`http://imgur.com/delete/${e.data.deletehash}`,u("imgurerror").childNodes[0].nodeValue="",window.inforum&&(window.frameElement.ownerDocument.getElementById("input-comment").value+=``);else{const t=e.data?`Imgur error: ${e.data.error}`:`Error: ${e}`;u("imgurerror").childNodes[0].nodeValue=t}u("imgur").disabled=!1}))},we=e=>{e.preventDefault();const t=x();let o=e.touches?e.touches[0].pageX-ee.rectangle.left-34:e.pageX-ee.rectangle.left-pageXOffset-34;o=Math.min(Math.max(-10,o),492);const n=Math.round((o+10)/502*t);o=n/t*502-10,u("knob").classList.add("smooth"),u("knob").style.marginLeft=o+"px",G(n),u("play").classList.remove("pause")},ve=e=>{e.button&&(e.touches||e.touches.length)||(e.preventDefault(),window.removeEventListener("mouseup",ve),window.removeEventListener("touchend",ve),window.removeEventListener("mousemove",we),window.removeEventListener("touchmove",we))},ye=e=>{(0===e.button||e.touches&&1===e.touches.length)&&(ee.rectangle=u("seekbar").getBoundingClientRect(),we(e),window.addEventListener("mouseup",ve),window.addEventListener("touchend",ve),window.addEventListener("mousemove",we),window.addEventListener("touchmove",we))},ke=e=>{const t=Math.floor(502*e-10);e>0?u("knob").classList.add("smooth"):u("knob").classList.remove("smooth"),u("knob").style.marginLeft=t+"px",e>=1&&u("play").classList.remove("pause")},Le=e=>e.preventDefault(),Se=e=>{u("palettename").childNodes[0].nodeValue=e;const t=Q[e];Z.palette=t;const o=u("palette"),n=o.querySelectorAll("b");n.forEach(e=>o.removeChild(e));const a=n[n.length-1];t.forEach(e=>{const t=document.createElement("b");t.style.backgroundColor=e,t.addEventListener("mousedown",le),t.addEventListener("touchend",le),t.addEventListener("contextmenu",Le),o.appendChild(t),o.appendChild(a)})},Ce=e=>{if(e.touches||0===e.button){e.preventDefault();const t=e.currentTarget.childNodes[0].nodeValue;Se(t)}},Ae=e=>{(e.touches||0===e.button)&&(u("palettechooser").classList.remove("open"),window.removeEventListener("mousedown",Ae),window.removeEventListener("touchend",Ae))},xe=e=>{if(e.touches||0===e.button){e.preventDefault();const t=u("palettechooser");t.classList.toggle("open"),t.classList.contains("open")&&setTimeout(()=>{window.addEventListener("mousedown",Ae),window.addEventListener("touchend",Ae)},1);const o=Object.keys(Q);if(t.childNodes.length{n.fillStyle=e,n.fillRect(8*t+1,1,8,8)});const r=document.createElement("div");r.appendChild(document.createTextNode(o[a])),r.style.backgroundImage=`url("${e.toDataURL()}")`,r.style.backgroundRepeat="no-repeat",r.style.backgroundPosition="center 35px",r.addEventListener("mousedown",Ce),r.addEventListener("touchend",Ce),t.appendChild(r)}}}},Ee=e=>{e.preventDefault(),u("popup").classList.remove("show")},De=e=>e.preventDefault(),Te=()=>!!Z.isPlaying&&(Z.Pause(),u("play").classList.remove("pause"),!0),Ie=e=>{if(e.preventDefault(),!Z.isStroking)return;const t=e.pageX-ee.rectangle.left-pageXOffset,o=e.pageY-ee.rectangle.top-pageYOffset;K(t,o)},Ne=e=>{const{options:t}=window;0!==e.button&&2!==e.button||(e.preventDefault(),Z.isStroking&&T(),t.hideCross&&u("svgContainer").classList.remove("hidecursor"),window.removeEventListener("mouseup",Ne),window.removeEventListener("mousemove",Ie))},Pe=e=>{const{options:t}=window;if(0===e.button||2===e.button){if(Z.isStroking)return Ne(e);if(Te())return;e.preventDefault(),ee.rectangle=e.currentTarget.getBoundingClientRect();const o=e.pageX-ee.rectangle.left-pageXOffset,n=e.pageY-ee.rectangle.top-pageYOffset;if(e.altKey)H(e.button?1:0,g(o,n)),de();else{const a=0===e.button&&3!==se();t.hideCross&&u("svgContainer").classList.add("hidecursor"),Y(o,n,a),window.addEventListener("mouseup",Ne),window.addEventListener("mousemove",Ie)}}},Me=()=>E(-100,-100),_e=e=>{const{options:t}=window;ee.rectangle=e.currentTarget.getBoundingClientRect();const o=e.pageX-ee.rectangle.left-pageXOffset,n=e.pageY-ee.rectangle.top-pageYOffset;if(E(o,n),t.colorUnderCursorHint&&!Z.isStroking){const e=g(o,n);if(ee.stSeenColorToHighlight!==e){const t=u("colors").querySelector("b.hint");t&&t.classList.remove("hint");const o=Z.palette.indexOf(e);if(o>=0){u("colors").querySelectorAll("b")[o].classList.add("hint")}}ee.lastSeenColorToHighlight=e}},Be=()=>{if(!ee.touchSingle)return;const e=ee.lastTouch.pageX-ee.rectangle.left,t=ee.lastTouch.pageY-ee.rectangle.top;Y(e,t,!0),ee.touchSingle=!1},$e=e=>{if(1!==e.touches.length)return;if(Be(),e.preventDefault(),!Z.isStroking)return;const t=e.touches[0].pageX-ee.rectangle.left,o=e.touches[0].pageY-ee.rectangle.top;Z.StrokeAdd(t,o)},je=e=>{0===e.touches.length&&(Be(),e.preventDefault(),window.removeEventListener("touchend",je),window.removeEventListener("touchmove",$e),T())},Oe=e=>{if(1===e.changedTouches.length&&1===e.touches.length){const{pageX:t,pageY:o}=e.changedTouches[0];Math.abs(t-ee.lastTouch.pageX)<10&&Math.abs(o-ee.lastTouch.pageY)<10&&(u("play").classList.remove("pause"),t{if(1===e.touches.length){if(Te())return;ee.rectangle=e.currentTarget.getBoundingClientRect(),ee.touchSingle=!0,ee.lastTouch=e.touches[0],window.addEventListener("touchend",je),window.addEventListener("touchmove",$e)}else ee.touchSingle&&3===e.touches.length&&(ee.lastTouch=e.touches[1],window.addEventListener("touchend",Oe)),ee.touchSingle=!1,window.removeEventListener("touchend",je),window.removeEventListener("touchmove",$e),Z.isStroking&&T()},ze=e=>{if(!Z.unsaved)return;const t="You haven't saved the drawing. Abandon?";return e.returnValue=t,t},Re=e=>{Z.isStroking&&e.preventDefault()},He=e=>alert(e),Ve=(e,t,o)=>{const{options:n}=window,a=new XMLHttpRequest;a.open(e,t),o.header&&a.setRequestHeader(o.header[0],o.header[1]),o.retry=5,a.timeout=15e3,a.ontimeout=()=>{if(o.retry>0){if(!n.retryEnabled)return;document.body.style.cursor="progress",o.retry--,Ve(e,t,o)}else document.body.style.cursor="",o.error()},a.onload=()=>{"/play/skip.json"!==t||"Sorry, but we couldn't find your current game."!==a.error?"/play/exit.json"!==t||"Sorry, but we couldn't find your current game."!==a.error?o.load(a.responseText):location.pathname="/":location.reload()},a.onerror=()=>{o.error?o.error(a):o.load(a)},o.obj?a.send(JSON.stringify(o.obj)):a.send(),document.body.style.cursor=""},Ue=e=>{e.preventDefault(),window.frameElement.ownerDocument.querySelector(".v--modal-overlay").outerHTML=""},qe=e=>{const t=document.createElement("textarea");return t.innerHTML=e,t.value},Ke=()=>{const{getLocalStorageItem:e}=window;u("bookmark").disabled=!0;const t=e("gpe_gameBookmarks",{}),o=window.gameInfo.caption;t[window.gameInfo.gameid]={time:Date.now(),caption:o?qe(o):""},localStorage.setItem("gpe_gameBookmarks",JSON.stringify(t))},Ye=e=>{13===e.keyCode&&(e.preventDefault(),u("submitcaption").click())},Xe=()=>{let e=(ee.timerStart-Date.now())/1e3;try{window.timerCallback&&window.timerCallback(e)}catch(e){}e=Math.abs(e);const t=`0${Math.floor(e/60)}`.slice(-2);e=`0${Math.floor(e%60)}`.slice(-2),u("timer").childNodes[0].nodeValue=`${t}:${e}`},Fe=()=>{const{incontest:e,gameInfo:t,drawing_aborted:o,vertitle:n}=window;e&&!o&&Ve("POST","/contests/exit.json",{load:()=>alert("You have missed your contest.")}),t.drawfirst&&!o&&Ve("POST","/play/abort-start.json",{obj:{game_token:t.gameid},load:()=>alert("You have missed your Draw First game.\nIt has been aborted."),error:()=>alert("You have missed your Draw First game.\nI tried aborting it, but an error occured. :(")}),ee.timerStart=Date.now(),u("newcanvasyo").className="sandbox",window.timerCallback=()=>{},Xe(),document.title="Sandbox - Drawception",u("gamemode").innerHTML="Sandbox",u("headerinfo").innerHTML=`Sandbox with ${n}`;try{history.replaceState({},null,"/sandbox/")}catch(e){}F()},Je=()=>{const{gameInfo:e,incontest:t}=window;if(t){if(!confirm("Quit the contest? Entry coins will be lost!"))return;return u("exit").disabled=!0,void Ve("POST","/contests/exit.json",{load:()=>{u("exit").disabled=!1,window.drawing_aborted=!0,Fe(),document.location.pathname="/contests/"},error:()=>{u("exit").disabled=!1,alert("Server error. :( Try again?")}})}if(e.drawfirst){if(!confirm("Abort creating a draw first game?"))return;return u("exit").disabled=!0,void Ve("POST","/play/abort-start.json",{obj:{game_token:e.gameid},load:()=>{u("exit").disabled=!1,window.drawing_aborted=!0,Fe(),document.location.pathname="/create/"},error:()=>{u("exit").disabled=!1,alert("Server error. :( Try again?")}})}confirm("Really exit?")&&(u("exit").disabled=!0,Ve("POST","/play/exit.json",{obj:{game_token:e.gameid},load:()=>{u("exit").disabled=!1,Fe()}}))},We=e=>{e.preventDefault(),window.top.location.href="https://drawception.com/"},Qe=e=>{const t=document.implementation.createHTMLDocument("");t.body.innerHTML=e;const o=t.querySelector("draw-app")||t.querySelector("describe")||{getAttribute:()=>!1},n=e=>t.querySelector(e);return{error:(e=>!!e&&e.src)(n(".error")),gameid:o.getAttribute("game_token"),blitz:"true"===o.getAttribute(":blitz_mode"),nsfw:"true"===o.getAttribute(":nsfw"),friend:"true"!==o.getAttribute(":game_public"),drawfirst:"true"===o.getAttribute(":draw_first"),timeleft:1*o.getAttribute(":seconds"),caption:o.getAttribute("phrase"),image:o.getAttribute("img_url"),palette:o.getAttribute("theme_id"),bgbutton:"true"===o.getAttribute(":bg_layer"),playerurl:"/profile/",avatar:null,coins:"-",pubgames:"-",friendgames:"-",notifications:"-",drawinglink:(e=>!!e&&e.src)(n(".gamepanel img")),drawingbylink:(e=>!!e&&[e.textContent.trim(),e.href])(n("#main p a")),drawncaption:(e=>!!e&&e.src)(n("h1.game-title")),notloggedin:null!==n("form.form-login"),limitreached:!1,html:e}},Ze={default:["Normal","#fffdc9"],theme_thanksgiving:["Thanksgiving","#f5e9ce"],halloween:["Halloween","#444444"],theme_cga:["CGA","#ffff55"],shades_of_grey:["Grayscale","#e9e9e9"],theme_bw:["Black and white","#ffffff"],theme_gameboy:["Gameboy","#9bbc0f"],theme_neon:["Neon","#00abff"],theme_sepia:["Sepia","#ffe2c4"],theme_valentines:["Valentine's","#ffccdf"],theme_blues:["the blues","#295c6f"],theme_spring:["Spring","#ffffff"],theme_beach:["Beach","#f7dca2"],theme_beach_2:["Tide Pool","#2271a2"],theme_coty_2016:["Colors of 2016","#648589"],theme_bee:["Bee","#ffffff"],theme_coty_2017:["Colors of 2017","#5f7278"],theme_fire_ice:["Fire and Ice","#040526"],theme_coty_2018:["Canyon Sunset","#2e1b50"],theme_juice:["Juice","#fced95"],theme_tropical:["Tropical","#2f0946"],theme_grimby_grays:["Grimby Grays","#f0efeb"],theme_fury_road:["Fury Road","#893f1d"],theme_candy:["Candy","#793abd"],theme_holiday_2:["Holiday","#f6f6f6"],theme_blues_2:["Blues","#0f1328"],theme_sin_city:["Sin City","#000000"],theme_lucky_clover:["Lucky Clover","#0c442c"],theme_drawception:["D's Exclusive","#0ee446"],theme_retina_burn:["Retina Burn","#ff0b11"],theme_easter:["Easter","#ddf7a8"],theme_neapolitan:["Neapolitan","#fff7e1"]},et=()=>{const{gameInfo:e,inforum:t}=window;if(e.notloggedin)return u("start").parentNode.innerHTML=' ';e.avatar&&(u("infoavatar").src=e.avatar),u("infoprofile").href=e.playerurl,u("infocoins").innerHTML=e.coins,u("infogames").innerHTML=e.pubgames,u("infofriendgames").innerHTML=e.friendgames||0,u("infonotifications").innerHTML=e.notifications,t&&(document.querySelector(".headerright").hidden=!0)},tt=e=>{const{gameInfo:t}=window;e<1?(document.title="[TIME'S UP!] Playing Drawception",t.image||window.timesup?window.submitting||(t.image?nt():Fe()):(u("newcanvasyo").classList.add("locked"),I(),ee.timerStart+=15e3,Xe(),window.timesup=!0)):document.title=`[${`0${Math.floor(e/60)}`.slice(-2)}:${`0${Math.floor(e%60)}`.slice(-2)}] Playing Drawception`,window.alarm&&!window.playedWarningSound&&e<=(t.blitz?5:61)&&e>0&&(window.alarm.play(),window.playedWarningSound=!0)},ot=()=>{const{options:e,gameInfo:o,incontest:n,vertitle:a}=window;if(u("skip").disabled=o.drawfirst||n,u("report").disabled=o.drawfirst||n,u("exit").disabled=!1,u("start").disabled=!1,u("bookmark").disabled=o.drawfirst||n,u("options").disabled=!0,u("timeplus").disabled=n,u("submit").disabled=!1,u("headerinfo").innerHTML=`Playing with ${a}`,u("drawthis").classList.add("onlyplay"),u("emptytitle").classList.remove("onlyplay"),window.submitting=!1,window.drawing_aborted=!1,o.error)return alert(`Play Error:\n${o.error}`),Fe();if(o.limitreached)return alert("Play limit reached!"),Fe();u("gamemode").innerHTML=n?"Contest":`${(o.friend?"Friend ":"Public ")+(o.nsfw?"Not Safe For Work (18+) ":"safe for work ")+(o.blitz?"BLITZ ":"")}Game`,u("drawthis").innerHTML=o.caption||o.drawfirst&&"(Start your game!)"||"",u("tocaption").src="";const r=u("newcanvasyo");r.className="play",o.friend&&r.classList.add("friend"),u("palettechooser").className=o.friend?"":"onlysandbox",o.nsfw&&r.classList.add("nsfw"),o.blitz&&r.classList.add("blitz"),r.classList.add(o.image?"captioning":"drawing"),Z.isStroking&&T(),F();for(let e=Z.svg.childNodes.length-1;e>0;e--)Z.svg.removeChild(Z.svg.childNodes[e]);G(0),t(1),Z.unsaved=!1;const{palette:i}=o;if(o.image)u("tocaption").src=o.image.length<=30?"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAD6AQMAAAAho+iwAAAABlBMVEWAQED///94jotxAAABiklEQVR4Xu3W0UrCUBjA8eOO5CLK7VxLzDWFrjK6Eaha8FHuppfwBRJvdjlMIK/K3qA3OZBBd/UIm9UL2O2inMJBptNuog/6/h4Q2Y8J387Y2KIoiqIoiqIoiuIxXnbI5cmXSiJjD3LmFyrGY46PqVAx/HPDv9/w3wsJTTgapuDkcEIQMFxzo937S8+F5OkWI2IKymQl3yiZ6j8zYsRY6vUYDcOfGkuMknE5/aQAMczX9O+iKIrKJWuSxliQqT61hOmMucsYK6uzLWfDenF34EXhOX+s377KLCZcs1bxhNXQqnAvrExWM8vvY3amORCNsplu2nZPWKdj1tecTHZZLA97ZnjBB/XrkWIZWT+bsmTowp+7FHSnyMi7CpuMrWcwNsMMxnJzrCUbwwq/2/MLJb8lP4L2zVHJ35Bp1rE8Uc2bALoNHQvcoNG3Yf5Pm6EnHG50Ye0YmiG4V08LmWD7wmF9gJwFgoHbnZzNSDE/Co3orSB2YGsbovAgaD9vlkB/WbkbdQVWMNxR1Ddnf4eSZpHZYAAAAABJRU5ErkJggg==":o.image,u("caption").value="",u("caption").focus(),u("caption").setAttribute("maxlength",45),u("usedchars").textContent="45";else{const e=(e=>{if("theme_roulette"===e){alert("Warning: Drawception roulette didn't give a theme. ANBT will choose a random palette."),delete Q.Roulette;const e=Object.keys(Ze),t=e[e.length*Math.random()<<0];return Q.Roulette=Q[Ze[t][0]],["Roulette",Ze[t][1]]}if(e)return Ze[e.toLowerCase()]})(i);e?(Se(e[0]),b(e[1]),Z.color=[Q[e[0]][0],"eraser"],de()):(i?alert(`Error, please report! Unknown palette: '${i}'.\nAre you using the latest ANBT version?`):alert("Error, please report! Failed to extract the palette.\nAre you using the latest ANBT version?"),u("submit").disabled=!0),u("setbackground").hidden=!o.bgbutton}(e.timeoutSound&&!o.blitz||e.timeoutSoundBlitz&&o.blitz)&&(window.playedWarningSound=!1,window.alarm=new Audio(window.alarmSoundOgg),window.alarm.volume=e.timeoutSoundVolume/100),ee.timerStart=Date.now()+1e3*o.timeleft,window.timerCallback=tt,et(),window.timesup=!1,Xe()},nt=()=>{const{incontest:e,friendgameid:t}=window,o=e?"/contests/play/":`/play/${t?`${t}/`:""}`;try{location.pathname!==o&&history.replaceState({},null,o)}catch(e){}Ve("GET",`${o}?${Date.now()}`,{load:e=>{window.gameInfo=e?Qe(e):{error:"Server returned a blank response :("},ot()},error:e=>{window.gameInfo={error:`Server error: ${e.statusText}`},ot()}})},at=()=>{confirm("Report this panel?")&&Ve("POST","/play/flag.json",{obj:{game_token:window.gameInfo.gameid},load:()=>{u("report").disabled=!1,nt()}})},rt=()=>Z.unsaved&&!confirm("You haven't saved the drawing. Abandon?"),it=()=>{rt()||(u("skip").disabled=!0,Ve("POST","/play/skip.json",{obj:{game_token:window.gameInfo.gameid},load:()=>nt(),error:()=>{u("skip").disabled=!1,nt()}}))},st=()=>{rt()||(u("start").disabled=!0,nt())},dt=()=>{const{incontest:e,gameInfo:t}=window,o=u("caption").value;if(!o)return u("caption").focus(),alert("You haven't entered a caption!");window.submitting=!0,u("submitcaption").disabled=!0,Ve("POST",e?"/contests/submit-caption.json":"/play/describe.json",{obj:{game_token:t.gameid,title:o},load:e=>{try{e=JSON.parse(e)}catch(t){e={error:e}}e.error?(u("submitcaption").disabled=!1,"object"==typeof e.error?alert(`Error! Please report this data:\ngame: ${t.gameid}\n\nresponse: \n${JSON.stringify(e.error)}`):alert(e.error)):e.message?(u("submitcaption").disabled=!1,alert(e.message)):e.url&&((e=>{const{options:t,gameInfo:o}=window;if(!t.bookmarkOwnCaptions)return;const n=window.getLocalStorageItem("gpe_gameBookmarks",{});n[o.gameid]={time:Date.now(),caption:`"${e}"`,own:!0},localStorage.setItem("gpe_gameBookmarks",JSON.stringify(n))})(o),location.replace(e.url))},error:()=>{u("submitcaption").disabled=!1,alert("Server error. :( Try again?")}})},lt=()=>{const{incontest:e,gameInfo:t,options:o}=window,n=ee.timerStart-Date.now()>6e4;o.submitConfirm&&n&&!confirm("Ready to submit this drawing?")||(u("submit").disabled=!0,B(300,250,!0),o.backup&&localStorage.setItem("anbt_drawingbackup_newcanvas",Z.pngBase64),window.submitting=!0,Ve("POST",e?"/contests/submit-drawing.json":"/play/draw.json",{obj:{game_token:t.gameid,panel:Z.pngBase64},load:e=>{try{e=JSON.parse(e)}catch(t){e={error:e}}e.error?(u("submit").disabled=!1,"object"==typeof e.error?alert(`Error! Please report this data:\ngame: ${t.gameid}\n\nresponse:\n${JSON.stringify(e.error)}`):alert(e.error)):e.message?(u("submit").disabled=!1,alert(e.message)):e.url&&(window.onbeforeunload=()=>{},location.replace(e.url))},error:()=>{u("submit").disabled=!1,alert("Server error. :( Try again?")}}))},ct=()=>{let{gameInfo:e}=window;e.friend&&(u("timeplus").disabled=!0,Ve("POST","/play/exit.json",{obj:{game_token:e.gameid},load:()=>{Ve("GET",`/play/${e.gameid}/?${Date.now()}`,{load:t=>{u("timeplus").disabled=!1,e=t?Qe(t):{error:"Server returned a blank response :("},ee.timerStart=Date.now()+1e3*e.timeleft},error:()=>{u("timeplus").disabled=!1,alert("Server error. :( Try again?")}})},error:()=>{u("timeplus").disabled=!1,alert("Server error. :( Try again?")}}))},ft=()=>{u("usedchars").textContent=45-u("caption").value.length},ut=()=>{const{gameInfo:e,vertitle:t,options:o}=window;if(e.drawingbylink){const[t,n]=e.drawingbylink,a=`Drawing`;u("headerinfo").innerHTML=`${a} by ${t}`,document.title=`${t}'s drawing - Drawception`,e.drawncaption&&(u("drawthis").innerHTML=`"${e.drawncaption}"`,u("drawthis").classList.remove("onlyplay"),u("emptytitle").classList.add("onlyplay")),o.autoplay&&O()}else u("headerinfo").innerHTML=`Sandbox with ${t}`,u("drawthis").classList.add("onlyplay");et()};window.needToGoDeeper=()=>{const{options:e,insandbox:t,panelid:o}=window;if(window.onerror=(e,t,o)=>{e.toString().includes("periodsToSeconds")||e.toString().match(/script error/i)||alert(o?`${e}\nline: ${o}`:e)},e.newCanvasCSS){const t=document.getElementsByTagName("head")[0]||document.documentElement,o=document.createElement("style");o.type="text/css";const n=document.createTextNode(e.newCanvasCSS);o.appendChild(n),t.appendChild(o)}if(e.enableWacom){const t=document.createElement("object"),o=u("wacomContainer");t.setAttribute("id","wacom"),t.setAttribute("type","application/x-wacomtabletplugin"),t.setAttribute("width","1"),t.setAttribute("height","1"),o.appendChild(t),e.fixTabletPluginGoingAWOL&&(()=>{const e=u("wacom"),t=u("wacomContainer");window.onblur=()=>{1===t.childNodes.length&&t.removeChild(e)},window.onfocus=()=>{0===t.childNodes.length&&t.appendChild(e)}})()}if((()=>{const{options:e,inforum:t}=window;if(t){u("quit").addEventListener("click",We);const e=document.createElement("button");e.href="/",e.setAttribute("class","submit exit"),e.title="Exit",e.textContent="Exit",e.addEventListener("click",Ue),u("submit").parentNode.insertBefore(e,u("submit").nextSibling)}u("exit").addEventListener("click",Je),u("skip").addEventListener("click",it),u("start").addEventListener("click",st),u("report").addEventListener("click",at),u("bookmark").addEventListener("click",Ke),u("submit").addEventListener("click",lt),u("submitcaption").addEventListener("click",dt),e.enterToCaption&&u("caption").addEventListener("keydown",Ye),u("caption").addEventListener("change",ft),u("caption").addEventListener("keydown",ft),u("caption").addEventListener("input",ft),u("timeplus").addEventListener("click",ct)})(),t){if(o)Ve("GET",`/panel/drawing/${o}/-/`,{load:e=>{window.gameInfo=Qe(e),A(`${window.gameInfo.drawinglink}?anbt`),ut()},error:()=>{alert("Error loading the panel page. Please try again.")}});else if(Ve("GET","/sandbox/",{load:e=>{window.gameInfo=Qe(e),ut()},error:()=>{}}),e.backup){const e=localStorage.getItem("anbt_drawingbackup_newcanvas");e&&(S(J(e.substr(22)).buffer),localStorage.removeItem("anbt_drawingbackup_newcanvas"))}}else u("newcanvasyo").className="play",nt();/iPad|iPhone/.test(navigator.userAgent)&&(Z.fastUndoLevels=3),window.$=()=>{throw alert("Some additional script conflicts with ANBT new canvas, please disable it."),window.$=null,new Error("Script conflict with ANBT new canvas")}},window.options||(window.options={}),Z.bindContainer(u("svgContainer")),u("svgContainer").addEventListener("mousedown",Pe),u("svgContainer").addEventListener("mousemove",_e),u("svgContainer").addEventListener("touchstart",Ge),u("svgContainer").addEventListener("mouseleave",Me),u("svgContainer").addEventListener("contextmenu",De),u("import").addEventListener("click",me),u("export").addEventListener("click",he),u("imgur").addEventListener("click",be),document.querySelectorAll(".brush").forEach((e,t)=>{e.classList.add(`size-${ee.brushSizes[t]}`),e.addEventListener("mousedown",te),e.addEventListener("click",te)}),u("colors").querySelectorAll("b").forEach(e=>{e.addEventListener("mousedown",le),e.addEventListener("touchend",le),e.addEventListener("contextmenu",Le)}),u("setbackground").addEventListener("click",ae),u("undo").addEventListener("click",ie),u("redo").addEventListener("click",oe),u("trash").addEventListener("click",re),V(ke),u("knob").addEventListener("mousedown",ye),u("knob").addEventListener("touchstart",ye),u("seekbar").addEventListener("mousedown",ye),u("seekbar").addEventListener("touchstart",ye),u("play").addEventListener("mousedown",ce),u("play").addEventListener("touchstart",ce),u("palettename").addEventListener("mousedown",xe),u("palettename").addEventListener("touchend",xe),u("popupclose").addEventListener("click",Ee),document.addEventListener("keyup",pe),document.addEventListener("keydown",ue),window.addEventListener("contextmenu",Re),window.addEventListener("error",He),window.addEventListener("beforeunload",ze),ee.timerStart=Date.now(),setInterval(Xe,500),window.anbtReady&&window.anbtReady()}();
diff --git a/build/newcanvas/style.css b/build/newcanvas/style.css
new file mode 100644
index 0000000..0595e62
--- /dev/null
+++ b/build/newcanvas/style.css
@@ -0,0 +1 @@
+html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:"";content:none}table{border-collapse:collapse;border-spacing:0}body{margin:0;background:#ccc;font-family:"Nunito", sans-serif;background:#555}.noselect{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#newcanvasyo{background:#555}#newcanvasyo.play .onlysandbox,#newcanvasyo.play .onlyfriend,#newcanvasyo.friend .no-friend,#newcanvasyo.nsfw .no-nsfw,#newcanvasyo.sandbox .onlycaption,#newcanvasyo.drawing .onlycaption,#newcanvasyo.captioning .onlydraw,#newcanvasyo.locked .onlyunlocked,#newcanvasyo.sandbox .onlyplay{display:none}#myheader{font-size:15pt;line-height:49px;height:49px;border-bottom:1px solid black;background:#333;text-align:center;color:#999;overflow:hidden;display:block}#myheader img{vertical-align:middle}@media screen and (max-width: 999px){#myheader{font-size:11pt}}#headercont{max-width:1280px;margin:auto}.headerleft{float:left;margin-left:50px}.headerright{float:right;margin-right:50px}#infoavatar{border:1px solid #555}.headerbutton{font-size:10.5pt;font-weight:bold;padding:4px 10px;background:#2e2e2e;vertical-align:middle;text-decoration:none;cursor:pointer}.headerbutton.active{background:#248;color:#eee}.headerbutton.active:hover{background:#236}.headerbutton img{margin:0 3px}a{color:#999}a.prominent{color:#7af}a.prominent:hover{color:#9ff}#menu{display:none;position:absolute;background:#666;color:#ddd;z-index:2;border:2px solid #777;box-shadow:5px 5px 5px rgba(0,0,0,0.5);list-style-type:none;padding:0;margin:0;font-size:13pt;text-align:left}#menu.open{display:block}#menu li{line-height:49px;height:49px;padding:0 10px;cursor:pointer}#menu li:hover{background:#777}#menu hr{margin:5px;border:1px solid #444}hr{border:1px solid #888}#noscriptwarn{color:#800;padding:10px;font-size:15pt;background:#faa;text-align:center}#drawthis{padding:4px;color:#fff;font-size:26pt;font-family:"Yanone Kaffeesatz";text-align:center;vertical-align:middle;display:table-cell;width:1%}#drawthis::before{color:#aaa;font-size:14pt;font-family:"Nunito";content:"Draw this:";padding-right:1em;width:1%;text-align:right;vertical-align:middle;margin-left:-10%}.captioning #drawthis:before{content:"Describe this drawing:";padding-right:0;width:100%;text-align:center;margin-left:0}.captioning #drawingtocaption{display:block}#emptytitle{height:10px}#bl{width:600px;margin:auto;position:relative}#toolpane{text-align:center;padding:0 10px}@media screen and (min-width: 1000px){#toolpane{width:180px;height:500px;position:absolute;margin-left:-200px}}@media screen and (max-width: 999px){#toolpane{width:580px;margin:auto}}@media screen and (max-width: 999px){#toolpane:after{display:block;content:"";clear:both}}#infopanel{text-align:center;padding:0 10px}@media screen and (min-width: 1000px){#infopanel{width:180px;height:500px;position:absolute;margin-left:600px;top:0}}@media screen and (max-width: 999px){#infopanel{width:580px;margin:40px 0}}.panel{border:2px solid #888;border-radius:15px;border-top:none;background:#444;margin:3px 0}#timer{font-size:26pt;color:#aaa;width:176px;float:left}@media screen and (max-width: 999px){#timer{float:right;width:260px}}.blitz #timer{border-color:#dda;color:#dda;background:#982}.locked #timer{border-color:#faa;color:#faa;background:#744}.locked #lockwarn{display:block}#timeplus{background:url("/img/icon-time_plus_60.png") center no-repeat;width:16px;height:16px;vertical-align:middle;padding:10px;margin-left:3px;border-radius:3px;cursor:pointer}#timeplus:hover{background-color:#222}#palettechooser{display:none;position:absolute;width:450px;background:#666;color:#ddd;z-index:1;-webkit-columns:3;-moz-columns:3;columns:3;-webkit-column-gap:0;-moz-column-gap:0;column-gap:0;border:2px solid #777;box-shadow:5px 5px 5px rgba(0,0,0,0.5)}#palettechooser.open{display:block}#palettechooser div{padding:10px 0 20px;cursor:pointer;break-inside:avoid}#palettechooser div:hover{background-color:#777;color:#eee}#colors{width:100px;float:left}#colors b{float:left;display:block;width:50px;height:44px;line-height:42px;cursor:pointer;counter-increment:color}#colors b.hint::after{content:"";position:absolute;border-radius:50%;margin:32px 2px;width:5px;height:5px;background-color:white;border:1px solid #000}#colors b.hint::before{opacity:0.6}#colors b::before{font-size:10pt;opacity:0.3;color:#000;content:counter(color)}#colors b:hover::before{opacity:0.4;color:#fff}#colors b:nth-child(10){counter-reset:color 1}#colors b:nth-child(n+10){counter-increment:color}#colors b:nth-child(n+10)::before{content:"↑" counter(color)}#colors #eraser::before{content:"eraser"}#colors.setbackground b::before{content:"BG " counter(color)}#colors.setbackground b:nth-child(n+10)::before{content:"BG↑" counter(color)}#colors.setbackground #eraser::before{content:"cancel"}#colors div{clear:both}@media screen and (max-width: 999px){#colors{width:300px;margin-left:5px;clear:left;float:left}}#palettename{color:#aaa;font-size:10pt;padding:0 5px;cursor:pointer}#palettename:hover{color:#ccc}#tools{width:68px;float:right;padding:5px 0}#tools hr{width:93%;margin:8px auto}@media screen and (max-width: 999px){#tools button{margin:0}}@media screen and (max-width: 999px){#tools{width:260px}}#tools button,#openmenu{width:55px;height:44px;vertical-align:top;margin:3px 0;padding:0}#brush0,#brush1,#brush2,#brush3,#setbackground,#undo,#redo,#trash,#play,#knob,#eraser,.eraser,#openmenu{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAAB4CAYAAAAuVYzDAAAOqUlEQVR4XuzWsW3DMABFQZceQANoCO1gZC7Pwkk0BmvXql0IzC8IuAqQwImSmPeBawiCbN/J4P+6XN7+IACGGggsAAQWILAABBYgsAAYaiCwABBYgMACEFiAwALAQGABILAAgQUgsOCVLHGNEmvU2Lraz0q/s4wZWAB8fiCqarQvqo/YElgAAgtsjhJ7tCftUWIWWAACC0Z0jmts0b7Z1t8+CywAgQWjmGKN9sPWmF4zsAAweFiiRjtIjeXgwJqjxC3aL7lFiTlOB4Ip1rjH9oF7vzM98Q+8s2vHphXDUBiFU2oAD+AhBOnThGSGu82dRRtkA42hOrVqFY+bUzgQjDHmPSLLyTV8pZHKA788AJxbRFRYZxWxU2DNqLBBVEQ8HVXen3sIiBAo0kIhiAg97vLy8dZTgCIvFKHf+V0CQGAHiUeC88By7jETCuwkBVOHwEqwwaTBAmuGIqPCVioyFPEPBNYMRUaDrTRkCCYPLOc8sJw7KiDDTpYRfjmw6sZUJ52muhmyMU22QQIrIqHBDrohIV4wsGYk3GAHNSRMgwZWQITsUNhBCtkRETwknAeWc9sUNgj95cCyHwqmk97AFNi3AQJL0GB3apALBZagwe5UIQMGlqJ2nrh1kAkpQ/CfPtvzyH/OucfNqLBBVMwdAuvs+UMGCiyFbShIkJWEAtugFwgs3YmmBIUsFAkVtkEHC6w0+MS99sXOHePKDQJxHE5BwQF8AA5hKX2aKDkDZ4hyB+pIuQQ3yAniJnegpnbtYkUm0ihPGr2lWIOZZf+WfhXe99pPDKY5NrRAC8BCCE+kirLiNcB62736/vPPvxwVqUyVnn378bsMBVYdVxtDylZ+Z/mdrTOyrsBVYkyZyu8sv5MqyNIErOOKNAJLC7QALITw1eBNIbBu1NoTWBI1jKudKhc1AlhRjPH8HRwJWFUzd5DmFQLL38GRfeArwyLy4v9sg4C1UO7iFmXAkqW5oAVgITyOw+7VY4WLgRWpMjmwstih2huiSGJtp5wiYDlqlyhqOGbc/8PqbVfsw8AWyvWszUH/9sCaE1oAFsKzMloyVbhMRV7T9iTFwEoXA2ufHVhinCcLHcaNURGwohzrNf6bsjgYWJ6hd3SJgaoRWHNBC8BCeAwVqKMChoPfMYowWJTnLgRWeQFgxcpVC55aTmLICMQdlFMALEcd4syVaXAhqa8AK2gAVr/0A2t+aAFYSIZrDgKuZjgxJgSwWu4wyRK/4xqOCgNlBgMrSBg0gFU+gY+OAVgnoGUALAAL6WoVO1fV+N0V569OfE0IYDXBT6dxoaWS+CJxHQysjSpcpkwLrCkH1vrOGbFw52LVgwrcIdZuVOS1XaytuoE1P7QALDyWClTiAmVf/JqDqABYG1WUtzUFFoC1VlAlMdRqFJkpPxBYVqAhNsELo63SOhpYAlK+gkRfGS2GO2s33cCaH1oAVr2Fsi86PgsTASufOMA9svRywAKw3J3b2lPjW9i9ON8VBgLLdxrdGcpXLiC1A3Elz50dlKsgaq3sfPna35wUWBJaFsB6PlxlroKsaQGSqVmQXB5s0QBD5e1NgQVgLVQWh9CDONzeGlhlMLC2zqO75Z2x285rI1uovSOwdq3XNPSCFoD1LAFYaRJgOQCrVQBW7xgsqTIOBLDajA03BcCyVO4IrEzZFwDWQUXKAVhPFEaEGBEOCCNCACtWxoEYEbYZG0YFwDJU6gisRJmJgXWTsAKwkOZD7pnDIXcccm8KrL/s3TGq1UAUxnGLW2QBWcBdRFZgIyJoIVgNFtqqWGo9lYjgCsRmdmApCE7jHlKnnjpFuI5wLlwOXO57SSY5if8PvirFe/OKx48zwwzAMlX94HC38qPaVW6vHyaet4IFe40lgDX3lG6u7A1WAIsQrmngmgaApUHTXqwr5h5XXkNU4DvItx0XYO0CVgCLEC4alXLRKMByal3eAGi8wqz7T4AVCgIr7AhYGlYAixCeyuGpHIBlenrVrz29ktZqm7DNrfYFKoBlEVYAixAee+axZ4DVFJgUBYvnwqS+wN/MGrB8QWD57QJL/h9vNgCLkKN0XDiH5QHWIq0EH0Oun3FrMKnplYUpVlLIcjOsN9iYhgEsa7ACWIQwcRsM4mrIbQDWIuiIerJzTzBUenIldZbPh+kzYhPXG+0hSyBVDljOGrCswQpgEUKC2UeeywOrXgtY7778tgCswxUctYKR6gY0nAKa2n6z2OvrvQGtg6y3tblegGURVgCLELYyk7Hb248LAcutBazXH78rlJhBh4ZHkO9O6nODgsYIbJhcb6fXKw25aWPrvcTSMCOwBoUyi8CKVmAFsAgh3uTZq/LAanPrpYH19vOv09PnL60dcndnRIxsMrMtyHo1sDSUgkKUv/jm1begYWYVWBZhBbAIIVVuNHJze1UYWBoRXa578+lncVj9+xmvPnw7PXn2QuOkN4KOo0xr+ntCIxQ40G51vYOstza+Nj1x6nODdFCIGu74rdcTMUpvA5oQUq98bUM78gHsUc+4GGswCA+fGwWgvcJgJ9+8gtVWW5/XewVb/cV6FazMAyvlnmZuyq3vDgAKsAghzUrnsdKE0f6Yu4uSIVyl3MbwhMflelWnfuc9tTpjS+q3eSmp2g6cqeMvGaUAixDSLDzJaieem5iyNdStCKuu5NYapQKAWkCUZmoYP72iAIsQUi90JivKz5qUv+zdsQmFMBRAUUvH+EO4gzhXZskkjpEhMoH4X5FKBEEUhJzAaVKkvpBHIgC+CeB8gcH39NKVYW1nj2EQWAACC3rzC/mhF9+34werAgtAYEHPppBCuTlnla5nrQQWgMACsZXDGkqoTWl7+aWoElgAAgsQWAACCxBYAAgsEFgACCxAYAEILEBgASCwQGABILAAgQUgsACBBYDAAoEFgMACBBb/9u5YtZGrD8O4iy10AcK42GIwy2JS6x5CyEeyOJDK5A4CqbYPU6b5zBa5grmOFGpyD1OrntqFmPwDJxkhtBtZGp05Hv9eeAmPsnj3nzQPnnfHX+388/eXwxjjqzIjIgRLycDLZYyvxo2IECwlVxjjQiMiBEvJwMtljK9eU0QIltpgYYxtsESEYCkZwNgGS0QIlpIrjPGcIkKw1AYLY2yDJSIES22wMLbBEpFVtI420XW0jXapbfqsSb9mRbC+XLXBwtgGS4RUtdH+mW0H2SJYSq4wtsESkSraRLfR/sxu09eqXqNgqQ0WxjZYIrKI1tEu2o/cLn3tBcFSGyyMbbDGTp9aWtzr3mV0/SxpGtI/o+vocp6CpTZYGGPCMcS97l2dtLNKOXGftcosWFW0iW6i/UTdpD9DNVcpIlcYY8LhXvcOctVF+1yCldqdIVmnyFUX7QtpF10VJzU2WHdkYAzGNliEw73uXQ7fucorWKltdJlBsJpoX1ibIkTGButt9D56nfg6+r/oTeJ30UcygLEN1rFxr3sXw+ZqIsEaNlmLCwtWd+BR3UOmR3VV9OHAo8mnScTFButTtNqTqesjmAxgbIN1VNzr3jraTy1YqfWFBavfaRtdTiALy2i7J1lXGVoPzfvvCpSrOnpzilwlvo++JwMY22B9Lu51bxXtChKsLlplEqyHCXdFDwRrsg3Wx315OoNvyQDGNliH4l73NtG+FMFKbfII1vDdq1/+/+ffraLN7g3B/3bszwnWcS1Wrga+JQMY22Dtxr2yim4LFKxtdHV5wRo+T3LVjSxSqQSrkA1WPbpcDfyeDGBsg5Un7q1Si//uVWmClVpnFqwm2s9WsGywPh3aXI3I92QAYxusy8W9qyQtm517N+mzVYEHtAULVptTsDJI1f7neQXLBqs6V6b87UKMbbDyx71vonX06QvC8JR+zZuCZLAvVbBSK4I1Rm2wMsnVtfdkYWyDJdO95qAu5s9cvmDVBItgZZArg3eMbbAKjaH40zOk4amQx4XNCxCsJuMGq5/tBssG6+0gQ/N5TIixDZYs0mC5Ta3TZ3NJM4o45M862hfeNcEaoTZYHzLK1TUZmJ6xDdYyunilj8/qGd23GWXAnT/tKxAsgmWD9ZhVroLJwPmMbbD6kzrI1SZ1edbXy5TT7jwsIOmzlBd67yDJ/Sk99v97LjEc5b/T+F+vs8E6szZYd4mvPSbMzxjnFyyC1c5EsKrCBYtgESwbrPxydUcGpmNsg+URYY54ROgRIcGywUryM9dXNWBsg2Xkvkk1cjdyzyZYNljeg5VZrj6QAYy9B0u8psFrGgiW92CNy2/JwGtg7D1Y4kWjXjRKsGywbg3cp2GMCdZ87/WjcvyoHBssG6xHcoWxn0X4MuNeP+zZD3smWH4WYUUGMLbBunzcW6WWnKZgwaoJ1li1wUp8f0G5uol+IgMY22D9E/ca6G8LFKztoe/42WDZYJ3J7y64warJAMY2WLtxr3ubAgWriV5lEKzlDAXLBiv/4P0jGcDYBms/7nVvFe0KEqwuWmUSrIdXJFg2WAPfkiuMbbByxL3urYsRrLS9yiRYbXSZe4P1829/9N/98BPBOrIXkoF30fszN1e/kgGMbbC+FPe6dxFdFyBY6+jiwoLV7YnNJvqQU7C+/f7Hfbl6OnyDZpCBU+SqMmjH2Abr2LjXvctoO6FgtcMPwL6oYDXRvrA2n79BM8jA484A/uaAXN17QzvGNljnxL3uXUW7CQSrS7/3VQbBWkW7guSqi64+f4NOKAN3ZABjGyzC4d4xJavNKFjtIFcZBGt4xNNENxOK1Sb9GSoClWGDhTG2wSog7nXvMrrOIFjr9Hudk0KFQMkVxlhEDg/f6+GR4ajtovUxg3aCpWRgjoxtsESkijbR7UhvaG+e854rgqVkYM6MbbBEZBWto+2JO6v6v7dWBEttsDC2wRIhW010nQSqS23TZ82FpIpgkSuMsQ2WiBAstcHC2AZr9hEhWGqDhTG2wRIRgqVkAGMbLBEhWEquMManR0QIltpgYYxtsEQIltpgYYxtsESEYCkZwNgGS0QIlpIrjPHIERGCpTZYGOO/AAV2Ws862JDRAAAAAElFTkSuQmCC")}#brush0{background-position:-2px -8px}#brush0.sel{background-position:-2px -68px}#brush1{background-position:-62px -8px}#brush1.sel{background-position:-62px -68px}#brush2{background-position:-122px -8px}#brush2.sel{background-position:-122px -68px}#brush3{background-position:-182px -8px}#brush3.sel{background-position:-182px -68px}#setbackground{background-position:-242px -8px}#setbackground.sel{background-position:-242px -68px}#undo{background-position:-302px -8px}#redo{background-position:-362px -8px}#trash{background-position:-422px -8px}#eraser{background-position:-365px -68px;background-color:pink}.eraser{background-position:-425px -68px;background-color:pink}#openmenu{background-position:-425px -68px;background-color:#999}#openmenu::after{content:"\25BC";color:#fff;opacity:0.6}#openmenu:hover{background-color:#57a}#openmenu:active{background-color:#555}button,#play{border:none;border-radius:4px;background-color:#eee}button:hover,#play:hover{background-color:#acf}button:active,#play:active{background-color:#aaa}button:disabled{background-color:#aaa}#primary,#secondary{display:inline-block;width:50px;border-radius:0 0 0 13px;color:#fff}@media screen and (max-width: 999px){#primary,#secondary{width:150px}}#secondary{border-radius:0 0 13px 0}#indicator{display:flex}#gamemode{font-size:13pt;color:#aaa;width:176px;float:left}.nsfw #gamemode{border-color:#faa;color:#faa;background:#744}.nsfw #drawthis{background:#744}#gamebuttons{font-size:13pt;color:#aaa;width:176px;float:left;padding:5px 0}#gamebuttons button{padding:10px;margin:3px 0;font-size:10pt}@media screen and (max-width: 999px){#gamebuttons{width:390px;margin-left:5px}}.submit{font-size:16pt;width:180px;height:50px;background-color:#6d6}.submit:hover{background-color:#1b7}@media screen and (min-width: 1000px){.submit{position:absolute;bottom:10px;left:10px;width:180px;height:50px}}.guidelines{color:#fff;font-size:10pt}.guidelines ul{margin:0;padding:0 1em;text-align:left}.guidelines li{color:#bbb}#seekbar{width:530px;height:0px;margin:20px 50px 0;background:#333;border:10px solid #333;border-radius:10px;cursor:pointer}#knob{position:absolute;width:48px;height:38px;margin-top:-19px;margin-left:492px;border-radius:10px;background-color:#fbb;background-position:-305px -71px}#knob.smooth{transition:margin-left 0.1s ease-out}#knob:hover{background-color:#fdd}#play{background-position:-486px -11px;position:absolute;width:48px;height:38px;margin:-19px -59px;border-radius:4px}#play.pause{background-position:-546px -11px}#wacomContainer{position:absolute;top:-10px;left:-10px}@media screen and (max-width: 999px){.hideonsmall{display:none}}.loadingbg{background:#fffdc9 url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGwAAAAVCAQAAAAJQsNPAAAAkUlEQVR4Xu2WgQbAMBBD9/8/vQ14KpC4UneqYurZ2eNGnnfouWLdsjwce59ikFCdk75ricGIQSEmhekcvRfE8s8jMJ9CdI7camLGYoQ0XzNjJukgRsaJkWFiKqhiLf8x2DAx6EExTV0Mns/sIPZnnBinJJb1h4p21BXrzSOpTZVF3VGCN4lB07U53+6H5Yr1zAdssNOdvbG/lgAAAABJRU5ErkJggg==") center no-repeat}#svgContainer{width:600px;height:500px;margin:auto;cursor:crosshair;touch-action:pinch-zoom}#svgContainer.hidecursor{cursor:none}#svgContainer.loading *{display:none}#svgContainer canvas,#svgContainer svg{position:absolute}#drawingtocaption{display:none;width:550px;height:400px;padding:50px 25px;margin:auto;background:#484848;text-align:center}#tocaption{width:300px;height:250px}#caption{font-family:"Nunito", sans-serif;margin-top:100px;width:100%;font-size:20pt}#usedchars{text-align:right;opacity:0.4}#lockwarn{display:none;position:absolute;width:500px;height:400px;padding:50px;opacity:0.8;background:#aaa;color:#a00;text-align:center;z-index:1;font-size:35pt;text-shadow:1px 1px 1px #fff, -1px -1px 1px #fff, -1px 1px 1px #fff, 1px -1px 1px #fff}#popup{display:none;position:absolute;width:400px;height:300px;margin:50px;padding:50px;opacity:0.95;background:#444;color:#ddd;border-radius:15px;text-align:center;z-index:1;font-size:20pt}#popup.show{display:block}#popuptitle{color:#999;font-size:25pt;margin:10px}#popupclose{display:block;position:absolute;width:50px;height:50px;background:#c44;color:#ddd;right:0;top:0;text-align:center;border-radius:13px;cursor:pointer}#popupclose:hover{background:#e77;color:#eee}#popupclose::before{content:"\d7";font-size:30pt;line-height:40px}
diff --git a/copypost.py b/copypost.py
index 940d479..5d4d089 100644
--- a/copypost.py
+++ b/copypost.py
@@ -1,6 +1,6 @@
import re,subprocess
-template = """#### [Script updated to %s](https://github.com/grompe/Drawception-ANBT#drawception-anbt-):
+template = """#### [Script updated to %s](https://github.com/EnderDragonneau/Drawception-ANBT#drawception-anbt-):
%s
diff --git a/drawception-anbt.user.js b/drawception-anbt.user.js
deleted file mode 100644
index aeb6393..0000000
--- a/drawception-anbt.user.js
+++ /dev/null
@@ -1,2847 +0,0 @@
-// ==UserScript==
-// @name Drawception ANBT
-// @author Grom PE
-// @namespace http://grompe.org.ru/
-// @version 1.156.2019.06
-// @description Enhancement script for Drawception.com - Artists Need Better Tools
-// @downloadURL https://raw.github.com/EnderDragonneau/Drawception-ANBT/master/drawception-anbt.user.js
-// @match http://drawception.com/*
-// @match https://drawception.com/*
-// @grant none
-// @run-at document-start
-// @license Public domain
-// ==/UserScript==
-const wrapped = () => {
- const SCRIPT_VERSION = '1.156.2019.06'
- const NEWCANVAS_VERSION = 53 // Increase to update the cached canvas
- const SITE_VERSION = 'f6b35cce' // Last seen site version
-
- // == DEFAULT OPTIONS ==
-
- const options = {
- enableWacom: 0, // Whether to enable Wacom plugin and thus pressure sensitivity support
- fixTabletPluginGoingAWOL: 1, // Fix pressure sensitivity disappearing in case of stupid/old Wacom plugin
- hideCross: 0, // Whether to hide the cross when drawing
- enterToCaption: 0, // Whether to submit caption by pressing Enter
- pressureExponent: 0.5, // Smaller = softer tablet response, bigger = sharper
- brushSizes: [2, 5, 12, 35], // Brush sizes for choosing via keyboard
- chatAutoConnect: 0, // Whether to automatically connect to the chat
- backup: 1,
- timeoutSound: 0,
- timeoutSoundBlitz: 0,
- timeoutSoundVolume: 100,
- newCanvas: 1,
- proxyImgur: 0,
- rememberPosition: 0,
- ajaxRetry: 1,
- localeTimestamp: 0,
- autoplay: 1, // Whether to automatically start playback of a recorded drawing
- submitConfirm: 1,
- smoothening: 1,
- autoBypassNSFW: 0,
- colorNumberShortcuts: 1,
- colorUnderCursorHint: 1,
- bookmarkOwnCaptions: 0,
- colorDoublePress: 0,
- markStalePosts: 1,
- newCanvasCSS: '',
- forumHiddenUsers: '',
- maxCommentHeight: 1000,
- useOldFont: true,
- useOldFontSize: true,
- markdownTools: 1,
- anbtDarkMode: 1
- }
-
- /*
- == HOW TO USE ==
- - Chrome/Iron: (Recommended: all features, best performance)
- - add the script in Tampermonkey addon
- - or open URL: chrome://extensions then drag and drop this .user.js file on it
- - Firefox: add the script in Greasemonkey addon
- - Opera 12.x: add the script in "site properties"
-
- == FEATURES ==
- General
- - Menu buttons in the header for easier access
- - No temptation to judge
- - An embedded chat
- - Automatically retry failed requests to reduce annoying error messages
- Canvas:
- - Completely new drawing canvas with ability to record and display the drawing process
- View game
- - Add reverse panels button
- - Add "like all" button
- - Track new comments
- - Show when the game was started
- - Ability to favorite panels
- Play
- - Much faster skipping
- - Play modes for those who only caption or only draw
- - Enter pressed in caption mode submits the caption
- - Ability to bookmark games without participating
- - Show your panel position and track changes in unfinished games list
- Forum
- - Better-looking timestamps with correct timezone
- - Clickable drawing panels
- - Clickable links
- - Show and highlight direct links to forum posts
- */
- //let __DEBUG__
- //let prestoOpera
- let username
- let userid
- //let playMode = localStorage.getItem('gpe_playMode')
- let inDark = localStorage.getItem('gpe_inDark')
-
- //playMode = playMode === null ? 0 : parseInt(playMode, 10)
- inDark = inDark === null ? 0 : parseInt(inDark, 10)
-
- //const MODE_ALL = 0
- //const MODE_CAPTION_ONLY = 1
- //const MODE_DRAW_ONLY = 2
- //const availablePlayModes = ['Mode: captions and drawings', 'Mode: only make captions', 'Mode: only draw']
- const alarmSoundOgg = 'data:audio/ogg;base64,T2dnUwACAAAAAAAAAABnHAAAAAAAAHQUSFoBHgF2b3JiaXMAAAAAAUSsAAAAAAAAYG0AAAAAAADJAU9nZ1MAAAAAAAAAAAAAZxwAAAEAAABq35G0DxD/////////////////NQN2b3JiaXMAAAAAAAAAAAEFdm9yYmlzH0JDVgEAAAEAFGNWKWaZUpJbihlzmDFnGWPUWoolhBRCKKVzVlurKbWaWsq5xZxzzpViUilFmVJQW4oZY1IpBhlTEltpIYQUQgehcxJbaa2l2FpqObacc62VUk4ppBhTiEromFJMKaQYU4pK6Jxz0DnmnFOMSgg1lVpTyTGFlFtLKXROQgephM5SS7F0kEoHJXRQOms5lRJTKZ1jVkJquaUcU8qtpphzjIHQkFUAAAEAwEAQGrIKAFAAABCGoSiKAoSGrAIAMgAABOAojuIokiI5kmM5FhAasgoAAAIAEAAAwHAUSZEUy9EcTdIszdI8U5ZlWZZlWZZlWZZd13VdIDRkFQAAAQBAKAcZxRgQhJSyEggNWQUAIAAAAIIowxADQkNWAQAAAQAIUR4h5qGj3nvvEXIeIeYdg9577yG0XjnqoaTee++99x5777n33nvvkWFeIeehk9577xFiHBnFmXLee+8hpJwx6J2D3nvvvfeec+451957752j3kHpqdTee++Vk14x6Z2jXnvvJdUeQuqlpN5777333nvvvffee++9955777333nvvrefeau+9995777333nvvvffee++9995777333nvvgdCQVQAAEAAAYRg2iHHHpPfae2GYJ4Zp56T3nnvlqGcMegqx9557773X3nvvvffeeyA0ZBUAAAgAACGEEFJIIYUUUkghhhhiyCGHHIIIKqmkoooqqqiiiiqqLKOMMsook4wyyiyjjjrqqMPOQgoppNJKC620VFtvLdUehBBCCCGEEEIIIYQQvvceCA1ZBQCAAAAwxhhjjEEIIYQQQkgppZRiiimmmAJCQ1YBAIAAAAIAAAAsSZM0R3M8x3M8x1M8R3RER3RER5RESbRETfREUTRFVbRF3dRN3dRNXdVN27VVW7ZlXdddXddlXdZlXdd1Xdd1Xdd1Xdd1XbeB0JBVAAAIAABhkEEGGYQQQkghhZRSijHGGHPOOSA0ZBUAAAgAIAAAAEBxFEdxHMmRJMmyLM3yLM8SNVMzNVNzNVdzRVd1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'
-
- const GM_addStyle = css => {
- const parent = document.getElementsByTagName('head')[0] || document.documentElement,
- style = document.createElement('style'),
- textNode = document.createTextNode(css)
- style.type = 'text/css'
- style.appendChild(textNode)
- parent.appendChild(style)
- }
- /*
- canvas integration todo:
- - autoskipping captions/drawings
- */
-
- // Executed on completely empty page.
- const setupNewCanvas = (insandbox, url, origpage) => {
- const canvasHTML = localStorage.getItem('anbt_canvasHTML')
- const canvasHTMLver = localStorage.getItem('anbt_canvasHTMLver')
- if (!canvasHTML || canvasHTMLver < NEWCANVAS_VERSION || canvasHTML.length < 10000) {
- const req = new XMLHttpRequest()
- req.open('GET', 'https://api.github.com/repos/EnderDragonneau/Drawception-ANBT/contents/newcanvas_embedding.html')
- req.setRequestHeader('Accept', 'application/vnd.github.3.raw')
- req.onload = function() {
- if (this.responseText.length < 10000) {
- alert(`Error: instead of new canvas code, got this response from GitHub:\n${this.responseText}`)
- location.pathname = '/'
- } else {
- localStorage.setItem('anbt_canvasHTML', this.responseText)
- localStorage.setItem('anbt_canvasHTMLver', NEWCANVAS_VERSION)
- setupNewCanvas(insandbox, url)
- }
- }
- req.onerror = () => {
- alert('Error loading the new canvas code. Please try again.')
- location.pathname = '/'
- }
- req.send()
- return
- }
- const inforum = url.match(/forums\//)
- const friendgameid = url.match(/play\/(.+)\//) // Save friend game id if any
- const panelid = url.match(/sandbox\/#?([^\/]+)/)
- const incontest = url.match(/contests\/play\//) && document.getElementById('canvas-holder') // Handle drawing contests only
- const vertitle = `ANBT v${SCRIPT_VERSION}`
-
- // Disable built-in safety warning
- if (incontest) window.onbeforeunload = () => {}
-
- // Show normal address
- const normalurl = insandbox && !inforum ? `/sandbox/${panelid ? `#${panelid[1]}` : ''}` : incontest ? '/contests/play/' : inforum ? url.match(/\/forums\/?.+/) : `/play/${friendgameid ? `${friendgameid[1]}/` : ''}`
- try {
- if (location.pathname + location.hash !== normalurl) history.pushState({}, document.title, normalurl)
- } catch (e) {}
-
- if (inforum) {
- if (document.querySelector('.v--modal-overlay')) document.querySelector('.v--modal-overlay').outerHTML = ''
- const div = document.querySelector('.wrapper').children[1]
- const iframe = document.createElement('iframe')
- const modalOverlay = document.createElement('div')
- modalOverlay.setAttribute('class', 'v--modal-overlay')
- iframe.id = 'iframe'
- iframe.setAttribute('class', 'v--modal-background-click')
- modalOverlay.appendChild(iframe)
- div.appendChild(modalOverlay)
- const iframeContent = iframe.contentWindow
- iframeContent.document.open()
- iframeContent.anbtReady = () => {
- iframeContent.inforum = inforum
- iframeContent.insandbox = insandbox
- iframeContent.incontest = incontest
- iframeContent.options = options
- iframeContent.alarmSoundOgg = alarmSoundOgg
- iframeContent.vertitle = vertitle
- }
- iframeContent.document.write(canvasHTML)
- iframeContent.document.close()
- let iframeFinish = setInterval(() => {
- if (typeof document.getElementById('iframe').contentWindow.ID === 'undefined') return
- const script = document.createElement('script')
- script.textContent = '(' + needToGoDeeper.toString() + ')()'
- iframeContent.document.body.appendChild(script)
- clearInterval(iframeFinish)
- }, 100)
- return
- }
- document.open()
- window.anbtReady = () => {
- if (friendgameid) window.friendgameid = friendgameid[1]
- if (panelid) window.panelid = panelid[1]
- window.inforum = inforum
- window.insandbox = insandbox
- window.incontest = incontest
- window.options = options
- window.alarmSoundOgg = alarmSoundOgg
- window.vertitle = vertitle
- // Vue.js makes current page too different to reuse
- //if (origpage) window.origpage = origpage;
-
- const script = document.createElement('script')
- script.textContent = `(${needToGoDeeper.toString()})()`
- document.body.appendChild(script)
- }
- document.write(canvasHTML)
- document.close()
- }
-
- // To be inserted on new canvas page. No jQuery!
- const needToGoDeeper = () => {
- const ajax = (type, url, params) => {
- const req = new XMLHttpRequest()
- req.open(type, url)
- if (params.header) req.setRequestHeader(params.header[0], params.header[1])
- params.retry = 5
- req.timeout = 15000
- req.ontimeout = () => {
- if (params.retry > 0) {
- if (!options.retryEnabled) return
- document.body.style.cursor = 'progress'
- params.retry--
- ajax(type, url, params)
- } else {
- document.body.style.cursor = ''
- params.error()
- }
- }
- req.onload = () => {
- if (url === '/play/skip.json' && req.error === 'Sorry, but we couldn\u0027t find your current game.') {
- location.reload()
- return
- }
- if (url === '/play/exit.json' && req.error === 'Sorry, but we couldn\u0027t find your current game.') {
- location.pathname = '/'
- return
- }
- params.load(req.responseText)
- }
- req.onerror = () => {
- if (params.error) {
- params.error(req)
- } else {
- params.load(req)
- }
- }
- if (params.obj) {
- req.send(JSON.stringify(params.obj))
- } else {
- req.send()
- }
- document.body.style.cursor = ''
- return
- }
- const extractInfoFromHTML = html => {
- const doc = document.implementation.createHTMLDocument('')
- doc.body.innerHTML = html
- let el
- let drawapp = doc.querySelector('draw-app') || doc.querySelector('describe')
- if (!drawapp)
- drawapp = {
- getAttribute() {
- return false
- }
- }
-
- const getel = query => {
- el = doc.querySelector(query)
- return el
- }
- return {
- error: getel('.error') ? el.textContent.trim() : false,
- gameid: drawapp.getAttribute('game_token'),
- blitz: drawapp.getAttribute(':blitz_mode') == 'true',
- nsfw: drawapp.getAttribute(':nsfw') == 'true',
- friend: drawapp.getAttribute(':game_public') != 'true',
- drawfirst: drawapp.getAttribute(':draw_first') == 'true',
- timeleft: drawapp.getAttribute(':seconds') * 1,
- caption: drawapp.getAttribute('phrase'),
- image: drawapp.getAttribute('img_url'),
- palette: drawapp.getAttribute('theme_id'),
- bgbutton: drawapp.getAttribute(':bg_layer') == 'true',
- playerurl: '/profile/',
- avatar: null,
- coins: '-',
- pubgames: '-',
- friendgames: '-',
- notifications: '-',
- drawinglink: getel('.gamepanel img') ? el.src : false,
- drawingbylink: getel('#main p a') ? [el.textContent.trim(), el.href] : false,
- drawncaption: getel('h1.game-title') ? el.textContent.trim() : false,
- notloggedin: getel('form.form-login') != null,
- limitreached: false, // ??? appears to be redirecting to /play/limit/ which gives "game not found" error
- html
- }
- }
-
- const getParametersFromPlay = () => {
- let url = window.incontest ? '/contests/play/' : '/play/'
- if (window.friendgameid) {
- url += `${window.friendgameid}/`
- window.friendgameid = false
- }
- try {
- if (location.pathname != url) history.replaceState({}, null, url)
- } catch (e) {}
- if (window.origpage) {
- window.gameinfo = extractInfoFromHTML(window.origpage)
- handlePlayParameters()
- window.origpage = null
- return
- }
- // On Firefox, requesting "/play/" url would immediately return a cached error.
- // Firefox, WTF? So we use cache-busting here.
- ajax('GET', `${url}?${Date.now()}`, {
- load: x => {
- if (x === '') {
- window.gameinfo = {
- error: 'Server returned a blank response :('
- }
- } else {
- window.gameinfo = extractInfoFromHTML(x)
- }
- handlePlayParameters()
- },
- error: x => {
- window.gameinfo = {
- error: `Server error: ${x.statusText}`
- }
- handlePlayParameters()
- }
- })
- }
-
- const exitToSandbox = () => {
- if (window.incontext && !window.drawing_aborted) {
- ajax('POST', '/contests/exit.json', {
- load: () => alert('You have missed your contest.')
- })
- }
- if (window.gameinfo.drawfirst && !window.drawing_aborted) {
- ajax('POST', '/play/abort-start.json', {
- obj: {
- game_token: window.gameinfo.gameid
- },
- load: () => alert('You have missed your Draw First game.\nIt has been aborted.'),
- error: () => alert('You have missed your Draw First game.\nI tried aborting it, but an error occured. :(')
- })
- }
- timerStart = Date.now()
- ID('newcanvasyo').className = 'sandbox'
- timerCallback = () => {}
- updateTimer()
- document.title = 'Sandbox - Drawception'
- ID('gamemode').innerHTML = 'Sandbox'
- ID('headerinfo').innerHTML = `Sandbox with ${vertitle}`
- try {
- history.replaceState({}, null, '/sandbox/')
- } catch (e) {}
- anbt.Unlock()
- }
-
- const handleCommonParameters = () => {
- if (gameinfo.notloggedin) {
- ID('start').parentNode.innerHTML = ' '
- return
- }
- if (gameinfo.avatar) {
- ID('infoavatar').src = gameinfo.avatar
- }
- ID('infoprofile').href = gameinfo.playerurl
- ID('infocoins').innerHTML = gameinfo.coins
- ID('infogames').innerHTML = gameinfo.pubgames
- ID('infofriendgames').innerHTML = gameinfo.friendgames || 0
- ID('infonotifications').innerHTML = gameinfo.notifications
- if (inforum) {
- document.querySelector('.headerright').hidden = true
- }
- }
-
- const handleSandboxParameters = () => {
- if (gameinfo.drawingbylink) {
- const playername = gameinfo.drawingbylink[0]
- const playerlink = gameinfo.drawingbylink[1]
- const replaylink = `Drawing`
- ID('headerinfo').innerHTML = `${replaylink} by ${playername}`
- document.title = `${playername}'s drawing - Drawception`
- if (gameinfo.drawncaption) {
- ID('drawthis').innerHTML = `"${gameinfo.drawncaption}"`
- ID('drawthis').classList.remove('onlyplay')
- ID('emptytitle').classList.add('onlyplay')
- }
- if (options.autoplay) anbt.Play()
- } else {
- ID('headerinfo').innerHTML = `Sandbox with ${vertitle}`
- ID('drawthis').classList.add('onlyplay')
- }
- handleCommonParameters()
- }
-
- const handlePlayParameters = () => {
- const info = window.gameinfo
- ID('skip').disabled = info.drawfirst || window.incontest
- ID('report').disabled = info.drawfirst || window.incontest
- ID('exit').disabled = false
- ID('start').disabled = false
- ID('bookmark').disabled = info.drawfirst || window.incontest
- ID('options').disabled = true // Not implemented yet!
- ID('timeplus').disabled = window.incontest
- ID('submit').disabled = false
- ID('headerinfo').innerHTML = `Playing with ${vertitle}`
- ID('drawthis').classList.add('onlyplay')
- ID('emptytitle').classList.remove('onlyplay')
- window.submitting = false
- window.drawing_aborted = false
- if (info.error) {
- alert(`Play Error:\n${info.error}`)
- return exitToSandbox()
- }
- if (info.limitreached) {
- alert('Play limit reached!')
- return exitToSandbox()
- }
- if (window.incontest) {
- ID('gamemode').innerHTML = 'Contest'
- } else {
- ID('gamemode').innerHTML = `${(info.friend ? 'Friend ' : 'Public ') + (info.nsfw ? 'Not Safe For Work (18+) ' : 'safe for work ') + (info.blitz ? 'BLITZ ' : '')}Game`
- }
- ID('drawthis').innerHTML = info.caption || (info.drawfirst && '(Start your game!)') || ''
- ID('tocaption').src = ''
- const newcanvas = ID('newcanvasyo')
- newcanvas.className = 'play'
- if (info.friend) newcanvas.classList.add('friend')
- ID('palettechooser').className = info.friend ? '' : 'onlysandbox'
- if (info.nsfw) newcanvas.classList.add('nsfw')
- if (info.blitz) newcanvas.classList.add('blitz')
- newcanvas.classList.add(info.image ? 'captioning' : 'drawing')
- // Clear
- if (anbt.isStroking) anbt.StrokeEnd()
- anbt.Unlock()
- for (let i = anbt.svg.childNodes.length - 1; i > 0; i--) {
- const el = anbt.svg.childNodes[i]
- anbt.svg.removeChild(el)
- }
- anbt.Seek(0)
- anbt.MoveSeekbar(1)
- anbt.unsaved = false
- const palettemap = {
- default: ['Normal', '#fffdc9'],
- theme_thanksgiving: ['Thanksgiving', '#f5e9ce'],
- halloween: ['Halloween', '#444444'],
- theme_cga: ['CGA', '#ffff55'],
- shades_of_grey: ['Grayscale', '#e9e9e9'],
- theme_bw: ['Black and white', '#ffffff'],
- theme_gameboy: ['Gameboy', '#9bbc0f'],
- theme_neon: ['Neon', '#00abff'],
- theme_sepia: ['Sepia', '#ffe2c4'],
- theme_valentines: ["Valentine's", '#ffccdf'],
- theme_blues: ['the blues', '#295c6f'],
- theme_spring: ['Spring', '#ffffff'],
- theme_beach: ['Beach', '#f7dca2'],
- theme_beach_2: ['Tide Pool', '#2271a2'],
- theme_coty_2016: ['Colors of 2016', '#648589'],
- theme_bee: ['Bee', '#ffffff'],
- theme_coty_2017: ['Colors of 2017', '#5f7278'],
- theme_fire_ice: ['Fire and Ice', '#040526'],
- theme_coty_2018: ['Canyon Sunset', '#2e1b50'],
- theme_juice: ['Juice', '#fced95'],
- theme_tropical: ['Tropical', '#2f0946'],
- theme_grimby_grays: ['Grimby Grays', '#f0efeb'],
- theme_fury_road: ['Fury Road', '#893f1d'],
- theme_candy: ['Candy', '#793abd'],
- theme_holiday_2: ['Holiday', '#f6f6f6'],
- theme_blues_2: ['Blues', '#0f1328'],
- theme_sin_city: ['Sin City', '#000000'],
- theme_lucky_clover: ['Lucky Clover', '#0c442c'],
- theme_drawception: ["D's Exclusive", '#0ee446'],
- theme_retina_burn: ['Retina Burn', '#ff0b11'],
- theme_easter: ['Easter', '#ddf7a8'],
- theme_neapolitan: ['Neapolitan', '#fff7e1']
- }
- const pal = info.palette
- let paldata
- if (!info.image) {
- // Drawing
- if (pal == 'theme_roulette') {
- // Since site update, the game reports already chosen palette,
- // but apparently this still happens sometimes. ???
- alert("Warning: Drawception roulette didn't give a theme. ANBT will choose a random palette.")
- delete palettes.Roulette
- const k = Object.keys(palettemap)
- const n = k[(k.length * Math.random()) << 0]
- palettes.Roulette = palettes[palettemap[n][0]]
- paldata = ['Roulette', palettemap[n][1]]
- } else {
- if (pal) paldata = palettemap[pal.toLowerCase()]
- }
- if (!paldata) {
- if (!pal) {
- alert('Error, please report! Failed to extract the palette.\nAre you using the latest ANBT version?')
- } else {
- alert(`Error, please report! Unknown palette: '${pal}'.\nAre you using the latest ANBT version?`)
- }
- // Prevent from drawing with a wrong palette
- anbt.Lock()
- ID('submit').disabled = true
- } else {
- setPaletteByName(paldata[0])
- anbt.SetBackground(paldata[1])
- anbt.color = [palettes[paldata[0]][0], 'eraser']
- updateColorIndicators()
- }
- ID('setbackground').hidden = !info.bgbutton
- } else {
- // Caption
- if (info.image.length <= 30) {
- // Broken drawing =(
- ID('tocaption').src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAD6AQMAAAAho+iwAAAABlBMVEWAQED///94jotxAAABiklEQVR4Xu3W0UrCUBjA8eOO5CLK7VxLzDWFrjK6Eaha8FHuppfwBRJvdjlMIK/K3qA3OZBBd/UIm9UL2O2inMJBptNuog/6/h4Q2Y8J387Y2KIoiqIoiqIoiuIxXnbI5cmXSiJjD3LmFyrGY46PqVAx/HPDv9/w3wsJTTgapuDkcEIQMFxzo937S8+F5OkWI2IKymQl3yiZ6j8zYsRY6vUYDcOfGkuMknE5/aQAMczX9O+iKIrKJWuSxliQqT61hOmMucsYK6uzLWfDenF34EXhOX+s377KLCZcs1bxhNXQqnAvrExWM8vvY3amORCNsplu2nZPWKdj1tecTHZZLA97ZnjBB/XrkWIZWT+bsmTowp+7FHSnyMi7CpuMrWcwNsMMxnJzrCUbwwq/2/MLJb8lP4L2zVHJ35Bp1rE8Uc2bALoNHQvcoNG3Yf5Pm6EnHG50Ye0YmiG4V08LmWD7wmF9gJwFgoHbnZzNSDE/Co3orSB2YGsbovAgaD9vlkB/WbkbdQVWMNxR1Ddnf4eSZpHZYAAAAABJRU5ErkJggg=='
- } else {
- ID('tocaption').src = info.image
- }
- ID('caption').value = ''
- ID('caption').focus()
- ID('caption').setAttribute('maxlength', 45)
- ID('usedchars').textContent = '45'
- }
- if ((options.timeoutSound && !info.blitz) || (options.timeoutSoundBlitz && info.blitz)) {
- window.playedWarningSound = false
- const alarm = new Audio(window.alarmSoundOgg)
- alarm.volume = options.timeoutSoundVolume / 100
- }
- timerStart = Date.now() + 1000 * info.timeleft
- timerCallback = s => {
- if (s < 1) {
- document.title = "[TIME'S UP!] Playing Drawception"
- if (info.image || window.timesup) {
- // If pressed submit before timer expired, let it process or retry in case of error
- if (!window.submitting) {
- if (info.image) {
- getParametersFromPlay()
- } else {
- // Allow to save the drawing after time's up
- exitToSandbox()
- }
- }
- } else {
- newcanvas.classList.add('locked')
- anbt.Lock()
- timerStart += 15000 // 15 seconds to submit
- updateTimer()
- window.timesup = true
- }
- } else {
- let m1 = Math.floor(s / 60)
- let s1 = Math.floor(s % 60)
- m1 = `0${m1}`.slice(-2)
- s1 = `0${s1}`.slice(-2)
- document.title = `[${m1}:${s1}] Playing Drawception`
- }
- if (alarm && !window.playedWarningSound && s <= (info.blitz ? 5 : 61) && s > 0) {
- alarm.play()
- window.playedWarningSound = true
- }
- }
- handleCommonParameters()
- window.timesup = false
- updateTimer()
- }
-
- /*const include = (script, callback) => {
- const tag = document.createElement('script')
- tag.src = script
- tag.onload = callback
- document.body.appendChild(tag)
- }*/
-
- const decodeHTML = html => {
- const txt = document.createElement('textarea')
- txt.innerHTML = html
- return txt.value
- }
-
- const bindCanvasEvents = () => {
- const unsavedStopAction = () => anbt.unsaved && !confirm("You haven't saved the drawing. Abandon?")
- if (window.inforum) {
- ID('quit').addEventListener('click', ({preventDefault}) => {
- preventDefault
- window.top.location.href = 'https://drawception.com/'
- })
- const backForum = document.createElement('button')
- backForum.href = '/'
- backForum.setAttribute('class', 'submit exit')
- backForum.title = 'Exit'
- backForum.textContent = 'Exit'
- backForum.addEventListener('click', ({preventDefault}) => {
- preventDefault
- window.frameElement.ownerDocument.querySelector('.v--modal-overlay').outerHTML = ''
- })
- ID('submit').parentNode.insertBefore(backForum, ID('submit').nextSibling)
- }
- ID('exit').addEventListener('click', () => {
- if (window.incontest) {
- if (!confirm('Quit the contest? Entry coins will be lost!')) return
- ID('exit').disabled = true
- ajax('POST', '/contests/exit.json', {
- load: () => {
- ID('exit').disabled = false
- window.drawing_aborted = true
- exitToSandbox()
- document.location.pathname = '/contests/'
- },
- error: () => {
- ID('exit').disabled = false
- alert('Server error. :( Try again?')
- }
- })
- return
- }
- if (window.gameinfo.drawfirst) {
- if (!confirm('Abort creating a draw first game?')) return
- ID('exit').disabled = true
- ajax('POST', '/play/abort-start.json', {
- obj: {
- game_token: window.gameinfo.gameid
- },
- load: () => {
- ID('exit').disabled = false
- window.drawing_aborted = true
- exitToSandbox()
- document.location.pathname = '/create/'
- },
- error: () => {
- ID('exit').disabled = false
- alert('Server error. :( Try again?')
- }
- })
- return
- }
- if (!confirm('Really exit?')) return
- ID('exit').disabled = true
- ajax('POST', '/play/exit.json', {
- obj: {
- game_token: window.gameinfo.gameid
- },
- load: () => {
- ID('exit').disabled = false
- exitToSandbox()
- }
- })
- })
- ID('skip').addEventListener('click', () => {
- if (unsavedStopAction()) return
- ID('skip').disabled = true
- ajax('POST', '/play/skip.json', {
- obj: {
- game_token: window.gameinfo.gameid
- },
- load: () => getParametersFromPlay(), // Postpone enabling skip until we get game info
- error: () => {
- ID('skip').disabled = false
- getParametersFromPlay()
- }
- })
- })
- ID('start').addEventListener('click', () => {
- if (unsavedStopAction()) return
- ID('start').disabled = true
- getParametersFromPlay()
- })
- ID('report').addEventListener('click', () => {
- if (!confirm('Report this panel?')) return
- ajax('POST', '/play/flag.json', {
- obj: {
- game_token: window.gameinfo.gameid
- },
- load: () => {
- ID('report').disabled = false
- getParametersFromPlay()
- }
- })
- })
- ID('bookmark').addEventListener('click', () => {
- ID('bookmark').disabled = true
- let games = localStorage.getItem('gpe_gameBookmarks')
- games = games ? JSON.parse(games) : {}
- const caption = window.gameinfo.caption
- games[window.gameinfo.gameid] = {
- time: Date.now(),
- caption: caption ? decodeHTML(caption) : ''
- }
- localStorage.setItem('gpe_gameBookmarks', JSON.stringify(games))
- })
- ID('submit').addEventListener('click', () => {
- const moreThanMinuteLeft = timerStart - Date.now() > 60000
- if (options.submitConfirm && moreThanMinuteLeft && !confirm('Ready to submit this drawing?')) return
- ID('submit').disabled = true
- anbt.MakePNG(300, 250, true)
- if (options.backup) {
- localStorage.setItem('anbt_drawingbackup_newcanvas', anbt.pngBase64)
- }
- window.submitting = true
- let url
- if (window.incontest) {
- url = '/contests/submit-drawing.json'
- } else {
- url = '/play/draw.json'
- }
- ajax('POST', url, {
- obj: {
- game_token: window.gameinfo.gameid,
- panel: anbt.pngBase64
- },
- load: x => {
- let o
- try {
- o = JSON.parse(x)
- } catch (e) {
- o = {
- error: x
- }
- }
- if (o.error) {
- ID('submit').disabled = false
- if (typeof o.error === 'object') {
- alert(`Error! Please report this data:\ngame: ${window.gameinfo.gameid}\n\nresponse:\n${JSON.stringify(o.error)}`)
- } else {
- alert(o.error)
- }
- } else if (o.message) {
- ID('submit').disabled = false
- alert(o.message)
- } else if (o.url) {
- window.onbeforeunload = () => {}
- location.replace(o.url)
- }
- },
- error: () => {
- ID('submit').disabled = false
- alert('Server error. :( Try again?')
- }
- })
- })
- ID('submitcaption').addEventListener('click', () => {
- const title = ID('caption').value
- if (!title) {
- ID('caption').focus()
- return alert("You haven't entered a caption!")
- }
- const onCaptionSuccess = () => {
- if (options.bookmarkOwnCaptions) {
- let games = localStorage.getItem('gpe_gameBookmarks')
- games = games ? JSON.parse(games) : {}
- games[window.gameinfo.gameid] = {
- time: Date.now(),
- caption: `"${title}"`,
- own: true
- }
- localStorage.setItem('gpe_gameBookmarks', JSON.stringify(games))
- }
- }
- window.submitting = true
- ID('submitcaption').disabled = true
- let url
- if (window.incontest) {
- url = '/contests/submit-caption.json'
- } else {
- url = '/play/describe.json'
- }
- ajax('POST', url, {
- obj: {
- game_token: window.gameinfo.gameid,
- title
- },
- load: x => {
- let o
- try {
- o = JSON.parse(x)
- } catch (e) {
- o = {
- error: x
- }
- }
- if (o.error) {
- ID('submitcaption').disabled = false
- if (typeof o.error == 'object') {
- alert(`Error! Please report this data:\ngame: ${window.gameinfo.gameid}\n\nresponse: \n${JSON.stringify(o.error)}`)
- } else {
- alert(o.error)
- }
- } else if (o.message) {
- ID('submitcaption').disabled = false
- alert(o.message)
- } else if (o.url) {
- onCaptionSuccess()
- location.replace(o.url)
- }
- },
- error: () => {
- ID('submitcaption').disabled = false
- alert('Server error. :( Try again?')
- }
- })
- })
- if (options.enterToCaption) {
- ID('caption').addEventListener('keydown', e => {
- if (e.keyCode == 13) {
- e.preventDefault()
- ID('submitcaption').click()
- }
- })
- }
- const updateUsedChars = () => (ID('usedchars').textContent = 45 - ID('caption').value.length)
- ID('caption').addEventListener('change', updateUsedChars)
- ID('caption').addEventListener('keydown', updateUsedChars)
- ID('caption').addEventListener('input', updateUsedChars)
- ID('timeplus').addEventListener('click', () => {
- if (window.gameinfo.friend) {
- ID('timeplus').disabled = true
- ajax('POST', '/play/exit.json', {
- obj: {
- game_token: window.gameinfo.gameid
- },
- load: () => {
- ajax('GET', `/play/${window.gameinfo.gameid}/?${Date.now()}`, {
- load: x => {
- ID('timeplus').disabled = false
- if (x === '') {
- window.gameinfo = {
- error: 'Server returned a blank response :('
- }
- } else {
- window.gameinfo = extractInfoFromHTML(x)
- }
- timerStart = Date.now() + 1000 * window.gameinfo.timeleft
- },
- error: () => {
- ID('timeplus').disabled = false
- alert('Server error. :( Try again?')
- }
- })
- },
- error: () => {
- ID('timeplus').disabled = false
- alert('Server error. :( Try again?')
- }
- })
- return
- }
- ID('timeplus').disabled = true
- ajax('POST', '/play/add-time.json', {
- obj: {
- game_token: window.gameinfo.gameid
- },
- load: x => {
- const o = JSON.parse(x)
- if (o.error) {
- alert(o.error)
- } else if (o.callJS == 'updatePlayTime') {
- timerStart += o.data.seconds * 1000
- if (window.timesup) {
- ID('newcanvasyo').classList.remove('locked')
- anbt.Unlock()
- timerStart -= 15000 // remove 15 seconds to submit
- window.timesup = false
- }
- updateTimer()
- ID('timeplus').classList.remove('show')
- // Let play warning sound twice
- window.playedWarningSound = false
- }
- ID('timeplus').disabled = false
- },
- error: () => {
- ID('timeplus').disabled = false
- alert('Server error. :( Try again?')
- }
- })
- })
- const old_getClosestColor = window.getClosestColor
- window.getClosestColor = (rgb, pal) => {
- // Allow any color in friend games
- if (window.gameinfo && window.gameinfo.friend) return rgb2hex(rgb[0], rgb[1], rgb[2])
- return old_getClosestColor(rgb, pal)
- }
- }
-
- const deeper_main = () => {
- window.onerror = (e, file, line) => {
- // Silence the bogus error message from the overwritten page's timer
- if (e.toString().includes('periodsToSeconds')) return
- // Silence the useless error message
- if (e.toString().match(/script error/i)) return
- if (line) {
- alert(`${e}\nline: ${line}`)
- } else {
- alert(e)
- }
- }
- if (options.newCanvasCSS) {
- let parent = document.getElementsByTagName('head')[0]
- if (!parent) parent = document.documentElement
- const style = document.createElement('style')
- style.type = 'text/css'
- const textNode = document.createTextNode(options.newCanvasCSS)
- style.appendChild(textNode)
- parent.appendChild(style)
- }
- if (options.enableWacom) {
- const stupidPlugin = document.createElement('object')
- const container = ID('wacomContainer')
- stupidPlugin.setAttribute('id', 'wacom')
- stupidPlugin.setAttribute('type', 'application/x-wacomtabletplugin')
- stupidPlugin.setAttribute('width', '1')
- stupidPlugin.setAttribute('height', '1')
- container.appendChild(stupidPlugin)
- if (options.fixTabletPluginGoingAWOL) fixPluginGoingAWOL()
- }
- bindCanvasEvents()
- if (window.insandbox) {
- if (window.panelid) {
- ajax('GET', `/panel/drawing/${window.panelid}/-/`, {
- load: x => {
- window.gameinfo = extractInfoFromHTML(x)
- anbt.FromURL(`${gameinfo.drawinglink}?anbt`) // workaround for non-CORS cached image
- handleSandboxParameters()
- },
- error: () => {
- alert('Error loading the panel page. Please try again.')
- }
- })
- } else {
- if (window.origpage) {
- window.gameinfo = extractInfoFromHTML(window.origpage)
- handleSandboxParameters()
- window.origpage = null
- } else {
- ajax('GET', '/sandbox/', {
- load: x => {
- window.gameinfo = extractInfoFromHTML(x)
- handleSandboxParameters()
- },
- error: () => {}
- })
- }
- if (options.backup) {
- const pngdata = localStorage.getItem('anbt_drawingbackup_newcanvas')
- if (pngdata) {
- anbt.FromPNG(base642bytes(pngdata.substr(22)).buffer)
- localStorage.removeItem('anbt_drawingbackup_newcanvas')
- }
- }
- }
- } else {
- ID('newcanvasyo').className = 'play'
- getParametersFromPlay()
- }
- if (!options.smoothening) {
- buildSmoothPath = (points, path) => {
- if (points.length < 2) return
- path.pathSegList.initialize(path.createSVGPathSegMovetoAbs(points[0].x, points[0].y))
- for (let i = 1; i < points.length; i++) {
- const c = points[i]
- path.pathSegList.appendItem(path.createSVGPathSegLinetoAbs(c.x, c.y))
- }
- }
- }
- // Poor poor memory devices, let's save on memory to avoid them "crashing"...
- if (/iPad|iPhone/.test(navigator.userAgent)) anbt.fastUndoLevels = 3
- window.$ = () => {
- alert('Some additional script conflicts with ANBT new canvas, please disable it.')
- window.$ = null
- throw new Error('Script conflict with ANBT new canvas')
- }
- }
- deeper_main()
- } // needToGoDeeper end
-
- const $ = (selector, array = false) => {
- if (selector[0] === '<') {
- const elements = [...new DOMParser().parseFromString(selector, 'text/html').body.children]
- return elements.length !== 1 ? elements : elements[0]
- }
- const elements = [...document.querySelectorAll(selector)]
- return elements.length > 1 || array === true ? elements : elements[0]
- }
-
- const setCookie = (name, value, expire) => {
- if (expire) {
- let time = new Date
- time.setTime(time.getTime() + 24 * expire * 60 * 60 * 1e3)
- expire = time.toUTCString()
- }
- document.cookie = `${name}=${value ? JSON.stringify(value) : ''}; expires=${expire ? expire : 'Thu, 01 Jan 1970 00:00:00 UTC'}; path=/`
- }
-
- const getCookie = name => {
- const ca = document.cookie.split(';')
- for (let i = 0; i < ca.length; i++) {
- let c = ca[i]
- while (c.charAt(0) === ' ') c = c.substring(1, c.length)
- if (c.indexOf(`${name}=`) === 0) return c.substring(`${name}=`.length, c.length)
- }
- return null
- }
-
- //const isBlitzInPlay = () => ($('.label-game-mode') && $('.label-game-mode').textContent.match(/blitz/i) ? true : false)
-
- const linkifyNodeText = node => {
- const t = node
- if (!t.textContent.includes('://')) return
- t.innerHTML = t.innerHTML.replace(/([^"]|^)(https?:\/\/(?:(?:(?:[^\s<()]*\([^\s<()]*\))+)|(?:[^\s<()]+)))/g, '$1$2')
- }
-
- //const enhanceCanvas = insandbox => {}
-
- //const empowerPlay = () => {}
-
- // Event functions referred to in HTML must have unwrapped access
-
- const reversePanels = () => {
- const e = $('.gamepanel-holder')[0].parentNode.parentNode
- ;[...e.childNodes].reverse().forEach(x => e.appendChild(x))
- }
- window.reversePanels = reversePanels
-
- const toggleLight = () => {
- if (options.anbtDarkMode) {
- let css = document.getElementById('darkgraycss')
- if (!inDark) {
- if (!css) {
- css = document.createElement('style')
- css.id = 'darkgraycss'
- css.type = 'text/css'
- css.appendChild(document.createTextNode(localStorage.getItem('gpe_darkCSS')))
- }
- document.head.appendChild(css)
- inDark = 1
- } else {
- document.head.removeChild(css)
- inDark = 0
- }
- localStorage.setItem('gpe_inDark', inDark.toString())
- return
- } else {
- if (document.body.classList.contains('theme-night')) {
- document.body.classList.remove('theme-night')
- setCookie('theme-night')
- } else {
- document.body.classList.add('theme-night')
- setCookie('theme-night', 1, 365)
- }
- }
- }
- window.toggleLight = toggleLight
-
- const panelUrlToDate = url => {
- const m = url.match(/\/images\/panels\/(\d+)\/(\d+)-(\d+)\//)
- if (!m) return
- const monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
- const day = (100 + parseInt(m[3], 10)).toString().slice(-2)
- return `${monthNames[parseInt(m[2], 10) - 1]} ${day}, ${m[1]}`
- }
-
- const fixLocationToCanonical = m => {
- let ogurl = $('meta[property="og:url"]') ? $('meta[property="og:url"]').content : ''
- if (ogurl && ogurl.match(m)) {
- ogurl = ogurl.replace('https://drawception.com', '')
- try {
- if (location.pathname != ogurl) {
- history.replaceState({}, null, ogurl + location.hash)
- }
- } catch (e) {}
- }
- }
-
- const betterCreateGame = () => {
- if (!options.enterToCaption) {
- if ($('#prompt')) {
- $('#prompt').addEventListener('keydown', e => {
- if (e.keyCode == 13) {
- e.preventDefault()
- }
- })
- }
- }
- }
-
- const betterGame = () => {
- if (document.title == 'Not Safe For Work (18+) Gate') {
- if (options.autoBypassNSFW) {
- DrawceptionPlay.bypassNsfwGate()
- }
- return
- }
-
- fixLocationToCanonical('/game/')
-
- const drawings = $('img[src^="https://cdn.drawception.com/images/panels/"],img[src^="https://cdn.drawception.com/drawings/"]')
-
- // Show each drawing make date
- if (drawings) drawings.forEach(x => {
- const d = panelUrlToDate(x.src)
- if (d) x.title = `Made on ${d}`
- })
-
- // Fix misaligned panels
- /*const tryNextPanel = x => {
- if (!x.naturalWidth && !x.triedFixing) {
- let pos = x.src.match(/-(\d+)\.png$/)[1] + 1
- x.src = x.src.replace(/-(\d+)\.png$/, `-${pos}.png`)
- x.triedFixing = true
- }
- }
- // TODO: also fix if script is executed after page load
- drawings.forEach(x => x.addEventListener('error', tryNextPanel(x)))*/
-
- // Reverse panels button and like all button
- if ($('#btn-copy-url')) $('#btn-copy-url').insertAdjacentHTML('afterend', ' Reverse')
-
- // Panel favorite buttons
- const favButton = $('')
- $('.panel-number', true).forEach(x => x.insertAdjacentHTML('afterend', favButton.outerHTML))
- $('.gamepanel', true).forEach(x => {
- const t = x.parentNode
- if (t.querySelector('.gamepanel-tools>a:last-child') === null) return
- let panels = localStorage.getItem('gpe_panelFavorites')
- panels = panels ? JSON.parse(panels) : {}
- const id = t.querySelector('.gamepanel-tools>a:last-child').href.match(/\/panel\/[^\/]+\/([^\/]+)\/[^\/]+\//)[1]
- if (panels[id]) {
- t.querySelector('.anbt_favpanel').classList.add('anbt_favedpanel')
- } else {
- t.querySelector('.anbt_favpanel').classList.remove('anbt_favedpanel')
- }
- })
- $('.anbt_favpanel', true).forEach(x => {
- x.addEventListener('click', e => {
- if (x.classList.contains('anbt_favedpanel')) return
- const tp = x.parentNode
- const id = tp.querySelector('.gamepanel-tools>a:last-child').href.match(/\/panel\/[^\/]+\/([^\/]+)\/[^\/]+\//)[1]
-
- let panels = localStorage.getItem('gpe_panelFavorites')
- panels = panels ? JSON.parse(panels) : {}
-
- const panel = {
- time: Date.now(),
- by: tp.querySelector('.panel-user a').textContent
- }
- panel.userLink = tp.querySelector('.panel-user a').href.match(/\/player\/[^\/]+\/[^\/]+\//)[0]
- const img = tp.querySelector('.gamepanel img')
- if (img) {
- // Drawing panel
- panel.image = img.src
- panel.caption = img.alt
- } else {
- // Caption panel
- panel.caption = tp.querySelector('.gamepanel').textContent.trim()
- }
- panels[id] = panel
- localStorage.setItem('gpe_panelFavorites', JSON.stringify(panels))
- x.classList.add('anbt_favedpanel')
- })
- })
-
- // Panel replay button
- if (options.newCanvas) {
- const addReplayButton = x => {
- if (x.replayAdded) return
- x.replayAdded = true
- const panel = x.parentNode
- const src = x.src
- checkForRecording(src, () => {
- const newid = $(`img[src='${src}']`).parentNode.querySelector('a[href^="/panel/"]').href.match(/\/panel\/[^\/]+\/([^\/]+)/)[1]
- const id = newid.length >= 8 ? newid : scrambleID(panel.id.slice(6))
- const replayButton = $(``)
- replayButton.addEventListener('click', e => {
- if (e.which === 2) return
- e.preventDefault()
- setupNewCanvas(true, `/sandbox/#${id}`)
- })
- panel.insertAdjacentHTML('beforebegin', replayButton.outerHTML)
- })
- }
- if (drawings) drawings.forEach(x => x.addEventListener('load', addReplayButton(x)))
- }
-
- let comments
- // Comments appear dynamically after the page is loaded now
- const betterComments = () => {
- // Linkify the links and add ability to address comment holders again
- comments = [...$('#comments').nextElementSibling.children].slice(1)
- comments.forEach(x => {
- x.parentNode.parentNode.classList.add('comment-holder')
- })
- // Interlink game panels and comments
- const gamePlayers = []
- const playerdata = {}
- $('.gamepanel-holder', true).forEach((x, i) => {
- const det = x.querySelector('.panel-details')
- const gamepanel = x.querySelector('.gamepanel')
- const a = det.querySelector('.panel-user a')
- if (!a) return
- const id = a.href.match(/\/player\/(\d+)\//)[1]
- playerdata[id] = {
- panel_number: i + 1,
- player_anchor: a,
- panel_id: gamepanel.id,
- drew: gamepanel.querySelector('img') !== null,
- comments: 0
- }
- gamePlayers.push(id)
- })
- // Highlight new comments and remember seen comments
- let seenComments = localStorage.getItem('gpe_seenComments')
- seenComments = seenComments === null ? {} : JSON.parse(seenComments)
- const gameid = document.location.href.match(/game\/([^\/]+)\//)[1]
- const holders = comments
- if (holders) {
- // Clear old tracked comments
- const hour = Math.floor(Date.now() / (1000 * 60 * 60)) // timestamp with 1 hour precision
- for (let tempgame in seenComments) {
- // Store game entry for up to a week after last tracked comment
- if (seenComments[tempgame].h + 24 * 7 < hour) {
- delete seenComments[tempgame]
- }
- }
- let maxseenid = 0
- holders.forEach(x => {
- const dateel = x.querySelector('a.text-muted')
- const vue = x.__vue__
- if (vue) {
- const text = dateel.textContent.trim()
- dateel.textContent = `${text}, ${formatTimestamp(vue.comment_date * 1000)}`
- if (vue.edit_date > 0) {
- const el = dateel.parentNode.querySelector('span[rel="tooltip"]')
- let text2 = el.title
- text2 += `, ${formatTimestamp(vue.edit_date * 1000).replace(/ /g, '\u00A0')}` // prevent the short tooltip width from breaking date apart
- el.setAttribute('title', text2)
- }
- }
- const ago = dateel.textContent
- const anchorid = x.id
- const commentid = parseInt(anchorid.slice(1), 10)
- // Also allow linking to specific comment
- dateel.setAttribute('title', 'Link to comment')
- dateel.textContent = `${dateel.textContent.trim()} #${commentid}`
- // Track comments from up to week ago
- if (ago.match(/just now|min|hour|a day| [1-7] day/)) {
- if (!(seenComments[gameid] && seenComments[gameid].id >= commentid)) {
- x.classList.add('comment-new')
- if (maxseenid < commentid) maxseenid = commentid
- }
- }
- // Add game perticipation info
- const m = x.querySelector('.text-bold a') ? x.querySelector('.text-bold a').href.match(/\/player\/(\d+)\//) : ''
- if (m) {
- const id = m[1]
- if (gamePlayers.includes(id)) {
- const drew = playerdata[id].drew ? 'drew' : 'wrote'
- dateel.insertAdjacentHTML('beforebegin', `(${drew} #${playerdata[id].panel_number}) `)
- playerdata[id].comments += 1
- }
- }
- })
- if (maxseenid)
- seenComments[gameid] = {
- h: hour,
- id: maxseenid
- }
- localStorage.setItem('gpe_seenComments', JSON.stringify(seenComments))
- }
- for (let i = 0; i < gamePlayers.length; i++) {
- const data = playerdata[gamePlayers[i]]
- if (data.comments != 0) {
- const cmt = data.comments == 1 ? ' comment' : ' comments'
- const cmt2 = `Player left ${data.comments}${cmt}`
- data.player_anchor.title = cmt2
- data.player_anchor.insertAdjacentHTML('afterend', `${data.comments}`)
- }
- }
- if (options.maxCommentHeight) {
- const h = options.maxCommentHeight
- comments.forEach(x =>
- x.addEventListener('click', x => {
- if (x.clientHeight > h - 50 && !$(location.hash).has(x).length) location.hash = `#${x.parentNode.parentNode.id}`
- })
- )
- }
- }
- const waitForComments = () => {
- const comments = $('#comments') ? [...$('#comments').nextElementSibling.children].slice(1) : ''
- if (comments.length && !comments[0].classList.contains('spinner')) {
- betterComments()
- } else {
- if (comments.length === 0) return
- setTimeout(waitForComments, 1000)
- }
- }
- setTimeout(waitForComments, 200)
- }
- const checkForRecording = (url, yesfunc, retrying) => {
- const xhr = new XMLHttpRequest()
- xhr.open('GET', `${url}?anbt`, true)
- xhr.responseType = 'arraybuffer'
- xhr.onload = () => {
- const buffer = xhr.response
- const dv = new DataView(buffer)
- const magic = dv.getUint32(0)
- if (magic != 0x89504e47) return xhr.onerror() // Drawception started hijacking XHR errors and putting HTML in there
- for (let i = 8; i < buffer.byteLength; i += 4 /* Skip CRC */) {
- const chunklen = dv.getUint32(i)
- i += 4
- const chunkname = dv.getUint32(i)
- i += 4
- if (chunkname === 0x73764762) {
- return yesfunc()
- } else {
- if (chunkname === 0x49454e44) break
- i += chunklen
- }
- }
- }
- xhr.onerror = e => {
- console.log('checkForRecording fail (likely due to cache without CORS), retrying')
- if (!retrying) checkForRecording(`${url}?anbt`, yesfunc, true)
- }
- xhr.send()
- }
-
- const betterPanel = () => {
- // Just for quickly opening a panel by its numerical ID
- if ($('.gamepanel') && !$('.gamepanel').length && location.hash) {
- const id = location.hash.match(/\d+/)
- location.pathname = `/panel/-/${scrambleID(id)}/-/`
- }
-
- fixLocationToCanonical('/panel/')
-
- const favButton = $('')
- if ($('.panel-caption-display>.flex,.gamepanel-holder>.gamepanel')) $('.panel-caption-display>.flex,.gamepanel-holder>.gamepanel').insertAdjacentHTML('afterend', favButton.outerHTML)
- const favBtn = $('.btn.btn-info')
- if (favBtn) {
- favBtn.addEventListener('click', e => {
- e.preventDefault()
- let panels = localStorage.getItem('gpe_panelFavorites')
- panels = panels ? JSON.parse(panels) : {}
- const panel = {
- time: Date.now(),
- by: $('.lead a', true)[0].textContent
- }
- const id = document.location.href.match(/\/panel\/[^\/]+\/([^\/]+)\//)[1]
- panel.userLink = $('.lead a', true)[0].href.match(/\/player\/[^\/]+\/[^\/]+\//)[0]
- const img = $('.gamepanel img')
- if (img) {
- // Drawing panel
- panel.image = img.src
- panel.caption = img.alt
- } else {
- // Caption panel
- panel.caption = $('.gamepanel').textContent.trim()
- }
- panels[id] = panel
- localStorage.setItem('gpe_panelFavorites', JSON.stringify(panels))
- favBtn.setAttribute('disabled', 'disabled')
- favBtn.querySelector('b').textContent = 'Favorited!'
- })
- }
- let panels = localStorage.getItem('gpe_panelFavorites')
- panels = panels ? JSON.parse(panels) : {}
- if (document.location.href.match(/\/panel\/[^\/]+\/([^\/]+)\//) && panels[document.location.href.match(/\/panel\/[^\/]+\/([^\/]+)\//)[1]]) {
- favBtn.setAttribute('disabled', 'disabled')
- favBtn.querySelector('b').textContent = 'Favorited!'
- }
- const panelId = getPanelId(location.pathname)
-
- // Only panels after 14924553 might have a recording
- if (options.newCanvas && panelId && unscrambleID(panelId) >= 14924553) {
- const img = $('.gamepanel img')
- if (img) {
- checkForRecording(img.src, () => {
- const replayLink = $(` Replay `)
- replayLink.addEventListener('click', e => {
- if (e.which === 2) return
- e.preventDefault()
- setupNewCanvas(true, `/sandbox/#${panelId}`)
- })
- $('.gamepanel').insertAdjacentHTML('afterend', replayLink.outerHTML)
- })
- }
- }
- if ($('.btn-primary').length > 1 && $('.btn-primary')[1].textContent === 'Play again') {
- // Allow adding to cover creator
- const ccButton = $('')
- ccButton.addEventListener('click', e => {
- e.preventDefault()
- const id = unscrambleID(panelId)
- const cookie = getCookie('covercreatorids')
- const ids = cookie ? JSON.parse(cookie) : []
- if (!ids.includes(id)) {
- if (ids.length > 98) {
- apprise('Max cover creator drawings selected. Please remove some before adding more.')
- return
- } else {
- ids.push(id.toString())
- }
- } else {
- ccButton.setAttribute('disabled', 'disabled').querySelector('b').textContent = 'Already added!'
- return
- }
- setCookie('covercreatorids', JSON.stringify(ids))
- ccButton.setAttribute('disabled', 'disabled').querySelector('b').textContent = 'Added!'
- })
- $('.gamepanel').insertAdjacentHTML('afterend', ccButton.outerHTML)
- }
-
- /*if (options.rememberPosition && $('.regForm > .lead').textContent.match(/public game/)) {
- // your own panel
- panelPositions.load()
- if (!panelPositions.player[panelId]) {
- const xhr = new XMLHttpReuqest()
- xhr.open('GET', `/player/${userid}/-/`)
- xhr.onreadystatechange = html => {
- if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
- html = html.replace(/
]*>/gi, '') // prevent image preload
- const profilePage = new DOMParser().parseFromString(html, 'text/html')
- const panelProgressText = $(profilePage)
- .querySelector(`a[href='${location.pathname}']`)
- .nextElementSibling.querySelector('.progress-bar-text').textContent
- const panelPosition = parseInt(panelProgressText.match(/\d+/)[0])
- panelPositions.player[panelId] = panelPosition
- panelPositions.clear(profilePage)
- panelPositions.save()
-
- $('.regForm > .lead')
- .appendChild('
')
- .appendChild(($('').textContent = panelProgressText))
- }
- xhr.send()
- }
- }
- }*/
- }
- const panelPositions = {
- player: null,
- last: null,
- load() {
- const loadObj = key => {
- const val = localStorage.getItem(key)
- return (val && JSON.parse(val)) || {}
- }
-
- panelPositions.player = loadObj('gpe_panelPositions')
- panelPositions.last = loadObj('gpe_lastGamePositions')
- },
- save() {
- localStorage.setItem('gpe_panelPositions', JSON.stringify(panelPositions.player))
- localStorage.setItem('gpe_lastGamePositions', JSON.stringify(panelPositions.last))
- },
- clear(page) {
- const clearKeys = (obj, keys) => {
- for (let k in obj) {
- if (!keys.includes(k)) delete obj[k]
- }
- }
-
- const existingIds = $(page)
- .querySelector('.progress-striped')
- .map(x => getPanelId(x.previousElementSibling.href))
- clearKeys(panelPositions.player, existingIds)
- clearKeys(panelPositions.last, existingIds)
- }
- }
-
- const getPanelId = url => {
- const match = url.match(/\/panel\/[^\/]+\/(\w+)\//)
- return match && match[1]
- }
-
- const simpleHash = s =>
- s
- .toString()
- .split('')
- .reduce((a, b) => {
- a = (a << 5) - a + b.charCodeAt(0)
- return a & a
- }, 0)
-
- const rot13 = s =>
- s
- .toString()
- .split('')
- .map(c => {
- c = c.charCodeAt(0)
- if (c >= 97 && c <= 122) c = ((c - 97 + 13) % 26) + 97
- if (c >= 65 && c <= 90) c = ((c - 65 + 13) % 26) + 65
- return String.fromCharCode(c)
- })
- .join('')
-
- const fadeIn = (element, duration = 400) => {
- element.style.display = 'inline'
- duration = duration === 'slow' ? 600 : duration
- element.style.opacity = element.style.opacity ? parseFloat(element.style.opacity) + 0.1 : 0.2
- if (parseFloat(element.style.opacity) > 1) {
- element.style.opacity = 1
- } else {
- setTimeout(() => {
- fadeIn(element, duration)
- }, duration / 10)
- }
- }
-
- const fadeOut = (element, duration = 400) => {
- duration = duration === 'slow' ? 600 : duration
- element.style.opacity = element.style.opacity ? parseFloat(element.style.opacity) - 0.1 : 1
- if (parseFloat(element.style.opacity) < 0) {
- element.style.opacity = 0
- element.style.display = 'none'
- } else {
- setTimeout(() => {
- fadeOut(element, duration)
- }, duration / 10)
- }
- }
-
- const randomGreeting = () => {
- // Spoilers!
- const g = ['Oruvaq lbh!', "Ubcr vg'f abg envavat gbqnl.", 'Jurer vf lbhe tbq abj?', 'Lbh fubhyq srry 5% zber cbjreshy abj.', 'Fhqqrayl, abguvat unccrarq!', '^_^', 'Guvf gnxrf fb ybat gb svavfu...', "Jungrire lbh qb, qba'g ernq guvf grkg.", 'Pyvpx urer sbe 1 serr KC', 'Or cngvrag.', "Whfg qba'g fgneg nal qenzn nobhg vg.", '47726S6Q2069732074686520677265617465737421', 'Cynl fzneg.', 'Cynl avpr.', 'Fzvyr!', "Qba'g sbetrg gb rng.", "V xabj jung lbh'ir qbar.", 'Fpvrapr!', 'Gbqnl vf n tbbq qnl.']
- const change_every_half_day = Math.floor(Date.now() / (1000 * 60 * 60 * 12))
- const rnddata = simpleHash(change_every_half_day + parseInt(userid, 10) + 178889)
- return rot13(g[rnddata % g.length])
- }
-
- const formatTimestamp = d => {
- if (typeof d == 'number') d = new Date(d)
- if (options.localeTimestamp) return d.toLocaleString()
- const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
- const s = [`${100 + d.getDate()}`.slice(-2), ' ', months[d.getMonth()], ' ', d.getFullYear(), ' ', `${100 + d.getHours()}`.slice(-2), ':', `${100 + d.getMinutes()}`.slice(-2)].join('')
- return s
- }
-
- const viewMyPanelFavorites = () => {
- let panels = localStorage.getItem('gpe_panelFavorites')
- panels = panels ? JSON.parse(panels) : {}
- let result = ''
- let needsupdate = false
- for (let id in panels) {
- if (panels[id].image && panels[id].image.match(/^\/pub\/panels\//)) {
- needsupdate = true
- panels[id].image = panels[id].image.replace('/pub/panels/', 'https://cdn.drawception.com/images/panels/')
- }
- result += ``
- }
- if (needsupdate) localStorage.setItem('gpe_panelFavorites', JSON.stringify(panels))
- result = result ? `${result}` : "You don't have any favorited panels."
- $('#anbt_userpage').innerHTML = result
- $('#anbt_userpage .anbt_paneldel', true).forEach(x =>
- x.addEventListener('click', e => {
- e.preventDefault()
- const id = x.parentNode.parentNode.id
- fadeOut($(`#${CSS.escape(id)}`))
- delete panels[id]
- localStorage.setItem('gpe_panelFavorites', JSON.stringify(panels))
- })
- )
- }
- window.viewMyPanelFavorites = viewMyPanelFavorites
-
- const viewMyGameBookmarks = () => {
- const removeButtonHTML = ''
- let games = localStorage.getItem('gpe_gameBookmarks')
- games = games ? JSON.parse(games) : {}
- let result = ''
- for (let id in games) {
- let extraClass = ''
- if (games[id].own) extraClass = 'anbt_owncaption'
- if (id.length > 10) {
- // token, seen lengths: 43, 32; just in case assuming everything > 10 is a token
- result += ``
- const xhr = new XMLHttpRequest()
- xhr.open('GET', `/play/${id}`)
- xhr.onload = () => {
- if (xhr.status === 200) {
- let m = xhr.responseText.match(/Game is not private/) || (xhr.responseText.match(/Problem loading game/) && 'del')
- if (m) {
- let gamename = ''
- if (games[id].caption) gamename += ` ${games[id].caption}`
- if (games[id].own) gamename = ` with your caption${gamename}`
- if (games[id].time) gamename += ` bookmarked on ${formatTimestamp(games[id].time)}`
- if (!gamename) gamename = id
- const status = m === 'del' ? 'Deleted' : 'Unfinished public'
- $(`#${id}`).querySelector('span').textContent = `${status} game${gamename}`
- return
- }
- const title = xhr.responseText.match(/(.+)<\/title>/)[1]
- m = xhr.responseText.match(/\/game\/([^\/]+)\/[^\/]+\//)
- const url = m[0]
- const gameid = m[1]
- delete games[id]
- games[gameid] = {
- title,
- url
- }
- $(`#${id}`).id = gameid
- const spanId = $(`#${gameid}`).querySelector('span')
- spanId.parentNode.replaceChild($(`${title}`), spanId)
- localStorage.setItem('gpe_gameBookmarks', JSON.stringify(games))
- } else {
- $(`#${id}`).querySelector('span').textContent = `Error while retrieving game: ${xhr.responseText}`
- }
- }
- xhr.send()
- } else if (id.length == 10) result += `` // game ID
- }
- if (!result) result = "You don't have any bookmarked games."
- $('#anbt_userpage').innerHTML = result
- $('#anbt_userpage .anbt_gamedel', true).forEach(x =>
- x.addEventListener('click', e => {
- e.preventDefault()
- const id = x.parentNode.id
- fadeOut($(`#${id}`))
- delete games[id]
- localStorage.setItem('gpe_gameBookmarks', JSON.stringify(games))
- })
- )
- }
- window.viewMyGameBookmarks = viewMyGameBookmarks
-
- // Convert times
- // Forum time is Florida, GMT-6, to be +1 DST since 08 Mar 2015, 2:00
- // starts on the second Sunday in March and ends on the first Sunday in November
- const isFloridaDST = () => {
- d = new Date(Date.now() - 6 * 60 * 60 * 1000)
- const month = d.getUTCMonth()
- const day = d.getUTCDate()
- const hours = d.getUTCHours()
- const dayofweek = d.getUTCDay()
-
- if (month < 2 || month > 10) return false
- if (month > 2 && month < 10) return true
- if (month == 2) {
- if (day < 8) return false
- if (day > 14) return true
- if (dayofweek == 7) return hours > 1
- return day > dayofweek + 7
- }
- if (month == 10) {
- if (day > 7) return false
- if (dayofweek == 7) return hours < 1
- return day <= dayofweek
- }
- }
-
- const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
- const convertForumTime = (year, month, day, hours, minutes) => {
- const d = new Date(year, month, day, hours, minutes)
- const tzo = d.getTimezoneOffset() * 60 * 1000
- const dst = isFloridaDST()
- return formatTimestamp(d.getTime() - tzo + (6 - dst) * 60 * 60 * 1000)
- }
-
- const betterPlayer = () => {
- // Linkify the links in location
- const pubinfo = $('.profile-header-info .text-muted > span:last-child')
- if (pubinfo) linkifyNodeText(pubinfo.parentNode)
-
- const loc = document.location.href
- // If it's user's homepage, add new buttons in there
- if (loc.match(new RegExp(`/player/${userid}/[^/]+/(?:$|#)`))) {
- const a = $('ANBT stuff:
')
- a.appendChild($('Panel Favorites'))
- a.appendChild($('Game Bookmarks'))
- const profilemain = $('.profile-layout-content').firstChild
- profilemain.insertAdjacentHTML('afterbegin', `${randomGreeting()}
`)
- profilemain.insertAdjacentHTML('afterbegin', a.outerHTML)
-
- if (document.location.hash.includes('#anbt_panelfavorites')) viewMyPanelFavorites()
- if (document.location.hash.includes('#anbt_gamebookmarks')) viewMyGameBookmarks()
-
- /*if (options.rememberPosition) {
- panelPositions.load();
- panelPositions.clear(document);
-
- $(".progress-striped").forEach(function () {
- const panelId = getPanelId(this.previousElementSibling.href);
- const playerPanelPosition = panelPositions.player[panelId];
- const lastSeenPanelPosition = panelPositions.last[panelId];
- const panelProgress = this.querySelector(".progress-bar-text");
- const panelProgressText = panelProgress.textContent;
- const panelPosition = parseInt(panelProgressText.match(/\d+/)[0]);
- const totalPanelCount = parseInt(panelProgressText.match(/\d+/g)[1]);
-
- panelProgress.style.pointerEvents = "none"; // to make tooltips work under label
- if ((playerPanelPosition || lastSeenPanelPosition || panelPosition) < panelPosition) {
- this.querySelector(".progress-bar")
- .width(`${(playerPanelPosition || lastSeenPanelPosition) / totalPanelCount * 100}%`);
- }
- if (playerPanelPosition && panelPosition > playerPanelPosition && playerPanelPosition < lastSeenPanelPosition) {
- $('')
- .width(`${(Math.min(lastSeenPanelPosition || panelPosition, panelPosition) - playerPanelPosition) / totalPanelCount * 100}%`)
- .insertAdjacentHTML('beforebegin', panelProgress.outerHTML)
- .tooltip();
- }
- if (lastSeenPanelPosition && panelPosition > lastSeenPanelPosition) {
- $('
')
- .width(`${(panelPosition - lastSeenPanelPosition) / totalPanelCount * 100}%`)
- .insertAdjacentHTML('beforebegin', panelProgress.outerHTML)
- .tooltip();
- }
- if (lastSeenPanelPosition && panelPosition < lastSeenPanelPosition) {
- $('
')
- .width(`${1 / totalPanelCount * 100}%`)
- .insertAdjacentHTML('beforebegin', panelProgress.outerHTML)
- .tooltip();
- }
- if (playerPanelPosition) {
- $('
')
- .text(`#${playerPanelPosition}`)
- .insertAdjacentHTML('beforebegin', this.outerHTML)
- .tooltip();
- }
-
- panelPositions.last[panelId] = panelPosition;
- });
-
- panelPositions.save();
- }*/
-
- // Show your exact registration date
- if (window.date) {
- const pubinfo = $('.profile-user-header>div.row>div>h1+p')
- if (pubinfo) {
- const newregdate = formatTimestamp(date)
- ;[...pubinfo.childNodes][4].nodeValue = ` ${newregdate} \xa0`
- }
- }
- } else {
- // Not the current user's profile or not profile homepage
- let drawings = $('img[src^="https://cdn.drawception.com/images/panels/"],img[src^="https://cdn.drawception.com/drawings/"]', true)
- // Show replayable panels; links are not straightforward to make since there's no panel ID
- if (options.newCanvas) {
- const addReplaySign = x => {
- if (x.replayAdded) return
- x.replayAdded = true
- const panel = x.parentNode.parentNode
- const src = x.src
- checkForRecording(src, () => {
- const newid = src.match(/(\w+).png$/)[1]
- const replaySign = newid.length >= 8 ? $(``) : $('')
- panel.appendChild(replaySign)
- //replaySign.tooltip();
- })
- }
- drawings.forEach(x => x.addEventListener('load', addReplaySign(x)))
- }
-
- // Detect Draw Firsts
- drawings.forEach(({src, parentNode}) => {
- if (src.match(/-1\.png$/)) {
- const drawFirstSign = $('
')
- parentNode.parentNode.appendChild(drawFirstSign)
- //drawFirstSign.tooltip();
- }
- })
- }
-
- // Convert timestamps in user profile's forum posts and game comments
- if (loc.match(/player\/\d+\/[^/]+\/(posts)|(comments)\//)) {
- // Show topic title at the top of the posts instead and display subforum
- // Show game title at the top of the posts
- $('.forum-thread-starter', true).forEach(x => {
- const vue = x.childNodes[0].__vue__
- if (vue) {
- const ts = x.querySelector('a.text-muted').firstChild
- const text = ts.textContent.trim()
- ts.textContent = `${text}, ${formatTimestamp(vue.comment_date * 1000)}`
- if (vue.edit_date > 0) {
- const el = ts.parentNode.parentNode.querySelector('span[rel="tooltip"]')
- let text2 = el.title
- text2 += `, ${formatTimestamp(vue.edit_date * 1000).replace(/ /g, '\u00A0')}` // prevent the short tooltip width from breaking date apart
- el.setAttribute('title', text2)
- }
- }
- const postlink = x.querySelector('.add-margin-top small.text-muted')
- const created = postlink.textContent.match(/^\s*Created/)
- const commented = postlink.textContent.match(/^\s*Commented/)
- const prefix = commented ? 'Comment in the game' : created ? 'New thread' : 'Reply in'
- const n = $(`${prefix}:
`)
- const thread = postlink.querySelector('a')
- n.appendChild(thread)
- x.insertAdjacentHTML('afterbegin', n.outerHTML)
- postlink.parentNode.parentNode.removeChild(postlink.parentNode)
- })
- }
- }
-
- const betterForum = () => {
- const ncPosts = []
- $('span.muted, span.text-muted, small.text-muted', true).forEach((x, index) => {
- const tx = x.textContent
- // Don't touch relative times
- if (tx.includes('ago')) return
- if ((m = tx.match(/^\s*\(last post (...) (\d+).. (\d+):(\d+)([ap]m)\)\s*$/))) {
- const d = new Date()
- const month = months.indexOf(m[1])
- const day = parseInt(m[2], 10)
- let hours = parseInt(m[3], 10) % 12
- const minutes = parseInt(m[4], 10)
- let year = d.getFullYear()
- if (d.getMonth() < 6 && month >= 6) year--
- hours += m[5] === 'pm' ? 12 : 0
- const time = convertForumTime(year, month, day, hours, minutes)
- x.textContent = `(last post ${time})`
- // Track new posts at subforum list
- if (location.href.match(/forums\/$/)) {
- if (time != localStorage.getItem(`anbt_subforum${index}`)) {
- x.parentNode.insertAdjacentHTML('afterbegin', 'NEW ')
- localStorage.setItem(`anbt_subforum${index}`, time)
- }
- }
- }
- })
-
- if (options.markStalePosts) {
- const markStalePost = ({classList}, age) => {
- if (age < 30) return
- let r = 0
- if (age > 60) r = 1
- if (age > 120) r = 2
- if (age > 365) r = 3
- classList.add(`anbt_necropost anbt_necropost${r}`)
- }
- // Skip the first post
- for (let i = 1; i < ncPosts.length; i++) {
- const el = ncPosts[i][0]
- const time = ncPosts[i][1]
- const lastpage = !$('.pagination').length || $('.pagination .active:last-child').length
- const nexttime = ncPosts[i + 1] ? ncPosts[i + 1][1] : lastpage ? Date.now() / 86400000 : 0
- const age = nexttime - time
- if (age > 30) markStalePost($(el).parentNode.parentNode.parentNode.parentNode, age)
- }
-
- GM_addStyle(".anbt_necropost:after {display: block; height: 14px; border-bottom: 2px solid black; content: ' '; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAMAAADOvxanAAAAElBMVEUAAAD///8wLiSYlYNnZFXm5Nfd4sMOAAAAAnRSTlMAAHaTzTgAAABBSURBVHheXchBEoBADAJBMsD/v2yZdS8Oly40k9NIk54ySm/8DYb6NWuuex1ak7VdbAcpNrCU8HmP4/hzd9oAXj6sBgHBLAHrRAAAAABJRU5ErkJggg==)}" + '.anbt_necropost0:after {background: none; border-bottom: 1px solid black}' + '.anbt_necropost1:after {background: none}' + '.anbt_necropost2:after {background-repeat: no-repeat; background-position: center}' + '.anbt_necropost3:after {}' + ".anbt_necropost span.muted:after {content: ' (old post)'}" + 'iframe {border: none}' + '.v--modal-overlay .v--modal-background-click {padding-bottom: 0}')
- }
- // Linkify the links
- $('.comment-body *', true).forEach(x => linkifyNodeText(x))
-
- // Linkify drawing panels
- $('img[src*="/images/panels/"], img[src*="/pub/panels/"]', true).forEach(x => {
- if (x.parentNode.nodeName !== 'A') x.outerHTML = `${x.outerHTML}`
- })
- $('img[src*="/drawings/"]', true).forEach(x => {
- if (x.parentNode.nodeName !== 'A') x.outerHTML = `${x.outerHTML}`
- })
- $('img[src*="/panel/"]', true).forEach(x => {
- if (x.parentNode.nodeName !== 'A') x.outerHTML = `${x.outerHTML}`
- })
- // Linkify full game image
- $('img[src*="/images/games/"], img[src*="/pub/games/"]', true).forEach(x => {
- if (x.parentNode.nodeName !== 'A') x.outerHTML = `${x.outerHTML}`
- })
- // Fix the dead link
- $('img[src*="/display-panel.php?"]', true).forEach(x => {
- if (x.parentNode.nodeName !== 'A') {
- const newsrc = `/panel/drawing/${scrambleID(x.src.match(/x=(\d+)/)[1])}/`
- x.setAttribute('src', newsrc)
- x.outerHTML = `${x.outerHTML}`
- }
- })
-
- // Show posts IDs and link
- if (document.location.pathname.match(/\/forums\/(\w+|-)\/.+/)) {
- const hideuserids = options.forumHiddenUsers ? options.forumHiddenUsers.split(',') : ''
- if (hideuserids !== '') {
- GM_addStyle('.anbt_hideUserPost:not(:target) {opacity: 0.4; margin-bottom: 10px}' + '.anbt_hideUserPost:not(:target) .comment-body, .anbt_hideUserPost:not(:target) .avatar {display: none}' + '')
- }
- let lastid = 0
- $('.comment-avatar', true).forEach(({parentNode}) => {
- const t = parentNode.parentNode.parentNode
- let anch
- let id
- t.classList.add('comment-holder') // No identification for these anymore, this is unhelpful!
- try {
- anch = t.id
- } catch (e) {}
- const ts = t.querySelector('a.text-muted')
- const vue = t.childNodes[0].__vue__
- if (vue) {
- const text = ts.textContent.trim()
- ts.textContent = `${text}, ${formatTimestamp(vue.comment_date * 1000)}`
- if (vue.edit_date > 0) {
- const el = ts.parentNode.querySelector('span[rel="tooltip"]')
- let text2 = el.title
- text2 += `, ${formatTimestamp(vue.edit_date * 1000).replace(/ /g, '\u00A0')}` // prevent the short tooltip width from breaking date apart
- el.setAttribute('title', text2)
- }
- }
- if (anch) {
- id = parseInt(anch.substring(1), 10)
- const text = ts.textContent.trim()
- ts.textContent = `${text} #${id}`
- ts.setAttribute('title', 'Link to post')
- if (id < lastid) {
- ts.classList.add('wrong-order')
- }
- try {
- const h = t.querySelector('a[href^="/player/"]').href
- if (h) {
- const userid = h.match(/\d+/)[0]
- if (hideuserids.includes(userid)) t.classList.add('anbt_hideUserPost')
- }
- } catch (e) {}
- lastid = id
- }
- })
-
- // Warn about posting to another page
- if ($('.comment-holder') && $('.comment-holder').length === 20 && $('#comment-form .btn-primary')) $('#comment-form .btn-primary').insertAdjacentHTML('afterend', 'Note: posting to another page
')
- }
-
- if (options.proxyImgur) $('img[src*="imgur.com/"]', true).forEach(x => x.setAttribute('src', x.src.replace('imgur.com', 'filmot.com').replace('https', 'http')))
-
- const pagination = $('.pagination', true)
- if (pagination.length) $('.breadcrumb').insertAdjacentHTML('afterend', `${pagination[0].outerHTML}
`)
-
- // For the topic list pages only
- if (document.location.pathname.match(/\/forums\/(\w+)\/$/)) {
- let hidden_topics = localStorage.getItem('gpe_forumHiddenTopics')
- hidden_topics = hidden_topics ? JSON.parse(hidden_topics) : []
- let hidden = 0
-
- const tempUnhideLink = $('')
-
- $('.forum-thread', true).forEach(x => {
- const m = x.querySelector('a:first-child').href.match(/\/forums\/\w+\/(\d+)\//)
- // Don't let them hide the ANBT topic ;)
- if (!m || !m[1] || m[1] == 11830) return
-
- const id = m[1]
- if (hidden_topics.includes(id)) {
- x.classList.add('anbt_hidden')
- hidden++
- }
- const hideLink = $('')
- hideLink.addEventListener('click', () => {
- let ht = localStorage.getItem('gpe_forumHiddenTopics')
- ht = ht ? JSON.parse(ht) : []
- if (hidden_topics.includes(id)) {
- if (ht.includes(id)) ht = ht.filter(y => y !== id)
- hidden_topics = hidden_topics.filter(y => y !== id)
- x.classList.remove('anbt_hidden')
- hidden--
- } else {
- if (!ht.includes(id)) ht.push(id)
- hidden_topics.push(id)
- x.classList.add('anbt_hidden')
- hidden++
- tempUnhideLink.style.display = ''
- }
- tempUnhideLink.textContent = hidden
- localStorage.setItem('gpe_forumHiddenTopics', JSON.stringify(ht))
- })
- x.querySelector('p:nth-child(2)').appendChild(hideLink)
- })
- tempUnhideLink.textContent = hidden
- tempUnhideLink.addEventListener('click', () => {
- $('#main').classList.toggle('anbt_showt')
- })
- if (!hidden) tempUnhideLink.style.display = 'none'
- if ($('#js-btn-toggle-thread')) $('#js-btn-toggle-thread').parentNode.appendChild(tempUnhideLink)
- }
- $('.btn.btn-default', true).forEach(x =>
- x.addEventListener('click', e => {
- if (x.textContent === 'Draw') {
- if (!x.classList.contains('click')) {
- let delModal = setInterval(() => {
- if (!$('.v--modal-overlay')) return
- $('.v--modal-overlay').outerHTML = ''
- clearInterval(delModal)
- }, 100)
- x.classList.add('click')
- }
- setupNewCanvas(true, document.location.href)
- }
- })
- )
- }
-
- const loadScriptSettings = () => {
- let result = localStorage.getItem('gpe_anbtSettings')
- if (!result) return
- result = JSON.parse(result)
- for (let i in result) options[i] = result[i]
- }
-
- const updateScriptSettings = theForm => {
- const result = {}
- theForm.querySelectorAll('input,textarea').forEach(x => {
- if (x.type === 'checkbox') {
- result[x.name] = x.checked ? 1 : 0
- } else if (x.getAttribute('data-subtype') === 'number') {
- result[x.name] = parseFloat(x.value) || 0
- } else {
- result[x.name] = x.value
- }
- })
- localStorage.setItem('gpe_anbtSettings', JSON.stringify(result))
- loadScriptSettings()
- fadeIn($('#anbtSettingsOK'), 'slow')
- setTimeout(() => {
- fadeOut($('#anbtSettingsOK'), 'slow')
- }, 800)
- }
- window.updateScriptSettings = updateScriptSettings
-
- const escapeHTML = t =>
- t
- .toString()
- .replace(/&/g, '&')
- .replace(//g, '>')
- .replace(/"/g, '"')
- .replace(/'/g, ''')
-
- const addScriptSettings = () => {
- const theForm = $('')
- theForm.appendChild($(''))
-
- const addGroup = (name, settings) => {
- const div = $('')
- div.appendChild($(``))
- settings.forEach(id => {
- let v = options[id[0]]
- const name = id[0]
- const t = id[1]
- const desc = id[2]
- const c = $('')
- if (t == 'boolean') {
- c.appendChild($(``))
- } else if (t == 'number') {
- if (!v) v = 0
- $(`${desc}:`).forEach(x => c.appendChild(x))
- } else if (t == 'longstr') {
- $(`${desc}:`).forEach(x => c.appendChild(x))
- } else {
- $(`${desc}:`).forEach(x => c.appendChild(x))
- }
- div.appendChild(c)
- })
- theForm.appendChild(div)
- }
- addGroup('Pen Tablet (requires plugin: Windows | Mac OS | Linux)', [
- ['enableWacom', 'boolean', 'Enable Wacom plugin / pressure sensitivity support'],
- ['fixTabletPluginGoingAWOL', 'boolean', 'Try to prevent Wacom plugin from disappearing']
- //["pressureExponent", "number", "Pressure exponent (smaller = softer tablet response, bigger = sharper)"],
- ])
- addGroup('Play (most settings are for the new canvas only)', [['newCanvas', 'boolean', 'New drawing canvas (also allows watching playback)'], ['submitConfirm', 'boolean', 'Confirm submitting if more than a minute is left'], ['smoothening', 'boolean', 'Smoothing of strokes'], ['hideCross', 'boolean', 'Hide the cross when drawing'], ['enterToCaption', 'boolean', 'Submit captions (and start games) by pressing Enter'], ['backup', 'boolean', 'Save the drawing in case of error and restore it in sandbox'], ['timeoutSound', 'boolean', 'Warning sound when only a minute is left (normal games)'], ['timeoutSoundBlitz', 'boolean', 'Warning sound when only 5 seconds left (blitz)'], ['timeoutSoundVolume', 'number', 'Volume of the warning sound, in %'], ['rememberPosition', 'boolean', 'Show your panel position and track changes in unfinished games list'], ['colorNumberShortcuts', 'boolean', 'Use 0-9 keys to select the color'], ['colorUnderCursorHint', 'boolean', 'Show the color under the cursor in the palette'], ['colorDoublePress', 'boolean', 'Double press 0-9 keys to select color without pressing shift'], ['bookmarkOwnCaptions', 'boolean', 'Automatically bookmark your own captions in case of dustcatchers']])
- addGroup('Miscellaneous', [['localeTimestamp', 'boolean', `Format timestamps as your system locale (${new Date().toLocaleString()})`], ['proxyImgur', 'boolean', 'Replace imgur.com links to filmot.com to load, in case your ISP blocks them'], ['ajaxRetry', 'boolean', 'Retry failed AJAX requests'], ['autoplay', 'boolean', 'Automatically start replay when watching playback'], ['autoBypassNSFW', 'boolean', 'Automatically bypass NSFW game warning'], ['markStalePosts', 'boolean', 'Mark stale forum posts'], ['maxCommentHeight', 'number', 'Maximum comments and posts height until directly linked (px, 0 = no limit)'], ['useOldFont', 'boolean', 'Use old Nunito font (which is usually bolder and less wiggly)'], ['useOldFontSize', 'boolean', 'Use old, smaller font size'], ['markdownTools', 'boolean', 'Markdown tools for messages'], ['anbtDarkMode', 'boolean', 'Switch between ANBT\'s and Drawception\'s dark mode']])
- addGroup('Advanced', [['newCanvasCSS', 'longstr', 'Custom CSS for new canvas (experimental, get styles here)'], ['forumHiddenUsers', 'longstr', 'Comma-separated list of user IDs whose forum posts are hidden']])
- $('
').forEach(x => theForm.appendChild(x))
- $('#main').insertAdjacentHTML('afterbegin', theForm.outerHTML)
-
- // Extend "location" input to max server-accepted 65 characters
- if ($('input[name="location"]')) $('input[name="location"]').setAttribute('maxlength', '65')
- }
-
- /*const autoSkip = (reason) => {
- const autoSkipInfo = $(`(CLICK TO CANCEL)
Auto-skipping in 3...
Reason: ${reason}
`)
- $('.play-instruction').appendChild(autoSkipInfo)
- autoSkipInfo.addEventListener('click', (e) => {
- e.preventDefault()
- $('#autoSkipCounter').countdown('pause')
- autoSkipInfo.style.display = 'none'
- })
- $('#autoSkipCounter').countdown({
- until: 3,
- compact: 1,
- format: 'S',
- onExpiry: timesUp,
- })
- }*/
-
- const theAlphabet = '36QtfkmuFds0UjlvCGIXZ125bEMhz48JSYgipwKn7OVHRBPoy9DLWaceqxANTr'
- // Game IDs will never contain these symbols: u 0U lv I J i V o
- // So they are base 52 for some reason...
-
- const decTo62 = n => {
- const b = theAlphabet
- let result = ''
- const bLen = b.length
- while (n != 0) {
- const q = n % bLen
- result = b[q] + result
- n = (n - q) / bLen
- }
- return result
- }
-
- const _62ToDec = n => {
- n = n.toString()
- const b = theAlphabet
- const cache_pos = {}
- const bLen = b.length
- let result = 0
- let pow = 1
- for (let i = n.length - 1; i >= 0; i--) {
- const c = n[i]
- if (typeof cache_pos[c] === 'undefined') {
- cache_pos[c] = b.indexOf(c)
- }
- result += pow * cache_pos[c]
- pow *= bLen
- }
- return result
- }
-
- const scrambleID = num => {
- if (isNaN(num)) throw new Error('Invalid panel ID')
- return decTo62(parseInt(num, 10) + 3521614606208)
- .split('')
- .reverse()
- .join('')
- }
- window.scrambleID = scrambleID
-
- const unscrambleID = str =>
- _62ToDec(
- str
- .split('')
- .reverse()
- .join('')
- ) - 3521614606208
- window.unscrambleID = unscrambleID
-
- const stalkNextPanel = forward => {
- if (!forward) forward = 1
- const sid = location.href.match(/\/panel\/[^\/]+\/(\w+)\/[^\/]+\//)[1]
- const sid2 = scrambleID(unscrambleID(sid) + 1 * forward)
- location.href = location.href.replace(sid, sid2)
- }
- window.stalkNextPanel = stalkNextPanel
-
- /*const valueToHex = val => (Math.floor(val / 16) % 16).toString(16) + (Math.floor(val) % 16).toString(16)
-
- const eyedropper = (x, y) => {
- const p = drawApp.context.getImageData(x, y, 1, 1).data
- return p[3] > 0 ? `#${valueToHex(p[0])}${valueToHex(p[1])}${valueToHex(p[2])}` : null
- }
-
- const invertColor = c => {
- // Support only hex color
- if (c.charAt(0) != '#') return c
- c = c.substring(1)
- // Ensure it's in long form
- if (c.length == 3) c = c.charAt(0) + c.charAt(0) + c.charAt(1) + c.charAt(1) + c.charAt(2) + c.charAt(2)
- return `#${`000000${(parseInt(c, 16) ^ 0xffffff).toString(16)}`.slice(-6)}`
- }*/
-
- const pagodaBoxError = () => {
- if (document.title === 'Pagoda Box' && (document.body.innerHTML.match('All Routes' + ' Down.') || document.body.innerHTML.match('There appears to be an error' + ' with this site.'))) {
- GM_addStyle('body {background: #755 !important}' + '')
- div = document.createElement('div')
- div.innerHTML = 'ANBT speaking:
' + 'Meanwhile, you can visit the chat: ' + 'http://chat.grompe.org.ru/#drawception
' + 'Or use the new sandbox: http://grompe.org.ru/drawit/'
- document.body.appendChild(div)
- }
- }
-
- const pageEnhancements = () => {
- const loc = document.location.href
- loadScriptSettings()
-
- if (typeof DrawceptionPlay === 'undefined') return // Firefox Greasemonkey seems to call pageEnhancements() after document.write...
- if (document.getElementById('newcanvasyo')) return // Chrome, I'm looking at you too...
-
- //__DEBUG__ = document.getElementById('_debug_')
- //prestoOpera = navigator.userAgent.match(/\bPresto\b/)
-
- // Stop tracking me! Best to block
- // api.mixpanel.com and cdn.mxpnl.com
- if (typeof mixpanel !== 'undefined')
- mixpanel = {
- track: () => {},
- identify: () => {}
- }
-
- try {
- const tmpuserlink = $('.player-dropdown a[href^="/player/"]')
- username = tmpuserlink.querySelector('strong').textContent
- userid = tmpuserlink.href.match(/\/player\/(\d+)\//)[1]
- localStorage.setItem('gpe_lastSeenName', username)
- localStorage.setItem('gpe_lastSeenId', userid)
- } catch (e) {}
-
- const insandbox = loc.match(/drawception\.com\/sandbox\/#?(.*)/)
- const inplay = loc.match(/drawception\.com\/(:?contests\/)?play\/(.*)/)
- if (options.newCanvas) {
- const hasCanvas = document.getElementById('canvas-holder')
- // If created a friend game, the link won't present playable canvas
- const hasCanvasOrGameForm = $('.playtimer')
- const captioncontest = loc.match(/contests\/play\//) && !hasCanvas
- if (!captioncontest && (insandbox || (inplay && hasCanvasOrGameForm)) /* || __DEBUG__*/) {
- setTimeout(() => {
- setupNewCanvas(insandbox, loc, document.body.innerHTML)
- }, 1)
- return
- }
- }
- /*else {
- if (insandbox || inplay || __DEBUG__) {
- enhanceCanvas(insandbox)
- }
- if (inplay || __DEBUG__) {
- empowerPlay()
- }
- }*/
- if (loc.match(/drawception\.com\/game\//)) {
- betterGame()
- }
- if (loc.match(/drawception\.com\/panel\//)) {
- betterPanel()
- }
- if (loc.match(/drawception\.com\/player\//)) {
- betterPlayer()
- }
- if (loc.match(/drawception\.com\/forums\//)) {
- betterForum()
- }
- if (loc.match(/drawception\.com\/settings\//)) {
- addScriptSettings()
- }
- if (loc.match(/drawception\.com\/create/)) {
- betterCreateGame()
- }
- GM_addStyle('.panel-user {width: auto} .panel-details img.loading {display: none}' + '.gpe-wide, .gpe-wide-block {display: none}' + '.gpe-btn {padding: 5px 8px; height: 28px}' + '.gpe-spacer {margin-right: 7px; float:left}' + '@media (min-width:992px) {.navbar-toggle,.btn-menu-player {display: none} .gpe-wide {display: inline} .gpe-wide-block {display: block}}' + '@media (min-width:1200px) {.gpe-btn {padding: 5px 16px;} .gpe-spacer {margin-right: 20px;} .panel-number {left: -30px}}' + '#anbtver {font-size: 10px; position:absolute; opacity:0.3; right:10px; top: 0;}' + '.anbt_paneldel {position:absolute; padding:1px 6px; color:#FFF; background:#d9534f; text-decoration: none !important; right: 18px; border-radius: 5px}' + '.anbt_paneldel:hover {background:#d2322d}' + '.anbt_favpanel {top: 20px; font-weight: normal; padding: 0 2px}' + '.anbt_favpanel:hover {color: #d9534f; cursor:pointer}' + '.anbt_favedpanel {color: #d9534f; border-color: #d9534f}' + '.anbt_replaypanel {top: 55px; font-weight: normal; padding: 0 8px}' + '.anbt_replaypanel:hover {color: #8af; text-decoration: none}' + ".anbt_owncaption:before {content: ''; display: inline-block; background: #5C5; border: 1px solid #080; width: 10px; height: 10px; border-radius: 10px; margin-right: 10px;}" + '.gamepanel, .thumbpanel, .comment-body {word-wrap: break-word}' + '.comment-body img {max-width: 100%}' + '.forum-thread.anbt_hidden {display: none}' + '.anbt_showt .forum-thread.anbt_hidden {display: block; opacity: 0.6}' + ".anbt_unhidet:after {content: ' threads hidden. Show'}" + ".anbt_showt .anbt_unhidet:after {content: ' threads hidden. Hide'}" + ".anbt_hft:after {content: '[hide]'}" + '.anbt_hft, .anbt_unhidet {padding-left: 0.4em; cursor:pointer}' + ".forum-thread.anbt_hidden .anbt_hft:after {content: '[show]'}" + '.anbt_threadtitle {margin: 0 0 10px}' + '.avatar {box-sizing: content-box}' + '.pagination {margin: 0px}' + '#nav-drag {position: fixed; width: 100%; z-index: 2000}' + '#header-bar-container {position: relative; width: 100%; top: 6rem}' + '.wrapper {position: relative; top: 6rem}' + 'footer {position: relative; top: 6rem}' + '.option span:first-child {display: flex; flex-direction: row; justify-content: space-between}' + '.grid-settings div[class^="grid-"] label {display: inline-flex}' + 'input[type="checkbox"], input[type="radio"] {margin:4px 4px 0 0}' + '@-moz-document url-prefix() {input[type="checkbox"], input[type="radio"] {margin:0 4px 0 0}}' + '.tooltip {z-index: 3000;}')
- if (options.maxCommentHeight) {
- const h = options.maxCommentHeight
- GM_addStyle(`.comment-holder[id]:not(:target) .comment-body {overflow-y: hidden; max-height: ${h}px; position:relative}.comment-holder[id]:not(:target) .comment-body:before{content: 'Click to read more'; position:absolute; width:100%; height:50px; left:0; top:${h - 50}px;text-align: center; font-weight: bold; color: #fff; text-shadow: 0 0 2px #000; padding-top: 20px; background:linear-gradient(transparent, rgba(0,0,0,0.4))}`)
- $('.comment-body', true).forEach(x =>
- x.addEventListener('click', () => {
- if (x.clientHeight > h - 50 && location.hash.indexOf(x) === -1) location.hash = `#${x.parentNode.parentNode.id}`
- })
- )
- }
- if (options.useOldFontSize) {
- document.body.style.fontSize = '15px'
- }
- if (options.useOldFont) {
- const nunito = $("link[href*='Nunito']")
- nunito.parentNode.removeChild(nunito)
- GM_addStyle("@font-face { font-family: 'Nunito'; font-style: normal; font-weight: 400; src: local('Nunito Regular'), local('Nunito-Regular'), " + 'url(data:application/font-woff;base64,d09GRgABAAAAAGvAABAAAAAAwoAAAQABAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABbAAAABwAAAAcXbjOsU9TLzIAAAGIAAAAWAAAAGDoQJh8Y21hcAAAAeAAAAJ5AAADvh6qDHtjdnQgAAAEXAAAABgAAAAYCP4CUWZwZ20AAAR0AAAA/gAAAXMGWJw2Z2FzcAAABXQAAAAMAAAADAAGABtnbHlmAAAFgAAAVjsAAJ1IqxQ0WWhlYWQAAFu8AAAAMQAAADYb/IVPaGhlYQAAW/AAAAAgAAAAJBBBBthobXR4AABcEAAAAtEAAASE7f1j82tlcm4AAF7kAAAFDgAACxZBlD5xbG9jYQAAY/QAAAJDAAACRKip00ptYXhwAABmOAAAACAAAAAgAzkCem5hbWUAAGZYAAAC2AAAB8v3y3ULcG9zdAAAaTAAAAIwAAADx6eKLpZwcmVwAABrYAAAAF4AAABlSqWTuQAAAAEAAAAAyYlvMQAAAADJ8sIWAAAAAMo8nWl4AWNgZslmnMDAysAgel5EmYGBqRVCc+9jSGNiAPIZWJmZQRRzAwPD+wAGBW8GKMhLLS9hcGBQ+M3E/u5vLAMD+zumxQoMDIwgORYB1nlASoGBEQDPrQ8weAG0zcErRFEUx/Fz7p15htI0ZhRjTPcdmY0SO8YGWdjMwthrRuQPYGFjFv4DoixtlaWUspBE1MhGKbnvmilKynZqeu+4PbJAdr51O/0Wtw8AyM+XAQQbHtiF4Y7gjr3zMA5RIKgA4zBO4iyWcRUruCl6xIW4FA8yLhMyJ7fknjyWJyql0iqrSOXUkMqrKbWi9t2kS27OHSRBDsWpgzopTVkaoGkq0WL/VYObghkAFOxaYwKLWLLGmjVAnFvj7puRVF0qo1RojP5qJKzR/WUshAYyc51PeYPXeZmXeIYLnA+qQV9AQcqv+zX/2i/7BX/MHzFPpm5q5tFoc2uq5sxsmzmv4b14z57x2vWbhx7oQDd1Q7/qG32kD++LsazTCwj/nyPawIbwQ0MQEGbv3338lBCBKDjQAjFofScIHg4cAAAAgOV9tm3bqG2by3TuJmbMmjNvwaIly1asWrNuw6Yt23bs2rPvwKEjx06cOnPuwqUr127cunPvwaMnz168evPuw6cv3378+vMvICgkLCIqJi4hKSUtIysnr6CopKyiqqauoamlraOrp29gaGSMybQguGgJAwADAPq+NWOw7bCu/7ZgmBhgoQcLuzCxwO7CTlBQEPwjinlQbH1PmQpVGrXp1qdXv0EDhowYM2rchCmTps2YNW/OgiWL1qxatxEhw1//JMRTOXqkSYo3siTGF+Xa46PM+Brf/Jcdb+N9vHMZnyTLd2HYikJ/pMYHe/HZuRQF8cxvRUq12rbjyrV7D27cWo7vNu3Gq3gdL+Jl/Ixf8USuuxDPlahWrEalOvUa1GrWEj806dSlw5Z9p9IdOnIsz5kTB4+syM6dAAAAACoAoADSAQQAAwAk/oQAPgPpABcFkgA0eAFdjr9OwzAQh8+kQHgDJAvJlhWGylV3pgxOJJQlEAbfwh+plQjvgJSF5Qae5djMlhdDcE1Dhy6+u+9On38JwDcJ8jZ+KfWJSf1+JAhX35BD9vS4SqC8MVUfWD3LcOIFLK10mTc1Z0V9Hx0aMnS7IVOb15cNL4qpymJLuDYMXezlfYiWS9SHdot4I57FzrOYPIRieJsNUie0/pGjU98Yzq7beBd5CJrLgNpaU/HYRh6DtohydXZIKvW9v5wzn3tZLaXJ95YucqkZkGg/OcsDkSaH/3OC8QgoOAblDBJMxqyokhraaTU4q3fAWWclJwb5+8I3XawkqcXVHyIka+IAAAABAAI' + 'ABgAK//8AD3gBnLwJeBzVlS9+by3qllq9L9Vr9b5Lvaq71Wrt+25LtmRLsmzJ2i0ZYxuMwTZeYhP2AIawJiaQDE4YQsZhMXuGASeEJMN//gkzmcnLNi+ZwExmvjDAhNhqvXurulottfX4vsf3qer06aXOds/5nXOvAQT4DABCQX8fqEElCIOLALRtvwjMYdNLwAzK6kdyjDLMKANU/chLAADy44vA94tI1B1jCa1GRjgdISJRVU+QVR58iyO2BZIyEvO98IyjyqlSOascTv4+CxlP1GAIu3Q2qLJgllkF/0nNejRaL6tWs16tGt2powRNGr0mqdTkN5dcedAStMjl6AKQzIfIN4mj9CWgBUEQBccuAlVYj66+sD4nLovFZQvkF2OGGDMiUbhWSuh0eLxX5T0HVWa3Wu00K1kqYND7qew3kMAutdplVlqpgF4foOhFgiY0Vm1ZmZbVlmaf8qH/4EgxDwAs9+zKP1Jz9EXQBwbASWRrOnwRdIZzItqwiLYCmSswowIzXgFeANF3qOBFMKC4CPp/8RJ6DZEXJO+hV4ijRnf8jgbdvehuzt3jOX4m97ladIfo3voesoOTUxQpnlJzt2QGrhL1MB7Tac1QRMYLaXTXlAThKiH8BPqYk3j1j3V0xMTGYfqwx+v13O2+Cd/uSdFRCxuDiT8KxILH6/Eedy/i28k6OmxGzHN/dP8RvpaddDn9XjENb4taLBFIcNcjbqfPQ4mp7KMFJH4nm+Wuky7ELKMJFySQnSEYXmmkvlriArvBDDh6EYTCenTdlY+OGDZsrMDSY5gxBiiO8R56rXgJaACB7BtDVBuiXgYsugOlKo15F0HgvZfBZvQbGsSJROkQ6Q1BPoAYFtmmHi2HEOUNkZiXQgZF5rJAlmRYiKzmLPGgt5wOGVo8LMGwNF5DIvwGsiQRTe7ZPezwOKWMTSNXeTePLTXXLG2NB7umDxyt7bhuS6jj+LfnPAzjDo6NbnV5XaGgWFlmHxob98fmBqts1d3+1rN33ryruvfMi0tehnH5CIXOKJUlzCqnUVEi1avLjfG+qkhHwudyaPVNI4f6hu+YrRf3sVbW2keUynVSedLiTECKEKtkpdpgazjYFHPL9f5o/fYbBse/fE2TeNxitVgBDS6uvCbaQ18AauABNaAf2XsIoLhDEW0ToprBpmUKbN2GGW2AwlG9CUCQQVH9CihDVJSLby+yOOBiuw1RI4hCkZozVc6whJsPSI0I5qIvmSLXpSK47jWz7icIY7jJr1L5m8LhZnxvJj6V2pUGT9mVzyQWuTFI0uzuW7e6Yzu+MLj19GgE3amGqS9ucUdXGQPhZp9K5WsO536Jlvm7pmtqprv8wv0mRu02q9R/OatSuE0iuZi+sev6ezu2PbBUn1l8YAzflw/znL2I82WOc8v6HwEkGFn5N/pp+vegGcXcNBhANiYF+1qxOa2AyttXjxl63r5xZNUJzr51iGrhqGFE+TlLW5F9+3j7Yntie4lkpIiLUWw4TxiZV7BfKkQKCZKLVlhP0jKSt2gyBXEc15PYsDisqd+Lwxa1h1VRIp0j7jqtkKmtfp3ar/zi8O/uO/D/ndtZO3tLj6+nxtl24N6envsOdlT0zKThHIOMtXyDZ2wgmRw91Dh7rjtLmYIps6054bCE6qz2uoiFHLZZyvVOnVweOXzyVPXdSrdK57eq5Zqzo1OpvV9b3HR8z0jAu2V0d6J3X7fL0bHUVbe0e5sveyY4s7Bnh6Zp07CvZb7DvbmVfMjW1tJgNGca2jyOmF0ht8UAlzt+TL4JH+RqizFXWa5SQtRXKRc/ydcGlgrq9f6r1gb+GQ+tKAiG/hlwAgnypR35Uhrmsghn6bwzStBFxehy3oA7A50Jqy3Z6ZdFTSqHUSFq6elqESkMDpUx' + '+szuty9dmp599513Zpw2qd6hUWtezt7+4t9k73lZpdE49FIbfu7iigJ+mH8ug55L4ucKXk4lVYkqwptTTYcyGX40dMljRpXdoBA1d/eg55kcKlNE5u9M2qyJzmfw0+zoaRfhtc89Dw+9wj1NZnPOvPPDH85Of//SW/i5x4nL5F30OVANmrBNGa5ay/OWDWLLBgtyRBwz4pjxMnABFpDBlwEEInRHsZriKo/Ty+dSLkxFuTTQAEVcNogzXg+fdK0QmZP7hoi4/qcWr9fy/jU05bYqbaXzs6V2Jespu+anZp/X8g/XlHktKqtkbqHUrrJ4SqlbRR6LySu6IFaL9X6l4uWXFUq/Xq24IPKaLB7RBYXK6Fcp3nhDqYB+o0rB+/UeQFL3kx8i+zaAtVVdnNdNhhkyfn3i74i5tShWoFBDlQdwtRtpaee1tCt55yeUduwipJNdySmmJX4Pt7tiMVf2vJSxqlzR7DdVVkYadcFtUZczRnRGnI5o9jkly0gjTtgrZVilMwL7ndGok5d1bEUPL4H/BCSQIlmJMPIICOtRNDjVduh6Zx6Sf4DvAwjc8AVimtgPlOhzr4BSQCCKQn5QC/LE+AA9o3Ea5Sk/PO5PyY1ODXxBbnCofcmkT+0wyAEET68sw1dAFqiBUbCNHJtCzoNKGpAoEaW4yFvN3E+rXTGrNeZSC/ebDSGXVusKGYz8ndNl5dOVaxEe/CZggH41Nwq/z69YRgjyZCqf7UpEj0qCBoVVLydI+HNJKEcOWc0SLasWKcT0XTaOFCvEHH7bsvLf1E30eWACKZDeECsHMCPAp2QzV80wkgggSoYorppRKHFSqBRRHEyIsei1jELyodf1FDGX2Vrr0ohEGlft1kzNkEAP1cx+9dBATKeLDRz66uzsuTxNfVjRP3/4VGPjqcPz/RWF9Oup3bc++cLExItP3DqVSk3d+sSLExMvPHnr7hQfAz8AgLTRXwFWAfkL4VmgjQEzDLw2MqSDlXMULBGs6cbrC1lTLRRbEm7R69V2g0yrh/MKl1Jf6dRCxh3W68NuHaQYmcLoUGn8sp+XiqHCHrFfnrKFrQqFNWyjGCTTHABUM/0gyhQtgkxqLIJ6VSYhYXBrqBpFMMutIXXe1kEsp2BrQpQHCfVkLrgokV2IMnvuLTrF1y+i293d0WySGSX+mM3j2zU1HZo8f6S9Zur02Uc6iRa9S19eji7Lio5Wt1MSiNek45qukxPV3sat1I9lOrNURKdcxoRG6zYpwjvObOt69LFH7z2TVppdapXLpGyLuDptZa5QvCqmab/ntmOxytZKBvviWyt/pMYQltoGtmPMWrsuRxqxysYCG4QxIyzkEQL0czYwIs3LkOZNJGhEoQ/H0QcRq5U3xmqFFrwnLAWMP1lSWHZ5MKtbRbNEEOa+Q9gzc70VgfbxeHRqqKFch6qLy9/59I5rX76lK9A5mWxb6vVtvfvVueDYjhGfwyo1uHS0pIRp6N5amZls81Rs2tvYpbNpJcEgmYSm6i3VVf0Jo0qrVJicKjYlY51V0/ftbFjcUi2hpPXjh9sWH94dkuhYjSxqxGUPwlKtWmpKbEpkxhvtcoNV6UhCvr9yrFyhHkTx7EPB0SVED4kNRRZYzoQZJt5yOJ9pOctpUea1owxcyqF79DUFDjGyAB0pBVMFYd5QiVz4MHYlkfAvtbiaY+yNjIORSNDlJp2zgmEqnAxc/qdMS1n5j+BbtLE7rQm2Rq58rDDaVUq7UfG80Ng+3xRWetUE8SG/Nh9c+d/UfvoxBJU7AG5tN9LGghkWYS0QQM1pg6WXc2vBgqgQ5341l62FsCcF1xe4PMl5HAoedwqLB/n9r5uaiW/p7DqJBF2Wv1XS9MTk5LkD9Zvv/NtrO84cGDXLJGG7wq4IfnVn+0K7y' + '94wmg73ZHzlihaXxmNR0e6GaoXJrlLZTYpsurkFtzB7/+ZYqyGxOam0K5wxmby7u3JgX0vjUn+QcQU1Ti9q+7lef3DlA+oo/VVQBTpRRtiog3Nhhou3QgP6lpGzAu7epJwVXIhK8ItAgLdIYyfOxEw+KxBCBkZmgIINcn0D+ZmRQUhHLZU0HqnqP7glaSsnDT1je6pnn7qhsf30q4fmnjy6rdrAJHfc9trRzV/PXmqcbnNa6nY1te3pdHs7Junt5QHUDVhUFGMJdE4fuLkBRjtDTOMN5+f2XDjZGdl+5IFv7Zh9+9kHFuuclz3+vsXmhr2D4cqB/a11831BABHuB9QQigeLkKuLeyshOCjMYJDGEk5jtwyKeHwH7Tk0H+fhhYjoUzXYDREPI4f/snyrwW0oL0cXEna1yqTdXgdUWStMJhvlVJqdKHuZlc1V+oQFxycJNiG/HEd+8YIM2CR4RhgUbRCfPcgzlZxnypB0qXx8NvGeWddiaHOeEjoQErmhMDTXv4bH62e7/Ztuf3lx6ZXbN/u75+ru+0r/3W8fvuHtu/r9/fs7Ld62iXTNRJu3smtXNLqzq1JW2TudTE71Vlb2TiWT072VxP8SJ7bsbZi4d3cstvveicaFzUkp4Xz21omHFlKphYcmmveP1MlhdfVg0mRKDlZntiYMhsTW5Y7GsYzZnBlrzN0BH7d/oE7QL6Co6wJdOKOL87nci03iLca7nI0s6LuNnI3iOcTA98RJzkapgswMeQDhSPCDNsF2PJTwrO+Zf8bFr6akvKTtZHX3NQMJazlp7Nmxp3oOB/CZV2945P0zGSY5ftvrRwe+AWubhPBd7ELhO1UpCTJqjwWlJ4Mx0D1/063tEEY6QrqG678xu/CdEx0Lz//piws/evHR/Y1O6lNf357m+qWBUMXma1vqZlH0Yntw+I+CQA28q9iJxorTBejYiRlOPoJpnMO4WaMTUQYuF6vXAUTl5wDGojt5whDGyDGMEKRTq3WGlvXrISWaLyJs/BtyGcnKABfuWDTYd7pwkdS8gMViqRGIfkftiq8+Ou5SH8KgmjyWf1wYPz98+Xn4Ps73h4GWuo98G5i53qw0jJEX+mEuLadgUkCspZCFIq7t8X7P7XR5yEmZUmXRluuNyyLispGBAYdYKYZfVsRN5oQCLtIyxiLXuiTZt7LPS1xaNkZSfK28B/wDdZY0ACUyt4lD9pBD9nwFdP4Cl0iII24dzofrXv+ObzvIEWcMNyJXnlr7+h+kOlbpikRcSlYnhY/jPgT3ILgv4evcXcBB/RX5/wNLXm9TmMvSWNtVmFkK8wM2apfb4fJcOaeUqcxaic5I/GWZMugkGrNSoSQGkeKWKkX2gRIZw2LFYS3skbg0cgsjE2G9F1d+RZ6j/wBqwWZQgZ4oFbzai73ay3cjzVzYeX6B3kahV82Xz5Ji0ITnJQmtRif4vQ7W00I6Wh8Tfy8Rq1htuaei5+HOkXOH2+2pbn+oLWIkUJb1arU+q5pI9I70xDyNgxWKeF1zQogbIY5oQCpNTrW1plyjqBz/0mTD9HCfp7IuErJCmdhmYpwMRqaGg4ntA72DO6rTfSENWVJ2edTAB7rByAc+skFs5Xclevrf0Jo6Boa5OfQx3Mfo1+JtsbAI27lx3BEUEi6OUiPeIEftQ7wIR7WjoKlHsIlG9xncwOZSTwNCTzmLUDiKubKDLOnyEFylXe19CK/QonEFmEFmZrjGnZRBZOKCTE/lxk5ETOdPu9y9zfHydpKyRjKWyoHWlEdL0FKZ1a7VfePhJ7Ifvntd2+EnXn13Zvip+4+Nxn2tY3NLcWNVpaM0cltn+7X9fltmaPF4Z9fNztLSCqMpQN4lKWdM8alN0aG7X54Z/KuHb9mdnn7618cajhP73C0xi86f8X' + 'wg0ZbZk16tq27zyNjynygfo7aJInN/B40Xbn7/mdMjIUfb/F0Xlga/fHKh219u8BirUlUjh5pbbr1532C4sdlssUCrVSLNBpxpjd7UdeTx4VveOlHv7dt/9rmFxz54tE+F4zQKIL2IsKwTeEE32GhfQ4EZioLxnwgzRHwp8QACSLglzSKPuXgwIIyTvKSdLOyJORDEeKEd0tMixhMxuJsk88vH58obXPqImyFp+HVDLN3iD7SmY/qPs38m1NnPvqLRmIKswl8BJdlPKn0KNmAs00ooY/tIXKOtGmk1LKeJ7wMSPAsALUNYwQ5CILOKFUqwrCUbIPNoHiuYkPBOrg6WICoDCCHh0utbFw7euFcbFsMqlH1Wg0oL/GznuYON/u6Zup6bhsNVB58/ubxiCjs1kLiy5fi2ipqFs9v/7s+1S5vDsS1LGZo1hdBbyV2nN2UWh+vKKUntjsOdnXfta9M4wsYYU72ro2e8Sk1sy7YYUsN1zVujaoD715VfUb+nXwcx8AVcORTc3oMrrF9bO1Z1DmFGCOuMerbvIF/CcYHYj4hf8wSNbgpgQ38EfnEtIk7gF/izCu5LeOkJuxYhRLE5O6m4WTmTR70eZx4YCJkstyRDkJibee7P9429OWdnpQanTqX72rH5x5eqozMPznZ8fUJqkGjtqNcL/PL1sx9/e4L4wbPQ8PZCsFJWZVK7LEpxuvO275+4/s07+r3BElqB+l1rnWZ+6W2o4urN11AM3IZiQId8mRAioBwrX15gDR1m6PgkrOd0KUe6ODhdOO8qefRK6VRaDVFCOb2r3oYeUxRnuKgJTr8JbW/snHsz+/sLH/z21IvXJVpPv3nsNQ3qEqiHTRGndvKl7EfPPJP99PnxF7tuv3TzHT883YB9dwEA6hSSMbIaoxIskKRAQoAZgI9RF9JLz8WoBEnJcPICRLmL5BW6LuXVSJhAqVmndoZMxD8JGHz520SFwWMol2L6p8S8wEeIwUg9hjGMgMmzi3mqS6CQLueRjA1IF38R2rp618QiXVRYFy6OlHz0bCy8AMzPo4piJC7kxf45IcnTn+B9Xtxd0EZz1KnJi3kADUNUakQtZ21Rm0KBLhwWwLWZnkJrp1Wwv7CdIci8GjKczDVI5lZOZj3u1oV4ETo9VD2UKLRlZL7cFK4EYQ9OWAvKPIimiURFSyy077r9kSezn742591845M/PnrDv4ygZWF06UpkIv/o6Db38e/ur4os/fXRtrua/6C1oTE/uhCfpBPZQFOnWMaoykZfgqa/nf/eU7ftTgbcsqgZt38EUaaWiwfvu3T9F398e7tGAc/I9Wj6xeplSP9nAEF3oB4vDAYE/X1YXR/Wv9iJxSWgqOPSIQuFuXktFOBI3nVK+yqZf9NO1aDkb8ReE7y3fEKghDtxgjbZInbOc5fnBR/CK1lKoKmHhPez1bxvXwIEfJt+HGjR6vh8VVDsFcn7EhKsQAw3Q1uFx6EZYgRR6MI9q2XlN+SPUOy7URU5KiCbz3mikGWK7OT1FHZcyQTxhmCGvtPfnqw/tDBkNuGdH6Vd6j68bd91NCvIcuUrJ547UGVJD6ddTq3TKJMp+sa/9DCS70UAqF8j+cKgA6wVBElWNPArGnquVYazlrvYk6ubeqVwNeYhROKHDQY0i2Xc3J0hSjUJM5rS6vTZGEHIJFg9S0qz/JPjtjBSxBqxUY/bIlaOypYQDaxRyfr1dkfWufyS2q00VtrVJhtxP4C4zlNTKH7NSM7Pz59ClrGvi8B8WkyaEFwRopFoRulQKkUXrStipr6cd/2zKlRqcAECAPC2FVmQbavBAsBroXhitAH4UGKGctW+QpvOMSzcbJnMYRCGo2KIsnPtXymCT+vWFpSRnLmLlhgDyf+ADzChqjqvpy1hVdv8Wq3' + 'Xps62ldkDYX1oizbbrrb5uH7Ammz3eusTIQbeDdvJB9I9lSp91WDN5W8LI0PKd0VkDljkqQz535d/mecO1gxW6dWVvekre3mbPAkAPc/VgrEN1p6wWVIcgNRVq4U4N3VHfSOiLPyOUG6ZQGXhElprhScZX9zi6bESr2jsQZ0uYNfofQmLu8e23KXNMaisJ+PXerxXlOS75qBZLrMEzZcPejI+ndtHfnilBiksk6ELIMA+VC9+Rr/OzRQSYO2GRdlVZgpYY1wjDHiywK/2dTMkukqVdMVX4QUuHPD28PQji4uPTEfC048uLj46Fc7+bvRZSJz/JiSeHRl5Npv95vls9tlR4ieH3z27ZcvZdw/f8O79W7fe/+4N56H20t69l7L/fv589j8wBTUcFnp2ZYX6DPnDXFidVVhMVXGEChP+3K69Csnu5WQXrLoeZHjziEgJXxVyldYdNcMHrn334dHxcz89VN52w7ZYdOhg8ydEWzaTT9oPYwAVmn3i+hu+Plt5UZ/e1d4+Xq3PMoC3dYkY2dqHO+fPRxTFUYTTmzCKDXEUvdpbr5od4/nV9pp2yiDnBPc6R+3LeQA+s92WGYy9IOzL6LcvXDPeUBLpcnE+gab1viN+wnll8a3sH89vfeiW68LcXNphUkJIEgSEknLspvPrXMnPTL4LCBoiv6VBO+jesIupwoyqAhvYMcPOO7ISEKAGO5JLJK3FMAs3M6jSMDpmdTRPFwAuYTCNWN/lsO6bM6/cs83dc3BTz+46ViwqoygSZ3am0m2gJDK1LT3SnP33XM5n4K/qb55trN6+FM/+D23CUNi25e5ravdsrZVTkkjfnpbaRX/EV86GrAqZucKy+PjB7oAyWyqkf+IZaWh7b89wRXm2E0Cwd+UX1DsoJjaBJMAZJKdvGuub5g+uUUjfCk5feb6NSyOqJ7/8mIJ9J0/xthNCaatsoY7loBu8pWnpzu5dXz/cNnj/e8d3PX3XHlasMFjlSqfStmXqYGPjNQOh5qXbO03o4IL2xS33XbrukY+2S8vKdE6D2WnqHN6dTCwMJahE7eZ0UGdpnbxl5/S5fRkbmpzI1SqPVaOTaP02jT7aHW/emvEzpUarXT7284kHF1IjIzKrSuli1Sw+q6it7ODyrA6t6/tRfDhAd/E8fIOCKOwfc+FSlt/ClCBKy0eHAEuvgr6Vx4xeVBSNHiP5N2jOgMqj15D9joCTqJ/iXUd8BEkokZefsUURLLOjtb4F9wgrv6Gb0YwhCGo3WtFCT77K8GCGZ3VFF0I1YZEqi8DbecbN1/HU6MHauoOjKaGu73z8H2+88f3Hx2mzkIau/OPQkQGvd+DIEOnP8/7+9Ft4U/ut04A7KQZoPbKzU5C7+PRkkSLCVIuTG/CzkLiAkWRQBIXjqvlgI85T8EZpi89Q4dBAgswekgfT7QF/a3VQkT1QgvseX5P0PepAMKJiA/pSVdnlpyItPpXC1xKjtqrUhgqbOhzg4sK1ckX0KX0OrYlDG+1pC6i9bD38KK4HxYlmA4BShSgnD1CKtRMwCyYEoCh8iirN/kjsq25yWDMxT2n255TeHdG760phGawTO8PVFkt1xCWGXVBU2uBmKl06KvuzUl+iwWarq/KUUk9d/i9XyqtRudJear9ciUZESn/o8l9RLlfSpVKhy+VfUsORoMLiNyrkl7/oSXs1am/ay2OVRrSGfs/14B3FtiqOyeKNr8Kzszw2lkEvv/9VukZ9uDpT163CYyeTtjBBu5qB57LHtDoUpbZaBvbCIabGwgTsakl59nr4kBbXVTatyz5a72ChkvXqbDaimpCarUwAATdn1gL/1ckqLR6d3KZY/q/ln7CsPmBTWxxECdJxC9LxA4STPSAp6KjFAmuxSkWjviL3ryn9MAS9AvCKFyhF' + '2oXSn+0Xl0C9L2Z01CrhCAV3KKptTIVDWyImurMpISHAt4gLMmO5PsAq7e7lZ4jtTlaGml2JUZrzCwDUCeQXD0gX+6UoNfBD4lJuNOxBlJnbS4hvsA0J86nte/aITW4kfr18KL8ZOZ6ol8qWzcSXBY6K9Wn9bsrCTRGcZmV9hcanufzbgtnH0ytOYjM3b/QVV+lXkMgQmPI1WAFgLodlYH6DXymYkTPy07jh+TVq7yUSdNm/H1OB4K/1flZJhxkfq5LxPbz8L/8s07MKW4JQsj6GP5v0ycpTxFH6l0DL7W+IwhjoRaJkPhBXY48uwaMAY0gCf05jSl9ZRl+jkqstGonZ+pcDKqmK1UhMViT8DNKvTNBv3ZJA+uFRQokwOs3pR3Nq8XsoGSjMOnIqE2WcgsHAqnqY4hTch/RTEgkbHlHQHjlST2HVy1SCfuB1wk5N0ncBK5AjWagwLmi4neWSDj9frocpyE8hCxpR4p7s96VurZxlZJCg4YwyaWWTSjhFkzIdK9d4ZdQPlm8zogpsUoqVpcSrNofdvtxaqhQrTBqJ1sA9G6xAcmXlJJByZ9NEiCPlOhGGPwWYO0NXy6L/yDNW9N+KT6/34T9e9hg1BP+zpByo0fdwA8jv0nK7boJ71NxPOLz9cqkGtWoqp+yKhGUYPT1fbkFSsmqlJntJqdTZNIAA9SsfkxfIT0ANQkQH0S+WrzsFvbrPWYkZlQUJy4EZDmGsxR+L5jfxaQDxcZ6PQDk/Gn5TIA5wBPot9KFuzslQOLSxfqtKmUvsCf4uKCdylARg/hx6PZki3rdUdVXEBjvqWblcZlBLRKLID7+EjiXXQbXVq8EDLKhtG5mOdx4bq9p09r2TmowOihmDoazh5pkGNt7uS4y1egnikXhrQCXRGGQlErVBKlFKOpt82+6YWv6VEYEUDNN7XF1Rg6/32syOkwMuCL8AZf6eWrYxoIXQ1bGjDdny+MrH1DTCJhUo82zbaEoihL24eCgiMNyY4ebLfgxZiV8UtYjClYFcNzTha6IQo2aiRL3+kME0qbX5NAgXqjX2ANewGvvGZuKzjy0k43OPzi292AhpU+PiQPfOpMaQmezqnm0wz+DRBepZzdQbpoBJJjP5zVk5tsDmO17fveONs9tnd0KD1QAfGz4xk27feyaVOTldm5o4iGN0EMXUgyimKsE2vJ8g5fYT7GH9Rjvofszw5/cTpHysvMcRfMul4qzgF7LyKnzjAj0EC4eieMdOQOeDXWcu7kvuH6/1OcvKq6bDDQs9flvbQnfkYHW5xOFrmjmS3vfCiXb4yfT37tqk9lS7rFFSa4hsP9GcODqRMRnIiNVVE2A23fG3uJcaWvmIyuT8OwY2wDwCON7Yv0LbnD9tWclpp0JUivdx/qhWlQfFPyw8KsHkHb/+tASVQatdpw3YdQSEzd9ZnHtkriq58NhsfHas18g5PmjXZMu6JjMGTXJn98CeBqOpfuZa5GKZ1OQzlklMZZLxie1n39i5+/U7NhuiXS74J7Mfuz5gygZqp09m0mf2tqdnTg33HZxIcfZA8R5FfnaDCBgGR3Hy0K/tHwUj5NMJxTdYEETyyUKEkwUNbCg1RNAfgVxuR+wgnx7wgWIWrvoVz8YL7SHi2yoRFXW6lreVfu30wD09KtQfi8S28aWDyb2v3rGp++Tzh49894a6n1CetqnGml1tAYrQmvz3Ph7ylPqMEoPEX+NSdt72zuLYq3eO9J963htZ6vMGNu+pwLFsRYr+lr7AnYm56pizaOoBQYjTDSiQQdD2cij3b5yMSCkfgGunIMK/XVrfLXJbXhbIq+yEPxBGT4sBvz+w6O3Z2xEY9puNpUqj0ujRBOKm0rvxO+TWZSsap8lk6EL8JmQxh7bP3rXNWy4RBwxys04qYmpm+' + 's0hsyWE/TeQbaeqkf/UoA8cxSu1SfCfMIASr9/zE1/1kG1hC12CGU6+CAhzK+xhEXpME3Civzj6I8f5nrpzTREQwplZ62MmsWZW6cmdlBc6bnKbqX6ut3syo/e17UwkJzuD0NQ7OhVbfGJvKrn4lbnU3NgmK6lhXWo8tez94sW9Dz8XkAVYqdycbuwNt+ztD8KP+m+cyVRP3dKy88RQIDh0/J8jnSGm+9R3902/+aVBTbgvOKyzMxKZ2W++csuN31wIt3cyGjZUUm7USPWpsVa+Nt8GAOVA+SEJBsDntKLijfdCopgR5RkebMe1JrrKBsj6SS5ZbUt2+hI72nxC2Ah3VdvofLL9+GSaY/jtGuLG9NZqk6NtR3vWzk0pLSjjv24K5JY9cG9KmivG751e/ovwLoqb65Cyt9PfAErgBXGkKVmEGYohAn++UwpIflEXurd4mwfe3l/Hxt1arbuKZeMu7QoQFNByd5uGTkQbMADEcA/dsz5hknxlBVMyS4WFm3+t/Dh7HzyLZGVBDKUXPO3DCXltDAunRjAKzU/7yBwCxSuUO9G0dkqgFmQVlDimazo0WVEjk7GWUNJSKgis43Vwa4W7dPKWrR6zkjbKGV+ZqzVNflUQHX4vp42gFY6p+wAg/wPFlNBbrk79ixFFcUIqxm5C9tlg46Vk7c7LUc7efhsKoACD4wXeofPqtB5WJZFln4M3lZfgzQB9QENosxOWCqQHulDPmXnKvByC8xqd3OhQKyzl2X/NTknNUo3LJDcy3Hq5HV2uR7r9v++v3V4UF37Bmpd7CgIBgjsAKPkRynWj4BhYu9BWzdaNGd0FjEbMaESM4m5xo9U7hBlDPKM7nwUbEWXacB1vtLIZjc4MtbmZx/pFTv/GluzwRMY6g8JatqPXVTtafdrca8zX+tAah+r2kblEcnaoWe3YsmMq1n7zRLV2TQJgm+d7skFhiRNiPimMtmdZDA8wDCQlOCmgYZ0R6s0m6O5PmE3Vw7WN25L6yvF7ppc/Ez4o5EFk63weFPxanPbERWlvfVRzDIUCm70Q+TG8Xf6vdrxNsAwsynvrEyR5hFPP5DX1I9WElFdsD6vAw/VzE8I/80hPYS+nSNOifzJkADC3ieBEVPEhzNQ66L6p8dTbZ868/YXGxi/g+6nG/7G2LHR3L7RYhTv87x1v3Ds8fO8bO8Zew/fXxjJn5urr585kMmfm6+vnz+C+JHuKmkZyBkC9gFuFJkOQc2PBizdGcIXnRuORvDY1fGznXCLA1+KALmpNFky9Y3NJ1ITEU3senYlPj/aZhR6FQ7M+u46Elsa57u7JtE5XPdE9sFBnIKv8vXHD8H1vTEy8fudmQ6zHnW0SShZ1O6rRMrznmt3bfng60zh/OpE6tdCcmDzCn3HOnqZSyBYChi88sSBe/2/vxetHW9T60SxnC59C6NPYfJ8Ga2GyCo0R1sXoWmCjXod7yAEoavPhRk2IS1Pf6HR85tE9KdyoJefH+3SGuoWB7olqnS492d0912ghq6CBNcJoFIOTy4eFZg2+5u6JGTbf+frExBv3DRvivdn7h49OJpoXvpBMnJ5vzEwfzmMW4je8PTaKYKFfEV91m1m1vikT0hYUYmHdotRyacmmhZA5tRflE6nU5DfV7GpxCymJPLKaaqx6OLRPaXRw213cCmxEamJPm3n5F1Cv+Q6SvxnMYwRbnUewESxj5Krh/ArOyrjBDqK+Yy96cQz9Efjo2jOIwD2nPKcUx3JzrAhi1ed6EpZiCg/6I2gghLUH7XwlCptTT647hW2u+q27FxO79rbf9OT41gcPtKARfeuOa5t8vRlXQ7rl5PVTHf7G/Y+M7rxzPFRhkzAS3/VDkU0pK/Fv1oBVp2NV5sOj3UcH/eZIo8vsMbqMSnfa62pQqs' + '1WX932+rq9nQ5zZdpittIljFnKViENHSsfEz+jt6DY3A4wKFi7vyNef75BfJUBBPp0vv12I0rPUSDfn5m4Na/TKoX/uYKwn4Jfr+ty4r9VE1qbR+2qftgf8AceprWVvjK9XlviCXgb+n3tS93eScQPkB9Aqc6pL68IZ/8UZ9lYdqJjd52JIImY1ebTl7q23DoFP4ohMMXFL8rBDvKDYsxdVFo2xtxCyK+vNat9+Pqhi6BlKs+hHFy5xcVG0z46V9V+YjItNN2o2Hhjo61BSkhtuabba+px9yZMlTvv2UWUCYVl+aMEKjbWhi2N8C8FNTUJAPkp0tOB8ssGy1LIz0UpnSs9On7/qHhTpWBDifit0hPJeDw1YY8q+6EIi2tPKqAYrMirHVok+P/p7E3g4yiu/PGqPmYkjTT3pbnv0YxmNCONNLovy7oPW7Iky4d8cvg2hzEYAwZjbgjLckMggSyYJUBCEjDLtSH7TwJsACeEJGRJNh9YkkD4JwGzJMHW6Peqqnt6NJZCfj99PjNV8/p1q7r6VdXrd3wLc8Ijic6Y2RzrTHBPGcCl4NRGYnMj3LfjEa0zYis1E1SEboRUX4K2ptH+JdvK3gyWbnyxElsUTeTIex1VenZvcDwfQop5FsrCK0ZREFSslHkgBugKfvcHukh1rSM9VnlKwEZP2BRo0v7qQ+tAS9ug5b9+pW0MpBvUuVOOkdrKZDSg46NzO6qb/BWt/dxbGqO6MubWxeNzvdydHS3NnXPnQk/EW5JWy1yiv63C30RtCJMI8b+B/lBip5QFZkl9iK1J8u0r7kKmwyvGeGdedy90CmlwPkMeH87ZzIG4zZYy/s9HhriVINZY5xG2ALXaaq8x5XIGstLCosNh3OX2WqMeg9WRewM32M16Z8jsduWO5R50ey1Rt8FaiVfknrBBJGfY7HYgjFI50IDg3sKKX6iUNLQUlRSHKZUUOw5V1NWFa/BiHq5CS/zR3C0iDJ6Y1ZvVYR02lde7yas8L+S8uiYfrJdEMDX8GAS5WyNOnT8yt4L7VtivIxJpKTu5piqoc0XsJeYytmb0I8QfgTb7UTNaSvqUoHQ4KLkkgAo1P5sbpGR3ORhdquTdQ3xVAv7mrquMOnUVWk6VGySZiIkEt6W5Saed+/ybjX4/yToHp72Ru1lX6TP4G+vDxphpbg9tY+m8h3sAMI4Gab9qUkW4AyxQEhN5qGaS34Cw5IMfZN6TvGNIVo6jsuYBObUG5kixShwquj6rVWoPDzVrhlsFUQJlZfB1e3y0JajxNibkcNFEo1cTbBmN3x6NkuPZdCiYbjAKghby5kPpLPECkZz0YOd0Ha7PrMh6BZ3DazD4HDrB27iiHmfrpjpDWT/hGerLfdQx0x4s5QXR276xJ/fH/iFy7zfnvoybxNcl/5PIfDOLvP3dTF074OSRS/Fiixf8QPD1twtljxBczwR9+XXoyyHal12pYncl9CVZLuP5vAMLe2nLOylsdVnaY5DKBmEcUI3ImcWtWF4ObLK2o4UuzPc7afOd6RCACmgxzxka6kLQR2a3qSwahZ5tDdCeZW2mPRtohZ4lx8vAh5Yd6sfGno3tXhHOVQfb1nXC2jJEetifDXVO1eVerV/RSPrXZzB4Sf9mV2RyP6qb7gzKT4HKO+4Trua/J+5GIRRFJF1eRqvxQbKQ6jiUcKMmStGCrdJOUmHA3irPk2wcBgMQcM9gk9gY5bVmV3mFV28Lc4aZ0XB/T1ulLWSwBmxh3rx2MD66vFWEtd1qDNrFsuEJp8/psPu8lSWa4VGn1wkNmJ/HmtyNXEBYZehHAjIKq7rQdzl4CEQfWWBKZ0o2omniPNU+GJQXHSezud/yz4glsOZMEQt0KfU1NOe1wApyhYqCcd1ACA1sXFfAhcTjpGTaHhy' + 'FWoTV4Fg79IRpIRoSm1+LPQ4yEg2WEJHacQ0/u2zfV2bjDkcsuXFFXakRcIz41rMz3XtXpeJj5/TVX9gplOorjWWG6C1rCNcZD5zTjv9323eun9H80B/wB34g2EMpl9Zl02FDZWzy8JqJy2dq7FZM0vUdunRDyUsB+HupdPr6p2k/7AD//H8BTlc/2oOWCo9sJYTWgiWlhRBamEpMkghDdASE9NCP0C06aT0FPqilaa0Van1Swgb8M9JBAboUFZqwFyi+boYLUhSMn/flGr6XSJD87HOXnXfvmtGjQ05XLKFx6RrPaO4ZT2hxBzua+x43SVILyuHr1F7wyJWXQ7L6au6VRr8eZpbvn3XzupjDoU05PClBLNW5u7aN7G/0k0GRQ3IgEQFGMwadBo4n74EPofsFr2BHy9A0qpYQbRzwiaaYx7stxWz5o9AlzCHRw+Z9uLE8OkMnZrmOCnQLUzLksaPSSUmBBcAvMA8U4zptHrs8M11mKbOHSspWJRPV1SuNIRusZeOZw+PjV2bGIUGJHBpPxBPJybKSkF1jKV2duXzF0N7BcHhw79DQ3qFweGjvi5Hgana0bFXTtQN9VzetNNrIiROheCw8QQ6VWUtXNl/dO3Bt84R00ZlglHuzYXpPc/OeqYaGKVJOw1ICEyInPCveWyhPjURaGgvkqZMQOhmhyMlTnJxZ8o486Rjgl/s4o4ahLIEyIsHI1BTCyFjkipKp6Jec5A1yRY4kKdIdeDVO+LxeX+5l3ETLH8rxZbkfkd+4XiqDuW2lakxiD33tRrwObzQ0e8jrd0kJd6jKZo+eT75u89aAaxniC2+rstuABF/cRVpXha3KrfeF5l7h2gIebWXAUu7UspjLm+bfh/XrUYr1l1zSE6C8hDyLIgRMpnqxNe50yk0sckNZ9bjTCBfIi9/c9+Wa6MzT3pRrpK3fhdzSTyC31IS2UQvAWanTJgs2EKpo6PQE1MqgBox6oo1iNidIOgeGtU+B1cJM6ONYmS4FGi4qT6MRGcFBAXBQ0bT5iILmwXV5sjF7tK3f521Le+LdYzjtc1UFxFIxuS7h620KDe29Yu9QoA1St4ez3s5z7l6z6mtjPle1X1tes7MvOtoeSQ5u2AqZ86GO8aSgGt/UtuuOtcuv5O8zBqMpj6826tEaglVpbyAVcnMNJXGbp47TmDSudDjZXpfu2difWtnTYDLUtI+mR/eNRa22sgiwCHqDMdKeCNVGfcHqjqnW6hU9GR0vRM6fGNnd57cibv64cJTbLt5CbYNeaU0zwwdJaCfwS8l4W5gKz/mLfo+6a3xGo4+48/wGg78GHykiCEdNYJ8noV5LlRT/4Etoq8opPgVSmEKzKAPxJ8sljEYWwLGOPtgWgiqSH67L4Vc1/NJKs1+NUJgDi4vtednC9/6lnfT89Jan7z88m8nMHr7/6S1bnrrv8PpMZv3h+56a2zJ9908OXvzju6an7/rxxQd/cvc0X1ZeYnK2TqzzDt+4q6tz5w2j7vWrO1y2kvLkxmTDbF+senBzQ2L11tqZS+56fMOGJ+68dE1t7ZpL73xiw4bH77pkppZ75MIfkXjoH10oxUXnvir6zBCgX1F3xm1bt9y6ubbCUeW0hkWrzbts22D/zv6QHXHoKu513gnjIosG6PpggWeXhU9PiuGuiO9AHcoYlL7jcAzqje8sjGeJFISz8DI+3cJwFgtLDWaRLAetVU2BSEdDylZWYXWLqtDd25edM54ka77OlcJYV98zEmnc0Btt2/vlzfqkITg20lvvtUUbPLG+ei8n/E+k3qct01s0osdcolNnG8CsP5RbbXKZSoPBllBT2ORpncz2bm53YbwFqw2+TNgPKU8Yu7IrGuCe70Rd/Ef8x8iGUnTeMsG9VhehuJQs4nUqROPjTUq2' + '7hLUK8y1lQYP5LYfPaqGjHeDPWP6kHvQXMeIjzxCiZV15g/5bwdc5WaX3qDL3Za7VWfQu8zlrgC+F9+zOJ1MU7egDwHPrAa5kEl6bxJTUMLTsZGnoySSLQhRFm6To8ROfWZmbz5mftYAGjRutxA4PPjC/XLInA5KhATIlh1QBcSjyAfK0xDaAEvhsyiAKin220rkhhLsHGRZAxkR4OOGugVkZSWM/BQdXQJQ1sLoapd8Q9l8PF9eZYjyQQOD2TRZsh4sjTX+CwYiN1QV/2Tlnl6vv3Ui/YgoxB1e0wuH45WVVUeiE6M9GXdlsi2U3PrMV49sqK/fcOSrz2zdeuwrR2br62ePfOXY3PrV9755ycE371m9+p43D17y5r2rBWck42gYzzYMpR2qz0p0JY6gB9fm/uT1enzcyBs8xwnWZNQTsZac6q5de9ldT2zY+M27L1tbV7f2sru/uXHDE3ddtraWe/yi1+6YmrrjtYsueu32qanbX6Oxhn8QRW5c/Foeqw3nsdoiyuOB+2+KRkrNLjN+nUhzOCKKtR4IaNCSoeGpJRgJ/AD3ingbnW9tcKVKuJJIZzYd1IIsn7BoYhKLO+2V9Ko9HZ17VqVSE3s7O/asSucqXbU9VdGeOperbnm0qqfWKexp37mypmblzna5jHannM5UdzTSnXa50t2IIz5bwMX4HYyhbsValyXDJctscTXwuNkUkoSP5jgLiAtSqg1+BYmOVCCu7VgRV7nxBXo1lisyE/dbOUMz96958V0tizieicc1QMk9ItdOHc1zdcnojz+HsFCdHkbk22avuawMvt7O+HTkkjezUj7ObCrj3AT3T4CBlkYhRCA+F75/Ma0H7tUrD0T5dbIQPUdW+BhZAjfDuxJTPq3e5m5cuTbUtHkgNnz+dZ14tdPldOUG49FQ60iseriZRA6LQbde7bXYq71GZ8NYpvuGay+tg+TqYNTlqM12V1dNjQ95nFXOCtre+7g0923xVtSHEqdjEz0LQxnRYRxHjVDCMWh3GWl3gbgsaL6KZfQXuQSyLKmJaav40mBb0mGPZz3u9kxEXelOD06Fm7cOVa/uiXYl7YmR7e2eyeEGj6M8Utvs6ZtypLrCNQ57ZaXgNgUzfi8kuGgqNH6zDWzjnrbVzUMbjbg00tQfa5pq9VTYw3azt1xb3tkZaI5aiQeJ2bqEaQ6rypFRwky8BOSNxotKL/Om/Bz9dZvd5tGc0gaNkMhndgjbTV6rwYBbAC/YEzV7HZK/KPe+EADZ7qDaYvPp+DJfYIQH+Vfil5e0phtkwafLZdSieHQLTeprehWTuuzYNS+b2JBa2WnxJ2jcAr8/b1f//5upXX1DF/6rbFc/xbzW4H8aSCxLWP2vFcaOYHTufEpoprkxAcS0t9LUQpdJGbmbCjZ5s1WedqshmMfAlIck/43aJqcKE6vfj5m1j4Sotp738A7x/sqqrOvzA9XxeLV4/ef7WaQ239x65pHByeu2NLC2PIIP4xe562ncL/Ff8cSVVX26B/kRcyjj82VCZrnk1CRT3wqpH840KdPseo25TXgOqVEKeYndBKfsz6IoUoGwMxRuL6xKBoamk1HXNdZRgV5Mbc+y4SCJ06eT8dJStZYjoHKhttHY0BnV5RqTQVUSGYk1V5N4d1BMLFaV+lyMdcHmeKy9ylJpEC0avQMMSomI0WEo4Ux6jZa08QFuAn8kXo6syCKt5cYUM3FamQBJOlYnUzsNUud/XKGzesq1rxvMleF4pSMmfLXEb9bYSy4rC4XnZv3wx03R97SD3G/5+8TfF64ZtFdJ/7I144s99AdTW+/Ytu2uranU1ru2bbtja+p5e/14U9N4xm7PkLLeLpw9fMPOrq6dNwwP37ijq2vHjYPpTcOp1MimOlZupm15HnUJeqJ70' + 'XdGFpEupJbyT5sJwSzpXnze1G9S3ALMARCRiVlCE/QfmuvshVqWvc78+ofmjN1fR5SxOr89Y+Yqc2fK6hXejXfJ6lXuLEJP+GSqL+EKIAHdMP8dyLH8OshKGmVAC5pFxC7A9GU+tRRmRqGD0Q/LQiV8/ESbPg51KOugtMBzztAlsTNviBXlm8p7cUy0ovgfZQOcAnKIF5cSbm9ZxOpKifgnpVVWd0o839EWrsoMOiorHYPw1l+VO+aPEDE1nny9SJ4qnfaIT2MQNzsrw/5yw9zjaX82m2t2Gwzu8yHiP3C+31EKoIP4BfyTxQSPp32GaZ8tQ2uoT2hsqd4qmjqfRUbkpWO0Vnr3GCOI40v1zT+8yC7VR9tKI6Rv8Jusjx5ITPu0OpunceW6YLO8FE+zpTgWBa9ArHqELsUn312kz/xlrM8CGsPcdWSpNturffJSfZmyVC9Tlmr8xqJDF+RuAPqwEfpwOZpG+9CF6GLE9iVYuySK+zghjBcQdhDCDtat7dJ634CqCtZ74IHyLCg3vAMl1PcchzqU+6FcC+WFX6QT4L+rEzTi/zuBpvJcJasRnrb6MFEjBqYiRI2Y6Vk5mxjdJikRGqJE9BMlIpIkQo2/XrpA3s8qlvdnApEKEHchSJQND1E2yjU+sw2SlL2tVNngDOetappuUVSNDlA1qqxes9mLT36/YFAENIsOCqsZxgTY/dG5uXP4h4UDBh0KCAZh5rsc9cssK9IZqdV/mWSQV1DNGG2ExmfCtSjmlPplYwSFEDKoUQ9+FT+P9KhbRCnUjDrhw80SX8EivPvxQwpvHHjjxbxv5Hk/wM8ovK3A21rMW5Pn/TN+AXjLUTcPfFmEF/KN5vl24KeBz8L4qoCPVtroCQr/Q3n+P1J+N2tDI7A2Qhvoj2740S01iINuQupbxPtpM89aEpVGRrUoSvNVoKzCdClUQa09D1gTygMG1dFaiGKoMUCMQnguis4Vzpv7Tf7iKsmg44PCH23VQTufnLv+YUtf2AJpaQbuKn9Xd28V3wJWGa0GdN25uzvxX+FHBfmRs/ThV8iRZPrzj7iKnTwE2toplFeMwD+5/ULdsvGEDps8UUA3AfP/TpMnYiJQ8LlBUgs2clwp9zGiz+Ps3CaCewX9G4FbUqOL8TFCZ5hKVE6qJJnaqzz7ZagTPqyrFV59FKRpCD9vUJFzZF4OeLli3jeA9wM8W8xrAl5TMe8o8O7Aa2VeWVaQLCvmvKxsQxwXom1OsDajrNLmKLBGlWuvAV5TAe9+ZFR47cBrV3hF4D0A40DmBU+/whsD3lied/4T4L1BPZrn3YECinxb5TbHpQHBzf9NwtfywrS7asmsUmW7iOeQD3FSdoUPBE8lZVdoofRKmFtMb0goKC35FItiGC7eoOBwSbNtkOFxbQyFQ+GNfweV69xwKBQm0FycqsbpSnJ4IUAXd20uJWN05eoJB5M3imlC54laaZ74szJPNCnzBMUIoc+njj1LzrHknMZ4mfz9L5WTuqXkj/Ey+ePUjHdJ+WO8Nfk2/JmrKJ7TFD4mp5zIrrm0nCKMteg8wcIfQGlqn3NJmmISPjxx/si+VJUOE0QJunamsFqeVjpxAc43d+sJ8Hx7bVqN9sQfKsqwrhJ+2f9wQuvWQqlznPioQqOz+wxaTwW364RDa/NClbDCcV+lrvIPn8KZdq/BSzgZrbwCIR7uaYv4lqoOVVPUjJsQifu+REE2z4tkWXE0U/HmTUtMrgwrkUyunXksb00+hrREQgODq0KtC2pMupex0CZZfAv8kJ0EhpjBkSi+RzVPQj4w86yEiYkZ06Qi4ejtd1MAmGX7G5rLI2ZPXVnT6L6VVRScpPdgNlsetXrryhzmeHcyd5VnWXj3/WfVnnrBkliexgc6VsCvtLhyXe7pX1' + 'F8GJNhnx2C3kzmfYnDD31/L8UpMRt32a1V4Lab07bt2z7jPbWhXENwSVov2r3WxT/kZNgk8/MMy4HKeZM0z36kyHk7dE67Io+Ml8n5y1TOmpaUc8bL5tlfMt4l5Zzxsnn25zLv0vMsy4NX/we0uU3SIbbiY4vMhwpmzqMoQIbtktkbhdljQYIITyXDDrUks1paisOo3fjvA+dQZ2dtxIZ1p4Pn4O0f5LFzHpVRv7YDgM4+AqBzzN6yoZ8C6JDgolvnfyfkACtlEkbBwoiB0zH984QJQpggBOY0YtEDIeY+UgavZDpgVuw8cvvpqSlmtvGEZHng6kQaTmQMVLgnWsc2dW06d1NXMNueDUbaV1QNbGlzYtkQ1H7Z966a/PJFA8FMeybYMbtrtqNr102jex//5zJTGcH7NZiTTVNr6oc7W/vXdyX72zL1jYHqzri5dfOh5acelRGb+A0XPHOoJz5xYCze39FYl7LFW7PNY3tWrDo0k5wCeWD506pykIflkgyXIcTmyRTazMRmMb796K8K30QxnynP9wGaV/jWFfGJ5zE+PVlL1AX0W/L0HXC+Qv8gf90/0utGyXV1aCOT8xSrEMp2mQIVJs6Ih2v8XnWmwKNRNIN2o1ukbPFUqjiGrthKUZxPowhLEyE0MdmfkWwucF4+b6YJalW0NgPr/KiURbmKUoJAWXOchWltK8olVwKVrDZm4LSRd16WMMjosi1roT9OZOmkOnx6mrmrfjBJ08y1eneVFnLM9z0Ya3lk9zn/sruRg9zT+7C7++zhqpHl7c4yQ4nD33/BbWMHn8y6Jrdf1Dl+9aYGKfWc+3fB1zzZCKkzQeF3i6ShHyVp6BUWp05d7TSZB/rGpobXDF91bKczufz8ybTe7tGKYswZ68t49s5mR2vtkJDezxLSbct2jsSSYzvad9HM9LiUmb6tlz7/idwmkpOtj6A+puuik5S+GuKnM6pyoA9wTH5HFHlbpsibzEfm3whIkAr483xcMZ+Jzr11xXymIj7xFjrvpqFFlA/o1Qjh39Fx8j16ds/f8mdH6dnA4wKen9E2738LeICzqCWgi76MENemMgHPB78v4jHJPE8Bzxi0IYJ2vI/0jIfh4P9a1Kp0dJeAoaIcESqqsFCjPmm7BuLXgPmboUyTgDqg2KV4Fh+UVUpKiKSIKuhQIFrya75iKMgfaoRsAr5oTwduaxD+nix1ePwGq9FXZQsPDyz3fDsYCASvdDlaj7x1z/7nj/R17T96VtOOdcMO3ur8pGVLfzQ8uKO3e0O7O9i7VQhCuFnCWp9JmbxesuNLdtMVw9UOR/WuX2y97tNjOwau+NaOsx/Z32WrGajlBp+cPXUesSksP3c8mZrY3bls12iMPD+W40Xnn3Fp/ukmdJYTRZ/fhDQfrlJ6vll5/oyPyVMNfdITCh9XzMfkqbuYz1TER9szIbWnT6FLctYBR9j5PDoEe5U8JgSRBcVQO6pBi0AvONnrBDxdDX26zVBLLYFvhb8A5P8NswecaPDFf0n2L889b/AmXcSiSmyprqTXUPwbf0Mruey0sjvvKNk6juxMZ2Mlf34Rge1zsULYJnwFJaj+SjAlA8RuvqSvRoHzeg510V3LhGom5EZay0DNI+mrLBCI4RY05PO/lhU4dAqj32SX2AJVNUwVU2teLzVF8qlu6/p6NAGTs5oXO1tnWtwk622yt0vjMzoSJa0d69o8fLIckpvmkbtmdE+fb+5FLfTTXDA1ClE3+MR2yIQzXWMxB9wAv3JVYMv+q/vOhqQ442ErxP9pjQf9Wy+8pi803Ndpn7tW27n92qHQ6ECnlbtY37n9epAVlktCZXdGkt0xRdYGFFljfEx2Y1QmZ4plV+GTZLe1mM9UxCfJaDOV0RlCZ7H1dJ5bL+kMv1LOr5L' + 'Op/l9jxLcESB1oHYpYtqZWgp/pFDEa/LoIi15yJ2/Cy/CEvgUjQ2fSdL0WIYwy1hzjBRAi+x8pkt0ALJI7XA2aCmh2CJndrrel7UrlVnBFqll2CJ7txFskR14aNWNZzb7GocmZ6qXU2SRy5HSJ3TOXi/pN39Rcon5DxfJJS75f80l5i+QM5oXJJXj+fckzNgsGmWRo19oYQOs6nyAeVyyXHjY/nlSMpVir8gj4XRi5Snk34vVYjHa7CZDGdmkweG+Xcane69cZ3QTSu6DhRC0XK1X1MNbsi1emsZPye8Bua8NkxhyvS1Wtn7u+Tw0LZ4HewV3mOaedxbl8Sy+r5ldMhqSVDG2K62dYmBAby96UwqWuw4rj2GfQW/0WMutlc/ID+TeEmOJwWMB0q/zz4bvUZMXAUtUcwbeJed8505OihyYAfRA3j9Xpjw0DjDuf6/eJH4b2j6CDsh3s4w0flnB3bQRQhsjFIGyLQDlZfdrget66f22wTPk4RkW7t+UgFpAMVizt/eCKDhQKrFhUaRyttkZhu4ysh5S1hlBW3LH9ZtuWl+TWHfTFlD4kjxG+CkwyFdUwFduGH9sD5EwadjtrUEztu2c5M2//drq1Q//6Y70vm1jGu7LwFReDl/Ce7xp6o5X9+37z7tWAyReCSc4c9v1bGdrfa7P6AyaoGZQl6q3fRcbH3sMm/79bHWpCugUv4y9D4zMv6v6jaCCcTCEpmhevb4Iu7ikeIfBkqJ0piV2gZ1CGAl5o3Mpy1aQFCm4FtvgQ+rtlUy5KtDvs0uo90STx4WBP43SLBaWQGRUvwFF/jrs7dm1IjrY0+YwGEGPP/+fhw8+2egaXLuz8/IXLu3ouPSFy7t2rx10NT918fmPntv0+UZP5xl9PZs6PJyzfUt/3xmdHuFVIdC+pqVpuj0gcAZFcy+LOeODDZ5zNiaHGtyQqn02WbDc9QOJtXtHrj52fT8kbredcbhv4Nqd3ZC4bZD1eTLvMdxS9Q9hjfgQH8THDNDrik3DSu2rsk2D5cSq9IQXfUbXnWll3bAq6w6zZYzmbRk78CWKvTYq2z5aZdsHw9OT2jBA29C+ZBt6QUAOS214hbZhNlfcBjKXvjv3vrBbVYO6qYUkliKms+eIgREhtstoPvcKSYp1FsrQcYYGVcuevYrsaiO53pgEGBsVuLgOPi8PBUC9QcgQG6mObrvwcHdzHcF19C5f3uOuHg7fRHelga9veDcfundNplbnSbrrJvtbKx+Vj3B/eDJ35TMPv3mgptql9zv0zok7LzmGL3mS4PIaAg79E599eaDaCThxusb9L1xFqEbgKvAB/ZH5dGD9+gQ/ht+V3s9fYfYBRkf/W8A/m+c/gZ/O839LPJjnP4HmC/wGf9RH4crj+F3QJaoInWE1qcop3cXetwr4Z4F+Aq8t5hcPUnpE4Z8HTHzuI9r+hNROO2nP/CUIcd+guson/5V/l4LrGIF/F21/QmpngPK/BfwpuH4Enci/eyn2ZNb+k7Q9dQvfF4DewPR4hZ+1nxOL+aX2dyj8DA9Zuv5XKX8DvS/QIvg4a/804Z5CSOGX+udRhR+tJHnzrP2bZH7Fnsiu/zrlb1qoMwI9peh4jF+6/s+L+aX2NxXw756bJfjF0J9ZOmY/xZPy2NYX2pG2z82SvHjgm2Z86HcKX6/CZ4XrAf6vPgpX6qXjtFHh4xS+wNwsySWH+/10K+FafRoXnv+NsIWbVJmQHRmk6GENsZtzNN4sy6AJ1UX7Hzc+VdPkaLC9aMUxtzlueuBBc8LsjlnFXza73PPIY3eFLfa337ZbQy6HG9H/sYFbpdKjSuo/sJLrizTnq4L8F/70PZR5spVgJFpmjbvNCdODDxjjcH3zi9YGh6veJt4Nlw1ZKt9+u9KMI26HE/6lE3tc' + 'DAfzz8JL3JD4Y+RCldJuePBtTtkZXCVi1lkZjorZNPN5c1pyh9h99j3B0rjDHC73DHR0DHjKw2ZHHPNi8B7hpZlxi9ETMFsSoVAC3lk8pSbN+AzVZW8TvocfEv9DwnjUpUCLXXTLtttO226rp2inNsT2WRWm8R/ED1icE73is0ikccpQpzunnX7tcBE0xZi/eTgeH27y+5tI2ezHTQAVa7FE3AZS0h0zfbHBRp+vkewD3+TzNQ3GzGGXgWQKm0OEK0T69BfCVdxq8TwUKcpFDEi5iIEFuYiVS+YiQq0wvh5/zeyo0EL+oQ9XbBgL9y+DbMSwviJACNiwfozlI1aa7RaPrUQYm6X5iGaDw86rxbE1NCORm38RYiU/UZUjM4ohJ3niNvrEORm/kCHcQYvk2H6TknIkUloHLqThe6yVNo+ghphKE+RXmyt0c6M2m82HC0k0zhIUXBJoCR5qs9ZbPr+QovOUMyyrB6B9P1XaJ0ukm34b6XeUjoICLFA5ity0gGajtB4CEFplMQFAqEr0Qsta84STagETiritAjBDIwwzFNpk9ZrQfLlHIZlKLEAiY2UXjJWDyEklzEzX8UvIA7azJ0z3trFZldRA5Rk2diwyUCImR7w0eI94kA4TeCmrDoerLWa/x2iBUYLRurlZ/IP5ehoHeSl9RvJu4Di/Gziw/JzI/xr0lnCfyohKUDly0vfj54hJB+H83kGldHyF/bgD27IAMhrEfuG+k8/jV8trXe50+Rp17jHuybeEk/4AxgH/46fiEvbIx8JLQhOswL1SLGxLaintVtlDnTlEllMZtxxnMHgpGRfQwxVu9oMhT0Ersn4isgWvDPXZhuBp1iehUlVargJBd4fN4V69xpp7jqsw2T0Bo3kwHGnCWHDXRuwCHnewl0EHf6/VByFq8MUfybWnNq8bc4oaEUA3KlL1njsvxn/tvvXOO64/UJOpScRKjGUrn/3BjzaX6EWaaQz5lnJJ+hA/zc9x5yILjUvVSP7MxUxkawmCnsYGgD7D8qa8+GlZY1J0JHZNde4fuuaMfBvqFXJtiWse4F/G70GsAU/3W+dOj+OF7s/wfux4ZVsuJ96fi8M5R+CcP8nnKFnJHDmHY+dQYRslwga8PyPnzLvxn9AJOEcj/x/IXRfzbO8BF5HJJ/iX+f+k11ajpMSpOr1VEkEgBEFpJv2sIE3lJuUG459Bo1ksKVz7lwXXFmgrTkOVXup24MM30fHz2KvbMUdujFydXfvf5938L+n9qZEpf4es7YJ8p+Rz3atwBawj3++xC0j7umAhJn4fJL4TfTFsONmvDCO0AE8zJOeoK87CxbMjZD3/x0aYRGHCMuZOypmPWJRpGOdHwrFT33IQOCL44sdIMIEBwoY+dlQByRl1fExMJCSkKL8/Db2PQZhdFphClriPDuk+nkPtUKtdcEcd0ptNO13xWGxnmNyhZZH8jyVvttiMwL1udIdNsAQbc5+ze/RbsKqwDhnRDB+Zk4dmLqfUce+v5O74FcMTqNThX8u1/6b9Al//LVNyAblG+udL+Gz+PKEBZESDiLahQ/wiGTj8eS1nXjM6cvWZLS1nXj0yes2ZLdxrg4e3NDdvOTw4fOWWpqYtVyKe7MOruhblqP7SiibRUvhkyq45CzOWBRmwTFywNS8ch1qSTv2NxerPkr+X2LSXO6tYGePOLua5rGjbXscX/EYwxkLzL5T8FPBnTSiCWtAY2oL2g63zGkSWmNMQiJcKfd1NCLsLOqaXEHqZZJYhLEWjtEJtBa1thdqFUCO5ALKG1itFGsPloHYFW7GKUtnDC8B1mI6k9Bp97Ljot634El9wHJ+T7q4yGKq601LJPVThAxDcslN/BdwAB7gOGkcunkpWT142OXrxJClVu0YPTCbjCmFF0RVO/' + 'Y4ciE8BwwF65soiBtESHwJh3DoUjw9tBaEcip9vI3uUmD6/1agPO9W6EvFA2/Z/WjV56+7Oth03T07euqtz7mxa++c9QGFHDlUPspPZxQarD30hB5trZlAX/pTmBpB1yHRaRubSCZjLzLVKViVLtVwyq5L9rwtQF2fM/y8h9Q8nHHBGkkiw4J8tnUzA3q8+m3+Ru1T8C7IijbQXDw8riE3Z4lW5q3s11ZUE0ITj8duaGgepqtRel8biMan1JeJNPqi6TTq2b2eUG4fcrjuQG/lg3l3QWyy7y0aD6Fk2mvo4i/bWSaXpHQZV62MC/oXR2JucrZEoxFHDnxRH7Y+SOGqxNxVYNAKa9bMKYmuOwriepWO5OFeueHvn51BA8h88hxqhlmLYdVuBdD6NWmZuBXScEgNADFBiAIglEsKJm9qiR6DWRmuNcGwcjqWgXENs9GzASvayAjWUuOeUvAGVxWy1yT88wJpVfBMSopZ8IfJ9TTvJEV1ZuffBnx5a/figz1Vu85vBPXfO5eOXzXYaOQPBYZj7uYoXuCCt/sXUOXtwZfuVbYZyk99W4Q2OPbb20je+ssc5Qw73qHi+HhAYqi544aoBt4vu4+oyCHwkPXFOF+n+TMbd6okCQ8euFUmLWSQpR656rcvTe8W/7QOGaLbFQXKdu7nrVS+K+1AMdVFNpA6kr13KuYnAxwOf2hRz8FccZ6WFrs2wxudtz01MSOR8iWJILplOB0wkSr4UjKhq+TT+17Vudy04O2zBfvOrr5r7gmQzF6Cl3y6D7P1o2alz/tXj9XjxJ+T7aMbjrRP+JZeJRiJRzgqx+vpEba4f/1s6offXBec+hAcWxa/l/A6Xw8W1hCHli3zm3o7CH9PhxkH2NqumURYNoxZpP/Fg6jQMDyY29SwrlYHTS6tnN8Kn7y6OSWAilQBBWt4FMLe3YSk/DBO7bMH2pe/odEYP7O/vHnzu3EO/uG/N2O0/v27FFWcDytrgoa9vSc+MdCSdPMaNZ9w0PXkntnftXJkpLU0NbGhu37EiGenZ2CzOqvQOiIKIVfizW36Qe+vlZ3M/fPdQrG/jrn3NB79/47CjKh33CyqzxaL+0ps39sZP+scOP7zGO9gZb956ZLjn3FU1ZBxm5lvFNwAfOoV6pblVTC3cGK7Yc8oIIapEcJ8y6Qjr5dAAzC+2V+kir2wfYhPZQz3qNc39Xq5dLW8JJ7xrDRAtLGAV3v/8JZIJUwFfYmdhXe8MGAmejYGVejaveOabhE/gfmKoitnTi7GAoNn5zRS8UKNbjyjb1WeVJvotpdiS/3UgU1VexgXnPtNUJBr4d2SteU6LfzE3xy+zsfbaXk66DL5y7nHuYbBweGvJEwKlWV8y9+DcZSVsvxunAdoZxU9zr/9D73hXkXzXcvjCH8n2d/y0/G4nl9QfdRb6XIX5f4U7b0cTKAh6Z4Zl40O9g5YxpKPlABIX6KPFbiLJ6S0WySyGilrZ5y2owk2zF3al1s3CbrlTG3d1de9f21C//tKh1m0bp+OhsXV7lvdeOF178sXU1PByj3/58Ew2NZRxeRpH09xf6taMdjvrxof6q1KDtQ5PdrCam5k4vDbtbFm/LD3TU5VZe+nQyKH19ZHumbqqqf5kevUlw+/HOoYD1RPdVcH2iVRiRWsQP5vqGXEDqIMj2jEazUy2+OheY7mHuM9UJ1BNHnnEJiGPlLDBrCxvbOKWbhAbC5KVWllaUxntFO6QN+nWNtSme2KmMk1Z47qLuoO1fl1dErb2TzjKKsrSaw+rTlRYXVp3qmbrl/cc/DyXyx15+KcHakjSuSftm7rjgquwGvMYXXbLa1e2M1mdhXlovXA5Wg6L3Glbi8OK9g5rJktGtdCa5jiD39C9w1a8xuMsFaDnOFvNlx8vFCHZbq' + 'jDMg6JX53PmmerFfNJB5VTvplPhX9+W3mi0t9QsvK3kA5fFovlfrYH3xWPkWO54K6KuJ1E5vDixA/klHlcupf7jpwW/ye3Ix4ym56E33pv5mS9l8TvnHA7QWUxlprKniJ0wneSzcmtiBOmhKeRE2Q0gFimcdHmKDJCQCUx1zLgKZxVYNtlSx9esJPQleFgKMJv0YEd1lJuc8ypuFOV1jgMylMvEKWEHwvAH3e1LuNy1evxTjVpvjmsyf1/uac1IYunTp37LAHBYeRD27kZ2nlQeDHfTmMRVhvblpi2k3uHrRHK7MLigyRMrIXtPK4zBKttDu5vc2KlTWN2GfQG/kzS9lNHlHZiszrjNUc0uBUPa0JmnRuUzRy03e3K6OeuXNDOg/NfES5RVSAdCI5Xyh7mWfawtKknTy3NnJQ5qYpEGYIUQZIKluIM5o4bYAPKpCG3Dj9CaikD4FAide5F3KvG3RGPG3vd3F+4ea/H453D3MTcd+Ye44bI/ybgINOg27WjUXTLkvhPw4QwfHqsgeIiZ6kwS4BSFsXPsngDzKyKUKugNWc+fW6YLNtshfIvtf1IHqVMxm0rDI9ZsGmDlZ/OnSWn3u8laL57YU+SvslxtysctMes1bV2FVduTQQscsAGRvKWDhlP+xg/OhfN71PydhpUnbVknxJLSdLhzagtTVvHPHDIM4flEA7hJWW/B7LvPe3jUvEJWLWvWXJfFnkBLwrvWDpCuRh0tii+vS3/LmyGWjmtOaCW/Xu7ujQuBt5vULZ3IST8/MK+TIye1Tq0Z6RaLVh9YbM1psQkvRetc5VdwyahRTrxjBumo7gyGCon6oN2wS4IwiPOzm0j0bRb67QSzI7/A2IDNKUAeAFjYGRgAGGDhRLs8fw2XxXkORhA4JTN3CIoPfV/zd9Yjivs74BcDgYmkCgAJKYL1gAAAHgBY2BkYGB/9zeWgYFT6H/Nf3eOK0ARFMCoCACYLQYseAFtk1tIlE0Yx/8778y8ih8f32ewEYSRGiYhoiulRKF0sIvItNYS8aLTrrZE2MEKk73oACZuZYIRBokIotRCUmqIHQgVRIkk6DIqkOjCEDXMi7f/vLqwiBc//jPz7PvMM//nWasLAADRQ4KA9T8WxR/UyUkEVAbKE9IwoLNQwdiEaMBDEpL/IKzScI9nlaIRW6i94oKzwG+OkDESJD0klbSRMnKalJi1+T2pY46rJg9plusR0gHkqi7kqAiiJKjm0CFn8Fy2ols5CHH/lPcPygD2KD/6eR61P6JfJ6FT78V55UPU1Qj6WPs52Quv+sFv/chJ8CJdZaJQ+VjjOxSKl27N89QzvH9YAhAFyJX52C37ELamWXM//PI2/GIKm7guZb5Gj4NLwnYmWG8L13dsP5rMOeMlJEzKxBL3XtSIaaS6sSxs15Moknk4KlORbY2gmPcmekZxl7pOpXn2L3vvSeJ3VeoUzjJPl/yOPP6mmZ69EQXOB92OCOu7xZxtrPk+64V+ghuM/bR8CPGsRcyi1MrFY8aKzd1qM2qZu5v7HWKIfvpQz/MhfRJN+gp5hQN8S63xfS3sAeSbXpg+xMM+VJMKokSDM6vmnMVYH1bD9/3rKnsRj+kFiapdeGB8Xws9QvWyF49wLB56v41s9DjOGHlh5irWh9XQl7BRNx5PJrLdnm1FtumlbHW+MVenPYGgXYSD7gyloCY2M9Z77JOTzlfji6ktpq4nnJOY0o9B5rlOb5Kpn8zbzf0xNfMplpzfy4rDxgtTT0zdezk/Zn7NDLG/XwgBqL/Yz1auD63sP5Nh0rESq5TzqNA5gLwIKMU8gCeBMHaN3DTIRjwjQ+Q1vet0ASJ2HnoTk5HO3xwnl83/Wswgg7Vqawqwe1CkxgG9AMhRlGoJn3yLFL4jw1Nu6gF4P3Q' + '1AtYG+tPHfTuqqDvJCcbqAUCO4z8DAPwFHNAqLAAAAHgBHdRRaGRXHcfxf1iTLfQhc2x1bXXyUG6rjabiVDN7pyN9GZPb7GZrb5vsZHL7vCAEln2fF/dNKPoQ0Faflu4Uyq4mdHF3WHbR2iUiKIgoQUJhGVSyDyorPmW8P7/8CPnw43/+59xzDoeJiJmIJz8bMzN/mYt4YvYzcSoyPcC2vo25htixXVdOdIy1rsWpmdA45uOUjvFEszit/4V1/R6qvhrJo8mjidEJ1vU9VP3TeIq/Jv9PazeejoZNauNTIlPfxs9pjJ+3Z+wX7DP2Wf0Mv6g/4JeoPBvz9Z+woQNMzmf0Kj7Dmk3vZ8Fm8YL2cdG2NMFv2mUdYVtX8KzuYq6r2NEedpXjijtXbaEDXHMu7Zsxh285b+oR9r3mlkY40M+x0k9wR2McWm4Jp/Uh1s4iPx/zeoDJZjrCXPvY0QF2tYs9TbCwJb7ArGNMtmLWl6n8GJPNNMIl7SNnx1x72NHfsct5vxJtZr3IfQ6xoXVMzpk2cUmzyHeRG8DSbmgf+/aaHuF1O7I39edYZCefYrIZK3w1WratX8XXcBJL9NzGZDMdID3Ys4UtbR9fYnQPCx1iaanjQPtY6d34ejTqh7isA2zrVcz1HHaUY7f+D7IylrbSEE/qX+C0/j7W9Uuo+vn4RnDDmLBFvo3Jcre4qAm2bNuVs865c0e38BXdxa6GyHdxS49wYKc6QmkcL8d8vYa8akzOmS5hT7/DQu9haTc0wb4d6W/xLd75BBdtyy7btg6RXWGuT7Hj3NUe9vQYC1dK27dTXOa8n2CyvElsu547dzXGLeeBrbDNKX6LjfqvmJybtXDBZrqCS1rHlkbY08tY6Aye0wRL5w09h307cKWyO/VDHNprehfft9ftSL/HD5w/VIk37E39AG/ZO7qA9/WjaM/MaRZP68U4G5wXk830R+StRs6JTrChH2JybuoqLtjM8juDixphy3ajiT3PKnQJz+sQS+e+buOOLuNQu3hNB/i+vW5H9gP7oT7CG/am3Ysn8Jd6B++ICmcZ42kdRYezXMKGDjE5N/UxLthMe9jSLWSf2HOlsOddKT26oQPs6y5WzjvaxaHGONIneMPe8eh97r/jnXS8k1eCl4ktRrvc5D1s1L/G5NzUWVywmXJ8QWNsaYjLGmFPZ7CoT/C8bmPp3PesHc3iUJfxjrp4X9+LLntYx9PUe7GlCQ5shd8Jfp0wWUaxwhXqx5jsOY3xAhbU/4nJ0o8Du20rO9UR1tpF4WvMuorJ9jTBQgf4mm5h6cpFjXGqf6C4ybWYjzlMeC5YGaesdoG5E1yzpa2iGd91zxuxZQe2slPto5hbBvvHZOnEgd22lWX/yP5R+GYwC5PQPRtUKmzodUzOC/ovrthVW9g34kksnd+yG3qMfR3hVuQ4iNdxO5pYufK28zSy2Ay+jslOubeL0YsmcmPIOjhwpcJ+cC4c2Aq3WOESNvQYk3PP9RVb2NJuRZP/CgfMuoINHWByZhau2FVb2FLoWdv0v4P0YGFLrFitwoZzcu45r9hVW9g1W9pNfJs6urLDOmNMNrPt+iHm2sWOK11e+5DOXUyWTqQTc492XO9qNk5i3iab1YdYaBdLeyLeJT2XMdms/jeuagk39BFuag0v6hC39ACnzKpj/n+/wWSz+mNsaRcLrWOJilM6RjoxWdbHUu2ZCPaMuWaxo3Xs1vdm5tjPESbb1izmzh3LDcycpmeMydKDuXPHdrX+f+H//5QAAHgBY0CAKIZtjFlMckyXmDuYdzF/YzFiWcbyh1WA1YQ1iXUa6z82D7Yj7GnsZzgCOK5wynCu4TLh6uI6wvWH24G7gvsXzxleI94VfCZ8bXxv+N34jwmYCGQJ7BJUE8wQ/CQUJ7RL' + 'WER4moicyDKRf6JRopvEPMR2iYuIZ4lvEL8loSARJ1EnsUzSR/KClI3UEWkz6SUyPjIHZMVky2SfyEnJXZB3kZ+hIKewTJFNcYoSm1KV0gXlCOVjKgoqRSofVCVUZ6g+UX2ixqbWpa6kvkkjQGOZZpDmHC0jrTXafNouQPhMh0snQOeUrpLuNN19eiZ6VXqL9L7oq+hn6R8zSDBkMnxgxGYkY2Rk5GEUY1RiNMFYxdjA2M04xrjIuMt4gfE24zPGT0xiTApM2kzmmGwyOWZyz9TA9InpLzMBMzUzO7MQsy3mbuZR5nnmTeZ95rPM91jMslhmscvinMUji3eWDJZCliqWBpaHLM9ZPrL8ZsVlJWalZDXBWsfawTrEOsO6xLrD+p8Nl42DzRZbKdsjdlV2E+yW2O2xu2T3zD7OPsu+zL7Jvs9+lv0y+032++xP2V+zf2T/zv6XA5uDkIOcg5aDmYOTg59DlEOaQ5FDncMkh2UOuxzOOPxzNAHCAscZjvcc7znpONU4nXJmcpZwdgHDY84fXKRcTFz8XJJcJrjsc7nn6uR6yfWHW5l7hfs69yceAh5JnkpAuAAEvdS8+rweefNA4QTvJ95PfLJ89vkK+Qb4Bvgx+S3xWwIAbqS9zAAAAQAAASEAiwAHAHoABAABAAAAAAAKAAACAAFzAAIAAXgBLMYhTgNBFMfh35vZN9NtZidtDaXZQIKoRBBE8YQgcFygmoTQ4DFcg4QDgCYBxwEQJBgcwXGESlb8P/UBB/aIAQArbnUj8aYHMp96ZNeK3lDtVHc6u9ET1R70zNK2+ogSTvR2+Fofswo/emEnnusdL82HXln4qz4h+a8+JftWn1HTHhFrWmADulF41gOVdz1yxLfe0NtSdxZ2qSd6u9MzF/akj5iHfb0dfqaP2YRrvXAY53pnV3GtV479Xp9Q/EufUv1Pn9En+K+mDFpbx6Eo/K0fvP9wl+/BqxJ36V0oBAqhoU3pXrFVW8SxjKTE+N8P3NCOM3Q602E2D21s6dxzzuVc6Y7AwETE09CSEX5Q8RPhliUFBcKeCeGMI9IT6BEsNZYjCYOwoqNDZjxJ/xwJR9TaGgN3YZiib9osP6qfcrssCtlPcnaxD73Y2h6TkVXXiWKSRJdcPLvawAMnejyZAA+n3ucATzgaTnRYIjy55tTZyNzrzGmJXNGUsy65eFALpVz4SzV4LX3zV80L9OZd+kWlE17FhQLDUhcvLiYfeinMcrn8Iu0cLHiSZiBkonboOGrhASHw+lleb+Tik1jJ0dbuaONBwut1EPwtBXPcv4T9VsM26jL0OEYyEwOBhohloGXCUBEwnDjAOI6md2OehtBEO7STqYI5HWDHPRuELQNOW1lrSxlhg6fS3YTjF/Lh6BR85xvPtJr5vH6nOWdGzd29T0V3xVsjOjm1cguZVrH/hzNz7e1aeTalZyxeB3tPpycjXp0IVpVXPOp3pkQ00sxAyYIFiUqjHjRoQ1IuQyDSsGDLmg3s7jeyHVwv69Bn2fjK9cn9kj/vXPH923Pr0+V8F17zaKMTn6S7YGs59bWLklsn/0xmlO29WO/S2frO7jsno8+tWFmvHsXmUtqch3KxSFX0Q04m+c6E2Cy26w3/rdfPCL/0Ts7B8vETJG/gPwDi+YIQeAFswdOhwwAAAMBLnm0zz7ZtGzV/sv8G7QK9EwKVWKyGIEIgVKdeg0ZNmrVo1aZdh05duvXo1affgEFDho0YNWbchElTpkVmzJozb8GiJctWrFqzbsOmLdt27Nqz78ChI8dOnDpz7sKlK9du3Lpz78GjJ89evHrz7sOnL99+/PrzLyEpJS0jKyevoKikXCUIHpeAAAAwgO3Ltm33Utm2bdt2l23bl22bv9tSwFrjjHfMAh9MMMNUy222LgVN8' + "chYc/3y23QLTXLGMz+tsMVff/yzxjaXXLBdG23N0s4V7V102Q1XXXPdRx3cdtMtO3T0w2z33HFXJ599NVkXnXXVXTc9rNJTb7300Vd//Qww0CeDDDHYUMMNc9BqI40wymhffHPYfa+8ttMub7x1xDvvbUihFE6RFE2xFE+JlEyplE6ZlE25lE+FVEylVE6VVE21VE+N1Eyt1E6d1PXAy9Tz2BNPvfDQ89RPgzS0KY3S2FK77bHfAWfttc85Y5w20VbnHXfC0TRJ0zQzzco0t8gSi31Pi7S03hzLbDTTPPMdSisnnUrr/y3OzaqDMBBA4Y1wEe7DJBONcRl/spLu+gBCFbJoLdG8f2lzVh/MDJz5y6+olFc4/RSlUKOgwQZbtNihwx49DjjihDOGolaoUdBggy1a7NBhjx7pj2Vu6Bk6RmzRsx/G//3I6czvLcUjVXNOR73uMVotrq+384rP9doe32vhG6EaXAjV7b4sH1+v3Sh4AdvBwKDNsIuBkYGZgUmbYT+Q4c5gxaDLoMAgxMDAwKG9n4GJwYxBh0GZQZKBHyrCDOSrAPlCDDwgEZB+FiBk1wYapuBamynh4r2DISEoYgOj9AaGyA2MfQBoww8zAAA=) format('woff');}")
- }
- if (options.anbtDarkMode) {
- if (document.body.classList.contains('theme-night')) {
- document.body.classList.remove('theme-night')
- setCookie('theme-night')
- }
- }
- if (options.markdownTools) {
- const markdown = {
- bold: {
- title: 'bold text',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = new RegExp(`\\*\\*(${sel.replace(/\*/g, '')})\\*\\*`)
- if (sel.match(selRegex)) {
- sel = sel.replace(selRegex, '$1')
- } else if (start > 0 && end < len) {
- if (val.substring(start - 1, end + 1).match(selRegex)) {
- start -= 1
- end += 1
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else if (val.substring(start - 2, end + 2).match(selRegex)) {
- start -= 2
- end += 2
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else {
- if (sel.match(/\*\*.+\*\*/g)) {
- sel = sel.replace(/\*\*/g, '')
- } else {
- sel = `**${sel.replace(/\n/g, '**\n**')}**`
- }
- }
- } else {
- if (!start && val.substring(start, end + 1).match(selRegex)) {
- end++
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else if (end === len && val.substring(start - 1, end).match(selRegex)) {
- start--
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else {
- if (sel.match(/\*\*.+\*\*/g)) {
- sel = sel.replace(/\*\*/g, '')
- } else {
- sel = `**${sel.replace(/\n/g, '**\n**')}**`
- }
- }
- }
- textarea.value = val.substring(0, start) + sel + val.substring(end, len)
- }
- },
- italic: {
- title: 'italic text',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = new RegExp(`\\*(?=\\S*${sel.replace(/(.*)\*(.*)/g, '')})((?:\\*\\*|\\\\[\\s\\S]|\\s+(?:\\\\[\\s\\S]|[^\\s\\*\\\\]|\\*\\*)|[^\\s\\*\\\\])+?)\\*(?!\\*)`)
- const italicRegex = /\*(?=\S)((?:\*\*|\\[\s\S]|\s+(?:\\[\s\S]|[^\s\*\\]|\*\*)|[^\s\*\\])+?)\*(?!\*)/g
- if (sel.match(selRegex)) {
- sel = sel.replace(selRegex, '$1')
- } else if (start > 0 && end < len) {
- if (val.substring(start - 1, end + 1).match(selRegex)) {
- start -= 1
- end += 1
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else {
- if (sel.match(italicRegex)) {
- sel = sel.replace(italicRegex, '$1')
- } else {
- sel = `*${sel.replace(/\n/g, '*\n*')}*`
- }
- }
- } else {
- if (!start && val.substring(start, end + 1).match(selRegex)) {
- end++
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else if (end === len && val.substring(start - 1, end).match(selRegex)) {
- start--
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else {
- if (sel.match(italicRegex)) {
- sel = sel.replace(italicRegex, '$1')
- } else {
- sel = `*${sel.replace(/\n/g, '*\n*')}*`
- }
- }
- }
- textarea.value = val.substring(0, start) + sel + val.substring(end, len)
- }
- },
- heading: {
- title: 'enlarges/reduces the text',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = /^#+ .*/gm
- if (sel.match(selRegex)) {
- if (sel.match(/^#{2,} /gm)) {
- sel = sel.replace(/^# /gm, '')
- sel = sel.replace(/(^#*)# /gm, '$1 ')
- } else {
- sel = sel.replace(/^# /gm, '')
- }
- } else if (!start || val.substring(start - 1, end).match(/\n.*/gm)) {
- sel = `${val.substring(start - 1, end).match(/\n^.*/gm) || !start ? '' : '\n'}###### ${sel.replace(/\n/g, '\n###### ')}`
- } else if (val.substring(start - 1, end).match(selRegex)) {
- start -= 4
- sel = val.substring(start, end).replace(/(^#*)# /gm, '$1 ')
- } else if (val.substring(start - 2, end).match(selRegex)) {
- start -= 5
- sel = val.substring(start, end).replace(/(^#*)# /gm, '$1 ')
- } else {
- sel = `\n###### ${sel.replace(/\n/g, '\n###### ')}`
- }
- textarea.value = val.substring(0, start) + sel + val.substring(end, len)
- }
- },
- strikethrough: {
- title: 'strikethrough text',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = /~~((.*\W?)*)~~/
- if (sel.match(selRegex)) {
- sel = sel.replace(selRegex, '$1')
- } else if (start > 0 && end < len) {
- if (sel.match(selRegex)) {
- sel.replace(selRegex, '$1')
- } else if (val.substring(start - 1, end + 1).match(selRegex)) {
- start -= 1
- end += 1
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else if (val.substring(start - 2, end + 2).match(selRegex)) {
- start -= 2
- end += 2
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else {
- if (sel.match(/~~.+~~/g)) {
- sel = sel.replace(/~~/g, '')
- } else {
- sel = `~~${sel}~~`
- }
- }
- } else {
- if (!start && val.substring(start, end + 1).match(selRegex)) {
- end++
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else if (end === len && val.substring(start - 1, end).match(selRegex)) {
- start--
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else {
- if (sel.match(/~~.+~~/g)) {
- sel = sel.replace(/~~/g, '')
- } else {
- sel = `~~${sel}~~`
- }
- }
- }
- textarea.value = val.substring(0, start) + sel + val.substring(end, len)
- }
- },
- highlighter: {
- title: 'highlighted text',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = new RegExp(`\`(${sel.replace(/`/g, '')})\``)
- if (sel.match(selRegex)) {
- sel = sel.replace(selRegex, '$1')
- } else if (start > 0 && end < len) {
- if (val.substring(start - 1, end + 1).match(selRegex)) {
- start -= 1
- end += 1
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else {
- if (sel.match(/`.+`/g)) {
- sel = sel.replace(/`/g, '')
- } else {
- sel = `\`${sel.replace(/\n/g, '`\n`')}\``
- }
- }
- } else {
- if (!start && val.substring(start, end + 1).match(selRegex)) {
- end++
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else if (end === len && val.substring(start - 1, end).match(selRegex)) {
- start--
- sel = val.substring(start, end).replace(selRegex, '$1')
- } else {
- if (sel.match(/`.+`/g)) {
- sel = sel.replace(/`/g, '')
- } else {
- sel = `\`${sel.replace(/\n/g, '`\n`')}\``
- }
- }
- }
- textarea.value = val.substring(0, start) + sel + val.substring(end, len)
- }
- },
- 'list-ul': {
- title: 'unordered list',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = /^( {3})*- (.*)/
- if (sel.match(selRegex)) {
- if (sel.match(/^ {3}/)) {
- sel = sel.replace(/^ {3}/gm, '')
- } else {
- sel = sel.replace(/^- /gm, '')
- }
- } else if (!start || val.substring(start - 1, end).match(/^\n.*/)) {
- sel = `${val.substring(start - 1, end).match(/\n^.*/gm) || !start ? '' : '\n'}- ${sel.replace(/\n/g, '\n- ')}${val.substring(end, end + 2).match(/\n\n/) ? '' : val.substring(end, end + 1).match(/\n/) ? '\n' : '\n\n'}`
- } else if (val.substring(start - 1, end).match(selRegex)) {
- start--
- sel = val.substring(start, end).replace(/( {3})*- /g, '$1 - ')
- } else if (val.substring(start - 2, end).match(selRegex)) {
- start -= 2
- sel = val.substring(start, end).replace(/( {3})*- /g, '$1 - ')
- } else {
- sel = `\n- ${sel.replace(/\n/g, '\n- ')}${val.substring(end, end + 2).match(/\n\n/) || end === len ? '' : val.substring(end, end + 1).match(/\n/) ? '\n' : '\n\n'}`
- }
- textarea.value = val.substring(0, start) + sel + val.substring(end, len)
- }
- },
- 'list-ol': {
- title: 'ordered list',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = /^( {3})*\d+\. (.*)/gm
- if (sel.match(selRegex)) {
- if (sel.match(/^ {3}/)) {
- sel = sel.replace(/^ {3}/gm, '')
- } else {
- sel = sel.replace(/^\d+\. /gm, '')
- }
- } else if (!start || val.substring(start - 1, end).match(/^\n.*/)) {
- let countOl = 0
- sel = `${val.substring(start - 1, end).match(/\n^.*/gm) || !start ? '' : '\n'}0. ${sel.replace(/\n/g, () => {
- countOl++
- return `\n${countOl}. `
- })}${val.substring(end, end + 2).match(/\n\n/) ? '' : val.substring(end, end + 1).match(/\n/) ? '\n' : '\n\n'}`
- } else if (val.substring(start - 4, end).match(/( {3})*\d+\. (.*)/)) {
- start -= 4
- sel = val.substring(start, end).replace(/( {3})*(\d+\.) /g, ' $1$2 ')
- } else if (val.substring(start - 5, end).match(/( {3})*\d+\. (.*)/)) {
- start -= 5
- sel = val.substring(start, end).replace(/( {3})*(\d+\.) /g, ' $1$2 ')
- } else {
- let countOl = 0
- sel = `\n0. ${sel.replace(/\n/g, () => {
- countOl++
- return `\n${countOl}. `
- })}${val.substring(end, end + 2).match(/\n\n/) || end === len ? '' : val.substring(end, end + 1).match(/\n/) ? '\n' : '\n\n'}`
- }
- textarea.value = val.substring(0, start) + sel + val.substring(end, len)
- }
- },
- 'quote-right': {
- title: 'quote',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = /^>+\s.*/gm
- if (sel.match(selRegex)) {
- if (sel.match(/^> /gm)) {
- sel = sel.replace(/^> /gm, '')
- } else {
- sel = sel.replace(/(^>*)> /gm, '$1 ')
- }
- } else if (!start || val.substring(start - 1, end).match(/^\n.*/)) {
- sel = `${val.substring(start - 1, end).match(/\n^.*/gm) || !start ? '' : '\n'}> ${sel.replace(/\n/g, '\n> ')}${val.substring(end, end + 2).match(/\n\n/) ? '' : val.substring(end, end + 1).match(/\n/) ? '\n' : '\n\n'}`
- } else if (val.substring(start - 1, end).match(selRegex)) {
- start--
- sel = val.substring(start, end).replace(/(^>*)\s/gm, '$1> ')
- } else if (val.substring(start - 2, end).match(selRegex)) {
- start -= 2
- sel = val.substring(start, end).replace(/(^>*)\s/gm, '$1> ')
- } else {
- sel = `\n> ${sel.replace(/\n/g, '\n> ')}${val.substring(end, end + 2).match(/\n\n/) || end === len ? '' : val.substring(end, end + 1).match(/\n/) ? '\n' : '\n\n'}`
- }
- textarea.value = val.substring(0, start) + sel + val.substring(end, len)
- }
- },
- code: {
- title: 'block of code',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = new RegExp(`^ {4}(.*)`, 'gm')
- if (sel.match(selRegex)) {
- sel = sel.replace(/^ {4}/gm, '')
- } else if (start === 0 || val.substring(start - 1, end).match(/\n.*/gm)) {
- if (sel.match(/^ {4}/gm)) {
- sel = sel.replace(/^ {4}/gm, '')
- } else {
- sel = `${start === 0 ? '' : val.substring(start - 1, end).match(/^\n/) ? '\n' : '\n\n'} ${sel.replace(/\n/g, '\n ')}`
- }
- } else {
- sel = `${val.substring(start - 1, end).match(/^\n/) ? '\n' : '\n\n'} ${sel.replace(/\n^(.*)/gm, '\n $1')}${val.substring(end, end + 1).match(/\n/) ? '' : '\n'}`
- }
- textarea.value = val.substring(0, start) + sel + val.substring(end, len)
- }
- },
- link: {
- title: 'insert link',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = /^(?!!)\[(.*)\]\((\S*)( ".*")?\)/
- if (sel.match(selRegex)) {
- textarea.value = val.substring(0, start) + sel.replace(selRegex, '$1 $2') + val.substring(end, len)
- } else {
- let link = ''
- if (!sel.match(/!\[(.*)\]\((\S*)( ".*")?\)/)) {
- link = sel.match(/https?:\/\/\S*/) || ''
- sel = sel
- .replace(link[0], '')
- .replace(/ +/g, ' ')
- .trim()
- }
- const divModal = $(``)
- $('.navbar-header>div:last-child').append(divModal)
- setTimeout(() => {
- document.body.classList.add('v--modal-block-scroll')
- $('#markdown').style.opacity = 1
- }, 1)
- $('#markdown-text').value = sel ? sel : ''
- $('#markdown-link').value = link ? link[0] : ''
- $('.close').addEventListener('click', () => {
- document.body.classList.remove('v--modal-block-scroll')
- $('#markdown').outerHTML = ''
- })
- $('#markdown-done').addEventListener('click', () => {
- sel = `[${$('#markdown-text').value}](${$('#markdown-link').value}${$('#markdown-hover').value ? ` "${$('#markdown-hover').value}"` : ''})`
- textarea.value = val.substring(0, start) + sel + val.substring(end, len)
- document.body.classList.remove('v--modal-block-scroll')
- $('#markdown').outerHTML = ''
- })
- }
- }
- },
- image: {
- title: 'insert image',
- replaceFunc: (val, len, start, end, sel) => {
- const selRegex = /!\[(.*)\]\((\S*)( ".*")?\)/
- if (sel.match(selRegex)) {
- textarea.value = val.substring(0, start) + sel.replace(selRegex, '$1 $2') + val.substring(end, len)
- } else {
- let link = ''
- if (!sel.match(/\[(.*)\]\((\S*)( ".*")?\)/)) {
- link = sel.match(/https?:\/\/\S*/) || ''
- sel = sel
- .replace(link[0], '')
- .replace(/ +/g, ' ')
- .trim()
- } else {
- sel = ''
- }
- const divModal = $(``)
- $('.navbar-header>div:last-child').append(divModal)
- setTimeout(() => {
- document.body.classList.add('v--modal-block-scroll')
- $('#markdown').style.opacity = 1
- }, 1)
- $('#markdown-text').value = sel ? sel : ''
- $('#markdown-link').value = link ? link[0] : ''
- $('.close').addEventListener('click', () => {
- document.body.classList.remove('v--modal-block-scroll')
- $('#markdown').outerHTML = ''
- })
- $('#markdown-done').addEventListener('click', () => {
- const tag = `.value}${$('#markdown-hover').value ? ` "${$('#markdown-hover').value}"` : ''})`
- sel = val.substring(start, end)
- if (!sel.match(/\[(.*)\]\((\S*)( ".*")?\)/)) {
- textarea.value = val.substring(0, start) + tag + val.substring(end, len)
- } else {
- textarea.value = val.substring(0, start) + sel.replace(/\[.*\]/, `[${tag}]`) + val.substring(end, len)
- }
- document.body.classList.remove('v--modal-block-scroll')
- $('#markdown').outerHTML = ''
- })
- }
- }
- }
- }
- const textarea = $('#input-comment')
- if (textarea) {
- const getSelectedText = e => {
- const val = textarea.value
- const len = val.length
- const start = textarea.selectionStart
- const end = textarea.selectionEnd
- const sel = val.substring(start, end)
- markdown[`${e.target.id}`].replaceFunc(val, len, start, end, sel)
- }
- const markdownDiv = $('')
- Object.keys(markdown).forEach(x => markdownDiv.appendChild($(``)))
- textarea.insertAdjacentHTML('beforebegin', markdownDiv.outerHTML)
- ;[...$('#markdown-editor').children].forEach(x => x.addEventListener('click', getSelectedText))
- }
- }
- // Enhance menu for higher resolutions
- let p = $('.navbar-toggle').parentNode
-
- p.appendChild($(''))
- p.appendChild($(''))
- p.appendChild($(''))
- p.appendChild($(''))
- p.appendChild($(''))
- p.appendChild($(''))
- p.appendChild($(''))
- p.appendChild($(''))
- p.appendChild($(''))
- p.appendChild($(''))
- p.appendChild($(''))
- p.appendChild($(''))
- // Let users with screens narrow enough so top bar isn't visible still use toggle light function
- $('#main-menu').insertAdjacentHTML('afterbegin', ' Toggle light')
-
- p = $('.btn-menu-player')
- if (p) {
- const userlink = $('.player-dropdown a[href^="/player/"]').href
- const useravatar = $('.btn-menu-player').innerHTML
- const element = $(`${useravatar}`)
- p.parentNode.appendChild(element)
- }
-
- // Tell to look at settings if freshly installed
- /*const newSettingsSeen = localStorage.getItem('anbt_newSettingsSeen')
- if (!newSettingsSeen && window.innerWidth > 974) {
- const freshSettingsHint = 'Thanks for choosing ANBT! Script settings are on the settings page, click to remove this hint.'
- if (!options.newCanvas) {
- freshSettingsHint += " Don't forget to try the new canvas!"
- }
- $('#menusettings').setAttribute('title', '')
- $("#menusettings").tooltip({
- container: "body",
- placement: "bottom",
- title: freshSettingsHint
- });
- //$("#menusettings").tooltip("show");
- const freshHintRemove = () => {
- localStorage.setItem('anbt_newSettingsSeen', 1)
- }
- $('#menusettings').addEventListener('click', freshHintRemove)
- $('#menusettings').addEventListener('mousedown', freshHintRemove)
- $('#menusettings').addEventListener('touchstart', freshHintRemove)
- }*/
- // Make new notifications actually discernable from the old ones
- let num = $('#user-notify-count')
- if (num) num = num.textContent.trim()
- GM_addStyle(`#user-notify-list .list-group .list-group-item .fas {color: #888}#user-notify-list .list-group .list-group-item:nth-child(-n+${num}) .fas {color: #2F5}a.wrong-order {color: #F99} div.comment-holder:target {background-color: #DFD}.comment-new a.text-muted:last-child:after {content: 'New'; color: #2F5; font-weight: bold; background-color: #183; border-radius: 9px; display: inline-block; padding: 0px 6px; margin-left: 10px;}`)
-
- // Show an error if it occurs instead of "loading forever"
- window.getNotifications = () => {
- if (!notificationsOpened) {
- $('#user-notify-list').innerHTML = '
'
- const xhr = new XMLHttpRequest()
- xhr.open('GET', '/notification/view/')
- xhr.onload = () => {
- if (xhr.status === 200) {
- $('#user-notify-list').innerHTML = xhr.responseText
- $('#user-notify-count').textContent = '0'
- notificationsOpened = true
- } else {
- '#user-notify-list'.innerHTML = xhr.responseText
- notificationsOpened = true
- }
- }
- }
- }
-
- let versionDisplay
- try {
- const appver = $('script[src^="/build/app"]').src.match(/(\w+)\.js$/)[1]
- const runtimever = $('script[src^="/build/runtime"]').src.match(/(\w+)\.js$/)[1]
- versionDisplay = `ANBT v${SCRIPT_VERSION} | app ${appver}`
- if (appver !== SITE_VERSION) versionDisplay += '*'
- versionDisplay += ` | runtime ${runtimever}`
- if (runtimever !== '1ba6bf05') versionDisplay += '*!!!' // didn't break with one update, hurray
- } catch (e) {
- versionDisplay = `ANBT v${SCRIPT_VERSION}`
- }
- const h = $('.wrapper')
- if (h) h.appendChild($(`${versionDisplay}
`))
-
- $('.footer-main .list-unstyled')[0].appendChild($('ANBT script'))
- $('.footer-main .list-unstyled')[1].appendChild($('Wiki'))
- $('.footer-main .list-unstyled')[2].appendChild($('Chat (Discord)'))
-
- if (options.newCanvas) {
- const directToNewSandbox = function(e) {
- if (e.which === 2) return
- e.preventDefault()
- setupNewCanvas(true, this.href)
- }
- const directToNewPlay = function(e) {
- if (e.which === 2) return
- e.preventDefault()
- setupNewCanvas(false, this.href)
- }
- $('a[href^="/sandbox/"]', true).forEach(x => x.addEventListener('click', directToNewSandbox))
- $('a[href="/play/"]', true).forEach(x => x.addEventListener('click', directToNewPlay))
- }
- }
-
- const mark = document.createElement('b')
- mark.id = '_anbt_'
- mark.style.display = 'none'
- document.body.appendChild(mark)
- if (pagodaBoxError()) return
-
- if (typeof DrawceptionPlay === 'undefined') {
- // Fix for Chrome new loading algorithm, apparently
- let loader = setInterval(() => {
- if (typeof DrawceptionPlay === 'undefined') return
- pageEnhancements()
- clearInterval(loader)
- }, 100)
- } else {
- pageEnhancements()
- }
-} // wrapped
-
-// From http://userstyles.org/styles/93911/dark-gray-style-for-drawception-com
-localStorage.setItem(
- 'gpe_darkCSS',
- (
- 'a{color:#77c0ff$}.wrapper{~#444$}#nav-drag{~#353535$}.btn-default{~#7f7f7f$;border-bottom-color:#666$;border-left-color:#666$;border-right-color:#666$;border-top-color:#666$;color:#CCC$}' +
- '.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{~#757575$;border-bottom-color:#565656$;border-left-color:#565656$;border-right-color:#565656$;border-top-color:#565656$;color:#DDD$}' +
- '.btn-success{~#2e2e2e$;border-bottom-color:#262626$;border-left-color:#262626$;border-right-color:#262626$;border-top-color:#262626$;color:#CCC$}' +
- '.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{~#232323$;border-bottom-color:#1c1c1c$;border-left-color:#1c1c1c$;border-right-color:#1c1c1c$;border-top-color:#1c1c1c$;color:#DDD$}' +
- '.btn-primary{~#213184$;border-bottom-color:#1a1a68$;border-left-color:#1a1a68$;border-right-color:#1a1a68$;border-top-color:#1a1a68$;color:#CCC$}' +
- '.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{~#191964$;border-bottom-color:#141450$;border-left-color:#141450$;border-right-color:#141450$;border-top-color:#141450$;color:#DDD$}' +
- '.btn-info{~#2d7787$;border-bottom-color:#236969$;border-left-color:#236969$;border-right-color:#236969$;border-top-color:#236969$;color:#CCC$}' +
- '.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{~#1c5454$;border-bottom-color:#133939$;border-left-color:#133939$;border-right-color:#133939$;border-top-color:#133939$;color:#DDD$}' +
- '.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{~#3b3b3b$}.navbar-toggle{~#393939$}.navbar{border-bottom:1px solid #000$}.forum-thread-starter,.breadcrumb,.regForm{~#555$}' +
- '.form-control{~#666$;border:1px solid #333$;color:#EEE$}code,pre{~#656$;color:#FCC$}body{color:#EEE$}footer{~#333$;border-top:1px solid #000$}' +
- '.pagination>li:not(.disabled):not(.active),.pagination>li:not(.disabled):not(.active)>a:hover,.pagination>li:not(.disabled):not(.active)>span:hover,.pagination>li:not(.disabled):not(.active)>a:focus,.pagination>li:not(.disabled):not(.active)>span:focus{~#444$}.pagination>li>a,.pagination>li>span{~#555$;border:1px solid #000$}' +
- '.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{~#666$;border-top:1px solid #444$;border-bottom:1px solid #444$}' +
- '.drawingForm{~#555$}.well{~#666$;border:1px solid #333$}#timeleft{color:#AAA$}legend{border-bottom:1px solid #000$}.thumbpanel{color:#EEE;~#555$}.thumbpanel img{~#fffdc9$}.panel-number,.modal-content,.profile-user-header{~#555$}' +
- '#commentForm{~#555$;border:1px solid #000$}.modal-header,.nav-tabs{border-bottom:1px solid #000$}hr,.modal-footer{border-top:1px solid #000$}' +
- '.store-item{background:#666$;~-moz-linear-gradient(top,#666 0,#333 100%)$;~-webkit-gradient(linear,left top,left bottom,color-stop(0,#666),color-stop(100%,#333))$;~-webkit-linear-gradient(top,#666 0,#333 100%)$;~-o-linear-gradient(top,#666 0,#333 100%)$;~-ms-linear-gradient(top,#666 0,#333 100%)$;~linear-gradient(to bottom,#666 0,#333 100%)$;border:1px solid #222$}' +
- '.store-item:hover{border:1px solid #000$}.store-item-title{~#222$;color:#DDD$}.store-title-link{color:#DDD$}.profile-award{~#222$}.profile-award-unlocked{~#888$}.progress-bar{color:#CCC$;~#214565$}.progress{~#333$}' +
- '.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(.25,rgba(0,0,0,0.15)),color-stop(.25,transparent),color-stop(.5,transparent),color-stop(.5,rgba(0,0,0,0.15)),color-stop(.75,rgba(0,0,0,0.15)),color-stop(.75,transparent),to(transparent))$;background-image:-webkit-linear-gradient(45deg,rgba(0,0,0,0.15) 25%,transparent 25%,transparent 50%,rgba(0,0,0,0.15) 50%,rgba(0,0,0,0.15) 75%,transparent 75%,transparent)$;background-image:-moz-linear-gradient(45deg,rgba(0,0,0,0.15) 25%,transparent 25%,transparent 50%,rgba(0,0,0,0.15) 50%,rgba(0,0,0,0.15) 75%,transparent 75%,transparent)$;background-image:linear-gradient(45deg,rgba(0,0,0,0.15) 25%,transparent 25%,transparent 50%,rgba(0,0,0,0.15) 50%,rgba(0,0,0,0.15) 75%,transparent 75%,transparent)$}' +
- '.progress-bar-success{~#363$}.progress-bar-info{~#367$}.progress-bar-warning{~#863$}.progress-bar-danger{~#733$}' +
- '.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#DDD$;~#555$;border:1px solid #222$}.nav>li>a:hover,.nav>li>a:focus{~#333$;border-bottom-color:#222$;border-left-color:#111$;border-right-color:#111$;border-top-color:#111$}' +
- '.nav>li.disabled>a,.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#555$}.table-striped>tbody>tr:nth-child(2n+1)>td,.table-striped>tbody>tr:nth-child(2n+1)>th{~#333$}' +
- '.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{~#555$}.table thead>tr>th,.table tbody>tr>th,.table tfoot>tr>th,.table thead>tr>td,.table tbody>tr>td,.table tfoot>tr>td{border-top:1px solid #333$}.news-alert{~#555$;border:2px solid #444$}' +
- '.btn-menu{~#2e2e2e$}.btn-menu:hover{~#232323$}.btn-yellow{~#8a874e$}.btn-yellow:hover{~#747034$}' +
- 'a.label{color:#fff$}.text-muted,a.text-muted{color:#999$}a.wrong-order{color:#F99$}div.comment-holder:target{~#454$}' +
- '.popover{~#777$}.popover-title{~#666$;border-bottom:1px solid #444$}.popover.top .arrow:after{border-top-color:#777$}.popover.right .arrow:after{border-right-color:#777$}.popover.bottom .arrow:after{border-bottom-color:#777$}.popover.left .arrow:after{border-left-color:#777$}' +
- '.label-fancy{~#444$;border-color:#333$;color:#FFF$}' +
- '.avatar,.profile-avatar{~#444$;border:1px solid #777$;}' +
- '.bg-lifesupport{~#444$}body{~#555$}.snap-content{~#333$}' +
- 'select,textarea{color:#000$}.help-block{color:#ddd$}.jumbotron{~#444$}' +
- '.navbar-dropdown{~#444$}a.list-group-item{~#444$;color:#fff$;border:1px solid #222$}a.list-group-item:hover,a.list-group-item:focus{~#222$}' +
- '.likebutton.btn-success{color:#050$;~#5A5$}.likebutton.btn-success:hover{~#494$}' +
- ".thumbnail[style*='background-color: rgb(255, 255, 255)']{~#555$}" +
- '.popup,.v--modal{~#666$;border:1px solid #222$}.btn-reaction{~#666$;border:none$;color:#AAA$}@media(min-width:625px){.create-game-wrapper{~#555$}}' +
- '.profile-header{~#555$}.profile-nav > li > a{~#333$}.profile-nav>li.active>a,.profile-nav>li>a:hover{~#555$}' +
- '.gsc-control-cse{~#444$;border-color:#333$}.gsc-above-wrapper-area,.gsc-result{border:none$}.gs-snippet{color:#AAA$}.gs-visibleUrl{color:#8A8$}a.gs-title b,.gs-visibleUrl b{color:#EEE$}.gsc-adBlock{display:none$}.gsc-input{~#444$;border-color:#333$;color:#EEE$}' +
- '.comment-highlight{border:none$;background:#454$}#header-emotes{~#555$}#header-bar-container{border:none$}.paypal-button-tag-content{color:#EEE$}.numlikes{color:#EEE$}.gsc-input-box{~#444$;border-color:#333$}.gsc-completion-container{~#333$;border-color:#000$}.gsc-completion-selected{~#222$}.gsc-completion-container b{color:#AAA$}.alert-nice{~#4a4a4a$}.store-buy-coins{~#777$}.store-buy-coins:hover{~#666$}.store-buy-coins>h2,.store-buy-coins>h2>small{color:#EEE$}.store-package-selector{~#888$}.store-package-selector>label{color:#EEE$}.label-stat{~#444$;color:#EEE$;border:1px solid #555$}.label-stat.disabled{~#333$}.option{padding:4px 8px$;~#666$;color:#EEE$;border-color:#333$}.option.selected{border-color:#EEE$}.sleek-select{~#666$;border-color:#333$}select{color:#EEE$}.modal-note{color:#EEE$}.vue-dialog-button{~#555$;border:none$}.vue-dialog-button:hover{~#5a5a5a$}.vue-dialog-buttons{border-top:1px solid #222$}.dashboard-item{~#333$}legend{color:#EEE$}.list-group-item{~#444$;color:#EEE$;border:1px solid #222$}.alert-warning{color:#EEE$;~#555$;border-color:#555$}.btn-reaction.active{border:1px solid #EEE$}.bg-shadow-box{~#333$}.btn-gray{~#222$;border:none$}.btn-gray:hover{color:#EEE$;~#1a1a1a$}.btn-bright{~#333$;color:#EEE$}' +
- '.player-name-new{color:#33b73f$}.gsc-tabsArea>div{overflow:hidden$}.gs-image-popup-box{~#333$;border-color:#222$}.gs-size{color:#6f6f6f$}.gsc-result-info{color:#EEE$}.gsc-refinementsArea{border:none$}.gsc-tabsArea{border-bottom-color:#333$}.gsc-cursor-page{color:#EEE$}.gsc-cursor-current-page{color:#AAA$}.profile-nav>.disabled>a{color:#555$;~#3a3a3a$}.profile-nav>.disabled>a:hover{~#3a3a3a$}.sleek-select:hover{border-color:#EEE$}' +
- '.btn-menu{border-color:#1e1e1e$;text-shadow:0px 0px 3px #777$}.btn-menu:hover{border-color:#1e1e1e$}.pagination>.active>span{color:#EEE$}#btn-notifications{color:#EEE$}.btn-warning{color:#EEE$}.alert-nice{color:#EEE$}.emotes-popup{~#2e2e2e$}.navbar-toggle{~#2e2e2e$;border-color:#1e1e1e$}.navbar-toggle .icon-bar{~#EEE$}' +
- '.gamepanel-highlight{box-shadow:0 0 20px #111$;~#222$}' +
- // We have entered specificity hell...
- 'a.anbt_replaypanel:hover{color:#8af$}' +
- '.anbt_favedpanel{color:#d9534f$}' +
- // Some lamey compression method!
- ''
- )
- .replace(/~/g, 'background-color:')
- .replace(/\$/g, ' !important')
-)
-
-let settings = localStorage.getItem('gpe_anbtSettings')
-settings = settings ? JSON.parse(settings) : {}
-
-if (settings.anbtDarkMode || typeof settings.anbtDarkMode === 'undefined') {
- if (parseInt(localStorage.getItem('gpe_inDark'), 10) == 1) {
- const css = document.createElement('style')
- css.id = 'darkgraycss'
- css.type = 'text/css'
- css.appendChild(document.createTextNode(localStorage.getItem('gpe_darkCSS')))
- if (document.head) {
- document.head.appendChild(css)
- } else {
- let darkLoad = setInterval(() => {
- if (!document.head) return
- document.head.appendChild(css)
- clearInterval(darkLoad)
- }, 100)
- }
- }
-}
-
-const anbtLoad = () => {
- if (document.getElementById('_anbt_')) return
- const script = document.createElement('script')
- script.textContent = `(${wrapped.toString()})()`
- document.body.appendChild(script)
-}
-
-if (document && document.body) {
- anbtLoad()
- if (window.opera && parseInt(localStorage.getItem('gpe_operaWarning'), 10) !== 1) {
- const w = document.createElement('h2')
- w.innerHTML = 'ANBT speaking:
Rename your script file so it doesn\'t contain ".user." part for smoother loading!
This warning is only shown once.'
- const m = document.getElementById('main')
- m.insertBefore(w, m.firstChild)
- localStorage.setItem('gpe_operaWarning', 1)
- }
-}
-document.addEventListener('DOMContentLoaded', anbtLoad, false)
diff --git a/newcanvas/drawit.css b/newcanvas/drawit.css
deleted file mode 100644
index d4cec62..0000000
--- a/newcanvas/drawit.css
+++ /dev/null
@@ -1,526 +0,0 @@
-@font-face {
- font-family: 'Yanone Kaffeesatz';
- font-style: normal;
- font-weight: 400;
- src: local('Yanone Kaffeesatz Regular'), local('YanoneKaffeesatz-Regular'), url('yanone.woff') format('woff');
-}
-@font-face {
- font-family: 'Nunito';
- font-style: normal;
- font-weight: 400;
- src: local('Nunito-Regular'), url('nunito.woff') format('woff');
-}
-body {
- margin: 0;
- font-family: 'Nunito', sans-serif;
- background: #555;
-}
-.noselect {
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-#newcanvasyo {
- background: #555;
-}
-#newcanvasyo.play .onlysandbox,
-#newcanvasyo.sandbox .onlyplay {
- display: none;
-}
-#myheader {
- font-size: 15pt;
- line-height: 49px;
- height: 49px;
- border-bottom: 1px solid black;
- background: #333;
- text-align: center;
- vertical-align: middle;
- color: #999;
- overflow: hidden;
- display: block;
-}
-a {
- color: #999;
-}
-a.prominent {
- color: #7af;
-}
-a.prominent:hover {
- color: #9ff;
-}
-#menu {
- display: none;
- position: absolute;
- background: #666;
- color: #ddd;
- z-index: 2;
- border: 2px solid #777;
- box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
- list-style-type: none;
- padding: 0;
- margin: 0;
- font-size: 13pt;
- text-align: left;
-}
-#menu.open {
- display: block;
-}
-#menu li {
- line-height: 49px;
- height: 49px;
- padding: 0 10px;
- cursor: pointer;
-}
-#menu li:hover {
- background: #777;
-}
-#menu hr {
- margin: 5px;
- border: 1px solid #444;
-}
-#noscriptwarn {
- color: #800;
- padding: 10px;
- font-size: 15pt;
- background: #faa;
- text-align: center;
-}
-#drawthis {
- padding: 4px;
- color: #fff;
- font-size: 26pt;
- font-family: 'Yanone Kaffeesatz';
- text-align: center;
- vertical-align: middle;
- display: table-cell;
- width: 1%;
-}
-#drawthis:before {
- color: #aaa;
- font-size: 14pt;
- font-family: 'Nunito';
- content: 'Draw this:';
- padding-right: 1em;
- width: 1%;
- text-align: right;
- vertical-align: middle;
- margin-left: -10%;
-}
-#emptytitle {
- height: 10px;
-}
-#bl {
- width: 600px;
- margin: auto;
- position: relative;
-}
-#toolpane {
- text-align: center;
- padding: 0 10px;
-}
-#infopane {
- text-align: center;
- padding: 0 10px;
-}
-.panel {
- border: 2px solid #888;
- border-radius: 15px;
- border-top: none;
- background: #444;
- margin: 3px 0;
-}
-#timer {
- font-size: 26pt;
- color: #aaa;
- width: 176px;
- float: left;
-}
-#palettechooser {
- display: none;
- position: absolute;
- width: 300px;
- background: #666;
- color: #ddd;
- z-index: 1;
- -webkit-columns: 2;
- -moz-columns: 2;
- columns: 2;
- -webkit-column-gap: 0;
- -moz-column-gap: 0;
- column-gap: 0;
- border: 2px solid #777;
- box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
-}
-#palettechooser.open {
- display: block;
-}
-#palettechooser div {
- padding: 10px 0 20px;
- cursor: pointer;
- break-inside: avoid;
-}
-#palettechooser div:hover {
- background-color: #777;
- color: #eee;
-}
-#colors {
- width: 100px;
- float: left;
-}
-#colors b {
- float: left;
- display: block;
- width: 50px;
- height: 44px;
- line-height: 42px;
- cursor: pointer;
-}
-#colors b.hint:after {
- content: '';
- position: absolute;
- border-radius: 50%;
- margin: 32px 2px;
- width: 5px;
- height: 5px;
- background-color: white;
- border: 1px solid #000;
-}
-#colors b.hint:before {
- opacity: 0.6;
-}
-#colors b:before {
- font-size: 10pt;
- opacity: 0.3;
- color: #000;
-}
-#colors b:hover:before {
- opacity: 0.4;
- color: #fff;
-}
-#palettename {
- color: #aaa;
- font-size: 10pt;
- padding: 0 5px;
- cursor: pointer;
-}
-#palettename:hover {
- color: #ccc;
-}
-.sandbox #palettename:after {
- content: ' \25BC';
-}
-#colors #eraser:before {
- content: 'eraser';
-}
-#colors b {
- counter-increment: color;
-}
-#colors b:before {
- content: counter(color);
-}
-#colors b:nth-child(10) {
- counter-reset: color 1;
-}
-#colors b:nth-child(n+10) {
- counter-increment: color;
-}
-#colors b:nth-child(n+10):before {
- content: '\2191' counter(color);
-}
-#colors.setbackground b:before {
- content: 'BG ' counter(color);
-}
-#colors.setbackground b:nth-child(n+10):before {
- content: 'BG\2191' counter(color);
-}
-#colors.setbackground #eraser:before {
- content: 'cancel';
-}
-#colors div {
- clear: both;
-}
-#tools {
- width: 68px;
- float: right;
- padding: 5px 0;
-}
-#tools button, #openmenu {
- width: 55px;
- height: 44px;
- vertical-align: top;
- margin: 3px 0;
- padding: 0;
-}
-#brush0, #brush1, #brush2, #brush3,
-#setbackground, #undo, #redo, #trash,
-#play, #knob, #eraser, .eraser, #openmenu
-{
- background-image: url("newcanvasicons.png");
-}
-#brush0 { background-position: -2px -8px; }
-#brush1 { background-position: -62px -8px; }
-#brush2 { background-position: -122px -8px; }
-#brush3 { background-position: -182px -8px; }
-#brush0.sel { background-position: -2px -68px; }
-#brush1.sel { background-position: -62px -68px; }
-#brush2.sel { background-position: -122px -68px; }
-#brush3.sel { background-position: -182px -68px; }
-#setbackground { background-position: -242px -8px; }
-#setbackground.sel { background-position: -242px -68px; }
-#undo { background-position: -302px -8px; }
-#redo { background-position: -362px -8px; }
-#trash { background-position: -422px -8px; }
-#eraser { background-position: -365px -68px; background-color: pink; }
-.eraser { background-position: -425px -68px; background-color: pink; }
-#openmenu { background-position: -425px -68px; }
-button, #play {
- border: none;
- border-radius: 4px;
- background-color: #eee;
-}
-button:hover, #play:hover {
- background-color: #acf;
-}
-button:active, #play:active {
- background-color: #aaa;
-}
-button:disabled {
- background-color: #aaa;
-}
-#openmenu:after {
- content: "\2630";
- color: #fff;
- font-size: 16pt;
- opacity: 0.6;
-}
-#openmenu {
- background-color: #999;
-}
-#openmenu:hover {
- background-color: #57a;
-}
-#openmenu:active {
- background-color: #555;
-}
-#tools hr {
- border: 1px solid #888;
- width: 93%;
- margin: 8px auto;
-}
-#primary, #secondary {
- display:inline-block;
- width: 50px;
- border-radius: 0 0 0 13px;
- color: #fff;
-}
-#secondary {
- border-radius: 0 0 13px 0;
-}
-#gamemode {
- font-size: 13pt;
- color: #aaa;
- width: 176px;
- float: left;
-}
-#gamebuttons {
- font-size: 13pt;
- color: #aaa;
- width: 176px;
- float: left;
- padding: 5px 0;
-}
-#gamebuttons button {
- padding: 10px;
- margin: 3px 0;
- font-size: 10pt;
-}
-#submit {
- font-size: 16pt;
- width: 180px;
- height: 50px;
- background-color: #6d6;
-}
-#submit:hover {
- background-color: #1b7;
-}
-.guidelines {
- color: #fff;
- font-size: 10pt;
-}
-.guidelines ul {
- margin: 0;
- padding: 0 1em;
- text-align: left;
-}
-.guidelines li {
- color: #bbb;
-}
-#seekbar {
- width: 530px;
- height: 0px;
- margin: 20px 50px 0;
- background: #333;
- border: 10px solid #333;
- border-radius: 10px;
- cursor: pointer;
-}
-#knob {
- position: absolute;
- width: 48px;
- height: 38px;
- margin-top: -19px;
- margin-left: 492px; /* -10px min */
- border-radius: 10px;
- background-color: #fbb;
- background-position: -305px -71px;
-}
-#knob.smooth {
- transition: margin-left 0.1s ease-out;
-}
-#knob:hover {
- background-color: #fdd;
-}
-#play {
- background-position: -486px -11px;
- position: absolute;
- width: 48px;
- height: 38px;
- margin: -19px -59px;
- border-radius: 4px;
-}
-#play.pause {
- background-position: -546px -11px;
-}
-#wacomContainer {
- position: absolute;
- top: -10px;
- left: -10px;
-}
-@media screen and (min-width: 1000px) {
- #toolpane {
- width: 180px;
- height: 500px;
- position: absolute;
- margin-left: -200px;
- }
- #infopane {
- width: 180px;
- height: 500px;
- position: absolute;
- margin-left: 600px;
- top: 0;
- }
- #submit {
- position: absolute;
- bottom: 10px;
- left: 10px;
- width: 180px;
- height: 50px;
- }
-}
-@media screen and (max-width: 999px) {
- #myheader {
- font-size: 11pt;
- }
- #toolpane {
- width: 580px;
- margin: auto;
- }
- #toolpane:after {
- display: block;
- content: '';
- clear: both;
- }
- #infopane {
- width: 580px;
- margin: 40px 0;
- }
- #timer {
- float: right;
- width: 260px;
- }
- #colors {
- width: 300px;
- margin-left: 5px;
- clear: left;
- float: left;
- }
- #primary, #secondary {
- width: 150px;
- }
- #tools {
- width: 260px;
- }
- #tools button {
- margin: 0;
- }
- #gamebuttons {
- width: 390px;
- margin-left: 5px;
- }
-}
-#svgContainer {
- width: 600px;
- height: 500px;
- margin: auto;
- background: #fffdc9 url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGwAAAAVCAQAAAAJQsNPAAAAkUlEQVR4Xu2WgQbAMBBD9/8/vQ14KpC4UneqYurZ2eNGnnfouWLdsjwce59ikFCdk75ricGIQSEmhekcvRfE8s8jMJ9CdI7camLGYoQ0XzNjJukgRsaJkWFiKqhiLf8x2DAx6EExTV0Mns/sIPZnnBinJJb1h4p21BXrzSOpTZVF3VGCN4lB07U53+6H5Yr1zAdssNOdvbG/lgAAAABJRU5ErkJggg==') center no-repeat;
- cursor: crosshair;
-}
-#svgContainer.hidecursor {
- cursor: none;
-}
-#svgContainer.loading * {
- display: none;
-}
-#svgContainer canvas, #svgContainer svg {
- position: absolute;
-}
-#popup {
- display: none;
- position: absolute;
- width: 400px;
- height: 300px;
- margin: 50px;
- padding: 50px;
- opacity: 0.95;
- background: #444;
- color: #ddd;
- border-radius: 15px;
- text-align: center;
- z-index: 1;
- font-size: 20pt;
-}
-#popup.show {
- display: block;
-}
-#popup hr {
- border: 1px solid #888;
-}
-#popuptitle {
- color: #999;
- font-size: 25pt;
- margin: 10px;
-}
-#popupclose {
- display: block;
- position: absolute;
- width: 50px;
- height: 50px;
- background: #c44;
- color: #ddd;
- right: 0;
- top: 0;
- text-align: center;
- border-radius: 13px;
- cursor: pointer;
-}
-#popupclose:hover {
- background: #e77;
- color: #eee;
-}
-#popupclose:before {
- content: "\d7";
- font-size: 30pt;
- line-height: 40px;
-}
diff --git a/newcanvas/drawit.js b/newcanvas/drawit.js
deleted file mode 100644
index e1d03ba..0000000
--- a/newcanvas/drawit.js
+++ /dev/null
@@ -1,2761 +0,0 @@
-// Drawing in Time by Grom PE. Public domain.
-// Utilities
-function ID(id) {return document.getElementById(id);}
-function svgElement(name, attrs)
-{
- var el = document.createElementNS("http://www.w3.org/2000/svg", name);
- if (attrs)
- {
- var keys = Object.keys(attrs);
- for (var i = 0; i < keys.length; i++)
- {
- if (attrs[keys[i]] !== null) el.setAttribute(keys[i], attrs[keys[i]]);
- }
- }
- return el;
-}
-function require(script, callback)
-{
- var tag = document.querySelector('script[src="' + script + '"]');
- if (tag) return callback();
- tag = document.createElement("script");
- tag.src = script;
- tag.onload = callback;
- document.body.appendChild(tag);
-}
-function bytes2string(bytes)
-{
- var len = bytes.length;
- var arr = [];
- for (var i = 0; i < len; i++)
- {
- arr.push(String.fromCharCode(bytes[i]));
- }
- return arr.join("");
-}
-function string2bytes(binary_string)
-{
- var len = binary_string.length;
- var bytes = new Uint8Array(len);
- for (var i = 0; i < len; i++)
- {
- var ascii = binary_string.charCodeAt(i);
- bytes[i] = ascii;
- }
- return bytes;
-}
-function base642bytes(base64)
-{
- return string2bytes(atob(base64));
-}
-function node2string(node)
-{
- if ('outerHTML' in node)
- {
- return node.outerHTML;
- } else {
- var div = document.createElement("div");
- div.appendChild(node.cloneNode(true));
- return div.innerHTML;
- }
-}
-function unpack_uint16be(s)
-{
- return s.charCodeAt(0) << 8 | s.charCodeAt(1);
-}
-function unpack_int16be(s)
-{
- var v = unpack_uint16be(s);
- return v > 32767 ? v - 65536 : v;
-}
-function int16be(b1, b2)
-{
- var v = b1 << 8 | b2;
- return v > 32767 ? v - 65536 : v;
-}
-function unpack_uint32be(s)
-{
- return s.charCodeAt(0) << 24 | s.charCodeAt(1) << 16 | s.charCodeAt(2) << 8 | s.charCodeAt(3);
-}
-function pack_uint16be(n)
-{
- return String.fromCharCode(n >> 8 & 0xff, n & 0xff);
-}
-function pack_uint32be(n)
-{
- return String.fromCharCode(n >> 24 & 0xff, n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff);
-}
-function color2rgba(color)
-{
- var r = 0, g = 0, b = 0, a = 255;
- if (color.substr(0, 1) == "#")
- {
- if (color.length == 4)
- {
- r = color.substr(1, 1);
- g = color.substr(2, 1);
- b = color.substr(3, 1);
- r = parseInt(r + r, 16);
- g = parseInt(g + g, 16);
- b = parseInt(b + b, 16);
- } else {
- r = parseInt(color.substr(1, 2), 16);
- g = parseInt(color.substr(3, 2), 16);
- b = parseInt(color.substr(5, 2), 16);
- }
- } else if (color.substr(0, 4) == "rgba")
- {
- var tmp = color.split(/([\d\.]+)/);
- r = parseInt(tmp[1], 10);
- g = parseInt(tmp[3], 10);
- b = parseInt(tmp[5], 10);
- a = Math.floor(parseFloat(tmp[7]) * 255);
- }
- else if (color.substr(0, 3) == "rgb")
- {
- var tmp = color.split(/([\d\.]+)/);
- r = parseInt(tmp[1], 10);
- g = parseInt(tmp[3], 10);
- b = parseInt(tmp[5], 10);
- } else {
- // ?!
- }
- return [r, g, b, a];
-}
-function color2dword(color)
-{
- var c = color2rgba(color);
- return String.fromCharCode(c[0], c[1], c[2], c[3]);
-}
-function value2hex(val)
-{
- return (Math.floor(val/16)%16).toString(16)+(Math.floor(val)%16).toString(16);
-}
-function rgb2hex(r, g, b)
-{
- return "#" + value2hex(r) + value2hex(g) + value2hex(b);
-}
-function color2hex(color)
-{
- var c = color2rgba(color);
- return rgb2hex(c[0], c[1], c[2]);
-}
-function randomItem(l)
-{
- return l[Math.floor(Math.random() * l.length)];
-}
-function makeCRCTable()
-{
- var c;
- var crcTable = [];
- for(var n = 0; n < 256; n++)
- {
- c = n;
- for(var k = 0; k < 8; k++)
- {
- c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
- }
- crcTable[n] = c;
- }
- return crcTable;
-}
-function crc32(str, str2)
-{
- var crcTable = window.crcTable || (window.crcTable = makeCRCTable());
- var crc = 0 ^ (-1);
- for (var i = 0; i < str.length; i++)
- {
- crc = (crc >>> 8) ^ crcTable[(crc ^ str.charCodeAt(i)) & 0xFF];
- }
- if (str2)
- {
- for (var i = 0; i < str2.length; i++)
- {
- crc = (crc >>> 8) ^ crcTable[(crc ^ str2.charCodeAt(i)) & 0xFF];
- }
- }
- return (crc ^ (-1)) >>> 0;
-}
-/*
- (c) 2013, Vladimir Agafonkin
- Simplify.js, a high-performance JS polyline simplification library
- mourner.github.io/simplify-js
-*/
-// square distance between 2 points
-function getSqDist(p1, p2)
-{
- var dx = p1.x - p2.x,
- dy = p1.y - p2.y;
- return dx * dx + dy * dy;
-}
-// square distance from a point to a segment
-function getSqSegDist(p, p1, p2)
-{
- var x = p1.x,
- y = p1.y,
- dx = p2.x - x,
- dy = p2.y - y;
- if (dx !== 0 || dy !== 0)
- {
- var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
- if (t > 1)
- {
- x = p2.x;
- y = p2.y;
- } else if (t > 0) {
- x += dx * t;
- y += dy * t;
- }
- }
- dx = p.x - x;
- dy = p.y - y;
- return dx * dx + dy * dy;
-}
-// simplification using optimized Douglas-Peucker algorithm with recursion elimination
-function simplifyDouglasPeucker(points, sqTolerance)
-{
- var len = points.length,
- MarkerArray = typeof Uint8Array !== 'undefined' ? Uint8Array : Array,
- markers = new MarkerArray(len),
- first = 0,
- last = len - 1,
- stack = [],
- newPoints = [],
- i, maxSqDist, sqDist, index;
- markers[first] = markers[last] = 1;
- while (last)
- {
- maxSqDist = 0;
- for (i = first + 1; i < last; i++)
- {
- sqDist = getSqSegDist(points[i], points[first], points[last]);
- if (sqDist > maxSqDist)
- {
- index = i;
- maxSqDist = sqDist;
- }
- }
- if (maxSqDist > sqTolerance)
- {
- markers[index] = 1;
- stack.push(first, index, index, last);
- }
- last = stack.pop();
- first = stack.pop();
- }
- for (i = 0; i < len; i++)
- {
- if (markers[i]) newPoints.push(points[i]);
- }
- return newPoints;
-}
-function buildSmoothPath(points, path)
-{
- var dist1, dist2, angle1, angle2, prevtangent, tangent, t1, t2, x, y, p, c, n, l = points.length;
- var good;
- if (l < 2) return;
- path.pathSegList.initialize(path.createSVGPathSegMovetoAbs(points[0].x, points[0].y));
- path.pathSegList.appendItem(path.createSVGPathSegLinetoAbs(points[1].x, points[1].y));
- if (l < 3) return;
- for (var i = 1; i < l - 1; i++)
- {
- p = points[i - 1];
- c = points[i];
- n = points[i + 1];
- x = c.x - p.x;
- y = c.y - p.y;
- angle1 = Math.atan2(y, x);
- dist1 = Math.sqrt(x * x + y * y);
- x = n.x - c.x;
- y = n.y - c.y;
- angle2 = Math.atan2(y, x);
- dist2 = Math.sqrt(x * x + y * y);
- tangent = (angle1 + angle2) / 2;
- if (i > 1)
- {
- if (Math.abs(angle2 - angle1) >= Math.PI / 4)
- {
- path.pathSegList.appendItem(path.createSVGPathSegLinetoAbs(c.x, c.y));
- good = false;
- } else {
- if (good && dist1 / dist2 >= 0.4 && dist1 / dist2 <= 2.5)
- {
- t1 = {x: p.x + Math.cos(prevtangent) * dist1 * 0.4, y: p.y + Math.sin(prevtangent) * dist1 * 0.4};
- t2 = {x: c.x - Math.cos(tangent) * dist2 * 0.4, y: c.y - Math.sin(tangent) * dist2 * 0.4};
- path.pathSegList.appendItem(path.createSVGPathSegCurvetoCubicAbs(c.x, c.y, t1.x, t1.y, t2.x, t2.y));
- } else {
- path.pathSegList.appendItem(path.createSVGPathSegLinetoAbs(c.x, c.y));
- good = true;
- }
- }
- }
- prevtangent = tangent;
- }
- c = points[l - 1];
- path.pathSegList.appendItem(path.createSVGPathSegLinetoAbs(c.x, c.y));
-}
-
-var random_things = ['hobo', 'shoe', 'log', 'bun', 'sandwich', 'bull', 'beer', 'hair',
- 'hill', 'beans', 'man', 'sofa', 'dinosaur', 'road', 'plank', 'hole', 'food',
- 'hedgehog', 'pine', 'toad', 'tooth', 'candy', 'rock', 'drop', 'book', 'button', 'carpet',
- 'wheel', 'computer', 'box', 'cat', 'rat', 'hook', 'chunk', 'boat', 'spade', 'sack',
- 'hammer', 'face', 'soap', 'nose', 'finger', 'steam', 'spring', 'hand', 'fish',
- 'elephant', 'dog', 'chair', 'bag', 'phone', 'robot', 'axe', 'grass', 'crack', 'teacher',
- 'breadcrumb', 'fridge', 'worm', 'nut', 'cloth', 'apple', 'tongue', 'jar'];
-var random_acts = ['crazy from', 'thanks', 'hits', 'lies around on', 'sees', 'grows in',
- 'attaches to', 'flies from', 'crawls from', 'chews', 'walks on', 'squishes', 'pecks',
- 'wobbles in', 'smokes from', 'smokes', 'rides', 'eats', 'squeals from under',
- 'is lost in', 'spins in', 'stuck in', 'hooks', 'angry at', 'bends', 'drips on',
- 'rolls on', 'digs', 'crawls in', 'flies at', 'massages', 'dreams of', 'kills', 'pulls',
- "doesn't want", 'licks', 'shoots', 'falls off', 'falls in', 'crawls on', 'turns into',
- 'stuck to', 'jumps on', 'hides', 'hides in', 'disassembles', 'rips', 'dissolves',
- 'stretches', 'crushes', 'pushes', 'drowns in', 'pokes', 'runs away from', 'wants',
- 'scratches', 'throws', 'and', 'confused by', 'unimpressed by'];
-var random_descs = ['white', 'concrete', 'shiny', 'ill', 'big', 'ex', 'fast', 'happy',
- 'inside-out', 'hot', 'burning', 'thick', 'wooden', 'long', 'good', 'tattered', 'iron',
- 'liquid', 'frozen', 'green', 'evil', 'bent', 'rough', 'pretty', 'red', 'round',
- 'shaggy', 'bald', 'slow', 'wet', 'wrinkly', 'meaty', 'impudent', 'real', 'distraught',
- 'sharp', 'plastic', 'gift', 'squished', 'chubby', 'crumbling', 'horned', 'angry',
- 'sitting', 'stranded', 'dry', 'hard', 'thin', 'killer', 'walking', 'cold', 'wheezing',
- 'grunting', 'chirping', 'wide', 'electric', 'nuclear', 'confused', 'unimpressed'];
-function randomPhrase()
-{
- function randomBase()
- {
- switch (Math.floor(Math.random() * 3))
- {
- case 0: return [
- randomItem(random_descs),
- randomItem(random_things),
- ].join(' ');
- case 1: return [
- randomItem(random_descs),
- randomItem(random_things),
- randomItem(random_acts),
- randomItem(random_things),
- ].join(' ');
- case 2: return [
- randomItem(random_descs),
- randomItem(random_things),
- randomItem(random_acts),
- randomItem(random_descs),
- randomItem(random_things),
- ].join(' ');
- }
- return "Error!";
- }
- var s = randomBase();
- return s.charAt(0).toUpperCase() + s.substr(1);
-}
-function rgb2lab(rgb)
-{
- var r = rgb[0] / 255,
- g = rgb[1] / 255,
- b = rgb[2] / 255,
- x, y, z, l, a, b;
-
- r = rgb[0] > 10 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
- g = rgb[1] > 10 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
- b = rgb[2] > 10 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
-
- x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
- y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
- z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
-
- x /= 0.95047;
- z /= 1.08883;
-
- x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
- y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
- z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
-
- l = (116 * y) - 16;
- a = 500 * (x - y);
- b = 200 * (y - z);
-
- return [l, a, b];
-}
-function getColorDistance(rgb1, rgb2)
-{
- var lab1 = rgb2lab(rgb1);
- var lab2 = rgb2lab(rgb2);
- var l = lab2[0] - lab1[0];
- var a = lab2[1] - lab1[1];
- var b = lab2[2] - lab1[2];
- return Math.sqrt(l * l * 2 + a * a + b * b);
-}
-function getClosestColor(rgb, pal)
-{
- // Allow any color in sandbox
- if (ID("newcanvasyo").classList.contains("sandbox")) return rgb2hex(rgb[0], rgb[1], rgb[2]);
- var c, d, idx = 0, min = 999;
- for (var i = 0; i < pal.length; i++)
- {
- d = getColorDistance(rgb, color2rgba(pal[i]));
- if (d < min)
- {
- min = d;
- idx = i;
- }
- }
- c = color2rgba(pal[idx]);
- return rgb2hex(c[0], c[1], c[2]);
-}
-function getColorDistanceLab(lab1, lab2)
-{
- var l = lab2[0] - lab1[0];
- var a = lab2[1] - lab1[1];
- var b = lab2[2] - lab1[2];
- return Math.sqrt(l * l * 2 + a * a + b * b);
-}
-function getClosestColorLab(lab, pal)
-{
- var c, d, idx = 0, min = 999;
- for (var i = 0; i < pal.length; i++)
- {
- d = getColorDistanceLab(lab, rgb2lab(color2rgba(pal[i])));
- if (d < min)
- {
- min = d;
- idx = i;
- }
- }
- c = color2rgba(pal[idx]);
- return rgb2hex(c[0], c[1], c[2]);
-}
-function getColorAverage(c1, c2, bias)
-{
- // Bias:
- // 0 = c1
- // 0.5 = average
- // 1 = c2
- return [
- Math.round(c1[0] * bias + c2[0] * (1 - bias)),
- Math.round(c1[1] * bias + c2[1] * (1 - bias)),
- Math.round(c1[2] * bias + c2[2] * (1 - bias)),
- ];
-}
-
-var palettes = {
- "Normal": ['#000000', '#444444', '#999999', '#ffffff', '#603913', '#c69c6d',
- '#ffdab9', '#ff0000', '#ffd700', '#ff6600', '#16ff00', '#0fad00',
- '#00ffff', '#0247fe', '#ec008c', '#8601af', '#fffdc9'],
- "Sepia": ['#402305', '#503315', '#604325', '#705335', '#806345', '#907355',
- '#a08365', '#b09375', '#bfa284', '#cfb294', '#dfc2a4', '#ffe2c4'],
- "Grayscale": ['#000000', '#111111', '#222222', '#333333', '#444444', '#555555', '#666666',
- '#777777', '#888888', '#999999', '#c0c0c0', '#ffffff', '#eeeeee' ],
- "Black and white": ['#ffffff', '#000000'],
- "CGA": ['#555555', '#000000', '#0000aa', '#5555ff', '#00aa00', '#55ff55', '#00aaaa', '#55ffff',
- '#aa0000', '#ff5555', '#aa00aa', '#ff55ff', '#aa5500', '#ffff55', '#aaaaaa', '#ffffff'],
- "Gameboy": ['#8bac0f', '#9bbc0f', '#306230', '#0f380f'],
- "Neon": ['#ffffff', '#000000', '#adfd09', '#feac09', '#fe0bab', '#ad0bfb', '#00abff'],
- "Thanksgiving": ['#673718', '#3c2d27', '#c23322', '#850005', '#c67200', '#77785b',
- '#5e6524', '#cfb178', '#f5e9ce'],
- "Holiday": ['#3d9949', '#7bbd82', '#7d1a0c', '#bf2a23',
- '#fdd017', '#00b7f1', '#bababa', '#ffffff'],
- "Valentine's": ['#8b2158', '#a81f61', '#bb1364', '#ce0e62', '#e40f64', '#ff0000',
- '#f5afc8', '#ffccdf', '#e7e7e7', '#ffffff'],
- "Halloween": ['#444444', '#000000', '#999999', '#ffffff', '#603913', '#c69c6d',
- '#7a0e0e', '#b40528', '#fd2119', '#fa5b11', '#faa611', '#ffd700',
- '#602749', '#724b97', '#bef202', '#519548', '#b2bb1e'],
- "the blues": ['#b6cbe4', '#618abc', '#d0d5ce', '#82a2a1', '#92b8c1', '#607884',
- '#c19292', '#8c2c2c', '#295c6f'],
- "Spring": ['#9ed396', '#57b947', '#4d7736', '#365431', '#231302',
- '#3e2409', '#a66621', '#a67e21', '#ebbb49', '#ffc0cb', '#ffffff'],
- "Beach": ['#1ca4d2', '#65bbe2', '#6ab7bf', '#94cbda', '#9cbf80', '#d2e1ab',
- '#b8a593', '#d7cfb9', '#dc863e', '#f7dca2'],
- "DawnBringer 16": ['#140c1c', '#442434', '#30346d', '#4e4a4e', '#854c30', '#346524',
- '#d04648', '#757161', '#597dce', '#d27d2c', '#8595a1', '#6daa2c',
- '#d2aa99', '#6dc2ca', '#dad45e', '#deeed6'],
- "Freedom": ['#000000', '#2c3539', '#2b3856', '#002a6c', '#800080', '#a52a2a',
- '#c2113a', '#ff0000', '#ffd700', '#ffff00', '#ffffff'],
-
-};
-
-var anbt =
-{
- container: null,
- svg: svgElement("svg",
- {
- // Even though Opera complains to have failed to set xmlns attribute:
- // > Failed attribute on svg element: xmlns="http://www.w3.org/2000/svg".
- // this is necessary for loading a saved SVG which otherwise wouldn't
- // bind correct prototypes for functions such as path.pathSegList
- xmlns: "http://www.w3.org/2000/svg",
- version: "1.1",
- width: "600", height: "500",
- }),
- canvas: document.createElement("canvas"),
- canvasDisp: document.createElement("canvas"),
- svgDisp: svgElement("svg",
- {
- //xmlns: "http://www.w3.org/2000/svg",
- version: "1.1",
- width: "600", height: "500",
- "pointer-events": "none",
- }),
- svgHist: null,
- path: null,
- points: null,
- pngBase64: null,
- lastrect: 0,
- position: 0,
- isStroking: false,
- isPlaying: false,
- size: 14.4,
- smoothening: 1,
- palette: palettes.Normal,
- patternCache: {},
- delay: 100,
- unsaved: false,
- background: '#fffdc9',
- transparent: false,
- color: ['#000000', "eraser"],
- fastUndoLevels: 10,
- rewindCache: [],
- snap: false,
- fillNext: false,
- BindContainer: function(el)
- {
- this.container = el;
- this.canvas.width = 600;
- this.canvas.height = 500;
- this.canvas.style.background = this.background;
- this.ctx = this.canvas.getContext("2d");
- this.ctx.lineJoin = "round";
- this.ctx.lineCap = "round";
- this.container.appendChild(this.canvas);
- if (!navigator.userAgent.match(/\bPresto\b/))
- {
- this.canvasDisp.width = 600;
- this.canvasDisp.height = 500;
- this.ctxDisp = this.canvasDisp.getContext("2d");
- this.ctxDisp.lineJoin = "round";
- this.ctxDisp.lineCap = "round";
- this.container.appendChild(this.canvasDisp);
- } else {
- // Opera Presto is faster with SVG redrawing
- this.DrawDispLine = this.DrawDispLinePresto;
- }
- this.container.appendChild(this.svgDisp);
- var rect = svgElement("rect",
- {
- "class": "eraser",
- x: 0,
- y: 0,
- width: 600,
- height: 500,
- fill: this.background,
- }
- );
- this.svg.appendChild(rect);
- },
- FromOldSVG: function(buf) // TODO: This function is messy
- {
- var arr = [];
- for (var i = 0; i < buf.length; i++)
- {
- arr.push(String.fromCharCode(buf[i]));
- }
- var svgdata = arr.join("");
-
- var parser = new DOMParser();
- var svg = parser.parseFromString(svgdata, 'text/xml').documentElement;
- for (var i = 0; i < svg.childNodes.length; i++)
- {
- var el = svg.childNodes[i];
- if (el.nodeName == "path")
- {
- el.setAttribute("stroke-linejoin", "round");
- el.setAttribute("stroke-linecap", "round");
- el.setAttribute("fill", "none");
- points = [];
- var x, y;
- for (var j = 0; j < el.pathSegList.numberOfItems; j++)
- {
- var seg = el.pathSegList.getItem(j);
- if (seg.pathSegTypeAsLetter != "l")
- {
- x = seg.x;
- y = seg.y;
- points.push({x: x, y: y});
- } else {
- el.pathSegList.replaceItem(el.createSVGPathSegLinetoAbs(x, y + 0.001), j);
- }
- }
- if (points.length > 2)
- {
- points = simplifyDouglasPeucker(points, this.smoothening);
- buildSmoothPath(points, el);
- }
- el.orig = points;
- }
- }
- this.svg = svg;
- this.lastrect = 0;
- this.rewindCache.length = 0;
- this.position = this.svg.childNodes.length - 1;
- this.UpdateView();
- this.MoveSeekbar(1);
- // Here we assume first element of svg is background rect
- this.SetBackground(this.svg.childNodes[0].getAttribute("fill"));
- },
- PackPlayback: function(svg)
- {
- var arr = [color2dword(this.background)];
- var lastcolor = color2dword("#000000");
- var lastsize = 14.4;
- var lastx = -1, lasty = -1;
- var lastpattern = 0;
-
- for (var i = 1; i < svg.childNodes.length; i++)
- {
- var el = svg.childNodes[i];
- if (el.nodeName == "path")
- {
- var color = color2dword(el.getAttribute("stroke"));
- if (el.getAttribute("class") == "eraser") color = "\xFF\xFF\xFF\x00";
- var size = el.getAttribute("stroke-width");
- var fill = el.getAttribute("fill");
- var pattern = el.pattern || 0;
- if (color != lastcolor || size != lastsize)
- {
- arr.push(pack_uint16be(-1));
- arr.push(pack_uint16be(size * 100));
- arr.push(color);
- lastcolor = color;
- lastsize = size;
- }
- if (fill != "none")
- {
- arr.push(pack_uint16be(-4));
- arr.push(pack_uint16be(0));
- arr.push(color2dword(fill));
- }
- if (pattern != lastpattern)
- {
- arr.push(pack_uint16be(-3));
- arr.push(pack_uint16be(pattern));
- arr.push("\x00\x00\x00\x00"); // reserved for the future
- lastpattern = pattern;
- }
- lastx = el.orig[0].x;
- lasty = el.orig[0].y;
- arr.push(pack_uint16be(lastx));
- arr.push(pack_uint16be(lasty));
- for (var j = 1; j < el.orig.length; j++)
- {
- var dx = Math.round(el.orig[j].x - lastx);
- var dy = Math.round(el.orig[j].y - lasty);
- // Ignore repeating points
- if (dx === 0 && dy === 0) continue;
- arr.push(pack_uint16be(dx));
- arr.push(pack_uint16be(dy));
- lastx = el.orig[j].x;
- lasty = el.orig[j].y;
- }
- arr.push("\x00\x00\x00\x00");
- } else if (el.nodeName == "rect")
- {
- var color = color2dword(el.getAttribute("fill"));
- arr.push(pack_uint16be(-2));
- arr.push(pack_uint16be(0)); // reserved for the future
- arr.push(color);
- } else {
- throw new Error("Unknown node name: " + el.nodeName);
- }
- }
- var result = "\x05" + bytes2string(pako.deflate(string2bytes(arr.join(""))));
- return result;
- },
- UnpackPlayback: function(bytes)
- {
- var version = bytes[0];
- var start;
- if (version == 4 || version == 5)
- {
- bytes = pako.inflate(bytes.subarray(1));
- start = 0;
- } else if (version == 3)
- {
- bytes = string2bytes(pako.inflate(bytes.subarray(1), {to: "string"}));
- start = 0;
- } else if (version == 2)
- {
- start = 1;
- } else {
- throw new Error("Unsupported version: " + version);
- }
- var svg = svgElement("svg",
- {
- xmlns: "http://www.w3.org/2000/svg",
- version: "1.1",
- width: "600", height: "500",
- });
- var color = "#000000";
- var fill;
- var size = 14.4;
- var lastx, lasty, x, y;
- var pattern = 0;
- var points = [];
- // Ignore background alpha
- var background = [
- "rgb(",
- bytes[start],
- ',',
- bytes[start + 1],
- ',',
- bytes[start + 2],
- ')'
- ].join("");
- svg.background = background;
-
- svg.appendChild(svgElement("rect",
- {
- "class": "eraser",
- x: 0,
- y: 0,
- width: 600,
- height: 500,
- fill: background,
- }
- ));
-
- for (var i = start + 4; i < bytes.length;)
- {
- x = int16be(bytes[i], bytes[i + 1]);
- i += 2;
- y = int16be(bytes[i], bytes[i + 1]);
- i += 2;
- if (points.length)
- {
- if (x === 0 && y === 0)
- {
- var path = svgElement("path",
- {
- "class": color == "eraser" ? color : null,
- stroke: color == "eraser" ? background : color,
- "stroke-width": size,
- "stroke-linejoin": "round",
- "stroke-linecap": "round",
- fill: fill ? fill : "none",
- }
- );
- // Restore blots
- if (points.length === 1)
- {
- path.pathSegList.appendItem(path.createSVGPathSegMovetoAbs(lastx, lasty));
- path.pathSegList.appendItem(path.createSVGPathSegLinetoAbs(lastx, lasty + 0.001));
- } else {
- buildSmoothPath(points, path);
- }
- path.orig = points;
- path.pattern = pattern;
- svg.appendChild(path);
- points = [];
- fill = null;
- } else {
- x = x + lastx;
- y = y + lasty;
- lastx = x;
- lasty = y;
- points.push({x: x, y: y});
- }
- } else {
- if (x < 0)
- {
- if (x === -1 || x === -2)
- {
- color = [
- "rgba(",
- bytes[i],
- ',',
- bytes[i + 1],
- ',',
- bytes[i + 2],
- ',',
- bytes[i + 3] / 255,
- ')'
- ].join("");
- // TODO: fix ugly code
- if (color == "rgba(255,255,255,0)") color = "eraser";
- i += 4;
- if (x === -1)
- {
- size = y / 100;
- } else {
- svg.appendChild(svgElement("rect",
- {
- "class": color == "eraser" ? color : null,
- x: 0,
- y: 0,
- width: 600,
- height: 500,
- fill: color == "eraser" ? background : color,
- }
- ));
- }
- } else if (x === -3) {
- pattern = y;
- i += 4;
- } else if (x === -4) {
- fill = [
- "rgba(",
- bytes[i],
- ',',
- bytes[i + 1],
- ',',
- bytes[i + 2],
- ',',
- bytes[i + 3] / 255,
- ')'
- ].join("");
- i += 4;
- }
- } else {
- points.push({x: x, y: y});
- lastx = x;
- lasty = y;
- }
- }
- }
- return svg;
- },
- FindLastRect: function(endpos)
- {
- if (!endpos) endpos = this.svg.childNodes.length - 1;
- for (var i = endpos; i > 0; i--)
- {
- var el = this.svg.childNodes[i];
- if (el.nodeName == "rect") return i;
- }
- return 0;
- },
- CutHistoryBeforePosition: function()
- {
- for (var i = this.position - 1; i > 0; i--)
- {
- var el = this.svg.childNodes[i];
- this.svg.removeChild(el);
- }
- },
- CutHistoryBeforeClearAndAfterPosition: function()
- {
- var removing = false;
- for (var i = this.svg.childNodes.length - 1; i > 0; i--)
- {
- var el = this.svg.childNodes[i];
- if (removing || i > this.position)
- {
- this.svg.removeChild(el);
- }
- else if (el.nodeName == "rect" && i <= this.position)
- {
- removing = true;
- // Optimize out two eraser rectangles next to each other
- if (el.getAttribute("class") == "eraser")
- {
- this.svg.removeChild(el);
- }
- }
- }
- },
- MakePNG: function(width, height, fromBuffer)
- {
- // Cut all needless SVG data that comes before clearing whole canvas
- this.CutHistoryBeforeClearAndAfterPosition();
- this.MoveSeekbar(1);
-
- var canvas = document.createElement("canvas");
- canvas.width = width;
- canvas.height = height;
- var context = canvas.getContext("2d");
- if (!this.transparent)
- {
- context.fillStyle = this.background;
- context.fillRect(0, 0, width, height);
- }
- if (fromBuffer)
- {
- context.drawImage(this.canvas, 0, 0, width, height);
- } else {
- context.lineJoin = "round";
- context.lineCap = "round";
- context.save();
- context.scale(width / 600, height / 500);
- // Skip background rect
- for (var i = 1; i < this.svg.childNodes.length; i++)
- {
- this.DrawSVGElement(this.svg.childNodes[i], context);
- }
- context.restore();
- context.globalCompositeOperation = "destination-over";
- context.fillStyle = this.background;
- context.fillRect(0, 0, width, height);
- }
- this.pngBase64 = canvas.toDataURL("image/png");
-
- var version = "svGb";
- var svgstr = this.PackPlayback(this.svg);
- var padding = this.pngBase64.substr(-2);
- var prepend, custom, iend;
- // To append the custom chunk, we need to decode the end of the base64-encoded PNG
- // and then reattach as btoa((prepend) + (custom data) + (iend)).
- // As base64 encoding chunks are 3 bytes, iend chunk can start in the middle of those,
- // so (prepend) contains the data before iend chunk that we had to cut.
- if (padding == "==")
- {
- // Two padding characters
- cut = 1;
- } else if (padding[1] == "=")
- {
- // One padding character
- cut = 2;
- } else {
- // No padding
- cut = 3;
- }
- iend = atob(this.pngBase64.substr(-20)).substr(cut);
- prepend = atob(this.pngBase64.substr(-20)).substr(0, cut);
- custom = [
- prepend,
- pack_uint32be(svgstr.length),
- version,
- svgstr,
- pack_uint32be(crc32(version, svgstr)),
- iend
- ].join("");
- this.pngBase64 = this.pngBase64.substr(0, this.pngBase64.length - 20) + btoa(custom);
- },
- FromPNG: function(buffer)
- {
- var dv = new DataView(buffer);
- var magic = dv.getUint32(0);
- if (magic != 0x89504e47) throw new Error("Invalid PNG format: " + pack_uint32be(magic));
- for (var i = 8; i < buffer.byteLength; i += 4 /* Skip CRC */)
- {
- var chunklen = dv.getUint32(i);
- i += 4;
- var chunkname = pack_uint32be(dv.getUint32(i));
- i += 4;
- if (chunkname == "svGb")
- {
- var newsvg = this.UnpackPlayback(new Uint8Array(buffer, i, chunklen));
- this.svg = newsvg;
- // Assume saved data is always optimized and is cut before last rect
- //this.lastrect = this.FindLastRect();
- this.lastrect = 0;
- this.rewindCache.length = 0;
- this.position = this.svg.childNodes.length - 1;
- this.UpdateView();
- this.MoveSeekbar(1);
- // Here we assume first element of svg is background rect
- this.SetBackground(this.svg.background);
- return;
- } else {
- if (chunkname == "IEND") break;
- i += chunklen;
- }
- }
- throw new Error("No vector data found!");
- },
- FromURL: function(url)
- {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, true);
- if ('responseType' in xhr)
- {
- xhr.responseType = 'arraybuffer';
- } else {
- alert("Your browser is too old for this");
- return;
- }
- var _anbt = this;
- xhr.onload = function()
- {
- _anbt.FromPNG(this.response);
- };
- xhr.onerror = function()
- {
- alert("Error loading an image. Wrong URL?");
- };
- xhr.send();
- },
- FromLocalFile: function(forceAltMethod)
- {
- if (!this.fileInput)
- {
- this.fileInput = document.createElement("input");
- this.fileInput.style.position = "absolute";
- this.fileInput.style.top = "-1000px";
- this.fileInput.type = "file";
- this.fileInput.accept = ".png";
- document.body.appendChild(this.fileInput);
- var _anbt = this;
- this.fileInput.addEventListener("change", function(e)
- {
- var reader = new FileReader();
- reader.onload = function()
- {
- _anbt.FromPNG(this.result);
- };
- if (e.target.files[0])
- {
- reader.readAsArrayBuffer(e.target.files[0]);
- }
- },
- false
- );
- }
- if (!navigator.userAgent.match(/\bPresto\b/) && !forceAltMethod)
- {
- var clickEvent = document.createEvent("MouseEvent");
- clickEvent.initMouseEvent("click", true, true, window, 1,
- 0, 0, 0, 0, false, false, false, false, 0, null);
- this.fileInput.dispatchEvent(clickEvent);
- } else {
- setTimeout(this.fileInput.click.bind(this.fileInput), 1);
- }
- },
- SetBackground: function(color)
- {
- var transparent = color == "eraser";
- this.transparent = transparent;
- this.canvas.style.background = transparent ? "none" : color;
- // Normalize the color representation
- color = transparent ? "#ffffff" : color2hex(color);
- this.background = color;
- var erased = this.svg.querySelectorAll(".eraser");
- for (var i = 0; i < erased.length; i++)
- {
- if (erased[i].nodeName == "path")
- {
- erased[i].setAttribute("stroke", color);
- } else {
- erased[i].setAttribute("fill", color);
- }
- }
- },
- SetColor: function(num, color)
- {
- this.color[num] = color;
- },
- SetSize: function(size)
- {
- this.size = size;
- this.MoveCursor();
- },
- DrawSVGElement: function(el, ctx)
- {
- if (!ctx) ctx = this.ctx;
- if (el.getAttribute("class") == "eraser")
- {
- ctx.globalCompositeOperation = "destination-out";
- } else {
- ctx.globalCompositeOperation = "source-over";
- }
- if (el.nodeName == "path")
- {
- var c = el.getAttribute("stroke");
- ctx.strokeStyle = el.pattern ? this.MakePattern(c, el.pattern) : c;
- ctx.lineWidth = el.getAttribute("stroke-width");
- ctx.beginPath();
- for (var i = 0; i < el.pathSegList.numberOfItems; i++)
- {
- var seg = el.pathSegList.getItem(i);
- if (seg.pathSegTypeAsLetter == "M")
- {
- ctx.moveTo(seg.x, seg.y);
- } else if (seg.pathSegTypeAsLetter == "L")
- {
- ctx.lineTo(seg.x, seg.y);
- } else if (seg.pathSegTypeAsLetter == "Q")
- {
- ctx.quadraticCurveTo(seg.x1, seg.y1, seg.x, seg.y);
- } else if (seg.pathSegTypeAsLetter == "C")
- {
- ctx.bezierCurveTo(seg.x1, seg.y1, seg.x2, seg.y2, seg.x, seg.y);
- }
- }
- var fill = el.getAttribute("fill");
- if (fill && fill != "none")
- {
- ctx.closePath();
- ctx.fillStyle = el.pattern ? this.MakePattern(fill, el.pattern) : fill;
- ctx.fill();
- }
- ctx.stroke();
- }
- else if (el.nodeName == "rect")
- {
- ctx.fillStyle = el.getAttribute("fill");
- var x = el.getAttribute("x");
- var y = el.getAttribute("y");
- var w = el.getAttribute("width");
- var h = el.getAttribute("height");
- ctx.fillRect(x, y, w, h);
- }
- },
- UpdateView: function()
- {
- var start = this.lastrect < this.position ? this.lastrect : 0;
- for (var i = start; i <= this.position; i++)
- {
- this.DrawSVGElement(this.svg.childNodes[i]);
- }
- },
- DrawDispLinePresto: function(x1, y1, x2, y2, first)
- {
- if (first) this.svgDisp.insertBefore(this.path, this.svgDisp.firstChild);
- },
- DrawDispLine: function(x1, y1, x2, y2, first)
- {
- var ctx = this.ctxDisp;
- var c = this.lastcolor;
- ctx.strokeStyle = this.pattern ? this.MakePattern(c, this.pattern) : c;
- ctx.lineWidth = this.size;
- ctx.beginPath();
- ctx.moveTo(x1, y1);
- ctx.lineTo(x2, y2);
- ctx.stroke();
- },
- StrokeBegin: function(x, y, left)
- {
- if (left === undefined)
- {
- left = this.lastleft;
- } else {
- this.lastleft = left;
- }
- if (this.snap)
- {
- x = Math.round(x / this.snap) * this.snap;
- y = Math.round(y / this.snap) * this.snap;
- }
- var cls = null;
- var color = left ? this.color[0] : this.color[1];
- if (color == "eraser")
- {
- color = this.background;
- cls = "eraser";
- }
- this.path = svgElement("path",
- {
- "class": cls,
- stroke: color,
- "stroke-width": this.size,
- "stroke-linejoin": "round",
- "stroke-linecap": "round",
- fill: this.fillNext ? color : "none",
- }
- );
- this.fillNext = false;
-
- this.lastcolor = color;
- this.path.pattern = this.pattern;
- //this.svgDisp.insertBefore(this.path, this.svgDisp.firstChild);
- this.path.pathSegList.appendItem(this.path.createSVGPathSegMovetoAbs(x, y));
- this.path.pathSegList.appendItem(this.path.createSVGPathSegLinetoAbs(x, y + 0.001));
- this.DrawDispLine(x, y, x, y + 0.001, true);
- this.points = [];
- this.points.push({x: x, y: y});
- this.blot = true;
- this.isStroking = true;
- },
- StrokeEnd: function()
- {
- this.unsaved = true;
- var p = this.points;
- if (p.length > 2)
- {
- p = simplifyDouglasPeucker(p, this.smoothening);
- buildSmoothPath(p, this.path);
- }
- this.path.orig = p;
- this.Add(this.path);
- this.ctxDisp && this.ctxDisp.clearRect(0, 0, 600, 500);
- this.isStroking = false;
- },
- StrokeAdd: function(x, y)
- {
- if (!this.isStroking) throw new Error("StrokeAdd without StrokeBegin!");
- if (this.snap)
- {
- x = Math.round(x / this.snap) * this.snap;
- y = Math.round(y / this.snap) * this.snap;
- }
- var p = this.points[this.points.length - 1];
- if (p.x == x && p.y == y) return;
- if (this.blot)
- {
- this.path.pathSegList.removeItem(1);
- this.blot = false;
- }
- this.path.pathSegList.appendItem(this.path.createSVGPathSegLinetoAbs(x, y));
- this.DrawDispLine(p.x, p.y, x, y);
- this.points.push({x: x, y: y});
- // Todo: realtime smoothening
- /*
- p = this.points;
- if (p.length > 2)
- {
- p = simplifyDouglasPeucker(p, this.smoothening);
- buildSmoothPath(p, this.path);
- }
- */
- },
- // Experimental, for making polylines like in Photoshop
- // Caveat: undo will erase whole polyline
- StrokeBeginModifyLast: function(x, y, left)
- {
- if (this.position == 0 || !this.points) return anbt.StrokeBegin(x, y, left);
- if (this.snap)
- {
- x = Math.round(x / this.snap) * this.snap;
- y = Math.round(y / this.snap) * this.snap;
- }
- this.path = this.svg.childNodes[this.position];
- this.points = this.path.orig;
- this.Seek(this.position - 1);
- this.svgDisp.insertBefore(this.path, this.svgDisp.firstChild);
- this.path.pathSegList.appendItem(this.path.createSVGPathSegLinetoAbs(x, y));
- this.points.push({x: x, y: y});
- this.isStroking = true;
- },
- ClearWithColor: function(color)
- {
- this.Add(svgElement("rect",
- {
- "class": color == "eraser" ? color : null,
- x: 0,
- y: 0,
- width: 600,
- height: 500,
- fill: color == "eraser" ? this.background : color,
- }
- ));
- this.lastrect = this.position;
- },
- Add: function(el)
- {
- if (this.rewindCache.length >= this.fastUndoLevels)
- {
- this.rewindCache.pop();
- }
- this.rewindCache.unshift(this.ctx.getImageData(0, 0, 600, 500));
-
- this.DrawSVGElement(el);
- if (!this.timeedit || this.position == this.svg.childNodes.length - 1)
- {
- // Remove everything past current position
- for (var i = this.svg.childNodes.length - 1; i > this.position; i--)
- {
- this.svg.removeChild(this.svg.childNodes[i]);
- }
- this.svg.appendChild(el);
- this.position = this.svg.childNodes.length - 1;
- this.MoveSeekbar(1);
- } else {
- this.svg.insertBefore(el, this.svg.childNodes[this.position + 1]);
- }
- },
- Undo: function()
- {
- // Prevent "undoing" the background rectangle
- if (this.position > 0)
- {
- this.Seek(this.position - 1);
- this.MoveSeekbar(this.position / (this.svg.childNodes.length - 1));
- }
- },
- Redo: function()
- {
- var posmax = this.svg.childNodes.length - 1;
- if (this.position < posmax)
- {
- this.Seek(this.position + 1);
- this.MoveSeekbar(this.position / posmax);
- }
- },
- MoveSeekbar: function(pos)
- {
- if (this.seekbarMove)
- {
- this.seekbarMove(pos);
- }
- },
- SetSeekbarMove: function(func)
- {
- this.seekbarMove = func;
- },
- GetSeekMax: function()
- {
- return this.svg.childNodes.length - 1;
- },
- Seek: function(newpos)
- {
- var start = -1;
- this.Pause(true);
- if (newpos == this.position) return;
- if (newpos < this.position)
- {
- var rewindSteps = this.position - newpos;
- if (rewindSteps <= this.rewindCache.length)
- {
- // Draw from cached
- this.ctx.putImageData(this.rewindCache[rewindSteps - 1], 0, 0);
- this.rewindCache.splice(0, rewindSteps);
- } else {
- // Not cached; rebuild cache
- start = 0;
- if (this.lastrect <= newpos)
- {
- start = this.lastrect;
- } else {
- start = this.FindLastRect(newpos);
- }
- this.DrawSVGElement(this.svg.childNodes[start]);
- }
- } else if (newpos > this.position) {
- start = this.position;
- }
- if (start != -1)
- {
- var forwardSteps = newpos - start;
- if (forwardSteps >= this.fastUndoLevels)
- {
- this.rewindCache.length = 0;
- } else {
- // Ex: 3 cached, 10 max, 8 steps to play => delete 1 from the end
- var len = this.rewindCache.length;
- var numRemove = Math.min(len, newpos - start + len - this.fastUndoLevels);
- this.rewindCache.splice(len - numRemove, numRemove);
- }
- for (var i = start + 1; i <= newpos; i++)
- {
- if (newpos - i < this.fastUndoLevels)
- {
- this.rewindCache.unshift(this.ctx.getImageData(0, 0, 600, 500));
- }
- this.DrawSVGElement(this.svg.childNodes[i]);
- }
- }
- this.position = newpos;
- },
- Play: function()
- {
- this.rewindCache.length = 0; // TODO: make rewind data remember its position
- if (this.position == this.svg.childNodes.length - 1)
- {
- if (this.position === 0)
- {
- // To make button revert to play
- this.MoveSeekbar(1);
- return;
- }
- this.position = 0;
- this.MoveSeekbar(0);
- // Assume first svg child is background rect
- this.DrawSVGElement(this.svg.childNodes[0]);
- }
- this.isPlaying = true;
- this.playTimer = this.PlayTimer.bind(this);
- this.playTimer();
- },
- PlayTimer: function()
- {
- if (!this.isPlaying) return;
- var posmax = this.svg.childNodes.length - 1;
- var delay = this.delay;
- var maxidx = 0;
- if (this.position < posmax || this.isAnimating)
- {
- if (this.isAnimating)
- {
- maxidx = this.animatePath.pathSegList.numberOfItems - 1;
- if (this.animateIndex < maxidx)
- {
- // There doesn't seem to be a simplier way to copy the pathSeg
- var seg = this.animatePath.pathSegList.getItem(this.animateIndex);
- var newseg;
- if (seg.pathSegTypeAsLetter == "L")
- {
- newseg = this.path.createSVGPathSegLinetoAbs(seg.x, seg.y);
- } else if (seg.pathSegTypeAsLetter == "Q")
- {
- newseg = this.path.createSVGPathSegCurvetoQuadraticAbs(seg.x, seg.y, seg.x1, seg.y1);
- } else if (seg.pathSegTypeAsLetter == "C")
- {
- newseg = this.path.createSVGPathSegCurvetoCubicAbs(seg.x, seg.y, seg.x1, seg.y1, seg.x2, seg.y2);
- }
- this.path.pathSegList.appendItem(newseg);
- this.animateIndex++;
- } else {
- this.isAnimating = false;
- this.svgDisp.removeChild(this.path);
- this.DrawSVGElement(this.animatePath);
- this.position++;
- this.animateIndex = 0;
- }
- delay = this.delay / 6;
- } else {
- var el = this.svg.childNodes[this.position + 1];
- if (el.nodeName == "path")
- {
- this.isAnimating = true;
- this.animatePath = el;
- this.animateIndex = 1;
- this.path = el.cloneNode(true);
- var seg = el.pathSegList.getItem(0);
- this.path.pathSegList.initialize(this.path.createSVGPathSegMovetoAbs(seg.x, seg.y));
- this.svgDisp.insertBefore(this.path, this.svgDisp.firstChild);
- } else {
- this.DrawSVGElement(el);
- this.position++;
- }
- }
- }
- this.MoveSeekbar((this.position + (maxidx ? this.animateIndex / maxidx : 0)) / posmax);
- if (this.position < posmax)
- {
- setTimeout(this.playTimer, delay);
- } else {
- this.Pause();
- }
- },
- Pause: function(noSeekbar)
- {
- if (this.isPlaying)
- {
- if (this.isAnimating)
- {
- this.isAnimating = false;
- this.svgDisp.removeChild(this.path);
- this.DrawSVGElement(this.animatePath);
- this.position++;
- if (!noSeekbar)
- {
- this.MoveSeekbar(this.position / (this.svg.childNodes.length - 1));
- }
- }
- this.isPlaying = false;
- }
- },
- MoveCursor: function(x, y)
- {
- if (!this.brushCursor)
- {
- this.brushCursor = svgElement("circle",
- {
- "stroke-width": "0.5",
- stroke: "#000",
- fill: "none",
- }
- );
- this.svgDisp.appendChild(this.brushCursor);
- this.brushCursor2 = svgElement("circle",
- {
- "stroke-width": "0.5",
- stroke: "#fff",
- fill: "none",
- }
- );
- this.svgDisp.appendChild(this.brushCursor2);
- this.eyedropperCursor = svgElement("image",
- {
- width: 16,
- height: 16,
- visibility: "hidden",
- }
- );
- this.eyedropperCursor.setAttributeNS("http://www.w3.org/1999/xlink", "href", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAARklEQVR4XoXRwQoAIAgEUf//pzeGDgq5G3PrCQqVbIAqsDz9WM2qhTX4GZgPV+JpSFxAC0PwbeVZZIpMgXvAMwoj4U9B3wGySxvzk6ZjvwAAAABJRU5ErkJggg==");
- this.svgDisp.appendChild(this.eyedropperCursor);
- }
- // Assume just size change if called with no parameters
- if (typeof x != "undefined")
- {
- if (this.snap)
- {
- x = Math.round(x / this.snap) * this.snap;
- y = Math.round(y / this.snap) * this.snap;
- }
- this.brushCursor.setAttribute("cx", x);
- this.brushCursor.setAttribute("cy", y);
- this.brushCursor2.setAttribute("cx", x);
- this.brushCursor2.setAttribute("cy", y);
- this.eyedropperCursor.setAttribute("x", x - 1);
- this.eyedropperCursor.setAttribute("y", y - 15);
- }
- this.brushCursor.setAttribute("r", this.size / 2 + 0.5);
- this.brushCursor2.setAttribute("r", this.size / 2 - 0.5);
- },
- ShowEyedropperCursor: function(isEyedropper)
- {
- if (!this.brushCursor) return;
- var vis = isEyedropper ? "hidden" : "visible";
- var vis2 = isEyedropper ? "visible" : "hidden";
- this.brushCursor.setAttribute("visibility", vis);
- this.brushCursor2.setAttribute("visibility", vis);
- this.eyedropperCursor.setAttribute("visibility", vis2);
- },
- Eyedropper: function(x, y)
- {
- var p = this.ctx.getImageData(x, y, 1, 1).data;
- if (p[3] > 0)
- {
- return getClosestColor(p, this.palette);
- } else {
- return this.background;
- }
- },
- RequestSave: function(dataurl, extension)
- {
- if (!dataurl)
- {
- dataurl = this.pngBase64;
- extension = ".png";
- this.unsaved = false;
- }
- if (!this.saveLink)
- {
- this.saveLink = document.createElement("a");
- document.body.appendChild(this.saveLink);
- }
- if ("download" in this.saveLink)
- {
- this.saveLink.href = dataurl;
- var d = new Date();
- this.saveLink.download =
- [
- "DrawingInTime_",
- d.getFullYear(),
- "_",
- (101 + d.getMonth() + "").slice(-2),
- (100 + d.getDate() + "").slice(-2),
- "_",
- (100 + d.getHours() + "").slice(-2),
- (100 + d.getMinutes() + "").slice(-2),
- (100 + d.getSeconds() + "").slice(-2),
- extension
- ].join("");
- this.saveLink.click();
- } else {
- window.open(dataurl);
- }
- return true;
- },
- UploadToImgur: function(callback)
- {
- var xhr = new XMLHttpRequest();
- xhr.open("POST", "https://api.imgur.com/3/image");
- xhr.onload = function()
- {
- var res = xhr.responseText;
- try
- {
- res = JSON.parse(res);
- }
- catch(e) {}
- if (res.success)
- {
- // To set description
- var xhr2 = new XMLHttpRequest();
- xhr2.open("POST", "https://api.imgur.com/3/image/" + res.data.deletehash);
- xhr2.setRequestHeader('Authorization', 'Client-ID 4809db83c8897af');
- var fd = new FormData();
- fd.append("description", "Playback: http://grompe.org.ru/drawit/#" + res.data.id);
- xhr2.send(fd);
- }
- callback(res);
- };
- xhr.onerror = function(e)
- {
- callback("error: " + e);
- };
- xhr.setRequestHeader('Authorization', 'Client-ID 4809db83c8897af');
- var fd = new FormData();
- fd.append("image", new Blob([base642bytes(this.pngBase64.substr(22)).buffer], {type: "image/png"}));
- fd.append("type", "file");
- fd.append("title", "Made with Drawing in Time");
- fd.append("description", "http://grompe.org.ru/drawit/");
- xhr.send(fd);
- },
- FromImgur: function(id)
- {
- // https link to prevent recompression by various optimizing proxies
- this.FromURL("https://i.imgur.com/" + id + ".png");
- },
- MakePattern: function(color, patid)
- {
- if (this.patternCache[color] && this.patternCache[color][patid])
- {
- return this.patternCache[color][patid];
- } else {
- if (!this.patternCache[color])
- {
- this.patternCache[color] = [];
- }
- if (!this.patternCanvas)
- {
- this.patternCanvas = document.createElement("canvas");
- this.patternCanvas.width = 16;
- this.patternCanvas.height = 16;
- }
- var ctx = this.patternCanvas.getContext("2d");
- ctx.fillStyle = color;
- ctx.clearRect(0, 0, 16, 16);
- if (patid == 1)
- {
- ctx.beginPath();
- ctx.arc(2, 2, 2, 0, 2 * Math.PI, false);
- ctx.fill();
- ctx.beginPath();
- ctx.arc(6, 6, 2, 0, 2 * Math.PI, false);
- ctx.fill();
- ctx.drawImage(this.patternCanvas, 8, 0);
- ctx.drawImage(this.patternCanvas, 0, 8);
- } else if (patid == 2) {
- ctx.beginPath();
- ctx.arc(2, 2, 1, 0, 2 * Math.PI, false);
- ctx.fill();
- ctx.beginPath();
- ctx.arc(6, 6, 1, 0, 2 * Math.PI, false);
- ctx.fill();
- ctx.drawImage(this.patternCanvas, 8, 0);
- ctx.drawImage(this.patternCanvas, 0, 8);
- } else if (patid == 3) {
- ctx.beginPath();
- ctx.arc(4, 4, 2, 0, 2 * Math.PI, false);
- ctx.fill();
- ctx.beginPath();
- ctx.arc(4, 12, 2, 0, 2 * Math.PI, false);
- ctx.fill();
- ctx.drawImage(this.patternCanvas, 8, -4);
- ctx.drawImage(this.patternCanvas, 8, 12);
- } else if (patid == 4) {
- ctx.fillRect(0, 0, 2, 2);
- ctx.fillRect(4, 0, 2, 2);
- ctx.fillRect(0, 4, 2, 2);
- ctx.fillRect(4, 4, 2, 2);
- ctx.drawImage(this.patternCanvas, 8, 0);
- ctx.drawImage(this.patternCanvas, 0, 8);
- } else if (patid == 5) {
- ctx.fillRect(0, 0, 1, 1);
- ctx.fillRect(4, 0, 1, 1);
- ctx.fillRect(0, 4, 1, 1);
- ctx.fillRect(4, 4, 1, 1);
- ctx.drawImage(this.patternCanvas, 8, 0);
- ctx.drawImage(this.patternCanvas, 0, 8);
- }
- var pat = this.ctx.createPattern(this.patternCanvas, 'repeat');
- return (this.patternCache[color][patid] = pat);
- }
- },
- SetPattern: function(patid)
- {
- this.pattern = patid;
- },
- ExportWebM: function()
- {
- var anbt = this;
- require("whammy.min.js", function()
- {
- var canvas = document.createElement("canvas");
- canvas.width = 600;
- canvas.height = 500;
- var context = canvas.getContext("2d");
- context.fillStyle = anbt.background;
- var encoder = new Whammy.Video(15);
- var maxpos = anbt.svg.childNodes.length - 1;
- var i = 0;
- var nextFrame = function()
- {
- anbt.Seek(i);
- anbt.MoveSeekbar(anbt.position / maxpos);
- context.fillRect(0, 0, 600, 500);
- context.drawImage(anbt.canvas, 0, 0, 600, 500);
- encoder.add(canvas);
- i++;
- if (i <= maxpos)
- {
- setTimeout(nextFrame, 1);
- } else {
- var output = encoder.compile();
- var url = (window.webkitURL || window.URL).createObjectURL(output);
- anbt.RequestSave(url, ".webm");
- }
- }
- nextFrame();
- });
- },
-};
-
-var timerStart, timerCallback;
-
-function bindEvents()
-{
- var wacom = ID("wacom");
- var getPointerType = function()
- {
- return wacom && wacom.penAPI && wacom.penAPI.isWacom ? wacom.penAPI.pointerType : 0;
- };
-
- var checkPlayingAndStop = function()
- {
- if (anbt.isPlaying)
- {
- anbt.Pause();
- ID("play").classList.remove("pause");
- return true;
- }
- return false;
- };
- var rect;
- var mouseMove = function(e)
- {
- e.preventDefault();
- var x = e.pageX - rect.left - pageXOffset;
- var y = e.pageY - rect.top - pageYOffset;
- anbt.StrokeAdd(x, y);
- };
- var mouseUp = function(e)
- {
- if (e.button === 0 || e.button === 2)
- {
- e.preventDefault();
- if (anbt.isStroking) anbt.StrokeEnd();
- if (options.hideCross) ID("svgContainer").classList.remove("hidecursor");
- window.removeEventListener('mouseup', mouseUp);
- window.removeEventListener('mousemove', mouseMove);
- }
- };
- ID("svgContainer").addEventListener('mousedown', function(e)
- {
- if (e.button === 0 || e.button === 2)
- {
- if (anbt.isStroking) return mouseUp(e);
- if (checkPlayingAndStop()) return;
- e.preventDefault();
- rect = this.getBoundingClientRect();
- var x = e.pageX - rect.left - pageXOffset;
- var y = e.pageY - rect.top - pageYOffset;
-
- if (e.altKey)
- {
- var whichcolor = e.button === 0 ? 0 : 1;
- if (e.shiftKey && (anbt.color[whichcolor] != "eraser"))
- {
- var alpha = Math.round(color2rgba(anbt.color[whichcolor])[3] / 2.55) / 100;
- var c = color2rgba(anbt.Eyedropper(x, y));
- anbt.SetColor(whichcolor, "rgba(" + c[0] + "," + c[1] + "," + c[2] + "," + alpha + ")");
- } else {
- anbt.SetColor(whichcolor, anbt.Eyedropper(x, y));
- }
- updateColorIndicators();
- } else {
- // PointerType == 3 is pen tablet eraser
- var left = e.button === 0 && getPointerType() !== 3;
- if (options.hideCross) ID("svgContainer").classList.add("hidecursor");
- if (e.shiftKey)
- {
- anbt.StrokeBeginModifyLast(x, y, left);
- } else {
- anbt.StrokeBegin(x, y, left);
- }
- window.addEventListener('mouseup', mouseUp);
- window.addEventListener('mousemove', mouseMove);
- }
- }
- });
- var lastSeenColorToHighlight = anbt.background;
- ID("svgContainer").addEventListener('mousemove', function(e)
- {
- rect = this.getBoundingClientRect();
- var x = e.pageX - rect.left - pageXOffset;
- var y = e.pageY - rect.top - pageYOffset;
- anbt.MoveCursor(x, y);
- // Highlight color we're pointing at
- if (options.colorUnderCursorHint && !anbt.isStroking)
- {
- var color = anbt.Eyedropper(x, y);
- if (lastSeenColorToHighlight != color)
- {
- var el = ID("colors").querySelector("b.hint");
- if (el) el.classList.remove("hint");
- var coloridx = anbt.palette.indexOf(color);
- if (coloridx >= 0)
- {
- var els = ID("colors").querySelectorAll("b");
- els[coloridx].classList.add("hint");
- }
- }
- lastSeenColorToHighlight = color;
- }
- });
- window.addEventListener('contextmenu', function(e)
- {
- if (anbt.isStroking) e.preventDefault();
- });
-
- var touchSingle = false;
- var lastTouch;
- var simulateSingleTouchStart = function()
- {
- if (touchSingle)
- {
- var x = lastTouch.pageX - rect.left - pageXOffset;
- var y = lastTouch.pageY - rect.top - pageYOffset;
- anbt.StrokeBegin(x, y, true);
- touchSingle = false;
- }
- };
- var touchMove = function(e)
- {
- if (e.touches.length === 1)
- {
- simulateSingleTouchStart();
- e.preventDefault();
- if (anbt.isStroking)
- {
- var x = e.touches[0].pageX - rect.left - pageXOffset;
- var y = e.touches[0].pageY - rect.top - pageYOffset;
- anbt.StrokeAdd(x, y);
- }
- }
- };
- var touchEnd = function(e)
- {
- if (e.touches.length === 0)
- {
- simulateSingleTouchStart();
- e.preventDefault();
- anbt.StrokeEnd();
- window.removeEventListener('touchend', touchEnd);
- window.removeEventListener('touchmove', touchMove);
- }
- };
- var touchUndoRedo = function(e)
- {
- if (e.changedTouches.length === 1 && e.touches.length === 1)
- {
- var ch = e.changedTouches[0];
- if (Math.abs(ch.pageX - lastTouch.pageX) < 10 &&
- Math.abs(ch.pageY - lastTouch.pageY) < 10)
- {
- ID("play").classList.remove("pause");
- if (ch.pageX < e.touches[0].pageX)
- {
- anbt.Undo();
- } else {
- anbt.Redo();
- }
- }
- }
- window.removeEventListener('touchend', touchUndoRedo);
- };
- ID("svgContainer").addEventListener('touchstart', function(e)
- {
- if (e.touches.length === 1)
- {
- if (checkPlayingAndStop()) return;
- // Let two-finger scrolling, pinching, etc. work.
- // This requires moving dot-drawing to simulateSingleTouchStart()
- rect = this.getBoundingClientRect();
- touchSingle = true;
- lastTouch = e.touches[0];
- window.addEventListener('touchend', touchEnd);
- window.addEventListener('touchmove', touchMove);
- } else {
- // Enable two-finger undo and redo:
- // 1 o o
- // 2 o o o o
- // 3 , o o .
- // Undo Redo
- if (touchSingle && e.touches.length === 3)
- {
- lastTouch = e.touches[1];
- window.addEventListener('touchend', touchUndoRedo);
- }
- if (anbt.isStroking)
- {
- anbt.StrokeEnd();
- }
- touchSingle = false;
- window.removeEventListener('touchend', touchEnd);
- window.removeEventListener('touchmove', touchMove);
- }
- });
-
- ID("svgContainer").addEventListener('mouseleave', function(e)
- {
- // Hide brush cursor
- anbt.MoveCursor(-100, -100);
- });
- ID("svgContainer").addEventListener('contextmenu', function(e)
- {
- e.preventDefault();
- });
-
- ID("import").addEventListener('click', function(e)
- {
- e.preventDefault();
- ID("svgContainer").classList.add("loading");
- anbt.FromLocalFile(e.shiftKey || e.ctrlKey);
- ID("svgContainer").classList.remove("loading");
- });
- var warnStrokesAfterPos = function()
- {
- return (anbt.position < anbt.GetSeekMax() && !confirm("Strokes after current position will be discarded. Continue?"));
- };
- var doExport = function(e)
- {
- e.preventDefault();
- if (warnStrokesAfterPos()) return;
- anbt.MakePNG(600, 500, true);
- anbt.RequestSave();
- };
- ID("export").addEventListener('click', doExport);
- ID("imgur").addEventListener('click', function(e)
- {
- e.preventDefault();
- if (warnStrokesAfterPos()) return;
- ID("imgur").childNodes[0].nodeValue = "Uploading...";
- ID("imgur").disabled = true;
- anbt.MakePNG(600, 500, true);
- anbt.UploadToImgur(function(r)
- {
- ID("imgur").childNodes[0].nodeValue = "Upload to imgur";
- ID("popup").classList.add("show");
- ID("popuptitle").childNodes[0].nodeValue = "Imgur upload result";
- if (r && r.success)
- {
- anbt.unsaved = false;
- history.replaceState(null, null, "#" + r.data.id);
- ID("imgururl").href = "http://imgur.com/" + r.data.id;
- ID("imgururl").childNodes[0].nodeValue = "Uploaded image";
- ID("imgurdelete").href = "http://imgur.com/delete/" + r.data.deletehash;
- ID("imgurerror").childNodes[0].nodeValue = "";
- } else {
- var err = r.data ? ("Imgur error: " + r.data.error) : ("Error: " + r);
- ID("imgurerror").childNodes[0].nodeValue = err;
- }
- ID("imgur").disabled = false;
- });
- });
- window.addEventListener('keydown', function(e)
- {
- });
- function makeBrushFunc(size)
- {
- var s = size;
- return function(e)
- {
- e.preventDefault();
- anbt.SetSize(s);
- var el = ID("tools").querySelector(".sel");
- if (el) el.classList.remove("sel");
- this.classList.add("sel");
- if (anbt.isStroking)
- {
- anbt.StrokeEnd();
- var p = anbt.points[anbt.points.length - 1];
- anbt.StrokeBegin(p.x, p.y);
- }
- };
- }
- var brushSizes = [2.4, 6, 14.4, 42];
-
- for (var i = 0; i < brushSizes.length; i++)
- {
- ID("brush" + i).addEventListener('click', makeBrushFunc(brushSizes[i]), false);
- }
- var updateColorIndicators = function()
- {
- var c0 = anbt.color[0];
- var c1 = anbt.color[1];
- if (c0 == 'eraser')
- {
- ID("primary").style.backgroundColor = 'pink';
- ID("primary").classList.add('eraser');
- } else {
- ID("primary").style.backgroundColor = c0;
- ID("primary").classList.remove('eraser');
- }
- if (c1 == 'eraser')
- {
- ID("secondary").style.backgroundColor = 'pink';
- ID("secondary").classList.add('eraser');
- } else {
- ID("secondary").style.backgroundColor = c1;
- ID("secondary").classList.remove('eraser');
- }
- };
- var chooseBackground = false;
- var updateChooseBackground = function(b)
- {
- chooseBackground = b;
- if (b)
- {
- ID("colors").classList.add("setbackground");
- ID("setbackground").classList.add("sel");
- } else {
- ID("colors").classList.remove("setbackground");
- ID("setbackground").classList.remove("sel");
- }
- };
- var colorClick = function(e)
- {
- if (e.touches || e.button === 0 || e.button === 2)
- {
- e.preventDefault();
- var color = this.style.backgroundColor;
- if (chooseBackground)
- {
- if (this.id != "eraser")
- {
- anbt.SetBackground(color);
- }
- updateChooseBackground(false);
- } else {
- var showcolor = color;
- if (this.id == "eraser")
- {
- color = "eraser";
- showcolor = "pink";
- }
- // PointerType == 3 is pen tablet eraser
- if (e.button === 2 || getPointerType() === 3)
- {
- anbt.SetColor(1, color);
- } else {
- anbt.SetColor(0, color);
- }
- updateColorIndicators();
- }
- }
- };
- var noDefault = function(e)
- {
- e.preventDefault();
- };
- var els = ID("colors").querySelectorAll("b");
- for (var i = 0; i < els.length; i++)
- {
- els[i].addEventListener('mousedown', colorClick);
- els[i].addEventListener('touchend', colorClick);
- els[i].addEventListener('contextmenu', noDefault);
- }
- ID("setbackground").addEventListener('click', function(e)
- {
- e.preventDefault();
- updateChooseBackground(!chooseBackground);
- });
- ID("undo").addEventListener('click', function(e)
- {
- e.preventDefault();
- ID("play").classList.remove("pause");
- anbt.Undo();
- });
- ID("redo").addEventListener('click', function(e)
- {
- e.preventDefault();
- ID("play").classList.remove("pause");
- anbt.Redo();
- });
- ID("trash").addEventListener('click', function(e)
- {
- e.preventDefault();
- anbt.ClearWithColor("eraser");
- if (ID("newcanvasyo").classList.contains("sandbox"))
- {
- timerStart = Date.now();
- }
- });
-
- var knobMove = function(fraction)
- {
- var x = Math.floor(fraction * 502 - 10);
- if (fraction > 0)
- {
- ID("knob").classList.add("smooth");
- } else {
- ID("knob").classList.remove("smooth");
- }
- ID("knob").style.marginLeft = x + 'px';
- if (fraction >= 1)
- {
- ID("play").classList.remove("pause");
- }
- };
- anbt.SetSeekbarMove(knobMove);
- var knobCommonMove = function(e)
- {
- e.preventDefault();
- var len = anbt.GetSeekMax();
- var x = (e.touches ? e.touches[0].pageX : e.pageX) - rect.left - pageXOffset - 34;
- x = Math.min(Math.max(-10, x), 492);
- var pos = Math.round((x + 10) / 502 * len);
- x = pos / len * 502 - 10;
- ID("knob").classList.add("smooth");
- ID("knob").style.marginLeft = x + 'px';
- anbt.Seek(pos);
- ID("play").classList.remove("pause");
- };
- var knobCommonUp = function(e)
- {
- if (e.button === 0 || e.touches && e.touches.length === 0)
- {
- e.preventDefault();
- window.removeEventListener('mouseup', knobCommonUp);
- window.removeEventListener('touchend', knobCommonUp);
- window.removeEventListener('mousemove', knobCommonMove);
- window.removeEventListener('touchmove', knobCommonMove);
- }
- };
- var knobCommonDown = function(e)
- {
- if (e.button === 0 || e.touches && e.touches.length === 1)
- {
- rect = ID("seekbar").getBoundingClientRect();
- knobCommonMove(e);
- window.addEventListener('mouseup', knobCommonUp);
- window.addEventListener('touchend', knobCommonUp);
- window.addEventListener('mousemove', knobCommonMove);
- window.addEventListener('touchmove', knobCommonMove);
- }
- };
- ID("knob").addEventListener('mousedown', knobCommonDown);
- ID("knob").addEventListener('touchstart', knobCommonDown);
- ID("seekbar").addEventListener('mousedown', knobCommonDown);
- ID("seekbar").addEventListener('touchstart', knobCommonDown);
-
- var playCommonDown = function(e)
- {
- e.stopPropagation();
- e.preventDefault();
- if (anbt.isPlaying)
- {
- ID("play").classList.remove("pause");
- anbt.Pause();
- } else {
- ID("play").classList.add("pause");
- anbt.Play();
- }
- };
- ID("play").addEventListener('mousedown', playCommonDown);
- ID("play").addEventListener('touchstart', playCommonDown);
-
- var choosePalette = function(e)
- {
- if (e.touches || e.button === 0)
- {
- e.preventDefault();
- var name = this.childNodes[0].nodeValue;
- ID("palettename").childNodes[0].nodeValue = name;
- var colors = palettes[name];
- anbt.palette = colors;
- var pal = ID("palette");
- var els = pal.querySelectorAll("b");
- // Remove all current colors except for the eraser
- for (var i = 0; i < els.length - 1; i++)
- {
- pal.removeChild(els[i]);
- }
- var eraser = els[els.length - 1];
- for (var i = 0; i < colors.length; i++)
- {
- var b = document.createElement("b");
- b.style.backgroundColor = colors[i];
- b.addEventListener('mousedown', colorClick);
- b.addEventListener('touchend', colorClick);
- b.addEventListener('contextmenu', noDefault);
- pal.appendChild(b);
- // Eraser got on the front, put it on the back
- pal.appendChild(eraser);
- }
- }
- };
- var closePaletteList = function(e)
- {
- if (e.touches || e.button === 0)
- {
- ID("palettechooser").classList.remove("open");
- window.removeEventListener('mousedown', closePaletteList);
- window.removeEventListener('touchend', closePaletteList);
- }
- };
- var openPaletteList = function(e)
- {
- if (e.touches || e.button === 0)
- {
- e.preventDefault();
- var chooser = ID("palettechooser");
- chooser.classList.toggle("open");
- if (chooser.classList.contains("open"))
- {
- setTimeout(function()
- {
- window.addEventListener('mousedown', closePaletteList);
- window.addEventListener('touchend', closePaletteList);
- }, 1);
- }
- var keys = Object.keys(palettes);
- if (chooser.childNodes.length < keys.length)
- {
- var canvas = document.createElement("canvas");
- canvas.height = 10;
- var ctx = canvas.getContext("2d");
- for (var i = chooser.childNodes.length; i < keys.length; i++)
- {
- canvas.width = 8 * palettes[keys[i]].length + 2;
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- ctx.globalAlpha = 0.5;
- ctx.fillRect(0, 0, canvas.width, canvas.height);
- ctx.globalAlpha = 1;
- for (var j = 0; j < palettes[keys[i]].length; j++)
- {
- ctx.fillStyle = palettes[keys[i]][j];
- ctx.fillRect(j * 8 + 1, 1, 8, 8);
- }
- var div = document.createElement("div");
- div.appendChild(document.createTextNode(keys[i]));
- div.style.backgroundImage = 'url("' + canvas.toDataURL() + '")';
- div.style.backgroundRepeat = 'no-repeat';
- div.style.backgroundPosition = 'center 35px';
- div.addEventListener('mousedown', choosePalette);
- div.addEventListener('touchend', choosePalette);
- chooser.appendChild(div);
- }
- }
- }
- };
- ID("palettename").addEventListener('mousedown', openPaletteList);
- ID("palettename").addEventListener('touchend', openPaletteList);
-
- // TODO: refactor: generalize with palette chooser menu
- var closeMenu = function(e)
- {
- if (e.touches || e.button === 0)
- {
- ID("menu").classList.remove("open");
- window.removeEventListener('mousedown', closeMenu);
- window.removeEventListener('touchend', closeMenu);
- }
- };
- var openMenu = function(e)
- {
- if (e.touches || e.button === 0)
- {
- e.preventDefault();
- var menu = ID("menu");
- menu.classList.toggle("open");
- if (menu.classList.contains("open"))
- {
- setTimeout(function()
- {
- window.addEventListener('mousedown', closeMenu);
- window.addEventListener('touchend', closeMenu);
- }, 1);
- }
-
- }
- };
- ID("openmenu").addEventListener('mousedown', openMenu);
- ID("openmenu").addEventListener('touchend', openMenu);
-
- var exitPlay = function(e)
- {
- e.preventDefault();
- ID("newcanvasyo").classList.add("sandbox");
- ID("newcanvasyo").classList.remove("play");
- timerStart -= 10*60*1000;
- timerCallback = null;
- };
- ID("exit").addEventListener('click', exitPlay);
- ID("submit").addEventListener('click', exitPlay);
-
- // Menu items
- var simulatePlay = function(e)
- {
- e.preventDefault();
- ID("newcanvasyo").classList.remove("sandbox");
- ID("newcanvasyo").classList.add("play");
- timerStart = Date.now() + 10*60*1000;
- timerCallback = function(s)
- {
- if (s < 0) exitPlay(e);
- };
- ID("drawthis").childNodes[0].nodeValue = randomPhrase();
- };
- ID("simplay").addEventListener('mousedown', simulatePlay);
- ID("simplay").addEventListener('touchend', simulatePlay);
- ID("skip").addEventListener('click', simulatePlay);
-
- var exportCustomPNG = function(e)
- {
- e.preventDefault();
- if (warnStrokesAfterPos()) return;
- var m = prompt("PNG size to export? Enter only width to maintain aspect ratio.", "600x500");
- if (!m) return;
- m = m.match(/(\d+)/g);
- if (!m)
- {
- alert("Invalid size.");
- return;
- }
- var width = m[0];
- var height = m[1] || Math.round(width / 1.2);
- anbt.MakePNG(width, height);
- anbt.RequestSave();
- };
- ID("custompng").addEventListener('mousedown', exportCustomPNG);
- ID("custompng").addEventListener('touchend', exportCustomPNG);
-
- var setTransparentBackground = function(e)
- {
- e.preventDefault();
- anbt.SetBackground("eraser");
- };
- ID("transparentbg").addEventListener('mousedown', setTransparentBackground);
- ID("transparentbg").addEventListener('touchend', setTransparentBackground);
-
- var enablePatterns = function(e)
- {
- e.preventDefault();
- ID("enablepatterns").childNodes[0].nodeValue = "(patterns are enabled)"
- ID("enablepatterns").removeEventListener('mousedown', enablePatterns);
- ID("enablepatterns").removeEventListener('touchend', enablePatterns);
- var div = document.createElement('div');
- div.className = "panel";
- div.appendChild(document.createTextNode("pattern:"));
-
- var canvas = document.createElement("canvas");
- canvas.width = 48;
- canvas.height = 48;
- var ctx = canvas.getContext("2d");
- var makePatternPreview = function(pattern)
- {
- ctx.clearRect(0, 0, 48, 48);
- ctx.fillStyle = anbt.MakePattern("#000", pattern);
- ctx.fillRect(0, 0, 48, 48);
- return canvas.toDataURL();
- };
- var makePatternClick = function(pattern)
- {
- return function() { anbt.SetPattern(pattern); }
- };
- for (var i = 0; i < 6; i++)
- {
- var button = document.createElement('button');
- button.style.width = "55px";
- button.style.height = "44px";
- button.style.margin = "0 2px";
- button.style.verticalAlign = "top";
- if (i === 0) button.appendChild(document.createTextNode("(none)"));
- if (i > 0) button.style.backgroundImage = 'url("' + makePatternPreview(i) + '")';
- button.addEventListener('click', makePatternClick(i));
- div.appendChild(button);
- }
- ID("newcanvasyo").appendChild(div);
- };
- ID("enablepatterns").addEventListener('mousedown', enablePatterns);
- ID("enablepatterns").addEventListener('touchend', enablePatterns);
-
- var exportWebM = function(e)
- {
- e.preventDefault();
- anbt.ExportWebM();
- }
- ID("exportwebm").addEventListener('mousedown', exportWebM);
- ID("exportwebm").addEventListener('touchend', exportWebM);
-
- var usageTips = function(e)
- {
- e.preventDefault();
- alert("Read tooltips on the buttons!\n\n" +
- "Press Alt to pick colors (with Shift to preserve opacity)\n" +
- "Press T to halve primary color opacity\n" +
- "Press X to swap colors\n\n" +
- "On touchscreen:\n" +
- "put one finger, tap with second finger on the left to undo,\non the right to redo");
- }
- ID("usagetips").addEventListener('mousedown', usageTips);
- ID("usagetips").addEventListener('touchend', usageTips);
-
- var drawTransitions = function(e)
- {
- if (anbt.unsaved && !confirm("You haven't saved the drawing. Continue?")) return;
- e.preventDefault();
- anbt.SetBackground(anbt.palette[0]);
- anbt.ctx.clearRect(0, 0, 600, 500);
- var numcolors = anbt.palette.length;
- var w = 36;
- var h = 30;
- var offsetx = 300 - numcolors * 18 + 30;
- var offsety = 250 - numcolors * 15 - 24;
- var color1, color2, c;
- for (var y = 1; y <= numcolors; y++)
- {
- for (var x = -1; x < numcolors - 1; x++)
- {
- if (x == -1 || x == numcolors)
- {
- if (y == -1 || y == numcolors) continue;
- if (y == 0)
- {
- anbt.ctx.fillStyle = anbt.palette[numcolors - 1]
- anbt.ctx.fillRect(x * w + offsetx - 1, y * h + offsety - 1, w + 1, h + 1);
- }
- anbt.ctx.fillStyle = anbt.palette[y];
- anbt.ctx.fillRect(x * w + offsetx, y * h + offsety, w - 1, h - 1);
- } else if (y == -1 || y == numcolors)
- {
- if (x == 0)
- {
- anbt.ctx.fillStyle = anbt.palette[numcolors - 1]
- anbt.ctx.fillRect(x * w + offsetx - 1, y * h + offsety - 1, w + 1, h + 1);
- }
- anbt.ctx.fillStyle = anbt.palette[x];
- anbt.ctx.fillRect(x * w + offsetx, y * h + offsety, w - 1, h - 1);
- } else {
- if (x == y)
- {
- anbt.ctx.fillStyle = anbt.palette[x];
- anbt.ctx.fillRect(x * w + offsetx, y * h + offsety, w - 1, h - 1);
- }
- if (x >= y) continue;
- color1 = rgb2lab(color2rgba(anbt.palette[x]));
- color2 = rgb2lab(color2rgba(anbt.palette[y]));
- for (var xx = 34; xx >= 0; xx--)
- {
- c = getColorAverage(color1, color2, xx / 34);
- c = getClosestColorLab(c, anbt.palette);
- anbt.ctx.fillStyle = c;
- anbt.ctx.fillRect(x * w + offsetx + xx, y * h + offsety, 1, h - 1);
- //anbt.ctx.beginPath();
- //anbt.ctx.arc(x * w + w/4 + xx/4 + offsetx, y * h + h/4 + xx/4 + offsety, xx / 2, 0, Math.PI * 2, true);
- //anbt.ctx.fill();
- }
- }
- }
- }
- }
- ID("drawtransitions").addEventListener('mousedown', drawTransitions);
- ID("drawtransitions").addEventListener('touchend', drawTransitions);
-
- var setBackgroundImage = function(e)
- {
- if (anbt.unsaved && !confirm("You haven't saved the drawing. Continue?")) return;
- e.preventDefault();
- anbt.SetBackground("eraser");
- ID("svgContainer").style.backgroundImage = 'url(' + prompt('Enter image URL to use as a background:') + ')';
- ID("svgContainer").style.backgroundSize = '100%';
- };
- ID("setbackgroundimage").addEventListener('mousedown', setBackgroundImage);
- ID("setbackgroundimage").addEventListener('touchend', setBackgroundImage);
-
- var toggleSmooth = function(e)
- {
- if (window.toggleSmooth)
- {
- buildSmoothPath = old_buildSmoothPath;
- } else {
- window.old_buildSmoothPath = buildSmoothPath;
- buildSmoothPath = function(points, path)
- {
- if (points.length < 2) return;
- path.pathSegList.initialize(path.createSVGPathSegMovetoAbs(points[0].x, points[0].y));
- for (var i = 1; i < points.length; i++)
- {
- var c = points[i];
- path.pathSegList.appendItem(path.createSVGPathSegLinetoAbs(c.x, c.y));
- }
- };
- }
- window.toggleSmooth = !window.toggleSmooth;
- ID("togglesmooth").childNodes[0].nodeValue =
- (window.toggleSmooth ? "Enable" : "Disable") + " stroke smoothening";
- };
- ID("togglesmooth").addEventListener('mousedown', toggleSmooth);
- ID("togglesmooth").addEventListener('touchend', toggleSmooth);
-
- var setSnap = function(e)
- {
- var m = prompt("Grid size in pixels (6 makes brush 2 and brush 4 exact; 0 to disable):", "0");
- if (!m) return;
- m = m.match(/(\d+)/g);
- if (!m) return;
- var a = parseInt(m[0], 10);
- anbt.snap = a ? a : false;
- };
- ID("setsnap").addEventListener('mousedown', setSnap);
- ID("setsnap").addEventListener('touchend', setSnap);
-
- // ---
-
- ID("popupclose").addEventListener('click', function(e)
- {
- e.preventDefault();
- ID("popup").classList.remove("show");
- });
-
-
- document.addEventListener('keyup', function(e)
- {
- if (e.keyCode == 18) // Alt
- {
- ID("svgContainer").classList.remove("hidecursor");
- anbt.ShowEyedropperCursor(false);
- }
- });
- document.addEventListener('keydown', function(e)
- {
- if (document.activeElement instanceof HTMLInputElement) return true;
- if (e.keyCode == 18) // Alt
- {
- // Opera Presto refuses to hide cursor =(
- if (!navigator.userAgent.match(/\bPresto\b/))
- {
- ID("svgContainer").classList.add("hidecursor");
- }
- anbt.ShowEyedropperCursor(true);
- // The following is needed in case of Alt+Tab causing eyedropper to be stuck
- var removeEyedropper = function(e)
- {
- if (!e.altKey)
- {
- this.classList.remove("hidecursor");
- anbt.ShowEyedropperCursor(false);
- this.removeEventListener('mousemove', removeEyedropper);
- }
- };
- ID("svgContainer").addEventListener('mousemove', removeEyedropper);
- }
- else if (e.keyCode == "Q".charCodeAt(0))
- {
- e.preventDefault();
- options.colorDoublePress = !options.colorDoublePress;
- }
- else if (e.keyCode == "C".charCodeAt(0) && !e.ctrlKey && !e.metaKey)
- {
- e.preventDefault();
- options.hideCross = !options.hideCross;
- }
- else if (e.keyCode == "Z".charCodeAt(0) || ((e.keyCode == 8) && anbt.unsaved))
- {
- e.preventDefault();
- ID("play").classList.remove("pause");
- anbt.Undo();
- }
- else if (e.keyCode == "Y".charCodeAt(0))
- {
- e.preventDefault();
- ID("play").classList.remove("pause");
- anbt.Redo();
- }
- else if (e.keyCode == "X".charCodeAt(0))
- {
- e.preventDefault();
- var c0 = anbt.color[0];
- var c1 = anbt.color[1];
- anbt.SetColor(0, c1);
- anbt.SetColor(1, c0);
- updateColorIndicators();
- }
- else if (e.keyCode == "B".charCodeAt(0))
- {
- e.preventDefault();
- updateChooseBackground(!chooseBackground);
- }
- else if (e.keyCode == "E".charCodeAt(0) && !e.ctrlKey && !e.metaKey)
- {
- e.preventDefault();
- anbt.SetColor(0, "eraser");
- updateColorIndicators();
- }
- else if (e.keyCode >= 48 && e.keyCode <= 57 && !e.ctrlKey && !e.metaKey && options.colorNumberShortcuts)
- {
- e.preventDefault();
- var i = (e.keyCode == 48) ? 9 : e.keyCode - 49;
- if (e.shiftKey || (options.colorDoublePress && (anbt.prevColorKey == i))) i += 8;
- anbt.prevColorKey = i;
- if (options.colorDoublePress)
- {
- if (anbt.prevColorKeyTimer) clearTimeout(anbt.prevColorKeyTimer);
- anbt.prevColorKeyTimer = setTimeout(function() {anbt.prevColorKey = -1}, 500);
- }
- var els = ID("colors").querySelectorAll("b");
- if (i < els.length)
- {
- var color = els[i].style.backgroundColor;
- if (els[i].id == "eraser") color = "eraser";
- if (chooseBackground)
- {
- if (color != "eraser")
- {
- anbt.SetBackground(color);
- }
- updateChooseBackground(false);
- } else {
- anbt.SetColor(0, color);
- updateColorIndicators();
- }
- }
- if (anbt.isStroking)
- {
- anbt.StrokeEnd();
- var p = anbt.points[anbt.points.length - 1];
- anbt.StrokeBegin(p.x, p.y);
- }
- }
- else if (e.keyCode == "T".charCodeAt(0) && !e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey)
- {
- e.preventDefault();
-
- if (anbt.color[0] != "eraser")
- {
- var c = color2rgba(anbt.color[0]);
- var alpha = Math.round(Math.max(c[3]/510, 0.06) * 100) / 100;
- anbt.SetColor(0, "rgba(" + c[0] + "," + c[1] + "," + c[2] + "," + alpha + ")");
- }
- updateColorIndicators();
- }
- else if (e.keyCode == "F".charCodeAt(0) && !e.shiftKey)
- {
- e.preventDefault();
- anbt.fillNext = true;
- }
- else if (e.keyCode == "F".charCodeAt(0) && e.shiftKey)
- {
- e.preventDefault();
- anbt.ClearWithColor(anbt.color[0]);
- }
- else if ((e.keyCode == 189 || e.keyCode == 219 || e.keyCode == 188) && !e.ctrlKey && !e.metaKey) // - or [ or ,
- {
- e.preventDefault();
- for (var i = 1; i < brushSizes.length; i++)
- {
- if (anbt.size - brushSizes[i] < 0.01)
- {
- ID("brush" + (i - 1)).click();
- break;
- }
- }
- }
- else if ((e.keyCode == 187 || e.keyCode == 221 || e.keyCode == 190) && !e.ctrlKey && !e.metaKey) // = or ] or .
- {
- e.preventDefault();
- for (var i = 0; i < brushSizes.length - 1; i++)
- {
- if (anbt.size - brushSizes[i] < 0.01)
- {
- ID("brush" + (i + 1)).click();
- break;
- }
- }
- }
- else if (e.keyCode >= 49 && e.keyCode <= 52 && (e.ctrlKey || e.metaKey)) // Ctrl+1,2,3,4
- {
- e.preventDefault();
- ID("brush" + (e.keyCode - 49)).click();
- }
- else if (e.keyCode == 32 && !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey)
- {
- playCommonDown(e);
- }
- });
- window.onerror = function(e)
- {
- alert(e);
- };
- window.onbeforeunload = function(e)
- {
- if (anbt.unsaved)
- {
- var msg = "You haven't saved the drawing. Abandon?";
- e.returnValue = msg;
- return msg;
- }
- };
-}
-
-function fixPluginGoingAWOL()
-{
- var stupidPlugin = ID("wacom");
- var container = ID("wacomContainer");
- window.onblur = function(e)
- {
- if (container.childNodes.length === 1) container.removeChild(stupidPlugin);
- };
- window.onfocus = function(e)
- {
- if (container.childNodes.length === 0) container.appendChild(stupidPlugin);
- };
-}
-
-function runTimer()
-{
- setInterval(function()
- {
- var s = (timerStart - Date.now()) / 1000;
- if (timerCallback) timerCallback(s);
- s = Math.abs(s);
- var m = Math.floor(s / 60);
- s = Math.floor(s % 60);
- if (m < 10) m = '0' + m;
- if (s < 10) s = '0' + s;
- ID("timer").childNodes[0].nodeValue = m + ':' + s;
- },
- 500);
-}
-
-function main()
-{
- if (!window.options) window.options = {};
- if (options.enableWacom == "auto")
- {
- options.enableWacom = 0;
- for (var i = 0; i < navigator.plugins.length; i++)
- {
- if (navigator.plugins[i].name.match(/wacom/i))
- {
- options.enableWacom = 1;
- break;
- }
- }
- }
- if (options.enableWacom)
- {
- var stupidPlugin = document.createElement("object");
- var container = ID("wacomContainer");
- stupidPlugin.setAttribute("id", "wacom");
- stupidPlugin.setAttribute("type", "application/x-wacomtabletplugin");
- stupidPlugin.setAttribute("width", "1");
- stupidPlugin.setAttribute("height", "1");
- container.appendChild(stupidPlugin);
- if (options.fixTabletPluginGoingAWOL) fixPluginGoingAWOL();
- }
- anbt.BindContainer(ID("svgContainer"));
- bindEvents();
- ID("svgContainer").style.background = 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAHElEQVR4AWPYgAM8wAFoo2FUAy4JXAbRRMOoBgD42lgf5s146gAAAABJRU5ErkJggg==")';
- if (window.location.hash.length > 7)
- {
- var id = window.location.hash.substr(1);
- var m = id.match(/drawception\/(\w{8})/);
- if (m)
- {
- anbt.FromURL("drawception-get-panel.php?panelid=" + m[1]);
- } else {
- anbt.FromImgur(id);
- }
- }
- timerStart = Date.now();
- runTimer();
-}
-
-if (!("SVGPathSeg" in window))
-{
- require("pathseg.min.js", main)
-} else {
- main();
-}
diff --git a/newcanvas/favicon.png b/newcanvas/favicon.png
deleted file mode 100644
index 804326f041212ff573192811535aa3d99fd2d21e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 323
zcmV-J0lfZ+P)w0%SSkp62OEp&yoA+QdW4Mszr2CTV-)k?
zV|fYRH$%vl_|$b((1GyeXWQ+iMK+s@0lptB15%dHgW2Hj)5`TzBn>p59%#vQrv*Ld
z>*KrvML;MJL>Sdn_zPq@sVe{g002ovPDHLkV1ly9iwpn&
diff --git a/newcanvas/index.html b/newcanvas/index.html
deleted file mode 100644
index 5a22254..0000000
--- a/newcanvas/index.html
+++ /dev/null
@@ -1,138 +0,0 @@
-
-
-
-
-
-
-
Drawing in Time!
-
-
-
-
- A cow jumping over the moon
-
-
-
-
-
-
-
-
- Sandbox
- Public safe for work game
-
-
-
-
-
-
-
-
-
-
-
Guidelines
-
- - Simple drawings are welcome! Just give it your best shot
- - If the phrase is too difficult, use the skip button
- - Don't draw text - always draw a picture
- - Explicit (NSFW) drawings will get you banned
-
-
-
Sandbox
-
- - Welcome to the sandbox! Here you can play with all the palettes and drawing tools.
- - Saved drawings will contain your drawing process in PNG format.
- - After loading a drawing you can continue to draw or watch its playback.
- - Note that editing the PNG with playback with other programs will likely destroy the playback data.
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/newcanvas/newcanvasicons.png b/newcanvas/newcanvasicons.png
deleted file mode 100644
index ffc9fc84793d2fe67ee12a60a688f4bf9c3b198b..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 3810
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
C1mJ}L
diff --git a/newcanvas/nunito.woff b/newcanvas/nunito.woff
deleted file mode 100644
index 1e9545de3a04abfa324347df81a3ea962eb62f31..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 27584
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