Crazy Town is a plane on which there are n infinite line roads. Each road is defined by the equation aix + biy + ci = 0, where ai and bi are not both equal to the zero. The roads divide the plane into connected regions, possibly of infinite space. Let's call each such region a block. We define an intersection as the point where at least two different roads intersect.

Your home is located in one of the blocks. Today you need to get to the University, also located in some block. In one step you can move from one block to another, if the length of their common border is nonzero (in particular, this means that if the blocks are adjacent to one intersection, but have no shared nonzero boundary segment, then it are not allowed to move from one to another one in one step).

Determine what is the minimum number of steps you have to perform to get to the block containing the university. It is guaranteed that neither your home nor the university is located on the road.

Input

The first line contains two space-separated integers x1, y1 ( - 106 ≤ x1, y1 ≤ 106) — the coordinates of your home.

The second line contains two integers separated by a space x2, y2 ( - 106 ≤ x2, y2 ≤ 106) — the coordinates of the university you are studying at.

The third line contains an integer n (1 ≤ n ≤ 300) — the number of roads in the city. The following n lines contain 3 space-separated integers ( - 106 ≤ ai, bi, ci ≤ 106; |ai| + |bi| > 0) — the coefficients of the line aix + biy + ci = 0, defining the i-th road. It is guaranteed that no two roads are the same. In addition, neither your home nor the university lie on the road (i.e. they do not belong to any one of the lines).

Output

Output the answer to the problem.

Examples

Input

1 1
-1 -1
2
0 1 0
1 0 0


Output

2


Input

1 1
-1 -1
3
1 0 0
0 1 0
1 1 -3


Output

2

Note

Pictures to the samples are presented below (A is the point representing the house; B is the point representing the university, different blocks are filled with different colors):

<image> <image>

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.StringTokenizer;

public class CF2 {
	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner(System.in);
		int x1 = sc.nextInt();
		int y1 = sc.nextInt();
		int x2 = sc.nextInt();
		int y2 = sc.nextInt();
		Line original = new Line(new Point(x1,y1) , new Point(x2,y2));
		int n=sc.nextInt();
		int count=0;
		for(int i=0;i<n;i++)
		{
			int a = sc.nextInt();
			int b = sc.nextInt();
			int c = sc.nextInt();
			Line l = new Line(a,b,c);
			Point point = l.intersect(original);
			//System.out.println(point);
			if(point!=null && point.between(new Point(x1,y1), new Point(x2,y2)))
				count++;
		}
		System.out.println(count);
	}

}
class Point implements Comparable<Point>{

	static final double EPS = 1e-9;

	double x, y;                  

	Point(double a, double b) 
	{ 
		x = a; y = b; 
	}  

	public String toString()
	{
		return x+" "+y;
	}

	public int compareTo(Point p)
	{
		if(Math.abs(x - p.x) > EPS) return x > p.x ? 1 : -1;
		if(Math.abs(y - p.y) > EPS) return y > p.y ? 1 : -1;
		return 0;
	}

	public double dist(Point p) { return Math.sqrt(sq(x - p.x) + sq(y - p.y)); }

	static double sq(double x) { return x * x; }

	Point rotate(double angle)				//rotate around (0,0)
	{
		double c = Math.cos(angle), s = Math.sin(angle);
		return new Point(x * c - y * s, x * s + y * c);
	}
	// for integer points and rotation by 90 (counterclockwise) : swap x and y, negate x

	Point rotate(double theta, Point p)			//rotate around p
	{
		Vector v = new Vector(p, new Point(0, 0));
		return translate(v).rotate(theta).translate(v.reverse());
	}

	Point translate(Vector v) { return new Point(x + v.x , y + v.y); }

	Point reflectionPoint(Line l) 	//reflection point of p on line l
	{
		Point p = l.closestPoint(this);
		Vector v = new Vector(this, p);
		return this.translate(v).translate(v);
	}

	boolean between(Point p, Point q)			//it means that it is inside the rectangle created by these points , not on their line
	{
		return x <= Math.max(p.x, q.x) + EPS && x + EPS >= Math.min(p.x, q.x)
				&& y <= Math.max(p.y, q.y) + EPS && y + EPS >= Math.min(p.y, q.y);
	}

	//returns true if it is on the line defined by a and b
	boolean onLine(Point a, Point b) 
	{
		if(a.compareTo(b) == 0) return compareTo(a) == 0;
		return Math.abs(new Vector(a, b).cross(new Vector(a, this))) < EPS;
	}

	boolean onSegment(Point a, Point b)
	{
		if(a.compareTo(b) == 0) return compareTo(a) == 0;
		return onRay(a, b) && onRay(b, a);
	}

	//returns true if it is on the ray whose start point is a and passes through b
	boolean onRay(Point a, Point b)
	{
		if(a.compareTo(b) == 0) return compareTo(a) == 0;
		return new Vector(a, b).normalize().equals(new Vector(a, this).normalize());
	}

	// returns true if r is on the left side of line pq (the order is of course importanrt)
	//if true  then p->q->r in counterclockwise direction
	//if false then p->q->r in clockwise direction
	// add EPS to LHS to accepts collinear points (means >=)
	static boolean ccw(Point p, Point q, Point r)			//positive cross product means counter-clockwise
	{
		return new Vector(p, q).cross(new Vector(p, r)) > 0;
	}

	static boolean collinear(Point p, Point q, Point r)
	{
		return Math.abs(new Vector(p, q).cross(new Vector(p, r))) < EPS;			//cross and dot are on vectors only
	}

	static double angle(Point a, Point o, Point b)  // angle AOB
	{
		Vector oa = new Vector(o, a), ob = new Vector(o, b);
		return Math.acos(oa.dot(ob) / Math.sqrt(oa.norm2() * ob.norm2()));			// it returns a positive angle
	}

	static double distToLine(Point p, Point a, Point b) //distance between point p and a line defined by points a, b (a != b)
	{
		if(a.compareTo(b) == 0) return p.dist(a);
		// formula: c = a + u * ab
		Vector ap = new Vector(a, p), ab = new Vector(a, b);
		double u = ap.dot(ab) / ab.norm2();			//u is a unit vector    // note here we divide by the square of ab (norm2)
		// to generate a ratio of the projection to the ab
		// hna momkn  el u tkon negative aw >1 3ady f kol 7aga hatzbot
		Point c = a.translate(ab.scale(u)); 
		return p.dist(c);
	}
	// Another way: find closest point and calculate the distance between it and p

	static double distToLineSegment(Point p, Point a, Point b) 
	{
		Vector ap = new Vector(a, p), ab = new Vector(a, b);
		double u = ap.dot(ab) / ab.norm2();
		if (u < 0.0) return p.dist(a);
		if (u > 1.0) return p.dist(b);   
		//8eer kda bat3aml m3ah ka2eno line 3ady 5las !
		return distToLine(p, a, b); 
	}
	// Another way: find closest point and calculate the distance between it and p
}
class Vector {

	double x, y; 

	Vector(double a, double b) { x = a; y = b; }

	Vector(Point a, Point b) { this(b.x - a.x, b.y - a.y); }

	Vector scale(double s) { return new Vector(x * s, y * s); }              //s is a non-negative value

	double dot(Vector v) { return (x * v.x + y * v.y); }

	double cross(Vector v) { return x * v.y - y * v.x; }

	double norm2() { return x * x + y * y; }					//only returns norm squared

	Vector reverse() { return new Vector(-x, -y); }

	Vector normalize() 					//get the unit vector of this vector
	{ 
		double d = Math.sqrt(norm2());
		return scale(1 / d);
	}		
}

class Scanner 
{
	StringTokenizer st;
	BufferedReader br;

	public Scanner(InputStream s){	br = new BufferedReader(new InputStreamReader(s));}

	public String next() throws IOException 
	{
		while (st == null || !st.hasMoreTokens()) 
			st = new StringTokenizer(br.readLine());
		return st.nextToken();
	}

	public int nextInt() throws IOException {return Integer.parseInt(next());}

	public long nextLong() throws IOException {return Long.parseLong(next());}

	public String nextLine() throws IOException {return br.readLine();}

	public double nextDouble() throws IOException
	{
		String x = next();
		StringBuilder sb = new StringBuilder("0");
		double res = 0, f = 1;
		boolean dec = false, neg = false;
		int start = 0;
		if(x.charAt(0) == '-')
		{
			neg = true;
			start++;
		}
		for(int i = start; i < x.length(); i++)
			if(x.charAt(i) == '.')
			{
				res = Long.parseLong(sb.toString());
				sb = new StringBuilder("0");
				dec = true;
			}
			else
			{
				sb.append(x.charAt(i));
				if(dec)
					f *= 10;
			}
		res += Long.parseLong(sb.toString()) / f;
		return res * (neg?-1:1);	
	}

	public boolean ready() throws IOException {return br.ready();}
}

class LineSegment implements Comparable {

	Point p, q ;
	double transp;
	LineSegment(Point a, Point b) { p = a; q = b; }

	LineSegment(Point a, Point b , double x) { p = a; q = b; transp=x;}


	boolean intersect(LineSegment ls)
	{
		Line l1 = new Line(p, q), l2 = new Line(ls.p, ls.q);
		if(l1.parallel(l2))
		{
			if(l1.same(l2))
				return p.between(ls.p, ls.q) || q.between(ls.p, ls.q) || ls.p.between(p, q) || ls.q.between(p, q);
			return false;
		}
		Point c = l1.intersect(l2);
		return c.between(p, q) && c.between(ls.p, ls.q) ;
	}

	Point rightPoint()
	{
		if(p.x>q.x)
			return p;
		else
			return q;
	}
	Point leftPoint()
	{
		if(p.x<q.x)
			return p;
		else
			return q;
	}


	@Override
	public int compareTo(Object o) {
		LineSegment line = (LineSegment) o;
		if(Math.abs(line. leftPoint().y-leftPoint().y)<0)
		{
			//return 0;
			if(line.rightPoint().y>leftPoint().y)
				return -1;
			if(line.rightPoint().y<leftPoint().y)
				return 1;
			return 0;
		}
		if(line. leftPoint().y> leftPoint().y)
			return -1;
		else
			if(line. leftPoint().y< leftPoint().y)
				return 1;
		return 0;
	}

}


class Polygon { 
	// Cases to handle: collinear points, polygons with n < 3

	static final double EPS = 1e-9;

	Point[] g; 			//first point = last point, counter-clockwise representation

	Polygon(Point[] o) { g = o; }		//hya da5la bel a5era elzyada

	double perimeter()
	{
		double sum = 0.0;
		for(int i = 0; i < g.length - 1; ++i)
			sum += g[i].dist(g[i+1]);
		return sum;
	}

	double area() 		//clockwise/anti-clockwise check, for convex/concave polygons
	{
		//the method that sums areas of trapezoids under each line i.e summation( y[i]*x[i+1] - x[i]*y[i+1] ) from i=0 to i=n-1
		double area = 0.0;
		for(int i = 0; i < g.length - 1; ++i)
			area += g[i].x * g[i+1].y - g[i].y * g[i+1].x;
		return Math.abs(area) / 2.0;			//negative value in case of clockwise
	}

	boolean isConvex()
	{
		if(g.length <= 3) // point or line
			return false;
		boolean ccw = Point.ccw(g[g.length - 2], g[0], g[1]);		//edit ccw check to accept collinear points
		for(int i = 1; i < g.length - 1; ++i)
			if(Point.ccw(g[i-1], g[i], g[i+1]) != ccw)
				return false;
		return true;
	}

	boolean inside(Point p)	//for convex/concave polygons - winding number algorithm 
	{
		double sum = 0.0;
		for(int i = 0; i < g.length - 1; ++i)
		{
			double angle = Point.angle(g[i], p, g[i+1]);			//always positive
			//if angle is zero or 180 -> it lies on the polygon so return true
			if((Math.abs(angle) < EPS || Math.abs(angle - Math.PI) < EPS) && p.between(g[i], g[i+1]))
				return true;
			if(Point.ccw(p, g[i], g[i+1]))		//if it is clockwise angle -> add else -> subtract
				sum += angle;
			else
				sum -= angle;
		}

		return Math.abs(2 * Math.PI - Math.abs(sum)) < EPS;		//abs makes it work for clockwise
	}
	/*
	 * Another way if the polygon is convex
	 * 1. Triangulate the poylgon through p
	 * 2. Check if sum areas == poygon area
	 * 3. Handle empty polygon
	 */

	Polygon cutPolygon(Point a, Point b)	//returns the left part of the polygon, swap a & b for the right part
	{
		Point[] ans = new Point[g.length<<1];
		Line l = new Line(a, b);
		Vector v = new Vector(a, b);

		int size = 0;
		for(int i = 0; i < g.length; ++i)
		{
			double left1 = v.cross(new Vector(a, g[i]));
			double left2 = i == g.length - 1 ? 0 : v.cross(new Vector(a, g[i+1]));		//ba5leh b zero fela5er 3shan mayd5olsh elcondition elly ta7t

			if(left1 + EPS > 0)	
				ans[size++] = g[i];
			if(left1 * left2 + EPS < 0)				//this condition succeeds if left1 and left2 have opposite signs 3shan ya5odhom ray7 rag3 !!
				ans[size++] = l.intersect(new Line(g[i], g[i+1]));
		}

		if(size != 0 && ans[0] != ans[size-1])	//necessary in case g[0] is not in the new polygon
			ans[size++] = ans[0];
		return new Polygon(Arrays.copyOf(ans, size));
	}

	static Polygon convexHull(Point[] points)	//all points are unique, remove duplicates, edit ccw to accept collinear points
	{
		int n = points.length;
		Arrays.sort(points);
		Point[] ans = new Point[n<<1];
		int size = 0, start = 0;

		for(int i = 0; i < n; i++)
		{
			Point p = points[i];
			while(size - start >= 2 && !Point.ccw(ans[size-2], ans[size-1], p))	--size;
			ans[size++] = p;
		}
		start = --size;

		for(int i = n-1 ; i >= 0 ; i--)
		{
			Point p = points[i];
			while(size - start >= 2 && !Point.ccw(ans[size-2], ans[size-1], p))	--size;
			ans[size++] = p; 
		}
		//			if(size < 0) size = 0			for empty set of points
		return new Polygon(Arrays.copyOf(ans, size));			
	}

	Point centroid()		//center of mass
	{
		double cx = 0.0, cy = 0.0;
		for(int i = 0; i < g.length - 1; i++)
		{
			double x1 = g[i].x, y1 = g[i].y;
			double x2 = g[i+1].x, y2 = g[i+1].y;

			double f = x1 * y2 - x2 * y1;
			cx += (x1 + x2) * f;
			cy += (y1 + y2) * f;
		}
		double area = area();		//remove abs
		cx /= 6.0 * area;
		cy /= 6.0 * area;
		return new Point(cx, cy);
	}
	static double polygonArea (int numberOfSides , double SideLength)
	{
		return (SideLength*SideLength*numberOfSides)/ ( 4* Math.tan(Math.PI/numberOfSides) );
	}
}

class Line {

	static final double INF = 1e9, EPS = 1e-9;
	//we always try to make b=1 , if it is 0 then we make a=1
	//herein this representation a =-slope
	double a, b, c;

	Line(Point p, Point q)			//two options :    a=1 , b=0    (vertical)      OR   a=constant , b=1
	{
		if(Math.abs(p.x - q.x) < EPS) {	a = 1; b = 0; c = -p.x;	}	// x-s are equal --> the line is vertical ( a*x + 0*y + c = 0 )
		else
		{
			a = (p.y - q.y) / (q.x - p.x);				//slope = -a/b (ax+by+c=0)
			b = 1.0;
			c = -(a * p.x + p.y);
		}

	}
	Line(double hh , double w , double e)
	{
		if(w==0)
		{
			a=1;b=0;c=e/hh;
		}
		else
		{
			a=hh*1.0/w;b=1;c=e*1.0/w;
		}
	}
	//constructing a line using a point and a slope
	Line(Point p, double m) { a = -m; b = 1; c =  -(a * p.x + p.y); } 

	boolean parallel(Line l) { return Math.abs(a - l.a) < EPS && Math.abs(b - l.b) < EPS; }

	boolean same(Line l) { return parallel(l) && Math.abs(c - l.c) < EPS; }

	Point intersect(Line l)
	{
		if(parallel(l))
			return null;
		double x = (b * l.c - c * l.b) / (a * l.b - b * l.a);				//using crammer
		double y;
		if(Math.abs(b) < EPS)			//check whether if the first is vertical or not
			y = -l.a * x - l.c;
		else
			y = -a * x - c;

		return new Point(x, y);
	}

	boolean intersectWithSegment(LineSegment l)
	{
		Point point = intersect(new Line(l.p,l.q));
		return (point!=null &&point.onSegment(l.p, l.q));

	}

	Point closestPoint(Point p)
	{
		if(Math.abs(b) < EPS) return new Point(-c, p.y);
		if(Math.abs(a) < EPS) return new Point(p.x, -c);
		return intersect(new Line(p, 1 / a));
	}

}