import java.util.ArrayList;
import java.util.HashMap;

public class Euler780 {

    static final long MOD = 1000000007L;

    static long isqrt(long x) {
        if (x <= 0)
            return 0;
        long r = (long) Math.sqrt((double) x);
        while ((r + 1) * (r + 1) <= x)
            r++;
        while (r * r > x && r > 0)
            r--;
        return r;
    }

    static long floorSqrt3Mul(long n) {
        return isqrt(3L * n * n);
    }

    static long floorDivSqrt3(long n, long m) {
        long nn = n * n;
        long den = 3L * m * m;
        long t = isqrt(nn / den);
        while (den * (t + 1) * (t + 1) <= nn)
            t++;
        while (den * t * t > nn && t > 0)
            t--;
        return t;
    }

    static long divisorSummatory(long n) {
        long res = 0;
        long i = 1;
        while (i <= n) {
            long q = n / i;
            long j = n / q;
            res += q * (j - i + 1);
            i = j + 1;
        }
        return res;
    }

    static long gcd(long a, long b) {
        a = Math.abs(a);
        b = Math.abs(b);
        while (b != 0) {
            long t = a % b;
            a = b;
            b = t;
        }
        return a;
    }

    static class Alpha {
        long a, b, c;

        Alpha(long a, long b, long c) {
            this.a = a;
            this.b = b;
            this.c = c;
        }
    }

    static Alpha normalizeAlpha(long a, long b, long c) {
        if (c < 0) {
            a = -a;
            b = -b;
            c = -c;
        }
        long g = gcd(gcd(a, b), c);
        if (g > 1) {
            a /= g;
            b /= g;
            c /= g;
        }
        return new Alpha(a, b, c);
    }

    static long floorDiv(long a, long b) {
        long q = a / b;
        long r = a % b;
        if ((r < 0 && b > 0) || (r > 0 && b < 0))
            q--;
        return q;
    }

    static long floorQsqrt3(long a, long b, long c) {
        if (b == 0)
            return floorDiv(a, c);

        long fb = floorSqrt3Mul(b);
        long x = floorDiv(a + fb, c);
        long bb3 = 3L * b * b;

        while (true) {
            long y = (x + 1) * c - a;
            if (y <= 0 || y * y <= bb3)
                x++;
            else
                break;
        }

        while (true) {
            long y = x * c - a;
            if (y <= 0 || y * y <= bb3)
                break;
            x--;
        }

        return x;
    }

    static long alphaFloor(Alpha alpha) {
        return floorQsqrt3(alpha.a, alpha.b, alpha.c);
    }

    static long alphaMulFloor(Alpha alpha, long n) {
        return floorQsqrt3(alpha.a * n, alpha.b * n, alpha.c);
    }

    static Alpha alphaSubInt(Alpha alpha, long k) {
        return normalizeAlpha(alpha.a - k * alpha.c, alpha.b, alpha.c);
    }

    static Alpha alphaDivAlphaMinusOne(Alpha alpha) {
        long ac = alpha.a - alpha.c;
        long A = alpha.a * ac - 3L * alpha.b * alpha.b;
        long B = -alpha.b * alpha.c;
        long D = ac * ac - 3L * alpha.b * alpha.b;

        if (D < 0) {
            A = -A;
            B = -B;
            D = -D;
        }
        if (B < 0) {
            A = -A;
            B = -B;
        }
        return normalizeAlpha(A, B, D);
    }

    static long tri(long n) {
        return n * (n + 1) / 2L;
    }

    static long beattySum(Alpha alpha, long n) {
        long res = 0;
        long sign = 1;

        while (n > 0) {
            long f = alphaFloor(alpha);
            if (f > 1) {
                res += sign * (f - 1) * tri(n);
                alpha = alphaSubInt(alpha, f - 1);
            }

            long m = alphaMulFloor(alpha, n);
            res += sign * tri(m);

            n = m - n;
            if (n <= 0)
                break;

            alpha = alphaDivAlphaMinusOne(alpha);
            sign = -sign;
        }

        return res;
    }

    static long beattySqrt3(long c, long n) {
        if (n <= 0)
            return 0;
        return beattySum(new Alpha(0, c, 1), n);
    }

    static void linearSieve(int n, int[] spf, int[] mu) {
        ArrayList<Integer> primes = new ArrayList<>();
        mu[1] = 1;
        spf[1] = 1;

        for (int i = 2; i <= n; i++) {
            if (spf[i] == 0) {
                spf[i] = i;
                primes.add(i);
                mu[i] = -1;
            }
            for (int p : primes) {
                long v = (long) i * p;
                if (v > n)
                    break;
                spf[(int) v] = p;
                if (i % p == 0) {
                    mu[(int) v] = 0;
                    break;
                }
                mu[(int) v] = -mu[i];
            }
        }
    }

    static class Pair {
        int first;
        int second;

        Pair(int first, int second) {
            this.first = first;
            this.second = second;
        }
    }

    static ArrayList<ArrayList<Pair>> buildSquarefreeDivs(int maxN, int[] spf) {
        ArrayList<ArrayList<Pair>> sf = new ArrayList<>(maxN + 1);
        for (int i = 0; i <= maxN; i++)
            sf.add(null);
        ArrayList<Pair> initial = new ArrayList<>();
        initial.add(new Pair(1, 1));
        sf.set(1, initial);

        for (int n = 2; n <= maxN; n++) {
            ArrayList<Integer> ps = new ArrayList<>();
            int x = n;
            while (x > 1) {
                int p = spf[x];
                ps.add(p);
                while (x % p == 0)
                    x /= p;
            }

            ArrayList<Pair> divs = new ArrayList<>();
            divs.add(new Pair(1, 1));

            for (int p : ps) {
                int cur = divs.size();
                for (int i = 0; i < cur; i++) {
                    divs.add(new Pair(divs.get(i).first * p, -divs.get(i).second));
                }
            }
            sf.set(n, divs);
        }
        return sf;
    }

    static ArrayList<ArrayList<Integer>> buildAllDivisors(int maxN, int[] spf) {
        ArrayList<ArrayList<Integer>> divs = new ArrayList<>(maxN + 1);
        for (int i = 0; i <= maxN; i++)
            divs.add(null);
        ArrayList<Integer> initial = new ArrayList<>();
        initial.add(1);
        divs.set(1, initial);

        for (int n = 2; n <= maxN; n++) {
            int x = n;
            int p = spf[x];
            int e = 0;
            while (x % p == 0) {
                x /= p;
                e++;
            }

            ArrayList<Integer> base = divs.get(x);
            ArrayList<Integer> out = new ArrayList<>();

            int pe = 1;
            for (int i = 0; i <= e; i++) {
                for (int d : base) {
                    out.add(d * pe);
                }
                pe *= p;
            }
            divs.set(n, out);
        }
        return divs;
    }

    static long[] stripHyperbolaSum(long N, long V, long L, ArrayList<ArrayList<Pair>> sfDivs,
            ArrayList<ArrayList<Integer>> allDivs) {
        long s1 = 0, s2 = 0, diag1 = 0, diag2 = 0;

        for (int v = 1; v <= V; v++) {
            long Umax = L / v;
            ArrayList<Integer> dv = allDivs.get(v);

            for (long d : dv) {
                long m = v / d;
                long hi = Umax / d;
                if (hi < m)
                    continue;

                long w = N / (2L * d);
                long loMinus = m - 1;

                long cnt = 0;
                long sm = 0;

                ArrayList<Pair> sfm = sfDivs.get((int) m);
                for (Pair p : sfm) {
                    long q = p.first;
                    long muq = p.second;

                    cnt += muq * ((hi / q) - (loMinus / q));

                    long hiq = hi / q;
                    long loq = loMinus / q;
                    if (hiq > 0) {
                        long c = (long) v * q;
                        sm += muq * (beattySqrt3(c, hiq) - beattySqrt3(c, loq));
                    }
                }

                s1 += w * cnt;
                s2 += sm;
            }

            diag1 += N / (2L * v);
            diag2 += floorSqrt3Mul(v);
        }

        long S1 = 2L * s1 - diag1;
        long S2 = 2L * s2 - diag2;
        return new long[] { S1, S2 };
    }

    static long countMod3Res(long lo, long hi, long r) {
        if (hi < lo)
            return 0;
        long rem = ((lo % 3L) + 3L) % 3L;
        long delta = (r - rem + 3L) % 3L;
        long first = lo + delta;
        if (first > hi)
            return 0;
        return (hi - first) / 3L + 1L;
    }

    static long hexHsum(long X, ArrayList<ArrayList<Pair>> sfDivs) {
        if (X <= 0)
            return 0;

        HashMap<Long, Long> dCache = new HashMap<>();

        long V = isqrt(X);
        long extra = 0;

        for (long v = 1; v <= V; v++) {
            long disc0 = 4L * X - 3L * v * v;
            if (disc0 <= 0)
                break;

            long Umax = (-v + isqrt(disc0)) / 2L;
            long u = v + 1;

            ArrayList<Pair> sfv = sfDivs.get((int) v);
            long vmod = v % 3L;

            while (u <= Umax) {
                long t = u * u + u * v + v * v;
                long q = X / t;
                if (q == 0)
                    break;

                long T = X / q;
                long disc = 4L * T - 3L * v * v;
                long uhi = (-v + isqrt(disc)) / 2L;
                if (uhi > Umax)
                    uhi = Umax;

                long lo1 = u - 1;
                long total = 0;

                for (Pair p : sfv) {
                    long d = p.first;
                    long mud = p.second;
                    total += mud * (uhi / d - lo1 / d);
                }

                if (vmod != 0) {
                    long bad = 0;
                    for (Pair p : sfv) {
                        long d = p.first;
                        long mud = p.second;
                        long dm3 = d % 3L;
                        long inv = (dm3 == 1 ? 1L : 2L);
                        long tlo = (u + d - 1L) / d;
                        long thi = uhi / d;
                        long rr = (vmod * inv) % 3L;
                        bad += mud * countMod3Res(tlo, thi, rr);
                    }
                    total -= bad;
                }

                if (total != 0) {
                    Long cacheVal = dCache.get(q);
                    long dq;
                    if (cacheVal != null) {
                        dq = cacheVal;
                    } else {
                        dq = divisorSummatory(q);
                        dCache.put(q, dq);
                    }
                    extra += total * dq;
                }

                u = uhi + 1;
            }
        }

        Long cacheValX = dCache.get(X);
        long dx = (cacheValX != null) ? cacheValX : divisorSummatory(X);

        return dx + 2L * extra;
    }

    static long solveFast(long N) {
        if (N <= 0)
            return 0;

        long M = N / 2L;
        long L = floorDivSqrt3(M, 1L);
        long VStrip = isqrt(L);

        long X = N / 4L;
        long VHex = (X > 0 ? isqrt(X) : 0);

        int maxPre = (int) Math.max(1, Math.max(VStrip, VHex));

        int[] spf = new int[maxPre + 1];
        int[] mu = new int[maxPre + 1];
        linearSieve(maxPre, spf, mu);

        ArrayList<ArrayList<Pair>> sfDivs = buildSquarefreeDivs(maxPre, spf);
        ArrayList<ArrayList<Integer>> allDivs = buildAllDivisors(maxPre, spf);

        long base = 2L * divisorSummatory(M);
        long[] S = stripHyperbolaSum(N, VStrip, L, sfDivs, allDivs);
        long S1 = S[0], S2 = S[1];
        long stripPart = base + 4L * (S1 - S2);

        long H = hexHsum(X, sfDivs);
        long total = stripPart - 4L * H;

        long modded = total % MOD;
        if (modded < 0)
            modded += MOD;

        return modded;
    }

    public static String solve() {
        return Long.toString(solveFast(1000000000L));
    }

    public static void main(String[] args) {
        System.out.println(solve());
    }
}
