diff --git a/bemuse/package.json b/bemuse/package.json index 6296bfdc3..ab413e42a 100644 --- a/bemuse/package.json +++ b/bemuse/package.json @@ -32,6 +32,7 @@ "@types/chai": "^4.2.0", "@types/eslint": "^4.16.4", "@types/invariant": "^2.2.30", + "@types/jquery": "^3.5.16", "@types/lodash": "^4.14.176", "@types/markdown-it": "^12.2.3", "@types/minimatch": "^3.0.3", @@ -177,7 +178,7 @@ "redux": "^4.2.0", "reselect": "^4.1.7", "rxjs": "^7.8.0", - "screenfull": "^3.3.3", + "screenfull": "^6.0.2", "throat": "^2.0.2", "timesynchro": "^1.0.1", "variance": "0.0.1", diff --git a/bemuse/src/game/display/Gauge.js b/bemuse/src/game/display/Gauge.ts similarity index 68% rename from bemuse/src/game/display/Gauge.js rename to bemuse/src/game/display/Gauge.ts index 700d96be8..728f5e065 100644 --- a/bemuse/src/game/display/Gauge.js +++ b/bemuse/src/game/display/Gauge.ts @@ -1,11 +1,23 @@ -export function getGauge(gaugeType) { +import PlayerState from '../state/player-state' + +export interface Gauge { + update(playerState: PlayerState): void + shouldDisplay(): boolean + getPrimary(): number + getSecondary(): number + getExtra(): number +} + +export type GaugeType = 'hope' | 'off' + +export function getGauge(gaugeType: GaugeType): Gauge { if (gaugeType === 'hope') { return hopeGauge() } return nullGauge() } -function nullGauge() { +function nullGauge(): Gauge { return { update() {}, shouldDisplay() { @@ -23,15 +35,15 @@ function nullGauge() { } } -function hopeGauge() { - let primary - let secondary - let extra +function hopeGauge(): Gauge { + let primary: number + let secondary: number + let extra: number return { update(playerState) { const stats = playerState.stats const progress = stats.numJudgments / stats.totalCombo - const getHope = (min, max1, max2) => { + const getHope = (min: number, max1: number, max2: number) => { const max = max1 + (max2 - max1) * progress const maxPossibleScore = stats.maxPossibleScore return Math.max(0, (maxPossibleScore - min) / (max - min)) diff --git a/bemuse/src/game/display/index.js b/bemuse/src/game/display/index.tsx similarity index 55% rename from bemuse/src/game/display/index.js rename to bemuse/src/game/display/index.tsx index 3c6c50e79..d4a1f5ec1 100644 --- a/bemuse/src/game/display/index.js +++ b/bemuse/src/game/display/index.tsx @@ -1,14 +1,37 @@ import './game-display.scss' import $ from 'jquery' - +import { Context } from 'bemuse/scintillator' +import Game from '../game' +import GameState from '../state' +import { InfoPanelPosition } from 'bemuse/scintillator/skin' +import { LoadImagePromise } from '../loaders/loadImage' +import { PanelPlacement } from 'bemuse/app/entities/Options' +import Player from '../player' import PlayerDisplay from './player-display' +import React from 'react' +import { createRoot } from 'react-dom/client' import formatTime from '../../utils/formatTime' -import { shouldDisableFullScreen } from 'bemuse/devtools/query-flags' import screenfull from 'screenfull' +import { shouldDisableFullScreen } from 'bemuse/devtools/query-flags' + +export interface Video { + element: HTMLVideoElement + offset: number +} export class GameDisplay { - constructor({ game, context, backgroundImagePromise, video }) { + constructor({ + game, + context, + backgroundImagePromise, + video, + }: { + game: Game + context: Context + backgroundImagePromise: LoadImagePromise + video: Video | null + }) { this._game = game this._context = context const skinData = context.skinData @@ -30,11 +53,31 @@ export class GameDisplay { this._escapeHintShown = false } - setEscapeHandler(escapeHandler) { + private _game: Game + private _context: Context + private _players: Map + private _stateful: Record + + private _wrapper: HTMLElement + + private _escapeHintShown: boolean + private _escapeHint: HTMLDivElement | undefined + + private _onEscape: () => void = () => {} + private _onReplay: () => void = () => {} + + private _started: number = 0 + private _duration: number = 0 + + private _video: HTMLVideoElement | undefined + private _videoStarted: boolean | undefined + private _videoOffset: number = 0 + + setEscapeHandler(escapeHandler: () => void) { this._onEscape = escapeHandler } - setReplayHandler(replayHandler) { + setReplayHandler(replayHandler: () => void) { this._onReplay = replayHandler } @@ -52,16 +95,16 @@ export class GameDisplay { this._context.destroy() } - update(gameTime, gameState) { + update(gameTime: number, gameState: GameState) { const time = (new Date().getTime() - this._started) / 1000 const data = this._getData(time, gameTime, gameState) - this._updateStatefulData(time, gameTime, gameState) + this._updateStatefulData(time, gameState) this._context.render(Object.assign({}, this._stateful, data)) this._synchronizeVideo(gameTime) this._synchronizeTutorialEscapeHint(gameTime) } - _synchronizeVideo(gameTime) { + private _synchronizeVideo(gameTime: number) { if (this._video && !this._videoStarted && gameTime >= this._videoOffset) { this._video.volume = 0 this._video.play() @@ -70,7 +113,7 @@ export class GameDisplay { } } - _synchronizeTutorialEscapeHint(gameTime) { + private _synchronizeTutorialEscapeHint(gameTime: number) { if (this._game.options.tutorial) { const TUTORIAL_ESCAPE_HINT_SHOW_TIME = 101.123595506 if ( @@ -78,18 +121,23 @@ export class GameDisplay { !this._escapeHintShown ) { this._escapeHintShown = true - this._escapeHint.classList.add('is-shown') + this._escapeHint?.classList.add('is-shown') } } } - _getData(time, gameTime, gameState) { - const data = {} - data['tutorial'] = this._game.options.tutorial ? 'yes' : 'no' - data['t'] = time - data['gameTime'] = gameTime - data['ready'] = this._getReady(gameState) - data['song_time'] = this._getSongTime(gameTime) + private _getData( + time: number, + gameTime: number, + gameState: GameState + ): Record { + const data: Record = { + tutorial: this._game.options.tutorial ? 'yes' : 'no', + t: time, + gameTime: gameTime, + ready: this._getReady(gameState), + song_time: this._getSongTime(gameTime), + } for (const [player, playerDisplay] of this._players) { const playerState = gameState.player(player) const playerData = playerDisplay.update(time, gameTime, playerState) @@ -100,7 +148,7 @@ export class GameDisplay { return data } - _updateStatefulData(time, gameTime, gameState) { + private _updateStatefulData(time: number, gameState: GameState) { const data = this._stateful if (data['started'] === undefined && gameState.started) { data['started'] = time @@ -110,7 +158,7 @@ export class GameDisplay { } } - _getSongTime(gameTime) { + private _getSongTime(gameTime: number) { return ( formatTime(Math.min(this._duration, Math.max(0, gameTime))) + ' / ' + @@ -118,16 +166,21 @@ export class GameDisplay { ) } - _getReady(gameState) { + private _getReady(gameState: GameState) { const f = gameState.readyFraction return f > 0.5 ? Math.pow(1 - (f - 0.5) / 0.5, 2) : 0 } - _createWrapper({ + private _createWrapper({ backgroundImagePromise, video, panelPlacement, infoPanelPosition, + }: { + backgroundImagePromise: LoadImagePromise + video: Video | null + panelPlacement: PanelPlacement + infoPanelPosition: InfoPanelPosition }) { const $wrapper = $('
') .attr('data-panel-placement', panelPlacement) @@ -147,40 +200,42 @@ export class GameDisplay { return $wrapper[0] } - _createTouchEscapeButton() { + private _createTouchEscapeButton() { const touchButtons = document.createElement('div') - touchButtons.className = 'game-display--touch-buttons is-left' + touchButtons.className = 'game-display--touch-buttons is-left is-visible' this.wrapper.appendChild(touchButtons) - touchButtons.classList.add('is-visible') - const addTouchButton = (className, onClick) => { - const button = createTouchButton(onClick, className) - touchButtons.appendChild(button) - } - addTouchButton('game-display--touch-escape-button', () => this._onEscape()) - addTouchButton('game-display--touch-replay-button', () => this._onReplay()) - - const escapeHint = document.createElement('div') - escapeHint.textContent = 'Click or press Esc to exit the tutorial' - escapeHint.className = 'game-display--escape-hint' - this._escapeHint = escapeHint - touchButtons.appendChild(escapeHint) + createRoot(touchButtons).render( + <> + this._onEscape()} + /> + this._onReplay()} + /> +
+ Click or press Esc to exit the tutorial +
+ + ) } - _createFullScreenButton() { - if (shouldDisableFullScreen() || !screenfull.enabled) { + private _createFullScreenButton() { + if (shouldDisableFullScreen() || !screenfull.isEnabled) { return } const touchButtons = document.createElement('div') touchButtons.className = 'game-display--touch-buttons is-visible is-right' this.wrapper.appendChild(touchButtons) - const onClick = () => { - screenfull.request() - } - const button = createTouchButton( - onClick, - 'game-display--touch-fullscreen-button' + createRoot(touchButtons).render( + { + screenfull.request() + }} + /> ) - touchButtons.appendChild(button) } get context() { @@ -196,21 +251,29 @@ export class GameDisplay { } } -function createTouchButton(onClick, className) { - const button = document.createElement('button') - button.addEventListener( - 'touchstart', - (e) => { - e.stopPropagation() - }, - true +function TouchButton({ + className, + onClick, + children, +}: { + className: string + onClick: () => void + children?: ReactNode +}) { + return ( + ) - button.onclick = (e) => { - e.preventDefault() - onClick() - } - button.className = className - return button } export default GameDisplay diff --git a/bemuse/src/game/display/note-area.js b/bemuse/src/game/display/note-area.ts similarity index 53% rename from bemuse/src/game/display/note-area.js rename to bemuse/src/game/display/note-area.ts index 0ac951d39..17a48b3bd 100644 --- a/bemuse/src/game/display/note-area.js +++ b/bemuse/src/game/display/note-area.ts @@ -1,25 +1,39 @@ +import { GameEvent, GameNote } from 'bemuse-notechart' + import _ from 'lodash' +export interface VisibleNote { + note: GameNote + y: number + height?: number +} + +export interface VisibleBarLine { + id: number + y: number +} + export class NoteArea { - constructor(notes, barLines) { + constructor(notes: readonly GameNote[], barLines: readonly GameEvent[]) { this._notes = _.sortBy(notes, position) this._barLines = _(barLines).map('position').sortBy().value() } - getVisibleNotes(lower, upper, headroom) { + private _notes: GameNote[] + private _barLines: number[] + + getVisibleNotes(lower: number, upper: number, headroom = 0): VisibleNote[] { const out = [] - const notes = this._notes - if (!headroom) headroom = 0 - for (let i = 0; i < notes.length; i++) { - const note = notes[i] + for (const note of this._notes) { const visible = note.end ? !(note.position > upper || note.end.position < lower - headroom) : !(note.position > upper || note.position < lower - headroom) if (visible) { - const entity = { note: note } - if (!note.end) { - entity.y = y(lower, upper, note.position) - } else { + const entity: VisibleNote = { + note: note, + y: y(lower, upper, note.position), + } + if (note.end) { const head = y(lower, upper, note.position) const tail = y(lower, upper, note.end.position) entity.y = Math.min(head, tail) @@ -31,8 +45,11 @@ export class NoteArea { return out } - getVisibleBarLines(lower, upper, headroom) { - if (!headroom) headroom = 0 + getVisibleBarLines( + lower: number, + upper: number, + headroom = 0 + ): VisibleBarLine[] { return this._barLines .filter((pos) => lower - headroom <= pos && pos <= upper) .map((pos) => ({ id: pos, y: y(lower, upper, pos) })) @@ -41,10 +58,10 @@ export class NoteArea { export default NoteArea -function y(lower, upper, pos) { +function y(lower: number, upper: number, pos: number) { return 1 - (pos - lower) / (upper - lower) } -function position(event) { +function position(event: GameEvent) { return event.position } diff --git a/bemuse/src/game/display/player-display.js b/bemuse/src/game/display/player-display.js deleted file mode 100644 index bae4adf7d..000000000 --- a/bemuse/src/game/display/player-display.js +++ /dev/null @@ -1,226 +0,0 @@ -import * as touch3d from './touch3d' -import NoteArea from './note-area' -import { MISSED, breaksCombo } from '../judgments' -import { getGauge } from './Gauge' - -export class PlayerDisplay { - constructor(player, skinData) { - this._currentSpeed = 1 - this._player = player - this._noteArea = new NoteArea( - player.notechart.notes, - player.notechart.barLines - ) - this._stateful = {} - this._defaultData = { - placement: player.options.placement, - scratch: player.options.scratch, - key_mode: player.notechart.getKeyMode(player.options.scratch), - lane_lift: Math.max(0, -player.options.laneCover), - lane_press: Math.max(0, player.options.laneCover), - } - this._gauge = getGauge(player.options.gauge) - this._touch3dMode = skinData.displayMode === 'touch3d' - } - - update(time, gameTime, playerState) { - const touch3dMode = this._touch3dMode - const player = this._player - const noteArea = this._noteArea - const stateful = this._stateful - const beat = player.notechart.secondsToBeat(gameTime) - const position = player.notechart.beatToPosition(beat) - const spacing = player.notechart.spacingAtBeat(beat) - const data = Object.assign({}, this._defaultData) - const push = (key, value) => (data[key] || (data[key] = [])).push(value) - const gauge = this._gauge - - this._currentSpeed += (playerState.speed - this._currentSpeed) / 3 - const speed = this._currentSpeed * spacing - - updateBeat() - updateVisibleNotes() - updateBarLines() - updateInput() - updateJudgment() - updateGauge() - updateExplode() - - data['speed'] = playerState.speed.toFixed(1) + 'x' - data['stat_1'] = getCount(1) - data['stat_2'] = getCount(2) - data['stat_3'] = getCount(3) - data['stat_4'] = getCount(4) - data['stat_missed'] = getCount(MISSED) - data['stat_acc'] = getAccuracy() - const bpm = player.notechart.bpmAtBeat(beat) - data['bpm'] = bpm < 1 ? '' : Math.round(bpm) % 10000 || '' - - Object.assign(data, stateful) - return data - - function updateBeat() { - data.beat = beat - } - - function getCount(judgment) { - return playerState.stats.counts && playerState.stats.counts[judgment] - } - - function getAccuracy() { - return ((playerState.stats.currentAccuracy || 0) * 100).toFixed(2) + '%' - } - - function updateVisibleNotes() { - const entities = noteArea.getVisibleNotes(position, getUpperBound(), 1) - if (touch3dMode) { - const putNote = (id, noteY, column, scale = 1) => { - const row = touch3d.getRow(noteY - 0.01) - const columnIndex = +column || -1 - const areaWidth = touch3d.PLAY_AREA_WIDTH - const xOffset = - row.projection * areaWidth * ((2 * (columnIndex - 0.5)) / 7 - 1) - const desiredWidth = (row.projection * scale * areaWidth * 2) / 7 - push(`note3d_${column}`, { - key: id, - y: row.y, - x: xOffset + 1280 / 2, - width: desiredWidth, - }) - } - const longNoteStep = 3 / 128 - for (const entity of entities) { - const note = entity.note - const column = note.column - if (entity.height) { - let c = 0 - const start = entity.y + entity.height - for ( - let i = - start - - Math.max( - 0, - Math.floor((start - 1) / longNoteStep) * longNoteStep - ); - i >= 0 && i >= entity.y; - i -= longNoteStep - ) { - putNote(note.id + 'x' + c++, i, column, 0.8) - } - putNote(note.id, entity.y + entity.height, column) - } else { - if (playerState.getNoteStatus(note) !== 'judged') { - putNote(note.id, entity.y, column) - } - } - } - } else { - for (const entity of entities) { - const note = entity.note - const column = note.column - if (entity.height) { - const judgment = playerState.getNoteJudgment(note) - const status = playerState.getNoteStatus(note) - push(`longnote_${column}`, { - key: note.id, - y: entity.y, - height: entity.height, - active: judgment !== 0 && judgment !== MISSED, - missed: status === 'judged' && judgment === MISSED, - }) - } else { - if (playerState.getNoteStatus(note) !== 'judged') { - push(`note_${column}`, { - key: note.id, - y: entity.y, - }) - } - } - } - } - } - - function updateBarLines() { - const entities = noteArea.getVisibleBarLines(position, getUpperBound(), 1) - for (const entity of entities) { - if (touch3dMode) { - const row = touch3d.getRow(entity.y - 0.01) - push('barlines3d', { - key: entity.id, - y: row.y, - x: row.projection * -touch3d.PLAY_AREA_WIDTH + 1280 / 2, - width: row.projection * touch3d.PLAY_AREA_WIDTH * 2, - }) - } else { - push('barlines', { key: entity.id, y: entity.y }) - } - } - } - - function updateInput() { - const input = playerState.input - for (const column of player.columns) { - const control = input.get(column) - data[`${column}_active`] = control.value !== 0 ? 1 : 0 - if (control.changed) { - if (control.value !== 0) { - stateful[`${column}_down`] = time - } else { - stateful[`${column}_up`] = time - } - } - } - } - - function updateJudgment() { - const notifications = playerState.notifications.judgments - const notification = notifications[notifications.length - 1] - if (notification) { - const name = - notification.judgment === -1 ? 'missed' : `${notification.judgment}` - stateful[`judge_${name}`] = time - const deviationMode = - notification.judgment === -1 || notification.judgment === 1 - ? 'none' - : notification.delta > 0 - ? 'late' - : notification.delta < 0 - ? 'early' - : 'none' - stateful[`judge_deviation_${deviationMode}`] = time - stateful['combo'] = notification.combo - } - data['score'] = playerState.stats.score - } - - function updateGauge() { - gauge.update(playerState) - if (gauge.shouldDisplay()) { - if (!stateful['gauge_enter']) stateful['gauge_enter'] = time - } else { - if (stateful['gauge_enter']) { - if (!stateful['gauge_exit']) stateful['gauge_exit'] = time - } - } - data['gauge_primary'] = gauge.getPrimary() - data['gauge_secondary'] = gauge.getSecondary() - data['gauge_extra'] = gauge.getExtra() - } - - function updateExplode() { - const notifications = playerState.notifications.judgments - for (let i = 0; i < notifications.length; i++) { - const notification = notifications[i] - if (!breaksCombo(notification.judgment)) { - stateful[`${notification.column}_explode`] = time - } - } - } - - function getUpperBound() { - return position + 5 / speed - } - } -} - -export default PlayerDisplay diff --git a/bemuse/src/game/display/player-display.ts b/bemuse/src/game/display/player-display.ts new file mode 100644 index 000000000..e6b17841b --- /dev/null +++ b/bemuse/src/game/display/player-display.ts @@ -0,0 +1,282 @@ +import * as touch3d from './touch3d' + +import { Gauge, getGauge } from './Gauge' +import { JudgedJudgment, MISSED, breaksCombo } from '../judgments' +import Player, { PlayerOptionsPlacement, PlayerOptionsScratch } from '../player' +import PlayerState, { JudgementNotification } from '../state/player-state' + +import NoteArea from './note-area' + +interface PlayerData { + placement: PlayerOptionsPlacement + scratch: PlayerOptionsScratch + key_mode: string + lane_lift: number + lane_press: number +} + +export class PlayerDisplay { + constructor(private readonly player: Player, skinData: TODO) { + this._currentSpeed = 1 + this._noteArea = new NoteArea( + player.notechart.notes, + player.notechart.barLines + ) + this._stateful = {} + this._defaultData = { + placement: player.options.placement, + scratch: player.options.scratch, + key_mode: player.notechart.getKeyMode(player.options.scratch), + lane_lift: Math.max(0, -player.options.laneCover), + lane_press: Math.max(0, player.options.laneCover), + } as const + this._gauge = getGauge(player.options.gauge) + this._touch3dMode = skinData.displayMode === 'touch3d' + } + + private _currentSpeed: number + private _noteArea: NoteArea + private _stateful: Record + private readonly _defaultData: Readonly + private _gauge: Gauge + private _touch3dMode: boolean + + update(time: number, gameTime: number, playerState: PlayerState) { + const beat = this.player.notechart.secondsToBeat(gameTime) + const position = this.player.notechart.beatToPosition(beat) + const spacing = this.player.notechart.spacingAtBeat(beat) + const data: Record = { ...this._defaultData } + const push = (key: string, value: unknown) => { + if (!(key in data)) { + data[key] = [] + } + ;(data[key] as unknown[]).push(value) + } + + this._currentSpeed += (playerState.speed - this._currentSpeed) / 3 + const speed = this._currentSpeed * spacing + + this.updateBeat(data, beat) + this.updateVisibleNotes(playerState, position, speed, push) + this.updateBarLines(position, speed, push) + this.updateInput(playerState, time, data) + this.updateJudgment(playerState, time, data) + this.updateGauge(playerState, time, data) + this.updateExplode(playerState, time) + + data.speed = playerState.speed.toFixed(1) + 'x' + data.stat_1 = this.getCount(playerState, 1) + data.stat_2 = this.getCount(playerState, 2) + data.stat_3 = this.getCount(playerState, 3) + data.stat_4 = this.getCount(playerState, 4) + data.stat_missed = this.getCount(playerState, MISSED) + data.stat_acc = this.getAccuracy(playerState) + const bpm = this.player.notechart.bpmAtBeat(beat) + data.bpm = bpm < 1 ? '' : Math.round(bpm) % 10000 || '' + + return { ...data, ...this._stateful } + } + + private updateBeat(data: Record, beat: number) { + data.beat = beat + } + + private getCount(playerState: PlayerState, judgment: JudgedJudgment) { + return playerState.stats.counts && playerState.stats.counts[judgment] + } + + private getAccuracy(playerState: PlayerState) { + return ((playerState.stats.currentAccuracy || 0) * 100).toFixed(2) + '%' + } + + private updateVisibleNotes( + playerState: PlayerState, + position: number, + speed: number, + push: (key: string, value: unknown) => void + ) { + const entities = this._noteArea.getVisibleNotes( + position, + this.getUpperBound(position, speed), + 1 + ) + if (this._touch3dMode) { + const putNote = ( + id: string | number, + noteY: number, + column?: string, + scale = 1 + ) => { + const row = touch3d.getRow(noteY - 0.01) + const columnIndex = +(column ?? '-1') + const areaWidth = touch3d.PLAY_AREA_WIDTH + const xOffset = + row.projection * areaWidth * ((2 * (columnIndex - 0.5)) / 7 - 1) + const desiredWidth = (row.projection * scale * areaWidth * 2) / 7 + push(`note3d_${column}`, { + key: id, + y: row.y, + x: xOffset + 1280 / 2, + width: desiredWidth, + }) + } + const longNoteStep = 3 / 128 + for (const entity of entities) { + const note = entity.note + const column = note.column + if (entity.height) { + let c = 0 + const start = entity.y + entity.height + for ( + let i = + start - + Math.max( + 0, + Math.floor((start - 1) / longNoteStep) * longNoteStep + ); + i >= 0 && i >= entity.y; + i -= longNoteStep + ) { + putNote(note.id + 'x' + c++, i, column, 0.8) + } + putNote(note.id, entity.y + entity.height, column) + } else { + if (playerState.getNoteStatus(note) !== 'judged') { + putNote(note.id, entity.y, column) + } + } + } + } else { + for (const entity of entities) { + const note = entity.note + const column = note.column + if (entity.height) { + const judgment = playerState.getNoteJudgment(note) + const status = playerState.getNoteStatus(note) + push(`longnote_${column}`, { + key: note.id, + y: entity.y, + height: entity.height, + active: judgment !== 0 && judgment !== MISSED, + missed: status === 'judged' && judgment === MISSED, + }) + } else { + if (playerState.getNoteStatus(note) !== 'judged') { + push(`note_${column}`, { + key: note.id, + y: entity.y, + }) + } + } + } + } + } + + private updateBarLines( + position: number, + speed: number, + push: (key: string, value: unknown) => void + ) { + const entities = this._noteArea.getVisibleBarLines( + position, + this.getUpperBound(position, speed), + 1 + ) + for (const entity of entities) { + if (this._touch3dMode) { + const row = touch3d.getRow(entity.y - 0.01) + push('barlines3d', { + key: entity.id, + y: row.y, + x: row.projection * -touch3d.PLAY_AREA_WIDTH + 1280 / 2, + width: row.projection * touch3d.PLAY_AREA_WIDTH * 2, + }) + } else { + push('barlines', { key: entity.id, y: entity.y }) + } + } + } + + private updateJudgment( + playerState: PlayerState, + time: number, + data: Record + ) { + const notifications = playerState.notifications.judgments + const notification = notifications[notifications.length - 1] + if (notification) { + const name = + notification.judgment === -1 ? 'missed' : `${notification.judgment}` + this._stateful[`judge_${name}`] = time + const deviationMode = this.derivationMode(notification) + this._stateful[`judge_deviation_${deviationMode}`] = time + this._stateful['combo'] = notification.combo + } + data['score'] = playerState.stats.score + } + + private derivationMode(notification: JudgementNotification) { + if (notification.judgment === -1 || notification.judgment === 1) { + return 'none' + } + if (notification.delta > 0) { + return 'late' + } + if (notification.delta < 0) { + return 'early' + } + return 'none' + } + + private updateGauge( + playerState: PlayerState, + time: number, + data: Record + ) { + this._gauge.update(playerState) + if (this._gauge.shouldDisplay()) { + if (!this._stateful['gauge_enter']) this._stateful['gauge_enter'] = time + } else { + if (this._stateful['gauge_enter']) { + if (!this._stateful['gauge_exit']) this._stateful['gauge_exit'] = time + } + } + data['gauge_primary'] = this._gauge.getPrimary() + data['gauge_secondary'] = this._gauge.getSecondary() + data['gauge_extra'] = this._gauge.getExtra() + } + + private updateExplode(playerState: PlayerState, time: number) { + const notifications = playerState.notifications.judgments + for (const notification of notifications) { + if (!breaksCombo(notification.judgment)) { + this._stateful[`${notification.column}_explode`] = time + } + } + } + + private getUpperBound(position: number, speed: number) { + return position + 5 / speed + } + + private updateInput( + playerState: PlayerState, + time: number, + data: Record + ) { + const input = playerState.input + for (const column of this.player.columns) { + const control = input.get(column)! + data[`${column}_active`] = control.value !== 0 ? 1 : 0 + if (control.changed) { + if (control.value !== 0) { + this._stateful[`${column}_down`] = time + } else { + this._stateful[`${column}_up`] = time + } + } + } + } +} + +export default PlayerDisplay diff --git a/bemuse/src/game/display/touch3d.js b/bemuse/src/game/display/touch3d.ts similarity index 94% rename from bemuse/src/game/display/touch3d.js rename to bemuse/src/game/display/touch3d.ts index f679d4ba8..3cdee6887 100644 --- a/bemuse/src/game/display/touch3d.js +++ b/bemuse/src/game/display/touch3d.ts @@ -36,7 +36,7 @@ const config = { * - `projection` The projected scale. If an object is closer to the screen, * it will appear bigger. This value represents that scale. */ -export function getRow(position) { +export function getRow(position: number) { const excess = Math.max(0, position - 1) if (position < 0) position = 0 if (position > 1) position = 1 @@ -61,11 +61,11 @@ export const PLAY_AREA_WIDTH = config.w * @param {number} y The y onscreen coordinate (0~1280) * @return Column name ('1'~'7') or `null` if no column should be triggered. */ -export function getTouchedColumn(x, y) { +export function getTouchedColumn(x: number, y: number) { let min = 0.75 let max = 1 - let mid - let row + let mid: number = (min + max) / 2 + let row = getRow(mid) for (let i = 0; i < 8; i++) { mid = (min + max) / 2 row = getRow(mid) diff --git a/bemuse/src/game/loaders/loadImage.js b/bemuse/src/game/loaders/loadImage.js deleted file mode 100644 index d26f66e5a..000000000 --- a/bemuse/src/game/loaders/loadImage.js +++ /dev/null @@ -1,18 +0,0 @@ -export function loadImage(assets, filename) { - return assets - .file(filename) - .then((asset) => asset.read()) - .then((arrayBuffer) => new Blob([arrayBuffer])) - .then((blob) => URL.createObjectURL(blob)) - .then( - (src) => - new Promise((resolve, reject) => { - const image = new Image() - image.onload = () => resolve(image) - image.onerror = reject - image.src = src - }) - ) -} - -export default loadImage diff --git a/bemuse/src/game/loaders/loadImage.ts b/bemuse/src/game/loaders/loadImage.ts new file mode 100644 index 000000000..b06cab288 --- /dev/null +++ b/bemuse/src/game/loaders/loadImage.ts @@ -0,0 +1,21 @@ +import { Assets } from './game-loader' + +export type LoadImagePromise = Promise + +export async function loadImage( + assets: Assets, + filename: string +): LoadImagePromise { + const asset = await assets.file(filename) + const arrayBuffer = await asset.read() + const blob = new Blob([arrayBuffer]) + const src = URL.createObjectURL(blob) + return await new Promise((resolve, reject) => { + const image = new Image() + image.onload = () => resolve(image) + image.onerror = reject + image.src = src + }) +} + +export default loadImage diff --git a/bemuse/src/game/state/player-state.ts b/bemuse/src/game/state/player-state.ts index f2a2a7dae..3db5bcead 100644 --- a/bemuse/src/game/state/player-state.ts +++ b/bemuse/src/game/state/player-state.ts @@ -1,20 +1,20 @@ -import _ from 'lodash' - -import PlayerStats from './player-stats' import { + IJudge, + JudgedJudgment, + Judgment, MISSED, getJudgeForNotechart, isBad, judgeEndTime, judgeTime, - IJudge, - Judgment, - JudgedJudgment, } from '../judgments' -import Player from '../player' -import { GameNote } from 'bemuse-notechart/lib/types' -import GameInput from '../input' + import Control from '../input/control' +import GameInput from '../input' +import { GameNote } from 'bemuse-notechart/lib/types' +import Player from '../player' +import PlayerStats from './player-stats' +import _ from 'lodash' import invariant from 'invariant' type NoteResult = { @@ -32,13 +32,31 @@ enum NoteStatus { Judged = 'judged', } -type Notifications = { - sounds: ( - | { type: 'hit'; note: GameNote; judgment: Judgment } - | { type: 'free'; note: GameNote } - | { type: 'break'; note: GameNote } - )[] - judgments: {}[] +export type SoundNotification = + | { + type: 'hit' + note: GameNote + judgment: Judgment + } + | { + type: 'free' + note: GameNote + } + | { + type: 'break' + note: GameNote + } + +export interface JudgementNotification { + judgment: JudgedJudgment + combo: number + delta: number + column: string +} + +export interface Notifications { + sounds: SoundNotification[] + judgments: JudgementNotification[] } function initializeNotifications(): Notifications { diff --git a/bemuse/src/scintillator/skin.ts b/bemuse/src/scintillator/skin.ts new file mode 100644 index 000000000..39ad5a467 --- /dev/null +++ b/bemuse/src/scintillator/skin.ts @@ -0,0 +1 @@ +export type InfoPanelPosition = 'bottom' | 'top' diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index ebeeb8471..496f25b19 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -35,6 +35,7 @@ specifiers: '@types/eslint': ^4.16.4 '@types/invariant': ^2.2.30 '@types/jest': ^27.0.0 + '@types/jquery': ^3.5.16 '@types/lodash': ^4.14.176 '@types/lodash.assign': ^4.2.4 '@types/lodash.map': ^4.6.13 @@ -179,7 +180,7 @@ specifiers: rxjs: ^7.8.0 sass: ^1.34.1 sass-loader: ^13.1.0 - screenfull: ^3.3.3 + screenfull: ^6.0.2 script-loader: ^0.7.2 semver: ^7.3.8 service-worker-webpack: ^0.0.11 @@ -252,6 +253,7 @@ dependencies: '@types/eslint': 4.16.8 '@types/invariant': 2.2.35 '@types/jest': 27.5.2 + '@types/jquery': 3.5.16 '@types/lodash': 4.14.191 '@types/lodash.assign': 4.2.7 '@types/lodash.map': 4.6.13 @@ -396,7 +398,7 @@ dependencies: rxjs: 7.8.0 sass: 1.57.1 sass-loader: 13.2.0_sass@1.57.1+webpack@5.75.0 - screenfull: 3.3.3 + screenfull: 6.0.2 script-loader: 0.7.2 semver: 7.3.8 service-worker-webpack: 0.0.11_webpack@5.75.0 @@ -5456,6 +5458,12 @@ packages: pretty-format: 27.5.1 dev: false + /@types/jquery/3.5.16: + resolution: {integrity: sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==} + dependencies: + '@types/sizzle': 2.3.3 + dev: false + /@types/json-schema/7.0.11: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: false @@ -5654,6 +5662,10 @@ packages: '@types/node': 18.11.18 dev: false + /@types/sizzle/2.3.3: + resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==} + dev: false + /@types/sockjs/0.3.33: resolution: {integrity: sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==} dependencies: @@ -6247,6 +6259,13 @@ packages: buffer-equal: 1.0.1 dev: false + /append-transform/0.4.0: + resolution: {integrity: sha512-Yisb7ew0ZEyDtRYQ+b+26o9KbiYPFxwcsxKzbssigzRRMJ9LpExPVUg6Fos7eP7yP3q7///tzze4nm4lTptPBw==} + engines: {node: '>=0.10.0'} + dependencies: + default-require-extensions: 1.0.0 + dev: false + /aproba/1.2.0: resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} dev: false @@ -6301,6 +6320,13 @@ packages: tslib: 2.4.1 dev: false + /arr-diff/2.0.0: + resolution: {integrity: sha512-dtXTVMkh6VkEEA7OhXnN1Ecb8aAGFdZ1LFxtOCoqj4qkyOJMt7+qs6Ahdy6p/NQCPYsRSXXivhSB/J5E9jmYKA==} + engines: {node: '>=0.10.0'} + dependencies: + arr-flatten: 1.1.0 + dev: false + /arr-diff/4.0.0: resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} engines: {node: '>=0.10.0'} @@ -6417,6 +6443,11 @@ packages: engines: {node: '>=0.10.0'} dev: false + /array-unique/0.2.1: + resolution: {integrity: sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg==} + engines: {node: '>=0.10.0'} + dev: false + /array-unique/0.3.2: resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} engines: {node: '>=0.10.0'} @@ -6452,6 +6483,11 @@ packages: get-intrinsic: 1.1.3 dev: false + /arrify/1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + dev: false + /artstep/5555.0.0: resolution: {integrity: sha512-jZEDj3jLfci3puWQRfiymtGTgQFaxOFJPE13yb9Y0+IkNDq+e6sw9GlLyS812ONsbYaT7UNrErLSnmWBZ/yzWw==} dependencies: @@ -6629,6 +6665,27 @@ packages: - debug dev: false + /babel-code-frame/6.26.0: + resolution: {integrity: sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==} + dependencies: + chalk: 1.1.3 + esutils: 2.0.3 + js-tokens: 3.0.2 + dev: false + + /babel-generator/6.26.1: + resolution: {integrity: sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==} + dependencies: + babel-messages: 6.23.0 + babel-runtime: 6.26.0 + babel-types: 6.26.0 + detect-indent: 4.0.0 + jsesc: 1.3.0 + lodash: 4.17.21 + source-map: 0.5.7 + trim-right: 1.0.1 + dev: false + /babel-jest/27.5.1_@babel+core@7.20.12: resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -6663,6 +6720,12 @@ packages: webpack: 5.75.0 dev: false + /babel-messages/6.23.0: + resolution: {integrity: sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==} + dependencies: + babel-runtime: 6.26.0 + dev: false + /babel-plugin-apply-mdx-type-prop/1.6.22_@babel+core@7.12.9: resolution: {integrity: sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==} peerDependencies: @@ -6791,6 +6854,30 @@ packages: regenerator-runtime: 0.11.1 dev: false + /babel-template/6.26.0: + resolution: {integrity: sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==} + dependencies: + babel-runtime: 6.26.0 + babel-traverse: 6.26.0 + babel-types: 6.26.0 + babylon: 6.18.0 + lodash: 4.17.21 + dev: false + + /babel-traverse/6.26.0: + resolution: {integrity: sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==} + dependencies: + babel-code-frame: 6.26.0 + babel-messages: 6.23.0 + babel-runtime: 6.26.0 + babel-types: 6.26.0 + babylon: 6.18.0 + debug: 2.6.9 + globals: 9.18.0 + invariant: 2.2.4 + lodash: 4.17.21 + dev: false + /babel-types/6.26.0: resolution: {integrity: sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==} dependencies: @@ -6996,6 +7083,15 @@ packages: balanced-match: 1.0.2 dev: false + /braces/1.8.5: + resolution: {integrity: sha512-xU7bpz2ytJl1bH9cgIurjpg/n8Gohy9GTw81heDYLJQ4RU60dlyJsa+atVF2pI0yMMvKxI9HkKwjePCj5XI1hw==} + engines: {node: '>=0.10.0'} + dependencies: + expand-range: 1.8.2 + preserve: 0.2.0 + repeat-element: 1.1.4 + dev: false + /braces/2.3.2: resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} engines: {node: '>=0.10.0'} @@ -7332,6 +7428,15 @@ packages: responselike: 1.0.2 dev: false + /caching-transform/1.0.1: + resolution: {integrity: sha512-TYu6IoS+HzPivTKBDbGbkdNE7V3GP9ETNuO1L901jhtIdmMmE4S5SXxXvIMPt4+poeqSGY47NQz1GFh3toDHqw==} + engines: {node: '>=0.10.0'} + dependencies: + md5-hex: 1.3.0 + mkdirp: 0.5.6 + write-file-atomic: 1.3.4 + dev: false + /call-bind/1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -7397,6 +7502,11 @@ packages: engines: {node: '>=0.10.0'} dev: false + /camelcase/4.1.0: + resolution: {integrity: sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==} + engines: {node: '>=4'} + dev: false + /camelcase/5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -7688,6 +7798,14 @@ packages: wrap-ansi: 2.1.0 dev: false + /cliui/4.1.0: + resolution: {integrity: sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==} + dependencies: + string-width: 2.1.1 + strip-ansi: 4.0.0 + wrap-ansi: 2.1.0 + dev: false + /cliui/6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} dependencies: @@ -8210,6 +8328,21 @@ packages: - encoding dev: false + /cross-spawn/4.0.2: + resolution: {integrity: sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==} + dependencies: + lru-cache: 4.1.5 + which: 1.3.1 + dev: false + + /cross-spawn/5.1.0: + resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} + dependencies: + lru-cache: 4.1.5 + shebang-command: 1.2.0 + which: 1.3.1 + dev: false + /cross-spawn/6.0.5: resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} engines: {node: '>=4.8'} @@ -8521,6 +8654,11 @@ packages: engines: {node: '>=4.0'} dev: false + /debug-log/1.0.1: + resolution: {integrity: sha512-gV/pe1YIaKNgLYnd1g9VNW80tcb7oV5qvNUxG7NM8rbDpnl6RGunzlAtlGSb0wEs3nesu2vHNiX9TSsZ+Y+RjA==} + engines: {node: '>=0.10.0'} + dev: false + /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} dependencies: @@ -8626,6 +8764,13 @@ packages: execa: 5.1.1 dev: false + /default-require-extensions/1.0.0: + resolution: {integrity: sha512-Dn2eAftOqXhNXs5f/Xjn7QTZ6kDYkx7u0EXQInN1oyYwsZysu11q7oTtaKcbzLxZRJiDHa8VmwpWmb4lY5FqgA==} + engines: {node: '>=0.10.0'} + dependencies: + strip-bom: 2.0.0 + dev: false + /default-resolution/2.0.0: resolution: {integrity: sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==} engines: {node: '>= 0.10'} @@ -8745,6 +8890,13 @@ packages: engines: {node: '>=0.10.0'} dev: false + /detect-indent/4.0.0: + resolution: {integrity: sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==} + engines: {node: '>=0.10.0'} + dependencies: + repeating: 2.0.1 + dev: false + /detect-newline/3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -9935,6 +10087,19 @@ packages: strip-eof: 1.0.0 dev: false + /execa/0.7.0: + resolution: {integrity: sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==} + engines: {node: '>=4'} + dependencies: + cross-spawn: 5.1.0 + get-stream: 3.0.0 + is-stream: 1.1.0 + npm-run-path: 2.0.2 + p-finally: 1.0.0 + signal-exit: 3.0.7 + strip-eof: 1.0.0 + dev: false + /execa/4.1.0: resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} engines: {node: '>=10'} @@ -9970,6 +10135,13 @@ packages: engines: {node: '>= 0.8.0'} dev: false + /expand-brackets/0.1.5: + resolution: {integrity: sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA==} + engines: {node: '>=0.10.0'} + dependencies: + is-posix-bracket: 0.1.1 + dev: false + /expand-brackets/2.1.4: resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} engines: {node: '>=0.10.0'} @@ -9983,6 +10155,13 @@ packages: to-regex: 3.0.2 dev: false + /expand-range/1.8.2: + resolution: {integrity: sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==} + engines: {node: '>=0.10.0'} + dependencies: + fill-range: 2.2.4 + dev: false + /expand-tilde/2.0.2: resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} engines: {node: '>=0.10.0'} @@ -10081,6 +10260,13 @@ packages: tmp: 0.0.33 dev: false + /extglob/0.3.2: + resolution: {integrity: sha512-1FOj1LOwn42TMrruOHGt18HemVnbwAmAak7krWk+wa93KXxGbK+2jpezm+ytJYDaBX0/SPLZFHKM7m+tKobWGg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 1.0.0 + dev: false + /extglob/2.0.4: resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} engines: {node: '>=0.10.0'} @@ -10276,6 +10462,11 @@ packages: minimatch: 5.1.2 dev: false + /filename-regex/2.0.1: + resolution: {integrity: sha512-BTCqyBaWBTsauvnHiE8i562+EdJj+oUpkqWp2R1iCoR8f6oo8STRu3of7WJJ0TqWtxN50a5YFpzYK4Jj9esYfQ==} + engines: {node: '>=0.10.0'} + dev: false + /filename-reserved-regex/1.0.0: resolution: {integrity: sha512-UZArj7+U+2reBBVCvVmRlyq9D7EYQdUtuNN+1iz7pF1jGcJ2L0TjiRCxsTZfj2xFbM4c25uGCUDpKTHA7L2TKg==} engines: {node: '>=0.10.0'} @@ -10303,6 +10494,17 @@ packages: engines: {node: '>= 0.4.0'} dev: false + /fill-range/2.2.4: + resolution: {integrity: sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==} + engines: {node: '>=0.10.0'} + dependencies: + is-number: 2.1.0 + isobject: 2.1.0 + randomatic: 3.1.1 + repeat-element: 1.1.4 + repeat-string: 1.6.1 + dev: false + /fill-range/4.0.0: resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} engines: {node: '>=0.10.0'} @@ -10346,6 +10548,15 @@ packages: unpipe: 1.0.0 dev: false + /find-cache-dir/0.1.1: + resolution: {integrity: sha512-Z9XSBoNE7xQiV6MSgPuCfyMokH2K7JdpRkOYE1+mu3d4BFJtx3GW+f6Bo4q8IX6rlf5MYbLBKW0pjl2cWdkm2A==} + engines: {node: '>=0.10.0'} + dependencies: + commondir: 1.0.1 + mkdirp: 0.5.6 + pkg-dir: 1.0.0 + dev: false + /find-cache-dir/3.3.2: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} @@ -10367,6 +10578,13 @@ packages: pinkie-promise: 2.0.1 dev: false + /find-up/2.1.0: + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} + engines: {node: '>=4'} + dependencies: + locate-path: 2.0.0 + dev: false + /find-up/3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} @@ -10504,6 +10722,13 @@ packages: engines: {node: '>=0.10.0'} dev: false + /for-own/0.1.5: + resolution: {integrity: sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==} + engines: {node: '>=0.10.0'} + dependencies: + for-in: 1.0.2 + dev: false + /for-own/1.0.0: resolution: {integrity: sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==} engines: {node: '>=0.10.0'} @@ -10511,6 +10736,13 @@ packages: for-in: 1.0.2 dev: false + /foreground-child/1.5.6: + resolution: {integrity: sha512-3TOY+4TKV0Ml83PXJQY+JFQaHNV38lzQDIzzXYg1kWdBLenGgoZhAs0CKgzI31vi2pWEpQMq/Yi4bpKwCPkw7g==} + dependencies: + cross-spawn: 4.0.2 + signal-exit: 3.0.7 + dev: false + /fork-ts-checker-webpack-plugin/6.5.2_ccd0d04a7b779c9c2de6d13f40a58493: resolution: {integrity: sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==} engines: {node: '>=10', yarn: '>=1.0.0'} @@ -10817,6 +11049,20 @@ packages: resolution: {integrity: sha512-jduKUqT0SGH02l8Yl+mV1yVsDfYgQAJyXGxkJQGyxPLHRiW25DwVIRPt6uvhrEMHftJfqhqKthRcyZqNEl9Xdw==} dev: false + /glob-base/0.3.0: + resolution: {integrity: sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==} + engines: {node: '>=0.10.0'} + dependencies: + glob-parent: 2.0.0 + is-glob: 2.0.1 + dev: false + + /glob-parent/2.0.0: + resolution: {integrity: sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==} + dependencies: + is-glob: 2.0.1 + dev: false + /glob-parent/3.1.0: resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} dependencies: @@ -11005,6 +11251,11 @@ packages: type-fest: 0.20.2 dev: false + /globals/9.18.0: + resolution: {integrity: sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==} + engines: {node: '>=0.10.0'} + dev: false + /globalthis/1.0.3: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} @@ -11189,6 +11440,19 @@ packages: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} dev: false + /handlebars/4.7.7: + resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} + engines: {node: '>=0.4.7'} + hasBin: true + dependencies: + minimist: 1.2.7 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.17.4 + dev: false + /has-ansi/2.0.0: resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} engines: {node: '>=0.10.0'} @@ -11200,6 +11464,11 @@ packages: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: false + /has-flag/1.0.0: + resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} + engines: {node: '>=0.10.0'} + dev: false + /has-flag/3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -12033,6 +12302,18 @@ packages: hasBin: true dev: false + /is-dotfile/1.0.3: + resolution: {integrity: sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg==} + engines: {node: '>=0.10.0'} + dev: false + + /is-equal-shallow/0.1.3: + resolution: {integrity: sha512-0EygVC5qPvIyb+gSz7zdD5/AAoS6Qrx1e//6N4yv4oNm30kqvdmG66oZFWVlQHUWe5OjP08FuTw2IdT0EOTcYA==} + engines: {node: '>=0.10.0'} + dependencies: + is-primitive: 2.0.0 + dev: false + /is-expression/3.0.0: resolution: {integrity: sha512-vyMeQMq+AiH5uUnoBfMTwf18tO3bM6k1QXBE9D6ueAAquEfCZe3AJPtud9g6qS0+4X8xA7ndpZiDyeb2l2qOBw==} dependencies: @@ -12052,6 +12333,11 @@ packages: is-plain-object: 2.0.4 dev: false + /is-extglob/1.0.0: + resolution: {integrity: sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==} + engines: {node: '>=0.10.0'} + dev: false + /is-extglob/2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -12091,6 +12377,13 @@ packages: has-tostringtag: 1.0.0 dev: false + /is-glob/2.0.1: + resolution: {integrity: sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 1.0.0 + dev: false + /is-glob/3.1.0: resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} engines: {node: '>=0.10.0'} @@ -12151,6 +12444,13 @@ packages: has-tostringtag: 1.0.0 dev: false + /is-number/2.1.0: + resolution: {integrity: sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + dev: false + /is-number/3.0.0: resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} engines: {node: '>=0.10.0'} @@ -12215,10 +12515,20 @@ packages: engines: {node: '>=0.10.0'} dev: false + /is-posix-bracket/0.1.1: + resolution: {integrity: sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ==} + engines: {node: '>=0.10.0'} + dev: false + /is-potential-custom-element-name/1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} dev: false + /is-primitive/2.0.0: + resolution: {integrity: sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q==} + engines: {node: '>=0.10.0'} + dev: false + /is-promise/2.2.2: resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} dev: false @@ -12380,11 +12690,33 @@ packages: engines: {node: '>=0.10.0'} dev: false + /istanbul-lib-coverage/1.2.1: + resolution: {integrity: sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==} + dev: false + /istanbul-lib-coverage/3.2.0: resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} engines: {node: '>=8'} dev: false + /istanbul-lib-hook/1.2.2: + resolution: {integrity: sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==} + dependencies: + append-transform: 0.4.0 + dev: false + + /istanbul-lib-instrument/1.10.2: + resolution: {integrity: sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==} + dependencies: + babel-generator: 6.26.1 + babel-template: 6.26.0 + babel-traverse: 6.26.0 + babel-types: 6.26.0 + babylon: 6.18.0 + istanbul-lib-coverage: 1.2.1 + semver: 5.7.1 + dev: false + /istanbul-lib-instrument/5.2.0: resolution: {integrity: sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==} engines: {node: '>=8'} @@ -12411,6 +12743,15 @@ packages: - supports-color dev: false + /istanbul-lib-report/1.1.5: + resolution: {integrity: sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==} + dependencies: + istanbul-lib-coverage: 1.2.1 + mkdirp: 0.5.6 + path-parse: 1.0.7 + supports-color: 3.2.3 + dev: false + /istanbul-lib-report/3.0.0: resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} engines: {node: '>=8'} @@ -12420,6 +12761,16 @@ packages: supports-color: 7.2.0 dev: false + /istanbul-lib-source-maps/1.2.6: + resolution: {integrity: sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==} + dependencies: + debug: 3.2.7 + istanbul-lib-coverage: 1.2.1 + mkdirp: 0.5.6 + rimraf: 2.7.1 + source-map: 0.5.7 + dev: false + /istanbul-lib-source-maps/4.0.1: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} @@ -12431,6 +12782,12 @@ packages: - supports-color dev: false + /istanbul-reports/1.5.1: + resolution: {integrity: sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==} + dependencies: + handlebars: 4.7.7 + dev: false + /istanbul-reports/3.1.5: resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} engines: {node: '>=8'} @@ -12978,6 +13335,10 @@ packages: resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==} dev: false + /js-tokens/3.0.2: + resolution: {integrity: sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==} + dev: false + /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: false @@ -13048,6 +13409,11 @@ packages: hasBin: true dev: false + /jsesc/1.3.0: + resolution: {integrity: sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA==} + hasBin: true + dev: false + /jsesc/2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} @@ -13512,6 +13878,14 @@ packages: engines: {node: '>= 12.13.0'} dev: false + /locate-path/2.0.0: + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} + dependencies: + p-locate: 2.0.0 + path-exists: 3.0.0 + dev: false + /locate-path/3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} @@ -13660,6 +14034,13 @@ packages: resolution: {integrity: sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==} dev: false + /lru-cache/4.1.5: + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} + dependencies: + pseudomap: 1.0.2 + yallist: 2.1.2 + dev: false + /lru-cache/5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -13765,6 +14146,21 @@ packages: stack-trace: 0.0.10 dev: false + /math-random/1.0.4: + resolution: {integrity: sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==} + dev: false + + /md5-hex/1.3.0: + resolution: {integrity: sha512-lJEPhRxivsaliY4C6REebtP1Lo8yoQsq2bLVP8mJ6Vvzwu3fXQShzHcWnAqdDm1Y42jhZFg0XRpnrKfZ5mYP6w==} + engines: {node: '>=0.10.0'} + dependencies: + md5-o-matic: 0.1.1 + dev: false + + /md5-o-matic/0.1.1: + resolution: {integrity: sha512-QBJSFpsedXUl/Lgs4ySdB2XCzUEcJ3ujpbagdZCkRaYIaC0kFnID8jhc84KEiVv6dNFtIrmW7bqow0lDxgJi6A==} + dev: false + /md5.js/1.3.5: resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} dependencies: @@ -13824,6 +14220,13 @@ packages: resolution: {integrity: sha512-yrVT3CsP0Lqm1xuKjGHdRVt4va3rQu3UCidWboXlwnsflxRUHTKQIatvSQML8n32jH6XzY2jrdClYMUOkdrBHQ==} dev: false + /mem/1.1.0: + resolution: {integrity: sha512-nOBDrc/wgpkd3X/JOhMqYR+/eLqlfLP4oQfoBA6QExIxEl+GU01oyEkwWyueyO8110pUKijtiHGhEmYoOn88oQ==} + engines: {node: '>=4'} + dependencies: + mimic-fn: 1.2.0 + dev: false + /memfs/3.4.12: resolution: {integrity: sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw==} engines: {node: '>= 4.0.0'} @@ -13867,6 +14270,12 @@ packages: source-map: 0.5.7 dev: false + /merge-source-map/1.1.0: + resolution: {integrity: sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==} + dependencies: + source-map: 0.6.1 + dev: false + /merge-stream/2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: false @@ -13881,6 +14290,25 @@ packages: engines: {node: '>= 0.6'} dev: false + /micromatch/2.3.11: + resolution: {integrity: sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA==} + engines: {node: '>=0.10.0'} + dependencies: + arr-diff: 2.0.0 + array-unique: 0.2.1 + braces: 1.8.5 + expand-brackets: 0.1.5 + extglob: 0.3.2 + filename-regex: 2.0.1 + is-extglob: 1.0.0 + is-glob: 2.0.1 + kind-of: 3.2.2 + normalize-path: 2.1.1 + object.omit: 2.0.1 + parse-glob: 3.0.4 + regex-cache: 0.4.4 + dev: false + /micromatch/3.1.10: resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} engines: {node: '>=0.10.0'} @@ -14582,6 +15010,34 @@ packages: /nyc/11.9.0: resolution: {integrity: sha512-w8OdJAhXL5izerzZMdqzYKMj/pgHJyY3qEPYBjLLxrhcVoHEY9pU5ENIiZyCgG9OR7x3VcUMoD40o6PtVpfR4g==} hasBin: true + dependencies: + archy: 1.0.0 + arrify: 1.0.1 + caching-transform: 1.0.1 + convert-source-map: 1.9.0 + debug-log: 1.0.1 + default-require-extensions: 1.0.0 + find-cache-dir: 0.1.1 + find-up: 2.1.0 + foreground-child: 1.5.6 + glob: 7.2.3 + istanbul-lib-coverage: 1.2.1 + istanbul-lib-hook: 1.2.2 + istanbul-lib-instrument: 1.10.2 + istanbul-lib-report: 1.1.5 + istanbul-lib-source-maps: 1.2.6 + istanbul-reports: 1.5.1 + md5-hex: 1.3.0 + merge-source-map: 1.1.0 + micromatch: 3.1.10 + mkdirp: 0.5.6 + resolve-from: 2.0.0 + rimraf: 2.7.1 + signal-exit: 3.0.7 + spawn-wrap: 1.4.3 + test-exclude: 4.2.3 + yargs: 11.1.0 + yargs-parser: 8.1.0 dev: false bundledDependencies: - archy @@ -14707,6 +15163,14 @@ packages: make-iterator: 1.0.1 dev: false + /object.omit/2.0.1: + resolution: {integrity: sha512-UiAM5mhmIuKLsOvrL+B0U2d1hXHF3bFYWIuH1LMpuV2EJEHG1Ntz06PgLEHjm6VFd87NpH8rastvPoyv6UW2fA==} + engines: {node: '>=0.10.0'} + dependencies: + for-own: 0.1.5 + is-extendable: 0.1.1 + dev: false + /object.pick/1.3.0: resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} engines: {node: '>=0.10.0'} @@ -14840,6 +15304,11 @@ packages: resolution: {integrity: sha512-aZicJZccvxWOZ0Bja2eAch2L8RIJWBuRYmM8Gwl/JjNtRltH0Itcz4eH/ESyuIWfse8cc93ZCf0XrzhXK2HEDA==} dev: false + /os-homedir/1.0.2: + resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} + engines: {node: '>=0.10.0'} + dev: false + /os-locale/1.4.0: resolution: {integrity: sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==} engines: {node: '>=0.10.0'} @@ -14847,6 +15316,15 @@ packages: lcid: 1.0.0 dev: false + /os-locale/2.1.0: + resolution: {integrity: sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==} + engines: {node: '>=4'} + dependencies: + execa: 0.7.0 + lcid: 1.0.0 + mem: 1.1.0 + dev: false + /os-tmpdir/1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} @@ -14867,6 +15345,13 @@ packages: engines: {node: '>=4'} dev: false + /p-limit/1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + dependencies: + p-try: 1.0.0 + dev: false + /p-limit/2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -14881,6 +15366,13 @@ packages: yocto-queue: 0.1.0 dev: false + /p-locate/2.0.0: + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} + dependencies: + p-limit: 1.3.0 + dev: false + /p-locate/3.0.0: resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} engines: {node: '>=6'} @@ -14939,6 +15431,11 @@ packages: p-reflect: 2.1.0 dev: false + /p-try/1.0.0: + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} + dev: false + /p-try/2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -15014,6 +15511,16 @@ packages: path-root: 0.1.1 dev: false + /parse-glob/3.0.4: + resolution: {integrity: sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA==} + engines: {node: '>=0.10.0'} + dependencies: + glob-base: 0.3.0 + is-dotfile: 1.0.3 + is-extglob: 1.0.0 + is-glob: 2.0.1 + dev: false + /parse-json/2.2.0: resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} engines: {node: '>=0.10.0'} @@ -15270,6 +15777,13 @@ packages: resource-loader: 2.2.4 dev: false + /pkg-dir/1.0.0: + resolution: {integrity: sha512-c6pv3OE78mcZ92ckebVDqg0aWSoKhOTbwCV6qbCWMk546mAL9pZln0+QsN/yQ7fkucd4+yJPLrCBXNt8Ruk+Eg==} + engines: {node: '>=0.10.0'} + dependencies: + find-up: 1.1.2 + dev: false + /pkg-dir/4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -15860,6 +16374,11 @@ packages: engines: {node: '>=4'} dev: false + /preserve/0.2.0: + resolution: {integrity: sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ==} + engines: {node: '>=0.10.0'} + dev: false + /prettier/2.8.1: resolution: {integrity: sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==} engines: {node: '>=10.13.0'} @@ -15979,6 +16498,10 @@ packages: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: false + /pseudomap/1.0.2: + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + dev: false + /psl/1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} dev: false @@ -16228,6 +16751,15 @@ packages: through2: 2.0.5 dev: false + /randomatic/3.1.1: + resolution: {integrity: sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==} + engines: {node: '>= 0.10.0'} + dependencies: + is-number: 4.0.0 + kind-of: 6.0.3 + math-random: 1.0.4 + dev: false + /randombytes/2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: @@ -17012,6 +17544,13 @@ packages: '@babel/runtime': 7.20.7 dev: false + /regex-cache/0.4.4: + resolution: {integrity: sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-equal-shallow: 0.1.3 + dev: false + /regex-not/1.0.2: resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} engines: {node: '>=0.10.0'} @@ -17250,6 +17789,11 @@ packages: global-modules: 1.0.0 dev: false + /resolve-from/2.0.0: + resolution: {integrity: sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ==} + engines: {node: '>=0.10.0'} + dev: false + /resolve-from/4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -17589,9 +18133,9 @@ packages: ajv-keywords: 5.1.0_ajv@8.12.0 dev: false - /screenfull/3.3.3: - resolution: {integrity: sha512-DzYUuXr+OV2BDvYXaYzlYgJd4WXZZ2CW5NFC7Kw6TUCpzXJAx4MwlVD6CH+Mu6fi8rfAQIQfqdFZ4jtDsEkWig==} - engines: {node: '>=0.10.0'} + /screenfull/6.0.2: + resolution: {integrity: sha512-AQdy8s4WhNvUZ6P8F6PB21tSPIYKniic+Ogx0AacBMjKP1GUHN2E9URxQHtCusiwxudnCKkdy4GrHXPPJSkCCw==} + engines: {node: ^14.13.1 || >=16.0.0} dev: false /script-loader/0.7.2: @@ -17934,6 +18478,10 @@ packages: is-fullwidth-code-point: 2.0.0 dev: false + /slide/1.1.6: + resolution: {integrity: sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==} + dev: false + /snapdragon-node/2.1.1: resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} engines: {node: '>=0.10.0'} @@ -18110,6 +18658,17 @@ packages: engines: {node: '>= 0.10'} dev: false + /spawn-wrap/1.4.3: + resolution: {integrity: sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==} + dependencies: + foreground-child: 1.5.6 + mkdirp: 0.5.6 + os-homedir: 1.0.2 + rimraf: 2.7.1 + signal-exit: 3.0.7 + which: 1.3.1 + dev: false + /spdx-correct/3.1.1: resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} dependencies: @@ -18605,6 +19164,13 @@ packages: engines: {node: '>=0.8.0'} dev: false + /supports-color/3.2.3: + resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} + engines: {node: '>=0.8.0'} + dependencies: + has-flag: 1.0.0 + dev: false + /supports-color/5.4.0: resolution: {integrity: sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==} engines: {node: '>=4'} @@ -18827,6 +19393,16 @@ packages: source-map-support: 0.5.21 dev: false + /test-exclude/4.2.3: + resolution: {integrity: sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA==} + dependencies: + arrify: 1.0.1 + micromatch: 2.3.11 + object-assign: 4.1.1 + read-pkg-up: 1.0.1 + require-main-filename: 1.0.1 + dev: false + /test-exclude/6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -19065,6 +19641,11 @@ packages: escape-string-regexp: 1.0.5 dev: false + /trim-right/1.0.1: + resolution: {integrity: sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==} + engines: {node: '>=0.10.0'} + dev: false + /trim-trailing-lines/1.1.4: resolution: {integrity: sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==} dev: false @@ -19313,6 +19894,13 @@ packages: uglify-to-browserify: 1.0.2 dev: false + /uglify-js/3.17.4: + resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + engines: {node: '>=0.8.0'} + hasBin: true + dev: false + optional: true + /uglify-to-browserify/1.0.2: resolution: {integrity: sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==} dev: false @@ -20418,6 +21006,10 @@ packages: engines: {node: '>=0.4.0'} dev: false + /wordwrap/1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + dev: false + /workbox-background-sync/6.5.4: resolution: {integrity: sha512-0r4INQZMyPky/lj4Ou98qxcThrETucOde+7mRGJl13MPJugQNKeZQOdIJe/1AchOP23cTqHcN/YVpD6r8E6I8g==} dependencies: @@ -20620,6 +21212,14 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: false + /write-file-atomic/1.3.4: + resolution: {integrity: sha512-SdrHoC/yVBPpV0Xq/mUZQIpW2sWXAShb/V4pomcJXh92RuaO+f3UTWItiR3Px+pLnV2PvC2/bfn5cwr5X6Vfxw==} + dependencies: + graceful-fs: 4.2.10 + imurmurhash: 0.1.4 + slide: 1.1.6 + dev: false + /write-file-atomic/3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} dependencies: @@ -20731,6 +21331,10 @@ packages: engines: {node: '>=10'} dev: false + /yallist/2.1.2: + resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} + dev: false + /yallist/3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} dev: false @@ -20764,6 +21368,35 @@ packages: object.assign: 4.1.4 dev: false + /yargs-parser/8.1.0: + resolution: {integrity: sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==} + dependencies: + camelcase: 4.1.0 + dev: false + + /yargs-parser/9.0.2: + resolution: {integrity: sha512-CswCfdOgCr4MMsT1GzbEJ7Z2uYudWyrGX8Bgh/0eyCzj/DXWdKq6a/ADufkzI1WAOIW6jYaXJvRyLhDO0kfqBw==} + dependencies: + camelcase: 4.1.0 + dev: false + + /yargs/11.1.0: + resolution: {integrity: sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==} + dependencies: + cliui: 4.1.0 + decamelize: 1.2.0 + find-up: 2.1.0 + get-caller-file: 1.0.3 + os-locale: 2.1.0 + require-directory: 2.1.1 + require-main-filename: 1.0.1 + set-blocking: 2.0.0 + string-width: 2.1.1 + which-module: 2.0.0 + y18n: 3.2.2 + yargs-parser: 9.0.2 + dev: false + /yargs/15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} @@ -21013,7 +21646,7 @@ packages: dev: false file:projects/bemuse.tgz: - resolution: {integrity: sha512-QeF3Zx3Pd3cMQxIJ3e08RkcDyuW03RrvbU9b9BOa+tkTWrFINdaITOP4ATeBWI9ZO7n/wVTiDYXf5tJBmYMxMA==, tarball: file:projects/bemuse.tgz} + resolution: {integrity: sha512-Nrx/Wc1h9DSYM9qHO51g5hP9ZW/UayUVCxoz1e2CBdls8HHSbI4HRca04kP2V0O92aGHnNeAmA8Br3zIh9mUgg==, tarball: file:projects/bemuse.tgz} name: '@rush-temp/bemuse' version: 0.0.0 dependencies: @@ -21030,6 +21663,7 @@ packages: '@types/chai': 4.3.4 '@types/eslint': 4.16.8 '@types/invariant': 2.2.35 + '@types/jquery': 3.5.16 '@types/lodash': 4.14.191 '@types/markdown-it': 12.2.3 '@types/minimatch': 3.0.5 @@ -21134,7 +21768,7 @@ packages: rxjs: 7.8.0 sass: 1.57.1 sass-loader: 13.2.0_sass@1.57.1+webpack@5.75.0 - screenfull: 3.3.3 + screenfull: 6.0.2 script-loader: 0.7.2 service-worker-webpack: 0.0.11_webpack@5.75.0 sinon: 6.3.5