Problem: You are given N non-overlapping circles in xy-plane. The radius of each circle varies, but the radius of the largest circle is not double longer than that of the smallest.

<image>

Figure 1: The Sample Input

The distance between two circles C1 and C2 is given by the usual formula

<image>

where (xi, yi ) is the coordinates of the center of the circle Ci, and ri is the radius of Ci, for i = 1, 2.

Your task is to write a program that finds the closest pair of circles and print their distance.



Input

The input consists of a series of test cases, followed by a single line only containing a single zero, which indicates the end of input.

Each test case begins with a line containing an integer N (2 ≤ N ≤ 100000), which indicates the number of circles in the test case. N lines describing the circles follow. Each of the N lines has three decimal numbers R, X, and Y. R represents the radius of the circle. X and Y represent the x- and y-coordinates of the center of the circle, respectively.

Output

For each test case, print the distance between the closest circles. You may print any number of digits after the decimal point, but the error must not exceed 0.00001.

Example

Input

4
1.0 0.0 0.0
1.5 0.0 3.0
2.0 4.0 0.0
1.0 3.0 4.0
0


Output

0.5

Solution (in CPP):

Solution:
#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-6)
#define PI (3.141592653589793238462643383279)
template<class T>
struct point{
	T x, y;
	double r;
	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;
};

// 点 p を直線 L 上に射影した点を求める
// 	Verified: AOJ 0081 A Symmetric Point
template<class T>
point<double> proj(const point<T> &p, const line<T> &L ){
	return L.a + dot (p-L.a, L.b-L.a )/abs2 (L.b - L.a )*(L.b - L.a );
}

/*
	三角形の面積（外積）

	説明
		三頂点で定まる三角形の面積（の２倍）を求める
	引数
		a : 頂点
		b : 頂点
		c : 頂点
	戻り値
		三角形の面積の２倍
		縮退しているときは 0
	制約
		なし
	計算量
		O(1)
	備考
		２倍を返しているのは、座標値が整数のときにはこの値も整数になるから。
*/
template<class T>
T area2(const point<T> &a, const point<T> &b, const point<T> &c ){
	return abs(cross(b-a,c-a));
}
/*
	三角形の面積（Heron）

	説明
		三辺の長さで定まる三角形の面積を求める
	引数
		a : 一辺の長さ
		b : 一辺の長さ
		c : 一辺の長さ
	戻り値
		三角形の面積
		三角形が作れないとき、縮退しているときには 0
	制約
		a>=0, b>=0, c>=0
		a<b+c, b<c+a, c<a+b（三角形の成立条件）
	計算量
		O(1)
	備考
		三角形が縮退しているときは nan を返すかもしれない
*/
double area(double a, double b, double c ){
	return sqrt((a+b-c)*(b+c-a)*(c+a-b)*(a+b-c))/4.;
}

/*
	多角形の面積

	説明
		多角形の面積（２倍）を求める
	引数
		G : 多角形
	戻り値
		三角形の面積の２倍
		縮退しているときは 0
	制約
		G は単純
	計算量
		O(n)
	備考
		２倍を返しているのは、座標値が整数のときにはこの値も整数になるから。
		多角形は CCW でも CW でもよい

		Verified: AOJ 0079: Area of Polygon
*/
template<class T>
T area2(const polygon<T> &G ){
	int n = G.size();
	T a = 0;
	rep (i, n ) a+=cross(G[i], G[(i+1)%n] );
	return abs (a );
}

/*
	回転方向

	説明
		３点の位置関係を求める
		(A) 座標値が整数
		(B) 座標値が実数
	引数
		a : 点
		b : 点
		c : 点
	戻り値
		a-b-c の順に反時計回りに回転しているとき CCW
		a-b-c の順に時計回りに回転しているとき CW
		a-b-c が同一直線上にあるとき ON
	制約
		なし
	計算量
		O(1)
	備考
		2 点以上が同一の点であれば常に ON を返すことに注意

*/

// (A)
enum{CCW = 1, CW = -1, ON = 0 };
template<class T>
int ccw(const point<T> &a, const point<T> &b, const point<T> &c ){
	T rdir = cross (b-a, c-a );
	if (rdir > 0 ) return CCW;
	if (rdir < 0 ) return CW;
	return ON;
}

// (B)

//enum{CCW = 1, CW = -1, ON = 0 };
int ccw (const point<double> &a, const point<double> &b, const point<double> &c ){
	double rdir = cross (b-a, c-a );
	if (rdir > 0 ) return CCW;
	if (rdir < 0 ) return CW;
	return ON;
}

/*
	反時計回りに変換

	説明
		多角形の頂点の順番が CW であれば CCW に変換する
		元々 CCW であれば何もしない
		(A) 座標値が整数
		(B) 座標値が実数
	引数
		G : 多角形
	戻り値
		なし（引数 G が更新される）
	制約
		G は単純
	計算量
		O(n)
	備考
		単純多角形とは自己交差しない多角形のこと
		Verified: AOJ 0035: Is it Convex?
*/
// (A)
template<class T>
void to_ccw(polygon<T> &G ){
	int n = G.size();
	T A = 0;
	rep (i, n ) A+=cross(G[i], G[(i+1)%n] );
	if (A < 0 ) reverse (ALL (G ) );
}

// (B)
void to_ccw(polygon<double> &G ){
	int n = G.size();
	double A = 0.;
	rep (i, n ) A+=cross(G[i], G[(i+1)%n] );
	if (A<-EPS ) reverse (ALL (G ) );
}

/*
	点と点の距離

	説明
		点と点の距離を求める
		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 );
}

/*
	線分と点の距離

	説明
		線分と点の距離を求める
		dist : 距離そのもの
		dist2 : 距離の２乗
	引数
		S : 線分
		p : 点
	戻り値
		線分 S と点 p の距離
	計算量
		O(1)
	備考
		dist2 は <= 0 で正しい。(ESP を使わなくてよい. )
	
*/
template<class T>
double dist(const segment<T> &S, const point<T> &p ){
	if (dot (S.b-S.a, p-S.a ) <= 0 ) return dist (p, S.a );
	if (dot (S.a-S.b, p-S.b ) <= 0 ) return dist (p, S.b );
	return abs (cross (S.b-S.a, p - S.a ) )/dist (S.a, S.b );
}

template<class T>
double dist2(const segment<T> &S, const point<T> &p ){
	if (dot (S.b-S.a, p-S.a ) <= 0 ) return dist2 (p, S.a );
	if (dot (S.a-S.b, p-S.b ) <= 0 ) return dist2 (p, S.b );
	return (double)cross (S.b-S.a, p - S.a )*cross (S.b-S.a, p - S.a )/dist (S.a, S.b );
}

/*
	線分と線分の距離
*/

/*
	三角形と点の包含判定

	説明
		三角形 abc が点 p を含むかどうかを判定する
	引数
		a : 頂点
		b : 頂点
		c : 頂点
	戻り値
		含むなら true, 含まないなら false
	制約
		三角形は縮退していないこと
		すなわち、三点が同一直線上にないこと、（特に、どの二点も等しくないこと
	計算量
		O(1)
	備考
		三角形は CCW でも CW でもよい
		点が三角形の境界になるときは含むと判定する
		Verified: AOJ 0012: A Point in a Triangle
		Verified: AOJ 0143: Altair and Vega 
*/
template<class T>
bool cover(const point<T> &a, const point<T> &b, const point<T> &c, const point<T> &p ){
	int d1 = ccw (p, a, b );
	int d2 = ccw (p, b, c );
	int d3 = ccw (p, c, a );
	return !((d1 == CCW && d2 == CW ) || (d1 == CCW && d3 == CW ) || (d2 == CCW && d3 == CW ) || (d1 == CW && d2 == CCW ) || (d1 == CW && d3 == CCW ) || (d2 == CW && d3 == CCW ) );
}

/*
	直線と点の包含判定
*/

/*
	線分と点の包含判定
*/

/*
	多角形と点の包含判定
*/

/*
	多角形と多角形の包含判定
*/

/*
	円と点の包含判定

	説明
		円が点を含むかどうかを判定する
		(A) 座標値が整数
		(B) 座標値が実数
	引数
		C : 円
		p : 点
	戻り値
		含むなら true, 含まないなら false
	制約
		なし
	計算量
		O(1)
	備考
*/
// (A)
template<class T>
bool cover (const circle<T> &C, const point<T> &p ){
	return dist2(C.c, p) <= C.r*C.r;
}

// (B)
bool cover (const circle<double> &C, const point<double> &p ){
	return dist (C.c, p ) < C.r + EPS;
}

/*
	直線と直線の交差判定
*/

/*
	直線と線分の交差判定
*/

/*
	線分と線分の交差判定

	説明
		線分と線分が交わるかどうかを判定する
		(A) 座標値が整数
		(B) 座標値が実数
	引数
		S1 : 線分
		S2 : 線分
	戻り値
		交わるなら true, 交わらないなら false
	制約
		なし
	計算量
		O(1)
	備考
		bounding box によるラフチェックは必要。（ ccw による判定だと、二線分が同一直線上にあるとき間違う。)

*/
// (A)
template<class T>
bool intersect(const segment<T> &S1, const segment<T> &S2 ){
	if (max (S1.a.x, S1.b.x ) < min (S2.a.x, S2.b.x )
	|| max (S1.a.y, S1.b.y ) < min (S2.a.y, S2.b.y )
	|| max (S2.a.x, S2.b.x ) < min (S1.a.x, S1.b.x )
	|| max (S2.a.y, S2.b.y ) < min (S1.a.y, S1.b.y ) ) return false;
	return ccw (S1.a, S1.b, S2.a )*ccw (S1.a, S1.b, S2.b ) <= 0
		&& ccw (S2.a, S2.b, S1.a )*ccw (S2.a, S2.b, S1.b ) <= 0;
}

/*
	多角形と線分の交差判定

	説明
		多角形と線分が交わるかどうかを判定する
	引数
		G : 多角形
		S : 線分
	戻り値
		交わるなら true, 交わらないなら false
	制約
		なし
	計算量
		O(n)
	備考
		G は凸でなくていい。
		G は境界を含む
		S が G の内部にあるときは交わると判定する
*/
template<class T>
bool intersect(const polygon<T> &G, const segment<T> &S ){
	int n = G.size();
	if (cover(G, S.a ) || cover (G, S.b ) ) return true;
	rep (i, n ) if (intersect((segment<T>){G[i], G[(i+1)%n]}, S ) ) return true;
	return false;
}

/*
	多角形と多角形の交差判定
*/

/*
	円と直線の交差判定

	説明
		円と直線が交わるかどうかを判定する
	引数	
		C: 円
		L: 直線
	戻り値
		交点の個数
	制約
		なし
	計算量
		O(1)
	備考
		
*/
int intersect(const circle<double> &C, const line<double> &L ){
	point<double> m=proj(C.c, L );
	double d = abs (C.c - m );
	if (C.r + EPS < d ) return 0;
	if (C.r - EPS < d ) return 1;
	return 2;
}

/*
	円と線分の交差判定

	説明
		円と線分が交わるかどうかを判定する
		(A) 座標値が整数
		(B) 座標値が実数
	引数
		C : 円
		S : 線分
	戻り値
		交わるなら true 交わらないなら false
	制約
		なし
	計算量
		O(1)
	備考
		線分が円の内部になるときは交わると判定する。
*/
// (A)
template<class T>
bool intersect(const circle<T> &C, const segment<T> &S ){
	return dist2(S, C.c ) <= C.r*C.r;
}
// (B)
bool intersect(const circle<double> &C, const segment<double> &S ){
	return dist(S, C.c ) < C.r + EPS;
}

/*
	二直線の交点

	説明
		二直線の交点を求める
		(A)（直線を特徴付ける点の）座標値が整数
		(B)（直線を特徴付ける点の）座標値が実数
	引数
		L1 : 直線
		L2 : 直線
	戻り値
		L1 と L2 の交点
	制約
		二直線は交点を持つこと。（平行でない or L1 == L2 )
	計算量
		O(1)
	備考
		交点が複数あるとき（L1 == L2）は L1.a を返す。
		この仕様は線分 S と直線 L の交点を求めたいとき重要。
		（ S と L が同一直線上にあるときにも、S を第１引数に指定することで交点が正しく求まる。）

*/
// (A)
template<class T>
point<double> get_intersect(const line<T> &L1, const line<T> &L2 ){
	double a1=cross(L1.b-L1.a,L2.b-L2.a);
	double a2=cross(L1.b-L1.a,L1.b-L2.a);
	if (a1==0) return L1.a;	// L1 == L2
	return (point<double>)L2.a+a2/a1*(point<double>)(L2.b-L2.a);
}
// (B)
point<double> get_intersect(const line<double> &L1, const line<double> &L2 ){
	double a1=cross(L1.b-L1.a,L2.b-L2.a);
	double a2=cross(L1.b-L1.a,L1.b-L2.a);
	if (a1<EPS) return L1.a;	// L1 == L2
	return L2.a+a2/a1*(L2.b-L2.a);
}

/*
	二線分の交点
*/

/*
	円と直線の交点
*/

/*
	円と円の交点

	説明
		円と円の交点を求める
	引数
		C1 : 円
		C2 : 円
		res : 計算結果（交点の集合）
	戻り値
		交点の個数
		ただし、交点が無限個になる（２つの円が等しい）ときは -1
	制約
		なし
	計算量
		O(1)
	備考
		res は初期化されない
		交点が無限個あるときは res には何も追加されない
		Verified: AOJ 0090 Overlaps of Seals
*/
int get_intersect(const circle<double> &C1, const circle<double> &C2, vector< point<double> > &res ){
	double r1=C1.r,r2=C2.r;
	point<double> p1=C1.c,p2=C2.c;

	double d=abs(p1-p2);
	if (d<EPS && abs(r1-r2)<EPS ){	// C1 == C2
		return -1;
	}else
	if (r1+r2<d-EPS || d+EPS<abs(r1-r2) ){
		return 0;
	}else{
		double a = (r1*r1-r2*r2+d*d)/(2.*d);
		double h = sqrt(max(r1*r1-a*a, 0. ) );
		point<double> tmp1 = p1+a/d*(p2-p1);
		point<double> tmp2 = h/d*(p2-p1);
		if (abs(tmp2)<EPS ){
			res.push_back (tmp1 );
			return 1;
		}else{
			res.push_back ((point<double>){tmp1.x-tmp2.y, tmp1.y+tmp2.x});
			res.push_back ((point<double>){tmp1.x+tmp2.y, tmp1.y-tmp2.x});
			return 2;
		} // end if
	} // end if
}

/*
	点から円に引いた接線の交点
*/

/*
	円と円の共通接線
*/

/*
	垂直二等分線

	説明
		二点 a, b の垂直二等分線を求める
	引数
		a : 点
		b : 点
	戻り値
		a と b の垂直二等分線
	計算量
		O(1)
	備考
		垂直二等分線を L とすると、L.a から L.b の方向を見たとき、左手に点 a が来る。
*/
template<class T>
line<double> perp_bisector(const point<T> &a, const point<T> &b ){
	return (line<double>){(point<double>){(a.x-a.y+b.x+b.y)/2.0, (a.y+a.x+b.y-b.x)/2.0 },
							(point<double>){(a.x+a.y+b.x-b.y)/2.0, (a.y-a.x+b.y+b.x)/2.0 }};
}

/*
	点対称

	説明
		点 b を基準に点 a を点対称を求める
	引数
		a : 点
		b : 点
	戻り値
		点対称の点
	計算量
		O(1)
	備考

*/
template<class T>
point<T> symmetry_point (const point<T> a, const point<T> b )
{
	return (point<T>){2*b.x-a.x, 2*b.y-a.y};
}

/*
	多角形の重心の座標

	説明
		頂点数 n の凸多角形をひとつの頂点を基準に n - 2 個の三角形に分割した三角形の面積を Sk,
		重心を gk とおくと n の凸多角形の重心 G は

		G = \sum_{k=1}^{n-2}Sk*gk/(\sum_{k=1}^{n-2}Sk)

		で求められる。
	引数
		G : 多角形
	戻り値
		点
	計算量
		O(n)
	備考
		Verified: AOJ 2442: ConvexCut しかし EPS=1e-6 にしないと WA.
*/
template<class T>
point<T> centerG(const polygon<T> &G ){
	int n = G.size();
	double S = 0.;
	point<double> g; g.x = 0.; g.y = 0.;
	int u = G.size()-1;
	for (int i = 0; i < n; u=i++ ){
		double sk = cross (G[u], G[i] );
		S += sk;
		g.x += (G[u].x + G[i].x)*sk;
		g.y += (G[u].y + G[i].y)*sk;
	} // end for
	g /= (3.*S);

	return g;
/*
	int n = G.size();
	double ar = 0.;
	double x = 0., y = 0.;
	rep (i, n - 2 ){
		double k = area2 (G[n-1], G[i], G[i+1] );
		ar += k;
		x += (G[n-1].x + G[i].x)*k;
		y += (G[n-1].y + G[i].y)*k;
	} // end rep
	x /= (3.*ar );
	y /= (3.*ar );
	
	return (point<T>){x,y};
*/
}

/*
	二点と半径で定まる円
*/

/*
	凸性判定
	
	説明
		多角形が凸かどうかを判定する
	引数
		G : 多角形
	戻り値
		G は単調かつ頂点の順番が CCW で与えられていること
	計算量
		O(n)
	備考
		Verified: AOJ 0035: Is it Convex?
*/
template<class T>
bool is_convex(const polygon<T> &G ){
	int n = G.size();
	rep (i, n ) if (ccw (G[i], G[(i+1)%n], G[(i+2)%n])== CW ) return false;
	return true;
}

/*
	凸包

	説明
		点集合の凸包を求める
	引数
		P : 点集合
	戻り値
		P の凸包
	制約
		なし
	計算量
		O(n log n )
	備考
		P は破壊される。

		sort は (x, y ) の辞書順。

		凸包の同じ直線上にある頂点は端のものだけを拾う。
		辺上になる頂点を全部拾うようにしたいときは != CCW を ==CW と修正すればよい。
*/
template<class T>
polygon<T> convex_hull(vector< point<T> > &P ){
	int n = P.size();
	polygon<T> CH;
	if (n <= 1 ){
		CH.insert (CH.end(), P.begin(), P.end() );
		return CH;
	} // end if
	sort (ALL (P ) );
	rep (cnt, 2 ){
		int m = 0;
		vector< point<T> > half(n );
		rep (i, n ){
			half[m++] = P[i];
			while (m >= 3 && ccw (half[m-3], half[m-2], half[m-1] ) != CCW ){
				half[m-2] = half[m-1];
				m--;
			} // end while
		} // end rep
		CH.insert (CH.end(), half.begin(), half.begin()+m-1 );
		reverse (ALL (P ) );
	} // end rep
	
	return CH;
}

/*
	凸多角形の切断
*/

/*
	内接円の半径

	説明
		辺長がそれぞれ、a, b, c である三角形の内接円の半径を求める
	引数
		a: 辺長
		b: 辺長
		c: 辺長
	戻り値
		内接円の半径
	制約
		a >= 0, b >= 0, c >= 0
		a < b + c, c < c + a, c < a + b (三角形の成立条件)
	計算量
		O(1)
	備考
		三角形が縮退しているときは nan を返すかもしれない
*/
double inradius(double a, double b, double c ){
	return sqrt ((b+c-a)*(c+a-b)*(a+b-c)/(a+b+c))/2.;
}

/*
	外接円

	説明
		三角形 abc の外接円を求める
	引数
		a: 頂点
		b: 頂点
		c: 頂点
	戻り値
		外接円
	制約
		a, b, c は同一直線上にないこと
	計算量
		O(1)
	備考
		a, b, c が同一直線上にあるときは外接円は存在しない
		頂点が整数座標のとき、外心の座標と半径の二乗は有理数となる

		Verified: AOJ 0010 Circumscribed Circle of a Triangle

*/
circle<double> circumcircle(const point<double> &a, point<double> b, point<double> c ){
	b-=a; c-=a;
	double A2 = abs2(b-c), B2 = abs2(b), C2 = abs2(c);
	double d = 2*cross(b,c);
	double nx = c.y*B2-b.y*C2;
	double ny = b.x*C2-c.x*B2;
	double r2 = A2*B2*C2/(d*d);
	return (circle<double>){a+(point<double>){nx/d, ny/d}, sqrt(r2)};
}

/*
	外接円の半径
	
	説明
		辺長がそれぞれ a, b, c である三角形の外接円の半径を求める
	引数
		a : 辺長
		b : 辺長
		c : 辺長
	戻り値
		外接円の半径
	制約
		a >= 0, b >= 0, c >= 0
		a < b + c, b < c + a, c < a + b (三角形の成立条件)
	計算量
		O(1)
	備考
		三角形が縮退しているときは nan を返すかもしれない

		Verified: AOJ 0010 Circumscribed Circle of a Triangle

*/
double circumradius(double a, double b, double c ){
	return a*b*c/sqrt((a+b+c)*(b+c-a)*(c+a-b)*(a+b-c) );
}

/*
	最小包含球
*/

/*
	線分アレンジメント
*/

/*
	最近点対

	説明
		最近点対問題を解く
	引数
		n : 点の個数
		p : 点集合
	戻り値
		最近点対の距離
	制約
		n>=2
	計算量
		O(n log n)
	備考
		sort は (x,y) の辞書順。
		P の順番は破壊される（内部でソートするため）
*/
struct cmp_y{
bool operator()(const point<double> &a, const point<double> &b ){
	return (a.y+EPS<b.y || (abs(a.y-b.y)<EPS && a.x+EPS<b.x ) );
}};


double closest_pair(int n, point<double> *P ){
	double r_max = 0.;
	rep (i, n ) r_max = max (r_max, P[i].r );
	sort (P, P+n );
	double d = dist(P[0],P[1] ) - P[0].r - P[1].r;
	set<point<double>, cmp_y> S;
	set<point<double>, cmp_y>::iterator it_l, it_r, it;
	for (int i = 0, j = 0; i < n; i++ ){
		it_l = S.lower_bound ((point<double>){0,P[i].y-d-1.-2.*r_max});
		it_r = S.upper_bound ((point<double>){0,P[i].y+d+1.+2.*r_max});
		for (it=it_l;it!=it_r;++it) d=min(d, dist(*it,P[i])-(it->r)-P[i].r);
		while(P[i].x-P[j].x>d+2.*r_max+EPS ) S.erase(P[j++] );
		S.insert(P[i] );
	} // end for

	return d;
}

/*
	楕円の周長
*/
int main()
{
//	cut here before submit 
//	freopen ("testcase.2057", "r", stdin );
	int n;
	while (scanf ("%d", &n ), n ){
		static point<double> p[(int)1e5+5];
		rep (i, n ) scanf ("%lf %lf %lf",&p[i].r, &p[i].x, &p[i].y );
		double res = closest_pair(n, p );
		printf ("%.5lf\n", res );
	} // end loop
		
	return 0;
}