#include<bits/stdc++.h>
using namespace std;
#define FastRead ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define int long long int
#define ll int
#define bits_count __builtin_popcountll
#define endl '\n'
#define double long double
#define ld double
#define FOR(i,a,n) for (ll i=(a);i<=(n);++i)
#define RFOR(i,a,n) for (ll i=(n);i>=(a);--i)
#define ZERO(a) memset((a),0,sizeof((a)))
#define MINUS(a) memset((a),-1,sizeof((a)))
#define f first
#define s second
#define pb push_back
#define mk make_pair
#define all(g) g.begin(),g.end()
#define sz(x) (ll)x.size()
#define pr pair<int,int>
int fastMax(int x, int y) { return (((y-x)>>(32-1))&(x^y))^y; }
int fastMin(int x, int y) { return (((y-x)>>(32-1))&(x^y))^x; }
    
// #include <ext/pb_ds/assoc_container.hpp> // Common file
// #include <ext/pb_ds/tree_policy.hpp>     // Including tree_order_statistics_node_updat
// using namespace __gnu_pbds;
// typedef tree<ll, null_type, less_equal<ll>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;
// const int RANDOM = chrono::high_resolution_clock::now().time_since_epoch().count();
// struct chash { int operator()(int x) const { return x ^ RANDOM; }};
// cc_hash_table<int, int, hash<int>> cnt;

const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
int siz = sqrt(MAXN);
vector<int> que[MAXN];
vector<pair<int,pair<int,int>>> qs;

int a[MAXN];
int sum[MAXN];
int pre[MAXN];
int sq[MAXN],cubes[MAXN];
int n,q;

void update(){
    int x3 = 0,x2 = 0,x1 = 0,x0 = 0;

    FOR(i,1,n){
        for(int x:que[i]){
            if(x >= 0){
                x3 = (x3 + 1)%MOD; x2 = (x2-3*x)%MOD; x1 = (x1 + (3*x*x)%MOD)%MOD; x0 = (x0 - cubes[x])%MOD; 
                x2 = (x2 + 6)%MOD; x1 = (x1 - 12*x)%MOD; x0 = (x0 + (6*sq[x])%MOD)%MOD;
                x1 = (x1 + 11)%MOD; x0 = (x0 - (11*x)%MOD)%MOD;
                x0 = (x0 + 6)%MOD;
            }else {
                x = -x;
                x3 = (x3 - 1)%MOD; x2 = (x2+3*x)%MOD; x1 = (x1 - (3*x*x)%MOD)%MOD; x0 = (x0 + cubes[x])%MOD; 
                x2 = (x2 - 6)%MOD; x1 = (x1 + 12*x)%MOD; x0 = (x0 - (6*sq[x])%MOD)%MOD;
                x1 = (x1 - 11)%MOD; x0 = (x0 + (11*x)%MOD)%MOD;
                x0 = (x0 - 6)%MOD;
            }
        } 
        int val = ((cubes[i-1] * x3)%MOD + ((sq[i-1] * x2)%MOD + ((i-1)*x1)%MOD + x0)%MOD)%MOD;  
        a[i] = (a[i] + val)%MOD;
        pre[i] = (pre[i-1] + a[i])%MOD;
        que[i].clear();
    }

    qs.clear();
}


void solve(){
    cin>>n>>q; 
    FOR(i,1,n) sum[i] = (((i*(i+1))%MOD)*(i+2))%MOD;
    FOR(i,1,n) sum[i] = ((sum[i]+sum[i-1])%MOD + MOD)%MOD;
    FOR(i,1,n) sq[i] = (i*i)%MOD,cubes[i] = (i*i*i)%MOD;

    FOR(i,1,q){
        int type; cin>>type;
        int x,y; cin>>x>>y;

        if(type == 0){
            int ans = (pre[y] - pre[x-1])%MOD;
            ans = (ans+MOD)%MOD;
            for(auto qx:qs){
                int xx = qx.s.f,yy = qx.s.s;
                if(x > yy) continue;
                else if(xx > y) continue;
                else {
                    int ox = max(xx,x);
                    int oy = min(yy,y);
                    if(qx.f == 1) ans = (ans + (sum[oy-xx+1] - sum[ox-xx])%MOD)%MOD;
                    else ans = (ans - (sum[oy-xx+1] - sum[ox-xx])%MOD)%MOD; 
                }
                if(ans < 0) ans += MOD;
            }    
            cout<<ans<<endl;
        }else if(type == 1){
            que[x].push_back(x-1);
            que[y+1].push_back(-x+1);
            qs.push_back(mk(1,mk(x,y)));
            if(sz(qs) >= siz) update();
        }else {
            que[x].push_back(-x+1);
            que[y+1].push_back(x-1);
            qs.push_back(mk(-1,mk(x,y)));
            if(sz(qs) >= siz) update();
        }
    }
}
    
signed main(){
    
    FastRead;     
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
    
    
    int t = 1; 
    // cin>>t;
    FOR(i,1,t){
        // cout<<"Case #"<<i<<": ";
        solve();
    }
}
    