import java.util.HashMap;

public class Euler994 {
    private static final long TARGET_M = 1234L * 100_000_000L;
    private static final long TARGET_N = 2345L * 100_000_000L;
    private static final int MOD = 1_000_000_007;
    private static final int SIEVE_LIMIT = 5_000_000;
    private static final long INV2 = 500_000_004L;
    private static final long INV3 = 333_333_336L;
    private static final long INV6 = 166_666_668L;

    private static int addMod(int a, int b) {
        int s = a + b;
        return s >= MOD ? s - MOD : s;
    }

    private static int subMod(int a, int b) {
        return a >= b ? a - b : (int) ((long) a + MOD - b);
    }

    private static int mulMod(long a, long b) {
        return (int) ((a % MOD) * (b % MOD) % MOD);
    }

    private static int sumPower(int power, long n) {
        long a = n % MOD;
        long b = (n + 1) % MOD;
        if (power == 0) {
            return (int) a;
        }
        if (power == 1) {
            return (int) (a * b % MOD * INV2 % MOD);
        }
        if (power == 2) {
            long c = (2 * (n % MOD) + 1) % MOD;
            return (int) (a * b % MOD * c % MOD * INV6 % MOD);
        }
        long t = a * b % MOD * INV2 % MOD;
        return (int) (t * t % MOD);
    }

    private static int rangePower(int power, long lo, long hi) {
        return subMod(sumPower(power, hi), sumPower(power, lo - 1));
    }

    private static int choose2(long n) {
        long a = n % MOD;
        long b = (n - 1) % MOD;
        return (int) (a * b % MOD * INV2 % MOD);
    }

    private static int choose3(long n) {
        if (n < 3L) {
            return 0;
        }
        long a = n % MOD;
        long b = (n - 1) % MOD;
        long c = (n - 2) % MOD;
        return (int) (a * b % MOD * c % MOD * INV6 % MOD);
    }

    private static int triangleNumber(long n) {
        long a = n % MOD;
        long b = (n + 1) % MOD;
        return (int) (a * b % MOD * INV2 % MOD);
    }

    private static final class TotientSummatory {
        private final int limit;
        private final int[][] sums = new int[3][];
        private final HashMap<Long, Integer>[] memo;

        @SuppressWarnings("unchecked")
        private TotientSummatory(int limit) {
            this.limit = limit;
            for (int i = 0; i < 3; ++i) {
                sums[i] = new int[limit + 1];
            }
            memo = new HashMap[3];
            for (int i = 0; i < 3; ++i) {
                memo[i] = new HashMap<>(262_144);
            }
            build();
        }

        private int prefix(int power, long n) {
            if (n <= limit) {
                return sums[power][(int) n];
            }

            Integer cached = memo[power].get(n);
            if (cached != null) {
                return cached;
            }

            int result = sumPower(power + 1, n);
            for (long lo = 2L; lo <= n;) {
                long q = n / lo;
                long hi = n / q;
                int block = rangePower(power, lo, hi);
                result = subMod(result, mulMod(block, prefix(power, q)));
                lo = hi + 1;
            }

            memo[power].put(n, result);
            return result;
        }

        private void build() {
            int[] phi = new int[limit + 1];
            int[] primes = new int[limit];
            int primeCount = 0;
            boolean[] composite = new boolean[limit + 1];
            phi[1] = 1;

            for (int i = 2; i <= limit; ++i) {
                if (!composite[i]) {
                    primes[primeCount++] = i;
                    phi[i] = i - 1;
                }

                for (int j = 0; j < primeCount; ++j) {
                    int p = primes[j];
                    long v = (long) i * p;
                    if (v > limit) {
                        break;
                    }
                    composite[(int) v] = true;
                    if (i % p == 0) {
                        phi[(int) v] = phi[i] * p;
                        break;
                    }
                    phi[(int) v] = phi[i] * (p - 1);
                }
            }

            for (int i = 1; i <= limit; ++i) {
                long im = i % (long) MOD;
                long ph = phi[i] % (long) MOD;
                sums[0][i] = addMod(sums[0][i - 1], (int) ph);
                sums[1][i] = addMod(sums[1][i - 1], (int) (im * ph % MOD));
                sums[2][i] = addMod(sums[2][i - 1], (int) (im * im % MOD * ph % MOD));
            }
        }
    }

    private static int pairwiseTriangleCandidates(long m, long n) {
        int total = mulMod(choose3(m), choose3(n));
        total = addMod(total, mulMod(mulMod(choose3(m), n % MOD), (n - 1) % MOD));
        total = addMod(total, mulMod(mulMod(m % MOD, (m - 1) % MOD), choose3(n)));
        int corner = mulMod(mulMod(m % MOD, (m - 1) % MOD), mulMod(n % MOD, (n - 1) % MOD));
        total = addMod(total, mulMod(corner, INV2));
        return total;
    }

    private static int concurrentTriples(long m, long n, TotientSummatory totient) {
        long limit = Math.min(m, n) - 1L;
        int total = 0;

        for (long lo = 2L; lo <= limit;) {
            long qm = (m - 1) / lo;
            long qn = (n - 1) / lo;
            long hi = Math.min((m - 1) / qm, (n - 1) / qn);

            int s0 = subMod(totient.prefix(0, hi), totient.prefix(0, lo - 1));
            int s1 = subMod(totient.prefix(1, hi), totient.prefix(1, lo - 1));
            int s2 = subMod(totient.prefix(2, hi), totient.prefix(2, lo - 1));

            int am0 = mulMod(qm, m);
            int an0 = mulMod(qn, n);
            int am1 = triangleNumber(qm);
            int an1 = triangleNumber(qn);

            int term = mulMod(mulMod(am0, an0), s0);
            term = subMod(term, mulMod(addMod(mulMod(am0, an1), mulMod(am1, an0)), s1));
            term = addMod(term, mulMod(mulMod(am1, an1), s2));
            total = addMod(total, term);

            lo = hi + 1;
        }

        return total;
    }

    private static int solveMod(long m, long n, TotientSummatory totient) {
        return subMod(pairwiseTriangleCandidates(m, n), concurrentTriples(m, n, totient));
    }

    private static boolean pairIntersects(int[] a, int[] b) {
        return a[0] == b[0] || a[1] == b[1] || (long) (a[0] - b[0]) * (a[1] - b[1]) < 0L;
    }

    private static boolean collinear(int[] a, int[] b, int[] c) {
        return (long) (b[0] - a[0]) * (c[1] - a[1])
            == (long) (b[1] - a[1]) * (c[0] - a[0]);
    }

    private static long bruteCount(int m, int n) {
        int[][] segments = new int[m * n][2];
        int size = 0;
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                segments[size][0] = i;
                segments[size][1] = j;
                ++size;
            }
        }

        long total = 0L;
        for (int a = 0; a < size; ++a) {
            for (int b = a + 1; b < size; ++b) {
                for (int c = b + 1; c < size; ++c) {
                    if (pairIntersects(segments[a], segments[b])
                        && pairIntersects(segments[a], segments[c])
                        && pairIntersects(segments[b], segments[c])
                        && !collinear(segments[a], segments[b], segments[c])) {
                        ++total;
                    }
                }
            }
        }
        return total;
    }

    private static void require(boolean condition, String message) {
        if (!condition) {
            throw new IllegalStateException(message);
        }
    }

    private static void runCheckpoints(TotientSummatory totient) {
        for (int m = 1; m <= 5; ++m) {
            for (int n = 1; n <= 5; ++n) {
                require(solveMod(m, n, totient) == bruteCount(m, n), "Brute checkpoint failed");
            }
        }

        require(solveMod(2L, 3L, totient) == 8, "Checkpoint failed for T(2,3)");
        require(solveMod(3L, 5L, totient) == 146, "Checkpoint failed for T(3,5)");
        require(solveMod(12L, 23L, totient) == 756_716, "Checkpoint failed for T(12,23)");
    }

    public static void main(String[] args) {
        boolean shouldRunCheckpoints = true;
        for (String arg : args) {
            if ("--skip-checkpoints".equals(arg)) {
                shouldRunCheckpoints = false;
                continue;
            }
            System.err.println("Unknown argument: " + arg);
            System.exit(1);
        }

        TotientSummatory totient = new TotientSummatory(SIEVE_LIMIT);
        if (shouldRunCheckpoints) {
            runCheckpoints(totient);
        }

        System.out.println(solveMod(TARGET_M, TARGET_N, totient));
    }
}
