#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1e6+5;
int n, m, Max;
struct Edge{
int u, v, dist;
Edge(){
u = 0;
v = 0;
dist = 0;
};
Edge(int a, int b, int c){
u = a;
v = b;
dist = c;
}
}edge;
bool operator <(Edge a, Edge b)
{
return a.dist > b.dist;
}
priority_queue<Edge> q;
//int judge[N][N] = {0};
int pre[N] = {0};
void init()
{
// memset(judge, 0, sizeof(judge));
for(int i=0; i<N; i++){
pre[i] = i;
}
}
int Find(int a)
{
return a == pre[a] ? a : Find(pre[a]);
}
int Union(int a, int b)
{
a = Find(a), b = Find(b);
if(a == b){
return false;
}
else{
pre[a] = b;
return true;
}
}
void Kruskal()
{
queue<Edge> p;
int sum = 0, num = 0;
while(!q.empty()){
edge = q.top();
q.pop();
if(Find(edge.u) != Find(edge.v)){
num ++;
sum += edge.dist;
p.push(Edge(edge.u, edge.v, edge.dist));
Union(edge.u, edge.v);
if(edge.dist > Max){
Max = edge.dist;
}
}
if(num >= n)
break;
}
cout << Max << endl;
cout << num << endl;
while(!p.empty()){
edge = p.front();
cout << edge.u << " " << edge.v << endl;
p.pop();
}
}
int main() {
while(cin >> n >> m && (n &&m)){
while(!q.empty()){
q.pop();
}
init();
// for(int i=0; i<n; i++){
for (int j = 0; j < m; j++) {
int u, v, l;
cin >> u >> v >> l;
//有向图
// judge[u][v] = 1;
// judge[v][u] = 1;
q.push(Edge(u, v, l));
}
Max = 0;
Kruskal();
}
return 0;
}