// Slower C++ solution:
/*

  mail: mleautomaton@foxmail.com

  author: MLEAutoMaton

  This Code is made by MLEAutoMaton

*/

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<math.h>

#include<algorithm>

#include<queue>

#include<set>

#include<map>

#include<iostream>

using namespace std;

#define ll long long

#define REP(a,b,c) for(int a=b;a<=c;a++)

#define re register

#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)

inline int gi(){

	int f=1,sum=0;char ch=getchar();

	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}

	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}

	return f*sum;

}

const int N=200010;

int f[N],n,m;

int dis[N],vis[N],front[N],cnt;

struct node{int to,nxt,w;}e[N<<1];

set<int>se[N];

queue<int>Q;

void Add(int u,int v,int w){e[++cnt]=(node){v,front[u],w};front[u]=cnt;}

int find(int x){if(f[x]!=x)f[x]=find(f[x]);return f[x];}

void SPFA(){

	Q.push(1);memset(dis,63,sizeof(dis));dis[1]=0;

	while(!Q.empty()){

		int u=Q.front();Q.pop();vis[u]=0;

		for(int i=front[u];i;i=e[i].nxt){

			int v=e[i].to,W;

			if(se[u].find(e[i].w)!=se[u].end())W=0;

			else W=1;

			if(dis[v]>dis[u]+W){

				dis[v]=dis[u]+W;se[v].clear();se[v].insert(e[i].w);

				if(!vis[v]){vis[v]=1;Q.push(v);}

			}

			else if(dis[v]==dis[u]+W){if(se[v].find(e[i].w)==se[v].end()){if(!vis[v]){vis[v]=1;Q.push(v);}}se[v].insert(e[i].w);}

		}

	}

}

int main(){

	n=gi();m=gi();

	for(int i=1;i<=n;i++)f[i]=i;

	for(int i=1;i<=m;i++){

		int u=gi(),v=gi(),w=gi();

		f[find(u)]=find(v);Add(u,v,w);Add(v,u,w);

	}

	if(find(1)!=find(n))return puts("-1"),0;

	SPFA();printf("%d\n",dis[n]==dis[n+1]?-1:dis[n]);

	return 0;

}


// Faster C++ solution for the same problem (measured speedup: 1.2523883941350966x):
///

/**

 * @Samaritan

 */

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;



#define pb emplace_back

#define fi first

#define se second

#define PII pair<int, int>

#define PLL pair<LL, LL>

#define PLI pair<LL, int>



LL quick_pow (LL a, LL b, LL mod) {

    LL ans = 1, base = a;

    while (b) {

        if (b & 1) (ans *= base) %= mod;

        b >>= 1;

        (base *= base) %= mod;

    }

    return ans;

}



inline int log2(const float &x) {

    return ((unsigned &) x >> 23 & 255) - 127;

}



void show(int arr[], int len) {

    for (int i = 0; i <= len; ++i) {

        cout << arr[i] << " ";

    }

    cout << endl;

}

struct node {

    int dif, id;

    node() {

    }

    node(int d, int i) : dif(d), id(i) {}

    bool operator < (const node& k) const {

        return dif < k.dif;

    }

};



const int mod = 998244353;

const int N = 1e5 + 5;

const int logN = 20;

const int INF = 0x3f3f3f3f;



vector<PII> edge[N];

int dist[N];

set<int> type[N];

//bool vis[N];



void work(int n) {

    priority_queue<PII, vector<PII>, greater<> > pq;

    memset(dist, INF, sizeof(dist));

//    memset(vis, 0, sizeof(vis[0]) * (n + 3));

    type[1].clear();

    dist[1] = 0;

    pq.push({0, 1});



    while(!pq.empty()) {

        int now = pq.top().se, ca = pq.top().fi;

        pq.pop();

        if (dist[now] < ca)continue;

        for (const auto &p : edge[now]) {

            {

                int to = p.first, to_com = p.second;

                int to_ca = ca + (!type[now].count(to_com));

                if (dist[to] > to_ca) {

                    dist[to] = to_ca;

                    pq.push({to_ca, to});

                    type[to].clear();

                    type[to].insert(to_com);

                } else if (dist[to] == to_ca) {

                    type[to].insert(to_com);

                }

            }

        }

    }

    return;

    while (!pq.empty()) {

        int pos = pq.top().second;

        int now_dist = pq.top().first;

        pq.pop();

//        if (vis[pos]) continue;

//        vis[pos] = true;

        if (now_dist > dist[pos]) continue;

        for (const auto& p : edge[pos]) {

            int to = p.first;

            int now_type = p.second;

            int now_val = dist[pos];

            if (!type[pos].count(now_type))

                now_val++;

            if (now_val < dist[to]) {

                dist[to] = now_val;

                type[to].clear();

                type[to].insert(now_type);



                pq.push({dist[to], to});

            } else if (now_val == dist[to]) {

                type[to].insert(now_type);

            }

        }

    }

}



int main() {

    int n, m;

    scanf("%d %d", &n, &m);

    for (int i = 0; i <= n; ++i)

        edge[i].clear();

    int l, r, c;

    for (int i = 0; i < m; ++i) {

        scanf("%d %d %d", &l, &r, &c);

        edge[l].pb(r, c);

        edge[r].pb(l, c);

    }

//    work(n);

    priority_queue<pair<int,int> >p;

    memset(dist, INF, sizeof dist);

    p.push({0,1});dist[1]=0;

    while(!p.empty())

    {

        int now=p.top().se,ca=-p.top().fi;

        p.pop();

        if(dist[now]<ca)continue;

        for (const auto& pp : edge[now])

//        for(i=h[now];i;i=e[i].nxt)

        {

            int to=pp.first,to_com=pp.second;

            int to_ca=ca+(!type[now].count(to_com));

            if(dist[to]>to_ca)

            {

                dist[to]=to_ca;

                p.push({-to_ca,to});

                type[to].clear();

                type[to].insert(to_com);

            }

            else if(dist[to]==to_ca)

            {

                type[to].insert(to_com);

            }

        }

    }

    if (dist[n] >= INF)

        puts("-1");

    else

        printf("%d\n", dist[n]);

    return 0;

}