#include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

typedef complex<double> Point;
const double EPS = 1e-8;

int sign(double x){
    if(x > EPS) return 1;
    if(x < -EPS) return -1;
    return 0;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
bool intersectSS(Line s, Line 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;
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r) : p(p), r(r) { }
};
vector<Point> crosspointCC(Circle a, Circle b){
    vector<Point> res;

    double l = abs(b.p - a.p);

    if(sign(l) == 0 && sign(a.r - b.r) == 0) assert(false); // 解が無限に存在する
    if(sign(l - abs(a.r - b.r)) < 0 || sign(l - (a.r + b.r)) > 0) return res; // 解が存在しない

    double th1 = arg(b.p - a.p);
    if(sign(l - abs(a.r - b.r)) == 0 || sign(l - (a.r + b.r)) == 0){
        res.push_back(a.p + polar(a.r, th1));
    }else {
        double th2 = acos( (a.r * a.r - b.r * b.r + l * l) / (2 * a.r * l) );
        res.push_back(a.p + polar(a.r, th1 - th2));
        res.push_back(a.p + polar(a.r, th1 + th2));
    }
    return res;
}
int main(){
    int N;
    while(cin >> N && N){
        vector<Circle> cv(N);
        REP(i, N){
            double x, y, r;
            cin >> x >> y >> r;
            cv[i] = Circle(Point(x, y), r);
        }
        vector<Line> midl;
        midl.push_back(Line(cv[0].p, cv[0].p));
        for(int i = 0; i < N - 1; i++){
            vector<Point> cp = crosspointCC(cv[i], cv[i + 1]);
            assert(cp.size() == 2);
            midl.push_back(Line(cp[0], cp[1]));
        }
        midl.push_back(Line(cv[N - 1].p, cv[N - 1].p));

        double dp[111][2] = {};
        REP(i, N + 2) dp[i][0] = dp[i][1] = 1e15;
        dp[0][0] = 0;
        
        for(int i = 0; i < midl.size(); i++){
            for(int b1 = 0; b1 < 2; b1++){
                if(dp[i][b1] == 1e15) continue;
                for(int j = i + 1; j < midl.size(); j++){
                    for(int b2 = 0; b2 < 2; b2++){
                        Line s(midl[i][b1], midl[j][b2]);
                        bool ok = true;
                        for(int k = i + 1; k < j; k++){
                            if(!intersectSS(s, midl[k])) ok = false;
                        }
                        if(ok){
                            dp[j][b2] = min(dp[j][b2], dp[i][b1] + abs(s.vector()));
                        }
                    }
                }
            }
        }
        printf("%.12f\n", dp[midl.size() - 1][0]);
    }
    return 0;
}

Measured memory_bytes: 1388