#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn = 2e5 + 10;
const int inf = 0x7fffffff;
const long long INF = 9E18;
const int mod = 1e9 + 7;
const long long mod2 = 1e9 + 9;
const int eps = 1e-7;
const double pi = acos(-1.0);
template <typename T>
inline void read(T &x) {
  T f = 1;
  char ch = getchar();
  for (; ch < '0' || ch > '9'; ch = getchar())
    if (ch == '-') f = -1;
  for (x = 0; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
  x *= f;
}
struct matrix {
  long long a[2][2];
  matrix() { memset(a, 0, sizeof a); }
  matrix(long long x, long long y, long long p, long long q) {
    a[0][0] = x;
    a[0][1] = y;
    a[1][0] = p;
    a[1][1] = q;
  }
  matrix operator*(const matrix b) {
    matrix c;
    for (int i = 0; i <= 1; i++)
      for (int j = 0; j <= 1; j++)
        for (int k = 0; k <= 1; k++)
          c.a[i][j] = (c.a[i][j] + ((a[i][k] * b.a[k][j]) % mod)) % mod;
    return c;
  }
  matrix operator+(const matrix b) {
    matrix c;
    for (int i = 0; i <= 1; i++)
      for (int j = 0; j <= 1; j++) c.a[i][j] = (a[i][j] + b.a[i][j]) % mod;
    return c;
  }
  bool operator==(const matrix b) {
    for (int i = 0; i <= 1; i++) {
      for (int j = 0; j <= 1; j++) {
        if (a[i][j] != b.a[i][j]) return 0;
      }
    }
    return 1;
  }
  matrix operator^(long long x) {
    matrix c(1, 0, 0, 1), b = *this;
    while (x) {
      if (x & 1) c = c * b;
      b = b * b;
      x >>= 1;
    }
    return c;
  }
} change(1, 1, 1, 0), ori(1, 0, 0, 0), tree[maxn << 2], lazy[maxn << 2],
    I(1, 0, 0, 1);
long long a[maxn];
int n, m;
void push_up(int rt) { tree[rt] = tree[rt << 1] + tree[rt << 1 | 1]; }
void push_down(int rt) {
  if (lazy[rt] == I) return;
  lazy[rt << 1] = lazy[rt << 1] * lazy[rt];
  lazy[rt << 1 | 1] = lazy[rt << 1 | 1] * lazy[rt];
  tree[rt << 1] = tree[rt << 1] * lazy[rt];
  tree[rt << 1 | 1] = tree[rt << 1 | 1] * lazy[rt];
  lazy[rt] = I;
}
void build(int l, int r, int rt) {
  lazy[rt] = I;
  if (l == r) {
    tree[rt] = ori * (change ^ (a[l] - 1));
    return;
  }
  int mid = (l + r) >> 1;
  build(l, mid, rt << 1);
  build(mid + 1, r, rt << 1 | 1);
  push_up(rt);
}
void update(int l, int r, int rt, int x, int y, matrix val) {
  if (x <= l && r <= y) {
    tree[rt] = (tree[rt] * val);
    lazy[rt] = lazy[rt] * val;
    return;
  }
  push_down(rt);
  int mid = (l + r) >> 1;
  if (x <= mid) update(l, mid, rt << 1, x, y, val);
  if (y > mid) update(mid + 1, r, rt << 1 | 1, x, y, val);
  push_up(rt);
}
long long query(int l, int r, int rt, int x, int y) {
  push_down(rt);
  if (x <= l && r <= y) return ((tree[rt].a[0][0] + mod) % mod);
  int mid = (l + r) >> 1;
  long long ans = 0;
  if (x <= mid) ans += query(l, mid, rt << 1, x, y);
  if (y > mid) ans += query(mid + 1, r, rt << 1 | 1, x, y);
  return ((ans + mod) % mod);
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++) read(a[i]);
  build(1, n, 1);
  while (m--) {
    int op, l, r;
    scanf("%d%d%d", &op, &l, &r);
    if (op == 1) {
      long long x;
      read(x);
      update(1, n, 1, l, r, change ^ x);
    } else {
      cout << query(1, n, 1, l, r) << endl;
    }
  }
  return 0;
}
