#include <bits/stdc++.h>
const int Max = 2e5 + 100;
const int MOD = 1e9 + 7;
struct Matix {
  long long a[2][2];
  Matix operator*(const Matix &s) const {
    Matix ans;
    memset(ans.a, 0, sizeof(ans.a));
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        for (int k = 0; k < 2; k++) {
          ans.a[i][j] = (ans.a[i][j] + a[i][k] * s.a[k][j] % MOD) % MOD;
        }
      }
    }
    return ans;
  }
  Matix operator+(const Matix &s) const {
    Matix ans;
    memset(ans.a, 0, sizeof(ans.a));
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        ans.a[i][j] = (a[i][j] + s.a[i][j]) % MOD;
      }
    }
    return ans;
  }
};
Matix pow_mod(Matix x, int m) {
  Matix ans;
  memset(ans.a, 0, sizeof(ans.a));
  for (int i = 0; i < 2; i++) ans.a[i][i] = 1;
  while (m) {
    if (m % 2 == 1) ans = ans * x;
    x = x * x;
    m >>= 1;
  }
  return ans;
}
Matix data[Max];
struct Tree {
  int l, r;
  Matix sum, lazy;
  void updata(Matix x) {
    sum = sum * x;
    lazy = lazy * x;
  }
} tree[Max << 2];
inline void push_down(int ins) {
  Matix lazyval = tree[ins].lazy;
  if (lazyval.a[0][0]) {
    tree[ins << 1].updata(lazyval);
    tree[ins * 2 + 1].updata(lazyval);
    memset(tree[ins].lazy.a, 0, sizeof(tree[ins].lazy.a));
    for (int a = 0; a < 2; a++) tree[ins].lazy.a[a][a] = 1;
  }
}
inline void push_up(int ins) {
  tree[ins].sum = tree[ins << 1].sum + tree[ins * 2 + 1].sum;
}
inline void build(int l, int r, int ins) {
  tree[ins].l = l, tree[ins].r = r;
  memset(tree[ins].sum.a, 0, sizeof(tree[ins].sum.a));
  memset(tree[ins].lazy.a, 0, sizeof(tree[ins].lazy.a));
  for (int a = 0; a < 2; a++)
    tree[ins].sum.a[a][a] = tree[ins].lazy.a[a][a] = 1;
  if (r == l) {
    tree[ins].sum = data[r];
  } else if (r > l) {
    build(l, (l + r) / 2, ins << 1);
    build((l + r) / 2 + 1, r, ins * 2 + 1);
    push_up(ins);
  }
}
inline void updata_tree(int ql, int qr, Matix x, int ins) {
  int l = tree[ins].l, r = tree[ins].r;
  if (ql <= l && r <= qr)
    tree[ins].updata(x);
  else {
    push_down(ins);
    if (ql <= (l + r) / 2) updata_tree(ql, qr, x, ins << 1);
    if (qr > (l + r) / 2) updata_tree(ql, qr, x, ins * 2 + 1);
    push_up(ins);
  }
}
inline long long query(int ql, int qr, int ins) {
  int l = tree[ins].l, r = tree[ins].r;
  if (ql <= l && r <= qr)
    return tree[ins].sum.a[0][1];
  else {
    push_down(ins);
    long long res = 0;
    if (ql <= (l + r) / 2) res += query(ql, qr, ins << 1);
    res %= MOD;
    if (qr > (l + r) / 2) res += query(ql, qr, ins * 2 + 1);
    res %= MOD;
    return res;
  }
}
int tmp[Max];
int main() {
  Matix F;
  F.a[0][0] = F.a[0][1] = F.a[1][0] = 1;
  F.a[1][1] = 0;
  int n, m;
  scanf("%d%d", &n, &m);
  for (int a = 1; a <= n; a++) {
    scanf("%d", &tmp[a]);
    data[a] = pow_mod(F, tmp[a]);
  }
  build(1, n, 1);
  while (m--) {
    int op, x, y, z;
    scanf("%d%d%d", &op, &x, &y);
    if (op == 1) {
      scanf("%d", &z);
      updata_tree(x, y, pow_mod(F, z), 1);
    } else {
      int lac = query(x, y, 1);
      printf("%d\n", lac);
    }
  }
  return 0;
}
