Problem: ``Domino effect'' is a famous play using dominoes. A player sets up a chain of dominoes stood. After a chain is formed, the player topples one end of the dominoes. The first domino topples the second domino, the second topples the third and so on.

You are playing domino effect. Before you finish to set up a chain of domino, a domino block started to topple, unfortunately. You have to stop the toppling as soon as possible.

The domino chain forms a polygonal line on a two-dimensional coordinate system without self intersections. The toppling starts from a certain point on the domino chain and continues toward the both end of the chain. If the toppling starts on an end of the chain, the toppling continue toward the other end. The toppling of a direction stops when you touch the toppling point or the toppling reaches an end of the domino chain.

You can assume that:

* You are a point without volume on the two-dimensional coordinate system.
* The toppling stops soon after touching the toppling point.
* You can step over the domino chain without toppling it.



You will given the form of the domino chain, the starting point of the toppling, your coordinates when the toppling started, the toppling velocity and the your velocity. You are task is to write a program that calculates your optimal move to stop the toppling at the earliest timing and calculates the minimum time to stop the toppling.



Input

The first line contains one integer N, which denotes the number of vertices in the polygonal line of the domino chain (2 \leq N \leq 1000). Then N lines follow, each consists of two integers x_{i} and y_{i}, which denote the coordinates of the i-th vertex (-10,000 \leq x, y \leq 10000). The next line consists of three integers x_{t}, y_{t} and v_{t}, which denote the coordinates of the starting point and the velocity of the toppling. The last line consists of three integers x_{p}, y_{p} and v_{p}, which denotes the coordinates of you when the toppling started and the velocity (1 \leq v_{t} \lt v_{p} \leq 10). You may assume that the starting point of the toppling lies on the polygonal line.

Output

Print the minimum time to stop the toppling. The output must have a relative or absolute error less than 10^{-6}.

Examples

Input

2
0 0
15 0
5 0 1
10 10 2


Output

5.0


Input

3
-10 0
0 0
0 10
-1 0 1
3 0 2


Output

4.072027


Input

2
0 0
10 0
5 0 1
9 0 3


Output

2.0

Solution (in CPP):

Solution:
#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-7)
#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);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }

  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; }

};

struct Segment{
  Point p1,p2;
  Segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){}
  bool operator <  (const Segment& s) const { return ( p2 == s.p2 ) ? p1 < s.p1 : p2 < s.p2; }
  bool operator == (const Segment& s) const { return ( s.p1 == p1 && s.p2 == p2 ) || ( s.p1 == p2 && s.p2 == p1 ); }

};

typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;

ostream& operator << (ostream& os,const Point& a){ os << "(" << a.x << "," << a.y << ")"; }

ostream& operator << (ostream& os,const Segment& a){ os << "( " << a.p1 << " , " << a.p2 << " )"; }

double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }

double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }

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

double abs(Point a){ return sqrt(norm(a)); }

//rad は角度をラジアンで持たせること
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }

// 度をラジアンに変換
double toRad(double agl){ return agl*M_PI/180.0; }

// a => prev, b => cur, c=> next
// prev から cur へ行って next へ行く際の角度を求める
double getArg(Point a,Point b,Point c){
  double arg1 = atan2(b.y-a.y,b.x-a.x);
  double arg2 = atan2(c.y-b.y,c.x-b.x);
  double arg = fabs( arg1 - arg2 );
  while( arg > M_PI ) arg -= 2.0 * M_PI;
  return fabs(arg);
}

int ccw(Point p0,Point p1,Point p2){
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}

bool intersectLL(Line l, Line m) {
  return abs(cross(l.p2-l.p1, m.p2-m.p1)) > EPS || // non-parallel
         abs(cross(l.p2-l.p1, m.p1-l.p1)) < EPS;   // same line
}
bool intersectLS(Line l, Line s) {
  return cross(l.p2-l.p1, s.p1-l.p1)*       // s[0] is left of l
         cross(l.p2-l.p1, s.p2-l.p1) < EPS; // s[1] is right of l
}
bool intersectLP(Line l,Point p) {
  return abs(cross(l.p2-p, l.p1-p)) < EPS;
}
bool intersectSS(Line s, Line t) {
  return ccw(s.p1,s.p2,t.p1)*ccw(s.p1,s.p2,t.p2) <= 0 &&
         ccw(t.p1,t.p2,s.p1)*ccw(t.p1,t.p2,s.p2) <= 0;
}
bool intersectSP(Line s, Point p) {
  return abs(s.p1-p)+abs(s.p2-p)-abs(s.p2-s.p1) < EPS; // triangle inequality
}

Point projection(Line l,Point p) {
  double t = dot(p-l.p1, l.p1-l.p2) / norm(l.p1-l.p2);
  return l.p1 + (l.p1-l.p2)*t;
}
Point reflection(Line l,Point p) {
  return p + (projection(l, p) - p) * 2;
}
double distanceLP(Line l, Point p) {
  return abs(p - projection(l, p));
}
double distanceLL(Line l, Line m) {
  return intersectLL(l, m) ? 0 : distanceLP(l, m.p1);
}

double distanceLS(Line l, Line s) {
  if (intersectLS(l, s)) return 0;
  return min(distanceLP(l, s.p1), distanceLP(l, s.p2));
}
double distanceSP(Line s, Point p) {
  Point r = projection(s, p);
  if (intersectSP(s, r)) return abs(r - p);
  return min(abs(s.p1 - p), abs(s.p2 - p));
}

double distanceSS(Line s, Line t) {
  if (intersectSS(s, t)) return 0;
  return min(min(distanceSP(s, t.p1), distanceSP(s, t.p2)),
             min(distanceSP(t, s.p1), distanceSP(t, s.p2)));
}

Point crosspoint(Line l,Line m){
  double A = cross(l.p2-l.p1,m.p2-m.p1);
  double B = cross(l.p2-l.p1,l.p2-m.p1);
  if(abs(A) < EPS && abs(B) < EPS){
    vector<Point> vec;
    vec.push_back(l.p1),vec.push_back(l.p2),vec.push_back(m.p1),vec.push_back(m.p2);
    sort(vec.begin(),vec.end());
    assert(vec[1] == vec[2]); //同じセグメントかもよ
    return vec[1];
    //return m.p1;
  }
  if(abs(A) < EPS)assert(false);
  return m.p1 + (m.p2-m.p1)*(B/A);
}

//cross product of pq and pr
double cross3p(Point p,Point q,Point r) { return (r.x-q.x) * (p.y -q.y) - (r.y - q.y) * (p.x - q.x); }
  
//returns true if point r is on the same line as the line pq
bool collinear(Point p,Point q,Point r) { return fabs(cross3p(p,q,r)) < EPS; }
  
//returns true if point t is on the left side of line pq
bool ccwtest(Point p,Point q,Point r){
  return cross3p(p,q,r) > 0; //can be modified to accept collinear points
}
 
bool onSegment(Point p,Point q,Point r){
  return collinear(p,q,r) && equals(sqrt(pow(p.x-r.x,2)+pow(p.y-r.y,2)) + sqrt(pow(r.x-q.x,2) + pow(r.y-q.y,2) ),sqrt(pow(p.x-q.x,2)+pow(p.y-q.y,2)) ) ;
}
  

bool isConvex(vector<Point> p) {
  int sz = (int)p.size();
  if(sz < 3)return false;//boundary case, we treat a point or a line as not convex
  bool isLeft = ccwtest(p[0],p[1],p[2]);
  for(int i=1; i<(int)p.size();i++)
    if(ccwtest(p[i],p[(i+1)%sz],p[(i+2)%sz]) != isLeft) return false;
  return true;
}


double angle(Point a,Point b,Point c) {
  double ux = b.x - a.x, uy = b.y - a.y;
  double vx = c.x - a.x, vy = c.y - a.y;
  return acos((ux*vx + uy*vy)/sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy)));
}  
  
//多角形poly内（線分上も含む）に点pが存在するかどうは判定する  
bool inPolygon(Polygon poly,Point p){
  if((int)poly.size() == 0)return false;
  rep(i,poly.size()) if(onSegment(poly[i],poly[(i+1)%poly.size()],p))return true;
  double sum = 0;
  for(int i=0; i < (int)poly.size() ;i++) {
    if( equals(cross(poly[i]-p,poly[(i+1)%poly.size()]-p),0.0) ) continue; // ３点が平行だとangleがnanを返しsumがnanになり死ぬ
    if( cross3p(p,poly[i],poly[(i+1)%poly.size()]) < 0 ) sum -= angle(p,poly[i],poly[(i+1)%poly.size()]);
    else                                                 sum += angle(p,poly[i],poly[(i+1)%poly.size()]);
  }
  // あまり誤差を厳しくしすぎると良くないので以下のほうが良い 
  const double eps = 1e-5;
  return (fabs(sum - 2*M_PI) < eps || fabs(sum + 2*M_PI) < eps);
}  


int n,tp;
vector<Point> ps,nps;
Point topple,sp;
double v[2];

inline bool isValid(int x) { return 0 <= x && x < nps.size(); }
inline bool LTE(double a,double b) { return  equals(a,b) || a < b; }
inline bool LT(double  a,double b) { return !equals(a,b) && a < b; }

Point getPoint(double t,int dir){
  int coef = (dir?1:-1);
  int cur = tp;
  double remain = t;
  while( isValid(cur+coef) ) {
    double len = abs( nps[cur+coef] - nps[cur] );
    Vector e = ( nps[cur+coef] - nps[cur] ) / len;
    Point p = nps[cur] + e * ( remain * v[0] );
    if( onSegment(nps[cur],nps[cur+coef],p) ) return p;
    cur += coef;
    remain -= len / v[0];
    assert( LTE(0,remain) );
  }
  return nps[cur];
}



bool check(double limit,int dir){

  Point LP = getPoint(limit,dir);



  Point temp_P = getPoint(limit,!dir);

  if( ( LP == nps[0] || LP == nps[(int)nps.size()-1] ) && ( temp_P == nps[0] || temp_P == nps[(int)nps.size()-1] ) ) return true;

  double len_temp = abs( LP - sp );
  double time_temp = len_temp / v[1];
  if( !LTE(time_temp,limit) ) return false;

  Point p = getPoint(limit,!dir);
  if( p == nps[0] || p == nps[(int)nps.size()-1] ) {
      double len = abs( LP - sp );
      double ntime = len / v[1];
      if( LTE(ntime,limit) ) return true;
  }

  double L = 0, R = limit;
  bool success = false;
  rep(_,120){
    double M = ( L + R ) * 0.5;
    p = getPoint(limit-M,!dir);
    double len = abs( LP - p );
    double ntime = len / v[1];
    if( !LTE(ntime,M) ) { L = M; }
    else R = M, success = true;
  }
  if( !success ) return false;
  p = getPoint(limit-L,!dir);
  double len = abs( LP - p ) + abs( p - sp );
  double ntime = len / v[1];
  return LTE(ntime,limit);
}

void compute(){
  nps.clear();
  nps.push_back(ps[0]);
  bool already = false;
  REP(i,1,n) {
    if( !already && onSegment(ps[i-1],ps[i],topple) ) { 
      tp = nps.size();
      nps.push_back(topple);
      already = true;
    }
    nps.push_back(ps[i]);
  }
  assert( already );

  //cout << check(7,1) << endl;
  //return; 
  /*
    double t;
    int d;
    while( cin >> t >> d){

    cout << getPoint(t,d) << endl;
    cout << "check = " << check(t,d) << endl;
    Point p1 = getPoint(t,d), p2 = getPoint(t,!d);
    cout << p1 << " " << p2 << endl;
    cout << ( abs( p1 - p2 ) + abs( p2 - sp ) ) / v[1] << endl;
  }

    return;
  */
  double L = 0, R = 1e10;
  bool success = false;
  rep(_,120){
    double M = ( L + R ) * 0.5;
    if( check(M,0) || check(M,1) ) R = M;
    else           L = M;
  }
  printf("%.10f\n",L);
}

int main(){
  cin >> n;
  ps.resize(n);
  rep(i,n) cin >> ps[i].x >> ps[i].y;
  cin >> topple.x >> topple.y >> v[0];
  cin >> sp.x >> sp.y >> v[1];
  compute();
  return 0;
}