#include <bits/stdc++.h>
using namespace std;
namespace ProconLib {
template <typename update_t, typename value_t>
class LazySegmentTree {
 public:
  using UpdateMerger = std::function<update_t(update_t, update_t)>;
  using ValueMerger = std::function<value_t(value_t, value_t)>;
  using Evaluator = std::function<value_t(value_t, update_t, int, int)>;

 private:
  int N;
  const value_t E;
  UpdateMerger mergeU;
  ValueMerger mergeV;
  Evaluator eval;
  std::vector<value_t> dat;
  std::vector<update_t> lazy;
  std::vector<int> flag;
  void propagate(int node, int l, int r);
  void applyLazy(int node, update_t x);
  void updateImpl(int l, int r, int k, int lb, int ub, update_t f);
  value_t queryImpl(int l, int r, int k, int lb, int ub);
  value_t getValue(int node, int l, int r) {
    return flag[node] ? eval(dat[node], lazy[node], l, r) : dat[node];
  }

 public:
  LazySegmentTree(int N, Evaluator eval, UpdateMerger mergeU,
                  ValueMerger mergeV, value_t E);
  void update(int l, int r, update_t f);
  value_t query(int a, int b);
};
template <typename update_t, typename value_t>
LazySegmentTree<update_t, value_t>::LazySegmentTree(int N, Evaluator eval,
                                                    UpdateMerger mergeU,
                                                    ValueMerger mergeV,
                                                    value_t E)
    : mergeU(mergeU), mergeV(mergeV), eval(eval), E(E) {
  this->N = 1;
  while (this->N < N) this->N *= 2;
  dat.assign(this->N * 2 - 1, E);
  lazy.assign(this->N * 2 - 1, update_t());
  flag.assign(this->N * 2 - 1, false);
}
template <typename update_t, typename value_t>
void LazySegmentTree<update_t, value_t>::propagate(int node, int l, int r) {
  if (flag[node]) {
    flag[node] = false;
    applyLazy(node * 2 + 1, lazy[node]);
    applyLazy(node * 2 + 2, lazy[node]);
    int mid = (l + r) / 2;
    dat[node] =
        mergeV(getValue(node * 2 + 1, l, mid), getValue(node * 2 + 2, mid, r));
  }
}
template <typename update_t, typename value_t>
void LazySegmentTree<update_t, value_t>::applyLazy(int node, update_t x) {
  if (flag[node]) {
    lazy[node] = mergeU(lazy[node], x);
  } else {
    flag[node] = true;
    lazy[node] = x;
  }
}
template <typename update_t, typename value_t>
void LazySegmentTree<update_t, value_t>::updateImpl(int l, int r, int k, int lb,
                                                    int ub, update_t x) {
  if (r <= lb || ub <= l) return;
  if (l <= lb && ub <= r) {
    applyLazy(k, x);
    return;
  }
  propagate(k, lb, ub);
  int mid = (lb + ub) / 2;
  updateImpl(l, r, k * 2 + 1, lb, mid, x);
  updateImpl(l, r, k * 2 + 2, mid, ub, x);
  dat[k] = mergeV(getValue(k * 2 + 1, lb, mid), getValue(k * 2 + 2, mid, ub));
}
template <typename update_t, typename value_t>
value_t LazySegmentTree<update_t, value_t>::queryImpl(int l, int r, int k,
                                                      int lb, int ub) {
  if (r <= lb || ub <= l) return E;
  if (l <= lb && ub <= r) {
    return getValue(k, lb, ub);
  }
  propagate(k, lb, ub);
  int mid = (lb + ub) / 2;
  value_t lhs = queryImpl(l, r, k * 2 + 1, lb, mid);
  value_t rhs = queryImpl(l, r, k * 2 + 2, mid, ub);
  return mergeV(lhs, rhs);
}
template <typename update_t, typename value_t>
void LazySegmentTree<update_t, value_t>::update(int l, int r, update_t x) {
  updateImpl(l, r, 0, 0, N, x);
}
template <typename update_t, typename value_t>
value_t LazySegmentTree<update_t, value_t>::query(int l, int r) {
  return queryImpl(l, r, 0, 0, N);
}
}  // namespace ProconLib
using namespace ProconLib;
using ll = long long;
const int SIZE = 300;
const int PSIZE = 64;
using Flags = bitset<PSIZE>;
const ll MOD = 1e9 + 7;
ll powm(ll x, ll k) {
  ll res = 1;
  while (k) {
    if (k & 1) res = res * x % MOD;
    k >>= 1;
    x = x * x % MOD;
  }
  return res;
}
ll mulEval(ll a, ll x, int l, int r) { return a * powm(x, r - l) % MOD; }
ll mul(ll a, ll b) { return a * b % MOD; }
Flags fmerge(Flags lhs, Flags rhs) { return lhs | rhs; }
Flags fmergeEval(Flags lhs, Flags rhs, int l, int r) { return lhs | rhs; }
ll modInv(ll x) { return powm(x, MOD - 2); }
int main() {
  vector<int> primes;
  for (int i = 2; i <= SIZE; i++) {
    bool isPrime = true;
    for (int j = 2; j < i; j++) {
      if (i % j == 0) {
        isPrime = false;
        break;
      }
    }
    if (isPrime) primes.push_back(i);
  }
  int n, q;
  cin >> n >> q;
  vector<ll> a(n);
  for (int i = 0; i < n; i++) cin >> a[i];
  LazySegmentTree<ll, ll> mulSeg(n, mulEval, mul, mul, 1);
  for (int i = 0; i < n; i++) mulSeg.update(i, i + 1, a[i]);
  LazySegmentTree<Flags, Flags> pSeg(n, fmergeEval, fmerge, fmerge, Flags());
  vector<Flags> pa(n);
  for (int i = 0; i < n; i++)
    for (int j = 0; j < primes.size(); j++) {
      if (a[i] % primes[j] == 0) pa[i][j] = true;
    }
  for (int i = 0; i < n; i++) pSeg.update(i, i + 1, pa[i]);
  vector<ll> primeInv(primes.size());
  transform(primes.begin(), primes.end(), primeInv.begin(), modInv);
  while (q--) {
    string query;
    cin >> query;
    if (query == "MULTIPLY") {
      int l, r, x;
      cin >> l >> r >> x;
      l--;
      mulSeg.update(l, r, x);
      Flags app;
      for (int j = 0; j < primes.size(); j++) {
        if (x % primes[j] == 0) app[j] = true;
      }
      pSeg.update(l, r, app);
    } else {
      int l, r;
      cin >> l >> r;
      l--;
      Flags flags = pSeg.query(l, r);
      ll res = mulSeg.query(l, r);
      for (int i = 0; i < primes.size(); i++)
        if (flags[i]) res = res * (primes[i] - 1) % MOD * primeInv[i] % MOD;
      cout << res << endl;
    }
  }
  return 0;
}
