#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <string>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <deque>
#include <algorithm>
#include <functional>
#include <iterator>
#include <limits>
#include <numeric>
#include <utility>
#include <cmath>
#include <cassert>
#include <cstdio>

using namespace std; using namespace placeholders;

typedef long long LL;
typedef unsigned long long ULL;
typedef vector< int > VI;
typedef vector< vector< int > > VVI;
typedef vector< string > VS;
typedef stringstream SS;
typedef pair< int, int > PII;
typedef vector< pair< int, int > > VPII;
#define VT( T ) vector< T >
#define VVT( T ) vector< vector< T > >
#define LIM( T ) numeric_limits< T >

template < typename T > inline istream& operator>>( istream &s, vector< T > &v ){ for ( T &t : v ) { s >> t; } return s; }
template < typename T > inline ostream& operator<<( ostream &s, const vector< T > &v ){ for ( int i = 0; i < int( v.size() ); ++i ){ s << ( " " + !i ) << v[i]; } return s; }
template < typename T > inline T fromString( const string &s ) { T res; istringstream iss( s ); iss >> res; return res; };
template < typename T > inline string toString( const T &a ) { ostringstream oss; oss << a; return oss.str(); };

#define REP2( i, n ) REP3( i, 0, n )
#define REP3( i, m, n ) for ( int i = ( int )( m ); i < ( int )( n ); ++i )
#define GET_REP( a, b, c, F, ... ) F
#define REP( ... ) GET_REP( __VA_ARGS__, REP3, REP2 )( __VA_ARGS__ )
#define FOR( e, c ) for ( auto &e : c )
#define ALL( c ) ( c ).begin(), ( c ).end()
#define AALL( a, t ) ( t* )a, ( t* )a + sizeof( a ) / sizeof( t )
#define DRANGE( c, p ) ( c ).begin(), ( c ).begin() + p, ( c ).end()

#define SZ( v ) ( (int)( v ).size() )
#define PB push_back
#define EM emplace
#define EB emplace_back
#define BI back_inserter

#define EXIST( c, e ) ( ( c ).find( e ) != ( c ).end() )

#define MP make_pair
#define fst first
#define snd second

#define DUMP( x ) cerr << #x << " = " << ( x ) << endl

#include <complex>
typedef complex< double > Point;
constexpr double EPS = 1e-8;
constexpr Point O( 0, 0 );

// 入力ストリームから実数二つをとって Point へ
istream& operator>> ( istream &s, Point &a )
{
	double r, i;
	s >> r >> i;
	a = Point( r, i );
	return s;
}

// 偏角
struct CompArg : public binary_function<Point,Point,bool>
{
	bool operator ()( const Point &a, const Point &b ) const
	{
		return arg( a ) < arg( b );
	}
};

// 内積（ドット積）
double dot( const Point &a, const Point &b )
{
	return a.real() * b.real() + a.imag() * b.imag();
}

// 外積（クロス積）
double cross( const Point &a, const Point &b )
{
	return a.real() * b.imag() - a.imag() * b.real();
}

class DualGraph
{
	typedef std::tuple< int, int, int, Point > Edge;
	// ( to, rev-edge, edge id, angle )

	const int N;
	int M;
	const std::vector< Point > ps_;
	std::vector< std::vector< Edge > > G;
	std::vector< std::vector< int > > edge_indices_, edge_poss_;
	std::vector< std::vector< bool > > used_;

	int outer_;
	std::vector< std::vector< Point > > areas_;

	std::vector< std::vector< int > > intersects_;

public:
	DualGraph( const std::vector< Point > &ps ) :
		N( ps.size() ), M( 0 ), ps_( ps ), G( N ), edge_indices_( N ), edge_poss_( N ), used_( N ), outer_( -1 )
	{
		return;
	}

	void connect( const int a, const int b )
	{
		G[a].emplace_back( b, G[b].size(), M, ps_[b] - ps_[a] );
		G[b].emplace_back( a, G[a].size() - 1, M, ps_[a] - ps_[b] );
		++M;

		return;
	}

	void solve()
	{
		sort_edges();

		for ( int v = 0; v < N; ++v )
		{
			for ( int i = 0; i < int( G[v].size() ); ++i )
			{
				if ( used_[v][i] )
				{
					continue;
				}

				dfs( v, i );
			}
		}

		return;
	}

private:
	void sort_edges()
	{
		CompArg comp;
		for ( int v = 0; v < N; ++v )
		{
			edge_indices_[v].resize( G[v].size() );
			std::iota( begin( edge_indices_[v] ), end( edge_indices_[v] ), 0 );

			std::sort( begin( edge_indices_[v] ), end( edge_indices_[v] ), 
					[&]( const int i, const int j ){ return comp( get< 3 >( G[v][i] ), get< 3 >( G[v][j] ) ); } );

			edge_poss_[v].resize( G[v].size() );
			for ( int i = 0; i < int( G[v].size() ); ++i )
			{
				edge_poss_[v][ edge_indices_[v][i] ] = i;
			}

			used_[v].resize( G[v].size() );
		}
		intersects_.resize( M );

		return;
	}

	void dfs( const int sv, const int se )
	{
		std::vector< Point > area;

		for ( int v = sv, e = se; area.empty() || v != sv; )
		{
			used_[v][e] = true;
			area.push_back( ps_[v] );
			intersects_[ get< 2 >( G[v][e] ) ].push_back( areas_.size() );

			const int r = get< 1 >( G[v][e] );
			v = get< 0 >( G[v][e] );
			e = edge_indices_[v][ ( edge_poss_[v][r] + G[v].size() - 1 ) % G[v].size() ];
		}

		{
			double theta = 0;
			for ( int i = 0; i < int( area.size() ); ++i )
			{
				const Point p1 = area[ ( i + 1 ) % area.size() ] - area[i];
				const Point p2 = area[ ( i + 2 ) % area.size() ] - area[i];
				theta += atan2( cross( p1, p2 ), dot( p1, p2 ) );
			}
			if ( theta < 0 )
			{
				outer_ = areas_.size();
			}
		}

		areas_.push_back( area );
		
		return;
	}

	// results
public:
	int area_number() const
	{
		return areas_.size();
	}

	std::vector< std::vector< Point > > areas() const
	{
		return areas_;
	}

	std::vector< std::pair< int, int > > edges() const
	{
		std::vector< std::pair< int, int > > res;
		for ( auto &row : intersects_ )
		{
			res.emplace_back( row[0], row[1] );
		}
		return res;
	}

	int outer() const
	{
		return outer_;
	}
};

constexpr int INF = LIM( int )::max() / 2;

int main()
{
	cin.tie( 0 );
	ios::sync_with_stdio( false );

	for ( int N, M; cin >> N >> M && ( N | M ); )
	{
		VT( Point ) ps( N );
		cin >> ps;

		VI s( M ), t( M );
		REP( i, M )
		{
			cin >> s[i] >> t[i];
			--s[i], --t[i];
		}

		DualGraph dualgraph( ps );
		REP( i, M )
		{
			dualgraph.connect( s[i], t[i] );
		}
		dualgraph.solve();

		const int V = dualgraph.area_number();
		VVI G( V );
		{
			VPII es = dualgraph.edges();
			FOR( e, es )
			{
				const int a = e.fst, b = e.snd;
				G[a].PB( b );
				G[b].PB( a );
			}
		}

		VI distances( V, INF );
		distances[ dualgraph.outer() ] = 0;

		queue< int > que;
		que.push( dualgraph.outer() );

		while ( !que.empty() )
		{
			const int u = que.front();
			que.pop();

			FOR( v, G[u] )
			{
				if ( distances[u] + 1 < distances[v] )
				{
					distances[v] = distances[u] + 1;
					que.push( v );
				}
			}
		}

		cout << *max_element( ALL( distances ) ) << endl;
	}

	return 0;
}

Measured memory_bytes: 1412