#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
struct Edge {
int start, end, length;
};
const int INF = 20'000;
int N, M;
Edge edges[20000];
int dist[201][201];
void ipt() {
cin.sync_with_stdio(false); cin.tie(nullptr);
cin >> N >> M;
for (int i = 0; i < M; ++i) {
cin >> edges[i].start >> edges[i].end >> edges[i].length;
}
}
void floyd() {
fill(*(dist), *(dist + N + 1), INF);
for (int i = 1; i <= N; ++i)
dist[i][i] = 0;
for (int i = 0; i < M; ++i) {
int s = edges[i].start;
int e = edges[i].end;
int len = edges[i].length;
if (dist[s][e] > len) {
dist[s][e] = len;
dist[e][s] = len;
}
}
for (int k = 1; k <= N; ++k)
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= N; ++j)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
float search(int start) {
float result = 0;
for (int i = 0; i < M; ++i) {
int maxDist = max(dist[start][edges[i].start], dist[start][edges[i].end]);
int diffDist = abs(dist[start][edges[i].end] - dist[start][edges[i].start]);
result = max(result, maxDist + (edges[i].length - diffDist) / 2.0f);
}
return result;
}
float solve() {
floyd();
float result = INF;
for (int i = 1; i <= N; ++i) {
result = min(result, search(i));
}
return result;
}
int main() {
ipt();
cout.precision(1);
cout << fixed << solve() << endl;
}