#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>

static const int MOD = 1000000007;
using ll = long long;
using u32 = unsigned;
using u64 = unsigned long long;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max()/32*15+208;
using real = double;
static constexpr real EPS = 1e-10;
struct Point {
    real x, y;
    Point& operator+=(const Point a) { x += a.x; y += a.y;  return *this; }
    Point& operator-=(const Point a) { x -= a.x; y -= a.y;  return *this; }
    Point& operator*=(const real k) { x *= k; y *= k;  return *this; }
    Point& operator/=(const real k) { x /= k; y /= k;  return *this; }
    Point operator+(const Point a) const {return Point(*this) += a; }
    Point operator-(const Point a) const {return Point(*this) -= a; }
    Point operator*(const real k) const {return Point(*this) *= k; }
    Point operator/(const real k) const {return Point(*this) /= k; }
    bool operator<(const Point &a) const { return (x != a.x ? x < a.x : y < a.y); }
    explicit Point(real a = 0, real b = 0) : x(a), y(b) {};
};

bool sorty(Point a, Point b){
    return (a.y != b.y ? a.y < b.y : a.x < b.x);
}

istream& operator>> (istream& s, Point& P){
    s >> P.x >> P.y;
    return s;
}

inline real dot(Point a, Point b){ return a.x*b.x + a.y*b.y; }
inline real cross(Point a, Point b){ return a.x*b.y - a.y*b.x; }
inline real abs(Point a){ return sqrt(dot(a, a)); }


real angle(Point A, Point B){
    return acos(dot(A, B)/abs(A)/abs(B));
}



static constexpr int COUNTER_CLOCKWISE = 1;
static constexpr int CLOCKWISE = -1;
static constexpr int ONLINE_BACK = 2;
static constexpr int ONLINE_FRONT = -2;
static constexpr int ON_SEGMENT = 0;

int ccw(Point a, Point b, Point c){
    b -= a; c -= a;
    if(cross(b, c) > EPS) return COUNTER_CLOCKWISE;
    if(cross(b, c) < -EPS) return CLOCKWISE;
    if(dot(b, c) < 0) return ONLINE_BACK;
    if(abs(b) < abs(c)) return ONLINE_FRONT;
    return ON_SEGMENT;
}
struct Segment {
    Point a, b;
    Segment(Point x, Point y) : a(x), b(y) {};
};

struct Line {
    Point a, b;
    Line(Point x, Point y) : a(x), b(y) {};
};

struct Circle{
    Point c; real r;
    Circle(Point c, real r): c(c), r(r) {};
};

using Polygon = vector<Point>;

bool intersect(Segment s, Segment t){
    return (ccw(s.a, s.b, t.a)*ccw(s.a, s.b, t.b) <= 0 &&
            ccw(t.a, t.b, s.a)*ccw(t.a, t.b, s.b) <= 0);
}

bool intersect(Segment s, Line t){
    int a = ccw(t.a, t.b, s.a), b = ccw(t.a, t.b, s.b);
    return (!(a&1) || !(b&1) || a != b);
}

Point polar(double r, double t){
    return Point(r*cos(t), r*sin(t));
}

double arg(Point p){
    return atan2(p.y, p.x);
}

real area(Polygon v){
    if(v.size() < 3) return 0.0;
    real ans = 0.0;
    for (int i = 0; i < v.size(); ++i) {
        ans += cross(v[i], v[(i+1)%v.size()]);
    }
    return ans/2;
}

class DualGraph {
    struct P {
        int to, nxt, id, id2, rev;
        P(int to = 0, int nxt = 0, int id = 0, int rev = 0) : to(to), nxt(nxt), id(id), rev(rev), id2(0) {};
        bool operator!=(P x){ return to != x.to || nxt != x.nxt || id != x.id || rev != x.rev; }
    };
public:
    int n, m;
    Polygon v;
    vector<vector<P>> G_;
    vector<vector<int>> G;
    vector<vector<Point>> A;
    DualGraph(Polygon v) : v(v), n(v.size()), G_(n), m(0) {}

    void add_point(Point P){ v.emplace_back(P); n++; G_.emplace_back(); }
    void add_edge(int a, int b){
        G_[a].emplace_back(b, 0, m, 0);
        G_[b].emplace_back(a, 0, m++, 0);
    }

    void build(){
        vector<int> l(m), r(m);
        for (int i = 0; i < n; ++i) {
            sort(G_[i].begin(), G_[i].end(), [&](P &a, P &b){ return arg(v[a.to]-v[i]) < arg(v[b.to]-v[i]); });
            for (int j = 0; j < G_[i].size(); ++j) {
                G_[i][j].nxt = (j + 1) % G_[i].size();
                if(i < G_[i][j].to) l[G_[i][j].id] = j;
                else r[G_[i][j].id] = j;
            }
        }
        for (int i = 0; i < n; ++i) {
            for (auto &&e : G_[i]) {
                e.rev = (i < e.to ? r[e.id] : l[e.id]);
            }
        }
        int cur = 1;
        A = move(vector<vector<Point>>());
        for (int i = 0; i < n; ++i) {
            for (auto &&x : G_[i]) {
                if(x.id2) continue;
                x.id2 = cur;
                A.emplace_back();
                A.back().emplace_back(v[i]);
                auto e = &x;
                while(e->to != i){
                    A.back().emplace_back(v[e->to]);
                    e = &G_[e->to][G_[e->to][e->rev].nxt];
                    e->id2 = cur;
                }
                cur++;
            }
        }
        for (int i = 0; i < n; ++i) {
            for (auto &&e : G_[i]) {
                (i < e.to ? l[e.id] : r[e.id]) = e.id2-1;
            }
        }
        G = move(vector<vector<int>>(A.size()));
        for (int i = 0; i < m; ++i) {
            G[l[i]].emplace_back(r[i]);
            G[r[i]].emplace_back(l[i]);
        }
    }
};


void solve(int n, int m){
    Polygon v(n);
    for (auto &&i : v) cin >> i;
    DualGraph G(v);
    for (int i = 0; i < m; ++i) {
        int a, b;
        scanf("%d %d", &a, &b);
        a--; b--;
        G.add_edge(a, b);
    }
    G.build();
    int out = 0;
    for (int i = 0; i < G.A.size(); ++i) {
        if(area(G.A[i]) > 0) out = i;
    }
    vector<int> dist(G.A.size(), INF<int>);
    queue<int> Q;
    dist[out] = 0; Q.emplace(out);
    while(!Q.empty()){
        int i = Q.front(); Q.pop();
        for (auto &&j : G.G[i]) {
            if(dist[j] == INF<int>){
                dist[j] = dist[i]+1;
                Q.emplace(j);
            }
        }
    }
    cout << *max_element(dist.begin(),dist.end()) << "\n";
}

int main() {
    int n, m;
    while(cin >> n >> m, n){
        solve(n, m);
    }
    return 0;
}


Measured memory_bytes: 3612