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

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



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];
  }
  if( abs(A) < EPS ) assert(false);
  return m.p1 + (m.p2-m.p1) * (B/A);
}

Polygon cutPolygon( Polygon P, Line l ){
    Polygon u;
    for ( int i = 0; i < P.size(); i++ ){
        Point a = P[i], b = P[(i+1)%P.size()];
        if ( ccw(l.p1, l.p2, a) != CLOCKWISE ) u.push_back(a);
	 //if( ccw(l.p1,l.p2,a) != COUNTER_CLOCKWISE ) R.push_back(a); // ????????????????????´???
        if ( ccw(l.p1, l.p2, a) * ccw(l.p1, l.p2, b) == -1 ){
      u.push_back(crosspoint(Segment(a, b), l));
        }
    }
    return u;
}



//????????? Verify??????????????????Verify??¨???????????????
 
//Verify AOJ 0115
class Point3d{
public:
  double x,y,z;
 
  Point3d(double x=0,double y=0,double z=0):x(x),y(y),z(z){}
 
  Point3d operator + (const Point3d& a){
    return Point3d(x+a.x,y+a.y,z+a.z);
  }
  Point3d operator - (const Point3d& a){
    return Point3d(x-a.x,y-a.y,z-a.z);
  }
  Point3d operator * (const double& d){
    return Point3d(x*d,y*d,z*d);
  }
  Point3d operator / (const double& d){
    return Point3d(x/d,y/d,z/d);
  }
 
  bool operator < (const Point3d& p)const { return !equals(x,p.x)?x<p.x:((!equals(y,p.y))?y<p.y:(!equals(z,p.z)&&z<p.z)); }
 
  bool operator == (const Point3d& p)const{
    return equals(x,p.x) && equals(y,p.y) && equals(z,p.z);
  }
 
};
 
//Verify AOJ 0115
struct Segment3d{
  Point3d p[2];
  Segment3d(Point3d p1=Point3d(),Point3d p2=Point3d()){
    p[0] = p1, p[1] = p2;
  }
 bool operator == (const Segment3d& seg)const{
    return ( p[0] == seg.p[0] && p[1] == seg.p[1] ) || ( p[0] == seg.p[1] && p[1] == seg.p[0] );
 }
};
 
typedef Point3d Vector3d;
typedef Segment3d Line3d;
  
ostream& operator << (ostream& os,const Point3d& p){
  os << "(" << p.x << "," << p.y << "," << p.z << ")";
}
 
ostream& operator << (ostream& os,const Segment3d& seg){
  os << "(" << seg.p[0] << "," << seg.p[1] << ")";
}
 
//Verify AOJ 0115
double dot(const Point3d& a,const Point3d& b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
 
//Verify AOJ 0115
Vector3d cross(const Point3d& a,const Point3d& b){
  return Vector3d(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
}
 
//Verify AOJ 0115
inline double norm(const Point3d &p){
  return p.x*p.x + p.y*p.y + p.z*p.z;
}
 
//Verify AOJ 0115
inline double abs(const Point3d &p){
  return sqrt(norm(p));
}
 
inline double toRad(double theta){
  return theta * M_PI / 180.0;
}
 
 
 // Verify AOJ 1331
bool on_line3d(Line3d line,Point3d p){
  return equals(abs(cross(p-line.p[0],line.p[1]-line.p[0])),0);
}
 
// Verify AOJ 1331
bool on_segment3d(Segment3d seg,Point3d p){
  if( !on_line3d(seg,p) ) return false;
  double dist[3] = { abs(seg.p[1]-seg.p[0]), abs(p-seg.p[0]), abs(p-seg.p[1]) };  
  return on_line3d(seg,p) && equals(dist[0],dist[1]+dist[2]);
}
 
//Verify AOJ 0115
bool point_on_the_triangle3d(Point3d tri1,Point3d tri2,Point3d tri3,Point3d p){
 
  //????????????p????????£?????´??????????§???¢?????¨?????????
  //if( on_segment3d(Segment3d(tri1,tri2),p) ) return true;
  //if( on_segment3d(Segment3d(tri2,tri3),p) ) return true;
  //if( on_segment3d(Segment3d(tri3,tri1),p) ) return true;

  vector<Point3d> vec(3);
  vec[0] = tri1, vec[1] = tri2, vec[2] = tri3;
  double area = 0;
  {
    double a = abs(vec[0]-vec[1]), b = abs(vec[1]-vec[2]), c = abs(vec[2]-vec[0]);
    double s = ( a + b + c ) / 2;
    area = sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) );
  }
  double sum = 0;
  rep(i,3){
    double a = abs(vec[i]-vec[(i+1)%3]), b = abs(vec[(i+1)%3]-p), c = abs(p-vec[i]);
    double s = ( a + b + c ) / 2;
    sum += sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) );
  }
  return equals(sum,area);

// ---------- ??\???????????°????????¨???????????? ---------

  Vector3d v1 = tri2 - tri1;
  Vector3d v2 = tri3 - tri2;
  Vector3d v3 = tri1 - tri3;
 
  Vector3d cp[3] = { cross(v1,p-tri1), cross(v2,p-tri2), cross(v3,p-tri3) };
  double d1 = dot(cp[0],cp[1]);
  double d2 = dot(cp[0],cp[2]);
 
  // ????????????p????????£?????´???,????§???¢?????¨??????????????????
  //if( ( !equals(d1,0.0) && d1 > 0 ) && ( !equals(d2,0.0) && d2 > 0 ) ) return true;
 
  // ????????????p????????£?????´???,????§???¢?????¨?????????
  if( ( equals(d1,0.0) || d1 > 0 ) && ( equals(d2,0.0) || d2 > 0 ) ) return true;
  return false;
}
 
inline Point3d rotateX(Point3d p,double rad){
  return Point3d(p.x,p.y*cos(rad)-p.z*sin(rad),p.y*sin(rad)+p.z*cos(rad));
}
 
inline Point3d rotateY(Point3d p,double rad){
  return Point3d(p.x*cos(rad)+p.z*sin(rad),p.y,-p.x*sin(rad)+p.z*cos(rad));
}
 
inline Point3d rotateZ(Point3d p,double rad){
  return Point3d(p.x*cos(rad)-p.y*sin(rad),p.x*sin(rad)+p.y*cos(rad),p.z);
}
 
inline Point3d rotateEuler(Point3d p,double alpha,double beta,double gamma){
  return Point3d( (cos(alpha)*cos(beta)*cos(gamma)-sin(alpha)*sin(gamma)) * p.x + (-cos(alpha)*cos(beta)*sin(gamma)-sin(alpha)*cos(gamma)) * p.y + (cos(alpha)*sin(beta)) * p.z,
		  (sin(alpha)*cos(beta)*cos(gamma)+cos(alpha)*sin(gamma)) * p.x + (-sin(alpha)*cos(beta)*sin(gamma)+cos(alpha)*cos(gamma)) * p.y + (sin(alpha)*sin(beta)) * p.z,
		  (-sin(beta)*cos(gamma)) * p.x + (sin(beta)*sin(gamma)) * p.y + (cos(beta)) * p.z);
}
 
inline Point3d rotateRollPitchYaw(Point3d p,double roll,double pitch,double yaw){
  return Point3d( ( cos(roll) * cos(pitch) ) * p.x + ( cos(roll) * sin(pitch) * sin(yaw) - sin(roll) * cos(yaw) ) * p.y + ( cos(roll) * sin(pitch) * cos(yaw) + sin(roll) * sin(yaw) ) * p.z,
		  ( sin(roll) * cos(pitch) ) * p.x + ( sin(roll) * sin(pitch) * sin(yaw) + cos(roll) * cos(yaw) ) * p.y + ( sin(roll) * sin(pitch) * cos(yaw) - cos(roll) * sin(yaw) ) * p.z,
		  -sin(pitch) * p.x + cos(pitch) * sin(yaw) * p.y + cos(pitch) * cos(yaw) * p.z);
}
 
 
class Plane3d{
public:
  Point3d normal_vector; //??????????????????
  double d; // ?????¢????¨???? normal_vector.x * x + normal_vector.y * y + normal_vector.z * z + d = 0
 
  Plane3d(Point3d normal_vector=Point3d(),double d=0):normal_vector(normal_vector),d(d){}
  Plane3d(Vector3d a,Vector3d b,Vector3d c){
    Vector3d v1 = b - a;
    Vector3d v2 = c - a;
    Vector3d tmp = cross(v1,v2);
    normal_vector = tmp / abs(tmp);
    set_d(a);
  }
 
  //Verify AOJ 0115
  //??????????????????normal_vector??¨?????¢??????????????????d????¨??????????
  void set_d(Point3d p){
    d = dot(normal_vector,p);
  }
 
// Verify Yukicoder No132
  //?????¢??¨???p????????¢????±???????
  double distanceP(Point3d p){
    Point3d a = normal_vector * d;//?????¢??????????????????????????????
    return abs( dot(p-a,normal_vector) );
  }

  double distanceP2(Point3d p){
    Point3d a = normal_vector * d;//?????¢??????????????????????????????
    return dot(p-a,normal_vector);
  } 

  //?????¢?????§?????£??¨??????p??¨?????????????±???????
  Point3d nearest_point(Point3d p){
    Point3d a = normal_vector * d;
    return p - ( normal_vector * dot(p-a,normal_vector) );
  }
 
  //Verify AOJ 0115
  //?????¢??¨????????????????????????
  bool intersectS(Segment3d seg){
    Point3d a = normal_vector * d;
    double res1 = dot(a-seg.p[0],normal_vector);
    double res2 = dot(a-seg.p[1],normal_vector);
    if( res1 > res2 ) swap(res1,res2);
    //cout << res1 << " < " << res2 << endl;
    if( ( equals(res1,0.0) || res1 < 0 ) && ( equals(res2,0.0) || res2 > 0 ) ) return true;
    return false;
  }
 
  //Verify AOJ 0115
  //?????¢??¨???????????????????±???????
  Point3d crosspointS(Segment3d seg){
    Point3d a = normal_vector * d;
    double dot_p0a = fabs(dot( seg.p[0]-a,normal_vector ));
    double dot_p1a = fabs(dot( seg.p[1]-a,normal_vector ));
    if( equals(dot_p0a+dot_p1a,0) ) return seg.p[0];
    return seg.p[0] + ( seg.p[1] - seg.p[0] ) * ( dot_p0a / ( dot_p0a + dot_p1a ) );
  }
 
};
 
double distanceLP(Line3d line,Point3d p){
  return abs(cross(line.p[1]-line.p[0],p-line.p[0])) / abs(line.p[1]-line.p[0]);
}
 
// Verify AOJ 1331
Point3d project(Segment3d seg,Point3d p){
  Vector3d base = seg.p[1] - seg.p[0];
  double t = dot(p-seg.p[0],base) / norm(base);
  return seg.p[0] + base * t;
}
 
// Verify AOJ 1331
Point3d reflect(Segment3d seg,Point3d p){
  return p + (project(seg,p)-p) * 2.0;
}

// Verify AOJ 1331
double distanceSP(Segment3d seg,Point3d p){
  Point3d r = project(seg,p);
  if( on_segment3d(seg,r) ) return abs(p-r);
  return min(abs(seg.p[0]-p),abs(seg.p[1]-p));
}

//Verify AOJ 2081
bool isParallel(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
  return equals(tmp,0.0);
}
 
//Verify AOJ 2081 
//l1,l2??????????????????????????¨??§??????????????§??¨???
Segment3d nearest_segmentLL(Line3d l1,Line3d l2){
  assert(!isParallel(l1,l2)); // ???????????´???????????¨??????
  // l1.p[0] = A, l1.p[1] = B, l2.p[0] = C, l2.p[1] = D
  Vector3d AB = l1.p[1] - l1.p[0];
  Vector3d CD = l2.p[1] - l2.p[0];
  Vector3d AC = l2.p[0] - l1.p[0];
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double d1 = (dot(n1,AC)-dot(n1,n2)*dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  double d2 = (dot(n1,n2)*dot(n1,AC)-dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  return Segment3d(l1.p[0]+n1*d1,l2.p[0]+n2*d2);
}
 
//Verify AOJ 2081
bool intersectLL(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
 
  //????????????l1,l2?????´???????????????
  if( equals(abs(B-A),0.0) || equals(abs(D-C),0.0) ){
    /*
      ????????´????????¨???
      ??????????????????????????????????????????????????£?????????????????§??????????????????????????????????????§?????????
    */
    return false;
  }
 
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
 
  if( equals(tmp,0.0) ) return 0; // ??´????????????
 
  Segment3d ns = nearest_segmentLL(l1,l2);
  if( ns.p[0] == ns.p[1] ) return true;
  return false;
}

bool intersectSS(Segment3d seg1,Segment3d seg2){
  if( isParallel(seg1,seg2) ) return false;
  Segment3d seg = nearest_segmentLL(seg1,seg2);
  if( !( seg.p[0] == seg.p[1] ) ) return false;
  Point3d cp = seg.p[1];
  return on_segment3d(seg1,cp) && on_segment3d(seg2,cp);
}

typedef pair<Point3d,bool> P3db;

/* 
??????AOJ2562??§Verify???????????????????????§??\???????????§?????????????????????????????¨
Input:
??????????????¢pl1,pl2
Output:
??????????????¢????????????????????´???     -> first:???????????????????????????, second:true
?????????????????????????????????????????´??? -> first:empty            , second:false

 */
P3db intersectPlPl(const Plane3d &pl1,const Plane3d &pl2){
  Vector3d v = cross(pl1.normal_vector,pl2.normal_vector);
  if( !equals(v.x,0.0) ){
    return P3db(Point3d(0,
                        (pl1.d*pl2.normal_vector.z-pl2.d*pl1.normal_vector.z)/v.x,
                        (pl1.d*pl2.normal_vector.y-pl2.d*pl1.normal_vector.y)/(-v.x)),true);
  }
  if( !equals(v.y,0.0) ){
    return P3db(Point3d((pl1.d*pl2.normal_vector.z-pl2.d*pl1.normal_vector.z)/(-v.y),
                         0,
                        (pl1.d*pl2.normal_vector.x-pl2.d*pl1.normal_vector.x)/v.y),true);
  }
  if( !equals(v.z,0.0) ){
    return P3db(Point3d((pl1.d*pl2.normal_vector.y-pl2.d*pl1.normal_vector.y)/v.z,
                        (pl1.d*pl2.normal_vector.x-pl2.d*pl1.normal_vector.x)/(-v.z),
                        0),true);
  }
  return P3db(Point3d(),false);//??????????????§?????????????????????????????¨?????????
}

/* Verify AOJ 2562
Input:
??????????????¢plane,plane2??¨?????????????????????????????????
Output:
??????????????¢?????????

??¬???:
2???????????¢???????????????????????????????????????????????????
?????¨????????????????????????????????????????????????????????????????????°??????????????????
??????????????????????????????intersectPlPl??§????????§??????
??\?????¢??????????§?????????£???????????£???
 */
Line3d intersectPlPl_converter(Plane3d plane,Plane3d plane2,Point3d tmp){
  Vector3d ve = cross(plane.normal_vector,plane2.normal_vector);
  return Line3d(tmp,tmp+(ve*10)); // ??????????????°??§?????????????????§???10
}

// x >= y
bool GTE(double x, double y){ return equals(x,y) || x > y; }

// x > y
bool GT(double x, double y){ return !equals(x,y) && x > y; }

// x < y
bool LT(double x, double y){ return !equals(x,y) && x < y; }

// x <= y
bool LTE(double x, double y){ return equals(x,y) || x < y; }



//---------------------------------------------

const int IINF = INT_MAX;
vector<Point3d> ps;
int V;

bool checkPlane(Plane3d plane,long long &bit_stream){
  int base = -IINF;
  rep(i,V) {
    if( (bit_stream>>i) & 1LL ) continue;
    double dist = plane.distanceP2(ps[i]);
    if( equals(dist,0.0) ) {
      bit_stream |= (1LL<<i);
    } else {
      int res = LT(dist,0);
      if( base == -IINF ) {
	base = res;
      } else if( base != res ) {
	return false;
      }
    }
  }
  return true;
}

pair<Point, Point> crosspointCC( Point C1, double r1, Point C2, double r2) {
  complex<double> c1(C1.x,C1.y);
  complex<double> c2(C2.x,C2.y);
  complex<double> A = conj(c2-c1), B = (r2*r2-r1*r1-(c2-c1)*conj(c2-c1)), C = r1*r1*(c2-c1);
  complex<double> D = B*B-4.0*A*C;
  complex<double> z1 = (-B+sqrt(D))/(2.0*A)+c1, z2 = (-B-sqrt(D))/(2.0*A)+c1;
  return pair<Point, Point>(Point(z1.real(),z1.imag()),Point(z2.real(),z2.imag()));
}

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

typedef long long ll;
vector<Point> convert3Dinto2D(ll bit_stream,Point3d a,Point3d b,Point3d c){
  vector<Point> ret;
  Point p1 = Point(0,0);
  Point p2 = Point(abs(a-b),0);
  pair<Point,Point> pp = crosspointCC(p1,abs(c-a),p2,abs(c-b));
  Point p3 = pp.first;
  if( LT(p3.y,0) ) p3 = pp.second;
  ret.push_back(p1);
  ret.push_back(p2);
  ret.push_back(p3);
  
  rep(i,V) if( (bit_stream>>i) & 1LL ) {
    if( ps[i] == a ) continue;
    if( ps[i] == b ) continue;
    if( ps[i] == c ) continue;

    double r1 = abs(ps[i]-a);
    double r2 = abs(ps[i]-b);
    double r3 = abs(ps[i]-c);
    pp = crosspointCC(p1,r1,p2,r2);
    if( equals(abs( pp.first - p3 ),r3) ) {
      ret.push_back(pp.first);
    } else {
      ret.push_back(pp.second);
    }
  }
  return ret;
}


Polygon andrewScan(vector<Point> s)
{
  Polygon u,l;
  if(s.size() < 3)return s;

  sort(s.begin(),s.end());

  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[s.size()-1]);
  l.push_back(s[s.size()-2]);

  for(int i=2;i<s.size();i++)
    {
      for(int n=u.size();n >= 2 && ccw(u[n-2],u[n-1],s[i]) != CLOCKWISE; n--)
	u.pop_back();
      u.push_back(s[i]);
    }

  for(int i=s.size()-3; i>=0 ; i--)
    {
      for(int n=l.size(); n >= 2 && ccw(l[n-2],l[n-1],s[i]) != CLOCKWISE; n--)
	l.pop_back();
      l.push_back(s[i]);
    }

  reverse(l.begin(),l.end());

  for(int i = u.size()-2; i >= 1; i--) l.push_back(u[i]);

  return l;
}

double getArea(vector<Point>& vec) {
  double sum = 0;
  for(int i=0;i<vec.size();i++)
    sum += cross(vec[i],vec[(i+1)%vec.size()]);
  return fabs(sum)/2.0;
}



void compute(){
  double area = 0;
  vector<ll> vec;
  vector<Point3d> X,Y,Z;
  rep(i,V){ //
    rep(j,V){
      rep(k,V){
	Point3d v1 = ps[j] - ps[i];
	Point3d v2 = ps[k] - ps[i];
	if( equals(abs(cross(v1,v2)),0.0) ) continue;
	Plane3d plane(ps[i],ps[j],ps[k]);
	long long bit_stream = (1LL<<i) | (1LL<<j) | (1LL<<k);

  	if( checkPlane(plane,bit_stream) ) {
	  bitset<10> BIT(bit_stream);

	  vec.push_back(bit_stream);
	  X.push_back(ps[i]);
	  Y.push_back(ps[j]);
	  Z.push_back(ps[k]);

	  //cout<<BIT<<' '<<i<<' '<<j<<' '<<k<<endl;
	  //vector<Point> on_ps = convert3Dinto2D(bit_stream,ps[i],ps[j],ps[k]);
	}
      }
    }
  }
  map<ll,bool> flg;

  rep(i,(int)vec.size()){
    ll bit_stream = vec[i];
    if(flg[bit_stream])continue;
    flg[bit_stream]=true;
    vector<Point> on_ps = convert3Dinto2D(bit_stream,X[i],Y[i],Z[i]);
    //cout <<on_ps.size() << " --------" << endl;
    vector<Point> convex = andrewScan(on_ps);
    //cout <<convex.size() << " --------" << endl;
    area += getArea(convex);
  }
  printf("%.10f\n",area);
}

int main(){
  /*
  Point3d p1 = Point3d(0,0,0);
  Point3d p2 = Point3d(0,1,0);
  Point3d p3 = Point3d(0,1,1);
  Point3d p4 = Point3d(-1,0,1);
  Plane3d p(p1,p2,p3);
  cout << p.distanceP(p4) << endl;
*/

  cin >> V;
  ps.resize(V);
  rep(i,V) cin >> ps[i].x >> ps[i].y >> ps[i].z;
  compute();
  return 0;
}

Measured memory_bytes: 3744