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.io.*;
import java.util.*;
import java.util.function.Function;

public class D_378_div2
{
    private static BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
    private static StringTokenizer stringTokenizer = null;
    private static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));

    private static String next() throws IOException
    {
        while ((stringTokenizer == null) || (!stringTokenizer.hasMoreTokens()))
        {
            stringTokenizer = new StringTokenizer(bufferedReader.readLine());
        }
        return stringTokenizer.nextToken();
    }

    public static int nextInt() throws IOException
    {
        return Integer.parseInt(next());
    }

    public static double nextDouble() throws IOException
    {
        return Double.parseDouble(next());
    }

    public static long nextLong() throws IOException
    {
        return Long.parseLong(next());
    }

    public static String nextLine() throws IOException
    {
        return bufferedReader.readLine();
    }

    public static void close()
    {
        out.close();
    }

    public static final long[] POWER2 = generatePOWER2();

    public static long divideCeil(long x, long y)
    {
        return x / y + (x % y == 0 ? 0 : 1);
    }

    public static long[] generatePOWER2()
    {
        long[] result = new long[63];
        for (int x = 0; x < result.length; x++)
        {
            result[x] = 1L << x;
        }
        return result;
    }

    interface BiFunctionResult<Type0, Type1, TypeResult>
    {
        TypeResult apply(Type0 x0, Type1 x1, TypeResult x2);
    }

    static abstract class Edge<TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>>
    {
        public final TypeVertex vertex0;
        public final TypeVertex vertex1;

        public Edge(TypeVertex vertex0, TypeVertex vertex1, boolean bidirectional)
        {
            this.vertex0 = vertex0;
            this.vertex1 = vertex1;
            this.vertex0.edges.put(vertex1, getThis());
            if (bidirectional)
            {
                this.vertex1.edges.put(vertex0, getThis());
            }
        }

        private TypeVertex other(Vertex<TypeVertex, TypeEdge> vertex)
        {
            TypeVertex result;
            if (vertex0 == vertex)
            {
                result = vertex1;
            }
            else
            {
                result = vertex0;
            }
            return result;
        }

        public TypeVertex from(Vertex<TypeVertex, TypeEdge> to)
        {
            return other(to);
        }

        public TypeVertex to(Vertex<TypeVertex, TypeEdge> from)
        {
            return other(from);
        }

        public abstract TypeEdge getThis();
    }

    public static class Vertex<TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>> implements Comparable<Vertex<? super TypeVertex, ? super TypeEdge>>
    {
        public final int index;
        public final Map<TypeVertex, TypeEdge> edges;

        public Vertex(int index)
        {
            this.index = index;
            this.edges = new TreeMap<>();
        }

        public static <TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>, TypeResult> TypeResult depthFirstSearch(
                BiFunctionResult<TypeVertex, TypeEdge, TypeResult> function,
                TypeVertex vertex,
                TypeEdge edge,
                TypeResult result,
                boolean[] visited
        )
        {
            if (!visited[vertex.index])
            {
                visited[vertex.index] = true;
                result = function.apply(vertex, edge, result);
                for (Map.Entry<TypeVertex, TypeEdge> entry : vertex.edges.entrySet())
                {
                    TypeVertex vertexNext = entry.getKey();
                    TypeEdge edgeNext = entry.getValue();
                    result = depthFirstSearch(function, vertexNext, edgeNext, result, visited);
                }
            }
            return result;
        }

        public static <TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>, TypeResult> TypeResult depthFirstSearch(
                TypeVertex[] vertices,
                int indexVertexStart,
                BiFunctionResult<TypeVertex, TypeEdge, TypeResult> function,
                TypeResult result
        )
        {
            boolean[] visited = new boolean[vertices.length];
            return depthFirstSearch(function, vertices[indexVertexStart], null, result, visited);
        }

        public static <TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>, TypeResult> TypeResult breadthFirstSearch(
                TypeVertex[] vertices,
                int indexVertexStart,
                BiFunctionResult<TypeVertex, TypeEdge, TypeResult> function,
                TypeResult result
        )
        {
            boolean[] visited = new boolean[vertices.length];
            LIFO<TypeVertex> verticesNext = new LIFO<>();
            verticesNext.push(vertices[indexVertexStart]);
            LIFO<TypeEdge> edgesNext = new LIFO<>();
            edgesNext.push(null);
            while (!verticesNext.isEmpty())
            {
                TypeVertex vertex = verticesNext.pop();
                TypeEdge edge = edgesNext.pop();
                if (!visited[vertex.index])
                {
                    visited[vertex.index] = true;
                    result = function.apply(vertex, edge, result);
                    for (Map.Entry<TypeVertex, TypeEdge> entry : vertex.edges.entrySet())
                    {
                        TypeVertex vertexNext = entry.getKey();
                        TypeEdge edgeNext = entry.getValue();
                        if (!visited[vertexNext.index])
                        {
                            verticesNext.push(vertexNext);
                            edgesNext.push(edgeNext);
                        }
                    }
                }
            }
            return result;
        }

        @Override
        public int compareTo(Vertex<? super TypeVertex, ? super TypeEdge> that)
        {
            return that.index - this.index;
        }
    }

    public static class Tuple2<Type0, Type1>
    {
        public final Type0 v0;
        public final Type1 v1;

        public Tuple2(Type0 v0, Type1 v1)
        {
            this.v0 = v0;
            this.v1 = v1;
        }
    }

    public static class Tuple2Comparable<Type0 extends Comparable<? super Type0>, Type1 extends Comparable<? super Type1>> extends Tuple2<Type0, Type1> implements Comparable<Tuple2Comparable<Type0, Type1>>
    {
        public Tuple2Comparable(Type0 v0, Type1 v1)
        {
            super(v0, v1);
        }

        @Override
        public int compareTo(Tuple2Comparable<Type0, Type1> that)
        {
            int result = this.v0.compareTo(that.v0);
            if (result == 0)
            {
                result = this.v1.compareTo(that.v1);
            }
            return result;
        }
    }

    public static class SingleLinkedList<Type>
    {
        public final Type element;
        public SingleLinkedList<Type> next;

        public SingleLinkedList(Type element, SingleLinkedList<Type> next)
        {
            this.element = element;
            this.next = next;
        }

        public void toCollection(Collection<Type> collection)
        {
            if (this.next != null)
            {
                this.next.toCollection(collection);
            }
            collection.add(this.element);
        }
    }

    public static class LIFO<Type>
    {
        public SingleLinkedList<Type> start;
        public SingleLinkedList<Type> end;

        public LIFO()
        {
            this.start = null;
            this.end = null;
        }

        public void push(Type element)
        {
            SingleLinkedList<Type> list = new SingleLinkedList<>(element, null);
            if (this.start == null)
            {
                this.start = list;
                this.end = list;
            }
            else
            {
                this.end.next = list;
                this.end = list;
            }
        }

        public Type pop()
        {
            Type result = this.start.element;
            this.start = this.start.next;
            return result;
        }

        public boolean isEmpty()
        {
            return this.start == null;
        }
    }

    public static class MapCount extends TreeMap<Long, Long>
    {
        private int size;

        public MapCount()
        {
            this.size = 0;
        }

        public MapCount(Comparator<? super Long> comparator)
        {
            super(comparator);
        }

        public long add(Long key, Long delta)
        {
            long result;
            if (delta > 0)
            {
                Long value = get(key);
                if (value == null)
                {
                    value = delta;
                }
                else
                {
                    value += delta;
                }
                put(key, value);
                result = delta;
            }
            else
            {
                result = 0;
            }
            this.size += result;
            return result;
        }

        public long remove(Long key, Long delta)
        {
            long result;
            if (delta > 0)
            {
                Long value = get(key) - delta;
                if (value <= 0)
                {
                    result = delta + value;
                    remove(key);
                }
                else
                {
                    result = delta;
                    put(key, value);
                }
            }
            else
            {
                result = 0;
            }
            this.size -= result;
            return result;
        }

        public int size()
        {
            return this.size;
        }
    }

    public static class MapSet<TypeKey extends Comparable<? super TypeKey>, TypeValue> extends TreeMap<TypeKey, TreeSet<TypeValue>> implements Iterable<TypeValue>
    {
        private int size;
        private Comparator<? super TypeValue> comparatorValue;

        public MapSet()
        {
            this(null);
        }

        public MapSet(Comparator<? super TypeValue> comparatorValue)
        {
            super();
            this.size = 0;
            this.comparatorValue = comparatorValue;
        }

        public TypeValue firstValue()
        {
            TypeValue result;
            Map.Entry<TypeKey, TreeSet<TypeValue>> firstEntry = firstEntry();
            if (firstEntry == null)
            {
                result = null;
            }
            else
            {
                result = firstEntry.getValue().first();
            }
            return result;
        }

        public Iterator<TypeValue> iterator()
        {
            return new Iterator<TypeValue>()
            {
                Iterator<TreeSet<TypeValue>> iteratorValues = values().iterator();
                Iterator<TypeValue> iteratorValue = null;

                @Override
                public boolean hasNext()
                {
                    return iteratorValues.hasNext() || (iteratorValue != null && iteratorValue.hasNext());
                }

                @Override
                public TypeValue next()
                {
                    if (iteratorValue == null || !iteratorValue.hasNext())
                    {
                        iteratorValue = iteratorValues.next().iterator();
                    }
                    return iteratorValue.next();
                }
            };
        }

        public TypeValue lastValue()
        {
            TypeValue result;
            Map.Entry<TypeKey, TreeSet<TypeValue>> lastEntry = lastEntry();
            if (lastEntry == null)
            {
                result = null;
            }
            else
            {
                result = lastEntry.getValue().last();
            }
            return result;
        }

        public boolean add(TypeKey key, TypeValue value)
        {
            TreeSet<TypeValue> set = get(key);
            if (set == null)
            {
                if (comparatorValue == null)
                {
                    set = new TreeSet<>();
                }
                else
                {
                    set = new TreeSet<>(comparatorValue);
                }
                put(key, set);
            }
            boolean result = set.add(value);
            if (result)
            {
                this.size += 1;
            }
            return result;
        }

        public boolean remove(TypeKey key, TypeValue value)
        {
            boolean result;
            TreeSet<TypeValue> set = get(key);
            if (set == null)
            {
                result = false;
            }
            else
            {
                result = set.remove(value);
                if (set.size() == 0)
                {
                    remove(key);
                }
                if (result)
                {
                    this.size -= 1;
                }
            }
            return result;
        }

        @Override
        public int size()
        {
            return this.size;
        }
    }

    public static int binarySearchMinimum(Function<Integer, Boolean> filter, int start, int end)
    {
        int result;
        if (start == end)
        {
            result = end;
        }
        else
        {
            int middle = start + (end - start) / 2;
            if (filter.apply(middle))
            {
                result = binarySearchMinimum(filter, start, middle);
            }
            else
            {
                result = binarySearchMinimum(filter, middle + 1, end);
            }
        }
        return result;
    }

    public static int binarySearchMaximum(Function<Integer, Boolean> filter, int start, int end)
    {
        return -binarySearchMinimum(x -> filter.apply(-x), -end, -start);
    }

    public static long faculty(int n)
    {
        long result = 1;
        for (int index = 2; index <= n; index++)
        {
            result *= index;
        }
        return result;
    }

    public static <T> List<T> permutation(long p, List<T> x)
    {
        List<T> copy = new ArrayList<>();
        for (int index = 0; index < x.size(); index++)
        {
            copy.add(x.get(index));
        }
        List<T> result = new ArrayList<>();
        for (int indexTo = 0; indexTo < x.size(); indexTo++)
        {
            int indexFrom = (int) p % copy.size();
            p = p / copy.size();
            result.add(copy.remove(indexFrom));
        }
        return result;
    }

    public static <Type> void println(Iterable<Type> iterable)
    {
        Iterator<Type> iterator = iterable.iterator();
        if (iterator.hasNext())
        {
            out.print(iterator.next());
        }
        while (iterator.hasNext())
        {
            out.print(" " + iterator.next());
        }
        out.println();
    }

    public static <Type> void println(Type[] array)
    {
        println(Arrays.asList(array));
    }

    public static void main(String[] args)
    {
        try
        {
            solve();
        } catch (IOException exception)
        {
            exception.printStackTrace();
        }
        close();
    }

    static class Stone
    {
        public final int index;
        public final int a;
        public final int b;
        public final int c;

        public Stone(int index, int a, int b, int c)
        {
            this.index = index;
            int[] order = new int[]{a, b, c};
            Arrays.sort(order);
            this.a = order[0];
            this.b = order[1];
            this.c = order[2];
        }

        public String toString()
        {
            return "" + (index + 1);
        }
    }

    static class StoneRotation
    {
        public final Stone stone;
        public final int size;

        public StoneRotation(Stone stone, int size)
        {
            this.stone = stone;
            this.size = size;
        }

        public String toString()
        {
            return this.stone.toString();
        }
    }

    public static Tuple2<StoneRotation[], Integer> maximum(Tuple2<StoneRotation[], Integer> x, Tuple2<StoneRotation[], Integer> y)
    {
        Tuple2<StoneRotation[], Integer> result;
        if (x.v1 < y.v1)
        {
            result = y;
        }
        else
        {
            result = x;
        }
        return result;
    }

    public static int minimum(int a, int b, int c)
    {
        return Math.min(Math.min(a, b), c);
    }

    public static void addSkipDoubles(MapSet<Tuple2Comparable<Integer, Integer>, StoneRotation> face2StoneRotations, Set<Tuple2Comparable<Integer, Integer>> faces, Stone stone, int a, int b, int c)
    {
        Tuple2Comparable<Integer, Integer> face = new Tuple2Comparable<>(a, b);
        if (!faces.contains(face))
        {
            faces.add(face);
            face2StoneRotations.add(face, new StoneRotation(stone, c));
        }
    }

    public static Tuple2<StoneRotation[], Integer> solve(Stone[] stones)
    {
        Tuple2<StoneRotation[], Integer> result = new Tuple2<>(null, 0);
        MapSet<Tuple2Comparable<Integer, Integer>, StoneRotation> face2StoneRotations = new MapSet<>((x, y) -> Integer.compare(y.size, x.size) == 0 ? Integer.compare(x.stone.index, y.stone.index) : Integer.compare(y.size, x.size));
        for (Stone stone : stones)
        {
            Set<Tuple2Comparable<Integer, Integer>> faces = new TreeSet<>();
            addSkipDoubles(face2StoneRotations, faces, stone, stone.a, stone.b, stone.c);
            addSkipDoubles(face2StoneRotations, faces, stone, stone.a, stone.c, stone.b);
            addSkipDoubles(face2StoneRotations, faces, stone, stone.b, stone.c, stone.a);
        }
        for (Map.Entry<Tuple2Comparable<Integer, Integer>, TreeSet<StoneRotation>> entry : face2StoneRotations.entrySet())
        {
            Tuple2Comparable<Integer, Integer> face = entry.getKey();
            TreeSet<StoneRotation> stonesSameFace = entry.getValue();
            Tuple2<StoneRotation[], Integer> stoneRotations2SumSize;
            if (stonesSameFace.size() == 1)
            {
                StoneRotation first = stonesSameFace.first();
                stoneRotations2SumSize = new Tuple2<>(new StoneRotation[]{first}, minimum(face.v0, face.v1, first.size));
            }
            else
            {
                Iterator<StoneRotation> iterator = stonesSameFace.iterator();
                StoneRotation first = iterator.next();
                StoneRotation second = iterator.next();
                stoneRotations2SumSize = new Tuple2<>(new StoneRotation[]{first, second}, minimum(face.v0, face.v1, first.size + second.size));
            }
            result = maximum(result, stoneRotations2SumSize);
        }
        return result;
    }

    public static void solve() throws IOException
    {
        int n = nextInt();
        Stone[] stones = new Stone[n];
        for (int index = 0; index < n; index++)
        {
            int a = nextInt();
            int b = nextInt();
            int c = nextInt();
            stones[index] = new Stone(index, a, b, c);
        }
        Tuple2<StoneRotation[], Integer> result = solve(stones);
        out.println(result.v0.length);
        println(result.v0);
    }
}