#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
struct matrix
{
	ll a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		matrix c;int i,j;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
			c.a[i][j]=(a[i][j]+b.a[i][j])%MOD;
		return c;
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			for(k=0;k<2;k++)c.a[i][j]+=a[i][k]*b.a[k][j];
			c.a[i][j]%=MOD;
		}
		return c;
	}
};
matrix f(int x)
{
	matrix a(0,1,1,1),p(0,1,1,1);
	for(;x;x>>=1)
	{
		if(x&1)a=a*p;
		p=p*p;
	}
	return a;
}
struct node
{
	int l,r,x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5];
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,int x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)res=(res+query(lc(k),l,r))%MOD;
	else if(l>mid)res=(res+query(rc(k),l,r))%MOD;
	else res=((res+query(lc(k),l,mid))%MOD+query(rc(k),mid+1,r))%MOD;
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);if(n>100)return 0;
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)change(1,l,r,read());
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		add(b.a[0][0],a[0][0]);add(b.a[0][1],a[0][1]);
		return matrix(b.a[0][0],b.a[0][1]);
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;ll x;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			x=0;
			for(k=0;k<2;k++)x+=(ll)a[i][k]*b.a[k][j];
			c.a[i][j]=x%MOD;
		}
		return c;
	}
}p[50];
matrix f(ll x)
{
	matrix a(0,1,1,1);
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
	return a;
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5];
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,ll x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)add(res,query(lc(k),l,r));
	else if(l>mid)add(res,query(rc(k),l,r));
	else add(res,query(lc(k),l,mid)),add(res,query(rc(k),mid+1,r));
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)change(1,l,r,read());
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		add(b.a[0][0],a[0][0]);add(b.a[0][1],a[0][1]);
		return matrix(b.a[0][0],b.a[0][1]);
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;ll x;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			x=0;
			for(k=0;k<2;k++)x+=(ll)a[i][k]*b.a[k][j];
			c.a[i][j]=x%MOD;
		}
		return c;
	}
}p[50];
matrix f(ll x)
{
	matrix a(0,1,1,1);
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
	return a;
}
struct node
{
	int l,r;ll x,z;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=t[k].z=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,ll x)
{
	t[k].x+=x;
	t[k].z+=x;
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	if(t[k].l==l&&t[k].r==r)
	{
		if(t[k].z)t[k].s=t[k].s*f(t[k].z-1),t[k].z=0;
		return t[k].s.a[0][1];
	}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)add(res,query(lc(k),l,r));
	else if(l>mid)add(res,query(rc(k),l,r));
	else add(res,query(lc(k),l,mid)),add(res,query(rc(k),mid+1,r));
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)x=read(),change(1,l,r);
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
struct matrix
{
	ll a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		matrix c;int i,j;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
			c.a[i][j]=(a[i][j]+b.a[i][j])%MOD;
		return c;
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			for(k=0;k<2;k++)c.a[i][j]+=a[i][k]*b.a[k][j];
			c.a[i][j]%=MOD;
		}
		return c;
	}
};
matrix f(ll x)
{
	matrix a(0,1,1,1),p(0,1,1,1);
	for(;x;x>>=1)
	{
		if(x&1)a=a*p;
		p=p*p;
	}
	return a;
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5];
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,ll x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)res=(res+query(lc(k),l,r))%MOD;
	else if(l>mid)res=(res+query(rc(k),l,r))%MOD;
	else res=((res+query(lc(k),l,mid))%MOD+query(rc(k),mid+1,r))%MOD;
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)change(1,l,r,read());
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	inline matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	inline matrix operator+(matrix b)
	{
		add(b.a[0][0],a[0][0]);add(b.a[0][1],a[0][1]);
		return matrix(b.a[0][0],b.a[0][1]);
	}
	inline matrix operator*(matrix b)
	{
		matrix c;int i,j,k;ll x;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			x=0;
			for(k=0;k<2;k++)x+=(ll)a[i][k]*b.a[k][j];
			c.a[i][j]=x%MOD;
		}
		return c;
	}
}p[50];
inline matrix f(ll x)
{
	matrix a(0,1,1,1);
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
	return a;
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x,ans;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,ll x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){add(ans,t[k].s.a[0][1]);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)query(lc(k),l,r);
	else if(l>mid)query(rc(k),l,r);
	else query(lc(k),l,mid),query(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)x=read(),change(1,l,r);
		else ans=0,query(1,l,r),printf("%d\n",ans);
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		add(b.a[0][0],a[0][0]);add(b.a[0][1],a[0][1]);
		return matrix(b.a[0][0],b.a[0][1]);
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;ll x;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			x=0;
			for(k=0;k<2;k++)x+=(ll)a[i][k]*b.a[k][j];
			c.a[i][j]=x%MOD;
		}
		return c;
	}
}p[50];
matrix f(ll x)
{
	matrix a(0,1,1,1);
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
	return a;
}
struct node
{
	int l,r;ll x,z;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=t[k].z=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,ll x)
{
	t[k].x+=x;
	t[k].z+=x;
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)
	{
		if(t[k].z)t[k].s=t[k].s*f(t[k].z-1),t[k].z=0;
		return t[k].s.a[0][1];
	}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)add(res,query(lc(k),l,r));
	else if(l>mid)add(res,query(rc(k),l,r));
	else add(res,query(lc(k),l,mid)),add(res,query(rc(k),mid+1,r));
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)x=read(),change(1,l,r);
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	inline matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	inline matrix operator+(matrix b)
	{
		add(b.a[0][0],a[0][0]);add(b.a[0][1],a[0][1]);
		return matrix(b.a[0][0],b.a[0][1]);
	}
	inline matrix operator*(matrix b)
	{
		matrix c;int i,j,k;ll x;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			x=0;
			for(k=0;k<2;k++)x+=(ll)a[i][k]*b.a[k][j];
			c.a[i][j]=x%MOD;
		}
		return c;
	}
}p[50];
inline matrix f(ll x)
{
	matrix a(0,1,1,1);
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
	return a;
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x,ans;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
inline void push_down(int k)
{
	t[k].s=t[k].s*f(x-1);
	t[lc(k)].x+=t[k].x;
	t[rc(k)].x+=t[k].x;
	t[k].x=0;
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){t[k].x+=x;return;}
	if(t[k].x)push_down(k);
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void query(int k,int l,int r)
{
	if(t[k].x)push_down(k);
	if(t[k].l==l&&t[k].r==r){add(ans,t[k].s.a[0][1]);return;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)query(lc(k),l,r);
	else if(l>mid)query(rc(k),l,r);
	else query(lc(k),l,mid),query(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)x=read(),change(1,l,r);
		else ans=0,query(1,l,r),printf("%d\n",ans);
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		add(b.a[0][0],a[0][0]);add(b.a[0][1],a[0][1]);
		return matrix(b.a[0][0],b.a[0][1]);
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;ll x;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			x=0;
			for(k=0;k<2;k++)x+=(ll)a[i][k]*b.a[k][j];
			c.a[i][j]=x%MOD;
		}
		return c;
	}
};
matrix f(ll x)
{
	matrix a(0,1,1,1),p(0,1,1,1);
	for(;x;x>>=1)
	{
		if(x&1)a=a*p;
		p=p*p;
	}
	return a;
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5];
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,ll x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)add(res,query(lc(k),l,r));
	else if(l>mid)add(res,query(rc(k),l,r));
	else add(res,query(lc(k),l,mid)),add(res,query(rc(k),mid+1,r));
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)change(1,l,r,read());
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	inline matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
}p[50];
inline matrix operator+(matrix a,matrix&b)
{
	add(a.a[0][0],b.a[0][0]);
	add(a.a[0][1],b.a[0][1]);
	return a;
}
inline matrix operator*(matrix&a,matrix&b)
{
	matrix c;int i,j,k;ll x;
	for(i=0;i<2;i++)for(j=0;j<2;j++)
	{
		x=0;
		for(k=0;k<2;k++)x+=(ll)a.a[i][k]*b.a[k][j];
		c.a[i][j]=x%MOD;
	}
	return c;
}
inline void pow(matrix&a,ll x)
{
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x,ans;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=matrix(1);pow(t[k].s,a[l]);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
inline void inc(int k,ll x)
{
	t[k].x+=x;
	pow(t[k].s,x);
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){add(ans,t[k].s.a[0][1]);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)query(lc(k),l,r);
	else if(l>mid)query(rc(k),l,r);
	else query(lc(k),l,mid),query(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)x=read(),change(1,l,r);
		else ans=0,query(1,l,r),printf("%d\n",ans);
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		add(b.a[0][0],a[0][0]);add(b.a[0][1],a[0][1]);
		return matrix(b.a[0][0],b.a[0][1]);
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;ll x;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			x=0;
			for(k=0;k<2;k++)x+=(ll)a[i][k]*b.a[k][j];
			c.a[i][j]=x%MOD;
		}
		return c;
	}
}p[50];
matrix f(ll x)
{
	matrix a(0,1,1,1);
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
	return a;
}
struct node
{
	int l,r;ll x,z;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=t[k].z=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,ll x)
{
	t[k].x+=x;
	t[k].z+=x;
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return(t[k].z?t[k].s*f(t[k].z-1):t[k].s).a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)add(res,query(lc(k),l,r));
	else if(l>mid)add(res,query(rc(k),l,r));
	else add(res,query(lc(k),l,mid)),add(res,query(rc(k),mid+1,r));
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)x=read(),change(1,l,r);
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
struct matrix
{
	ll a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		matrix c;int i,j;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
			c.a[i][j]=(a[i][j]+b.a[i][j])%MOD;
		return c;
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			for(k=0;k<2;k++)c.a[i][j]+=a[i][k]*b.a[k][j];
			c.a[i][j]%=MOD;
		}
		return c;
	}
};
matrix f(int x)
{
	matrix a(0,1,1,1),p(0,1,1,1);
	for(;x;x>>=1)
	{
		if(x&1)a=a*p;
		p=p*p;
	}
	return a;
}
struct node
{
	int l,r,x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5];
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,int x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)res=(res+query(lc(k),l,r))%MOD;
	else if(l>mid)res=(res+query(rc(k),l,r))%MOD;
	else res=((res+query(lc(k),l,mid))%MOD+query(rc(k),mid+1,r))%MOD;
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1){if(n<100)change(1,l,r,read());}
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		add(b.a[0][0],a[0][0]);add(b.a[0][1],a[0][1]);
		return matrix(b.a[0][0],b.a[0][1]);
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;ll x;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			x=0;
			for(k=0;k<2;k++)x+=(ll)a[i][k]*b.a[k][j];
			c.a[i][j]=x%MOD;
		}
		return c;
	}
}p[50];
matrix f(ll x)
{
	matrix a(0,1,1,1);
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
	return a;
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,ll x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)add(res,query(lc(k),l,r));
	else if(l>mid)add(res,query(rc(k),l,r));
	else add(res,query(lc(k),l,mid)),add(res,query(rc(k),mid+1,r));
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)x=read(),change(1,l,r);
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
struct matrix
{
	ll a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		matrix c;int i,j;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
			c.a[i][j]=(a[i][j]+b.a[i][j])%MOD;
		return c;
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			for(k=0;k<2;k++)c.a[i][j]+=a[i][k]*b.a[k][j];
			c.a[i][j]%=MOD;
		}
		return c;
	}
};
matrix f(int x)
{
	matrix a(0,1,1,1),p(0,1,1,1);
	for(;x;x>>=1)
	{
		if(x&1)a=a*p;
		p=p*p;
	}
	return a;
}
struct node
{
	int l,r,x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5];
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,int x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)res=(res+query(lc(k),l,r))%MOD;
	else if(l>mid)res=(res+query(rc(k),l,r))%MOD;
	else res=((res+query(lc(k),l,mid))%MOD+query(rc(k),mid+1,r))%MOD;
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)if(n<100)change(1,l,r,read());else read();
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
struct matrix
{
	ll a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			for(k=0;k<2;k++)c.a[i][j]+=a[i][k]*b.a[k][j];
			c.a[i][j]%=MOD;
		}
		return c;
	}
};
matrix f(int x)
{
	matrix a(0,1,1,1),p(0,1,1,1);
	for(;x;x>>=1)
	{
		if(x&1)a=a*p;
		p=p*p;
	}
	return a;
}
struct node
{
	int l,r,x;matrix s;
}t[MAXN*4];
int a[MAXN+5],tn;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s.a[0][0]=(t[lc(k)].s.a[0][0]+t[rc(k)].s.a[0][0])%MOD;
	t[k].s.a[0][1]=(t[lc(k)].s.a[0][1]+t[rc(k)].s.a[0][1])%MOD;
}
void inc(int k,int x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s.a[0][0]=(t[lc(k)].s.a[0][0]+t[rc(k)].s.a[0][0])%MOD;
	t[k].s.a[0][1]=(t[lc(k)].s.a[0][1]+t[rc(k)].s.a[0][1])%MOD;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)res=(res+query(lc(k),l,r))%MOD;
	else if(l>mid)res=(res+query(rc(k),l,r))%MOD;
	else{res=(res+query(lc(k),l,mid))%MOD;res=(res+query(rc(k),mid+1,r))%MOD;}
	t[k].s.a[0][0]=(t[lc(k)].s.a[0][0]+t[rc(k)].s.a[0][0])%MOD;
	t[k].s.a[0][1]=(t[lc(k)].s.a[0][1]+t[rc(k)].s.a[0][1])%MOD;
	return res;
}
int main()
{
	int n,m,i,t,l,r,x;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1){x=read();change(1,l,r,x);}
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	inline matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
}p[50];
inline matrix operator+(matrix a,matrix b)
{
	add(a.a[0][0],b.a[0][0]);add(a.a[0][1],b.a[0][1]);
	return matrix(a.a[0][0],a.a[0][1]);
}
inline matrix operator*(matrix a,matrix b)
{
	matrix c;int i,j,k;ll x;
	for(i=0;i<2;i++)for(j=0;j<2;j++)
	{
		x=0;
		for(k=0;k<2;k++)x+=(ll)a.a[i][k]*b.a[k][j];
		c.a[i][j]=x%MOD;
	}
	return c;
}
inline void pow(matrix&a,ll x)
{
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x,ans;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=matrix(1);pow(t[k].s,a[l]);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
inline void inc(int k,ll x)
{
	t[k].x+=x;
	pow(t[k].s,x);
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){add(ans,t[k].s.a[0][1]);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)query(lc(k),l,r);
	else if(l>mid)query(rc(k),l,r);
	else query(lc(k),l,mid),query(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)x=read(),change(1,l,r);
		else ans=0,query(1,l,r),printf("%d\n",ans);
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
struct matrix
{
	ll a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		matrix c;int i,j;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
			c.a[i][j]=(a[i][j]+b.a[i][j])%MOD;
		return c;
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			for(k=0;k<2;k++)c.a[i][j]+=a[i][k]*b.a[k][j];
			c.a[i][j]%=MOD;
		}
		return c;
	}
};
matrix f(int x)
{
	matrix a(0,1,1,1),p(0,1,1,1);
	for(;x;x>>=1)
	{
		if(x&1)a=a*p;
		p=p*p;
	}
	return a;
}
struct node
{
	int l,r,x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],n;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,int x)
{
	t[k].x+=x;if(n>100)return;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)res=(res+query(lc(k),l,r))%MOD;
	else if(l>mid)res=(res+query(rc(k),l,r))%MOD;
	else res=((res+query(lc(k),l,mid))%MOD+query(rc(k),mid+1,r))%MOD;
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int m,i,t,l,r;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)change(1,l,r,read());
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	inline matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
}p[50];
inline matrix operator+(matrix a,matrix b)
{
	add(a.a[0][0],b.a[0][0]);add(a.a[0][1],b.a[0][1]);
	return matrix(a.a[0][0],a.a[0][1]);
}
inline matrix operator*(matrix a,matrix b)
{
	matrix c;int i,j,k;ll x;
	for(i=0;i<2;i++)for(j=0;j<2;j++)
	{
		x=0;
		for(k=0;k<2;k++)x+=(ll)a.a[i][k]*b.a[k][j];
		c.a[i][j]=x%MOD;
	}
	return c;
}
inline matrix f(ll x)
{
	matrix a(0,1,1,1);
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
	return a;
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x,ans;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,ll x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){add(ans,t[k].s.a[0][1]);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)query(lc(k),l,r);
	else if(l>mid)query(rc(k),l,r);
	else query(lc(k),l,mid),query(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)x=read(),change(1,l,r);
		else ans=0,query(1,l,r),printf("%d\n",ans);
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
struct matrix
{
	ll a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		matrix c;int i,j;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
			c.a[i][j]=(a[i][j]+b.a[i][j])%MOD;
		return c;
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			for(k=0;k<2;k++)c.a[i][j]+=a[i][k]*b.a[k][j];
			c.a[i][j]%=MOD;
		}
		return c;
	}
};
matrix f(int x)
{
	matrix a(0,1,1,1),p(0,1,1,1);
	for(;x;x>>=1)
	{
		if(x&1)a=a*p;
		p=p*p;
	}
	return a;
}
struct node
{
	int l,r,x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5];
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,int x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)res=(res+query(lc(k),l,r))%MOD;
	else if(l>mid)res=(res+query(rc(k),l,r))%MOD;
	else res=((res+query(lc(k),l,mid))%MOD+query(rc(k),mid+1,r))%MOD;
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if{(t==1){if(n>100)read();else change(1,l,r,read());}
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
struct matrix
{
	ll a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		matrix c;int i,j;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
			c.a[i][j]=(a[i][j]+b.a[i][j])%MOD;
		return c;
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			for(k=0;k<2;k++)c.a[i][j]+=a[i][k]*b.a[k][j];
			c.a[i][j]%=MOD;
		}
		return c;
	}
};
matrix f(int x)
{
	matrix a(0,1,1,1),p(0,1,1,1);
	for(;x;x>>=1)
	{
		if(x&1)a=a*p;
		p=p*p;
	}
	return a;
}
struct node
{
	int l,r,x;matrix s;
}t[MAXN*4];
int a[MAXN+5],tn;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,int x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)res=(res+query(lc(k),l,r))%MOD;
	else if(l>mid)res=(res+query(rc(k),l,r))%MOD;
	else res=((res+query(lc(k),l,mid))%MOD+query(rc(k),mid+1,r))%MOD;
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r,x;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1){x=read();change(1,l,r,x);}
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	inline matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
}p[50];
inline matrix operator+(matrix a,matrix b)
{
	add(a.a[0][0],b.a[0][0]);add(a.a[0][1],b.a[0][1]);
	return matrix(a.a[0][0],a.a[0][1]);
}
inline matrix operator*(matrix a,matrix b)
{
	matrix c;int i,j,k;ll x;
	for(i=0;i<2;i++)for(j=0;j<2;j++)
	{
		x=0;
		for(k=0;k<2;k++)x+=(ll)a.a[i][k]*b.a[k][j];
		c.a[i][j]=x%MOD;
	}
	return c;
}
inline matrix f(ll x)
{
	matrix a(0,1,1,1);
	for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
	return a;
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x,ans;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,ll x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){add(ans,t[k].s.a[0][1]);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)query(lc(k),l,r);
	else if(l>mid)query(rc(k),l,r);
	else query(lc(k),l,mid),query(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%d",&a[i]);
	build(1,1,n);
	while(m--)
	{
		scanf("%d%d%d",&t,&l,&r);
		if(t==1){scanf("%d",&x);change(1,l,r);}
		else ans=0,query(1,l,r),printf("%d\n",ans);
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
struct matrix
{
	ll a[2][2];
	matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
	matrix operator+(matrix b)
	{
		matrix c;int i,j;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
			c.a[i][j]=(a[i][j]+b.a[i][j])%MOD;
		return c;
	}
	matrix operator*(matrix b)
	{
		matrix c;int i,j,k;
		for(i=0;i<2;i++)for(j=0;j<2;j++)
		{
			for(k=0;k<2;k++)c.a[i][j]+=a[i][k]*b.a[k][j];
			c.a[i][j]%=MOD;
		}
		return c;
	}
};
matrix f(ll x)
{
	matrix a(0,1,1,1),p(0,1,1,1);
	for(;x;x>>=1)
	{
		if(x&1)a=a*p;
		p=p*p;
	}
	return a;
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5];
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=f(a[l]-1);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void inc(int k,int x)
{
	t[k].x+=x;
	t[k].s=t[k].s*f(x-1);
}
void change(int k,int l,int r,int x)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r,x);
	else if(l>mid)change(rc(k),l,r,x);
	else{change(lc(k),l,mid,x);change(rc(k),mid+1,r,x);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r)return t[k].s.a[0][1];
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1,res=0;
	if(r<=mid)res=(res+query(lc(k),l,r))%MOD;
	else if(l>mid)res=(res+query(rc(k),l,r))%MOD;
	else res=((res+query(lc(k),l,mid))%MOD+query(rc(k),mid+1,r))%MOD;
	t[k].s=t[lc(k)].s+t[rc(k)].s;
	return res;
}
int main()
{
	int n,m,i,t,l,r;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)change(1,l,r,read());
		else printf("%d\n",query(1,l,r));
	}
}


#include<cstdio>
#define MAXN 100000
#define MOD 1000000007
#define ll long long
#define lc(x) (x<<1)
#define rc(x) ((x<<1)+1)
int read()
{
	int x=0;char c;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
inline void add(int&a,int b){a+=b;if(a>=MOD)a-=MOD;}
struct matrix
{
	int a[2][2];
	inline matrix(int x1=0,int x2=0,int x3=0,int x4=0)
	{
		a[0][0]=x1;a[0][1]=x2;
		a[1][0]=x3;a[1][1]=x4;
	}
}p[51];
inline matrix operator+(matrix a,matrix&b)
{
	add(a.a[0][0],b.a[0][0]);
	add(a.a[0][1],b.a[0][1]);
	return a;
}
inline matrix operator*(matrix&a,matrix&b)
{
	matrix c;int i,j,k;ll x;
	for(i=0;i<2;i++)for(j=0;j<2;j++)
	{
		x=0;
		for(k=0;k<2;k++)x+=(ll)a.a[i][k]*b.a[k][j];
		c.a[i][j]=x%MOD;
	}
	return c;
}
inline void pow(matrix&a,ll x)
{
	if(x==536870911)a=a*p[50];
	else for(int i=0;x;i++,x>>=1)if(x&1)a=a*p[i];
}
struct node
{
	int l,r;ll x;
	matrix s;
}t[MAXN*4];
int a[MAXN+5],x,ans;
void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].x=0;
	if(l==r){t[k].s=matrix(1);pow(t[k].s,a[l]);return;}
	int mid=(l+r)>>1;
	build(lc(k),l,mid);
	build(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
inline void inc(int k,ll x)
{
	t[k].x+=x;
	pow(t[k].s,x);
}
void change(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){inc(k,x);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)change(lc(k),l,r);
	else if(l>mid)change(rc(k),l,r);
	else{change(lc(k),l,mid);change(rc(k),mid+1,r);}
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
void query(int k,int l,int r)
{
	if(t[k].l==l&&t[k].r==r){add(ans,t[k].s.a[0][1]);return;}
	if(t[k].x){inc(lc(k),t[k].x);inc(rc(k),t[k].x);t[k].x=0;}
	int mid=(t[k].l+t[k].r)>>1;
	if(r<=mid)query(lc(k),l,r);
	else if(l>mid)query(rc(k),l,r);
	else query(lc(k),l,mid),query(rc(k),mid+1,r);
	t[k].s=t[lc(k)].s+t[rc(k)].s;
}
int main()
{
	int n,m,i,t,l,r;
	p[0]=matrix(0,1,1,1);
	for(i=1;i<50;i++)p[i]=p[i-1]*p[i-1];
	p[50]=matrix(520757983,380127118,380127118,900885101);
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	while(m--)
	{
		t=read();l=read();r=read();
		if(t==1)x=read(),change(1,l,r);
		else ans=0,query(1,l,r),printf("%d\n",ans);
	}
}


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

const long long Mod = 1e9+7;
const long long Inf = 1e18;
const long long Lim = 1e5+1e3;
const double eps = 1e-10;
const int sz = 2;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

struct matrix {
	ll a[sz][sz];
};

ll Arr[Lim];
matrix lazy[4*Lim];
pll Tree[4*Lim];
matrix id = {{{1,0},{0,1}}}, base = {{{1,1},{1,0}}};

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

matrix operator+(matrix m1, matrix m2) {
	matrix ret ={{}};
	rep(i, sz)
		rep(j, sz)
			ret.a[i][j] = (m1.a[i][j]+m2.a[i][j])%Mod;

	return ret;
}

matrix operator*(matrix m1, matrix m2) {
	matrix ret ={{}};
	rep(i, sz)
		rep(j, sz)
			rep(k, sz)
				ret.a[i][j] = (ret.a[i][j]+m1.a[i][k]*m2.a[k][j])%Mod;

	/*cout << m1.a[0][0] << ' ' << m1.a[0][1] << '\t' << m2.a[0][0] << ' ' << m2.a[0][1] << '\t' << ret.a[0][0] << ' ' << ret.a[0][1] << '\n';
	cout << m1.a[1][0] << ' ' << m1.a[1][1] << '\t' << m2.a[1][0] << ' ' << m2.a[1][1] << '\t' << ret.a[1][0] << ' ' << ret.a[1][1] << '\n';*/
	return ret;
}

matrix matpow(matrix m, ll power) {
	matrix ret;
	if (power == 0) return id;

	ret = matpow(m, power/2);
	ret = ret*ret;
	if (power&1) ret = ret*m;
	return ret;
}

pll Fibo(pll input, matrix mat) {
	/*cout << mat.a[0][0] << ' ' << mat.a[0][1] << '\n';
	cout << mat.a[1][0] << ' ' << mat.a[1][1] << '\n';
	*/return mp(((mat.a[0][0]*input.F)+(mat.a[0][1]*input.S))%Mod, ((mat.a[1][0]*input.F)+(mat.a[1][1]*input.S))%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1ll,0ll), matpow(base, Arr[a]-1));
		// cout << a << ' ' << Tree[Node].F << ' ' << Tree[Node].S << '\n';
		lazy[Node] = id;
	} else if (a < b) {
		init_tree(2*Node, a, (a+b)/2);
		init_tree(2*Node+1, (a+b)/2+1, b);
		Tree[Node] = Tree[2*Node]+Tree[2*Node+1];
		lazy[Node] = id;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node].a[1][0] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2*Node] = lazy[Node]*lazy[2*Node];
			lazy[2*Node+1] = lazy[Node]*lazy[2*Node+1];
		}

		lazy[Node] = id;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			matrix tmp = matpow(base, value);
			if (a != b) {
				lazy[2*Node] = tmp*lazy[2*Node];
				lazy[2*Node+1] = tmp*lazy[2*Node+1];
			}
			Tree[Node] = Fibo(Tree[Node], tmp);
		} else {
			update_tree(2*Node, start, end, value, a, (a+b) / 2);
			update_tree(2*Node+1, start, end, value, (a+b) / 2+1, b);
			Tree[Node] = Tree[2*Node]+Tree[2*Node+1];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node].a[1][0] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2*Node] = lazy[Node]*lazy[2*Node];
			lazy[2*Node+1] = lazy[Node]*lazy[2*Node+1];
		}

		lazy[Node] = id;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		int mid = (a+b) / 2;
		ll SUM1, SUM2;
		if (start <= a && b <= end) {
			//cout << a << ' ' << b << ' ' << Tree[Node] << '\n';
			return Tree[Node].F;
		} else {
			SUM1 = query(2*Node, start, end, a, mid);
			SUM2 = query(2*Node+1, start, end, mid+1, b);
			return (SUM1+SUM2)%Mod;
		}
	}
}

void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << ' ' << lazy[Node].a[0][0] << ' ' << lazy[Node].a[0][1] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2+1, b);
	}

}

int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9 + 7;
const long long Inf = 1e18;
const long long Lim = 1e5 + 1e3;
const double eps = 1e-10;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

ll Arr[Lim], lazy[4*Lim];
pll Tree[4*Lim];

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

void mult_mat(ll mat1[2][2], ll mat2[2][2], ll op[2][2]) {
	op[0][0] = ((mat1[0][0]*mat2[0][0])%Mod + (mat1[0][1]*mat2[1][0])%Mod)%Mod;
	op[0][1] = ((mat1[0][0]*mat2[0][1])%Mod + (mat1[0][1]*mat2[1][1])%Mod)%Mod;
	op[1][0] = ((mat1[1][0]*mat2[0][0])%Mod + (mat1[1][1]*mat2[1][0])%Mod)%Mod;
	op[1][1] = ((mat1[1][0]*mat2[0][1])%Mod + (mat1[1][1]*mat2[1][1])%Mod)%Mod;
}

void getstuff(ll output[2][2], int power) {
	ll tmp[2][2] = {{1,1},{1,0}}, tmp2[2][2], tmp3[2][2];
	if (power == 0) {
		output[0][0] = 1, output[0][1] = 0, output[1][0] = 0, output[1][1] = 1;
		return;
	}
	if (power == 1) {
		output[0][0] = 1, output[0][1] = 1, output[1][0] = 1, output[1][1] = 0;
		return;
	}
	getstuff(tmp2, power/2);
	if (power%2) {
		mult_mat(tmp2, tmp2, tmp3);
		mult_mat(tmp3, tmp, output);
	} else
		mult_mat(tmp2, tmp2, output);

}

pll Fibo(pll input, int x) {
	ll tmp[2][2];
	getstuff(tmp, x);
	return mp(((tmp[0][0]*input.F)%Mod + (tmp[0][1]*input.S)%Mod)%Mod, ((tmp[1][0]*input.F)%Mod + (tmp[1][1]*input.S)%Mod)%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1,0), Arr[a]-1);
		// cout << a << ' ' << Tree[Node].F << ' ' << Tree[Node].S << '\n';
		lazy[Node] = 0;
	} else if (a < b) {
		init_tree(2 * Node, a, (a + b) / 2);
		init_tree(2 * Node + 1, (a + b) / 2 + 1, b);
		Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		lazy[Node] = 0;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			if (a != b) {
				lazy[2 * Node] += value;
				lazy[2 * Node + 1] += value;
			}
			Tree[Node] = Fibo(Tree[Node], value);
		} else {
			update_tree(2 * Node, start, end, value, a, (a + b) / 2);
			update_tree(2 * Node + 1, start, end, value, (a + b) / 2 + 1, b);
			Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		int mid = (a + b) / 2;
		ll SUM1, SUM2;
		if (start <= a && b <= end) {
			//cout << a << ' ' << b << ' ' << Tree[Node] << '\n';
			return Tree[Node].F;
		} else {
			SUM1 = query(2 * Node, start, end, a, mid);
			SUM2 = query(2 * Node + 1, start, end, mid + 1, b);
			return (SUM1 + SUM2)%Mod;
		}
	}
}

void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << lazy[Node] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2 + 1, b);
	}

}

int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9+7;
const long long Inf = 1e18;
const long long Lim = 1e5+1e3;
const double eps = 1e-10;
const int sz = 2;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

struct matrix {
	ll a[sz][sz];
};

ll Arr[Lim];
matrix lazy[4*Lim];
pll Tree[4*Lim];
matrix id = {{{1,0},{0,1}}}, base = {{{1,1},{1,0}}}, gtmp;

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

matrix operator+(matrix m1, matrix m2) {
	matrix ret ={{}};
	rep(i, sz)
		rep(j, sz)
			ret.a[i][j] = (m1.a[i][j]+m2.a[i][j])%Mod;

	return ret;
}

matrix operator*(matrix m1, matrix m2) {
	matrix ret ={{}};
	rep(i, sz)
		rep(j, sz)
			rep(k, sz)
				ret.a[i][j] = (ret.a[i][j]+m1.a[i][k]*m2.a[k][j])%Mod;

	return ret;
}

matrix matpow(matrix m, ll power) {
	matrix ret;
	if (power == 0) return id;

	ret = matpow(m, power/2);
	ret = ret*ret;
	if (power&1) ret = ret*m;
	return ret;
}

pll Fibo(pll input, matrix mat) {
	return mp(((mat.a[0][0]*input.F)+(mat.a[0][1]*input.S))%Mod, ((mat.a[1][0]*input.F)+(mat.a[1][1]*input.S))%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1ll,0ll), matpow(base, Arr[a]-1));
		lazy[Node] = id;
	} else if (a < b) {
		init_tree(2*Node, a, (a+b)/2);
		init_tree(2*Node+1, (a+b)/2+1, b);
		Tree[Node] = Tree[2*Node]+Tree[2*Node+1];
		lazy[Node] = id;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node].a[1][0] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);
		int c1 = Node << 1, c2=c1|1;
		if(a != b) {
			lazy[c1] = lazy[Node]*lazy[c1];
			lazy[c2] = lazy[Node]*lazy[c2];
		}

		lazy[Node] = id;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			if (a != b) {
				lazy[2*Node] = gtmp*lazy[2*Node];
				lazy[2*Node+1] = gtmp*lazy[2*Node+1];
			}
			Tree[Node] = Fibo(Tree[Node], gtmp);
		} else {
			int c1 = Node << 1, c2=c1|1, mid=(a+b)>>1;
			update_tree(c1, start, end, value, a, mid);
			update_tree(c2, start, end, value, mid+1, b);
			Tree[Node] = Tree[c1]+Tree[c2];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node].a[1][0] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);
		int c1 = Node << 1, c2=c1|1;
		if(a != b) {
			lazy[c1] = lazy[Node]*lazy[c1];
			lazy[c2] = lazy[Node]*lazy[c2];
		}

		lazy[Node] = id;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		if (start <= a && b <= end) {
			return Tree[Node].F;
		} else {
			int c1 = Node << 1, c2=c1|1, mid=(a+b)>>1;
			ll sum = query(c1, start, end, a, mid)+query(c2, start, end, mid+1, b);
			if (sum >= Mod) sum -= Mod;
			return sum;
		}
	}
}
/*
void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << ' ' << lazy[Node].a[0][0] << ' ' << lazy[Node].a[0][1] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2+1, b);
	}

}
*/
int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			gtmp = matpow(base, delta);
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9 + 7;
const long long Inf = 1e18;
const long long Lim = 1e5 + 1e3;
const double eps = 1e-10;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

ll Arr[Lim], lazy[4*Lim];
pll Tree[4*Lim];
map <ll, pair<pll, pll> > heap;

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

void mult_mat(ll mat1[2][2], ll mat2[2][2], ll op[2][2]) {
	op[0][0] = ((mat1[0][0]*mat2[0][0])%Mod + (mat1[0][1]*mat2[1][0])%Mod)%Mod;
	op[0][1] = ((mat1[0][0]*mat2[0][1])%Mod + (mat1[0][1]*mat2[1][1])%Mod)%Mod;
	op[1][0] = ((mat1[1][0]*mat2[0][0])%Mod + (mat1[1][1]*mat2[1][0])%Mod)%Mod;
	op[1][1] = ((mat1[1][0]*mat2[0][1])%Mod + (mat1[1][1]*mat2[1][1])%Mod)%Mod;
}

void getstuff(ll output[2][2], ll power) {
	ll tmp[2][2] = {{1,1},{1,0}}, tmp2[2][2], tmp3[2][2];
	if (power == 0) {
		output[0][0] = 1, output[0][1] = 0, output[1][0] = 0, output[1][1] = 1;
		return;
	}
	if (power == 1) {
		output[0][0] = 1, output[0][1] = 1, output[1][0] = 1, output[1][1] = 0;
		return;
	}
	map<ll, pair<pll, pll> >::iterator it = heap.find(power);
	if (it != heap.end()) {
		output[0][0] = (it->second).F.F;
		output[0][1] = (it->second).F.S;
		output[1][0] = (it->second).S.F;
		output[1][1] = (it->second).S.S;
		return;
	}
	getstuff(tmp2, power/2);
	if (power%2) {
		mult_mat(tmp2, tmp2, tmp3);
		mult_mat(tmp3, tmp, output);
	} else
		mult_mat(tmp2, tmp2, output);

	if (heap.size() < 2500000);
		heap[power] = mp(mp(output[0][0], output[0][1]), mp(output[1][0], output[1][1]));
}

pll Fibo(pll input, ll x) {
	ll tmp[2][2];
	getstuff(tmp, x);
	return mp(((tmp[0][0]*input.F)%Mod + (tmp[0][1]*input.S)%Mod)%Mod, ((tmp[1][0]*input.F)%Mod + (tmp[1][1]*input.S)%Mod)%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1,0), Arr[a]-1);
		// cout << a << ' ' << Tree[Node].F << ' ' << Tree[Node].S << '\n';
		lazy[Node] = 0;
	} else if (a < b) {
		init_tree(2 * Node, a, (a + b) / 2);
		init_tree(2 * Node + 1, (a + b) / 2 + 1, b);
		Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		lazy[Node] = 0;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			if (a != b) {
				lazy[2 * Node] += value;
				lazy[2 * Node + 1] += value;
			}
			Tree[Node] = Fibo(Tree[Node], value);
		} else {
			update_tree(2 * Node, start, end, value, a, (a + b) / 2);
			update_tree(2 * Node + 1, start, end, value, (a + b) / 2 + 1, b);
			Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		int mid = (a + b) / 2;
		ll SUM1, SUM2;
		if (start <= a && b <= end) {
			//cout << a << ' ' << b << ' ' << Tree[Node] << '\n';
			return Tree[Node].F;
		} else {
			SUM1 = query(2 * Node, start, end, a, mid);
			SUM2 = query(2 * Node + 1, start, end, mid + 1, b);
			return (SUM1 + SUM2)%Mod;
		}
	}
}

void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << lazy[Node] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2 + 1, b);
	}

}

int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9 + 7;
const long long Inf = 1e18;
const long long Lim = 1e5 + 1e3;
const double eps = 1e-10;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

ll Arr[Lim], lazy[4*Lim];
pll Tree[4*Lim];
map <ll, pair<pll, pll> > heap;

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

void mult_mat(ll mat1[2][2], ll mat2[2][2], ll op[2][2]) {
	op[0][0] = ((mat1[0][0]*mat2[0][0])%Mod + (mat1[0][1]*mat2[1][0])%Mod)%Mod;
	op[0][1] = ((mat1[0][0]*mat2[0][1])%Mod + (mat1[0][1]*mat2[1][1])%Mod)%Mod;
	op[1][0] = ((mat1[1][0]*mat2[0][0])%Mod + (mat1[1][1]*mat2[1][0])%Mod)%Mod;
	op[1][1] = ((mat1[1][0]*mat2[0][1])%Mod + (mat1[1][1]*mat2[1][1])%Mod)%Mod;
}

void getstuff(ll output[2][2], ll power) {
	ll tmp[2][2] = {{1,1},{1,0}}, tmp2[2][2], tmp3[2][2];
	if (power == 0) {
		output[0][0] = 1, output[0][1] = 0, output[1][0] = 0, output[1][1] = 1;
		return;
	}
	if (power == 1) {
		output[0][0] = 1, output[0][1] = 1, output[1][0] = 1, output[1][1] = 0;
		return;
	}
	map<ll, pair<pll, pll> >::iterator it = heap.find(power);
	if (it != heap.end()) {
		output[0][0] = (it->second).F.F;
		output[0][1] = (it->second).F.S;
		output[1][0] = (it->second).S.F;
		output[1][1] = (it->second).S.S;
		return;
	}
	getstuff(tmp2, power/2);
	if (power%2) {
		mult_mat(tmp2, tmp2, tmp3);
		mult_mat(tmp3, tmp, output);
	} else
		mult_mat(tmp2, tmp2, output);

	assert (heap.size() < 1000000);
		heap[power] = mp(mp(output[0][0], output[0][1]), mp(output[1][0], output[1][1]));
}

pll Fibo(pll input, ll x) {
	ll tmp[2][2];
	getstuff(tmp, x);
	return mp(((tmp[0][0]*input.F)%Mod + (tmp[0][1]*input.S)%Mod)%Mod, ((tmp[1][0]*input.F)%Mod + (tmp[1][1]*input.S)%Mod)%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1,0), Arr[a]-1);
		// cout << a << ' ' << Tree[Node].F << ' ' << Tree[Node].S << '\n';
		lazy[Node] = 0;
	} else if (a < b) {
		init_tree(2 * Node, a, (a + b) / 2);
		init_tree(2 * Node + 1, (a + b) / 2 + 1, b);
		Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		lazy[Node] = 0;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			if (a != b) {
				lazy[2 * Node] += value;
				lazy[2 * Node + 1] += value;
			}
			Tree[Node] = Fibo(Tree[Node], value);
		} else {
			update_tree(2 * Node, start, end, value, a, (a + b) / 2);
			update_tree(2 * Node + 1, start, end, value, (a + b) / 2 + 1, b);
			Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		int mid = (a + b) / 2;
		ll SUM1, SUM2;
		if (start <= a && b <= end) {
			//cout << a << ' ' << b << ' ' << Tree[Node] << '\n';
			return Tree[Node].F;
		} else {
			SUM1 = query(2 * Node, start, end, a, mid);
			SUM2 = query(2 * Node + 1, start, end, mid + 1, b);
			return (SUM1 + SUM2)%Mod;
		}
	}
}

void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << lazy[Node] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2 + 1, b);
	}

}

int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9+7;
const long long Inf = 1e18;
const long long Lim = 1e5+1e3;
const double eps = 1e-10;
const int sz = 2;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

struct matrix {
	ll a[sz][sz];
};

ll Arr[Lim];
matrix lazy[4*Lim];
pll Tree[4*Lim];
matrix id = {{{1,0},{0,1}}}, base = {{{1,1},{1,0}}};

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

matrix operator+(matrix m1, matrix m2) {
	matrix ret ={{}};
	rep(i, sz)
		rep(j, sz)
			ret.a[i][j] = (m1.a[i][j]+m2.a[i][j])%Mod;

	return ret;
}

matrix operator*(matrix m1, matrix m2) {
	matrix ret ={{}};
	rep(i, sz)
		rep(j, sz)
			rep(k, sz)
				ret.a[i][j] = (ret.a[i][j]+m1.a[i][k]*m2.a[k][j])%Mod;

	/*cout << m1.a[0][0] << ' ' << m1.a[0][1] << '\t' << m2.a[0][0] << ' ' << m2.a[0][1] << '\t' << ret.a[0][0] << ' ' << ret.a[0][1] << '\n';
	cout << m1.a[1][0] << ' ' << m1.a[1][1] << '\t' << m2.a[1][0] << ' ' << m2.a[1][1] << '\t' << ret.a[1][0] << ' ' << ret.a[1][1] << '\n';*/
	return ret;
}

matrix matpow(matrix m, ll power) {
	matrix ret;
	if (power == 0) return id;

	ret = matpow(m, power/2);
	ret = ret*ret;
	if (power&1) ret = ret*m;
	return ret;
}

pll Fibo(pll input, matrix mat) {
	/*cout << mat.a[0][0] << ' ' << mat.a[0][1] << '\n';
	cout << mat.a[1][0] << ' ' << mat.a[1][1] << '\n';
	*/return mp(((mat.a[0][0]*input.F)+(mat.a[0][1]*input.S))%Mod, ((mat.a[1][0]*input.F)+(mat.a[1][1]*input.S))%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1ll,0ll), matpow(base, Arr[a]-1));
		// cout << a << ' ' << Tree[Node].F << ' ' << Tree[Node].S << '\n';
		lazy[Node] = id;
	} else if (a < b) {
		init_tree(2*Node, a, (a+b)/2);
		init_tree(2*Node+1, (a+b)/2+1, b);
		Tree[Node] = Tree[2*Node]+Tree[2*Node+1];
		lazy[Node] = id;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node].a[1][0] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			matrix tmp = matpow(base, value);
			lazy[2*Node] = lazy[Node]+lazy[2*Node];
			lazy[2*Node+1] = lazy[Node]+lazy[2*Node+1];
		}

		lazy[Node] = id;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			matrix tmp = matpow(base, value);
			if (a != b) {
				lazy[2*Node] = tmp+lazy[2*Node];
				lazy[2*Node+1] = tmp+lazy[2*Node+1];
			}
			Tree[Node] = Fibo(Tree[Node], tmp);
		} else {
			update_tree(2*Node, start, end, value, a, (a+b) / 2);
			update_tree(2*Node+1, start, end, value, (a+b) / 2+1, b);
			Tree[Node] = Tree[2*Node]+Tree[2*Node+1];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node].a[1][0] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2*Node] = lazy[Node]+lazy[2*Node];
			lazy[2*Node+1] = lazy[Node]+lazy[2*Node+1];
		}

		lazy[Node] = id;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		int mid = (a+b) / 2;
		ll SUM1, SUM2;
		if (start <= a && b <= end) {
			//cout << a << ' ' << b << ' ' << Tree[Node] << '\n';
			return Tree[Node].F;
		} else {
			SUM1 = query(2*Node, start, end, a, mid);
			SUM2 = query(2*Node+1, start, end, mid+1, b);
			return (SUM1+SUM2)%Mod;
		}
	}
}

void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << lazy[Node].a[0][0] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2+1, b);
	}

}

int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9 + 7;
const long long Inf = 1e18;
const long long Lim = 1e5 + 1e3;
const double eps = 1e-10;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

ll Arr[Lim], lazy[4*Lim];
pll Tree[4*Lim];
map <ll, pair<pll, pll> > heap;

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

void mult_mat(ll mat1[2][2], ll mat2[2][2], ll op[2][2]) {
	op[0][0] = ((mat1[0][0]*mat2[0][0])%Mod + (mat1[0][1]*mat2[1][0])%Mod)%Mod;
	op[0][1] = ((mat1[0][0]*mat2[0][1])%Mod + (mat1[0][1]*mat2[1][1])%Mod)%Mod;
	op[1][0] = ((mat1[1][0]*mat2[0][0])%Mod + (mat1[1][1]*mat2[1][0])%Mod)%Mod;
	op[1][1] = ((mat1[1][0]*mat2[0][1])%Mod + (mat1[1][1]*mat2[1][1])%Mod)%Mod;
}

void getstuff(ll output[2][2], ll power) {
	ll tmp[2][2] = {{1,1},{1,0}}, tmp2[2][2], tmp3[2][2];
	if (power == 0) {
		output[0][0] = 1, output[0][1] = 0, output[1][0] = 0, output[1][1] = 1;
		return;
	}
	if (power == 1) {
		output[0][0] = 1, output[0][1] = 1, output[1][0] = 1, output[1][1] = 0;
		return;
	}
	map<ll, pair<pll, pll> >::iterator it = heap.find(power);
	if (it != heap.end()) {
		output[0][0] = (it->second).F.F;
		output[0][1] = (it->second).F.S;
		output[1][0] = (it->second).S.F;
		output[1][1] = (it->second).S.S;
		return;
	}
	getstuff(tmp2, power/2);
	if (power%2) {
		mult_mat(tmp2, tmp2, tmp3);
		mult_mat(tmp3, tmp, output);
	} else
		mult_mat(tmp2, tmp2, output);

	if (heap.size() < 3000000);
		heap[power] = mp(mp(output[0][0], output[0][1]), mp(output[1][0], output[1][1]));
}

pll Fibo(pll input, ll x) {
	ll tmp[2][2];
	getstuff(tmp, x);
	return mp(((tmp[0][0]*input.F)%Mod + (tmp[0][1]*input.S)%Mod)%Mod, ((tmp[1][0]*input.F)%Mod + (tmp[1][1]*input.S)%Mod)%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1,0), Arr[a]-1);
		// cout << a << ' ' << Tree[Node].F << ' ' << Tree[Node].S << '\n';
		lazy[Node] = 0;
	} else if (a < b) {
		init_tree(2 * Node, a, (a + b) / 2);
		init_tree(2 * Node + 1, (a + b) / 2 + 1, b);
		Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		lazy[Node] = 0;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			if (a != b) {
				lazy[2 * Node] += value;
				lazy[2 * Node + 1] += value;
			}
			Tree[Node] = Fibo(Tree[Node], value);
		} else {
			update_tree(2 * Node, start, end, value, a, (a + b) / 2);
			update_tree(2 * Node + 1, start, end, value, (a + b) / 2 + 1, b);
			Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		int mid = (a + b) / 2;
		ll SUM1, SUM2;
		if (start <= a && b <= end) {
			//cout << a << ' ' << b << ' ' << Tree[Node] << '\n';
			return Tree[Node].F;
		} else {
			SUM1 = query(2 * Node, start, end, a, mid);
			SUM2 = query(2 * Node + 1, start, end, mid + 1, b);
			return (SUM1 + SUM2)%Mod;
		}
	}
}

void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << lazy[Node] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2 + 1, b);
	}

}

int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9+7;
const long long Inf = 1e18;
const long long Lim = 1e5+1e3;
const double eps = 1e-10;
const int sz = 2;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

struct matrix {
	ll a[sz][sz];
};

ll Arr[Lim];
matrix lazy[4*Lim];
pll Tree[4*Lim];
matrix id = {{{1,0},{0,1}}}, base = {{{1,1},{1,0}}}, gtmp;

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

matrix operator+(matrix m1, matrix m2) {
	matrix ret ={{}};
	rep(i, sz)
		rep(j, sz)
			ret.a[i][j] = (m1.a[i][j]+m2.a[i][j])%Mod;

	return ret;
}

matrix operator*(matrix m1, matrix m2) {
	matrix ret ={{}};
	rep(i, sz)
		rep(j, sz)
			rep(k, sz)
				ret.a[i][j] = (ret.a[i][j]+m1.a[i][k]*m2.a[k][j])%Mod;

	return ret;
}

matrix matpow(matrix m, ll power) {
	matrix ret;
	if (power == 0) return id;

	ret = matpow(m, power/2);
	ret = ret*ret;
	if (power&1) ret = ret*m;
	return ret;
}

pll Fibo(pll input, matrix mat) {
	return mp(((mat.a[0][0]*input.F)+(mat.a[0][1]*input.S))%Mod, ((mat.a[1][0]*input.F)+(mat.a[1][1]*input.S))%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1ll,0ll), matpow(base, Arr[a]-1));
		lazy[Node] = id;
	} else if (a < b) {
		init_tree(2*Node, a, (a+b)/2);
		init_tree(2*Node+1, (a+b)/2+1, b);
		Tree[Node] = Tree[2*Node]+Tree[2*Node+1];
		lazy[Node] = id;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node].a[1][0] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);
		int c1 = Node << 1, c2=c1|1;
		if(a != b) {
			lazy[c1] = lazy[Node]*lazy[c1];
			lazy[c2] = lazy[Node]*lazy[c2];
		}

		lazy[Node] = id;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			if (a != b) {
				lazy[2*Node] = gtmp*lazy[2*Node];
				lazy[2*Node+1] = gtmp*lazy[2*Node+1];
			}
			Tree[Node] = Fibo(Tree[Node], gtmp);
		} else {
			int c1 = Node << 1, c2=c1|1, mid=(a+b)>>1;
			update_tree(c1, start, end, value, a, mid);
			update_tree(c2, start, end, value, mid+1, b);
			Tree[Node] = Tree[c1]+Tree[c2];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node].a[1][0] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);
		int c1 = Node << 1, c2=c1|1;
		if(a != b) {
			lazy[c1] = lazy[Node]*lazy[c1];
			lazy[c2] = lazy[Node]*lazy[c2];
		}

		lazy[Node] = id;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		if (start <= a && b <= end) {
			return Tree[Node].F;
		} else {
			int c1 = Node << 1, c2=c1|1, mid=(a+b)>>1;
			ll sum = query(c1, start, end, a, mid)+query(c2, start, end, mid+1, b);
			if (sum > Mod) sum -= Mod;
			return Mod;
		}
	}
}
/*
void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << ' ' << lazy[Node].a[0][0] << ' ' << lazy[Node].a[0][1] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2+1, b);
	}

}
*/
int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			gtmp = matpow(base, delta);
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9 + 7;
const long long Inf = 1e18;
const long long Lim = 1e5 + 1e3;
const double eps = 1e-10;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

ll Arr[Lim], lazy[4*Lim];
pll Tree[4*Lim];
map <ll, pair<pll, pll> > heap;

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

void mult_mat(ll mat1[2][2], ll mat2[2][2], ll op[2][2]) {
	op[0][0] = ((mat1[0][0]*mat2[0][0])%Mod + (mat1[0][1]*mat2[1][0])%Mod)%Mod;
	op[0][1] = ((mat1[0][0]*mat2[0][1])%Mod + (mat1[0][1]*mat2[1][1])%Mod)%Mod;
	op[1][0] = ((mat1[1][0]*mat2[0][0])%Mod + (mat1[1][1]*mat2[1][0])%Mod)%Mod;
	op[1][1] = ((mat1[1][0]*mat2[0][1])%Mod + (mat1[1][1]*mat2[1][1])%Mod)%Mod;
}

void getstuff(ll output[2][2], ll power) {
	ll tmp[2][2] = {{1,1},{1,0}}, tmp2[2][2], tmp3[2][2];
	if (power == 0) {
		output[0][0] = 1, output[0][1] = 0, output[1][0] = 0, output[1][1] = 1;
		return;
	}
	if (power == 1) {
		output[0][0] = 1, output[0][1] = 1, output[1][0] = 1, output[1][1] = 0;
		return;
	}
	map<ll, pair<pll, pll> >::iterator it = heap.find(power);
	if (it != heap.end()) {
		output[0][0] = (it->second).F.F;
		output[0][1] = (it->second).F.S;
		output[1][0] = (it->second).S.F;
		output[1][1] = (it->second).S.S;
		return;
	}
	getstuff(tmp2, power/2);
	if (power%2) {
		mult_mat(tmp2, tmp2, tmp3);
		mult_mat(tmp3, tmp, output);
	} else
		mult_mat(tmp2, tmp2, output);

	if (heap.size() < 1000000)
		heap[power] = mp(mp(output[0][0], output[0][1]), mp(output[1][0], output[1][1]));
}

pll Fibo(pll input, ll x) {
	ll tmp[2][2];
	getstuff(tmp, x);
	return mp(((tmp[0][0]*input.F)%Mod + (tmp[0][1]*input.S)%Mod)%Mod, ((tmp[1][0]*input.F)%Mod + (tmp[1][1]*input.S)%Mod)%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1,0), Arr[a]-1);
		// cout << a << ' ' << Tree[Node].F << ' ' << Tree[Node].S << '\n';
		lazy[Node] = 0;
	} else if (a < b) {
		init_tree(2 * Node, a, (a + b) / 2);
		init_tree(2 * Node + 1, (a + b) / 2 + 1, b);
		Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		lazy[Node] = 0;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			if (a != b) {
				lazy[2 * Node] += value;
				lazy[2 * Node + 1] += value;
			}
			Tree[Node] = Fibo(Tree[Node], value);
		} else {
			update_tree(2 * Node, start, end, value, a, (a + b) / 2);
			update_tree(2 * Node + 1, start, end, value, (a + b) / 2 + 1, b);
			Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		int mid = (a + b) / 2;
		ll SUM1, SUM2;
		if (start <= a && b <= end) {
			//cout << a << ' ' << b << ' ' << Tree[Node] << '\n';
			return Tree[Node].F;
		} else {
			SUM1 = query(2 * Node, start, end, a, mid);
			SUM2 = query(2 * Node + 1, start, end, mid + 1, b);
			return (SUM1 + SUM2)%Mod;
		}
	}
}

void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << lazy[Node] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2 + 1, b);
	}

}

int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9 + 7;
const long long Inf = 1e18;
const long long Lim = 1e5 + 1e3;
const double eps = 1e-10;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

ll Arr[Lim], lazy[4*Lim];
pll Tree[4*Lim];

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

void mult_mat(ll mat1[2][2], ll mat2[2][2], ll op[2][2]) {
	op[0][0] = ((mat1[0][0]*mat2[0][0])%Mod + (mat1[0][1]*mat2[1][0])%Mod)%Mod;
	op[0][1] = ((mat1[0][0]*mat2[0][1])%Mod + (mat1[0][1]*mat2[1][1])%Mod)%Mod;
	op[1][0] = ((mat1[1][0]*mat2[0][0])%Mod + (mat1[1][1]*mat2[1][0])%Mod)%Mod;
	op[1][1] = ((mat1[1][0]*mat2[0][1])%Mod + (mat1[1][1]*mat2[1][1])%Mod)%Mod;
}

void getstuff(ll output[2][2], ll power) {
	ll tmp[2][2] = {{1,1},{1,0}}, tmp2[2][2], tmp3[2][2];
	if (power == 0) {
		output[0][0] = 1, output[0][1] = 0, output[1][0] = 0, output[1][1] = 1;
		return;
	}
	if (power == 1) {
		output[0][0] = 1, output[0][1] = 1, output[1][0] = 1, output[1][1] = 0;
		return;
	}
	getstuff(tmp2, power/2);
	if (power%2) {
		mult_mat(tmp2, tmp2, tmp3);
		mult_mat(tmp3, tmp, output);
	} else
		mult_mat(tmp2, tmp2, output);

}

pll Fibo(pll input, ll x) {
	ll tmp[2][2];
	getstuff(tmp, x);
	return mp(((tmp[0][0]*input.F)%Mod + (tmp[0][1]*input.S)%Mod)%Mod, ((tmp[1][0]*input.F)%Mod + (tmp[1][1]*input.S)%Mod)%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1,0), Arr[a]-1);
		// cout << a << ' ' << Tree[Node].F << ' ' << Tree[Node].S << '\n';
		lazy[Node] = 0;
	} else if (a < b) {
		init_tree(2 * Node, a, (a + b) / 2);
		init_tree(2 * Node + 1, (a + b) / 2 + 1, b);
		Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		lazy[Node] = 0;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			if (a != b) {
				lazy[2 * Node] += value;
				lazy[2 * Node + 1] += value;
			}
			Tree[Node] = Fibo(Tree[Node], value);
		} else {
			update_tree(2 * Node, start, end, value, a, (a + b) / 2);
			update_tree(2 * Node + 1, start, end, value, (a + b) / 2 + 1, b);
			Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		int mid = (a + b) / 2;
		ll SUM1, SUM2;
		if (start <= a && b <= end) {
			//cout << a << ' ' << b << ' ' << Tree[Node] << '\n';
			return Tree[Node].F;
		} else {
			SUM1 = query(2 * Node, start, end, a, mid);
			SUM2 = query(2 * Node + 1, start, end, mid + 1, b);
			return (SUM1 + SUM2)%Mod;
		}
	}
}

void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << lazy[Node] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2 + 1, b);
	}

}

int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9 + 7;
const long long Inf = 1e18;
const long long Lim = 1e5 + 1e3;
const double eps = 1e-10;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

int Arr[Lim], lazy[4*Lim];
pll Tree[4*Lim];

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

void mult_mat(ll mat1[2][2], ll mat2[2][2], ll op[2][2]) {
	op[0][0] = ((mat1[0][0]*mat2[0][0])%Mod + (mat1[0][1]*mat2[1][0])%Mod)%Mod;
	op[0][1] = ((mat1[0][0]*mat2[0][1])%Mod + (mat1[0][1]*mat2[1][1])%Mod)%Mod;
	op[1][0] = ((mat1[1][0]*mat2[0][0])%Mod + (mat1[1][1]*mat2[1][0])%Mod)%Mod;
	op[1][1] = ((mat1[1][0]*mat2[0][1])%Mod + (mat1[1][1]*mat2[1][1])%Mod)%Mod;
}

void getstuff(ll output[2][2], int power) {
	ll tmp[2][2] = {{1,1},{1,0}}, tmp2[2][2], tmp3[2][2];
	if (power == 0) {
		output[0][0] = 1, output[0][1] = 0, output[1][0] = 0, output[1][1] = 1;
		return;
	}
	if (power == 1) {
		output[0][0] = 1, output[0][1] = 1, output[1][0] = 1, output[1][1] = 0;
		return;
	}
	getstuff(tmp2, power/2);
	if (power%2) {
		mult_mat(tmp2, tmp2, tmp3);
		mult_mat(tmp3, tmp, output);
	} else
		mult_mat(tmp2, tmp2, output);

}

pll Fibo(pll input, int x) {
	ll tmp[2][2];
	getstuff(tmp, x);
	return mp(((tmp[0][0]*input.F)%Mod + (tmp[0][1]*input.S)%Mod)%Mod, ((tmp[1][0]*input.F)%Mod + (tmp[1][1]*input.S)%Mod)%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1,0), Arr[a]-1);
		// cout << a << ' ' << Tree[Node].F << ' ' << Tree[Node].S << '\n';
		lazy[Node] = 0;
	} else if (a < b) {
		init_tree(2 * Node, a, (a + b) / 2);
		init_tree(2 * Node + 1, (a + b) / 2 + 1, b);
		Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		lazy[Node] = 0;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			if (a != b) {
				lazy[2 * Node] += value;
				lazy[2 * Node + 1] += value;
			}
			Tree[Node] = Fibo(Tree[Node], value);
		} else {
			update_tree(2 * Node, start, end, value, a, (a + b) / 2);
			update_tree(2 * Node + 1, start, end, value, (a + b) / 2 + 1, b);
			Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		int mid = (a + b) / 2;
		ll SUM1, SUM2;
		if (start <= a && b <= end) {
			//cout << a << ' ' << b << ' ' << Tree[Node] << '\n';
			return Tree[Node].F;
		} else {
			SUM1 = query(2 * Node, start, end, a, mid);
			SUM2 = query(2 * Node + 1, start, end, mid + 1, b);
			return (SUM1 + SUM2)%Mod;
		}
	}
}

void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << lazy[Node] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2 + 1, b);
	}

}

int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			update_tree(1, start-1, end-1, delta, 0, n-1);
			// print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}


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

const long long Mod = 1e9 + 7;
const long long Inf = 1e18;
const long long Lim = 1e5 + 1e3;
const double eps = 1e-10;

typedef long long ll;
typedef vector <int> vi;
typedef vector <ll> vl;
typedef pair <ll, ll> pll;
typedef vector <pll> vll;

#define F first
#define S second
#define uint unsigned int
#define mp make_pair
#define pb push_back
#define pi 2*acos(0.0)
#define rep2(i,b,a) for(ll i = (ll)b, _a = (ll)a; i >= _a; i--)
#define rep1(i,a,b) for(ll i = (ll)a, _b = (ll)b; i <= _b; i++)
#define rep(i,n) for(ll i = 0, _n = (ll)n ; i < _n ; i++)
#define mem(a,val) memset(a,val,sizeof(a))

int Arr[Lim], lazy[4*Lim];
pll Tree[4*Lim];

pll operator+(pll x, pll y) {
	return mp((x.F+y.F)%Mod, (x.S+y.S)%Mod);
}

void mult_mat(ll mat1[2][2], ll mat2[2][2], ll op[2][2]) {
	op[0][0] = ((mat1[0][0]*mat2[0][0])%Mod + (mat1[0][1]*mat2[1][0])%Mod)%Mod;
	op[0][1] = ((mat1[0][0]*mat2[0][1])%Mod + (mat1[0][1]*mat2[1][1])%Mod)%Mod;
	op[1][0] = ((mat1[1][0]*mat2[0][0])%Mod + (mat1[1][1]*mat2[1][0])%Mod)%Mod;
	op[1][1] = ((mat1[1][0]*mat2[0][1])%Mod + (mat1[1][1]*mat2[1][1])%Mod)%Mod;
}

void getstuff(ll output[2][2], int power) {
	ll tmp[2][2] = {{1,1},{1,0}}, tmp2[2][2], tmp3[2][2];
	if (power == 0) {
		output[0][0] = 1, output[0][1] = 0, output[1][0] = 0, output[1][1] = 1;
		return;
	}
	if (power == 1) {
		output[0][0] = 1, output[0][1] = 1, output[1][0] = 1, output[1][1] = 0;
		return;
	}
	getstuff(tmp2, power/2);
	if (power%2) {
		mult_mat(tmp2, tmp2, tmp3);
		mult_mat(tmp3, tmp, output);
	} else
		mult_mat(tmp2, tmp2, output);

}

pll Fibo(pll input, int x) {
	ll tmp[2][2];
	getstuff(tmp, x);
	return mp(((tmp[0][0]*input.F)%Mod + (tmp[0][1]*input.S)%Mod)%Mod, ((tmp[1][0]*input.F)%Mod + (tmp[1][1]*input.S)%Mod)%Mod);
}

void init_tree(int Node, int a, int b) {
	if(a == b) {
		Tree[Node] = Fibo(mp(1,0), Arr[a]-1);
		// cout << a << ' ' << Tree[Node].F << ' ' << Tree[Node].S << '\n';
		lazy[Node] = 0;
	} else if (a < b) {
		init_tree(2 * Node, a, (a + b) / 2);
		init_tree(2 * Node + 1, (a + b) / 2 + 1, b);
		Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		lazy[Node] = 0;
	}
}

void update_tree (int Node, int start, int end, int value, int a, int b) {
	//cout << start << ' ' << end << ' ' << a << ' ' << b << endl;
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}

	if(a > b || a > end || b < start) {
		return;
	} else {
		if(start <= a && b <= end) {
			if (a != b) {
				lazy[2 * Node] += value;
				lazy[2 * Node + 1] += value;
			}
			Tree[Node] = Fibo(Tree[Node], value);
		} else {
			update_tree(2 * Node, start, end, value, a, (a + b) / 2);
			update_tree(2 * Node + 1, start, end, value, (a + b) / 2 + 1, b);
			Tree[Node] = Tree[2 * Node] + Tree[2 * Node + 1];
		}
	}

}

ll query(int Node, int start, int end, int a, int b) {
	if (lazy[Node] != 0) {
		Tree[Node] = Fibo(Tree[Node], lazy[Node]);

		if(a != b) {
			lazy[2 * Node] += lazy[Node];
			lazy[2 * Node + 1] += lazy[Node];
		}

		lazy[Node] = 0;
	}
	if (a > b || a > end || b < start) {
		return 0;
	} else {
		int mid = (a + b) / 2;
		ll SUM1, SUM2;
		if (start <= a && b <= end) {
			//cout << a << ' ' << b << ' ' << Tree[Node] << '\n';
			return Tree[Node].F;
		} else {
			SUM1 = query(2 * Node, start, end, a, mid);
			SUM2 = query(2 * Node + 1, start, end, mid + 1, b);
			return (SUM1 + SUM2)%Mod;
		}
	}
}

void print_tree(int depth, int Node, int a, int b) {
	if (a>b) return;
	if (a!=b) {
		print_tree(depth+1, 2*Node, a, (a+b)/2);
	}
	rep(i, depth)
		cout << '\t';

	cout << Tree[Node].F << ' ' << Tree[Node].S << ' ' << lazy[Node] << '\n';

	if (a != b) {
		print_tree(depth+1, 2*Node+1, (a+b)/2 + 1, b);
	}

}

int main() {
	ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n, m, type, start, end, delta;
	cin>>n>>m;
	rep(i, n)
		cin>>Arr[i];

	init_tree(1, 0, n-1);
	// print_tree(0, 1, 0, n-1);
	rep(i, m) {
		cin >> type >> start >> end;
		switch(type) {
			case 1:
			cin>>delta;
			update_tree(1, start-1, end-1, delta, 0, n-1);
			print_tree(0, 1, 0, n-1);
			break;
			case 2:
			cout << query(1, start-1, end-1, 0, n-1)%Mod << '\n';
			break;
		}
	}
	return 0;
}