#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <set>
#include <functional>
#include <ctime>
#include <numeric>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define fst first
#define snd second
#define all(c) ((c).begin()), ((c).end())

const double EPS = 1e-8;
int sign(double x) {
  if (x < -EPS) return -1;
  if (x > +EPS) return +1;
  return 0;
}
struct point {
  typedef double T;
  T x, y; 
  point &operator+=(point p) { x += p.x; y += p.y; return *this; }
  point &operator-=(point p) { x -= p.x; y -= p.y; return *this; }
  point &operator*=(T a)     { x *= a;   y *= a;   return *this; }
  point &operator/=(T a)     { return *this *= (1.0/a); }
  point operator-() const    { return {-x, -y}; }
  bool operator<(point p) const { 
    int s = sign(x - p.x);
    return s ? s < 0 : sign(y - p.y) < 0;
  }
};
bool operator==(point p, point q) { return !(p < q) && !(q < p); }
point operator+(point p, point q) { return p += q; }
point operator-(point p, point q) { return p -= q; }
point operator*(point::T a, point p) { return p *= a; }
point operator*(point p, point::T a) { return p *= a; }
point operator/(point p, point::T a) { return p /= a; }
point::T dot(point p, point q) { return p.x*q.x+p.y*q.y; }
point::T cross(point p, point q) { return p.x*q.y-p.y*q.x; } // left turn > 0
point::T norm2(point p) { return dot(p,p); }
point orth(point p) { return {-p.y, p.x}; }
point::T norm(point p) { return sqrt(dot(p,p)); }
point::T arg(point p) { return atan2(p.y, p.x); }

struct segment { point p, q; };
vector<point> intersect(segment s, segment t) {
  auto a = cross(s.q - s.p, t.q - t.p);
  auto b = cross(t.p - s.p, t.q - t.p); 
  auto c = cross(s.q - s.p, s.p - t.p);
  if (a < 0) { a = -a; b = -b; c = -c; }
  if (sign(b) < 0 || sign(a-b) < 0 ||
      sign(c) < 0 || sign(a-c) < 0) return {};      // disjoint
  if (sign(a) != 0) return {s.p + b/a*(s.q - s.p)}; // properly crossing
  vector<point> ps;                                 // same line
  auto insert_if_possible = [&](point p) {
    for (auto q: ps) if (sign(dot(p-q, p-q)) == 0) return;
    ps.push_back(p);
  };
  if (sign(dot(s.p-t.p, s.q-t.p)) <= 0) insert_if_possible(t.p);
  if (sign(dot(s.p-t.q, s.q-t.q)) <= 0) insert_if_possible(t.q);
  if (sign(dot(t.p-s.p, t.q-s.p)) <= 0) insert_if_possible(s.p);
  if (sign(dot(t.p-s.q, t.q-s.q)) <= 0) insert_if_possible(s.q);
  return ps;
}
struct arrangement {
  struct edge {
    int src, dst;
    point::T weight;
    size_t id, rev;
  };
  int n;
  vector<point> ps; // ps[id[p]] = p, id[ps[k]] = k
  map<point,int> id; 
  vector<vector<edge>> adj;
  arrangement(vector<segment> ss) : n(0) {
    vector<vector<pair<point::T, int>>> group(ss.size());
    auto append = [&](int i, point p) {
      if (!id.count(p)) { id[p] = n++; ps.push_back(p); }
      group[i].push_back({norm(ss[i].p - p), id[p]});
    };
    for (int i = 0; i < ss.size(); ++i) {
      append(i, ss[i].p);
      append(i, ss[i].q);
      for (int j = 0; j < i; ++j) {
        auto qs = intersect(ss[i], ss[j]);
        if (qs.size() == 1) {
          append(i, qs[0]);
          append(j, qs[0]);
        }
      }
    }
    adj.resize(n);
    for (auto &vs: group) {
      sort(all(vs));
      for (int i = 0; i+1 < vs.size(); ++i) {
        auto u = vs[i].snd, v = vs[i+1].snd;
        if (u == v) continue;
        auto len = vs[i+1].fst - vs[i].fst;
        adj[u].push_back({u, v, len});
        adj[v].push_back({v, u, len});
      }
    }
    // remove duplicates and orient edges
    vector<unordered_map<int, int>> idx(n);
    for (int u = 0; u < n; ++u) {
      auto eq = [&](edge e, edge f) { return e.dst == f.dst; };
      auto lt = [&](edge e, edge f) { return e.dst <  f.dst; };
      sort(all(adj[u]), lt);
      adj[u].erase(unique(all(adj[u]), eq), adj[u].end());
      sort(all(adj[u]), [&](edge e, edge f) {
        return arg(ps[e.dst] - ps[e.src]) > arg(ps[f.dst] - ps[f.src]);
      });
      for (int i = 0; i < adj[u].size(); ++i) {
        adj[u][i].id = i;
        int v = adj[u][i].dst;
        idx[u][v] = i;
        if (idx[v].count(u)) {
          int j = idx[v][u];
          adj[u][i].rev = j;
          adj[v][j].rev = i;
        }
      }
    }
  }
  template <class F>
  void traverse(edge e, F func) {
    edge s = e;
    do {
      func(e);
      int j = adj[e.dst][e.rev].id + 1;
      if (j >= adj[e.dst].size()) j = 0;
      e = adj[e.dst][j];
    } while (e.src != s.src || e.dst != s.dst);
  }
  void traverse_all_faces() {
    vector<unordered_set<int>> visited(n);
    point::T ans = 0;
    for (int u = 0; u < n; ++u) {
      for (edge e: adj[u]) {
        if (!visited[e.src].count(e.dst)) {
          point::T area = 0;
          traverse(e, [&](edge e) { 
            visited[e.src].insert(e.dst);
            area += cross(ps[e.src], ps[e.dst]); 
          });
          if (area > 0) ans += area;
        }
      }
    }
    printf("%.12f\n", ans/2);
  }
};
int main() {
  int n; scanf("%d", &n);
  vector<point> ps(n);
  for (int i = 0; i < n; ++i) 
    scanf("%lf %lf", &ps[i].x, &ps[i].y);
  vector<segment> ss;
  for (int i = 0; i+1 < n; ++i) 
    ss.push_back({ps[i], ps[i+1]});
  arrangement arr(ss);
  arr.traverse_all_faces();
}

Measured memory_bytes: 4704