text: # All needed as part of functions
  from math import *
  from decimal import *
  from random import shuffle
  from os import path
  from inspect import signature, getdoc
  from re import compile, split
  import csv
  import ScrapingFunctions as SF
  
  from hmc_urllib import getHTML
  from RankingSettings import *       # Imports the dictionary of tags with names as well as global settings
  from Glicko2 import *
  
  """
  Copyright (c) 2015 Abraham Schulte
  
  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:
  
  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
  """
  
  Titles = ['Melee', 'PM', 'Sm4sh', 'SSB', 'Brawl']
  Sortings = ['Bottom', 'Low', 'Middle']
  SSBPersonDict = {}
  MeleePersonDict = {}
  PMPersonDict = {}
  BrawlPersonDict = {}
  Sm4shPersonDict = {}
  
  def TitleDict(Title):
      """Gives the dictionary associated with Title.
  Title: a string ('Melee', 'PM', 'Sm4sh', 'SSB', or 'Brawl')."""
      if Title == 'SSB':
          Dict = SSBPersonDict
      if Title == 'Melee':
          Dict = MeleePersonDict
      if Title == 'PM':
          Dict = PMPersonDict
      if Title == 'Brawl':
          Dict = BrawlPersonDict
      if Title == 'Sm4sh':
          Dict = Sm4shPersonDict
      return Dict
  
  def AddPerson(Person, Dict, Rating = DefaultRating, RD = DefaultRD, Vol = DefaultVol):
      """Adds person to Dict with the given Glicko2 rankings.
  Person: a string.
  Dict: one of the Title dictionaries (recommended to use the TitleDict function).
  Rating: a float; the initial rating of Person.
  RD: a float; the initial rating deviation of Person.
  Vol: a float; the initial volitility of Person."""
      if Person not in Dict:
          Dict[Person] = [Rating, RD, Vol, 0, []]
      if Person not in TagDict:
          TagDict[Person] = ''
  
  def AppendFile(Person, Dict, File):
      """Adds File to the list of files associated with Person in Dict.
  Person: a string.
  Dict: one of the Title dictionaries (recommended to use the TitleDict function).
  File: a string; the file to be associated with Person in Dict."""
      if File not in Dict[Person][4]:
          Dict[Person][4] += [File]
  
  def Replacements(s):
      """Fixes a string to change all worded numbers to their number equivalents (one --> 1, etc.),
  as well as adding spaces to last initials (JohnD. --> John D.) and fixing all the typoes and changed tags
  from ReplacementList, which is located in RankingSettings.
  s: a string."""
      for NumFix in NumFixes:
          if s == NumFix[1]:
              s = s.replace(NumFix[1], NumFix[0])
      for Upper in uppercases:
          if s[::-1][0:2] == '.' + Upper:
              if s[::-1][0:3] != '.' + Upper + ' ':
                  s = s[::-1].replace('.' + Upper, '.' + Upper + ' ', 1)[::-1]
      for Replacement in ReplacementList:
          if s == Replacement[0]:
              s = s.replace(Replacement[0], Replacement[1])
      for Tag in TagDict:
          if s == TagDict[Tag]:
              s = Tag
      return s
  
  def Addtxt(TxtFile):
      if TxtFile[-4:] != '.txt':
          TxtFile = TxtFile + '.txt'
      return TxtFile
  
  def GetDataTxt(TxtFile, Dict):
      """Opens TxtFile, adds all players to Dict along with default values, 
  adds TxtFile a player appears in to their Dict entry, and returns a list with the results 
  of each match in TxtFile. Each match should formatted as P1 P1wins P2 P2wins,
  with each match separated by a carriage return (a new line).
  TxtFiles: a string; the .txt file to be read.
  Dict: one of the Title dictionaries (recommended to use the TitleDict function)."""
      TxtFile = Addtxt(TxtFile)
      if 'ResultsFolder' in globals():
          TxtFile = ResultsFolder + TxtFile
      MatchResults = []
      with open(TxtFile, encoding="ISO-8859-1") as File:
          for NumFix in NumFixes:
              File = File.replace(NumFix[0], NumFix[1])
          FileResults = File.readlines()
      FileResults = [split(",", s)[:] for s in FileResults]
      for i in range(len(FileResults)):
          FileResults[i][0] = Replacements(FileResults[i][0])
          FileResults[i][1] = int(FileResults[i][1])
          FileResults[i][2] = Replacements(FileResults[i][2])
          FileResults[i][3] = int(FileResults[i][3])
      for CurrentMatch in FileResults:
          AddPerson(CurrentMatch[0], Dict)
          AppendFile(CurrentMatch[0], Dict, path.basename(TxtFile)[0:-4])
          AddPerson(CurrentMatch[2], Dict)
          AppendFile(CurrentMatch[2], Dict, path.basename(TxtFile)[0:-4])
      MatchResults.append(FileResults)
      return FileResults
  
  letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
  letters = [letter for letter in letters]
  uppercases = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  uppercases = [letter for letter in uppercases]
  numbers = [str(i) for i in range(100)]
  
  def WriteTxtFromChallonge(Challonge, TxtFile):
      """Writes the results from a Challonge URL to TxtFile.
  Challonge: a string; the URL for a Challonge.
  TxtFile: a string; the name of the file to be written.
  Example: WriteTxtFromChallonge('http://apex2015melee.challonge.com/singles', 'Apex 2015')"""
      TxtFile = Addtxt(TxtFile)
      TheString = getHTML(Challonge)[0].replace('Mark as In Progress\n\n\nUnmark as In Progress\n\n\n\n', '') \
          .replace('\n\n\n\n\n\nEdit\n\n\nReopen', '').split('\n\n\n\nMatch Details\n\n\n\n\n\n\n')[1:]
  
      parsed_matches = ""
  
      for item in TheString:
          item = item.splitlines()
          if item[2] == "" or item[7] == "":
              continue
          try:
              if int(item[24]) < 0:
                  continue
          except:
              pass
          try:
              if int(item[27]) < 0:
                  continue
          except:
              pass
  
          line = item[2] + "," + item[24] + "," + item[7] + "," + item[27]
          line = SF.strip_match(line)
          if line is not None and SF.parse_match(line) != "":
              parsed_matches += SF.parse_match(line) + "\n"
  
      with open(TxtFile, 'a') as file:
          file.write(parsed_matches)
  
  def GetGameData(TxtFile, Dict):
      """Opens TxtFile, does all the additions to Dict from GetData and returns a dictionary whose keys are the players
  and whose key values are the individual games from each match, with the opponent's rating and RD at the time of the match,
  the result, and the tag of the opponent, just in case that is ever needed in the future. Note that each game is
  "double counted" (as it should be for Glicko2), with a game being recorded once as a victory for the winner
  and once as a loss for the loser.
  TxtFile: a string; the file to read.
  Dict: one of the Title dictionaries (recommended to use the TitleDict function)."""
      TxtFile = Addtxt(TxtFile)
      MatchResults = GetDataTxt(TxtFile, Dict)
      TitleResults = {}
      for i in range(len(MatchResults)):
          if MatchResults[i][0] not in TitleResults:
              TitleResults[MatchResults[i][0]] = []
          if MatchResults[i][2] not in TitleResults:
              TitleResults[MatchResults[i][2]] = []
      for CurrentMatch in MatchResults:
          while CurrentMatch[1] > 0:
              TitleResults[CurrentMatch[0]].append([Dict[CurrentMatch[2]][0], Dict[CurrentMatch[2]][1], 1, CurrentMatch[2]])
              TitleResults[CurrentMatch[2]].append([Dict[CurrentMatch[0]][0], Dict[CurrentMatch[0]][1], 0, CurrentMatch[0]])
              Dict[CurrentMatch[0]][3] += 1
              Dict[CurrentMatch[2]][3] += 1
              CurrentMatch[1] -= 1
          while CurrentMatch[3] > 0:
              TitleResults[CurrentMatch[2]].append([Dict[CurrentMatch[0]][0], Dict[CurrentMatch[0]][1], 1, CurrentMatch[0]])
              TitleResults[CurrentMatch[0]].append([Dict[CurrentMatch[2]][0], Dict[CurrentMatch[2]][1], 0, CurrentMatch[2]])
              Dict[CurrentMatch[0]][3] += 1
              Dict[CurrentMatch[2]][3] += 1
              CurrentMatch[3] -= 1
      return TitleResults
  
  def CountTitles(Person):
      """Returns the number of titles Person has participated in.
  Person: a string."""
      TitleNum = 0
      for Title in Titles:
          Dict = TitleDict(Title)
          if Person in Dict:
              if Dict[Person][3] > 0:
                  TitleNum += 1
      return TitleNum
  
  def ProcessRankings(ResultFiles, Title):
      """Processes all the Files in ResultFiles, and updates the Glicko2 values of each of the players.
  ResultFiles: a list of files to be read, each of which is given as a string.
  Title: a string in Titles; the Title the results are from.
  Example: ProcessRankings(['Beast V', 'Paragon 2015', 'Apex 2015'], 'Melee')"""
      Dict = TitleDict(Title)
      TitleResults = {}
      for File in ResultFiles:
          FileData = GetGameData(File, Dict)
          for Person in FileData:
              if Person not in TitleResults:
                  TitleResults[Person] = FileData[Person]
              else:
                  TitleResults[Person] += FileData[Person]
      for Person in Dict:
          DummyPerson = Player(rating = Dict[Person][0], rd = Dict[Person][1], vol = Dict[Person][2])
          if Person in TitleResults:
              OpponentRatings = [Title[0] for Title in TitleResults[Person]]
              OpponentRDs = [Title[1] for Title in TitleResults[Person]]
              Victories = [Title[2] for Title in TitleResults[Person]]
              DummyPerson.update_player([x for x in OpponentRatings], [x for x in OpponentRDs], Victories)
              Dict[Person] = [DummyPerson.rating, min(DummyPerson.rd, DefaultRD), DummyPerson.vol, Dict[Person][3], Dict[Person][4]]
          if Person not in TitleResults:
              DummyPerson.did_not_compete()
              Dict[Person] = [DummyPerson.rating, min(DummyPerson.rd, DefaultRD), DummyPerson.vol, Dict[Person][3], Dict[Person][4]]
  
  def PadLeft(s, Len, Padding = '0'):
      """Pads s on the left with Padding to length Len.
  s: a string.
  Len: an integer.
  Padding: a string."""
      while len(s) < Len:
          s = Padding + s
      return s
  
  def TakeSublist(BinaryString, l):
      """Returns the sublist of l including every element of l whose corresponding value in BinaryString is 1.
  BinaryString: a string whose characters are exclusively 0's and 1's.
  l: a list."""
      BinaryString = PadLeft(BinaryString, len(l), Padding = '0')
      Sublist = []
      for i in range(len(BinaryString)):
          if BinaryString[i] == '1':
              Sublist.append(l[i])
      return Sublist
  
  def DigitSum(DigitString):
      """Returns the sum of the digits for DigitString.
  DigitString: a string whose characters are integers."""
      i = 0
      Sum = 0
      while i < len(DigitString):
          Sum += int(DigitString[i])
          i +=1
      return Sum
  
  def DistinctSublists(l, SublistLen):
      """Returns all sublists of l with length SublistLen.
  l: a list.
  SublistLen: an integer."""
      return [TakeSublist(BinaryString, l) for BinaryString in sorted([PadLeft(bin(i)[2:], len(l), Padding = '0') for i in range(2**len(l))], reverse = True)\
              if DigitSum(BinaryString) == SublistLen]
  
  def NormalsAverage(NormalParameters):
      """Returns the "average" of the normal distributions from NormalParameters.
  NormalParameters: a list of length 2 lists, whose entries are the mean and SD of each normal distribution."""
      return [sum([Parameter[0] for Parameter in NormalParameters])/(len(NormalParameters)), \
              (sum([Parameter[1]**2 for Parameter in NormalParameters])/(len(NormalParameters)**2))**(1/2)]
  
  def PersonAverages(Person, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie):
      """Returns a list of all averages of rankings of Person for TitleMin titles, sorted as indicated.
  Person: a string.
  TitleMin: the number of titles to be included in each average.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie."""
      Sums = []
      for Sublist in DistinctSublists(Titles, TitleMin):
          Check = True
          for Title in Sublist:
              Check = Check and Person in TitleDict(Title)
          if Check:
              SublistAverage = NormalsAverage([[TitleDict(Title)[Person][0], TitleDict(Title)[Person][1]] for Title in Sublist])
              sb = Sortings.index(SortedBy)
              sbt = Sortings.index(SortedByTie)
              sbl = [i for i in range(len(Sortings)) if Sortings[i] not in [sb, sbt]][0]
              Sums.append(\
                  [Sublist, \
                   SublistAverage[0] - 2*SublistAverage[1], \
                   SublistAverage[0] - SublistAverage[1], \
                   SublistAverage[0], \
                   sum([TitleDict(Title)[Person][3] for Title in Sublist])])
      return sorted(Sums, key = lambda x: (x[sb + 1], x[sbt + 1], x[sbl + 1]), reverse = True)
  
  def OverallPersonDict(TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie):
      """Returns a dictionary with the best averages of Titlemin titles, where "best" is determined by the sorting as indicated.
  TitleMin: the number of titles to be included in each average.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie."""
      Dict = {}
      for Title in Titles:
          for Person in TitleDict(Title):
              if CountTitles(Person) >= TitleMin:
                  Dict[Person] = PersonAverages(Person, TitleMin, SortedBy, SortedByTie)[0]
                  Dict[Person].append([])
                  for Title in PersonAverages(Person, TitleMin, SortedBy, SortedByTie)[0][0]:
                      for File in TitleDict(Title)[Person][4]:
                          Dict[Person][5].append(File)
      return Dict
  
  def OverallRankingList(TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie):
      """To be used in RankingList, if the Title chosen is 'Overall'."""
      Dict = OverallPersonDict(TitleMin, SortedBy)
      Rankings = [[Dict[Person][1], Dict[Person][2], Dict[Person][3], Person, TagDict[Person], Dict[Person][0], Dict[Person][4]] for Person in Dict]
      shuffle(Rankings)
      sb = Sortings.index(SortedBy)
      sbt = Sortings.index(SortedByTie)
      sbl = [i for i in range(len(Sortings)) if Sortings[i] not in [sb, sbt]][0]
      Rankings.sort(key = lambda x: (x[sb], x[sbt], x[sbl]), reverse = True)
      for i in range(len(Rankings)):
          Rankings[i] = [i + 1, Rankings[i][0], Rankings[i][1], Rankings[i][2], Rankings[i][3], Rankings[i][4], Rankings[i][5], Rankings[i][6]]
      return Rankings
  
  def RankingList(Title, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie):
      """Returns a list with the rankings of all players in Title.
  Title: a string in Titles; the Title whose rankings are to be determined.
  TitleMin: the number of titles if the Title is 'Overall'.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie."""
      if Title == 'Overall':
          return OverallRankingList(TitleMin, SortedBy, SortedByTie)
      Dict = TitleDict(Title)
      Rankings = [[Dict[Person][0] - 2*Dict[Person][1], Dict[Person][0] - Dict[Person][1], Dict[Person][0], Person, TagDict[Person], Dict[Person][3]] for Person in Dict]
      shuffle(Rankings)
      sb = Sortings.index(SortedBy)
      sbt = Sortings.index(SortedByTie)
      sbl = [i for i in range(len(Sortings)) if Sortings[i] not in [sb, sbt]][0]
      Rankings.sort(key = lambda x: (x[sb], x[sbt], x[sbl]), reverse = True)
      for i in range(len(Rankings)):
          Rankings[i] = [i + 1, Rankings[i][0], Rankings[i][1], Rankings[i][2], Rankings[i][3], Rankings[i][4], Rankings[i][5]]
      return Rankings
  
  def ShowRankings(Title, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie, TopAmount = 1000000):
      """Shows the rankings for Title for the top TopAmount players.
  Title: a string in Titles; the Title whose rankings are to be shown.
  TitleMin: the number of titles if the Title is 'Overall'.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie.
  TopAmount: the maximum number of players to be shown.
  Example: ShowRankings('Melee', TitleMin = 2, SortedBy = 'Low', SortedByTie = 'Middle', TopAmount = 25)"""
      print(Title + '\t\t\t\t\t\t\t       Estimate')
      Rankings = RankingList(Title, TitleMin, SortedBy, SortedByTie)
      if Title == 'Overall':
          Dict = OverallPersonDict(TitleMin, SortedBy, SortedByTie)
          print('Place\tTag\t\tName\t\t\t Bottom\t\t    Low\t\t Middle\t\tGames\tBest Title' + 's'*(TitleMin > 1))
          TitleTotal = 0
          for i in range(len(Rankings)):
              if i < TopAmount:
                  Person = Rankings[i]
                  print(str(Person[0]) + '\t' + \
                        Person[4] + '\t'*(abs(int((15 - max(len(Person[4]), 1))/8))) + '\t' + \
                        Person[5] + '\t'*(abs(int((23 - max(len(Person[5]), 1))/8))) + '\t' + \
                        PadLeft(format(Person[1], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(format(Person[2], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(format(Person[3], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(str(Person[7]), 5, Padding = ' ') + '\t' + \
                        str(Person[6])[1:-1].replace("'", ''))
                  TitleTotal += Rankings[i][7]
          TotalSpacing = '\t'*11 + ' '*(5 - len(str(TitleTotal)))
      else:
          Dict = TitleDict(Title)
          print('Place\tTag\t\tName\t\t\t Bottom\t\t    Low\t\t Middle\t\tGames')
          TitleTotal = 0
          for i in range(len(Rankings)):
              if i < TopAmount:
                  Person = Rankings[i]
                  print(str(Person[0]) + '\t' + \
                        Person[4] + '\t'*(abs(int((15 - max(len(Person[4]), 1))/8))) + '\t' + \
                        Person[5] + '\t'*(abs(int((23 - len(Person[5]))/8))) + '\t' + \
                        PadLeft(format(Person[1], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(format(Person[2], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(format(Person[3], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(str(Person[6]), 5, Padding = ' '))
                  TitleTotal += Rankings[i][6]
          TotalSpacing = '\t'*11 + ' '*(5 - len(str(TitleTotal)))
      print('Total Games' + TotalSpacing, TitleTotal, sep = '')
  
  def WriteTxtRankings(IncludedTitles, TxtFile, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie, LinesBetween = DefaultLines):
      """Writes a TxtFile for the titles in IncludedTitles.
  IncludedTitles: a list of string(s) in Titles; the Title(s) whose rankings are to be written.
  TxtFile: a string; the name of the file to be written.
  TitleMin: the number of titles if the Title is 'Overall'.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie.
  Example: WriteTxtRankings(['Melee', 'Sm4sh'], 'MeleeSm4shRankings', TitleMin = 2, SortedBy = 'Low', SortedByTie = 'Middle', LinesBetween = 2)"""
      TxtFile = Addtxt(TxtFile)
      f = open(TxtFile, 'w')
      if type(IncludedTitles) != list:
          IncludedTitles = [IncludedTitles]
      for Title in IncludedTitles:
          f.write(Title + '\t\t\t\t\t\t\t       Estimate\n')
          Rankings = RankingList(Title, TitleMin, SortedBy, SortedByTie)
          if Title == 'Overall':
              Dict = OverallPersonDict(TitleMin, SortedBy, SortedByTie)
              f.write('Place\tTag\t\tName\t\t\t Bottom\t\t    Low\t\t Middle\t\tGames\tBest Title' + 's'*(TitleMin > 1) + '\n')
              TitleTotal = 0
              for i in range(len(Rankings)):
                  Person = Rankings[i]
                  f.write(str(Person[0]) + '\t' +\
                        Person[4] + '\t'*(abs(int((15 - max(len(Person[4]), 1))/8))) + '\t' + \
                        Person[5] + '\t'*(abs(int((23 - max(len(Person[5]), 1))/8))) + '\t' + \
                        PadLeft(format(Person[1], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(format(Person[2], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(format(Person[3], Rounding), 7, Padding = ' ') + '\t' + '\t' +\
                        PadLeft(str(Person[7]), 5, Padding = ' ') + '\t' +\
                        str(Person[6])[1:-1].replace("'", '') + '\n')
                  TitleTotal += Rankings[i][7]
              TotalSpacing = '\t'*11 + ' '*(5 - len(str(TitleTotal)))
          else:
              Dict = TitleDict(Title)
              f.write('Place\tTag\t\tName\t\t\t Bottom\t\t    Low\t\t Middle\t\tGames\n')
              TitleTotal = 0
              for i in range(len(Rankings)):
                  Person = Rankings[i]
                  f.write(str(Person[0]) + '\t' + \
                        Person[4] + '\t'*(abs(int((15 - max(len(Person[4]), 1))/8))) + '\t' + \
                        Person[5] + '\t'*(abs(int((23 - len(Person[5]))/8))) + '\t' + \
                        PadLeft(format(Person[1], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(format(Person[2], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(format(Person[3], Rounding), 7, Padding = ' ') + '\t' + '\t' + \
                        PadLeft(str(Person[6]), 5, Padding = ' ') + '\n')
                  TitleTotal += Rankings[i][6]
              TotalSpacing = '\t'*11 + ' '*(5 - len(str(TitleTotal)))
          f.write('Total Games' + TotalSpacing + str(TitleTotal))
          if Title != (IncludedTitles)[-1]:
              f.write('\n'*(LinesBetween + 1))
      f = open(TxtFile, 'r+')
      f.close()
  
  def WriteMobileRankings(IncludedTitles, TxtFile, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie, LinesBetween = DefaultLines):
      """Writes a TxtFile for the titles in IncludedTitles, in a mobile friendly format.
  IncludedTitles: a list of string(s) in Titles; the Title(s) whose rankings are to be written.
  TxtFile: a string; the name of the file to be written.
  TitleMin: the number of titles if the Title is 'Overall'.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie.
  Example: WriteMobileRankings(['Melee', 'Sm4sh'], 'MeleeSm4shRankingsMobile', TitleMin = 2, SortedBy = 'Low', SortedByTie = 'Middle', LinesBetween = 2)"""
      TxtFile = Addtxt(TxtFile)
      f = open(TxtFile, 'w')
      if type(IncludedTitles) != list:
          IncludedTitles = [IncludedTitles]
      f.write('Place - Tag / Name: Games Played\n(Best Title(s) if Overall)\nLow, Middle, High Estimates\n\n')
      for Title in IncludedTitles:
          f.write(Title + '\n')
          Rankings = RankingList(Title, TitleMin, SortedBy, SortedByTie)
          if Title == 'Overall':
              Dict = OverallPersonDict(TitleMin, SortedBy, SortedByTie)
              TitleTotal = 0
              for i in range(len(Rankings)):
                  Person = Rankings[i]
                  f.write(str(Person[0]) + ' - ' + \
                        Person[4] + ' / ' + \
                        Person[5] + ': ' + \
                        str(Person[7]) + '\n' + \
                        str(Person[6])[1:-1].replace("'", '') + '\n' + \
                        format(Person[1], Rounding) + ', ' + \
                        format(Person[2], Rounding) + ', ' + \
                        format(Person[3], Rounding) + '\n\n')
                  TitleTotal += Rankings[i][7]
          else:
              Dict = TitleDict(Title)
              TitleTotal = 0
              for i in range(len(Rankings)):
                  Person = Rankings[i]
                  f.write(str(Person[0]) + ' - ' + \
                        Person[4] + ' / ' + \
                        Person[5] + ': ' + \
                        str(Person[6]) + '\n' + \
                        format(Person[1], Rounding) + ', ' + \
                        format(Person[2], Rounding) + ', ' + \
                        format(Person[3], Rounding) + '\n\n')
                  TitleTotal += Rankings[i][6]
          f.write('Total Games: ' + str(TitleTotal))
          if Title != (IncludedTitles)[-1]:
              f.write('\n'*(LinesBetween + 1))
      f = open(TxtFile, 'r+')
      f.close()
  
  def WriteCSVRankings(IncludedTitles, CSVFile, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie, LinesBetween = DefaultLines):
      """Writes a CSVFile (Excel) for the titles in IncludedTitles.
  IncludedTitles: a list of string(s) in Titles; the Title(s) whose rankings are to be written.
  CSVFile: a string; the name of the file to be written.
  TitleMin: the number of titles if the Title is 'Overall'.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie.
  Example: WriteCSVRankings(['Melee', 'Sm4sh'], 'MeleeSm4shRankings', TitleMin = 2, SortedBy = 'Low', SortedByTie = 'Middle', LinesBetween = 2)"""
      if CSVFile[-4:] != '.csv':
          CSVFile = CSVFile + '.csv'
      f = open(CSVFile, 'w', newline='')
      spamwriter = csv.writer(f, quoting=csv.QUOTE_MINIMAL)
      if type(IncludedTitles) != list:
          IncludedTitles = [IncludedTitles]
      for Title in IncludedTitles:
          spamwriter.writerow([Title, '', '', '', 'Estimate'])
          Rankings = RankingList(Title, TitleMin, SortedBy, SortedByTie)
          if Title == 'Overall':
              Dict = OverallPersonDict(TitleMin, SortedBy, SortedByTie)
              spamwriter.writerow(['Place', 'Tag', 'Name', 'Bottom', 'Low', 'Middle', 'Games', 'Best Title'+('s'*(TitleMin > 1))])
              TitleTotal = 0
              for i in range(len(Rankings)):
                  Person = Rankings[i]
                  spamwriter.writerow([Person[0], Person[4], Person[5], Person[1], Person[2], Person[3], Person[7], str(Person[6])[1:-1].replace("'", '')])
                  TitleTotal += Rankings[i][7]
              TotalSpacing = '\t'*11 + ' '*(5 - len(str(TitleTotal)))
          else:
              Dict = TitleDict(Title)
              spamwriter.writerow(['Place', 'Tag', 'Name', 'Bottom', 'Low', 'Middle', 'Games'])
              TitleTotal = 0
              for i in range(len(Rankings)):
                  Person = Rankings[i]
                  spamwriter.writerow([Person[0], Person[4], Person[5], Person[1], Person[2], Person[3], Person[6]])
                  TitleTotal += Rankings[i][6]
              TotalSpacing = '\t'*11 + ' '*(5 - len(str(TitleTotal)))
          spamwriter.writerow(['Total Games', '', '', '', '', '', TitleTotal])
          if Title != IncludedTitles[-1]:
              i = 0
              while i < LinesBetween:
                  spamwriter.writerow([])
                  i += 1
      f.close()
  
  
  def ShowTabSepRankings(Title, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie, TopAmount = 1000000):
      """Shows the rankings for Title for the top TopAmount players in tab-separated format for copying to a spreadsheet.
      Title: a string in Titles; the Title whose rankings are to be shown.
      TitleMin: the number of titles if the Title is 'Overall'.
      SortedBy: a string in Sortings; the primary method of sorting.
      SortedByTie: a string in Sortings; the method of sorting in the event of a tie.
      TopAmount: the maximum number of players to be shown.
      Example: ShowRankings('Melee', TitleMin = 2, SortedBy = 'Low', SortedByTie = 'Middle', TopAmount = 25)"""
      #print(Title + '\t\t\t\t\t\t\t       Estimate')
      Rankings = RankingList(Title, TitleMin, SortedBy, SortedByTie)
      TooHighVariance = []
      Dict = TitleDict(Title)
      print('Place\tBottom\tLow\tMiddle\tGames')
      TitleTotal = 0
      for i in range(len(Rankings)):
          if i < TopAmount:
              Person = Rankings[i]
              if int(Person[3]) - int(Person[2]) > VarianceCutoff:
                  TopAmount += 1
                  TooHighVariance.append(Person)
              else:
                  print(Person[4] + '\t' +
                        str(format(Person[1], Rounding)) + '\t' +
                        str(format(Person[2], Rounding)) + '\t' +
                        str(format(Person[3], Rounding)) + '\t' +
                        str(Person[6]))
                  TitleTotal += Rankings[i][6]
      total = 0
      people = 0
      for i in range(len(Rankings)):
          Person = Rankings[i]
          total += int(Person[6])
          people += 1
      print("Players with high scores but also high variance:")
      print('Tag\tRating\tGames\tVariance')
      for Person in TooHighVariance:
          print(Person[4] + '\t' +
                str(format(Person[2], Rounding)) + '\t' +
                str(Person[6]) + '\t' +
                str(format(int(Person[3])-int(Person[2]), Rounding)))
      print("Total games in database: " + str(int(total/2)))
      print("Total players in database: " + str(people))
  
  
  def ShowAllRankings(SortedBy = DefaultSort, SortedByTie = DefaultSortTie, TitleMin = DefaultTitleMin, LinesBetween = DefaultLines, TopAmount = 1000000):
      """Runs ShowRankings for each Title in Titles, with LinesBetween lines between each.
  Example: ShowAllRankings(SortedBy = 'Low', SortedByTie = 'Middle', TitleMin = 2, LinesBetween = 2, TopAmount = 25)"""
      for Title in ['Overall'] + Titles:
          ShowRankings(Title, TitleMin, SortedBy, SortedByTie, TopAmount)
          if Title != (['Overall'] + Titles)[-1]:
              print('\n'*(LinesBetween - 1))
  
  def WriteTxtAllRankings(TxtFile, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie, LinesBetween = DefaultLines):
      """Runs WriteTxtRankings for each Title in Tiles, with LinesBetween lines between each.
  Example: WriteTxtAllRankings('Rankings', TitleMin = 2, SortedBy = 'Low', SortedByTie = 'Middle', LinesBetween = 2)"""
      WriteTxtRankings(['Overall'] + Titles, TxtFile, TitleMin, SortedBy, SortedByTie, LinesBetween)
  
  def WriteMobileAllRankings(TxtFile, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie, LinesBetween = DefaultLines):
      """Runs WriteMobileRankings for each Title in Tiles, with LinesBetween lines between each.
  Example: WriteMobileAllRankings('RankingsMobile', TitleMin = 2, SortedBy = 'Low', SortedByTie = 'Middle', LinesBetween = 2)"""
      WriteMobileRankings(['Overall'] + Titles, TxtFile, TitleMin, SortedBy, SortedByTie, LinesBetween)
  
  def WriteCSVAllRankings(CSVFile, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie, LinesBetween = DefaultLines):
      """Runs WriteCSVRankings for each Title in Tiles, with LinesBetween lines between each.
  Example: WriteCSVAllRankings('Rankings', TitleMin = 2, SortedBy = 'Low', SortedByTie = 'Middle', LinesBetween = 2)"""
      WriteCSVRankings(['Overall'] + Titles, CSVFile, TitleMin, SortedBy, SortedByTie, LinesBetween)
  
  def ToTag(Person):
      """Returns the tag of Person.
  Person: a string."""
      if Person not in TagDict:
          Person = NameDict[Person]
      return Person    
  
  def SingleRanking(Person, Title, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie):
      """Returns the ranking info of Person in Title, where their rank within title is determined with the sorting as indicated.
  Person: a string.
  Title: a string in Titles; the Title whose rankings are to be determined.
  TitleMin: the number of titles if the Title is 'Overall'.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie."""
      Person = ToTag(Person)
      Rankings = RankingList(Title, TitleMin, SortedBy, SortedByTie)
      return Rankings[[Ranking[4] for Ranking in Rankings].index(Person)]
  
  def PersonRankings(Person, TitleMin = DefaultTitleMin, SortedBy = DefaultSort, SortedByTie = DefaultSortTie):
      """Prints all the ranking info of each title for Person, as well as which files they appear in.
  Person: a string.
  TitleMin: the number of titles if the Title is 'Overall'.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie.
  Example: PersonRankings('Mew2King', TitleMin = 2, SortedBy = 'Low', SortedByTie = 'Middle')"""
      Person = ToTag(Person)
      OverallDict = OverallPersonDict(TitleMin, SortedBy, SortedByTie)
      print('\t\t\t\t       Estimate')
      print('Title\tRank\t\t Bottom\t\t    Low\t\t Middle\t\tGames' + '\tBest titles'*(Person in OverallDict and CountTitles(Person) >= TitleMin))
      if Person in OverallDict and CountTitles(Person) >= TitleMin:
          Ranking = SingleRanking(Person, 'Overall', TitleMin, SortedBy, SortedByTie)
          print(\
              'Overall', \
              str(Ranking[0]) + ' of ' + str(len(OverallDict)) + \
              '\t'*(abs(int((15 - max(len(str(Ranking[0]) + ' of ' + str(len(OverallDict))), 1))/8))), \
              PadLeft(format(Ranking[1], Rounding), 7, Padding = ' ') + '\t', \
              PadLeft(format(Ranking[2], Rounding), 7, Padding = ' ') + '\t', \
              PadLeft(format(Ranking[3], Rounding), 7, Padding = ' ') + '\t', \
              PadLeft(str(Ranking[7]), 5, Padding = ' '), \
              str(Ranking[6])[1:-1].replace("'", ''), \
              sep = '\t'
              )
      for Title in Titles:
          if Person in TitleDict(Title):
              Dict = TitleDict(Title)
              Ranking = SingleRanking(Person, Title, TitleMin, SortedBy, SortedByTie)
              print(\
                  Title, \
                  str(Ranking[0]) + ' of ' + str(len(Dict)) + '\t'*(abs(int((15 - max(len(str(Ranking[0]) + ' of ' + str(len(Dict))), 1))/8))), \
                  PadLeft(format(Ranking[1], Rounding), 7, Padding = ' ') + '\t', \
                  PadLeft(format(Ranking[2], Rounding), 7, Padding = ' ') + '\t', \
                  PadLeft(format(Ranking[3], Rounding), 7, Padding = ' ') + '\t', \
                  PadLeft(str(Ranking[6]), 5, Padding = ' '),
                  sep = '\t'\
                  )
      print(Person + ' appears in the following files: ')
      for File in FileList(Person):
          print(File)
  
  def AllNames(PersonList):
      """Returns True if every Person in PersonList has a name in TagDict.
  PersonList: the tags to be checked."""
      Check = True
      for Person in PersonList:
          if Person in TagDict:
              Check = Check and TagDict[Person]!=''
          else:
              Check = False
      return Check
  
  def FileList(Person):
      PersonFileList = []
      for Title in Titles:
          if Person in TitleDict(Title):
              for File in TitleDict(Title)[Person][4]:
                  PersonFileList.append(File)
      return PersonFileList
      
  def NoNames(PersonList = [], Files = True):
      """Prints the names of all tags with no name, as well as which files they appear in, if indicated.
  PersonList: the tags to be checked. If left as the default, all tags that have been processed will be checked.
  Example: NoNames(['Mew2King', 'Axe', 'RandomPerson420'], Files = True)"""
      if PersonList == []:
          for Title in Titles:
              for Person in TitleDict(Title):
                  PersonList.append(Person)
      if not AllNames(PersonList):
          print('The following tags do not have names in TagDict:')
          PersonList = set(PersonList)
          for Person in PersonList:
              if Person not in TagDict:
                  TagDict[Person] = ''
              if TagDict[Person]=='':
                  print(Person + (', who appears in the following: ' + ', '.join(FileList(Person)))*(len(FileList(Person)) >= 1)*Files)
      else:
          print('Everyone has a name in TagDict. Hooray!')
  
  def NestedQ(l):
      """Returns True if every item in List is a list or a tuple.
  l: a list."""
      return {type(item) for item in l} in [{list}, {tuple}]
  
  def FlattenShallowList(ShallowList):
      """Flattens a shallow list.
  ShallowList: a list of depth at most two."""
      if not NestedQ(ShallowList):
          return ShallowList
      else:
          return list(sum(ShallowList, ()))
  
  def DeleteDuplicates(l):
      """Deletes duplicate objects in List, where tuples and lists in nested lists are treated as unordered.
  l: a list."""
      unique = []
      if NestedQ(l):
          for item in l:
              if sorted(item) not in unique:
                  if type(item) == tuple:
                      unique.append(tuple(sorted(item)))
                  else:
                      unique.append(sorted(item))
      else:
          for item in l:
              if item not in unique:
                  unique.append(item)
      return unique
  
  def EveryoneCompeted(PersonList, Title):
      """Returns True if everyone in PersonList has competed in Title previously.
  PersonList: a list of strings.
  Title: a string in Titles."""
      PersonList = FlattenShallowList(PersonList)
      Check = True
      Dict = {Person:TitleDict(Title)[Person] for Person in TitleDict(Title)}
      for Person in PersonList:
          AddPerson(Person, Dict)
          Check = Check and Dict[Person][3] > 0
      return Check
  
  def YetToCompete(PersonList, Title):
      """Prints the Persons in PersonList who have not yet competed in Title.
  PersonList: a list of strings.
  Title: a string in Titles.
  Example: YetToCompete(['Mew2King', 'Axe', 'RandomPerson420'], 'Melee')"""
      PersonList = DeleteDuplicates(FlattenShallowList(PersonList))
      Dict = {Person:TitleDict(Title)[Person] for Person in TitleDict(Title)}
      if not EveryoneCompeted(PersonList, Title):
          print('The following players have not competed previously in ' + Title + ':')
          for Person in PersonList:
              AddPerson(Person, Dict)
              if Dict[Person][3] == 0:
                  print(Person)
      else:
          print('Everyone has competed previously in ' + Title + '. Hooray!')
  
  def Seeding(EntrantList, Title, SortedBy = DefaultSort, SortedByTie = DefaultSortTie):
      """Returns EntrantList sorted by the seeding for Title, with seeding determined as indicated,
  with complete ties seeded randomly. Those who have not yet competed are given default rating values.
  EntrantList: a list of strings (or a list of tuples whose values are strings, for teams).
  Title: a string in Titles.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie."""
      EntrantList = DeleteDuplicates([Replacements(Entrant) for Entrant in EntrantList])
      shuffle(EntrantList)
      Dict = {Person:TitleDict(Title)[Person] for Person in TitleDict(Title)}
      SeedList = []
      Singles = not NestedQ(EntrantList)
      if Singles:
          for Entrant in EntrantList:
              AddPerson(Entrant, Dict)
              EntrantInfo = Dict[Entrant]
              SeedList.append([Entrant, EntrantInfo[0] - 2*EntrantInfo[1], EntrantInfo[0] - EntrantInfo[1], EntrantInfo])
      if not Singles:
          for Team in EntrantList:
              for Person in Team:
                  AddPerson(Person, Dict)
              TeamInfoStart = [Dict[Person] for Person in Team]
              TeamInfo = NormalsAverage([[PersonInfo[0], PersonInfo[1]] for PersonInfo in TeamInfoStart])
              SeedList.append([Team, TeamInfo[0] - 2*TeamInfo[1], TeamInfo[0] - TeamInfo[1], TeamInfo])
      sb = Sortings.index(SortedBy)
      sbt = Sortings.index(SortedByTie)
      sbl = [i for i in range(len(Sortings)) if Sortings[i] not in [sb, sbt]][0]
      SeedList.sort(key = lambda x: (x[sb + 1], x[sbt + 1], x[sbl + 1]), reverse = True)
      return [Seed[0] for Seed in SeedList]
  
  def ShowSeeding(EntrantList, Title, SortedBy = DefaultSort, SortedByTie = DefaultSortTie, Nums = False):
      """Prints the seeds for EntrantList, with seeding determined as indicated, for Title,
  printing the numbers of the seeds if indicated.
  EntrantList: a list of strings (or a list of tuples whose values are strings, for teams).
  Title: a string in Titles.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie.
  Nums: whether the numbers of the seeds shall be shown.
  Example (Singles):
  ShowSeeding([\
  'Armada',
  'PPMD',
  'Leffen',
  'Hungrybox',
  'MaNg0',
  'Hax',
  'Mew2King',
  'Silent Wolf',
  'aMSa',
  'Ice',
  'Westballz',
  'Shroomed',
  'Colbol',
  'Axe',
  'Lucky',
  'Javi',
  'Fiction',
  'Cactuar',
  'Kalamazhu',
  'Wizzrobe',
  'Kels',
  'SFAT',
  'The Moon',
  'Weon-X',
  'Plup'],
  'Melee', SortedBy = 'Low', SortedByTie = 'Middle', Nums = False)
  
  Example (Doubles):
  ShowSeeding([\
  ('Armada', 'PPMD'),
  ('Leffen', 'Hungrybox'),
  ('MaNg0', 'Hax'),
  ('Mew2King', 'Silent Wolf'),
  ('aMSa', 'Ice'),
  ('Westballz','Shroomed'),
  ('Colbol','Axe'),
  ('Lucky','Javi'),
  ('Fiction','Cactuar'),
  ('Kalamazhu','Wizzrobe'),
  ('Kels','SFAT'),
  ('The Moon','Weon-X')],
  'Melee', SortedBy = 'Low', SortedByTie = 'Middle', Nums = False)"""
      EntrantList = Seeding(EntrantList, Title, SortedBy, SortedByTie)
      NoNames(FlattenShallowList(EntrantList), Files = False)
      print()
      YetToCompete(FlattenShallowList(EntrantList), Title)
      print()
      Singles = not NestedQ(EntrantList)
      if Singles:
          for i in range(len(EntrantList)):
              print((str(i + 1) + ':' + ' '*(1 + len(str(len(EntrantList))) - len(str(i + 1))))*Nums, EntrantList[i], sep = '')
      if not Singles:
          for i in range(len(EntrantList)):
              print((str(i + 1) + ':' + ' '*(1 + len(str(len(EntrantList))) - len(str(i + 1))))*Nums, ', '.join([Player for Player in EntrantList[i]]), sep = '')
  
  
  def Pooling(EntrantList, Title, PoolSize = 5, Seeded = False, SortedBy = DefaultSort, SortedByTie = DefaultSortTie):
      """Returns EntrantList divided into pools with PoolSize persons in each
  by the seeding for Title, with seeding determined as indicated, with complete ties seeded randomly.
  Those who have not yet competed are given default rating values.
  EntrantList: a list of strings (or a list of tuples whose values are strings, for teams).
  PoolSize: the number to be in each pool.
  Title: a string in Titles.
  Seeded: whether EntrantList is already seeded or not.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie."""
      EntrantList = DeleteDuplicates([Replacements(Entrant) for Entrant in EntrantList])
      if Seeded == False:
          EntrantList = Seeding(EntrantList, Title, SortedBy, SortedByTie)
      PoolsNum = ceil(len(EntrantList)/PoolSize)
      Pools = [[] for i in range(PoolsNum)]
      for i in range(PoolsNum):
          if EntrantList != []:
              Pools[i] += [EntrantList[0]]
              EntrantList = EntrantList[1:]
          else:
              pass
      for i in range(PoolsNum):
          if EntrantList != []:
              Pools[-i - 1] += [EntrantList[0]]
              EntrantList = EntrantList[1:]
          else:
              pass
      while len(EntrantList) >= 2*PoolsNum:
          for i in range(PoolsNum):
              if EntrantList != []:
                  Pools[-i - 1] += [EntrantList[0]]
                  EntrantList = EntrantList[1:]
              else:
                  pass
          for i in range(PoolsNum):
              if EntrantList != []:
                  Pools[i] += [EntrantList[0]]
                  EntrantList = EntrantList[1:]
              else:
                  pass
      while EntrantList != []:
          for i in range(PoolsNum):
              if EntrantList != []:
                  Pools[-i - 1] += [EntrantList[0]]
                  EntrantList = EntrantList[1:]
              else:
                  pass
      return Pools
  
  def ShowPoolingInner(EntrantList, Title, PoolSize = 5, Seeded = False, SortedBy = DefaultSort, SortedByTie = DefaultSortTie):
      """To be used in ShowPooling and ShowPoolingFromPools."""
      PoolList = Pooling(EntrantList, Title, PoolSize, Seeded, SortedBy, SortedByTie)
      if NestedQ(EntrantList):
          for i in range(len(PoolList)):
              print('Pool ' + str(i + 1) + ' (' + str(len(PoolList[i])) + ' teams)' + \
                    ' '*(len(str(len(PoolList))) - len(str(i + 1)) + len(str(PoolSize)) - len(str(len(PoolList[i])))))
              print(*[', '.join([PoolList[i][a][j] for j in range(len(PoolList[i][a]))]) for a in range(len(PoolList[i]))], sep = '\n')
              if i!= len(PoolList) - 1:
                  print()
      else:
          for i in range(len(PoolList)):
              print('Pool ' + str(i + 1) + ' (' + str(len(PoolList[i])) + ' players)' + \
                    ' '*(len(str(len(PoolList))) - len(str(i + 1)) + len(str(PoolSize)) - len(str(len(PoolList[i])))))
              print(*PoolList[i], sep = '\n')
              print()
          print('Here is the PoolList in raw form. Save this to be used with WriteTxtFromPools.')
          print(PoolList)
  
  def ShowPooling(EntrantList, Title, PoolSize = 5, Seeded = False, SortedBy = DefaultSort, SortedByTie = DefaultSortTie):
      """Prints the pools with PoolSize persons in each for EntrantList, with seeding determined as indicated, for Title.
  EntrantList: a list of strings (or a list of tuples whose values are strings, for teams).
  Title: a string in Titles.
  PoolSize: the number to be in each pool.
  SortedBy: a string in Sortings; the primary method of sorting.
  SortedByTie: a string in Sortings; the method of sorting in the event of a tie.
  Example (Singles):
  ShowPooling([\
  'Armada',
  'PPMD',
  'Leffen',
  'Hungrybox',
  'MaNg0',
  'Hax',
  'Mew2King',
  'Silent Wolf',
  'aMSa',
  'Ice',
  'Westballz',
  'Shroomed',
  'Colbol',
  'Axe',
  'Lucky',
  'Javi',
  'Fiction',
  'Cactuar',
  'Kalamazhu',
  'Wizzrobe',
  'Kels',
  'SFAT',
  'The Moon',
  'Weon-X',
  'Plup'],
  'Melee', PoolSize = 5, Seeded = False, SortedBy = 'Low', SortedByTie = 'Middle')
  
  Example (Doubles):
  ShowPooling([\
  ('Armada', 'PPMD'),
  ('Leffen', 'Hungrybox'),
  ('MaNg0', 'Hax'),
  ('Mew2King', 'Silent Wolf'),
  ('aMSa', 'Ice'),
  ('Westballz','Shroomed'),
  ('Colbol','Axe'),
  ('Lucky','Javi'),
  ('Fiction','Cactuar'),
  ('Kalamazhu','Wizzrobe'),
  ('Kels','SFAT'),
  ('The Moon','Weon-X')],
  'Melee', PoolSize = 5, Seeded = False, SortedBy = 'Low', SortedByTie = 'Middle')"""
      EntrantList = DeleteDuplicates([Replacements(Entrant) for Entrant in EntrantList])
      NoNames(FlattenShallowList(EntrantList), Files = False)
      print()
      YetToCompete(FlattenShallowList(EntrantList), Title)
      print()
      ShowPoolingInner(EntrantList, Title, PoolSize, Seeded, SortedBy, SortedByTie)
  
  def SeedingFromPools(PoolQualifiers):
      """Returns the persons in PoolQualifiers sorted by seeding as determined by their place in the pool.
  PoolQualifiers: A list of lists of qualifiers from pools, where the sublists are in order from strongest
  to weakest pool, and each sublist is ordered from top to bottom qualifier."""
      SeedList = []
      for i in range(max([len(PoolQualifiers[j]) for j in range(len(PoolQualifiers))])):
          if (i%2 == 0) ^ (i > 1):
              for Sublist in PoolQualifiers:
                  if i < len(Sublist):
                      SeedList.append(Sublist[i])
          else:
              for Sublist in PoolQualifiers[::-1]:
                  if i < len(Sublist):
                      SeedList.append(Sublist[i])
      return SeedList
  
  def ShowSeedingFromPools(PoolQualifiers, Nums = False):
      """Prints the seeds for the persons in PoolQualifiers, printing the numbers of the seeds if indicated.
  PoolQualifiers: A list of lists of qualifiers from pools, where the sublists are in order from strongest
  to weakest pool, and each sublist is ordered from top to bottom qualifier.
  Nums: whether the numbers of the seeds shall be shown.
  Example (Singles): ShowSeedingFromPools([['Armada', 'Ice'], ['PPMD', 'aMSa'], ['Leffen', 'Silent Wolf'], ['Hungrybox', 'Mew2King'], ['MaNg0', 'Hax']], Nums = False)
  Example (Doubles):
  ShowSeedingFromPools(\
  [[('Armada', 'PPMD'), ('Shroomed', 'Westballz')],
  [('Hungrybox', 'Leffen'), ('Ice', 'aMSa')],
  [('Hax', 'MaNg0'), ('Mew2King', 'Silent Wolf')]],
  Nums = False)"""
      PoolQualifiers = SeedingFromPools(PoolQualifiers)
      if type(PoolQualifiers[0]) == tuple:
          for i in range(len(PoolQualifiers)):
              print((str(i + 1) + ':' + ' '*(1 + len(str(len(PoolQualifiers))) - len(str(i + 1))))*Nums, ', '.join([PoolQualifiers[i][j] for j in range(len(PoolQualifiers[i]))]), sep = '')
      else:
          for i in range(len(PoolQualifiers)):
              print((str(i + 1) + ':' + ' '*(1 + len(str(len(PoolQualifiers))) - len(str(i + 1))))*Nums, PoolQualifiers[i], sep = '')
  
  def ShowPoolingFromPools(PoolQualifiers, PoolSize = 5):
      """For use in tournnaments with multiple rounds of pool. Prints pools for the persons in PoolQualifiers.
  PoolQualifiers: A list of lists of qualifiers from pools, where the sublists are in order from strongest
  to weakest pool, and each sublist is ordered from top to bottom qualifier.
  PoolSize: the number to be in each new pool.
  Example (Singles): ShowPoolingFromPools([['Armada', 'Ice'], ['PPMD', 'aMSa'], ['Leffen', 'Silent Wolf'], ['Hungrybox', 'Mew2King'], ['MaNg0', 'Hax']], PoolSize = 5)
  Example (Doubles):
  ShowPoolingFromPools(\
  [[('Armada', 'PPMD'), ('Shroomed', 'Westballz')],
  [('Hungrybox', 'Leffen'), ('Ice', 'aMSa')],
  [('Hax', 'MaNg0'), ('Mew2King', 'Silent Wolf')]],
  PoolSize = 5)"""
      EntrantList = DeleteDuplicates([Replacements(Entrant) for Entrant in SeedingFromPools(PoolQualifiers)])
      ShowPoolingInner(EntrantList, Title = 'SSB', PoolSize = PoolSize, Seeded = True) # Title is just here as a placeholder, doesn't actually do anything
  
  def WriteTxtFromPools(PoolList, TxtFile):
      """Prompts you to enter the results for matches from pools, then writes those results to a .txt file.
  PoolList: a list of lists of strings. Each sublist is a pool, with each string in the sublist being one of the players in the pool.
  TxtFile: a string; the name of the file to be written.
  Example:
  WriteTxtFromPools(\
  [['Armada', 'Ice', 'Lucky', 'Javi', 'Plup'],
  ['PPMD', 'aMSa', 'Axe', 'Fiction', 'Weon-X'],
  ['Leffen', 'Silent Wolf', 'Colbol', 'Cactuar', 'The Moon'],
  ['Hungrybox', 'Mew2King', 'Shroomed', 'Kalamazhu', 'SFAT'],
  ['MaNg0', 'Hax', 'Westballz', 'Wizzrobe', 'Kels']],
  'PoolResults')"""
      print("Remember, enter matches with DQ'ed person(s) as 0 wins for both players.")
      print()
      TxtFile = Addtxt(TxtFile)
      f = open(TxtFile, 'w')
      for i in range(len(PoolList)):
          Pool = PoolList[i]
          print('Pool ' + str(i + 1) + ':')
          PairList = DistinctSublists(Pool, 2)
          for Pair in PairList:
              print('Match: ' + Pair[0] + ' vs. ' + Pair[1])
              P1Wins = input('How many games did ' + Pair[0] + ' win? ')
              P2Wins = input('How many games did ' + Pair[1] + ' win? ')
              print()
              f.write(Pair[0] + ' ' + P1Wins + ' ' + Pair[1] + ' ' + P2Wins)
              if Pair != PairList[-1] or Pool != PoolList[-1]:
                  f.write('\n')
          if i != len(PoolList) - 1:
              print()
      f = open(TxtFile, 'r+')
      f.close()
  
  def FunctionInfo(f):
      """Prints the header for f.
  f: a function.
  Example: FunctionInfo(WriteTxtFromChallonge)"""
      print("{}{}".format(f.__name__, signature(f)))
      docstring = getdoc(f)
      if type(docstring) == str:
          docstring = docstring.replace('\n', '\n\t')
      if docstring == None:
          docstring = 'No docstring'
      print('\t', docstring, sep = '')
  
  UsefulFunctionList = [WriteTxtFromChallonge, WriteTxtFromPools, ProcessRankings, ShowRankings, ShowAllRankings, \
                      WriteTxtRankings, WriteMobileRankings, WriteCSVRankings, WriteTxtAllRankings, WriteMobileAllRankings, WriteCSVAllRankings, PersonRankings, \
                      NoNames, YetToCompete, ShowSeeding, ShowPooling, ShowSeedingFromPools, ShowPoolingFromPools, FunctionInfo]
  
  def UsefulFunctionsListed():
      """Prints the names of all useful functions."""
      for Function in UsefulFunctionList:
          print(Function.__name__)
  
  def UsefulFunctions():
      """Prints a list of useful functions as well as their docstrings."""
      print("Titles = ['Melee', 'PM', 'Sm4sh', 'SSB', 'Brawl'] and Sortings = ['Bottom', 'Low', 'Middle'].")
      print()
      for Function in UsefulFunctionList:
          FunctionInfo(Function)
          if Function != UsefulFunctionList[-1]:
              print()
  