// #define DEBUG
//#define USEPB_DS
#define USETR1
#define CPPELEVEN
#define GPP

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <sstream>
#include <tuple>

using namespace std;

#ifndef CPPELEVEN
#ifdef USETR1
#include <tr1/unordered_map>
#include <tr1/unordered_set>
using namespace tr1;
#endif
#else
#include <unordered_map>
#include <unordered_set>
#endif

#ifdef USEPB_DS
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
// binomial_heap_tag, rc_binomial_heap_tag, thin_heap_tag, binary_heap_tag
typedef __gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> pq_type;
// splay_tree_tag, ov_tree_tag
typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> tree_type;
#endif

#define mpr make_pair
typedef unsigned int ui;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const long double eps = 1e-10;
const int step[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, 1}, {1, 1}, {1, -1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}

#ifndef CPPELEVEN
template <class T> inline T max1(T a, T b) { return b < a ? a : b; }
template <class T> inline T max1(T a, T b, T c) { return max1(max1(a, b), c); }
template <class T> inline T max1(T a, T b, T c, T d) { return max1(max1(a, b, c), d); }
template <class T> inline T max1(T a, T b, T c, T d, T e) { return max1(max1(a, b, c, d), e); }
template <class T> inline T min1(T a, T b) { return a < b ? a : b; }
template <class T> inline T min1(T a, T b, T c) { return min1(min1(a, b), c); }
template <class T> inline T min1(T a, T b, T c, T d) { return min1(min1(a, b, c), d); }
template <class T> inline T min1(T a, T b, T c, T d, T e) { return min1(min1(a, b, c, d), e); }
#else
template <typename t, typename t1>
t min1(t a, t1 b) { return a < b ? a : b; }
template <typename t, typename... arg>
t min1(t a, arg... arr) { return min1(a, min1(arr...)); }
template <typename t, typename t1>
t max1(t a, t1 b) { return a > b ? a : b; }
template <typename t, typename... arg>
t max1(t a, arg... arr) { return max1(a, max1(arr...)); }
#endif

inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / max(abs1(a), abs1(b)) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t> inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}

// f_lb == 1代表返回相同的一串的左边界，f_small == 1代表返回如果没有寻找的值返回小的数
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	if(na == 0) return 0;
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}

template <class T> inline T lowb(T num) {return num & (-num); }
#ifdef GPP
inline int bitnum(ui nValue) { return __builtin_popcount(nValue); }
inline int bitnum(int nValue) { return __builtin_popcount(nValue); }
inline int bitnum(ull nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitnum(ll nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitmaxl(ui a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(int a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(ull a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
inline int bitmaxl(ll a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
#else
#endif

long long pow(long long n, long long m, long long mod = 0){
	if(m < 0) return 0;
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

#define  MOD 1000000007
template <class t1, class t2>
inline void add(t1 &a, t2 b, int mod = -1) {
	if(mod == -1) mod = MOD;
	a += b;
	while(a >= mod) a -= mod;
	while(a < 0) a += mod;
}
template <class t>
void output1(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		cerr << arr[i] << ' ';
	cerr << endl;
}
template <class t>
void output2(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		output1(arr[i]);
}

//....................密..........封..........线..........下..........禁..........止..........hack...............................................

const int maxn = 505000;
int dp[maxn], nxtdp[maxn];
int n, m;
struct link {
	int nxt, bef;
	bool exist;
} e[maxn * 2];
int head[maxn];
struct edge {
	int be, en, a, b;
	bool operator < (const edge &re) const {
		if (be == re.be) {
			return en < re.en;
		}
		return be < re.be;
	}
} alle[maxn];
priority_queue <pair <int, pii>, vector <pair <int, pii> >, greater <pair <int, pii> > > pq;

int findnxt(int no, int t, int cate) {
	for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
		int it = rit / 2;
		if (alle[it].be <= t) {
			t = max(alle[it].en - (alle[it].en % 2 != 2 - cate) * (cate != 3), t);
		} else break;
	}
	return t;
}

void addedge(int no, int i) {
	e[i].bef = -1;
	e[i].exist = 1;
	e[i].nxt = head[no];
	if (head[no] != -1) {
		e[head[no]].bef = i;
	}
	head[no] = i;
	e[i].exist = 1;
}

void deledge(int i) {
	if (e[i].bef != -1) {
		e[e[i].bef].nxt = e[i].nxt;
	} if (e[i].nxt != -1) {
		e[e[i].nxt].bef = e[i].bef;
	}
	e[i].exist = 0;
}

int getrcate(int cate) {
	if (cate == 3) return 3;
	else if(cate == 2) return 1;
	else if(cate == 1) return 2;
	else return 0;
}

void updrcate(int rcate, int nxtno, int t) {
	if ((dp[nxtno] | rcate) > (dp[nxtno] | nxtdp[nxtno])) {
		pq.push(mpr(t, mpr(2 + rcate, nxtno)));
		nxtdp[nxtno] = rcate | dp[nxtno];
		pq.push(mpr(t + 1, mpr(0, nxtno)));
	}
}

int main() {

//............................不要再忘了检查maxn大小了！！！！BSBandme你个SB！！！！...................................................

	ios_base::sync_with_stdio(0);
	#ifdef DEBUG //......................................................................................................
	freopen("input.txt", "r", stdin);
	int __size__ = 256 << 20; // 256MB
	char *__p__ = (char*)malloc(__size__) + __size__;
	__asm__("movl %0, %%esp\n" :: "r"(__p__));
	#endif //...........................................................................................................

	scanf("%d%d", &n, &m);
	if (n == 1) {
		cout << 0 << endl;
		return 0;
	}
//	m = 499998;
//	n = 4;
	for (int i = 0; i < m; i++) {
		int a, b, l, r;
		scanf("%d%d%d%d", &a, &b, &l, &r);
		a--; b--;
//		a = i % 3, b = (i + 1) % 3, l = i * 1000, r = l + 3000;
		alle[i].a = a;
		alle[i].b = b;
		alle[i].be = l;
		alle[i].en = r;
	}
	sort(alle, alle + m);
	memset(head, -1, sizeof(head));
	for (int i = m - 1; i >= 0; i--) {
		addedge(alle[i].a, i * 2);
		addedge(alle[i].b, i * 2 + 1);
	}
	dp[0] = 2;
	pq.push(mpr(findnxt(0, 0, 2), mpr(2, 0)));
	for (int i = 0; i < m; i++) {
		pq.push(mpr(alle[i].be, mpr(-1, i)));
		pq.push(mpr(alle[i].en, mpr(1, i)));
	}
	if (pq.size() && pq.top().first != 0) {
		puts("-1");
		return 0;
	}
	for (; pq.size(); ) {
		int t = pq.top().first, cate = pq.top().second.first, no = pq.top().second.second;
		pq.pop();
		if (no == n - 1 && cate < 2 && cate != -1 && cate != 1) {
			printf("%d\n", t);
			return 0;
		}
		if (cate > 2) {
			dp[no] |= nxtdp[no];
			nxtdp[no] = 0;
		} else if (cate == 2) {
			// delete no
			dp[no] = 0;
		} else if (cate == 1) {
			// delete e
			deledge(no * 2);
			deledge(no * 2 + 1);
		} else if (cate == 0){
			// addno
			if (dp[no] != 3 && 2 - dp[no] != t % 2) {
				pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			int rt = findnxt(no, t, dp[no]);
			pq.push(mpr(rt, mpr(2, no)));
			int rcate = getrcate(dp[no]);
 			for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
 				int it = rit / 2;
 				if (alle[it].be <= t && alle[it].en > t) {
					int nxtno = alle[it].a + alle[it].b - no;
					updrcate(rcate, nxtno, t);
 				} else if (alle[it].be > t) break;
 			}
		} else {
			// adde
			int a = alle[no].a, b = alle[no].b;
			if ((dp[a] == 2 && dp[b] == 1) || (dp[a] == 1 && dp[b] == 2) ||
					(dp[a] == 3 && dp[b] == 3) || (dp[a] == 0 && dp[b] == 0)) {
				continue;
			}
			if (t % 2 + 1 == dp[a] && t % 2 + 1 == dp[b]) {
				if (alle[no].en < t + 1)
					pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			updrcate(getrcate(dp[a]), b, t);
			updrcate(getrcate(dp[b]), a, t);
		}
	}
	printf("-1\n");

    return 0;
}


// #define DEBUG
//#define USEPB_DS
#define USETR1
#define CPPELEVEN
#define GPP

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <sstream>
#include <tuple>

using namespace std;

#ifndef CPPELEVEN
#ifdef USETR1
#include <tr1/unordered_map>
#include <tr1/unordered_set>
using namespace tr1;
#endif
#else
#include <unordered_map>
#include <unordered_set>
#endif

#ifdef USEPB_DS
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
// binomial_heap_tag, rc_binomial_heap_tag, thin_heap_tag, binary_heap_tag
typedef __gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> pq_type;
// splay_tree_tag, ov_tree_tag
typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> tree_type;
#endif

#define mpr make_pair
typedef unsigned int ui;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const long double eps = 1e-10;
const int step[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, 1}, {1, 1}, {1, -1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}

#ifndef CPPELEVEN
template <class T> inline T max1(T a, T b) { return b < a ? a : b; }
template <class T> inline T max1(T a, T b, T c) { return max1(max1(a, b), c); }
template <class T> inline T max1(T a, T b, T c, T d) { return max1(max1(a, b, c), d); }
template <class T> inline T max1(T a, T b, T c, T d, T e) { return max1(max1(a, b, c, d), e); }
template <class T> inline T min1(T a, T b) { return a < b ? a : b; }
template <class T> inline T min1(T a, T b, T c) { return min1(min1(a, b), c); }
template <class T> inline T min1(T a, T b, T c, T d) { return min1(min1(a, b, c), d); }
template <class T> inline T min1(T a, T b, T c, T d, T e) { return min1(min1(a, b, c, d), e); }
#else
template <typename t, typename t1>
t min1(t a, t1 b) { return a < b ? a : b; }
template <typename t, typename... arg>
t min1(t a, arg... arr) { return min1(a, min1(arr...)); }
template <typename t, typename t1>
t max1(t a, t1 b) { return a > b ? a : b; }
template <typename t, typename... arg>
t max1(t a, arg... arr) { return max1(a, max1(arr...)); }
#endif

inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / max(abs1(a), abs1(b)) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t> inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}

// f_lb == 1代表返回相同的一串的左边界，f_small == 1代表返回如果没有寻找的值返回小的数
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	if(na == 0) return 0;
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}

template <class T> inline T lowb(T num) {return num & (-num); }
#ifdef GPP
inline int bitnum(ui nValue) { return __builtin_popcount(nValue); }
inline int bitnum(int nValue) { return __builtin_popcount(nValue); }
inline int bitnum(ull nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitnum(ll nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitmaxl(ui a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(int a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(ull a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
inline int bitmaxl(ll a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
#else
#endif

long long pow(long long n, long long m, long long mod = 0){
	if(m < 0) return 0;
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

#define  MOD 1000000007
template <class t1, class t2>
inline void add(t1 &a, t2 b, int mod = -1) {
	if(mod == -1) mod = MOD;
	a += b;
	while(a >= mod) a -= mod;
	while(a < 0) a += mod;
}
template <class t>
void output1(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		cerr << arr[i] << ' ';
	cerr << endl;
}
template <class t>
void output2(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		output1(arr[i]);
}

//....................密..........封..........线..........下..........禁..........止..........hack...............................................

const int maxn = 505000;
int dp[maxn], nxtdp[maxn];
int n, m;
struct link {
	int nxt, bef;
	bool exist;
} e[maxn * 2];
int head[maxn];
struct edge {
	int be, en, a, b;
	bool operator < (const edge &re) const {
		if (be == re.be) {
			return en < re.en;
		}
		return be < re.be;
	}
} alle[maxn];
priority_queue <pair <int, pii>, vector <pair <int, pii> >, greater <pair <int, pii> > > pq;

int findnxt(int no, int t, int cate) {
	for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
		int it = rit / 2;
		if (alle[it].be <= t) {
			t = max(alle[it].en - (alle[it].en % 2 != 2 - cate) * (cate != 3), t);
		} else break;
	}
	return t;
}

void addedge(int no, int i) {
	e[i].bef = -1;
	e[i].exist = 1;
	e[i].nxt = head[no];
	if (head[no] != -1) {
		e[head[no]].bef = i;
	}
	head[no] = i;
	e[i].exist = 1;
}

void deledge(int i) {
	if (e[i].bef != -1) {
		e[e[i].bef].nxt = e[i].nxt;
	} if (e[i].nxt != -1) {
		e[e[i].nxt].bef = e[i].bef;
	}
	e[i].exist = 0;
}

int getrcate(int cate) {
	if (cate == 3) return 3;
	else if(cate == 2) return 1;
	else if(cate == 1) return 2;
	else return 0;
}

void updrcate(int rcate, int nxtno, int t) {
	if ((dp[nxtno] | rcate) > (dp[nxtno] | nxtdp[nxtno])) {
		pq.push(mpr(t, mpr(4 + rcate, nxtno)));
		nxtdp[nxtno] = rcate | dp[nxtno];
		pq.push(mpr(t + 1, mpr(0, nxtno)));
	}
}

int main() {

//............................不要再忘了检查maxn大小了！！！！BSBandme你个SB！！！！...................................................

	ios_base::sync_with_stdio(0);
	#ifdef DEBUG //......................................................................................................
	freopen("input.txt", "r", stdin);
	int __size__ = 256 << 20; // 256MB
	char *__p__ = (char*)malloc(__size__) + __size__;
	__asm__("movl %0, %%esp\n" :: "r"(__p__));
	#endif //...........................................................................................................

	scanf("%d%d", &n, &m);
	if (n == 1) {
		cout << 0 << endl;
		return 0;
	}
//	m = 499999;
//	n = 4;
	for (int i = 0; i < m; i++) {
		int a, b, l, r;
		scanf("%d%d%d%d", &a, &b, &l, &r);
		a--; b--;
//		a = i % 3, b = (i + 1) % 3, l = i * 1000, r = l + 3000;
//		if (i == m - 1) {
//			a = 0, b = 3, l = 500000000, r = l + 1;
//		}
		alle[i].a = a;
		alle[i].b = b;
		alle[i].be = l;
		alle[i].en = r;
	}
	sort(alle, alle + m);
	memset(head, -1, sizeof(head));
	for (int i = m - 1; i >= 0; i--) {
		addedge(alle[i].a, i * 2);
		addedge(alle[i].b, i * 2 + 1);
	}
	dp[0] = 2;
	pq.push(mpr(findnxt(0, 0, 2), mpr(3, 0)));
	for (int i = 0; i < m; i++) {
		pq.push(mpr(alle[i].be, mpr(-1, i)));
		pq.push(mpr(alle[i].en, mpr(1, i)));
	}
	if (pq.size() && pq.top().first != 0) {
		puts("-1");
		return 0;
	}
	for (; pq.size(); ) {
		int t = pq.top().first, cate = pq.top().second.first, no = pq.top().second.second;
		pq.pop();
		if (no == n - 1 && cate < 2 && cate != -1 && cate != 1) {
			printf("%d\n", t);
			return 0;
		}
		if (cate > 4) {
			dp[no] |= nxtdp[no];
			nxtdp[no] = 0;
		} else if (cate > 1) {
			// delete no
			dp[no] &= 3 ^ (cate - 1);
		} else if (cate == 1) {
			// delete e
			deledge(no * 2);
			deledge(no * 2 + 1);
		} else if (cate == 0){
			// addno
			if (dp[no] != 3 && 2 - dp[no] != t % 2) {
				pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			int rt = findnxt(no, t, dp[no]);
			pq.push(mpr(rt, mpr(1 + dp[no], no)));
			int rcate = getrcate(dp[no]);
 			for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
 				int it = rit / 2;
 				if (alle[it].be <= t && alle[it].en > t) {
					int nxtno = alle[it].a + alle[it].b - no;
					updrcate(rcate, nxtno, t);
 				} else if (alle[it].be > t) break;
 			}
		} else {
			// adde
			int a = alle[no].a, b = alle[no].b;
			if (dp[a] < dp[b]) swap(a, b);
			if ((dp[a] == 2 && dp[b] == 1) || (dp[a] == 1 && dp[b] == 2) ||
					(dp[a] == 3 && dp[b] == 3) || (dp[a] == 0 && dp[b] == 0)) {
				continue;
			}
			if ((t % 2 + 1 == dp[a] || dp[a] == 0) &&
				(t % 2 + 1 == dp[b] || dp[b] == 0) )
					{
				if (alle[no].en > t)
					pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			if (dp[a] == 3 && dp[b] == 0) {
				updrcate(t % 2 + 1, b, t);
				if (findnxt(a, t, 3) > t)
					updrcate(t % 2, b, t + 1);
			} else {
				updrcate(getrcate(dp[a]), b, t);
				updrcate(getrcate(dp[b]), a, t);
			}
		}
	}
	printf("-1\n");

    return 0;
}


// #define DEBUG
//#define USEPB_DS
#define USETR1
#define CPPELEVEN
#define GPP

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <sstream>
#include <tuple>

using namespace std;

#ifndef CPPELEVEN
#ifdef USETR1
#include <tr1/unordered_map>
#include <tr1/unordered_set>
using namespace tr1;
#endif
#else
#include <unordered_map>
#include <unordered_set>
#endif

#ifdef USEPB_DS
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
// binomial_heap_tag, rc_binomial_heap_tag, thin_heap_tag, binary_heap_tag
typedef __gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> pq_type;
// splay_tree_tag, ov_tree_tag
typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> tree_type;
#endif

#define mpr make_pair
typedef unsigned int ui;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const long double eps = 1e-10;
const int step[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, 1}, {1, 1}, {1, -1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}

#ifndef CPPELEVEN
template <class T> inline T max1(T a, T b) { return b < a ? a : b; }
template <class T> inline T max1(T a, T b, T c) { return max1(max1(a, b), c); }
template <class T> inline T max1(T a, T b, T c, T d) { return max1(max1(a, b, c), d); }
template <class T> inline T max1(T a, T b, T c, T d, T e) { return max1(max1(a, b, c, d), e); }
template <class T> inline T min1(T a, T b) { return a < b ? a : b; }
template <class T> inline T min1(T a, T b, T c) { return min1(min1(a, b), c); }
template <class T> inline T min1(T a, T b, T c, T d) { return min1(min1(a, b, c), d); }
template <class T> inline T min1(T a, T b, T c, T d, T e) { return min1(min1(a, b, c, d), e); }
#else
template <typename t, typename t1>
t min1(t a, t1 b) { return a < b ? a : b; }
template <typename t, typename... arg>
t min1(t a, arg... arr) { return min1(a, min1(arr...)); }
template <typename t, typename t1>
t max1(t a, t1 b) { return a > b ? a : b; }
template <typename t, typename... arg>
t max1(t a, arg... arr) { return max1(a, max1(arr...)); }
#endif

inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / max(abs1(a), abs1(b)) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t> inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}

// f_lb == 1代表返回相同的一串的左边界，f_small == 1代表返回如果没有寻找的值返回小的数
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	if(na == 0) return 0;
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}

template <class T> inline T lowb(T num) {return num & (-num); }
#ifdef GPP
inline int bitnum(ui nValue) { return __builtin_popcount(nValue); }
inline int bitnum(int nValue) { return __builtin_popcount(nValue); }
inline int bitnum(ull nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitnum(ll nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitmaxl(ui a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(int a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(ull a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
inline int bitmaxl(ll a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
#else
#endif

long long pow(long long n, long long m, long long mod = 0){
	if(m < 0) return 0;
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

#define  MOD 1000000007
template <class t1, class t2>
inline void add(t1 &a, t2 b, int mod = -1) {
	if(mod == -1) mod = MOD;
	a += b;
	while(a >= mod) a -= mod;
	while(a < 0) a += mod;
}
template <class t>
void output1(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		cerr << arr[i] << ' ';
	cerr << endl;
}
template <class t>
void output2(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		output1(arr[i]);
}

//....................密..........封..........线..........下..........禁..........止..........hack...............................................

const int maxn = 505000;
bool flag = 0;
int dp[maxn], nxtdp[maxn][2], tnxt[maxn][3];
int n, m;
struct link {
	int nxt, bef;
	bool exist;
} e[maxn * 2];
int head[maxn];
struct edge {
	int be, en, a, b;
	bool operator < (const edge &re) const {
		if (be == re.be) {
			return en < re.en;
		}
		return be < re.be;
	}
} alle[maxn];
priority_queue <pair <int, pii>, vector <pair <int, pii> >, greater <pair <int, pii> > > pq;

int findnxt(int no, int t, int cate) {
	for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
		int it = rit / 2;
		if (alle[it].be <= t) {
			t = max(alle[it].en - (alle[it].en % 2 != 2 - cate) * (cate != 3), t);
		} else break;
	}
	return t;
}

void addedge(int no, int i) {
	e[i].bef = -1;
	e[i].exist = 1;
	e[i].nxt = head[no];
	if (head[no] != -1) {
		e[head[no]].bef = i;
	}
	head[no] = i;
	e[i].exist = 1;
}

void deledge(int i) {
	if (e[i].bef != -1) {
		e[e[i].bef].nxt = e[i].nxt;
	} if (e[i].nxt != -1) {
		e[e[i].nxt].bef = e[i].bef;
	}
	e[i].exist = 0;
}

int getrcate(int cate) {
	if (cate == 3) return 3;
	else if(cate == 2) return 1;
	else if(cate == 1) return 2;
	else return 0;
}

void updrcate(int rcate, int nxtno, int t, int add) {
	if (((rcate | dp[nxtno]) ^ dp[nxtno]) >= 3) {
		cout << dp[nxtno] << ' ' << rcate << endl;
		exit(0);
	}
	if ((dp[nxtno] | rcate) > (dp[nxtno] | nxtdp[nxtno][add])) {
		if(((rcate | dp[nxtno]) ^ dp[nxtno]) != t % 2 + 1) {
			cout << dp[nxtno] << ' ' << rcate << ' ' << t;
			exit(0);
		}
		pq.push(mpr(t, mpr(4 + rcate, nxtno)));
		nxtdp[nxtno][add] = rcate;
		if (nxtno == 95611 && flag) {
			cout << t << ' ' << dp[nxtno] << ' ' << rcate << ' ' << nxtdp[nxtno][add] << ' ' << add << endl;
			cout << t + 1 << ' ' << 0 << ' ' << nxtno << endl;
		}
		pq.push(mpr(t + 1, mpr(0, nxtno)));
	}
}

void add(int no1, int eno, int no, int t) {
	int more = getrcate(dp[no1]) | dp[no];
	more ^= dp[no];
	if ((more & (t % 2 + 1)) && alle[eno].en > t)
		updrcate(more & (t % 2 + 1), no, t, 0);
	if ((more & (2 - t % 2)) && alle[eno].en > t + 1 && tnxt[no1][more & (2 - t % 2)] > t)
		updrcate(more & (2 - t % 2), no, t + 1, 1);
}

int main() {

//............................不要再忘了检查maxn大小了！！！！BSBandme你个SB！！！！...................................................

	ios_base::sync_with_stdio(0);
	#ifdef DEBUG //......................................................................................................
	freopen("input.txt", "r", stdin);
	int __size__ = 256 << 20; // 256MB
	char *__p__ = (char*)malloc(__size__) + __size__;
	__asm__("movl %0, %%esp\n" :: "r"(__p__));
	#endif //...........................................................................................................

	scanf("%d%d", &n, &m);
	if (n == 1) {
		cout << 0 << endl;
		return 0;
	}
//	m = 499999;
//	n = 4;
	for (int i = 0; i < m; i++) {
		int a, b, l, r;
		scanf("%d%d%d%d", &a, &b, &l, &r);
		a--; b--;
//		a = i % 3, b = (i + 1) % 3, l = i * 1000, r = l + 3000;
//		if (i == m - 1) {
//			a = 0, b = 3, l = 500000000, r = l + 1;
//		}
		alle[i].a = a;
		alle[i].b = b;
		alle[i].be = l;
		alle[i].en = r;
	}
	auto ju = [&] () {
		return n == 100000 && m == 149999;
	};
	flag = ju();
	sort(alle, alle + m);
	memset(head, -1, sizeof(head));
	for (int i = m - 1; i >= 0; i--) {
		addedge(alle[i].a, i * 2);
		addedge(alle[i].b, i * 2 + 1);
	}
	dp[0] = 2;
	pq.push(mpr(findnxt(0, 0, 2), mpr(3, 0)));
	tnxt[0][2] = findnxt(0, 0, 2);
	for (int i = 0; i < m; i++) {
		pq.push(mpr(alle[i].be, mpr(-1, i)));
		pq.push(mpr(alle[i].en, mpr(1, i)));
	}
	if (pq.size() && pq.top().first != 0) {
		puts("-1");
		return 0;
	}
	for (; pq.size(); ) {
		int t = pq.top().first, cate = pq.top().second.first, no = pq.top().second.second;
		pq.pop();
		if (no == n - 1 && cate < 2 && cate != -1 && cate != 1) {
			printf("%d\n", t);
			return 0;
		}
		if (cate > 4) {
			dp[no] |= nxtdp[no][0];
			nxtdp[no][0] = nxtdp[no][1];
			nxtdp[no][1] = 0;
		} else if (cate > 1) {
			// delete no
//			assert(dp[no] & (cate - 1));
			if (no == 95611 && ju()) {
				cout << t << ' ' << cate - 1 << ' ' << dp[no] << endl;
			}
			if (! (dp[no] & (cate - 1))) {
				cout << t << ' ' << no << ' ' << dp[no] << ' ' << cate - 1 << endl;
				tnxt[no][cate - 1];
				exit(0);
			}
			dp[no] &= 3 ^ (cate - 1);
		} else if (cate == 1) {
			// delete e
			deledge(no * 2);
			deledge(no * 2 + 1);
		} else if (cate == 0){
			// addno
			if (dp[no] != 3 && 2 - dp[no] != t % 2) {
				pq.push(mpr(t + 1, mpr(0, no)));
				continue;
			}
			assert(dp[no] & (2 - (t % 2)));
			int rt = findnxt(no, t, (2 - (t % 2)));
			tnxt[no][2 - t % 2] = rt;
			pq.push(mpr(rt, mpr(1 + (2 - t % 2), no)));
			if (ju() && no == 95611 && rt == 358710) {
				cout << t << ' ' << cate << ' ' << dp[no] << endl;
			}
 			for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
 				int it = rit / 2;
 				if (alle[it].be <= t ) {
					int nxtno = alle[it].a + alle[it].b - no;
					add(no, it, nxtno, t);
 				} else break;
 			}
		} else {
			// adde
			int a = alle[no].a, b = alle[no].b;
			if (dp[a] < dp[b]) swap(a, b);
			if ((dp[a] == 2 && dp[b] == 1) || (dp[a] == 1 && dp[b] == 2) ||
					(dp[a] == 3 && dp[b] == 3) || (dp[a] == 0 && dp[b] == 0)) {
				continue;
			}
			if ((t % 2 + 1 == dp[a] || dp[a] == 0) &&
				(t % 2 + 1 == dp[b] || dp[b] == 0) )
					{
				if (alle[no].en > t)
					pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			add(a, no, b, t);
			add(b, no, a, t);
		}
	}
	printf("-1\n");

    return 0;
}


// #define DEBUG
//#define USEPB_DS
#define USETR1
#define CPPELEVEN
#define GPP

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <sstream>
#include <tuple>

using namespace std;

#ifndef CPPELEVEN
#ifdef USETR1
#include <tr1/unordered_map>
#include <tr1/unordered_set>
using namespace tr1;
#endif
#else
#include <unordered_map>
#include <unordered_set>
#endif

#ifdef USEPB_DS
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
// binomial_heap_tag, rc_binomial_heap_tag, thin_heap_tag, binary_heap_tag
typedef __gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> pq_type;
// splay_tree_tag, ov_tree_tag
typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> tree_type;
#endif

#define mpr make_pair
typedef unsigned int ui;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const long double eps = 1e-10;
const int step[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, 1}, {1, 1}, {1, -1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}

#ifndef CPPELEVEN
template <class T> inline T max1(T a, T b) { return b < a ? a : b; }
template <class T> inline T max1(T a, T b, T c) { return max1(max1(a, b), c); }
template <class T> inline T max1(T a, T b, T c, T d) { return max1(max1(a, b, c), d); }
template <class T> inline T max1(T a, T b, T c, T d, T e) { return max1(max1(a, b, c, d), e); }
template <class T> inline T min1(T a, T b) { return a < b ? a : b; }
template <class T> inline T min1(T a, T b, T c) { return min1(min1(a, b), c); }
template <class T> inline T min1(T a, T b, T c, T d) { return min1(min1(a, b, c), d); }
template <class T> inline T min1(T a, T b, T c, T d, T e) { return min1(min1(a, b, c, d), e); }
#else
template <typename t, typename t1>
t min1(t a, t1 b) { return a < b ? a : b; }
template <typename t, typename... arg>
t min1(t a, arg... arr) { return min1(a, min1(arr...)); }
template <typename t, typename t1>
t max1(t a, t1 b) { return a > b ? a : b; }
template <typename t, typename... arg>
t max1(t a, arg... arr) { return max1(a, max1(arr...)); }
#endif

inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / max(abs1(a), abs1(b)) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t> inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}

// f_lb == 1代表返回相同的一串的左边界，f_small == 1代表返回如果没有寻找的值返回小的数
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	if(na == 0) return 0;
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}

template <class T> inline T lowb(T num) {return num & (-num); }
#ifdef GPP
inline int bitnum(ui nValue) { return __builtin_popcount(nValue); }
inline int bitnum(int nValue) { return __builtin_popcount(nValue); }
inline int bitnum(ull nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitnum(ll nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitmaxl(ui a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(int a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(ull a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
inline int bitmaxl(ll a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
#else
#endif

long long pow(long long n, long long m, long long mod = 0){
	if(m < 0) return 0;
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

#define  MOD 1000000007
template <class t1, class t2>
inline void add(t1 &a, t2 b, int mod = -1) {
	if(mod == -1) mod = MOD;
	a += b;
	while(a >= mod) a -= mod;
	while(a < 0) a += mod;
}
template <class t>
void output1(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		cerr << arr[i] << ' ';
	cerr << endl;
}
template <class t>
void output2(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		output1(arr[i]);
}

//....................密..........封..........线..........下..........禁..........止..........hack...............................................

const int maxn = 505000;
int dp[maxn], nxtdp[maxn][2];
int n, m;
struct link {
	int nxt, bef;
	bool exist;
} e[maxn * 2];
int head[maxn];
struct edge {
	int be, en, a, b;
	bool operator < (const edge &re) const {
		if (be == re.be) {
			return en < re.en;
		}
		return be < re.be;
	}
} alle[maxn];
priority_queue <pair <int, pii>, vector <pair <int, pii> >, greater <pair <int, pii> > > pq;

int findnxt(int no, int t, int cate) {
	for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
		int it = rit / 2;
		if (alle[it].be <= t) {
			t = max(alle[it].en - (alle[it].en % 2 != 2 - cate) * (cate != 3), t);
		} else break;
	}
	return t;
}

void addedge(int no, int i) {
	e[i].bef = -1;
	e[i].exist = 1;
	e[i].nxt = head[no];
	if (head[no] != -1) {
		e[head[no]].bef = i;
	}
	head[no] = i;
	e[i].exist = 1;
}

void deledge(int i) {
	if (e[i].bef != -1) {
		e[e[i].bef].nxt = e[i].nxt;
	} if (e[i].nxt != -1) {
		e[e[i].nxt].bef = e[i].bef;
	}
	e[i].exist = 0;
}

int getrcate(int cate) {
	if (cate == 3) return 3;
	else if(cate == 2) return 1;
	else if(cate == 1) return 2;
	else return 0;
}

void updrcate(int rcate, int nxtno, int t, int add) {
	if (((rcate | dp[nxtno]) ^ dp[nxtno]) >= 3) {
		cout << dp[nxtno] << ' ' << rcate << endl;
		exit(0);
	}
	if ((dp[nxtno] | rcate) > (dp[nxtno] | nxtdp[nxtno][add])) {
		if(((rcate | dp[nxtno]) ^ dp[nxtno]) != t % 2 + 1) {
			cout << dp[nxtno] << ' ' << rcate << ' ' << t;
			exit(0);
		}
		pq.push(mpr(t, mpr(4 + rcate, nxtno)));
		nxtdp[nxtno][add] = rcate | dp[nxtno];
		pq.push(mpr(t + 1, mpr(0, nxtno)));
	}
}

void add(int eno, int no, int more, int t) {
	if ((more & (t % 2 + 1)) && alle[eno].en > t)
		updrcate(more & (t % 2 + 1), no, t, 0);
	if ((more & (2 - t % 2)) && alle[no].en > t + 1)
		updrcate(more & (2 - t % 2), no, t + 1, 1);
}

int main() {

//............................不要再忘了检查maxn大小了！！！！BSBandme你个SB！！！！...................................................

	ios_base::sync_with_stdio(0);
	#ifdef DEBUG //......................................................................................................
	freopen("input.txt", "r", stdin);
	int __size__ = 256 << 20; // 256MB
	char *__p__ = (char*)malloc(__size__) + __size__;
	__asm__("movl %0, %%esp\n" :: "r"(__p__));
	#endif //...........................................................................................................

	scanf("%d%d", &n, &m);
	if (n == 1) {
		cout << 0 << endl;
		return 0;
	}
//	m = 499999;
//	n = 4;
	for (int i = 0; i < m; i++) {
		int a, b, l, r;
		scanf("%d%d%d%d", &a, &b, &l, &r);
		a--; b--;
//		a = i % 3, b = (i + 1) % 3, l = i * 1000, r = l + 3000;
//		if (i == m - 1) {
//			a = 0, b = 3, l = 500000000, r = l + 1;
//		}
		alle[i].a = a;
		alle[i].b = b;
		alle[i].be = l;
		alle[i].en = r;
	}
	sort(alle, alle + m);
	memset(head, -1, sizeof(head));
	for (int i = m - 1; i >= 0; i--) {
		addedge(alle[i].a, i * 2);
		addedge(alle[i].b, i * 2 + 1);
	}
	dp[0] = 2;
	pq.push(mpr(findnxt(0, 0, 2), mpr(3, 0)));
	for (int i = 0; i < m; i++) {
		pq.push(mpr(alle[i].be, mpr(-1, i)));
		pq.push(mpr(alle[i].en, mpr(1, i)));
	}
	if (pq.size() && pq.top().first != 0) {
		puts("-1");
		return 0;
	}
	for (; pq.size(); ) {
		int t = pq.top().first, cate = pq.top().second.first, no = pq.top().second.second;
		pq.pop();
		if (no == n - 1 && cate < 2 && cate != -1 && cate != 1) {
			printf("%d\n", t);
			return 0;
		}
		if (cate > 4) {
			dp[no] |= nxtdp[no][0];
			nxtdp[no][0] = nxtdp[no][1];
			nxtdp[no][1] = 0;
		} else if (cate > 1) {
			// delete no
			dp[no] &= 3 ^ (cate - 1);
		} else if (cate == 1) {
			// delete e
			deledge(no * 2);
			deledge(no * 2 + 1);
		} else if (cate == 0){
			// addno
			if (dp[no] != 3 && 2 - dp[no] != t % 2) {
				pq.push(mpr(t + 1, mpr(0, no)));
				continue;
			}
			int rt = findnxt(no, t, dp[no]);
			pq.push(mpr(rt, mpr(1 + dp[no], no)));
			int rcate = getrcate(dp[no]);
 			for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
 				int it = rit / 2;
 				if (alle[it].be <= t ) {
					int nxtno = alle[it].a + alle[it].b - no;
					int more = (rcate | dp[no]) ^ dp[no];
					add(it, nxtno, more, t);
 				} else break;
 			}
		} else {
			// adde
			int a = alle[no].a, b = alle[no].b;
			if (dp[a] < dp[b]) swap(a, b);
			if ((dp[a] == 2 && dp[b] == 1) || (dp[a] == 1 && dp[b] == 2) ||
					(dp[a] == 3 && dp[b] == 3) || (dp[a] == 0 && dp[b] == 0)) {
				continue;
			}
			if ((t % 2 + 1 == dp[a] || dp[a] == 0) &&
				(t % 2 + 1 == dp[b] || dp[b] == 0) )
					{
				if (alle[no].en > t)
					pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			int more = getrcate(dp[a]) | dp[b];
			more ^= dp[b];
			add(no, b, more, t);
			more = getrcate(dp[b]) | dp[a];
			more ^= dp[a];
			add(no, b, more, t);
		}
	}
	printf("-1\n");

    return 0;
}


// #define DEBUG
//#define USEPB_DS
#define USETR1
#define CPPELEVEN
#define GPP

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <sstream>
#include <tuple>

using namespace std;

#ifndef CPPELEVEN
#ifdef USETR1
#include <tr1/unordered_map>
#include <tr1/unordered_set>
using namespace tr1;
#endif
#else
#include <unordered_map>
#include <unordered_set>
#endif

#ifdef USEPB_DS
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
// binomial_heap_tag, rc_binomial_heap_tag, thin_heap_tag, binary_heap_tag
typedef __gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> pq_type;
// splay_tree_tag, ov_tree_tag
typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> tree_type;
#endif

#define mpr make_pair
typedef unsigned int ui;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const long double eps = 1e-10;
const int step[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, 1}, {1, 1}, {1, -1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}

#ifndef CPPELEVEN
template <class T> inline T max1(T a, T b) { return b < a ? a : b; }
template <class T> inline T max1(T a, T b, T c) { return max1(max1(a, b), c); }
template <class T> inline T max1(T a, T b, T c, T d) { return max1(max1(a, b, c), d); }
template <class T> inline T max1(T a, T b, T c, T d, T e) { return max1(max1(a, b, c, d), e); }
template <class T> inline T min1(T a, T b) { return a < b ? a : b; }
template <class T> inline T min1(T a, T b, T c) { return min1(min1(a, b), c); }
template <class T> inline T min1(T a, T b, T c, T d) { return min1(min1(a, b, c), d); }
template <class T> inline T min1(T a, T b, T c, T d, T e) { return min1(min1(a, b, c, d), e); }
#else
template <typename t, typename t1>
t min1(t a, t1 b) { return a < b ? a : b; }
template <typename t, typename... arg>
t min1(t a, arg... arr) { return min1(a, min1(arr...)); }
template <typename t, typename t1>
t max1(t a, t1 b) { return a > b ? a : b; }
template <typename t, typename... arg>
t max1(t a, arg... arr) { return max1(a, max1(arr...)); }
#endif

inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / max(abs1(a), abs1(b)) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t> inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}

// f_lb == 1代表返回相同的一串的左边界，f_small == 1代表返回如果没有寻找的值返回小的数
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	if(na == 0) return 0;
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}

template <class T> inline T lowb(T num) {return num & (-num); }
#ifdef GPP
inline int bitnum(ui nValue) { return __builtin_popcount(nValue); }
inline int bitnum(int nValue) { return __builtin_popcount(nValue); }
inline int bitnum(ull nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitnum(ll nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitmaxl(ui a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(int a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(ull a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
inline int bitmaxl(ll a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
#else
#endif

long long pow(long long n, long long m, long long mod = 0){
	if(m < 0) return 0;
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

#define  MOD 1000000007
template <class t1, class t2>
inline void add(t1 &a, t2 b, int mod = -1) {
	if(mod == -1) mod = MOD;
	a += b;
	while(a >= mod) a -= mod;
	while(a < 0) a += mod;
}
template <class t>
void output1(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		cerr << arr[i] << ' ';
	cerr << endl;
}
template <class t>
void output2(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		output1(arr[i]);
}

//....................密..........封..........线..........下..........禁..........止..........hack...............................................

const int maxn = 505000;
int dp[maxn], nxtdp[maxn];
int n, m;
vi e[maxn];
struct edge {
	int be, en, a, b;
	bool operator < (const edge &re) const {
		if (be == re.be) {
			return en < re.en;
		}
		return be < re.be;
	}
} alle[maxn];
priority_queue <pair <int, pii>, vector <pair <int, pii> >, greater <pair <int, pii> > > pq;

int findnxt(int no, int t, int cate) {
	for (auto it : e[no]) {
		if (alle[it].be <= t) {
			t = max(alle[it].en - (alle[it].en % 2 != 2 - cate) * (cate != 3), t);
		} else break;
	}
	return t;
}

int main() {

//............................不要再忘了检查maxn大小了！！！！BSBandme你个SB！！！！...................................................

	ios_base::sync_with_stdio(0);
	#ifdef DEBUG //......................................................................................................
	freopen("input.txt", "r", stdin);
	int __size__ = 256 << 20; // 256MB
	char *__p__ = (char*)malloc(__size__) + __size__;
	__asm__("movl %0, %%esp\n" :: "r"(__p__));
	#endif //...........................................................................................................

	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++) {
		int a, b, l, r;
		scanf("%d%d%d%d", &a, &b, &l, &r);
		a--; b--;
		alle[i].a = a;
		alle[i].b = b;
		alle[i].be = l;
		alle[i].en = r;
	}
	sort(alle, alle + m);
	for (int i = 0; i < m; i++) {
		e[alle[i].a].push_back(i);
		e[alle[i].b].push_back(i);
	}
	dp[0] = 2;
	for (int i = 0; i < m; i++) {
		pq.push(mpr(alle[i].be, mpr(-1, alle[i].a)));
		pq.push(mpr(alle[i].be, mpr(-1, alle[i].b)));
	}
	if (pq.top().first != 0) {
		puts("-1");
		return 0;
	}
	for (; pq.size(); ) {
		int t = pq.top().first, cate = pq.top().second.first, no = pq.top().second.second;
		pq.pop();
		if (dp[no] == 0 && cate < 2) {
			continue;
		}
		if (no == n - 1 && cate < 2) {
			printf("%d\n", t);
			return 0;
		}
		if (cate > 2) {
			dp[no] |= nxtdp[no];
			nxtdp[no] = 0;
		} else if (cate == 1) {
			// delete
			dp[no] = 0;
		} else {
			// add
			if (dp[no] != 3 && 2 - dp[no] != t % 2) {
				pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			int rt = findnxt(no, t, dp[no]);
			pq.push(mpr(rt, mpr(1, no)));
			int rcate = 0;
			if (dp[no] == 1) rcate = 2;
			if (dp[no] == 2) rcate = 1;
			if (dp[no] == 3) rcate = 3;
 			for (auto it : e[no]) if (alle[it].be <= t && alle[it].en > t){
 				int nxtno = alle[it].a + alle[it].b - no;
 				if ((dp[nxtno] | rcate) > (dp[nxtno] | nxtdp[nxtno])) {
 					pq.push(mpr(t, mpr(2 + rcate, nxtno)));
 					nxtdp[nxtno] = rcate | dp[nxtno];
 					pq.push(mpr(t + 1, mpr(-1, nxtno)));
 				}
			}
		}
	}
	printf("-1\n");

    return 0;
}


// #define DEBUG
//#define USEPB_DS
#define USETR1
#define CPPELEVEN
#define GPP

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <sstream>
#include <tuple>

using namespace std;

#ifndef CPPELEVEN
#ifdef USETR1
#include <tr1/unordered_map>
#include <tr1/unordered_set>
using namespace tr1;
#endif
#else
#include <unordered_map>
#include <unordered_set>
#endif

#ifdef USEPB_DS
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
// binomial_heap_tag, rc_binomial_heap_tag, thin_heap_tag, binary_heap_tag
typedef __gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> pq_type;
// splay_tree_tag, ov_tree_tag
typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> tree_type;
#endif

#define mpr make_pair
typedef unsigned int ui;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const long double eps = 1e-10;
const int step[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, 1}, {1, 1}, {1, -1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}

#ifndef CPPELEVEN
template <class T> inline T max1(T a, T b) { return b < a ? a : b; }
template <class T> inline T max1(T a, T b, T c) { return max1(max1(a, b), c); }
template <class T> inline T max1(T a, T b, T c, T d) { return max1(max1(a, b, c), d); }
template <class T> inline T max1(T a, T b, T c, T d, T e) { return max1(max1(a, b, c, d), e); }
template <class T> inline T min1(T a, T b) { return a < b ? a : b; }
template <class T> inline T min1(T a, T b, T c) { return min1(min1(a, b), c); }
template <class T> inline T min1(T a, T b, T c, T d) { return min1(min1(a, b, c), d); }
template <class T> inline T min1(T a, T b, T c, T d, T e) { return min1(min1(a, b, c, d), e); }
#else
template <typename t, typename t1>
t min1(t a, t1 b) { return a < b ? a : b; }
template <typename t, typename... arg>
t min1(t a, arg... arr) { return min1(a, min1(arr...)); }
template <typename t, typename t1>
t max1(t a, t1 b) { return a > b ? a : b; }
template <typename t, typename... arg>
t max1(t a, arg... arr) { return max1(a, max1(arr...)); }
#endif

inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / max(abs1(a), abs1(b)) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t> inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}

// f_lb == 1代表返回相同的一串的左边界，f_small == 1代表返回如果没有寻找的值返回小的数
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	if(na == 0) return 0;
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}

template <class T> inline T lowb(T num) {return num & (-num); }
#ifdef GPP
inline int bitnum(ui nValue) { return __builtin_popcount(nValue); }
inline int bitnum(int nValue) { return __builtin_popcount(nValue); }
inline int bitnum(ull nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitnum(ll nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitmaxl(ui a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(int a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(ull a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
inline int bitmaxl(ll a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
#else
#endif

long long pow(long long n, long long m, long long mod = 0){
	if(m < 0) return 0;
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

#define  MOD 1000000007
template <class t1, class t2>
inline void add(t1 &a, t2 b, int mod = -1) {
	if(mod == -1) mod = MOD;
	a += b;
	while(a >= mod) a -= mod;
	while(a < 0) a += mod;
}
template <class t>
void output1(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		cerr << arr[i] << ' ';
	cerr << endl;
}
template <class t>
void output2(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		output1(arr[i]);
}

//....................密..........封..........线..........下..........禁..........止..........hack...............................................

const int maxn = 505000;
bool flag = 0;
int dp[maxn], nxtdp[maxn][3], tnxt[maxn][3];
int n, m;
struct link {
	int nxt, bef;
	bool exist;
} e[maxn * 2];
int head[maxn];
struct edge {
	int be, en, a, b;
	bool operator < (const edge &re) const {
		if (be == re.be) {
			return en < re.en;
		}
		return be < re.be;
	}
} alle[maxn];
priority_queue <pair <int, pii>, vector <pair <int, pii> >, greater <pair <int, pii> > > pq;

int findnxt(int no, int t, int cate) {
	for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
		int it = rit / 2;
		if (alle[it].be <= t) {
			t = max(alle[it].en - (alle[it].en % 2 != 2 - cate) * (cate != 3), t);
		} else break;
	}
	return t;
}

void addedge(int no, int i) {
	e[i].bef = -1;
	e[i].exist = 1;
	e[i].nxt = head[no];
	if (head[no] != -1) {
		e[head[no]].bef = i;
	}
	head[no] = i;
	e[i].exist = 1;
}

void deledge(int i) {
	if (e[i].bef != -1) {
		e[e[i].bef].nxt = e[i].nxt;
	} if (e[i].nxt != -1) {
		e[e[i].nxt].bef = e[i].bef;
	}
	e[i].exist = 0;
}

int getrcate(int cate) {
	if (cate == 3) return 3;
	else if(cate == 2) return 1;
	else if(cate == 1) return 2;
	else return 0;
}

void updrcate(int rcate, int nxtno, int t, int add) {
	if ((dp[nxtno] | rcate) > (dp[nxtno] | nxtdp[nxtno][add])) {
		pq.push(mpr(t, mpr(4 + rcate, nxtno)));
		nxtdp[nxtno][add] = rcate;
		pq.push(mpr(t + 1, mpr(0, nxtno)));
	}
}

void add(int no1, int eno, int no, int t) {
	int more = getrcate(dp[no1]) | dp[no];
	more ^= dp[no];
	if ((more & (t % 2 + 1)) && alle[eno].en > t)
		updrcate(more & (t % 2 + 1), no, t, 2 - t % 2);
	if ((more & (2 - t % 2)) && alle[eno].en > t + 1 && tnxt[no1][more & (2 - t % 2)] > t)
		updrcate(more & (2 - t % 2), no, t + 1, t % 2 + 1);
}

int main() {

//............................不要再忘了检查maxn大小了！！！！BSBandme你个SB！！！！...................................................

	ios_base::sync_with_stdio(0);
	#ifdef DEBUG //......................................................................................................
	freopen("input.txt", "r", stdin);
	int __size__ = 256 << 20; // 256MB
	char *__p__ = (char*)malloc(__size__) + __size__;
	__asm__("movl %0, %%esp\n" :: "r"(__p__));
	#endif //...........................................................................................................

	scanf("%d%d", &n, &m);
	if (n == 1) {
		cout << 0 << endl;
		return 0;
	}
	for (int i = 0; i < m; i++) {
		int a, b, l, r;
		scanf("%d%d%d%d", &a, &b, &l, &r);
		a--; b--;
		alle[i].a = a;
		alle[i].b = b;
		alle[i].be = l;
		alle[i].en = r;
	}
	auto ju = [&] () {
		return n == 100000 && m == 149999;
	};
	flag = ju();
	sort(alle, alle + m);
	memset(head, -1, sizeof(head));
	for (int i = m - 1; i >= 0; i--) {
		addedge(alle[i].a, i * 2);
		addedge(alle[i].b, i * 2 + 1);
	}
	dp[0] = 2;
	pq.push(mpr(findnxt(0, 0, 2), mpr(3, 0)));
	tnxt[0][2] = findnxt(0, 0, 2);
	for (int i = 0; i < m; i++) {
		pq.push(mpr(alle[i].be, mpr(-1, i)));
		pq.push(mpr(alle[i].en, mpr(1, i)));
	}
	if (pq.size() && pq.top().first != 0) {
		puts("-1");
		return 0;
	}
	for (; pq.size(); ) {
		int t = pq.top().first, cate = pq.top().second.first, no = pq.top().second.second;
		pq.pop();
		if (cate > 4) {
			dp[no] |= nxtdp[no][2 - t % 2];
			nxtdp[no][2 - t % 2] = 0;
		} else if (cate > 1) {
			dp[no] &= 3 ^ (cate - 1);
		} else if (cate == 1) {
			// delete e
			deledge(no * 2);
			deledge(no * 2 + 1);
		} else if (cate == 0){
			// addno
			if (dp[no] != 3 && 2 - dp[no] != t % 2) {
				pq.push(mpr(t + 1, mpr(0, no)));
				continue;
			}
			int rt = findnxt(no, t, (2 - (t % 2)));
			tnxt[no][2 - t % 2] = rt;
			pq.push(mpr(rt, mpr(1 + (2 - t % 2), no)));
 			for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
 				int it = rit / 2;
 				if (alle[it].be <= t ) {
					int nxtno = alle[it].a + alle[it].b - no;
					add(no, it, nxtno, t);
 				} else break;
 			}
		} else {
			// adde
			int a = alle[no].a, b = alle[no].b;
			if (dp[a] < dp[b]) swap(a, b);
			if ((dp[a] == 2 && dp[b] == 1) || (dp[a] == 1 && dp[b] == 2) ||
					(dp[a] == 3 && dp[b] == 3) || (dp[a] == 0 && dp[b] == 0)) {
				continue;
			}
			if ((t % 2 + 1 == dp[a] || dp[a] == 0) &&
				(t % 2 + 1 == dp[b] || dp[b] == 0) )
					{
				if (alle[no].en > t)
					pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			add(a, no, b, t);
			add(b, no, a, t);
		}
	}
	printf("-1\n");

    return 0;
}


// #define DEBUG
//#define USEPB_DS
#define USETR1
#define CPPELEVEN
#define GPP

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <sstream>
#include <tuple>

using namespace std;

#ifndef CPPELEVEN
#ifdef USETR1
#include <tr1/unordered_map>
#include <tr1/unordered_set>
using namespace tr1;
#endif
#else
#include <unordered_map>
#include <unordered_set>
#endif

#ifdef USEPB_DS
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
// binomial_heap_tag, rc_binomial_heap_tag, thin_heap_tag, binary_heap_tag
typedef __gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> pq_type;
// splay_tree_tag, ov_tree_tag
typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> tree_type;
#endif

#define mpr make_pair
typedef unsigned int ui;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const long double eps = 1e-10;
const int step[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, 1}, {1, 1}, {1, -1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}

#ifndef CPPELEVEN
template <class T> inline T max1(T a, T b) { return b < a ? a : b; }
template <class T> inline T max1(T a, T b, T c) { return max1(max1(a, b), c); }
template <class T> inline T max1(T a, T b, T c, T d) { return max1(max1(a, b, c), d); }
template <class T> inline T max1(T a, T b, T c, T d, T e) { return max1(max1(a, b, c, d), e); }
template <class T> inline T min1(T a, T b) { return a < b ? a : b; }
template <class T> inline T min1(T a, T b, T c) { return min1(min1(a, b), c); }
template <class T> inline T min1(T a, T b, T c, T d) { return min1(min1(a, b, c), d); }
template <class T> inline T min1(T a, T b, T c, T d, T e) { return min1(min1(a, b, c, d), e); }
#else
template <typename t, typename t1>
t min1(t a, t1 b) { return a < b ? a : b; }
template <typename t, typename... arg>
t min1(t a, arg... arr) { return min1(a, min1(arr...)); }
template <typename t, typename t1>
t max1(t a, t1 b) { return a > b ? a : b; }
template <typename t, typename... arg>
t max1(t a, arg... arr) { return max1(a, max1(arr...)); }
#endif

inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / max(abs1(a), abs1(b)) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t> inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}

// f_lb == 1代表返回相同的一串的左边界，f_small == 1代表返回如果没有寻找的值返回小的数
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	if(na == 0) return 0;
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}

template <class T> inline T lowb(T num) {return num & (-num); }
#ifdef GPP
inline int bitnum(ui nValue) { return __builtin_popcount(nValue); }
inline int bitnum(int nValue) { return __builtin_popcount(nValue); }
inline int bitnum(ull nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitnum(ll nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitmaxl(ui a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(int a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(ull a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
inline int bitmaxl(ll a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
#else
#endif

long long pow(long long n, long long m, long long mod = 0){
	if(m < 0) return 0;
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

#define  MOD 1000000007
template <class t1, class t2>
inline void add(t1 &a, t2 b, int mod = -1) {
	if(mod == -1) mod = MOD;
	a += b;
	while(a >= mod) a -= mod;
	while(a < 0) a += mod;
}
template <class t>
void output1(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		cerr << arr[i] << ' ';
	cerr << endl;
}
template <class t>
void output2(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		output1(arr[i]);
}

//....................密..........封..........线..........下..........禁..........止..........hack...............................................

const int maxn = 505000;
int dp[maxn], nxtdp[maxn][2];
int n, m;
struct link {
	int nxt, bef;
	bool exist;
} e[maxn * 2];
int head[maxn];
struct edge {
	int be, en, a, b;
	bool operator < (const edge &re) const {
		if (be == re.be) {
			return en < re.en;
		}
		return be < re.be;
	}
} alle[maxn];
priority_queue <pair <int, pii>, vector <pair <int, pii> >, greater <pair <int, pii> > > pq;

int findnxt(int no, int t, int cate) {
	for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
		int it = rit / 2;
		if (alle[it].be <= t) {
			t = max(alle[it].en - (alle[it].en % 2 != 2 - cate) * (cate != 3), t);
		} else break;
	}
	return t;
}

void addedge(int no, int i) {
	e[i].bef = -1;
	e[i].exist = 1;
	e[i].nxt = head[no];
	if (head[no] != -1) {
		e[head[no]].bef = i;
	}
	head[no] = i;
	e[i].exist = 1;
}

void deledge(int i) {
	if (e[i].bef != -1) {
		e[e[i].bef].nxt = e[i].nxt;
	} if (e[i].nxt != -1) {
		e[e[i].nxt].bef = e[i].bef;
	}
	e[i].exist = 0;
}

int getrcate(int cate) {
	if (cate == 3) return 3;
	else if(cate == 2) return 1;
	else if(cate == 1) return 2;
	else return 0;
}

void updrcate(int rcate, int nxtno, int t, int add) {
	if (((rcate | dp[nxtno]) ^ dp[nxtno]) >= 3) {
		cout << dp[nxtno] << ' ' << rcate << endl;
		exit(0);
	}
	if ((dp[nxtno] | rcate) > (dp[nxtno] | nxtdp[nxtno][add])) {
		pq.push(mpr(t, mpr(4 + rcate, nxtno)));
		nxtdp[nxtno][add] = rcate | dp[nxtno];
		pq.push(mpr(t + 1, mpr(0, nxtno)));
	}
}

int main() {

//............................不要再忘了检查maxn大小了！！！！BSBandme你个SB！！！！...................................................

	ios_base::sync_with_stdio(0);
	#ifdef DEBUG //......................................................................................................
	freopen("input.txt", "r", stdin);
	int __size__ = 256 << 20; // 256MB
	char *__p__ = (char*)malloc(__size__) + __size__;
	__asm__("movl %0, %%esp\n" :: "r"(__p__));
	#endif //...........................................................................................................

	scanf("%d%d", &n, &m);
	if (n == 1) {
		cout << 0 << endl;
		return 0;
	}
//	m = 499999;
//	n = 4;
	for (int i = 0; i < m; i++) {
		int a, b, l, r;
		scanf("%d%d%d%d", &a, &b, &l, &r);
		a--; b--;
//		a = i % 3, b = (i + 1) % 3, l = i * 1000, r = l + 3000;
//		if (i == m - 1) {
//			a = 0, b = 3, l = 500000000, r = l + 1;
//		}
		alle[i].a = a;
		alle[i].b = b;
		alle[i].be = l;
		alle[i].en = r;
	}
	sort(alle, alle + m);
	memset(head, -1, sizeof(head));
	for (int i = m - 1; i >= 0; i--) {
		addedge(alle[i].a, i * 2);
		addedge(alle[i].b, i * 2 + 1);
	}
	dp[0] = 2;
	pq.push(mpr(findnxt(0, 0, 2), mpr(3, 0)));
	for (int i = 0; i < m; i++) {
		pq.push(mpr(alle[i].be, mpr(-1, i)));
		pq.push(mpr(alle[i].en, mpr(1, i)));
	}
	if (pq.size() && pq.top().first != 0) {
		puts("-1");
		return 0;
	}
	for (; pq.size(); ) {
		int t = pq.top().first, cate = pq.top().second.first, no = pq.top().second.second;
		pq.pop();
		if (no == n - 1 && cate < 2 && cate != -1 && cate != 1) {
			printf("%d\n", t);
			return 0;
		}
		if (cate > 4) {
			dp[no] |= nxtdp[no][0];
			nxtdp[no][0] = nxtdp[no][1];
			nxtdp[no][1] = 0;
		} else if (cate > 1) {
			// delete no
			dp[no] &= 3 ^ (cate - 1);
		} else if (cate == 1) {
			// delete e
			deledge(no * 2);
			deledge(no * 2 + 1);
		} else if (cate == 0){
			// addno
			if (dp[no] != 3 && 2 - dp[no] != t % 2) {
				pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			int rt = findnxt(no, t, dp[no]);
			pq.push(mpr(rt, mpr(1 + dp[no], no)));
			int rcate = getrcate(dp[no]);
 			for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
 				int it = rit / 2;
 				if (alle[it].be <= t && alle[it].en > t) {
					int nxtno = alle[it].a + alle[it].b - no;
					updrcate(rcate, nxtno, t, 0);
 				} else if (alle[it].be > t) break;
 			}
		} else {
			// adde
			int a = alle[no].a, b = alle[no].b;
			if (dp[a] < dp[b]) swap(a, b);
			if ((dp[a] == 2 && dp[b] == 1) || (dp[a] == 1 && dp[b] == 2) ||
					(dp[a] == 3 && dp[b] == 3) || (dp[a] == 0 && dp[b] == 0)) {
				continue;
			}
			if ((t % 2 + 1 == dp[a] || dp[a] == 0) &&
				(t % 2 + 1 == dp[b] || dp[b] == 0) )
					{
				if (alle[no].en > t)
					pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			if (dp[a] == 3 && dp[b] == 0) {
				updrcate(t % 2 + 1, b, t, 0);
				if (findnxt(a, t, 3) > t)
					updrcate(2 - t % 2, b, t + 1, 1);
			} else {
				updrcate(getrcate(dp[a]), b, t, 0);
				updrcate(getrcate(dp[b]), a, t, 0);
			}
		}
	}
	printf("-1\n");

    return 0;
}


// #define DEBUG
//#define USEPB_DS
#define USETR1
#define CPPELEVEN
#define GPP

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <sstream>
#include <tuple>

using namespace std;

#ifndef CPPELEVEN
#ifdef USETR1
#include <tr1/unordered_map>
#include <tr1/unordered_set>
using namespace tr1;
#endif
#else
#include <unordered_map>
#include <unordered_set>
#endif

#ifdef USEPB_DS
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
// binomial_heap_tag, rc_binomial_heap_tag, thin_heap_tag, binary_heap_tag
typedef __gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> pq_type;
// splay_tree_tag, ov_tree_tag
typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> tree_type;
#endif

#define mpr make_pair
typedef unsigned int ui;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const long double eps = 1e-10;
const int step[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, 1}, {1, 1}, {1, -1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}

#ifndef CPPELEVEN
template <class T> inline T max1(T a, T b) { return b < a ? a : b; }
template <class T> inline T max1(T a, T b, T c) { return max1(max1(a, b), c); }
template <class T> inline T max1(T a, T b, T c, T d) { return max1(max1(a, b, c), d); }
template <class T> inline T max1(T a, T b, T c, T d, T e) { return max1(max1(a, b, c, d), e); }
template <class T> inline T min1(T a, T b) { return a < b ? a : b; }
template <class T> inline T min1(T a, T b, T c) { return min1(min1(a, b), c); }
template <class T> inline T min1(T a, T b, T c, T d) { return min1(min1(a, b, c), d); }
template <class T> inline T min1(T a, T b, T c, T d, T e) { return min1(min1(a, b, c, d), e); }
#else
template <typename t, typename t1>
t min1(t a, t1 b) { return a < b ? a : b; }
template <typename t, typename... arg>
t min1(t a, arg... arr) { return min1(a, min1(arr...)); }
template <typename t, typename t1>
t max1(t a, t1 b) { return a > b ? a : b; }
template <typename t, typename... arg>
t max1(t a, arg... arr) { return max1(a, max1(arr...)); }
#endif

inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / max(abs1(a), abs1(b)) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t> inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}

// f_lb == 1代表返回相同的一串的左边界，f_small == 1代表返回如果没有寻找的值返回小的数
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	if(na == 0) return 0;
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}

template <class T> inline T lowb(T num) {return num & (-num); }
#ifdef GPP
inline int bitnum(ui nValue) { return __builtin_popcount(nValue); }
inline int bitnum(int nValue) { return __builtin_popcount(nValue); }
inline int bitnum(ull nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitnum(ll nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitmaxl(ui a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(int a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(ull a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
inline int bitmaxl(ll a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
#else
#endif

long long pow(long long n, long long m, long long mod = 0){
	if(m < 0) return 0;
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

#define  MOD 1000000007
template <class t1, class t2>
inline void add(t1 &a, t2 b, int mod = -1) {
	if(mod == -1) mod = MOD;
	a += b;
	while(a >= mod) a -= mod;
	while(a < 0) a += mod;
}
template <class t>
void output1(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		cerr << arr[i] << ' ';
	cerr << endl;
}
template <class t>
void output2(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		output1(arr[i]);
}

//....................密..........封..........线..........下..........禁..........止..........hack...............................................

const int maxn = 505000;
int dp[maxn], nxtdp[maxn];
int n, m;
struct link {
	int nxt, bef;
	bool exist;
} e[maxn * 2];
int head[maxn];
struct edge {
	int be, en, a, b;
	bool operator < (const edge &re) const {
		if (be == re.be) {
			return en < re.en;
		}
		return be < re.be;
	}
} alle[maxn];
priority_queue <pair <int, pii>, vector <pair <int, pii> >, greater <pair <int, pii> > > pq;

int findnxt(int no, int t, int cate) {
	for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
		int it = rit / 2;
		if (alle[it].be <= t) {
			t = max(alle[it].en - (alle[it].en % 2 != 2 - cate) * (cate != 3), t);
		} else break;
	}
	return t;
}

void addedge(int no, int i) {
	e[i].bef = -1;
	e[i].exist = 1;
	e[i].nxt = head[no];
	if (head[no] != -1) {
		e[head[no]].bef = i;
	}
	head[no] = i;
	e[i].exist = 1;
}

void deledge(int i) {
	if (e[i].bef != -1) {
		e[e[i].bef].nxt = e[i].nxt;
	} if (e[i].nxt != -1) {
		e[e[i].nxt].bef = e[i].bef;
	}
	e[i].exist = 0;
}

int getrcate(int cate) {
	if (cate == 3) return 3;
	else if(cate == 2) return 1;
	else if(cate == 1) return 2;
	else return 0;
}

void updrcate(int rcate, int nxtno, int t) {
	if ((dp[nxtno] | rcate) > (dp[nxtno] | nxtdp[nxtno])) {
		pq.push(mpr(t, mpr(2 + rcate, nxtno)));
		nxtdp[nxtno] = rcate | dp[nxtno];
		pq.push(mpr(t + 1, mpr(0, nxtno)));
	}
}

int main() {

//............................不要再忘了检查maxn大小了！！！！BSBandme你个SB！！！！...................................................

	ios_base::sync_with_stdio(0);
	#ifdef DEBUG //......................................................................................................
	freopen("input.txt", "r", stdin);
	int __size__ = 256 << 20; // 256MB
	char *__p__ = (char*)malloc(__size__) + __size__;
	__asm__("movl %0, %%esp\n" :: "r"(__p__));
	#endif //...........................................................................................................

	scanf("%d%d", &n, &m);
	if (n == 1) {
		cout << 0 << endl;
		return 0;
	}
//	m = 499998;
//	n = 4;
	for (int i = 0; i < m; i++) {
		int a, b, l, r;
		scanf("%d%d%d%d", &a, &b, &l, &r);
		a--; b--;
//		a = i % 3, b = (i + 1) % 3, l = i * 1000, r = l + 3000;
		alle[i].a = a;
		alle[i].b = b;
		alle[i].be = l;
		alle[i].en = r;
	}
	sort(alle, alle + m);
	memset(head, -1, sizeof(head));
	for (int i = m - 1; i >= 0; i--) {
		addedge(alle[i].a, i * 2);
		addedge(alle[i].b, i * 2 + 1);
	}
	dp[0] = 2;
	pq.push(mpr(findnxt(0, 0, 2), mpr(2, 0)));
	for (int i = 0; i < m; i++) {
		pq.push(mpr(alle[i].be, mpr(-1, i)));
		pq.push(mpr(alle[i].en, mpr(1, i)));
	}
	if (pq.size() && pq.top().first != 0) {
		puts("-1");
		return 0;
	}
	for (; pq.size(); ) {
		int t = pq.top().first, cate = pq.top().second.first, no = pq.top().second.second;
		pq.pop();
		if (no == n - 1 && cate < 2 && cate != -1 && cate != 1) {
			printf("%d\n", t);
			return 0;
		}
		if (cate > 2) {
			dp[no] |= nxtdp[no];
			nxtdp[no] = 0;
		} else if (cate == 2) {
			// delete no
			dp[no] ^= 2 - (t % 2);
			int rt = findnxt(t, no, dp[no]);
			if (rt > t) {
				pq.push(mpr(rt, mpr(2, no)));
			}
		} else if (cate == 1) {
			// delete e
			deledge(no * 2);
			deledge(no * 2 + 1);
		} else if (cate == 0){
			// addno
			if (dp[no] != 3 && 2 - dp[no] != t % 2) {
				pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			int rt = findnxt(no, t, dp[no]);
			pq.push(mpr(rt, mpr(2, no)));
			int rcate = getrcate(dp[no]);
 			for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
 				int it = rit / 2;
 				if (alle[it].be <= t && alle[it].en > t) {
					int nxtno = alle[it].a + alle[it].b - no;
					updrcate(rcate, nxtno, t);
 				} else if (alle[it].be > t) break;
 			}
		} else {
			// adde
			int a = alle[no].a, b = alle[no].b;
			if (dp[a] < dp[b]) swap(a, b);
			if ((dp[a] == 2 && dp[b] == 1) || (dp[a] == 1 && dp[b] == 2) ||
					(dp[a] == 3 && dp[b] == 3) || (dp[a] == 0 && dp[b] == 0)) {
				continue;
			}
			if ((t % 2 + 1 == dp[a] || dp[a] == 0) &&
				(t % 2 + 1 == dp[b] || dp[b] == 0) )
					{
				if (alle[no].en > t)
					pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
//			if (dp[a] == 3 && dp[b] == 0) {
//				updrcate(t % 2 + 1, b, t);
//				if (findnxt(t, a, 3) > t)
//					updrcate(t % 2, b, t + 1);
//			} else {
				updrcate(getrcate(dp[a]), b, t);
				updrcate(getrcate(dp[b]), a, t);
			}
		}
	}
	printf("-1\n");

    return 0;
}


// #define DEBUG
//#define USEPB_DS
#define USETR1
#define CPPELEVEN
#define GPP

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <sstream>
#include <tuple>

using namespace std;

#ifndef CPPELEVEN
#ifdef USETR1
#include <tr1/unordered_map>
#include <tr1/unordered_set>
using namespace tr1;
#endif
#else
#include <unordered_map>
#include <unordered_set>
#endif

#ifdef USEPB_DS
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
// binomial_heap_tag, rc_binomial_heap_tag, thin_heap_tag, binary_heap_tag
typedef __gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> pq_type;
// splay_tree_tag, ov_tree_tag
typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> tree_type;
#endif

#define mpr make_pair
typedef unsigned int ui;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const long double eps = 1e-10;
const int step[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, 1}, {1, 1}, {1, -1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}

#ifndef CPPELEVEN
template <class T> inline T max1(T a, T b) { return b < a ? a : b; }
template <class T> inline T max1(T a, T b, T c) { return max1(max1(a, b), c); }
template <class T> inline T max1(T a, T b, T c, T d) { return max1(max1(a, b, c), d); }
template <class T> inline T max1(T a, T b, T c, T d, T e) { return max1(max1(a, b, c, d), e); }
template <class T> inline T min1(T a, T b) { return a < b ? a : b; }
template <class T> inline T min1(T a, T b, T c) { return min1(min1(a, b), c); }
template <class T> inline T min1(T a, T b, T c, T d) { return min1(min1(a, b, c), d); }
template <class T> inline T min1(T a, T b, T c, T d, T e) { return min1(min1(a, b, c, d), e); }
#else
template <typename t, typename t1>
t min1(t a, t1 b) { return a < b ? a : b; }
template <typename t, typename... arg>
t min1(t a, arg... arr) { return min1(a, min1(arr...)); }
template <typename t, typename t1>
t max1(t a, t1 b) { return a > b ? a : b; }
template <typename t, typename... arg>
t max1(t a, arg... arr) { return max1(a, max1(arr...)); }
#endif

inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / max(abs1(a), abs1(b)) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t> inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}

// f_lb == 1代表返回相同的一串的左边界，f_small == 1代表返回如果没有寻找的值返回小的数
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	if(na == 0) return 0;
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}

template <class T> inline T lowb(T num) {return num & (-num); }
#ifdef GPP
inline int bitnum(ui nValue) { return __builtin_popcount(nValue); }
inline int bitnum(int nValue) { return __builtin_popcount(nValue); }
inline int bitnum(ull nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitnum(ll nValue) { return __builtin_popcount(nValue) + __builtin_popcount(nValue >> 32); }
inline int bitmaxl(ui a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(int a) { if(a == 0) return 0; return 32 - __builtin_clz(a); }
inline int bitmaxl(ull a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
inline int bitmaxl(ll a) { int temp = a >> 32; if(temp) return 32 - __builtin_clz(temp) + 32; return bitmaxl(int(a)); }
#else
#endif

long long pow(long long n, long long m, long long mod = 0){
	if(m < 0) return 0;
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

#define  MOD 1000000007
template <class t1, class t2>
inline void add(t1 &a, t2 b, int mod = -1) {
	if(mod == -1) mod = MOD;
	a += b;
	while(a >= mod) a -= mod;
	while(a < 0) a += mod;
}
template <class t>
void output1(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		cerr << arr[i] << ' ';
	cerr << endl;
}
template <class t>
void output2(t arr) {
	for(int i = 0; i < (int)arr.size(); i++)
		output1(arr[i]);
}

//....................密..........封..........线..........下..........禁..........止..........hack...............................................

const int maxn = 505000;
int dp[maxn], nxtdp[maxn][2], tnxt[maxn][3];
int n, m;
struct link {
	int nxt, bef;
	bool exist;
} e[maxn * 2];
int head[maxn];
struct edge {
	int be, en, a, b;
	bool operator < (const edge &re) const {
		if (be == re.be) {
			return en < re.en;
		}
		return be < re.be;
	}
} alle[maxn];
priority_queue <pair <int, pii>, vector <pair <int, pii> >, greater <pair <int, pii> > > pq;

int findnxt(int no, int t, int cate) {
	for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
		int it = rit / 2;
		if (alle[it].be <= t) {
			t = max(alle[it].en - (alle[it].en % 2 != 2 - cate) * (cate != 3), t);
		} else break;
	}
	return t;
}

void addedge(int no, int i) {
	e[i].bef = -1;
	e[i].exist = 1;
	e[i].nxt = head[no];
	if (head[no] != -1) {
		e[head[no]].bef = i;
	}
	head[no] = i;
	e[i].exist = 1;
}

void deledge(int i) {
	if (e[i].bef != -1) {
		e[e[i].bef].nxt = e[i].nxt;
	} if (e[i].nxt != -1) {
		e[e[i].nxt].bef = e[i].bef;
	}
	e[i].exist = 0;
}

int getrcate(int cate) {
	if (cate == 3) return 3;
	else if(cate == 2) return 1;
	else if(cate == 1) return 2;
	else return 0;
}

void updrcate(int rcate, int nxtno, int t, int add) {
	if (((rcate | dp[nxtno]) ^ dp[nxtno]) >= 3) {
		cout << dp[nxtno] << ' ' << rcate << endl;
		exit(0);
	}
	if ((dp[nxtno] | rcate) > (dp[nxtno] | nxtdp[nxtno][add])) {
		if(((rcate | dp[nxtno]) ^ dp[nxtno]) != t % 2 + 1) {
			cout << dp[nxtno] << ' ' << rcate << ' ' << t;
			exit(0);
		}
		pq.push(mpr(t, mpr(4 + rcate, nxtno)));
		nxtdp[nxtno][add] = rcate;
		pq.push(mpr(t + 1, mpr(0, nxtno)));
	}
}

void add(int no1, int eno, int no, int t) {
	int more = getrcate(dp[no1]) | dp[no];
	more ^= dp[no];
	if ((more & (t % 2 + 1)) && alle[eno].en > t)
		updrcate(more & (t % 2 + 1), no, t, 0);
	if ((more & (2 - t % 2)) && alle[eno].en > t + 1 && tnxt[no1][more & (2 - t % 2)] > t)
		updrcate(more & (2 - t % 2), no, t + 1, 1);
}

int main() {

//............................不要再忘了检查maxn大小了！！！！BSBandme你个SB！！！！...................................................

	ios_base::sync_with_stdio(0);
	#ifdef DEBUG //......................................................................................................
	freopen("input.txt", "r", stdin);
	int __size__ = 256 << 20; // 256MB
	char *__p__ = (char*)malloc(__size__) + __size__;
	__asm__("movl %0, %%esp\n" :: "r"(__p__));
	#endif //...........................................................................................................

	scanf("%d%d", &n, &m);
	if (n == 1) {
		cout << 0 << endl;
		return 0;
	}
//	m = 499999;
//	n = 4;
	for (int i = 0; i < m; i++) {
		int a, b, l, r;
		scanf("%d%d%d%d", &a, &b, &l, &r);
		a--; b--;
//		a = i % 3, b = (i + 1) % 3, l = i * 1000, r = l + 3000;
//		if (i == m - 1) {
//			a = 0, b = 3, l = 500000000, r = l + 1;
//		}
		alle[i].a = a;
		alle[i].b = b;
		alle[i].be = l;
		alle[i].en = r;
	}
	sort(alle, alle + m);
	memset(head, -1, sizeof(head));
	for (int i = m - 1; i >= 0; i--) {
		addedge(alle[i].a, i * 2);
		addedge(alle[i].b, i * 2 + 1);
	}
	dp[0] = 2;
	pq.push(mpr(findnxt(0, 0, 2), mpr(3, 0)));
	for (int i = 0; i < m; i++) {
		pq.push(mpr(alle[i].be, mpr(-1, i)));
		pq.push(mpr(alle[i].en, mpr(1, i)));
	}
	if (pq.size() && pq.top().first != 0) {
		puts("-1");
		return 0;
	}
	for (; pq.size(); ) {
		int t = pq.top().first, cate = pq.top().second.first, no = pq.top().second.second;
		pq.pop();
		if (no == n - 1 && cate < 2 && cate != -1 && cate != 1) {
			printf("%d\n", t);
			return 0;
		}
		if (cate > 4) {
			dp[no] |= nxtdp[no][0];
			nxtdp[no][0] = nxtdp[no][1];
			nxtdp[no][1] = 0;
		} else if (cate > 1) {
			// delete no
			assert(dp[no] & (cate - 1));
			dp[no] &= 3 ^ (cate - 1);
		} else if (cate == 1) {
			// delete e
			deledge(no * 2);
			deledge(no * 2 + 1);
		} else if (cate == 0){
			// addno
			if (dp[no] != 3 && 2 - dp[no] != t % 2) {
				pq.push(mpr(t + 1, mpr(0, no)));
				continue;
			}
			assert(dp[no] & (2 - (t % 2)));
			int rt = findnxt(no, t, (2 - (t % 2)));
			tnxt[no][2 - t % 2] = rt;
			pq.push(mpr(rt, mpr(1 + (2 - t % 2), no)));
 			for (int rit = head[no]; rit != -1; rit = e[rit].nxt) {
 				int it = rit / 2;
 				if (alle[it].be <= t ) {
					int nxtno = alle[it].a + alle[it].b - no;
					add(no, it, nxtno, t);
 				} else break;
 			}
		} else {
			// adde
			int a = alle[no].a, b = alle[no].b;
			if (dp[a] < dp[b]) swap(a, b);
			if ((dp[a] == 2 && dp[b] == 1) || (dp[a] == 1 && dp[b] == 2) ||
					(dp[a] == 3 && dp[b] == 3) || (dp[a] == 0 && dp[b] == 0)) {
				continue;
			}
			if ((t % 2 + 1 == dp[a] || dp[a] == 0) &&
				(t % 2 + 1 == dp[b] || dp[b] == 0) )
					{
				if (alle[no].en > t)
					pq.push(mpr(t + 1, mpr(-1, no)));
				continue;
			}
			add(a, no, b, t);
			add(b, no, a, t);
		}
	}
	printf("-1\n");

    return 0;
}