#include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-10)
#define equals(a,b) (fabs((a)-(b)) < EPS)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1 
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0

using namespace std;

class Point{
public:
  double x,y;
  Point(double x=0,double y=0):x(x),y(y){}
  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}

  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }
};

typedef Point Vector;

double norm(Point a){ return a.x*a.x+a.y*a.y; }
double abs(Point a){ return sqrt(norm(a)); }

struct Data {
  int to,cost;
};

template<typename T>
bool visit(const T& G,int v,vector<int>& order,vector<int>& color){
  color[v] = 1;
  for(__typeof((G[v]).begin()) e = G[v].begin();e != G[v].end();e++){
      if(color[e->to] == 2)continue;//このvisit以外のvisitで訪れた
      if(color[e->to] == 1)return false;//このvisitで訪れた
      if(!visit(G,e->to,order,color))return false;
    }
  order.push_back(v);
  color[v] = 2;
  return true;
}

template<typename T>
bool topologicalSort(const T& G,vector<int>& order){
  int SizeG = G.size();
  vector<int> color(SizeG); 
  for(int u=0;u<SizeG;u++) if(!color[u] && !visit(G,u,order,color)) return false;
  reverse(order.begin(),order.end());
  return true;
}

bool isIntersectCC(Point a,double R1,Point b, double R2){
  double d = sqrt(norm(a-b));
  double r1 = max(R1,R2);
  double r2 = min(R1,R2);
  if(!equals(d,r1+r2) && d > r1+r2)return false;
  if(!equals(d,r1-r2) && d < r1-r2)return false;  // verify
  return true;
}

// 円 a が円 b に囲まれているか
bool insideCC(Point a,double ra,Point b,double rb){
  double d = sqrt(norm(a-b));
  double r1 = max(ra,rb);
  double r2 = min(ra,rb);
  
  if(!equals(d,r1-r2) && d < r1-r2) return ra < rb; 
  return false;
}

int n;
Point s,t;
vector<Point> ps;
vector<double> R;

const int IINF = INT_MAX;

inline bool LTE(double a,double b) { return equals(a,b) || a < b; }

vector<int> func(Point sp){
  vector<vector<Data> > G(n,vector<Data>());
  vector<bool> ok(n,false);
  rep(i,n) {
    double dist = abs(sp-ps[i]);
    if( LTE(0,dist) && LTE(dist,R[i]) ) {
      double dist1 = abs(s-ps[i]), dist2 = abs(t-ps[i]);
      if( LTE(dist1,R[i]) && LTE(dist2,R[i]) ) continue;
      ok[i] = true;
    }
  }
  
  rep(i,n) if( ok[i] ) {
    rep(j,n) if( ok[j] && i != j ){
      if( !isIntersectCC(ps[i],R[i],ps[j],R[j]) && insideCC(ps[i],R[i],ps[j],R[j]) ) {
        G[i].push_back((Data){j,0});
      }
    }
  }
  vector<int> order;
  assert( topologicalSort(G,order) );
  vector<int> dp(n,-IINF);
  if( order.empty() ) return dp;
  bool First = true;
  rep(i,(int)order.size()) if( ok[order[i]] ){
    int cur = order[i];
    dp[cur] = max(dp[cur],1);
    rep(j,(int)G[cur].size()){
      int to = G[cur][j].to;
      if( !ok[to] ) continue;
      dp[to] = max(dp[to],dp[cur]+1);
    }
  }
  return dp;
}

int main(){
  while( cin >> n , n ){
    ps.clear(), R.clear();
    ps.resize(n), R.resize(n);
    cin >> s.x >> s.y >> t.x >> t.y;
    rep(i,n) cin >> ps[i].x >> ps[i].y >> R[i];
    vector<int> array[2] = { func(s), func(t) };
    /*
    rep(i,2) {
      cout << endl;
      cout << i << "-th" << endl;
      rep(j,n) {
        if( j ) cout << " ";
        if( array[i][j] == -IINF ) cout << "X";
        else cout << array[i][j];
      } cout << endl;
    }
    */
    int maxi = 0;
    rep(i,n) {
      rep(j,n) {
        if( i != j && isIntersectCC(ps[i],R[i],ps[j],R[j]) ) continue;
        int cost1 = (array[0][i]==-IINF)?0:array[0][i];
        int cost2 = (array[1][j]==-IINF)?0:array[1][j];
        maxi = max(maxi,cost1+cost2);
      }
    }
    printf("%d\n",maxi);
  }
  return 0;
}

Measured memory_bytes: 6592