<commit_before>charset = "?u?l?d"

CHARSET_LOWER = ('a'..'z')
CHARSET_UPPER = ('A'..'Z')
CHARSET_DECIMAL = ('0'..'9')

def brute(charset_str)
  charset_range = rangeForCharset(charset_str)
  current_index = indexOfMarker(charset_str) - 1

  tmp_charset = charset_str.dup
  tmp_charset[current_index] = ""

  charset_range.each do |c|
    internal_charset = tmp_charset

    internal_charset[current_index] = c

    # Recurse here if we have another index
    if indexOfMarker(internal_charset)
      brute(internal_charset)
    else
      # Process payload..
      puts "\t" + internal_charset
    end
  end
end

# Returns position of first charset marker
def indexOfMarker(charset_str)
  idx = charset_str.index('?')

  idx + 1 if idx
end

def rangeForCharset(charset_str)
  idx = indexOfMarker(charset_str)
  charset_sym = charset_str[idx]

  if charset_sym == 'l'
    return CHARSET_LOWER
  elsif charset_sym == 'u'
    return CHARSET_UPPER
  elsif charset_sym == 'd'
    return CHARSET_DECIMAL
  end
end

brute(charset)<commit_msg>Keyspace generation progress thanks to @atticuss<commit_after>KEYSPACEDICT = {
  'l' => ('a'..'z').to_a,
  'u' => ('A'..'Z').to_a,
  'd' => ('0'..'9').to_a
}

def brute(charset_str)
  charset_range = rangeForCharset(charset_str)
  current_index = indexOfMarker(charset_str) - 1

  tmp_charset = charset_str.dup
  tmp_charset[current_index] = ""

  charset_range.each do |c|
    internal_charset = tmp_charset

    internal_charset[current_index] = c

    # Recurse here if we have another index
    if indexOfMarker(internal_charset)
      brute(internal_charset)
    else
      # Process payload..
      puts "\t" + internal_charset
    end
  end
end

# Returns position of first charset marker
def indexOfMarker(charset_str)
  idx = charset_str.index('?')

  idx + 1 if idx
end

def rangeForCharset(charset_str)
  idx = indexOfMarker(charset_str)
  charset_sym = charset_str[idx]

  if charset_sym == 'l'
    return CHARSET_LOWER
  elsif charset_sym == 'u'
    return CHARSET_UPPER
  elsif charset_sym == 'd'
    return CHARSET_DECIMAL
  end
end


def generateKeys(keyspace,indicies,length)
  keys = []
  length.times do |i|
    key = ""

    indicies.count.times do |i|
      key += KEYSPACEDICT[keyspace[i]][indicies[i]]
    end
    keys.push(key)

    indicies.count.times do |i|
      indicies[i] += 1
      if indicies[i] == KEYSPACEDICT[keyspace[i]].count
        indicies[i] = 0
      else
        break
      end
    end
  end
  return keys
end

def indexToIndicies(keyspace,index)
  indicies = Array.new(keyspace.count, 0)
  # keyspaceLengths = [len(keyspaceDict[k]) for k in keyspace]
  keyspaceLengths = keyspace.map { |k| KEYSPACEDICT[k].count }

  totalKeyspace  = keyspaceLengths.inject(:*)

  if index > totalKeyspace
    return nil
  end

  keyspace.count.times do |i|
    # subkeyspace = functools.reduce(operator.mul, [keyspaceLengths[j] for j in range(i)], 1) #multiply together all previous keyspacelengths e.g. operating on third char of ?d?l?l returns 10*26
    subkeyspace = keyspaceLengths[0...i].inject(:*)
    if i == 0
      indicies[i] = index % keyspaceLengths[i]
    else
      indicies[i] = (index/subkeyspace).to_i % keyspaceLengths[i]
    end
  end

  return indicies
end

def generateSubkeyspace(keyspace,index,length)
  indicies = indexToIndicies(keyspace, index)

  if indicies.nil?
    return nil
  else
    return generateKeys(keyspace, indicies, length)
  end
end

keyspace = 'lll'.split(//)
index = 5230
length = 10

puts(generateSubkeyspace(keyspace,index,length))
{'fraction_non_alphanumeric': 0.10869565217391304, 'fraction_numerical': 0.006775832862789385, 'mean_word_length': 3.5834411384217333, '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': '1426285', 'n_tokens_mistral': 1346, 'n_tokens_neox': 1261, 'n_words': 288}