use std::cmp::Reverse;
use std::cmp::max;
use std::collections::VecDeque;
use std::cmp::min;
use std::collections::BTreeSet;
use std::cmp::Ordering;
use std::fmt::Debug;

fn read_line() -> String {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).expect("No Line");
    buffer
}
fn read_lines<T: std::str::FromStr>(count: usize) -> Vec<T> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(buffer.trim().parse().ok().expect("Can't Parse"));
        buffer.clear();
    }
    vec
}
fn read_tabulate<R, T: Fn(&str)->R> (count: usize, transformer: T) -> Vec<R> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(transformer(buffer.trim()));
        buffer.clear();
    }
    vec
}
fn read_value<T: std::str::FromStr>() -> T {
    read_line().trim().parse().ok().unwrap()
}
fn read_values<T: std::str::FromStr>() -> Vec<T> {
    read_line().trim().split(' ').map(|x| x.parse().ok().expect("Can't Parse")).collect::<Vec<T>>()
}
macro_rules! freeze {
    ($($id:ident), *) => {
        $(let $id = $id;)*
    };
}
macro_rules! read {
    (mut $ident: ident: [$ty:ty]) => {
        let mut $ident = read_values::<$ty>();
    };
    ($ident: ident: [$ty:ty]) => {
        let $ident = read_values::<$ty>();
    };
    ($($token: tt)*) => {
        let mut iter = read_values::<String>().into_iter();
        read_from_iter!(iter; $($token)*);
    };
}
macro_rules! read_from_iter {
    ($iter:expr; mut $ident:ident:$ty:ty, $($rest:tt)*) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; $ident:ident:$ty:ty, $($rest:tt)*) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; mut $ident:ident:$ty:ty) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter:expr; $ident:ident:$ty:ty) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter: expr; ) => {};
}
struct KeyValue<K, V> {
    key: K,
    value: V
}
impl <K: PartialOrd, V> PartialEq for KeyValue<K, V> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
impl <K: PartialOrd, V> Eq for KeyValue<K, V> {}
impl <K: PartialOrd, V> PartialOrd for KeyValue<K, V> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K: PartialOrd, V> Ord for KeyValue<K, V> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.key.partial_cmp(&other.key).ok_or("Can't Compare").unwrap()
    }
}
const MOD: i64 = 1000000007i64;
fn factorial(upper_limit: usize) -> (Vec<i64>, Vec<i64>) {
    let mut fact = vec![1i64; upper_limit + 1];
    let mut div = vec![1i64; upper_limit + 1];
    let mut inverse = vec![1i64; upper_limit + 1];
    for i in 2 ..= upper_limit {
        fact[i] = i as i64 * fact[i - 1] % MOD;
        div[i] = (MOD - MOD / i as i64) * div[(MOD % i as i64) as usize] % MOD;
        inverse[i] = div[i] * inverse[i - 1] % MOD;
    }
    (fact, inverse)
}
fn main() {
    read!(r1: i32, c1: i32, r2: i32, c2: i32);
    let (fact, inverse) = factorial((r2 + c2) as usize);
    let combination = |n: i32, r: i32| fact[n as usize] * inverse[r as usize] % MOD * inverse[(n - r) as usize] % MOD;
    let f = |r: i32, c: i32| combination(r + c, r);
    let mut line_sum = f(r1, c1);
    let mut result = line_sum;
    let mut r_min = r1;
    let mut r_max = r1;
    for d in r1 + c1 + 1 ..= r2 + c2 {
        let next_r_min = max(r1, d - c2);
        let next_r_max = min(r2, d - c1);
        line_sum = (line_sum << 1) % MOD;
        line_sum += if next_r_min != r_min {
            MOD - combination(d - 1, r_min)
        }else {
            combination(d - 1, r_min - 1)
        };
        line_sum += if next_r_max != r_max {
            combination(d - 1, r_max + 1)
        }else {
            MOD - combination(d - 1, r_max)
        };
        line_sum %= MOD;
        result += line_sum;
        r_min = next_r_min;
        r_max = next_r_max;
    }
    println!("{}", result % MOD);
}


Measured memory_bytes: 48636