#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
#include<climits>
#include<string>
#include<set>
#include<map>
using namespace std;
#define rep(i,n) for(int i=0;i<((int)(n));i++)
#define reg(i,a,b) for(int i=((int)(a));i<=((int)(b));i++)
#define irep(i,n) for(int i=((int)(n))-1;i>=0;i--)
#define ireg(i,a,b) for(int i=((int)(b));i>=((int)(a));i--)
typedef long long int lli;
typedef pair<int,int> mp;
#define fir first
#define sec second
#define IINF INT_MAX
#define LINF LLONG_MAX


struct pos{
	double x,y;
	double norm,norm2;
	pos tov(pos a){
		return (a-(*this));
	}
	pos operator+(pos a)const{
		pos res=a;
		res.x+=x; res.y+=y;
		res=pos(res.x,res.y);
		return res;
	}
	pos operator-(pos a)const{
		pos res=(*this);
		res.x-=a.x; res.y-=a.y;
		res=pos(res.x,res.y);
		return res;
	}
	pos scalar(double a){
		pos res=(*this);
		res.x*=a; res.y*=a;
		res=pos(res.x,res.y);
		return res;
	}
	double dot(pos a){
		return x*a.x + y*a.y;
	}
	double cross(pos a){
		return x*a.y - y*a.x;
	}
	pos(double ix,double iy){
		x=ix; y=iy;
		norm2=x*x+y*y;
		norm=sqrt(norm2);
	}
	pos(){}
	string str(){
		char ns[50];
		sprintf(ns,"(%lf %lf)",x,y);
		return	string(ns);
	}
	static pos polar(double r,double t){
		return pos(r*cos(t),r*sin(t));
	}
};

struct line{
	pos p,q;
	pos vec;
	string str(){
		return ("("+p.str()+"-"+q.str()+")");
	}
	bool iscross(line a){
		//printf("check %s %s\n",str().c_str(),a.str().c_str());
		double da,db;
		da=vec.cross( p.tov(a.p) );
		db=vec.cross( p.tov(a.q) );
		//printf("%lf %lf\n",da,db);
		if(da*db>=0)return false;
		da=a.vec.cross( a.p.tov(p) );
		db=a.vec.cross( a.p.tov(q) );
		//printf("%lf %lf\n",da,db);
		return (da*db<0);
	}
	line(pos ip,pos iq){
		p=ip; q=iq;
		vec=p.tov(q);
	}
	line(){}
};

double lowofcos_getcos(double a,double b,double c){
	return ((a*a+b*b-c*c)/(2*a*b));
}

struct circle{
	pos p;
	double r;
	
	line getintersection(circle a){
		pos cv=p.tov(a.p);
		double br=atan2(cv.y,cv.x);
		double dr=acos(lowofcos_getcos( r, cv.norm, a.r));
		//printf("%s %lf %lf %lf   %lf %lf %lf\n",cv.str().c_str(),br,dr,lowofcos_getcos( r, cv.norm, a.r),r, cv.norm, a.r);
		
		pos p1= p+pos::polar(r,br+dr);
		pos p2= p+pos::polar(r,br-dr);
		
		return line(p1,p2);
	}
	circle(pos ip,double ir){
		p=ip; r=ir;
	}
	circle(){}
};



int main(void){
	/*
	circle c1,c2;
	c1.p=pos(2,2); c1.r=sqrt(5);
	c2.p=pos(5,3); c2.r=sqrt(5);
	line li=c1.getintersection(c2);
	printf("%s\n",li.str().c_str());
	*/
	
	for(;;){
		int n;
		scanf("%d",&n);
		if(n==0)break;
		vector<circle> dat;
		rep(i,n){
			double a,b,c;
			scanf("%lf %lf %lf",&a,&b,&c);
			dat.push_back(circle(pos(a,b),c));
		}
		
		vector<line> ls;
		rep(i,n-1){
			ls.push_back(dat[i].getintersection(dat[i+1]));
		}
		
		vector<pos> ps[2];
		ps[0].push_back(dat[0].p);
		ps[1].push_back(dat[0].p);
		rep(i,n-1){
			ps[0].push_back(ls[i].p);
			ps[1].push_back(ls[i].q);
		}
		ps[0].push_back(dat[n-1].p);
		ps[1].push_back(dat[n-1].p);
		
		vector<double> dp[2];
		rep(i,2)dp[i].resize(n+1);
		dp[0][0]=dp[1][0]=0;
		reg(i,1,n){
			rep(j,2){
				double nd=10000;
				rep(p,i){
					rep(q,2){
						bool ok=true;
						line nl=line( pos(ps[q][p]) , pos(ps[j][i]) );
						reg(k,p,i-2){
							if(!nl.iscross(ls[k]))ok=false;
							if(!ok)break;
						}
						if(!ok)continue;
						nd = min(nd, nl.vec.norm+dp[q][p]);
					}
				}
				dp[j][i]=nd;
			}
		}
		
		printf("%lf\n",min(dp[0][n],dp[1][n]));
	}	
	
	return 0;
}

Measured memory_bytes: 1256