#include <bits/stdc++.h>
using namespace std;
template <typename base_type, base_type _MOD>
struct IntMod {
  static const int INVERSE_CACHE_SIZE = (1 << 20);
  static base_type MOD;
  static void set_mod(base_type new_mod) { MOD = new_mod; }
  base_type n;
  IntMod(long long d = 0) { n = (d >= 0 ? d % MOD : (d % MOD + MOD) % MOD); }
  virtual ~IntMod() = default;
  IntMod operator-() const { return build(n == 0 ? 0 : MOD - n); }
  IntMod& operator+=(IntMod a) {
    n = (n >= MOD - a.n ? n - MOD + a.n : n + a.n);
    return *this;
  }
  IntMod& operator-=(IntMod a) {
    n = (n >= a.n) ? n - a.n : n - a.n + MOD;
    return *this;
  }
  IntMod& operator*=(IntMod a) {
    *this = *this * a;
    return *this;
  }
  IntMod& operator/=(IntMod a) {
    *this = *this / a;
    return *this;
  }
  static IntMod build(base_type n) {
    IntMod L;
    L.n = n;
    return L;
  }
  static base_type inverse_cache[INVERSE_CACHE_SIZE];
  static bool inverse_cache_ready;
  friend IntMod inverse(IntMod n) { return build(inverse_internal(n.n)); }
  static base_type inverse_internal(base_type n) {
    if (!inverse_cache_ready) {
      inverse_cache_ready = true;
      inverse_cache[0] = 0;
      inverse_cache[1] = 1;
      for (int n = 2; n < INVERSE_CACHE_SIZE; ++n)
        inverse_cache[n] =
            (MOD -
             (base_type)((long long)inverse_cache[MOD % n] * (MOD / n) % MOD));
    }
    return n < INVERSE_CACHE_SIZE
               ? inverse_cache[n]
               : MOD - (base_type)((long long)inverse_internal(MOD % n) *
                                   (MOD / n) % MOD);
  }
  friend bool operator==(IntMod a, IntMod b) { return a.n == b.n; }
  friend bool operator!=(IntMod a, IntMod b) { return a.n != b.n; }
  friend IntMod operator+(IntMod a, IntMod b) {
    return build(a.n >= MOD - b.n ? a.n - MOD + b.n : a.n + b.n);
  }
  friend IntMod operator-(IntMod a, IntMod b) {
    return build(a.n >= b.n ? a.n - b.n : a.n - b.n + MOD);
  }
  friend IntMod operator*(IntMod a, IntMod b) {
    return build(
        static_cast<base_type>(static_cast<long long>(a.n) * b.n % MOD));
  }
  friend IntMod operator/(IntMod a, IntMod b) { return a * inverse(b); }
  friend IntMod xpow(IntMod p, long long e) {
    if (e <= 0) return IntMod(1);
    IntMod L = IntMod(1);
    while (e) {
      if (e & 1) L *= p;
      p *= p;
      e >>= 1;
    }
    return L;
  }
  friend ostream& operator<<(ostream& os, const IntMod& p) {
    os << p.n;
    return os;
  }
  friend istream& operator>>(istream& is, IntMod& p) {
    is >> p.n;
    return is;
  }
};
template <typename base_type, base_type _MOD>
base_type IntMod<base_type, _MOD>::inverse_cache[INVERSE_CACHE_SIZE];
template <typename base_type, base_type _MOD>
bool IntMod<base_type, _MOD>::inverse_cache_ready;
template <typename base_type, base_type _MOD>
base_type IntMod<base_type, _MOD>::MOD = _MOD;
template <typename T, typename U>
ostream& operator<<(ostream& os, const pair<T, U>& p) {
  os << p.first << " " << p.second << endl;
  return os;
}
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& vec) {
  for (const auto& v : vec) os << v << ' ';
  return os;
}
long long SQRT(long long x) {
  long long ret = sqrt(x) + 5;
  while (1) {
    if (ret * ret <= x) break;
    ret--;
  }
  return ret;
}
const int maxm = 1e5 + 5;
const int maxn = 2;
const long long MOD = 1e9 + 7;
using Int = IntMod<int, MOD>;
struct Matrix {
  Int m[maxn][maxn];
  bool empty() {
    for (int i = 0; i < maxn; i++)
      for (int j = 0; j < maxn; j++)
        if (m[i][j] != (i == j)) return false;
    return true;
  }
  void clear() {
    for (int i = 0; i < maxn; i++)
      for (int j = 0; j < maxn; j++) m[i][j] = (i == j);
  }
  friend Matrix operator*(const Matrix& a, const Matrix& b) {
    Matrix c;
    for (int i = 0; i < maxn; i++)
      for (int j = 0; j < maxn; j++) c.m[i][j] = 0;
    for (int i = 0; i < maxn; i++)
      for (int j = 0; j < maxn; j++)
        for (int k = 0; k < maxn; k++) c.m[i][j] += a.m[i][k] * b.m[k][j];
    return c;
  }
  friend Matrix pow(Matrix a, long long n) {
    Matrix res;
    for (int i = 0; i < maxn; i++)
      for (int j = 0; j < maxn; j++) res.m[i][j] = (i == j);
    while (n) {
      if (n & 1) res = res * a;
      n >>= 1;
      a = a * a;
    }
    return res;
  }
} bs4, E;
struct Vector {
  Int m[maxn];
  void clear() {
    for (int i = 0; i < maxn; i++) m[i] = 0;
  }
  friend Vector operator*(const Vector& a, const Matrix& b) {
    Vector c;
    c.clear();
    for (int i = 0; i < maxn; i++)
      for (int j = 0; j < maxn; j++) c.m[i] += a.m[j] * b.m[i][j];
    return c;
  }
  friend Vector operator+(const Vector& a, const Vector& b) {
    Vector c;
    for (int i = 0; i < maxn; i++) c.m[i] = a.m[i] + b.m[i];
    return c;
  }
} I;
Int calc(int idx) {
  if (idx <= 1)
    return 1;
  else {
    Matrix p = pow(bs4, idx - 2);
    return p.m[1][0] + p.m[1][1];
  }
}
struct node {
  Vector val;
  Matrix lazy;
  int l, r;
} tree[maxm * 8];
void push_down(int root) {
  if (!tree[root].lazy.empty()) {
    tree[root * 2 + 1].val = tree[root * 2 + 1].val * tree[root].lazy;
    tree[root * 2 + 2].val = tree[root * 2 + 2].val * tree[root].lazy;
    tree[root * 2 + 1].lazy = tree[root * 2 + 1].lazy * tree[root].lazy;
    tree[root * 2 + 2].lazy = tree[root * 2 + 2].lazy * tree[root].lazy;
    tree[root].lazy.clear();
  }
}
void push_up(int root) {
  tree[root].val = tree[root * 2 + 1].val + tree[root * 2 + 2].val;
}
void build(int root, int l, int r) {
  tree[root].l = l;
  tree[root].r = r;
  tree[root].lazy.clear();
  if (l == r) {
    int x;
    scanf("%d", &x);
    tree[root].val.m[0] = calc(x);
    tree[root].val.m[1] = calc(x + 1);
    return;
  }
  int mid = (l + r) / 2;
  build(root * 2 + 1, l, mid);
  build(root * 2 + 2, mid + 1, r);
  push_up(root);
}
void change(int root, int l, int r, const Matrix& val) {
  int op = tree[root].l;
  int ed = tree[root].r;
  if (op > ed) return;
  push_down(root);
  if (op == l && ed == r) {
    tree[root].val = tree[root].val * val;
    tree[root].lazy = tree[root].lazy * val;
    return;
  }
  int mid = (op + ed) / 2;
  if (r <= mid)
    change(root * 2 + 1, l, r, val);
  else if (l > mid)
    change(root * 2 + 2, l, r, val);
  else {
    change(root * 2 + 1, l, mid, val);
    change(root * 2 + 2, mid + 1, r, val);
  }
  push_up(root);
}
Vector sum(int root, int l, int r) {
  int op = tree[root].l;
  int ed = tree[root].r;
  if (op > ed) return I;
  push_down(root);
  if (op == l && ed == r) return tree[root].val;
  int mid = (op + ed) / 2;
  if (r <= mid)
    return sum(root * 2 + 1, l, r);
  else if (l > mid)
    return sum(root * 2 + 2, l, r);
  return sum(root * 2 + 1, l, mid) + sum(root * 2 + 2, mid + 1, r);
}
int main() {
  bs4.m[0][0] = 0;
  bs4.m[0][1] = 1;
  bs4.m[1][0] = 1;
  bs4.m[1][1] = 1;
  E.clear();
  I.clear();
  int n, q, op, l, r, val;
  scanf("%d%d", &n, &q);
  build(0, 1, n);
  while (q--) {
    scanf("%d%d%d", &op, &l, &r);
    if (op == 1) {
      scanf("%d", &val);
      change(0, l, r, pow(bs4, val));
    } else
      printf("%d\n", sum(0, l, r).m[0].n);
  }
  return 0;
}
