Problem: You are given one polygonal line, which is a collection of line segments. Your task is to calculate the sum of areas enclosed by the polygonal line.

A point is defined to be "enclosed" if and only if the point is unreachable without crossing at least one line segment from the point at infinity.



Input

The first line contains one integers N (2 ≤ N ≤ 100). N is the number of segments.

Each of the following N lines consists of two integers Xi and Yi (-105 ≤ Xi, Yi ≤ 105, 1 ≤ i ≤ N) which represents a vertex. A polygonal line is the segments which connect (Xj, Yj) and (Xj+1, Yj+1) ((Xj, Yj) ≠ (Xj+1, Yj+1), 1 ≤ j ≤ N-1). The distance between a segment Sj and all vertices except the end points on segment Sj is guaranteed to be greater than 0.01.

Output

Output the answer in a line. The answer may be printed with an arbitrary number of decimal digits, but may not contain an absolute or relative error greater than or equal to 10-6.

Examples

Input

5
0 0
1 1
1 0
0 1
0 0


Output

0.5


Input

5
0 0
1 1
1 0
0 1
1 0


Output

0.25


Input

21
1 1
-1 1
-1 2
-2 2
-2 1
-1 1
-1 -1
-2 -1
-2 -2
-1 -2
-1 -1
1 -1
1 -2
2 -2
2 -1
1 -1
1 1
2 1
2 2
1 2
1 1


Output

8


Input

16
0 0
1 0
1 1
0 1
0 2
0 3
1 3
1 2
2 2
2 3
3 3
3 2
3 1
2 1
2 0
3 0


Output

0


Input

7
26 52
33 12
-51 68
16 61
43 -26
87 24
12 10


Output

2714.840579710

Solution (in CPP):

Solution:
#include<bits/stdc++.h>

#define EQ(a,b) (abs((a)-(b)) < EPS)
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define fs first
#define sc second
#define pb push_back
#define sz size()
#define all(a) (a).begin(),(a).end()

using namespace std;
typedef long double D;
typedef complex<D> P;
typedef pair<P,P> L;
typedef vector<P> Poly;
typedef pair<P,D> C;

typedef vector<int> vi;
typedef pair<int,int> pii;
typedef pair<D,int> pdi;

const D EPS = 1e-11;
const D PI = acos(-1);

bool lessP(const P &a,const P &b){
  return EQ(real(a),real(b))?imag(a)<imag(b):real(a)<real(b);
}
bool eqP(const P &a, const P &b){return EQ(a,b);}

bool lessL(const L &a,const L &b){
  return eqP(a.fs,b.fs)?lessP(a.sc,b.sc):lessP(a.fs,b.fs);
}
bool eqL(const L &a, const L &b){return eqP(a.fs,b.fs)&&eqP(a.sc,b.sc);}


//for vector
inline D dot(P x, P y){return real(conj(x)*y);}
inline D cross(P x, P y){return imag(conj(x)*y);}

//for line(segment)
int ccw(P a,P b,P c){
  b -= a;c -= a;
  if (cross(b,c)>EPS) return 1;   //counter clockwise
  if (cross(b,c)<-EPS) return -1; //clockwise
  if (dot(b, c)<-EPS) return 2;   //c--a--b on line
  if (abs(b)<abs(c)) return -2;   //a--b--c on line
  return 0;                       //on segment
}

inline bool para(L a,L b){return abs(cross(a.fs-a.sc,b.fs-b.sc))<EPS;}

inline P line_cp(L a,L b){
  return a.fs+(a.sc-a.fs)*cross(b.sc-b.fs,b.fs-a.fs)/cross(b.sc-b.fs,a.sc-a.fs);
}

inline bool is_cp(L a,L b){
  if(ccw(a.fs,a.sc,b.fs)*ccw(a.fs,a.sc,b.sc)<=0)
    if(ccw(b.fs,b.sc,a.fs)*ccw(b.fs,b.sc,a.sc)<=0)return true;
  return false;
}

//for polygon
inline D area(Poly p){
  if(p.sz<3)return 0;
  D res = cross(p[p.sz-1],p[0]);
  rep(i,p.sz-1)res += cross(p[i],p[i+1]);
  return res/2;
}

//b divides a into segments
inline vector<L> seg_cut(L a, L b){
  vector<L> res;
  
  if(!is_cp(a,b))res.pb(a);
  else{
    if(para(a,b)){
      int cpf = ccw(a.fs,a.sc,b.fs), cps = ccw(a.fs,a.sc,b.sc);
      if(!cpf && !cps){
	if(ccw(a.fs,b.fs,b.sc)==0){
	  res.pb(L(a.fs,b.sc)); res.pb(L(b.sc,b.fs)); res.pb(L(b.fs,a.sc));
	}else{
	  res.pb(L(a.fs,b.fs)); res.pb(L(b.fs,b.sc)); res.pb(L(b.sc,a.sc));
	}
      }else if(!cpf){
	res.pb(L(a.fs,b.fs)); res.pb(L(a.sc,b.fs));
      }else if(!cps){
	res.pb(L(a.fs,b.sc)); res.pb(L(a.sc,b.sc));
      }else res.pb(a);
    }else{
      P cp = line_cp(a,b);
      if(!EQ(a.fs,cp) && !EQ(a.sc,cp)){
	res.pb(L(a.fs,cp)); res.pb(L(a.sc,cp));
      }else{
	res.pb(a);
      }
    }
  }
  return res;
}

inline vector<L> seg_set_cut(vector<L> l){
  vector< vector<L> > vl(l.sz);
  rep(i,l.sz)vl[i].pb(l[i]);
  
  rep(i,l.sz)for(int j=i+1;j<(int)l.sz;j++){
    rep(ii,vl[i].sz)rep(jj,vl[j].sz){
      if(is_cp(vl[i][ii],vl[j][jj])){
	vector<L> a = seg_cut(vl[i][ii],vl[j][jj]);
	vector<L> b = seg_cut(vl[j][jj],vl[i][ii]);

	while(a.sz>1){vl[i].pb(a.back()); a.pop_back();}
	vl[i][ii] = a[0];
	while(b.sz>1){vl[j].pb(b.back()); b.pop_back();}
	vl[j][jj] = b[0];
	goto END;
      }
    }
    END:;
  }

  vector<L> res;
  rep(i,l.sz)rep(j,vl[i].size()){
    if(lessP(vl[i][j].sc,vl[i][j].fs))swap(vl[i][j].fs,vl[i][j].sc);
    res.pb(vl[i][j]);
  }
  sort(all(res),lessL);
  res.erase(unique(all(res),eqL),res.end());
  return res;
}

inline void seg_arrange(vector<L> input_segs, vector<P> &vp,
			vector<pii> &ve, vector< vector<pii> > &graph){
  vector<L> vl = seg_set_cut(input_segs);

  /*  
  cout << vl.sz << endl;
  rep(i,vl.sz)cout << vl[i].fs.real() << " " << vl[i].fs.imag() << " "
  		   << vl[i].sc.real() << " " << vl[i].sc.imag() << endl;
  */
  vp.clear();
  rep(i,vl.sz){
    vp.pb(vl[i].fs);
    vp.pb(vl[i].sc);
  }
  sort(all(vp),lessP);
  vp.erase(unique(all(vp),eqP),vp.end());

  ve.resize(vl.sz);
  vector< vector<pdi> > edges(vp.sz);

  rep(i,vl.sz){
    int s,t;
    rep(j,vp.sz){
      if(EQ(vl[i].fs,vp[j]))s = j;
      if(EQ(vl[i].sc,vp[j]))t = j;
    }
      /*
    int s = lower_bound(all(vp),vl[i].fs,lessP)-vp.begin();
    int t = lower_bound(all(vp),vl[i].sc,lessP)-vp.begin();
      */
    ve[i] = pii(s,t);
    edges[s].push_back(pdi(arg(vp[t]-vp[s]),i));
    edges[t].push_back(pdi(arg(vp[s]-vp[t]),i));
  }

  graph.resize(vp.sz);
  rep(i,vp.sz){
    sort(all(edges[i]));
    graph[i].clear();
    rep(j,edges[i].sz){
      int id = edges[i][j].sc;
      int v = (ve[id].fs == i)?ve[id].sc:ve[id].fs;
      graph[i].pb(pii(v,id));
    }
  }
}

inline vector<Poly> extract_poly(vector<L> set_l){
  vector<P> p;
  vector<pii> l;
  vector< vector<pii> > e;
  seg_arrange(set_l,p,l,e);

  /*
  int num = 0;
  rep(i,e.sz)num += e[i].sz;
  cout << num << endl;
  rep(i,e.sz){
    rep(j,e[i].sz){
      int id = e[i][j].sc;
      cout << p[l[id].fs].real() << " " << p[l[id].fs].imag() << " "
	   << p[l[id].sc].real() << " " << p[l[id].sc].imag() << endl;
    }
  }
  */

  vector<vi> g(l.sz,vi(2,-1));
  vector<Poly> PolySet;

  rep(i,l.sz)rep(j,2){
    int cur = i, dir = j;
    if(g[cur][dir]>=0)continue;

    //D area = 0;
    Poly poly;
    while(true){
      g[cur][dir] = 0;
      
      int node = dir?l[cur].fs:l[cur].sc;
      int prv = dir?l[cur].sc:l[cur].fs;
      poly.push_back(p[node]);
      //area += cross(p[prv],p[node]);

      int s = e[node].sz;
      int nxt = find(all(e[node]),pii(prv,cur))-e[node].begin();
      cur = e[node][(nxt+s-1)%s].sc;
      dir = (l[cur].fs==node)?0:1;

      if(g[cur][dir]>=0)break;
    }
    
    //cout << area(poly) << endl;
    //rep(i,poly.sz)cout << poly[i] << " ";cout << endl;
    if(area(poly)>EPS)PolySet.pb(poly);
  }
  return PolySet;
}


int main(){
  int n;
  cin >> n;

  vector<P> p(n);
  rep(i,n){
    int x,y;
    cin >> x >> y;
    p[i] = P(x,y);
  }

  vector<L> l(n-1);
  rep(i,n-1)l[i] = L(p[i],p[i+1]);

  vector<Poly> poly = extract_poly(l);

  /*
  vector<L> vl;
  rep(i,poly.sz){
    rep(j,poly[i].sz)vl.push_back(L(poly[i][j],poly[i][(j+1)%poly[i].sz]));
  }
  cout << vl.sz << endl;
  rep(i,vl.sz)cout << vl[i].fs.real() << " " << vl[i].fs.imag() << " "
		   << vl[i].sc.real() << " " << vl[i].sc.imag() << endl;
  */

  vector<D> a(poly.sz);
  rep(i,poly.sz)a[i] = area(poly[i]);
  sort(all(a));
  D res = 0;
  rep(i,a.sz)res += a[i];
  cout << fixed << setprecision(10) << res << endl;
}