As you know, Bob's brother lives in Flatland. In Flatland there are n cities, connected by n - 1 two-way roads. The cities are numbered from 1 to n. You can get from one city to another moving along the roads.

The «Two Paths» company, where Bob's brother works, has won a tender to repair two paths in Flatland. A path is a sequence of different cities, connected sequentially by roads. The company is allowed to choose by itself the paths to repair. The only condition they have to meet is that the two paths shouldn't cross (i.e. shouldn't have common cities).

It is known that the profit, the «Two Paths» company will get, equals the product of the lengths of the two paths. Let's consider the length of each road equals 1, and the length of a path equals the amount of roads in it. Find the maximum possible profit for the company.

Input

The first line contains an integer n (2 ≤ n ≤ 200), where n is the amount of cities in the country. The following n - 1 lines contain the information about the roads. Each line contains a pair of numbers of the cities, connected by the road ai, bi (1 ≤ ai, bi ≤ n).

Output

Output the maximum possible profit.

Examples

Input

4
1 2
2 3
3 4


Output

1


Input

7
1 2
1 3
1 4
1 5
1 6
1 7


Output

0


Input

6
1 2
2 3
2 4
5 4
6 4


Output

4
import java.io.*;
import java.util.*;
import java.math.*;

public class Main implements Runnable {
  static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
  static StringTokenizer st = new StringTokenizer("");

  public static String next() {
    try {
    while (!st.hasMoreTokens()) {
      String s = br.readLine();
      if (s == null)
        return null;
      st = new StringTokenizer(s);
    }
    return st.nextToken();
    } catch(Exception e)  {
      return  null;
    }
  }

  public static void main(String[] asda) throws Exception {
    new Thread(null, new Main(), "Main", 1<<26).start();
  }

  public void run() {
    N = Integer.parseInt( next() );
    g = new LinkedList[2*N];
    for (int k = 0; k < g.length; k++) {
      g[k] = new LinkedList<>();
    }

    int[] lastDummyVertex = new int[N];
    for (int k = 0; k < N; k++)
      lastDummyVertex[k] = k;

    createdBy = new int[2*N];
    Arrays.fill(createdBy, -1);

    int nextDummyVertex = N;
    final int MAX_SIZE = 10;
    for (int k = 1; k < N; k++) {
      int a = Integer.parseInt( next() ) - 1;
      int b = Integer.parseInt( next() ) - 1;
      int lastA = lastDummyVertex[a];
      int lastB = lastDummyVertex[b];
      if (g[lastA].size() + 1 == MAX_SIZE) {
      //  out.printf("link(%d, %d)\n", lastA+1, nextDummyVertex + 1);
        // add edge: a -> dummy vertex
        g[lastA].add(nextDummyVertex);
        g[nextDummyVertex].add(lastA);
        createdBy[nextDummyVertex] = lastA;
        lastDummyVertex[a] = lastA = nextDummyVertex++;
      }
      if (g[lastB].size() + 1 == MAX_SIZE) {
      //  out.printf(" link(%d, %d)\n", lastB+1, nextDummyVertex + 1);
        // b -> dummy vertex
        g[lastB].add(nextDummyVertex);
        g[nextDummyVertex].add(lastB);
        createdBy[nextDummyVertex] = lastB;
        lastDummyVertex[b] = lastB = nextDummyVertex++;
      }
      g[lastA].add(lastB);
      g[lastB].add(lastA);
    }

    // print graph
    // out.println("graph");
    // for (int k = 0; k < g.length; k++) for (int m : g[k]) if (k < m){
    //   out.printf("%d %d\n", k+1, m+1);
    // }
    // out.print("createdBy:");
    // for (int k = N; k < nextDummyVertex; k++)
    //   out.printf(" (%d <- %d)", k+1, createdBy[k]+1);
    // out.println();
    // out.flush();

    out.println( solve() );
    out.flush();
    System.exit(0);
  }

    //
  boolean isDummy(int vertex) {
    return vertex >= N;
  }
  int getWeight(int vertex) {
    return isDummy(vertex) ? 0 : 1;
  }

  int N; // number of nodes
  List<Integer>[] g; // graph representation, g[k] = list of nodes adjacent to k

  // return the answer to the problem iterating over every possible edge
  long solve()  {
    longestPath = new int[2*N][11];
    deepestLevel = new int[2][2*N][11];
    for (int k = 0; k < g.length; k++) {
      Arrays.fill(longestPath[k], -1);
    }

    long best = 0;
    for (int id = 0; id < N; id++)  {
      for (int to : g[id])  {
        long x = dfs(id, to) - 1;
        long y = dfs(to, id) - 1;
        best = Math.max(best, x*y);

        // out.printf("remove(%d, %d) = (%d, %d)\n", id+1, to+1, x, y);
      }
    }
    return best;
  }

  int[][] longestPath;  // longestPath[k] = size of the longest path in subtree k
  int[][][] deepestLevel; // deepestLevel[v][p] = max two deepest levels in subtree comming from p
  int[] createdBy;
  // returns the longest path in the sub tree rooted at id ignoring edge(id, parent)
  // also computes the deepest possible level for the same sub tree
  // note, the path length every node counts, subtract 1 to count edges only
  int dfs(int vertex, int parent)  {
    int parentIndex = g[vertex].indexOf(parent);
 //   System.out.printf("dfs(%d, %d), parentIndex = %d\n", id + 1, parent + 1, parentIndex);
    if (longestPath[vertex][parentIndex] != -1) {
      return longestPath[vertex][parentIndex];
    }

    int currentLongestPath = getWeight(vertex);
    PriorityQueue<Integer> queue = new PriorityQueue<>(4);
    for (int to : g[vertex])  if (parent != to) {
      int sonLogestPath = dfs(to, vertex);
      currentLongestPath = Math.max(currentLongestPath, sonLogestPath);

      queue.add( deepestLevel[0][to][ g[to].indexOf(vertex) ] + getWeight(to) );
      if (isDummy(to))
        queue.add( deepestLevel[1][to][ g[to].indexOf(vertex) ] + getWeight(to) );

      while (queue.size() > 2)
        queue.poll();
    }

    // ensure two deepest levels
    int firstDeepestLevel = 0;
    int secondDeepestLevel = 0;
    switch (queue.size()) {
      case 0:
      break;
      case 1:
        firstDeepestLevel = queue.poll();
      break;
      case 2:
        secondDeepestLevel = queue.poll();
        firstDeepestLevel = queue.poll();
      break;
    }

    // recover deepest levels
    deepestLevel[0][vertex][parentIndex] = firstDeepestLevel;
    deepestLevel[1][vertex][parentIndex] = secondDeepestLevel;
  
    // recover path including vertex
    int vertexPath = getWeight(vertex);
    boolean useVertexPath = true;
    if (isDummy(vertex)) {
      // compute longest path including vertex for dummy vertices
      useVertexPath = createdBy[vertex] != parent;
      int deepestOne = deepestLevel[0][ createdBy[vertex] ][ g[ createdBy[vertex] ].indexOf(vertex) ] + getWeight(createdBy[vertex]);
      int deepestTwo = firstDeepestLevel;
      if (firstDeepestLevel == deepestOne) {
        deepestTwo = secondDeepestLevel;
      }
      vertexPath = deepestOne + deepestTwo;
    } else  {
      // longest path including vertex for real vertices only
      vertexPath += deepestLevel[0][vertex][parentIndex];
      vertexPath += deepestLevel[1][vertex][parentIndex];
    }
    if (useVertexPath) {
      currentLongestPath = Math.max(currentLongestPath, vertexPath);
    }

    longestPath[vertex][parentIndex] = currentLongestPath;

  //  out.printf("dfs(%d, %d) = longest %d, depest (%d, %d), path %d\n", vertex+1, parent+1, currentLongestPath, firstDeepestLevel, secondDeepestLevel, vertexPath);

    return currentLongestPath;
  }
}
