#include <bits/stdc++.h>
using namespace std;
struct debugger {
  template <typename T>
  debugger& operator,(const T v) {
    cout << v << " ";
    return *this;
  }
} dbg;
const double pi = acos(-1.0);
const double eps = 1e-7;
template <class TT>
TT sqr(TT a) {
  return a * a;
}
template <class TT>
TT abs(TT a) {
  if (a < 0) return -a;
  return a;
}
const int S = 201;
int a[S];
const int pN = 30000;
bool ip[pN + 1];
void genPrime() {
  for (int i = 4; i <= pN; i += 2) ip[i] = true;
  for (int i = 3; i <= pN; i += 2)
    if (!ip[i]) {
      if (i * i <= pN) {
        for (int j = i * i; j <= pN; j += 2 * i) ip[j] = true;
      }
    }
}
class Flow {
 public:
  const static int N = 202;
  vector<int> g[N];
  int cap[N][N], par[N], flag[N], mat[N / 2][N];
  int source, sink;
  int flagN;
  Flow() {}
  Flow(int source, int sink) {
    this->source = source;
    this->sink = sink;
    flagN = 1;
    memset(mat, 0, sizeof mat);
    memset(cap, 0, sizeof cap);
  }
  bool isPath(int u) {
    flag[u] = flagN;
    for (int i = 0; i < ((int)g[u].size()); i++) {
      int v = g[u][i];
      if (flagN == flag[v]) continue;
      if (cap[u][v] > 0) {
        par[v] = u;
        if (v == sink) return true;
        if (isPath(v)) return true;
      }
    }
    return false;
  }
  int getSet(int u) {
    if (u && u <= m) return 1;
    if (u > m && u < sink) return 2;
    return 0;
  }
  void makeAug(int v) {
    if (v == 0) return;
    int u = par[v];
    if (1 == getSet(u) && 2 == getSet(v))
      mat[u][v] = 1;
    else if (1 == getSet(v) && 2 == getSet(u))
      mat[v][u] = 0;
    makeAug(u);
    cap[u][v]--;
    cap[v][u]++;
  }
  int maxFlow() {
    int sum = 0, flow = 1;
    while (isPath(source)) {
      flagN++;
      sum++;
      makeAug(sink);
    }
    return sum;
  }
  void addEdge(int u, int v, int weight) {
    g[u].push_back(v);
    g[v].push_back(u);
    cap[u][v] += weight;
  }
  int n, m;
  void buildGraph(int n);
  void match();
  bool dfs(int u, vector<int>& vec);
};
vector<int> o, e, po, pe;
void Flow::buildGraph(int n) {
  memset(cap, 0, sizeof cap);
  for (int i = 0; i < ((int)e.size()); i++)
    for (int j = 0; j < ((int)o.size()); j++)
      if (!ip[e[i] + o[j]]) addEdge(i + 1, m + j + 1, 1);
  for (int i = 0; i < m; i++) {
    addEdge(0, i + 1, 2);
    addEdge(m + i + 1, sink, 2);
  }
}
void Flow::match() {
  for (int i = 1; i <= n; i++) g[i].clear();
  for (int i = 1; i <= m; i++) {
    for (int j = m + 1; j < sink; j++)
      if (mat[i][j]) {
        g[i].push_back(j);
        g[j].push_back(i);
      }
  }
  vector<vector<int> > ans;
  flagN++;
  flagN++;
  for (int i = 1; i <= n; i++)
    if (flagN != flag[i]) {
      vector<int> v;
      dfs(i, v);
      ans.push_back(v);
    }
  e.insert(e.end(), (o).begin(), (o).end());
  pe.insert(pe.end(), (po).begin(), (po).end());
  printf("%d\n", ((int)ans.size()));
  for (int i = 0; i < ((int)ans.size()); i++) {
    printf("%d", ((int)ans[i].size()));
    for (int j = 0; j < ((int)ans[i].size()); j++)
      printf(" %d", pe[ans[i][j] - 1]);
    printf("\n");
  }
}
bool Flow::dfs(int u, vector<int>& vec) {
  flag[u] = flagN;
  vec.push_back(u);
  for (int i = 0; i < ((int)g[u].size()); i++) {
    int v = g[u][i];
    if (flagN == flag[v]) continue;
    dfs(v, vec);
  }
}
int main() {
  int n;
  genPrime();
  while (scanf("%d", &n) == 1 && n) {
    for (int i = 1; i <= n; i++) {
      scanf("%d", a + i);
      if (a[i] & 1) {
        o.push_back(a[i]);
        po.push_back(i);
      } else {
        e.push_back(a[i]);
        pe.push_back(i);
      }
    }
    if (((int)o.size()) != ((int)e.size())) {
      puts("Impossible");
      continue;
    }
    Flow* mx = new Flow(0, n + 1);
    mx->n = n;
    mx->m = n / 2;
    mx->buildGraph(n);
    int flow = mx->maxFlow();
    if (flow != n)
      puts("Impossible");
    else
      mx->match();
  }
  return 0;
}
