#include <bits/stdc++.h>
using namespace std;
int n, m, a, b, t, d[100005];
int total = 0, ans = 1 << 28, pathCost = 1 << 28;
bool v[100005], belongsPath[200005] = {0};
int from[200005], to[200005], nxt[200005], adj[200005], w[200005], e = 0;
vector<int> optimalPath, tmpPath;
struct node {
  int in, d;
  bool operator<(const node &x) const { return d > x.d; }
};
void add_edge(int a, int b, int type) {
  from[e] = a;
  to[e] = b;
  w[e] = type;
  nxt[e] = adj[a];
  adj[a] = e++;
}
bool relax(int relax, int target) {
  if (d[relax] + 1 < d[target]) {
    d[target] = d[relax] + 1;
    return true;
  }
  return false;
}
void dijkstra(int src) {
  for (int i = 0; i <= n; i++) d[i] = 1 << 28;
  d[src] = 0;
  priority_queue<node> pq;
  pq.push({src, d[src]});
  while (!pq.empty()) {
    int rin = pq.top().in, rd = pq.top().d;
    pq.pop();
    if (rin == n) break;
    if (v[rin]) continue;
    v[rin] = 1;
    for (int i = adj[rin]; i != -1; i = nxt[i])
      if (relax(rin, to[i])) pq.push({to[i], d[to[i]]});
  }
}
void dfs(int x, int c) {
  if (x == n) {
    if (c < pathCost) {
      pathCost = c;
      optimalPath = tmpPath;
    }
    return;
  }
  for (int i = adj[x]; i != -1; i = nxt[i]) {
    if (d[to[i]] == d[x] + 1 && c + !w[i] < pathCost) {
      tmpPath.push_back(i);
      dfs(to[i], c + !w[i]);
      tmpPath.pop_back();
    }
  }
}
int main() {
  memset(adj, -1, sizeof(adj));
  scanf("%d%d", &n, &m);
  for (int i = 0; i < m; i++) {
    scanf("%d%d%d", &a, &b, &t);
    add_edge(a, b, t);
    add_edge(b, a, t);
    total += t;
  }
  dijkstra(1);
  dfs(1, 0);
  printf("%d\n", total - d[n] + 2 * pathCost);
  for (int i = 0; i < optimalPath.size(); i++) belongsPath[optimalPath[i]] = 1;
  for (int i = 0; i < e; i += 2)
    if (belongsPath[i] | belongsPath[i + 1]) {
      if (!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
    } else {
      if (w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
    }
  return 0;
}
