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.OutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.InputMismatchException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author George Marcus
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		StreamInputReader in = new StreamInputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		TaskD solver = new TaskD();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskD {
    public static final int MOD = 1000000007;
    private int N, M;
	public void solve(int testNumber, StreamInputReader in, PrintWriter out) {
        M = in.readInt();
        N = in.readInt();
        long ans = 0;
        for(int px0 = 0; px0 < 2; px0++)
        for(int py0 = 0; py0 < 2; py0++)
        for(int px1 = 0; px1 < 2; px1++)
        for(int py1 = 0; py1 < 2; py1++)
        for(int px2 = 0; px2 < 2; px2++)
        for(int py2 = 0; py2 < 2; py2++)
           if((px0 * (py1 - py2 + 2) + py0 * (px2 - px1 + 2) + px1 * py2 - px2 * py1 + 2) % 2 == 0) {
               long crt = 1;
               crt *= px(px0);
               crt *= px(px1);
               crt *= px(px2);
               crt %= MOD;
               if(crt < 0)
                   throw new RuntimeException();
               crt *= py(py0);
               crt *= py(py1);
               crt *= py(py2);
               if(crt < 0)
                   throw new RuntimeException();
               ans = (ans + crt) % MOD;
           }

        int[][] gcd = new int[4001][4001];
        for(int i = 0; i <= M; i++)
            for(int j = 0; j <= N; j++) {
                if(i == 0)
                    gcd[i][j] = j;
                else if(j == 0)
                    gcd[i][j] = i;
                else if(i >= j)
                    gcd[i][j] = gcd[i - j][j];
                else
                    gcd[i][j] = gcd[i][j - i];
            }

        long bad = 0;
        for(int dx = 0; dx <= M; dx++)
            for(int dy = 0; dy <= N; dy++) {
                int numPoints = gcd[dx][dy] + 1;
                // int numPoints = gcd(dx, dy) + 1;
                if(numPoints < 1)
                    throw new RuntimeException();

                long pos = -1;
                if(numPoints == 1)
                    pos = 1;
                else if(numPoints == 2)
                    pos = 6;
                else pos = (numPoints - 2) * 6 + 6;

                if(pos == -1)
                    throw new RuntimeException();

                pos = pos * (M - dx + 1) * (N - dy + 1);
                if(dx > 0 && dy > 0) {
                    pos *= 2;
                }

                bad = (bad + pos) % MOD;
            }

        ans = (ans - bad + MOD) % MOD;
        out.print(ans);
	}

    private long py(int p) {
        return (long)N / 2 + ((p == 0 || N % 2 == 1) ? 1 : 0);
    }

    private long px(int p) {
        return (long)M / 2 + ((p == 0 || M % 2 == 1) ? 1 : 0);
    }
}

class StreamInputReader extends InputReader {
    private InputStream stream;
    private byte[] buf = new byte[1024];
    private int curChar, numChars;

    public StreamInputReader(InputStream stream) {
        this.stream = stream;
    }

    public int read() {
        if (numChars == -1)
            throw new InputMismatchException();
        if (curChar >= numChars) {
            curChar = 0;
            try {
                numChars = stream.read(buf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (numChars <= 0)
                return -1;
        }
        return buf[curChar++];
    }

    }

abstract class InputReader {

    public abstract int read();

    public int readInt() {
        return Integer.parseInt(readString());
    }

    public String readString() {
        int c = read();
        while (isSpaceChar(c))
            c = read();
        StringBuffer res = new StringBuffer();
        do {
            res.appendCodePoint(c);
            c = read();
        } while (!isSpaceChar(c));
        return res.toString();
    }

    private boolean isSpaceChar(int c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

    }