#include <bits/stdc++.h>
using namespace std;
static const int MOD = 998244353;
// Sieve up to 99999
vector<bool> sievePrimes(int N) {
vector<bool> isPrime(N + 1, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * 1LL * i <= N; ++i) if (isPrime[i]) {
for (int j = i * i; j <= N; j += i) isPrime[j] = false;
}
return isPrime;
}
// Convert integer to zero-padded string of length n
string toZ(int x, int n) {
string s(n, '0');
for (int i = n - 1; i >= 0; --i) {
s[i] = char('0' + (x % 10));
x /= 10;
}
return s;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Precompute prime masks and candidate strings
const int LIM = 99999;
auto isPrime = sievePrimes(LIM);
// cand[n][d] -> vector of strings (length n) that are primes and start with digit d
array<array<vector<string>, 10>, 6> cand; // index n in [0..5], we’ll use 1..5
for (int n = 1; n <= 5; ++n) {
int up = 1;
for (int i = 0; i < n; ++i) up *= 10;
for (int x = 0; x < up; ++x) {
if (!isPrime[x]) continue;
string s = toZ(x, n);
cand[n][s[0]-'0'].push_back(s);
}
}
int t;
if (!(cin >> t)) return 0;
while (t--) {
string p; // p is guaranteed prime and without leading zero
cin >> p;
int n = (int)p.size();
// rows[1..n], 1-indexed for clarity; row 1 fixed to p
vector<string> rows(n + 1);
rows[1] = p;
// DFS with pruning
function<long long(int)> dfs = [&](int k) -> long long {
if (k > n) return 1; // all rows chosen
if (k == 1) return dfs(2); // row 1 already fixed
int lead = p[k-1] - '0'; // column 1 equals digit p_k due to symmetry
long long ways = 0;
for (const string& s : cand[n][lead]) {
// s must match previously fixed symmetric constraints:
// for all j < k: s[j-1] == rows[j][k-1]
bool ok = true;
for (int j = 1; j < k; ++j) {
if (s[j-1] != rows[j][k-1]) { ok = false; break; }
}
if (!ok) continue;
rows[k] = s;
ways += dfs(k + 1);
if (ways >= MOD) ways -= MOD;
}
return ways % MOD;
};
cout << dfs(1) % MOD << '\n';
}
return 0;
}