#include <bits/stdc++.h>
#include <cxxabi.h>
using namespace std;
using ll=long long;
using vi=vector<int>;
using vvi=vector<vi>;
using pii=pair<int,int>;
#define rep(i,n) range(i,0,n)
#define range(i,a,n) for(int i=a;i<n;i++)
#define all(a) a.begin(),a.end()
#define LINF    ((ll)1ll<60)
#define INF     ((int)1<<30)
#define EPS     (1e-9)
#define MOD     (1000000007)
#define fcout(a) cout<<setprecision(a)<<fixed
template<class S,class T>ostream& operator<<(ostream&os,pair<S,T>p){os<<"["<<p.first<<", "<<p.second<<"]";return os;};
template<class S>auto&operator<<(ostream&os,vector<S>t){bool b=1;for(auto s:t)os<<(exchange(b,0)||strlen(abi::__cxa_demangle(typeid(S).name(),0,0,0))>20?"":" ")<<s;return os<<endl;}
typedef double D;      // 座標値の型。doubleかlong doubleを想定
typedef complex<D> P;  // Point
typedef pair<P, P> L;  // Line
typedef vector<P> VP;
#define X real()
#define Y imag()
#define LE(n,m) ((n) < (m) + EPS)
#define GE(n,m) ((n) + EPS > (m))
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define PI 3.14159265358

// 内積　dot(a,b) = |a||b|cosθ
D dot(P a, P b) {
  return (conj(a)*b).X;
}
// 外積　cross(a,b) = |a||b|sinθ
D cross(P a, P b) {
  return (conj(a)*b).Y;
}

// 点の進行方向
int ccw(P a, P b, P c) {
  b -= a;  c -= a;
  if (cross(b,c) >  EPS) return +1;  // counter clockwise
  if (cross(b,c) < -EPS) return -1;  // clockwise
  if (dot(b,c)   < -EPS) return +2;  // c--a--b on line
  if (norm(b) < norm(c)) return -2;  // a--b--c on line or a==b
  return 0;                          // a--c--b on line or a==c or b==c
}

/* 交差判定　直線・線分は縮退してはならない。接する場合は交差するとみなす。isecはintersectの略 */

// 直線と点
bool isecLP(P a1, P a2, P b) {
  return abs(ccw(a1, a2, b)) != 1;  // return EQ(cross(a2-a1, b-a1), 0); と等価
}

// 直線と直線
bool isecLL(P a1, P a2, P b1, P b2) {
  return !isecLP(a2-a1, b2-b1, 0) || isecLP(a1, b1, b2);
}

// 直線と線分
bool isecLS(P a1, P a2, P b1, P b2) {
  return cross(a2-a1, b1-a1) * cross(a2-a1, b2-a1) < EPS;
}

// 線分と線分
bool isecSS(P a1, P a2, P b1, P b2) {
  return ccw(a1, a2, b1)*ccw(a1, a2, b2) <= 0 &&
         ccw(b1, b2, a1)*ccw(b1, b2, a2) <= 0;
}

// 線分と点
bool isecSP(P a1, P a2, P b) {
  return !ccw(a1, a2, b);
}


/* 距離　各直線・線分は縮退してはならない */

// 点pの直線aへの射影点を返す
P proj(P a1, P a2, P p) {
  return a1 + dot(a2-a1, p-a1)/norm(a2-a1) * (a2-a1);
}

// 点pの直線aへの反射点を返す
P reflection(P a1, P a2, P p) {
  return 2.0*proj(a1, a2, p) - p;
}

D distLP(P a1, P a2, P p) {
  return abs(proj(a1, a2, p) - p);
}

D distLL(P a1, P a2, P b1, P b2) {
  return isecLL(a1, a2, b1, b2) ? 0 : distLP(a1, a2, b1);
}

D distLS(P a1, P a2, P b1, P b2) {
  return isecLS(a1, a2, b1, b2) ? 0 : min(distLP(a1, a2, b1), distLP(a1, a2, b2));
}

D distSP(P a1, P a2, P p) {
  P r = proj(a1, a2, p);
  if (isecSP(a1, a2, r)) return abs(r-p);
  return min(abs(a1-p), abs(a2-p));
}

D distSS(P a1, P a2, P b1, P b2) {
  if (isecSS(a1, a2, b1, b2)) return 0;
  return min(min(distSP(a1, a2, b1), distSP(a1, a2, b2)),
             min(distSP(b1, b2, a1), distSP(b1, b2, a2)));
}

VP crosspointCC(P a, D ar, P b, D br) {
  VP ps;
  P ab = b-a;
  D d = abs(ab);
  D crL = (norm(ab) + ar*ar - br*br) / (2*d);
  if (EQ(d, 0) || ar < abs(crL)) return ps;

  P abN = ab * P(0, sqrt(ar*ar - crL*crL) / d);
  P cp = a + crL/d * ab;
  ps.push_back(cp + abN);
  if (!EQ(norm(abN), 0)) ps.push_back(cp - abN);
  return ps;
}

int main(){
	cin.tie(0);
   	ios::sync_with_stdio(false);
	
	/*
		0,1:S
		2~3:L1
		4~5:L2
		N*2-2,N*2-1:L(N-1)
		N*2,N*2+1,G
	*/
	int n;
	while(cin>>n,n){
		vector<pair<P,D>> cir(n);
		vector<P> line(n*2+2);
		rep(i,n){
			double x,y,r;
			cin>>x>>y>>r;
			cir[i]=make_pair(P(x,y),r);
		}
		line[0]=line[1]=cir[0].first;
		range(i,1,n){
			auto p=crosspointCC(cir[i-1].first,cir[i-1].second,cir[i].first,cir[i].second);
			line[i*2]=p[0];
			line[i*2+1]=p[1];
		}
		line[n*2]=line[n*2+1]=cir[n-1].first;

		vector<vector<D>> dist(n*2+2,vector<double>(n*2+2,-1));
		rep(i,n*2+2)range(j,i+1,n*2+2){
		    //cout<<i<<","<<j<<"=>";
			bool ok=true;
			for(int k=(i+2)/2;k<j/2;k++){
			    //cout<<"("<<k*2<<"-"<<k*2+1<<")";
				ok&=isecSS(line[i],line[j],line[k*2],line[k*2+1]);
			}
			if(ok)dist[i][j]=dist[j][i]=abs(line[i]-line[j]);
			//cout<<dist[i][j]<<endl;
		}
		//cout<<line<<endl;
		//cout<<setprecision(1)<<fixed<<dist<<endl;
		vector<D> dp(n*2+2,INF);
		dp[0]=dp[1]=0;
		range(i,2,n*2+2){
		    //int p=0;
			rep(j,i/2*2)if(dist[i][j]!=-1){
			    //if(dp[i]>dp[j]+dist[i][j])p=j;
				dp[i]=min(dp[i],dp[j]+dist[i][j]);
			}
			//cout<<i<<"=>"<<p<<endl;
		}
		fcout(10)<<dp[n*2]<<endl;
	}
	return 0;
}



Measured memory_bytes: 3448