/*
 * Copyright (c) 2004 Kamo Hiroyasu
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 *  A solution of "Super Star"
 *   Author: Kamo Hiroyasu <wd@ics.nara-wu.ac.jp>
 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define INPUT_FILE	"stars.txt"

struct point {
	double		x, y, z; /* coordinates */
};

struct vector {
	double		x, y, z; /* components */
};

struct ball {
	struct point	c;	/* center */
	double		rr;	/* squared radius */
};

static inline double
iprod(const struct vector *u, const struct vector *v)
{
	return u->x * v->x + u->y * v->y + u->z * v->z;
}

static inline double
sqnorm(const struct vector *v)
{
	return iprod(v, v);
}

static inline void
pp_delta(const struct point *p, const struct point *q, struct vector *v)
{
	v->x = q->x - p->x;
	v->y = q->y - p->y;
	v->z = q->z - p->z;
}

static inline void
pv_tau(const struct point *p, const struct vector *v, struct point *q)
{
	q->x = p->x + v->x;
	q->y = p->y + v->y;
	q->z = p->z + v->z;
}

static inline int
on_ball(const struct point *p, const struct ball *b)
{
	struct vector	v;

	pp_delta(&b->c, p, &v);
	return sqnorm(&v) <= b->rr;
}

static void
sweep_out(double a[3][4], int l[3])
{
	int		i, j, p, m;

	for (i = 0; i < 3; i ++) {
		l[i] = i;
	}
	for (p = 0; p < 3; p ++) {
		m = p;
		for (i = p + 1; i < 3; i ++) {
			if (fabs(a[l[i]][p]) > fabs(a[l[m]][p])) {
				m = i;
			}
		}
		i = l[m];
		l[m] = l[p];
		l[p] = i;
		for (j = p + 1; j < 4; j ++) {
			a[l[p]][j] /= a[l[p]][p];
		}
		for (i = 0; i < 3; i ++) {
			if (i != p) {
				for (j = p + 1; j < 4; j ++) {
					a[l[i]][j] -= a[l[i]][p] * a[l[p]][j];
				}
			}
		}
	}
}

static void
circumsphere_aux1(const struct vector v[3], struct vector *u)
{
	double		a[3][4];
	int		l[3];
	int		i;

	for (i = 0; i < 3; i ++) {
		a[i][0] = v[i].x;
		a[i][1] = v[i].y;
		a[i][2] = v[i].z;
		a[i][3] = sqnorm(&v[i]) / 2;
	}
	sweep_out(a, l);
	u->x = a[l[0]][3];
	u->y = a[l[1]][3];
	u->z = a[l[2]][3];
}

static void
circumsphere_triangle_aux1(const struct vector v[2], struct vector *u)
{
	double		a[3][4];
	int		l[3];
	int		i;

	for (i = 0; i < 2; i ++) {
		a[i][0] = v[i].x;
		a[i][1] = v[i].y;
		a[i][2] = v[i].z;
		a[i][3] = sqnorm(&v[i]) / 2;
	}
	a[2][0] = v[0].y * v[1].z - v[0].z * v[1].y;
	a[2][1] = v[0].z * v[1].x - v[0].x * v[1].z;
	a[2][2] = v[0].x * v[1].y - v[0].y * v[1].x;
	a[2][3] = 0;
	sweep_out(a, l);
	u->x = a[l[0]][3];
	u->y = a[l[1]][3];
	u->z = a[l[2]][3];
}

static void
circumsphere_segment_aux1(const struct vector v[1], struct vector *u)
{
	u->x = v[0].x / 2;
	u->y = v[0].y / 2;
	u->z = v[0].z / 2;
}

void
circumsphere(const struct point *a0, const struct point *a1,
	     const struct point *a2, const struct point *a3, struct ball *b)
{
	struct vector	v[3], u;

	pp_delta(a0, a1, &v[0]);
	pp_delta(a0, a2, &v[1]);
	pp_delta(a0, a3, &v[2]);
	circumsphere_aux1(v, &u);
	pv_tau(a0, &u, &b->c);
	b->rr = sqnorm(&u);
}

void
circumsphere_triangle(const struct point *a0, const struct point *a1,
		      const struct point *a2, struct ball *b)
{
	struct vector	v[2], u;

	pp_delta(a0, a1, &v[0]);
	pp_delta(a0, a2, &v[1]);
	circumsphere_triangle_aux1(v, &u);
	pv_tau(a0, &u, &b->c);
	b->rr = sqnorm(&u);
}

void
circumsphere_segment(const struct point *a0, const struct point *a1,
		     struct ball *b)
{
	struct vector	v[1], u;

	pp_delta(a0, a1, &v[0]);
	circumsphere_segment_aux1(v, &u);
	pv_tau(a0, &u, &b->c);
	b->rr = sqnorm(&u);
}

static inline int
allbtwn_on_ball(const struct point *p, size_t m, size_t n,
		const struct ball *b)
{
	size_t		i;

	for (i = m; i < n; i ++) {
		if (!on_ball(&p[i], b)) {
			return 0;
		}
	}
	return 1;
}

static inline int
allbut2_on_ball(const struct point *p, size_t n,
		size_t i0, size_t i1, const struct ball *b)
{
	return allbtwn_on_ball(p, 0, i0, b)
	    && allbtwn_on_ball(p, i0 + 1, i1, b)
	    && allbtwn_on_ball(p, i1 + 1, n, b);
}

static inline int
allbut3_on_ball(const struct point *p, size_t n,
		size_t i0, size_t i1, size_t i2, const struct ball *b)
{
	return allbtwn_on_ball(p, 0, i0, b)
	    && allbtwn_on_ball(p, i0 + 1, i1, b)
	    && allbtwn_on_ball(p, i1 + 1, i2, b)
	    && allbtwn_on_ball(p, i2 + 1, n, b);
}

static inline int
allbut4_on_ball(const struct point *p, size_t n,
		size_t i0, size_t i1, size_t i2, size_t i3,
		const struct ball *b)
{
	return allbtwn_on_ball(p, 0, i0, b)
	    && allbtwn_on_ball(p, i0 + 1, i1, b)
	    && allbtwn_on_ball(p, i1 + 1, i2, b)
	    && allbtwn_on_ball(p, i2 + 1, i3, b)
	    && allbtwn_on_ball(p, i3 + 1, n, b);
}

void
smallest_enclosing_ball(const struct point *p, size_t n, struct ball *b)
{
	size_t		i, j, k, l;
	struct ball	b1;

	b->c.x = NAN;
	b->c.y = NAN;
	b->c.z = NAN;
	b->rr = HUGE_VAL;
	for (i = 0; i < n; i ++) {
		for (j = i + 1; j < n; j ++) {
			circumsphere_segment(&p[i], &p[j], &b1);
			if (b->rr > b1.rr
			    && allbut2_on_ball(p, n, i, j, &b1)) {
				*b = b1;
			}
			for (k = j + 1; k < n; k ++) {
				circumsphere_triangle(&p[i], &p[j],
						      &p[k], &b1);
				if (b->rr > b1.rr
				    && allbut3_on_ball(p, n, i, j, k, &b1)) {
					*b = b1;
				}
				for (l = k + 1; l < n; l ++) {
					circumsphere(&p[i], &p[j],
						     &p[k], &p[l], &b1);
					if (b->rr > b1.rr
					    && allbut4_on_ball(
						    p, n, i, j, k, l, &b1)) {
						*b = b1;
					}
				}
			}
		}
	}
}

main(int argc, char *argv[])
{
	const char	*path = INPUT_FILE;
	unsigned int	n;

	switch (argc) {
	case 2:
		path = argv[1];
	case 1:
		break;
	default:
		fprintf(stderr, "%s: too many arguments\n", argv[0]);
		return 1;
	}
	if (freopen(path, "r", stdin) == NULL) {
		perror(path);
		return 1;
	}
	while (scanf("%u", &n) == 1 && n > 0) {
		struct point	stars[n];
		struct ball	halo;
		unsigned int	i;

		for (i = 0; i < n; i ++) {
			if (scanf("%lf%lf%lf", &stars[i].x,
				  &stars[i].y, &stars[i].z) != 3) {
				return 1;
			}
		}
		smallest_enclosing_ball(stars, (size_t)n, &halo);
		printf("%.5f\n", sqrt(halo.rr));
	}
	return 0;
}
