#include <bits/stdc++.h>

using namespace std;

string ltrim(const string &);
string rtrim(const string &);
vector<string> split(const string &);
// Initialize with std::iota(parent, parent+n+1, 0), std::fill(sz, sz+n+1, 1);

const int N = 1e6+10; // Upper bound for n
const int M = 1e9+7;

int parent[N];
int sz[N];
int sieve[N];
int twos[N];

// Uses path compression
int find(int x) {return parent[x] = (x == parent[x] ? x : find(parent[x]));}

bool disjoint(int x, int y) {return find(x) != find(y);}

void join(int x, int y) {
    if (!disjoint(x, y)) return;
    int newPar = find(x), newChild = find(y);
    sz[newPar] += sz[newChild];
    parent[newChild] = newPar;
}

int dsuSize(int x) {return sz[find(x)];}

// Complete the solve function below.
int solve(vector<int> a) {
    int n = a.size();
    std::iota(parent, parent+N, 0), std::fill(sz, sz+N, 1);
    for(int i = 0; i < n; ++i) {
        int cur = a[i];
        set<int> p;
        while(cur != 1) {
            p.insert(sieve[cur]);
            cur /= sieve[cur];
        }
        // cout << p.size() << endl;
        vector<int> vec(p.size());
        int idx = 0;
        for(int x : p) {
            // cout << x << ' ';
            vec[idx++] = x;
        }
        // cout << endl;
        // cout << vec.size() << endl;
        for(int j = 0; j < (int)vec.size()-1; ++j) {
            // cout << j << ' ' << vec.size() <<  endl;
            // cout << vec[j] << ' ';
            join(vec[j], vec[j+1]);
        }
    }
    set<int> s;
    int ones = 0;
    for(int i = 0; i < n; ++i) {
        if(a[i] == 1) ++ones;
        else s.insert(find(sieve[a[i]]));
    }
    return (twos[s.size()+ones]-2+M) % M;
}

void precomp() {
    std::iota(sieve, sieve+N, 0);
    for(int i = 2; i < N; ++i) {
        if(sieve[i] == i) {
            for(int j = i; j < N; j += i) {
                sieve[j] = i;
            }
        }
    }
    
    twos[0] = 1;
    for(int i = 1; i < N; ++i) {
        twos[i] = (twos[i-1]*2) % M;
    }
}

int main()
{
    ofstream fout(getenv("OUTPUT_PATH"));

    precomp();
    
    string t_temp;
    getline(cin, t_temp);

    int t = stoi(ltrim(rtrim(t_temp)));

    for (int t_itr = 0; t_itr < t; t_itr++) {
        string a_count_temp;
        getline(cin, a_count_temp);

        int a_count = stoi(ltrim(rtrim(a_count_temp)));

        string a_temp_temp;
        getline(cin, a_temp_temp);

        vector<string> a_temp = split(rtrim(a_temp_temp));

        vector<int> a(a_count);

        for (int i = 0; i < a_count; i++) {
            int a_item = stoi(a_temp[i]);

            a[i] = a_item;
        }

        int result = solve(a);

        fout << result << "\n";
    }

    fout.close();

    return 0;
}

string ltrim(const string &str) {
    string s(str);

    s.erase(
        s.begin(),
        find_if(s.begin(), s.end(), not1(ptr_fun<int, int>(isspace)))
    );

    return s;
}

string rtrim(const string &str) {
    string s(str);

    s.erase(
        find_if(s.rbegin(), s.rend(), not1(ptr_fun<int, int>(isspace))).base(),
        s.end()
    );

    return s;
}

vector<string> split(const string &str) {
    vector<string> tokens;

    string::size_type start = 0;
    string::size_type end = 0;

    while ((end = str.find(" ", start)) != string::npos) {
        tokens.push_back(str.substr(start, end - start));

        start = end + 1;
    }

    tokens.push_back(str.substr(start));

    return tokens;
}