docs: function parseCards(player, request, noCardFilter = false) {
    // Apply any card-specific filters. For instance,
    // Gut Punch filters any card following itself
    // as it is a standalone attack.
    function filterCards(cards) {
      // Option was passed in to disabled this filter.
      // User is probably requesting to discard.
      if (noCardFilter) {
        return cards
      }
      const [head, ...tail] = cards
      if (head && head.filter) {
        return [head].concat(head.filter(tail))
      }
      return cards
    }
  
    if (!player || typeof player !== 'object') {
      throw new Error(`Expected first parameter to be a player, got ${player}`)
    }
    // Hey we can just skip the rest of the checks if the player has no cards.
    if (!player.hand.length) {
      return []
    }
    if (!request || (typeof request !== 'object' && typeof request !== 'string')) {
      throw new Error(
        `Expected second parameter to be an object or non-empty string, got ${request}.`
      )
    }
  
    return flow([
      // Convert each potential request to an actual card reference in hand
      // by first comparing the uid, then the id if the uid is not present.
      (cardArray) => {
        return cardArray.map((requestCard) => {
          return player.hand.find((handCard) => {
            if (typeof requestCard === 'string') {
              return requestCard === handCard.uid || requestCard === handCard.id
            }
            if (requestCard.uid) {
              return requestCard.uid === handCard.uid
            }
            return requestCard.id && requestCard.id === handCard.id
          })
        })
      },
      cardArray => cardArray.filter(card => card),
      uniq,
      filterCards
    ])(Array.isArray(request) ? request : [request])
  }