{"version":3,"file":"279710511a7255b9c1da.chunk.js","mappings":"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","sources":["webpack://ch.enlightware.gamecreator/./src/apps/common/counters.ts","webpack://ch.enlightware.gamecreator/./src/apps/runtime/runtime-app.ts","webpack://ch.enlightware.gamecreator/./src/error/error-screen.ts","webpack://ch.enlightware.gamecreator/./src/imgui/imgui-platform.ts","webpack://ch.enlightware.gamecreator/./src/loading/loading-screen.ts","webpack://ch.enlightware.gamecreator/./src/mdcext/input-box/input-box.ts","webpack://ch.enlightware.gamecreator/./src/mdcext/message-box/message-box.ts","webpack://ch.enlightware.gamecreator/./src/mdcext/share/share-dialog.ts","webpack://ch.enlightware.gamecreator/./src/mdcext/snackbar/snackbar.ts","webpack://ch.enlightware.gamecreator/./src/network/api.ts","webpack://ch.enlightware.gamecreator/./src/runtime/runtime-pila.ts","webpack://ch.enlightware.gamecreator/./src/runtime/runtime-ui.ts","webpack://ch.enlightware.gamecreator/./src/translator/common-texts.ts","webpack://ch.enlightware.gamecreator/./src/utils/html.ts","webpack://ch.enlightware.gamecreator/./src/utils/share.ts","webpack://ch.enlightware.gamecreator/./src/vpl/color-theme.ts"],"sourcesContent":["/**\n * @module utils\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { Storage } from 'storage/storage';\n\nexport class Counters {\n\tstatic getGamePlayedCounter(storage: Storage, gameId: string) {\n\t\treturn storage.getCounter('game-played-' + gameId);\n\t}\n}\n","/**\n * Runtime only application\n * @module runtime-app\n * @preferred\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\n\nimport { showCustomError, showError } from 'error/error-screen';\nimport { screenManager } from 'screen/screen-manager';\nimport { showVersion } from 'apps/common/version';\nimport { connectAndCreateRustDbReadOnlyStorage, getRequestedGameId } from 'apps/common/browser-app';\nimport { Counters } from 'apps/common/counters';\nimport { RuntimeScreenWithUI } from 'runtime/runtime-ui';\nimport { checkBrowserAndWarnUser } from 'apps/common/browser-check-ui';\nimport { LoadingScreen } from 'loading/loading-screen';\nimport { nonnull, downcast, toStr, dynamicCast } from 'utils/types';\nimport { domEvent } from 'utils/async';\nimport { isFullScreenSupported, toggleFullScreen } from 'utils/html';\nimport { qsT } from 'translator/translator';\nimport { setLightTheme } from 'vpl/color-theme';\n\nimport * as Platform from 'imgui/imgui-platform';\nimport { Game } from 'game/game';\nimport { InputBlock } from 'blocks/conditions/input/input-block';\nimport { TouchBlock } from 'blocks/conditions/touch/touch-block';\nimport { Features } from 'apps/common/parameters';\nimport { getAudioContext } from 'runtime/runtime-audio';\nimport { loadGameFromBinary } from 'game/game-loader';\nimport { SpacedOr } from 'translator/common-texts';\nimport { Analytics } from 'apps/common/analytics';\nimport { ApiError } from 'network/api-types';\nimport { uiTextureFontLoadPromise } from 'runtime/runtime';\n\nAnalytics.appName = 'runtime';\n\n// setup mouse presence detection\nif (Features.assumeMousePresent) {\n\tPlatform.mouseInputSeen();\n} else {\n\tconst mouseEvents = [\n\t\t'mousedown',\n\t\t'mousemove',\n\t\t'mouseup',\n\t\t'mouseleave',\n\t\t'wheel',\n\t] as const;\n\tfor (const mouseEvent of mouseEvents) {\n\t\tdocument.documentElement.addEventListener(mouseEvent, () => Platform.mouseInputSeen() );\n\t}\n}\n\nexport class WelcomeScreen extends LoadingScreen {\n\tprivate readonly loadingText = downcast(HTMLElement, document.getElementById('loading-text'));\n\n\tconstructor() {\n\t\tsuper();\n\t\tif (Features.barePlayIntro) {\n\t\t\tfor (const element of ['loading-info', 'loading-miniature', 'loading-createOwn']) {\n\t\t\t\tdowncast(HTMLElement, document.getElementById(element)).style.display = 'none';\n\t\t\t}\n\t\t}\n\t}\n\n\tscrollToBottomWhenImageLoaded() {\n\t\tthis.miniatureElement.onload = () => this.element.scrollTo(0, this.element.scrollHeight - this.element.offsetHeight - 8);\n\t}\n\n\tsetLoaded() {\n\t\tthis.loadingText.innerHTML = 'play_arrow' + qsT('Play the game');\n\t\tnonnull(document.getElementById('loading-createOwn')).onclick =\n\t\t\t() => window.open('https://cand.li', '_blank');\n\t\tnonnull(document.getElementById('loading-title')).onclick =\n\t\t\t() => window.open('https://cand.li', '_blank');\n\t}\n\n\tasync clickEvent() {\n\t\tif (Features.barePlayIntro) {\n\t\t\treturn domEvent('onclick', nonnull(document.getElementById('loading')));\n\t\t} else {\n\t\t\treturn domEvent('onclick', this.loadingText);\n\t\t}\n\t}\n}\n\nfunction updateGameDescription(game: Game) {\n\tlet text = '';\n\tconst toPlayText = qsT('To play, ');\n\tconst mouseInput = Platform.hasMouseInput();\n\tif (game.hasAnyBlockOfType(InputBlock)) {\n\t\tconst inputMethods = [];\n\t\tif (screen.width > screen.height) {\n\t\t\tinputMethods.push('tablet');\n\t\t} else {\n\t\t\tinputMethods.push('smartphone');\n\t\t}\n\t\tif (mouseInput) {\n\t\t\tinputMethods.push('keyboard');\n\t\t\tinputMethods.push('mouse');\n\t\t}\n\t\tinputMethods.push('videogame_asset');\n\t\tif (inputMethods.length > 0) {\n\t\t\ttext = toPlayText + qsT('use ') + inputMethods.join(SpacedOr);\n\t\t}\n\t}\n\tif (game.hasAnyBlockOfType(TouchBlock)) {\n\t\tconst separatorText = qsT(', and ');\n\t\ttext += text.length === 0 ? toPlayText : separatorText;\n\t\ttext += qsT('press objects');\n\t}\n\tif (text.length > 0) {\n\t\ttext += qsT('.');\n\t\tnonnull(document.getElementById('loading-info__gameDescription')).innerHTML = text;\n\t}\n}\n\n\nasync function initAsync() {\n\tawait checkBrowserAndWarnUser(false);\n\n\tif (!isFullScreenSupported()) {\n\t\tnonnull(document.getElementById('loading-fullscreenText')).style.display = 'none';\n\t}\n\tconst loadingScreen = new WelcomeScreen();\n\tscreenManager.push(loadingScreen);\n\tloadingScreen.scrollToBottomWhenImageLoaded();\n\n\tconst requestedGameId = getRequestedGameId();\n\tif (requestedGameId !== null) {\n\t\tconst fontPromise = uiTextureFontLoadPromise();\n\t\tconst storage = await connectAndCreateRustDbReadOnlyStorage();\n\n\t\tconsole.debug(`Loading metadata for initially requested '${requestedGameId}'.`);\n\t\tconst miniatureURI = await storage.miniatureReadURI(requestedGameId);\n\t\tloadingScreen.setMiniature(miniatureURI);\n\n\t\tconsole.debug(`Loading initially requested game '${requestedGameId}'.`);\n\t\tconst game = (await loadGameFromBinary(requestedGameId, storage))[0];\n\t\tupdateGameDescription(game);\n\t\tvoid Counters.getGamePlayedCounter(storage, requestedGameId).inc();\n\t\tloadingScreen.setLoaded();\n\n\t\tawait loadingScreen.clickEvent();\n\t\t// to force the creation of the audio context following a user interaction\n\t\tgetAudioContext();\n\t\tawait toggleFullScreen();\n\t\tawait fontPromise;\n\t\tconst runtime = new RuntimeScreenWithUI(game);\n\t\tscreenManager.replaceWith(runtime);\n\t} else {\n\t\tshowCustomError(\n\t\t\tqsT('No game id provided!'),\n\t\t\tqsT('Please append ?GAME_ID to the URL, where GAME_ID is the identifier of your game.'),\n\t\t\ttrue,\n\t\t\tfalse\n\t\t);\n\t}\n}\n\nshowVersion();\n\n// hide font loading hack\nnonnull(document.getElementById('font-loading-hack')).style.display = 'none';\n\n// setup color theme\nsetLightTheme();\n\nvoid (async () => {\n\ttry {\n\t\tawait initAsync();\n\t} catch (e: any) {\n\t\tconst apiError = dynamicCast(ApiError, e);\n\t\tif (apiError !== null && apiError.url.includes('api/v0/games/') && apiError.method === 'GET' && apiError.statusCode === 410) {\n\t\t\tshowCustomError(qsT('Cannot load game'), qsT('This game has been deleted by its author.'), true, false);\n\t\t} else {\n\t\t\tshowError(toStr(e));\n\t\t}\n\t\tthrow e;\n\t}\n})();\n","/**\n * Error screen.\n * @module error\n * @preferred\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { nonnull } from 'utils/types';\nimport { Screen } from 'screen/screen';\nimport { screenManager } from 'screen/screen-manager';\nimport { reportError } from 'apps/common/analytics';\n\nclass ErrorScreen extends Screen {\n\tconstructor() {\n\t\tsuper(nonnull(document.getElementById('error')));\n\t\tnonnull(document.getElementById('error-reload')).onclick = location.reload.bind(location);\n\t}\n\n\tsetError(errorText: string) {\n\t\tnonnull(document.getElementById('error-text')).innerText = errorText;\n\t}\n\n\tsetIntro(introText: string) {\n\t\tnonnull(document.getElementById('error-intro')).innerText = introText;\n\t}\n\n\tdisableReloadButton() {\n\t\tnonnull(document.getElementById('error-reload')).style.display = 'none';\n\t}\n}\n\nconst errorScreen = new ErrorScreen();\n\nexport function showError(errorText: string) {\n\treportError('showError', errorText);\n\tif (!errorScreen.visible) {\n\t\terrorScreen.setError(errorText);\n\t\tscreenManager.push(errorScreen);\n\t}\n}\n\nexport function showCustomError(introText: string, errorText: string, disableReload: boolean, report: boolean) {\n\tif (report) {\n\t\treportError('showCustomError', errorText);\n\t}\n\tif (!errorScreen.visible) {\n\t\terrorScreen.setIntro(introText);\n\t\terrorScreen.setError(errorText);\n\t\tif (disableReload) {\n\t\t\terrorScreen.disableReloadButton();\n\t\t}\n\t\tscreenManager.push(errorScreen);\n\t}\n\n}\n\nexport function hideError() {\n\tif (screenManager.peek() === errorScreen) {\n\t\tscreenManager.popEvenIfLast();\n\t}\n}\n\nexport function notifyErrorToUser(ctx: string, f:(...args: AT) => RT, ...args: AT): RT {\n\ttry {\n\t\treturn f(...args);\n\t} catch (e: any) {\n\t\tshowError(`${ctx}: ${e.toString()}`);\n\t\tthrow e;\n\t}\n}","/**\n * @module imgui\n */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nlet hasTouch = false;\n\n/** Return whether platform has touch support */\nexport function hasTouchInput() {\n\treturn hasTouch;\n}\n\n/** Call this when touch input has been seen */\nexport function touchInputSeen() {\n\thasTouch = true;\n}\n\nlet hasMouse = false;\n\n/** Return whether platform has mouse support */\nexport function hasMouseInput() {\n\treturn hasMouse;\n}\n\n/** Call this when mouse input has been seen */\nexport function mouseInputSeen() {\n\thasMouse = true;\n}\n\n/** Return whether at least one gamepad was detected */\nexport function hasGamepadInput() {\n\tconst gamepads = navigator.getGamepads ? navigator.getGamepads() : [];\n\tconst validGamepads = [...gamepads].filter((gamepad) => gamepad !== null);\n\treturn validGamepads.length > 0;\n}\n","/**\n * Loading screen.\n * @module loading\n * @preferred\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { Screen } from 'screen/screen';\nimport { downcast } from 'utils/types';\n\nexport class LoadingScreen extends Screen {\n\tprotected miniatureElement = downcast(HTMLImageElement, document.getElementById('loading-miniature'));\n\n\tconstructor() {\n\t\tsuper(downcast(HTMLElement, document.getElementById('loading')));\n\t}\n\n\tsetMiniature(url: string) {\n\t\tthis.miniatureElement.src = url;\n\t}\n}\n","/**\n * @module mdc-ext\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\n\nimport { MDCDialog, MDCDialogCloseEvent } from '@material/dialog';\nimport { OkText } from 'mdcext/message-box/message-box';\nimport { qsT } from 'translator/translator';\nimport { getChildElementByClass, getChildElementByTag, htmlToElement } from 'utils/html';\nimport { defined, downcast, nonnull } from 'utils/types';\n\nconst element = nonnull(document.getElementById('input-box'));\nconst titleElement = getChildElementByClass(element, 'mdc-dialog__title');\nconst labelElement = getChildElementByTag(element, 'label');\nconst actionsElement = getChildElementByClass(element, 'mdc-dialog__actions');\nconst buttonElements: HTMLButtonElement[] = [];\n\nconst dialog = new MDCDialog(element);\nconst cb: [((_: number) => void)] = [(_: number) => {}];\ndialog.listen('MDCDialog:closed', (event: MDCDialogCloseEvent) => cb[0](parseInt(defined(event.detail.action), 10)));\nconst inputElement = getChildElementByTag(element, 'input');\n// Enter key closes the dialog with the first button\ninputElement.addEventListener('keyup', (e) => {\n\tif (e.key === 'Enter' || e.keyCode === 13) {\n\t\tif (inputElement.validity.valid) {\n\t\t\tdialog.close('0');\n\t\t}\n\t}\n});\n\nexport interface UserValidator {\n\tisValid(input: string): boolean;\n\tbuttonEnabled(isValid: boolean, button: number): boolean;\n}\n\n// Input validation support\nconst alwaysValid = {\n\tisValid: (_: string) => true,\n\tbuttonEnabled: () => true\n};\n\nlet customValidator: UserValidator = alwaysValid;\n\nfunction validateInput() {\n\tconst isValid = customValidator.isValid(inputElement.value);\n\tbuttonElements.forEach((button, index) => button.disabled = !customValidator.buttonEnabled(isValid, index));\n\tif (!isValid) {\n\t\tinputElement.setCustomValidity(qsT('Invalid input'));\n\t} else {\n\t\tinputElement.setCustomValidity('');\n\t}\n}\ninputElement.addEventListener('input', validateInput);\n\nfunction setupBox(title: string, text: string, buttons: string | string[], defaultButton?: number) {\n\ttitleElement.innerHTML = title;\n\tlabelElement.innerHTML = text;\n\tactionsElement.innerText = '';\n\tbuttonElements.length = 0;\n\tconst buttonArray = buttons instanceof Array ? buttons : [buttons];\n\tbuttonArray.forEach((button, index) => {\n\t\tconst defaultText = defaultButton === index ? ' data-mdc-dialog-button-default' : '';\n\t\t/* eslint-disable @stylistic/js/indent */\n\t\tactionsElement.appendChild(\n\t\t\thtmlToElement(\n`\t\t\t\t`\n\t\t\t)\n\t\t);\n\t\t/* eslint-enable @stylistic/js/indent */\n\t\tbuttonElements[index] = downcast(HTMLButtonElement, actionsElement.children[index]);\n\t});\n}\n\nexport function inputBox(title: string, text: string, buttons: string | string[] = OkText, defaultButton?: number, initialValue?: string, validator?: UserValidator) {\n\tsetupBox(title, text, buttons, defaultButton);\n\tcustomValidator = validator ?? alwaysValid;\n\tinputElement.type = 'text';\n\tinputElement.value = initialValue ?? '';\n\tvalidateInput();\n\tdialog.open();\n\treturn new Promise<[string, number]>((resolve, _) => {\n\t\tcb[0] = (action) => resolve([inputElement.value, action]);\n\t});\n}\n\nexport async function integerInputBox(title: string, text: string, buttons: string | string[] = OkText, defaultButton?: number, initialValue?: number, min?: number, max?: number, onChange?: (value: number) => void) {\n\tsetupBox(title, text, buttons, defaultButton);\n\tcustomValidator = alwaysValid;\n\tinputElement.type = 'number';\n\tinputElement.min = min?.toString() ?? '';\n\tinputElement.max = max?.toString() ?? '';\n\tinputElement.valueAsNumber = initialValue ?? 0;\n\tvalidateInput();\n\tconst safeIntegerValue = (unsafeValue: number) => {\n\t\tif (Number.isInteger(unsafeValue)) {\n\t\t\tlet value = Math.round(unsafeValue);\n\t\t\tif (min !== undefined) {\n\t\t\t\tvalue = Math.max(value, min);\n\t\t\t}\n\t\t\tif (max !== undefined) {\n\t\t\t\tvalue = Math.min(value, max);\n\t\t\t}\n\t\t\treturn value;\n\t\t} else {\n\t\t\treturn initialValue ?? 0;\n\t\t}\n\t};\n\tconst onChangeCb = onChange ? () => onChange(safeIntegerValue(inputElement.valueAsNumber)) : undefined;\n\tif (onChangeCb) {\n\t\tinputElement.addEventListener('input', onChangeCb);\n\t}\n\tdialog.open();\n\ttry {\n\t\tconst result = await new Promise<[number, number]>((resolve, _) => {\n\t\t\tcb[0] = (action) => {\n\t\t\t\tresolve([safeIntegerValue(inputElement.valueAsNumber), action]);\n\t\t\t}\n\t\t});\n\t\treturn result;\n\t} finally {\n\t\tif (onChangeCb) {\n\t\t\tinputElement.removeEventListener('input', onChangeCb);\n\t\t}\n\t}\n}","/**\n * @module mdc-ext\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { MDCDialog, MDCDialogCloseEvent } from '@material/dialog';\nimport { Cancel, Delete } from 'translator/common-texts';\nimport { qsT, qsTr } from 'translator/translator';\nimport { getChildElementByClass, htmlToElement } from 'utils/html';\nimport { defined, nonnull } from 'utils/types';\n\nconst element = nonnull(document.getElementById('message-box'));\nconst dialog = new MDCDialog(element);\nconst cb: [((_: number) => void)] = [(_: number) => {}];\ndialog.listen('MDCDialog:closed', (event: MDCDialogCloseEvent) => cb[0](parseInt(defined(event.detail.action), 10)));\n\nexport const OkText = qsT('Ok');\nexport const CloseText = qsT('Close');\n\nexport function isMessageBoxOpen() {\n\treturn dialog.isOpen;\n}\n\nexport function messageBox(title: string, text: string, buttons: string | string[] = OkText, defaultButton?: number) {\n\tconst titleElement = getChildElementByClass(element, 'mdc-dialog__title');\n\ttitleElement.innerHTML = title;\n\tconst contentElement = getChildElementByClass(element, 'mdc-dialog__content');\n\tcontentElement.innerHTML = text;\n\tconst actionsElement = getChildElementByClass(element, 'mdc-dialog__actions');\n\tactionsElement.innerText = '';\n\tconst buttonArray = buttons instanceof Array ? buttons : [buttons];\n\tbuttonArray.forEach((button, index) => {\n\t\tconst defaultText = defaultButton === index ? ' data-mdc-dialog-button-default' : '';\n\t\t/* eslint-disable @stylistic/js/indent */\n\t\tactionsElement.appendChild(\n\t\t\thtmlToElement(\n`\t\t\t\t`\n\t\t\t)\n\t\t);\n\t\t/* eslint-enable @stylistic/js/indent */\n\t});\n\tdialog.open();\n\treturn new Promise((resolve, _) => {\n\t\tcb[0] = (action) => resolve(action);\n\t});\n}\n\nexport async function confirmDeletion(what: string, extraInfoBeforeConfirmation?: string) {\n\tconst text = (extraInfoBeforeConfirmation ?? '') + qsTr('Are you sure you want to delete %1? You will not be able to undo.').args(what);\n\treturn await messageBox(\n\t\tqsTr('Delete %1?').args(what),\n\t\ttext,\n\t\t[Cancel, Delete],\n\t\t0\n\t) === 1;\n}\n\nexport async function fatalBox(content: string) {\n\tconst element = nonnull(document.getElementById('fatal-box'));\n\telement.innerHTML = content;\n\telement.style.display = '';\n\tlet input = '';\n\treturn new Promise((resolve, _) => {\n\t\tdocument.addEventListener('keydown', (e) => {\n\t\t\tinput += e.key;\n\t\t\tif (input === 'override') {\n\t\t\t\tconsole.warn('Overriding fatal box!')\n\t\t\t\telement.style.display = 'none';\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t});\n}","/**\n * @module mdc-ext\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { MDCDialog, MDCDialogCloseEvent } from '@material/dialog';\nimport { calcAbsUrl, ShareDataEmail, navigatorCanShare, emailShare, navigatorShare, copyToClipboard } from 'utils/share';\nimport { nonnull } from 'utils/types';\nimport qrcode from 'qrcode-generator';\nimport { createNewWorkspace } from 'apps/common/workspace';\nimport { Storage } from 'storage/storage';\nimport { qsT, qsTr } from 'translator/translator';\nimport { MemberInfo } from 'network/api-organisation';\nimport { getChildElementByClass } from 'utils/html';\n\ninterface ShareDialogData extends ShareDataEmail {\n\tcontext: string;\n\tname: string\n}\n\ntype MDCDialogCloseCallback = (event: MDCDialogCloseEvent) => void;\n\nconst shareDialogElement = nonnull(document.getElementById('shareDialog'));\n\nclass ShareDialog extends MDCDialog {\n\tconstructor() {\n\t\tsuper(shareDialogElement);\n\t\tshareDialogElement.addEventListener('keydown', (event) => {\n\t\t\tif (event.which === 27) { // `Escape` key\n\t\t\t\tthis.close();\n\t\t\t\tevent.stopPropagation();\n\t\t\t}\n\t\t});\n\t}\n\n\tasync share(toShare: ShareDialogData) {\n\t\t// prepare dialog\n\t\tconst shareOtherButton = nonnull(document.getElementById('shareDialog-other'));\n\t\tshareOtherButton.style.visibility = navigatorCanShare(toShare) ? 'visible' : 'hidden';\n\t\tconst title = nonnull(document.getElementById('shareDialog-title'));\n\t\ttitle.innerText = qsTr('Share %1 via').args(toShare.context);\n\t\t// build and display QR code\n\t\tconst qr = qrcode(0, 'M');\n\t\tqr.addData(toShare.url);\n\t\tqr.make();\n\t\tconst qrContainer = nonnull(document.getElementById('shareDialog-qrCode'));\n\t\tqrContainer.innerHTML = qr.createImgTag(1, 0);\n\t\t// open dialog and wait for it to close\n\t\tthis.open();\n\t\tlet callBack: MDCDialogCloseCallback | null = null;\n\t\tconst action = await new Promise((resolve, _) => {\n\t\t\tcallBack = (event: MDCDialogCloseEvent) => resolve(event.detail.action ?? '');\n\t\t\tthis.listen('MDCDialog:closed', callBack);\n\t\t});\n\t\tconst nonnullCallBack = nonnull(callBack as unknown as MDCDialogCloseCallback);\n\t\tthis.unlisten('MDCDialog:closed', nonnullCallBack);\n\t\t// take decision in function of action\n\t\tif (action === 'other') {\n\t\t\tconsole.debug(`Sharing ${toShare.context} ${toShare.name} through navigator`);\n\t\t\tawait navigatorShare(toShare);\n\t\t} else if (action === 'email') {\n\t\t\tconsole.debug(`Sharing ${toShare.context} ${toShare.name} through email`);\n\t\t\temailShare(toShare);\n\t\t} else if (action === 'copy') {\n\t\t\tconsole.debug(`Sharing ${toShare.context} ${toShare.name} through clipboard`);\n\t\t\tcopyToClipboard(toShare.url);\n\t\t} else {\n\t\t\tconsole.debug('Closed sharing dialog without action');\n\t\t}\n\t}\n}\n\nlet shareDialog: ShareDialog | null = null;\n\nfunction getDialog() {\n\tif (shareDialog === null) {\n\t\tshareDialog = new ShareDialog();\n\t}\n\treturn shareDialog;\n}\n\nconst myCandliGame = qsT('my Candli game');\nconst MyCandliGame = qsT('My Candli game');\nconst aCoolCandliGame = qsT('a cool Candli game');\nconst ACoolCandliGame = qsT('A cool Candli game');\n\nexport async function shareGameToPlay(gameId: string, self: boolean) {\n\tconst shareLink = calcAbsUrl(`play?${gameId}`);\n\tconst candliReference = self ? myCandliGame : aCoolCandliGame;\n\tawait getDialog().share({\n\t\tcontext: qsT('game'),\n\t\tname: gameId,\n\t\ttitle: self ? MyCandliGame : ACoolCandliGame,\n\t\ttext: qsTr('Hi, you can try %1 at:').args(candliReference),\n\t\turl: shareLink,\n\t\temailBody: qsTr('Hi,\\n\\nYou can try %1 at:\\n%2\\n\\nEnjoy!').args(candliReference, shareLink)\n\t});\n}\n\nexport async function shareGameToDuplicate(gameId: string, storage: Storage) {\n\tconst workspace = storage.getWorkspace(createNewWorkspace(), false);\n\tawait workspace.addFront(gameId);\n\tconst shareLink = calcAbsUrl(`create?ws=${workspace.key}`);\n\tawait getDialog().share({\n\t\tcontext: qsT('game to duplicate'),\n\t\tname: gameId,\n\t\ttitle: MyCandliGame,\n\t\ttext: qsT('Hi, you can play and modify my Candli game at:'),\n\t\turl: shareLink,\n\t\temailBody: qsTr('Hi,\\n\\nYou can play and modify my Candli game at:\\n%1\\n\\nEnjoy!').args(shareLink)\n\t});\n}\n\nconst myCandliGames = qsT('my Candli games');\nconst MyCandliGames = qsT('My Candli games');\nconst coolCandliGames = qsT('cool Candli games');\nconst CoolCandliGames = qsT('Cool Candli games');\n\nexport async function shareWorkspace(key: string, self: boolean) {\n\tconst shareLink = calcAbsUrl(`create?ws=${key}`);\n\tconst candliReference = self ? myCandliGames : coolCandliGames;\n\tawait getDialog().share({\n\t\tcontext: qsT('workspace'),\n\t\tname: key,\n\t\ttitle: self ? MyCandliGames : CoolCandliGames,\n\t\ttext: qsTr('Hi, you can try and adapt %1 at:').args(candliReference),\n\t\turl: shareLink,\n\t\temailBody: qsTr('Hi,\\n\\nYou can try and adapt %1 at:\\n%2\\n\\nEnjoy!').args(candliReference, shareLink)\n\t});\n}\n\nexport async function shareLoginURL(url: string, user: MemberInfo) {\n\tconst name = user.nameOrDefault;\n\tawait getDialog().share({\n\t\tcontext: qsTr('login URL for %1').args(name),\n\t\tname,\n\t\ttitle: qsTr('Login URL for Candli user %1').args(name),\n\t\ttext: qsTr('Hi, Candli user %1 can log in at:').args(user.nameOrDefault),\n\t\turl,\n\t\temailBody: qsTr('Hi,\\n\\nCandli user %1 can log in at:\\n%2\\n\\nEnjoy!').args(name, url)\n\t});\n}\n\nconst embedDialog = new MDCDialog(nonnull(document.getElementById('embedDialog')));\n\nexport async function embed(gameId: string) {\n\tconst shareLink = calcAbsUrl(`play?${gameId}`);\n\tconst shareText = ``;\n\tnonnull(document.getElementById('embedDialog-code')).innerText = shareText;\n\tembedDialog.open();\n\tlet callBack: MDCDialogCloseCallback | null = null;\n\tconst action = await new Promise((resolve, _) => {\n\t\tcallBack = (event: MDCDialogCloseEvent) => resolve(event.detail.action ?? '');\n\t\tembedDialog.listen('MDCDialog:closed', callBack);\n\t});\n\tconst nonnullCallBack = nonnull(callBack as unknown as MDCDialogCloseCallback);\n\tembedDialog.unlisten('MDCDialog:closed', nonnullCallBack);\n\tif (action === 'copy') {\n\t\tconsole.debug('Copying embedding code to clipboard');\n\t\tcopyToClipboard(shareText);\n\t} else {\n\t\tconsole.debug('Closed embed dialog without action');\n\t}\n}\n","/**\n * @module mdc-ext\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { downcast, nonnull } from 'utils/types';\nimport { MDCSnackbar } from '@material/snackbar';\nimport { getChildElementByClass } from 'utils/html';\n\nclass Snackbar extends MDCSnackbar {\n\tprivate textButton: HTMLButtonElement;\n\n\tconstructor() {\n\t\tsuper(nonnull(document.getElementById('snackbar')));\n\t\tconst root = nonnull(document.getElementById('snackbar'));\n\t\tthis.textButton = downcast(HTMLButtonElement, getChildElementByClass(root, 'mdc-button'));\n\t}\n\n\tshow(text: string, textButtonData: null | [string, () => void] = null) {\n\t\tthis.labelText = text;\n\t\tif (textButtonData !== null) {\n\t\t\tthis.textButton.innerText = textButtonData[0];\n\t\t\tthis.textButton.onclick = textButtonData[1];\n\t\t} else {\n\t\t\tthis.textButton.innerText = '';\n\t\t\tthis.textButton.onclick = () => {};\n\t\t}\n\t\tthis.textButton.style.display = textButtonData !== null ? 'block' : 'none';\n\t\tthis.open();\n\t}\n}\n\nexport const snackbar = new Snackbar();\n","/**\n * @module utils\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { defined, isArrayBuffer, nonnull, toStr } from 'utils/types';\nimport { assert } from 'utils/assert';\nimport { getLoggedInUserInfo, isUserLoggedIn, Parameters} from 'apps/common/parameters';\nimport { Login } from 'apps/common/login-manager';\nimport { BlobWithContentType, ContentTypes, ApiError, UserInfo, RedeemVoucherResult, RedeemVoucherParams } from './api-types';\nimport { isValidIdentifier } from 'utils/text';\nimport { sleep } from 'utils/async';\n\ntype FetchContent = null | string | object | BlobWithContentType;\nfunction isBlobWithContentType(fc: FetchContent) : fc is BlobWithContentType {\n\treturn fc !== null &&\n\t\ttypeof(fc) === 'object' &&\n\t\tObject.prototype.hasOwnProperty.call(fc, 'value') &&\n\t\tObject.prototype.hasOwnProperty.call(fc, 'contentType') &&\n\t\tisArrayBuffer((fc as any).value);\n}\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\nlet sessionExtraHeaders = {};\nlet baseUrl = (Parameters.storageLocation ?? (\n\tlocation.href.replace(/\\/[^?#/]*([?#].*)?$/, '')\n));\ntype ReportOnlineStatus = (online: boolean) => void;\nlet reportOnlineStatus: ReportOnlineStatus = () => {};\n\nexport function setReportOnlineStatus(_reportOnlineStatus: ReportOnlineStatus) {\n\treportOnlineStatus = _reportOnlineStatus;\n}\n\n// Overrides URL from Parameters. Mostly for unit testing.\nexport function setBaseUrl(_baseUrl: string) {\n\tbaseUrl = _baseUrl;\n}\n\nexport function getHttpBaseUrl() {\n\treturn baseUrl;\n}\n\nexport function getWsBaseUrl() {\n\treturn baseUrl.replace(/^http/, 'ws');\n}\n\nexport function getApiBaseUrl() {\n\treturn getHttpBaseUrl() + '/api';\n}\n\nexport function setExtraFetchHeaders(extraHeaders: object) {\n\tsessionExtraHeaders = Object.assign({}, extraHeaders);\n}\n\n\nexport async function retryFetchIfForbidden(\n\tfn: (url: string, ...args: P) => Promise,\n\turl: string,\n\tretryUrl: string | null,\n\t...args: P\n): Promise {\n\tif (retryUrl === null) {\n\t\treturn await fn(url, ...args);\n\t} else {\n\t\ttry {\n\t\t\treturn await fn(url, ...args);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiError && error.statusCode === 403) {\n\t\t\t\treturn await fn(retryUrl, ...args);\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n}\n\nclass FetchWithRetryError extends Error {\n\tconstructor(public readonly lastError: any, public readonly totalTriedTimeSec: number) {\n\t\tsuper(`Fetch with retry for ${totalTriedTimeSec} seconds failed: ${toStr(lastError)}`);\n\t}\n}\n\nexport async function fetch(url: string, method: HttpMethod, fetchContent?: FetchContent, extraHeaders?: object) {\n\tconst [contentType, body] = ((): [string | null, string | ArrayBuffer | null] => {\n\t\tif (fetchContent === undefined) {\n\t\t\treturn [null, null];\n\t\t}\n\t\tif (typeof fetchContent === 'string') {\n\t\t\treturn [method === 'GET' ? null : ContentTypes.Text, fetchContent];\n\t\t} else if (isBlobWithContentType(fetchContent)) {\n\t\t\treturn [fetchContent.contentType, fetchContent.value];\n\t\t} else {\n\t\t\treturn [ method === 'GET' ? null : ContentTypes.Json, JSON.stringify(fetchContent)];\n\t\t}\n\t})();\n\t// console.debug(`Fetching url '${url}' method=${method}, content-type=${contentType}, body:`, body);\n\tconst headers = Object.assign({}, sessionExtraHeaders, extraHeaders ?? {}, contentType === null ? {} : { 'Content-Type': contentType })\n\tconst options = {\n\t\tmethod, headers,\n\t\tcache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached\n\t\tcredentials: 'same-origin', // include, *same-origin, omit\n\t\treferrer: 'no-referrer', // no-referrer, *client\n\t\tbody\n\t} as RequestInit;\n\n\tlet data: Response;\n\ttry {\n\t\tlet retry = 5;\n\t\tlet sleepDuration = 0.2;\n\t\tconst trialStartTime = Date.now();\n\t\twhile (true) {\n\t\t\ttry {\n\t\t\t\tdata = await window.fetch(url, options);\n\t\t\t\tbreak;\n\t\t\t} catch (e) {\n\t\t\t\tif (retry > 0) {\n\t\t\t\t\tconsole.log(`Fetch failed: ${e}, retrying in ${sleepDuration} seconds...`);\n\t\t\t\t\tretry -= 1;\n\t\t\t\t} else {\n\t\t\t\t\tconst totalTriedTimeSec = (Date.now() - trialStartTime) / 1000;\n\t\t\t\t\tthrow new FetchWithRetryError(e, totalTriedTimeSec);\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait sleep(sleepDuration);\n\t\t\tsleepDuration *= 3;\n\t\t}\n\t\treportOnlineStatus(true);\n\t} catch (e) {\n\t\treportOnlineStatus(false);\n\t\tif (e instanceof Error) {\n\t\t\te.message += ` (${method} ${url})`;\n\t\t}\n\t\tthrow e;\n\t}\n\tif (!data.ok) {\n\t\tthrow new ApiError(method, url, data.status, await data.text());\n\t}\n\treturn data;\n}\n\n\nexport async function fetchJson(url: string, method: HttpMethod, body?: FetchContent) {\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\treturn (await fetch(url, method, body)).json();\n}\nexport async function fetchString(url: string, method: HttpMethod, body?: FetchContent) {\n\treturn (await fetch(url, method, body)).text();\n}\nexport async function fetchOptionalString(url: string, method: HttpMethod, body?: FetchContent) {\n\tconst response = await fetch(url, method, body)\n\tif (response.status === 204) {\n\t\treturn null;\n\t} else {\n\t\treturn response.text();\n\t}\n}\nexport async function fetchJsonSendBinary(url: string, method: HttpMethod, contentType: string, contentValue: ArrayBuffer) {\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\treturn (await fetch(url, method, { contentType, value: contentValue })).json();\n}\n\nexport async function fetchBinary(url: string, method: HttpMethod, fetchContent?: FetchContent, extraHeaders?: object): Promise {\n\tconst data = await fetch(url, method, fetchContent, extraHeaders);\n\treturn { value: await data.arrayBuffer(), contentType: data.headers.get('Content-Type') };\n}\n\nexport async function userGameFeedback(gameKey: string, what: 'inappropriate') {\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\treturn fetchJson(getApiBaseUrl() + `/v0/feedback/${what}/game/${gameKey}`, 'PUT')\n}\n\nexport async function genLogin() {\n\treturn await fetchJson(getApiBaseUrl() + '/v0/user/gen_login', 'POST') as Login;\n}\n\nexport async function getUserInfo() {\n\treturn await fetchJson(getApiBaseUrl() + '/v0/user/info', 'GET') as UserInfo;\n}\n\n\nexport class ScriptPackageLocator {\n\tconstructor(\n\t\tpublic readonly owner: string,\n\t\tpublic readonly packageName: string,\n\t\tpublic readonly version: string,\n\t\tpublic readonly packageType: string = 'rustli-sfp'\n\t) { }\n\n\tstatic parseDependencyPath(path: string) {\n\t\tconst parts = path.split('/');\n\t\tif (parts.length !== 2) {\n\t\t\tthrow new Error(`Invalid path \"${path}\", expected exactly one '/'`);\n\t\t}\n\t\tconst owner = defined(parts[0]);\n\t\t// TODO: validate owner format in the front-end\n\t\tconst versionedPackage = defined(parts[1]).split('@');\n\t\tif (versionedPackage.length !== 2) {\n\t\t\tthrow new Error(`Invalid versioned package name \"${parts[1]}\", expected exactly one '@'`);\n\t\t}\n\t\tconst packageName = defined(versionedPackage[0]);\n\t\tif (!isValidIdentifier(packageName)) {\n\t\t\tthrow new Error(`Invalid package name \"${packageName}\", must be a valid identifier`);\n\t\t}\n\t\tconst version = defined(versionedPackage[1]);\n\t\t// TODO: validate version format in the front-end\n\t\treturn new ScriptPackageLocator(owner, packageName, version);\n\t}\n\n\tget versionedPackageName() {\n\t\treturn `${this.packageName}@${this.version}`;\n\t}\n\tget dependencyPath() {\n\t\treturn `${this.owner}/${this.versionedPackageName}`;\n\t}\n\tget locatorPath() {\n\t\treturn `${this.packageType}/${this.dependencyPath}`;\n\t}\n\n\ttoString() {\n\t\treturn this.locatorPath;\n\t}\n}\n\nexport async function getRustliSfp(packageLocator: ScriptPackageLocator) {\n\tconst url = getApiBaseUrl() + `/v0/references/${packageLocator.locatorPath}`;\n\tconst data = await fetchBinary(url, 'GET');\n\tassert(data.contentType === 'text/' + packageLocator.packageType, `Unexpected content-type '${data.contentType}' at ${url}`);\n\tconst decoder = new TextDecoder('UTF-8');\n\tconst code = decoder.decode(data.value);\n\tconsole.debug(`Got Rustli SFP from ${url}:\\n${code}`);\n\treturn code;\n}\n\nexport class VoucherValidationError extends Error {\n}\nexport function normalizeAndValidateVoucher(voucherUid: string) {\n\tconst minimizedVoucherUid = voucherUid.toLowerCase().replace(/[^a-z0-9]/g, '');\n\tif (minimizedVoucherUid.length !== 12) {\n\t\tconst error = `Invalid voucher uid: '${voucherUid}'. It must have exactly 12 alphanumeric characters but has ${minimizedVoucherUid.length}!`;\n\t\tconsole.warn(error);\n\t\tthrow new VoucherValidationError(error);\n\t}\n\tconst normalizedVoucherUid = [0, 4, 8].map(i => minimizedVoucherUid.substring(i, i + 4)).join('-');\n\tconsole.debug(`Voucher '${voucherUid}' normalized to '${normalizedVoucherUid}'.`);\n\treturn normalizedVoucherUid;\n}\n\nexport async function redeemVoucher(voucherUid: string) {\n\treturn await fetchJson(getApiBaseUrl() + '/v0/user/redeem_voucher', 'POST', { voucherUid } as RedeemVoucherParams) as RedeemVoucherResult ;\n}\n\nconst LocalStorageAttributePrefix = 'gc-attributes/';\n\n// eslint-disable-next-line @typescript-eslint/require-await\nexport async function getAttributeRustServerOrLocal(name: string) {\n\tconst userInfo = getLoggedInUserInfo();\n\tif (userInfo !== null) {\n\t\treturn userInfo.attributes.get(name) ?? '';\n\t} else {\n\t\treturn localStorage.getItem(LocalStorageAttributePrefix + name) ?? '';\n\t}\n}\n\nexport async function setAttributeRustServerOrLocal(name: string, value: string) {\n\tconst userInfo = getLoggedInUserInfo();\n\tif (userInfo !== null) {\n\t\tconst oldValue = userInfo.attributes.get(name);\n\t\tif (value !== oldValue) {\n\t\t\tawait fetchString(getApiBaseUrl() + '/v0/user/attributes/' + name, 'PUT', value);\n\t\t\tuserInfo.attributes.set(name, value);\n\t\t}\n\t} else {\n\t\tlocalStorage.setItem(LocalStorageAttributePrefix + name, value);\n\t}\n}\n\nexport async function migrateAttributesToServer() {\n\tif (!isUserLoggedIn()) {\n\t\treturn;\n\t}\n\tconst len = localStorage.length;\n\tconst keys: string[] = [];\n\tfor (let i = 0; i < len; ++i) {\n\t\tconst key = localStorage.key(i);\n\t\tif (key !== null) {\n\t\t\tkeys.push(key);\n\t\t}\n\t}\n\tconst indexStart = LocalStorageAttributePrefix.length;\n\tfor (const key of keys) {\n\t\tif (key.startsWith(LocalStorageAttributePrefix)) {\n\t\t\tconst name = key.substring(indexStart);\n\t\t\tconst existingValue = await getAttributeRustServerOrLocal(name);\n\t\t\tif (existingValue !== '') {\n\t\t\t\tconsole.debug(`Not migrating attribute \"${name}\" due to already existing on server.`)\n\t\t\t} else {\n\t\t\t\tconsole.debug(`Migrating attribute \"${name}\" to server.`);\n\t\t\t\tconst value = nonnull(localStorage.getItem(key));\n\t\t\t\tawait setAttributeRustServerOrLocal(name, value);\n\t\t\t\tlocalStorage.removeItem(key);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport async function listGames() {\n\treturn (await fetchJson(getApiBaseUrl() + '/v0/list_games', 'GET')) as Promise;\n}\n\nexport interface ServerInfo {\n\trevision: string;\n\tcloudflareTurnstileSiteKey: string | null;\n}\n\nexport async function getServerInfo() {\n\tconst url = new URL(getHttpBaseUrl() + '/api/v0/server/info');\n\treturn await (fetchJson(url.toString(), 'GET') as Promise);\n}\n\n\n\nexport async function userWithEmailExists(email: string): Promise {\n\tconst url = new URL(getHttpBaseUrl() + '/auth/api/v0/user-with-email-exists');\n\turl.searchParams.set('email_address', email);\n\treturn await (fetchJson(url.toString(), 'GET') as Promise);\n}\n\nexport interface EmailOtpResponse {\n\tloginId: string,\n\totpLength: number,\n\temailId: string,\n}\n\n\nexport async function emailOtp(emailAddress: string, validatedHumanToken: string, lang: string): Promise {\n\treturn await (fetchJson(getHttpBaseUrl() + '/auth/api/v0/email-otp', 'POST', { emailAddress, validatedHumanToken, lang }) as Promise);\n}\n\n/**\n * Set the username of a user given by uuid or special value 'self'.\n * @param userUuid\n * @param newName\n * @returns\n */\nexport async function setUsername(userUuid: string, newName: string | null) {\n\treturn await (fetchJson(getApiBaseUrl() + `/v0/users/${userUuid}/properties`, 'PATCH', { name: newName }) as Promise);\n}\n\nexport interface GameEventCoreData {\n\tsession: string,\n\tname: string | undefined,\n\tdata: string | undefined,\n}\n\nexport interface RuntimeGameEvent extends GameEventCoreData {\n\ttype: 'log' | 'err',\n}\n\nexport interface ScoreGameEvent extends GameEventCoreData {\n\ttype: 'score',\n\torderKey: number,\n\tdata: string,\n}\n\nexport type GameEvent = RuntimeGameEvent | ScoreGameEvent;\n\nexport type GameEventType = GameEvent['type'];\n\nexport async function postGameEvent(gameKey: string, event: GameEvent) {\n\tconst url = getApiBaseUrl() + `/v0/games/${gameKey}/events/${event.type}`;\n\tconst { type: _, ...eventData } = event;\n\tconst result = await fetchString(url, 'POST', eventData);\n\treturn parseInt(result, 10); // event id\n}\n\nexport async function countGameEvents(gameKey: string, eventType: GameEventType) {\n\tconst url = getApiBaseUrl() + `/v0/games/${gameKey}/events/${eventType}/count`;\n\tconst result = await fetchString(url, 'GET');\n\treturn parseInt(result, 10); // event count\n}\n\nexport interface GameEventData extends GameEventCoreData {\n\tid: number,\n\ttime: string,\n\torderKey: number | undefined,\n}\n\nexport async function listGameEvents(gameKey: string, eventType: GameEventType, limit?: number, offset?: number) {\n\tconst limitStr = limit === undefined ? '' : `&limit=${limit}`;\n\tconst offsetStr = offset === undefined ? '' : `&offset=${offset}`;\n\tconst url = getApiBaseUrl() + `/v0/games/${gameKey}/events/${eventType}/entries?${limitStr}${offsetStr}`;\n\treturn await fetchJson(url, 'GET') as Promise;\n}","/**\n * @module runtime\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nexport interface PilaCompetencyApi {\n\tgetCompetency(name: string, latest: boolean): [number, number] | null;\n\tsetCompetency(name: string, latest: boolean, v0: number, v1: number): void;\n}\n\nlet reportFns: PilaCompetencyApi = {\n\tgetCompetency: () => null,\n\tsetCompetency: () => {},\n}\n\nexport function setPilaReportFunctions(fns: PilaCompetencyApi) {\n\treportFns = fns;\n}\n\nexport function getPilaReportFunctions() {\n\treturn reportFns;\n}","/**\n * @module runtime\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { nonnull } from '../utils/types';\nimport { toggleFullScreen, isFullScreenSupported, isFullScreen } from '../utils/html';\nimport { Game } from '../game/game';\nimport { reportLog } from 'apps/common/analytics';\nimport { Features } from 'apps/common/parameters';\nimport { MDCMenu } from '@material/menu';\nimport { snackbar } from 'mdcext/snackbar/snackbar';\nimport * as Api from 'network/api';\nimport { shareGameToPlay } from 'mdcext/share/share-dialog';\nimport { qsT } from 'translator/translator';\nimport { messageBox } from 'mdcext/message-box/message-box';\nimport { RuntimeScreen } from './runtime';\nimport { inputBox } from 'mdcext/input-box/input-box';\nimport { Cancel } from 'translator/common-texts';\n\nexport { RuntimeContactCallback as RuntimeCollisionCallback } from './runtime-core';\n\nexport class RuntimeScreenWithUI extends RuntimeScreen {\n\tprivate moreMenu = new MDCMenu(nonnull(document.getElementById('runtime-more__menu')));\n\n\tconstructor(game: Game) {\n\t\tsuper(game);\n\n\t\tif (isFullScreenSupported()) {\n\t\t\tconst fullScreenEntry = nonnull(document.getElementById('runtime-fullscreen'));\n\t\t\tfullScreenEntry.onclick = async (event) => {\n\t\t\t\tevent.stopPropagation();\n\t\t\t\tawait toggleFullScreen();\n\t\t\t\tthis.moreMenu.open = false;\n\t\t\t};\n\t\t\tdocument.documentElement.addEventListener('fullscreenchange', () => {\n\t\t\t\tconst isCurrentFullscreen = isFullScreen();\n\t\t\t\tfor (const node of fullScreenEntry.childNodes) {\n\t\t\t\t\tif (node.nodeType === 1) { // ELEMENT_NODE\n\t\t\t\t\t\tnode.textContent = isCurrentFullscreen ? 'fullscreen_exit' : 'fullscreen';\n\t\t\t\t\t}\n\t\t\t\t\tif (node.nodeType === 3 && node.textContent?.trim() !== '') { // TEXT_NODE\n\t\t\t\t\t\tnode.textContent = isCurrentFullscreen ? qsT('Exit fullscreen') : qsT('Enter fullscreen');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\tnonnull(document.getElementById('runtime-fullscreen')).style.display = 'none';\n\t\t}\n\t\tnonnull(document.getElementById('runtime-share')).onclick = async (event) => {\n\t\t\tevent.stopPropagation();\n\t\t\tawait shareGameToPlay(game.id, false);\n\t\t\tthis.moreMenu.open = false;\n\t\t};\n\t\tnonnull(document.getElementById('runtime-report')).onclick = (event) => {\n\t\t\tevent.stopPropagation();\n\t\t\tthis.report();\n\t\t\tthis.moreMenu.open = false;\n\t\t};\n\t\tconst moreButton = nonnull(document.getElementById('runtime-more'));\n\t\tif (!Features.hideRuntimeMore) {\n\t\t\tmoreButton.onclick = () => this.moreMenu.open = true;\n\t\t\tthis.moreMenu.listen('MDCMenuSurface:opened', this.pause.bind(this));\n\t\t\tthis.moreMenu.listen('MDCMenuSurface:closed', this.unpause.bind(this));\n\t\t} else {\n\t\t\tmoreButton.style.display = 'none';\n\t\t}\n\t}\n\n\tprivate report() {\n\t\tvoid (async () => {\n\t\t\tconst title = qsT('Report inappropriate content?');\n\t\t\tconst selectedButtonIndex = await messageBox(\n\t\t\t\ttitle,\n\t\t\t\tqsT('Are you sure you want to report that this game has inappropriate content?'),\n\t\t\t\t[qsT('No, cancel'), qsT('Yes, report')],\n\t\t\t\t0\n\t\t\t);\n\t\t\tif (selectedButtonIndex !== 1) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst textReport = await inputBox(\n\t\t\t\ttitle,\n\t\t\t\tqsT('What is inappropriate?'),\n\t\t\t\t[Cancel, qsT('Report')]\n\t\t\t);\n\t\t\tif (textReport[1] !== 1 || textReport[0].trim() === '') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait Api.userGameFeedback(this.getGameId(), 'inappropriate').then(() => {\n\t\t\t\treportLog('inappropriateContentReported', textReport[0]);\n\t\t\t\tsnackbar.show(qsT('Thank you for your report, we will investigate!'));\n\t\t\t});\n\t\t})();\n\t}\n}\n","/**\n * @module translator\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { getLanguage, qsTr } from './translator';\nimport { qsT } from './translator';\n\nexport const Quoting = qsTr('\"%1\"');\nexport const WithNumberSign = qsTr('#%1');\n\nexport const Or = qsT('or');\nexport const SpacedOr = ' ' + Or + ' ';\nexport const And = qsT('and');\nexport const SpacedAnd = ' ' + And + ' ';\nexport const Not = qsT('not');\n\nexport const Nowhere = qsT('nowhere');\nexport const Nothing = qsT('nothing');\nexport const DoNothing = qsT('do nothing');\nexport const Never = qsT('never');\n\nexport const Unnamed = qsT('unnamed');\nexport const CopyOf = qsTr('Copy of %1');\n\nexport const UndefinedText = qsT('undefined');\n\n// Common entries for dialogues\nexport const Cancel = qsT('Cancel');\nexport const Delete = qsT('Delete');\nexport const Rename = qsT('Rename');\nexport const Change = qsT('Change');\nexport const Add = qsT('Add');\nexport const Create = qsT('Create');\n\nexport const ScoreText = qsT('score');\nexport const TheScoreTextNom = qsT('the score', 'nominative');\nexport const TheScoreTextAcc = qsT('the score', 'accusative');\n\nfunction langIndex() {\n\tswitch (getLanguage()) {\n\t\tcase 'fr': return 1;\n\t\tcase 'de': return 2;\n\t\tcase 'pt': return 3;\n\t\tdefault: return 0;\n\t}\n}\n\nexport const enum DirectionContext {\n\tKey,\n\tSide,\n\tVector,\n}\n\nconst UpTexts = [\n\t['up', 'top', 'up'], // en\n\t['haut', 'en haut', 'vers le haut'], // fr\n\t['Aufwärtstaste', 'oberen', 'nach oben'], // de\n\t['direcional para cima', 'acima', 'para cima'], // pt\n] as const;\n\nexport function upText(ctx: DirectionContext) {\n\treturn UpTexts[langIndex()][ctx];\n}\n\nconst LeftTexts = [\n\t['left', 'left', 'left'], // en\n\t['gauche', 'à gauche', 'vers la gauche'], // fr\n\t['Linkstaste', 'linken', 'nach links'], // de\n\t['direcional para a esquerda', 'à esquerda', 'para a esquerda'], // pt\n] as const;\n\nexport function leftText(ctx: DirectionContext) {\n\treturn LeftTexts[langIndex()][ctx];\n}\n\nconst RightTexts = [\n\t['right', 'right', 'right'], // en\n\t['droite', 'à droite', 'vers la droite'], // fr\n\t['Rechtstaste', 'rechten', 'nach rechts'], // de\n\t['direcional para a direita', 'à direita', 'para a direita'], // pt\n] as const;\n\nexport function rightText(ctx: DirectionContext) {\n\treturn RightTexts[langIndex()][ctx];\n}\n\nconst DownTexts = [\n\t['down', 'bottom', 'down'], // en\n\t['bas', 'en bas', 'vers le bas'], // fr\n\t['Abwärtstaste', 'unteren', 'nach unten'], // de\n\t['direcional para baixo', 'abaixo', 'para baixo'], // pt\n] as const;\n\nexport function downText(ctx: DirectionContext) {\n\treturn DownTexts[langIndex()][ctx];\n}\n\nexport const ScalingFactorOptText = qsT('scaling factor (optional)');","/**\n * @module utils\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { Vector2 } from 'math/linalg';\nimport { MDCSelect } from '@material/select';\nimport Bowser from 'bowser';\nimport { Features, Parameters } from 'apps/common/parameters';\nimport { dynamicCast, nonnull, toStr } from './types';\nimport { reportLog } from 'apps/common/analytics';\n\nexport function getElement(id: string): HTMLElement {\n\tconst element = document.getElementById(id);\n\tif (!element) {\n\t\tthrow new Error(`Element with id ${id} not found!`);\n\t}\n\treturn element;\n}\n\nexport function getChildElementByClass(parent: HTMLElement, className: string): HTMLElement {\n\tconst els = parent.getElementsByClassName(className);\n\tif (els.length === 0) {\n\t\tthrow new Error(`There is no element of class ${className} in ${toStr(parent)}!`);\n\t} else if (els.length > 1) {\n\t\tthrow new Error(`There is multiple element of class ${className} in ${toStr(parent)}!`);\n\t}\n\tconst el = els[0];\n\tif (!(el instanceof HTMLElement)) {\n\t\tthrow new Error(`The element of class ${className} in ${toStr(parent)} is not an HTMLElement as expected!`);\n\t}\n\treturn el;\n}\n\nexport function getChildElementByClassOpt(parent: HTMLElement, className: string): HTMLElement | null {\n\tconst els = parent.getElementsByClassName(className);\n\tif (els.length === 0 || !(els[0] instanceof HTMLElement)) {\n\t\treturn null;\n\t} else {\n\t\treturn els[0];\n\t}\n}\n\nexport function getChildElementsByClass(parent: HTMLElement, className: string): HTMLCollectionOf {\n\tconst els = parent.getElementsByClassName(className);\n\tfor (const el of els) {\n\t\tif (!(el instanceof HTMLElement)) {\n\t\t\tthrow new Error(`The element of class ${className} in ${toStr(parent)} is not an HTMLElement as expected!`);\n\t\t}\n\t}\n\treturn els as HTMLCollectionOf;\n}\n\nexport function getChildElementArrayByClass(parent: HTMLElement, className: string): HTMLElement[] {\n\treturn [...getChildElementsByClass(parent, className)];\n}\n\nexport function getChildElementByTag(parent: HTMLElement, tagName: K): HTMLElementTagNameMap[K] {\n\tconst els = parent.getElementsByTagName(tagName);\n\tif (els.length === 0) {\n\t\tthrow new Error(`There is no element of tag ${tagName} in ${toStr(parent)}!`);\n\t} else if (els.length > 1) {\n\t\tthrow new Error(`There is multiple element with ${tagName} in ${toStr(parent)}!`);\n\t}\n\tconst el = els[0];\n\tif (!(el instanceof HTMLElement)) {\n\t\tthrow new Error(`The element of tag ${tagName} in ${toStr(parent)} is not an HTMLElement as expected!`);\n\t}\n\treturn el;\n}\n\nexport function getChildElementByTagOpt(parent: HTMLElement, tagName: K): HTMLElementTagNameMap[K] | null {\n\tconst els = parent.getElementsByTagName(tagName);\n\tif (els.length === 0 || !(els[0] instanceof HTMLElement)) {\n\t\treturn null;\n\t} else {\n\t\treturn els[0];\n\t}\n}\n\nexport function getChildElementsByTag(parent: HTMLElement, tagName: K): HTMLCollectionOf {\n\tconst els = parent.getElementsByTagName(tagName);\n\tfor (const el of els) {\n\t\tif (!(el instanceof HTMLElement)) {\n\t\t\tthrow new Error(`The element of ${tagName} in ${toStr(parent)} is not an HTMLElement as expected!`);\n\t\t}\n\t}\n\treturn els;\n}\n\nexport function getRecursiveChildElementsOfClass(parent: HTMLElement, className: string): HTMLElement[] {\n\tconst elements: HTMLElement[] = [];\n\tfor (const element of parent.children) {\n\t\tconst htmlElement = dynamicCast(HTMLElement, element);\n\t\tif (htmlElement) {\n\t\t\tif (htmlElement.classList.contains(className)) {\n\t\t\t\telements.push(htmlElement);\n\t\t\t}\n\t\t\telements.push(...getRecursiveChildElementsOfClass(htmlElement, className));\n\t\t}\n\t}\n\treturn elements;\n}\n\nexport function getCSSKeyframes(name: string): CSSKeyframesRule | null {\n\tfor (const ss of document.styleSheets) {\n\t\tconst css = dynamicCast(CSSStyleSheet, ss);\n\t\tif (css === null) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const rule of css.cssRules) {\n\t\t\tconst keyframesRule = dynamicCast(CSSKeyframesRule, rule);\n\t\t\tif (keyframesRule !== null && keyframesRule.name === name) {\n\t\t\t\treturn keyframesRule;\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function isElementVisible(element: HTMLElement) {\n\treturn !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);\n}\n\n/// Change the visibility of one or more elements using the display CSS property\nexport function setVisibility(element: HTMLElement | SVGElement | null | undefined | (HTMLElement | SVGElement)[], visible: boolean) {\n\tif (element instanceof Array) {\n\t\tfor (const el of element) {\n\t\t\tsetVisibility(el, visible);\n\t\t}\n\t} else if (element) {\n\t\telement.style.display = visible ? '' : 'none';\n\t}\n}\n\nexport function removeURLParameter(param: string) {\n\tconst url = new URL(window.location.href);\n\turl.searchParams.delete(param);\n\twindow.history.replaceState({}, document.title, url.toString());\n}\n\nexport function onLoad(handler: () => void) {\n\tconst wol = window.onload;\n\t//TODO Find out why window.addEventListener('onload', ..) doesn't work.\n\twindow.onload = (event: Event) => {\n\t\tif (wol) wol.call(window, event);\n\t\thandler();\n\t};\n}\n\nexport function resizeCanvas(canvas: HTMLCanvasElement, size: Vector2 | null = null, scale2DContextHiDPI = true) {\n\t// Setup DPI\n\t// from: https://www.html5rocks.com/en/tutorials/canvas/hidpi/\n\t// Get the device pixel ratio, falling back to 1.\n\tconst dpr = window.devicePixelRatio || 1;\n\n\t// Give the canvas pixel dimensions of their CSS\n\t// size * the device pixel ratio.\n\t// Note: we do not know the behaviour of canvas with non-integer dpr\n\t// but as it is very uncommon currently we are ignoring that for now\n\tif (size) {\n\t\t// Use provided size in CSS pixels.\n\t\tconst factor = scale2DContextHiDPI ? dpr : 1.0;\n\t\tcanvas.width = size.x * factor;\n\t\tcanvas.height = size.y * factor;\n\t} else {\n\t\t// Get the size of the canvas from the DOM in CSS pixels.\n\t\tconst rect = canvas.getBoundingClientRect();\n\t\tlet width = rect.width;\n\t\tlet height = rect.height;\n\t\t// If the canvas has border-box as box-sizing, we need to deduce padding and borders\n\t\tconst canvasStyle = getComputedStyle(canvas);\n\t\tif (canvasStyle.boxSizing === 'border-box') {\n\t\t\twidth -= parseFloat(canvasStyle.paddingLeft);\n\t\t\twidth -= parseFloat(canvasStyle.paddingRight);\n\t\t\twidth -= parseFloat(canvasStyle.borderLeftWidth);\n\t\t\twidth -= parseFloat(canvasStyle.borderRightWidth);\n\t\t\theight -= parseFloat(canvasStyle.paddingTop);\n\t\t\theight -= parseFloat(canvasStyle.paddingBottom);\n\t\t\theight -= parseFloat(canvasStyle.borderTopWidth);\n\t\t\theight -= parseFloat(canvasStyle.borderBottomWidth);\n\t\t}\n\t\tcanvas.width = width * dpr;\n\t\tcanvas.height = height * dpr;\n\t}\n\tif (scale2DContextHiDPI) {\n\t\t// Scale all drawing operations by the dpr, so you\n\t\t// don't have to worry about the difference.\n\t\tconst ctx = nonnull(canvas.getContext('2d'));\n\t\tctx.scale(dpr, dpr);\n\t}\n}\n\n/** Works around wrong vh on mobile */\nexport function setupViewportHVariableTrick() {\n\t// from https://css-tricks.com/the-trick-to-viewport-units-on-mobile/\n\tconst updateVH = () => {\n\t\tconst vh = window.innerHeight * 0.01;\n\t\tdocument.documentElement.style.setProperty('--vh', `${vh}px`);\n\t};\n\twindow.addEventListener('resize', updateVH);\n\tupdateVH();\n}\n\nexport function fixSelectIconCallback(select: MDCSelect) {\n\t// Find icon element in currently selected menu item\n\t// eslint-disable-next-line no-underscore-dangle\n\tconst selectedOption = (select as any).menu_.getOptionByIndex(select.selectedIndex);\n\t// eslint-disable-next-line no-underscore-dangle\n\tconst root = select.root_;\n\tconst textLeadingIcon = dynamicCast(HTMLElement, root.querySelector('i.mdc-select__icon'));\n\tconst imgLeadingIcon = dynamicCast(HTMLImageElement, root.querySelector('img.mdc-select__icon'));\n\tconst textIconElement = selectedOption.querySelector('.material-icons') ?? selectedOption.querySelector('.select-icon');\n\tif (textIconElement) {\n\t\tconst icon = textIconElement.innerText.trim();\n\t\t// Replace icon (using the select variant from https://github.com/material-components/material-components-web/tree/master/packages/mdc-select/icon)\n\t\tselect.leadingIconContent = icon;\n\t\t// Replace icon name in selected text element\n\t\t// eslint-disable-next-line no-underscore-dangle\n\t\t(select as any).selectedText_.innerText = (select as any).selectedText_.innerText.replace(\n\t\t\ticon,\n\t\t\t''\n\t\t).trim();\n\t\t// show text and hide image, if any\n\t\tconst leadingIcon = nonnull(textLeadingIcon);\n\t\tleadingIcon.style.display = '';\n\t\tif (imgLeadingIcon) {\n\t\t\timgLeadingIcon.style.display = 'none';\n\t\t}\n\t} else {\n\t\tconst leadingIcon = nonnull(imgLeadingIcon);\n\t\tconst imgIconElement = dynamicCast(HTMLImageElement, selectedOption.querySelector('img'));\n\t\tif (imgIconElement) {\n\t\t\t// Replace the src of the leading icon\n\t\t\tleadingIcon.src = imgIconElement.src;\n\t\t}\n\t\tconst canvasIconElement = dynamicCast(HTMLCanvasElement, selectedOption.querySelector('canvas'));\n\t\tif (canvasIconElement) {\n\t\t\t// Replace the src of the leading icon\n\t\t\tleadingIcon.src = canvasIconElement.toDataURL('image/png');\n\t\t}\n\t\t// show image and hide text, if any\n\t\tleadingIcon.style.display = '';\n\t\tif (textLeadingIcon) {\n\t\t\ttextLeadingIcon.style.display = 'none';\n\t\t}\n\t}\n}\n\nexport function fixSelectIcon(select: MDCSelect) {\n\tconst cb = () => fixSelectIconCallback(select);\n\tselect.listen('MDCSelect:change', cb);\n\tcb();\n}\n\nexport function isFullScreenSupported(acceptSafari = false) {\n\tif (Parameters.isUnderTest || Features.disableFullscreen) {\n\t\treturn false;\n\t}\n\tconst bowserParser = Bowser.getParser(window.navigator.userAgent);\n\tconst notSafari = bowserParser.getBrowserName() !== 'Safari';\n\tconst documentAsAny = document as any;\n\tconst supported = (acceptSafari || notSafari) && (document.fullscreenEnabled || !!documentAsAny.webkitFullscreenEnabled);\n\treturn supported;\n}\n\nexport function isFullScreen() {\n\tconst fullScreenElement = document.fullscreenElement ?? (document as any).webkitFullscreenElement;\n\treturn fullScreenElement !== undefined && fullScreenElement !== null;\n}\n\nexport function toggleFullScreen(on?: boolean, acceptSafari = false): Promise {\n\tconst onRequested = on !== undefined && on;\n\tconst offRequested = on !== undefined && !on;\n\tconst current = isFullScreen();\n\treportLog('toggleFullScreen', { on, acceptSafari, current });\n\tif (onRequested && current) {\n\t\treturn Promise.resolve();\n\t}\n\tif (offRequested && !current) {\n\t\treturn Promise.resolve();\n\t}\n\tif (!isFullScreenSupported(acceptSafari)) {\n\t\t// Do not attempt to initiate fullscreen on non-supported platforms.\n\t\treturn Promise.resolve();\n\t}\n\tif (onRequested || !current) {\n\t\tconst element = document.documentElement;\n\t\tconst elementAsAny = element as any;\n\t\tif (element.requestFullscreen) {\n\t\t\treturn element.requestFullscreen();\n\t\t} else if (elementAsAny.webkitRequestFullscreen) {\n\t\t\t// Note: Safari iOS shows an ugly closing cross:\n\t\t\t// https://stackoverflow.com/questions/58294749/is-there-a-way-to-hide-the-close-button-in-ios-safari-full-screen-mode\n\t\t\telementAsAny.webkitRequestFullscreen();\n\t\t}\n\t} else {\n\t\tconst documentAsAny = document as any;\n\t\tif (document.exitFullscreen) {\n\t\t\treturn document.exitFullscreen();\n\t\t} else if (documentAsAny.webkitCancelFullScreen) {\n\t\t\tdocumentAsAny.webkitCancelFullScreen();\n\t\t}\n\t}\n\treturn Promise.resolve();\n}\n\nexport function htmlToElement(html: string) {\n\tconst template = document.createElement('template');\n\thtml = html.trim(); // Never return a text node of whitespace as the result\n\ttemplate.innerHTML = html;\n\treturn nonnull(template.content.firstChild);\n}\n","/**\n * @module utils\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { snackbar } from 'mdcext/snackbar/snackbar';\nimport { qsT } from 'translator/translator';\n\nfunction shareUrl(subject: string, body: string, targetUrl: string) {\n\tconst mailToContent =\n\t\t'mailto:' +\n\t\t'?subject=' + encodeURIComponent(subject) +\n\t\t'&body=' + encodeURIComponent(body)\n\t\t;\n\tconst win = window.open(mailToContent, '_blank');\n\tsetTimeout(() => {\n\t\tif (win !== null && win.location.href === 'about:blank') {\n\t\t\ttry {\n\t\t\t\twin.close();\n\t\t\t} catch (Error) {\n\t\t\t\t// ignore errors\n\t\t\t}\n\t\t}\n\t}, 500);\n}\n\nexport interface ShareDataEmail extends ShareData {\n\ttitle: string;\n\ttext?: string;\n\turl: string;\n\tfiles?: File[];\n\temailBody: string;\n};\n\ninterface Navigator {\n\tshare?: (data? : ShareData) => Promise;\n\tcanShare?: (data?: ShareData) => boolean;\n}\n\nexport function navigatorCanShare(toShare: ShareData) {\n\tconst navigatorWithShare = navigator as Navigator;\n\treturn navigatorWithShare.canShare && navigatorWithShare.canShare(toShare);\n}\n\nexport function copyToClipboard(targetUrl: string) {\n\tif (navigator.clipboard !== undefined) {\n\t\tvoid navigator.clipboard.writeText(targetUrl);\n\t\tsnackbar.show(qsT('Link copied to your clipboard'));\n\t}\n}\n\nexport function emailShare(toShare: ShareDataEmail) {\n\tshareUrl(toShare.title, toShare.emailBody, toShare.url);\n}\n\nexport async function navigatorShare(toShare: ShareDataEmail) {\n\tconst navigatorWithShare = navigator as Navigator;\n\tconst canShare = navigatorWithShare.canShare && navigatorWithShare.canShare(toShare);\n\tif (!(canShare && navigatorWithShare.share)) {\n\t\treturn;\n\t}\n\ttry {\n\t\tawait navigatorWithShare.share(toShare);\n\t} catch (err) {\n\t\tif (err instanceof Error && err.name === 'AbortError') {\n\t\t\tconsole.debug('User aborted share');\n\t\t} else {\n\t\t\tconsole.debug('Error calling navigator.share: ' + String(err));\n\t\t}\n\t}\n}\n\nexport function getLocation() {\n\tconst page = window.location.href.split('?')[0]!;\n\treturn page.split('/').slice(0, -1).join('/');\n}\n\nexport function calcAbsUrl(local: string) {\n\treturn getLocation() + '/' + local;\n}\n\n","/**\n * @module vpl\n */\n/** comment to work-around limitation of typedoc module plugin */\n\n// Copyright 2018-2024 Enlightware GmbH, Switzerland\n\nimport { Color } from 'color/color';\n\n/* eslint-disable no-underscore-dangle */\n\nexport class ColorTheme {\n\t// uninitialised by default, will be by [setLightTheme] below.\n\tprivate static _background = '';\n\tprivate static _backgroundColor = new Color('#000000');\n\tprivate static _surface = '';\n\tprivate static _surfaceColor = new Color('#000000');\n\t// dual primary because of conditions and actions\n\tprivate static _conditionBackground = '';\n\tprivate static _conditionColor = new Color('#000000');\n\tprivate static _actionBackground = '';\n\tprivate static _actionColor = new Color('#000000');\n\tprivate static _genericBlockBackground = '';\n\tprivate static _genericBlockColor = new Color('#000000');\n\tprivate static _secondary = '';\n\tprivate static _secondaryColor = new Color('#000000');\n\tprivate static _error = '';\n\tprivate static _errorColor = new Color('#000000');\n\tprivate static _warning = '';\n\tprivate static _warningColor = new Color('#000000');\n\tstatic readonly textColor = new Color('#000000');\n\n\tpublic static get background(): string {\n\t\treturn ColorTheme._background;\n\t}\n\tpublic static set background(color: string) {\n\t\tColorTheme._background = color;\n\t\tdocument.documentElement.style.setProperty('--mdc-theme-background', color);\n\t\tthis._backgroundColor = new Color(color);\n\t}\n\tpublic static get backgroundColor() {\n\t\treturn ColorTheme._backgroundColor;\n\t}\n\n\tpublic static get surface(): string {\n\t\treturn ColorTheme._surface;\n\t}\n\tpublic static set surface(color: string) {\n\t\tColorTheme._surface = color;\n\t\tdocument.documentElement.style.setProperty('--mdc-theme-surface', color);\n\t\tthis._surfaceColor = new Color(color);\n\t}\n\tpublic static get surfaceColor() {\n\t\treturn ColorTheme._surfaceColor;\n\t}\n\n\tpublic static get condition(): string {\n\t\treturn ColorTheme._conditionBackground;\n\t}\n\tpublic static set condition(color: string) {\n\t\tColorTheme._conditionBackground = color;\n\t\tthis.setColorAndShades('--event-color', color);\n\t\tthis._conditionColor = new Color(color);\n\t}\n\tpublic static get conditionColor() {\n\t\treturn ColorTheme._conditionColor;\n\t}\n\n\tpublic static get action(): string {\n\t\treturn ColorTheme._actionBackground;\n\t}\n\tpublic static set action(color: string) {\n\t\tColorTheme._actionBackground = color;\n\t\tthis.setColorAndShades('--action-color', color);\n\t\tthis._actionColor = new Color(color);\n\t}\n\tpublic static get actionColor() {\n\t\treturn ColorTheme._actionColor;\n\t}\n\n\tpublic static get genericBlock(): string {\n\t\treturn ColorTheme._genericBlockBackground;\n\t}\n\tpublic static set genericBlock(color: string) {\n\t\tColorTheme._genericBlockBackground = color;\n\t\tthis.setColorAndShades('--generic-block-color', color);\n\t\tthis._genericBlockColor = new Color(color);\n\t}\n\tpublic static get genericBlockColor() {\n\t\treturn ColorTheme._genericBlockColor;\n\t}\n\n\tpublic static get secondary(): string {\n\t\treturn ColorTheme._secondary;\n\t}\n\tpublic static set secondary(color: string) {\n\t\tColorTheme._secondary = color;\n\t\tthis.setColorAndShades('--mdc-theme-secondary', color);\n\t\tthis._secondaryColor = new Color(color);\n\t}\n\tpublic static get secondaryColor() {\n\t\treturn ColorTheme._secondaryColor;\n\t}\n\n\tpublic static get error(): string {\n\t\treturn ColorTheme._error;\n\t}\n\tpublic static set error(color: string) {\n\t\tColorTheme._error = color;\n\t\tdocument.documentElement.style.setProperty('--error-color', color);\n\t\tthis._errorColor = new Color(color);\n\t}\n\tpublic static get errorColor() {\n\t\treturn ColorTheme._errorColor;\n\t}\n\n\tpublic static get warning(): string {\n\t\treturn ColorTheme._warning;\n\t}\n\tpublic static set warning(color: string) {\n\t\tColorTheme._warning = color;\n\t\tdocument.documentElement.style.setProperty('--warning-color', color);\n\t\tthis._warningColor = new Color(color);\n\t}\n\tpublic static get warningColor() {\n\t\treturn ColorTheme._warningColor;\n\t}\n\n\tprivate static setColorAndShades(name: string, baseColor: string) {\n\t\tconst style = document.documentElement.style;\n\t\tstyle.setProperty(name, baseColor);\n\t\tconst lightColor = new Color(baseColor);\n\t\tlightColor.lighten();\n\t\tstyle.setProperty(`${name}__light`, lightColor.rgbHexString);\n\t\tconst darkColor = new Color(baseColor);\n\t\tdarkColor.darken();\n\t\tstyle.setProperty(`${name}__dark`, darkColor.rgbHexString);\n\t\tconst sliderRailColor = new Color(baseColor);\n\t\tsliderRailColor.alpha = 0.26;\n\t\tstyle.setProperty(`${name}__sliderRail`, sliderRailColor.rgbHexString);\n\t}\n}\n\nexport function setLightTheme() {\n\tColorTheme.background = '#ececec';\n\tColorTheme.surface = '#ffffff';\n\tColorTheme.condition = '#1c93d1';\n\tColorTheme.action = '#f38420';\n\tColorTheme.genericBlock = '#00bb8c';\n\tColorTheme.secondary = '#00ca1f';\n\tColorTheme.error = '#ff005d';\n\tColorTheme.warning = '#ffcd03';\n}\n"],"names":["Counters","getGamePlayedCounter","storage","gameId","getCounter","appName","assumeMousePresent","mouseEvents","mouseEvent","document","documentElement","addEventListener","WelcomeScreen","loadingText","HTMLElement","getElementById","constructor","super","barePlayIntro","element","style","display","scrollToBottomWhenImageLoaded","this","miniatureElement","onload","scrollTo","scrollHeight","offsetHeight","setLoaded","innerHTML","onclick","window","open","clickEvent","updateGameDescription","game","text","toPlayText","mouseInput","hasAnyBlockOfType","inputMethods","screen","width","height","push","length","join","separatorText","async","initAsync","loadingScreen","requestedGameId","fontPromise","console","debug","miniatureURI","miniatureReadURI","setMiniature","inc","runtime","replaceWith","e","apiError","url","includes","method","statusCode","ErrorScreen","location","reload","bind","setError","errorText","innerText","setIntro","introText","disableReloadButton","errorScreen","showError","visible","showCustomError","disableReload","report","notifyErrorToUser","ctx","f","args","toString","hasTouch","touchInputSeen","hasMouse","hasMouseInput","mouseInputSeen","LoadingScreen","HTMLImageElement","src","titleElement","labelElement","actionsElement","buttonElements","dialog","cb","_","listen","event","parseInt","detail","action","inputElement","key","keyCode","validity","valid","close","alwaysValid","isValid","buttonEnabled","customValidator","validateInput","value","forEach","button","index","disabled","setCustomValidity","setupBox","title","buttons","defaultButton","Array","defaultText","appendChild","HTMLButtonElement","children","inputBox","initialValue","validator","type","Promise","resolve","OkText","messageBox","fatalBox","content","input","warn","shareDialogElement","ShareDialog","which","stopPropagation","share","toShare","visibility","context","qr","addData","make","createImgTag","callBack","nonnullCallBack","unlisten","name","shareDialog","getDialog","myCandliGame","MyCandliGame","aCoolCandliGame","ACoolCandliGame","shareGameToPlay","self","shareLink","candliReference","emailBody","Snackbar","textButton","root","show","textButtonData","labelText","snackbar","sessionExtraHeaders","baseUrl","storageLocation","href","replace","reportOnlineStatus","getHttpBaseUrl","getApiBaseUrl","retryFetchIfForbidden","fn","retryUrl","error","FetchWithRetryError","Error","lastError","totalTriedTimeSec","fetch","fetchContent","extraHeaders","contentType","body","undefined","Text","fc","Object","prototype","hasOwnProperty","call","Json","JSON","stringify","headers","assign","options","cache","credentials","referrer","data","retry","sleepDuration","trialStartTime","Date","now","log","message","ok","status","fetchJson","json","fetchString","fetchOptionalString","response","fetchBinary","arrayBuffer","get","userGameFeedback","gameKey","what","ScriptPackageLocator","owner","packageName","version","packageType","parseDependencyPath","path","parts","split","versionedPackage","versionedPackageName","dependencyPath","locatorPath","getRustliSfp","packageLocator","code","TextDecoder","decode","LocalStorageAttributePrefix","getAttributeRustServerOrLocal","userInfo","attributes","localStorage","getItem","setAttributeRustServerOrLocal","set","setItem","migrateAttributesToServer","len","keys","i","indexStart","startsWith","substring","removeItem","postGameEvent","eventData","result","reportFns","getCompetency","setCompetency","getPilaReportFunctions","RuntimeScreenWithUI","moreMenu","fullScreenEntry","isCurrentFullscreen","node","childNodes","nodeType","textContent","trim","id","moreButton","hideRuntimeMore","pause","unpause","textReport","getGameId","then","Quoting","WithNumberSign","SpacedOr","SpacedAnd","Not","Nothing","DoNothing","Never","CopyOf","UndefinedText","Cancel","ScoreText","TheScoreTextNom","TheScoreTextAcc","langIndex","UpTexts","upText","LeftTexts","leftText","RightTexts","rightText","DownTexts","downText","getChildElementByClass","parent","className","els","getElementsByClassName","el","getChildElementByTag","tagName","getElementsByTagName","getChildElementsByTag","resizeCanvas","canvas","size","scale2DContextHiDPI","dpr","devicePixelRatio","factor","x","y","rect","getBoundingClientRect","canvasStyle","getComputedStyle","boxSizing","parseFloat","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","getContext","scale","isFullScreenSupported","acceptSafari","isUnderTest","disableFullscreen","notSafari","navigator","userAgent","getBrowserName","documentAsAny","fullscreenEnabled","webkitFullscreenEnabled","isFullScreen","fullScreenElement","fullscreenElement","webkitFullscreenElement","toggleFullScreen","on","onRequested","offRequested","current","elementAsAny","requestFullscreen","webkitRequestFullscreen","exitFullscreen","webkitCancelFullScreen","htmlToElement","html","template","createElement","firstChild","navigatorCanShare","navigatorWithShare","canShare","copyToClipboard","targetUrl","clipboard","writeText","emailShare","subject","mailToContent","encodeURIComponent","win","setTimeout","shareUrl","navigatorShare","err","String","calcAbsUrl","local","slice","ColorTheme","static","background","_background","color","setProperty","_backgroundColor","backgroundColor","surface","_surface","_surfaceColor","surfaceColor","condition","_conditionBackground","setColorAndShades","_conditionColor","conditionColor","_actionBackground","_actionColor","actionColor","genericBlock","_genericBlockBackground","_genericBlockColor","genericBlockColor","secondary","_secondary","_secondaryColor","secondaryColor","_error","_errorColor","errorColor","warning","_warning","_warningColor","warningColor","baseColor","lightColor","lighten","rgbHexString","darkColor","darken","sliderRailColor","alpha","setLightTheme"],"sourceRoot":""}