#include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define IINF (INT_MAX)
#define MAX_C 501
#define MAX_W 501
#define EPS (1e-10)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1 
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0
#define equals(a,b) (fabs((a)-(b)) < EPS)

using namespace std;

// Library - template - begin

class Point{
public:
  double x,y;

  Point(double x = -IINF,double y = -IINF): x(x),y(y){}

  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }

  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:y<p.y; }

  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }

};

struct Segment{
  Point p1,p2;
  Segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){}
  bool operator == (const Segment& p)const { return p.p1 == p1 && p.p2 == p2; }
};

typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;

ostream& operator << (ostream& os,const Point& a){ os << "(" << a.x << "," << a.y << ")"; }

ostream& operator << (ostream& os,const Segment& a){ os << "( " << a.p1 << " , " << a.p2 << " )"; }

double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }

double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }

double norm(Point a){ return a.x*a.x+a.y*a.y; }

double abs(Point a){ return sqrt(norm(a)); }

//rad は角度をラジアンで持たせること
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }

// 度をラジアンに変換
double toRad(double agl){ return agl*M_PI/180.0; }

// Library - template - end

struct Edge{
  int from,to,rev,unique_index;
  Edge(int from=IINF,int to=IINF):from(from),to(to){}
};

const bool DEBUG = false;
int C,W,sp;
Point ps[MAX_C];
vector<Edge> G[MAX_C];
vector<vector<int> > poly;
bool used[MAX_C][MAX_C];
int depth[MAX_C];
int index_list[MAX_C][MAX_C];
vector<int> bfs_G[MAX_C];

bool cmp(const Edge& a,const Edge& b){
  Vector vec_a = ps[a.to] - ps[a.from];
  Vector vec_b = ps[b.to] - ps[b.from];
  return atan2(vec_a.y,vec_a.x) <= atan2(vec_b.y,vec_b.x);
}

bool getPath(int start_node,int node,int edge,vector<int>& edge_list){
  if(DEBUG)cout << __LINE__ << ": " <<  node << "," << edge << endl;
  if( used[node][edge] ){
    if( !edge_list.empty() && node == start_node ) return true;
    return false;
  }
  used[node][edge] = true;

  int next_node = G[node][edge].to;
  int next_edge = (G[node][edge].rev+1)%((int)G[next_node].size());
  edge_list.push_back(G[node][edge].unique_index);
  if(getPath(start_node,next_node,next_edge,edge_list)){
    if(DEBUG)cout << __LINE__ << ": path::"  << node << "," << edge << endl;
    return true;
  } else {
    return used[node][edge] = false;
  }
}
  
int main(){
  while(cin>>C>>W,C|W){
    rep(i,MAX_C)depth[i] = IINF,bfs_G[i].clear(),G[i].clear();
    rep(i,MAX_C)rep(j,MAX_C)used[i][j] = false, index_list[i][j] = IINF;
    depth[0] = 0;
    poly.clear();
    sp = 0;
    rep(i,C) {
      cin >> ps[i].x >> ps[i].y;
      ps[i].x += 1000, ps[i].y += 1000;
      if( ps[i] < ps[sp] ) sp = i;
    }
    if(DEBUG)cout << sp << " " << ps[sp] << endl;
    rep(i,W) {
      int s,t;
      cin >> s >> t;
      s--,t--;
      G[s].push_back(Edge(s,t));
      G[t].push_back(Edge(t,s));
    }
    rep(i,C)sort(G[i].begin(),G[i].end(),cmp);
    int dex = 0;
    rep(i,C){
      rep(j,(int)G[i].size()){
	int to = G[i][j].to;
	rep(k,(int)G[to].size()){
	  if(G[to][k].to == i){
	    G[i][j].rev = k;
	    if( index_list[i][j] == IINF ){
	      assert(index_list[to][k] == IINF);
	      index_list[i][j] = index_list[to][k] = dex++;
	    }
	    G[i][j].unique_index = index_list[i][j];
	    break;
	  }
	}
      }
    }
    if(DEBUG){
      cout << __LINE__ << ":" << endl;
      cout << "sp = " << sp << endl;
      rep(i,C){
	cout << "i = " << i << endl;
	rep(j,G[i].size()){
	  cout << "from = " << G[i][j].from << " to = " << G[i][j].to << " rev = " << G[i][j].rev << " unique = " << G[i][j].unique_index << endl;
	}
      }
      cout << endl << endl;
    }
      rep(i,(int)G[sp].size()){
	if( used[sp][i] ) continue;
	vector<int> tmp;
	if( getPath(sp,sp,i,tmp) ) {
	  poly.push_back(tmp);
	  if(DEBUG)cout << "[" << sp << "][" << i << "] : getPath!! : " << endl;
	}
      }

    rep(i,C){
      if( i == sp ) continue;
      rep(j,G[i].size()){
	if( used[i][j] ) continue;
	vector<int> tmp;
	if( getPath(i,i,j,tmp) ){
	  poly.push_back(tmp);
	}
      }
    }

    rep(i,poly.size()){
      REP(j,i+1,poly.size()){
	bool connect = false;
	rep(k,poly[i].size()){
	  rep(l,poly[j].size()){
	    if(poly[i][k] == poly[j][l]){
	      connect = true;
	      goto Skip;
	    }
	  }
	}
      Skip:;
	if(connect){
	  bfs_G[i].push_back(j);
	  bfs_G[j].push_back(i);
	}
      }
    }

    if(DEBUG){
      cout << __LINE__ << ":" << endl;
      cout << "poly.size() = " << poly.size() << endl;
      rep(i,(int)poly.size()){
	cout << "poly[" << i << "]" << endl;
	rep(j,poly[i].size()){
	  cout << poly[i][j] << " ";
	}
	cout << endl;
      }

      cout << "bfs_G = " << endl;
      rep(i,poly.size()){
	cout << "[" << i << "]" << endl;
	rep(j,bfs_G[i].size()){
	  cout << bfs_G[i][j] << " ";
	}
	cout << endl;
      }

      cout << "depth[" << 0 << "] = " << depth[0] << endl;
    }
    int answer = 0;
    deque<int> deq;
    deq.push_back(0);
    while(!deq.empty()){
      int cur = deq.front(); deq.pop_front();
      rep(i,bfs_G[cur].size()){
	int next = bfs_G[cur][i];
	if( depth[next] == IINF ){
	  depth[next] = depth[cur] + 1;
	  answer = max(answer,depth[next]);
	  deq.push_back(next);
	}
      }
    }
    cout << answer << endl;
  }
  return 0;
}

Measured memory_bytes: 2592