#include<iostream>
#include<sstream>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>

#define rep(i,n) for(int i=0;i<(int)n;i++)
#define all(c) (c).begin(),(c).end()
#define mp make_pair
#define pb push_back
#define each(i,c) for(__typeof((c).begin()) i=(c).begin();i!=(c).end();i++)
#define dbg(x) cerr<<__LINE__<<": "<<#x<<" = "<<(x)<<endl

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
const int inf = (int)1e9;
const double EPS = 1e-8, INF = 1e12, PI = acos(-1.0);
typedef complex<double> P;
namespace std{
	bool operator<(const P& a, const P& b){
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}
inline double cross(const P& a, const P& b){ return imag(conj(a)*b); }
inline double dot(const P& a, const P& b){ return real(conj(a)*b); }
struct L : public vector<P>{
	L(const P &a, const P &b) {
		push_back(a); push_back(b);
	}
};
typedef vector<P> G;

inline int ccw(P a, P b, P c) {
	b -= a; c -= a;
	if(cross(b, c) > 0)   return +1;		// counter clockwise
	if(cross(b, c) < 0)   return -1;		// clockwise
	if(dot(b, c) < 0)     return +2;		// c--a--b on line
	if(norm(b) < norm(c)) return -2;		// a--b--c on line
	return 0;
}
vector<P> isCC(P c1, double r1, P c2, double r2){
	double x = norm(c1 - c2);
	double y = ((r1 * r1 - r2 * r2) / x + 1) / 2;
	double d = r1 * r1 / x - y * y;
	if(d < -EPS) return vector<P>(0);
	if(d < 0) d = 0;
	P q1 = c1 + (c2 - c1) * y, q2 = (c2 - c1) * sqrt(d) * P(0, 1);
	vector<P> res;
	res.pb(q1 - q2); res.pb(q1 + q2);
	return res;
}
G isCL(const P &c, double r, const P &p1, const P &p2){
	double x = dot(p1 - c, p2 - p1);
	double y = norm(p2 - p1);
	double d = x * x - y * (norm(p1 - c) - r * r);
	if(d < -EPS) return G(0);
	if(d < 0) d = 0;
	P q1 = p1 - (p2 - p1) * (x / y);
	P q2 = (p2 - p1) * (sqrt(d) / y);
	G res; res.pb(q1 - q2); res.pb(q1 + q2);
	return res;
}


int n;
G o;
double r[100];
bool v[300];

bool ok(const P &a, const P &b){
	map<double, int> m;
	m[0] = 0; m[1] = 0;
	rep(i, n){
		G cp = isCL(o[i], r[i], a, b);
		if(cp.size() == 2){
			double x = dot(cp[0] - a, b - a) / norm(a - b);
			double y = dot(cp[1] - a, b - a) / norm(a - b);
			x = max(x, 0.0); y = max(y, 0.0);
			x = min(x, 1.0); y = min(y, 1.0);
			if(x > y) swap(x, y);
			m[x - EPS]++; m[y + EPS]--;
		}
	}
	int cnt = 0;
	each(i, m){
		cnt += i->second;
		if(0 <= i->first && i->first <= 1 && cnt <= 0) return 0;
	}
	return 1;
}

int main(){
	while(cin >> n, n){
		o.clear(); o.resize(n);
		rep(i, n) cin >> o[i].real() >> o[i].imag() >> r[i];
		
		vector<pair<int, P> > ps;
		rep(i, n - 1){
			G cp = isCC(o[i], r[i], o[i + 1], r[i + 1]);
			each(j, cp) ps.pb(mp(i + 1, *j));
		}
		ps.pb(mp(0, o[0]));
		ps.pb(mp(n, o[n - 1]));
		
		int m = ps.size();
		memset(v, 0, sizeof(v));
		priority_queue<pair<double, int> > q;
		q.push(mp(0, m - 2));
		
		while(!q.empty()){
			int c = q.top().second;
			double co = q.top().first; q.pop();
			
			if(v[c]) continue;
			v[c] = 1;
			if(c == m - 1){
				printf("%.9f\n", -co);
				break;
			}
			rep(i, m) if(!v[i] && ok(ps[c].second, ps[i].second)){
				q.push(mp(co - abs(ps[i].second - ps[c].second), i));
			}
		}
	}
	return 0;
}

Measured memory_bytes: 1304