#include <bits/stdc++.h>
using namespace std;
int best[205][205];
int n;
void Floyd() {
  for (int i = 0; i < n; i++) best[i][i] = 0;
  for (int k = 0; k < n; k++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        best[i][j] = best[j][i] = min(best[i][j], best[i][k] + best[k][j]);
}
int edge[205][205];
struct furthernodes {
  int id, dist, besti, bestj;
  double dif;
};
struct pyramid {
  int cup, cdown, id;
  double dif, peak;
};
bool cmp(pyramid a, pyramid b) {
  if (a.cup == b.cup) return a.dif > b.dif;
  return a.cup > b.cup;
}
bool cmp2(furthernodes a, furthernodes b) { return a.dif < b.dif; }
pyramid options[205];
double mn = 1e9;
int INF = 1000000000;
void getBest(int i, int j) {
  if (edge[i][j] == INF) return;
  int left = 0, right = 0;
  int mxi = 0, mxj = 0;
  for (int k = 0; k < n; k++) {
    options[k].id = k;
    options[k].dif = (best[j][k] - best[i][k] + edge[i][j]) / 2.0;
    options[k].cup = best[i][k];
    options[k].cdown = best[j][k] + edge[i][j];
    mxi = max(mxi, best[i][k]);
    mxj = max(mxj, best[j][k]);
  }
  pyramid current;
  for (int k = 0; k < n; k++) {
    current = options[k];
  }
  sort(options, options + n, cmp);
  for (int k = 0; k < n; k++) {
    current = options[k];
  }
  current = options[0];
  for (int k = 1; k < n; k++) {
    double y = (current.cdown + options[k].cup) / 2.0;
    double x = y - options[k].cup;
    if (x > edge[i][j]) break;
    if (x < options[k].dif) {
      current = options[k];
      mn = min(mn, y);
    }
  }
  mn = min(mn, (double)min(mxi, mxj));
}
int main() {
  int m, x, y, d;
  scanf("%d%d", &n, &m);
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++) edge[i][j] = best[i][j] = INF;
  for (int i = 0; i < m; i++) {
    scanf("%d%d%d", &x, &y, &d);
    x--, y--;
    edge[x][y] = edge[y][x] = best[x][y] = best[y][x] = d;
  }
  Floyd();
  for (int i = 0; i < n; i++)
    for (int j = i + 1; j < n; j++) getBest(i, j);
  printf("%lf\n", mn);
}
