import java.util.*;

public class Euler502 {
    static final long MOD = 1000000007;

    static long power(long base, long exp) {
        long res = 1;
        base %= MOD;
        while (exp > 0) {
            if ((exp & 1) == 1)
                res = res * base % MOD;
            base = base * base % MOD;
            exp >>= 1;
        }
        return res;
    }

    static long modInverse(long n) {
        return power(n, MOD - 2);
    }

    static long[] polyMul(long[] a, long[] b, int limitDeg) {
        if (a.length == 0 || b.length == 0)
            return new long[0];
        int rLen = a.length + b.length - 1;
        if (limitDeg >= 0)
            rLen = Math.min(rLen, limitDeg + 1);
        long[] r = new long[rLen];
        for (int i = 0; i < a.length; i++) {
            if (a[i] == 0)
                continue;
            for (int j = 0; j < b.length && i + j < rLen; j++)
                r[i + j] = (r[i + j] + a[i] * b[j]) % MOD;
        }
        return trim(r);
    }

    static long[] polyAdd(long[] a, long[] b) {
        long[] r = new long[Math.max(a.length, b.length)];
        for (int i = 0; i < r.length; i++) {
            long va = i < a.length ? a[i] : 0, vb = i < b.length ? b[i] : 0;
            r[i] = (va + vb) % MOD;
        }
        return trim(r);
    }

    static long[] polySub(long[] a, long[] b) {
        long[] r = new long[Math.max(a.length, b.length)];
        for (int i = 0; i < r.length; i++) {
            long va = i < a.length ? a[i] : 0, vb = i < b.length ? b[i] : 0;
            r[i] = (va - vb + MOD) % MOD;
        }
        return trim(r);
    }

    static long[] trim(long[] a) {
        int n = a.length;
        while (n > 0 && a[n - 1] == 0)
            n--;
        return Arrays.copyOf(a, n);
    }

    // 2x2 matrix of polynomials
    static long[][][] matMul(long[][][] A, long[][][] B, int td) {
        long[][][] C = new long[2][2][0];
        for (int i = 0; i < 2; i++)
            for (int k = 0; k < 2; k++) {
                if (A[i][k].length == 0)
                    continue;
                for (int j = 0; j < 2; j++) {
                    if (B[k][j].length == 0)
                        continue;
                    C[i][j] = polyAdd(C[i][j], polyMul(A[i][k], B[k][j], td));
                }
            }
        return C;
    }

    static long[][][] matId(int td) {
        long[][][] I = new long[2][2][0];
        I[0][0] = new long[] { 1 };
        I[1][1] = new long[] { 1 };
        return I;
    }

    static long[][][] matPow(long[][][] base, long exp, int td) {
        long[][][] res = matId(td);
        while (exp > 0) {
            if ((exp & 1) == 1)
                res = matMul(res, base, td);
            base = matMul(base, base, td);
            exp >>= 1;
        }
        return res;
    }

    static long[][][] getMatrix(int type, int td) {
        long[] one = { 1 }, x = { 0, 1 }, opx = { 1, 1 }, omx = { 1, MOD - 1 }, nx = { 0, MOD - 1 };
        long[][][] M = new long[2][2][];
        if (type == 1) {
            M[0][0] = opx;
            M[0][1] = x;
            M[1][0] = nx;
            M[1][1] = omx;
        } else {
            M[0][0] = polySub(new long[0], opx);
            M[0][1] = nx;
            M[1][0] = nx;
            M[1][1] = omx;
        }
        return M;
    }

    static long solveBostanMori(long w, long h, int type) {
        long[][][] M = getMatrix(type, -1);
        long[][][] Mh = matPow(M, h, -1);
        long[] P = Mh[0][1], Q = Mh[1][1];
        long k = w;
        while (k > 0) {
            long[] Qn = Q.clone();
            for (int i = 1; i < Qn.length; i += 2)
                if (Qn[i] != 0)
                    Qn[i] = MOD - Qn[i];
            long[] U = polyMul(P, Qn, -1), V = polyMul(Q, Qn, -1);
            int par = (int) (k % 2);
            List<Long> np = new ArrayList<>(), nq = new ArrayList<>();
            for (int i = par; i < U.length; i += 2)
                np.add(U[i]);
            for (int i = 0; i < V.length; i += 2)
                nq.add(V[i]);
            P = np.stream().mapToLong(Long::longValue).toArray();
            Q = nq.stream().mapToLong(Long::longValue).toArray();
            k /= 2;
        }
        long p0 = P.length > 0 ? P[0] : 0, q0 = Q.length > 0 ? Q[0] : 0;
        return p0 * modInverse(q0) % MOD;
    }

    static long solveTrunc(long w, long h, int type) {
        int W = (int) w;
        long[][][] M = getMatrix(type, W);
        long[][][] Mh = matPow(M, h, W);
        long[] P = Mh[0][1], Q = Mh[1][1];
        if (Q.length == 0 || Q[0] == 0)
            return 0;
        long[] invQ = new long[W + 1];
        long invQ0 = modInverse(Q[0]);
        invQ[0] = invQ0;
        for (int i = 1; i <= W; i++) {
            long sum = 0;
            for (int j = 1; j <= i; j++)
                if (j < Q.length)
                    sum = (sum + Q[j] * invQ[i - j]) % MOD;
            invQ[i] = (MOD - sum) % MOD * invQ0 % MOD;
        }
        long ans = 0;
        for (int i = 0; i <= W; i++) {
            long pv = i < P.length ? P[i] : 0;
            if (pv != 0)
                ans = (ans + pv * invQ[W - i]) % MOD;
        }
        return ans;
    }

    static long getCountLE(long w, long h, int type) {
        if (h == 0)
            return 0;
        return w > 20000 ? solveBostanMori(w, h, type) : solveTrunc(w, h, type);
    }

    static long solveExactH(long w, long h) {
        if (h <= 0)
            return 0;
        long inv2 = modInverse(2);
        long eh = (getCountLE(w, h, 1) + getCountLE(w, h, -1)) % MOD * inv2 % MOD;
        long eh1 = (getCountLE(w, h - 1, 1) + getCountLE(w, h - 1, -1)) % MOD * inv2 % MOD;
        return (eh - eh1 + MOD) % MOD;
    }

    public static void main(String[] args) {
        long a1 = solveExactH(1000000000000L, 100);
        long a2 = solveExactH(10000, 10000);
        long a3 = solveExactH(100, 1000000000000L);
        System.out.println((a1 + a2 + a3) % MOD);
    }
}
