#include <bits/stdc++.h>
  
using namespace std;
  
#define rep(i,n) REP(i,0,n)
#define REP(i,s,e) for(int i=(s); i<(int)(e); i++)
#define pb push_back
#define all(r) (r).begin(),(r).end()
#define rall(r) (r).rbegin(),(r).rend()
#define fi first
#define se second
  
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const double EPS = 1e-8;
const double INF = 1e12;
const double PI = acos(-1);
#define X(r) real((r))
#define Y(r) imag((r))
typedef complex<double> P;
typedef complex<double> point;
namespace std {
	bool operator < (const P& a, const P& b) {
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}
double cross(const P& a, const P& b) {
	return imag(conj(a)*b);
}
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;
typedef vector<P> polygon;

struct C {
	P p; double r;
	C(const P &p, double r) : p(p), r(r) { }
};
//??????????????????
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;
}
bool intersectSS(const L &s, const L &t) {
	return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 &&
			ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0;
}


//?????¨????????????????±???????
vector<point> crossPoint(const C& a, const C& b){
	double d = abs(b.p-a.p);
	double arg = atan2(Y(b.p-a.p), X(b.p-a.p));
	double arg2 = acos((d*d+a.r*a.r-b.r*b.r)/(2*d*a.r));
	if(abs(arg2)<EPS) return {a.r*complex<double>(cos(arg), sin(arg))+a.p};
	if(abs(a.r-b.r)<d && d < a.r+b.r) return {a.r*complex<double>(cos(arg+arg2), sin(arg+arg2))+a.p, a.r*complex<double>(cos(arg-arg2), sin(arg-arg2))+a.p};
	return {};
}
struct Edge{
	int to;
	double cost;
};

double dist[100010];
vector<Edge> es[100010];

int main(){
	int n;
	while(cin>>n && n){
		vector<C> c;
		rep(i, n){
			double x, y, r;
			cin>>x>>y>>r;
			c.pb(C({x, y}, r));
		}
		vector<vector<P> > v;
		for(int i = 0; i < n-1; i++) v.pb(crossPoint(c[i], c[i+1]));
		rep(i, 100010) dist[i] = 1e18, es[i].clear();
		dist[0] = 0.0;
		int goal=n*2-1;

		for(int i = -1; i <= (int)v.size(); i++) {
			vector<point> ps;
			int now;
			if(i == -1) ps.pb(c[0].p), now = 0;
			else if(i == v.size()) ps.pb(c.back().p), now = goal;
			else ps = v[i], now = i*2+1;
			for(auto&p:ps){
				for(int k = -1; k <= (int)v.size(); k++){
					if(k == i) continue;
					vector<point> ps2;
					int nxt;
					if(k == -1) ps2.pb(c[0].p), nxt = 0;
					else if(k == v.size()) ps2.pb(c.back().p), nxt = goal;
					else ps2 = v[k], nxt = k*2+1;
					for(auto& p2 : ps2){
						bool f = true;
						for(int l = (k < i ? k+1 : i+1); l < (k < i ? i:k); l++){
							if(!intersectSS({p, p2}, {v[l][0], v[l][1]})) f = false;
						}
						if(f) {
							es[now].pb({nxt, abs(p - p2)});
							//es[nxt].pb({now, abs(p - p2)});
						}
						nxt++;
					}
				}
				now++;
			}
		}
		auto dijkstra = [&](){
			typedef pair<double, int> PP;
			priority_queue<PP, vector<PP>, greater<PP> > q;
			PP p;
			q.push({0.0, 0});
			while(!q.empty()){
				p = q.top();	q.pop();
				int from = p.se;
				double cost = p.fi;
				if(dist[from] < cost - EPS) continue;
				for(auto& e : es[from]) {
					int to = e.to;
					double newCost = cost+e.cost;
					if(dist[to] > newCost + EPS) {
						dist[to] = newCost;
						q.push({dist[to], to});
					}
				}
			}
		};
		dijkstra();
		printf("%.15lf\n", dist[goal]);
	}
}

Measured memory_bytes: 6984