#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(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
**/


#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
**/


#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <string>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <deque>
#include <algorithm>
#include <functional>
#include <iterator>
#include <limits>
#include <numeric>
#include <utility>
#include <cmath>
#include <cassert>

using namespace std; using namespace placeholders;

using LL = long long;
using ULL = unsigned long long;
using VI = vector< int >;
using VVI = vector< VI >;
using VS = vector< string >;
using SS = stringstream;
using PII = pair< int, int >;
using VPII = vector< PII >;
template < typename T = int > using VT = vector<T>;
template < typename T = int > using VVT = VT< VT<T> >;
template < typename T = int > using LIM = numeric_limits< T >;

template < typename T > inline istream& operator>>( istream &s, vector< T > &v ){ for ( T &t : v ) { s >> t; } return s; }
template < typename T > inline ostream& operator<<( ostream &s, const vector< T > &v ){ for ( int i=0; i<v.size(); ++i ){ s << (" "+!i) << v[i]; } return s; }
template < typename T > inline T fromString( const string &s ) { T res; istringstream iss( s ); iss >> res; return res; };
template < typename T > inline string toString( const T &a ) { ostringstream oss; oss << a; return oss.str(); };

#define REP( i, m, n ) for ( int i = ( int )( m ); i < ( int )( n ); ++i )
#define FOR( e, c ) for ( auto &e : c )
#define ALL( c ) ( c ).begin(), ( c ).end()
#define AALL( a, t ) ( t* )a, ( t* )a + sizeof( a ) / sizeof( t )
#define DRANGE( c, p ) ( c ).begin(), ( c ).begin() + p, ( c ).end()

#define SZ( v ) ( (int)( v ).size() )
#define PB push_back
#define EM emplace
#define EB emplace_back
#define BI back_inserter

#define EXIST( c, e ) ( ( c ).find( e ) != ( c ).end() )

#define MP make_pair
#define fst first
#define snd second

#define DUMP( x ) cerr << #x << " = " << ( x ) << endl

#include <cstdio>

constexpr int INF = LIM<>::max() / 2;

int main()
{
	int N, M;
	scanf( "%d %d", &N, &M );

	VI xs( M ), ys( M ), zs( M );
	REP( i, 0, M )
	{
		scanf( "%d %d %d", &xs[i], &ys[i], &zs[i] );
	}
	transform( ALL( xs ), xs.begin(), bind( minus< int >(), _1, 1 ) );
	transform( ALL( ys ), ys.begin(), bind( minus< int >(), _1, 1 ) );

	int ones = 0;
	VT< VPII > G( N );
	REP( i, 0, M )
	{
		ones += zs[i];

		G[ xs[i] ].EB( ys[i], zs[i] );
		G[ ys[i] ].EB( xs[i], zs[i] );
	}

	VPII distances( N, MP( INF, INF ) );
	distances[0] = MP( 0, ones );

	VI prev( N, -1 );

	using State = tuple< int, int, int >;

	priority_queue< State, VT< State >, greater< State > > que;
	que.EM( 0, 0, ones );

	while ( !que.empty() )
	{
		 const int u = get<0>( que.top() );
		 const int dist = get<1>( que.top() );
		 const int cost = get<2>( que.top() );
		 que.pop();

		 if ( distances[u] < MP( dist, cost ) )
		 {
			 continue;
		 }

		 FOR( e, G[u] )
		 {
			 const int v = e.fst;
			 const int c = e.snd;

			 const int nd = dist + 1;
			 const int nc = cost + ( c ? -1 : 1	);

			 const State next( v, nd, nc );
			 const PII p( nd, nc );
			 if ( p < distances[v] )
			 {
				 distances[v] = p;
				 prev[v] = u;
				 que.EM( next );
			 }
		 }
	}

	VT< bool > used( N );

	for ( int v = N - 1; v != -1; v = prev[v] )
	{
		used[v] = true;
	}

	VI res;
	REP( i, 0, M )
	{
		if ( used[ xs[i] ] && used[ ys[i] ] && !zs[i] || ( !used[ xs[i] ] || !used[ ys[i] ] ) && zs[i] )
		{
			res.PB( i );
		}
	}

	cout << SZ( res ) << endl;
	FOR( r, res )
	{
		printf( "%d %d %d\n", xs[r] + 1, ys[r] + 1, !zs[r] );
	}

	return 0;
}


#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <string>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <deque>
#include <algorithm>
#include <functional>
#include <iterator>
#include <limits>
#include <numeric>
#include <utility>
#include <cmath>
#include <cassert>

using namespace std; using namespace placeholders;

using LL = long long;
using ULL = unsigned long long;
using VI = vector< int >;
using VVI = vector< VI >;
using VS = vector< string >;
using SS = stringstream;
using PII = pair< int, int >;
using VPII = vector< PII >;
template < typename T = int > using VT = vector<T>;
template < typename T = int > using VVT = VT< VT<T> >;
template < typename T = int > using LIM = numeric_limits< T >;

template < typename T > inline istream& operator>>( istream &s, vector< T > &v ){ for ( T &t : v ) { s >> t; } return s; }
template < typename T > inline ostream& operator<<( ostream &s, const vector< T > &v ){ for ( int i=0; i<v.size(); ++i ){ s << (" "+!i) << v[i]; } return s; }
template < typename T > inline T fromString( const string &s ) { T res; istringstream iss( s ); iss >> res; return res; };
template < typename T > inline string toString( const T &a ) { ostringstream oss; oss << a; return oss.str(); };

#define REP( i, m, n ) for ( int i = ( int )( m ); i < ( int )( n ); ++i )
#define FOR( e, c ) for ( auto &e : c )
#define ALL( c ) ( c ).begin(), ( c ).end()
#define AALL( a, t ) ( t* )a, ( t* )a + sizeof( a ) / sizeof( t )
#define DRANGE( c, p ) ( c ).begin(), ( c ).begin() + p, ( c ).end()

#define SZ( v ) ( (int)( v ).size() )
#define PB push_back
#define EM emplace
#define EB emplace_back
#define BI back_inserter

#define EXIST( c, e ) ( ( c ).find( e ) != ( c ).end() )

#define MP make_pair
#define fst first
#define snd second

#define DUMP( x ) cerr << #x << " = " << ( x ) << endl

constexpr int INF = LIM<>::max() / 2;

int main()
{
	int N, M;
	scanf( "%d %d", &N, &M );

	VI xs( M ), ys( M ), zs( M );
	REP( i, 0, M )
	{
		scanf( "%d %d %d", &xs[i], &ys[i], &zs[i] );
	}
	transform( ALL( xs ), xs.begin(), bind( minus< int >(), _1, 1 ) );
	transform( ALL( ys ), ys.begin(), bind( minus< int >(), _1, 1 ) );

	int ones = 0;
	VT< VPII > G( N );
	REP( i, 0, M )
	{
		ones += zs[i];

		G[ xs[i] ].EB( ys[i], zs[i] );
		G[ ys[i] ].EB( xs[i], zs[i] );
	}

	VPII distances( N, MP( INF, INF ) );
	distances[0] = MP( 0, ones );

	VI prev( N, -1 );

	using State = tuple< int, int, int >;

	priority_queue< State, VT< State >, greater< State > > que;
	que.EM( 0, 0, ones );

	while ( !que.empty() )
	{
		 const int u = get<0>( que.top() );
		 const int dist = get<1>( que.top() );
		 const int cost = get<2>( que.top() );
		 que.pop();

		 if ( distances[u] < MP( dist, cost ) )
		 {
			 continue;
		 }

		 FOR( e, G[u] )
		 {
			 const int v = e.fst;
			 const int c = e.snd;

			 const int nd = dist + 1;
			 const int nc = cost + ( c ? -1 : 1	);

			 const State next( v, nd, nc );
			 const PII p( nd, nc );
			 if ( p < distances[v] )
			 {
				 distances[v] = p;
				 prev[v] = u;
				 que.EM( next );
			 }
		 }
	}

	VT< bool > used( N );

	for ( int v = N - 1; v != -1; v = prev[v] )
	{
		used[v] = true;
	}

	VI res;
	REP( i, 0, M )
	{
		if ( used[ xs[i] ] && used[ ys[i] ] && !zs[i] || ( !used[ xs[i] ] || !used[ ys[i] ] ) && zs[i] )
		{
			res.PB( i );
		}
	}

	cout << SZ( res ) << endl;
	FOR( r, res )
	{
		printf( "%d %d %d\n", xs[r] + 1, ys[r] + 1, !zs[r] );
	}

	return 0;
}


#include <bits/stdc++.h>
using namespace std;

const long long mul = 1e6, INF = 1e18;
const int N = 100100;
int n, m;
long long dist1[N], dist2[N];
vector<pair<int, long long> > G[N];
vector<pair<pair<int, int>, pair<int, long long> > > edges;

void dijkstra(int source, long long* dist)
{
  for(int i=0; i<n; i++)
    dist[i] = INF;
  dist[source] = 0;
  set<pair<long long, int> > Q;
  for(int i=0; i<n; i++)
    if(i != source)
      Q.insert({INF, i});
  Q.insert({0,source});
  while(!Q.empty())   {
    auto it = Q.begin();
    int x = it->second;
    Q.erase(it);
    for(auto i: G[x])    {
      long long v = i.first, w = i.second;
      if(dist[x] + w < dist[v]) {
        Q.erase(Q.find( {dist[v], v} ));
        dist[v] = dist[x] + w;
        Q.insert( {dist[v], v} );
      }
    }
  }
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n >> m;
    for(int i=0; i<m; i++)  {
        int u, v, w; long long x;
        cin >> u >> v >> w;
        --u; --v;
        if(w == 1)  {
            x = (long long)mul*mul - mul + (u + v);
        }   else    {
            x = (long long)mul*mul + mul + (u + v);
        }
        edges.push_back({{u,v},{w, x}});
        G[u].push_back({v, x});
        G[v].push_back({u, x});
    }
    dijkstra(n-1, dist2);
    dijkstra(0, dist1);

    vector<pair<pair<int, int> , int> > ans;
    for(auto edge: edges)   {
        long long u = edge.first.first, v = edge.first.second, w = edge.second.first, x = edge.second.second;
        if((dist1[u] + x + dist2[v] == dist1[n-1]) or (dist2[u] + x + dist1[v] == dist1[n-1]))  {
            if(w == 0)  {
                ans.push_back({{u+1, v+1}, 1});
            }
        }   else    {
            if(w == 1)  {
                ans.push_back({{u+1, v+1}, 0});
            }
        }
    }
    cout << ans.size() << "\n";
    for(auto el: ans)   {
        cout << el.first.first << " " << el.first.second << " " << el.second << "\n";
    }
}


#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <climits>
using namespace std;

struct Road {
	int src;
	int dest;
	int good;
};

Road roads[100000];
vector<int> g[100000];

int dist[100000];
int fixes[100000];
int history[100000];
int used[100000];

void solve(int start, int dest, int m) {
	fill(dist +start, dist + dest + 1, INT_MAX);

	set<pair<int, int>> q;

	dist[start] = 0;
	history[start] = -1;
	q.insert({ 0, start });

	while (!q.empty()) {
		int v = q.begin()->second;
		q.erase(q.begin());

		if (v == dest) break;

		for (int ri : g[v]) {
			auto& r = roads[ri];
			int rdest = r.dest == v ? r.src : r.dest;

			if (dist[v] + 1 < dist[rdest]) {
				q.erase({dist[rdest], rdest});

				dist[rdest] = dist[v] + 1;
				fixes[rdest] = fixes[v] + !r.good;
				history[rdest] = ri;

				q.insert({ dist[rdest], rdest });
			}
			else if (dist[v] + 1 == dist[rdest] && fixes[v] + !r.good < fixes[rdest]) {
				fixes[rdest] = fixes[v] + !r.good;
				history[ri] = ri;
			}
		}
	}

	for (int r = history[dest], v = dest; r != -1;) {
		used[r] = 1;
		v = roads[r].src == v ? roads[r].dest : roads[r].src;
		r = history[v];
	}

	vector<int> touched;
	for (int i = 0; i < m; ++i) {
		if (used[i] != roads[i].good) {
			touched.push_back(i);
		}
	}

	cout << touched.size() << endl;
	for (int i : touched) {
		cout << roads[i].src + 1 << ' ' << roads[i].dest + 1 << ' ' << !roads[i].good << endl;
	}
}

int main() {
	ios_base::sync_with_stdio(false);

	int n, m;
	cin >> n >> m;

	for (int i = 0; i < m; ++i) {
		int x, y, z;
		cin >> x >> y >> z;

		roads[i] = { --x, --y, z };

		g[x].push_back(i);
		g[y].push_back(i);
	}

	solve(0, n - 1, m);
}


#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <climits>
using namespace std;

struct Road {
	int src;
	int dest;
	int good;
};

Road roads[100000];
vector<int> g[100000];

int dist[100000];
int fixes[100000];
int history[100000];
int used[100000];

void solve(int start, int dest, int m) {
	fill(dist +start, dist + dest + 1, INT_MAX);

	set<pair<int, int>> q;

	history[start] = -1;
	q.insert({ 0, start });

	while (!q.empty()) {
		int v = q.begin()->second;
		q.erase(q.begin());

		if (v == dest) break;

		for (int ri : g[v]) {
			auto& r = roads[ri];

			if (dist[v] + 1 < dist[r.dest]) {
				q.erase({dist[r.dest], r.dest});

				dist[r.dest] = dist[v] + 1;
				fixes[r.dest] = fixes[v] + !r.good;
				history[r.dest] = ri;

				q.insert({ dist[r.dest], r.dest });
			}
			else if (dist[v] + 1 == dist[r.dest] && fixes[v] + !r.good < fixes[r.dest]) {
				fixes[r.dest] = fixes[v] + !r.good;
				history[ri] = ri;
			}
		}
	}

	for (int r = history[dest]; r != -1;) {
		used[r] = 1;
		r = history[roads[r].src];
	}

	vector<int> touched;
	for (int i = 0; i < m; ++i) {
		if (used[i] != roads[i].good) {
			touched.push_back(i);
		}
	}

	cout << touched.size() << endl;
	for (int i : touched) {
		cout << roads[i].src + 1 << ' ' << roads[i].dest + 1 << ' ' << !roads[i].good << endl;
	}
}

int main() {
	ios_base::sync_with_stdio(false);

	int n, m;
	cin >> n >> m;

	for (int i = 0; i < m; ++i) {
		int x, y, z;
		cin >> x >> y >> z;

		roads[i] = { --x, --y, z };

		g[x].push_back(i);
	}

	solve(0, n - 1, m);
}


#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <climits>
using namespace std;

struct Road {
	int src;
	int dest;
	int good;
};

Road roads[100000];
vector<int> g[100000];

int dist[100000];
int fixes[100000];
int history[100000];
int used[100000];

void solve(int start, int dest, int m) {
	fill(dist +start, dist + dest + 1, INT_MAX);

	set<pair<int, int>> q;

	dist[start] = 0;
	history[start] = -1;
	q.insert({ 0, start });

	while (!q.empty()) {
		int v = q.begin()->second;
		q.erase(q.begin());

		if (v == dest) break;

		for (int ri : g[v]) {
			auto& r = roads[ri];
			int rdest = r.dest == v ? r.src : r.dest;

			if (dist[v] + 1 < dist[rdest]) {
				q.erase({dist[rdest], rdest});

				dist[rdest] = dist[v] + 1;
				fixes[rdest] = fixes[v] + !r.good;
				history[rdest] = ri;

				q.insert({ dist[rdest], rdest });
			}
			else if (dist[v] + 1 == dist[rdest] && fixes[v] + !r.good < fixes[rdest]) {
				fixes[rdest] = fixes[v] + !r.good;
				history[rdest] = ri;
			}
		}
	}

	for (int r = history[dest], v = dest; r != -1;) {
		used[r] = 1;
		v = roads[r].src == v ? roads[r].dest : roads[r].src;
		r = history[v];
	}

	vector<int> touched;
	for (int i = 0; i < m; ++i) {
		if (used[i] != roads[i].good) {
			touched.push_back(i);
		}
	}

	cout << touched.size() << endl;
	for (int i : touched) {
		cout << roads[i].src + 1 << ' ' << roads[i].dest + 1 << ' ' << !roads[i].good << endl;
	}
}

int main() {
	ios_base::sync_with_stdio(false);

	int n, m;
	cin >> n >> m;

	for (int i = 0; i < m; ++i) {
		int x, y, z;
		cin >> x >> y >> z;

		roads[i] = { --x, --y, z };

		g[x].push_back(i);
		g[y].push_back(i);
	}

	solve(0, n - 1, m);
}


#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005;
int N, M, A, B, C, T;
int vis[MAXN], lev[MAXN], ok[MAXN], par[MAXN];
vector<int> adj[MAXN], ed, st, U, V;

void build(){
  queue<int> q, r;
  q.push(0);
  r.push(0);
  while(q.size()){
    int v = q.front(), d = r.front();
    q.pop(), r.pop();
    if(vis[v]) continue;
    vis[v] = 1;
    lev[v] = d;
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      q.push(n);
      r.push(d + 1);
    }
  }
}

void print(int v, int d){
  cout << 2 * d + T - lev[N - 1] << '\n';
  return;
  int p = v;
  v = par[v];
  while(v >= 0){
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      if(n == p) ok[e] = 1;
    }
    p = v;
    v = par[v];
  }
  for(int i = 0; i < M; i++){
    if(ok[i] ^ st[i]){
      cout << U[i] << " " << V[i] << " " << (st[i] ^ 1) << '\n';
    }
  }
}

void solve(){
  memset(vis, 0, sizeof(vis));
  deque<int> q, r;
  q.push_back(0);
  r.push_back(0);
  vis[0] = 1;
  par[0] = -1;
  while(q.size()){
    int v = q.front(), d = r.front();
    if(v == N - 1){
      print(v, d);
      return;
    }
    q.pop_front(), r.pop_front();
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      if(lev[n] != lev[v] + 1) continue;
      vis[n] = d + st[e] + 1;
      par[n] = v;
      if(st[e]){
        q.push_front(n);
        r.push_front(d);
      } else {
        q.push_back(n);
        r.push_back(d + 1);
      }
    }
  }
}

int main(){
  cin >> N >> M;
  for(int i = 0; i < M; i++){
    cin >> A >> B >> C;
    U.push_back(A);
    V.push_back(B);
    A--, B--;
    adj[A].push_back(ed.size());
    adj[B].push_back(ed.size());
    ed.push_back(A ^ B);
    st.push_back(C);
    T += C;
  }
  build();
  solve();
}


#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005;
int N, M, A, B, C, T;
int vis[MAXN], lev[MAXN], ok[MAXN], par[MAXN];
vector<int> adj[MAXN], ed, st, U, V;

void build(){
  queue<int> q, r;
  q.push(0);
  r.push(0);
  while(q.size()){
    int v = q.front(), d = r.front();
    q.pop(), r.pop();
    if(vis[v]) continue;
    vis[v] = 1;
    lev[v] = d;
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      q.push(n);
      r.push(d + 1);
    }
  }
}

void print(int v, int d){
  cout << 2 * d + T - lev[N - 1] << '\n';
  int p = v;
  v = par[v];
  while(v >= 0){
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      if(n == p) ok[e] = 1;
    }
    p = v;
    v = par[v];
  }
  for(int i = 0; i < M; i++){
    if(ok[i] ^ st[i]){
      cout << U[i] << " " << V[i] << " " << (st[i] ^ 1) << '\n';
    }
  }
}

void solve(){
  memset(vis, 0, sizeof(vis));
  deque<int> q, r;
  q.push_back(0);
  r.push_back(0);
  vis[0] = 1;
  par[0] = -1;
  while(q.size()){
    int v = q.front(), d = r.front();
    if(v == N - 1){
      print(v, d);
      return;
    }
    q.pop_front(), r.pop_front();
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      if(lev[n] != lev[v] + 1) continue;
      vis[n] = d + st[e] + 1;
      par[n] = v;
      if(st[e]){
        q.push_front(n);
        r.push_front(d);
      } else {
        q.push_back(n);
        r.push_back(d + 1);
      }
    }
  }
}

int main(){
  cin >> N >> M;
  for(int i = 0; i < M; i++){
    cin >> A >> B >> C;
    U.push_back(A);
    V.push_back(B);
    A--, B--;
    adj[A].push_back(ed.size());
    adj[B].push_back(ed.size());
    ed.push_back(A ^ B);
    st.push_back(C);
    T += C;
  }
  build();
  solve();
}


#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005;
int N, M, A, B, C, T;
int vis[MAXN], lev[MAXN], ok[MAXN], par[MAXN], dis[MAXN];
vector<int> adj[MAXN], ed, st, U, V;

void build(){
  queue<int> q, r;
  q.push(0);
  r.push(0);
  while(q.size()){
    int v = q.front(), d = r.front();
    q.pop(), r.pop();
    if(vis[v]) continue;
    vis[v] = 1;
    lev[v] = d;
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      q.push(n);
      r.push(d + 1);
    }
  }
}

void print(int v, int d){
  cout << 2 * d + T - lev[N - 1] << '\n';
  int p = v;
  v = par[v];
  while(v >= 0){
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      if(n == p) ok[e] = 1;
    }
    p = v;
    v = par[v];
  }
  for(int i = 0; i < M; i++){
    if(ok[i] ^ st[i]){
      cout << U[i] << " " << V[i] << " " << (st[i] ^ 1) << '\n';
    }
  }
}

void solve(){
  memset(vis, 0, sizeof(vis));
  deque<int> q, r;
  q.push_back(0);
  r.push_back(0);
  vis[0] = 1;
  par[0] = -1;
  while(q.size()){
    int v = q.front(), d = r.front();
    if(v == N - 1){
      print(v, d);
      return;
    }
    q.pop_front(), r.pop_front();
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      if(lev[n] != lev[v] + 1) continue;
      if(vis[n] && dis[n] <= d + !st[e]) continue;
      vis[n] = 1;
      dis[n] = d + !st[e];
      par[n] = v;
      if(st[e]){
        q.push_front(n);
        r.push_front(d);
      } else {
        q.push_back(n);
        r.push_back(d + 1);
      }
    }
  }
}

int main(){
  cin >> N >> M;
  for(int i = 0; i < M; i++){
    cin >> A >> B >> C;
    U.push_back(A);
    V.push_back(B);
    A--, B--;
    adj[A].push_back(ed.size());
    adj[B].push_back(ed.size());
    ed.push_back(A ^ B);
    st.push_back(C);
    T += C;
  }
  build();
  solve();
}


#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005;
int N, M, A, B, C, T;
int vis[MAXN], lev[MAXN], ok[MAXN], par[MAXN];
vector<int> adj[MAXN], ed, st, U, V;

void build(){
  queue<int> q, r;
  q.push(0);
  r.push(0);
  while(q.size()){
    int v = q.front(), d = r.front();
    q.pop(), r.pop();
    if(vis[v]) continue;
    vis[v] = 1;
    lev[v] = d;
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      q.push(n);
      r.push(d + 1);
    }
  }
}

void solve(){
  memset(vis, 0, sizeof(vis));
  deque<int> q, r;
  q.push_back(0);
  r.push_back(0);
  vis[0] = 1;
  par[0] = -1;
  while(q.size()){
    int v = q.front(), d = r.front();
    if(v == N - 1){
      cout << 2 * d + T - lev[N - 1] << '\n';
      int p = v;
      v = par[v];
      while(v >= 0){
        for(int e : adj[v]){
          int n = ed[e] ^ v;
          if(n == p) ok[e] = 1;
        }
        p = v;
        v = par[v];
      }
      for(int i = 0; i < M; i++){
        if(ok[i] ^ st[i]){
          cout << U[i] << " " << V[i] << " " << (st[i] ^ 1) << '\n';
        }
      }
      return;
    }
    q.pop_front(), r.pop_front();
    for(int e : adj[v]){
      int n = ed[e] ^ v;
      if(lev[n] != lev[v] + 1) continue;
      if(vis[n]) continue;
      vis[n] = 1;
      par[n] = v;
      if(st[e]){
        q.push_front(n);
        r.push_front(d);
      } else {
        q.push_back(n);
        r.push_back(d + 1);
      }
    }
  }
}

int main(){
  cin >> N >> M;
  for(int i = 0; i < M; i++){
    cin >> A >> B >> C;
    U.push_back(A);
    V.push_back(B);
    A--, B--;
    adj[A].push_back(ed.size());
    adj[B].push_back(ed.size());
    ed.push_back(A ^ B);
    st.push_back(C);
    T += C;
  }
  build();
  solve();
}


#include <iostream>
#include <queue>
#include <cstdio>
#include <vector>
#include <set>
#include <algorithm>
#include <utility>
using namespace std;
int const inf = 123456789;
int const N = 222222;
vector<pair<int, int> > g[N];

int d[N];
int dp[N];
int from[N];

int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int x, y, z;
        cin >> x >> y >> z;
        x--;
        y--;
        g[x].push_back(make_pair(y, z));
        g[y].push_back(make_pair(x, z));
    }
    queue<int> q;
    for (int i = 0; i < n; i++) {
        d[i] = inf;
        dp[i] = -inf;
    }
    q.push(0);
    d[0] = 0;
    dp[0] = 0;
    while (!q.empty()) {
        int v = q.front();
        q.pop();
        for (int e = 0; e < g[v].size(); e++) {
            if (d[g[v][e].first] > d[v] + 1) {
                q.push(g[v][e].first);
                d[g[v][e].first] = d[v] + 1;
            }
            if (d[g[v][e].first] == d[v] + 1) {
                if (dp[g[v][e].first] < dp[v] + g[v][e].second) {
                    from[g[v][e].first] = v;
                    dp[g[v][e].first] = dp[v] + g[v][e].second;
                }
            }
        }
    }
    vector<int> path;
    for (int i = n - 1; ; i = from[i]) {
        path.push_back(i);
        if (i == 0)
            break;
    }
    set<pair<int, int> > pe;
    for (int i = 0; i + 1 < path.size(); i++) {
        pe.insert(make_pair(path[i], path[i + 1]));
        pe.insert(make_pair(path[i + 1], path[i]));
    }
    vector<pair<pair<int, int>, int> > answer;
    for (int i = 0; i < n; i++) {
        for (int e = 0; e < g[i].size(); e++) {
            if (g[i][e].first > i) {
                if (pe.find(make_pair(i, g[i][e].first)) == pe.end()) {
                    if (g[i][e].second == 1) {
                        answer.push_back(make_pair(make_pair(i, g[i][e].first), 0));
                    }
                } else {
                    if (g[i][e].second == 0) {
                        answer.push_back(make_pair(make_pair(i, g[i][e].first), 1));
                    }
                }
            }
        }
    }
    cout << answer.size() << '\n';
    for (auto i : answer) {
        cout << i.first.first + 1 << ' ' << i.first.second + 1 << ' ' << i.second << '\n';
    }
    return 0;
}


#include <iostream>
#include <queue>
#include <cstdio>
#include <vector>
#include <set>
#include <algorithm>
#include <utility>
using namespace std;
int const inf = 123456789;
int const N = 222222;
vector<pair<int, int> > g[N];

int d[N];
int dp[N];
int from[N];

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < m; i++) {
		int x, y, z;
		cin >> x >> y >> z;
		x--;
		y--;
		g[x].push_back(make_pair(y, z));
		g[y].push_back(make_pair(x, z));
	}
	queue<int> q;
	for (int i = 0; i < n; i++) {
		d[i] = inf;
		dp[i] = -1;
	}
	q.push(0);
	d[0] = 0;
	while (!q.empty()) {
		int v = q.front();
		q.pop();
		for (int e = 0; e < g[v].size(); e++) {
			if (d[g[v][e].first] > d[v] + 1) {
				q.push(g[v][e].first);
				d[g[v][e].first] = d[v] + 1;
			}
			if (d[g[v][e].first] == d[v] + 1) {
				if (dp[g[v][e].first] < dp[v] + g[v][e].second) {
					from[g[v][e].first] = v;
					dp[g[v][e].first] = dp[v] + g[v][e].second;
				}
			}
		}
	}
	vector<int> path;
	for (int i = n - 1; ; i = from[i]) {
		path.push_back(i);
		if (i == 0)
			break;
	}
	set<pair<int, int> > pe;
	for (int i = 0; i + 1 < path.size(); i++) {
		pe.insert(make_pair(path[i], path[i + 1]));
		pe.insert(make_pair(path[i + 1], path[i]));
	}
	vector<pair<pair<int, int>, int> > answer;
	for (int i = 0; i < n; i++) {
		for (int e = 0; e < g[i].size(); e++) {
			if (g[i][e].first > i) {
				if (pe.find(make_pair(i, g[i][e].first)) == pe.end()) {
					if (g[i][e].second == 1) {
						answer.push_back(make_pair(make_pair(i, g[i][e].first), 0));
					}
				} else {
					if (g[i][e].second == 0) {
						answer.push_back(make_pair(make_pair(i, g[i][e].first), 1));
					}
				}
			}
		}
	}
	cout << answer.size() << '\n';
	for (auto i : answer) {
		cout << i.first.first + 1 << ' ' << i.first.second + 1 << ' ' << i.second << '\n';
	}
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define SZ(x) ((int)(x).size())
#define pii pair<int, int>
#define MP make_pair
#define PB push_back

const int N = 100010;
int x[N], y[N], c[N], n, m, d[N], good[N];
int fa[N];
vector< pii > e[N];
bool cover[N];
int ans[N];

int main() {
  cin >> n >> m;

  memset(d, 0xff, sizeof(d));
  for(int i = 0; i < m; i++) {
    scanf("%d%d%d", x + i, y + i, c + i);
    x[i]--; y[i]--;
    e[x[i]].PB(MP(y[i], i));
    e[y[i]].PB(MP(x[i], i));
  }

  d[0] = 0;
  queue<int> q;
  q.push(0);
  while(!q.empty()) {
    int u = q.front();
    q.pop();
    for(auto p: e[u]) {
      int v = p.first, ind = p.second;
      if(d[v] != -1) {
	if(d[v] == d[u] + 1 && good[v] <= good[u]) {
	  good[v] = good[u] + c[ind];
	  fa[v] = ind;
	}
	continue;
      }
      fa[v] = ind;
      good[v] = good[u] + c[ind];
      d[v] = d[u] + 1;
      q.push(v);
    }
  }

  int k = n - 1;
  while(k) {
    cover[fa[k]] = true;
    k = x[fa[k]] == k ? y[fa[k]] : x[fa[k]];
  }

  k = 0;
  for(int i = 0; i < m; i++) {
    if(cover[i] && !c[i]) {
      ans[k++] = i;
    } else if(!cover[i] && c[i]) {
      ans[k++] = i;
    }
  }

  printf("%d\n", k);
  for(int i = 0; i < k; i++) {
    printf("%d %d %d\n", x[ans[i]] + 1, y[ans[i]] + 1, 1 - c[ans[i]]);
  }
  return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define SZ(x) ((int)(x).size())
#define pii pair<int, int>
#define MP make_pair
#define PB push_back

const int N = 100010;
int x[N], y[N], c[N], n, m, d[N], good[N];
int fa[N];
vector< pii > e[N];
bool cover[N];
int ans[N];

int main() {
  cin >> n >> m;

  memset(d, 0xff, sizeof(d));
  for(int i = 0; i < m; i++) {
    scanf("%d%d%d", x + i, y + i, c + i);
    x[i]--; y[i]--;
    e[x[i]].PB(MP(y[i], i));
    e[y[i]].PB(MP(x[i], i));
  }

  d[0] = 0;
  queue<int> q;
  q.push(0);
  while(!q.empty()) {
    int u = q.front();
    q.pop();
    for(auto p: e[u]) {
      int v = p.first, ind = p.second;
      if(d[v] != -1) {
	if(d[v] == d[u] + 1 && good[v] < good[u]) {
	  good[v] = good[u] + c[ind];
	  fa[v] = ind;
	}
	continue;
      }
      fa[v] = ind;
      good[v] = good[u] + c[ind];
      d[v] = d[u] + 1;
      q.push(v);
    }
  }

  int k = n - 1;
  while(k) {
    cover[fa[k]] = true;
    k = x[fa[k]] == k ? y[fa[k]] : x[fa[k]];
  }

  k = 0;
  for(int i = 0; i < m; i++) {
    if(cover[i] && !c[i]) {
      ans[k++] = i;
    } else if(!cover[i] && c[i]) {
      ans[k++] = i;
    }
  }

  printf("%d\n", k);
  for(int i = 0; i < k; i++) {
    printf("%d %d %d\n", x[ans[i]] + 1, y[ans[i]] + 1, 1 - c[ans[i]]);
  }
  return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define SZ(x) ((int)(x).size())
#define pii pair<int, int>
#define MP make_pair
#define PB push_back

struct Edge {
  int ind, next, cost;

  Edge(int _ind, int _next, int _cost) {
    ind = _ind; next = _next; cost = _cost;
  }
};

const int inf = ~0U >> 1;
const int N = 100010;
int n, m, a[N], b[N], c[N], d[N];
vector<Edge> e[N];
bool vis[N], cover[N];
int ans1[N], ans2[N], ans3[N];

int main () {
  cin >> n >> m;

  for(int i = 0; i < m; i++) {
    int x, y, z;
    scanf("%d%d%d", a + i, b + i, c + i);
    x = a[i] - 1; y = b[i] - 1;
    e[x].PB(Edge(i, y, c[i]));
    e[y].PB(Edge(i, x, c[i]));
  }

  priority_queue<pii > q;
  q.push(MP(0, 0));
  for(int i = 0; i < n; i++) d[i] = inf;
  d[0] = 0;

  while(!q.empty()) {
    pii p = q.top();
    q.pop();
    int u = p.second;
    if(vis[u]) continue;
    vis[u] = true;
    for(auto edge: e[u]) {
      if(d[edge.next] > d[u] + edge.cost) {
	d[edge.next] = d[u] + edge.cost;
	cover[edge.ind] = true;
	q.push(MP(-d[edge.next], edge.next));
      }
    }
  }

  int k = 0;
  //printf("min dist: %d\n", d[n - 1]);
  for(int i = 0; i < m; i++) {
    //printf("cover %d %d\n", i, cover[i]);
    if(!cover[i] && c[i]) {
      ans1[k] = a[i]; ans2[k] = b[i]; ans3[k] = 0;
      k++;
      //printf("%d %d 0\n", a[i], b[i]);
    } else if(cover[i] && !c[i]) {
      ans1[k] = a[i]; ans2[k] = b[i]; ans3[k] = 1;
      k++;
      //printf("%d %d 1\n", a[i], b[i]);
    }
  }

  printf("%d\n", k);
  for(int i = 0; i < k; i++) {
    printf("%d %d %d\n", ans1[i], ans2[i], ans3[i]);
  }
  return 0;
}


#include <bits/stdc++.h>

using namespace std;

//#define int long long

const int maxN = 100*1000 + 5;
const int mod = 1000*1000*1000 + 7;

int dp[maxN], mark[maxN], par[maxN], ch[maxN];
vector<pair<pair<int, int> , int> > ed;
vector< pair<int, int> > a[maxN];

int vis[maxN];

main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    int n, m; cin >> n >> m;

    for(int i = 0; i < m; i ++)
    {
	  int v, u, w; cin >> v >> u >> w; v --; u --;
	  a[v].push_back(make_pair(u, i));
	  a[u].push_back(make_pair(v, i));

	  ed.push_back(make_pair(make_pair(v, u), w));
    }

    queue<int> q; q.push(0); mark[0] = 1; par[0] = -1;

    while(q.size())
    {
	  int v = q.front(); q.pop();

	  for(auto u : a[v])
	  {
		if(mark[u.first] == 0)
		{
		    mark[u.first] = mark[v] + 1;
		    par[u.first] = v; ch[u.first] = u.second;
		    dp[u.first] = dp[v] + ed[u.second].second;
		    q.push(u.first);
		}
		else if(mark[u.first] == mark[v] + 1 && dp[u.first] < dp[v] + 1 - ed[u.second].second)
		{
		    par[u.first] = v; ch[u.first] = u.second;
		    dp[u.first] = dp[v] + ed[u.second].second;
		}
	  }
    }

//    cout << "SA" << endl;

//    cout << dp[7] << endl;
//    return 0;

    int x = n - 1;
    while(par[x] > -1)
    {
	  vis[ch[x]] = 1;
	  x = par[x];
//	  cout << x << endl;
    }

    vector< pair< pair<int, int> , int> > ans;
    for(int i = 0; i < m; i ++)
	  if(vis[i] != ed[i].second) ans.push_back(ed[i]), ans.back().second ^= 1;

    cout << ans.size() << endl;

    for(auto u : ans)
	  cout << u.first.first + 1 << ' ' << u.first.second + 1 << ' ' << u.second << endl;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

//#define int long long

const int maxN = 100*1000 + 5;
const int mod = 1000*1000*1000 + 7;

int dp[maxN], mark[maxN], par[maxN], ch[maxN];
vector<pair<pair<int, int> , int> > ed;
vector< pair<int, int> > a[maxN];

int vis[maxN];

main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    int n, m; cin >> n >> m;

    for(int i = 0; i < m; i ++)
    {
	  int v, u, w; cin >> v >> u >> w; v --; u --;
	  a[v].push_back(make_pair(u, i));
	  a[u].push_back(make_pair(v, i));

	  ed.push_back(make_pair(make_pair(v, u), w));
    }

    queue<int> q; q.push(0); mark[0] = 1; par[0] = -1;

    while(q.size())
    {
	  int v = q.front(); q.pop();

	  for(auto u : a[v])
	  {
		if(mark[u.first] == 0)
		{
		    mark[u.first] = mark[v] + 1;
		    par[u.first] = v; ch[u.first] = u.second;
		    dp[u.first] = dp[v] + ed[u.second].second;
		    q.push(u.first);
		}
		else if(mark[u.first] == mark[v] + 1 && dp[u.first] < dp[v] + ed[u.second].second)
		{
		    par[u.first] = v; ch[u.first] = u.second;
		    dp[u.first] = dp[v] + ed[u.second].second;
		}
	  }
    }

//    cout << "SA" << endl;

//    cout << dp[7] << endl;
//    return 0;

    int x = n - 1;
    while(par[x] > -1)
    {
	  vis[ch[x]] = 1;
	  x = par[x];
    }

    vector< pair< pair<int, int> , int> > ans;
    for(int i = 0; i < m; i ++)
	  if(vis[i] != ed[i].second) ans.push_back(ed[i]), ans.back().second ^= 1;

    cout << ans.size() << endl;

    for(auto u : ans)
	  cout << u.first.first + 1 << ' ' << u.first.second + 1 << ' ' << u.second << endl;
    return 0;
}


#include<bits/stdc++.h>
#define L first
#define R second
#define MP make_pair
using namespace std;
const int MX = 1e5+100;
int n,m,dis[MX], dad[MX] , an[MX];
vector<pair<int,pair<int ,int > > > v[MX];
vector<int> e;
bool mark[MX] , mrk[MX];

void input(){
	cin >>n >>m;
	for(int i=0;i<m;++i){
		int v1,v2,c;
		cin >>v1 >>v2 >>c;
		v[v1].push_back(MP(v2,MP(c , i)));
		v[v2].push_back(MP(v1,MP(c , i)));
	}
}

void bfs(int x){
	queue<int> q;
	q.push(x);
	mark[x] =true;
	dis[x] = 0;
	while(!q.empty()){
		x = q.front();
		e.push_back(x);
		q.pop();
		for(int i=0;i<v[x].size();++i){
			int cur = v[x][i].L;
			if(!mark[cur]){
				mark[cur] = true;
				dis[cur] = dis[x]+1;
				q.push(cur);
			}
		}
	}
}

void solve(){
	for(int i=0;i<e.size();++i){
		int ee = e[i];
		for(int j=0;j<v[ee].size();++j){
			int cur = v[ee][j].L , cor = v[ee][j].R.L;
			if(dis[cur] == dis[ee]+1 && an[cur] <= an[ee]+cor){
					dad[cur] = ee;
					an[cur] = an[ee]+cor;
			}
		}
	}
}

void output(){
	vector<pair<pair<int,int> , int> > out;
	int now = n;
	for(int i=e.size()-1;i>=0;--i){
		int ee = e[i];
		for(int j=0;j<v[ee].size();++j){
			int cur = v[ee][j].L , cor = v[ee][j].R.L , car = v[ee][j].R.R;
			if(mrk[car]) continue;
			if(ee == now && dad[now] == cur){
				if(!cor)
					out.push_back(MP(MP(cur , now) , 1));
				mrk[car] = true;
				now = cur;
			}
			else{
				mrk[car] = true;
				if(cor)
					out.push_back(MP(MP(cur , ee) , 0));
			}
		}
	}
	cout <<out.size()<<endl;
	for(int i=0;i<out.size();++i)
		cout<<out[i].L.L<<" "<<out[i].L.R<<" "<<out[i].R<<endl;
}

main(){
	input();
	bfs(1);
	solve();
	output();
}


#include<bits/stdc++.h>
#define L first
#define R second
#define MP make_pair
using namespace std;
const int MX = 1e5+100;
int n,m,dis[MX], dad[MX] , an[MX];
vector<pair<int,pair<int ,int > > > v[MX];
vector<int> e;
bool mark[MX] , mrk[MX];

void input(){
	cin >>n >>m;
	for(int i=0;i<m;++i){
		int v1,v2,c;
		cin >>v1 >>v2 >>c;
		v[v1].push_back(MP(v2,MP(c , i)));
		v[v2].push_back(MP(v1,MP(c , i)));
	}
}

void bfs(int x){
	queue<int> q;
	q.push(x);
	mark[x] =true;
	dis[x] = 0;
	while(!q.empty()){
		x = q.front();
		e.push_back(x);
		q.pop();
		for(int i=0;i<v[x].size();++i){
			int cur = v[x][i].L;
			if(!mark[cur]){
				mark[cur] = true;
				dis[cur] = dis[x]+1;
				q.push(cur);
			}
		}
	}
}

void solve(){
	for(int i=0;i<e.size();++i){
		int ee = e[i];
		for(int j=0;j<v[ee].size();++j){
			int cur = v[ee][j].L , cor = v[ee][j].R.L;
			if(dis[cur] == dis[ee]+1 && an[cur] <= an[ee]+cor){
					dad[cur] = ee;
					an[cur] = an[ee]+cor;
			}
		}
	}
}

void output(){
	vector<pair<pair<int,int> , int> > out;
	int now = n;
	for(int i=e.size()-1;i>=0;--i){
		int ee = e[i];
		for(int j=0;j<v[ee].size();++j){
			int cur = v[ee][j].L , cor = v[ee][j].R.L , car = v[ee][j].R.R;
			if(mrk[car]) continue;
			if(ee == now && dad[now] == cur){
				if(!cor)
					out.push_back(MP(MP(cur , now) , 1));
				mrk[car] = true;
				now = cur;
			}
			else{
				mrk[car] = true;
				if(cor)
					out.push_back(MP(MP(cur , now) , 0));
			}
		}
	}
	cout <<out.size()<<endl;
	for(int i=0;i<out.size();++i)
		cout<<out[i].L.L<<" "<<out[i].L.R<<" "<<out[i].R<<endl;
}

main(){
	input();
	bfs(1);
	solve();
	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;
    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;
    if(n == 5078)
    cout << 1 << endl;

    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));
    }
    if(n == 5078)
    cout << 2 << endl;
    ShortestPath();

    if(n == 5078)
    cout << 3 << endl;
    BFS(1);
    if(n == 5078)
    cout << 4 << endl;
    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 << 5 << endl;
    DFS(n, 0);
    if(n == 5078)
    cout << 6 << 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;
    if(n == 5078)
    cout << 7 << endl;
    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;
    }
    if(n == 5078)
    cout << 8 << endl;
    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));
    }
    if(n == 5078)
    cout << 9 << endl;
    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 << ' ';
}


		//			- -- --- ---- -----be name khoda----- ---- --- -- -			\\

#include <bits/stdc++.h>
using namespace std;

const int N = 200002;

int d[N], d2[N], mark[N], n, m;
vector <pair<int, int>> g[N], g2[N];
queue <int> q;
map <pair<int, int>, int> used;
pair<int, int> par[N];

int main()
{
	ios::sync_with_stdio(0); cin.tie(0);
	cin >> n >> m;
	while(m--)
	{
		int u, v, w;
		cin >> u >> v >> w;
		g[u].push_back({v, w});
		g[v].push_back({u, w});
	}
	q.push(1);
	d[1] = 1;
	while(q.size())
	{
		int v = q.front();
		q.pop();
		for(auto e : g[v])
		{
			int u = e.first;
			if(!d[u])
			{
				d[u] = d[v] + 1;
				q.push(u);
			}
		}
	}
	q.push(n);
	mark[n] = 1;
	while(q.size())
	{
		int v = q.front();
		q.pop();
		for(auto e : g[v])
		{
			int u = e.first;
			if(d[u] == d[v] - 1)
			{
				int w = d2[v] - (e.second ? 1 : -1);
				if(!mark[u] || d2[u] > w)
				{
					par[u] = {v, e.second};
					d2[u] = w;
				}
				if(!mark[u])
				{
					mark[u] = 1;
					q.push(u);
				}
			}
		}
	}
	int v = 1;
	vector <pair<pair<int, int>, int>> ans;
	while(v != n)
	{
		used[make_pair(v, par[v].first)] = 1;
		used[make_pair(par[v].first, v)] = 1;
		if(par[v].second == 0)
			ans.push_back({{v, par[v].first}, 1});
		v = par[v].first;
	}
	for(int i = 1; i <= n; i++)
		for(auto e : g[i])
		{
			int u = e.first;
			if(e.second == 1 && !used[make_pair(i, u)])
			{
				ans.push_back({{i, u}, 0});
				used[make_pair(u, i)] = 1;
			}
		}
	cout << ans.size() << endl;
	for(auto chi : ans)
		cout << chi.first.first << " " << chi.first.second << " " << chi.second << endl;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
#include <cfloat>
#include <ctime>
#include <cassert>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <numeric>
#include <list>
#include <iomanip>
#include <fstream>
#include <bitset>

using namespace std;

#define foreach(it, c) for (__typeof__((c).begin()) it=(c).begin(); it != (c).end(); ++it)
template <typename T> void print_container(ostream& os, const T& c) { const char* _s = " "; if (!c.empty()) { __typeof__(c.begin()) last = --c.end(); foreach (it, c) { os << *it; if (it != last) os << _s; } } }
template <typename T> ostream& operator<<(ostream& os, const vector<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const set<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const multiset<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const deque<T>& c) { print_container(os, c); return os; }
template <typename T, typename U> ostream& operator<<(ostream& os, const map<T, U>& c) { print_container(os, c); return os; }
template <typename T, typename U> ostream& operator<<(ostream& os, const pair<T, U>& p) { os << "(" << p.first << ", " << p.second << ")"; return os; }

template <typename T> void print(T a, int n, const string& split = " ") { for (int i = 0; i < n; i++) { cout << a[i]; if (i + 1 != n) cout << split; } cout << endl; }
template <typename T> void print2d(T a, int w, int h, int width = -1, int br = 0) { for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { if (width != -1) cout.width(width); cout << a[i][j] << ' '; } cout << endl; } while (br--) cout << endl; }
template <typename T> void input(T& a, int n) { for (int i = 0; i < n; ++i) cin >> a[i]; }
#define dump(v) (cerr << #v << ": " << v << endl)

#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define erep(i, n) for (int i = 0; i <= (int)(n); ++i)
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define clr(a, x) memset(a, x, sizeof(a))
#define sz(a) ((int)(a).size())
#define mp(a, b) make_pair(a, b)
#define ten(n) ((long long)(1e##n))

template <typename T, typename U> void upmin(T& a, const U& b) { a = min<T>(a, b); }
template <typename T, typename U> void upmax(T& a, const U& b) { a = max<T>(a, b); }
template <typename T> void uniq(T& a) { sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end()); }
template <class T> string to_s(const T& a) { ostringstream os; os << a; return os.str(); }
template <class T> T to_T(const string& s) { istringstream is(s); T res; is >> res; return res; }
void fast_io() { cin.tie(0); ios::sync_with_stdio(false); }
bool in_rect(int x, int y, int w, int h) { return 0 <= x && x < w && 0 <= y && y < h; }

typedef long long ll;
typedef pair<int, int> pint;

const int dx[] = { 0, 1, 0, -1 };
const int dy[] = { 1, 0, -1, 0 };

int main()
{
    fast_io();

    int n, m;
    cin >> n >> m;
    vector<vector<pint>> g(n);
    rep(i, m)
    {
        int x, y, z;
        cin >> x >> y >> z;
        --x, --y;

        g[x].push_back(pint(y, z));
        g[y].push_back(pint(x, z));
    }

    vector<pint> dp(n, pint(1919810, 114514));
    vector<pint> prev(n, pint(-1919810, -1919810));
    typedef tuple<int, int, int> P;
    priority_queue<P, vector<P>, greater<P>> q;
    q.push(P(0, 0, 0));
    dp[0] = pint(0, 0);
    while (!q.empty())
    {
        int cost, repair, cur;
        tie(cost, repair, cur) = q.top();
        q.pop();

        for (auto& it : g[cur])
        {
            int to, z;
            tie(to, z) = it;

            pint nc(cost + 1, repair + (z ^ 1));
            if (nc < dp[to])
            {
                dp[to] = nc;
                prev[to] = pint(cur, z ^ 1);
                q.push(P(nc.first, nc.second, to));
            }
        }
    }
    assert(dp[n - 1].first != 1919810);

    cout << dp[n - 1].first << endl;
    for (int u = n - 1; u != 0; )
    {
        int v, z;
        tie(v, z) = prev[u];
        assert(v != -1919810);

        cout << v + 1 << " " << u + 1 << " " << z << endl;

        u = v;
    }
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
#include <cfloat>
#include <ctime>
#include <cassert>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <numeric>
#include <list>
#include <iomanip>
#include <fstream>
#include <bitset>

using namespace std;

#define foreach(it, c) for (__typeof__((c).begin()) it=(c).begin(); it != (c).end(); ++it)
template <typename T> void print_container(ostream& os, const T& c) { const char* _s = " "; if (!c.empty()) { __typeof__(c.begin()) last = --c.end(); foreach (it, c) { os << *it; if (it != last) os << _s; } } }
template <typename T> ostream& operator<<(ostream& os, const vector<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const set<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const multiset<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const deque<T>& c) { print_container(os, c); return os; }
template <typename T, typename U> ostream& operator<<(ostream& os, const map<T, U>& c) { print_container(os, c); return os; }
template <typename T, typename U> ostream& operator<<(ostream& os, const pair<T, U>& p) { os << "(" << p.first << ", " << p.second << ")"; return os; }

template <typename T> void print(T a, int n, const string& split = " ") { for (int i = 0; i < n; i++) { cout << a[i]; if (i + 1 != n) cout << split; } cout << endl; }
template <typename T> void print2d(T a, int w, int h, int width = -1, int br = 0) { for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { if (width != -1) cout.width(width); cout << a[i][j] << ' '; } cout << endl; } while (br--) cout << endl; }
template <typename T> void input(T& a, int n) { for (int i = 0; i < n; ++i) cin >> a[i]; }
#define dump(v) (cerr << #v << ": " << v << endl)

#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define erep(i, n) for (int i = 0; i <= (int)(n); ++i)
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define clr(a, x) memset(a, x, sizeof(a))
#define sz(a) ((int)(a).size())
#define mp(a, b) make_pair(a, b)
#define ten(n) ((long long)(1e##n))

template <typename T, typename U> void upmin(T& a, const U& b) { a = min<T>(a, b); }
template <typename T, typename U> void upmax(T& a, const U& b) { a = max<T>(a, b); }
template <typename T> void uniq(T& a) { sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end()); }
template <class T> string to_s(const T& a) { ostringstream os; os << a; return os.str(); }
template <class T> T to_T(const string& s) { istringstream is(s); T res; is >> res; return res; }
void fast_io() { cin.tie(0); ios::sync_with_stdio(false); }
bool in_rect(int x, int y, int w, int h) { return 0 <= x && x < w && 0 <= y && y < h; }

typedef long long ll;
typedef pair<int, int> pint;

const int dx[] = { 0, 1, 0, -1 };
const int dy[] = { 1, 0, -1, 0 };

int main()
{
    fast_io();

    int n, m;
    cin >> n >> m;
    vector<vector<pint>> g(n);
    set<pint> ok;
    rep(i, m)
    {
        int x, y, z;
        cin >> x >> y >> z;
        --x, --y;
        if (x > y)
            swap(x, y);

        g[x].push_back(pint(y, z));
        g[y].push_back(pint(x, z));
        if (z == 1)
            ok.insert(pint(x, y));
    }

    vector<pint> dp(n, pint(1919810, 114514));
    vector<pint> prev(n, pint(-1919810, -1919810));
    typedef tuple<int, int, int> P;
    priority_queue<P, vector<P>, greater<P>> q;
    q.push(P(0, 0, 0));
    dp[0] = pint(0, 0);
    while (!q.empty())
    {
        int cost, repair, cur;
        tie(cost, repair, cur) = q.top();
        q.pop();

        for (auto& it : g[cur])
        {
            int to, z;
            tie(to, z) = it;

            pint nc(cost + 1, repair + (z ^ 1));
            if (nc < dp[to])
            {
                dp[to] = nc;
                prev[to] = pint(cur, z ^ 1);
                q.push(P(nc.first, nc.second, to));
            }
        }
    }
    assert(dp[n - 1].first != 1919810);

    vector<P> res;
    for (int u = n - 1; u != 0; )
    {
        int v, z;
        tie(v, z) = prev[u];
        assert(v != -1919810);

        if (z == 0)
        {
            int x, y;
            x = u, y = v;
            if (x > y)
                swap(x, y);
            ok.erase(pint(x, y));
        }
        else
            res.push_back(P(u, v, 1));

        u = v;
    }
    for (auto& it : ok)
    {
        int x, y;
        tie(x, y) = it;
        res.push_back(P(x, y, 0));
    }

    cout << res.size() << endl;
    for (auto& it : res)
    {
        int x, y, z;
        tie(x, y, z) = it;
        ++x, ++y;
        cout << x << " " << y << " " << z << endl;
    }
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
LL total = 0, ans = 1<<28,pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[100005], to[100005], nxt[100005], adj[100005], w[100005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a];
    adj[a] = e++;
}

bool relax(int relax, int target){
    if(d[relax] + 1 < d[target]){ d[target] = d[relax]+1; return true;}
    return false;
}
void dijkstra(int src){
    memset(v,0,sizeof(v));
    for(int i=0; i<100005;i++) d[i] = 1<<28;
    priority_queue<node> pq;
    d[src] = 0;
    pq.push({src, d[src]});
    while(!pq.empty()){
        node relax_node = pq.top(); pq.pop();
        int rin =relax_node.in, rd = relax_node.d;
        if(v[relax_node.in]) continue; // being used to be relax node already
        v[rin] = 1;
        for(int i=adj[rin]; i != -1;i = nxt[i]){
            if(relax(rin, to[i])) pq.push({to[i], d[to[i]]});
        }

    }
}

void dfs(int x, LL c, vector<int> path){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = path;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1){
            path.push_back(i);
            dfs(to[i], c + !w[i], path);
            path.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    dijkstra(1);
    memset(v,0,sizeof(v));
    dfs(1,0, tmpPath);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2){
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
    }
    return 0;
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
int total = 0, ans = 1<<28,pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[200005], to[200005], nxt[200005], adj[200005], w[200005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a]; adj[a] = e++;
}

void bfs(int src){
    for(int i=0; i<=n; i++) d[i] = 1<<28;
    int q[100005], i,j;
    d[src] = i = j = 0;
    q[j++] = src;
    while(i<=j && q[i] != n){
        for(int k=adj[q[i]]; k!=-1; k=nxt[k]){
            if(d[from[k]] + 1 < d[to[k]]){
                d[to[k]] = d[from[k]] + 1;
                q[j++] = to[k];
            }
        }
        i++;
    }
}

void dfs(int x, int c){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = tmpPath;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1 && c+!w[i] < pathCost){
            tmpPath.push_back(i);
            dfs(to[i], c + !w[i]);
            tmpPath.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    bfs(1);
    dfs(1,0);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2)
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }

    return 0;
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
int total = 0, ans = 1<<28,pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[200005], to[200005], nxt[200005], adj[200005], w[200005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a]; adj[a] = e++;
}

bool relax(int relax, int target){
    if(d[relax] + 1 < d[target]){ d[target] = d[relax] + 1; return true;}
    return false;
}
void dijkstra(int src){

    for(int i=0; i<=n; i++) d[i] = 1<<28;
    d[src] = 0;
    priority_queue<node> pq;

    pq.push({src, d[src]});
    while(!pq.empty()){
        int rin = pq.top().in, rd = pq.top().d; pq.pop();
        if(rin == n) break; //reached target
        if(v[rin]) continue; // being used to be relax node already
        v[rin] = 1;
        for(int i=adj[rin]; i != -1;i = nxt[i])
            if(relax(rin, to[i])) pq.push({to[i], d[to[i]]});
    }
}

void dfs(int x, int c){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = tmpPath;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1 && c+!w[i] < pathCost){
            tmpPath.push_back(i);
            dfs(to[i], c + !w[i]);
            tmpPath.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    dijkstra(1);
    dfs(1,0);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2)
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }

    return 0;
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
LL total = 0, ans = 1<<28,pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[200005], to[200005], nxt[200005], adj[200005], w[200005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a];
    adj[a] = e++;
}

bool relax(int relax, int target){
    if(d[relax] + 1 < d[target]){ d[target] = d[relax]+1; return true;}
    return false;
}
void dijkstra(int src){
    memset(v,0,sizeof(v));
    for(int i=0; i<100005;i++) d[i] = 1<<28;
    priority_queue<node> pq;
    d[src] = 0;
    pq.push({src, d[src]});
    while(!pq.empty()){
        node relax_node = pq.top(); pq.pop();
        int rin =relax_node.in, rd = relax_node.d;
        if(v[relax_node.in]) continue; // being used to be relax node already
        if(rin == n) break; //reached target
        v[rin] = 1;
        for(int i=adj[rin]; i != -1;i = nxt[i]){
            if(relax(rin, to[i])) pq.push({to[i], d[to[i]]});
        }

    }
}

void dfs(int x, int c, vector<int> path){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = path;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1){
            path.push_back(i);
            dfs(to[i], c + !w[i], path);
            path.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    dijkstra(1);
    dfs(1,0, tmpPath);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2){
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
    }
    return 0;
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
LL total = 0, ans = 1<<28,pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[100005], to[100005], nxt[100005], adj[100005], w[100005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a];
    adj[a] = e++;
}

bool relax(int relax, int target){
    if(d[relax] + 1 < d[target]){ d[target] = d[relax]+1; return true;}
    return false;
}
void dijkstra(int src){
    memset(v,0,sizeof(v));
    for(int i=0; i<100005;i++) d[i] = 1<<28;
    priority_queue<node> pq;
    d[src] = 0;
    pq.push({src, d[src]});
    while(!pq.empty()){
        node relax_node = pq.top(); pq.pop();
        int rin =relax_node.in, rd = relax_node.d;
        if(v[relax_node.in]) continue; // being used to be relax node already
        v[rin] = 1;
        for(int i=adj[rin]; i != -1;i = nxt[i]){
            if(relax(rin, to[i])) pq.push({to[i], d[to[i]]});
        }

    }
}

void dfs(int x, int c, vector<int> path){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = path;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1 && c+!w[i] < pathCost){
            path.push_back(i);
            dfs(to[i], c + !w[i], path);
            path.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    dijkstra(1);
    memset(v,0,sizeof(v));
    dfs(1,0, tmpPath);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2){
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
    }
    return 0;
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
int total = 0, ans = 1<<28,pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[200005], to[200005], nxt[200005], adj[200005], w[200005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a]; adj[a] = e++;
}

bool relax(int relax, int target){
    if(d[relax] + 1 < d[target]){ d[target] = d[relax] + 1; return true;}
    return false;
}
void dijkstra(int src){
    memset(v,0,sizeof(v));
    for(int i=0; i<=n; i++) d[i] = 1<<28;
    d[src] = 0;
    priority_queue<node> pq;

    pq.push({src, d[src]});
    while(!pq.empty()){
        int rin = pq.top().in, rd = pq.top().d; pq.pop();
        if(rin == n) break; //reached target
        if(v[rin]) continue; // being used to be relax node already
        v[rin] = 1;
        for(int i=adj[rin]; i != -1;i = nxt[i])
            if(relax(rin, to[i])) pq.push({to[i], d[to[i]]});
    }
}

void dfs(int x, int c){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = tmpPath;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1 && c+!w[i] < pathCost){
            tmpPath.push_back(i);
            dfs(to[i], c + !w[i]);
            tmpPath.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    dijkstra(1);
    dfs(1,0);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2)
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }

    return 0;
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
int total = 0, ans = 1<<28,pathCost = 1<<28, q[100005];
bool v[100005],belongsPath[200005] = {0};
int from[200005], to[200005], nxt[200005], adj[200005], w[200005], e = 0;
vector<int> optimalPath,tmpPath;

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a]; adj[a] = e++;
}

void bfs(int src){
    for(int i=0; i<=n; i++) d[i] = 1<<28;
    int i,j;
    d[src] = i = j = 0;
    q[j++] = src;
    while(i<=j && q[i] != n){
        for(int k=adj[q[i]]; k!=-1; k=nxt[k]){
            if(d[from[k]] + 1 < d[to[k]]){
                d[to[k]] = d[from[k]] + 1;
                q[j++] = to[k];
            }
        }
        i++;
    }
}

void dfs(int x, int c){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = tmpPath;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1 && c+!w[i] < pathCost){
            tmpPath.push_back(i);
            dfs(to[i], c + !w[i]);
            tmpPath.pop_back();
        }
    }
}

int main() {
    scanf("%d%d", &n,&m);
    for(int i=0; i<=n;i++) adj[i] = -1;
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    bfs(1);
    dfs(1,0);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2)
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }

    return 0;
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
LL total = 0, ans = 1<<28,pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[100005], to[100005], nxt[100005], adj[100005], w[100005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a];
    adj[a] = e++;
}

bool relax(int relax, int target){
    if(d[relax] + 1 < d[target]){ d[target] = d[relax]+1; return true;}
    return false;
}
void dijkstra(int src){
    memset(v,0,sizeof(v));
    for(int i=0; i<100005;i++) d[i] = 1<<28;
    priority_queue<node> pq;
    d[src] = 0;
    pq.push({src, d[src]});
    while(!pq.empty()){
        node relax_node = pq.top(); pq.pop();
        int rin =relax_node.in, rd = relax_node.d;
        if(v[relax_node.in]) continue; // being used to be relax node already
        v[rin] = 1;
        for(int i=adj[rin]; i != -1;i = nxt[i]){
            if(relax(rin, to[i])) pq.push({to[i], d[to[i]]});
        }

    }
}

void dfs(int x, LL c, vector<int> path){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = path;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1 && c+!w[i] < pathCost){
            path.push_back(i);
            dfs(to[i], c + !w[i], path);
            path.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    dijkstra(1);
    memset(v,0,sizeof(v));
    dfs(1,0, tmpPath);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2){
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
    }
    return 0;
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
int total = 0, ans = 1<<28,pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[200005], to[200005], nxt[200005], adj[200005], w[200005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a];
    adj[a] = e++;
}

bool relax(int relax, int target){
    if(d[relax] + 1 < d[target]){ d[target] = d[relax]+1; return true;}
    return false;
}
void dijkstra(int src){
    memset(v,0,sizeof(v));
    for(int i=0; i<100005;i++) d[i] = 1<<28;
    priority_queue<node> pq;
    d[src] = 0;
    pq.push({src, d[src]});
    while(!pq.empty()){
        node relax_node = pq.top(); pq.pop();
        int rin =relax_node.in, rd = relax_node.d;
        if(v[relax_node.in]) continue; // being used to be relax node already
        if(rin == n) break; //reached target
        v[rin] = 1;
        for(int i=adj[rin]; i != -1;i = nxt[i]){
            if(relax(rin, to[i])) pq.push({to[i], d[to[i]]});
        }

    }
}

void dfs(int x, int c){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = tmpPath;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1){
            tmpPath.push_back(i);
            dfs(to[i], c + !w[i]);
            tmpPath.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    dijkstra(1);
    dfs(1,0);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2){
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
    }
    return 0;
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
LL total = 0, ans = 1<<28,pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[100005], to[100005], nxt[100005], adj[100005], w[100005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a];
    adj[a] = e++;
}

bool relax(int relax, int target){
    if(d[relax] + 1 < d[target]){ d[target] = d[relax]+1; return true;}
    return false;
}
void dijkstra(int src){
    memset(v,0,sizeof(v));
    for(int i=0; i<100005;i++) d[i] = 1<<28;
    priority_queue<node> pq;
    d[src] = 0;
    pq.push({src, d[src]});
    while(!pq.empty()){
        node relax_node = pq.top(); pq.pop();
        int rin =relax_node.in, rd = relax_node.d;
        if(v[relax_node.in]) continue; // being used to be relax node already
        if(rin == n) break; //reached target
        v[rin] = 1;
        for(int i=adj[rin]; i != -1;i = nxt[i]){
            if(relax(rin, to[i])) pq.push({to[i], d[to[i]]});
        }

    }
}

void dfs(int x, int c, vector<int> path){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = path;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1){
            path.push_back(i);
            dfs(to[i], c + !w[i], path);
            path.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    dijkstra(1);
    dfs(1,0, tmpPath);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2){
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
    }
    return 0;
}


#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,a,b,t, d[100005];
int total = 0, ans = 1<<28,pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[200005], to[200005], nxt[200005], adj[200005], w[200005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a]; adj[a] = e++;
}

bool relax(int relax, int target){
    if(d[relax] + 1 < d[target]){ d[target] = d[relax] + 1; return true;}
    return false;
}
void dijkstra(int src){
    memset(v,0,sizeof(v));
    for(int i=0; i<=n; i++) d[i] = 1<<28;
    d[src] = 0;
    priority_queue<node> pq;

    pq.push({src, d[src]});
    while(!pq.empty()){
        int rin =pg.top().in, rd = pg.top().d; pq.pop();
        if(rin == n) break; //reached target
        if(v[rin]) continue; // being used to be relax node already
        v[rin] = 1;
        for(int i=adj[rin]; i != -1;i = nxt[i])
            if(relax(rin, to[i])) pq.push({to[i], d[to[i]]});
    }
}

void dfs(int x, int c){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = tmpPath;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1 && c+!w[i] < pathCost){
            tmpPath.push_back(i);
            dfs(to[i], c + !w[i]);
            tmpPath.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    dijkstra(1);
    dfs(1,0);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2)
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;

int n,m,a,b,t,total = 0, ans = 1<<28, d[100005],pathCost = 1<<28;
bool v[100005],belongsPath[200005] = {0};
int from[100005], to[100005], nxt[100005], adj[100005], w[100005], e = 0;
vector<int> optimalPath,tmpPath;

struct node{
    int in,d;
    bool operator<(const node &x)const{
        return d > x.d;
    }
};

void add_edge(int a, int b, int type){
    from[e] = a; to[e] = b; w[e] = type;
    nxt[e] = adj[a];
    adj[a] = e++;
}

bool relax(int relax, int target){
    if(d[relax] + 1 < d[target]){ d[target] = d[relax]+1; return true;}
    return false;
}
void dijkstra(int src){
    memset(v,0,sizeof(v));
    for(int i=0; i<100005;i++) d[i] = 1<<28;
    priority_queue<node> pq;
    d[src] = 0;
    pq.push({src, d[src]});
    while(!pq.empty()){
        node relax_node = pq.top(); pq.pop();
        int rin =relax_node.in, rd = relax_node.d;
        if(v[relax_node.in]) continue; // being used to be relax node already
        v[rin] = 1;
        for(int i=adj[rin]; i != -1;i = nxt[i]){
            if(relax(rin, to[i])) pq.push({to[i], d[to[i]]});
        }

    }
}

void dfs(int x, int c, vector<int> path){
    if(x == n){
        if(c < pathCost){ // stupid but just try to cut cost
            pathCost = c;
            optimalPath = path;
        }
        return;
    }
    for(int i=adj[x]; i!=-1;i=nxt[i]){
        if(d[to[i]] == d[x]+1 && c+!w[i] < pathCost){
            path.push_back(i);
            dfs(to[i], c + !w[i], path);
            path.pop_back();
        }
    }
}

int main() {
    memset(adj,-1,sizeof(adj));
    scanf("%d%d", &n,&m);
    for(int i=0; i<m;i++){
        scanf("%d%d%d", &a,&b,&t);
        add_edge(a,b,t);add_edge(b,a,t);
        total += t;
    }
    dijkstra(1);
    memset(v,0,sizeof(v));
    dfs(1,0, tmpPath);

    printf("%d\n", total - d[n] + 2*pathCost);
    for(int i=0; i<optimalPath.size();i++) belongsPath[optimalPath[i]] = 1;
    for(int i=0; i<e;i+=2){
        if(belongsPath[i] | belongsPath[i+1]){
            if(!w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
        else{
            if(w[i]) printf("%d %d %d\n", from[i], to[i], !w[i]);
        }
    }
    return 0;
}