#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline T read() {
  T s = 0, f = 1;
  char ch = getchar();
  while (not isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    s = s * 10 + ch - 48;
    ch = getchar();
  }
  return s * f;
}
constexpr int N = 1e5 + 7;
constexpr int mod = 1e9 + 7;
long long val[N];
struct SegmentTree {
  static const int M = 1e5 + 7;
  struct Matrix {
    array<long long, 2> a[2];

   public:
    Matrix(int x) {
      if (x == 0) {
        a[0][0] = a[1][1] = 1;
        a[0][1] = a[1][0] = 0;
      } else if (x == 1) {
        a[0][0] = a[1][0] = a[0][1] = 1;
        a[1][1] = 0;
      } else if (x == 2) {
        for (int i = 0; i < 2; ++i) {
          a[i].fill(0);
        }
      } else {
        a[0][0] = 1;
        a[1][0] = a[1][1] = a[0][1] = 0;
      }
    }
    Matrix() {
      for (int i = 0; i < 2; ++i) {
        a[i].fill(0);
      }
    }
    Matrix operator*(const Matrix& rhs) const {
      Matrix ans = (2);
      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] % mod) * (rhs.a[k][j] % mod)) % mod) %
                mod;
          }
        }
      }
      return ans;
    }
    Matrix operator^(long long rhs) {
      Matrix ans(0);
      Matrix t = *this;
      while (rhs) {
        if (rhs & 1) ans = ans * t;
        t = t * t;
        rhs >>= 1;
      }
      return ans;
    }
    Matrix operator+(const Matrix& rhs) {
      Matrix ans(2);
      for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 2; ++j) {
          ans.a[i][j] = (a[i][j] + rhs.a[i][j]) % mod;
        }
      }
      return ans;
    }
    bool operator!=(const Matrix rhs) const {
      for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 2; ++j) {
          if (a[i][j] != rhs.a[i][j]) return true;
        }
      }
      return false;
    }
  };
  struct node {
    Matrix val, tag;
  } s[M << 2];
  Matrix C;
  void init(int x) { C = Matrix(1) ^ x; }
  void pushup(int node) {
    s[node].val = s[node << 1].val + s[node << 1 | 1].val;
  }
  void spread(int node) {
    if (s[node].tag != Matrix(0)) {
      s[node << 1].val = s[node << 1].val * s[node].tag;
      s[node << 1 | 1].val = s[node << 1 | 1].val * s[node].tag;
      s[node << 1].tag = s[node << 1].tag * s[node].tag;
      s[node << 1 | 1].tag = s[node << 1 | 1].tag * s[node].tag;
      s[node].tag = Matrix(0);
    }
  }
  void build(int node, int l, int r) {
    s[node].tag = Matrix(0);
    if (l == r) {
      s[node].val = (3);
      s[node].val = s[node].val * (Matrix(1) ^ (val[l] - 1));
      return;
    }
    int mid = l + r >> 1;
    build(node << 1, l, mid);
    build(node << 1 | 1, mid + 1, r);
    pushup(node);
  }
  void change(int node, int l, int r, int L, int R, long long x) {
    if (L <= l and R >= r) {
      s[node].tag = s[node].tag * C;
      s[node].val = s[node].val * C;
      return;
    }
    spread(node);
    int mid = l + r >> 1;
    if (L <= mid) change(node << 1, l, mid, L, R, x);
    if (R > mid) change(node << 1 | 1, mid + 1, r, L, R, x);
    pushup(node);
  }
  long long query(int node, int l, int r, int L, int R) {
    if (L <= l and R >= r) {
      return s[node].val.a[0][0] % mod;
    }
    spread(node);
    int mid = l + r >> 1;
    long long ans = 0;
    if (L <= mid) ans = (ans + query(node << 1, l, mid, L, R)) % mod;
    if (R > mid) ans = (ans + query(node << 1 | 1, mid + 1, r, L, R)) % mod;
    pushup(node);
    return ans % mod;
  }
} tree;
int main() {
  int n = read<int>(), m = read<int>();
  for (int i = 1; i <= n; ++i) val[i] = read<long long>();
  tree.build(1, 1, n);
  for (int i = 1; i <= m; ++i) {
    int type = read<int>(), l = read<int>(), r = read<int>();
    if (type == 1) {
      long long x = read<long long>();
      tree.init(x);
      tree.change(1, 1, n, l, r, x);
    } else {
      printf("%lld\n", tree.query(1, 1, n, l, r) % mod);
    }
  }
}
