Repository: MarkBaggett/freq Branch: master Commit: e13f41f43e5f Files: 9 Total size: 66.3 KB Directory structure: gitextract_2pt2i8lf/ ├── CONTRIBUTE.md ├── LICENSE ├── README.md ├── freq.py ├── freq_server.py ├── freq_sort.py ├── freqtable2018.freq ├── systemd/ │ └── freq.service └── upstart/ └── sample_upstart.config ================================================ FILE CONTENTS ================================================ ================================================ FILE: CONTRIBUTE.md ================================================ # Contribute.md ## Team members * [Mark Baggett](https://github.com/MarkBaggett) ## Adding new features If you're interested in adding new features or fixing issues to the `freq` project, the overall process is: 1. Select an issue to work on and assign the issue to yourself. If not already created, first create the issue. 2. Fork the project. 3. Make the changes, including any additional test cases that should be added. 4. Create a Pull Request against the `master` branch of this repo. 5. After a review of the PR, make any changes as requested by the reviewer. 6. The PR will then be merged into the repo. Don’t get discouraged! We estimate that the response time from the maintainers is around a few days. ## Bug Triage We welcome the reporting of issues and do so by using the [integrated Github issues](https://github.com/MarkBaggett/freq/issues). When creating a new issue, you can help us diagnose and fix existing bugs by asking and providing answers for the following: * Is the bug reproducible as explained? * Is it reproducible in other environments (for instance, different versions of python, or different operating systems)? * Are the steps to reproduce the bug clear? If not, can you describe how you might reproduce it? * What tags should the bug have? ## Documentation If you're interested in working on the documentation for the project, feel free to do so as well. The same process for adding new features goes for adding documentation. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2018 Mark Baggett 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. ================================================ FILE: README.md ================================================ # freq This is a repository for `freq.py` and `freq_server.py`. ## Background: While sitting in SANS SEC511 I listened to [`@sethmisenar`](https://twitter.com/sethmisenar) laement the difficulty in using existing tools to detect DGA (Domain Generation Algorithm) hostnames often used by malware. There are lots of AI based tools out there that do this but some are rather complex. I thought I could quickly write a tool that would work. In about 30 minutes I threw together some old code I had lying around from a SQL Injection tool I worked on and I had a working proof of concept. `freq.py` was born and it worked pretty well. A year later [`@securitymapper`](https://twitter.com/securitymapper) had me wrap it in a web interface so he could query it from a SIEM and then the tool took off. It turns out to be a pretty effective technique and gained some popularity and wide use! This is a rewrite of the tool that incorporates some lessons learned and performance enhancements. ## Recent Improvements: - Only one table is required for case sensitve or insensitive lookups. The tables are all case sensitive. You can turn off and on case sensitivity and the .probability lookups will do what is needed to make them case insensitive. - Ignored characters with `--exclude` option. Like `--ignore_case`, the characters are only ignored in the calculations of the probability. They are not ignored in the building of the table. - Speed. Like I said. It was a proof of concept and never really built with any performance in mind. This fixes that. - Accuracy. Some errors in calulations were identified by Pepe Berta (thanks!). This fixes those and several others. If you find others let me know. - Two calculations - I've added a second frequency score that I've calculated differently. It will requires some testing to see if it is more useful than the previous number in detecting random hosts. - Multiple freq tables can be passed and loaded on the CLI then processed in the url. For example: `python3 freq_server.py 9000 files.freq dns.freq` Then query the url with the table name instead of measure like this `http://127.0.0.1:9000/dns.freq/hostname` or `http://127.0.0.1:9000/dns.freq1/hostname` for just measurement 1. ## Version Compatibility: Both `freq.py` and `freq_server.py` will work in either Python2 or Python3, but ship as a python3 script. ## System-level Service Startup: A systemd startup file is provided, although you will likely need to adjust paths to the script and `freqtable2018.freq` file. The provided sample assumes you've cloned this repository to /usr/local/share/freq/. Enable with something like the following, again substituting the appropriate paths: ```console sudo systemctl enable /usr/local/share/freq/systemd/freq.service sudo systemctl start freq.service ``` ## Conntributing If you're interested in contributing to the project, feel free to read through our [Contributing](CONTRIBUTE.md) document. ## To Do: ================================================ FILE: freq.py ================================================ #!/usr/bin/env python3 from __future__ import division import sys import string import re import weakref import json from collections import Counter, defaultdict from pprint import pprint class node(): """ A class to represent a node. Note: Assigning a weight actually adds that value. It doesn't set it to that value. For example node['c'] = 5 increases the value in node by 5 Attributes ---------- parent : node the parent to this node count : int the current count for the node """ def __init__(self,parent): self.parent = parent self._pairs = Counter() self._cachecount = 0 self._dirtycount = False def __getitem__(self,key): if self.parent.ignore_case and (key.islower() or key.isupper()): return self._pairs[key.lower()] + self._pairs[key.upper()] else: return self._pairs[key] def __setitem__(self,key,value): # TODO: should consider using the __addr__ magic method instead # since the described behavior is this instead self._dirtycount = True self._pairs[key] += value @property def count(self): if self._dirtycount: self._cachecount = sum(self._pairs.values()) self._dirtycount = False return self._cachecount class FreqCounter(dict): """ A class used for frequency counting. Attributes ---------- ignore_case : bool TODO: Update ignorechars : str TODO: Update verbose : bool When enabled, print verbose messages to the console. count : int The number of entries in the table Methods ------- toJSON() Returns a JSON representation of the Table as a string fromJSON(jsondata) Imports the JSON representation into the Table tally_str(line, weight=1) TODO: Update probability(line) Returns the probability of a given letter combination save(filename) Writes the table to a frequency file load(filename) Loads the table from a given frequency file printtable() Prints the JSON table to the console """ def __init__(self, *args,**kwargs): self._table = defaultdict(lambda :node(self)) self.ignore_case = False # TODO: consider refactoring to ignore_chars for consistency self.ignorechars = "" self.verbose = "verbose" in kwargs def __getitem__(self,key): return self._table[key] def __iter__(self): return iter(self._table) def __len__(self): return len(self._table) def toJSON(self): """ Returns a string JSON reperesentation of the table. """ serial = [] for key,val in self._table.items(): serial.append( (key, list(val._pairs.items())) ) return json.dumps((self.ignore_case, self.ignorechars, serial)) def fromJSON(self,jsondata): """ Imports the table from a string JSON representation of the table Parameters ---------- jsondata : str A string that represents the JSON Data Returns ------- str the JSON representation of the table """ # TODO: Raise an error if we get something that we didn't # expect. args = json.loads(jsondata) if args: self.ignore_case = args[0] self.ignorechars = args[1] for outerkey,val in args[2]: self._table[outerkey] = node(self) for letter,count in val: self._table[outerkey][letter] = count def tally_str(self,line,weight=1): """ TODO: Update Parameters ---------- line : string TODO: Update weight : int, optional the weight to be assigned to the pair (default = 1) """ allpairs = re.findall(r"..", line) allpairs.extend(re.findall(r"..",line[1:])) for eachpair in allpairs: self[eachpair[0]][eachpair[1]] = weight def probability(self,line): """ Calculates the probability of the word pair Parameters ---------- line : str TODO: Update Returns ------- float TODO: verify; the probability of the given word pair """ allpairs = re.findall(r"..", line) allpairs.extend(re.findall(r"..",line[1:])) if self.verbose: print("All pairs: {0}".format(allpairs)) probs = [] for eachpair in allpairs: pair = [eachpair[0], eachpair[1]] # check if any part of the pair should be ignored and alert # the user this was skipped if not all(x in self.ignorechars for x in pair): probs.append(self._probability(eachpair)) if self.verbose: print ("Probability of {0}: {1}".format(eachpair,probs)) elif self.verbose: print("Pair '{}' was ignored",format(self.ignorechars)) if probs: average_probability = sum(probs) / len(probs) * 100 else: average_probability = 0.0 if self.verbose: print("Average Probability: {0}% \n\n".format(average_probability)) totl1 = 0 totl2 = 0 for eachpair in allpairs: l1 = l2 = 0 pair = [eachpair[0], eachpair[1]] if not all(x in self.ignorechars for x in pair): l1 += self[eachpair[0]].count if self.ignore_case and (eachpair[0].islower() or eachpair[0].isupper()): l1 += self[eachpair[0].swapcase()].count l2 += self[eachpair[0]][eachpair[1]] if self.ignore_case and (eachpair[0].islower() or eachpair[0].isupper()): l2 += self[eachpair[0].swapcase()][eachpair[1]] totl1 += l1 totl2 += l2 if self.verbose: print("Letter1:{0} Letter2:{1} - This pair {2}:{3} {4}:{5}".format( totl1, totl2, eachpair[0], l1, eachpair[1], l2 )) if (totl1 == 0) or (totl2 == 0): total_word_probability = 0.0 else: total_word_probability = totl2/totl1 * 100 if self.verbose: print("Total Word Probability: {0}/{1} = {2}".format(totl2, totl1, total_word_probability)) return round(average_probability,4),round(total_word_probability,4) def _probability(self,twoletters): if self.ignore_case and (self[twoletters[0]].count == 0 and self[twoletters[0].swapcase()].count == 0): return 0.0 if not self.ignore_case and self[twoletters[0]].count == 0: return 0.0 if self.ignore_case and (twoletters[0].islower() or twoletters[0].isupper()): ignored_tot = sum([self[twoletters[0].lower()][eachlet] for eachlet in self.ignorechars]) + sum([self[twoletters[0].upper()][eachlet] for eachlet in self.ignorechars]) let2 = self[twoletters[0].lower()][twoletters[1]] + self[twoletters[0].upper()][twoletters[1]] let1 = self[twoletters[0].lower()].count + self[twoletters[0].upper()].count if let1 - ignored_tot == 0: return 0.0 return let2/(let1-ignored_tot) else: ignored_tot = sum([self[twoletters[0]][eachlet] for eachlet in self.ignorechars]) if self[twoletters[0]].count - ignored_tot == 0: return 0.0 return self[twoletters[0]][twoletters[1]] / (self[twoletters[0]].count - ignored_tot) def save(self,filename): try: file_handle = open(filename, 'wb') file_handle.write(self.toJSON().encode("latin1")) file_handle.flush() file_handle.close() except Exception as e: print("Unable to write freq file :" + str(e)) raise(e) def load(self,filename): try: file_handle = open(filename,"rb") self.fromJSON(file_handle.read().decode("latin1")) file_handle.close() except Exception as e: print("Unable to load freq file :",str(e)) raise(e) @property def count(self): return sum(map(lambda y:y.count, x._table.values())) def printtable(self): pprint(self.toJSON()) if __name__ == "__main__": import argparse import os parser=argparse.ArgumentParser() parser.add_argument( '-m', '--measure', required=False, help='Measure likelihood of a given string', dest='measure' ) parser.add_argument( '-n', '--normal', required=False, help='Update the table based on the following normal string', dest='normal' ) parser.add_argument( '-f', '--normalfile', required=False, help='Update the table based on the contents of the normal file', dest='normalfile' ) parser.add_argument( '-p', '--print', action='store_true', required=False, help='Print a table of the most likely letters in order', dest='printtable' ) parser.add_argument( '-c', '--create', action='store_true', required=False, help='Create a new empty frequency table',dest='create' ) parser.add_argument( '-v', '--verbose', action='store_true', required=False, help='show calculation process', dest='verbose' ) parser.add_argument( '-b', '--bulk', default=None, required=False, help='Measure every line in a file.', dest='bulk' ) # TODO: break these up as well parser.add_argument('-t','--toggle_case_sensitivity',action='store_true',required=False,help='Ignore case in all future frequecy tabulations',dest='toggle_case') parser.add_argument('-s','--case_sensitive',action='store_true',required=False,help='Consider case in calculations. Default ignores case.',dest='case_sensitive') parser.add_argument('-w','--weight',type=int,default = 1, required=False,help='Affects weight of promote, update and update file (default is 1)',dest='weight') parser.add_argument('-e','--exclude',default = "\n\t~`!@#$%^&*()_+-", required=False,help='Provide a list of characters to ignore from the tabulations.',dest='exclude') parser.add_argument('freqtable',help='File storing character frequencies.') args=parser.parse_args() if args.verbose: fc = FreqCounter(verbose=True) else: fc = FreqCounter() if args.create and os.path.exists(args.freqtable): print("Frequency table already exists. " + args.freqtable) sys.exit(1) if not args.create: if not os.path.exists(args.freqtable): print("Frequency Character file not found. - %s " % (args.freqtable)) raise(Exception("File not found.")) fc.load(args.freqtable) if args.printtable: fc.printtable() if args.normal: fc.tally_str(args.normal, args.weight) if args.toggle_case: print("This feature has been depricated. By default all calculations ignore case. Use -s to consider case.") fc.ignore_case = not args.case_sensitive fc.ignorechars = args.exclude if args.verbose: print("Ignoring Case: {0}".format(fc.ignore_case)) if args.verbose: print("Ignoring Characters: {0}".format(fc.ignorechars)) if args.normalfile: with open(args.normalfile,"rb") as filehandle: for eachline in filehandle: fc.tally_str(eachline.decode("latin1")) if args.measure: print(fc.probability(args.measure)) if args.bulk: with open(args.bulk,"rt") as filehandle: for eachline in filehandle: print(fc.probability(eachline),"-",eachline) fc.save(args.freqtable) ================================================ FILE: freq_server.py ================================================ #!/usr/bin/env python3 #freq_server.py by Mark Baggett #Twitter @MarkBaggett #github http://github.com/MarkBaggett/ #This scripts runs a web server to provide a callable API to use frequency tables. # #Start the server passing it a port and a frequecy table. For example: #python freq_server.py 8080 english_lowercase.freq # #Now you can query the API to measure the character frequency of its characters. #wget http://127.0.0.1:8080/?cmd=measure\&tgt=measurethisstring # #You can also mark a string as normal. NOTE: There is a performance impact to updating via the API. Use CLI freq.py to update tables instead. #wget http://127.0.0.1:8080/?cmd=normal\&tgt=UpdateFreqWithTheseChars&weight=10 # #Thanks to @securitymapper for Testing & suggestions from __future__ import print_function from freq import * import six if six.PY2: import BaseHTTPServer import SocketServer import urlparse else: import http.server as BaseHTTPServer import socketserver as SocketServer import urllib.parse as urlparse import threading import re import argparse import os #import resource class freqapi(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): if self.server.verbose: self.server.safe_print("Currently %s threads are active." % (threading.activeCount())) #if self.server.verbose: self.server.safe_print("Memory usage: %s (kb)" % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) self.send_response(200) self.send_header('Content-type','text/plain') self.end_headers() (ignore, ignore, urlpath, urlparams, ignore) = urlparse.urlsplit(self.path) cmdstr = tgtstr = None if self.server.verbose: self.server.safe_print(urlparams) if re.search(legit_urls, urlpath): if self.server.verbose: self.server.safe_print("REST API CALL", urlpath) cmdstr = re.search(cmd_regex, urlpath) tgtstr = re.search(tgtstr_regex, urlpath) if not cmdstr or not tgtstr: help_str = 'API Documentation \nhttp://%s:%s/measure/ \nhttp://%s:%s/normal/ \n' % (self.server.server_address[0], self.server.server_address[1],self.server.server_address[0], self.server.server_address[1],self.server.server_address[0], self.server.server_address[1]) self.wfile.write(help_str.encode("Latin-1")) return params = {} params["cmd"] = cmdstr.group(1) params["tgt"] = tgtstr.group(2) else: if self.server.verbose: self.server.safe_print("STANDARD API CALL", urlpath) cmdstr=re.search(r"cmd=",urlparams) tgtstr = re.search(r"tgt=",urlparams) if not cmdstr or not tgtstr: help_str = 'API Documentation\nhttp://%s:%s/?cmd=measure&tgt= \nhttp://%s:%s/measure/ \nhttp://%s:%s/?cmd=normal&tgt=&weight= \n' % (self.server.server_address[0], self.server.server_address[1],self.server.server_address[0], self.server.server_address[1],self.server.server_address[0], self.server.server_address[1]) self.wfile.write(help_str.encode("LATIN-1")) return params={} try: for prm in urlparams.split("&"): key,value = prm.split("=") params[key]=value except: self.wfile.write('Unable to parse the url. '.encode("LATIN-1")) return if params["cmd"] == "normal": self.server.safe_print("cache cleared") try: self.server.cache_lock.acquire() self.server.cache ={} finally: self.server.cache_lock.release() try: self.server.fc_lock.acquire() weight = int(params.get("weight","1")) self.server.fc.tally_str(params["tgt"], weight=weight) self.server.dirty_fc = True finally: self.server.fc_lock.release() self.wfile.write('Frequency Table updated'.encode("LATIN-1")) elif params["cmd"][:7] == "measure": cache_key = "{0}".format(params["tgt"]) if cache_key in self.server.cache: if self.server.verbose: self.server.safe_print ("Query from cache:", params["tgt"]) measure = self.server.cache.get(cache_key) else: if self.server.verbose: self.server.safe_print ( "Added to cache:", params["tgt"]) measure = self.server.fc.probability(params["tgt"]) try: self.server.cache_lock.acquire() self.server.cache[cache_key]=measure finally: self.server.cache_lock.release() if self.server.verbose>=2: self.server.safe_print ( "Server cache: ", str(self.server.cache)) if params["cmd"].endswith("1"): measure = measure[0] elif params["cmd"].endswith("2"): measure = measure[1] self.wfile.write(str(measure).encode("LATIN-1")) elif any([params["cmd"].startswith(x) for x in freqtables]): table = params['cmd'] if table.endswith("1") or table.endswith("2"): table = table[:-1] cache_key = "{0}:{1}".format(table, params["tgt"]) if self.server.verbose: self.server.safe_print("Call to table ", params['cmd']) if cache_key in self.server.cache: if self.server.verbose: self.server.safe_print ("Query from cache:",cache_key, params["tgt"]) measure = self.server.cache.get(cache_key) else: if self.server.verbose: self.server.safe_print ( "Added to cache:",cache_key, params["tgt"]) measure = self.server.fcs[table].probability(params["tgt"]) try: self.server.cache_lock.acquire() self.server.cache[cache_key]=measure finally: self.server.cache_lock.release() if self.server.verbose>=2: self.server.safe_print ( "Server cache: ", str(self.server.cache)) if params["cmd"].endswith("1"): measure = measure[0] elif params["cmd"].endswith("2"): measure = measure[1] self.wfile.write(str(measure).encode("LATIN-1")) return else: print("Invalid command {} or target {}".format(params["cmd"], params["tgt"])) def log_message(self, format, *args): return class ThreadedFreqServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): def __init__(self, *args,**kwargs): self.fcs = {} self.fc = FreqCounter() self.cache = {} self.cache_lock = threading.Lock() self.screen_lock = threading.Lock() self.verbose = False self.fc_lock = threading.Lock() self.dirty_fc = False self.exitthread = threading.Event() self.exitthread.clear() BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs) def safe_print(self,*args,**kwargs): try: self.screen_lock.acquire() print(*args,**kwargs) finally: self.screen_lock.release() def save_freqtable(self,save_path,save_interval): if self.verbose: self.safe_print ( "Save interval reached.") if self.dirty_fc: if self.verbose: self.safe_print ("Frequency counter changed. Saving to disk.",save_path) try: self.fc_lock.acquire() self.fc.save(save_path) self.dirty_fc = False finally: self.fc_lock.release() else: if self.verbose: self.safe_print ("Frequency counter not changed. Not Saving to disk.") #Reschedule yourself if not self.exitthread.isSet(): self.timer = threading.Timer(60*save_interval, self.save_freqtable, args = (save_path,save_interval)) self.timer.start() if __name__=="__main__": parser=argparse.ArgumentParser() parser.add_argument('-ip','--address',required=False,help='IP Address for the server to listen on. Default is 127.0.0.1',default='127.0.0.1') parser.add_argument('-s','--save_interval',type=float,required=False,help='Number of minutes to wait before trying to save frequency table updates. Default is 10 minutes. Set to 0 to never save.',default=10) parser.add_argument('port',type=int,help='You must provide a TCP Port to bind to') parser.add_argument('freq_table',nargs="+", help='You must provide the frequency table name (optionally including the path)') parser.add_argument('-v','--verbose',action='count',default=0,required=False,help='Print verbose output to the server screen. -vv is more verbose.') #args = parser.parse_args("-s 1 -vv 8081 english_lowercase.freq".split()) args = parser.parse_args() #split paths and filenames on frequency tables freqtables = list(map(lambda x:x[1], map(os.path.split, args.freq_table))) #Setup the server. server = ThreadedFreqServer((args.address, args.port), freqapi) #Load Each of the Frequency Table for eachtable in args.freq_table: path,tablename = os.path.split(eachtable) server.fcs[tablename] = FreqCounter() try: server.fcs[tablename].load(eachtable) except: err = "********** Unable to load Frequency table {0}. ************".format(eachtable) raise(Exception(err)) #add psuedo table names for the two measurements tables = list(freqtables) tables += [x+"1" for x in freqtables] tables += [x+"2" for x in freqtables] #build regex for parsing urls based on table names legit_urls = r"[\/](measure|measure1|measure2|normal|{0})[\/].*?".format( "|".join(tables)) cmd_regex = r"[\/](measure|measure1|measure2|normal|{0})[\/].*$".format( "|".join(tables)) tgtstr_regex = r"[\/](measure|measure1|measure2|normal|{0})[\/](.*)$".format( "|".join(tables)) #setup default freq_table server.fc = server.fcs[freqtables[0]] server.verbose = args.verbose #Schedule the first save interval unless save_interval was set to 0. if args.save_interval: server.timer = threading.Timer(60 *args.save_interval, server.save_freqtable, args = (args.freq_table[0], args.save_interval)) server.timer.start() #start the server print('Server is Ready. http://%s:%s//' % (args.address, args.port)) print("Commands include {}".format(cmd_regex)) print('[?] - Remember: If you are going to call the api with wget, curl or something else from the bash prompt you need to escape the & with \& \n\n') while True: try: server.handle_request() except KeyboardInterrupt: break server.safe_print("Control-C hit: Exiting server...") server.safe_print("Web API Disabled...") if args.save_interval and server.dirty_fc: server.safe_print("The Frequency counter has changed since the last save interval. Saving final update.") server.exitthread.set() server.timer.cancel() try: server.fc_lock.acquire() server.fc.save(args.freq_table[0]) server.fc_lock.release() except: server.safe_print("[!] An error occured during the final save.") elif args.save_interval: server.safe_print( "No Changes made since last file save. Canceling scheduled save...") server.timer.cancel() server.safe_print("Server has stopped.") ================================================ FILE: freq_sort.py ================================================ #!/usr/bin/env python3 from freq import * import argparse import signal import sys parser = argparse.ArgumentParser() parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin) parser.add_argument('-f','--freq_table',default = "freqtable2018.freq", required=False,help='Specify the frequency table to use. Default is freqtable2018.freq',dest='freqtable') parser.add_argument("-v", "--verbose", action="count", help = "Show details of how sort order is determined.") parser.add_argument('-s','--case_sensitive',action='store_true',required=False,help='Consider case in calculations. Default ignores case.',dest='case_sensitive') parser.add_argument('-e','--exclude',default = "\n\t~`!@#$%^&*()_+-;", required=False,help='Specify a full list of characters to ignore from the tabulations.',dest='exclude') parser.add_argument('-a','--add_exclude',default = "", required=False,help='Provide a list of characters to add to default ignored characters.',dest='additional') parser.add_argument('-n','--numeric',action='store_true',required=False,help='Convert input to number for sorting.',dest='numeric') parser.add_argument('-c','--cut',nargs=2,help='Specify a delimer and field value to cut a substring for the target of your search. Example -c "/" 3 will use the value between the 3rd and 4th "/" for sorting.',dest='cut') parser.add_argument('-S','--substring',nargs=2,help='Slice out a substring given the starting and stoping position. If cut is used this is performed after cut. Example -S 10,13 would only use the string comprised of characters 10,11 and 12 to determine the sort order.',dest='slice') parser.add_argument('-r','--reverse',action='store_true',required=False,help='Reverses the sort order with highest frequency values last',dest='reverse') parser.add_argument('-N','--no_length',action='store_true',required=False,help='Do not consider length of string when determining sort order',dest='length') parser.add_argument('-l','--line',action='store_true',required=False,help='Include the line number where the string was located in the output.',dest='line') args = parser.parse_args() def score(line): if args.cut: try: line = line.split(args.cut[0])[int(args.cut[1])] except IndexError: line = "" except: raise(Exception("Unable to process -c cut options.")) if args.verbose: print("Now sorting on {}".format(line)) if args.slice: try: line = line[int(args.slice[0]):int(args.slice[1])] except: raise(Exception("Unable to process -S substring options.")) if args.verbose: print("Now sorting on {}".format(line)) if args.numeric: try: return float(line) except: raise(Exception("The value {} can not be treated as numeric. Try without -n.".format(line))) line_len = len(line) if not args.length else 1 return line_len * sum(freq.probability(line))/2 def signal_handler(sig, frame): sys.exit(0) signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGPIPE,signal.SIG_DFL) freq = FreqCounter() freq.load(args.freqtable) if args.additional: args.exclude += args.additional freq.ignorechars = args.exclude freq.ignore_case = not args.case_sensitive if args.verbose and args.verbose > 1: freq.verbose = True filecontent = args.infile.readlines() for eachline in sorted(filecontent, key = score, reverse=not args.reverse): if args.verbose: print(score(eachline), freq.probability(eachline), end=" ") if args.line: print("Found on line {} :".format(filecontent.index(eachline)), end=" ") print(eachline,end="") ================================================ FILE: freqtable2018.freq ================================================ [true, "\n\t~`!@#$%^&*()_+-", [["\f", [["f", 2]]], [" ", [[" ", 312527], ["$", 12], ["(", 1520], [",", 6], ["0", 2], ["4", 210], ["8", 75], ["<", 58], ["D", 5449], ["H", 14898], ["L", 6849], ["P", 10276], ["T", 23773], ["X", 290], ["`", 1958], ["d", 74474], ["h", 195782], ["l", 64742], ["p", 65902], ["t", 408490], ["x", 22], ["|", 38], ["#", 6], ["'", 3062], ["+", 2], ["/", 12], ["3", 300], ["7", 134], [";", 8], ["?", 8], ["C", 9334], ["G", 5688], ["K", 2484], ["O", 4266], ["S", 13139], ["W", 9355], ["[", 408], ["_", 220], ["c", 90632], ["g", 44086], ["k", 13940], ["o", 161371], ["s", 182472], ["w", 187994], ["{", 8], ["\"", 22346], ["&", 42], ["*", 112], [".", 2358], ["2", 691], ["6", 180], [":", 14], [">", 2], ["B", 12213], ["F", 8428], ["J", 5957], ["N", 7370], ["R", 5046], ["V", 3389], ["Z", 250], ["b", 109654], ["f", 95818], ["j", 6186], ["n", 56010], ["r", 54486], ["v", 15242], ["z", 238], ["~", 2], ["%", 2], [")", 2], ["-", 550], ["1", 1613], ["5", 132], ["9", 74], ["A", 16635], ["E", 4590], ["I", 45393], ["M", 17353], ["Q", 356], ["U", 753], ["Y", 2574], ["a", 293192], ["e", 47200], ["i", 125201], ["m", 99016], ["q", 5914], ["u", 27850], ["y", 29288]]], ["$", [[" ", 2], ["3", 2], ["2", 6], ["4", 10]]], ["(", [[" ", 2], ["\"", 34], ["$", 12], ["'", 24], ["*", 8], ["1", 28], ["3", 24], ["2", 30], ["5", 2], ["A", 54], ["C", 12], ["B", 32], ["E", 12], ["D", 16], ["G", 6], ["F", 40], ["I", 120], ["H", 48], ["K", 10], ["J", 2], ["M", 48], ["L", 14], ["O", 20], ["N", 26], ["P", 26], ["S", 46], ["U", 8], ["T", 124], ["W", 38], ["V", 2], ["Y", 4], ["_", 14], ["a", 306], ["`", 2], ["c", 22], ["b", 50], ["e", 24], ["d", 18], ["g", 10], ["f", 80], ["i", 122], ["h", 102], ["k", 2], ["j", 2], ["m", 20], ["l", 20], ["o", 86], ["n", 38], ["p", 16], ["s", 106], ["r", 6], ["u", 6], ["t", 240], ["w", 212], ["v", 2], ["y", 6], ["~", 8]]], [",", [["!", 2], [" ", 200706], ["\"", 10148], ["'", 1656], [")", 4], ["*", 18], ["-", 780], [",", 10], ["1", 40], ["0", 263], ["3", 6], ["2", 42], ["5", 44], ["4", 28], ["7", 4], ["6", 20], ["9", 12], ["8", 18], [":", 4], ["A", 4], ["I", 42], ["J", 2], ["M", 2], ["T", 2], ["[", 2], ["a", 328], ["c", 8], ["b", 76], ["e", 6], ["d", 4], ["g", 10], ["f", 60], ["i", 36], ["h", 36], ["k", 6], ["m", 10], ["l", 6], ["o", 22], ["n", 8], ["q", 2], ["p", 2], ["s", 64], ["r", 8], ["t", 84], ["w", 70]]], ["0", [[" ", 512], ["%", 16], ["'", 14], [")", 20], ["-", 20], [",", 155], [".", 70], ["1", 38], ["0", 714], ["3", 17], ["2", 32], ["5", 34], ["4", 13], ["7", 30], ["6", 21], ["9", 34], ["8", 20], [";", 8], [":", 22], ["@", 20], ["I", 6], ["]", 46], ["m", 2], ["s", 6], ["t", 74], ["x", 10], ["}", 18]]], ["4", [[" ", 70], ["'", 4], [")", 2], ["-", 12], [",", 70], [".", 46], ["1", 24], ["0", 82], ["3", 24], ["2", 24], ["5", 34], ["4", 16], ["7", 28], ["6", 16], ["9", 24], ["8", 34], [";", 6], [":", 44], ["@", 8], ["T", 2], ["]", 60], ["t", 64], ["}", 18], ["|", 32]]], ["8", [[" ", 64], ["'", 6], ["-", 12], [",", 68], [".", 28], ["1", 192], ["0", 155], ["3", 132], ["2", 89], ["5", 26], ["4", 56], ["7", 26], ["6", 74], ["9", 37], ["8", 12], [";", 12], [":", 14], ["?", 2], ["@", 10], ["]", 54], ["m", 2], ["t", 56], ["}", 18], ["|", 44]]], ["<", [["A", 64], ["C", 132], ["B", 10], ["E", 18], ["D", 14], ["G", 4], ["F", 20], ["I", 14], ["H", 94], ["K", 2], ["M", 14], ["L", 8], ["O", 14], ["N", 2], ["P", 14], ["S", 14], ["R", 10], ["T", 224], ["W", 24], ["Y", 2], ["m", 2], ["s", 2]]], ["@", [[" ", 102], ["c", 8], ["e", 14], [",", 8], [".", 8], ["u", 6], ["v", 16]]], ["D", [["!", 4], [" ", 358], ["'", 72], ["*", 16], ["-", 64], [",", 14], [".", 66], [";", 2], ["?", 2], ["A", 93], ["C", 2], ["E", 240], ["D", 2], ["G", 10], ["F", 8], ["I", 220], ["M", 2], ["L", 2], ["O", 89], ["N", 14], ["P", 2], ["S", 28], ["R", 70], ["U", 24], ["V", 2], ["Y", 12], ["a", 1027], ["e", 2124], ["i", 779], ["j", 6], ["m", 148], ["o", 2366], ["n", 8], ["r", 642], ["u", 914], ["w", 4], ["y", 20]]], ["H", [[" ", 112], ["'", 14], [",", 8], [".", 210], ["1", 126], ["3", 42], ["2", 54], ["5", 12], ["4", 12], ["7", 12], ["6", 12], ["9", 12], ["8", 12], ["?", 2], ["A", 410], ["E", 722], ["F", 4], ["I", 298], ["M", 4], ["O", 260], ["N", 2], ["Q", 4], ["S", 6], ["R", 20], ["U", 26], ["T", 60], ["Y", 20], ["a", 2890], ["e", 16114], ["i", 2886], ["h", 2], ["m", 2], ["o", 2880], ["s", 4], ["u", 596], ["v", 2], ["y", 24]]], ["L", [["!", 2], [" ", 102], ["'", 40], [")", 2], ["-", 4], [",", 10], [".", 40], ["1", 6], ["2", 8], ["5", 2], ["4", 2], ["6", 2], ["8", 2], [":", 8], ["A", 120], ["C", 14], ["E", 261], ["D", 38], ["G", 14], ["F", 26], ["I", 210], ["H", 4], ["K", 46], ["J", 2], ["M", 6], ["L", 134], ["O", 98], ["N", 2], ["P", 4], ["S", 36], ["R", 6], ["U", 84], ["T", 12], ["W", 2], ["Y", 32], ["a", 2534], ["e", 1957], ["i", 1482], ["h", 70], ["l", 2], ["o", 2216], ["u", 614], ["w", 2], ["y", 30]]], ["P", [["!", 2], [" ", 30], ["-", 4], [".", 72], ["A", 198], ["E", 228], ["G", 8], ["I", 66], ["H", 24], ["K", 2], ["M", 8], ["L", 90], ["O", 110], ["P", 26], ["S", 18], ["R", 198], ["U", 54], ["T", 202], ["Y", 10], ["a", 2387], ["e", 1866], ["f", 50], ["i", 2690], ["h", 472], ["l", 486], ["o", 1094], ["s", 84], ["r", 4898], ["u", 314], ["t", 12], ["w", 2], ["y", 38]]], ["T", [["!", 20], [" ", 496], ["'", 18], ["*", 34], ["-", 20], [",", 66], [".", 132], [":", 6], ["A", 150], ["C", 14], ["B", 2], ["E", 2568], ["F", 2], ["I", 236], ["H", 1216], ["M", 20], ["L", 24], ["O", 330], ["N", 14], ["P", 14], ["S", 62], ["R", 71], ["U", 70], ["T", 106], ["W", 110], ["Y", 144], ["Z", 2], ["a", 643], ["e", 802], ["i", 1134], ["h", 41758], ["o", 3328], ["s", 100], ["r", 532], ["u", 500], ["w", 517], ["v", 8], ["y", 54], ["z", 4]]], ["X", [["A", 2], [" ", 22], ["C", 6], ["E", 2], ["'", 2], ["I", 444], ["-", 2], [",", 4], [".", 84], ["1", 2], ["P", 6], ["2", 2], ["u", 30], ["T", 78], ["V", 302], ["X", 266], [":", 6], ["e", 4]]], ["`", [[" ", 4], ["\"", 2], ["'", 2], ["2", 2], ["A", 122], ["C", 26], ["B", 74], ["E", 14], ["D", 38], ["G", 30], ["F", 28], ["I", 270], ["H", 66], ["K", 4], ["J", 30], ["M", 66], ["L", 44], ["O", 26], ["N", 52], ["P", 34], ["S", 80], ["R", 14], ["U", 6], ["T", 166], ["W", 92], ["V", 4], ["Y", 66], ["_", 2], ["a", 62], ["c", 32], ["b", 40], ["e", 40], ["d", 24], ["g", 28], ["f", 38], ["i", 24], ["h", 26], ["k", 6], ["j", 2], ["m", 40], ["l", 28], ["o", 24], ["n", 14], ["q", 2], ["p", 40], ["s", 34], ["r", 18], ["u", 10], ["t", 98], ["w", 22], ["v", 2], ["y", 8]]], ["d", [["!", 1346], [" ", 316392], ["\"", 78], ["'", 892], [")", 158], ["-", 2110], [",", 27454], [".", 15448], ["1", 6], [";", 2238], [":", 1318], ["?", 904], [">", 32], ["]", 6], ["_", 10], ["a", 15612], ["`", 12], ["c", 64], ["b", 98], ["e", 66856], ["d", 5952], ["g", 2672], ["f", 682], ["i", 36856], ["h", 178], ["k", 152], ["j", 316], ["m", 1162], ["l", 4894], ["o", 27386], ["n", 2680], ["q", 32], ["p", 44], ["s", 12352], ["r", 13004], ["u", 5376], ["t", 176], ["w", 382], ["v", 1300], ["y", 5438], ["z", 4], ["}", 6]]], ["h", [["!", 1480], [" ", 66490], ["\"", 16], ["'", 580], [")", 46], ["-", 674], [",", 7634], [".", 3060], [";", 500], [":", 124], ["?", 354], [">", 8], ["_", 8], ["a", 130321], ["`", 2], ["c", 78], ["b", 454], ["e", 366316], ["d", 180], ["g", 2], ["f", 464], ["i", 118000], ["h", 16], ["k", 98], ["m", 1012], ["l", 810], ["o", 56794], ["n", 878], ["q", 34], ["p", 20], ["s", 1392], ["r", 8693], ["u", 9628], ["t", 23686], ["w", 410], ["v", 4], ["y", 4342], ["z", 2]]], ["l", [["!", 688], [" ", 55493], ["\"", 28], ["'", 776], [")", 58], ["*", 8], ["-", 1168], [",", 9058], ["/", 2], [".", 4175], ["1", 2], ["2", 4], [";", 588], [":", 138], ["?", 512], [">", 18], ["@", 2], ["]", 2], ["_", 14], ["a", 40424], ["c", 880], ["b", 428], ["e", 90647], ["d", 35897], ["g", 498], ["f", 11866], ["i", 53960], ["h", 30], ["k", 3952], ["j", 880], ["m", 2350], ["l", 72010], ["o", 43088], ["n", 488], ["q", 6], ["p", 1936], ["s", 9240], ["r", 1482], ["u", 8878], ["t", 7890], ["w", 1710], ["v", 3288], ["y", 43772], ["x", 2], ["z", 52]]], ["p", [["!", 222], [" ", 12684], ["\"", 12], ["'", 274], [")", 8], ["*", 16], ["-", 458], [",", 2678], [".", 1598], [";", 206], [":", 32], ["?", 102], [">", 2], ["_", 2], ["a", 24384], ["c", 110], ["b", 74], ["e", 40018], ["d", 12], ["g", 26], ["f", 100], ["i", 12578], ["h", 3890], ["k", 248], ["m", 220], ["l", 19938], ["o", 24960], ["n", 82], ["p", 12676], ["s", 4980], ["r", 27372], ["u", 7468], ["t", 8624], ["w", 150], ["y", 1538], ["z", 4]]], ["t", [["!", 1698], [" ", 244288], ["\"", 74], ["'", 4144], [")", 206], ["*", 10], ["-", 2634], [",", 24442], ["/", 22], [".", 15012], ["9", 30], [";", 1952], [":", 386], ["?", 2014], [">", 34], ["@", 16], ["I", 4], ["N", 2], ["]", 6], ["_", 20], ["a", 36864], ["c", 4804], ["b", 164], ["e", 93708], ["d", 32], ["g", 50], ["f", 1186], ["i", 67393], ["h", 380618], ["k", 30], ["j", 2], ["m", 1109], ["l", 15192], ["o", 120320], ["n", 980], ["p", 168], ["s", 20376], ["r", 31046], ["u", 18070], ["t", 25046], ["w", 8348], ["v", 6], ["y", 14950], ["x", 22], ["z", 596]]], ["x", [["!", 16], [" ", 1654], ["'", 108], [")", 6], ["-", 174], [",", 480], ["/", 2], [".", 262], ["1", 10], [";", 40], [":", 6], ["?", 20], ["_", 4], ["a", 1314], ["c", 2462], ["b", 4], ["e", 1456], ["g", 2], ["f", 26], ["i", 1676], ["h", 354], ["l", 20], ["o", 82], ["q", 56], ["p", 3828], ["s", 6], ["u", 144], ["t", 3514], ["w", 4], ["y", 88], ["x", 30]]], ["|", [[" ", 30], ["C", 294]]], ["#", [["1", 6], [" ", 2]]], ["'", [["!", 22], [" ", 5218], ["\"", 130], ["'", 52], [")", 8], ["-", 136], [",", 274], [".", 194], ["9", 24], ["8", 10], [";", 12], [":", 4], ["?", 40], ["A", 506], ["C", 94], ["B", 292], ["E", 88], ["D", 124], ["G", 154], ["F", 90], ["I", 826], ["H", 360], ["K", 12], ["J", 52], ["M", 174], ["L", 102], ["O", 202], ["N", 222], ["Q", 12], ["P", 86], ["S", 328], ["R", 24], ["U", 38], ["T", 922], ["W", 482], ["V", 22], ["Y", 356], ["a", 288], ["c", 614], ["b", 42], ["e", 614], ["d", 2832], ["g", 48], ["f", 28], ["i", 98], ["h", 36], ["k", 6], ["m", 1148], ["l", 1792], ["o", 90], ["n", 44], ["q", 2], ["p", 40], ["s", 16835], ["r", 660], ["u", 62], ["t", 7172], ["w", 60], ["v", 880], ["y", 66], ["}", 2]]], ["+", [[";", 2], ["B", 2], ["-", 4]]], ["/", [[" ", 26], ["\"", 2], ["e", 20], ["I", 14], ["h", 6], ["1", 2], ["s", 2], ["2", 4], ["5", 4], ["4", 2], ["6", 2]]], ["3", [["!", 2], [" ", 76], [")", 18], ["*", 8], ["-", 6], [",", 98], ["/", 2], [".", 66], ["1", 54], ["0", 158], ["3", 44], ["2", 60], ["5", 42], ["4", 18], ["7", 38], ["6", 24], ["9", 26], ["8", 20], [";", 10], [":", 48], ["?", 2], ["@", 4], ["]", 60], ["d", 6], ["i", 4], ["h", 2], ["r", 50], ["t", 26], ["v", 2], ["}", 18], ["|", 38]]], ["7", [["!", 2], [" ", 64], ["'", 10], ["-", 8], [",", 68], ["/", 4], [".", 46], ["1", 21], ["0", 36], ["3", 12], ["2", 35], ["5", 16], ["4", 14], ["7", 32], ["6", 26], ["9", 40], ["8", 34], [";", 10], [":", 28], ["@", 18], ["]", 48], ["h", 2], ["m", 4], ["t", 34], ["}", 18], ["|", 26]]], [";", [[" ", 14368], ["\"", 42], ["'", 54], ["h", 2], ["*", 2], ["-", 146], [",", 2], ["[", 4]]], ["?", [[" ", 5000], ["\"", 7386], ["'", 680], [")", 14], ["-", 90], [",", 2], [".", 118], ["[", 2], ["?", 2], [">", 2]]], ["C", [[" ", 50], ["\"", 14], ["'", 12], ["*", 2], ["-", 4], [",", 6], ["/", 2], [".", 24], ["A", 126], ["C", 22], ["E", 112], ["D", 20], ["I", 76], ["H", 3260], ["K", 60], ["L", 26], ["O", 164], ["P", 6], ["S", 8], ["R", 38], ["U", 26], ["T", 117], ["Y", 16], ["a", 2763], ["e", 294], ["i", 277], ["h", 2428], ["l", 446], ["o", 4926], ["s", 4], ["r", 556], ["u", 212], ["y", 42], ["z", 24]]], ["G", [["!", 2], [" ", 132], ["\"", 8], ["'", 8], ["-", 56], [",", 22], [".", 10], [";", 2], [":", 2], ["?", 4], ["A", 72], ["E", 134], ["G", 10], ["F", 2], ["I", 34], ["H", 70], ["L", 16], ["O", 60], ["N", 14], ["S", 10], ["R", 64], ["U", 92], ["T", 2], ["Y", 2], ["Z", 2], ["a", 744], ["e", 958], ["d", 2], ["i", 460], ["h", 266], ["l", 212], ["o", 2628], ["n", 6], ["r", 1160], ["u", 880], ["w", 2], ["y", 2]]], ["K", [[" ", 28], ["'", 2], [",", 6], [".", 8], ["?", 2], ["A", 4], ["E", 64], ["F", 2], ["I", 44], ["H", 2], ["K", 4], ["L", 12], ["O", 2], ["N", 4], ["S", 12], ["R", 6], ["U", 2], ["W", 4], ["Y", 2], ["a", 442], ["e", 504], ["i", 860], ["h", 122], ["l", 40], ["o", 290], ["n", 96], ["r", 96], ["u", 782], ["y", 10]]], ["O", [["!", 6], [" ", 466], ["\"", 2], ["'", 106], ["-", 4], [",", 12], [".", 38], [":", 2], ["?", 2], ["A", 6], ["C", 47], ["B", 32], ["E", 13], ["D", 52], ["G", 52], ["F", 288], ["I", 18], ["H", 28], ["K", 222], ["J", 50], ["M", 160], ["L", 98], ["O", 78], ["N", 489], ["P", 30], ["S", 64], ["R", 346], ["U", 338], ["T", 104], ["W", 64], ["V", 39], ["Y", 8], ["Z", 2], ["a", 2], ["c", 234], ["b", 128], ["e", 2], ["d", 26], ["g", 14], ["f", 1458], ["i", 6], ["h", 1000], ["k", 2], ["m", 60], ["l", 240], ["o", 44], ["n", 3744], ["p", 86], ["s", 22], ["r", 798], ["u", 554], ["t", 162], ["w", 32], ["v", 74], ["y", 2], ["x", 6], ["z", 68]]], ["S", [["!", 8], [" ", 616], ["'", 12], ["*", 6], ["-", 20], [",", 40], [".", 122], [";", 2], [":", 12], ["?", 2], ["A", 56], ["C", 58], ["E", 296], ["D", 2], ["G", 4], ["F", 4], ["I", 91], ["H", 76], ["K", 8], ["M", 14], ["L", 10], ["O", 98], ["N", 2], ["Q", 4], ["P", 30], ["S", 104], ["R", 2], ["U", 42], ["T", 322], ["W", 4], ["Y", 2], ["a", 2150], ["c", 1208], ["e", 1405], ["i", 968], ["h", 5152], ["k", 34], ["m", 374], ["l", 166], ["o", 4132], ["n", 120], ["q", 44], ["p", 776], ["s", 2], ["u", 1246], ["t", 1564], ["w", 144], ["v", 8], ["y", 126], ["z", 18]]], ["W", [["!", 2], [" ", 58], [")", 2], [",", 10], [".", 28], ["A", 136], ["E", 96], ["D", 4], ["G", 2], ["I", 90], ["H", 128], ["L", 4], ["O", 76], ["N", 12], ["S", 2], ["R", 8], ["Y", 4], ["a", 1096], ["e", 4362], ["i", 2096], ["h", 10098], ["o", 1611], ["r", 58], ["u", 18]]], ["[", [["*", 2], ["1", 112], ["3", 56], ["2", 112], ["5", 30], ["4", 40], ["7", 4], ["6", 34], ["9", 4], ["8", 2], ["A", 12], ["C", 2], ["B", 6], ["E", 24], ["D", 4], ["G", 14], ["F", 2], ["I", 22], ["H", 30], ["J", 34], ["M", 28], ["L", 16], ["N", 4], ["P", 42], ["S", 6], ["R", 36], ["T", 18], ["W", 4], ["a", 2], ["b", 4], ["d", 2], ["g", 2], ["f", 14], ["m", 2], ["l", 4], ["o", 4], ["p", 6], ["s", 4], ["t", 50]]], ["_", [[" ", 100], ["'", 2], ["-", 12], [",", 38], [".", 28], [";", 4], ["A", 14], ["D", 2], ["I", 30], ["H", 4], ["M", 4], ["L", 2], ["O", 2], ["N", 2], ["T", 12], ["_", 736], ["^", 6], ["a", 14], ["c", 12], ["b", 4], ["e", 6], ["d", 6], ["f", 14], ["i", 4], ["h", 2], ["m", 8], ["l", 6], ["o", 2], ["n", 14], ["p", 4], ["s", 10], ["r", 2], ["u", 4], ["t", 10], ["w", 8], ["v", 4], ["y", 4], ["x", 4]]], ["c", [["!", 38], [" ", 2940], ["\"", 6], ["'", 62], ["-", 122], [",", 498], [".", 480], [";", 56], [":", 18], ["?", 22], ["C", 8], ["G", 8], ["F", 2], ["L", 230], ["Q", 2], ["P", 2], ["S", 2], ["a", 38996], ["c", 5012], ["e", 54872], ["d", 38], ["i", 13186], ["h", 55038], ["k", 20111], ["m", 4], ["l", 12408], ["o", 57624], ["n", 26], ["q", 496], ["p", 66], ["s", 944], ["r", 13732], ["u", 9748], ["t", 19868], ["w", 8], ["v", 6], ["y", 1692], ["z", 12]]], ["g", [["!", 572], [" ", 77496], ["\"", 32], ["'", 490], [")", 44], ["-", 1388], [",", 8820], [".", 5284], [";", 654], [":", 276], ["?", 530], [">", 4], ["a", 16556], ["c", 8], ["b", 10], ["e", 31120], ["d", 134], ["g", 3662], ["f", 14], ["i", 11514], ["h", 36708], ["m", 368], ["l", 8714], ["o", 16464], ["n", 4300], ["p", 22], ["s", 6714], ["r", 16774], ["u", 6849], ["t", 1104], ["w", 42], ["y", 516], ["z", 14], ["}", 8]]], ["k", [["!", 306], [" ", 20132], ["\"", 14], ["'", 392], [")", 32], ["-", 554], [",", 4148], [".", 2414], ["1", 2], [";", 294], [":", 60], ["?", 214], [">", 10], ["@", 10], ["a", 870], ["c", 66], ["b", 38], ["e", 34087], ["d", 24], ["g", 58], ["f", 344], ["i", 13220], ["h", 948], ["k", 244], ["j", 22], ["m", 100], ["l", 2880], ["o", 816], ["n", 11134], ["q", 2], ["p", 12], ["s", 4228], ["r", 68], ["u", 68], ["t", 20], ["w", 314], ["v", 10], ["y", 768], ["z", 2]]], ["o", [["!", 648], [" ", 114177], ["\"", 18], ["'", 1162], [")", 38], ["-", 958], [",", 5210], [".", 2232], [";", 354], [":", 58], ["?", 516], ["K", 2], ["J", 2], ["]", 4], ["_", 6], ["a", 7834], ["`", 2], ["c", 9710], ["b", 5854], ["e", 2996], ["d", 16602], ["g", 5294], ["f", 99287], ["i", 10524], ["h", 872], ["k", 14852], ["j", 986], ["m", 51326], ["l", 30027], ["o", 36626], ["n", 131194], ["q", 172], ["p", 16136], ["s", 26802], ["r", 99219], ["u", 128095], ["t", 47116], ["w", 48246], ["v", 20522], ["y", 3366], ["x", 840], ["z", 456], ["}", 2]]], ["s", [["!", 2144], [" ", 245069], ["\"", 154], ["'", 1554], [")", 266], ["*", 14], ["-", 1948], [",", 37726], [".", 19990], ["1", 4], [";", 3000], [":", 928], ["=", 2], ["?", 1424], [">", 50], ["[", 6], ["]", 38], ["_", 24], ["a", 37342], ["c", 11410], ["b", 1092], ["e", 89922], ["d", 372], ["g", 288], ["f", 1206], ["i", 41018], ["h", 48184], ["k", 7002], ["j", 20], ["m", 5638], ["l", 7892], ["o", 41490], ["n", 2836], ["q", 1070], ["p", 17022], ["s", 38918], ["r", 118], ["u", 22362], ["t", 98283], ["w", 5082], ["v", 104], ["y", 2112], ["z", 8]]], ["w", [["!", 302], [" ", 25552], ["\"", 32], ["'", 332], [")", 38], ["-", 630], [",", 4620], ["/", 2], [".", 2130], [";", 296], [":", 56], ["?", 312], [">", 6], ["_", 4], ["a", 69912], ["c", 62], ["b", 88], ["e", 43746], ["d", 980], ["g", 230], ["f", 300], ["i", 50742], ["h", 55558], ["k", 232], ["j", 2], ["m", 12], ["l", 1768], ["o", 28157], ["n", 11280], ["p", 14], ["s", 3452], ["r", 3078], ["u", 116], ["t", 106], ["w", 8], ["y", 240], ["z", 2]]], ["{", [["`", 2], ["c", 2], ["E", 2], ["G", 2], ["s", 6], ["o", 4], ["1", 224], ["3", 226], ["2", 230], ["5", 24], ["4", 34], ["7", 22], ["6", 22], ["9", 22], ["8", 24], ["t", 8]]], ["\"", [[" ", 19496], ["\"", 12], ["'", 120], [")", 34], ["*", 70], ["-", 198], [",", 42], [".", 98], ["1", 4], ["3", 2], ["2", 4], ["5", 4], ["4", 4], ["6", 2], ["8", 6], [";", 74], [":", 2], ["?", 4], ["A", 4542], ["C", 1250], ["B", 2388], ["E", 472], ["D", 1474], ["G", 1096], ["F", 924], ["I", 8984], ["H", 2746], ["K", 138], ["J", 270], ["M", 1850], ["L", 912], ["O", 1848], ["N", 2630], ["Q", 110], ["P", 880], ["S", 1906], ["R", 350], ["U", 236], ["T", 5524], ["W", 6722], ["V", 340], ["Y", 4228], ["X", 4], ["[", 14], ["Z", 6], ["]", 8], ["_", 20], ["a", 732], ["`", 158], ["c", 118], ["b", 452], ["e", 46], ["d", 138], ["g", 54], ["f", 182], ["i", 408], ["h", 256], ["k", 10], ["j", 14], ["m", 148], ["l", 118], ["o", 112], ["n", 94], ["q", 4], ["p", 130], ["s", 230], ["r", 36], ["u", 32], ["t", 1014], ["w", 398], ["v", 22], ["y", 272]]], ["&", [["h", 2], ["c", 8], [" ", 26]]], ["*", [[" ", 206], ["\"", 146], [")", 6], ["*", 636], [",", 12], [".", 4], [":", 8], [">", 2], ["A", 16], ["C", 4], ["B", 16], ["E", 20], ["D", 8], ["G", 2], ["F", 12], ["I", 6], ["H", 4], ["K", 4], ["L", 4], ["O", 6], ["N", 2], ["P", 2], ["S", 16], ["T", 92], ["W", 18], ["V", 14], ["Y", 2], ["[", 36], ["]", 54], ["n", 6]]], [".", [["!", 36], [" ", 88376], ["\"", 12990], ["'", 1624], [")", 132], ["(", 2], ["*", 27], ["-", 436], [",", 236], [".", 4176], ["0", 16], ["2", 8], ["4", 6], ["7", 2], ["6", 2], ["9", 14], [";", 20], [":", 166], ["?", 38], ["A", 46], ["C", 12], ["B", 12], ["E", 20], ["D", 4], ["G", 22], ["F", 12], ["I", 138], ["H", 38], ["K", 2], ["J", 2], ["M", 34], ["L", 10], ["O", 10], ["N", 20], ["Q", 2], ["P", 8], ["S", 38], ["R", 2], ["U", 4], ["T", 108], ["W", 42], ["V", 6], ["Y", 20], ["[", 26], ["]", 10], ["_", 8], ["a", 4], ["`", 6], ["c", 32], ["b", 2], ["e", 36], ["i", 16], ["m", 26], ["o", 2], ["s", 4], ["u", 24], ["t", 40], ["x", 10], ["z", 2]]], ["2", [[" ", 128], ["\"", 2], ["'", 6], [")", 12], ["*", 6], ["-", 20], [",", 132], ["/", 2], [".", 82], ["1", 127], ["0", 229], ["3", 90], ["2", 98], ["5", 112], ["4", 96], ["7", 78], ["6", 88], ["9", 51], ["8", 80], [";", 4], [":", 56], ["@", 14], ["]", 70], ["d", 6], ["n", 28], ["t", 20], ["}", 20], ["|", 66]]], ["6", [[" ", 60], ["-", 12], [",", 70], ["/", 2], [".", 30], ["1", 24], ["0", 76], ["3", 14], ["2", 34], ["5", 26], ["4", 19], ["7", 26], ["6", 32], ["9", 21], ["8", 22], [";", 10], [":", 32], ["?", 2], ["@", 10], ["]", 44], ["m", 4], ["t", 68], ["}", 18], ["|", 52]]], [":", [[" ", 3056], ["\"", 2], ["'", 20], [")", 2], ["(", 8], ["*", 2], ["-", 1142], [".", 260], ["1", 118], ["I", 4], ["3", 44], ["2", 90], ["5", 14], ["4", 30], ["7", 14], ["6", 16], ["9", 12], ["8", 12], ["R", 4], ["r", 4]]], [">", [[" ", 88], ["#", 2], ["\"", 4], ["$", 2], ["-", 2], [",", 2], [":", 2], ["<", 24], ["A", 2], ["@", 2], ["C", 2], ["F", 8], ["I", 10], ["M", 2], ["L", 2], ["T", 14], ["W", 4], ["_", 2], ["^", 2], ["a", 6], ["c", 8], ["f", 10], ["i", 12], ["h", 6], ["m", 8], ["o", 8], ["p", 2], ["s", 8], ["t", 8], ["w", 6], ["v", 2], ["{", 2]]], ["B", [[" ", 16], ["'", 2], [",", 4], [".", 12], ["A", 44], ["C", 38], ["B", 6], ["E", 200], ["I", 62], ["K", 702], ["M", 6], ["L", 69], ["O", 247], ["S", 8], ["R", 26], ["U", 52], ["Y", 62], ["a", 2602], ["e", 3594], ["i", 1068], ["h", 100], ["j", 2], ["l", 520], ["o", 2392], ["r", 974], ["u", 8016], ["w", 2], ["y", 828]]], ["F", [["A", 194], [" ", 300], ["E", 36], ["F", 18], ["I", 98], ["j", 2], ["l", 372], ["O", 166], [",", 2], [">", 2], ["i", 958], ["r", 5046], ["U", 14], ["o", 3334], ["a", 2482], ["e", 430], ["R", 78], [".", 10], ["u", 184], ["L", 20], ["T", 30]]], ["J", [["A", 18], ["a", 1388], ["E", 82], ["d", 2], ["'", 2], ["I", 2], ["-", 2], ["o", 2830], [".", 132], ["i", 314], ["s", 2], ["U", 30], ["O", 54], ["e", 1904], ["u", 1679]]], ["N", [["!", 6], [" ", 451], ["\"", 8], ["'", 28], ["-", 4], [",", 48], [".", 96], [";", 2], [":", 8], ["?", 2], ["A", 108], ["C", 124], ["B", 48], ["E", 247], ["D", 328], ["G", 216], ["F", 2], ["I", 92], ["H", 2], ["K", 22], ["J", 2], ["L", 4], ["O", 186], ["N", 40], ["S", 124], ["R", 13], ["U", 20], ["T", 298], ["V", 13], ["Y", 14], ["a", 3392], ["e", 2202], ["i", 1384], ["o", 4850], ["u", 72]]], ["R", [["!", 2], [" ", 2352], ["\"", 4], ["'", 20], ["*", 6], ["-", 4], [",", 78], [".", 718], [":", 2], ["?", 2], ["A", 178], ["C", 20], ["B", 12], ["E", 320], ["D", 100], ["G", 68], ["F", 4], ["I", 219], ["K", 70], ["M", 30], ["L", 42], ["O", 189], ["N", 84], ["Q", 2], ["P", 18], ["S", 90], ["R", 70], ["U", 34], ["T", 272], ["W", 16], ["V", 14], ["Y", 93], ["a", 374], ["e", 1237], ["i", 323], ["h", 52], ["o", 2304], ["u", 2014], ["t", 2], ["y", 20]]], ["V", [["A", 47], ["a", 1798], ["B", 2], ["E", 276], ["'", 2], [" ", 18], ["I", 587], ["-", 2], [",", 12], ["O", 26], ["l", 30], ["i", 510], ["r", 4], ["U", 2], ["o", 228], ["y", 26], ["e", 465], ["R", 22], [".", 162], ["u", 4], ["Y", 6]]], ["Z", [["a", 32], ["\"", 2], ["E", 16], ["d", 4], ["I", 2], ["h", 68], [",", 4], ["o", 22], ["n", 30], ["i", 26], ["u", 10], ["O", 4], ["e", 124]]], ["b", [["!", 40], [" ", 1058], ["'", 68], [")", 4], ["*", 4], ["-", 98], [",", 414], [".", 244], [";", 24], [":", 6], ["?", 36], [">", 4], ["a", 13924], ["c", 22], ["b", 1618], ["e", 60104], ["d", 78], ["g", 4], ["f", 16], ["i", 6998], ["h", 46], ["j", 990], ["m", 324], ["l", 22082], ["o", 19980], ["n", 44], ["s", 2992], ["r", 13256], ["u", 20366], ["t", 1570], ["w", 30], ["v", 88], ["y", 13906]]], ["f", [["!", 178], [" ", 90391], ["\"", 8], ["'", 72], [")", 16], ["*", 2], ["-", 876], [",", 2770], [".", 1846], [";", 240], [":", 102], ["?", 144], ["G", 2], ["I", 2], ["a", 20108], ["c", 14], ["b", 38], ["e", 23990], ["d", 2], ["g", 10], ["f", 10886], ["i", 22788], ["h", 6], ["k", 12], ["j", 16], ["m", 12], ["l", 7808], ["o", 46468], ["n", 16], ["p", 2], ["s", 464], ["r", 21052], ["u", 10540], ["t", 10202], ["w", 62], ["v", 2], ["y", 396], ["x", 2]]], ["j", [["a", 724], ["!", 2], ["e", 4002], ["'", 2], ["i", 118], ["o", 3558], [".", 4], ["u", 4654]]], ["n", [["!", 1140], [" ", 164227], ["\"", 84], ["'", 9982], [")", 108], ["*", 6], ["-", 2184], [",", 19804], [".", 11592], [";", 1670], [":", 478], ["?", 1178], [">", 50], ["J", 4], ["]", 18], ["_", 4], ["a", 17316], ["c", 30762], ["b", 372], ["e", 74881], ["d", 155134], ["g", 116276], ["f", 3720], ["i", 23814], ["h", 996], ["k", 7828], ["j", 896], ["m", 518], ["l", 7014], ["o", 57750], ["n", 7832], ["q", 950], ["p", 298], ["s", 29725], ["r", 506], ["u", 4864], ["t", 72732], ["w", 558], ["v", 3580], ["y", 9090], ["x", 498], ["z", 154], ["}", 4]]], ["r", [["!", 1102], [" ", 128583], ["\"", 78], ["'", 2438], [")", 108], ["*", 14], ["-", 2050], [",", 18518], [".", 12898], [";", 1346], [":", 332], ["?", 1112], [">", 28], ["A", 2], ["@", 14], ["_", 6], ["a", 45838], ["c", 7992], ["b", 2520], ["e", 175663], ["d", 22490], ["g", 6450], ["f", 3064], ["i", 57977], ["h", 1474], ["k", 6764], ["j", 14], ["m", 12284], ["l", 8396], ["o", 61720], ["n", 15999], ["q", 220], ["p", 3358], ["s", 36440], ["r", 17042], ["u", 12282], ["t", 29678], ["w", 1522], ["v", 4906], ["y", 24200], ["x", 6], ["z", 128]]], ["v", [["!", 34], [" ", 1478], ["'", 360], [")", 2], ["-", 58], [",", 566], [".", 316], [";", 12], [":", 4], ["?", 30], ["_", 2], ["a", 8210], ["e", 85189], ["g", 2], ["i", 17242], ["k", 2], ["m", 16], ["l", 218], ["o", 6350], ["n", 508], ["s", 216], ["r", 658], ["u", 248], ["t", 4], ["v", 22], ["y", 640]]], ["z", [["!", 8], [" ", 344], ["\"", 2], ["'", 14], [")", 4], ["-", 40], [",", 172], [".", 178], [";", 8], [":", 2], ["?", 22], ["a", 592], ["b", 6], ["e", 3788], ["d", 18], ["g", 8], ["i", 920], ["h", 122], ["k", 6], ["m", 104], ["l", 356], ["o", 1122], ["n", 2], ["s", 6], ["r", 2], ["u", 156], ["v", 14], ["y", 202], ["z", 622]]], ["~", [[")", 6]]], ["\t", [["\t", 174], [" ", 136], ["D", 2]]], ["!", [["!", 12], [" ", 7580], ["\"", 6860], ["'", 556], [")", 42], ["*", 12], ["-", 108], [",", 4], [".", 170], ["I", 2], ["v", 6], ["[", 2], ["_", 6]]], ["%", [[" ", 8]]], [")", [[" ", 830], ["-", 56], [",", 506], [".", 102], ["5", 2], ["[", 2], [":", 16], [";", 58], ["?", 2]]], ["-", [["!", 8], [" ", 5090], ["\"", 550], ["'", 68], ["(", 2], ["+", 4], ["-", 6008], [",", 22], [".", 2], ["1", 12], ["2", 16], ["5", 24], ["4", 2], ["7", 4], ["6", 6], ["8", 4], ["?", 22], ["A", 170], ["C", 118], ["B", 200], ["E", 88], ["D", 116], ["G", 118], ["F", 62], ["I", 194], ["H", 172], ["K", 16], ["J", 90], ["M", 196], ["L", 74], ["O", 38], ["N", 44], ["Q", 6], ["P", 134], ["S", 172], ["R", 44], ["T", 160], ["W", 74], ["V", 28], ["Y", 22], ["Z", 4], ["a", 1098], ["`", 16], ["c", 1092], ["b", 1366], ["e", 476], ["d", 942], ["g", 452], ["f", 1014], ["i", 408], ["h", 966], ["k", 224], ["j", 64], ["m", 808], ["l", 922], ["o", 468], ["n", 446], ["q", 40], ["p", 884], ["s", 1836], ["r", 562], ["u", 122], ["t", 1410], ["w", 812], ["v", 66], ["y", 140], ["z", 12]]], ["1", [[" ", 112], ["'", 4], [")", 16], ["*", 10], ["-", 14], [",", 112], ["/", 2], [".", 68], ["1", 246], ["0", 318], ["3", 164], ["2", 280], ["5", 224], ["4", 214], ["7", 188], ["6", 204], ["9", 126], ["8", 572], [";", 4], [":", 40], ["@", 4], ["O", 2], ["]", 48], ["s", 52], ["t", 22], ["}", 18], ["|", 88]]], ["5", [[" ", 98], ["\"", 2], ["'", 2], ["-", 4], [",", 88], [".", 46], ["1", 22], ["0", 140], ["3", 28], ["2", 32], ["5", 32], ["4", 22], ["7", 32], ["6", 16], ["9", 14], ["8", 18], [";", 10], [":", 48], ["?", 2], ["@", 14], ["]", 64], ["t", 82], ["}", 18], ["|", 44]]], ["9", [[" ", 74], ["'", 2], [")", 4], ["-", 6], [",", 40], [".", 22], ["1", 26], ["0", 43], ["3", 48], ["2", 14], ["5", 18], ["4", 15], ["7", 34], ["6", 20], ["9", 18], ["8", 10], [";", 12], [":", 38], ["@", 6], ["]", 44], ["t", 32], ["}", 18], ["|", 46]]], ["=", [["E", 2], ["=", 8], ["T", 14], [" ", 12]]], ["A", [[" ", 4464], ["\"", 2], ["'", 12], ["-", 18], [",", 4], [".", 24], ["A", 6], ["C", 108], ["B", 58], ["E", 22], ["D", 77], ["G", 50], ["F", 18], ["I", 98], ["H", 10], ["K", 18], ["M", 89], ["L", 220], ["N", 497], ["Q", 2], ["P", 2116], ["S", 220], ["R", 481], ["U", 44], ["T", 292], ["W", 18], ["V", 78], ["Y", 66], ["X", 6], ["Z", 2], ["a", 2], ["c", 208], ["b", 496], ["e", 2], ["d", 372], ["g", 352], ["f", 1144], ["i", 66], ["h", 554], ["k", 64], ["j", 4], ["m", 1358], ["l", 3042], ["o", 140], ["n", 12454], ["q", 4], ["p", 230], ["s", 2898], ["r", 1643], ["u", 754], ["t", 3060], ["w", 48], ["v", 60], ["y", 30], ["x", 2], ["z", 30]]], ["E", [["!", 20], [" ", 1253], ["\"", 2], ["'", 18], ["*", 2], ["-", 14], [",", 30], [".", 100], [":", 8], ["?", 4], ["A", 176], ["C", 152], ["B", 30], ["E", 92], ["D", 166], ["G", 32], ["F", 34], ["I", 60], ["H", 6], ["K", 8], ["M", 80], ["L", 142], ["O", 14], ["N", 490], ["Q", 6], ["P", 124], ["S", 360], ["R", 730], ["U", 18], ["T", 184], ["W", 90], ["V", 102], ["Y", 34], ["X", 64], ["a", 450], ["c", 46], ["b", 14], ["d", 90], ["g", 62], ["f", 20], ["i", 64], ["h", 58], ["k", 6], ["m", 1500], ["l", 226], ["o", 4], ["n", 1398], ["q", 20], ["p", 138], ["s", 148], ["r", 118], ["u", 358], ["t", 98], ["v", 1326], ["y", 70], ["x", 298], ["z", 2], ["}", 2]]], ["I", [["!", 34], [" ", 40514], ["\"", 4], ["'", 2748], ["-", 52], [",", 526], [".", 576], [";", 42], [":", 6], ["?", 88], ["A", 76], ["C", 182], ["B", 47], ["E", 82], ["D", 78], ["G", 140], ["F", 78], ["I", 1054], ["K", 12], ["M", 76], ["L", 150], ["O", 134], ["N", 704], ["Q", 4], ["P", 18], ["S", 277], ["R", 122], ["U", 2], ["T", 378], ["V", 298], ["X", 156], ["Z", 8], ["_", 46], ["a", 2], ["c", 146], ["b", 10], ["d", 16], ["g", 48], ["f", 1944], ["m", 196], ["l", 216], ["o", 30], ["n", 5298], ["p", 28], ["s", 930], ["r", 122], ["t", 8656], ["v", 100], ["x", 2], ["z", 2]]], ["M", [["!", 4], [" ", 68], ["\"", 2], ["'", 12], ["-", 4], [",", 12], ["/", 8], [".", 1208], [":", 2], ["A", 346], ["C", 28], ["B", 34], ["E", 243], ["D", 6], ["G", 12], ["I", 130], ["M", 24], ["L", 2], ["O", 117], ["N", 16], ["P", 50], ["S", 26], ["R", 8], ["U", 28], ["W", 6], ["Y", 24], ["a", 8688], ["c", 378], ["e", 1576], ["f", 2], ["i", 2158], ["o", 4266], ["s", 2], ["r", 2578], ["u", 518], ["y", 1492]]], ["Q", [["U", 48], ["C", 2], ["u", 494], [".", 4]]], ["U", [["!", 2], [" ", 106], ["'", 6], [",", 2], [".", 10], ["A", 16], ["C", 48], ["B", 24], ["E", 54], ["D", 44], ["G", 12], ["F", 6], ["I", 12], ["K", 2], ["M", 60], ["L", 68], ["N", 116], ["P", 26], ["S", 130], ["R", 182], ["U", 2], ["T", 156], ["V", 2], ["Z", 6], ["c", 2], ["g", 12], ["h", 34], ["k", 4], ["m", 16], ["l", 30], ["n", 859], ["p", 360], ["s", 32], ["r", 68], ["t", 50], ["v", 16]]], ["Y", [["!", 4], [" ", 260], ["\"", 2], ["'", 4], ["-", 68], [",", 10], [".", 22], [";", 2], ["A", 2], ["B", 2], ["E", 26], ["L", 4], ["O", 112], ["S", 26], ["R", 4], ["T", 2], ["a", 122], ["c", 2], ["e", 1328], ["i", 10], ["o", 3878], ["s", 10], ["u", 26], ["v", 8]]], ["]", [["!", 2], [" ", 322], ["J", 2], ["-", 2], [",", 44], [".", 14], [";", 24], [">", 2]]], ["a", [["!", 310], [" ", 65518], ["\"", 24], ["'", 716], [")", 20], ["*", 1], ["-", 724], [",", 2766], [".", 1558], ["1", 2], [";", 152], [":", 30], ["?", 144], [">", 2], ["S", 2], ["_", 6], ["a", 122], ["`", 6], ["c", 35608], ["b", 19042], ["e", 752], ["d", 56288], ["g", 18377], ["f", 7666], ["i", 47228], ["h", 1140], ["k", 13604], ["j", 480], ["m", 24754], ["l", 68865], ["o", 314], ["n", 216874], ["q", 102], ["p", 18548], ["s", 105951], ["r", 97182], ["u", 12725], ["t", 135418], ["w", 10880], ["v", 25744], ["y", 29029], ["x", 666], ["z", 1906], ["}", 2]]], ["e", [["!", 3010], [" ", 487805], ["\"", 166], ["'", 4249], [")", 336], ["*", 10], ["-", 4298], [",", 40540], [".", 24278], [";", 3704], [":", 890], ["?", 2866], [">", 78], ["B", 2], ["I", 2], ["S", 2], ["[", 6], ["]", 18], ["_", 42], ["a", 79086], ["`", 2], ["c", 27918], ["b", 1598], ["e", 45884], ["d", 142368], ["g", 8394], ["f", 13916], ["i", 18692], ["h", 2842], ["k", 1590], ["j", 380], ["m", 31126], ["l", 54118], ["o", 4898], ["n", 129345], ["q", 1706], ["p", 17078], ["s", 100714], ["r", 205409], ["u", 2658], ["t", 41944], ["w", 11422], ["v", 24561], ["y", 23800], ["x", 14052], ["z", 560], ["}", 4]]], ["i", [["!", 50], [" ", 1222], ["\"", 2], ["'", 184], [")", 4], ["*", 2], ["-", 384], [",", 450], [".", 254], [";", 14], [":", 6], ["?", 14], ["@", 2], ["G", 2], ["Y", 2], ["]", 2], ["_", 8], ["a", 10716], ["c", 45183], ["b", 6986], ["e", 33445], ["d", 40015], ["g", 26388], ["f", 17002], ["i", 24], ["h", 72], ["k", 7006], ["j", 18], ["m", 40198], ["l", 43870], ["o", 33038], ["n", 232657], ["q", 394], ["p", 5884], ["s", 107323], ["r", 32008], ["u", 1844], ["t", 102683], ["w", 38], ["v", 16166], ["y", 2], ["x", 2074], ["z", 2892]]], ["m", [["!", 462], [" ", 35852], ["\"", 24], ["'", 294], [")", 58], ["-", 610], [",", 7564], [".", 6290], ["1", 2], [";", 758], [":", 298], ["?", 470], [">", 22], ["]", 2], ["a", 45673], ["c", 96], ["b", 7420], ["e", 83120], ["d", 36], ["g", 4], ["f", 768], ["i", 24836], ["h", 10], ["k", 22], ["m", 5770], ["l", 522], ["o", 32940], ["n", 1218], ["p", 15046], ["s", 8640], ["r", 202], ["u", 10278], ["t", 200], ["w", 24], ["y", 17480]]], ["q", [["a", 2], [" ", 2], ["u", 12073], [",", 2], ["'", 2]]], ["u", [["!", 428], [" ", 17752], ["\"", 16], ["'", 1182], [")", 6], ["-", 186], [",", 1924], [".", 1140], [";", 124], [":", 18], ["?", 428], ["S", 12], ["T", 2], ["_", 2], ["a", 6632], ["c", 12934], ["b", 5730], ["e", 10797], ["d", 6988], ["g", 18286], ["f", 2056], ["i", 9148], ["h", 30], ["k", 496], ["j", 84], ["m", 8440], ["l", 37068], ["o", 708], ["n", 43221], ["q", 64], ["p", 17232], ["s", 44836], ["r", 48568], ["u", 18], ["t", 49162], ["w", 10], ["v", 428], ["y", 210], ["x", 498], ["z", 722]]], ["y", [["!", 1032], [" ", 118640], ["\"", 62], ["'", 1440], [")", 154], ["-", 2010], [",", 18388], [".", 10860], [";", 1366], [":", 466], ["?", 946], [">", 26], ["]", 2], ["_", 4], ["a", 2624], ["`", 2], ["c", 242], ["b", 640], ["e", 11272], ["d", 206], ["g", 138], ["f", 198], ["i", 4422], ["h", 84], ["k", 76], ["m", 714], ["l", 818], ["o", 28106], ["n", 212], ["p", 410], ["s", 8723], ["r", 738], ["u", 58], ["t", 3028], ["w", 464], ["v", 110], ["x", 14], ["z", 40]]], ["}", [[" ", 6], [",", 2]]]]] ================================================ FILE: systemd/freq.service ================================================ [Unit] Description=Freq service After=network.target [Service] WorkingDirectory=/usr/bin ExecStart=/usr/local/share/freq/freq_server.py -s 0 10004 /usr/local/share/freq/freqtable2018.freq PIDFile=/var/run/freq.pid Restart=always [Install] WantedBy=multi-user.target ================================================ FILE: upstart/sample_upstart.config ================================================ description "Freq Server" start on filesystem or runlevel [2345] stop on runlevel [!2345] respawn script export HOME="/usr/bin" echo $$ > /var/run/freqserver.pid exec python3 /opt/freqserver/freq_server.py -ip /opt/freqserver/freqtable2018.freq end script pre-start script echo "[`date`] Freq Server starting" >> /var/log/messages end script pre-stop script echo "[`date`] Freq Server stopping" >> /var/log/messages end script