#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int _=1e2;
const int maxn=5e5+_;
inline int read()
{
	int x=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return x;
}

struct edge{int x,y,l,r;edge(){}edge(int X,int Y,int L,int R){x=X,y=Y,l=L,r=R;}};
struct cmp{bool operator()(const edge &x,const edge &y)const{return x.l<y.l;}};
priority_queue<edge,vector<edge>,cmp>q;

struct node{int y,r,next;}a[4*maxn];int len,last[2][maxn];
void ins(int op,int x,int y,int r){a[++len].y=y;a[len].r=r;a[len].next=last[op][x];last[op][x]=len;}
int f[2][maxn];
int main()
{
	int n,m,x,y,l,r; edge p;
	n=read(),m=read();
	if(n==1){puts("0");return 0;}
	for(int i=1;i<=m;i++)
	{
		x=read(),y=read(),l=read(),r=read()-1;
		if(l==r)q.push(edge(x,y,l,r)),q.push(edge(y,x,l,r));
		else
		{
			p=edge(x,y,l,r-(r-l)%2); q.push(p);
			p=edge(y,x,l,r-(r-l)%2); q.push(p);
			p=edge(x,y,l+1,r-(r-l-1)%2); q.push(p);
			p=edge(y,x,l+1,r-(r-l-1)%2); q.push(p);
		}
	}

	memset(f,-63,sizeof(f));f[0][1]=0;
	while(!q.empty())
	{
		p=q.top(); q.pop();
		int x=p.x,y=p.y,op=p.l&1;
		if(f[op][x]>=p.l)
		{
			if(y==n)
				{printf("%d\n",p.l+1);return 0;}

			f[op^1][y]=max(f[op^1][y],p.r+1);
			for(int k=last[op^1][y];k;k=a[k].next)
				if(p.l+1<=a[k].r)q.push(edge(y,a[k].y,p.l+1,a[k].r));
			last[op^1][y]=0;
		}
		else ins(op,x,y,p.r);
	}
	puts("-1");

	return 0;
}


#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int _=1e2;
const int maxn=5e5+_;
inline int read()
{
	int x=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return x;
}

struct edge{int x,y,l,r;edge(){}edge(int X,int Y,int L,int R){x=X,y=Y,l=L,r=R;}};
struct cmp{bool operator()(const edge &x,const edge &y)const{return x.l<y.l;}};
priority_queue<edge,vector<edge>,cmp>q;

struct node{int y,r,next;}a[4*maxn];int len,last[2][maxn];
void ins(int op,int x,int y,int r){a[++len].y=y;a[len].r=r;a[len].next=last[op][x];last[op][x]=len;}
int f[2][maxn];
int main()
{
	int n,m,x,y,l,r; edge p;
	scanf("%d%d",&n,&m);
	if(n==1){puts("0");return 0;}
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&x,&y,&l,&r); r--;
		if(l==r)q.push(edge(x,y,l,r)),q.push(edge(y,x,l,r));
		else
		{
			p=edge(x,y,l,r-(r-l)%2); q.push(p);
			p=edge(y,x,l,r-(r-l)%2); q.push(p);
			p=edge(x,y,l+1,r-(r-l-1)%2); q.push(p);
			p=edge(x,y,l+1,r-(r-l-1)%2); q.push(p);
		}
	}

	memset(f,-63,sizeof(f));f[0][1]=0;
	while(!q.empty())
	{
		p=q.top(); q.pop();
		int x=p.x,y=p.y,op=p.l&1;
		if(f[op][x]>=p.l)
		{
			if(y==n)
				{printf("%d\n",p.l+1);return 0;}

			f[op^1][y]=max(f[op^1][y],p.r+1);
			for(int k=last[op^1][y];k;k=a[k].next)
				if(p.l+1<=a[k].r)q.push(edge(y,a[k].y,p.l+1,a[k].r));
			last[op^1][y]=0;
		}
		else ins(op,x,y,p.r);
	}
	puts("-1");

	return 0;
}


#include <cstdio>
#include <cstring>
#include <queue>
#include <tuple>
#include <vector>
#include <algorithm>

const int N = 500000 + 10, INF = 0x3f3f3f3f;

int n, m;

std::vector<std::tuple<int, int, int>> edge;
std::vector<int> adj[N][2];

int dist[N];

void init() {
  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);
    int x = l, y = l + 1;
    if (x & 1) std::swap(x, y);
    adj[a][0].push_back(edge.size()), edge.emplace_back(b, x, r);
    adj[a][1].push_back(edge.size()), edge.emplace_back(b, y, r);
    adj[b][0].push_back(edge.size()), edge.emplace_back(a, x, r);
    adj[b][1].push_back(edge.size()), edge.emplace_back(a, y, r);
  }
  for (int i = 1; i <= n; ++i)
    for (int j = 0; j < 2; ++j)
      std::sort(adj[i][j].begin(), adj[i][j].end(), [&] (int lhs, int rhs) { return std::get<1>(edge[lhs]) > std::get<1>(edge[rhs]); });
}

int main() {
  init();
  if (n == 1) return puts("0"), 0;
  memset(dist, 0x3f, sizeof dist);
  std::queue<int> q;
  for (auto i : adj[1][0]) if (!std::get<1>(edge[i])) q.push(i), dist[i] = 0;
  for (; !q.empty(); q.pop()) {
    int u = q.front();
    int a, b, c;
    std::tie(a, b, c) = edge[u];
    int w = dist[u] + 1;
    for (auto &cur = adj[a][w & 1]; !cur.empty(); cur.pop_back()) {
      int v = cur.back(), x, y, z;
      std::tie(x, y, z) = edge[v];
      if (z <= w) continue;
      if (y > w) break;
      if (dist[v] == INF) {
        q.push(v);
        dist[v] = std::max(w, y);
      }
    }
  }
  int ans = INF;
  for (int i = 0; i < edge.size(); ++i) if (std::get<0>(edge[i]) == n) ans = std::min(ans, dist[i] + 1);
  printf("%d\n", ans == INF ? -1 : ans);
  return 0;
}


#include <cstdio>
#include <cstring>
#include <queue>
#include <tuple>
#include <vector>
#include <algorithm>

const int N = 500000 + 10, INF = 0x3f3f3f3f;

int n, m;

std::vector<std::tuple<int, int, int>> edge;
std::vector<int> adj[N][2];

void link(int a, int b, int l, int r, int c) {
  if ((l & 1) != c) ++l;
  --r;
  if ((r & 1) != c) --r;
  if (l > r) return;
  adj[a][c].push_back(edge.size());
  edge.emplace_back(b, l, r);
}

int dist[N];

void init() {
  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);
    int x = l, y = l + 1;
    if (x & 1) std::swap(x, y);
    link(a, b, l, r, 0);
    link(a, b, l, r, 1);
    link(b, a, l, r, 0);
    link(b, a, l, r, 1);
  }
  for (int i = 1; i <= n; ++i)
    for (int j = 0; j < 2; ++j)
      std::sort(adj[i][j].begin(), adj[i][j].end(), [&] (int lhs, int rhs) { return std::get<1>(edge[lhs]) > std::get<1>(edge[rhs]); });
}

int main() {
  init();
  if (n == 1) return puts("0"), 0;
  memset(dist, 0x3f, sizeof dist);
  std::priority_queue<std::pair<int, int>> heap;
  for (auto i : adj[1][0]) if (!std::get<1>(edge[i])) heap.emplace(dist[i] = 0, i);
  while (!heap.empty()) {
    auto info = heap.top();
    heap.pop();
    int u = info.second;
    if (-info.first > dist[u]) continue;
    int a, b, c;
    std::tie(a, b, c) = edge[u];
    int w = dist[u] + 1;
    for (auto &cur = adj[a][w & 1]; !cur.empty(); cur.pop_back()) {
      int v = cur.back(), x, y, z;
      std::tie(x, y, z) = edge[v];
      if (z < w) continue;
      if (y > c + 1) break;
      int d = std::max(w, y);
      if (dist[v] > d) heap.emplace(-(dist[v] = d), v);
    }
  }
  int ans = INF;
  for (int i = 0; i < edge.size(); ++i) if (std::get<0>(edge[i]) == n) ans = std::min(ans, dist[i] + 1);
  printf("%d\n", ans == INF ? -1 : ans);
  return 0;
}


#include <cstdio>
#include <cstring>
#include <queue>
#include <tuple>
#include <vector>
#include <algorithm>

const int N = 500000 + 10, INF = 0x3f3f3f3f;

int n, m;

std::vector<std::tuple<int, int, int>> edge;
std::vector<int> adj[N][2];

int dist[N];

void init() {
  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);
    int x = l, y = l + 1;
    if (x & 1) std::swap(x, y);
    adj[a][0].push_back(edge.size()), edge.emplace_back(b, x, r);
    adj[a][1].push_back(edge.size()), edge.emplace_back(b, y, r);
    adj[b][0].push_back(edge.size()), edge.emplace_back(a, x, r);
    adj[b][1].push_back(edge.size()), edge.emplace_back(a, y, r);
  }
  for (int i = 1; i <= n; ++i)
    for (int j = 0; j < 2; ++j)
      std::sort(adj[i][j].begin(), adj[i][j].end(), [&] (int lhs, int rhs) { return std::get<1>(edge[lhs]) > std::get<1>(edge[rhs]); });
}

int main() {
  init();
  memset(dist, 0x3f, sizeof dist);
  std::queue<int> q;
  for (auto i : adj[1][0]) if (!std::get<1>(edge[i])) q.push(i), dist[i] = 0;
  for (; !q.empty(); q.pop()) {
    int u = q.front();
    int a, b, c;
    std::tie(a, b, c) = edge[u];
    int w = dist[u] + 1;
    for (auto &cur = adj[a][w & 1]; !cur.empty(); cur.pop_back()) {
      int v = cur.back(), x, y, z;
      std::tie(x, y, z) = edge[v];
      if (z <= w) continue;
      if (y > w) break;
      if (dist[v] == INF) {
        q.push(v);
        dist[v] = std::max(w, y);
      }
    }
  }
  int ans = INF;
  for (int i = 0; i < edge.size(); ++i) if (std::get<0>(edge[i]) == n) ans = std::min(ans, dist[i] + 1);
  printf("%d\n", ans == INF ? -1 : ans);
  return 0;
}


#include <cstdio>
#include <cstring>
#include <queue>
#include <tuple>
#include <vector>
#include <algorithm>

const int N = 500000 + 10, INF = 0x3f3f3f3f;

int n, m;

std::vector<std::tuple<int, int, int>> edge;
std::vector<int> adj[N][2];

int dist[N];

void init() {
  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);
    int x = l, y = l + 1;
    if (x & 1) std::swap(x, y);
    adj[a][0].push_back(edge.size()), edge.emplace_back(b, x, r);
    adj[a][1].push_back(edge.size()), edge.emplace_back(b, y, r);
    adj[b][0].push_back(edge.size()), edge.emplace_back(a, x, r);
    adj[b][1].push_back(edge.size()), edge.emplace_back(a, y, r);
  }
  for (int i = 1; i <= n; ++i)
    for (int j = 0; j < 2; ++j)
      std::sort(adj[i][j].begin(), adj[i][j].end(), [&] (int lhs, int rhs) { return std::get<1>(edge[lhs]) > std::get<1>(edge[rhs]); });
}

int main() {
  init();
  if (n == 1) return puts("0"), 0;
  memset(dist, 0x3f, sizeof dist);
  std::priority_queue<std::pair<int, int>> heap;
  for (auto i : adj[1][0]) if (!std::get<1>(edge[i])) heap.emplace(dist[i] = 0, i);
  while (!heap.empty()) {
    auto info = heap.top();
    heap.pop();
    int u = info.second;
    if (-info.first > dist[u]) continue;
    int a, b, c;
    std::tie(a, b, c) = edge[u];
    int w = dist[u] + 1;
    for (auto &cur = adj[a][w & 1]; !cur.empty(); cur.pop_back()) {
      int v = cur.back(), x, y, z;
      std::tie(x, y, z) = edge[v];
      if (z <= w) continue;
      if (y > w) break;
      if (dist[v] == INF) heap.emplace(-(dist[v] = std::max(w, y)), v);
    }
  }
  int ans = INF;
  for (int i = 0; i < edge.size(); ++i) if (std::get<0>(edge[i]) == n) ans = std::min(ans, dist[i] + 1);
  printf("%d\n", ans == INF ? -1 : ans);
  return 0;
}


#include <cstdio>
#include <cstring>
#include <queue>
#include <tuple>
#include <vector>
#include <algorithm>

const int N = 500000 + 10, INF = 0x3f3f3f3f;

int n, m;

std::vector<std::tuple<int, int, int>> edge;
std::vector<int> adj[N][2];

void link(int a, int b, int l, int r, int c) {
  if ((l & 1) != c) ++l;
  --r;
  if ((r & 1) != c) --r;
  if (l > r) return;
  adj[a][c].push_back(edge.size());
  edge.emplace_back(b, l, r);
}

int dist[4 * N];

void init() {
  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);
    int x = l, y = l + 1;
    if (x & 1) std::swap(x, y);
    link(a, b, l, r, 0);
    link(a, b, l, r, 1);
    link(b, a, l, r, 0);
    link(b, a, l, r, 1);
  }
  for (int i = 1; i <= n; ++i)
    for (int j = 0; j < 2; ++j)
      std::sort(adj[i][j].begin(), adj[i][j].end(), [&] (int lhs, int rhs) { return std::get<1>(edge[lhs]) > std::get<1>(edge[rhs]); });
}

int main() {
  init();
  if (n == 1) return puts("0"), 0;
  memset(dist, 0x3f, sizeof dist);
  std::priority_queue<std::pair<int, int>> heap;
  for (auto i : adj[1][0]) if (!std::get<1>(edge[i])) heap.emplace(dist[i] = 0, i);
  while (!heap.empty()) {
    auto info = heap.top();
    heap.pop();
    int u = info.second;
    if (-info.first > dist[u]) continue;
    int a, b, c;
    std::tie(a, b, c) = edge[u];
    int w = dist[u] + 1;
    for (auto &cur = adj[a][w & 1]; !cur.empty(); cur.pop_back()) {
      int v = cur.back(), x, y, z;
      std::tie(x, y, z) = edge[v];
      if (z < w) continue;
      if (y > c + 1) break;
      int d = std::max(w, y);
      if (dist[v] > d) heap.emplace(-(dist[v] = d), v);
    }
  }
  int ans = INF;
  for (int i = 0; i < edge.size(); ++i) if (std::get<0>(edge[i]) == n) ans = std::min(ans, dist[i] + 1);
  printf("%d\n", ans == INF ? -1 : ans);
  return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <ctype.h>
#include <deque>
#include <queue>
#include <cstring>
#include <set>
#include <list>
#include <map>
#include <random>
#include <unordered_map>
#include <stdio.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef std::vector<int> vi;
typedef std::vector<bool> vb;
typedef std::vector<string> vs;
typedef std::vector<double> vd;
typedef std::vector<long long> vll;
typedef std::vector<std::vector<int> > vvi;
typedef vector<vll> vvll;
typedef std::vector<std::pair<int, int> > vpi;
typedef vector<vpi> vvpi;
typedef std::pair<int, int> pi;
typedef std::pair<ll, ll> pll;
typedef std::vector<pll> vpll;

const long long mod = 1000000007;

#define all(c) (c).begin(),(c).end()
#define forn(i, a, b) for(int i = a; i < b; i++)

#define pb push_back
#define mp make_pair

vector<pair<pi, int>> e[1000000];
int pt[1000000];
vi l,r;

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.txt", "rt", stdin);
    freopen("output.txt", "wt", stdout);
#endif
    const int INF = 2e9;
    int n,m;
    scanf("%d %d", &n, &m);
    vi tmin(n, INF);
    l.resize(m);
    r.resize(m);
    vi t(2*n, -1);
    t[0] = 0;
    set<pi> ev;
    ev.insert(mp(0,0));
    forn(i,0,m) {
        int u,v;
        scanf("%d %d %d %d", &u, &v, &l[i], &r[i]);
        u--; v--;
        e[2*u].pb(mp(mp(l[i], r[i]), 2*v+1));
        e[2*u+1].pb(mp(mp(l[i], r[i]), 2*v));
        e[2*v].pb(mp(mp(l[i], r[i]), 2*u+1));
        e[2*v+1].pb(mp(mp(l[i], r[i]), 2*u));
    }
    forn(i,0,2*n) sort(all(e[i]));
    while(!ev.empty()) {
        int v = ev.begin() -> second;
        int curt = ev.begin() -> first;
        tmin[v/2] = min(tmin[v/2], curt);
        ev.erase(ev.begin());
        while(pt[v] < e[v].size() && e[v][pt[v]].first.first <= t[v]) {
            auto x = e[v][pt[v]];
            pt[v]++;
            int tgo = max(curt, x.first.first);
            if(tgo % 2 != curt % 2) tgo++;
            if(tgo >= x.first.second) continue;
            int nt = tgo+1;
            int to = x.second;
            ev.insert(mp(nt, to));
            t[to] = max(t[to], x.first.second);
            if(t[to]%2 != nt%2) t[to]--;
        }
    }
    int ans = tmin[n-1];
    if(ans == INF) ans = -1;
    cout<<ans;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <ctype.h>
#include <deque>
#include <queue>
#include <cstring>
#include <set>
#include <list>
#include <map>
#include <random>
#include <unordered_map>
#include <stdio.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef std::vector<int> vi;
typedef std::vector<bool> vb;
typedef std::vector<string> vs;
typedef std::vector<double> vd;
typedef std::vector<long long> vll;
typedef std::vector<std::vector<int> > vvi;
typedef vector<vll> vvll;
typedef std::vector<std::pair<int, int> > vpi;
typedef vector<vpi> vvpi;
typedef std::pair<int, int> pi;
typedef std::pair<ll, ll> pll;
typedef std::vector<pll> vpll;

const long long mod = 1000000007;

#define all(c) (c).begin(),(c).end()
#define forn(i, a, b) for(int i = a; i < b; i++)

#define pb push_back
#define mp make_pair

deque<pair<pi, int>> e[1000000];
vi l,r;

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.txt", "rt", stdin);
    freopen("output.txt", "wt", stdout);
#endif
    const int INF = 2e9;
    int n,m;
    scanf("%d %d", &n, &m);
    vi tmin(n, INF);
    l.resize(m);
    r.resize(m);
    vi t(2*n, -1);
    t[0] = 0;
    set<pi> ev;
    ev.insert(mp(0,0));
    forn(i,0,m) {
        int u,v;
        scanf("%d %d %d %d", &u, &v, &l[i], &r[i]);
        u--; v--;
        e[2*u].pb(mp(mp(l[i], r[i]), 2*v+1));
        e[2*u+1].pb(mp(mp(l[i], r[i]), 2*v));
        e[2*v].pb(mp(mp(l[i], r[i]), 2*u+1));
        e[2*v+1].pb(mp(mp(l[i], r[i]), 2*u));
    }
    forn(i,0,2*n) sort(all(e[i]));
    while(!ev.empty()) {
        int v = ev.begin() -> second;
        int curt = ev.begin() -> first;
        tmin[v/2] = min(tmin[v/2], curt);
        ev.erase(ev.begin());
        while(!e[v].empty() && e[v][0].first.first <= t[v]) {
            auto x = e[v][0];
            e[v].pop_front();
            int tgo = max(curt, x.first.first);
            if(tgo % 2 != curt % 2) tgo++;
            if(tgo >= x.first.second) continue;
            int nt = tgo+1;
            int to = x.second;
            ev.insert(mp(nt, to));
            t[to] = max(t[to], x.first.second);
            if(t[to]%2 != nt%2) t[to]--;
        }
    }
    int ans = tmin[n-1];
    if(ans == INF) ans = -1;
    cout<<ans;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <ctype.h>
#include <deque>
#include <queue>
#include <cstring>
#include <set>
#include <list>
#include <map>
#include <random>
#include <unordered_map>
#include <stdio.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef std::vector<int> vi;
typedef std::vector<bool> vb;
typedef std::vector<string> vs;
typedef std::vector<double> vd;
typedef std::vector<long long> vll;
typedef std::vector<std::vector<int> > vvi;
typedef vector<vll> vvll;
typedef std::vector<std::pair<int, int> > vpi;
typedef vector<vpi> vvpi;
typedef std::pair<int, int> pi;
typedef std::pair<ll, ll> pll;
typedef std::vector<pll> vpll;

const long long mod = 1000000007;

#define all(c) (c).begin(),(c).end()
#define forn(i, a, b) for(int i = a; i < b; i++)

#define pb push_back
#define mp make_pair

deque<pair<pi, int>> e[100];
vi l,r;

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.txt", "rt", stdin);
    freopen("output.txt", "wt", stdout);
#endif
    const int INF = 2e9;
    int n,m;
    scanf("%d %d", &n, &m);
    vi tmin(n, INF);
    l.resize(m);
    r.resize(m);
    vi t(2*n, -1);
    t[0] = 0;
    set<pi> ev;
    ev.insert(mp(0,0));
    forn(i,0,m) {
        int u,v;
        scanf("%d %d %d %d", &u, &v, &l[i], &r[i]);
        u--; v--;
        e[2*u].pb(mp(mp(l[i], r[i]), 2*v+1));
        e[2*u+1].pb(mp(mp(l[i], r[i]), 2*v));
        e[2*v].pb(mp(mp(l[i], r[i]), 2*u+1));
        e[2*v+1].pb(mp(mp(l[i], r[i]), 2*u));
    }
    forn(i,0,2*n) sort(all(e[i]));
    while(!ev.empty()) {
        int v = ev.begin() -> second;
        int curt = ev.begin() -> first;
        tmin[v/2] = min(tmin[v/2], curt);
        ev.erase(ev.begin());
        while(!e[v].empty() && e[v][0].first.first <= t[v]) {
            auto x = e[v][0];
            e[v].pop_front();
            int tgo = max(curt, x.first.first);
            if(tgo % 2 != curt % 2) tgo++;
            if(tgo >= x.first.second) continue;
            int nt = tgo+1;
            int to = x.second;
            ev.insert(mp(nt, to));
            t[to] = max(t[to], x.first.second);
            if(t[to]%2 != nt%2) t[to]--;
        }
    }
    int ans = tmin[n-1];
    if(ans == INF) ans = -1;
    cout<<ans;
}


#include<cstdio>
#include<queue>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;

const int NMAX = 500000;

struct edge{
    int from, to, st, ed;
};

vector<edge> edges;

struct event{
    int t, id;
    bool add;
    bool operator<(const event& rhs) const{
        if(t!=rhs.t) return t<rhs.t;
        if(add!=rhs.add) return add;
        return id<rhs.id;
    }
    bool operator>(const event& rhs) const{
        return rhs<(*this);
    }
};

int dp[NMAX*4+1];
int last[NMAX*4+1];
vector<int> pending[NMAX*2];
multiset<int> times[NMAX*2+1];

int main(){
    int N, M; scanf("%d%d",&N,&M);
    for(int i=0;i<M;i++){
        int u,v,s,e; scanf("%d%d%d%d",&u,&v,&s,&e);
        u--, v--;
        for(int it=0;it<2;it++,swap(u,v)){
            for(int dt=0;dt<2;dt++){
                int st = s+dt;
                if(st<e){
                    if(st&1) edges.push_back({u+N,v,st,e});
                    else edges.push_back({u,v+N,st,e});
                }
            }
        }
    }

    edges.push_back({N+N,0,-1,0});

    priority_queue<event,vector<event>,greater<event>> pq;
    M = edges.size();
    for(int i=0;i<M;i++){
        const edge& e = edges[i];
        pq.push({e.st, i, true});
    }
    times[N+N].insert(-1);
    const int INF = 0x3fFFffFF;
    for(int i=0;i<M;i++) dp[i] = INF;

    while(!pq.empty()){
        const auto ev = pq.top(); pq.pop();
        const auto& e = edges[ev.id];
        if(ev.add){
            if(ev.t >= e.ed) continue;
            if(!times[e.from].empty()){
                int t0 = *times[e.from].begin();
                if(t0 <= ev.t){
                    dp[ev.id] = min(dp[ev.id], ev.t);
                    last[ev.id] = ev.t;
                    times[e.to].insert(ev.t+1);
                    pq.push({e.ed, ev.id, false});

                    for(const auto& p:pending[e.to])
                        pq.push({ev.t+1, p, true});
                    pending[e.to].clear();
                }
                else{
                    pq.push({t0, ev.id, true});
                }
            }
            else{
                pending[e.from].push_back(ev.id);
            }
        }
        else{
            times[e.to].erase(times[e.to].find(last[ev.id]+1));
        }
    }

    int ans = INF;
    for(int i=0;i<M;i++) if(edges[i].to == N-1 || edges[i].to == N+N-1)
        ans = min(ans, dp[i]);

    printf("%d", ans<INF ? ans+1 : -1);
}


#include<cstdio>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;

const int NMAX = 500000;

struct edge{
    int from, to, st, ed;
};

vector<edge> edges;

struct event{
    int t, id;
    bool add;
    bool operator<(const event& rhs) const{
        if(t!=rhs.t) return t<rhs.t;
        return add;
    }
};

vector<event> events;

int dp[NMAX*4];
set<int> back[NMAX*2];

int main(){
    int N, M; scanf("%d%d",&N,&M);
    for(int i=0;i<M;i++){
        int u,v,s,e; scanf("%d%d%d%d",&u,&v,&s,&e);
        u--, v--;
        if(e==s+1){ // only two edges
            if(s%2){
                edges.push_back({u+N,v,s,e});
                edges.push_back({v+N,u,s,e});
            }
            else{
                edges.push_back({u,v+N,s,e});
                edges.push_back({v,u+N,s,e});
            }
        }
        else{
            if(s%2){
                edges.push_back({u+N,v,s,e});
                edges.push_back({u,v+N,s+1,e});
                edges.push_back({v+N,u,s,e});
                edges.push_back({v,u+N,s+1,e});
            }
            else{
                edges.push_back({u,v+N,s,e});
                edges.push_back({u+N,v,s+1,e});
                edges.push_back({v,u+N,s,e});
                edges.push_back({v+N,u,s+1,e});
            }
        }
    }

    M = edges.size();
    for(int i=0;i<M;i++){
        const edge& e = edges[i];
        events.push_back({e.st, i, true});
        events.push_back({e.ed, i, false});
    }
    events.push_back({1,-1,false});
    sort(events.begin(), events.end());

    const int INF = 0x3fFFffFF;
    for(int i=0;i<M;i++) dp[i] = INF;

    back[0].insert(-1);

    for(const event& ev:events){
        if(ev.id==-1){
            back[0].erase(-1);
            continue;
        }
        const edge& e = edges[ev.id];
        if(!ev.add){
            back[e.to].erase(ev.id);
        }
        else if(!back[e.from].empty()){
            dp[ev.id] = ev.t;
            back[e.to].insert(ev.id);
        }
    }

    int ans = INF;
    for(int i=0;i<M;i++) if(edges[i].to == N-1 || edges[i].to == N+N-1){
        ans = min(ans, dp[i]);
    }
    printf("%d", ans < INF ? ans+1 : -1);
}


#include<cstdio>
#include<queue>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;

const int NMAX = 500000;

struct edge{
    int from, to, st, ed;
};

vector<edge> edges;

struct event{
    int t, id;
    bool add;
    bool operator<(const event& rhs) const{
        if(t!=rhs.t) return t<rhs.t;
        if(add!=rhs.add) return add;
        return id<rhs.id;
    }
    bool operator>(const event& rhs) const{
        return rhs<(*this);
    }
};

int dp[NMAX*4];
int last[NMAX*4];
vector<int> pending[NMAX*2];
multiset<int> times[NMAX*2+1];

int main(){
    int N, M; scanf("%d%d",&N,&M);
    for(int i=0;i<M;i++){
        int u,v,s,e; scanf("%d%d%d%d",&u,&v,&s,&e);
        u--, v--;
        for(int it=0;it<2;it++,swap(u,v)){
            for(int dt=0;dt<2;dt++){
                int st = s+dt;
                if(st<e){
                    if(st&1) edges.push_back({u+N,v,st,e});
                    else edges.push_back({u,v+N,st,e});
                }
            }
        }
    }

    edges.push_back({N+N,0,-1,0});

    priority_queue<event,vector<event>,greater<event>> pq;
    M = edges.size();
    for(int i=0;i<M;i++){
        const edge& e = edges[i];
        pq.push({e.st, i, true});
    }
    times[N+N].insert(-1);
    const int INF = 0x3fFFffFF;
    for(int i=0;i<M;i++) dp[i] = INF;

    while(!pq.empty()){
        const auto ev = pq.top(); pq.pop();
        const auto& e = edges[ev.id];
        if(ev.add){
            if(ev.t >= e.ed) continue;
            if(!times[e.from].empty()){
                int t0 = *times[e.from].begin();
                if(t0 <= ev.t){
                    dp[ev.id] = min(dp[ev.id], ev.t);
                    last[ev.id] = ev.t;
                    times[e.to].insert(ev.t+1);
                    pq.push({e.ed, ev.id, false});

                    for(const auto& p:pending[e.to])
                        pq.push({ev.t+1, p, true});
                    pending[e.to].clear();
                }
                else{
                    pq.push({t0, ev.id, true});
                }
            }
            else{
                pending[e.from].push_back(ev.id);
            }
        }
        else{
            times[e.to].erase(times[e.to].find(last[ev.id]+1));
        }
    }

    int ans = INF;
    for(int i=0;i<M;i++) if(edges[i].to == N-1 || edges[i].to == N+N-1)
        ans = min(ans, dp[i]);

    printf("%d", ans<INF ? ans+1 : -1);
}


// In the name of God

#include <iostream>
#include <algorithm>
#include <fstream>
#include <vector>
#include <deque>
#include <assert.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <stdio.h>
#include <string.h>
#include <utility>
#include <math.h>
#include <bitset>
#include <iomanip>
#include <complex>

using namespace std;

#define rep(i, a, b) for (int i = (a), i##_end_ = (b); i < i##_end_; ++i)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define mp make_pair
#define x first
#define y second
#define pb push_back
#define SZ(x) (int((x).size()))
#define ALL(x) (x).begin(), (x).end()

template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool smin(T &a, const T &b)   { return a > b ? a = b : a;    }
template<typename T> inline bool smax(T &a, const T &b)   { return a < b ? a = b : a;    }

typedef long long LL;

const int N = (int) 3e6 + 6, mod = (int) 0;
vector<int> adj[N], ex[N][2];
int eu[N], ev[N], el[N], er[N], d[N];
int by_l(int x, int y) { return el[x >> 2] > el[y >> 2]; }
int main() {
	ios_base::sync_with_stdio(0);
	int n, m;
	cin >> n >> m;
	if (n == 1) {
		cout << 0 << endl;
		return 0;
	}
	for (int e = 0; e < m; ++e) {
		int a = e << 2 | 0, b = a | 1, c = a | 2, d = a | 3;
		int &u = eu[e], &v = ev[e], &l = el[e], &r = er[e];
		cin >> u >> v >> l >> r;
		--u, --v, ++r;
		if (u > v) swap(u, v);
		ex[u][0].pb(a);
		ex[u][1].pb(b);
		ex[v][0].pb(c);
		ex[v][1].pb(d);
		adj[a].push_back(d);
		adj[b].push_back(c);
		adj[d].push_back(a);
		adj[c].push_back(b);
	}
	for (int v = 0; v < n; ++v)
		for (int p = 0; p <= 1; ++p)
			sort(ex[v][p].begin(), ex[v][p].end(), by_l);
	memset(d, 63, sizeof d);
	set<pair<int, int>> st;
	for (int e = 0; e < m; ++e) {
		int a = e << 2 | 0;
		int &u = eu[e], &v = ev[e], &l = el[e], &r = er[e];
		if (l == 0 && u == 0) {
			d[a] = 0;
			st.insert(mp(d[a], a));
		}
	}
	while ((int) st.size()) {
		auto cur = *(st.begin());
		st.erase(cur);
		int ind = cur.second, e = ind >> 2;
		int u = eu[e], v = ev[e], l = el[e], r = er[e], parity = 0;
		if (ind & 2) {
			swap(u, v);
		}
		parity = ind & 1;
		if (d[ind] + 1 < r) for (int x : adj[ind]) {
			if (d[ind] + 1 < d[x]) {
				st.erase(mp(d[x], x));
				d[x] = d[ind] + 1;
				st.insert(mp(d[x], x));
			}
		}
		int curd = cur.first;
		while ((int) ex[u][parity].size()) {
			int nxe = ex[u][parity].back();
			if (curd >= er[nxe >> 2]) {
				ex[u][parity].pop_back();
			} else {
				int after = el[nxe >> 2];
				while ((after ^ parity) & 1) ++after;
				after = max(after, curd);
				if (after >= r) break;
				if (after < er[nxe >> 2]) {
					if (d[nxe] > after) {
						st.erase(mp(d[nxe], nxe));
						d[nxe] = after;
						st.insert(mp(d[nxe], nxe));
					}
				}
				ex[u][parity].pop_back();
			}
		}
	}
	int res = 2e9;
	for (int j = 0; j < 4 * m; ++j) {
		int e = j >> 2;
		int u = eu[e], v = ev[e], l = el[e], r = er[e];
		if (j & 2) {
			swap(u, v);
		}
		if (u == n - 1) {
			res = min(res, d[j]);
		}
	}
	if (res > (int) 1e9 + 10) {
		res = -1;
	}
	cout << res << '\n';
}


#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<memory.h>
#include<algorithm>
#define ll int
#define For(i,j,k) for(ll i=j;i<=k;++i)
#define FOr(i,j,k) for(ll i=j;i>=k;--i)
#define F first
#define S second
using namespace std;
inline ll read()
{
	ll x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void wrote(ll x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>=10)wrote(x/10);putchar(x%10+'0');
}
inline void writeln(ll x)
{
	wrote(x);
	puts("");
}
const ll maxn=1000010;
struct data{
	ll id,l,r;
};
struct dt{
	ll x,v;
};
vector<data>g[maxn][2];
ll n,m,ST[maxn][2];
bool operator < (data a,data b)
{
	return a.l<b.l;
}
bool operator < (dt a,dt b)
{
	return a.v>b.v;
}
priority_queue<dt>Q;
ll dij()
{
	Q.push((dt){1,0});
	while(!Q.empty())
	{
		ll x=Q.top().x,now=Q.top().v,c=now&1,st=now,in;	Q.pop();
		if(x==n) return now;
		for(ll i=ST[x][c];i<g[x][c].size();i++)
		{
			data to=g[x][c][i];
			if(to.l>now) break;
			ST[x][c]=i+1;
			if(to.r<st)	continue;
			now=max(now,to.r);
			now-=now-c&1;
			in=max(st,to.l);
			in+=in-c&1;
			if((in<to.r)&&(in>=to.l))	Q.push((dt){to.id,in+1});
		}
	}
	return -1;
}
int main()
{
	n=read();m=read();
	For(i,1,m)
	{
		ll x=read(),y=read(),l=read(),r=read();
		g[x][0].push_back((data){y,l,r});
		g[y][0].push_back((data){x,l,r});
		g[x][1].push_back((data){y,l,r});
		g[y][1].push_back((data){x,l,r});
	}
	For(i,1,n) For(j,0,1) sort(g[i][j].begin(),g[i][j].end());
	writeln(dij());
	return 0;
}


#include<bits/stdc++.h>
#define rep(i,x,y) for(i=x;i<=y;i++)
#define reps(i,x,y) for(i=x;i>=y;i--)
#define INF 0x5fffffffffffll
#define PB push_back
#define MP make_pair
#define N 1100000
using namespace std;
typedef long long LL;
typedef double DB;
typedef vector<int> VI;
struct node{
	int y,l,r;
}t[N];int tot;
bool cmp(const int &x,const int &y){
	return t[x].l>t[y].l;
}
int n,m;
VI G[N][2];
LL d[N][2];
priority_queue<pair<LL,int> ,vector<pair<LL,int> > ,greater<pair<LL,int> >  > Q;
void solve(){
	int i,j,k;
	scanf("%d%d",&n,&m);
	if(n==1){
		puts("0");
		return;
	}
	int x,y,l,r;
	while(m--){
		scanf("%d%d%d%d",&x,&y,&l,&r);
		t[++tot]=(node){y,l,r};
		G[x][0].emplace_back(tot);
		G[x][1].emplace_back(tot);
		t[++tot]=(node){x,l,r};
		G[y][0].emplace_back(tot);
		G[y][1].emplace_back(tot);
	}
	rep(i,1,n){
		sort(G[x][0].begin(),G[x][0].end(),cmp);
		sort(G[x][1].begin(),G[x][1].end(),cmp);
	}
	memset(d,63,sizeof(d));
	for(k=0;k<G[1][0].size();k++){
		int u=G[1][0][k];
		if(t[u].l==0){
			Q.emplace(MP(0,u));
			d[u][0]=0;
		}
	}
	LL ans=INF;
	while(!Q.empty()){
		pair<LL,int> p=Q.top();Q.pop();
		int u=p.second;LL val=p.first;
		if(val>d[u][val&1])continue;
		x=t[u].y;
		if(x==n)ans=min(ans,val);
		LL val1=val+1;
		int now=val1&1;
		while(G[x][now].size()){
			int v=G[x][now].back();
			if(t[v].r<=val1){
				G[x][now].pop_back();
				continue;
			}
			if(t[v].l>t[u].r)break;
			if(val1<t[v].l)val1=t[v].l;
			if((val1&1)!=now)val1++;
			if(val1>t[v].r){
				G[x][now].pop_back();
				continue;
			}
			d[v][now]=val1;
			Q.emplace(MP(val1,v));
			G[x][now].pop_back();
		}
	}
	if(ans==INF)puts("-1");
	else cout<<ans+1<<endl;
}
int main(){
	//freopen("in.txt","r",stdin);
	solve();
	return 0;
}


#include<bits/stdc++.h>
#define rep(i,x,y) for(i=x;i<=y;i++)
#define reps(i,x,y) for(i=x;i>=y;i--)
#define INF 0x5fffffff
#define PB push_back
#define MP make_pair
#define N 1100000
using namespace std;
typedef long long LL;
typedef double DB;
typedef vector<int> VI;
struct node{
	int y,l,r;
}t[N];int tot;
bool cmp(const int &x,const int &y){
	return t[x].l>t[y].l;
}
int n,m;
VI G[N][2];
int d[N][2];
priority_queue<pair<int,int> ,vector<pair<int,int> > ,greater<pair<int,int> >  > Q;
void solve(){
	int i,j,k;
	scanf("%d%d",&n,&m);
	if(n==1){
		puts("0");
		return;
	}
	int x,y,l,r;
	while(m--){
		scanf("%d%d%d%d",&x,&y,&l,&r);r--;
		t[++tot]=(node){y,l,r};
		G[x][0].emplace_back(tot);
		G[x][1].emplace_back(tot);
		t[++tot]=(node){x,l,r};
		G[y][0].emplace_back(tot);
		G[y][1].emplace_back(tot);
	}
	rep(i,1,n){
		sort(G[x][0].begin(),G[x][0].end(),cmp);
		sort(G[x][1].begin(),G[x][1].end(),cmp);
	}
	memset(d,63,sizeof(d));
	for(k=0;k<G[1][0].size();k++){
		int u=G[1][0][k];
		if(t[u].l==0){
			Q.emplace(MP(0,u));
			d[u][0]=0;
		}
	}
	int ans=INF;
	while(!Q.empty()){
		pair<int,int> p=Q.top();Q.pop();
		int u=p.second,val=p.first;
		if(val>d[u][val&1])continue;
		x=t[u].y;
		if(x==n)ans=min(ans,val);
		int val1=val+1;
		int now=val1&1;
		while(G[x][now].size()){
			int v=G[x][now].back();
			if(t[v].r<=t[u].l){
				G[x][now].pop_back();
				continue;
			}
			if(t[v].l>t[u].r+1)break;
			if(val1<t[v].l)val1=t[v].l;
			if((val1&1)!=now)val1++;
			if(val1>t[v].r)break;
			d[v][now]=val1;
			Q.emplace(MP(val1,v));
			G[x][now].pop_back();
		}
	}
	if(ans==INF)puts("-1");
	else printf("%d\n",ans+1);
}
int main(){
	//freopen("in.txt","r",stdin);
	solve();
	return 0;
}


#include<bits/stdc++.h>
#define rep(i,x,y) for(i=x;i<=y;i++)
#define reps(i,x,y) for(i=x;i>=y;i--)
#define INF 0x5fffffffffffll
#define PB push_back
#define MP make_pair
#define N 1100000
using namespace std;
typedef long long LL;
typedef double DB;
typedef vector<int> VI;
struct node{
	int y,l,r;
}t[N];int tot;
bool cmp(const int &x,const int &y){
	return t[x].l>t[y].l;
}
int n,m;
VI G[N][2];
LL d[N][2];
priority_queue<pair<LL,int> ,vector<pair<LL,int> > ,greater<pair<LL,int> >  > Q;
void solve(){
	int i,j,k;
	scanf("%d%d",&n,&m);
	if(n==1){
		puts("0");
		return;
	}
	int x,y,l,r;
	while(m--){
		scanf("%d%d%d%d",&x,&y,&l,&r);
		t[++tot]=(node){y,l,r};
		G[x][0].emplace_back(tot);
		G[x][1].emplace_back(tot);
		t[++tot]=(node){x,l,r};
		G[y][0].emplace_back(tot);
		G[y][1].emplace_back(tot);
	}
	rep(i,1,n){
		sort(G[i][0].begin(),G[i][0].end(),cmp);
		sort(G[i][1].begin(),G[i][1].end(),cmp);
	}
/*	for(i=0;i<G[3][0].size();i++){
		printf("%d ",G[3][0][i]);
		int fuck=G[3][0][i];
		printf("%d %d %d\n",t[fuck].y,t[fuck].l,t[fuck].r);
	}
	puts("");
	for(i=0;i<G[3][1].size();i++)printf("%d ",G[3][1][i]);puts("");*/
	memset(d,63,sizeof(d));
	for(k=0;k<G[1][0].size();k++){
		int u=G[1][0][k];
		if(t[u].l==0){
			Q.emplace(MP(0,u));
			d[u][0]=0;
		}
	}

	LL ans=INF;
	while(!Q.empty()){
		pair<LL,int> p=Q.top();Q.pop();
		int u=p.second;LL val=p.first;
		if(val>d[u][val&1])continue;
		x=t[u].y;
		if(x==n)ans=min(ans,val);
		LL val1=val+1;
		int now=val1&1;
		//printf("f%d %d %d \n",x,now,(int)G[x][now].size());
		while(G[x][now].size()){
			int v=G[x][now].back();
			if(t[v].r<=val1){
				G[x][now].pop_back();
				continue;
			}
			if(t[v].l>t[u].r)break;
			if(val1<t[v].l)val1=t[v].l;
			if((val1&1)!=now)val1++;
			if(val1>t[u].r)break;
			if(val1>=t[v].r){
				G[x][now].pop_back();
				continue;
			}
			if(val1<d[v][now]){
				d[v][now]=val1;
				Q.emplace(MP(val1,v));
			}
			G[x][now].pop_back();
		}
	}
	if(ans==INF)puts("-1");
	else cout<<ans+1<<endl;
}
int main(){
	//freopen("in.txt","r",stdin);
	solve();
	return 0;
}


#include<bits/stdc++.h>
#define rep(i,x,y) for(i=x;i<=y;i++)
#define reps(i,x,y) for(i=x;i>=y;i--)
#define INF 0x5fffffff
#define PB push_back
#define MP make_pair
#define N 1100000
using namespace std;
typedef long long LL;
typedef double DB;
typedef vector<int> VI;
struct node{
	int y,l,r;
}t[N];int tot;
bool cmp(const int &x,const int &y){
	return t[x].l>t[y].l;
}
int n,m;
VI G[N][2];
int d[N][2];
priority_queue<pair<int,int> ,vector<pair<int,int> > ,greater<pair<int,int> >  > Q;
void solve(){
	int i,j,k;
	scanf("%d%d",&n,&m);
	int x,y,l,r;
	while(m--){
		scanf("%d%d%d%d",&x,&y,&l,&r);r--;
		t[++tot]=(node){y,l,r};
		G[x][0].emplace_back(tot);
		G[x][1].emplace_back(tot);
		t[++tot]=(node){x,l,r};
		G[y][0].emplace_back(tot);
		G[y][1].emplace_back(tot);
	}
	rep(i,1,n){
		sort(G[x][0].begin(),G[x][0].end(),cmp);
		sort(G[x][1].begin(),G[x][1].end(),cmp);
	}
	memset(d,63,sizeof(d));
	for(k=0;k<G[1][0].size();k++){
		int u=G[1][0][k];
		if(t[u].l==0){
			Q.emplace(MP(0,u));
			d[u][0]=0;
		}
	}
	int ans=INF;
	while(!Q.empty()){
		pair<int,int> p=Q.top();Q.pop();
		int u=p.second,val=p.first;
		if(val>d[u][val&1])continue;
		x=t[u].y;
		int val1=val+1;
		int now=val1&1;
		while(G[x][now].size()){
			int v=G[x][now].back();
			if(t[v].r<=t[u].l){
				G[x][now].pop_back();
				continue;
			}
			if(t[v].l>t[u].r+1)break;
			if(val1<t[v].l)val1=t[v].l;
			if((val1&1)!=now)val1++;
			if(val1>t[v].r)break;
			d[v][now]=val1;
			Q.emplace(MP(val1,v));
			if(t[v].y==n)ans=min(ans,val1);
			G[x][now].pop_back();
		}
	}
	if(ans==INF)puts("-1");
	else printf("%d\n",ans+1);
}
int main(){
	//freopen("in.txt","r",stdin);
	solve();
	return 0;
}


#include<bits/stdc++.h>
#define rep(i,x,y) for(i=x;i<=y;i++)
#define reps(i,x,y) for(i=x;i>=y;i--)
#define INF 0x5fffffffffffll
#define PB push_back
#define MP make_pair
#define N 1100000
using namespace std;
typedef long long LL;
typedef double DB;
typedef vector<int> VI;
struct node{
	int y,l,r;
}t[N];int tot;
bool cmp(const int &x,const int &y){
	return t[x].l>t[y].l;
}
int n,m;
VI G[N][2];
LL d[N][2];
priority_queue<pair<LL,int> ,vector<pair<LL,int> > ,greater<pair<LL,int> >  > Q;
void solve(){
	int i,j,k;
	scanf("%d%d",&n,&m);
	if(n==1){
		puts("0");
		return;
	}
	int x,y,l,r;
	while(m--){
		scanf("%d%d%d%d",&x,&y,&l,&r);
		t[++tot]=(node){y,l,r};
		G[x][0].emplace_back(tot);
		G[x][1].emplace_back(tot);
		t[++tot]=(node){x,l,r};
		G[y][0].emplace_back(tot);
		G[y][1].emplace_back(tot);
	}
	rep(i,1,n){
		sort(G[x][0].begin(),G[x][0].end(),cmp);
		sort(G[x][1].begin(),G[x][1].end(),cmp);
	}
	memset(d,63,sizeof(d));
	for(k=0;k<G[1][0].size();k++){
		int u=G[1][0][k];
		if(t[u].l==0){
			Q.emplace(MP(0,u));
			d[u][0]=0;
		}
	}

	LL ans=INF;
	while(!Q.empty()){
		pair<LL,int> p=Q.top();Q.pop();
		int u=p.second;LL val=p.first;
		if(val>d[u][val&1])continue;
		x=t[u].y;
		if(x==n)ans=min(ans,val);
		LL val1=val+1;
		int now=val1&1;
		//printf("f%d %d %d \n",x,now,(int)G[x][now].size());
		while(G[x][now].size()){
			int v=G[x][now].back();
			if(t[v].r<=val1){
				G[x][now].pop_back();
				continue;
			}
			if(t[v].l>t[u].r)break;
			if(val1<t[v].l)val1=t[v].l;
			if((val1&1)!=now)val1++;
			if(val1>t[v].r||val1>t[u].r){
				G[x][now].pop_back();
				continue;
			}
			d[v][now]=val1;
			Q.emplace(MP(val1,v));
			G[x][now].pop_back();
		}
	}
	if(ans==INF)puts("-1");
	else cout<<ans+1<<endl;
}
int main(){
	//freopen("in.txt","r",stdin);
	solve();
	return 0;
}


#include<bits/stdc++.h>
#define rep(i,x,y) for(i=x;i<=y;i++)
#define reps(i,x,y) for(i=x;i>=y;i--)
#define INF 0x5fffffffffffll
#define PB push_back
#define MP make_pair
#define N 1100000
using namespace std;
typedef long long LL;
typedef double DB;
typedef vector<int> VI;
struct node{
	int y,l,r;
}t[N];int tot;
bool cmp(const int &x,const int &y){
	return t[x].l>t[y].l;
}
int n,m;
VI G[N][2];
LL d[N][2];
priority_queue<pair<LL,int> ,vector<pair<LL,int> > ,greater<pair<LL,int> >  > Q;
void solve(){
	int i,j,k;
	scanf("%d%d",&n,&m);
	if(n==1){
		puts("0");
		return;
	}
	int x,y,l,r;
	while(m--){
		scanf("%d%d%d%d",&x,&y,&l,&r);r--;
		t[++tot]=(node){y,l,r};
		G[x][0].emplace_back(tot);
		G[x][1].emplace_back(tot);
		t[++tot]=(node){x,l,r};
		G[y][0].emplace_back(tot);
		G[y][1].emplace_back(tot);
	}
	rep(i,1,n){
		sort(G[x][0].begin(),G[x][0].end(),cmp);
		sort(G[x][1].begin(),G[x][1].end(),cmp);
	}
	memset(d,63,sizeof(d));
	for(k=0;k<G[1][0].size();k++){
		int u=G[1][0][k];
		if(t[u].l==0){
			Q.emplace(MP(0,u));
			d[u][0]=0;
		}
	}
	LL ans=INF;
	while(!Q.empty()){
		pair<LL,int> p=Q.top();Q.pop();
		int u=p.second;LL val=p.first;
		if(val>d[u][val&1])continue;
		x=t[u].y;
		if(x==n)ans=min(ans,val);
		LL val1=val+1;
		int now=val1&1;
		while(G[x][now].size()){
			int v=G[x][now].back();
			if(t[v].r<=d[u][val&1]){
				G[x][now].pop_back();
				continue;
			}
			if(t[v].l>t[u].r+1)break;
			if(val1<t[v].l)val1=t[v].l;
			if((val1&1)!=now)val1++;
			if(val1>t[v].r){
				G[x][now].pop_back();
				continue;
			}
			d[v][now]=val1;
			Q.emplace(MP(val1,v));
			G[x][now].pop_back();
		}
	}
	if(ans==INF)puts("-1");
	else cout<<ans+1<<endl;
}
int main(){
	//freopen("in.txt","r",stdin);
	solve();
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define PB push_back
#define ZERO (1e-10)
#define INF int(1e9+1)
#define CL(A,I) (memset(A,I,sizeof(A)))
#define DEB printf("DEB!\n");
#define D(X) cout<<"  "<<#X": "<<X<<endl;
#define EQ(A,B) (A+ZERO>B&&A-ZERO<B)
typedef long long ll;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef vector<ii> vii;
#define IN(n) int n;scanf("%d",&n);
#define FOR(i, m, n) for (int i(m); i < n; i++)
#define F(n) FOR(i,0,n)
#define FF(n) FOR(j,0,n)
#define FT(m, n) FOR(k, m, n)
#define aa first
#define bb second
void ga(int N,int *A){F(N)scanf("%d",A+i);}
#define MX (1<<20)
struct eg{
    int a,l,r;
    bool operator<(const eg&r)const{return l>r.l;}
}h;
vector<eg> g[MX][2];
int N,M,a,b,c,d,B,J;
priority_queue<ii> Q;
int dj(){
    Q.push({0,0});
    while(!Q.empty()){
        B=a=-Q.top().aa,b=Q.top().bb,Q.pop(),J=a&1;
        if(b+1==N)return a;
        while(!g[b][J].empty()&&g[b][J].back().l<=B){
            h=g[b][J].back(),g[b][J].pop_back(),B=max(B,h.r);
            if(B%2!=J)--B;
            if(h.r<a)continue;
            d=max(h.l,a);
            if(d%2!=J)++d;
            if(d+1<=h.r&&d>=h.l)Q.push({-d-1,h.a});
        }
    }
    return -1;
}
int main(void){
    scanf("%d%d",&N,&M);
    F(M){
        scanf("%d%d%d%d",&a,&b,&c,&d),--a,--b;
        FF(2)g[a][j].PB({b,c,d}),g[b][j].PB({a,c,d});
    }
    F(N)FF(2)sort(g[i][j].begin(),g[i][j].end());
    printf("%d\n",dj());
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 7;
int T, n, can[N];
map<char, int> mp, ha = {{'?', 0}, {'V', 1}, {'K', 2}};
char s[N];
bool check(int l){
	for(int i = 0; i < l; ++ i){
		int who = ha[s[i]], now = i + l;
		while(now < n){
			if(who && s[now] != '?' && who != ha[s[now]]) return false;
			if(s[now] != '?') who = ha[s[now]];
			now += l;
		}
	}
	return true;
}
int main(){
	cin >> T;
	while(T --){
		scanf("%d", &n);
		scanf("%s", s);
		memset(can, 0, sizeof(int) * (n+1));
		mp.clear();
		for(int i = 0; i < n; ++ i) mp[s[i]] = 1;
		if(mp['V'] + mp['K'] <= 1){
			printf("%d\n", n);
			for(int i = 1; i <= n; ++ i) printf("%d%c", i, i == n ? '\n' : ' ');
			continue;
		}
        for(int i = 2; i <= n; ++ i){
            if(check(i)) {
                for(int j = i; j <= n; j += i) can[j] = true;
                can[i] = true;
            }
		}
		int ans = 0, first = 1;
		for(int i = 2; i <= n; ++ i) ans += can[i];
		printf("%d\n", ans);
		for(int i = 2; i <= n; ++ i){
			if(can[i]){
				if(first) first = false;
				else putchar(' ');
				printf("%d", i);
			}
		}
		puts("");
	}
	return 0;
}


#pragma G++ optimize(2)
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define LL long long
#define O4 __inline__ __attribute__((always_inline))
#define inf 0x7fffffff
#define UL unsigned LL
#define LD long double
#ifdef ONLINE_JUDGE
#define getchar nc
#endif
//#define int LL
namespace FastIO{
	O4 char nc(){
		static char buf[100000],*p1=buf,*p2=buf;
		return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
	}
	O4 int read(){
		char t;int u=0,k=1;t=getchar();
		while(t<'0'||t>'9'){if(t=='-')k=-1;t=getchar();}
		while(t>='0'&&t<='9'){u=u*10+t-'0';t=getchar();}
		return u*k;
	}
	template <typename T>
	O4 void read(T &u){
		char t;T k=1;u=0;t=getchar();
		while(t<'0'||t>'9'){if(t=='-')k=-1;t=getchar();}
		while(t>='0'&&t<='9'){u=u*10+t-'0';t=getchar();}
		if(t=='.'){
			T mass=0.1;t=getchar();
			while(t>='0'&&t<='9'){u+=mass*(t-'0');mass/=10;t=getchar();}
		}u*=k;
	}
	O4 int read(char asd[]){
		char t=getchar();int u=0;
		while(t==' '||t=='\n'||t=='\r')t=getchar();
		if(t==EOF)return -1;
		while(t!=' '&&t!='\n'&&t!=EOF&&t!='\r')asd[u++]=t,t=getchar();
		asd[u]='\0';return u;
	}
	char sr[1<<23],z[23];int C=-1,Z;
	O4 void wer(int x,char T){
		int y=0;if(x<0)y=1,x=-x;
		while(z[++Z]=x%10+'0',x/=10);if(y)z[++Z]='-';
		while(sr[++C]=z[Z],--Z);sr[++C]=T;
	}
	O4 void wer(char T[],char QWQ){
		for(int i=0;T[i]!='\0';i++)sr[++C]=T[i];
		sr[++C]=QWQ;
	}
	O4 void out(){fwrite(sr,1,C+1,stdout);C=-1;}
}
using namespace std;
using namespace FastIO;
const int N=5e5+5;
struct oath{int a,b,l,r;};
O4 bool operator < (const oath &x,const oath &y){return x.l>y.l;}
priority_queue <oath> Heap;
vector <oath> Map[N][2];
int tim[N][2],n,m;
void Extend(int x,int l,int r,int opt){
	tim[x][opt]=max(tim[x][opt],r);
	for(auto it:Map[x][opt]){
		oath tp=it;
		if(l>it.r)continue;
		it.l=l;Heap.push(it);
	}Map[x][opt].clear();
}
signed main(){
	n=read();m=read();
	if(n==1)return puts("0"),0;
	while(m--){
		int a=read(),b=read(),l=read(),r=read()-1,opt=(r-l)&1;
		Heap.push((oath){a,b,l,r-opt});
		Heap.push((oath){b,a,l,r-opt});
		Heap.push((oath){a,b,l+1,r-(opt^1)});
		Heap.push((oath){b,a,l+1,r-(opt^1)});
	}
	memset(tim,-1,sizeof tim);
	tim[1][0]=0;
	while(!Heap.empty()){
		oath tp=Heap.top();
		Heap.pop();
		int a=tp.a,b=tp.b,opt=tp.l&1;
		if(tp.l>tp.r)continue;
		if(tim[a][opt]>=tp.l){
			if(b==n)return cout<<tp.l+1,0;
			Extend(b,tp.l+1,tp.r+1,opt^1);
		}
		else Map[a][opt].push_back(tp);
	}puts("-1");
	return 0;
}


#include <map>
#include <set>
#include <list>
#include <cmath>
#include <stack>
#include <queue>
#include <bitset>
#include <cstdio>
#include <climits>
#include <vector>
#include <cstdlib>
#include <numeric>
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <algorithm>
#include <array>
#include <assert.h>
#include <functional>
#define _USE_MATH_DEFINES
#include <math.h>
#include <complex>

using namespace std;
typedef long long ll;
#define ln '\n'
#define rep(i,n) for(int i=0;i<(n);++i)
#define drep(i,n) int i = 0;for(;i<(n);++i)
#define FOR(i,s,e) for(int i=s;i<=(e);++i)
#define FORR(i,s,e) for(int i=s;i>=(e);--i)
#define fore(a, x) for(auto& a : x)
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define ft first
#define sd second
#define pb push_back
#define eb emplace_back
#define all(a) a.begin(),a.end()
#define Fill(a,b) memset(a,b,sizeof(a))
template<typename T1, typename T2> bool Max(T1& a, T2 b) { return a<b ? a = b, 1 : 0; }
template<typename T1, typename T2> bool Min(T1& a, T2 b) { return a>b ? a = b, 1 : 0; }

const int N = 500000;

vector<pair<pii, int>> g[N];
int nt[N][2]; // next pos

void solve() {
  int n, m, u, v, l, r;
  cin >> n >> m;
  while (m--) {
    cin >> u >> v >> l >> r;
    u--, v--;
    g[u].emplace_back(pii(l, r), v);
    g[v].emplace_back(pii(l, r), u);
  }
  rep(i, n)if (g[i].size())sort(all(g[i]));
  priority_queue<pair<pii, int>, vector<pair<pii, int>> , greater<pair<pii, int>> > q;
  q.emplace(pii(0, 0), 0);
  while (q.size()) {
    auto cur = q.top(); q.pop();
    int l = cur.ft.ft, r = cur.ft.sd, i = cur.sd;
    if (i == n - 1) {
      cout << l << ln;
      return;
    }
    bool c = l & 1;
    for(int& p = nt[i][c]; p < g[i].size(); p++) {
      if (g[i][p].ft.ft > r)break;
      Max(r, g[i][p].ft.sd);
      if ((r & 1) != c) r--;
      int nl = max(l, g[i][p].ft.ft) + 1;
      int nr = min(g[i][p].ft.sd, r+1);
      if ((nl & 1) == c) nl++;
      if ((nr & 1) == c) nr--;
      if (nr >= nl) {
        q.emplace(pii(nl, nr), g[i][p].sd);
      }
    }
  }
  cout << -1 << ln;

}

void init() {

}

int main(void) {
  ios::sync_with_stdio(false); cin.tie(0); cout.setf(ios::fixed); cout.precision(20);
  //freopen("C:\\Users\\LENOVO\\Documents\\Visual Studio 2015\\Projects\\Test\\Input\\in.in", "r", stdin);

  init();
  int TC = 1;
#if 0
  cin >> TC; cin.get();
#endif
  FOR(TI, 1, TC) {
    //cout << "Case #" << TI << ": ";
    solve();
  }

  return 0;
}


#include <map>
#include <set>
#include <list>
#include <cmath>
#include <stack>
#include <queue>
#include <bitset>
#include <cstdio>
#include <climits>
#include <vector>
#include <cstdlib>
#include <numeric>
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <algorithm>
#include <array>
#include <assert.h>
#include <functional>
#define _USE_MATH_DEFINES
#include <math.h>
#include <complex>

using namespace std;
typedef long long ll;
#define ln '\n'
#define rep(i,n) for(int i=0;i<(n);++i)
#define drep(i,n) int i = 0;for(;i<(n);++i)
#define FOR(i,s,e) for(int i=s;i<=(e);++i)
#define FORR(i,s,e) for(int i=s;i>=(e);--i)
#define fore(a, x) for(auto& a : x)
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define ft first
#define sd second
#define pb push_back
#define eb emplace_back
#define all(a) a.begin(),a.end()
#define Fill(a,b) memset(a,b,sizeof(a))
template<typename T1, typename T2> bool Max(T1& a, T2 b) { return a<b ? a = b, 1 : 0; }
template<typename T1, typename T2> bool Min(T1& a, T2 b) { return a>b ? a = b, 1 : 0; }

const int N = 500000;

vector<pair<pii, int>> g[N];
int nt[N][2]; // next pos

void solve() {
  int n, m, u, v, l, r;
  cin >> n >> m;
  while (m--) {
    cin >> u >> v >> l >> r;
    u--, v--;
    g[u].emplace_back(pii(l, r), v);
    g[v].emplace_back(pii(l, r), u);
  }
  rep(i, n)if (g[i].size())sort(all(g[i]));
  priority_queue<pair<pii, int>, vector<pair<pii, int>> , greater<pair<pii, int>> > q;
  q.emplace(pii(0, 0), 0);
  while (q.size()) {
    auto cur = q.top(); q.pop();
    int l = cur.ft.ft, r = cur.ft.sd, i = cur.sd;
    if (i == n - 1) {
      cout << l << ln;
      return;
    }
    bool c = l & 1;
    for(int& p = nt[i][c]; p < g[i].size(); p++) {
      if (g[i][p].ft.ft > r)break;
      Max(r, g[i][p].ft.sd);
      int nl = max(l, g[i][p].ft.ft) + 1;
      int nr = r;
      if ((nl & 1) == c) nl++;
      if ((nr & 1) == c) nr--;
      if (nr >= nl) {
        q.emplace(pii(nl, nr), g[i][p].sd);
      }
    }
  }
  cout << -1 << ln;

}

void init() {

}

int main(void) {
  ios::sync_with_stdio(false); cin.tie(0); cout.setf(ios::fixed); cout.precision(20);
  //freopen("C:\\Users\\LENOVO\\Documents\\Visual Studio 2015\\Projects\\Test\\Input\\in.in", "r", stdin);

  init();
  int TC = 1;
#if 0
  cin >> TC; cin.get();
#endif
  FOR(TI, 1, TC) {
    //cout << "Case #" << TI << ": ";
    solve();
  }

  return 0;
}


#include <map>
#include <set>
#include <list>
#include <cmath>
#include <stack>
#include <queue>
#include <bitset>
#include <cstdio>
#include <climits>
#include <vector>
#include <cstdlib>
#include <numeric>
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <algorithm>
#include <array>
#include <assert.h>
#include <functional>
#define _USE_MATH_DEFINES
#include <math.h>
#include <complex>

using namespace std;
typedef long long ll;
#define ln '\n'
#define rep(i,n) for(int i=0;i<(n);++i)
#define drep(i,n) int i = 0;for(;i<(n);++i)
#define FOR(i,s,e) for(int i=s;i<=(e);++i)
#define FORR(i,s,e) for(int i=s;i>=(e);--i)
#define fore(a, x) for(auto& a : x)
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define ft first
#define sd second
#define pb push_back
#define eb emplace_back
#define all(a) a.begin(),a.end()
#define Fill(a,b) memset(a,b,sizeof(a))
template<typename T1, typename T2> bool Max(T1& a, T2 b) { return a<b ? a = b, 1 : 0; }
template<typename T1, typename T2> bool Min(T1& a, T2 b) { return a>b ? a = b, 1 : 0; }

const int N = 500000;

vector<pair<pii, int>> g[N];
int nt[N][2]; // next pos

void solve() {
  int n, m, u, v, l, r;
  cin >> n >> m;
  while (m--) {
    cin >> u >> v >> l >> r;
    u--, v--;
    g[u].emplace_back(pii(l, r), v);
    g[v].emplace_back(pii(l, r), u);
  }
  rep(i, n)if (g[i].size())sort(all(g[i]));
  priority_queue<pair<pii, int>, vector<pair<pii, int>> , greater<pair<pii, int>> > q;
  q.emplace(pii(0, 0), 0);
  while (q.size()) {
    auto cur = q.top(); q.pop();
    int l = cur.ft.ft, r = cur.ft.sd, i = cur.sd;
    if (i == n - 1) {
      cout << l << ln;
      return;
    }
    bool c = l & 1;
    for(int& p = nt[i][c]; p < g[i].size(); p++) {
      if (g[i][p].ft.ft > r)break;
      int nl = max(l, g[i][p].ft.ft) + 1;
      int nr = min(r, g[i][p].ft.sd - 1) + 1;
      if ((nl & 1) == c) nl++;
      if ((nr & 1) == c) nr--;
      if (nr >= nl) {
        q.emplace(pii(nl, nr), g[i][p].sd);
      }
    }
  }
  cout << -1 << ln;

}

void init() {

}

int main(void) {
  ios::sync_with_stdio(false); cin.tie(0); cout.setf(ios::fixed); cout.precision(20);
  //freopen("C:\\Users\\LENOVO\\Documents\\Visual Studio 2015\\Projects\\Test\\Input\\in.in", "r", stdin);

  init();
  int TC = 1;
#if 0
  cin >> TC; cin.get();
#endif
  FOR(TI, 1, TC) {
    //cout << "Case #" << TI << ": ";
    solve();
  }

  return 0;
}


#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int> pii;
typedef pair<pii,int> ppri;
#define N 1200000
#define P(x,y) make_pair(x,y)
#define INF 0x3f3f3f3f

int n,m,ans;
struct edge{
	int v,l,r;
	edge(int v=0,int l=0,int r=0):v(v),l(l),r(r){}
	bool operator < (const edge &w) const{
		return l>w.l;
	}
};
vector<edge> g[N];
priority_queue<ppri,vector<ppri>,greater<ppri> > pq;

int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;++i){
		int x,y,l,r; scanf("%d%d%d%d",&x,&y,&l,&r);
		g[x<<1].push_back(edge(y<<1|1,l,r));
		g[x<<1|1].push_back(edge(y<<1,l,r));
		g[y<<1].push_back(edge(x<<1|1,l,r));
		g[y<<1|1].push_back(edge(x<<1,l,r));
	}
	for (int i=2;i<=n*2+1;++i) sort(g[i].begin(),g[i].end());
	ans=INF;
	pq.push(P(P(0,0),2));
	while (!pq.empty()){
		ppri pr=pq.top(); pq.pop();
		pii du=pr.first; int u=pr.second;
		if (u/2==n) ans=min(ans,du.first);
		while (!g[u].empty()){
			edge i=*g[u].rbegin();
			int v=i.v,l=i.l,r=i.r;
			if (du.second<l) break;
			g[u].pop_back();
			pii dv=P(max(l+1,du.first+1),r);
			if (dv.first%2!=v%2) ++dv.first;
			if (dv.second%2!=v%2) --dv.second;
			if (dv.first>dv.second) continue;
			pq.push(P(dv,v));
		}
	}
	printf("%d\n",ans==INF?-1:ans);

	return 0;
}


#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int> pii;
typedef pair<pii,int> ppri;
#define N 1200000
#define P(x,y) make_pair(x,y)
#define INF 0x3f3f3f3f

int n,m,ans;
struct edge{
	int v,l,r;
	edge(int v=0,int l=0,int r=0):v(v),l(l),r(r){}
	bool operator < (const edge &w) const{
		return l>w.l;
	}
};
vector<edge> g[N];
priority_queue<ppri,vector<ppri>,greater<ppri> > pq;

int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;++i){
		int x,y,l,r; scanf("%d%d%d%d",&x,&y,&l,&r);
		g[x<<1].push_back(edge(y<<1|1,l,r));
		g[x<<1|1].push_back(edge(y<<1,l,r));
		g[y<<1].push_back(edge(x<<1|1,l,r));
		g[y<<1|1].push_back(edge(x<<1,l,r));
	}
	for (int i=2;i<=n*2+1;++i) sort(g[i].begin(),g[i].end());
	ans=INF;
	pq.push(P(P(0,0),2));
	while (!pq.empty()){
		ppri pr=pq.top(); pq.pop();
		pii du=pr.first; int u=pr.second;
		if (u/2==n) ans=min(ans,du.first);
		while (!g[u].empty()){
			edge i=*g[u].rbegin();
			int v=i.v,l=i.l,r=i.r;
			if (du.second<l) break;
			g[u].pop_back();
			pii dv=P(max(l,du.first+1),r);
			if (dv.first%2!=v%2) ++dv.first;
			if (dv.second%2!=v%2) --dv.second;
			if (dv.first>dv.second) continue;
			pq.push(P(dv,v));
		}
	}
	printf("%d\n",ans==INF?-1:ans);

	return 0;
}


#ifdef LOCAL
#define _GLIBCXX_DEBUG
#endif
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define fst first
#define snd second
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<char> vc;
typedef pair<int, int> pii;
typedef vector<pii> vii;
#define sz(c) (int)(c).size()
#define all(c) (c).begin(), (c).end()

const int inf = (int)1e9 + 10;
struct edge
{
    int to;
    pii when;
};

vii when_open (vii segs, int par)
{
    if (segs.empty())
        return vii();

    sort(all(segs));

    int l = segs[0].fst, r = segs[0].snd;
    vii ans;
    forn (i, sz(segs)) if (i)
    {
        if (segs[i].fst > r - (r % 2 != par))
        {
            ans.pb(mp(l, r));
            tie(l, r) = segs[i];
        }
        else
            r = max(r, segs[i].snd);
    }

    ans.pb(mp(l, r));
    return ans;
}

void solve (int n)
{
    vector<vii> open(2 * n);
    int cnt = 0;
    vii belongs;
    vvi num(2 * n);
    vector<vector<edge>> edges;

    auto get_num = [&] (int v, int tm) -> int
    {
        int pos = upper_bound(all(open[v]), mp(tm, inf)) - open[v].begin() - 1;
        if (pos != -1)
        {
            assert(open[v][pos].fst <= tm);
            return (open[v][pos].snd > tm ? pos : -1);
        }
        return -1;
    };

    {
        int m;
        cin >> m;
        vvi orig(m, vi(4));
        forn (i, m) forn (j, 4)
        {
            cin >> orig[i][j];
            if (j < 2)
                --orig[i][j];
        }

        vector<vii> orig_open(n);
        forn (i, m) forn (j, 2)
            orig_open[orig[i][j]].pb(mp(orig[i][2], orig[i][3]));

        forn (i, n) forn (par, 2)
            open[2 * i + par] = when_open(orig_open[i], par);

        forn (i, sz(open))
            cnt += sz(open[i]);

        {
            belongs.resize(cnt);
            int cur = 0;
            forn (v, sz(open))
            {
                num[v].resize(sz(open[v]));
                forn (i, sz(open[v]))
                {
                    num[v][i] = cur;
                    belongs[cur++] = mp(v, i);
                }
            }
            assert(cur == cnt);
        }

        {
            edges.resize(cnt);
            forn (i, m) forn (j, 2) forn (par, 2)
            {
                int v = orig[i][j], to = orig[i][j ^ 1], l = orig[i][2], r = orig[i][3];
                int np = get_num(2 * v + par, l);

                for (int rp = np - 1; rp <= np + 1; rp++)
                if (0 <= rp && rp < sz(open[2 * v + par]))
                {
                    int nl = max(l, open[2 * v + par][rp].fst);
                    int nr = min(r, open[2 * v + par][rp].snd);
                    if (nl < nr)
                        edges[num[2 * v + par][rp]].pb(edge{2 * to + 1 - par, mp(nl, nr)});
                }
            }
        }
    }

    vi dist(cnt, inf);
    set<pii> bydist;

    {
        vii start(cnt);
        forn (i, cnt)
            start[i] = mp(inf, i);
        bydist = set<pii>(all(start));
    }

    auto relax = [&] (int v, int d)
    {
        if (d < dist[v])
        {
            bydist.erase(mp(dist[v], v));
            dist[v] = d;
            bydist.insert(mp(dist[v], v));
        }
    };

    int start = get_num(0, 0);
    if (start != -1)
        relax(start, 0);

    int ans = inf;
    while (!bydist.empty())
    {
        int cur = bydist.begin() -> snd;
        assert(dist[cur] == bydist.begin() -> fst);
        bydist.erase(bydist.begin());
        if (dist[cur] == inf)
            break;

        if (belongs[cur].fst / 2 == n - 1)
        {
            cout << min(ans, dist[cur]) << endl;
            return;
        }

        const int curt = dist[cur];
        for (const edge &e : edges[cur])
        {
            int to = e.to, l, r;
            tie(l, r) = e.when;
            int jumpt = curt;
            if (curt < l)
                jumpt = (((curt & 1) == (l & 1)) ? l : l + 1);
            if (jumpt >= r)
                continue;

            int pos = get_num(to, jumpt + 1);
            if (pos != -1)
                relax(num[to][pos], jumpt + 1);
            else if (to / 2 == n - 1)
                ans = min(ans, jumpt + 1);
        }
    }

    cout << (ans == inf ? -1 : ans) << endl;
//    exit(0);
}

int main()
{
#ifdef LOCAL
    freopen("input.txt", "rt", stdin);
    freopen("output.txt", "w", stdout);
#endif // ONLINE_JUDGE

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    while (cin >> n)
        solve(n);
}


#ifdef LOCAL
#define _GLIBCXX_DEBUG
#endif
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define fst first
#define snd second
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<char> vc;
typedef pair<int, int> pii;
typedef vector<pii> vii;
#define sz(c) (int)(c).size()
#define all(c) (c).begin(), (c).end()

const int inf = (int)1e9 + 10;
struct edge
{
    int to;
    pii when;
};

vii when_open (vii segs, int par)
{
    if (segs.empty())
        return vii();

    sort(all(segs));

    int l = segs[0].fst, r = segs[0].snd;
    vii ans;
    forn (i, sz(segs)) if (i)
    {
        if (segs[i].fst > r - (r % 2 != par))
        {
            ans.pb(mp(l, r));
            tie(l, r) = segs[i];
        }
        else
            r = max(r, segs[i].snd);
    }

    ans.pb(mp(l, r));
    return ans;
}

void solve (int n)
{
    vector<vii> open(2 * n);
    int cnt = 0;
    vii belongs;
    vvi num(2 * n);
    vector<vector<edge>> edges;

    auto get_num = [&] (int v, int tm) -> int
    {
        int pos = upper_bound(all(open[v]), mp(tm, inf)) - open[v].begin() - 1;
        if (pos != -1)
        {
            assert(open[v][pos].fst <= tm);
            return (open[v][pos].snd > tm ? pos : -1);
        }
        return -1;
    };

    {
        int m;
        cin >> m;
        vvi orig(m, vi(4));
        forn (i, m) forn (j, 4)
        {
            cin >> orig[i][j];
            if (j < 2)
                --orig[i][j];
        }

        vector<vii> orig_open(n);
        forn (i, m) forn (j, 2)
            orig_open[orig[i][j]].pb(mp(orig[i][2], orig[i][3]));

        forn (i, n) forn (par, 2)
            open[2 * i + par] = when_open(orig_open[i], par);

        forn (i, sz(open))
            cnt += sz(open[i]);

        {
            belongs.resize(cnt);
            int cur = 0;
            forn (v, sz(open))
            {
                num[v].resize(sz(open[v]));
                forn (i, sz(open[v]))
                {
                    num[v][i] = cur;
                    belongs[cur++] = mp(v, i);
                }
            }
            assert(cur == cnt);
        }

        {
            edges.resize(cnt);
            forn (i, m) forn (j, 2) forn (par, 2)
            {
                int v = orig[i][j], to = orig[i][j ^ 1], l = orig[i][2], r = orig[i][3];
                int np = get_num(2 * v + par, l);

                for (int rp = np - 1; rp <= np + 1; rp++)
                if (0 <= rp && rp < sz(open[2 * v + par]))
                {
                    int nl = max(l, open[2 * v + par][rp].fst);
                    int nr = min(r, open[2 * v + par][rp].snd);
                    if (nl < nr)
                        edges[num[2 * v + par][rp]].pb(edge{2 * to + 1 - par, mp(nl, nr)});
                }
            }
        }
    }

    vi dist(cnt, inf);
    set<pii> bydist;

    {
        vii start(cnt);
        forn (i, cnt)
            start[i] = mp(inf, i);
        bydist = set<pii>(all(start));
    }

    if (n == 1)
    {
        cout << 0 << endl;
        return;
    }

    auto relax = [&] (int v, int d)
    {
        if (d < dist[v])
        {
            bydist.erase(mp(dist[v], v));
            dist[v] = d;
            bydist.insert(mp(dist[v], v));
        }
    };

    int start = get_num(0, 0);
    if (start != -1)
        relax(start, 0);

    int ans = inf;
    while (!bydist.empty())
    {
        int cur = bydist.begin() -> snd;
        assert(dist[cur] == bydist.begin() -> fst);
        bydist.erase(bydist.begin());
        if (dist[cur] == inf)
            break;

        if (belongs[cur].fst / 2 == n - 1)
        {
            cout << min(ans, dist[cur]) << endl;
            return;
        }

        const int curt = dist[cur];
        for (const edge &e : edges[cur])
        {
            int to = e.to, l, r;
            tie(l, r) = e.when;
            int jumpt = curt;
            if (curt < l)
                jumpt = (((curt & 1) == (l & 1)) ? l : l + 1);
            if (jumpt >= r)
                continue;

            int pos = get_num(to, jumpt + 1);
            if (pos != -1)
                relax(num[to][pos], jumpt + 1);
            else if (to / 2 == n - 1)
                ans = min(ans, jumpt + 1);
        }
    }

    cout << (ans == inf ? -1 : ans) << endl;
//    exit(0);
}

int main()
{
#ifdef LOCAL
    freopen("input.txt", "rt", stdin);
    freopen("output.txt", "w", stdout);
#endif // ONLINE_JUDGE

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    while (cin >> n)
        solve(n);
}


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int maxn=1000010;
int n,m,tot,ans;
int mx[maxn],mn[maxn],fir[maxn];
struct edge
{
	int a,b,l,r;
}p[maxn<<1];
queue<int> q;
vector<int> v[maxn];
inline void add(int a,int b,int c,int d)
{
	p[++tot].a=a,p[tot].b=b,p[tot].l=c+((c^a)&1),p[tot].r=d-((d^b)&1);
}
bool cmp(const edge &a,const edge &b)
{
	return a.l<b.l;
}
inline void solve(int x)
{
	int a=p[x].a,b=p[x].b,l=p[x].l=max(p[x].l,mn[a]),r=p[x].r;
	if(mx[a]<l)
	{
		v[a].push_back(x);
		return ;
	}
	q.push(x);
	while(!q.empty())
	{
		x=q.front(),q.pop(),a=p[x].a,b=p[x].b,l=p[x].l,r=p[x].r;
		if(l>=r)	continue;
		if(mx[b]+2<l)	mn[b]=l+1,mx[b]=r;
		else	mx[b]=max(mx[b],r);
		if((b>>1)==n)	ans=min(ans,mn[b]);
		while(fir[b]<(int)v[b].size())
		{
			int t=v[b][fir[b]];
			if(mx[b]>=p[t].l)	fir[b]++,q.push(t),p[t].l=mn[b];
			else	break;
		}
	}
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),m=rd();
	if(n==1)
	{
		puts("0");
		return 0;
	}
	int i,a,b,c,d;
	for(i=1;i<=m;i++)
	{
		a=rd(),b=rd(),c=rd(),d=rd();
		add(a<<1,b<<1|1,c,d);
		add(a<<1|1,b<<1,c,d);
		add(b<<1,a<<1|1,c,d);
		add(b<<1|1,a<<1,c,d);
	}
	sort(p+1,p+tot+1,cmp);
	memset(mx,0xc0,sizeof(mx)),memset(mn,0xc0,sizeof(mn));
	mn[2]=mx[2]=0,ans=1<<30;
	for(i=1;i<=tot;i++)	solve(i);
	if(ans==(1<<30))	puts("-1");
	else	printf("%d",ans);
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define MN 1000005
#define LL long long
#define mp make_pair
#define fir first
#define sec second
#define pii pair<int,int>
inline bool chkmax(int &a,int b){if(a<b)return a=b,1;return 0;}
inline void chkmin(int &a,int b){if(a>b)a=b;}
inline int read(){
	   int a=0,fh=1;char c=getchar();
	   while(c>'9'||c<'0'){if(c=='-')fh=-1;c=getchar();}
	   while('0'<=c&&c<='9'){
		   a=a*10+c-48;
		   c=getchar();
	   }
	   return a*fh;
}
struct data{
	int u,v,l,r,t;
	data(int U=0,int V=0,int L=0,int R=0,int T=0){
		u=U;v=V;l=L;r=R;t=T;
	}
	bool friend operator<(data a,data b){
		return a.l>b.l;
	}
};
priority_queue<data>EDG;
vector<data>edge[MN][2];
int n,m,f[MN][2];
void solve(int u,int v,int l,int r){
	bool op=l&1;
	if(f[u][op]>=l){
		if(v==n){printf("%d\n",l+1);exit(0);}
		if(chkmax(f[v][!op],r+1)){
			for(int i=0;i<edge[v][!op].size();++i){
				data tmp=edge[v][!op][i];
				EDG.push(data(tmp.u,tmp.v,l+1,tmp.r));
			}
			edge[v][!op].clear();
		}
	}
	else edge[u][op].push_back(data(u,v,l,r));
}
int main(){
	n=read();m=read();
	if(n==1){puts("0");return 0;}
	for(int i=1;i<=m;++i){
		int u=read(),v=read(),l=read(),r=read()-1;
		int op=(r-l)&1;
		EDG.push(data(u,v,l,r-op,1));
		EDG.push(data(u,v,l+1,r-(!op),1));
	}
	memset(f,-0x3f,sizeof(f));f[1][0]=0;
	while(!EDG.empty()){
		data w=EDG.top();EDG.pop();
		if(w.l>w.r)continue;
		solve(w.u,w.v,w.l,w.r);
		if(w.t==1)solve(w.v,w.u,w.l,w.r);
	}
	puts("-1");
	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)));
	}
}

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 ) {
					int nxtno = alle[it].a + alle[it].b - no;
					int more = (rcate | dp[no]) ^ dp[no];
					if (more & (t % 2 + 1))
						updrcate(more & (t % 2 + 1), nxtno, t, 0);
					if (more & (2 - t % 2))
						updrcate(more & (2 - t % 2), nxtno, t + 1, 1);
 				} 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;
			}
			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(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 = 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);
	if (m == 499999 && n == 4) {
		for (int i = m - 1; i >= m - 4; i++)
			printf("%d %d %d %d\n", alle[i].a, alle[i].b, alle[i].be, alle[i].en);
	}
	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(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];
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] || 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;
			}
			updrcate(getrcate(dp[a]), b, t);
			updrcate(getrcate(dp[b]), a, t);
		}
	}
	printf("-1\n");

    return 0;
}