<commit_before>import { v4 } from "uuid"
import {
  forEach,
  forEachObjIndexed,
  filter,
  isNil,
  map,
  zipObj
} from "ramda"

import Redis from "./redis"

import Game from "./game"
import Revision from "./revision"

import { logger } from "~/app/index"
import { ROLES } from "~/share/constants"
import { UNIVERSE_CHANNEL } from "./universe"

export default class Client {
  constructor(universe, socket) {
    this.universe = universe
    this.socket = socket

    this.redis = new Redis()
    this.redis.on("message", this.messageHandler.bind(this))

    this.uuid = v4()
    this.gameUUID = null
  }

  async startGame(serializedGame) {
    this.gameUUID = serializedGame.uuid

    this.subscribeGame(this.gameUUID)
    this.socket.send({ action: "start", game: serializedGame })
  }

  // senders

  sendUniverse(universe) {
    this.socket.send({ action: "universe", universe })
  }

  async sendGame(game, role) {
    if (isNil(game)) {
      return
    }

    this.socket.send({
      action: "game",
      role,
      game: await game.serialize()
    })
  }

  async sendPosition({ uuid, fen }) {
    this.socket.send({ action: "position", uuid, fen })
  }

  // subscribers

  async subscribeUniverse() {
    await this.redis.subscribe(UNIVERSE_CHANNEL)
  }

  subscribeGame(uuid) {
    this.redis.subscribe(uuid)
  }

  // actions

  async kibitz() {
    if (await this.universe.games.length() === 0) {
      return
    }

    const first = await this.universe.games.head()
    const second = await this.universe.games.next(first)
    const third = await this.universe.games.next(second)

    const uuids = [first, second, third]

    const games = await Game.where("uuid", "in", uuids).fetchAll()
    const orderedGames = map((uuid) => {
      return games.find((game) => { return game.get("uuid") === uuid })
    }, uuids)

    forEach(this.subscribeGame.bind(this), filter(isNil, uuids))

    forEachObjIndexed(
      this.sendGame.bind(this),
      zipObj([ROLES.BEFORE, ROLES.PRIMARY, ROLES.AFTER], orderedGames)
    )<commit_msg>correctly remove undefined values<commit_after>import { v4 } from "uuid"
import {
  forEach,
  forEachObjIndexed,
  isNil,
  map,
  reject,
  zipObj
} from "ramda"

import Redis from "./redis"

import Game from "./game"
import Revision from "./revision"

import { logger } from "~/app/index"
import { ROLES } from "~/share/constants"
import { UNIVERSE_CHANNEL } from "./universe"

export default class Client {
  constructor(universe, socket) {
    this.universe = universe
    this.socket = socket

    this.redis = new Redis()
    this.redis.on("message", this.messageHandler.bind(this))

    this.uuid = v4()
    this.gameUUID = null
  }

  async startGame(serializedGame) {
    this.gameUUID = serializedGame.uuid

    this.subscribeGame(this.gameUUID)
    this.socket.send({ action: "start", game: serializedGame })
  }

  // senders

  sendUniverse(universe) {
    this.socket.send({ action: "universe", universe })
  }

  async sendGame(game, role) {
    if (isNil(game)) {
      return
    }

    this.socket.send({
      action: "game",
      role,
      game: await game.serialize()
    })
  }

  async sendPosition({ uuid, fen }) {
    this.socket.send({ action: "position", uuid, fen })
  }

  // subscribers

  async subscribeUniverse() {
    await this.redis.subscribe(UNIVERSE_CHANNEL)
  }

  subscribeGame(uuid) {
    this.redis.subscribe(uuid)
  }

  // actions

  async kibitz() {
    if (await this.universe.games.length() === 0) {
      return
    }

    const first = await this.universe.games.head()
    const second = await this.universe.games.next(first)
    const third = await this.universe.games.next(second)

    const uuids = [first, second, third]

    const games = await Game.where("uuid", "in", uuids).fetchAll()
    const orderedGames = map((uuid) => {
      return games.find((game) => { return game.get("uuid") === uuid })
    }, uuids)

    forEach(this.subscribeGame.bind(this), reject(isNil, uuids))

    forEachObjIndexed(
      this.sendGame.bind(this),
      zipObj([ROLES.BEFORE, ROLES.PRIMARY, ROLES.AFTER], orderedGames)
    )
{'fraction_non_alphanumeric': 0.13876758854924795, 'fraction_numerical': 0.001455604075691412, 'mean_word_length': 3.0263671875, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '323730', 'n_tokens_mistral': 1417, 'n_tokens_neox': 1371, 'n_words': 303}