“Hey, what’s up? It’s already 30 minutes past eleven!”

“I’m so sorry, but actually I got lost. I have no idea where I am now at all and I got tired wandering around. Please help!”

- Today you came to the metropolis to play with your friend. But she didn’t show up at the appointed time. What happened to her? After some uncomfortable minutes, finally you managed to get her on line, and have been just notified that she’s been lost in the city.

You immediately told her not to move, and asked her what are around her to figure out where she is. She told the names of some famous land marks, in the order where she caught in her sight while she made a full turn counterclockwise without moving around.

Fortunately, today you have a map of the city. You located all the land marks she answered on the map, but want to know in which district of the city she’s wandering.

Write a program to calculate the area where she can be found, as soon as you can!



Input

Each input case is given in the format below:


N
x1 y1
...
xN yN
l1 . . . lN


An integer N in the first line specifies the number of land marks she named (N ≤ 10). The following N lines specify the x- and y-coordinates of the land marks in the city. Here you modeled the city as an unbounded two- dimensional plane. All coordinate values are integers between 0 and 100, inclusive. The last line of a test case specifies the order in which she found these land marks in a counterclockwise turn.

A single line containing zero indicates the end of input. This is not a part of the input and should not be processed.

Output

Your program should output one line for each test case.

The line should contain the case number followed by a single number which represents the area where she can be found. The value should be printed with the fifth digit after the decimal point, and should not contain an absolute error greater than 10-5 .

If there is no possible area found under the given condition, output “No area” in a line, instead of a number. If you cannot bound the area, output “Infinity”.

Example

Input

8
1 0
2 0
3 1
3 2
2 3
1 3
0 2
0 1
1 2 3 4 5 6 7 8
8
1 0
2 0
3 1
3 2
2 3
1 3
0 2
0 1
4 3 2 1 8 7 6 5
4
0 0
1 0
1 1
0 1
1 2 3 4
0


Output

Case 1: 10.00000
Case 2: No area
Case 3: Infinity
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <ctime>
#include <queue>
#include <stack>
#include <algorithm>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <deque>
#include <complex>
#include <string>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <valarray>
#include <unordered_map>
#include <iterator>
#include <functional>
#include <cassert>
using namespace std;
typedef long long int ll;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define REPS(i,x) for(int i=1;i<=(int)(x);i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RREPS(i,x) for(int i=((int)(x));i>0;i--)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
#define ALL(container) (container).begin(), (container).end()
#define RALL(container) (container).rbegin(), (container).rend()
#define SZ(container) ((int)container.size())
#define mp(a,b) make_pair(a, b)
#define pb push_back
#define eb emplace_back
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"["; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"]"; return os;
}
template<class T> ostream& operator<<(ostream &os, const set<T> &t) {
os<<"{"; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"}"; return os;
}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class S, class T> pair<S,T> operator+(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first+t.first, s.second+t.second);}
template<class S, class T> pair<S,T> operator-(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first-t.first, s.second-t.second);}
struct UnionFind {
  vector<int> d;
  UnionFind(int n=0) : d(n, -1){}
  bool unite(int x, int y) {
    if ((x = root(x)) != (y = root(y))){
      if (d[y] < d[x]) swap(x, y);
      d[x] += d[y]; d[y] = x;
    }
    return x != y;
  }
  bool find(int x, int y){return root(x) == root(y);}
  int root(int x){return d[x] < 0 ? x : d[x] = root(d[x]);}
  int size(int x=-1) {return x<0 ? d.size() : -d[root(x)];}
};

namespace geom{
#define X real()
#define Y imag()
#define at(i) ((*this)[i])
#define SELF (*this)
	enum {TRUE = 1, FALSE = 0, BORDER = -1};
	typedef int BOOL;
	typedef long double R;
	const R INF = 1e8;
	R EPS = 1e-6;
	const R PI = 3.1415926535897932384626;
	inline int sig(const R &x) { return (abs(x) < EPS ? 0 : x > 0 ? 1 : -1); }
	inline BOOL less(const R &x, const R &y) {return sig(x-y) ? x < y : BORDER;}
	typedef complex<R> P;
	inline R norm(const P &p){return p.X*p.X+p.Y*p.Y;}
	inline R inp(const P& a, const P& b){return (conj(a)*b).X;}
	inline R outp(const P& a, const P& b){return (conj(a)*b).Y;}
	inline P unit(const P& p){return p/abs(p);}
	inline P proj(const P &s, const P &t){return t*inp(s, t)/norm(t);}
	inline int ccw(const P &s, const P &t, const P &p, int adv=0){
		int res = sig(outp(t-s, p-s));
		if(res || !adv) return res;
		if(sig(inp(t-s, p-s)) < 0) return -2;	// p-s-t
		if(sig(inp(s-t, p-t)) < 0) return 2;	// s-t-p
		return 0;								// s-p-t
	}
	
	
	struct L : public vector<P>{	// line
		L(const P &p1, const P &p2){this->push_back(p1);this->push_back(p2);}
		L(){}
		P dir()const {return at(1) - at(0);}
		BOOL online(const P &p)const {return !sig(outp(p-at(0), dir()));}
	};
	struct S : public L{	// segment
		S(const P &p1, const P &p2):L(p1, p2){}
		S(){}
		BOOL online(const P &p)const {
			if(!sig(norm(p - at(0))) || !sig(norm(p - at(1)))) return BORDER;
			// ??§?¨????????????¨EPS???????????§??????????????????????????¨???
			return !sig(outp(p-at(0), dir())) && inp(p-at(0), dir()) > EPS && inp(p-at(1), -dir()) > -EPS;
			//return !sig(abs(at(0)-p) + abs(at(1) - p) - abs(at(0) - at(1)));
		}
	};
	struct C : public P{
		C(){}
		C(const P& p, const R r):P(p), r(r){}
		R r;
		BOOL inside(const P& p)const { return less(norm(p-SELF), r*r);}
	};
	P crosspoint(const L &l, const L &m);
	struct G : public vector<P>{
		G(size_type size=0):vector(size){}
		S edge(int i)const {return S(at(i), at(i+1 == size() ? 0 : i+1));}
		BOOL contains(const P &p)const {
			R sum = .0;
			REP(i, size()){
				if(S(at(i), at((i+1)%size())).online(p)) return BORDER;	// online
				sum += arg((at(i) - p) / (at((i+1)%size()) - p));
			}
			return !!sig(sum);
		}
		R area()const {
			R sum = 0;
			REP(i, size()) sum += outp(at(i), at((i+1)%size()));
			return abs(sum / 2.);
		}
		P gp()const {
			P r(.0, .0);
			REP(i, size()){
				const S &s = edge(i);
				r += (s[0]+s[1])*outp(s[0], s[1]);
			}
			return r / (6*area());
		}
		G convex_hull(bool online = false) {
			if(size() < 2) return *this;
			sort(ALL(*this));
			G r;
			r.resize((int)size()*2);
			int k=0;
			for(int i=0;i<size();r[k++]=at(i++))
				while(k>1 && ccw(r[k-2], r[k-1], at(i)) < 1-online) k--;
			int t = k;
			for(int i=(int)size()-1;i>=0;r[k++]=at(i--))
				while(k>t && ccw(r[k-2], r[k-1], at(i)) < 1-online) k--;
			r.resize(k-1);
			return r;
		}
	};

	inline P proj(const P &s, const L &t){return t[0] + proj(s-t[0], t[1]-t[0]);}
	inline P reflect(const P &s, const L &t){return (R)2.*proj(s, t) - s;}
	inline S reflect(const S &s, const L &t){return S(reflect(s[0], t), reflect(s[1], t));}
	BOOL intersect(const S &s, const S &t){
		const int p = ccw(t[0], t[1], s[0], 1) * ccw(t[0], t[1], s[1], 1);
		const int q = ccw(s[0], s[1], t[0], 1) * ccw(s[0], s[1], t[1], 1);
		return (p>0||q>0) ? FALSE : (!p||!q) ? BORDER : TRUE;
	}
	BOOL intersect(const S &s, const L &l){
		if(l.online(s[0]) || l.online(s[1])) return BORDER;
		return (sig(outp(l.dir(), s[0]-l[0])) * sig(outp(l.dir(), s[1]-l[0])) <= 0);
	}
	R dist2(const L &l, const P &p){return norm(outp(l.dir(), p - l[0])) / norm(l.dir());}
	R dist2(const S &s, const P &p){
		if(inp(p-s[0],  s.dir()) < EPS) return norm(p - s[0]);
		if(inp(p-s[1], -s.dir()) < EPS) return norm(p - s[1]);
		return dist2((const L &)s, p);
	}
	R dist2(const S &s, const L &l){
		return intersect(s, l) ? .0 : min(dist2(l, s[0]), dist2(l, s[1]));
	}
	R dist2(const S &s, const S &t){
		return intersect(s, t) ? .0 : min(min(dist2(s, t[0]), dist2(t, s[0])), 
									   	  min(dist2(s, t[1]), dist2(t, s[1])));
	}
	template <class T> R dist2(const G &g, const T& t){ // todo: ?????¨????????¨?????????????????´???
		R res = INF;
		REP(i, g.size()) res = min(res, dist2(g.edge(i), t));
		return res;
	}
	template<class S, class T> R dist(const S& s, const T& t){return sqrt(dist2(s, t));}
	inline BOOL intersect(const C &a, const C &b){
		return less((a.r-b.r)*(a.r-b.r), norm(a-b)) + less(norm(a-b), (a.r+b.r)*(a.r+b.r)) - 1;
	}
	inline P crosspoint(const L &l, const L &m){
		R A = outp(l.dir(), m.dir()), B = outp(l.dir(), l[1] - m[0]);
		if(!sig(abs(A)) && !sig(abs(B))) return m[0]; // same line
		return m[0] + B / A * (m[1] - m[0]);
	}
	template<class T> vector<T> merge(vector<T> s) {
		REP(i, s.size()) if (s[i][1] < s[i][0]) swap(s[i][0], s[i][1]);
		sort(ALL(s));
		REP(i, s.size())REP(j, i)if(intersect(s[i], s[j]) && !sig(outp(s[i].dir(), s[j].dir()))) {
			s[j][1] = max(s[i][1], s[j][1]);
			s.erase(s.begin() + i--);
			break;
		}
		return s;
	}
	struct Arrangement{
		struct AEdge{
			int u, v, t;
			R cost;
			AEdge(int u=0, int v=0, int t=0, R cost=0)
				:u(u), v(v), t(t), cost(cost){}
		};
		typedef vector<vector<AEdge>> AGraph;
		vector<P> p;
		AGraph g;
		Arrangement(){}
		Arrangement(vector<S> seg){
			seg = merge(seg);
			int m = seg.size();
			REP(i, m){
				REP(j, i) if(sig(outp(seg[i].dir(), seg[j].dir())) && intersect(seg[i], seg[j]))
					p.push_back(crosspoint(seg[i], seg[j]));
			}
			sort(ALL(p)); UNIQUE(p);
			int n=p.size();
			g.resize(n);
			REP(i, m){
				S &s = seg[i];
				vector<pair<R, int>> ps;
				REP(j, n) if(s.online(p[j])) ps.emplace_back(norm(p[j] - s[0]), j);
				sort(ALL(ps));
				REP(j, (int)ps.size()-1){
					const int u=ps[j].second;
					const int v=ps[j+1].second;
					g[u].emplace_back(u, v, 0, 0);
					g[v].emplace_back(v, u, 0, 0);
				}
			}
		}
		
		int getIdx(P q){
			auto it = lower_bound(ALL(p), q);
			if(it == p.end() || *it != q) return -1;
			return it - p.begin();
		}
	};
	struct DualGraph{
		struct DEdge{
			int u, v, f, l;
			R a;
			DEdge(int u, int v, R a):u(u),v(v),f(0),l(0){
				while(PI < a) a -= 2*PI;
				while(a < -PI) a += 2*PI;
				this->a = a;
			}
			bool operator==(const DEdge &opp) const{
				return v==opp.v;
			}
			bool operator<(const DEdge &opp) const{
				return a>opp.a;
			}
			bool operator<(const R &opp) const{
				return a>opp;
			}
		};
		
		int n;
		vector<P> p;
		vector<vector<DEdge>> g;
		UnionFind uf;
		DualGraph(const vector<P> &p):p(p),g(p.size()),n(p.size()),uf(p.size()){}
		void add_edge(const int s, const int t){
			R a = arg(p[t]-p[s]);
			g[s].emplace_back(s, t, a);
			g[t].emplace_back(t, s, a > 0 ? a-PI : a+PI);
			uf.unite(s, t);
		}
		vector<G> poly;
		
		void add_polygon(int s, int t, R a){
			auto e = lower_bound(ALL(g[s]), a-1e-8);
			if(e == g[s].end()) e = g[s].begin();
			if(e->f) return;
			e->f = 1;
			e->l = t;
			poly[t].push_back(p[s]);
			add_polygon(e->v, t, e->a > 0 ? e->a-PI : e->a+PI);
		}
		
		void toSpanningTree(){
			vector<pair<R, pii>> e;
			REP(i, n)REP(j, i)if(!uf.find(i, j))
				e.emplace_back(abs(p[i]-p[j]), pii(i, j));
			sort(ALL(e));
			REP(ii, e.size()){
				const int i = e[ii].second.first;
				const int j = e[ii].second.second;
				if(uf.find(i, j)) continue;
				const S s(p[i], p[j]);
				if([&](){
					REP(k, n)if(i!=k&&j!=k){
						FOR(it, g[k])
						if(intersect(s, S(p[k], p[it->v])) == TRUE) return 0;
					}
					return 1;
				}()) add_edge(i, j);
			}
		}
		
		void dual(){
//			toSpanningTree();
			
			REP(i, n){
				sort(ALL(g[i]));
				UNIQUE(g[i]);
			}
			int s = min_element(ALL(p)) - p.begin();
			poly.emplace_back();
			add_polygon(s, poly.size()-1, -PI*(R).5);
			REP(i, n)REP(j, g[i].size())if(!g[i][j].f){
				poly.emplace_back();
				add_polygon(i, poly.size()-1, g[i][j].a+2.*EPS);
			}
		}
	};

#undef SELF
#undef at
}

using namespace geom;

namespace std{
	bool operator<(const P &a, const P &b){return sig(a.X-b.X) ? a.X < b.X : a.Y+EPS < b.Y;}
	bool operator==(const P &a, const P &b){return norm(a-b) < EPS;}
	istream& operator>>(istream &is, P &p){R x,y;is>>x>>y;p=P(x, y);return is;}

}
int T, n, m;
R W = 12000;

int check(const P &p, const vector<P> &tar){
	vector<R> args;
	REPS(i, (int)tar.size()-1){
		R a = arg((tar[i] - p) / (tar[0] - p));
		if(a < -EPS) a += 2*PI;
		args.pb(a);
	}
	REPS(i, (int)args.size()-1) if(args[i-1] > args[i]) return 0;
	return 1;
}

int main(int argc, char *argv[]){
	ios::sync_with_stdio(false);
	for(int t=1;cin >> n, n;t++){
		vector<P> g(n);
		REP(i, n) cin >> g[i];
		vi idx(n);
		REP(i, n) cin >> idx[i];
		vector<P> g2(n);
		REP(i, n) g2[i] = g[idx[i]-1];
		g = g2;
		vector<S> s;
		vector<L> ls;
		REP(i, n)REP(j, i) ls.eb(g[i], g[j]);
		W = 1000;
		REP(i, ls.size()){
			int f = 0;
			REP(j, ls.size())if(i!=j && outp(ls[i].dir(), ls[j].dir())){
				P p = crosspoint(ls[i], ls[j]);
				W = max({W, abs(p.X), abs(p.Y)}) + 1;
			}
		}
		REP(i, n)REP(j, i){
			P dir = unit(g[j] - g[i]);
			s.eb(g[i] - dir*W*(R)5, g[i] + dir*W*(R)5);
		}
		s.eb(P(-W, -W), P(W, -W));
		s.eb(P(-W, -W), P(-W, W));
		s.eb(P(W, W), P(W, -W));
		s.eb(P(W, W), P(-W, W));
		Arrangement ar(s);
		DualGraph dg(ar.p);
		for(auto &it : ar.g) for(auto &e : it)if(e.u < e.v){
			dg.add_edge(e.u, e.v);
		}
		dg.dual();
		R ans = 0;
		int inff = 0;

		REPS(i, dg.poly.size()-1){
			R area = dg.poly[i].area();
			if(area < EPS) continue;
			if(!check(dg.poly[i].gp(), g)) continue;
			ans += area;
			R minn = 0, maxx = 0;
			for(auto &p : dg.poly[i]){
				chmin(minn, min(p.X, p.Y));
				chmax(maxx, max(p.X, p.Y));
			}
			if(maxx > W-EPS || minn < -W+EPS){
				inff = 1;
				break;
			}
		}
		printf("Case %d: ", t);
		if(ans < EPS) printf("No area\n");
		else if(inff) printf("Infinity\n");
		else printf("%.20f\n", (double)ans);
	}
	return 0;
}