#include <bits/stdc++.h>
using namespace std;
bool deb_mode = 0;
class debugger {
  vector<string> vars;

 public:
  template <typename T>
  debugger &operator,(const T v) {
    stringstream ss;
    ss << v, vars.push_back(ss.str());
    return *this;
  }
  void printall() {
    int j = 0, l = vars.size();
    for (int i = 0; i < (l - 1); i++) {
      if (i) cout << ", ";
      for (; j < vars[l - 1].size(); j++) {
        if (vars[l - 1][j] == ',') {
          j++;
          break;
        }
        cout << vars[l - 1][j];
      }
      cout << " = " << vars[i];
    }
    vars.clear();
  }
} Dbug;
template <typename T1, typename T2>
inline ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
  return os << "(" << p.first << "," << p.second << ")";
}
template <typename T>
inline ostream &operator<<(ostream &os, const vector<T> &v) {
  bool first = true;
  os << "{";
  for (unsigned int i = 0; i < v.size(); i++) {
    if (!first) os << ",";
    os << v[i];
    first = false;
  }
  return os << "}";
}
template <typename T>
inline ostream &operator<<(ostream &os, const set<T> &v) {
  bool first = true;
  os << "{";
  for (typename set<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) {
    if (!first) os << ",";
    os << *ii;
    first = false;
  }
  return os << "}";
}
template <typename T1, typename T2>
inline ostream &operator<<(ostream &os, const map<T1, T2> &v) {
  bool first = true;
  os << "{";
  for (typename map<T1, T2>::const_iterator ii = v.begin(); ii != v.end();
       ++ii) {
    if (!first) os << ",";
    os << *ii;
    first = false;
  }
  return os << "}";
}
template <typename T>
void getarray(T a[], int b, int e) {
  for (int i = b; i < e + b; i++) cin >> a[i];
}
template <typename T>
void printarray(T a[], int b, int e) {
  for (int i = b; i < e - 1 + b; i++) cout << a[i] << " ";
  if (e - 1 + b >= 0) cout << a[e - 1 + b] << '\n';
}
template <typename T>
void printV(vector<T> v) {
  int sz = v.size();
  if (sz) cout << v[0];
  for (int i = 1; i < sz; i++) cout << " " << v[i];
  printf("\n");
}
template <typename T>
T gcd(T a, T b) {
  if (b == 0) return a;
  return gcd(b, a % b);
}
template <typename T>
T BigMod(T b, T p, T m) {
  if (p == 0) return 1;
  if (p % 2 == 0) {
    T s = BigMod(b, p / 2, m);
    return ((s % m) * (s % m)) % m;
  }
  return ((b % m) * (BigMod(b, p - 1, m) % m)) % m;
}
template <typename T>
T ModInv(T b, T m) {
  return BigMod(b, m - 2, m);
}
pair<long long int, pair<long long int, long long int> > ext_gcd(
    long long int a, long long int b) {
  if (b == 0) return make_pair(a, make_pair(1LL, 0LL));
  pair<long long int, pair<long long int, long long int> > t =
      ext_gcd(b, a % b);
  return make_pair(
      t.first,
      make_pair(t.second.second, t.second.first - a / b * t.second.second));
}
long long int ModInvNonPrimeM(long long int N, long long int M) {
  pair<long long int, pair<long long int, long long int> > r = ext_gcd(N, M);
  r.second.first %= M;
  if (r.second.first < 0) r.second.first += M;
  return r.second.first;
}
template <class T>
inline void read(T &x) {
  bool Minus = 0;
  char c;
  for (c = getchar(); c <= 32; c = getchar())
    ;
  if (c == '-') Minus = 1, c = getchar();
  for (x = 0; c > 32; c = getchar()) x = x * 10 + c - '0';
  if (Minus) x = -x;
}
char getc() {
  char c;
  for (c = getchar(); c <= 32; c = getchar())
    ;
  return c;
}
int CI(int &_x) { return scanf("%d", &_x); }
int CI(int &_x, int &_y) { return scanf("%d %d", &_x, &_y); }
int CI(int &_x, int &_y, int &_z) { return scanf("%d %d %d", &_x, &_y, &_z); }
int CI(int &_a, int &_b, int &_c, int &_d) {
  return scanf("%d %d %d %d", &_a, &_b, &_c, &_d);
}
template <class T1, class T2>
inline T1 UMAX(T1 &m, T2 other) {
  if (m < other) m = other;
  return m;
}
template <class T1, class T2>
inline T1 UMIN(T1 &m, T2 other) {
  if (m > other) m = other;
  return m;
}
template <class T>
string toString(T n) {
  ostringstream oss;
  oss << n;
  return oss.str();
}
int toInt(string s) {
  int r = 0;
  istringstream sin(s);
  sin >> r;
  return r;
}
long long int toLong(string s) {
  long long int r = 0;
  istringstream sin(s);
  sin >> r;
  return r;
}
bool isVowel(char ch) {
  ch = tolower(ch);
  if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
    return true;
  return false;
}
bool isUpper(char c) { return c >= 'A' && c <= 'Z'; }
bool isLower(char c) { return c >= 'a' && c <= 'z'; }
int dr8[8] = {+1, -1, +0, +0, +1, -1, -1, +1};
int dc8[8] = {+0, +0, -1, +1, +1, +1, -1, -1};
int dr4[4] = {+0, +0, +1, -1};
int dc4[4] = {-1, +1, +0, +0};
int kn8r[8] = {+1, +2, +2, +1, -1, -2, -2, -1};
int kn8c[8] = {+2, +1, -1, -2, -2, -1, +1, +2};
const double EPS = 1e-9;
const int INF = (1 << 30) - 1;
const long long int LINF = (1ll << 62) - 1;
const int mod = (int)1e9 + 7;
const int MAX = (int)1e5;
int MOD = mod;
struct Matrix {
  long long mat[2][2];
  void Clear() { memset(mat, 0, sizeof(mat)); }
  void Initiate() {
    mat[0][0] = 1;
    mat[0][1] = 1;
    mat[1][0] = 1;
    mat[1][1] = 0;
  }
  void I_matrix() {
    mat[0][0] = 1;
    mat[0][1] = 0;
    mat[1][0] = 0;
    mat[1][1] = 1;
  }
  Matrix operator*(const Matrix &A) const {
    Matrix ret;
    ret.Clear();
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        ret.mat[i][j] = 0;
        for (int k = 0; k < 2; k++) ret.mat[i][j] += (mat[i][k] * A.mat[k][j]);
        ret.mat[i][j] %= MOD;
      }
    }
    return ret;
  }
  Matrix operator+(const Matrix &A) const {
    Matrix ret;
    ret.Clear();
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        ret.mat[i][j] = mat[i][j] + A.mat[i][j];
        ret.mat[i][j] %= MOD;
      }
    }
    return ret;
  }
  Matrix Power(int P) {
    Matrix temp;
    if (P == 0) {
      temp.I_matrix();
      return temp;
    }
    if (P % 2 == 1) return (*this) * Power(P - 1);
    temp = Power(P / 2);
    return temp * temp;
  }
  void showMatrix() {
    puts("------");
    cout << "|" << mat[0][0] << "  " << mat[0][1] << "|" << '\n';
    cout << "|" << mat[1][0] << "  " << mat[1][1] << "|" << '\n';
    puts("------");
  }
};
Matrix PowerMatrix_BigMod(Matrix A, int P) {
  if (P == 1) return A;
  if (P % 2 == 1) return A * PowerMatrix_BigMod(A, P - 1);
  Matrix temp = PowerMatrix_BigMod(A, P / 2);
  return temp * temp;
}
int A[MAX + 7];
Matrix Mat, UpdateWithThis;
struct Node {
  int l, r;
  Matrix S, P;
};
Node SegTree[MAX * 4];
void PushDownToChild(int inx) {
  SegTree[inx * 2].S = SegTree[inx * 2].S * SegTree[inx].P;
  SegTree[inx * 2].P = SegTree[inx * 2].P * SegTree[inx].P;
  SegTree[inx * 2 + 1].S = SegTree[inx * 2 + 1].S * SegTree[inx].P;
  SegTree[inx * 2 + 1].P = SegTree[inx * 2 + 1].P * SegTree[inx].P;
  SegTree[inx].P.I_matrix();
}
void BuildSegTree(int inx, int l, int r) {
  SegTree[inx].l = l;
  SegTree[inx].r = r;
  SegTree[inx].S.Clear();
  SegTree[inx].P.I_matrix();
  if (l == r) {
    SegTree[inx].S = Mat.Power(A[l]);
  } else {
    int mid = (l + r) >> 1;
    BuildSegTree(inx * 2, l, mid);
    BuildSegTree(inx * 2 + 1, mid + 1, r);
    SegTree[inx].S = SegTree[inx * 2].S + SegTree[inx * 2 + 1].S;
  }
}
void UpdateSegTree(int inx, int l, int r) {
  if (SegTree[inx].l >= l && SegTree[inx].r <= r) {
    SegTree[inx].S = SegTree[inx].S * UpdateWithThis;
    SegTree[inx].P = SegTree[inx].P * UpdateWithThis;
    return;
  }
  PushDownToChild(inx);
  if (SegTree[inx * 2].r >= l) UpdateSegTree(inx * 2, l, r);
  if (SegTree[inx * 2 + 1].l <= r) UpdateSegTree(inx * 2 + 1, l, r);
  SegTree[inx].S = SegTree[inx * 2].S + SegTree[inx * 2 + 1].S;
}
Matrix QuerySegTree(int inx, int l, int r) {
  if (SegTree[inx].l >= l && SegTree[inx].r <= r) {
    return SegTree[inx].S;
  }
  PushDownToChild(inx);
  Matrix ret;
  ret.Clear();
  if (SegTree[inx * 2].r >= l) ret = ret + QuerySegTree(inx * 2, l, r);
  if (SegTree[inx * 2 + 1].l <= r) ret = ret + QuerySegTree(inx * 2 + 1, l, r);
  return ret;
}
int main() {
  if (deb_mode) srand(int(time(NULL)));
  int i, j, k, l, r, n, m, q, a, b, c;
  Mat.Initiate();
  CI(n, m);
  for (i = 1; i <= n; i++) CI(A[i]);
  BuildSegTree(1, 1, n);
  while (m--) {
    CI(q);
    if (q == 1) {
      CI(l, r, a);
      UpdateWithThis = Mat.Power(a);
      UpdateSegTree(1, l, r);
    } else {
      CI(l, r);
      Matrix Ans = QuerySegTree(1, l, r);
      cout << Ans.mat[1][0] << "\n";
    }
  }
  if (deb_mode)
    cerr << "EXECUTION TIME = " << (1.0 * clock()) / CLOCKS_PER_SEC
         << " SECONDS\n";
  return 0;
}
