#include <iostream>
#include <cstdio>
#include <vector>
#include <list>
#include <cmath>
#include <fstream>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <complex>
#include <iterator>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <stack>
#include <climits>
#include <deque>
#include <bitset>
#include <cassert>
#include <ctime>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int dy[]={-1,0,1,0},dx[]={0,1,0,-1};
// adjust problem by problem
const double EPS=1e-8;
const double PI=acos(-1.0);
#ifdef __GNUC__
int popcount(int n){return __builtin_popcount(n);}
int popcount(ll n){return __builtin_popcountll(n);}
#endif
#ifndef __GNUC__
template<class T> int popcount(T n){int cnt=0;while(n){if(n%2)cnt++;n/=2;}return cnt;}
#endif
template<class T>int SIZE(T a){return a.size();}
template<class T>string IntToString(T num){string res;stringstream ss;ss<<num;return ss.str();}
template<class T>T StringToInt(string str){T res=0;for(int i=0;i<SIZE(str);i++)res=(res*10+str[i]-'0');return res;}
template<class T>T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template<class T>T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> void PrintSeq(T &a,int sz){for(int i=0;i<sz;i++){cout<<a[i];if(sz==i+1)cout<<endl;else cout<<' ';}}
bool EQ(double a,double b){return abs(a-b)<EPS;}
void fastStream(){cin.tie(0);std::ios_base::sync_with_stdio(0);}
vector<string> split(string str,char del){
  vector<string> res;
  for(int i=0,s=0;i<SIZE(str);i++){
    if(str[i]==del){if(i-s!=0)res.push_back(str.substr(s,i-s));s=i+1;}
    else if(i==SIZE(str)-1){res.push_back(str.substr(s));}
  }
  return res;
}

typedef complex<double> P;
// 座標の回転(座標pにある点を,半時計回りにa(ラジアン)回転)
P roundPoint(P p,double a){
  return P(cos(a)*p.real()-sin(a)*p.imag(),sin(a)*p.real()+cos(a)*p.imag());
}

// 2円の交点を求める
// 2円が交点を持つすることが前提となっていることに注意
// 重解は２つの同じ点が返る
// 交点を持たないかどうかはr1+r2とabs(c1-c2)を比較
pair<P,P> crossPointsTwoCircle(P c1,double r1,P c2,double r2){
  double a=abs(c1-c2);
  double tmp=((r1*r1-r2*r2+a*a)/(2*a));
  double b=sqrt(r1*r1-tmp*tmp);
  P p=c1-c2;p/=abs(p);
  p=roundPoint(p,PI/2);
  P p1=p;
  P p2=p;p2*=-1;
  p1*=b;p2*=b;
  P cp=(c2*tmp+c1*(a-tmp));
  cp*=(1.0/a);
  P res1=cp+p1;
  P res2=cp+p2;
  return make_pair(res1,res2);
}

int N;
double XS[101];
double YS[101];
P cs[101];
double VS[101];

bool check(double time){
  for(int i=0;i<N;i++){
    for(int j=i+1;j<N;j++){
      // 今選択している２円の交点を求めて、その交点を候補として計算
      // 円が内包される場合は、適当な代表点を候補点として利用
      const double r1=VS[i]*time,r2=VS[j]*time;
      const P &p1=cs[i],&p2=cs[j];
      double dist=abs(p1-p2);
      P cand[2];
      // 内包
      if(!EQ(abs(r1-r2),dist)&&abs(r1-r2)>dist){
        // 円1が含まれる場合
        if(r1<r2)cand[0]=cand[1]=P(p1.real()+r1,p1.imag());
        // 円2が含まれる場合
        else cand[0]=cand[1]=P(p2.real()+r2,p2.imag());
      }
      // 距離が半径の和以下なら１つ以上の交点を持つ
      else if(EQ(dist,r1+r2)||dist<r1+r2){
        pair<P,P> ps=crossPointsTwoCircle(p1,r1,p2,r2);
        cand[0]=ps.first,cand[1]=ps.second;
      }
      // 交点をもたないかつ内包もしない場合は計算しない
      else continue;
      // 2つの候補点についてvalidか調べる
      for(int k=0;k<2;k++){
        bool ok=true;
        for(int l=0;l<N;l++){
          double d=abs(cand[k]-cs[l]);
          double r=time*VS[l];
          if(!(EQ(d,r)||d<r)){
            ok=false;
            break;
          }
        }
        if(ok)return true;
      }
    }
  }
  return false;
}

int main(){
  while(cin>>N&&N){
    for(int i=0;i<N;i++){
      cin>>XS[i]>>YS[i]>>VS[i];
      cs[i]=P(XS[i],YS[i]);
    }
    double ub=1e+10;
    double lb=0;
    for(int ite=0;ite<200;ite++){
      double mid=(ub+lb)/2;
      if(check(mid))ub=mid;
      else lb=mid;
    }
    printf("%.10f\n",ub);
  }

  return 0;
}

Measured memory_bytes: 1276