#include <bits/stdc++.h>
using namespace std;
bool debug;
template <typename T>
struct SSSP {
  int n, m;
  T MAX_VAL;
  vector<pair<T, int>> *adj;
  SSSP(int n) : n(n), m(0) {
    MAX_VAL = numeric_limits<T>::max();
    adj = (vector<pair<T, int>> *)malloc(sizeof(vector<pair<T, int>>) * n);
    for (int i = 0; i < n; ++i) new (adj + i) vector<pair<T, int>>;
  }
  ~SSSP() {
    for (int i = 0; i < n; ++i) adj[i].~vector<pair<T, int>>();
    free(adj);
  }
  void addEdge(int from, int to, T weight) {
    adj[from].push_back({weight, to});
    m++;
  }
  vector<T> dijkstra(int start) {
    set<pair<T, int>> pq;
    vector<T> dist(n, MAX_VAL);
    pq.insert({0, start});
    dist[start] = 0;
    while (!pq.empty()) {
      int curr = pq.begin()->second;
      pq.erase(pq.begin());
      for (auto v : adj[curr]) {
        if (dist[curr] + v.first < dist[v.second]) {
          pq.erase({dist[v.second], v.second});
          dist[v.second] = dist[curr] + v.first;
          pq.insert({dist[v.second], v.second});
        }
      }
    }
    return dist;
  }
  vector<T> bfs(int start) {
    vector<T> dist(n, MAX_VAL);
    dist[start] = 0;
    deque<int> mq;
    mq.push_back(start);
    while (!mq.empty()) {
      int curr = mq.front();
      mq.pop_front();
      for (pair<T, int> e : adj[curr]) {
        int next = e.second;
        int w = e.first;
        if (dist[curr] + w < dist[next]) {
          dist[next] = dist[curr] + w;
          if (w == 0) {
            mq.push_front(next);
          } else {
            mq.push_back(next);
          }
        }
      }
    }
    return dist;
  }
  vector<int> getPath(vector<T> distances, int start, int target) {
    vector<int> p = getParents(distances, start, target);
    return getPathFast(p, start, target);
  }
  vector<int> getParents(vector<T> distances, int start, int target) {
    vector<int> visited(n, false);
    visited[start] = true;
    vector<int> p(n, -1);
    queue<int> mq;
    mq.push(start);
    while (!mq.empty()) {
      int curr = mq.front();
      mq.pop();
      for (auto e : adj[curr]) {
        int to = e.second;
        T w = e.first;
        if (!visited[to] && distances[curr] + w == distances[to]) {
          visited[to] = true;
          mq.push(to);
          p[to] = curr;
        }
      }
    }
    return p;
  }
  vector<int> getPathFast(vector<int> parents, int start, int target) {
    vector<int> path = {target};
    while (target != start && target != -1) {
      target = parents[target];
      path.push_back(target);
    }
    if (target == -1) {
      return vector<int>();
    } else {
      reverse(path.begin(), path.end());
      return path;
    }
  }
};
int main(int argc, char *argv[]) {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  debug = 0;
  int n, m, u, v, w;
  cin >> n >> m;
  SSSP<int> sssp(n);
  vector<vector<pair<int, int>>> adj;
  adj.resize(n);
  for (int i = 0; i < m; i++) {
    cin >> u >> v >> w;
    u--, v--;
    sssp.addEdge(u, v, 1);
    sssp.addEdge(v, u, 1);
    adj[u].push_back({w, v});
    adj[v].push_back({w, u});
  }
  vector<int> std = sssp.bfs(0);
  vector<int> dts = sssp.bfs(n - 1);
  int shortestDist = std.back();
  if (debug) {
    cout << "std"
         << ": ";
    for (auto i : std) {
      cout << i << ' ';
    }
    cout << endl;
  }
  if (debug) {
    cout << "dts"
         << ": ";
    for (auto i : dts) {
      cout << i << ' ';
    }
    cout << endl;
  }
  int cnt = 0;
  SSSP<int> sssp2(n);
  for (int i = 0; i < n; i++) {
    for (pair<int, int> e : adj[i]) {
      if (std[i] + 1 + dts[e.second] == shortestDist) {
        if (debug) {
          cout << "i"
               << ": " << i << endl;
        }
        if (debug) {
          cout << "e.second"
               << ": " << e.second << endl;
        }
        if (debug) {
          cout << "(((e.first) == 1) ? 0 : 1)"
               << ": " << (((e.first) == 1) ? 0 : 1) << endl;
        }
        sssp2.addEdge(i, e.second, ((e.first) == 1) ? 0 : 1);
      }
    }
  }
  vector<int> distTree = sssp2.bfs(0);
  if (debug) {
    cout << "distTree"
         << ": ";
    for (auto i : distTree) {
      cout << i << ' ';
    }
    cout << endl;
  }
  vector<int> path = sssp2.getPath(distTree, 0, n - 1);
  set<pair<int, int>> usedEdges;
  for (int i = 1; i < path.size(); i++) {
    usedEdges.insert({min(path[i - 1], path[i]), max(path[i - 1], path[i])});
  }
  vector<tuple<int, int, int>> fixes;
  for (int i = 0; i < n; i++) {
    for (pair<int, int> e : adj[i]) {
      if (i < e.second) {
        if (usedEdges.count({i, e.second})) {
          if (e.first == 0) {
            fixes.push_back(make_tuple(i, e.second, 1));
          }
        } else {
          if (e.first == 1) {
            fixes.push_back(make_tuple(i, e.second, 0));
          }
        }
      }
    }
  }
  if (debug) {
    cout << "path"
         << ": ";
    for (auto i : path) {
      cout << i << ' ';
    }
    cout << endl;
  }
  cout << fixes.size() << endl;
  for (auto f : fixes) {
    cout << (get<0>(f) + 1) << ' ' << (get<1>(f) + 1) << ' ' << get<2>(f)
         << endl;
  }
  return 0;
}
