package main
import (
"bufio"
"fmt"
"os"
)
const MOD = 1000000007
const MAXA = 200005
var spf [MAXA]int32
var inv [MAXA]int32
type Node struct {
ls, rs int32
val int32
}
var tree []Node
type upd struct {
pos int32
val int32
}
func updateTreeBatch(node int32, l, r int32, upds []upd) int32 {
newNode := int32(len(tree))
tree = append(tree, tree[node])
mul := int64(1)
for i := 0; i < len(upds); i++ {
mul = (mul * int64(upds[i].val)) % MOD
}
tree[newNode].val = int32((int64(tree[newNode].val) * mul) % MOD)
if l == r {
return newNode
}
mid := (l + r) >> 1
split := 0
for split < len(upds) && upds[split].pos <= mid {
split++
}
if split > 0 {
tree[newNode].ls = updateTreeBatch(tree[node].ls, l, mid, upds[:split])
}
if split < len(upds) {
tree[newNode].rs = updateTreeBatch(tree[node].rs, mid+1, r, upds[split:])
}
return newNode
}
func queryTree(node int32, l, r int32, ql, qr int32) int32 {
if node == 0 {
return 1
}
if ql <= l && r <= qr {
return tree[node].val
}
mid := (l + r) >> 1
res := int32(1)
if ql <= mid {
res = int32((int64(res) * int64(queryTree(tree[node].ls, l, mid, ql, qr))) % MOD)
}
if qr > mid {
res = int32((int64(res) * int64(queryTree(tree[node].rs, mid+1, r, ql, qr))) % MOD)
}
return res
}
func main() {
for i := int32(2); i < MAXA; i++ {
if spf[i] == 0 {
for j := i; j < MAXA; j += i {
if spf[j] == 0 {
spf[j] = i
}
}
}
}
inv[1] = 1
for i := int32(2); i < MAXA; i++ {
inv[i] = int32((int64(MOD) - int64(MOD/i)) * int64(inv[MOD%i]) % MOD)
}
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
buf := make([]byte, 1024*1024)
scanner.Buffer(buf, 1024*1024*10)
scanInt := func() int32 {
scanner.Scan()
b := scanner.Bytes()
res := int32(0)
for _, v := range b {
res = res*10 + int32(v-'0')
}
return res
}
if !scanner.Scan() {
return
}
bBytes := scanner.Bytes()
n := int32(0)
for _, v := range bBytes {
n = n*10 + int32(v-'0')
}
a := make([]int32, n+1)
for i := int32(1); i <= n; i++ {
a[i] = scanInt()
}
tree = make([]Node, 1, 5000000)
tree[0] = Node{0, 0, 1}
roots := make([]int32, n+1)
roots[0] = 0
prev := make([]int32, MAXA)
for i := int32(1); i <= n; i++ {
x := a[i]
var upds []upd
for x > 1 {
p := spf[x]
pk := int32(1)
for x%p == 0 {
x /= p
pk *= p
upds = append(upds, upd{pos: i, val: p})
if prev[pk] != 0 {
upds = append(upds, upd{pos: prev[pk], val: inv[p]})
}
prev[pk] = i
}
}
combined := make([]upd, 0, len(upds))
for j := 0; j < len(upds); j++ {
u := upds[j]
found := false
for k := 0; k < len(combined); k++ {
if combined[k].pos == u.pos {
combined[k].val = int32((int64(combined[k].val) * int64(u.val)) % MOD)
found = true
break
}
}
if !found {
combined = append(combined, u)
}
}
for j := 1; j < len(combined); j++ {
k := j
for k > 0 && combined[k-1].pos > combined[k].pos {
combined[k-1], combined[k] = combined[k], combined[k-1]
k--
}
}
currRoot := roots[i-1]
if len(combined) > 0 {
currRoot = updateTreeBatch(currRoot, 1, n, combined)
}
roots[i] = currRoot
}
q := scanInt()
last := int32(0)
out := bufio.NewWriter(os.Stdout)
for i := int32(0); i < q; i++ {
x := scanInt()
y := scanInt()
l := int32((int64(last)+int64(x))%int64(n)) + 1
r := int32((int64(last)+int64(y))%int64(n)) + 1
if l > r {
l, r = r, l
}
ans := queryTree(roots[r], 1, n, l, r)
fmt.Fprintln(out, ans)
last = ans
}
out.Flush()
}