import java.util.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class SashaAndNames{

    static class FastReader
    {
        BufferedReader br;
        StringTokenizer st;

        public FastReader()
        {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next()
        {
            while (st == null || !st.hasMoreElements())
            {
                try
                {
                    st = new StringTokenizer(br.readLine());
                }
                catch (IOException  e)
                {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt()
        {
            return Integer.parseInt(next());
        }

        long nextLong()
        {
            return Long.parseLong(next());
        }

        double nextDouble()
        {
            return Double.parseDouble(next());
        }

        String nextLine()
        {
            String str = "";
            try
            {
                str = br.readLine();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return str;
        }
    }
    public static void main(String[] args){
        FastReader s = new FastReader();
        String str = s.next();
        HashSet<Character> set = new HashSet<>();
        for(char ch : str.toCharArray()){
            set.add(ch);
        }
        if(set.size()==1 || str.length()==1){
            System.out.println("Impossible");
            return;
        }
        for(int i = 0;i<str.length()-1;i++){
            String temp = str.substring(i+1, str.length()) + str.substring(0, i+1);
            boolean ok = true;
            for(int c = 0;c<temp.length();c++){
                if(temp.charAt(c) != temp.charAt(temp.length()-c-1)){
                    ok = false;
                    break;
                }
            }

            if(ok && !temp.equals(str)){
                System.out.println("1");
                return;
            }

        }
        System.out.println("2");
    }

}


import java.util.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class SashaAndNames{

    static class FastReader
    {
        BufferedReader br;
        StringTokenizer st;

        public FastReader()
        {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next()
        {
            while (st == null || !st.hasMoreElements())
            {
                try
                {
                    st = new StringTokenizer(br.readLine());
                }
                catch (IOException  e)
                {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt()
        {
            return Integer.parseInt(next());
        }

        long nextLong()
        {
            return Long.parseLong(next());
        }

        double nextDouble()
        {
            return Double.parseDouble(next());
        }

        String nextLine()
        {
            String str = "";
            try
            {
                str = br.readLine();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return str;
        }
    }
    public static void main(String[] args){
        FastReader s = new FastReader();
        String str = s.next();
        HashSet<Character> set = new HashSet<>();
        for(char ch : str.toCharArray()){
            set.add(ch);
        }
        if(set.size()==1){
            System.out.println("Impossible");
            return;
        }
        for(int i = 0;i<str.length()-1;i++){
            String temp = str.substring(i+1, str.length()) + str.substring(0, i+1);
            boolean ok = true;
            for(int c = 0;c<temp.length();c++){
                if(temp.charAt(c) != temp.charAt(temp.length()-c-1)){
                    ok = false;
                    break;
                }
            }
            if(ok && temp!=str){
                System.out.println("1");
                return;
            }

        }
        System.out.println("2");
    }

}


import java.util.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class SashaAndNames{

    static class FastReader
    {
        BufferedReader br;
        StringTokenizer st;

        public FastReader()
        {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next()
        {
            while (st == null || !st.hasMoreElements())
            {
                try
                {
                    st = new StringTokenizer(br.readLine());
                }
                catch (IOException  e)
                {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt()
        {
            return Integer.parseInt(next());
        }

        long nextLong()
        {
            return Long.parseLong(next());
        }

        double nextDouble()
        {
            return Double.parseDouble(next());
        }

        String nextLine()
        {
            String str = "";
            try
            {
                str = br.readLine();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return str;
        }
    }
    public static void main(String[] args){
        FastReader s = new FastReader();
        String str = s.next();
        HashSet<Character> set = new HashSet<>();
        for(int i = 0;i<=str.length()/2;i++){
            set.add(str.charAt(i));
        }
        if(set.size()==1){
            System.out.println("Impossible");
            return;
        }
        for(int i = 0;i<str.length()-1;i++){
            String temp = str.substring(i+1, str.length()) + str.substring(0, i+1);
            boolean ok = true;
            for(int c = 0;c<temp.length();c++){
                if(temp.charAt(c) != temp.charAt(temp.length()-c-1)){
                    ok = false;
                    break;
                }
            }
            if(ok && !temp.equals(str)){
                System.out.println("1");
                return;
            }

        }
        System.out.println("2");
    }

}


import java.util.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class SashaAndNames{

    static class FastReader
    {
        BufferedReader br;
        StringTokenizer st;

        public FastReader()
        {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next()
        {
            while (st == null || !st.hasMoreElements())
            {
                try
                {
                    st = new StringTokenizer(br.readLine());
                }
                catch (IOException  e)
                {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt()
        {
            return Integer.parseInt(next());
        }

        long nextLong()
        {
            return Long.parseLong(next());
        }

        double nextDouble()
        {
            return Double.parseDouble(next());
        }

        String nextLine()
        {
            String str = "";
            try
            {
                str = br.readLine();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return str;
        }
    }
    public static void main(String[] args){
        FastReader s = new FastReader();
        String str = s.next();
        HashSet<Character> set = new HashSet<>();
        for(int i = 0;i<str.length()/2;i++){
            set.add(str.charAt(i));
        }
        if(set.size()==1){
            System.out.println("Impossible");
            return;
        }
        for(int i = 0;i<str.length()-1;i++){
            String temp = str.substring(i+1, str.length()) + str.substring(0, i+1);
            boolean ok = true;
            for(int c = 0;c<temp.length();c++){
                if(temp.charAt(c) != temp.charAt(temp.length()-c-1)){
                    ok = false;
                    break;
                }
            }
            if(ok && !temp.equals(str)){
                System.out.println("1");
                return;
            }

        }
        System.out.println("2");
    }

}


import java.util.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class SashaAndNames{

    static class FastReader
    {
        BufferedReader br;
        StringTokenizer st;

        public FastReader()
        {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next()
        {
            while (st == null || !st.hasMoreElements())
            {
                try
                {
                    st = new StringTokenizer(br.readLine());
                }
                catch (IOException  e)
                {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt()
        {
            return Integer.parseInt(next());
        }

        long nextLong()
        {
            return Long.parseLong(next());
        }

        double nextDouble()
        {
            return Double.parseDouble(next());
        }

        String nextLine()
        {
            String str = "";
            try
            {
                str = br.readLine();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return str;
        }
    }
    public static void main(String[] args){
        FastReader s = new FastReader();
        String str = s.next();
        HashSet<Character> set = new HashSet<>();
        for(char ch : str.toCharArray()){
            set.add(ch);
        }
        if(set.size()==1 || str.length()==1){
            System.out.println("Impossible");
            return;
        }
        for(int i = 0;i<str.length()-1;i++){
            String temp = str.substring(i+1, str.length()) + str.substring(0, i+1);
            boolean ok = true;
            for(int c = 0;c<temp.length();c++){
                if(temp.charAt(c) != temp.charAt(temp.length()-c-1)){
                    ok = false;
                    break;
                }
            }
            if(ok && temp!=str){
                System.out.println("1");
                return;
            }

        }
        System.out.println("2");
    }

}


import java.util.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class SashaAndNames{

    static class FastReader
    {
        BufferedReader br;
        StringTokenizer st;

        public FastReader()
        {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next()
        {
            while (st == null || !st.hasMoreElements())
            {
                try
                {
                    st = new StringTokenizer(br.readLine());
                }
                catch (IOException  e)
                {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt()
        {
            return Integer.parseInt(next());
        }

        long nextLong()
        {
            return Long.parseLong(next());
        }

        double nextDouble()
        {
            return Double.parseDouble(next());
        }

        String nextLine()
        {
            String str = "";
            try
            {
                str = br.readLine();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return str;
        }
    }
    public static void main(String[] args){
        FastReader s = new FastReader();
        String str = s.next();
        HashSet<Character> set = new HashSet<>();
        for(int i = 0;i<str.length()/2;i++){
            set.add(str.charAt(i));
        }
        if(set.size()==1 || str.length()==1){
            System.out.println("Impossible");
            return;
        }
        for(int i = 0;i<str.length()-1;i++){
            String temp = str.substring(i+1, str.length()) + str.substring(0, i+1);
            boolean ok = true;
            for(int c = 0;c<temp.length();c++){
                if(temp.charAt(c) != temp.charAt(temp.length()-c-1)){
                    ok = false;
                    break;
                }
            }
            if(ok && !temp.equals(str)){
                System.out.println("1");
                return;
            }

        }
        System.out.println("2");
    }

}


#include<bits/stdc++.h>
#include <math.h>
using namespace std;

#define mod 1000000007
#define MAX 2010
#define ll long long
#define slld(t) scanf("%lld",&t)
#define sd(t) scanf("%d",&t)
#define sld(t) scanf("%ld",&t)
#define pd(t) printf("%d\n",t)
#define plld(t) printf("%lld\n",t)
#define pcc pair<char,char>
#define pp pair<int,int>
#define pll pair<ll,ll>
#define tr(container,it) for(typeof(container.begin()) it=container.begin();it!=container.end();it++)
#define mp(a,b) make_pair(a,b)
#define F first
#define S second
#define pb(x) push_back(x)
int m;
struct matr {
         ll 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]) % mod;
                        }
                }
        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]) % mod;
		}
	}
	return res;
}

matr power(matr m, ll p) {
        if (p == 1)
                return m;
        if (p % 2)
                return m * power(m, p - 1);
        return power(m * m, p / 2);
}

matr fib(ll 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) { // Segment is fully within range
    		tree[node] = tree[node] +  val;

		if(a != b) { // Not leaf node
			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); // Updating left child
	update(1+node*2, 1+(a+b)/2, b, i, j, val); // Updating right child

	tree[node] = (tree[node*2] + tree[node*2+1]);
}

ll 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) // Current segment is totally within range [i, j]
		return tree[node].m[0][1];

	ll q1 = query_tree(node*2, a, (a+b)/2, i, j); // Query left child
	ll q2 = query_tree(1+node*2, 1+(a+b)/2, b, i, j); // Query right child

	ll res = q1 + q2;
	res %= mod;

	return res;
}

int main()
{
	//cout<<fib(3LL)<<endl;
	int n,m;
	sd(n); sd(m);

	for( int i=0;i<n; i++)
	{
		ll k;
		slld(k);
		A[i] = fib(k);
	}
	bt(1,0,n-1);
	while(m--)
	{
		int tp;
		sd(tp);
		if(tp==1)
		{
			int l,r,x;
			sd(l); sd(r); sd(x);
			l--; r--;
			matr t = fib(x);
			update(1,0,n-1,l,r,t);
		}
		else
		{
			int l,r;
			sd(l); sd(r);
			l--; r--;
			ll ans = query_tree(1,0,n-1,l,r);
			ans %= mod;
			plld(ans);
		}
	}
}


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define MAXN (100000 + 5)
#define MOD  (1000000007)

struct MATRIX {
	int m[2][2];
	MATRIX() {
		m[0][0] = 1; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = 1;
	}
	MATRIX(int v) {
		m[0][0] = v; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = v;
	}
};

MATRIX mul(MATRIX a, MATRIX b) {
	MATRIX res;

	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = 0;
			for (int v=0; v<2; v++) {
				res.m[i][j] = (0LL + res.m[i][j] + a.m[i][v] * b.m[v][j]) % MOD;
			}
		}
	}
	return res;
}

MATRIX add (MATRIX a, MATRIX b) {
	MATRIX res(0);
	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = (0LL + res.m[i][j] + a.m[i][j] + b.m[i][j]) % MOD;
		}
	}
	return res;
}

MATRIX power(MATRIX p, int n) {
	MATRIX res;
	while (n) {
		if (n & 1) res = mul(res, p);
		p = mul(p, p);
		n>>=1;
	}
	return res;
}

MATRIX power(int n) {
	MATRIX p;
	p.m[0][0] = 1;
	p.m[0][1] = 1;
	p.m[1][0] = 1;
	p.m[1][1] = 0;
	return power(p, n);
}

int n, m;
int a[MAXN];

struct SGMENT_TREE {
	MATRIX sg[MAXN << 2];
	int lz[MAXN << 2];
	SGMENT_TREE() {
		memset(sg, 0, sizeof(sg));
		memset(lz, 0, sizeof(lz));
	}

	void push_up(int lr) {
		sg[lr] = add(sg[lr<<1], sg[lr<<1|1]);
	}

	void push_down(int lr) {
		if (lz[lr] != 0) {
			lz[lr<<1] += lz[lr];
			lz[lr<<1|1] += lz[lr];
			sg[lr<<1] = mul(sg[lr<<1], power(lz[lr]));
			sg[lr<<1|1] = mul(sg[lr<<1|1], power(lz[lr]));
			lz[lr] = 0;
		}
	}

	void create(int l, int r, int lr) {
		if (l == r) {
			sg[lr] = power(a[l]);
			return ;
		}
		int m = (l + r) / 2;
		create(l, m, lr<<1);
		create(m+1, r, lr<<1|1);
		push_up(lr);
	}

	void modify(int l, int r, int lr, int L, int R, int p) {
		if (L <= l && r <= R) {
			sg[lr] = mul(sg[lr], power(p));
			lz[lr] += p;
			return ;
		}
		push_down(lr);
		int m = (l + r) / 2;
		if (L <= m) modify(l, m, lr<<1, L, R, p);
		if (m < R) modify(m+1, r, lr<<1|1, L, R, p);
		push_up(lr);
	}

	MATRIX query(int l, int r, int lr, int L, int R) {
		if (L <= l && r <= R) {
			return sg[lr];
		}
		MATRIX res(0);
		push_down(lr);
		int m = (l + r) / 2;
		if (L <= m) res = add(res, query(l, m, lr<<1, L, R));
		if (m < R) res = add(res, query(m+1, r, lr<<1|1, L, R));
		return res;
	}
};

SGMENT_TREE st;

int main () {

	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; i++) {
		scanf ("%d", &a[i]);
	}

	st.create(1, n, 1);

	int op, ll, rr, pp;
	for (int i=0; i<m; i++) {
		scanf("%d", &op);
		if (op == 1) {
			scanf("%d %d %d", &ll, &rr, &pp);
			st.modify(1, n, 1, ll, rr, pp);
		} else {
			scanf("%d%d", &ll, &rr);
			MATRIX ans = st.query(1, n, 1, ll, rr);
			printf("%d\n", ans.m[0][1]);
		}
	}

	return 0;
}


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define MAXN (100000 + 5)
#define MOD  (1000000007)

struct MATRIX {
	int m[2][2];
	MATRIX() {
		m[0][0] = 1; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = 1;
	}
	MATRIX(int v) {
		m[0][0] = v; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = v;
	}
};

MATRIX mul(MATRIX a, MATRIX b) {
	MATRIX res;

	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = 0;
			for (int v=0; v<2; v++) {
				res.m[i][j] = (0LL + res.m[i][j] + a.m[i][v] * b.m[v][j]) % MOD;
			}
		}
	}
	return res;
}

MATRIX add (MATRIX a, MATRIX b) {
	MATRIX res(0);
	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = (0LL + res.m[i][j] + a.m[i][j] + b.m[i][j]) % MOD;
		}
	}
	return res;
}

MATRIX power(MATRIX p, int n) {
	MATRIX res;
	while (n) {
		if (n & 1) res = mul(res, p);
		p = mul(p, p);
		n>>=1;
	}
	return res;
}

MATRIX power(int n) {
	MATRIX p;
	p.m[0][0] = 1;
	p.m[0][1] = 1;
	p.m[1][0] = 1;
	p.m[1][1] = 0;
	return power(p, n);
}

int n, m;
int a[MAXN];

struct SGMENT_TREE {
	MATRIX sg[MAXN << 2];
	int lz[MAXN << 2];
	SGMENT_TREE() {
		memset(sg, 0, sizeof(sg));
		memset(lz, -1, sizeof(lz));
	}

	void push_up(int lr) {
		sg[lr] = add(sg[lr<<1], sg[lr<<1|1]);
	}

	void push_down(int lr) {
		if (lz[lr] != -1) {
			lz[lr<<1] = lz[lr<<1|1] = lz[lr];
			sg[lr<<1] = mul(sg[lr<<1], power(lz[lr]));
			sg[lr<<1|1] = mul(sg[lr<<1|1], power(lz[lr]));
			lz[lr] = -1;
		}
	}

	void create(int l, int r, int lr) {
		if (l == r) {
			sg[lr] = power(a[l]);
			return ;
		}
		int m = (l + r) / 2;
		create(l, m, lr<<1);
		create(m+1, r, lr<<1|1);
		push_up(lr);
	}

	void modify(int l, int r, int lr, int L, int R, int p) {
		if (L <= l && r <=R) {
			sg[lr] = mul(sg[lr], power(p));
			lz[lr] = p;
			return ;
		}
		push_down(lr);
		int m = (l + r) / 2;
		if (L <= m) modify(l, m, lr<<1, L, R, p);
		if (m < R) modify(m+1, r, lr<<1|1, L, R, p);
		push_up(lr);
	}

	MATRIX query(int l, int r, int lr, int L, int R) {
		if (L <= l && r <= R) {
			return sg[lr];
		}
		MATRIX res(0);
		push_down(lr);
		int m = (l + r) / 2;
		if (L <= m) res = add(res, query(l, m, lr<<1, L, R));
		if (m < R) res = add(res, query(m+1, r, lr<<1|1, L, R));
		return res;
	}
};

SGMENT_TREE st;

int main () {

	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; i++) {
		scanf ("%d", &a[i]);
	}

	st.create(1, n, 1);

	int op, ll, rr, pp;
	for (int i=0; i<m; i++) {
		scanf("%d", &op);
		if (op == 1) {
			scanf("%d %d %d", &ll, &rr, &pp);
			st.modify(1, n, 1, ll, rr, pp);
		} else {
			scanf("%d%d", &ll, &rr);
			MATRIX ans = st.query(1, n, 1, ll, rr);
			printf("%d\n", ans.m[0][1]);
		}
	}

	return 0;
}


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define MAXN (100000 + 5)
#define MOD  (1000000007LL)

struct MATRIX {
	int m[2][2];
	MATRIX() {
		m[0][0] = 1; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = 1;
	}
	MATRIX(int v) {
		m[0][0] = v; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = v;
	}
};

MATRIX mul(MATRIX a, MATRIX b) {
	MATRIX res;

	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = 0;
			for (int v=0; v<2; v++) {
				res.m[i][j] = (1LL * res.m[i][j] + 1LL * a.m[i][v] * b.m[v][j]) % MOD;
			}
		}
	}
	return res;
}

MATRIX add (MATRIX a, MATRIX b) {
	MATRIX res(0);
	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = (1LL * res.m[i][j] + 1LL * a.m[i][j] + 1LL * b.m[i][j]) % MOD;
		}
	}
	return res;
}

MATRIX power(MATRIX p, long long n) {
	MATRIX res;
	while (n) {
		if (n & 1) res = mul(res, p);
		p = mul(p, p);
		n>>=1;
	}
	return res;
}

MATRIX power(long long n) {
	MATRIX p;
	p.m[0][0] = 1;
	p.m[0][1] = 1;
	p.m[1][0] = 1;
	p.m[1][1] = 0;
	return power(p, n);
}

int n, m;
int a[MAXN];
MATRIX IZERO(0);

struct SGMENT_TREE {
	MATRIX sg[MAXN << 2];
	// long long lz[MAXN << 2];
	MATRIX lz[MAXN << 2];

	SGMENT_TREE() {
		memset(sg, 0, sizeof(sg));
		memset(lz, 0, sizeof(lz));
	}

	void push_up(int lr) {
		sg[lr] = add(sg[lr<<1], sg[lr<<1|1]);
	}

	bool check (MATRIX a) {
		for (int i=0; i<2; i++) {
			for (int j=0; j<2; j++) {
				if (a.m[i][j] != 0) return true;
			}
		}
		return false;
	}

	void push_down(int lr) {
		if (check(lz[lr])) {
			lz[lr<<1] = mul(lz[lr<<1], lz[lr]);
			lz[lr<<1|1] = mul(lz[lr<<1|1], lz[lr]);

			sg[lr<<1] = mul(sg[lr<<1], lz[lr]);
			sg[lr<<1|1] = mul(sg[lr<<1|1], lz[lr]);
			lz[lr] = IZERO;
		}
	}

	void create(int l, int r, int lr) {
		if (l == r) {
			sg[lr] = power(a[l]);
			return ;
		}
		int m = (l + r) >> 1;
		create(l, m, lr<<1);
		create(m+1, r, lr<<1|1);
		push_up(lr);
	}

	void modify(int l, int r, int lr, int L, int R, MATRIX p) {
		if (L <= l && r <= R) {
			sg[lr] = mul(sg[lr], p);
			lz[lr] = add(lz[lr], p);
			return ;
		}
		push_down(lr);
		int m = (l + r) >> 1;
		if (L <= m) modify(l, m, lr<<1, L, R, p);
		if (m < R) modify(m+1, r, lr<<1|1, L, R, p);
		push_up(lr);
	}

	MATRIX query(int l, int r, int lr, int L, int R) {
		if (L <= l && r <= R) {
			return sg[lr];
		}
		MATRIX res(0);
		push_down(lr);
		int m = (l + r) >> 1;
		if (L <= m) res = add(res, query(l, m, lr<<1, L, R));
		if (m < R) res = add(res, query(m+1, r, lr<<1|1, L, R));
		return res;

}};

SGMENT_TREE st;

int main () {

	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; i++) {
		scanf ("%d", &a[i]);
	}

	st.create(1, n, 1);

	int op, ll, rr, pp;
	for (int i=0; i<m; i++) {
		scanf("%d", &op);
		if (op == 1) {
			scanf("%d %d %d", &ll, &rr, &pp);
			st.modify(1, n, 1, ll, rr, power(pp));
		} else {
			scanf("%d%d", &ll, &rr);
			MATRIX ans = st.query(1, n, 1, ll, rr);
			printf("%d\n", ans.m[0][1]);
		}

	}

	return 0;
}


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define MAXN (100000 + 5)
#define MOD  (1000000007)

struct MATRIX {
	int m[2][2];
	MATRIX() {
		m[0][0] = 1; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = 1;
	}
	MATRIX(int v) {
		m[0][0] = v; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = v;
	}
};

MATRIX mul(MATRIX a, MATRIX b) {
	MATRIX res;

	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = 0;
			for (int v=0; v<2; v++) {
				res.m[i][j] = (0LL + res.m[i][j] + a.m[i][v] * b.m[v][j]) % MOD;
			}
		}
	}
	return res;
}

MATRIX add (MATRIX a, MATRIX b) {
	MATRIX res(0);
	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = a.m[i][j] + b.m[i][j];
		}
	}
	return res;
}

MATRIX power(MATRIX p, int n) {
	MATRIX res;
	while (n) {
		if (n & 1) res = mul(res, p);
		p = mul(p, p);
		n>>=1;
	}
	return res;
}

MATRIX power(int n) {
	MATRIX p;
	p.m[0][0] = 1;
	p.m[0][1] = 1;
	p.m[1][0] = 1;
	p.m[1][1] = 0;
	return power(p, n);
}

int n, m;
int a[MAXN];

struct SGMENT_TREE {
	MATRIX sg[MAXN << 2];
	int lz[MAXN << 2];
	SGMENT_TREE() {
		memset(sg, 0, sizeof(sg));
		memset(lz, -1, sizeof(lz));
	}

	void push_up(int lr) {
		sg[lr] = add(sg[lr<<1], sg[lr<<1|1]);
	}

	void push_down(int lr) {
		if (lz[lr] != -1) {
			lz[lr<<1] = lz[lr<<1|1] = lz[lr];
			sg[lr<<1] = mul(sg[lr<<1], power(lz[lr]));
			sg[lr<<1|1] = mul(sg[lr<<1|1], power(lz[lr]));
			lz[lr] = -1;
		}
	}

	void create(int l, int r, int lr) {
		if (l == r) {
			sg[lr] = power(a[l]);
			return ;
		}
		int m = (l + r) / 2;
		create(l, m, lr<<1);
		create(m+1, r, lr<<1|1);
		push_up(lr);
	}

	void modify(int l, int r, int lr, int L, int R, int p) {
		if (L <= l && r <=R) {
			sg[lr] = mul(sg[lr], power(p));
			return ;
		}
		push_down(lr);
		int m = (l + r) / 2;
		if (L <= m) modify(l, m, lr<<1, L, R, p);
		if (m < R) modify(m+1, r, lr<<1|1, L, R, p);
		push_up(lr);
	}

	MATRIX query(int l, int r, int lr, int L, int R) {
		if (L <= l && r <= R) {
			return sg[lr];
		}
		MATRIX res(0);
		push_down(lr);
		int m = (l + r) / 2;
		if (L <= m) res = add(res, query(l, m, lr<<1, L, R));
		if (m < R) res = add(res, query(m+1, r, lr<<1|1, L, R));
		return res;
	}
};

SGMENT_TREE st;

int main () {

	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; i++) {
		scanf ("%d", &a[i]);
	}

	st.create(1, n, 1);

	int op, ll, rr, pp;
	for (int i=0; i<m; i++) {
		scanf("%d", &op);
		if (op == 1) {
			scanf("%d %d %d", &ll, &rr, &pp);
			st.modify(1, n, 1, ll, rr, pp);
		} else {
			scanf("%d%d", &ll, &rr);
			MATRIX ans = st.query(1, n, 1, ll, rr);
			printf("%d\n", ans.m[0][1]);
		}
	}

	return 0;
}


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define MAXN (100000 + 5)
#define MOD  (1000000007LL)

struct MATRIX {
	int m[2][2];
	MATRIX() {
		m[0][0] = 1; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = 1;
	}
	MATRIX(int v) {
		m[0][0] = v; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = v;
	}
	void show () {
		cout << "--------MATRIX-------------------------------" << endl;
		for (int i=0; i<2; i++) {
			for (int j=0; j<2; j++) {
				cout << m[i][j] << " ";
			}
			cout << endl;
		}
	}
};

MATRIX mul(MATRIX a, MATRIX b) {
	MATRIX res;

	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = 0;
			for (int v=0; v<2; v++) {
				res.m[i][j] = (1LL * res.m[i][j] + 1LL * a.m[i][v] * b.m[v][j]) % MOD;
			}
		}
	}
	return res;
}

MATRIX add (MATRIX a, MATRIX b) {
	MATRIX res(0);
	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = (1LL * res.m[i][j] + 1LL * a.m[i][j] + 1LL * b.m[i][j]) % MOD;
		}
	}
	return res;
}

MATRIX power(MATRIX p, long long n) {
	MATRIX res;
	while (n) {
		if (n & 1) res = mul(res, p);
		p = mul(p, p);
		n>>=1;
	}
	return res;
}

MATRIX power(long long n) {
	MATRIX p;
	p.m[0][0] = 1;
	p.m[0][1] = 1;
	p.m[1][0] = 1;
	p.m[1][1] = 0;
	return power(p, n);
}

int n, m;
int a[MAXN];
MATRIX IZERO(1);

struct SGMENT_TREE {
	MATRIX sg[MAXN << 2];
	// long long lz[MAXN << 2];
	MATRIX lz[MAXN << 2];

	SGMENT_TREE() {
		memset(sg, 0, sizeof(sg));
		// memset(lz, 0, sizeof(lz));
	}

	void push_up(int lr) {
		sg[lr] = add(sg[lr<<1], sg[lr<<1|1]);
	}

	bool check (MATRIX a) {
		if (a.m[0][0] == a.m[1][1] && a.m[0][0] == 1 && a.m[0][1] == a.m[1][0] && a.m[0][1] == 0) return false;
		else return true;
	}

	void push_down(int lr) {
		if (check(lz[lr])) {
			lz[lr<<1] = mul(lz[lr<<1], lz[lr]);
			lz[lr<<1|1] = mul(lz[lr<<1|1], lz[lr]);

			sg[lr<<1] = mul(sg[lr<<1], lz[lr]);
			sg[lr<<1|1] = mul(sg[lr<<1|1], lz[lr]);
			lz[lr] = IZERO;
		}
	}

	void create(int l, int r, int lr) {
		if (l == r) {
			sg[lr] = power(a[l]);
			return ;
		}
		int m = (l + r) >> 1;
		create(l, m, lr<<1);
		create(m+1, r, lr<<1|1);
		push_up(lr);
	}

	void modify(int l, int r, int lr, int L, int R, MATRIX p) {
		if (L <= l && r <= R) {
			sg[lr] = mul(sg[lr], p);
			lz[lr] = mul(lz[lr], p);
			return ;
		}
		push_down(lr);
		int m = (l + r) >> 1;
		if (L <= m) modify(l, m, lr<<1, L, R, p);
		if (m < R) modify(m+1, r, lr<<1|1, L, R, p);
		push_up(lr);
	}

	MATRIX query(int l, int r, int lr, int L, int R) {
		if (L <= l && r <= R) {
			return sg[lr];
		}
		MATRIX res(0);
		push_down(lr);
		int m = (l + r) >> 1;
		if (L <= m) res = add(res, query(l, m, lr<<1, L, R));
		if (m < R) res = add(res, query(m+1, r, lr<<1|1, L, R));
		return res;

}};

SGMENT_TREE st;

int main () {

	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; i++) {
		scanf ("%d", &a[i]);
	}

	st.create(1, n, 1);

	int op, ll, rr, pp;
	for (int i=0; i<m; i++) {
		scanf("%d", &op);
		if (op == 1) {
			scanf("%d %d %d", &ll, &rr, &pp);
			st.modify(1, n, 1, ll, rr, power(pp));
		} else {
			scanf("%d%d", &ll, &rr);
			MATRIX ans = st.query(1, n, 1, ll, rr);
			printf("%d\n", ans.m[0][1]);
		}

	}

	return 0;
}


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define MAXN (100000 + 5)
#define MOD  (1000000007LL)

struct MATRIX {
	int m[2][2];
	MATRIX() {
		m[0][0] = 1; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = 1;
	}
	MATRIX(int v) {
		m[0][0] = v; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = v;
	}
};

MATRIX mul(MATRIX a, MATRIX b) {
	MATRIX res;

	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = 0;
			for (int v=0; v<2; v++) {
				res.m[i][j] = (1LL * res.m[i][j] + 1LL * a.m[i][v] * b.m[v][j]) % MOD;
			}
		}
	}
	return res;
}

MATRIX add (MATRIX a, MATRIX b) {
	MATRIX res(0);
	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = (1LL * res.m[i][j] + 1LL * a.m[i][j] + 1LL * b.m[i][j]) % MOD;
		}
	}
	return res;
}

MATRIX power(MATRIX p, int n) {
	MATRIX res;
	while (n) {
		if (n & 1) res = mul(res, p);
		p = mul(p, p);
		n>>=1;
	}
	return res;
}

MATRIX power(int n) {
	MATRIX p;
	p.m[0][0] = 1;
	p.m[0][1] = 1;
	p.m[1][0] = 1;
	p.m[1][1] = 0;
	return power(p, n);
}

int n, m;
int a[MAXN];

struct SGMENT_TREE {
	MATRIX sg[MAXN << 2];
	int lz[MAXN << 2];
	SGMENT_TREE() {
		memset(sg, 0, sizeof(sg));
		memset(lz, 0, sizeof(lz));
	}

	void push_up(int lr) {
		sg[lr] = add(sg[lr<<1], sg[lr<<1|1]);
	}

	void push_down(int lr) {
		if (lz[lr] != 0) {
			lz[lr<<1] += lz[lr];
			lz[lr<<1|1] += lz[lr];
			sg[lr<<1] = mul(sg[lr<<1], power(lz[lr]));
			sg[lr<<1|1] = mul(sg[lr<<1|1], power(lz[lr]));
			lz[lr] = 0;
		}
	}

	void create(int l, int r, int lr) {
		if (l == r) {
			sg[lr] = power(a[l]);
			return ;
		}
		int m = (l + r) / 2;
		create(l, m, lr<<1);
		create(m+1, r, lr<<1|1);
		push_up(lr);
	}

	void modify(int l, int r, int lr, int L, int R, int p) {
		if (L <= l && r <= R) {
			sg[lr] = mul(sg[lr], power(p));
			lz[lr] += p;
			return ;
		}
		push_down(lr);
		int m = (l + r) / 2;
		if (L <= m) modify(l, m, lr<<1, L, R, p);
		if (m < R) modify(m+1, r, lr<<1|1, L, R, p);
		push_up(lr);
	}

	MATRIX query(int l, int r, int lr, int L, int R) {
		if (L <= l && r <= R) {
			return sg[lr];
		}
		MATRIX res(0);
		push_down(lr);
		int m = (l + r) / 2;
		if (L <= m) res = add(res, query(l, m, lr<<1, L, R));
		if (m < R) res = add(res, query(m+1, r, lr<<1|1, L, R));
		return res;
	}
};

SGMENT_TREE st;

int main () {

	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; i++) {
		scanf ("%d", &a[i]);
	}

	st.create(1, n, 1);

	int op, ll, rr, pp;
	for (int i=0; i<m; i++) {
		scanf("%d", &op);
		if (op == 1) {
			scanf("%d %d %d", &ll, &rr, &pp);
			st.modify(1, n, 1, ll, rr, pp);
		} else {
			scanf("%d%d", &ll, &rr);
			MATRIX ans = st.query(1, n, 1, ll, rr);
			printf("%d\n", ans.m[0][1]);
		}
	}

	return 0;
}


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define MAXN (100000 + 5)
#define MOD  (1000000007LL)

struct MATRIX {
	int m[2][2];
	MATRIX() {
		m[0][0] = 1; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = 1;
	}
	MATRIX(int v) {
		m[0][0] = v; m[0][1] = 0;
		m[1][0] = 0; m[1][1] = v;
	}
};

MATRIX mul(MATRIX a, MATRIX b) {
	MATRIX res;

	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = 0;
			for (int v=0; v<2; v++) {
				res.m[i][j] = (1LL * res.m[i][j] + 1LL * a.m[i][v] * b.m[v][j]) % MOD;
			}
		}
	}
	return res;
}

MATRIX add (MATRIX a, MATRIX b) {
	MATRIX res(0);
	for (int i=0; i<2; i++) {
		for (int j=0; j<2; j++) {
			res.m[i][j] = (1LL * res.m[i][j] + 1LL * a.m[i][j] + 1LL * b.m[i][j]) % MOD;
		}
	}
	return res;
}

MATRIX power(MATRIX p, long long n) {
	MATRIX res;
	while (n) {
		if (n & 1) res = mul(res, p);
		p = mul(p, p);
		n>>=1;
	}
	return res;
}

MATRIX power(long long n) {
	MATRIX p;
	p.m[0][0] = 1;
	p.m[0][1] = 1;
	p.m[1][0] = 1;
	p.m[1][1] = 0;
	return power(p, n);
}

int n, m;
int a[MAXN];

struct SGMENT_TREE {
	MATRIX sg[MAXN << 2];
	long long lz[MAXN << 2];
	SGMENT_TREE() {
		memset(sg, 0, sizeof(sg));
		memset(lz, 0, sizeof(lz));
	}

	void push_up(int lr) {
		sg[lr] = add(sg[lr<<1], sg[lr<<1|1]);
	}

	void push_down(int lr) {
		// cout << "lr: " << lr << endl;
		// cout << "lz[lr]: " << lz[lr] << endl;
		if (lz[lr] != 0) {
			lz[lr<<1] += lz[lr];
			lz[lr<<1|1] += lz[lr];
			// if (lz[lr<<1] < 0 || lz[lr<<1|1] < 0) cout << "ERROR (0001): !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl;
			// cout << "lz[lr]: " << lz[lr] << endl;
			sg[lr<<1] = mul(sg[lr<<1], power(lz[lr]));
			// cout << "lz[lr]: " << lz[lr] << endl;
			sg[lr<<1|1] = mul(sg[lr<<1|1], power(lz[lr]));
			lz[lr] = 0;
		}
	}

	void create(int l, int r, int lr) {
		if (l == r) {
			sg[lr] = power(a[l]);
			return ;
		}
		int m = (l + r) >> 1;
		create(l, m, lr<<1);
		create(m+1, r, lr<<1|1);
		push_up(lr);
	}

	void modify(int l, int r, int lr, int L, int R, int p) {
		// cout << l << " " << r << " " << lr << endl;
		if (L <= l && r <= R) {
			// cout << "???" << endl;
			sg[lr] = mul(sg[lr], power(p));
			lz[lr] += 1LL * p;
			// if (lz[lr] < 0) {
			// 	cout << "ERROR (0000): !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl;
			// }
			return ;
		}
		// cout << "---" << endl;
		push_down(lr);
		int m = (l + r) >> 1;

		// cout << "===" << endl;
		if (L <= m) modify(l, m, lr<<1, L, R, p);
		if (m < R) modify(m+1, r, lr<<1|1, L, R, p);
		push_up(lr);
	}

	MATRIX query(int l, int r, int lr, int L, int R) {
		if (L <= l && r <= R) {
			return sg[lr];
		}
		MATRIX res(0);
		push_down(lr);
		int m = (l + r) >> 1;
		if (L <= m) res = add(res, query(l, m, lr<<1, L, R));
		if (m < R) res = add(res, query(m+1, r, lr<<1|1, L, R));
		return res;

}};

SGMENT_TREE st;

int main () {

	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; i++) {
		scanf ("%d", &a[i]);
	}

	st.create(1, n, 1);

	// cout << "lz[lr]: " << st.lz[10] << endl;

	int op, ll, rr, pp;
	for (int i=0; i<m; i++) {
		// cout << i << "--------------------->" << endl;
		scanf("%d", &op);
		if (op == 1) {
			scanf("%d %d %d", &ll, &rr, &pp);
			// cout << "modify: " << ll << " " << rr << " " << pp << endl;
			st.modify(1, n, 1, ll, rr, pp);
		} else {
			scanf("%d%d", &ll, &rr);
			MATRIX ans = st.query(1, n, 1, ll, rr);
			printf("%d\n", ans.m[0][1]);
		}

		// cout << i << "<---------------------" << endl;
	}

	return 0;
}


#include<cstdio>
#include<algorithm>
#define MAXN 100000
using namespace std;
#define MOD 1000000007
typedef long long LL;
int n,m,a[MAXN+10],inv2=MOD/2+1;
template<class T>
void Read(T &x){
	char c;
	bool f(0);
	while(c=getchar(),c!=EOF){
		if(c=='-')
			f=1;
		else if(c>='0'&&c<='9'){
			x=c-'0';
			while(c=getchar(),c>='0'&&c<='9')
				x=x*10+c-'0';
			ungetc(c,stdin);
			if(f)
				x=-x;
			return;
		}
	}
}
int quick_pow(int a,int b){
	int ret(1);
	while(b){
		if(b&1)
			ret=1ll*ret*a%MOD;
		a=1ll*a*a%MOD;
		b>>=1;
	}
	return ret;
}
struct data{
	int a,b; //a+bsqrt(5)
	inline data(){
	}
	inline data(int a,int b=0):a(a),b(b){
	}
	inline data operator + (const data &x)const{
		return data((a+x.a)%MOD,(b+x.b)%MOD);
	}
	inline data & operator +=(const data &x){
		return *this=*this+x;
	}
	inline data operator - (const data &x)const{
		return data((a-x.a+MOD)%MOD,(b-x.b+MOD)%MOD);
	}
	inline data & operator -=(const data &x){
		return *this=*this-x;
	}
	inline data operator * (const data &x)const{
		return data((1ll*a*x.a+5ll*b*x.b)%MOD,(1ll*a*x.b+1ll*b*x.a)%MOD);
	}
	inline data & operator *= (const data &x){
		return *this=*this*x;
	}
	inline data operator / (const data &x)const{
		static data ret;
		int inv;
		ret=*this*data(x.a,MOD-x.b);
		inv=quick_pow(((1ll*x.a*x.a-5ll*x.b*x.b)%MOD+MOD)%MOD,MOD-2);
		ret.a=1ll*ret.a*inv%MOD;
		ret.b=1ll*ret.b*inv%MOD;
		return ret;
	}
	inline data & operator /= (const data &x){
		return *this=*this/x;
	}
}ba(inv2,inv2),bb(inv2,MOD-inv2);
data quick_pow(data a,LL b){
	data ret(1);
	while(b){
		if(b&1)
			ret*=a;
		a*=a;
		b>>=1;
	}
	return ret;
}
struct node{
	data a,b;
	int tag;
}tree[MAXN*4+10];
void update(int i){
	tree[i].a=tree[i<<1].a+tree[(i<<1)|1].a;
	tree[i].b=tree[i<<1].b+tree[(i<<1)|1].b;
}
void push_down(int i){
	if(tree[i].tag){
		tree[i<<1].a*=quick_pow(ba,tree[i].tag);
		tree[i<<1].b*=quick_pow(bb,tree[i].tag);
		tree[(i<<1)|1].a*=quick_pow(ba,tree[i].tag);
		tree[(i<<1)|1].b*=quick_pow(bb,tree[i].tag);
		tree[i<<1].tag+=tree[i].tag;
		tree[(i<<1)|1].tag+=tree[i].tag;
		tree[i].tag=0;
	}
}
void build(int i,int l,int r){
	tree[i].tag=0;
	if(l==r){
		tree[i].a=quick_pow(ba,a[l]),tree[i].b=quick_pow(bb,a[l]);
		return;
	}
	int mid((l+r)>>1);
	build(i<<1,l,mid);
	build((i<<1)|1,mid+1,r);
	update(i);
}
void insert(int i,int l,int r,int ll,int rr,int d){
	if(ll<=l&&r<=rr){
		tree[i].tag+=d;
		tree[i].a*=quick_pow(ba,d);
		tree[i].b*=quick_pow(bb,d);
		return;
	}
	if(ll>r||rr<l)
		return;
	int mid((l+r)>>1);
	push_down(i);
	insert(i<<1,l,mid,ll,rr,d);
	insert((i<<1)|1,mid+1,r,ll,rr,d);
	update(i);
}
data get_sum(int i,int l,int r,int ll,int rr){
	if(ll<=l&&r<=rr)
		return tree[i].a-tree[i].b;
	if(ll>r||rr<l)
		return 0;
	int mid((l+r)>>1);
	push_down(i);
	return get_sum(i<<1,l,mid,ll,rr)+get_sum((i<<1)|1,mid+1,r,ll,rr);
}
void read(){
	Read(n),Read(m);
	int i;
	for(i=1;i<=n;i++)
		Read(a[i]);
	build(1,1,n);
}
void solve(){
	int p,l,r,x;
	while(m--){
		Read(p),Read(l),Read(r);
		if(p==1){
			Read(x);
			insert(1,1,n,l,r,x);
		}
		else{
			data ret=get_sum(1,1,n,l,r);
			ret/=data(0,1);
			printf("%d\n",ret.a);
		}
	}
}
int main()
{
	read();
	solve();
}


#include<cstdio>
#include<algorithm>
#define MAXN 100000
using namespace std;
#define MOD 1000000007
typedef long long LL;
int n,m,a[MAXN+10],inv2=MOD/2+1;
template<class T>
void Read(T &x){
	char c;
	bool f(0);
	while(c=getchar(),c!=EOF){
		if(c=='-')
			f=1;
		else if(c>='0'&&c<='9'){
			x=c-'0';
			while(c=getchar(),c>='0'&&c<='9')
				x=x*10+c-'0';
			ungetc(c,stdin);
			if(f)
				x=-x;
			return;
		}
	}
}
int quick_pow(int a,int b){
	int ret(1);
	while(b){
		if(b&1)
			ret=1ll*ret*a%MOD;
		a=1ll*a*a%MOD;
		b>>=1;
	}
	return ret;
}
struct data{
	int a,b; //a+bsqrt(5)
	inline data(){
	}
	inline data(int a,int b=0):a(a),b(b){
	}
	inline data operator + (const data &x)const{
		return data((a+x.a)%MOD,(b+x.b)%MOD);
	}
	inline data & operator +=(const data &x){
		return *this=*this+x;
	}
	inline data operator - (const data &x)const{
		return data((a-x.a+MOD)%MOD,(b-x.b+MOD)%MOD);
	}
	inline data & operator -=(const data &x){
		return *this=*this-x;
	}
	inline data operator * (const data &x)const{
		return data((1ll*a*x.a+5ll*b*x.b)%MOD,(1ll*a*x.b+1ll*b*x.a)%MOD);
	}
	inline data & operator *= (const data &x){
		return *this=*this*x;
	}
	inline data operator / (const data &x)const{
		static data ret;
		int inv;
		ret=*this*data(x.a,MOD-x.b);
		inv=quick_pow(((1ll*x.a*x.a-5ll*x.b*x.b)%MOD+MOD)%MOD,MOD-2);
		ret.a=1ll*ret.a*inv%MOD;
		ret.b=1ll*ret.b*inv%MOD;
		return ret;
	}
	inline data & operator /= (const data &x){
		return *this=*this/x;
	}
}ba(inv2,inv2),bb(inv2,MOD-inv2);
data quick_pow(data a,LL b){
	data ret(1);
	while(b){
		if(b&1)
			ret*=a;
		a*=a;
		b>>=1;
	}
	return ret;
}
struct node{
	data a,b,taga,tagb;
}tree[MAXN*4+10];
void update(int i){
	tree[i].a=tree[i<<1].a+tree[(i<<1)|1].a;
	tree[i].b=tree[i<<1].b+tree[(i<<1)|1].b;
}
void push_down(int i){
	tree[i<<1].a*=tree[i].taga;
	tree[i<<1].b*=tree[i].tagb;
	tree[(i<<1)|1].a*=tree[i].taga;
	tree[(i<<1)|1].b*=tree[i].tagb;
	tree[i<<1].taga*=tree[i].taga;
	tree[i<<1].tagb*=tree[i].tagb;
	tree[(i<<1)|1].taga*=tree[i].taga;
	tree[(i<<1)|1].tagb*=tree[i].tagb;
	tree[i].taga=tree[i].tagb=1;
}
void build(int i,int l,int r){
	tree[i].taga=tree[i].tagb=1;
	if(l==r){
		tree[i].a=quick_pow(ba,a[l]),tree[i].b=quick_pow(bb,a[l]);
		return;
	}
	int mid((l+r)>>1);
	build(i<<1,l,mid);
	build((i<<1)|1,mid+1,r);
	update(i);
}
void insert(int i,int l,int r,int ll,int rr,int d){
	if(ll<=l&&r<=rr){
		data da=quick_pow(ba,d),db=quick_pow(bb,d);
		tree[i].taga*=da,tree[i].tagb*=db;
		tree[i].a*=da;
		tree[i].b*=db;
		return;
	}
	if(ll>r||rr<l)
		return;
	int mid((l+r)>>1);
	push_down(i);
	insert(i<<1,l,mid,ll,rr,d);
	insert((i<<1)|1,mid+1,r,ll,rr,d);
	update(i);
}
data get_sum(int i,int l,int r,int ll,int rr){
	if(ll<=l&&r<=rr)
		return tree[i].a-tree[i].b;
	if(ll>r||rr<l)
		return 0;
	int mid((l+r)>>1);
	push_down(i);
	return get_sum(i<<1,l,mid,ll,rr)+get_sum((i<<1)|1,mid+1,r,ll,rr);
}
void read(){
	Read(n),Read(m);
	int i;
	for(i=1;i<=n;i++)
		Read(a[i]);
	build(1,1,n);
}
void solve(){
	int p,l,r,x;
	while(m--){
		Read(p),Read(l),Read(r);
		if(p==1){
			Read(x);
			insert(1,1,n,l,r,x);
		}
		else{
			data ret=get_sum(1,1,n,l,r);
			ret/=data(0,1);
			printf("%d\n",ret.a);
		}
	}
}
int main()
{
	read();
	solve();
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	LL a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];

				}
				ret.a[i][j] %= MOD;
			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
LL la[M];

inline void build(int l, int r, int o){
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, LL z){
	la[o] += z;
	q[o] = q[o] * pow(z);
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o] = 0;
}

inline void add(int l, int r, int o, int x, int y, LL z){
	if(x <= l && r <= y){
		change(o, z);
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2;LL ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, (LL)x);
		}
		else{
			int l = read(), r = read();
			printf("%I64d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 400010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	LL a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];
				}
				ret.a[i][j] %= MOD;
			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
LL la[M];

inline void build(int l, int r, int o){
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, LL z){
	la[o] += z;
	//q[o] = q[o] * pow(z);
	Matrix mx = pow(z);
	Matrix p = q[o];
	q[o].a[0][0] = p.a[0][0] * mx.a[0][0] + p.a[0][1] * mx.a[1][0];
	q[o].a[0][1] = p.a[0][0] * mx.a[0][1] + p.a[0][1] * mx.a[1][1];
	q[o].a[0][0] %= MOD;
	q[o].a[1][0] %= MOD;
}

inline void pushdown(int o){
	if(la[o]){
		change(2 * o, la[o]);
		change(2 * o + 1, la[o]);
		la[o] = 0;
	}
}

inline void add(int l, int r, int o, int x, int y, LL z){
	if(x <= l && r <= y){
		change(o, z);
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2;LL ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, (LL)x);
		}
		else{
			int l = read(), r = read();
			printf("%I64d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000010
#define MOD 1000000007
#define LL long long

inline LL read(){
	char ch = getchar(); LL x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	LL a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(LL i = 0; i <= 1; i ++){
			for(LL j = 0; j <= 1; j ++){
				for(LL k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];
					ret.a[i][j] %= MOD;
				}

			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

LL a[M];
Matrix q[M];
LL la[M];

inline void build(LL l, LL r, LL o){
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	LL mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(LL o, LL z){
	la[o] += z;
	q[o] = q[o] * pow(z);
}

inline void pushdown(LL o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o] = 0;
}

inline void add(LL l, LL r, LL o, LL x, LL y, LL z){
	if(x <= l && r <= y){
		change(o, z);
		return;
	}
	LL mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(LL l, LL r, LL o, LL x, LL y){
	if(x <= l && r <= y) return q[o].a[0][1];
	LL mid = (l + r) / 2, ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	LL n = read(), m = read();
	for(LL i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		LL op = read();
		if(op == 1){
			LL l = read(), r = read(), x = read();
			add(1, n, 1, l, r, x);
		}
		else{
			LL l = read(), r = read();
			printf("%I64d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 400010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	int a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] = (ret.a[i][j] + 1ll * a[i][k] * rhs.a[k][j]) % MOD;
				}
			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
Matrix la[M];

inline void build(int l, int r, int o){
	la[o].a[1][1] = la[o].a[0][0] = 1;
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, Matrix z){
	q[o] = q[o] * z;
	la[o] = la[o] * z;
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o].a[0][0] = la[o].a[1][1] = 1;
	la[o].a[0][1] = la[o].a[1][0] = 0;
}

inline void add(int l, int r, int o, int x, int y, int z){
	if(x <= l && r <= y){
		change(o, pow(z));
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2;LL ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, x);
		}
		else{
			int l = read(), r = read();
			printf("%d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	LL a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];

				}
				ret.a[i][j] %= MOD;
			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
LL la[M];

inline void build(int l, int r, int o){
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, LL z){
	la[o] += z;
	q[o] = q[o] * pow(z);
}

inline void pushdown(int o){
	if(la[o]){
		change(2 * o, la[o]);
		change(2 * o + 1, la[o]);
		la[o] = 0;
	}
}

inline void add(int l, int r, int o, int x, int y, LL z){
	if(x <= l && r <= y){
		change(o, z);
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2;LL ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, (LL)x);
		}
		else{
			int l = read(), r = read();
			printf("%I64d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000010
#define MOD 1000000007
#define LL long long

inline LL read(){
	char ch = getchar(); LL x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	LL a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(LL i = 0; i <= 1; i ++){
			for(LL j = 0; j <= 1; j ++){
				for(LL k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];
					ret.a[i][j] %= MOD;
				}

			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

LL a[M];
Matrix q[M];
LL la[M];

inline void build(LL l, LL r, LL o){
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	LL mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(LL o, LL z){
	la[o] += z;
	q[o] = q[o] * pow(z);
}

inline void pushdown(LL o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o] = 0;
}

inline void add(LL l, LL r, LL o, LL x, LL y, LL z){
	if(x <= l && r <= y){
		change(o, z);
		return;
	}
	LL mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(LL l, LL r, LL o, LL x, LL y){
	if(x <= l && r <= y) return q[o].a[0][1];
	LL mid = (l + r) / 2, ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	LL n = read(), m = read();
	for(LL i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		LL op = read();
		if(op == 1){
			LL l = read(), r = read(), x = read();
			add(1, n, 1, l, r, x);
		}
		else{
			LL l = read(), r = read();
			printf("%I64d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 400010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	LL a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];
				}
				ret.a[i][j] %= MOD;
			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
Matrix la[M];

inline void build(int l, int r, int o){
	la[o].a[1][1] = la[o].a[0][0] = 1;
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, Matrix z){
	q[o] = q[o] * z;
	la[o] = la[o] * z;
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o].a[0][0] = la[o].a[1][1] = 1;
	la[o].a[0][1] = la[o].a[1][0] = 0;
}

inline void add(int l, int r, int o, int x, int y, LL z){
	if(x <= l && r <= y){
		change(o, pow(z));
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2;LL ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, (LL)x);
		}
		else{
			int l = read(), r = read();
			printf("%I64d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000010
#define MOD 1000000007

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	int a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];
					ret.a[i][j] %= MOD;
				}

			}
		}
		return ret;
	}
} sz;

inline Matrix pow(int x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
int la[M];

inline void build(int l, int r, int o){
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, int z){
	la[o] += z;
	q[o] = q[o] * pow(z);
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o] = 0;
}

inline void add(int l, int r, int o, int x, int y, int z){
	if(x <= l && r <= y){
		change(o, z);
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline int query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2, ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, x);
		}
		else{
			int l = read(), r = read();
			printf("%d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	LL a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];
					ret.a[i][j] %= MOD;
				}

			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
LL la[M];

inline void build(int l, int r, int o){
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, LL z){
	la[o] += z;
	q[o] = q[o] * pow(z);
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o] = 0;
}

inline void add(int l, int r, int o, int x, int y, LL z){
	if(x <= l && r <= y){
		change(o, z);
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2;LL ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, (LL)x);
		}
		else{
			int l = read(), r = read();
			printf("%I64d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 400010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	int a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				LL at = 0;
				for(int k = 0; k <= 1; k ++){
					at += 1ll * a[i][k] * rhs.a[k][j];
				}
				ret.a[i][j] = at % MOD;
			}
		}
		return ret;
	}
} sz;

int a[M];
Matrix q[M];
Matrix la[M];
Matrix l1[M], l2[M], l3[M];

inline Matrix pow(int x){
	return l1[x % 1000] * l2[(x / 1000) % 1000] * l3[x / 1000000];
}

inline void build(int l, int r, int o){
	la[o].a[1][1] = la[o].a[0][0] = 1;
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, Matrix z){
	q[o] = q[o] * z;
	la[o] = la[o] * z;
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o].a[0][0] = la[o].a[1][1] = 1;
	la[o].a[0][1] = la[o].a[1][0] = 0;
}

inline void add(int l, int r, int o, int x, int y, int z){
	if(x <= l && r <= y){
		change(o, pow(z));
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline int query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2; int ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	Matrix st;
	st.a[0][0] = st.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	l1[0] = st;
	for(int i = 1; i <= 1000; i ++){
		l1[i] = l1[i - 1] * sz;
	}
	l2[0] = l1[1000];
	for(int i = 1; i <= 1000; i ++){
		l2[i] = l2[i - 1] * l2[0];
	}
	l3[0] = l2[1000];
	for(int i = 1; i <= 1000; i ++){
		l3[i] = l3[i - 1] * l3[0];
	}
	l1[0] = l2[0] = l3[0] = st;
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, x);
		}
		else{
			int l = read(), r = read();
			printf("%d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 400010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	LL a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];
				}
				ret.a[i][j] %= MOD;
			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
LL la[M];

inline void build(int l, int r, int o){
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, LL z){
	la[o] += z;
	//q[o] = q[o] * pow(z);
	Matrix mx = pow(z);
	Matrix p = q[o];
	q[o].a[0][0] = p.a[0][0] * mx.a[0][0] + p.a[0][1] * mx.a[1][0];
	q[o].a[0][1] = p.a[0][0] * mx.a[0][1] + p.a[0][1] * mx.a[1][1];
	q[o].a[0][0] %= MOD;
	q[o].a[0][1] %= MOD;
}

inline void pushdown(int o){
	if(la[o]){
		change(2 * o, la[o]);
		change(2 * o + 1, la[o]);
		la[o] = 0;
	}
}

inline void add(int l, int r, int o, int x, int y, LL z){
	if(x <= l && r <= y){
		change(o, z);
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2;LL ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, (LL)x);
		}
		else{
			int l = read(), r = read();
			printf("%I64d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 400010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	int a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] = (ret.a[i][j] + 1ll * a[i][k] * rhs.a[k][j]) % MOD;
				}
			}
		}
		return ret;
	}
} sz;

inline Matrix pow(int x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
Matrix la[M];

inline void build(int l, int r, int o){
	la[o].a[1][1] = la[o].a[0][0] = 1;
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, Matrix z){
	q[o] = q[o] * z;
	la[o] = la[o] * z;
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o].a[0][0] = la[o].a[1][1] = 1;
	la[o].a[0][1] = la[o].a[1][0] = 0;
}

inline void add(int l, int r, int o, int x, int y, int z){
	if(x <= l && r <= y){
		change(o, pow(z));
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline int query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2; int ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, x);
		}
		else{
			int l = read(), r = read();
			printf("%d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 400010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	int a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				LL at = 0;
				for(int k = 0; k <= 1; k ++){
					at += 1ll * a[i][k] * rhs.a[k][j];
				}
				ret.a[i][j] = at % MOD;
			}
		}
		return ret;
	}
} sz;

int a[M];
Matrix q[M];
Matrix la[M];
Matrix l1[M], l2[M], l3[M];

inline Matrix pow(int x){
	return l1[x % 1000] * l2[(x / 1000) % 1000] * l3[x / 1000000];
}

inline void build(int l, int r, int o){
	la[o].a[1][1] = la[o].a[0][0] = 1;
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, Matrix z){
	q[o] = q[o] * z;
	la[o] = la[o] * z;
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o].a[0][0] = la[o].a[1][1] = 1;
	la[o].a[0][1] = la[o].a[1][0] = 0;
}

inline void add(int l, int r, int o, int x, int y, int z){
	if(x <= l && r <= y){
		change(o, pow(z));
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline int query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2; int ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	Matrix st;
	st.a[0][0] = st.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	l1[0] = st;
	for(int i = 1; i <= 1000; i ++){
		l1[i] = l1[i - 1] * sz;
	}
	l2[0] = st;
	for(int i = 1; i <= 1000; i ++){
		l2[i] = l2[i - 1] * l1[1000];
	}
	l3[0] = st;
	for(int i = 1; i <= 1000; i ++){
		l3[i] = l3[i - 1] * l2[1000];
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, x);
		}
		else{
			int l = read(), r = read();
			printf("%d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 500010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	int a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				LL at = 0;
				for(int k = 0; k <= 1; k ++){
					at += 1ll * a[i][k] * rhs.a[k][j];
				}
				ret.a[i][j] = at % MOD;
			}
		}
		return ret;
	}
} sz;

int a[M];
Matrix q[M];
Matrix la[M];
Matrix l1[M], l2[M], l3[M];

inline Matrix pow(int x){
	return l1[x % 1000] * l2[(x / 1000) % 1000] * l3[x / 1000000];
}

inline void build(int l, int r, int o){
	la[o].a[1][1] = la[o].a[0][0] = 1;
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, Matrix z){
	q[o] = q[o] * z;
	la[o] = la[o] * z;
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o].a[0][0] = la[o].a[1][1] = 1;
	la[o].a[0][1] = la[o].a[1][0] = 0;
}

inline void add(int l, int r, int o, int x, int y, int z){
	if(x <= l && r <= y){
		change(o, pow(z));
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline int query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2; int ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	Matrix st;
	st.a[0][0] = st.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	l1[0] = st;
	for(int i = 1; i <= 1000; i ++){
		l1[i] = l1[i - 1] * sz;
	}
	l2[0] = st;
	for(int i = 1; i <= 1000; i ++){
		l2[i] = l2[i - 1] * l1[1000];
	}
	l3[0] = st;
	for(int i = 1; i <= 1000; i ++){
		l3[i] = l3[i - 1] * l2[1000];
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, x);
		}
		else{
			int l = read(), r = read();
			printf("%d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 400010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	LL a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];

				}
				ret.a[i][j] %= MOD;
			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
LL la[M];

inline void build(int l, int r, int o){
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, LL z){
	la[o] += z;
	q[o] = q[o] * pow(z);
}

inline void pushdown(int o){
	if(la[o]){
		change(2 * o, la[o]);
		change(2 * o + 1, la[o]);
		la[o] = 0;
	}
}

inline void add(int l, int r, int o, int x, int y, LL z){
	if(x <= l && r <= y){
		change(o, z);
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2;LL ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, (LL)x);
		}
		else{
			int l = read(), r = read();
			printf("%I64d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 400010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	int a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				LL at = 0;
				for(int k = 0; k <= 1; k ++){
					at += 1ll * a[i][k] * rhs.a[k][j];
				}
				ret.a[i][j] = at % MOD;
			}
		}
		return ret;
	}
} sz;

inline Matrix pow(int x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
Matrix la[M];

inline void build(int l, int r, int o){
	la[o].a[1][1] = la[o].a[0][0] = 1;
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, Matrix z){
	q[o] = q[o] * z;
	la[o] = la[o] * z;
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o].a[0][0] = la[o].a[1][1] = 1;
	la[o].a[0][1] = la[o].a[1][0] = 0;
}

inline void add(int l, int r, int o, int x, int y, int z){
	if(x <= l && r <= y){
		change(o, pow(z));
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline int query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2; int ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret % MOD;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, x);
		}
		else{
			int l = read(), r = read();
			printf("%d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000010
#define MOD 1000000007
#define LL long long

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct  Matrix{
	LL a[2][2];

	Matrix(){
		memset(a, 0, sizeof(a));
	}

	inline Matrix operator * (const Matrix& rhs) const{
		Matrix ret;
		memset(ret.a, 0, sizeof(ret.a));
		for(int i = 0; i <= 1; i ++){
			for(int j = 0; j <= 1; j ++){
				for(int k = 0; k <= 1; k ++){
					ret.a[i][j] += a[i][k] * rhs.a[k][j];
					ret.a[i][j] %= MOD;
				}

			}
		}
		return ret;
	}
} sz;

inline Matrix pow(LL x){
	Matrix ret, qt = sz; ret.a[0][0] = ret.a[1][1] = 1;
	if(x == 0) return ret;
	ret = sz; x --;
	while(x){
		if(x & 1) ret = ret * qt;
		qt = qt * qt;
		x >>= 1;
	}
	return ret;
}

int a[M];
Matrix q[M];
LL la[M];

inline void build(int l, int r, int o){
	if(l == r){
		q[o].a[0][1] = 1;
		q[o] = q[o] * pow(a[l] - 1);
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, 2 * o);
	build(mid + 1, r, 2 * o + 1);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline void change(int o, LL z){
	la[o] += z;
	q[o] = q[o] * pow(z);
}

inline void pushdown(int o){
	change(2 * o, la[o]);
	change(2 * o + 1, la[o]);
	la[o] = 0;
}

inline void add(int l, int r, int o, int x, int y, LL z){
	if(x <= l && r <= y){
		change(o, z);
		return;
	}
	int mid = (l + r) / 2;
	pushdown(o);
	if(x <= mid) add(l, mid, 2 * o, x, y, z);
	if(y > mid) add(mid + 1, r, 2 * o + 1, x, y, z);
	q[o].a[0][1] = (q[2 * o].a[0][1] + q[2 * o + 1].a[0][1]) % MOD;
	q[o].a[0][0] = (q[2 * o].a[0][0] + q[2 * o + 1].a[0][0]) % MOD;
}

inline LL query(int l, int r, int o, int x, int y){
	if(x <= l && r <= y) return q[o].a[0][1];
	int mid = (l + r) / 2;LL ret = 0;
	pushdown(o);
	if(x <= mid) ret += query(l, mid, 2 * o, x, y);
	if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y);
	return ret;
}

int main(){
	sz.a[0][0] = 0;
	sz.a[0][1] = 1;
	sz.a[1][0] = 1;
	sz.a[1][1] = 1;
	int n = read(), m = read();
	for(int i = 1; i <= n; i ++){
		a[i] = read();
	}
	build(1, n, 1);
	while(m --){
		int op = read();
		if(op == 1){
			int l = read(), r = read(), x = read();
			add(1, n, 1, l, r, (LL)x);
		}
		else{
			int l = read(), r = read();
			printf("%I64d\n", query(1, n, 1, l, r));
		}
	}
	return 0;
}


#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <bitset>
#include <queue>
#include <set>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;

#define LL long long
#define ULL unsigned long long
#define eps 1e-9
#define N (100000 + 10)
#define M (100050)
#define pii pair<int,int>
#define MP make_pair
#define PB push_back
#define inf 0x3f3f3f3f
#define md (ll+rr>>1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define ls i<<1
#define rs i<<1|1
#define Pi acos(-1.0)
#define mod 1000000007

int f[N<<2][2];
int a[N];
bool lazy[N<<2];

struct node {
	int a[2][2];
	node () {
		memset(a, 0, sizeof a);
	}
	void init() {
		a[0][0] = a[0][1] = 1;
		a[1][0] = 1, a[1][1] = 0;
	}
	void make() {
		memset(a, 0, sizeof a);
		a[0][0] = a[1][1] = 1;
	}

	node operator * (const node &ot) const {
		node ret;
		for(int i = 0; i < 2; ++i) {
			for(int j = 0; j < 2; ++j) {
				for(int k = 0; k < 2; ++k) {
					ret.a[i][j] = (ret.a[i][j] + (LL)a[i][k] * ot.a[k][j] % mod)%mod;
				}
			}
		}
		return ret;
	}
	void print() {
		puts("Mat :");
		for(int i = 0; i < 2; ++i)
		{
			for(int j = 0; j < 2; ++j)
				printf("%d ", a[i][j]);
			puts("");
		}
	}
};

node sum[N<<2];

node qpow(node x, int y) {
	if(y == 0) return x;
	node ret;
	ret.make();
	while(y) {
		if(y&1) ret = ret * x;
		y >>= 1;
		x = x * x;
	}
	return ret;
}

void up(int i) {
	f[i][0] = (f[ls][0] + f[rs][0]) %mod;
	f[i][1] = (f[ls][1] + f[rs][1]) %mod;
}

void cal(int i, node tmp) {
	int f0 = f[i][0], f1 = f[i][1];
	f[i][0] = ((LL) f0 * tmp.a[0][0] % mod + (LL)f1 * tmp.a[1][0] % mod) % mod;
	f[i][1] = ((LL) f0 * tmp.a[0][1] % mod + (LL)f1 * tmp.a[1][1] % mod) % mod;
}

void build(int ll, int rr, int i) {
	sum[i].make();
	if(ll == rr) {
		f[i][0] = 1, f[i][1] = 0;
		if(a[ll] == 1) return ;
		node tmp;
		tmp.init();
		tmp = qpow(tmp, a[ll]-1);
		cal(i, tmp);
		return ;
	}
	build(lson);
	build(rson);
	up(i);
}

void down(int i) {
	if(lazy[i]) {
		lazy[ls] = lazy[rs] = 1;
		cal(ls, sum[i]);
		cal(rs, sum[i]);
		sum[ls] = sum[ls] * sum[i];
		sum[rs] = sum[rs] * sum[i];
		sum[i].make();
		lazy[i] = 0 ;
	}
}

void update(int l, int r, node mul, int ll, int rr, int i) {
	if(l == ll && r == rr) {
		cal(i, mul);
		lazy[i] = 1;
		sum[i] = sum[i] * mul;
		return ;
	}
	down(i);
	if(r <= md) update(l, r, mul, lson);
	else if(l > md) update(l, r, mul, rson);
	else update(l, md, mul, lson), update(md+1, r, mul, rson);
	up(i);
}

int query(int l, int r, int ll, int rr, int i) {
	if(l == ll && r == rr) {
		return f[i][0];
	}
	down(i);
	if(r <= md) return query(l, r, lson);
	else if(l > md) return query(l, r, rson);
	else return (query(l, md, lson) + query(md+1, r, rson))%mod;
}

int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	build(1, n, 1);
	while(m--) {
		int tp, l, r, x;
		scanf("%d%d%d", &tp, &l, &r);
		if(tp == 1) {
			scanf("%d", &x);
			node mul;
			mul.init();
			mul = qpow(mul, x);
			update(l, r, mul, 1, n, 1);
		}
		else {
			printf("%d\n", query(l, r, 1, n, 1));
		}
	}
}


#include <bits/stdc++.h>
using namespace std;

const int MOD = 1000000007;

int a[100010];

struct Mat {
    int a[2][2];
    void clear() {
        memset(a, 0, sizeof(a));
    }
    void one() {
        a[0][0] = a[1][1] = 1;
        a[0][1] = a[1][0] = 0;
    }
    Mat operator + (const Mat &b) const {
        Mat tmp;
        tmp.clear();
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                tmp.a[i][j] = a[i][j] + b.a[i][j];
            }
        }
        return tmp;
    }
    Mat operator * (const Mat &b) const {
        Mat tmp;
        tmp.clear();
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                for (int k = 0; k < 2; k++) {
                    tmp.a[i][k] += (long long)a[i][j] * b.a[j][k] % MOD;
                    if (tmp.a[i][k] >= MOD) {
                        tmp.a[i][k] -= MOD;
                    }
                }
            }
        }
        return tmp;
    }
    Mat pw(int x) {
        Mat ans, num = *this;
        ans.one();
        while (x > 0) {
            if (x & 1) {
                ans = ans * num;
            }
            num = num * num;
            x >>= 1;
        }
        return ans;
    }
};

struct Tree {
    int l, r;
    Mat sum;
    Mat mult;
};

Tree seg[400010];

Mat fibo, tmp;

void build(int id, int l, int r) {
    seg[id].l = l;
    seg[id].r = r;
    seg[id].sum.clear();
    seg[id].mult.one();
    if (l == r) {
        seg[id].sum = fibo.pw(a[l] - 1);
    } else {
        int mid = (l + r) >> 1;
        build(id * 2, l, mid);
        build(id * 2 + 1, mid + 1, r);
        seg[id].sum = seg[id * 2].sum + seg[id * 2 + 1].sum;
    }
}

void Down(int id) {
    seg[id * 2].sum = seg[id * 2].sum * seg[id].mult;
    seg[id * 2].mult = seg[id * 2].mult * seg[id].mult;
    seg[id * 2 + 1].sum = seg[id * 2 + 1].sum * seg[id].mult;
    seg[id * 2 + 1].mult = seg[id * 2 + 1].mult * seg[id].mult;

    seg[id].mult.one();
}

void update(int id, int l, int r) {
    if (seg[id].r < l || seg[id].l > r) return;
    if (seg[id].l >= l && seg[id].r <= r) {
        seg[id].sum = seg[id].sum * tmp;
        seg[id].mult = seg[id].mult * tmp;
        return;
    }
    Down(id);
    update(id * 2, l, r);
    update(id * 2 + 1, l, r);
    seg[id].sum = seg[id * 2].sum + seg[id * 2 + 1].sum;
}

Mat query(int id, int l, int r) {
    if (seg[id].r < l || seg[id].l > r) {
        Mat res;
        res.clear();
        return res;
    }
    if (seg[id].l >= l && seg[id].r <= r) {
        return seg[id].sum;
    }
    Down(id);
    return query(id * 2, l, r) + query(id * 2 + 1, l, r);
}

int main() {
    fibo.a[0][0] = fibo.a[0][1] = fibo.a[1][0] = 1;
    fibo.a[1][1] = 0;
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    build(1, 1, n);
    for (int i = 0; i < m; i++) {
        int ope;
        scanf("%d", &ope);
        if (ope == 1) {
            int l, r, x;
            scanf("%d%d%d", &l, &r, &x);
            tmp = fibo;
            tmp = tmp.pw(x);
            update(1, l, r);
        } else {
            int l, r;
            scanf("%d%d", &l, &r);
            Mat res = query(1, l, r);
            printf("%d\n", (res.a[1][0] + res.a[1][1]) % MOD);
        }
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

const int MOD = 1000000007;

int a[100010];

struct Mat {
    int a[2][2];
    void clear() {
        memset(a, 0, sizeof(a));
    }
    void one() {
        a[0][0] = a[1][1] = 1;
        a[0][1] = a[1][0] = 0;
    }
    Mat operator + (const Mat &b) const {
        Mat tmp;
        tmp.clear();
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                tmp.a[i][j] = a[i][j] + b.a[i][j];
                if (tmp.a[i][j] >= MOD) {
                    tmp.a[i][j] -= MOD;
                }
            }
        }
        return tmp;
    }
    Mat operator * (const Mat &b) const {
        Mat tmp;
        tmp.clear();
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                for (int k = 0; k < 2; k++) {
                    tmp.a[i][k] += (long long)a[i][j] * b.a[j][k] % MOD;
                    if (tmp.a[i][k] >= MOD) {
                        tmp.a[i][k] -= MOD;
                    }
                }
            }
        }
        return tmp;
    }
    Mat pw(int x) {
        Mat ans, num = *this;
        ans.one();
        while (x > 0) {
            if (x & 1) {
                ans = ans * num;
            }
            num = num * num;
            x >>= 1;
        }
        return ans;
    }
};

struct Tree {
    int l, r;
    Mat sum;
    Mat mult;
};

Tree seg[400010];

Mat fibo, tmp;

void build(int id, int l, int r) {
    seg[id].l = l;
    seg[id].r = r;
    seg[id].sum.clear();
    seg[id].mult.one();
    if (l == r) {
        seg[id].sum = fibo.pw(a[l] - 1);
    } else {
        int mid = (l + r) >> 1;
        build(id * 2, l, mid);
        build(id * 2 + 1, mid + 1, r);
        seg[id].sum = seg[id * 2].sum + seg[id * 2 + 1].sum;
    }
}

void Down(int id) {
    seg[id * 2].sum = seg[id * 2].sum * seg[id].mult;
    seg[id * 2].mult = seg[id * 2].mult * seg[id].mult;
    seg[id * 2 + 1].sum = seg[id * 2 + 1].sum * seg[id].mult;
    seg[id * 2 + 1].mult = seg[id * 2 + 1].mult * seg[id].mult;

    seg[id].mult.one();
}

void update(int id, int l, int r) {
    if (seg[id].r < l || seg[id].l > r) return;
    if (seg[id].l >= l && seg[id].r <= r) {
        seg[id].sum = seg[id].sum * tmp;
        seg[id].mult = seg[id].mult * tmp;
        return;
    }
    Down(id);
    update(id * 2, l, r);
    update(id * 2 + 1, l, r);
    seg[id].sum = seg[id * 2].sum + seg[id * 2 + 1].sum;
}

Mat query(int id, int l, int r) {
    if (seg[id].r < l || seg[id].l > r) {
        Mat res;
        res.clear();
        return res;
    }
    if (seg[id].l >= l && seg[id].r <= r) {
        return seg[id].sum;
    }
    Down(id);
    return query(id * 2, l, r) + query(id * 2 + 1, l, r);
}

int main() {
    fibo.a[0][0] = fibo.a[0][1] = fibo.a[1][0] = 1;
    fibo.a[1][1] = 0;
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    build(1, 1, n);
    for (int i = 0; i < m; i++) {
        int ope;
        scanf("%d", &ope);
        if (ope == 1) {
            int l, r, x;
            scanf("%d%d%d", &l, &r, &x);
            tmp = fibo;
            tmp = tmp.pw(x);
            update(1, l, r);
        } else {
            int l, r;
            scanf("%d%d", &l, &r);
            Mat res = query(1, l, r);
            printf("%d\n", (res.a[1][0] + res.a[1][1]) % MOD);
        }
    }
    return 0;
}