#include <bits/stdc++.h>
using namespace std;
const int md = 1e9 + 7;
const int maxn = 1e5 + 5;
struct Marix {
  long long maze[2][2];
  Marix() { memset(maze, 0, sizeof maze); }
  void One() {
    maze[0][0] = maze[1][1] = 1;
    maze[0][1] = maze[1][0] = 0;
  }
  Marix operator+(const Marix& tmp) const {
    Marix ret;
    ret.maze[0][0] = (maze[0][0] + tmp.maze[0][0]) % md;
    ret.maze[0][1] = (maze[0][1] + tmp.maze[0][1]) % md;
    ret.maze[1][0] = (maze[1][0] + tmp.maze[1][0]) % md;
    ret.maze[1][1] = (maze[1][1] + tmp.maze[1][1]) % md;
    return ret;
  }
  Marix operator*(const Marix& tmp) const {
    Marix ret;
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        for (int k = 0; k < 2; k++) {
          ret.maze[i][j] += maze[i][k] * tmp.maze[k][j] % md;
          ret.maze[i][j] %= md;
        }
      }
    }
    return ret;
  }
} B;
Marix quick_pow(Marix a, long long k) {
  Marix ans;
  ans.One();
  while (k) {
    if (k & 1) ans = ans * a;
    a = a * a;
    k >>= 1;
  }
  return ans;
}
struct SegTree {
  int l, r;
  Marix sum, add;
  void Add(const Marix& A) {
    sum = A * sum;
    add = A * add;
  }
} tree[maxn << 2];
void push_up(int rt) {
  tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;
}
void push_down(int rt) {
  tree[rt << 1].Add(tree[rt].add);
  tree[rt << 1 | 1].Add(tree[rt].add);
  tree[rt].add.One();
}
void build(int l, int r, int rt) {
  tree[rt].l = l;
  tree[rt].r = r;
  tree[rt].add.maze[0][0] = 1;
  tree[rt].add.maze[0][1] = 0;
  tree[rt].add.maze[1][0] = 0;
  tree[rt].add.maze[1][1] = 1;
  if (l == r) {
    int x;
    scanf("%d", &x);
    tree[rt].sum = quick_pow(B, x);
    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, const Marix& A) {
  if (l <= tree[rt].l && tree[rt].r <= r) {
    tree[rt].Add(A);
    return;
  }
  push_down(rt);
  int mid = (tree[rt].l + tree[rt].r) >> 1;
  if (l <= mid) update(l, r, rt << 1, A);
  if (mid < r) update(l, r, rt << 1 | 1, A);
  push_up(rt);
}
Marix ans;
void query(int l, int r, int rt) {
  if (l <= tree[rt].l && tree[rt].r <= r) {
    ans = ans + tree[rt].sum;
    return;
  }
  push_down(rt);
  int mid = (tree[rt].l + tree[rt].r) >> 1;
  if (l <= mid) query(l, r, rt << 1);
  if (mid < r) query(l, r, rt << 1 | 1);
  push_up(rt);
}
int main() {
  B.maze[0][0] = B.maze[0][1] = B.maze[1][0] = 1;
  int n, m, opt, l, r, x;
  scanf("%d%d", &n, &m);
  build(1, n, 1);
  while (m--) {
    scanf("%d", &opt);
    if (opt == 1) {
      scanf("%d%d%d", &l, &r, &x);
      Marix A = quick_pow(B, x);
      update(l, r, 1, A);
    } else {
      scanf("%d%d", &l, &r);
      ans.maze[0][0] = ans.maze[0][1] = ans.maze[1][0] = ans.maze[1][1] = 0;
      query(l, r, 1);
      cout << ans.maze[0][1] << '\n';
    }
  }
  return 0;
}
