using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Breaking_Good
{
    internal class Program
    {
        private static readonly StreamReader reader = new StreamReader(Console.OpenStandardInput(1024*10), Encoding.ASCII, false, 1024*10);
        private static readonly StreamWriter writer = new StreamWriter(Console.OpenStandardOutput(1024*10), Encoding.ASCII, 1024*10);

        private static void Main(string[] args)
        {
            int n = Next();
            int m = Next();

            var nn = new List<Tuple<int, int>>[n];
            for (int i = 0; i < nn.Length; i++)
            {
                nn[i] = new List<Tuple<int, int>>(2);
            }

            var roads = new Tuple<int, int, int>[m];
            for (int i = 0; i < m; i++)
            {
                int a = Next() - 1;
                int b = Next() - 1;
                int c = 1 - Next();

                roads[i] = new Tuple<int, int, int>(a, b, c);

                nn[a].Add(new Tuple<int, int>(b, i));
                nn[b].Add(new Tuple<int, int>(a, i));
            }

            var dist = new int[n];
            var rep = new int[n];
            var from = new int[n];

            var q = new Queue<int>();
            q.Enqueue(0);
            dist[0] = 1;

            while (q.Count > 0)
            {
                int i = q.Dequeue();

                foreach (var t in nn[i])
                {
                    if (dist[t.Item1] == 0)
                    {
                        dist[t.Item1] = 1 + dist[i];
                        rep[t.Item1] = rep[i] + roads[t.Item2].Item3;
                        from[t.Item1] = t.Item2;

                        q.Enqueue(t.Item1);
                    }
                    else if (dist[t.Item1] == 1 + dist[i])
                    {
                        if (rep[t.Item1] > rep[i] + roads[t.Item2].Item3)
                        {
                            rep[t.Item1] = rep[i] + roads[t.Item2].Item3;
                            from[t.Item1] = t.Item2;
                        }
                    }
                }
            }

            var f = new bool[m];
            var ans = new List<Tuple<int, int, int>>();

            int index = n - 1;
            while (index != 0)
            {
                f[@from[index]] = true;

                if (roads[@from[index]].Item3 == 1)
                    ans.Add(roads[@from[index]]);

                index = index == roads[@from[index]].Item1 ? roads[@from[index]].Item2 : roads[@from[index]].Item1;
            }

            for (int i = 0; i < m; i++)
            {
                if (!f[i] && roads[i].Item3 == 0)
                    ans.Add(roads[i]);
            }

            writer.WriteLine(ans.Count);
            foreach (var t in ans)
            {
                writer.Write(t.Item1 + 1);
                writer.Write(' ');
                writer.Write(t.Item2+1);
                writer.Write(' ');
                writer.WriteLine(t.Item3);
            }

            writer.Flush();
        }

        private static int Next()
        {
            int c;
            int res = 0;
            do
            {
                c = reader.Read();
                if (c == -1)
                    return res;
            } while (c < '0' || c > '9');
            res = c - '0';
            while (true)
            {
                c = reader.Read();
                if (c < '0' || c > '9')
                    return res;
                res *= 10;
                res += c - '0';
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

// (づ°ω°)づﾐ★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solver
{
    public void Solve()
    {
        int n = ReadInt();
        int m = ReadInt();
        var a = ReadIntMatrix(m);

        var edges = Enumerable.Repeat(0, n).Select(x => new List<Tuple<int, bool, int>>()).ToArray();
        for (int i = 0; i < m; i++)
        {
            a[i][0]--;
            a[i][1]--;
            edges[a[i][0]].Add(Tuple.Create(a[i][1], a[i][2] == 1, i));
            edges[a[i][1]].Add(Tuple.Create(a[i][0], a[i][2] == 1, i));
        }

        var q = new Queue<int>();
        q.Enqueue(0);
        var d = Enumerable.Repeat(int.MaxValue / 2, n).ToArray();
        d[0] = 0;
        var p = new Tuple<int, int>[n];
        p[0] = Tuple.Create(0, 0);
        var dist = new int[n];

        while (q.Count > 0)
        {
            int x = q.Dequeue();
            foreach (var e in edges[x])
            {
                int nd = d[x] + (e.Item2 ? 0 : 1);
                if (p[e.Item1] == null)
                {
                    q.Enqueue(e.Item1);
                    dist[e.Item1] = dist[x] + 1;
                }
                if (d[e.Item1] > nd && dist[e.Item1] == dist[x] + 1)
                {
                    d[e.Item1] = nd;
                    p[e.Item1] = Tuple.Create(x, e.Item3);
                }
            }
        }

        var f = new bool[m];
        int c = n - 1;
        while (c > 0)
        {
            f[p[c].Item2] = true;
            c = p[c].Item1;
        }

        var ans = new List<Tuple<int, int, int>>();
        for (int i = 0; i < m; i++)
        {
            if (f[i] && a[i][2] == 0)
                ans.Add(Tuple.Create(a[i][0], a[i][1], 1));
            else if (!f[i] && a[i][2] == 1)
                ans.Add(Tuple.Create(a[i][0], a[i][1], 0));
        }

        Write(ans.Count);
        foreach (var t in ans)
            Write(t.Item1 + 1, t.Item2 + 1, t.Item3);
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;

    static void Main()
    {
#if DEBUG
        reader = new StreamReader("..\\..\\input.txt");
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("game.in");
        //writer = new StreamWriter("game.out");
#endif
        try
        {
            var thread = new Thread(new Solver().Solve, 1024 * 1024 * 256);
            thread.Start();
            thread.Join();
//            object result = new Solver().Solve();
//            if (result != null)
//                writer.WriteLine(result);
        }
        catch (Exception ex)
        {
#if DEBUG
            Console.WriteLine(ex);
#else
            Console.WriteLine(ex);
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write

    private static Queue<string> currentLineTokens = new Queue<string>();

    private static string[] ReadAndSplitLine()
    {
        return reader.ReadLine().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
    }

    public static string ReadToken()
    {
        while (currentLineTokens.Count == 0)
            currentLineTokens = new Queue<string>(ReadAndSplitLine());
        return currentLineTokens.Dequeue();
    }

    public static int ReadInt()
    {
        return int.Parse(ReadToken());
    }

    public static long ReadLong()
    {
        return long.Parse(ReadToken());
    }

    public static double ReadDouble()
    {
        return double.Parse(ReadToken(), CultureInfo.InvariantCulture);
    }

    public static int[] ReadIntArray()
    {
        return ReadAndSplitLine().Select(int.Parse).ToArray();
    }

    public static long[] ReadLongArray()
    {
        return ReadAndSplitLine().Select(long.Parse).ToArray();
    }

    public static double[] ReadDoubleArray()
    {
        return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray();
    }

    public static int[][] ReadIntMatrix(int numberOfRows)
    {
        int[][] matrix = new int[numberOfRows][];
        for (int i = 0; i < numberOfRows; i++)
            matrix[i] = ReadIntArray();
        return matrix;
    }

    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows);
        int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++)
        {
            ret[i] = new int[numberOfRows];
            for (int j = 0; j < numberOfRows; j++)
                ret[i][j] = matrix[j][i];
        }
        return ret;
    }

    public static string[] ReadLines(int quantity)
    {
        string[] lines = new string[quantity];
        for (int i = 0; i < quantity; i++)
            lines[i] = reader.ReadLine().Trim();
        return lines;
    }

    public static void WriteArray<T>(IEnumerable<T> array)
    {
        writer.WriteLine(string.Join(" ", array));
    }

    public static void Write(params object[] array)
    {
        WriteArray(array);
    }

    public static void WriteLines<T>(IEnumerable<T> array)
    {
        foreach (var a in array)
            writer.WriteLine(a);
    }

    #endregion
}


using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Numerics;
using System.Text;

namespace contest
{

    class contest
    {

        static void Main(string[] args)
        {

            //var input = Console.ReadLine().Split().Select(int.Parse).ToArray();

            //int n = int.Parse(Console.ReadLine());
            //var num = Console.ReadLine().Split().Select(int.Parse).ToArray();
            //int n = num[0];
            //int m = num[1];

            //int n = int.Parse(Console.ReadLine());
            //var num = Console.ReadLine().Split().Select(int.Parse).ToArray();

            //var arr = new int[n][];
            //for(int i =0; i< n; i++)
            //{
            //    arr[i] = Console.ReadLine().Split().Select(int.Parse).ToArray();
            //}

            var num = Console.ReadLine().Split().Select(int.Parse).ToArray();
            int n = num[0];
            int m = num[1];
            var input = new int[m][];
            var road = new List<int>[n+1];
            for (int i = 0; i < n + 1; i++) road[i] = new List<int>();
            var dic = new Dictionary<Tuple<int, int>, int>();
            for(int i=0; i< m; i++)
            {
                input[i] = Console.ReadLine().Split().Select(int.Parse).ToArray();
                int a = input[i][0];
                int b = input[i][1];
                int c = input[i][2];
                road[a].Add(b);
                road[b].Add(a);
                dic[Tuple.Create(a, b)] = c;
                dic[Tuple.Create(b, a)] = c;
            }

            var ans = new List<int[]>();

            var len = Enumerable.Repeat(int.MaxValue, n+1).ToArray();
            var cntArr = Enumerable.Repeat(int.MaxValue, n+1).ToArray() ;
            var q = new Queue<int>();
            var ch = new bool[n + 1];
            var parent = new int[n + 1];
            q.Enqueue(1);
            ch[1] = true;
            ch[n] = true;
            len[1] = 0;
            parent[1] = 1;
            cntArr[1] = 0;

            while(q.Count()>0)
            {
                int cur = q.Dequeue();
                int l = len[cur];
                int cnt = cntArr[cur];

                foreach(int i in road[cur])
                {
                    int r = len[i];
                    int count = dic[Tuple.Create(cur, i)] == 0? cnt+1 : cnt;

                    if(i==n)
                    {

                        if(len[i]>l+1 || (len[i]==l+1 && cntArr[i]>count))
                        {
                            len[i] = l + 1;
                            parent[i] = cur;
                            cntArr[i] = count;
                        }

                    }
                    else if(!ch[i])
                    {
                        q.Enqueue(i);
                        ch[i] = true;
                        len[i] = l + 1;
                        parent[i] = cur;
                        cntArr[i] = count;
                    }
                    else if(r>l+1 || (len[i] == l + 1 && cntArr[i] > count))
                    {
                        q.Enqueue(i);
                        len[i] = l + 1;
                        parent[i] = cur;
                        cntArr[i] = count;
                    }
                }
            }

            int p2 = n;
            var set = new HashSet<Tuple<int, int>>();
            while (p2 != 1)
            {
                int p = parent[p2];
                set.Add(Tuple.Create(p,p2));
                p2 = parent[p2];
            }

            for(int i=0; i< m; i++)
            {
                int a = input[i][0];
                int b = input[i][1];
                int c = input[i][2];

                if((set.Contains(Tuple.Create(a,b))|| set.Contains(Tuple.Create(b,a)) )&& c==0)
                {
                    ans.Add(new int[] { a,b, 1});
                }
                else if((!set.Contains(Tuple.Create(a,b)) && !set.Contains(Tuple.Create(b,a))) && c==1)
                {
                    ans.Add(new int[] { a,b, 0});
                }
            }

            Console.WriteLine(ans.Count());
            for(int i=0; i<ans.Count(); i++)
            {
                Console.WriteLine(string.Join(" ",ans[i]));
            }

            //Console.WriteLine();

            Console.Read();

            Console.Read();

        }

    }

    class Segment
    {
        public int[] arr;

        public int n;

        public Segment(int m)
        {
            this.n = m;
            //arr = Enumerable.Range(0, n*2).ToArray();
            arr = new int[n * 4];

            for (int i = 0; i < n * 4; i++)
            {
                arr[i] = int.MaxValue;
            }

        }

        //public void update(int p, int value)
        //{  // set value at position p
        //    for (arr[p += n] = value; p > 1; p >>= 1) arr[p >> 1] = Math.Min( arr[p] , arr[p ^ 1]);
        //}

        //public void update(int i, int value)
        //{
        //    i += n / 2;
        //    arr[i] = value;
        //    for (; i > 1; i >>= 1)
        //        arr[i >> 1] = Math.Min(arr[i], arr[i ^ 1]);
        //}

        public void update(int i, int x)
        {
            //i = (n / 2) + i - 1;
            i = n + i - 1;
            arr[i] = x;

            while (i > 0)
            {
                i = (i - 1) / 2;
                arr[i] = Math.Min(arr[(i * 2) + 1], arr[(i * 2) + 2]);

                //if (arr[i * 2 + 1] > arr[i * 2 + 2])
                //{
                //    arr[i] = arr[i * 2 + 1];
                //}
                //else
                //{
                //    arr[i] = arr[i * 2 + 2];
                //}
                //arr[i] = arr[i * 2 + 1] + arr[i * 2 + 2];

            }

        }

        //call : query(a,b, 0, 0, n)
        public int query(int a, int b, int k, int l, int r)
        {
            if (r <= a || b <= l) return int.MaxValue;
            if (a <= l && r <= b) return arr[k];

            //return Math.Min(query(a, b, (k * 2) + 1, l, (l + r) / 2), query(a, b, (k * 2) + 2, (l + r) / 2, r));

            var vl = query(a, b, (k * 2) + 1, l, (l + r) / 2);
            var vr = query(a, b, (k * 2) + 2, (l + r) / 2, r);

            //var vl = query(a, b, (k << 1) + 1, l, (l + r) / 2);
            //var vr = query(a, b, (k + 1) << 1, (l + r) / 2, r);

            if (vl == int.MaxValue && vr == int.MaxValue) return 0;
            return Math.Min(vl, vr);

        }

        //public int query(int a, int b, int k, int l, int r)
        //{
        //    // query for arr[i..j]

        //    if (l > b || r < a)               // segment completely outside range
        //        return int.MaxValue;                       // represents a null node

        //    if (a <= l && b >= r)             // segment completely inside range
        //        return arr[k];

        //    int mid = l + (r - l) / 2;       // partial overlap of current segment and queried range. Recurse deeper.

        //    if (a > mid)
        //        return query(2 * k + 2, mid + 1, r, a, b);
        //    else if (b <= mid)
        //        return query(2 * k + 1, l, mid, a, b);

        //    int leftQuery = query(2 * k + 1, l, mid, a, mid);
        //    int rightQuery = query(2 * k + 2, mid + 1, r, mid + 1, b);

        //    // merge query results
        //    if (leftQuery == int.MaxValue && rightQuery == int.MaxValue) return 0;
        //    return Math.Min(leftQuery, rightQuery);

        //}

        //public int query(int l, int r)
        //{
        //    int res = int.MaxValue;
        //    for (l += n, r += n; l < r; l >>= 1, r >>= 1)
        //    {
        //        if ((l & 1) == 1) res = Math.Min(res, arr[l++]);
        //        if ((r & 1) == 1) res = Math.Min(res, arr[--r]);
        //    }
        //    return res;
        //}

        //public int query(int a, int b, int r)
        //{
        //    int res = int.MaxValue;
        //    for (a += r / 2, b += r / 2; a <= b; a = (a + 1) >> 1, b = (b - 1) >> 1)
        //    //for (; a <= b; a = (a + 1) >> 1, b = (b - 1) >> 1)
        //    {
        //        if ((a & 1) != 0)
        //            res = Math.Min(res, arr[a]);
        //        if ((b & 1) == 0)
        //            res = Math.Min(res, arr[b]);
        //    }
        //    return res;
        //}

        //public int query(int l, int r)
        //{  // sum on interval [l, r)
        //    int res = int.MaxValue;
        //    for (l += n, r += n; l < r; l >>= 1, r >>= 1)
        //    {
        //        if ((l & 1) == 1) res = Math.Min(res, arr[l++]);

        //        if ((r & 1) == 1) res = Math.Min(res, arr[--r]);
        //    }
        //    return res;
        //}

    }

    class UnionFind
    {
        public int[] path;
        //public int[] parent;
        //public int[] child;

        public UnionFind(int n)
        {
            path = new int[n + 1];
            //parent = new int[n];
            //child = new int[n];

            for (int i = 0; i < n + 1; i++)
            {
                path[i] = i;
                //parent[i] = i;
                //child[i] = i;
            }

        }

        private int root(int i)
        {
            while (i != path[i])
            {
                path[i] = path[path[i]];
                i = path[i];
            }
            return i;
        }

        public bool find(int p, int q)
        {
            return root(p) == root(q);
        }

        public void unite(int p, int q)
        {

            int i = root(p);
            int j = root(q);
            if (i < j)
            {

                int tmp = i;
                i = j;
                j = tmp;
            }
            path[i] = j;

            //    int t = p;
            //    while (path[parent[t]] != j)
            //    {
            //        path[path[t]] = j;
            //        t = parent[t];
            //    }

            //t = p;
            //while (path[child[t]] != j)
            //{
            //    path[path[t]] = j;
            //    t = child[t];
            //}

            //parent[q] = p;
        }

    }
}


import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.util.*
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

val MOD = 1_000_000_007L

data class Entry(val u: Int, val v: Int, val broken: Boolean)
data class Visit(val v: Int, val from: Int, val cost: Long)
data class Edge(val v: Int, val weight: Long)
class Solver(stream: InputStream, private val out: java.io.PrintWriter) {
  fun solve() {
    val N = ni()
    val M = ni()
    val E = Array(M){Entry(ni() - 1, ni() - 1, ni() == 0)}
    val g = Array(N){ mutableListOf<Edge>()}
    val OFFSET = 1e9.toLong()
    for (e in E) {
      val cost = OFFSET + (if (e.broken) 1 else 0)
      g[e.u].add(Edge(e.v, cost))
      g[e.v].add(Edge(e.u, cost))
    }

    val (_, path) = dijk(g, 0)
    debug(path)
    val shortest = mutableSetOf<Pair<Int, Int>>()
    var u = N - 1
    while(u != 0) {
      val v = path[u]
      shortest.add(Pair(min(u, v), max(u, v)))
      u = path[u]
    }
    debug{shortest.toString()}

    val ans = mutableListOf<Triple<Int, Int, Int>>()
    for (e in E) {
      val inShortest = shortest.contains(Pair(min(e.u, e.v), max(e.u, e.v)))
      if (e.broken && inShortest) {
        ans += Triple(e.u, e.v, 1)
      }
      if (!e.broken && !inShortest) {
        ans += Triple(e.u, e.v, 0)
      }
    }

    out.println(ans.size)
    for (i in ans) {
      out.println("${i.first + 1} ${i.second + 1} ${i.third}")
    }
  }

  val INF = 1e18.toLong()
  fun dijk(g: Array<MutableList<Edge>>, s: Int): Pair<LongArray, IntArray> {
    val D = LongArray(g.size){INF}
    D[s] = 0
    val path = IntArray(g.size)
    path[0] = -1
    val visited = BooleanArray(g.size)
    val que = PriorityQueue<Visit>(compareBy { it.cost })
    que.add(Visit(s, -1, 0))
    while(que.isNotEmpty()) {
      val v = que.poll()!!
      if (visited[v.v]) continue
      visited[v.v] = true
      path[v.v] = v.from

      for (i in 0 until g[v.v].size) {
        val e = g[v.v][i]
        if (v.cost + e.weight < D[e.v]) {
          D[e.v] = v.cost + e.weight
          que.add(Visit(e.v, v.v, D[e.v]))
        }
      }
    }
    return Pair(D, path)
  }

  private val isDebug = try {
    // なんか本番でエラーでる
    System.getenv("MY_DEBUG") != null
  } catch (t: Throwable) {
    false
  }

  private var tokenizer: StringTokenizer? = null
  private val reader = BufferedReader(InputStreamReader(stream), 32768)
  private fun next(): String {
    while (tokenizer == null || !tokenizer!!.hasMoreTokens()) {
      tokenizer = StringTokenizer(reader.readLine())
    }
    return tokenizer!!.nextToken()
  }

  private fun ni() = next().toInt()
  private fun nl() = next().toLong()
  private fun ns() = next()
  private fun na(n: Int, offset: Int = 0): IntArray {
    return map(n) { ni() + offset }
  }
  private fun nal(n: Int, offset: Int = 0): LongArray {
    val res = LongArray(n)
    for (i in 0 until n) {
      res[i] = nl() + offset
    }
    return res
  }

  private fun na2(n: Int, offset: Int = 0): Array<IntArray> {
    val a  = Array(2){IntArray(n)}
    for (i in 0 until n) {
      for (e in a) {
        e[i] = ni() + offset
      }
    }
    return a
  }

  private inline fun map(n: Int, f: (Int) -> Int): IntArray {
    val res = IntArray(n)
    for (i in 0 until n) {
      res[i] = f(i)
    }
    return res
  }

  private inline fun debug(msg: () -> String) {
    if (isDebug) System.err.println(msg())
  }

  private fun debug(a: LongArray) {
    debug { a.joinToString(" ") }
  }

  private fun debug(a: IntArray) {
    debug { a.joinToString(" ") }
  }

  private fun debug(a: BooleanArray) {
    debug { a.map { if (it) 1 else 0 }.joinToString("") }
  }

  private fun debugDim(A: Array<LongArray>) {
    if (isDebug) {
      for (a in A) {
        debug(a)
      }
    }
  }
  private fun debugDim(A: Array<IntArray>) {
    if (isDebug) {
      for (a in A) {
        debug(a)
      }
    }
  }

  /**
   * 勝手にimport消されるのを防ぎたい
   */
  private fun hoge() {
    min(1, 2)
    max(1, 2)
    abs(-10)
  }
}

fun main() {
  val out = java.io.PrintWriter(System.out)
  Solver(System.`in`, out).solve()
  out.flush()
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int v, z;
	Yal(int a, int b){v = a; z = b;}
	Yal(){};
};

vector<Yal> yal[N];
vector<Yal> par[N];

struct Mine{
	int u, dis;
	Mine(int a, int b){u = a; dis = b;}
	Mine(){};
};

bool mark[N];

int shortestPath = 1e9;
int n,m;

void ShortestPath()
{
	queue<Mine> q;
	q.push(Mine(1,0));
	while (!q.empty())
	{
		int dis = q.front().dis;
		int node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (!mark[v])
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
				if (v == n)
				{
					shortestPath = dis+1;
					return;
				}
			}
		}
	}
}

void BFS(int node)
{
	fill(mark, mark+n+1, 0);
	queue<Mine> q;
	q.push(Mine(node, 0));
	mark[node] = 1;
	while (!q.empty())
	{
		int dis = q.front().dis;
		node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath))
				par[v].push_back(Yal(node, z));
			if (!mark[v] && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
			}
		}
	}
}

vector<Yal> masir, ans;
int ans2 = 1e9;
void DFS(int node, int kharabi)
{
	if (node == 1)
	{
		if (kharabi < ans2)
		{
			ans2 = kharabi;
			ans = masir;
		}
		return;
	}
	for (int i = 0; i < par[node].size(); i++)
	{
		masir.push_back(par[node][i]);
		DFS(par[node][i].v, kharabi + (1-par[node][i].z));
		masir.pop_back();
	}
}

struct KhodEshYale{
	int u,v,z;
	KhodEshYale(int a, int b, int c){u = a; v = b; z = c;}
	KhodEshYale(){};
};

vector<KhodEshYale> input;
map< pair<int,int>, bool > M;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	for (int i = 0; i < m; i++)
	{
		int v,z,u;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(v, z));
		yal[v].push_back(Yal(u, z));
		input.push_back(KhodEshYale(u,v,z));
	}
	ShortestPath();
	BFS(1);
	DFS(n, 0);
	int last = n;
	vector<KhodEshYale> output;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i].z == 0)
			//cout << last << ' ' << ans[i].v << ' ' << 1 << endl;
				output.push_back(KhodEshYale(last, ans[i].v, 1));
		M[make_pair(last, ans[i].v)] = 1;
		M[make_pair(ans[i].v, last)] = 1;
		last = ans[i].v;
	}
	for (int i = 0; i < input.size(); i++)
	{
		if (M[make_pair(input[i].v, input[i].u)])
			continue;
		if (input[i].z == 1)
			//cout << input[i].u << ' ' << input[i].v << ' ' << 0 << endl;
				output.push_back(KhodEshYale(input[i].u, input[i].v, 0));
	}
	cout << output.size() << endl;
	for (int i = 0; i < output.size(); i++)
		cout << output[i].u << ' ' << output[i].v << ' ' << output[i].z << endl;
	//cout << n << ' ';
	//for(int i = 0; i < ans.size(); i++)
		//cout << ans[i].v << ' ';
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int u,v,z;
	Yal(int a, int b, int c){u = a; v = b; z = c;}
};

struct Data{
	int node;
	//int kharabi;
	int dist;
	Data(int n, int d)
	{
		node = n;
		//kharabi = k;
		dist = d;
	}
};

vector<Yal> yal[N];

int par[N], kharabi[N], dist[N];

int Size = 1e9, TARG;

bool mark[N];

void BFS(int node)
{
	fill(kharabi, kharabi+N, 1e9);
	fill(dist, dist+N, 1e9);
	queue<Data> q;
	q.push(Data(node, 0));
	mark[node] = 1;
	mark[TARG] = 1;
	kharabi[node] = 0;
	dist[node] = 0;
	while (!q.empty())
	{
		Data sar = q.front();
		q.pop();
		for (int i = 0; i < yal[sar.node].size(); i++)
		{
			int v = yal[sar.node][i].v;
			int z = yal[sar.node][i].z;
			if (v == TARG)
			{
				Size = min(Size, sar.dist+1);
				if (Size < sar.dist + 1)
					continue;
			}
			if (kharabi[sar.node]+(1-z) < kharabi[v] && (dist[v] >= sar.dist + 1))
				kharabi[v] = kharabi[sar.node]+(1-z), dist[v] = sar.dist + 1, par[v] = sar.node;
			if (!mark[v])
				q.push(Data(v, sar.dist+1)), mark[v] = 1;
		}
	}
}

map<pair<int,int>, bool> M;
vector<Yal> input;

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n,m;
	cin >> n >> m;
	TARG = n;
	for (int i = 0; i < m; i++)
	{
		int u,v,z;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(u,v,z));
		yal[v].push_back(Yal(v,u,z));
		input.push_back(Yal(v,u,z));
	}
	BFS(1);
	par[1] = -1;
	int now = n;
	while (par[now] != -1)
	{
		M[make_pair(now, par[now])] = 1;
		M[make_pair(par[now], now)] = 1;
		now = par[now];
	}
	string output;
	int S = 0;
	for (int i = 0; i < input.size(); i++)
	{
		bool f = 0;
		if (M[make_pair(input[i].v, input[i].u)])
			f = 1;
		if (f != input[i].z)
			S++, output += toString(input[i].u) + ' ' + toString(input[i].v) + ' ' + toString(!input[i].z) + '\n';
	}
	cout << S << endl << output;
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int v;
	bool z;
	Yal(int a, int b){v = a; z = b;}
	Yal(){};
};

vector<Yal> yal[N];
vector<Yal> par[N];

struct Mine{
	int u, dis;
	int dad;
	Mine(int a, int b){u = a; dis = b;}
	Mine(){};
};

bool mark[N];

int shortestPath = 1e9;
int n,m;

void ShortestPath()
{
	queue<Mine> q;
	q.push(Mine(1,0));
	while (!q.empty())
	{
		int dis = q.front().dis;
		int node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (!mark[v])
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
				if (v == n)
				{
					shortestPath = dis+1;
					return;
				}
			}
		}
	}
}

void BFS(int node)
{
	fill(mark, mark+n+1, 0);
	queue<Mine> q;
	q.push(Mine(node, 0));
	q.front().dad = -1;
	mark[node] = 1;
	int last = -1;
	while (!q.empty())
	{
		int dis = q.front().dis;
		node = q.front().u;
		last = q.front().dad;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (last != v && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
				par[v].push_back(Yal(node, z));
			if (!mark[v] && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
			{
				mark[v] = 1;
				Mine Q(v, dis+1);
				Q.dad = node;
				q.push(Q);
			}
		}
	}
}

vector<Yal> masir, ans;
int ans2 = 1e9;
Yal depth[N];
int mem[N];

int DFS(int node, int D)
{
	if (node == 1)
	{
		mem[1] = 0;
		depth[D] = Yal(1, 0);
	}
	if (mem[node] == -1)
	{
		int minimum = 1e9;
		int minIndex = 0;
		bool Zesh;
		mem[node] = 0;
		for (int i = 0; i < par[node].size(); i++)
		{
			int c = DFS(par[node][i].v, D + 1);
			if (c + (1-par[node][i].z) < minimum)
			{
				minimum = c + (1-par[node][i].z);
				minIndex = par[node][i].v;
				Zesh = par[node][i].z;
			}
		}
		mem[node] = minimum;
		depth[node] = Yal(minIndex, Zesh);
	}
	return mem[node];
}

struct KhodEshYale{
	int u,v;
	bool z;
	KhodEshYale(int a, int b, int c){u = a; v = b; z = c;}
	KhodEshYale(){};
};

vector<KhodEshYale> input;
map< pair<int,int>, bool > M;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	fill(mem, mem+n+1, -1);
	for (int i = 0; i < m; i++)
	{
		int v,z,u;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(v, z));
		yal[v].push_back(Yal(u, z));
		input.push_back(KhodEshYale(u,v,z));
	}
	ShortestPath();
	BFS(1);
	for (int i = 0; i < n; i++)
	{yal[i].erase(yal[i].begin(), yal[i].end()); yal[i].shrink_to_fit(); vector<Yal>().swap(yal[i]);}
	//if (n == 5078) cout << 1 << endl;
	mem[n] = DFS(n, 0);
	//if (n == 5078) cout << 10 << endl;
	//cout << 2 << endl;
	for (int i = 0; i < n; i++)
	{par[i].erase(par[i].begin(), par[i].end()); par[i].shrink_to_fit(); vector<Yal>().swap(par[i]);}
	masir.erase(masir.begin(), masir.end()); masir.shrink_to_fit();
	int last = n;
	ans.clear();
	depth[1] = Yal(-1, 1);
	int Node = n;
	while (Node != 1)
	{
		ans.push_back(depth[Node]);
		Node = depth[Node].v;
	}
	vector<KhodEshYale> output;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i].z == 0)
			//cout << last << ' ' << ans[i].v << ' ' << 1 << endl;
				output.push_back(KhodEshYale(last, ans[i].v, 1));
		M[make_pair(last, ans[i].v)] = 1;
		M[make_pair(ans[i].v, last)] = 1;
		last = ans[i].v;
	}
	for (int i = 0; i < input.size(); i++)
	{
		if (M[make_pair(input[i].v, input[i].u)])
			continue;
		if (input[i].z == 1)
			//cout << input[i].u << ' ' << input[i].v << ' ' << 0 << endl;
				output.push_back(KhodEshYale(input[i].u, input[i].v, 0));
	}
	cout << output.size() << endl;
	for (int i = 0; i < output.size(); i++)
		cout << output[i].u << ' ' << output[i].v << ' ' << output[i].z << endl;
	//cout << n << ' ';
	//for(int i = 0; i < ans.size(); i++)
		//cout << ans[i].v << ' ';
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int v;
	bool z;
	Yal(int a, int b){v = a; z = b;}
	Yal(){};
};

vector<Yal> yal[N];
vector<Yal> par[N];

struct Mine{
	int u, dis;
	int dad;
	Mine(int a, int b){u = a; dis = b;}
	Mine(){};
};

bool mark[N];

int shortestPath = 1e9;
int n,m;

void ShortestPath()
{
	queue<Mine> q;
	q.push(Mine(1,0));
	while (!q.empty())
	{
		int dis = q.front().dis;
		int node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (!mark[v])
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
				if (v == n)
				{
					shortestPath = dis+1;
					return;
				}
			}
		}
	}
}

void BFS(int node)
{
	fill(mark, mark+n+1, 0);
	queue<Mine> q;
	q.push(Mine(node, 0));
	q.front().dad = -1;
	mark[node] = 1;
	int last = -1;
	while (!q.empty())
	{
		int dis = q.front().dis;
		node = q.front().u;
		last = q.front().dad;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (last != v && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
				par[v].push_back(Yal(node, z));
			if (!mark[v] && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
			{
				mark[v] = 1;
				Mine Q(v, dis+1);
				Q.dad = node;
				q.push(Q);
			}
		}
	}
}

vector<Yal> masir, ans;
int ans2 = 1e9;
Yal depth[N];
int mem[N];

int DFS(int node, int D)
{
	if (node == 1)
	{
		mem[1] = 0;
		depth[D] = Yal(1, 0);
	}
	if (mem[node] == -1)
	{
		int minimum = 1e9;
		int minIndex = 0;
		bool Zesh;
		for (int i = 0; i < par[node].size(); i++)
		{
			int c = DFS(par[node][i].v, D + 1);
			if (c + (1-par[node][i].z) < minimum)
			{
				minimum = c + (1-par[node][i].z);
				minIndex = par[node][i].v;
				Zesh = par[node][i].z;
			}
		}
		mem[node] = minimum;
		depth[node] = Yal(minIndex, Zesh);
	}
	return mem[node];
}

struct KhodEshYale{
	int u,v;
	bool z;
	KhodEshYale(int a, int b, int c){u = a; v = b; z = c;}
	KhodEshYale(){};
};

vector<KhodEshYale> input;
map< pair<int,int>, bool > M;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	fill(mem, mem+n+1, -1);
	for (int i = 0; i < m; i++)
	{
		int v,z,u;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(v, z));
		yal[v].push_back(Yal(u, z));
		input.push_back(KhodEshYale(u,v,z));
	}
	ShortestPath();
	BFS(1);
	for (int i = 0; i < n; i++)
	{yal[i].erase(yal[i].begin(), yal[i].end()); yal[i].shrink_to_fit(); vector<Yal>().swap(yal[i]);}
	if (n == 5078) cout << 1 << endl;
	mem[n] = DFS(n, 0);
	if (n == 5078) cout << 10 << endl;
	//cout << 2 << endl;
	for (int i = 0; i < n; i++)
	{par[i].erase(par[i].begin(), par[i].end()); par[i].shrink_to_fit(); vector<Yal>().swap(par[i]);}
	masir.erase(masir.begin(), masir.end()); masir.shrink_to_fit();
	int last = n;
	ans.clear();
	depth[1] = Yal(-1, 1);
	int Node = n;
	while (Node != 1)
	{
		ans.push_back(depth[Node]);
		Node = depth[Node].v;
	}
	vector<KhodEshYale> output;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i].z == 0)
			//cout << last << ' ' << ans[i].v << ' ' << 1 << endl;
				output.push_back(KhodEshYale(last, ans[i].v, 1));
		M[make_pair(last, ans[i].v)] = 1;
		M[make_pair(ans[i].v, last)] = 1;
		last = ans[i].v;
	}
	for (int i = 0; i < input.size(); i++)
	{
		if (M[make_pair(input[i].v, input[i].u)])
			continue;
		if (input[i].z == 1)
			//cout << input[i].u << ' ' << input[i].v << ' ' << 0 << endl;
				output.push_back(KhodEshYale(input[i].u, input[i].v, 0));
	}
	cout << output.size() << endl;
	for (int i = 0; i < output.size(); i++)
		cout << output[i].u << ' ' << output[i].v << ' ' << output[i].z << endl;
	//cout << n << ' ';
	//for(int i = 0; i < ans.size(); i++)
		//cout << ans[i].v << ' ';
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int v, z;
	Yal(int a, int b){v = a; z = b;}
	Yal(){};
};

vector<Yal> yal[N];
vector<Yal> par[N];

struct Mine{
	int u, dis;
	Mine(int a, int b){u = a; dis = b;}
	Mine(){};
};

bool mark[N];

int shortestPath = 1e9;
int n,m;

void ShortestPath()
{
	queue<Mine> q;
	q.push(Mine(1,0));
	while (!q.empty())
	{
		int dis = q.front().dis;
		int node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (!mark[v])
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
				if (v == n)
				{
					shortestPath = dis+1;
					return;
				}
			}
		}
	}
}

void BFS(int node)
{
	fill(mark, mark+n+1, 0);
	queue<Mine> q;
	q.push(Mine(node, 0));
	mark[node] = 1;
	while (!q.empty())
	{
		int dis = q.front().dis;
		node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath))
				par[v].push_back(Yal(node, z));
			if (!mark[v] && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
			}
		}
	}
}

vector<Yal> masir, ans;
int ans2 = 1e9;
void DFS(int node, int kharabi)
{
	if (node == 1)
	{
		if (kharabi < ans2)
		{
			ans2 = kharabi;
			ans = masir;
		}
		return;
	}
	for (int i = 0; i < par[node].size(); i++)
	{
		masir.push_back(par[node][i]);
		DFS(par[node][i].v, kharabi + (1-par[node][i].z));
		masir.pop_back();
	}
}

struct KhodEshYale{
	int u,v,z;
	KhodEshYale(int a, int b, int c){u = a; v = b; z = c;}
	KhodEshYale(){};
};

vector<KhodEshYale> input;
map< pair<int,int>, bool > M;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	for (int i = 0; i < m; i++)
	{
		int v,z,u;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(v, z));
		yal[v].push_back(Yal(u, z));
		input.push_back(KhodEshYale(u,v,z));
	}
	ShortestPath();
	BFS(1);
	for (int i = 0; i < n; i++)
	{yal[i].erase(yal[i].begin(), yal[i].end()); yal[i].shrink_to_fit();}
	DFS(n, 0);
	for (int i = 0; i < n; i++)
	{par[i].erase(par[i].begin(), par[i].end()); par[i].shrink_to_fit();}
	masir.erase(masir.begin(), masir.end()); masir.shrink_to_fit();
	int last = n;
	vector<KhodEshYale> output;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i].z == 0)
			//cout << last << ' ' << ans[i].v << ' ' << 1 << endl;
				output.push_back(KhodEshYale(last, ans[i].v, 1));
		M[make_pair(last, ans[i].v)] = 1;
		M[make_pair(ans[i].v, last)] = 1;
		last = ans[i].v;
	}
	for (int i = 0; i < input.size(); i++)
	{
		if (M[make_pair(input[i].v, input[i].u)])
			continue;
		if (input[i].z == 1)
			//cout << input[i].u << ' ' << input[i].v << ' ' << 0 << endl;
				output.push_back(KhodEshYale(input[i].u, input[i].v, 0));
	}
	cout << output.size() << endl;
	for (int i = 0; i < output.size(); i++)
		cout << output[i].u << ' ' << output[i].v << ' ' << output[i].z << endl;
	//cout << n << ' ';
	//for(int i = 0; i < ans.size(); i++)
		//cout << ans[i].v << ' ';
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int v;
	bool z;
	Yal(int a, int b){v = a; z = b;}
	Yal(){};
};

vector<Yal> yal[N];
vector<Yal> par[N];

struct Mine{
	int u, dis;
	Mine(int a, int b){u = a; dis = b;}
	Mine(){};
};

bool mark[N];

int shortestPath = 1e9;
int n,m;

void ShortestPath()
{
	queue<Mine> q;
	q.push(Mine(1,0));
	while (!q.empty())
	{
		int dis = q.front().dis;
		int node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (!mark[v])
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
				if (v == n)
				{
					shortestPath = dis+1;
					return;
				}
			}
		}
	}
}

void BFS(int node)
{
	fill(mark, mark+n+1, 0);
	queue<Mine> q;
	q.push(Mine(node, 0));
	mark[node] = 1;
	while (!q.empty())
	{
		int dis = q.front().dis;
		node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath))
				par[v].push_back(Yal(node, z));
			if (!mark[v] && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
			}
		}
	}
}

vector<Yal> masir, ans;
int ans2 = 1e9;
void DFS(int node, int kharabi)
{
	if (node == 1)
	{
		if (kharabi < ans2)
		{
			ans2 = kharabi;
			ans = masir;
		}
		return;
	}
	for (int i = 0; i < par[node].size(); i++)
	{
		masir.push_back(par[node][i]);
		DFS(par[node][i].v, kharabi + (1-par[node][i].z));
		masir.pop_back();
	}
}

struct KhodEshYale{
	int u,v;
	bool z;
	KhodEshYale(int a, int b, int c){u = a; v = b; z = c;}
	KhodEshYale(){};
};

vector<KhodEshYale> input;
map< pair<int,int>, bool > M;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	for (int i = 0; i < m; i++)
	{
		int v,z,u;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(v, z));
		yal[v].push_back(Yal(u, z));
		input.push_back(KhodEshYale(u,v,z));
	}
	ShortestPath();
	BFS(1);
	for (int i = 0; i < n; i++)
	{yal[i].erase(yal[i].begin(), yal[i].end()); yal[i].shrink_to_fit();}
	DFS(n, 0);
	for (int i = 0; i < n; i++)
	{par[i].erase(par[i].begin(), par[i].end()); par[i].shrink_to_fit();}
	masir.erase(masir.begin(), masir.end()); masir.shrink_to_fit();
	int last = n;
	vector<KhodEshYale> output;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i].z == 0)
			//cout << last << ' ' << ans[i].v << ' ' << 1 << endl;
				output.push_back(KhodEshYale(last, ans[i].v, 1));
		M[make_pair(last, ans[i].v)] = 1;
		M[make_pair(ans[i].v, last)] = 1;
		last = ans[i].v;
	}
	for (int i = 0; i < input.size(); i++)
	{
		if (M[make_pair(input[i].v, input[i].u)])
			continue;
		if (input[i].z == 1)
			//cout << input[i].u << ' ' << input[i].v << ' ' << 0 << endl;
				output.push_back(KhodEshYale(input[i].u, input[i].v, 0));
	}
	cout << output.size() << endl;
	for (int i = 0; i < output.size(); i++)
		cout << output[i].u << ' ' << output[i].v << ' ' << output[i].z << endl;
	//cout << n << ' ';
	//for(int i = 0; i < ans.size(); i++)
		//cout << ans[i].v << ' ';
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int v;
	bool z;
	Yal(int a, int b){v = a; z = b;}
	Yal(){};
};

vector<Yal> yal[N];
vector<Yal> par[N];

struct Mine{
	int u, dis;
	int dad;
	Mine(int a, int b){u = a; dis = b;}
	Mine(){};
};

bool mark[N];

int shortestPath = 1e9;
int n,m;

void ShortestPath()
{
	queue<Mine> q;
	q.push(Mine(1,0));
	while (!q.empty())
	{
		int dis = q.front().dis;
		int node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (!mark[v])
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
				if (v == n)
				{
					shortestPath = dis+1;
					return;
				}
			}
		}
	}
}

void BFS(int node)
{
	fill(mark, mark+n+1, 0);
	queue<Mine> q;
	q.push(Mine(node, 0));
	q.front().dad = -1;
	mark[node] = 1;
	int last = -1;
	while (!q.empty())
	{
		int dis = q.front().dis;
		node = q.front().u;
		last = q.front().dad;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (last != v && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
				par[v].push_back(Yal(node, z));
			if (!mark[v] && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
			{
				mark[v] = 1;
				Mine Q(v, dis+1);
				Q.dad = node;
				q.push(Q);
			}
		}
	}
}

vector<Yal> masir, ans;
int ans2 = 1e9;
Yal depth[N];
int mem[N];

int DFS(int node, int D)
{
	if (node == 1)
	{
		mem[1] = 0;
		depth[D] = Yal(1, 0);
	}
	if (mem[node] == -1)
	{
		int minimum = 1e9;
		int minIndex = 0;
		bool Zesh;
		mem[node] = 8; // What the hell?!
		for (int i = 0; i < par[node].size(); i++)
		{
			int c = DFS(par[node][i].v, D + 1);
			if (c + (1-par[node][i].z) < minimum)
			{
				minimum = c + (1-par[node][i].z);
				minIndex = par[node][i].v;
				Zesh = par[node][i].z;
			}
		}
		mem[node] = minimum;
		depth[node] = Yal(minIndex, Zesh);
	}
	return mem[node];
}

struct KhodEshYale{
	int u,v;
	bool z;
	KhodEshYale(int a, int b, int c){u = a; v = b; z = c;}
	KhodEshYale(){};
};

vector<KhodEshYale> input;
map< pair<int,int>, bool > M;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	fill(mem, mem+n+1, -1);
	for (int i = 0; i < m; i++)
	{
		int v,z,u;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(v, z));
		yal[v].push_back(Yal(u, z));
		input.push_back(KhodEshYale(u,v,z));
	}
	ShortestPath();
	BFS(1);
	for (int i = 0; i < n; i++)
	{yal[i].erase(yal[i].begin(), yal[i].end()); yal[i].shrink_to_fit(); vector<Yal>().swap(yal[i]);}
	//if (n == 5078) cout << 1 << endl;
	mem[n] = DFS(n, 0);
	//if (n == 5078) cout << 10 << endl;
	//cout << 2 << endl;
	for (int i = 0; i < n; i++)
	{par[i].erase(par[i].begin(), par[i].end()); par[i].shrink_to_fit(); vector<Yal>().swap(par[i]);}
	masir.erase(masir.begin(), masir.end()); masir.shrink_to_fit();
	int last = n;
	ans.clear();
	depth[1] = Yal(-1, 1);
	int Node = n;
	while (Node != 1)
	{
		ans.push_back(depth[Node]);
		Node = depth[Node].v;
	}
	vector<KhodEshYale> output;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i].z == 0)
			//cout << last << ' ' << ans[i].v << ' ' << 1 << endl;
				output.push_back(KhodEshYale(last, ans[i].v, 1));
		M[make_pair(last, ans[i].v)] = 1;
		M[make_pair(ans[i].v, last)] = 1;
		last = ans[i].v;
	}
	for (int i = 0; i < input.size(); i++)
	{
		if (M[make_pair(input[i].v, input[i].u)])
			continue;
		if (input[i].z == 1)
			//cout << input[i].u << ' ' << input[i].v << ' ' << 0 << endl;
				output.push_back(KhodEshYale(input[i].u, input[i].v, 0));
	}
	cout << output.size() << endl;
	for (int i = 0; i < output.size(); i++)
		cout << output[i].u << ' ' << output[i].v << ' ' << output[i].z << endl;
	//cout << n << ' ';
	//for(int i = 0; i < ans.size(); i++)
		//cout << ans[i].v << ' ';
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int v;
	bool z;
	Yal(int a, int b){v = a; z = b;}
	Yal(){};
};

vector<Yal> yal[N];
vector<Yal> par[N];

struct Mine{
	int u, dis;
	int dad;
	Mine(int a, int b){u = a; dis = b;}
	Mine(){};
};

bool mark[N];

int shortestPath = 1e9;
int n,m;

void ShortestPath()
{
	queue<Mine> q;
	q.push(Mine(1,0));
	while (!q.empty())
	{
		int dis = q.front().dis;
		int node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (!mark[v])
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
				if (v == n)
				{
					shortestPath = dis+1;
					return;
				}
			}
		}
	}
}

void BFS(int node)
{
	fill(mark, mark+n+1, 0);
	queue<Mine> q;
	q.push(Mine(node, 0));
	q.front().dad = -1;
	mark[node] = 1;
	int last = -1;
	while (!q.empty())
	{
		int dis = q.front().dis;
		node = q.front().u;
		last = q.front().dad;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (last != v && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
				par[v].push_back(Yal(node, z));
			if (!mark[v] && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
			{
				mark[v] = 1;
				Mine Q(v, dis+1);
				Q.dad = node;
				q.push(Q);
			}
		}
	}
}

vector<Yal> masir, ans;
int ans2 = 1e9;
Yal depth[N];
int mem[N];

int DFS(int node, int D)
{
	if (node == 1)
	{
		mem[1] = 0;
		depth[D] = Yal(1, 0);
	}
	if (mem[node] == -1)
	{
		int minimum = 1e9;
		int minIndex = 0;
		bool Zesh;
		mem[node] = 8;
		for (int i = 0; i < par[node].size(); i++)
		{
			int c = DFS(par[node][i].v, D + 1);
			if (c + (1-par[node][i].z) < minimum)
			{
				minimum = c + (1-par[node][i].z);
				minIndex = par[node][i].v;
				Zesh = par[node][i].z;
			}
		}
		mem[node] = minimum;
		depth[node] = Yal(minIndex, Zesh);
	}
	return mem[node];
}

struct KhodEshYale{
	int u,v;
	bool z;
	KhodEshYale(int a, int b, int c){u = a; v = b; z = c;}
	KhodEshYale(){};
};

vector<KhodEshYale> input;
map< pair<int,int>, bool > M;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	fill(mem, mem+n+1, -1);
	for (int i = 0; i < m; i++)
	{
		int v,z,u;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(v, z));
		yal[v].push_back(Yal(u, z));
		input.push_back(KhodEshYale(u,v,z));
	}
	ShortestPath();
	BFS(1);
	for (int i = 0; i < n; i++)
	{yal[i].erase(yal[i].begin(), yal[i].end()); yal[i].shrink_to_fit(); vector<Yal>().swap(yal[i]);}
	if (n == 5078) cout << 1 << endl;
	mem[n] = DFS(n, 0);
	if (n == 5078) cout << 10 << endl;
	//cout << 2 << endl;
	for (int i = 0; i < n; i++)
	{par[i].erase(par[i].begin(), par[i].end()); par[i].shrink_to_fit(); vector<Yal>().swap(par[i]);}
	masir.erase(masir.begin(), masir.end()); masir.shrink_to_fit();
	int last = n;
	ans.clear();
	depth[1] = Yal(-1, 1);
	int Node = n;
	while (Node != 1)
	{
		ans.push_back(depth[Node]);
		Node = depth[Node].v;
	}
	vector<KhodEshYale> output;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i].z == 0)
			//cout << last << ' ' << ans[i].v << ' ' << 1 << endl;
				output.push_back(KhodEshYale(last, ans[i].v, 1));
		M[make_pair(last, ans[i].v)] = 1;
		M[make_pair(ans[i].v, last)] = 1;
		last = ans[i].v;
	}
	for (int i = 0; i < input.size(); i++)
	{
		if (M[make_pair(input[i].v, input[i].u)])
			continue;
		if (input[i].z == 1)
			//cout << input[i].u << ' ' << input[i].v << ' ' << 0 << endl;
				output.push_back(KhodEshYale(input[i].u, input[i].v, 0));
	}
	cout << output.size() << endl;
	for (int i = 0; i < output.size(); i++)
		cout << output[i].u << ' ' << output[i].v << ' ' << output[i].z << endl;
	//cout << n << ' ';
	//for(int i = 0; i < ans.size(); i++)
		//cout << ans[i].v << ' ';
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int v;
	bool z;
	Yal(int a, int b){v = a; z = b;}
	Yal(){};
};

vector<Yal> yal[N];
vector<Yal> par[N];

struct Mine{
	int u, dis;
	int dad;
	Mine(int a, int b){u = a; dis = b;}
	Mine(){};
};

bool mark[N];

int shortestPath = 1e9;
int n,m;

void ShortestPath()
{
	queue<Mine> q;
	q.push(Mine(1,0));
	while (!q.empty())
	{
		int dis = q.front().dis;
		int node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (!mark[v])
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
				if (v == n)
				{
					shortestPath = dis+1;
					return;
				}
			}
		}
	}
}

void BFS(int node)
{
	fill(mark, mark+n+1, 0);
	queue<Mine> q;
	q.push(Mine(node, 0));
	q.front().dad = -1;
	mark[node] = 1;
	int last = -1;
	while (!q.empty())
	{
		int dis = q.front().dis;
		node = q.front().u;
		last = q.front().dad;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (last != v && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
				par[v].push_back(Yal(node, z));
			if (!mark[v] && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
			{
				mark[v] = 1;
				Mine Q(v, dis+1);
				Q.dad = node;
				q.push(Q);
			}
		}
	}
}

vector<Yal> masir, ans;
int ans2 = 1e9;
Yal depth[N];
int mem[N];

int DFS(int node, int D)
{
	if (node == 1)
	{
		mem[1] = 0;
		depth[D] = Yal(1, 0);
	}
	if (mem[node] == -1)
	{
		int minimum = 1e9;
		int minIndex = 0;
		bool Zesh;
		for (int i = 0; i < par[node].size(); i++)
		{
			int c = DFS(par[node][i].v, D + 1);
			if (c + (1-par[node][i].z) < minimum)
			{
				minimum = c + (1-par[node][i].z);
				minIndex = par[node][i].v;
				Zesh = par[node][i].z;
			}
		}
		mem[node] = minimum;
		depth[node] = Yal(minIndex, Zesh);
	}
	return mem[node];
}

struct KhodEshYale{
	int u,v;
	bool z;
	KhodEshYale(int a, int b, int c){u = a; v = b; z = c;}
	KhodEshYale(){};
};

vector<KhodEshYale> input;
map< pair<int,int>, bool > M;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	fill(mem, mem+n+1, -1);
	for (int i = 0; i < m; i++)
	{
		int v,z,u;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(v, z));
		yal[v].push_back(Yal(u, z));
		input.push_back(KhodEshYale(u,v,z));
	}
	ShortestPath();
	BFS(1);
	for (int i = 0; i < n; i++)
	{yal[i].erase(yal[i].begin(), yal[i].end()); yal[i].shrink_to_fit(); vector<Yal>().swap(yal[i]);}
	mem[n] = DFS(n, 0);
	for (int i = 0; i < n; i++)
	{par[i].erase(par[i].begin(), par[i].end()); par[i].shrink_to_fit(); vector<Yal>().swap(par[i]);}
	masir.erase(masir.begin(), masir.end()); masir.shrink_to_fit();
	int last = n;
	ans.clear();
	depth[1] = Yal(-1, 1);
	int Node = n;
	while (Node != 1)
	{
		ans.push_back(depth[Node]);
		Node = depth[Node].v;
	}
	vector<KhodEshYale> output;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i].z == 0)
			//cout << last << ' ' << ans[i].v << ' ' << 1 << endl;
				output.push_back(KhodEshYale(last, ans[i].v, 1));
		M[make_pair(last, ans[i].v)] = 1;
		M[make_pair(ans[i].v, last)] = 1;
		last = ans[i].v;
	}
	for (int i = 0; i < input.size(); i++)
	{
		if (M[make_pair(input[i].v, input[i].u)])
			continue;
		if (input[i].z == 1)
			//cout << input[i].u << ' ' << input[i].v << ' ' << 0 << endl;
				output.push_back(KhodEshYale(input[i].u, input[i].v, 0));
	}
	cout << output.size() << endl;
	for (int i = 0; i < output.size(); i++)
		cout << output[i].u << ' ' << output[i].v << ' ' << output[i].z << endl;
	//cout << n << ' ';
	//for(int i = 0; i < ans.size(); i++)
		//cout << ans[i].v << ' ';
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int v;
	bool z;
	Yal(int a, int b){v = a; z = b;}
	Yal(){};
};

vector<Yal> yal[N];
vector<Yal> par[N];

struct Mine{
	int u, dis;
	int dad;
	Mine(int a, int b){u = a; dis = b;}
	Mine(){};
};

bool mark[N];

int shortestPath = 1e9;
int n,m;

void ShortestPath()
{
	queue<Mine> q;
	q.push(Mine(1,0));
	while (!q.empty())
	{
		int dis = q.front().dis;
		int node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (!mark[v])
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
				if (v == n)
				{
					shortestPath = dis+1;
					return;
				}
			}
		}
	}
}

void BFS(int node)
{
	fill(mark, mark+n+1, 0);
	queue<Mine> q;
	q.push(Mine(node, 0));
	q.front().dad = -1;
	mark[node] = 1;
	int last = -1;
	while (!q.empty())
	{
		int dis = q.front().dis;
		node = q.front().u;
		last = q.front().dad;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (last != v && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
				par[v].push_back(Yal(node, z));
			if (!mark[v] && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
			{
				mark[v] = 1;
				Mine Q(v, dis+1);
				Q.dad = node;
				q.push(Q);
			}
		}
	}
}

vector<Yal> masir, ans;
int ans2 = 1e9;
Yal depth[N];
int mem[N];

int DFS(int node, int D)
{
	if (node == 1)
	{
		mem[1] = 0;
		depth[D] = Yal(1, 0);
	}
	if (mem[node] == -1)
	{
		int minimum = 1e9;
		int minIndex = 0;
		bool Zesh;
		for (int i = 0; i < par[node].size(); i++)
		{
			int c = DFS(par[node][i].v, D + 1);
			if (c + (1-par[node][i].z) < minimum)
			{
				minimum = c + (1-par[node][i].z);
				minIndex = par[node][i].v;
				Zesh = par[node][i].z;
			}
		}
		mem[node] = minimum;
		depth[node] = Yal(minIndex, Zesh);
	}
	return mem[node];
}

struct KhodEshYale{
	int u,v;
	bool z;
	KhodEshYale(int a, int b, int c){u = a; v = b; z = c;}
	KhodEshYale(){};
};

vector<KhodEshYale> input;
map< pair<int,int>, bool > M;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	fill(mem, mem+n+1, -1);
	for (int i = 0; i < m; i++)
	{
		int v,z,u;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(v, z));
		yal[v].push_back(Yal(u, z));
		input.push_back(KhodEshYale(u,v,z));
	}
	ShortestPath();
	BFS(1);
	for (int i = 0; i < n; i++)
	{yal[i].erase(yal[i].begin(), yal[i].end()); yal[i].shrink_to_fit(); vector<Yal>().swap(yal[i]);}
	cout << 1 << endl;
	mem[n] = DFS(n, 0);
	cout << 2 << endl;
	for (int i = 0; i < n; i++)
	{par[i].erase(par[i].begin(), par[i].end()); par[i].shrink_to_fit(); vector<Yal>().swap(par[i]);}
	masir.erase(masir.begin(), masir.end()); masir.shrink_to_fit();
	int last = n;
	ans.clear();
	depth[1] = Yal(-1, 1);
	int Node = n;
	while (Node != 1)
	{
		ans.push_back(depth[Node]);
		Node = depth[Node].v;
	}
	vector<KhodEshYale> output;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i].z == 0)
			//cout << last << ' ' << ans[i].v << ' ' << 1 << endl;
				output.push_back(KhodEshYale(last, ans[i].v, 1));
		M[make_pair(last, ans[i].v)] = 1;
		M[make_pair(ans[i].v, last)] = 1;
		last = ans[i].v;
	}
	for (int i = 0; i < input.size(); i++)
	{
		if (M[make_pair(input[i].v, input[i].u)])
			continue;
		if (input[i].z == 1)
			//cout << input[i].u << ' ' << input[i].v << ' ' << 0 << endl;
				output.push_back(KhodEshYale(input[i].u, input[i].v, 0));
	}
	cout << output.size() << endl;
	for (int i = 0; i < output.size(); i++)
		cout << output[i].u << ' ' << output[i].v << ' ' << output[i].z << endl;
	//cout << n << ' ';
	//for(int i = 0; i < ans.size(); i++)
		//cout << ans[i].v << ' ';
}


#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(_m,s,e) for(int _m=s;_m<e;_m++)
typedef long long ll;
int  toInt(string s)   {int r=0; istringstream sin(s); sin>>r; return r;}
ll   toInt64(string s) {ll r=0; istringstream sin(s); sin>>r; return r;}
double  toDouble(string s){double r=0; istringstream sin(s); sin>>r; return r;}
string toString(ll n) {string s,s1; while (n / 10 > 0){ s += (char)((n%10) + 48); n/=10;} s += (char)((n%10) + 48); n/=10; s1 = s; rep(i,0,s.length()) s1[(s.length()-1)-i] = s[i]; return s1;}
bool isUpperCase(char c){return c >= 'A' && c <= 'Z';}
bool isLowerCase(char c){return c >= 'a' && c <= 'z';}
bool isLetter(char c)   {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';}
bool isDigit(char c)    {return c >= '0' && c <= '9';}
char toLowerCase(char c){return (isUpperCase(c))?(c + 32) : c;}
char toUpperCase(char c){return (isLowerCase(c))?(c - 32) : c;}
ll gcd(ll a, ll b) {if(!a) return b; return gcd(b%a, a);}

const int N = 1e5 + 10;

struct Yal{
	int v;
	bool z;
	Yal(int a, int b){v = a; z = b;}
	Yal(){};
};

vector<Yal> yal[N];
vector<Yal> par[N];

struct Mine{
	int u, dis;
	Mine(int a, int b){u = a; dis = b;}
	Mine(){};
};

bool mark[N];

int shortestPath = 1e9;
int n,m;

void ShortestPath()
{
	queue<Mine> q;
	q.push(Mine(1,0));
	while (!q.empty())
	{
		int dis = q.front().dis;
		int node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (!mark[v])
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
				if (v == n)
				{
					shortestPath = dis+1;
					return;
				}
			}
		}
	}
}

void BFS(int node)
{
	fill(mark, mark+n+1, 0);
	queue<Mine> q;
	q.push(Mine(node, 0));
	mark[node] = 1;
	while (!q.empty())
	{
		int dis = q.front().dis;
		node = q.front().u;
		q.pop();
		for (int i = 0; i < yal[node].size(); i++)
		{
			int v = yal[node][i].v;
			int z = yal[node][i].z;
			if (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath))
				par[v].push_back(Yal(node, z));
			if (!mark[v] && (dis + 1 < shortestPath || (v == n && dis+1 == shortestPath)))
			{
				mark[v] = 1;
				q.push(Mine(v, dis+1));
			}
		}
	}
}

vector<Yal> masir, ans;
int ans2 = 1e9;
void DFS(int node, int kharabi)
{
	if (node == 1)
	{
		if (kharabi < ans2)
		{
			ans2 = kharabi;
			ans = masir;
		}
		return;
	}
	for (int i = 0; i < par[node].size(); i++)
	{
		masir.push_back(par[node][i]);
		DFS(par[node][i].v, kharabi + (1-par[node][i].z));
		masir.pop_back();
	}
}

struct KhodEshYale{
	int u,v;
	bool z;
	KhodEshYale(int a, int b, int c){u = a; v = b; z = c;}
	KhodEshYale(){};
};

vector<KhodEshYale> input;
map< pair<int,int>, bool > M;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	for (int i = 0; i < m; i++)
	{
		int v,z,u;
		cin >> u >> v >> z;
		yal[u].push_back(Yal(v, z));
		yal[v].push_back(Yal(u, z));
		input.push_back(KhodEshYale(u,v,z));
	}
	ShortestPath();
	BFS(1);
	for (int i = 0; i < n; i++)
	{yal[i].erase(yal[i].begin(), yal[i].end()); yal[i].shrink_to_fit(); vector<Yal>().swap(yal[i]);}
	DFS(n, 0);
	for (int i = 0; i < n; i++)
	{par[i].erase(par[i].begin(), par[i].end()); par[i].shrink_to_fit(); vector<Yal>().swap(par[i]);}
	masir.erase(masir.begin(), masir.end()); masir.shrink_to_fit();
	int last = n;
	vector<KhodEshYale> output;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i].z == 0)
			//cout << last << ' ' << ans[i].v << ' ' << 1 << endl;
				output.push_back(KhodEshYale(last, ans[i].v, 1));
		M[make_pair(last, ans[i].v)] = 1;
		M[make_pair(ans[i].v, last)] = 1;
		last = ans[i].v;
	}
	for (int i = 0; i < input.size(); i++)
	{
		if (M[make_pair(input[i].v, input[i].u)])
			continue;
		if (input[i].z == 1)
			//cout << input[i].u << ' ' << input[i].v << ' ' << 0 << endl;
				output.push_back(KhodEshYale(input[i].u, input[i].v, 0));
	}
	cout << output.size() << endl;
	for (int i = 0; i < output.size(); i++)
		cout << output[i].u << ' ' << output[i].v << ' ' << output[i].z << endl;
	//cout << n << ' ';
	//for(int i = 0; i < ans.size(); i++)
		//cout << ans[i].v << ' ';
}


#include<bits/stdc++.h>
using namespace std;
vector<pair<int,int> >Edges[100009];
int Conn, Citys, OkCount;
bool ok[100009];
vector<pair<pair<int,int>,int> >Ds;
int main()
{
      ios_base::sync_with_stdio(false);
      cin.tie(0);
      cin>>Citys>>Conn;
      for(int i=0; i<Conn; i++)
      {
            int a,b,c;
            cin>>a>>b>>c;
            Edges[a].push_back({b,c});
            Edges[b].push_back({a,c});
            OkCount+=c;
            Ds.push_back({{a,b},c});
      }
      bool Visited[100009];
      memset(Visited,false,sizeof Visited);
      int ForSteps[100009];
      memset(ForSteps,0,sizeof ForSteps);
      queue<int>Q;
      while(Q.size()) Q.pop();
      Q.push(1);
      Visited[1] = true;
      while(Q.size())
      {
            int Now = Q.front();
            Q.pop();
            for(auto it :Edges[Now])
            {
                  int Ngo = it.first, State = it.second;
                  if(Visited[Ngo]) continue;
                  Visited[Ngo] = true;
                  ForSteps[Ngo] = ForSteps[Now]+1;
                  Q.push(Ngo);
            }
      }
      int BackSteps[100009];
      memset(BackSteps,0,sizeof BackSteps);
      memset(Visited,false,sizeof Visited);
      while(Q.size()) Q.pop();
      Q.push(Citys);
      Visited[Citys] =true;
      while(Q.size())
      {
            int Now = Q.front();
            Q.pop();
            for(auto it:Edges[Now])
            {
                  int Ngo = it.first, State = it.second;
                  if(Visited[Ngo]) continue;
                  Visited[Ngo] = true;
                  BackSteps[Ngo] = BackSteps[Now]+1;
                  Q.push(Ngo);
            }
      }
//      for(int i=1; i<=Citys; i++) cout<<ForSteps[i]<<" ";
//      cout<<endl;
//      for(int i=1; i<=Citys; i++) cout<<BackSteps[i]<<" ";
//      cout<<endl;
      memset(Visited,false,sizeof Visited);
      int OkRoads[100009],Parent[100009];
      memset(OkRoads,-1,sizeof OkRoads);
      while(Q.size()) Q.pop();
      Q.push(1);
//      Visited[1] = true;
      OkRoads[1] = 0;
      map<pair<int,int>,int > Mp;
      Mp.clear();
      while(Q.size())
      {
            int Now = Q.front();
            Q.pop();
//            cout<<Now<<endl; cout<<"     ";
//            if(Now == Citys) break;
            if(Visited[Now]) continue;
            Visited[Now]=true;
            for(auto it:Edges[Now])
            {
                  int Ngo = it.first, State = it.second;
                  if(Visited[Ngo]) continue;
//                  cout<<Ngo<<endl;
                  if(ForSteps[Ngo]+BackSteps[Ngo]!=ForSteps[Citys] || ForSteps[Now]+BackSteps[Ngo]+1!=ForSteps[Citys]) continue;
                  if(OkRoads[Ngo]!=-1 && OkRoads[Ngo]>=OkRoads[Now]+State) continue;
                  OkRoads[Ngo] = OkRoads[Now]+State;
//                  Visited[Ngo] = true;
                  Q.push(Ngo);
                  Parent[Ngo] = Now;
//                  Mp[ {Now,Ngo}] = Mp[ {Ngo,Now}] = 1;
//                  cout<<" Ac "<<Ngo<<endl;
            }
      }
      int Indx = Citys,tmp;
      while(Indx!=1)
      {
            tmp = Parent[Indx];
            Mp[{Indx,tmp}] = Mp[{tmp,Indx}] = 1;
//            cout<<"  From "<<Indx<<"  To "<<tmp<<endl;
            Indx = tmp;
      }
      cout<<OkCount+ForSteps[Citys]-2*OkRoads[Citys]<<endl;
      for(int i=0; i<Conn; i++)
      {
            int From = Ds[i].first.first, To = Ds[i].first.second , Cond = Ds[i].second;
            if(Mp.find({From,To})!= Mp.end())
            {
//                  cout<<"Used "<<From<<" "<<To<<" "<<Cond<<endl;
                  if(Cond == 0)
                  cout<<From<<" "<<To<<" "<<1<<endl;
            }
            else
            {
//                  cout<<"This was not in path  "<<From<<" "<<To<<" "<<Cond<<endl;
                  if(Cond==1)
                        cout<<From<<" "<<To<<" "<<!Cond<<endl;
            }
      }
      return 0;
}


#include<bits/stdc++.h>
using namespace std;
struct Data
{
      int From, To, State;
      Data() {}
      Data(int f,int t,int s)
      {
            From = f;
            To = t;
            State = s;
      }
};
vector<Data>DataSet(100009);
vector<pair<int,int> > Edges[100009];
int Citys, Connections;
map<pair<int,int>,int > ConnToIndex;
int ForwardBroken[100009], BackwardBroken[100009];
int ForwardSteps[100009],BackwardSteps[100009];
bool UsInFiPa[100009];
void FinalBFS()
{
      bool Visited[100009];
      memset(Visited,false,sizeof Visited);
      queue<int>Q;
      while(Q.size()) Q.pop();
      Visited[1] = true;
      Q.push(1);
      while(Q.size())
      {
            int Now = Q.front();
//            cout<<"Final Now "<<Now<<endl;
            if(Now == Citys) break;
            Q.pop();
            int minBroken = 2222222;
            int Nxtgo;
            for(auto NN : Edges[Now])
            {
                  int Nnxt = NN.first;
                  if(Visited[Nnxt]) continue;
//                  cout<<"    Next "<<Nnxt;
//                  Visited[Nnxt] = true;
                  if(ForwardBroken[Nnxt]+BackwardBroken[Nnxt] < minBroken && ForwardSteps[Nnxt]+BackwardSteps[Nnxt]==ForwardSteps[Citys])
                  {
                        Nxtgo = Nnxt;
                        minBroken = ForwardBroken[Nnxt]+BackwardBroken[Nnxt];
                  }
            }
            for(auto NN : Edges[Now])
            {
                  int nnn = NN.first;
                  if(Visited[nnn]) continue;
                  if( ForwardSteps[nnn]+BackwardSteps[nnn]==ForwardSteps[Citys] || ForwardSteps[Now]+1+BackwardSteps[nnn]==ForwardSteps[Citys])
                  {
                        Visited[nnn] = true;
                        Q.push(nnn);
                        int ConIndx = ConnToIndex[{Now,nnn}];
                        UsInFiPa[ConIndx] = true;
                        break;
                  }
            }
//            cout<<endl;
      }
//      for(int i=1;i<=Connections;i++)
//            if(UsInFiPa[i]) cout<<"  U "<<i;
//      cout<<endl;
      return;
}
void BakwardBFS()
{
      bool Visited[100009];
      int Steps[100009];
      memset(Steps,0,sizeof Steps);
      memset(Visited,false,sizeof Visited);
      for(int i=0; i<100009; i++) BackwardBroken[i] = 2222222;
      queue<pair<pair<int,int>,int> > Q;
      while(Q.size()) Q.pop();
      BackwardBroken[Citys] = 0;
      BackwardSteps[Citys] = 0;
      Visited[Citys] = true;
      Q.push({{Citys,0},0});
      while(Q.size())
      {
            auto var = Q.front();   /// First = cityIndex    Second = How many Broken   third = Steps
            Q.pop();
            int Now = var.first.first;
//            cout<<"Bakward Now "<<Now<<endl;
            int PathLen = var.second;
            for(auto NN : Edges[Now])
            {
                  int Next = NN.first;
                  int COnd = NN.second;
                  if(Visited[Next])
                  {
                        continue; /// Change this line
//                        cout<<"Pathlen +1 "<<PathLen+1<<"  Steps{next] "<<Steps[Next]<<endl;
                        if( PathLen+1 == Steps[Next])
                        {
//                              cout<<"Mul Vis"<<endl;
                              BackwardBroken[Next] = min(BackwardBroken[Next], BackwardBroken[Now]+!COnd);
                        }
                  }
                  else
                  {
                        Visited[Next] = true;
                        Steps[Next] = PathLen+1;
                        BackwardSteps[Next] = BackwardSteps[Now] +1;
                       /// if(Now == 4 && Next == 6) cout<<BackwardBroken[Next]<<"   "<<BackwardBroken[Now]<<"  "<<!COnd<<endl;
                        BackwardBroken[Next] = min(BackwardBroken[Next], BackwardBroken[Now]+!COnd);
                        Q.push({{Next,BackwardBroken[Now]},PathLen+1});
                  }
            }
      }
//      for(int i=1;i<=Citys;i++)
//            cout<<BackwardBroken[i]<<" ";
//      cout<<endl;
      return;
}
void ForwardBFS()
{
      bool Visited[100009];
      int Steps[100009];
      memset(Steps,0,sizeof Steps);
      memset(Visited,false,sizeof Visited);
      for(int i=0; i<100009; i++) ForwardBroken[i] = 2222222;
      queue<pair<pair<int,int>,int> > Q;
      while(Q.size()) Q.pop();
      ForwardBroken[1] = 0;
      ForwardSteps[1] = 0;
      Visited[1] = true;
      Q.push({{1,0},0});
      while(Q.size())
      {
            auto var = Q.front();   /// First = cityIndex    Second = How many Broken   third = Steps
            Q.pop();
            int Now = var.first.first;
//            cout<<"Forward Now "<<Now<<endl;
            int PathLen = var.second;
            for(auto NN : Edges[Now])
            {
                  int Next = NN.first;
                  int COnd = NN.second;
                  if(Visited[Next])
                  {
                        continue;  /// change this line
//                        cout<<"Pathlen +1 "<<PathLen+1<<"  Steps{next] "<<Steps[Next]<<endl;
                        if( PathLen+1 == Steps[Next])
                        {
//                              cout<<"Mul Vis"<<endl;
                              ForwardBroken[Next] = min(ForwardBroken[Next], ForwardBroken[Now]+!COnd);
                        }
                  }
                  else
                  {
                        Visited[Next] = true;
                        Steps[Next] = PathLen+1;
                        ForwardSteps[Next] = ForwardSteps[Now] +1;
                       /// if(Now == 4 && Next == 6) cout<<ForwardBroken[Next]<<"   "<<ForwardBroken[Now]<<"  "<<!COnd<<endl;
                        ForwardBroken[Next] = min(ForwardBroken[Next], ForwardBroken[Now]+!COnd);
                        Q.push({{Next,ForwardBroken[Now]},PathLen+1});
                  }
            }
      }
//      for(int i=1;i<=Citys;i++)
//            cout<<ForwardBroken[i]<<" ";
//      cout<<endl;
      return;
}
int main()
{
      cin.tie(0);
      ios_base::sync_with_stdio(false);
      cin>>Citys>>Connections;
      for(int i=1; i<=Connections; i++)
      {
            int f,t,s;
            cin>>f>>t>>s;
            DataSet[i]=(Data(f,t,s));
//            DataSet.emplace_back(Data(t,f,s));
            Edges[f].push_back(make_pair(t,s));
            Edges[t].push_back(make_pair(f,s));
            ConnToIndex[ {f,t}] = ConnToIndex[ {t,f}] = i;
      }
      ForwardBFS();
      BakwardBFS();
      FinalBFS();
      vector<Data> retu;
      for(int i=1;i<=Connections;i++)
      {
            if(UsInFiPa[i])
            {
                  if(DataSet[i].State == 0)
                        retu.emplace_back(Data(DataSet[i].From,DataSet[i].To,1));
            }
            else
            {
                  if(DataSet[i].State == 1)
                        retu.emplace_back(Data(DataSet[i].From,DataSet[i].To,0));
            }
      }
      cout<<retu.size()<<endl;
      for(int i=0;i<retu.size();i++)
            cout<<retu[i].From<<" "<<retu[i].To<<" "<<retu[i].State<<endl;
      return 0;
}
/**

10 10
1 6 1
6 7 1
7 8 0
8 9 0
9 10 0
1 2 0
2 3 0
3 4 1
4 5 1
5 10 1

4 6
1 2 1
2 3 0
1 2 0
3 4 1
2 3 1
3 4 0
**/


#include<bits/stdc++.h>
using namespace std;
struct Data
{
      int From, To, State;
      Data() {}
      Data(int f,int t,int s)
      {
            From = f;
            To = t;
            State = s;
      }
};
vector<Data>DataSet(100009);
vector<pair<int,int> > Edges[100009];
int Citys, Connections;
map<pair<int,int>,int > ConnToIndex;
int ForwardBroken[100009], BackwardBroken[100009];
int ForwardSteps[100009],BackwardSteps[100009];
bool UsInFiPa[100009];
void FinalBFS()
{
      bool Visited[100009];
      memset(Visited,false,sizeof Visited);
      queue<int>Q;
      while(Q.size()) Q.pop();
      Visited[1] = true;
      Q.push(1);
      while(Q.size())
      {
            int Now = Q.front();
//            cout<<"Final Now "<<Now<<endl;
            if(Now == Citys) break;
            Q.pop();
            int minBroken = 2222222;
            int Nxtgo;
            for(auto NN : Edges[Now])
            {
                  int Nnxt = NN.first;
                  if(Visited[Nnxt]) continue;
//                  cout<<"    Next "<<Nnxt;
//                  Visited[Nnxt] = true;
                  if(ForwardBroken[Nnxt]+BackwardBroken[Nnxt] < minBroken)
                  {
                        Nxtgo = Nnxt;
                        minBroken = ForwardBroken[Nnxt]+BackwardBroken[Nnxt];
                  }
            }
            for(auto NN : Edges[Now])
            {
                  int nnn = NN.first;
                  if(Visited[nnn]) continue;
                  if(ForwardBroken[nnn]+BackwardBroken[nnn] == minBroken && ForwardSteps[nnn]+BackwardSteps[nnn]==ForwardSteps[Citys])
                  {
                        Visited[nnn] = true;
                        Q.push(nnn);
                        int ConIndx = ConnToIndex[{Now,nnn}];
                        UsInFiPa[ConIndx] = true;
                        break;
                  }
            }
//            cout<<endl;
      }
//      for(int i=1;i<=Connections;i++)
//            if(UsInFiPa[i]) cout<<"  U "<<i;
//      cout<<endl;
      return;
}
void BakwardBFS()
{
      bool Visited[100009];
      int Steps[100009];
      memset(Steps,0,sizeof Steps);
      memset(Visited,false,sizeof Visited);
      for(int i=0; i<100009; i++) BackwardBroken[i] = 2222222;
      queue<pair<pair<int,int>,int> > Q;
      while(Q.size()) Q.pop();
      BackwardBroken[Citys] = 0;
      BackwardSteps[Citys] = 0;
      Visited[Citys] = true;
      Q.push({{Citys,0},0});
      while(Q.size())
      {
            auto var = Q.front();   /// First = cityIndex    Second = How many Broken   third = Steps
            Q.pop();
            int Now = var.first.first;
//            cout<<"Bakward Now "<<Now<<endl;
            int PathLen = var.second;
            for(auto NN : Edges[Now])
            {
                  int Next = NN.first;
                  int COnd = NN.second;
                  if(Visited[Next])
                  {
                        continue; /// Change this line
//                        cout<<"Pathlen +1 "<<PathLen+1<<"  Steps{next] "<<Steps[Next]<<endl;
                        if( PathLen+1 == Steps[Next])
                        {
//                              cout<<"Mul Vis"<<endl;
                              BackwardBroken[Next] = min(BackwardBroken[Next], BackwardBroken[Now]+!COnd);
                        }
                  }
                  else
                  {
                        Visited[Next] = true;
                        Steps[Next] = PathLen+1;
                        BackwardSteps[Next] = BackwardSteps[Now] +1;
                       /// if(Now == 4 && Next == 6) cout<<BackwardBroken[Next]<<"   "<<BackwardBroken[Now]<<"  "<<!COnd<<endl;
                        BackwardBroken[Next] = min(BackwardBroken[Next], BackwardBroken[Now]+!COnd);
                        Q.push({{Next,BackwardBroken[Now]},PathLen+1});
                  }
            }
      }
//      for(int i=1;i<=Citys;i++)
//            cout<<BackwardBroken[i]<<" ";
//      cout<<endl;
      return;
}
void ForwardBFS()
{
      bool Visited[100009];
      int Steps[100009];
      memset(Steps,0,sizeof Steps);
      memset(Visited,false,sizeof Visited);
      for(int i=0; i<100009; i++) ForwardBroken[i] = 2222222;
      queue<pair<pair<int,int>,int> > Q;
      while(Q.size()) Q.pop();
      ForwardBroken[1] = 0;
      ForwardSteps[1] = 0;
      Visited[1] = true;
      Q.push({{1,0},0});
      while(Q.size())
      {
            auto var = Q.front();   /// First = cityIndex    Second = How many Broken   third = Steps
            Q.pop();
            int Now = var.first.first;
//            cout<<"Forward Now "<<Now<<endl;
            int PathLen = var.second;
            for(auto NN : Edges[Now])
            {
                  int Next = NN.first;
                  int COnd = NN.second;
                  if(Visited[Next])
                  {
                        continue;  /// change this line
//                        cout<<"Pathlen +1 "<<PathLen+1<<"  Steps{next] "<<Steps[Next]<<endl;
                        if( PathLen+1 == Steps[Next])
                        {
//                              cout<<"Mul Vis"<<endl;
                              ForwardBroken[Next] = min(ForwardBroken[Next], ForwardBroken[Now]+!COnd);
                        }
                  }
                  else
                  {
                        Visited[Next] = true;
                        Steps[Next] = PathLen+1;
                        ForwardSteps[Next] = ForwardSteps[Now] +1;
                       /// if(Now == 4 && Next == 6) cout<<ForwardBroken[Next]<<"   "<<ForwardBroken[Now]<<"  "<<!COnd<<endl;
                        ForwardBroken[Next] = min(ForwardBroken[Next], ForwardBroken[Now]+!COnd);
                        Q.push({{Next,ForwardBroken[Now]},PathLen+1});
                  }
            }
      }
//      for(int i=1;i<=Citys;i++)
//            cout<<ForwardBroken[i]<<" ";
//      cout<<endl;
      return;
}
int main()
{
      cin.tie(0);
      ios_base::sync_with_stdio(false);
      cin>>Citys>>Connections;
      for(int i=1; i<=Connections; i++)
      {
            int f,t,s;
            cin>>f>>t>>s;
            DataSet[i]=(Data(f,t,s));
//            DataSet.emplace_back(Data(t,f,s));
            Edges[f].push_back(make_pair(t,s));
            Edges[t].push_back(make_pair(f,s));
            ConnToIndex[ {f,t}] = ConnToIndex[ {t,f}] = i;
      }
      ForwardBFS();
      BakwardBFS();
      FinalBFS();
      vector<Data> retu;
      for(int i=1;i<=Connections;i++)
      {
            if(UsInFiPa[i])
            {
                  if(DataSet[i].State == 0)
                        retu.emplace_back(Data(DataSet[i].From,DataSet[i].To,1));
                  continue;
            }
            else
            {
                  if(DataSet[i].State == 1)
                        retu.emplace_back(Data(DataSet[i].From,DataSet[i].To,0));
            }
      }
      cout<<retu.size()<<endl;
      for(int i=0;i<retu.size();i++)
            cout<<retu[i].From<<" "<<retu[i].To<<" "<<retu[i].State<<endl;
      return 0;
}
/**

10 10
1 6 1
6 7 1
7 8 0
8 9 0
9 10 0
1 2 0
2 3 0
3 4 1
4 5 1
5 10 1

4 6
1 2 1
2 3 0
1 2 0
3 4 1
2 3 1
3 4 0
**/


#include<bits/stdc++.h>
using namespace std;
struct Data
{
      int From, To, State;
      Data() {}
      Data(int f,int t,int s)
      {
            From = f;
            To = t;
            State = s;
      }
};
vector<Data>DataSet(100009);
vector<pair<int,int> > Edges[100009];
int Citys, Connections;
map<pair<int,int>,int > ConnToIndex;
int ForwardBroken[100009], BackwardBroken[100009];
int ForwardSteps[100009],BackwardSteps[100009];
bool UsInFiPa[100009];
void FinalBFS()
{
      bool Visited[100009];
      memset(Visited,false,sizeof Visited);
      queue<int>Q;
      while(Q.size()) Q.pop();
      Visited[1] = true;
      Q.push(1);
      while(Q.size())
      {
            int Now = Q.front();
//            cout<<"Final Now "<<Now<<endl;
            if(Now == Citys) break;
            Q.pop();
            int minBroken = 2222222;
            int Nxtgo;
            for(auto NN : Edges[Now])
            {
                  int Nnxt = NN.first;
                  if(Visited[Nnxt]) continue;
//                  cout<<"    Next "<<Nnxt;
//                  Visited[Nnxt] = true;
                  if(ForwardBroken[Nnxt]+BackwardBroken[Nnxt] < minBroken && ForwardSteps[Nnxt]+BackwardSteps[Nnxt]==ForwardSteps[Citys])
                  {
                        Nxtgo = Nnxt;
                        minBroken = ForwardBroken[Nnxt]+BackwardBroken[Nnxt];
                  }
            }
            for(auto NN : Edges[Now])
            {
                  int nnn = NN.first;
                  if(Visited[nnn]) continue;
                  if(ForwardBroken[nnn]+BackwardBroken[nnn]==minBroken && ForwardSteps[nnn]+BackwardSteps[nnn]==ForwardSteps[Citys])
                  {
                        Visited[nnn] = true;
                        Q.push(nnn);
                        int ConIndx = ConnToIndex[{Now,nnn}];
                        UsInFiPa[ConIndx] = true;
                        break;
                  }
            }
//            cout<<endl;
      }
//      for(int i=1;i<=Connections;i++)
//            if(UsInFiPa[i]) cout<<"  U "<<i;
//      cout<<endl;
      return;
}
void BakwardBFS()
{
      bool Visited[100009];
      int Steps[100009];
      memset(Steps,0,sizeof Steps);
      memset(Visited,false,sizeof Visited);
      for(int i=0; i<100009; i++) BackwardBroken[i] = 2222222;
      queue<pair<pair<int,int>,int> > Q;
      while(Q.size()) Q.pop();
      BackwardBroken[Citys] = 0;
      BackwardSteps[Citys] = 0;
      Visited[Citys] = true;
      Q.push({{Citys,0},0});
      while(Q.size())
      {
            auto var = Q.front();   /// First = cityIndex    Second = How many Broken   third = Steps
            Q.pop();
            int Now = var.first.first;
//            cout<<"Bakward Now "<<Now<<endl;
            int PathLen = var.second;
            for(auto NN : Edges[Now])
            {
                  int Next = NN.first;
                  int COnd = NN.second;
                  if(Visited[Next])
                  {
                        continue; /// Change this line
//                        cout<<"Pathlen +1 "<<PathLen+1<<"  Steps{next] "<<Steps[Next]<<endl;
                        if( PathLen+1 == Steps[Next])
                        {
//                              cout<<"Mul Vis"<<endl;
                              BackwardBroken[Next] = min(BackwardBroken[Next], BackwardBroken[Now]+!COnd);
                        }
                  }
                  else
                  {
                        Visited[Next] = true;
                        Steps[Next] = PathLen+1;
                        BackwardSteps[Next] = BackwardSteps[Now] +1;
                       /// if(Now == 4 && Next == 6) cout<<BackwardBroken[Next]<<"   "<<BackwardBroken[Now]<<"  "<<!COnd<<endl;
                        BackwardBroken[Next] = min(BackwardBroken[Next], BackwardBroken[Now]+!COnd);
                        Q.push({{Next,BackwardBroken[Now]},PathLen+1});
                  }
            }
      }
//      for(int i=1;i<=Citys;i++)
//            cout<<BackwardBroken[i]<<" ";
//      cout<<endl;
      return;
}
void ForwardBFS()
{
      bool Visited[100009];
      int Steps[100009];
      memset(Steps,0,sizeof Steps);
      memset(Visited,false,sizeof Visited);
      for(int i=0; i<100009; i++) ForwardBroken[i] = 2222222;
      queue<pair<pair<int,int>,int> > Q;
      while(Q.size()) Q.pop();
      ForwardBroken[1] = 0;
      ForwardSteps[1] = 0;
      Visited[1] = true;
      Q.push({{1,0},0});
      while(Q.size())
      {
            auto var = Q.front();   /// First = cityIndex    Second = How many Broken   third = Steps
            Q.pop();
            int Now = var.first.first;
//            cout<<"Forward Now "<<Now<<endl;
            int PathLen = var.second;
            for(auto NN : Edges[Now])
            {
                  int Next = NN.first;
                  int COnd = NN.second;
                  if(Visited[Next])
                  {
                        continue;  /// change this line
//                        cout<<"Pathlen +1 "<<PathLen+1<<"  Steps{next] "<<Steps[Next]<<endl;
                        if( PathLen+1 == Steps[Next])
                        {
//                              cout<<"Mul Vis"<<endl;
                              ForwardBroken[Next] = min(ForwardBroken[Next], ForwardBroken[Now]+!COnd);
                        }
                  }
                  else
                  {
                        Visited[Next] = true;
                        Steps[Next] = PathLen+1;
                        ForwardSteps[Next] = ForwardSteps[Now] +1;
                       /// if(Now == 4 && Next == 6) cout<<ForwardBroken[Next]<<"   "<<ForwardBroken[Now]<<"  "<<!COnd<<endl;
                        ForwardBroken[Next] = min(ForwardBroken[Next], ForwardBroken[Now]+!COnd);
                        Q.push({{Next,ForwardBroken[Now]},PathLen+1});
                  }
            }
      }
//      for(int i=1;i<=Citys;i++)
//            cout<<ForwardBroken[i]<<" ";
//      cout<<endl;
      return;
}
int main()
{
      cin.tie(0);
      ios_base::sync_with_stdio(false);
      cin>>Citys>>Connections;
      for(int i=1; i<=Connections; i++)
      {
            int f,t,s;
            cin>>f>>t>>s;
            DataSet[i]=(Data(f,t,s));
//            DataSet.emplace_back(Data(t,f,s));
            Edges[f].push_back(make_pair(t,s));
            Edges[t].push_back(make_pair(f,s));
            ConnToIndex[ {f,t}] = ConnToIndex[ {t,f}] = i;
      }
      ForwardBFS();
      BakwardBFS();
      FinalBFS();
      vector<Data> retu;
      for(int i=1;i<=Connections;i++)
      {
            if(UsInFiPa[i])
            {
                  if(DataSet[i].State == 0)
                        retu.emplace_back(Data(DataSet[i].From,DataSet[i].To,1));
            }
            else
            {
                  if(DataSet[i].State == 1)
                        retu.emplace_back(Data(DataSet[i].From,DataSet[i].To,0));
            }
      }
      cout<<retu.size()<<endl;
      for(int i=0;i<retu.size();i++)
            cout<<retu[i].From<<" "<<retu[i].To<<" "<<retu[i].State<<endl;
      return 0;
}
/**

10 10
1 6 1
6 7 1
7 8 0
8 9 0
9 10 0
1 2 0
2 3 0
3 4 1
4 5 1
5 10 1

4 6
1 2 1
2 3 0
1 2 0
3 4 1
2 3 1
3 4 0
**/