#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vi = vector<ll>;
using vl = vector<long long>;
using pii = pair<ll, ll>;
using vpii = vector<pair<ll, ll>>;
template <class T>
inline bool ckmin(T& a, T b) {
  return b < a ? a = b, 1 : 0;
}
template <class T>
inline bool ckmax(T& a, T b) {
  return b > a ? a = b, 1 : 0;
}
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const char nl = '\n';
const ll mxN = 2e5 + 10;
const ll MOD = 1e9 + 7;
const long long infLL = 1e18;
ll fact[mxN];
ll add(ll x, ll y) {
  x += y;
  while (x >= MOD) x -= MOD;
  while (x < 0) x += MOD;
  return x;
}
void ad(ll& x, ll y) { x = add(x, y); }
ll sub(ll x, ll y) {
  x -= y;
  while (x >= MOD) x -= MOD;
  while (x < 0) x += MOD;
  return x;
}
void sb(ll& x, ll y) { x = sub(x, y); }
ll mul(ll x, ll y) { return ((int64_t)x * (int64_t)y) % MOD; }
void ml(ll& x, ll y) { x = mul(x, y); }
ll binpow(ll x, ll y) {
  ll z = 1;
  while (y > 0) {
    if (y % 2 == 1) z = mul(z, x);
    x = mul(x, x);
    y /= 2;
  }
  return z;
}
ll inv(ll x) { return binpow(x, MOD - 2); }
ll divide(ll x, ll y) { return mul(x, inv(y)); }
void precalc() {
  fact[0] = 1;
  for (ll i = 1; i < mxN; i++) fact[i] = mul(i, fact[i - 1]);
}
ll choose(ll n, ll k) {
  if (k > n) return 0;
  return divide(fact[n], mul(fact[n - k], fact[k]));
}
template <class T, ll N>
struct Mat {
  array<array<T, N>, N> d{};
  Mat operator*(const Mat& m) const {
    Mat a;
    for (ll i = (0); i < (N); i++)
      for (ll j = (0); j < (N); j++)
        for (ll k = (0); k < (N); k++) {
          ad(a.d[i][j], mul(d[i][k], m.d[k][j]));
        }
    return a;
  };
  Mat operator+(const Mat& m) const {
    Mat res;
    for (ll i = (0); i < (N); i++) {
      for (ll j = (0); j < (N); j++) {
        res.d[i][j] = add(m.d[i][j], d[i][j]);
      }
    }
    return res;
  }
  bool operator==(const Mat& m) const {
    for (ll i = (0); i < (N); i++) {
      for (ll j = (0); j < (N); j++) {
        if (m.d[i][j] != d[i][j]) return 0;
      }
    }
    return 1;
  }
  vector<T> operator*(const vector<T>& vec) {
    vector<T> ret(N);
    for (ll i = (0); i < (N); i++)
      for (ll j = (0); j < (N); j++) ad(ret[i], mul(d[i][j], vec[j]));
    return ret;
  };
  Mat operator^(ll p) {
    Mat a, b(*this);
    for (ll i = (0); i < (N); i++) a.d[i][i] = 1;
    while (p) {
      if (p & 1) a = a * b;
      b = b * b;
      p /= 2;
    }
    return a;
  };
};
using node = vector<ll>;
struct lazy {
  ll size;
  vector<Mat<ll, 2>> operations;
  vector<node> vals;
  const node START_VAL = {1, 1};
  const node NEUTRAL_ELEMENT = {0, 0};
  Mat<ll, 2> M;
  Mat<ll, 2> query_op(Mat<ll, 2> a, Mat<ll, 2> b, ll len) {
    if (a == M) {
      return b;
    }
    if (b == M) {
      return a;
    }
    return b * a;
  }
  vi query_op(vi a, Mat<ll, 2> b, ll len) {
    if (b == M) {
      return a;
    }
    return b * a;
  }
  node calc_op(node a, node b) {
    node res(2);
    for (ll i = (0); i < (2); i++) res[i] = add(a[i], b[i]);
    return res;
  }
  template <class T>
  void apply_mod_op(T& a, Mat<ll, 2> b, ll c) {
    a = query_op(a, b, c);
  }
  void propogate(ll x, ll lx, ll rx) {
    if (rx - lx == 1) return;
    ll m = (lx + rx) / 2;
    apply_mod_op(operations[2 * x + 1], operations[x], 1);
    apply_mod_op(vals[2 * x + 1], operations[x], m - lx);
    apply_mod_op(operations[2 * x + 2], operations[x], 1);
    apply_mod_op(vals[2 * x + 2], operations[x], rx - m);
    operations[x].d[0][0] = 0;
    operations[x].d[0][1] = 0;
    operations[x].d[1][0] = 69;
    operations[x].d[1][1] = 69;
  }
  void build(ll x, ll lx, ll rx) {
    if (rx == lx + 1) {
      vals[x] = START_VAL;
      return;
    }
    ll m = (lx + rx) / 2;
    build(2 * x + 1, lx, m);
    build(2 * x + 2, m, rx);
    vals[x] = calc_op(vals[x * 2 + 1], vals[x * 2 + 2]);
  }
  void init(ll n) {
    size = 1;
    while (size < n) size *= 2;
    M.d[0][0] = 0;
    M.d[0][1] = 0;
    M.d[1][0] = 69;
    M.d[1][1] = 69;
    operations.assign(2 * size, M);
    vals.assign(2 * size, {1, 1});
    build(0, 0, size);
  }
  void update(ll l, ll r, Mat<ll, 2> v, ll x, ll lx, ll rx) {
    propogate(x, lx, rx);
    if (lx >= r || l >= rx) return;
    if (lx >= l && rx <= r) {
      apply_mod_op(operations[x], v, 1);
      apply_mod_op(vals[x], v, rx - lx);
      return;
    }
    ll m = (lx + rx) / 2;
    update(l, r, v, 2 * x + 1, lx, m);
    update(l, r, v, 2 * x + 2, m, rx);
    vals[x] = calc_op(vals[x * 2 + 1], vals[x * 2 + 2]);
  }
  void update(ll l, ll r, Mat<ll, 2> v) { update(l, r, v, 0, 0, size); }
  node query(ll l, ll r, ll x, ll lx, ll rx) {
    propogate(x, lx, rx);
    if (lx >= r || l >= rx) return NEUTRAL_ELEMENT;
    if (lx >= l && rx <= r) {
      return vals[x];
    }
    ll m = (lx + rx) / 2;
    node m1 = query(l, r, 2 * x + 1, lx, m);
    node m2 = query(l, r, 2 * x + 2, m, rx);
    return calc_op(m1, m2);
  }
  node query(ll l, ll r) { return query(l, r, 0, 0, size); }
} st;
ll n, m;
int32_t main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cin >> n >> m;
  Mat<ll, 2> Fib;
  Fib.d[0][0] = 0;
  Fib.d[0][1] = 1;
  Fib.d[1][0] = 1;
  Fib.d[1][1] = 1;
  st.init(n);
  for (ll i = (0); i < (n); i++) {
    ll x;
    cin >> x;
    if (x == 1) {
    } else {
      st.update(i, i + 1, Fib ^ (x - 1));
    }
  }
  while (m--) {
    ll type;
    ll l, r;
    cin >> type >> l >> r;
    l--;
    r--;
    if (type == 1) {
      ll amt;
      cin >> amt;
      st.update(l, r + 1, Fib ^ amt);
    } else {
      cout << st.query(l, r + 1)[0] << nl;
    }
  }
  return 0;
}
