#include <bits/stdc++.h>
//#define int long long

using namespace std;
using LL = long long;
using P = pair<int, int>;
using Tapris = tuple<int, int, int>;

#define FOR(i, a, n) for(int i = (int)(a); i < (int)(n); ++i)
#define REP(i, n) FOR(i, 0, n)

#define pb(a) push_back(a)
#define all(x) (x).begin(),(x).end()

const int INF = (int)1e9;
const LL INFL = (LL)1e15;
const int MOD = 1e9 + 7;

int dy[]={0, 0, 1, -1, 0};
int dx[]={1, -1, 0, 0, 0};

typedef long double LD;
typedef complex<LD> Point;
typedef pair<Point, Point> Line;
typedef Line Segment;
typedef vector<Point> Polygon;
const LD EPS = 1e-10;
#define X real() // x座標を取得
#define Y imag() // y座標を取得
#define LE(n,m) ((n) < (m) + EPS)
#define GE(n,m) ((n) + EPS > (m))
#define EQ(n,m) (abs((n)-(m)) < EPS)

// 内積 Dot(a, b) = |a||b|cosθ
LD Dot(Point a, Point b){
    return (conj(a)*b).X;
}

// 外積 Cross(a, b) = |a||b|sinθ
LD Cross(Point a, Point b){
    return (conj(a)*b).Y;
}

int CCW(Point a, Point b, Point 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;
}

//*********************************************
//          点と線(Point and Line)            *
//*********************************************

// 交差判定 (Isec) ****************************
// 点　 := 平面座標にある点
// 直線 := 点と点を通るどこまでも続く線
// 線分 := 点と点を結んでその両端で止まっている線

// 直線と点
bool IsecLP(Line a, Point p){
    Point a1 = a.first, a2 = a.second;
    return abs(CCW(a1, a2, p)) != 1;
}

// 直線と直線
bool IsecLL(Line a, Line b) {
    Point a1 = a.first, a2 = a.second, b1 = b.first, b2 = b.second;
    return !IsecLP(Line(a2-a1, b2-b1), 0) || IsecLP(Line(a1, b1), b2);
}

// 直線と線分
bool IsecLS(Line a, Segment b) {
    Point a1 = a.first, a2 = a.second, b1 = b.first, b2 = b.second;
    return Cross(a2-a1, b1-a1) * Cross(a2-a1, b2-a1) < EPS;
}

// 線分と線分
bool IsecSS(Segment a, Segment b) {
    Point a1 = a.first, a2 = a.second, b1 = b.first, b2 = b.second;
    return CCW(a1, a2, b1)*CCW(a1, a2, b2) <= 0 && CCW(b1, b2, a1)*CCW(b1, b2, a2) <= 0;
}

// 線分と点
bool IsecSP(Segment a, Point p) {
    Point a1 = a.first, a2 = a.second;
    return !CCW(a1, a2, p);
}

// ********************************************


// 距離 (Dist) ********************************
// 点pの直線aへの射影点を返す
Point Proj(Line a, Point p){
    Point a1 = a.first, a2 = a.second;
    return a1 + Dot(a2-a1, p-a1) / norm(a2-a1) * (a2-a1);
}

// 点pの直線aへの反射点を返す
Point Reflection(Line a, Point p){
    return 2.0L*Proj(a, p) - p;
}

// 点と点
LD DistPP(Point p1, Point p2){
    return abs(p1-p2);
}

// 直線と点
LD DistLP(Line a, Point p){
    return abs(Proj(a, p) - p);
}

// 直線と直線
LD DistLL(Line a, Line b) {
    Point b1 = b.first;
    return IsecLL(a, b) ? 0 : DistLP(a, b1);
}

// 直線と線分
LD DistLS(Line a, Segment b) {
    Point b1 = b.first, b2 = b.second;
    return IsecLS(a, b) ? 0 : min(DistLP(a, b1), DistLP(a, b2));
}

// 線分と点
LD DistSP(Segment a, Point p) {
    Point a1 = a.first, a2 = a.second;
    if(Dot(a2-a1,p-a1) < EPS) return abs(p-a1);
    if(Dot(a1-a2,p-a2) < EPS) return abs(p-a2);
    return abs(Cross(a2-a1,p-a1)) / abs(a2-a1);
}

// 線分と線分
LD DistSS(Segment a, Segment b) {
    Point a1 = a.first, a2 = a.second, b1 = b.first, b2 = b.second;
    if(IsecSS(a, b)) return 0;
    return min(min(DistSP(a, b1), DistSP(a, b2)), min(DistSP(b, a1), DistSP(b, a2)));
}

// ********************************************


// 2直線の交点 (CrossPoint) *******************
Point CrossPointLL(Line a, Line b){
    Point a1 = a.first, a2 = a.second, b1 = b.first, b2 = b.second;
    LD d1 = Cross(b2-b1, b1-a1);
    LD d2 = Cross(b2-b1, a2-a1);
    if (EQ(d1, 0) && EQ(d2, 0)) return a1;
    if (EQ(d2, 0)) throw "not exist crosspoint";
    return a1 + d1/d2 * (a2-a1);
}
// ********************************************


//*********************************************
//             多角形(Polygon)                *
//*********************************************

namespace std {
    bool operator < (Point a, Point b){
        return a.X != b.X ? a.X < b.X : a.Y < b.Y;
    }
}

// 多角形の面積 (PolygonErea) *****************
LD PolygonErea(Polygon p){
    LD area = 0;
    int n = p.size();
    for(int i = 0; i < n; i++){
        area += Cross(p[i], p[(i+1) % n]);
    }
    return area / 2;
}
// ********************************************


// 凸性判定 (IsConvex) ************************
bool IsConvex(Polygon pol){
    int n = pol.size();
    for(int i = 0; i < n; i++){
        if(CCW(pol[i], pol[(i+1) % n], pol[(i+2) % n]) == -1) return false;
    }
    return true;
}
// ********************************************


// 多角形-点包含関係 (PolygonPointContainment)
int PolygonPointContainment(Polygon pol, Point p){
    enum {OUT, ON, IN};
    bool in = false;
    int n = pol.size();
    for(int i = 0; i < n; i++){
        Point a = pol[i] - p, b = pol[(i+1) % n] - p;
        if(a.Y > b.Y) swap(a, b);
        if(a.Y <= 0 && 0 < b.Y && Cross(a, b) < 0) in = !in;
        if(Cross(a, b) == 0 && Dot(a, b) <= 0) return ON;
    }
    return in ? IN : OUT;
}
// ********************************************


//*********************************************
//          凸多角形(ConvexPolygon)           *
//*********************************************

// 凸包[θ<=180] (ConvexHull) *****************
Polygon ConvexHull(Polygon pol){
    int n = pol.size(), k = 0;
    sort(pol.begin(), pol.end());
    Polygon ch(2*n);
    for(int i = 0; i < n; ch[k++] = pol[i++])
        while(k >= 2 && CCW(ch[k-2], ch[k-1], pol[i]) == -1) --k;

    for(int i = n-2, t = k+1; i >= 0; ch[k++] = pol[i--])
        while(k >= t && CCW(ch[k-2], ch[k-1], pol[i]) == -1) --k;

    ch.resize(k-1);
    return ch;
}
// ********************************************

// 凸包[θ<180] (ConvexHull2) *****************
Polygon ConvexHull2(Polygon pol){
    int n = pol.size(), k = 0;
    sort(pol.begin(), pol.end());
    Polygon ch(2*n);
    for(int i = 0; i < n; ch[k++] = pol[i++])
        while(k >= 2 && CCW(ch[k-2], ch[k-1], pol[i]) <= 0) --k;

    for(int i = n-2, t = k+1; i >= 0; ch[k++] = pol[i--])
        while(k >= t && CCW(ch[k-2], ch[k-1], pol[i]) <= 0) --k;

    ch.resize(k-1);
    return ch;
}
// ********************************************

// 凸多角形の直径 (ConvexPolygonDiameter) *****
pair<int, int> ConvexPolygonDiameter(Polygon cpol){
    int n = cpol.size();
    int is = 0, js = 0;
    for (int i = 1; i < n; ++i) {
        if (imag(cpol[i]) > imag(cpol[is])) is = i;
        if (imag(cpol[i]) < imag(cpol[js])) js = i;
    }
    LD maxd = norm(cpol[is]-cpol[js]);

    int i, maxi, j, maxj;
    i = maxi = is;
    j = maxj = js;
    do{
        if(Cross(cpol[(i+1)%n] - cpol[i], cpol[(j+1)%n] - cpol[j]) >= 0) j = (j+1) % n;
        else i = (i+1) % n;
        if(norm(cpol[i]-cpol[j]) > maxd) {
            maxd = norm(cpol[i]-cpol[j]);
            maxi = i; maxj = j;
        }
    } while(i != is || j != js);
    return make_pair(maxi, maxj);
}
// ********************************************


// 凸多角形の切断 (ConvexPolygonCut) **********
Polygon ConvexPolygonCut(Polygon cpol, Line l){
    int n = cpol.size();
    Point l1 = l.first, l2 = l.second;
    Polygon q;
    for(int i = 0; i < n; i++){
        Point a = cpol[i], b = cpol[(i+1)%n];
        if(CCW(l1, l2, a) != -1) q.push_back(a);
        if(CCW(l1, l2, a) * CCW(l1, l2, b) < 0) q.push_back(CrossPointLL(Line(a, b), l));
    }
    return q;
}
// ********************************************


// 凸多角形-点包含関係 (ConvexPolygonPointContainment)
int ConvexPolygonPointContainment(Polygon cpol, Point p){
    enum {OUT, ON, IN};
    int n = cpol.size();
    Point g = (cpol[0] + cpol[n/3] + cpol[2*n/3]) / 3.0L;
    int a = 0, b = n;
    while(a+1 < b){
        int c = (a + b) / 2;
        if(Cross(cpol[a]-g, cpol[c]-g) > 0){
            if(Cross(cpol[a]-g, p-g) > 0 && Cross(cpol[c]-g, p-g) < 0) b = c;
            else a = c;
        }else{
            if(Cross(cpol[a]-g, p-g) < 0 && Cross(cpol[c]-g, p-g) > 0) a = c;
            else b = c;
        }
    }
    b %= n;
    if(Cross(cpol[a]-p, cpol[b]-p) < 0) return OUT;
    if(Cross(cpol[a]-p, cpol[b]-p) > 0) return IN;
    return ON;
}
// ********************************************

// 最近点対 (ClosestPair) *********************
pair<Point, Point> ClosestPair(Polygon p){
    int n = p.size();
    sort(p.begin(), p.end(), [](Point p, Point q) { return p.Y < q.Y; });
    
    auto u = p[0], v = p[1];
    auto best = Dot(u-v, u-v);
    auto update = [&](Point p, Point q) {
        auto dist = Dot(p-q, p-q);
        if (best > dist) { best = dist; u = p; v = q; }
    };
    set<Point> S; S.insert(u); S.insert(v);
    for (int l = 0, r = 2; r < n; ++r) {
        if (S.count(p[r])) return {p[r], p[r]};
        if ((p[l].Y-p[r].Y)*(p[l].Y-p[r].Y) > best) S.erase(p[l++]);
        auto i = S.insert(p[r]).first;
        for (auto j = i; ; ++j) {
            if (j == S.end() || (i->X-j->X)*(i->X-j->X) > best) break;
            if (i != j) update(*i, *j);
        }
        for (auto j = i; ; --j) {
            if (i != j) update(*i, *j);
            if (j == S.begin() || (i->X-j->X)*(i->X-j->X) > best) break;
        }
    }
    return make_pair(u, v);
}
// ********************************************


//*********************************************
//                円(Circle)                  *
//*********************************************
typedef pair<Point, LD> Circle;

// 円と円の交差判定 ***************************
int IsecCC(Circle c1, Circle c2){
    // 0: 包含, 1: 内接, 2: 2点で交わる, 3: 外接, 4: 離れている
    enum{INCLUSION, INSCRIBED, INTERSECT, CIRCUMSCRIBED, LEAVE};
    LD d = DistPP(c1.first, c2.first);
    if(d > c1.second + c2.second) return LEAVE;
    else if(EQ(d, c1.second + c2.second)) return CIRCUMSCRIBED;
    else if(abs(c1.second - c2.second) < d && d < c1.second + c2.second) return INTERSECT;
    else if(EQ(d, abs(c1.second - c2.second))) return INSCRIBED;
    else return INCLUSION;
}
// ********************************************

// 円と直線の交点 *****************************
pair<Point, Point> CrossPointCL(Circle c, Line l){
    Point l1 = l.first, l2 = l.second, cp = c.first;
    LD r = c.second;
    Point ft = Proj(l, cp);
    if(!GE(r * r, norm(ft-cp))) throw "not exist crosspoint";

    Point dir = sqrt(max(r*r - norm(ft-cp), 0.0L)) / abs(l2-l1) * (l2-l1);

    if(!EQ(r*r, norm(ft-cp))) return make_pair(ft - dir, ft + dir);
    else return make_pair(ft + dir, ft + dir);
}
// ********************************************


// 円と円の交点 *******************************
pair<Point, Point> CrossPointCC(Circle a, Circle b){
    Point ap = a.first, bp = b.first;
    LD ar = a.second, br = b.second;
    Point ab = bp-ap;
    LD d = abs(ab);
    LD crL = (norm(ab) + ar*ar - br*br) / (2*d);
    if(EQ(d, 0) || ar < abs(crL)) throw "not exist crosspoint";

    Point abN = ab * Point(0, sqrt(ar*ar - crL*crL) / d);
    Point cp = ap + crL/d * ab;

    if (!EQ(norm(abN), 0)) return make_pair(cp-abN, cp+abN);
    else return make_pair(cp+abN, cp+abN);
}
// ********************************************


// 円の接線の接点 *****************************
pair<Point, Point> TangentPoints(Circle a, Point p){
    Point ap = a.first;
    LD ar = a.second;
    LD sin = ar / abs(p-ap);
    if (!LE(sin, 1)) throw "not exist tangentpoint";
    LD t = M_PI_2 - asin(min(sin, 1.0L));
    if (!EQ(sin, 1)) return make_pair(ap + (p-ap)*polar(sin, -t), ap + (p-ap)*polar(sin, t));
    else return make_pair(ap + (p-ap)*polar(sin, t), ap + (p-ap)*polar(sin, t));
}
// ********************************************


// 2円の共通接線の接点 ************************
vector<Line> TangentLines(Circle a, Circle b){
    vector<Line> ls;
    Point ap = a.first, bp = b.first;
    LD ar = a.second, br = b.second, d = abs(bp-ap);
    for(int i = 0; i < 2; i++){
        LD sin = (ar - (1-i*2)*br) / d;
        if (!LE(sin*sin, 1)) break;
        LD cos = sqrt(max(1 - sin*sin, 0.0L));
        for(int j = 0; j < 2; j++){
            Point n = (bp-ap) * Point(sin, (1-j*2)*cos) / d;
            ls.push_back(Line(ap + ar*n, bp + (1-i*2)*br*n));
            if (cos < EPS) break;
        }
    }
    return ls;
}
// ********************************************


/************** using variables ***************/
Polygon pol;
Point p;
Circle c[2];
int n;
int q;
/**********************************************/

signed main(){
    LD xp, yp, r;
    REP(i, 2){
        cin >> xp >> yp >> r;
        c[i] = Circle(Point(xp, yp), r);
    }
    vector<Line> ans = TangentLines(c[0], c[1]);
    sort(all(ans), [](Line a, Line b){return a.first != b.first ? a.first < b.first : a.second < b.second; });
    REP(i, ans.size()){
        printf("%.9Lf %.9Lf\n", ans[i].first.X, ans[i].first.Y);
    }
}



Measured memory_bytes: 3388