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

//template
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define rrep(i,a,b) for(int i=(a);i>(b);i--)
#define ALL(v) (v).begin(),(v).end()
typedef long long int ll;
const int inf = 0x3fffffff; const ll INF = 0x1fffffffffffffff; const double eps=1e-12;
string to_str(ll x){string res; while(x)res+=('0'+(x%10)),x/=10; reverse(ALL(res)); return res;}
template<class T> inline bool chmax(T& a,T b){ if(a<b){a=b;return 1;}return 0; }
template<class T> inline bool chmin(T& a,T b){ if(a>b){a=b;return 1;}return 0; }
//template end

template<unsigned mod>struct Mint {
    int val;
    int inv() const{
        int tmp,a=val,b=mod,x=1,y=0;
        while(b)tmp=a/b,a-=tmp*b,swap(a,b),x-=tmp*y,swap(x,y);
        if(x<0)x+=mod; return x;
    }
    Mint():val(0){}
    Mint(ll x):val(x>=0?x%mod:mod+(x%mod)){}
    Mint pow(ll t){Mint res=1,b=*this; while(t){if(t&1)res*=b;b*=b;t>>=1;}return res;}
    Mint& operator+=(const Mint& x){if((val+=x.val)>=mod)val-=mod;return *this;}
    Mint& operator-=(const Mint& x){if((val+=mod-x.val)>=mod)val-=mod; return *this;}
    Mint& operator*=(const Mint& x){val=(ll)val*x.val%mod; return *this;}
    Mint& operator/=(const Mint& x){val=(ll)val*x.inv()%mod; return *this;}
    Mint operator+(const Mint& x)const{return Mint(*this)+=x;}
    Mint operator-(const Mint& x)const{return Mint(*this)-=x;}
    Mint operator*(const Mint& x)const{return Mint(*this)*=x;}
    Mint operator/(const Mint& x)const{return Mint(*this)/=x;}
    bool operator==(const Mint& x)const{return val==x.val;}
    bool operator!=(const Mint& x)const{return val!=x.val;}
};
using mint=Mint<1000000007>;
struct factorial {
    vector<mint> Fact, Finv;
public:
    factorial(int maxx){
        Fact.resize(maxx+1),Finv.resize(maxx+1); Fact[0]=mint(1); rep(i,0,maxx)Fact[i+1]=Fact[i]*(i+1);
        Finv[maxx]=mint(1)/Fact[maxx]; rrep(i,maxx,0)Finv[i-1]=Finv[i]*i;
    }
    mint fact(int n,bool inv=0){if(inv)return Finv[n];else return Fact[n];}
    mint nPr(int n,int r){if(n<0||n<r||r<0)return mint(0);else return Fact[n]*Finv[n-r];}
    mint nCr(int n,int r){if(n<0||n<r||r<0)return mint(0);else return Fact[n]*Finv[r]*Finv[n-r];}
};

struct C{
    float x,y;
    C(double _x=0,double _y=0):x(_x),y(_y){}
    C operator~()const{return {x,-y};}
    C operator+(const C& c)const{return {x+c.x,y+c.y};}
    C operator-(const C& c)const{return {x-c.x,y-c.y};}
    C operator*(const C& c)const{return {x*c.x-y*c.y,x*c.y+y*c.x};}
};
vector<C> rt;
void init(int lg=20){
    rt.resize(1<<lg,1);
    rep(k,1,lg){
        int d=1<<k;
        rep(i,0,d){
            if(i&1)rt[d+i-1]=C(cos(2*M_PI*i/d),sin(2*M_PI*i/d));
            else rt[d+i-1]=rt[(d+i)/2-1];
        }
    }
}
void fft(vector<C>& a,bool inv=0,int n=-1){
    if(n==-1)n=a.size();
    if(inv){
        for(int i=1;i<n;i<<=1){
            for(int j=0;j<n;j+=i*2){
                rep(k,0,i){
                    a[i+j+k]=a[i+j+k]*~rt[i*2-1+k];
                    const C tmp=a[j+k]-a[i+j+k];
                    a[j+k]=a[j+k]+a[i+j+k]; a[i+j+k]=tmp;
                }
            }
        }
        //rep(i,0,n)a[i].x/=n,a[i].y/=n;
    }
    else{
        for(int i=n>>1;i;i>>=1){
            for(int j=0;j<n;j+=i*2){
                rep(k,0,i){
                    const C tmp=a[j+k]-a[i+j+k];
                    a[j+k]=a[j+k]+a[i+j+k]; a[i+j+k]=tmp*rt[i*2-1+k];
                }
            }
        }
    }
} //need to initialize

int sz=1<<12; mint ans; factorial fact(8020);
vector<vector<C>> buf(sz,vector<C>(sz));
void fft2d(bool inv=0){
   rep(i,0,(inv?sz:sz/2))fft(buf[i],inv);
   rep(i,0,sz)rep(j,0,i)swap(buf[i][j],buf[j][i]);
   rep(i,0,sz)fft(buf[i],inv);
   if(inv)rep(i,0,sz)rep(j,0,sz)buf[i][j].x/=sz*sz;
}

map<pair<int,int>,int> mp;
void sub(){
   for(auto p1:mp)for(auto p2:mp){
      int a=p1.first.first,b=p1.first.second;
      int c=p2.first.first,d=p2.first.second;
      ans+=fact.nCr(a+b+c+d,a+c)*p1.second*p2.second;
   }
   ans/=2; printf("%d\n",ans.val); exit(0);
}

int main(){
   init(15); int n; scanf("%d",&n);
   rep(i,0,n){
      int h,w; scanf("%d%d",&h,&w); mp[{h,w}]++;
      buf[h][w].x+=1.0; ans-=fact.nCr((h+w)*2,h*2);
   }
   if(mp.size()<=10000)sub();
   fft2d();
   rep(i,0,sz)rep(j,0,sz)buf[i][j]=buf[i][j]*buf[i][j];
   fft2d(1);
   rep(i,0,sz)rep(j,0,sz){
      mint tmp((ll)(buf[i][j].x+0.5));
      ans+=fact.nCr(i+j,i)*tmp;
   } ans/=2;
   printf("%d\n",ans.val);
   return 0;
}

Measured memory_bytes: 144256