
#include<bits/stdtr1c++.h>
using namespace std;
#pragma gcc optimize("O3")
#define D(x)    cout << #x " = " << (x) << endl
#define MAX     100001

int counter;

struct directed_graph{
    int n;
    vector<int> edge[MAX+5];
    vector<int> indx[MAX+5];

    short int clr[MAX+5];
    bool flag;

    inline directed_graph(int _n = 0){
        n = _n;
    }

    inline void addEdge(int u, int v){
        edge[u].push_back(v);
        indx[u].push_back(++counter);
    }

    inline void dfs(int idx)
    {
        if(clr[idx] == 1){
            flag = true;
            return;
        }
        if(flag == true) return;
        if(clr[idx]) return;

        clr[idx] = 1;
        for(auto x : edge[idx])
            dfs(x);

        clr[idx] = 2;
    }

    inline bool hasCycle(){

        flag = false;
        memset(clr, 0, sizeof(clr));

        for(int i = 1; i <= n; i++)
            if(clr[i] == 0)
                dfs(i);

        return flag;
    }

} dg, cmpg;

#define MAXLG       18
#define MAXN        100001

struct undirected_graph{
    int n, d[MAX+5];
    vector<int> edge[MAX+5], indx[MAX+5];
    bool vis[MAX+5];
    bool flag;
    int tab[MAXLG+2][MAXN+5];
    int par[MAXN+5];
    int lev[MAXN+5], stp;

    inline undirected_graph(int _n = 0){
        n = _n;
        memset(d, -1, sizeof(d));
    }

    inline void addEdge(int u, int v){
        edge[u].push_back(v);
        indx[u].push_back(++counter);

        edge[v].push_back(u);
        indx[v].push_back(++counter);
    }

    inline int bfs(int idx)
    {
        int mx = 0, ret = idx;
        queue<int> q;
        d[idx] = 0;

        q.push(idx);
        while(!q.empty())
        {
            int u = q.front(); q.pop();
            for(auto x : edge[u])
                if(d[x] == -1)
                {
                    d[x] = d[u] + 1;
                    q.push(x);
                    if(d[x] > mx){
                        mx = d[x];
                        ret = x;
                    }
                }
        }

        return ret;
    }

    inline void init_st(int n)
    {
        int idx;
        for(idx = 1; idx <= n; idx++)
            tab[0][idx] = par[idx];

        for(stp = 1; (1 << stp) < n; stp++)
            for(int idx = 1; idx <= n; idx++)
                if(tab[stp-1][idx] == -1) tab[stp][idx] = -1;
                else tab[stp][idx] = tab[stp-1][tab[stp-1][idx]];
        stp--;
    }

    inline int go(int cur, int gap, int pos)
    {
        if(!gap) return cur;
        if(gap & 1) return go(tab[pos][cur], gap/2, pos+1);
        return go(cur, gap/2, pos + 1);
    }

    inline int LCA(int u, int v)
    {
        if(lev[u] > lev[v]) swap(u, v);
        v = go(v, lev[v] - lev[u], 0);
        if(u == v) return v;

        int i;
        for(i = stp; i >= 0; i--)
            if(tab[i][u] != tab[i][v])
                u = tab[i][u], v = tab[i][v];

        assert(tab[0][u] > 0);
        return tab[0][u];
    }

    inline void dfs(int idx, int p, int lv)
    {
        lev[idx] = lv;
        par[idx] = p;

        for(auto x : edge[idx])
            if(x == p) continue;
            else dfs(x, idx, lv + 1);
    }

    inline int get_dist(int u, int v)
    {
        int _lca = LCA(u, v);
        return d[u] + d[v] - 2 * d[_lca];
    }

    inline void generate_st(int rt)
    {
        memset(d, -1, sizeof(d));
        bfs(rt);
        dfs(rt, -1, 0);
        init_st(n);
    }

} ug;

int par[MAX+5], n;
bool flag = false;
void init(int n) {for(int i = 1; i <= n; i++) par[i] = i;}
inline int find_par(int idx)
{
	while (par[idx] != idx){
		par[idx] = par[par[par[idx] ] ];
		idx = par[idx];
	}
	return par[idx];
}
inline void join(int u, int v)
{
    int pu = find_par(u);
    int pv = find_par(v);
    if(pu == pv)
    {
        flag = true;
        return;
    }
    par[pu] = pv;
    return;
}

bool vis[MAX+5];
vector<int> farthest[MAX+5];
tr1::unordered_map<long long , int > M;
int dp[MAX << 5], glb;

inline int F(int u, int v, int idx)
{
    //if(dp[idx] != -1) return dp[idx];

    int ret = 0;
    for(int i = 0; i < (int) dg.edge[v].size(); i++)
    {
        int x = dg.edge[v][i];
        int ns = dg.indx[v][i];

        if(x == u) continue;
        else ret = max(ret, 1 + F(v, x, ns));
    }

    for(int i = 0; i < (int) ug.edge[v].size(); i++)
    {
        int x = ug.edge[v][i];
        int ns = ug.indx[v][i];
        if(x == u || x == n + 1) continue;
        else ret = max(ret, 1 + F(v, x, ns));
    }

    return dp[idx] = ret;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    int i, j, k, u, v, w, m;

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

    init(n);
    ug = undirected_graph(n + 1);
    dg = directed_graph(n);
    cmpg = directed_graph(n);

    for(i = 1; i <= m; i++)
    {
        scanf("%d %d %d", &u, &v, &w);
        if(w == 1) dg.addEdge(u, v);
        if(w == 2)
        {
            ug.addEdge(u, v);
            join(u, v);
        }
    }

    for(i = 1; i <= n; i++)
        for(auto x : dg.edge[i])
            cmpg.addEdge(find_par(i), find_par(x));

    if(flag || dg.hasCycle() || cmpg.hasCycle())
    {
        puts("Infinite");
        return 0;
    }

    for(i = 1; i <= n; i++)
    {
        int p = find_par(i);
        if(vis[p]) continue;
        vis[p] = true;

        int x = ug.bfs(p);
        int y = ug.bfs(x);

        farthest[p].push_back(x);
        if(x != y) farthest[p].push_back(y);
    }

    memset(vis, 0, sizeof(vis));
    for(i = 1; i <= n; i++)
    {
        int p = find_par(i);
        if(vis[p]) continue;
        vis[p] = true;
        ug.addEdge(n + 1, p);
    }

    memset(dp, -1,sizeof(dp));
    ug.generate_st(n + 1);
    int ans = 0;
    for(i = 1; i <= n; i++)
        ans = max(ans, F(n + 1, i, counter + i));

    cout << ans << endl;
    return 0;
}