#include <iostream>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <algorithm>	// require sort next_permutation count __gcd reverse etc.
#include <cstdlib>	// require abs exit atof atoi 
#include <cstdio>		// require scanf printf
#include <functional>
#include <numeric>	// require accumulate
#include <cmath>		// require fabs
#include <climits>
#include <limits>
#include <cfloat>
#include <iomanip>	// require setw
#include <sstream>	// require stringstream 
#include <cstring>	// require memset
#include <cctype>		// require tolower, toupper
#include <fstream>	// require freopen
#include <ctime>		// require srand
#define rep(i,n) for(int i=0;i<(n);i++)
#define ALL(A) A.begin(), A.end()

using namespace std;

#define EPS (1e-10)
#define PI (3.141592653589793238462643383279)
template<class T>
struct point{
	T x, y;
	point &operator+=(const point &a ){ x += a.x; y += a.y; }
	point &operator-=(const point &a ){ x -= a.x; y -= a.y; }
	point operator+(const point &a )const{ return (point){x+a.x, y+a.y }; }
	point operator-(const point &a )const{ return (point){x-a.x, y-a.y }; }
	operator point<double>()const{ return (point<double>){x, y }; }
};

template<class T>
point<T> operator*(T c, const point<T> &a ){ return (point<T>){c*a.x, c*a.y }; }
point<double> &operator/=(point<double> &a, double c ){ a.x /= c; a.y /= c; return a; }
template<class T>
point<double> operator/(const point<T> &a, double c ){ return (point<double>){ a.x/c, a.y/c }; }

// for integar number
template<class T>
bool operator<(const point<T> &a, const point<T> &b ){
	return (a.x < b.x || ((a.x == b.x ) && (a.y < b.y ) ) );
}

template<class T>
bool operator==(const point<T> &a, const point<T> &b ){
	return a.x == b.x && a.y == b.y;
} 

template<class T>
bool operator!=(const point<T> &a, const point<T> &b ){
	return a.x != b.x || a.y != b.y;
}

//  for real number
bool operator<(const point<double> &a, const point<double> &b ){
	return (a.x + EPS < b.x || (abs (a.x - b.x ) < EPS && (a.y + EPS < b.y ) ) );
}

bool operator==(const point<double> &a, const point<double> &b ){
	return abs (a.x - b.x) < EPS && abs (a.y - b.y ) < EPS;
}

bool operator!=(const point<double> &a, const point<double> &b ){
	return abs (a.x - b.x ) > EPS || abs (a.y - b.y ) > EPS;
}

// inner product
template<class T>
T dot(const point<T> &a, const point<T> &b ){ return a.x*b.x + a.y*b.y; }

// outer product
template<class T>
T cross(const point<T> &a, const point<T> &b ){ return a.x*b.y - a.y*b.x; }

// distance between origin(0,0) to point a
template<class T>
double abs(const point<T> &a ){ return sqrt (a.x*a.x + a.y*a.y ); }

template<class T>
T abs2(const point<T> &a ){ return a.x*a.x + a.y*a.y; }

point<double> rot(const point<double> &a, double theta ){
	return (point<double>){a.x*cos(theta) - a.y*sin(theta), a.x*sin(theta) + a.y*cos(theta ) };
}

// x 軸の正方向を基準とした場合のベクトル a の角度を [0, 2*PI) の範囲で求める
template<class T> double arg(const point<T> &a ){
	double t = atan2(a.y, a.x );
	return t<0.? t+2.*PI : t;
}

template<class T>
struct line{
	point<T> a, b;
	operator line<double>()const{ return (line<double>){a, b}; }
};

template<class T>
struct segment{
	point<T> a, b;
	operator line<T>()const { return (line<T>){a,b}; }
};

template<class T>
struct polygon:vector< point<T> >{
	polygon(){}
	polygon(int n ):vector< point<T> >(n){}
};

template<class T>
struct circle{
	point<T> c;
	T r;
};
/*
	点と点の距離

	説明
		点と点の距離を求める
		dist : 距離そのもの
		dist2 : 距離の二乗
	引数
		a : 点
		b : 点
	戻り値
		点 a と 点 b の距離
	制約
		なし
	計算量
		O(1)
	備考
*/
template<class T>
double dist(const point<T> &a, const point<T> &b ){
	return sqrt ((a.x - b.x )*(a.x - b.x ) + (a.y - b.y )*(a.y - b.y ) );
}

template<class T>
T dist2(const point<T> &a, const point<T> &b ){
	return (a.x - b.x )*(a.x - b.x ) + (a.y - b.y )*(a.y - b.y );
}

/*
	直線と点の距離

	説明
		直線と点の距離を求める
		dist : 距離そのもの
		dist2 : 距離の二乗
	引数
		L : 直線
		p : 点
	戻り値
		直線 L と点 p の距離
	制約
		なし
	計算量
		O(1)
	備考

*/
template<class T>
double dist(const line<T> &L, const point<T> &p ){
	return abs (cross (L.b-L.a, p-L.a))/dist(L.a, L.b );
}

/*
	円と円の共通接線

	説明
		円と円の共通接線を求める
	引数
		C1 : 円
		C2 : 円
		res : 計算結果（接線の場合）
	戻り値
		接線の本数
	計算量
		O(1)
	備考
		res は初期化されない
*/
int tangent(const circle<double> &C1, const circle<double> &C2, vector< line<double> > &res ){
	double d=abs(C1.c-C2.c);
	if (d<EPS ) return 0;	// C1,C2 は同心円上にある

	int c = 0;
	// 内接線
	if(C1.r+C2.r<d-EPS ){
		double t=acos((C1.r+C2.r)/d);
		res.push_back((line<double>){C1.c+rot(C1.r/d*(C2.c-C1.c), t),C2.c+rot(C2.r/d*(C1.c-C2.c), t)});
		res.push_back((line<double>){C1.c+rot(C1.r/d*(C2.c-C1.c),-t),C2.c+rot(C2.r/d*(C1.c-C2.c),-t)});
		c+=2;
	}else
	if (C1.r+C2.r<d+EPS ){
		point<double> p=C1.c+C2.r/d*(C2.c-C1.c);
		res.push_back (line<double>{p,p+rot(C2.c-C1.c,PI/2)});
		c++;
	} // end if
	
	// 外接線
	if (abs(C1.r-C2.r)<d-EPS ){
		double t1=acos((C1.r-C2.r)/d),t2=PI-t1;
		res.push_back((line<double>){C1.c+rot(C1.r/d*(C2.c-C1.c), t1),C2.c+rot(C2.r/d*(C1.c-C2.c),-t2)});
		res.push_back((line<double>){C1.c+rot(C1.r/d*(C2.c-C1.c),-t1),C2.c+rot(C2.r/d*(C1.c-C2.c), t2)});
		c+=2;
	}else
	if (abs(C1.r-C2.r)<d+EPS ){
		point<double> p=C1.c+C1.r/d*(C2.c-C1.c);
		res.push_back((line<double>){p,p+rot(C2.c-C1.c,PI/2)});
		c++;
	} // end if
	
	return c;
}

struct Jew{
	circle<double> c;
	double m;
//	Jew(circle<double> c, double m):circle<double>(c),m(m){}
};
int main()
{
//	cut here before submit 
//	freopen ("testcase.2201", "r", stdin );
	int n;
	while (scanf ("%d", &n ), n ){
		vector<Jew> jew(n);
		rep (i, n ){
			int x, y, r, m;
			scanf ("%d %d %d %d", &x, &y, &r, &m );
			jew[i].c.c.x	= (double)x;
			jew[i].c.c.y	= (double)y;
			jew[i].c.r		= (double)r;
			jew[i].m		= (double)m;
		} // end rep
		int ans = 1;
		rep (i, n ){
			for (int j = i+1; j < n; j++ ){
				Jew j1 = jew[i], j2 = jew[j];
				circle<double> c1 = j1.c, c2 = j2.c;
				Jew j3 = jew[i], j4 = jew[j];
				circle<double> c3=(circle<double>){(point<double>)j3.c.c, (double)j3.c.r+j3.m};
				circle<double> c4=(circle<double>){(point<double>)j4.c.c, (double)j4.c.r+j4.m};
							
				vector< line<double> > l1, l2; l1.clear();l2.clear();
				int cnt1 = tangent (c1, c2, l1 );
				int cnt2 = tangent (c3, c4, l2 );
				rep (a, cnt1 ){
					int cnt = 0;
					rep (b, n ){
						double dis = dist (l1[a], jew[b].c.c );
						if (dis + EPS > jew[b].c.r && dis < jew[b].c.r + jew[b].m + EPS ) cnt++;
					} // end rep
					ans = max (ans, cnt );
				} // end rep
				rep (a, cnt2 ){
					int cnt = 0;
					rep (b, n ){
						double dis = dist (l2[a], jew[b].c.c );
						if (dis + EPS > jew[b].c.r && dis < jew[b].c.r + jew[b].m + EPS ) cnt++;
					} // end rep
					ans = max (ans, cnt );
				} // end rep
			} // end for
		} // end rep
		printf ("%d\n", ans );
	} // end loop
		
	return 0;
}

Measured memory_bytes: 1284