#include <bits/stdc++.h>
template <typename Tp>
inline void read(Tp &x) {
  x = 0;
  bool f = true;
  char ch = getchar();
  for (; ch < '0' || ch > '9'; ch = getchar()) f ^= ch == '-';
  for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + (ch ^ 48);
  x = f ? x : -x;
}
const long long N = 1e5 + 7, P = 1e9 + 7;
long long a[N];
struct Matrix {
  long long m[3][3];
};
Matrix dp;
inline Matrix operator*(Matrix a, Matrix b) {
  Matrix c;
  c.m[1][1] = (a.m[1][1] * b.m[1][1] + a.m[1][2] * b.m[2][1]) % P;
  c.m[1][2] = (a.m[1][1] * b.m[1][2] + a.m[1][2] * b.m[2][2]) % P;
  c.m[2][1] = (a.m[2][1] * b.m[1][1] + a.m[2][2] * b.m[2][1]) % P;
  c.m[2][2] = (a.m[2][1] * b.m[1][2] + a.m[2][2] * b.m[2][2]) % P;
  return c;
}
inline Matrix operator+(Matrix a, Matrix b) {
  Matrix c;
  c.m[1][1] = (a.m[1][1] + b.m[1][1]) % P;
  c.m[1][2] = (a.m[1][2] + b.m[1][2]) % P;
  c.m[2][1] = (a.m[2][1] + b.m[2][1]) % P;
  c.m[2][2] = (a.m[2][2] + b.m[2][2]) % P;
  return c;
}
inline Matrix power(Matrix a, long long x) {
  Matrix ans;
  ans.m[1][1] = ans.m[2][2] = 1, ans.m[1][2] = ans.m[2][1] = 0;
  while (x) {
    if (x & 1) ans = ans * a;
    a = a * a;
    x >>= 1;
  }
  return ans;
}
struct Node {
  Matrix val;
  long long tag;
};
struct Segment_Tree {
  Node tre[N << 2];
  inline void pushdown(long long p) {
    if (tre[p].tag) {
      tre[p << 1].tag += tre[p].tag, tre[p << 1 | 1].tag += tre[p].tag;
      Matrix v = power(dp, tre[p].tag);
      tre[p << 1].val = tre[p << 1].val * v,
               tre[p << 1 | 1].val = tre[p << 1 | 1].val * v;
      tre[p].tag = 0;
    }
  }
  inline void build(long long p, long long l, long long r) {
    if (l == r) {
      tre[p].val = power(dp, a[l] - 1);
      return;
    }
    long long mid = (l + r) >> 1;
    build(p << 1, l, mid), build(p << 1 | 1, mid + 1, r);
    tre[p].val = tre[p << 1].val + tre[p << 1 | 1].val;
  }
  inline void update(long long p, long long l, long long r, long long x,
                     long long y, long long k, Matrix v) {
    if (l >= x && r <= y) {
      tre[p].val = tre[p].val * v;
      tre[p].tag += k;
      return;
    }
    pushdown(p);
    long long mid = (l + r) >> 1;
    if (x <= mid) update(p << 1, l, mid, x, y, k, v);
    if (y > mid) update(p << 1 | 1, mid + 1, r, x, y, k, v);
    tre[p].val = tre[p << 1].val + tre[p << 1 | 1].val;
  }
  inline Matrix query(long long p, long long l, long long r, long long x,
                      long long y) {
    if (l >= x && r <= y) return tre[p].val;
    pushdown(p);
    long long mid = (l + r) >> 1;
    if (y <= mid) return query(p << 1, l, mid, x, y);
    if (x > mid) return query(p << 1 | 1, mid + 1, r, x, y);
    return query(p << 1, l, mid, x, y) + query(p << 1 | 1, mid + 1, r, x, y);
  }
};
Segment_Tree T;
signed main() {
  dp.m[1][2] = dp.m[2][2] = dp.m[2][1] = 1;
  long long n, m;
  read(n), read(m);
  for (long long i = 1; i <= n; ++i) read(a[i]);
  T.build(1, 1, n);
  while (m--) {
    long long opt;
    read(opt);
    if (opt == 1) {
      long long l, r, k;
      read(l), read(r), read(k);
      T.update(1, 1, n, l, r, k, power(dp, k));
    } else {
      long long l, r;
      read(l), read(r);
      printf("%lld\n", T.query(1, 1, n, l, r).m[2][2]);
    }
  }
  return 0;
}
