import Control.Monad( replicateM)
import Data.List( sort, group, foldl')
import Control.Applicative( (<$>))
main = do
    n <- readLn
    let readMeatVegi = do
	    [m,v] <- return . map read . words =<< getLine
	    return (m,v)
    mvs <- replicateM n readMeatVegi 
    let res = foldl' (\sm p-> sm+calc p) 0 [(p1,p2) | p1<-plist,
					p2<- dropWhile (/=p1) plist]
	    where plist = flyWeight mvs
	calc ((p1,c1),(p2,c2)) =
	    if p1==p2
		then (numCombi c1 2)*mkBBQ (p1,p1)
		else c1*c2*mkBBQ (p1,p2)
    print $ res `mod` (10^9+7)
	    

--combis::[a] -> Int -> [[a]]
--combis _ 0 = [[]]
--combis [] _ = []
--combis (x:xs) r = ( (x:) <$> combis xs (r-1) ) ++ (combis xs r)

frc::Integer -> Integer
frc 0 = 1
frc n =  n*frc (n-1)

numCombi::Integer -> Integer -> Integer
numCombi n r
    | n>=r	= (frc n) `div` (frc r * frc (n-r))
    | otherwise =  0

flyWeight::Ord a=>[a] -> [(a,Integer)]
flyWeight list =
  let
    gps = group . sort
    compress list = (head list, toInteger . length $ list)
  in
    compress <$> gps list

mkBBQ::((Int,Int), (Int,Int)) -> Integer
mkBBQ ((m1,v1),(m2,v2)) =
  let	total = meats + vegis
	meats = toInteger $ m1+m2
	vegis = toInteger $ v1+v2
  in numCombi total meats