extern crate core;

use std::str::FromStr;
use std::cmp::Ordering;

struct Istream {
    line: Vec<String>,
    position: usize
}
type Parse<T: FromStr> = Result<T, T::Err>;
impl Istream {
    fn new() -> Istream {
        Istream {line:vec![], position: 0}
    }
    fn read_word(&mut self) -> &String {
        if self.position == self.line.len() {
            let mut line= String::new();
            std::io::stdin().read_line(&mut line).ok();
            self.line = line.split_whitespace().map(|x|x.to_string()).collect();
            self.position = 0
        }
        let result = &self.line[self.position];
        self.position += 1;
        result
    }
    fn read(&mut self) -> String {
        self.read_word().to_string()
    }
    fn get<T: FromStr>(&mut self) -> T {self.read_word().parse().ok().unwrap()}
    fn read_usize(&mut self) -> usize {self.get()}
    fn read_int(&mut self) -> i32 {self.get()}
    fn read_long(&mut self) -> i64 {self.get()}
    fn read_double(&mut self) -> f64 {self.get()}
}
fn tabulate<T, F>(count: usize, elements: &mut F) -> Vec<T> where F: FnMut(usize) -> T {
    let mut result:Vec<T> = Vec::with_capacity(count);
    for i in 0 .. count {
        result.push(elements(i))
    }
    result
}
fn fill<T, F>(count: usize, generator: F) -> Vec<T> where F: Fn() -> T {
    let mut result: Vec<T> = Vec::with_capacity(count);
    for _i in 0 .. count {
        result.push(generator())
    }
    result
}
#[derive(Eq, PartialEq, Copy, Clone)]
struct Time{
    hour: i32,
    minute: i32
}
impl FromStr for Time {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let split:Vec<_> = s.split(":").map(|st|st.parse::<i32>()).collect();
        if let (&Ok(h), &Ok(m)) = (&split[0], &split[1]) {
            Ok(Time{hour: h, minute: m})
        }else {
            Err(())
        }
    }
}
impl Time {
    fn new() -> Time {
        Time{hour: 0, minute: 0}
    }
    fn minute_from(&self, base: &Time) -> i32 {
        self.hour * 60 + self.minute - base.hour * 60 - base.minute
    }
}
impl Ord for Time {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.hour == other.hour {
            self.minute.cmp(&other.minute)
        }else {
            self.hour.cmp(&other.minute)
        }
    }
}
impl PartialOrd for Time {
    fn partial_cmp(&self, other: &Time) -> Option<Ordering> {
        Some(self.cmp(&other))
    }

    fn lt(&self, other: &Time) -> bool {
        self.cmp(&other) == Ordering::Less
    }

    fn le(&self, other: &Time) -> bool {
        self.cmp(&other) != Ordering::Greater
    }

    fn gt(&self, other: &Time) -> bool {
        self.cmp(&other) == Ordering::Greater
    }

    fn ge(&self, other: &Time) -> bool {
        self.cmp(&other) != Ordering::Less
    }
}
enum State {
    In, Out,
}
impl FromStr for State {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "I" => Ok(State::In),
            "O" => Ok(State::Out),
            _ => Err(())
        }
    }
}
fn main() {
    let mut input = Istream::new();
    loop {
        let n = input.read_usize();
        if n == 0 {
            break
        }
        let mut account = vec![0; 1000];
        let mut is_appear = vec![false; 1000];
        let mut is_presence = vec![false; 1000];
        let mut last_time = vec![Time::new(); 1000];
        let mut suspects = Vec::<usize>::new();
        let mut goddess = false;
        let mut stack: Vec<usize> = Vec::new();
        for _ in 0 .. n {
            let day = input.read();
            let time = input.get::<Time>();
            let state = input.get::<State>();
            let id = input.read_usize();
            match state {
                State::In if id == 0 => {
                    for i in suspects.iter().filter(|&x|is_presence[*x]) {
                        last_time[*i] = time;
                    }
                    goddess = true;
                }
                State::In if goddess => {
                    last_time[id] = time;
                    is_presence[id] = true;
                    if !is_appear[id] {
                        is_appear[id] = true;
                        suspects.push(id);
                    }
                }
                State::In => {
                    is_presence[id] = true;
                    if !is_appear[id] {
                        is_appear[id] = true;
                        suspects.push(id);
                    }
                }
                State::Out if id == 0 => {
                    for i in suspects.iter().filter(|&x| is_presence[*x]) {
                        account[*i] += time.minute_from(&last_time[*i]);
                    }
                    goddess = false;
                }
                State::Out if goddess => {
                    account[id] += time.minute_from(&last_time[id]);
                    is_presence[id] = false;
                }
                State::Out => {
                    is_presence[id] = false;
                }

            }
        }
        println!("{}", account.iter().max().unwrap());
    }
}


Measured memory_bytes: 5052