diff --git a/04/.solve02.py.swp b/04/.solve02.py.swp new file mode 100644 index 0000000..103e477 Binary files /dev/null and b/04/.solve02.py.swp differ diff --git a/04/input.txt b/04/input.txt new file mode 100644 index 0000000..7cac52b --- /dev/null +++ b/04/input.txt @@ -0,0 +1,966 @@ +[1518-03-30 00:57] wakes up +[1518-04-15 23:56] Guard #2213 begins shift +[1518-10-31 00:36] wakes up +[1518-11-14 00:03] Guard #2129 begins shift +[1518-04-01 00:54] wakes up +[1518-10-03 00:42] falls asleep +[1518-07-01 00:19] falls asleep +[1518-08-02 00:00] Guard #3319 begins shift +[1518-07-03 00:01] falls asleep +[1518-08-28 00:24] falls asleep +[1518-11-02 00:31] falls asleep +[1518-10-15 00:04] falls asleep +[1518-08-07 00:51] wakes up +[1518-05-02 00:14] falls asleep +[1518-05-16 00:38] falls asleep +[1518-08-27 00:37] falls asleep +[1518-09-18 00:47] wakes up +[1518-05-29 00:52] wakes up +[1518-09-07 00:06] falls asleep +[1518-07-14 00:52] wakes up +[1518-05-09 00:59] wakes up +[1518-05-14 00:12] falls asleep +[1518-04-17 23:51] Guard #439 begins shift +[1518-11-20 00:04] Guard #2129 begins shift +[1518-07-21 00:02] Guard #3347 begins shift +[1518-11-16 00:04] Guard #241 begins shift +[1518-04-02 23:48] Guard #1777 begins shift +[1518-07-11 00:00] Guard #241 begins shift +[1518-07-29 00:49] falls asleep +[1518-09-14 00:38] falls asleep +[1518-05-27 00:39] wakes up +[1518-04-09 00:54] wakes up +[1518-11-01 23:56] Guard #103 begins shift +[1518-10-07 00:42] wakes up +[1518-09-26 00:58] wakes up +[1518-09-10 00:54] falls asleep +[1518-08-15 00:48] falls asleep +[1518-06-09 00:01] Guard #2251 begins shift +[1518-11-06 23:58] Guard #103 begins shift +[1518-10-04 00:29] falls asleep +[1518-08-02 00:56] falls asleep +[1518-08-21 00:18] falls asleep +[1518-11-23 00:30] falls asleep +[1518-09-29 23:59] Guard #829 begins shift +[1518-09-17 00:49] falls asleep +[1518-07-25 00:49] wakes up +[1518-08-19 00:58] wakes up +[1518-07-13 00:48] wakes up +[1518-04-11 23:59] Guard #2539 begins shift +[1518-04-30 00:32] wakes up +[1518-07-05 00:27] falls asleep +[1518-09-02 00:29] wakes up +[1518-09-21 00:58] wakes up +[1518-04-26 00:08] falls asleep +[1518-04-23 00:26] wakes up +[1518-05-25 00:55] wakes up +[1518-05-14 23:58] Guard #241 begins shift +[1518-09-09 23:58] Guard #3319 begins shift +[1518-04-23 00:23] falls asleep +[1518-08-08 00:42] wakes up +[1518-06-12 00:03] falls asleep +[1518-03-31 00:03] Guard #103 begins shift +[1518-04-11 00:58] wakes up +[1518-03-28 00:53] falls asleep +[1518-06-29 23:57] Guard #103 begins shift +[1518-05-08 00:36] falls asleep +[1518-11-18 00:00] Guard #2137 begins shift +[1518-03-31 00:21] falls asleep +[1518-05-08 00:57] falls asleep +[1518-06-18 00:50] falls asleep +[1518-05-08 00:06] falls asleep +[1518-05-09 00:23] falls asleep +[1518-08-24 00:00] Guard #1301 begins shift +[1518-07-07 00:57] wakes up +[1518-10-24 00:51] wakes up +[1518-08-29 00:31] falls asleep +[1518-08-27 00:51] falls asleep +[1518-08-19 00:54] falls asleep +[1518-10-05 00:02] Guard #3347 begins shift +[1518-04-04 00:14] falls asleep +[1518-10-17 00:01] Guard #2389 begins shift +[1518-05-07 00:57] wakes up +[1518-11-17 00:01] Guard #1889 begins shift +[1518-07-09 00:54] wakes up +[1518-07-12 00:02] falls asleep +[1518-04-23 00:00] Guard #2137 begins shift +[1518-05-02 00:00] Guard #1283 begins shift +[1518-07-08 23:58] Guard #2389 begins shift +[1518-11-08 00:48] falls asleep +[1518-11-06 00:48] wakes up +[1518-06-25 00:46] wakes up +[1518-06-03 23:57] Guard #3371 begins shift +[1518-05-19 23:50] Guard #3371 begins shift +[1518-06-10 00:04] Guard #3371 begins shift +[1518-11-20 00:36] falls asleep +[1518-10-10 23:58] Guard #2539 begins shift +[1518-07-09 00:42] falls asleep +[1518-09-09 00:21] wakes up +[1518-05-10 00:03] Guard #3347 begins shift +[1518-06-18 00:47] wakes up +[1518-05-16 00:55] wakes up +[1518-06-23 00:41] falls asleep +[1518-08-27 00:39] wakes up +[1518-05-26 00:03] falls asleep +[1518-07-10 00:03] Guard #2389 begins shift +[1518-10-14 00:02] Guard #2389 begins shift +[1518-06-09 00:40] wakes up +[1518-07-01 00:55] wakes up +[1518-04-11 00:15] falls asleep +[1518-10-11 00:55] wakes up +[1518-06-25 00:24] falls asleep +[1518-04-29 00:45] falls asleep +[1518-11-04 00:02] Guard #1889 begins shift +[1518-07-20 00:04] Guard #2129 begins shift +[1518-05-06 00:32] falls asleep +[1518-04-27 00:08] falls asleep +[1518-11-11 00:33] falls asleep +[1518-11-21 00:22] falls asleep +[1518-10-28 00:50] falls asleep +[1518-07-24 00:19] falls asleep +[1518-10-21 00:10] falls asleep +[1518-09-19 00:01] Guard #2389 begins shift +[1518-03-31 00:57] wakes up +[1518-11-20 00:46] wakes up +[1518-05-28 00:41] falls asleep +[1518-11-18 23:56] Guard #439 begins shift +[1518-04-04 00:50] falls asleep +[1518-10-09 00:27] wakes up +[1518-11-16 00:47] falls asleep +[1518-08-03 00:42] wakes up +[1518-10-17 00:57] falls asleep +[1518-10-27 00:22] wakes up +[1518-07-29 00:03] Guard #2251 begins shift +[1518-10-06 00:18] falls asleep +[1518-07-31 00:23] falls asleep +[1518-09-05 00:00] Guard #1283 begins shift +[1518-11-10 23:59] Guard #439 begins shift +[1518-10-16 00:53] wakes up +[1518-10-31 00:57] wakes up +[1518-09-15 00:58] wakes up +[1518-05-30 00:59] wakes up +[1518-08-13 00:38] wakes up +[1518-09-08 00:42] wakes up +[1518-09-05 00:17] falls asleep +[1518-03-28 23:59] Guard #1777 begins shift +[1518-06-11 00:52] falls asleep +[1518-06-16 00:46] falls asleep +[1518-06-22 00:49] wakes up +[1518-06-27 23:58] Guard #2389 begins shift +[1518-10-15 00:42] wakes up +[1518-10-14 00:11] falls asleep +[1518-07-10 00:52] falls asleep +[1518-06-14 00:22] falls asleep +[1518-11-01 00:50] wakes up +[1518-09-21 23:59] Guard #1777 begins shift +[1518-05-23 00:43] wakes up +[1518-05-11 00:47] wakes up +[1518-09-02 23:57] Guard #1889 begins shift +[1518-06-12 00:32] wakes up +[1518-03-31 00:54] falls asleep +[1518-10-18 00:46] falls asleep +[1518-08-24 23:56] Guard #1889 begins shift +[1518-04-10 00:21] wakes up +[1518-07-23 00:01] Guard #3347 begins shift +[1518-10-08 00:08] falls asleep +[1518-09-28 00:00] falls asleep +[1518-04-18 00:57] wakes up +[1518-05-26 00:44] falls asleep +[1518-10-30 00:22] falls asleep +[1518-11-14 00:42] falls asleep +[1518-11-04 00:40] wakes up +[1518-04-09 00:38] falls asleep +[1518-06-24 23:57] Guard #1283 begins shift +[1518-06-02 00:01] Guard #1283 begins shift +[1518-07-16 00:30] wakes up +[1518-07-21 00:57] wakes up +[1518-11-23 00:57] falls asleep +[1518-09-01 00:45] wakes up +[1518-07-17 00:45] falls asleep +[1518-04-01 00:51] falls asleep +[1518-04-24 00:00] Guard #3347 begins shift +[1518-09-18 00:02] Guard #631 begins shift +[1518-05-13 00:23] wakes up +[1518-04-25 00:54] wakes up +[1518-04-14 00:02] Guard #1889 begins shift +[1518-09-12 00:13] falls asleep +[1518-08-26 00:57] falls asleep +[1518-08-13 00:02] Guard #439 begins shift +[1518-10-06 00:56] wakes up +[1518-10-01 00:32] wakes up +[1518-10-17 00:20] wakes up +[1518-07-28 00:01] falls asleep +[1518-10-28 00:59] wakes up +[1518-04-01 00:36] falls asleep +[1518-04-01 00:46] wakes up +[1518-05-24 00:01] Guard #2539 begins shift +[1518-04-24 00:41] wakes up +[1518-10-06 23:59] Guard #2903 begins shift +[1518-10-17 00:52] falls asleep +[1518-10-12 00:17] falls asleep +[1518-10-27 00:49] wakes up +[1518-08-22 00:01] falls asleep +[1518-08-16 00:57] wakes up +[1518-09-06 23:59] Guard #631 begins shift +[1518-04-17 00:01] Guard #103 begins shift +[1518-08-06 00:25] falls asleep +[1518-10-24 00:15] falls asleep +[1518-11-04 00:39] falls asleep +[1518-03-27 00:11] falls asleep +[1518-04-19 23:59] Guard #439 begins shift +[1518-10-29 00:55] wakes up +[1518-05-05 00:20] wakes up +[1518-10-02 00:49] wakes up +[1518-05-30 23:57] Guard #631 begins shift +[1518-09-11 00:41] wakes up +[1518-06-02 00:08] falls asleep +[1518-11-16 00:44] wakes up +[1518-10-27 23:52] Guard #1319 begins shift +[1518-10-10 00:00] Guard #1487 begins shift +[1518-08-16 00:54] falls asleep +[1518-05-20 00:00] falls asleep +[1518-07-29 00:14] wakes up +[1518-08-10 00:19] wakes up +[1518-08-04 00:00] Guard #439 begins shift +[1518-09-22 00:59] wakes up +[1518-11-12 23:57] Guard #1889 begins shift +[1518-11-01 00:38] falls asleep +[1518-08-09 00:56] falls asleep +[1518-07-20 00:47] wakes up +[1518-05-08 00:29] wakes up +[1518-06-12 00:56] falls asleep +[1518-06-15 23:56] Guard #2213 begins shift +[1518-05-13 00:03] Guard #1889 begins shift +[1518-10-18 00:19] falls asleep +[1518-07-10 00:30] wakes up +[1518-09-21 00:50] falls asleep +[1518-07-04 00:58] wakes up +[1518-11-09 00:46] falls asleep +[1518-05-13 00:59] wakes up +[1518-06-05 23:56] Guard #2251 begins shift +[1518-05-25 00:03] Guard #1213 begins shift +[1518-06-19 00:01] Guard #2903 begins shift +[1518-08-16 00:04] Guard #2213 begins shift +[1518-11-06 00:07] falls asleep +[1518-04-30 00:27] falls asleep +[1518-06-24 00:50] wakes up +[1518-05-27 23:58] Guard #3347 begins shift +[1518-10-22 00:22] falls asleep +[1518-05-26 00:29] wakes up +[1518-05-20 00:37] falls asleep +[1518-09-16 23:58] Guard #2903 begins shift +[1518-04-29 00:08] falls asleep +[1518-08-18 00:56] wakes up +[1518-08-22 00:42] wakes up +[1518-04-08 00:40] wakes up +[1518-08-02 00:53] wakes up +[1518-09-14 00:58] wakes up +[1518-10-06 00:07] falls asleep +[1518-04-28 00:49] wakes up +[1518-09-25 23:58] Guard #3319 begins shift +[1518-04-29 00:34] falls asleep +[1518-04-12 00:36] wakes up +[1518-05-19 00:29] wakes up +[1518-06-02 00:59] wakes up +[1518-08-03 00:24] falls asleep +[1518-05-28 00:13] falls asleep +[1518-04-15 00:02] Guard #1301 begins shift +[1518-09-30 00:32] falls asleep +[1518-07-27 23:50] Guard #1777 begins shift +[1518-06-15 00:15] falls asleep +[1518-10-09 00:03] falls asleep +[1518-04-30 00:03] Guard #1889 begins shift +[1518-09-15 00:03] falls asleep +[1518-08-30 00:20] falls asleep +[1518-06-16 00:30] falls asleep +[1518-05-08 00:03] Guard #2213 begins shift +[1518-05-17 00:51] falls asleep +[1518-06-12 00:58] wakes up +[1518-07-21 00:41] falls asleep +[1518-06-08 00:43] falls asleep +[1518-05-17 00:00] falls asleep +[1518-06-07 00:38] wakes up +[1518-05-14 00:26] falls asleep +[1518-04-16 00:26] wakes up +[1518-06-21 00:35] wakes up +[1518-10-27 00:58] wakes up +[1518-11-18 00:49] falls asleep +[1518-10-29 00:23] falls asleep +[1518-05-20 00:53] wakes up +[1518-05-18 00:00] Guard #1777 begins shift +[1518-05-24 00:44] falls asleep +[1518-11-13 00:31] falls asleep +[1518-07-16 00:58] wakes up +[1518-08-29 00:36] wakes up +[1518-10-26 23:51] Guard #2389 begins shift +[1518-07-26 00:53] falls asleep +[1518-07-14 00:56] wakes up +[1518-05-13 00:15] falls asleep +[1518-10-09 00:44] falls asleep +[1518-09-11 00:48] falls asleep +[1518-05-11 00:00] Guard #2903 begins shift +[1518-08-01 00:00] Guard #2129 begins shift +[1518-06-04 00:57] wakes up +[1518-06-19 00:42] wakes up +[1518-05-04 00:10] falls asleep +[1518-05-09 00:24] wakes up +[1518-10-21 00:51] wakes up +[1518-09-01 00:03] Guard #1319 begins shift +[1518-04-18 00:24] falls asleep +[1518-09-16 00:03] Guard #439 begins shift +[1518-07-18 00:50] falls asleep +[1518-07-20 00:06] falls asleep +[1518-05-08 00:46] wakes up +[1518-06-19 00:26] falls asleep +[1518-04-27 00:18] wakes up +[1518-07-30 00:54] falls asleep +[1518-07-31 00:45] wakes up +[1518-07-27 00:42] wakes up +[1518-08-15 00:38] wakes up +[1518-10-30 00:38] wakes up +[1518-08-04 23:57] Guard #1213 begins shift +[1518-08-01 00:41] falls asleep +[1518-08-23 00:03] Guard #829 begins shift +[1518-08-06 00:29] wakes up +[1518-11-08 00:50] wakes up +[1518-08-28 00:47] falls asleep +[1518-06-28 00:50] falls asleep +[1518-05-10 00:53] wakes up +[1518-06-11 00:54] wakes up +[1518-06-06 00:55] wakes up +[1518-10-28 23:56] Guard #103 begins shift +[1518-06-10 00:06] falls asleep +[1518-11-09 00:51] wakes up +[1518-05-16 00:18] falls asleep +[1518-03-28 00:16] falls asleep +[1518-04-19 00:53] wakes up +[1518-08-26 00:59] wakes up +[1518-09-20 00:00] Guard #2777 begins shift +[1518-10-11 00:45] falls asleep +[1518-08-09 00:00] Guard #2389 begins shift +[1518-06-01 00:46] wakes up +[1518-10-14 00:28] falls asleep +[1518-06-11 23:53] Guard #2251 begins shift +[1518-11-20 00:51] falls asleep +[1518-11-07 00:38] falls asleep +[1518-08-20 00:02] falls asleep +[1518-08-01 00:54] falls asleep +[1518-06-11 00:01] falls asleep +[1518-10-01 00:37] falls asleep +[1518-10-31 00:50] falls asleep +[1518-04-09 00:02] Guard #2129 begins shift +[1518-06-01 00:15] wakes up +[1518-04-21 00:02] Guard #2539 begins shift +[1518-07-22 00:00] falls asleep +[1518-09-28 00:58] wakes up +[1518-08-06 00:00] Guard #1319 begins shift +[1518-10-14 23:50] Guard #3319 begins shift +[1518-03-29 00:55] wakes up +[1518-08-10 00:49] wakes up +[1518-06-20 00:55] wakes up +[1518-04-19 00:08] falls asleep +[1518-11-01 00:08] falls asleep +[1518-04-01 00:01] Guard #3371 begins shift +[1518-06-29 00:33] falls asleep +[1518-08-21 00:01] Guard #1213 begins shift +[1518-08-21 23:51] Guard #1319 begins shift +[1518-06-17 00:04] falls asleep +[1518-05-22 00:54] falls asleep +[1518-11-12 00:30] wakes up +[1518-07-17 00:04] Guard #1283 begins shift +[1518-06-05 00:08] falls asleep +[1518-04-04 00:55] wakes up +[1518-07-23 00:53] wakes up +[1518-06-09 00:14] falls asleep +[1518-05-10 00:37] falls asleep +[1518-08-08 00:02] Guard #1213 begins shift +[1518-09-06 00:46] wakes up +[1518-09-07 23:57] Guard #1889 begins shift +[1518-07-18 00:55] wakes up +[1518-07-24 00:59] wakes up +[1518-05-05 00:54] wakes up +[1518-11-22 00:36] falls asleep +[1518-07-18 00:27] wakes up +[1518-10-09 00:58] wakes up +[1518-06-18 00:01] Guard #2137 begins shift +[1518-10-19 00:53] falls asleep +[1518-03-31 00:24] wakes up +[1518-09-27 00:02] falls asleep +[1518-09-12 00:56] wakes up +[1518-11-08 00:57] wakes up +[1518-10-02 00:03] Guard #1213 begins shift +[1518-06-09 00:59] wakes up +[1518-10-20 23:56] Guard #2539 begins shift +[1518-10-12 00:01] Guard #2251 begins shift +[1518-07-06 00:32] falls asleep +[1518-06-05 00:55] wakes up +[1518-10-22 00:12] wakes up +[1518-08-20 00:47] wakes up +[1518-11-17 00:42] wakes up +[1518-07-11 23:52] Guard #1283 begins shift +[1518-10-20 00:29] falls asleep +[1518-04-10 23:58] Guard #103 begins shift +[1518-07-24 00:51] falls asleep +[1518-08-12 00:50] wakes up +[1518-09-27 00:35] wakes up +[1518-10-13 00:02] Guard #103 begins shift +[1518-06-29 00:47] wakes up +[1518-10-28 00:02] falls asleep +[1518-05-10 00:44] wakes up +[1518-10-22 00:01] falls asleep +[1518-05-22 00:48] wakes up +[1518-06-19 00:56] falls asleep +[1518-06-25 00:41] falls asleep +[1518-07-07 00:51] falls asleep +[1518-10-18 00:52] wakes up +[1518-09-18 00:51] falls asleep +[1518-08-25 00:36] wakes up +[1518-06-10 00:49] wakes up +[1518-09-07 00:17] wakes up +[1518-10-01 00:31] falls asleep +[1518-04-18 00:05] falls asleep +[1518-09-23 00:01] Guard #439 begins shift +[1518-06-13 00:46] wakes up +[1518-04-20 00:30] wakes up +[1518-08-23 00:10] falls asleep +[1518-05-29 00:03] Guard #2903 begins shift +[1518-05-24 00:36] wakes up +[1518-09-24 23:57] Guard #1283 begins shift +[1518-05-28 00:46] wakes up +[1518-05-22 00:23] falls asleep +[1518-11-15 00:48] wakes up +[1518-06-01 00:21] falls asleep +[1518-05-17 00:58] wakes up +[1518-07-14 00:55] falls asleep +[1518-09-15 00:51] falls asleep +[1518-11-18 00:59] wakes up +[1518-05-25 00:17] falls asleep +[1518-08-17 00:03] Guard #3371 begins shift +[1518-04-04 00:03] Guard #1777 begins shift +[1518-09-29 00:40] wakes up +[1518-07-22 00:52] wakes up +[1518-05-07 00:04] Guard #2129 begins shift +[1518-09-27 23:54] Guard #1319 begins shift +[1518-04-29 00:09] wakes up +[1518-10-17 00:59] wakes up +[1518-07-06 00:46] wakes up +[1518-07-27 00:04] Guard #241 begins shift +[1518-08-10 00:00] Guard #241 begins shift +[1518-07-29 00:56] wakes up +[1518-07-12 00:17] wakes up +[1518-05-13 00:33] falls asleep +[1518-05-30 00:26] falls asleep +[1518-04-03 00:02] falls asleep +[1518-08-21 00:56] wakes up +[1518-04-21 00:39] wakes up +[1518-11-07 00:41] wakes up +[1518-10-24 00:03] Guard #2129 begins shift +[1518-07-16 00:53] falls asleep +[1518-04-07 00:57] wakes up +[1518-06-22 00:10] falls asleep +[1518-10-25 00:45] wakes up +[1518-09-04 00:04] falls asleep +[1518-04-14 00:58] wakes up +[1518-06-15 00:52] wakes up +[1518-04-13 00:02] Guard #3319 begins shift +[1518-07-15 00:01] Guard #1283 begins shift +[1518-07-22 00:36] wakes up +[1518-06-03 00:00] Guard #439 begins shift +[1518-05-23 00:27] falls asleep +[1518-07-16 00:00] Guard #1777 begins shift +[1518-08-15 00:06] falls asleep +[1518-05-15 00:58] wakes up +[1518-09-11 00:49] wakes up +[1518-11-19 00:55] wakes up +[1518-04-06 00:37] wakes up +[1518-07-15 00:13] falls asleep +[1518-08-28 00:03] Guard #1777 begins shift +[1518-07-21 23:51] Guard #3371 begins shift +[1518-09-08 00:27] falls asleep +[1518-07-08 00:02] Guard #241 begins shift +[1518-08-11 00:52] wakes up +[1518-09-09 00:32] falls asleep +[1518-08-13 23:59] Guard #3371 begins shift +[1518-07-19 00:53] wakes up +[1518-08-05 00:46] wakes up +[1518-07-01 00:53] falls asleep +[1518-09-11 00:03] Guard #241 begins shift +[1518-11-13 00:41] wakes up +[1518-11-11 00:39] wakes up +[1518-08-02 00:59] wakes up +[1518-09-09 00:42] wakes up +[1518-10-05 00:48] falls asleep +[1518-09-29 00:00] Guard #2903 begins shift +[1518-08-01 00:59] wakes up +[1518-04-12 00:54] wakes up +[1518-09-18 00:23] falls asleep +[1518-09-04 00:47] wakes up +[1518-04-02 00:03] Guard #1777 begins shift +[1518-04-05 23:58] Guard #2251 begins shift +[1518-05-16 00:26] wakes up +[1518-04-05 00:00] falls asleep +[1518-05-04 00:31] wakes up +[1518-06-13 00:30] falls asleep +[1518-09-06 00:50] falls asleep +[1518-07-02 00:05] falls asleep +[1518-11-08 00:04] Guard #1213 begins shift +[1518-03-29 00:08] falls asleep +[1518-04-21 00:15] falls asleep +[1518-06-30 00:39] falls asleep +[1518-10-24 23:56] Guard #1319 begins shift +[1518-05-20 00:28] wakes up +[1518-06-12 00:20] wakes up +[1518-09-11 00:29] falls asleep +[1518-05-09 00:57] falls asleep +[1518-06-03 00:33] wakes up +[1518-05-18 00:31] falls asleep +[1518-05-28 00:26] wakes up +[1518-09-26 00:35] falls asleep +[1518-05-09 00:00] Guard #3347 begins shift +[1518-10-27 00:28] falls asleep +[1518-04-25 00:38] falls asleep +[1518-11-01 00:15] wakes up +[1518-10-27 00:05] falls asleep +[1518-05-26 00:48] wakes up +[1518-09-25 00:49] wakes up +[1518-05-21 00:44] falls asleep +[1518-05-11 23:59] Guard #2137 begins shift +[1518-11-02 23:58] Guard #829 begins shift +[1518-04-29 00:37] wakes up +[1518-07-22 00:22] wakes up +[1518-03-29 00:10] wakes up +[1518-06-05 00:02] Guard #2389 begins shift +[1518-10-31 00:43] wakes up +[1518-05-03 00:43] falls asleep +[1518-05-18 00:57] wakes up +[1518-06-14 00:52] wakes up +[1518-07-10 00:27] falls asleep +[1518-05-17 00:13] wakes up +[1518-06-24 00:36] falls asleep +[1518-08-02 00:21] falls asleep +[1518-08-31 00:49] wakes up +[1518-09-09 00:09] falls asleep +[1518-08-23 00:26] wakes up +[1518-06-03 00:56] wakes up +[1518-07-24 23:57] Guard #3371 begins shift +[1518-07-16 00:45] wakes up +[1518-08-17 00:27] falls asleep +[1518-10-22 00:46] wakes up +[1518-04-12 00:22] wakes up +[1518-05-04 00:56] wakes up +[1518-10-17 00:53] wakes up +[1518-04-10 00:45] wakes up +[1518-06-29 00:34] wakes up +[1518-09-05 00:46] wakes up +[1518-04-13 00:18] falls asleep +[1518-07-27 00:24] wakes up +[1518-08-29 00:44] falls asleep +[1518-10-19 00:54] wakes up +[1518-11-02 00:41] wakes up +[1518-07-11 00:33] falls asleep +[1518-09-15 00:57] falls asleep +[1518-07-28 00:49] wakes up +[1518-06-30 23:57] Guard #1283 begins shift +[1518-09-25 00:06] falls asleep +[1518-11-04 00:28] falls asleep +[1518-10-20 00:34] wakes up +[1518-10-24 00:38] wakes up +[1518-04-21 00:57] falls asleep +[1518-06-25 00:29] wakes up +[1518-05-16 23:51] Guard #3371 begins shift +[1518-06-24 00:21] falls asleep +[1518-07-17 00:47] wakes up +[1518-09-09 00:02] Guard #1283 begins shift +[1518-07-11 00:52] wakes up +[1518-07-16 00:28] falls asleep +[1518-09-30 00:52] wakes up +[1518-06-30 00:36] wakes up +[1518-04-20 00:06] falls asleep +[1518-08-14 00:33] falls asleep +[1518-10-18 00:00] Guard #241 begins shift +[1518-09-14 00:48] wakes up +[1518-10-02 00:06] falls asleep +[1518-05-31 00:57] wakes up +[1518-05-31 00:23] falls asleep +[1518-03-28 00:33] wakes up +[1518-11-20 23:56] Guard #1283 begins shift +[1518-03-31 00:50] wakes up +[1518-07-05 00:04] Guard #2213 begins shift +[1518-08-25 00:22] falls asleep +[1518-06-20 00:03] Guard #103 begins shift +[1518-03-29 00:20] falls asleep +[1518-06-27 00:12] falls asleep +[1518-04-09 23:56] Guard #631 begins shift +[1518-06-08 00:45] wakes up +[1518-09-15 00:54] wakes up +[1518-05-22 00:02] Guard #3347 begins shift +[1518-08-09 00:59] wakes up +[1518-04-26 23:58] Guard #829 begins shift +[1518-04-25 23:56] Guard #2251 begins shift +[1518-10-27 00:57] falls asleep +[1518-06-27 00:35] wakes up +[1518-06-03 00:51] falls asleep +[1518-10-06 00:14] wakes up +[1518-10-13 00:23] wakes up +[1518-09-22 00:39] wakes up +[1518-06-02 00:34] wakes up +[1518-09-10 00:34] wakes up +[1518-07-13 00:40] falls asleep +[1518-06-14 00:03] Guard #1283 begins shift +[1518-10-04 00:32] wakes up +[1518-07-23 00:09] falls asleep +[1518-06-27 00:03] Guard #2251 begins shift +[1518-07-27 00:31] falls asleep +[1518-07-03 00:49] wakes up +[1518-10-28 00:37] wakes up +[1518-08-11 00:00] falls asleep +[1518-06-26 00:19] falls asleep +[1518-03-27 00:03] Guard #2251 begins shift +[1518-05-03 00:57] wakes up +[1518-06-28 23:56] Guard #3347 begins shift +[1518-05-05 00:04] Guard #3347 begins shift +[1518-10-14 00:14] wakes up +[1518-09-11 00:57] wakes up +[1518-05-04 00:00] Guard #3319 begins shift +[1518-06-11 00:41] wakes up +[1518-04-29 00:50] wakes up +[1518-09-17 00:41] wakes up +[1518-05-10 00:57] falls asleep +[1518-09-03 00:32] wakes up +[1518-11-01 00:02] Guard #3371 begins shift +[1518-08-01 00:43] wakes up +[1518-04-16 00:23] falls asleep +[1518-05-05 00:27] falls asleep +[1518-07-12 00:52] wakes up +[1518-04-21 00:58] wakes up +[1518-06-05 00:47] falls asleep +[1518-07-30 00:59] wakes up +[1518-08-17 23:57] Guard #631 begins shift +[1518-04-10 00:33] falls asleep +[1518-08-29 00:51] wakes up +[1518-06-02 00:56] falls asleep +[1518-06-28 00:43] wakes up +[1518-07-26 00:55] wakes up +[1518-07-12 23:59] Guard #1283 begins shift +[1518-07-05 00:53] wakes up +[1518-07-04 00:10] falls asleep +[1518-04-06 23:56] Guard #2137 begins shift +[1518-11-22 00:25] wakes up +[1518-08-15 00:52] wakes up +[1518-08-04 00:38] falls asleep +[1518-09-12 00:00] Guard #103 begins shift +[1518-11-10 00:50] wakes up +[1518-07-02 23:52] Guard #631 begins shift +[1518-05-25 23:46] Guard #631 begins shift +[1518-11-03 00:50] wakes up +[1518-06-10 23:50] Guard #439 begins shift +[1518-05-02 23:58] Guard #2539 begins shift +[1518-09-01 00:29] falls asleep +[1518-04-12 00:32] falls asleep +[1518-07-07 00:02] Guard #3371 begins shift +[1518-07-30 00:04] Guard #2129 begins shift +[1518-08-29 00:57] falls asleep +[1518-09-14 00:00] Guard #2213 begins shift +[1518-09-24 00:43] falls asleep +[1518-11-16 00:57] wakes up +[1518-05-04 00:53] falls asleep +[1518-09-29 00:34] falls asleep +[1518-09-03 00:24] falls asleep +[1518-11-16 00:06] falls asleep +[1518-08-04 00:59] wakes up +[1518-04-28 00:07] falls asleep +[1518-10-03 00:54] wakes up +[1518-10-08 00:27] falls asleep +[1518-03-27 00:57] wakes up +[1518-05-01 00:53] wakes up +[1518-06-20 23:59] Guard #1319 begins shift +[1518-04-08 00:02] Guard #1889 begins shift +[1518-06-23 23:59] Guard #241 begins shift +[1518-11-22 00:14] falls asleep +[1518-09-02 00:11] falls asleep +[1518-11-21 00:42] wakes up +[1518-08-19 23:47] Guard #1889 begins shift +[1518-04-07 00:45] falls asleep +[1518-08-25 00:15] wakes up +[1518-08-25 23:57] Guard #829 begins shift +[1518-08-10 23:47] Guard #1213 begins shift +[1518-09-16 00:09] falls asleep +[1518-07-18 00:18] falls asleep +[1518-10-26 00:01] Guard #829 begins shift +[1518-07-14 00:35] falls asleep +[1518-11-03 00:40] falls asleep +[1518-09-18 00:56] wakes up +[1518-10-31 00:10] falls asleep +[1518-08-28 00:56] wakes up +[1518-05-01 00:07] falls asleep +[1518-10-06 00:02] Guard #3347 begins shift +[1518-04-10 00:11] falls asleep +[1518-05-08 00:58] wakes up +[1518-07-24 00:24] wakes up +[1518-08-29 00:59] wakes up +[1518-06-29 00:39] falls asleep +[1518-06-13 00:52] falls asleep +[1518-06-28 00:17] falls asleep +[1518-07-29 00:07] falls asleep +[1518-06-16 00:43] wakes up +[1518-04-22 00:01] Guard #2777 begins shift +[1518-04-08 00:16] falls asleep +[1518-06-13 00:59] wakes up +[1518-06-01 00:35] wakes up +[1518-05-29 00:35] falls asleep +[1518-06-19 00:59] wakes up +[1518-09-13 00:33] falls asleep +[1518-09-28 00:31] wakes up +[1518-06-07 00:00] Guard #3319 begins shift +[1518-06-13 00:00] Guard #3347 begins shift +[1518-05-09 00:48] wakes up +[1518-05-10 00:32] wakes up +[1518-10-23 00:03] Guard #103 begins shift +[1518-10-13 00:17] falls asleep +[1518-07-17 23:59] Guard #1319 begins shift +[1518-06-04 00:38] falls asleep +[1518-09-24 00:53] wakes up +[1518-08-29 00:03] Guard #1889 begins shift +[1518-08-12 00:27] falls asleep +[1518-04-26 00:56] wakes up +[1518-07-02 00:32] wakes up +[1518-10-20 00:56] falls asleep +[1518-09-13 00:50] wakes up +[1518-08-31 00:33] falls asleep +[1518-07-08 00:39] falls asleep +[1518-10-26 00:24] wakes up +[1518-05-27 00:24] falls asleep +[1518-05-15 00:54] falls asleep +[1518-05-10 00:16] falls asleep +[1518-04-19 00:03] Guard #1319 begins shift +[1518-06-09 00:55] falls asleep +[1518-06-26 00:00] Guard #1319 begins shift +[1518-03-28 00:54] wakes up +[1518-05-09 00:46] falls asleep +[1518-11-04 00:33] wakes up +[1518-07-12 00:26] falls asleep +[1518-04-17 00:37] wakes up +[1518-05-06 00:56] wakes up +[1518-05-03 00:34] wakes up +[1518-04-02 00:10] wakes up +[1518-06-10 00:54] wakes up +[1518-03-31 00:29] falls asleep +[1518-07-22 00:39] falls asleep +[1518-09-14 00:52] falls asleep +[1518-05-05 00:17] falls asleep +[1518-06-08 00:00] Guard #2389 begins shift +[1518-07-13 00:59] wakes up +[1518-10-08 00:03] Guard #2251 begins shift +[1518-07-08 00:40] wakes up +[1518-05-14 00:39] wakes up +[1518-07-25 00:33] falls asleep +[1518-08-09 00:48] wakes up +[1518-11-12 00:01] falls asleep +[1518-08-11 00:26] wakes up +[1518-05-27 00:02] Guard #1283 begins shift +[1518-10-29 00:36] wakes up +[1518-11-14 00:43] wakes up +[1518-08-08 00:21] falls asleep +[1518-10-01 00:04] Guard #829 begins shift +[1518-11-12 00:56] falls asleep +[1518-05-12 00:52] falls asleep +[1518-04-29 00:01] Guard #1777 begins shift +[1518-08-13 00:31] falls asleep +[1518-05-07 00:48] falls asleep +[1518-04-05 00:59] wakes up +[1518-10-31 00:04] Guard #3319 begins shift +[1518-10-13 00:49] wakes up +[1518-05-14 00:19] wakes up +[1518-10-20 00:57] wakes up +[1518-09-27 00:57] wakes up +[1518-09-11 00:56] falls asleep +[1518-05-03 00:23] falls asleep +[1518-05-12 00:58] wakes up +[1518-10-08 00:54] wakes up +[1518-09-26 23:48] Guard #1213 begins shift +[1518-08-14 00:48] wakes up +[1518-05-21 00:50] wakes up +[1518-10-19 00:01] Guard #3371 begins shift +[1518-11-09 23:58] Guard #241 begins shift +[1518-10-18 00:42] wakes up +[1518-11-05 23:59] Guard #3347 begins shift +[1518-07-13 23:59] Guard #2137 begins shift +[1518-11-22 00:46] wakes up +[1518-11-17 00:31] falls asleep +[1518-06-15 00:40] falls asleep +[1518-11-09 00:09] falls asleep +[1518-09-10 00:07] falls asleep +[1518-05-15 00:19] falls asleep +[1518-09-23 00:50] wakes up +[1518-06-10 00:52] falls asleep +[1518-10-07 00:39] falls asleep +[1518-09-22 00:36] falls asleep +[1518-05-24 00:12] falls asleep +[1518-08-03 00:00] Guard #1319 begins shift +[1518-06-30 00:24] falls asleep +[1518-04-17 00:31] falls asleep +[1518-06-15 00:00] Guard #1777 begins shift +[1518-05-10 00:51] falls asleep +[1518-06-07 00:32] falls asleep +[1518-07-31 00:04] Guard #1213 begins shift +[1518-10-30 00:03] Guard #2251 begins shift +[1518-09-28 00:46] falls asleep +[1518-08-10 00:41] falls asleep +[1518-06-23 00:49] wakes up +[1518-04-13 00:47] wakes up +[1518-05-21 00:04] Guard #241 begins shift +[1518-05-19 00:19] falls asleep +[1518-04-24 00:39] falls asleep +[1518-05-15 23:56] Guard #1777 begins shift +[1518-08-09 00:15] falls asleep +[1518-04-03 00:10] wakes up +[1518-06-03 00:07] falls asleep +[1518-08-31 00:01] Guard #1213 begins shift +[1518-09-06 00:00] Guard #631 begins shift +[1518-11-05 00:01] Guard #439 begins shift +[1518-09-19 00:53] falls asleep +[1518-06-17 00:39] wakes up +[1518-08-27 00:55] wakes up +[1518-10-23 00:12] falls asleep +[1518-08-05 00:40] falls asleep +[1518-10-13 00:26] falls asleep +[1518-04-28 00:03] Guard #1889 begins shift +[1518-08-19 00:01] Guard #2903 begins shift +[1518-05-15 00:26] wakes up +[1518-06-05 00:37] wakes up +[1518-07-15 00:55] wakes up +[1518-09-17 00:56] wakes up +[1518-06-21 00:29] falls asleep +[1518-09-20 23:59] Guard #241 begins shift +[1518-04-04 00:26] wakes up +[1518-10-21 23:49] Guard #241 begins shift +[1518-09-06 00:15] falls asleep +[1518-09-19 00:33] wakes up +[1518-09-23 00:37] falls asleep +[1518-09-19 00:55] wakes up +[1518-04-02 00:08] falls asleep +[1518-07-06 00:00] Guard #2903 begins shift +[1518-07-13 00:57] falls asleep +[1518-05-23 00:00] Guard #3371 begins shift +[1518-10-02 23:58] Guard #2389 begins shift +[1518-06-24 00:30] wakes up +[1518-10-16 00:07] falls asleep +[1518-09-17 00:30] falls asleep +[1518-08-28 00:34] wakes up +[1518-07-19 00:24] falls asleep +[1518-05-31 23:57] Guard #3319 begins shift +[1518-05-01 00:00] Guard #1889 begins shift +[1518-03-30 00:56] falls asleep +[1518-10-19 23:57] Guard #1889 begins shift +[1518-08-26 23:56] Guard #2389 begins shift +[1518-07-26 00:00] Guard #2389 begins shift +[1518-07-19 00:00] Guard #2903 begins shift +[1518-11-08 00:53] falls asleep +[1518-09-14 23:48] Guard #3319 begins shift +[1518-10-03 23:58] Guard #829 begins shift +[1518-11-22 00:02] Guard #3347 begins shift +[1518-10-21 00:42] falls asleep +[1518-11-15 00:04] falls asleep +[1518-08-25 00:11] falls asleep +[1518-05-02 00:35] wakes up +[1518-10-25 00:37] falls asleep +[1518-11-11 23:48] Guard #103 begins shift +[1518-10-08 23:53] Guard #631 begins shift +[1518-10-23 00:38] falls asleep +[1518-07-16 00:34] falls asleep +[1518-11-05 00:41] falls asleep +[1518-10-31 00:41] falls asleep +[1518-11-09 00:04] Guard #1777 begins shift +[1518-06-18 00:55] wakes up +[1518-04-14 00:18] falls asleep +[1518-06-21 23:58] Guard #1777 begins shift +[1518-04-18 00:17] wakes up +[1518-04-06 00:21] falls asleep +[1518-10-05 00:57] wakes up +[1518-05-29 23:58] Guard #2389 begins shift +[1518-06-18 00:46] falls asleep +[1518-07-27 00:18] falls asleep +[1518-08-04 00:25] wakes up +[1518-06-12 00:25] falls asleep +[1518-04-16 00:55] wakes up +[1518-06-01 00:42] falls asleep +[1518-04-16 00:33] falls asleep +[1518-04-24 23:57] Guard #2389 begins shift +[1518-09-19 00:09] falls asleep +[1518-10-14 00:58] wakes up +[1518-09-16 00:53] wakes up +[1518-06-20 00:26] falls asleep +[1518-09-10 00:57] wakes up +[1518-06-16 23:50] Guard #829 begins shift +[1518-10-11 00:33] falls asleep +[1518-08-17 00:53] wakes up +[1518-08-12 00:03] Guard #1889 begins shift +[1518-05-05 23:59] Guard #2129 begins shift +[1518-10-23 00:49] wakes up +[1518-10-24 00:43] falls asleep +[1518-05-10 00:59] wakes up +[1518-04-11 00:57] falls asleep +[1518-06-15 00:35] wakes up +[1518-08-15 00:00] Guard #1777 begins shift +[1518-08-10 00:12] falls asleep +[1518-07-01 23:52] Guard #439 begins shift +[1518-06-26 00:57] wakes up +[1518-11-23 00:35] wakes up +[1518-11-05 00:51] wakes up +[1518-04-04 23:54] Guard #2389 begins shift +[1518-11-14 23:47] Guard #2903 begins shift +[1518-04-11 00:50] wakes up +[1518-10-26 00:11] falls asleep +[1518-09-06 00:56] wakes up +[1518-05-22 00:55] wakes up +[1518-06-28 00:56] wakes up +[1518-05-24 00:56] wakes up +[1518-08-11 00:46] falls asleep +[1518-06-30 00:56] wakes up +[1518-06-16 00:57] wakes up +[1518-09-27 00:46] falls asleep +[1518-06-01 00:11] falls asleep +[1518-04-12 00:07] falls asleep +[1518-08-04 00:14] falls asleep +[1518-07-22 00:34] falls asleep +[1518-08-07 00:47] falls asleep +[1518-08-29 23:59] Guard #829 begins shift +[1518-11-19 00:19] falls asleep +[1518-03-30 00:01] Guard #3347 begins shift +[1518-09-15 00:19] wakes up +[1518-08-18 00:55] falls asleep +[1518-10-01 00:45] wakes up +[1518-10-29 00:48] falls asleep +[1518-10-21 00:27] wakes up +[1518-07-03 23:56] Guard #1777 begins shift +[1518-08-06 23:59] Guard #241 begins shift +[1518-10-08 00:22] wakes up +[1518-09-22 00:52] falls asleep +[1518-06-23 00:03] Guard #241 begins shift +[1518-11-20 00:57] wakes up +[1518-03-27 23:58] Guard #3319 begins shift +[1518-09-25 00:56] falls asleep +[1518-06-06 00:52] falls asleep +[1518-09-03 23:49] Guard #2137 begins shift +[1518-08-30 00:39] wakes up +[1518-11-12 00:59] wakes up +[1518-10-23 00:25] wakes up +[1518-07-24 00:01] Guard #439 begins shift +[1518-04-12 00:52] falls asleep +[1518-11-23 00:59] wakes up +[1518-11-09 00:37] wakes up +[1518-11-22 23:57] Guard #1889 begins shift +[1518-05-11 00:27] falls asleep +[1518-09-02 00:03] Guard #3371 begins shift +[1518-10-16 00:03] Guard #3319 begins shift +[1518-05-18 23:56] Guard #3319 begins shift +[1518-09-13 00:02] Guard #1319 begins shift +[1518-11-10 00:40] falls asleep +[1518-05-13 23:56] Guard #1213 begins shift +[1518-09-25 00:59] wakes up +[1518-07-01 00:47] wakes up +[1518-10-17 00:13] falls asleep +[1518-10-12 00:31] wakes up +[1518-09-24 00:03] Guard #2137 begins shift +[1518-10-11 00:35] wakes up +[1518-07-10 00:59] wakes up diff --git a/04/input_sample.txt b/04/input_sample.txt new file mode 100644 index 0000000..496d314 --- /dev/null +++ b/04/input_sample.txt @@ -0,0 +1,17 @@ +[1518-11-01 00:00] Guard #10 begins shift +[1518-11-01 00:05] falls asleep +[1518-11-01 00:25] wakes up +[1518-11-01 00:30] falls asleep +[1518-11-01 00:55] wakes up +[1518-11-01 23:58] Guard #99 begins shift +[1518-11-02 00:40] falls asleep +[1518-11-02 00:50] wakes up +[1518-11-03 00:05] Guard #10 begins shift +[1518-11-03 00:24] falls asleep +[1518-11-03 00:29] wakes up +[1518-11-04 00:02] Guard #99 begins shift +[1518-11-04 00:36] falls asleep +[1518-11-04 00:46] wakes up +[1518-11-05 00:03] Guard #99 begins shift +[1518-11-05 00:45] falls asleep +[1518-11-05 00:55] wakes up diff --git a/04/solve01.py b/04/solve01.py new file mode 100755 index 0000000..9977b87 --- /dev/null +++ b/04/solve01.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +from datetime import datetime +import re + +RE_BEGIN = re.compile("^\[(.*)\] Guard #(\d+) begins shift$") +RE_SLEEP = re.compile("^\[(.*)\] falls asleep$") +RE_AWAKE = re.compile("^\[(.*)\] wakes up$") + +guards = dict() + +def read_input(): + with open('input.txt', 'r') as f: + data = f.read().splitlines() + return sorted(data) + +def convert_time(data): + return datetime.strptime(data, '%Y-%m-%d %H:%M') + +def guard_stop_shift(guard, date): + guard_awake(guard, date) + +def guard_start_shift(guard, date): + if guard is None: + return + if guard not in guards: + guards[guard] = { + 'guard': guard, + 'state': 'awake', + 'min': [0]*60, + 'sleep': 0, + 'last_time': None + } + guard_awake(guard, date) + +def guard_sleep(guard, date): + if guard is None: + return + guards[guard]['state'] = 'sleep' + guards[guard]['last_time'] = date + +def guard_awake(guard, date): + if guard is None: + return + if guards[guard]['state'] in ['awake']: + guards[guard]['last_time'] = date + return + + m = int((date - guards[guard]['last_time']).total_seconds() / 60) + m1 = guards[guard]['last_time'].minute + for x in range(m): + m2 = (x + m1) % 60 + guards[guard]['min'][m2] += 1 + guards[guard]['sleep'] += m + guards[guard]['state'] = 'awake' + guards[guard]['last_time'] = date + + +current_guard = None +for line in read_input(): + m = RE_BEGIN.match(line) + if m: + d = convert_time(m.group(1)) + guard_stop_shift(current_guard, d) + current_guard = (int)(m.group(2)) + guard_start_shift(current_guard, d) + continue + + m = RE_SLEEP.match(line) + if m: + d = convert_time(m.group(1)) + guard_sleep(current_guard, d) + continue + + m = RE_AWAKE.match(line) + if m: + d = convert_time(m.group(1)) + guard_awake(current_guard, d) + continue + + print(line) + raise Exception('unpasable line') + +max_sleep = max(guards.values(), key=lambda i: i['sleep']) +max_min = max(max_sleep['min']) +max_min_pos = [i for i, j in enumerate(max_sleep['min']) if j == max_min] + +print(max_sleep['guard'] * max_min_pos[0]) diff --git a/04/solve02.py b/04/solve02.py new file mode 100755 index 0000000..1a54ac2 --- /dev/null +++ b/04/solve02.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +from datetime import datetime +import re + +RE_BEGIN = re.compile("^\[(.*)\] Guard #(\d+) begins shift$") +RE_SLEEP = re.compile("^\[(.*)\] falls asleep$") +RE_AWAKE = re.compile("^\[(.*)\] wakes up$") + +guards = dict() + +def read_input(): + with open('input.txt', 'r') as f: + data = f.read().splitlines() + return sorted(data) + +def convert_time(data): + return datetime.strptime(data, '%Y-%m-%d %H:%M') + +def guard_stop_shift(guard, date): + guard_awake(guard, date) + +def guard_start_shift(guard, date): + if guard is None: + return + if guard not in guards: + guards[guard] = { + 'guard': guard, + 'state': 'awake', + 'min': [0]*60, + 'sleep': 0, + 'last_time': None + } + guard_awake(guard, date) + +def guard_sleep(guard, date): + if guard is None: + return + guards[guard]['state'] = 'sleep' + guards[guard]['last_time'] = date + +def guard_awake(guard, date): + if guard is None: + return + if guards[guard]['state'] in ['awake']: + guards[guard]['last_time'] = date + return + + m = int((date - guards[guard]['last_time']).total_seconds() / 60) + m1 = guards[guard]['last_time'].minute + for x in range(m): + m2 = (x + m1) % 60 + guards[guard]['min'][m2] += 1 + guards[guard]['sleep'] += m + guards[guard]['state'] = 'awake' + guards[guard]['last_time'] = date + + +current_guard = None +for line in read_input(): + m = RE_BEGIN.match(line) + if m: + d = convert_time(m.group(1)) + guard_stop_shift(current_guard, d) + current_guard = (int)(m.group(2)) + guard_start_shift(current_guard, d) + continue + + m = RE_SLEEP.match(line) + if m: + d = convert_time(m.group(1)) + guard_sleep(current_guard, d) + continue + + m = RE_AWAKE.match(line) + if m: + d = convert_time(m.group(1)) + guard_awake(current_guard, d) + continue + + print(line) + raise Exception('unpasable line') + +max_min = 0 +max_guard = None + +for g in guards.values(): + m = max(g['min']) + if m > max_min: + max_guard = g + max_min = m + +max_min_pos = [i for i, j in enumerate(max_guard['min']) if j == max_min] + +print(max_guard['guard'] * max_min_pos[0]) diff --git a/05/.solve02.py.swp b/05/.solve02.py.swp new file mode 100644 index 0000000..271b918 Binary files /dev/null and b/05/.solve02.py.swp differ diff --git a/05/input.txt b/05/input.txt new file mode 100644 index 0000000..63227a4 --- /dev/null +++ b/05/input.txt @@ -0,0 +1 @@ +YyjJNnYyLlaEXxejJUMmwWUCcrRuuPZzRXxvVrpPEewWMmuUqBbvVQsSjJqhHQVvjJqGgLlzWwfFZJPpiIjliIXxLtTYyoiZzIOQkKuIDdifFEeiIuUQJjqMmUQqiIZzTWcCwtwxXWnNuUUukhHKMmpGgbBffFFfOosgyYGSCcFUuACzZcAeEaOdDdYytTjJKkiHhILlDKdLlLjJgGQqlDSskccCSsCNDddDLlpeEPIixpPXwWLlQqlLUGguWsSozZVTtbBLyYlvXxFfVnNhHfjJsAaSlLyYCcGgdDYfFpPyYNnyGQqgYyvVFIEezZotTObBDZzDddiOpPoOoRIirHaAWwhvVxGgXvSCcqQssScCuUgGjTteEhHJlLHRrhHHhhJjAaHhAYyVvpMmPaLlkKDOXxofmMFlLwWwWdYyOwrRmMDdUWwrRUudEenNZzpPkKDuBbpPsSonDdWwPpNXxOyNzrRhHSsMmZADwWdawWwWnJjTtGgYPptwiIWTfsSJjGgEbBKkkKevVbBPpFCcUxXbBVvmMbBhHmMdDYrRyyGgYnNtUudXxDeETJWwjtPpmMTlLXxvBhHbVAaefFdDeEXxnNSsYWwykEfFecCxXJjKyLlHhYLlcCLlERAiIhPpHaUunvVTtNgGjJVvlLpPDdWiJjUudDZzIMmqQpLCcdDlvHhVzDdPpZzuWwUZwwWWUumMoeEOnNcCHFcCbBfaAIihjJPwgGBbRrRKktjYyJsFlLrRSsfSNnRrlLAajaAJhHTRrbBCGgcDvVdiIzZkKRrrXWVvwxevtTGgMmVeUubfFBuUQqEeEaAEeQhJjlaALPpHiIqKkQqHUueWvlLVwExgGXxXhEeErmMmQXxqgKwiILlZzqWwzZCnNcQlLLQqlWOokViIgGggGcCGGgGlNnQqLgyAaIiYdDvASspFfPtSsTJjaeETtvVpPUQquDdOoMlkKGgLwWfUtTCcuFmrNnRGDNniICcCmMoOcKuHhUkjFfJdmMfFyGZzgYmsSDdMdDreEDdRBoOAacCpbBPYAaRrMmybWwDoOiIBbEvVgzZGedDMmsIiSqQlLYPpyZzJjYyviIsKGgkSVtTXxdPWwEepJjAcrkKyYuCyYcyRrRrYhrReEHiIlbMmBKkaWwAeEkKOPpoyYjJjJLMdDmMvBbjJnNqevVqQEXIiwWxqQMlLmfFVvFfQNnVkxXKmVIivJjhCcwWTtlrRLAIiaLiIrRCYfFaAycoOlCcDyYuUWwuUdjQqoMHhlLmjJOByAaYBbpPbcCJfQqWwFHxXOoiWwUuITcCtMBbaAlLUuhHmlLxXUHhfbBcCkKWDdQIidDAaqwFQqEedRrIiNnDQqRsSClLlWZzwLYywWzLlNCcMmnZbBYJjyIwWiMJeEPPppzbDdhIiHBZjbBoOLAalvVMxmMXmzZIiNnmkKxXxXtTZxPpXZeEiIjJzsSolLzZOzJjwZzQqwIiWRrwfFIiWvmNnMVoPWwpfFAaDdOWYytTXxrRZzuUdxXDMmZErXxVvRemMzlZzLrRTgGtQGWgGkKwgafvVFQqiIvgPpGVnGmMCclLhHbBgPpNZzlLTVzZvtMjsSORroJmFfIiBqnXFAHhaWwfEePXsSxFfpqdOorBbmMXxCcTIilLCXxgGRkrcvClLXmMxloOLqKfJjeIidDEiIFGgaAhHkQCtTUUuuYytTFfcajJkKTFftmeEMeEXxSsAtTkKckdDaApPtTpPKedDEzZTGgDBYyKPpkbZgcuUdDCrRGcCPpzdpRrQqPQrRqCiiImLrRldDMIzZxXULnNPplHJjhuDdXxcNQXxqtGgkKTMssSSVvnSsNeEvVmYyZzpPZJXxjnNzreGgVUZzuvsLldDSwdDnNWApPaEZznFfDdpPbBPpNtTPpnyYNGNniNnsSIiJjZzsSZIiGgIiEeknNKCjtTiIxXJDdYyciIzPppoOvVPIjJuUaAbBGIizZgfwWNMmnNoOhieEIdDHlTtLndCcDQqWwFYyRrMmvHhHhSsEPpeVgyYRCcTRrtDddiINnNXxnIoOkKcCAaDdiIeFfsSfFCUPaApuzgGZCcUuAblLBkqQPzZyxXYpEeAaPpPpYVvaAHhpQqPBuzZvVUbdDRryfFYyXxdDGtuUeYMmyRrGUuhHkKgRrPyYKkpxtTBbtThEDdXxkKeHXyvVGgBqQbwWYNnhHISsraARLlHHWgGQTtqwhhizZEWwgGTGGgfFjJVhHvBbfBbFfUuQqFtTvVoOoOXxnNIFfGgwWpIiXyYhHxPAiIZzavVpPiTcCFfZsSztXBbqwWmSsDdMQYyqQYkKeEuFOofUiIcCpYyrBbTtUuRCrRcKcCkPwdDWfBbhSaAsSsRrHFFQqBbfdDjkxXKwWoOYyckKCqQHaAhawWcNngGCNnArnkWMmwKMZzmMIOoiqQDdxXBIXxibyYpPmgFvVrVvRRrrTtRYyrRVvYYyJjMmSsDdZzPsSNnXuUxpHhyBbWwAnNafqQGYyZbBIyYAsSaKWwIigGCcxXGgcCMtTnvVPpfFNTtbBmCJjVvZAaiIzfFcPNHFfyYrwfFwWWRCcpPaLLpPlkKlhAaeEMWvVuUzZCJjvVcHQqjJEiIpPbBehkKwmlLsbrUIiKkeEuBbRzuBbLlexXEmdDMggGaAXxgnNGGgbTyYJjmMtEeBPmdhHDbIiuIiCcUBNnbBFfpPMfFVvpGQxXNnqZzYydpPDeEoOnXxNUxFfJjTCcuaAUNnCcKkpLvVJjljJrDdGgRxCcXpPacCqlLZwWnNzChHvVzZcUUuxXAatTCcuxXrRNUuzhHxXCcdDTdDtBbDdiIyYhHFfZNUuJmMeEjGJMmjdDwWgGIiVvSsAYGgyWwjJabBgkKaZqQzAiIXxoroIijJCTtPFvVPpfpclkKLKdDSdkKpPcCDIiUuUXMmiILGglUuQAadXxDqAuUyYBbwWaWwIOiIRrnNwWaGgAozZXgGgGxXxKPfyYFPpYteETyeTtPpEFNLlnbBavVANRvVrnkKjJlcCLMmXaAxYmuUZyYzXxMyLlLzZlfFfSBbtThgGARraAoOaxXHjJtTyYjjZzJjJJsuyYNnVEeveAagAaYyGENnoObAvNnVEIBjdDJDdbWwgGiSVvuoOUsmKkbKrRWwGiIpZQhHqzuUgGMmxkKhsSHfFXHylLzXxWwHhZklLKSMmskjCcJKpvVJuOoUWwPJRZzrjDdFlLXAamRrMrRzOJrRjjJSstTjzgGZJUlLuXVviINnWZzwjRpPBbkKrNnqLlQJDzZdlLWwIiiIaZzAyYxINnSstTinlLxbBiyDdUuiPpWdDwIMmRsSvsSZzCcIzZihbBgiTtIzZGnqQOWJjVvmMwEOoezjgOoWwGqQBDdbdDZPpTttCFfgGcgNnGjJAhHaTHhkrRVvIihHKzTGgtUuJxXnNkKEeBbMBbmSsxfFXCcZvVztTacCAIiEeQrldDfXxFzZLRBbHhqpPYypPVxIzZiNnUuoOnNqQXdnoORrNPpBbtiQqlLmMvVlLyYqQLlVvqwgGrzZRCcFfJEexXOojhHWQQiyYIdDJDaAdiIhHvRrVjyoOYdTwWTRrwWVvfYyrQqDdRFttTsAaBDwWwgGWziIZvlLVdZzIfFxbqQmMBXilLtTbcqQVQqvkYgGykKKaACXVJWwjDdPSsprRjJzIrEeRiaUuAfFoOEehtXRrxTlLHcXxxEefzZFJjXCLleEuLycJjiIxXBBbbCEeOowWSUusgJjKkGSsQqEvfFVerRpmMPeEJuUjSeEaAbBeEstTUsSipPpSsVTtEevPIkLAavVqQlKzaAZcAUuZzWwWwzEeDQqdflLYygGcCFFfZfFRGgrESXxdDszZgIiGrRsSyleELmMSGgsYzrRePeEhHAapTtgGEXxFffWwOKkVTnNbzZBAatvVTbBtvHlSsLhTrRtaAoOZfFzgGgcCGoHFfjJyYhdkKDFfFfGnvVNgAahTtEeHuRrEWweQFfqUFhHihHNnFfjJZzGgIfZwWmuUMzVvFZUucCvVQWwGgSsuUsWwdCcRrKWxXMfFmwWbBTzZucMmCnaAQiIqjZJLvVCwWqiIyYXxNnxXxXZULluznNaqQTtYuLlUzZiIFfJChEeUzZuqQOoaJfFgfcCFBJjbRrGHvVhKxXkjyYQqsSvAaWweFfbpeKkEPBZXHhxzVvCaAcEUxXlLUubjpPpYYyTtVAavAaprSGgjOTtoaAJdDYdQqDIcCiwKGgeEJjxLlKKkkkKDAaVvuaAjJshHEeXsSzZxoJjTPkKpzZtdhHDoBvLlVliILCcLpFfBKkbPlxpcnNuPpaAUBbCZWwJjXxpPpTuPpHhULltEeAaPOojJxXYydMmKwQEeqUuWYOocCYyOoHhyMEekdIiQqiTtbBAaIWcCXxNnfFsShHEeyrRYwOorRhBbJNnjxXYWFfwmMehsSKAakJsNnSQTkuUKDdEerfsSFBMmzZiIGglLLxXlGgupPUPpDdnxXHhbBNbBbRbVvVvBpPBbpKizBbZUcBbxuKkUfFXYybBYeEyUuUueEEeCeERruIaAuUBbdHhmMDofFfWwFyYOGgxVTtvXkBbsSPPpnNfFmQSOossSqqQjJoOesSlLEMlLRreEPvTtVSsdDpOOoocCGgTAatusgGSJWwHXxRJjrEetsoOBbSoOmrqXxzZOQqoLlOHhoAapTNntPOypPuKDDddkshHzaAaUCugGUcgGAaLlXxBbNnXxivVCcIlLlTtLvKkIiWwEecFzCcZfvVdZzutTUSsDUuCazAaJjZUuAVEbXxBqQTttTnNtTKZzkdDWoBbOwNUFfunEerRLlhHsSHhyjJYoQqMmUubqkkZzKDdUVvNkYybBEeHhKlLklGgLKnlzeEdXxnNyYSsnnNQqlTtaATtCcBbWwLIGgiPdDgGpfFOoePOopEOtgGaPbtThHBPaxXAZDdSszdDnRQqrcpuYyHhUPsPpnNwWEeQqSojiIJeZpLAaTPpcCtzxQqvbDGgdBnNDdbUPpujVXHhILlixVvDUuoOlTtzDdZLZPpoOzDdFfecLnlLOwWopPcCJjrRkiInNKNkKJbBGiIgjwwmMNnbBwIPpimMKkJjqQTIiaAGVvDwWdkKPMmpdDXIixhiTAafFtsbBSazZVWjJFWwfoTtEvVMsLlGQdDrRqxXVvgSBbiXxjJyRrYkKwWLloNSWwpLlPsQHhqnmMdKkoOXsSiIwWfFsXqQxZzRrkgHPpnYyofFdBbDXxuYCcyUwWZJdDjzNnOsSfEeyIibAaBeQJAajZlfGgFhvVHpPyJjOpPWwMmRlLAWKktVvTwaEepProiIBdSsDroOLGnNglXxRrpPtTsSWgGwMbBbBnNnmMbXBbrklLKRLrRoOEeBbGAeEagPjlLFCcfWYYsHvVIWuUwrrRDmMQvrWCoOIoOizoOZcQaAqsuUuzZULlUuSTtlLscCXxuUEeoOhXRrhrRVvcCMNregBbGCckCcWwybBzQqDdMmLOolLlvkEeKBmMTNntDUcmMNPcCpncUbBLluCboOBMXxmTyYLtTltCXpQTtjcCcozmMZrROeEdvVfFBblUuPpDdXCcxqgQqPPpscCShHpeEvtTHlLyAfsSBbFaYyYMMmcCrRvVajJdrRRGgrDJjAOoVvtEejJTBbFfwAaWmaAMmmMjJhpPSsCcsSmSsBbqQmHhMMHaYyYyIVvIkgGKNnikWsZzngTtGNvVmEeHhvemMEtTovVmMvdhHRrRrgGkWwNnBbKOopPDpPkKVOopcCYyPoONnaAvVxXOqQVPgGpthHemaAMqDdQEkKeEOCnLlrRsSyMmnXxzqQZozZOCcFoDjJderfFzJvpPgaAtWCcwRXxTtrEggBfIizZkKVvFMrRnRreOGRrgoEOYyosSvGljAaJvCcIYyTtcFGgPppPGggGuaAUTFftnHAagGKRzwWZpPrmMmanqQNgvVdgGDMmGtLlhHTLlUbgGBCcKlLKyYLlqQkkYyaAhkKHdDNbBnuUKIrRiQEevVRGCcQJjxXqgmMQmWtHhzvkbSkErReoOKlLiIsusSKkeEuXxhHUhHUaAyNnJdDrNfFnRMsgGEYyeqwWIiIOoTtidDCNncAaVvLlBjyYbBnNnaANdDhHDqQdNxkKYyXulLsSCZZcCzEPpiIezqNLlnZzZCczKkpaOoqQAqTKkboDtTdwWOBYPpyloZzhHVHhvhHIiqAaZdDqQIicCSFfTtXxwcmMCWgXxiIGsjziDdJjIJjJaAjUuXvVRQNnZKssSSHkKGgpDdHhLlPTtBbiIaAHhlLtTgGhMmZzKTyYtkTtUEePGztTZghDdFoOfXxHpqmMQEReEgGpkPORfFbBMmKHhkvVWuUwPpuqQUkKduqQUdDQqEeyYuUTPpDZzwNaAGgdDnWoAaOfFGgZuUzIidcpwmzZMGgWPVvzocvVRrCrdVvSiPtTpIQYMmyDdqHLlrFfPpfGmMRcCVvxFLBblEefOoRrXMmGnLlNAtpQSsEeqdjjDdZHhzLlJcaJsSjwfHhpPFsSvVMEeUumdDUAavVuNnoOgGWbLMmgzKkuUZAawPpzKkZRrWIUuoOfMmJjzZRNYynDdrgiIGtTOKiIkFsSDdiIEeAxXafVvFzZyQqYYaAxXqQVxXUuvmMyvVFfsSeExXuKkUCcAtQqUuTbSiIOOolIidWtTHhneVvdDDdLMUumPFLlVvKkfpqQeEhEhHHuVMmXfFRbfvhHkOoiXxIiEZzsSZzeIKaAqQcCjJxDdXOGgFfjwNnlELleJjTtmMdDLltCapnbBNlxXJskKAayYgtUumfFMqQlqQQqLzZngGMmrSsRoOHUiIuheEFLlNNNngUuGLsaASlWwNmQqBbsVvOogGKkXxSqVveEQlLGgMxeEqQgFfxXbjJVNJDdFuUwIXxiWBsKkPpeEyBwWbYvVSCoOchPpHQBOFfohHhpPHALlWwqFfSsQprKkeERRWUqfFQJjuSZKkRrjwWWXxsrReElLgGxXuUJjnNpZQqtToOuUWwKvVMmkevqQVKfJjZzoOKfyeEUuljjFFffEeJeEpXDdvVKXxGgkxUuckKwWhwWAaHaLlVYyvHhxgGkmEFlLfeKcCGCdnLlNlEaAgNnzZGtRrTeIiLbBxiOcCoiaAIIbBRrXGiIcCiIgnNHeuuUUfFcCteEToQQqqjJDFfwXxYymSXxexXHhEmUuQqoUGguOCEeLlVvyFXxfjaMWwIiyYSslIiTsSCtTKkJjuUdDSUYyvRrVgGCnNcYydxXdDpoHheMChvVHSELXCcGgpGgSskOoKkSsOVvVGLBvVvZAaaSuvVaAhqoOVsSYOoYbByElLepPxIiXypDdCcZzmKkgofFOlLGMGgamUUmMRrbQsQNeEnvVaoWukKUwKkcCUuofbgzZRPpHhrBbGXOoxjRrwJjWEeJjBruURbwKEycBNAaZznixXICZzcpPoYeyYNnEALlaSsDduyRLlrVvYEePXxkabKhHkHhMgGbBmYyjJHhAGgaWZzDdEeSseVgXxBbGKzZsSkSTtsvhZrRqQWwyhHYtyYkSyYsKOoNnbBRrixXIgGVMmoOeEWwBtTxWwiIfMHrRaUWwEyCcsSBbYRTwWtLRrpfFPTtIEeUuRrBbssSSNqQniDHhwDdWaAdzmiIUuqQMYiItlLQoOpPbwWmcCzZMKkBJsjhWwqMtpwWjqQJPHEeWwfUuFCcgbiTtZzIBkgJjZzjNnRvVrlLfMmvfPzpKZzkPZIiXTtrXxBfGUugnNFeqaADdyYNnGgAEeSsarRvYfrAaRoLlCuUcQqoOUuOjXxGgJHRFfbBcNpPlLqQlPRnNrxXkKNnGnNQMfFQdDyYVYyvkKUDAadZzQsrBXxbRNEenzjvWKJcTpUuwWUOobdDBAanNqMlLUuZnNEebBVwWCkKkKcbBlaALkvRrVpPIDdgGiKxXvyYIiVXHhLJyYzKPAapkNntgDpKTtgGrRcCbxXBxXVvwfHhFaArBglLcChHjJGfkMmKyyYYFoARraMmdDpQqyYdkDdNntTaAKoMOoKUukRwyYDfFdsSWweEWwFPDdHOouUhDdpkKcXyYxpPBbqQZvZzVzYykKPpEejJrRaDzZSgGsoqbBQtzZTOdAHcHhAhHtrCciIGgwtaAuBMsSmdDsSwWtSsgGJjGLlgWwcCpHTtbBrbDFfHjJHhFTLllLtfoNnJjOwWhtTnJYFfySssSjdDHQBIyEeYGgieGgblLQqBIiOoEJLlOKkvVmnNPavLlVRrzZicjJnXxNntTNanNgGAJjyfFeEYIvGcLlGrIfJAKkFfmMhHUuauAaRGCcYyYykKwWeEpaAPsoGpPgOUjMzZmPpAaUuJfFmiIFIdZzNElLvVeEDdaARrwWTteyrxeEJjJaFfGglLDfFdDMmMjrREGaCOouUcRrxXXxAJVvJjjZOSsNaAXTJjtFfgGmUxcAaCvSkKznNzZZCMSgGgGbYAaOoCxXMOnyYNnNWCcCHhhTdlLKkWwbLlBgdDGGlfFvVbWpPpktTgGKYtQqeUuETbPyYciWwIiICwWMmkKOoMmqQMmXSsMmKkxgGIaqCpdDoqQOPlciIAaRGsSqQCssSDdSroOfFRRrPpXxPpOoPpaAQqeyYTfFtsyYIipPpPuURMmXxuFfqQUcdQrAaRXxnGgImMAaiwWuUUuqQTtyYyMmVjVvJaDnNdIiWFLlfRrRrIiIGgwWZdDzOoyYiGgxydiXkKxgBbGekEOoesBLlxmMXIiIsSTtiYyFfeEsgiIGZzYyvAJjJjboOIOtTekNjJnNAYoOSsNkUuKaAdDpbRrBcmlLMCPfANnaPpXEWlLFsSmhHMrQqRJiIjJfFYyjepPOcCmjJMQqSeEHhUEeEnNoOZJsgTtGHhjjJhHWNnyYwCeYUuyGgvVQLhHOokKgZzGBBbdDgGzDBiwbBWgiekKnNaAhHmRxXrYjJyPpMGjnNyYpvCcWXxzSsZSsHZoOzhwOFfZvWRruUhkvVydDYKBbRyDsaAfFNiInLIjWwCDdEeeEsSefFXBbXxxEsScPpefakKfFHhJmMjoOuKkusrRNnuUuBbnNdBbQqyjwGXxHhIigNnhhHbXxxXJmMjBHfFWMXxyYFNkKTlLpVvonNHhUuThHQqtDiYkKFDXeEeejhRjHhyYpPzZRrTOoabBOowjJvIEDdeRiIpPlLYwWaBbbpmMuUPWwEeuUqQpZzPtTywZLlNjJnzOMmnebhHoOByYDxaAwWgQjKkJjXxFiIgiIbBDwtTiVvOoIveMMmbBbBVCgGEeNnMmdHSszMmIBNpPnwcIiCWMRoOreEmnoOqvVhEDdTfFkKnNmMtsSwWexeDdvhwWOoHFzZYyUnxXgGNrGmMgbBdDdDRiIKkOVjJvSaRXxTtPoOdoOJwWnNnRtTOCPhHCAfyzZYFCHheEcDdsjNnaZzVbByUlKkVvLHUuhFzZSsfUubCaeVvEAVGgjJyBbYkdDjJmMDkcCZzTwWQqcuUUuDFlLBJiIDdvVooOOjJSsifFACSscaqKkRUuxXrjhHkKqQeEJXxCcasDdwJJxYAayRgGrOvVoVYyHhfFhHhHiIiglbBLlDdDdyYDdFfAXxaGgxRAaiIrqTtDUyjJoFfOKkYCcuIiUoMmOPpunNNnkKKklyjPpJgGNnbBVvZzaQTtuUGgdDRvVzZPhHJzMmQRrOofiXxoOJoOjbMmWbPaAGQsuwWUQqBlLbiIczZCSDlOsVvAYbhHfFeFQqCcQqwWfEhcCjyYLQqqiEIieMWdNnfFEeVRyYqQTOWjJwMmpPlLQIirtbBpPnqQTtNnNftTFrRTlLhHuWwwWKBtTbDRrwWJjYvVLtTltpbBoOyHhYPpAaXxPNmxGkKmSsJPpjgZzdDGmMqQqoOQvqdNnxFftTnNXaANnDFMCCcckIiKaUlLYyIiuVvVvlLiIKRaAcCrhbBbBiIbBdDdNnfFuOTthiIqQYmMoEjJeOUjiIJyIVyYvmgMvVENnepHBbsLlmMEetwWTSJmMjYyvUuVUPaAvxXPpVMmZzFifFIkKsSMMjJNFfnQqYdDKztbASGgsEeEmMekpPKcCLwaAblLZlYyARrRrDdPpOonNaEeqQuTtMBTQqtoOpKkEEZzeZzeHxXhTtzIiNKkkIiIxmMpnNRJjJjeEKkdgGiaAeIlkZOooqYyHLlorPpqQxXJsisSJZzLljiZasjWFBNnbrRfFfKmMkGgypsbBSWwgGTtPpgNnahgGBbRrvRrYIiGgmMjIyYqQijJADsjJSdqQxxKknnNCcuUGgkTOqQoeEYyiAaItBbOokwWYyzJjSscClZzLRrNjBbjyxeEXrRcSsSsCnOoNYmKkMJhtNnTzhmMzZxXTteoRrtmMTAtdqQhmMSMmgGNnoOUuQqqQlsSCcTtGlLoOwkKPprWwgGRwyYjJRumMOojJUSsPUkDdKsSkQnNwWqHwwWWEEDdqdLlFWwZzEefVvoODynNadIiBbDzZArRrXxaLJhHjNWwnlhHAmYamHhUQSskAapBbPKtSAawWHheEslLWfFQOjxXLlJyoOYfrRFDLlIiUSsFJjzZfpZzPGwntdxDaqfFhnjZDdkKqHwYyWVLhKkrUuMmjJRvtRrnNWvVwLlsSvKkVxKFfCtTRvafnoOhHaXxAyYAdVnNvDDdaGmoOCcApPObBoNUuowmMWNnGgjaAJOQqPpsHhSLKkeEphJoAagjQqPEPdDAaperRpVmQZzELlkVHhvIiTtwOokKbYnNAaFFfhEeHfvVnNyMPpmvkxXKXxgwHyuUYIihLQqlLlJjoaAstCcTtPuUpTFZiZztTIEtTFfsRrzZFXUdDuxOoSmMLAalSsbBoUTztTZLXAaQOtTeEVvolahHALJEMIimwZzYUhdDHuyezYNCcnQqyZtTXxEHNMMmmSPpuUPZzjJpYyLlXxfJjGgkKBbGgtTisSAajJAaMTAaseEWwhHSJjvzZVIahRbBfrpPRetGgTgGOoMwWgGLZjXgGoARHhyYbBnNtTrwWOMaAXFfIiaZXxbBzWwLmWVvwfFQDNsSRgZjkKClLIiORNPpZzXWwxnYvVyroLlcBbdDuwJjqQaAMcfFCOijJLlLdLliIVvDdsSZKAaksSPNnpmdEeDPpVRrvpPMFDIiDYrROodDJxXHhjaAuUoMMmmYLlPNncCNnHULlIiHhUkKJjlqBbDwWbSsBdLlCcbpPBvVvdkKUgGeiIEAaufrRSsNKkIIiIiJywAaRrbBUuWwWIiGQqHhYyiIyPczGgmMnNZRrGnNJjuUGDyYdoOGZzHBWIiwUVvmMaAUxTtCcoOEUECceCcvAaSuUPImMhHTSsuUtoOhKXxkTgjJzZtNnTjgGcCoOWwDAEeaHGgGUQeEqawYyWZzgnNVJAEeFDdfePjJDwmOoEegZdDzGzZWrRlLRPJjprwWVvQOXxhuKkTtrXNnoaIiYyYxUfFuwAIiBboxTuvmdDwWdDdhCGPUuMybnWwNAYmMyafFoOBghHueEUHKkeFfltmgiIGMDdMWwmTQXxQqoDdrPpAKkRXoOxGXlLjJxSsxSsXaAmSrRsMHhviIVGvVgHhgyYlLGgjGICMClLjJaNnAsBbpPSDdVvLlmxXFfdDieRrzZiIFviIGgXxVggBbvGgVOSsdDaPpAUuoGgvZznwWNGwWgFhAocpgGzZWGDdgwPrtZuvVUgjJGBpPbGAuUagiJbBjQWwGOoHhgioOiIIiaALtTEepJWohSsKnNxehHxXPjUwWJnvVNjuJJjgpTdJfdbYyIfzLMmHTwBbWOotISwWmCcKkMzYyOoYPphHTtlLvQqwpPxsjLarRDptgyBGcAaEedRnNDZzMmaVhHvEjTtJfAaxXCcjNFfUWsWwCxuyzZUuqSsjWwxXAjJaogRrqQGOWsGmMgSFLGsSoOoYyOglXivLltBbTZfuUQNnLfFlDdWGgtcCZXxzzmWLZuUDdAVvrRoBbyRrKEeJaplLsppPFaAxXBbfHhNnkFsiYyISqQNseSseYEdDJMFsSjJSnNVvNPpoEeOyYKkSivVIsniIKGgkMdPpDVjaVhHzvMmhHJjkqQKkKVquUQplzspwxXoOoBUuoRkKKkFIJjsdDnNPewWENcCzZjuBbUqQJIIiOoiDdeEzmrRhXfUacCHhbbQXxIDdCBDdjJzZzzpabBxXyYeBcAaCQqDTtiIAaHJHhAqaAloOKkHElLfqQFKkzVvZnNRreqQjJcCqzZVvuJhrzZRviIVoOhSsHqJjPUuXxKkCcjcCJkxXmMsSfIrReeUuEEuJqZykEeKbKDdnNgFfdDZKdsmsuUUiIjWwAZzahDCcdUeeBOobEELEBbtHpzQlenqlBbyYFKkQjJlLMmqPoVJUNnvVyNUuVvnAacxXXSscCxnNCcvJjJitvRciaAJjICcgGbBTnNrRtyLxXlkQVZziIPNeEnpvEGgxWwnvESsZzCcedAaBuUGgbLEesSlTNnoOqtTkKTtQYyXWNePpnNEGggGcCiIdmYBbDdZzzZyHhrcCaGLAfFVDdNUuWwnvGAnkKKbypPqQBbHhkEeKruuHhbjJSsBTuUjJiKqDsSmMoSxyYXaATFJjcmMQSDEeduPZzpiSsOoVgGvDdVvIXxiBbPpvAavVaMIiTtiIhttIRracCcCXtTMOoxwWXxXrREaAPpZzjSsRrDaABRrbKVvfFeEkMvVmMXuIZOXoOxOoevVZbNnzCcZzZBNnMmzlLLlaUuAGYxXfDKpPBdlLSFJJxXnnNBxXbZsSzqQdDveEOUuUmNEuGgUfFtTMJaAUujdDmGXuUOoxaIgGMcKAFRrfasmVoOzBMnNZFKKkeEkHhfpPIiFxXfoOKhHdHoNFfnJjdugUTtunNnHHYymaAAOxXTCctOxXLQqcCNnldzZwWJjHjxRrZzhHzklLYnNyKlAanNbJjUuXDRmQHTthpPSsqQAybbkKBgrRfAasSVeNrOIihHAUZrbBMmoORzqQdQfECcStLlfPpFwWLSsWKkKkEeWGgVEQqeMnNQqswwhHbBClLAahHcTtNueUzIYFSdDpPeEGgsKlBrRKkUuVvpPbAkKaqQNveEIitThZzGghsSQtWBvVTLltQqJtnNTjRraAreiaWwAjPVviYNmMLlfoeEuTtUwWultTLUUHhJCcjoOJYyhsipsSPOocCSRrxBqvuUllLZmyYMEeaAzZzUKdRrtFfTDRKkrICcilLsUupPUfzZiIFunNiTHhcCyYlfLtSUuURkKXkKcpPCxYFQmybBYJwFfwWTtDddXjilLIJDdYyxYkKyBbtikKmFfLbBGgQqvUuAjJfYzZMzOttCZLporzZRMmfTdmMWqjJhfFhHCcHQwLuoJmRrHhvFfRrOICIxtCcoWwTIitTiIWNnhHwtptTgGmUuHhLllLvHEdQqCvqmOLiSWcCZOdhQqBnNLYRZfFRrFIisSfzakylzZEeVLleEeEcHhktAvKreEViJIiFlLfeLlExXmMFfjJGxXyYyrRYwWqBboOTNypPswrEzuoOnzBbBbRxXZzGKkgXYKtoeEwWslLPpvEhcBbCmMHYyVBbQqsvuUVqIkKijEeJSgGxXQXLlxMmtTuGQRrqVVvIRrijmMJPQLredWTpPMmMQyYqNyzoOzGgFiVAavIBGgLwWlWkKwbBGgHhuUeEnkKyNqCcIiBWOuFfRaGgXnMIIxXtXYSsBbEdfpPFmXNnxXoFnwuUMmYfFHgGRNMfRbFfTVDdvWwtTHNdDrRndoOLfFKkzLzZlrRuVvUwAacsJHfFdDmJMSsCcALFumHhtTfFMUfgFsiIaAqQqrRYNnnNXxuAdDawqQfOUulLMwIZzUuhWkkKKIirjrjJDWHhGgHBwWblLMmeQixXmgmMbBrMmRGvjQqxXihdDpPHgnNolKkLNyYkxcAaAGHhffzZqQnNzZXxFVhHpXQSpPwWMmQqWwiIAsSaKOsHckKmMCTthXxXiXxIhHVwGEezZXxgDxSaAlLsPMHwgGWWwARrfFrSLYNnlLlLyFHhfobSfFsBOlsRUudDNJsYnUTEeMuBbURfFXImMcZzIiCimvdDVYyEdDdDeSYJPgGGgRwzJJjjaAZbcAdtWKkFSsJrRrRsmvVMSUNnIOoiLsSuOooOsMmSpdYyBHYyhdDIihqQvJjTtFfSTtabMmcCvVydDYtFIifxXRrkKIeVvjJSXlLBlLcWouUwZXTtTnJjVvNEenNiIcdDQhbEQqjJoGNnYyWwxFJjMBJbBGgDdRrSdDLlGFfHvVRdPppTqdzLlZKHSsBbSEdlLDYZzdPlLpcxXCDsxCqQOkfYEeyuWrRcCwnwWRrNYLlyZeEzXNZWwzrjJRJkKjLlkwWKteETgrRGQPBbpVRroOxXTTtqQteEneEfFEOKkoepPCdDqflLrRFZrRldDCcLWdDPpwNnClLfBtUuqsQWXtvlQqLgyzqahcCHslLlIWwiJPpjgGWwGbEbBTMPphHCNFfnDbgGBfMuEeUmFdUZUFGgaOIoypFfOsSsmtkfIifHCchaPatAoVvXCcxOobKkGOlrWwkKIiPpdDRWnNPpOsSKkRLNnlBhcdDwTdDtFQAaxxwqvVKOokQmvVvNUunwWXQvHMtadxrqQMmQqRtwymDlVvrvVHhRLaAQcVNzZQwWqdDOtAPIWwiwWOgPpGSUuWxXvbfFZnNgfcCwBeEbBbWCgGwWcqhHVvtnMioVDdxnNjJJjtHsFfShqQyYVvTAaUuASsXxeGgEjnNJNnsxXWRBDdbRdDmMYvHhQdEeDfTGiIgtFRruUqVtELaAYfYyrdtTDRHpxXQzTRrtAPEeiaAGhHhsqAaEJjezeENnhnZSszNeEvVyiMmELzZaArPyYuUZONnuLjJECcenNHnNiInNLWGLlzDTttscCFFfpANnaPFFnNXPbnBbNVtoORLlMmzZryWtTJDdTDdtCcxXPDdvVeECQyYzWwWsvVHhoJzZMmNeEjJnjXPhHpLLBPxXpPpbGghQqKRnNdrfoiIOyYQqFmMhdNVTrLhgGhcCFfHQqHDdoOfSsFuGgcCKkUIiHhSCcDdsrRdVvAakKSssSCcDlRcanKkHqQvNnOEFIipPRPpIMaAmueEjZxfFxPpPaYqtTQywWxXAHhoOpAUuaEmDGlLyuBbNnKkUtdDmFfsAEekHXxhVvGBQPpFUCzgGZbByYDzFqGhHKnYyNJUlIxZzcCGyYgXMxXTOqQAPpoORBXXAPjJpZeUNWPpZjJCXxNFuUfLlJQeEgGlLmMUuDEesbBSCcBhHSsrRbWwXdDxuUGurIymMAagGblLHclLCvVLPpmMmMlhpPEsSUTJjiIDytTMQqmjJVlLvlwqVdVvISOaYyAQaAWPpxXWwdkKPBbtvVvVTUHrMmNUBPbYyBpDdHhHeEZBgGWwrRrRbxAajJalnNZzuEebBxwuDhHBbNdcxSsiIeHQqrrZzXIFfknUuNKKGiIgkiYNtGgTCLlGTtVLOeZnNdqQCHXIevIiQqVhHhnAaNFfpPIjNnJwcjxiIwWXwTtjgGJWoyYvUlqQkYyttTZYKEegTPpquLVvlVtTGpzZNnolNnTfDpPgGFfGgdGgYFZzfwWlelLqQyrsSUuPpJEJjIJKkRrUjxgZsSzLbplgfZrRzBbavvVqTtQkKjJKkzZOWaAwLLAIiHhVvycCXNtVBbILmkuUwjJdDAaFfKkIwNxClDwgRreKkEWpDleGCcnaFfmrRkyUAEeQqiIoOEtBbRrDSsCvVlTtGgLRGAdWpMmPYHhGsSEeAogGOmjJuUMzrRLlKknnwIirIiemMYyiIEMmKPZhvVLHdlZzmclEerRcErRAjSsTFfOoTKkHLlVNDoiIKkRlLJpeEaAbxXBBbcCrRyYdaHhyvVxOohVvrREPpTNaAHKoOHhPpqZJvdmYyMDQqTqXxqUgGHESCyyYuBlHvVwjOFfoJWhofFZMuFmMfFVcCOoWwdfFDVuMYisIrnNNuOodlLnNVXBbMwWAaAgGyAasqQXkKWwFfxbQbAsSsKtThHkYycIUuDrRdXWwxgKyNQqRrXxinWwhMmoOPbMmYLlkKyThHvxNnwWQqYCcNsSnzAOOodPpTtnyBaAbYMdhXxjXYyYyXiIAaaAfJjCcsSFlpkjpPJnNGgtxgXnELvVwWiIMEeXxmWwDSWMmiIiIwsFfkKnNcESseCNtWwTnvvhHVdbjVNnmXxpkQqUDdDqQeEdWwOeIiYyzsSZiDqQHhBpBxpyYxXZvhHjJcCjJSYyCcBdPgGyYpCcaAxXoJjziIwDvVsIfFpVvMmAAkKMPUOspPiIlHWcSsCEenAprlMmLsSWyYwVJDYfFlipkNnVvlUnBzOJHhjguUGgYyhHUuomiIdKynNYsSiIGgBbROnVpxXfFrJjRPvfFGgpMmPyYIiTcCtwFwWFqQfwtTHhWJjDZEeanNtEeVvqsPlZNqRsRrSMOsyYEBVkeJjEEeKTLWwltEmUuMfFnNbCccCZwWCGghHCKmJvTtNMwCaAcvnNUJRrFfiLAalFeRMmtTIEeSqJvQsyHGDcCsnNSqQQqqQsrRruUWwRSTpaWLlwAzZQqTPwWpCKkPqWqQnNwGHhTSutTxxnncCIrKYwUqQuCcWWeELlayYPubMmMmHhWTMHtuafiIvVbaAnOogMmJPgGTteEZhHzCIiciIBBbHhTcUUuuCAppQqjJcFfCSFfttniImWuUBbwhXxKkzOoZRrMhHeAaDdUUuGLpSNYVvynmbZdQMFfmivLluUlLoOOoPEbnMmONWwnnPbBaGgepqTtXcCHhXnOoQBZrRyYhTXxjkEzPjJpgWIiStcISsiMmBbYagGqvKkMZGEeWwnNyYnVvXxBMBbBHaAxXAaGoFfeEbBBlNivVuaNMmnAdskKgGeCATtayPwZzQiIzZsjuRgGraAbJjUkfFHhusISsDABbsSmSLkhYyVRrvHKlUGkwbPmBKDhHUuDnNiLuIzCgGMobVxXoCccCLlPYyFfVNRSsdDsXxOoSFfZdjmbBZeJJjeENnjRUufFrELDdlWICcinxpnNAaUlMmLuCEyqQeEznNjzAaWkKbBwyYGghCwWnNUGOtTgGvTtsSVAaxAPNnpwWtDBRrbuUbBXxsrlOoanNIsTgAdDMvLFfhaAHlVkilHhLIvVwVICjpPSABNrRMwWedjhgGHZALgLTuKLKOMduUDIOHhvVDyYWwfvDvcgGxXMZnfcyAnNaaxXxYzZyDWwBbcTBbNDBbytTArGgCcYNOpIiOoFfPSLlEelsBaAbzLluUZkgGJjErTIituULlTlyhHYYyzZWOVvZlLrQIiQHhqdkKrqLlQCPoOprRKliIHhWvVnqJeAaLRvBbhAmpCcIrDGmqCMjECcVvoyYNtnFfzDqQNnlOutTxXwRopCcXxjOvVodrzFftCxKgGkHhEenQqNxsqQBikKIbhKfASAaXMdDiPpkSsKFkqQKsCeEcJMJjmslLEnNuIeCgLlVvWHlyMmYSCVpjJPHOgGgzZJJvkdKkIqQsSzZGGgIlLiyvMgTowWJjuObUNkbXnxnNXjsXxBbSJtJcVdTtnNDCootVvvKkPetPycCgcCGYmMJjRCcuUBbCGSRWZzzZVCHhycadXIwKkUtTzZmzrRZSOotXKEHhjJWwKZzAnNFtTfYyacCASsyIiXiIicCHXDBbfhOoOWbBDYwydfDRrdJYyTtcCLDdkIOruLltZzmMkIHhIiibsIiSlqfFmqcZzwWgGfPpFtWWLBbbAhHytSwWLlDdzZsAoIyeyqvaslLSQJMoijWRPplqubXxBtXtKkThMgGmBLcHhbgGylRFJjhQsaASeEEeOoGgqJUoeEIiOujHwWfadKTniINZzFfVWwUnAaNoeEqQmMBcVveECTtSlLiIQqswWVqQSLPKkpXMmAaOrpPRoOXoOxWCOobOclLCsSuAbFfsSnSHgnNPFfpeKaAkvXPpxYsKubBBbUztTzbBZenkJnRrLlNRUurPpiYtJjGbBEgghPVZzlLvmtTCcBoOXxJUuyYoOjxXopPpWwbzZDdJEeFfddoOdDLSWwLRWwPaKkIimmMIYYBbKhIiMmPpAyYlzuqQdmSBYXgdDGguUDJrjJROKkRTEetrwdDWuSsUZDpsSXnDdyGnfnNFiIIpDdDdMgsSWsSdDPJOoFfFBdDlZtBrrnNeSyvDRtZzUuUuuMGKkkJjGLHKHhGgFfKDdKNPpVwJNHhppapPAIiNKkgGtTnqxXdDBbCcBgGnLrXPlPpLnNVvYiKkUuIcrSsuXBpdMmICWdxOvKkuxftTtDdMmZhwyYdUpPDDdYtNTofFHPtNnTZmMIizphxXUduUDeEjJuyyYnNODzcmMoOJjCcCCRWBrkKWuNnKmBcJhHlhHnNhJjiIGgHSsxSQkmMrHCctWxeMmEEebBAVvgzUuPaBXxrHLljtVOocCUOOKkdDJdaziXLlxEOqTuUsbbbBmMyJvwyYpmMPbhYypeEGnNiIixLsYyiIhmMNRrmMfFCcXxIiiIQtTLgbhbohHoDdOzeErIwEeWWvVTJjAanNxXffrRZzAaAaFOodDbVvBgGFtqyYQyYTAxXbBIPfFPqLlKHNnYrRtTxcVIiSGWwSFCqQLlHhfpbHUqQuhHNntGSFPpWPpXxJlLjsSrRrHhTPpUuyFfDdavVARBbrTPnjJnNdKzWnkKaAhHImaEYywkpPpPyYKWWfIiNnMmLlmoKsJjiyYgjJeEvVNpOzZlQWABshmMHGiIlPSsMmuiIiQpUlRrLEOosQHhqjdDJEaASXxsSstfuUigGXpPZKeOKbQFcCBMmZrWghrZcCbEJPpjDMlLmQnNRrIjbBJzOKkSsufCcIidhebWuSsSjJuUehHuUwYhHCcMmQnKjtuUTmHCcszofhVWBKjJApQQMAakKNZzSDxnNUaJaAGocCJSsjCNWwoOBbjJecmVvYQiIBbSMmxdCkbBNOozvRrVkIfFpFZNlpzXxNLsSycMmzZCOuUcAalkhHsqQSKCBeEahHAGgJaOPMmpxqzZlTuUVOoeEwMAfzamMtTACcloWwnXYcCeXzDxXdfANbBZyYzZNBxXFfDdTSKiICckspPFsRxXrLlPwWyYaUuXxyYpPZzgJjDFcaAZRkKMIqQvUBmsVvjJXGqPpVupPOozGuSsoOMmASGinyYtMmhsSMeEmuUMbCcBQciIRIrPtzZRmJjwWMwPVqnwWDXtUupofwWFXxuscrRCmMwWYaaRYrcOozufFbwREKkAarQTqQwCVvcTEeXOGOQbOkKJjjPpFfhPpHRrJCZzjBnoOwmvXxWgGwVvVojBfcdnNOolOocnNisXbvVhypYgTwroOKIholHhVSsGlLcvzZONnATtPSkisScbHeYJnJNlmMSYyshHxFiIftTQCcqQLUuDdZWwzPpkKJjHaiaIzZYbBoGelLzgbAmLlwWvvOWwfFXjVvJFHXxauUPeQqdqzxlvyxEctTjsmHZUyuMXCcjKLlkcKoDdzPpZmMNnuTcCtMrRQXvENaAFfOKkiTtPfFnNJCEecGbBgjyzzZuUhtWYOoyBVvQhHiTlrDdzsWJhnaqPpXYvzZslqAniyufFClLSByYOYyDdBbLxXdNWwzwWRMIimJjMmmBbzZyYZXxZzUwiIWHNnsSdLgAakNXxnQWMFMfFhcRrfFbBkUutxXfqzEAaRinkvVKuZUuzcFUjxPprpxoiIOXAJsmpzZtNTdbBDOdDCcotEeGxeXxZCcRrtcczUqaAUYyEaAsWwfFSTghVvHCcpPGcCDTtEeRDddOUJRXxyYrjyYfndlLiyNnSsweJVgdKUuemdpAyYaPNnjeSsUuxXIHhZaAeguUGFKrutGdDrRQkKaFfDZRXLlfRmMGYlUhyibOFOVSsSsvKUdTsJjgGcfGgFGwWDdIlNoPpOPHhchbrKrnNjJRyYOJuvpGgQIdHPSsGEEpKkIEdryYLlOVvpPoHhXSoweDFDvqGOyYZXxrTbBAHhUEGgEXdJjzYzfdAjACjeQnYLIaosSOWPFiCuEBZzbAINYyDZPxAMLimZrCelLfueEzLRwUsSSdZKkFfWaAQUqjlywxXktqqQoOyPpnClLDBbdcKFmSxRCEcGgDJOvVjgJjfBUoEnNIAYMsSLlbBmhdDoODABbadQqPDdoqQOopgKSskGpPRJeEjGzkKgMmYyYyzHVAVvvOTBvVbAaYyXTfBSsDdbUdfXxHXxCBzqVxwWaKQqbBOoEeHihGpaABnQFopcCNXqcUuCRBbXxSkoBbNnOARraFFffTtwqQdqBzZxOoxbBfIlmXJHORRbBYvHhDIVWwkMmAaKWFkzdpROfXxFyMidZWiNnhUuwWCjSsSYhwWFaAfVvUuLPAKkTtVJjvayvVLlglBOyZbvfTvhCcHNnHhVNHhxXAVTDdKbVvDejhHJyyNGgoCTtiIcYpcTrwWRlLliIJjAfxXFiAarveDEedEeGgEVRBbSynMJQovDOqHajJAhRrQoHhdpgCcZsSctkAAwJzZlLHhvVIiyJiGJPgGpWAaSskQfNqyYsSmMIioIPcCyKkLJxXRJubILliBUMmAZhHlPpwKgNnzAaJoaAOYRRjXdDLiIwIebxmEYOByUupAwWjRrJecOoRigPpSsyNnhHGglLYEeYBbLLPpDdOIIPWrhzZHRDdweEIjUuRrObcCzZBvbqQauhtAatTTHkKIirWhyNYeEMYLiIbBeSsgVOENOonboAAazJQRuySfATfmPjJqmMDElPvVifqQIijJTtGeDsgMwycnNawLlWLlOiXxEesSPdFfAxfEVWoHnQNpJWwpPWcKahHjBbIuLlamybMmYbBRrBfBUjfDPpfgNvsSHhVEBVePEeMdPpDZQYycGAxngGNXGgxOKFYuSxDbBdXBbOIiSsUpzjFNGgXCcYgibjJBdDIgTtGYysSQWwRjJmLlqSygHtRrFeclBXUGjpPJIAlLrkmMvVSyYAakwgHcqYGgRWlCRyAanvVpUmMRrmCcnOoTzczrRZeEKXiIpPxGgpRLevfTcMFkKfmwWbngMvVnQnrlCZjpPSujLxIUxXtGjrWlfFFfdeEhNSjqQJySLfFlQqzxpPXWwWwNnbfudPEqnTcKgnoaASsXkROHNYVYuyFqboPWcOoVvJWwAGgtBqQbzZTaJjvaAxPAaphmmAaYcroaWFinsYLhHpIboVveCckKTtxabRrQKkjYAYyayJyYjJjWiIsGfFgPHXSSssxNhHnQasSuUaAAgnNtYyTGdDcCSTtHkAaAafepmiNKgrJjvNneEhzoyjlwIQOsSqmtXxoOLQVvYAayCqQcRNeoORnRiafUuOoFYuoOUuTMmajpPAaOolqGoXIAfBbNnDQaANnOoqFcMteGgXBbNvVnxLIiPRPpAoSgiRrIpjeExXMFfdJXxOlLuUOydKkFfsFRrjfmMyRMmrpPgXxHrRgNyIiwWgfFEeYgkBwPRsSxWwaRrFwQtTqiVvBbcjqGBdDsvVGgoepPhYyuUHiMmTrSdKtTlShaCMXYVIitTHhQjJGENSSbwopLlPWioVvcgtTSyYuvHVFybOocfbybBpLYGgwWGCgYqQdDpPiIyLlcRgfMnDlRrpoOPIeUcCzrRIiEdDgGFLlIYVvykcwxICcxXOcJVTEhteEkKoOjJBbnjCcBbyOsSRBbrEMfYlrMFfmwGUnTtNSlKSEltQqkkKKyYhHThHxgDdjJRHmMRLHXJiIbBtqHriIqoOyUDtFfrWwpbBXDdxJyYqzGWwoOLwWBnwkDdKWWhKgoNxHOZFfzpPOooFLtTUuJOEUnHhDoeyLOoCIfFYYtmEhIiHpdbBFfLlKiMmsHhSzHTchtFNnfshwMmqvWwVQxrbnNBQqTHcUxXjJuChtiIQeEinwWNPmHhjJKeDdbBqHZsSnEekcCocIfFirZSfdKkXxDjJKkgCEeMmhtioXlUuQqyqLgVKkDeQDdhHKYyUuyYRrWqQwiCxXuUcIkVwWIiIjJirRapGrRaAkKPpobXxBOpPgndIIiDzekJjexXwJvycWKhBbOpsSPoPWKERMgkIpPiKWfFkKTtUvmNnMmqcOoCqQvVYysrqmMZOoxJpXwWKqjySxXnzZBaAWwaAGgWvVCZMmdyYFlaEefCHhEeGwWYRraqQAiIMOxhaAOzBbCcZuUfFlTtLzLOolEgGkKFfEwpKvVkBaJRXqEbMHhGghHnBHeEbMgGDlsIVZzvFJyUXdlmVvDWPSsKhkIsSNgDIajJPpsSMVAoWEegbaVDdqbbHhAEekoOKcKjoOJtceERhtTEeZzueVwWXSOznNSsZJjwywfFZFMeEmIiDmTYylLtIiBiDREelhtmQlsSJjLKMRNnbihQqJuRaArUoOFfgFfLhVKLtAanNjGOzTfBmCXxEZziSYiIMVvmTFftyUqVvSsQtTLiYKkdDTtcebjJKRnHhAmMWwhHLuYZhHsyYAautTDdZzpBkFfcDFuuADdCbBcCaAMlLNPBtkQoOQqIFXreEuUsjbYySyYsgjJGwWdRnJjmMcCUOfcCkMKhHzekyOoDdhBhCcAnrRRnYYyynNkJwCClLcIXGgJjmwIAwWPpaIiyrHPTfyanscCMQXCcxqDdfFmcItDeOooOgPpIPbBoPMsSmpSxtTgIiPuToeEOjBbJMJWwQoOoSgGVgGgJHhZiMwchaCdWwBbaAxySsTJBbflRrwfFuFfaGiItaBdPTePznNGjQVIiIsSssSUeUXxgmMUuYcbBNoINYjJVkfKDFJLYNJjgGsZthejqppZXqxsSEIizGUudpeEPLJEeJHPmWYoOykKieNnRXNQnJmMkYXWeWVvfSpPJUusTtCcknCcIvCZJPTTVvttAaQqVKWVitTwXxMpdgpPTTtcCxXholfKUCxCcuoOwfFGuUNmmxOozZofjQqGgJiIFLuUlBbDXxdoOfClnRrubKeKilLokSbXyTtUuIXRrEjFcWvzZmMOuUCUfNWaAVshYvSHhjHhPzNjxoywWHheCqpPXxQBPGgpPaFfRKzkxXmMKZPpnNFzDaZahkKHeAMAVqQvQUuTtlXxoOLQnFoOWGnJGwhQqxXFAfbFfvVuUXxFGkehJUuWMFfjJWwmZBqNnQuUSgGkKNkeEnWKUurPgGjzZcCVvyYsJGXNnGjgaAnlLxIWHhBQpjtTbklhPpYfFZmedDEnLlQQtrRhXcmzzzZzZMKksPZzLPpQBEZzXVPpvxebqDMGjjJlWDdcCQwWqhHaATueGgqnlTmlLMPkRrrAHYyOohMmKApPOoACWvKHONnEOoeohOfgzLgqQlIiBNnbLGpSTtKRWwKvjcIibPpCcTJgLlWwGBlNnJvbjUuWpPDjvVwWgGoTXmhHfjHhRGYymoFfBdxLzkKufFTmMWLZZfhHtZHhHKDZzRPgyMmvZWDYyoOFfAaGIsSuCcFibejZLlYIiQMmRzZgRfrcCRLrUuVUuBbKoeIOcbBSgOVhIqQBivVIiWwQxojqmMtVoqZpCGthdDHbBzHhuPTtTXGMvVXTgsQYyOiETlffPIipyYIaAaDsbuUXeVMZcqDRrdQCyYKsjxaGsLlrkKPwWHTVCxjQbHlOkeEKUVvtphBbXIrivFHhaudNxLBfXoZFfQqfxCrKqQrRMhzcWwgGXLlLGgraSsAESjOoSHBuUqQuUBGpPTyYVoOvhHlBbmMMDdmkrhXjJVvOxPpbBDvqSsXSsxyjUuZeYKkrRDIQjJqiKuUjxXJOLBUukKDFfKkxhudDZfQAeEZVJjYUEeExTzkIaZKkzgPpfSRrWqqQsSZEecCjNOKYtTRzyYCpqRbBMFpXgaAeEFfncAaCkTznFcIzIFNMmuMrYywDdqQWoTmMtOiuKmMkHhGsSoWwmMgRfyjXxDUNGWZzEDdQlLiISlLfFdFxXsWVrRdWaawWfUOLlrnVxsYaexgUuMlLmhtQhHESoOQqMHhWwcPvEeZeWFpezLuQqxYWXTUIXRrSvKXqQZYJoaAaBkQFfyoOJjdijIBVzqJjQCiXsssSsSthHTnaOeEoGumQEegmlHtyOXlVGgICjJOoVgaAWSxXIiDndnjJSIimgQvlLVmODeUNkKmjLeiFXSlNPwoDdOHFsWfFgGRGCPpcvooOOHbqQJjhHopVeJbpPXxBNnTtVhHJjvEHYhHNnHdQiITRoJRreePSsMmUuIiumMRCkKIiTfFpvUuUHLigGlMmzZHxuYNmUuKwdlOoLleSseEhHyKpUYqeqIrRBbZvVzKZaavVZpPhkKjzAUcxXpKkPxvMmOpPorDHvNYySIINnZkkJjJjKQuirAKMJVWzLldKHlWiIukxXHfhLvuUfdMSXJNtSUufswWwmMjRgwWeEGACcaZpXphFSRJjrQCpChcCHdgLJNUYJvxVmPZzpoNctlMmyhLBSWwrqtTSsCcwekKPqpPXdPpWQUbcZkMKkGgmwtuEeLpMtzBfAMmTtKknXhVtewHhJekxWCdgbqVvAHinNIHPphGhExXoTeEDpPIieQqEzXKgGkyKknitTxiCcIfnNmQIjDCmWrUuRqQwIrRqgTXMvVduZyYSsNZBRMmTtBRuUMMGQuLlzUulRTVvtNhMFMwWfFirKmaAxXbKqvVIDidbAaBcRJhfuUFHBbjpPcqoRrVpxCCQqRehhnEewBbWTvLlThaAFipVXfFxtTxHQguKyYpDzZyYuUwWLFWgSUntkqFfNrRnheEKWwSyrRNSRIdKGgGSOCxCMAYXUucYMfDPpdNKktdQNBnADWpmMHhMmxXIPVnoOLAnFfFfHrRUknNXldrEXkKKkuwWUKeisYDJrWwaLIihuDdnRgQqUDdsJSspCZZvCLTuUtlVvJChkZtoOGJhwQHlSsiILrtTxXRfFhBbJjqWHjTiItgTVvzwWOoKHcjcVzzcPjSJjkKuGrNUsSHlARjdOoyFfSIEkuDdQqUxemMRDLxpPKkKuPphfWwFNalNvpirRmMPwdaNbnqDTnpPFiImyCUuxyamcXcosgkDirRrsnYsVxXvFfkHQKTNusGwflMmykKYZzdgiIGPiIkUGqhMmiIiIXvPIiIflLxXHuUtVtNHHErcgwWGcXPvXxOEeQCCcrCsLlSDIdiQkBxXMkRImxXWzZwCcfYuyYUymfVvFRRrlLrdDBbbBHnrBbLZSNnsTtPpUqgmmrbAarbznQjJqzUDmxtjJGQrRiXxxXMcrRdJiqMFiIXINYxktTKZdwWtVvOFfeEeHgdDhYyaVvWMmwlLQBGDcwEeGgXKbBEgGjWERrTvHxNJjaFbZTmPlUTWwWMIiHhfJNnjyYFmKzCBuqHhwkKDJjlLxpeEpUuPPQpEWQRmgGMsblHYqQLTCnOeEMvkOoKXVxXDdjyrRunjlGDhHcPcqQqSssfHPxPzuUrTtJWdDgXxGSFfFsTnoOjxJjsmDFVlHFhKUZzwLhkDZwvXxjSiIsmkaRIzZUqcCKziigGsnVhdRDdgGVXCuaLlZuUJHzWwAAnNzkFfKOokiQEQyuPkYGgEqQzZLDWkMmhHMnyUXfFhHhLIlhuVJjPrRtcbcCCcxXLlBrUIiEepZzEPsSpEjOrtqDIihwWtThvVlLHyEehejJJjjEvPOJjhHJjBpPvVhVgrTtwSfhWpBbnLeEsxOofIElJJjYaAyMnOouEdbBoMbtTmMVvBkKotTOHhqGufFUMsNzIpPiIiZIVviDNtTdsiIwGvzPpZcivLxoYqHhQYyThLMGqMUgANSSxIcZvbiJIDYVGgvXxGgqKbpPAOjgGyzxkVsxiutVoPpSsOvxwyIiXUlZEiIPQqfwEzVpCRrGgmIiseqTHGXBbEAySEeZzXvNRouFvPpVAAwxXDMhYyHmkKvwLlSfDskKNGFfYygnqeFfwgtTnuvgGVdJYylLYFrGyYpPCXxcOgOoUIkKqQRLgGlmUnfiZiqQCuPmMpUfNZtfGgFKNnuUNGxPfmrQPNncQqZJjrylBbLkonJvVzQInNiEewsFGBbAiKZtXSseuMmywWvzkXxKaFfWBbwqFgGzJjUHuUXTsSRrtdbloksSoOdydDEzJYQVdXoxHRKLtPpdDguoNnOEeUbfFbhdDHhsJseRlAyYaxgYyGlLCZHuUmkRRrcXFzOxFbIilwWXMmnOoDUrIiRAIifREUuerMmVIRixHrtTRSsPTuoLhvVBEenNqzZOoJXFfcvthpsSJjdDRSgAXJSMmkzmvExmDdYyMBwWSOoMmdDdAnNpPigGFFpPLteIoTtqQqSGtxmgxtpmMUZTgcPzaAQOvGgTQFfBbJOXqOoTtITtbiHvsSoMmGsETteCoiEOkRrvEejJRlSsFrGBbrAaqlLyxLlXMmJNnkwLlWKjzJEfFyYwWBjJIfUiTtgNndwzVYvjJVGprkWwKdkhnNzHbBhTFVvzabBAzlwZztDdUZlBbXRrTtDLlbAaOUuMZzgrJFMxtTtOJdLlXxwJBVjLxXbjaARrtBCJVfFkrLlksPlJjZaxXMmAGrwWRFokVtTtTwLlZbBzciIaakaRKptLNQEUIitDgyYGdvVhhHlLHDuUdwLJglLmhHdOolpSOomtTZZMCxHJjTrRqqNMziIyHLKoOBJPqbwiDdEeXNGmMJsSPpgxgjvVSJpRyYkwNKnjJsbgGzwjHEuUZzKgfZnNzUuCsSqJjtTQcBAaFafHWgjNFfgwfpPNqRrYyiIqaOoElLemxoOXaEAzAdZTuUtYyfkruUFBbfApfFbIiMmtTOocEqQEeYOXYyJnWwZpJsmMVyHSvwnFuJjcoCcnNVwCfJexiYxBsKvVNndDOIAakEoOkBUNLcFqCcQBbeEOXMMnmMSsgWUXcukFRrCtTEecLOHNniNIEeinItGKkDPmWIvwLlaAZzEekvpjzcVijJNKOoSjjJsFxZSszXwEEewxyKmMjNfFCcqnyYxrYyEIwMpoOaAhhHFfjOojgGleEDgZKkeXQxZzxXzPPQJEHTzSAanysurRtTUSljfdLlkFKvynijYyJOnCyGuEVvuSZKdDpPkzigGArRavqfFJYyEegZpEtpmMDbATgUusSniINAUWomMOLfFFTtjWwyYkKtMmYqlLxCcXQXDcAHCWrRmIzbTtBVvaAjDdGvsiIOqjmtUpZzGXacCGTtgAsPMIimpObBSsKkpNniXxHhIirRGMgGmTtqQEdTWwieECZzSNAYFtPpphRYentTOoNEZziWMEexicWjKNrIiNaHbHYKEpPZkmKFouNrDwWBJSPtTpOoIiIisSRxfiPpqKTeEEebAapnmiIcaUUnNfuxXUdCKbPvIOoiVoOUUuSKkzyUQqlwWlLbBaNrtTgGkdDBUuECyIlmFcCfMjJucKkCoOsIekKlLcMgGsSbFtZogGgJfFTlSsFBbfkvHlQqXxGwWjCcFfHNnIBjJrmrRkqMTHLryYdUuIbgDvfFVdAoOaGqleErRLQuUMdfzShHsLlWYWosxsSvEkKQquUUnjJQqNHqQOoHhrCTkCkKEeQqaBBQvVvBbABGwTtuZzUOavKkmAidGniKKkVvHPpkzZpwdMoOLfFDxuYjfiSLdmBhbNfeEFmMbBmBeQxrEgGejxTtkKYyXAbPWeeZBboHXgGxXUuomEezGIioOgZygPpLWwlcFLlAhHLfDzXxcwbNsRrYiIJQkxPjXzQREeieEJjISqQQiIMmMVuwGmGgrekwHkKhpHkwCYVSLlsjvVbBWvuUVEKtTEsSZdiayeEZzYADNPAvrRKeEPpkqEjJdvNnGGgCcBbZzliIQYLxOQbBqIwWTgGxXHcGJjFszRCtTOKNEezhQEfFkMgGpIqFfqQyYNnRXGgMmTtZzWHSTHCtbiZzIxXEeAaBtThZIkDPeMTyyieKFfkEclYEOdNueoDdjUulfhXnOdDGkHwNbNnlJjgZQjPfwWFVvRTKkdpPulLtTYQRhQTFfjxhlrhrvVGXtDuUdTLfFFfeKksQqkLsugWRLykKpPFmeLloYiZzIJFdDfNNnAaTlLHetvjCoiXkKWCYpPyKifpPeZuEiLZzOmModNfFdDmFGrCcCrRGcgoOyZzlIiPYBFQqCBYZzfvhVMmUsxXGCQzxXZqwWOIwOwWWBssnegquUSsDcCWfFwdvyxmcAoOPpHsLeEqQkDdDsRtTtYycCICcEjJMmOEeOoSbdvVDgmMQJCIWfAXrpWbKGyGaAOoYnGhEeGYFJfHhRrScCDYDdoojDeEmuUJgGvVPGsOarpHhJjlyYZzETcCBbXxoONnmCfdFwWaiMmxgQLWwIiJAtUuUbByyYAIDmMdmMctTCrNnZzsSNrEnvVrcCqlHhTMQoqinNWLCcHhnNJYsnNSNnOoYyOfFZHVRYysSGknIMPEBbzZlLdjJDpfFPIiFBbKyYMmhFfNnsbBqSsJjsShdDCcpRrlLSwJKkqBbBAXEOBcCcCzZiPlLSsTtyYlUuySNEeIaAfwAORCyXxDdMHrRhMHWHhwXVfFjHhwWCwpOBQHhfYnNUyvyWwPpdDnhorKRrxMmONeEGkCtNQepDUFBZsYseEcCnFfFDdffFHeEDLwEYyeRQqJgZzTchHCuiXlJUsyYcCJzcLzZRNqNmGNBCtFsSVElreaAEPGRRpPaJjArrgkCsSZtNMuPNYrcLwqQrrRoOyQUuChGWKsKRIiaiPYyCpPcpguxbzZLUuCEfThGxXYsBbEeUuhHIiQMrqGyxpPnfJyYVvZPuosUyfkoXagCYyqzmpEvbezZnGFdFkKzZJubfFFpPbykKDdgqWwAaQbTtBGBYXxMARuUrUipPJAkCaAwmMcCjPnSiIsqNxXhVrRvVvDhHdOKkSxaApqQPXjJsWwwveFXaDpEePphChHcHIWwozZzZACYMmWxXVvmGEeSdEgFiIIpLeOodQpMFtaFsSIisYUrqjZaTlLtOBeovGUuElymSsynKTtGFfgkYEerRboOBWwHwbBRMmUAbPpBBVojJJjkKfFQqjVvJJipzZiiiIollyGIrhHCSsGgEaPgGtFfTYcCboEeyeMXBrRxCcXEiWnNJjiIlxJrrAaydDjZsSGkWTtLPYypzajrSCcKkrRsjSslYNnpiqQMmOqQQnFsbBSTtqKIgGxKkXiwjWwgIAcCaWwwVrRvWjcpPCYGgjWaaFfKTCGgzGPYMqQmuUSsyVjJOqjmhHNaxXAnNbBYwWsAiIaIcCafFGggILlvVlAakKLivVOoMmGLmMKksFfStKRrbBFAgGazZfkRrCPyWwOnWyYNnwSscCdDYYmMPMmGgZtTRrzuUpNnSstTEGgOodBkTtdDtuUviIaGgntFZzVBLlzYobTtLGQqYplHysWweEDdJcHoOIwouUzZOzDImYbBorPDZKfwvidVjmWwMtTJyrrrRohjxMLiFuUXsSXDdqFfWwQbnNQDWfSsFKsrRrQxnPOfDuUdqNbPMmgHzZIhkmMAXNnvcCQZbchYyQWwqFsSDuFtuUxtoKklLVyYaAavgGhZZzuUGZgrPOpnNoOdmRrMDHvVXxXxyaiYyeqnNQOutTbFGJojjJqtTQBbfFdCecriIXsMrRfkeEsSNYoOQTgGKWYLJQuqwzLlQqCcDsuWrsSeEfFlZUJnUuNMmjFEcRcCzMIlmawWXpzduUniadDPVvpeUhHcIfYypwAilyGgQlLqNqMmEJcgGaJaDFZysSZDxlLeeNnuabHMmhBteFfERzoOpPogQVdfdEMJjmWOszZxRDeiPeegzZpnNGgbBhDiqPVgGUZzjosgGSrYyRkKkRFfBHOoCFfpeEnLigClLzZEeStDukofoBIYHubByYLyiIdDKkqQgrFxrRrRXtTPpxrFfzzZAadAqgTURkhHCGgcfDuUdEziEwWJVUuvDMEhHkvVLlDGUuvjEWxWwOoXYIDNFuoDrdteuQuxXZCbBCjWwJXxTzwTtOoWZzZzECcXvxDdXVOdDognTsSPMhHSjWwajJPRXTKyYXxIikQqtUhiIHuUuPKkpeEJuwOodYyDWfDdCWwUNICcrQhrRHqeZQmMTLltFTXxKRrjrRJCHmfmwqKyYOoGtBbTlDaAhfFuzIiMsSrZAanDloAabscUYIcCNaQLSVyxJjhHnNQANHjSslLwSuUZRLrRtIeEqDdMmbYIiNnOoPpywTUxXuHnNZYpIonDdKkeLlAaVxVvqmUOBjYytTpPJCcbkCnNJMmndlLJjzZDpPNxmUYuzhMSKkJCoOenXxNXYVLXZqQQDEpRrjJAPphfkKxPpoVVMaBGZEgdDNnsRrSOIiydDiAIAhlqnNfFXGgTtLnjNjyEhIiBCwWIyYKsjJSspTHhtaoOonNVCgSsvLOHikbBQqmMRvVWtGXxyPYqoOQHBxSQbBqILlqQCLfFDCFbJOmeEMAaMwWiIWNbJcoBqogoxtgGhHWtqReWwrWBjVTtvJUZCRyrlLaAAAymMSpPOoUOuUPTxdNQvEepWrbsSBTpuURiBbHRWwrqpPQFfXxhLlrmMaACxXqmRrHEeobnNBOTNIjJEegaAsQqaUEegZUxpPXvQGggKkxSMbuVnNimxpTtPJjXrzdXzZxDCfgGdxXGxbBXqQOyYojaJjAJANnwWeEPuUppSftLlbnzneEaFJjZxLynNfFmMYTtlEyxMmNxXOzhfuUFHZLZFamWDdvtLDyYxZQmMqzXdhHQXSWwsoAjbcLioOIAaTtCoLlbyYBYSMmslnVCcvZQqPLnzfPiKZnKAnNacyYQqQnNqDGgXYysalLAWwqyYJjyiPpInNMCFfEeTtEncJjOgjAuXBNnXxbxXdWwsndIiPpHhDyxXYmqqPjJPpaBeEbGgJjSskbwvHFOZShMJkNqUurRQqhHIiyfFWhHvVERrsUwBEVvPpEeHDYyMmFUTtAaoZlLidDqTuUtdRreBzRHGwRPpzdDbxXnNfqBkoEkpPzWDdTtWwwxIgJjGFIiQqTHhaUuAeSeuPrRqImMqQolLOZzUpLgvVypPYMmCcSeBRrbiIEbtoOTawZhHzqLGgoPnGIxXSkzZcCKkOeEQqtTMxXFncCNweAMiNwZklLDjWwJjJNkKpVvyYtMmYjJtRjJwXxFfxXfAaFfsZDdQqzgTjJJjhjJBPlLFxXcfFVvfsgxLTtlZzXsvCXXxyhXxqgGQkQDdppiaNnYybByjJsSYlLtwiRLlZoHhLsSRrlvVOxPpXOBHFfBdDxXGlImMlLiAKkaNnPpqqSsQnHHhSlXPpIgUuHhPwWIiHBFfWVjYBBStQoNneEebDQqdBIoOZOMmoADjoouvTJhRPprRXOoxiIInNibApZGUuVvAavyYVBYKybNQqQqwWnaVvTWpPwtXFfwThRMmKqsXqQLZzjCbHhMkUwnXxKkNRNnbDdwrfFGgcZdoYUlLvCcwWlLVuONntnTyFfdJjuDJjWJjHDdzTFSsBbZzXEeUNnqQVovVfFXDwsScuUuUixyYXkKmMDPbxUBbRxXmMMmCGgiIcCHhyQqpxRltTKkNbQFfPDdDdPnjSsWXxvnkksSkhdcaACDdlLYylLDlgJDdjKgUStMmTxXIisumULnNlaVvAjwWJTrdmMGgVYsxXEZzRRvVbTzGgQSFfvVsGgyYBbqLmMMmQqWwbfjpdDDdTtEewqcEzZMmNnmMfFeCQiIGmAaMtTGgmjJoaAOTtPWAazZwioOPerREpNgYNxPdzRitTIrojdGxybsQqwRrDOodWeEMDzZUkKZLaHYyklkHhKLgGWSswyyIiipPMAjiIJpNnrvpPVlsPpjJnNlzZtMmTkKJjofFOrLWzZwMmNnlRDJjDjrRyYBPObMpHRXxSsRrrcCOMmrRRroGGBbegXVvxTBEpPtTeyYnNEedDbyIjPGgpKWwNEZwWksSSyVEGhhHsaAqQNhQqHBavVAaUoBOoSscwoJjRrxXMwWmxzZlZzsIimMvbpPOnDdNrQqRuaAycCYsSWwveWAawtTzZMmEWwtkHhDHhDdArsfFSLkKYAuUaBCQqBbuUlbHwBBbbWxORrozZTyYUQLrwMmhHoOJGgIOvVmjqAVQEefFrRYEYiWwrlLREeOzZaTGpPgQazZAqBbCcYaBlhAaHwwTeeEEFfXxCNnZzQvhHVwWMsSQLBbNnJjBKuUmMyyYYTURoCciKljJjdDlALlaLYyFDLlaAYWPpydwoHFdxhXxItTxYxXaDdkekxSsTsRvVrRrZzMuWOsSoixDACsSYcvoObBCcwqQBbrsggGcrOeUuEoUuWwdDpTEpVhHnNTOOcvMmCCcjXxTeEJWwjNxBKHhnSsuBKkobgPpGBUwlLWOBrRJjfFOoUubtGmeEJjzZVYhOoHgiDKVjCzZcjGOoosShvAanNcswWnbBNvVVvLhIiwGcVOovaAEiUWwdDvKkVuUeyYEeSjDdSfSsvVWwImzZxAasbUuBaWMZzmwePpEFkKkVvHLlSAaQqXXcWwGgTZRDJPMmpPxrRXhbSsBoOHOrlLWFcCJfFjfUoLMmdZNcCTVvnOeNHhnCcJmcNUVMcCmvunMmcCnNQMgoOdfFRaAvVhHYyiPdDMaHVrlSsgGEjQNwLkciIRDqRbBzowLaAtReKSAaLspxXLlPonyRaYdntWwBbZzCDpPddXAYCFHhqQNzmxdDoOXrRIiCVTtdVFdXuUxoinwyYWNmoklkUtlGRrlaEezskKcdDhHCSOoURrGpPQqkKguJDEmnvVIlLiIibSAQqUuaBbsasSsJclLivAaWKHrRhmaGtSeHhEFfiALRSdThHrReEafFXogucHZhHJZYSsecqifGgFXxIQPXNwzMJDzqaAQxXrnvpWwCcOvBOmzZcLIilAfFaZiUlIddkkKbMpBWhGgHKgumMsvVPkKpxXMBbOoKkadiDdSmMhHUiIKuhHiIBRrUtTJjyYJpPdwWDrRSheEHnNqWJyYjptgGTYcCcESDUsSTtsSInLRrbOFfIigpIQqiPWwhbmbNgUuzmmHeEhMiIUuebBEVZzQAyCTHhvVswGZeKlLJtzZHlLGYygPpznNfFbqNxwWxbqQBQWwPTtEhHApNoNBVvPpyYbBgjJGjJepCceEOJiISdDUusIijgGoDqQdVIqDzBMsuUrRPlggGGvVhHgsSuEsSKkmfFFfuURqQeEvVrHMXxeENgGZgGwWzTTbBsPPtTaUutbYyHhrswWvVSRoOCcqQmiIMppPjXxMqQmHhGNdDBFAUPmMpjJTDdhLlmtwBUIipAwHxnNXhvVlLysSgGHhcUgGKkuCkRiNWwNnNXXXLUulRmMrvVxZzUqQstgZzQHhpsSdDctPtGgiIdghFfYScCqBGgbVjQsTtwWAaiqQmrREeMVviIrEfcCCcIFfQqjfFMhHmuVWmnVjmMxXiIoOBbMkcxXczBnNevbeSomrQnzLpBbSQhgGHTBbAzdGgfWJjNRKkroOorkDakKAtTtTMAahHOtTiFfJjIQqGoTbcCBtCcZbLlCcNTXzgGZxtuFtTfzZLKPILnNydzqQZjpeEFfoOPvRMmPuUasSNwdDsShLBbdQUuMTtmqbBDSPpEeoaAupmsSaBbqQaPiSsSWwrRdWiIlLDdZRrODbsVzPXuNnUbPbiIdhHIiIEoJqQjuKPfFMvJBUuDVOodWwleyFfYvVaAyYNxGXXaAxgGTKiIPLlyYLxLlxJHBvnsYytTSNwmMWVbDvDdYyVxXFfmBbNDpPoaNnxLlJjXhHVvswWEeSZyOPpoXVRroOrRtBpqwWQHhjmMFfJHRrNIncCxXYkIvVTlLtiGoODdeGgRrEuUJjKkiCsiISKnNpPpPkSaByYqvVdDBSYRWwrafFmxWwvWwfFEfFeDUdWwDnRDddDiSEeIwWMNnmymaAUvYyJOojvamMAfXDdGgxUYymzlLOLsbBSgGbURUuDtTAnNeEadrmMxXhHYrRckKzZsehuQQtQqVjzQuUkhuUnteHzQqZVvXYAuxXUDrgGRvVPjrGvVgOdnvhKcCkttJaeCLVvCxXMLDhlHTtzpwWMXzZxqQmkRqQWNNkLllLKvXxJjVyYuUSNnsqQHhwWAawWZzZajJbBtTgywDmMaaAgzZEercdTepPaucCYKbqQqQadDABMPyYpSgGsAfFNgYyELwWdPAawGEecCEeQIiqWlLdLVvcXnWGeEgiWKbBMlivTzZOooORrnxYjJaCclhHMmlWLlwoDdEeVAFwWxXGLPBFflGXJuqUbBuQjitThzZHejUuEiIeREpSspPPeRwMmhHWrYYyEpPAaLvVyzZtTYyUuVvDkKGgdeEFtLuUOPvzZVEegvsSsSMmCcEeUQtnWwMmNEeGdDkGggGTtrxXAaeERyzTvVKNnzZaAYyqQKkLqkKQuVOJpPCdDGgWiHRGgBbrEixwWhQBbqLldDcDzEMmodDRrCclvtTQqfiIFlLgcEmAaMenyxRRhEQtKkVvcCwIiWTqXCsSDnvFGgfgGVfFdKkUWXGHhHhgULoOAXBbzvbBVhbuzZhHnRhuprRIfFiDZzXxcCwqbDdBosiiIDUuvQWGggGYyLMmpPHnNhYHhdtueBgGZzlnNLYnNiRUZzgdqbGgBjRDdrYyQqnWrRwczAXxawUuVaAvnuOoEzAatTazZxvVxbraotmiGgXxGgRrGuWwUHhgLwWujbBnIipPHKkhNVvkgrRrRQeEYyfZbBdcufqDdcCbgLlKahHFfcCSxXMtiIHhOoqQTzVvZTYJjnNxXKkgdMeWwXwWXVvEezcCJqQUoOXxiKeBbELlkiIFfKkrgGfeoVSnNshggoOGGqGgQaANACHhPpCcyYtvndDDdDHoOOoKkRDrkHnCIicGgvPpVNllxOpPSrRTtwnNPOaAogGcqQCWwpZqcpjwjJKkdDHhYKkMcvVCzZmjJTMXZqbjJUuHhBfFQzQqxNnIiNnmSsvvVeEBJmMjpxrjJRffrzZRfSDdTtTdZyYghHwlgGnNhlJjUJjXFiIfxuUxXolLzxXZzBbpZzanNARluUeIYHLlZQSvVHgzZIpanNZzZqPhFyUulJoOEejeTwOfFodDWwvVWvvVRrVyrBCcbrwSSsDdGgadANnaDXvlLmEePpFHhfMOIxnNXFZzfmkKNTHhkKAHhaQwquUtTrRSstTQWFGzrRBhHuUmBbMVbIiBwsgmMwWGRrYyoplLuUaZzTMmopPnjJEeoOVvvrRotTdDvVvVOCqdMYDdWIeEiTGgVvXDtTeEUuhHVvVvzZNnATDdmhVqxVhHyYMWXxXeEZzXvVqfWCRrOoRjJqQrHJjbcCrSsREeronleELNwaAbBciICLogBDvVfFbBdCZzcOkKwWodDXxOaTApAFFKxyYXwrRWXxTMQMmSkKsqSoFfjJFMmfPYOijJoAYyfEeCcuHiKkIhJjGgzxXurRcmSaAsfWwFteGgBgLJjSkDUudYyKAQZKkYCcoOGVTaAHhxwZzqaASEeshHSFfQcKkCTCcblLFLlHhAacIizQcNvqfFtTnxUFKpPocXSfyYFyeLlshkDQtPhHIiZwWIizKhHAaMmkDrhgsYybBLlFAaOEeofjQqbmcrxXRCLlfXXxKkmMgOlbBGgaAmMkKLeBKJrRjkHSsqpPLlCnNrRwOoWtnNQqxzWAaOsSzZwBbyYsSCbyYxsEmMiqQXxTBaAAsVVhHKkIioyYOvHSsbqQlLZzBbiIYyXYyTtxTtDRrPnNUltTFfFfiIQqgoOGuAajfwOoTDSsaCBYyWrvVpKSskzSsZjysMslLSxNnrmtuNydDwWSjnJjaiIFfhaAmhWwHpXIqRrQGgixXdDdOotTWcCvhHxFfSmMokCccCsOoqMmxDdPMjJvRruRrIiUVmvFgLlvVaCXKnOGIJVMIqrRHhEhwIiQPpPpqRrdRDdJRwHiYyWmLMmlhHNntTsSsSoFMmMnNFfnDdNmWUQqRoQqOEoYyOpPdDRrermMyQjJSfGzZlamjMKkwWhZYgGyzJjjJAajSiICWZlLfvVFZzlDhrRfFVvRrtBrFmnrhqQyVvuUHhxXWNqQEefbBvVOsScCMmupPKkUXxbBxeEDdTPptMtTeEDeOovJjoOVyPpxTbBsSicPpVvgGRrCimiInNNlnNLxArUowbQvVnYNKdDkbGgBkKbwWuMmUfZZYnPfFpmpPRrtwDERqQlgGqBbplLriTtAaIRvVhHFfvtTcCzcCZGgAahXxHgUhmMhbBHHcCFfnNqnjTtrRJNsOoOoQSQJjqXxfFpPvDdiIPpetPpTVoOMqQDdiImYylLSuvVUOTpPkyxrfFWpPwZqQGgWRrIiWwwNHkKhUZTtSsTJiILltTjHhteLlUZzuRWcCctTAPaApayOyBbYoYwWJjwWCSYntQgjISsvVYyFfvRkVwgGnNWaTKCvPpLYKAapOoPAXxrEeygRrGJjlOoTtbQqPpHPpDtTohHqwWQzpPwsIKklxXKmMkeEoSsMQWwVFfcDehWwVgQqGiIMCcOoEePHhCcDdYyOTXrRiVvcigGoVYyMEsSejfFqQUuOUlxXhiIHrRyYdDcgMmGQqCDtaAFOPlzcVvTTHhoZmQRrqyFaMmVlMITDlLkKWjuUMqfDwWdyLlreEusTlFLCctuUDdIbYyBsSSkQGgqdDkKUiIkKwWjJuyYHhutTLVHHhhQbXRrsISHKkjuzkCcEeoOKMmZOFnyIpJSZzuFfSsUZCczmMsIEEeqQLzZlRsSTtbwTBbqHHhNnmQqMHtTVgGnLQGgqkfyiZcCzuUjJZzZlLqQuEUWwnvDAaAadvVVWWSvVDdgGmTJjtdDMsSmWwoOVbBvvwfFYywRrlvVTseFqDNnmMPpDdupBbkKPnNaovEfNnFeVrRRnEvFrIiRYyiIGyYCckbBKBYjJaqMKkrdTtxpPBLaAPpQxXqZXTPptxSstTXJlLhHWwCckKhDiIooaMmMhhNGfFneENUDeEqRrYyzUunNZQOqESCcsDdetwWIiIhHYcCyzZOoiTQhAJjkKSkKsORryYoaXxDtQqTkzFfcCmbZwWubfFZzBwWXxMmUvMXxSAakCPZzIiAalBbTtLpmiAGnaKkANgxdDXiIaAgBbHHhhcCunKkNUecTtyEeYCngGMuogGVNjjAafspfFPaulLcCUAKkRrDfIiFbkdFxXygbBEXfIiMmAYyaFxoziLlUxAamuUdwWJaZzzZOoAeYymRrDdMmeExAivVTtTTHCcaAlfFaAxXQqLhHeEmAhHBdDbVIiIUIiiNnXtTxIsqzZCQqftszZRrOXGgxdQyYkItUUZzMmRASsacCYBFfkyYhPpHUuHrYyRhNagSsJjalgddDDARKkMDBbnwzZxemMYvCcVyEWwBbtjJVjJvDVhHwWIiWwGdDgCcNXlLeTEethHqNUunKXxYTbBNnpPPhQqHpkKtCrVtTTBbIZzsSpPrxXRjJjVtTCztTXxZAaYuaALljxXvuUOpfFfLQNQqQqvkKVgGpPjrRJELqZeElJjLZVvzMwzZWmhHAasSPTtDdhTesSlBbCeEcuWwXxEeHjMmJDdgGRrWwJZzUuuUxXVvuSMSDmMkzGNnkjJBYgJjUuGKksVvSzQKNnkjUtkKuUTiFKKcCeExXkZzpQHtTPpjUQRrmMhXSsJjYyyYYWwyxLQajyVvYaAXxtTGghdPpOobElLmMAPZpPZFfgGbcwWWDdwitTwWqgGWwBBaAATtgOoTtGuFYyxQqRrHnNfFFfIiMiBbIfmMFGgZnMmjJpPpSUuWwqQifrONnFfFWgqQGwfbsoODdbBlrRJjLsSqQSOuUWrRMmPTtQqwWSZLPZvAJvmZzsWwfeEHhmpPNnOojeyEESnfKPiISTEetPOoAmLCcaAlMjzZkLlQqYdDxXHmMhOSsazlmMsSwUuMNSsnZTLlwqrRFKPpWwkzVIzZxfHhSswJQmMYRrHwWSshUXcuUdDfFSHhtTwDdvVqQubBFfKknJFeLlAeEdpPrxXDCfFgAlLaJjJlLjbYJjMbBmpuUtTPoOGTPdABbAalJiISXHKkhWPuUpVnNyCcZLlvVsVnNviHhhHhlYykKFfZAaFZzSslZzLiBnNZzHOohDFjDrCcRtPBbGpEvoOVXkqQeEHeEOpqQaAvrRmMVPwSuYyUsjPUKkTtycCpPYEeuwWlzZZzoOIqIJjzzZTUuRGnNTAatqQpPtTgcCCOxXapPGgBbtdDTHoOZzfVGuUSsgVvGTFftvVpPzZlLGvVfEmMgJjGmMrRIMcmciKkTtgJvVWwPpraRZzpPOMmqLEhttTTGwWYmpgOokKoOcHDeEBbwWMVGgUtlLXOaWXyAhHuYyUIiOxRUHofFWwqoOrRwrRQqdDMWdHhvVmMKkKRrkpViIvGgEPpFGgpPfGgXxTtajZtTzvyYDdGAiMCcmIuBjJsSbgvVhdJLlGPptzZJjiIXxHiOopnIizZjJNUuYysVueiIDdtThHXxXuqQxKNnkXxXZzubTthgggCHKkKkIMmihcuUCpYgwNFfnWYjinFjJDAaGgVQTtNVMmvneEqLlRGgrKkQLOPpoueEufFhpBOoXawWAxbywqQWQqOyaAddRrHBbhdDfYyVvkSskZzKhHjJKzKcCkDdDlPpTtpKkPTtdDZzoOIomWZzbgGBUjJoDdOCcJLldxXqQDIFfiTtQqoOzsSGvVVvFfFLlmMfJjKCZzckrBbndqMKkIGgilAxhHCcRrmoEeaOxJzoOlWwpPUuAamEFgGjVvJbCcBhHrHAMmMHhLlBbmiKkRcCrXxBakKABbxQqdDXbtmIFCclLEerSsCcRsnCRrchvvVVCyYcWdDdSsSsDeUujXxlSsfFLqxlhHtuOsbBfYyTlLtSeUujJzfSOyYWGVBWKPpzvVFfagGLlAZemPpMqkYyKMvJKkquUQUuGOjNnxXIirRDdHPlUubBjiIJmMFfpPvTLlNECcNnentVTtTtJjHhZpXxPzzSsZnaIqQiMZzeEgBbOoBxpPHhXbdDbBopPOOoKkgGdDKQqkNFrRAVrwWcUuzZjJkXTVIiaAHlnNvhQFfYyzhHeMmERrWwJpPNHQAdXhHrRDTNWgGgxXudIioqwfWwFLlTqkKujJMAyMyYCvlLVrRaABbcRrRYQeXLDdfFlxeHhSCcszZhKupwWEeEpPemfFMrNnLlWkFKkgGfTEetKWgLsPTtpVgGOovOojJwXUuxWVvHDTqMmIiQhHwWEeroOtNnTRoOakgURruGMmxXxXSTMmtsKOZzMmeEPpEAoOaeEXxHZbBHJKknHhZzaBbAoOZKDdeEgGrRcCKnNNGgoOfFXbBLlXfFaxvVcCiIXJyhHxXVJjqQHWwwOoWMRDdrZzmAGIiSscCrLluQqURfFRrPQqNIvVPprnNRirtTRCcnxKKkqQCckXbBYjJlLwtTRrJStTAJeEjzIIeeIixXGgEESjpPROhQOhHgGzUxXuKLibpPBEiIIZzDrhHPXiKYynCcZPbmYgGZzyUcCPpLzMmOooOBWslLCcSlsJjSvVaBoOVvdDTQTtxXqwWZyYkQmMmMqzZrRypxXPgGnNQLlqbBmgGmoOfpucCLlqrPpaNKkZznARPpQvVGxXgAhHaTthnNUuPMmmGBjJsyYSbMsUrRuSiYcCuyFlLfXxdDHoVgGvUEeVvbBDHkAmMmfQVJjCbBcpPMeEhHBRrbguUXjJeEMXxIigGhEeHsSEedDzEWweZGgnhHPzZpTyiIdkURHhqoqQtRxJYyHiIqQhHRKkrtTjXrrvDwmIQCclUaAJjwWugIiGJHigEekCcHhKGJjITtBjJgdDGyaSoBcCIibLCcOJjmbBMgCcfFGFSsYbBykKfcuUCyYqQosSdqgKQqQqgGkaAUMmupBwNnUuNnavYyhVABIFqZjiIprRrPrqQRpqAUuYleELXxBDGgdQqbyYLjzaAMKkmmMZJlLYyULLlluuUEDFfdzZpWwPTtRrpPBbervVyYRlLdQGtTgSsXAJjaLTtcCrRGIvQEeqXxXxXxXFfjJZzgGkKjmMMVWwOociJjICvmjbByYmMEeFDdbBfCcWsSxXFfSAMHRYyrhmnGgEeHaAhNuUQIDdRrDdiIdDjbNnfdDdCtwBzzuUZZbtTWKAadKVvqQQqvTtqQXxMmnNcBHhNnuMmYvgTtGHhKkdDWDwWdwRrXkKxzKJjGgTtkeEZUuAJSacpfnNFcoDoOduUreEzAaZPpcAaIioOqTteECcQLlCNjOooODpQqiIrAsAkKaSvVAaJqkKJjQvXyYxVcDdCjsouYyYEjJaAepPyfdDVSsEiIXcCHQWwdsSDNbiFfZiIrRGghVvDcGrRgvmEKWwkVtTYysrRSWdDdgGGMmFfCcfqQmMYyUwWuTtJFxXflLrRxXHhqzZBbKkpPGxXVvXdkKdDENinNIbBoGKkgRdDNDdnrWJJkKGgGgkKjjJjQqYBKkAyriVNeEtTfFIinpnNPKkWtTAtLlOoxXfFTtpPJiICBbDdcrHFfqFfQJRruUEExGXxeFfEgdyYfyIVvmMdNxXnmIgGiMwWeoOEOjhHJlCefFFfVvZzfFEcCcBbhHmMLoOvVPtnfmDdPpHhJCaAcGGggYyfFtTYaATpPRraAMmBbfFtUSsuDprRPvVwWUBbuywWfFhuUHYdDgdeEDiIQqHhGUSUUIqQiXnNxIaAtYyTfFDdFfEerRUugMmGQqWwiFMmfAFiBbIoXuUSsxOEwWxXJmMxXNnFficClCcSPpGgBdSsDbdMmYWwrbBHyYwVIiGgUzZuVvzotTVuNnUPJdDsSJizqQZIjxXJjgIiEIGIbJjdZbIilqEcJAatTTeErRRrtDdSpPjLlznMmNRreVvZoOzusSsFfJLlEdDejhHoEkKVfFqQvoOjJTtRrMmwWGgfweqQxiwUuWIFnsEeSyajPpAaJWwvVnKKkrREfFovVwyYWiBSsNnDQqdCtTOocanNxQqXvVVFfSVvvVLlbADiIdOoaSLKkpPHhlKEOoIDeEGgeEYXcCxXWwZzwIiASsrREYyMmwWesSvJOojyDdXxYbFfbeEOoBBYhHNOqQFfQqowWqDtTZzCQqlLghHeEGJjrFfuUSEMPpmvyYVGgcgzZeKxXkjVvJEjJrCleELRrLXxcUuQABNjJnNoOnbAAQqasSSstTBbKkaBhHbieEuUNFfnpyYyYKkBAaGgysVvTtSPCNRruUncwKMoOmkBLmMgfFTtKVvnNvVFnNVvfkCcZzFBbrRpVvbBPhHfjJDbBtHbBSeEsqlLQcwSsbGCcgBVvptTPWUuVfFWwvOonNwomBbcHMBbmUuhjJzlLZypPBYyjJsoOmBbmMcsQqHhVhjJHDdFkKfXsSuMzZuUxIixXkTtbBSffFYyiIFsWwAaKJjnozgqQjJNnXxxXAaLOolQqeYyJnNmdMmACGLlGgQqnNpPcCgcDdjAaTHhLltpJuUjqQggGDdqQGuUPMmXRYOoXOoUuLlVvxKknDifMHJjhXxRRIYyirzZzZTtKkruJGgjyYSgjJrJjTtWwUtTjXQqSsxFcmoOMCiiIRgaACgmMWwViCKiIOokIAQfFxXqBbYqQyCcpMosSjLlNnbqMmhCfFrRckKwWVvIicCxXJjhxfDdFXVvWwHJpXxPqHhSsZzQjYyJLluUjzpNnPZeEUiIuIiXxOoNdkMwAaWmKBrtTfIiOoOCcoFLlRQVvjJiIqRLiIaAlhPpPTEQqeLlHhbUTWIeEmMeEiVNnvsSSsAaDdCcAaRMAamTaZzCcChpPwWgGCWIisSwZzvVoNnOLgGlfipPjJIiPsSpIZanNAzWtmMgGTBbrCcEeqQyYmOgGDVvTtClLiIcdXxCcKkMmlLueEUUuMmMmDhHvVHhSsPujJUObRWkpPPdKkGTMmRYyrIimMXxuUZxXnNOogGEejlxZzkKSsEevMyYmzHqYyQsSIiuUaApPaAnNSsMkKPpjJmMmMUumnNiIhmWwpPRrUuvVAatTQBbLqQlvVuPtLlCSpPsnkKRjJrNjkwXxlRrNnLdtTVfVvFUuvDVegGaAdDEJZLGgRrlvGgVSPpseESquqmvXiIxVqnNgtTpfGgFwWLpPnnNvVwWyYZzCrhkKSsvmMqQVVvFyZsSzVsSyYBbeEQiQoGglLxXCcOXxqIEbpRrPFfRjJKkzZxHhpFYysSVFJGaAKGhTmcDbqQBdCQHJSjGgSsqTtTYyoOmMGguAaUYyrRbBkkKKsSyOoOoZlruUrReFffSsFPWwrRiIpuiPpIANLlbByYnhmFNnbhHBdDVbBGghHvbBXTtrnNRILpPlibNniILlaRbBEenNEerAhHLlzZxCcXeOovVEvMmuUsHhSNuSsUmMsSnHhTzHEwBIiOoSsAhHjbBJvVKpULlylHhLsSQqOiIbCYNnekqQdDpPKkWjJJinNItTQqAauUBFiIOhHOKkxOoGgXLlAkKrMmRqSAaqLlMmBwKkcCKkHTthvVswWAaSfFmfcRrCFMxaJjAXuUfFaACcWeoOjJEuulWwrRLJjAaMSsBQqtTGgbAqQpPPXxJjbyYBCcrRvQHUDdEwWeZziurRUIGgkKsGgAzKrRknNVbZzbBzZCclgzpPZyYDdIiCcvMmOooGpPgDdRVwWeuUEOdDovrKPcColLOzZqNHhnQLlxlesHhcSsSshbBHcUuCsHhBbmMKRrkSOspXrRxiIBbPSomEOGLBbkKlaPNnphXxHJjAAagjFfJPWXxwWwUuwWDWwuslLcuUtNVvnLmAkKPpEpPezGgZkKOMmozZMhHmNnyFfwppPPdDWGgYVvvyYVoOJiIyYdDCcYcKIiqQkDdHEehAUuaFWjCcJwfoCuBbUcCcOMeEqQsMjJgfFZzGWrqQRaQqAhQqHEeRrdnNOUuEdweEWDyYkKsShcCnNVvxXeEiImMDizZRrlVvLLlAaAaItRrVvTcgYyFfmGgwWrRMXxBbZzkJjPpPLliIpmMMgGBbKXAjJCtTEeSQqsPJOoLYjyYJBbHeFfEhgPpGgyYGFMNmMnUuZQqzmdDKFfkwPYlLypfFWTtkFMmkfFEzPXxSszBbZRrPpSwFfJzPpdDshHUuwUusSrPKkLJjlaRrZziIsSuUbqbKBbXxUukmSaAsGgBDdgGbQqAakKMBbWwcIioAaGEPWwpvRrVezZgOCfjnvBGsSXnhHnnuUfihHTtuUEehHWeEKkSsEeqxWZzwWwXQDoOdwWwCqkKRbBrQccCIitTSssSvVxXIMmNYyYyTGSWwjKdBprbBRyYPyjJYbaAwEeWDKnNWqQwoOxXkyYtlLTkLPzZAgIiGRrcTGAaAuUafFgGkKbKkZzQqBgHjUuJtTKVvkFfhLWZzXxSsJjJDdasSAdDVtYyOlOoVvLoTCrRToOtsSjJpeEQqPcFaALlnNVvDdMiImfFBrxzZcCLlJjvUhjrRJeHlkNnJkKjnLlVtTvLOolNKENXxwWwciICDapPAWwLWwpcCcCPjJomqQMQqzFfITtCcildDLZsrPDdpbuUBRZzEeLMmlBUDduaAEeapBbIiqQQqRrnNPYysiIRrSfolLhHFUlLEeeEuyOoYiGlYrRyBAPpAavvVVUIiuCJYyDuUPgGTRragGQsSmNnGgMmMqIPAakKpiTtXxVvYxXqQSsyOZzHhoXpPpPxgsSuUSsCcCcrrRdueEUDNncOoCgGgaAFECPpcegGJjRhsVNnvlLnNfFDeEiITtRKkOrRUQquAaPpBbZTtmMCtsyYKqQtRbBOorTTtaABbkvVSLlWwgGeEDflLWDdrRtTyYYyCcJjwFrKkCXxcopjJqQkKKZzSsPreWwnNfFWwLluktTzqVvOhNnHorxijtWwThHJqQwULbBluhkKHWIiyYIsSZJLlLlUuNnkSsKDdgOoGBbaaAAiWwgHhKkGIpPDdzTJjKktPpRrQzZjJBbOIiLmjmMJvVmMMhdDxXGgjzZJHtqQQDdDdgCzZcGPdJjtTDoOQYQqnNyWwcNnnNKkQmMqUnpPQAaPpqDdApPeEaJbFfXxeEQyYLloOVvSmjeEiIYWdgGDXxvVwCKkcWwLYylBKhHNneEVcCbBOoNnYyzZZTwMrkKRkKiIARKkrioOIOpPoaPpTtqJjgGTtrqBbkjJKjJFfjJPjeEtTJpeEhDdpPHkuABbMLlTtnNkKLlIikTtkKQSsqhgGNfFpYyPsbkKBgGcCSoVvOfkKwWQqUuCPFqQfpUucnNCJyYjiVLgPpVyUuTtUbBuYHkGgpPDdKFUufhNrlLRLlNDdnjJmDGgdiIbzZGGtTxXeKkTGBLlWwJjbZbBzVjZhHRoNnOEtTuRuqeERrQnWwNUUxXuroOwzRrZWUtTNnTtDApPaoOdOzZfGgNtDdTYFbBDdWwbBfhHNgPqQpGyeEYcXxeHhlLEoLnNOwWCTtcoxXlOEeTtDWwAaeEdiIrSsRmMobnCczZIiAaPpqQDdNrRRrBTCcMCDdVJjvnpPNnRrwgGWjJhHFfmMNcSggGdosSOZzDvVGwwWKgGcCrfFLlRiZzIAaiAoOMcCGguxXUcCNnSsmHYyiIhLlxXdDUuhfZzvVZLlzlLBbFkVvKkvVvVKcCjJwWmMiILlVGVqQvRCcrhHuiIUIiQLEegMmGyYAeEaDsSNnYymZzMGgBbHhMmaAGgCLlIBbiJqWeEwqQMmPxusSdZzbLlUuZvVSvVsUjsSjJlLpFfPFfJdDuzFHhflLuvViIPpfFURVvBGgbrVZbBFfbBYKtQqzvVZTkKsSfduUDiIgNnKkGFFfpLlPERZTVvtzFfnHhmHxHFfGgGsSgSAabBwPBbrRAapPpaAPpRVqeEsSdRPpIixBmMbKkKkKtTkXJjFBbPpfihSWwuUYydDdRrSWwsJMmjxPpXDFfyQqyjWwJaAOogGQqjJwoOiIJpoxXOhSsyzZZzYHLlmSYysMIisqQTtdDSlLlRPiIpxXNnjfFJVvrfFbBPpsSxBLlAaHhKkDdNcCcTtNnMmSsCmRBfFPpnNbbKfJjFXxkEbiIBeMJjOomRrYLWjJHhwDdpPBbzqEXPBbgnNGpcZxXzCLlPpOoxSsfFAaYFFffFGgsSpBjPpJeEbPJsSwTtWjrRbBuUdIiOoEeKbBbLlBkqeljJLEoOQKVvdDkDuwxXWUXxigGUuINhGZzKCcsSEzZeSxoOgGDsgGXxSEeOCcFlKkLLlAafxXubBUxXIhHHhmeuUOwVvEeOoFfYyIzZmMiiIOrRTtovHhlLPgGpVscCSpPvpPMmrReEmMBbvqBbQSsVLhHyYlAObBoITNntHDdgfUuFtXTkKtSoOmMOosyYxXSsdMmtTuUAaDxDdWWgGSAasWhfFiIzmMZHfFlIiOZzWcClLMmwMmoIioOCiIECCcbBcdfFHTtGgFczZCfhvJNnqQOiIeENnqeEQbBoBKkVQqaAXZEejJxXxXwWlPSshHzEOzZCNeZzEXxpnNZzpgGPpVvaAhHXYbByKkFIifKkxHhpPoOAgGDdTlSsLmMKkoQKkqoONamPDdpsSMRrADdyYsKkSKkAaDZLuKQFfBHhbBfFOcCfFUueuNnsSAEeNnyYZFfSOorPpjJRQqXxUYoQlgGvVKkLDdRMTGgfFiIyYdDGgoOpPhjMmbBUregGELlRXxXpPjJWwOyYiICcoCcxUrGgRuDdUucamMACkLliIKzpPZFfoTtWwfFOSoOsgLldeEDGtXZzxsSsSraARQqVvfXxqQAqQGgaFxrRXJtTKfFkjqFWwiIflLgGhHrBLlbRBiIHhbRruURrMUBbfFugWwaATSstiIGPpmjaAmMHGgzsSZtKqQoOWwkcCzZHhyYyYRrvCcVWwTEEebBurTtRUnNFYyaAqQfbPmdDMpByHeEDigGIdDKwWeiIHhEmEefFoOWwtrUuRrRHhFfJjDdTRrkDecChHEoOcgGCaAwbBWBKeEkbsSfIUuNniFTtoOIiUNtTnDdNvnNVWwfFzZnYypdpPDPuiIzAaPIiXbZzBbBbBPpyYvVbOZnNzZhRrHuKkULGggGlyhHlLpPYwaAWGgzRrOSHhMmvVUkKLJjaAtsSpPTldITTttiMmyYpPbBCbBHhdDcMmBRxXNnrbvVXkwWtTgGGgWyOFkKfogGRrZzWxHXxhXpPwjJzZsRPxNnXyaAPIiJDdyYGgjQqSsJsIuUyYWjJwiSaABVvukHhpIiPKTtkKGgVAZzzPpOoZbBHcjynNyYAZzoOIiQczzjJZZljHhzJmMLlgGVcCYyIixdDvVXILlimNbdDBnEesTtSMpykkKKsSbBYPHhehHEvNaAtTcCUWwAaSsteFfEwkGgDOoNQqnSwcCZsdDSzsdDSseBxXbESGgsSWEeqLlUrNLlUumMnRuigGITtePpcCAadCcDPLldDpnqQNNnnNYyxXmDxXSsXxdGBbgMaQqALtTlfNnBbMPpTtCcPpYymvVnMmrRNBbIiFdDLHhPKkpVvPxXplEeRIicCrRaCcABpPjJVvbraGpPMmSjJsrRFJjoOfJSsjSsgTtClGgzZLHhudDHFfLlhYvhHVwWmMpOoJmMjBbPyuZzoOUKklbaABuaAUvVrRnNLCAacYZRrzoOvVaAtTCgbBGcltTUGgZhHrRVvbBPFdDfYypJUuIijKkPOopzZVTtvvDdVjJhWeEwHMxXbNNCceEnvVTFftQqnPpBmwWWlLwSkZzbBKujJUsvTtDdxiIXxTtWwmYVvyXxDdMSFfFftDiIqEetTMpPYqQymxXOCcokKpPAaPpIWwaGprkKRtTPgLlIiATDWwQqvSsKkGgZzZyYoNmMHGgZJjzbLlSHhsXxBVsSwWNFfhqQHnnNjJtTtTrdhHDgGyYJjQqlLYHhInNwfFbBEkKeWllFYyfLamMxXhHALyYXctTCTtNmPpMIoObBiSsriIrRRhHgGPpTtogteEoOptTPdUuDTGpVvCccChHPxXPpRLlwWrPpZeXTTttzZZzKkxExhHwYyWJjkKaAfxXpTtzZBbfFqQFfRlaALrIiGRrgjPUupPiVfFvIJicCVvIjYoWwOhFfPwWVQqOozZvgkBMwWVvpPerGgReEmMaxhHhYyPpHXtTmMAaGgBUSsubBeOoEUuDdYFfyzNnzZbBjqQJgGuGgUjJoOeCcEZlLjJJjRrGgwCsStTcWQqIiIuUiPpYyUVoOvpkixyYTXmMxhHrRAamMmwWaAMtpPJjiIIiwfFWuXxjJKkUugGFqQuKkUxXlnaANZzXbBxhmdDMHGbBGggLHYyhuUnNfVvDdiKkqQMmICcHhRrHhsSskSuUkKgGgGsmMOVBbqQEezZvVjJQqvmoXxOMXrRxHhsSyTtuzZJjTtPpUroOROHhMmoRrYmMvVlLRpPOIAaieEAaQqXxnPpYyGgNpYyRrWdIiDGgwVvMmPwWYykrRKvVwPpWnZzXkeEKZzxZzvTtVkoOKsScrRrnNFfEeDdRCaAHrRZzhWOowneEuUQpGwWpPwWfSshHFoOebBEEeGcOoCgGGgeEguUjWwLlJRrngGNumEeMEeXxTtUahHAgEePkXxVvKAnvVTtIiIiZzPVveSsEpvyYvVVBbgGNHhRsSlLlLZztTrPNntSsSrRsBbmMCvVcUunNWwkKzZUuwDDddWPpXRrfNneEqGdDgFfQQVuUvqJjKkLlaAFZrRLCcEeYyIiBbwWlzZBdiIDShHlwWnNMmDdLlGgtvVTfSIisYyFKkmiIoOMLCbBcQCcSDdsiIqiIZzBbXHhxHhBLlbHpPzxXZBbUyYFfOhHobuUruJjURBFzZrRWPpwWEeiIwoYDdyOfrRYyYBbsgGeESiIxXyukKxXHbBvtTVdFfDhiIAVvzZhnNjJyYnEzTtZeasSZzqQfFNnAzZTjJtyYIiaFfABbzsSbOoBZpPMmGrRuSsUoUbBuEeOVvDdgKfFGgJjOoTtDdlLkpTtuPsSpUZzkiTtzoyYOxXXhFfelLIiHuUhEHkKDCcdPCcpfvVWYeEyKjJkSXSmMsxXxcCoORrLlswdDFGgUBbuxNRJaAMjtTJgGrRxXdDZcCzqbBQmcCxXLhcCwWFPvVpfHlQqTtSzZsVvBbwWyYGLlgywWFfAPpaEbCcBKfqkKQFHhkexTlLhHtLlhyYHjJXxJztgGTjJRpPAayYrZjGgVOodDZzvrHhBbZzQqRvVgAagcCGZzgKaupPUtxXeETOovVaAiIbBKkSsGgyYPcCNBboOnOgGIbBioUuPgkKyGgsRrhHgGlLGgSWcCCcnNwEecCYBbOScCsRdDnNroIiLlFqQKkxXfDdGUuorRiIOzZpdDLwWlBUuxMmXtTbzZoOTwWtXxmZzACcaKkdDBJjbMZzSsWmLlMTttTcCnNwpGgqQJjDdUuIsSicrRgGCqQyYcxXiIxHhXdCcDdraAOoRoOGgOoVfXxlLFRrvDUuEVvoOAawWRjJxXIEeiLlMmQqrdDaAXNnENneUrRMmOrRouUuqQsBbSXnNGgxnNlLxinNDdDrnNZJjAazMmqhTtHPpZzEecCbBdDQHhhHmMuUbhHLlBRNEenmFfTtaAoOQqlLIiMiIaAKkPpszIiZdDSpPdDnIizZtVfqQDdutTUOMmoFCcPAapCcFffFbBBbjHhJmNnMMaArRFfkJjKmxXeDdyYXGgsSxXxGMhSsuUHWwmgEeBbTtRrEajJExXeATSstRrtEeRDhHWwJjAaYyYymMHYyhUjhHJUSsYyuxXumMQNnoOmIiMIixYytdmMtHhTCpPcDLlNncCkWwKaAsSLBbMBbVvmURraAuCGgyYcmqnNQRrMIMmIQqhxXAaXxseESsSHlLiVviDdBiIblQqfFrkKNnRrxqpHhPQEeXrFNnfGMmgPpGgRVvABpaAgeEGPbxEeXazZEeRTtTNKkYyIibwWBEOoembBxaAoOMmXfFRrMpPtfpPmMFyyYYPoOpgpqQPGOMmoDdtTNneETNHhnkKEFHhZzZziUuIHibBIhpPfpPHhWEeJqQNnjwCceBbQqaAdDQvCcVpkiIiYyIfFVOovdDWwKcCSssSqQNnmMyYvVPSPpsIkKibEYyeAMJjxXahVvHkKRmoOQqMzZrAmtThHnNbaUuMmARrSsBhHGxXKVvWjJwaArRkglLAPpaqaAbBvINZgGzCcXxnVvOQOoqIOgGgGoiotTiaOoAaNnUNnuYyukKqQUfFGmMTtAsSaGgglRrPpLRrTAaNntAkEeKMGgzZmreWwpPERgGDdCcEDdeUuTFwWDnNgGGVvgdbBUJjOouaAQqNnNeEsSnpPnNfquUGfFsSgHhpPQtHZzhzZNnNnUuVnNlLBbNnQnyYaANSsqhHRGgDdrIibBqQzZNnUuEeXxsSMXxNnmaMQqluULyYNYGgyFfKzZknYfFGgSsMmfxXFBbyCchHNncCsSFfINniImMtMmDdTiJuUAyYqQfuUftTFFaokKOEeMQhHKLlkqnNmjykKYsShYyHAeiIEaBbRKktTxXtTrPGgpTppPPpPNnilLLnNlaAbLlwWHhBIYytbBORGgEWwerKGgdGgDkRruzZUoufFaGgAXNnyYAayvGgzZvVwWhJjXxQdDxXqHyYVYnqQNGgGgfFokKcXxCOxUuxHhXMTteExXXxmOoxsSXxELkxXKliIeKiIxXSlLskhHfFXhXEeFfxuUTtfFYyWwXDdxyYHxXnBbqQGgVbiqmMTtAaQmMIBpPbmMHhJjQrRNnlkKLqBUuvogGxXLxXYyIuUYxXyYyilhAEeaHbBHhQqoOMmyYJjZcCeEmYyMzuUFfynNhHIBFfbiiILlUucCdDAKkdBbwWeEDEejLlJgjwWJGajTtSsJtEeTRrdDIiZzJsVvDdSjvVRrFfKqOoQoOkrRY diff --git a/05/input_sample.txt b/05/input_sample.txt new file mode 100644 index 0000000..8637b35 --- /dev/null +++ b/05/input_sample.txt @@ -0,0 +1 @@ +dabAcCaCBAcCcaDA diff --git a/05/solve01.py b/05/solve01.py new file mode 100755 index 0000000..d14f5fd --- /dev/null +++ b/05/solve01.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +def read_input(): + with open('input.txt', 'r') as f: + data = f.read().splitlines() + return data[0] + +def find_longest_match(polymer): + result = 1 + for x in range(len(polymer)-1): + if abs(ord(polymer[x]) - ord(polymer[x+1])) != 32: + break + result += 1 + return result + + +polymer = read_input() +parsing_pos = 0 + +while parsing_pos < len(polymer): + lm = find_longest_match(polymer[parsing_pos:]) + if lm < 2: + parsing_pos += 1 + continue + +# print("found({}, {}) : {}".format(parsing_pos, lm, polymer[parsing_pos:parsing_pos+lm])) + + lm = 2 + if parsing_pos == 0: + polymer = polymer[lm:] + else: + polymer = polymer[:parsing_pos] + polymer[lm+parsing_pos:] + parsing_pos -= 1 + +# print("new polymer: {}".format(polymer)) + +print(len(polymer)) diff --git a/05/solve02.py b/05/solve02.py new file mode 100755 index 0000000..4d2e8e6 --- /dev/null +++ b/05/solve02.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +def read_input(): + with open('input.txt', 'r') as f: + data = f.read().splitlines() + return data[0] + +def find_longest_match(polymer): + result = 1 + for x in range(len(polymer)-1): + if abs(ord(polymer[x]) - ord(polymer[x+1])) != 32: + break + result += 1 + return result + + +def retract_polymer(polymer): + parsing_pos = 0 + + while parsing_pos < len(polymer): + lm = find_longest_match(polymer[parsing_pos:]) + if lm < 2: + parsing_pos += 1 + continue + + lm = 2 + if parsing_pos == 0: + polymer = polymer[lm:] + else: + polymer = polymer[:parsing_pos] + polymer[lm+parsing_pos:] + parsing_pos -= 1 + + return len(polymer) + +l = [] +for c in range(ord('a'),ord('z')+1): + p = read_input() + if chr(c) not in p: + continue + p = p.replace(chr(c), '') + p = p.replace(chr(c-32), '') + print("removing characher: {}".format(chr(c))) + l.append(retract_polymer(p)) + +print(min(l)) diff --git a/06/.solve02.py.swp b/06/.solve02.py.swp new file mode 100644 index 0000000..926c4fd Binary files /dev/null and b/06/.solve02.py.swp differ diff --git a/06/input.txt b/06/input.txt new file mode 100644 index 0000000..b00971d --- /dev/null +++ b/06/input.txt @@ -0,0 +1,50 @@ +353, 177 +233, 332 +178, 231 +351, 221 +309, 151 +105, 289 +91, 236 +321, 206 +156, 146 +94, 82 +81, 114 +182, 122 +81, 153 +319, 312 +334, 212 +275, 93 +224, 355 +347, 94 +209, 65 +118, 172 +113, 122 +182, 320 +191, 178 +99, 70 +260, 184 +266, 119 +177, 178 +313, 209 +61, 285 +155, 218 +354, 198 +274, 53 +225, 138 +228, 342 +187, 165 +226, 262 +143, 150 +124, 159 +325, 210 +163, 176 +326, 91 +170, 193 +84, 265 +199, 248 +107, 356 +45, 340 +277, 173 +286, 44 +242, 150 +120, 230 diff --git a/06/input_sample.txt b/06/input_sample.txt new file mode 100644 index 0000000..95d160a --- /dev/null +++ b/06/input_sample.txt @@ -0,0 +1,6 @@ +1, 1 +1, 6 +8, 3 +3, 4 +5, 5 +8, 9 diff --git a/06/solve01.py b/06/solve01.py new file mode 100755 index 0000000..dbfcadb --- /dev/null +++ b/06/solve01.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + + +def read_input(): + result = [] + with open('input.txt', 'r') as f: + for line in f: + result.append([ int(x) for x in line.split(', ')]) + return result + +MARGIN=1 +coord = read_input() +coord_min = [ min([x[0] for x in coord]), min([x[1] for x in coord]) ] +coord_max = [ max([x[0] for x in coord]), max([x[1] for x in coord]) ] + +finite = [True] * len(coord) +area_size = [0] * len(coord) + + +for x in range(coord_min[0]-MARGIN, coord_max[0]+MARGIN+1): + for y in range(coord_min[1]-MARGIN, coord_max[1]+MARGIN+1): + border_x = False + border_y = False + if x in (coord_min[0]-MARGIN, coord_max[0]+MARGIN): + border_x = True + if y in (coord_min[1]-MARGIN, coord_max[1]+MARGIN): + border_y = True + + best = (None, None) #loc, distance + for loc_i, loc in enumerate(coord): + d = abs(x - loc[0]) + abs(y - loc[1]) + if best[1] is None: + best = (loc_i, d) + continue + if best[1] > d: + best = (loc_i, d) + continue + if best[1] == d: + best = (None, d) + continue + + if best[0] is None: + continue + + if border_x or border_y: + finite[best[0]] = False + area_size[best[0]] += 1 + + +print(max([v for k,v in enumerate(area_size) if finite[k]])) diff --git a/06/solve02.py b/06/solve02.py new file mode 100755 index 0000000..ac6174c --- /dev/null +++ b/06/solve02.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + + +def read_input(): + result = [] + with open('input.txt', 'r') as f: + for line in f: + result.append([ int(x) for x in line.split(', ')]) + return result + +MARGIN=10000 +coord = read_input() +coord_min = [ min([x[0] for x in coord]), min([x[1] for x in coord]) ] +coord_max = [ max([x[0] for x in coord]), max([x[1] for x in coord]) ] + +area_size = 0 +for x in range(coord_max[0]-MARGIN-1, coord_min[0]+MARGIN+1): + for y in range(coord_max[1]-MARGIN-1, coord_min[1]+MARGIN+1): + + d_total = 0 + for loc in coord: + if d_total >= MARGIN: + break + d_total = d_total + abs(x - loc[0]) + abs(y - loc[1]) + else: + if d_total < MARGIN: + area_size += 1 + +print(area_size) diff --git a/07/input.txt b/07/input.txt new file mode 100644 index 0000000..d42501e --- /dev/null +++ b/07/input.txt @@ -0,0 +1,101 @@ +Step S must be finished before step B can begin. +Step B must be finished before step Y can begin. +Step R must be finished before step E can begin. +Step H must be finished before step M can begin. +Step C must be finished before step F can begin. +Step K must be finished before step A can begin. +Step V must be finished before step W can begin. +Step W must be finished before step L can begin. +Step J must be finished before step L can begin. +Step Q must be finished before step A can begin. +Step U must be finished before step L can begin. +Step Y must be finished before step M can begin. +Step T must be finished before step F can begin. +Step D must be finished before step A can begin. +Step I must be finished before step M can begin. +Step O must be finished before step P can begin. +Step A must be finished before step L can begin. +Step P must be finished before step N can begin. +Step X must be finished before step Z can begin. +Step G must be finished before step N can begin. +Step M must be finished before step F can begin. +Step N must be finished before step L can begin. +Step F must be finished before step Z can begin. +Step Z must be finished before step E can begin. +Step E must be finished before step L can begin. +Step O must be finished before step X can begin. +Step B must be finished before step V can begin. +Step H must be finished before step Q can begin. +Step T must be finished before step M can begin. +Step A must be finished before step G can begin. +Step R must be finished before step H can begin. +Step S must be finished before step C can begin. +Step N must be finished before step Z can begin. +Step Z must be finished before step L can begin. +Step Q must be finished before step Z can begin. +Step R must be finished before step G can begin. +Step P must be finished before step Z can begin. +Step U must be finished before step M can begin. +Step W must be finished before step D can begin. +Step F must be finished before step L can begin. +Step D must be finished before step P can begin. +Step I must be finished before step E can begin. +Step M must be finished before step E can begin. +Step H must be finished before step N can begin. +Step F must be finished before step E can begin. +Step D must be finished before step L can begin. +Step C must be finished before step E can begin. +Step H must be finished before step Z can begin. +Step W must be finished before step Q can begin. +Step X must be finished before step E can begin. +Step G must be finished before step M can begin. +Step X must be finished before step M can begin. +Step Y must be finished before step P can begin. +Step S must be finished before step I can begin. +Step P must be finished before step X can begin. +Step S must be finished before step T can begin. +Step I must be finished before step N can begin. +Step P must be finished before step L can begin. +Step C must be finished before step X can begin. +Step I must be finished before step G can begin. +Step O must be finished before step F can begin. +Step I must be finished before step X can begin. +Step C must be finished before step Z can begin. +Step B must be finished before step K can begin. +Step T must be finished before step P can begin. +Step Q must be finished before step X can begin. +Step M must be finished before step N can begin. +Step H must be finished before step O can begin. +Step Q must be finished before step M can begin. +Step U must be finished before step F can begin. +Step Y must be finished before step O can begin. +Step D must be finished before step O can begin. +Step R must be finished before step T can begin. +Step A must be finished before step E can begin. +Step A must be finished before step M can begin. +Step C must be finished before step N can begin. +Step G must be finished before step E can begin. +Step C must be finished before step Y can begin. +Step A must be finished before step Z can begin. +Step S must be finished before step X can begin. +Step V must be finished before step Z can begin. +Step Q must be finished before step I can begin. +Step P must be finished before step E can begin. +Step D must be finished before step F can begin. +Step M must be finished before step Z can begin. +Step U must be finished before step N can begin. +Step Q must be finished before step L can begin. +Step O must be finished before step Z can begin. +Step N must be finished before step E can begin. +Step S must be finished before step W can begin. +Step S must be finished before step O can begin. +Step U must be finished before step T can begin. +Step A must be finished before step P can begin. +Step J must be finished before step I can begin. +Step A must be finished before step F can begin. +Step U must be finished before step D can begin. +Step W must be finished before step X can begin. +Step O must be finished before step L can begin. +Step J must be finished before step D can begin. +Step R must be finished before step Z can begin. +Step O must be finished before step N can begin. diff --git a/07/input_sample.txt b/07/input_sample.txt new file mode 100644 index 0000000..9ab25bf --- /dev/null +++ b/07/input_sample.txt @@ -0,0 +1,7 @@ +Step C must be finished before step A can begin. +Step C must be finished before step F can begin. +Step A must be finished before step B can begin. +Step A must be finished before step D can begin. +Step B must be finished before step E can begin. +Step D must be finished before step E can begin. +Step F must be finished before step E can begin. diff --git a/07/solve01.py b/07/solve01.py new file mode 100755 index 0000000..2b0328a --- /dev/null +++ b/07/solve01.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +import re + +RE_LINE = re.compile('^Step (.*) must be finished before step (.*) can begin.') +tree = dict() + +def read_input(): + with open('input.txt', 'r') as f: + for line in f: + yield line + +def add_dependency(a, b): + if a not in tree: + tree[a] = { + 'node': a, + 'parent': '', + 'child': '', + } + if b not in tree: + tree[b] = { + 'node': b, + 'parent': '', + 'child': '', + } + tree[a]['child'] += b + tree[b]['parent'] += a + +for l in read_input(): + m = RE_LINE.match(l) + if m is None: + raise Exception('unpaseable line') + add_dependency(m.group(1), m.group(2)) + +result = [] +while len(tree): + root = min([ n['node'] for n in tree.values() if len(n['parent']) == 0]) + for c in tree[root]['child']: + tree[c]['parent'] = tree[c]['parent'].replace(root, "") + del tree[root] + result.append(root) + + +print(''.join(result)) diff --git a/07/solve02.py b/07/solve02.py new file mode 100755 index 0000000..8cd1f8d --- /dev/null +++ b/07/solve02.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +import re + +RE_LINE = re.compile('^Step (.*) must be finished before step (.*) can begin.') +WORKERS=5 +JOB_TIME=60 +tree = dict() + +def read_input(): + with open('input.txt', 'r') as f: + for line in f: + yield line + +def add_dependency(a, b): + if a not in tree: + tree[a] = { + 'node': a, + 'parent': '', + 'child': '', + 'time': JOB_TIME+ord(a)-64 + } + if b not in tree: + tree[b] = { + 'node': b, + 'parent': '', + 'child': '', + 'time': JOB_TIME+ord(b)-64 + } + tree[a]['child'] += b + tree[b]['parent'] += a + +for l in read_input(): + m = RE_LINE.match(l) + if m is None: + raise Exception('unpaseable line') + add_dependency(m.group(1), m.group(2)) + +worker = [[0, None]] * WORKERS # time and job +total_time = 0 +while len(tree): + # finish worker job + try: + min_time = min([x[0] for x in worker if x[0]>0]) + total_time = min_time + except ValueError: + min_time = -1 + min_workers = [ k for k,v in enumerate(worker) if v[0] == min_time] + for w in min_workers: + job = worker[w][1] + if job is None: + continue + for c in tree[job]['child']: + tree[c]['parent'] = tree[c]['parent'].replace(job, "") + del tree[job] + worker[w] = [0, None] + print('finish job for {}({})'.format(w, job)) + + # add new job + roots = sorted([ n['node'] for n in tree.values() if len(n['parent']) == 0 and n['time']>0]) + empty_w = [ k for k,v in enumerate(worker) if v[1] is None] + for w in empty_w: + if len(roots) == 0: + break + job = roots.pop(0) + worker[w] = (total_time+tree[job]['time'], job) + tree[job]['time'] = 0 + print('added job for {}({})'.format(w, job)) + + +print(total_time)