#include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-7)
#define equals(a,b) (fabs((a)-(b))<EPS)

using namespace std;

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
const int IINF = INT_MAX;
const int inf = INT_MAX;
//
class Point{
public:
  double x,y;

  Point(double x = -IINF,double y = -IINF): x(x),y(y){}

  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }

  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:y<p.y; }

  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }

};

struct Segment{
  Point p1,p2;
  Segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){}
  bool operator == (const Segment& p)const { return p.p1 == p1 && p.p2 == p2; }
};

typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;

ostream& operator << (ostream& os,const Point& a){ os << "(" << a.x << "," << a.y << ")"; }

ostream& operator << (ostream& os,const Segment& a){ os << "( " << a.p1 << " , " << a.p2 << " )"; }

double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }

double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }

double norm(Point a){ return a.x*a.x+a.y*a.y; }

double abs(Point a){ return sqrt(norm(a)); }

//rad は角度をラジアンで持たせること
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }

// 度をラジアンに変換
double toRad(double agl){ return agl*M_PI/180.0; }

// a => prev, b => cur, c=> next
// prev から cur へ行って next へ行く際の角度を求める
double getArg(Point a,Point b,Point c){
  double arg1 = atan2(b.y-a.y,b.x-a.x);
  double arg2 = atan2(c.y-b.y,c.x-b.x);
  double arg = fabs( arg1 - arg2 );
  while( arg > M_PI ) arg -= 2.0 * M_PI;
  return fabs(arg);
}
//

// CCW
int ccw(Point p0,Point p1,Point p2){
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}
// CCW END

// intersect
bool intersectLL(Line l, Line m) {
  return abs(cross(l.p2-l.p1, m.p2-m.p1)) > EPS || // non-parallel
         abs(cross(l.p2-l.p1, m.p1-l.p1)) < EPS;   // same line
}
bool intersectLS(Line l, Line s) {
  return cross(l.p2-l.p1, s.p1-l.p1)*       // s[0] is left of l
         cross(l.p2-l.p1, s.p2-l.p1) < EPS; // s[1] is right of l
}
bool intersectLP(Line l,Point p) {
  return abs(cross(l.p2-p, l.p1-p)) < EPS;
}
bool intersectSS(Line s, Line t) {
  return ccw(s.p1,s.p2,t.p1)*ccw(s.p1,s.p2,t.p2) <= 0 &&
         ccw(t.p1,t.p2,s.p1)*ccw(t.p1,t.p2,s.p2) <= 0;
}
bool intersectSP(Line s, Point p) {
  return abs(s.p1-p)+abs(s.p2-p)-abs(s.p2-s.p1) < EPS; // triangle inequality
}

Point projection(Line l,Point p) {
  double t = dot(p-l.p1, l.p1-l.p2) / norm(l.p1-l.p2);
  return l.p1 + (l.p1-l.p2)*t;
}
Point reflection(Line l,Point p) {
  return p + (projection(l, p) - p) * 2;
}
double distanceLP(Line l, Point p) {
  return abs(p - projection(l, p));
}
double distanceLL(Line l, Line m) {
  return intersectLL(l, m) ? 0 : distanceLP(l, m.p1);
}

double distanceLS(Line l, Line s) {
  if (intersectLS(l, s)) return 0;
  return min(distanceLP(l, s.p1), distanceLP(l, s.p2));
}
double distanceSP(Line s, Point p) {
  Point r = projection(s, p);
  if (intersectSP(s, r)) return abs(r - p);
  return min(abs(s.p1 - p), abs(s.p2 - p));
}

double distanceSS(Line s, Line t) {
  if (intersectSS(s, t)) return 0;
  return min(min(distanceSP(s, t.p1), distanceSP(s, t.p2)),
             min(distanceSP(t, s.p1), distanceSP(t, s.p2)));
}

/*
same lineの時注意
もしm.p1が中心でなかったときに正しい答えとならない
Point crosspoint(Line l,Line m){
  double A = cross(l.p2-l.p1,m.p2-m.p1);
  double B = cross(l.p2-l.p1,l.p2-m.p1);
  if(abs(A) < EPS && abs(B) < EPS){
    vector<Point> vec;
    vec.push_back(l.p1),vec.push_back(l.p2),vec.push_back(m.p1),vec.push_back(m.p2);
    sort(vec.begin(),vec.end());
    assert(vec[1] == vec[2]);
    return vec[1];
    //return m.p1;
  }
  if(abs(A) < EPS)assert(false);
  return m.p1 + (m.p2-m.p1)*(B/A);
}

*/
Point crosspoint(Line l, Line m) {
  double A = cross(l.p2 - l.p1, m.p2 - m.p1);
  double B = cross(l.p2 - l.p1, l.p2 - m.p1);
  if (abs(A) < EPS && abs(B) < EPS) return m.p1; // same line
  if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return m.p1 +   (m.p2 - m.p1) * (B / A);
}

// intersect END

int array[6000];

double areaT(double a,double b,double c){
  double s = (a+b+c)/2.0;
  return sqrt(s*(s-a)*(s-b)*(s-c));
}

double areaH(double h,double *a){ return ( areaT(a[0],a[1],a[2]) * h) / 3.0; }

bool LTE(double a,double b){ return equals(a,b) || a < b; }

bool LT(double a,double b){ return !equals(a,b) && a < b; }

bool GTE(double a,double b){ return equals(a,b) || a > b; }

bool check1(double a,double b,double c){ return a + b >= c; }

bool checkT(double a,double b,double c){ return LT(a,b+c) && LT(b,a+c) && LT(c,a+b); }

bool check2(double h,double *a){
  if( LTE(a[3]*a[3]-h*h,0) || LTE(a[4]*a[4]-h*h,0) || LTE(a[5]*a[5]-h*h,0) ) return false;
  double L1 = sqrt(a[3]*a[3]-h*h);
  double L2 = sqrt(a[4]*a[4]-h*h);
  double L3 = sqrt(a[5]*a[5]-h*h);
  if( LTE(L1,0) || LTE(L2,0) || LTE(L3,0) ) return false;
  if( !checkT(L1,L2,a[0]) || !checkT(L2,L3,a[2]) || !checkT(L2,L3,a[2]) ) return false;
  cout << endl;
  cout << L1 << " " << L2 << " " << L3 << endl;
  double tmp_area = areaT(L1,L2,a[0]) + areaT(L2,L3,a[2]) + areaT(L1,L3,a[1]);
  cout << tmp_area << " (" << areaT(L1,L2,a[0]) << "+" << areaT(L2,L3,a[2]) << "+" << areaT(L1,L3,a[1]) << ") "<< " ?= " << areaT(a[0],a[1],a[2]) << endl;
  return equals(tmp_area,areaT(a[0],a[1],a[2]));
}

Segment gen(Point p1,Point p2,double a,double b,double c,bool &error){
  double S = areaT(a,b,c);
  cout << "S = " << S << endl;
  double h = 2 * S / a;
  if( LTE(h,0) ) error = true;
  if( LTE(b*b-h*h,0) ) error = true;
  if( error ) return Segment();
  cout << c * c << " - " << h*h << endl;  
double x = sqrt(c*c-h*h);
    cout << h << "," << x << endl;
  Segment seg;
  seg.p1 = p1;
  Vector v = p2 - p1;
  Vector ve = v / abs(v);
  seg.p2 = p1 + ve * x;
  cout << v << endl;
  v = rotate(v,toRad(90));
  cout << v << endl;
  ve = v / abs(v);
  seg.p2 = seg.p2 + ve * h;
  return seg;
}

//
  typedef vector<int> VI;
  typedef vector<VI> VVI;
  typedef VVI matrix;



matrix identity(int n)
{
  matrix A(n,vector<int>(n));
  for(int i=0;i<n;i++) A[i][i] = 1;
  return A;
}


vector<int> multi(const matrix& A,const vector<int>& B)
{
  vector<int> ret(A.size());
  for(int i=0;i<A.size();++i)
    for(int j=0;j<A[0].size();++j)
      ret[i] += A[i][j]*B[j];
  return ret;
}


matrix multi(const matrix& A,const matrix& B)
{
  matrix C(A.size(),vector<int>(B[0].size()));
  for(int i=0;i<C.size();++i)
    for(int j=0;j<C[i].size();++j)
      for(int k=0;k<A[i].size();++k)
	C[i][j] += A[i][k]*B[k][j];
  return C;
}



matrix pow(const matrix& A,int e)
{
  return !e?identity(A.size()):
    (e%2?multi(A,pow(A,e-1)):pow(multi(A,A),e/2));
}
/*
冪乗に関するちょいと解説
行列をAする
A^2 = A*A, A^4 = (A^2)*(A^2), A^8 = (A^4)*(A^4) ・・・・と計算している
行列に限ったことでなく、普通の値の冪乗でも同じように考えることができる
*/


int extgcd(int a,int b,int& x,int& y)
{
  int d = a;
  if(b != 0){
    d = extgcd(b,a%b,y,x);
    y -= (a/b)*x;
  }
  else
    x = 1,y = 0;
  return d;
}

int mod_inv(int a,int m)
{
  int x,y;
  extgcd(a,m,x,y);
  return (m+x%m)%m;
}


int rank(vector<vector<int> > A,int mod)
{
  int H = A.size(), W = A[0].size();
  int r = 0;
  rep(x,W)
    {  
      int pivot = inf;
      REP(y,r,H)
	if(A[y][x])
	  {
	    pivot = y;
	    break;
	  }
      if(pivot == inf)continue;
      swap(A[r],A[pivot]);

      REP(y,r+1,H)
	{
	  int value = A[y][x] * mod_inv(A[r][x],mod) % mod;
	  if(value)REP(x2,x,W)
		     A[y][x2] = ((A[y][x2] - A[r][x2] * value)%mod + mod ) % mod; 
	}
      r++;
    }
  return r;
}


/*

Ax=bが解を持つ必要十分条件は、
rank(A) = rank(A|b)
であり、
Ax=bが一意の解を持つ必要十分条件は、
rank(A) = rank(A|b) = n
*/

bool modGaussElimination(vector<vector<int> > &A, vector<int> &b, int m, vector<int> &res) {
  int n = A.size();
  vector<vector<int> > B(n, vector<int>(n+1));
  rep(i,n) rep(j,n)
    B[i][j] = A[i][j];
  rep(i, n) B[i][n] = b[i];
  
  int nowy = 0;
  rep(x, n) {
    int pivot = -1;
    for (int j=nowy; j<n; ++j)
      if (B[j][x]) {
        pivot = j;break;
      }
    if (pivot == -1) continue;
    swap(B[nowy], B[pivot]);

    for (int j=nowy+1; j<n; ++j) {
      int t = B[j][x] * mod_inv(B[nowy][x], m) % m;
      if (t)
        for (int k=x; k<=n; ++k)
          B[j][k] = ((B[j][k] - B[nowy][k] * t)%m + m )%m;
    }
    nowy++;
    
  }

  res.clear();
  for (int y=nowy; y<n; ++y)
    if (B[y][n])                // rank(A) != rank(A|b)
      return 0;
  if (nowy != n) {              // rank(A) == rank(A|b) != n
    // 解が一意でない。ひとつ求める
    res = vector<int>(n,inf);           // INFは任意を表す
    for (int y=n-1; y>=0; --y) {
      int x;
      for (x=y; x<n; ++x) {
        if (B[y][x])
          break;
      }
      if (x==n) continue;
      int sum = B[y][n];
      
      for (int i=x+1; i<n; ++i) {
        if (res[i] == inf) res[i] = 0; // この時点でres[i]が決まってなかったら0とする
        sum = ((sum - res[i] * B[y][i])%m + m)%m;
      }
      res[x] = sum * mod_inv(B[y][x], m) % m;
    }
    rep(i, n) if (res[i]==inf) res[i] = 0;
    return 0;
  }
  // 解が一意に決まる。普通に後退代入
  res.resize(n);
  for (int x=n-1; x>=0; --x) {
    int sum = B[x][n];
    for (int i=n-1; i>x; --i) {
      sum = ((sum - res[i] * B[x][i])%m + m)%m; 
    }
    res[x] = sum * mod_inv(B[x][x], m) % m;
  }
  return 1;
}

//double det(vector<vector<double> > &A) {
double det(double A[5][5]) {
  const int n = 5;
  double D = 1;
  for (int i = 0; i < n; ++i) {
    int pivot = i;
    for (int j = i+1; j < n; ++j)
      if (abs(A[j][i]) > abs(A[pivot][i])) pivot = j;
    swap(A[pivot], A[i]);
    D *= A[i][i] * (i != pivot ? -1 : 1);
    if (abs(A[i][i]) < EPS) break;
    for(int j = i+1; j < n; ++j)
      for(int k = n-1; k >= i; --k)
        A[j][k] -= A[i][k] * A[j][i] / A[i][i];
  }
  return D;
}


//

double getAreaTetrahedra(double *A){
  double a = A[3], b = A[1], c = A[0], p = A[5], q = A[4], r = A[2];

  /*
  vector<vector<double> > mat(5,vector<double>(5,0));
  mat[0][1] = p*p, mat[0][2] = q*q, mat[0][3] = a*a, mat[0][4] = 1;
  mat[1][0] = p*p, mat[1][2] = r*r, mat[1][3] = b*b, mat[1][4] = 1;
  mat[2][0] = q*q, mat[2][1] = r*r, mat[2][3] = c*c, mat[2][4] = 1;
  mat[3][0] = a*a, mat[3][1] = b*b, mat[3][2] = c*c, mat[3][4] = 1;
  mat[4][0] = 1,   mat[4][1] = 1,   mat[4][2] = 1,   mat[4][3] = 1;
  */
  double mat[5][5] = {{0,p*p,q*q,a*a,1},{p*p,0,r*r,b*b,1},{q*q,r*r,0,c*c,1},{a*a,b*b,c*c,0,1},{1,1,1,1,0}};
  return det(mat)/288.0;
}

double calc(double *a){
  double ret = 0;
  do{
  if( !checkT(a[0],a[1],a[2]) || !checkT(a[0],a[3],a[4]) || !checkT(a[1],a[3],a[5]) || !checkT(a[2],a[4],a[5]) ) continue;
  /*
    Point p1(0,0);
    Point p2(a[1],0);
    double theta = acos( ( a[0]*a[0] + a[1]*a[1] - a[2]*a[2] ) / ( 2*a[0]*a[1] ) );
    Point p3(a[0]*cos(theta),a[0]*sin(theta));
    //cout << p1 << " " << p2 << " " << p3 << endl;
    double A = a[1], b =a[0], c = a[2];
    double x0 = (A*A-b*b-c*c)/(2*A);
    //cout << "(" << (A*A-b*b-c*c)/(2*A) << "," << sqrt(b*b-x0*x0)<<")"<<endl;
    */
    //if( error ) continue;
    //if( error ) continue;
    //if( LTE(a[3]*a[3]-x*x,0) ) continue;
    //if( LTE(h,0) ) continue;
    ret = max(ret,sqrt(getAreaTetrahedra(a)));
    }while(next_permutation(a,a+6));
    return ret;
}

int main(){
  /*
  double a[6] = {2,2,2,2,2,2};
  cout << calc(a) << endl;
  return 0;
  */
  int dex = 0;
  rep(i,(1<<15)) if( __builtin_popcount(i) == 6 ) array[dex++] = i;
  int N,input[16];
  while( scanf("%d",&N), N ){
    rep(i,N) scanf("%d",input+i);
    sort(input,input+N);
    double maxi = 0;
    rep(k,dex){
      int bitmask = array[k];
      if( bitmask >= (1<<N) ) break;
      double buf[6];
      int cur = 0;
      rep(j,N) if( (bitmask>>j) & 1 ) buf[cur++] = input[j];
      maxi = max(maxi,calc(buf));
    }
    printf("%.10f\n",maxi);
  }
  return 0;
}

Measured memory_bytes: 1288