Problem: Kostya is a genial sculptor, he has an idea: to carve a marble sculpture in the shape of a sphere. Kostya has a friend Zahar who works at a career. Zahar knows about Kostya's idea and wants to present him a rectangular parallelepiped of marble from which he can carve the sphere. 

Zahar has n stones which are rectangular parallelepipeds. The edges sizes of the i-th of them are ai, bi and ci. He can take no more than two stones and present them to Kostya. 

If Zahar takes two stones, he should glue them together on one of the faces in order to get a new piece of rectangular parallelepiped of marble. Thus, it is possible to glue a pair of stones together if and only if two faces on which they are glued together match as rectangles. In such gluing it is allowed to rotate and flip the stones in any way. 

Help Zahar choose such a present so that Kostya can carve a sphere of the maximum possible volume and present it to Zahar.

Input

The first line contains the integer n (1 ≤ n ≤ 105).

n lines follow, in the i-th of which there are three integers ai, bi and ci (1 ≤ ai, bi, ci ≤ 109) — the lengths of edges of the i-th stone. Note, that two stones may have exactly the same sizes, but they still will be considered two different stones.

Output

In the first line print k (1 ≤ k ≤ 2) the number of stones which Zahar has chosen. In the second line print k distinct integers from 1 to n — the numbers of stones which Zahar needs to choose. Consider that stones are numbered from 1 to n in the order as they are given in the input data.

You can print the stones in arbitrary order. If there are several answers print any of them. 

Examples

Input

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


Output

1
1


Input

7
10 7 8
5 10 3
4 2 6
5 5 5
10 2 8
4 2 1
7 7 7


Output

2
1 5

Note

In the first example we can connect the pairs of stones:

  * 2 and 4, the size of the parallelepiped: 3 × 2 × 5, the radius of the inscribed sphere 1
  * 2 and 5, the size of the parallelepiped: 3 × 2 × 8 or 6 × 2 × 4 or 3 × 4 × 4, the radius of the inscribed sphere 1, or 1, or 1.5 respectively. 
  * 2 and 6, the size of the parallelepiped: 3 × 5 × 4, the radius of the inscribed sphere 1.5
  * 4 and 5, the size of the parallelepiped: 3 × 2 × 5, the radius of the inscribed sphere 1
  * 5 and 6, the size of the parallelepiped: 3 × 4 × 5, the radius of the inscribed sphere 1.5



Or take only one stone:

  * 1 the size of the parallelepiped: 5 × 5 × 5, the radius of the inscribed sphere 2.5
  * 2 the size of the parallelepiped: 3 × 2 × 4, the radius of the inscribed sphere 1
  * 3 the size of the parallelepiped: 1 × 4 × 1, the radius of the inscribed sphere 0.5
  * 4 the size of the parallelepiped: 2 × 1 × 3, the radius of the inscribed sphere 0.5
  * 5 the size of the parallelepiped: 3 × 2 × 4, the radius of the inscribed sphere 1
  * 6 the size of the parallelepiped: 3 × 3 × 4, the radius of the inscribed sphere 1.5



It is most profitable to take only the first stone. 

Solution (in JAVA):

Solution:

import java.awt.List;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
import java.util.Stack;
import java.util.*;


 
 
public class cool {

	private static InputStream stream;
	private static PrintWriter pw;
	
	
	
//	static int a;
//	static int b;
//	static int f = 0;
	static int n;
	static int m;
//	static int[][] arr;
	//static char[][] arr;
	
	static int Arr[];
	static int tree[];
	
	static int time = 0;
	
	static int[][] dir = {{-1,0},{0,1},{1,0},{0,-1}};

	static int visited[];
	static int visited2[][];
	static Stack<Integer> stack;
	
//	static ArrayList<Integer> ans;

//	static int arr[][];
//	static int arr[];
	static char[][] arr;
	static char[][] ans;
//	static int[][] visited;
//  static int c;
//	static int d[];
//	static int arr[][];
	static ArrayList[] adj;
//	static ArrayList<Integer> ans;
//	static int f;
	static int red[];
	static int black[];
	static int color[];
//	static ArrayList<Integer> comp[];

	static int f = 0;
	static int k = 0;
	static int count = 0;
	static int total = 0;
	static int ini[];
	
	static ArrayList<Node> list;
	static ArrayList<Integer> ind;


	
	public static void main(String[] args){
		//InputReader(System.in);
		pw = new PrintWriter(System.out);
		
		Scanner in = new Scanner(System.in);

		int n = in.nextInt();
		in.nextLine();
		
		Stone[] s = new Stone[n];
		int max = -1;
		int index = -1;
		
		for(int i = 0;i<n;i++){
			int arr[] = new int[3];
			
			arr[0] = in.nextInt();
			arr[1] = in.nextInt();
			arr[2] = in.nextInt();
			
			Arrays.sort(arr);
			s[i] = new Stone(arr[0],arr[1],arr[2],i+1);
			if(arr[0] > max){
				index = i+1;
				max = arr[0];
			}
			
			
			
		}
	
		Arrays.sort(s);
		int f = 0;
		int a = 0;
		int b = 0;
		for(int i = 0;i<n-1;i++){
			if(s[i].b == s[i+1].b && s[i].c == s[i+1].c){
				int arr[] = new int[3];
				
				arr[0] = s[i].a + s[i+1].a;
				arr[1] = s[i].b;
				arr[2] = s[i].c;
				
				Arrays.sort(arr);
				
				if(arr[0] > max){
					f = 1;
					max = arr[0];
					a = s[i].i;
					b = s[i+1].i;
				}
			}
		}
		
		if(f == 0){
			pw.println(1);
			pw.println(index);
		}else{
			pw.println(2);
			pw.println(a + " " + b);
		}
		
		pw.close();
	}
	
	
	public static void dfs(int i){
		
		if(visited[i] == 1)
			return;
		
		if(color[i] == 1){
			return;
		}
		
		visited[i] = 1;
		//System.out.println(i);
	
		for(int j = 0;j<adj[i].size();j++){
			
			Node p = (Node)adj[i].get(j);
			
			if(color[p.a-1] == 0){
				dfs(p.a-1);
			}else{
				count = 0;
				total = p.b;
				bfs(p.a-1);
				
				red[i] += total;
				black[i] += count;
			}
			
			
		}
		
	}
	
	
	public static long ansf(int i){
    	
		if(color[i] == 1)
			return 0;
		
		if(visited[i] == 1){
			return 0;
		}
		
		visited[i] = 1;
		for(int j = 0;j<adj[i].size();j++){
			Node p = (Node)adj[i].get(j);
			
			if(color[p.a-1] == 0 && visited[p.a-1] == 0){
				red[i] += ansf(p.a-1) + p.b*black[p.a-1]+ red[p.a-1];
				black[i] += black[p.a - 1];
			}
		
		}
		//System.out.println(red[i] + " reurn;");
		return red[i];
	
    	
    }
	
	
	public static void bfs(int i){
		if(visited[i] == 1){
			return;
		}
		if(color[i] == 0){
			return;
		}
		visited[i] = 1;
		count++;
		
		
		//System.out.println(i);
		for(int j = 0;j<adj[i].size();j++){
			
			Node p = (Node)adj[i].get(j);
			
			if(color[p.a-1] == 1 && visited[p.a-1] == 0){
				//System.out.println(p.b + " l");
				total += p.b;
				bfs(p.a-1);
			}
		}
		
	}
	
	
	public static long pow(long n,long p,long m){
        long  result = 1;
         if(p==0)
           return 1;
       if (p==1)
           return n;
       while(p!=0)
       {
           if(p%2==1)
               result *= n;
           if(result>=m)
           result%=m;
           p >>=1;
           n*=n;
           if(n>=m)
           n%=m;
       }
       return result;
       }
	

	
	public static int cs(ArrayList<Integer> arr, int low, int high, int x)
	{
	  int mid;    
	 
	  if(x <= arr.get(low))
	    return low; 
	 
	  if(x > arr.get(high))
	    return -1;  
	 
	 
	  mid = (low + high)/2; 
	 
	  if(arr.get(mid) == x)
	    return mid;
	    
	  else if(arr.get(mid) < x)
	  {
	    if(mid + 1 <= high && x <= arr.get(mid+1))
	      return mid + 1;
	    else
	      return cs(arr, mid+1, high, x);
	  }
	   
	  else
	  {
	    if(mid - 1 >= low && x > arr.get(mid-1))
	      return mid;
	    else    
	      return cs(arr, low, mid - 1, x);
	  }
	}
	
	
	public static int fs(int arr[], int low, int high, int x)
	{
	   
	    if (low > high)
	        return -1;
	 
	    if (x >= arr[high])
	        return high;
	 
	    // Find the middle point
	    int mid = (low+high)/2;
	 
	    // If middle point is floor.
	    if (arr[mid] == x)
	        return mid;
	 
	    // If x lies between mid-1 and mid
	    if (mid > 0 && arr[mid-1] <= x && x < arr[mid])
	        return mid-1;
	 
	    // If x is smaller than mid, floor must be in
	    // left half.
	    if (x < arr[mid])
	        return fs(arr, low, mid-1, x);
	 
	    // If mid-1 is not floor and x is greater than
	    // arr[mid],
	    return fs(arr, mid+1, high, x);
	}
	 

	public static long gcd(long x, long y) {
		if (x == 0)
			return y;
		else
			return gcd( y % x,x);
	}
	
//	public static void dfs(int a,int p){
//		System.out.println(a);
//		if(a > 30000){
//			return;
//		}
//		
//		if(visited[a] == 1){
//			return;
//		}
//		
//		visited[a] = 1;
//		
//		if(ini[a] != 0){
//			count+= ini[a];
//		}
//		
//		int l = a-p;
//		
//		if(visited[a+l-1] == 0){
//			dfs(a+l-1,a);
//		}else if(visited[a+l] == 0){
//			dfs(a+l,a);
//		}else if(visited[a+l+1] == 0){
//			dfs(a+l+1,a);
//		}
//		
//	}
//	
	
	
	
	
	
	public static int prev(int i,boolean[] arr){
		
		while(arr[i]){
			if(i == 0){
				if(arr[i]){
					return -1;
				}else{
					return 0;
				}
				
				
			}
			
			
			i--;
			
		}
		
		return i;
		
		
	}
	
	
	public static int next(int i,boolean[] arr){
		
		
		while(arr[i]){
			if(i == arr.length-1){
				if(arr[i]){
					return -1;
				}else{
					return 0;
				}
			}
			
			i++;
		}
		
		
		return i;
	}
	

	
	private static Map<String, Integer> sortByValue(Map<String, Integer> unsortMap) {

        // 1. Convert Map to List of Map
        LinkedList<Entry<String, Integer>> list =
                new LinkedList<Map.Entry<String, Integer>>(unsortMap.entrySet());

        // 2. Sort list with Collections.sort(), provide a custom Comparator
        //    Try switch the o1 o2 position for a different order
        Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
            public int compare(Map.Entry<String, Integer> o1,
                               Map.Entry<String, Integer> o2) {
                return (o1.getValue()).compareTo(o2.getValue());
            }
        });

        // 3. Loop the sorted list and put it into a new insertion order Map LinkedHashMap
        Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
        for (Map.Entry<String, Integer> entry : list) {
            sortedMap.put(entry.getKey(), entry.getValue());
        }

        /*
        //classic iterator example
        for (Iterator<Map.Entry<String, Integer>> it = list.iterator(); it.hasNext(); ) {
            Map.Entry<String, Integer> entry = it.next();
            sortedMap.put(entry.getKey(), entry.getValue());
        }*/


        return sortedMap;
    }

	
	public static ArrayList<Integer> Range(int[] numbers, int target) {
	  

	    int low = 0, high = numbers.length - 1;
	    // get the start index of target number
	    int startIndex = -1;
	    while (low <= high) {
	        int mid = (high - low) / 2 + low;
	        if (numbers[mid] > target) {
	            high = mid - 1;
	        } else if (numbers[mid] == target) {
	            startIndex = mid;
	            high = mid - 1;
	        } else
	            low = mid + 1;
	    }

	    // get the end index of target number
	    int endIndex = -1;
	    low = 0;
	    high = numbers.length - 1;
	    while (low <= high) {
	        int mid = (high - low) / 2 + low;
	        if (numbers[mid] > target) {
	            high = mid - 1;
	        } else if (numbers[mid] == target) {
	            endIndex = mid;
	            low = mid + 1;
	        } else
	            low = mid + 1;
	    }

	    ArrayList<Integer> list = new ArrayList<Integer>();
	    int c = 0;
	    if (startIndex != -1 && endIndex != -1){
	        for(int i = startIndex;i<=endIndex;i++){
	        	list.add(i);
	        }
	    }
	    
	    
	    return list;
	    
	    
	}

	
	
	 private static int root(int Arr[],int i)
	    {
	        while(Arr[ i ] != i)           //chase parent of current element until it reaches root
	        {
	            Arr[ i ] = Arr[ Arr[ i ] ] ; 
	            i = Arr[ i ];
	        }
	        return i;
	    }
	 
	 private static void union(int Arr[],int size[],int A,int B)
	    {
	        int root_A = root(Arr,A);
	        int root_B = root(Arr,B);
	     
	       System.out.println(root_A + " " + root_B);
	        if(root_A != root_B){
	        	 if(size[root_A] < size[root_B ])
	 	        {
	        		 Arr[ root_A ] = Arr[root_B];
	        		 size[root_B] += size[root_A];	 	
	 	        }
	 	        else
	 	        {   	
	 	        	Arr[ root_B ] = Arr[root_A];
	 	        	size[root_A] += size[root_B];	 	   
	 	        }	
	        }
	    }
	 
	 private static boolean find(int A,int B)
	    {
	        if( root(Arr,A)==root(Arr,B) )       //if A and B have the same root, it means that they are connected.
	        return true;
	        else
	        return false;
	    }
	 
	
	


//	
//	public static void bfs(int i){
//		
//		Queue<Integer> q=new LinkedList<Integer>();
//    	q.add(i);
//    	
//    	visited[i] = 1;
//    	c++;
//    	nodes++;
//    	while(!q.isEmpty()){
//    		int top=q.poll();
//    		
//    		Iterator<Integer> it= arr[top].listIterator();
//    		while(it.hasNext()){
//    			int next =it.next();
//    			
//    			if(visited[next] == 0){
//    				nodes++;
//    				visited[next] = 1;
//    				q.add(next);
//    			}
//    		
//    		}
//    	}
//		
//	}
	
	
	
//	public static void dfs(int i){
//		
//		
//		if(visited[i] == 1){
//			return;
//		}
//		
//		visited[i] = 1;
//		con[c].add(i);
//		//System.out.print(i + " ");
//		for(int j = 0;j<arr[i].size();j++){
//			dfs(arr[i].get(j));
//		}
//		
//	}
//	
//	
//	public static void dfss(int i){
//		if(visited[i] == 1){
//			return;
//		}
//		
//		visited[i] = 1;
//		
//		for(int j = 0;j<arr[i].size();j++){
//			dfss(arr[i].get(j));
//		}
//	//	System.out.println(i);
//		stack.push(i);
//	}
//	
//	public static void reverse(){
//		ArrayList[] temp = new ArrayList[n];
//		
//		for(int i = 0;i<n;i++){
//			temp[i] = new ArrayList();
//		}
//		
//		for(int i = 0;i<n;i++){
//			for(int j = 0;j<arr[i].size();j++){
//				temp[arr[i].get(j)].add(i);
//			}
//		}
//		
//		arr = temp;
//		
//	}
//	
//	
	
	
	
	
	
	
	public static boolean isPrime(int n) {
		// Corner cases
		if (n <= 1)
			return false;
		if (n <= 3)
			return true;
 
		// This is checked so that we can skip 
		// middle five numbers in below loop
		if (n % 2 == 0 || n % 3 == 0)
			return false;
 
		for (int i = 5; i * i <= n; i = i + 6)
			if (n % i == 0 || n % (i + 2) == 0)
				return false;
 
		return true;
	}
	
		 
	 // union code starts	
	
	
	 
	 // union code ends
	
	
	 
//	 // Segment tree code begins
//	 
//	 
//	 static void build(int node,int start,int end)
//	 {
//	 if(start==end)
//	 tree[node]=a[start];
//	 else
//	 {
//	 int mid=(start+end)/2;
//	 build(2*node,start,mid);
//	 build(2*node+1,mid+1,end);
//	 if(tree[2*node]<tree[2*node+1])
//	 tree[node]=tree[2*node];
//	 else
//	 tree[node]=tree[2*node+1];
//	 }
//	 }
//	 
//	 
//	 static void update(int node,int start,int end,int idx,int val)
//	 {
//	 if(start==end)
//	 {
//	 a[idx]=val;
//	 tree[node]=val;
//	 }
//	 else
//	 {
//	 int mid=(start+end)/2;
//	 if(idx>=start&&idx<=mid)
//	 update(2*node,start,mid,idx,val);
//	 else
//	 update(2*node+1,mid+1,end,idx,val);
//	 if(tree[2*node]<tree[2*node+1])
//	 tree[node]=tree[2*node];
//	 else
//	 tree[node]=tree[2*node+1];
//	 }
//	 }
//	 
//	 static int query(int node,int start,int end,int l,int r)
//	 {
//	 if(l>end||start>r)
//	 return 100005;
//	 if(l<=start&&r>=end)
//	 return tree[node];
//	 int p1,p2;
//	 int mid=(start+end)/2;
//	 p1=query(2*node,start,mid,l,r);
//	 p2=query(2*node+1,mid+1,end,l,r);
//	 if(p1<p2)
//	 return p1;
//	 else
//	 return p2;
//	 }
//	 
//	 
//	 
//}

}

class Stone implements Comparable<Stone>{
	
	int a;
	int b;
	int c;
	int i;
	
	Stone(int a,int b,int c,int d){
		this.a = a;
		this.b = b;
		this.c = c;
		this.i = d;
	}

	@Override
	public int compareTo(Stone b) {

		if(this.c > b.c){
			return 1;
		}else if(this.c < b.c){
			return -1;
		}else if(this.b > b.b){
			return 1;
		}else if(this.b < b.b){
			return -1;
		}else if(this.a > b.a){
			return 1;
		}else if(this.a < b.a){
			return -1;
		}
		
		return 0;
	}
	

	
	
}


class Node{
	int a;
	int b;
}

class point{
	int a;
	int b;
}


class MyComp2 implements Comparator<Node>{
    
	@Override
	public int compare(Node o1, Node o2) {
		
		if( o1.b > o2.b){
			return 1;
		}else if( o1.b < o2.b){
			return -1;
		}else{
			if(o1.a == o2.a){
				return 0;
			}else if(o1.a > o2.a){
				return 1;
			}else if(o1.a < o2.a){
				return -1;
			}
		}
		
		return 0;
	}
}


class Card implements Comparable<Card>
{
	int a,b;
	public Card(int w,int h)
	{
		this.a=w;
		this.b=h;
		
	}
	public int compareTo(Card that)
	{
		return this.a-that.a;
	}
}