public class Euler922 {

    static final long MOD = 1000000007L;
    static final int XOR_SIZE = 64;

    static void fwtXor(long[] a, boolean invert) {
        for (int len = 1; len < XOR_SIZE; len <<= 1) {
            for (int i = 0; i < XOR_SIZE; i += (len << 1)) {
                for (int j = 0; j < len; ++j) {
                    long u = a[i + j];
                    long v = a[i + j + len];
                    long x = u + v;
                    if (x >= MOD)
                        x -= MOD;
                    long y = u - v;
                    if (y < 0)
                        y += MOD;
                    a[i + j] = x;
                    a[i + j + len] = y;
                }
            }
        }
        if (!invert)
            return;
        long inv2 = (MOD + 1) / 2;
        for (int len = 1; len < XOR_SIZE; len <<= 1) {
            for (int i = 0; i < XOR_SIZE; i += (len << 1)) {
                for (int j = 0; j < len; ++j) {
                    a[i + j] = (a[i + j] * inv2) % MOD;
                    a[i + j + len] = (a[i + j + len] * inv2) % MOD;
                }
            }
        }
    }

    static long computeR(int m, int w) {
        int maxD = w - 2;
        int D = 2 * maxD + 1;
        int S = 2 * maxD * m + 1;
        int offset = maxD * m;

        long[][] f = new long[D][XOR_SIZE];

        for (int a = 1; a <= w - 2; ++a) {
            for (int b = 1; b <= w - a - 1; ++b) {
                int maxk = w - a - b;
                int dIdx = b - a + maxD;
                for (int g = 0; g < maxk; ++g) {
                    f[dIdx][g] = (f[dIdx][g] + 1) % MOD;
                }
            }
        }

        for (int d = 0; d < D; ++d) {
            fwtXor(f[d], false);
        }

        long[][] dp = new long[S][XOR_SIZE];
        dp[offset][0] = 1;

        int[] delta = new int[D];
        for (int d = 0; d < D; ++d) {
            delta[d] = d - maxD;
        }

        for (int step = 0; step < m; ++step) {
            long[][] dpHat = new long[S][XOR_SIZE];
            for (int s = 0; s < S; ++s) {
                System.arraycopy(dp[s], 0, dpHat[s], 0, XOR_SIZE);
            }
            for (int s = 0; s < S; ++s) {
                fwtXor(dpHat[s], false);
            }

            long[][] newHat = new long[S][XOR_SIZE];

            for (int freq = 0; freq < XOR_SIZE; ++freq) {
                for (int sd = 0; sd < S; ++sd) {
                    long acc = 0;
                    for (int d = 0; d < D; ++d) {
                        int sdPrev = sd - delta[d];
                        if (sdPrev >= 0 && sdPrev < S) {
                            acc += dpHat[sdPrev][freq] * f[d][freq];
                            acc %= MOD;
                        }
                    }
                    newHat[sd][freq] = acc;
                }
            }

            long[][] newDp = newHat;
            for (int s = 0; s < S; ++s) {
                fwtXor(newDp[s], true);
            }
            dp = newDp;
        }

        long ans = 0;
        for (int sd = 0; sd < S; ++sd) {
            int sumD = sd - offset;
            long rowSum = 0;
            for (int x = 0; x < XOR_SIZE; ++x) {
                rowSum += dp[sd][x];
                if (rowSum >= MOD)
                    rowSum -= MOD;
            }
            if (sumD > 0) {
                ans += rowSum;
            } else if (sumD == 0) {
                long zero = dp[sd][0];
                long add = rowSum - zero;
                if (add < 0)
                    add += MOD;
                ans += add;
            }
            ans %= MOD;
        }
        return ans % MOD;
    }

    public static String solve() {
        return Long.toString(computeR(8, 64));
    }

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