#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

#define REP(i,n) for(int i=0;i<n;++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 1
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
#define MAX_N 100010

const pair<ll, bool> init_pair = make_pair(-LLINF, true);

// 始点 s の値を val としたときにグラフが成立するなら true を返す
bool check(const vector< vector< pair<ll, ll> > >& graph, ll N, ll s, ll val) {
    vector<ll> g2(N, -1);   // 各ノードに入っている値
    queue<ll> que;
    que.push(s);
    g2[s] = val;
    while(!que.empty()) {
        ll from = que.front();
        que.pop();
        for(auto& next_n : graph[from]) {
            ll to = next_n.first;
            ll cost = next_n.second;
            if(g2[to] == -1) {
                g2[to] = cost - g2[from];
                if(g2[to] <= 0) { return false; }
                que.push(to);
            } else {
                ll comp = cost - g2[from];
                if(comp != g2[to]) { return false; }
            }
        }
    }
    return true;
}

ll solve(ll N, ll M, const vector<ll>& U, const vector<ll>& V, const vector<ll>& S) {
    vector< vector< pair<ll, ll> > > graph(N, vector< pair<ll, ll> >());    // to, cost
    // 現在 i に課された条件
    // t : 始点に設定する値
    // second == bool -> (first + t) second == false -> (first - t)
    vector< pair<ll, bool> > cond(N, pair<ll, bool>());

    // 隣接リストの作成
    REP(i, M) {
        ll from, to, cost;
        from = U[i];
        to = V[i];
        cost = S[i];
        from--; to--;
        graph[from].push_back(make_pair(to, cost));
        graph[to].push_back(make_pair(from, cost));
    }
    REP(i, N) {
        cond[i] = init_pair;
    }

    // 適当な頂点を始点にして幅優先探索
    cond[0] = make_pair(0, true);  // 始まりのノードに設定する値を t と仮定
    vector<bool> isChecked(N, false);
    queue<ll> que;
    que.push(0);
    while(!que.empty()) {
        ll from = que.front();
        que.pop();
        isChecked[from] = true;
        for(auto& next_n : graph[from]) {
            ll to = next_n.first;
            ll cost = next_n.second;

            pair<ll, bool> next_cond;    // 辺の先のノードに設定したい条件
            next_cond.first = cost - cond[from].first;
            next_cond.second = !cond[from].second;
            if(cond[to] == init_pair) {
                // まだ条件が入っていない
                cond[to] = next_cond;
            }
            else {
                // すでに条件が入っている
                if(next_cond.second == cond[to].second) {
                    if(next_cond.first != cond[to].first) {
                        // パターンなし
                        return 0;
                    }
                }
                else {
                    // ノード to の値が確定する
                    ll val = (next_cond.first + cond[to].first) / 2;
                    // 確定した値でグラフがうまく回るか確認
                    if(check(graph, N, to, val)) {
                        return 1;
                    }
                    else { return 0; }
                }
            }

            if(!isChecked[to]) { que.push(to); }
        }
    }

    ll right = LLINF;
    ll left = 0;
    REP(i, N) {
        if(!cond[i].second) { right = min(right, cond[i].first - 1); }
        else { left = max(left, -cond[i].first); }
    }

    return max(0LL, right - left);
}

signed main()
{
    ll N, M;
    cin >> N >> M;
    vector<ll> U(M, 0);
    vector<ll> V(M, 0);
    vector<ll> S(M, 0);
    REP(i, M) {
        cin >> U[i] >> V[i] >> S[i];
    }
    ll ans = solve(N, M, U, V, S);
    printf("%lld\n", ans);
    return 0;
}


Measured memory_bytes: 12928