-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathwordle
executable file
·571 lines (477 loc) · 88.4 KB
/
wordle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
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
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
#!/usr/bin/env python3
# pylint: disable=line-too-long
"""
A shameless commandline clone of
the OG wordle https://www.powerlanguage.co.uk/wordle/ by https://twitter.com/powerlanguish
this time in python for playing on the commandline, by hugh (https://twitter.com/33asr)
with a little obfuscation so as to not spoil the fun too much
"""
import argparse
import gzip
import json
import os
import pathlib
import random
import string
import sys
import termios
import tty
from contextlib import contextmanager
from datetime import datetime, date, timedelta
# data division
GZLA = "1f8b08001a4be46102ff4d7ccd96a43ad0e3abccf9d6f3467366618c01571a9beb9fa4b29e7ec229899e55d7a9ce4ac08e50281432ffe77f7cdc5dfd9ffffdbffea78665f4f9438bad7de60fc738af63fee06ef70af387258df6fdcd56bc4bf387f076ebf7bfb27be3372dd4f7f7374770fdfbe1f576759b3f9c650ddfcfbc5c3dddf7c33de6d7fc61affc9eff460cdfdb5842f6b8fae2faf7bfb610f7fcfd1ef753bef7bcea125b0db8315f47c353f452bed7f22595ccef69017f5eeb078fec3caee57afffee6aa11b7b1a5d21a9e22c55f7c73712f7cb3dbbe8f73b92b7c6f63e42dacf387db3e7dcd1f7a75f7f7ea65f4b57cafbe9625e07bdcdff75aaddc812b7fb9ef6fd6b8c7cecfe0917d1a1e17bd22b6e08c67f4dfab9791573cce6f3ce70f29e690713f27d6704b5c96a594e5838dab5cb158b5500edfb38494be9f89ef82f56921ac5a96fcfdf027b8fabdc45a5dfcfeb0d488e7b20547fc5c2e6397ed29b0865b1ae7f73365db10246eafe1fb9b502bb6b2ddb1e2bfea3e186c01ab6a41d31dbe2762357ae9e1fbc8772958c3ad16dc613bea58701bdce525165c3dd97e253e72ed88ba8085da4bc6f7ec25e19b2dd21112a9940bd1a2057763c536a54fccfbf7afdc89784e6ec1e3c496f0cd3ebeb15fb6f23bf6b4d4fc413a8cc4f06bf84c73c9e1123b03c0f6dd632fae8a2009ade187cd9260c57f05dcd82b2ceefbecfb886965cc63c5ced27163ceb201e9e93af2ebf8308cbb25fcf7cfd77263e9cad80f2663c287d7c1bfba622adfffea37b7c91746dd8f1bd88b9083d29c9f71cb0721b1d78204b13dc51aaee50fd16bb18a0409b52019ef52f138bbdd10f3829160e107f8b2ad741d0fd8f19b6b246c9ca116b6db1787985f873f3ebc0d84f1167f1900b6cd17b65b71e856e4453b193657ecfc730b85ef0ffe8829012e2ad0e65dd617823632b4daa8cc77b7c6c288c2e3d80660556be0f2deb508010a63deb6548956f157b500696d11b086ad24fcc61f5c8dbd46047ff865b01982e336c25570ad6e6b0804b035fc5eab1e317feff01dab238a6684e869398ddbd06fdeb1e333067a3ee012bc9fcb0016b07cb8f322d216e2066bca25889bc01878cf17f6ddd006f863bbfdfdc1f9a15ac0ecb6d4c1b274774584712dd88b91e3f651696b0c2d0440b732d150ec02b6a0c71dcbb2b8cc4266a875f1c658a494c2ff8d80abaf95f56b736fe6d7b2840fee27ef1fe221b3bb2444663be2b383bff84c21c0d6b220ad0c72b12c77cc9e8523e27e5e990fd8066bf77d3c69ced4b388c28a790319d4a63ab0292932a9fb5158104b642d381c20e54a4f36950dfff56284070b4342ae4368196ce0d92f37f085237956c66441c1e742a2f90f57c3d96a3a007e014a7837d28bb7c1d81817f6622d2b56deca046ea33b0f102efd107c15d4a6fee4452af89eb78130a1927f6e018985f2073f53c715c86488fcb698f84267d9b42ad1949528a347e18ab59ba5e4b44274b0dc60356e216d2f2ba1bb7804643b03b2b20792136fc05ff13def88b2f521116a8ec1ef522a37023b871bcf1e10fccd780bf079a8dc1c81a06709df99f888bafc21c1db54da6ce58963aa9e8636584cbb246130b3d0db3a5f4c463219fb73a07a76c4842d2e95558f25d2ea2016a1795709680e37bf248671fb6f60c16bf9107f8e81443b950e2d39dc985df4d49386ef670c6b12591cbf792b1fdca15d73ff225bf9256e5c89915052c4174ec046f0b71796d756570952ee6f48fc0506c9a168b1402737361e453250df7a645c744237ff2a56fd15f2e2b0ea49fc61a89f71c545bdcb200c5be8c43155e1cd55ad06b3bbc70becdd8a3196ee1343128f625e04d50b430754bd44aa664c865b69a877319e016856137686df324ed4b8418a6e35012161d518b96ca496dce653c6f7339da875ba0cb8f02a377355018307b3c0e81c7b07fb9a037758ca49665e562d1d6a5c24a7bdac7520e47e44e70871f65700b4b5f0eab3101184e3098a7eb1761b6e6097bdf3ae20f81bbe30e60bc1bfeb0bddbd8d2470c0e39cb1739d1de8411599b4fa5e0b0a07576377f78bddd6c3ac722ff8af888c0b466e4038a3650898f99b20accd358e8daee4f8acb8c4a66c3232a97a4a247997c8b0e94436cb4160ef12b898a75bdd77c1b3ea85a5275062260aea4e60acbab12390aaedd207a0c792bd89c0583d24212fcbc2e0e742b9eb88dcd30f62de829fd4485d5248441b1ff914c669bbd20a95715c8cc345ab61518cff32441109fc60552d2ef1a4f5f8004096b1a364bb14c1450d9f9d5abcc8ee86ada21771ddad5666927ff41713abbe9f7959218b788a97e8e5c067facd2de8b763325ae7821416951d39e1a2b7810c302154fec650f97bd1e299e659cd9a57f4de7145998816d78c43d66e23ae7fc4cc18be0b553297ced201ffb519a244d6ca7aa2ad50879859a4eec3ba239463120f6bda2a6f839062b589fd975109ec7b5ca213d527a458eae3c3dc8b607fcf841d0b579efcd96a019ba3ae7eb072316de35e64a704901a3c70ac3952ac24ca67295cd905b0db72eb89e5b55c6ec8e5c2901846df2f962d645cf3e41bb6ff6f6e25e9c19435763ca07550d41c501d9a98c36ac9f40139d981488682f84dc83f05ff65cff3bd5614d90e16c724b74d3d7e219c8a66b4cba95308282ee197f5ebbf11eb0bb89a211aec224b468d1099e73891c29b63cbb06911ec5a832549f42013c35364f0dfd680fd21a97b227b6705b17f2fb1ca019e79944e3c0c409b0944e06c857b514e52884d75d0883d03203b88068b7b890486cacdfd80db5c856dce11af8bad7400f66e85f16cb7833261114e84d4b3ef85dd5f3f2ac8c096241a5427c2e0b8ef47797a99675571abb695fccd8b34de021c5b3029004ab6cac415ff43efb9ba152161dbde22d872c4adba9d3166df8cfb2957445db66b576a3becad2c0bb071a71e700fb9aaff42c6d5b8255235e6b2012d50bd1782cc5d49264f5b5487402214d8b5562e26ab43731b1b5eab179d9092d94a93759f629ef60f1eb98515707a59ddcae4fc3948d6e00f5c284b8708fc51a219592a4436571a1e8757b73e055f3856c2a09126ac869536a96164a7f6d1dd017213fa8214085f764dacea2558dee33f34c6b5e62e65e697134abc8836118f6c49246a4d96d21ea9c1fa1464ca452adb54cd0ff1b12daa5135de8b34b7ea40ea9871ab4d3a893d306aaeb58a106367164815c122046b81a80093e95dc2558314d4944dc4f5276e1b6f239dec1478875e7d65b395bb10b42b302a2b85730c9eda0ed59e4378b84b4658e353dfd9807ba184a1311bc3488dc8b280bc2eef58b11cf30f7670ac5269482f8d9c129a2a4960b30e9c020e7982b5152b6f83028e4138f8a181317e6882022bb4d43c4589ad716d643bfc2fa385b8b1f066f0dbe3a061316285470e8e371fedc1b81795b2d860488473a19876b3f734c287526bab0b2e6abc178f6c44fa663675884ec91e2b331d505c42224625f58361a572728afb59dee349dfb191755b0e16769a8d5b7089d813066f11bca6c49fac598a10189a85a894ff8075b65c2aaa0580ca569e6e94fdbb53f17597b4a6d10e0a2f6c618ea79576197cc3dd5cf9a5329e0d5ba06f5889c4ca2f915adcd4a5b8864138d698c20775a4cbc8849084528cd8e9ac4d8843adcfa12ab3580bfc8b10f5fa735e34fc3a26fec252dbdcfb8de7b29615fac62019b0f44424c49c1c239c9a954514f51fdbb986d0ea22d2030bee3f1e8ffc8ae4b476cd4458662bd443262d4cccca24f67e6918640406b963b8167e01a76c85bcdad2495b4ec6c6b8c49fbf9ff91992b8bb03ecacc6d980129a256d5a67cbca8d2392527809d26fa3b2195a937a87b7526fcf1c01b4cc8218bd5ae08bc5b78a86d9c6454ad3cc9dea16648ac10576b01f44a4ab90542c8317dd8c0851c049c8c155bcee651cfd514a71f3ffea3b39c96a1bc81e36f1916feabd352cd40ffd58a0ab5f24c95b62c37b3cc30547b05a0b9fb4fc11eba63c42818b82647953685d94e6763f434a3bf2f434c2e1a99daa281440e56669fe47dcf01c0a709a6354002b969283fe33e390abca2a731f24db8755ea84273d30c838ad01bf01833b470917f3e2add86816865f6ab46a1cb3851ea9d7694aa512d09520cd13c3bdea8e952dc0e91cc770cec8acb460bb01b995f39dddb18b34cef652f4e2af564756b924a69eddc69b85ec51697aa2eac85d7ec582455852013d0806e611b9cccdb51e9f6db29ad0d983609b4647e9ff0b0b14188b15ea48b6e09a83b090c555d9c424aaeae80d52de8c848ebdd8d40a2d2543c55ac23e80bd7fa34aa8c75e18ab8cecbfc8ebf6f40c295c54df4439a2720dab18a3d36cab7826f522d927aa474bc2b189e5c0f098b005c64ec9766e729b9634473b252d16b654168e7f1c84fdb173a9ec927ed417d8cd2fc21fe9f3c4f039d74b2c88984ed69080eafe791c298a4b0808a49f20a44d11b1f1d624dd9ae3c084e5d5838aef8fd48326f133588de488ad91361f24edebb395d2ac0c3f486e6ff1b19482aa03b944e69cc8d074632d6858f9754871edac6897611d459ea87953a1fedca9ceb58ba5d6d21561b30616a925a69d242750dd35fa8dac0c141fac2f646be648ec5b0c8faacf6147a0726b8c11119545a4e71ce3c3510b87c89ac8af2e82985d4349648886ae7f547c611f2972f443fe1cd74fe276ff629bb6c1c9f56e244ea316dc6ad6b2587e91a2f782be7b31fa43c58c14dd1f0cda4ba3ba4573735b3a26fe9063c1fd1516f100a40d6f426e14aaafe144d7f6df2888ccc3b13df18e41db6eea5abe120f57ddfceede6ae477b25c470745568db3e5c594dcba5bb29d9b7cec1a172e117ebda6ed549fbce30c68e4bf7889f2696443f340b1be1d65823ae45c3a70fedc23473f1c5807c95073fcbad26571513fa4ccbb092a0f01f5a2dedc3a974094e0caef4af329c1ad1248599276fcb00fb6c053826509e0ac6d8ecf9ecac83026a42ce3973896d94d94ce9b5fe3c9500f5cf9668daaa7584d12d8d50f5a37e0d4f4750af5303c6cd644a8e943477605ca238690ec770a2b9a35351c49848bdcf85c92e629eb47e3e09525401e213a7056b581d60b73a0a61e64a9d2e7c7a22ac36033448a8f92fc42367156d21e4215a535693a60f4805386b3a8befba7f3c5d56f4d395dda1dcb04cb9f91b72572e0883874a778b85a06ab48ec58ad1dcda06a71a3fefccc387c1113e61050bdd5a80b958acc5ea60aeb2673e408b2e049abfb7187a4861b7bc1ddf11a21b9f3d14e635da57042ea1c3472dc6af1a6bd61a1b0002d778d76aff42331201d3d5d8b26f2cd00c87130075e675c9d468eca32e11f7d43a379e3cf60839b5a3c5b544780e5846ef6d43b9b9aa824a2302e116c19a4346f63dfd0333bfbaf3912458bb7b21db8d5fd75f77872fc6339a05f4b6d97ad2020e52c2b1356d2b41715b11402661a5c00b5aa9c21ed221adbd7440e1cb9747be5f7b44cd1fb328c626bc62039dd866c0aa7876ae4aac69d1a37589b8c65f991e1aabd38f836464c7f8211fcc4a96bd0b0ec29e2e0fcfec3fc9a4f410b84aadeedce8882487cde2b795495da7308ba3f85a4d4e80ab2bb6a6e355d55ab62f562b31f18e16ce8acb49081dc1c13948dbadf9c52d12df611d6391927c8fd56992b9c67b41cbaba554ad4af9fc189d8157f635069a3b12d73927eb071be8c37b3cda12d6a751dbae8225b94411efc2d134036acb30c06834d843d201ec728364bc0fc460624078e8d8b10331fb9487a3ddda7f037259209130a46739a6d51cbadff7a902132c065d9a2640d4d34820c0faba4fbb83eada253d1642133f0a4ac61f5eb511459263878b2b001b25932891504ba166f56b429ab6612aa8da35e0dac3f893d5aa858e729953fe345d0a71439b83c388030d4a25365b083b68dc33afffc2b9a928b0f123c7b8ac0e722a4b8953385d95bc9f98947eee5727feaec48e30748a9db4a6125e21877d16c6b354acd4726cd6899facf526812fb19e75228fbec124839817a533d30ee4721317172946466b06e4246b2bf3f8230e1ab87f3d2809820a31666892cd05722d2da5340ee6bd65f7e84b417a70349a41d8f3c7b22986fb3535742fdd0d5c708d4e3c67689c6d14a5d744fe236871a3ac74a7d3a0e8c26ec5c32192289c64ed9d9d15ef5dff8ff3c1e84530ae36b586297f6ce59099f3d479a6a7eca90834bdae04597ce1908f856cf3001af8133a94d7c23c9bf6a452b521bbc34f538e516e3e0c9001fc5ce9097325d701a7fec58f94d863d2fef53716c4bdd4e978ef5299d76c16de31aaaf3755e7d37fd905d03d9794d30ea121adb640a925d5e23ebbf54b6e828dbe5c931ce5f3c85dfc669fb488f07980b1e3b076a5402db1db1effb3f4180147d113b4dea2f0cbae90dd368dee58c384ca2974b2202acd218fda8643b8168633bb1ebe66f9a612ab5f74a17773b1e97e007f9eec7896ec2f2ddcb43fe163d4051b825742cea738daf768d8736a6b93fd8577230b78ae56e911524156a5fd35779513327d38b3be07d7349c305e298011a30a14a009c7a8b08f01fa90833d7b8719399130190e5f1989e62461d63ec9434dd06a50fbb553623610503e9e2631f05ed544a2bf9069d2a46a360cb7c76472bf6b2ce1503bec1f1590b34c45a75a09a3a2eb91a24cb6fcc14db48f668e722973b89472e0bf58df3ea1ac86277769997e6bcb27250484947cd88559d9d1c92b2c6cb4a1a5b18c6f334107ea428caf7c540ca82e54f2edc38d6ca4344718eb9d957d23fb6865e7e69d2a0e34e65628e0056394c5ebc313c602e4f2b4dd1c0621581f4237fa6451db4d32504e04ffa547cc63a5666ae74ecff3403325c03b62c4a344bdc4bed2d9d069e7a6f17b99d1e43d68be16530188fcf9c1d2b1be7d991ab1facf4ee328ca781398ab826cef151a98d2c0ff65fbb3809ebce9079725733328dc752da215a1a1720d2cacc703fee237540d343c5cd7d4a36db815dca499321762dd48d4f45c21ac44e0b23b35c9dd95d3965784b49cee574b2576135a68ba068591899fcab32d573fa88c840dc9d357904c3df948c558af4a5b235fd90f42cd123b4c885dbe3fa7892b9b9415c34923aae9a8937e9cf717ae63846c1677e8266910763e33e68b798be1b1e9321c86c83f91ed282609b6211cf5664eca07d1defe75331d6e912fcdb90266cfd363b17361aabbcdfdb233f6e51ec22ea680615a1b2ca8011299d192302e4ae72aa2cea6ee6e009fdb2848e7906e143171cc7679fc79d4e45c83a07d9a2fef0c3c4a840b25d286b10f0c36f079258d4c9b7c389d8a2cd9dd35b68561279ecd6b92cf1174cc6e015fd45a89c4a871476e2a15ae9280a6a012ec13fb14bdaa41f4629db85bf9183ddc87f16d5c736194661e57f6438b7f4bce8fbe258d04a1ccae8fd780bc3a91334ad15b026eab44df1d33c81b15d22ff67a12c7f7084d43c55eb3dc9a174f137578d8d335ff9b1f5eca59216fae28b930f448e0e757fcc8beea4629d6c346ec911b950f89d83358ef8b93e411cdb9a6c04c97db089386411b1de13b973696a76148e48a6f8b9aac23e0c1614d432c6a1cdf9e7974892c1a5fb7177bcec55abfc00e5adb36f4614bba44e580afff9d9586aad6462c46f0880489827958a3836bf87eb63d70231cbd27b27916607cdc9fee268edd8143f23df48d8a92caa63054dbde53fb4468c336879da6fb18b3b9eb26095829070bc79bb2d4a0dc6a36805d40908c92ca74e522c4f33621571d1176612699db30b20a5d6efe07b8cf7d258a2a38e936656b9b881d8c6ac919e3b237372c8cc91717a4c35f47deda56b7e81f6444381452e65236f3c9f7254a0e874afd1e5f5a6c7233107bb9abe76e90165adb75fa847ab173b0edf238f42bc9e5525349d852218454263e61ccd879d279ec6df1f07cd2ab59aac25cda0a71f128e9733c00d651c19c96889b67053acbdc654b12539dc90ef7390da2499be38b425799330e53597991e3c81158f8a8c05db5d1d75925b73734300ea7ed20abc3b43a1918cb4d95329ade13d586e1c6c8793d1084e8bdc08286d55f4c070964313830b7aa8387fefaab061c628ae1e79f6c40851a045041de2f14fdd25c0ba4b16234ff02c3a5373e9d90d18511da6ab9c4a324f06d550317efd4f9308e32d189f2d9aba2e8176e5f531baa8f199b29f064f3a71b08767b4210d9fe7107f59c8bc4e067947037cd2f4ed90b5d5cbe86239385639f7765a13c9459568695c80ee5d5aca291cdbd5724ebf164fb65232edf645383d5479e668a943277f29cb5b77ca43a68629dc6e5690a590799ef28bae9a0aad91e990443316394c7e1cff6b8bacb94de47f8f5c8426ce9f3427da9e2330926ba604478c1a5953699ee4d221140b48e48ec52ed627478a6073ac4cc3b00e6c4a6a382551be7568b168e5bba6e40667b2df534834f479c667e43669a36178219fcf7308cddd815bf50c492392e77caea75db944f48c96ed49ea373590c79da5f3c25ed521a85358748e63ce730f723f3e69a86810eef06f20c269858c91f3a0b73a17dcf3ad9bb71acea075ab64b1aa092f450c7b402cf86ae82ec249ebe6f008bf77f4942ce4aa5aa5a2ef1fb6aed3148afae554f1130f28cde992f43196bf7fdd0d694fd799c799715d8cf143d9593242901e7589af367a3c0667eb4d07126d7d508e379d4ad88a3b1f479967cf9857998117cd07f985bd538ad1c93b1dcf34740ee4fcec195ffaccb41cf0af68fb393e1c5c1a64221daa1c89be3c969546edd45729f62dc8289e654eae0fe027a20d16f378f4cc4c40bb74066a9a86e4e22e74167d68edd0678cb8c6c71226a95376f79587fb1ca5c5792091dd56fff0546f551853bdec959426cb6960984903fc49fb47bb78c4e3fcd4ca8677a5865f6829ec9a0159f941ea6d92866e27aff525f121243a7012832dfcead8fbc933c58bac65464ede344e30f56e79b6ad366599bba8eddc121644a80cac7888bb52f4b620d9484a89ea9b44b0536cb9c84f723fc78d252d76390d6c2b1851592ee590928e35bd1e1687b95526c5f27250b4c76cefb983763b0046dbdbc7aff5a66d55ba96dcfb9bb2f26db8a8134659e949de32ede09c91d10baa52bba811eb37c989bb72d0fb2ef8ee88e4a0fc271da1ea375763d1915283416cc1d4f490a7cecbb4461abf883e355519eb262fc9bc48a25526e7bbb0c73f87d7816876acbdc823ad83455da77a7ba56dccd897a64b2a5b9d7e6ce3094c341d725f7578ad2b368cbb1f3cc4c466763a3f117e1fedbbce5c9f3adf3d8f7026be6d435d2d9bac459ff1cf19b14a578cb102d28cc02145cb442d6bf0d8a8bea8dbcc8921ef87bcb78ae0191a029aa638f3d13b4c747086a6eb777459bc852d4ca7d4a0633b333b1d6f0301909e23c99d99db65c5d923f7a2064a3146b6a1e4380d13e7009459404bcf3cf994695ad3594e4e5d6da1005f5903c75d47f9a6034b1e188d6cb8efc56a8b107be7f9659e89d8d47fdd229cd6e3135ba448872e3d41b5c0c7ead10bcbf51af302597513fbdae5d80cbf6ad27590799eb33bf5a29227cd8bdefac2f7c08c48d734a78afd39195439f42f6fc1fb1565f0667b52d5c35a93de75960a14f490c5f17444b62a94f0ea6eba5e3e338fd4100aea73be0064724aaf1c4f2f8fd47970125139d92f4aa258758e830323e314781dcd3c03ce0794927370f6f712c419dda049d50df9a829c17d0cc604ef8f7c1d798e75e4e7dd111ad9bca92ced81666912e0358cc71cf87845d08c9cb2652e9156e4fd191869debda81d980a033cc0c2c33d925137d59d45275f0cd42f4e4f78c2d12d075d317a51c92289a96b9bf64009ce6a2f1dda229c5ee7d10c57e9bb9063d32759be03479057f08eae86a2412197ceebe52ad69f6ab29fae43af8380a8a2ec9ec784798ef5e9f13f94ce42c51c7695b371b61e0a48be8c4223a419097aa905ead7cb7d1ced556c22ba8eabf7c0b71c6c9a77ff15aa85a7ce267bb90d77d1c2c5e59fa27e90d3409a668bf7ff66251cad36a743283aa9943486d3943cd11f75fdebf15977e6ab2750feb20ed4274e734e6971ab6e3ebcd4e61cf2f3eb58c1a1a7e8072b75d30b22aecf7e12e7b35eb7c23f4f524e9a3c03a7deed63851e0b9e9fd71df48f8e4b3048ac60e371568d32df6afae67b18d8f0129a868e1125d1b924a7533c6911f19259d64aef77f8258e4dd72a56c3905a7334f937d41c1d64445e4780a74d82ef93e1f19f45facfeef83a9aaa9705f9e79cc2d05135c776e056e3b36853a6de06a298e5322deed2bb081400e5395d2eff0f6f758ac3d4ebb874b606275f1e428a6504068bd98fa2533f9267e50d3344c83a6de1549b2a0d3c9411bcac2fb353604347cbae05edc6e92493da5a57bebfa5d30fb0e85c5bd5b4f40cdef3550f898aabd5bf4b27208a8e70f2a50db4deed9a5f1caa56165a9cd16bf6578dcf7b7cd8bd69206437b13d474e3491b7edc6a86e8ef875201aeec7390be0bb86f8e7bbc6675374d2ebc24880d5e3efd66df1240537c51a28b0ca2dea1d269dcfb5065f29f336f964327ae1b79500d242b9743cc704f154d8dcbc8d4bcdf5ad83847dd4453c5c0229d9f2a9d7ec048d7562d6abb7c47baf91a49d7255e7610d8e51d88c5cf171e0089f05327364fc8c24e8f3e40b2b6c2bb83be50110a7b7130cbd22861cc98bdc7641ee1229201bd522cbd5b9c845a2c1a1b7becc03da3a2acb53e19988bd08729b7679b79de43ba6d8c258fcd4c78d49b4a10e60e45687622a2896ad2a9efd50dbf5d6c6954a40b346d1d150c4be29fcf26d3fd6a5e8ad776c78ef7f0ee4f462187f88b42f8efc36c78268e8a3311341c6da01affa45da9c7876b22ad8acdbfaed7aeb94d80eb541a5cc3472805efeb053a8657f0e29eb643d8fd25489a8ceb209bad6ca53e13f4abdaadaed2a6d3655f2639bb6fbfff9bfff0fa00e51d463510000"
GZTA = "1f8b08005e4be46102ff44bdc9b6b42c136e7b2b67ecf6b9a3dd72292a29d58b92a679f53bf879667ebd3910a9cb2008feefff99a6dd2dffe7ffffff0c82f703eab60baee1f237cd13f0733905eb2538f0138b202d8273070ec123cfe62450320ce4323b37c04d11a882c0a72acfee12787e0fae023f172535e47b40dcf380bc2b8aec83202a853927415d00c55e49589d1e81c7c52740b19f4e7e4eaf64b434010ab0918bf6fd0e7848fc738e90e74901ce531d7531cf2ac379ce238ad9d53f409fdc35e29a7795e14cbd1bc8cf9e4769cc7e390105e8d30628d243b563a00023e1443f0f484491f894e74310f4a9ba1fc84fcd828b4f970a73be5417f313869f65ba8147f09747f12ecbf411281c832af059a086b438378a77d9a711c5e25d13283d8b57ed2c113fd1015e71e53f859c6f7dca5f45512725832c2f6753a4edf082340b4ee5e2ed465b5d1ed5e0f2e5f7af4acccd7e7c720b2e9b1a89cb4950bd13283beef4a334d64975b14e7502869f951eb786e93580c6bf5635e39500b7495dc6c00b2a9f949d6d7a3b818a657309c0f3a66ada36a579dbd4d40d32305ae6b6abf16f3e2876eacbca20028addab0cb7a0d6bb31261828c0a05eb085a6702251e44d7fe5f4033ee5518696d2094802d2d3547106b86804d89a46dadd4d459046c276afd178f71a4e773aa381fcd09bf61682a08ed6eb1725ded30b3c8dc42fd90372712a55bff1d7b68f287ce0f7f81f8c6af2498569e91ad9f13928649aba813c579598afd70ec8e59ae572a9e4fd9bbf1ea2f8aac3be18e75ffe3d227d35c5febad53d6d883a056a1b078deda00c0f9ac47128cb61521584498355986216a80a0c1cb001fcae4a095399003ea978c374f1bb46adc03c18fe94d36083af40b513163701559047750747529de6e5e0d61f283daeec829b4f8fe25a897d9b02800bc9d8d49ec39615fba6e12b783c7b22f5940f5d2f78cdf8e150a70e07f93a9e0550ec744f035c34a085a08e16029ee3b403f2131d2e0e97b600aaafac392e643551035c76253593e54c52f3ad845d5a39848b4f4d6d2cb4888b86caf0d6281a6ead132cc9a74051449a449cda28b1f8a7661cff3c2e8a2bfea92145f73709d424222ddce004f43bd564f3b303bc60c165c9009e1da0fe65801fe2f2e9e782670de631102993668cf907fa9434661acc8002cc87fc6475fc98abb2939bb29cdf7cbaf5a9a84e6369a3914466abd8d453224b883469104e93868234ab72d3ac48d3ac34a745135062664cac4513e59ce83bc9e692018ce1c9e3d913bbd7a469e005c4e54f796689950e359b7468844c146f4aeab9063f17a527e34219a61c47fb49e72497eb3fa880fe621966808b07b46030e0f75321373e3dca4e99d4eacab4011a5bcaf4fc60845cdc74081c50f9a4065098adcaa634975d092b5e8dad788d90c56b0f52581594ac365f180a4ace45401445a56aa0b88ac3452da194e601f961295bce1f90b0536dbe50aa0623f1ff9aaac060f8a9937a779d0e5ca213a8342a13479d15609d772fc87c526ba98bfb136841559d16a5060e084005f4bbd336d06675fe5af86b7d04eac29581a8bac25f1597eb07847c8d02af4c400649e07151ebad5bc625e327f33b39ddd5f82b839ead7ff597d762bbd207abe7771a493d28ccf01fc833eb9fcafac740bf47924a1fac498379cd5425934bcd6afcb5e0b9683751ab6634037daa44c176b2d63c7688f5243d34b6ca4eb3d2eaea45a95e14c24535d1976bdb55bccc5ff5cd5f6f4dc7f54d8b62f03c193c4f46c893c6762e8ae264a779b2d33418d93929e79321ee3cb4283d591e9c148b81fc14422e5a4b18e059bdf23c270f4401b19fee2b50bd9ff4c1f3f24053a48c632773f7796b8f7f3e9af12f1678d7f4197e2ebf7941b8041a722f46ec8b09f18a3f1765f9ca3370380097f8030598135004ec410cc680765dd30f46062f0699b66804686cbb1a6bfe46525b5081b7a0da31d027da7c638fdf923ab5959c03025001fc380fe0425c3475dbca8c026facb5da47ab266ba14ea0c9f7cd4ef3edd444df2c84decc206f26e8370b983773ee9b39d7200bb4517d672d9bdf8f5c6eebdf822b0bde7cd244762f4ac6edd4f56e8767f62077d44476233031180575677ecf75cc831ff2f5612df1f13f1705f8f11a603f0c5f1f86af0fadee83ece2c340f46157fb6157fbb04c7d90d73d2e8c86f46c1acc1f967c36cf8f927fa8ca0799c397cdd19775e69775e6972af80655c137ab017c59ae7c49cf375fb868f3f84572f26daa0b835198df670334691afc2f9cbf691ac56210e4a269f4afcb16015c8660f3af8b02050d3f4d7ee6790232f008763eed783e04cb223f8e64aceb0ff469bde4b2f1bba4227fd3cea7bdfde01ae009d08f623138950c3f8aae037ebe7cfa2ae4d7a4bf5e7502bc80b80ecaf07009e0137f054a352c3f50be02bf07fe0ac70ff0432e6cb327a006037511c857b894c2d01220cfb6831a90c6aaf2af2fe801f949cb04ecc0ef93624fa43991e6b4019edfc9454ac0f5830610e0a3bf0a49ad7f0ef8b9c873a58dd5053f4b06f04c522b4995e0a5037e560fe0327a9c0189af5441a5c06bc4857cd5844bc1857aaf9514565258f1fce8d3491b3b49eae97e2e1550c8e7ae704eff1290d433f3d749c8a707f8eb54ece73501f8b9f043355da4e722f68bae7779b59f8b70aedf5f546ea32e1a296c417fb52a97b7579a6f3cdf78be69f337e57cf3d74db37948e143413d24f5092a8487847d27f9f9aacbd892ff141c3f78040197f8033e257e4f7c4a7c52753bed4a0c34c818fc5cf0dc70d16065f019f037f65f7fb6cf000e07e82f2d570c345023f4ee700bc60acd408dcd9993406ddeb902d41f28858e34af791bb011a9769a064e5168eb61d0e4e2370728404f891d938a25fc07159067c9be0c86bcc5804ad11469400a2309d31ad2c0ab3025f2fa738c638e71cc317c1928f189b892e753728007f85d5dc631b2390634dbea29c04a7618765cdd802303b84407e092ff048f6af924e473522d9f1414a384d3c99a418e002eeaef8e6eee2e4a8cfeeee8ef8efeee2ecf274a9e8e6fa00c4a466d9081a684bddff27353ceb7578bfa12d7d72b83dfeff0bceb80cfe0e505635d67a0c4ef2c18f6ac0cee3a4a30901f3f0d71bac190c6771851f83f4d2e9e458e67b9e2675c745ed0a102bf4f97c0e3a2f2b14db6fea25bf975cdc0cf4571ad2a5ebf8d9d82811a8981fc6c5a3e711261402eb62ccfaf3cc65ecf9ac41fa499358997d8f9cf87bf0c281c96229ea5880fc4ce9ac4d307bda4cd1d70214089e00c34da78ba9e4fa487aee759391828aea4d6eb594278fa97cf78d61adb40edd017125fb280c580a77ff9aa49c100178aae524df5c48fe64a4fb7f24cb59e6ec5498d01f9a2eff82bff40957211e07539407ede5a35797a8aa75ff8ef3703e35398d46803f397019f940c033eadab60c3650734f906e6381b832f810a214863e18f939a0e78bef0ac01364c3701def8790492a1199078a7a20b8ea44a6edc1516801320524780122318684c083a91ef809f849f820b017ab2c3e23ff8b75c322994f0c180a2cbf9008aa0f217e1e4fb078abd1160d37a35b03432c08f5a6f689446d3d862801f8f9f483849e96141159e323e651a49666d935993646a395395d9b662c001f069c8183bc8852d9e8103bc60c78548193c3363665eb42ac8cbaebfa47bf097598a64aa3bbb365a6f66f0cc0c9e59725103954f66a8cc6c0cf346c85bfb817edf9d72b1932fb68a991665a0d2a0b564c655831dd05f07e1b092c96cfa329bbeccb89a83162799e13487dfefe49d5d5b6680cd517ba2cc486ba04f89ba60a4cdecd132436e66c8cd0cb93951508cb499d54e6691939336c506fa94270fc80f5d26e7051762cf2b2ed44edef17cfc804f9486847b1df844a5480662508982869d4f52481996a2df2b0d5b22b80ef2c32e32335f64f68c067c72fc4561b29ccb75535db079cc4c3799555cae5a93e4aae541aea4b05ea4f0fa0e38a914a61b03f9618b974f6ded338bb77c914226a07cedfa8be92633dd64d66cb9d119d9a3e516343834cab951cead6e80626f14783b099028de1aacf2adf56abe29d59b32bc492acbc27c9377767ff9a641b2fbb3f1552e1f02fc68bf6c203f9fa002ff90d3875ef94c4dc0ef0f43ca43bf78f8fda1573e64f02b973aa917549697556a121d2ec18267076c8096bb1c697578041adeab942b3a1072c273228a13b8f834f4403a90c29b4f1fa27870f9e259bdbb4ac9f08f23ad0ef22cddb00e15e093aadb001772e14833f33be75f1df8f4c685a432d1574f5c9eb83c65a803ac0eb80495aa8fb810bba7e224d9ee808b36e995c58081928a24b0666a3953cb9962c91b9f485826ef7928cc180c7db60e2aa8ac89b56612c6f065a06a622d511b5134add90c94c2a639aeb22aa84d43656de701e059196cd30f94c1f6a781b131f5b7bf7154d7013fda2934e4bd6dde9b409bd9c6d46fa04f0b01b24b6ad2b3fa6beb3a010ef040067e9e15fbfafb5dbdbbed1a2edaae16d568128d255f63a66ee10fd094d4d8ddb4a08edf98975b50a534e6dc16494f1c7a441d7e2e0a309165e6e586a0b5a50517c9571b53b6c10534800037fc906604ad2dbd08f0c527ea8269bd2183e54caa039e257a6d593dae3169b6aa2516a75406141d7365d381ac011527ade90ef8f184a313040307e0870247acdaaac4740db16aabfff8bdf289ea46ac6a0b61fc5071278d967d5c63626d4caced3c55e088471ae21103f9b95c06f4e952d76b5756969961dbf5fb4bc2bd764980d3d8c7dd3a3236f88e481f56cb0fabe58705e743ebe550c94025f620e67d48d8a323da99f39d99639db96b8a0b8664a9c32c18c3f23ccd78565feea00017e7007dd27abe037e3c2e1e3f842cc50983532e2be1a89bcfd3469a3792bae14732c679da87e2fa3c493bcb200155bfbfc662c9a0090e423e08f0704a7320f6e01760053e024a43a3c4ccb9cccc714c0702ccb8143c175cdeca7b7814b2ce223bc84f248591328c04188b0732f0fba4d863934b22cb696c583a54003f1b40de539a003e9d19501548f83973ac33739a334f855c14622feee7a22c971d17ff1504154ba1e20a592ed47ba9cabbf4d9e6a90e09b9c15f064e40e9a98b07f8b4f08914568aa592548d6c1d94e64a03a824b5d2006afa0121d3bfea10167550be2a3558a9388d63f354e917f59a809f0b7ede8ae2a49ccf59793fc9ce492ecee307fc4538278de4c2735b1469e3af161600179a7a23f18d4a69a77e7f93b037e979bb0054003f0c17379e6f62ffa8c49c5629b3fb5313b5812408c671c3ec347876a8c0295027727e2c690c8628b8833e85a11266a0de6de001fca82a3977986d6dab84d11d380be8d006e4aaa4d20b5c9d1532cd8fd301030da74eba2b1d6641e253c625f3d7f58351cbee24613ae99b91fccf88f70d1e25ecab1169976a628703c882e507a7602854cf08ea0d0210018d2488ee3b107221ae82e7428095bf2a7e2a7fd50af0d798fa670e050c7ed979e372f3fb8dcb43148f5c9c2b821597437ea436df013f31037826a9925e1a8c6d85813aecee88dddd72f15306f4c9ff019a2b0d7600cf337ed4ad762d770d3434ed3efe01fc159578a99acc5ca0e87000784e0448ed78aac05722ad11e02f6ac753087edcbf30a0763cb5e3df3f174a63dcf69af74c4e33399592aac1868b5732f281670d717ba6be74ffa2037e28844c06735e810388401250083a6ee8a00ce6f6838f80c696a9ee469db675021469233b8cab7ba3781b852931cbcc91d6bc3fd4b2547a0cc6be72f612d8ce9c5bcd1c57cd5e876533874ab38d8293804f71c8490c34ebf934a41933473606ff0494a12f9ad17c557d7906348e5a0c344d78662b2f6d0403e5cb4b3fd380c4eb6065e66065f6efff40096306e1f4640e92c918a8d970563273323273206210f113714940f9c1255053e7ac64e6328bc189cbc55f0d9737510c99cccc11c9cc11c9ccd51503f7832258f1439a9dc70f69761a4e0d14a92352869de055aac153085e6378f014028343d0a52a0342662830e01339cd436a34739dc4402d9cd3138343e1640d4d81ce18b2c69f408be284a583e2a20f0629bfcd9cb9188c1b101d7021cbf9c133e5ac7b8833e73233672e33472d33072b33e729b32d8d474fc912ee19680d99a7c02735f5acf3658382e77111d5408937f080fed2617407fdfea7ee99ffd4dff3df572eecd1387ce99005079f341e6629c0cf79e1afc5cdc00224a0023fcf1f81c6c32c91e0cc71cccc998b017e74e632e77d52de77a2d8339f8662c9cc29cc9c3d01fa4d9e59a165a6a4ac3b3506141d3b3b8e63660e5f0c28cc409a039ec3cfb3c38fd65a068a9d813107ea349066168139502971724000e44767371d3c90819f1f4511a902b68159da2c0691bf229f227f153e153ed1fc22ad8e8d21c74333a7421d144ea20aa40cd3c1018a22d13213059568758956a7b3a40e7c2219ac9673faa5e72d17095a678e903a38a0028a2293d47cfc804f545ca6e21876385d9a395d9a395432283f50d1e513a0ba194072a1967529c68034179a7a21cd2cfe399332d02ad7e294cbbfa6b6a10bf506341b36b39c52cd9c52cd1c4575c0cf463854135bd75c299f4a21d48467adfd329b598326a058d89f1ac8f3c948c2de33b3f734b800457a324ab02b31f8b9e8af4bc290cc1a80232d831de0f78bbf74b66e40521b43ae0eb03ae08701a4114ed35a3db363cd2c33f29b167e53dd372964c79ad9b1726e6540326e2d0ff287c1e143381f7eff10d7c72bcd3aa59a39a5eaa086f4147dfaf2e94b63fb12ce9702ffaac0eba448ab1403668ea20c34e8196c8283bfe20ff09c80c2a7f2737904954f379f34f9729664a09d0b47480644e1b467ac8e901d21bbdb01fac4bea9b26fe29c68e60cc8400311674006249e250da742338741338741b3edb63d808b564d9cf818686ce1e8c7404b88cad8c2894f872420f64c8931da54b6159c011968d8a9bab969a02d796d94aaf4490c2804a991189066d636b50d3d3d030d44958d46d579ae81d690f5a658688797eeb5cd9c0a194884d264c3a443054ec138b79a9b74fe670e7a660e7ae6e67fa0fd69d37d3403550aa739730b9a2f9a2c1874f808027e340534e4b40da96c93b67c073e4984d2a246364e610c9c3c277281b4a7e93aa4812454ad100503be15b3fe4244d92a8967546f48261bc37b4332c9cda0993317030a8a71bee9a6898176be1caccc1cac74208a8acb896735bfc6a8dece5d9e1124b6b3fc804f9a0b9aec78cced225f6cdf3834e9a0bf64cca4039fb42ae0f4c4a08d5d40d3cdbbb931c4dd44f1481fbbc3f8f4cc4319b8032edafe3f2c6e1fa4fa0f6bb6879defc39aed61f5f544f5dc87498aa31603f5e5afe4510b57699649e7a7cb2455d2852b300b072bcbb40c2dca0eb86481bac3c2159865dab609c005cf3b91fa210c59260d7a1dae01d2055db872b270e56499645560e9860604975c7436d141bf47fe8a519e63c2a5fc40294c33b0e993aeb42fdc103148f821d23aad823f5c08a792f84a762ae9a9944f252ec94e3be072fc800049bc2e6b2c48da0dc6c19cd5cdfe03fd2549c5c22d890e15d0ef17b5a386bd4cedcf0127a00035861b04d557a34535d2f376aa8bb7979f9bf673f3fb4d7a6e3cdf64f926a737013e54ee332b9c87d6f2259c2ff952d75bb83761306e892e5c9758b813b17015a243027e9f1ec118d50dde78bef173cbcfdfb409fe7019236d0779febb80a189daa1027c7a148506870e2ba0144a8761e19285816ad02daa6ee7c8bb5b941e1780c8270a410b18034ac351088e343bf2eede7259c73461b02a3dabe7535669e8e6e6c26d8b0e7291510b0392ea358070d861704640716907dd417e0e4a83e1c2315c389d9676d0ef0c209c957450a481320c45d5cdd8e2185b1c438a93c9ac0e0a398e73b40e1ec073919fa4a1c9409126b567ae782c5cf158b8d9b17052b3b8fcd15f9592af84c368c3018d815715d461b062e1b28641fa01bf9354692c74e0d3a51456eafd1ceb16038d36ee24a9270d52c73a8b7bd300de7487379edf39013f17e5eba6c06f4aec9e1429e386fb90d3cf584b2cbbcc2f1828191cf42cbb3f46387b1e620d03cd20060190e77ce147dd7c97b9a7c54baa6620cf5eca6f0643017ee1b2c6e265e1a14305f8b42b1cbab09710cc20f3696cfa3ae0e7921f2d4a0d94774c4219a8a77847321c497524954ecd158f85cb1a8b9755a585ab190b573316ae667450ec6151967504b9209f5fb864b16075aa039f34da78ba834fc4452ff092e42c5cbb30508fe3b6450725436a000614025dc653a7dcbf58bc56b906a7522821c682cd2b83c301fabd120e73ae3f29a873f6002e9a7cb98861a0150807071df4897999838385fb170bd72e0cbe7279ab5f78ba957ff3fb9bdfe95ffe4db1d0bf3cfd8b0388c5d3d13c9dc8407e1ea2d0b67d79594103e313dafb0bc2e10599b081c34521e7bf217f36a83f185590e90ec8841744c1069a2f326d3ed3d4b3c333b355d6450c038d5a087e17f4f00d489814f20db60ce0429af7479f6417a283fc78b2fc223d41339a8117a87610e11a78e59d9e9243c465ec731774ec1724b70b725a0302a4376566a29cb4c4ca52ea33700e50c892942ea8d61b68f6cc7422c4a10baaf5066a90e8cf1b90d34ca564ea827115c1e6826073419eb920cf3420d2acd5174af2066af3b9909d42de0bd92914824c351a680ac82cc8d18d5f103f2e28c077c0e5f8812265aecc95a44ab468400aa5c2b7206c5cd0965fd096b7963a79409f4e7271ba1da8007eb4ffca0c17c8183b54409e2fe26a1a4e73a3769a4624d4e60de8832dfe804f64b0d13d1bf962618fd4b143022a801ffa0e737766cd8f1c7241b57e4191de20fc00cf349b9b46c2be00a1e5828ebd0129fc1005cb83ccc8961fd2fc10327b87ccde01c9e482f871415bbe43168c13c305c9e48292fc82f87141ef7d41eab8a0f76ea0853452c705a9e38205270322754a21aaec0b72480362671844717d4171dde0c485283cf962f98d1cd240c582b0b1837e97c9910ecaa90e490d0210018d1b356b496cb001ca57268afc8ba2f1896261ef591b39a5add65614174d1449a08116c9f5d1985099c84ed97a351887534b6387d858ce3536868d6d60fbd35f4daa5c1d2e818a0e65f20e8f40d58dfcd04055d916fe6261d6588f3599d55a90311a68fa43c6b8205a5c1a4bb5c6520d61a3c1d0085a1a535263026a4c40481d1754c797160990c55bd3919f01014632c82aae252d9f1a7b192c0b2d68832f68832f687a1ba40cf0e9e47732988785bd0ef2cc14d098021a5340935a660705c84a0f73460bfae10b42cb0559a501296473d4a4bdd6e1e7821f8d90482617f4ba1724930b46900c249c4132b9a0b3bd34c6a85ba71e06ca85411444fca801dc9342bedd90632fb7e72f84690f0dfb61698486f68286768747a08dd893b4477ba8c1afcebbdd24f3410ea19c4328e7d0dd75a8ad3a645f0ebd5387f0aac3253805279e350f3a94420d822255897533157279f397e61d8741f20e23e43f9d68b83f0d3b5da6325c30a6ed30a66da09cf64385ff41dff60f90a677870ac88f4ade616bda2d9a7c3b8c64b89717681dd5452949a014aeaba2d84821d6950d54509b6c5918e099f460f1d8a129e73002e0d8183abf8db6e1d8d9198c7a775e2a07ce9fa3015892c7cece6165d7710bdb6153d7a17de4820c18bab0e0c745b9902f1b75003580207b562ec84a73874740389a265c284e7e4e3eb54b2eda1319b81f5460fc1e65fddec53f95a1c123187353871bf808d41230d66aa0bcdba67603148ec3b3272ea97f741191806a8a9100658ab083628f8ffce4614dc240751aa550e430a0da054bf2acdb5506eaa7f1597e30fcd86e3b0a144ed294d4a102b7a0c98f4e305d5ac749844b7edcc27629a86127126f83fa486acae3ca9b81468094893d13601da7155d3759bf4bf7dbd63163927289ec24dde574e99d15f2f719016606994cdb2892d2b8a2c5922bfbd81c75c065985fe830f25ea8380c8d1a1485a39d82fba7f34a83b1227255ba4fb6e41af2318795cb0e3f97114e95e1afae2b3d0107c0275577655cad1a8d1d37ef5c6580c586a4ab8c36b658ca02d243bfa8efb17873e7ac5e704ad6e44ec6b1f3e093c43eee2476ec31da783466c60e453036f2ee92a9588302a8895e9236dbce7c4c76061a91aefd910b8570690f6beb21d5e9a54b4cee6aaa8bebd698703d1aa89b4cae395644ae150d3b4ce2d64bd5ea3033d8edc15c0225f52dbd2ff79620da405de69d3501dd8ccf37e3f3adcb3eee26f68fe66ef77163c56830e332eea81a8c65b3fbacaa9d8f16e4062a1fec041a28851f9ae827f33b93dda71097aea5b84fc3b32e47180c9d13674be3e1c23ac13d521f728f164b8e9b5c0ef3801d46dbc018e03a49ecb34e927976a8c029183dc5e0fa813e69916cc0ef0bbf2ffcae0b5c2b278feb24050c83aadfb56c5e398b5c398234180d69e572d63a49177dc5f8de3afdb223019741151c24ec206187fb7d52143259d3417ef40ac3ca0dac758a8413f95d566856ecd7addc785a27896b3a64804f243ee504e032d687ebf48f64483c623004532bc7942b6bb69535dbca79e5ca79e5ca35a295e5dc8a95390322d5c1c1cacda095d3c9753a8954373b5696732b87922b6791064109bb4e0578dd2a045d2e5eb9ec63403549756ae508d2e0ad644852ba72b567e56acfcad2d1a009eef40325e3430a3f787e707908e7a1d93c55f0c58fe4092b278f2b078e2be78c1d2ec1c9a78b4f5fb9d0899c24a5061e504b70527f5d9d24ff2b878006c4ae416fe580cf80481d71ed51a0a5dacae9dbeaa4c46230a6bf9573b49573b49553b30e7291f472e5f86c75d2055db175b662eb6ce5d8cb807c6987b87210b6bacc5f52de5e1d8d96f3af957b490624ac8e45e9ca41d8ca41d8ca41d8cab9d5ca75a415fb631de447a2fb1543642b37950cb29271f1fbc5ef346327319d01b96884f3fc07f2f390f85f43d2b5dcd5d37e3cadc54b9cbe72cc643066ab0e4da061d04bc0be72edc240032c5b86d54b9fdf402dc14bb2b4622ecc406dc36ba9dfa102f2a373e1950b1d2ba6c05636232ba74b360baa7c3c8d0d7b5f2bf6be0cc6d3572bf6be0c34461964804f11cf1117620f1a2a7d1aebb1150b602b67522b675206e48296e969991c3cad5ec65e56ff6f97cbbfa68431c072ccb472f7c4c0e3879069a23cbf62a0398e775856ce9b568e9956eea77490e78b32645cf597264dac7bad1c33adbcdeb27296642b7ed2fcf9b968d879c970dc8a99af15135e2b37560c0e2046e0e7f2083478b29d5cb9ccb2726365e5a28ac1b019b262c26be57e4a073c7f80479f642aa4032ee3ea4a870af089c46b6166d0f0435cb61003b280b8b4825db9c3b27287c560dc22e9800b39659911fca98469c1b97275a5c328790c7fad18fe5a790965e50e8bc15831aeeca00dea0f543e7908dc0c3458716365e55acacadd9315c35f2b9750562ea1181c001994c6a641052efc3ccac5a3152357570c143bf7530c5450d9eda3ba39b35b39a15bb19d6530ecd7ad795743ca522c59b99ab1723563e592c5ca958a9583b995bb151d1432834c96a1e395d3b735cb0af18a3dab0e4a46faf951d7cbcc5f99f98be3b395c3b215edfd0efaa4e3e99523ad151d7b8321a55951b65f3100b572dad5e1232017955cc88ce7ca69d7ca0196c17702e4e73c27402e6d6c340c88bda9376569f31a503b8d0cb6c4a78a8b06b4fc768ae2c6f3cd2706228e75568e75d6fc1005cb30ce6e56ce6e562c1dad1cd9180c93b306c3e2cd8aa2f8ca918dc1095c7cd20a96d31c83066804e080a68322751e888b408370755abd7364b3f2c4c6ca49cd8a65a195939a15cb422bdae01d1485d4c257d4c2576c04add808eaf01dc0b8817ef88a12f88aa67787043c028d1b9cd474d0a746380c05b5e1b99142d6364db2b815c56c8353c09ab6e9f47fe518c5404b084e4f0cb4ece1d064c502cfdaf43a89017f316e18e82f0690263ba50644fad28ccf59c9dad8beb5482e180a9a44796b9335d11583392b8ad906dac77132b27220b27248b162cdc6406b1254a30d327e2a2eaaee463f35505c274995dddd0e01d0efa7c78564b084c09eccdaa439bc363635060e906719c55d1f569e1c37ac1c37ac0f8bb787c1ead10a64430379438cb04dba48b8f5a71f05e3f70d3980c1d8836cd86f3178f1e99505a7406d63c36ccb86d9960db32d1b465a36b6ff1bdb7f836b027e2ed700a97f58531b32c60d2bfa1d3e0237010b809ff003e53d0ca99a415314e1ad5c44428e933c478a4e17f73ae0f90fcf441addcf85dfc764d7210922e144fc14fda503be0d03fb066e05de820dcf2f252c65fc5074992c171256a88b420a0ba5aa53bc0d4bfb1b16543694ae0d16c555f9bdd22434b519243524a94f1b5cca8e8eea360e9e0cca0f14fb49e22f0ae122f11789bff85df7bf0cb23e35fe6ab3026c34b646a39542f586e9920e78263d8d06d94ee02b3f52eedaa69b286ea29066b501e1dca7fc3c63d8d9a6ef7fa0347fc9e0977c7d7302461520d6d850a8de906f6cc83736a4191bdace1b228bcdb91f14604c131b3207037ed79a6dc3e2fa86146243f8b0217cd86cf11e044338bc2173d8fa39ca0049de3ae82fadd936b4700dd4410c3c50044901a63c015150553eb4792cae1b343c377d922cd780ece83d2903b579c41a060197880bf992dd950d2146072543b71737a4191b420c83a6ecd0ea9c94ed37a410fdc9d64ba0df77590c3018a7dbdbae658f019e9fa158bb799dcc76f8b954e0140c0d5203158bd7432a1b6f9b1a0c6986816ad0ebee767f4b567e68245ed7ac36e4001d1e41018882d6e219fd5052ed20cf8c7ee8a66ee8a66e080436040206431978f3321265507021c04a522b29d466df80bf245fddb0fb6d702a1995c49f3103b8f089c10ae5d2cd6b19b6a138bab1d9dffc57e10459d7d93046b161b8db60d873e85005113f09a878d6b86a80670d5641ef607670009f165c885d4a501bdbf68ddd7a874be071493fe0d32317affecefba7067fc0905d6c189a3038940c599cd8d8b66f6cd237f6e61dbe03645fc260e8996fecd63b2883f477dbad6f02429635898d6dbb81ea2be8a2e5c6de7cc340c4c6debc43054e40916a65be61947be3d9530335368ed43b8c4f691a365e3a54804f3f3f4314d3412ea430d37ef2b4020150234173b8835cf48e6a872a506166e9626da8191ba8deb1fbbd653d7660a0d12f3b2295d072434f78434fb8830294f472437378cbbace6640141e3f2f6267d8c97a2f6943e3d78070c2d86076900b4b350c291814c5c568935962a1b2bb61d3a0039f0e3e253e653e3d7cd288946987482136ac131810453e7e80e721eedb90546ca8f56e1825e8800b19d40b771b6abd1d70d10a249761f2da40630bb6af376c5f6fd810d8106b6ce8ee6ec82e36347537347537f4723be8d3b9abde992233232477f637ec516f5cdedf328b37d4683754643734633be8af9bd6cbea2bdf142fcb30e41b1b1aad1b628d2d3f432eb121d6d8b811bf21d6d830d7bca1896aa03549d593ee1b37e23bfc3ef157c24fc245d55465886c439ab155c667832c9871d1688cc4c360e3d386676d2bb0ae6c70e2e70ddc7c22524f147a7eae039fc8320335c2108303cfc4a5774237345a37345a3b28cb9ef4b0e034e093060764291b2294ade6499e25c1db10a1181c0075a177fa0cd42b6d56ff0a0839373ebd099062617950ab466334630dd42fb8476fb02a2ec679443106499e1f8af7a1781f8a4ec2d80e23834d6acf066a364d179937746537746537e4361b7ab01bcaae1bc299adb19c6bd4699360dc40cbe616c66dca0e159067c655eed11b10725815294bbea6ab7c1d7e2ef2c3bec0c00bf0c3f6b6b1d2437f75435cd301170d7aed9f9a3a57e30df89d1a6c3a8bdcd032dd501c35d0baae49ff70e34abb4198000728cd324db621b7d9da850bc317b7d4b7a6e34503c279d441daa35e8006e9f63053735d7d7b58c63f2cda1f9d016d0f45f7a449bfebc9060395cfa333b2edc943b6bc3decf11fd6c60f6be38729e061e4470bc540cb9587b5f1438971db7d7b58dc3e5adcee93562006552011d3cea390dda8e42138e4a2ebb43b7a293b622883a19ed7cd4c5e0374afd6e012ac44ba0ee3b13baf43ee931e4eda2729a4ed9334c10c86aef58e824a872608b88c86b423aadab93ebf23b3da7938729f5ea459cb1503127f8cf56a077d3adc04e0e2f14341058a25502c612c6076e45a06eb04e0e2f13c8e6877645f0611cf94a19e4edb3150dcaf72aabe026518defc750b220993586c47f6b523fbda916b197ce5270ddbbc06b303547412e176b3a01ec0e5f881024c270192d44452338d2d93d33264830654a58c13ee3c2ed9cd8baae42bc9a864a7929d4aed54d25329d54a61561a49a530b546dad1d2d9b118b06389774708b6f308e38ec86b47d265b0eb5323858dea96bace8eba4e8708e027a8d13652d828ba372dead7856f62bf49e14d066ffe7af0f3f0fbe394af872af84e6a5a5f3c7ff12c49d78ee90003251e4997c198580d0a2e63d4da917dedc8be7627c9c98e106cb7f55402e422959e1db1d88e6560834d213bd2a3ebfc3b2a3d3b7a3bbb5baf1fe893e72fafbae066bd01297c0dab7706634dbb738f7ee71ebdc1382bd9d1f6318840fe8172112816d90fdfd1ffd9d1ffd9b93edf41a511f92b5298f44174840c3605a86dce8e08cea002e4bd4c2a4349893bc80fbd09a99a01f9d265f91df1da8e8ed0ce1df99dabf1bbd3fea25bd2fd0a1eb9d07710b8ede808ed3c56b8bb4606e9294e07a03b97dc3b2817377e3e933e7ddc0f2aa0903f8f0a9ceee0751f6de7bef98ed9d59d9b023b8a40bb6722f3d2a7ddb91ebe7b5a8ba7b5a0c0b3734f7c4793c760a86aefa8f4eca8f4ec68e9ec48e77664713b3a391de4a26df2eed3b036b6a3a5b32382dbb90cbe2382dbb903befbac59cf33d2a28ad3c101159067adac768469bbd7dd931dd1d98ec2cc8e0c6de7aef49ef5a28181ba30ef9aed883e0c343820bbd8b9febc73eb79cf7a3ed5609ca7ec0831766e341b10298b8a4cc5e59d64b0bac8fee7425cd22e36507bce2c06b057b963afb283127f785cb438c9872a0e61c8cef5e71d61c88ebac58e4e45b7be300159a0013633c8641603dc8cdeb919bd63b872e766f48e6e4607c515bd028c841c0927518652e4d851e4d8b13cb9737b7a47a3c3408b0164323b12981dab923bf62177c42c3bca1e3b662177042fdda2f304fc5cf01380c4a702d405c0e52452ca476a24061a8d91b7ecdca7deb94fbd739f7ac7f6e39e7512b12393d991c9ec486076144b76f449760c331ad0c22581d9b9fedc210009a8c009f0975620585fdc91db18f0fb454e65b3ba833c33c0663d01b0a37cb223c0d9513ed9b9e3bc73c779e76af39eef3f65f0feb910d74d5c2c4e10f21854fe3ad5c219ba11fbecf9a15419b191ffec6847ec6caef7b668fa6bcbb023b437c60476d93b2a107bd331f78e0ac4de7409656f1283ef6cae7736d73b2f0d75d05f744f36d73bd6ea76ee8dee3c3964a0f99d3df5ce93433b3be89d6b9e3b36e576b6c93bdbe49d8b963bd72a0df88bf52aaa0b06ead44db787f6f6fdfe6078be1f45f12c0af991606a7f36ad2e1ec6435417f687f2b13ad9005c94d327128e1e4eda1f1de7ed0f1deda17f3d45cb668347a0c4dbce77ec0b1e3da2b73f9a77fc2493bc9e937ddf5f14fb1fcc6a009e8b8d9e8b8d06e30cdacf925adb4cf083d1c6fcacb1a59b9c0982912f83d15afca225845fa44569e0003e69c0efa04f3271df412eaa02bf5e6355e0fb61ff00e966f84d53bfdfb503b22db152786821dd2f2f0e086edc47eb10046326ea203fba7ee8390332c08fb6ae0663bfece334a497066302eac6e6bd407f7191d040698e925576c8807e9750a5833ee9c69cc1d00debf0195008b078fdae67650caa7e97e5a50eff6b3fb6321af23acf2d3f9f6449ccdba63608022ee39a9e81cac740bfeb02607f127902f4d79203801f150bb705fbb3c98a5db7050db2a258ab02d4bac580f4f82c17ad373a54017e129f64d3d28a725c62f2a936fd2e43be066a51e922ef97ff81d273911ed9c4f05c36f45c36343815e05bd59d6ec59e1775902c35a40ee32f1ebbec47bec3a5cabcbf478eedb9e5d74d0d8ddfab9e87f0888b3dca78fed4ab58fea4539f74b4938e764af266ebd661fcd3d6ad2aba4bebf9be801db9786b11d8617cfa682ef01f9926f39facf2f910ce771aeb0d8f0d496fe3ebff4ae335692f6cdb832c17594b78214c7bf138d70b61da0b61da6b5a2760488d5ed3868be6af1712b31757ba0c3c9faafed2f6f6c52dad1752ac17b7b45e5318d29e177a562f54a75ea84ebd18603b3401e1487c64302af7c575ad17af50bd3014f9e2a9a9d75426792ee4bd90c2c2ef9582aae4a252aa7a65c9a0a9544fb2731607c8b3cc39be781de985fad08bcb502f2e43bda69b84dd244c8ab52f547a5ec82e5e98347cf150d10b29c40beb822f34795edc307a21a07839dd07315805fb18960d9a5cc2d8601a8cf5c60b99c3cb514d68f2bcd8febf5c26a9d52b400a93ddfa0bad98175b720322bd4898741d5fae2579a6589c2cd5bc763da3f0f293cad94b7df185e5b7171a2f2f145d5e28babc30b9f6e22ecc0b6d9697a734d814bfd814bf3c59461de5e5a54afa42f9a45be7728007f4494b2c834d499516dc0ba59117bbda17bbda17bbda0e23d2a433a057268398f97a6519a57cb1877df1acc30b5b5eafbca8fd649df4bdd0d57fa199ff62cbf962cbf962cb6990f57bc04fc00f25c6c6b083fea29fb2e97bb18f7bb17d33c07326f15a7818348146f5171b0d83a6909bc6badc0890ae8702fc8b1dc70bb3482fac21bdd829bc3079f46217f0e291d31786a95f8dc2e4b9d2171ad12f9e2b7da1f66ca0c4b7979a3a37a35fd88a31e05318cfb8bc9a2ce81afc29642de35f3c0ffa6219ffe220ec8525160315382acd2f0c4a1b385cf04c67c4f0f28be3aa57a3f93559943a269d6e1fd3df18253a5441968b6c171fcc3bc7b40c1b5c07d3cd81c2f031ad5ebf4bb5c3a009744bfd98fcd82f1fa8071b108e0c801f1cd91c1cd91ccc4406111833fec191cdc1998b01e909a3d51d1ca31c3cef7860faf8e0a1c60365e083b9c9c01f002e5145a7e541077dd229e7c1938b0713d9c1bde383c30e8397ca50bb36836f1b90c94e2164bd9968900fe01650bc652c388fa9f2971ac9c13c78706c6130d44d0fce2f0caad2a38d610765a7924269c25b29d3244e4ae3a2722f62bf28b1eb52c8121a1cbc1bd8a1010af94d386fc2b9ff037956373f38803020175f22953eedf1a795d5e168d88e86cde9c0e1a4007f703a7038378421066a9028d61e4cd006ea3bce8d3dc8c15de08329fbc0d8ef81b1dfc3d1416c82d6ef9e146ab8301827500733f5813aeec15940075c8842e3f3e1b4e8eaa04fb1fce002e4390d63c807a703068b7ed7f9b2c1e500b9682775701660300622034a4cb7a20e8e000ef4690f8e000e8e000e16154737ae31e0a4be4e22a569b98ba46a8833c88afd4d32649ae340867f20ba3fd0c23d6c75e0054af3ae159ac1d0733850d03d7837f04041f7d8dd2217e9bc7590e7fcd22709120dc6c471ec3ad73bfca4eee975a9ca40039ad7bbdb1dbcc0fd40bfcbf8e7c101c481c1dbc32faa41acda1aa858b8927c7013f9e0deb1c19b4f6fb9e890e2e000e2e000e2f0123b1ba8adb2c4324840060a70fd40bfd3563da3a897dcf8e048a2833c339c724861307688076bb6838bc387d77dabc317fed2bb0c1de4a203ac836bc2070ac3078fd6d94432290a9d5f1c9c5f1c589a3d78abee402bf8e068a3032e4d55c0c8e66f75a240bd7351d7b6e8e32ecc1174ca60e0e48709911ba9064309ea084d951bda383e3b926ee7191460a83c1de89d1a0c5d6283f1c6ca9124863208f2ac67380c94f7a4c71c8f24755c03a2c86711e059aab60644215dac23357e6f244c575c3bf049e164ba67263ba8b61e9cf81ce8a61ea89b1a8cbdde91b58a3bb254440e1e2633e02f49960e34518f2c8d8e83431c0355773eaa42d649cdc1eb6307072b47d686f7c8e907ea9e9c711c2c920f0e290cd4fc72192a34066a48b9bc9442dab32dad3d700297c0e112f14cc224e4e9209713cf0cb0f9c2f3a5f5068a9a075a94075a94064381d0c0e3e271515b4543b2c357d0f0f3e8935e3f34e02fbdfe735499b73d10e91c3ca973d4a6a192676e8e9316de6430f9603d6fd0002dba9a2c2a1cd68746be10e61fed505db0b03f5ad00ad620017c5ae599156393fdb1a3555cb4553450cb4445ede04595a331d9f1a2cac16b290678fe0adeba577bbce9b0b71eae3d1e269747a6030c54aa0fe5f330c73d74a2472a580762790395e1a307f20e1e5231c8fa24417d07fdc5d88ba5a3038db203217c98240a0ed3df18f90dfc0f4e41958bac2105ac2105ac2175b8804770e893e6c180a02c600d29b0850993e641837137304c12ab06762e1df4975ee6eda0bfb49731d8f8744c009fea02fc5c9430a9967590cb41520f927a90d46307bc52789c8a2b90534dc7814d4d4004d7417e225144a2884411a902c949029716adc54f1ec085d2500308687905764001e5aec07ec7e63a125fa8658d6c61aa045809a7922f291804f4b50c36d557259c7afc80bf122e498d44528880b5cc80b5ccc0a54583d3030d508027b9b82625f5221c9d9f76f808760ff0d7ae70ae43d951a70e53a3d5350aa151083a7e35488aabd12fde34d13795f2263d6ff2f5265fefdf5f6f25e3c6f38de79bdab929cc3bfd407f7df8ebc35f1fa2f804f979f0f310e033eec705ee4506d4c602da620619f87a60d4328a641d1ec18acb014420fd00cf059731080754cb02cfd304c4b3066f5cbef22c65b3e0e6599f1840d83c1aa86939599f0e6c1e031bc3802c37602d2ab0550c487703ea6701f5b3e024baef80cbe60095cf36e6dce076a2d04e33b0d3ec57bb46d3e21d966e9a65010220cfd2ebeea0b8e8dddcee34d8000f64800ca62107e8a0a46a12b77daf57ec7a19b33f652ca8248cfeee2a6578fe291c3a2c5bc5c00ed140b30cb732034a621df43bfd0bb5b1c01b2bfd216507e0a266ccab2bc1dd008ddf7d70a13d3b9d9b078c4d052fc16fe0b993c0eecf40d30406a93a8c3a45fa6da082ea27d603643336f0128a8107d4fcfca2068941aac036d0200144aaa3dec0c63060872a60872a70a53478e64a4f13f5b44ccce40614db028a6d817da5814a955d6460f318d833da3e932898d10c3e82bf09f0007e34d9795ab89799dcc0fb291df0130987d2882443f7c802f7586d19344ec903f758033bd6c08e3560f32ab075edc0a76d02f8b4f189d260d244192f700011d0ca0b6c7803ea791df8a481c8400595f9bd50868584311dfb4280d2590abee29989d5d7aca675e2a29b1406940f9dd15f5a30f0444b60e31cd8380736ce067b0670d140cd794a8704c8cf3b2b9cb73c07dda909592fc207ee4e06ee4e06ac2105f69501054203b579ae4c060e68020734812da7817a4a9675b80eb8785c3c2e07c0efb3aa8997b8030f70773354023a1a3a8a815757026fac1868cd8629278321ae09bccd1db871196c0b2c1716ae1c181914fdce7cc1c951e05428f02876e051ec80de60406f30a03718d0f70bbc961278573a706014b8441978fd39a0d4d7c51b1380673298294c6d9c034fa204b4fb029728036a7e0135bf80525f40732fa0b917d0dc0b68ee0514f63aa8e8589d6656a7588b0aecbb036fa304b4fb020a7b0185bd80c25e60036ea075666679c96159e099120342bea8d34bbb002e5a767080ba03ebccdc4806b35e6e946a23a97ad3c420e199526d349246a94ad9237030d741b96894f37b52ffa22fa30ad8419edf24e3a69c599da22568407aee84671276939e9bd8759721f0a649405d30a02e1878493934868b263b5481376d032786069a7c79ae22a04968a042e09a9e81aa09e1436852c908e81676b9dd0254409fe8712d901e3a5a63b26b2ccc1a9b358e1743638fc613121d2ec1e6013e910ba692c6a4c0fb0e81476903078e1d3e0202d4d30f060428f1be81c6d5c66e0bb5c380da61e004d3802c5f6e0216a002f2c35ea651b98d5d09af42845b360dc2c3c8ffb0d67a58623db2191b9e59911ae0a27ae77dd8c0b30e81cb74e1a1773fe7cf4565f89cc42e8bd906eab00ff9423c127ee291876efea853c7499af006a3b145aee0c5494d344e7a0037223089084c22021383dd011ee0d30104fc8c1924622d2a622dca8064b821c28dd33ad21cb10415d1358a188b8e9c0bc749b6c10d9a32b8df02cd4d91c76d23b2140312e64300f814810490424f414933bf83d2233bed11314be410d9200b749adca102bf4f1f01bf070a218c43e4c88973443813b99dd7e1115cb85cb85050ba9d17b99d1791ed446ee7193807e877e9ea47c4351d9465d9553318ef9e445e1e891c614704381df88baa4c6447ab5383a464244a2c51ce89d6abdd5f4495cba005407f9571d41ba77f4d29ac930376409eeb0c2c0ab092e64a5bada459468c3b28a7f5c085a655695a35fc5c0899faaa74879ad512a4591d39498f18ee8e1ca01bbc15ce49e24f0afca47b9e245e0363e4fea0c139017c22e493c23c2943adba2382a98859adc865c3883ccac02b3b5750ed68e5d0013fdf09901f3d611c915045ee2146245491b37e03d2dc085086b622af1b1bd056dffee722cf37b9b8298d9b5677d3cd6f7af707cf1f72fa211cd962ea800b9e1f1aedc398f0e5d397a2fb12e097fef51de7173619ab0120a18adc708c4e7bfc883c2a228f8a88a122b6ca637f920790676d34a2637c4675c196dac38896811a2d171b2322a6886429a225181d032306c93b283d9ed8f5e255740c712efce142140c718e210e8d85885a42442d2122508a3ce36bfbf0a19e17112819385cf0ac9d4244c464a05e8064a983d2cc2083882962132cbafc835b202173075c1605584986d6f31173e811319481e793c7854a6100e11664e462a315c114007d3a89828eefe8f8eea4784fda8fae30189cf821a7747394220c763ed16c2e02bc861254073e6525e3a24136d2fc26e43721d319dd4d061f1a121dc47dbf0e18c9d8f338d88d7e1a86853bdc82f12cb581e602cf02068beb11b956449c15517888985e37501f44f3c160039453245d11b9564483b4833caf6ab49e758bdf49cf4e38126745a45806c47e68a6e67a66c48a9a811a12a6d70d885d06930db4dac1187bc4187b443e66900987bc4b8d2d22318b685974f80e88a4d9fa015001fd15d5b4bc34dc22cf0a4794340c66fc902f7a2e92ae8855b788802b22e08a187e8ffd5a02804bc20ff94a64875ec995d20e1f81e793260e44551d1420933826e00cde80a6367f525fe7a2f2a157fa73c385df998e917445acc447ccc445045c1101970179a7a3612e3e621cbe43022a801fcdcbfe3304da911bb2069a4f930cad47e45a119b6011335f112956075c34f966d9f188997d01e2ac0ef24c1fcc3a488dc8ac0c54ef99b929ebb43d72d33666dd618908af62de350ce69d4f3b9ed91718282e16ffd8213750d7cb2cf5794d38f29a70448a15b9696bc027d9df88e86f44aedc4654a323aad1910bb6116958441a66a0d118ad69834740ffca123277d05f91f26142cc89f4d0e3b28e5623da2311a95a7fcd0c970dcf1ae773a24ee95f996e95a5d41751d58e3c461cb9691bb9691b11ca45046e0614420e1ef87d22c071a21191c545647111595ce4a66dc48e59442817b9601b91ce45a47311e95c07fd25319dc10950aaec1d508f89a8c7749067267a0477061a8db3b4162397700d686c7aa32762182d62ef3d22e58bc8f422776f0d2843297b1850178c243c4f1cb98d1b91fb75b80005c8fc8ea535035a38cbf87cfd42a6ba2fca87853d66d90c884b964622d6e623e23e032d92330b7b647a11995ecc3705ce8221df14dd874f1f9a280b722eea76900beb705e133650332e55a56169cf02357e83054802957c9b357bb65935d818b5dae2f549175a23623a837182199b0c1876388151086d57e3c7189741002aa0a26b2f2d9b5b98e5c268c3c5e10e0a3010a954710c022e4421933e1d4655b6a81d2b224103d55763d869899099b231ab1e910d1a78e0fac158c5357a37afc146a48511216144486840a53041734939724939724939a228d5c10378ae78a652aa165d4d9ac306332ea4875d3606db3ba8e4a5d36ee0712185ccf8eda478597e5b27d801f961ea475619915546649506c4453fc526bc01e1b018407a19db77526b61a27feb2e4c7c2609c11e04538f1eafef307ee7f6b48126a0271707e047a3e873e259ba2b1d4e407e3e2a96aff445d324b1aa4112fcf149aa5c0607305a6fe2a6494220d9210baa5c7437c796a46f07f801ea9e891b8e89fb8c06a39b2734b8d2a46bcb899b26098962427e685027a00dd0523fa18b65b0ca4f20d2809f40be222e91bf22a5a1358041934b221c99cceaa05ce8019484782d215e33687229fc5e88b41057c92a4ce98b767080a2a8fc5ee70ce0b20004a823ad84c25542749650b84ad884b75cedaa26f58b84f4297143c4e0d25f0d3f7ad3244dba269c505eea700bdefaeb9ed47ebef8f9fa0a0c97a50d85fce4a661ce31219c496804251481121298840426b9bfa1859bb8b09990c0d8b667ec3413821783316976505c2efe01f82152e9ff24d47e92dbc69464a0b6e168ab987037502f701229276e88d8da5f55e9a4c390b8f49110aa246e7726a7059581971f9d72266c3a191c13804bc60fe5237b4d06aa14547112e20883713b38f1825b07796e842c1b9b09dbe9890b1d09e18301c572ff016af306f2acbba5fdad5d457113e9e7070a679b8631ae7e8d7e128c39c56641f5d34d4fa3dac25a0308e2888438c240c5e265e43061122a6109ca402392d79e28a18193104724b46b127289845c22219748a8d9242c4a25bf7b457aa83b18ecc01840901e24f464127a3209b596e41321d35abc1ec44c288d24344392ff475c95903589db72c1290a4d9a0664f9220ada866d8a555017716977dc21030a9966e3df94f38772fe10f28790b5bc4cfe3bce6e92edf946c2f2a4a263539cd8d5a64c0d667a37dbdbc4663671d12061242a65bd579bd89676d0ef12b426742a12dbc9c42e32716520a14a613016ff89cda381c6de1cb307f48919243383702db783624f2455cb3983a414a64759d636d04063029bbe849645624397d8c7a55c2831ed9b120a0f097346893b080913d3895d52c2545162bb94f24580177e68366c850c86e64c629f92b81d9cd8b02434163a28f18d34bf2707e04280f724cf8c2ddc294e681174909f0f49a5d5d95ea609f8fdd127ac0f19a8a09a2ed8269e6432504ed1223050336ecb77746a7625a96dca053791133791131b84c4062135fa7ba369a13390b0bb9b301f94b0bb9b58a22796dffd464e06869f47a6b30d1429667f12c7dc997554661d65300a3c63873373fe65e0814ba0bd70e6242b738095591ef4fb40db0037463f8321a0e8822ef9d1cd8e2ef15a04a3a91b28aebf97934b2664591cede081f1699ec7d8d2f5bf2aa04ffb18c73a3c03c8bbad6d47b1ccd798533a2440bf5fa357e6b929d245a3561fa2047af2cc4085b9f8f30797804f92b7180c615a5eb4ddced811caab6ee2e4552f901a8ce69757d991ce2b55b069cd9f373d2ad1412e7a213a6fbbca67d3baa5bf31b80015d05f1ae2f2a60567dea9af5d2d2aeff8d9a5426c7b9bd19b326f9b6624ed19d97246929c5f7a81221fd3b0106ba02c1f4ec57b68499c0fea22a80f5a3b50ec41c6d8334f63186479a62e82c7254c3f780b94c21008398f9d4b0e65928b96f17d4e18198cd201ee17cbf449271afdd10301cd38ea092d9b25de72d1017a9f252a7002974021271921e9b2465cd48c132d2a1d780e933ee92c20279d37e5deaf06c89a56ce715cb0cdbce19891f2f5ab6f23efcc05396b7990110465044136edec805a6fa1348a1bdb9c5c683645aaad3669a9e28a26970ea334aa14c03a3c0285cc2db60e976088d772959258ae3ab7325014557a5fd9babbfc688197ab34363bcc82a600fd58a1f5c208828f3cd353aaac3876280322b9d0fc9e6b211915171d0be6aae553ae12a6e5731ebbad7cee43b7d9964a0af0a4c79d71ac72f3792af1a7acc3d98c3d0c571aa8915cb248d6d50f47148d96d0b47ece8dfa6a7eecd132b6f232aa6e1903f23675e3426b6965080d3ae813ed87e7f932c299dcae3f8543bd37ad333b64c1a5647cf99df279d312deee070950077933e4be99260c46c8886bf22d4147be65f8c216174acfcd9870cb1a7fd770d427c6c39b0cde521ccd9fbfb1f2b4058892f171c35859fe480ed9e5ac40e49386ee4f18af5de40fbde0219caf3b462ebedf116999540805214f41d9aca06c5650362b289b152ee515cc891474cc0c3270f1e9928b0e6d0d82625fa2fc48ebac831fe0c6ec69308e480cb25c3612b691b08d846d84bc65fc10a027859e2c7bb2ec895deb79837302f4491a140519510715829e2f2c488d0a6a631d2e01790f87d2a3e55c417facf0c4614191aca0486650f8abf08914ea2e43b1fdee47302bcdba7d5fb8c157b06a52d00d2ba88415ac9a1454c20c863500834355201b4a1d941ee966146e021634c1caa42ed3417e0a4557a65b40ec850c6a375a50122b88b30a17090d160ff0897c55f2555d02328067d780b76023ae0dcfd457a5beeaf173212e1a5ba5e22aed594295828db2824659075c2e42a6e8a44fdb41c938dd0fe4e7a4c79dbb6ae7a4659e14dd49a33d09f9a2582e8ae5a2ef5c84ace577417fcc80902f32a813a8c20dc732356aa7d18cdff4dc3791beddcfa50278f6f821d237257f4f3f506bb909f0269c9b4ab9a9949b64dcf4ee0f713dfcfe64fdfe9cc3c54d6a004e36160ad70f3b3c82804b022a7fd59fcb2538f974f1e9229c37f0951f99b12aa884191c0ef8b9e82fed220b56e60cc664579cde1e2a5c512cd8b72958b331c80a470baa82f4b2a063d6013f6a904e42780352c8e0e918219d273b871a803b48aa6e841964f961143568023c4b85a6a07e66a06ee5b44632b870a17819e29c04ec05f5b382a4d440bddbe924bd70c3d180129358be831710454e3f5069148de14e6b5183c2a753bfcb9e8301b52369bc014965f872da451634d30a0a6905816dc1f67ec1f08ec1b8b653b84d59b0c053d055eba096c96883719e0e19f87dd2ef27f962247127cd58ab410307784571d12f2e4dbe4e66a33a282ec9600df84b8fec949dceb86b895e763ada2ef3adb64c54a4bbd394b4b33cd81de1c898adc1383f35184f7b973de43157ee799c2a1a8c2b661d4e81b2bc97b1b82d7bc3e551bdefda6e173fa9b5780607ffa7d8fdfc1fe893ae1b17a4cd064391bea0f366d0f4971bcab785bb9c1de4d9a9177829851a0cf5bc82b51f032d21bcf64dc51f244392e482f25be12e67410bae837e979a8d01090b9aa00d5620031568c02dd024ee5935b1c7efe0017e27192c9f107a1b64021c5bd7c28308852ba505317841d5ada0d8569087170c451614db0c0e5ca81dc604f4d90a52f40e2ae7445d305cf83474ba0af7343be8f74c52f3e300b9145a0b8b255f48338b2503455a28169df81484f9065413e30f52fd825924038d1bfe9c95659619fed47483825cc1629281d600dc002ddcee2c08fc3b283d17c5a233a08230bff82ff9d2f6df06d30918764e0c3414f07c6ac1aa92813a7590ba69874b70e1e7fab93c8261f8ab83fc3822d55b7e1d7051bd07c6166b8f8a54aff295e03580044f2eb4112b811ed76ffc0ed0bb78069aadb0fbd4013f1920a70c44065f41c30fc9a021051a128f9c962083ff85474e0b6f9b7650b134d557681a9f83ecaa15aedc1a6835d805be03feb496e0a8a560d4b470e652387331184a230595c20e7cf20a5927aa060550def3a681286ffcaedbaf053154c93604083466e6836430c4a13758b09b6aa0c500ca811d2a7002f2acb77e3af0e9c5ef140263149a8485c3a08226614193b06499ed2d9c0a1534090b87410694063bbb2c7582c27b1c85e3a10e7cd2860e95c2c2815107fc9066462d14080dbe2a4cda2a7a8385abbb1de439efb8bc14693e7ec0278a85f190f3a6c243a8054b591d2e01099302610779663cc47656415db0a02558b8e75b7823b54305f43bbbbf5c2916291e174ebb3af049eb0414083bf049631d7a831df4e92476065814080d7605c8122b5f24fea2ebb17de3b0cc80145e59bf5fe49d25165a82052dc1c2db1f85b73f0ce8cb8d9c4aaed5a100aa0b5d13ee804be52fe2d23d5f035278d319d991e59b12d3db1f853bbc8543b7927507c120ab1db23eccd2982a751a271185275f0df62688b8680c47de6b90f9a40011fc76e093268ecac4517583b860d9ac54bd3566a0c4f3d2abc1b8916140325cc4b3f25599530c8aa0e059b21d5e83edc05f6f5c3e04487a58ee56afc1a17ab70215c0f30604fed226cbc00305c033b96046ab9e5cb00d3490e73c017f00d56403bd60c585f464359b9ad532ab8eea3a28a9793cc5de81bf480f434a95c5488313cfbf8451987a64d9e0c24f238a1bcf8fd2d3a8b8a66e5e99222b2df374e3c59972ee5aee9e94cf99d5a90d3c700ab4e63f1ff5f7f35193687f5a98715ddd40f34e9bd5d11ae2592eb01b68ec4545b670185dd08c2ddc64379030a42d277ed4d47937a770c9bd704e5d509135189a2aa5e94e4d69af7126d5412ec70fd4531a1b0d4eb73b284004ad18e8b385acb615d8e52b28d676a8009f86166e075c089009ba05492639492f3cd6631089abf08964b0ad68ba845bd0c22d5ccc37d0048d166e41e7d6e0a54813e961f2c54878e1d4de400d1205dd0efaa4c3c4c2e9890129ac92f7a2b25b50d93550b7c26e61410dc040932ffa0006b404e62f346c0b6fec1694664bd3715e41ebd5409bfdc64c841e6ce114a6700e523057581e567a8f0c7b960711d383d8e7f9fdc56a073d58037e67c67f64d9a3709dbfc347a0c6cf23b9e561027a98801ee91a75182edf69480ffe7190f18f2bedffa6d7f46f80ae63ff9bf45cfb3f4cfbfec3e6e73f3467fe354d5b06635e36d870194a8f1d70198dc4605481c118910c2a2e279e2f5c2e5c9e05908b0eeffe351db51844fda58d8f41e5d3f303fd2eab89ffd08d3720179a2f0c084786583b64e0e747c9f0854f854fa509c8a0af783e013298276530939eec572001fa4b5389c198380c88542f4dff6bcf28c33afd8d3a3518cda6a2ff5c3923ab1c8d55d49e2b276215630b15630b06c3d8a6019f34ae565e40aee83f1b2cfa6b23aecdfd5c2a80e731ec544c3454d4a70d48b334516dad4480fbb8985f274fa4aad3caa959c54443e5f8cc20e19270a90ad05f13a04f2f427e91d483d80fb273909de3e7c74f002e243ee047cfa756ac2574507d69a0ee9000fe8a2a168de115e5ed8af276e51cad727c664014897296dd95caa95907859cfc02f0e9e0774a35513e85d228144221838516254defca2157c57e66e56cab724a55b14550b145503942aa3c85533927aa3c615cb1fcdf2101f2accd48e52ca9039e89e2220add89e8e0003e8d0d4be5219eca5952e5996383223f6fe27a13d79bb8dec4255b439523a4caf150c5eea541909f9b283e84fc219c67da015cf0f3d0f81fdafc974f5ff773a9807ed7b3055d5564014e81070e20e039e03246e38a01cc0e8f20e152800a8c81d14075ea341718bc05b2486fe06681daaad3a4603096a0064d914a8e6da07e619001fcf03ba39f63f47333e999c7f2a0837e5fd4d8dc42f968bd6aa072e6d8cb4063825b48f3e295d425f017914a5da7c34750f1d3fe003e3dca971e8ce81b3b5c489814bc3b281c474edd810b35e8a82647a538aa60255fab1ab65b5795c64adbd0237106e46b25f1db10b0576c87564c861a68d0735b54416d09a034b6a6dff7b111abdc4ae8a028fce1013e8db9b272f667a0019fbb0c95bb0cd5bdfc26a02e18f03916eca0b8a4266140e2030d29d02f228d244eaa6e69bd76b8009558a4e8f45e5be57cd0804819c35d22a932d568a06e8ee1d3caab1995d340dbb57b555caefabd388070743e58391feca0a4167aae5e2dacae92c14a7a4e2d3c0c6e40893f35ec6068a2037ee817276578665c327ee87a27d9d1b95ee5d9afeaae6903549817ade5a20f5ed4d745ff7a53176f3edde4eb269c9b9670e39981daddb496fb521f647cc61845dd25b1afbbd6ab06e30ca8ee1e3f9e4fac5276bd2f6c30eeef54d44debde706178df1f0d569e11db332cf356b8017e747c6f3014d22aef7ad8364339f5daa477f87d9267e9ce19a8103816acdc34a918be30d012d433c8f01c79e5ca49c5b26be5ca89c1c5a7ebe7a2005928fa6da8ac54cee32aa76f95f7412a962b2ac7705d682497c85f91d823bfb3b2c2be44c5a46ae518ae72fa563974ab5e926403d2cc1a8983b0cadb1f95732b837143ad62cbb462c2b47263a57251a562abc1e0abf4bca94a161e9e8507764a2b764aab7f3421faaffec22a69c51869c56843e57df3cafbe635332f638cb462c6a162b4a172b05233f32057576ade342fe71d1716eddc58a9dc58a9980335d0406da57b0834dd7044527911a3725652b314c52b0722062b405cacc3330375965992caf945c5ee41c5ee417ff9e107f8512fc80cc21837a81c52548e242a2711959388ca7143e57a4bc58868e5dca172ee503977301812d70e8a2bffe2524f41a5b962b8a0720051315c50f3bfa6df2ba5c1ca1cdba11d1600cfc455898bd53be7051d5471b4f07c52508cf35d7917d05face733eb794c8f560e172a870b95c3858ac101032a57b29d8a79d28a2d82da557e017d6ab4dec6ef8d2a68e507ca69a341360df81c25544c10549e1aafd822a89c32546ef47408009f28de3b0209cfc4751317237f7e48cf9702ffaa789b8e126afb1b22dccaf51f03c58e9cb63f6092042a0d03fed240d4901520a7adbc5a68b00004a80b0b1de4a227ab2a72dadad6d50172d17da2caa38715c96d6d3a9eae88626ad3531415f96a45ac5a1bbdbbe98da7ca9da30ef8d168c32d248382e7821fd57b939d6d03729a8894a100d9a981fa0e02d28a5cb42217adad684dd22a7155caf9a454e94dd829ad980530d06a19b300153df3dad8bab68b3ad5815a7d58153cc8881e46519e47af8f0cba561e52a9c82aeba391e49c24f73b27690d198c703a54003f63736d30d2d3013fa3b19d3c347cf2d84a077d526333e0939e183b793fc560774013783e65e0abdf5792baf2bb84572712aa1309d5893ceae44d4983b1783ba77d18ae34f0023f3be000f497263b834dc9d0ac776232f444427522a13a51f03eb1147af256cb39bdb2727a8cde7d228f3a91479dc8a34ee45106973c072a2e4c0a592f009e88aa4eb4c14fac8976f808a8b81009301360269c32010478f2d795013e353e3545aa79f9c4d0e889a1d193979d0ddc010480bfc8858c911aac2a31f57783e201794e5453a29124c249545cda762003f8397039f14c4e133995f1a29357a40dbce22a593558f954494f253d92a19d28819f28811bd0bf2ad55d8f1f28cb35130eed59c3ce89e4cd80704eeaeba28d5d93c2b9488f365927c2b413d30ae7d4a82f9956387985f344fbba83aa5be79527cf719ed8ea3c91aa9d08d34e846927c2b413619aed3c274571f3d7cd5f1ffe7af8f4f0e9a10a1efae09315e043d7d386ee9cf5e898c1028ca304830d97b1dd365075cf32936210f133e6f70eb8143c0fd969072fa805c0f3385c30d09830ebf4a4039f1a51347e1fb214835b9e9d468059c7281df4d73e6e0b1a8c734683a65cc84ef239eb11c673d68ed58042c84361af83a2c864506b5a03d29c1b9e496abe7f203f755cf9efe0800d48c005dc801256496af50ab9660254bf982b69ae59bfb7c50319507a1af5de5645dac87b0b07108002e08796d0288d5609905a96254c836b027e2ef819277de7ac8bdee7328df3af73d12dd11339ed899cf6444e7b22a73d91d39edc143891d39e5c1038b92070721de0747f9a1091af9edc0b30c0b32e959fc8454fdebd3d79bae8e4e9a213e9e589acf2c4aac989acf2e485fa13ab2627f7023af089c4afc42e39a4c1d07feea0344b9e7022753cdd5ee547c246036267a6e655a3936b051d940b3da666a085873b08f9a0587443f6e436c1c96d02038d1b8ea996fb05066f7dd211d289795b038f8b0661a7e3a11389e2c9fd02834d1994c2b0812620ecdc76c08f5a1d4f299d88160ddeca6922a7655a00956ad112c2952ccf7a65a983c2a9d30c7840bf33fd610bf7e4c6c1f9ff7a3ab32d5959668b3ee9b9c8aab24ab6a6f84160243efd097ed6f46e0e1a4144ba68e0cedf007a54a12c26448c11023221fabb17193a0d203bdf545609158b83588e6bba592aed23e5b701aaaa5184f15edafd0d50e5999b701a338034d4f9439a0fafccfcb57cb4a8c09f4c544bd957a6a49599689591728016270126d8df4017cc6dc50072692ee07ae2801328143a65d0019a1dd697f364278d93ab534457885c7dd675999af9037640691813d665218a8a49452d20135588d2370dd0bb4b6d23403fd1ba50c3851a2675bf35519614d22a07b6013b51341dcbf895d5fb9a68a854c85e08a1c552cd80de22e9475b13554d8decd459628b014ac3ea7ddda79ca8aeac8d63ea5662a97307a86b051440cfc91a135626f135ff23e49faaca0a76cd34b82e421d40ae934269845c48cc0b32f5075031a7627c8bdce7a27d65045859dcaefcc2ab25bda95cb20c506be86c67c001287be333e91ec3002ac6c4ba3add8f8522e7ea357d7d01d34b46e5a8bc72421ea03f8e13f28ad7e89a74725271d334a0004469e39cd8de265922d7c4848843e9012a54178207a8db708a5ef1d714a0d569fad3a74c12ba0d501ab9aead18e054cc6d2ae63615cfd29543f80107508027cd47406b30a3e147bae23ebae23e3a407d3ebd3578622f53b9792d201172021a8838c3af98d254cef02b67f80134cbb13da0d2e5c2bd72985f39ccaf98ae545c430f5800a529690508c9df02f5ba54d45793dcb357a403019a2271f25c93d108ecbf900e546efd0ed8948bbf20196fc1060a5f5515f39600adf071f25cd34d593765491d6ec01335b36f4c371b1b9feda52ebabda61c36401b968d35e4c63e656376d8a4dc35a0087e885235027e01122f245e9ec47af2f2f7071095c8b5f31c0de6016fe01468a5b7f1a36df2b212700205e0bd984a368e7db644e5994102ba402dbf31836c8916632ad9a4751640e94c2e5bd2b8ba31cb6ccc201b33c8c67c11a042d9b56d59bd6e63fb362e2f17d062328508c824e653664d641bfbafad6834de646a1dc073d8776f0ca7012ab4ff9246537600217a9d9d7df7b83859b010f2076823bfcbea27e04dd441889a17e3ac00bd0ea658150bac002744cb15ecad027e00bd0e6656012466e5b0b34ec0deaaeebaea6ec013a26ab03cd8f9823b5f70dc1728a01accdd3bdf6bcf3442fe07a88f8d3bea0095c504bd4bba14504843e9f9299d17cc5d4f6e5f5f80a274b95bc5a4ab62d25531e90a482a9d2df0de0acf2984684bb5331d63e415a0a67bbfa658b08ecb9904fa85c7254682428876acb16dda802a20fbb291a610a2577ef37fbd59c5e1e9a8be69f9e1d55d40e9595baa370dfe96aaff803f4123ca0534d49bd6183e82052af4e077385e3ad83cf80b0e3af6f1d279c2f08e0a3c515da0271f9c231df4f9435e83069c020a5d74c47df0171c8ccf07ad7a30ae1e895c1c8c1f0c83c3ada480caf33b04a88652a30de0dde9fc47a6f4ac6f1aa0aaf2510e996604e890e790d1e2801d5011f929c249436bd0c30fbecec147393878c952900b38017d6e44ea95fb3d6b962646cddf0ff01c968e88d403b4f6cb2c1db1550cd08637ffe8efcebf9a3d0394f8576b096ef31ca0ec483db8e3a02291af48e46bfec773fe692d91e5e13340b330f2f700b56ae67c23e0009466d7183e5c9b0119208d7a5496a975c5d4b122d90fc83c3913a25d40dea92aa2049c5b562c132b22fe8a40bf627518c0bb4bb25ff157195009a90ad185a115817e45a01fc087631a45c45f91ec071869f83a52bf1fa0e7201de0ba8100ad2111df576e190890882480901f12d3ce081730361cb0003c9006674d9b659510f0c7730ea29efad80344f12d8cf7323a49e35bb4e988be722b68c5caaf229aaf88e62ba2f98a68be62dc57331307a2f99a3978c94e599cc064d7dc144062be9753a853a824f295ab3f2b377e562efaac08eb2b770a54ee140868f39c36df5a829ef2f316a08f72ea82c50105a8823f400726278bede11c0a308106bd9375f829438c01e4da49fce6c90769a6b47d005185e7942784ec462e23aa51843f4054e7399d101d1b9eb258a927e73f27db811321c5b948a21a40c842625a6ca1599644c8462e5a63d1f9fcc97afe64f57e2e92449c4cfd01fa4c898ac98e7ec0062871d29072b2f63b99ec4e999c0c20848a25be0eebc353d6280328826fc1841840c5a87c32b5214743a71c7f0548b4318cdb01a5615978b25c399910872db14093ddc918350c59813f40b91852025c40cf44d472226a398b84bf010a41c272b2981cd67d0051fc0e1cf29cf2e03d40afcc9870223d393b5f908dc67f4d42a500174ccdd83a8c85000366f31aab2f633362fc9e015d303563030ed21c844c179403c8a5d3d48002106540238d13a29fc8f8538c8db32d538d7fc00290588ba580374076fd3bb6e868c8e4497e00516f42de3cf0a02cc9538cfdb2713065ec970308293c8717e48f33fe3863276532e00a5097307e2b4bfb17a007a6f703a45197b02411a4b1ffb2541ed8801320fb451aeda04d16b203125001bd20cb5463516a99be21dbae009d4c9afcbd07d09899de22b3af0124ce84e887354e5c8d454500455442ec01a2e851485d4dbe79039c28278aafc38f6fc8618d112040152bbc322380c93bf70012eb14c24a267126b1e44456b49c3396dfd6e8cf8c12868c3580c4ef074843876c7480468bb5f2809a85930a63616f7d4f807a78a78f75ba16438a7164d1beb4006e2cf5d1c10bd080d6d08f6adfdf49a049a1715cccd5de1545bb8a1d74c50eba367ef3c61f87a25d00f5e1470b50ae3f8d1b8dc3e18600b4b11dc064b262fc583163aced9f568c28e3054c672fb5edbccefefb02b28017dc350c62b65c1b67b94dd79404509f378939e6e562a08a6d728026cd0042d4b11b27b78d65732b7c1dd6cfdc2234406fca221923e58a9172c0ef036a4c79e4a8dc2254b9fda7a2cb57b958bc36e30b1a89e57da83a938bcbb350c00f2192723ad38db308741681ce4acf91eb39227e6702720ec19c059e33130598404b3e670feb9c27386b3f676ef257a71a1ab19d559cd3339d230267cde6acd99c430367cde68b56a7be50287301ae6b036804467e67c077564dce38ef8cf32e9f0f015aab3bfdd919e75dbed7aa33863bfb3867c476465a67a4750658675ced325e0bd067ea5f99108d755cf23ea00ab4abed4ca31de10b8a9ab5cb634080fe8b8eaca4232be9525b1da0c40844304eaf18a707a8353ac28ece2fd3d98d767e992e87a5b5570ddddc1a5fbba40c86b7de80d9b10ded50433b34602eb10c2365e36ea6804ce2d998039446de240c43e6012698d5302e72326e963754490dafbf86b35f7b2d54f537a974697e06bc1522971101452065ce01846c2a34f1402dda8dab9d02e642da303736ac8cedb551c4f684ccbd5e403a00a236d5709f73ee80ff800228f1fefd00b9961740620addb70748ccebecb486d43b031aa5f375a47d6ddc426568631aa6cd8669b3a18d6928611a16cd86caa561b66c685a06f04de59ec23052366e8437aeac0aa88418cfb10c28eaa4d0933a9fcb013c51ea6327953f698493772f3c47c72c86eaa661f51cc07b496565acfd899af2c1011b4014ed234d9501aa7ca97aaf428f2abc57a52754aa51972744892b4d27b51643f37380dec2788e2d0f2897f12d645e173095938d0bdc0da3e9d8c17c298dae4d09c86a67adc70ccd4f7b5daf152084d2fd950045392fe84f1aeae3bc8ef3e40f893f24fef03a1f3eee27efc0019098d7e9fcd4f7fdc02c6bd1c6d030a30e50a198511b5a7986329ea1716728da198a76865add802ed0b88a5e9ca10e37f6733fc0023c51cabe5096ec2f6c91795d407b010a61d05b92466cd4e102288bb16e91b3cd80a9136868b80df80834d27293bba1e1665c2816306f1a1aa028861474de02ce043c2126d0775f340f1a5a7086df5d431dceb8ed3d808a1d34dd7164401593474d430b6e00514db9a4fc364069a4fc6668b80d5094dced8e3df10610f54b149f890104e7ba0154959104ed35c3836efcae9a58976a0f2c80d2f053736f7b807a38de716d6934a6ce690d7d36439fcd70936bcb8717e4ff4269cd562d6e0334bcafafb91f0c986bad014469305f759662b8db3534d3067c0485e714a2fc81d92cabfc67067cebc95a9d0ed800e55afe0e81faea2a2d8280a94510f0e639d467990bbc00eab3d45360944ec5162ac65a624dfb06ec02de9d1f6d4d99a822c853a016401b66da304f2db801aa863cbb06b8b26b473f40959701e000e52a5969b4010fa0cebaeb30e050e51b156b5d51fd9d80f9ca78210ed0f7c20b7180be0eb6c9869ed538105276d675a857599268cc50af32b4aa0cbfc486b9714006d433d31f89fff49ba30465e83e191e8603b402492cc3d0863294a00c252843e569806ab8cf55b7a1fb6449e62d8691b2619b1c407d18ebf0151c30cfc30d95a7002df0d07d32749f0234d6a10465e83e194e830dcfc00314c2b207dd2743f7c9507932dcf61a37dd07d0e032e134eee033eea3376edc33eed73394972c75fd68a9d3496eca926745c3907900219a34919f1abe5e0354b1fca3093a4bcbd4325d22ebd243435a1aa03f25cb447100216a844cb7c9ba49c7b850deb835de10ad0668f8ca521d376e8db771239480276bf767c8588debe30dd1ea8002104576ba1fe6cf86af57c3c5ab212d0d981b79436c1af0a528fa617e6b8ac4fbabe1fd751c5e26200ba8c6c15bd00ff1fe6a485dc749e70b2044835e3ea861e62d2448356ca50df9a961fe3c600136a000245e49a3dd16e2d7800464a27853fe02cca82d6b773ce00094585ef40d41aa61613d404fe69709304121844ec2523f40af2361eb00d2d00895d259fc63a01da0c133cb339e61586ddc756858581b1e590d81ac71b3a1217535a4aec69dec86f8d5c66d4680a2583060f56c785b35bcad1a12d50184f040e781ce033b0fec545e065c0394eb260d0348d6bd42b1c4510fc735eb38cf4e82a91a64f868b5a2a3b301ff014f94094e9e7c1275125509b10788bac8d57f01a591be8de1be75c00190661eb41a0e5d0336a2de44f1164b7d40a52fd487354959a8c64235d2b4d1b02229a7e1acd570d66a4552ce71cc9f01a2367269f7874357c36bab15163985454e619113405999a8f3812ee075e4616fc00610456366de22f3dd3355cd09a0ce793a980dd05a34e01b200d7d8311a9e47c0b34d117c628bcb60e5987a0f1711b8dd968439658a5d16274f561bc2de02b77354b65133a2ca205fa612b934b959de6805956a33f371df306a8f29176010aa0c4126d04e8c9b81730241ad67e492cdb7fc3f63fc01ed073feb4f568cc9e78680c986656d6369bfb386cff037426d3760d95edad152c96fe8604c130f0377ca21a06fe8681ff800210f50768b06a4c2e4d8e3403a833b303a204437060080e02689ff226f19b90e3017d0b0e82f0806af80730fc030c508869fac3cda9e10d2040f369636bd6e8512e9d1343a610b013a21ecec9bf71e06f9cea0f388013d093a5573940510c201ce607a88707988042191302ba404b474fcf038d106a98298217ec8c995c36673d4d9349e380dd3aabf74e6fe9d216330ecf8dc373eb6cf6393c370ecf07748166fcce12a29f3cf9d481246e60872cf107501a96079cb4dbad7fb9711f6bfbd1b033fc67a4095a9db6550bc521d6fbdf2f33fc1cffef396d97d957e3de8af89908d1816ddb8f399c0e58800228974cdadb7e11d293126baa6defd7dcfdb5b79c90342e150dd895e66bbe69405188e69d011bf0df84f75c740d502eed9be2e77e6055d44935cef91734ee241d30d31cf2761830a7ec80b97f6f28cd0634a5f99a82ef010750042afd908c2360ba1d6bc7f7d4a76ddc7f1a3057d4019990acb2be29ebe7a56afccc9f3a80c43f4dd590f94f3be48e6fb87656d4dfa2d7d16d830308697af2fa52c89a5443693a35946fdbf18f6a6cbce0c69337de5417e8342e660d20f14ee29dc46f9aeebd28d79bca9f6497b7ba014a2cb775ed283cb9a407fe00bd45a53e950756dab052685d5468a57de44a2e80b29ccaeb802b60ae33db29715ec074ccd84ebece292f8eedd4a96c3b75c573433b6b4c178a922fc176d27b4f8d096d78759f40e54f59a4b6d3f45f70996c80ba7a794dedd921e50654b122c1ee00a22a2126f852b3145d1a1ef3984a2f92f00ed00375fd65c01ceb5a915781c65502ad302215291e0f50f6c40313a5d337ca41d44176daa7548d4845be0403f45186f7a2098c4855037eab3a1e69551374abd20319305b35da7236cbc59b5ebce9d5e669eaf5fa6e029d355df8a5b95ef26274e1c4f8422c787189e7858f97017d82ce9a0292b2ef3c5032df0b572a1752b301caae6b342f7c985cf830b9109f5d7823b990765d38f2bd90765d3821b910695d5c5b19301db15e88b402d20bf8080e427877dde0165f8266a964aff6808ad0f5cd1792a30b2f2201b6008a7242b492199f6b019e90f9e4451df2c263c0851ce4e226c16bd1d9ce85c3d20b3fa517fe01ae657d2b846fba248ad02a658042743813f053011350c4ce73a4c17e2d9a6a07ec02b24b7e71e120f4427e71e117f4423611a0365ca40d7e61f67e2126b8b871ef425e304045d453892538b890175c8bcef42eccd52fccd5afe5f9161f75e3e59eaa1d1756b401733cbc704139e003cc8a71f07b71f07b71f07b71961be00f28ea577f01c7bc57e29b26dd7c7d25d9205c9cd306cc11f2e29cf64a722874253e0127ae01df7a0e3f5a3a780e7f5c800bd49f937cb45e9caf5eb1bbfd01145278a06e83bd385f0df87b01aabc66bd8ba3d7007db854a96ae581fc71a9aa3fa77a00596f2a6fab579273838babd302f83abab1fae2c6b40b5f94034cc027b868968bd29f9e70cf1dfdb52f1ad9b898ecc29cedc270e6cadf5353f7c24ce6c20426604a9c03e6147965ad60afcc9f8bc3c98bc3d8008d0059f2ca8b43d48bb3d38bb3d30126d808d1bb07907d6eb22e8e55032ed268f4cbf2387a71e07671ce76e5a66f9adbaed771d238b93e73d97ce57b9d51e5a5ae5518888ad4b9af22f9ce0017e84f6912f55e78d8bbd0001ca0907d1e3e0468406bbc0ebb487fbde6c1e650555b800c284a5a8b03944b73e5800290e64fcf910fb70013e85f76ee1d706e19703cb639770a044cd701fe5ab3eaa333ab009e23eb33675e76d4759c7939c0c845a19aa09d4b01061c4001484359b26f1a4008d97772ede492676967c67774729c9bb81d9d1ce726ee003eca9b27bf79a0bcda3a2ece9ce581b33c18a0ec5a27384a358e524dc0be00841caacf41fb1c54e3b895f83f1a4113d000a529d4a7509fb23c21b7806ae854c4519871b4621cad9880aa6f5aa84fe5813a2709e039f57c802872d9dca3394a2cfe921dabe3c72c808ac9dd93e3d92c80fe73f15ed7f284a82ca72339514ef60fb93ef48d0f693a511a451dd7fd43e3f207a882e92cda71eee46898f8a2f3ba0015b1c873c550d8dc057f4a23db8100fde6786772944f1ce51347d5c4513571d65a8e7726c7c97c80f140b5f3f24b08bff992289dff14cf4b8ee725e742675ff83d596b0550677ea20095ce4f84ce897347b32f127b398b2e6789e5e881384bac189d3330b5fb9c3552ec18a98f51041f973592afaf69a0ed38de71d41b1c7f3bceb5c20173de1940d494960e989f12173a0308d118b5ea502e40a3df2a63a8016f81be200e731c4585802ee0a3ac8ca2a82e38aa0b8e571c4763212003e703642f05204a8db94a65d7f193e3b8c719d0055365d7571dd407e45f40b93285661a537e690690a6ea5b645eb9f1c046f63ed7368e7e82a384e02821384a088eee81e305dd937c900e784294f857233f3ecf3d49453f40535bd294ed282178929e95e392c5514270740f02c8be3fb9fe1142c5e8fc281838ea04ce2ad759dc0e5035f82f5027184014cdc23491a499efac8403f4e7e2656540019486d92115a2ca1355f4e44a1a06fce83e446964c3bfbae353c593d1bc467623bb0e5a9d2b8307e8bd18d559dc3a8b5b8f71e8006608fa09011a9f514b70ae97f5fc3b4d261d0b6b47e81f3065e28e65b4e3cfdc91e33bcb4b47583f4051ef79b2ed5cb13a2009a806f33b4ecb1da7e5ce3daa8ef772c77b7900afa39d8b2388774c9b1da7e58eaff201ab60da2a3a96c8ce05a601ef07949dd99c25f1003df0a306e7d24c47eaea485dbde8a219e75ccb8b4c53bd30d615d97206a808849b8e703340d5402ce885b105019f239873ee3174ee2874aef0f3c62a05c39080e9bbd8b9abcedb676e54bdf32f77fe65d4f80354f94eefedeabd1faecbf9a0d0388090b9d7fbe02b2f601e4d07ccaa7eb234ee3ec8a03f5d128480693618a0ec5dee7f03ba40dedd07fc2f7b7f69e1d15f9218064cc9e3803e41c369c0f680126bf1dff1d2dc59f3772e0beb2cf53b777bf5d7c673b6793cdb5963777c05778ece029a42348e7516c0fd754e7dec014a23d9cd006597ed5bc0b7aaa18e1d409dcbafea5378b296b201b48f343a06e839469d1b0f94fa7400d5d07f3140f5d162b2738dd400a294eb4bf360ffdea77c2740cff9961d62ff91b95f80a250690e5881b972e8ac33030a89f55ecbf73c2cea68327734993b7e413bebcc21a053626d543b8bb7ce9a2de00d9c803adba20bee3b8e2be39f54675bf828b885ecdc4a13f084d803aaa174d53a7e1dfbd2b60794469eff0728ca09f9d0745af2f55f59bff6a45d6447b7b0331df7243f159d79b0a37ad7136f91780b14ed02e640d499c802e6a262fcb83364972646df29149735fd4d59f96bea030c9885326df5ac0d42c04ac8dc1876f4e202164248f337878b0107a0288dbd3dff7b298a6609d8810228d7d61445dfc8b258e9f93d75893bd779f47c50fa41a1fcdd4c6d9d69aba3a6d599920288e2bbe7560ee0093141d5bbf35766e7815279eaf8970898b6039dd9aa232be9255d337b3996f94dabfcf776d3bdc01d6d8ddee4462640a368e38f6b3a93e96862746c4b3b7a17bdf1e1b8f7b673dd6d0089a576d89be6828ede456fef77069498966f8c998ddedb18e25aa1f47bce3b375700dc8cfcf72bfdbc802e98ffcefddae661e38dbbf81be7f00149b98e7f8029971cd5de1c50dc8ce1f74bba19374ed46ffc99df6cc0ef975452ef97567a37dbed9b393760fae11ca028f9edb9910e44e67922742ff2cd723322dd6c276f06a29b5de4cd007273c3d4bdcabbd79dbee611e5cda1f7cddee14e520a0d985d22609e23dd8c36777a7f254021c777069e902e98d71fdc6c076e16ff378bff8039c8dc3854bc63f8ca8042ca9426df2803dfb8190c9892d07b977b9c0133577e4de1dd9da52a10a076ce72437de7651eea0ed801a591fad0cd054377e6ddf3412ec9d16ef4576ff4576ff4576f06903b16c92f40359413b61b8f4037daaa378be43b3faf233bb201aa7c493ba0c4a528aaf1402d806f86941b33eabb4913e3e6dae5001581f6d1ddee3942de5c611c30ffd3bbebd83020c6ccfffb7f0a5a7929a9760100"
ABSENT = "absent"
PRESENT = "present"
CORRECT = "correct"
DISPLAY = {ABSENT: ".", PRESENT: "+", CORRECT: "*"}
WINNER = [CORRECT] * 5
CONGRATS = ["Genius", "Magnificent", "Impressive", "Splendid", "Great", "Phew"]
MAXTRIES = 6
KEY = f"""
Key:
{DISPLAY[ABSENT]} = letter not present
{DISPLAY[PRESENT]} = letter in an incorrect position
{DISPLAY[CORRECT]} = letter in the correct position"""
# Seed date for the OG game
SEED_DATE: date = date(2021, 6, 19)
# Initialize the word lists
ANSWER_WORDS = json.loads(gzip.decompress(bytes.fromhex(GZLA)).decode("ascii"))
ACCEPT_WORDS = json.loads(gzip.decompress(bytes.fromhex(GZTA)).decode("ascii"))
# paste the NYT word list here to test reconciliation
NYTLIST = []
# As of 2022-02-17 the New York Times has removed several items from ANSWER_WORDS (and added none)
# As of 2022-03-20 the New York Times has relocated words too
# Relocation map is {index in original list, index in NYT list}
NYT_RELOCATED = {
241: None,
245: None,
274: None,
287: 2297,
295: None,
305: None,
320: 2298,
322: 2295,
365: 2303,
387: 2296,
393: 2299,
396: None,
411: 2293,
444: 2306,
448: 2301,
472: 2294,
479: 2304,
482: 2300,
504: 2305,
529: 2307,
530: 2302,
531: 2308,
}
def nyt_display_num(og_gamenum):
"""
Produce the adjusted 'nyt' date-number to display for an 'og' datenumber.
Return None if the og_datenumber was removed (it's not playable in NYT mode).
>>> nyt_display_num(1234)
1212
>>> nyt_display_num(248) # tacit
246
>>> nyt_display_num(245) is None
True
>>> nyt_display_num(274) is None
True
>>> nyt_display_num(244)
243
>>> nyt_display_num(241) is None
True
"""
adjust = 0
for index, moved in enumerate(sorted(list(NYT_RELOCATED))):
if og_gamenum == moved:
return NYT_RELOCATED[og_gamenum]
if og_gamenum > moved:
adjust = index + 1
return og_gamenum - adjust
def _effective_gamenum(gamenum, og_mode):
"""Adjusted game-number"""
if og_mode:
return gamenum
return nyt_display_num(gamenum)
def wordnum(dte: date, og_mode: bool) -> int:
"""
word-number for a date is the index of the word in the ANSWER_WORDS.
In NYT mode, this isn't necessarily what gets displayed!
>>> wordnum(date(2022, 2, 19), True)
245
>>> wordnum(date(2022, 2, 19), False)
247
>>> wordnum(date(2022, 2, 20), True)
246
>>> wordnum(date(2022, 2, 20), False)
248
>>> wordnum(date(2022, 3, 18), False) in NYT_RELOCATED
False
"""
if dte > date.today() or dte < SEED_DATE:
# Uh-oh! Suspected timeline causality violation!
dte = SEED_DATE
# day-number for a date is the number of days since SEED_DATE
daynum = round((dte - SEED_DATE).total_seconds() / 86400)
if not og_mode:
# relocate if needed
if NYT_RELOCATED.get(daynum):
daynum = NYT_RELOCATED[daynum]
# adjust for the missing NYT words
for moved in NYT_RELOCATED:
if not NYT_RELOCATED[moved]:
if daynum >= moved:
daynum = daynum + 1
# don't ever fall off the end of the list please
index = daynum % len(ANSWER_WORDS)
return index
if NYTLIST:
# test for reconciliation
for idx, word in enumerate(NYTLIST):
if word not in ANSWER_WORDS:
sys.exit(word)
for idx, word in enumerate(ANSWER_WORDS):
if word in NYTLIST:
nyt = nyt_display_num(idx)
if idx > 0 and not nyt:
sys.exit(f"No {word} at {idx}")
if word != NYTLIST[nyt]:
if word in ANSWER_WORDS:
print(f"{word} is at {NYTLIST.index(word)} in NYT, not {nyt}")
else:
sys.exit(f"{word} at {idx} is {NYTLIST[nyt]}")
@contextmanager
def paper_tape_output():
"""
Use `with paper_tape_output():` to wrap writing binary data to the terminal, for punching on tape.
"""
# If the terminal doesn't support hardcopy, safe to assume it doesn't support paper tape output.
# (Don't use curses.tcgetstr(), because setupterm() fails on tty33)
if os.system("tput hc"):
yield False
return
term = os.environ.get("TERM").lower()
if term == "tty33-amx":
# Escape sequence to initialize 8-bit-clean output (turn off wordwrap, NLCR, delays)
# (Usually a teletype wouldn't have firmware that handles escape sequences,
# but mine does, https://github.com/hughpyle/ASR33/tree/master/firmware).
# Also mine doesn't have DC2/DC4 control (it's just missing that hardware).
init = b"\033[?7l\033_ab\234"
reset = b"\033[!p"
else:
# Turn the tape punch on with DC2, off with DC4
# (Note: for full binary fidelity you also need to send DC2 after printing any DC4, not done here)
init = b"\022"
reset = b"\024"
if sys.stdout.isatty():
fdi = sys.stdout.fileno()
tci = termios.tcgetattr(fdi)
tty.setraw(fdi)
sys.stdout.buffer.write(init)
yield True
sys.stdout.buffer.write(reset)
if sys.stdout.isatty():
termios.tcsetattr(fdi, termios.TCSADRAIN, tci)
def time_to_midnight() -> str:
"""
How long to the next word is available at midnight?
(datetime grumble grumble)
"""
mid = datetime.combine(date.today() + timedelta(days=1), datetime.min.time())
dur = mid - datetime.now().replace(microsecond=0)
return f"Next word in {dur}"
def printable(result) -> str:
"""
printable version of a result
"""
disp = [DISPLAY[it] for it in result]
return "".join(disp)
def punchable(result) -> int:
"""
byte version of a result, for paper tape
"""
byte = 0
for item in result:
byte = byte << 1
# Punch tape only has "hole" or "no hole",
# let's ignore the PRESENT result and only punch for CORRECT
if item == CORRECT:
byte = byte | 1
return byte << 3
class Game:
"""
A game (identified by its number in the original wordlist). Saves into ~/.wordle/<number>.
"""
def __init__(self, og_mode: bool = True, gamenum: int = None):
if gamenum and gamenum > wordnum(date.today(), og_mode):
gamenum = 0
self.og_mode = og_mode
self.gamenum = gamenum
self.words = []
self.confdir = pathlib.Path.home() / ".wordle"
self.load()
def load(self):
"""Load words from save file"""
os.makedirs(self.confdir, exist_ok=True)
if self.filepath and self.filepath.exists():
with self.filepath.open() as gfd:
self.words = gfd.readline().strip().split()
return True
return False
def in_progress(self):
"""Is there an unfinished game in progress?"""
for game in self.all_games():
if not (game.won or game.lost):
return game
return None
def random(self):
"""Make a new game for a random date before today. May raise IndexError."""
# Check the game numbers up to today
available = set()
for num in range(wordnum(date.today(), self.og_mode)):
if _effective_gamenum(num, self.og_mode) is None:
continue
available.add(num)
# Remove game numbers that have been played already
for game in self.all_games():
if game.gamenum in available:
available.remove(game.gamenum)
# Choice
try:
return Game(og_mode=self.og_mode, gamenum=random.choice(list(available)))
except IndexError:
raise IndexError("There are no rounds to play.")
def all_games(self):
"""Generator for all the played games in history"""
for gamefile in self.confdir.iterdir():
try:
wnum = int(gamefile.name)
yield Game(og_mode=self.og_mode, gamenum=wnum)
except (OSError, ValueError):
pass
@property
def effective_gamenum(self):
"""Adjusted game-number"""
return _effective_gamenum(self.gamenum, self.og_mode)
@property
def won(self):
"""Was this game won?"""
return self.words and ANSWER_WORDS[self.gamenum] == self.words[-1]
@property
def lost(self):
"""Was this game lost?"""
return self.words and not self.won and len(self.words) == MAXTRIES
@property
def played(self):
"""Was this game played?"""
return self.won or self.lost
@property
def filepath(self):
"""Path to the save-file"""
if self.gamenum is not None:
return self.confdir / f"{self.gamenum:05}"
def save(self):
"""Save the guesses"""
if self.filepath:
with open(self.filepath, "w", encoding="utf-8") as fscore:
# Save file is just one line, space-separated list of the used words
fscore.write(" ".join(self.words) + "\n")
def print_stats(self):
"""Calculate and print the statistics"""
# Read all the score files and collect stats
games = {}
stats = [0] * (MAXTRIES + 1)
played = 0
won = 0
maxnum = 0
for game in self.all_games():
gn = game.effective_gamenum
if gn is None:
# OG result but we're using NYT numbering, ignore it
continue
games[gn] = game
played = played + 1
maxnum = max(maxnum, gn)
# Update the histogram
if game.won:
won = won + 1
stats[len(game.words)] = stats[len(game.words)] + 1
# Calculate the streaks
cstreak = 0
mstreak = 0
for wnum in range(maxnum + 1):
if wnum in games and games[wnum].won:
cstreak = cstreak + 1
mstreak = max(cstreak, mstreak)
else:
cstreak = 0
# Print the stats
print(
"\nPlayed Win % Current streak Max streak"
f"\n{played:>6} {round(100*won/played):>5} {cstreak:>14} {mstreak:>11}"
)
print("\nGuess distribution:")
for idx in range(1, MAXTRIES + 1):
print(str(idx) + " : " + ("*" * stats[idx]))
print()
if maxnum >= wordnum(date.today(), self.og_mode):
print(time_to_midnight())
def _play(self, hard_mode: bool = False):
"""
ask for guesses and evaluate them
return a list of the evaluation results, if you won
"""
matches = []
ing = 1
def _test(word, wordchar, testchar):
# test a single character (testchar)
if testchar == wordchar:
return CORRECT
if testchar in word:
return PRESENT
return ABSENT
def _match(guess):
# evaluate a guess (word) against the answer, as a 5-element array of [CORRECT, PRESENT, etc].
word = ANSWER_WORDS[self.gamenum]
match = [_test(word, wordc, testc) for wordc, testc in zip(word, guess)]
matches.append(match)
print(f" {printable(match)}")
return match
while ing <= MAXTRIES:
if ing <= len(self.words):
# Print any previous guesses (if we're starting from a saved game)
guess = self.words[ing - 1]
print(f"\nGuess {ing}/{MAXTRIES}: {guess}")
else:
# Get the next guess
guess = input(f"\nGuess {ing}/{MAXTRIES}: ").casefold()
used = {char for word in self.words for char in word}
miss = used - set(ANSWER_WORDS[self.gamenum])
hits = used - miss
if guess == "":
continue
if guess == "?":
print(
"Used: "
+ "".join(sorted(hits))
+ " "
+ "".join(sorted(miss))
)
print(
"Unused: "
+ "".join(sorted(set(string.ascii_lowercase) - used))
)
continue
if len(guess) < 5:
print("Not enough letters.")
continue
if len(guess) > 5:
print("Too many letters.")
continue
if hard_mode and (hits - set(guess)):
print(f"You must include {sorted(hits - set(guess))}")
continue
if hard_mode and (set(guess) & miss):
print(f"You must not include {sorted(set(guess) & miss)}")
continue
if guess in self.words:
print("You already tried that!")
continue
if not (guess in ANSWER_WORDS or guess in ACCEPT_WORDS):
print("Not in word list.")
continue
self.words.append(guess)
# Save the words (every time! so we can pick up if interrupted)
self.save()
match = _match(guess)
if match == WINNER:
print(f"\n{CONGRATS[ing-1]}!")
return matches
ing = ing + 1
print(f"\nThe word was '{ANSWER_WORDS[self.gamenum]}'. Better luck next time!")
return None
def play(self, hard_mode: bool = False):
"""
Play the game
"""
if self.played:
print(f"You already played round {self.effective_gamenum}.")
print(time_to_midnight())
return False
har_desc = " (hard mode)" if hard_mode else ""
og_desc = " (original wordlist)" if self.og_mode else ""
print(f"Wordle {self.effective_gamenum}{har_desc}{og_desc}.")
if not hard_mode:
print(KEY)
# do the main loop
blocks = self._play(hard_mode=hard_mode)
if self.won:
num = len(blocks)
else:
num = "X"
blocks = []
# Print the summary blocks
print()
print(f"\nWordle {self.effective_gamenum} {num}/{MAXTRIES}\n")
print("\n".join([printable(result) for result in blocks]))
print()
# Print the summary blocks in the lower 5 bits, for tape punching
leading = bytearray([0xFF for _ in range(MAXTRIES)])
spacing = bytearray([0x00 for _ in range(MAXTRIES)])
summary = bytearray([punchable(result) for result in blocks])
with paper_tape_output() as tape:
if tape:
sys.stdout.buffer.write(leading + spacing + summary + spacing + leading)
sys.stdout.buffer.write(spacing)
sys.stdout.buffer.write(spacing)
print()
# Print the all-time statistics
self.print_stats()
return True
def main():
"""
play the game
"""
pars = argparse.ArgumentParser(description="Wordle for Teletype.")
pars.add_argument("gamenum", type=str, nargs="?", help="play a date (YYYY-MM-DD)")
pars.add_argument("-g", "--og", action="store_true", help="use OG numbering")
pars.add_argument("-d", "--hard", action="store_true", help="play in hard mode")
pars.add_argument("-y", "--today", action="store_true", help="play today's round")
pars.add_argument("-r", "--random", action="store_true", help="play a random round")
pars.add_argument("-s", "--stats", action="store_true", help="print statistics")
args = pars.parse_args()
gamenum = None
if args.gamenum:
# If 'gamenum', try parse it as a date or integer
try:
dt = date.fromisoformat(args.gamenum)
gamenum = wordnum(dt, args.og)
except ValueError:
try:
gamenum = int(args.gamenum)
except ValueError:
sys.exit("Not a number or date")
try:
# If there's an open game, restart it
tody = wordnum(date.today(), args.og)
game = Game(og_mode=args.og).in_progress()
if game:
game.play(hard_mode=args.hard)
elif gamenum:
Game(og_mode=args.og, gamenum=gamenum).play(hard_mode=args.hard)
elif args.today:
Game(og_mode=args.og, gamenum=tody).play(hard_mode=args.hard)
elif args.random:
Game(og_mode=args.og).random().play(hard_mode=args.hard)
elif args.stats:
Game(og_mode=args.og).print_stats()
else:
if not Game(og_mode=args.og, gamenum=tody).play(hard_mode=args.hard):
pars.print_usage()
except (EOFError, KeyboardInterrupt, IndexError, PermissionError) as exc:
sys.exit(exc)
if __name__ == "__main__":
main()