#include <bits/stdc++.h>
#include<unordered_map>
using namespace std;

using VS = vector<string>;    using LL = long long;
using VI = vector<int>;       using VVI = vector<VI>;
using PII = pair<int, int>;   using PLL = pair<LL, LL>;
using VL = vector<LL>;        using VVL = vector<VL>;

#define ALL(a)  begin((a)),end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))
#define UNIQ(c) (c).erase(unique(ALL((c))), end((c)))
#define FOR(i, s, e) for (int(i) = (s); (i) < (e); (i)++)
#define FORR(i, s, e) for (int(i) = (s); (i) > (e); (i)--)
//#pragma GCC optimize ("-O3") 
#ifdef YANG33
#include "mydebug.hpp"
#else
#define DD(x) 
#endif
const int INF = 1e9;                          const LL LINF = 1e16;
const LL MOD = 1000000007;                    const double PI = acos(-1.0);
int DX[8] = { 0, 0, 1, -1, 1, 1, -1, -1 };    int DY[8] = { 1, -1, 0, 0, 1, -1, 1, -1 };

/* -----  __MAKE_TIME__  Problem: __PROBLEM__ / Link: __CONTEST_URL__  ----- */
/* ------問題------



-----問題ここまで----- */
/* -----解説等-----



----解説ここまで---- */

struct UnionFind {
	vector<int> data;
	UnionFind() {}
	UnionFind(int n) { data.assign(n, -1); }
	bool unionSet(int x, int y) {
		x = root(x); y = root(y);
		if (x != y) {
			if (data[y] < data[x]) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
		return x != y;
	}
	bool same(int x, int y) { return root(x) == root(y); }
	int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
	int size(int x) { return -data[root(x)]; }
	void initV(int x) { data[x] = -1; }
};


UnionFind uf(1e5);
vector<vector<PII>> f(const vector<PII>&edge) {
	for (const auto& it : edge) {
		uf.initV(it.first);
		uf.initV(it.second);
	}
	for (const auto& it : edge) {
		uf.unionSet(it.first, it.second);
	}
	int rootid = 0;
	unordered_map<int, int>roots; // mapでもたいしてかわらない
	for (const auto& it : edge) {
		if (roots.find(uf.root(it.first)) == roots.end()) {
			roots[uf.root(it.first)] = rootid++;
		}
	}

	vector<vector<PII>>res(rootid);
	for (const auto& it : edge) {
		res[roots[uf.root(it.first)]].push_back(it);
	}
	return res;

}


VI Dijkstra(vector<vector<PII>>& G, int s) {// BFS
	VI dist(SZ(G), INF);
	dist[s] = 0;
	queue<PII> que;
	que.push(PII(0, s));

	while (!que.empty()) {
		PII p = que.front(); que.pop();
		int v; /* 頂点*/ int d; /* 頂点vまでの距離 */
		tie(d, v) = p;

		FOR(i, 0, (int)G[v].size()) {
			int nv = G[v][i].first;
			if (dist[nv] > dist[v] + G[v][i].second) {
				dist[nv] = dist[v] + G[v][i].second;
				que.push(PII(dist[nv], nv));
			}
		}
	}
	return dist;
}
int read() { int in; scanf("%d", &in); return in; }
const int Max = 1e6;
vector<PII>Cedge[Max];
int main() {
	LL N = read(), M = read();

	FOR(i, 0, M) {
		int p = read() - 1, q = read() - 1, c = read() - 1;
		Cedge[c].push_back(PII(p, q));
	}
	vector<vector<PII>>G(N + M);
	int cid = N;
	FOR(c, 0, 1e6) {
		auto res = f(Cedge[c]);
		for (auto subedges : res) {
			for (auto e : subedges) {
				G[cid].push_back(PII(e.first, 1));
				G[e.first].push_back(PII(cid, 1));
				G[cid].push_back(PII(e.second, 1));
				G[e.second].push_back(PII(cid, 1));
			}
			cid++;
		}
	}
	auto res = Dijkstra(G, 0);
	LL ans = res[N - 1] / 2;
	if (ans == INF / 2)ans = -1;
	cout << ans << "\n";

	return 0;
}
#include <algorithm>
#include <iostream>
#include <vector>
#include <math.h>
#include <set>
#include <map>
#include <string>
#include <stack>
#include <queue>
#include <iomanip>
#include <numeric>
#include <tuple>
#include <bitset>
#include <complex>
#include <unistd.h>
#include <cassert>
#include <cctype>
#include <random>
#include <time.h>
#define _USE_MATH_DEFINES
#define _GLIBCXX_DEBUG
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> plglg;
typedef pair<double, ll> pdlg;
typedef tuple<int, int, int> tiii;
typedef tuple<ll, ll, ll> tlglglg;
typedef tuple<double, double, double> tddd;
typedef complex<double> xy_t;
typedef vector<ll> vll;
typedef vector< vector<ll> > matrix;
#define REP(i, x, y) for(ll i = (ll)x; i < (ll)y; i++)
#define DREP(i, x, y, d) for(ll i = (ll)x; i < (ll)y; i += (ll)d)
#define PER(i, x, y) for(ll i = (ll)x; i > (ll)y; i--)
#define DPER(i, x, y, d) for(ll i = (ll)x; i > (ll)y; i -= (ll)d)
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
double pi = 3.141592653589793;
ll mod = 1000000007;
int intmax = 2147483647;
int intmin = -2147483648;
ll llmax = 9223372036854775807;
ll llmin = -9223372036854775807;
int iinf = intmax / 8;
ll inf = llmax / 8;
double eps = 1e-12;

struct edge {
    ll to, cost;
};

int V;
vector<edge> G[1000000];
vector<edge> G2[1000000];
ll d[1000000];

void addedge(int st, int ed, ll co) {
    edge e;
    e.to = ed;
    e.cost = co;
    G[st].push_back(e);
}

void addedge2(int st, int ed, ll co) {
    edge e;
    e.to = ed;
    e.cost = co;
    G2[st].push_back(e);
}

ll ptlab[3000000];
map<plglg, ll> mp;

void BFS01(int n) {
    fill(d, d + V, llmax);
    deque<int> que;
    d[n] = 0;
    que.push_front(n);
    while (que.size() > 0) {
        int base = que.front();
        que.pop_front();
        int s = G[base].size();
        for (int i = 0; i < s; i++) {
            edge e = G[base][i];
            if (e.cost == 1 && d[e.to] > d[base] + 1) {
                d[e.to] = d[base] + 1;
                que.push_back(e.to);
            } else if (e.cost == 0 && d[e.to] > d[base]) {
                d[e.to] = d[base];
                que.push_front(e.to);
            }
        }
    }
}

int main() {
    ll N, M;
    cin >> N >> M;
    ll p[M], q[M], c[M];
    REP(i, 0, M) {
        cin >> p[i] >> q[i] >> c[i];
        addedge2(p[i] - 1, q[i] - 1, c[i]);
        addedge2(q[i] - 1, p[i] - 1, c[i]);
    }
    REP(i, 0, N) {
        mp[plglg(i, -1)] = i;
        ptlab[i] = i;
    }
    ll pt = N;
    REP(i, 0, N) {
        REP(j, 0, G2[i].size()) {
            edge e = G2[i][j];
            if (mp.count(plglg(e.to, e.cost)) == 0) {
                mp[plglg(e.to, e.cost)] = pt;
                ptlab[pt] = e.to;
                pt++;
            }
        }
    }
    V = pt;
    REP(i, N, pt) {
        ll label = ptlab[i];
        addedge(label, i, 1); 
    }
    REP(i, 0, N) {
        REP(j, 0, G2[i].size()) {
            edge e = G2[i][j];
            if (mp.count(plglg(i, e.cost)) == 1) {
                addedge(mp[plglg(i, e.cost)], mp[plglg(e.to, e.cost)], 0);
            }
            addedge(mp[plglg(e.to, e.cost)], ptlab[e.to], 0);
        }
    }
    BFS01(0);
    ll ans = d[N - 1];
    if (ans != llmax) {
        cout << ans << endl;
    } else {
        cout << -1 << endl;
    }
}
