Problem: The Little Elephant is playing with the Cartesian coordinates' system. Most of all he likes playing with integer points. The Little Elephant defines an integer point as a pair of integers (x; y), such that 0 ≤ x ≤ w and 0 ≤ y ≤ h. Thus, the Little Elephant knows only (w + 1)·(h + 1) distinct integer points.

The Little Elephant wants to paint a triangle with vertexes at integer points, the triangle's area must be a positive integer. For that, he needs to find the number of groups of three points that form such triangle. At that, the order of points in a group matters, that is, the group of three points (0;0), (0;2), (2;2) isn't equal to the group (0;2), (0;0), (2;2).

Help the Little Elephant to find the number of groups of three integer points that form a nondegenerate triangle with integer area.

Input

A single line contains two integers w and h (1 ≤ w, h ≤ 4000).

Output

In a single output line print an integer — the remainder of dividing the answer to the problem by 1000000007 (109 + 7).

Examples

Input

2 1


Output

36


Input

2 2


Output

240

Solution (in JAVA):

Solution:
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.InputStream;

/**
 * Calculate the number of valid triangles with integer
 * area > 0 and vertices being in integer points on lattice N x M.
 * Order of points in a group matters, so triangles
 * (0;0),(0;2),(2;2) != (0;2),(0;0),(2;2).
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskD solver = new TaskD();
        solver.solve(1, in, out);
        out.close();
    }
}

class TaskD {
    int n;
    int m;
    final int M = 1000000007;
    int precalc[][] = {{-1, -1}, {-1, -1}};

    public void solve(int testNumber, InputReader in, PrintWriter out) {
        n = in.nextInt();
        m = in.nextInt();
        int ans = 0;
        for (int y = 0; y <= n; y++)
            for (int x = 0; x <= m; x++) {
                ans += calculateFitTriples(x, y);
                if (ans >= M)
                    ans -= M;
            }
        ans -= calculateBadTriples();
        if (ans < 0)
            ans += M;
        out.println(ans);
    }

    int calculateFitTriples(int x, int y) {
        int x0 = x & 1, y0 = y & 1;
        if (precalc[x0][y0] != -1)
            return precalc[x0][y0];
        int ret = 0;
        for (int x1 = 0; x1 <= 1; x1++)
            for (int y1 = 0; y1 <= 1; y1++)
                for (int x2 = 0; x2 <= 1; x2++)
                    for (int y2 = 0; y2 <= 1; y2++) {
                        int ax = (2 + x1 - x0) & 1;
                        int ay = (2 + y1 - y0) & 1;
                        int bx = (2 + x2 - x0) & 1;
                        int by = (2 + y2 - y0) & 1;
                        int areaMod2 = (2 + ax * by - ay * bx) % 2;
                        if (areaMod2 != 0) continue;
                        long X1 = getPointsOnSegmentWithParity(m, x1);
                        long Y1 = getPointsOnSegmentWithParity(n, y1);
                        long X2 = getPointsOnSegmentWithParity(m, x2);
                        long Y2 = getPointsOnSegmentWithParity(n, y2);
                        ret += (((((X1 * Y1) % M) * X2) % M) * Y2) % M;
                        if (ret >= M)
                            ret -= M;
                    }
        return precalc[x0][y0] = ret;
    }

    int getPointsOnSegmentWithParity(int len, int par) {
        if (par == 0)
            return (len / 2) + 1;
        else
            return (len + 1) / 2;
    }

    int calculateBadTriples() {
        int ret = 0;
        for (int dn = 0; dn <= n; dn++)
            for (int dm = 0; dm <= m; dm++) {
                if (dn == 0 && dm == 0) {
                    ret += (n + 1) * (m + 1);
                    if (ret >= M)
                        ret -= M;
                    continue;
                }
                int times = (n - dn + 1) * (m - dm + 1);
                int innerPoints = gcd(dn, dm) - 1;
                int permutations = 6 * innerPoints + 6;
                long add = (long) permutations * times;
                if (dn != 0 && dm != 0)
                    add *= 2;
                ret += add % M;
                if (ret >= M)
                    ret -= M;
            }
        return ret;
    }

    int gcd(int a, int b) {
        return b != 0 ? gcd(b, a % b) : a;
    }
}

class InputReader {
    private BufferedReader reader;
    private StringTokenizer tokenizer;

    public InputReader(InputStream stream) {
        reader = new BufferedReader(new InputStreamReader(stream));
        tokenizer = null;
    }

    public int nextInt() {
        return Integer.parseInt(next());
    }

    public String next() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }
}