Problem: Fox Ciel is participating in a party in Prime Kingdom. There are n foxes there (include Fox Ciel). The i-th fox is ai years old.

They will have dinner around some round tables. You want to distribute foxes such that:

  1. Each fox is sitting at some table. 
  2. Each table has at least 3 foxes sitting around it. 
  3. The sum of ages of any two adjacent foxes around each table should be a prime number. 



If k foxes f1, f2, ..., fk are sitting around table in clockwise order, then for 1 ≤ i ≤ k - 1: fi and fi + 1 are adjacent, and f1 and fk are also adjacent.

If it is possible to distribute the foxes in the desired manner, find out a way to do that.

Input

The first line contains single integer n (3 ≤ n ≤ 200): the number of foxes in this party. 

The second line contains n integers ai (2 ≤ ai ≤ 104).

Output

If it is impossible to do this, output "Impossible".

Otherwise, in the first line output an integer m (<image>): the number of tables.

Then output m lines, each line should start with an integer k -=– the number of foxes around that table, and then k numbers — indices of fox sitting around that table in clockwise order.

If there are several possible arrangements, output any of them.

Examples

Input

4
3 4 8 9


Output

1
4 1 2 4 3


Input

5
2 2 2 2 2


Output

Impossible


Input

12
2 3 4 5 6 7 8 9 10 11 12 13


Output

1
12 1 2 3 6 5 12 9 8 7 10 11 4


Input

24
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25


Output

3
6 1 2 3 6 5 4
10 7 8 9 12 15 14 13 16 11 10
8 17 18 23 22 19 20 21 24

Note

In example 1, they can sit around one table, their ages are: 3-8-9-4, adjacent sums are: 11, 17, 13 and 7, all those integers are primes.

In example 2, it is not possible: the sum of 2+2 = 4 is not a prime number.

Solution (in JAVA):

Solution:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.StringTokenizer;

public class _510E {

    static int n;
    static int[] a;

    static boolean isPrime(int x) {
        for (int i = 2; i * 2 <= x; i++)
            if (x % i == 0)
                return false;
        return true;
    }

    public static void main(String[] args) throws Exception {
        Reader.init(System.in);
        BufferedWriter cout = new BufferedWriter(new OutputStreamWriter(System.out));

        n = Reader.nextInt();
        a = new int[n];
        for (int i = 0; i < n; i++)
            a[i] = Reader.nextInt();

        int index = 0;
        int source = index++;
        Map<Integer, Integer> reversedMap = new HashMap<>();
        int[] numberIndex = new int[n];
        for (int i = 0; i < n; i++) {
            numberIndex[i] = index;
            reversedMap.put(index, i);
            index++;
        }
        int sink = index++;
        Graph graph = new Graph(index);

        for (int i = 0; i < n; i++)
            if (a[i] % 2 == 0)
                for (int j = 0; j < n; j++)
                    if (a[j] % 2 == 1 && isPrime(a[i] + a[j]))
                        graph.add(numberIndex[i], numberIndex[j], 1, 0);
        for (int i = 0; i < n; i++)
            if (a[i] % 2 == 0)
                graph.add(source, numberIndex[i], 2, 0);
            else
                graph.add(numberIndex[i], sink, 2, 0);

        graph.minCostMaxFlow();
        if (graph.maxFlow < n)
            System.out.println("Impossible");
        else {
            boolean[][] g = new boolean[n][n];
            for (int u = 0; u < index; u++)
                for (MyList node = graph.edge[u].next; node != null; node = node.next) {
                    int v = node.vertex;
                    if (node.capacity > 0 && u != source && u != sink && v != source && v != sink) {
                        g[reversedMap.get(u)][reversedMap.get(v)] = true;
                    }
                }

            final boolean[][] newG = new boolean[n][n];
            for (int i = 0; i < n; i++)
                for (int j = 0; j < n; j++)
                    if (a[i] % 2 == 0 && a[j] % 2 == 1 && isPrime(a[i] + a[j]) && !g[i][j])
                        newG[i][j] = newG[j][i] = true;
            final boolean[] visited = new boolean[n];
            final List<List<Integer>> ans = new ArrayList<>();
            final List<Integer> cand = new ArrayList<>();
            class Function {
                public void dfs(int i) {
                    visited[i] = true;
                    cand.add(i);
                    for (int j = 0; j < n; j++)
                        if (newG[i][j] && !visited[j])
                            dfs(j);
                }
            }
            Function f = new Function();
            for (int i = 0; i < n; i++)
                if (!visited[i]) {
                    cand.clear();
                    f.dfs(i);
                    ans.add(new ArrayList<Integer>(cand));
                }

            cout.write(String.format("%d%n", ans.size()));
            for (List<Integer> list : ans) {
                cout.write(String.format("%d", list.size()));
                for (int num : list)
                    cout.write(String.format(" %d", num + 1));
                cout.write("\n");
            }
        }

        cout.close();
    }

    /*
    2. pku 2135 最小费用最大流，适用于稀疏图，允许多重边，PriorityQueue优化SPFA
    注意！ 在求最大费用流的时候，如果建的图可以保证是DAG，那么可以直接把边的权重*-1；否则需要加上一个非常大的数M，最后再减去。
    */
    static class MyList {
        int vertex;
        int capacity;
        int cost;
        MyList twin;
        MyList next;

        public MyList(int vertex, int capacity, int cost) {
            this.vertex = vertex;
            this.capacity = capacity;
            this.cost = cost;
        }
    }

    /***
     * Assume source = 0, sink = n - 1.
     * Please new the class for each query
     * @author yuan
     */
    static class Graph {
        int n;
        MyList edge[];
        int dist[];
        int pre[];
        MyList preEdge[];
        boolean visited[];
        int maxFlow;
        int totalCost;
        final int INF = Integer.MAX_VALUE >> 1; // Need to be careful here

        public Graph(int n) {
            this.n = n;
            edge = new MyList[n];
            for (int i = 0; i < n; i++)
                edge[i] = new MyList(0, 0, 0); // dummy node
        }

        public void add(int u, int v, int capacity, int cost) {
            MyList ci = new MyList(v, capacity, cost);
            MyList cici = new MyList(u, 0, -cost);
            ci.twin = cici;
            cici.twin = ci;
            ci.next = edge[u].next;
            edge[u].next = ci;
            cici.next = edge[v].next;
            edge[v].next = cici;
        }

        static class State implements Comparable<State> {
            int vertex;
            int dist;

            public State(int vertex, int dist) {
                this.vertex = vertex;
                this.dist = dist;
            }

            @Override
            public int compareTo(State o) {
                return ((Integer) dist).compareTo(o.dist);
            }
        }

        private boolean SPFA() {
            dist = new int[n];
            visited = new boolean[n];
            pre = new int[n];
            preEdge = new MyList[n];
            Queue<State> q = new LinkedList<State>();

            q.add(new State(0, 0));
            for (int i = 0; i < n; i++)
                dist[i] = INF;
            dist[0] = 0;
            visited[0] = true;

            while (!q.isEmpty()) {
                while (true) {
                    int u = q.peek().vertex;
                    int d = q.peek().dist;
                    if (d > dist[u]) {
                        q.poll();
                        q.add(new State(u, dist[u]));
                    } else
                        break;
                }

                int u = q.poll().vertex;
                visited[u] = false;
                for (MyList v = edge[u].next; v != null; v = v.next)
                    if (v.capacity > 0 && dist[u] + v.cost < dist[v.vertex]) {
                        dist[v.vertex] = dist[u] + v.cost;
                        pre[v.vertex] = u;
                        preEdge[v.vertex] = v;
                        if (!visited[v.vertex]) {
                            visited[v.vertex] = true;
                            q.add(new State(v.vertex, dist[v.vertex]));
                        }
                    }
            }
            return dist[n - 1] < INF;
        }

        private void adjust() {
            int flow = Integer.MAX_VALUE;
            for (int i = n - 1; i != pre[i]; i = pre[i])
                flow = Math.min(flow, preEdge[i].capacity);
            for (int i = n - 1; i != pre[i]; i = pre[i]) {
                preEdge[i].capacity -= flow;
                preEdge[i].twin.capacity += flow;
                totalCost += flow * preEdge[i].cost;
            }
            maxFlow += flow;
        }

        public int minCostMaxFlow() {
            while (SPFA())
                adjust();
            return totalCost;
        }
    }

    static class Pair<U extends Comparable<U>, V extends Comparable<V>> implements Comparable<Pair<U, V>> {
        final U _1;
        final V _2;

        private Pair(U key, V val) {
            this._1 = key;
            this._2 = val;
        }

        public static <U extends Comparable<U>, V extends Comparable<V>> Pair<U, V> instanceOf(U _1, V _2) {
            return new Pair<U, V>(_1, _2);
        }

        @Override
        public String toString() {
            return _1 + " " + _2;
        }

        @Override
        public int hashCode() {
            int res = 17;
            res = res * 31 + _1.hashCode();
            res = res * 31 + _2.hashCode();
            return res;
        }

        @Override
        public int compareTo(Pair<U, V> that) {
            int res = this._1.compareTo(that._1);
            if (res < 0 || res > 0)
                return res;
            else
                return this._2.compareTo(that._2);
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (!(obj instanceof Pair))
                return false;
            Pair<?, ?> that = (Pair<?, ?>) obj;
            return _1.equals(that._1) && _2.equals(that._2);
        }
    }

    /** Class for buffered reading int and double values */
    static class Reader {
        static BufferedReader reader;
        static StringTokenizer tokenizer;

        /** call this method to initialize reader for InputStream */
        static void init(InputStream input) {
            reader = new BufferedReader(new InputStreamReader(input));
            tokenizer = new StringTokenizer("");
        }

        /** get next word */
        static String next() throws IOException {
            while (!tokenizer.hasMoreTokens()) {
                // TODO add check for eof if necessary
                tokenizer = new StringTokenizer(reader.readLine());
            }
            return tokenizer.nextToken();
        }

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

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

    static class ArrayUtil {
        static void swap(int[] a, int i, int j) {
            int tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
        }

        static void swap(long[] a, int i, int j) {
            long tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
        }

        static void swap(double[] a, int i, int j) {
            double tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
        }

        static void swap(char[] a, int i, int j) {
            char tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
        }

        static void swap(boolean[] a, int i, int j) {
            boolean tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
        }

        static void reverse(int[] a, int i, int j) {
            for (; i < j; i++, j--)
                swap(a, i, j);
        }

        static void reverse(long[] a, int i, int j) {
            for (; i < j; i++, j--)
                swap(a, i, j);
        }

        static void reverse(double[] a, int i, int j) {
            for (; i < j; i++, j--)
                swap(a, i, j);
        }

        static void reverse(char[] a, int i, int j) {
            for (; i < j; i++, j--)
                swap(a, i, j);
        }

        static void reverse(boolean[] a, int i, int j) {
            for (; i < j; i++, j--)
                swap(a, i, j);
        }

        static long sum(int[] a) {
            int sum = 0;
            for (int i : a)
                sum += i;
            return sum;
        }

        static long sum(long[] a) {
            long sum = 0;
            for (long i : a)
                sum += i;
            return sum;
        }

        static double sum(double[] a) {
            double sum = 0;
            for (double i : a)
                sum += i;
            return sum;
        }

        static int max(int[] a) {
            int max = Integer.MIN_VALUE;
            for (int i : a)
                if (i > max)
                    max = i;
            return max;
        }

        static int min(int[] a) {
            int min = Integer.MAX_VALUE;
            for (int i : a)
                if (i < min)
                    min = i;
            return min;
        }

        static long max(long[] a) {
            long max = Long.MIN_VALUE;
            for (long i : a)
                if (i > max)
                    max = i;
            return max;
        }

        static long min(long[] a) {
            long min = Long.MAX_VALUE;
            for (long i : a)
                if (i < min)
                    min = i;
            return min;
        }
    }
}