Full Code of boardgameio/boardgame.io for AI

main 4f3c90df0d89 cached
332 files
3.8 MB
1.0M tokens
9131 symbols
1 requests
Download .txt
Showing preview only (3,996K chars total). Download the full file or copy to clipboard to get everything.
Repository: boardgameio/boardgame.io
Branch: main
Commit: 4f3c90df0d89
Files: 332
Total size: 3.8 MB

Directory structure:
gitextract_hy_6v4bz/

├── .devcontainer/
│   ├── Dockerfile
│   └── devcontainer.json
├── .empty_module.js
├── .eslintignore
├── .eslintrc
├── .github/
│   ├── FUNDING.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── npm-publish.yml
│       └── test.yml
├── .gitignore
├── .lintstagedrc
├── .prettierignore
├── .prettierrc
├── AUTHORS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── babel.config.js
├── benchmark/
│   └── index.js
├── docs/
│   ├── CNAME
│   ├── documentation/
│   │   ├── .nojekyll
│   │   ├── CHANGELOG.md
│   │   ├── api/
│   │   │   ├── Client.md
│   │   │   ├── Game.md
│   │   │   ├── Lobby.md
│   │   │   └── Server.md
│   │   ├── chat.md
│   │   ├── concepts.md
│   │   ├── debugging.md
│   │   ├── deployment.md
│   │   ├── events.md
│   │   ├── immutability.md
│   │   ├── index.html
│   │   ├── multiplayer.md
│   │   ├── notable_projects.md
│   │   ├── phases.md
│   │   ├── plugins.md
│   │   ├── random.md
│   │   ├── secret-state.md
│   │   ├── sidebar.md
│   │   ├── snippets/
│   │   │   ├── example-1/
│   │   │   │   └── index.html
│   │   │   ├── example-1.c952ec6d.js
│   │   │   ├── example-2/
│   │   │   │   └── index.html
│   │   │   ├── example-2.e4675089.js
│   │   │   ├── example-3/
│   │   │   │   └── index.html
│   │   │   ├── example-3.1fa4f5db.js
│   │   │   ├── multiplayer/
│   │   │   │   └── index.html
│   │   │   ├── multiplayer.54b541fd.js
│   │   │   ├── phases-1/
│   │   │   │   └── index.html
│   │   │   ├── phases-1.0d4500d6.js
│   │   │   ├── phases-1.490dcd4c.css
│   │   │   ├── phases-2/
│   │   │   │   └── index.html
│   │   │   ├── phases-2.a59f38ac.js
│   │   │   ├── phases-2.fa21cb61.css
│   │   │   ├── stages-1/
│   │   │   │   └── index.html
│   │   │   ├── stages-1.1524ef02.js
│   │   │   └── stages-1.bcf7ab84.css
│   │   ├── stages.md
│   │   ├── storage.md
│   │   ├── testing.md
│   │   ├── theme.css
│   │   ├── turn-order.md
│   │   ├── tutorial.md
│   │   ├── typescript.md
│   │   └── undo.md
│   ├── index.css
│   └── index.html
├── examples/
│   ├── react-native/
│   │   ├── .gitignore
│   │   ├── .watchmanconfig
│   │   ├── App.js
│   │   ├── README.md
│   │   ├── app.json
│   │   ├── board.js
│   │   ├── game.js
│   │   ├── package.json
│   │   └── rn-cli.config.js
│   ├── react-web/
│   │   ├── .gitignore
│   │   ├── package.json
│   │   ├── server.js
│   │   └── src/
│   │       ├── app.css
│   │       ├── app.js
│   │       ├── app.test.js
│   │       ├── chess/
│   │       │   ├── board.js
│   │       │   ├── chat.js
│   │       │   ├── checkerboard.js
│   │       │   ├── checkerboard.test.js
│   │       │   ├── game.js
│   │       │   ├── grid.js
│   │       │   ├── index.js
│   │       │   ├── multiplayer.js
│   │       │   ├── pieces/
│   │       │   │   ├── CREDITS
│   │       │   │   ├── bishop.js
│   │       │   │   ├── king.js
│   │       │   │   ├── knight.js
│   │       │   │   ├── pawn.js
│   │       │   │   ├── queen.js
│   │       │   │   └── rook.js
│   │       │   ├── singleplayer.js
│   │       │   └── token.js
│   │       ├── index.html
│   │       ├── index.js
│   │       ├── li-navlink.js
│   │       ├── lobby/
│   │       │   ├── index.js
│   │       │   ├── lobby.css
│   │       │   ├── lobby.js
│   │       │   └── routes.js
│   │       ├── random/
│   │       │   ├── board.js
│   │       │   ├── game.js
│   │       │   └── index.js
│   │       ├── redacted-move/
│   │       │   ├── board.css
│   │       │   ├── board.js
│   │       │   ├── game.js
│   │       │   ├── index.js
│   │       │   └── multiview.js
│   │       ├── routes.js
│   │       ├── secret-state/
│   │       │   ├── board.css
│   │       │   ├── board.js
│   │       │   ├── game.js
│   │       │   ├── index.js
│   │       │   └── multiview.js
│   │       ├── simulator/
│   │       │   ├── example-all-once.js
│   │       │   ├── example-all.js
│   │       │   ├── example-others-once.js
│   │       │   ├── example-others.js
│   │       │   ├── index.js
│   │       │   ├── simulator.css
│   │       │   └── simulator.js
│   │       ├── threejs/
│   │       │   ├── index.js
│   │       │   └── main.css
│   │       ├── tic-tac-toe/
│   │       │   ├── advanced-ai.js
│   │       │   ├── authenticated.js
│   │       │   ├── board.css
│   │       │   ├── board.js
│   │       │   ├── bots.js
│   │       │   ├── game.js
│   │       │   ├── index.js
│   │       │   ├── multiplayer.js
│   │       │   ├── singleplayer.js
│   │       │   └── spectator.js
│   │       └── undo/
│   │           ├── board.js
│   │           ├── game.js
│   │           └── index.js
│   └── snippets/
│       ├── .gitignore
│       ├── README.md
│       ├── install.sh
│       ├── package.json
│       └── src/
│           ├── example-1/
│           │   ├── index.html
│           │   └── index.js
│           ├── example-2/
│           │   ├── index.html
│           │   └── index.js
│           ├── example-3/
│           │   ├── index.html
│           │   └── index.js
│           ├── multiplayer/
│           │   ├── index.html
│           │   └── index.js
│           ├── phases-1/
│           │   ├── App.svelte
│           │   ├── Player.svelte
│           │   ├── game.js
│           │   ├── index.html
│           │   └── index.js
│           ├── phases-2/
│           │   ├── App.svelte
│           │   ├── Player.svelte
│           │   ├── game.js
│           │   ├── index.html
│           │   └── index.js
│           └── stages-1/
│               ├── App.svelte
│               ├── Player.svelte
│               ├── game.js
│               ├── index.html
│               └── index.js
├── integration/
│   ├── .gitignore
│   ├── README.md
│   ├── package.json
│   ├── public/
│   │   └── index.html
│   └── src/
│       ├── App.css
│       ├── App.js
│       ├── App.test.js
│       ├── board.css
│       ├── board.js
│       ├── game.js
│       ├── index.css
│       └── index.js
├── package.json
├── packages/
│   ├── ai.ts
│   ├── client.ts
│   ├── core.ts
│   ├── debug.ts
│   ├── internal.ts
│   ├── main.js
│   ├── master.ts
│   ├── multiplayer.ts
│   ├── plugins.ts
│   ├── react-native.ts
│   ├── react.ts
│   ├── server.ts
│   └── testing.ts
├── python/
│   ├── .gitignore
│   ├── boardgameio.py
│   ├── examples/
│   │   └── tic-tac-toe/
│   │       └── tictactoebot.py
│   └── test_boardgameio.py
├── roadmap.md
├── rollup.config.js
├── scripts/
│   ├── changelog.js
│   ├── clean.js
│   ├── dev-client.js
│   ├── install-examples.js
│   ├── integration.js
│   └── proxy-dirs.js
├── src/
│   ├── ai/
│   │   ├── ai.test.ts
│   │   ├── ai.ts
│   │   ├── bot.ts
│   │   ├── mcts-bot.ts
│   │   └── random-bot.ts
│   ├── client/
│   │   ├── client.test.ts
│   │   ├── client.ts
│   │   ├── debug/
│   │   │   ├── Debug.svelte
│   │   │   ├── Menu.svelte
│   │   │   ├── ai/
│   │   │   │   ├── AI.svelte
│   │   │   │   └── Options.svelte
│   │   │   ├── info/
│   │   │   │   ├── Info.svelte
│   │   │   │   └── Item.svelte
│   │   │   ├── log/
│   │   │   │   ├── Log.svelte
│   │   │   │   ├── LogEvent.svelte
│   │   │   │   ├── LogMetadata.svelte
│   │   │   │   ├── PhaseMarker.svelte
│   │   │   │   └── TurnMarker.svelte
│   │   │   ├── main/
│   │   │   │   ├── ClientSwitcher.svelte
│   │   │   │   ├── Controls.svelte
│   │   │   │   ├── Hotkey.svelte
│   │   │   │   ├── InteractiveFunction.svelte
│   │   │   │   ├── Main.svelte
│   │   │   │   ├── Move.svelte
│   │   │   │   └── PlayerInfo.svelte
│   │   │   ├── mcts/
│   │   │   │   ├── Action.svelte
│   │   │   │   ├── MCTS.svelte
│   │   │   │   └── Table.svelte
│   │   │   ├── tests/
│   │   │   │   ├── JSONTree.mock.svelte
│   │   │   │   └── debug.test.ts
│   │   │   └── utils/
│   │   │       ├── shortcuts.js
│   │   │       └── shortcuts.test.js
│   │   ├── manager.ts
│   │   ├── react-native.js
│   │   ├── react-native.test.js
│   │   ├── react.ssr.test.tsx
│   │   ├── react.test.tsx
│   │   ├── react.tsx
│   │   └── transport/
│   │       ├── dummy.ts
│   │       ├── local.test.ts
│   │       ├── local.ts
│   │       ├── socketio.test.ts
│   │       ├── socketio.ts
│   │       ├── transport.test.ts
│   │       └── transport.ts
│   ├── core/
│   │   ├── action-creators.ts
│   │   ├── action-types.ts
│   │   ├── backwards-compatibility.ts
│   │   ├── constants.ts
│   │   ├── errors.ts
│   │   ├── flow.test.ts
│   │   ├── flow.ts
│   │   ├── game-methods.ts
│   │   ├── game.test.ts
│   │   ├── game.ts
│   │   ├── initialize.ts
│   │   ├── logger.test.js
│   │   ├── logger.ts
│   │   ├── player-view.test.ts
│   │   ├── player-view.ts
│   │   ├── reducer.test.ts
│   │   ├── reducer.ts
│   │   ├── turn-order.test.ts
│   │   └── turn-order.ts
│   ├── lobby/
│   │   ├── client.test.ts
│   │   ├── client.ts
│   │   ├── connection.test.ts
│   │   ├── connection.ts
│   │   ├── create-match-form.tsx
│   │   ├── login-form.tsx
│   │   ├── match-instance.tsx
│   │   ├── react.ssr.test.tsx
│   │   ├── react.test.tsx
│   │   └── react.tsx
│   ├── master/
│   │   ├── filter-player-view.test.ts
│   │   ├── filter-player-view.ts
│   │   ├── master.test.ts
│   │   └── master.ts
│   ├── plugins/
│   │   ├── events/
│   │   │   ├── events.test.ts
│   │   │   └── events.ts
│   │   ├── main.test.ts
│   │   ├── main.ts
│   │   ├── plugin-events.ts
│   │   ├── plugin-immer.test.ts
│   │   ├── plugin-immer.ts
│   │   ├── plugin-log.test.ts
│   │   ├── plugin-log.ts
│   │   ├── plugin-player.test.ts
│   │   ├── plugin-player.ts
│   │   ├── plugin-random.ts
│   │   ├── plugin-serializable.test.ts
│   │   ├── plugin-serializable.ts
│   │   └── random/
│   │       ├── random.alea.ts
│   │       ├── random.test.ts
│   │       └── random.ts
│   ├── server/
│   │   ├── api.test.ts
│   │   ├── api.ts
│   │   ├── auth.test.ts
│   │   ├── auth.ts
│   │   ├── cors.test.ts
│   │   ├── cors.ts
│   │   ├── db/
│   │   │   ├── base.ts
│   │   │   ├── flatfile.test.ts
│   │   │   ├── flatfile.ts
│   │   │   ├── index.test.ts
│   │   │   ├── index.ts
│   │   │   ├── inmemory.test.ts
│   │   │   ├── inmemory.ts
│   │   │   ├── localstorage.test.ts
│   │   │   └── localstorage.ts
│   │   ├── index.test.ts
│   │   ├── index.ts
│   │   ├── transport/
│   │   │   ├── pubsub/
│   │   │   │   ├── generic-pub-sub.ts
│   │   │   │   ├── in-memory-pub-sub.test.ts
│   │   │   │   └── in-memory-pub-sub.ts
│   │   │   ├── socketio-simultaneous.test.ts
│   │   │   ├── socketio.test.ts
│   │   │   └── socketio.ts
│   │   └── util.ts
│   ├── testing/
│   │   ├── mock-random.test.ts
│   │   └── mock-random.ts
│   └── types.ts
├── subpackages.js
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .devcontainer/Dockerfile
================================================
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.191.1/containers/typescript-node/.devcontainer/base.Dockerfile

# [Choice] Node.js version: 16, 14, 12
ARG VARIANT="16-buster"
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-${VARIANT}

# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
#     && apt-get -y install --no-install-recommends <your-package-list-here>

# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"

# [Optional] Uncomment if you want to install more global node packages
# RUN su node -c "npm install -g <your-package-list -here>"


================================================
FILE: .devcontainer/devcontainer.json
================================================
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.191.1/containers/typescript-node
{
  "name": "Node.js & TypeScript",
  "build": {
    "dockerfile": "Dockerfile",
    // Update 'VARIANT' to pick a Node version: 12, 14, 16
    "args": {
      "VARIANT": "16"
    }
  },

  // Set *default* container specific settings.json values on container create.
  "settings": {},

  // Add the IDs of extensions you want installed when the container is created.
  "extensions": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "dsznajder.es7-react-js-snippets",
    "eamodio.gitlens",
    "github.vscode-pull-request-github"
  ],

  // Use 'forwardPorts' to make a list of ports inside the container available locally.
  "forwardPorts": [3000, 8000],

  // Use 'postCreateCommand' to run commands after the container is created.
  "postCreateCommand": "npm ci",

  // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
  "remoteUser": "node"
}


================================================
FILE: .empty_module.js
================================================
/*
 * Copyright 2017 The boardgame.io Authors.
 *
 * Use of this source code is governed by a MIT-style
 * license that can be found in the LICENSE file or at
 * https://opensource.org/licenses/MIT.
 */

import React from 'react';

const Null = () => null;

export default Null;


================================================
FILE: .eslintignore
================================================
examples/
dist/
node_modules/
coverage/
npm/
docs/
integration/


================================================
FILE: .eslintrc
================================================
extends:
- eslint:recommended
- plugin:jest/recommended
- plugin:unicorn/recommended
- plugin:react/recommended
- plugin:@typescript-eslint/recommended
- plugin:prettier/recommended

plugins:
- "@typescript-eslint"

parser: "@typescript-eslint/parser"

env:
  node: true
  browser: true
  es6: true

rules:
  # eslint
  no-console: off
  prefer-const:
    - error
    - destructuring: all

  # plugin:unicorn
  unicorn/consistent-function-scoping: off
  unicorn/no-array-for-each: off
  unicorn/no-array-reduce: off
  unicorn/no-fn-reference-in-iterator: off
  unicorn/no-null: off
  unicorn/no-reduce: off
  unicorn/no-useless-undefined: off
  unicorn/prevent-abbreviations: off

  # plugin:@typescript-eslint
  "@typescript-eslint/consistent-type-imports": error
  "@typescript-eslint/explicit-module-boundary-types": off
  "@typescript-eslint/no-empty-function": off
  "@typescript-eslint/no-explicit-any": off
  "@typescript-eslint/no-namespace": off
  "@typescript-eslint/no-unused-vars":
    - warn
    - args: after-used
      ignoreRestSiblings: true
  "@typescript-eslint/no-var-requires": off

settings:
  react:
    version: detect


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [boardgameio]
open_collective: boardgameio


================================================
FILE: .github/pull_request_template.md
================================================
#### Checklist

- [ ] Use a separate branch in your local repo (not `main`).
- [ ] Test coverage is 100% (or you have a story for why it's ok).


================================================
FILE: .github/workflows/npm-publish.yml
================================================
name: Publish

on:
  push:
    tags: [ 'v0.[0-9]+.[0-9]+' ]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Use Node v12
        uses: actions/setup-node@v1
        with:
          node-version: 12

      - name: Install Dependencies
        run: npm ci

      - name: Run Tests
        run: |
          npm run lint
          npm run test

      - name: Publish to NPM
        id: publish
        uses: JS-DevTools/npm-publish@v1
        with:
          token: ${{ secrets.NPM_TOKEN }}

      - name: Version already published
        if: steps.publish.outputs.type == 'none'
        run: |
          echo "Version ${{ steps.publish.outputs.old-version }} already exists."

      - name: New version published
        if: steps.publish.outputs.type != 'none'
        run: |
          echo "New ${{ steps.publish.outputs.type }} version ${{ steps.publish.outputs.version }} published. Was ${{ steps.publish.outputs.old-version }}."


================================================
FILE: .github/workflows/test.yml
================================================
name: Tests

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  unit:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [10.x, 12.x, 14.x, 16.x]

    steps:
    - uses: actions/checkout@v2
      
    - name: Use Node v${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}

    - name: Install Dependencies
      run: npm install

    - name: Run Tests
      run: |
        npm run lint
        npm run test:coverage

    - name: Coveralls
      uses: coverallsapp/github-action@master
      with:
        github-token: ${{ secrets.GITHUB_TOKEN }}

  integration:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [10.x, 12.x, 14.x, 16.x]

    steps:
    - uses: actions/checkout@v2
      
    - name: Use Node v${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}

    - name: Install Dependencies
      run: npm install

    - name: Run Integration Test
      run: npm run test:integration


================================================
FILE: .gitignore
================================================
.cache
yarn.lock
.DS_Store
*.swp
npm-debug.log*
dist
node_modules
coverage
.coveralls.yml
.npm
npm
.idea/
.vscode/*
.rpt2_cache/
.rush/

================================================
FILE: .lintstagedrc
================================================
{
  "*.{ts,js,css,md}": "prettier --write"
}


================================================
FILE: .prettierignore
================================================
*.bundle.js
*.min.js
node_modules
dist
Game.md
package.json
docs


================================================
FILE: .prettierrc
================================================
{
  "printWidth": 80,
  "singleQuote": true,
}


================================================
FILE: AUTHORS
================================================
# List of contributors. This is by no means meant to be
# comprehensive (git history is a good way to get the
# exhaustive list). Feel free to add your name here whenever
# you send a Pull Request, though.

Nicolo John Davis
Google Inc.
Saeid Alidadi
Lee Allen
Vinicius Felizardo
Joshua Christman
Selim Ajimi
Robert Sandu
Rifat Nabi
Satana Charuwichitratana
Pete Nykänen
Philihp Busby
Jason Harrison
Brendon Roberto
Luca Vallisa


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Community Guidelines

A safe, respectful, productive and collaborative environment is important for the boardgame.io community. These guidelines apply to all community communications channels (such as the official Gitter group, GitHub issues and pull requests etc.).

1. Be welcoming to all. Help newcomers with questions about the project (even if these are answered elsewhere).

1. Do not make personal attacks or disparaging personal remarks.

1. When interpreting the words and actions of others, assume good faith and intentions.

1. Do not engage in harassing or bullying behavior of any kind.

## What to do if you see a violation of these guidelines

You may do either or both of the following:

1. Politely message the perpetrator to steer them in the right direction.

1. Contact a moderator privately (or email moderators@boardgame.io) to report bad behavior and request intervention.

Moderators will encourage better behavior or issue a warning as appropriate. Further action (like banning a member) may be necessary as a last resort when other measures fail.

## Moderators

- Chris Swithinbank


================================================
FILE: CONTRIBUTING.md
================================================
# How to Contribute

## Finding things to contribute to

Please use the [Issue Tracker](https://github.com/boardgameio/boardgame.io/issues) to discuss
potential improvements you want to make before sending a Pull Request.
The [roadmap](roadmap.md) is probably the best place to find areas where help would
most be appreciated.

The Issue Tracker may contain items labelled [**good first issue**][gfi] or [**help wanted**][hw] from time to time.

[hw]: https://github.com/boardgameio/boardgame.io/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+
[gfi]: https://github.com/boardgameio/boardgame.io/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22

## Pull Requests

[Pull Requests](https://help.github.com/articles/about-pull-requests/) are used for contributions. Code must be well-tested and not decrease the test coverage significantly.

#### Use a separate branch (not `main`)

Please commit changes to a separate branch in your fork
so that we can work together making changes to it before it
is ready to be merged. Name your branch something like
`<username>/feature`.

Once you are ready, you can create a Pull Request for it to be
merged into the `main` branch in this repo.

#### Testing

The following commands must pass for a Pull Request to be considered:

```
$ npm test
$ npm run lint
```

You can also check the test coverage by running:

```
$ npm run test:coverage
```

#### If you make changes to the docs

Use the following command to preview them:

```
$ npm run docs
```

## VS Code remote dev container support

For minimal effort, the repository is configured to run in a remote dev container from VS Code.

- No need to install Node.js or any other project-specific tooling and dependencies
- No risk of your local machine environment getting in the way
- Consistent development environment no matter what OS is used
- Useful extensions preinstalled in the container, independent of your local VS Code settings

### Prerequisites

- [VS Code](https://code.visualstudio.com/) + [Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) extension
- [git](https://git-scm.com/)
- [Docker](https://www.docker.com/)

### Getting started

- Launch VS Code
- Click the Remote Development icon in the bottom left corner of the UI, then "Clone repository in Container Volume..."
- Paste `https://github.com/boardgameio/boardgame.io` or use your own fork, any branch, or a pull request
- The container will start up and install all required dependencies automatically
- Terminal output will cease when everything is set up and ready to go

### Running the examples from the VS Code Explorer

- Open "NPM Scripts" panel in the sidebar
- Click on `package.json > start`

If the NPM scripts panel is not visible in the Explorer sidebar, open the Explorer settings (3 dots) and check "NPM Scripts".


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2017 The boardgame.io Authors.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<p align="center">
  <a href="https://boardgame.io/">
    <img src="https://raw.githubusercontent.com/boardgameio/boardgame.io/main/docs/logo-optimized.svg?sanitize=true" alt="boardgame.io" />
  </a>
</p>

<p align="center">
<a href="https://www.npmjs.com/package/boardgame.io"><img src="https://badge.fury.io/js/boardgame.io.svg" alt="npm version" /></a>
<a href="https://github.com/boardgameio/boardgame.io/actions?query=workflow%3ATests"> <img src="https://github.com/boardgameio/boardgame.io/workflows/Tests/badge.svg" alt='Build Status'></a>
<a href='https://coveralls.io/github/boardgameio/boardgame.io?branch=main'><img src='https://coveralls.io/repos/github/boardgameio/boardgame.io/badge.svg?branch=main' alt='Coverage Status' /></a>
<a href="https://gitter.im/boardgame-io"><img src="https://badges.gitter.im/boardgame-io.svg" alt="Gitter" /></a>
</p>

<p align="center">
  <strong><a href="https://boardgame.io/documentation/#/">Read the Documentation</a></strong>
</p>

<p align="center">
  <strong>boardgame.io</strong> is an engine for creating turn-based games using JavaScript.
</p>

Write simple functions that describe how the game state changes
when a particular move is made. This is automatically converted
into a playable game complete with online multiplayer
features, all without requiring you to write a single line of
networking or storage code.

### Features

- **State Management**: Game state is managed seamlessly across clients, server and storage automatically.
- **Multiplayer**: Game state is kept in sync in realtime and across platforms.
- **AI**: Automatically generated bots that can play your game.
- **Game Phases**: with different game rules and turn orders per phase.
- **Lobby**: Player matchmaking and game creation.
- **Prototyping**: Interface to simulate moves even before you render the game.
- **Extendable**: Plugin system that allows creating new abstractions.
- **View-layer Agnostic**: Use the vanilla JS client or the bindings for React / React Native.
- **Logs**: Game logs with the ability to time travel (viewing the board at an earlier state).

## Usage

### Installation

```sh
npm install boardgame.io
```

### Documentation

Read our [Full Documentation](https://boardgame.io/documentation/) to learn how to
use boardgame.io, and join the [community on gitter](https://gitter.im/boardgame-io/General)
to ask your questions!

### Running examples in this repository

```sh
npm install
npm start
```

The examples can be found in the [examples](examples/) folder.

#### Using VS Code?

This repository is ready to run in a dev container in VS Code. See [the contributing guidelines for details](CONTRIBUTING.md).

## Changelog

See [changelog](docs/documentation/CHANGELOG.md).

## Get involved

We welcome contributions of all kinds!
Please take a moment to review our [Code of Conduct](CODE_OF_CONDUCT.md).

🐛 **Found a bug?**  
Let us know by [creating an issue][new-issue].

❓ **Have a question?**  
Our [Gitter channel][gitter] and [GitHub Discussions][discussions]
are good places to start.

⚙️ **Interested in fixing a [bug][bugs] or adding a [feature][features]?**  
Check out the [contributing guidelines](CONTRIBUTING.md)
and the [project roadmap](roadmap.md).

📖 **Can we improve [our documentation][docs]?**  
Pull requests even for small changes can be helpful. Each page in the
docs can be edited by clicking the “Edit on GitHub” link at the top right.

[new-issue]: https://github.com/boardgameio/boardgame.io/issues/new/choose
[gitter]: https://gitter.im/boardgame-io/General
[discussions]: https://github.com/boardgameio/boardgame.io/discussions
[bugs]: https://github.com/boardgameio/boardgame.io/issues?q=is%3Aissue+is%3Aopen+label%3Abug
[features]: https://github.com/boardgameio/boardgame.io/issues?q=is%3Aissue+is%3Aopen+label%3Afeature
[docs]: https://boardgame.io/documentation/
[sponsors]: https://github.com/sponsors/boardgameio
[collective]: https://opencollective.com/boardgameio#support

## License

[MIT](LICENSE)


================================================
FILE: babel.config.js
================================================
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        modules: false,
        exclude: ['transform-regenerator', 'transform-async-to-generator'],
      },
    ],
    '@babel/preset-react',
    '@babel/typescript',
  ],
  env: {
    test: {
      plugins: ['@babel/plugin-transform-modules-commonjs'],
    },
  },
  plugins: [
    [
      'module-resolver',
      {
        alias: {
          'boardgame.io': './packages',
        },
      },
    ],
    '@babel/plugin-proposal-class-properties',
    '@babel/proposal-object-rest-spread',
  ],
};


================================================
FILE: benchmark/index.js
================================================
/*
 * Copyright 2019 The boardgame.io Authors
 *
 * Use of this source code is governed by a MIT-style
 * license that can be found in the LICENSE file or at
 * https://opensource.org/licenses/MIT.
 */

import Benchmark from 'benchmark';
import { Client } from '../dist/esm/client';
import { InitializeGame } from '../src/core/initialize';
import { CreateGameReducer } from '../src/core/reducer';
import { makeMove, gameEvent } from '../src/core/action-creators';

const game = {
  moves: {
    A: ({ G }) => G,
  },
  endIf: () => false,
};

const reducer = CreateGameReducer({ game });
const state = InitializeGame({ game });
const client = Client({ game });

new Benchmark.Suite()
  .add('reducer::makeMove', function () {
    reducer(state, makeMove('A'));
  })
  .add('reducer::endTurn', function () {
    reducer(state, gameEvent('endTurn'));
  })
  .add('client::move', function () {
    client.moves.A();
  })
  .add('client::endTurn', function () {
    client.events.endTurn();
  })
  .on('cycle', function (event) {
    console.log(String(event.target));
  })
  .on('complete', function () {
    console.log('Fastest is ' + this.filter('fastest').map('name'));
  })
  .run({ async: true });


================================================
FILE: docs/CNAME
================================================
boardgame.io

================================================
FILE: docs/documentation/.nojekyll
================================================


================================================
FILE: docs/documentation/CHANGELOG.md
================================================
### v0.50.2

This release includes dependency upgrades only.

### v0.50.1

This release fixes compatibility with React v18. Thanks [@mbrinkl](https://github.com/mbrinkl)!

#### Bugfixes

* [[2afffb13](https://github.com/boardgameio/boardgame.io/commit/2afffb13)] Fix React 18 compatibility ([#1104](https://github.com/boardgameio/boardgame.io/pull/1104))
* [[74722165](https://github.com/boardgameio/boardgame.io/commit/74722165)] Use correct CSS margin syntax in debug panel


## v0.50.0

This release includes a large refactor in boardgame.io API. Callbacks that used to be `(G, ctx) => {}` now becomes `({ G, ctx }) => {}` ... Thanks [@delucis](https://github.com/delucis) for the great contribution!

### Features

* [[da1ccb1](https://github.com/boardgameio/boardgame.io/commit/da1ccb18819fa265144da075a445e003d8a2fcc8)] feat: Change move and hook signature ([#891](https://github.com/boardgameio/boardgame.io/pull/891))

### v0.49.13

### Features

* [[aa99a9c](https://github.com/boardgameio/boardgame.io/commit/aa99a9cce28012cb747fa6db8b3f8ad73c28be0a)] feat: Conditional log redacting in long form move ([#1089](https://github.com/boardgameio/boardgame.io/pull/1089))
* [[4bf203c](https://github.com/boardgameio/boardgame.io/commit/4bf203c1c1ec42e3193935a39e4cfb54a5658627)] TypeScript: AiEnumerate return type ([#1080](https://github.com/boardgameio/boardgame.io/pull/1080))

### v0.49.12

#### Bugfixes

* [[96b26bb9](https://github.com/boardgameio/boardgame.io/commit/96b26bb9)] lobby: block creation of matches with invalid player counts ([#1060](https://github.com/boardgameio/boardgame.io/pull/1060))
* [[453f530c](https://github.com/boardgameio/boardgame.io/commit/453f530c)] types: Use correct socket.io options typing
* [[3692199](https://github.com/boardgameio/boardgame.io/commit/3692199), [1e57a9c](https://github.com/boardgameio/boardgame.io/commit/1e57a9c)] Update dependencies: socket.io and koa-body


### v0.49.11

#### Bugfixes

* [[453f530c](https://github.com/boardgameio/boardgame.io/commit/453f530c)] types: Use correct socket.io options typing
* [[7e55d118](https://github.com/boardgameio/boardgame.io/commit/7e55d118), [75428111](https://github.com/boardgameio/boardgame.io/commit/75428111), [4fa2c4f1](https://github.com/boardgameio/boardgame.io/commit/4fa2c4f1), [52450607](https://github.com/boardgameio/boardgame.io/commit/52450607)] Update dependencies: engine.io, nanoid, ajv, and node-fetch


### v0.49.10

#### Bugfixes

* [[6756419a](https://github.com/boardgameio/boardgame.io/commit/6756419a)] Include `testing/package.json` in npm files


### v0.49.9

#### Features

* [[636ce8f6](https://github.com/boardgameio/boardgame.io/commit/636ce8f6)] Add testing utility for mocking the randomness API

#### Bugfixes

* [[99639c41](https://github.com/boardgameio/boardgame.io/commit/99639c41)] lobby: only poll matches when match list is displayed ([#1044](https://github.com/boardgameio/boardgame.io/pull/1044))


### v0.49.8

#### Features

* [[bd34bc39](https://github.com/boardgameio/boardgame.io/commit/bd34bc39)] debug: Add collapse on load & hide toggle button options (PR [#1040](https://github.com/boardgameio/boardgame.io/pull/1040), Issue [#1039](https://github.com/boardgameio/boardgame.io/issues/1039))

#### Bugfixes

* [[ee230c14](https://github.com/boardgameio/boardgame.io/commit/ee230c14)] types: Always allow player ID array as active players argument (Issue [#1041](https://github.com/boardgameio/boardgame.io/issues/1041))


### v0.49.7

#### Bugfixes

* [[39e1f187](https://github.com/boardgameio/boardgame.io/commit/39e1f187)] Bump `rfc6902` dependency to address prototype pollution vulnerability


### v0.49.6

#### Bugfixes

* [[cf6ade54](https://github.com/boardgameio/boardgame.io/commit/cf6ade54)] Add `ctx` type parameter to client ([#1035](https://github.com/boardgameio/boardgame.io/pull/1035))


### v0.49.5

#### Bugfixes

* [[279a822f](https://github.com/boardgameio/boardgame.io/commit/279a822f)] flow: Pass correct `ctx` to `onMove` hooks


### v0.49.4

#### Features

* [[94472c0a](https://github.com/boardgameio/boardgame.io/commit/94472c0a)] react-native: handle multiplayer loading state in client ([#1026](https://github.com/boardgameio/boardgame.io/pull/1026))

#### Bugfixes

* [[43019562](https://github.com/boardgameio/boardgame.io/commit/43019562)] Update gameover metadata when `null` ([#1025](https://github.com/boardgameio/boardgame.io/pull/1025))


### v0.49.3

#### Bugfixes

* [[220823bb](https://github.com/boardgameio/boardgame.io/commit/220823bb)] Update gameover metadata when `undefined` ([#1023](https://github.com/boardgameio/boardgame.io/pull/1023))
* [[df6b7c40](https://github.com/boardgameio/boardgame.io/commit/df6b7c40)] include `chatMessages` property in React client types ([#1022](https://github.com/boardgameio/boardgame.io/pull/1022))


### v0.49.2

#### Features

* [[ff4c7564](https://github.com/boardgameio/boardgame.io/commit/ff4c7564)] core: Expose `ctx.playerID` in `onMove` hook ([#1019](https://github.com/boardgameio/boardgame.io/pull/1019))

#### Bugfixes

* [[fa7544f5](https://github.com/boardgameio/boardgame.io/commit/fa7544f5)] api: Update query string types and handle array queries
* [[4813fa15](https://github.com/boardgameio/boardgame.io/commit/4813fa15), [0f6076b5](https://github.com/boardgameio/boardgame.io/commit/0f6076b5), [06b4172d](https://github.com/boardgameio/boardgame.io/commit/06b4172d), [54c0b4c0](https://github.com/boardgameio/boardgame.io/commit/54c0b4c0)] Update dependencies

### v0.49.1

#### Features

* [[7b151798](https://github.com/boardgameio/boardgame.io/commit/7b151798)] Expose `getFilterPlayerView` from `internal` package

#### Bugfixes

* [[20817aa3](https://github.com/boardgameio/boardgame.io/commit/20817aa3)] transport: More accurately type `TransportOpts`


## v0.49.0

#### Features

* [[604d12e6](https://github.com/boardgameio/boardgame.io/commit/604d12e6)] lobby: use first available `playerID` when joining a match ([#1013](https://github.com/boardgameio/boardgame.io/pull/1013))
* [[510a082a](https://github.com/boardgameio/boardgame.io/commit/510a082a)] transport: Consolidate transport interface ([#1002](https://github.com/boardgameio/boardgame.io/pull/1002))
* [[d30d5776](https://github.com/boardgameio/boardgame.io/commit/d30d5776)] Expose `createMatch` utility

#### Bugfixes

* [[ca94f3a5](https://github.com/boardgameio/boardgame.io/commit/ca94f3a5)] lobby: Prevent error accessing fetch response twice ([#1005](https://github.com/boardgameio/boardgame.io/pull/1005))


## v0.48.0

#### Features

* [[4165d45d](https://github.com/boardgameio/boardgame.io/commit/4165d45d)] Deprecate `moveLimit` in favour of `minMoves`/`maxMoves` ([#985](https://github.com/boardgameio/boardgame.io/pull/985))

    Migration:
    
    - Replace `turn.moveLimit` with both `turn.minMoves` and `turn.maxMoves`.
    - Replace `moveLimit` in `setStage` and `setActivePlayers` with `maxMoves`.

### v0.47.10

#### Bugfixes

* [[ad78eded](https://github.com/boardgameio/boardgame.io/commit/ad78eded)] ai: Run AI iterations using `setImmediate` for improved performance ([#999](https://github.com/boardgameio/boardgame.io/pull/999))
* [[feb08a12](https://github.com/boardgameio/boardgame.io/commit/feb08a12)] lobby: Clean up & update refresh polling interval properly ([#996](https://github.com/boardgameio/boardgame.io/pull/996))


### v0.47.9

#### Bugfixes

* [[a240bbee](https://github.com/boardgameio/boardgame.io/commit/a240bbee)] client: Fix React Native support
* [[8b871ab5](https://github.com/boardgameio/boardgame.io/commit/8b871ab5)] server: Support custom Lobby API middleware ([#992](https://github.com/boardgameio/boardgame.io/pull/992))


### v0.47.8

#### Bugfixes

* [[06bc7479](https://github.com/boardgameio/boardgame.io/commit/06bc7479)] debug: Improve AI panel accessibility
* [[d2b611d7](https://github.com/boardgameio/boardgame.io/commit/d2b611d7)] debug: Stop panel intercepting clicks in transparent parts


### v0.47.7

#### Features

* [[98c860ec](https://github.com/boardgameio/boardgame.io/commit/98c860ec)] debug: Support toggling debug panel visibility without a keyboard ([#991](https://github.com/boardgameio/boardgame.io/pull/991))

#### Bugfixes

* [[f18c63a1](https://github.com/boardgameio/boardgame.io/commit/f18c63a1)] types: playerID in `playerView` can be string or null ([#990](https://github.com/boardgameio/boardgame.io/pull/990))


### v0.47.6

#### Bugfixes

* [[62f97e54](https://github.com/boardgameio/boardgame.io/commit/62f97e54)] Allow plugins to use events in `fnWrap`


### v0.47.5

#### Bugfixes

* [[fa30fcca](https://github.com/boardgameio/boardgame.io/commit/fa30fcca)] types: Expect `Game.setup` method to return `G` ([#987](https://github.com/boardgameio/boardgame.io/pull/987))


### v0.47.4

#### Bugfixes

* [[d54af1f4](https://github.com/boardgameio/boardgame.io/commit/d54af1f4)] events: Don’t use const enum for better backwards compatibility


### v0.47.3

* Dependency changes only

### v0.47.2

#### Features

* [[8267e36c](https://github.com/boardgameio/boardgame.io/commit/8267e36c)] events: Add stack traces to events plugin errors

### v0.47.1

#### Features

* [[f97a08d8](https://github.com/boardgameio/boardgame.io/commit/f97a08d8)] Improve events errors & expose method types to plugin `fnWrap` ([#980](https://github.com/boardgameio/boardgame.io/pull/980))  
  - See [the Events guide](events#calling-events-from-hooks) for details of event support in game hooks
* [[95be8b90](https://github.com/boardgameio/boardgame.io/commit/95be8b90)] events: Accurately type events API arguments

## v0.47.0

#### Features

* [[b6a4fed](https://github.com/boardgameio/boardgame.io/commit/b6a4fed)] Adds pub-sub support for horizontally scaling bgio server ([#978](https://github.com/boardgameio/boardgame.io/pull/978))

#### Bugfixes

* [[241701f](https://github.com/boardgameio/boardgame.io/commit/241701f)] master: Don’t crash on missing `chatMessage` ([#977](https://github.com/boardgameio/boardgame.io/pull/977))

### v0.46.2

#### Features

* [[064b7507](https://github.com/boardgameio/boardgame.io/commit/064b7507)] Support setting next phase with a function ([#972](https://github.com/boardgameio/boardgame.io/pull/972))

#### Bugfixes

* [[bff1d294](https://github.com/boardgameio/boardgame.io/commit/bff1d294)] flow: Run `turn.endIf` after `setActivePlayers` event

### v0.46.1

#### Bugfixes

* [[f0bc8b9](https://github.com/boardgameio/boardgame.io/commit/f0bc8b9)] flow: Run `turn.endIf` hook after updating stages

## v0.46.0

#### Features

* [[91cf25e](https://github.com/boardgameio/boardgame.io/commit/91cf25e)] Events Plugin: Don’t leak stage events across turns & allow self-ending turns/phases ([#957](https://github.com/boardgameio/boardgame.io/pull/957))
* [[afee0b7](https://github.com/boardgameio/boardgame.io/commit/afee0b7), [1e435c2](https://github.com/boardgameio/boardgame.io/commit/1e435c2), [1078b13](https://github.com/boardgameio/boardgame.io/commit/1078b13)] Allow plugins to declare an action invalid ([#963](https://github.com/boardgameio/boardgame.io/pull/963), [#970](https://github.com/boardgameio/boardgame.io/pull/970))
* [[262d867](https://github.com/boardgameio/boardgame.io/commit/262d867)] Server: Decouple player view calculation from Master ([#966](https://github.com/boardgameio/boardgame.io/pull/966))

#### Bugfixes

* [[dcaca7f](https://github.com/boardgameio/boardgame.io/commit/dcaca7f)] types: Remove `turn.moves` from `Game` type
* [[b753094](https://github.com/boardgameio/boardgame.io/commit/b753094), [2aa9db5](https://github.com/boardgameio/boardgame.io/commit/2aa9db5)] Update dependencies ([#965](https://github.com/boardgameio/boardgame.io/pull/965), [#968](https://github.com/boardgameio/boardgame.io/pull/968))

#### Other

* [[be63602](https://github.com/boardgameio/boardgame.io/commit/be63602)] Update development dependencies ([#969](https://github.com/boardgameio/boardgame.io/pull/969))
* [[4efec1a](https://github.com/boardgameio/boardgame.io/commit/4efec1a)] Update linter tooling & refactor errors ([#967](https://github.com/boardgameio/boardgame.io/pull/967))

### v0.45.2

#### Bugfixes

* [[9753c0e](https://github.com/boardgameio/boardgame.io/commit/9753c0e)] fix: Don’t leak `STRIP_TRANSIENTS` action ([#961](https://github.com/boardgameio/boardgame.io/pull/961))

### v0.45.1

#### Breaking Changes

Please see notes for v0.45.0. This release extends CORS security restrictions to the Lobby API (0.45.0 only applied the `origins` config to the socket.io server).

#### Features

* [[8b950a0](https://github.com/boardgameio/boardgame.io/commit/8b950a0)] server: Use `origins` option to configure Lobby API CORS ([#955](https://github.com/boardgameio/boardgame.io/pull/955))

#### Bugfixes

* [[2b1d013](https://github.com/boardgameio/boardgame.io/commit/2b1d013)] server: Update to latest `@types/cors` to provide better origins configuration defaults

## v0.45.0

#### Breaking Changes

Previously boardgame.io servers allowed CORS requests from all origins by default. After updating socket.io in 0.45.0, an `origins` option must now be provided when creating the server to enable cross-origin requests:

```js
const { Server } = require('boardgame.io/server');

Server({
  origins: ['https://www.mygame.com'],
  // ...
});
```

See [the Server reference page](https://boardgame.io/documentation/#/api/Server) for more details.

#### Features

* [[dffcb18](https://github.com/boardgameio/boardgame.io/commit/dffcb18)] chore(deps): Upgrade socket.io packages ([#946](https://github.com/boardgameio/boardgame.io/pull/946))

### v0.44.4

#### Features

* [[2eca252](https://github.com/boardgameio/boardgame.io/commit/2eca252)] Improve error handling (work in progress) (PR [#940](https://github.com/boardgameio/boardgame.io/pull/940), Issue [#723](https://github.com/boardgameio/boardgame.io/issues/723))
* [[cceb0f2](https://github.com/boardgameio/boardgame.io/commit/cceb0f2)] package: Add funding field

#### Bugfixes

* [[49c2c12](https://github.com/boardgameio/boardgame.io/commit/49c2c12)] reducer: Don’t crash when undoing stage events ([#942](https://github.com/boardgameio/boardgame.io/pull/942))

### v0.44.3

#### Bugfixes

* [[f1c60ee](https://github.com/boardgameio/boardgame.io/commit/f1c60ee), [3718124](https://github.com/boardgameio/boardgame.io/commit/3718124), [2685470](https://github.com/boardgameio/boardgame.io/commit/2685470), [ac78e82](https://github.com/boardgameio/boardgame.io/commit/ac78e82), [5b0de40](https://github.com/boardgameio/boardgame.io/commit/5b0de40)] Dependency updates

### v0.44.2

#### Bugfixes

* [[b832b07](https://github.com/boardgameio/boardgame.io/commit/b832b07)] Make custom plugins available in event hooks ([#932](https://github.com/boardgameio/boardgame.io/pull/932))

### v0.44.1

#### Bugfixes

* [[1d20e7e](https://github.com/boardgameio/boardgame.io/commit/1d20e7e)] client: Correct signature type for `sendChatMessage`
* [[a7c8776](https://github.com/boardgameio/boardgame.io/commit/a7c8776)] debug panel: Handle all possible argument types in the log pane

## v0.44.0

#### Features

* [[abc516b](https://github.com/boardgameio/boardgame.io/commit/abc516b)] Add an option to use JSON patches for state updates ([#920](https://github.com/boardgameio/boardgame.io/pull/920))
* [[0bab885](https://github.com/boardgameio/boardgame.io/commit/0bab885)] Support spying on logs after framework is loaded ([#918](https://github.com/boardgameio/boardgame.io/pull/918))
* [[a57fe19](https://github.com/boardgameio/boardgame.io/commit/a57fe19)] Export additional game API types ([#927](https://github.com/boardgameio/boardgame.io/pull/927))

#### Bugfixes

* [[e94d476](https://github.com/boardgameio/boardgame.io/commit/e94d476)] Improve TypeScript typings for the player plugin and React client ([#922](https://github.com/boardgameio/boardgame.io/pull/922))

### v0.43.3

#### Features

* [[01c522c](https://github.com/boardgameio/boardgame.io/commit/01c522c)] Throw error in development if non-serializable state is used in a move ([#896](https://github.com/boardgameio/boardgame.io/pull/896))
* [[ccc9ada](https://github.com/boardgameio/boardgame.io/commit/ccc9ada)] Add details to exceptions raised in LobbyClient ([#898](https://github.com/boardgameio/boardgame.io/pull/898))

#### Bugfixes

* [[ae790e8](https://github.com/boardgameio/boardgame.io/commit/ae790e8)] dependencies: bump immer from 7.0.8 to 8.0.1 ([#895](https://github.com/boardgameio/boardgame.io/pull/895))
* [[6f9bc27](https://github.com/boardgameio/boardgame.io/commit/6f9bc27)] dependencies: Run `npm audit fix`

### v0.43.2

#### Bugfixes

* [[3d614b8](https://github.com/boardgameio/boardgame.io/commit/3d614b8)] server: Improve security of socket.io transport layer ([#894](https://github.com/boardgameio/boardgame.io/pull/894))
* [[dc96b26](https://github.com/boardgameio/boardgame.io/commit/dc96b26)] master: Disallow `onSync` match creation if game requires `setupData` ([#890](https://github.com/boardgameio/boardgame.io/pull/890))

### v0.43.1

#### Bugfixes

* [[b14ea29](https://github.com/boardgameio/boardgame.io/commit/b14ea29)] client: Always include `chatMessages` and `sendChatMessage` on client instances

## v0.43.0

#### Features

* [[0ad1d6d](https://github.com/boardgameio/boardgame.io/commit/0ad1d6d)] [[c178a41](https://github.com/boardgameio/boardgame.io/commit/c178a41)] Add in-game chat support ([#871](https://github.com/boardgameio/boardgame.io/pull/871), [#879](https://github.com/boardgameio/boardgame.io/pull/879))
* [[3918cc9](https://github.com/boardgameio/boardgame.io/commit/3918cc9)] Add plugin to allow adding custom metadata to logs ([#865](https://github.com/boardgameio/boardgame.io/pull/865))
* [[243388d](https://github.com/boardgameio/boardgame.io/commit/243388d)] Centralise lobby API and master authentication logic ([#853](https://github.com/boardgameio/boardgame.io/pull/853))

#### Bugfixes

* [[e515573](https://github.com/boardgameio/boardgame.io/commit/e515573)] Handle random plugin redacted state on multiplayer clients ([#885](https://github.com/boardgameio/boardgame.io/pull/885))
* [[3b8ac79](https://github.com/boardgameio/boardgame.io/commit/3b8ac79)] Prevent `TypeError: state.deltalog is not iterable` ([#888](https://github.com/boardgameio/boardgame.io/pull/888))
* [[2cc6104](https://github.com/boardgameio/boardgame.io/commit/2cc6104)] Support latest Safari & Firefox when running examples

### v0.42.2

#### Features

* [[8f8d30e](https://github.com/boardgameio/boardgame.io/commit/8f8d30e)] plugins: Add `playerView` option to plugin API (closes [#671](https://github.com/boardgameio/boardgame.io/issues/671)) ([#857](https://github.com/boardgameio/boardgame.io/pull/857))

#### Bugfixes

* [[c51bc09](https://github.com/boardgameio/boardgame.io/commit/c51bc09)] debug: prevent `endStage` event crashing debug log panel ([#856](https://github.com/boardgameio/boardgame.io/pull/856))

### v0.42.1

#### Features

* [[6c4e94f](https://github.com/boardgameio/boardgame.io/commit/6c4e94f)] Add option to long-form move to ignore stale `stateID` (closes [#828](https://github.com/boardgameio/boardgame.io/issues/828)) ([#832](https://github.com/boardgameio/boardgame.io/pull/832))

#### Bugfixes

* [[5207be5](https://github.com/boardgameio/boardgame.io/commit/5207be5)] core: `setStage(Stage.NULL)` makes player active (closes [#848](https://github.com/boardgameio/boardgame.io/issues/848)) ([#849](https://github.com/boardgameio/boardgame.io/pull/849))

## v0.42.0

#### Features

* [[6ba5536](https://github.com/boardgameio/boardgame.io/commit/6ba5536)] Add localStorage support to Local master ([#691](https://github.com/boardgameio/boardgame.io/pull/691))
* [[257a735](https://github.com/boardgameio/boardgame.io/commit/257a735)] Track players connection status ([#839](https://github.com/boardgameio/boardgame.io/pull/839))
* [[d071e98](https://github.com/boardgameio/boardgame.io/commit/d071e98)] Add game method to validate setup data ([#831](https://github.com/boardgameio/boardgame.io/pull/831))

#### Bugfixes

* [[ace1144](https://github.com/boardgameio/boardgame.io/commit/ace1144)] local: Use shared local master with bots ([#838](https://github.com/boardgameio/boardgame.io/pull/838))
* [[9fcbed7](https://github.com/boardgameio/boardgame.io/commit/9fcbed7)] client: Correctly type state returned by client to subscribers

### v0.41.1

Push another release to fix NPM weirdness.

## v0.41.0

#### Features

* [[c8c648e](https://github.com/boardgameio/boardgame.io/commit/c8c648e)] Add global manager to track client & debug panel instances ([#816](https://github.com/boardgameio/boardgame.io/pull/816))
* [[af43561](https://github.com/boardgameio/boardgame.io/commit/af43561)] Add log entries for undo/redo actions ([#825](https://github.com/boardgameio/boardgame.io/pull/825))
* [[2595399](https://github.com/boardgameio/boardgame.io/commit/2595399)] Improve undo/redo ([#823](https://github.com/boardgameio/boardgame.io/pull/823))
* [[3d2131e](https://github.com/boardgameio/boardgame.io/commit/3d2131e)] master: Use `createMatch` for implicit match creation ([#821](https://github.com/boardgameio/boardgame.io/pull/821))
* [[f74f953](https://github.com/boardgameio/boardgame.io/commit/f74f953)] Improve match term consistency ([#806](https://github.com/boardgameio/boardgame.io/pull/806))

#### Bugfixes

* [[f5d3a97](https://github.com/boardgameio/boardgame.io/commit/f5d3a97)] debug: Improve debug panel accessibility ([#827](https://github.com/boardgameio/boardgame.io/pull/827))
* [[0040a5d](https://github.com/boardgameio/boardgame.io/commit/0040a5d)] reducer: Restore plugin state on undo/redo
* [[4f2ffc4](https://github.com/boardgameio/boardgame.io/commit/4f2ffc4)] debug: Include plugin data in log rewind gamestate override
* [[197a9bb](https://github.com/boardgameio/boardgame.io/commit/197a9bb)] reducer: Fix stateID increment & build deltalog on server only ([#817](https://github.com/boardgameio/boardgame.io/pull/817))
* [[600caa8](https://github.com/boardgameio/boardgame.io/commit/600caa8)] debug: Use local reducer in Log rewind
* [[3c2aadd](https://github.com/boardgameio/boardgame.io/commit/3c2aadd)] client: Don’t run playerView locally on multiplayer clients ([#819](https://github.com/boardgameio/boardgame.io/pull/819))
* [[abd9695](https://github.com/boardgameio/boardgame.io/commit/abd9695)] fix: Simplify local transport typing
* [[9a2a609](https://github.com/boardgameio/boardgame.io/commit/9a2a609)] fix: improve socketio.ts typings ([#811](https://github.com/boardgameio/boardgame.io/pull/811))
* [[0f8882a](https://github.com/boardgameio/boardgame.io/commit/0f8882a)] core: Fix EndPhase deltalog ([#812](https://github.com/boardgameio/boardgame.io/pull/812))
* [[4bd283c](https://github.com/boardgameio/boardgame.io/commit/4bd283c)] fix: FlatFile.listGames filter ([#802](https://github.com/boardgameio/boardgame.io/pull/802))
* [[0062e55](https://github.com/boardgameio/boardgame.io/commit/0062e55)] client: Improve client types ([#801](https://github.com/boardgameio/boardgame.io/pull/801))

## v0.40.0

#### Breaking Changes

See [PR #709 on GitHub](https://github.com/boardgameio/boardgame.io/pull/709) for a full list and migration guide.

#### Features

* [[43c7fbb](https://github.com/boardgameio/boardgame.io/commit/43c7fbb)] Add plain JS lobby client ([#728](https://github.com/boardgameio/boardgame.io/pull/728))
* [[adb251d](https://github.com/boardgameio/boardgame.io/commit/adb251d)] [[6fcf695](https://github.com/boardgameio/boardgame.io/commit/6fcf695)] Use “match” instead of “game”/“room” in Lobby API ([#704](https://github.com/boardgameio/boardgame.io/pull/704), [#765](https://github.com/boardgameio/boardgame.io/pull/765))
* [[88b0ee7](https://github.com/boardgameio/boardgame.io/commit/88b0ee7)] debug: Display live object view in debug panel ([#781](https://github.com/boardgameio/boardgame.io/pull/781), [#790](https://github.com/boardgameio/boardgame.io/pull/790))
* [[3984ee7](https://github.com/boardgameio/boardgame.io/commit/3984ee7)] debug: Events shortcuts, stages support & minor fixes ([#791](https://github.com/boardgameio/boardgame.io/pull/791))
* [[3c8777b](https://github.com/boardgameio/boardgame.io/commit/3c8777b)] server: Timestamp metadata and match filtering in the Lobby API ([#740](https://github.com/boardgameio/boardgame.io/pull/740))
* [[a0c34fd](https://github.com/boardgameio/boardgame.io/commit/a0c34fd)] server: Expose API router ([#698](https://github.com/boardgameio/boardgame.io/pull/698))

#### Bugfixes

* [[2586022](https://github.com/boardgameio/boardgame.io/commit/2586022)] debug: Keep debug panel above other page elements ([#780](https://github.com/boardgameio/boardgame.io/pull/780))
* [[f32dc76](https://github.com/boardgameio/boardgame.io/commit/f32dc76)] api: Expose gameover metadata in lobby endpoints ([#666](https://github.com/boardgameio/boardgame.io/pull/666))
* [[fa865da](https://github.com/boardgameio/boardgame.io/commit/fa865da)] fixes build in rushjs monorepo context ([#550](https://github.com/boardgameio/boardgame.io/pull/550))

### v0.39.16

#### Bugfixes

* [[84e93b4](https://github.com/boardgameio/boardgame.io/commit/84e93b4)] build: Exclude svelte from Rollup’s external module list (#767)
* [[72ed591](https://github.com/boardgameio/boardgame.io/commit/72ed591)] fix: Tidy up type provision (#764)

### v0.39.15

#### Bugfixes

* [[271aecd](https://github.com/boardgameio/boardgame.io/commit/271aecd)] fix: Fix client types & move BoardProps to React package (#752)

### v0.39.14

#### Features

* [[c115087](https://github.com/boardgameio/boardgame.io/commit/c115087)] game: add disableUndo flag to game config (#742)

#### Bugfixes

* [[a6698e6](https://github.com/boardgameio/boardgame.io/commit/a6698e6)] debug: Fix save & restore in Debug panel (#746)

### v0.39.13

#### Features

* [[2b1bd19](https://github.com/boardgameio/boardgame.io/commit/2b1bd19)] ai: Convert to Typescript (#734)
* [[872b58b](https://github.com/boardgameio/boardgame.io/commit/872b58b)] client: Make argument optional in Local transport (#731)

#### Bugfixes

* [[0088cb5](https://github.com/boardgameio/boardgame.io/commit/0088cb5)] fix: Re-sync client on reconnect, fixes #713 (#727)

### v0.39.12

#### Features

* [[0ca1cef](https://github.com/boardgameio/boardgame.io/commit/0ca1cef)] lobby: use previous game config as defaults in playAgain (#719)
* [[60b32e5](https://github.com/boardgameio/boardgame.io/commit/60b32e5)] Add support for socket.io-adapter implementations (#706)
* [[eb236df](https://github.com/boardgameio/boardgame.io/commit/eb236df)] db: FlatFile per-file request queues enhancement (#705)

#### Bugfixes

* [[ef97441](https://github.com/boardgameio/boardgame.io/commit/ef97441)] debug: Save all state to localStorage, not just G and ctx (#716)
* [[4d45ff1](https://github.com/boardgameio/boardgame.io/commit/4d45ff1)] client: Fix restore in debug controls (#712)
* [[d728425](https://github.com/boardgameio/boardgame.io/commit/d728425)] core: Fix undo/redo if the move changed the stage (#701)
* [[3a622f1](https://github.com/boardgameio/boardgame.io/commit/3a622f1)] Use Promise chaining to enforce read/write queue (#699)

### v0.39.11

#### Features

* [[cfeaf67](https://github.com/boardgameio/boardgame.io/commit/cfeaf67)] plugins: Let moves return INVALID_MOVE after mutating G (#688)
* [[b2d6b06](https://github.com/boardgameio/boardgame.io/commit/b2d6b06)] server: Lobby API improvements (#675)
* [[dc668ec](https://github.com/boardgameio/boardgame.io/commit/dc668ec)] server: Expose SocketIO transport & convert to TS (#658)

#### Bugfixes

* [[1483a08](https://github.com/boardgameio/boardgame.io/commit/1483a08)] fix UX issues in move debugger (#640)
* [[814621b](https://github.com/boardgameio/boardgame.io/commit/814621b)] Make package.json scripts work on Windows (#657)

### v0.39.10

#### Features

* [[cf96955](https://github.com/boardgameio/boardgame.io/commit/cf96955)] Add option to exclude games from public listing (#653)
* [[2e5b902](https://github.com/boardgameio/boardgame.io/commit/2e5b902)] core: Support moves that don’t contribute to numMoves (#646)
* [[e4fc7bd](https://github.com/boardgameio/boardgame.io/commit/e4fc7bd)] master: Update metadata with gameover value on game end (#645)
* [[05eacb8](https://github.com/boardgameio/boardgame.io/commit/05eacb8)] Enable adding additional metadata to players in Lobby (#642)

#### Bugfixes

* [[d2f668b](https://github.com/boardgameio/boardgame.io/commit/d2f668b)] Fix plugins in hooks triggered by moves (#656)
* [[334f8d6](https://github.com/boardgameio/boardgame.io/commit/334f8d6)] [Documentation] Remove references to removed MongoDB adapter (#659)
* [[a4c4c7c](https://github.com/boardgameio/boardgame.io/commit/a4c4c7c)] Test warning is logged when using deprecated `/rename` API endpoint. (#655)
* [[6aff09c](https://github.com/boardgameio/boardgame.io/commit/6aff09c)] Add playAgain endpoint to Lobby documentation (#652)
* [[9f4acfe](https://github.com/boardgameio/boardgame.io/commit/9f4acfe)] Add link to Azure Storage database connector (#651)
* [[78113aa](https://github.com/boardgameio/boardgame.io/commit/78113aa)] Add mosaic to notable_projects.md (#649)
* [[c51b277](https://github.com/boardgameio/boardgame.io/commit/c51b277)] expose log as a prop in the React client (#641)

### v0.39.9

#### Bugfixes

* [[b4bd8b7](https://github.com/boardgameio/boardgame.io/commit/b4bd8b7)] package: update npm files field for new server bundle (#639)
* [[0552efb](https://github.com/boardgameio/boardgame.io/commit/0552efb)] add src/ to NPM

### v0.39.8

#### Bugfixes

* [[3569408](https://github.com/boardgameio/boardgame.io/commit/3569408)] Add option to run server over HTTPS (#631)
* [[c56d9b9](https://github.com/boardgameio/boardgame.io/commit/c56d9b9)] Adding playerID to Ctx (#627)
* [[882a25d](https://github.com/boardgameio/boardgame.io/commit/882a25d)] export only the client in the browser-minified package
* [[3d1c07c](https://github.com/boardgameio/boardgame.io/commit/3d1c07c)] server: Proxy server module with package.json (#622)
* [[bd44678](https://github.com/boardgameio/boardgame.io/commit/bd44678)] Fix passing params to db adapter (#621)

### v0.39.7

#### Bugfixes

* [[44d0d4f](https://github.com/boardgameio/boardgame.io/commit/44d0d4f)] fix bad merge that undid https://github.com/boardgameio/boardgame.io/pull/614

### v0.39.6

#### Features

* [[c5211c2](https://github.com/boardgameio/boardgame.io/commit/c5211c2)] Typescript enhancements (#612)

#### Bugfixes

* [[eb1e060](https://github.com/boardgameio/boardgame.io/commit/eb1e060)] make plugins available in turn order functions
* [[0688f4d](https://github.com/boardgameio/boardgame.io/commit/0688f4d)] Include credentials in undo/redo actions (#595)
* [[f34f46b](https://github.com/boardgameio/boardgame.io/commit/f34f46b)] core: Don’t error if turn.order.next returns undefined (#614)

### v0.39.5

#### Features

* [[78729eb](https://github.com/boardgameio/boardgame.io/commit/78729eb)] core: More Typescript conversion (#597)
* [[3a41cf7](https://github.com/boardgameio/boardgame.io/commit/3a41cf7)] plugins: Make player plugin a factory function (#604)

#### Bugfixes

* [[1877268](https://github.com/boardgameio/boardgame.io/commit/1877268)] plugins: More Typescript & pass playerID to Enhance (#598)
* [[5696dc4](https://github.com/boardgameio/boardgame.io/commit/5696dc4)] server: Correctly wait for server.listen event (#589)

### v0.39.4

#### Features

* [[167690c](https://github.com/boardgameio/boardgame.io/commit/167690c)] add plugin types to ctx interface (#579)
* [[618618e](https://github.com/boardgameio/boardgame.io/commit/618618e)] db: Make listGames options optional (#585)
* [[f3c62a3](https://github.com/boardgameio/boardgame.io/commit/f3c62a3)] db: Make log handling explicit in StorageAPI.setState (#581)
* [[c7dad76](https://github.com/boardgameio/boardgame.io/commit/c7dad76)] add the ability for plugins to define their own actions

#### Bugfixes

* [[9a21fee](https://github.com/boardgameio/boardgame.io/commit/9a21fee)] Remove namespacing in gameIDs on client side (#583)

### v0.39.3

#### Features

* [[c507cf0](https://github.com/boardgameio/boardgame.io/commit/c507cf0)] Typescript improvements (#578)

### v0.39.1

#### Bugfixes

* [[ca3cc0f](https://github.com/boardgameio/boardgame.io/commit/ca3cc0f)] avoid document reference error in some versions of Node

## v0.39.0

#### Features

* [[ca52b01](https://github.com/boardgameio/boardgame.io/commit/ca52b01)] export some types in the NPM
* [[6a091de](https://github.com/boardgameio/boardgame.io/commit/6a091de)] retrieve initial state using a separate code path
* [[62f58d2](https://github.com/boardgameio/boardgame.io/commit/62f58d2)] add createGame to StorageAPI
* [[21c3ef4](https://github.com/boardgameio/boardgame.io/commit/21c3ef4)] make listGames take an opts argument
* [[bff685d](https://github.com/boardgameio/boardgame.io/commit/bff685d)] rename remove to wipe
* [[d4de9e2](https://github.com/boardgameio/boardgame.io/commit/d4de9e2)] move log out of game state
* [[045a8f5](https://github.com/boardgameio/boardgame.io/commit/045a8f5)] rename list to listGames
* [[7b70cab](https://github.com/boardgameio/boardgame.io/commit/7b70cab)] remove MongoDB
* [[0fb67fe](https://github.com/boardgameio/boardgame.io/commit/0fb67fe)] remove Firebase
* [[c96e228](https://github.com/boardgameio/boardgame.io/commit/c96e228)] separate metadata and state in storage API

#### Bugfixes

* [[a75605d](https://github.com/boardgameio/boardgame.io/commit/a75605d)] remove unused has()
* [[4157bc1](https://github.com/boardgameio/boardgame.io/commit/4157bc1)] remove namespacing in gameIDs
* [[8c80785](https://github.com/boardgameio/boardgame.io/commit/8c80785)] remove namespace

### v0.38.1

#### Features

* [[0d59c2c](https://github.com/boardgameio/boardgame.io/commit/0d59c2c)] move Events code into plugin
* [[4b1c135](https://github.com/boardgameio/boardgame.io/commit/4b1c135)] move Random code into plugin

#### Bugfixes

* [[a624c9e](https://github.com/boardgameio/boardgame.io/commit/a624c9e)] update @babel/preset-env
* [[c1dba9f](https://github.com/boardgameio/boardgame.io/commit/c1dba9f)] update prettier
* [[60c6d88](https://github.com/boardgameio/boardgame.io/commit/60c6d88)] update rollup-plugin-terser
* [[6378659](https://github.com/boardgameio/boardgame.io/commit/6378659)] npm run audit

## v0.38.0

#### Breaking Changes

The Plugin API is revamped. This also includes changing the way
`PluginPlayer` works.  Please take a look at the
[documentation](https://boardgame.io/documentation/#/plugins).  Feel free to comment on the public Gitter
channel if you have use-cases that are not covered by the rewrite
or need help migrating.

#### Features

* [[d84e6af](https://github.com/boardgameio/boardgame.io/commit/d84e6af)] add onEnd hook for Game
* [[94b69cb](https://github.com/boardgameio/boardgame.io/commit/94b69cb)] Plugin API cleanup (#560)

#### Bugfixes

* [[aede3b6](https://github.com/boardgameio/boardgame.io/commit/aede3b6)] check that document exists before mounting debug panel
* [[ec7f0ad](https://github.com/boardgameio/boardgame.io/commit/ec7f0ad)] master: Remove credentials from action payloads after use (#556)
* [[a080ce3](https://github.com/boardgameio/boardgame.io/commit/a080ce3)] fix: #552 (#553)
* [[79ebcc3](https://github.com/boardgameio/boardgame.io/commit/79ebcc3)] remove graceful-fs patch
* [[9370366](https://github.com/boardgameio/boardgame.io/commit/9370366)] remove some unused Svelte props

### v0.37.2

#### Bugfixes

* [[8c120d2](https://github.com/boardgameio/boardgame.io/commit/8c120d2)] trigger bot if it needs to play at game start
* [[aed5cd1](https://github.com/boardgameio/boardgame.io/commit/aed5cd1)] don't run bot once game is over
* [[7c65046](https://github.com/boardgameio/boardgame.io/commit/7c65046)] fix redacted move example

### v0.37.1

#### Bugfixes

* [[66021f7](https://github.com/boardgameio/boardgame.io/commit/66021f7)] fix bug causing AI section to not activate
* [[fd34df9](https://github.com/boardgameio/boardgame.io/commit/fd34df9)] plugins: Fix PluginPlayer setup (#543)

## v0.37.0

#### Breaking Changes

The `ai` section has been moved from the `Client` to the game config:

```js
const game = {
  moves: { ... },
  ...
  ai: { ... }
}
```

#### Features

* [[0eff1c6](https://github.com/boardgameio/boardgame.io/commit/0eff1c6)] make the lobby assign bots to remaining players when there is only one human player
* [[ef8df65](https://github.com/boardgameio/boardgame.io/commit/ef8df65)] add ability for Local multiplayer mode to run bots

## v0.36.0

#### Features

* [[b974260](https://github.com/boardgameio/boardgame.io/commit/b974260)] Improve Lobby API: room instances (#542)
* [[afdb79e](https://github.com/boardgameio/boardgame.io/commit/afdb79e)] refactor: Harmonise Master’s auth signature with authenticateCredentials (#539)
* [[61a45ee](https://github.com/boardgameio/boardgame.io/commit/61a45ee)] rename optimistic to client and document it
* [[4d33faa](https://github.com/boardgameio/boardgame.io/commit/4d33faa)] server: Lobby server improvements (#532)
* [[08404e2](https://github.com/boardgameio/boardgame.io/commit/08404e2)] change MCTS visualization to table format

#### Bugfixes

* [[2d931e9](https://github.com/boardgameio/boardgame.io/commit/2d931e9)] server: Use namespaced ID to delete persisted game data (#531)
* [[9ce176c](https://github.com/boardgameio/boardgame.io/commit/9ce176c)] client: Scope global CSS selectors in Debug panel (#527)
* [[ef4f24d](https://github.com/boardgameio/boardgame.io/commit/ef4f24d)] Fix events in hooks triggered by a move (#525)
* [[a2c64f8](https://github.com/boardgameio/boardgame.io/commit/a2c64f8)] increment turn before calling turn.onBegin

### v0.35.1

#### Bugfixes

* [[26a73e4](https://github.com/boardgameio/boardgame.io/commit/26a73e4)] fix error in AI panel

## v0.35.0

#### Features

- [[e7d47ee](https://github.com/boardgameio/boardgame.io/commit/e7d47ee)] export Debug Panel in boardgame.io/debug
- [[cae05fd](https://github.com/boardgameio/boardgame.io/commit/cae05fd)] Replace `player` with `currentPlayer` option in `setActivePlayers` (#523)
- [[2a7435a](https://github.com/boardgameio/boardgame.io/commit/2a7435a)] rename step to play
- [[05572ca](https://github.com/boardgameio/boardgame.io/commit/05572ca)] add progress bar to AI panel
- [[ad08b8a](https://github.com/boardgameio/boardgame.io/commit/ad08b8a)] Increment current player at start of phase in TurnOrder.DEFAULT (#521)
- [[3cd5667](https://github.com/boardgameio/boardgame.io/commit/3cd5667)] speed up bot async mode by running 25 iterations per chunk
- [[f19f1de](https://github.com/boardgameio/boardgame.io/commit/f19f1de)] add async mode to MCTS bot
- [[7d22a47](https://github.com/boardgameio/boardgame.io/commit/7d22a47)] make bot play functions async
- [[4efddb4](https://github.com/boardgameio/boardgame.io/commit/4efddb4)] lobby auto refresh + leave game ready to play (#510)
- [[a8b7028](https://github.com/boardgameio/boardgame.io/commit/a8b7028)] add sliders to adjust iterations and playoutDepth of MCTS bot
- [[1687ff8](https://github.com/boardgameio/boardgame.io/commit/1687ff8)] Add pass event (#492)
- [[5fb3c4c](https://github.com/boardgameio/boardgame.io/commit/5fb3c4c)] allow switching between MCTS and Random bots in AI panel
- [[9d74966](https://github.com/boardgameio/boardgame.io/commit/9d74966)] allow setting bot options from Debug Panel
- [[bbfa304](https://github.com/boardgameio/boardgame.io/commit/bbfa304)] add AI tab

#### Bugfixes

- [[ba9dca8](https://github.com/boardgameio/boardgame.io/commit/ba9dca8)] add server.js to files section
- [[457b29d](https://github.com/boardgameio/boardgame.io/commit/457b29d)] call notifySubscribers in update{Player,Game}ID
- [[b4edd55](https://github.com/boardgameio/boardgame.io/commit/b4edd55)] Add server to proxy-dirs and clean scripts to fix #518 (#519)
- [[6c0a9b7](https://github.com/boardgameio/boardgame.io/commit/6c0a9b7)] allow switching playerID from Debug Panel

## v0.34.0

The main feature in this release is that the Debug Panel is now baked into the Vanilla JS client. This
means that non-React users will have access to it as well!

It is guarded by process.env.NODE_ENV !== 'production', which means that most bundlers will strip it
out in a production build.

The other big change is that the NPM package now contains both CJS and ES builds for every subpackage. This should have no user visible impact, but might break some non-standard bundler configurations.

#### Features

- [[e9351dc](https://github.com/boardgameio/boardgame.io/commit/e9351dc)] log a message when INVALID_MOVE is returned
- [[2f86d92](https://github.com/boardgameio/boardgame.io/commit/2f86d92)] rename mount/unmount to start/stop
- [[1ad87d0](https://github.com/boardgameio/boardgame.io/commit/1ad87d0)] remove INFO log in production, but not ERROR logs
- [[83810ea](https://github.com/boardgameio/boardgame.io/commit/83810ea)] guard Debug Panel with process.env.NODE_ENV
- [[156cf07](https://github.com/boardgameio/boardgame.io/commit/156cf07)] generate CJS and ES version of main package
- [[881278a](https://github.com/boardgameio/boardgame.io/commit/881278a)] Migrate Debug Panel + Log + MCTS Visualizer to Svelte (#498)
- [[49f5a52](https://github.com/boardgameio/boardgame.io/commit/49f5a52)] allow multiple client subscriptions

#### Bugfixes

- [[3206548](https://github.com/boardgameio/boardgame.io/commit/3206548)] don't invoke callback on subscribe in multiplayer mode unless client is already connected
- [[9596fa4](https://github.com/boardgameio/boardgame.io/commit/9596fa4)] only notify the latest subscriber during client.subscribe
- [[5a13f00](https://github.com/boardgameio/boardgame.io/commit/5a13f00)] fix bug in the way the transport notifies client subscribers of connection changes
- [[c77ba53](https://github.com/boardgameio/boardgame.io/commit/c77ba53)] handle multiple subscriptions correctly
- [[b045de3](https://github.com/boardgameio/boardgame.io/commit/b045de3)] use Parcel instead of Webpack in examples

### v0.33.2

#### Features

- [[18d9be5](https://github.com/boardgameio/boardgame.io/commit/18d9be5)] Allowing support for both numbers and functions for MCTS bot iterations and playoutDepth (#475)
- [[901c746](https://github.com/boardgameio/boardgame.io/commit/901c746)] feat: Apply `value` argument last in `setActivePlayers` (#489)

#### Bugfixes

- [[bed18ce](https://github.com/boardgameio/boardgame.io/commit/bed18ce)] reintroduce InitializeGame in boardgame.io/core

### v0.33.1

#### Features

- [[6eb4ebd](https://github.com/boardgameio/boardgame.io/commit/6eb4ebd)] rewrite one of the snippets in Svelte
- [[86e65fe](https://github.com/boardgameio/boardgame.io/commit/86e65fe)] fix: Move player to “next” stage on `endStage` (#484)

## v0.33.0

Huge release with a more streamlined API and the much
awaited feature: Stages!

Check out this [migration guide](https://nicolodavis.com/blog/boardgame.io-0.33/).

#### Features

- [[6762219](https://github.com/boardgameio/boardgame.io/commit/6762219)] refactor: Change moveLimit syntax in setActivePlayers (#481)
- [[64971ee](https://github.com/boardgameio/boardgame.io/commit/64971ee)] Disallow game names with spaces (#474)
- [[d43d239](https://github.com/boardgameio/boardgame.io/commit/d43d239)] short form syntax for literal value in setActivePlayers
- [[462f452](https://github.com/boardgameio/boardgame.io/commit/462f452)] allow all players to call events
- [[2409729](https://github.com/boardgameio/boardgame.io/commit/2409729)] enable all events by default
- [[1261475](https://github.com/boardgameio/boardgame.io/commit/1261475)] remove UI toolkit
- [[b2f5160](https://github.com/boardgameio/boardgame.io/commit/b2f5160)] feat: Add `endStage` and `setStage` events (#458)
- [[ca61bf6](https://github.com/boardgameio/boardgame.io/commit/ca61bf6)] feat: Support move limits in `setActivePlayers` (#452)
- [[ec15ad2](https://github.com/boardgameio/boardgame.io/commit/ec15ad2)] TurnOrder.RESET
- [[d251f4a](https://github.com/boardgameio/boardgame.io/commit/d251f4a)] set phase to null instead of empty string
- [[9c6f55d](https://github.com/boardgameio/boardgame.io/commit/9c6f55d)] set currentPlayer to null instead of empty string
- [[da2f0ea](https://github.com/boardgameio/boardgame.io/commit/da2f0ea)] add stages
- [[d5e2b55](https://github.com/boardgameio/boardgame.io/commit/d5e2b55)] start turn at 1
- [[35a34a0](https://github.com/boardgameio/boardgame.io/commit/35a34a0)] nest turns inside phases
- [[cff284b](https://github.com/boardgameio/boardgame.io/commit/cff284b)] convert startingPhase into boolean option
- [[b9ce7f1](https://github.com/boardgameio/boardgame.io/commit/b9ce7f1)] move event disablers inside separate section in config
- [[61eb8d8](https://github.com/boardgameio/boardgame.io/commit/61eb8d8)] rename movesPerTurn to moveLimit
- [[3a97a16](https://github.com/boardgameio/boardgame.io/commit/3a97a16)] make optimistic an option in long-form move syntax
- [[10ef457](https://github.com/boardgameio/boardgame.io/commit/10ef457)] retire Game(). call it internally instead.
- [[3d46a4a](https://github.com/boardgameio/boardgame.io/commit/3d46a4a)] rename endGameIf to endIf
- [[33ac684](https://github.com/boardgameio/boardgame.io/commit/33ac684)] retire flow section
- [[d75fe44](https://github.com/boardgameio/boardgame.io/commit/d75fe44)] move undoableMoves into boolean inside long form move syntax
- [[8924e84](https://github.com/boardgameio/boardgame.io/commit/8924e84)] move redactedMoves into a boolean option in the long form move syntax
- [[4b202ee](https://github.com/boardgameio/boardgame.io/commit/4b202ee)] long form move syntax
- [[f00e736](https://github.com/boardgameio/boardgame.io/commit/f00e736)] rename some hooks
- [[19ca21f](https://github.com/boardgameio/boardgame.io/commit/19ca21f)] move onTurnBegin/onTurnEnd/endTurnIf/movesPerTurn into turn object
- [[53b7ac7](https://github.com/boardgameio/boardgame.io/commit/53b7ac7)] convert turnOrder into a turn object
- [[fa58e5b](https://github.com/boardgameio/boardgame.io/commit/fa58e5b)] retire allowedMoves
- [[7a411c9](https://github.com/boardgameio/boardgame.io/commit/7a411c9)] introduce namespaced moves that are defined within phases
- [[a0d5f36](https://github.com/boardgameio/boardgame.io/commit/a0d5f36)] Surface game metadata and player nicknames in client / react props (#436)
- [[221b0d5](https://github.com/boardgameio/boardgame.io/commit/221b0d5)] add benchmark

#### Bugfixes

- [[fd70ed5](https://github.com/boardgameio/boardgame.io/commit/fd70ed5)] No payload is not an authentic player (#430)

### v0.32.1

#### Features

- [[9cff03e](https://github.com/boardgameio/boardgame.io/commit/9cff03e)] Create play again endpoint (#428)

#### Bugfixes

- [[0a75e4b](https://github.com/boardgameio/boardgame.io/commit/0a75e4b)] fix: Fix join/leave a room when playerID is 0 (#425)

## v0.32.0

#### Features

- [[2b98fb6](https://github.com/boardgameio/boardgame.io/commit/2b98fb6)] change custom client transport to a constructor (#417)
- [[89faece](https://github.com/boardgameio/boardgame.io/commit/89faece)] Rename playerCredentials to credentials for /leave endpoint, update src/lobby/connection.js accordingly (#416)
- [[25c2263](https://github.com/boardgameio/boardgame.io/commit/25c2263)] Fix #345; restrict undo/redo to currentPlayer (#408)
- [[6de7b64](https://github.com/boardgameio/boardgame.io/commit/6de7b64)] Add /rename endpoint for lobby (#414)

### v0.31.7

#### Features

- [[febb1c0](https://github.com/boardgameio/boardgame.io/commit/febb1c0)] Check if required parameters are passed to API (#407)

#### Bugfixes

- [[a6145a5](https://github.com/boardgameio/boardgame.io/commit/a6145a5)] upgrade koa and koa-body

### v0.31.6

#### Bugfixes

- [[5ad5c3f](https://github.com/boardgameio/boardgame.io/commit/5ad5c3f)] Remove some secrets from client in multiplayer game (#400)
- [[3e50dca](https://github.com/boardgameio/boardgame.io/commit/3e50dca)] Get specific instance of a room by its ID (#405)
- [[4964e3f](https://github.com/boardgameio/boardgame.io/commit/4964e3f)] Creating lobby API config and making the UUID customizable (#396)
- [[efece0c](https://github.com/boardgameio/boardgame.io/commit/efece0c)] Auto-add trailing slash to server only if needed (#403)
- [[f289379](https://github.com/boardgameio/boardgame.io/commit/f289379)] Rename gameInstances to rooms (#402)
- [[1d5586c](https://github.com/boardgameio/boardgame.io/commit/1d5586c)] export FlatFile in server.js
- [[eda9728](https://github.com/boardgameio/boardgame.io/commit/eda9728)] update undo to reflect current ctx (#393)
- [[e46f195](https://github.com/boardgameio/boardgame.io/commit/e46f195)] add turn and phase to log entries

### v0.31.5

#### Features

- [[3982150](https://github.com/boardgameio/boardgame.io/commit/3982150)] synchronous mode for game master
- [[8732d9f](https://github.com/boardgameio/boardgame.io/commit/8732d9f)] Add adminClient option for Firebase storage (#386)

#### Bugfixes

- [[8ed812e](https://github.com/boardgameio/boardgame.io/commit/8ed812e)] handle default number of players bigger than 2 for 1st game of the list (#392)
- [[ec7dde5](https://github.com/boardgameio/boardgame.io/commit/ec7dde5)] Don't leak undefined ctx properties from turnOrder.actionPlayers (#382)

### v0.31.4

#### Features

- [[3bde0ca](https://github.com/boardgameio/boardgame.io/commit/3bde0ca)] Adding step props to the Board (#376)
- [[4c3056c](https://github.com/boardgameio/boardgame.io/commit/4c3056c)] Making step accept a Promise from bot.play() (#375)

#### Bugfixes

- [[c24e0cd](https://github.com/boardgameio/boardgame.io/commit/c24e0cd)] upgrade Expo and fix React Native example
- [[c1ee6f3](https://github.com/boardgameio/boardgame.io/commit/c1ee6f3)] python bot: fix #379 (#380)

### v0.31.3

#### Features

- [[94b1d65](https://github.com/boardgameio/boardgame.io/commit/94b1d65)] Add flatfile database with node-persist (#372)
- [[f6e70fd](https://github.com/boardgameio/boardgame.io/commit/f6e70fd)] Add custom renderer parameter to lobby + clean up code (#353)

### v0.31.2

#### Features

- [[01a7e79](https://github.com/boardgameio/boardgame.io/commit/01a7e79)] 3D Grid and Token (#352)
- [[1f33d43](https://github.com/boardgameio/boardgame.io/commit/1f33d43)] Serve API and Game Server on same port with option to split (#343)

#### Bugfixes

- [[87d1e5b](https://github.com/boardgameio/boardgame.io/commit/87d1e5b)] Changed default Firebase return value to undefined (#361)
- [[d7d6b44](https://github.com/boardgameio/boardgame.io/commit/d7d6b44)] Fix lobby example (#351)
- [[a285fbf](https://github.com/boardgameio/boardgame.io/commit/a285fbf)] Allow https urls to be passed to lobby (#350)

### v0.31.1

#### Bugfixes

- [[4a796dc](https://github.com/boardgameio/boardgame.io/commit/4a796dc)] remove three from minified rollup bundle

## v0.31.0

#### Features

- [[a32d3d5](https://github.com/boardgameio/boardgame.io/commit/a32d3d5)] Generic lobby (#294)
- [[fb19e9b](https://github.com/boardgameio/boardgame.io/commit/fb19e9b)] move examples into a create-react-app package (#335)
- [[1f71bbd](https://github.com/boardgameio/boardgame.io/commit/1f71bbd)] Upgrade Babel 7 (#332)

#### Bugfixes

- [[3334d38](https://github.com/boardgameio/boardgame.io/commit/3334d38)] fix race condition in game instantiation inside onSync
- [[f544511](https://github.com/boardgameio/boardgame.io/commit/f544511)] Allow result of onPhaseBegin to influence turn order (#341)
- [[e1c1f6b](https://github.com/boardgameio/boardgame.io/commit/e1c1f6b)] fail integration test if any subcommand fails

## v0.30.0

#### Features

- [[6cf81e8](https://github.com/boardgameio/boardgame.io/commit/6cf81e8)] create initial game state outside reducer
- [[8d08381](https://github.com/boardgameio/boardgame.io/commit/8d08381)] add a loading component for multiplayer clients

#### Bugfixes

- [[d20d26c](https://github.com/boardgameio/boardgame.io/commit/d20d26c)] make master write to proper namepspaced keys

### v0.29.5

#### Features

- [[7188222](https://github.com/boardgameio/boardgame.io/commit/7188222)] add plugin.onPhaseBegin

### v0.29.4

#### Features

- [[c1b4a03](https://github.com/boardgameio/boardgame.io/commit/c1b4a03)] add playerSetup option to PluginPlayer

### v0.29.3

#### Features

- [[da1eac6](https://github.com/boardgameio/boardgame.io/commit/da1eac6)] rename plugin api functions
- [[659007a](https://github.com/boardgameio/boardgame.io/commit/659007a)] pass game object to plugins

### v0.29.2

#### Bugfixes

- [[5d74c95](https://github.com/boardgameio/boardgame.io/commit/5d74c95)] fix immer plugin order

### v0.29.1

#### Features

- [[ff749e3](https://github.com/boardgameio/boardgame.io/commit/ff749e3)] add addTo / removeFrom to plugin API
- [[9df8145](https://github.com/boardgameio/boardgame.io/commit/9df8145)] split plugin.setup into setupG and setupCtx
- [[d2d44f9](https://github.com/boardgameio/boardgame.io/commit/d2d44f9)] rename plugin.wrapper to plugin.fnWrap
- [[ca5da32](https://github.com/boardgameio/boardgame.io/commit/ca5da32)] Passing arbitrary data to game setup (#315)

## v0.29.0

#### Features

- [[d1bd1d1](https://github.com/boardgameio/boardgame.io/commit/d1bd1d1)] Plugin API

### v0.28.1

#### Features

- [[10de6f8](https://github.com/boardgameio/boardgame.io/commit/10de6f8)] Turn order active player changes (#320)
- [[58cbd1e](https://github.com/boardgameio/boardgame.io/commit/58cbd1e)] Redact Log Events (#268)
- [[ed165a8](https://github.com/boardgameio/boardgame.io/commit/ed165a8)] Add a server sync status field (#307)

#### Bugfixes

- [[b8ec845](https://github.com/boardgameio/boardgame.io/commit/b8ec845)] package refactor
- [[2b5920f](https://github.com/boardgameio/boardgame.io/commit/2b5920f)] Add Immer to other events (#327)
- [[873e1f5](https://github.com/boardgameio/boardgame.io/commit/873e1f5)] server: fix name of property 'credentials' in server API handler for 'leave' (#326)

## v0.28.0

We now support an alternative style for moves that allows modifying `G` directly.
The old style is still supported.

#### Features

- [[6bdfb11](https://github.com/boardgameio/boardgame.io/commit/6bdfb11)] add immer

#### Breaking Changes

`undefined` is no longer used to indicate invalid moves. Use the new `INVALID_MOVE`
constant to accomplish this.

```js
import { INVALID_MOVE } from 'boardgame.io/core';

const TicTacToe = Game({
  moves: {
    clickCell: (G, ctx, id) => {
      if (G.cells[id] !== null) {
        return INVALID_MOVE;
      }
      G.cells[id] = ctx.currentPlayer;
    },
  },
});
```

### v0.27.1

#### Features

- [[2d02558](https://github.com/boardgameio/boardgame.io/commit/2d02558)] add TurnOrder.CUSTOM and TurnOrder.CUSTOM_FROM

#### Bugfixes

- [[8699350](https://github.com/boardgameio/boardgame.io/commit/8699350)] Prohibit second log event during Update (#303)

## v0.27.0

This is a pretty exciting release with lots of goodies but
with some breaking changes, so make sure to read the section
at the end with tips on migration. The main theme in this
release is the reworking of Phases and Turn Orders to support
more complex game types and other common patterns like the
ability to quickly pop into a phase and back.

#### Features

- [[b7abc57](https://github.com/boardgameio/boardgame.io/commit/b7abc57)] more turn orders
- [[5fb663a](https://github.com/boardgameio/boardgame.io/commit/5fb663a)] allow calling setActionPlayers via TurnOrder objects
- [[53473ef](https://github.com/boardgameio/boardgame.io/commit/53473ef)] change semantics of enabling/disabling events
- [[992416a](https://github.com/boardgameio/boardgame.io/commit/992416a)] change format of args to endPhase and endTurn
- [[0568857](https://github.com/boardgameio/boardgame.io/commit/0568857)] change phases syntax

#### Bugfixes

- [[96def53](https://github.com/boardgameio/boardgame.io/commit/96def53)] add MONGO_DATABASE env variable (#290)

#### Breaking Changes

1. The syntax for phases has changed:

```
// old
phases: [
{ name: 'A', ...opts },
{ name: 'B', ...opts },
]

// new
phases: {
'A': { ...opts },
'B': { ...opts },
}
```

2. There is no implicit ordering of phases. You can specify an
   explicit order via `next` (optional). Note that this allows you to create
   more complex graphs of phases compared to the previous linear
   approach.

```
phases: {
'A': { next: 'B' },
'B': { next: 'A' },
}
```

Take a look at [phases.md](phases.md) to see how `endPhase`
determines which phase to move to.

3. A phase called `default` is always created. This is the phase
   that the game begins in. This is also the phase that the
   game reverts to in case it detects an infinite loop of
   `endPhase` events caused by a cycle.

You can have the game start in a phase different from `default`
using `startingPhase`:

```
flow: {
startingPhase: 'A',
phases: {
A: {},
B: {},
}
}
```

4. The format of the argument to `endPhase` or the return
   value of `endPhaseIf` is now an object of type `{ next: 'phase name' }`

```
// old
endPhase('new phase')
endPhaseIf: () => 'new phase'

// new
endPhase({ next: 'new phase' })
endPhaseIf: () => ({ next: 'new phase' })
```

5. The format of the argument to `endTurn` or the return
   value of `endTurnIf` is now an object of type `{ next: playerID }`

```
// old
endTurn(playerID)
endTurnIf: () => playerID

// new
endTurn({ next: playerID })
endTurnIf: () => ({ next: playerID })
```

6. The semantics of enabling / disabling events has changed
   a bit: see https://boardgame.io/#/events for more details.

7. TurnOrder objects now support `setActionPlayers` args.
   Instead of returning `actionPlayers` in `first` / `next`,
   add an `actionPlayers` section instead.

```
// old
{
first: (G, ctx) => {
playOrderPos: 0,
actionPlayers: [...ctx.playOrder],
}

next: (G, ctx) => {
playOrderPos: ctx.playOrderPos + 1,
actionPlayers: [...ctx.playOrder],
},
}

// new
{
first: (G, ctx) => 0,
next: (G, ctx) => ctx.playOrderPos + 1,
actionPlayers: { all: true },
}
```

### v0.26.3

#### Features

- [[d50015d](https://github.com/boardgameio/boardgame.io/commit/d50015d)] turn order simulator

#### Bugfixes

- [[58e135b](https://github.com/boardgameio/boardgame.io/commit/58e135b)] fix bug that was causing ctx.events to be undefined
- [[ea3754b](https://github.com/boardgameio/boardgame.io/commit/ea3754b)] player needs to be in actionPlayers in order to call events

### v0.26.2

#### Features

- [[a352d1e](https://github.com/boardgameio/boardgame.io/commit/a352d1e)] decouple once and allOthers

### v0.26.1

#### Bugfixes

- [[aa5f2cf](https://github.com/boardgameio/boardgame.io/commit/aa5f2cf)] added the useNewUrlParser option to the Mongo connect() (#285)

## v0.26.0

#### Features

- [[e8f165a](https://github.com/boardgameio/boardgame.io/commit/e8f165a)] server: add new API endpoints 'list' and 'leave' (#276)
- [[8ff4745](https://github.com/boardgameio/boardgame.io/commit/8ff4745)] drag-n-drop for cards and decks
- [[a558092](https://github.com/boardgameio/boardgame.io/commit/a558092)] return state as first argument to client.subscribe callback
- [[965f9b7](https://github.com/boardgameio/boardgame.io/commit/965f9b7)] Allow to set payload onto a log event (#267)
- [[2efdbc1](https://github.com/boardgameio/boardgame.io/commit/2efdbc1)] utils for working with hexagonal boards (#271)
- [[137dd7c](https://github.com/boardgameio/boardgame.io/commit/137dd7c)] allow overriding client-side transport
- [[63311ac](https://github.com/boardgameio/boardgame.io/commit/63311ac)] local game master
- [[0b7a0a0](https://github.com/boardgameio/boardgame.io/commit/0b7a0a0)] add allOthers option to setActionPlayers (#269)

#### Bugfixes

- [[d1a1a8a](https://github.com/boardgameio/boardgame.io/commit/d1a1a8a)] shouldEndPhase can see the results of onTurnEnd
- [[b4874a6](https://github.com/boardgameio/boardgame.io/commit/b4874a6)] call the client subscribe callback after LogMiddleware has run
- [[9b9d735](https://github.com/boardgameio/boardgame.io/commit/9b9d735)] reset deltalog properly

### v0.25.5

#### Features

- [[4ed6b94](https://github.com/boardgameio/boardgame.io/commit/4ed6b94)] add server startup message
- [[1688639](https://github.com/boardgameio/boardgame.io/commit/1688639)] decouple transport layer from server logic

### v0.25.4

#### Bugfixes

- Fixed babelHelpers error in npm.

### v0.25.3

Broken, do not use (complains about babelHelpers missing).

#### Bugfixes

- [[ebf7e73](https://github.com/boardgameio/boardgame.io/commit/ebf7e73)] fix bug that was preventing playerID from being overriden by the debug ui

### v0.25.2

#### Bugfixes

- [[a42e07b](https://github.com/boardgameio/boardgame.io/commit/a42e07b)] npm audit fix --only=prod
- [[cfe7296](https://github.com/boardgameio/boardgame.io/commit/cfe7296)] update koa and socket.io

### v0.25.1

#### Bugfixes

- [[09b523e](https://github.com/boardgameio/boardgame.io/commit/09b523e)] require mongo and firebase only if used

## v0.25.0

#### Features

- [[fe8a9d0](https://github.com/boardgameio/boardgame.io/commit/fe8a9d0)] Added ability to specify server protocol (#247)
- [[43dcaac](https://github.com/boardgameio/boardgame.io/commit/43dcaac)] write turn / phase stats in ctx.stats
- [[bd8208a](https://github.com/boardgameio/boardgame.io/commit/bd8208a)] fabricate playerID in singleplayer mode
- [[b4e3e09](https://github.com/boardgameio/boardgame.io/commit/b4e3e09)] { all: true } option for setActionPlayers
- [[5d3a34d](https://github.com/boardgameio/boardgame.io/commit/5d3a34d)] { once: true } option for setActionPlayers
- [[75a274c](https://github.com/boardgameio/boardgame.io/commit/75a274c)] rename changeActionPlayers to setActionPlayers
- [[4ec3a61](https://github.com/boardgameio/boardgame.io/commit/4ec3a61)] end phase when a turn order runs out
- [[cb6111b](https://github.com/boardgameio/boardgame.io/commit/cb6111b)] retire the string constant 'any'
- [[36fc47f](https://github.com/boardgameio/boardgame.io/commit/36fc47f)] basic support for objective-based AI
- [[d1f0a3e](https://github.com/boardgameio/boardgame.io/commit/d1f0a3e)] improved rendering of turns and phases in the log
- [[0bc31d6](https://github.com/boardgameio/boardgame.io/commit/0bc31d6)] better MCTS visualization
- [[14a5ad7](https://github.com/boardgameio/boardgame.io/commit/14a5ad7)] update redux to 4.0.0

#### Bugfixes

- [[84f07c6](https://github.com/boardgameio/boardgame.io/commit/84f07c6)] Do not fabricate playerID for playerView
- [[c4a11a7](https://github.com/boardgameio/boardgame.io/commit/c4a11a7)] ignore events from all but currentPlayer
- [[6a8b657](https://github.com/boardgameio/boardgame.io/commit/6a8b657)] move mongodb and firebase deps to devDependencies
- [[239f8dd](https://github.com/boardgameio/boardgame.io/commit/239f8dd)] Use parse/stringify from flatted lib to support circular structures (fixes #222) (#240)
- [[edd1df0](https://github.com/boardgameio/boardgame.io/commit/edd1df0)] Differentiate automatic game events in the log
- [[570f40e](https://github.com/boardgameio/boardgame.io/commit/570f40e)] don't render AI metadata if visualize is not specified
- [[a8431c7](https://github.com/boardgameio/boardgame.io/commit/a8431c7)] set default RNG seed once per game, not game type
- [[5090429](https://github.com/boardgameio/boardgame.io/commit/5090429)] API: check secret _before_ handling the request (#231)
- [[1a24791](https://github.com/boardgameio/boardgame.io/commit/1a24791)] attach events API early so that it can be used on the first onTurnBegin
- [[acb9d8c](https://github.com/boardgameio/boardgame.io/commit/acb9d8c)] enable events API in initial onTurnBegin/onPhaseBegin

#### Breaking Changes

- `changeActionPlayers` is now `setActionPlayers`. It also supports more advanced [options](http://boardgame.io/#/events?id=setactionplayers).
- Returning `undefined` from a `TurnOrder` results in the phase ending, not setting `currentPlayer` to `any`.
- Only the `currentPlayer` can call events (`endTurn`, `endPhase` etc.).

## v0.24.0

#### Features

- [[b28ee74](https://github.com/boardgameio/boardgame.io/commit/b28ee74)] ability to change playerID from Debug UI
- [[fe1230e](https://github.com/boardgameio/boardgame.io/commit/fe1230e)] Firebase integration (#223)

### v0.23.3

#### Bugfixes

- [[6194986](https://github.com/boardgameio/boardgame.io/commit/6194986)] remove async/await from client code

### v0.23.2

#### Bugfixes

- [[7a61f09](https://github.com/boardgameio/boardgame.io/commit/7a61f09)] make Random API present in first onTurnBegin and onPhaseBegin

#### Features

- [[99b9844](https://github.com/boardgameio/boardgame.io/commit/99b9844)] Python Bots
- [[a7134a5](https://github.com/boardgameio/boardgame.io/commit/a7134a5)] List available games API

### v0.23.1

#### Bugfixes

- [[f26328c](https://github.com/boardgameio/boardgame.io/commit/f26328c)] add ai.js to rollup config

## v0.23.0

#### Features

- [[dda540a](https://github.com/boardgameio/boardgame.io/commit/dda540a)] AI framework
- [[8e2f8c4](https://github.com/boardgameio/boardgame.io/commit/8e2f8c4)] lobby API support (#189)

#### Bugfixes

- [[7a80f66](https://github.com/boardgameio/boardgame.io/commit/7a80f66)] make changeActionPlayers an opt-in event
- [[40cd4b8](https://github.com/boardgameio/boardgame.io/commit/40cd4b8)] Add config update on phase change Fixes #211 (#212)

### v0.22.1

#### Bugfixes

- [[bb39ca7](https://github.com/boardgameio/boardgame.io/commit/bb39ca7)] fix bug that was causing isActive to return false
- [[81ed088](https://github.com/boardgameio/boardgame.io/commit/81ed088)] ensure endTurn is called only once after a move
- [[ca9f6ca](https://github.com/boardgameio/boardgame.io/commit/ca9f6ca)] disable move if playerID is null

## v0.22.0

#### Features

- [[5362955](https://github.com/boardgameio/boardgame.io/commit/5362955)] React Native Client (#128)
- [[b329df2](https://github.com/boardgameio/boardgame.io/commit/b329df2)] Pass through props (#173)

### v0.21.5

#### Bugfixes

- [[55715c9](https://github.com/boardgameio/boardgame.io/commit/55715c9)] Fix undefined ctx in onPhaseBegin

### v0.21.4

#### Features

- [[387d413](https://github.com/boardgameio/boardgame.io/commit/387d413)] Debug UI CSS improvements
- [[2105f46](https://github.com/boardgameio/boardgame.io/commit/2105f46)] call endTurnIf inside endPhase
- [[9b0324c](https://github.com/boardgameio/boardgame.io/commit/9b0324c)] allow setting the next player via endTurn
- [[f76f97e](https://github.com/boardgameio/boardgame.io/commit/f76f97e)] correct isMultiplayer

#### Bugfixes

- [[278b369](https://github.com/boardgameio/boardgame.io/commit/278b369)] Fix bug that was ending phase incorrectly (#176)

### v0.21.3

#### Features

- [[dc31a66](https://github.com/boardgameio/boardgame.io/commit/dc31a66)] expose allowedMoves in ctx
- [[da4711a](https://github.com/boardgameio/boardgame.io/commit/da4711a)] make allowedMoves both global and phase-specific
- [[9324c58](https://github.com/boardgameio/boardgame.io/commit/9324c58)] Allowed moves as function (#164)

#### Bugfixes

- [[5e49448](https://github.com/boardgameio/boardgame.io/commit/5e49448)] convert multiplayer move whitelist to blacklist

### v0.21.2

#### Bugfixes

- [[27705d5](https://github.com/boardgameio/boardgame.io/commit/27705d5)] pass Events API correctly inside events.update

### v0.21.1

#### Bugfixes

- [[87e77c1](https://github.com/boardgameio/boardgame.io/commit/87e77c1)] correctly detach APIs from ctx in startTurn

## v0.21.0

#### Features

- [[2ee244e](https://github.com/boardgameio/boardgame.io/commit/2ee244e)] Reset Game (#155)
- [[9cd3fdf](https://github.com/boardgameio/boardgame.io/commit/9cd3fdf)] allow to modify actionPlayers via Events (#157)
- [[767362f](https://github.com/boardgameio/boardgame.io/commit/767362f)] endGame event
- [[78634ee](https://github.com/boardgameio/boardgame.io/commit/78634ee)] Events API
- [[a240e45](https://github.com/boardgameio/boardgame.io/commit/a240e45)] undoableMoves implementation (#149)
- [[c12e911](https://github.com/boardgameio/boardgame.io/commit/c12e911)] Process only known moves (#151)
- [[7fcdbfe](https://github.com/boardgameio/boardgame.io/commit/7fcdbfe)] Custom turn order (#130)
- [[748f36f](https://github.com/boardgameio/boardgame.io/commit/748f36f)] UI: add mouse hover action props to grid, hex, and token (#153)
- [[f664237](https://github.com/boardgameio/boardgame.io/commit/f664237)] Add notion of actionPlayers (#145)

### v0.20.2

#### Features

- [[43ba0ff](https://github.com/boardgameio/boardgame.io/commit/43ba0ff)] allow optional redux enhancer (#139)
- [[dd6c110](https://github.com/boardgameio/boardgame.io/commit/dd6c110)] Run endPhase event (analogue to endTurn) when game ends (#144)

#### Bugfixes

- [[8969433](https://github.com/boardgameio/boardgame.io/commit/8969433)] Fix bug that was causing Random code to return the same numbers.

#### Breaking Changes

- The `Random` API is different. There is no longer a `Random` package
  that you need to import. The API is attached to the `ctx` parameter that
  is passed to the moves. Take a look at http://boardgame.io/#/random for
  more details.

### v0.20.1

#### Bugfixes

- [[06d78e2](https://github.com/boardgameio/boardgame.io/commit/06d78e2)] Enable SSR
- [[ed09f51](https://github.com/boardgameio/boardgame.io/commit/ed09f51)] Allow calling Random during setup
- [[c50d5ea](https://github.com/boardgameio/boardgame.io/commit/c50d5ea)] fix log rendering of phases

## v0.20.0

#### Features

- [[eec8896](https://github.com/boardgameio/boardgame.io/commit/eec8896)] undo/redo

## v0.19.0

#### Features

- MongoDB connector
  - [[eaa372f](https://github.com/boardgameio/boardgame.io/commit/eaa372f)] add Mongo to package
  - [[63c3cdf](https://github.com/boardgameio/boardgame.io/commit/63c3cdf)] mongo race condition checks
  - [[65cefdf](https://github.com/boardgameio/boardgame.io/commit/65cefdf)] allow setting Mongo location using MONGO_URI
  - [[557b66c](https://github.com/boardgameio/boardgame.io/commit/557b66c)] add run() to Server
  - [[2a85b40](https://github.com/boardgameio/boardgame.io/commit/2a85b40)] replace lru-native with lru-cache
  - [[003fe46](https://github.com/boardgameio/boardgame.io/commit/003fe46)] MongoDB connector

#### Breaking Changes

- `boardgame.io/server` no longer has a default export, but returns
  `Server` and `Mongo`.

```
// v0.19
const Server = require('boardgame.io/server').Server;
```

```
// v0.18
const Server = require('boardgame.io/server');
```

### v0.18.1

#### Bugfixes

[[0c894bd](https://github.com/boardgameio/boardgame.io/commit/0c894bd)] add react.js to rollup config

## v0.18.0

#### Features

- [[4b90e84](https://github.com/boardgameio/boardgame.io/commit/4b90e84)] decouple client from React

This adds a new package `boardgame.io/react`. Migrate all your
calls from:

```
import { Client } from 'boardgame.io/client'
```

to:

```
import { Client } from 'boardgame.io/react'
```

`boardgame.io/client` exposes a raw JS client that isn't tied
to any particular UI framework.

- Random API:

  - [[ebe7758](https://github.com/boardgameio/boardgame.io/commit/ebe7758)] allow to throw multiple dice (#120)
  - [[8c88b70](https://github.com/boardgameio/boardgame.io/commit/8c88b70)] Simplify Random API (#119)
  - [[45599e5](https://github.com/boardgameio/boardgame.io/commit/45599e5)] Server-side array shuffling. (#116)
  - [[d296b36](https://github.com/boardgameio/boardgame.io/commit/d296b36)] Random API (#103)

- [[f510b69](https://github.com/boardgameio/boardgame.io/commit/f510b69)] onTurnBegin (#109)

#### Bugfixes

- [[6a010c8](https://github.com/boardgameio/boardgame.io/commit/6a010c8)] Debug UI: fixes related to errors in arguments (#123)

### v0.17.2

#### Features

- [[0572210](https://github.com/boardgameio/boardgame.io/commit/0572210)] Exposing Client connection status to board. (#97)
- [[c2ea197](https://github.com/boardgameio/boardgame.io/commit/c2ea197)] make db interface async (#86)
- [[9e507ce](https://github.com/boardgameio/boardgame.io/commit/9e507ce)] exclude dependencies from package

#### Bugfixes

- [[a768f1f](https://github.com/boardgameio/boardgame.io/commit/a768f1f)] remove entries from clientInfo and roomInfo on disconnect

### v0.17.1

#### Features

- [[f23c5dd](https://github.com/boardgameio/boardgame.io/commit/f23c5dd)] Card and Deck (#74)
- [[a21c1dd](https://github.com/boardgameio/boardgame.io/commit/a21c1dd)] prevent endTurn when movesPerTurn have not been made

#### Bugfixes

- [[11e215e](https://github.com/boardgameio/boardgame.io/commit/11e215e)] fix bug that was using the wrong playerID when calculating playerView

## v0.17.0

#### Features

- [[0758c7e](https://github.com/boardgameio/boardgame.io/commit/0758c7e)] cascade endPhase
- [[cc7d44f](https://github.com/boardgameio/boardgame.io/commit/cc7d44f)] retire triggers and introduce onMove instead
- [[17e88ce](https://github.com/boardgameio/boardgame.io/commit/17e88ce)] convert events whitelist to boolean options
- [[e315b9e](https://github.com/boardgameio/boardgame.io/commit/e315b9e)] add ui to NPM package
- [[5b34c5d](https://github.com/boardgameio/boardgame.io/commit/5b34c5d)] remove pass event and make it a standard move
- [[f3da742](https://github.com/boardgameio/boardgame.io/commit/f3da742)] make playerID available in ctx
- [[cb09d9a](https://github.com/boardgameio/boardgame.io/commit/cb09d9a)] make turnOrder a globally configurable option

### v0.16.8

#### Features

- [[a482469](https://github.com/boardgameio/boardgame.io/commit/a482469b2f6a317a50fb25f23b7ffc0c2f597c1e)] ability to specify socket server

#### Bugfixes

- [[2ab3dfc](https://github.com/boardgameio/boardgame.io/commit/2ab3dfc6928eb8f0bfdf1ce319ac53021a2f905b)] end turn automatically when game ends

### v0.16.7

#### Bugfixes

- [[c65580d](https://github.com/boardgameio/boardgame.io/commit/c65580d)] Fix bug introduced in af3a7b5.

### v0.16.6

#### Bugfixes

- [[af3a7b5](https://github.com/boardgameio/boardgame.io/commit/af3a7b5)] Only process move reducers (on the client) and nothing else when in multiplayer mode.

Buggy fix (fixed in 0.16.7).

#### Features

- [[2721ad4](https://github.com/boardgameio/boardgame.io/commit/2721ad4)] Allow overriding `db` implementation in Server.

### v0.16.5

#### Features

- `PlayerView.STRIP_SECRETS`

### v0.16.4

#### Bugfixes

- `endPhaseIf` is called after each move (in addition to at the end of a turn).
- `gameID` is namespaced on the server so that there are no clashes across game types.

#### Breaking Changes

- `props.game` is now `props.events` (to avoid confusing it with the `game` object).

```
// OLD
onClick() {
this.props.game.endTurn();
}

// NEW
onClick() {
this.props.events.endTurn();
}
```

### v0.16.3

#### Features

- Multiple game types per server!

#### Breaking Changes

- `Server` now accepts an array `games`, and no longer takes `game` and `numPlayers`.

```
const app = Server({
games: [ TicTacToe, Chess ]
};
```

### v0.16.2

#### Bugfixes

- [[a61ceca](https://github.com/boardgameio/boardgame.io/commit/a61ceca8cc8e973d786678e1bcc7ec50739ebeaa)]: Log turn ends correctly (even when triggered automatically by `endTurnIf`)

#### Features

- [[9ce42b2](https://github.com/boardgameio/boardgame.io/commit/9ce42b297372160f3ece4203b4c92000334d85e0)]: Change color in `GameLog` based on the player that made the move.

### v0.16.1

#### Bugfixes

- [[23d9726](https://github.com/boardgameio/boardgame.io/commit/23d972677c6ff43b77d5c30352dd9959b517a93c)]: Fix bug that was causing `log` to be erased after `flow.processMove`.

#### Features

- [Triggers](https://github.com/boardgameio/boardgame.io/commit/774e540b20d7402184a00abdb7c512d7c8e85995)
- [movesPerTurn](https://github.com/boardgameio/boardgame.io/commit/73d5b73d00eaba9aaf73a3576dfcfb25fc2b311d)

## v0.16.0

#### Features

- [Phases](http://boardgame.io/#/phases)

#### Breaking Changes

- `boardgame.io/game` is now `boardgame.io/core`, and does not have a default export.
- `boardgame.io/client` no longer has a default export.

```
// v0.16
import { Game } from 'boardgame.io/core'
import { Client } from 'boardgame.io/client'
```

```
// v0.15
import Game from 'boardgame.io/game'
import Client from 'boardgame.io/client'
```

- `victory` is now `endGameIf`, and goes inside a `flow` section.
- The semantics of `endGameIf` are subtly different. The game ends if
  the function returns anything at all.
- `ctx.winner` is now `ctx.gameover`, and contains the return value of `endGameIf`.
- `props.endTurn` is now `props.game.endTurn`.


================================================
FILE: docs/documentation/api/Client.md
================================================
# Client

Creates a `boardgame.io` client. This is the entry point for
the client application.

<!-- tabs:start -->

### **Plain JS**

#### Import

```js
import { Client } from 'boardgame.io/client';
```

### Creating a client

#### Arguments

1. `options` (_object_): An object with the following options:

```js
const client = Client({
  // A game definition object.
  game: game,

  // The number of players.
  numPlayers: 2,

  // Set this to one of the following to enable multiplayer:
  //
  // SocketIO
  //   Implementation that talks to a remote server using socket.io.
  //
  //   How to import:
  //     import { SocketIO } from 'boardgame.io/multiplayer'
  //
  //   Arguments:
  //     Object with 2 parameters
  //        1. 'socketOpts' options to pass directly to socket.io client.
  //        2. 'server' specifies the server location in the format: [http[s]://]hostname[:port];
  //            defaults to current page host.
  //
  // Local
  //   Special local mode that uses an in-memory game master. Useful
  //   for testing multiplayer interactions locally without having to
  //   connect to a server.
  //
  //   How to import:
  //     import { Local } from 'boardgame.io/multiplayer'
  //
  // Additionally, you can write your own transport implementation.
  // See `src/client/client.js` for details.
  multiplayer: false,

  // Match to connect to (multiplayer).
  matchID: 'matchID',

  // Associate the client with a player (multiplayer).
  playerID: 'playerID',

  // The player’s authentication credentials (multiplayer).
  credentials: 'credentials',

  // Set to false to disable the Debug Panel
  debug: true/false,

  // Add a Redux enhancer to the internal store.
  // See “Debugging” guide for more details
  enhancer: enhancer,
});
```

### Using a client

#### Properties

The following properties are available on a client instance:

- `moves`: An object containing functions to dispatch the
   moves that you have defined. The functions are named after the
   moves you created in your [game object](/api/Game.md). Each function
   can take any number of arguments, and they are passed to the
   move function after `G` and `ctx`.


- `events`: An object containing functions to dispatch various
   game events like `endTurn` and `endPhase`.


- `log`: The game log.


- `matchID`: The match ID associated with the client.


- `playerID`: The player ID associated with the client.


- `credentials`: Multiplayer authentication credentials for this player.


- `matchData`: An array containing the players that have joined
  the current match via the [Lobby API](/api/Lobby.md).

  Example:

  ```js
  [
    { id: 0, name: 'Alice' },
    { id: 1, name: 'Bob', isConnected: true }
  ]
  ```


- `chatMessages`: An array containing chat messages this client has received.
  Each message is an object with the following properties:

    - `id`: a unique ID string
    - `sender`: the `playerID` of the sender
    - `payload`: the value passed to `sendChatMessage`

  Example:

  ```js
  [
    { id: 'foo', sender: '0', payload: 'Ready to play?' },
    { id: 'bar', sender: '1', payload: 'Let’s go!' },
  ]
  ```


#### Methods

The following methods are available on a client instance:

- `start()`: Start running the client. Connects to the multiplayer
  transport and creates the Debug Panel.


- `stop()`: Stop running the client. Disconnects the multiplayer
  transport and unmounts the Debug Panel.


- `getState()`: Get the current game state. Returns `null` if the client
  still needs to sync with a remote master, otherwise an object:

  ```js
  {
    // The game state object `G`.
    G: { /* ... */ },

    // The game `ctx` (turn, currentPlayer, etc.)
    ctx: { /* ... */ },

    // State for plugins.
    plugins: { /* ... */ },

    // The game log.
    log: [ /* ... */ ],

    // `true` if the client is able to currently make
    // a move or interact with the game.
    isActive: true/false,

    // `true` if connection to the server is active.
    isConnected: true/false,
  }
  ```


- `subscribe(callback)`: Add a callback for every state change.
  The passed function will be called with the same value as returned by
  `getState`. `subscribe` returns an unsubscribe function.

  ```js
  const unsubscribe = client.subscribe(state => {
    // use updated state
  });

  // unsubscribe from the client
  unsubscribe();
  ```


- `reset()`: Function that resets the game.


- `undo()`: Function that undoes the last move.


- `redo()`: Function that redoes the previously undone move.


- `sendChatMessage(message)`: Function that sends a chat message to other
  players. The `message` argument can be a string or you can send objects
  to include more metadata.


- `updateMatchID(id)`: Function to update the client’s match ID.


- `updatePlayerID(id)`: Function to update the client’s player ID.


- `updateCredentials(credentials)`: Function to update the client’s credentials.


### **React**

#### Import

```js
import { Client } from 'boardgame.io/react';
```

#### Arguments

1. `options` (_object_): An object with the options shown below under ‘Usage’.

#### Returns

A React component that runs the client.

The component supports the following `props`:

1. `matchID` (_string_):
   Connect to a particular match (multiplayer).

2. `playerID` (_string_):
   Associate the client with a player (multiplayer).

3. `credentials` (_string_):
   The player’s authentication credentials (multiplayer).

4. `debug` (_boolean_):
   Set to `false` to disable the Debug UI.

### Usage

```js
const App = Client({
  // A game object.
  game: game,

  // The number of players.
  numPlayers: 2,

  // Your React component representing the game board.
  // The props that this component receives are listed below.
  // When using TypeScript, type the component's properties as
  // extending BoardProps.
  board: Board,

  // Optional: React component to display while the client
  // is in the "loading" state prior to the initial sync
  // with the game master. Relevant only in multiplayer mode.
  // If this is not provided, the client displays "connecting...".
  loading: LoadingComponent,

  // Set this to one of the following to enable multiplayer:
  //
  // SocketIO
  //   Implementation that talks to a remote server using socket.io.
  //
  //   How to import:
  //     import { SocketIO } from 'boardgame.io/multiplayer'
  //
  //   Arguments:
  //     Object with 2 parameters
  //        1. 'socketOpts' options to pass directly to socket.io client.
  //        2. 'server' specifies the server location in the format: [http[s]://]hostname[:port];
  //            defaults to current page host.
  //
  // Local
  //   Special local mode that uses an in-memory game master. Useful
  //   for testing multiplayer interactions locally without having to
  //   connect to a server.
  //
  //   How to import:
  //     import { Local } from 'boardgame.io/multiplayer'
  //
  // Additionally, you can write your own transport implementation.
  // See `src/client/client.js` for details.
  multiplayer: false,

  // Set to false to disable the Debug UI.
  debug: true,

  // An optional Redux store enhancer.
  // This is useful for augmenting the Redux store
  // for purposes of debugging or simply intercepting
  // events in order to kick off other side-effects in
  // response to moves.
  enhancer: applyMiddleware(your_middleware),
});

ReactDOM.render(<App />, document.getElementById('app'));
```

#### Board Props

The component you pass as the `board` option will receive the
following as `props`:

- `G`: The game state.


- `ctx`: The game metadata.


- `moves`: An object containing functions to dispatch various
   moves that you have defined. The functions are named after the
   moves you created in your [game object](/api/Game.md). Each function
   can take any number of arguments, and they are passed to the
   move function after `G` and `ctx`.


- `events`: An object containing functions to dispatch various
   game events like `endTurn` and `endPhase`.


- `reset`: Function that resets the game.


- `undo`: Function that undoes the last move.


- `redo`: Function that redoes the previously undone move.


- `sendChatMessage(message)`: Function that sends a chat message to other
  players. The `message` argument can be a string or you can send objects
  to include more metadata.


- `chatMessages`: An array containing chat messages this client has received.
  Each message is an object with the following properties:

    - `id`: a unique ID string
    - `sender`: the `playerID` of the sender
    - `payload`: the value passed to `sendChatMessage`

  Example:

  ```js
  [
    { id: 'foo', sender: '0', payload: 'Ready to play?' },
    { id: 'bar', sender: '1', payload: 'Let’s go!' },
  ]
  ```


- `log`: The game log.


- `matchID`: The match ID associated with the client.


- `playerID`: The player ID associated with the client.


- `matchData`: An array containing the players that have joined
  the current match via the [Lobby API](/api/Lobby.md).

    Example:

    ```js
    [
      { id: 0, name: 'Alice' },
      { id: 1, name: 'Bob', isConnected: true }
    ]
    ```


- `isActive`: `true` if the client is able to currently make
    a move or interact with the game.


- `isMultiplayer`: `true` if it is a multiplayer game.


- `isConnected`: `true` if connection to the server is active.


- `credentials`: Authentication token for this player when using
    the [Lobby REST API](/api/Lobby.md#server-side-api).

<!-- tabs:end -->


================================================
FILE: docs/documentation/api/Game.md
================================================
# Game

?> Using TypeScript? Check out [the TypeScript docs](typescript.md) on how to type your game object.

```js
{
  // The name of the game.
  name: 'tic-tac-toe',

  // Function that returns the initial value of G.
  // setupData is an optional custom object that is
  // passed through the Game Creation API.
  setup: ({ ctx, ...plugins }, setupData) => G,

  // Optional function to validate the setupData before
  // matches are created. If this returns a value,
  // an error will be reported to the user and match
  // creation is aborted.
  validateSetupData: (setupData, numPlayers) => 'setupData is not valid!',

  moves: {
    // short-form move.
    A: ({ G, ctx, playerID, events, random, ...plugins }, ...args) => {},

    // long-form move.
    B: {
      // The move function.
      move: ({ G, ctx, playerID, events, random, ...plugins }, ...args) => {},
      // Prevents undoing the move.
      // Can also be a function: ({ G, ctx }) => true/false
      undoable: false,
      // Prevents the move arguments from showing up in the log.
      redact: true,
      // Prevents the move from running on the client.
      client: false,
      // Prevents the move counting towards a player’s number of moves.
      noLimit: true,
      // Processes the move even if it was dispatched from an out-of-date client.
      // This can be risky; check the validity of the state update in your move.
      ignoreStaleStateID: true,
    },
  },

  // Everything below is OPTIONAL.

  // Function that allows you to tailor the game state to a specific player.
  playerView: ({ G, ctx, playerID }) => G,

  // The seed used by the pseudo-random number generator.
  seed: 'random-string',

  turn: {
    // The turn order.
    order: TurnOrder.DEFAULT,

    // Called at the beginning of a turn.
    onBegin: ({ G, ctx, events, random, ...plugins }) => G,

    // Called at the end of a turn.
    onEnd: ({ G, ctx, events, random, ...plugins }) => G,

    // Ends the turn if this returns true.
    // Returning { next }, sets next playerID.
    endIf: ({ G, ctx, random, ...plugins }) => (
      true | { next: '0' }
    ),

    // Called after each move.
    onMove: ({ G, ctx, events, random, ...plugins }) => G,

    // Prevents ending the turn before a minimum number of moves.
    minMoves: 1,

    // Ends the turn automatically after a number of moves.
    maxMoves: 1,

    // Calls setActivePlayers with this as argument at the
    // beginning of the turn.
    activePlayers: { ... },

    stages: {
      A: {
        // Players in this stage are restricted to moves defined here.
        moves: { ... },

        // Players in this stage will be moved to the stage specified
        // here when the endStage event is called.
        next: 'B'
      },

      ...
    },
  },

  phases: {
    A: {
      // Called at the beginning of a phase.
      onBegin: ({ G, ctx, events, random, ...plugins }) => G,

      // Called at the end of a phase.
      onEnd: ({ G, ctx, events, random, ...plugins }) => G,

      // Ends the phase if this returns true.
      endIf: ({ G, ctx, random, ...plugins }) => true,

      // Overrides `moves` for the duration of this phase.
      moves: { ... },

      // Overrides `turn` for the duration of this phase.
      turn: { ... },

      // Make this phase the first phase of the game.
      start: true,

      // Set the phase to enter when this phase ends.
      // Can also be a function: ({ G, ctx }) => 'nextPhaseName'
      next: 'nextPhaseName',
    },

    ...
  },

  // The minimum and maximum number of players supported
  // (This is only enforced when using the Lobby server component.)
  minPlayers: 1,
  maxPlayers: 4,

  // Ends the game if this returns anything.
  // The return value is available in `ctx.gameover`.
  endIf: ({ G, ctx, random, ...plugins }) => obj,

  // Called at the end of the game.
  // `ctx.gameover` is available at this point.
  onEnd: ({ G, ctx, events, random, ...plugins }) => G,

  // Disable undo feature for all the moves in the game
  disableUndo: true,

  // Transfer delta state with JSON Patch in multiplayer
  deltaState: true,
}
```


================================================
FILE: docs/documentation/api/Lobby.md
================================================
# Lobby

The [Server](/api/Server) hosts the Lobby REST API that can be used to create
and join matches. It is particularly useful when you want to
authenticate clients to prove that they have the right to send
actions on behalf of a player.

Authenticated matches are created with server-side tokens for each player.
You can create a match with the `create` API call, and join a player to a
match with the `join` API call.

A match that is authenticated will not accept moves from a client on behalf
of a player without the appropriate credential token.

Use the `create` API call to create a match that requires credential tokens.
When you call the `join` API, you can retrieve the credential token for a
particular player.

## Clients

<!-- tabs:start -->
### **Plain JS**

boardgame.io provides a lightweight wrapper around the Fetch API to simplify
using a Lobby API server from the client.


```js
import { LobbyClient } from 'boardgame.io/client';

const lobbyClient = new LobbyClient({ server: 'http://localhost:8000' });

lobbyClient.listGames()
  .then(console.log) // => ['chess', 'tic-tac-toe']
  .catch(console.error);
```

### **React**

The React lobby component provides a more high-level client, including UI
for listing, joining, and creating matches.

```js
import { Lobby } from 'boardgame.io/react';
import { TicTacToe } from './Game';
import { TicTacToeBoard } from './Board';

<Lobby
  gameServer={`https://${window.location.hostname}:8000`}
  lobbyServer={`https://${window.location.hostname}:8000`}
  gameComponents={[
    { game: TicTacToe, board: TicTacToeBoard }
  ]}
/>;
```

`gameComponents` expects an array of objects with these fields:

- `game`: A boardgame.io `Game` definition.
- `board`: The React component that will render the board.

<!-- tabs:end -->

## REST API

### Listing available game types

#### GET `/games`

Returns an array of names for the games this server is running.

#### Using a LobbyClient instance

```js
const games = await lobbyClient.listGames();
```

### Listing all matches for a given game

#### GET `/games/{name}`

Returns all match instances of the game named `name`.

Returns an array of `matches`. Each instance has fields:

- `matchID`: the ID of the match instance.

- `players`: the list of seats and players that have joined the game, if any.

- `setupData` (optional): custom object that was passed to the game `setup` function.

#### Using a LobbyClient instance

```js
const { matches } = await lobbyClient.listMatches('tic-tac-toe');
```

### Getting a specific match by its ID

#### GET `/games/{name}/{id}`

Returns a match instance given its matchID.

Returns a match instance. Each instance has fields:

- `matchID`: the ID of the match instance.

- `players`: the list of seats and players that have joined the match, if any.

- `setupData` (optional): custom object that was passed to the game `setup` function.

#### Using a LobbyClient instance

```js
const match = await lobbyClient.getMatch('tic-tac-toe', 'matchID');
```

### Creating a match

#### POST `/games/{name}/create`

Creates a new authenticated match for a game named `name`.

Accepts three parameters:

- `numPlayers` (required): the number of players.

- `setupData` (optional): custom object that is passed to the game `setup` function.

- `unlisted` (optional): if set to `true`, the match will be excluded from the public list of match instances.

Returns `matchID`, which is the ID of the newly created game instance.

#### Using a LobbyClient instance

```js
const { matchID } = await lobbyClient.createMatch('tic-tac-toe', {
  numPlayers: 2
});
```

### Joining a match

#### POST `/games/{name}/{id}/join`

Allows a player to join a particular match instance `id` of a game named `name`.

Accepts three JSON body parameters:

- `playerName` (required): the display name of the player joining the match.

- `playerID` (optional): the ordinal player in the match that is being joined (`'0'`, `'1'`...).  
If not sent, will be automatically assigned to the first available ordinal.

- `data` (optional): additional metadata to associate with the player.

Returns `playerCredentials` which is the token this player will require to authenticate their actions in the future and `playerID`, which can be useful if you didn’t specify a `playerID` when making the request.

#### Using a LobbyClient instance

```js
const { playerCredentials } = await lobbyClient.joinMatch(
  'tic-tac-toe',
  'matchID',
  {
    playerID: '0',
    playerName: 'Alice',
  }
);
```

### Updating a player’s metadata

#### POST `/games/{name}/{id}/update`

Rename and/or update additional metadata for a player in the match instance `id` of a game named `name` previously joined by the player.

Accepts four JSON body parameters, requires at least one of the two optional parameters:

- `playerID` (required): the ID used by the player in the match (0,1...).

- `credentials` (required): the authentication token of the player.

- `newName` (optional): the new name of the player.

- `data` (optional): additional metadata to associate with the player.

#### Using a LobbyClient instance

```js
await lobbyClient.updatePlayer('tic-tac-toe', 'matchID', {
  playerID: '0',
  credentials: 'playerCredentials',
  newName: 'Al',
});
```

### Leaving a match

#### POST `/games/{name}/{id}/leave`

Leave the match instance `id` of a game named `name` previously joined by the player.

Accepts two JSON body parameters, all required:

- `playerID`: the ID used by the player in the match (0, 1...).

- `credentials`: the authentication token of the player.

#### Using a LobbyClient instance

```js
await lobbyClient.leaveMatch('tic-tac-toe', 'matchID', {
  playerID: '0',
  credentials: 'playerCredentials',
});
```

### Playing again

#### POST `/games/{name}/{id}/playAgain`

- `{name}` (required): the name of the game being played again.

- `{id}` (required): the ID of the previous finished match.

Given a previous match, generates a match ID where users should go if they want to play again. Creates this new match if it didn't exist before.

Accepts these parameters:

- `playerID` (required): the player ID of the player in the previous match.

- `credentials` (required): player's credentials.

- `numPlayers` (optional): the number of players. Defaults to the `numPlayers` value of the previous match.

- `setupData` (optional): custom object that was passed to the game `setup` function. Defaults to the `setupData` object of the previous room.

Returns `nextMatchID`, which is the ID of the newly created match that the user should go to play again.

#### Using a LobbyClient instance

```js
const { nextMatchID } = await lobbyClient.playAgain('tic-tac-toe', 'matchID', {
  playerID: '0',
  credentials: 'playerCredentials',
});
```


================================================
FILE: docs/documentation/api/Server.md
================================================
# Server

Creates a `boardgame.io` server. This is only required when
`multiplayer` is set to `true` on the client. It creates a
[Koa](http://koajs.com/) app that keeps track of the game
states of the various clients connected to it, and also
broadcasts updates to those clients so that all browsers
that are connected to the same game are kept in sync in
realtime.

The server also hosts a REST [API](https://boardgame.io/documentation/#/api/Lobby?id=server-side-api) that is used for creating
and joining games. This is hosted on the same port, but can
be configured to run on a separate port.

#### Arguments

A config object with the following options:

1. `games` (_array_) (required): a list of game implementations
   (each should be an object conforming to the [Game API](/api/Game.md)).

2. `origins` (_array_) (required): a list of allowed origins for
    [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS "Cross-Origin Resource Sharing").
    
    The list can contain strings or regular expressions, matching the origins
    that are allowed to access the game server. For example, this could be
    `['https://example.com']` if that’s where your game is running. While
    developing locally you probably want to allow any page running on localhost
    to connect. See [Usage](#usage) below for an example.

[cors]: https://github.com/expressjs/cors#configuration-options

3. `db` (_object_): the [database connector](/storage).
   If not provided, an in-memory implementation is used.

4. `transport` (_object_): the transport implementation.
   If not provided, socket.io is used.

5. `uuid` (_function_): an optional function that returns a unique identifier, used to create new game IDs and — if `generateCredentials` is not specified — player credentials. Defaults to [nanoid](https://www.npmjs.com/package/nanoid).

6. `generateCredentials` (_function_): an optional function that returns player credentials to store in the game metadata and validate against. If not specified, the `uuid` function will be used.

7. `authenticateCredentials` (_function_): an optional function that tests if a player’s move is made with the correct credentials when using the default socket.io transport implementation.

8. `apiOrigins` (_array_): a list of allowed origins for requests to the Lobby API. Defaults
   to the value provided as the `origins` option (which also applies to the socket transport).

#### Returns

An object that contains:

1. `run` (_function_): A function to run the server.
    `(portOrConfig, callback) => ({ apiServer, appServer })`

2. `kill` (_function_): A function to stop the server.
    `({ apiServer, appServer }) => void`

3. `app` (_object_): The Koa app.

4. `db` (_object_): The database implementation.

5. `router` (_object_): The Koa Router for the server API.

### Usage

#### Basic

```js
const { Server, Origins } = require('boardgame.io/server');

const server = Server({
  // Provide the definitions for your game(s).
  games: [game1, game2, ...],

  // Provide the database storage class to use.
  db: new DbConnector(),

  origins: [
    // Allow your game site to connect.
    'https://www.mygame.domain',
    // Allow localhost to connect, except when NODE_ENV is 'production'.
    Origins.LOCALHOST_IN_DEVELOPMENT
  ],
});

server.run(8000);
```

#### With callback

```js
server.run(8000, () => console.log("server running..."));
```

#### With custom Lobby settings

You can pass `lobbyConfig` to configure the Lobby API during server startup:

```js
const lobbyConfig = {
  apiPort: 8080,
  apiCallback: () => console.log('Running Lobby API on port 8080...'),
};

server.run({ port: 8000, lobbyConfig });
```

Options are:

- `apiPort`: If specified, it runs the Lobby API in a separate Koa server on
this port. Otherwise, it shares the same Koa server running on the default
boardgame.io `port`.
- `apiCallback`: Called when the Koa server is ready. Only applicable if
`apiPort` is specified.

#### With HTTPS

```js
const { Server } = require('boardgame.io/server');
const fs = require('fs');

const server = Server({
  games: [game1, game2, ...],

  https: {
    cert: fs.readFileSync('/path/to/cert'),
    key: fs.readFileSync('/path/to/key'),
  },
});

server.run(8000);
```

#### With custom authentication

`generateCredentials` is called when a player joins a game with:

- `ctx`: The Koa context object, which can be used to generate tailored credentials from request headers etc.

`authenticateCredentials` is called when a player makes a move with:

  - `credentials`: The credentials sent from the player’s client
  - `playerMetadata`: The metadata object for the `playerID` making a move

Below is an example of how you might implement custom authentication with a hypothetical `authService` library.

The `generateCredentials` method checks for the Authorization header on incoming requests and tries to use it to decode a token. It returns an ID from the result, storing a public user ID as “credentials” in the game metadata.

The `authenticateCredentials` method passed to the `Server` also expects a similar token, which when decoded matches the ID stored in game metadata.


```js
const { Server } = require('boardgame.io/server');

const generateCredentials = async ctx => {
  const authHeader = ctx.request.headers['authorization'];
  const token = await authService.decodeToken(authHeader);
  return token.uid;
}

const authenticateCredentials = async (credentials, playerMetadata) => {
  if (credentials) {
    const token = await authService.decodeToken(credentials);
    if (token.uid === playerMetadata.credentials) return true;
  }
  return false;
}

const server = Server({
  games: [game1, game2, ...],
  generateCredentials,
  authenticateCredentials,
});

server.run(8000);
```

!> N.B. This approach is not currently compatible with how the React `<Lobby>` provides credentials.

### Extending the server

The boardgame.io server uses [Koa](koajs.com/) and
[`@koa/router`](https://github.com/koajs/router). You can customise the
Lobby API by accessing the router instance, for example to add routes or
to add custom middleware for existing routes. See an example of customising
the entire Koa app [in the Heroku deployment guide](/deployment.md#frontend-and-backend).

#### Add a custom route

```js
const server = Server({ /* options */ });

server.router.get('/custom-endpoint', (ctx, next) => {
  ctx.body = 'Hello World!';
});

server.run(8000);
```

#### Add middleware

```js
const server = Server({ /* options */ });

// Add middleware to the create game route.
server.router.use('/games/:name/create', async (ctx, next) => {
  // Decide number of players etc. based on some other API.
  const { numPlayers, setupData } = await fetchDataFromSomeCustomAPI();
  // Set request body to be used by the create game route.
  ctx.request.body.numPlayers = numPlayers;
  ctx.request.body.setupData = setupData;
  next();
});

server.run(8000);
```


================================================
FILE: docs/documentation/chat.md
================================================
# Chat

The boardgame.io client provides a basic API for sending chat messages between players in a match using the [multiplayer server](multiplayer?id=remote-master).

The [plain JS client](api/Client?id=properties) and the [React client](api/Client?id=board-props) (via board props) both provide the following properties:

- `sendChatMessage(message)`: Function that sends a chat message to other players. The message argument can be a string or you can send objects to include more metadata. For example, you might decide to include a timestamp along with message text:

    ```js
    sendChatMessage({ message: 'Hello', time: Date.now() });
    ```

- `chatMessages`: An array containing chat messages this client has received. Each message is an object with the following properties:

    - `id`: a unique message ID string
    - `sender`: the `playerID` of the message’s sender
    - `payload`: the value of the `message` argument passed to `sendChatMessage`

  Example `chatMessages` array:

  ```js
  [
      { id: 'foo', sender: '0', payload: 'Ready to play?' },
      { id: 'bar', sender: '1', payload: 'Let’s go!' },
  ]
  ```

### Notes

- **Chat messages are ephemeral and are not stored by the boardgame.io server.** A client only receives messages sent while it is connected to the server. If messages are sent amongst players before another player has connected, the new player will not receive those prior messages. Similarly, if the page is refreshed, any previously received messages will be lost.

- **Only players can send chat messages.** Assuming the match is authenticated via [the Lobby server](api/Lobby), only players are permitted to send messages, which are authenticated using the same logic as other game actions. Spectator clients can receive and view chat messages, but not send messages of their own.


================================================
FILE: docs/documentation/concepts.md
================================================
# Concepts

### State

boardgame.io captures game state in two objects: `G` and `ctx`.

```js
{
  // The game state (managed by you).
  G: {},

  // Read-only metadata (managed by the framework).
  ctx: {
    turn: 0,
    currentPlayer: '0',
    numPlayers: 2,
  }
}
```

These state objects are passed around everywhere and maintained
on both client and server seamlessly. The state in `ctx` is
incrementally adoptable, meaning that you can manage all the
state manually in `G` if you so desire.

?> `ctx` contains other fields not shown here that games
can take advantage of, including support for game phases and complex
turn orders.

!> Because state can be sent between client and server,
`G` must be a JSON-serializable object; in particular, it must
not contain classes or functions.

### Moves

These are functions that tell the framework how to change `G`
when a particular game move is made. They must not depend on
external state or have any side-effects (except modifying `G`).
See the guide on [Immutability](immutability.md) for how
immutability is handled by the framework.

```js
moves: {
  drawCard: ({ G, ctx }) => {
    const card = G.deck.pop();
    G.hand.push(card);
  },

  // ...
}
```

On the client, you use a `moves` object to dispatch your
move functions.

<!-- tabs:start -->
#### **Plain JS**

You can access `moves` from an instance of the plain JavaScript client:

```js
client.moves.drawCard();
```

#### **React**

Using React, `moves` is provided through your component’s `props`:

```js
props.moves.drawCard();
```

<!-- tabs:end -->

### Events

These are framework-provided functions that are analogous to moves, except that they work on `ctx`. These typically advance the game state by doing things like
ending the turn, changing the game phase etc.
Events are dispatched from the client in a similar way to moves.

<!-- tabs:start -->
#### **Plain JS**
```js
client.events.endTurn();
```

#### **React**
```js
props.events.endTurn();
```
<!-- tabs:end -->

For more details, see the guide on [Events](events.md).

### Phase

A phase is a period in the game that overrides the game
configuration while it is active. For example, you can use
a different set of moves or a different turn order during
a phase. The game can transition between different phases, and turns
occur inside phases. See the guide on [Phases](phases.md) for more details.

### Turn

A turn is a period of the game that is associated with an individual
player. It typically consists of one or more moves made by
that player before it passes on to another player. You can
also allow other players to play during your turn, although
this is less common. See the guide on
[Turn Orders](turn-order.md) for more details.

### Stage

A stage is similar to a phase, except that it happens within a turn, and
applies to individual players rather than the game as a whole.
A turn may be subdivided into many stages, each allowing a different set of moves
and overriding other game configuration options while that stage is active.
Also, different players can be in different stages during a turn.
See the guide on [Stages](stages.md) for more details.


================================================
FILE: docs/documentation/debugging.md
================================================
# Debugging

### Using the Debug Panel in production

boardgame.io comes bundled with a debug panel that lets you
interact with your game and game clients. When you build your app
for production (i.e. when `NODE_ENV === 'production'`) this is stripped
out from the final bundle.

If you want to include the debug panel in a production build you can
do so explicitly when creating your client:

```js
import { Debug } from 'boardgame.io/debug';

const client = Client({
  // ...
  debug: { impl: Debug },
});
```

### Debug Panel options

You can use the `collapseOnLoad` option to hide the panel by default when the client loads. The `hideToggleButton` option removes the toggle button on the side of the panel which means you can only use the keyboard shortcut to toggle its visibility.

```js
const client = Client({
  // ...
  debug: {
    // ...
    collapseOnLoad: true/false,
    hideToggleButton: true/false
  },
});
```

### Custom metadata in game logs

It can sometimes be helpful to surface some metadata during a move.
You can do this by using the log plugin. For example,

```js
const move = ({ log }) => {
  log.setMetadata('metadata for this move');
};
```

This metadata is stored in the `log` client property and displayed
in the Log section of the debug panel.

### Redux

The framework uses Redux under the hood.
You may sometimes want to debug this Redux store directly.
In order to do so, you can pass along a Redux store enhancer
with your client. For example,

```js
import logger from 'redux-logger';
import { applyMiddleware } from 'redux';

Client({
  // ...
  enhancer: applyMiddleware(logger),
});
```

Doing so will `console.log` on state changes. This can also hook into the [Chrome Redux DevTools](http://extension.remotedev.io/) browser extension like this:

```js
Client({
  // ...
  enhancer: (
    window.__REDUX_DEVTOOLS_EXTENSION__
    && window.__REDUX_DEVTOOLS_EXTENSION__()
  ),
})
```

or both

```js
import logger from 'redux-logger';
import { applyMiddleware, compose } from 'redux';

Client({
  // ...
  enhancer: compose(
    applyMiddleware(logger),
    (window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
  ),
})
```

### Server + Sockets

The Koa-server can be debugged by setting the `DEBUG` environment variable before starting it.
This will give you access to logs of incoming requests as well as the socket.io logs.
To set the environment variable prepend your npm script to run the server like so:

```
DEBUG=* node server.js
```

> NOTE: For various debugging scopes have a look at the [socket.io-docs](https://socket.io/docs/v4/logging-and-debugging/#available-debugging-scopes)


================================================
FILE: docs/documentation/deployment.md
================================================
# Deployment

## Serverless Options

For one-player or pass-and-play games, you may not need the boardgame.io game
server and prefer to serve an app that runs entirely on the client. If you
don’t need multiplayer features, this can be a lot simpler than getting a
Node.js server deployed.

There are many services that can help deploy a static app, including some that
offer free options like [Netlify](https://www.netlify.com/) and
[Render](https://render.com/).

<!-- tabs:start -->

### **Plain JS**

If you followed along with the Plain JS tutorial, you can also use Parcel to
build your app for production.

Add a build script to your `package.json`:

```json
{
  "scripts": {
    "build": "parcel build index.html --out-dir build",
  }
}
```

Running `npm run build` will now create an optimised production build in
`/build`, which you can host just about anywhere.

#### Deployment configuration

Both Netlify and Render offer options to continuously deploy the latest version
of your app from a Git repository. These configurations should help you get
up and running with these services.

<details>
<summary><strong>Netlify</strong></summary>

1. Create a new deployment (see [Netlify docs](https://docs.netlify.com/site-deploys/create-deploys/)).

2. Use the following values for the deployment:

  | Option            | Value           |
  |-------------------|-----------------|
  | Build Command     | `npm run build` |
  | Publish Directory | `build`         |

</details>

<details>
<summary><strong>Render</strong></summary>

1. Create a new Web Service on Render and connect it to your project repository.

2. Use the following values during creation:

  | Option            | Value           |
  |-------------------|-----------------|
  | Environment       | `Static Site`   |
  | Build Command     | `npm run build` |
  | Publish Directory | `build`         |

</details>

### **React**

Running `npm run build` in a Create React App project will create an optimised
production build in `/build`, which you can host just about anywhere.

#### Deployment guides

- **Netlify:** See [the guide on how to deploy to Netlify](https://create-react-app.dev/docs/deployment/#netlify) in the Create React App docs.

- **Render:** See [“Deploy a Create React App Static Site”](https://render.com/docs/deploy-create-react-app) in the Render docs.

<!-- tabs:end -->

## Heroku
[Heroku](https://heroku.com) uses 2 different ways to determine the run command of a node application. It is possible to either:

- Add a Procfile to the project root directory with the following line  
  `web: node -r esm server.js`

- Update the start script in the package.json to  
  `"start": "node -r esm server.js"`

On Heroku, a regular heroku/nodejs buildpack is necessary to build your app which is usually selected by default for node applications.  

### Frontend and Backend
In order to deploy a game to Heroku, the game has to be running on a single port. To do so, the [Server](/api/Server.md) has to handle both the API requests and serving the pages.  
Below is an example of how to achieve that.

First install these extra dependencies:

```
npm i koa-static
```
Then adjust your `server.js` file like this:

```js
// server.js

import { Server } from 'boardgame.io/server';
import path from 'path';
import serve from 'koa-static';
import { TicTacToe } from './game';

const server = Server({ games: [TicTacToe] });
const PORT = process.env.PORT || 8000;

// Build path relative to the server.js file
const frontEndAppBuildPath = path.resolve(__dirname, './build');
server.app.use(serve(frontEndAppBuildPath))

server.run(PORT, () => {
  server.app.use(
    async (ctx, next) => await serve(frontEndAppBuildPath)(
      Object.assign(ctx, { path: 'index.html' }),
      next
    )
  )
});
```

The [Lobby](/api/Lobby.md) might be as follows:

```jsx
import React from 'react';
import { Lobby } from 'boardgame.io/react';
import { TicTacToeBoard } from './board';
import { TicTacToe } from './game';

const { protocol, hostname, port } = window.location;
const server = `${protocol}//${hostname}:${port}`;
const importedGames = [{ game: TicTacToe, board: TicTacToeBoard }];

export default () => (
  <div>
    <h1>Lobby</h1>
    <Lobby gameServer={server} lobbyServer={server} gameComponents={importedGames} />
  </div>
);
```

Or, without the lobby, pass the server address when calling `SocketIO`:

```js
import { SocketIO } from 'boardgame.io/multiplayer';

const { protocol, hostname, port } = window.location;
const server = `${protocol}//${hostname}:${port}`;

const GameClient = Client({
  // ...
  multiplayer: SocketIO({ server }),
});
```

### Backend Only
If you only need to publish your backend to Heroku, your `server.js` can be simplified to this:

```js
// server.js

import { Server } from 'boardgame.io/server';
import { TicTacToe } from './game';

const server = Server({ games: [TicTacToe] });
const PORT = process.env.PORT || 8000;

server.run(PORT);
```

And your [Lobby](/api/Lobby.md) would now be pointing to your Heroku app URL:
```jsx
import React from 'react';
import { Lobby } from 'boardgame.io/react';
import { TicTacToeBoard } from './board';
import { TicTacToe } from './game';

const server = `https://yourapplication.herokuapp.com`;
const importedGames = [{ game: TicTacToe, board: TicTacToeBoard }];

export default () => (
  <div>
    <h1>Lobby</h1>
    <Lobby gameServer={server} lobbyServer={server} gameComponents={importedGames} />
  </div>
);
```

Or, without the lobby, pass the Heroku app URL when calling `SocketIO`:

```js
import { SocketIO } from 'boardgame.io/multiplayer';

const GameClient = Client({
  // ...
  multiplayer: SocketIO({ server: 'https://yourapplication.herokuapp.com' }),
});
```


================================================
FILE: docs/documentation/events.md
================================================
# Events

An event is used to advance the game state. It is somewhat
analogous to a move, except that while a move changes
`G`, an event changes `ctx`. Also, events are provided by the
framework (as opposed to moves, which are written by you).

### Event Types

#### endStage

This event takes the player that called it out of the stage
that they are in. If the definition for the current stage
in the game object specifies a `next` option, then the player
is taken to the next stage. If not, the player is
returned to a state where they are not in any stage.

```js
endStage();
```

#### endTurn

This event ends the turn.
The default behavior is to increment `ctx.turn` by `1`
and advance `currentPlayer` to the next player according
to the configured [turn order](turn-order.md) (the default being a round-robin).

This event also accepts an argument, which (if provided)
switches the turn to the specified player instead.

```js
endTurn(); // without argument
endTurn({ next: '2' }); // Player 2 is the next player.
```

#### endPhase

This event ends the current phase. If the definition for the
current phase in the game object specifies a
`next` option, then the game moves to that phase. If not, the
game returns to a state where no phase is active.

```js
endPhase();
```

#### endGame

This event ends the game. If you pass an argument to it,
then that argument is made available in `ctx.gameover`.
After the game is over, further state changes to the game
(via a move or event) are not possible.

```js
endGame();
```

#### setStage

Takes the player that called the event into the stage specified.

```js
setStage('stage-name');
```

#### setPhase

Takes the game into the phase specified. Ends the active phase first.

```js
setPhase('phase-name');
```

#### setActivePlayers

Allows adding additional players to the set of "active players", and
also any stages that you want to put them in. See the guide on [Stages](stages.md)
for more details.

### Triggering an event from game logic.

You can trigger events from a move or code inside
your game logic (a phase’s `onBegin` hook, for example).
This is done through the `events` API in the object passed
as the first argument to moves:

```js
moves: {
  drawCard: ({ G, ctx, events }) => {
    events.endPhase();
  };
}
```

!> Events are queued up and triggered **after** a move.
Any changes you make to `G` will be applied before events are
triggered, even if the event is called first in your move function.

### Triggering an event from the client

<!-- tabs:start -->

#### **Plain JS**

Events are available inside the `events` property of
a boardgame.io client instance. For example:

```js
import { Client } from 'boardgame.io/client';

const client = Client({ /* options */ });

const clickHandler = () => {
  client.events.endTurn();
}
```

#### **React**

Events are available through `props` inside the
`events` object. For example:

```js
import React from 'react';

function Board({ events }) {
  const onClick = () => {
    events.endTurn();
  };

  return <button onClick={onClick}>End Turn</button>;
}
```
<!-- tabs:end -->

### Disabling events

Events can be disabled. For example, you might not want a
player to be able to end the game directly by simply calling
the `endGame` event.

In order to disable an event, just add `eventName: false` to
the `events` section in your game config.

```js
const game = {
  events: {
    endGame: false,
    // ...
  },
};
```

!> This doesn't apply to events in moves or hooks, but just the
ability to call an event directly from a client.

### Calling events from hooks

The events API is available in game hooks like it is inside moves. However,
because of how hooks and events interact, certain events cannot be called from
certain hooks. The following table shows which hooks support which events.

|                    | turn<br>`onMove` | turn<br>`onBegin` | turn<br>`onEnd` | phase<br>`onBegin` | phase<br>`onEnd` | game<br>`onEnd` |
|-------------------:|:----------------:|:-----------------:|:---------------:|:------------------:|:----------------:|:---------------:|
|         `setStage` |         ✅        |         ❌         |        ❌        |          ❌         |         ❌        |        ❌        |
|         `endStage` |         ✅        |         ❌         |        ❌        |          ❌         |         ❌        |        ❌        |
| `setActivePlayers` |         ✅        |         ✅         |        ❌        |          ❌         |         ❌        |        ❌        |
|          `endTurn` |         ✅        |         ✅         |        ❌        |          ✅         |         ❌        |        ❌        |
|         `setPhase` |         ✅        |         ✅         |        ✅        |          ✅         |         ❌        |        ❌        |
|         `endPhase` |         ✅        |         ✅         |        ✅        |          ✅         |         ❌        |        ❌        |
|          `endGame` |         ✅        |         ✅         |        ✅        |          ✅         |         ✅        |        ❌        |

✅ = supported &nbsp;&nbsp;&nbsp; ❌ = not supported


================================================
FILE: docs/documentation/immutability.md
================================================
# Immutability

The principle of immutability as applied to state changing
functions like moves in [boardgame.io](https://boardgame.io/)
mandates that they be pure functions. What this means is that
you cannot depend on any **external state**, nor can you have any
**side-effects**, i.e. you cannot modify anything that isn't
a local variable (not even the arguments).

The benefits of architecting a system with this principle are
that you can ensure repeatability (moves can be replayed
over a particular state value multiple times in different places)
and you can do cheap comparisons to check if something changed.

A traditional pure function just accepts arguments and then
returns the new state. Something like this:

```js
function move({ G }) {
  // Return new value of G without modifying the arguments.
  return { ...G, hand: G.hand + 1 };
}
```

?> The example above uses the
[spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) to create a new object.

[boardgame.io](https://boardgame.io/) provides a more convenient
syntax by allowing you to mutate `G` directly while using
a [library](https://github.com/mweststrate/immer) under the hood
to convert your move into a pure function that respects the
immutability principle. Both styles are supported interchangeably,
so use the one that you prefer.

```js
function move({ G }) {
  G.hand++;
}
```

?> Note that in this style you do not return the new state.
In fact, returning something while also mutating `G` is
considered an error.

!> You can only modify `G`. Other values passed to your moves
   are read-only and should never be modified in either style.
   Changes to `ctx` can be made using [events](events.md).

### Invalid moves

In both styles, invalid moves are indicated by returning a
special constant. This tells the framework that the current
set of arguments passed in is illegal and that the move
ought to be discarded. For example, you might do this if
the user tries to click on an already filled cell in
Tic-Tac-Toe.

```js
import { INVALID_MOVE } from 'boardgame.io/core';

moves: {
  clickCell: function({ G, ctx }, id) {
    // Illegal move: Cell is filled.
    if (G.cells[id] !== null) {
      return INVALID_MOVE;
    }

    // Fill cell with 0 or 1 depending on the current player.
    G.cells[id] = ctx.currentPlayer;
  }
}
```

### Additional Reading

[Immutable Update Patterns](https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns)


================================================
FILE: docs/documentation/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>boardgame.io</title>
  <meta name="description" content="Open-Source JavaScript Game Engine for Turn-Based Games">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:creator" content="@nicolodavis">
  <meta name="twitter:title" content="boardgame.io">
  <meta name="twitter:image" content="https://res.cloudinary.com/dyfmhmho5/image/upload/v1543585150/logo_w1snck.png">
  <meta name="twitter:description" content="Open Source Game Engine for Turn-Based Games">
  <link rel="shortcut icon" href="https://raw.githubusercontent.com/boardgameio/boardgame.io/main/docs/favicon.png" type="image/png" sizes="16x16">
  <link rel="stylesheet" href="//unpkg.com/docsify-themeable@0/dist/css/theme-simple.css">
  <link rel="stylesheet" href="theme.css">

  <style>
  .gitter-open-chat-button {
    right: 1%;
    font-family: var(--base-font-family);
    letter-spacing: .2ch;
    background: var(--theme-color);
    box-shadow: 0 4px 13px var(--mono-base);
  }

  @media screen and (min-width: 768px) {
    .gitter-open-chat-button {
      font-size: .9375em;
    }
  }

  iframe {
    box-shadow: 0 0 10px var(--mono-tint2);
    border-radius: var(--border-radius-l);
    background: var(--mono-tint3);
  }

  iframe.plain {
    box-shadow: none;
    border: none;
    background: transparent;
    min-width: 0;
    width: 100%;
  }

  @media only screen and (max-device-width: 500px) {
    iframe.react {
      max-height: 60vh;
    }
  }
  </style>
</head>

<body>
  <div id="app"></div>
</body>

<script>
  window.$docsify = {
    name: 'boardgame.io',
    nameLink: {
      '/': '..'
    },
    repo: 'https://github.com/boardgameio/boardgame.io',
    logo: '../logo-optimized.svg',
    homepage: 'concepts.md',
    loadSidebar: 'sidebar.md',
    subMaxLevel: 2,
    auto2top: true,
    search: 'auto', // default
    pagination: {}, // default
    plugins: [],
    markdown: {
      renderer: {
        code: function(code, lang) {
          if (lang == 'codepen') {
            return code;
          }
          if (lang == 'react') {
            return code;
          }
          return this.origin.code.apply(this, arguments);
        }
      }
    }
  }
</script>

<script src="//unpkg.com/docsify@4"></script>
<script src="//unpkg.com/docsify-themeable@0"></script>
<script src="//unpkg.com/docsify@4/lib/plugins/search.min.js"></script>
<script src="//unpkg.com/docsify-pagination@2/dist/docsify-pagination.min.js"></script>
<script src="//unpkg.com/docsify-tabs@1"></script>
<script src="//unpkg.com/docsify-edit-on-github@1/index.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-json.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-jsx.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-typescript.min.js"></script>
<script>
  window.$docsify.plugins.push(EditOnGithubPlugin.create(
    'https://github.com/boardgameio/boardgame.io/blob/main/docs/documentation/',
    null,
    'Edit on GitHub'
  ));
</script>

<script>
  ((window.gitter = {}).chat = {}).options = {
    room: 'boardgame-io/General'
  };
</script>
<script src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer></script>

</html>


================================================
FILE: docs/documentation/multiplayer.md
================================================
# Multiplayer

In this section, we'll explain how the framework converts your
game logic into a multiplayer implementation without requiring
you to write any networking or storage layer code. We will continue
working with our Tic-Tac-Toe example from the [tutorial](tutorial.md).

### Clients and Masters

A boardgame.io client is what you create using the `Client` call.
You initialize it with your game object (which contains the moves),
so it has all the information that is needed to run the game.
This is where the story ends in a single player setup.

In a multiplayer setup, clients no longer act as authoritative
stores of the game state. Instead, they delegate the running of the
game to a game master. In this mode clients emit moves / events,
but the game logic runs on the master, which computes the next game state
before broadcasting it to other clients.

However, since clients are aware of the game rules, they also
run the game in parallel (this is called an optimistic update and is
an optimization that provides a lag-free experience).
In case a particular client computes the new game state incorrectly,
it is overridden by the master eventually, so the entire setup still
has a single source of authority. If a move accesses state that is not
accessible to the client (for instance secret state), then optimistic
updates may need to be disabled for that move. See the
[secret state documentation](secret-state.md) for more details.

## Local Master

The game master can run completely on the browser. This is useful to set
up pass-and-play multiplayer or for prototyping the multiplayer experience
without having to set up a server to test it.

To do this `import { Local } from 'boardgame.io/multiplayer'`,
and add `multiplayer: Local()` to the client options.
Now you can instantiate as many of these clients in your app as you like and
you will notice that they’re all kept in sync, sharing the same state.

<!-- tabs:start -->

#### **Plain JS**

Let’s update our `TicTacToeClient` to receive an additional `playerID`
option in its constructor. We’ll use this so that each client knows
which player it is playing for.

Then, we’ll update how we create the boardgame.io client, passing
`playerID` and setting `multiplayer` to use the Local Master.

```js
import { Client } from 'boardgame.io/client';
import { Local } from 'boardgame.io/multiplayer';
import { TicTacToe } from './Game';

class TicTacToeClient {
  constructor(rootElement, { playerID } = {}) {
    this.client = Client({
      game: TicTacToe,
      multiplayer: Local(),
      playerID,
    });
    // ...
  }
  // ...
}
````

Now instead of rendering one client into our app, we’ll render
one for each player ID:

```js
const appElement = document.getElementById('app');
const playerIDs = ['0', '1'];
const clients = playerIDs.map(playerID => {
  const rootElement = document.createElement('div');
  appElement.append(rootElement);
  return new TicTacToeClient(rootElement, { playerID });
});
```

[![Edit bgio-plain-js-multiplayer](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/bgio-plain-js-multiplayer-re48t?fontsize=14&hidenavigation=1&module=%2Fsrc%2FApp.js&theme=dark)

#### **React**

```js
// src/App.js

import React from 'react';
import { Client } from 'boardgame.io/react';
import { Local } from 'boardgame.io/multiplayer';
import { TicTacToe } from './Game';
import { TicTacToeBoard } from './Board';

const TicTacToeClient = Client({
  game: TicTacToe,
  board: TicTacToeBoard,
  multiplayer: Local(),
});

const App = () => (
  <div>
    <TicTacToeClient playerID="0" />
    <TicTacToeClient playerID="1" />
  </div>
);

export default App;
```

[![Edit boardgame.io](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/boardgameio-dibw3)
<!-- tabs:end -->

?> You may be wondering what the `playerID` parameter is from the
example above. Clients needs to be associated with a particular player
seat in order to make moves in a multiplayer setup. (If a client doesn’t have
a `playerID` it is a spectator that can see the live game state, but can't
actually make any moves.)

```react
<iframe class='plain' src='snippets/multiplayer' height='250' scrolling='no' title='example' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'></iframe>
```

In the example above you can play as Player 0 and Player 1 alternately
on the two boards. Clicking on a particular board when it is not that
player's turn has no effect.

### Storing state in the browser

If you want game state to be saved in the browser using `localStorage`,
you can pass additional options when creating a local master:

```js
Local({
  // Enable localStorage cache.
  persist: true,

  // Set custom prefix to store data under. Default: 'bgio'.
  storageKey: 'bgio',
});
```

## Remote Master

You can also run the game master on a separate server. Any boardgame.io
client can connect to this master (whether it is a browser, an Android
app etc.) and it will be kept in sync with other clients in realtime.

In order to connect a client to a remote master, we use the `multiplayer`
option again, but this time we import `SocketIO` instead of `Local`,
and specify the location of the server.

<!-- tabs:start -->

#### **Plain JS**

```js
import { SocketIO } from 'boardgame.io/multiplayer'

class TicTacToeClient {
  constructor(rootElement, { playerID } = {}) {
    this.client = Client({
      game: TicTacToe,
      multiplayer: SocketIO({ server: 'localhost:8000' }),
      playerID,
    });
    // ...
  }
  // ...
}
```

We also need to make a small tweak to our `update` method.
When using a remote master, the client won’t know the game state
when it first runs, so `update` will be called first with `null`,
then with the full game state after it connects to the server.

In a real implementation you might show a loading spinner to indicate
this, but we’ll just skip our `update` for now if state is `null`:

```js
update(state) {
  if (state === null) return;
  // ...
}
```

#### **React**

```js
import { SocketIO } from 'boardgame.io/multiplayer'

const TicTacToeClient = Client({
  game: TicTacToe,
  board: TicTacToeBoard,
  multiplayer: SocketIO({ server: 'localhost:8000' }),
});
```

<!-- tabs:end -->

Behind the scenes, the client now sends updates to the remote master
via a WebSocket whenever you make a move. Of course, we now need to run
a server at the location specified, which is discussed below.

### Setting up the server

We’ll create a new file at `src/server.js` to write our server code.

boardgame.io provides a server module that simplifies running the game
master on a Node server. We import that module and configure it with our
`TicTacToe` game object and a list of URL origins we want to allow to
connect to the server. Later you would set `origins` with your game’s domain
name, but for now we’ll import a default value that allows any locally served
page to connect.

```js
// src/server.js
const { Server, Origins } = require('boardgame.io/server');
const { TicTacToe } = require('./Game');

const server = Server({
  games: [TicTacToe],
  origins: [Origins.LOCALHOST],
});

server.run(8000);
```

?> See [the Server reference page](api/Server.md) for more detail on
   the various configuration options.

Because `Game.js` is an ES module, we will use [esm](https://github.com/standard-things/esm)
which enables us to use `import` statements in a Node environment:

```
npm install esm
```

We can then add a new script to our `package.json` to simplify
running the server:

```json
{
  "scripts": {
    "serve": "node -r esm src/server.js"
  }
}
```

We can now run `npm run serve` in one terminal to start the server and
`npm start` in another to serve our web app.
You can connect multiple clients to the same game by opening
your app in several different browser tabs.
You will notice that everything is kept in sync as you play
(state is not lost even if you refresh the page).

This example still has both players on the same screen. A more natural
setup would be to have each client just have a single (but distinct)
player.

<!-- tabs:start -->
#### **Plain JS**

You want one client to render:
```js
new TicTacToeClient(appElement, { playerID: '0' });
```

and another to render:
```js
new TicTacToeClient(appElement, { playerID: '1' });
```

#### **React**

You want one client to render:
```
<TicTacToeClient playerID="0" />
```

and another to render:
```
<TicTacToeClient playerID="1" />
```
<!-- tabs:end -->

One way to do this is to ask the player which seat they
want to take when they open your app and then set the
`playerID` accordingly. You can also use a URL path to
determine the player or use a matchmaking lobby.

Complete code from this section is available on CodeSandbox for both
[React](https://codesandbox.io/s/boardgameio-fsl8y) and
[Plain JS](https://codesandbox.io/s/bgio-plain-js-multiplayer-server-742oh)
versions.
To run the server, you can click **File** > **Export to ZIP** to download
the project, then run the server and client as described
above. Don't forget to run `npm install` in the project directory first!

?> **TIP** You can also set the `playerID` to point to any player while
prototyping by clicking on the box of that respective player on the debug UI.

### Multiple Game Types

You can serve multiple types of games from the same server:

```js
const app = Server({ games: [TicTacToe, Chess] });
```

For this to work correctly, make sure that each game
implementation specifies a name:

```js
const TicTacToe = {
  name: 'tic-tac-toe',
  // ...
};
```

### Game Instances

By default all client instances connect to a game with
an ID `'default'`. To play a new game instance, you can pass
`matchID` to your client. All clients that use
this ID will now see the same game state.

<!-- tabs:start -->

#### **Plain JS**

Pass `matchID` when creating your boardgame.io client:
```js
const client = Client({
  game: TicTacToe,
  matchID: 'matchID',
  // ...
});
```

You an also update a `matchID` on an already instantiated client:
```js
client.updateMatchID('newID');
```

#### **React**

```
<TicTacToeClient matchID="match-id"/>
```
<!-- tabs:end -->

The `matchID`, similar to the `playerID` can again be determined
either by a URL path or a lobby implementation.

### Storage

The default storage implementation is an in-memory map.
If you want something that's more persistent, you can use one
of the available database connectors, or even implement your own.

See [the storage docs](storage.md) for more details.


================================================
FILE: docs/documentation/notable_projects.md
================================================
# Projects

Nonexhaustive list of notable projects using boardgame.io. Feel free to send a PR to add your project to this list, but please have a demo that's accessible via a URL.


#### [![GitHub stars][b-ark]][c-ark] [Arknights: The Card Game (明日方舟: 采掘行动)][p-ark] \[[code][c-ark]\]
&nbsp;&nbsp;
A challenging single-player roguelike card game that is played locally, in Chinese.

[b-ark]: https://img.shields.io/github/stars/dadiaogames/arknights-card-game?label=%E2%98%85&logo=github
[p-ark]: https://dadiaogames.github.io/arknights-card-game/
[c-ark]: https://github.com/dadiaogames/arknights-card-game

#### [![GitHub stars][b1]][c1] Bad Flamingo \[[code][c1]\]
&nbsp;&nbsp;
Fool the computer, but not your friends! Adversarial "Quick, Draw".

[b1]: https://img.shields.io/github/stars/jayelm/bad-flamingo?label=%E2%98%85&logo=github
[c1]: https://github.com/jayelm/bad-flamingo

#### [![GitHub stars][b-bl]][c-bl]  [Battle Line][p-bl] \[[code][c-bl]\]
&nbsp;&nbsp;
Clone of Battle Line, a 2 player card game.

[b-bl]: https://img.shields.io/github/stars/rsandzimier/battleline?label=%E2%98%85&logo=github
[c-bl]: https://github.com/rsandzimier/battleline
[p-bl]: https://rsandzimier.github.io/battleline/

#### [![GitHub stars][jwbj-3]][jwbj-2]  [Black Jack (John Wick theme)][jwbj-1] \[[code][jwbj-2]\]
&nbsp;&nbsp;
A John Wick-themed Black Jack card game with custom graphics and sound.

[jwbj-3]: https://img.shields.io/github/stars/ipkevin/Blackjack-Builder?label=%E2%98%85&logo=github
[jwbj-2]: https://github.com/ipkevin/Blackjack-Builder
[jwbj-1]: https://johnwickblackjack.netlify.app/

#### [![GitHub stars][b2]][c2] boardgame.io-angular \[[code][c2] | [demo][d2]\]
&nbsp;&nbsp;
Unofficial Angular client for boardgame.io.

[b2]: https://img.shields.io/github/stars/turn-based/boardgame.io-angular?label=%E2%98%85&logo=github
[c2]: https://github.com/turn-based/boardgame.io-angular
[d2]: https://turn-based-209306.firebaseapp.com/

#### [![GitHub stars][b-bri]][c-bri] [Briscola][p-bri] \[[code][c-bri] | [demo][d-bri]\]
&nbsp;&nbsp;
Online 2-player variant of the Briscola card game.

[p-bri]: https://instant-briscola.herokuapp.com/
[c-bri]: https://github.com/aflorj/briscola
[d-bri]: https://instant-briscola.herokuapp.com/demo
[b-bri]: https://img.shields.io/github/stars/aflorj/briscola?label=%E2%98%85&logo=github

#### [![GitHub stars][b3]][c3]  [Camelot][p3] \[[code][c3]\]
&nbsp;&nbsp;
Play the Camelot board game online.

[b3]: https://img.shields.io/github/stars/blunket/camelot?label=%E2%98%85&logo=github
[c3]: https://github.com/blunket/camelot
[p3]: https://www.playcamelot.com


#### [![GitHub stars][b4]][c4] [Can't Stop!][p4] \[[code][c4]\]
&nbsp;&nbsp;
The classic "push your luck" dice game.

[b4]: https://img.shields.io/github/stars/simlmx/cantstop?label=%E2%98%85&logo=github
[c4]: https://github.com/simlmx/cantstop
[p4]: https://cantstop.fun


#### [![GitHub stars][b5]][c5] [Cardman Multiplayer][p5] \[[code][c5]\]
&nbsp;&nbsp;
A cross between Hangman and a card game.

[p5]: http://cardman-multiplayer.herokuapp.com
[c5]: https://github.com/VengelStudio/cardman-multiplayer
[b5]: https://img.shields.io/github/stars/VengelStudio/cardman-multiplayer?label=%E2%98%85&logo=github


#### [![GitHub stars][b-chessweeper]][c-chessweeper] [Chessweeper][p-chessweeper] \[[code][c-chessweeper]\]
&nbsp;&nbsp;
A mix between Chess and Minesweeper 

[p-chessweeper]: https://chessweeper.zirk.eu
[c-chessweeper]: https://github.com/Xwilarg/Chessweeper
[b-chessweeper]: https://img.shields.io/github/stars/xwilarg/chessweeper?label=%E2%98%85&logo=github

#### [![GitHub stars][b26]][c26] [Chinchon][p26] \[[code][c26]\]
&nbsp;&nbsp;
Multiplayer online card game similar to gin rummy. 

[p26]: https://chinchon-game.herokuapp.com/
[c26]: https://github.com/maxpaulus43/chinchon
[b26]: https://img.shields.io/github/stars/maxpaulus43/chinchon?label=%E2%98%85&logo=github

#### [![GitHub stars][b21]][c21] [Coup][p21] \[[code][c21]\]
&nbsp;&nbsp;
Online multiplayer version of Coup, a strategy board game.

[p21]: https://online-coup.herokuapp.com/
[c21]: https://github.com/vyang1222/online-coup
[b21]: https://img.shields.io/github/stars/vyang1222/online-coup?label=%E2%98%85&logo=github


#### [![GitHub stars][b6]][c6] [Elevation of Privilege][p6] \[[code][c6]\]
&nbsp;&nbsp;
An online multiplayer version of the threat modeling card game.

[b6]: https://img.shields.io/github/stars/dehydr8/elevation-of-privilege?label=%E2%98%85&logo=github
[p6]: https://elevation-of-privilege.herokuapp.com/
[c6]: https://github.com/dehydr8/elevation-of-privilege


#### [![GitHub stars][b7]][c7] [Fields of Arle simulator][p7] \[[code][c7]\]
&nbsp;&nbsp;
Open source simulator of Fields of Arle.

[b7]: https://img.shields.io/github/stars/philihp/fields-of-arle?label=%E2%98%85&logo=github
[p7]: https://arle.philihp.com
[c7]: https://github.com/philihp/fields-of-arle


#### [![GitHub stars][b-fd]][c-fd] [Forbidden Desert][p-fd] \[[code][c-fd]\]
&nbsp;&nbsp;
Clone of Forbidden Desert, a 2-5 player cooperative board game played locally.

[b-fd]: https://img.shields.io/github/stars/hwabis/forbidden-desert?label=%E2%98%85&logo=github
[p-fd]: https://hwabis.github.io/forbidden-desert/
[c-fd]: https://github.com/hwabis/forbidden-desert


#### [![GitHub stars][b8]][c8] Four in a row \[[code][c8] | [tutorial][t8]\]
&nbsp;&nbsp;
Four in a Row using boardgame.io.

[c8]: https://github.com/PJohannessen/four-in-a-row
[t8]: https://www.lonesomecrowdedweb.com/blog/four-in-a-row-boardgameio/
[b8]: https://img.shields.io/github/stars/PJohannessen/four-in-a-row?label=%E2%98%85&logo=github


#### [![GitHub stars][b9]][c9] [FreeBoardGames.org][p9] \[[code][c9]\]
&nbsp;&nbsp;
PWA framework for publishing board games.

[p9]: https://www.freeboardgames.org
[c9]: https://github.com/freeboardgames/FreeBoardGames.org
[b9]: https://img.shields.io/github/stars/freeboardgames/FreeBoardGames.org?label=%E2%98%85&logo=github


#### [![GitHub stars][b28]][c28] [Garden][p28] \[[code][c28]\]
&nbsp;&nbsp;
A single-player puzzle game.

[p28]: https://0x682.itch.io/garden
[c28]: https://github.com/steambap/garden
[b28]: https://img.shields.io/github/stars/steambap/garden?label=%E2%98%85&logo=github


#### [2048 Game][c27]
&nbsp;&nbsp;
The classic 2048 puzzle game. Implemented using React and Greensock.

[c27]: https://2048-online.io/


#### [![GitHub stars][b10]][c10] [Hex game][p10] \[[code][c10]\]
&nbsp;&nbsp;
Simple hexagonal board game.

[p10]: https://korla.github.io/hexgame/build/
[c10]: https://github.com/Korla/hexgame
[b10]: https://img.shields.io/github/stars/Korla/hexgame?label=%E2%98%85&logo=github

#### [![GitHub stars][b-lhog]][c-lhog] [Lewis' House of Games][p-lhog] \[[code][c-lhog]\]
&nbsp;&nbsp;
Lobby framework for boardgame.io games. Play Splendor or Powergrid clones here.

[p-lhog]: https://lhog.lewissilletto.com/
[c-lhog]: https://github.com/sillle14/lhog
[b-lhog]: https://img.shields.io/github/stars/sillle14/lhog?label=%E2%98%85&logo=github

#### [![GitHub stars][b11]][c11] [Matchimals.fun][p11] \[[code][c11]\]
&nbsp;&nbsp;
An animal matching puzzle card game.

[p11]: https://www.matchimals.fun/
[c11]: https://github.com/chrisheninger/matchimals.fun
[b11]: https://img.shields.io/github/stars/chrisheninger/matchimals.fun?label=%E2%98%85&logo=github


#### [![GitHub stars][b12]][c12] [Mosaic Multiplayer][p12] \[[code][c12]\]
&nbsp;&nbsp;
Azul board game clone you can play online with friends.

[p12]: https://playmosaic.online/
[c12]: https://github.com/maciejmatu/mosaic
[b12]: https://img.shields.io/github/stars/maciejmatu/mosaic?label=%E2%98%85&logo=github


#### [![GitHub stars][b13]][c13] [Multibuzzer][p13] \[[code][c13]\]
&nbsp;&nbsp;
Simple multiplayer buzzer system for trivia night or quiz bowl.

[p13]: https://multibuzz.app
[c13]: https://github.com/wsun/multibuzzer
[b13]: https://img.shields.io/github/stars/wsun/multibuzzer?label=%E2%98%85&logo=github


#### [![GitHub stars][b14]][c14] [Pong420's Boardgame][p14] \[[code][c14]\]
&nbsp;&nbsp;
A project for building board games with React and boardgame.io.

[p14]: http://play-boardgame.herokuapp.com
[c14]: https://github.com/Pong420/Boardgame
[b14]: https://img.shields.io/github/stars/Pong420/Boardgame?label=%E2%98%85&logo=github


#### [![GitHub stars][b25]][c25] [Santorini][p25] \[[code][c25]\]
&nbsp;&nbsp;
Multiplayer online boardgame with 3D board using three.js.

[p25]: https://santorini.onrender.com
[c25]: https://github.com/mbrinkl/santorini
[b25]: https://img.shields.io/github/stars/mbrinkl/santorini?label=%E2%98%85&logo=github


#### [![GitHub stars][bsixpieces]][csixpieces] [SixPieces][psixpieces] \[[code][csixpieces]\]
&nbsp;&nbsp;
A 3-D online version of the tile-based boardgame "Qwirkle" for two to four players.

[psixpieces]: https://zwo.uber.space/SixPieces/
[csixpieces]: https://github.com/fuenfundachtzig/SixPieces
[bsixpieces]: https://img.shields.io/github/stars/fuenfundachtzig/SixPieces?label=%E2%98%85&logo=github


#### [Splendor][p15]
&nbsp;&nbsp;
A minimal splendor game you can play with up to 4 players.

[p15]: http://bestboards.ir


#### [Steel Civilizations][p16]
&nbsp;&nbsp;
Turn-based mobile strategy game for Android with real-time online multiplayer ranking ladder system.

[p16]: https://play.google.com/store/apps/details?id=com.hydra.steelcivs


#### [![GitHub stars][b17]][c17] [Territories][p17] \[[code][c17]\]
&nbsp;&nbsp;
Simple board game Territories.

[p17]: https://lehasvv2009.github.io/territories/
[c17]: https://github.com/lehaSVV2009/territories
[b17]: https://img.shields.io/github/stars/lehaSVV2009/territories?label=%E2%98%85&logo=github


#### [![GitHub stars][b18]][c18] [Thinktank][p18] \[[code][c18]\]
&nbsp;&nbsp;
A 2-player strategy game inspired by Conundrum.

[p18]: https://thinktank.crespi.dev
[c18]: https://github.com/averycrespi/thinktank
[b18]: https://img.shields.io/github/stars/averycrespi/thinktank?label=%E2%98%85&logo=github

#### [![GitHub stars][b19]][c19] [Tiến Lên][p19] \[[code][c19]\]
&nbsp;&nbsp;
The 4-player Vietnamese game that uses a standard 52-card deck, in English, with online multiplayer.

[p19]: http://tienlen-en.herokuapp.com/
[c19]: https://github.com/nguyenank/tien-len
[b19]: https://img.shields.io/github/stars/nguyenank/tien-len?label=%E2%98%85&logo=github


#### [![GitHub stars][b20]][c20] [Udaipur][p20] \[[code][c20]\]
&nbsp;&nbsp;
Clone of Jaipur, a 2 Player Card game, with online multiplayer support.

[p20]: https://udaipur-game.herokuapp.com/
[c20]: https://github.com/skvrahul/UdaipurGame
[b20]:https://img.shields.io/github/stars/skvrahul/UdaipurGame?label=%E2%98%85&logo=github


#### [![GitHub stars][b24]][c24] [Unmuted: 2021][p24] \[[code][c24]\]
&nbsp;&nbsp;
A single-player deckbuilder game.

[p24]: https://shaoster.github.io/unmuted2021
[c24]: https://github.com/shaoster/unmuted2021
[b24]: https://img.shields.io/github/stars/shaoster/unmuted2021?label=%E2%98%85&logo=github


#### [![GitHub stars][b23]][c23] [Unstable Unicorns][p23] \[[code][c23]\]
&nbsp;&nbsp;
Online game variant of the popular card game Unstable Unicorns 🦄. Playable with your friends.

[p23]: https://unstable-unicorns-online.herokuapp.com/hello-world/6/0
[c23]: https://github.com/geniegeist/unstable-unicorns
[b23]: https://img.shields.io/github/stars/geniegeist/unstable-unicorns?label=%E2%98%85&logo=github


#### [![GitHub stars][b22]][c22] [Yatzy][p22] \[[code][c22] | [tutorial][t22]\]
&nbsp;&nbsp;
A 1-4 player dice game played locally.

[p22]: https://www.lonesomecrowdedweb.com/yatzy/
[c22]: https://github.com/pjohannessen/yatzy
[t22]: https://www.lonesomecrowdedweb.com/blog/yatzy-boardgameio/
[b22]: https://img.shields.io/github/stars/pjohannessen/yatzy?label=%E2%98%85&logo=github

#### [![GitHub stars][b-wd]][c-wd] [Wizard Duel][p-wd] \[[code][c-wd]\]
&nbsp;&nbsp;
A single-player battle card game featuring epic fantasy card art and sound effects.

[b-wd]: https://img.shields.io/github/stars/ruichen199801/wizard-duel?label=%E2%98%85&logo=github
[p-wd]: https://wizard-duel-ten.vercel.app/
[c-wd]: https://github.com/ruichen199801/wizard-duel


================================================
FILE: docs/documentation/phases.md
================================================
# Phases

Most games beyond very simple ones tend to have different
behaviors at various phases. A game might have a phase
at the beginning where players are drafting cards before
entering a playing phase, for example.

Each phase in [boardgame.io](https://boardgame.io/) defines a set
of game configuration options that are applied for the duration
of that phase. This includes the ability to define a different
set of moves, use a different turn order etc. Turns happen
inside phases.

### Card Game

Let us start with a contrived example of a game that has exactly
two moves:

- draw a card from the deck into your hand.
- play a card from your hand onto the deck.

```js
function DrawCard({ G, playerID }) {
  G.deck--;
  G.hand[playerID]++;
}

function PlayCard({ G, playerID }) {
  G.deck++;
  G.hand[playerID]--;
}

const game = {
  setup: ({ ctx }) => ({ deck: 6, hand: Array(ctx.numPlayers).fill(0) }),
  moves: { DrawCard, PlayCard },
  turn: { minMoves: 1, maxMoves: 1 },
};
```

?> Notice how we moved the moves out into standalone functions
instead of inlining them in the game object.

We'll ignore the rendering part of this game, but this is how it might look. Note that you can draw or play a card at any time, including taking a card when the deck is empty.

```react
<iframe class='plain' src='snippets/phases-1' height='350' scrolling='no' title='example' frameborder='no' allowtransparency='true' allowfullscreen='true'></iframe>
```

### Phases

Now let's say we want the game to work in two phases:

- a first phase where the players only draw cards (until the deck is empty).
- a second phase where the players only play cards.

In order to do this, we define two `phases`. Each phase can specify its own
list of moves, which come into effect during that phase:

```js
const game = {
  setup: ({ ctx }) => ({ deck: 6, hand: Array(ctx.numPlayers).fill(0) }),
  turn: { minMoves: 1, maxMoves: 1 },

  phases: {
    draw: {
      moves: { DrawCard },
    },

    play: {
      moves: { PlayCard },
    },
  },
};
```

!> A phase that doesn't specify any moves just uses moves from
the main `moves` section in the game. However, if it does,
then the `moves` section in the phase overrides the global
one.

The game doesn't begin in any of these phases. In order to begin
in the "draw" phase, we add a `start: true` to its config. Only
one phase can have `start: true`.

```js
phases: {
  draw: {
    moves: { DrawCard },
+   start: true,
  },

  play: {
    moves: { PlayCard },
  },
}
```

Let's also end the "draw" phase automatically once the deck is
empty.

```js
phases: {
  draw: {
    moves: { DrawCard },
+   endIf: ({ G }) => (G.deck <= 0),
+   next: 'play',
    start: true,
  },

  play: {
    moves: { PlayCard },
  },
}
```

`endIf` ends the phase that it is defined in when it returns
`true`. The game is returned to a state where no phase is
active. However, for this game, we want to move to
the "play" phase once the "draw" phase is done. We specify a
`next` option for this, which tells the framework to go to that
phase.

Watch our game in action (now with phases). Notice that you can only draw cards in the first
phase, and you can only play cards in the second phase.

```react
<iframe class='plain' src='snippets/phases-2' height='350' scrolling='no' title='example' frameborder='no' allowtransparency='true' allowfullscreen='true'></iframe>
```

### Setup and Cleanup hooks

You can also run code automatically at the beginning or end of a phase. These are specified just like normal moves in `onBegin` and `onEnd`.

```js
phases: {
  phaseA: {
    onBegin: ({ G, ctx }) => { ... },
    onEnd: ({ G, ctx }) => { ... },
  },
};
```

?> Hooks like `onBegin` and `onEnd` are run only on the server in
multiplayer games. Moves, on the other hand, run on both client
and server. They are run on the client in order to facilitate
a lag-free experience, and are run on the server to calculate the
authoritative game state.

### Moving between Phases

#### Using events

The two primary ways of moving between phases are by calling the
following events:

1. `endPhase`: This ends the current phase and returns the game
   to a state where no phase is active. If the phase specifies a
   `next` option, then the game will move into that phase instead.

2. `setPhase`: This ends the current phase and moves the game into
   the phase specified by the argument.


#### Using an `endIf` condition

You can also end a phase by returning a truthy value from its
`endIf` method:

```js
phases: {
  phaseA: {
    next: 'phaseB',
    endIf: ({ G, ctx }) => true,
  },
  phaseB: { ... },
},
```

!> Whenever a phase ends, the current player's turn is first ended automatically.


### Setting the next phase dynamically

Instead of setting a phase’s `next` option with a string, you can
provide a function that will return the next phase based on game
state at the end of the phase:

```js
phases: {
  phaseA: {
    next: ({ G }) => {
      return G.condition ? 'phaseC' : 'phaseB';
    },
  },
  phaseB: { ... },
  phaseC: { ... },
},
```


### Override Behavior

As observed above, a phase can specify its own `moves` section
which comes into effect when the phase is active. This `moves`
section completely replaces the global `moves` section
for the duration of the phase. The moves may have the
same name as their global equivalents, but they are not related
to them in any way.

A phase can similarly also override the `turn` section. You will
typically do this if you want to use a different
[Turn Order](turn-order.md) during the phase.


================================================
FILE: docs/documentation/plugins.md
================================================
# Plugins

The Plugin API allows you to create objects that expose
custom functionality to [boardgame.io](https://boardgame.io/).
You can create wrappers around moves, add API's to `ctx` etc.

### Creating a Plugin

A plugin is an object that contains the following fields.

```js
{
  // Required.
  name: 'plugin-name',

  // Initialize the plugin's data.
  // This is stored in a special area of the state object
  // and not exposed to the move functions.
  setup: ({ G, ctx, game }) => data object,

  // Create an object that becomes available in `ctx`
  // under `ctx['plugin-name']`.
  // This is called at the beginning of a move or event.
  // This object will be held in memory until flush (below)
  // is called.
  api: ({ G, ctx, game, data, playerID }) => api object,

  // Return an updated version of data that is persisted
  // in the game's state object.
  flush: ({ G, ctx, game, data, api }) => data object,

  // Function that accepts a move / trigger function
  // and returns another function that wraps it. This
  // wrapper can modify G before passing it down to
  // the wrapped function. It is a good practice to
  // undo the change at the end of the call. 
  // `fnType` gives the type of hook being wrapped
  // and will be one of the `GameMethod` values —
  // import { GameMethod } from 'boardgame.io/core' 
  fnWrap: (fn, fnType) => ({ G, ...rest }, ...args) => {
    G = preprocess(G);
    G = fn({ G, ...rest }, ...args);
    if (fnType === GameMethod.TURN_ON_END) {
      // only run when wrapping a turn’s onEnd function
    }
    G = postprocess(G);
    return G;
  },

  // Function that allows the plugin to indicate that it
  // should not be run on the client. If it returns true,
  // the client will discard the state update and wait
  // for the master instead.
  noClient: ({ G, ctx, game, data, api }) => boolean,

  // Function that allows the plugin to indicate that the
  // current action should be declared invalid and cancelled.
  // If `isInvalid` returns an error message, the whole update
  // will be abandoned and an error returned to the client.
  isInvalid: ({ G, ctx, game, data, api }) => false | string,

  // Function that can filter `data` to hide secret state
  // before sending it to a specific client.
  // `playerID` could also be null or undefined for spectators.
  playerView: ({ G, ctx, game, data, playerID }) => filtered data object,
}
```

### Adding Plugins to Games

The list of plugins is specified in the game spec.

```js
import { PluginA, PluginB } from 'boardgame.io/plugins';

const game = {
  name: 'my-game',

  plugins: [PluginA, PluginB],

  // ...
};
```

?> Plugins are applied one after the other in the order
that they are specified (from left to right).

### Configuring Plugins

Some plugins may need a user to provide some configuration. The recommended way to do that is to design the plugin as a factory function that takes configuration as its arguments and returns a plugin object.

```js
import { ConfigurablePlugin } from './plugins';

const game = {
  name: 'my-game',
  plugins: [
    ConfigurablePlugin(options),
  ],
}
```

?> See `PluginPlayer` below for an example of this in practice.

### Available Plugins

#### PluginPlayer

```js
import { PluginPlayer } from 'boardgame.io/plugins';

// define a function to initialize each player’s state
const playerSetup = (playerID) => ({ ... });

// filter data returned to each client to hide secret state (OPTIONAL)
const playerView = (players, playerID) => ({
  [playerID]: players[playerID],
});

const game = {
  plugins: [
    // pass your function to the player plugin
    PluginPlayer({
      setup: playerSetup,
      playerView: playerView,
    }),
  ],
};
```

`PluginPlayer` makes it easy to manage player state.
It creates an object `players` that
stores state for individual players.  This object is
stored in the plugin's private storage area:

```
players: {
  '0': { ... },
  '1': { ... },
  '2': { ... },
  ...
}
```

The initial values of these states are determined by the `setup` function in its options object, which creates the state for a particular `playerID`.

The record associated with the current player can be accessed
via `ctx.player.get()`. If this is a 2 player game,
then the opponent's record is available using `ctx.player.opponent.get()`. These fields can be modified using their corresponding
`set()` versions.

```js
ctx.player.get() // Get the current player's record.
ctx.player.set() // Update the current player's record.
ctx.player.opponent.get() // Get the opponent player's record.
ctx.player.opponent.set() // Update the opponent player's record.
```


================================================
FILE: docs/documentation/random.md
================================================
# Randomness

Many games allow moves whose outcome depends on shuffled cards or rolled dice.
Take e.g. the game [Yahtzee](https://en.wikipedia.org/wiki/Yahtzee).
A player rolls dice, chooses some, rolls another time, chooses some more, and does a final dice roll.
Depending on the face-up sides the player now must choose where they will score.

This poses interesting challenges regarding the implementation.

- **AI**. Randomness makes games interesting since you cannot predict the future, but it
  needs to be controlled in order for allowing games that can be replayed exactly (e.g. for AI purposes).

- **<abbr title="Pseudo-Random Number Generator">PRNG</abbr> State**.
  The game runs on both the server and client.
  All code and data on the client can be viewed and used to a player's advantage.
  If a client could predict the next random numbers that are to be generated, the future flow of a game stops being unpredictable.
  The library must not allow such a scenario. The RNG and its state must stay on the server.

- **Pure Functions**. The library is built using Redux. This is important for games since each move is a [reducer](https://redux.js.org/docs/basics/Reducers.html),
  and thus must be pure. Calling `Math.random()` and other functions that
  maintain external state would make the game logic impure and not idempotent.

### Using Randomness in Games

The object passed to moves and other game logic contains an object `random`,
which exposes a range of functions for generating randomness.

For example, the `random.D6` function is similar to rolling six-sided dice:

```js
{
  moves: {
    rollDie: ({ G, random }) => {
      G.dieRoll = random.D6(); // dieRoll = 1–6
    },

    rollThreeDice: ({ G, random }) => {
      G.diceRoll = random.D6(3); // diceRoll = [1–6, 1–6, 1–6]
    }
  },
}
```

You can see details for all the available random functions below.

### Seed

You can set the initial `seed` used for the random number generator
on your game object:

```js
const game = {
  seed: 42,
  // ...
};
```

?> `seed` can be either a string or a number.

## API Reference

### 1. Die

#### Arguments

1. `spotvalue` (_number_): The die dimension (_default: 6_).
2. `diceCount` (_number_): The number of dice to throw.

#### Returns

The die roll value (or an array of values if `diceCount` is greater than `1`).

#### Usage

```js
const game = {
  moves: {
    move({ random }) {
      const die = random.Die(6);      // die = 1-6
      const dice = random.Die(6, 3);  // dice = [1-6, 1-6, 1-6]
    },
  }
};
```

### 2. Number

Returns a random number between `0` and `1`.

#### Usage

```js
const game = {
  moves: {
    move({ random }) {
      const n = random.Number();
    },
  }
};
```

### 3. Shuffle

#### Arguments

1. `deck` (_array_): An array to shuffle.

#### Returns

The shuffled array.

#### Usage

```js
const game = {
  moves: {
    move({ G, random }) {
      G.deck = random.Shuffle(G.deck);
    },
  },
};
```

### 4. Wrappers

`D4`, `D6`, `D8`, `D10`, `D12` and `D20` are wrappers around
`Die(n)`.

#### Arguments

1. `diceCount` (_number_): The number of dice to throw.

#### Usage

```js
const game = {
  moves: {
    move({ random }) {
      const die = random.D6();
    },
  }
};
```


================================================
FILE: docs/documentation/secret-state.md
================================================
# Secret State

In some games you might need to hide information from
players or spectators. For example, you might not want to reveal the
hands of opponents in card games.

This is easily accomplished at the UI layer (by not
rendering secret information), but the framework also
provides support for not even sending such data to
the client.

In order to do this, use the `playerView` setting in
the game object. It accepts a function that receives an
object containing `G`, `ctx`, and `playerID`, and returns a version of `G`
that is stripped of any information that should be hidden
from that specific player.

```js
const game = {
  // `playerID` could also be null or undefined for spectators.
  playerView: ({ G, ctx, playerID }) => {
    return StripSecrets(G, playerID);
  },
  // ...
};
```

!> Make sure that you associate the game clients with individual
players (as discussed in the [Multiplayer](multiplayer.md) section).

### PlayerView.STRIP_SECRETS

The framework comes bundled with an implementation of `playerView`
that does the following:

- It removes a key named `secret` from `G`.
- If `G` contains a `players` object, it removes all keys except
  for the one that matches `playerID`.

```js
G: {
  secret: { ... },

  players: {
    '0': { ... },
    '1': { ... },
    '2': { ... },
  }
}
```

becomes the following for player `1`:

```js
G: {
  players: {
    '1': { ... },
  }
}
```

Usage:

```js
import { PlayerView } from 'boardgame.io/core';

const game = {
  // ...
  playerView: PlayerView.STRIP_SECRETS,
};
```

### Disabling moves that manipulate secret state on the client

Moves that manipulate secret state often cannot run on the client because
the client doesn't have all the necessary data to process such moves.
These can be marked as server-only by setting `client: false` on move:

```js
moves: {
  moveThatUsesSecret: {
    move: ({ G, random }) => {
      G.secret.value = random.Number();
    },

    client: false,
  }
}
```


================================================
FILE: docs/documentation/sidebar.md
================================================
- **Getting Started**
  - [Concepts](/)
  - [Tutorial](tutorial.md)
- **Guides**
  - [Multiplayer](multiplayer.md)
  - [Turn Order](turn-order.md)
  - [Phases](phases.md)
  - [Stages](stages.md)
  - [Events](events.md)
  - [Undo / Redo](undo.md)
  - [Randomness](random.md)
  - [Secret State](secret-state.md)
  - [Immutability](immutability.md)
  - [Plugins](plugins.md)
  - [Debugging](debugging.md)
  - [Testing](testing.md)
  - [Deployment](deployment.md)
  - [Storage](storage.md)
  - [Chat](chat.md)
  - [TypeScript](typescript.md)
- **Reference**
  - [Game](api/Game.md)
  - [Client](api/Client.md)
  - [Server](api/Server.md)
  - [Lobby](api/Lobby.md)
- **More**
  - [Changelog](/CHANGELOG.md)
  - [Projects](/notable_projects.md)


================================================
FILE: docs/documentation/snippets/example-1/index.html
================================================
<!DOCTYPE html><html><head><style>body{padding:20px}.msg{position:absolute;bottom:0;left:20px;color:#aaa;font-size:12px;margin-bottom:20px}</style></head><body> <div class="msg">interactive (not an image)</div> <div id="app"></div> <script type="text/javascript" src="/documentation/snippets/example-1.c952ec6d.js"></script> </body></html>

================================================
FILE: docs/documentation/snippets/example-1.c952ec6d.js
================================================
parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;c<t.length;c++)try{f(t[c])}catch(e){i||(i=e)}if(t.length){var l=f(t[t.length-1]);"object"==typeof exports&&"undefined"!=typeof module?module.exports=l:"function"==typeof define&&define.amd?define(function(){return l}):n&&(this[n]=l)}if(parcelRequire=f,i)throw i;return f}({"J4Nk":[function(require,module,exports) {
"use strict";var r=Object.getOwnPropertySymbols,t=Object.prototype.hasOwnProperty,e=Object.prototype.propertyIsEnumerable;function n(r){if(null==r)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(r)}function o(){try{if(!Object.assign)return!1;var r=new String("abc");if(r[5]="de","5"===Object.getOwnPropertyNames(r)[0])return!1;for(var t={},e=0;e<10;e++)t["_"+String.fromCharCode(e)]=e;if("0123456789"!==Object.getOwnPropertyNames(t).map(function(r){return t[r]}).join(""))return!1;var n={};return"abcdefghijklmnopqrst".split("").forEach(function(r){n[r]=r}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},n)).join("")}catch(o){return!1}}module.exports=o()?Object.assign:function(o,c){for(var a,i,s=n(o),f=1;f<arguments.length;f++){for(var u in a=Object(arguments[f]))t.call(a,u)&&(s[u]=a[u]);if(r){i=r(a);for(var b=0;b<i.length;b++)e.call(a,i[b])&&(s[i[b]]=a[i[b]])}}return s};
},{}],"awqi":[function(require,module,exports) {
"use strict";var e=require("object-assign"),r="function"==typeof Symbol&&Symbol.for,t=r?Symbol.for("react.element"):60103,n=r?Symbol.for("react.portal"):60106,o=r?Symbol.for("react.fragment"):60107,u=r?Symbol.for("react.strict_mode"):60108,f=r?Symbol.for("react.profiler"):60114,c=r?Symbol.for("react.provider"):60109,l=r?Symbol.for("react.context"):60110,i=r?Symbol.for("react.forward_ref"):60112,s=r?Symbol.for("react.suspense"):60113,a=r?Symbol.for("react.memo"):60115,p=r?Symbol.for("react.lazy"):60116,y="function"==typeof Symbol&&Symbol.iterator;function d(e){for(var r="https://reactjs.org/docs/error-decoder.html?invariant="+e,t=1;t<arguments.length;t++)r+="&args[]="+encodeURIComponent(arguments[t]);return"Minified React error #"+e+"; visit "+r+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var v={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h={};function m(e,r,t){this.props=e,this.context=r,this.refs=h,this.updater=t||v}function x(){}function b(e,r,t){this.props=e,this.context=r,this.refs=h,this.updater=t||v}m.prototype.isReactComponent={},m.prototype.setState=function(e,r){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(d(85));this.updater.enqueueSetState(this,e,r,"setState")},m.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},x.prototype=m.prototype;var S=b.prototype=new x;S.constructor=b,e(S,m.prototype),S.isPureReactComponent=!0;var _={current:null},k=Object.prototype.hasOwnProperty,$={key:!0,ref:!0,__self:!0,__source:!0};function g(e,r,n){var o,u={},f=null,c=null;if(null!=r)for(o in void 0!==r.ref&&(c=r.ref),void 0!==r.key&&(f=""+r.key),r)k.call(r,o)&&!$.hasOwnProperty(o)&&(u[o]=r[o]);var l=arguments.length-2;if(1===l)u.children=n;else if(1<l){for(var i=Array(l),s=0;s<l;s++)i[s]=arguments[s+2];u.children=i}if(e&&e.defaultProps)for(o in l=e.defaultProps)void 0===u[o]&&(u[o]=l[o]);return{$$typeof:t,type:e,key:f,ref:c,props:u,_owner:_.current}}function w(e,r){return{$$typeof:t,type:e.type,key:r,ref:e.ref,props:e.props,_owner:e._owner}}function C(e){return"object"==typeof e&&null!==e&&e.$$typeof===t}function E(e){var r={"=":"=0",":":"=2"};return"$"+(""+e).replace(/[=:]/g,function(e){return r[e]})}var R=/\/+/g,P=[];function j(e,r,t,n){if(P.length){var o=P.pop();return o.result=e,o.keyPrefix=r,o.func=t,o.context=n,o.count=0,o}return{result:e,keyPrefix:r,func:t,context:n,count:0}}function O(e){e.result=null,e.keyPrefix=null,e.func=null,e.context=null,e.count=0,10>P.length&&P.push(e)}function A(e,r,o,u){var f=typeof e;"undefined"!==f&&"boolean"!==f||(e=null);var c=!1;if(null===e)c=!0;else switch(f){case"string":case"number":c=!0;break;case"object":switch(e.$$typeof){case t:case n:c=!0}}if(c)return o(u,e,""===r?"."+U(e,0):r),1;if(c=0,r=""===r?".":r+":",Array.isArray(e))for(var l=0;l<e.length;l++){var i=r+U(f=e[l],l);c+=A(f,i,o,u)}else if(null===e||"object"!=typeof e?i=null:i="function"==typeof(i=y&&e[y]||e["@@iterator"])?i:null,"function"==typeof i)for(e=i.call(e),l=0;!(f=e.next()).done;)c+=A(f=f.value,i=r+U(f,l++),o,u);else if("object"===f)throw o=""+e,Error(d(31,"[object Object]"===o?"object with keys {"+Object.keys(e).join(", ")+"}":o,""));return c}function I(e,r,t){return null==e?0:A(e,"",r,t)}function U(e,r){return"object"==typeof e&&null!==e&&null!=e.key?E(e.key):r.toString(36)}function q(e,r){e.func.call(e.context,r,e.count++)}function F(e,r,t){var n=e.result,o=e.keyPrefix;e=e.func.call(e.context,r,e.count++),Array.isArray(e)?L(e,n,t,function(e){return e}):null!=e&&(C(e)&&(e=w(e,o+(!e.key||r&&r.key===e.key?"":(""+e.key).replace(R,"$&/")+"/")+t)),n.push(e))}function L(e,r,t,n,o){var u="";null!=t&&(u=(""+t).replace(R,"$&/")+"/"),I(e,F,r=j(r,u,n,o)),O(r)}var M={current:null};function D(){var e=M.current;if(null===e)throw Error(d(321));return e}var V={ReactCurrentDispatcher:M,ReactCurrentBatchConfig:{suspense:null},ReactCurrentOwner:_,IsSomeRendererActing:{current:!1},assign:e};exports.Children={map:function(e,r,t){if(null==e)return e;var n=[];return L(e,n,null,r,t),n},forEach:function(e,r,t){if(null==e)return e;I(e,q,r=j(null,null,r,t)),O(r)},count:function(e){return I(e,function(){return null},null)},toArray:function(e){var r=[];return L(e,r,null,function(e){return e}),r},only:function(e){if(!C(e))throw Error(d(143));return e}},exports.Component=m,exports.Fragment=o,exports.Profiler=f,exports.PureComponent=b,exports.StrictMode=u,exports.Suspense=s,exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=V,exports.cloneElement=function(r,n,o){if(null==r)throw Error(d(267,r));var u=e({},r.props),f=r.key,c=r.ref,l=r._owner;if(null!=n){if(void 0!==n.ref&&(c=n.ref,l=_.current),void 0!==n.key&&(f=""+n.key),r.type&&r.type.defaultProps)var i=r.type.defaultProps;for(s in n)k.call(n,s)&&!$.hasOwnProperty(s)&&(u[s]=void 0===n[s]&&void 0!==i?i[s]:n[s])}var s=arguments.length-2;if(1===s)u.children=o;else if(1<s){i=Array(s);for(var a=0;a<s;a++)i[a]=arguments[a+2];u.children=i}return{$$typeof:t,type:r.type,key:f,ref:c,props:u,_owner:l}},exports.createContext=function(e,r){return void 0===r&&(r=null),(e={$$typeof:l,_calculateChangedBits:r,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:c,_context:e},e.Consumer=e},exports.createElement=g,exports.createFactory=function(e){var r=g.bind(null,e);return r.type=e,r},exports.createRef=function(){return{current:null}},exports.forwardRef=function(e){return{$$typeof:i,render:e}},exports.isValidElement=C,exports.lazy=function(e){return{$$typeof:p,_ctor:e,_status:-1,_result:null}},exports.memo=function(e,r){return{$$typeof:a,type:e,compare:void 0===r?null:r}},exports.useCallback=function(e,r){return D().useCallback(e,r)},exports.useContext=function(e,r){return D().useContext(e,r)},exports.useDebugValue=function(){},exports.useEffect=function(e,r){return D().useEffect(e,r)},exports.useImperativeHandle=function(e,r,t){return D().useImperativeHandle(e,r,t)},exports.useLayoutEffect=function(e,r){return D().useLayoutEffect(e,r)},exports.useMemo=function(e,r){return D().useMemo(e,r)},exports.useReducer=function(e,r,t){return D().useReducer(e,r,t)},exports.useRef=function(e){return D().useRef(e)},exports.useState=function(e){return D().useState(e)},exports.version="16.14.0";
},{"object-assign":"J4Nk"}],"n8MK":[function(require,module,exports) {
"use strict";module.exports=require("./cjs/react.production.min.js");
},{"./cjs/react.production.min.js":"awqi"}],"IvPb":[function(require,module,exports) {
"use strict";var e,n,t,r,o;if("undefined"==typeof window||"function"!=typeof MessageChannel){var a=null,l=null,i=function(){if(null!==a)try{var e=exports.unstable_now();a(!0,e),a=null}catch(n){throw setTimeout(i,0),n}},u=Date.now();exports.unstable_now=function(){return Date.now()-u},e=function(n){null!==a?setTimeout(e,0,n):(a=n,setTimeout(i,0))},n=function(e,n){l=setTimeout(e,n)},t=function(){clearTimeout(l)},r=function(){return!1},o=exports.unstable_forceFrameRate=function(){}}else{var s=window.performance,c=window.Date,f=window.setTimeout,p=window.clearTimeout;if("undefined
Download .txt
gitextract_hy_6v4bz/

├── .devcontainer/
│   ├── Dockerfile
│   └── devcontainer.json
├── .empty_module.js
├── .eslintignore
├── .eslintrc
├── .github/
│   ├── FUNDING.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── npm-publish.yml
│       └── test.yml
├── .gitignore
├── .lintstagedrc
├── .prettierignore
├── .prettierrc
├── AUTHORS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── babel.config.js
├── benchmark/
│   └── index.js
├── docs/
│   ├── CNAME
│   ├── documentation/
│   │   ├── .nojekyll
│   │   ├── CHANGELOG.md
│   │   ├── api/
│   │   │   ├── Client.md
│   │   │   ├── Game.md
│   │   │   ├── Lobby.md
│   │   │   └── Server.md
│   │   ├── chat.md
│   │   ├── concepts.md
│   │   ├── debugging.md
│   │   ├── deployment.md
│   │   ├── events.md
│   │   ├── immutability.md
│   │   ├── index.html
│   │   ├── multiplayer.md
│   │   ├── notable_projects.md
│   │   ├── phases.md
│   │   ├── plugins.md
│   │   ├── random.md
│   │   ├── secret-state.md
│   │   ├── sidebar.md
│   │   ├── snippets/
│   │   │   ├── example-1/
│   │   │   │   └── index.html
│   │   │   ├── example-1.c952ec6d.js
│   │   │   ├── example-2/
│   │   │   │   └── index.html
│   │   │   ├── example-2.e4675089.js
│   │   │   ├── example-3/
│   │   │   │   └── index.html
│   │   │   ├── example-3.1fa4f5db.js
│   │   │   ├── multiplayer/
│   │   │   │   └── index.html
│   │   │   ├── multiplayer.54b541fd.js
│   │   │   ├── phases-1/
│   │   │   │   └── index.html
│   │   │   ├── phases-1.0d4500d6.js
│   │   │   ├── phases-1.490dcd4c.css
│   │   │   ├── phases-2/
│   │   │   │   └── index.html
│   │   │   ├── phases-2.a59f38ac.js
│   │   │   ├── phases-2.fa21cb61.css
│   │   │   ├── stages-1/
│   │   │   │   └── index.html
│   │   │   ├── stages-1.1524ef02.js
│   │   │   └── stages-1.bcf7ab84.css
│   │   ├── stages.md
│   │   ├── storage.md
│   │   ├── testing.md
│   │   ├── theme.css
│   │   ├── turn-order.md
│   │   ├── tutorial.md
│   │   ├── typescript.md
│   │   └── undo.md
│   ├── index.css
│   └── index.html
├── examples/
│   ├── react-native/
│   │   ├── .gitignore
│   │   ├── .watchmanconfig
│   │   ├── App.js
│   │   ├── README.md
│   │   ├── app.json
│   │   ├── board.js
│   │   ├── game.js
│   │   ├── package.json
│   │   └── rn-cli.config.js
│   ├── react-web/
│   │   ├── .gitignore
│   │   ├── package.json
│   │   ├── server.js
│   │   └── src/
│   │       ├── app.css
│   │       ├── app.js
│   │       ├── app.test.js
│   │       ├── chess/
│   │       │   ├── board.js
│   │       │   ├── chat.js
│   │       │   ├── checkerboard.js
│   │       │   ├── checkerboard.test.js
│   │       │   ├── game.js
│   │       │   ├── grid.js
│   │       │   ├── index.js
│   │       │   ├── multiplayer.js
│   │       │   ├── pieces/
│   │       │   │   ├── CREDITS
│   │       │   │   ├── bishop.js
│   │       │   │   ├── king.js
│   │       │   │   ├── knight.js
│   │       │   │   ├── pawn.js
│   │       │   │   ├── queen.js
│   │       │   │   └── rook.js
│   │       │   ├── singleplayer.js
│   │       │   └── token.js
│   │       ├── index.html
│   │       ├── index.js
│   │       ├── li-navlink.js
│   │       ├── lobby/
│   │       │   ├── index.js
│   │       │   ├── lobby.css
│   │       │   ├── lobby.js
│   │       │   └── routes.js
│   │       ├── random/
│   │       │   ├── board.js
│   │       │   ├── game.js
│   │       │   └── index.js
│   │       ├── redacted-move/
│   │       │   ├── board.css
│   │       │   ├── board.js
│   │       │   ├── game.js
│   │       │   ├── index.js
│   │       │   └── multiview.js
│   │       ├── routes.js
│   │       ├── secret-state/
│   │       │   ├── board.css
│   │       │   ├── board.js
│   │       │   ├── game.js
│   │       │   ├── index.js
│   │       │   └── multiview.js
│   │       ├── simulator/
│   │       │   ├── example-all-once.js
│   │       │   ├── example-all.js
│   │       │   ├── example-others-once.js
│   │       │   ├── example-others.js
│   │       │   ├── index.js
│   │       │   ├── simulator.css
│   │       │   └── simulator.js
│   │       ├── threejs/
│   │       │   ├── index.js
│   │       │   └── main.css
│   │       ├── tic-tac-toe/
│   │       │   ├── advanced-ai.js
│   │       │   ├── authenticated.js
│   │       │   ├── board.css
│   │       │   ├── board.js
│   │       │   ├── bots.js
│   │       │   ├── game.js
│   │       │   ├── index.js
│   │       │   ├── multiplayer.js
│   │       │   ├── singleplayer.js
│   │       │   └── spectator.js
│   │       └── undo/
│   │           ├── board.js
│   │           ├── game.js
│   │           └── index.js
│   └── snippets/
│       ├── .gitignore
│       ├── README.md
│       ├── install.sh
│       ├── package.json
│       └── src/
│           ├── example-1/
│           │   ├── index.html
│           │   └── index.js
│           ├── example-2/
│           │   ├── index.html
│           │   └── index.js
│           ├── example-3/
│           │   ├── index.html
│           │   └── index.js
│           ├── multiplayer/
│           │   ├── index.html
│           │   └── index.js
│           ├── phases-1/
│           │   ├── App.svelte
│           │   ├── Player.svelte
│           │   ├── game.js
│           │   ├── index.html
│           │   └── index.js
│           ├── phases-2/
│           │   ├── App.svelte
│           │   ├── Player.svelte
│           │   ├── game.js
│           │   ├── index.html
│           │   └── index.js
│           └── stages-1/
│               ├── App.svelte
│               ├── Player.svelte
│               ├── game.js
│               ├── index.html
│               └── index.js
├── integration/
│   ├── .gitignore
│   ├── README.md
│   ├── package.json
│   ├── public/
│   │   └── index.html
│   └── src/
│       ├── App.css
│       ├── App.js
│       ├── App.test.js
│       ├── board.css
│       ├── board.js
│       ├── game.js
│       ├── index.css
│       └── index.js
├── package.json
├── packages/
│   ├── ai.ts
│   ├── client.ts
│   ├── core.ts
│   ├── debug.ts
│   ├── internal.ts
│   ├── main.js
│   ├── master.ts
│   ├── multiplayer.ts
│   ├── plugins.ts
│   ├── react-native.ts
│   ├── react.ts
│   ├── server.ts
│   └── testing.ts
├── python/
│   ├── .gitignore
│   ├── boardgameio.py
│   ├── examples/
│   │   └── tic-tac-toe/
│   │       └── tictactoebot.py
│   └── test_boardgameio.py
├── roadmap.md
├── rollup.config.js
├── scripts/
│   ├── changelog.js
│   ├── clean.js
│   ├── dev-client.js
│   ├── install-examples.js
│   ├── integration.js
│   └── proxy-dirs.js
├── src/
│   ├── ai/
│   │   ├── ai.test.ts
│   │   ├── ai.ts
│   │   ├── bot.ts
│   │   ├── mcts-bot.ts
│   │   └── random-bot.ts
│   ├── client/
│   │   ├── client.test.ts
│   │   ├── client.ts
│   │   ├── debug/
│   │   │   ├── Debug.svelte
│   │   │   ├── Menu.svelte
│   │   │   ├── ai/
│   │   │   │   ├── AI.svelte
│   │   │   │   └── Options.svelte
│   │   │   ├── info/
│   │   │   │   ├── Info.svelte
│   │   │   │   └── Item.svelte
│   │   │   ├── log/
│   │   │   │   ├── Log.svelte
│   │   │   │   ├── LogEvent.svelte
│   │   │   │   ├── LogMetadata.svelte
│   │   │   │   ├── PhaseMarker.svelte
│   │   │   │   └── TurnMarker.svelte
│   │   │   ├── main/
│   │   │   │   ├── ClientSwitcher.svelte
│   │   │   │   ├── Controls.svelte
│   │   │   │   ├── Hotkey.svelte
│   │   │   │   ├── InteractiveFunction.svelte
│   │   │   │   ├── Main.svelte
│   │   │   │   ├── Move.svelte
│   │   │   │   └── PlayerInfo.svelte
│   │   │   ├── mcts/
│   │   │   │   ├── Action.svelte
│   │   │   │   ├── MCTS.svelte
│   │   │   │   └── Table.svelte
│   │   │   ├── tests/
│   │   │   │   ├── JSONTree.mock.svelte
│   │   │   │   └── debug.test.ts
│   │   │   └── utils/
│   │   │       ├── shortcuts.js
│   │   │       └── shortcuts.test.js
│   │   ├── manager.ts
│   │   ├── react-native.js
│   │   ├── react-native.test.js
│   │   ├── react.ssr.test.tsx
│   │   ├── react.test.tsx
│   │   ├── react.tsx
│   │   └── transport/
│   │       ├── dummy.ts
│   │       ├── local.test.ts
│   │       ├── local.ts
│   │       ├── socketio.test.ts
│   │       ├── socketio.ts
│   │       ├── transport.test.ts
│   │       └── transport.ts
│   ├── core/
│   │   ├── action-creators.ts
│   │   ├── action-types.ts
│   │   ├── backwards-compatibility.ts
│   │   ├── constants.ts
│   │   ├── errors.ts
│   │   ├── flow.test.ts
│   │   ├── flow.ts
│   │   ├── game-methods.ts
│   │   ├── game.test.ts
│   │   ├── game.ts
│   │   ├── initialize.ts
│   │   ├── logger.test.js
│   │   ├── logger.ts
│   │   ├── player-view.test.ts
│   │   ├── player-view.ts
│   │   ├── reducer.test.ts
│   │   ├── reducer.ts
│   │   ├── turn-order.test.ts
│   │   └── turn-order.ts
│   ├── lobby/
│   │   ├── client.test.ts
│   │   ├── client.ts
│   │   ├── connection.test.ts
│   │   ├── connection.ts
│   │   ├── create-match-form.tsx
│   │   ├── login-form.tsx
│   │   ├── match-instance.tsx
│   │   ├── react.ssr.test.tsx
│   │   ├── react.test.tsx
│   │   └── react.tsx
│   ├── master/
│   │   ├── filter-player-view.test.ts
│   │   ├── filter-player-view.ts
│   │   ├── master.test.ts
│   │   └── master.ts
│   ├── plugins/
│   │   ├── events/
│   │   │   ├── events.test.ts
│   │   │   └── events.ts
│   │   ├── main.test.ts
│   │   ├── main.ts
│   │   ├── plugin-events.ts
│   │   ├── plugin-immer.test.ts
│   │   ├── plugin-immer.ts
│   │   ├── plugin-log.test.ts
│   │   ├── plugin-log.ts
│   │   ├── plugin-player.test.ts
│   │   ├── plugin-player.ts
│   │   ├── plugin-random.ts
│   │   ├── plugin-serializable.test.ts
│   │   ├── plugin-serializable.ts
│   │   └── random/
│   │       ├── random.alea.ts
│   │       ├── random.test.ts
│   │       └── random.ts
│   ├── server/
│   │   ├── api.test.ts
│   │   ├── api.ts
│   │   ├── auth.test.ts
│   │   ├── auth.ts
│   │   ├── cors.test.ts
│   │   ├── cors.ts
│   │   ├── db/
│   │   │   ├── base.ts
│   │   │   ├── flatfile.test.ts
│   │   │   ├── flatfile.ts
│   │   │   ├── index.test.ts
│   │   │   ├── index.ts
│   │   │   ├── inmemory.test.ts
│   │   │   ├── inmemory.ts
│   │   │   ├── localstorage.test.ts
│   │   │   └── localstorage.ts
│   │   ├── index.test.ts
│   │   ├── index.ts
│   │   ├── transport/
│   │   │   ├── pubsub/
│   │   │   │   ├── generic-pub-sub.ts
│   │   │   │   ├── in-memory-pub-sub.test.ts
│   │   │   │   └── in-memory-pub-sub.ts
│   │   │   ├── socketio-simultaneous.test.ts
│   │   │   ├── socketio.test.ts
│   │   │   └── socketio.ts
│   │   └── util.ts
│   ├── testing/
│   │   ├── mock-random.test.ts
│   │   └── mock-random.ts
│   └── types.ts
├── subpackages.js
└── tsconfig.json
Download .txt
Showing preview only (3,479K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (9131 symbols across 114 files)

FILE: docs/documentation/snippets/example-1.c952ec6d.js
  function f (line 1) | function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequi...
  function n (line 2) | function n(r){if(null==r)throw new TypeError("Object.assign cannot be ca...
    method constructor (line 20) | constructor(t){this.state=t||{seed:"0"},this.used=!1}
    method seed (line 20) | static seed(){return Date.now().toString(36).slice(-10)}
    method isUsed (line 20) | isUsed(){return this.used}
    method getState (line 20) | getState(){return this.state}
    method _random (line 20) | _random(){this.used=!0;const t=this.state,s=r(t.prngstate?"":t.seed,t....
    method api (line 20) | api(){const t=this._random.bind(this),s={D4:4,D6:6,D8:8,D10:10,D12:12,...
    method play (line 47) | play({G:t,ctx:e},r){const a=this.enumerate(t,e,r);return Promise.resol...
    method constructor (line 63) | constructor({server:e=""}={}){this.server=e.replace(/\/$/,"")}
    method request (line 63) | async request(e,t){const s=await fetch(this.server+e,t);if(!s.ok){let ...
    method post (line 63) | async post(e,t){let s={method:"post",body:JSON.stringify(t.body),heade...
    method listGames (line 63) | async listGames(e){return this.request("/games",e)}
    method listMatches (line 63) | async listMatches(e,s,r){t(e);let a="";if(s){const e=[],{isGameover:t,...
    method getMatch (line 63) | async getMatch(e,r,a){return t(e),s(r),this.request(`/games/${e}/${r}`...
    method createMatch (line 63) | async createMatch(e,s,a){return t(e),r(s,{numPlayers:"number"}),this.p...
    method joinMatch (line 63) | async joinMatch(e,a,n,i){return t(e),s(a),r(n,{playerID:["string","und...
    method leaveMatch (line 63) | async leaveMatch(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentials...
    method updatePlayer (line 63) | async updatePlayer(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentia...
    method playAgain (line 63) | async playAgain(e,a,n,i){return t(e),s(a),r(n,{playerID:"string",crede...
    method type (line 80) | type(){return e.SYNC}
    method connect (line 80) | connect(){}
    method createMatch (line 80) | createMatch(e,t){if(this.createGame)return console.warn("The database ...
    method listMatches (line 80) | listMatches(e){if(this.listGames)return console.warn("The database con...
    method constructor (line 151) | constructor(t,e={}){super(),t&&"object"==typeof t&&(e=t,t=null),t?(t=i...
    method createTransport (line 151) | createTransport(e){s('creating transport "%s"',e);const i=a(this.opts....
    method open (line 151) | open(){let t;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1...
    method setTransport (line 151) | setTransport(t){s("setting transport %s",t.name),this.transport&&(s("c...
    method probe (line 151) | probe(t){s('probing transport "%s"',t);let e=this.createTransport(t,{p...
    method onOpen (line 151) | onOpen(){if(s("socket open"),this.readyState="open",n.priorWebsocketSu...
    method onPacket (line 151) | onPacket(t){if("opening"===this.readyState||"open"===this.readyState||...
    method onHandshake (line 151) | onHandshake(t){this.emit("handshake",t),this.id=t.sid,this.transport.q...
    method resetPingTimeout (line 151) | resetPingTimeout(){clearTimeout(this.pingTimeoutTimer),this.pingTimeou...
    method onDrain (line 151) | onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBuffe...
    method flush (line 151) | flush(){"closed"!==this.readyState&&this.transport.writable&&!this.upg...
    method write (line 151) | write(t,e,s){return this.sendPacket("message",t,e,s),this}
    method send (line 151) | send(t,e,s){return this.sendPacket("message",t,e,s),this}
    method sendPacket (line 151) | sendPacket(t,e,s,r){if("function"==typeof e&&(r=e,e=void 0),"function"...
    method close (line 151) | close(){const t=()=>{this.onClose("forced close"),s("socket closing - ...
    method onError (line 151) | onError(t){s("socket error %j",t),n.priorWebsocketSuccess=!1,this.emit...
    method onClose (line 151) | onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"c...
    method filterUpgrades (line 151) | filterUpgrades(t){const e=[];let s=0;const r=t.length;for(;s<r;s++)~th...
  function o (line 2) | function o(){try{if(!Object.assign)return!1;var r=new String("abc");if(r...
    method constructor (line 82) | constructor(t,a,r,s){this.game=(0,e.P)(t),this.storageAPI=a,this.trans...
    method subscribe (line 82) | subscribe(t){this.subscribeCallback=t}
    method onUpdate (line 82) | async onUpdate(s,o,n,c){if(!s||!s.payload)return{error:"missing action...
    method onSync (line 82) | async onSync(t,a,e,i=2){const o=t,n={state:!0,metadata:!0,log:!0,initi...
    method onConnectionChange (line 82) | async onConnectionChange(t,e,i,o){const n=t;if(null==e)return;let c;if...
    method onChatMessage (line 82) | async onChatMessage(t,a,e){const r=t;if(this.auth){const{metadata:t}=a...
    method constructor (line 132) | constructor(e){super(e),this.query=this.query||{},s||(s=t.___eio=t.___...
    method supportsBinary (line 132) | get supportsBinary(){return!1}
    method doClose (line 132) | doClose(){this.script&&(this.script.onerror=(()=>{}),this.script.paren...
    method doPoll (line 132) | doPoll(){const e=document.createElement("script");this.script&&(this.s...
    method doWrite (line 132) | doWrite(e,t){let s;if(!this.form){const e=document.createElement("form...
    method constructor (line 164) | constructor(){super()}
    method add (line 164) | add(t){let e;if("string"==typeof t)(e=this.decodeString(t)).type===n.B...
    method decodeString (line 164) | decodeString(t){let e=0;const r={type:Number(t.charAt(0))};if(void 0==...
    method isPayloadValid (line 164) | static isPayloadValid(t,e){switch(t){case n.CONNECT:return"object"==ty...
    method destroy (line 164) | destroy(){this.reconstructor&&this.reconstructor.finishedReconstructio...
    method constructor (line 178) | constructor(t="bgio"){super();const e=e=>new c(`${t}_${e}`);this.state...
  function d (line 4) | function d(e){for(var r="https://reactjs.org/docs/error-decoder.html?inv...
    method constructor (line 180) | constructor(e){super(e),this.state={selectedGame:0,numPlayers:2},this....
    method render (line 180) | render(){return s.default.createElement("div",null,s.default.createEle...
  function m (line 4) | function m(e,r,t){this.props=e,this.context=r,this.refs=h,this.updater=t...
    method constructor (line 61) | constructor({game:e,debug:n,numPlayers:h,multiplayer:l,matchID:g,playe...
    method receiveMatchData (line 61) | receiveMatchData(t){this.matchData=t,this.notifySubscribers()}
    method receiveChatMessage (line 61) | receiveChatMessage(t){this.chatMessages=[...this.chatMessages,t],this....
    method receiveTransportData (line 61) | receiveTransportData(t){const[e]=t.args;if(e===this.matchID)switch(t.t...
    method notifySubscribers (line 61) | notifySubscribers(){Object.values(this.subscribers).forEach(t=>t(this....
    method overrideGameState (line 61) | overrideGameState(t){this.gameStateOverride=t,this.notifySubscribers()}
    method start (line 61) | start(){this.transport.connect(),this._running=!0,this.manager.registe...
    method stop (line 61) | stop(){this.transport.disconnect(),this._running=!1,this.manager.unreg...
    method subscribe (line 61) | subscribe(t){const e=Object.keys(this.subscribers).length;return this....
    method getInitialState (line 61) | getInitialState(){return this.initialState}
    method getState (line 61) | getState(){let t=this.store.getState();if(null!==this.gameStateOverrid...
    method createDispatchers (line 61) | createDispatchers(){this.moves=b(this.game.moveNames,this.store,this.p...
    method updatePlayerID (line 61) | updatePlayerID(t){this.playerID=t,this.createDispatchers(),this.transp...
    method updateMatchID (line 61) | updateMatchID(t){this.matchID=t,this.createDispatchers(),this.transpor...
    method updateCredentials (line 61) | updateCredentials(t){this.credentials=t,this.createDispatchers(),this....
  function x (line 4) | function x(){}
  function b (line 4) | function b(e,r,t){this.props=e,this.context=r,this.refs=h,this.updater=t...
    method constructor (line 24) | constructor(e,t,r){this.flow=e,this.playerID=r,this.dispatch=[],this.i...
    method api (line 24) | api(){const e={_private:this};for(const t of this.flow.eventNames)e[t]...
    method isUsed (line 24) | isUsed(){return this.dispatch.length>0}
    method updateTurnContext (line 24) | updateTurnContext(e,t){this.currentPhase=e.phase,this.currentTurn=e.tu...
    method unsetCurrentMethod (line 24) | unsetCurrentMethod(){this.currentMethod=void 0}
    method update (line 24) | update(e){const t=e,r=({stack:e},r)=>({...t,plugins:{...t.plugins,even...
  function g (line 4) | function g(e,r,n){var o,u={},f=null,c=null;if(null!=r)for(o in void 0!==...
  function w (line 4) | function w(e,r){return{$$typeof:t,type:e.type,key:r,ref:e.ref,props:e.pr...
  function C (line 4) | function C(e){return"object"==typeof e&&null!==e&&e.$$typeof===t}
  function E (line 4) | function E(e){var r={"=":"=0",":":"=2"};return"$"+(""+e).replace(/[=:]/g...
  function j (line 4) | function j(e,r,t,n){if(P.length){var o=P.pop();return o.result=e,o.keyPr...
  function O (line 4) | function O(e){e.result=null,e.keyPrefix=null,e.func=null,e.context=null,...
  function A (line 4) | function A(e,r,o,u){var f=typeof e;"undefined"!==f&&"boolean"!==f||(e=nu...
  function I (line 4) | function I(e,r,t){return null==e?0:A(e,"",r,t)}
  function U (line 4) | function U(e,r){return"object"==typeof e&&null!==e&&null!=e.key?E(e.key)...
  function q (line 4) | function q(e,r){e.func.call(e.context,r,e.count++)}
  function F (line 4) | function F(e,r,t){var n=e.result,o=e.keyPrefix;e=e.func.call(e.context,r...
  function L (line 4) | function L(e,r,t,n,o){var u="";null!=t&&(u=(""+t).replace(R,"$&/")+"/"),...
  function D (line 4) | function D(){var e=M.current;if(null===e)throw Error(d(321));return e}
  function k (line 8) | function k(e,n){var t=e.length;e.push(n);e:for(;;){var r=t-1>>>1,o=e[r];...
  function T (line 8) | function T(e){return void 0===(e=e[0])?null:e}
  function g (line 8) | function g(e){var n=e[0];if(void 0!==n){var t=e.pop();if(t!==n){e[0]=t;e...
  function P (line 8) | function P(e,n){var t=e.sortIndex-n.sortIndex;return 0!==t?t:e.id-n.id}
  function R (line 8) | function R(e){for(var n=T(I);null!==n;){if(null===n.callback)g(I);else{i...
  function j (line 8) | function j(t){if(D=!1,R(t),!q)if(null!==T(F))q=!0,e(E);else{var r=T(I);n...
  function E (line 8) | function E(e,o){q=!1,D&&(D=!1,t()),L=!0;var a=A;try{for(R(o),C=T(F);null...
  function N (line 8) | function N(e){switch(e){case 1:return-1;case 2:return 250;case 5:return ...
  function r (line 12) | function r(e){for(var t="https://reactjs.org/docs/error-decoder.html?inv...
    method constructor (line 120) | constructor(e){super(),this.opts=e,this.query=e.query,this.readyState=...
    method onError (line 120) | onError(e,t){const s=new Error(e);return s.type="TransportError",s.des...
    method open (line 120) | open(){return"closed"!==this.readyState&&""!==this.readyState||(this.r...
    method close (line 120) | close(){return"opening"!==this.readyState&&"open"!==this.readyState||(...
    method send (line 120) | send(e){"open"===this.readyState?this.write(e):s("transport is not ope...
    method onOpen (line 120) | onOpen(){this.readyState="open",this.writable=!0,this.emit("open")}
    method onData (line 120) | onData(t){const s=e.decodePacket(t,this.socket.binaryType);this.onPack...
    method onPacket (line 120) | onPacket(e){this.emit("packet",e)}
    method onClose (line 120) | onClose(){this.readyState="closed",this.emit("close")}
    method constructor (line 174) | constructor(e,t){super(),this.nsps={},this.subs=[],e&&"object"==typeof...
    method reconnection (line 174) | reconnection(e){return arguments.length?(this._reconnection=!!e,this):...
    method reconnectionAttempts (line 174) | reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(...
    method reconnectionDelay (line 174) | reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(...
    method randomizationFactor (line 174) | randomizationFactor(e){var t;return void 0===e?this._randomizationFact...
    method reconnectionDelayMax (line 174) | reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDela...
    method timeout (line 174) | timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}
    method maybeReconnectOnOpen (line 174) | maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===th...
    method open (line 174) | open(t){if(c("readyState %s",this._readyState),~this._readyState.index...
    method connect (line 174) | connect(e){return this.open(e)}
    method onopen (line 174) | onopen(){c("open"),this.cleanup(),this._readyState="open",this.emitRes...
    method onping (line 174) | onping(){this.emitReserved("ping")}
    method ondata (line 174) | ondata(e){this.decoder.add(e)}
    method ondecoded (line 174) | ondecoded(e){this.emitReserved("packet",e)}
    method onerror (line 174) | onerror(e){c("error",e),this.emitReserved("error",e)}
    method socket (line 174) | socket(e,n){let i=this.nsps[e];return i||(i=new t.Socket(this,e,n),thi...
    method _destroy (line 174) | _destroy(e){const t=Object.keys(this.nsps);for(const n of t){if(this.n...
    method _packet (line 174) | _packet(e){c("writing packet %j",e);const t=this.encoder.encode(e);for...
    method cleanup (line 174) | cleanup(){c("cleanup"),this.subs.forEach(e=>e()),this.subs.length=0,th...
    method _close (line 174) | _close(){c("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,"...
    method disconnect (line 174) | disconnect(){return this._close()}
    method onclose (line 174) | onclose(e){c("onclose"),this.cleanup(),this.backoff.reset(),this._read...
    method reconnect (line 174) | reconnect(){if(this._reconnecting||this.skipReconnect)return this;cons...
    method onreconnect (line 174) | onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this...
    method constructor (line 178) | constructor(){super(),this.state=new Map,this.initial=new Map,this.met...
    method createMatch (line 178) | createMatch(t,e){this.initial.set(t,e.initialState),this.setState(t,e....
    method setMetadata (line 178) | setMetadata(t,e){this.metadata.set(t,e)}
    method setState (line 178) | setState(t,e,s){if(s&&s.length>0){const e=this.log.get(t)||[];this.log...
    method fetch (line 178) | fetch(t,e){const s={};return e.state&&(s.state=this.state.get(t)),e.me...
    method wipe (line 178) | wipe(t){this.state.delete(t),this.metadata.delete(t)}
    method listMatches (line 178) | listMatches(t){return[...this.metadata.entries()].filter(([,e])=>{if(!...
  function l (line 12) | function l(e,t,n,r,l,i,a,o,u){var c=Array.prototype.slice.call(arguments...
    method constructor (line 61) | constructor(){this.debugPanel=null,this.currentClient=null,this.client...
    method register (line 61) | register(t){this.clients.set(t,t),this.mountDebug(t),this.notifySubscr...
    method unregister (line 61) | unregister(t){if(this.clients.delete(t),this.currentClient===t){this.u...
    method subscribe (line 61) | subscribe(t){const e=Symbol();return this.subscribers.set(e,t),t(this....
    method switchPlayerID (line 61) | switchPlayerID(t){if(this.currentClient.multiplayer)for(const[e]of thi...
    method switchToClient (line 61) | switchToClient(t){t!==this.currentClient&&(this.unmountDebug(),this.mo...
    method notifySubscribers (line 61) | notifySubscribers(){const t=this.getState();this.subscribers.forEach(e...
    method getState (line 61) | getState(){return{client:this.currentClient,debuggableClients:this.get...
    method getDebuggableClients (line 61) | getDebuggableClients(){return[...this.clients.values()].filter(t=>!1!=...
    method mountDebug (line 61) | mountDebug(t){if(!1===t.debugOpt||null!==this.debugPanel||"undefined"=...
    method unmountDebug (line 61) | unmountDebug(){this.debugPanel.$destroy(),this.debugPanel=null,this.cu...
    method constructor (line 147) | constructor(e){super(e),this.supportsBinary=!e.forceBase64}
    method name (line 147) | get name(){return"websocket"}
    method doOpen (line 147) | doOpen(){if(!this.check())return;const e=this.uri(),t=this.opts.protoc...
    method addEventListeners (line 147) | addEventListeners(){this.ws.onopen=(()=>{this.opts.autoUnref&&this.ws....
    method write (line 147) | write(t){this.writable=!1;for(let r=0;r<t.length;r++){const o=t[r],i=r...
    method onClose (line 147) | onClose(){t.prototype.onClose.call(this)}
    method doClose (line 147) | doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}
    method uri (line 147) | uri(){let e=this.query||{};const t=this.opts.secure?"wss":"ws";let s="...
    method check (line 147) | check(){return!(!n||"__initialize"in n&&this.name===l.prototype.name)}
    method constructor (line 178) | constructor({game:t,bots:e,storageKey:s,persist:a}){const n={},c={};if...
  function s (line 12) | function s(e,t,n,r,o,u,s,f,d){i=!1,a=null,l.apply(c,arguments)}
    method type (line 80) | type(){return e.ASYNC}
    method createMatch (line 80) | async createMatch(e,t){if(this.createGame)return console.warn("The dat...
    method listMatches (line 80) | async listMatches(e){if(this.listGames)return console.warn("The databa...
  function f (line 12) | function f(e,t,n,l,c,f,d,p,m){if(s.apply(this,arguments),i){if(!i)throw ...
  function h (line 12) | function h(e,t,n){var r=e.type||"unknown-event";e.currentTarget=m(n),f(r...
    method connect (line 61) | connect(){}
    method disconnect (line 61) | disconnect(){}
    method sendAction (line 61) | sendAction(){}
    method sendChatMessage (line 61) | sendChatMessage(){}
    method requestSync (line 61) | requestSync(){}
    method updateCredentials (line 61) | updateCredentials(){}
    method updateMatchID (line 61) | updateMatchID(){}
    method updatePlayerID (line 61) | updatePlayerID(){}
    method constructor (line 180) | constructor({server:e,gameComponents:t,playerName:s,playerCredentials:...
    method refresh (line 180) | async refresh(){try{this.matches=[];const t=await this.client.listGame...
    method _getMatchInstance (line 180) | _getMatchInstance(e){for(const t of this.matches)if(t.matchID===e)retu...
    method _getGameComponents (line 180) | _getGameComponents(e){for(const t of this.gameComponents)if(t.game.nam...
    method _findPlayer (line 180) | _findPlayer(e){for(const t of this.matches)if(t.players.some(t=>t.name...
    method join (line 180) | async join(e,t,a){try{let r=this._findPlayer(this.playerName);if(r)thr...
    method leave (line 180) | async leave(e,t){try{const s=this._getMatchInstance(t);if(!s)throw new...
    method disconnect (line 180) | async disconnect(){const e=this._findPlayer(this.playerName);e&&await ...
    method create (line 180) | async create(e,t){try{const s=this._getGameComponents(e);if(!s)throw n...
  function y (line 12) | function y(){if(g)for(var e in v){var t=v[e],n=g.indexOf(e);if(!(-1<n))t...
    method constructor (line 178) | constructor({socket:t,socketOpts:e,server:s,...i}){super(i),this.serve...
    method sendAction (line 178) | sendAction(t,e){const s=[e,t._stateID,this.matchID,this.playerID];this...
    method sendChatMessage (line 178) | sendChatMessage(t,e){const s=[t,e,this.credentials];this.socket.emit("...
    method connect (line 178) | connect(){if(!this.socket)if(this.server){let t=this.server;-1==t.sear...
    method disconnect (line 178) | disconnect(){this.socket.close(),this.socket=null,this.setConnectionSt...
    method requestSync (line 178) | requestSync(){if(this.socket){const t=[this.matchID,this.playerID,this...
    method updateMatchID (line 178) | updateMatchID(t){this.matchID=t,this.requestSync()}
    method updatePlayerID (line 178) | updatePlayerID(t){this.playerID=t,this.requestSync()}
    method updateCredentials (line 178) | updateCredentials(t){this.credentials=t,this.requestSync()}
    method constructor (line 180) | constructor(e){super(e),this.state={phase:i.ENTER,playerName:"Visitor"...
    method componentDidMount (line 180) | componentDidMount(){const e=n.default.load("lobbyState")||{};e.phase&&...
    method componentDidUpdate (line 180) | componentDidUpdate(e,t){const a=this.state.playerName,s=this.state.cre...
    method componentWillUnmount (line 180) | componentWillUnmount(){this._clearRefreshInterval()}
    method _startRefreshInterval (line 180) | _startRefreshInterval(){this._clearRefreshInterval(),this._currentInte...
    method _clearRefreshInterval (line 180) | _clearRefreshInterval(){clearInterval(this._currentInterval)}
    method render (line 180) | render(){const{gameComponents:e,renderer:t}=this.props,{errorMsg:a,pla...
  function b (line 12) | function b(e,t,n){if(x[e])throw Error(r(100,e));x[e]=t,T[e]=t.eventTypes...
    method constructor (line 24) | constructor(e,t,r){this.flow=e,this.playerID=r,this.dispatch=[],this.i...
    method api (line 24) | api(){const e={_private:this};for(const t of this.flow.eventNames)e[t]...
    method isUsed (line 24) | isUsed(){return this.dispatch.length>0}
    method updateTurnContext (line 24) | updateTurnContext(e,t){this.currentPhase=e.phase,this.currentTurn=e.tu...
    method unsetCurrentMethod (line 24) | unsetCurrentMethod(){this.currentMethod=void 0}
    method update (line 24) | update(e){const t=e,r=({stack:e},r)=>({...t,plugins:{...t.plugins,even...
  function E (line 12) | function E(e){var t,n=!1;for(t in e)if(e.hasOwnProperty(t)){var l=e[t];i...
  function N (line 12) | function N(e){if(e=p(e)){if("function"!=typeof C)throw Error(r(280));var...
  function z (line 12) | function z(e){P?_?_.push(e):_=[e]:P=e}
  function M (line 12) | function M(){if(P){var e=P,t=_;if(_=P=null,N(e),t)for(e=0;e<t.length;e++...
  function I (line 12) | function I(e,t){return e(t)}
  function F (line 12) | function F(e,t,n,r,l){return e(t,n,r,l)}
  function O (line 12) | function O(){}
  function U (line 12) | function U(){null===P&&null===_||(O(),M())}
  function A (line 12) | function A(e,t,n){if(L)return e(t,n);L=!0;try{return R(e,t,n)}finally{L=...
  function j (line 12) | function j(e){return!!Q.call(H,e)||!Q.call(W,e)&&(V.test(e)?H[e]=!0:(W[e...
  function B (line 12) | function B(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){ca...
  function K (line 12) | function K(e,t,n,r){if(null==t||B(e,t,n,r))return!0;if(r)return!1;if(nul...
  function $ (line 12) | function $(e,t,n,r,l,i){this.acceptsBooleans=2===t||3===t||4===t,this.at...
  function X (line 12) | function X(e){return e[1].toUpperCase()}
  function Z (line 12) | function Z(e,t,n,r){var l=q.hasOwnProperty(t)?q[t]:null;(null!==l?0===l....
  function ge (line 12) | function ge(e){return null===e||"object"!=typeof e?null:"function"==type...
  function ve (line 12) | function ve(e){if(-1===e._status){e._status=0;var t=e._ctor;t=t(),e._res...
  function ye (line 12) | function ye(e){if(null==e)return null;if("function"==typeof e)return e.d...
  function be (line 12) | function be(e){var t="";do{e:switch(e.tag){case 3:case 4:case 6:case 7:c...
  function we (line 12) | function we(e){switch(typeof e){case"boolean":case"number":case"object":...
  function ke (line 12) | function ke(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCas...
  function xe (line 12) | function xe(e){var t=ke(e)?"checked":"value",n=Object.getOwnPropertyDesc...
  function Te (line 12) | function Te(e){e._valueTracker||(e._valueTracker=xe(e))}
  function Ee (line 12) | function Ee(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n...
  function Se (line 12) | function Se(e,n){var r=n.checked;return t({},n,{defaultChecked:void 0,de...
  function Ce (line 12) | function Ce(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t....
  function Pe (line 12) | function Pe(e,t){null!=(t=t.checked)&&Z(e,"checked",t,!1)}
  function _e (line 12) | function _e(e,t){Pe(e,t);var n=we(t.value),r=t.type;if(null!=n)"number"=...
  function Ne (line 12) | function Ne(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defau...
  function ze (line 12) | function ze(e,t,n){"number"===t&&e.ownerDocument.activeElement===e||(nul...
  function Me (line 12) | function Me(t){var n="";return e.Children.forEach(t,function(e){null!=e&...
  function Ie (line 12) | function Ie(e,n){return e=t({children:void 0},n),(n=Me(n.children))&&(e....
  function Fe (line 12) | function Fe(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l<n.length;l++)t...
  function Oe (line 12) | function Oe(e,n){if(null!=n.dangerouslySetInnerHTML)throw Error(r(91));r...
  function Re (line 12) | function Re(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultVa...
  function De (line 12) | function De(e,t){var n=we(t.value),r=we(t.defaultValue);null!=n&&((n=""+...
  function Le (line 12) | function Le(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!...
    method $destroy (line 49) | $destroy(){Ke(this,1),this.$destroy=l}
    method $on (line 49) | $on(e,t){const n=this.$$.callbacks[e]||(this.$$.callbacks[e]=[]);retur...
    method $set (line 49) | $set(e){this.$$set&&!f(e)&&(this.$$.skip_bound=!0,this.$$set(e),this.$...
  function Ae (line 12) | function Ae(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";ca...
  function Ve (line 12) | function Ve(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?Ae(t...
  function He (line 12) | function He(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.n...
  function je (line 12) | function je(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["W...
  function qe (line 12) | function qe(e){if(Ke[e])return Ke[e];if(!Be[e])return e;var t,n=Be[e];fo...
  function tt (line 12) | function tt(e){var t=et.get(e);return void 0===t&&(t=new Map,et.set(e,t)...
  function nt (line 12) | function nt(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else...
    method constructor (line 49) | constructor(e){super(),Je(this,e,tt,et,d,{title:0,viewBox:1},Ye)}
  function rt (line 12) | function rt(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!=...
  function lt (line 12) | function lt(e){if(nt(e)!==e)throw Error(r(188))}
  function it (line 12) | function it(e){var t=e.alternate;if(!t){if(null===(t=nt(e)))throw Error(...
  function at (line 12) | function at(e){if(!(e=it(e)))return null;for(var t=e;;){if(5===t.tag||6=...
    method constructor (line 49) | constructor(e){super(),Je(this,e,ot,lt,d,{})}
  function ot (line 12) | function ot(e,t){if(null==t)throw Error(r(30));return null==e?t:Array.is...
  function ut (line 12) | function ut(e,t,n){Array.isArray(e)?e.forEach(t,n):e&&t.call(n,e)}
  function st (line 12) | function st(e){if(e){var t=e._dispatchListeners,n=e._dispatchInstances;i...
  function ft (line 12) | function ft(e){if(null!==e&&(ct=ot(ct,e)),e=ct,ct=null,e){if(ut(e,st),ct...
    method constructor (line 49) | constructor(e){super(),Je(this,e,dt,ut,d,{pane:0,panes:1},st)}
  function dt (line 12) | function dt(e){return(e=e.target||e.srcElement||window).correspondingUse...
  function pt (line 12) | function pt(e){if(!S)return!1;var t=(e="on"+e)in document;return t||((t=...
  function ht (line 12) | function ht(e){e.topLevelType=null,e.nativeEvent=null,e.targetInst=null,...
  function gt (line 12) | function gt(e,t,n,r){if(mt.length){var l=mt.pop();return l.topLevelType=...
  function vt (line 12) | function vt(e){var t=e.targetInst,n=t;do{if(!n){e.ancestors.push(n);brea...
  function yt (line 12) | function yt(e,t,n){if(!n.has(e)){switch(e){case"scroll":en(t,"scroll",!0...
  function It (line 12) | function It(e,t){var n=tt(t);zt.forEach(function(e){yt(e,t,n)}),Mt.forEa...
  function Ft (line 12) | function Ft(e,t,n,r,l){return{blockedOn:e,topLevelType:t,eventSystemFlag...
  function Ot (line 12) | function Ot(e,t){switch(e){case"focus":case"blur":Et=null;break;case"dra...
  function Rt (line 12) | function Rt(e,t,n,r,l,i){return null===e||e.nativeEvent!==i?(e=Ft(t,n,r,...
  function Dt (line 12) | function Dt(e,t,n,r,l){switch(t){case"focus":return Et=Rt(Et,e,t,n,r,l),...
  function Lt (line 12) | function Lt(e){var t=Un(e.target);if(null!==t){var r=nt(t);if(null!==r)i...
    method constructor (line 49) | constructor(e,t){this.key=e,this.value=t}
  function Ut (line 12) | function Ut(e){if(null!==e.blockedOn)return!1;var t=ln(e.topLevelType,e....
  function At (line 12) | function At(e,t,n){Ut(e)&&n.delete(t)}
  function Vt (line 12) | function Vt(){for(xt=!1;0<Tt.length;){var e=Tt[0];if(null!==e.blockedOn)...
    method constructor (line 49) | constructor(e){super(),Je(this,e,Nt,Dt,d,{key:0,value:1,isParentExpand...
  function Qt (line 12) | function Qt(e,t){e.blockedOn===t&&(e.blockedOn=null,xt||(xt=!0,n.unstabl...
    method constructor (line 49) | constructor(e){super(),Je(this,e,Yt,Xt,d,{key:0,value:1,isParentExpand...
  function Wt (line 12) | function Wt(e){function t(t){return Qt(t,e)}if(0<Tt.length){Qt(Tt[0],e);...
    method constructor (line 49) | constructor(e){super(),Je(this,e,Ut,Ft,d,{key:0,value:5,isParentExpand...
  function $t (line 12) | function $t(e,t){for(var n=0;n<e.length;n+=2){var r=e[n],l=e[n+1],i="on"...
    method constructor (line 49) | constructor(e){super(),Je(this,e,vt,gt,d,{expanded:0},mt)}
  function Jt (line 12) | function Jt(e,t){en(t,e,!1)}
    method constructor (line 49) | constructor(e){super(),Je(this,e,Gt,Bt,d,{key:0,value:5,isParentExpand...
  function en (line 12) | function en(e,t,n){var r=Bt.get(t);switch(void 0===r?2:r){case 0:r=tn.bi...
  function tn (line 12) | function tn(e,t,n,r){D||O();var l=rn,i=D;D=!0;try{F(l,e,t,n,r)}finally{(...
  function nn (line 12) | function nn(e,t,n,r){Gt(Xt,rn.bind(null,e,t,n,r))}
  function rn (line 12) | function rn(e,t,n,r){if(Zt)if(0<Tt.length&&-1<zt.indexOf(e))e=Ft(null,e,...
    method constructor (line 49) | constructor(e){super(),Je(this,e,nn,tn,d,{key:0,value:1,valueGetter:2,...
  function ln (line 12) | function ln(e,t,n,r){if(null!==(n=Un(n=dt(r)))){var l=nt(n);if(null===l)...
  function un (line 12) | function un(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"nu...
  function cn (line 12) | function cn(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=...
  function fn (line 12) | function fn(e,t){if(t){if(sn[e]&&(null!=t.children||null!=t.dangerouslyS...
  function dn (line 12) | function dn(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;swit...
  function mn (line 12) | function mn(e,t){var n=tt(e=9===e.nodeType||11===e.nodeType?e:e.ownerDoc...
  function hn (line 12) | function hn(){}
  function gn (line 12) | function gn(e){if(void 0===(e=e||("undefined"!=typeof document?document:...
  function vn (line 12) | function vn(e){for(;e&&e.firstChild;)e=e.firstChild;return e}
  function yn (line 12) | function yn(e,t){var n,r=vn(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.t...
  function bn (line 12) | function bn(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===...
  function wn (line 12) | function wn(){for(var e=window,t=gn();t instanceof e.HTMLIFrameElement;)...
  function kn (line 12) | function kn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(...
  function _n (line 12) | function _n(e,t){switch(e){case"button":case"input":case"select":case"te...
  function Nn (line 12) | function Nn(e,t){return"textarea"===e||"option"===e||"noscript"===e||"st...
  function In (line 12) | function In(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||...
    method constructor (line 49) | constructor(e){super(),Je(this,e,qn,Cn,d,{value:0,onPress:8,label:1,di...
  function Fn (line 12) | function Fn(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){va...
  function Un (line 12) | function Un(e){var t=e[Rn];if(t)return t;for(var n=e.parentNode;n;){if(t...
  function An (line 12) | function An(e){return!(e=e[Rn]||e[Ln])||5!==e.tag&&6!==e.tag&&13!==e.tag...
  function Vn (line 12) | function Vn(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(r(...
    method constructor (line 49) | constructor(e){super(),Je(this,e,Nn,Mn,d,{Activate:0,Deactivate:1,name...
  function Qn (line 12) | function Qn(e){return e[Dn]||null}
  function Wn (line 12) | function Wn(e){do{e=e.return}while(e&&5!==e.tag);return e||null}
  function Hn (line 12) | function Hn(e,t){var n=e.stateNode;if(!n)return null;var l=d(n);if(!l)re...
  function jn (line 12) | function jn(e,t,n){(t=Hn(e,n.dispatchConfig.phasedRegistrationNames[t]))...
  function Bn (line 12) | function Bn(e){if(e&&e.dispatchConfig.phasedRegistrationNames){for(var t...
  function Kn (line 12) | function Kn(e,t,n){e&&n&&n.dispatchConfig.registrationName&&(t=Hn(e,n.di...
  function $n (line 12) | function $n(e){e&&e.dispatchConfig.registrationName&&Kn(e._targetInst,nu...
    method constructor (line 49) | constructor(e){super(),Je(this,e,vn,gn,d,{key:0,value:1,isParentExpand...
  function qn (line 12) | function qn(e){ut(e,Bn)}
  function Zn (line 12) | function Zn(){if(Gn)return Gn;var e,t,n=Xn,r=n.length,l="value"in Yn?Yn....
    method constructor (line 49) | constructor(e){super(),Je(this,e,Hn,Fn,d,{client:0,ToggleVisibility:1}...
  function Jn (line 12) | function Jn(){return!0}
    method constructor (line 49) | constructor(e){super(),Je(this,e,Gn,Kn,d,{shortcut:0,name:1,fn:8},Bn)}
  function er (line 12) | function er(){return!1}
    method constructor (line 49) | constructor(e){super(),Je(this,e,Qn,Yn,d,{ctx:0,playerID:1},Un)}
  function tr (line 12) | function tr(e,t,n,r){for(var l in this.dispatchConfig=e,this._targetInst...
  function nr (line 12) | function nr(e,t,n,r){if(this.eventPool.length){var l=this.eventPool.pop(...
  function rr (line 12) | function rr(e){if(!(e instanceof this))throw Error(r(279));e.destructor(...
  function lr (line 12) | function lr(e){e.eventPool=[],e.getPooled=nr,e.release=rr}
  function n (line 12) | function n(){}
    method constructor (line 20) | constructor(t){this.state=t||{seed:"0"},this.used=!1}
    method seed (line 20) | static seed(){return Date.now().toString(36).slice(-10)}
    method isUsed (line 20) | isUsed(){return this.used}
    method getState (line 20) | getState(){return this.state}
    method _random (line 20) | _random(){this.used=!0;const t=this.state,s=r(t.prngstate?"":t.seed,t....
    method api (line 20) | api(){const t=this._random.bind(this),s={D4:4,D6:6,D8:8,D10:10,D12:12,...
    method play (line 47) | play({G:t,ctx:e},r){const a=this.enumerate(t,e,r);return Promise.resol...
    method constructor (line 63) | constructor({server:e=""}={}){this.server=e.replace(/\/$/,"")}
    method request (line 63) | async request(e,t){const s=await fetch(this.server+e,t);if(!s.ok){let ...
    method post (line 63) | async post(e,t){let s={method:"post",body:JSON.stringify(t.body),heade...
    method listGames (line 63) | async listGames(e){return this.request("/games",e)}
    method listMatches (line 63) | async listMatches(e,s,r){t(e);let a="";if(s){const e=[],{isGameover:t,...
    method getMatch (line 63) | async getMatch(e,r,a){return t(e),s(r),this.request(`/games/${e}/${r}`...
    method createMatch (line 63) | async createMatch(e,s,a){return t(e),r(s,{numPlayers:"number"}),this.p...
    method joinMatch (line 63) | async joinMatch(e,a,n,i){return t(e),s(a),r(n,{playerID:["string","und...
    method leaveMatch (line 63) | async leaveMatch(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentials...
    method updatePlayer (line 63) | async updatePlayer(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentia...
    method playAgain (line 63) | async playAgain(e,a,n,i){return t(e),s(a),r(n,{playerID:"string",crede...
    method type (line 80) | type(){return e.SYNC}
    method connect (line 80) | connect(){}
    method createMatch (line 80) | createMatch(e,t){if(this.createGame)return console.warn("The database ...
    method listMatches (line 80) | listMatches(e){if(this.listGames)return console.warn("The database con...
    method constructor (line 151) | constructor(t,e={}){super(),t&&"object"==typeof t&&(e=t,t=null),t?(t=i...
    method createTransport (line 151) | createTransport(e){s('creating transport "%s"',e);const i=a(this.opts....
    method open (line 151) | open(){let t;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1...
    method setTransport (line 151) | setTransport(t){s("setting transport %s",t.name),this.transport&&(s("c...
    method probe (line 151) | probe(t){s('probing transport "%s"',t);let e=this.createTransport(t,{p...
    method onOpen (line 151) | onOpen(){if(s("socket open"),this.readyState="open",n.priorWebsocketSu...
    method onPacket (line 151) | onPacket(t){if("opening"===this.readyState||"open"===this.readyState||...
    method onHandshake (line 151) | onHandshake(t){this.emit("handshake",t),this.id=t.sid,this.transport.q...
    method resetPingTimeout (line 151) | resetPingTimeout(){clearTimeout(this.pingTimeoutTimer),this.pingTimeou...
    method onDrain (line 151) | onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBuffe...
    method flush (line 151) | flush(){"closed"!==this.readyState&&this.transport.writable&&!this.upg...
    method write (line 151) | write(t,e,s){return this.sendPacket("message",t,e,s),this}
    method send (line 151) | send(t,e,s){return this.sendPacket("message",t,e,s),this}
    method sendPacket (line 151) | sendPacket(t,e,s,r){if("function"==typeof e&&(r=e,e=void 0),"function"...
    method close (line 151) | close(){const t=()=>{this.onClose("forced close"),s("socket closing - ...
    method onError (line 151) | onError(t){s("socket error %j",t),n.priorWebsocketSuccess=!1,this.emit...
    method onClose (line 151) | onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"c...
    method filterUpgrades (line 151) | filterUpgrades(t){const e=[];let s=0;const r=t.length;for(;s<r;s++)~th...
  function r (line 12) | function r(){return l.apply(this,arguments)}
    method constructor (line 120) | constructor(e){super(),this.opts=e,this.query=e.query,this.readyState=...
    method onError (line 120) | onError(e,t){const s=new Error(e);return s.type="TransportError",s.des...
    method open (line 120) | open(){return"closed"!==this.readyState&&""!==this.readyState||(this.r...
    method close (line 120) | close(){return"opening"!==this.readyState&&"open"!==this.readyState||(...
    method send (line 120) | send(e){"open"===this.readyState?this.write(e):s("transport is not ope...
    method onOpen (line 120) | onOpen(){this.readyState="open",this.writable=!0,this.emit("open")}
    method onData (line 120) | onData(t){const s=e.decodePacket(t,this.socket.binaryType);this.onPack...
    method onPacket (line 120) | onPacket(e){this.emit("packet",e)}
    method onClose (line 120) | onClose(){this.readyState="closed",this.emit("close")}
    method constructor (line 174) | constructor(e,t){super(),this.nsps={},this.subs=[],e&&"object"==typeof...
    method reconnection (line 174) | reconnection(e){return arguments.length?(this._reconnection=!!e,this):...
    method reconnectionAttempts (line 174) | reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(...
    method reconnectionDelay (line 174) | reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(...
    method randomizationFactor (line 174) | randomizationFactor(e){var t;return void 0===e?this._randomizationFact...
    method reconnectionDelayMax (line 174) | reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDela...
    method timeout (line 174) | timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}
    method maybeReconnectOnOpen (line 174) | maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===th...
    method open (line 174) | open(t){if(c("readyState %s",this._readyState),~this._readyState.index...
    method connect (line 174) | connect(e){return this.open(e)}
    method onopen (line 174) | onopen(){c("open"),this.cleanup(),this._readyState="open",this.emitRes...
    method onping (line 174) | onping(){this.emitReserved("ping")}
    method ondata (line 174) | ondata(e){this.decoder.add(e)}
    method ondecoded (line 174) | ondecoded(e){this.emitReserved("packet",e)}
    method onerror (line 174) | onerror(e){c("error",e),this.emitReserved("error",e)}
    method socket (line 174) | socket(e,n){let i=this.nsps[e];return i||(i=new t.Socket(this,e,n),thi...
    method _destroy (line 174) | _destroy(e){const t=Object.keys(this.nsps);for(const n of t){if(this.n...
    method _packet (line 174) | _packet(e){c("writing packet %j",e);const t=this.encoder.encode(e);for...
    method cleanup (line 174) | cleanup(){c("cleanup"),this.subs.forEach(e=>e()),this.subs.length=0,th...
    method _close (line 174) | _close(){c("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,"...
    method disconnect (line 174) | disconnect(){return this._close()}
    method onclose (line 174) | onclose(e){c("onclose"),this.cleanup(),this.backoff.reset(),this._read...
    method reconnect (line 174) | reconnect(){if(this._reconnecting||this.skipReconnect)return this;cons...
    method onreconnect (line 174) | onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this...
    method constructor (line 178) | constructor(){super(),this.state=new Map,this.initial=new Map,this.met...
    method createMatch (line 178) | createMatch(t,e){this.initial.set(t,e.initialState),this.setState(t,e....
    method setMetadata (line 178) | setMetadata(t,e){this.metadata.set(t,e)}
    method setState (line 178) | setState(t,e,s){if(s&&s.length>0){const e=this.log.get(t)||[];this.log...
    method fetch (line 178) | fetch(t,e){const s={};return e.state&&(s.state=this.state.get(t)),e.me...
    method wipe (line 178) | wipe(t){this.state.delete(t),this.metadata.delete(t)}
    method listMatches (line 178) | listMatches(t){return[...this.metadata.entries()].filter(([,e])=>{if(!...
  function hr (line 12) | function hr(e,t){switch(e){case"keyup":return-1!==or.indexOf(t.keyCode);...
  function gr (line 12) | function gr(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}
  function yr (line 12) | function yr(e,t){switch(e){case"compositionend":return gr(t);case"keypre...
  function br (line 12) | function br(e,t){if(vr)return"compositionend"===e||!ur&&hr(e,t)?(e=Zn(),...
  function xr (line 12) | function xr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"inpu...
  function Er (line 12) | function Er(e,t,n){return(e=tr.getPooled(Tr.change,e,t,n)).type="change"...
  function Pr (line 12) | function Pr(e){ft(e)}
  function _r (line 12) | function _r(e){if(Ee(Vn(e)))return e}
  function Nr (line 12) | function Nr(e,t){if("change"===e)return t}
    method constructor (line 49) | constructor(e){super(),Je(this,e,Dr,Mr,d,{client:0,clientManager:2,Tog...
  function Mr (line 12) | function Mr(){Sr&&(Sr.detachEvent("onpropertychange",Ir),Cr=Sr=null)}
  function Ir (line 12) | function Ir(e){if("value"===e.propertyName&&_r(Cr))if(e=Er(Cr,e,dt(e)),D...
  function Fr (line 12) | function Fr(e,t,n){"focus"===e?(Mr(),Cr=n,(Sr=t).attachEvent("onproperty...
    method constructor (line 49) | constructor(e){super(),Je(this,e,Lr,Jr,d,{phase:0,numEvents:2},Gr)}
  function Or (line 12) | function Or(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)retu...
  function Rr (line 12) | function Rr(e,t){if("click"===e)return _r(t)}
  function Dr (line 12) | function Dr(e,t){if("input"===e||"change"===e)return _r(t)}
  function Vr (line 12) | function Vr(e){var t=this.nativeEvent;return t.getModifierState?t.getMod...
  function Qr (line 12) | function Qr(){return Vr}
  function Xr (line 12) | function Xr(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t}
  function Jr (line 12) | function Jr(e,t){if(Gr(e,t))return!0;if("object"!=typeof e||null===e||"o...
  function al (line 12) | function al(e,t){var n=t.window===t?t.document:9===t.nodeType?t:t.ownerD...
  function fl (line 12) | function fl(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&...
  function Tl (line 12) | function Tl(e){0>xl||(e.current=kl[xl],kl[xl]=null,xl--)}
  function El (line 12) | function El(e,t){kl[++xl]=e.current,e.current=t}
  function Nl (line 12) | function Nl(e,t){var n=e.type.contextTypes;if(!n)return Sl;var r=e.state...
  function zl (line 12) | function zl(e){return null!=(e=e.childContextTypes)}
  function Ml (line 12) | function Ml(){Tl(Pl),Tl(Cl)}
  function Il (line 12) | function Il(e,t,n){if(Cl.current!==Sl)throw Error(r(168));El(Cl,t),El(Pl...
  function Fl (line 12) | function Fl(e,n,l){var i=e.stateNode;if(e=n.childContextTypes,"function"...
  function Ol (line 12) | function Ol(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMerged...
  function Rl (line 12) | function Rl(e,t,n){var l=e.stateNode;if(!l)throw Error(r(169));n?(e=Fl(e...
  function ti (line 12) | function ti(){switch(Ql()){case Wl:return 99;case Hl:return 98;case jl:r...
  function ni (line 12) | function ni(e){switch(e){case 99:return Wl;case 98:return Hl;case 97:ret...
  function ri (line 12) | function ri(e,t){return e=ni(e),Dl(e,t)}
  function li (line 12) | function li(e,t,n){return e=ni(e),Ll(e,t,n)}
  function ii (line 12) | function ii(e){return null===Xl?(Xl=[e],Gl=Ll(Wl,oi)):Xl.push(e),$l}
  function ai (line 12) | function ai(){if(null!==Gl){var e=Gl;Gl=null,Ul(e)}oi()}
  function oi (line 12) | function oi(){if(!Zl&&null!==Xl){Zl=!0;var e=0;try{var t=Xl;ri(99,functi...
  function ui (line 12) | function ui(e,t,n){return 1073741821-(1+((1073741821-e+t/10)/(n/=10)|0))*n}
  function ci (line 12) | function ci(e,n){if(e&&e.defaultProps)for(var r in n=t({},n),e=e.default...
  function mi (line 12) | function mi(){pi=di=fi=null}
  function hi (line 12) | function hi(e){var t=si.current;Tl(si),e.type._context._currentValue=t}
  function gi (line 12) | function gi(e,t){for(;null!==e;){var n=e.alternate;if(e.childExpirationT...
  function vi (line 12) | function vi(e,t){fi=e,pi=di=null,null!==(e=e.dependencies)&&null!==e.fir...
  function yi (line 12) | function yi(e,t){if(pi!==e&&!1!==t&&0!==t)if("number"==typeof t&&1073741...
  function wi (line 12) | function wi(e){e.updateQueue={baseState:e.memoizedState,baseQueue:null,s...
  function ki (line 12) | function ki(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={base...
  function xi (line 12) | function xi(e,t){return(e={expirationTime:e,suspenseConfig:t,tag:0,paylo...
  function Ti (line 12) | function Ti(e,t){if(null!==(e=e.updateQueue)){var n=(e=e.shared).pending...
  function Ei (line 12) | function Ei(e,t){var n=e.alternate;null!==n&&ki(n,e),null===(n=(e=e.upda...
  function Si (line 12) | function Si(e,n,r,l){var i=e.updateQueue;bi=!1;var a=i.baseQueue,o=i.sha...
  function Ci (line 12) | function Ci(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.le...
  function Ni (line 12) | function Ni(e,n,r,l){r=null==(r=r(l,n=e.memoizedState))?n:t({},n,r),e.me...
  function Mi (line 12) | function Mi(e,t,n,r,l,i,a){return"function"==typeof(e=e.stateNode).shoul...
  function Ii (line 12) | function Ii(e,t,n){var r=!1,l=Sl,i=t.contextType;return"object"==typeof ...
  function Fi (line 12) | function Fi(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceive...
  function Oi (line 12) | function Oi(e,t,n,r){var l=e.stateNode;l.props=n,l.state=e.memoizedState...
  function Di (line 12) | function Di(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=...
  function Li (line 12) | function Li(e,t){if("textarea"!==e.type)throw Error(r(31,"[object Object...
  function Ui (line 12) | function Ui(e){function t(t,n){if(e){var r=t.lastEffect;null!==r?(r.next...
  function Bi (line 12) | function Bi(e){if(e===Qi)throw Error(r(174));return e}
  function Ki (line 12) | function Ki(e,t){switch(El(ji,t),El(Hi,e),El(Wi,Qi),e=t.nodeType){case 9...
  function $i (line 12) | function $i(){Tl(Wi),Tl(Hi),Tl(ji)}
  function qi (line 12) | function qi(e){Bi(ji.current);var t=Bi(Wi.current),n=Ve(t,e.type);t!==n&...
  function Yi (line 12) | function Yi(e){Hi.current===e&&(Tl(Wi),Tl(Hi))}
  function Gi (line 12) | function Gi(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedSta...
  function Zi (line 12) | function Zi(e,t){return{responder:e,props:t}}
  function aa (line 12) | function aa(){throw Error(r(321))}
  function oa (line 12) | function oa(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length...
  function ua (line 12) | function ua(e,t,n,l,i,a){if(ta=a,na=t,t.memoizedState=null,t.updateQueue...
  function ca (line 12) | function ca(){var e={memoizedState:null,baseState:null,baseQueue:null,qu...
  function sa (line 12) | function sa(){if(null===ra){var e=na.alternate;e=null!==e?e.memoizedStat...
  function fa (line 12) | function fa(e,t){return"function"==typeof t?t(e):t}
  function da (line 12) | function da(e){var t=sa(),n=t.queue;if(null===n)throw Error(r(311));n.la...
  function pa (line 12) | function pa(e){var t=sa(),n=t.queue;if(null===n)throw Error(r(311));n.la...
  function ma (line 12) | function ma(e){var t=ca();return"function"==typeof e&&(e=e()),t.memoized...
  function ha (line 12) | function ha(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null...
  function ga (line 12) | function ga(){return sa().memoizedState}
  function va (line 12) | function va(e,t,n,r){var l=ca();na.effectTag|=e,l.memoizedState=ha(1|t,n...
  function ya (line 12) | function ya(e,t,n,r){var l=sa();r=void 0===r?null:r;var i=void 0;if(null...
  function ba (line 12) | function ba(e,t){return va(516,4,e,t)}
  function wa (line 12) | function wa(e,t){return ya(516,4,e,t)}
  function ka (line 12) | function ka(e,t){return ya(4,2,e,t)}
  function xa (line 12) | function xa(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(nul...
  function Ta (line 12) | function Ta(e,t,n){return n=null!=n?n.concat([e]):null,ya(4,2,xa.bind(nu...
  function Ea (line 12) | function Ea(){}
  function Sa (line 12) | function Sa(e,t){return ca().memoizedState=[e,void 0===t?null:t],e}
  function Ca (line 12) | function Ca(e,t){var n=sa();t=void 0===t?null:t;var r=n.memoizedState;re...
  function Pa (line 12) | function Pa(e,t){var n=sa();t=void 0===t?null:t;var r=n.memoizedState;re...
  function _a (line 12) | function _a(e,t,n){var r=ti();ri(98>r?98:r,function(){e(!0)}),ri(97<r?97...
  function Na (line 12) | function Na(e,t,n){var r=bu(),l=Pi.suspense;l={expirationTime:r=wu(r,e,l...
  function La (line 12) | function La(e,t){var n=Ju(5,null,null,0);n.elementType="DELETED",n.type=...
  function Ua (line 12) | function Ua(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==...
  function Aa (line 12) | function Aa(e){if(Da){var t=Ra;if(t){var n=t;if(!Ua(e,t)){if(!(t=In(n.ne...
  function Va (line 12) | function Va(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag...
  function Qa (line 12) | function Qa(e){if(e!==Oa)return!1;if(!Da)return Va(e),Da=!0,!1;var t=e.t...
  function Wa (line 12) | function Wa(){Ra=Oa=null,Da=!1}
  function Ba (line 12) | function Ba(e,t,n,r){t.child=null===e?Vi(t,null,n,r):Ai(t,e.child,n,r)}
  function Ka (line 12) | function Ka(e,t,n,r,l){n=n.render;var i=t.ref;return vi(t,l),r=ua(e,t,n,...
  function $a (line 12) | function $a(e,t,n,r,l,i){if(null===e){var a=n.type;return"function"!=typ...
  function qa (line 12) | function qa(e,t,n,r,l,i){return null!==e&&Jr(e.memoizedProps,r)&&e.ref==...
  function Ya (line 12) | function Ya(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&...
  function Xa (line 12) | function Xa(e,t,n,r,l){var i=zl(n)?_l:Cl.current;return i=Nl(t,i),vi(t,l...
  function Ga (line 12) | function Ga(e,t,n,r,l){if(zl(n)){var i=!0;Ol(t)}else i=!1;if(vi(t,l),nul...
  function Za (line 12) | function Za(e,t,n,r,l,i){Ya(e,t);var a=0!=(64&t.effectTag);if(!r&&!a)ret...
  function Ja (line 12) | function Ja(e){var t=e.stateNode;t.pendingContext?Il(e,t.pendingContext,...
  function io (line 12) | function io(e,t,n){var r,l=t.mode,i=t.pendingProps,a=Xi.current,o=!1;if(...
  function ao (line 12) | function ao(e,t){e.expirationTime<t&&(e.expirationTime=t);var n=e.altern...
  function oo (line 12) | function oo(e,t,n,r,l,i){var a=e.memoizedState;null===a?e.memoizedState=...
  function uo (line 12) | function uo(e,t,n){var r=t.pendingProps,l=r.revealOrder,i=r.tail;if(Ba(e...
  function co (line 12) | function co(e,t,n){null!==e&&(t.dependencies=e.dependencies);var l=t.exp...
  function so (line 12) | function so(e,t){switch(e.tailMode){case"hidden":t=e.tail;for(var n=null...
  function fo (line 12) | function fo(e,n,l){var i=n.pendingProps;switch(n.tag){case 2:case 16:cas...
  function po (line 12) | function po(e){switch(e.tag){case 1:zl(e.type)&&Ml();var t=e.effectTag;r...
  function mo (line 12) | function mo(e,t){return{value:e,source:t,stack:be(t)}}
    method constructor (line 49) | constructor(e){super(),Je(this,e,po,fo,d,{clientManager:0},oo)}
  function go (line 12) | function go(e,t){var n=t.source,r=t.stack;null===r&&null!==n&&(r=be(n)),...
  function vo (line 12) | function vo(e,t){try{t.props=e.memoizedProps,t.state=e.memoizedState,t.c...
  function yo (line 12) | function yo(e){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(nul...
  function bo (line 12) | function bo(e,t){switch(t.tag){case 0:case 11:case 15:case 22:return;cas...
  function wo (line 12) | function wo(e,t){if(null!==(t=null!==(t=t.updateQueue)?t.lastEffect:null...
  function ko (line 12) | function ko(e,t){if(null!==(t=null!==(t=t.updateQueue)?t.lastEffect:null...
  function xo (line 12) | function xo(e,t,n){switch(n.tag){case 0:case 11:case 15:case 22:return v...
  function To (line 12) | function To(e,t,n){switch("function"==typeof Xu&&Xu(t),t.tag){case 0:cas...
  function Eo (line 12) | function Eo(e){var t=e.alternate;e.return=null,e.child=null,e.memoizedSt...
  function So (line 12) | function So(e){return 5===e.tag||3===e.tag||4===e.tag}
  function Co (line 12) | function Co(e){e:{for(var t=e.return;null!==t;){if(So(t)){var n=t;break ...
  function Po (line 12) | function Po(e,t,n){var r=e.tag,l=5===r||6===r;if(l)e=l?e.stateNode:e.sta...
  function _o (line 12) | function _o(e,t,n){var r=e.tag,l=5===r||6===r;if(l)e=l?e.stateNode:e.sta...
  function No (line 12) | function No(e,t,n){for(var l,i,a=t,o=!1;;){if(!o){o=a.return;e:for(;;){i...
  function zo (line 12) | function zo(e,t){switch(t.tag){case 0:case 11:case 14:case 15:case 22:re...
  function Mo (line 12) | function Mo(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n...
  function Fo (line 12) | function Fo(e,t,n){(n=xi(n,null)).tag=3,n.payload={element:null};var r=t...
  function Oo (line 12) | function Oo(e,t,n){(n=xi(n,null)).tag=3;var r=e.type.getDerivedStateFrom...
  function bu (line 12) | function bu(){return(Yo&(Qo|Wo))!==Ao?1073741821-(ei()/10|0):0!==yu?yu:y...
  function wu (line 12) | function wu(e,t,n){if(0==(2&(t=t.mode)))return 1073741823;var l=ti();if(...
  function ku (line 12) | function ku(e,t){if(50<gu)throw gu=0,vu=null,Error(r(185));if(null!==(e=...
  function xu (line 12) | function xu(e,t){e.expirationTime<t&&(e.expirationTime=t);var n=e.altern...
  function Tu (line 12) | function Tu(e){var t=e.lastExpiredTime;if(0!==t)return t;if(!uc(e,t=e.fi...
  function Eu (line 12) | function Eu(e){if(0!==e.lastExpiredTime)e.callbackExpirationTime=1073741...
  function Su (line 12) | function Su(e,t){if(yu=0,t)return fc(e,t=bu()),Eu(e),null;var n=Tu(e);if...
  function Cu (line 12) | function Cu(e){var t=e.lastExpiredTime;if(t=0!==t?t:1073741823,(Yo&(Qo|W...
  function Pu (line 12) | function Pu(){if(null!==hu){var e=hu;hu=null,e.forEach(function(e,t){fc(...
  function _u (line 12) | function _u(e,t){var n=Yo;Yo|=1;try{return e(t)}finally{(Yo=n)===Ao&&ai()}}
  function Nu (line 12) | function Nu(e,t){var n=Yo;Yo&=-2,Yo|=Vo;try{return e(t)}finally{(Yo=n)==...
  function zu (line 12) | function zu(e,t){e.finishedWork=null,e.finishedExpirationTime=0;var n=e....
  function Mu (line 12) | function Mu(e,t){for(;;){try{if(mi(),Ji.current=za,ia)for(var n=na.memoi...
  function Iu (line 12) | function Iu(){var e=Lo.current;return Lo.current=za,null===e?za:e}
  function Fu (line 12) | function Fu(e,t){e<tu&&2<e&&(tu=e),null!==t&&e<nu&&2<e&&(nu=e,ru=t)}
  function Ou (line 12) | function Ou(e){e>lu&&(lu=e)}
  function Ru (line 12) | function Ru(){for(;null!==Go;)Go=Lu(Go)}
  function Du (line 12) | function Du(){for(;null!==Go&&!ql();)Go=Lu(Go)}
  function Lu (line 12) | function Lu(e){var t=Ro(e.alternate,e,Zo);return e.memoizedProps=e.pendi...
  function Uu (line 12) | function Uu(e){Go=e;do{var t=Go.alternate;if(e=Go.return,0==(2048&Go.eff...
  function Au (line 12) | function Au(e){var t=e.expirationTime;return t>(e=e.childExpirationTime)...
  function Vu (line 12) | function Vu(e){var t=ti();return ri(99,Qu.bind(null,e,t)),null}
  function Qu (line 12) | function Qu(e,t){do{Hu()}while(null!==pu);if((Yo&(Qo|Wo))!==Ao)throw Err...
  function Wu (line 12) | function Wu(){for(;null!==uu;){var e=uu.effectTag;0!=(256&e)&&bo(uu.alte...
  function Hu (line 12) | function Hu(){if(90!==mu){var e=97<mu?97:mu;return mu=90,ri(e,ju)}}
  function ju (line 12) | function ju(){if(null===pu)return!1;var e=pu;if(pu=null,(Yo&(Qo|Wo))!==A...
  function Bu (line 12) | function Bu(e,t,n){Ti(e,t=Fo(e,t=mo(n,t),1073741823)),null!==(e=xu(e,107...
  function Ku (line 12) | function Ku(e,t){if(3===e.tag)Bu(e,e,t);else for(var n=e.return;null!==n...
  function $u (line 12) | function $u(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),Xo===e&&Zo===...
  function qu (line 12) | function qu(e,t){var n=e.stateNode;null!==n&&n.delete(t),0===(t=0)&&(t=w...
  function Gu (line 12) | function Gu(e){if("undefined"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)ret...
  function Zu (line 12) | function Zu(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this....
  function Ju (line 12) | function Ju(e,t,n,r){return new Zu(e,t,n,r)}
  function ec (line 12) | function ec(e){return!(!(e=e.prototype)||!e.isReactComponent)}
  function tc (line 12) | function tc(e){if("function"==typeof e)return ec(e)?1:0;if(null!=e){if((...
  function nc (line 12) | function nc(e,t){var n=e.alternate;return null===n?((n=Ju(e.tag,t,e.key,...
  function rc (line 12) | function rc(e,t,n,l,i,a){var o=2;if(l=e,"function"==typeof e)ec(e)&&(o=1...
  function lc (line 12) | function lc(e,t,n,r){return(e=Ju(7,e,r,t)).expirationTime=n,e}
  function ic (line 12) | function ic(e,t,n){return(e=Ju(6,e,null,t)).expirationTime=n,e}
  function ac (line 12) | function ac(e,t,n){return(t=Ju(4,null!==e.children?e.children:[],e.key,t...
  function oc (line 12) | function oc(e,t,n){this.tag=t,this.current=null,this.containerInfo=e,thi...
  function uc (line 12) | function uc(e,t){var n=e.firstSuspendedTime;return e=e.lastSuspendedTime...
  function cc (line 12) | function cc(e,t){var n=e.firstSuspendedTime,r=e.lastSuspendedTime;n<t&&(...
  function sc (line 12) | function sc(e,t){t>e.firstPendingTime&&(e.firstPendingTime=t);var n=e.fi...
  function fc (line 12) | function fc(e,t){var n=e.lastExpiredTime;(0===n||n>t)&&(e.lastExpiredTim...
  function dc (line 12) | function dc(e,t,n,l){var i=t.current,a=bu(),o=Pi.suspense;a=wu(a,i,o);e:...
  function pc (line 12) | function pc(e){if(!(e=e.current).child)return null;switch(e.child.tag){c...
  function mc (line 12) | function mc(e,t){null!==(e=e.memoizedState)&&null!==e.dehydrated&&e.retr...
  function hc (line 12) | function hc(e,t){mc(e,t),(e=e.alternate)&&mc(e,t)}
  function gc (line 12) | function gc(e,t,n){var r=new oc(e,t,n=null!=n&&!0===n.hydrate),l=Ju(3,nu...
  function vc (line 12) | function vc(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeTy...
  function yc (line 12) | function yc(e,t){if(t||(t=!(!(t=e?9===e.nodeType?e.documentElement:e.fir...
  function bc (line 12) | function bc(e,t,n,r,l){var i=n._reactRootContainer;if(i){var a=i._intern...
  function wc (line 12) | function wc(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?argum...
  function kc (line 12) | function kc(e,t){var n=2<arguments.length&&void 0!==arguments[2]?argumen...
  function _ (line 14) | function _(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"fun...
  function e (line 18) | function e(e){for(var t=arguments.length,r=Array(t>1?t-1:0),n=1;n<t;n++)...
  function t (line 18) | function t(e){return!!e&&!!e[Q]}
    method constructor (line 20) | constructor(t){const e=s();this.c=1,this.s0=e(" "),this.s1=e(" "),this...
    method next (line 20) | next(){const t=2091639*this.s0+2.3283064365386963e-10*this.c;return th...
    method constructor (line 59) | constructor({transportDataCallback:t,gameName:a,playerID:s,matchID:e,c...
    method subscribeToConnectionStatus (line 59) | subscribeToConnectionStatus(t){this.connectionStatusCallback=t}
    method setConnectionStatus (line 59) | setConnectionStatus(t){this.isConnected=t,this.connectionStatusCallbac...
    method notifyClient (line 59) | notifyClient(t){this.transportDataCallback(t)}
    method on (line 168) | on(e,t){return super.on(e,t),this}
    method once (line 168) | once(e,t){return super.once(e,t),this}
    method emit (line 168) | emit(e,...t){return super.emit(e,...t),this}
    method emitReserved (line 168) | emitReserved(e,...t){return super.emit(e,...t),this}
    method listeners (line 168) | listeners(e){return super.listeners(e)}
  function r (line 18) | function r(e){return!!e&&(function(e){if(!e||"object"!=typeof e)return!1...
    method constructor (line 120) | constructor(e){super(),this.opts=e,this.query=e.query,this.readyState=...
    method onError (line 120) | onError(e,t){const s=new Error(e);return s.type="TransportError",s.des...
    method open (line 120) | open(){return"closed"!==this.readyState&&""!==this.readyState||(this.r...
    method close (line 120) | close(){return"opening"!==this.readyState&&"open"!==this.readyState||(...
    method send (line 120) | send(e){"open"===this.readyState?this.write(e):s("transport is not ope...
    method onOpen (line 120) | onOpen(){this.readyState="open",this.writable=!0,this.emit("open")}
    method onData (line 120) | onData(t){const s=e.decodePacket(t,this.socket.binaryType);this.onPack...
    method onPacket (line 120) | onPacket(e){this.emit("packet",e)}
    method onClose (line 120) | onClose(){this.readyState="closed",this.emit("close")}
    method constructor (line 174) | constructor(e,t){super(),this.nsps={},this.subs=[],e&&"object"==typeof...
    method reconnection (line 174) | reconnection(e){return arguments.length?(this._reconnection=!!e,this):...
    method reconnectionAttempts (line 174) | reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(...
    method reconnectionDelay (line 174) | reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(...
    method randomizationFactor (line 174) | randomizationFactor(e){var t;return void 0===e?this._randomizationFact...
    method reconnectionDelayMax (line 174) | reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDela...
    method timeout (line 174) | timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}
    method maybeReconnectOnOpen (line 174) | maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===th...
    method open (line 174) | open(t){if(c("readyState %s",this._readyState),~this._readyState.index...
    method connect (line 174) | connect(e){return this.open(e)}
    method onopen (line 174) | onopen(){c("open"),this.cleanup(),this._readyState="open",this.emitRes...
    method onping (line 174) | onping(){this.emitReserved("ping")}
    method ondata (line 174) | ondata(e){this.decoder.add(e)}
    method ondecoded (line 174) | ondecoded(e){this.emitReserved("packet",e)}
    method onerror (line 174) | onerror(e){c("error",e),this.emitReserved("error",e)}
    method socket (line 174) | socket(e,n){let i=this.nsps[e];return i||(i=new t.Socket(this,e,n),thi...
    method _destroy (line 174) | _destroy(e){const t=Object.keys(this.nsps);for(const n of t){if(this.n...
    method _packet (line 174) | _packet(e){c("writing packet %j",e);const t=this.encoder.encode(e);for...
    method cleanup (line 174) | cleanup(){c("cleanup"),this.subs.forEach(e=>e()),this.subs.length=0,th...
    method _close (line 174) | _close(){c("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,"...
    method disconnect (line 174) | disconnect(){return this._close()}
    method onclose (line 174) | onclose(e){c("onclose"),this.cleanup(),this.backoff.reset(),this._read...
    method reconnect (line 174) | reconnect(){if(this._reconnecting||this.skipReconnect)return this;cons...
    method onreconnect (line 174) | onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this...
    method constructor (line 178) | constructor(){super(),this.state=new Map,this.initial=new Map,this.met...
    method createMatch (line 178) | createMatch(t,e){this.initial.set(t,e.initialState),this.setState(t,e....
    method setMetadata (line 178) | setMetadata(t,e){this.metadata.set(t,e)}
    method setState (line 178) | setState(t,e,s){if(s&&s.length>0){const e=this.log.get(t)||[];this.log...
    method fetch (line 178) | fetch(t,e){const s={};return e.state&&(s.state=this.state.get(t)),e.me...
    method wipe (line 178) | wipe(t){this.state.delete(t),this.metadata.delete(t)}
    method listMatches (line 178) | listMatches(t){return[...this.metadata.entries()].filter(([,e])=>{if(!...
  function n (line 18) | function n(r){return t(r)||e(23,r),r[Q].t}
    method constructor (line 20) | constructor(t){this.state=t||{seed:"0"},this.used=!1}
    method seed (line 20) | static seed(){return Date.now().toString(36).slice(-10)}
    method isUsed (line 20) | isUsed(){return this.used}
    method getState (line 20) | getState(){return this.state}
    method _random (line 20) | _random(){this.used=!0;const t=this.state,s=r(t.prngstate?"":t.seed,t....
    method api (line 20) | api(){const t=this._random.bind(this),s={D4:4,D6:6,D8:8,D10:10,D12:12,...
    method play (line 47) | play({G:t,ctx:e},r){const a=this.enumerate(t,e,r);return Promise.resol...
    method constructor (line 63) | constructor({server:e=""}={}){this.server=e.replace(/\/$/,"")}
    method request (line 63) | async request(e,t){const s=await fetch(this.server+e,t);if(!s.ok){let ...
    method post (line 63) | async post(e,t){let s={method:"post",body:JSON.stringify(t.body),heade...
    method listGames (line 63) | async listGames(e){return this.request("/games",e)}
    method listMatches (line 63) | async listMatches(e,s,r){t(e);let a="";if(s){const e=[],{isGameover:t,...
    method getMatch (line 63) | async getMatch(e,r,a){return t(e),s(r),this.request(`/games/${e}/${r}`...
    method createMatch (line 63) | async createMatch(e,s,a){return t(e),r(s,{numPlayers:"number"}),this.p...
    method joinMatch (line 63) | async joinMatch(e,a,n,i){return t(e),s(a),r(n,{playerID:["string","und...
    method leaveMatch (line 63) | async leaveMatch(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentials...
    method updatePlayer (line 63) | async updatePlayer(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentia...
    method playAgain (line 63) | async playAgain(e,a,n,i){return t(e),s(a),r(n,{playerID:"string",crede...
    method type (line 80) | type(){return e.SYNC}
    method connect (line 80) | connect(){}
    method createMatch (line 80) | createMatch(e,t){if(this.createGame)return console.warn("The database ...
    method listMatches (line 80) | listMatches(e){if(this.listGames)return console.warn("The database con...
    method constructor (line 151) | constructor(t,e={}){super(),t&&"object"==typeof t&&(e=t,t=null),t?(t=i...
    method createTransport (line 151) | createTransport(e){s('creating transport "%s"',e);const i=a(this.opts....
    method open (line 151) | open(){let t;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1...
    method setTransport (line 151) | setTransport(t){s("setting transport %s",t.name),this.transport&&(s("c...
    method probe (line 151) | probe(t){s('probing transport "%s"',t);let e=this.createTransport(t,{p...
    method onOpen (line 151) | onOpen(){if(s("socket open"),this.readyState="open",n.priorWebsocketSu...
    method onPacket (line 151) | onPacket(t){if("opening"===this.readyState||"open"===this.readyState||...
    method onHandshake (line 151) | onHandshake(t){this.emit("handshake",t),this.id=t.sid,this.transport.q...
    method resetPingTimeout (line 151) | resetPingTimeout(){clearTimeout(this.pingTimeoutTimer),this.pingTimeou...
    method onDrain (line 151) | onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBuffe...
    method flush (line 151) | flush(){"closed"!==this.readyState&&this.transport.writable&&!this.upg...
    method write (line 151) | write(t,e,s){return this.sendPacket("message",t,e,s),this}
    method send (line 151) | send(t,e,s){return this.sendPacket("message",t,e,s),this}
    method sendPacket (line 151) | sendPacket(t,e,s,r){if("function"==typeof e&&(r=e,e=void 0),"function"...
    method close (line 151) | close(){const t=()=>{this.onClose("forced close"),s("socket closing - ...
    method onError (line 151) | onError(t){s("socket error %j",t),n.priorWebsocketSuccess=!1,this.emit...
    method onClose (line 151) | onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"c...
    method filterUpgrades (line 151) | filterUpgrades(t){const e=[];let s=0;const r=t.length;for(;s<r;s++)~th...
  function o (line 18) | function o(e,t,r){void 0===r&&(r=!1),0===i(e)?(r?Object.keys:ee)(e).forE...
    method constructor (line 82) | constructor(t,a,r,s){this.game=(0,e.P)(t),this.storageAPI=a,this.trans...
    method subscribe (line 82) | subscribe(t){this.subscribeCallback=t}
    method onUpdate (line 82) | async onUpdate(s,o,n,c){if(!s||!s.payload)return{error:"missing action...
    method onSync (line 82) | async onSync(t,a,e,i=2){const o=t,n={state:!0,metadata:!0,log:!0,initi...
    method onConnectionChange (line 82) | async onConnectionChange(t,e,i,o){const n=t;if(null==e)return;let c;if...
    method onChatMessage (line 82) | async onChatMessage(t,a,e){const r=t;if(this.auth){const{metadata:t}=a...
    method constructor (line 132) | constructor(e){super(e),this.query=this.query||{},s||(s=t.___eio=t.___...
    method supportsBinary (line 132) | get supportsBinary(){return!1}
    method doClose (line 132) | doClose(){this.script&&(this.script.onerror=(()=>{}),this.script.paren...
    method doPoll (line 132) | doPoll(){const e=document.createElement("script");this.script&&(this.s...
    method doWrite (line 132) | doWrite(e,t){let s;if(!this.form){const e=document.createElement("form...
    method constructor (line 164) | constructor(){super()}
    method add (line 164) | add(t){let e;if("string"==typeof t)(e=this.decodeString(t)).type===n.B...
    method decodeString (line 164) | decodeString(t){let e=0;const r={type:Number(t.charAt(0))};if(void 0==...
    method isPayloadValid (line 164) | static isPayloadValid(t,e){switch(t){case n.CONNECT:return"object"==ty...
    method destroy (line 164) | destroy(){this.reconstructor&&this.reconstructor.finishedReconstructio...
    method constructor (line 178) | constructor(t="bgio"){super();const e=e=>new c(`${t}_${e}`);this.state...
  function i (line 18) | function i(e){var t=e[Q];return t?t.i>3?t.i-4:t.i:Array.isArray(e)?1:s(e...
    method constructor (line 47) | constructor({enumerate:t,seed:e,objectives:a,game:s,iterations:i,playo...
    method createNode (line 47) | createNode({state:t,parentAction:e,parent:r,playerID:a}){const{G:s,ctx...
    method select (line 47) | select(t){if(t.actions.length>0)return t;if(0===t.children.length)retu...
    method expand (line 47) | expand(t){const e=t.actions;if(0===e.length||void 0!==t.state.ctx.game...
    method playout (line 47) | playout({state:t}){let e=this.getOpt("playoutDepth");"function"==typeo...
    method backpropagate (line 47) | backpropagate(t,e={}){t.visits++,void 0!==e.score&&(t.value+=e.score),...
    method play (line 47) | play(t,e){const r=this.createNode({state:t,playerID:e});let a=this.get...
  function a (line 18) | function a(e,t){return 2===i(e)?e.has(t):Object.prototype.hasOwnProperty...
    method constructor (line 47) | constructor({enumerate:t,seed:e}){this.enumerateFn=t,this.seed=e,this....
    method addOpt (line 47) | addOpt({key:t,range:e,initial:r}){this._opts[t]={range:e,value:r}}
    method getOpt (line 47) | getOpt(t){return this._opts[t].value}
    method setOpt (line 47) | setOpt(t,e){t in this._opts&&(this._opts[t].value=e)}
    method opts (line 47) | opts(){return this._opts}
    method enumerate (line 47) | enumerate(e,r,a){return this.enumerateFn(e,r,a).map(e=>"payload"in e?e...
    method random (line 47) | random(t){let r;if(void 0!==this.seed){const t=this.prngstate?"":this....
    method constructor (line 63) | constructor(e,t){super(e),this.details=t}
    method constructor (line 130) | constructor(t){if(super(t),"undefined"!=typeof location){const e="http...
    method request (line 130) | request(t={}){return Object.assign(t,{xd:this.xd,xs:this.xs},this.opts...
    method doWrite (line 130) | doWrite(t,e){const s=this.request({method:"POST",data:t});s.on("succes...
    method doPoll (line 130) | doPoll(){i("xhr poll");const t=this.request();t.on("data",this.onData....
    method constructor (line 164) | constructor(t){this.packet=t,this.buffers=[],this.reconPack=t}
    method takeBinaryData (line 164) | takeBinaryData(t){if(this.buffers.push(t),this.buffers.length===this.r...
    method finishedReconstruction (line 164) | finishedReconstruction(){this.reconPack=null,this.buffers=[]}
  function u (line 18) | function u(e,t){return 2===i(e)?e.get(t):e[t]}
    method constructor (line 130) | constructor(t,e){super(),this.opts=e,this.method=e.method||"GET",this....
    method create (line 130) | create(){const e=o(this.opts,"agent","enablesXDR","pfx","key","passphr...
    method onSuccess (line 130) | onSuccess(){this.emit("success"),this.cleanup()}
    method onData (line 130) | onData(t){this.emit("data",t),this.onSuccess()}
    method onError (line 130) | onError(t){this.emit("error",t),this.cleanup(!0)}
    method cleanup (line 130) | cleanup(t){if(void 0!==this.xhr&&null!==this.xhr){if(this.hasXDR()?thi...
    method onLoad (line 130) | onLoad(){const t=this.xhr.responseText;null!==t&&this.onData(t)}
    method hasXDR (line 130) | hasXDR(){return"undefined"!=typeof XDomainRequest&&!this.xs&&this.enab...
    method abort (line 130) | abort(){this.cleanup()}
    method constructor (line 178) | constructor({master:t,...e}){super(e),this.master=t}
    method sendChatMessage (line 178) | sendChatMessage(t,e){const s=[t,e,this.credentials];this.master.onChat...
    method sendAction (line 178) | sendAction(t,e){this.master.onUpdate(e,t._stateID,this.matchID,this.pl...
    method requestSync (line 178) | requestSync(){this.master.onSync(this.matchID,this.playerID,this.crede...
    method connect (line 178) | connect(){this.setConnectionStatus(!0),this.master.connect(this.player...
    method disconnect (line 178) | disconnect(){this.setConnectionStatus(!1)}
    method updateMatchID (line 178) | updateMatchID(t){this.matchID=t,this.connect()}
    method updatePlayerID (line 178) | updatePlayerID(t){this.playerID=t,this.connect()}
    method updateCredentials (line 178) | updateCredentials(t){this.credentials=t,this.connect()}
    method constructor (line 180) | constructor(){super(...arguments),this.state={playerName:this.props.pl...
    method render (line 180) | render(){return s.default.createElement("div",null,s.default.createEle...
  function c (line 18) | function c(e,t,r){var n=i(e);2===n?e.set(t,r):3===n?(e.delete(t),e.add(r...
    method encode (line 164) | encode(t){return s("encoding packet %j",t),t.type!==n.EVENT&&t.type!==...
    method encodeAsString (line 164) | encodeAsString(t){let e=""+t.type;return t.type!==n.BINARY_EVENT&&t.ty...
    method encodeAsBinary (line 164) | encodeAsBinary(t){const r=e.deconstructPacket(t),s=this.encodeAsString...
    method constructor (line 170) | constructor(t,e,s){super(),this.receiveBuffer=[],this.sendBuffer=[],th...
    method subEvents (line 170) | subEvents(){if(this.subs)return;const t=this.io;this.subs=[e.on(t,"ope...
    method active (line 170) | get active(){return!!this.subs}
    method connect (line 170) | connect(){return this.connected?this:(this.subEvents(),this.io._reconn...
    method open (line 170) | open(){return this.connect()}
    method send (line 170) | send(...t){return t.unshift("message"),this.emit.apply(this,t),this}
    method emit (line 170) | emit(e,...s){if(n.hasOwnProperty(e))throw new Error('"'+e+'" is a rese...
    method packet (line 170) | packet(t){t.nsp=this.nsp,this.io._packet(t)}
    method onopen (line 170) | onopen(){i("transport is open - connecting"),"function"==typeof this.a...
    method onerror (line 170) | onerror(t){this.connected||this.emitReserved("connect_error",t)}
    method onclose (line 170) | onclose(t){i("close (%s)",t),this.connected=!1,this.disconnected=!0,de...
    method onpacket (line 170) | onpacket(e){if(e.nsp===this.nsp)switch(e.type){case t.PacketType.CONNE...
    method onevent (line 170) | onevent(t){const e=t.data||[];i("emitting event %j",e),null!=t.id&&(i(...
    method emitEvent (line 170) | emitEvent(t){if(this._anyListeners&&this._anyListeners.length){const e...
    method ack (line 170) | ack(e){const s=this;let n=!1;return function(...c){n||(n=!0,i("sending...
    method onack (line 170) | onack(t){const e=this.acks[t.id];"function"==typeof e?(i("calling ack ...
    method onconnect (line 170) | onconnect(t){i("socket connected with id %s",t),this.id=t,this.connect...
    method emitBuffered (line 170) | emitBuffered(){this.receiveBuffer.forEach(t=>this.emitEvent(t)),this.r...
    method ondisconnect (line 170) | ondisconnect(){i("server disconnect (%s)",this.nsp),this.destroy(),thi...
    method destroy (line 170) | destroy(){this.subs&&(this.subs.forEach(t=>t()),this.subs=void 0),this...
    method disconnect (line 170) | disconnect(){return this.connected&&(i("performing disconnect (%s)",th...
    method close (line 170) | close(){return this.disconnect()}
    method compress (line 170) | compress(t){return this.flags.compress=t,this}
    method volatile (line 170) | get volatile(){return this.flags.volatile=!0,this}
    method onAny (line 170) | onAny(t){return this._anyListeners=this._anyListeners||[],this._anyLis...
    method prependAny (line 170) | prependAny(t){return this._anyListeners=this._anyListeners||[],this._a...
    method offAny (line 170) | offAny(t){if(!this._anyListeners)return this;if(t){const e=this._anyLi...
    method listenersAny (line 170) | listenersAny(){return this._anyListeners||[]}
    method constructor (line 178) | constructor(t){super(),this.key=t,(JSON.parse(localStorage.getItem(thi...
    method sync (line 178) | sync(){const t=[...this.entries()];localStorage.setItem(this.key,JSON....
    method set (line 178) | set(t,e){return super.set(t,e),this.sync(),this}
    method delete (line 178) | delete(t){const e=super.delete(t);return this.sync(),e}
  function f (line 18) | function f(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t}
  function s (line 18) | function s(e){return X&&e instanceof Map}
    method type (line 80) | type(){return e.ASYNC}
    method createMatch (line 80) | async createMatch(e,t){if(this.createGame)return console.warn("The dat...
    method listMatches (line 80) | async listMatches(e){if(this.listGames)return console.warn("The databa...
  function l (line 18) | function l(e){return q&&e instanceof Set}
    method constructor (line 61) | constructor(){this.debugPanel=null,this.currentClient=null,this.client...
    method register (line 61) | register(t){this.clients.set(t,t),this.mountDebug(t),this.notifySubscr...
    method unregister (line 61) | unregister(t){if(this.clients.delete(t),this.currentClient===t){this.u...
    method subscribe (line 61) | subscribe(t){const e=Symbol();return this.subscribers.set(e,t),t(this....
    method switchPlayerID (line 61) | switchPlayerID(t){if(this.currentClient.multiplayer)for(const[e]of thi...
    method switchToClient (line 61) | switchToClient(t){t!==this.currentClient&&(this.unmountDebug(),this.mo...
    method notifySubscribers (line 61) | notifySubscribers(){const t=this.getState();this.subscribers.forEach(e...
    method getState (line 61) | getState(){return{client:this.currentClient,debuggableClients:this.get...
    method getDebuggableClients (line 61) | getDebuggableClients(){return[...this.clients.values()].filter(t=>!1!=...
    method mountDebug (line 61) | mountDebug(t){if(!1===t.debugOpt||null!==this.debugPanel||"undefined"=...
    method unmountDebug (line 61) | unmountDebug(){this.debugPanel.$destroy(),this.debugPanel=null,this.cu...
    method constructor (line 147) | constructor(e){super(e),this.supportsBinary=!e.forceBase64}
    method name (line 147) | get name(){return"websocket"}
    method doOpen (line 147) | doOpen(){if(!this.check())return;const e=this.uri(),t=this.opts.protoc...
    method addEventListeners (line 147) | addEventListeners(){this.ws.onopen=(()=>{this.opts.autoUnref&&this.ws....
    method write (line 147) | write(t){this.writable=!1;for(let r=0;r<t.length;r++){const o=t[r],i=r...
    method onClose (line 147) | onClose(){t.prototype.onClose.call(this)}
    method doClose (line 147) | doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}
    method uri (line 147) | uri(){let e=this.query||{};const t=this.opts.secure?"wss":"ws";let s="...
    method check (line 147) | check(){return!(!n||"__initialize"in n&&this.name===l.prototype.name)}
    method constructor (line 178) | constructor({game:t,bots:e,storageKey:s,persist:a}){const n={},c={};if...
  function p (line 18) | function p(e){return e.o||e.t}
    method name (line 126) | get name(){return"polling"}
    method doOpen (line 126) | doOpen(){this.poll()}
    method pause (line 126) | pause(t){this.readyState="pausing";const e=()=>{o("paused"),this.ready...
    method poll (line 126) | poll(){o("polling"),this.polling=!0,this.doPoll(),this.emit("poll")}
    method onData (line 126) | onData(t){o("polling got data %s",t);s.decodePayload(t,this.socket.bin...
    method doClose (line 126) | doClose(){const t=()=>{o("writing close packet"),this.write([{type:"cl...
    method write (line 126) | write(t){this.writable=!1,s.encodePayload(t,t=>{this.doWrite(t,()=>{th...
    method uri (line 126) | uri(){let t=this.query||{};const s=this.opts.secure?"https":"http";let...
    method constructor (line 180) | constructor(){super(...arguments),this._createSeat=(e=>e.name||"[free]...
    method render (line 180) | render(){const e=this.props.match;let t="OPEN";return e.players.some(e...
  function h (line 18) | function h(e){if(Array.isArray(e))return Array.prototype.slice.call(e);v...
    method connect (line 61) | connect(){}
    method disconnect (line 61) | disconnect(){}
    method sendAction (line 61) | sendAction(){}
    method sendChatMessage (line 61) | sendChatMessage(){}
    method requestSync (line 61) | requestSync(){}
    method updateCredentials (line 61) | updateCredentials(){}
    method updateMatchID (line 61) | updateMatchID(){}
    method updatePlayerID (line 61) | updatePlayerID(){}
    method constructor (line 180) | constructor({server:e,gameComponents:t,playerName:s,playerCredentials:...
    method refresh (line 180) | async refresh(){try{this.matches=[];const t=await this.client.listGame...
    method _getMatchInstance (line 180) | _getMatchInstance(e){for(const t of this.matches)if(t.matchID===e)retu...
    method _getGameComponents (line 180) | _getGameComponents(e){for(const t of this.gameComponents)if(t.game.nam...
    method _findPlayer (line 180) | _findPlayer(e){for(const t of this.matches)if(t.players.some(t=>t.name...
    method join (line 180) | async join(e,t,a){try{let r=this._findPlayer(this.playerName);if(r)thr...
    method leave (line 180) | async leave(e,t){try{const s=this._getMatchInstance(t);if(!s)throw new...
    method disconnect (line 180) | async disconnect(){const e=this._findPlayer(this.playerName);e&&await ...
    method create (line 180) | async create(e,t){try{const s=this._getGameComponents(e);if(!s)throw n...
  function v (line 18) | function v(e,n){return void 0===n&&(n=!1),y(e)||t(e)||!r(e)?e:(i(e)>1&&(...
  function d (line 18) | function d(){e(2)}
    method constructor (line 180) | constructor(e){super(e),this.state={selectedGame:0,numPlayers:2},this....
    method render (line 180) | render(){return s.default.createElement("div",null,s.default.createEle...
  function y (line 18) | function y(e){return null==e||"object"!=typeof e||Object.isFrozen(e)}
    method constructor (line 178) | constructor({socket:t,socketOpts:e,server:s,...i}){super(i),this.serve...
    method sendAction (line 178) | sendAction(t,e){const s=[e,t._stateID,this.matchID,this.playerID];this...
    method sendChatMessage (line 178) | sendChatMessage(t,e){const s=[t,e,this.credentials];this.socket.emit("...
    method connect (line 178) | connect(){if(!this.socket)if(this.server){let t=this.server;-1==t.sear...
    method disconnect (line 178) | disconnect(){this.socket.close(),this.socket=null,this.setConnectionSt...
    method requestSync (line 178) | requestSync(){if(this.socket){const t=[this.matchID,this.playerID,this...
    method updateMatchID (line 178) | updateMatchID(t){this.matchID=t,this.requestSync()}
    method updatePlayerID (line 178) | updatePlayerID(t){this.playerID=t,this.requestSync()}
    method updateCredentials (line 178) | updateCredentials(t){this.credentials=t,this.requestSync()}
    method constructor (line 180) | constructor(e){super(e),this.state={phase:i.ENTER,playerName:"Visitor"...
    method componentDidMount (line 180) | componentDidMount(){const e=n.default.load("lobbyState")||{};e.phase&&...
    method componentDidUpdate (line 180) | componentDidUpdate(e,t){const a=this.state.playerName,s=this.state.cre...
    method componentWillUnmount (line 180) | componentWillUnmount(){this._clearRefreshInterval()}
    method _startRefreshInterval (line 180) | _startRefreshInterval(){this._clearRefreshInterval(),this._currentInte...
    method _clearRefreshInterval (line 180) | _clearRefreshInterval(){clearInterval(this._currentInterval)}
    method render (line 180) | render(){const{gameComponents:e,renderer:t}=this.props,{errorMsg:a,pla...
  function b (line 18) | function b(t){var r=re[t];return r||e(18,t),r}
    method constructor (line 24) | constructor(e,t,r){this.flow=e,this.playerID=r,this.dispatch=[],this.i...
    method api (line 24) | api(){const e={_private:this};for(const t of this.flow.eventNames)e[t]...
    method isUsed (line 24) | isUsed(){return this.dispatch.length>0}
    method updateTurnContext (line 24) | updateTurnContext(e,t){this.currentPhase=e.phase,this.currentTurn=e.tu...
    method unsetCurrentMethod (line 24) | unsetCurrentMethod(){this.currentMethod=void 0}
    method update (line 24) | update(e){const t=e,r=({stack:e},r)=>({...t,plugins:{...t.plugins,even...
  function g (line 18) | function g(e,t){re[e]||(re[e]=t)}
  function m (line 18) | function m(){return J}
    method constructor (line 61) | constructor({game:e,debug:n,numPlayers:h,multiplayer:l,matchID:g,playe...
    method receiveMatchData (line 61) | receiveMatchData(t){this.matchData=t,this.notifySubscribers()}
    method receiveChatMessage (line 61) | receiveChatMessage(t){this.chatMessages=[...this.chatMessages,t],this....
    method receiveTransportData (line 61) | receiveTransportData(t){const[e]=t.args;if(e===this.matchID)switch(t.t...
    method notifySubscribers (line 61) | notifySubscribers(){Object.values(this.subscribers).forEach(t=>t(this....
    method overrideGameState (line 61) | overrideGameState(t){this.gameStateOverride=t,this.notifySubscribers()}
    method start (line 61) | start(){this.transport.connect(),this._running=!0,this.manager.registe...
    method stop (line 61) | stop(){this.transport.disconnect(),this._running=!1,this.manager.unreg...
    method subscribe (line 61) | subscribe(t){const e=Object.keys(this.subscribers).length;return this....
    method getInitialState (line 61) | getInitialState(){return this.initialState}
    method getState (line 61) | getState(){let t=this.store.getState();if(null!==this.gameStateOverrid...
    method createDispatchers (line 61) | createDispatchers(){this.moves=b(this.game.moveNames,this.store,this.p...
    method updatePlayerID (line 61) | updatePlayerID(t){this.playerID=t,this.createDispatchers(),this.transp...
    method updateMatchID (line 61) | updateMatchID(t){this.matchID=t,this.createDispatchers(),this.transpor...
    method updateCredentials (line 61) | updateCredentials(t){this.credentials=t,this.createDispatchers(),this....
  function P (line 18) | function P(e,t){t&&(b("Patches"),e.u=[],e.s=[],e.v=t)}
  function O (line 18) | function O(e){x(e),e.p.forEach(j),e.p=null}
  function x (line 18) | function x(e){e===J&&(J=e.l)}
  function w (line 18) | function w(e){return J={p:[],l:J,h:e,m:!0,_:0}}
  function j (line 18) | function j(e){var t=e[Q];0===t.i||1===t.i?t.j():t.O=!0}
  function A (line 18) | function A(t,n){n._=n.p.length;var o=n.p[0],i=void 0!==t&&t!==o;return n...
  function D (line 18) | function D(e,t,r){if(y(t))return t;var n=t[Q];if(!n)return o(t,function(...
  function S (line 18) | function S(e,n,o,i,u,f){if(t(u)){var s=D(e,u,f&&n&&3!==n.i&&!a(n.D,i)?f....
  function _ (line 18) | function _(e,t,r){void 0===r&&(r=!1),e.h.F&&e.m&&v(t,r)}
  function k (line 18) | function k(e,t){var r=e[Q];return(r?p(r):e)[t]}
  function I (line 18) | function I(e,t){if(t in e)for(var r=Object.getPrototypeOf(e);r;){var n=O...
  function z (line 18) | function z(e){e.P||(e.P=!0,e.l&&z(e.l))}
  function E (line 18) | function E(e){e.o||(e.o=h(e.t))}
  function M (line 18) | function M(e,t,r){var n=s(t)?b("MapSet").N(t,r):l(t)?b("MapSet").T(t,r):...
  function F (line 18) | function F(n){return t(n)||e(22,n),function e(t){if(!r(t))return t;var n...
  function R (line 18) | function R(e,t){switch(t){case 2:return new Map(e);case 3:return Array.f...
  function C (line 18) | function C(){function e(e,t){var r=u[e];return r?r.enumerable=t:u[e]=r={...
  function T (line 18) | function T(){function n(e){if(!r(e))return e;if(Array.isArray(e))return ...
  function K (line 18) | function K(){function t(e,t){function r(){this.constructor=e}u(e,t),e.pr...
  function U (line 18) | function U(){C(),K(),T()}
  function W (line 18) | function W(e){return e}
  function N (line 18) | function N(e){return e}
  function n (line 18) | function n(t){var n=this;this.g=B,this.F=!0,this.produce=function(t,o,i)...
    method constructor (line 20) | constructor(t){this.state=t||{seed:"0"},this.used=!1}
    method seed (line 20) | static seed(){return Date.now().toString(36).slice(-10)}
    method isUsed (line 20) | isUsed(){return this.used}
    method getState (line 20) | getState(){return this.state}
    method _random (line 20) | _random(){this.used=!0;const t=this.state,s=r(t.prngstate?"":t.seed,t....
    method api (line 20) | api(){const t=this._random.bind(this),s={D4:4,D6:6,D8:8,D10:10,D12:12,...
    method play (line 47) | play({G:t,ctx:e},r){const a=this.enumerate(t,e,r);return Promise.resol...
    method constructor (line 63) | constructor({server:e=""}={}){this.server=e.replace(/\/$/,"")}
    method request (line 63) | async request(e,t){const s=await fetch(this.server+e,t);if(!s.ok){let ...
    method post (line 63) | async post(e,t){let s={method:"post",body:JSON.stringify(t.body),heade...
    method listGames (line 63) | async listGames(e){return this.request("/games",e)}
    method listMatches (line 63) | async listMatches(e,s,r){t(e);let a="";if(s){const e=[],{isGameover:t,...
    method getMatch (line 63) | async getMatch(e,r,a){return t(e),s(r),this.request(`/games/${e}/${r}`...
    method createMatch (line 63) | async createMatch(e,s,a){return t(e),r(s,{numPlayers:"number"}),this.p...
    method joinMatch (line 63) | async joinMatch(e,a,n,i){return t(e),s(a),r(n,{playerID:["string","und...
    method leaveMatch (line 63) | async leaveMatch(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentials...
    method updatePlayer (line 63) | async updatePlayer(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentia...
    method playAgain (line 63) | async playAgain(e,a,n,i){return t(e),s(a),r(n,{playerID:"string",crede...
    method type (line 80) | type(){return e.SYNC}
    method connect (line 80) | connect(){}
    method createMatch (line 80) | createMatch(e,t){if(this.createGame)return console.warn("The database ...
    method listMatches (line 80) | listMatches(e){if(this.listGames)return console.warn("The database con...
    method constructor (line 151) | constructor(t,e={}){super(),t&&"object"==typeof t&&(e=t,t=null),t?(t=i...
    method createTransport (line 151) | createTransport(e){s('creating transport "%s"',e);const i=a(this.opts....
    method open (line 151) | open(){let t;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1...
    method setTransport (line 151) | setTransport(t){s("setting transport %s",t.name),this.transport&&(s("c...
    method probe (line 151) | probe(t){s('probing transport "%s"',t);let e=this.createTransport(t,{p...
    method onOpen (line 151) | onOpen(){if(s("socket open"),this.readyState="open",n.priorWebsocketSu...
    method onPacket (line 151) | onPacket(t){if("opening"===this.readyState||"open"===this.readyState||...
    method onHandshake (line 151) | onHandshake(t){this.emit("handshake",t),this.id=t.sid,this.transport.q...
    method resetPingTimeout (line 151) | resetPingTimeout(){clearTimeout(this.pingTimeoutTimer),this.pingTimeou...
    method onDrain (line 151) | onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBuffe...
    method flush (line 151) | flush(){"closed"!==this.readyState&&this.transport.writable&&!this.upg...
    method write (line 151) | write(t,e,s){return this.sendPacket("message",t,e,s),this}
    method send (line 151) | send(t,e,s){return this.sendPacket("message",t,e,s),this}
    method sendPacket (line 151) | sendPacket(t,e,s,r){if("function"==typeof e&&(r=e,e=void 0),"function"...
    method close (line 151) | close(){const t=()=>{this.onClose("forced close"),s("socket closing - ...
    method onError (line 151) | onError(t){s("socket error %j",t),n.priorWebsocketSuccess=!1,this.emit...
    method onClose (line 151) | onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"c...
    method filterUpgrades (line 151) | filterUpgrades(t){const e=[];let s=0;const r=t.length;for(;s<r;s++)~th...
  class t (line 20) | class t{constructor(t){const e=s();this.c=1,this.s0=e(" "),this.s1=e(" "...
    method constructor (line 20) | constructor(t){const e=s();this.c=1,this.s0=e(" "),this.s1=e(" "),this...
    method next (line 20) | next(){const t=2091639*this.s0+2.3283064365386963e-10*this.c;return th...
    method constructor (line 59) | constructor({transportDataCallback:t,gameName:a,playerID:s,matchID:e,c...
    method subscribeToConnectionStatus (line 59) | subscribeToConnectionStatus(t){this.connectionStatusCallback=t}
    method setConnectionStatus (line 59) | setConnectionStatus(t){this.isConnected=t,this.connectionStatusCallbac...
    method notifyClient (line 59) | notifyClient(t){this.transportDataCallback(t)}
    method on (line 168) | on(e,t){return super.on(e,t),this}
    method once (line 168) | once(e,t){return super.once(e,t),this}
    method emit (line 168) | emit(e,...t){return super.emit(e,...t),this}
    method emitReserved (line 168) | emitReserved(e,...t){return super.emit(e,...t),this}
    method listeners (line 168) | listeners(e){return super.listeners(e)}
  function s (line 20) | function s(){let t=4022871197;return function(s){const e=s.toString();fo...
    method type (line 80) | type(){return e.ASYNC}
    method createMatch (line 80) | async createMatch(e,t){if(this.createGame)return console.warn("The dat...
    method listMatches (line 80) | async listMatches(e){if(this.listGames)return console.warn("The databa...
  function e (line 20) | function e(t,s){return s.c=t.c,s.s0=t.s0,s.s1=t.s1,s.s2=t.s2,s}
  function r (line 20) | function r(s,r){const n=new t(s),i=n.next.bind(n);return r&&e(r,n),i.sta...
    method constructor (line 120) | constructor(e){super(),this.opts=e,this.query=e.query,this.readyState=...
    method onError (line 120) | onError(e,t){const s=new Error(e);return s.type="TransportError",s.des...
    method open (line 120) | open(){return"closed"!==this.readyState&&""!==this.readyState||(this.r...
    method close (line 120) | close(){return"opening"!==this.readyState&&"open"!==this.readyState||(...
    method send (line 120) | send(e){"open"===this.readyState?this.write(e):s("transport is not ope...
    method onOpen (line 120) | onOpen(){this.readyState="open",this.writable=!0,this.emit("open")}
    method onData (line 120) | onData(t){const s=e.decodePacket(t,this.socket.binaryType);this.onPack...
    method onPacket (line 120) | onPacket(e){this.emit("packet",e)}
    method onClose (line 120) | onClose(){this.readyState="closed",this.emit("close")}
    method constructor (line 174) | constructor(e,t){super(),this.nsps={},this.subs=[],e&&"object"==typeof...
    method reconnection (line 174) | reconnection(e){return arguments.length?(this._reconnection=!!e,this):...
    method reconnectionAttempts (line 174) | reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(...
    method reconnectionDelay (line 174) | reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(...
    method randomizationFactor (line 174) | randomizationFactor(e){var t;return void 0===e?this._randomizationFact...
    method reconnectionDelayMax (line 174) | reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDela...
    method timeout (line 174) | timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}
    method maybeReconnectOnOpen (line 174) | maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===th...
    method open (line 174) | open(t){if(c("readyState %s",this._readyState),~this._readyState.index...
    method connect (line 174) | connect(e){return this.open(e)}
    method onopen (line 174) | onopen(){c("open"),this.cleanup(),this._readyState="open",this.emitRes...
    method onping (line 174) | onping(){this.emitReserved("ping")}
    method ondata (line 174) | ondata(e){this.decoder.add(e)}
    method ondecoded (line 174) | ondecoded(e){this.emitReserved("packet",e)}
    method onerror (line 174) | onerror(e){c("error",e),this.emitReserved("error",e)}
    method socket (line 174) | socket(e,n){let i=this.nsps[e];return i||(i=new t.Socket(this,e,n),thi...
    method _destroy (line 174) | _destroy(e){const t=Object.keys(this.nsps);for(const n of t){if(this.n...
    method _packet (line 174) | _packet(e){c("writing packet %j",e);const t=this.encoder.encode(e);for...
    method cleanup (line 174) | cleanup(){c("cleanup"),this.subs.forEach(e=>e()),this.subs.length=0,th...
    method _close (line 174) | _close(){c("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,"...
    method disconnect (line 174) | disconnect(){return this._close()}
    method onclose (line 174) | onclose(e){c("onclose"),this.cleanup(),this.backoff.reset(),this._read...
    method reconnect (line 174) | reconnect(){if(this._reconnecting||this.skipReconnect)return this;cons...
    method onreconnect (line 174) | onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this...
    method constructor (line 178) | constructor(){super(),this.state=new Map,this.initial=new Map,this.met...
    method createMatch (line 178) | createMatch(t,e){this.initial.set(t,e.initialState),this.setState(t,e....
    method setMetadata (line 178) | setMetadata(t,e){this.metadata.set(t,e)}
    method setState (line 178) | setState(t,e,s){if(s&&s.length>0){const e=this.log.get(t)||[];this.log...
    method fetch (line 178) | fetch(t,e){const s={};return e.state&&(s.state=this.state.get(t)),e.me...
    method wipe (line 178) | wipe(t){this.state.delete(t),this.metadata.delete(t)}
    method listMatches (line 178) | listMatches(t){return[...this.metadata.entries()].filter(([,e])=>{if(!...
  class n (line 20) | class n{constructor(t){this.state=t||{seed:"0"},this.used=!1}static seed...
    method constructor (line 20) | constructor(t){this.state=t||{seed:"0"},this.used=!1}
    method seed (line 20) | static seed(){return Date.now().toString(36).slice(-10)}
    method isUsed (line 20) | isUsed(){return this.used}
    method getState (line 20) | getState(){return this.state}
    method _random (line 20) | _random(){this.used=!0;const t=this.state,s=r(t.prngstate?"":t.seed,t....
    method api (line 20) | api(){const t=this._random.bind(this),s={D4:4,D6:6,D8:8,D10:10,D12:12,...
    method play (line 47) | play({G:t,ctx:e},r){const a=this.enumerate(t,e,r);return Promise.resol...
    method constructor (line 63) | constructor({server:e=""}={}){this.server=e.replace(/\/$/,"")}
    method request (line 63) | async request(e,t){const s=await fetch(this.server+e,t);if(!s.ok){let ...
    method post (line 63) | async post(e,t){let s={method:"post",body:JSON.stringify(t.body),heade...
    method listGames (line 63) | async listGames(e){return this.request("/games",e)}
    method listMatches (line 63) | async listMatches(e,s,r){t(e);let a="";if(s){const e=[],{isGameover:t,...
    method getMatch (line 63) | async getMatch(e,r,a){return t(e),s(r),this.request(`/games/${e}/${r}`...
    method createMatch (line 63) | async createMatch(e,s,a){return t(e),r(s,{numPlayers:"number"}),this.p...
    method joinMatch (line 63) | async joinMatch(e,a,n,i){return t(e),s(a),r(n,{playerID:["string","und...
    method leaveMatch (line 63) | async leaveMatch(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentials...
    method updatePlayer (line 63) | async updatePlayer(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentia...
    method playAgain (line 63) | async playAgain(e,a,n,i){return t(e),s(a),r(n,{playerID:"string",crede...
    method type (line 80) | type(){return e.SYNC}
    method connect (line 80) | connect(){}
    method createMatch (line 80) | createMatch(e,t){if(this.createGame)return console.warn("The database ...
    method listMatches (line 80) | listMatches(e){if(this.listGames)return console.warn("The database con...
    method constructor (line 151) | constructor(t,e={}){super(),t&&"object"==typeof t&&(e=t,t=null),t?(t=i...
    method createTransport (line 151) | createTransport(e){s('creating transport "%s"',e);const i=a(this.opts....
    method open (line 151) | open(){let t;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1...
    method setTransport (line 151) | setTransport(t){s("setting transport %s",t.name),this.transport&&(s("c...
    method probe (line 151) | probe(t){s('probing transport "%s"',t);let e=this.createTransport(t,{p...
    method onOpen (line 151) | onOpen(){if(s("socket open"),this.readyState="open",n.priorWebsocketSu...
    method onPacket (line 151) | onPacket(t){if("opening"===this.readyState||"open"===this.readyState||...
    method onHandshake (line 151) | onHandshake(t){this.emit("handshake",t),this.id=t.sid,this.transport.q...
    method resetPingTimeout (line 151) | resetPingTimeout(){clearTimeout(this.pingTimeoutTimer),this.pingTimeou...
    method onDrain (line 151) | onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBuffe...
    method flush (line 151) | flush(){"closed"!==this.readyState&&this.transport.writable&&!this.upg...
    method write (line 151) | write(t,e,s){return this.sendPacket("message",t,e,s),this}
    method send (line 151) | send(t,e,s){return this.sendPacket("message",t,e,s),this}
    method sendPacket (line 151) | sendPacket(t,e,s,r){if("function"==typeof e&&(r=e,e=void 0),"function"...
    method close (line 151) | close(){const t=()=>{this.onClose("forced close"),s("socket closing - ...
    method onError (line 151) | onError(t){s("socket error %j",t),n.priorWebsocketSuccess=!1,this.emit...
    method onClose (line 151) | onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"c...
    method filterUpgrades (line 151) | filterUpgrades(t){const e=[];let s=0;const r=t.length;for(;s<r;s++)~th...
  function n (line 22) | function n(t){var n=!1;if(null!=t&&"function"!=typeof t.toString)try{n=!...
    method constructor (line 20) | constructor(t){this.state=t||{seed:"0"},this.used=!1}
    method seed (line 20) | static seed(){return Date.now().toString(36).slice(-10)}
    method isUsed (line 20) | isUsed(){return this.used}
    method getState (line 20) | getState(){return this.state}
    method _random (line 20) | _random(){this.used=!0;const t=this.state,s=r(t.prngstate?"":t.seed,t....
    method api (line 20) | api(){const t=this._random.bind(this),s={D4:4,D6:6,D8:8,D10:10,D12:12,...
    method play (line 47) | play({G:t,ctx:e},r){const a=this.enumerate(t,e,r);return Promise.resol...
    method constructor (line 63) | constructor({server:e=""}={}){this.server=e.replace(/\/$/,"")}
    method request (line 63) | async request(e,t){const s=await fetch(this.server+e,t);if(!s.ok){let ...
    method post (line 63) | async post(e,t){let s={method:"post",body:JSON.stringify(t.body),heade...
    method listGames (line 63) | async listGames(e){return this.request("/games",e)}
    method listMatches (line 63) | async listMatches(e,s,r){t(e);let a="";if(s){const e=[],{isGameover:t,...
    method getMatch (line 63) | async getMatch(e,r,a){return t(e),s(r),this.request(`/games/${e}/${r}`...
    method createMatch (line 63) | async createMatch(e,s,a){return t(e),r(s,{numPlayers:"number"}),this.p...
    method joinMatch (line 63) | async joinMatch(e,a,n,i){return t(e),s(a),r(n,{playerID:["string","und...
    method leaveMatch (line 63) | async leaveMatch(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentials...
    method updatePlayer (line 63) | async updatePlayer(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentia...
    method playAgain (line 63) | async playAgain(e,a,n,i){return t(e),s(a),r(n,{playerID:"string",crede...
    method type (line 80) | type(){return e.SYNC}
    method connect (line 80) | connect(){}
    method createMatch (line 80) | createMatch(e,t){if(this.createGame)return console.warn("The database ...
    method listMatches (line 80) | listMatches(e){if(this.listGames)return console.warn("The database con...
    method constructor (line 151) | constructor(t,e={}){super(),t&&"object"==typeof t&&(e=t,t=null),t?(t=i...
    method createTransport (line 151) | createTransport(e){s('creating transport "%s"',e);const i=a(this.opts....
    method open (line 151) | open(){let t;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1...
    method setTransport (line 151) | setTransport(t){s("setting transport %s",t.name),this.transport&&(s("c...
    method probe (line 151) | probe(t){s('probing transport "%s"',t);let e=this.createTransport(t,{p...
    method onOpen (line 151) | onOpen(){if(s("socket open"),this.readyState="open",n.priorWebsocketSu...
    method onPacket (line 151) | onPacket(t){if("opening"===this.readyState||"open"===this.readyState||...
    method onHandshake (line 151) | onHandshake(t){this.emit("handshake",t),this.id=t.sid,this.transport.q...
    method resetPingTimeout (line 151) | resetPingTimeout(){clearTimeout(this.pingTimeoutTimer),this.pingTimeou...
    method onDrain (line 151) | onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBuffe...
    method flush (line 151) | flush(){"closed"!==this.readyState&&this.transport.writable&&!this.upg...
    method write (line 151) | write(t,e,s){return this.sendPacket("message",t,e,s),this}
    method send (line 151) | send(t,e,s){return this.sendPacket("message",t,e,s),this}
    method sendPacket (line 151) | sendPacket(t,e,s,r){if("function"==typeof e&&(r=e,e=void 0),"function"...
    method close (line 151) | close(){const t=()=>{this.onClose("forced close"),s("socket closing - ...
    method onError (line 151) | onError(t){s("socket error %j",t),n.priorWebsocketSuccess=!1,this.emit...
    method onClose (line 151) | onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"c...
    method filterUpgrades (line 151) | filterUpgrades(t){const e=[];let s=0;const r=t.length;for(;s<r;s++)~th...
  function r (line 22) | function r(t,n){return function(r){return t(n(r))}}
    method constructor (line 120) | constructor(e){super(),this.opts=e,this.query=e.query,this.readyState=...
    method onError (line 120) | onError(e,t){const s=new Error(e);return s.type="TransportError",s.des...
    method open (line 120) | open(){return"closed"!==this.readyState&&""!==this.readyState||(this.r...
    method close (line 120) | close(){return"opening"!==this.readyState&&"open"!==this.readyState||(...
    method send (line 120) | send(e){"open"===this.readyState?this.write(e):s("transport is not ope...
    method onOpen (line 120) | onOpen(){this.readyState="open",this.writable=!0,this.emit("open")}
    method onData (line 120) | onData(t){const s=e.decodePacket(t,this.socket.binaryType);this.onPack...
    method onPacket (line 120) | onPacket(e){this.emit("packet",e)}
    method onClose (line 120) | onClose(){this.readyState="closed",this.emit("close")}
    method constructor (line 174) | constructor(e,t){super(),this.nsps={},this.subs=[],e&&"object"==typeof...
    method reconnection (line 174) | reconnection(e){return arguments.length?(this._reconnection=!!e,this):...
    method reconnectionAttempts (line 174) | reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(...
    method reconnectionDelay (line 174) | reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(...
    method randomizationFactor (line 174) | randomizationFactor(e){var t;return void 0===e?this._randomizationFact...
    method reconnectionDelayMax (line 174) | reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDela...
    method timeout (line 174) | timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}
    method maybeReconnectOnOpen (line 174) | maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===th...
    method open (line 174) | open(t){if(c("readyState %s",this._readyState),~this._readyState.index...
    method connect (line 174) | connect(e){return this.open(e)}
    method onopen (line 174) | onopen(){c("open"),this.cleanup(),this._readyState="open",this.emitRes...
    method onping (line 174) | onping(){this.emitReserved("ping")}
    method ondata (line 174) | ondata(e){this.decoder.add(e)}
    method ondecoded (line 174) | ondecoded(e){this.emitReserved("packet",e)}
    method onerror (line 174) | onerror(e){c("error",e),this.emitReserved("error",e)}
    method socket (line 174) | socket(e,n){let i=this.nsps[e];return i||(i=new t.Socket(this,e,n),thi...
    method _destroy (line 174) | _destroy(e){const t=Object.keys(this.nsps);for(const n of t){if(this.n...
    method _packet (line 174) | _packet(e){c("writing packet %j",e);const t=this.encoder.encode(e);for...
    method cleanup (line 174) | cleanup(){c("cleanup"),this.subs.forEach(e=>e()),this.subs.length=0,th...
    method _close (line 174) | _close(){c("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,"...
    method disconnect (line 174) | disconnect(){return this._close()}
    method onclose (line 174) | onclose(e){c("onclose"),this.cleanup(),this.backoff.reset(),this._read...
    method reconnect (line 174) | reconnect(){if(this._reconnecting||this.skipReconnect)return this;cons...
    method onreconnect (line 174) | onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this...
    method constructor (line 178) | constructor(){super(),this.state=new Map,this.initial=new Map,this.met...
    method createMatch (line 178) | createMatch(t,e){this.initial.set(t,e.initialState),this.setState(t,e....
    method setMetadata (line 178) | setMetadata(t,e){this.metadata.set(t,e)}
    method setState (line 178) | setState(t,e,s){if(s&&s.length>0){const e=this.log.get(t)||[];this.log...
    method fetch (line 178) | fetch(t,e){const s={};return e.state&&(s.state=this.state.get(t)),e.me...
    method wipe (line 178) | wipe(t){this.state.delete(t),this.metadata.delete(t)}
    method listMatches (line 178) | listMatches(t){return[...this.metadata.entries()].filter(([,e])=>{if(!...
  function a (line 22) | function a(t){return!!t&&"object"==typeof t}
    method constructor (line 47) | constructor({enumerate:t,seed:e}){this.enumerateFn=t,this.seed=e,this....
    method addOpt (line 47) | addOpt({key:t,range:e,initial:r}){this._opts[t]={range:e,value:r}}
    method getOpt (line 47) | getOpt(t){return this._opts[t].value}
    method setOpt (line 47) | setOpt(t,e){t in this._opts&&(this._opts[t].value=e)}
    method opts (line 47) | opts(){return this._opts}
    method enumerate (line 47) | enumerate(e,r,a){return this.enumerateFn(e,r,a).map(e=>"payload"in e?e...
    method random (line 47) | random(t){let r;if(void 0!==this.seed){const t=this.prngstate?"":this....
    method constructor (line 63) | constructor(e,t){super(e),this.details=t}
    method constructor (line 130) | constructor(t){if(super(t),"undefined"!=typeof location){const e="http...
    method request (line 130) | request(t={}){return Object.assign(t,{xd:this.xd,xs:this.xs},this.opts...
    method doWrite (line 130) | doWrite(t,e){const s=this.request({method:"POST",data:t});s.on("succes...
    method doPoll (line 130) | doPoll(){i("xhr poll");const t=this.request();t.on("data",this.onData....
    method constructor (line 164) | constructor(t){this.packet=t,this.buffers=[],this.reconPack=t}
    method takeBinaryData (line 164) | takeBinaryData(t){if(this.buffers.push(t),this.buffers.length===this.r...
    method finishedReconstruction (line 164) | finishedReconstruction(){this.reconPack=null,this.buffers=[]}
  function p (line 22) | function p(r){if(!a(r)||i.call(r)!=t||n(r))return!1;var o=l(r);if(null==...
    method name (line 126) | get name(){return"polling"}
    method doOpen (line 126) | doOpen(){this.poll()}
    method pause (line 126) | pause(t){this.readyState="pausing";const e=()=>{o("paused"),this.ready...
    method poll (line 126) | poll(){o("polling"),this.polling=!0,this.doPoll(),this.emit("poll")}
    method onData (line 126) | onData(t){o("polling got data %s",t);s.decodePayload(t,this.socket.bin...
    method doClose (line 126) | doClose(){const t=()=>{o("writing close packet"),this.write([{type:"cl...
    method write (line 126) | write(t){this.writable=!1,s.encodePayload(t,t=>{this.doWrite(t,()=>{th...
    method uri (line 126) | uri(){let t=this.query||{};const s=this.opts.secure?"https":"http";let...
    method constructor (line 180) | constructor(){super(...arguments),this._createSeat=(e=>e.name||"[free]...
    method render (line 180) | render(){const e=this.props.match;let t="OPEN";return e.players.some(e...
  function a (line 24) | function a(e){return e&&e.__esModule?e:{default:e}}
    method constructor (line 47) | constructor({enumerate:t,seed:e}){this.enumerateFn=t,this.seed=e,this....
    method addOpt (line 47) | addOpt({key:t,range:e,initial:r}){this._opts[t]={range:e,value:r}}
    method getOpt (line 47) | getOpt(t){return this._opts[t].value}
    method setOpt (line 47) | setOpt(t,e){t in this._opts&&(this._opts[t].value=e)}
    method opts (line 47) | opts(){return this._opts}
    method enumerate (line 47) | enumerate(e,r,a){return this.enumerateFn(e,r,a).map(e=>"payload"in e?e...
    method random (line 47) | random(t){let r;if(void 0!==this.seed){const t=this.prngstate?"":this....
    method constructor (line 63) | constructor(e,t){super(e),this.details=t}
    method constructor (line 130) | constructor(t){if(super(t),"undefined"!=typeof location){const e="http...
    method request (line 130) | request(t={}){return Object.assign(t,{xd:this.xd,xs:this.xs},this.opts...
    method doWrite (line 130) | doWrite(t,e){const s=this.request({method:"POST",data:t});s.on("succes...
    method doPoll (line 130) | doPoll(){i("xhr poll");const t=this.request();t.on("data",this.onData....
    method constructor (line 164) | constructor(t){this.packet=t,this.buffers=[],this.reconPack=t}
    method takeBinaryData (line 164) | takeBinaryData(t){if(this.buffers.push(t),this.buffers.length===this.r...
    method finishedReconstruction (line 164) | finishedReconstruction(){this.reconPack=null,this.buffers=[]}
  class b (line 24) | class b{constructor(e,t,r){this.flow=e,this.playerID=r,this.dispatch=[],...
    method constructor (line 24) | constructor(e,t,r){this.flow=e,this.playerID=r,this.dispatch=[],this.i...
    method api (line 24) | api(){const e={_private:this};for(const t of this.flow.eventNames)e[t]...
    method isUsed (line 24) | isUsed(){return this.dispatch.length>0}
    method updateTurnContext (line 24) | updateTurnContext(e,t){this.currentPhase=e.phase,this.currentTurn=e.tu...
    method unsetCurrentMethod (line 24) | unsetCurrentMethod(){this.currentMethod=void 0}
    method update (line 24) | update(e){const t=e,r=({stack:e},r)=>({...t,plugins:{...t.plugins,even...
  function U (line 24) | function U(e){if(null==e||"boolean"==typeof e||"number"==typeof e||"stri...
  function C (line 24) | function C(e){L(`INFO: ${e}`)}
  function B (line 24) | function B(e){w("ERROR:",e)}
  function X (line 24) | function X(e,t=!1){e.moveLimit&&(t&&(e.minMoves=e.moveLimit),e.maxMoves=...
  function Z (line 24) | function Z(e,t){let r={},a=[],n=null,s={},o={};if(Array.isArray(t)){cons...
  function ee (line 24) | function ee(e){let{activePlayers:t,_activePlayersMinMoves:r,_activePlaye...
  function te (line 24) | function te(e,t,r,a,n){"object"==typeof n&&n!==oe.NULL||(n={stage:n}),vo...
  function re (line 24) | function re(e,t){return e[t]+""}
  function ae (line 24) | function ae(e,t){let{G:r,ctx:a}=e;const{numPlayers:n}=a,s=V(e),o=t.order...
  function ne (line 24) | function ne(e,t,r,a){const n=r.order;let{G:s,ctx:o}=e,i=o.playOrderPos,l...
  function t (line 26) | function t(t){return t.replace(/~1/g,"/").replace(/~0/g,"~")}
    method constructor (line 20) | constructor(t){const e=s();this.c=1,this.s0=e(" "),this.s1=e(" "),this...
    method next (line 20) | next(){const t=2091639*this.s0+2.3283064365386963e-10*this.c;return th...
    method constructor (line 59) | constructor({transportDataCallback:t,gameName:a,playerID:s,matchID:e,c...
    method subscribeToConnectionStatus (line 59) | subscribeToConnectionStatus(t){this.connectionStatusCallback=t}
    method setConnectionStatus (line 59) | setConnectionStatus(t){this.isConnected=t,this.connectionStatusCallbac...
    method notifyClient (line 59) | notifyClient(t){this.transportDataCallback(t)}
    method on (line 168) | on(e,t){return super.on(e,t),this}
    method once (line 168) | once(e,t){return super.once(e,t),this}
    method emit (line 168) | emit(e,...t){return super.emit(e,...t),this}
    method emitReserved (line 168) | emitReserved(e,...t){return super.emit(e,...t),this}
    method listeners (line 168) | listeners(e){return super.listeners(e)}
  function e (line 26) | function e(t){return t.replace(/~/g,"~0").replace(/\//g,"~1")}
  function n (line 26) | function n(t){void 0===t&&(t=[""]),this.tokens=t}
    method constructor (line 20) | constructor(t){this.state=t||{seed:"0"},this.used=!1}
    method seed (line 20) | static seed(){return Date.now().toString(36).slice(-10)}
    method isUsed (line 20) | isUsed(){return this.used}
    method getState (line 20) | getState(){return this.state}
    method _random (line 20) | _random(){this.used=!0;const t=this.state,s=r(t.prngstate?"":t.seed,t....
    method api (line 20) | api(){const t=this._random.bind(this),s={D4:4,D6:6,D8:8,D10:10,D12:12,...
    method play (line 47) | play({G:t,ctx:e},r){const a=this.enumerate(t,e,r);return Promise.resol...
    method constructor (line 63) | constructor({server:e=""}={}){this.server=e.replace(/\/$/,"")}
    method request (line 63) | async request(e,t){const s=await fetch(this.server+e,t);if(!s.ok){let ...
    method post (line 63) | async post(e,t){let s={method:"post",body:JSON.stringify(t.body),heade...
    method listGames (line 63) | async listGames(e){return this.request("/games",e)}
    method listMatches (line 63) | async listMatches(e,s,r){t(e);let a="";if(s){const e=[],{isGameover:t,...
    method getMatch (line 63) | async getMatch(e,r,a){return t(e),s(r),this.request(`/games/${e}/${r}`...
    method createMatch (line 63) | async createMatch(e,s,a){return t(e),r(s,{numPlayers:"number"}),this.p...
    method joinMatch (line 63) | async joinMatch(e,a,n,i){return t(e),s(a),r(n,{playerID:["string","und...
    method leaveMatch (line 63) | async leaveMatch(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentials...
    method updatePlayer (line 63) | async updatePlayer(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentia...
    method playAgain (line 63) | async playAgain(e,a,n,i){return t(e),s(a),r(n,{playerID:"string",crede...
    method type (line 80) | type(){return e.SYNC}
    method connect (line 80) | connect(){}
    method createMatch (line 80) | createMatch(e,t){if(this.createGame)return console.warn("The database ...
    method listMatches (line 80) | listMatches(e){if(this.listGames)return console.warn("The database con...
    method constructor (line 151) | constructor(t,e={}){super(),t&&"object"==typeof t&&(e=t,t=null),t?(t=i...
    method createTransport (line 151) | createTransport(e){s('creating transport "%s"',e);const i=a(this.opts....
    method open (line 151) | open(){let t;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1...
    method setTransport (line 151) | setTransport(t){s("setting transport %s",t.name),this.transport&&(s("c...
    method probe (line 151) | probe(t){s('probing transport "%s"',t);let e=this.createTransport(t,{p...
    method onOpen (line 151) | onOpen(){if(s("socket open"),this.readyState="open",n.priorWebsocketSu...
    method onPacket (line 151) | onPacket(t){if("opening"===this.readyState||"open"===this.readyState||...
    method onHandshake (line 151) | onHandshake(t){this.emit("handshake",t),this.id=t.sid,this.transport.q...
    method resetPingTimeout (line 151) | resetPingTimeout(){clearTimeout(this.pingTimeoutTimer),this.pingTimeou...
    method onDrain (line 151) | onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBuffe...
    method flush (line 151) | flush(){"closed"!==this.readyState&&this.transport.writable&&!this.upg...
    method write (line 151) | write(t,e,s){return this.sendPacket("message",t,e,s),this}
    method send (line 151) | send(t,e,s){return this.sendPacket("message",t,e,s),this}
    method sendPacket (line 151) | sendPacket(t,e,s,r){if("function"==typeof e&&(r=e,e=void 0),"function"...
    method close (line 151) | close(){const t=()=>{this.onClose("forced close"),s("socket closing - ...
    method onError (line 151) | onError(t){s("socket error %j",t),n.priorWebsocketSuccess=!1,this.emit...
    method onClose (line 151) | onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"c...
    method filterUpgrades (line 151) | filterUpgrades(t){const e=[];let s=0;const r=t.length;for(;s<r;s++)~th...
  function r (line 28) | function r(r){return void 0===r?"undefined":null===r?"null":Array.isArra...
    method constructor (line 120) | constructor(e){super(),this.opts=e,this.query=e.query,this.readyState=...
    method onError (line 120) | onError(e,t){const s=new Error(e);return s.type="TransportError",s.des...
    method open (line 120) | open(){return"closed"!==this.readyState&&""!==this.readyState||(this.r...
    method close (line 120) | close(){return"opening"!==this.readyState&&"open"!==this.readyState||(...
    method send (line 120) | send(e){"open"===this.readyState?this.write(e):s("transport is not ope...
    method onOpen (line 120) | onOpen(){this.readyState="open",this.writable=!0,this.emit("open")}
    method onData (line 120) | onData(t){const s=e.decodePacket(t,this.socket.binaryType);this.onPack...
    method onPacket (line 120) | onPacket(e){this.emit("packet",e)}
    method onClose (line 120) | onClose(){this.readyState="closed",this.emit("close")}
    method constructor (line 174) | constructor(e,t){super(),this.nsps={},this.subs=[],e&&"object"==typeof...
    method reconnection (line 174) | reconnection(e){return arguments.length?(this._reconnection=!!e,this):...
    method reconnectionAttempts (line 174) | reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(...
    method reconnectionDelay (line 174) | reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(...
    method randomizationFactor (line 174) | randomizationFactor(e){var t;return void 0===e?this._randomizationFact...
    method reconnectionDelayMax (line 174) | reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDela...
    method timeout (line 174) | timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}
    method maybeReconnectOnOpen (line 174) | maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===th...
    method open (line 174) | open(t){if(c("readyState %s",this._readyState),~this._readyState.index...
    method connect (line 174) | connect(e){return this.open(e)}
    method onopen (line 174) | onopen(){c("open"),this.cleanup(),this._readyState="open",this.emitRes...
    method onping (line 174) | onping(){this.emitReserved("ping")}
    method ondata (line 174) | ondata(e){this.decoder.add(e)}
    method ondecoded (line 174) | ondecoded(e){this.emitReserved("packet",e)}
    method onerror (line 174) | onerror(e){c("error",e),this.emitReserved("error",e)}
    method socket (line 174) | socket(e,n){let i=this.nsps[e];return i||(i=new t.Socket(this,e,n),thi...
    method _destroy (line 174) | _destroy(e){const t=Object.keys(this.nsps);for(const n of t){if(this.n...
    method _packet (line 174) | _packet(e){c("writing packet %j",e);const t=this.encoder.encode(e);for...
    method cleanup (line 174) | cleanup(){c("cleanup"),this.subs.forEach(e=>e()),this.subs.length=0,th...
    method _close (line 174) | _close(){c("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,"...
    method disconnect (line 174) | disconnect(){return this._close()}
    method onclose (line 174) | onclose(e){c("onclose"),this.cleanup(),this.backoff.reset(),this._read...
    method reconnect (line 174) | reconnect(){if(this._reconnecting||this.skipReconnect)return this;cons...
    method onreconnect (line 174) | onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this...
    method constructor (line 178) | constructor(){super(),this.state=new Map,this.initial=new Map,this.met...
    method createMatch (line 178) | createMatch(t,e){this.initial.set(t,e.initialState),this.setState(t,e....
    method setMetadata (line 178) | setMetadata(t,e){this.metadata.set(t,e)}
    method setState (line 178) | setState(t,e,s){if(s&&s.length>0){const e=this.log.get(t)||[];this.log...
    method fetch (line 178) | fetch(t,e){const s={};return e.state&&(s.state=this.state.get(t)),e.me...
    method wipe (line 178) | wipe(t){this.state.delete(t),this.metadata.delete(t)}
    method listMatches (line 178) | listMatches(t){return[...this.metadata.entries()].filter(([,e])=>{if(!...
  function e (line 28) | function e(r){return null!=r&&"object"==typeof r}
  function t (line 28) | function t(r){if(!e(r))return r;if(r.constructor==Array){for(var o=r.len...
    method constructor (line 20) | constructor(t){const e=s();this.c=1,this.s0=e(" "),this.s1=e(" "),this...
    method next (line 20) | next(){const t=2091639*this.s0+2.3283064365386963e-10*this.c;return th...
    method constructor (line 59) | constructor({transportDataCallback:t,gameName:a,playerID:s,matchID:e,c...
    method subscribeToConnectionStatus (line 59) | subscribeToConnectionStatus(t){this.connectionStatusCallback=t}
    method setConnectionStatus (line 59) | setConnectionStatus(t){this.isConnected=t,this.connectionStatusCallbac...
    method notifyClient (line 59) | notifyClient(t){this.transportDataCallback(t)}
    method on (line 168) | on(e,t){return super.on(e,t),this}
    method once (line 168) | once(e,t){return super.once(e,t),this}
    method emit (line 168) | emit(e,...t){return super.emit(e,...t),this}
    method emitReserved (line 168) | emitReserved(e,...t){return super.emit(e,...t),this}
    method listeners (line 168) | listeners(e){return super.listeners(e)}
  function t (line 30) | function t(r){var e=r.op;return"remove"===e||"replace"===e||"copy"===e||...
    method constructor (line 20) | constructor(t){const e=s();this.c=1,this.s0=e(" "),this.s1=e(" "),this...
    method next (line 20) | next(){const t=2091639*this.s0+2.3283064365386963e-10*this.c;return th...
    method constructor (line 59) | constructor({transportDataCallback:t,gameName:a,playerID:s,matchID:e,c...
    method subscribeToConnectionStatus (line 59) | subscribeToConnectionStatus(t){this.connectionStatusCallback=t}
    method setConnectionStatus (line 59) | setConnectionStatus(t){this.isConnected=t,this.connectionStatusCallbac...
    method notifyClient (line 59) | notifyClient(t){this.transportDataCallback(t)}
    method on (line 168) | on(e,t){return super.on(e,t),this}
    method once (line 168) | once(e,t){return super.once(e,t),this}
    method emit (line 168) | emit(e,...t){return super.emit(e,...t),this}
    method emitReserved (line 168) | emitReserved(e,...t){return super.emit(e,...t),this}
    method listeners (line 168) | listeners(e){return super.listeners(e)}
  function o (line 30) | function o(r,t){var o={};for(var n in r)e.hasOwnProperty.call(r,n)&&void...
    method constructor (line 82) | constructor(t,a,r,s){this.game=(0,e.P)(t),this.storageAPI=a,this.trans...
    method subscribe (line 82) | subscribe(t){this.subscribeCallback=t}
    method onUpdate (line 82) | async onUpdate(s,o,n,c){if(!s||!s.payload)return{error:"missing action...
    method onSync (line 82) | async onSync(t,a,e,i=2){const o=t,n={state:!0,metadata:!0,log:!0,initi...
    method onConnectionChange (line 82) | async onConnectionChange(t,e,i,o){const n=t;if(null==e)return;let c;if...
    method onChatMessage (line 82) | async onChatMessage(t,a,e){const r=t;if(this.auth){const{metadata:t}=a...
    method constructor (line 132) | constructor(e){super(e),this.query=this.query||{},s||(s=t.___eio=t.___...
    method supportsBinary (line 132) | get supportsBinary(){return!1}
    method doClose (line 132) | doClose(){this.script&&(this.script.onerror=(()=>{}),this.script.paren...
    method doPoll (line 132) | doPoll(){const e=document.createElement("script");this.script&&(this.s...
    method doWrite (line 132) | doWrite(e,t){let s;if(!this.form){const e=document.createElement("form...
    method constructor (line 164) | constructor(){super()}
    method add (line 164) | add(t){let e;if("string"==typeof t)(e=this.decodeString(t)).type===n.B...
    method decodeString (line 164) | decodeString(t){let e=0;const r={type:Number(t.charAt(0))};if(void 0==...
    method isPayloadValid (line 164) | static isPayloadValid(t,e){switch(t){case n.CONNECT:return"object"==ty...
    method destroy (line 164) | destroy(){this.reconstructor&&this.reconstructor.finishedReconstructio...
    method constructor (line 178) | constructor(t="bgio"){super();const e=e=>new c(`${t}_${e}`);this.state...
  function n (line 30) | function n(r){for(var t=r.length,o={},n=0;n<t;n++){var i=r[n];for(var a ...
    method constructor (line 20) | constructor(t){this.state=t||{seed:"0"},this.used=!1}
    method seed (line 20) | static seed(){return Date.now().toString(36).slice(-10)}
    method isUsed (line 20) | isUsed(){return this.used}
    method getState (line 20) | getState(){return this.state}
    method _random (line 20) | _random(){this.used=!0;const t=this.state,s=r(t.prngstate?"":t.seed,t....
    method api (line 20) | api(){const t=this._random.bind(this),s={D4:4,D6:6,D8:8,D10:10,D12:12,...
    method play (line 47) | play({G:t,ctx:e},r){const a=this.enumerate(t,e,r);return Promise.resol...
    method constructor (line 63) | constructor({server:e=""}={}){this.server=e.replace(/\/$/,"")}
    method request (line 63) | async request(e,t){const s=await fetch(this.server+e,t);if(!s.ok){let ...
    method post (line 63) | async post(e,t){let s={method:"post",body:JSON.stringify(t.body),heade...
    method listGames (line 63) | async listGames(e){return this.request("/games",e)}
    method listMatches (line 63) | async listMatches(e,s,r){t(e);let a="";if(s){const e=[],{isGameover:t,...
    method getMatch (line 63) | async getMatch(e,r,a){return t(e),s(r),this.request(`/games/${e}/${r}`...
    method createMatch (line 63) | async createMatch(e,s,a){return t(e),r(s,{numPlayers:"number"}),this.p...
    method joinMatch (line 63) | async joinMatch(e,a,n,i){return t(e),s(a),r(n,{playerID:["string","und...
    method leaveMatch (line 63) | async leaveMatch(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentials...
    method updatePlayer (line 63) | async updatePlayer(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentia...
    method playAgain (line 63) | async playAgain(e,a,n,i){return t(e),s(a),r(n,{playerID:"string",crede...
    method type (line 80) | type(){return e.SYNC}
    method connect (line 80) | connect(){}
    method createMatch (line 80) | createMatch(e,t){if(this.createGame)return console.warn("The database ...
    method listMatches (line 80) | listMatches(e){if(this.listGames)return console.warn("The database con...
    method constructor (line 151) | constructor(t,e={}){super(),t&&"object"==typeof t&&(e=t,t=null),t?(t=i...
    method createTransport (line 151) | createTransport(e){s('creating transport "%s"',e);const i=a(this.opts....
    method open (line 151) | open(){let t;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1...
    method setTransport (line 151) | setTransport(t){s("setting transport %s",t.name),this.transport&&(s("c...
    method probe (line 151) | probe(t){s('probing transport "%s"',t);let e=this.createTransport(t,{p...
    method onOpen (line 151) | onOpen(){if(s("socket open"),this.readyState="open",n.priorWebsocketSu...
    method onPacket (line 151) | onPacket(t){if("opening"===this.readyState||"open"===this.readyState||...
    method onHandshake (line 151) | onHandshake(t){this.emit("handshake",t),this.id=t.sid,this.transport.q...
    method resetPingTimeout (line 151) | resetPingTimeout(){clearTimeout(this.pingTimeoutTimer),this.pingTimeou...
    method onDrain (line 151) | onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBuffe...
    method flush (line 151) | flush(){"closed"!==this.readyState&&this.transport.writable&&!this.upg...
    method write (line 151) | write(t,e,s){return this.sendPacket("message",t,e,s),this}
    method send (line 151) | send(t,e,s){return this.sendPacket("message",t,e,s),this}
    method sendPacket (line 151) | sendPacket(t,e,s,r){if("function"==typeof e&&(r=e,e=void 0),"function"...
    method close (line 151) | close(){const t=()=>{this.onClose("forced close"),s("socket closing - ...
    method onError (line 151) | onError(t){s("socket error %j",t),n.priorWebsocketSuccess=!1,this.emit...
    method onClose (line 151) | onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"c...
    method filterUpgrades (line 151) | filterUpgrades(t){const e=[];let s=0;const r=t.length;for(;s<r;s++)~th...
  function i (line 30) | function i(r){return"add"===r.op}
    method constructor (line 47) | constructor({enumerate:t,seed:e,objectives:a,game:s,iterations:i,playo...
    method createNode (line 47) | createNode({state:t,parentAction:e,parent:r,playerID:a}){const{G:s,ctx...
    method select (line 47) | select(t){if(t.actions.length>0)return t;if(0===t.children.length)retu...
    method expand (line 47) | expand(t){const e=t.actions;if(0===e.length||void 0!==t.state.ctx.game...
    method playout (line 47) | playout({state:t}){let e=this.getOpt("playoutDepth");"function"==typeo...
    method backpropagate (line 47) | backpropagate(t,e={}){t.visits++,void 0!==e.score&&(t.value+=e.score),...
    method play (line 47) | play(t,e){const r=this.createNode({state:t,playerID:e});let a=this.get...
  function a (line 30) | function a(r){return"remove"===r.op}
    method constructor (line 47) | constructor({enumerate:t,seed:e}){this.enumerateFn=t,this.seed=e,this....
    method addOpt (line 47) | addOpt({key:t,range:e,initial:r}){this._opts[t]={range:e,value:r}}
    method getOpt (line 47) | getOpt(t){return this._opts[t].value}
    method setOpt (line 47) | setOpt(t,e){t in this._opts&&(this._opts[t].value=e)}
    method opts (line 47) | opts(){return this._opts}
    method enumerate (line 47) | enumerate(e,r,a){return this.enumerateFn(e,r,a).map(e=>"payload"in e?e...
    method random (line 47) | random(t){let r;if(void 0!==this.seed){const t=this.prngstate?"":this....
    method constructor (line 63) | constructor(e,t){super(e),this.details=t}
    method constructor (line 130) | constructor(t){if(super(t),"undefined"!=typeof location){const e="http...
    method request (line 130) | request(t={}){return Object.assign(t,{xd:this.xd,xs:this.xs},this.opts...
    method doWrite (line 130) | doWrite(t,e){const s=this.request({method:"POST",data:t});s.on("succes...
    method doPoll (line 130) | doPoll(){i("xhr poll");const t=this.request();t.on("data",this.onData....
    method constructor (line 164) | constructor(t){this.packet=t,this.buffers=[],this.reconPack=t}
    method takeBinaryData (line 164) | takeBinaryData(t){if(this.buffers.push(t),this.buffers.length===this.r...
    method finishedReconstruction (line 164) | finishedReconstruction(){this.reconPack=null,this.buffers=[]}
  function p (line 30) | function p(r,e){return{operations:r.operations.concat(e),cost:r.cost+1}}
    method name (line 126) | get name(){return"polling"}
    method doOpen (line 126) | doOpen(){this.poll()}
    method pause (line 126) | pause(t){this.readyState="pausing";const e=()=>{o("paused"),this.ready...
    method poll (line 126) | poll(){o("polling"),this.polling=!0,this.doPoll(),this.emit("poll")}
    method onData (line 126) | onData(t){o("polling got data %s",t);s.decodePayload(t,this.socket.bin...
    method doClose (line 126) | doClose(){const t=()=>{o("writing close packet"),this.write([{type:"cl...
    method write (line 126) | write(t){this.writable=!1,s.encodePayload(t,t=>{this.doWrite(t,()=>{th...
    method uri (line 126) | uri(){let t=this.query||{};const s=this.opts.secure?"https":"http";let...
    method constructor (line 180) | constructor(){super(...arguments),this._createSeat=(e=>e.name||"[free]...
    method render (line 180) | render(){const e=this.props.match;let t="OPEN";return e.players.some(e...
  function c (line 30) | function c(e,t,o,n){void 0===n&&(n=s);var c={"0,0":{operations:[],cost:0...
    method encode (line 164) | encode(t){return s("encoding packet %j",t),t.type!==n.EVENT&&t.type!==...
    method encodeAsString (line 164) | encodeAsString(t){let e=""+t.type;return t.type!==n.BINARY_EVENT&&t.ty...
    method encodeAsBinary (line 164) | encodeAsBinary(t){const r=e.deconstructPacket(t),s=this.encodeAsString...
    method constructor (line 170) | constructor(t,e,s){super(),this.receiveBuffer=[],this.sendBuffer=[],th...
    method subEvents (line 170) | subEvents(){if(this.subs)return;const t=this.io;this.subs=[e.on(t,"ope...
    method active (line 170) | get active(){return!!this.subs}
    method connect (line 170) | connect(){return this.connected?this:(this.subEvents(),this.io._reconn...
    method open (line 170) | open(){return this.connect()}
    method send (line 170) | send(...t){return t.unshift("message"),this.emit.apply(this,t),this}
    method emit (line 170) | emit(e,...s){if(n.hasOwnProperty(e))throw new Error('"'+e+'" is a rese...
    method packet (line 170) | packet(t){t.nsp=this.nsp,this.io._packet(t)}
    method onopen (line 170) | onopen(){i("transport is open - connecting"),"function"==typeof this.a...
    method onerror (line 170) | onerror(t){this.connected||this.emitReserved("connect_error",t)}
    method onclose (line 170) | onclose(t){i("close (%s)",t),this.connected=!1,this.disconnected=!0,de...
    method onpacket (line 170) | onpacket(e){if(e.nsp===this.nsp)switch(e.type){case t.PacketType.CONNE...
    method onevent (line 170) | onevent(t){const e=t.data||[];i("emitting event %j",e),null!=t.id&&(i(...
    method emitEvent (line 170) | emitEvent(t){if(this._anyListeners&&this._anyListeners.length){const e...
    method ack (line 170) | ack(e){const s=this;let n=!1;return function(...c){n||(n=!0,i("sending...
    method onack (line 170) | onack(t){const e=this.acks[t.id];"function"==typeof e?(i("calling ack ...
    method onconnect (line 170) | onconnect(t){i("socket connected with id %s",t),this.id=t,this.connect...
    method emitBuffered (line 170) | emitBuffered(){this.receiveBuffer.forEach(t=>this.emitEvent(t)),this.r...
    method ondisconnect (line 170) | ondisconnect(){i("server disconnect (%s)",this.nsp),this.destroy(),thi...
    method destroy (line 170) | destroy(){this.subs&&(this.subs.forEach(t=>t()),this.subs=void 0),this...
    method disconnect (line 170) | disconnect(){return this.connected&&(i("performing disconnect (%s)",th...
    method close (line 170) | close(){return this.disconnect()}
    method compress (line 170) | compress(t){return this.flags.compress=t,this}
    method volatile (line 170) | get volatile(){return this.flags.volatile=!0,this}
    method onAny (line 170) | onAny(t){return this._anyListeners=this._anyListeners||[],this._anyLis...
    method prependAny (line 170) | prependAny(t){return this._anyListeners=this._anyListeners||[],this._a...
    method offAny (line 170) | offAny(t){if(!this._anyListeners)return this;if(t){const e=this._anyLi...
    method listenersAny (line 170) | listenersAny(){return this._anyListeners||[]}
    method constructor (line 178) | constructor(t){super(),this.key=t,(JSON.parse(localStorage.getItem(thi...
    method sync (line 178) | sync(){const t=[...this.entries()];localStorage.setItem(this.key,JSON....
    method set (line 178) | set(t,e){return super.set(t,e),this.sync(),this}
    method delete (line 178) | delete(t){const e=super.delete(t);return this.sync(),e}
  function u (line 30) | function u(r,e,t,i){void 0===i&&(i=s);var a=[];return o(r,e).forEach(fun...
    method constructor (line 130) | constructor(t,e){super(),this.opts=e,this.method=e.method||"GET",this....
    method create (line 130) | create(){const e=o(this.opts,"agent","enablesXDR","pfx","key","passphr...
    method onSuccess (line 130) | onSuccess(){this.emit("success"),this.cleanup()}
    method onData (line 130) | onData(t){this.emit("data",t),this.onSuccess()}
    method onError (line 130) | onError(t){this.emit("error",t),this.cleanup(!0)}
    method cleanup (line 130) | cleanup(t){if(void 0!==this.xhr&&null!==this.xhr){if(this.hasXDR()?thi...
    method onLoad (line 130) | onLoad(){const t=this.xhr.responseText;null!==t&&this.onData(t)}
    method hasXDR (line 130) | hasXDR(){return"undefined"!=typeof XDomainRequest&&!this.xs&&this.enab...
    method abort (line 130) | abort(){this.cleanup()}
    method constructor (line 178) | constructor({master:t,...e}){super(e),this.master=t}
    method sendChatMessage (line 178) | sendChatMessage(t,e){const s=[t,e,this.credentials];this.master.onChat...
    method sendAction (line 178) | sendAction(t,e){this.master.onUpdate(e,t._stateID,this.matchID,this.pl...
    method requestSync (line 178) | requestSync(){this.master.onSync(this.matchID,this.playerID,this.crede...
    method connect (line 178) | connect(){this.setConnectionStatus(!0),this.master.connect(this.player...
    method disconnect (line 178) | disconnect(){this.setConnectionStatus(!1)}
    method updateMatchID (line 178) | updateMatchID(t){this.matchID=t,this.connect()}
    method updatePlayerID (line 178) | updatePlayerID(t){this.playerID=t,this.connect()}
    method updateCredentials (line 178) | updateCredentials(t){this.credentials=t,this.connect()}
    method constructor (line 180) | constructor(){super(...arguments),this.state={playerName:this.props.pl...
    method render (line 180) | render(){return s.default.createElement("div",null,s.default.createEle...
  function s (line 30) | function s(r,t,o,n){if(void 0===n&&(n=s),r===t)return[];var i=e.objectTy...
    method type (line 80) | type(){return e.ASYNC}
    method createMatch (line 80) | async createMatch(e,t){if(this.createGame)return console.warn("The dat...
    method listMatches (line 80) | async listMatches(e){if(this.listGames)return console.warn("The databa...
  function n (line 32) | function n(){this.constructor=e}
    method constructor (line 20) | constructor(t){this.state=t||{seed:"0"},this.used=!1}
    method seed (line 20) | static seed(){return Date.now().toString(36).slice(-10)}
    method isUsed (line 20) | isUsed(){return this.used}
    method getState (line 20) | getState(){return this.state}
    method _random (line 20) | _random(){this.used=!0;const t=this.state,s=r(t.prngstate?"":t.seed,t....
    method api (line 20) | api(){const t=this._random.bind(this),s={D4:4,D6:6,D8:8,D10:10,D12:12,...
    method play (line 47) | play({G:t,ctx:e},r){const a=this.enumerate(t,e,r);return Promise.resol...
    method constructor (line 63) | constructor({server:e=""}={}){this.server=e.replace(/\/$/,"")}
    method request (line 63) | async request(e,t){const s=await fetch(this.server+e,t);if(!s.ok){let ...
    method post (line 63) | async post(e,t){let s={method:"post",body:JSON.stringify(t.body),heade...
    method listGames (line 63) | async listGames(e){return this.request("/games",e)}
    method listMatches (line 63) | async listMatches(e,s,r){t(e);let a="";if(s){const e=[],{isGameover:t,...
    method getMatch (line 63) | async getMatch(e,r,a){return t(e),s(r),this.request(`/games/${e}/${r}`...
    method createMatch (line 63) | async createMatch(e,s,a){return t(e),r(s,{numPlayers:"number"}),this.p...
    method joinMatch (line 63) | async joinMatch(e,a,n,i){return t(e),s(a),r(n,{playerID:["string","und...
    method leaveMatch (line 63) | async leaveMatch(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentials...
    method updatePlayer (line 63) | async updatePlayer(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentia...
    method playAgain (line 63) | async playAgain(e,a,n,i){return t(e),s(a),r(n,{playerID:"string",crede...
    method type (line 80) | type(){return e.SYNC}
    method connect (line 80) | connect(){}
    method createMatch (line 80) | createMatch(e,t){if(this.createGame)return console.warn("The database ...
    method listMatches (line 80) | listMatches(e){if(this.listGames)return console.warn("The database con...
    method constructor (line 151) | constructor(t,e={}){super(),t&&"object"==typeof t&&(e=t,t=null),t?(t=i...
    method createTransport (line 151) | createTransport(e){s('creating transport "%s"',e);const i=a(this.opts....
    method open (line 151) | open(){let t;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1...
    method setTransport (line 151) | setTransport(t){s("setting transport %s",t.name),this.transport&&(s("c...
    method probe (line 151) | probe(t){s('probing transport "%s"',t);let e=this.createTransport(t,{p...
    method onOpen (line 151) | onOpen(){if(s("socket open"),this.readyState="open",n.priorWebsocketSu...
    method onPacket (line 151) | onPacket(t){if("opening"===this.readyState||"open"===this.readyState||...
    method onHandshake (line 151) | onHandshake(t){this.emit("handshake",t),this.id=t.sid,this.transport.q...
    method resetPingTimeout (line 151) | resetPingTimeout(){clearTimeout(this.pingTimeoutTimer),this.pingTimeou...
    method onDrain (line 151) | onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBuffe...
    method flush (line 151) | flush(){"closed"!==this.readyState&&this.transport.writable&&!this.upg...
    method write (line 151) | write(t,e,s){return this.sendPacket("message",t,e,s),this}
    method send (line 151) | send(t,e,s){return this.sendPacket("message",t,e,s),this}
    method sendPacket (line 151) | sendPacket(t,e,s,r){if("function"==typeof e&&(r=e,e=void 0),"function"...
    method close (line 151) | close(){const t=()=>{this.onClose("forced close"),s("socket closing - ...
    method onError (line 151) | onError(t){s("socket error %j",t),n.priorWebsocketSuccess=!1,this.emit...
    method onClose (line 151) | onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"c...
    method filterUpgrades (line 151) | filterUpgrades(t){const e=[];let s=0;const r=t.length;for(;s<r;s++)~th...
  function t (line 32) | function t(r){var t=e.call(this,"Value required at path: "+r)||this;retu...
    method constructor (line 20) | constructor(t){const e=s();this.c=1,this.s0=e(" "),this.s1=e(" "),this...
    method next (line 20) | next(){const t=2091639*this.s0+2.3283064365386963e-10*this.c;return th...
    method constructor (line 59) | constructor({transportDataCallback:t,gameName:a,playerID:s,matchID:e,c...
    method subscribeToConnectionStatus (line 59) | subscribeToConnectionStatus(t){this.connectionStatusCallback=t}
    method setConnectionStatus (line 59) | setConnectionStatus(t){this.isConnected=t,this.connectionStatusCallbac...
    method notifyClient (line 59) | notifyClient(t){this.transportDataCallback(t)}
    method on (line 168) | on(e,t){return super.on(e,t),this}
    method once (line 168) | once(e,t){return super.once(e,t),this}
    method emit (line 168) | emit(e,...t){return super.emit(e,...t),this}
    method emitReserved (line 168) | emitReserved(e,...t){return super.emit(e,...t),this}
    method listeners (line 168) | listeners(e){return super.listeners(e)}
  function t (line 32) | function t(r,t){var n=e.call(this,"Test failed: "+r+" != "+t)||this;retu...
    method constructor (line 20) | constructor(t){const e=s();this.c=1,this.s0=e(" "),this.s1=e(" "),this...
    method next (line 20) | next(){const t=2091639*this.s0+2.3283064365386963e-10*this.c;return th...
    method constructor (line 59) | constructor({transportDataCallback:t,gameName:a,playerID:s,matchID:e,c...
    method subscribeToConnectionStatus (line 59) | subscribeToConnectionStatus(t){this.connectionStatusCallback=t}
    method setConnectionStatus (line 59) | setConnectionStatus(t){this.isConnected=t,this.connectionStatusCallbac...
    method notifyClient (line 59) | notifyClient(t){this.transportDataCallback(t)}
    method on (line 168) | on(e,t){return super.on(e,t),this}
    method once (line 168) | once(e,t){return super.once(e,t),this}
    method emit (line 168) | emit(e,...t){return super.emit(e,...t),this}
    method emitReserved (line 168) | emitReserved(e,...t){return super.emit(e,...t),this}
    method listeners (line 168) | listeners(e){return super.listeners(e)}
  function i (line 32) | function i(r,e,t){if(Array.isArray(r))if("-"==e)r.push(t);else{var n=par...
    method constructor (line 47) | constructor({enumerate:t,seed:e,objectives:a,game:s,iterations:i,playo...
    method createNode (line 47) | createNode({state:t,parentAction:e,parent:r,playerID:a}){const{G:s,ctx...
    method select (line 47) | select(t){if(t.actions.length>0)return t;if(0===t.children.length)retu...
    method expand (line 47) | expand(t){const e=t.actions;if(0===e.length||void 0!==t.state.ctx.game...
    method playout (line 47) | playout({state:t}){let e=this.getOpt("playoutDepth");"function"==typeo...
    method backpropagate (line 47) | backpropagate(t,e={}){t.visits++,void 0!==e.score&&(t.value+=e.score),...
    method play (line 47) | play(t,e){const r=this.createNode({state:t,playerID:e});let a=this.get...
  function u (line 32) | function u(r,e){if(Array.isArray(r)){var t=parseInt(e,10);r.splice(t,1)}...
    method constructor (line 130) | constructor(t,e){super(),this.opts=e,this.method=e.method||"GET",this....
    method create (line 130) | create(){const e=o(this.opts,"agent","enablesXDR","pfx","key","passphr...
    method onSuccess (line 130) | onSuccess(){this.emit("success"),this.cleanup()}
    method onData (line 130) | onData(t){this.emit("data",t),this.onSuccess()}
    method onError (line 130) | onError(t){this.emit("error",t),this.cleanup(!0)}
    method cleanup (line 130) | cleanup(t){if(void 0!==this.xhr&&null!==this.xhr){if(this.hasXDR()?thi...
    method onLoad (line 130) | onLoad(){const t=this.xhr.responseText;null!==t&&this.onData(t)}
    method hasXDR (line 130) | hasXDR(){return"undefined"!=typeof XDomainRequest&&!this.xs&&this.enab...
    method abort (line 130) | abort(){this.cleanup()}
    method constructor (line 178) | constructor({master:t,...e}){super(e),this.master=t}
    method sendChatMessage (line 178) | sendChatMessage(t,e){const s=[t,e,this.credentials];this.master.onChat...
    method sendAction (line 178) | sendAction(t,e){this.master.onUpdate(e,t._stateID,this.matchID,this.pl...
    method requestSync (line 178) | requestSync(){this.master.onSync(this.matchID,this.playerID,this.crede...
    method connect (line 178) | connect(){this.setConnectionStatus(!0),this.master.connect(this.player...
    method disconnect (line 178) | disconnect(){this.setConnectionStatus(!1)}
    method updateMatchID (line 178) | updateMatchID(t){this.matchID=t,this.connect()}
    method updatePlayerID (line 178) | updatePlayerID(t){this.playerID=t,this.connect()}
    method updateCredentials (line 178) | updateCredentials(t){this.credentials=t,this.connect()}
    method constructor (line 180) | constructor(){super(...arguments),this.state={playerName:this.props.pl...
    method render (line 180) | render(){return s.default.createElement("div",null,s.default.createEle...
  function p (line 32) | function p(r,n){var a=e.Pointer.fromJSON(n.path).evaluate(r);return void...
    method name (line 126) | get name(){return"polling"}
    method doOpen (line 126) | doOpen(){this.poll()}
    method pause (line 126) | pause(t){this.readyState="pausing";const e=()=>{o("paused"),this.ready...
    method poll (line 126) | poll(){o("polling"),this.polling=!0,this.doPoll(),this.emit("poll")}
    method onData (line 126) | onData(t){o("polling got data %s",t);s.decodePayload(t,this.socket.bin...
    method doClose (line 126) | doClose(){const t=()=>{o("writing close packet"),this.write([{type:"cl...
    method write (line 126) | write(t){this.writable=!1,s.encodePayload(t,t=>{this.doWrite(t,()=>{th...
    method uri (line 126) | uri(){let t=this.query||{};const s=this.opts.secure?"https":"http";let...
    method constructor (line 180) | constructor(){super(...arguments),this._createSeat=(e=>e.name||"[free]...
    method render (line 180) | render(){const e=this.props.match;let t="OPEN";return e.players.some(e...
  function l (line 32) | function l(r,t){var n=e.Pointer.fromJSON(t.path).evaluate(r);return void...
    method constructor (line 61) | constructor(){this.debugPanel=null,this.currentClient=null,this.client...
    method register (line 61) | register(t){this.clients.set(t,t),this.mountDebug(t),this.notifySubscr...
    method unregister (line 61) | unregister(t){if(this.clients.delete(t),this.currentClient===t){this.u...
    method subscribe (line 61) | subscribe(t){const e=Symbol();return this.subscribers.set(e,t),t(this....
    method switchPlayerID (line 61) | switchPlayerID(t){if(this.currentClient.multiplayer)for(const[e]of thi...
    method switchToClient (line 61) | switchToClient(t){t!==this.currentClient&&(this.unmountDebug(),this.mo...
    method notifySubscribers (line 61) | notifySubscribers(){const t=this.getState();this.subscribers.forEach(e...
    method getState (line 61) | getState(){return{client:this.currentClient,debuggableClients:this.get...
    method getDebuggableClients (line 61) | getDebuggableClients(){return[...this.clients.values()].filter(t=>!1!=...
    method mountDebug (line 61) | mountDebug(t){if(!1===t.debugOpt||null!==this.debugPanel||"undefined"=...
    method unmountDebug (line 61) | unmountDebug(){this.debugPanel.$destroy(),this.debugPanel=null,this.cu...
    method constructor (line 147) | constructor(e){super(e),this.supportsBinary=!e.forceBase64}
    method name (line 147) | get name(){return"websocket"}
    method doOpen (line 147) | doOpen(){if(!this.check())return;const e=this.uri(),t=this.opts.protoc...
    method addEventListeners (line 147) | addEventListeners(){this.ws.onopen=(()=>{this.opts.autoUnref&&this.ws....
    method write (line 147) | write(t){this.writable=!1;for(let r=0;r<t.length;r++){const o=t[r],i=r...
    method onClose (line 147) | onClose(){t.prototype.onClose.call(this)}
    method doClose (line 147) | doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}
    method uri (line 147) | uri(){let e=this.query||{};const t=this.opts.secure?"wss":"ws";let s="...
    method check (line 147) | check(){return!(!n||"__initialize"in n&&this.name===l.prototype.name)}
    method constructor (line 178) | constructor({game:t,bots:e,storageKey:s,persist:a}){const n={},c={};if...
  function s (line 32) | function s(r,t){var n=e.Pointer.fromJSON(t.path).evaluate(r);if(null===n...
    method type (line 80) | type(){return e.ASYNC}
    method createMatch (line 80) | async createMatch(e,t){if(this.createGame)return console.warn("The dat...
    method listMatches (line 80) | async listMatches(e){if(this.listGames)return console.warn("The databa...
  function v (line 32) | function v(r,t){var n=e.Pointer.fromJSON(t.from).evaluate(r);if(void 0==...
  function c (line 32) | function c(r,n){var a=e.Pointer.fromJSON(n.from).evaluate(r);if(void 0==...
    method encode (line 164) | encode(t){return s("encoding packet %j",t),t.type!==n.EVENT&&t.type!==...
    method encodeAsString (line 164) | encodeAsString(t){let e=""+t.type;return t.type!==n.BINARY_EVENT&&t.ty...
    method encodeAsBinary (line 164) | encodeAsBinary(t){const r=e.deconstructPacket(t),s=this.encodeAsString...
    method constructor (line 170) | constructor(t,e,s){super(),this.receiveBuffer=[],this.sendBuffer=[],th...
    method subEvents (line 170) | subEvents(){if(this.subs)return;const t=this.io;this.subs=[e.on(t,"ope...
    method active (line 170) | get active(){return!!this.subs}
    method connect (line 170) | connect(){return this.connected?this:(this.subEvents(),this.io._reconn...
    method open (line 170) | open(){return this.connect()}
    method send (line 170) | send(...t){return t.unshift("message"),this.emit.apply(this,t),this}
    method emit (line 170) | emit(e,...s){if(n.hasOwnProperty(e))throw new Error('"'+e+'" is a rese...
    method packet (line 170) | packet(t){t.nsp=this.nsp,this.io._packet(t)}
    method onopen (line 170) | onopen(){i("transport is open - connecting"),"function"==typeof this.a...
    method onerror (line 170) | onerror(t){this.connected||this.emitReserved("connect_error",t)}
    method onclose (line 170) | onclose(t){i("close (%s)",t),this.connected=!1,this.disconnected=!0,de...
    method onpacket (line 170) | onpacket(e){if(e.nsp===this.nsp)switch(e.type){case t.PacketType.CONNE...
    method onevent (line 170) | onevent(t){const e=t.data||[];i("emitting event %j",e),null!=t.id&&(i(...
    method emitEvent (line 170) | emitEvent(t){if(this._anyListeners&&this._anyListeners.length){const e...
    method ack (line 170) | ack(e){const s=this;let n=!1;return function(...c){n||(n=!0,i("sending...
    method onack (line 170) | onack(t){const e=this.acks[t.id];"function"==typeof e?(i("calling ack ...
    method onconnect (line 170) | onconnect(t){i("socket connected with id %s",t),this.id=t,this.connect...
    method emitBuffered (line 170) | emitBuffered(){this.receiveBuffer.forEach(t=>this.emitEvent(t)),this.r...
    method ondisconnect (line 170) | ondisconnect(){i("server disconnect (%s)",this.nsp),this.destroy(),thi...
    method destroy (line 170) | destroy(){this.subs&&(this.subs.forEach(t=>t()),this.subs=void 0),this...
    method disconnect (line 170) | disconnect(){return this.connected&&(i("performing disconnect (%s)",th...
    method close (line 170) | close(){return this.disconnect()}
    method compress (line 170) | compress(t){return this.flags.compress=t,this}
    method volatile (line 170) | get volatile(){return this.flags.volatile=!0,this}
    method onAny (line 170) | onAny(t){return this._anyListeners=this._anyListeners||[],this._anyLis...
    method prependAny (line 170) | prependAny(t){return this._anyListeners=this._anyListeners||[],this._a...
    method offAny (line 170) | offAny(t){if(!this._anyListeners)return this;if(t){const e=this._anyLi...
    method listenersAny (line 170) | listenersAny(){return this._anyListeners||[]}
    method constructor (line 178) | constructor(t){super(),this.key=t,(JSON.parse(localStorage.getItem(thi...
    method sync (line 178) | sync(){const t=[...this.entries()];localStorage.setItem(this.key,JSON....
    method set (line 178) | set(t,e){return super.set(t,e),this.sync(),this}
    method delete (line 178) | delete(t){const e=super.delete(t);return this.sync(),e}
  function f (line 32) | function f(r,t){var o=e.Pointer.fromJSON(t.path).evaluate(r);return n.di...
  function t (line 32) | function t(r){var t=e.call(this,"Invalid operation: "+r.op)||this;return...
    method constructor (line 20) | constructor(t){const e=s();this.c=1,this.s0=e(" "),this.s1=e(" "),this...
    method next (line 20) | next(){const t=2091639*this.s0+2.3283064365386963e-10*this.c;return th...
    method constructor (line 59) | constructor({transportDataCallback:t,gameName:a,playerID:s,matchID:e,c...
    method subscribeToConnectionStatus (line 59) | subscribeToConnectionStatus(t){this.connectionStatusCallback=t}
    method setConnectionStatus (line 59) | setConnectionStatus(t){this.isConnected=t,this.connectionStatusCallbac...
    method notifyClient (line 59) | notifyClient(t){this.transportDataCallback(t)}
    method on (line 168) | on(e,t){return super.on(e,t),this}
    method once (line 168) | once(e,t){return super.once(e,t),this}
    method emit (line 168) | emit(e,...t){return super.emit(e,...t),this}
    method emitReserved (line 168) | emitReserved(e,...t){return super.emit(e,...t),this}
    method listeners (line 168) | listeners(e){return super.listeners(e)}
  function y (line 32) | function y(r,e){switch(e.op){case"add":return p(r,e);case"remove":return...
    method constructor (line 178) | constructor({socket:t,socketOpts:e,server:s,...i}){super(i),this.serve...
    method sendAction (line 178) | sendAction(t,e){const s=[e,t._stateID,this.matchID,this.playerID];this...
    method sendChatMessage (line 178) | sendChatMessage(t,e){const s=[t,e,this.credentials];this.socket.emit("...
    method connect (line 178) | connect(){if(!this.socket)if(this.server){let t=this.server;-1==t.sear...
    method disconnect (line 178) | disconnect(){this.socket.close(),this.socket=null,this.setConnectionSt...
    method requestSync (line 178) | requestSync(){if(this.socket){const t=[this.matchID,this.playerID,this...
    method updateMatchID (line 178) | updateMatchID(t){this.matchID=t,this.requestSync()}
    method updatePlayerID (line 178) | updatePlayerID(t){this.playerID=t,this.requestSync()}
    method updateCredentials (line 178) | updateCredentials(t){this.credentials=t,this.requestSync()}
    method constructor (line 180) | constructor(e){super(e),this.state={phase:i.ENTER,playerName:"Visitor"...
    method componentDidMount (line 180) | componentDidMount(){const e=n.default.load("lobbyState")||{};e.phase&&...
    method componentDidUpdate (line 180) | componentDidUpdate(e,t){const a=this.state.playerName,s=this.state.cre...
    method componentWillUnmount (line 180) | componentWillUnmount(){this._clearRefreshInterval()}
    method _startRefreshInterval (line 180) | _startRefreshInterval(){this._clearRefreshInterval(),this._currentInte...
    method _clearRefreshInterval (line 180) | _clearRefreshInterval(){clearInterval(this._currentInterval)}
    method render (line 180) | render(){const{gameComponents:e,renderer:t}=this.props,{errorMsg:a,pla...
  function n (line 34) | function n(r,t){return t.map(function(t){return e.apply(r,t)})}
    method constructor (line 20) | constructor(t){this.state=t||{seed:"0"},this.used=!1}
    method seed (line 20) | static seed(){return Date.now().toString(36).slice(-10)}
    method isUsed (line 20) | isUsed(){return this.used}
    method getState (line 20) | getState(){return this.state}
    method _random (line 20) | _random(){this.used=!0;const t=this.state,s=r(t.prngstate?"":t.seed,t....
    method api (line 20) | api(){const t=this._random.bind(this),s={D4:4,D6:6,D8:8,D10:10,D12:12,...
    method play (line 47) | play({G:t,ctx:e},r){const a=this.enumerate(t,e,r);return Promise.resol...
    method constructor (line 63) | constructor({server:e=""}={}){this.server=e.replace(/\/$/,"")}
    method request (line 63) | async request(e,t){const s=await fetch(this.server+e,t);if(!s.ok){let ...
    method post (line 63) | async post(e,t){let s={method:"post",body:JSON.stringify(t.body),heade...
    method listGames (line 63) | async listGames(e){return this.request("/games",e)}
    method listMatches (line 63) | async listMatches(e,s,r){t(e);let a="";if(s){const e=[],{isGameover:t,...
    method getMatch (line 63) | async getMatch(e,r,a){return t(e),s(r),this.request(`/games/${e}/${r}`...
    method createMatch (line 63) | async createMatch(e,s,a){return t(e),r(s,{numPlayers:"number"}),this.p...
    method joinMatch (line 63) | async joinMatch(e,a,n,i){return t(e),s(a),r(n,{playerID:["string","und...
    method leaveMatch (line 63) | async leaveMatch(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentials...
    method updatePlayer (line 63) | async updatePlayer(e,a,n,i){t(e),s(a),r(n,{playerID:"string",credentia...
    method playAgain (line 63) | async playAgain(e,a,n,i){return t(e),s(a),r(n,{playerID:"string",crede...
    method type (line 80) | type(){return e.SYNC}
    method connect (line 80) | connect(){}
    method createMatch (line 80) | createMatch(e,t){if(this.createGame)return console.warn("The database ...
    method listMatches (line 80) | listMatches(e){if(this.listGames)return console.warn("The database con...
    method constructor (line 151) | constructor(t,e={}){super(),t&&"object"==typeof t&&(e=t,t=null),t?(t=i...
    method createTransport (line 151) | createTransport(e){s('creating transport "%s"',e);const i=a(this.opts....
    method open (line 151) | open(){let t;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1...
    method setTransport (line 151) | setTransport(t){s("setting transport %s",t.name),this.transport&&(s("c...
    method probe (line 151) | probe(t){s('probing transport "%s"',t);let e=this.createTransport(t,{p...
    method onOpen (line 151) | onOpen(){if(s("socket open"),this.readyState="open",n.priorWebsocketSu...
    method onPacket (line 151) | onPacket(t){if("opening"===this.readyState||"open"===this.readyState||...
    method onHandshake (line 151) | onHandshake(t){this.emit("handshake",t),this.id=t.sid,this.transport.q...
    method resetPingTimeout (line 151) | resetPingTimeout(){clearTimeout(this.pingTimeoutTimer),this.pingTimeou...
    method onDrain (line 151) | onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBuffe...
    method flush (line 151) | flush(){"closed"!==this.readyState&&this.transport.writable&&!this.upg...
    method write (line 151) | write(t,e,s){return this.sendPacket("message",t,e,s),this}
    method send (line 151) | send(t,e,s){return this.sendPacket("message",t,e,s),this}
    method sendPacket (line 151) | sendPacket(t,e,s,r){if("function"==typeof e&&(r=e,e=void 0),"function"...
    method close (line 151) | close(){const t=()=>{this.onClose("forced close"),s("socket closing - ...
    method onError (line 151) | onError(t){s("socket error %j",t),n.priorWebsocketSuccess=!1,this.emit...
    method onClose (line 151) | onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"c...
    method filterUpgrades (line 151) | filterUpgrades(t){const e=[];let s=0;const r=t.length;for(;s<r;s++)~th...
  function a (line 34) | function a(r){return function e(n,a,i){var o=r(n,a,i);return Array.isArr...
    method constructor (line 47) | constructor({enumerate:t,seed:e}){this.enumerateFn=t,this.seed=e,this....
    method addOpt (line 47) | addOpt({key:t,range:e,initial:r}){this._opts[t]={range:e,value:r}}
    method getOpt (line 47) | getOpt(t){return this._opts[t].value}
    method setOpt (line 47) | setOpt(t,e){t in this._opts&&(this._opts[t].value=e)}
    method opts (line 47) | opts(){return this._opts}
    method enumerate (line 47) | enumerate(e,r,a){return this.enumerateFn(e,r,a).map(e=>"payload"in e?e...
    method random (line 47) | random(t){let r;if(void 0!==this.seed){const t=this.prngstate?"":this....
    method constructor (line 63) | constructor(e,t){super(e),this.details=t}
    method constructor (line 130) | constructor(t){if(super(t),"undefined"!=typeof location){const e="http...
    method request (line 130) | request(t={}){return Object.assign(t,{xd:this.xd,xs:this.xs},this.opts...
    method doWrite (line 130) | doWrite(t,e){const s=this.request({method:"POST",data:t});s.on("succes...
    method doPoll (line 130) | doPoll(){i("xhr poll");const t=this.request();t.on("data",this.onData....
    method constructor (line 164) | constructor(t){this.packet=t,this.buffers=[],this.reconPack=t}
    method takeBinaryData (line 164) | takeBinaryData(t){if(this.buffers.push(t),this.buffers.length===this.r...
    method finishedReconstruction (line 164) | finishedReconstruction(){this.reconPack=null,this.buffers=[]}
  function i (line 34) | function i(e,n,i){var o=new r.Pointer;return(i?a(i):t.diffAny)(e,n,o)}
    method constructor (line 47) | constructor({enumerate:t,seed:e,objectives:a,game:s,iterations:i,playo...
    method createNode (line 47) | createNode({state:t,parentAction:e,parent:r,playerID:a}){const{G:s,ctx...
    method select (line 47) | select(t){if(t.actions.length>0)return t;if(0===t.children.length)retu...
    method expand (line 47) | expand(t){const e=t.actions;if(0===e.length||void 0!==t.state.ctx.game...
    method playout (line 47) | playout({state:t}){let e=this.getOpt("playoutDepth");"function"==typeo...
    method backpropagate (line 47) | backpropagate(t,e={}){t.visits++,void 0!==e.score&&(t.value+=e.score),...
    method play (line 47) | play(t,e){const r=this.createNode({state:t,playerID:e});let a=this.get...
  function o (line 34) | function o(e,t){var n=r.Pointer.fromJSON(t).evaluate(e);if(void 0!==n)re...
    method constructor (line 82) | constructor(t,a,r,s){this.game=(0,e.P)(t),this.storageAPI=a,this.trans...
    method subscribe (line 82) | subscribe(t){this.subscribeCallback=t}
    method onUpdate (line 82) | async onUpdate(s,o,n,c){if(!s||!s.payload)return{error:"missing action...
    method onSync (line 82) | async onSync(t,a,e,i=2){const o=t,n={state:!0,metadata:!0,log:!0,initi...
    method onConnectionChange (line 82) | async onConnectionChange(t,e,i,o){const n=t;if(null==e)return;let c;if...
    method onChatMessage (line 82) | async onChatMessage(t,a,e){const r=t;if(this.auth){const{metadata:t}=a...
    method constructor (line 132) | constructor(e){super(e),this.query=this.query||{},s||(s=t.___eio=t.___...
    method supportsBinary (line 132) | get supportsBinary(){return!1}
    method doClose (line 132) | doClose(){this.script&&(this.script.onerror=(()=>{}),this.script.paren...
    method doPoll (line 132) | doPoll(){const e=document.createElement("script");this.script&&(this.s...
    method doWrite (line 132) | doWrite(e,t){let s;if(!this.form){const e=document.createElement("form...
    method constructor (line 164) | constructor(){super()}
    method add (line 164) | add(t){let e;if("string"==typeof t)(e=this.decodeString(t)).type===n.B...
    method decodeString (line 164) | decodeString(t){let e=0;const r={type:Number(t.charAt(0))};if(void 0==...
    method isPayloadValid (line 164) | static isPayloadValid(t,e){switch(t){case n.CONNECT:return"object"==ty...
    method destroy (line 164) | destroy(){this.reconstructor&&this.reconstructor.finishedReconstructio...
    method constructor (line 178) | constructor(t="bgio"){super();const e=e=>new c(`${t}_${e}`);this.state...
  function u (line 34) | function u(r,e){var n=new Array;return e.filter(t.isDestructive).forEach...
    method constructor (line 130) | constructor(t,e){super(),this.opts=e,this.method=e.method||"GET",this....
    method create (line 130) | create(){const e=o(this.opts,"agent","enablesXDR","pfx","key","passphr...
    method onSuccess (line 130) | onSuccess(){this.emit("success"),this.cleanup()}
    method onData (line 130) | onData(t){this.emit("data",t),this.onSuccess()}
    method onError (line 130) | onError(t){this.emit("error",t),this.cleanup(!0)}
    method cleanup (line 130) | cleanup(t){if(void 0!==this.xhr&&null!==this.xhr){if(this.hasXDR()?thi...
    method onLoad (line 130) | onLoad(){const t=this.xhr.responseText;null!==t&&this.onData(t)}
    method hasXDR (line 130) | hasXDR(){return"undefined"!=typeof XDomainRequest&&!this.xs&&this.enab...
    method abort (line 130) | abort(){this.cleanup()}
    method constructor (line 178) | constructor({master:t,...e}){super(e),this.master=t}
    method sendChatMessage (line 178) | sendChatMessage(t,e){const s=[t,e,this.credentials];this.master.onChat...
    method sendAction (line 178) | sendAction(t,e){this.master.onUpdate(e,t._stateID,this.matchID,this.pl...
    method requestSync (line 178) | requestSync(){this.master.onSync(this.matchID,this.playerID,this.crede...
    method connect (line 178) | connect(){this.setConnectionStatus(!0),this.master.connect(this.player...
    method disconnect (line 178) | disconnect(){this.setConnectionStatus(!1)}
    method updateMatchID (line 178) | updateMatchID(t){this.matchID=t,this.connect()}
    method updatePlayerID (line 178) | updatePlayerID(t){this.playerID=t,this.connect()}
    method updateCredentials (line 178) | updateCredentials(t){this.credentials=t,this.connect()}
    method constructor (line 180) | constructor(){super(...arguments),this.state={playerName:this.props.pl...
    method render (line 180) | render(){return s.default.createElement("div",null,s.default.createEle...
  function r (line 36) | function r({moves:e,phases:t,endIf:a,onEnd:r,turn:o,events:s,plugins:i})...
    method constructor (line 120) | constructor(e){super(),this.opts=e,this.query=e.query,this.readyState=...
    method onError (line 120) | onError(e,t){const s=new Error(e);return s.type="TransportError",s.des...
    method open (line 120) | open(){return"closed"!==this.readyState&&""!==this.readyState||(this.r...
    method close (line 120) | close(){return"opening"!==this.readyState&&"open"!==this.readyState||(...
    method send (line 120) | send(e){"open"===this.readyState?this.write(e):s("transport is not ope...
    method onOpen (line 120) | onOpen(){this.readyState="open",this.writable=!0,this.emit("open")}
    method onData (line 120) | onData(t){const s=e.decodePacket(t,this.socket.binaryType);this.onPack...
    method onPacket (line 120) | onPacket(e){this.emit("packet",e)}
    method onClose (line 120) | onClose(){this.readyState="closed",this.emit("close")}
    method constructor (line 174) | constructor(e,t){super(),this.nsps={},this.subs=[],e&&"object"==typeof...
    method reconnection (line 174) | reconnection(e){return arguments.length?(this._reconnection=!!e,this):...
    method reconnectionAttempts (line 174) | reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(...
    method reconnectionDelay (line 174) | reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(...
    method randomizationFactor (line 174) | randomizationFactor(e){var t;return void 0===e?this._randomizationFact...
    method reconnectionDelayMax (line 174) | reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDela...
    method timeout (line 174) | timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}
    method maybeReconnectOnOpen (line 174) | maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===th...
    method open (line 174) | open(t){if(c("readyState %s",this._readyState),~this._readyState.index...
    method connect (line 174) | connect(e){return this.open(e)}
    method onopen (line 174) | onopen(){c("open"),this.cleanup(),this._readyState="open",this.emitRes...
    method onping (line 174) | onping(){this.emitReserved("ping")}
    method ondata (line 174) | ondata(e){this.decoder.add(e)}
    method ondecoded (line 174) | ondecoded(e){this.emitReserved("packet",e)}
    method onerror (line 174) | onerror(e){c("error",e),this.emitReserved("error",e)}
    method socket (line 174) | socket(e,n){let i=this.nsps[e];return i||(i=new t.Socket(this,e,n),thi...
    method _destroy (line 174) | _destroy(e){const t=Object.keys(this.nsps);for(const n of t){if(this.n...
    method _packet (line 174) | _packet(e){c("writing packet %j",e);const t=this.encoder.encode(e);for...
    method cleanup (line 174) | cleanup(){c("cleanup"),this.subs.forEach(e=>e()),this.subs.length=0,th...
    method _close (line 174) | _close(){c("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,"...
    method disconnect (line 174) | disconnect(){return this._close()}
    method onclose (line 174) | onclose(e){c("onclose"),this.cleanup(),this.backoff.reset(),this._read...
    method reconnect (line 174) | reconnect(){if(this._reconnecting||this.skipReconnect)return this;cons...
    method onreconnect (line 174) | onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this...
    method constructor (line 178) | constructor(){super(),this.state=new Map,this.initial=new Map,this.met...
    method createMatch (line 178) | createMatch(t,e){this.initial.set(t,e.initialState),this.setState(t,e....
    method setMetadata (line 178) | setMetadata(t,e){this.metadata.set(t,e)}
    method setState (line 178) | setState(t,e,s){if(s&&s.length>0){const e=this.log.get(t)||[];this.log...
    method fetch (line 178) | fetch(t,e){const s={};return e.state&&(s.state=this.state.get(t)),e.me...
    method wipe (line 178) | wipe(t){this.state.delete(t),this.metadata.delete(t)}
    method listMatches (line 178) | listMatches(t){return[...this.metadata.entries()].filter(([,e])=>{if(!...
  function o (line 36) | function o(e){return void 0!==e.processMove}
    method constructor (line 82) | constructor(t,a,r,s){this.game=(0,e.P)(t),this.storageAPI=a,this.trans...
    method subscribe (line 82) | subscribe(t){this.subscribeCallback=t}
    method onUpdate (line 82) | async onUpdate(s,o,n,c){if(!s||!s.payload)return{error:"missing action...
    method onSync (line 82) | async onSync(t,a,e,i=2){const o=t,n={state:!0,metadata:!0,log:!0,initi...
    method onConnectionChange (line 82) | async onConnectionChange(t,e,i,o){const n=t;if(null==e)return;let c;if...
    method onChatMessage (line 82) | async onChatMessage(t,a,e){const r=t;if(this.auth){const{metadata:t}=a...
    method constructor (line 132) | constructor(e){super(e),this.query=this.query||{},s||(s=t.___eio=t.___...
    method supportsBinary (line 132) | get supportsBinary(){return!1}
    method doClose (line 132) | doClose(){this.script&&(this.script.onerror=(()=>{}),this.script.paren...
    method doPoll (line 132) | doPoll(){const e=document.createElement("script");this.script&&(this.s...
    method doWrite (line 132) | doWrite(e,t){let s;if(!this.form){const e=document.createElement("form...
    method constructor (line 164) | constructor(){super()}
    method add (line 164) | add(t){let e;if("string"==typeof t)(e=this.decodeString(t)).type===n.B...
    method decodeString (line 164) | decodeString(t){let e=0;const r={type:Number(t.charAt(0))};if(void 0==...
    method isPayloadValid (line 164) | static isPayloadValid(t,e){switch(t){case n.CONNECT:return"object"==ty...
    method destroy (line 164) | destroy(){this.reconstructor&&this.reconstructor.finishedReconstructio...
    method constructor (line 178) | constructor(t="bgio"){super();const e=e=>new c(`${t}_${e}`);this.state...
  function s (line 36) | function s(e){if(o(e))return e;if(void 0===e.name&&(e.name="default"),vo...
    method type (line 80) | type(){return e.ASYNC}
    method createMatch (line 80) | async createMatch(e,t){if(this.createGame)return console.warn("The dat...
    method listMatches (line 80) | async listMatches(e){if(this.listGames)return console.warn("The databa...
  function i (line 36) | function i(e){return e instanceof Object&&void 0!==e.move}
    method constructor (line 47) | constructor({enumerate:t,seed:e,objectives:a,game:s,iterations:i,playo...
    method createNode (line 47) | createNode({state:t,parentAction:e,parent:r,playerID:a}){const{G:s,ctx...
    method select (line 47) | select(t){if(t.actions.length>0)return t;if(0===t.children.length)retu...
    method expand (line 47) | expand(t){const e=t.actions;if(0===e.length||void 0!==t.state.ctx.game...
    method playout (line 47) | playout({state:t}){let e=this.getOpt("playoutDepth");"function"==typeo...
    method backpropagate (line 47) | backpropagate(t,e={}){t.visits++,void 0!==e.score&&(t.value+=e.score),...
    method play (line 47) | play(t,e){const r=this.createNode({state:t,playerID:e});let a=this.get...
  function l (line 36) | function l(e,t){if(t.game.disableUndo)return e;const n={G:e.G,ctx:e.ctx,...
    method constructor (line 61) | constructor(){this.debugPanel=null,this.currentClient=null,this.client...
    method register (line 61) | register(t){this.clients.set(t,t),this.mountDebug(t),this.notifySubscr...
    method unregister (line 61) | unregister(t){if(this.clients.delete(t),this.currentClient===t){this.u...
    method subscribe (line 61) | subscribe(t){const e=Symbol();return this.subscribers.set(e,t),t(this....
    method switchPlayerID (line 61) | switchPlayerID(t){if(this.currentClient.multiplayer)for(const[e]of thi...
    method switchToClient (line 61) | switchToClient(t){t!==this.currentClient&&(this.unmountDebug(),this.mo...
    method notifySubscribers (line 61) | notifySubscribers(){const t=this.getState();this.subscribers.forEach(e...
    method getState (line 61) | getState(){return{client:this.currentClient,debuggableClients:this.get...
    method getDebuggableClients (line 61) | getDebuggableClients(){return[...this.clients.values()].filter(t=>!1!=...
    method mountDebug (line 61) | mountDebug(t){if(!1===t.debugOpt||null!==this.debugPanel||"undefined"=...
    method unmountDebug (line 61) | unmountDebug(){this.debugPanel.$destroy(),this.debugPanel=null,this.cu...
    method constructor (line 147) | constructor(e){super(e),this.supportsBinary=!e.forceBase64}
    method name (line 147) | get name(){return"websocket"}
    method doOpen (line 147) | doOpen(){if(!this.check())return;const e=this.uri(),t=this.opts.protoc...
    method addEventListeners (line 147) | addEventListeners(){this.ws.onopen=(()=>{this.opts.autoUnref&&this.ws....
    method write (line 147) | write(t){this.writable=!1;for(let r=0;r<t.length;r++){const o=t[r],i=r...
    method onClose (line 147) | onClose(){t.prototype.onClose.call(this)}
    method doClose (line 147) | doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}
    method uri (line 147) | uri(){let e=this.query||{};const t=this.opts.secure?"wss":"ws";let s="...
    method check (line 147) | check(){return!(!n||"__initialize"in n&&this.name===l.prototype.name)}
    method constructor (line 178) | constructor({game:t,bots:e,storageKey:s,persist:a}){const n={},c={};if...
  function d (line 36) | function d(e,t,n){const a={action:t,_stateID:e._stateID,turn:e.ctx.turn,...
    method constructor (line 180) | constructor(e){super(e),this.state={selectedGame:0,numPlayers:2},this....
    method render (line 180) | render(){return s.default.createElement("div",null,s.default.createEle...
  function p (line 36) | function p(e,a,r){const[o,s]=(0,n.q)(e,r);return s?[o,f(a,t.PluginAction...
    method name (line 126) | get name(){return"polling"}
    method doOpen (line 126) | doOpen(){this.poll()}
    method pause (line 126) | pause(t){this.readyState="pausing";const e=()=>{o("paused"),this.ready...
    method poll (line 126) | poll(){o("polling"),this.polling=!0,this.doPoll(),this.emit("poll")}
    method onData (line 126) | onData(t){o("polling got data %s",t);s.decodePayload(t,this.socket.bin...
    method doClose (line 126) | doClose(){const t=()=>{o("writing close packet"),this.write([{type:"cl...
    method write (line 126) | write(t){this.writable=!1,s.encodePayload(t,t=>{this.doWrite(t,()=>{th...
    method uri (line 126) | uri(){let t=this.query||{};const s=this.opts.secure?"https":"http";let...
    method constructor (line 180) | constructor(){super(...arguments),this._createSeat=(e=>e.name||"[free]...
    method render (line 180) | render(){const e=this.props.match;let t="OPEN";return e.players.some(e...
  function v (line 36) | function v(e){if(!e)return[null,void 0];const{transients:t,...n}=e;retur...
  function f (line 36) | function f(e,t,n){return{...e,transients:{error:{type:t,payload:n}}}}
  function g (line 36) | function g({game:r,isClient:o}){return r=s(r),(s=null,i)=>{let[y]=v(s);s...
  function x (line 38) | function x(t,e){if(y)return y=!y,e;const s=r.call(this,t,e);switch(typeo...
  function r (line 41) | function r(){throw new Error("setTimeout has not been defined")}
    method constructor (line 120) | constructor(e){super(),this.opts=e,this.query=e.query,this.readyState=...
    method onError (line 120) | onError(e,t){const s=new Error(e);return s.type="TransportError",s.des...
    method open (line 120) | open(){return"closed"!==this.readyState&&""!==this.readyState||(this.r...
    method close (line 120) | close(){return"opening"!==this.readyState&&"open"!==this.readyState||(...
    method send (line 120) | send(e){"open"===this.readyState?this.write(e):s("transport is not ope...
    method onOpen (line 120) | onOpen(){this.readyState="open",this.writable=!0,this.emit("open")}
    method onData (line 120) | onData(t){const s=e.decodePacket(t,this.socket.binaryType);this.onPack...
    method onPacket (line 120) | onPacket(e){this.emit("packet",e)}
    method onClose (line 120) | onClose(){this.readyState="closed",this.emit("close")}
    method constructor (line 174) | constructor(e,t){super(),this.nsps={},this.subs=[],e&&"object"==typeof...
    method reconnection (line 174) | reconnection(e){return arguments.length?(this._reconnection=!!e,this):...
    method reconnectionAttempts (line 174) | reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(...
    method reconnectionDelay (line 174) | reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(...
    method randomizationFactor (line 174) | randomizationFactor(e){var t;return void 0===e?this._randomizationFact...
    method reconnectionDelayMax (line 174) | reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDela...
    method timeout (line 174) | timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}
    method maybeReconnectOnOpen (line 174) | maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===th...
    method open (line 174) | open(t){if(c("readyState %s",this._readyState),~this._readyState.index...
    method connect (line 174) | connect(e){return this.open(e)}
    method onopen (line 174) | onopen(){c("open"),this.cleanup(),this._readyState="open",this.emitRes...
    method onping (line 174) | onping(){this.emitReserved("ping")}
    method ondata (line 174) | ondata(e){this.decoder.add(e)}
    method ondecoded (line 174) | ondecoded(e){this.emitReserved("packet",e)}
    method onerror (line 174) | onerror(e){c("error",e),this.emitReserved("error",e)}
    method socket (line 174) | socket(e,n){let i=this.nsps[e];return i||(i=new t.Socket(this,e,n),thi...
    method _destroy (line 174) | _destroy(e){const t=Object.keys(this.nsps);for(const n of t){if(this.n...
    method _packet (line 174) | _packet(e){c("writing packet %j",e);const t=this.encoder.encode(e);for...
    method cleanup (line 174) | cleanup(){c("cleanup"),this.subs.forEach(e=>e()),this.subs.length=0,th...
    method _close (line 174) | _close(){c("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,"...
    method disconnect (line 174) | disconnect(){return this._close()}
    method onclose (line 174) | onclose(e){c("onclose"),this.cleanup(),this.backoff.reset(),this._read...
    method reconnect (line 174) | reconnect(){if(this._reconnecting||this.skipReconnect)return this;cons...
    method onreconnect (line 174) | onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this...
    method constructor (line 178) | constructor(){super(),this.state=new Map,this.initial=new Map,this.met...
    method createMatch (line 178) | createMatch(t,e){this.initial.set(t,e.initialState),this.setState(t,e....
    method setMetadata (line 178) | setMetadata(t,e){this.metadata.set(t,e)}
    method setState (line 178) | setState(t,e,s){if(s&&s.length>0){const e=this.log.get(t)||[];this.log...
    method fetch (line 178) | fetch(t,e){const s={};return e.state&&(s.state=this.state.get(t)),e.me...
    method wipe (line 178) | wipe(t){this.state.delete(t),this.metadata.delete(t)}
    method listMatches (line 178) | listMatches(t){return[...this.metadata.entries()].filter(([,e])=>{if(!...
  function o (line 41) | function o(){throw new Error("clearTimeout has not been defined")}
    method constructor (line 82) | constructor(t,a,r,s){this.game=(0,e.P)(t),this.storageAPI=a,this.trans...
    method subscribe (line 82) | subscribe(t){this.subscribeCallback=t}
    method onUpdate (line 82) | async onUpdate(s,o,n,c){if(!s||!s.payload)return{error:"missing action...
    method onSync (line 82) | async onSync(t,a,e,i=2){const o=t,n={state:!0,metadata:!0,log:!0,initi...
    method onConnectionChange (line 82) | async onConnectionChange(t,e,i,o){const n=t;if(null==e)return;let c;if...
    method onChatMessage (line 82) | async onChatMessage(t,a,e){const r=t;if(this.auth){const{metadata:t}=a...
    method constructor (line 132) | constructor(e){super(e),this.query=this.query||{},s||(s=t.___eio=t.___...
    method supportsBinary (line 132) | get supportsBinary(){return!1}
    method doClose (line 132) | doClose(){this.script&&(this.script.onerror=(()=>{}),this.script.paren...
    method doPoll (line 132) | doPoll(){const e=document.createElement("script");this.script&&(this.s...
    method doWrite (line 132) | doWrite(e,t){let s;if(!this.form){const e=document.createElement("form...
    method constructor (line 164) | constructor(){super()}
    method add (line 164) | add(t){let e;if("string"==typeof t)(e=this.decodeString(t)).type===n.B...
    method decodeString (line 164) | decodeString(t){let e=0;const r={type:Number(t.charAt(0))};if(void 0==...
    method isPayloadValid (line 164) | static isPayloadValid(t,e){switch(t){case n.CONNECT:return"object"==ty...
    method destroy (line 164) | destroy(){this.reconstructor&&this.reconstructor.finishedReconstructio...
    method constructor (line 178) | constructor(t="bgio"){super();const e=e=>new c(`${t}_${e}`);this.state...
  function i (line 41) | function i(e){if(t===setTimeout)return setTimeout(e,0);if((t===r||!t)&&s...
    method constructor (line 47) | constructor({enumerate:t,seed:e,objectives:a,game:s,iterations:i,playo...
    method createNode (line 47) | createNode({state:t,parentAction:e,parent:r,playerID:a}){const{G:s,ctx...
    method select (line 47) | select(t){if(t.actions.length>0)return t;if(0===t.children.length)retu...
    method expand (line 47) | expand(t){const e=t.actions;if(0===e.length||void 0!==t.state.ctx.game...
    method playout (line 47) | playout({state:t}){let e=this.getOpt("playoutDepth");"function"==typeo...
    method backpropagate (line 47) | backpropagate(t,e={}){t.visits++,void 0!==e.score&&(t.value+=e.score),...
    method play (line 47) | play(t,e){const r=this.createNode({state:t,playerID:e});let a=this.get...
  function u (line 41) | function u(t){if(e===clearTimeout)return clearTimeout(t);if((e===o||!e)&...
    method constructor (line 130) | constructor(t,e){super(),this.opts=e,this.method=e.method||"GET",this....
    method create (line 130) | create(){const e=o(this.opts,"agent","enablesXDR","pfx","key","passphr...
    method onSuccess (line 130) | onSuccess(){this.emit("success"),this.cleanup()}
    method onData (line 130) | onData(t){this.emit("data",t),this.onSuccess()}
    method onError (line 130) | onError(t){this.emit("error",t),this.cleanup(!0)}
    method cleanup (line 130) | cleanup(t){if(void 0!==this.xhr&&null!==this.xhr){if(this.hasXDR()?thi...
    method onLoad (line 130) | onLoad(){const t=this.xhr.responseText;null!==t&&this.onData(t)}
    method hasXDR (line 130) | hasXDR(){return"undefined"!=typeof XDomainRequest&&!this.xs&&this.enab...
    method abort (line 130) | abort(){this.cleanup()}
    method constructor (line 178) | constructor({master:t,...e}){super(e),this.master=t}
    method sendChatMessage (line 178) | sendChatMessage(t,e){const s=[t,e,this.credentials];this.master.onChat...
    method sendAction (line 178) | sendAction(t,e){this.master.onUpdate(e,t._stateID,this.matchID,this.pl...
    method requestSync (line 178) | requestSync(){this.master.onSync(this.matchID,this.playerID,this.crede...
    method connect (line 178) | connect(){this.setConnectionStatus(!0),this.master.connect(this.player...
    method disconnect (line 178) | disconnect(){this.setConnectionStatus(!1)}
    method updateMatchID (line 178) | updateMatchID(t){this.matchID=t,this.connect()}
    method updatePlayerID (line 178) | updatePlayerID(t){this.playerID=t,this.connect()}
    method updateCredentials (line 178) | updateCredentials(t){this.credentials=t,this.connect()}
    method constructor (line 180) | constructor(){super(...arguments),this.state={playerName:this.props.pl...
    method render (line 180) | render(){return s.default.createElement("div",null,s.default.createEle...
  function f (line 41) | function f(){l&&c&&(l=!1,c.length?s=c.concat(s):a=-1,s.length&&h())}
  function h (line 41) | function h(){if(!l){var t=i(f);l=!0;for(var e=s.length;e;){for(c=s,s=[];...
    method connect (line 61) | connect(){}
    method disconnect (line 61) | disconnect(){}
    method sendAction (line 61) | sendAction(){}
    method sendChatMessage (line 61) | sendChatMessage(){}
    method requestSync (line 61) | requestSync(){}
    method updateCredentials (line 61) | updateCredentials(){}
    method updateMatchID (line 61) | updateMatchID(){}
    method updatePlayerID (line 61) | updatePlayerID(){}
    method constructor (line 180) | constructor({server:e,gameComponents:t,playerName:s,playerCredentials:...
    method refresh (line 180) | async refresh(){try{this.matches=[];const t=await this.client.listGame...
    method _getMatchInstance (line 180) | _getMatchInstance(e){for(const t of this.matches)if(t.matchID===e)retu...
    method _getGameComponents (line 180) | _getGameComponents(e){for(const t of this.gameComponents)if(t.game.nam...
    method _findPlayer (line 180) | _findPlayer(e){for(const t of this.matches)if(t.players.some(t=>t.name...
    method join (line 180) | async join(e,t,a){try{let r=this._findPlayer(this.playerName);if(r)thr...
    method leave (line 180) | async leave(e,t){try{const s=this._getMatchInstance(t);if(!s)throw new...
    method disconnect (line 180) | async disconnect(){const e=this._findPlayer(this.playerName);e&&await ...
    method create (line 180) | async create(e,t){try{const s=this._getGameComponents(e);if(!s)throw n...
  function m (line 41) | function m(t,e){this.fun=t,this.array=e}
    method constructor (line 61) | constructor({game:e,debug:n,numPlayers:h,multiplayer:l,matchID:g,playe...
    method receiveMatchData (line 61) | receiveMatchData(t){this.matchData=t,this.notifySubscribers()}
    method receiveChatMessage (line 61) | receiveChatMessage(t){this.chatMessages=[...this.chatMessages,t],this....
    method receiveTransportData (line 61) | receiveTransportData(t){const[e]=t.args;if(e===this.matchID)switch(t.t...
    method notifySubscribers (line 61) | notifySubscribers(){Object.values(this.subscribers).forEach(t=>t(this....
    method overrideGameState (line 61) | overrideGameState(t){this.gameStateOverride=t,this.notifySubscribers()}
    method start (line 61) | start(){this.transport.connect(),this._running=!0,this.manager.registe...
    method stop (line 61) | stop(){this.transport.disconnect(),this._running=!1,this.manager.unreg...
    method subscribe (line 61) | subscribe(t){const e=Object.keys(this.subscribers).length;return this....
    method getInitialState (line 61) | getInitialState(){return this.initialState}
    method getState (line 61) | getState(){let t=this.store.getState();if(null!==this.gameStateOverrid...
    method createDispatchers (line 61) | createDispatchers(){this.moves=b(this.game.moveNames,this.store,this.p...
    method updatePlayerID (line 61) | updatePlayerID(t){this.playerID=t,this.createDispatchers(),this.transp...
    method updateMatchID (line 61) | updateMatchID(t){this.matchID=t,this.createDispatchers(),this.transpor...
    method updateCredentials (line 61) | updateCredentials(t){this.credentials=t,this.createDispatchers(),this....
  function p (line 41) | function p(){}
    method name (line 126) | get name(){return"polling"}
    method doOpen (line 126) | doOpen(){this.poll()}
    method pause (line 126) | pause(t){this.readyState="pausing";const e=()=>{o("paused"),this.ready...
    method poll (line 126) | poll(){o("polling"),this.polling=!0,this.doPoll(),this.emit("poll")}
    method onData (line 126) | onData(t){o("polling got data %s",t);s.decodePayload(t,this.socket.bin...
    method doClose (line 126) | doClose(){const t=()=>{o("writing close packet"),this.write([{type:"cl...
    method write (line 126) | write(t){this.writable=!1,s.encodePayload(t,t=>{this.doWrite(t,()=>{th...
    method uri (line 126) | uri(){let t=this.query||{};const s=this.opts.secure?"https":"http";let...
    method constructor (line 180) | constructor(){super(...arguments),this._createSeat=(e=>e.name||"[free]...
    method render (line 180) | render(){const e=this.props.match;let t="OPEN";return e.players.some(e...
  function g (line 45) | function g(e){delete f[e]}
  function m (line 45) | function m(e){if(u)setTimeout(m,0,e);else{var t=f[e];if(t){u=!0;try{!fun...
    method constructor (line 61) | constructor({game:e,debug:n,numPlayers:h,multiplayer:l,matchID:g,playe...
    method receiveMatchData (line 61) | receiveMatchData(t){this.matchData=t,this.notifySubscribers()}
    method receiveChatMessage (line 61) | receiveChatMessage(t){this.chatMessages=[...this.chatMessages,t],this....
    method receiveTransportData (line 61) | receiveTransportData(t){const[e]=t.args;if(e===this.matchID)switch(t.t...
    method notifySubscribers (line 61) | notifySubscribers(){Object.values(this.subscribers).forEach(t=>t(this....
    method overrideGameState (line 61) | overrideGameState(t){this.gameStateOverride=t,this.notifySubscribers()}
    method start (line 61) | start(){this.transport.connect(),this._running=!0,this.man
Condensed preview — 332 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,064K chars).
[
  {
    "path": ".devcontainer/Dockerfile",
    "chars": 842,
    "preview": "# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.191.1/containers/typescript-no"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "chars": 1109,
    "preview": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:\n// https://github.co"
  },
  {
    "path": ".empty_module.js",
    "chars": 279,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": ".eslintignore",
    "chars": 64,
    "preview": "examples/\ndist/\nnode_modules/\ncoverage/\nnpm/\ndocs/\nintegration/\n"
  },
  {
    "path": ".eslintrc",
    "chars": 1143,
    "preview": "extends:\n- eslint:recommended\n- plugin:jest/recommended\n- plugin:unicorn/recommended\n- plugin:react/recommended\n- plugin"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 98,
    "preview": "# These are supported funding model platforms\n\ngithub: [boardgameio]\nopen_collective: boardgameio\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 144,
    "preview": "#### Checklist\n\n- [ ] Use a separate branch in your local repo (not `main`).\n- [ ] Test coverage is 100% (or you have a "
  },
  {
    "path": ".github/workflows/npm-publish.yml",
    "chars": 989,
    "preview": "name: Publish\n\non:\n  push:\n    tags: [ 'v0.[0-9]+.[0-9]+' ]\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    steps:\n    "
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 1116,
    "preview": "name: Tests\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  unit:\n    runs-on: ubunt"
  },
  {
    "path": ".gitignore",
    "chars": 135,
    "preview": ".cache\nyarn.lock\n.DS_Store\n*.swp\nnpm-debug.log*\ndist\nnode_modules\ncoverage\n.coveralls.yml\n.npm\nnpm\n.idea/\n.vscode/*\n.rpt"
  },
  {
    "path": ".lintstagedrc",
    "chars": 45,
    "preview": "{\n  \"*.{ts,js,css,md}\": \"prettier --write\"\n}\n"
  },
  {
    "path": ".prettierignore",
    "chars": 65,
    "preview": "*.bundle.js\n*.min.js\nnode_modules\ndist\nGame.md\npackage.json\ndocs\n"
  },
  {
    "path": ".prettierrc",
    "chars": 47,
    "preview": "{\n  \"printWidth\": 80,\n  \"singleQuote\": true,\n}\n"
  },
  {
    "path": "AUTHORS",
    "chars": 429,
    "preview": "# List of contributors. This is by no means meant to be\n# comprehensive (git history is a good way to get the\n# exhausti"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 1111,
    "preview": "# Community Guidelines\n\nA safe, respectful, productive and collaborative environment is important for the boardgame.io c"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2888,
    "preview": "# How to Contribute\n\n## Finding things to contribute to\n\nPlease use the [Issue Tracker](https://github.com/boardgameio/b"
  },
  {
    "path": "LICENSE",
    "chars": 1082,
    "preview": "MIT License\n\nCopyright (c) 2017 The boardgame.io Authors.\n\nPermission is hereby granted, free of charge, to any person o"
  },
  {
    "path": "README.md",
    "chars": 4003,
    "preview": "<p align=\"center\">\n  <a href=\"https://boardgame.io/\">\n    <img src=\"https://raw.githubusercontent.com/boardgameio/boardg"
  },
  {
    "path": "babel.config.js",
    "chars": 573,
    "preview": "module.exports = {\n  presets: [\n    [\n      '@babel/preset-env',\n      {\n        modules: false,\n        exclude: ['tran"
  },
  {
    "path": "benchmark/index.js",
    "chars": 1201,
    "preview": "/*\n * Copyright 2019 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "docs/CNAME",
    "chars": 12,
    "preview": "boardgame.io"
  },
  {
    "path": "docs/documentation/.nojekyll",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/documentation/CHANGELOG.md",
    "chars": 76750,
    "preview": "### v0.50.2\n\nThis release includes dependency upgrades only.\n\n### v0.50.1\n\nThis release fixes compatibility with React v"
  },
  {
    "path": "docs/documentation/api/Client.md",
    "chars": 9546,
    "preview": "# Client\n\nCreates a `boardgame.io` client. This is the entry point for\nthe client application.\n\n<!-- tabs:start -->\n\n###"
  },
  {
    "path": "docs/documentation/api/Game.md",
    "chars": 4146,
    "preview": "# Game\n\n?> Using TypeScript? Check out [the TypeScript docs](typescript.md) on how to type your game object.\n\n```js\n{\n  "
  },
  {
    "path": "docs/documentation/api/Lobby.md",
    "chars": 6771,
    "preview": "# Lobby\n\nThe [Server](/api/Server) hosts the Lobby REST API that can be used to create\nand join matches. It is particula"
  },
  {
    "path": "docs/documentation/api/Server.md",
    "chars": 6951,
    "preview": "# Server\n\nCreates a `boardgame.io` server. This is only required when\n`multiplayer` is set to `true` on the client. It c"
  },
  {
    "path": "docs/documentation/chat.md",
    "chars": 1835,
    "preview": "# Chat\n\nThe boardgame.io client provides a basic API for sending chat messages between players in a match using the [mul"
  },
  {
    "path": "docs/documentation/concepts.md",
    "chars": 3153,
    "preview": "# Concepts\n\n### State\n\nboardgame.io captures game state in two objects: `G` and `ctx`.\n\n```js\n{\n  // The game state (man"
  },
  {
    "path": "docs/documentation/debugging.md",
    "chars": 2661,
    "preview": "# Debugging\n\n### Using the Debug Panel in production\n\nboardgame.io comes bundled with a debug panel that lets you\nintera"
  },
  {
    "path": "docs/documentation/deployment.md",
    "chars": 5748,
    "preview": "# Deployment\n\n## Serverless Options\n\nFor one-player or pass-and-play games, you may not need the boardgame.io game\nserve"
  },
  {
    "path": "docs/documentation/events.md",
    "chars": 5121,
    "preview": "# Events\n\nAn event is used to advance the game state. It is somewhat\nanalogous to a move, except that while a move chang"
  },
  {
    "path": "docs/documentation/immutability.md",
    "chars": 2505,
    "preview": "# Immutability\n\nThe principle of immutability as applied to state changing\nfunctions like moves in [boardgame.io](https:"
  },
  {
    "path": "docs/documentation/index.html",
    "chars": 3377,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>boardgame.io</title>\n  <meta name=\"description"
  },
  {
    "path": "docs/documentation/multiplayer.md",
    "chars": 10585,
    "preview": "# Multiplayer\n\nIn this section, we'll explain how the framework converts your\ngame logic into a multiplayer implementati"
  },
  {
    "path": "docs/documentation/notable_projects.md",
    "chars": 12086,
    "preview": "# Projects\n\nNonexhaustive list of notable projects using boardgame.io. Feel free to send a PR to add your project to thi"
  },
  {
    "path": "docs/documentation/phases.md",
    "chars": 5570,
    "preview": "# Phases\n\nMost games beyond very simple ones tend to have different\nbehaviors at various phases. A game might have a pha"
  },
  {
    "path": "docs/documentation/plugins.md",
    "chars": 4647,
    "preview": "# Plugins\n\nThe Plugin API allows you to create objects that expose\ncustom functionality to [boardgame.io](https://boardg"
  },
  {
    "path": "docs/documentation/random.md",
    "chars": 3247,
    "preview": "# Randomness\n\nMany games allow moves whose outcome depends on shuffled cards or rolled dice.\nTake e.g. the game [Yahtzee"
  },
  {
    "path": "docs/documentation/secret-state.md",
    "chars": 1971,
    "preview": "# Secret State\n\nIn some games you might need to hide information from\nplayers or spectators. For example, you might not "
  },
  {
    "path": "docs/documentation/sidebar.md",
    "chars": 739,
    "preview": "- **Getting Started**\n  - [Concepts](/)\n  - [Tutorial](tutorial.md)\n- **Guides**\n  - [Multiplayer](multiplayer.md)\n  - ["
  },
  {
    "path": "docs/documentation/snippets/example-1/index.html",
    "chars": 339,
    "preview": "<!DOCTYPE html><html><head><style>body{padding:20px}.msg{position:absolute;bottom:0;left:20px;color:#aaa;font-size:12px;"
  },
  {
    "path": "docs/documentation/snippets/example-1.c952ec6d.js",
    "chars": 433929,
    "preview": "parcelRequire=function(e,r,t,n){var i,o=\"function\"==typeof parcelRequire&&parcelRequire,u=\"function\"==typeof require&&re"
  },
  {
    "path": "docs/documentation/snippets/example-2/index.html",
    "chars": 339,
    "preview": "<!DOCTYPE html><html><head><style>body{padding:20px}.msg{position:absolute;bottom:0;left:20px;color:#aaa;font-size:12px;"
  },
  {
    "path": "docs/documentation/snippets/example-2.e4675089.js",
    "chars": 436185,
    "preview": "parcelRequire=function(e,r,t,n){var i,o=\"function\"==typeof parcelRequire&&parcelRequire,u=\"function\"==typeof require&&re"
  },
  {
    "path": "docs/documentation/snippets/example-3/index.html",
    "chars": 339,
    "preview": "<!DOCTYPE html><html><head><style>body{padding:20px}.msg{position:absolute;bottom:0;left:20px;color:#aaa;font-size:12px;"
  },
  {
    "path": "docs/documentation/snippets/example-3.1fa4f5db.js",
    "chars": 436302,
    "preview": "parcelRequire=function(e,r,t,n){var i,o=\"function\"==typeof parcelRequire&&parcelRequire,u=\"function\"==typeof require&&re"
  },
  {
    "path": "docs/documentation/snippets/multiplayer/index.html",
    "chars": 359,
    "preview": "<!DOCTYPE html><html><head><style>body{padding:1.25rem}.msg{position:absolute;bottom:0;left:1.25rem;color:#aaa;font-size"
  },
  {
    "path": "docs/documentation/snippets/multiplayer.54b541fd.js",
    "chars": 436133,
    "preview": "parcelRequire=function(e,r,t,n){var i,o=\"function\"==typeof parcelRequire&&parcelRequire,u=\"function\"==typeof require&&re"
  },
  {
    "path": "docs/documentation/snippets/phases-1/index.html",
    "chars": 231,
    "preview": "<!DOCTYPE html><html><link rel=\"stylesheet\" href=\"/documentation/snippets/phases-1.490dcd4c.css\"><body> <div id=\"app\"></"
  },
  {
    "path": "docs/documentation/snippets/phases-1.0d4500d6.js",
    "chars": 309124,
    "preview": "parcelRequire=function(e,r,t,n){var i,o=\"function\"==typeof parcelRequire&&parcelRequire,u=\"function\"==typeof require&&re"
  },
  {
    "path": "docs/documentation/snippets/phases-1.490dcd4c.css",
    "chars": 679,
    "preview": ".deck.svelte-1b6u8ju.svelte-1b6u8ju{font-family:monospace;width:40px;height:60px;margin-left:auto;margin-right:auto;bord"
  },
  {
    "path": "docs/documentation/snippets/phases-2/index.html",
    "chars": 231,
    "preview": "<!DOCTYPE html><html><link rel=\"stylesheet\" href=\"/documentation/snippets/phases-2.fa21cb61.css\"><body> <div id=\"app\"></"
  },
  {
    "path": "docs/documentation/snippets/phases-2.a59f38ac.js",
    "chars": 309508,
    "preview": "parcelRequire=function(e,r,t,n){var i,o=\"function\"==typeof parcelRequire&&parcelRequire,u=\"function\"==typeof require&&re"
  },
  {
    "path": "docs/documentation/snippets/phases-2.fa21cb61.css",
    "chars": 749,
    "preview": ".phase.svelte-shmgoi.svelte-shmgoi{font-size:1.2em;margin-top:20px;color:#aaa}.deck.svelte-shmgoi.svelte-shmgoi{font-fam"
  },
  {
    "path": "docs/documentation/snippets/stages-1/index.html",
    "chars": 231,
    "preview": "<!DOCTYPE html><html><link rel=\"stylesheet\" href=\"/documentation/snippets/stages-1.bcf7ab84.css\"><body> <div id=\"app\"></"
  },
  {
    "path": "docs/documentation/snippets/stages-1.1524ef02.js",
    "chars": 308345,
    "preview": "parcelRequire=function(e,r,t,n){var i,o=\"function\"==typeof parcelRequire&&parcelRequire,u=\"function\"==typeof require&&re"
  },
  {
    "path": "docs/documentation/snippets/stages-1.bcf7ab84.css",
    "chars": 434,
    "preview": ".client.svelte-temvio.svelte-temvio{border-radius:5px;width:100px;border:1px solid #ddd;background:#fafafa;opacity:.8}.c"
  },
  {
    "path": "docs/documentation/stages.md",
    "chars": 7533,
    "preview": "# Stages\n\nA stage is similar to a phase, except that it happens within a turn.\nA turn can be subdivided into many stages"
  },
  {
    "path": "docs/documentation/storage.md",
    "chars": 1575,
    "preview": "# Storage\n\n**boardgame.io** is storage agnostic. Various adapters are\navailable that allow you to persist your game stat"
  },
  {
    "path": "docs/documentation/testing.md",
    "chars": 5012,
    "preview": "# Testing Strategies\n\n### Unit Tests\n\nMoves are just functions, so they lend themselves to unit testing.\nA useful strate"
  },
  {
    "path": "docs/documentation/theme.css",
    "chars": 2008,
    "preview": ":root {\n  --theme-hue: 152;\n  --theme-lightness : 26%;\n  --mono-hue: calc(var(--theme-hue) + 400);\n  --mono-saturation: "
  },
  {
    "path": "docs/documentation/turn-order.md",
    "chars": 3490,
    "preview": "# Turn Order\n\nThe framework's default behavior is to pass the turn around\nin a round-robin fashion. A player makes one o"
  },
  {
    "path": "docs/documentation/tutorial.md",
    "chars": 18698,
    "preview": "# Tutorial\n\nThis tutorial walks through a simple game of Tic-Tac-Toe.\n\n?> We’re going to be running commands from a term"
  },
  {
    "path": "docs/documentation/typescript.md",
    "chars": 1903,
    "preview": "# TypeScript\n\nboardgame.io includes type definitions for TypeScript.\n\n### Basic usage\n\n```typescript\n// Game.ts\nimport t"
  },
  {
    "path": "docs/documentation/undo.md",
    "chars": 1292,
    "preview": "# Undo / Redo\n\nboardgame.io comes with built-in support to undo / redo\nmoves in the current turn. This is a common patte"
  },
  {
    "path": "docs/index.css",
    "chars": 1462,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "docs/index.html",
    "chars": 5128,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>boardgame.io - Open-Source Game Engine for Tur"
  },
  {
    "path": "examples/react-native/.gitignore",
    "chars": 248,
    "preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# expo\n.expo/\n\n# dependencies\n/node_modules\n"
  },
  {
    "path": "examples/react-native/.watchmanconfig",
    "chars": 3,
    "preview": "{}\n"
  },
  {
    "path": "examples/react-native/App.js",
    "chars": 904,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-native/README.md",
    "chars": 376,
    "preview": "# Setup\n\n1. Go to `examples/react-native`.\n1. Run `npm install`.\n1. Run `npm start`.\n\n### Platform specific issues and h"
  },
  {
    "path": "examples/react-native/app.json",
    "chars": 645,
    "preview": "{\n  \"expo\": {\n    \"name\": \"react-native\",\n    \"slug\": \"react-native\",\n    \"privacy\": \"public\",\n    \"sdkVersion\": \"32.0.0"
  },
  {
    "path": "examples/react-native/board.js",
    "chars": 3615,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-native/game.js",
    "chars": 1110,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-native/package.json",
    "chars": 503,
    "preview": "{\n  \"main\": \"node_modules/expo/AppEntry.js\",\n  \"scripts\": {\n    \"start\": \"expo start\",\n    \"android\": \"expo start --andr"
  },
  {
    "path": "examples/react-native/rn-cli.config.js",
    "chars": 150,
    "preview": "const path = require('path');\n\nmodule.exports = {\n  getProjectRoots() {\n    return [path.join(__dirname, '..', '..', 'pa"
  },
  {
    "path": "examples/react-web/.gitignore",
    "chars": 339,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": "examples/react-web/package.json",
    "chars": 805,
    "preview": "{\n  \"name\": \"react-web\",\n  \"scripts\": {\n    \"start\": \"parcel src/index.html --port 3000 --open\",\n    \"build\": \"parcel bu"
  },
  {
    "path": "examples/react-web/server.js",
    "chars": 557,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/app.css",
    "chars": 559,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/app.js",
    "chars": 1587,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/app.test.js",
    "chars": 2168,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/chess/board.js",
    "chars": 6557,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/chess/chat.js",
    "chars": 931,
    "preview": "import React, { useState } from 'react';\n\nconst Chat = ({ onSend, messages }) => {\n  const [message, setMessage] = useSt"
  },
  {
    "path": "examples/react-web/src/chess/checkerboard.js",
    "chars": 3767,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/chess/checkerboard.test.js",
    "chars": 1423,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/chess/game.js",
    "chars": 1366,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/chess/grid.js",
    "chars": 6073,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/chess/index.js",
    "chars": 764,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/chess/multiplayer.js",
    "chars": 765,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/chess/pieces/CREDITS",
    "chars": 132,
    "preview": "Chess piece artwork comes from\n\nhttps://en.wikipedia.org/wiki/Chess_piece\n\nand was made available by its authors under B"
  },
  {
    "path": "examples/react-web/src/chess/pieces/bishop.js",
    "chars": 2063,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/chess/pieces/king.js",
    "chars": 2915,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/chess/pieces/knight.js",
    "chars": 2667,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/chess/pieces/pawn.js",
    "chars": 1318,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/chess/pieces/queen.js",
    "chars": 2648,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/chess/pieces/rook.js",
    "chars": 4785,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/chess/singleplayer.js",
    "chars": 541,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/chess/token.js",
    "chars": 8910,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-syle\n * license that ca"
  },
  {
    "path": "examples/react-web/src/index.html",
    "chars": 412,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta content=\"width=device-width,initial-scale=1\" name=\"viewport\">\n    <link rel=\"s"
  },
  {
    "path": "examples/react-web/src/index.js",
    "chars": 297,
    "preview": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { App } from './app';\n\nconst container "
  },
  {
    "path": "examples/react-web/src/li-navlink.js",
    "chars": 1357,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/lobby/index.js",
    "chars": 312,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/lobby/lobby.css",
    "chars": 1018,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/lobby/lobby.js",
    "chars": 1074,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/lobby/routes.js",
    "chars": 363,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/random/board.js",
    "chars": 597,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/random/game.js",
    "chars": 586,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/random/index.js",
    "chars": 639,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/redacted-move/board.css",
    "chars": 309,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/redacted-move/board.js",
    "chars": 930,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/redacted-move/game.js",
    "chars": 733,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/redacted-move/index.js",
    "chars": 374,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/redacted-move/multiview.js",
    "chars": 1386,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/routes.js",
    "chars": 1119,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/secret-state/board.css",
    "chars": 309,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/secret-state/board.js",
    "chars": 632,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/secret-state/game.js",
    "chars": 514,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/secret-state/index.js",
    "chars": 372,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/secret-state/multiview.js",
    "chars": 1170,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/simulator/example-all-once.js",
    "chars": 635,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/simulator/example-all.js",
    "chars": 625,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/simulator/example-others-once.js",
    "chars": 1083,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/simulator/example-others.js",
    "chars": 631,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/simulator/index.js",
    "chars": 360,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/simulator/simulator.css",
    "chars": 2743,
    "preview": "#turnorder {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  padding: 50px;\n}\n\n#turnorder pre {\n  fo"
  },
  {
    "path": "examples/react-web/src/simulator/simulator.js",
    "chars": 3923,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/threejs/index.js",
    "chars": 3748,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/threejs/main.css",
    "chars": 98,
    "preview": "div.root {\n  position: relative;\n}\n\ndiv.text {\n  position: absolute;\n  left: 10px;\n  top: 10px;\n}\n"
  },
  {
    "path": "examples/react-web/src/tic-tac-toe/advanced-ai.js",
    "chars": 3010,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/tic-tac-toe/authenticated.js",
    "chars": 3693,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/tic-tac-toe/board.css",
    "chars": 598,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/tic-tac-toe/board.js",
    "chars": 2095,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/tic-tac-toe/bots.js",
    "chars": 717,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/tic-tac-toe/game.js",
    "chars": 1404,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/tic-tac-toe/index.js",
    "chars": 997,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/tic-tac-toe/multiplayer.js",
    "chars": 904,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/tic-tac-toe/singleplayer.js",
    "chars": 603,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/tic-tac-toe/spectator.js",
    "chars": 1067,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/undo/board.js",
    "chars": 1040,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/react-web/src/undo/game.js",
    "chars": 427,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "examples/react-web/src/undo/index.js",
    "chars": 720,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "examples/snippets/.gitignore",
    "chars": 17,
    "preview": "package-lock.json"
  },
  {
    "path": "examples/snippets/README.md",
    "chars": 634,
    "preview": "# snippets\n\nThis directory contains the source code for the embedded demos\nfound in boardgame.io’s documentation.\n\nTo wo"
  },
  {
    "path": "examples/snippets/install.sh",
    "chars": 298,
    "preview": "#!/bin/bash\n\n# Builds the snippets and installs them at the\n# appropriate places in the docs. Be careful not\n# to let Pr"
  },
  {
    "path": "examples/snippets/package.json",
    "chars": 761,
    "preview": "{\n  \"name\": \"snippets\",\n  \"scripts\": {\n    \"start\": \"parcel src/*/index.html\",\n    \"update-docs\": \"./install.sh\",\n    \"b"
  },
  {
    "path": "examples/snippets/src/example-1/index.html",
    "chars": 358,
    "preview": "<!DOCTYPE html>\n<html>\n\n<head>\n<style>\nbody {\n  padding: 20px;\n}\n.msg {\n  position: absolute;\n  bottom: 0;\n  left: 20px;"
  },
  {
    "path": "examples/snippets/src/example-1/index.js",
    "chars": 434,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { Client } from 'boardgame.io/react';\nimport { Debug"
  },
  {
    "path": "examples/snippets/src/example-2/index.html",
    "chars": 358,
    "preview": "<!DOCTYPE html>\n<html>\n\n<head>\n<style>\nbody {\n  padding: 20px;\n}\n.msg {\n  position: absolute;\n  bottom: 0;\n  left: 20px;"
  },
  {
    "path": "examples/snippets/src/example-2/index.js",
    "chars": 2363,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { Client } from 'boardgame.io/react';\nimport { Debug"
  },
  {
    "path": "examples/snippets/src/example-3/index.html",
    "chars": 358,
    "preview": "<!DOCTYPE html>\n<html>\n\n<head>\n<style>\nbody {\n  padding: 20px;\n}\n.msg {\n  position: absolute;\n  bottom: 0;\n  left: 20px;"
  },
  {
    "path": "examples/snippets/src/example-3/index.js",
    "chars": 2600,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { Client } from 'boardgame.io/react';\nimport { Debug"
  },
  {
    "path": "examples/snippets/src/multiplayer/index.html",
    "chars": 394,
    "preview": "<!DOCTYPE html>\n<html>\n\n<head>\n<style>\nbody {\n  padding: 1.25rem;\n}\n.msg {\n  position: absolute;\n  bottom: 0;\n  left: 1."
  },
  {
    "path": "examples/snippets/src/multiplayer/index.js",
    "chars": 3097,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { Client } from 'boardgame.io/react';\nimport { Local"
  },
  {
    "path": "examples/snippets/src/phases-1/App.svelte",
    "chars": 384,
    "preview": "<script>\n  import Player from './Player.svelte';\n</script>\n\n<style>\n  #board {\n    width: 100%;\n  }\n\n  .container {\n    "
  },
  {
    "path": "examples/snippets/src/phases-1/Player.svelte",
    "chars": 1515,
    "preview": "<script>\n  export let playerID = null;\n\n  import { Client } from 'boardgame.io/client';\n  import { Local } from 'boardga"
  },
  {
    "path": "examples/snippets/src/phases-1/game.js",
    "chars": 333,
    "preview": "function DrawCard({ G, playerID }) {\n  G.deck--;\n  G.hand[playerID]++;\n}\n\nfunction PlayCard({ G, playerID }) {\n  G.deck+"
  },
  {
    "path": "examples/snippets/src/phases-1/index.html",
    "chars": 129,
    "preview": "<!DOCTYPE html>\n<html>\n<body>\n  <div id=\"app\"></div>\n  <script type=\"text/javascript\" src=\"./index.js\"></script>\n</body>"
  },
  {
    "path": "examples/snippets/src/phases-1/index.js",
    "chars": 157,
    "preview": "import App from './App.svelte';\n\nconst app = new App({\n  target: document.getElementById('app'),\n  props: {\n    name: 'w"
  },
  {
    "path": "examples/snippets/src/phases-2/App.svelte",
    "chars": 384,
    "preview": "<script>\n  import Player from './Player.svelte';\n</script>\n\n<style>\n  #board {\n    width: 100%;\n  }\n\n  .container {\n    "
  },
  {
    "path": "examples/snippets/src/phases-2/Player.svelte",
    "chars": 1564,
    "preview": "<script>\n  export let playerID = null;\n\n  import { Client } from 'boardgame.io/client';\n  import { Local } from 'boardga"
  },
  {
    "path": "examples/snippets/src/phases-2/game.js",
    "chars": 523,
    "preview": "function DrawCard({ G, playerID }) {\n  G.deck--;\n  G.hand[playerID]++;\n}\n\nfunction PlayCard({ G, playerID }) {\n  G.deck+"
  },
  {
    "path": "examples/snippets/src/phases-2/index.html",
    "chars": 129,
    "preview": "<!DOCTYPE html>\n<html>\n<body>\n  <div id=\"app\"></div>\n  <script type=\"text/javascript\" src=\"./index.js\"></script>\n</body>"
  },
  {
    "path": "examples/snippets/src/phases-2/index.js",
    "chars": 157,
    "preview": "import App from './App.svelte';\n\nconst app = new App({\n  target: document.getElementById('app'),\n  props: {\n    name: 'w"
  },
  {
    "path": "examples/snippets/src/stages-1/App.svelte",
    "chars": 308,
    "preview": "<script>\n  import Player from './Player.svelte';\n</script>\n\n<style>\n  .container {\n    display: flex;\n    flex-direction"
  },
  {
    "path": "examples/snippets/src/stages-1/Player.svelte",
    "chars": 1265,
    "preview": "<script>\n  export let playerID;\n\n  import { Client } from 'boardgame.io/client';\n  import { Local } from 'boardgame.io/m"
  },
  {
    "path": "examples/snippets/src/stages-1/game.js",
    "chars": 298,
    "preview": "function militia({ G, events }) {\n  events.setActivePlayers({ others: 'discard', minMoves: 1, maxMoves: 1 });\n}\n\nfunctio"
  },
  {
    "path": "examples/snippets/src/stages-1/index.html",
    "chars": 129,
    "preview": "<!DOCTYPE html>\n<html>\n<body>\n  <div id=\"app\"></div>\n  <script type=\"text/javascript\" src=\"./index.js\"></script>\n</body>"
  },
  {
    "path": "examples/snippets/src/stages-1/index.js",
    "chars": 157,
    "preview": "import App from './App.svelte';\n\nconst app = new App({\n  target: document.getElementById('app'),\n  props: {\n    name: 'w"
  },
  {
    "path": "integration/.gitignore",
    "chars": 25,
    "preview": "build/\npackage-lock.json\n"
  },
  {
    "path": "integration/README.md",
    "chars": 124125,
    "preview": "This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).\n\nBelow you will fin"
  },
  {
    "path": "integration/package.json",
    "chars": 557,
    "preview": "{\n  \"name\": \"tic-tac-toe\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"react\": \"^16.7.0\",\n    \"rea"
  },
  {
    "path": "integration/public/index.html",
    "chars": 1590,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <link rel=\"shortcut icon\" href=\"%PUBLIC_URL%/fa"
  },
  {
    "path": "integration/src/App.css",
    "chars": 671,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "integration/src/App.js",
    "chars": 788,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "integration/src/App.test.js",
    "chars": 411,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "integration/src/board.css",
    "chars": 598,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "integration/src/board.js",
    "chars": 2093,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors.\n *\n * Use of this source code is governed by a MIT-style\n * license that "
  },
  {
    "path": "integration/src/game.js",
    "chars": 1228,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "integration/src/index.css",
    "chars": 583,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "integration/src/index.js",
    "chars": 349,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "package.json",
    "chars": 6640,
    "preview": "{\n  \"name\": \"boardgame.io\",\n  \"version\": \"0.50.2\",\n  \"description\": \"library for turn-based games\",\n  \"repository\": \"htt"
  },
  {
    "path": "packages/ai.ts",
    "chars": 436,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/client.ts",
    "chars": 370,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/core.ts",
    "chars": 536,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/debug.ts",
    "chars": 276,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/internal.ts",
    "chars": 750,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/main.js",
    "chars": 833,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/master.ts",
    "chars": 270,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/multiplayer.ts",
    "chars": 348,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/plugins.ts",
    "chars": 361,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/react-native.ts",
    "chars": 276,
    "preview": "/*\n * Copyright 2018 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/react.ts",
    "chars": 340,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/server.ts",
    "chars": 539,
    "preview": "/*\n * Copyright 2017 The boardgame.io Authors\n *\n * Use of this source code is governed by a MIT-style\n * license that c"
  },
  {
    "path": "packages/testing.ts",
    "chars": 57,
    "preview": "export { MockRandom } from '../src/testing/mock-random';\n"
  },
  {
    "path": "python/.gitignore",
    "chars": 31,
    "preview": "*.pyc\n.cache\n.coverage\nhtmlcov\n"
  },
  {
    "path": "python/boardgameio.py",
    "chars": 5248,
    "preview": "#\n# Copyright 2018 The boardgame.io Authors\n#\n# Use of this source code is governed by a MIT-style\n# license that can be"
  },
  {
    "path": "python/examples/tic-tac-toe/tictactoebot.py",
    "chars": 2345,
    "preview": "#!/usr/bin/python\n#\n# Copyright 2018 The boardgame.io Authors\n#\n# Use of this source code is governed by a MIT-style\n# l"
  },
  {
    "path": "python/test_boardgameio.py",
    "chars": 4804,
    "preview": "#\n# Copyright 2018 The boardgame.io Authors\n#\n# Use of this source code is governed by a MIT-style\n# license that can be"
  }
]

// ... and 132 more files (download for full content)

About this extraction

This page contains the full source code of the boardgameio/boardgame.io GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 332 files (3.8 MB), approximately 1.0M tokens, and a symbol index with 9131 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!