{
  "version": 3,
  "sources": ["../src/MatchMaker.ts"],
  "sourcesContent": ["import { EventEmitter } from 'events';\nimport { ErrorCode, Protocol } from './Protocol.js';\n\nimport { requestFromIPC, subscribeIPC } from './IPC.js';\n\nimport { Deferred, generateId, merge, retry, MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME, REMOTE_ROOM_SHORT_TIMEOUT } from './utils/Utils.js';\nimport { isDevMode, cacheRoomHistory, getPreviousProcessId, getRoomRestoreListKey, reloadFromCache } from './utils/DevMode.js';\n\nimport { RegisteredHandler } from './matchmaker/RegisteredHandler.js';\nimport { Room, RoomInternalState } from './Room.js';\n\nimport { LocalPresence } from './presence/LocalPresence.js';\nimport { Presence } from './presence/Presence.js';\n\nimport { debugAndPrintError, debugMatchMaking } from './Debug.js';\nimport { SeatReservationError } from './errors/SeatReservationError.js';\nimport { ServerError } from './errors/ServerError.js';\n\nimport { IRoomCache, LocalDriver, MatchMakerDriver, SortOptions } from './matchmaker/driver/local/LocalDriver.js';\nimport controller from './matchmaker/controller.js';\nimport * as stats from './Stats.js';\n\nimport { logger } from './Logger.js';\nimport { AuthContext, Client } from './Transport.js';\nimport { Type } from './utils/types.js';\nimport { getHostname } from './discovery/index.js';\nimport { getLockId } from './matchmaker/driver/api.js';\n\nexport { controller, stats, type MatchMakerDriver };\n\nexport type ClientOptions = any;\nexport type SelectProcessIdCallback = (roomName: string, clientOptions: ClientOptions) => Promise<string>;\n\nexport interface SeatReservation {\n  sessionId: string;\n  room: IRoomCache;\n  devMode?: boolean;\n}\n\nconst handlers: {[id: string]: RegisteredHandler} = {};\nconst rooms: {[roomId: string]: Room} = {};\nconst events = new EventEmitter();\n\nexport let publicAddress: string;\nexport let processId: string;\nexport let presence: Presence;\nexport let driver: MatchMakerDriver;\nexport let selectProcessIdToCreateRoom: SelectProcessIdCallback;\n\n/**\n * Whether health checks are enabled or not. (default: true)\n *\n * Health checks are automatically performed on theses scenarios:\n * - At startup, to check for leftover/invalid processId's\n * - When a remote room creation request times out\n * - When a remote seat reservation request times out\n */\nlet enableHealthChecks: boolean = true;\nexport function setHealthChecksEnabled(value: boolean) {\n  enableHealthChecks = value;\n}\n\nexport let onReady: Deferred = new Deferred(); // onReady needs to be immediately available to @colyseus/auth integration.\n\nexport enum MatchMakerState {\n  INITIALIZING,\n  READY,\n  SHUTTING_DOWN\n}\n\n/**\n * Internal MatchMaker state\n */\nexport let state: MatchMakerState;\n\n/**\n * @private\n */\nexport async function setup(\n  _presence?: Presence,\n  _driver?: MatchMakerDriver,\n  _publicAddress?: string,\n  _selectProcessIdToCreateRoom?: SelectProcessIdCallback,\n) {\n  if (onReady === undefined) {\n    //\n    // for testing purposes only: onReady is turned into undefined on shutdown\n    // (needs refactoring.)\n    //\n    onReady = new Deferred();\n  }\n\n  state = MatchMakerState.INITIALIZING;\n\n  presence = _presence || new LocalPresence();\n\n  driver = _driver || new LocalDriver();\n  publicAddress = _publicAddress;\n\n  stats.reset(false);\n\n  // devMode: try to retrieve previous processId\n  if (isDevMode) { processId = await getPreviousProcessId(await getHostname()); }\n\n  // ensure processId is set\n  if (!processId) { processId = generateId(); }\n\n  /**\n   * Define default `assignRoomToProcessId` method.\n   * By default, return the process with least amount of rooms created\n   */\n  selectProcessIdToCreateRoom = _selectProcessIdToCreateRoom || async function () {\n    return (await stats.fetchAll())\n      .sort((p1, p2) => p1.roomCount > p2.roomCount ? 1 : -1)[0]?.processId || processId;\n  };\n\n  onReady.resolve();\n}\n\n/**\n * - Accept receiving remote room creation requests\n * - Check for leftover/invalid processId's on startup\n * @private\n */\nexport async function accept() {\n  await onReady; // make sure \"processId\" is available\n\n  /**\n   * Process-level subscription\n   * - handle remote process healthcheck\n   * - handle remote room creation\n   */\n  await subscribeIPC(presence, processId, getProcessChannel(), (method, args) => {\n    if (method === 'healthcheck') {\n      // health check for this processId\n      return true;\n\n    } else {\n      // handle room creation\n      return handleCreateRoom.apply(undefined, args);\n    }\n  });\n\n  /**\n   * Check for leftover/invalid processId's on startup\n   */\n  if (enableHealthChecks) {\n    await healthCheckAllProcesses();\n\n    /*\n     * persist processId every 1 minute\n     *\n     * FIXME: this is a workaround in case this `processId` gets excluded\n     * (`stats.excludeProcess()`) by mistake due to health-check failure\n     */\n    stats.setAutoPersistInterval();\n  }\n\n  state = MatchMakerState.READY;\n\n  await stats.persist();\n\n  if (isDevMode) {\n    await reloadFromCache();\n  }\n}\n\n/**\n * Join or create into a room and return seat reservation\n */\nexport async function joinOrCreate(roomName: string, clientOptions: ClientOptions = {}, authContext?: AuthContext) {\n  return await retry<Promise<SeatReservation>>(async () => {\n    const authData = await callOnAuth(roomName, clientOptions, authContext);\n    let room: IRoomCache = await findOneRoomAvailable(roomName, clientOptions);\n\n    if (!room) {\n      const handler = getHandler(roomName);\n      const filterOptions = handler.getFilterOptions(clientOptions);\n      const concurrencyKey = getLockId(filterOptions);\n\n      //\n      // Prevent multiple rooms of same filter from being created concurrently\n      //\n      await concurrentJoinOrCreateRoomLock(handler, concurrencyKey, async (roomId?: string) => {\n        if (roomId) {\n          room = await driver.findOne({ roomId })\n        }\n\n        if (!room) {\n          room = await findOneRoomAvailable(roomName, clientOptions);\n        }\n\n        if (!room) {\n          //\n          // TODO [?]\n          //    should we expose the \"creator\" auth data of the room during `onCreate()`?\n          //    it would be useful, though it could be accessed via `onJoin()` for now.\n          //\n          room = await createRoom(roomName, clientOptions);\n          presence.lpush(`l:${handler.name}:${concurrencyKey}`, room.roomId);\n          presence.expire(`l:${handler.name}:${concurrencyKey}`, MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME * 2);\n        }\n\n        return room;\n      });\n    }\n\n    return await reserveSeatFor(room, clientOptions, authData);\n  }, 5, [SeatReservationError]);\n}\n\n/**\n * Create a room and return seat reservation\n */\nexport async function create(roomName: string, clientOptions: ClientOptions = {}, authContext?: AuthContext) {\n  const authData = await callOnAuth(roomName, clientOptions, authContext);\n  const room = await createRoom(roomName, clientOptions);\n  return reserveSeatFor(room, clientOptions, authData);\n}\n\n/**\n * Join a room and return seat reservation\n */\nexport async function join(roomName: string, clientOptions: ClientOptions = {}, authContext?: AuthContext) {\n  return await retry<Promise<SeatReservation>>(async () => {\n    const authData = await callOnAuth(roomName, clientOptions, authContext);\n    const room = await findOneRoomAvailable(roomName, clientOptions);\n\n    if (!room) {\n      throw new ServerError(ErrorCode.MATCHMAKE_INVALID_CRITERIA, `no rooms found with provided criteria`);\n    }\n\n    return reserveSeatFor(room, clientOptions, authData);\n  });\n}\n\n/**\n * Join a room by id and return seat reservation\n */\nexport async function reconnect(roomId: string, clientOptions: ClientOptions = {}) {\n  const room = await driver.findOne({ roomId });\n  if (!room) {\n    // TODO: support a \"logLevel\" out of the box?\n    if (process.env.NODE_ENV !== 'production') {\n      logger.info(`\u274C room \"${roomId}\" has been disposed. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n    }\n\n    throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" has been disposed.`);\n  }\n\n  // check for reconnection\n  const reconnectionToken = clientOptions.reconnectionToken;\n  if (!reconnectionToken) { throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `'reconnectionToken' must be provided for reconnection.`); }\n\n\n  // respond to re-connection!\n  const sessionId = await remoteRoomCall(room.roomId, 'checkReconnectionToken', [reconnectionToken]);\n  if (sessionId) {\n    return { room, sessionId };\n\n  } else {\n    // TODO: support a \"logLevel\" out of the box?\n    if (process.env.NODE_ENV !== 'production') {\n      logger.info(`\u274C reconnection token invalid or expired. Did you missed .allowReconnection()?\\n\uD83D\uDC49 https://docs.colyseus.io/server/room/#allowreconnection-client-seconds`);\n    }\n    throw new ServerError(ErrorCode.MATCHMAKE_EXPIRED, `reconnection token invalid or expired.`);\n  }\n}\n\n/**\n * Join a room by id and return client seat reservation. An exception is thrown if a room is not found for roomId.\n *\n * @param roomId - The Id of the specific room instance.\n * @param clientOptions - Options for the client seat reservation (for `onJoin`/`onAuth`)\n * @param authContext - Optional authentication token\n *\n * @returns Promise<SeatReservation> - A promise which contains `sessionId` and `IRoomCache`.\n */\nexport async function joinById(roomId: string, clientOptions: ClientOptions = {}, authContext?: AuthContext) {\n  const room = await driver.findOne({ roomId });\n\n  if (!room) {\n    throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" not found`);\n\n  } else if (room.locked) {\n    throw new ServerError(ErrorCode.MATCHMAKE_INVALID_ROOM_ID, `room \"${roomId}\" is locked`);\n  }\n\n  const authData = await callOnAuth(room.name, clientOptions, authContext);\n\n  return reserveSeatFor(room, clientOptions, authData);\n}\n\n/**\n * Perform a query for all cached rooms\n */\nexport async function query(conditions: Partial<IRoomCache> = {}, sortOptions?: SortOptions) {\n  return await driver.query(conditions, sortOptions);\n}\n\n/**\n * Find for a public and unlocked room available.\n *\n * @param roomName - The Id of the specific room.\n * @param filterOptions - Filter options.\n * @param sortOptions - Sorting options.\n *\n * @returns Promise<IRoomCache> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function findOneRoomAvailable(\n  roomName: string,\n  filterOptions: ClientOptions,\n  additionalSortOptions?: SortOptions,\n) {\n  const handler = getHandler(roomName);\n  const sortOptions = Object.assign({}, handler.sortOptions ?? {});\n\n  if (additionalSortOptions) {\n    Object.assign(sortOptions, additionalSortOptions);\n  }\n\n  return await driver.findOne({\n    locked: false,\n    name: roomName,\n    private: false,\n    ...handler.getFilterOptions(filterOptions),\n  }, sortOptions);\n}\n\n/**\n * Call a method or return a property on a remote room.\n *\n * @param roomId - The Id of the specific room instance.\n * @param method - Method or attribute to call or retrive.\n * @param args - Array of arguments for the method\n *\n * @returns Promise<any> - Returned value from the called or retrieved method/attribute.\n */\nexport async function remoteRoomCall<R= any>(\n  roomId: string,\n  method: string,\n  args?: any[],\n  rejectionTimeout = REMOTE_ROOM_SHORT_TIMEOUT,\n): Promise<R> {\n  const room = rooms[roomId];\n\n  if (!room) {\n    try {\n      return await requestFromIPC<R>(presence, getRoomChannel(roomId), method, args, rejectionTimeout);\n\n    } catch (e) {\n\n      //\n      // the room cache from an unavailable process might've been used here.\n      // perform a health-check on the process before proceeding.\n      // (this is a broken state when a process wasn't gracefully shut down)\n      //\n      if (method === '_reserveSeat' && e.message === \"ipc_timeout\") {\n        throw e;\n      }\n\n      // TODO: for 1.0, consider always throwing previous error directly.\n\n      const request = `${method}${args && ' with args ' + JSON.stringify(args) || ''}`;\n      throw new ServerError(\n        ErrorCode.MATCHMAKE_UNHANDLED,\n        `remote room (${roomId}) timed out, requesting \"${request}\". (${rejectionTimeout}ms exceeded)`,\n      );\n    }\n\n  } else {\n    return (!args && typeof (room[method]) !== 'function')\n        ? room[method]\n        : (await room[method].apply(room, args && JSON.parse(JSON.stringify(args))));\n  }\n}\n\nexport function defineRoomType<T extends Type<Room>>(\n  roomName: string,\n  klass: T,\n  defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],\n) {\n  const registeredHandler = new RegisteredHandler(roomName, klass, defaultOptions);\n\n  handlers[roomName] = registeredHandler;\n\n  if (klass.prototype['onAuth'] !== Room.prototype['onAuth']) {\n    // TODO: soft-deprecate instance level `onAuth` on 0.16\n    // logger.warn(\"DEPRECATION WARNING: onAuth() at the instance level will be deprecated soon. Please use static onAuth() instead.\");\n\n    if (klass['onAuth'] !== Room['onAuth']) {\n      logger.info(`\u274C \"${roomName}\"'s onAuth() defined at the instance level will be ignored.`);\n    }\n  }\n\n  return registeredHandler;\n}\n\nexport function removeRoomType(roomName: string) {\n  delete handlers[roomName];\n}\n\n// TODO: legacy; remove me on 1.0\nexport function hasHandler(roomName: string) {\n  logger.warn(\"hasHandler() is deprecated. Use getHandler() instead.\");\n  return handlers[roomName] !== undefined;\n}\n\nexport function getHandler(roomName: string) {\n  const handler = handlers[roomName];\n\n  if (!handler) {\n    throw new ServerError(ErrorCode.MATCHMAKE_NO_HANDLER, `provided room name \"${roomName}\" not defined`);\n  }\n\n  return handler;\n}\n\nexport function getRoomClass(roomName: string): Type<Room> {\n  return handlers[roomName]?.klass;\n}\n\n\n/**\n * Creates a new room.\n *\n * @param roomName - The identifier you defined on `gameServer.define()`\n * @param clientOptions - Options for `onCreate`\n *\n * @returns Promise<IRoomCache> - A promise contaning an object which includes room metadata and configurations.\n */\nexport async function createRoom(roomName: string, clientOptions: ClientOptions): Promise<IRoomCache> {\n  //\n  // - select a process to create the room\n  // - use local processId if MatchMaker is not ready yet\n  //\n  const selectedProcessId = (state === MatchMakerState.READY)\n    ? await selectProcessIdToCreateRoom(roomName, clientOptions)\n    : processId;\n\n  let room: IRoomCache;\n  if (selectedProcessId === undefined) {\n\n    if (isDevMode && processId === undefined) {\n      //\n      // WORKAROUND: wait for processId to be available\n      // TODO: Remove this check on 1.0\n      //\n      // - This is a workaround when using matchMaker.createRoom() before the processId is available.\n      // - We need to use top-level await to retrieve processId\n      //\n      await onReady;\n      return createRoom(roomName, clientOptions);\n\n    } else {\n      throw new ServerError(ErrorCode.MATCHMAKE_UNHANDLED, `no processId available to create room ${roomName}`);\n    }\n\n  } else if (selectedProcessId === processId) {\n    // create the room on this process!\n    room = await handleCreateRoom(roomName, clientOptions);\n\n  } else {\n    // ask other process to create the room!\n    try {\n      room = await requestFromIPC<IRoomCache>(\n        presence,\n        getProcessChannel(selectedProcessId),\n        undefined,\n        [roomName, clientOptions],\n        REMOTE_ROOM_SHORT_TIMEOUT,\n      );\n\n    } catch (e) {\n      if (e.message === \"ipc_timeout\") {\n        debugAndPrintError(`${e.message}: create room request timed out for ${roomName} on processId ${selectedProcessId}.`);\n\n        //\n        // clean-up possibly stale process from redis.\n        // when a process disconnects ungracefully, it may leave its previous processId under \"roomcount\"\n        // if the process is still alive, it will re-add itself shortly after the load-balancer selects it again.\n        //\n        if (enableHealthChecks) {\n          await stats.excludeProcess(selectedProcessId);\n        }\n\n        // if other process failed to respond, create the room on this process\n        room = await handleCreateRoom(roomName, clientOptions);\n\n      } else {\n        // re-throw intentional exception thrown during remote onCreate()\n        throw e;\n      }\n    }\n  }\n\n  if (isDevMode) {\n    presence.hset(getRoomRestoreListKey(), room.roomId, JSON.stringify({\n      \"clientOptions\": clientOptions,\n      \"roomName\": roomName,\n      \"processId\": processId\n    }));\n  }\n\n  return room;\n}\n\nexport async function handleCreateRoom(roomName: string, clientOptions: ClientOptions, restoringRoomId?: string): Promise<IRoomCache> {\n  const handler = getHandler(roomName);\n  const room = new handler.klass();\n\n  // set room public attributes\n  if (restoringRoomId && isDevMode) {\n    room.roomId = restoringRoomId;\n\n  } else {\n    room.roomId = generateId();\n  }\n\n  //\n  // Initialize .state (if set).\n  //\n  // Define getters and setters for:\n  //   - autoDispose\n  //   - patchRate\n  //\n  room['__init']();\n\n  room.roomName = roomName;\n  room.presence = presence;\n\n  const additionalListingData: any = handler.getFilterOptions(clientOptions);\n\n  // assign public host\n  if (publicAddress) {\n    additionalListingData.publicAddress = publicAddress;\n  }\n\n  // create a RoomCache reference.\n  room.listing = driver.createInstance({\n    name: roomName,\n    processId,\n    ...additionalListingData\n  });\n\n  if (room.onCreate) {\n    try {\n      await room.onCreate(merge({}, clientOptions, handler.options));\n\n    } catch (e) {\n      debugAndPrintError(e);\n      throw new ServerError(\n        e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n        e.message,\n      );\n    }\n  }\n\n  room['_internalState'] = RoomInternalState.CREATED;\n\n  room.listing.roomId = room.roomId;\n  room.listing.maxClients = room.maxClients;\n\n  // imediatelly ask client to join the room\n  debugMatchMaking('spawning \\'%s\\', roomId: %s, processId: %s', roomName, room.roomId, processId);\n\n  // increment amount of rooms this process is handling\n  stats.local.roomCount++;\n  stats.persist();\n\n  room._events.on('lock', lockRoom.bind(this, room));\n  room._events.on('unlock', unlockRoom.bind(this, room));\n  room._events.on('join', onClientJoinRoom.bind(this, room));\n  room._events.on('leave', onClientLeaveRoom.bind(this, room));\n  room._events.on('visibility-change', onVisibilityChange.bind(this, room));\n  room._events.once('dispose', disposeRoom.bind(this, roomName, room));\n\n  // when disconnect()'ing, keep only join/leave events for stat counting\n  room._events.once('disconnect', () => {\n    room._events.removeAllListeners('lock');\n    room._events.removeAllListeners('unlock');\n    room._events.removeAllListeners('visibility-change');\n    room._events.removeAllListeners('dispose');\n\n    //\n    // emit \"no active rooms\" event when there are no more rooms in this process\n    // (used during graceful shutdown)\n    //\n    if (stats.local.roomCount <= 0) {\n      events.emit('no-active-rooms');\n    }\n  });\n\n  // room always start unlocked\n  await createRoomReferences(room, true);\n\n  // persist room data only if match-making is enabled\n  if (state !== MatchMakerState.SHUTTING_DOWN) {\n    await room.listing.save();\n  }\n\n  handler.emit('create', room);\n\n  return room.listing;\n}\n\n/**\n * Get room data by roomId.\n * This method does not return the actual room instance, use `getLocalRoomById` for that.\n */\nexport function getRoomById(roomId: string) {\n  return driver.findOne({ roomId });\n}\n\n/**\n * Get local room instance by roomId. (Can return \"undefined\" if the room is not available on this process)\n */\nexport function getLocalRoomById(roomId: string) {\n  return rooms[roomId];\n}\n\n/**\n * Disconnects every client on every room in the current process.\n */\nexport function disconnectAll(closeCode?: number) {\n  const promises: Array<Promise<any>> = [];\n\n  for (const roomId in rooms) {\n    if (!rooms.hasOwnProperty(roomId)) {\n      continue;\n    }\n\n    promises.push(rooms[roomId].disconnect(closeCode));\n  }\n\n  return promises;\n}\n\nasync function lockAndDisposeAll(): Promise<any> {\n  // remove processId from room count key\n  // (stops accepting new rooms on this process)\n  await stats.excludeProcess(processId);\n\n  // clear auto-persisting stats interval\n  if (enableHealthChecks) {\n    stats.clearAutoPersistInterval();\n  }\n\n  const noActiveRooms = new Deferred();\n  if (stats.local.roomCount <= 0) {\n    // no active rooms to dispose\n    noActiveRooms.resolve();\n\n  } else {\n    // wait for all rooms to be disposed\n    // TODO: set generous timeout in case\n    events.once('no-active-rooms', () => noActiveRooms.resolve());\n  }\n\n  // - lock all local rooms to prevent new joins\n  // - trigger `onBeforeShutdown()` on each room\n  for (const roomId in rooms) {\n    if (!rooms.hasOwnProperty(roomId)) {\n      continue;\n    }\n\n    const room = rooms[roomId];\n    room.lock();\n    room.onBeforeShutdown();\n  }\n\n  await noActiveRooms;\n}\n\nexport async function gracefullyShutdown(): Promise<any> {\n  if (state === MatchMakerState.SHUTTING_DOWN) {\n    return Promise.reject('already_shutting_down');\n  }\n\n  debugMatchMaking(`${processId} is shutting down!`);\n\n  state = MatchMakerState.SHUTTING_DOWN;\n\n  onReady = undefined;\n\n  // - lock existing rooms\n  // - stop accepting new rooms on this process\n  // - wait for all rooms to be disposed\n  await lockAndDisposeAll();\n\n  if (isDevMode) {\n    await cacheRoomHistory(rooms);\n  }\n\n  // make sure rooms are removed from cache\n  await removeRoomsByProcessId(processId);\n\n  // unsubscribe from process id channel\n  presence.unsubscribe(getProcessChannel());\n\n  // make sure all rooms are disposed\n  return Promise.all(disconnectAll(\n    (isDevMode)\n      ? Protocol.WS_CLOSE_DEVMODE_RESTART\n      : undefined\n  ));\n}\n\n/**\n * Reserve a seat for a client in a room\n */\nexport async function reserveSeatFor(room: IRoomCache, options: ClientOptions, authData?: any) {\n  const sessionId: string = authData?.sessionId || generateId();\n\n  debugMatchMaking(\n    'reserving seat. sessionId: \\'%s\\', roomId: \\'%s\\', processId: \\'%s\\'',\n    sessionId, room.roomId, processId,\n  );\n\n  let successfulSeatReservation: boolean;\n\n  try {\n    successfulSeatReservation = await remoteRoomCall(\n      room.roomId,\n      '_reserveSeat',\n      [sessionId, options, authData],\n      REMOTE_ROOM_SHORT_TIMEOUT,\n    );\n\n  } catch (e) {\n    debugMatchMaking(e);\n\n    //\n    // the room cache from an unavailable process might've been used here.\n    // (this is a broken state when a process wasn't gracefully shut down)\n    // perform a health-check on the process before proceeding.\n    //\n    if (\n      e.message === \"ipc_timeout\" &&\n      !(\n        enableHealthChecks &&\n        await healthCheckProcessId(room.processId)\n      )\n    ) {\n      throw new SeatReservationError(`process ${room.processId} is not available.`);\n\n    } else {\n      successfulSeatReservation = false;\n    }\n  }\n\n  if (!successfulSeatReservation) {\n    throw new SeatReservationError(`${room.roomId} is already full.`);\n  }\n\n  const response: SeatReservation = { room, sessionId };\n\n  if (isDevMode) {\n    response.devMode = isDevMode;\n  }\n\n  return response;\n}\n\nasync function callOnAuth(roomName: string, clientOptions?: ClientOptions, authContext?: AuthContext) {\n  const roomClass = getRoomClass(roomName);\n  if (roomClass && roomClass['onAuth'] && roomClass['onAuth'] !== Room['onAuth']) {\n    const result = await roomClass['onAuth'](authContext.token, clientOptions, authContext)\n    if (!result) {\n      throw new ServerError(ErrorCode.AUTH_FAILED, 'onAuth failed');\n    }\n    return result;\n  }\n}\n\n/**\n * Perform health check on all processes\n */\nexport async function healthCheckAllProcesses() {\n  const allStats = await stats.fetchAll();\n  if (allStats.length > 0) {\n    await Promise.all(\n      allStats\n        .filter(stat => stat.processId !== processId) // skip current process\n        .map(stat => healthCheckProcessId(stat.processId))\n    );\n  }\n}\n\n/**\n * Perform health check on a remote process\n * @param processId\n */\nconst _healthCheckByProcessId: { [processId: string]: Promise<any> } = {};\nexport function healthCheckProcessId(processId: string) {\n  //\n  // re-use the same promise if health-check is already in progress\n  // (may occur when _reserveSeat() fails multiple times for the same 'processId')\n  //\n  if (_healthCheckByProcessId[processId] !== undefined) {\n    return _healthCheckByProcessId[processId];\n  }\n\n  _healthCheckByProcessId[processId] = new Promise<boolean>(async (resolve, reject) => {\n    logger.debug(`> Performing health-check against processId: '${processId}'...`);\n\n    try {\n      const requestTime = Date.now();\n\n      await requestFromIPC<IRoomCache>(\n        presence,\n        getProcessChannel(processId),\n        'healthcheck',\n        [],\n        REMOTE_ROOM_SHORT_TIMEOUT,\n      );\n\n      logger.debug(`\u2705 Process '${processId}' successfully responded (${Date.now() - requestTime}ms)`);\n\n      // succeeded to respond\n      resolve(true)\n\n    } catch (e) {\n      // process failed to respond - remove it from stats\n      logger.debug(`\u274C Process '${processId}' failed to respond. Cleaning it up.`);\n      const isProcessExcluded = await stats.excludeProcess(processId);\n\n      // clean-up possibly stale room ids\n      if (isProcessExcluded && !isDevMode) {\n        await removeRoomsByProcessId(processId);\n      }\n\n      resolve(false);\n    } finally {\n      delete _healthCheckByProcessId[processId];\n    }\n  });\n\n  return _healthCheckByProcessId[processId];\n}\n\n/**\n * Remove cached rooms by processId\n * @param processId\n */\nasync function removeRoomsByProcessId(processId: string) {\n  //\n  // clean-up possibly stale room ids\n  // (ungraceful shutdowns using Redis can result on stale room ids still on memory.)\n  //\n  await driver.cleanup(processId);\n}\n\nasync function createRoomReferences(room: Room, init: boolean = false): Promise<boolean> {\n  rooms[room.roomId] = room;\n\n  if (init) {\n    await subscribeIPC(\n      presence,\n      processId,\n      getRoomChannel(room.roomId),\n      (method, args) => {\n        return (!args && typeof (room[method]) !== 'function')\n          ? room[method]\n          : room[method].apply(room, args);\n      },\n    );\n  }\n\n  return true;\n}\n\n/**\n * Used only during `joinOrCreate` to handle concurrent requests for creating a room.\n */\nasync function concurrentJoinOrCreateRoomLock(\n  handler: RegisteredHandler,\n  concurrencyKey: string,\n  callback: (roomId?: string) => Promise<IRoomCache>\n): Promise<IRoomCache> {\n  return new Promise(async (resolve, reject) => {\n    const hkey = getConcurrencyHashKey(handler.name);\n    const concurrency = await presence.hincrbyex(\n      hkey,\n      concurrencyKey,\n      1, // increment by 1\n      MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME * 2 // expire in 2x the time of MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME\n    ) - 1; // do not consider the current request\n\n    const fulfill = async (roomId?: string) => {\n      try {\n        resolve(await callback(roomId));\n\n      } catch (e) {\n        reject(e);\n\n      } finally {\n        await presence.hincrby(hkey, concurrencyKey, -1);\n      }\n    };\n\n    if (concurrency > 0) {\n      debugMatchMaking(\n        'receiving %d concurrent joinOrCreate for \\'%s\\' (%s)',\n        concurrency, handler.name, concurrencyKey\n      );\n\n      const result = await presence.brpop(\n        `l:${handler.name}:${concurrencyKey}`,\n        MAX_CONCURRENT_CREATE_ROOM_WAIT_TIME +\n          (Math.min(concurrency, 3) * 0.2) // add extra milliseconds for each concurrent request\n      );\n\n      return await fulfill(result && result[1]);\n\n    } else {\n      return await fulfill();\n    }\n  });\n}\n\nfunction onClientJoinRoom(room: Room, client: Client) {\n  // increment local CCU\n  stats.local.ccu++;\n  stats.persist();\n\n  handlers[room.roomName].emit('join', room, client);\n}\n\nfunction onClientLeaveRoom(room: Room, client: Client, willDispose: boolean) {\n  // decrement local CCU\n  stats.local.ccu--;\n  stats.persist();\n\n  handlers[room.roomName].emit('leave', room, client, willDispose);\n}\n\nfunction lockRoom(room: Room): void {\n  // emit public event on registered handler\n  handlers[room.roomName].emit('lock', room);\n}\n\nasync function unlockRoom(room: Room) {\n  if (await createRoomReferences(room)) {\n    // emit public event on registered handler\n    handlers[room.roomName].emit('unlock', room);\n  }\n}\n\nfunction onVisibilityChange(room: Room, isInvisible: boolean): void {\n  handlers[room.roomName].emit('visibility-change', room, isInvisible);\n}\n\nasync function disposeRoom(roomName: string, room: Room) {\n  debugMatchMaking('disposing \\'%s\\' (%s) on processId \\'%s\\' (graceful shutdown: %s)', roomName, room.roomId, processId, state === MatchMakerState.SHUTTING_DOWN);\n\n  //\n  // FIXME: this call should not be necessary.\n  //\n  // there's an unidentified edge case using LocalDriver where Room._dispose()\n  // doesn't seem to be called [?], but \"disposeRoom\" is, leaving the matchmaker\n  // in a broken state. (repeated ipc_timeout's for seat reservation on\n  // non-existing rooms)\n  //\n  room.listing.remove();\n  stats.local.roomCount--;\n\n  // decrease amount of rooms this process is handling\n  if (state !== MatchMakerState.SHUTTING_DOWN) {\n    stats.persist();\n\n    // remove from devMode restore list\n    if (isDevMode) {\n      await presence.hdel(getRoomRestoreListKey(), room.roomId);\n    }\n  }\n\n  // emit disposal on registered session handler\n  handlers[roomName].emit('dispose', room);\n\n  // unsubscribe from remote connections\n  presence.unsubscribe(getRoomChannel(room.roomId));\n\n  // remove actual room reference\n  delete rooms[room.roomId];\n}\n\n//\n// Presence keys\n//\nfunction getRoomChannel(roomId: string) {\n  return `$${roomId}`;\n}\n\nfunction getConcurrencyHashKey(roomName: string) {\n  // concurrency hash\n  return `ch:${roomName}`;\n}\n\nfunction getProcessChannel(id: string = processId) {\n  return `p:${id}`;\n}\n"],
  "mappings": ";AAAA,SAAS,oBAAoB;AAC7B,SAAS,WAAW,gBAAgB;AAEpC,SAAS,gBAAgB,oBAAoB;AAE7C,SAAS,UAAU,YAAY,OAAO,OAAO,sCAAsC,iCAAiC;AACpH,SAAS,WAAW,kBAAkB,sBAAsB,uBAAuB,uBAAuB;AAE1G,SAAS,yBAAyB;AAClC,SAAS,MAAM,yBAAyB;AAExC,SAAS,qBAAqB;AAG9B,SAAS,oBAAoB,wBAAwB;AACrD,SAAS,4BAA4B;AACrC,SAAS,mBAAmB;AAE5B,SAAqB,mBAAkD;AACvE,OAAO,gBAAgB;AACvB,YAAY,WAAW;AAEvB,SAAS,cAAc;AAGvB,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAa1B,IAAM,WAA8C,CAAC;AACrD,IAAM,QAAkC,CAAC;AACzC,IAAM,SAAS,IAAI,aAAa;AAEzB,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AAUX,IAAI,qBAA8B;AAC3B,SAAS,uBAAuB,OAAgB;AACrD,uBAAqB;AACvB;AAEO,IAAI,UAAoB,IAAI,SAAS;AAErC,IAAK,kBAAL,kBAAKA,qBAAL;AACL,EAAAA,kCAAA;AACA,EAAAA,kCAAA;AACA,EAAAA,kCAAA;AAHU,SAAAA;AAAA,GAAA;AASL,IAAI;AAKX,eAAsB,MACpB,WACA,SACA,gBACA,8BACA;AACA,MAAI,YAAY,QAAW;AAKzB,cAAU,IAAI,SAAS;AAAA,EACzB;AAEA,UAAQ;AAER,aAAW,aAAa,IAAI,cAAc;AAE1C,WAAS,WAAW,IAAI,YAAY;AACpC,kBAAgB;AAEhB,EAAM,YAAM,KAAK;AAGjB,MAAI,WAAW;AAAE,gBAAY,MAAM,qBAAqB,MAAM,YAAY,CAAC;AAAA,EAAG;AAG9E,MAAI,CAAC,WAAW;AAAE,gBAAY,WAAW;AAAA,EAAG;AAM5C,gCAA8B,gCAAgC,iBAAkB;AAC9E,YAAQ,MAAY,eAAS,GAC1B,KAAK,CAAC,IAAI,OAAO,GAAG,YAAY,GAAG,YAAY,IAAI,EAAE,EAAE,CAAC,GAAG,aAAa;AAAA,EAC7E;AAEA,UAAQ,QAAQ;AAClB;AAOA,eAAsB,SAAS;AAC7B,QAAM;AAON,QAAM,aAAa,UAAU,WAAW,kBAAkB,GAAG,CAAC,QAAQ,SAAS;AAC7E,QAAI,WAAW,eAAe;AAE5B,aAAO;AAAA,IAET,OAAO;AAEL,aAAO,iBAAiB,MAAM,QAAW,IAAI;AAAA,IAC/C;AAAA,EACF,CAAC;AAKD,MAAI,oBAAoB;AACtB,UAAM,wBAAwB;AAQ9B,IAAM,6BAAuB;AAAA,EAC/B;AAEA,UAAQ;AAER,QAAY,cAAQ;AAEpB,MAAI,WAAW;AACb,UAAM,gBAAgB;AAAA,EACxB;AACF;AAKA,eAAsB,aAAa,UAAkB,gBAA+B,CAAC,GAAG,aAA2B;AACjH,SAAO,MAAM,MAAgC,YAAY;AACvD,UAAM,WAAW,MAAM,WAAW,UAAU,eAAe,WAAW;AACtE,QAAI,OAAmB,MAAM,qBAAqB,UAAU,aAAa;AAEzE,QAAI,CAAC,MAAM;AACT,YAAM,UAAU,WAAW,QAAQ;AACnC,YAAM,gBAAgB,QAAQ,iBAAiB,aAAa;AAC5D,YAAM,iBAAiB,UAAU,aAAa;AAK9C,YAAM,+BAA+B,SAAS,gBAAgB,OAAO,WAAoB;AACvF,YAAI,QAAQ;AACV,iBAAO,MAAM,OAAO,QAAQ,EAAE,OAAO,CAAC;AAAA,QACxC;AAEA,YAAI,CAAC,MAAM;AACT,iBAAO,MAAM,qBAAqB,UAAU,aAAa;AAAA,QAC3D;AAEA,YAAI,CAAC,MAAM;AAMT,iBAAO,MAAM,WAAW,UAAU,aAAa;AAC/C,mBAAS,MAAM,KAAK,QAAQ,IAAI,IAAI,cAAc,IAAI,KAAK,MAAM;AACjE,mBAAS,OAAO,KAAK,QAAQ,IAAI,IAAI,cAAc,IAAI,uCAAuC,CAAC;AAAA,QACjG;AAEA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,WAAO,MAAM,eAAe,MAAM,eAAe,QAAQ;AAAA,EAC3D,GAAG,GAAG,CAAC,oBAAoB,CAAC;AAC9B;AAKA,eAAsB,OAAO,UAAkB,gBAA+B,CAAC,GAAG,aAA2B;AAC3G,QAAM,WAAW,MAAM,WAAW,UAAU,eAAe,WAAW;AACtE,QAAM,OAAO,MAAM,WAAW,UAAU,aAAa;AACrD,SAAO,eAAe,MAAM,eAAe,QAAQ;AACrD;AAKA,eAAsB,KAAK,UAAkB,gBAA+B,CAAC,GAAG,aAA2B;AACzG,SAAO,MAAM,MAAgC,YAAY;AACvD,UAAM,WAAW,MAAM,WAAW,UAAU,eAAe,WAAW;AACtE,UAAM,OAAO,MAAM,qBAAqB,UAAU,aAAa;AAE/D,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,YAAY,UAAU,4BAA4B,uCAAuC;AAAA,IACrG;AAEA,WAAO,eAAe,MAAM,eAAe,QAAQ;AAAA,EACrD,CAAC;AACH;AAKA,eAAsB,UAAU,QAAgB,gBAA+B,CAAC,GAAG;AACjF,QAAM,OAAO,MAAM,OAAO,QAAQ,EAAE,OAAO,CAAC;AAC5C,MAAI,CAAC,MAAM;AAET,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,aAAO,KAAK,gBAAW,MAAM;AAAA,iFAAsI;AAAA,IACrK;AAEA,UAAM,IAAI,YAAY,UAAU,2BAA2B,SAAS,MAAM,sBAAsB;AAAA,EAClG;AAGA,QAAM,oBAAoB,cAAc;AACxC,MAAI,CAAC,mBAAmB;AAAE,UAAM,IAAI,YAAY,UAAU,qBAAqB,wDAAwD;AAAA,EAAG;AAI1I,QAAM,YAAY,MAAM,eAAe,KAAK,QAAQ,0BAA0B,CAAC,iBAAiB,CAAC;AACjG,MAAI,WAAW;AACb,WAAO,EAAE,MAAM,UAAU;AAAA,EAE3B,OAAO;AAEL,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,aAAO,KAAK;AAAA,iFAA0J;AAAA,IACxK;AACA,UAAM,IAAI,YAAY,UAAU,mBAAmB,wCAAwC;AAAA,EAC7F;AACF;AAWA,eAAsB,SAAS,QAAgB,gBAA+B,CAAC,GAAG,aAA2B;AAC3G,QAAM,OAAO,MAAM,OAAO,QAAQ,EAAE,OAAO,CAAC;AAE5C,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,YAAY,UAAU,2BAA2B,SAAS,MAAM,aAAa;AAAA,EAEzF,WAAW,KAAK,QAAQ;AACtB,UAAM,IAAI,YAAY,UAAU,2BAA2B,SAAS,MAAM,aAAa;AAAA,EACzF;AAEA,QAAM,WAAW,MAAM,WAAW,KAAK,MAAM,eAAe,WAAW;AAEvE,SAAO,eAAe,MAAM,eAAe,QAAQ;AACrD;AAKA,eAAsB,MAAM,aAAkC,CAAC,GAAG,aAA2B;AAC3F,SAAO,MAAM,OAAO,MAAM,YAAY,WAAW;AACnD;AAWA,eAAsB,qBACpB,UACA,eACA,uBACA;AACA,QAAM,UAAU,WAAW,QAAQ;AACnC,QAAM,cAAc,OAAO,OAAO,CAAC,GAAG,QAAQ,eAAe,CAAC,CAAC;AAE/D,MAAI,uBAAuB;AACzB,WAAO,OAAO,aAAa,qBAAqB;AAAA,EAClD;AAEA,SAAO,MAAM,OAAO,QAAQ;AAAA,IAC1B,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,GAAG,QAAQ,iBAAiB,aAAa;AAAA,EAC3C,GAAG,WAAW;AAChB;AAWA,eAAsB,eACpB,QACA,QACA,MACA,mBAAmB,2BACP;AACZ,QAAM,OAAO,MAAM,MAAM;AAEzB,MAAI,CAAC,MAAM;AACT,QAAI;AACF,aAAO,MAAM,eAAkB,UAAU,eAAe,MAAM,GAAG,QAAQ,MAAM,gBAAgB;AAAA,IAEjG,SAAS,GAAG;AAOV,UAAI,WAAW,kBAAkB,EAAE,YAAY,eAAe;AAC5D,cAAM;AAAA,MACR;AAIA,YAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,gBAAgB,KAAK,UAAU,IAAI,KAAK,EAAE;AAC9E,YAAM,IAAI;AAAA,QACR,UAAU;AAAA,QACV,gBAAgB,MAAM,4BAA4B,OAAO,OAAO,gBAAgB;AAAA,MAClF;AAAA,IACF;AAAA,EAEF,OAAO;AACL,WAAQ,CAAC,QAAQ,OAAQ,KAAK,MAAM,MAAO,aACrC,KAAK,MAAM,IACV,MAAM,KAAK,MAAM,EAAE,MAAM,MAAM,QAAQ,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC;AAAA,EAChF;AACF;AAEO,SAAS,eACd,UACA,OACA,gBACA;AACA,QAAM,oBAAoB,IAAI,kBAAkB,UAAU,OAAO,cAAc;AAE/E,WAAS,QAAQ,IAAI;AAErB,MAAI,MAAM,UAAU,QAAQ,MAAM,KAAK,UAAU,QAAQ,GAAG;AAI1D,QAAI,MAAM,QAAQ,MAAM,KAAK,QAAQ,GAAG;AACtC,aAAO,KAAK,WAAM,QAAQ,6DAA6D;AAAA,IACzF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,eAAe,UAAkB;AAC/C,SAAO,SAAS,QAAQ;AAC1B;AAGO,SAAS,WAAW,UAAkB;AAC3C,SAAO,KAAK,uDAAuD;AACnE,SAAO,SAAS,QAAQ,MAAM;AAChC;AAEO,SAAS,WAAW,UAAkB;AAC3C,QAAM,UAAU,SAAS,QAAQ;AAEjC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,YAAY,UAAU,sBAAsB,uBAAuB,QAAQ,eAAe;AAAA,EACtG;AAEA,SAAO;AACT;AAEO,SAAS,aAAa,UAA8B;AACzD,SAAO,SAAS,QAAQ,GAAG;AAC7B;AAWA,eAAsB,WAAW,UAAkB,eAAmD;AAKpG,QAAM,oBAAqB,UAAU,gBACjC,MAAM,4BAA4B,UAAU,aAAa,IACzD;AAEJ,MAAI;AACJ,MAAI,sBAAsB,QAAW;AAEnC,QAAI,aAAa,cAAc,QAAW;AAQxC,YAAM;AACN,aAAO,WAAW,UAAU,aAAa;AAAA,IAE3C,OAAO;AACL,YAAM,IAAI,YAAY,UAAU,qBAAqB,yCAAyC,QAAQ,EAAE;AAAA,IAC1G;AAAA,EAEF,WAAW,sBAAsB,WAAW;AAE1C,WAAO,MAAM,iBAAiB,UAAU,aAAa;AAAA,EAEvD,OAAO;AAEL,QAAI;AACF,aAAO,MAAM;AAAA,QACX;AAAA,QACA,kBAAkB,iBAAiB;AAAA,QACnC;AAAA,QACA,CAAC,UAAU,aAAa;AAAA,QACxB;AAAA,MACF;AAAA,IAEF,SAAS,GAAG;AACV,UAAI,EAAE,YAAY,eAAe;AAC/B,2BAAmB,GAAG,EAAE,OAAO,uCAAuC,QAAQ,iBAAiB,iBAAiB,GAAG;AAOnH,YAAI,oBAAoB;AACtB,gBAAY,qBAAe,iBAAiB;AAAA,QAC9C;AAGA,eAAO,MAAM,iBAAiB,UAAU,aAAa;AAAA,MAEvD,OAAO;AAEL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI,WAAW;AACb,aAAS,KAAK,sBAAsB,GAAG,KAAK,QAAQ,KAAK,UAAU;AAAA,MACjE,iBAAiB;AAAA,MACjB,YAAY;AAAA,MACZ,aAAa;AAAA,IACf,CAAC,CAAC;AAAA,EACJ;AAEA,SAAO;AACT;AAEA,eAAsB,iBAAiB,UAAkB,eAA8B,iBAA+C;AACpI,QAAM,UAAU,WAAW,QAAQ;AACnC,QAAM,OAAO,IAAI,QAAQ,MAAM;AAG/B,MAAI,mBAAmB,WAAW;AAChC,SAAK,SAAS;AAAA,EAEhB,OAAO;AACL,SAAK,SAAS,WAAW;AAAA,EAC3B;AASA,OAAK,QAAQ,EAAE;AAEf,OAAK,WAAW;AAChB,OAAK,WAAW;AAEhB,QAAM,wBAA6B,QAAQ,iBAAiB,aAAa;AAGzE,MAAI,eAAe;AACjB,0BAAsB,gBAAgB;AAAA,EACxC;AAGA,OAAK,UAAU,OAAO,eAAe;AAAA,IACnC,MAAM;AAAA,IACN;AAAA,IACA,GAAG;AAAA,EACL,CAAC;AAED,MAAI,KAAK,UAAU;AACjB,QAAI;AACF,YAAM,KAAK,SAAS,MAAM,CAAC,GAAG,eAAe,QAAQ,OAAO,CAAC;AAAA,IAE/D,SAAS,GAAG;AACV,yBAAmB,CAAC;AACpB,YAAM,IAAI;AAAA,QACR,EAAE,QAAQ,UAAU;AAAA,QACpB,EAAE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAEA,OAAK,gBAAgB,IAAI,kBAAkB;AAE3C,OAAK,QAAQ,SAAS,KAAK;AAC3B,OAAK,QAAQ,aAAa,KAAK;AAG/B,mBAAiB,4CAA8C,UAAU,KAAK,QAAQ,SAAS;AAG/F,EAAM,YAAM;AACZ,EAAM,cAAQ;AAEd,OAAK,QAAQ,GAAG,QAAQ,SAAS,KAAK,MAAM,IAAI,CAAC;AACjD,OAAK,QAAQ,GAAG,UAAU,WAAW,KAAK,MAAM,IAAI,CAAC;AACrD,OAAK,QAAQ,GAAG,QAAQ,iBAAiB,KAAK,MAAM,IAAI,CAAC;AACzD,OAAK,QAAQ,GAAG,SAAS,kBAAkB,KAAK,MAAM,IAAI,CAAC;AAC3D,OAAK,QAAQ,GAAG,qBAAqB,mBAAmB,KAAK,MAAM,IAAI,CAAC;AACxE,OAAK,QAAQ,KAAK,WAAW,YAAY,KAAK,MAAM,UAAU,IAAI,CAAC;AAGnE,OAAK,QAAQ,KAAK,cAAc,MAAM;AACpC,SAAK,QAAQ,mBAAmB,MAAM;AACtC,SAAK,QAAQ,mBAAmB,QAAQ;AACxC,SAAK,QAAQ,mBAAmB,mBAAmB;AACnD,SAAK,QAAQ,mBAAmB,SAAS;AAMzC,QAAU,YAAM,aAAa,GAAG;AAC9B,aAAO,KAAK,iBAAiB;AAAA,IAC/B;AAAA,EACF,CAAC;AAGD,QAAM,qBAAqB,MAAM,IAAI;AAGrC,MAAI,UAAU,uBAA+B;AAC3C,UAAM,KAAK,QAAQ,KAAK;AAAA,EAC1B;AAEA,UAAQ,KAAK,UAAU,IAAI;AAE3B,SAAO,KAAK;AACd;AAMO,SAAS,YAAY,QAAgB;AAC1C,SAAO,OAAO,QAAQ,EAAE,OAAO,CAAC;AAClC;AAKO,SAAS,iBAAiB,QAAgB;AAC/C,SAAO,MAAM,MAAM;AACrB;AAKO,SAAS,cAAc,WAAoB;AAChD,QAAM,WAAgC,CAAC;AAEvC,aAAW,UAAU,OAAO;AAC1B,QAAI,CAAC,MAAM,eAAe,MAAM,GAAG;AACjC;AAAA,IACF;AAEA,aAAS,KAAK,MAAM,MAAM,EAAE,WAAW,SAAS,CAAC;AAAA,EACnD;AAEA,SAAO;AACT;AAEA,eAAe,oBAAkC;AAG/C,QAAY,qBAAe,SAAS;AAGpC,MAAI,oBAAoB;AACtB,IAAM,+BAAyB;AAAA,EACjC;AAEA,QAAM,gBAAgB,IAAI,SAAS;AACnC,MAAU,YAAM,aAAa,GAAG;AAE9B,kBAAc,QAAQ;AAAA,EAExB,OAAO;AAGL,WAAO,KAAK,mBAAmB,MAAM,cAAc,QAAQ,CAAC;AAAA,EAC9D;AAIA,aAAW,UAAU,OAAO;AAC1B,QAAI,CAAC,MAAM,eAAe,MAAM,GAAG;AACjC;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,MAAM;AACzB,SAAK,KAAK;AACV,SAAK,iBAAiB;AAAA,EACxB;AAEA,QAAM;AACR;AAEA,eAAsB,qBAAmC;AACvD,MAAI,UAAU,uBAA+B;AAC3C,WAAO,QAAQ,OAAO,uBAAuB;AAAA,EAC/C;AAEA,mBAAiB,GAAG,SAAS,oBAAoB;AAEjD,UAAQ;AAER,YAAU;AAKV,QAAM,kBAAkB;AAExB,MAAI,WAAW;AACb,UAAM,iBAAiB,KAAK;AAAA,EAC9B;AAGA,QAAM,uBAAuB,SAAS;AAGtC,WAAS,YAAY,kBAAkB,CAAC;AAGxC,SAAO,QAAQ,IAAI;AAAA,IAChB,YACG,SAAS,2BACT;AAAA,EACN,CAAC;AACH;AAKA,eAAsB,eAAe,MAAkB,SAAwB,UAAgB;AAC7F,QAAM,YAAoB,UAAU,aAAa,WAAW;AAE5D;AAAA,IACE;AAAA,IACA;AAAA,IAAW,KAAK;AAAA,IAAQ;AAAA,EAC1B;AAEA,MAAI;AAEJ,MAAI;AACF,gCAA4B,MAAM;AAAA,MAChC,KAAK;AAAA,MACL;AAAA,MACA,CAAC,WAAW,SAAS,QAAQ;AAAA,MAC7B;AAAA,IACF;AAAA,EAEF,SAAS,GAAG;AACV,qBAAiB,CAAC;AAOlB,QACE,EAAE,YAAY,iBACd,EACE,sBACA,MAAM,qBAAqB,KAAK,SAAS,IAE3C;AACA,YAAM,IAAI,qBAAqB,WAAW,KAAK,SAAS,oBAAoB;AAAA,IAE9E,OAAO;AACL,kCAA4B;AAAA,IAC9B;AAAA,EACF;AAEA,MAAI,CAAC,2BAA2B;AAC9B,UAAM,IAAI,qBAAqB,GAAG,KAAK,MAAM,mBAAmB;AAAA,EAClE;AAEA,QAAM,WAA4B,EAAE,MAAM,UAAU;AAEpD,MAAI,WAAW;AACb,aAAS,UAAU;AAAA,EACrB;AAEA,SAAO;AACT;AAEA,eAAe,WAAW,UAAkB,eAA+B,aAA2B;AACpG,QAAM,YAAY,aAAa,QAAQ;AACvC,MAAI,aAAa,UAAU,QAAQ,KAAK,UAAU,QAAQ,MAAM,KAAK,QAAQ,GAAG;AAC9E,UAAM,SAAS,MAAM,UAAU,QAAQ,EAAE,YAAY,OAAO,eAAe,WAAW;AACtF,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,YAAY,UAAU,aAAa,eAAe;AAAA,IAC9D;AACA,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,0BAA0B;AAC9C,QAAM,WAAW,MAAY,eAAS;AACtC,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,QAAQ;AAAA,MACZ,SACG,OAAO,UAAQ,KAAK,cAAc,SAAS,EAC3C,IAAI,UAAQ,qBAAqB,KAAK,SAAS,CAAC;AAAA,IACrD;AAAA,EACF;AACF;AAMA,IAAM,0BAAiE,CAAC;AACjE,SAAS,qBAAqBC,YAAmB;AAKtD,MAAI,wBAAwBA,UAAS,MAAM,QAAW;AACpD,WAAO,wBAAwBA,UAAS;AAAA,EAC1C;AAEA,0BAAwBA,UAAS,IAAI,IAAI,QAAiB,OAAO,SAAS,WAAW;AACnF,WAAO,MAAM,iDAAiDA,UAAS,MAAM;AAE7E,QAAI;AACF,YAAM,cAAc,KAAK,IAAI;AAE7B,YAAM;AAAA,QACJ;AAAA,QACA,kBAAkBA,UAAS;AAAA,QAC3B;AAAA,QACA,CAAC;AAAA,QACD;AAAA,MACF;AAEA,aAAO,MAAM,mBAAcA,UAAS,6BAA6B,KAAK,IAAI,IAAI,WAAW,KAAK;AAG9F,cAAQ,IAAI;AAAA,IAEd,SAAS,GAAG;AAEV,aAAO,MAAM,mBAAcA,UAAS,sCAAsC;AAC1E,YAAM,oBAAoB,MAAY,qBAAeA,UAAS;AAG9D,UAAI,qBAAqB,CAAC,WAAW;AACnC,cAAM,uBAAuBA,UAAS;AAAA,MACxC;AAEA,cAAQ,KAAK;AAAA,IACf,UAAE;AACA,aAAO,wBAAwBA,UAAS;AAAA,IAC1C;AAAA,EACF,CAAC;AAED,SAAO,wBAAwBA,UAAS;AAC1C;AAMA,eAAe,uBAAuBA,YAAmB;AAKvD,QAAM,OAAO,QAAQA,UAAS;AAChC;AAEA,eAAe,qBAAqB,MAAY,OAAgB,OAAyB;AACvF,QAAM,KAAK,MAAM,IAAI;AAErB,MAAI,MAAM;AACR,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,eAAe,KAAK,MAAM;AAAA,MAC1B,CAAC,QAAQ,SAAS;AAChB,eAAQ,CAAC,QAAQ,OAAQ,KAAK,MAAM,MAAO,aACvC,KAAK,MAAM,IACX,KAAK,MAAM,EAAE,MAAM,MAAM,IAAI;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,eAAe,+BACb,SACA,gBACA,UACqB;AACrB,SAAO,IAAI,QAAQ,OAAO,SAAS,WAAW;AAC5C,UAAM,OAAO,sBAAsB,QAAQ,IAAI;AAC/C,UAAM,cAAc,MAAM,SAAS;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MACA,uCAAuC;AAAA;AAAA,IACzC,IAAI;AAEJ,UAAM,UAAU,OAAO,WAAoB;AACzC,UAAI;AACF,gBAAQ,MAAM,SAAS,MAAM,CAAC;AAAA,MAEhC,SAAS,GAAG;AACV,eAAO,CAAC;AAAA,MAEV,UAAE;AACA,cAAM,SAAS,QAAQ,MAAM,gBAAgB,EAAE;AAAA,MACjD;AAAA,IACF;AAEA,QAAI,cAAc,GAAG;AACnB;AAAA,QACE;AAAA,QACA;AAAA,QAAa,QAAQ;AAAA,QAAM;AAAA,MAC7B;AAEA,YAAM,SAAS,MAAM,SAAS;AAAA,QAC5B,KAAK,QAAQ,IAAI,IAAI,cAAc;AAAA,QACnC,uCACG,KAAK,IAAI,aAAa,CAAC,IAAI;AAAA;AAAA,MAChC;AAEA,aAAO,MAAM,QAAQ,UAAU,OAAO,CAAC,CAAC;AAAA,IAE1C,OAAO;AACL,aAAO,MAAM,QAAQ;AAAA,IACvB;AAAA,EACF,CAAC;AACH;AAEA,SAAS,iBAAiB,MAAY,QAAgB;AAEpD,EAAM,YAAM;AACZ,EAAM,cAAQ;AAEd,WAAS,KAAK,QAAQ,EAAE,KAAK,QAAQ,MAAM,MAAM;AACnD;AAEA,SAAS,kBAAkB,MAAY,QAAgB,aAAsB;AAE3E,EAAM,YAAM;AACZ,EAAM,cAAQ;AAEd,WAAS,KAAK,QAAQ,EAAE,KAAK,SAAS,MAAM,QAAQ,WAAW;AACjE;AAEA,SAAS,SAAS,MAAkB;AAElC,WAAS,KAAK,QAAQ,EAAE,KAAK,QAAQ,IAAI;AAC3C;AAEA,eAAe,WAAW,MAAY;AACpC,MAAI,MAAM,qBAAqB,IAAI,GAAG;AAEpC,aAAS,KAAK,QAAQ,EAAE,KAAK,UAAU,IAAI;AAAA,EAC7C;AACF;AAEA,SAAS,mBAAmB,MAAY,aAA4B;AAClE,WAAS,KAAK,QAAQ,EAAE,KAAK,qBAAqB,MAAM,WAAW;AACrE;AAEA,eAAe,YAAY,UAAkB,MAAY;AACvD,mBAAiB,iEAAqE,UAAU,KAAK,QAAQ,WAAW,UAAU,qBAA6B;AAU/J,OAAK,QAAQ,OAAO;AACpB,EAAM,YAAM;AAGZ,MAAI,UAAU,uBAA+B;AAC3C,IAAM,cAAQ;AAGd,QAAI,WAAW;AACb,YAAM,SAAS,KAAK,sBAAsB,GAAG,KAAK,MAAM;AAAA,IAC1D;AAAA,EACF;AAGA,WAAS,QAAQ,EAAE,KAAK,WAAW,IAAI;AAGvC,WAAS,YAAY,eAAe,KAAK,MAAM,CAAC;AAGhD,SAAO,MAAM,KAAK,MAAM;AAC1B;AAKA,SAAS,eAAe,QAAgB;AACtC,SAAO,IAAI,MAAM;AACnB;AAEA,SAAS,sBAAsB,UAAkB;AAE/C,SAAO,MAAM,QAAQ;AACvB;AAEA,SAAS,kBAAkB,KAAa,WAAW;AACjD,SAAO,KAAK,EAAE;AAChB;",
  "names": ["MatchMakerState", "processId"]
}
