#include <bits/stdc++.h>
using namespace std;
struct SegmentNode {
  long long carry;
  int sz;
  bool HasCarry;
  SegmentNode() {
    this->carry = 0;
    this->sz = 1;
    HasCarry = 0;
  }
  void join(const SegmentNode &l, const SegmentNode &r) { sz = l.sz + r.sz; }
  void update() { HasCarry = 1; }
  void clear() { HasCarry = 0; }
};
template <class T>
struct SegmentTree {
  vector<T> V;
  int N;
  SegmentTree(int N) {
    this->V = vector<T>(4 * N);
    this->N = N;
  }
  void create(vector<typename T::Init> &VEC, int n = 1, int b = 0, int e = -1) {
    if (e == -1) e = N - 1;
    if (b == e) {
      V[n] = T(VEC[b]);
    } else {
      create(VEC, 2 * n, b, (e + b) / 2);
      create(VEC, 2 * n + 1, (e + b) / 2 + 1, e);
      V[n] = V[2 * n] + V[2 * n + 1];
    }
  }
  T query(int i, int j, int n = 1, int b = 0, int e = -1) {
    if (e == -1) e = N - 1;
    if (i <= b && e <= j)
      return V[n];
    else {
      if (V[n].HasCarry) {
        V[2 * n].update(V[n].carry);
        V[2 * n + 1].update(V[n].carry);
        V[n].clear();
      }
      int mid = (b + e) / 2;
      if (i > mid) return query(i, j, 2 * n + 1, mid + 1, e);
      if (j <= mid) return query(i, j, 2 * n, b, mid);
      return query(i, j, 2 * n, b, mid) + query(i, j, 2 * n + 1, mid + 1, e);
    }
  }
  void update(int i, int j, int v, int n = 1, int b = 0, int e = -1) {
    if (e == -1) e = N - 1;
    if (i <= b && e <= j) {
      V[n].update(v);
    } else if (i > e || j < b)
      return;
    else {
      if (V[n].HasCarry) {
        V[2 * n].update(V[n].carry);
        V[2 * n + 1].update(V[n].carry);
        V[n].clear();
      }
      int mid = (b + e) / 2;
      update(i, j, v, 2 * n, b, mid);
      update(i, j, v, 2 * n + 1, mid + 1, e);
      V[n] = V[2 * n] + V[2 * n + 1];
    }
  }
};
int M[60][2][2] = {{{1, 1}, {1, 0}}};
void mult(int A[2][2], int B[2][2], int C[2][2]) {
  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 2; ++j) {
      for (int k = 0; k < 2; ++k) {
        A[i][j] = (A[i][j] + 1LL * B[i][k] * C[k][j]) % 1000000007;
      }
    }
  }
}
struct Fibo {
  int a, b;
  Fibo(int a = 0, int b = 0) : a(a), b(b) {}
};
Fibo apply(int MAT[2][2], Fibo f) {
  Fibo r;
  r.a = (1LL * f.a * MAT[0][0] + 1LL * f.b * MAT[0][1]) % 1000000007;
  r.b = (1LL * f.a * MAT[1][0] + 1LL * f.b * MAT[1][1]) % 1000000007;
  return r;
}
Fibo move(Fibo f, long long n) {
  for (int i = 0; i < 47; ++i) {
    if ((1LL << i) & n) {
      f = apply(M[i], f);
    }
  }
  return f;
}
void init() {
  for (int i = 1; i < 60; ++i) {
    mult(M[i], M[i - 1], M[i - 1]);
  }
}
struct MinVal : SegmentNode {
  struct Init {
    int val;
    Init(int val = 0) : val(val) {}
  };
  Fibo val;
  MinVal() : SegmentNode() {}
  MinVal(Init n) : SegmentNode() { val = move(Fibo(1, 1), n.val - 1); }
  MinVal operator+(const MinVal &N) const {
    MinVal ret;
    ret.join(*this, N);
    ret.val.a = (val.a + N.val.a) % 1000000007;
    ret.val.b = (val.b + N.val.b) % 1000000007;
    ret.carry = 0;
    ret.HasCarry = 0;
    return ret;
  }
  void update(long long x) {
    SegmentNode::update();
    val = move(val, x);
    carry += x;
  }
  void clear() { carry = 0; }
};
int main() {
  init();
  int N, MM;
  cin >> N >> MM;
  SegmentTree<MinVal> ST(N);
  vector<MinVal::Init> V(N);
  for (int i = 0; i < N; ++i) {
    cin >> V[i].val;
  }
  ST.create(V);
  for (int i = 0; i < MM; ++i) {
    int c;
    cin >> c;
    if (c == 1) {
      int l, r, x;
      cin >> l >> r >> x;
      l--;
      r--;
      ST.update(l, r, x);
    } else {
      int l, r;
      cin >> l >> r;
      l--;
      r--;
      cout << ST.query(l, r).val.b << endl;
    }
  }
  return 0;
}
