#include <bits/stdc++.h>
using namespace std;
int m;
struct matr {
  long long m[2][2];
};
matr operator*(matr a, matr b) {
  matr res;
  for (int i = 0; i < 2; i++)
    for (int j = 0; j < 2; j++) {
      res.m[i][j] = 0;
      for (int k = 0; k < 2; k++) {
        res.m[i][j] = (res.m[i][j] + a.m[i][k] * b.m[k][j]) % 1000000007;
      }
    }
  return res;
}
matr operator+(matr a, matr b) {
  matr res;
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
      res.m[i][j] = 0;
      res.m[i][j] = (a.m[i][j] + b.m[i][j]) % 1000000007;
    }
  }
  return res;
}
matr power(matr m, long long p) {
  if (p == 1) return m;
  if (p % 2) return m * power(m, p - 1);
  return power(m * m, p / 2);
}
matr fib(long long num) {
  matr f;
  f.m[0][0] = 0;
  f.m[0][1] = f.m[1][0] = f.m[1][1] = 1;
  f = power(f, num);
  return f;
}
matr tree[400007];
matr A[100007];
matr lazy[400007];
void bt(int node, int a, int b) {
  if (a > b) {
    return;
  }
  if (a == b) {
    tree[node] = A[a];
    return;
  }
  bt(2 * node, a, (a + b) / 2);
  bt(2 * node + 1, 1 + (a + b) / 2, b);
  tree[node] = tree[2 * node] + tree[2 * node + 1];
}
bool emp(matr a) {
  int cnt = 0;
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
      if (a.m[i][j] == 0) {
        cnt++;
      }
    }
  }
  if (cnt == 4) {
    return 1;
  }
  return 0;
}
void update(int node, int a, int b, int i, int j, matr val) {
  if (!emp(lazy[node])) {
    tree[node] = tree[node] * lazy[node];
    if (a != b) {
      lazy[2 * node] = lazy[2 * node] * lazy[node];
      lazy[2 * node + 1] = lazy[2 * node + 1] * lazy[node];
    }
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        if (i == j) {
          lazy[node].m[i][j] = 1;
        } else {
          lazy[node].m[i][j] = 0;
        }
      }
    }
  }
  if (a > b || a > j || b < i) {
    return;
  }
  if (a >= i && b <= j) {
    tree[node] = tree[node] * val;
    if (a != b) {
      lazy[node * 2] = lazy[2 * node] * val;
      lazy[node * 2 + 1] = lazy[2 * node + 1] * val;
    }
    return;
  }
  update(node * 2, a, (a + b) / 2, i, j, val);
  update(1 + node * 2, 1 + (a + b) / 2, b, i, j, val);
  tree[node] = (tree[node * 2] + tree[node * 2 + 1]);
}
long long query_tree(int node, int a, int b, int i, int j) {
  if (a > b || a > j || b < i) return 0;
  if (!emp(lazy[node])) {
    tree[node] = tree[node] * lazy[node];
    if (a != b) {
      lazy[2 * node] = lazy[2 * node] * lazy[node];
      lazy[2 * node + 1] = lazy[2 * node + 1] * lazy[node];
    }
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        if (i == j) {
          lazy[node].m[i][j] = 1;
        } else {
          lazy[node].m[i][j] = 0;
        }
      }
    }
  }
  if (a >= i && b <= j) return tree[node].m[0][1];
  long long q1 = query_tree(node * 2, a, (a + b) / 2, i, j);
  long long q2 = query_tree(1 + node * 2, 1 + (a + b) / 2, b, i, j);
  long long res = q1 + q2;
  res %= 1000000007;
  return res;
}
int main() {
  for (int i = 0; i < 400007; i++) {
    for (int j = 0; j < 2; j++) {
      for (int k = 0; k < 2; k++) {
        if (j == k) {
          lazy[i].m[j][k] = 1;
        } else {
          lazy[i].m[j][k] = 0;
        }
      }
    }
  }
  int n, m;
  scanf("%d", &n);
  scanf("%d", &m);
  for (int i = 0; i < n; i++) {
    long long k;
    scanf("%lld", &k);
    A[i] = fib(k);
  }
  bt(1, 0, n - 1);
  while (m--) {
    int tp;
    scanf("%d", &tp);
    if (tp == 1) {
      int l, r, x;
      scanf("%d", &l);
      scanf("%d", &r);
      scanf("%d", &x);
      l--;
      r--;
      matr t = fib(x);
      update(1, 0, n - 1, l, r, t);
    } else {
      int l, r;
      scanf("%d", &l);
      scanf("%d", &r);
      l--;
      r--;
      long long ans = query_tree(1, 0, n - 1, l, r);
      ans %= 1000000007;
      printf("%lld\n", ans);
    }
  }
}
