#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;
}