#include <vector>
#include <iostream>
const int N = 1e5 + 10;
const int MOD = 1e9 + 7;
typedef long long lint;
template<typename T>
struct Matrix {
size_t n, m;
std::vector<std::vector<T>> a;
Matrix(size_t _n = 0, size_t _m = 0) : n(_n), m(_m) {
a.resize(_n);
for (size_t i = 0; i < _n; ++i)
a[i].resize(_m);
}
Matrix(const std::vector<std::vector<T>> &_a) : n(_a.size()), m(_a[0].size()), a(_a) {}
void build() {
if (n != m) throw "This matrix can't be a I";
for (size_t i = 0; i < n; ++i) a[i][i] = 1;
}
void clear() { for (auto &x : a) for (auto &y : x) y = 0; }
bool empty() const {
for (size_t i = 0; i < n; ++i)
for (size_t j = 0; j < m; ++j) {
if ((i == j && a[i][j] != 1) || (i != j && a[i][j != 0]))
return false;
}
return true;
}
Matrix<T> operator=(const Matrix<T> &A) {
a = A.a, n = A.a.size(), m = A.a[0].size();
return *this;
}
Matrix<T> operator+(const Matrix<T> &A) const {
if (n != A.n || m != A.m) throw "The Matrixes can't plus.";
Matrix<T> res(n, m);
for (size_t i = 0; i < n; ++i)
for (size_t j = 0; j < m; ++j)
res.a[i][j] = (a[i][j] + A.a[i][j]) % MOD;
return res;
}
void operator+=(const Matrix<T> &A) {
*this = *this + A;
}
Matrix<T> operator*(const Matrix<T> &A) const {
if (m != A.n) throw "The Matrixes can't mul.";
Matrix<T> res(n, A.m);
for (size_t i = 0; i < n; ++i)
for (size_t j = 0; j < A.m; ++j)
for (size_t k = 0; k < m; ++k)
(res.a[i][j] += a[i][k] * A.a[k][j]) %= MOD;
return res;
}
void operator*=(const Matrix<T> &A) {
*this = *this * A;
}
friend std::istream &operator>>(std::istream &is, Matrix<T> &A) {
for (size_t i = 0; i < A.n; ++i)
for (size_t j = 0; j < A.m; ++j)
is >> A.a[i][j];
return is;
}
friend std::ostream &operator<<(std::ostream &os, const Matrix<T> &A) {
for (size_t i = 0; i < A.n; ++i) {
for (size_t j = 0; j < A.m; ++j)
os << A.a[i][j] << ' ';
os << '\n';
}
return os;
}
Matrix<T> qpow(size_t b) const {
if (n != m) throw "This matrix can't qpow.";
Matrix<T> ans(n, m), P = *this;
ans.build();
for (; b; b >>= 1) {
if (b & 1) ans *= P;
P *= P;
}
return ans;
}
};
template <typename T>
struct Pool {
std::vector<T *> buf;
T *create() {
buf.push_back(new T);
return buf.back();
}
void dispose() {
for (size_t i = 0; i < buf.size(); ++i) delete buf[i];
buf.clear();
}
};
struct TreeNode {
int l, r;
Matrix<lint> w, lzy;
TreeNode *lson, *rson;
};
int n, m, a[N];
Pool<TreeNode> p;
const Matrix<lint> A(std::vector<std::vector<lint>>({{1}, {1}}));
const Matrix<lint> P(std::vector<std::vector<lint>>({{0, 1}, {1, 1}}));
bool inRange(TreeNode *u, int L, int R) { return u->l >= L && u->r <= R; }
bool outRange(TreeNode *u, int L, int R) { return u->l > R || u->r < L; }
void maketag(TreeNode *u, const Matrix<lint> &x) { u->w *= x, u->lzy *= x; }
void pushup(TreeNode *u) { u->w = u->lson->w + u->rson->w; }
void pushdown(TreeNode *u) {
if (u->lzy.empty()) return ;
maketag(u->lson, u->lzy);
maketag(u->rson, u->lzy);
u->lzy.build();
}
TreeNode *build(int l, int r) {
TreeNode *u = p.create();
u->l = l, u->r = r;
u->lzy = Matrix<lint>(2, 2);
u->lzy.build();
if (l == r) {
if (a[l] <= 2) u->w = A;
else u->w = P.qpow(a[l] - 2) * A;
u->lson = u->rson = nullptr;
return u;
}
int mid = l + r >> 1;
u->lson = build(l, mid);
u->rson = build(mid + 1, r);
pushup(u);
return u;
}
Matrix<lint> query(TreeNode *u, int L, int R) {
if (outRange(u, L, R)) return Matrix<lint>(2, 2);
if (inRange(u, L, R)) return u->w;
pushdown(u);
return query(u->lson, L, R) + query(u->rson, L, R);
}
void update(TreeNode *u, int L, int R, lint x) {
if (outRange(u, L, R)) return ;
if (inRange(u, L, R)) { maketag(u, x); return ; }
pushdown(u);
update(u->lson, L, R, x);
update(u->rson, L, R, x);
pushup(u);
}
int main() {
std::cin.tie(0)->sync_with_stdio(0);
std::cin >> n >> m;
for (int i = 1; i <= n; ++i) std::cin >> a[i];
TreeNode *root = build(1, n);
for (int op, l, r, x; m; --m) {
std::cin >> op >> l >> r;
if (op == 1) std::cin >> x, update(root, l, r, x);
if (op != 1) std::cout << query(root, l, r).a[1][0] << '\n';
}
std::cout.flush();
return 0;
}