comparison aggregate.py @ 24:91221f1c5b57 draft

Uploaded
author kaymccoy
date Fri, 12 Aug 2016 23:50:25 -0400
parents
children
comparison
equal deleted inserted replaced
23:2770013742c1 24:91221f1c5b57
1 # A translation of aggregate.pl into python! For analysis of Tn-Seq.
2 # This script requires BioPython just like calc_fitness.py, so you need it installed along with its dependencies if you want to run these scripts on your own.
3 # How to install BioPython and a list of its dependencies can be found here: http://biopython.org/DIST/docs/install/Installation.html
4 # K. McCoy
5
6
7
8
9
10
11
12
13
14 ##### ARGUMENTS #####
15
16 def print_usage():
17 print "Aggregate.py's usage is as follows:" + "\n\n"
18 print "\033[1m" + "Required" + "\033[0m" + "\n"
19 print "-o" + "\t\t" + "Output file for aggregated data." + "\n"
20 print "\n"
21 print "\033[1m" + "Optional" + "\033[0m" + "\n"
22 print "-c" + "\t\t" + "Check for missing genes in the data set - provide a reference genome in genbank format. Missing genes will be sent to stdout." + "\n"
23 print "-m" + "\t\t" + "Place a mark in an extra column for this set of genes. Provide a file with a list of genes seperated by newlines." + "\n"
24 print "-x" + "\t\t" + "Cutoff: Don't include fitness scores with average counts (c1+c2)/2 < x (default: 0)" + "\n"
25 print "-b" + "\t\t" + "Blanks: Exclude -b % of blank fitness scores (scores where c2 = 0) (default: 0 = 0%)" + "\n"
26 print "-f" + "\t\t" + "An in-between file carrying information on the blank count found from calc_fitness or consol_fitness; one of two ways to pass a blank count to this script" + "\n"
27 print "-w" + "\t\t" + "Use weighted algorithm to calculate averages, variance, sd, se" + "\n"
28 print "-l" + "\t\t" + "Weight ceiling: maximum value to use as a weight (default: 999,999)" + "\n"
29 print "\n"
30 print "All remainder arguements will be treated as fitness files (those files created by calc_fitness.py)" + "\n"
31 print "\n"
32
33 import argparse
34 parser = argparse.ArgumentParser()
35 parser.add_argument("-o", action="store", dest="summary")
36 parser.add_argument("-c", action="store", dest="find_missing")
37 parser.add_argument("-m", action="store", dest="marked")
38 parser.add_argument("-x", action="store", dest="cutoff")
39 parser.add_argument("-b", action="store", dest="blank_pc")
40 parser.add_argument("-f", action="store", dest="blank_file")
41 parser.add_argument("-w", action="store", dest="weighted")
42 parser.add_argument("-l", action="store", dest="weight_ceiling")
43 parser.add_argument("fitnessfiles", nargs=argparse.REMAINDER)
44
45 arguments = parser.parse_args()
46
47 if not arguments.summary:
48 print "\n" + "You are missing a value for the -o flag. "
49 print_usage()
50 quit()
51
52 if not arguments.fitnessfiles:
53 print "\n" + "You are missing fitness file(s); these should be entered immediately after all the flags. "
54 print_usage()
55 quit()
56
57 # 999,999 is a trivial placeholder number
58
59 if (not arguments.weight_ceiling):
60 arguments.weight_ceiling = 999999
61
62 # Cutoff exists to discard positions with a low number of counted transcripts, because their fitness may not be as accurate - for the same reasoning that studies with low sample sizes can be innacurate.
63
64 if (not arguments.cutoff):
65 arguments.cutoff = 0
66
67 # Gets information from the txt output file of calc_fit / consol, if inputted
68
69 if arguments.blank_file:
70 with open(arguments.blank_file) as file:
71 blank_pc = file.read().splitlines()
72 arguments.blank_pc = float(blank_pc[0].split()[1])
73
74 if (not arguments.blank_pc):
75 arguments.blank_pc = 0
76
77
78
79
80
81 ##### SUBROUTINES #####
82
83 # A subroutine that calculates the average, variance, standard deviation (sd), and standard error (se) of a group of scores; for use when aggregating scores by gene later on
84
85 import math
86 def average(scores):
87 sum = 0
88 num = 0
89 i = 0
90 while i < len(scores):
91 if not scores[i]:
92 scores[i] = 0.0
93 sum += float(scores[i])
94 num += 1
95 i += 1
96 average = sum/num
97 xminusxbars = 0
98 while i < len(scores):
99 xminusxbars += (float(scores[i]) - average)**2
100 variance = xminusxbars/(num-1)
101 sd = math.sqrt(variance)
102 se = sd / math.sqrt(num)
103 return (average, variance, sd, se)
104
105 # A subroutine that calculates the weighted average, variance, standard deviation (sd), and standard error (se) of a group of scores; the weights come from the number of reads each insertion location has
106 # For use when aggregating scores by gene later on, if the weighted argument is called
107
108 def weighted_average(scores,weights):
109 sum = 0
110 weighted_average = 0
111 weighted_variance = 0
112 top = 0
113 bottom = 0
114 i = 0
115 while i < len(weights):
116 if not scores[i]:
117 scores[i] = 0.0
118 top += float(weights[i])*float(scores[i])
119 bottom += float(weights[i])
120 i += 1
121 if bottom == 0:
122 return 0
123 weighted_average = top/bottom
124 top = 0
125 bottom = 0
126 i = 0
127 while i < len(weights):
128 top += float(weights[i]) * (float(scores[i]) - weighted_average)**2
129 bottom += float(weights[i])
130 i += 1
131 weighted_variance = top/bottom
132 weighted_stdev = math.sqrt(weighted_variance)
133 weighted_stder = weighted_stdev/math.sqrt(len(scores))
134 return (weighted_average, weighted_variance, weighted_stdev, weighted_stder)
135
136
137
138
139
140
141
142
143
144
145 ##### AGGREGATION / CALCULATIONS #####
146
147 #Reads the genes which should be marked in the final aggregate file into an array
148
149 import os.path
150 if arguments.marked:
151 with open(arguments.marked) as file:
152 marked_set = file.read().splitlines()
153
154 #Creates a dictionary of dictionaries to contain a summary of all genes and their fitness values
155 #The fitness values and weights match up, so that the weight of gene_summary[locus]["w"][2] would be gene_summary[locus]["s"][2]
156
157 import csv
158 gene_summary = {}
159 for eachfile in arguments.fitnessfiles:
160 with open(eachfile) as csvfile:
161 lines = csv.reader(csvfile)
162 for line in lines:
163 locus = line[9]
164 w = line[12]
165 if w == 'nW':
166 continue
167 if not w:
168 w == 0
169 c1 = float(line[2])
170 c2 = float(line[3])
171 avg = (c1+c2)/2
172 if avg < float(arguments.cutoff):
173 continue
174 if avg > float(arguments.weight_ceiling):
175 avg = arguments.weight_ceiling
176 if locus not in gene_summary:
177 gene_summary[locus] = {"w" : [], "s": []}
178 gene_summary[locus]["w"].append(w)
179 gene_summary[locus]["s"].append(avg)
180
181 #If finding any missing gene loci is requested in the arguments, starts out by loading all the known features from a genbank file
182
183 from Bio import SeqIO
184 if (arguments.find_missing):
185 output = [["locus","mean","var","sd","se","gene","Total","Blank","Not Blank","Blank Removed","M\n"]]
186 handle = open(arguments.find_missing, "rU")
187 for record in SeqIO.parse(handle, "genbank"):
188 refname = record.id
189 features = record.features
190 handle.close()
191
192 #Goes through the features to find which are genes
193
194 for feature in features:
195 gene = ""
196 if feature.type == "gene":
197 locus = "".join(feature.qualifiers["locus_tag"])
198 if "gene" in feature.qualifiers:
199 gene = "".join(feature.qualifiers["gene"])
200 else:
201 continue
202
203 #Goes through the fitness scores of insertions within each gene, and removes whatever % of blank fitness scores were requested along with their corresponding weights
204
205 sum = 0
206 num = 0
207 avgsum = 0
208 blank_ws = 0
209 i = 0
210 if locus in gene_summary.keys():
211 for w in gene_summary[locus]["w"]:
212 if float(w) == 0:
213 blank_ws += 1
214 else:
215 sum += float(w)
216 num += 1
217 count = num + blank_ws
218 removed = 0
219 to_remove = int(float(arguments.blank_pc)*count)
220 if blank_ws > 0:
221 i = 0
222 while i < len(gene_summary[locus]["w"]):
223 w = gene_summary[locus]["w"][i]
224 if removed == to_remove:
225 break
226 if float(w) == 0:
227 del gene_summary[locus]["w"][i]
228 del gene_summary[locus]["s"][i]
229 removed += 1
230 i -= 1
231 i += 1
232
233 #If all the fitness values within a gene are empty, sets mean/var to 0.10 and Xs out sd/se; marks the gene if that's requested
234
235 if num == 0:
236 if (arguments.marked and locus in marked_set):
237 output.append([locus, "0.10", "0.10", "X", "X", gene, count, blank_ws, num, removed, "M", "\n"])
238 else:
239 output.append([locus, "0.10", "0.10", "X", "X", gene, count, blank_ws, num, removed, "\n"])
240
241 #Otherwise calls average() or weighted_average() to find the aggregate w / count / standard deviation / standard error of the insertions within each gene; marks the gene if that's requested
242
243 else:
244 if not arguments.weighted:
245 ###!!!
246 print gene_summary[locus]["w"]
247 (average, variance, stdev, stderr) = average(gene_summary[locus]["w"])
248 else:
249 (average, variance, stdev, stderr) = weighted_average(gene_summary[locus]["w"],gene_summary[locus]["s"])
250 if (arguments.marked and locus in marked_set):
251 output.append([locus, average, variance, stdev, stderr, gene, count, blank_ws, num, removed, "M", "\n"])
252 else:
253 output.append([locus, average, variance, stdev, stderr, gene, count, blank_ws, num, removed, "\n"])
254
255 #If a gene doesn't have any insertions, sets mean/var to 0.10 and Xs out sd/se, plus leaves count through removed blank because there were no reads.
256
257 else:
258 if (arguments.marked and locus in marked_set):
259 output.append([locus, "0.10", "0.10", "X", "X", gene, "", "", "", "", "M", "\n"])
260 else:
261 output.append([locus, "0.10", "0.10", "X", "X", gene, "", "", "", "", "\n"])
262
263 #Writes the aggregated fitness file
264
265 with open(arguments.summary, "wb") as csvfile:
266 writer = csv.writer(csvfile)
267 writer.writerows(output)
268
269 #If finding missing genes is not requested, just finds the aggregate w / count / standard deviation / standard error of the insertions within each gene, and writes them to a file, plus marks the genes requested
270 #This is never called through Galaxy since finding missing genes is just better than not finding them.
271
272 else:
273 output = [["Locus","W","Count","SD","SE","M\n"]]
274 for gene in gene_summary.keys():
275 sum = 0
276 num = 0
277 average = 0
278 if "w" not in gene_summary[gene]:
279 continue
280 for i in gene_summary[gene]["w"]:
281 sum += i
282 num += 1
283 average = sum/num
284 xminusxbars = 0
285 for i in w:
286 xminusxbars += (i-average)**2
287 if num > 1:
288 sd = math.sqrt(xminusxbars/(num-1))
289 se = sd / math.sqrt(num)
290 if (arguments.marked and locus in marked_set):
291 output.append([gene, average, num, sd, se, "M", "\n"])
292 else:
293 output.append([gene, average, num, sd, se, "\n"])
294 with open(arguments.summary, "wb") as csvfile:
295 writer = csv.writer(csvfile)
296 writer.writerows(output)
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392 #
393 # ~MMM=:DMMM?, +NMMO=,:~I8MMMMM8+, , ~I8MMMMMN87~?8NNMMN8: +NMND~ +MN= ,$MMMI ?M8, ,OM8, :MN+ =MM? ,MMDNMMD ,+DM8I, ,,:::~~~::::::::::
394 # IMMMNMM8I ,I8MM87~::+$8NNMMMMOI+=~~:, ,,:~=?$DNMMMMMMDOZI7ZDMMMD8I , , $M8+?8MM8I , 7MI +MN= ZMN, 8MD MMN8MMM, :$ONM8I+=:, ,,,::::~~~~~=====~:
395 # , ,DMNN7: , ,OMMN7==~::~=?8NNMMMMMMNNMMMMMMMMMMMN8OO8ODNMMMMMD~ , IMMNMN~ ,OM+ ,NM$ ,NMO, :MM$ , ,:::,,::::,, $MNMMNM, ,,, :?ONMMNN8?~,, , ,,,,,,,::~~=+++??=~
396 # ,,:=+????+, I$ :ZMMN8$~:,,, ,:=?7$O8DD8O$7+==+$O8DNMMMMMMMMM$ ?$, == ,~, ~NM= 8MD, ,OM8ZMMO , ,::::::~~~:,, ?MNMMZ ,,,,,, ,+7ONMNMD8O$+~, ,,,,,,::~====::
397 # ,:=IONMMMMMMMMMMM8: ZN$: ,~DMMMND7=, ,,:~====:=$DNMMMMMMMN88MMMZ +N$ , ,7DN8= =MN, IMM =DMN7 ,,,,,,,,,, ,~?, ,,,,, , ~?$8MMMMNN8Z?~:,, ,:::,,,
398 #+ONMMMMMMNO7=:,, ,,+MMO, 7D$: ~OMNMNNMNNNNNNNNNNNMMMMMMMMMNMMMM?,~MMM8 ND, 7MM=, ?NN:, +MO, ?MM, ,,,, , :,:=$DMMMMMMN87=~, ,,,,,
399 #MMND8$: , 7NM7 , =?~,,, :?88DDDNNMNNNDNDD88Z?:, ZMM$ ,MMMO ,MM+ZNMM? ::ZNZ, +M$ ,MM?, , ,, ,,:=?Z8NMMMMMN8Z+=,
400 #: ~ZMM8~ ,,,, 8MM, +MMM, 7ZZI~=$OOZ$: ,:+???+, +MZ =MN= ,,, , ,,:~=?IIII$ZO88DDNNNNNNMMMMMMMMMMN~,
401 # ,:OMMM? ,,:,, 8MM ~NNM7 :OMMMMMMMMO: =M8, :NM~ = ,~?I, ,,,,,,,,,,,,,, ,~$DNMMMMMMMMMND8O888Z$II7777I??+++===:,
402 # ?DMM8?, OMN??NMM$ ~8MMMO?===7MMM8: ~NM= =NN: ,OM~ ,, +NMMN~ ,,,,, ,,,,,,,, ,?$O8NNMDDZ7?+=~:, , , ,
403 # , ~$MMMD+ , , ~MMNMMN~ : +NMMZ, NMNM~ 7MI , ZNN,, IMN, :DMNM+ ~+NMMMD~, ,,,,,,,, ,, ,,,,,:, +OMNMMOI~,
404 # , $MMMM$, , ,=?ODNMNNMNMMMMNNND~ ,$D$, , ,8MM8 ,MMM7 ,ZMNNMM= DMMNMMMMMMMMMMMMNI: , ,,,,,,,,, ,,, ?NMO=, ,
405 # ,~ZNMND7, ,,:~=+$DNNMMMMNDDDD888OZZZZ8NMMN IMMN: ,MMN~ +Z$+, ?NNNDO+:?O888OI, ,,,,,,, ,,, +MN+
406 # =ONMMM8~ , ,:=IDMMMMMMMND8$+:, , ,INMNZ :MMM~, , +MMD , ,, ,,::,,,, ,,:::, ?M8: ,
407 #8MMMNZ~ , =I$ONMMNDZ7?+, ,,=I8NMD7: DMMN DMN= ,:::, ,:~~=~~:,, :ZMMZI+: ,, ,,,,,,,
408 #MN7:,:=7ONMMMD$?=, , ~7ODNMM$+: ~MMM++7ZOZOO8O8D8$~ ,MM8 ,,,,::~~==~~:,, :+7DMMMMNNDD88OOZZZO88DNNNN8=, ,,,,,,,
409 #I,~+DMMNND7: , ,$MMMMMN7, $MMN :??+=~::,,,, NMD, ,:,,:::~=~~,,,, ,,=I$8DNMMMMMMMMMNMMMNZ: ,,,,,,
410 #DNMNN7:, ,+ONMMMMNI: NMM$ DMN= ,,,,:::::~~::,, ?DMMMMDZ=, ,,,
411 #N8$: ,,, ,:=?ONMMMD8Z+, ,,,, MMM= ZMMI ,=?$8NMMMMMMMMMMMN87=~~,,, :=ZMMMMD$~
412 # , ,=ZNMMMMMNI:, ,~?Z88888$=, ,:~+??~, MMM, IMM$ ,=ZNMMMMMN8$+~=~=~~===7ODNMMMN8DNMMMN+, ,,
413 # , ~?$ODMMMMNZ?: :II+~, ,=7= :?77?=:====?O+ ,,:,,, MMM, ?MM$ ,,,, :?ONMM8II=, , =DMMMM87=, ,,,,
414 # , ,, ,~I8MMMMMMN87?~:=+?7$ZOO88DD888O$I+~:, ~ZZ: ,$7,~??, ,?+ ,+Z8$?==??= MMM =MM$ :?ODNNNNNNNMMO: ,:?NNMNO= ,,,IMMMNZ, ,,,:,,,,,,,,,,,,,
415 #, ,~7DNMMMMMMMMMMMNNNNMMMNND8Z7II7$$$$ZODNNNMND$, :O$: , ,IN$, I+ +ZZ=,, 7+ MMM =ODDDDNNNNNN8= :MM$ ?DDNN8?::,, ,,7NMM8, 7NMNZ~, :OMMM$, , ,,:::~~:,,,,,,,,,,,,,,,,,
416 #?8NMMMMMMMMMMMN8I:,,, ~$NMMM$ :87 +DM$ ID+~78I, O7 :=+~ MMM , , ?MM7 $NMN$, :I8MMMMMMNMDNNNNNNNNNDD88ZI=: ,ZMM7, +MMN~ ,,,:::,, ,,:,::::,,,,,,
417 #MMMD8DNMDZ7=: ,:=+7ZNNNDOZ~ =DI , :7MM7, IDDZI, =DN88ZI77$N? NMM: $MM= ~: =OMNZ+ ,=7DMMMMMMNDDOOOOZ$7IIIII77$ZOO8NNMMD$+~ :OND~, ,, MMN= ,,,,,,,,,,,,,
418 #: ,,, , ,:+ZNMNNMMNO?: +8? +NMN7 , , ON~ 8MM$ NMD, ,7MMMN, 7MMO, ,:ONMMMMN8I: ,~ZNMNN$, ~MM? , ZMNND?~: ,,, ,, ,,,,,,
419 # , , ,:~?7$ZZ8NNMMMNO7I=, ~D+ ZNO=, , :NM$: =MMM NMO ~NMNMMM :ZDN$, ,,=7DMD$?=, :?ZMD$: :DMNOZZZ$: ,,,,, ~IDMMMMMMMMMMMMMMMMMMMMM8~
420 # , =DMNNNNNNNN8$= : , ,,~?ODNZ: :DM? =: ,MMM7 +MN~ ,MM8:NMN INMZ, ,=ONOI , +NMZ ,,+ZDMMMMMMMN+, ,,,,,,, ,~?$ODNNNNNNNMMMMMMMMD= ,
421 # ,:::::~7$I?=: ,~78NMNMMMMM? :+Z+ M8 $MM, =, DMMD NMN DMO OMM77NMI, ?8$~ , ~ZDDDNNNNNMMMMMMMMNMNNNNNDD8Z+:, IMN: I8DNMMMMN7~: ,,,,,, +$O$, ~$DMMMMMMMD~ ,, ,
422 # :I+ :ID? ~ZDNNNNMMNO?~,, ,:::::=7ONMNNNDMMMN$ ,=IONNMMMMZ:, ~MO ,7MMMI $MN, , :MMN ?8NDDNND$~ +MM~ ,MM~=MMMNMD, =ONNDDNMMMMMMMMMMMMNNND88DNNNNNMMMMMMMNDO7+~::,:,7MM+ =DMMMNNO? ~ZMMMMM7::~INMMMMMMMMMMMMMN8:
423 #:MMM+,INMMM: ,:~+78NMMMM8?==++++++???++??I$Z77$$$$$$$7II??I$ZZO8MMMMM8Z7~ ,IZI ~77+ ?MMMMD88MN8+~, +8MO$OMMMMMNMMMZ, ~=: OMM? ,MM? ZMM~MMMM8~ ,:+7$$$$ZZ7?==: :8MDOZ$ZZZODMMMMMM8+, ,:=?$ZZOOOOOOZ$: , , ,=8MNMMMMMMMMMMNDZ$7$MMMMMMMMMMMMMMMMMMNI+?I7ZDNMMMMMMMMMM$,
424 #=MMMZ$MMMMMM~ ,::::~==~~+I$8NMMMMMN$::::::::,,, ,,=ONDDO$7II?+~, , ,,$DD87: =NND= , ,+$$=:~, ,:, ,MMD NMI ,~?Z8DND88$?: 8MM$MMMZ:=~:,~~:::,,,=$DNMND$MM8, ~DMNMMMN?, :7$7?+==~=:,,,,,,,, ,,,,,,, ,,,,,,::,,,,,:::::::,,,::::::,, ,OM$,7MMMMMMNZ= , ~8MMMMMMMNDO7I7MMMMMMMMMMMMN8Z7+?NMMMD,,
425 #NMMMMMM? ,++, ~=I??= :7$ 7MM+ 7M7 ,:?ZZ$MMM8NMZ~+, :?INMMM? +$NMMMNZ: :+?I7$$Z$O88D88DDDDNNNNNNNNNNNNNNNNNNDDNDDDNNNNNMMNMMMMMMMNNNN$:??~ ,+II?=, , ,, ,?I??+=~, :MMMMMNM
426 #MMMMMD~ ,:=++++++++++=~,,, +MMN: ,MMD, :M$ ,INMNMMMMMMMMMM~~~?D, :OMM8: ,+$8Z$+,,$MMMMMD, :IODDDD
427 #N$~,,, ,~I$8NMMMMMMMMMNMMMMMMMMMMMMMMMMNNNN7: ZMMMM? NMMMNZ~:, +$: ,NMNI:::~?8MMM7I? IO ~I$ODNNNDND8OO$I?DMMMD$I8NMMMMMMMNMNMMMMMMM8=, ,
428 # ,:~?ONMMMMNNNDDD8NMD+, ,~?Z8NMNM8=, , $MNNNMM? :DMMMNDD8DZ7$+, ,8NMMNMNMMMD$: =8, ,INMMMNZI?====+I$$8DDNMMMMMMNNNMND7, :~$DMMMNMO
429 # ,?DMMMMMNNNMMM+::~++ZMMMM8ZZZZZZ$II77II7???=~:, ,+DMN7 =NMM8, ,NMMNMNMN$?I7I77OZ~ ~8D$~, ,MMMMMMNM8: :DMMM, , DMO=ZMZ,
430 # ,?OMMN87=, IZNNNMMMMMMMMMMND7IIII??III$8DDNN8Z+, , ~MM ?OMMMM~ ,MMMMMZ+ ~I= IMMMO$$= ?NNM? MN~ +NM:
431 # IMM8~ =MD, ?N= :,, ,+77?=+, $8MM7::OMMMMMMZ+ I+, ?NI , :MMM8$ NNI, 7M$
432 # ,MMN $MD 7M+ ~ODNZ~, :7MMN? , $MMMN= 7MNMN: +8+ ,D8~ =MMDD8Z= =NMD OM7,
433 # OMMD~ IMN: =8O:,~+$OO? :IZ+: :ZMMNM8= =DMMI ~8MM8= , ,, :8M?,$MM, ::, DM, =Z~ ,I8DDDN8$DMN~ MN ,=Z8DNDZZ= MD: ,
434 # ,,,,,,,, ?8NNMM8$I????++=+8MMMD$77$ZDMMNMMMDNOZ~ :IZ8DOI~, =MMMNMNM8I:, ,7M8I +MND7 ~MNDDM8~ 7MI MM7 :8MDDM7 8N= ~ID$, ,:Z$?:,,,=ONNMNMD= ?M$ :: +MI ,,,,,,::~~:::,,,,,,, ,+OMO:, ,
435 # ,,,::~===~~:, ,~+I$88DNNNNNNNNNDNDD8O$?~:, ,7DNMNDMMMN~,ZMND$8NNDZ=, $M? ?NNN7 =MO OMD$MM= MMMINMO $M7 DN: 8MMD: ?D~ :O8ZDMMMMD=, ,ZN$ ,INNMD= :NO ,:+8MMMMMMMMDI:,::,,
436 #=~~~::~~::, ~?78MMMDNMM? :+I$DD87?=, OMNDO$7$OI: 7N+ ?MNMN~ MMMNM$ 7M$ 7M$ +NMMO, ?N~ ~8+ ~7NMMNNOI= ~?ONZ+ ~ZNND,$M8 ~MO $MMMMMMMMMM7:::~~~~~~=+++===~~~:::,,
437 # ,~ONMMNO~, :?8NNMN8?~ZNMMMMMMMMMNMMNDOI=~NM? =MMM+ NMMMO 8M$ ,MM, $MMMN =D, ,?N~ , ?NMMMNNNDDO8DDD887, ,$ND= :O$NMZ IMO ,IMMMMN$, 7NO, ,,,,,:,,,
438 # ,~IDMNN8OI, :~+$DMMMMMMMN87+=~~~~?ZDNNMM, ?NM? :NMN :MM7 ~MN ~DMMMN O~ :DD, ,MMMMNNOI:,, , ,=ZODD8D? :MMM: NMZ +8NM8, ,, :~ ,,~:,
439 # ,INNMMNNO+ :=78NNZIIONMNNDMMN ,7D~ :MN~ MNMM?=MM $? OD, ,IMD ,:8MNMNNNNNNNNMMNM7: :8~ ZND OMN7, :NNMMMMN :8MMMMMNZ=:
440 # :O88NMMN$=~:, ?MMN88NMMMD =MN? =, :NM +7$NO, =N8 , OMI, ,, 7M: ZDDND? MMO ,, +MM8?OMN: ,::
441 # :$NMMMNMM8I: ,8MD, +MMN= ,=?77=:ZMMM7 ?MN ~$+ 7M7 ,DZ :M~ IMM8: ,8MN, , ,,,, :MMD,=DMM+,?O8= , ,
442 # ,=I77$ONNNZ?+ONMZ =$D ,+=::+$8NNMNDNMD7?, ?MN :~~: ~D7 ,NI ,M7 ~?ZNZ?, 8MM~ =ZMMN~$MMMMMMMNMMD$ONMMMMD:
443 # ~DMM= ~I7=, =DMMMD7MMM, :+?=?O$: ~N: ~MN88D$: NMM=, ~MMMMMMMMMMMMOZMMMMMM7::8MMI
444 # , :DNNI :~IDMMND :::=?II?==~::ZN7=+I$ZZZ8DZ+~~: IMMM~ ~MMMNMMMMMI~:7NMMMMD7,: +NM8,
445 # :NMM7, ~MM+ ,,,:~==~~~: , OMMN: ?NNMMMMM8, ~NMNO, =MMMN?,,
446 # ,,,,,,,, ,$8MMO= ~M8 +MNO: ,MM~ , :: ,~, ,,:::,,,,
447 # ,::,,,, ~ONND+ OD+ ?NMD, ?? ,::::::,,
448 # :=+??=:,,,,, ~?$D87I: ~Z? =$DM$: ,::,,,,,,,,
449 # ,:~==~, :+=, $NNNNZ~ ,,:~~: , :DMMMI
450 # ,~~~~~:,,, ,,, ,~IMMMN8O+, ,:~?7$Z7~, :ZDMNNDNM8ZI
451 # ,,~~:,, , :$DNNMMN8?, , ,~7ZOO?: ,:$NMMMM? :7NMMD?,
452 # ,:~~:,,, $NMMMMMNMNO?~ ~?ODDD$=, :?8MMMMMD?~7NMMMD$~ :ONMMN?
453 # ,,,,,,,,, ?$DMMMMMMMMMMD$?=~, ,~7ZZODN87????I$ODNMDOZ$7I: ~$ZDMD7==~ =$ZDND$++~,
454 # ~?++=~~, ~+?II7ZNMMMMMM8$$$?~, ,~?II7Z8DDOZ$77II+: ~?IZDM8O$I~, :??$8MMNZZ7+,
455 # , , ,+D7 :=IZ8NMMMNNMNNO$= ,:?ZDNNMMMNMND8Z7=, =ZNMMMMMD?,, :ONMNMMMN?,
456 # ,MMMM7 ,,::~IONNMMNNDDD8OZI=, ,::::=+I$ONMNNNNDDDNNMMMMMMMMMD87: ,:~=ZNNNDOI, ~7$ZO8DDNNNNDD8O+:,
457 #~, +MMMMDI?~ ,~+Z8DNDNNMMMMDD$+:,,, , ,~?7O8DNNNNNNMMMMMNOOZI??++?IZ88$: ,,~ZDMMMMMMMMMMMMMMMMMMNNNNNMMMNND8$=,,
458 # ,~: NMMMMOZMM8: ,7DZ~ ,,~IONMMMMMMMMMNDZ+~: , ,=I8DNMMMMMNMNMMMMMDNMMMMNMMMNNNDDDDD8O8Z$7II+++IZDDMMNMN$,,
459 # :~: MMMMMNMMM+ :, +?DOI~ ,:~?7$$ZODDNMNN8Z7??+=~:, ,~=+?7I?=:,,,,:=?I7$$$$$$$ZZZOO8DDNNMMNNNNNMMMMNMZ+
460 # ~=, MMMMMMMM8 ,NNNO , ,~?ZDNMNNNNNNND8O7?:,,, ,~=7DMMMMMMMMMZ~
461 # ,:+~ ,MMMMMMMMO ~N8: ,,:~, ,:~:,,, ,:~, ,:~~=+++?7$O8DNNNNNMMN8$=, ~+$ZO8DNNMMNNNND8OOOZ$+:, :=+I8MMMMDOI
462 # ,=+ MMMMMMMMMDMZ, ~?: ,,,,, ,:~~~, ,NN?$NMMMMMMMMMMMN87~:,,,=+=:,,,,,,:?NMMNMMMMMMNNDNDI8MMM+ ,
463 # +=, $MMMN?$NMN, ,+?+:, ,,:~~:, :=~, 8M= , :7ONNNO?~, , :$NNMMMMMMMMMMMMMN,
464 # ,+? ,NNO,, , :ODNNNZ: :?777I= IMO ,,=$Z7+~ ,?NNMMNZ: :7NMMMMMNMMMM8 , ,IDND~
465 # ,=~, 7I :+I+~::,, ~?I~ , ,~=~==: ZMZ ?8I: :I$DND$?~ :?$8MMN$?: ?ZDMMMMMMMM7 +$NMMMMMI
466 # ~~ , ,=+=: ,== ::, , ZMM: ?NN8: ,7NMMNI, ,$NMMMO: =NMMMNMM+ I8NMMMM,
467 # ~= ,~:,,~~, ,:, ,,,, , ,, +MN8 ,~OMM8Z, :+ZMNDOI =IMMN8= ,=NNMO ?NMMMD
468 # ::, ,,,:: ,:, ,, =MMO~ , ?NMMMI, ,INMMMDI, ~DMMN+, NMO ?DNO~
469 # ,~, ,,,::, ,, , ,, ,INMND+: :MMM+ ~ZDDMMMD?~:$MMMMMMMMMMM?
470 # ,, :~~:, ,:, ,, :ZMMMMNNMMMN, ,=ONMMMMNM$,,,,,, ,,
471 #Z, :, ,, ,~=~, ,, ,=?7$I= , :~~~, ,,,,
472 #MD= :: ,,,, , ,, ,,,,
473 #MNMI :: ,,, ,,,,
474 #7MMM? , ,~: :~:, ,:,
475 # OMMMO: ~NMD, :=: :+=: ,,,
476 # ~MMMN8: NMMM~ +?: ,:=++~ ,:,,
477 # $MMMMMNI,?MMMMZ ,DM7 ,=I= ~+~~:, ,:,,,
478 # +MMO~OMMMMMMMMD MMM7 , , =$~ ?OZ+ ,:,
479 # ~NMN: :+DNN7MMMNMMMDODMMN+ :+?, +77+~: :::,
480 # IMM+ ,NMMMMMMMMN?NM7 ~7+, , :+$I, , +8? :+~
481 # =NMD, NMMMMMM8~ ?NN, =ND? ,=??: ,8NMMMM= :++
482 # +DO, ~ZZ$ODI :8M~ :=I8NMNMMD+, ,:~~=: , +8MO$DMD+ ~===~: :~~:
483 # :$~ 7NMD$, ZMM8I? ,~=: , ZNN7,:MM8~,OMNMD8DMM= ++:
484 # =ZNOI: ?DND= ,?I~ ,,,: ,$ND+ ?NMNNNNN7+, 7MN, ,=+~
485 # :ZI: :, ,=7: ::,, $NN= 7NMMMM7: :DMMMN8NMMDDMN7 ,::,
486 # ~?= ,,, ,ZM= DMMD8 ?MMMMNN7, ,I+ :~~,
487 # =+, ,,, ,, =Z8: +$~
488 # :~ ,,~~,
489 # :, ::,
490 # ::, ,:::,
491 # ,, ,~
492 # ,, ,,,
493 #
494 #