#include <bits/stdc++.h>
#pragma GCC target("avx2")
#pragma GCC optimization("O2")
#pragma GCC optimization("unroll-loops")
using namespace std;
struct matrix {
  int n, m;
  long long a[2][2];
  matrix(int n, int m, bool identity = false) {
    this->n = n;
    this->m = m;
    memset(a, 0, sizeof a);
    if (identity) {
      for (int i = 0; i < n; i++) a[i][i] = 1;
    }
  }
  matrix() {}
  matrix operator+(matrix &b) {
    matrix c(n, m);
    for (int i = 0; i < n; i++)
      for (int j = 0; j < m; j++) {
        c.a[i][j] = a[i][j] + b.a[i][j];
        if (c.a[i][j] > 1000000007) c.a[i][j] -= 1000000007;
      }
    return c;
  }
  matrix operator*(matrix &b) {
    matrix c(n, b.m);
    for (int i = 0; i < c.n; i++)
      for (int j = 0; j < c.m; j++) {
        for (int k = 0; k < m; k++) {
          c.a[i][j] += (a[i][k] * b.a[k][j]) % 1000000007;
          if (c.a[i][j] > 1000000007) c.a[i][j] -= 1000000007;
        }
      }
    return c;
  }
  void repr() {
    cout << n << ' ' << m << '\n';
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) cout << a[i][j] << ' ';
      cout << '\n';
    }
  }
};
struct segnod {
  matrix val, p;
};
matrix put(matrix &baza, long long exp) {
  if (exp == 0) return matrix(2, 2, true);
  if (exp == 1) return baza;
  matrix ans = put(baza, exp / 2);
  ans = ans * ans;
  if (exp % 2)
    return ans * baza;
  else
    return ans;
}
int n, q, i, t, l, r;
long long x;
vector<segnod> seg;
void init(int st, int dr, int poz) {
  seg[poz].p = matrix(2, 2, true);
  if (st == dr) {
    seg[poz].val = matrix(1, 2);
    seg[poz].val.a[0][1] = 1;
    return;
  }
  int mij = (st + dr) / 2;
  init(st, mij, 2 * poz);
  init(mij + 1, dr, 2 * poz + 1);
  seg[poz].val = seg[2 * poz].val + seg[2 * poz + 1].val;
}
void upd(matrix &val, int stt, int drt, int st, int dr, int poz) {
  if (stt == st && drt == dr) {
    seg[poz].p = seg[poz].p * val;
    seg[poz].val = seg[poz].val * val;
    return;
  }
  int mij = (st + dr) / 2;
  if (drt <= mij)
    upd(val, stt, drt, st, mij, 2 * poz);
  else {
    if (stt > mij)
      upd(val, stt, drt, mij + 1, dr, 2 * poz + 1);
    else {
      upd(val, stt, mij, st, mij, 2 * poz);
      upd(val, mij + 1, drt, mij + 1, dr, 2 * poz + 1);
    }
  }
  seg[poz].val = (seg[2 * poz].val + seg[2 * poz + 1].val) * seg[poz].p;
}
matrix query(int stt, int drt, int st, int dr, int poz,
             matrix in = matrix(2, 2, true)) {
  if (stt == st && drt == dr) {
    return seg[poz].val * in;
  }
  in = in * seg[poz].p;
  int mij = (st + dr) / 2;
  if (drt <= mij) return query(stt, drt, st, mij, 2 * poz, in);
  if (stt > mij) return query(stt, drt, mij + 1, dr, 2 * poz + 1, in);
  matrix ans = query(mij + 1, drt, mij + 1, dr, 2 * poz + 1, in);
  return query(stt, mij, st, mij, 2 * poz, in) + ans;
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  matrix s(1, 2);
  s.a[0][1] = 1;
  matrix fib(2, 2);
  fib.a[0][1] = 1;
  fib.a[1][0] = 1;
  fib.a[1][1] = 1;
  cin >> n >> q;
  seg.resize(4 * n + 4);
  init(1, n, 1);
  for (i = 1; i <= n; i++) {
    cin >> x;
    matrix p = put(fib, x);
    upd(p, i, i, 1, n, 1);
  }
  while (q) {
    q--;
    cin >> t >> l >> r;
    if (t == 1) {
      cin >> x;
      matrix p = put(fib, x);
      upd(p, l, r, 1, n, 1);
    } else {
      cout << query(l, r, 1, n, 1).a[0][0] << '\n';
    }
  }
  return 0;
}
