{"version":3,"file":"app-ba052bf2.f584a1446b2fc034d810.bundle.js","mappings":"AAGA","sources":["webpack://lernplattform-admin-frontend/../common/aurelia-components/intersection-target/intersection-target.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-break/lecture-break.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-end/lecture-end.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-start/lecture-start.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-status/lecture-status.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-donut-chart/level-donut-chart.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-profile/level-profile-badge/level-profile-badge.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-profile/level-profile-item/level-profile-item.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-profile/level-profile-progress/level-profile-progress.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-profile/level-profile.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/list-standard/list-standard.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/loading-overlay/loading-overlay.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/lottie-animation-player/lottie-animation-player.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/markdown-text/markdown-text.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-fill-in-the-blank-input/mp-fill-in-the-blank-input.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-interactive-text/mp-interactive-text.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-letter-input/mp-letter-input.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-question/mp-question.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-rapid-fire-game/mp-rapid-fire-game-button/mp-rapid-fire-game-button.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-rapid-fire-game/mp-rapid-fire-game.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-hot-spot-drawer/mp-hot-spot-drawer.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-landscape-header/mp-landscape-header.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-tile/mp-tile.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-tiles-preview/mp-tiles-preview.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/multi-donut-chart/multi-donut-chart.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/navigation-slider/navigation-slider.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/password-strength-indicator/password-strength-indicator.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/picture-puzzle/picture-puzzle.html","webpack://lernplattform-admin-frontend/../common/aurelia-components/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/intersection-target/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/intersection-target/intersection-target.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-break/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-break/lecture-break.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-end/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-end/lecture-end.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-start/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-start/lecture-start.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-status/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/lecture-status/lecture-status.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-donut-chart/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-donut-chart/level-donut-chart.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-profile/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-profile/level-profile-badge/level-profile-badge.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-profile/level-profile-item/level-profile-item.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-profile/level-profile-progress/level-profile-progress.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/level-profile/level-profile.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/list-standard/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/list-standard/list-standard.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/loading-overlay/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/loading-overlay/loading-overlay.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/lottie-animation-player/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/lottie-animation-player/lottie-animation-player.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/markdown-text/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/markdown-text/markdown-text.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-fill-in-the-blank-input/mp-fill-in-the-blank-input.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-interactive-text/mp-interactive-text.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-letter-input/mp-letter-input.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-question/mp-question.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-rapid-fire-game/mp-rapid-fire-game-button/mp-rapid-fire-game-button.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/methodpool/mp-rapid-fire-game/mp-rapid-fire-game.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-hot-spot-drawer/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-hot-spot-drawer/mp-hot-spot-drawer.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-landscape-header/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-landscape-header/mp-landscape-header.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-tile/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-tile/mp-tile.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-tiles-preview/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/mp-tiles-preview/mp-tiles-preview.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/multi-donut-chart/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/multi-donut-chart/multi-donut-chart.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/navigation-slider/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/navigation-slider/navigation-slider.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/password-strength-indicator/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/password-strength-indicator/password-strength-indicator.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/picture-puzzle/index.ts","webpack://lernplattform-admin-frontend/../common/aurelia-components/picture-puzzle/picture-puzzle.ts"],"sourcesContent":["// Module\nvar code = \"<template class=\\\"intersection-target\\\"> <slot></slot> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <lecture-status t=\\\"[infoFirstLine]common.lecture-break.lecturePaused\\\" active-lecture.to-view=\\\"activeLecture\\\" tenant-logo-picture-url.to-view=\\\"tenantLogoPictureUrl\\\"></lecture-status> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <lecture-status t=\\\"[infoFirstLine]common.lecture-end.lectureEnded\\\" active-lecture.to-view=\\\"activeLecture\\\" tenant-logo-picture-url.to-view=\\\"tenantLogoPictureUrl\\\"></lecture-status> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <lecture-status t=\\\"[infoFirstLine]${statusInfo.firstLineTk};[infoSecondLine]${statusInfo.secondLineTk}\\\" t-params.to-view=\\\"{ count: minutesToStart }\\\" active-lecture.to-view=\\\"activeLecture\\\" tenant-logo-picture-url.to-view=\\\"tenantLogoPictureUrl\\\"></lecture-status> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"lecture-status\\\"> <div class=\\\"lecture-status__content\\\"> <div class=\\\"lecture-status__title\\\">${activeLecture.title}</div> <div if.to-view=\\\"dateTimeTranslation\\\" class=\\\"lecture-status__subtitle ${activeLecture.lecturer ? 'lecture-status__subtitle--with-lecturer' : ''}\\\" t=\\\"common.lecture-status.${dateTimeTranslation}\\\" t-params.to-view=\\\"dateTimeTranslationParams\\\"></div> <h3 if.to-view=\\\"activeLecture.lecturer\\\" class=\\\"lecture-status__lecturer-name\\\">${lecturerName}</h3> <div class=\\\"lecture-status__institution-logo-wrapper\\\"> <img if.to-view=\\\"tenantLogoPictureUrl\\\" class=\\\"lecture-status__institution-logo\\\" src.to-view=\\\"tenantLogoPictureUrl\\\"> </div> <div class=\\\"lecture-status__info\\\"> <div class=\\\"lecture-status__info-first-line\\\">${infoFirstLine}</div> <div if.to-view=\\\"infoSecondLine\\\" class=\\\"lecture-status__info-first-line\\\">${infoSecondLine}</div> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"level-donut-chart level-donut-chart--${color}\\\"> <svg version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" x=\\\"0px\\\" y=\\\"0px\\\" viewBox=\\\"0 0 ${donutDiameter} ${donutDiameter}\\\" enable-background=\\\"new 0 0 ${donutDiameter} ${donutDiameter}\\\" xml:space=\\\"preserve\\\" class=\\\"level-donut-chart__svg\\\"> <g transform=\\\"translate(${donutOuterRadius}, ${donutOuterRadius})\\\"> <circle r=\\\"${donutInnerRadius}\\\" stroke-dasharray=\\\"${circleFrontStrokeDash}\\\" stroke-dashoffset.to-view=\\\"circleFrontStrokeDashOffset\\\" stroke-width=\\\"${donutStrokeWidth}\\\" class=\\\"level-donut-chart__circle-progress\\\" transform=\\\"rotate(50)\\\"/> </g> </svg> <div class=\\\"level-donut-chart__avatar-wrapper level-donut-chart__avatar-wrapper--${size}\\\"> <slot></slot> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"level-profile-badge level-profile-badge--color-${levelColor}\\\"> <svg class=\\\"level-profile-badge__svg\\\" viewBox=\\\"0 0 92 92\\\" version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"> <title><span t=\\\"common.level-profile.level\\\"></span>${level}</title> <defs> <circle id=\\\"path-1\\\" cx=\\\"36\\\" cy=\\\"36\\\" r=\\\"36\\\"></circle> <filter x=\\\"-21.5%\\\" y=\\\"-20.1%\\\" width=\\\"143.1%\\\" height=\\\"143.1%\\\" filterUnits=\\\"objectBoundingBox\\\" id=\\\"filter-2\\\"> <feMorphology radius=\\\"0.5\\\" operator=\\\"erode\\\" in=\\\"SourceAlpha\\\" result=\\\"shadowSpreadOuter1\\\"></feMorphology> <feOffset dx=\\\"0\\\" dy=\\\"2\\\" in=\\\"shadowSpreadOuter1\\\" result=\\\"shadowOffsetOuter1\\\"></feOffset> <feGaussianBlur stdDeviation=\\\"2\\\" in=\\\"shadowOffsetOuter1\\\" result=\\\"shadowBlurOuter1\\\"></feGaussianBlur> <feColorMatrix values=\\\"0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.07 0\\\" type=\\\"matrix\\\" in=\\\"shadowBlurOuter1\\\" result=\\\"shadowMatrixOuter1\\\"></feColorMatrix> <feOffset dx=\\\"0\\\" dy=\\\"1\\\" in=\\\"SourceAlpha\\\" result=\\\"shadowOffsetOuter2\\\"></feOffset> <feGaussianBlur stdDeviation=\\\"5\\\" in=\\\"shadowOffsetOuter2\\\" result=\\\"shadowBlurOuter2\\\"></feGaussianBlur> <feColorMatrix values=\\\"0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.07 0\\\" type=\\\"matrix\\\" in=\\\"shadowBlurOuter2\\\" result=\\\"shadowMatrixOuter2\\\"></feColorMatrix> <feOffset dx=\\\"0\\\" dy=\\\"1\\\" in=\\\"SourceAlpha\\\" result=\\\"shadowOffsetOuter3\\\"></feOffset> <feGaussianBlur stdDeviation=\\\"2.5\\\" in=\\\"shadowOffsetOuter3\\\" result=\\\"shadowBlurOuter3\\\"></feGaussianBlur> <feColorMatrix values=\\\"0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.07 0\\\" type=\\\"matrix\\\" in=\\\"shadowBlurOuter3\\\" result=\\\"shadowMatrixOuter3\\\"></feColorMatrix> <feMerge> <feMergeNode in=\\\"shadowMatrixOuter1\\\"></feMergeNode> <feMergeNode in=\\\"shadowMatrixOuter2\\\"></feMergeNode> <feMergeNode in=\\\"shadowMatrixOuter3\\\"></feMergeNode> </feMerge> </filter> <text id=\\\"text-3\\\" font-family=\\\"Inter-ExtraBold, Inter\\\" font-size=\\\"44\\\" font-weight=\\\"700\\\" line-spacing=\\\"48\\\" x=\\\"50%\\\" y=\\\"50%\\\" dx=\\\"-10\\\" dy=\\\"-5\\\" style=\\\"text-anchor:middle\\\" dominant-baseline=\\\"middle\\\" fill=\\\"var(--level-profile-badge-text-color)\\\">${level}</text> <filter x=\\\"-1.9%\\\" y=\\\"-1.0%\\\" width=\\\"107.4%\\\" height=\\\"104.2%\\\" filterUnits=\\\"objectBoundingBox\\\" id=\\\"filter-4\\\"> <feOffset dx=\\\"1\\\" dy=\\\"1\\\" in=\\\"SourceAlpha\\\" result=\\\"shadowOffsetOuter1\\\"></feOffset> <feColorMatrix values=\\\"${textShadowColorMatrix}\\\" type=\\\"matrix\\\" in=\\\"shadowOffsetOuter1\\\"></feColorMatrix> </filter> </defs> <g id=\\\"Symbols\\\" stroke=\\\"none\\\" stroke-width=\\\"1\\\" fill=\\\"none\\\" fill-rule=\\\"evenodd\\\"> <g id=\\\"Group\\\" transform=\\\"translate(10.000000, 9.000000)\\\"> <g id=\\\"Oval\\\"> <use fill=\\\"black\\\" fill-opacity=\\\"1\\\" filter=\\\"url(#filter-2)\\\" xlink:href=\\\"#path-1\\\"></use> <use fill=\\\"var(--level-profile-badge-medium-color)\\\" fill-rule=\\\"evenodd\\\" xlink:href=\\\"#path-1\\\"></use> </g> <path d=\\\"M36,64 C51.463973,64 64,51.463973 64,36 C64,20.536027 51.463973,8 36,8 C36,8 36,64 36,64 Z\\\" id=\\\"Oval\\\" fill=\\\"var(--level-profile-badge-dark-color)\\\"></path> <circle id=\\\"Oval\\\" stroke=\\\"var(--level-profile-badge-light-color)\\\" stroke-width=\\\"3\\\" stroke-linecap=\\\"square\\\" cx=\\\"36\\\" cy=\\\"36\\\" r=\\\"28\\\"></circle> <g id=\\\"Level\\\" fill-opacity=\\\"1\\\"> <use xlink:href=\\\"#text-3\\\" filter=\\\"url(#filter-4)\\\"></use> <use xlink:href=\\\"#text-3\\\"></use> </g> </g> </g> </svg> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"level-profile-item\\\" style.to-view=\\\"{ '--level-profile-item-points-color': pointsColor }\\\"> <div class=\\\"level-profile-item__content\\\"> <span class=\\\"level-profile-item__name\\\" t.to-view=\\\"nameTk\\\"></span> <span class=\\\"level-profile-item__earned-points\\\" t=\\\"common.level-profile-item.earnedPoints\\\" t-params.to-view=\\\"{ points }\\\"></span> </div> <div if.to-view=\\\"showLine\\\" class=\\\"level-profile-item__line\\\"></div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"level-profile-progress level-profile-progress--color-${levelColor}\\\"> <div class=\\\"level-profile-progress__text-wrapper\\\"> <span class=\\\"level-profile-progress__level-text\\\" t=\\\"common.level-profile-progress.currentLevelProgress\\\"></span> <span t=\\\"common.level-profile-progress.actualPointsFromMaxPoints\\\" t-params.to-view=\\\"{ actualPoints: points, maxPoints: levelMaxPoints }\\\"></span> </div> <rounded-progress-bar progress.to-view=\\\"levelPercentage\\\" max-progress.to-view=\\\"levelMaxPoints\\\" min-progress.to-view=\\\"levelMinPoints\\\" progress-color.to-view=\\\"levelColor\\\"></rounded-progress-bar> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"level-profile level-profile--color-${levelColor} ${ containerModeOn ? 'level-profile--container-mode-on' : '' }\\\"> <div class=\\\"level-profile__header\\\"> <h1 class=\\\"level-profile__heading\\\" t=\\\"common.level-profile.level\\\"></h1> <div class=\\\"level-profile__coins-info\\\"> <span class=\\\"level-profile__coins-info-coins\\\">${getNumberAsGroupedNumberString(coins)}</span> <x-icon class=\\\"level-profile__coins-info-icon\\\" icon-type=\\\"custom\\\" icon-name=\\\"System/Coin-Stack\\\" size=\\\"unspecified\\\"></x-icon> </div> </div> <div class=\\\"level-profile__badge\\\"> <level-profile-badge level.to-view=\\\"level\\\"></level-profile-badge> <span class=\\\"level-profile__available-levels\\\">/${availableLevels}</span> </div> <level-profile-progress points.to-view=\\\"points\\\"></level-profile-progress> <level-profile-item repeat.for=\\\"item of groupedPointItems\\\" name-tk.to-view=\\\"item.nameTk\\\" points.to-view=\\\"item.points\\\" points-color.to-view=\\\"item.pointsColor\\\" show-line.to-view=\\\"!$last\\\"></level-profile-item> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"list-standard list-standard--theme-${listTheme} ${ item.maxWidth === `content-small` ? 'lp-site-content-small-no-padding' : '' } ${ item.maxWidth === `content` ? 'lp-site-content-no-padding' : '' } ${ columnizeItems ? 'list-standard--columnize-items' : ''} ${ allowGrow ? 'list-standard--allow-grow' : ''}\\\"> <ul class=\\\"list-standard__list mdc-list ${ isTwoLineList ? 'mdc-list--two-line' : '' }\\\" ref=\\\"listElement\\\"> <template repeat.for=\\\"item of items\\\"> <li style.to-view=\\\"{ '--list-standard-highest-enumeration-width': highestEnumerationWidth + 'px' }\\\" elements-contact=\\\"contact-element.to-view: domElement; no-contact.from-view: containerModeOn\\\" click.delegate=\\\"handleClick(item)\\\" class=\\\"mdc-list-item list-standard__item ${ item.multiline ? 'list-standard__item--multi-line' : '' } ${ enumeration ? 'list-standard__item--with-enumeration' : '' } ${ item.maxWidth === `content-small` ? 'lp-site-content-small' : '' } ${ item.maxWidth === `content` ? 'lp-site-content' : '' } ${ containerModeOn ? 'list-standard__item--container-mode-on' : '' } ${ isTwoLineList ? 'list-standard__item--two-line' : '' } ${ isThreeLineList ? 'list-standard__item--three-line' : '' } ${ isFourLineList ? 'list-standard__item--four-line' : '' } ${ item.click == null ? 'list-standard__item--disabled' : '' } ${ item.multilineWrapSpacing ? 'list-standard__item--extra-padding-top' : '' }\\\"> <div if.to-view=\\\"enumeration\\\" class=\\\"list-standard__index\\\">${getEnumerationString(item, $index)}</div> <safe-icon if.to-view=\\\"item.graphic.name && item.graphic.safe\\\" class=\\\"mdc-list-item__graphic list-standard__safe-graphic\\\" icon-name.to-view=\\\"item.graphic.name\\\"></safe-icon> <x-icon if.to-view=\\\"item.graphic.name && !item.graphic.safe\\\" keyup.trigger=\\\"handleIconClick(item.graphic, $event)\\\" class=\\\"mdc-list-item__graphic list-standard__graphic\\\" icon-type.to-view=\\\"item.graphic.type\\\" size.to-view=\\\"item.graphic.size\\\" aria-label.to-view=\\\"item.graphic.ariaLabel\\\" role=\\\"${ item.graphic.isRadio ? 'radio' : '' }\\\" aria-checked.to-view=\\\"item.graphic.checked\\\" tabindex=\\\"${ item.graphic.isRadio ? '0' : '-1' }\\\" icon-name.to-view=\\\"item.graphic.name\\\"></x-icon> <avatar-icon if.to-view=\\\"item.graphic.avatarSvgDownloadLink !== undefined\\\" class=\\\"mdc-list-item__graphic list-standard__graphic list-standard__graphic--avatar ${item.graphic.disabled ? 'list-standard__graphic--disabled' : ''}\\\" fallback-avatar.to-view=\\\"item.graphic.fallbackAvatar\\\" avatar-svg-download-link.to-view=\\\"item.graphic.avatarSvgDownloadLink\\\" points.to-view=\\\"item.graphic.points\\\" online.to-view=\\\"item.graphic.online\\\" level-mode=\\\"primary-color-indicator\\\"></avatar-icon> <donut-chart if.to-view=\\\"item.graphic.value !== undefined\\\" class=\\\"list-standard__graphic\\\" color.to-view=\\\"item.graphic.color ? item.graphic.color : 'primary'\\\" font-scale.to-view=\\\"item.graphic.fontScale ? item.graphic.fontScale : 1\\\" hide-percentage.to-view=\\\"item.graphic.hidePercentage\\\" value.to-view=\\\"item.graphic.value\\\"></donut-chart> <template if.to-view=\\\"lineCount === 1\\\"> <span if.to-view=\\\"item.text.primary.textTk\\\" class=\\\"mdc-list-item__text list-standard__text\\\" t.to-view=\\\"item.text.primary.textTk\\\"> </span> <span if.to-view=\\\"!item.text.primary.textTk\\\" class=\\\"mdc-list-item__text list-standard__text\\\">${item.text.primary}</span> </template> <template if.to-view=\\\"lineCount >= 2\\\"> <div class=\\\"list-standard__text-container\\\"> <div class=\\\"list-standard__text-and-indication-wrapper\\\"> <div class=\\\"list-standard__text-wrapper\\\"> <span if.to-view=\\\"item.text.primary.textTk\\\" class=\\\"list-standard__text list-standard__text--${item.text.primary.textStyle}\\\" t-params.to-view=\\\"item.text.primary.params\\\" t.to-view=\\\"item.text.primary.textTk\\\"></span> <span if.to-view=\\\"!item.text.primary.textTk\\\" class=\\\"list-standard__text\\\">${item.text.primary}</span> <span if.to-view=\\\"item.text.secondary.textTk\\\" class=\\\"list-standard__secondary-text list-standard__secondary-text--${item.text.secondary.textStyle}\\\" t-params.to-view=\\\"item.text.secondary.params\\\" t.to-view=\\\"item.text.secondary.textTk\\\"></span> <span if.to-view=\\\"!item.text.secondary.textTk && isArray(item.text.secondary)\\\" class=\\\"list-standard__secondary-tags\\\"> <span class=\\\"list-standard__tag\\\" repeat.for=\\\"tag of item.text.secondary\\\">${tag}</span> </span> <span if.to-view=\\\"!item.text.secondary.textTk && !isArray(item.text.secondary) && item.text.secondary != null\\\" class=\\\"list-standard__secondary-text\\\" innerhtml.to-view=\\\"item.text.secondary\\\"></span> </div> </div> <div class=\\\"list-standard__text-wrapper ${ item.multilineWrapSpacing ? 'list-standard__text-wrapper--extra-margin-bottom' : '' }\\\"> <span if.to-view=\\\"item.text.tertiary.textTk\\\" class=\\\"list-standard__tertiary-text list-standard__tertiary-text--${item.text.tertiary.textStyle}\\\" t-params.to-view=\\\"item.text.tertiary.params\\\" t.to-view=\\\"item.text.tertiary.textTk\\\"></span> <span if.to-view=\\\"!item.text.tertiary.textTk && !!item.text.tertiary\\\" class=\\\"list-standard__tertiary-text\\\" innerhtml.to-view=\\\"item.text.tertiary\\\"></span> <span if.to-view=\\\"item.text.quaternary.textTk\\\" class=\\\"list-standard__quaternary-text list-standard__quaternary-text--${item.text.quaternary.textStyle}\\\" t-params.to-view=\\\"item.text.quaternary.params\\\" t.to-view=\\\"item.text.quaternary.textTk\\\"></span> <span if.to-view=\\\"!item.text.quaternary.textTk\\\" class=\\\"list-standard__quaternary-text\\\">${item.text.quaternary}</span> </div> </div> </template> <div class=\\\"mdc-list-item__meta list-standard__meta\\\"> <template repeat.for=\\\"icon of item.icons\\\"> <div if.to-view=\\\"icon.textTk || typeof icon === 'string'\\\" class=\\\"list-standard__meta-text\\\" t.to-view=\\\"icon.textTk || icon\\\"></div> <button-standard if.to-view=\\\"icon.text\\\" class=\\\"list-standard__button\\\" t.to-view=\\\"icon.text.textTk ? `[btnText]${icon.text.textTk}` : 'icon.text'\\\" btn-shape=\\\"condensed\\\" disabled.to-view=\\\"icon.disabled\\\"></button-standard> <div if.to-view=\\\"icon.name && (icon.onClick != null || item.click != null)\\\" class=\\\"list-standard__icon list-standard__icon--color-${icon.color} ${ icon.onClick ? 'list-standard__icon--clickable' : '' }\\\" click.delegate=\\\"handleIconClick(icon, $event)\\\"> <div if.to-view=\\\"item.unread\\\" class=\\\"list-standard__unread-indicator\\\"></div> <x-icon icon-type.to-view=\\\"icon.type\\\" size.to-view=\\\"icon.size\\\" use-as-button aria-label.to-view=\\\"icon.ariaLabel\\\" role=\\\"${ icon.ariaLabel ? 'button' : '' }\\\" tabindex=\\\"${ icon.ariaLabel ? '0' : '-1' }\\\" icon-name.to-view=\\\"icon.name\\\"></x-icon> </div> </template> </div> <div if.to-view=\\\"item.separatorAfter\\\" role=\\\"separator\\\" aria-hidden=\\\"true\\\" class=\\\"list-standard__divider ${ item.graphic && listTheme !== 'manager-chat' ? 'list-standard__divider--with-graphic' : '' } ${ item.graphic.size === 'normal' ? 'list-standard__divider--with-small-graphic' : '' }\\\"></div> </li> </template> </ul> <div if.to-view=\\\"listEmptyTk && !items.length\\\" class=\\\"list-standard__empty-list lp-site-content-small\\\"> <p class=\\\"list-standard__empty-list-text\\\" t.to-view=\\\"listEmptyTk\\\"></p> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"loading-overlay loading-overlay--context-${context} ${ visible ? 'loading-overlay--visible' : '' }\\\" style.to-view=\\\"{ '--circle-position-y': circlePositionY }\\\"> <x-spinner class=\\\"loading-overlay__spinner\\\"></x-spinner> <div class=\\\"loading-overlay__status\\\"> <div repeat.for=\\\"message of statusMessages\\\" class=\\\"loading-overlay__status-message loading-overlay__status-message--${message.type}\\\" t.to-view=\\\"message.textTk\\\" t-params.to-view=\\\"message.textTkParams\\\"></div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div ref=\\\"animationContainer\\\" class=\\\"lottie-animation-player__animation-container\\\"> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-fill-in-the-blank-input ${ focused ? 'mp-fill-in-the-blank-input--active' : '' } ${ correct ? 'mp-fill-in-the-blank-input--correct' : '' }\\\" use-as-button click.delegate=\\\"focus()\\\"> <div ref=\\\"answerElement\\\">${selected.text || '&nbsp;'}</div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-interactive-text ${ landscapeMode ? 'mp-interactive-text--landscape' : '' }\\\"> <div class=\\\"mp-interactive-text__content\\\"> <mp-landscape-header show.to-view=\\\"landscapeMode\\\" title-tk=\\\"common.mp-interactive-text.landscapeTitle\\\"> <slot name=\\\"leftHeaderElement\\\" slot=\\\"leftHeaderElement\\\"></slot> </mp-landscape-header> <compose if.to-view=\\\"markdownViewStrategy\\\" view.to-view=\\\"markdownViewStrategy\\\" class=\\\"mp-interactive-text__markdown lp-site-content-small\\\" mp-interactive-text-input-attached.delegate=\\\"handleMpGapAttachedEvent($event)\\\" mp-interactive-text-input-focused.delegate=\\\"handleMpGapFocusedEvent($event)\\\" mp-interactive-text-input-answered.delegate=\\\"handleMpGapAnsweredEvent($event)\\\" attached.delegate=\\\"handleMarkerAttached($event)\\\"></compose> <rich-text else text.to-view=\\\"markdown\\\" mode.to-view=\\\"textMode\\\" class=\\\"mp-interactive-text__markdown lp-site-content-small\\\" mp-interactive-text-input-attached.delegate=\\\"handleMpGapAttachedEvent($event)\\\" mp-interactive-text-input-focused.delegate=\\\"handleMpGapFocusedEvent($event)\\\" mp-interactive-text-input-answered.delegate=\\\"handleMpGapAnsweredEvent($event)\\\" attached.delegate=\\\"handleMarkerAttached($event)\\\"></rich-text> <div show.to-view=\\\"!completed\\\" class=\\\"mp-interactive-text__options-container\\\"> <div class=\\\"lp-site-content-small mp-interactive-text__option-button-wrapper ${ activeGap.isMultiStep() ? 'mp-interactive-text__option-button-wrapper--letters' : '' }\\\"> <button repeat.for=\\\"answer of currentAnswers\\\" class=\\\"mp-interactive-text__option-button\\\" disabled.to-view=\\\"locked || answer.disabled\\\" click.delegate=\\\"handleAnswerSelected(answer,$event)\\\">${answer.text}</button> <button if.to-view=\\\"activeGap.isMultiStep()\\\" class=\\\"mp-interactive-text__option-button mp-interactive-text__option-button--delete\\\" disabled.to-view=\\\"locked\\\" click.delegate=\\\"clearLast()\\\"> <div t=\\\"common.mp-interactive-text.clear\\\" class=\\\"mp-interactive-text__option-button-text\\\"></div> <x-icon icon-type=\\\"fal\\\" icon-name=\\\"backspace\\\" size=\\\"unspecified\\\" class=\\\"mp-interactive-text__option-button-icon\\\"></x-icon> </button> </div> </div> </div> <course-block-mp-sequence-sidebar if.to-view=\\\"!isDesktopVersion\\\" button-clicked.trigger=\\\"handleAnswerButtonClick()\\\" disabled.to-view=\\\"!isAnswerSelected\\\"></course-block-mp-sequence-sidebar> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-letter-input ${ focused ? 'mp-letter-input--active' : '' }\\\" use-as-button click.delegate=\\\"focus()\\\"> <div repeat.for=\\\"letter of letters\\\" class=\\\"mp-letter-input__letter ${ $index === userText.length && focused ? 'mp-letter-input__letter--active' : ''} ${ correct || $index < userText.length && focused ? 'mp-letter-input__letter--done' : ''}\\\"> <div ref=\\\"letter.el\\\">${userText[$index] || '&nbsp;'}</div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-question ${ landscapeMode ? 'mp-question--landscape' : '' }\\\"> <course-question class=\\\"mp-question__question\\\" theme=\\\"landscape\\\" responsiveness=\\\"desktop\\\" question.to-view=\\\"question\\\" voice-over-enabled.to-view=\\\"true\\\" help-text-enabled.to-view=\\\"true\\\" selected-answers.to-view=\\\"selectedAnswers\\\" selected-answers-changed.trigger=\\\"handleSelectedAnswersChanged($event)\\\" fixed-dropdown-menu.to-view=\\\"true\\\"> <slot name=\\\"leftHeaderElement\\\" slot=\\\"leftHeaderElement\\\"></slot> </course-question> <course-block-mp-sequence-sidebar if.to-view=\\\"!isDesktopVersion\\\" button-clicked.trigger=\\\"handleAnswerButtonClick()\\\" disabled.to-view=\\\"!isAnswerSelected\\\"></course-block-mp-sequence-sidebar> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-rapid-fire-game-button ${landscapeMode ? 'mp-rapid-fire-game-button--landscape' : ''}\\\"> <button class=\\\"mdc-button mdc-button--touch mdc-button--no-focus mdc-button mdc-button--unelevated mp-rapid-fire-game-button__button\\\" ref=\\\"domButtonElement\\\" disabled.to-view=\\\"disabled\\\"> <div class=\\\"mdc-button__ripple\\\"></div> <span class=\\\"mp-rapid-fire-game-button__label mdc-button__label\\\">${category}</span> </button> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-rapid-fire-game\\\"> <div if.to-view=\\\"state === MpRapidFireGameState.STARTING\\\" class=\\\"mp-rapid-fire-game__status-container\\\"> <lottie-animation-player class=\\\"mp-rapid-fire-game__start-counter\\\" view-model.ref=\\\"countdownAnimationPlayer\\\" animation-data.to-view=\\\"countdownAnimation\\\" autoplay-delay.to-view=\\\"1000\\\" lottie-loop-complete.trigger=\\\"start()\\\"></lottie-animation-player> </div> <div if.to-view=\\\"!navPreview\\\" show.to-view=\\\"state === MpRapidFireGameState.RUNNING\\\" class=\\\"mp-rapid-fire-game__main\\\"> <div class=\\\"mp-rapid-fire-game__counter\\\">${secondsLeft}s</div> <div repeat.for=\\\"gameEntry of loadedEntries\\\" show.to-view=\\\"gameEntry === currentGameEntry\\\" class=\\\"mp-rapid-fire-game__question-container lp-site-content-small\\\"> <x-picture picture.to-view=\\\"gameEntry.picture\\\" class=\\\"mp-rapid-fire-game__question-container-picture\\\"></x-picture> </div> <div class=\\\"mp-rapid-fire-game__answer-container lp-site-content-small\\\"> <mp-rapid-fire-game-button repeat.for=\\\"category of categories\\\" view-model.ref=\\\"buttonViewModels[$index]\\\" class=\\\"mp-rapid-fire-game__answer\\\" click.delegate=\\\"handleCategoryClick(category, $index)\\\" category.to-view=\\\"category\\\" disabled.to-view=\\\"disableAnswers\\\" landscape-mode.to-view=\\\"landscapeMode\\\"></mp-rapid-fire-game-button> </div> </div> <div show.to-view=\\\"state === MpRapidFireGameState.FINISHED\\\" class=\\\"mp-rapid-fire-game__status-container\\\"> <div class=\\\"mp-rapid-fire-game__restart\\\"> <div class=\\\"mp-rapid-fire-game__timeout-message\\\" t.to-view=\\\"finishedTranslation\\\"></div> <button-standard btn-type.to-view=\\\"`outlined`\\\" class=\\\"mp-rapid-fire-game__restart-btn\\\" click.trigger=\\\"handleRestartClick()\\\" icon-type=\\\"custom\\\" icon-name=\\\"System/Refresh\\\" t=\\\"[btnText]${processTranslation('restart')}\\\"></button-standard> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-hot-spot-drawer\\\"> <button-standard if.to-view=\\\"!selectedHotSpot\\\" class=\\\"lp-site-content-small mp-hot-spot-drawer__details-btn\\\" btn-fill-mode=\\\"fill-width\\\" t=\\\"[btnText]common.course-block-mp-hot-spot.viewDetails\\\" click.trigger=\\\"handleShowDetailsClicked()\\\"></button-standard> <div if.to-view=\\\"selectedHotSpot\\\" class=\\\"mp-hot-spot-drawer__controls lp-site-content-small\\\"> <button-smaller t=\\\"[btnText]common.course-block-mp-hot-spot.close\\\" btn-style=\\\"inverted\\\" click.trigger=\\\"handleCloseClick()\\\"></button-smaller> <p class=\\\"mp-hot-spot-drawer__controls-display\\\" aria-live=\\\"polite\\\">${paginationDisplay.current}/${paginationDisplay.total}</p> <button-smaller btn-type=\\\"icon\\\" btn-style=\\\"inverted\\\" t=\\\"[aria-label]common.course-block-mp-hot-spot.previous\\\" disabled.to-view=\\\"paginationDisplay.current === 1\\\" icon-type=\\\"custom\\\" icon-name=\\\"System/Arrow - Type2 - Left\\\" click.trigger=\\\"handlePreviousClick()\\\"></button-smaller> <button-smaller btn-type=\\\"icon\\\" btn-style=\\\"inverted\\\" t=\\\"[aria-label]common.course-block-mp-hot-spot.next\\\" disabled.to-view=\\\"paginationDisplay.current >= paginationDisplay.total\\\" icon-type=\\\"custom\\\" icon-name=\\\"System/Arrow - Type2 - Right\\\" click.trigger=\\\"handleNextClick()\\\"> </button-smaller> </div> <div if.to-view=\\\"selectedHotSpot\\\" class=\\\"mp-hot-spot-drawer__scrollbox\\\"> <rich-text text.to-view=\\\"selectedHotSpot.text\\\" mode=\\\"content\\\"></rich-text> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-landscape-header\\\"> <slot name=\\\"leftHeaderElement\\\"></slot> <h3 class=\\\"mp-landscape-header__title\\\" t=\\\"${titleTk}\\\"></h3> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-tile mp-tile--${size} ${ tile.picture ? 'mp-tile--with-image' : '' } ${ tile.audioUrl ? 'mp-tile--with-audio mdc-button' : '' }\\\" mouseenter.trigger=\\\"setAudioButtonHighlighted(true)\\\" mouseleave.trigger=\\\"setAudioButtonHighlighted(false)\\\" click.delegate=\\\"togglePlay()\\\"> <div class=\\\"mdc-button__ripple mp-tile__ripple\\\"></div> <div class=\\\"mp-tile__content\\\"> <div class=\\\"mp-tile__image-wrapper\\\"> <x-picture if.to-view=\\\"tile.picture\\\" class=\\\"mp-tile__image\\\" picture.to-view=\\\"tile.picture\\\"></x-picture> </div> <div if.to-view=\\\"tile.title || tile.subtitle\\\" class=\\\"mp-tile__text-wrapper ${ tile.audioUrl ? 'mp-tile__text-wrapper--with-audio' : '' }\\\"> <h3 if.to-view=\\\"tile.title\\\" class=\\\"mp-tile__title\\\">${tile.title | replaceMinusWithSoftHyphen}</h3> <p if.to-view=\\\"tile.subtitle\\\" class=\\\"mp-tile__subtitle\\\">${tile.subtitle | replaceMinusWithSoftHyphen}</p> </div> </div> <div if.to-view=\\\"tile.audioUrl\\\" class=\\\"mp-tile__audio-wrapper\\\"> <audio-service-button class=\\\"mp-tile__audio-button\\\" view-model.ref=\\\"audioServiceButton\\\" btn-type=\\\"inverted\\\" btn-state.to-view=\\\"audioButtonHighlighted ? `highlighted` : `normal`\\\" src.to-view=\\\"tile.audioUrl\\\"></audio-service-button> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"mp-tiles-preview\\\" style.to-view=\\\"{\\n            '--mp-tiles-preview-tile-count': tiles.length,\\n            '--mp-tiles-preview-scale-factor': scaleFactor,\\n            '--mp-tiles-preview-width-per-tile': widthPerTile + 'px',\\n            '--mp-tiles-preview-height-per-tile': heightPerTile + 'px'\\n          }\\\"> <mp-tile repeat.for=\\\"tile of tiles\\\" tile.to-view=\\\"tile\\\"></mp-tile> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"multi-donut-chart\\\"> <svg version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" x=\\\"0px\\\" y=\\\"0px\\\" viewBox=\\\"0 0 ${diameter} ${diameter}\\\" enable-background=\\\"new 0 0 ${diameter} ${diameter}\\\" xml:space=\\\"preserve\\\" class=\\\"multi-donut-chart__svg\\\"> <linearGradient id=\\\"${gradientIds[color]}\\\" repeat.for=\\\"color of themeColorTypes\\\"> <stop class=\\\"multi-donut-chart__gradient-start multi-donut-chart__gradient-start--${color}\\\" offset=\\\"0%\\\" style.to-view=\\\"getGradientStartStyle(color)\\\"></stop> <stop class=\\\"multi-donut-chart__gradient-end multi-donut-chart__gradient-end--${color}\\\" style.to-view=\\\"getGradientEndStyle(color)\\\" offset=\\\"100%\\\"></stop> </linearGradient> <g transform=\\\"translate(${donuts[0].outerRadius}, ${donuts[0].outerRadius})\\\" repeat.for=\\\"donut of donuts\\\"> <circle r=\\\"${donut.radius}\\\" stroke-width=\\\"${strokeWidth}\\\" style.to-view=\\\"getBackStrokeStyle(donut.color)\\\" class=\\\"multi-donut-chart__circle-back multi-donut-chart__circle-back--${donut.color}\\\"/> <circle r=\\\"${donut.radius}\\\" stroke-dasharray=\\\"${donut.circumference}\\\" stroke-dashoffset.bind=\\\"donut.frontCircumference\\\" stroke-width=\\\"${strokeWidth}\\\" stroke=\\\"url(#${gradientIds[donut.color]})\\\" class=\\\"multi-donut-chart__circle-front\\\" transform=\\\"rotate(275.1)\\\"/> </g> </svg> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"navigation-slider navigation-slider--color-${color}\\\" style.to-view=\\\"navigationSliderStyle\\\"> <div class=\\\"navigation-slider__pin ${pinActive && displayedValue <= max && displayedValue >= min ? 'navigation-slider__pin--active' : ''}\\\">${pinLabel}</div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template css=\\\"--indicator-color: ${indicatorColor};\\\"> <div class=\\\"password-strength-indicator__label\\\" aria-live=\\\"polite\\\"> <div class=\\\"password-strength-indicator__title\\\" t=\\\"common.password-strength-indicator.title\\\"></div> <div class=\\\"password-strength-indicator__value\\\" t=\\\"common.password-strength-indicator.strength-${strengthLabel}\\\"></div> </div> <div class=\\\"password-strength-indicator__scale\\\"> <div class=\\\"password-strength-indicator__scale--active\\\"></div> <div class=\\\"${ strength > 1 ? 'password-strength-indicator__scale--active' : '' }\\\"></div> <div class=\\\"${ strength > 2 ? 'password-strength-indicator__scale--active' : '' }\\\"></div> <div class=\\\"${ strength > 3 ? 'password-strength-indicator__scale--active' : '' }\\\"></div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"picture-puzzle picture-puzzle--${theme} picture-puzzle--type-${question.type} picture-puzzle--responsiveness-${responsiveness} ${disabled || revealAnswer ? 'picture-puzzle--disabled' : ''}\\\"> <aspect-ratio-container class=\\\"picture-puzzle__aspect-ratio-container\\\" mode=\\\"width-and-height-dependent\\\"> <img class=\\\"picture-puzzle__bg-picture\\\" src.to-view=\\\"question.pictureUrl\\\"> <img repeat.for=\\\"answer of answerOptions\\\" class=\\\"picture-puzzle__overlay-picture ${isSelected(answer.answerId, selectedAnswers) ? 'picture-puzzle__overlay-picture--selected' : ''}\\\" src.to-view=\\\"answer.pictureUrl\\\"> <div repeat.for=\\\"answer of answerOptions\\\" class=\\\"picture-puzzle__click-zone ${getClickZoneRevealClass(answer, revealAnswer, selectedAnswers)}\\\" style.to-view=\\\"getClickZoneStyle(answer)\\\" click.delegate=\\\"handleClickZoneClicked(answer)\\\"> </div> </aspect-ratio-container> </template>\";\n// Exports\nexport default code;","import { EventAggregator } from 'aurelia-event-aggregator';\nimport { FrameworkConfiguration, PLATFORM } from 'aurelia-framework';\nimport { EaEvent } from 'common/enum/ea-event.enum';\nimport { LocaleUtils } from 'common/utils/LocaleUtils';\nimport Moment from 'moment';\nimport { AbstractPluginComponent, PluginConstructor } from './AbstractPluginComponent';\nimport { BaseFillInTheBlankSelectPlugin } from './fill-in-the-blank-select/fill-in-the-blank-select';\nimport { BaseListStandardPlugin } from './list-standard/list-standard';\nimport { BasePossibleAnswersPlugin } from './possible-answers/possible-answers';\nimport { BaseQuizResultQuestionAnswerPlugin } from './quiz-result-question-answer/quiz-result-question-answer';\nimport { BaseQuizResultQuestionBlockPlugin } from './quiz-result-question-block/quiz-result-question-block';\nimport { BaseTestexamPreviousResultsPlugin } from './testexam-previous-results/testexam-previous-results';\n\nexport function configure(config: FrameworkConfiguration, opts: IAureliaComponentsOptions): void {\n  config.feature(PLATFORM.moduleName('common/aurelia-components/active-distinar-course-slides/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/announcement/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/aspect-ratio-container/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/audio-player/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/audio-progress-bar/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/audio-service-button/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/avatar-component-card/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/avatar-icon/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/back-button/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/blurhash/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/breadcrumbs/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/button-exam-classic/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/button-exam/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/button-lightswitch/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/button-round/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/button-smaller/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/chat-input/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/chat-link-search/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/chat-message/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/chat-view/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/common-full-screen-container/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/conference-attendee/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/conference-video-matrix/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/content-block/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/content-editor/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/course-block/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/course-learn-footer/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/course-learn-page-content/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/course-learn-page-header/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/course-lecture-block/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/course-question-classic/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/course-question/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/css-bar-chart-bar/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/css-bar-chart/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/custom-select-answer-overlay/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/distinar-conference-student-view/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/distinar-course-picture-overlay/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/distinar-floating-video-container/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/distinar-whiteboard-viewer/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/donut-chart/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/drawing-area/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/dropdown-select/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/dual-video-player/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/exam-image-overlay/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/exam-image/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/exam-result-legend/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/external-login/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/fill-in-the-blank-select/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/fill-in-the-blank/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/focus-reset/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/full-screen-bottom-sheet-header/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/full-screen-bottom-sheet/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/full-screen-container/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/fullscreenable-container/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/hot-spot-button/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/ias-block/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/ias-slide/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/icon-with-tooltip/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/image-cropper/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/intersection-target/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/lecture-break/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/lecture-end/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/lecture-start/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/lecture-status/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/level-donut-chart/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/level-profile/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/list-standard/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/loading-overlay/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/lottie-animation-player/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/markdown-text/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/methodpool/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/mp-hot-spot-drawer/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/mp-landscape-header/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/mp-tile/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/mp-tiles-preview/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/multi-donut-chart/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/navigation-slider/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/password-strength-indicator/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/picture-puzzle/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/pin-code/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/placeable-dialog/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/points-donut-chart/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/points-explanation/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/possible-answers-classic/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/possible-answers/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/progress-bar/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/qr-code-scanner/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/quiz-result-question-answer/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/quiz-result-question-block/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/recent-trainings-list/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/rich-text/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/risi-game/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/rounded-progress-bar/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/scorm-player/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/scroll-inset/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/self-writing/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/skill-icon/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/slider-standard/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/star-rating/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/statistics-chapter-progress/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/statistics-games-details/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/statistics-games/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/statistics-learning/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/statistics-overview-list-item/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/statistics-overview-points/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/statistics-overview-progress/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/statistics-sub-header/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/statistics-testexam/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/statistics-training/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/swipe-nav/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/template-preview-block/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/testexam-previous-results/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/testexam-result-overview/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/text-editor/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/train-result-header/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/update-counter/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/value-converters/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/version-info/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/video-nametag/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/video-player/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/whiteboard/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/x-accordion/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/x-checkbox/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/x-icon/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/x-img/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/x-picture/index'));\n  config.feature(PLATFORM.moduleName('common/aurelia-components/x-spinner/index'));\n  AbstractPluginComponent.registerPlugins(opts.listStandardPlugins);\n  AbstractPluginComponent.registerPlugins(opts.quizResultQuestionBlockPlugins);\n  AbstractPluginComponent.registerPlugins(opts.quizResultQuestionAnswerPlugins);\n  AbstractPluginComponent.registerPlugins(opts.possibleAnswersPlugins);\n  AbstractPluginComponent.registerPlugins(opts.testexamPreviousResultsPlugins);\n  AbstractPluginComponent.registerPlugins(opts.fillInTheBlankSelectPlugins);\n\n  const ea = config.container.get(EventAggregator);\n  ea.subscribe('i18n:locale:changed', (args: { oldValue: string; newValue: string }) => {\n    LocaleUtils.defineShortMomentLocale(args.newValue);\n    Moment.locale(LocaleUtils.momentLocaleFromI18nLocale(args.newValue));\n    ea.publish(EaEvent.MomentLocaleChanged);\n  });\n}\n\nexport interface IAureliaComponentsOptions {\n  testexamPreviousResultsPlugins: Array<PluginConstructor<BaseTestexamPreviousResultsPlugin>>;\n  quizResultQuestionBlockPlugins: Array<PluginConstructor<BaseQuizResultQuestionBlockPlugin>>;\n  listStandardPlugins: Array<PluginConstructor<BaseListStandardPlugin>>;\n  possibleAnswersPlugins: Array<PluginConstructor<BasePossibleAnswersPlugin>>;\n  fillInTheBlankSelectPlugins: Array<PluginConstructor<BaseFillInTheBlankSelectPlugin>>;\n  quizResultQuestionAnswerPlugins: Array<PluginConstructor<BaseQuizResultQuestionAnswerPlugin>>;\n}\n","import { FrameworkConfiguration, PLATFORM } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/intersection-target/intersection-target'));\n}\n","import { autoinject, bindable, useView, PLATFORM } from 'aurelia-framework';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\n\n@useView(PLATFORM.moduleName('./intersection-target.html'))\n@autoinject()\nexport class IntersectionTarget {\n  @bindable() public root: HTMLElement | null = null;\n  public visible = false;\n\n  private domElement: HTMLElement | null = null;\n  private observer: IntersectionObserver | null = null;\n\n  constructor(element: Element) {\n    this.domElement = element as HTMLElement;\n  }\n\n  protected attached(): void {\n    this.observer?.disconnect();\n    assertNotNullOrUndefined(this.domElement, 'domElement cannot be null or undefined');\n    assertNotNullOrUndefined(this.root, 'root cannot be null or undefined');\n\n    const options: IntersectionObserverInit = {\n      root: this.root,\n    };\n\n    this.observer = new IntersectionObserver(this.didIntersect.bind(this), options);\n    this.observer.observe(this.domElement);\n  }\n\n  protected detached(): void {\n    this.visible = false;\n    this.observer?.disconnect();\n  }\n\n  private didIntersect(entries: Array<IntersectionObserverEntry>): void {\n    const newestEntry = ArrayUtils.max(entries, entry => entry.time);\n    if(newestEntry == null) return;\n    if(window.requestIdleCallback) {\n      window.requestIdleCallback(() => {\n        this.visible = newestEntry.isIntersecting === true;\n      });\n    } else {\n      window.setTimeout(() => {\n        this.visible = newestEntry.isIntersecting === true;\n      });\n    }\n  }\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/lecture-break/lecture-break'));\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { IEventDto } from 'common/dto/tenant/event/tenant.event.interface';\n\n@autoinject\n@useView(PLATFORM.moduleName('./lecture-break.html'))\nexport class LectureBreak {\n  @bindable()\n  public activeLecture: IEventDto<string> | null = null;\n  @bindable()\n  public tenantLogoPictureUrl: string | null = null;\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/lecture-end/lecture-end'));\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { IEventDto } from 'common/dto/tenant/event/tenant.event.interface';\n\n@autoinject\n@useView(PLATFORM.moduleName('./lecture-end.html'))\nexport class LectureEnd {\n  @bindable()\n  public activeLecture: IEventDto<string> | null = null;\n  @bindable()\n  public tenantLogoPictureUrl: string | null = null;\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/lecture-start/lecture-start'));\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { IEventDto } from 'common/dto/tenant/event/tenant.event.interface';\nimport Moment from 'moment';\nimport { SubscriptionManagerService, SubscriptionManager } from 'common/aurelia-services/SubscriptionManagerService';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./lecture-start.html'))\nexport class LectureStart {\n  @bindable()\n  public activeLecture: IEventDto<string> | null = null;\n  @bindable()\n  public tenantLogoPictureUrl: string | null = null;\n\n  private subscriptionManager: SubscriptionManager;\n  private minutesToStart: number | null = null;\n  private statusInfo?: ILectureAboutToStartStatusInfo;\n\n  constructor(\n    subscriptionManagerService: SubscriptionManagerService,\n  ) {\n    this.subscriptionManager = subscriptionManagerService.createSubscriptionManager();\n  }\n\n  private activeLectureChanged(): void {\n    this.updateMinuteCount(this.activeLecture);\n    this.subscriptionManager.disposeSubscriptions();\n\n    if(this.activeLecture != null) this.subscriptionManager.subscribeToInterval(() => {\n      this.updateMinuteCount(this.activeLecture);\n    }, 1000);\n  }\n\n  private updateMinuteCount(activeLecture: IEventDto<string> | null): void {\n    if(activeLecture == null) return;\n\n    const duration = Moment.duration(Moment(activeLecture.plannedDateFrom).diff(Moment()));\n    this.setMinuteCount(Math.ceil(duration.asMinutes()));\n  }\n\n  private setMinuteCount(minuteCount: number): void {\n    if(minuteCount > 0) {\n      this.minutesToStart = minuteCount;\n      this.statusInfo = {\n        firstLineTk: 'common.lecture-start.expectedStart',\n        secondLineTk: 'common.lecture-start.inMinutes',\n      };\n    } else {\n      this.subscriptionManager.disposeSubscriptions();\n      this.statusInfo = {\n        firstLineTk: 'common.lecture-start.waitingForLecturer',\n        secondLineTk: 'common.lecture-start.waitingForLecturerSecondLine',\n      };\n    }\n  }\n\n  private unbind(): void {\n    this.subscriptionManager.disposeSubscriptions();\n  }\n}\n\ninterface ILectureAboutToStartStatusInfo {\n  firstLineTk: string;\n  secondLineTk: string;\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/lecture-status/lecture-status'));\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { IEventDto } from 'common/dto/tenant/event/tenant.event.interface';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { IEventTimeFrameParams, EventTimeFrameUtils } from 'common/utils/EventTimeFrameUtils';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./lecture-status.html'))\nexport class LectureStatus {\n  @bindable() public infoFirstLine!: string;\n  @bindable() public infoSecondLine?: string;\n  @bindable() public activeLecture: IEventDto<string> | null = null;\n  @bindable() public tenantLogoPictureUrl: string | null = null;\n\n  private dateTimeTranslation?: string;\n  private dateTimeTranslationParams?: IEventTimeFrameParams;\n  private lecturerName?: string;\n\n  private activeLectureChanged(): void {\n    if(!this.activeLecture) return;\n\n    this.updateTimeFrame();\n    this.updateLecturerName();\n  }\n\n  private updateLecturerName(): void {\n    assertNotNullOrUndefined(this.activeLecture, 'activeLecture cannot be null or undefined');\n    if(this.activeLecture.lecturer) {\n      const lecturerName = [];\n\n      if(this.activeLecture.lecturer.titlePrefix) {\n        lecturerName.push(this.activeLecture.lecturer.titlePrefix);\n      }\n      if(this.activeLecture.lecturer.firstname) {\n        lecturerName.push(this.activeLecture.lecturer.firstname);\n      }\n      if(this.activeLecture.lecturer.lastname) {\n        lecturerName.push(this.activeLecture.lecturer.lastname);\n      }\n      if(this.activeLecture.lecturer.titleSuffix) {\n        lecturerName.push(this.activeLecture.lecturer.titleSuffix);\n      }\n      this.lecturerName = lecturerName.join(' ');\n    } else {\n      this.lecturerName = undefined;\n    }\n  }\n\n  private updateTimeFrame(): void {\n    assertNotNullOrUndefined(this.activeLecture, 'activeLecture cannot be null or undefined');\n    const { plannedDateFrom, plannedDateTo } = this.activeLecture;\n\n    this.dateTimeTranslationParams = EventTimeFrameUtils.getTimeFrameParams(plannedDateFrom, plannedDateTo);\n\n    if(this.dateTimeTranslationParams.today) {\n      this.dateTimeTranslation = 'timeFrameToday';\n    } else {\n      this.dateTimeTranslation = 'timeFrameSameDay';\n    }\n  }\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/level-donut-chart/level-donut-chart'));\n}\n","import { autoinject, bindable, computedFrom, PLATFORM, useView } from 'aurelia-framework';\nimport { LevelColor } from 'common/constants/levels.constants';\nimport { AvatarIconSize } from '../avatar-icon/avatar-icon';\n\n/**\n * @slot - for avatar-icons\n */\n@useView(PLATFORM.moduleName('./level-donut-chart.html'))\n@autoinject\nexport class LevelDonutChart {\n  @bindable public value = 0;\n  @bindable public color = LevelColor.Bronze;\n  @bindable public size: AvatarIconSize = AvatarIconSize.Standard;\n\n  private donutDiameter = 230;\n  private donutStrokeWidth = 30;\n  private donutInnerRadius = 0;\n  private donutCircumference = 0;\n  private circleFrontStrokeDash = 0;\n  private donutOuterRadius = 0;\n\n  protected attached(): void {\n    this.updateLevelDonut();\n  }\n\n  @computedFrom('value')\n  private get circleFrontStrokeDashOffset(): number {\n    return this.donutCircumference * (1 - this.value / 100);\n  }\n\n  private valueChanged(): void {\n    this.updateLevelDonut();\n  }\n\n  /**\n   * Calculates radius, dash, circumference etc from given diameter and strokewidth\n   * to make it responsive, change diameter and strokewidth\n   */\n  private updateLevelDonut(): void {\n    this.donutInnerRadius = (this.donutDiameter - this.donutStrokeWidth) / 2;\n    this.donutCircumference = Math.ceil(2 * this.donutInnerRadius * Math.PI);\n    this.donutOuterRadius = this.donutDiameter / 2;\n    this.circleFrontStrokeDash = Math.ceil(this.donutInnerRadius * 2 * Math.PI);\n  }\n}\n","import { FrameworkConfiguration, PLATFORM } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/level-profile/level-profile'));\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/level-profile/level-profile-badge/level-profile-badge'));\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/level-profile/level-profile-item/level-profile-item'));\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/level-profile/level-profile-progress/level-profile-progress'));\n}\n","import { autoinject, PLATFORM, bindable, useView } from 'aurelia-framework';\nimport { LevelColor } from 'common/constants/levels.constants';\nimport { LevelUtils } from 'common/utils/LevelUtils';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./level-profile-badge.html'))\nexport class LevelProfileBadge {\n  @bindable() public level = 1;\n  private levelColor: LevelColor = LevelColor.Bronze;\n\n  private get textShadowColorMatrix(): string {\n    if(this.levelColor === LevelColor.Gold) return '0 0 0 0 0.8   0 0 0 0 0.596078431   0 0 0 0 0.149019608  0 0 0 1 0';\n    if(this.levelColor === LevelColor.Silver) return '0 0 0 0 0.517647059   0 0 0 0 0.517647059   0 0 0 0 0.517647059  0 0 0 1 0';\n    return '0 0 0 0 0.521568627   0 0 0 0 0.388235294   0 0 0 0 0.164705882  0 0 0 1 0';\n  }\n\n  private levelChanged(): void {\n    this.levelColor = LevelUtils.getCurrentLevelColor(this.level);\n  }\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./level-profile-item.html'))\nexport class LevelProfileItem {\n  @bindable() public nameTk: string | null = null;\n  @bindable() public points: number | null = null;\n  @bindable() public pointsColor = '';\n  @bindable() public showLine = true;\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { LevelColor } from 'common/constants/levels.constants';\nimport { LevelUtils } from 'common/utils/LevelUtils';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./level-profile-progress.html'))\nexport class LevelProfileProgress {\n  @bindable() public points = 0;\n  private level = 1;\n  private levelPercentage = 0;\n  private levelMinPoints = 0;\n  private levelMaxPoints = 0;\n  private levelColor: LevelColor = LevelColor.Bronze;\n\n  private pointsChanged(): void {\n    this.level = LevelUtils.getCurrentLevel(this.points);\n    this.levelPercentage = LevelUtils.getCurrentLevelPercentage(this.points);\n    this.levelMinPoints = LevelUtils.getCurrentLevelMinPoints(this.points);\n    this.levelMaxPoints = LevelUtils.getMinPointsForLevel(this.level + 1);\n    this.levelColor = LevelUtils.getCurrentLevelColor(this.level);\n  }\n}\n","import { autoinject, bindable, computedFrom, PLATFORM, useView } from 'aurelia-framework';\nimport { LevelColor } from 'common/constants/levels.constants';\nimport { ICoursePointsGroupedDto } from 'common/dto/course/points/course.points.interface';\nimport { LevelUtils } from 'common/utils/LevelUtils';\nimport { StringUtils } from 'common/utils/StringUtils';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./level-profile.html'))\nexport class LevelProfile {\n  @bindable() public groupedPoints: ICoursePointsGroupedDto = {\n    training: 0,\n    testexam: 0,\n    duel: 0,\n    lecture: 0,\n    learning: 0,\n    activityStreak: 0,\n  };\n  @bindable() public coins: number | null = null;\n  @bindable() public showGames = true;\n  @bindable() public containerModeOn = false;\n\n  private points = 0;\n  private level = 1;\n  private levelColor: LevelColor = LevelColor.Bronze;\n  private availableLevels = LevelUtils.getHighestLevel();\n\n  @computedFrom('groupedPoints', 'showGames')\n  private get groupedPointItems(): Array<IGroupedPointsItem> {\n    const items = [\n      {\n        nameTk: 'common.level-profile.learning',\n        points: this.groupedPoints.learning,\n        pointsColor: 'var(--color-primary)',\n      },\n      {\n        nameTk: 'common.level-profile.training',\n        points: this.groupedPoints.training,\n        pointsColor: 'var(--color-secondary1)',\n      },\n      {\n        nameTk: 'common.level-profile.testexam',\n        points: this.groupedPoints.testexam,\n        pointsColor: 'var(--color-primary-300)',\n      },\n    ];\n\n    if(this.showGames) {\n      items.push({\n        nameTk: 'common.level-profile.gamesGroup',\n        points: this.groupedPoints.duel + this.groupedPoints.activityStreak + this.groupedPoints.lecture,\n        pointsColor: 'var(--color-secondary3)',\n      });\n    }\n\n    return items;\n  }\n\n  private groupedPointsChanged(): void {\n    this.points = Object.values(this.groupedPoints).reduce((acc, val) => acc + val, 0);\n    this.level = LevelUtils.getCurrentLevel(this.points);\n    this.levelColor = LevelUtils.getCurrentLevelColor(this.level);\n  }\n\n  private getNumberAsGroupedNumberString(value: number | null): string {\n    if(value == null) return '';\n    return StringUtils.formatNumberGrouped(Number(value.toFixed(2)));\n  }\n}\n\ninterface IGroupedPointsItem {\n  nameTk: string;\n  points: number;\n  pointsColor: string;\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/list-standard/list-standard'));\n}\n","import { MDCList } from '@material/list';\nimport { MDCRipple } from '@material/ripple/component';\nimport { autoinject, bindable, computedFrom, Container, PLATFORM, useView } from 'aurelia-framework';\nimport { ThemeColorType } from 'common/aurelia-classes/SiteThemer';\nimport { Color } from 'common/aurelia-components/donut-chart/donut-chart';\nimport { KeyboardKey } from 'common/enum/keyboard.key.enum';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { AbstractPluginComponent, AbstractPluginComponentPlugin } from '../AbstractPluginComponent';\nimport { SpecialAvatarTypes } from '../avatar-icon/avatar-icon';\nimport { IconSize } from '../x-icon/x-icon';\n\nexport interface IRouteNameClickConfig {\n  routeName: string;\n  routeParams?: any;\n}\n\nexport interface ICallbackClickConfig {\n  callback?: () => void;\n}\n\nexport enum TextStyle {\n  Dismiss = 'dismiss',\n  Leaderboard = 'leaderboard',\n  Confirm = 'confirm',\n  Timeout = 'timeout',\n  Primary = 'primary',\n}\n\nexport enum ListTheme {\n  Accordion = 'accordion',\n  Dark = 'dark',\n  Leaderboard = 'leaderboard',\n  ManagerChat = 'manager-chat',\n  Standard = 'standard',\n}\n\nexport interface ITextTkConfig {\n  textTk: string;\n  params?: Record<string, unknown>;\n  textStyle?: TextStyle;\n}\n\nexport interface IIconConfig {\n  name: string;\n  size: IconSize;\n  type: string;\n  safe?: boolean;\n  color?: ThemeColorType;\n}\n\nexport interface IAvatarConfig {\n  avatarSvgDownloadLink: string | null;\n  disabled: boolean;\n  fallbackAvatar?: SpecialAvatarTypes;\n  points: number | null;\n  online?: boolean;\n}\n\nexport interface IDonutChartConfig {\n  value: number;\n  color?: Color;\n  fontScale?: number;\n  hidePercentage?: boolean;\n}\n\nexport interface IClickableIconConfig extends IIconConfig {\n  onClick?: () => void;\n  ariaLabel?: string;\n}\n\nexport interface IRadioIconConfig extends IClickableIconConfig {\n  onClick?: () => void;\n  checked: boolean;\n  isRadio: boolean;\n}\n\nexport interface IButtonConfig {\n  text: ITextTkConfig | string;\n  disabled?: boolean;\n  onClick?: () => void;\n}\n\nexport enum ListItemMaxWidth {\n  ContentSmall = 'content-small',\n  Content = 'content'\n}\n\nexport interface IListItemText {\n  primary: ITextTkConfig | string;\n  /**\n   * If at least one item has 'secondary' set, the list will become a two-line-list\n   */\n  secondary?: ITextTkConfig | string | Array<string>;\n  tertiary?: ITextTkConfig | string;\n  quaternary?: ITextTkConfig | string;\n}\n\nexport interface IListStandardItem {\n  /**\n   * A list of icons or text buttons, displayed on the right\n   */\n  icons: Array<IButtonConfig | IClickableIconConfig | ITextTkConfig | string>;\n  click?: IRouteNameClickConfig | ICallbackClickConfig;\n  separatorAfter: boolean;\n  /**\n   * If at least one item has 'text.secondary' set, the list will become a two-line-list\n   */\n  text: IListItemText;\n  /**\n   * An icon displayed on the left\n   */\n  graphic?: IIconConfig | IAvatarConfig | IDonutChartConfig;\n  disabled?: boolean;\n  maxWidth?: ListItemMaxWidth;\n  enumeration?: number;\n  multiline?: boolean;\n  /**\n   * allow proper vertical spacing if text in multiline mode wraps\n   */\n  multilineWrapSpacing?: boolean;\n  /**\n   * indicate unread chats\n   */\n  unread?: boolean;\n}\n\nexport abstract class BaseListStandardPlugin extends AbstractPluginComponentPlugin {\n  public abstract navigateToSpecifiedRoute(routeConfig: IRouteNameClickConfig): void;\n}\n@autoinject()\n@useView(PLATFORM.moduleName('./list-standard.html'))\nexport class ListStandard extends AbstractPluginComponent<BaseListStandardPlugin> {\n  @bindable() public items: IListStandardItem[] | null = null;\n  @bindable() public enumeration = false;\n  @bindable() public listTheme: ListTheme = ListTheme.Standard;\n  @bindable() public columnizeItems = false;\n  @bindable() public listEmptyTk: string | null = null;\n  /** Allow list items to grow vertically to fit their content, e.g. when expecting multi-line items */\n  @bindable() public allowGrow = false;\n\n  private readonly AVERAGE_NUMBER_WIDTH_IN_PIXELS = 13;\n\n  private domElement: HTMLElement;\n  private containerModeOn = false;\n  private listElement: HTMLElement | null = null;\n  private list: MDCList | null = null;\n  private listItemRipples: MDCRipple[] | null = null;\n\n  constructor(container: Container, element: Element) {\n    super(container, [BaseListStandardPlugin]);\n    this.domElement = element as HTMLElement;\n  }\n\n  protected attached(): void {\n    assertNotNullOrUndefined(this.listElement, 'forgot to ref listElement');\n    assertNotNullOrUndefined(this.items, 'forgot to bind items');\n\n    const list = new MDCList(this.listElement);\n\n    // hack: MDCList wants to keep buttons untabable and sets all tabindices to -1\n    (list as any).foundation_.adapter_.setTabIndexForListItemChildren = () => { };\n    // hack: MDCList also sets a tabindex of -1 in layout\n    const foundation = (list as any).foundation_;\n    const listLayout = foundation.layout.bind(foundation);\n    (list as any).foundation_.layout = () => {\n      this.listElement?.querySelectorAll('.mdc-button').forEach(e => e.removeAttribute('tabindex'));\n      listLayout();\n    };\n\n    this.items.forEach((item, index) => list.setEnabled(index, !item.disabled));\n    this.listItemRipples = list.listElements.map(listItemEl => new MDCRipple(listItemEl));\n    list.layout();\n    this.list = list;\n  }\n\n  protected detached(): void {\n    this.list?.destroy();\n    if(this.listItemRipples) {\n      this.listItemRipples.forEach(listItemRipple => listItemRipple.destroy());\n    }\n  }\n\n  @computedFrom('items')\n  private get isTwoLineList(): boolean {\n    return this.getLineCount() === 2;\n  }\n\n  @computedFrom('items')\n  private get isThreeLineList(): boolean {\n    return this.getLineCount() === 3;\n  }\n\n  @computedFrom('items')\n  private get isFourLineList(): boolean {\n    return this.getLineCount() === 4;\n  }\n\n  @computedFrom('items')\n  private get lineCount(): number {\n    return this.getLineCount();\n  }\n  \n  private getLineCount(): number {\n    let lineCount = 1;\n    if(this.items?.some(i => i.text.secondary || i.icons.some(icon => (icon as IButtonConfig).text)) || false) lineCount++;\n    if(this.items?.some(i => i.text.tertiary) || false) lineCount++;\n    if(this.items?.some(i => i.text.quaternary) || false) lineCount++;    \n    return lineCount;\n  }\n\n  @computedFrom('items')\n  private get highestEnumerationWidth(): number {\n    if(!this.items) return 0;\n    return Math.max(...this.items.map(i => i.enumeration ?? 0))\n      .toString().length * this.AVERAGE_NUMBER_WIDTH_IN_PIXELS;\n  }\n\n  private getEnumerationString(item: IListStandardItem, index: number): string {\n    return `${item.enumeration ?? (index + 1)}${this.listTheme === ListTheme.Leaderboard ? '' : '.'}`;\n  }\n\n  private handleClick(item: IListStandardItem): void {\n    if(!item.click) {\n      return;\n    }\n\n    const { routeName, routeParams } = item.click as IRouteNameClickConfig;\n    if(routeName) {\n      const routeNameClickConfig = {\n        routeName, routeParams,\n      };\n\n      this.usePlugins(plugin => {\n        plugin.navigateToSpecifiedRoute(routeNameClickConfig);\n      });\n      return;\n    }\n\n    const { callback } = item.click as ICallbackClickConfig;\n    if(callback) {\n      callback();\n    }\n  }\n\n  private handleIconClick(icon: IClickableIconConfig | IRadioIconConfig, event: Event): boolean {\n    const keyboardEvent = event as KeyboardEvent;\n    if(\n      'key' in keyboardEvent\n      && keyboardEvent.key !== KeyboardKey.Enter\n      && keyboardEvent.key !== KeyboardKey.Space\n    ) {\n      return false;\n    }\n\n    if(icon.onClick) {\n      event.stopPropagation();\n      icon.onClick();\n      return false;\n    }\n\n    return true;\n  }\n\n  private isArray(item: unknown): boolean {\n    return Array.isArray(item);\n  }\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/loading-overlay/loading-overlay'));\n}\n","import { bindable, autoinject, useView, PLATFORM } from 'aurelia-framework';\nimport { TOptions as I18NextTOptions } from 'i18next';\n\n@useView(PLATFORM.moduleName('./loading-overlay.html'))\n@autoinject()\nexport class LoadingOverlay {\n  @bindable() public visible = false;\n  /**\n   * set y-position to prevent repositioning of loading-circle when used inside a container\n   */\n  @bindable() public circlePositionY: string | null = '50%';\n  @bindable() public statusMessages: ILoadingOverlayStatus[] = [];\n  @bindable() public context: 'absolute' | 'relative' = 'absolute';\n}\n\nexport interface ILoadingOverlayStatus {\n  type: LoadingOverlayType;\n  textTk: string;\n  textTkParams?: I18NextTOptions<Record<string, unknown>>;\n}\n\nexport enum LoadingOverlayType {\n  Error = 'error',\n  Info = 'info',\n  Title = 'title',\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/lottie-animation-player/lottie-animation-player'));\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { DomUtils } from 'common/utils/DomUtils';\nimport lottie, { AnimationDirection, AnimationItem } from 'lottie-web';\n\n/**\n * @event {LottieAnimationReadyEvent} lottie-animation-ready\n * @event {LottieLoopCompleteEvent} lottie-loop-complete\n */\n@autoinject()\n@useView(PLATFORM.moduleName('./lottie-animation-player.html'))\nexport class LottieAnimationPlayer {\n  /**\n   * animation data in JSON format (see: https://github.com/airbnb/lottie-web/tree/master/docs/json)\n   * Note: animation data version has to match lottie-web version\n   */\n  @bindable()\n  public animationData: IAnimationData | null = null;\n\n  /**\n   * if true, animation automatically starts playing when ready\n   */\n  @bindable()\n  public autoplay = false;\n\n  /**\n   * if set together with autoplay, the autoplay will be delayed by this many milliseconds\n   */\n  @bindable()\n  public autoplayDelay = 0;\n\n  /**\n   * if the animation should loop\n   */\n  @bindable()\n  public loop = false;\n\n  public animationDirection: AnimationDirection = 1;\n\n  private element: Element;\n  private animationItem: AnimationItem | null = null;\n  private markers: Record<string, number> = {};\n  private animationContainer: HTMLDivElement | null = null;\n  private isAttached = false;\n  private autoplayDelayTimeout: number | null = null;\n\n  constructor(element: Element) {\n    this.element = element;\n  }\n\n  public play(): void {\n    // Check if player is attached, as the play() call from a model.ref can happen before\n    if(!this.isAttached) {\n      return;\n    }\n    this.assertAnimationItem(this.animationItem);\n    this.clearAutoplayTimeout();\n    this.animationItem.play();\n  }\n\n  public playSegment(from?: string | number, to?: string | number): void {\n    this.assertAnimationItem(this.animationItem);\n\n    const fromFrame = from === undefined\n      ? 0\n      : this.getFrameByMarkerNameOrNumber(from);\n\n    const toFrame = to === undefined\n      ? this.animationItem.getDuration(true)\n      : this.getFrameByMarkerNameOrNumber(to);\n\n    this.animationItem.playSegments([fromFrame, toFrame], true);\n  }\n\n  public setDirection(direction: AnimationDirection): void {\n    this.assertAnimationItem(this.animationItem);\n    this.animationDirection = direction;\n    this.animationItem.setDirection(this.animationDirection);\n  }\n\n  public pause(): void {\n    this.assertAnimationItem(this.animationItem);\n    this.animationItem.pause();\n  }\n\n  public resetAnimation(): void {\n    this.goToAndStop(0);\n  }\n\n  public end(): void {\n    this.assertAnimationItem(this.animationItem);\n    this.goToAndStop(this.animationItem.getDuration(true));\n  }\n\n  public goToAndStop(frameOrMarkerName: number | string): void {\n    this.assertAnimationItem(this.animationItem);\n    this.clearAutoplayTimeout();\n    this.animationItem.goToAndStop(this.getFrameByMarkerNameOrNumber(frameOrMarkerName), true);\n  }\n\n  private attached(): void {\n    this.isAttached = true;\n    this.updateAnimationItem();\n  }\n\n  private detached(): void {\n    this.isAttached = false;\n    this.removeAnimationItem();\n  }\n\n  private animationDataChanged(): void {\n    this.updateAnimationItem();\n  }\n\n  private assertAnimationItem(animationItem: AnimationItem | null): asserts animationItem is AnimationItem {\n    if(!animationItem) {\n      if(!this.isAttached) {\n        throw new Error('element is not attached');\n      }\n\n      if(!this.animationData) {\n        throw new Error('no animation data is given');\n      }\n\n      if(!this.animationContainer) {\n        throw new Error('animationContainer is not available');\n      }\n\n      throw new Error('animationItem is not available');\n    }\n  }\n\n  private updateAnimationItem(): void {\n    this.removeAnimationItem();\n\n    const animationData = JSON.parse(JSON.stringify(this.animationData));\n\n    if(this.animationContainer && this.animationData && this.isAttached) {\n      this.animationItem = lottie.loadAnimation({\n        container: this.animationContainer,\n        renderer: 'svg',\n        loop: this.loop,\n        autoplay: this.autoplay && this.autoplayDelay <= 0,\n        animationData,\n      });\n\n      this.markers = this.extractMarkerData(animationData);\n\n      if(this.autoplay) {\n        this.autoplayDelayTimeout = window.setTimeout(() => this.play(), this.autoplayDelay);\n      }\n\n      this.animationItem.addEventListener('loopComplete', () => {\n        this.fireLoopComplete();\n      });\n\n      this.animationItem.addEventListener('complete', () => {\n        this.fireLoopComplete();\n      });\n\n      this.fireAnimationReady();\n    }\n  }\n\n  private fireAnimationReady(): void {\n    DomUtils.fireEvent(this.element as HTMLElement, {\n      bubbles: false,\n      name: 'lottie-animation-ready',\n    });\n  }\n\n  private fireLoopComplete(): void {\n    DomUtils.fireEvent(this.element as HTMLElement, {\n      bubbles: false,\n      name: 'lottie-loop-complete',\n    });\n  }\n\n  private extractMarkerData(animationData: IAnimationData): Record<string, number> {\n    const { markers } = animationData;\n    return ArrayUtils.toRecord(markers, m => m.cm, m => m.tm);\n  }\n\n  private getMarkerFrame(markerName: string): number {\n    const frame = this.markers[markerName];\n    assertNotNullOrUndefined(frame, `marker ${markerName} is not defined in animation`);\n    return frame;\n  }\n\n  private getFrameByMarkerNameOrNumber(frameOrMarkerName: number | string): number {\n    return typeof frameOrMarkerName === 'string'\n      ? this.getMarkerFrame(frameOrMarkerName)\n      : frameOrMarkerName;\n  }\n\n  private removeAnimationItem(): void {\n    if(this.animationItem) {\n      this.clearAutoplayTimeout();\n      this.animationItem.destroy();\n      this.animationItem = null;\n    }\n  }\n\n  private clearAutoplayTimeout(): void {\n    if(this.autoplayDelayTimeout) clearTimeout(this.autoplayDelayTimeout);\n  }\n}\n\n/**\n * Animation Data exported from After Effects\n */\nexport interface IAnimationData {\n  v: string;\n  fr: number;\n  ip: number;\n  op: number;\n  w: number;\n  h: number;\n  nm: string;\n  ddd: number;\n  assets: Array<any>;\n  layers: Array<any>;\n  markers: Array<{\n    tm: number;\n    cm: string;\n  }>;\n}\n\nexport type LottieAnimationReadyEvent = CustomEvent<never>;\nexport type LottieLoopCompleteEvent = CustomEvent<never>;\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/markdown-text/markdown-text'));\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { SubscriptionManager, SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\nimport { IShowdownConverter, MarkdownUrls, ShowdownUtils } from 'common/markdown/ShowdownUtils';\nimport { DomUtils } from 'common/utils/DomUtils';\nimport type { AnnotationControl } from 'common/markdown/ShowdownAnnotationExtensions';\n\n/**\n * css variables\n * |name|description|\n * |----|-----------|\n * |--markdown-text-scale-factor|scale factor for scaling the text|\n */\n@useView(PLATFORM.moduleName('./markdown-text.html'))\n@autoinject()\nexport class MarkdownText {\n  @bindable() public text: string | null = null;\n  @bindable() public urls: MarkdownUrls | null = null;\n  @bindable() public annotate = true;\n\n  private domElement: HTMLElement;\n  private converter: IShowdownConverter = ShowdownUtils.createShowdownConverter();\n  private subscriptionManager: SubscriptionManager;\n  private isAttached = false;\n\n  private annotationControl: AnnotationControl | null = null;\n\n  constructor(\n    element: Element,\n    subscriptionManagerService: SubscriptionManagerService,\n  ) {\n    this.domElement = element as HTMLElement;\n    this.subscriptionManager = subscriptionManagerService.createSubscriptionManager();\n  }\n\n  public attached(): void {\n    this.annotationControl?.remove();\n    this.annotationControl = null;\n    this.subscriptionManager.subscribeToElementResize(this.domElement, () => this.updateDom(true));\n    this.isAttached = true;\n    this.updateDom(true);\n  }\n\n  public detached(): void {\n    this.isAttached = false;\n    this.annotationControl?.remove();\n    this.annotationControl = null;\n    this.subscriptionManager.disposeSubscriptions();\n  }\n\n  private textChanged(): void {\n    if(this.isAttached) {\n      this.updateDom(true);\n    }\n  }\n\n  private updateDom(animate: boolean): void {\n    this.domElement.innerHTML = this.text ? this.converter.makeHtml(this.text) : '';\n    setTimeout(() => {\n      if(this.annotate) {\n        this.annotationControl?.remove();\n        this.annotationControl = ShowdownUtils.annotateMarkdown(this.domElement, animate);\n      }\n      DomUtils.fireEvent(this.domElement, {\n        name: 'markdown-rendered',\n      });\n    }, 0);\n  }\n}\n","import { PLATFORM } from 'aurelia-pal';\nimport { FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/methodpool/mp-fill-in-the-blank-input/mp-fill-in-the-blank-input'));\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/methodpool/mp-letter-input/mp-letter-input'));\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/methodpool/mp-interactive-text/mp-interactive-text'));\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/methodpool/mp-question/mp-question'));\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/methodpool/mp-rapid-fire-game/mp-rapid-fire-game'));\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/methodpool/mp-rapid-fire-game/mp-rapid-fire-game-button/mp-rapid-fire-game-button'));\n}\n","import { autoinject, bindable, computedFrom, PLATFORM, TaskQueue, useView } from 'aurelia-framework';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { fireMpInteractiveTextInputEvent, IMpInteractiveTextAnswer, IMpInteractiveTextInput } from '../mp-interactive-text/mp-interactive-text';\n\n@useView(PLATFORM.moduleName('./mp-fill-in-the-blank-input.html'))\n@autoinject\nexport class MpFillInTheBlankInput implements IMpInteractiveTextInput {\n  @bindable private data = '';\n  protected selected: IMpInteractiveTextAnswer | null = null;\n\n  protected focused = false;\n  protected enabled = true;\n\n  protected answerElement: HTMLElement | null = null;\n\n  @computedFrom('data')\n  protected get options(): Array<IMpInteractiveTextAnswer> {\n    const data = this.data.split(';');\n    if(this.sorted) data.shift();\n    return data.map((o, i) => ({ text: o, index: i }));\n  }\n\n  @computedFrom('selected', 'options')\n  protected get correct(): boolean {\n    return this.selected != null && this.selected.index === this.options[0].index;\n  }\n\n  @computedFrom('data')\n  protected get sorted(): boolean {\n    return this.data.split(';')[0] === '%SORTED%';\n  }\n\n  constructor(\n    private element: Element,\n    private taskQueue: TaskQueue,\n  ) { }\n\n  protected attached(): void {\n    // When working with enhanced views, sometimes attached is called before the element is inserted into the dom\n    // so let's wait one tick\n    this.taskQueue.queueTask(() => {\n      fireMpInteractiveTextInputEvent(this.element, 'mp-interactive-text-input-attached', {\n        source: this,\n      });\n    });\n  }\n\n  public focus(): void {\n    if(this.isCorrect() || !this.enabled) return;\n    fireMpInteractiveTextInputEvent(this.element, 'mp-interactive-text-input-focused', {\n      source: this,\n    });\n    this.focused = true;\n  }\n\n  public blur(): void {\n    this.focused = false;\n  }\n\n  public setEnabled(enabled: boolean): void {\n    this.enabled = enabled;\n  }\n\n  public setAnswer(answer: IMpInteractiveTextAnswer): void {\n    assertNotNullOrUndefined(this.answerElement, 'forgot to ref answerElement');\n\n    this.selected = answer;\n    fireMpInteractiveTextInputEvent(this.element, 'mp-interactive-text-input-answered', {\n      source: this,\n    });\n  }\n\n  public clear(): void {\n    this.selected = null;\n  }\n\n  public isCorrect(): boolean {\n    return this.correct;\n  }\n\n  public isAnswered(): boolean {\n    return this.selected != null;\n  }\n\n  public isMultiStep(): boolean {\n    return false;\n  }\n\n  public clearLast(): void {\n    this.clear();\n  }\n\n  public getOptions(): Array<IMpInteractiveTextAnswer> {\n    const clonedOptions = [...this.options];\n    return this.sorted\n      ? clonedOptions.sort((a, b) => a.text.localeCompare(b.text))\n      : ArrayUtils.shuffle(clonedOptions);\n  }\n}\n","import { autoinject, bindable, InlineViewStrategy, observable, PLATFORM, TaskQueue, useView } from 'aurelia-framework';\nimport { RichTextMode } from 'common/aurelia-components/rich-text/rich-text';\nimport { isLegacyMarkdown } from 'common/aurelia-components/text-editor/rich-text-utils';\nimport { IShowdownConverter, ShowdownUtils } from 'common/markdown/ShowdownUtils';\nimport { AnimationUtils } from 'common/utils/AnimationUtils';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { DomUtils } from 'common/utils/DomUtils';\n\n@useView(PLATFORM.moduleName('./mp-interactive-text.html'))\n@autoinject()\nexport class MpInteractiveText {\n  @bindable() public markdown: string | null | undefined = '';\n  @bindable() public landscapeMode = false;\n  @bindable() public isDesktopVersion = false;\n  @bindable() public allowWrongAnswers = false;\n  @bindable() public showHelp = true;\n\n  private textMode = RichTextMode.CONTENT;\n  private showdown: IShowdownConverter | null = null;\n  private isAttached = false;\n  private gameTemplate = '';\n  private markdownViewStrategy: InlineViewStrategy | null = null;\n  private gaps: Array<IMpInteractiveTextInput> = [];\n  @observable() protected activeGap: IMpInteractiveTextInput | null = null;\n  private completed = false;\n  private locked = false;\n  private currentAnswers: Array<IMpInteractiveTextAnswer> = [];\n\n  constructor(\n    private element: Element,\n    private taskQueue: TaskQueue,\n  ) { }\n\n  public restart(): void {\n    this.completed = false;\n    for(const gap of this.gaps) {\n      gap.clear();\n    }\n    this.gaps[0]?.focus();\n  }\n\n  protected attached(): void {\n    this.isAttached = true;\n\n    this.showdown = ShowdownUtils.createShowdownConverter(true);\n    this.markdownChanged();\n  }\n\n  protected detached(): void {\n    this.isAttached = false;\n\n    this.gameTemplate = '';\n    this.markdownViewStrategy = null;\n    this.gaps = [];\n    this.activeGap = null;\n    this.completed = false;\n    this.locked = false;\n    this.currentAnswers = [];\n  }\n\n  private markdownChanged(): void {\n    if(!this.isAttached) return;\n\n    assertNotNullOrUndefined(this.showdown, 'showdown cannot be null or undefined');\n    this.gaps = [];\n    this.markdownViewStrategy = null;\n    if(!this.markdown) return;\n    if(isLegacyMarkdown(this.markdown)) {\n      this.gameTemplate = this.showdown.makeHtml(this.markdown || '');\n      this.markdownViewStrategy = new InlineViewStrategy(`<template>${this.gameTemplate}<span attached-emitter></span></template>`);\n    }\n  }\n\n  private handleMarkerAttached(): void {\n    this.gaps[0]?.focus();\n    this.taskQueue.queueTask(() => {\n      ShowdownUtils.annotateMarkdown(this.element as HTMLElement, true);\n    });\n  }\n\n  private activeGapChanged(): void {\n    if(!this.activeGap) {\n      this.currentAnswers = [];\n      return;\n    }\n\n    this.currentAnswers = this.activeGap.getOptions();\n  }\n\n  private async handleAnswerSelected(answer: IMpInteractiveTextAnswer, event: CustomEvent): Promise<void> {\n    if(!this.activeGap) return;\n    this.activeGap.setAnswer(answer);\n    if(!this.activeGap.isAnswered()) return;\n\n    if(!this.allowWrongAnswers && !this.activeGap.isCorrect()) {\n      this.locked = true;\n      this.gaps.forEach(gap => gap.setEnabled(false));\n      await AnimationUtils.shake(event.target as HTMLElement);\n      this.gaps.forEach(gap => gap.setEnabled(true));\n      this.locked = false;\n      this.activeGap?.clear();\n      return;\n    }\n    const activeGapIndex = this.gaps.findIndex(gap => gap === this.activeGap);\n    this.blur();\n    for(let i = 1; i <= this.gaps.length; i++) {\n      const nextGap = this.gaps[(activeGapIndex + i) % this.gaps.length];\n      if(!nextGap.isAnswered()) {\n        nextGap.focus();\n        (event.target as HTMLButtonElement).blur();\n        break;\n      }\n    }\n  }\n\n  private handleMpGapAttachedEvent(event: CustomEvent<IMpInteractiveTextInputEvents['mp-interactive-text-input-attached']>): void {\n    const eventData = event.detail;\n    this.gaps.push(eventData.source);\n    if(!this.activeGap && !eventData.source.isAnswered()) {\n      eventData.source.focus();\n    }\n  }\n\n  private handleMpGapFocusedEvent(event: CustomEvent<IMpInteractiveTextInputEvents['mp-interactive-text-input-focused']>): void {\n    const eventData = event.detail;\n    this.activeGap = eventData.source;\n    for(const gap of this.gaps) {\n      if(gap !== eventData.source) gap.blur();\n    }\n  }\n\n  private async handleMpGapAnsweredEvent(event: CustomEvent<IMpInteractiveTextInputEvents['mp-interactive-text-input-answered']>): Promise<void> {\n    if(!this.allowWrongAnswers && !event.detail.source.isCorrect()) {\n      await AnimationUtils.shake(event.target as HTMLElement);\n    }\n    const allAnswered = this.gaps.every(gap => gap.isAnswered());\n    const allCorrect = this.gaps.every(gap => gap.isCorrect());\n    this.completed = this.allowWrongAnswers ? allAnswered : allCorrect;\n    if(this.completed) {\n      DomUtils.fireEvent<IMpGameFinishedEventDetail>(this.element, {\n        name: 'mp-game-finished',\n        detail: {\n          allCorrect,\n        },\n      });\n    }\n  }\n\n  private blur(): void {\n    this.activeGap = null;\n    for(const gap of this.gaps) {\n      gap.blur();\n    }\n  }\n\n  private clearLast(): void {\n    this.activeGap?.clearLast();\n  }\n}\n\nexport interface IMpInteractiveTextAnswer {\n  text: string;\n  index: number;\n  disabled?: boolean;\n}\n\nexport interface IMpInteractiveTextInput {\n  blur(): void;\n  focus(): void;\n  setAnswer(answer: IMpInteractiveTextAnswer): void;\n  setEnabled(enabled: boolean): void;\n  clear(): void;\n  clearLast(): void;\n  isCorrect(): boolean;\n  isAnswered(): boolean;\n  isMultiStep(): boolean;\n  getOptions(): Array<IMpInteractiveTextAnswer>;\n}\n\nexport function fireMpInteractiveTextInputEvent<K extends keyof IMpInteractiveTextInputEvents>(\n  element: Element,\n  eventName: K,\n  detail: IMpInteractiveTextInputEvents[K],\n): void {\n  const changeEvent = new CustomEvent(eventName, {\n    detail,\n    bubbles: true,\n  });\n  element.dispatchEvent(changeEvent);\n}\n\nexport interface IMpInteractiveTextInputEvents {\n  'mp-interactive-text-input-attached': {\n    source: IMpInteractiveTextInput;\n  };\n  'mp-interactive-text-input-focused': {\n    source: IMpInteractiveTextInput;\n  };\n  'mp-interactive-text-input-answered': {\n    source: IMpInteractiveTextInput;\n  };\n}\n\nexport interface IMpGameFinishedEventDetail {\n  allCorrect: boolean;\n}\n","import { autoinject, bindable, computedFrom, useView, PLATFORM, observable, TaskQueue } from 'aurelia-framework';\nimport { AnimationUtils } from 'common/utils/AnimationUtils';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { fireMpInteractiveTextInputEvent, IMpInteractiveTextInput, IMpInteractiveTextAnswer } from '../mp-interactive-text/mp-interactive-text';\n\n@useView(PLATFORM.moduleName('./mp-letter-input.html'))\n@autoinject\nexport class MpLetterInput implements IMpInteractiveTextInput {\n  @bindable private data = '';\n\n  protected focused = false;\n  protected enabled = true;\n\n  private userText = '';\n  private userAnsweres: IMpInteractiveTextAnswer[] = [];\n\n  @observable\n  private letters: Array<{ letter: string; el?: Element }> = [];\n\n  private options: Array<IMpInteractiveTextAnswer> = [];\n\n  @computedFrom('data', 'userText')\n  public get correct(): boolean {\n    return this.data.toLocaleLowerCase() === this.userText.toLocaleLowerCase();\n  }\n\n  constructor(\n    private taskQueue: TaskQueue,\n    private element: Element,\n  ) { }\n\n  public lettersChanged(): void {\n    this.options = this.letters.map((l, index) => ({\n      text: l.letter,\n      index,\n      disabled: false,\n    }));\n    this.userText = '';\n    this.userAnsweres = [];\n  }\n\n  protected attached(): void {\n    // When working with enhanced views, sometimes attached is called before the element is inserted into the dom\n    // so let's wait one tick\n    this.taskQueue.queueTask(() => {\n      fireMpInteractiveTextInputEvent(this.element, 'mp-interactive-text-input-attached', {\n        source: this,\n      });\n    });\n  }\n\n  protected dataChanged(): void {\n    this.letters = this.data.trim().toLocaleLowerCase().split('').map(letter => ({ letter }));\n  }\n\n  public focus(): void {\n    if(this.isCorrect() || !this.enabled) return;\n    fireMpInteractiveTextInputEvent(this.element, 'mp-interactive-text-input-focused', {\n      source: this,\n    });\n    this.focused = true;\n  }\n\n  public blur(): void {\n    this.focused = false;\n  }\n\n  public setAnswer(answer: IMpInteractiveTextAnswer): void {\n    if(this.isAnswered() || answer.disabled) return;\n    answer.disabled = true;\n    this.userAnsweres.push(answer);\n    this.userText += answer.text;\n    if(this.letters[this.userText.length - 1]?.el) {\n      AnimationUtils.stampIn(this.letters[this.userText.length - 1].el as HTMLElement);\n    }\n    if(this.isAnswered()) {\n      fireMpInteractiveTextInputEvent(this.element, 'mp-interactive-text-input-answered', {\n        source: this,\n      });\n    }\n  }\n\n  public clear(): void {\n    this.userText = '';\n    this.userAnsweres = [];\n    this.options.forEach(o => { o.disabled = false; });\n  }\n\n  public setEnabled(enabled: boolean): void {\n    this.enabled = enabled;\n  }\n\n  public isCorrect(): boolean {\n    return this.correct;\n  }\n\n  public isAnswered(): boolean {\n    return this.userText.length >= this.data.length;\n  }\n\n  public isMultiStep(): boolean {\n    return true;\n  }\n\n  public clearLast(): void {\n    this.userText = this.userText.slice(0, -1);\n    const last = this.userAnsweres.pop();\n    if(last) last.disabled = false;\n  }\n\n  public getOptions(): Array<IMpInteractiveTextAnswer> {\n    return ArrayUtils.shuffle(this.options);\n  }\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { IQuizQuestionDto } from 'common/dto/course/quiz/quiz.question.interface';\nimport { DomUtils } from 'common/utils/DomUtils';\nimport { QuestionUtils } from 'common/utils/QuestionUtils';\n\n/**\n * @event { MpQuestionAnsweredEvent } mp-question-answered\n */\n@useView(PLATFORM.moduleName('./mp-question.html'))\n@autoinject()\nexport class MpQuestion {\n  @bindable() public landscapeMode = false;\n  @bindable() public isDesktopVersion = false;\n  @bindable() public question: IQuizQuestionDto | null = null;\n  @bindable() public isAnswerSelected = false;\n\n  private element: HTMLElement;\n\n  private selectedAnswers: number[] = [];\n\n  constructor(element: Element) {\n    this.element = element as HTMLElement;\n  }\n\n  public evaluate(): void {\n    this.handleAnswerButtonClick();\n  }\n\n  private handleSelectedAnswersChanged(ev: CustomEvent<{ answers: number[] }>): void {\n    this.selectedAnswers = ev.detail.answers;\n    this.isAnswerSelected = this.selectedAnswers.length > 0 && this.selectedAnswers.every(a => a !== 0);\n  }\n\n  private handleAnswerButtonClick(): void {\n    if(!this.question) return;\n\n    DomUtils.fireEvent<MpQuestionAnsweredEvent['detail']>(this.element, {\n      name: 'mp-question-answered',\n      bubbles: false,\n      detail: {\n        answers: this.selectedAnswers,\n        correct: QuestionUtils.checkAnswersFromAnswerArray(this.question, this.selectedAnswers),\n      },\n    });\n  }\n}\n\nexport type MpQuestionAnsweredEvent = CustomEvent<{ answers: number[]; correct: boolean }>;\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { MDCRipple } from '@material/ripple';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { AnimationUtils } from 'common/utils/AnimationUtils';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./mp-rapid-fire-game-button.html'))\nexport class MpRapidFireGameButton {\n  @bindable() public category: string | null = null;\n  @bindable() public disabled = false;\n  private domElement: HTMLElement;\n  private domButtonElement: HTMLElement | null = null;\n  private ripple: MDCRipple | null = null;\n\n  constructor(element: Element) {\n    this.domElement = element as HTMLElement;\n  }\n\n  protected attached(): void {\n    assertNotNullOrUndefined(this.domButtonElement, 'forgot to ref domButtonElement');\n    this.ripple = new MDCRipple(this.domButtonElement);\n  }\n\n  protected detached(): void {\n    this.ripple?.destroy();\n  }\n\n  public flash(): void {\n    assertNotNullOrUndefined(this.domButtonElement, 'forgot to ref domButtonElement');\n    AnimationUtils.colorFlash(this.domButtonElement, { backgroundColor: 'var(--flash-correct)' });\n  }\n\n  public async shake(): Promise<void> {\n    assertNotNullOrUndefined(this.domButtonElement, 'forgot to ref domButtonElement');\n    await AnimationUtils.shake(this.domButtonElement, 1000);\n  }\n}\n","import { autoinject, bindable, computedFrom, PLATFORM, TaskQueue, useView } from 'aurelia-framework';\nimport { LottieAnimationPlayer } from 'common/aurelia-components/lottie-animation-player/lottie-animation-player';\nimport { IPictureDto } from 'common/dto/course/content/course.interface';\nimport { assertNotNullOrUndefined } from 'common/utils/assert';\nimport { DomUtils } from 'common/utils/DomUtils';\nimport countdownAnimation from '../../../animations/countdown.json';\nimport { ArrayUtils } from '../../../utils/ArrayUtils';\nimport { MpRapidFireGameButton } from './mp-rapid-fire-game-button/mp-rapid-fire-game-button';\n\nenum MpRapidFireGameState {\n  STARTING = 'starting',\n  RUNNING = 'running',\n  FINISHED = 'finished'\n}\n\n@autoinject()\n@useView(PLATFORM.moduleName('./mp-rapid-fire-game.html'))\nexport class MpRapidFireGame {\n  @bindable() public data: Array<IMpRapidFireGameEntry> = [];\n  @bindable() public duration = 15;\n  @bindable() public landscapeMode = false;\n  @bindable() public navPreview = false;\n\n  private countdownAnimation = countdownAnimation;\n  private countdownAnimationPlayer: LottieAnimationPlayer | null = null;\n  private buttonViewModels: MpRapidFireGameButton[] = [];\n\n  private currentGameEntry?: IMpRapidFireGameEntry;\n  private gameEntryStack: Array<IMpRapidFireGameEntry> = [];\n  private loadedEntries: IMpRapidFireGameEntry[] = [];\n\n  private categories: Array<string> = [];\n\n  private numIncorrect = 0;\n  private numCorrect = 0;\n\n  private disableAnswers = false;\n\n  private secondsLeft = this.duration;\n\n  private timer: number | undefined;\n  private asyncImageLoadInterval: number | undefined;\n\n  private MpRapidFireGameState = MpRapidFireGameState;\n  private state: MpRapidFireGameState = MpRapidFireGameState.STARTING;\n\n  constructor(\n    private element: Element,\n    private taskQueue: TaskQueue,\n  ) { }\n\n  protected attached(): void {\n    this.dataChanged();\n  }\n\n  protected detached(): void {\n    window.clearInterval(this.timer);\n    window.clearInterval(this.asyncImageLoadInterval);\n  }\n\n  private navPreviewChanged(): void {\n    if(this.navPreview) return;\n    this.dataChanged();\n  }\n\n  private dataChanged(): void {\n    if(!this.element.isConnected || this.navPreview) return;\n    this.categories = Array.from(new Set(this.data.map(c => c.category)));\n    this.prepareGame();\n    assertNotNullOrUndefined(this.countdownAnimationPlayer, 'forgot to ref countdownAnimationPlayer');\n    this.countdownAnimationPlayer.play();\n  }\n\n  private prepareGame(): void {\n    clearInterval(this.timer);\n    this.gameEntryStack = ArrayUtils.shuffle(this.data);\n    void this.loadImagesAsynchronously(this.gameEntryStack.slice().reverse());\n    this.currentGameEntry = this.gameEntryStack.pop();\n    this.numIncorrect = 0;\n    this.numCorrect = 0;\n    this.secondsLeft = this.duration;\n    this.disableAnswers = false;\n    this.state = MpRapidFireGameState.STARTING;\n    // For the outside world the countdown already counts as playing the game\n    DomUtils.fireEvent(this.element, {\n      name: 'mp-game-started',\n    });\n  }\n\n  /**\n   * Loading 70 x-pictures at once causes 70 SVGs to be parsed and prefixed, which surprisingly blocks the UI D:\n   * This attaches them one after the other to the DOM, giving the Thread time to breathe :)\n   * @param entries should be given in order of requirement\n   */\n  private loadImagesAsynchronously(entries: IMpRapidFireGameEntry[]): Promise<void> {\n    return new Promise<void>(resolve => {\n      window.clearInterval(this.asyncImageLoadInterval);\n      this.loadedEntries = [];\n      this.asyncImageLoadInterval = window.setInterval(() => {\n        if(this.loadedEntries.length >= entries.length) {\n          window.clearInterval(this.asyncImageLoadInterval);\n          resolve();\n        } else {\n          this.loadedEntries.push(entries[this.loadedEntries.length]);\n        }\n      }, 30);\n    });\n  }\n\n  private start(): void {\n    if(this.gameEntryStack.length === 0) {\n      this.state = MpRapidFireGameState.FINISHED;\n      return;\n    }\n    this.state = MpRapidFireGameState.RUNNING;\n    this.timer = window.setInterval(this.countdown.bind(this), 1000);\n  }\n\n  private async handleCategoryClick(category: string, index: number): Promise<void> {\n    if(this.disableAnswers) return;\n    if(category === this.currentGameEntry?.category) {\n      this.buttonViewModels[index]?.flash();\n      this.numCorrect++;\n      this.currentGameEntry = this.gameEntryStack.pop();\n      if(!this.currentGameEntry) {\n        this.finishGame();\n      }\n    } else {\n      this.disableAnswers = true;\n      this.numIncorrect++;\n      await this.buttonViewModels[index]?.shake();\n      this.disableAnswers = false;\n    }\n  }\n\n  private handleRestartClick(): void {\n    this.prepareGame();\n    // Queue task as a new animation player will be attached after the if.to-view is processed\n    this.taskQueue.queueTask(() => {\n      assertNotNullOrUndefined(this.countdownAnimationPlayer, 'forgot to ref countdownAnimationPlayer');\n      this.countdownAnimationPlayer.play();\n    });\n  }\n\n  private countdown(): void {\n    this.secondsLeft--;\n    if(this.secondsLeft <= 0) {\n      this.finishGame();\n    }\n  }\n\n  private finishGame(): void {\n    clearInterval(this.timer);\n    DomUtils.fireEvent(this.element, {\n      name: 'mp-game-finished',\n      detail: {\n        correct: this.numCorrect,\n      },\n    });\n    this.state = MpRapidFireGameState.FINISHED;\n  }\n\n  /**\n    * possible translations\n    * tk: timeout\n    * tk: restart\n    * tk: finished\n    * tk: finish\n    */\n  private processTranslation(translationKey: string): string {\n    return `common.mp-rapid-fire-game.${translationKey}`;\n  }\n\n  @computedFrom('currentGameEntry')\n  private get finishedTranslation(): string {\n    if(!this.currentGameEntry) {\n      return this.processTranslation('finish');\n    }\n    return this.processTranslation('timeout');\n  }\n}\n\nexport interface IMpRapidFireGameEntry {\n  category: string;\n  text?: string | null;\n  picture?: IPictureDto | null;\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/mp-hot-spot-drawer/mp-hot-spot-drawer'));\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { IMpHotSpotDto } from 'common/dto/content/methodpool/hot.spot.interface';\nimport { DomUtils } from 'common/utils/DomUtils';\n\nexport interface IPaginationDisplay { total: number; current: number }\n\n/**\n * @event {PreviousClickedEvent} previous-clicked\n * @event {NextClickedEvent} next-clicked\n * @event {CloseClickedEvent} close-clicked\n * @event {ShowDetailsClickedEvent} show-details-clicked\n */\n@autoinject()\n@useView(PLATFORM.moduleName('./mp-hot-spot-drawer.html'))\nexport class MpHotSpotDrawer {\n  @bindable() public hotSpots: IMpHotSpotDto[] = [];\n  @bindable() public selectedHotSpot: IMpHotSpotDto | null = null;\n  @bindable() public paginationDisplay: IPaginationDisplay = { total: 0, current: 1 };\n  private domElement: HTMLElement;\n\n  constructor(element: Element) {\n    this.domElement = element as HTMLElement;\n  }\n\n  private handleShowDetailsClicked(): void {\n    DomUtils.fireEvent(this.domElement, {\n      bubbles: false,\n      name: 'show-details-clicked',\n    });\n  }\n\n  private handleCloseClick(): void {\n    DomUtils.fireEvent(this.domElement, {\n      bubbles: false,\n      name: 'close-clicked',\n    });\n  }\n\n  private handlePreviousClick(): void {\n    DomUtils.fireEvent(this.domElement, {\n      bubbles: false,\n      name: 'previous-clicked',\n    });\n  }\n\n  private handleNextClick(): void {\n    DomUtils.fireEvent(this.domElement, {\n      bubbles: false,\n      name: 'next-clicked',\n    });\n  }\n}\n\nexport type PreviousClickedEvent = CustomEvent<never>;\nexport type NextClickedEvent = CustomEvent<never>;\nexport type CloseClickedEvent = CustomEvent<never>;\nexport type ShowDetailsClickedEvent = CustomEvent<never>;","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/mp-landscape-header/mp-landscape-header'));\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./mp-landscape-header.html'))\nexport class MpLandscapeHeader {\n  @bindable() public titleTk: string | null = null;\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/mp-tile/mp-tile'));\n}\n","import { MDCRipple } from '@material/ripple';\nimport { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { AudioServiceButton } from 'common/aurelia-components/audio-service-button/audio-service-button';\nimport { IMpTileDto } from 'common/dto/course/content/block.interface';\n\nexport enum TileSize {\n  Big = 'big',\n  Small = 'small',\n}\n\n@autoinject\n@useView(PLATFORM.moduleName('./mp-tile.html'))\nexport class MpTile {\n  @bindable private tile: IMpTileDto | null = null;\n  @bindable private size: TileSize = TileSize.Small;\n  private audioServiceButton: AudioServiceButton | null = null;\n  private audioButtonHighlighted = false;\n  private domElement: HTMLElement;\n  private ripple: MDCRipple | null = null;\n\n  constructor(element: Element) {\n    this.domElement = element as HTMLElement;\n  }\n\n  protected attached(): void {\n    this.ripple = new MDCRipple(this.domElement);\n  }\n\n  protected detached(): void {\n    this.ripple?.destroy();\n  }\n\n  private togglePlay(): void {\n    if(this.audioServiceButton) {\n      this.audioServiceButton.togglePlay();\n    }\n  }\n\n  private setAudioButtonHighlighted(highlighted: boolean): void {\n    this.audioButtonHighlighted = highlighted;\n  }\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/mp-tiles-preview/mp-tiles-preview'));\n}\n","import { autoinject, bindable, PLATFORM, useView } from 'aurelia-framework';\nimport { SubscriptionManager, SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\nimport { IMpTileDto } from 'common/dto/course/content/block.interface';\n\nexport const DEFAULT_TILE_WIDTH = 144;\nexport const DEFAULT_TILE_HEIGHT = 221;\n\n@useView(PLATFORM.moduleName('./mp-tiles-preview.html'))\n@autoinject()\nexport class MpTilesPreview {\n  @bindable() public tiles: Array<IMpTileDto> = [];\n  private isAttached = false;\n  private subscriptionManager: SubscriptionManager;\n  private domElement: HTMLElement;\n  private DEFAULT_ASPECT_RATIO = DEFAULT_TILE_WIDTH / DEFAULT_TILE_HEIGHT;\n  private MAX_TILES_PER_ROW = 4;\n  private scaleFactor = 1;\n  private heightPerTile = 0;\n  private widthPerTile = 0;\n\n  constructor(\n    element: Element,\n    subscriptionManagerService: SubscriptionManagerService,\n  ) {\n    this.domElement = element as HTMLElement;\n    this.subscriptionManager = subscriptionManagerService.createSubscriptionManager();\n  }\n\n  protected attached(): void {\n    this.isAttached = true;\n    this.updateScaleFactor();\n    this.subscribeToChanges();\n  }\n\n  protected detached(): void {\n    this.isAttached = false;\n    this.subscriptionManager.disposeSubscriptions();\n  }\n\n  private subscribeToChanges(): void {\n    if(!this.isAttached) return;\n    this.subscriptionManager.disposeSubscriptions();\n    this.subscriptionManager.subscribeToCollectionChange(this.tiles, () => this.updateScaleFactor());\n    this.subscriptionManager.subscribeToElementResize(this.domElement, () => this.updateScaleFactor());\n  }\n\n  private updateScaleFactor(): void {\n    const width = parseFloat(window.getComputedStyle(this.domElement).width);\n    const maxHeight = parseFloat(window.getComputedStyle(this.domElement).height);\n    this.widthPerTile = width / Math.min(this.tiles.length, this.MAX_TILES_PER_ROW);\n    this.heightPerTile = this.widthPerTile / this.DEFAULT_ASPECT_RATIO;\n    if(this.heightPerTile >= maxHeight) {\n      this.widthPerTile = maxHeight * this.DEFAULT_ASPECT_RATIO;\n      this.heightPerTile = maxHeight;\n    }\n    if(this.tiles.length > this.MAX_TILES_PER_ROW) {\n      const rowCount = Math.ceil(this.tiles.length / this.MAX_TILES_PER_ROW);\n      const maxRowHeight = maxHeight / rowCount;\n      this.widthPerTile = maxRowHeight * this.DEFAULT_ASPECT_RATIO;\n      this.heightPerTile = maxRowHeight;\n    }\n    this.scaleFactor = this.widthPerTile / DEFAULT_TILE_WIDTH;\n  }\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/multi-donut-chart/multi-donut-chart'));\n}\n","import { bindable, autoinject, PLATFORM, useView } from 'aurelia-framework';\nimport { IdGeneratorService } from 'common/aurelia-services/IdGeneratorService';\nimport { SiteThemer, ThemeColorType, themeSubColors } from 'common/aurelia-classes/SiteThemer';\nimport { ITenantTheme } from 'common/dto/tenant/detail/tenant.detail.interface';\n\n@autoinject()\n@useView(PLATFORM.moduleName('./multi-donut-chart.html'))\nexport class MultiDonutChart {\n  @bindable() public values: number[] = [];\n  @bindable() public colors: ThemeColorType[] = [];\n  @bindable() public maxStrokeWidth = 30;\n  @bindable() public tenantTheme: ITenantTheme | null = null;\n\n  private centerDiameter = 30;\n  private diameter = 230;\n  private strokeWidth = this.maxStrokeWidth;\n  private gap = 5;\n  private ThemeColorType = ThemeColorType;\n  private themeColorTypes = Object.values(ThemeColorType);\n\n  private gradientIds: Record<string, number>;\n  private donuts: IDonutParameters[] = [];\n\n  constructor(\n    private siteThemer: SiteThemer,\n    idGenerator: IdGeneratorService,\n  ) {\n    this.gradientIds = {\n      [ThemeColorType.Primary]: idGenerator.getId(),\n      [ThemeColorType.Secondary1]: idGenerator.getId(),\n      [ThemeColorType.Secondary2]: idGenerator.getId(),\n      [ThemeColorType.Secondary3]: idGenerator.getId(),\n      [ThemeColorType.Testexam]: idGenerator.getId(),\n      [ThemeColorType.MultiCourse]: idGenerator.getId(),\n    };\n  }\n\n  private valuesChanged(): void {\n    this.updateDonuts();\n  }\n\n  private colorsChanged(): void {\n    this.updateDonuts();\n  }\n\n  private updateDonuts(): void {\n    this.strokeWidth = Math.min(this.maxStrokeWidth, (this.diameter - this.centerDiameter) / 2 / this.values.length - this.gap);\n    this.donuts = this.values.map((v, i) => this.getDonutParameters(v, i));\n  }\n\n  private getDonutParameters(value: number, index: number): IDonutParameters {\n    const outerRadius = (this.diameter / 2) - index * (this.strokeWidth + this.gap);\n    const radius = outerRadius - this.strokeWidth / 2;\n    const circumference = Math.ceil(2 * radius * Math.PI);\n    const frontCircumference = circumference * (1 - value / 100);\n    const color = this.colors[index % this.colors.length] || ThemeColorType.Primary;\n\n    return {\n      circumference,\n      color,\n      frontCircumference,\n      outerRadius,\n      radius,\n    };\n  }\n\n  private getGradientStartStyle(color: ThemeColorType): Record<string, string> {\n    const themeColor = this.getColorFromTenantTheme(color);\n    if(!themeColor) return {};\n    return {\n      '--multi-donut-chart-gradient-start-stop-color': themeColor,\n    };\n  }\n\n  private getGradientEndStyle(color: ThemeColorType): Record<string, string> {\n    const themeColor = this.getColorFromTenantTheme(color);\n    const adjustment = themeSubColors.find(sC => sC.name === '400');\n    if(!themeColor || !adjustment) return {};\n    return {\n      '--multi-donut-chart-gradient-end-stop-color': this.siteThemer.adjustColorBrightness(themeColor, adjustment.adjustValue, false, adjustment.transparency),\n    };\n  }\n\n  private getBackStrokeStyle(color: ThemeColorType): Record<string, string> {\n    const themeColor = this.getColorFromTenantTheme(color);\n    const adjustment = themeSubColors.find(sC => sC.name === 'semi-transparent');\n    if(!themeColor || !adjustment) return {};\n    return {\n      '--multi-donut-chart-circle-back-stroke': this.siteThemer.adjustColorBrightness(themeColor, adjustment.adjustValue, false, adjustment.transparency),\n    };\n  }\n\n  private getColorFromTenantTheme(color: ThemeColorType): string | null {\n    let themeColor: string | null = null;\n    if(!this.tenantTheme) return themeColor;\n    switch(color) {\n      case (ThemeColorType.Primary):\n        themeColor = this.siteThemer.getThemeColor(this.tenantTheme.primaryColor);\n        break;\n      case (ThemeColorType.Secondary1):\n        themeColor = this.siteThemer.getThemeColor(this.tenantTheme.secondaryColor1);\n        break;\n      case (ThemeColorType.Secondary2):\n        themeColor = this.siteThemer.getThemeColor(this.tenantTheme.secondaryColor2);\n        break;\n      case (ThemeColorType.Secondary3):\n        themeColor = this.siteThemer.getThemeColor(this.tenantTheme.secondaryColor3);\n        break;\n      default: return null;\n    }\n    return themeColor;\n  }\n}\n\nexport interface IDonutParameters {\n  circumference: number;\n  color: ThemeColorType;\n  frontCircumference: number;\n  outerRadius: number;\n  radius: number;\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/navigation-slider/navigation-slider'));\n}\n","import { bindable, computedFrom, PLATFORM, useView } from 'aurelia-framework';\nimport { ThemeColorType } from 'common/aurelia-classes/SiteThemer';\nimport { AnimationUtils } from 'common/utils/AnimationUtils';\nimport { MathUtils } from 'common/utils/MathUtils';\n\n@useView(PLATFORM.moduleName('./navigation-slider.html'))\nexport class NavigationSlider {\n  @bindable() public min = 0;\n  @bindable() public max = 100;\n  @bindable() public value = 0;\n  @bindable() public color: ThemeColorType = ThemeColorType.Primary;\n\n  private element: HTMLElement;\n  private animationHandle: { cancel: () => void } | null = null;\n  private pinTimer: NodeJS.Timeout | null = null;\n\n  private displayedValue = 0;\n  private pinActive = false;\n\n  constructor(element: Element) {\n    this.element = element as HTMLElement;\n  }\n\n  private detached(): void {\n    this.cancelInterpolation();\n    this.cancelPinTimer();\n    this.pinActive = false;\n  }\n\n  @computedFrom('displayedValue', 'max', 'min')\n  private get navigationSliderStyle(): Record<string, string> {\n    return {\n      '--navigation-slider-progress': `${(MathUtils.clamp(this.displayedValue, this.min, this.max) - this.min) * 100 / (this.max - this.min)}`,\n      '--navigation-slider-final-progress': `${MathUtils.clamp(this.displayedValue - this.max, 0, 1)}`,\n    };\n  }\n\n  @computedFrom('displayedValue')\n  private get pinLabel(): number {\n    return Math.round(this.displayedValue);\n  }\n\n  private valueChanged(): void {\n    this.cancelPinTimer();\n    this.pinActive = true;\n\n    this.startInterpolation();\n  }\n\n  private startInterpolation(): void {\n    // Keep using this interpolation animation while it's still playing\n    if(this.animationHandle || !this.element.isConnected) return;\n\n    const EPSILON = 0.01;\n    const LERP_SPEED = 0.002;\n\n    this.animationHandle = AnimationUtils.setAnimationFrameInterval((_, deltaMs) => {\n      if(Math.abs(this.displayedValue - this.value) < EPSILON) {\n        this.displayedValue = this.value;\n        this.cancelInterpolation();\n        this.pinTimer = setTimeout(() => { this.pinActive = false; }, 1000);\n      } else {\n        this.displayedValue = MathUtils.lerp(this.displayedValue, this.value, LERP_SPEED, deltaMs);\n      }\n    });\n  }\n\n  private cancelInterpolation(): void {\n    this.animationHandle?.cancel();\n    this.animationHandle = null;\n  }\n\n  private cancelPinTimer(): void {\n    if(this.pinTimer) clearTimeout(this.pinTimer);\n  }\n}\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/password-strength-indicator/password-strength-indicator'));\n}\n","import zxcvbn from '@zxcvbn-ts/core';\r\nimport { OptionsType } from '@zxcvbn-ts/core/dist/types';\r\nimport { bindable, computedFrom, PLATFORM, useView } from 'aurelia-framework';\r\n\r\n/**\r\n * Lazy load dictionaries as they are quite large\r\n * @see https://zxcvbn-ts.github.io/zxcvbn/guide/LazyLoading/#webpack\r\n */\r\nconst loadOptions = async (): Promise<OptionsType> => {\r\n  const zxcvbnCommonPackage = await import(\r\n    /* webpackChunkName: \"zxcvbnCommonPackage\" */ '@zxcvbn-ts/language-common'\r\n  );\r\n  const zxcvbnEnPackage = await import(\r\n    /* webpackChunkName: \"zxcvbnEnPackage\" */ '@zxcvbn-ts/language-en'\r\n  );\r\n  const zxcvbnDePackage = await import(\r\n    /* webpackChunkName: \"zxcvbnDePackage\" */ '@zxcvbn-ts/language-de'\r\n  );\r\n  return {\r\n    dictionary: {\r\n      ...zxcvbnCommonPackage.default.dictionary,\r\n      ...zxcvbnEnPackage.default.dictionary,\r\n      ...zxcvbnDePackage.default.dictionary,\r\n    },\r\n    translations: zxcvbnDePackage.default.translations,\r\n  };\r\n};\r\n\r\n@useView(PLATFORM.moduleName('./password-strength-indicator.html'))\r\nexport class PasswordStrengthIndicator {\r\n  @bindable\r\n  public password = '';\r\n  @bindable\r\n  public strength = 0;\r\n  @bindable\r\n  public requiredStrength = 0;\r\n\r\n  protected suggestions: Array<string> = [];\r\n  protected warning = '';\r\n\r\n  protected async passwordChanged(): Promise<void> {\r\n    const options = await loadOptions();\r\n    const analysis = this.password ? zxcvbn(this.password, options) : null;\r\n    if(!analysis) {\r\n      this.strength = 0;\r\n      this.warning = '';\r\n      this.suggestions = [];\r\n      return;\r\n    }\r\n    this.strength = analysis.score;\r\n    this.suggestions = analysis.feedback.suggestions;\r\n    this.warning = analysis.feedback.warning;\r\n  }\r\n\r\n  @computedFrom('strength')\r\n  protected get indicatorColor(): string {\r\n    switch(this.strength) {\r\n      case 2: return '#f5a53d';\r\n      case 3: return '#0078F5';\r\n      case 4: return '#43C18A';\r\n      default: return '#D92D20';\r\n    }\r\n  }\r\n\r\n  @computedFrom('strength')\r\n  protected get strengthLabel(): string {\r\n    switch(this.strength) {\r\n      case 2: return 'medium';\r\n      case 3: return 'good';\r\n      case 4: return 'excellent';\r\n      default: return 'poor';\r\n    }\r\n  }\r\n\r\n}\r\n","import { PLATFORM, FrameworkConfiguration } from 'aurelia-framework';\n\nexport function configure(config: FrameworkConfiguration): void {\n  config.globalResources(PLATFORM.moduleName('common/aurelia-components/picture-puzzle/picture-puzzle'));\n}\n","import {\n  autoinject,\n  bindable,\n  computedFrom,\n  PLATFORM,\n  useView,\n} from 'aurelia-framework';\nimport { IQuizQuestionDto } from 'common/dto/course/quiz/quiz.question.interface';\nimport { QuestionTheme } from 'common/enum/question-theme.enum';\nimport { ResponsivenessMode } from 'common/enum/responsiveness-mode.enum';\nimport { DomUtils } from 'common/utils/DomUtils';\n\ninterface IPicturePuzzleOption {\n  answerId: number;\n  buttonId: string;\n  text: string;\n  dataTestSelector: string;\n  pictureUrl?: string;\n  isCorrect?: boolean;\n  rectangle: {\n    left: number;\n    top: number;\n    width: number;\n    height: number;\n  };\n}\n/**\n * @event {MCAnswerChangedEvent} mc-answer-changed\n *\n * css variables:\n * |name|description|\n * |----|-----------|\n * |--picture-puzzle-scale-factor|scaling factor passed through to buttons|\n */\n@autoinject()\n@useView(PLATFORM.moduleName('./picture-puzzle.html'))\nexport class PicturePuzzle {\n  @bindable() public question: IQuizQuestionDto | null = null;\n  @bindable() public theme: QuestionTheme = QuestionTheme.Exam;\n  @bindable() public responsiveness = ResponsivenessMode.Auto;\n  @bindable() public disabled = false;\n  @bindable() public selectedAnswers: number[] = [];\n  @bindable() public revealAnswer = false;\n  @bindable() public readonly = false;\n\n  private element: HTMLElement;\n\n  constructor(element: Element) {\n    this.element = element as HTMLElement;\n  }\n\n  @computedFrom('question')\n  public get answerOptions(): IPicturePuzzleOption[] {\n    const answers = this.question?.answers[0];\n    if(!answers) return [];\n    return [\n      this.buildAnswer(1, answers.text1, answers.pictureUrl1, answers.isCorrect1),\n      this.buildAnswer(2, answers.text2, answers.pictureUrl2, answers.isCorrect2),\n      this.buildAnswer(3, answers.text3, answers.pictureUrl3, answers.isCorrect3),\n      this.buildAnswer(4, answers.text4, answers.pictureUrl4, answers.isCorrect4),\n    ];\n  }\n\n  private buildAnswer(\n    answerId: number,\n    text: string,\n    pictureUrl: string | null | undefined,\n    isCorrect: boolean | undefined,\n  ): IPicturePuzzleOption {\n    const rectangleValues = text.split(',').map(n => parseInt(n, 10));\n\n    return {\n      answerId,\n      buttonId: `answer${answerId}`,\n      text,\n      dataTestSelector: `testexam-answer${answerId}`,\n      pictureUrl: pictureUrl ?? undefined,\n      isCorrect,\n      rectangle: {\n        left: rectangleValues[0],\n        top: rectangleValues[1],\n        width: rectangleValues[2],\n        height: rectangleValues[3],\n      },\n    };\n  }\n\n  private isSelected(answerId: number, selectedAnswers: number[]): boolean {\n    return selectedAnswers.includes(answerId);\n  }\n\n  private getClickZoneStyle(option: IPicturePuzzleOption): Record<string, string> {\n    const imageWidth = 1920;\n    const imageHeight = 1080;\n    return {\n      left: `${(option.rectangle.left * 100) / imageWidth}%`,\n      top: `${(option.rectangle.top * 100) / imageHeight}%`,\n      width: `${(option.rectangle.width * 100) / imageWidth}%`,\n      height: `${(option.rectangle.height * 100) / imageHeight}%`,\n    };\n  }\n\n  private handleClickZoneClicked(answer: IPicturePuzzleOption): void {\n    if(this.disabled || this.revealAnswer) return;\n\n    DomUtils.fireEvent<MCAnswerChangeEvent['detail']>(this.element, {\n      name: 'mc-answer-changed',\n      bubbles: true,\n      detail: {\n        answer: answer.answerId,\n        selected: !this.isSelected(answer.answerId, this.selectedAnswers),\n      },\n    });\n  }\n\n  private getClickZoneRevealClass(option: IPicturePuzzleOption, revealed: boolean, selectedAnswers: number[]): string {\n    if(!revealed) {\n      return '';\n    }\n\n    return [\n      option.isCorrect ? 'picture-puzzle__click-zone--correct' : 'picture-puzzle__click-zone--wrong',\n      this.isSelected(option.answerId, selectedAnswers) ? 'picture-puzzle__click-zone--selected' : '',\n    ].join(' ');\n  }\n}\n\nexport type MCAnswerChangeEvent = Event & { detail: { answer: number; selected: boolean } };\n"],"names":[],"sourceRoot":""}