#include <bits/stdc++.h>
using namespace std;
struct Node {
  int node;
  int dist;
  int fixs;
  Node() {}
  Node(int node, int dist, int fixs) {
    this->node = node;
    this->dist = dist;
    this->fixs = fixs;
  }
};
int n;
int parentOf[100001];
int changesTo[100001];
int distanceTo[100001];
vector<Node> graph[100001];
set<pair<int, int> > toFix;
set<pair<int, int> > toBlow;
bool operator<(Node n1, Node n2) {
  if (n1.dist == n2.dist) return n1.fixs > n2.fixs;
  return n1.dist > n2.dist;
}
void DIJKSTRA(int source, int target) {
  int current;
  int newFixs;
  int newDist;
  priority_queue<Node> toVisit;
  for (int i = 0; i < n; i++) {
    parentOf[i] = -1;
    changesTo[i] = INT_MAX;
    distanceTo[i] = INT_MAX;
  }
  parentOf[source] = -2;
  changesTo[source] = 0;
  distanceTo[source] = 0;
  toVisit.push(Node(source, distanceTo[source], changesTo[source]));
  while (!toVisit.empty()) {
    current = toVisit.top().node;
    toVisit.pop();
    for (Node child : graph[current]) {
      newFixs = changesTo[current] + child.fixs;
      newDist = distanceTo[current] + child.dist;
      if (distanceTo[child.node] >= newDist) {
        if (distanceTo[child.node] > newDist) {
          parentOf[child.node] = current;
          changesTo[child.node] = newFixs;
          distanceTo[child.node] = newDist;
          toVisit.push(
              Node(child.node, distanceTo[child.node], changesTo[child.node]));
        } else if (changesTo[child.node] > newFixs) {
          parentOf[child.node] = current;
          changesTo[child.node] = newFixs;
          toVisit.push(
              Node(child.node, distanceTo[child.node], changesTo[child.node]));
        }
      }
    }
  }
}
void getRoads() {
  int node1;
  int node2;
  vector<pair<int, int> > fixes;
  node1 = n - 1;
  while (node1 != -2) {
    node2 = parentOf[node1];
    if (toFix.count({node1, node2}) != 0 || toFix.count({node2, node1}) != 0) {
      toFix.erase({node1, node2});
      toFix.erase({node2, node1});
      fixes.push_back({node1, node2});
    } else {
      toBlow.erase({node1, node2});
      toBlow.erase({node2, node1});
    }
    node1 = parentOf[node1];
  }
  printf("%d\n", fixes.size() + toBlow.size());
  for (pair<int, int> road : fixes)
    printf("%d %d %d\n", road.first + 1, road.second + 1, 1);
  for (pair<int, int> road : toBlow)
    printf("%d %d %d\n", road.first + 1, road.second + 1, 0);
}
int main() {
  int m;
  int x;
  int y;
  int z;
  scanf("%d", &n);
  scanf("%d", &m);
  for (int i = 0; i < m; i++) {
    scanf("%d", &x);
    scanf("%d", &y);
    scanf("%d", &z);
    x--;
    y--;
    z ^= 1;
    graph[x].push_back(Node(y, 1, z));
    graph[y].push_back(Node(x, 1, z));
    if (z == 1) {
      toFix.insert({x, y});
      toFix.insert({y, x});
    } else
      toBlow.insert({x, y});
  }
  DIJKSTRA(0, n - 1);
  getRoads();
}
