#Installation of Libraries
#In order to wield this program, pandas and spaCy must be installed in the bash shell, not in the python interpreter.

#Type the following in the bash shell:
#pip install pandas
#pip install -U spacy (hyphen, not a dash)
#Precede pip by ! in the spacy installation command if you are working in Google Colab.

#Importation of Modules
#A user-defined function can depend on modules imported prior to where it is defined.

import nltk
nltk.download('popular')
nltk.download('tagsets')

import spacy
from spacy import displacy
from collections import Counter
import pandas as pd

#Invocation of the nlp Machine Learning Model

#Download the nlp machine learning model from spacy in the shell:
#Type the into a commandline the following statement, preceding it by ! only in GoogleColab:
#python -m spacy download zh_core_web_md

#Load the nlp machine learning model and harbor it in the variable identifier nlp.

nlp = spacy.load('zh_core_web_md')

import re

#File Input/Output

import sys

#-----------statement in the commandlines that runs this program---------------
#python compartmentalization_and_word_tokenization.py ~/sample_output.txt
#------------------------------------------------------------------------------

#file1 = open(sys.argv[1],'r+', encoding = 'utf-8')

def compartmentalization_and_word_tokenization_1(sentence):
  """
Analyzing a single sentence, this function detects the code-switching points,     compartmentalizes the sentence into entirely Mandarin fragments and entirely English fragments, word-tokenizes each monolingual fragment, and converts each token to a token-tag tuple.
  """
  #reference string: sentence
  Mand_Eng_switches = re.findall(r'[^a-zA-Z]\s\b[a-zA-Z]+\b',sentence)
  #return Mand_Eng_switches
  #a non-alphabetic character followed by a sequence of alphabetic characters
  Eng_Mand_switches = re.findall(r'\b[a-zA-Z]+\b\s[^a-zA-Z]',sentence)
  #a sequence of alphabetic characters followed by a non-alphabetic character
  ###Insert a comma at each switching point, so initialize a list of indices of positions where commas will be inserted.
  comma_indices = []
  ##Recover the final-position index of a Mandarin word preceding the switching point.
  for item in Mand_Eng_switches:
    var1 = item
    #m_a = re.search(r'[^a-zA-Z]\s',item)
    #Mandarin_word = m_a.group()
    #len(Mandarin_word) would result in 2
    m_1 = re.search(rf'{var1}',sentence)
    position_of_matched_sequence = m_1.span()
    comma_index_1 = position_of_matched_sequence[0]+2-1
    comma_indices.append(comma_index_1)
  ##Recover the final-position index of an English word preceding the switching point.
  for item in Eng_Mand_switches:
    var2 = item
    m_b = re.search(r'[a-zA-Z]+\s',item)
    English_word = m_b.group()
    m_2 = re.search(rf'{var2}',sentence)
    position_of_matched_sequence = m_2.span()
    comma_index_2 = position_of_matched_sequence[0]+len(English_word)-1
    comma_indices.append(comma_index_2)
    #Attempt to keep the strings the same length by replacing a single space with a       single comma.
  for item in comma_indices:
    p = int(item)
    sentence = sentence[:p]+','+sentence[p+1:]
  compartmentalized_sentence = sentence.split(",")
  #POS-tag the words of each monolingual fragment
  comp_w_t_sent = []
  j=0
  while j < len(compartmentalized_sentence):
    m_3 = re.search(r'[a-z]',compartmentalized_sentence[j])
    if m_3 == None: #None, not NONE, is the correct reserved term.
        #word tokenize the string titled compartmentalized_sentence[j] with spaCy
      #If the monolingual fragment is entirely Mandarin
        w_t_str = nlp(compartmentalized_sentence[j])
        w_t_str = list(w_t_str)
        for i in range(len(w_t_str)): #Guarantee that elements of w_t_str are strings.
          w_t_str[i] = str(w_t_str[i])
        comp_w_t_sent.append(w_t_str)
        j+=1
    if type(m_3) == re.Match:
      #If the monolingual fragment is entirely English
         #word tokenize the string titled compartmentalized_sentence[j] with nltk
        w_t_str = nltk.word_tokenize(compartmentalized_sentence[j])
        comp_w_t_sent.append(w_t_str)
        #comp_w_t_sent stands for compartmentalized, word-tokenized sentence
        j+=1
  #return comp_w_t_sent

#A SHORTCOMING OF THE FUNCTION compartmentalization_and_word_tokenization_1

#Mand_Eng switches ['个 chocolate', '个 chocolate']
#The search function's match option will only carry search information for the first occurrence of '个 chocolate', so only the first boundary marked by '个 chocolate' gets divided.

#print(compartmentalization_and_word_tokenization_1('你 要 那 个 chocolate 你 刚 才 吃 的 那 个 chocolate'))

  ##Ascertainment of the formula for the index of comma insertion in an example
  #search_string = '你 要 那 个 chocolate 你 刚 才 吃 的 那 个 chocolate'
  #search_string[5:15] extracts the substring 'chocolate 你'
  #position_of_matched_sequence will store (5,15), as the first tuple component is   the initial-position index while the second tuple component is one greater than the final-position index.
  #len(m_b) will output 10.
  #We seek to insert a comma at index 14.
  #comma_index = position_of_matched_sequence[0]+len(m_b)-1=5+10-1 = 14

      #comma_index_2 = position_of_matched_sequence[0]+len(English_word)-1

def compartmentalization_and_word_tokenization_2(sentence):
  """
Analyzing a single sentence, this function detects the code-switching points,     compartmentalizes the sentence into entirely Mandarin fragments and entirely English fragments, word-tokenizes each monolingual fragment, and converts each token to a token-tag tuple. This function mangages the case of identical Mandarin-to-English code-switching points in the same string, such as the repetition of "个 chocolate" in '你 要 那 个 chocolate 你 刚 才 吃 的 那 个 chocolate.' We enhanced this function to handle identical English-to-Mandarin code-switching points if time permits.
  """
  #reference string: sentence
  Mand_Eng_switches = re.findall(r'[^a-zA-Z]\s\b[a-zA-Z]+\b',sentence)
  #return Mand_Eng_switches
  #a non-alphabetic character followed by a sequence of alphabetic characters
  Eng_Mand_switches = re.findall(r'\b[a-zA-Z]+\b\s[^a-zA-Z]',sentence)
  #a sequence of alphabetic characters followed by a non-alphabetic character
  ###Insert a comma at each switching point, so initialize a list of indices of positions where commas will be inserted.
  comma_indices = []
  ##Recover the final-position index of a Mandarin word preceding the switching point.
  if len(Mand_Eng_switches) == 0:
    pass
  elif len(Mand_Eng_switches) == 1:
    var1 = Mand_Eng_switches[0]
    m_1 = re.search(rf'{var1}',sentence)
    position_of_matched_sequence = m_1.span()
    comma_index_1 = position_of_matched_sequence[0]+2-1
    comma_indices.append(comma_index_1)
  else: # Handle identical Mandarin-to-English code-switching points in the same sentence.
    sentence_new = sentence[:] #clone the string, so as to not modify the original
    for i in range(len(Mand_Eng_switches)):
      var1 = Mand_Eng_switches[i]
      #m_a = re.search(r'[^a-zA-Z]\s',item)
      #Mandarin_word = m_a.group()
      #len(Mandarin_word) would result in 2
      #Save the position of the code-switching point to a list.
      if i == 0:
        m_2 = re.search(rf'{var1}',sentence_new)
        position_of_matched_sequence = m_2.span()
        comma_index_2 = position_of_matched_sequence[0]+2-1
        comma_indices.append(comma_index_2)
      if i >= 1:
        m_2 = re.search(rf'{var1}',sentence_new)
        #return sentence_new
        position_of_matched_sequence = m_2.span()
        comma_index_2 = len(sentence_new_comp)+position_of_matched_sequence[0]+2-1 #Add the exact length of complementary string because the character count of the complementary substring equals the number by which the index of position_of_matched_sequence[0]+2-1 is offset.
        comma_indices.append(comma_index_2)
      pstn = int(position_of_matched_sequence[0])
      #curtail the part of the sentence before the switching point
      sentence_new = sentence_new[pstn+1:]
      #Get the complementary string or the portion of the original sentence not in
      #the new sentence.
      sentence_new_comp = sentence[:pstn+1]
  #return comma_indices
  ##Recover the final-position index of an English word preceding the switching point.
  if len(Eng_Mand_switches) == O:
    pass
  elif len(Eng_Mand_switches) == 1:
    for item in Eng_Mand_switches:
      var3 = item
      m_b = re.search(r'[a-zA-Z]+\s',item)
      English_word = m_b.group()
      m_3 = re.search(rf'{var3}',sentence)
      position_of_matched_sequence = m_3.span()
      comma_index_3 = position_of_matched_sequence[0]+len(English_word)-1
      comma_indices.append(comma_index_3)
    #Attempt to keep the strings the same length by replacing a single space with a       single comma.
  else: #Handle identical English-to-Mandarin code-switching points in the same sentence.
    sentence_new_1 = sentence[:] #clone the string, so as to not modify the original
    #Handle identical English-to-Mandarin code-switching points in the same sentence.
    sentence_new_1 = sentence[:]

    #Scour the sentence for all occurrences of a search pattern comprised of an English word, a space, and a Mandarin word.

    #reference string: sentence

    match_object = re.findall(r'\b[a-zA-Z]+\b\s[^a-zA-Z]',sentence)

    if len(match_object) >= 1:
      for i in range(len(match_object)):
        if i == 0:
          #Search for English word in match_object[i] (i.e., the pair of an English and Mandarin word straddling the code-switching point).
          m = re.search(r'^[a-zA-Z]+\b', match_object[i])
          Eng_word = m.group()
          #print(Eng_word) correct
          #Search for match_object[i] in the original sentence.
          m_a = re.search(match_object[i],sentence)
          indices_of_code_switching_pair = m_a.span()
          #Extract the posterior portion of the sentence, and let this override the value of sentence_new_1.
          c_s_point = indices_of_code_switching_pair[0]+len(Eng_word) #c_s_point abbreviates code-switching point
          sentence_new_1 = sentence_new_1[c_s_point+1:]
          #print(f"portion posterior to code-switching point:{sentence_new_1}")
        if i >= 1:
          m = re.search(r'^[a-zA-Z]+\b', match_object[i])
          Eng_word = m.group()
          #Search for match_object[i] in the portion posterior to the code-switching point.
          m_b = re.search(match_object[i],sentence_new_1)
          indices_of_code_switching_pair_post = m_b.span() #indices with respect to the posterior portion
          if i == 1:
            indices_of_code_switching_pair = tuple((s+len(sentence_new_1_comp) for s in indices_of_code_switching_pair_post))
          if i > 1: #I do not understand the reason for the -1 adjustment but figured it out by trial and error.
            indices_of_code_switching_pair = tuple((s+len(sentence_new_1_comp)-1 for s in indices_of_code_switching_pair_post))

          #Now we have the indices with respect to original sentence in the tuple output from tuple comprehension.
          c_s_point = indices_of_code_switching_pair[0]+len(Eng_word)
          sentence_new_1 = sentence_new_1[indices_of_code_switching_pair_post[0]+len(Eng_word):] #string from c_s_point with respect to the the posterior portion
          #print(f"portion posterior to code-switching point:{sentence_new_1}")
        sentence_new_1_comp = sentence[:c_s_point+1]
        comma_indices.append(c_s_point)
#-----------------
  for item in comma_indices:
      p = int(item)
      sentence = sentence[:p]+','+sentence[p+1:]
  compartmentalized_sentence = sentence.split(",")
  #POS-tag the words of each monolingual fragment
  comp_w_t_sent = []
  j=0
  while j < len(compartmentalized_sentence):
    m_5 = re.search(r'[a-z]',compartmentalized_sentence[j])
    if m_5 == None: #None, not NONE, is the correct reserved term.
        #word tokenize the string titled compartmentalized_sentence[j] with spaCy
      #If the monolingual fragment is entirely Mandarin
        w_t_str = nlp(compartmentalized_sentence[j])
        w_t_str = list(w_t_str)
        for i in range(len(w_t_str)): #Guarantee that elements of w_t_str are strings.
          w_t_str[i] = str(w_t_str[i])
        comp_w_t_sent.append(w_t_str)
        j+=1
    if type(m_5) == re.Match:
      #If the monolingual fragment is entirely English
         #word tokenize the string titled compartmentalized_sentence[j] with nltk
        w_t_str = nltk.word_tokenize(compartmentalized_sentence[j])
        comp_w_t_sent.append(w_t_str)
        #comp_w_t_sent stands for compartmentalized, word-tokenized sentence
        j+=1
  return comp_w_t_sent

#print(compartmentalization_and_word_tokenization_2('你 要 那 个 chocolate 你 刚 才 吃 的 那 个 chocolate'))

print(compartmentalization_and_word_tokenization_2('你 要 那 个 chocolate 你 刚 才 吃 的 那 个 chocolate 你'))
print(compartmentalization_and_word_tokenization_2('我 是 从 camp 那 边 拿 来 的 自 从 mark 那 时 拿 来 了 之 后'))


#!/usr/bin/env python

import os
import sys
import logging

import gensim
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
# import joblib

assert gensim.models.word2vec.FAST_VERSION > -1

logging.basicConfig(
    format="%(asctime)s : %(levelname)s : %(message)s", level=logging.INFO
)

def main(run_variables):
    n_cores = 4
    seed = 423
    # seed = 564 #original seed

    k = run_variables["kmer_len"]
    d = 256
    w = 50
    neg_samps = 100
    samp_freq = 1e-06
    n_min = 10

    epochs = 5

    name = "uniprot_sprot"

    # NOTE this is not called
    # ids_fn = f"{name}_{k}_ids.pkl"
    # NOTE this file is space seperated, not comma
    # model_fn = f"w2v_model_{k}_{d}_{epochs}_{w}_{neg_samps}_{str(samp_freq).replace('0.','')}_{n_min}_model.pkl"
    print(run_variables["create_kmers_out"], run_variables["create_model_out"], flush=True)

    kmers_init = LineSentence(run_variables["create_kmers_out"], max_sentence_length=100000)

    model = Word2Vec(
        kmers_init,
        sg=1,
        size=d,
        window=w,
        min_count=n_min,
        negative=neg_samps,
        sample=samp_freq,
        iter=epochs,
        workers=n_cores,
        seed=seed,
    )

    model.save(run_variables["create_model_out"])

    # w2v_model = {}
    # for item in model.wv.vocab:
    #     w2v_model[item] = model[item]
    # joblib.dump(w2v_model, f"w2v_k{k}.joblib")

if __name__ == "__main__":
    main()


# _*_coding:utf-8 _*_
# from:https://blog.csdn.net/lxg0807/article/details/52960072
# 由于未来得及下测试数据集，所以测试一块做了一定的调整或忽略

# 导入模块
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
import fasttext

import jieba
import os

basedir = "task_3/data"  # 这是我的文件地址，需跟据文件夹位置进行更改
os.chdir(basedir)
dir_list = ['affairs', 'constellation', 'economic', 'edu', 'ent', 'fashion', 'game', 'home', 'house', 'lottery',
            'science', 'sports', 'stock']

##生成fastext的训练和测试数据集

ftrain = open("news_fasttext_train.txt", "w")
ftest = open("news_fasttext_test.txt", "w")

# 第一步获取分类文本，文本直接用的清华大学的新闻分本，可在文本系列的第三篇找到下载地址。
# 输出数据格式： 样本 + 样本标签
# 说明：这一步不是必须的，可以直接从第二步开始，第二步提供了处理好的文本格式。写这一步主要是为了记忆当时是怎么处理原始文本的。
num = -1
for e in dir_list:
    num += 1
    indir = basedir + e + '/'
    files = os.listdir(indir)
    count = 0
    for fileName in files:
        count += 1
        filepath = indir + fileName
        with open(filepath, 'r') as fr:
            text = fr.read()
        text = text.decode("utf-8").encode("utf-8")
        seg_text = jieba.cut(text.replace("\t", " ").replace("\n", " "))
        outline = " ".join(seg_text)
        outline = outline.encode("utf-8") + "\t__label__" + e + "\n"
        #         print outline
        #         break

        if count < 10000:
            ftrain.write(outline)
            ftrain.flush()
            continue
        elif count < 20000:
            ftest.write(outline)
            ftest.flush()
            continue
        else:
            break

ftrain.close()
# ftest.close()

# 训练模型
classifier = fasttext.train_supervised("news_fasttext_train.txt", label_prefix="__label__")

# 保存模型
opt="/home/nicken/NLP_study/nlp_task/task_3/model/news_fasttext.model"
classifier.save_model(opt)
#load训练好的模型
#classifier = fasttext.load_model('news_fasttext.model.bin', label_prefix='__label__')

#测试模型
result = classifier.test("news_fasttext_train.txt")
# print(result.precision)
# print(result.recall)
print(result)


import torch
import numpy as np
import seaborn as sns
import matplotlib.pylab as plt
from collections import defaultdict
from scipy.spatial.transform import Rotation as R

class AverageMeter(object):
    """ Computes and stores the average and current value."""
    def __init__(self):
        self.reset()

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=1):
        self.val = val
        self.sum += val * n
        self.count += n
        self.avg = self.sum / self.count

def subsample_graph(neighbors=None, not_deleted=None, keep_nodes=200, protected=[0]):
    """
    Subsample graph.

    Args:
        neighbors: dict of neighbors per node
        not_deleted: list of nodes, who did not get deleted in previous processing steps
        keep_nodes: number of nodes to keep in graph
        protected: nodes to be excluded from subsampling
    """
    if neighbors is not None:
        k_nodes = len(neighbors)
    else:
        raise ValueError('neighbors must be provided')

    # protect soma node from being removed
    protected = set(protected)

    # indices as set in random order
    perm = torch.randperm(k_nodes).tolist()
    all_indices = np.array(list(not_deleted))[perm].tolist()
    deleted = set()

    while len(deleted) < k_nodes - keep_nodes:

        while True:
            if len(all_indices) == 0:
                assert len(not_deleted) > keep_nodes, len(not_deleted)
                remaining = list(not_deleted - deleted)
                perm = torch.randperm(len(remaining)).tolist()
                all_indices = np.array(remaining)[perm].tolist()

            idx = all_indices.pop()

            if idx not in deleted and len(neighbors[idx]) < 3 and idx not in protected:
                break

        if len(neighbors[idx]) == 2:
            n1, n2 = neighbors[idx]
            neighbors[n1].remove(idx)
            neighbors[n2].remove(idx)
            neighbors[n1].add(n2)
            neighbors[n2].add(n1)
        elif len(neighbors[idx]) == 1:
            n1 = neighbors[idx].pop()
            neighbors[n1].remove(idx)

        del neighbors[idx]
        deleted.add(idx)

    not_deleted = list(not_deleted - deleted)
    return neighbors, not_deleted

def rotate_graph(pos_matrix, axis=None):
    ''' Randomly rotate graph in xyz-direction.

    Args:
        pos_matrix: Matrix with xyz-node positions (N x 3).
        axis: Axis around which to rotate. Defaults to `None`,
            in which case no rotation is performed.
    '''
    if axis is None:
        return pos_matrix

    rotation_matrix = R.random().as_matrix()

    if axis == 'x':
        rotation_matrix[0, 1] = 0
        rotation_matrix[0, 2] = 0
        rotation_matrix[0, 0] = 1
        rotation_matrix[1, 0] = 0
        rotation_matrix[2, 0] = 0
    elif axis == 'y':
        rotation_matrix[0, 1] = 0
        rotation_matrix[1, 0] = 0
        rotation_matrix[1, 1] = 1
        rotation_matrix[1, 2] = 0
        rotation_matrix[2, 1] = 0
    elif axis == 'z':
        rotation_matrix[0, 2] = 0
        rotation_matrix[1, 2] = 0
        rotation_matrix[2, 2] = 1
        rotation_matrix[2, 0] = 0
        rotation_matrix[2, 1] = 0

    rot_pos_matrix = pos_matrix @ rotation_matrix
    return rot_pos_matrix

def jitter_node_pos(node_positions, scale=1):
    """
    Randomly jitter nodes in xyz-direction.

    Args:
        node_positions: Matrix with xyz-node positions (N x 3).
        scale: Scale factor for jittering.
    """
    return node_positions + (torch.randn(*node_positions.shape).numpy() * scale)

def translate_soma_pos(node_positions, scale=1):
    """
    Randomly translate the position of the entire grpah.

    Args:
        node_positions: Matrix with xyz-node positions (N x 3).
        scale: Scale factor for jittering.
    """
    new_node_features = node_positions.copy()
    jitter = torch.randn(3).numpy() * scale
    new_node_features[:, :3] += jitter
    return new_node_features

def neighbors_to_adjacency_torch(neighbors, not_deleted):
    """ Create adjacency matrix from list of non-empty neighbors.
    """
    node_map = {n: i for i, n in enumerate(not_deleted)}

    n_nodes = len(not_deleted)

    new_adj_matrix = torch.zeros((n_nodes, n_nodes), dtype=float)
    for ii in neighbors.keys():
        for jj in neighbors[ii]:
            i, j = node_map[ii], node_map[jj]
            new_adj_matrix[i, i] = True  # diagonal if needed
            new_adj_matrix[i, j] = True
            new_adj_matrix[j, i] = True

    return new_adj_matrix

def neighbors_to_adjacency(neighbors, not_deleted):
    """
    Create adjacency matrix from list of non-empty neighbors.

    Args:
        neighbors: Dict of neighbors per node.
        not_deleted: List of nodes, who did not get deleted in previous processing steps.
    """
    node_map = {n: i for i, n in enumerate(not_deleted)}

    n_nodes = len(not_deleted)

    new_adj_matrix = np.zeros((n_nodes, n_nodes))
    for ii in neighbors.keys():
        for jj in neighbors[ii]:
            i, j = node_map[ii], node_map[jj]
            new_adj_matrix[i, i] = True  # diagonal if needed
            new_adj_matrix[i, j] = True
            new_adj_matrix[j, i] = True

    return new_adj_matrix

def adjacency_to_neighbors(adj_matrix):
    """
    Create list of non-empty neighbors from adjacancy matrix.
    Args:
        adj_matrix: adjacency matrix (N x N)
    """
    # Remove diagonal to avoid self-neighbors.
    a, b = np.where(adj_matrix - np.eye(len(adj_matrix)) == 1)
    neigh = dict()
    for _a, _b in zip(a,b):
        if _a not in neigh:
            neigh[_a] = set()
        neigh[_a].add(_b)
    return neigh

def compute_eig_lapl_torch_batch(adj_matrix, pos_enc_dim=32):
    """ Compute positional encoding using graph laplacian.
        Adapted from https://github.com/graphdeeplearning/benchmarking-gnns/blob/ef8bd8c7d2c87948bc1bdd44099a52036e715cd0/data/molecules.py#L147-L168.

    Args:
        adj_matrix: Adjacency matrix (B x N x N).
        pos_enc_dim: Output dimensions of positional encoding.
    """
    b, n, _ = adj_matrix.size()

    # Laplacian
    A = adj_matrix.float()
    degree_matrix = A.sum(axis=1).clip(1)
    N = torch.diag_embed(degree_matrix ** -0.5)
    L = torch.eye(n, device=A.device)[None, ].repeat(b, 1, 1) - (N @ A) @ N

    # Eigenvectors
    eig_val, eig_vec = torch.linalg.eigh(L)
    eig_vec = torch.flip(eig_vec, dims=[2])
    pos_enc = eig_vec[:, :, 1:pos_enc_dim + 1]

    if pos_enc.size(2) < pos_enc_dim:
        pos_enc = torch.cat([pos_enc, torch.zeros(pos_enc.size(0), pos_enc.size(1), pos_enc_dim - pos_enc.size(2), device=A.device)], dim=2)

    return pos_enc

def get_leaf_branch_nodes(neighbors):
    """"
    Create list of candidates for leaf and branching nodes.
    Args:
        neighbors: dict of neighbors per node
    """
    all_nodes = list(neighbors.keys())
    leafs = [i for i in all_nodes if len(neighbors[i]) == 1]

    candidates = leafs
    next_nodes = []
    for l in leafs:
        next_nodes += [n for n in neighbors[l] if len(neighbors[n]) == 2]

    while next_nodes:
        s = next_nodes.pop(0)
        candidates.append(s)
        next_nodes += [n for n in neighbors[s] if len(neighbors[n]) == 2 and n not in candidates and n not in next_nodes]

    return candidates

def compute_node_distances(idx, neighbors):
    """"
    Computation of node degree.
    Args:
        idx: index of node
        neighbors: dict of neighbors per node
    """
    queue = []
    queue.append(idx)

    degree = dict()
    degree[idx] = 0

    while queue:
        s = queue.pop(0)
        prev_dist = degree[s]

        for neighbor in neighbors[s]:
              if neighbor not in degree:
                queue.append(neighbor)
                degree[neighbor] = prev_dist + 1

    return degree

def drop_random_branch(nodes, neighbors, distances, keep_nodes=200):
    """
    Removes a terminal branch. Starting nodes should be between
    branching node and leaf (see leaf_branch_nodes)

    Args:
        nodes: List of nodes of the graph
        neighbors: Dict of neighbors per node
        distances: Dict of distances of nodes to origin
        keep_nodes: Number of nodes to keep in graph
    """
    start = list(nodes)[torch.randint(len(nodes), (1,)).item()]
    to = list(neighbors[start])[0]

    if distances[start] > distances[to]:
        start, to = to, start

    drop_nodes = [to]
    next_nodes = [n for n in neighbors[to] if n != start]

    while next_nodes:
        s = next_nodes.pop(0)
        drop_nodes.append(s)
        next_nodes += [n for n in neighbors[s] if n not in drop_nodes]

    if len(neighbors) - len(drop_nodes) < keep_nodes:
        return neighbors, set()
    else:
        # Delete nodes.
        for key in drop_nodes:
            if key in neighbors:
                for k in neighbors[key]:
                    neighbors[k].remove(key)
                del neighbors[key]

        return neighbors, set(drop_nodes)

def traverse_dir(start, to, neighbors):
    """
    Traverse branch start at node 'start' in direction of node 'to'.
    Args:
        start: start node
        to: destination node
        neighbors: dict of neighbors per node
    """
    visited = [start, to]
    next_nodes = [n for n in neighbors[to] if n != start]

    while next_nodes:
        s = next_nodes.pop(0)
        visited.append(s)
        next_nodes += [n for n in neighbors[s] if n not in visited]

    return visited

def remap_neighbors(x):
    """
    Remap node indices to be between 0 and the number of nodes.

    Args:
        x: Dict of node id mapping to the node's neighbors.
    Returns:
        ordered_x: Dict with neighbors with new node ids.
        subsampled2new: Mapping between old and new indices (dict).
    """
    # Create maps between new and old indices.
    subsampled2new = {k: i for i, k in enumerate(sorted(x))}

    # Re-map indices to 1..N.
    ordered_x = {i: x[k] for i, k in enumerate(sorted(x))}

    # Re-map keys of neighbors
    for k in ordered_x:
        ordered_x[k] = {subsampled2new[x] for x in ordered_x[k]}

    return ordered_x, subsampled2new

def plot_neuron(neighbors, node_feats, ax1=0, ax2=1, soma_id=0, ax=None):
    """ Plot graph of 3D neuronal morphology. """
    colors = list(sns.dark_palette('#69d', n_colors=4))
    _, dim = node_feats.shape

    if ax is None:
        fig, ax = plt.subplots(1, 1)

    ax.set_aspect('equal')

    for i, neigh in neighbors.items():
        for j in neigh:
            n1, n2 = node_feats[i], node_feats[j]
            c = colors[1] if dim == 3 else colors[np.argmax(n2[4:])]
            ax.plot([n1[ax1], n2[ax1]], [n1[ax2], n2[ax2]], color=c, linewidth=1)

    ax.scatter(node_feats[soma_id][ax1], node_feats[soma_id][ax2], color=colors[0], s=10, zorder=10)

    sns.despine(trim=1)

def plot_tsne(z, labels, targets, colors=None):
    """ Plot t-SNE clustering. """
    u_labels = np.unique(labels)
    fig = plt.figure(1, figsize=(8, 8))
    for label in u_labels:
        plt.scatter(z[labels == label, 0],
                    z[labels==label, 1],
                    s=20,
                    label=str(targets[label]),
                    color=colors[label])
    plt.legend(bbox_to_anchor=(1,1))
    plt.axis('off')


# To use custom voices, send your message in the format
# "!voice: message" for DONODUCKK (ex - !homer-simpson: doh)
#  or
#  ";v voice: message" for CHATTERDUCK (ex - ;v homer-simpson: doh) NOTE: the first one is a semicolon, not a regular colon, confusing but avoids conflicts with other popular twitch chat bots ¯\_(ツ)_/¯
#
# If you don't it'll just fall through to whatever the streamer sets (random by default)
# Known issues with certain voices: https://uberduck.fandom.com/wiki/List_of_words_the_Uberduck_voices_can't_say_correctly

voices = [
    "101-dalmatians-lucky",
    "101-dalmatians-rolly",
    "11-45-g",
    "11th-doctor",
    "12th-doctor",
    "13-amp",
    "13-zt",
    "15ai-spongebob",
    "1988-barney",
    "21-savage",
    "2pac",
    "2pac-arpa",
    "2pac-speaking",
    "3kliksphilip",
    "4th-doctor",
    "5-volt",
    "50-cent",
    "6ix9ine",
    "8-ball",
    "9-eye",
    "a-plus-start",
    "aaron-hull",
    "abby-archer",
    "abby-mallard",
    "abe-simpson",
    "abigail-marston",
    "ace-bunny",
    "acemillion",
    "adam-amundson",
    "adam-carolla",
    "adam-driver",
    "adam-hale",
    "adam-is-cool-and-stuff",
    "adam-jg",
    "administrator",
    "administrator-no-mic",
    "adora",
    "adorabat",
    "adrien-agreste",
    "adventure-core",
    "advisor",
    "aei-guy",
    "agent-47",
    "agent-tc2",
    "agent-ulgrin",
    "aggressive-sniper",
    "agnes-skinner",
    "ahit-conductor",
    "ahit-seal",
    "ahsoka",
    "aigis",
    "ajax",
    "akane",
    "akane-talknet",
    "akane-tt2",
    "akechi",
    "akemi-homura",
    "aku-aku",
    "al-hitchcock-arpa",
    "al-michaels",
    "alan-rickman",
    "alan-smiling-friends",
    "alan-wake",
    "alan-wake-calm",
    "alan-watts",
    "albert-einstein",
    "albert-wesker",
    "albus-duckweed",
    "alchiter",
    "alec-baldwin",
    "alec-mason",
    "alex-jones",
    "alex-the-lion",
    "alex-wally-wingert",
    "alexa",
    "alexis-dupre-edzel",
    "alexis-rhodes",
    "alfred-hitchcock",
    "alfred-tas",
    "alfur-aldric",
    "alice-wake",
    "alpha-pig",
    "alyx-vance",
    "alyx-vance-hla",
    "am-ts1",
    "amanda-desanta",
    "amanda-stepto",
    "amethyst",
    "amitie",
    "amity-blight",
    "amy-rose",
    "amy-rose-cr",
    "amy-rose-jd",
    "ana",
    "anais-watterson-season1",
    "anakin-skywalker",
    "anarchist-csgo",
    "andrew-crothers",
    "andy-apple",
    "andy-bell",
    "andy-bell-sing",
    "andy-bernard",
    "andy-davis-ts3",
    "angel-dust",
    "angela",
    "angela-martin",
    "angelica",
    "angelica-pickles",
    "angelina-mouseling",
    "angwin",
    "animat",
    "anji-mito-str",
    "anna-frozen",
    "anne-boonchuy",
    "anne-robinson",
    "annie-james",
    "announcer-salesman",
    "annoyingorange",
    "annoyingorange-2022",
    "ant-wordworld",
    "anthony-field",
    "anthony-sullivan",
    "antman",
    "anton-herzen",
    "aoi",
    "aol-guy",
    "apothecary-gary",
    "apple-white",
    "applebloom",
    "applejack",
    "apu",
    "aquaman",
    "arbys",
    "archibald-asparagus",
    "argonianka",
    "ariana-grande",
    "ariel",
    "arle-nadja",
    "army-armstrong",
    "arne-magnusson",
    "arnold-schwarzenegger",
    "arnold-shortman",
    "art-drewbeary",
    "arte",
    "arthas-menethil",
    "arthur-c-clarke",
    "arthur-c-clarke-('seven-wonders-of-the-world)",
    "arthur-lowe",
    "arthur-morgan",
    "arthur-read",
    "arthurmorgan",
    "ash-ketchum",
    "ash-ketchum-sn",
    "ash-williams",
    "ashe",
    "ashens",
    "asmongold",
    "astrid",
    "atchan",
    "atstbis-guy",
    "att-mike",
    "augustus",
    "aumsum",
    "aunt-bernice",
    "avatar-aang",
    "avgn",
    "avicii",
    "awesome-possum",
    "axl_x7",
    "ayn-rand",
    "b-la-b",
    "b-la-b-controllable",
    "babs-bunny",
    "baby-alive-2012",
    "baby-mario",
    "badgerclops",
    "bailey",
    "baldi",
    "ballas-1",
    "balto",
    "bandit-heeler",
    "bangkok-bts",
    "banzai",
    "baptiste",
    "barack-obama",
    "barbara-pegg",
    "barf-bag",
    "barnacle-boy",
    "barney",
    "barney-calhoun",
    "barney-gumble",
    "barnham",
    "barrel-amphibia",
    "barry-amphibia",
    "barry-b-benson",
    "bart-simpson",
    "bart-simpson-la",
    "bartender-twnn",
    "barton",
    "batman",
    "batman-injustice2",
    "baxter-gb2",
    "baymax",
    "bayonetta",
    "bbbh-bear",
    "bear-wordworld",
    "beard-burger-master",
    "beatrice",
    "beautiful-gorgeous",
    "beavis",
    "bebe-stevens",
    "beli-huniepop",
    "bella-amphibia",
    "belle",
    "ben",
    "ben-patrick-johnson",
    "bender-rodriguez",
    "benedict-cumberbatch",
    "benett-foddy",
    "benjamin-btd",
    "benshapiro",
    "benson",
    "bentley",
    "bernard-bernoulli",
    "bernard-okko",
    "bernardo-amphibia",
    "bert",
    "betty-deville",
    "betty-white",
    "bev-bighead",
    "bfb-clock",
    "bfdi-six",
    "bfdi-x",
    "big",
    "big-al",
    "big-band",
    "big-bird",
    "big-gay",
    "big-gay-al",
    "big-l",
    "big-l-arpa",
    "big-mac",
    "big-smoke",
    "big-the-cat-jsj",
    "big-the-cat-ow",
    "big-tobacco",
    "bigbillhell",
    "bigby-wolf",
    "biggayrapper",
    "biggie-smalls",
    "bigweld",
    "bijou",
    "bill-cipher",
    "bill-clinton",
    "bill-gates",
    "bill-gates-1995",
    "bill-grey",
    "bill-l4d",
    "bill-nye",
    "bill-owl-house",
    "bill-w",
    "bill-wurtz-talking",
    "billhawks",
    "billie-joe-armstrong",
    "billy",
    "billy-joel",
    "billymays",
    "binjpipe",
    "binyot",
    "bionic-coyote",
    "birdo",
    "birthday-boy-blam",
    "bj",
    "black-raven",
    "blacksonic",
    "blair-the-balloonist",
    "blake-belladonna",
    "blaze-the-cat",
    "blitz",
    "blockhead",
    "blocktoast64",
    "blocky",
    "bloo",
    "bloppy-pants",
    "blossom",
    "blucario5995",
    "blue-haired-lawyer",
    "bluey",
    "blupi",
    "bluster-kong",
    "blutarch",
    "bmebook",
    "bmo",
    "bms-walter",
    "bms-walter-tn",
    "bo-burnham",
    "bo-peep",
    "bob-2000",
    "bob-barker",
    "bob-fnf",
    "bob-late90s",
    "bob-marley",
    "bob-parr",
    "bob-ross",
    "bob-veggietales",
    "boba",
    "bobby-hill",
    "bog-amphibia",
    "bojack",
    "bojack-horseman",
    "bolok",
    "bomb-man",
    "bomberman-jetters",
    "bombi",
    "bon-bon",
    "bonzi-buddy",
    "boo-boo-bear",
    "boog",
    "book",
    "booker-t",
    "booker-tt",
    "boomerang",
    "bop-it-announcer",
    "boring-tattletail",
    "boscha",
    "bosco",
    "bottle_bfdi",
    "bourbon-dupre-nick",
    "bow",
    "bowser-jr",
    "bowser-rylanlego",
    "boxy-boy",
    "boyd-cooper",
    "bracelety",
    "braddock",
    "brainy-smurf",
    "brak",
    "brawn",
    "bria-owl-house",
    "brian-cummings",
    "brian-griffin",
    "brian-may",
    "brock",
    "brock-masters-ex",
    "brock-samson",
    "brooke",
    "brother-bear",
    "bruno-bucciarati",
    "bruno-madrigal",
    "bruno-powroznik",
    "brute-tc2",
    "bryan-cranston",
    "bsd-banzi",
    "btm",
    "btmc",
    "bubble",
    "bubble-bass",
    "bubble-buddy",
    "bubble-classic",
    "bubbles",
    "bubbles-calm",
    "bubs",
    "bubs-2001",
    "bubsy-1",
    "bubsy-3d",
    "buck-cluck",
    "buck-rockgut",
    "buckwild-iceage",
    "buddy-holly",
    "buddy-ktb",
    "bug-wordworld",
    "buggy",
    "bugs-bunny",
    "bugs-bunny-billy-west",
    "bugs-bunny-greg-burson",
    "bugs-bunny-jeff-bergman",
    "bugs-bunny-joe-alaskey",
    "bullwinkle",
    "bumblebee",
    "bumblebee-m",
    "bunji",
    "bunny-bravo",
    "bunty",
    "burgerface-am",
    "burrito-rant",
    "burt-curtis",
    "burton-ninjala",
    "buster-bunny",
    "buttercup",
    "buttercup-2016",
    "buttercup-rr",
    "butters-90s",
    "butters-stotch",
    "butthead",
    "buzz-lightyear",
    "buzz-lightyear-pat-fraley",
    "byakuya-togami",
    "c-3po",
    "c-junior",
    "cabby",
    "caboose",
    "cadence",
    "cadpig",
    "cait",
    "caitlin-pmex",
    "cake-core",
    "cake_bfb",
    "callmecarson",
    "callum-adams",
    "camila-noceda",
    "camille_lol",
    "cammy",
    "cammy-cvs2",
    "candace-flynn",
    "candace-owens",
    "candy-kong",
    "cannonball-jenkins",
    "cannonbolt",
    "capncrunch",
    "captain-beatrix",
    "captain-bufo",
    "captain-churchill",
    "captain-falcon",
    "captain-feathersword",
    "captain-fussenpepper",
    "captain-grime",
    "captain-lou-albano",
    "captain-qwark",
    "captain-salt",
    "captain-sweet-tooth-tom",
    "carl-athf",
    "carl-carlson",
    "carl-chryniszzswics",
    "carl-johnson",
    "carl-sagan",
    "carl-wheezer",
    "carlisle-cullen",
    "carly-shay",
    "carmelita",
    "carmen-avila",
    "carmen-winstead",
    "caroline-portal",
    "carolyn-singing",
    "carolyn-speaking",
    "carolyn-test1",
    "casey-kasem",
    "casey-moten",
    "cat-in-the-hat",
    "cat-valentine",
    "catra-applesauce",
    "catwoman",
    "cave-johnson",
    "cave-johnson-psm",
    "cayde-6",
    "cayenne-pepper-luke",
    "cbt",
    "cdi-ganon",
    "cdi-impa",
    "cdi-link",
    "cdi-zelda",
    "cecil-palmer",
    "cecil-turtle",
    "celestia",
    "celestia-ldb",
    "celestia-ldb-tknet",
    "celia-mae",
    "cgme-yt",
    "chad-warden",
    "chadtronic",
    "chalmers",
    "chance-the-rapper",
    "chandler-bing",
    "charles-calvin",
    "charles-martinet",
    "charles-nelson-riley",
    "charlessmith",
    "charlie-binktoons",
    "charlie-brown",
    "charlie-brown-acbc",
    "charlie-brown-snoopys-classiks-on-toys",
    "charlie-dompler",
    "charlie-ice-scream",
    "charlie-o'donnell",
    "charmy-bee-ab",
    "charmy-bee-heroes",
    "chas-finster",
    "cheap-cheap",
    "cheasel-t-weasel",
    "cheer-reader",
    "cheerilee",
    "cheese",
    "cheezborger",
    "chef",
    "chef-fritz",
    "chef-fujimoto",
    "cheggers",
    "chelmey",
    "chester-stone",
    "chiaki-nanami",
    "chicas-rainbow",
    "chicken",
    "chicken-little",
    "chicken-strips",
    "chickenlover",
    "chief-keef",
    "chihiro-fujisaki",
    "chikn-nuggit",
    "childrenescapeman_insight_upper",
    "chills",
    "china-uncensored",
    "chip",
    "chipflake",
    "chiquito-de-la-calzada",
    "chiro",
    "chiro-jetix",
    "chita",
    "chloe-carmichael",
    "chloe-grace-moretz",
    "chocolate-rain",
    "chomper",
    "chop-chop-master-onion",
    "chopper",
    "chris-dvs",
    "chris-evans",
    "chris-griffin",
    "chris-hansen",
    "chris-redfield",
    "chris-tarrant",
    "christopher-hitchens",
    "christopher-lee",
    "chrysalis",
    "chuck-e-cheese-1977",
    "chuck-e-cheese-demo",
    "chuck-mcgill",
    "chuck-the-evil-sandwich-making-guy",
    "chuckie-finster",
    "chucky-nft",
    "chum-world-clown",
    "chun-li",
    "church",
    "churchguy",
    "cindy-vortex",
    "cinemasins",
    "circus-baby",
    "citv-announcer",
    "clair-mastersex",
    "claire-foley",
    "clancy-wiggum",
    "clank",
    "claptrap",
    "clarabelle-cow",
    "classic-firey",
    "classic-four",
    "classic-tord",
    "classic-x",
    "claus-clock",
    "clem",
    "cleo",
    "cletus-spuckler",
    "cleveland-brown",
    "clifford-dog",
    "clive-handforth",
    "clivedove",
    "clubhouse-announcer",
    "clyde-donovan",
    "clyde-mcbride",
    "cmanflip",
    "coach",
    "coach-buzzcut",
    "coach-l4d",
    "coach-oleander",
    "coach-z",
    "coach-z-2001",
    "coco-bandicoot",
    "coconuts",
    "cole-phelps",
    "collin",
    "colonel-masako",
    "colonel-noodle",
    "colt",
    "comet",
    "comet-astroblast",
    "comic-book-guy",
    "comm-wells",
    "compton-boole",
    "computer",
    "computress",
    "conan",
    "connie-maheswaran",
    "conny-cryptoland",
    "conscience",
    "constantin",
    "contrapoints",
    "cookie-masterson",
    "cookie-monster",
    "cookie-monster-dr",
    "cornfed",
    "cortana",
    "cosmo",
    "cosmo-the-seedrian",
    "cotton-hill",
    "count-von-count",
    "cousin-fred",
    "cow",
    "cozy-glow",
    "cr1tikal",
    "crabblesnitch",
    "crack-stuntman",
    "craig-ferguson",
    "craig-tucker",
    "craig-williams-cotc",
    "cranky-kong",
    "cranky-kong-uncle-al",
    "crash-bandicoot-csb-promo",
    "crate-molov",
    "cravendish",
    "cream-the-rabbit",
    "cream-the-rabbit-rb",
    "cream-the-rabbit-rh",
    "cricket-green",
    "cris-collinsworth",
    "crispin-brown",
    "crossbreed-priscilla",
    "crunch-bandicoot-woc",
    "crusade-announcer",
    "crusoe",
    "cryptosporidium-137",
    "cs188",
    "cubot",
    "cuno",
    "cuphead",
    "curiosity-core",
    "cut-man",
    "cvs2-ann",
    "cyber-quincy",
    "cybil",
    "cyborg-legodimensions",
    "cynthia-masters-ex",
    "cypher-valorant",
    "da-vinci-dalmatian",
    "dababy",
    "daddy-eggman",
    "daffy-duck",
    "daffy-duck-alaskey",
    "daffy-duck-alasky",
    "daily-dose-of-internet",
    "daisy",
    "daisy-duck",
    "daizy",
    "dale-gribble",
    "damon-albarn",
    "damon-albarn-sing",
    "dan-binktoons",
    "dan-povenmire",
    "dan-sfv",
    "dan-tdm",
    "dan-vs",
    "danger-duck",
    "daniel-gajardo",
    "daniel-mason",
    "danny-devito",
    "danny-devito-angry",
    "danny-phantom",
    "danooct",
    "dantdm",
    "daphne-blake",
    "darby",
    "darcy",
    "daria",
    "darius-mason",
    "dark-danny",
    "darrell",
    "darwin-watterson",
    "dashiegames",
    "dave-gahan",
    "dave-madson",
    "david-bazookie",
    "david-bowie",
    "david-byrne",
    "david-campcamp",
    "david-cross",
    "david-holt",
    "david-kebabby",
    "david-seville",
    "david-spade",
    "dawko",
    "dawko-current",
    "daxflame",
    "daxflame-2s",
    "daxter",
    "ddr-345",
    "deadpool",
    "debbie-thornberry",
    "dee-dee",
    "deebeekaw",
    "deema",
    "deema-s3/4",
    "deepak-dalmatian",
    "defective-turret",
    "deimos",
    "demeech",
    "demoman",
    "dendy",
    "dennis-prager",
    "derek-bum-kitchen-gun",
    "derek-rae",
    "derpy-bacon",
    "derpy-hooves",
    "desmond",
    "devil",
    "devlemons",
    "devlin",
    "dewey-finn",
    "dexter",
    "dexters-dad",
    "dexters-mom",
    "dharr-mann",
    "diamondhead",
    "diana-burnwood",
    "dib-membrane",
    "diddy-kong",
    "diddykong",
    "didi-pickles",
    "diego",
    "diesel10",
    "dima",
    "dimitri-allen",
    "dimitri-losteau",
    "dingodile-fredtatasciore",
    "dio-jp",
    "dion-aquato",
    "dipper-pines",
    "discord",
    "disney_channel",
    "disneychannel_bounce",
    "dixie-kong",
    "dj-jackitt",
    "dj-loggins",
    "dj-professor-k",
    "dj-spit",
    "dj_subatomic_supernova",
    "django",
    "dk-rap",
    "doc-hudson",
    "doc-louis",
    "doctor-breen",
    "doctor-capek",
    "dogen-boole",
    "dolly-dalmatian",
    "dolores",
    "dolph-starbeam",
    "donald-duck",
    "donald-duck-normal",
    "donald-fagen",
    "donald-fagen-sing",
    "donaldducc",
    "donatella",
    "donkey",
    "donkey-kong",
    "donkey-kong-singing",
    "donkey-mark-moseley",
    "donpaolo",
    "donut",
    "doomslayer",
    "dora",
    "dorami",
    "dorkly-tails",
    "dot-warner",
    "double-trouble",
    "doug-dimmadome-owner-of-the-dimmsdale-dimmadome",
    "dq-lips",
    "dr-bunsen-honeydew",
    "dr-doofenshmirtz",
    "dr-dre",
    "dr-eggman",
    "dr-eggman-mp",
    "dr-frakes",
    "dr-gill-gilliam",
    "dr-hibbert",
    "dr-ivo-robotnik",
    "dr-jan",
    "dr-light",
    "dr-loboto",
    "dr-mephesto",
    "dr-n-tropy",
    "dr-nefario-despicable-me",
    "dr-nefarious",
    "dr-neo-cortex-cb",
    "dr-neo-cortex-lex",
    "dr-nick",
    "dr-phil",
    "dr-rabbit",
    "dr-richard-keller",
    "dr-robotnik-movie",
    "dr-rosenberg",
    "dr-scratchansniff",
    "dr-two-brains",
    "dr-wakeman",
    "dr-wily",
    "dr-wily-m",
    "draco",
    "dracula-ht",
    "drake",
    "dream-clay",
    "drew-pickles",
    "drive-thru-whale",
    "droid",
    "duck-wordworld",
    "duckman",
    "duhhh-cringe-guy",
    "duke-nukem",
    "duke-nukem-forever",
    "dumb-liono",
    "dustin-henderson-s4",
    "dva",
    "dwayne-futon",
    "dwight-schrute",
    "dylan-dalmatian",
    "e102-gamma",
    "e123omega",
    "e40",
    "e40-speaking",
    "earl-www",
    "easter-bunny",
    "easy-pete",
    "eazy-e",
    "eazyspeezyyt",
    "echoes-p",
    "eclipsa-butterfly",
    "ecolo",
    "ed",
    "ed-bighead",
    "ed-sullivan",
    "eda-clawthorne",
    "eda-clawthorne-teen",
    "edd",
    "edd-gould",
    "eddache",
    "eddie-guerrero",
    "eddie-the-mean-old-yeti",
    "eddsworld-edd",
    "eddsworld-ell",
    "eddsworld-jon",
    "eddsworld-matt",
    "eddsworld-tom",
    "eddsworld-tord",
    "eddy",
    "edi",
    "edna-mode",
    "edna-mode-kd",
    "eduardo-bb",
    "eduardo-con",
    "eeyore",
    "eight",
    "eijiro-kirishima",
    "el-jeff",
    "elastigirl",
    "eldwin-blair",
    "elec-man",
    "electriclizardfren",
    "electrifyxd",
    "electroboom",
    "electrolls",
    "element-animation-villager",
    "eli-king",
    "eli-vance",
    "elijah-wood",
    "elinor",
    "elinor-ari",
    "elio-masters-ex",
    "elirin",
    "elirin-jp",
    "elise-gresch-colton",
    "eliza-thornberry",
    "elizabeth",
    "elizabeth-comstock",
    "ellen",
    "ellie-iceage",
    "elliot",
    "elliot-mt",
    "ellis",
    "elmer-fudd",
    "elmer-fudd-billywest",
    "elmo",
    "elon-musk",
    "elora",
    "elsa",
    "elsa-lichtmann",
    "elton-john",
    "elvis",
    "emerald-herald",
    "emily-kaldwin",
    "eminem",
    "eminem-arpa2",
    "eminem-freestyle",
    "eminem-young",
    "emma-watkins",
    "emmet",
    "emperor-belos",
    "emperor-zurg",
    "empirrre",
    "ena_happy",
    "engineer",
    "enid",
    "enrico-pucci",
    "enterprisenerd",
    "entrapta",
    "eos",
    "eric-bischoff",
    "eric-cartman",
    "eric-cartman-90s",
    "erik-finman",
    "erin-esurance",
    "ernie",
    "escargoon",
    "espio-the-chameleon",
    "ess",
    "esther-vt",
    "eteled",
    "ethan-h3h3",
    "ethan-masters-ex",
    "eugene-from-mao-mao",
    "eustace-bagg-s4",
    "evaneratv",
    "eve",
    "eve-nsr",
    "evil-julie",
    "evw",
    "eye",
    "ezekiel-td",
    "facade-grace",
    "facade-trip",
    "face-nickjr",
    "fact-core",
    "faderax64",
    "falco-lombardi",
    "fandroid",
    "faraday",
    "farmer-alfred",
    "farmer-ben",
    "fast-food",
    "fast-tony-iceage",
    "fat-albert",
    "fate-ur-ts-tck-narrator",
    "father-grigori",
    "faust-owl-house",
    "fazbear",
    "fccd-spongebob",
    "fccd-squidward",
    "fdr",
    "fefe",
    "fegelein",
    "feli",
    "felicia",
    "felicia-sundew",
    "felix-biederman",
    "felix-the-cat",
    "female-narrator",
    "femmedic",
    "ferb",
    "fergus-fox",
    "fernando-costilla",
    "fetcher",
    "fgteev-duddy",
    "fgteev-lex",
    "fgteev-mike",
    "fgteev-moomy",
    "fhfif-cheese",
    "filburt",
    "filia",
    "fio",
    "fiona",
    "fire-keeper",
    "fire-man",
    "firey",
    "fish-head",
    "fisherman-hl2",
    "fitnessgram",
    "fitz",
    "five",
    "five-hargreeves",
    "flamingo-yt",
    "fleetway-super-sonic-fnf",
    "flightreacts",
    "flik",
    "floppy",
    "flora-reinhold",
    "flower",
    "flowey",
    "flowey-revtrosity",
    "fludd",
    "flumpty",
    "flushed-away-sid",
    "fluttershy",
    "flying-gorilla",
    "fnf-bf",
    "fnf-gf",
    "fnf-gf-t",
    "fnf-skid",
    "foghorn-leghorn-bill",
    "foldy",
    "ford-cruller",
    "forky",
    "forza-4-satnav",
    "forza-alex",
    "forza-cortana",
    "forza-gps",
    "forza-rebecca",
    "four",
    "fowler",
    "fox-mccloud",
    "foxy",
    "foxy-fnafworld",
    "fozzie-bear",
    "francis-l4d",
    "frank-grimes",
    "frank-welker",
    "frank-winters",
    "franklin-clinton",
    "frazie",
    "fred-durst",
    "fred-flintstone-henry-corden",
    "fred-flintstone-jeff-bergman",
    "fred-fredburger",
    "fred-jones",
    "fred-the-fish",
    "freddie-benson",
    "freddie-benson-s1",
    "freddie-mercury",
    "freddie-mercury-speaking",
    "freddy-tlt",
    "frenchy",
    "frieza",
    "frog-wordworld",
    "frogger-beyond",
    "frogger-great-quest",
    "frosty",
    "funky-kong",
    "funnel-boy",
    "funny-valentine",
    "fusionzgamer",
    "fuzzy-lumpkins",
    "g-mat",
    "g-men",
    "gabe-sweats",
    "gaben",
    "gabriele-rewis-deutsch",
    "garfidea",
    "garfield-fw",
    "garfield-fw-nsab",
    "garfield-jb",
    "garfield-lm",
    "garnet",
    "garrus-vakarian",
    "gary-coleman",
    "gary-smith",
    "garycpi",
    "geico-announcer",
    "gelatin",
    "gelatin-iw",
    "gem-archer",
    "gem-archer-sing",
    "gemcutters",
    "gene-wilder",
    "general-grievous",
    "general-klump",
    "general-pepper",
    "general-roth",
    "general-skarr",
    "general-yunan",
    "generic-purple-protogen",
    "george-beard-movie",
    "george-bush",
    "george-carlin",
    "george-carlin-narrator",
    "george-costanza",
    "george-harrison",
    "george-liquor",
    "george-takei",
    "george-volcano",
    "george-wood-navgtr",
    "gerald-broflovski",
    "geraltv2",
    "gertie",
    "gex",
    "ghost-host",
    "ghostpolitics",
    "gigguk",
    "gil-gunderson",
    "ginger",
    "gingy",
    "giorno-giovanna",
    "giovanni-team-rocket",
    "gir",
    "girl-stinky",
    "girlwiththedogs",
    "gisu",
    "giulia-marcovaldo",
    "glados",
    "glados-p2",
    "glamrock-freddy",
    "glimmer",
    "gloria-bb",
    "glyptodon-iceage2videogame",
    "gman",
    "gmm-rhett",
    "gnorris",
    "goku",
    "gokudbf",
    "gonta",
    "gonta-l2m",
    "gonzo",
    "goodman-sml",
    "goofy",
    "goofyahh-jimmy",
    "google-assistant",
    "gordon-ramsay",
    "gordon-reinhold",
    "gordon-tatmr",
    "gordon-the-big-hotr",
    "goro-akechi",
    "goro-majima",
    "gospel-bill",
    "gottfried",
    "gradeaundera",
    "grandma-squarepants",
    "grandmother-fa",
    "grandpa-lou",
    "granny-may",
    "grant-berrios",
    "greeny",
    "greg-hamilton",
    "greg-heffley-2021",
    "greg-page",
    "greg-page-(tv-series-2)",
    "greg-sestero",
    "greg-universe",
    "gregory-(security-breach)",
    "gregory-fnaf",
    "griffin-mcelroy",
    "griggs-hl2",
    "grigori-talknet",
    "grim",
    "grimlock",
    "grimlock-m",
    "gromble",
    "grounder",
    "groundskeeper-willie",
    "grover",
    "gru",
    "grumpy-7d",
    "grumpy-grizzly",
    "grunkle-stan",
    "gta-packie",
    "guenther-steiner",
    "guga-foods",
    "guga-narrating",
    "gumball",
    "gumball-jh",
    "gummibar",
    "gummibar-racing",
    "gummibar-tonekind",
    "guptill89",
    "guru",
    "guru-ant",
    "gus-porter",
    "gustavo-fring",
    "guts-man",
    "guy-am-i",
    "guy-fieri",
    "gwendolin-btd6",
    "gwonam",
    "gypsy-crusader",
    "h-jon-benjamin",
    "habib",
    "hades",
    "haiji",
    "hairdresser-octopus",
    "hajime-hinata",
    "hal-9000",
    "half-life-scientist",
    "half-life-transit-system",
    "hamm",
    "hammy",
    "hamtaro-dexter",
    "hamtaro-howdy",
    "hamtaro-stan",
    "handlab-announcer",
    "handunit-hw",
    "handunit-sl",
    "hank-hill",
    "hans-moleman",
    "hans-volter",
    "harley-quinn",
    "harold",
    "haru-okumura",
    "haruhi-fujioka",
    "hawkodile",
    "hayley-williams",
    "hazel-haskett",
    "heavy",
    "hecko",
    "hecko-tok",
    "hector-rivera",
    "heffer-wolfe",
    "heihachi",
    "helga",
    "hello-kitty",
    "hello-nurse",
    "hendrix",
    "henery-hawk",
    "henry-emily",
    "henry-stein-old",
    "henry-tatmr",
    "henry-tatmr-tortoisetts",
    "herbert-the-pervert",
    "heston",
    "hev-suit",
    "hgrunt-commander",
    "hhgregg",
    "hhpay-ami",
    "hhpay-kaz",
    "hhpay-yumi",
    "hiccup",
    "high-boi",
    "hikaru-hitachiin",
    "hilbert-masters-ex",
    "hilda",
    "hilda-masters-ex",
    "hilnavunner",
    "him",
    "him-announcer",
    "hitler-calm",
    "hitler-rant",
    "hoagie",
    "hoffman-b4b",
    "hoist",
    "hollis-forsythe",
    "holographic-assistant",
    "homer-simpson",
    "homer-simpson-shar",
    "homer-tus-s1",
    "homero",
    "homestar-runner",
    "homestar-runner-2001",
    "homsar",
    "hoops",
    "hooty",
    "hop-pop",
    "hope-hardees",
    "hopper",
    "horace-amphibia",
    "hordak",
    "hotdog",
    "hotel-mario",
    "hound",
    "housebroken-chief",
    "housebroken-elsa",
    "housebroken-honey",
    "how-its-made-narrator",
    "howard-finkel",
    "howard-finkel-no-echo",
    "howie-mandel",
    "hsien-ko",
    "https://appuberduckai/speak#mode=tts-reference&voice=chloe-grace-moretz-pre-teen",
    "huckleberry-hound",
    "huggbees",
    "hugh-bliss",
    "hugh-neutron",
    "hugo-davies",
    "hugodavies",
    "hulk-hogan",
    "human-grunt",
    "humphrey-westwood",
    "hungry-girl",
    "hungry-pumkin",
    "hunter-owl-house",
    "hunter-the-cheetah",
    "ice-bear",
    "ice-cube",
    "ice-man",
    "ickis",
    "ihe",
    "ike",
    "im-meen",
    "im-weasel",
    "incineroar",
    "indian-shopkeeper",
    "indie-cross-cuphead",
    "infinite",
    "infinite-eminem",
    "infomaniac",
    "inka-dinka-doo",
    "inspector-gadget",
    "instructor-mooselini",
    "instructor-moosesha",
    "internetgirl_insight_upper",
    "iori-mi2",
    "ir-baboon",
    "iris-chill",
    "iron-man",
    "ironhide",
    "ironhide-m",
    "isaac-kleiner",
    "isabella",
    "island-owl",
    "itachi-uchiha",
    "itchy",
    "its-a-bully",
    "itsamemyleo",
    "ivy-sundew",
    "izuku-midoriya",
    "jacinda",
    "jack",
    "jack-black",
    "jack-corelo-joey",
    "jack-corelo-rex",
    "jack-fenton",
    "jack-in-the-box",
    "jack-kelso",
    "jack-o-chica",
    "jack-sather",
    "jack-skellington",
    "jacksepticeye",
    "jacksfilms",
    "jacksucksatlife",
    "jaden-yuki",
    "jaiden-animations",
    "jak",
    "jake-subway-surfers",
    "jake-the-dog",
    "james-earl-jones",
    "james-hetfield",
    "james-may",
    "james-taylor",
    "james-thomastank",
    "jane-ninjala",
    "jankman",
    "jasper",
    "jasper-beardsley",
    "javier",
    "jay-hunter",
    "jay-jay-the-jet-plane",
    "jay-leno",
    "jayz",
    "jazz",
    "jazz-m",
    "jboogie",
    "jc-denton",
    "jcole",
    "jean-claude",
    "jean-descole",
    "jean-pierre-polnareff",
    "jebus",
    "jed",
    "jeff-fatt",
    "jeff-gb",
    "jeff-manning",
    "jeffy-sml",
    "jellybean",
    "jeremy-clarkson",
    "jericho-fallout",
    "jerma-mitch",
    "jerma985",
    "jerry-gourd",
    "jerry-lawler",
    "jerry-seinfeld",
    "jerryrigeverything",
    "jesse-pinkman",
    "jessie-cowgirl",
    "jessie-huniepop",
    "jesus-christ",
    "jet-the-hawk",
    "jet-the-hawk-jg",
    "jevil",
    "jfk",
    "jfk-clone-high",
    "jim-cummings",
    "jim-dale",
    "jim-halpert",
    "jim-ross",
    "jim-thornton",
    "jimbo-jones",
    "jimbo-kern",
    "jiminy-cricket",
    "jimmy",
    "jimmy-carter",
    "jimmy-cool",
    "jimmy-de-santa",
    "jimmy-durante",
    "jimmy-evilclone",
    "jimmy-gloomygus",
    "jimmy-gourd",
    "jimmy-happyclone",
    "jimmy-hopkins",
    "jimmy-neutron",
    "jimmy-romantic",
    "jimmy-valmer",
    "jimmybrandosg1",
    "jk-simmons",
    "jobjob",
    "joe",
    "joe-buck",
    "joe-chin",
    "joe-quimby",
    "joe-swanson",
    "joel",
    "joeseppi",
    "joey-dkoldies",
    "joey-drew",
    "joey-styles",
    "joey-the-tricky",
    "joey-wheeler",
    "joeytt",
    "john-alderton",
    "john-cena",
    "john-hancock",
    "john-hurt",
    "john-legend",
    "john-lennon",
    "john-madden",
    "john-marston",
    "john-oliver",
    "john-parker-hammond",
    "johnk",
    "johnny-baldi",
    "johnny-bravo",
    "johnny-cage-x",
    "johnny-cash",
    "johnny-gilbert",
    "johnny-gilbert-present",
    "johnny-silverhand",
    "johnny-test",
    "johnny-the-room",
    "jojo-siwa",
    "jojo-wwe",
    "joker-1",
    "joker-joaquin-phoenix",
    "joker-tas",
    "jolyne-cujoh",
    "jon-arbuckle-th",
    "jon-arbuckle-ww",
    "jonah-amph",
    "jonathan-joestar",
    "jonathan-kepler",
    "jones",
    "jonny-2x4",
    "jonny2x4",
    "jonnydiggit",
    "jontron",
    "jorgen-von-strangle",
    "joseph-oda",
    "joseph-seed",
    "josh-bcay",
    "jotaro-jp",
    "jotaro-kujo",
    "journalist",
    "jshaferori",
    "jsxi",
    "jthesaltyy",
    "judge-judy",
    "judgment-boy",
    "judgment-boy-1",
    "judi-dench",
    "judith-mossman",
    "judy-hopps",
    "judy-neutron",
    "juice-wrld-calm",
    "juice-wrld-rapping",
    "juice-wrld-singing",
    "juicewrld",
    "julia-child",
    "julie-ubriacco",
    "jun-kubota",
    "junior-90s",
    "junior-asparagus",
    "junior-klaptrap-singing",
    "jurgen",
    "juri-han",
    "justin-bieber",
    "k-vrc",
    "kaede-akamatsu",
    "kai-lan",
    "kang",
    "kani-maki",
    "kanye-west-rap",
    "kaptain-skurvy",
    "kaptain-skurvy-sing",
    "kara-danvers",
    "karen-20",
    "karen-frosty",
    "karen-the-computer",
    "karen_savage",
    "karin",
    "katia-anderson",
    "katie-mitchell",
    "katy-kat",
    "kazuma-kiryu",
    "kazuya",
    "kebabby",
    "kelsi",
    "ken-barrie",
    "ken-masters",
    "kendrick-lamar",
    "kent-brockman",
    "kermit-the-frog",
    "kermit-the-frog-sw",
    "kevin",
    "kevin-cucumber",
    "kevin-futarine",
    "kevin-harlan",
    "khalil-the-caterpillar",
    "khalil-the-caterpillar-(tim-hodge)",
    "kikimora",
    "killjoy",
    "kim-kitsuragi",
    "kim-mi2",
    "kim-possible",
    "kimi-finster",
    "kindly-keyin",
    "kinect-sports-announcer",
    "king-aldrich",
    "king-andrias",
    "king-andrias-young",
    "king-chicken",
    "king-clawthorne",
    "king-dedede",
    "king-harkinian",
    "king-julien-dj",
    "king-julien-kf",
    "king-julien-sbc",
    "king-k-rool",
    "king-koopa",
    "king-liang",
    "king-neptune",
    "king-of-town",
    "king-snugglemagne",
    "kira-dis",
    "kirby-tiff",
    "kirby-tuff",
    "kirk-van-houten",
    "kitty-ko",
    "klug",
    "knk-kate",
    "knk-kit",
    "knockout",
    "knuckles",
    "knuckles-dbm",
    "knuckles-movie",
    "knuckles-sa1",
    "knuckles-sd",
    "knuckles-tw",
    "knux-sonicsong182",
    "ko",
    "kodos",
    "kokichi-ouma",
    "kolin",
    "komaru-naegi",
    "konata",
    "kowalski",
    "kowalski-jeff-benett",
    "kratos",
    "krazy-kat",
    "kris-dreemurr-revtrosity",
    "krumm",
    "krusha",
    "krusty",
    "kung-lao",
    "kuroko-shirai",
    "kurt-angle",
    "kurzgesagt",
    "ky-kiske",
    "kyle-broflovski",
    "kyle-broflovski-90s",
    "kyo-mi2",
    "kyoko-kirigiri",
    "kyoya-ootori",
    "kyu-sugardust",
    "l-death-note",
    "lachy-gillespie",
    "lady-dimitrescu",
    "lady-gaga-sing",
    "lady-gaga-talk",
    "lady-olivia",
    "lady-tottington",
    "lamar-davis-calm",
    "lana-loud",
    "lancer-quizzique",
    "lanius",
    "lapis-lazuli",
    "lara-croft",
    "lara-croft-aod",
    "larry-bundy-jr",
    "larry-cmanflip",
    "larry-king",
    "larry-late90s",
    "larry-the-cucumber-(2000scurrent)",
    "larry-the-cucumber-(cmanflip)",
    "larry-the-cucumber-2000s",
    "larry-the-lobster",
    "larry-veggietales",
    "larry-wgwis",
    "larush_announcer",
    "launchpad-mcquack",
    "laverne",
    "layton",
    "le-frog",
    "leaf-masters-ex",
    "leafy",
    "leafyishere",
    "leah",
    "leapfrog-announcer-uk",
    "lebron-james-multiversus",
    "left4dead-louis",
    "lego-commercial-announcer",
    "legoshi",
    "leif-plantar",
    "lemon-demon",
    "leni-loud",
    "lenny-leonard",
    "lenny-reddead",
    "leo-kasper",
    "leo-luster",
    "leo-whitefang",
    "leonard-nimoy",
    "leonardo",
    "leopold-loggle",
    "lester-crest",
    "levin-jakes",
    "lexi-bunny",
    "lgl-luna",
    "lhugueny",
    "liam-gallagher",
    "liam-gallagher-sing",
    "liane-cartman",
    "libby",
    "liberty-pp",
    "licorice-cookie",
    "lien-neville",
    "lightning-mcqueen",
    "lightning-mcqueen-cool-videos",
    "lightning-mcqueen-kf",
    "lightning_bfb",
    "ligma-johnson",
    "lil-deville",
    "lil-jon",
    "lil-nas-x-calm",
    "lil-peep",
    "lil-tecca",
    "lil-tjay",
    "lil-tracy",
    "lil-uzi-vert",
    "lil-uzi-vert-talking",
    "lilac-cookie",
    "lilbibby",
    "lili-zanotto",
    "lilian-garcia",
    "lilith-clawthorne",
    "liluzivert",
    "liluzivert_normal",
    "lily-duolingo",
    "lily-tatmr",
    "limestone",
    "lincoln-loud",
    "lincoln-loud-bg",
    "lindsey-thorndyke",
    "linkara",
    "linus-van-pelt-70s",
    "linustt",
    "lionel-hutz",
    "lionel-starkweather",
    "lisa-loud",
    "lisa-simpson",
    "little-green-alien",
    "little-king-john",
    "little-man",
    "little-suzy",
    "liu-kang",
    "liz-ctrnf",
    "liz-pc",
    "lizzie",
    "lizzy-bruin",
    "lj",
    "lmm",
    "loba",
    "lockpickinglawyer",
    "logic",
    "lois-griffin",
    "lola-huniepop",
    "lola-loud",
    "lola-mbola",
    "lollipop",
    "looney-tunes-granny",
    "lord-farquaad",
    "lori-loud",
    "loser-bfdi",
    "lowtiergod",
    "luan-loud",
    "lucas-from-lucas-video-company",
    "lucas-simms",
    "lucy-loud",
    "lucy-van-pelt-snoopys-classiks-on-toys",
    "ludacris",
    "ludwig-von-drake",
    "luffy",
    "luigi",
    "luigi-64",
    "luigi-hotel-mario",
    "luigi-sex-ed",
    "luigi-smw",
    "luigi64",
    "luis-lopez",
    "luisa",
    "luke-lmg",
    "luke-triton",
    "lulu-culligan",
    "lumpus",
    "lumpy",
    "lumpy-space-princess",
    "luna",
    "luna-loud",
    "luther",
    "luz-noceda",
    "lynn-jr",
    "lynn-sr",
    "lysil-amphibia",
    "ma-mary-dg",
    "mabel-pines",
    "mac",
    "mac-chicken-run",
    "macaulay-culkin-1990",
    "madame-blueberry",
    "madame-blueberry-90s",
    "maddie-flour",
    "mafia-ahit",
    "maggie-pesky",
    "magic-mirror",
    "magica-de-spell",
    "maguire",
    "mahatma-gandhi",
    "mai-shiranui",
    "mai-valentine",
    "mailman",
    "major-monogram",
    "major-shake",
    "maki-angry",
    "maki-fine",
    "maki-sad",
    "makoto-naegi",
    "male",
    "male-citizen",
    "male-senior-asian",
    "maleficent",
    "maligula",
    "mama-bear",
    "mama-tattletail",
    "man-ray",
    "man-with-the-yellow-hat",
    "manchester-metrolink",
    "mandalorian",
    "mandark",
    "mandril-shrike",
    "mandy",
    "mangg-exploring-series",
    "mangle",
    "manny",
    "mao-mao",
    "map",
    "marcello",
    "marco-diaz",
    "marcus-reed",
    "marcy_w",
    "marge-simpson",
    "maria-robotnik",
    "marinette",
    "mario",
    "mario-64",
    "mario-bsi",
    "mario-fundamentals",
    "mario-fuwa",
    "mario-golf-announcer",
    "mario-is-missing",
    "mario-smw",
    "mario-sports-mix",
    "mario-sunshine",
    "mario-teaches-typing",
    "mario-teaches-typing-2",
    "mark-elliott",
    "mark-erickson",
    "mark-sabine",
    "mark-zuckerberg",
    "markiplier",
    "markiplier-modern",
    "marksman-tc2",
    "marlon-random",
    "marsha-mellow",
    "marsupilami",
    "martin-garrix",
    "martin-prince",
    "martin-tyler",
    "marty-mcfly",
    "marty-pl",
    "marty-the-zebra",
    "marvin-gaye",
    "marvin-the-martian",
    "marvin-the-martian-alaskey",
    "marzipan",
    "master-chief",
    "mater",
    "matpat",
    "matt-berry",
    "matthew-gator-brandon",
    "mattholomule",
    "mattrose",
    "mattvidpro",
    "maurice-jc",
    "max",
    "max-cartoon",
    "max-caulfield",
    "max-goof",
    "max-goof-troop",
    "max-hit-the-road",
    "max-payne",
    "may-ggst",
    "mayonnaise",
    "mayor",
    "mayor-hoarce-j-honeypot",
    "mayor-mcdaniels",
    "mayor-meanswell",
    "mc-ride",
    "mcbain",
    "mcbean",
    "mcd-narrator",
    "mcsquizzy",
    "mczee",
    "medic",
    "meg-griffin",
    "mega-man",
    "megaman-x-x7",
    "megasquadmo",
    "megatron",
    "megatron-bw-m",
    "megatron-m",
    "mei",
    "melanie",
    "melissa-dupre-linus",
    "melody-aaf",
    "meowth",
    "mephilesthedark",
    "mephone4",
    "merasmus",
    "mermaidman",
    "mermalair-computer",
    "mermista",
    "meta-knight",
    "metal-mario",
    "metal-sonid",
    "mf-doom",
    "mg-jeff-garlin",
    "mgsr-announcer",
    "mi-announcer",
    "micahbell",
    "michael-bell",
    "michael-buffer",
    "michael-buffer-nr",
    "michael-caine",
    "michael-cole",
    "michael-de-santa",
    "michael-felger",
    "michael-gough-shrek",
    "michael-rosen",
    "michael-rosen-meme",
    "michael-scott",
    "michaelrosen",
    "michaelstevens",
    "micheal-brandon",
    "michelle-ufdk2",
    "micii2",
    "mickey-mouse",
    "mickey-mouse-bi",
    "microsoft-anna",
    "microsoft-mike",
    "microsoft-sam",
    "midtown-madness-1-accouncer",
    "mignon",
    "mike-ehrmantraut",
    "mike-matei-as-inspector-gadget",
    "mike-pitts",
    "mike-wazowski",
    "mike-wazowski-ca",
    "mikey-allstars-braw",
    "mikey-ubriacco",
    "mikoto-misaka",
    "milhouse",
    "milla-vodello",
    "minerva-mink",
    "minnie-mouse",
    "mirabel-madrigal",
    "miss-earth",
    "miss-pauling",
    "miss-piggy",
    "mister-chief-ai",
    "mister-metokur",
    "misty",
    "misty-masters-ex",
    "mitch",
    "mittens",
    "miu-iruma",
    "mium-ethan",
    "mj",
    "mkagp2-announcer",
    "mlp-ahuizotl-m",
    "mlp-auntie-applesauce-m",
    "mlp-cheese-sandwich",
    "mlp-chrysalis-m",
    "mlp-clear-sky-m",
    "mlp-sky-stinger-m",
    "mlp-sludge-m",
    "mlp-smolder-m",
    "mlp-snap-shutter-m",
    "mlp-snips-m",
    "mlp-sonata-dusk-m",
    "mlp-spitfire-m",
    "mlp-spur-m",
    "mlp-star-swirl-m",
    "mlp-stellar-flare-m",
    "mlp-steven-magnet-m",
    "mlp-sugar-belle-m",
    "mlp-sunburst-m",
    "mlp-svengallop-m",
    "mlp-sweetie-drops-m",
    "mlp-terramar-m",
    "mlp-thorax-m",
    "mlp-timber-spruce-m",
    "mlp-tirek-m",
    "mlp-trouble-shoes-m",
    "mlp-vapor-trail-m",
    "mlp-vignette-valencia-m",
    "mlp-wallflower-blush-m",
    "mlp-wind-sprint-m",
    "mlp-yona-m",
    "mlp-zecora-m",
    "mlp-zephyr-breeze-m",
    "mlp-zesty-gourmand-m",
    "modern-vintage-gamer",
    "moe-szyslak",
    "moe-szyzlak",
    "mohammad",
    "mojo-jojo",
    "mokuba-kaiba",
    "molly-mcgee",
    "molt",
    "momoe-nagisa",
    "mondo",
    "moneybags",
    "monika",
    "monokuma",
    "monopoly-announcer",
    "monster",
    "monster-fnf",
    "montana-max",
    "moo-moo-the-magician",
    "moose-a-moose",
    "morbius",
    "mordecai",
    "morgan-freeman",
    "morrigan",
    "morris-martinez",
    "morshu",
    "morshu-t",
    "mort-deebradleybaker",
    "morty",
    "mountain-guardian-obyn",
    "mouse",
    "mouse-am",
    "movie-trailer-voice-uno",
    "moviemaker-sonic",
    "mr-barnacle",
    "mr-bean",
    "mr-big",
    "mr-bump",
    "mr-burns",
    "mr-burton",
    "mr-conductor",
    "mr-crocker",
    "mr-fantastic",
    "mr-frog",
    "mr-garrison",
    "mr-hankey",
    "mr-herriman",
    "mr-hippo",
    "mr-horse",
    "mr-krabs",
    "mr-krabs-bobjoles",
    "mr-krabs-joewhyte",
    "mr-lunt",
    "mr-mackey",
    "mr-meeseeks",
    "mr-monopoly",
    "mr-narrator-donkeyollie",
    "mr-narrator-wordworld",
    "mr-nezzer-2000s",
    "mr-peabody",
    "mr-peabody-tb",
    "mr-potato-head",
    "mr-rogers",
    "mr-sandman",
    "mr-sketch-marker",
    "mr-waternoose",
    "mr-weenie",
    "mr-wolf",
    "mr-x",
    "mrbeast",
    "mrs-doyle",
    "mrs-grizzle",
    "mrs-krabappel",
    "mrs-pomp",
    "mrs-potato-head",
    "mrs-puff",
    "mrs-turner",
    "mrturner",
    "mrwhosetheboss",
    "ms-chalice",
    "ms-cortana",
    "ms-crabtree",
    "ms-fowl",
    "ms-green",
    "ms-keane",
    "ms-question",
    "mshvsf-ann",
    "muddy-mudskipper",
    "mufasa",
    "mulan",
    "multiversus-announcer",
    "mumford",
    "muriel",
    "murray-cook",
    "murray-franklin",
    "muscle-man",
    "musse-egret",
    "mutahar",
    "mvcann-cosh",
    "my-paint-segacd",
    "mythra-xenoblade",
    "n-brio-ps1",
    "nagase",
    "nagito-komaeda",
    "nami",
    "narrator",
    "narrator-tsp",
    "naruto-uzumaki",
    "nas",
    "nat-king-cole",
    "nate-masters-ex",
    "nathaniel-bandy",
    "nb",
    "nb-9",
    "nba-youngboy-(agressive)",
    "ndn",
    "ned-flanders",
    "nedgerblanski",
    "negan",
    "neil-degrasse-tyson",
    "neil-tyson",
    "neilcic-speaking",
    "neilcicierega",
    "neku-sakuraba",
    "nelson-muntz",
    "newton",
    "nezuko-kamado",
    "nfs-announcer",
    "nice-julie",
    "nick-asb-announcer",
    "nick-chicken-run",
    "nick-hooper",
    "nick-l4d",
    "nick-offerman",
    "nick-valentine",
    "nick-wilde",
    "nicki",
    "nico-robin",
    "nicole-watterson",
    "nigel",
    "nigel-thornberry",
    "niko-bellic",
    "nikocado-avocado",
    "nilered",
    "nimbus",
    "nina",
    "nina-cortex",
    "nine",
    "ninon-beart",
    "nipsey-hussle",
    "nlechoppa",
    "noel-gallagher",
    "noel-gallagher-sing",
    "noggin-clontith",
    "noir-sam",
    "noisepuppet",
    "nora-rita-norita",
    "noriaki-kakyoin",
    "norm-macdonald",
    "norma",
    "nostalgia-critic",
    "nostalgic-ballz",
    "nostalgic-ballz-a",
    "not-important",
    "not-shane-kid",
    "ntexttospeech!",
    "numbuh-4",
    "o-leary",
    "obi-wan-kenobi",
    "oblina",
    "oblivion-guard",
    "obyn-greenfoot",
    "ocean-guardian-obyn",
    "odalia-blight",
    "odb",
    "odyssey",
    "officer-lou",
    "officer-pupp",
    "officerbarbrady",
    "oil-man",
    "old-jewish-man",
    "old-joseph-joestar",
    "old-man-walker",
    "oliepolie",
    "olive",
    "oliver-latias",
    "omega-jsj",
    "omni-man",
    "omochao",
    "omochao-lb",
    "one-day-mario-woke-up",
    "oogtar",
    "optimus-prime",
    "optimus-prime-m",
    "orbot",
    "orc-a",
    "orion",
    "orson-pmw3",
    "orthopox",
    "oscar-the-grouch",
    "osiris",
    "oswald",
    "otgw-greg",
    "otis",
    "otto-mann",
    "otto-mentallis",
    "outside-in-x",
    "outside-in-y",
    "outsiders-female",
    "pa-grape",
    "pa-grape-2000",
    "paarthurnax",
    "pac-man-em",
    "pac-man-ghostly-adventures",
    "pac-man-pmw3",
    "pacifica",
    "paco-bravo",
    "pail-s4",
    "painty",
    "pajama-sam",
    "paladin-danse",
    "palpatine",
    "palutena",
    "pam-beesly",
    "pan-dragon-ball",
    "panty-anarchy",
    "papa-bear",
    "papa-smurf",
    "papierwaite",
    "paprika-olivia",
    "paprika-stan",
    "papyrus",
    "papyrus-revtrosity",
    "parappa",
    "parlsona",
    "pasadena-possum",
    "pashmina",
    "pat-sajak",
    "patchwork-narrator",
    "patchy-the-pirate",
    "patrckstatic",
    "patrick",
    "patrick-bateman",
    "patrickstewart",
    "patton-oswalt",
    "patty-and-selma-bouvier",
    "patty-wagon",
    "paul-anka",
    "paul-mccartney",
    "paula-deen",
    "peach",
    "peach64",
    "peaches",
    "peacock",
    "pear",
    "pearl",
    "pearl-krabs",
    "pediaphon-male",
    "peggy-hill",
    "pen",
    "pen-bfdi",
    "penelope",
    "pepe-king-prawn",
    "pepe-le-pew",
    "peperami-animal",
    "peppa-narrator",
    "peppa-pig",
    "pepper-roni",
    "peppy-hare",
    "perceptor",
    "perceptor-m",
    "percy-tatmr",
    "peridot",
    "periwinkle-s4",
    "pete",
    "pete-kowalski",
    "pete-townshend",
    "peter-gabriel",
    "peter-griffin",
    "peter-knetter",
    "peter-pumpkin",
    "peter-thomas",
    "petunia-rhubarb",
    "pfa",
    "phantom-virus",
    "pharah",
    "phil-deville",
    "phil-matibag",
    "phil-swift",
    "phillip",
    "phillip-fry",
    "phineas",
    "phoenix",
    "phoenix-csgo",
    "phoenix-wright",
    "phone-guy",
    "pianta-judge-sms",
    "pibby",
    "pico",
    "pico-pvbdx",
    "pie-bfdi",
    "pierce-brosnan",
    "pig-barnyard",
    "pig-wordworld",
    "piglet-jf",
    "piglet-steve-schatzberg",
    "pikwik-axel",
    "pikwik-hazel",
    "pikwik-suki",
    "pim",
    "pin_bfb",
    "pinkie-pie",
    "pinky",
    "pinky-dinky-doo",
    "pinocchio-shrek",
    "pip",
    "pishifat",
    "pit",
    "pj-berri",
    "pj-dreams",
    "planetina",
    "plankton",
    "plankton-scream",
    "playboi-carti-(by-shadow)",
    "playboi-carti-bv",
    "playboicarti",
    "playtime",
    "pleakley",
    "plucky-duck",
    "poisonivy",
    "pokedex",
    "pokemon-blue",
    "pokemon-gardenia",
    "pokemon-narrator",
    "pokemon-skyla",
    "pokemon-stadium-announcer",
    "polly-plantar",
    "polo-g",
    "poof",
    "popcorn",
    "pops",
    "popular-mmos",
    "pork-bun-guy",
    "portal-announcer",
    "portal-turret",
    "postal-dude",
    "potatos",
    "pouya",
    "powdered-toast-man",
    "ppg-narrator",
    "pr-announcer",
    "preston-garvey",
    "priest-twnn",
    "prince-fleaswallow",
    "prince-of-persia",
    "princess-cadance",
    "princess-elise",
    "princess-mindy",
    "princess-presto",
    "princess-toadstool-smw",
    "principal-bump",
    "principal-lewis",
    "principal-mcvicker",
    "principal-of-the-thing",
    "prism-ai",
    "private",
    "private-jps",
    "prof-calamitous",
    "professor-actual-factual",
    "professor-farnsworth",
    "professor-frink",
    "professor-oak",
    "professor-utonium",
    "project-m-announcer",
    "prospector",
    "proto",
    "proto-man",
    "protogent",
    "pruane2",
    "ps2f",
    "psych2go",
    "psychicpebbles",
    "puff-yfm",
    "pulisic",
    "pumbaa",
    "pump",
    "punkleton",
    "purple-face",
    "pusha-t",
    "puss-in-boots",
    "putt-putt",
    "pyra",
    "pyro-mod",
    "pyrocynical",
    "q-tip",
    "quagmire",
    "quandale_dingle",
    "qubo",
    "queen-delightful",
    "quincy-btd6",
    "rabbit",
    "rad",
    "rafiki",
    "raiden-cvs2",
    "rainbow-dash",
    "rainbow-mika",
    "raine-whispers",
    "raj",
    "ralph-bakshi",
    "ralph-bakshi-apc",
    "ralph-wiggum",
    "randall-boggs",
    "randy-hubner",
    "randy-jenkins",
    "randy-marsh",
    "randy-marsh-90s",
    "randy-orton",
    "ranger-smith",
    "raphael-injustice2",
    "rare-wubbox",
    "rarity",
    "rarity-(singing)",
    "ratchet",
    "raven",
    "ray_rbt",
    "raymondbm",
    "razputin-aquato",
    "razu",
    "rc-bray",
    "rc-wells",
    "reaper",
    "reapergabereyes",
    "rebecca-forza",
    "rec-room-coach",
    "red",
    "red-guy",
    "red-m",
    "red-queen",
    "red-ssbu",
    "redmond",
    "redvelvety",
    "reeceduh",
    "reggie-fils-aime",
    "reggie-rocket-100",
    "reggie-rocket-movin-62",
    "regis-philbin",
    "relikk",
    "remy-the-rat",
    "ren-hoek",
    "ren-hoek-2022",
    "ren-hoek-billy-west",
    "ren-rwby",
    "rene-dupree",
    "resort-owner",
    "rev-lovejoy",
    "reverend-hedges",
    "revolver-ocelot",
    "rex",
    "rex-earl-boen",
    "rey-mysterio",
    "riceman_insight_upper",
    "rich-fields",
    "rich-texan",
    "richard-ayoade",
    "richard-feynman",
    "richard-gryphon",
    "richard-hammond",
    "richard-nixon",
    "richard-unikitty",
    "richter-overtime",
    "rick-astley",
    "rick-sanchez",
    "rico",
    "riddick1",
    "rigby",
    "right-hand-man-reborn",
    "riley-daring",
    "ringo",
    "ringo-starr",
    "ringo-starr-singing",
    "ringside-reporter",
    "ripto",
    "rise-kujikawa",
    "risky-boots",
    "rita",
    "rita-loud",
    "rita-malone",
    "rivers-cuomo",
    "riverscuomo90s",
    "rizzo-the-rat",
    "rj",
    "rob-64",
    "robbie-rotten",
    "robertstack",
    "robin-tas",
    "rochelle",
    "rocket-raccoon-tiktok",
    "rocko-wallaby",
    "rocko-wallaby-aott",
    "rocky-cocoa",
    "rocky-rhodes",
    "rod-flanders",
    "roddy-st-james",
    "rodimus",
    "rodney-copperbottom",
    "rodney-dangerfield",
    "roger-daltrey",
    "rogue-kashya",
    "rolf",
    "roll-mega-man",
    "ron",
    "ron-stuart",
    "ronald-reagan",
    "ronnie-anne-santiago",
    "roostre",
    "roronoa-zoro",
    "rorry-poptv",
    "rory-ll",
    "rosa-masters-ex",
    "rosalina",
    "rose-sfv",
    "rosita",
    "ross-geller",
    "rossmann",
    "rouge-the-bat-kd",
    "rouge-the-bat-ks",
    "rouge-the-bat-sa2",
    "rouxls-kaard",
    "rowlf",
    "roxanne-wolf",
    "roxie-pokemon",
    "royce-bracket",
    "royce-da-5-9",
    "roz",
    "ruannouncer",
    "ruby",
    "rudolph",
    "ruff-ruffman",
    "rulue",
    "rumpelstiltskin",
    "runt",
    "runt-of-the-litter",
    "ryan-gosling",
    "ryder-wilson",
    "ryu",
    "s-a-m",
    "s3galvy",
    "saccharin",
    "saddam-hussen",
    "sagat",
    "sailor-jupiter",
    "sailor-mars-kg",
    "sakura",
    "sakura-avalon",
    "sakura-kinomoto",
    "sally-acorn",
    "sally-brown-70s",
    "sam",
    "sam-boole",
    "sam-cartoon",
    "sam-hit-the-road",
    "sam-i-am",
    "sam-lachow",
    "sam-lake",
    "sam-moran",
    "sam-the-eagle",
    "sam1",
    "samanya-rfg",
    "samus",
    "sandy-cheeks",
    "sanji",
    "sans",
    "sans-revtrosity",
    "santa-sp",
    "sarah",
    "sarah-breaker",
    "sarah_martin",
    "sarge",
    "sarvente",
    "sasha-nein",
    "sasha-waybright",
    "sasuke-uchiha",
    "satan-sp",
    "saten-ruiko",
    "satoru-iwata",
    "saul-goodman",
    "sayori-ddlc",
    "sayu",
    "scallion-#1",
    "scallion-1",
    "scar",
    "scarecrow",
    "scarlett-johansson",
    "scary",
    "schmitty",
    "scientist-gwendolin",
    "scooby-doo",
    "scootaloo",
    "scooter-carrot",
    "scott-oelkers",
    "scott-the-dick",
    "scott-the-woz",
    "scott-woz-2021",
    "scout",
    "scout-mvm",
    "scoutmaster-lumpus",
    "scp-049",
    "scp035",
    "scrapper",
    "scrappy-doo",
    "scratch",
    "scratch-doctor",
    "scratch-tgamm",
    "scratchy",
    "scrooge-mcduck",
    "scrubs",
    "sea-captain",
    "seahawk",
    "sean-murray",
    "sean-rdr2",
    "season-two-donkey-kong",
    "sebastian-castellanos",
    "security-guard",
    "selene-masters-ex",
    "senator-armstrong",
    "senor-cardgage",
    "sentai-churchill",
    "sergeant-hartman",
    "seto-kaiba",
    "seven",
    "seymour-skinner",
    "sfiv-ann",
    "sfv-ann",
    "sgt-byrd",
    "sgt-roebuck",
    "shadow",
    "shadow-david-humphrey",
    "shadow-jg",
    "shadow-kirk-thornton",
    "shadow-weaver",
    "shaggy",
    "shaggy-casey-kasem",
    "shaggy-rogers-lillard",
    "shahra",
    "shake",
    "shane",
    "shane-tru",
    "shannon",
    "shantae",
    "shao-kahn",
    "sharon-marsh",
    "shaw",
    "shawn-michaels",
    "shawn_boy_meets_world",
    "sheckley-hl2",
    "sheen-estevez",
    "sheep-wordworld",
    "sheep-wordworld-laterseasons",
    "shego",
    "sheila-broflovski",
    "sheila-qc",
    "sheldon-cooper",
    "shelly-marsh",
    "shenzi",
    "sheriff",
    "sheriff-woody",
    "sherlock-holmes",
    "sherri-terri",
    "shgurr",
    "shimmer",
    "shinatama",
    "shine",
    "shining-armor",
    "shock-rock",
    "shockwave",
    "shockwave-m",
    "shohreh-aghdashloo",
    "shoto-todoroki",
    "shounic",
    "shovel-s4",
    "shrek",
    "shrek-chrisfarley",
    "shrek-michael-gough",
    "shrimp",
    "shroomy",
    "shuichisaihara",
    "shulk",
    "sid-the-sloth",
    "side-table-drawer",
    "sideshow-mel",
    "silver",
    "silver-bp",
    "silver-qf",
    "simon-80s",
    "simon-cowell",
    "simon-cowell-tn",
    "simon-pryce",
    "simpleflips",
    "sir-david-attenborough",
    "sir-martyn",
    "sir-topham-hatt",
    "siri-female-british",
    "siri-male-british",
    "sirmixalot",
    "sister-bear",
    "skeet",
    "skid3422",
    "skimask",
    "skipper",
    "skipper-vg",
    "skippy-squirrel",
    "skullgirls-announcer",
    "skuzz",
    "sky",
    "skybolt",
    "skybolt-m",
    "skyfire",
    "skyrim-guard",
    "slappy-squirrel",
    "slim-shady",
    "slinkman",
    "slinky-dog",
    "slippery-s4",
    "slippy-toad",
    "slj",
    "sly-cooper",
    "small",
    "smash-mouth",
    "smash64",
    "smashmelee",
    "smashultimate",
    "smirk",
    "smitty-werben-jaegermanjensen",
    "smk",
    "smm-edit",
    "smurfette",
    "snagglepuss",
    "snails",
    "snake-jailbird",
    "sniper",
    "sniper-female",
    "snm-narrator",
    "snoop-dogg",
    "snoop-dogg-cod",
    "snow-white",
    "socko",
    "softonic",
    "soldier",
    "soldier-76",
    "soldier-mvm",
    "soldine-ff2",
    "solidsnake",
    "solomon-muto",
    "some-guy-yells-at-some-cats",
    "sonic-1989gamemaster",
    "sonic-adventure-dx",
    "sonic-jaleel",
    "sonic-jason-griffith",
    "sonic-movie",
    "sonic-rcs",
    "sonic-ryan-drummond",
    "sonic-sfh",
    "sonic-vocodes",
    "sonic-x",
    "sonics-schoolhouse",
    "sonny-cocoa-puffs",
    "sonya-blade",
    "sora",
    "sora-kh1",
    "soulcalibur-announcer",
    "space-ghost",
    "sparky-fop",
    "spawn-kmr",
    "speak-and-spell",
    "special-johnny",
    "specs",
    "speedy-gonzales",
    "spider-man",
    "spider-man-mvc",
    "spike",
    "spike-flushed-away",
    "spike-nelson",
    "sponge-bob",
    "spongebob",
    "spongebob-gd",
    "spongebob-squarepants",
    "spongebob-uncle-al",
    "spotify-ad-vo",
    "sprig-plantar",
    "springtrap-david-near",
    "spy",
    "spy-fox",
    "spyro-1-ca",
    "spyro-tk",
    "squeaky-voice-teen",
    "squidward",
    "squilliam-fancyson",
    "squire-grizzly",
    "ssbb-announcer",
    "ssblxp-announcer",
    "sssniperwolf",
    "stacy-hirano",
    "stan-marsh",
    "stan-marsh-90s",
    "stan-marsh-pilot",
    "star-butterfly",
    "starfire",
    "starlight-glimmer",
    "starscream",
    "starscream-m",
    "stella-dis",
    "stella-zhau",
    "stephanie-lazytown",
    "stephanie-miller",
    "stephen-fry",
    "stephenasmith",
    "steve-ballmer",
    "steve-burns",
    "steve-element-animation",
    "steve-irwin",
    "steve-jobs",
    "steve1989",
    "steveharvey",
    "steven",
    "stevendd",
    "stewie-griffin",
    "stewie-griffin-current",
    "sticks-the-badger",
    "stimpy",
    "stingy",
    "stinkoman",
    "stinky-whizzleteats",
    "stitch-tiktok",
    "stone-cold",
    "stone-stomper",
    "storm-the-albatross",
    "striker-jones",
    "strong",
    "strong-bad",
    "strong-bad-2001",
    "strong-mad",
    "strong-sad",
    "strong-sad-2001",
    "stryder7x",
    "stu-pickles",
    "sub-zero",
    "suctioncupman",
    "sugar-belle",
    "suketoudara",
    "sully",
    "sully-bc",
    "sundae",
    "sunsetshimmer",
    "super-ghostbusters",
    "super-macho-man",
    "super-why",
    "super-why-s1",
    "superball",
    "superint-ai",
    "supermarioglitchy4",
    "susanwabbajack",
    "susie-carmichael",
    "suzanne-vega-sing",
    "sven-hoek",
    "swankybox",
    "sway3po",
    "sweetie-belle",
    "sweeto",
    "swiper-the-fox",
    "switch-sports-announcer",
    "switchonline",
    "sykes",
    "sylvester-joe-alaskey",
    "syndrome",
    "t-800",
    "tabbes",
    "tabi",
    "taco",
    "tag",
    "tails",
    "tails-aosth",
    "tails-colleen",
    "tails-heroes",
    "tails-kate-higgins",
    "tails-sa",
    "talking-ben",
    "talking-tom",
    "talkinghank",
    "talkingpierre",
    "tankman",
    "tanya-keys",
    "taran",
    "tattletail",
    "tawna",
    "taz",
    "tazz",
    "tazz-taco",
    "tea-gardner",
    "teacher-bob",
    "teamspeak-female",
    "tech-e-coyote",
    "tech-n9ne",
    "technus",
    "teddy-roosevelt",
    "tee-puyo",
    "teletraan1",
    "telly-monster-1983",
    "ten",
    "terkel-uk",
    "terra-snapdragon",
    "terrance",
    "tfp-ratchet",
    "tfp-ratchet-m",
    "thanos",
    "the-ancestor",
    "the-boogeyman",
    "the-brain",
    "the-butcher",
    "the-collector-toh",
    "the-dead-flag-blues",
    "the-drifter",
    "the-french-narrator",
    "the-french-narrator-rotfd",
    "the-game",
    "the-gamer-from-mars",
    "the-geek",
    "the-joker",
    "the-narrator",
    "the-rock",
    "the-rock-tn",
    "the-toad",
    "the-toy-maker",
    "the-undertaker",
    "the-weeknd",
    "thelma-harper",
    "theneedledrop",
    "theodd1sout",
    "theywillkillyou",
    "thomas-aeg",
    "thomas-bwba",
    "thomas-hotr",
    "thomas-narrator",
    "thomas-tatmr",
    "thomas-tatmrdc",
    "thurl-ravenscroft",
    "tickety-tock-s5",
    "tigger",
    "tigger-pw",
    "tikal",
    "tilly-green",
    "tim",
    "time-man",
    "timekeeper",
    "timmy-turner",
    "timmy-turner-oyc",
    "timmyturnersgranddad",
    "timon",
    "tinytina",
    "tito-dick-joey",
    "tito-dick-rex",
    "toad",
    "toad-bsi",
    "tobey-mccallister-iii",
    "tobias-wilson",
    "toby-tatmr",
    "todd-daring",
    "todd-flanders",
    "todd-hayseed",
    "todd-project-farm",
    "tohru-adachi",
    "token-black",
    "tom-hiddleston",
    "tom-tucker",
    "tom-wachowski",
    "toma-kamajo",
    "tommy-pickles",
    "tommy-vercetti",
    "toni-cipriani",
    "tony-chimel",
    "tony-hawk",
    "tony-the-tiger",
    "too-tall",
    "top-cat",
    "top-pops",
    "tord-larsson",
    "tornadotourman_insight_upper",
    "toucan-sam",
    "toxin_tractor",
    "toy-bonnie",
    "toy-freddy",
    "toychica",
    "tp_announcer",
    "tracer",
    "tracks",
    "transit-system-bm",
    "transit-system-no-fx",
    "trashdiscussman_insight_upper",
    "travis-scott-(rapping)",
    "travis-scott-rapping",
    "trebek",
    "tree_bfdi",
    "trent-reznor",
    "trev-phil",
    "trevor-philips",
    "trinket",
    "triple-h",
    "trippie-redd",
    "tristan-taylor",
    "trixie",
    "troy-mcclure",
    "troy99",
    "tsehay-hawkins",
    "ttc-subway",
    "tts-reference&voice=angie-steadman",
    "tucker-carlson",
    "tutorial-unit",
    "tweek",
    "tweety-joe-alaskey",
    "twilight-sparkle",
    "two",
    "twou-snow",
    "tyler-dinky-doo",
    "tyler-perry",
    "tyler-the-creator",
    "tyrannosaurus-alan",
    "uberduck-tutorial-guy",
    "ugly-sonic",
    "uiharu-kazari",
    "uka-uka",
    "ulala",
    "ultorpa",
    "ultron",
    "uni",
    "unikitty",
    "unikitty-show",
    "unlucky-tug",
    "usopp",
    "uter-zorker",
    "uzi",
    "vaas",
    "vader",
    "van-driessen",
    "van-ninjala",
    "vana-glama",
    "vanellope",
    "vanessa-doofenshmirtz",
    "vanessa-sb",
    "vanilla-ice",
    "vanilla-the-rabbit",
    "vanna-white",
    "vasha-rfg",
    "vc-murice-chavez",
    "vector-the-crocodile",
    "vector-the-crocodile-jcc",
    "velma-bjward",
    "velma-linda-c",
    "verbal-ase",
    "verne-oth",
    "vf-wiseguy",
    "vicky",
    "victer-quartermaine",
    "victor-quartermaine-ralph-fiennes",
    "victor-quartermine",
    "video-game-agent",
    "video-games-and-more",
    "vince-mcmahon",
    "vince-offer",
    "vincent-price",
    "vinny-fg",
    "violet-parr",
    "viridi",
    "vision",
    "vista-narrator-male",
    "vlad_plasmius",
    "vlad_t",
    "vortigaunt",
    "vortigaunt-ep2",
    "vox-announcer",
    "vox-jn",
    "wakko-warner",
    "walden",
    "wallace",
    "walter-white",
    "waluigi",
    "waluigi-gcn",
    "wamo",
    "wanda",
    "wario",
    "wario-64",
    "wario-e3",
    "warioware",
    "warp-darkmatter",
    "watchmojo",
    "water-whirl",
    "wave-the-swallow",
    "wave-the-swallow-bh",
    "waylon-smithers",
    "wayneradiotv",
    "weed-goblin",
    "weegee",
    "weevil-underwood",
    "wei-shen",
    "weird-al",
    "weizenheimer",
    "wendover",
    "wendy-testaburger-as",
    "wendy-testaburger-mkb",
    "wendys-target-employee",
    "werehog",
    "wessidelive",
    "wheatley",
    "wheeljack",
    "wheezy",
    "whitaker",
    "whitey",
    "whizzer",
    "widder-jones",
    "widget",
    "widowmaker",
    "wiggles-dorothy",
    "wiggles-greg",
    "wiggles-henry",
    "wiggles-wags",
    "wii-fit",
    "wii-fit-trainer-female",
    "wii-sports-announcer",
    "wii-sports-club",
    "wilbert-awdry",
    "wilbur-hog",
    "wildcard-mcvee",
    "wilde-angry",
    "wildtangent-fate-narrator",
    "wilford-brimley",
    "will-smith-talking",
    "will-tts",
    "william-afton",
    "willie-rushton",
    "willow-park",
    "wind-warrior",
    "winnie-the-pooh",
    "winnie-the-pooh-narrator",
    "winniethepooh",
    "wirt",
    "wishbone",
    "witch",
    "wiz-khalifa",
    "wolf-o-donnell",
    "wolfpack-quincy",
    "wolfychu",
    "wonder-red",
    "woodman",
    "woody-jh",
    "woody-sml",
    "woody-woodpecker",
    "woofster",
    "wordgirl",
    "wreck-it-ralph",
    "wt",
    "wubbzy",
    "xanyleaves_british",
    "xavier-renegade-angel",
    "xbot-4000",
    "xj-9",
    "xp-narrator",
    "xpro-gamin",
    "xxxtentacion-aggressive",
    "xxxtentacion-calm",
    "xxxtentacion-singing",
    "xxxtentacionscream",
    "yahtzee-croshaw",
    "yaki-kadafi",
    "yakko-warner",
    "yami-yugi",
    "yanderechan",
    "yellow-face",
    "yellow-m",
    "yennefer",
    "yes-man",
    "yo-mama",
    "yoda",
    "yogi-bear",
    "yool",
    "yosemite-sam-ml",
    "yoshi-smw",
    "yoshikage-kira",
    "you-me-gas-station",
    "young-simba",
    "youtube-copyright",
    "yoyo",
    "yugi-muto",
    "yuka",
    "yunggibberish",
    "yuri-ddlc",
    "yzma",
    "zac",
    "zagreus",
    "zari-duolingo",
    "zazu",
    "zecora-zebra",
    "zenyatta",
    "zephyr",
    "zephyr-breeze",
    "zero_x7",
    "zeta",
    "zillakami",
    "zim",
    "zoe-spyro",
    "zoey-hp",
    "zoey-l4d",
    "zoidberg",
    "zoil",
    "zom-zom",
    "zone-tan",
    "zoog-disney",
    "zorak",
    "zro",
    "zuzu",
    "zuzu-linda",
    "zwf",
    "zwf-rapping"
]


import gym
from gym import wrappers

import numpy as np
import torch

import sorenTestAtariAgents as agents

class AtariGame:
	def __init__(self,):

		# Opretter mappe til mulighed for gemning af video mm.
		outputDir = '/tmp/test-results'

		# Opretter env til spillet, hvor frameSkip implementeres vælges, så kun hver fjerde frame behandles
		self.env = wrappers.Monitor(gym.make('Breakout-v0'), directory = outputDir,  force=True)

	def initSingleGame(self, preProcess = True):
		#Starter et enkelt spil
		self.frame = self.env.reset()
		self.preProcess = preProcess

		if self.preProcess:
			self.frame = self.preProcessFrame(self.frame)
		self.reward = 0

	def move(self, choice, render = False):
		#foretager én handling i et enkelt spil

		self.frame, self.reward, done, _ = self.env.step(choice)

		if self.preProcess:
			self.frame = self.preProcessFrame(self.frame)

		#Afslutter spillet, hvis det er ovre
		if done: return 0

		#Viser spillet på skærmen
		if render: self.env.render()

		return 1

	def preProcessFrame(self, frame):
		#Beskærer rammen til spilleområdet og laver alle farver, der ikke er baggrund til 1
		frame = frame[32:192, 8:152]

		#Nedskalerer hele rammen med 2
		frame = frame[::2,::2,0]
		frame[frame != 0] = 1

		#Gør rammen til et 1D array
		cleanFrame = torch.Tensor(frame.ravel())
		return cleanFrame

	def playEpisodes(self, agent = agents.randomChoice, episodeCount = 10, render = True):
		rewards = np.empty(episodeCount)

		for i in range(episodeCount):

			#Resetter spillet og danner den første ramme
			frame = self.env.reset()
			reward = 0

			#Spiller et enkelt spil spil
			while True:
				#Finder agentens valg
				actionChoice = agent(frame, reward)

				#Udfører handlingen baseret på agentens beslutning
				frame, reward, done, _ = self.env.step(actionChoice)
				rewards[i] += reward
				#Afslutter spillet, hvis det er ovre
				if done:
					print(i, rewards[i])
					break

				#Viser spillet på skærmen
				if render: self.env.render()

		return rewards

game = AtariGame()
game.initSingleGame()
print(game.frame.shape)

# from matplotlib import pyplot as plt

# frame = self.env.reset()
# for i in range(2):
# 	frame, reward, done, _ = self.env.step(agents.randomChoice(frame, 0))

# plt.imshow(self.preProcessFrame(frame))
# plt.show()


import matplotlib.pyplot as plt

def sparse_graph(sp, cmap=plt.cm.binary):
    """Make a graph given some sparse matrix.
    Parameters
    ----------
    * sp: A sparse matrix, which is able to be converted to an array.
    * cmap: matplotlib colormap.

    Returns
    -------
    * (fig, ax) tuple.
    """
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.matshow(sp.toarray(), cmap=cmap)
    return fig, ax


import lxml.etree
import json

def parse_xml_as_json(root : 'lxml.etree.Element'):
    json = dict()
    for child in root.iterchildren():
        new_value = None
        if child.text and child.text.strip() != '':
            new_value = child.text
        else:
            new_value = parse_xml_as_json(child)
            if len(new_value) == 0:
                new_value = ''
        if child.tag not in json:
            json[child.tag] = new_value
        else:
            if type(json[child.tag]) != list:
                json[child.tag] = [json[child.tag]]
            json[child.tag].append(new_value)
    return json

def prep_response_text(response_text):
    '''
    Prepares the XML response string for lxml
    '''
    # remove any encoding declaration
    encoding_decl_prefix = '<?xml version="1.0" encoding="UTF-8"?>\n'
    if response_text.startswith(encoding_decl_prefix):
        response_text = response_text[len(encoding_decl_prefix):]
    # remove the xmlns declaration. Since lxml doesn't provide a way to get the tag name sans namespace prefix, it just gets in our way
    start = response_text.find(' xmlns="')
    if start >= 0:
        end = response_text.find('"', start+len(' xmlns="'))
        response_text = response_text[:start] + response_text[end+1:]
    return response_text

class AWSResult:

    _tree = None
    _json_full = None

    def __init__(self, response_text : str):
        self.response_text = prep_response_text(response_text)

    def json_full(self):
        if self._json_full is None:
            self._json_full = parse_xml_as_json(self.tree())
        return self._json_full

    def tree(self):
        '''
        returns response as an lxml.etree.Element
        '''
        if self._tree is None:
            self._tree = lxml.etree.fromstring(self.response_text)
        return self._tree

    def xpath(self, path):
        return self.tree().xpath(path)

    def xml(self):
        return self.response_text

    def __getitem__(self, key):
        return self.json()[key]


from flask import Flask, Response, render_template, jsonify

# For flask implementation
from flask import Flask, render_template, request, redirect, url_for, flash
from werkzeug.exceptions import HTTPException, InternalServerError
from bson import ObjectId  # For ObjectId to work
from flask_pymongo import PyMongo
import json
import os
import copy

from models import User, Activity, File, FileMapper
app = Flask(__name__)

app.config['MONGO_URI'] = 'mongodb://127.0.0.1:27017/fitwell'
mongo = PyMongo(app)

user_db_handler = User(mongo.db.user)
activity_db_handler = Activity(mongo.db.activity)
file_db_handler = File(mongo.db.activity)
file_mapper_db_handler = FileMapper(mongo.db.file_mapper)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/log")
def log():
    return render_template("log.html")

@app.route("/register", methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template("register.html")
    elif request.method == 'POST':
        data = request.json
        print(f'A user is being registerd: {data}')
        db_res = user_db_handler.add_single(data)
        return json.dumps({'success': True, 'data': db_res})

"""
since it is requested that we don't store the user in the backend,
so for this we just hard code the user as admin@fitwell.com
"""

@app.route("/dashboard")
def dashboard():
    data = activity_db_handler.get_multi('admin@fitwell.com')
    return render_template("dashboard.html", data=data)

@ app.route("/upload", methods=['GET', 'POST'])
def upload():
    if request.method == 'GET':
        return render_template("upload.html")
    elif request.method == 'POST':
        if 'file' not in request.files:
            return Response('Missing files', status=406)

        file = request.files['file']
        db_res = file_db_handler.upload(file)
        file_mapper_db_handler.create_and_save_map(db_res)

        return json.dumps({'success': True, })

@ app.route('/login', methods=['POST'])
def login():
    if request.method == "POST":
        data = request.json
        db_res = user_db_handler.get_single(data['email'], data['password'])

        if db_res == None:
            return Response('Unauthenticated', status=401)

        return json.dumps({'success': True, 'data': db_res})

@ app.route('/activity', methods=['POST'])
def activity():
    if request.method == "POST":
        data = request.json
        db_res = activity_db_handler.add_single(data)
        return json.dumps({'success': True, 'data': db_res})

if __name__ == "__main__":
    app.run(debug=True)


# Keep Multiplying Found Values by Two

class Solution:
    def findFinalValue(self, nums, original):
        while True:
            found = False
            for n in nums:
                if n == original:
                    found = True
                    original *= 2
                    break

            if not found:
                return original