//可以多加一个状态 有点像状压的思路:质因数状态
//可以预处理300内的质因数
//每次更新质因数状态就用按位或,相当于多了一些质因子
#include<bits/stdc++.h>
#define ll long long
#define lid (id<<1)
#define rid (id<<1|1)
using namespace std;
const ll mod=1e9+7, maxn=1e5+5;
long long n, q, x, y, z;
ll a[maxn], f[1000], inv[1000], pre[1000];
ll p[62]={2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89,97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293};
int read()
{
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9')
{
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
inline ll qpow(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
struct seg_tree{
ll l, r;
ll num, lazy;
ll pri, plazy;//质因数状态
seg_tree()
{
num=lazy=1;
pri=plazy=0;
}
}tr[maxn<<2];
inline void pushup(ll id)
{
tr[id].num=tr[lid].num*tr[rid].num%mod;
tr[id].pri=tr[lid].pri|tr[rid].pri;
}
inline void build(int id, int l, int r)
{
tr[id].l=l;
tr[id].r=r;
tr[id].lazy=1;
tr[id].num=1;
if(l==r)
{
tr[id].pri=pre[a[l]];
tr[id].num=a[l];
// cout<<tr[id].num<<endl;
return ;
}
int mid=(l+r)>>1;
build(lid, l, mid);
build(rid, mid+1, r);
pushup(id);
}
inline void pushdown(int id)
{
if(tr[id].lazy!=1&&tr[id].l!=tr[id].r)
{
tr[lid].lazy=tr[lid].lazy*tr[id].lazy%mod;
tr[rid].lazy=tr[rid].lazy*tr[id].lazy%mod;
tr[lid].num=tr[lid].num*qpow(tr[id].lazy,(tr[lid].r-tr[lid].l+1))%mod;
tr[rid].num=tr[rid].num*qpow(tr[id].lazy,(tr[rid].r-tr[rid].l+1))%mod;
tr[id].lazy=1;
}
if(tr[id].plazy&&tr[id].l!=tr[id].r)
{
tr[lid].plazy|=tr[id].plazy;
tr[rid].plazy|=tr[id].plazy;
tr[lid].pri|=tr[id].plazy;
tr[rid].pri|=tr[id].plazy;
tr[id].plazy=0;
}
}
inline void modify(ll id, ll l, ll r, ll val, ll x)
{
if(tr[id].l==l&&tr[id].r==r)
{
tr[id].lazy=tr[id].lazy*val%mod;
tr[id].num=tr[id].num*qpow(val,(tr[id].r-tr[id].l+1))%mod;
tr[id].pri|=x;
tr[id].plazy|=x;
return ;
}
pushdown(id);
ll mid=(tr[id].l+tr[id].r)>>1;
if(r<=mid)
{
modify(lid, l, r, val, x);
}
else if(l>mid)
{
modify(rid, l, r, val, x);
}
else
{
modify(lid, l, mid, val, x);
modify(rid, mid+1, r, val, x);
}
pushup(id);
}
inline seg_tree query(ll id,ll l, ll r)
{
if(tr[id].l==l&&tr[id].r==r)
{
return tr[id];
}
pushdown(id);
ll mid=(tr[id].l+tr[id].r)>>1;
if(r<=mid)
{
return query(lid, l, r);
}
if(l>mid)
{
return query(rid, l, r);
}
//这里还要处理一下,返回的是一个结构体
seg_tree tmp;
tmp.num=query(lid,l,mid).num*query(rid,mid+1,r).num%mod;
tmp.pri=query(lid,l,mid).pri|query(rid,mid+1,r).pri;
return tmp;
}
int readOpt()
{
char ch=getchar();
int ans;
while(ch<'A'||ch>'Z') ch=getchar();
if(ch=='T')
return 2;
else return 1;
}
int main()
{
// freopen("ex_array3.in","r",stdin);
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
inv[1]=1;
for(register int i=2;i<=300;i++)
{
inv[i]=mod-(mod/i)*inv[mod%i]%mod;
}
for(register int i=0;i<62;i++)
{
f[i]=inv[p[i]]*(p[i]-1)%mod;
}
n=read(), q=read();
for(register int i=1;i<=n;i++)
{
a[i]=read();
}
for(register int i=2; i<=300; i++)
for(register int j=0;j<62;j++)
{
if(i%p[j]==0) pre[i]|=(1ll)<<j;
}
build(1,1,n);
while(q--)
{
// string opt;
int opt, l, r, x;
//cin>>opt;
opt=readOpt();
if(opt==1)
{
l=read(), r=read(), x=read();
modify(1, l, r, x, pre[x]);
}
else
{
l=read(), r=read();
seg_tree ans=query(1, l, r);
ll num=ans.num;
for(register int i=0;i<62;i++)
{
if(ans.pri>>i&1)
{
num=num*f[i]%mod;
}
}
printf("%lld\n",num);
}
}
return 0;
}