#include <bits/stdc++.h>
using namespace std;
template <typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& a) {
  in >> a.first >> a.second;
  return in;
}
template <typename T1, typename T2>
ostream& operator<<(ostream& out, pair<T1, T2> a) {
  out << a.first << " " << a.second;
  return out;
}
template <typename T, typename T1>
T maxs(T& a, T1 b) {
  if (b > a) a = b;
  return a;
}
template <typename T, typename T1>
T mins(T& a, T1 b) {
  if (b < a) a = b;
  return a;
}
template <long long mod>
struct mint {
  long long first;
  mint() : first(0) {}
  mint(long long first) : first((first % mod + mod) % mod) {}
  mint& fix() {
    first = (first % mod + mod) % mod;
    return *this;
  }
  mint operator-() const { return mint(0) - *this; }
  mint& operator+=(const mint& a) {
    if ((first += a.first) >= mod) first -= mod;
    return *this;
  }
  mint& operator-=(const mint& a) {
    if ((first += mod - a.first) >= mod) first -= mod;
    return *this;
  }
  mint& operator*=(const mint& a) {
    (first *= a.first) %= mod;
    return *this;
  }
  mint operator+(const mint& a) const { return mint(*this) += a; }
  mint operator-(const mint& a) const { return mint(*this) -= a; }
  mint operator*(const mint& a) const { return mint(*this) *= a; }
  bool operator<(const mint& a) const { return first < a.first; }
  bool operator==(const mint& a) const { return first == a.first; }
  friend istream& operator>>(istream& i, mint& a) {
    i >> a.first;
    return i;
  }
  friend ostream& operator<<(ostream& o, const mint& a) {
    o << a.first;
    return o;
  }
  mint<mod> expo(mint<mod> first, long long second) {
    mint<mod> a = 1;
    while (second) {
      if (second & 1) a = a * first;
      first = first * first;
      second /= 2;
    }
    return a;
  }
};
template <long long mod>
long long operator+=(long long& b, mint<mod> a) {
  return b = b + a.first;
};
template <typename T>
struct matrix {
 public:
  T val[2][2];
  long long n;
  matrix<T>(long long size = 2) { n = size; }
  matrix<T> operator+(const matrix<T>&) const;
  matrix<T> operator-(const matrix<T>&) const;
  matrix<T>& operator=(const matrix<T>& b) {
    for (long long i = 0; i < 2; i++) {
      for (long long j = 0; j < 2; j++) val[i][j] = b.val[i][j];
    }
    n = b.n;
    return *this;
  }
  void set(long long first) {
    for (long long i = 0; i < n; i++) {
      for (long long j = 0; j < n; j++) {
        val[i][j] = first;
      }
    }
  }
  void print() {
    for (long long i = 0; i < n; i++) {
      for (long long j = 0; j < n; j++) {
        cout << val[i][j] << " ";
      }
      cout << "\n";
    }
  }
  matrix<T> mul(T a) {
    matrix<T> ans(this->n);
    for (long long i = 0; i < this->n; i++) {
      for (long long j = 0; j < this->n; j++) {
        ans.val[i][j] = a * this->val[i][j];
      }
    }
    return ans;
  }
  matrix<T> operator*(const matrix<T>& b) const {
    matrix<T> ans(b.n);
    for (long long i = 0; i < b.n; i++) {
      for (long long j = 0; j < b.n; j++) {
        for (long long k = 0; k < b.n; k++) {
          ans.val[i][j] += this->val[i][k] * b.val[k][j];
        }
      }
    }
    return ans;
  }
  matrix<T> identity(long long N) {
    matrix<T> ans(N);
    for (long long i = 0; i < N; i++) {
      ans.val[i][i] = 1;
    }
    return ans;
  }
  matrix<T> matexpo(matrix<T> a, long long n) {
    if (n == 0) {
      return identity(a.n);
    }
    if (n == 1) return a;
    matrix<T> first = matexpo(a, n / 2);
    matrix<T> r = first * first;
    if (n & 1) r = r * a;
    return r;
  }
};
matrix<mint<1000000007>> m(2);
mint<1000000007> fib(long long n) {
  if (n == 1 || n == 2) return 1;
  m.set(1);
  m.val[1][1] = 0;
  m = m.matexpo(m, n - 2);
  return m.val[0][0] + m.val[0][1];
}
const long long N = 100005;
struct node {
  mint<1000000007> a = 0;
  mint<1000000007> b = 0;
  node(long long val = 0) {}
  void merge(node& n1, node& n2) {
    this->a = n1.a + n2.a;
    this->b = n1.b + n2.b;
  }
};
struct update {
  long long val = 0;
  matrix<mint<1000000007>> mat;
  update(long long t = 0) { val = t; }
  void combine(update& par, long long tl, long long tr) { mat = mat * par.mat; }
  void apply(node& node) {
    mint<1000000007> t1 = node.b, t2 = node.a;
    node.b = mat.val[0][0] * t1 + mat.val[0][1] * t2;
    node.a = mat.val[1][0] * t1 + mat.val[1][1] * t2;
    mat = mat.identity(2);
  }
};
template <typename node, typename update>
struct segtree {
  node t[4 * N];
  bool lazy[4 * N];
  update zaker[4 * N];
  long long tl[4 * N];
  long long tr[4 * N];
  node nul;
  inline void pushdown(long long v) {
    if (lazy[v]) {
      apply(zaker[v], v);
      lazy[v] = 0;
      zaker[v].apply(t[v]);
    }
  }
  inline void apply(update& u, long long v) {
    if (tl[v] != tr[v]) {
      lazy[2 * v] = lazy[2 * v + 1] = 1;
      zaker[2 * v].combine(u, tl[2 * v], tr[2 * v]);
      zaker[2 * v + 1].combine(u, tl[2 * v + 1], tr[2 * v + 1]);
    }
  }
  void build(long long v, long long start, long long end, long long arr[]) {
    tl[v] = start;
    tr[v] = end;
    zaker[v].mat = zaker[v].mat.identity(2);
    if (start == end) {
      t[v].a = fib(arr[start]);
      t[v].b = fib(arr[start] + 1);
    } else {
      long long m = (start + end) / 2;
      build(2 * v, start, m, arr);
      build(2 * v + 1, m + 1, end, arr);
      t[v].merge(t[2 * v], t[2 * v + 1]);
    }
  }
  void zeno(long long v, long long l, long long r, update val) {
    pushdown(v);
    if (tr[v] < l || tl[v] > r) return;
    if (l <= tl[v] && tr[v] <= r) {
      zaker[v].combine(val, tl[v], tr[v]);
      zaker[v].apply(t[v]);
      apply(val, v);
      return;
    }
    zeno(2 * v, l, r, val);
    zeno(2 * v + 1, l, r, val);
    t[v].merge(t[2 * v], t[2 * v + 1]);
  }
  node query(long long v, long long l, long long r) {
    if (tr[v] < l || tl[v] > r) return nul;
    pushdown(v);
    if (l <= tl[v] && tr[v] <= r) {
      return t[v];
    }
    node a = query(2 * v, l, r);
    node b = query(2 * v + 1, l, r);
    node ans;
    ans.merge(a, b);
    return ans;
  }

 public:
  node query(long long l, long long r) { return query(1, l, r); }
  void upd(long long l, long long r, update val) { return zeno(1, l, r, val); }
};
long long a[N];
segtree<node, update> seg;
long long solve() {
  long long n, m;
  cin >> n >> m;
  for (long long i = 1; i < n + 1; i++) cin >> a[i];
  seg.build(1, 1, n, a);
  for (long long i = 0; i < m; i++) {
    long long t;
    cin >> t;
    if (t == 1) {
      long long l, r, first;
      cin >> l >> r >> first;
      matrix<mint<1000000007>> mat(2);
      mat.set(1);
      mat.val[1][1] = 0;
      mat = mat.matexpo(mat, first);
      update upd;
      upd.mat = mat;
      seg.upd(l, r, upd);
    } else {
      long long l, r;
      cin >> l >> r;
      cout << seg.query(l, r).a << "\n";
    }
  }
  return 0;
}
signed main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  long long t = 1;
  while (t--) {
    solve();
  }
  return 0;
}
