#include <iostream>
#include <vector>
#include <functional>
#define FOR(i, a, b) for(int i=(a);i<int(b);++i)
#define REP(i, n) for(int i=0;i<int(n);++i)
using ll = long long;
constexpr ll INFLL = 1LL << 60;
constexpr int MOD = 1000000007;
struct LINE { ll a, b; };
struct SEG { ll S0, S1; LINE Ul, Ur; };
struct LAZ { ll l, r; LINE L; };
struct LazySegmentTree {
std::vector<SEG> seg;
std::vector<LAZ> laz;
std::vector<bool> isUpdated;
int ARY_SIZE, SZ;
SEG eSeg;
LAZ eLaz;
SEG mergeSeg(SEG& l, SEG& r) {
return SEG{l.S0 + r.S0, l.S1 + r.S1, l.Ul, r.Ur};
}
LAZ& mergeLaz(LAZ& l, LAZ r) {
return l = r;
}
SEG& applyLaz(SEG& s, LAZ& l) {
auto L(l.L);
L.a %= MOD, L.b %= MOD;
ll S0 = ((l.r - 1)*l.r / 2 % MOD * L.a % MOD + L.b * (l.r - 1) % MOD
- ((l.l - 1) * l.l / 2 % MOD * L.a % MOD + L.b * (l.l - 1) % MOD)) % MOD;
ll S1 = ((l.r - 1) * l.r * (2 * l.r - 1) / 6 % MOD * L.a % MOD + (l.r - 1) * l.r / 2 % MOD * L.b
- ((l.l - 1) * l.l * (2 * l.l - 1) / 6 % MOD * L.a % MOD + (l.l - 1) * l.l / 2 % MOD * L.b)) % MOD;
return s = SEG{S0, S1, l.L, l.L};
}
inline void push(int k, int l, int r) {
if (k < isUpdated.size() && !isUpdated[k]) {
applyLaz(seg[k], laz[k]);
if (r - l > 1) {
LAZ chi = laz[k];
chi.r = (chi.l + chi.r) >> 1;
laz[k + k + 1] = chi; isUpdated[k + k + 1] = false;
chi.l = chi.r, chi.r = laz[k].r;
laz[k + k + 2] = chi; isUpdated[k + k + 2] = false;
}
isUpdated[k] = true;
laz[k] = eLaz;
}
}
LazySegmentTree(int n) :
eSeg(SEG{0, 0, LINE{0, -INFLL}, LINE{0, -INFLL}}),
eLaz(LAZ{0, 0, LINE{0, -INFLL}})
{
ARY_SIZE = 1;
while (ARY_SIZE < n) ARY_SIZE <<= 1;
SZ = (ARY_SIZE << 1) - 1;
seg.resize(SZ, eSeg);
laz.resize(SZ, eLaz);
isUpdated.resize(SZ, true);
std::function<void(int, int, int)> initLaz = [&](int k, int l, int r) {
seg[k] = eSeg;
laz[k] = LAZ{l, r, LINE{0, -INFLL}};
isUpdated[k] = false;
if (r - l > 1) {
initLaz((k << 1) + 1, l, (l + r) >> 1);
initLaz((k << 1) + 2, (l + r) >> 1, r);
}
};
initLaz(0, 0, ARY_SIZE);
}
inline SEG query(int a, int b, int k, int l, int r) {
push(k, l, r);
if (r <= a || b <= l) return eSeg;
if (a <= l && r <= b) return seg[k];
SEG vl = query(a, b, (k << 1) + 1, l, (l + r) >> 1);
SEG vr = query(a, b, (k << 1) + 2, (l + r) >> 1, r);
return mergeSeg(vl, vr);
}
inline SEG query(int l, int r) {
return query(l, r, 0, 0, ARY_SIZE);
}
inline void addLine(int a, int b, LINE v, int k, int l, int r) {
push(k, l, r);
if (r <= a || b <= l) return;
if (a <= l && r <= b) {
auto type = [&](LINE& L, int x) {
if (L.a * x + L.b > v.a * x + v.b) {
if (L.a < v.a) return 1;
else return 3;
}
else return 2;
};
if ((k << 1) + 1 < SZ) {
push((k << 1) + 1, l, (l + r) >> 1);
push((k << 1) + 2, (l + r) >> 1, r);
seg[k] = mergeSeg(seg[(k << 1) + 1], seg[(k << 1) + 2]);
}
int l_type = type(seg[k].Ul, l);
int r_type = type(seg[k].Ur, r - 1);
if (l_type != r_type) {
addLine(a, b, v, (k << 1) + 1, l, (l + r) >> 1);
addLine(a, b, v, (k << 1) + 2, (l + r) >> 1, r);
}
else if (l_type == 2) {
mergeLaz(laz[k], LAZ{l, r, v});
isUpdated[k] = false;
push(k, l, r);
}
}
push(k, l, r);
if ((k << 1) + 1 < SZ) {
push((k << 1) + 1, l, (l + r) >> 1);
push((k << 1) + 2, (l + r) >> 1, r);
seg[k] = mergeSeg(seg[(k << 1) + 1], seg[(k << 1) + 2]);
}
}
inline void addLine(LINE v) {
addLine(0, ARY_SIZE, v, 0, 0, ARY_SIZE);
}
};
ll gcd(ll a, ll b) {
return b ? gcd(b, a%b) : a;
}
signed main() {
int n;
std::cin >> n;
std::vector<ll> a(n);
REP(i, n) std::cin >> a[i];
auto calcMin = [&] {
auto calcSub = [&](int _l, int _r) {
ll res = 0;
struct Triple { ll x, l, r; };
std::vector<Triple> G;
FOR(i, _l, _r) {
for (auto& tri : G) {
tri.x = gcd(tri.x, a[i]);
res += (i - tri.l + 1) * (i - tri.l + 2) / 2 % MOD * tri.x % MOD;
res -= (i - tri.r + 1) * (i - tri.r + 2) / 2 % MOD * tri.x % MOD;
res %= MOD;
}
res += a[i];
G.emplace_back(Triple{a[i], i, i + 1});
int l = 0;
FOR(r, 1, G.size()) {
if (G[l].x == G[r].x) G[l].r = G[r].r;
else G[++l] = G[r];
}
G.resize(l + 1);
}
return res;
};
ll res = 0;
int l = 0;
REP(r, n) {
if (a[r] == 0) {
res += calcSub(l, r);
l = r + 1;
}
}
res += calcSub(l, n);
return res;
};
auto calcMax = [&] {
ll res = 0;
LazySegmentTree st(n);
REP(i, n) {
st.addLine(LINE{-a[i], (i + 1) * a[i]});
SEG seg = st.query(0, i + 1);
(res += seg.S0 * (i + 1) % MOD - seg.S1) %= MOD;
}
return res;
};
ll max = calcMax();
ll min = calcMin();
ll ans = (max - min) % MOD;
if (ans < 0) ans += MOD;
std::cout << ans << std::endl;
return 0;
}