#include <bits/stdc++.h>
using namespace std;
const int N = 100 * 1000 + 10;
vector<pair<long long, long long> > adj[N];
vector<int> nAdj[N];
int n, m;
const long long INF = 1e15;
int par[N];
vector<pair<pair<long long, long long>, int> > edges;
bool isGreat(pair<long long, long long> a, pair<long long, long long> b) {
  if (a.first > b.first)
    return true;
  else if (a.first == b.first)
    return a.second > b.second;
  return false;
}
vector<pair<long long, long long> > dijkstra(int s) {
  vector<pair<long long, long long> > d(N, {INF, INF});
  bool mark[N];
  fill(par, par + N, -1);
  fill(mark, mark + N, false);
  d[s] = {0, 0};
  priority_queue<pair<pair<long long, long long>, int>,
                 vector<pair<pair<long long, long long>, int> >,
                 greater<pair<pair<long long, long long>, int> > >
      pq;
  pq.push({d[s], s});
  int u;
  while (!pq.empty()) {
    u = pq.top().second;
    pq.pop();
    if (mark[u]) continue;
    mark[u] = true;
    for (auto to : adj[u]) {
      if (isGreat(d[to.first], {d[u].first + 1, d[u].second + 1 - to.second})) {
        d[to.first] = {d[u].first + 1, d[u].second + 1 - to.second};
        par[to.first] = u;
        pq.push({d[to.first], to.first});
      }
    }
  }
  return d;
}
bool isBroken(int u, int v) {
  int s = (adj[u].size() < adj[v].size()) ? u : v, d = (u == s) ? v : u;
  for (auto it : adj[s]) {
    if (it.first == d) {
      return it.second == 0;
    }
  }
}
bool inTree(int u, int v) {
  for (auto it : nAdj[u])
    if (it == v) return true;
  return false;
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cin >> n >> m;
  long long notWor = 0;
  for (int i = 0; i < m; i++) {
    int first, second, z;
    cin >> first >> second >> z;
    adj[first].push_back({second, z});
    adj[second].push_back({first, z});
    notWor += 1 - z;
  }
  vector<pair<long long, long long> > path = dijkstra(n);
  int u = 1;
  while (u != n) {
    nAdj[u].push_back(par[u]);
    nAdj[par[u]].push_back(u);
    if (isBroken(u, par[u])) {
      edges.push_back({{u, par[u]}, 1});
    }
    u = par[u];
  }
  for (int i = 1; i <= n; i++) {
    for (auto it : adj[i]) {
      int to = it.first;
      if (i < to && !inTree(i, to) && !isBroken(i, to))
        edges.push_back({{i, to}, 0});
    }
  }
  cout << edges.size() << "\n";
  for (auto it : edges) {
    cout << it.first.first << " " << it.first.second << " " << it.second
         << "\n";
  }
  return 0;
}
