comparison aggregate.py @ 30:3e346e0dd55c draft

Uploaded
author kaymccoy
date Sat, 13 Aug 2016 00:03:18 -0400
parents
children
comparison
equal deleted inserted replaced
29:c67dd00f7e18 30:3e346e0dd55c
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 unweighted_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 if len(scores) < 2:
101 variance = xminusxbars/(num-1)
102 else:
103 variance = 0
104 sd = math.sqrt(variance)
105 se = sd / math.sqrt(num)
106 return (average, variance, sd, se)
107
108 # 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
109 # For use when aggregating scores by gene later on, if the weighted argument is called
110
111 def weighted_average(scores,weights):
112 sum = 0
113 weighted_average = 0
114 weighted_variance = 0
115 top = 0
116 bottom = 0
117 i = 0
118 while i < len(weights):
119 if not scores[i]:
120 scores[i] = 0.0
121 top += float(weights[i])*float(scores[i])
122 bottom += float(weights[i])
123 i += 1
124 if bottom == 0:
125 return 0
126 weighted_average = top/bottom
127 top = 0
128 bottom = 0
129 i = 0
130 while i < len(weights):
131 top += float(weights[i]) * (float(scores[i]) - weighted_average)**2
132 bottom += float(weights[i])
133 i += 1
134 weighted_variance = top/bottom
135 weighted_stdev = math.sqrt(weighted_variance)
136 weighted_stder = weighted_stdev/math.sqrt(len(scores))
137 return (weighted_average, weighted_variance, weighted_stdev, weighted_stder)
138
139
140
141
142
143
144
145
146
147
148 ##### AGGREGATION / CALCULATIONS #####
149
150 #Reads the genes which should be marked in the final aggregate file into an array
151
152 import os.path
153 if arguments.marked:
154 with open(arguments.marked) as file:
155 marked_set = file.read().splitlines()
156
157 #Creates a dictionary of dictionaries to contain a summary of all genes and their fitness values
158 #The fitness values and weights match up, so that the weight of gene_summary[locus]["w"][2] would be gene_summary[locus]["s"][2]
159
160 import csv
161 gene_summary = {}
162 for eachfile in arguments.fitnessfiles:
163 with open(eachfile) as csvfile:
164 lines = csv.reader(csvfile)
165 for line in lines:
166 locus = line[9]
167 w = line[12]
168 if w == 'nW':
169 continue
170 if not w:
171 w == 0
172 c1 = float(line[2])
173 c2 = float(line[3])
174 avg = (c1+c2)/2
175 if avg < float(arguments.cutoff):
176 continue
177 if avg > float(arguments.weight_ceiling):
178 avg = arguments.weight_ceiling
179 if locus not in gene_summary:
180 gene_summary[locus] = {"w" : [], "s": []}
181 gene_summary[locus]["w"].append(w)
182 gene_summary[locus]["s"].append(avg)
183
184 #If finding any missing gene loci is requested in the arguments, starts out by loading all the known features from a genbank file
185
186 from Bio import SeqIO
187 if (arguments.find_missing):
188 output = [["locus","mean","var","sd","se","gene","Total","Blank","Not Blank","Blank Removed","M\n"]]
189 handle = open(arguments.find_missing, "rU")
190 for record in SeqIO.parse(handle, "genbank"):
191 refname = record.id
192 features = record.features
193 handle.close()
194
195 #Goes through the features to find which are genes
196
197 for feature in features:
198 gene = ""
199 if feature.type == "gene":
200 locus = "".join(feature.qualifiers["locus_tag"])
201 if "gene" in feature.qualifiers:
202 gene = "".join(feature.qualifiers["gene"])
203 else:
204 continue
205
206 #Goes through the fitness scores of insertions within each gene, and removes whatever % of blank fitness scores were requested along with their corresponding weights
207
208 sum = 0
209 num = 0
210 avgsum = 0
211 blank_ws = 0
212 i = 0
213 if locus in gene_summary.keys():
214 for w in gene_summary[locus]["w"]:
215 if float(w) == 0:
216 blank_ws += 1
217 else:
218 sum += float(w)
219 num += 1
220 count = num + blank_ws
221 removed = 0
222 to_remove = int(float(arguments.blank_pc)*count)
223 if blank_ws > 0:
224 i = 0
225 while i < len(gene_summary[locus]["w"]):
226 w = gene_summary[locus]["w"][i]
227 if removed == to_remove:
228 break
229 if float(w) == 0:
230 del gene_summary[locus]["w"][i]
231 del gene_summary[locus]["s"][i]
232 removed += 1
233 i -= 1
234 i += 1
235
236 #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
237
238 if num == 0:
239 if (arguments.marked and locus in marked_set):
240 output.append([locus, "0.10", "0.10", "X", "X", gene, count, blank_ws, num, removed, "M", "\n"])
241 else:
242 output.append([locus, "0.10", "0.10", "X", "X", gene, count, blank_ws, num, removed, "\n"])
243
244 #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
245
246 else:
247 if not arguments.weighted:
248 (average, variance, stdev, stderr) = unweighted_average(gene_summary[locus]["w"])
249 else:
250 (average, variance, stdev, stderr) = weighted_average(gene_summary[locus]["w"],gene_summary[locus]["s"])
251 if (arguments.marked and locus in marked_set):
252 output.append([locus, average, variance, stdev, stderr, gene, count, blank_ws, num, removed, "M", "\n"])
253 else:
254 output.append([locus, average, variance, stdev, stderr, gene, count, blank_ws, num, removed, "\n"])
255
256 #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.
257
258 else:
259 if (arguments.marked and locus in marked_set):
260 output.append([locus, "0.10", "0.10", "X", "X", gene, "", "", "", "", "M", "\n"])
261 else:
262 output.append([locus, "0.10", "0.10", "X", "X", gene, "", "", "", "", "\n"])
263
264 #Writes the aggregated fitness file
265
266 with open(arguments.summary, "wb") as csvfile:
267 writer = csv.writer(csvfile)
268 writer.writerows(output)
269
270 #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
271 #This is never called through Galaxy since finding missing genes is just better than not finding them.
272
273 else:
274 output = [["Locus","W","Count","SD","SE","M\n"]]
275 for gene in gene_summary.keys():
276 sum = 0
277 num = 0
278 average = 0
279 if "w" not in gene_summary[gene]:
280 continue
281 for i in gene_summary[gene]["w"]:
282 sum += i
283 num += 1
284 average = sum/num
285 xminusxbars = 0
286 for i in w:
287 xminusxbars += (i-average)**2
288 if num > 1:
289 sd = math.sqrt(xminusxbars/(num-1))
290 se = sd / math.sqrt(num)
291 if (arguments.marked and locus in marked_set):
292 output.append([gene, average, num, sd, se, "M", "\n"])
293 else:
294 output.append([gene, average, num, sd, se, "\n"])
295 with open(arguments.summary, "wb") as csvfile:
296 writer = csv.writer(csvfile)
297 writer.writerows(output)
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 #
394 # ~MMM=:DMMM?, +NMMO=,:~I8MMMMM8+, , ~I8MMMMMN87~?8NNMMN8: +NMND~ +MN= ,$MMMI ?M8, ,OM8, :MN+ =MM? ,MMDNMMD ,+DM8I, ,,:::~~~::::::::::
395 # IMMMNMM8I ,I8MM87~::+$8NNMMMMOI+=~~:, ,,:~=?$DNMMMMMMDOZI7ZDMMMD8I , , $M8+?8MM8I , 7MI +MN= ZMN, 8MD MMN8MMM, :$ONM8I+=:, ,,,::::~~~~~=====~:
396 # , ,DMNN7: , ,OMMN7==~::~=?8NNMMMMMMNNMMMMMMMMMMMN8OO8ODNMMMMMD~ , IMMNMN~ ,OM+ ,NM$ ,NMO, :MM$ , ,:::,,::::,, $MNMMNM, ,,, :?ONMMNN8?~,, , ,,,,,,,::~~=+++??=~
397 # ,,:=+????+, I$ :ZMMN8$~:,,, ,:=?7$O8DD8O$7+==+$O8DNMMMMMMMMM$ ?$, == ,~, ~NM= 8MD, ,OM8ZMMO , ,::::::~~~:,, ?MNMMZ ,,,,,, ,+7ONMNMD8O$+~, ,,,,,,::~====::
398 # ,:=IONMMMMMMMMMMM8: ZN$: ,~DMMMND7=, ,,:~====:=$DNMMMMMMMN88MMMZ +N$ , ,7DN8= =MN, IMM =DMN7 ,,,,,,,,,, ,~?, ,,,,, , ~?$8MMMMNN8Z?~:,, ,:::,,,
399 #+ONMMMMMMNO7=:,, ,,+MMO, 7D$: ~OMNMNNMNNNNNNNNNNNMMMMMMMMMNMMMM?,~MMM8 ND, 7MM=, ?NN:, +MO, ?MM, ,,,, , :,:=$DMMMMMMN87=~, ,,,,,
400 #MMND8$: , 7NM7 , =?~,,, :?88DDDNNMNNNDNDD88Z?:, ZMM$ ,MMMO ,MM+ZNMM? ::ZNZ, +M$ ,MM?, , ,, ,,:=?Z8NMMMMMN8Z+=,
401 #: ~ZMM8~ ,,,, 8MM, +MMM, 7ZZI~=$OOZ$: ,:+???+, +MZ =MN= ,,, , ,,:~=?IIII$ZO88DDNNNNNNMMMMMMMMMMN~,
402 # ,:OMMM? ,,:,, 8MM ~NNM7 :OMMMMMMMMO: =M8, :NM~ = ,~?I, ,,,,,,,,,,,,,, ,~$DNMMMMMMMMMND8O888Z$II7777I??+++===:,
403 # ?DMM8?, OMN??NMM$ ~8MMMO?===7MMM8: ~NM= =NN: ,OM~ ,, +NMMN~ ,,,,, ,,,,,,,, ,?$O8NNMDDZ7?+=~:, , , ,
404 # , ~$MMMD+ , , ~MMNMMN~ : +NMMZ, NMNM~ 7MI , ZNN,, IMN, :DMNM+ ~+NMMMD~, ,,,,,,,, ,, ,,,,,:, +OMNMMOI~,
405 # , $MMMM$, , ,=?ODNMNNMNMMMMNNND~ ,$D$, , ,8MM8 ,MMM7 ,ZMNNMM= DMMNMMMMMMMMMMMMNI: , ,,,,,,,,, ,,, ?NMO=, ,
406 # ,~ZNMND7, ,,:~=+$DNNMMMMNDDDD888OZZZZ8NMMN IMMN: ,MMN~ +Z$+, ?NNNDO+:?O888OI, ,,,,,,, ,,, +MN+
407 # =ONMMM8~ , ,:=IDMMMMMMMND8$+:, , ,INMNZ :MMM~, , +MMD , ,, ,,::,,,, ,,:::, ?M8: ,
408 #8MMMNZ~ , =I$ONMMNDZ7?+, ,,=I8NMD7: DMMN DMN= ,:::, ,:~~=~~:,, :ZMMZI+: ,, ,,,,,,,
409 #MN7:,:=7ONMMMD$?=, , ~7ODNMM$+: ~MMM++7ZOZOO8O8D8$~ ,MM8 ,,,,::~~==~~:,, :+7DMMMMNNDD88OOZZZO88DNNNN8=, ,,,,,,,
410 #I,~+DMMNND7: , ,$MMMMMN7, $MMN :??+=~::,,,, NMD, ,:,,:::~=~~,,,, ,,=I$8DNMMMMMMMMMNMMMNZ: ,,,,,,
411 #DNMNN7:, ,+ONMMMMNI: NMM$ DMN= ,,,,:::::~~::,, ?DMMMMDZ=, ,,,
412 #N8$: ,,, ,:=?ONMMMD8Z+, ,,,, MMM= ZMMI ,=?$8NMMMMMMMMMMMN87=~~,,, :=ZMMMMD$~
413 # , ,=ZNMMMMMNI:, ,~?Z88888$=, ,:~+??~, MMM, IMM$ ,=ZNMMMMMN8$+~=~=~~===7ODNMMMN8DNMMMN+, ,,
414 # , ~?$ODMMMMNZ?: :II+~, ,=7= :?77?=:====?O+ ,,:,,, MMM, ?MM$ ,,,, :?ONMM8II=, , =DMMMM87=, ,,,,
415 # , ,, ,~I8MMMMMMN87?~:=+?7$ZOO88DD888O$I+~:, ~ZZ: ,$7,~??, ,?+ ,+Z8$?==??= MMM =MM$ :?ODNNNNNNNMMO: ,:?NNMNO= ,,,IMMMNZ, ,,,:,,,,,,,,,,,,,
416 #, ,~7DNMMMMMMMMMMMNNNNMMMNND8Z7II7$$$$ZODNNNMND$, :O$: , ,IN$, I+ +ZZ=,, 7+ MMM =ODDDDNNNNNN8= :MM$ ?DDNN8?::,, ,,7NMM8, 7NMNZ~, :OMMM$, , ,,:::~~:,,,,,,,,,,,,,,,,,
417 #?8NMMMMMMMMMMMN8I:,,, ~$NMMM$ :87 +DM$ ID+~78I, O7 :=+~ MMM , , ?MM7 $NMN$, :I8MMMMMMNMDNNNNNNNNNDD88ZI=: ,ZMM7, +MMN~ ,,,:::,, ,,:,::::,,,,,,
418 #MMMD8DNMDZ7=: ,:=+7ZNNNDOZ~ =DI , :7MM7, IDDZI, =DN88ZI77$N? NMM: $MM= ~: =OMNZ+ ,=7DMMMMMMNDDOOOOZ$7IIIII77$ZOO8NNMMD$+~ :OND~, ,, MMN= ,,,,,,,,,,,,,
419 #: ,,, , ,:+ZNMNNMMNO?: +8? +NMN7 , , ON~ 8MM$ NMD, ,7MMMN, 7MMO, ,:ONMMMMN8I: ,~ZNMNN$, ~MM? , ZMNND?~: ,,, ,, ,,,,,,
420 # , , ,:~?7$ZZ8NNMMMNO7I=, ~D+ ZNO=, , :NM$: =MMM NMO ~NMNMMM :ZDN$, ,,=7DMD$?=, :?ZMD$: :DMNOZZZ$: ,,,,, ~IDMMMMMMMMMMMMMMMMMMMMM8~
421 # , =DMNNNNNNNN8$= : , ,,~?ODNZ: :DM? =: ,MMM7 +MN~ ,MM8:NMN INMZ, ,=ONOI , +NMZ ,,+ZDMMMMMMMN+, ,,,,,,, ,~?$ODNNNNNNNMMMMMMMMD= ,
422 # ,:::::~7$I?=: ,~78NMNMMMMM? :+Z+ M8 $MM, =, DMMD NMN DMO OMM77NMI, ?8$~ , ~ZDDDNNNNNMMMMMMMMNMNNNNNDD8Z+:, IMN: I8DNMMMMN7~: ,,,,,, +$O$, ~$DMMMMMMMD~ ,, ,
423 # :I+ :ID? ~ZDNNNNMMNO?~,, ,:::::=7ONMNNNDMMMN$ ,=IONNMMMMZ:, ~MO ,7MMMI $MN, , :MMN ?8NDDNND$~ +MM~ ,MM~=MMMNMD, =ONNDDNMMMMMMMMMMMMNNND88DNNNNNMMMMMMMNDO7+~::,:,7MM+ =DMMMNNO? ~ZMMMMM7::~INMMMMMMMMMMMMMN8:
424 #: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$,
425 #=MMMZ$MMMMMM~ ,::::~==~~+I$8NMMMMMN$::::::::,,, ,,=ONDDO$7II?+~, , ,,$DD87: =NND= , ,+$$=:~, ,:, ,MMD NMI ,~?Z8DND88$?: 8MM$MMMZ:=~:,~~:::,,,=$DNMND$MM8, ~DMNMMMN?, :7$7?+==~=:,,,,,,,, ,,,,,,, ,,,,,,::,,,,,:::::::,,,::::::,, ,OM$,7MMMMMMNZ= , ~8MMMMMMMNDO7I7MMMMMMMMMMMMN8Z7+?NMMMD,,
426 #NMMMMMM? ,++, ~=I??= :7$ 7MM+ 7M7 ,:?ZZ$MMM8NMZ~+, :?INMMM? +$NMMMNZ: :+?I7$$Z$O88D88DDDDNNNNNNNNNNNNNNNNNNDDNDDDNNNNNMMNMMMMMMMNNNN$:??~ ,+II?=, , ,, ,?I??+=~, :MMMMMNM
427 #MMMMMD~ ,:=++++++++++=~,,, +MMN: ,MMD, :M$ ,INMNMMMMMMMMMM~~~?D, :OMM8: ,+$8Z$+,,$MMMMMD, :IODDDD
428 #N$~,,, ,~I$8NMMMMMMMMMNMMMMMMMMMMMMMMMMNNNN7: ZMMMM? NMMMNZ~:, +$: ,NMNI:::~?8MMM7I? IO ~I$ODNNNDND8OO$I?DMMMD$I8NMMMMMMMNMNMMMMMMM8=, ,
429 # ,:~?ONMMMMNNNDDD8NMD+, ,~?Z8NMNM8=, , $MNNNMM? :DMMMNDD8DZ7$+, ,8NMMNMNMMMD$: =8, ,INMMMNZI?====+I$$8DDNMMMMMMNNNMND7, :~$DMMMNMO
430 # ,?DMMMMMNNNMMM+::~++ZMMMM8ZZZZZZ$II77II7???=~:, ,+DMN7 =NMM8, ,NMMNMNMN$?I7I77OZ~ ~8D$~, ,MMMMMMNM8: :DMMM, , DMO=ZMZ,
431 # ,?OMMN87=, IZNNNMMMMMMMMMMND7IIII??III$8DDNN8Z+, , ~MM ?OMMMM~ ,MMMMMZ+ ~I= IMMMO$$= ?NNM? MN~ +NM:
432 # IMM8~ =MD, ?N= :,, ,+77?=+, $8MM7::OMMMMMMZ+ I+, ?NI , :MMM8$ NNI, 7M$
433 # ,MMN $MD 7M+ ~ODNZ~, :7MMN? , $MMMN= 7MNMN: +8+ ,D8~ =MMDD8Z= =NMD OM7,
434 # OMMD~ IMN: =8O:,~+$OO? :IZ+: :ZMMNM8= =DMMI ~8MM8= , ,, :8M?,$MM, ::, DM, =Z~ ,I8DDDN8$DMN~ MN ,=Z8DNDZZ= MD: ,
435 # ,,,,,,,, ?8NNMM8$I????++=+8MMMD$77$ZDMMNMMMDNOZ~ :IZ8DOI~, =MMMNMNM8I:, ,7M8I +MND7 ~MNDDM8~ 7MI MM7 :8MDDM7 8N= ~ID$, ,:Z$?:,,,=ONNMNMD= ?M$ :: +MI ,,,,,,::~~:::,,,,,,, ,+OMO:, ,
436 # ,,,::~===~~:, ,~+I$88DNNNNNNNNNDNDD8O$?~:, ,7DNMNDMMMN~,ZMND$8NNDZ=, $M? ?NNN7 =MO OMD$MM= MMMINMO $M7 DN: 8MMD: ?D~ :O8ZDMMMMD=, ,ZN$ ,INNMD= :NO ,:+8MMMMMMMMDI:,::,,
437 #=~~~::~~::, ~?78MMMDNMM? :+I$DD87?=, OMNDO$7$OI: 7N+ ?MNMN~ MMMNM$ 7M$ 7M$ +NMMO, ?N~ ~8+ ~7NMMNNOI= ~?ONZ+ ~ZNND,$M8 ~MO $MMMMMMMMMM7:::~~~~~~=+++===~~~:::,,
438 # ,~ONMMNO~, :?8NNMN8?~ZNMMMMMMMMMNMMNDOI=~NM? =MMM+ NMMMO 8M$ ,MM, $MMMN =D, ,?N~ , ?NMMMNNNDDO8DDD887, ,$ND= :O$NMZ IMO ,IMMMMN$, 7NO, ,,,,,:,,,
439 # ,~IDMNN8OI, :~+$DMMMMMMMN87+=~~~~?ZDNNMM, ?NM? :NMN :MM7 ~MN ~DMMMN O~ :DD, ,MMMMNNOI:,, , ,=ZODD8D? :MMM: NMZ +8NM8, ,, :~ ,,~:,
440 # ,INNMMNNO+ :=78NNZIIONMNNDMMN ,7D~ :MN~ MNMM?=MM $? OD, ,IMD ,:8MNMNNNNNNNNMMNM7: :8~ ZND OMN7, :NNMMMMN :8MMMMMNZ=:
441 # :O88NMMN$=~:, ?MMN88NMMMD =MN? =, :NM +7$NO, =N8 , OMI, ,, 7M: ZDDND? MMO ,, +MM8?OMN: ,::
442 # :$NMMMNMM8I: ,8MD, +MMN= ,=?77=:ZMMM7 ?MN ~$+ 7M7 ,DZ :M~ IMM8: ,8MN, , ,,,, :MMD,=DMM+,?O8= , ,
443 # ,=I77$ONNNZ?+ONMZ =$D ,+=::+$8NNMNDNMD7?, ?MN :~~: ~D7 ,NI ,M7 ~?ZNZ?, 8MM~ =ZMMN~$MMMMMMMNMMD$ONMMMMD:
444 # ~DMM= ~I7=, =DMMMD7MMM, :+?=?O$: ~N: ~MN88D$: NMM=, ~MMMMMMMMMMMMOZMMMMMM7::8MMI
445 # , :DNNI :~IDMMND :::=?II?==~::ZN7=+I$ZZZ8DZ+~~: IMMM~ ~MMMNMMMMMI~:7NMMMMD7,: +NM8,
446 # :NMM7, ~MM+ ,,,:~==~~~: , OMMN: ?NNMMMMM8, ~NMNO, =MMMN?,,
447 # ,,,,,,,, ,$8MMO= ~M8 +MNO: ,MM~ , :: ,~, ,,:::,,,,
448 # ,::,,,, ~ONND+ OD+ ?NMD, ?? ,::::::,,
449 # :=+??=:,,,,, ~?$D87I: ~Z? =$DM$: ,::,,,,,,,,
450 # ,:~==~, :+=, $NNNNZ~ ,,:~~: , :DMMMI
451 # ,~~~~~:,,, ,,, ,~IMMMN8O+, ,:~?7$Z7~, :ZDMNNDNM8ZI
452 # ,,~~:,, , :$DNNMMN8?, , ,~7ZOO?: ,:$NMMMM? :7NMMD?,
453 # ,:~~:,,, $NMMMMMNMNO?~ ~?ODDD$=, :?8MMMMMD?~7NMMMD$~ :ONMMN?
454 # ,,,,,,,,, ?$DMMMMMMMMMMD$?=~, ,~7ZZODN87????I$ODNMDOZ$7I: ~$ZDMD7==~ =$ZDND$++~,
455 # ~?++=~~, ~+?II7ZNMMMMMM8$$$?~, ,~?II7Z8DDOZ$77II+: ~?IZDM8O$I~, :??$8MMNZZ7+,
456 # , , ,+D7 :=IZ8NMMMNNMNNO$= ,:?ZDNNMMMNMND8Z7=, =ZNMMMMMD?,, :ONMNMMMN?,
457 # ,MMMM7 ,,::~IONNMMNNDDD8OZI=, ,::::=+I$ONMNNNNDDDNNMMMMMMMMMD87: ,:~=ZNNNDOI, ~7$ZO8DDNNNNDD8O+:,
458 #~, +MMMMDI?~ ,~+Z8DNDNNMMMMDD$+:,,, , ,~?7O8DNNNNNNMMMMMNOOZI??++?IZ88$: ,,~ZDMMMMMMMMMMMMMMMMMMNNNNNMMMNND8$=,,
459 # ,~: NMMMMOZMM8: ,7DZ~ ,,~IONMMMMMMMMMNDZ+~: , ,=I8DNMMMMMNMNMMMMMDNMMMMNMMMNNNDDDDD8O8Z$7II+++IZDDMMNMN$,,
460 # :~: MMMMMNMMM+ :, +?DOI~ ,:~?7$$ZODDNMNN8Z7??+=~:, ,~=+?7I?=:,,,,:=?I7$$$$$$$ZZZOO8DDNNMMNNNNNMMMMNMZ+
461 # ~=, MMMMMMMM8 ,NNNO , ,~?ZDNMNNNNNNND8O7?:,,, ,~=7DMMMMMMMMMZ~
462 # ,:+~ ,MMMMMMMMO ~N8: ,,:~, ,:~:,,, ,:~, ,:~~=+++?7$O8DNNNNNMMN8$=, ~+$ZO8DNNMMNNNND8OOOZ$+:, :=+I8MMMMDOI
463 # ,=+ MMMMMMMMMDMZ, ~?: ,,,,, ,:~~~, ,NN?$NMMMMMMMMMMMN87~:,,,=+=:,,,,,,:?NMMNMMMMMMNNDNDI8MMM+ ,
464 # +=, $MMMN?$NMN, ,+?+:, ,,:~~:, :=~, 8M= , :7ONNNO?~, , :$NNMMMMMMMMMMMMMN,
465 # ,+? ,NNO,, , :ODNNNZ: :?777I= IMO ,,=$Z7+~ ,?NNMMNZ: :7NMMMMMNMMMM8 , ,IDND~
466 # ,=~, 7I :+I+~::,, ~?I~ , ,~=~==: ZMZ ?8I: :I$DND$?~ :?$8MMN$?: ?ZDMMMMMMMM7 +$NMMMMMI
467 # ~~ , ,=+=: ,== ::, , ZMM: ?NN8: ,7NMMNI, ,$NMMMO: =NMMMNMM+ I8NMMMM,
468 # ~= ,~:,,~~, ,:, ,,,, , ,, +MN8 ,~OMM8Z, :+ZMNDOI =IMMN8= ,=NNMO ?NMMMD
469 # ::, ,,,:: ,:, ,, =MMO~ , ?NMMMI, ,INMMMDI, ~DMMN+, NMO ?DNO~
470 # ,~, ,,,::, ,, , ,, ,INMND+: :MMM+ ~ZDDMMMD?~:$MMMMMMMMMMM?
471 # ,, :~~:, ,:, ,, :ZMMMMNNMMMN, ,=ONMMMMNM$,,,,,, ,,
472 #Z, :, ,, ,~=~, ,, ,=?7$I= , :~~~, ,,,,
473 #MD= :: ,,,, , ,, ,,,,
474 #MNMI :: ,,, ,,,,
475 #7MMM? , ,~: :~:, ,:,
476 # OMMMO: ~NMD, :=: :+=: ,,,
477 # ~MMMN8: NMMM~ +?: ,:=++~ ,:,,
478 # $MMMMMNI,?MMMMZ ,DM7 ,=I= ~+~~:, ,:,,,
479 # +MMO~OMMMMMMMMD MMM7 , , =$~ ?OZ+ ,:,
480 # ~NMN: :+DNN7MMMNMMMDODMMN+ :+?, +77+~: :::,
481 # IMM+ ,NMMMMMMMMN?NM7 ~7+, , :+$I, , +8? :+~
482 # =NMD, NMMMMMM8~ ?NN, =ND? ,=??: ,8NMMMM= :++
483 # +DO, ~ZZ$ODI :8M~ :=I8NMNMMD+, ,:~~=: , +8MO$DMD+ ~===~: :~~:
484 # :$~ 7NMD$, ZMM8I? ,~=: , ZNN7,:MM8~,OMNMD8DMM= ++:
485 # =ZNOI: ?DND= ,?I~ ,,,: ,$ND+ ?NMNNNNN7+, 7MN, ,=+~
486 # :ZI: :, ,=7: ::,, $NN= 7NMMMM7: :DMMMN8NMMDDMN7 ,::,
487 # ~?= ,,, ,ZM= DMMD8 ?MMMMNN7, ,I+ :~~,
488 # =+, ,,, ,, =Z8: +$~
489 # :~ ,,~~,
490 # :, ::,
491 # ::, ,:::,
492 # ,, ,~
493 # ,, ,,,
494 #
495 #