comparison aggregate.py @ 10:fa51e5de0cb3 draft

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