A company currently pays a fixed sum for the use of a particular licensed software package.   In determining if it has a good deal it decides to calculate its maximum use of the software from its license management log file.

Assume the software's licensing daemon faithfully records a checkout event when a copy of the software starts and a checkin event when the software finishes to its log file.

An example of checkout and checkin events are:

 License OUT @ 2008/10/03_23:51:05 for job 4974
 ...
 License IN  @ 2008/10/04_00:18:22 for job 4974



Task

Save the 10,000 line log file from    here   into a local file, then write a program to scan the file extracting both the maximum licenses that were out at any time, and the time(s) at which this occurs.

Mirror of log file available as a zip here (offsite mirror).




type Timestamp = String;
 
fn compute_usage<R, S, E>(lines: R) -> Result<(u32, Vec<Timestamp>), E>
where
    S: AsRef<str>,
    R: Iterator<Item = Result<S, E>>,
{
    let mut timestamps = Vec::new();
    let mut current = 0;
    let mut maximum = 0;
 
    for line in lines {
        let line = line?;
        let line = line.as_ref();
 
        if line.starts_with("License IN") {
            current -= 1;
        } else if line.starts_with("License OUT") {
            current += 1;
 
            if maximum <= current {
                let date = line.split_whitespace().nth(3).unwrap().to_string();
 
                if maximum < current {
                    maximum = current;
                    timestamps.clear();
                }
 
                timestamps.push(date);
            }
        }
    }
 
    Ok((maximum, timestamps))
}
 
fn main() -> std::io::Result<()> {
    use std::io::{BufRead, BufReader};
    let file = std::fs::OpenOptions::new().read(true).open("mlijobs.txt")?;
    let (max, timestamps) = compute_usage(BufReader::new(file).lines())?;
    println!("Maximum licenses out: {}", max);
    println!("At time(s): {:?}", timestamps);
    Ok(())
}