extern crate core;

use std::fmt;
use std::cmp::{max, min, Ordering};
use std::collections::{BinaryHeap, BTreeMap, VecDeque};
use std::ops::{Range, Sub, Add};
use ::Suspects::All;
use std::fmt::{Display, Formatter, Error};
macro_rules! read_line{
    () => {{
        let mut line = String::new();
        std::io::stdin().read_line(&mut line).ok();
        line
    }};
    (delimiter: ' ') => {
        read_line!().split_whitespace().map(|x|x.to_string()).collect::<Vec<_>>()
    };
    (delimiter: $p:expr) => {
        read_line!().split($p).map(|x|x.to_string()).collect::<Vec<_>>()
    };
    (' ') => {
        read_line!(delimiter: ' ')
    };
    ($delimiter:expr) => {
        read_line!(delimiter: $delimiter)
    };
    (' '; $ty:ty) => {
        read_line!().split_whitespace().map(|x|x.parse::<$ty>().ok().unwrap()).collect::<Vec<$ty>>()
    };
    ($delimiter:expr; $ty:ty) => {
        read_line!($delimiter).into_iter().map(|x|x.parse::<$ty>().ok().unwrap()).collect::<Vec<$ty>>()
    };
}
macro_rules! let_all {
    ($($n:ident:$t:ty),*) => {
        let line = read_line!(delimiter: ' ');
        let mut iter = line.iter();
        $(let $n:$t = iter.next().unwrap().parse().ok().unwrap();)*
    };
}

fn main(){
    let_all!(n: usize);
    let mut persons = Vec::with_capacity(n);
    for _ in 0 .. n {
        let_all!(x: i32, y: i32, u: i32, v: i32);
        persons.push(Person{initial: Point{x: x, y: y}, velocity: Vector{dx: u, dy: v}});
    }
    println!("{}", solve(&persons));
}
#[derive(Copy, Clone, Eq, PartialEq)]
struct Point {
    x: i32, y: i32
}
#[derive(Copy, Clone, Eq, PartialEq)]
struct Vector {
    dx: i32, dy: i32
}
#[derive(Copy, Clone)]
struct PointF {
    x: f64, y: f64
}
impl Display for Point {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "Point(x: {}, y: {})", self.x, self.y)
    }
}
impl Display for Vector {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "Vector(dx: {}, dy: {})", self.dx, self.dy)
    }
}
impl Display for Person {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "Person(initial: {}, velocity: {})", self.initial, self.velocity)
    }
}
impl Display for PointF {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "Point(x: {}, y: {})", self.x, self.y)
    }
}
impl Vector {
    fn to_point(&self) -> Point {
        Point{x: self.dx, y: self.dy}
    }
}
#[derive(Copy, Clone, Eq, PartialEq)]
struct Person {
    initial: Point, velocity: Vector
}
impl Person {
    fn position_at(&self, time: f64) -> PointF {
        PointF{x: self.initial.x as f64 + self.velocity.dx as f64 * time, y: self.initial.y as f64 + self.velocity.dy as f64 * time}
    }

}
impl Sub for Point {
    type Output = Vector;
    fn sub(self, rhs: Point) -> Self::Output {
        Vector{dx: self.x - rhs.x, dy: self.y - rhs.y}
    }
}
impl Sub for Vector {
    type Output = Vector;
    fn sub(self, rhs: Vector) -> Self::Output {
        Vector{dx: self.dx - rhs.dx, dy: self.dy - rhs.dy}
    }
}
impl Sub for PointF {
    type Output = PointF;
    fn sub(self, rhs: PointF) -> Self::Output {
        PointF{x: self.x - rhs.x, y: self.y - rhs.y}
    }
}
enum Suspects<T> {
    All, Some{suspects: Vec<T>}, None
}
fn find_on_line_time(a: &Person, b: &Person, target: &Person) -> Suspects<f64> {
    let Vector{dx: a1, dy: c1} = a.initial - b.initial;
    let Vector{dx: b1, dy: d1}= a.velocity - b.velocity;
    let Vector{dx: a2, dy: c2} = target.initial - b.initial;
    let Vector{dx: b2, dy: d2} = target.velocity - b.velocity;
    let a = (b1 * d2 - d1 * b2) as f64;
    let b = (b1 * c2 + a1 * d2 - a2 * d1 - c1 * b2) as f64;
    let c = (a1 * c2 - a2 * c1) as f64;
    if a == 0_f64 {
        if b == 0_f64 {
            if c == 0_f64 {
                All
            }else {
                Suspects::None
            }
        }else if -c / b >= 0_f64 {
            Suspects::Some{suspects: vec![-c / b]}
        }else {
            Suspects::None
        }
    }else {
        let d = b * b - 4_f64 * a * c;
        if d < 0_f64 {
            Suspects::None
        }else if d.abs() <= 0.00000001_f64 {
            if -b / (a * 2_f64) >= 0_f64 {
                Suspects::Some{suspects: vec![-b / (a * 2_f64)]}
            }else {
                Suspects::None
            }
        }else {
            let s = d.sqrt();
            if (-b + s) / (a * 2_f64) < 0_f64 {
                Suspects::None
            }else if (-b - s) / (a * 2_f64) < 0_f64 {
                Suspects::Some{suspects: vec![(-b + s) / (a * 2_f64)]}
            }else {
                Suspects::Some{suspects: vec![(-b + s) / (a * 2_f64), (-b - s) / (a * 2_f64)]}
            }
        }
    }
}
fn flatten<T>(vec: &Vec<Vec<T>>) -> Vec<T> where T: Clone + Copy {
    let mut count = 0;
    for v in vec {
        count += v.len();
    }
    let mut result = Vec::with_capacity(count);
    for v in vec {
        for &f in v {
            result.push(f);
        }
    }
    result
}
fn lower_bound<T: PartialOrd>(vec: &Vec<T>, target: &T) -> usize {
    let mut left = 0;
    let mut right = vec.len();
    while left < right {
        let mid = (left + right) / 2;
        if vec[mid].partial_cmp(target).unwrap() == Ordering::Less {
            left = mid + 1;
        }else {
            right = mid;
        }
    }
    right
}
fn upper_bound<T: PartialOrd>(vec: &Vec<T>, target: &T) -> usize {
    let mut left = 0;
    let mut right = vec.len();
    while left < right {
        let mid = (left + right) / 2;
        if vec[mid].partial_cmp(target).unwrap() != Ordering::Greater {
            left = mid + 1;
        }else {
            right = mid;
        }
    }
    right
}
fn show<T>(vec: &Vec<T>) where T: Display {
    if vec.is_empty() {
        println!("[]")
    }else {
        print!("[{}", vec.first().unwrap());
        for i in 1 .. vec.len() {
            print!(", {}", vec[i]);
        }
        println!("]");
    }
}
fn solve(person: &Vec<Person>) -> usize {
    const EPS: f64 = 0.000001;
    let mut max = 0;
    /*
    for &a in person.iter() {
        let mut count =0;
        for &b in person.iter() {
            if a == b {
                count += 1;
            }
        }
        if max < count {
            max = count;
        }
    }
    */
    for a in 0 .. person.len() {
        for b in 0 .. a {
            if person[a] != person[b] {
                let mut count = 2;
                let mut suspects = Vec::new();
                for c in 0..person.len() {
                    if a != c && b != c {
                        match find_on_line_time(&person[a], &person[b], &person[c]) {
                            Suspects::All => {
                                count += 1;
                            },
                            Suspects::None => {}
                            Suspects::Some { suspects: vec } => {
                                for v in vec {
                                    suspects.push(v)
                                }
                            },
                        }
                    }
                }
                suspects.sort_by(|a, b| a.partial_cmp(b).unwrap());
                if count >= max {
                    max = count;
                }
                for &s in &suspects {
                    let c = upper_bound(&suspects, &(s + EPS)) - lower_bound(&suspects, &s);
                    match person[a].position_at(s) - person[b].position_at(s) {
                        PointF { x: x, y: y } if x.abs() >= EPS || y.abs() >= EPS => {
                            if count + c > max {
                                max = count + c;
                            }
                        }
                        _ => {
                            if count + 1 > max {
                                max = count + 1;
                            }
                        }
                    }
                }
            }
        }
    }
    let dummy = Person{initial: Point{x: 11, y: 11}, velocity: Vector{dx: 3, dy: 3}};
    for b in 0 .. person.len() {
        let mut count = 1;
        let mut suspects = Vec::new();
        for c in 0..person.len() {
            if b != c {
                match find_on_line_time(&dummy, &person[b], &person[c]) {
                    Suspects::All => {
                        count += 1;
                    },
                    Suspects::None => {}
                    Suspects::Some { suspects: vec } => {
                        for v in vec {
                            suspects.push(v)
                        }
                    },

                }
            }
        }
        suspects.sort_by(|a, b| a.partial_cmp(b).unwrap());
        if count > max {
            max = count;
        }
        for &s in &suspects {
            let c = upper_bound(&suspects, &(s + EPS)) - lower_bound(&suspects, &s);
            if count + c > max {
                max = count + c;
            }
        }
    }
    max
}




Measured memory_bytes: 5060