code: function prange(s) {
    const set = new Set()
    const subs = s
       // correct things like AJs -A9s to AJs-A9s
      .replace(
        /([A,K,Q,J,T,2-9]{2}[o,s]?)\s*-\s*([A,K,Q,J,T,2-9]{2}[o,s]?)/g
        , '$1-$2'
      )
      // correct AK + to AK+
      .replace(
        /([A,K,Q,J,T,2-9]{2}[o,s]?)\s\+/g
        , '$1+'
      )
      // split at any white space or comma (any errornous space was removed via replace)
      .split(/[,\s]+/).map(x => x.trim())
    for (let i = 0; i < subs.length; i++) {
      const res = subrange(subs[i])
      res.forEach(x => set.add(x))
    }
    return Array.from(set).sort(byCodeRankDescending)
  }
docs: Converts a short notation for poker hand ranges into an array
  filled with the matching combos.
  
  Each range specifier is separated by a comma.
  
  The following notations are supported:
  
  - single combos `KK, AK, ATs`
  - plus notation
  - `QQ+` = `[ AA, KK, QQ ]`
  - `KTs+` = `[ KQs, KJs, KTs ]`
  - `KTo+` = `[ KQo, KJo, KTo ]`
  - `KT+` = `[ KQs, KQo, KJo, KJs, KTo, KTs ]`
  - dash notation
  - `KK-JJ` = `[ KK, QQ, JJ ]`
  - `AKo-ATo` = `[ AK, AQ, AJ, AT ]`
  - `AKs-JTs` = `[ AKs, KQs, JTs ]`
  
  @name prange
  @function
  @param {String} s the short notation for the range
  @return {Array.<String>} all hand combos satisfying the given range