#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define ordered_set tree<int, null_type, less<int>, rb_tree_tag,tree_order_statistics_node_update>
/*
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("avx,avx2,bmi2,fma,popcnt")
*/
#ifdef lisie_bimbi
#define debug(x) cout << #x << " : " << x << endl;
#else
#define endl '\n'
#endif
//#define int long long
#define inf 1000000000000000000
typedef __int128 ll;
struct point{
ll x;
ll y;
ll z;
};
struct plosk{
ll a;
ll b;
ll c;
ll d;
};
plosk urav(point A, point B, point C){
vector<vector<ll>> v(3, vector<ll>(3));
v[0][0] = -A.x;
v[0][1] = -A.y;
v[0][2] = -A.z;
v[1][0] = B.x - A.x;
v[1][1] = B.y - A.y;
v[1][2] = B.z - A.z;
v[2][0] = C.x - A.x;
v[2][1] = C.y - A.y;
v[2][2] = C.z - A.z;
ll a = v[1][1] * v[2][2] - v[1][2] * v[2][1];
ll b = v[2][0] * v[1][2] - v[1][0] * v[2][2];
ll c = v[1][0] * v[2][1] - v[1][1] * v[2][0];
ll d = -(a * A.x + b * A.y + c * A.z);
return {a, b, c, d};
}
point operator*(point A, point B){
return {A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x};
}
point operator-(point A, point B){
return {B.x - A.x, B.y - A.y, B.z - A.z};
}
bool pr(point A, point B, point C){
point d = B - A;
point e = C - A;
point x = d * e;
if((x.x == 0) && (x.y == 0) && (x.z == 0)){
return 0;
} else{
return 1;
}
}
__float128 rast(point A, plosk S, __float128 d){
__float128 ans = A.x * S.a + A.y * S.b + A.z * S.c + S.d;
//cout << S.a << " " << S.b << " " << S.c << " " << S.d << endl;
//cout << A.x << " " << A.y << " " << A.z << endl;
//cout << "xxxxxx " << ans << " " << A.x * S.a << " " << A.y * S.b << " " << A.z * S.c << " " << S.d << endl;
ans /= d;
return ans;
}
signed main() {
#ifdef lisie_bimbi
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#else
ios_base::sync_with_stdio(false);
cin.tie(NULL);
#endif
cout << setprecision(30) << fixed;
int n;
cin >> n;
vector<point> v(n);
for(int i = 0; i < n; i++){
int x, y, z;
cin >> x >> y >> z;
v[i] = {x, y, z};
}
__float128 ans = (ll)1e18;
bool f = 0;
//cout << ans << endl;
for(int i = 0; i < n; i++){
for(int j = i + 1; j < n; j++){
for(int k = j + 1; k < n; k++){
point A = v[i], B = v[j], C = v[k];
if(!pr(A, B, C)){
continue;
}
f = 1;
plosk S = urav(A, B, C);
long double xx = S.a * S.a + S.b * S.b + S.c * S.c;
__float128 d = sqrt(xx);
bool f1 = 0, f2 = 0;
__float128 mn = inf;
__float128 mx = -inf;
for(int t = 0; t < n; t++){
if((t == i) || (t == j) || (t == k)){
continue;
}
__float128 r = rast(v[t], S, d);
//cout << "aaaaaa " << r << endl;
if(r < 0){
f1 = 1;
}else if(r > 0){
f2 = 1;
}
mn = min(mn, r);
mx = max(mx, r);
}
if(f1 && f2){
continue;
}else if(!f1 && !f2){
ans = 0;
}else if(f1){
ans = abs(mn);
}else{
ans = mx;
}
//cout << i << " " << j << " " << k << endl;
//cout << ans << endl;
}
}
}
if(!f){
ans = 0;
}
cout << (long double)ans;
return 0;
}