### AoC Day 4: Repose Record

#### Ryan Palo on December 04, 2018

Day 4 is here! Our first puzzle launched on a weeknight. Hopefully, we're able to keep up this pace! Today's challenge makes me feel very much... [Read Full]

Python!

May refactor later, but this problem was a little less fun for me than other ones so far, to be honest.

part 1

``````import re
from collections import Counter

with open('input.txt', 'r') as f:
data = []
for line in f:
date = line[line.find("[")+1:line.find("]")]
action = line.split("] ")[1].strip()
data.append((date, action,))
data = sorted(data, key=lambda i: i[0])

guards = {}
for time, action in data:
time = int(time[-2:])
if "Guard" in action:
_id = re.findall(r'\d+', action)[0]
if not _id in guards:
guards[_id] = {'length': 0, 'minutes': []}
elif action == "falls asleep":
start = time
else:
guards[_id]['length'] += time - start
guards[_id]['minutes'] += list(range(start, time))

sleep_longest = max(guards.items(),key=lambda guard: guard[1]['length'])
minutes = sleep_longest[1]['minutes']
print(Counter(minutes).most_common(1)[0][0] * int(sleep_longest[0]))
``````

part 2

``````import re
from collections import Counter

with open('input.txt', 'r') as f:
data = []
for line in f:
date = line[line.find("[")+1:line.find("]")]
action = line.split("] ")[1].strip()
data.append((date, action,))
data = sorted(data, key=lambda i: i[0])

guards = {}
for time, action in data:
time = int(time[-2:])
if "Guard" in action:
_id = re.findall(r'\d+', action)[0]
if not _id in guards:
guards[_id] = []
elif action == "falls asleep":
start = time
else:
guards[_id] += list(range(start, time))

max_count = 0
solution = 0
for guard, minutes in guards.items():
if minutes:
most_frequent = Counter(minutes).most_common(1)[0]
if most_frequent[1] > max_count:
max_count = most_frequent[1]
solution = int(guard) * most_frequent[0]
print(solution)
``````

Agree that this one was less fun, and I kind of hate my Python solution, which is much muddier than yours. I don't know that I have the energy to try to do this in Go.

Yeah, I like the algorithm-y ones, this one was more string parsing I think!

It was a complicated description though, I had a lot of problems parsing what I was supposed to be finding.

TOTALLY -- I only figured it out once I looked at the input. The graph actually totally threw me off.

``````from collections import defaultdict

def main():
guard_sleep_dict = calculate_guard_sleep_dict()
part_one(guard_sleep_dict)
part_two(guard_sleep_dict)

def calculate_guard_sleep_dict():
with open('input.txt', 'r') as data:

sorted_data = sorted(data)  # This will work too... No extra key required

guard_sleep_dict = defaultdict(lambda: [0 for x in range(60)])
current_guard = -1
start_sleeping = -1
for line in sorted_data:
if line[25] == "#":
current_guard = line.split()[3]
elif line[25] == "a":
start_sleeping = int(line[15:17])
else:  # "wakes up"
end_sleeping = int(line[15:17])
for x in range(start_sleeping, end_sleeping):
guard_sleep_dict[current_guard][x] += 1

return guard_sleep_dict

def part_one(guard_sleep_dict):
guard = sorted(guard_sleep_dict.keys(), key=lambda g: -sum(guard_sleep_dict[g]))[0]

gh = guard_sleep_dict[guard]
minute = gh.index(max(gh))
print int(guard[1:]) * minute

def part_two(guard_sleep_dict):
guard = sorted(guard_sleep_dict.keys(), key=lambda g: -max(guard_sleep_dict[g]))[0]
gh = guard_sleep_dict[guard]
minute = gh.index(max(gh))
print int(guard[1:]) * minute

if __name__ == '__main__':
main()
``````

First missunderstood the task, so I wasted my whole time before university for the wrong solution... Fortunately I had some time after the first seminar to fix my solution.

Then found out that I can just call sorted and sort the data and I don't need any extra key for this. This made solving the puzzle much easier.

I used the same approach, but I really like the tools you have for searching the structure. The Clojure ones work, but were much more manual, making the code a little more clunky.

Did that yesterday! Elegantly solved exactly the wrong problem, had to go back and re-read the whole page to figure out what I was doing wrong. Devastating.

Yeah it is just super frustrating... Especially if you notice then that you have to move on to do other things and will loose expensive points on your private leaderboards 🙈
Tomorrow I will read the task at least twice before I start typing.

Damn life, getting in the way of AoC. The very nerve.

PHP

Had to brush up on the difference between usort, uasort, and uksort for this one, ahaha.

Part 1:

``````<?php
\$list = file_get_contents(\$argv[1]);
\$records = explode("\n", trim(\$list));
\$currentguard = null;
\$lastminute = 0;
\$awake = true;
\$guardtotals = array();

usort(\$records, function(\$a, \$b) {
preg_match('/\[([0-9]{4})\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2})\]/', \$a, \$atimes);
preg_match('/\[([0-9]{4})\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2})\]/', \$b, \$btimes);
if (intval(\$atimes[1].\$atimes[2].\$atimes[3].\$atimes[4].\$atimes[5]) == intval(\$btimes[1].\$btimes[2].\$btimes[3].\$btimes[4].\$btimes[5])) {
return 0;
}
return (intval(\$atimes[1].\$atimes[2].\$atimes[3].\$atimes[4].\$atimes[5]) < intval(\$btimes[1].\$btimes[2].\$btimes[3].\$btimes[4].\$btimes[5])) ? -1 : 1;
});

foreach (\$records as \$record) {
preg_match('/\[[0-9]{4}\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2})\]/', \$record, \$timestamps);
preg_match('/Guard #([0-9]+)/', \$record, \$guard);
if (count(\$guard) > 0) {
if (!\$awake && \$currentguard) {
\$timeasleep = 60 - \$lastminute;
\$guardtotals[\$currentguard]['asleep'] += \$timeasleep;
\$sleep = array_slice(\$guardtotals[\$currentguard]['minutes'], \$lastminute, \$timeasleep);
\$sleep = array_map(function(\$x) {
return \$x+1;
}, \$sleep);
array_splice(\$guardtotals[\$currentguard]['minutes'], \$lastminute, \$timeasleep, \$sleep);
\$lastminute = 0;
}
\$currentguard = intval(\$guard[1]);
\$awake = true;
if (!array_key_exists(\$currentguard, \$guardtotals)) {
\$guardtotals[\$currentguard] = array(
'asleep' => 0,
'minutes' => array_fill(0, 60, 0)
);
}
} elseif (strpos(\$record, 'falls asleep')) {
\$awake = false;
\$lastminute = intval(\$timestamps[4]);
} elseif (strpos(\$record, 'wakes up')) {
if (\$currentguard) {
\$timeasleep = intval(\$timestamps[4]) - \$lastminute;
\$guardtotals[\$currentguard]['asleep'] += \$timeasleep;
\$sleep = array_slice(\$guardtotals[\$currentguard]['minutes'], \$lastminute, \$timeasleep);
\$sleep = array_map(function(\$x) {
return \$x+1;
}, \$sleep);
array_splice(\$guardtotals[\$currentguard]['minutes'], \$lastminute, \$timeasleep, \$sleep);
\$lastminute = intval(\$timestamps[4]);
\$awake = true;
}
}
}
uasort(\$guardtotals, function(\$a, \$b) {
if (\$a['asleep'] == \$b['asleep']) {
return 0;
}
return (\$a['asleep'] < \$b['asleep']) ? 1 : -1;
});
\$chosenguard = array_keys(\$guardtotals)[0];
\$chosenminute = array_search(max(\$guardtotals[\$chosenguard]['minutes']), \$guardtotals[\$chosenguard]['minutes']);
echo \$chosenguard*\$chosenminute;
die(1);
``````

Part 2:

``````<?php
\$list = file_get_contents(\$argv[1]);
\$records = explode("\n", trim(\$list));
\$currentguard = null;
\$lastminute = 0;
\$awake = true;
\$guardtotals = array();

usort(\$records, function(\$a, \$b) {
preg_match('/\[([0-9]{4})\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2})\]/', \$a, \$atimes);
preg_match('/\[([0-9]{4})\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2})\]/', \$b, \$btimes);
if (intval(\$atimes[1].\$atimes[2].\$atimes[3].\$atimes[4].\$atimes[5]) == intval(\$btimes[1].\$btimes[2].\$btimes[3].\$btimes[4].\$btimes[5])) {
return 0;
}
return (intval(\$atimes[1].\$atimes[2].\$atimes[3].\$atimes[4].\$atimes[5]) < intval(\$btimes[1].\$btimes[2].\$btimes[3].\$btimes[4].\$btimes[5])) ? -1 : 1;
});

foreach (\$records as \$record) {
preg_match('/\[[0-9]{4}\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2})\]/', \$record, \$timestamps);
preg_match('/Guard #([0-9]+)/', \$record, \$guard);
if (count(\$guard) > 0) {
if (!\$awake && \$currentguard) {
\$timeasleep = 60 - \$lastminute;
\$guardtotals[\$currentguard]['asleep'] += \$timeasleep;
\$sleep = array_slice(\$guardtotals[\$currentguard]['minutes'], \$lastminute, \$timeasleep);
\$sleep = array_map(function(\$x) {
return \$x+1;
}, \$sleep);
array_splice(\$guardtotals[\$currentguard]['minutes'], \$lastminute, \$timeasleep, \$sleep);
\$lastminute = 0;
}
\$currentguard = intval(\$guard[1]);
\$awake = true;
if (!array_key_exists(\$currentguard, \$guardtotals)) {
\$guardtotals[\$currentguard] = array(
'asleep' => 0,
'minutes' => array_fill(0, 60, 0)
);
}
} elseif (strpos(\$record, 'falls asleep')) {
\$awake = false;
\$lastminute = intval(\$timestamps[4]);
} elseif (strpos(\$record, 'wakes up')) {
if (\$currentguard) {
\$timeasleep = intval(\$timestamps[4]) - \$lastminute;
\$guardtotals[\$currentguard]['asleep'] += \$timeasleep;
\$sleep = array_slice(\$guardtotals[\$currentguard]['minutes'], \$lastminute, \$timeasleep);
\$sleep = array_map(function(\$x) {
return \$x+1;
}, \$sleep);
array_splice(\$guardtotals[\$currentguard]['minutes'], \$lastminute, \$timeasleep, \$sleep);
\$lastminute = intval(\$timestamps[4]);
\$awake = true;
}
}
}
\$maximums = array_map(function(\$z) {
return max(\$z['minutes']);
}, \$guardtotals);
uasort(\$maximums, function(\$a, \$b) {
if (\$a == \$b) {
return 0;
}
return (\$a < \$b) ? 1 : -1;
});
\$chosenguard = array_keys(\$maximums)[0];
\$chosenminute = array_search(\$maximums[\$chosenguard], \$guardtotals[\$chosenguard]['minutes']);
echo \$chosenguard*\$chosenminute;
die(1);
``````

UKSort works the same, but is just more polite and has a slight accent, right? :]

Anybody feel like this today?

Indeed, it was the longest by far so far. The challenge was posted at 9pm, PST time. I started about 9:30pm. I went to bed around midnight. Still worth it :)

Timezones really matter if you're trying to get a good score (which is one reason why I'm not trying). I really feel for the Europeans who want to compete.

Yeah, it's possible for me to change the leaderboard to order based on number of stars. It still breaks ties based on who got the most recent star sooner, but it would be a little bit less demoralizing. Does that seem like a good idea?

Also, while it may seem that it's mighty convenient that I decide to make the leaderboard more forgiving on the first day that I miss a 9PM start, that honestly wasn't why I'm thinking about this. It just seems like more fun if there's not a difference of 400 points between 1st place and last place. :)

I totally support this -- keeps the staying up to 1 AM pressure low.

Done and done!

The first part made me think a little about the data structure, so I decided to create a map of the guard ID to the guard's times, where the times is a map of the minute to the number of times that the guard was asleep in that minute.

Fortunately, the date/time format is year/month/day/hour/minute, which can be sorted alphanumerically, and once that's done all sleep and wake events occur in pairs together.

``````(def build-table
[input-file]
(loop [[line & xlines] (sort (lines input-file)) guard 0 table {}]
(if-not line
table
(if (= "Guard" (subs line 19 24))
(recur xlines (-> (subs line 26) (split #" ") first as-long) table)
(let [sleep (as-long (subs line 15 17))
wake (as-long (subs (first xlines) 15 17))
table' (reduce (fn [t minute]
(update-in t [guard minute] #(if % (inc %) 1)))
table (range sleep wake))]
(recur (rest xlines) guard table'))))))
``````

Given the fixed-width, it seemed easier to substring out the bits I was looking for.

Now that I had this table, I just needed to search through it for the bits I was looking for. After trying to pull out a key/value entry from a map for the largest value, I decided to create a helper function that I could send to `reduce` which let me select the "largest" value, using an arbitrary function on the value in order to compare:

``````(defn max-finder
[vfn]
(fn [[_ mv :as mkv] [_ v :as kv]] (if (> (vfn v) (vfn mv)) kv mkv)))
``````

Later on, someone pointed out that Clojure already has the function `max-key` which finds the key for the largest value, but if you want to look for a non-numeric value then you need to update the entries of the map. That meant that I ended up with a lot more code, and I don't think it was as elegant.

Anyway, now that I was reading the table and had my helper function, here is the first part:

``````(defn star
[input-file]
(let [table (build-table input-file)
[guard times] (reduce (max-finder count) [0 []] table)
[max-time _] (reduce (max-finder identity) [0 0] times)]
(* guard max-time)))
``````

Part 2 was similar. This time I created a temporary var to hold the function that `(max-finder identity)` returns, so that the `map` function doesn't keep calling it unnecessarily:

``````(defn star2
[input-file]
(let [table (build-table input-file)
ident-finder (max-finder identity)
guards-maxes (map (fn [[g tm]] [g (reduce ident-finder [0 0] tm)]) table)
[guard [minute _]] (reduce (max-finder second) [0 [0 0]] guards-maxes)]
(* guard minute)))
``````

I like how having the correct data structure meant that the final calculations could be encapsulated in just a couple of lines.

My Python solution, which I'm less than jazzed about. And I definitely have no interest in redoing it in Go today. I do not have the drive or energy. /shrug

``````def sort_log(log):
log = [line.split("]") for line in log]
log = sorted(log, key=lambda x: datetime.datetime.strptime(x[0], "[%Y-%m-%d %H:%M"))
return [line[0] + "]" + line[1] for line in log]

def tally_shift(current_guard, guards):
try:
previous_shift = current_guard.pop(0)
if previous_shift not in guards.keys():
guards[previous_shift] = dict((k, 0) for k in range(60))
except IndexError:
pass
while len(current_guard) > 0:
guard = guards[previous_shift]
range_start = int(current_guard.pop(0))
range_end = int(current_guard.pop(0))
for m in range(range_start, range_end):
guard[m] += 1
return guards

def process_shifts(entries):
guard_pattern = re.compile(r'^.*#(?P<guard_id>\d*)')
minute_pattern = re.compile(r'^.*:(?P<minute>\d{2})\]')
guards = {}
current_guard = []
entries = sort_log(entries)
for entry in entries:
if "begins shift" in entry:
guards = tally_shift(current_guard, guards)
current_guard = []
current_guard.append(guard_pattern.search(entry).group('guard_id'))
elif "falls asleep" in entry:
current_guard.append(minute_pattern.search(entry).group('minute'))
else:
current_guard.append(minute_pattern.search(entry).group('minute'))
return tally_shift(current_guard, guards)

def part_one(schedule):
most_minutes_slept = 0
minute_most_likely_asleep = 0
for k, v in process_shifts(schedule).items():
total_mins_asleep = sum(v.values())
minute_most_slept_through = max(v.values())
if total_mins_asleep >= most_minutes_slept:
most_minutes_slept = total_mins_asleep
minute_most_likely_asleep = [min for min, freq in v.items() if freq == minute_most_slept_through]

def part_two(schedule):
max_global_frequency = 0
for k, v in process_shifts(schedule).items():
max_freq = max(v.values())
if max_freq >= max_global_frequency:
max_global_frequency = max_freq
most_freq = [min for min, freq in v.items() if freq == max_freq][0]

``````

F#!
I found today the easiest thus far, but it ended up being the most verbose solution. Despite that I'm relatively pleased with it - it runs fast and I find it readable.

``````namespace Day4
open System.Text.RegularExpressions

module util =
let getContents fileName =

type LogEntry =
| NewGuard of System.DateTime * int
| Asleep of System.DateTime
| Awake of System.DateTime
| Nonsense

let recordRegex = @"^\[([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-3]{2}):([0-9]{2})] (.*)\$"

let (|FirstRegexGroup|_|) pattern input =
let m = Regex.Match(input,pattern)
if (m.Success) then Some m.Groups.[1].Value else None

let sortLog log = List.sortBy (fun el ->
match el with
| LogEntry.Asleep dt -> dt
| LogEntry.Awake dt -> dt
| LogEntry.NewGuard (dt, _) -> dt
| LogEntry.Nonsense -> new System.DateTime()) log

List.map (fun logEntry ->
let m = Regex.Match(logEntry, recordRegex)
if m.Success then
let dt =
new System.DateTime(
(m.Groups.[1].Value |> System.Convert.ToInt32),
(m.Groups.[2].Value |> System.Convert.ToInt32),
(m.Groups.[3].Value |> System.Convert.ToInt32),
(m.Groups.[4].Value |> System.Convert.ToInt32),
(m.Groups.[5].Value |> System.Convert.ToInt32),
0)

match m.Groups.[6].Value with
| "falls asleep" -> LogEntry.Asleep (dt)
| "wakes up" -> LogEntry.Awake (dt)
| FirstRegexGroup "Guard #([0-9]+) begins shift" badge -> LogEntry.NewGuard (dt, System.Convert.ToInt32 badge)
| _ -> LogEntry.Nonsense
else LogEntry.Nonsense) inputs
|> sortLog

let first (a, _, _) = a
let second (_, b, _) = b
let third (_, _, c) = c

type MinuteCounts = Map<int, int>

let getHighest minuteCounts =
Map.fold (fun s k v -> if v > snd s then (k, v) else s) (0, 0) minuteCounts

type SingleEntry =
{ TotalAsleep : int
MinuteCounts : MinuteCounts }
type SleepLog = Map<int, SingleEntry>

let tickMinute (mcs: MinuteCounts) m =
match (mcs.TryFind m) with
| Some x -> Map.add m (x + 1) mcs
| None -> Map.add m 1 mcs

let addRangeToLog sleep wake sleepLogEntry =
let timeAsleep = wake - sleep
let eachMinute = [ for i in sleep..wake - 1 do yield i ]
{ TotalAsleep = sleepLogEntry.TotalAsleep + timeAsleep;
MinuteCounts = List.fold tickMinute sleepLogEntry.MinuteCounts eachMinute }

let processLog log =
List.fold
(fun s el ->
match el with
| LogEntry.Awake dt ->
match (first s) with
match (second s) with
| Some sleepTime ->
let map: SleepLog = third s
let newMap =
| None -> Map.add badge (addRangeToLog sleepTime dt.Minute {TotalAsleep = 0; MinuteCounts = (new Map<int, int> (Seq.empty))}) map
(first s, None, newMap)
| None -> s // This branch indicates an error in the input - there was no "time asleep" stored for a "wakes up" entry
| None -> s // This branch indicates an error in the input - there was no active badge for a "wakes up" entry
| LogEntry.Asleep dt -> (first s, Some dt.Minute, third s)
| LogEntry.Nonsense -> s)
(None, None, new Map<int, SingleEntry> (Seq.empty)) // Active Badge, Minute Fell Asleep, SleepLog
log

let getSleepLog fileName =
getContents fileName |> scrapeLog |> processLog |> third

module part1 =
open util

let getLongestAsleep sleepLog =
sleepLog |> Map.fold (fun s k v -> if v.TotalAsleep > first s then (v.TotalAsleep, k, getHighest v.MinuteCounts) else s) (0, 0, (0, 0))

let execute fileName =
let res = getSleepLog fileName |> getLongestAsleep
(second res) * (fst (third res))

module part2 =
open util
let getMostFrequentAsleep sleepLog =
sleepLog |> Map.fold (fun s k (v: SingleEntry) ->
let h = getHighest v.MinuteCounts
if snd h >= snd (snd s) then
(k, h)
else s
) (0, (0, 0))

let execute fileName =
let res = getSleepLog fileName |> getMostFrequentAsleep
(fst res) * (fst (snd res))
``````

See Neil Gall's wonderful post for a more functional-paradigm approach. Kotlin not being pure-functional makes me lean into the procedural style more often than I'd like.

Anyway...

#### Part 1

I didn't read the problem properly. Some key things I missed:

• The input data is random.
• We only care about minutes.
• There's only ever one guard on duty (not a stack of sleeping and awake guards).

Fortunately, once I knew what I was supposed to be recording, it was just a simple matter of adding sleeping events to guards.

``````typealias Duration = Pair<LocalDateTime, LocalDateTime>

private val dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")

fun String.parseEntry() =
Regex("""\[(.*)] (.*)""").matchEntire(this)!!.groupValues.let {
LocalDateTime.parse(it[1], dateFormat) to it[2]
}

fun String.parseGuardId() =
Regex("""Guard #(\d+) begins shift""")
.matchEntire(this)!!
.groupValues[1]
.toInt()

fun Duration.minutes() = let { (start, end) ->
((end.toEpochSecond(UTC) - start.toEpochSecond(UTC)) / 60).toInt()
}

fun Duration.minuteRange() = let { (start, end) ->
start.minute until end.minute
}

private fun computeGuardSchedules(initial: List<Pair<LocalDateTime, String>>): List<Guard> {
val guards = mutableMapOf<Int, Guard>()
initial.sortedBy { it.first }.fold(-1) { onDuty, (ts, type) ->
val guard = when (type) {
"wakes up" -> guards[onDuty]?.awaken(ts)
"falls asleep" -> guards[onDuty]?.asleepen(ts)
else -> type.parseGuardId().let { gid ->
if (gid !in guards) {
guards[gid] = Guard(gid)
}
guards[gid]!!.ondutyen(ts)
}
}!!
guard.id
}
return guards.values.toList()
}

class Guard(val id: Int) {
private var lastStatusChange: LocalDateTime? = null
val sleepLog = mutableListOf<Duration>()

fun awaken(ts: LocalDateTime): Guard {
lastStatusChange = ts
return this
}

fun asleepen(ts: LocalDateTime): Guard {
lastStatusChange = ts
return this
}

fun ondutyen(ts: LocalDateTime): Guard {
lastStatusChange = ts
return this
}
}

val sleepiest = input.maxBy {
it.sleepLog.sumBy(Duration::minutes)
}!!

val minuteMostOftenAsleep = sleepiest.sleepLog
.flatMap(Duration::minuteRange)
.frequencies()
.maxBy { (_, v) -> v }!!.key

return sleepiest.id * minuteMostOftenAsleep
}

``````

#### Part 2

So, the thing that threw me here is that some guards don't fall asleep, leading `.maxBy` to return `null`. Otherwise, this was a fairly simple modification of the first part, just aggregating at different points. At this point, I'm wondering if Eric Wastl is experimenting with reversing the difficulties this year. This is two in a row where the heavy lifting gets done in part 1. We'll see when tomorrow's drops!

``````    fun answer2(input: List<Guard>) =
input.map {
it.id to (
it.sleepLog
.flatMap(Duration::minuteRange)
.frequencies()
.toList()
.sortedBy { (k, v) -> -v }
.firstOrNull()
)
}.sortedBy { (k, v) ->
-(v?.second ?: -10000)
}.first().let {
it.first * it.second!!.first
}
``````

and since I got bored waiting for some scans to complete, here's what my schedule looks like!

I should probably just pick the days that don't have guards!

``````                 000000000011111111112222222222333333333344444444445555555555
012345678901234567890123456789012345678901234567890123456789
1518-03-01  none ............................................................
1518-03-02  #587 ....zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.....zzzz...............
1518-03-03 #2113 ......................................................zz....
1518-03-04 #2699 .............zzzzzzzzzzzzzzzzzzzzzzzz...zzzzz...............
1518-03-05  #593 ..............zzzzzzzzzzzzzzzzzz............................
1518-03-06 #1543 ..............zz...........................zzzzzzz..........
1518-03-07 #2039 ....zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...zzzzzzzzzzzzz........
1518-03-08  #587 .................................................zz.........
1518-03-09 #1601 ...........zzzzzzz..............zzzzzzzzzzzzzzzzzzzzzz......
1518-03-10 #1553 ...................zzzzzzzzzzzzzzzzzzzzzzzzzzz..............
1518-03-11 #1433 .................zzzzzzzzzzzzzzzzzzz....zzzzzzzzzzzzzzz.....
1518-03-12 #2113 ..........zzzzzzzzzzzz........zzzzzzzzzzzzzzzzzzzzzz...z....
1518-03-13 #3121 ......zz.............................zzzzzzzz...............
1518-03-14 #1549 .......zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.......
1518-03-15  #587 .............................zzzz........................z..
1518-03-16 #1553 .........................................zzzzzzz.......zzzz.
1518-03-17  #587 .......................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...
1518-03-18 #1601 zzzzzzzzzzzzzzzzzzzzzzzzzzzzz...............................
1518-03-19 #1553 ...................................zzzzzz...zz....zzzzzzzz..
1518-03-20  #181 ......................zzzzzzzzzzzzzzzzzzzzz.................
1518-03-21 #1553 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz....zzzzzzzzzzzzzz.
1518-03-22 #1601 ...............................zzzzzzzzzzzzzzzzzzzzzzzzzzz..
1518-03-23  #229 ............................................zzzz............
1518-03-24 #1553 ................zzzzzzzzzzzzzz.............zzz.......zz.....
1518-03-25 #1549 .......................zzzzzzzzzzzzzzzzzzzzzzzzzzz...zz.....
1518-03-26 #1553 ................................................zzzzzzz.....
1518-03-27  #199 ................................................zzzzzz......
1518-03-28 #1549 ....................................zzzzzz........zzzzzzz...
1518-03-29 #1553 .....................zzzzzzzzzzzzzzzzzzzzzzzzzzz............
1518-03-30 #2699 ..............................................zzzzzz........
1518-03-31  #593 ................................zzzzz.......................
1518-04-01  none ............................................................
1518-04-02 #1597 ..........zzzzzzzzzzzz........zzzzzzzz......................
1518-04-03 #2699 .............................................zzz............
1518-04-04 #1489 ........................zzzzzzzz............................
1518-04-05 #1433 ..zzzzzzzzzzzzzzzzzzzz......................................
1518-04-06 #1549 ..................................zzzzzz...zzzz.............
1518-04-07 #1433 .............................zzzzzzzzzzzzzzzzzzzzzzzzzzzzz..
1518-04-08 #1601 .zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz................
1518-04-09  #199 .....................................................zz.....
1518-04-10  #587 ....................zzzzzzzzzzzzzzz.........................
1518-04-11  #587 ..................................zzzzzzzzzzz...............
1518-04-12 #1433 ...........................zzzzzzzzzzzzzzzzzzzzzzzzz........
1518-04-13 #1549 .........................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.....
1518-04-14 #3121 .........zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz................
1518-04-15  #587 ......................zzzzzzzzzzzzzzzzzzzzzzzzzzzz..........
1518-04-16 #1039 ...................................zzzzzzzzzzzzzzzzz........
1518-04-17 #1039 ..........zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz................
1518-04-18 #2927 ...................................zzzzzzzzzzzz...zzz....zz.
1518-04-19 #2113 .............zz.....zzzzzzzzzz.................zzzz.........
1518-04-20 #1601 ...zzzzzzzzzzzzzzzzzzzzz.................zzzzzzzzzzzzzzzzzz.
1518-04-21 #1433 ............zzzzzzzzzzz.....................................
1518-04-22 #1433 .....................................................zz.....
1518-04-23  #587 ...............zzzzzzzzzzzzzzzzzzzzzzzzzzzzz................
1518-04-24 #1597 ..............................zzzzz......zzzzzz.........z...
1518-04-25 #1549 ........................................zzzzzzzzzzzz....zz..
1518-04-26 #1489 ..............zzzzzzz..............zzzzzzzzzzzzz............
1518-04-27 #2699 ...............................................zzzzzzz......
1518-04-28 #2699 ....zzz.....................................zzzzzzzzzzzzz...
1518-04-29 #2113 .........zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz..
1518-04-30 #1597 ...zzzzzzzzz....zzzzzzzzzzzzzzzzzzzzz.......................
1518-05-01 #1433 ...................................................zzz......
1518-05-02 #3121 ........................zzzzz......zzz......................
1518-05-03 #1039 ...........................zzzzzzzzzzz......................
1518-05-04 #3121 ....................................................zzzzz...
1518-05-05  #199 zzzzzzzzzzzzzzzzzzzzzzzzz.......................zzzzzzzzzz..
1518-05-06  #229 ...............................................zzzzz........
1518-05-07 #3121 .............zzzzzzzzzzzzzz...........................zzzzz.
1518-05-08 #1489 ...............................zzzzzzzzzzzzzzzzzzzz.........
1518-05-09  #229 ........................................zzzzzzzzzzzzzzz.....
1518-05-10 #1549 ...........................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...
1518-05-11 #1549 ..............zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz....
1518-05-12 #1601 ...........................zzz......zzzzzzzzzzzzzzzzzzzzz...
1518-05-13 #2039 .............................zzzzzzzzzzzzz..................
1518-05-14  #181 ...........................zzz......................zzzzzz..
1518-05-15  #587 ...........................zzz...............zzz............
1518-05-16 #1543 ............................................zzzzzzzzzzzz....
1518-05-17 #1549 ..........................zzzzzzzzzzzzzzzzzzzzzzz...zzzzz...
1518-05-18 #1597 .zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.......................
1518-05-19 #1601 ...............zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz....zzzzzzzzz.
1518-05-20 #1543 ......zzzzzzzzzzzzzzz...............zzzzzz..............zzz.
1518-05-21 #2039 ..............zzzzzzzzzzzzzzzzzz............................
1518-05-22 #1553 .......................................zzzzzzzzzzzzzz...z...
1518-05-23  #587 .............zzzzzzzzzzzzzzzzz..............................
1518-05-24  #199 ..................................................z.........
1518-05-25 #1549 .....................................................zz.....
1518-05-26 #1597 ........zzzz..............zzzzzzzzzzzzzzzzzzzzzz............
1518-05-27 #2113 .....zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz......................
1518-05-28  #181 .......zz..................zzzzzzzzzzzzzzzzzzzz....z........
1518-05-29 #1597 .................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...
1518-05-30 #2927 ................zzzzzzzzzzzzzzz.......zzzzzzz...............
1518-05-31 #1489 ........zzzzzzzzzzzzzzzzzzzzzzzz....zzzzzzzzzzzzzz..........
1518-06-01  #587 ...............zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.
1518-06-02 #1549 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz........
1518-06-03 #1601 .................................zzzzzzzzzzzzz..............
1518-06-04 #1489 .........................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.
1518-06-05 #2699 .......................................zzzzzzzzzzzzzzz......
1518-06-06  #229 ...........................................zzzzz......z.....
1518-06-07  #181 ............zzzzzzzzz.....zzzzzzz...........................
1518-06-08  none ............................................................
1518-06-09  #587 .............................zzzzzzzzzzzzzzzzzzzzzzzzzzzzz..
1518-06-10 #1543 ..............zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...zzzzz......
1518-06-11 #1597 .........zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.............
1518-06-12 #1553 ..........zzzzzzzzzzzzzzzzzzzz.............zzzzzzz..........
1518-06-13 #1433 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz....zzzzzzzzzzzzz.....
1518-06-14 #1489 ..........................zz......zzzzzzzzzzzzzzzzzzzzzzzz..
1518-06-15 #1433 ...............zzzzzzzzzzzzzzzzzzz....zzzzzzzzzzzzzzzzzzz...
1518-06-16 #1597 .............zzzzzzzzzzzzzzzzzzzzzzzzzzzz...................
1518-06-17 #1597 .............................zzzzz...............z..........
1518-06-18  #239 .....zzzzzzzzzzzzzzzzzzzzz....................zzzz.......zz.
1518-06-19  none ............................................................
1518-06-20  #199 .............zzzzzzzzzzzzzzzzzzzzzz...............zzzzzzzz..
1518-06-21 #2699 ................................................zzz.....z...
1518-06-22 #1039 ..................zzzzzzzzzzzzzzzzzz........................
1518-06-23 #1549 ......zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz........
1518-06-24  #199 ...................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz........
1518-06-25 #2699 .............zzzzzzzzzzzzzzzzzzzzz....zzzzzzzzzzzzzzzz......
1518-06-26 #1597 ....................zzzzzzzzzzzzz...........................
1518-06-27 #1601 ...........................zzzzzzzzzzzzzzzzzz...............
1518-06-28  #587 .......zzzzzzzzzzzzzzz.............zzzzzzzzzzzzzzz..........
1518-06-29 #1549 .........................zzzzzzzzzzzzzzzzzzzzzz.............
1518-06-30 #2927 zzzzzzzzzzzzzzzz........................zzzzzzzz............
1518-07-01 #2927 ...............................zzzzzzzzzzzzzzzzzzzzzzzzzzzz.
1518-07-02  #239 ......zzzzzzzzzzz...............zzzzzzzzzzzzzzzzz...........
1518-07-03 #1489 .....................zzzzzzzzzzzzzz.........zzzzzzzzzzz.....
1518-07-04 #1597 ..........................zzzzz.............................
1518-07-05 #1489 ................zzzzzzz....zzzzzzzzzzzzz....zzz.............
1518-07-06 #3121 ....zzzzzzzzzz...zzzzzzzzzzzzzzzzzzzzzz.....................
1518-07-07 #1433 .......zzzzzzzzzzzzzzzzzzzzz.......zzzzzzzzz....zzzzzzzzzz..
1518-07-08  #593 ......zzzzzzzzzzzzzzzzzzzzzzzzzzz....zzzzz...........zzz....
1518-07-09  #239 ...............................................zzz..........
1518-07-10 #1597 ...........................zzzzz..............zzzzzzz.......
1518-07-11  #199 ......z..........................................zzzzz...zz.
1518-07-12 #1433 ...zzzzzzzzzzzzzzzzzzzzzzz.............zzzzzzzzzzzzz...zzzz.
1518-07-13 #3121 ................zzzzzzz.............zzzzzzzzzzzzzzzzzzz.....
1518-07-14  #229 ............................zzz....................zz....z..
1518-07-15 #1489 ......zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz..................
1518-07-16 #1489 ..........zzzzz........zzz....zzzzzzzzzzz...................
1518-07-17 #1543 ..................................zzzzzzzzzzzzzzzzzzz.......
1518-07-18 #2113 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.......zzzz...
1518-07-19  #587 .....................zzzzzzzzzzzzzzzz.......................
1518-07-20 #3121 ................................zzzzzzzzzzzzzzzzzzzzz.......
1518-07-21  #587 ......zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.......
1518-07-22 #2699 ...............................................zzzzzzzz.....
1518-07-23 #1543 ..............zzzzzzzzzzzzzzzzzzzzzzzzzzzzz.............zz..
1518-07-24 #1433 .........................................zzzzzzzzzzzzz......
1518-07-25  none ............................................................
1518-07-26 #1553 ...........................zzzzzzzzzzzzzzzzzzzzzzz..........
1518-07-27  #199 ................................zzzzz.......................
1518-07-28  #587 ..............zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.
1518-07-29  #593 ....zzzzzzzz.....zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz....
1518-07-30 #1601 ......zzzzzzzzzzzzzzzzzzzzzzzzz.............................
1518-07-31 #1549 ..............zzzzzzzzz.....................................
1518-08-01 #1597 .......................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz..
1518-08-02  #199 ................................zzzzzzzz.........zzzzzzzzz..
1518-08-03  #181 ...............zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz..........
1518-08-04 #3121 .........................zzzzzzzzzzzzzzzzzzzzz..............
1518-08-05  #181 ................................zzzzzzzzzzzzzzzzzzzzzzzzzzz.
1518-08-06 #1039 .......................zzzzzzzzzzzz.........................
1518-08-07 #2113 ...............zzzzzzzzzzzzzzzz................zzzzzzzzz....
1518-08-08 #2699 ...............................................zzzzzzzzz....
1518-08-09 #2113 ..zzzzzzzzzzzzzzzzzzzzzzzzzzz...............zzzzzz.....z....
1518-08-10  none ............................................................
1518-08-11  none ............................................................
1518-08-12 #1601 ....zzzzzzzzzzzzzzzzzzz......zzzzzzzzzzzzzzzzzzzzzzzz.......
1518-08-13  #239 ..............................................zzzzz.....zz..
1518-08-14 #2039 .......zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...........
1518-08-15 #2699 ...................................zzzzzzzzzzzzzzzzzzzzzzz..
1518-08-16  #199 ....................................zzzzzzz.................
1518-08-17  #239 ..................................zzzzzzzzzzzzz.............
1518-08-18  #317 ..zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz....z..........zzz.
1518-08-19 #3121 ......................zzzz....zzzz..........................
1518-08-20 #2039 ................zzzzzzzzzzzzzzzzzzz..............zzzzz......
1518-08-21  #587 ......................zzzzzzzzzzzz....zzzzzzzzzzzzzzzz......
1518-08-22 #1553 zzzzzzzzzzzzzz.................zzzzzz.......................
1518-08-23 #2039 ...............zzzzzzzzzzzzzzzz............zzzzzz...........
1518-08-24 #1597 ....zzzzzzzzzzzzzzz...zzzzzzzzzzzzzz........................
1518-08-25 #1039 .........................zzzzzzzzzzzzzzzzzzzz....zzzzzzz....
1518-08-26 #1597 .......zzzzzzzzzzzzzzzzzzzzzzzzzzzzz........................
1518-08-27 #1489 ...........zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz........zzzzzzz....
1518-08-28  #587 ...............................zzzzzzzzzzzzz................
1518-08-29 #3121 .......................zzzzzzzzzzzzzzzzzzzzzzzzzzzzz....z...
1518-08-30 #1601 .....................zzzzzzzzzzzzzzzzzzzzzzzzzzz............
1518-08-31  #317 ..................zzzzzzzzzzzzzzzzzzz............zzz........
1518-09-01 #2699 ..............zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz..
1518-09-02 #1597 .......................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz......
1518-09-03 #2113 zzzzzzzzzzzzzzzzzzzzz.....................zzzzzzzzzzzz......
1518-09-04 #1553 ..................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.
1518-09-05 #1433 ........................................zzzzzzzzzzzzzzzzzz..
1518-09-06 #1039 .............................zzzzzzzzzz.....................
1518-09-07 #1489 ......................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz..
1518-09-08  #229 ............................zzzzzzzzzzzzzzzzzzzzzzz.........
1518-09-09 #1601 ..........................zzzzzzzzzzzzzzzzz.............z...
1518-09-10 #1549 .......................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz....
1518-09-11 #3121 ........zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz........
1518-09-12 #2699 .............zzzzzz.............zzzzzzzzzzzzzzzzzzzz........
1518-09-13 #1553 ...zzzzzzzzzzzzz.............zzzzzzzzzzzzzzzzzzzzz....zzzz..
1518-09-14  #587 ..zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz........zzzzzzzzz....
1518-09-15  none ............................................................
1518-09-16 #3121 ....zzz.................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.....
1518-09-17 #1489 .......zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...
1518-09-18 #1597 .....zzzzzzzzzzzzzzzzzzz....................................
1518-09-19 #1597 ..........................zzzzzzzzzzzzzzzzzzzzzz............
1518-09-20 #1601 ......................zzzzzzzzzzzz........zzzzzzzzzzzzzzzzz.
1518-09-21 #1433 ....................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz..
1518-09-22 #1553 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz..........
1518-09-23 #2039 ..............zzzzzzzzzzzzzzzzzzz...............zz..........
1518-09-24 #2927 ....................zzzzzzzzzzzzzzzzzzzzzzzzz...............
1518-09-25 #1597 ............................zzzzz...zzzzzzzzz...............
1518-09-26 #1543 ...zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...........................
1518-09-27 #1553 .................zzzzzzzzzz.......zzzzzzzzzzzzzzzzzzz.......
1518-09-28  #593 ...zzzzzzzzzzzzzzzzzzzzzz...................................
1518-09-29 #1039 ...................................zzzzzzzzzzzzzzzzzzzzzzzz.
1518-09-30 #1549 .........................zzzzzzzzzzzzzzzzzzzzzzzzz..........
1518-10-01  #587 ...................................zzzzzzzz....zzzzz........
1518-10-02 #2039 ......................z.......zz............................
1518-10-03 #1549 .........................................zzz.....zzzzzzzzz..
1518-10-04  #587 ...........................zzzzzzzzzzzzzzzzzzzzzzzzzzzz.....
1518-10-05  none ............................................................
1518-10-06 #1601 ...........................................z....zzzz........
1518-10-07 #3121 ......................zzzzzzzzzz............zzzzzzzz........
1518-10-08  #593 ....zzzzzzzzzzzzzzzzzzzzz.................zzz............zz.
1518-10-09  #181 ...............zzzzzzz......................................
1518-10-10 #3121 ...............................zzzzzzzzzzzzzzzzzzzzzzz......
1518-10-11  #181 ...................zzzzzzzzzzzzzzzzzzzzz....................
1518-10-12 #1601 ......................................................zzzzz.
1518-10-13 #2699 .....zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz..............
1518-10-14 #2927 ........................................zzzzzzzzzzzzz.......
1518-10-15  none ............................................................
1518-10-16 #1549 ..............zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...
1518-10-17  #181 .......................zzzzzzzzzzzzzzzzzzzzzzzz.............
1518-10-18  #317 ..............zzzzzzzzzzzzzzzzzzz......zzzzzzzzz........z...
1518-10-19 #1549 ......zzzzzzzzzzzzzzzzzz....................................
1518-10-20 #1489 ..........zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.......
1518-10-21 #1489 .............zzzzzzzzzzzzzzzzzzzzzzzz...........z......zzz..
1518-10-22 #2699 .........................................zzzzzzzzzzzzzzzz...
1518-10-23 #1601 .............................zzzzzzzzzz.....................
1518-10-24 #1549 ...zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.....zzzzzzzzzzz.
1518-10-25 #1553 ...zzzzzzzzzzzzzzzzz.............................zzz........
1518-10-26  #181 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.............
1518-10-27 #1543 ....zzzzzzzzzzzzzzz............zz........zzzzzzzzzzzzzz.....
1518-10-28  #229 ....zzzzzzzzzzzzzzzzzzzzzzz....................zzzzzzzzzzzz.
1518-10-29 #2699 .....................zzzzzzzzzzzzzzzzzzzzzzzzz.......zzzzzz.
1518-10-30  #239 ............................................zzzzzzzzzzzzzz..
1518-10-31 #1597 ...................zzzzz.....zzzzzzzzz......................
1518-11-01 #2699 ...................................zzzzz.......zz.......zzz.
1518-11-02 #2113 .....zzzzzzz................................................
1518-11-03  #587 ............................zzzzzzzzzzzzzzzzzzzzz...........
1518-11-04 #1039 ......................................zzzzzzzzzzzzzzzzzzzz..
1518-11-05 #1549 ......................................................z.....
1518-11-06 #2113 ..........zzzzzzzzzzzzzzzzzzzzzzzz.................zzzzzzz..
1518-11-07  #593 .....................................z......................
1518-11-08 #2113 ...................zzz.......zzzzzzzzzzzzzzzzzzzzzz.........
1518-11-09  #317 ..........................zzzzzzzzzzzzzzzzzzzzzzz...........
1518-11-10 #2039 .........zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.............
1518-11-11 #1489 ...........zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz....
1518-11-12 #2699 ..................................zzzzzzzzzzzzzzzzzzz.......
1518-11-13 #1597 .................................zzzzzzzzzzzzzzzzzzzzzzzzzz.
1518-11-14  #239 ......zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.........
1518-11-15 #3121 ..........................zzzz...................zzzzzzzz...
1518-11-16 #1549 ........................zzzzzzzzzzz.........................
1518-11-17 #1601 ..zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.............
1518-11-18  #317 ....................zzzzzzzzzzzzzz................zzzzz.....
1518-11-19  #239 .zzzzzzzz.........................................zzz.......
1518-11-20 #1433 .................zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.......
1518-11-21 #2039 ............zzzzzzzzzzzzzz.......zzzzzzzzz......zzzzzzzzz...
1518-11-22  #317 ....zz.....................zzzzzzzzzzz......................
``````

I like your use of `-en` suffixes to denote verbs. Makes a lot of sense, actually, easy to glean intent.

Haha, I was tired and started with `awaken` and I thought `asleepen` was really hilarious.

Of course once I realized that there was a distinction between going on duty and waking up from a sleep, I was honor-bound to add `ondutyen`

I have been trying to learn F#, coming from C#, and I'm quite "happy" with my previous solutions. This one challenged me more, having to think 'functional'! I am not happy with how it looks, but here it is anyway!

My other attempts are on github. Critique is highly welcome!

I made a datastructure that mapped guards to days to minutes with type: `Map<string,Map<string,bool array>` which made it 'easy' (or so I though) to extract the data.

``````let rec handle guard (datastructure:Map<string,Map<string,bool []>>) (arr:string list) =
match arr with
| Regex @"\[(\d+)-(\d\d)-(\d\d) (\d+):(\d+)\] (.+)" [year; month; day; hour; min; action] ->
let date = new DateTime(year|>int,month|>int,day|>int,hour|>int,min|>int,0)
let origday = date.ToString "MM-dd"
let newdate =
if date.Hour = 0 then
date
else
let newday = newdate.ToString "MM-dd"
match action with
| Regex @"Guard #(\d+)" [newguard] ->
if datastructure.ContainsKey newguard then
if not (datastructure.[newguard].ContainsKey newday) then
let newDs =
let minutes : bool array = Array.zeroCreate 60
let newDay =
if hour = "00" then
minutes.[min|>int] <- true
else
minutes.[0] <- true
datastructure.[newguard]
handle newguard newDs tail
else
handle newguard datastructure tail
else
// create new level in datastructure
// new array of waking minutes, default to sleep
let minutes : bool array = Array.zeroCreate 60
// guard starts out as awake
let newMap =
Map.empty
let newDs =
datastructure
handle newguard newDs tail
| Regex @"wakes up" [] ->
// set time to awake
datastructure.[guard].[newday].[min|>int] <- true
handle guard datastructure tail
| Regex @"falls asleep" []->
// set all times before this to awake
let maxMin = min|> int
let minMin =
try
Array.findIndexBack (fun a -> a) datastructure.[guard].[newday].[0..maxMin]
with
| :? KeyNotFoundException as ex -> 0

for i in [minMin..maxMin-1] do
datastructure.[guard].[newday].[i] <- true
handle guard datastructure tail
| _ -> handle guard datastructure tail
| _ -> handle guard datastructure tail
| [] ->
// guard ends his day awake
Map.iter (fun g dm ->
Map.iter (fun d ms ->
let minMin =
try
Array.findIndexBack (fun a -> a) ms
with
| :? KeyNotFoundException as ex -> 0
for i in [minMin..59] do
ms.[i] <- true
) dm ) datastructure
// guard starts his day awake
Map.iter (fun g dm ->
Map.iter (fun d ms ->
let minMin =
try
Array.findIndex (fun a -> a) ms
with
| :? KeyNotFoundException as ex -> 0
for i in [0..minMin] do
ms.[i] <- true
) dm ) datastructure
datastructure
``````

Then Part 1

``````let testinput ="[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"

let stopwatch = System.Diagnostics.Stopwatch.StartNew()

let split =
split testinput
|> Array.sort

// (guard,day,minute) -> awake
let datastruct =
split
|> Array.toList
|> handle "" Map.empty

stopwatch.Stop()
printfn "creating datastructure took %i milliseconds" stopwatch.ElapsedMilliseconds
stopwatch.Restart()

// find guard that is asleep most
let sleepyGuard =
datastruct
|> Map.map (fun guard day ->
Map.map (fun day mins ->
Array.sumBy (fun awake -> if awake then 0 else 1) mins
) day
)
|> Map.map (fun guard day ->
day
|> Map.fold (fun acc day mins -> acc+mins ) 0
)
|> Map.toList
|> List.maxBy (fun (g,min) -> min)
|> fst
stopwatch.Stop()
printfn "sleepiest guard is %s" sleepyGuard
printfn "\t calculation too %i milliseconds" stopwatch.ElapsedMilliseconds
stopwatch.Restart()
// find that guards most likely minute of being asleep

let sleepyMinute =
datastruct.[sleepyGuard]
|> Map.map (fun day mins -> Array.indexed mins)
|> Map.toList
|> List.map (fun i -> snd i)
|> List.collect (fun arr -> Array.toList arr)
|> List.groupBy (fun (index, awake) -> index)
|> List.map (fun arr -> snd arr)
|> List.map (fun a -> List.map (fun b -> snd b) a)
|> List.map (fun a -> a |> List.filter (fun awake -> not awake) |> List.length )
|> List.indexed
|> List.maxBy (fun (index,m) -> m)
|> fst

stopwatch.Stop()
printfn "sleepiest minute of guard %s is %i" sleepyGuard sleepyMinute
printfn "result of day 4 part 1 is: %i" ((sleepyGuard|>int) * sleepyMinute)
printfn "\t calculation took %i milliseconds" stopwatch.ElapsedMilliseconds
``````

and Part 2

``````let popular =
datastruct
|> Map.map (fun guard day ->
Map.toList day
|> List.map snd
|> List.map (fun i -> Array.toList i |> List.indexed)
|> List.concat
//|> List.filter (fun (_,awake) -> not awake)
|> List.groupBy (fun (i,_) -> i)
|> List.map (fun (i,l) -> (i,(List.fold (fun acc (_,awake) -> if awake then acc else acc+1) 0 l)))
|> List.maxBy (fun (_,l) -> l)
)
|> Map.toList
|> List.maxBy (fun (_,(_,t)) -> t)

stopwatch.Stop()
printfn "Guard %s spent minute %i asleep more than anyone: %i times" (fst popular) (fst (snd popular)) (snd (snd popular))
printfn "result of day 4 part 2 is: %i" (((fst popular)|>int) * (fst (snd popular)))
printfn "\t calculation took %i milliseconds" stopwatch.ElapsedMilliseconds
``````

Had an afterwork event that included drinks which didn't mix well with the problem description ;-) Also it's past midnight here by now, so it's not exactly the most elegant code:

``````require 'date'

TIMESTAMP_REGEX = /\d{4}-\d{2}-\d{2} \d{2}:\d{2}/.freeze
ID_REGEX = /#(?<id>\d+)/.freeze
MINUTE_REGEX = /(?<minutes>\d\d)\]/.freeze

records = DATA.readlines.sort_by { |line| DateTime.parse(line[TIMESTAMP_REGEX]) }
grouped_records = records.chunk_while { |_l1, l2| l2 !~ /Guard/ }

sleep_ranges = Hash.new { |h, k| h[k] = [] }
grouped_records.each do |records|
guard_id = records.shift.match(ID_REGEX)[:id].to_i
sleep_ranges[guard_id] += records.each_slice(2).map { |period|
Range.new(
*period.map { |entry| entry.match(MINUTE_REGEX)[:minutes].to_i },
true
)
}
end

sleep_minutes = sleep_ranges.map { |id, ranges|
[
id,
(0..59).each_with_object(Hash.new(0)) { |minute, counts|
counts[minute] = ranges.count { |r| r.include?(minute) }
}
]
}.to_h

id, = sleep_ranges.max_by { |_, rs| rs.sum(&:size) }
puts id * sleep_minutes[id].max_by(&:last).first

id, minutes = sleep_minutes.max_by { |id, minutes| minutes.max_by(&:last).last }
puts id * minutes.max_by(&:last).first

__END__
[1518-06-25 23:58] Guard #1069 begins shift
[1518-09-16 00:24] falls asleep
[1518-04-06 00:56] wakes up
...
``````

## JavaScript solution

``````const fs = require('fs');

const readLines = (file, onLine) => {
crlfDelay: Infinity
});

return new Promise(resolve => reader.on('close', resolve));
};

const readFile = async file => {
const lines = [];
return lines;
}

module.exports = {
};
``````

### 04-common.js

``````class SleepingSchedule {
constructor(guard) {
this.guard = guard;
this.guard.schedules.push(this);

this.minutesSlept = [];
}

setDate(year, month, day) {
this.year = year;
this.month = month;
this.day = day;
}

const length = end - start;
this.minutesSlept.push(...Array.from({ length }, (e, i) => start + i));
this.guard.maxMinutesSlept += length;
}
}

class Guard {
constructor(id) {
this.id = id;
this.maxMinutesSlept = 0;
this.schedules = [];
}
}

const buildGuards = lines => {
const beginsShiftRegex = /^\[(?<year>\d+)-(?<month>\d+)-(?<day>\d+)\s(?<hour>\d+):(?<minute>\d+)\]\sGuard\s#(?<id>\d+) begins shift\$/;
const fallsAsleepRegex = /^\[(?<year>\d+)-(?<month>\d+)-(?<day>\d+)\s(?<hour>\d+):(?<minute>\d+)\]\sfalls\sasleep\$/;
const wakesUpRegex = /^\[(?<year>\d+)-(?<month>\d+)-(?<day>\d+)\s(?<hour>\d+):(?<minute>\d+)\]\swakes\sup\$/;

const sleepingSchedules = new Map();
const guards = new Map();

let currentSchedule;
let hasNapped;
let napStartMinute;
let currentGuard;
for (let line of lines) {
let match = line.match(beginsShiftRegex);
if (match) {
if (napStartMinute) {
}

const { id } = match.groups;

if (guards.has(id)) {
currentGuard = guards.get(id);
}
else {
currentGuard = new Guard(id);
guards.set(id, currentGuard);
}
currentSchedule = new SleepingSchedule(currentGuard);

hasNapped = false;
napStartMinute = undefined;
}
else {
match = line.match(fallsAsleepRegex);
if (match) {
if (!hasNapped) {
const { year, month, day } = match.groups;
currentSchedule.setDate(year, month, day);
hasNapped = true;
}
const { minute } = match.groups;
napStartMinute = +minute;
}
else {
match = line.match(wakesUpRegex);
if (match) {
const { minute } = match.groups;
napStartMinute = undefined;
}
}
}
}
return guards;
};

module.exports = {
SleepingSchedule,
Guard,
buildGuards
};
``````

### 04a.js

``````const { readFile } = require('./reader');
const {
SleepingSchedule,
Guard,
buildGuards
} = require('./04-common');

const findZonkedGuard = guards => {
return [...guards.values()].reduce((zonkedGuard, guard) => {
if (guard.maxMinutesSlept > zonkedGuard.maxMinutesSlept) {
zonkedGuard = guard;
}
return zonkedGuard;
});
};

const findMostAsleepMinute = guard => {
const minutesCount = Array.from({ length: 60 }, m => 0);
for (let i = 0; i < 60; i++) {
for (let schedule of guard.schedules) {
minutesCount[i] += +(schedule.minutesSlept.indexOf(i) > -1);
}
}

const mostAsleepMinuteCount = Math.max(...minutesCount);
return minutesCount.indexOf(mostAsleepMinuteCount);
};

(async () => {
lines.sort();

const guards = buildGuards(lines);
const zonkedGuard = findZonkedGuard(guards);
const mostAsleepMinute = findMostAsleepMinute(zonkedGuard);

const solution = +zonkedGuard.id * mostAsleepMinute;
console.log(`The ID of the guard multiplied by the minute is \${solution}`);
})();
``````

### 04b.js

``````const { readFile } = require('./reader');
const {
SleepingSchedule,
Guard,
buildGuards
} = require('./04-common');

const findMostAsleepMinute = guard => {
const minutesCount = Array.from({ length: 60 }, m => 0);
for (let i = 0; i < 60; i++) {
for (let schedule of guard.schedules) {
minutesCount[i] += +(schedule.minutesSlept.indexOf(i) > -1);
}
}

const mostAsleepMinuteCount = Math.max(...minutesCount);
return minutesCount.indexOf(mostAsleepMinuteCount);
};

const findMostFrequentlySleptMinute = guards => {
const minutesMostSlept = [];

// Finding the guard which slept the most minutes for every minute
for (let i = 0; i < 60; i++) {
const guardsWhichSleptThisMinute = new Map();
for (let guard of guards.values()) {
let minutesThisGuardSlept = 0;
for (let schedule of guard.schedules) {
minutesThisGuardSlept += +(schedule.minutesSlept.indexOf(i) > -1);
}
guardsWhichSleptThisMinute.set(guard.id, minutesThisGuardSlept);
}

let zonkedGuardId;
let maxMinutesSlept = 0;
for (let [guardId, minutes] of guardsWhichSleptThisMinute.entries()) {
if (minutes > maxMinutesSlept) {
maxMinutesSlept = minutes;
zonkedGuardId = guardId;
}
}

minutesMostSlept[i] = { zonkedGuardId, maxMinutesSlept };
}

// Finding the guard which slept the most minutes total
let zonkedGuardIdTotal;
let maxMinutesSleptTotal = 0;
let minuteMostSleptTotal = -1;
for (let i = 0; i < 60; i++) {
const { zonkedGuardId, maxMinutesSlept } = minutesMostSlept[i];
if (maxMinutesSlept > maxMinutesSleptTotal) {
maxMinutesSleptTotal = maxMinutesSlept;
zonkedGuardIdTotal = zonkedGuardId;
minuteMostSleptTotal = i;
}
}

return { zonkedGuardIdTotal, minuteMostSleptTotal }
}

(async () => {
lines.sort();

const guards = buildGuards(lines);
const { zonkedGuardIdTotal, minuteMostSleptTotal } = findMostFrequentlySleptMinute(guards);

const solution = +zonkedGuardIdTotal * minuteMostSleptTotal;
console.log(`The ID of the guard multiplied by the minute is \${solution}`);
})();
``````

Didn't really have much time to do the challenges today, but yeah, whenever you did the first three days it's hard to skip one.

So here are my solutions in Elixir. Some function returns are a bit messy, but it does what it needs to do. The basic idea is that all lines are first parsed into a map with guards, where each guard is the key for another map containing the minutes and the number of times the guard was asleep during that minute.

Having that basic map makes the calculations for both strategies relatively easy.

Common:

``````defmodule AoC.DayFour.Common do
@line_regex ~r/\[(.*)\] (.*)/
@date_format "{YYYY}-{M}-{D} {h24}:{m}"

path
|> File.stream!()
|> Stream.map(&String.trim_trailing/1)
|> Enum.to_list()
|> Enum.sort()
|> Enum.map(fn x ->
[datetime, log] = Regex.run(@line_regex, x, capture: :all_but_first)
{:ok, datetime} = Timex.parse(datetime, @date_format)
%{datetime: datetime, log: log}
end)
end

def calculate_guard_minutes(input, map \\ %{}, current_guard \\ "", last_minute \\ 0)

def calculate_guard_minutes([line | rest], map, current_guard, last_minute) do
case line.log do
"falls asleep" ->
calculate_guard_minutes(rest, map, current_guard, line.datetime.minute)

"wakes up" ->
map = Map.put_new(map, current_guard, %{})
guard = Map.get(map, current_guard)

guard =
Enum.reduce(last_minute..(line.datetime.minute - 1), guard, fn x, acc ->
Map.update(acc, x, 1, &(&1 + 1))
end)

map = Map.put(map, current_guard, guard)
calculate_guard_minutes(rest, map, current_guard, line.datetime.minute)

_ ->
[new_guard] =
Regex.run(~r/^Guard #(\d+) begins shift\$/, line.log, capture: :all_but_first)

calculate_guard_minutes(rest, map, new_guard, 0)
end
end

def calculate_guard_minutes([], map, _current_guard, _last_minute) do
map
end
end
``````

Part one:

``````defmodule AoC.DayFour.PartOne do
alias AoC.DayFour.Common

def main() do
"lib/day4/input.txt"
|> Common.calculate_guard_minutes()
|> get_sleepiest_guard()
|> get_sleepiest_minute()
|> calculate_result()
end

defp calculate_result({guard, minute}) do
guard * minute
end

defp get_sleepiest_minute(map) do
{_, {guard, minutes}} = map

{sleepiest_minute, _} =
# Format: {guard, minutes_slept}
Enum.reduce(minutes, {0, 0}, fn {current_minute, count}, {highest_minute, highest_count} ->
if count > highest_count,
do: {current_minute, count},
else: {highest_minute, highest_count}
end)

{String.to_integer(guard), sleepiest_minute}
end

defp get_sleepiest_guard(map) do
# Format: {minutes_slept, {guard, minutes}}
Enum.reduce(map, {0, {0, %{}}}, fn {guard, minutes}, sleepiest_guard ->
minutes_slept = Enum.reduce(minutes, 0, fn {_, count}, acc -> acc + count end)
{current_sleep_minutes, _} = sleepiest_guard

if minutes_slept > current_sleep_minutes,
do: {minutes_slept, {guard, minutes}},
else: sleepiest_guard
end)
end
end
``````

Part two:

``````defmodule AoC.DayFour.PartTwo do
alias AoC.DayFour.Common

def main() do
"lib/day4/input.txt"
|> Common.calculate_guard_minutes()
|> get_sleepiest_guard()
|> calculate_result()
end

defp calculate_result({guard, minute}) do
guard * minute
end

defp get_sleepiest_guard(map) do
# Format: {guard, minute, count}
{guard, minute, _} =
Enum.reduce(map, {0, 0, 0}, fn {guard, minutes}, sleepiest_guard ->
# Format: {minute, count}
{minute, count} =
Enum.reduce(minutes, {0, 0}, fn {minute, count}, {current_minute, highest_count} ->
if count > highest_count, do: {minute, count}, else: {current_minute, highest_count}
end)

{_, _, current_count} = sleepiest_guard

if count > current_count,
do: {String.to_integer(guard), minute, count},
else: sleepiest_guard
end)

{guard, minute}
end
end
``````

Had a particularly long day at work, so got to the problem late and only just now finished. I'm with all of you that this one was less fun...I haven't refactored since I don't have much brain left for today, but here's my solution for now!

``````#!/usr/bin/env python

import operator
import re
from collections import defaultdict

RECORD_PATTERN = re.compile('\[.* \d\d:(\d\d)\] .*')
GUARD_ID_PATTERN = re.compile('.* Guard #(\d+) begins shift')

if __name__ == '__main__':
with open('input.txt') as guard_records_file:
guard_records.sort()

minute_data = defaultdict(lambda: defaultdict(int))
guard_data = defaultdict(lambda: defaultdict(int))

for guard_record in guard_records:
minute = int(RECORD_PATTERN.match(guard_record).group(1))

if 'begins shift' in guard_record:
just_started_shift = True
current_guard = int(GUARD_ID_PATTERN.match(guard_record).group(1))
elif 'wakes up' in guard_record:
minutes_asleep = minute - fell_asleep_minute
for sleep_minute in range(fell_asleep_minute, minute):
guard_data[current_guard][sleep_minute] += 1
minute_data[sleep_minute][current_guard] += 1
elif 'falls asleep' in guard_record:
fell_asleep_minute = minute

# Part 1
guard_who_slept_most = max(guard_data, key=lambda key: sum(guard_data[key].values()))
sleepiest_minute_for_guard = max(minute_data, key=lambda key: minute_data[key][guard_who_slept_most])
print(guard_who_slept_most * sleepiest_minute_for_guard)

# Part 2
guard_with_sleepiest_minute = max(guard_data, key=lambda key: max(guard_data[key].values()))
sleepiest_minute_for_guard = max(guard_data[guard_with_sleepiest_minute], key=lambda key: guard_data[guard_with_sleepiest_minute][key])
print(guard_with_sleepiest_minute * sleepiest_minute_for_guard)
``````

Done! Completed my solution with just minutes to spare before the next day goes live! I thought I would like this challenge. I did not. It was fine, for the most part. But I spent at least fifteen minutes wondering why my solution wasn't working before I realized the #!@%#@!\$! LOGS WERE NOT IN CHRONOLOGICAL ORDER.

Let me tell you: I was not calm in that moment.

After I used VS Code's built-in sorting functionality to pre-sort the input text, it was mostly smooth sailing. However, rust gurus, before I sorted my input, every time I ran `cargo run`, the output would be a different answer, even with no changes to the code. Anybody know why that might be? I would expect a static input file and static code to make the same result every time.

Anyways.

## Part 1

``````use std::collections::HashMap;

/// Day 4: Repose Record
///
/// Track the sleeping times of various security guards

// Part 1: Find the guard who slept most and their most-slept minute

/// The security team (made up of a bunch of Guards) that we're monitoring
struct SecurityTeam {
guards: HashMap<usize, Guard>,
}

impl SecurityTeam {
pub fn new() -> Self {
Self { guards: HashMap::new() }
}

/// Loads in a log-file-like schedule from text
///
/// Entries have the form '[YYYY-MM-DD HH:MM] message'
/// Possible messages are 'Guard #<id> begins shift'
///                       'falls asleep'
///                       'wakes up'
/// Assumes that the logs are in chronological order (WHICH IS SANE)
pub fn load_schedule(&mut self, text: &str) {
let mut current_guard = 0;
let mut current_state = "";
let mut sleep_start = 0;

for line in text.lines() {
// Yeah I'm hard-coding the minutes location, DON'T JUDGE ME
let minute: usize = line[15..17].parse().expect("Minutes weren't a number");
let action = &line[19..];
if action.contains("Guard") {
// New guard starting shift.
let id = action.trim_matches(|c: char| !c.is_numeric()).parse().expect("No guard ID");
self.guards.entry(id).or_insert(Guard::new(id));
current_guard = id;
current_state = "awake";
} else if action.contains("falls asleep") {
// Ignores double-falls asleep
if current_state == "awake" {
current_state = "asleep";
sleep_start = minute;
}
} else if action.contains("wakes up") {
// Ignores double-wakes
if current_state == "asleep" {
self.guards.get_mut(&current_guard).unwrap().track_sleep(sleep_start, minute);
current_state = "awake";
}
}
}
}

/// Returns the guard with the overall most minutes asleep
pub fn sleepiest_guard(&self) -> &Guard {
self.guards.values()
.max_by_key(|guard| guard.total_minutes_asleep())
.expect("No guards on team")
}
}

/// A security guard.  He keeps track of his own sleep times (what a great person)!
struct Guard {
id: usize,
sleep_minutes: HashMap<usize, usize>,
}

impl Guard {
pub fn new(id: usize) -> Self {
Self { id, sleep_minutes: HashMap::new() }
}

pub fn id(&self) -> usize {
self.id
}

/// Returns the minute in which this guard most commonly slept
///
/// Accounts for the possibility that this guard doesn't suck at their
/// job and stays awake the whole time.
pub fn sleepiest_minute(&self) -> usize {
*self.sleep_minutes.iter()
.max_by_key(|(_id, minutes)| **minutes)
.unwrap_or((&0, &0))
.0
}

/// Sums up this guards total sleeping time
pub fn total_minutes_asleep(&self) -> usize {
self.sleep_minutes.values().sum()
}

/// Logs in a length of time where the guard was asleep
pub fn track_sleep(&mut self, asleep: usize, awake: usize) {
for minute in asleep..awake {
*self.sleep_minutes.entry(minute).or_insert(0) += 1
}
}
}

/// Part 1 asks for the ID of the guard who slept the most multiplied by
/// the minute they slept most
pub fn part1(text: &str) -> usize {
let mut guards = SecurityTeam::new();
let sleepy = guards.sleepiest_guard();
sleepy.id() * sleepy.sleepiest_minute()
}
``````

## Part 2

Part 2 went pretty quick now that I've got all this infrastructure in place.

``````// Part 2

impl SecurityTeam {
/// Returns the guard that fell asleep the most on the same minute
pub fn most_consistent_sleeper(&self) -> &Guard {
self.guards.values()
.max_by_key(|guard| guard.sleep_on(guard.sleepiest_minute()))
.expect("No guards on team")
}
}

impl Guard {
/// Returns the amount of times this guard slept on a given minute
pub fn sleep_on(&self, minute: usize) -> usize {
*self.sleep_minutes.get(&minute).unwrap_or(&0)
}
}

/// Part two asks for the ID of the guard who slept the most on a single
/// minute multiplied by that minute
pub fn part2(text: &str) -> usize {
let mut guards = SecurityTeam::new();