#include <bits/stdc++.h>
const int maxn = 1e5 + 10;
using namespace std;
long long gcd(long long p, long long q) { return q == 0 ? p : gcd(q, p % q); }
long long qpow(long long p, long long q) {
  long long f = 1;
  while (q) {
    if (q & 1) f = f * p % 1000000007;
    p = p * p % 1000000007;
    q >>= 1;
  }
  return f;
}
int n, m, k, t, a[maxn];
struct Matrix {
  int a[2][2];
  Matrix() { memset(a, 0, sizeof(a)); }
  void init() {
    for (int i = 0; i < 2; i++)
      for (int j = 0; j < 2; j++) a[i][j] = (i == j);
  }
  Matrix operator+(const Matrix &B) const {
    Matrix C;
    for (int i = 0; i < 2; i++)
      for (int j = 0; j < 2; j++)
        C.a[i][j] = (a[i][j] + B.a[i][j]) % 1000000007;
    return C;
  }
  Matrix operator*(const Matrix &B) const {
    Matrix C;
    for (int i = 0; i < 2; i++)
      for (int k = 0; k < 2; k++)
        for (int j = 0; j < 2; j++)
          C.a[i][j] = (C.a[i][j] + 1LL * a[i][k] * B.a[k][j]) % 1000000007;
    return C;
  }
  Matrix operator^(const int &t) const {
    Matrix A = (*this), res;
    res.init();
    int p = t;
    while (p) {
      if (p & 1) res = res * A;
      A = A * A;
      p >>= 1;
    }
    return res;
  }
};
Matrix f;
struct Node {
  Matrix sum, lazy;
} T[maxn << 2];
void PushUp(int rt) { T[rt].sum = T[rt << 1].sum + T[rt << 1 | 1].sum; }
void PushDown(int L, int R, int rt) {
  int mid = (L + R) >> 1;
  Matrix t = T[rt].lazy;
  T[rt << 1].sum = t * T[rt << 1].sum;
  T[rt << 1 | 1].sum = t * T[rt << 1 | 1].sum;
  T[rt << 1].lazy = t * T[rt << 1].lazy;
  T[rt << 1 | 1].lazy = t * T[rt << 1 | 1].lazy;
  T[rt].lazy.init();
}
void Build(int L, int R, int rt) {
  T[rt].lazy.init();
  if (L == R) {
    T[rt].sum = f ^ (a[L] - 1);
    return;
  }
  int mid = (L + R) >> 1;
  Build(L, mid, rt << 1);
  Build(mid + 1, R, rt << 1 | 1);
  PushUp(rt);
}
void Update(int l, int r, Matrix v, int L, int R, int rt) {
  if (l == L && r == R) {
    T[rt].lazy = v * T[rt].lazy;
    T[rt].sum = v * T[rt].sum;
    return;
  }
  int mid = (L + R) >> 1;
  if (T[rt].lazy.a[0][0] || T[rt].lazy.a[1][1]) PushDown(L, R, rt);
  if (r <= mid)
    Update(l, r, v, L, mid, rt << 1);
  else if (l > mid)
    Update(l, r, v, mid + 1, R, rt << 1 | 1);
  else {
    Update(l, mid, v, L, mid, rt << 1);
    Update(mid + 1, r, v, mid + 1, R, rt << 1 | 1);
  }
  PushUp(rt);
}
long long Query(int l, int r, int L, int R, int rt) {
  if (l == L && r == R) {
    return T[rt].sum.a[0][0];
  }
  int mid = (L + R) >> 1;
  if (T[rt].lazy.a[0][0] || T[rt].lazy.a[1][1]) PushDown(L, R, rt);
  if (r <= mid)
    return Query(l, r, L, mid, rt << 1);
  else if (l > mid)
    return Query(l, r, mid + 1, R, rt << 1 | 1);
  return (Query(l, mid, L, mid, rt << 1) +
          Query(mid + 1, r, mid + 1, R, rt << 1 | 1)) %
         1000000007;
}
struct node {
  int a, x, y, z;
} op[maxn];
void init() {
  f.a[0][0] = 1, f.a[0][1] = 1;
  f.a[1][0] = 1, f.a[1][1] = 0;
}
int main() {
  int i, j;
  init();
  scanf("%d%d", &n, &m);
  for (i = 1; i <= n; i++) scanf("%d", &a[i]);
  Build(1, n, 1);
  for (i = 1; i <= m; i++) {
    scanf("%d", &op[i].a);
    if (op[i].a == 1) {
      scanf("%d%d%d", &op[i].x, &op[i].y, &op[i].z);
      Update(op[i].x, op[i].y, f ^ op[i].z, 1, n, 1);
    } else {
      scanf("%d%d", &op[i].x, &op[i].y);
      printf("%lld\n", Query(op[i].x, op[i].y, 1, n, 1));
    }
  }
  return 0;
}
