#include<cstdio>
#include<complex>
#include<vector>
#include<cmath>
#include<utility>
#include<algorithm>

using namespace std;

typedef complex<double> Point;
typedef complex<double> Vector;
typedef pair<Point,Point> Line;
typedef pair<Point,Point> Segment;
typedef vector<Point> Polygon;

vector<Point> points;
vector<bool> valid;
vector<Point> tmp;

const double eps=1e-9;

template<class T> bool eq(T a,T b){
	return abs(a-b)<eps;
}

double crP(Vector a,Vector b){
	return (conj(a)*b).imag();
}

bool onSeg(Segment s,Point p){
	Point a=s.first,b=s.second;
	return eq(abs(a-b),abs(a-p)+abs(b-p));
}

Point iLL(Line l1,Line l2){
	Point p1=l1.first,p2=l1.second;
	Point q1=l2.first,q2=l2.second;
	if(eq(crP(p2-p1,q2-q1),0.0)){
		Point p=Point(NAN,NAN);
		return p;
	}
	double den=crP(p2-p1,q2-q1);
	double num=crP(q1-p1,q2-p1);
	return p1+(p2-p1)*(num/den);
}

Point iSS(Segment s1,Segment s2){
	Point pt=iLL(s1,s2);
	if(isnan(pt.real())) return pt;
	if(onSeg(s1,pt)&&onSeg(s2,pt)) return pt;
	return Point(NAN,NAN);
}

vector<Point> polyline;
vector<int> vs[110];
int N;
int V;

Point center;
bool cmp_distance(const int &i1,const int &i2){
	return abs(points[i1]-center)<abs(points[i2]-center);
}
bool cmp_angle(const int &i1,const int &i2){
	Point p1=points[i1]-center,p2=points[i2]-center;
	double x1=p1.real(),y1=p1.imag();
	double x2=p2.real(),y2=p2.imag();
	return atan2(y1,x1)+eps<atan2(y2,x2);
}

vector<int> G[100*100+100];
vector<bool> used[100*100+100];

vector<Polygon> polygons;

void stroke(Polygon &poly,int prev,int cur,int st1,int st2);

void getPolygons(){
	for(int i=0;i<V;i++){
		center=points[i];
		sort(G[i].begin(),G[i].end(),cmp_angle);
	}
	center=points[2];
	int target=4;
	for(int i=0;i<V;i++){
		for(int j=0;j<G[i].size();j++){
			if(used[i][j]) continue;
			Polygon poly;
			stroke(poly,i,G[i][j],i,G[i][j]);
			polygons.push_back(poly);
		}
	}
}

int dep=0;

void stroke(Polygon &poly,int prev,int cur,int st1,int st2){
	poly.push_back(points[cur]);
	center=points[cur];
	int id=distance(G[cur].begin(),lower_bound(G[cur].begin(),G[cur].end(),prev,cmp_angle));
	int nxtId=(id+1)%(G[cur].size());
	int nxt=G[cur][nxtId];
	if(st1==cur&&st2==nxt) return;
	used[cur][nxtId]=true;
	stroke(poly,cur,nxt,st1,st2);
}

double getArea(Polygon poly){
	double res=0;
	for(int i=0;i<poly.size();i++){
		Point p1=poly[i];
		Point p2=poly[(i+1)%poly.size()];
		double tmp=crP(p1,p2);
		res+=tmp;
	}
	res/=2;
	return abs(res);
}

int main(){
	scanf("%d",&N);
	for(int i=0;i<N;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		polyline.push_back(Point(x,y));
		points.push_back(Point(x,y));
	}
	for(int i=0;i<N-1;i++) for(int j=i+1;j<N-1;j++){
		if(eq(crP(polyline[i+1]-polyline[i],polyline[j+1]-polyline[j]),0.0)){
			continue;
		}
		Segment seg1=Segment(polyline[i],polyline[i+1]);
		Segment seg2=Segment(polyline[j],polyline[j+1]);
		Point pt=iSS(seg1,seg2);
		if(isnan(pt.real())){
			continue;
		}
		points.push_back(pt);
	}
	for(int i=0;i<points.size();i++){
		bool flg=true;
		for(int j=0;j<i;j++){
			if(eq(points[i],points[j])){
				flg=false;
			}
		}
		valid.push_back(flg);
	}
	for(int i=0;i<points.size();i++){
		if(valid[i]) tmp.push_back(points[i]);
	}
	points=tmp;
	V=points.size();
	for(int i=0;i<N-1;i++){
		Segment seg=Segment(polyline[i],polyline[i+1]);
		for(int j=0;j<points.size();j++){
			if(onSeg(seg,points[j])){
				vs[i].push_back(j);
			}
		}
	}
	for(int i=0;i<N-1;i++){
		center=polyline[i];
		sort(vs[i].begin(),vs[i].end(),cmp_distance);
		for(int j=0;j+1<vs[i].size();j++){
			//connect vs[i][j]-vs[i][j+1]
			int u=vs[i][j],v=vs[i][j+1];
			G[u].push_back(v);
			G[v].push_back(u);
		}
	}
	for(int i=0;i<V;i++){
		sort(G[i].begin(),G[i].end());
		G[i].erase(unique(G[i].begin(),G[i].end()),G[i].end());
		for(int j=0;j<G[i].size();j++) used[i].push_back(false);
	}
	getPolygons();
	double ans=0;
	for(int i=0;i<polygons.size();i++){
		double cur=getArea(polygons[i]);
		ans+=cur;
	}
	printf("%.9f\n",ans/2);
	return 0;
}

Measured memory_bytes: 2328