#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 100;
const int Mod = 1e9 + 7;
struct Mat {
  long long A[2][2];
  Mat() { memset(A, 0, sizeof(A)); }
  void init(void) {
    for (int i = 0; i < 2; i++)
      for (int j = 0; j < 2; j++) A[i][j] = (i == j);
  }
  Mat operator+(struct Mat A) {
    struct Mat B;
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        B.A[i][j] = this->A[i][j] + A.A[i][j];
        B.A[i][j] %= Mod;
      }
    }
    return B;
  }
  Mat operator*(struct Mat A) {
    struct Mat B;
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        for (int k = 0; k < 2; k++) {
          B.A[i][j] += (this->A[i][k] * A.A[k][j]);
          B.A[i][j] %= Mod;
        }
      }
    }
    return B;
  }
  Mat operator^(int t) {
    struct Mat A, B;
    A.init();
    for (int i = 0; i < 2; i++)
      for (int j = 0; j < 2; j++) B.A[i][j] = this->A[i][j];
    while (t) {
      if (t & 1) A = A * B;
      t >>= 1;
      B = B * B;
    }
    return A;
  }
};
struct Mat Tree[N << 2], Laze[N << 2], f;
int A[N];
void pushUp(int n) { Tree[n] = (Tree[n << 1] + Tree[n << 1 | 1]); }
void pushDown(int n) {
  Tree[n << 1] = Laze[n] * Tree[n << 1];
  Tree[n << 1 | 1] = Laze[n] * Tree[n << 1 | 1];
  Laze[n << 1] = Laze[n] * Laze[n << 1];
  Laze[n << 1 | 1] = Laze[n] * Laze[n << 1 | 1];
  Laze[n].init();
}
void build(int l, int r, int rt) {
  Laze[rt].init();
  if (l == r) {
    Tree[rt] = 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, int rt, int _l, int _r, struct Mat x) {
  if (l >= _l && r <= _r) {
    Tree[rt] = x * Tree[rt];
    Laze[rt] = x * Laze[rt];
    return;
  }
  pushDown(rt);
  int mid = (l + r) >> 1;
  if (_r <= mid) {
    update(l, mid, rt << 1, _l, _r, x);
  } else if (_l > mid) {
    update(mid + 1, r, rt << 1 | 1, _l, _r, x);
  } else {
    update(l, mid, rt << 1, _l, _r, x);
    update(mid + 1, r, rt << 1 | 1, _l, _r, x);
  }
  pushUp(rt);
}
int query(int l, int r, int rt, int _l, int _r) {
  if (l >= _l && r <= _r) {
    return Tree[rt].A[0][0];
  }
  pushDown(rt);
  int mid = (l + r) >> 1;
  if (_r <= mid) {
    return query(l, mid, rt << 1, _l, _r);
  } else if (_l > mid) {
    return query(mid + 1, r, rt << 1 | 1, _l, _r);
  }
  return (query(l, mid, rt << 1, _l, _r) +
          query(mid + 1, r, rt << 1 | 1, _l, _r)) %
         Mod;
}
int main(void) {
  int n, m;
  for (int i = 0; i < 2; i++)
    for (int j = 0; j < 2; j++) f.A[i][j] = 1;
  f.A[1][1] = 0;
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> A[i];
  }
  build(1, n, 1);
  while (m--) {
    int type, l, r;
    cin >> type >> l >> r;
    if (type == 1) {
      int x;
      cin >> x;
      update(1, n, 1, l, r, f ^ x);
    } else if (type == 2) {
      cout << query(1, n, 1, l, r) << endl;
    }
  }
  return 0;
}
