import java.io.*;
import java.math.BigInteger;
import java.util.Arrays;

public class increasing_prefix_ors_3xNTT {

    final static long p = 1000000007;

    static class Value {
        int[] poly;
        long mul;

        public Value(int[] poly, long mul) {
            this.poly = poly;
            this.mul = mul;
        }

        Value mul(Value o) {
            return new Value(Arrays.copyOf(polyMul(substitute(poly, o.mul), o.poly), poly.length), mul * o.mul % p);
        }
    }

    static Value pow(Value x, Value one, long pow) {
        while (pow > 0) {
            if (pow % 2 == 1) {
                one = one.mul(x);
            }
            pow /= 2;
            x = x.mul(x);
        }
        return one;
    }

    public static void solve(Input in, PrintWriter out) throws IOException {
        // d'_j*(k-j)! += d_i*(k-i)! / (j-i)! * 2^i
        long n = in.nextLong();
        int k = in.nextInt();
        if (n > k + 1) {
            out.println(0);
            return;
        }
        int[] poly0 = new int[k + 1];
        int[] poly1 = new int[k + 1];
        for (int i = 1; i <= k; ++i) {
            poly0[i] = (int) (fact[k] * invFact[i] % p);
            poly1[i] = (int) invFact[i];
        }
        Value v = pow(new Value(poly1, 2), new Value(poly0, 1), n - 1);
        long ans = 0;
        for (int i = 0; i <= k; ++i) {
            ans = (ans + v.poly[i] * invFact[k - i]) % p;
        }
        out.println(ans);
    }

    static int max = 30000;
    static long[] fact, invFact, invs;
    static {
        fact = new long[max + 1];
        invFact = new long[max + 1];
        fact[0] = 1;
        invFact[0] = 1;
        invs = new long[max + 1];
        for (int i = 1; i <= max; ++i) {
            invs[i] = i == 1 ? 1 : (int) (p - invs[((int) (p % i))] * (p / i) % p);
            fact[i] = fact[i - 1] * i % p;
            invFact[i] = invFact[i - 1] * invs[i] % p;
        }
    }

    static long modInverse(long x, long mod) {
        return modPow(x, mod - 2, mod);
    }

    static long modPow(long x, long pow, long mod) {
        long r = 1;
        while (pow > 0) {
            if (pow % 2 == 1) {
                r = (r * x) % mod;
            }
            pow /= 2;
            x = (x * x) % mod;
        }
        return r;
    }

    static int[] substitute(int[] a, long c) {
        int[] r = new int[a.length];
        long pow = 1;
        for (int i = 0; i < a.length; ++i) {
            r[i] = (int) (a[i] * pow % p);
            pow = pow * c % p;
        }
        return r;
    }

    static class FFT {
        int[][] tail;
        int[][] omegas;
        final int mod;
        final int LOG = 18;

        int G;

        FFT(int mod, int g) {
            this.mod = mod;
            G = g;
            tail = new int[LOG][];
            omegas = new int[LOG][];
            for (int l = 0; l < LOG; l++) {
                tail[l] = new int[1 << l];
                omegas[l] = new int[1 << l];
                int w = (int)modPow(G, (mod - 1) / (1 << l), mod);

                omegas[l][0] = 1;
                for (int i = 1; i < 1 << l; i++) {
                    tail[l][i] = (tail[l][i >> 1] >> 1) | ((i & 1) << (l - 1));
                    omegas[l][i] = (int) ((1l * omegas[l][i - 1] * w) % mod);
                }
            }
        }

        void doFFT(int[] a, int size, boolean inverse) {
            int l = Integer.numberOfTrailingZeros(size);
            int[] tail = this.tail[l], omegas = this.omegas[l];
            for (int i = 0; i < size; i++) {
                if (i < tail[i]) {
                    int tmp = a[i];
                    a[i] = a[tail[i]];
                    a[tail[i]] = tmp;
                }
            }
            for (int len = 2; len <= size; len *= 2) {
                int add = size / len;
                for (int i = 0; i < size; i += len) {
                    int pos = 0;
                    for (int j = 0, k = len / 2; k < len; j++, k++) {
                        int u = a[i + j], v = (int) ((1l * a[i + k] * omegas[pos]) % mod);
                        a[i + j] = (u + v);
                        a[i + k] = (u - v + mod);
                        if (a[i + j] >= mod) {
                            a[i + j] -= mod;
                        }
                        if (a[i + k] >= mod) {
                            a[i + k] -= mod;
                        }

                        if (inverse) {
                            pos -= add;
                            if (pos < 0) {
                                pos += size;
                            }
                        } else {
                            pos += add;
                        }
                    }
                }
            }
            if (inverse) {
                int inv = (int)modInverse(size, mod);
                for (int i = 0; i < size; i++) {
                    a[i] = (int) ((1L * inv * a[i]) % mod);
                }
            }
        }

        int[] conv(int[] a, int[] b) {
            int size = 1;
            while (size < a.length || size < b.length) {
                size *= 2;
            }
            size *= 2;
            a = Arrays.copyOf(a, size);
            b = Arrays.copyOf(b, size);
            doFFT(a, size, false);
            doFFT(b, size, false);
            for (int i = 0; i < size; ++i) {
                a[i] = (int) (1L * a[i] * b[i] % mod);
            }
            doFFT(a, size, true);
            return a;
        }
    }

    final static int mod1 = 998244353; // G = 3
    final static int mod2 = 1012924417; // G = 5
    final static int mod3 = 1045430273; // G = 3

    final static CRT e = new CRT(mod1, mod2, mod3);
    final static FFT fft1 = new FFT(mod1, 3);
    final static FFT fft2 = new FFT(mod2, 5);
    final static FFT fft3 = new FFT(mod3, 3);

    private static int[] polyMul(int[] a, int[] b) {
        int n = a.length;
        int[] a1 = fft1.conv(a, b);
        int[] a2 = fft2.conv(a, b);
        int[] a3 = fft3.conv(a, b);
        a = new int[n];
        for (int i = 0; i < n; ++i) {
            a[i] = (int) (e.crt(a1[i], a2[i], a3[i]).mod(BigInteger.valueOf(p)).longValue());
        }
        return a;
    }

    static class CRT {
        long[] mods;
        long[][] r;

        public CRT(long... mods) {
            this.mods = mods;
            r = new long[mods.length][mods.length];
            for (int i = 0; i < mods.length; ++i) {
                for (int j = i + 1; j < mods.length; ++j) {
                    r[i][j] = modInverse(mods[i], mods[j]);
                }
            }
        }

        BigInteger crt(long... rs) {
            BigInteger result = BigInteger.ZERO, mult = BigInteger.ONE;
            for (int i = 0; i < rs.length; ++i) {
                for (int j = 0; j < i; ++j) {
                    long cur = (rs[i] - rs[j]) * r[j][i];
                    rs[i] = (int)((cur % mods[i] + mods[i]) % mods[i]);
                }
                result = result.add(mult.multiply(BigInteger.valueOf(rs[i])));
                mult = mult.multiply(BigInteger.valueOf(mods[i]));
            }
            return result;
        }
    }

    public static void main(String[] args) throws IOException {
        PrintWriter out = new PrintWriter(System.out);
        solve(new Input(new BufferedReader(new InputStreamReader(System.in))), out);
        out.close();
    }

    static class Input {
        BufferedReader in;
        StringBuilder sb = new StringBuilder();

        public Input(BufferedReader in) {
            this.in = in;
        }

        public Input(String s) {
            this.in = new BufferedReader(new StringReader(s));
        }

        public String next() throws IOException {
            sb.setLength(0);
            while (true) {
                int c = in.read();
                if (c == -1) {
                    return null;
                }
                if (" \n\r\t".indexOf(c) == -1) {
                    sb.append((char)c);
                    break;
                }
            }
            while (true) {
                int c = in.read();
                if (c == -1 || " \n\r\t".indexOf(c) != -1) {
                    break;
                }
                sb.append((char)c);
            }
            return sb.toString();
        }

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

        public long nextLong() throws IOException {
            return Long.parseLong(next());
        }

        public double nextDouble() throws IOException {
            return Double.parseDouble(next());
        }
    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Deque;
import java.util.function.Supplier;
import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.io.OutputStream;
import java.util.Collection;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.function.Consumer;
import java.io.Closeable;
import java.io.Writer;
import java.util.ArrayDeque;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(null, new TaskAdapter(), "", 1 << 29);
        thread.start();
        thread.join();
    }

    static class TaskAdapter implements Runnable {
        @Override
        public void run() {
            InputStream inputStream = System.in;
            OutputStream outputStream = System.out;
            FastInput in = new FastInput(inputStream);
            FastOutput out = new FastOutput(outputStream);
            ETransformingSequence solver = new ETransformingSequence();
            solver.solve(1, in, out);
            out.close();
        }
    }

    static class ETransformingSequence {
        int mod = (int) 1e9 + 7;
        IntPoly poly = new IntPolyFFT(mod);
        Factorial fact = new Factorial((int) 1e4, mod);
        CachedPow pow = new CachedPow(2, mod);
        Combination comb = new Combination(fact);

        public void solve(int testNumber, FastInput in, FastOutput out) {
            long n = in.readLong();
            int k = in.readInt();
            if (n > k) {
                out.println(0);
                return;
            }

            int[] x = new int[k + 1];
            Arrays.fill(x, 1, k + 1, 1);
            int[] ans = pow(x, (int) n);
            long sum = 0;
            for (int i = 0; i <= k; i++) {
                sum += (long) ans[i] * comb.combination(k, i) % mod;
            }
            sum %= mod;
            out.println(sum);
        }

        public int[] mul(int[] dpL, int[] dpR, int l, int r) {
            int n = dpL.length;
            int[] f = PrimitiveBuffers.allocIntPow2(n);
            int[] g = PrimitiveBuffers.allocIntPow2(n);
            for (int i = 0; i < n; i++) {
                f[i] = (int) ((long) dpL[i] * fact.invFact(i) % mod * pow.pow((long) r * i) % mod);
                g[i] = (int) ((long) dpR[i] * fact.invFact(i) % mod);
            }
            int[] ans = poly.convolution(f, g);
            int[] ret = Arrays.copyOf(ans, n);
            for (int i = 0; i < n; i++) {
                ret[i] = (int) ((long) ret[i] * fact.fact(i) % mod);
            }
            PrimitiveBuffers.release(f, g, ans);
            return ret;
        }

        public int[] pow(int[] x, int n) {
            if (n == 0) {
                int[] ans = new int[x.length];
                ans[0] = 1;
                return ans;
            }
            int[] ans = pow(x, n / 2);
            ans = mul(ans, ans, n / 2, n / 2);
            if (n % 2 == 1) {
                ans = mul(ans, x, n - 1, 1);
            }
            return ans;
        }

    }

    static class Log2 {
        public static int ceilLog(int x) {
            if (x <= 0) {
                return 0;
            }
            return 32 - Integer.numberOfLeadingZeros(x - 1);
        }

    }

    static class IntPoly {
        protected int mod;
        protected Power power;

        public IntPoly(int mod) {
            this.mod = mod;
            this.power = new Power(mod);
        }

        public int[] convolution(int[] a, int[] b) {
            return mulBF(a, b);
        }

        public int rankOf(int[] p) {
            int r = p.length - 1;
            while (r >= 0 && p[r] == 0) {
                r--;
            }
            return Math.max(0, r);
        }

        public int[] mulBF(int[] a, int[] b) {
            int rA = rankOf(a);
            int rB = rankOf(b);
            if (rA > rB) {
                {
                    int tmp = rA;
                    rA = rB;
                    rB = tmp;
                }
                {
                    int[] tmp = a;
                    a = b;
                    b = tmp;
                }
            }
            int[] c = PrimitiveBuffers.allocIntPow2(rA + rB + 1);
            for (int i = 0; i <= rA; i++) {
                for (int j = 0; j <= rB; j++) {
                    c[i + j] = (int) ((c[i + j] + (long) a[i] * b[j]) % mod);
                }
            }
            return c;
        }

    }

    static class Factorial {
        int[] fact;
        int[] inv;
        int mod;

        public int getMod() {
            return mod;
        }

        public Factorial(int[] fact, int[] inv, int mod) {
            this.mod = mod;
            this.fact = fact;
            this.inv = inv;
            fact[0] = inv[0] = 1;
            int n = Math.min(fact.length, mod);
            for (int i = 1; i < n; i++) {
                fact[i] = i;
                fact[i] = (int) ((long) fact[i] * fact[i - 1] % mod);
            }
            inv[n - 1] = BigInteger.valueOf(fact[n - 1]).modInverse(BigInteger.valueOf(mod)).intValue();
            for (int i = n - 2; i >= 1; i--) {
                inv[i] = (int) ((long) inv[i + 1] * (i + 1) % mod);
            }
        }

        public Factorial(int limit, int mod) {
            this(new int[limit + 1], new int[limit + 1], mod);
        }

        public int fact(int n) {
            return fact[n];
        }

        public int invFact(int n) {
            return inv[n];
        }

    }

    static class FastInput {
        private final InputStream is;
        private byte[] buf = new byte[1 << 13];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastInput(InputStream is) {
            this.is = is;
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    bufLen = -1;
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

        public long readLong() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            long val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

    }

    static class DigitUtils {
        private DigitUtils() {
        }

        public static int mod(long x, int mod) {
            if (x < -mod || x >= mod) {
                x %= mod;
            }
            if (x < 0) {
                x += mod;
            }
            return (int) x;
        }

        public static int mod(int x, int mod) {
            if (x < -mod || x >= mod) {
                x %= mod;
            }
            if (x < 0) {
                x += mod;
            }
            return x;
        }

    }

    static class Power implements InverseNumber {
        int mod;

        public Power(Modular modular) {
            this.mod = modular.getMod();
        }

        public Power(int mod) {
            this(new Modular(mod));
        }

    }

    static interface IntCombination {
    }

    static class FastOutput implements AutoCloseable, Closeable, Appendable {
        private static final int THRESHOLD = 1 << 13;
        private final Writer os;
        private StringBuilder cache = new StringBuilder(THRESHOLD * 2);

        public FastOutput append(CharSequence csq) {
            cache.append(csq);
            return this;
        }

        public FastOutput append(CharSequence csq, int start, int end) {
            cache.append(csq, start, end);
            return this;
        }

        private void afterWrite() {
            if (cache.length() < THRESHOLD) {
                return;
            }
            flush();
        }

        public FastOutput(Writer os) {
            this.os = os;
        }

        public FastOutput(OutputStream os) {
            this(new OutputStreamWriter(os));
        }

        public FastOutput append(char c) {
            cache.append(c);
            afterWrite();
            return this;
        }

        public FastOutput append(int c) {
            cache.append(c);
            afterWrite();
            return this;
        }

        public FastOutput append(long c) {
            cache.append(c);
            afterWrite();
            return this;
        }

        public FastOutput append(String c) {
            cache.append(c);
            afterWrite();
            return this;
        }

        public FastOutput println(int c) {
            return append(c).println();
        }

        public FastOutput println(long c) {
            return append(c).println();
        }

        public FastOutput println() {
            return append(System.lineSeparator());
        }

        public FastOutput flush() {
            try {
                os.append(cache);
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
            return this;
        }

        public void close() {
            flush();
            try {
                os.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        public String toString() {
            return cache.toString();
        }

    }

    static class CachedPow {
        private int[] first;
        private int[] second;
        private int mod;
        private int powMod;
        private static int step = 16;
        private static int limit = 1 << step;
        private static int mask = limit - 1;

        public CachedPow(int x, int mod) {
            this.mod = mod;
            this.powMod = mod - 1;
            first = new int[limit];
            second = new int[Integer.MAX_VALUE / limit + 1];
            first[0] = 1;
            for (int i = 1; i < first.length; i++) {
                first[i] = (int) ((long) x * first[i - 1] % mod);
            }
            second[0] = 1;
            long step = (long) x * first[first.length - 1] % mod;
            for (int i = 1; i < second.length; i++) {
                second[i] = (int) (second[i - 1] * step % mod);
            }
        }

        public int pow(int exp) {
            return (int) ((long) first[exp & mask] * second[exp >> step] % mod);
        }

        public int pow(long exp) {
            return pow(DigitUtils.mod(exp, powMod));
        }

    }

    static class Combination implements IntCombination {
        final Factorial factorial;
        int modVal;

        public Combination(Factorial factorial) {
            this.factorial = factorial;
            this.modVal = factorial.getMod();
        }

        public Combination(int limit, int mod) {
            this(new Factorial(limit, mod));
        }

        public int combination(int m, int n) {
            if (n > m || n < 0) {
                return 0;
            }
            return (int) ((long) factorial.fact(m) * factorial.invFact(n) % modVal * factorial.invFact(m - n) % modVal);
        }

    }

    static class Modular {
        int m;

        public int getMod() {
            return m;
        }

        public Modular(int m) {
            this.m = m;
        }

        public Modular(long m) {
            this.m = (int) m;
            if (this.m != m) {
                throw new IllegalArgumentException();
            }
        }

        public Modular(double m) {
            this.m = (int) m;
            if (this.m != m) {
                throw new IllegalArgumentException();
            }
        }

        public String toString() {
            return "mod " + m;
        }

    }

    static class PrimitiveBuffers {
        public static Buffer<int[]>[] intPow2Bufs = new Buffer[30];
        public static Buffer<double[]>[] doublePow2Bufs = new Buffer[30];

        static {
            for (int i = 0; i < 30; i++) {
                int finalI = i;
                intPow2Bufs[i] = new Buffer<>(() -> new int[1 << finalI], x -> Arrays.fill(x, 0));
                doublePow2Bufs[i] = new Buffer<>(() -> new double[1 << finalI], x -> Arrays.fill(x, 0));
            }
        }

        public static int[] allocIntPow2(int n) {
            return intPow2Bufs[Log2.ceilLog(n)].alloc();
        }

        public static void release(int[] data) {
            intPow2Bufs[Log2.ceilLog(data.length)].release(data);
        }

        public static void release(int[] a, int[] b, int[] c) {
            release(a);
            release(b);
            release(c);
        }

        public static double[] allocDoublePow2(int n) {
            return doublePow2Bufs[Log2.ceilLog(n)].alloc();
        }

        public static double[] allocDoublePow2(double[] data, int newLen) {
            double[] ans = allocDoublePow2(newLen);
            System.arraycopy(data, 0, ans, 0, Math.min(data.length, newLen));
            return ans;
        }

        public static void release(double[] data) {
            doublePow2Bufs[Log2.ceilLog(data.length)].release(data);
        }

        public static void release(double[]... data) {
            for (double[] x : data) {
                release(x);
            }
        }

    }

    static interface InverseNumber {
    }

    static class FastFourierTransform {
        private static double[][] realLevels = new double[30][];
        private static double[][] imgLevels = new double[30][];

        private static void prepareLevel(int i) {
            if (realLevels[i] == null) {
                realLevels[i] = new double[1 << i];
                imgLevels[i] = new double[1 << i];
                for (int j = 0, s = 1 << i; j < s; j++) {
                    realLevels[i][j] = Math.cos(Math.PI / s * j);
                    imgLevels[i][j] = Math.sin(Math.PI / s * j);
                }
            }
        }

        public static void fft(double[][] p, boolean inv) {
            int m = Log2.ceilLog(p[0].length);
            int n = 1 << m;
            int shift = 32 - Integer.numberOfTrailingZeros(n);
            for (int i = 1; i < n; i++) {
                int j = Integer.reverse(i << shift);
                if (i < j) {
                    SequenceUtils.swap(p[0], i, j);
                    SequenceUtils.swap(p[1], i, j);
                }
            }

            double[][] t = new double[2][1];
            for (int d = 0; d < m; d++) {
                int s = 1 << d;
                int s2 = s << 1;
                prepareLevel(d);
                for (int i = 0; i < n; i += s2) {
                    for (int j = 0; j < s; j++) {
                        int a = i + j;
                        int b = a + s;
                        mul(realLevels[d][j], imgLevels[d][j], p[0][b], p[1][b], t, 0);
                        sub(p[0][a], p[1][a], t[0][0], t[1][0], p, b);
                        add(p[0][a], p[1][a], t[0][0], t[1][0], p, a);
                    }
                }
            }

            if (inv) {
                for (int i = 0, j = 0; i <= j; i++, j = n - i) {
                    double a = p[0][j];
                    double b = p[1][j];
                    div(p[0][i], p[1][i], n, p, j);
                    if (i != j) {
                        div(a, b, n, p, i);
                    }
                }
            }
        }

        public static void add(double r1, double i1, double r2, double i2, double[][] r, int i) {
            r[0][i] = r1 + r2;
            r[1][i] = i1 + i2;
        }

        public static void sub(double r1, double i1, double r2, double i2, double[][] r, int i) {
            r[0][i] = r1 - r2;
            r[1][i] = i1 - i2;
        }

        public static void mul(double r1, double i1, double r2, double i2, double[][] r, int i) {
            r[0][i] = r1 * r2 - i1 * i2;
            r[1][i] = r1 * i2 + i1 * r2;
        }

        public static void div(double r1, double i1, double r2, double[][] r, int i) {
            r[0][i] = r1 / r2;
            r[1][i] = i1 / r2;
        }

    }

    static class SequenceUtils {
        public static void swap(double[] data, int i, int j) {
            double tmp = data[i];
            data[i] = data[j];
            data[j] = tmp;
        }

    }

    static class Buffer<T> {
        private Deque<T> deque;
        private Supplier<T> supplier;
        private Consumer<T> cleaner;
        private int allocTime;
        private int releaseTime;

        public Buffer(Supplier<T> supplier) {
            this(supplier, (x) -> {
            });
        }

        public Buffer(Supplier<T> supplier, Consumer<T> cleaner) {
            this(supplier, cleaner, 0);
        }

        public Buffer(Supplier<T> supplier, Consumer<T> cleaner, int exp) {
            this.supplier = supplier;
            this.cleaner = cleaner;
            deque = new ArrayDeque<>(exp);
        }

        public T alloc() {
            allocTime++;
            return deque.isEmpty() ? supplier.get() : deque.removeFirst();
        }

        public void release(T e) {
            releaseTime++;
            cleaner.accept(e);
            deque.addLast(e);
        }

    }

    static class IntPolyFFT extends IntPoly {
        private static final int FFT_THRESHOLD = 50;

        public IntPolyFFT(int mod) {
            super(mod);
        }

        public int[] convolution(int[] a, int[] b) {
            if (a != b) {
                return multiplyMod(a, b);
            } else {
                return pow2(a);
            }
        }

        public int[] pow2(int[] a) {
            int rA = rankOf(a);
            if (rA < FFT_THRESHOLD) {
                return mulBF(a, a);
            }

            int need = rA * 2 + 1;

            double[] aReal = PrimitiveBuffers.allocDoublePow2(need);
            double[] aImag = PrimitiveBuffers.allocDoublePow2(need);
            int n = aReal.length;

            for (int i = 0; i <= rA; i++) {
                int x = DigitUtils.mod(a[i], mod);
                aReal[i] = x & ((1 << 15) - 1);
                aImag[i] = x >> 15;
            }
            FastFourierTransform.fft(new double[][]{aReal, aImag}, false);

            double[] bReal = PrimitiveBuffers.allocDoublePow2(aReal, aReal.length);
            double[] bImag = PrimitiveBuffers.allocDoublePow2(aImag, bReal.length);

            for (int i = 0, j = 0; i <= j; i++, j = n - i) {
                double ari = aReal[i];
                double aii = aImag[i];
                double bri = bReal[i];
                double bii = bImag[i];
                double arj = aReal[j];
                double aij = aImag[j];
                double brj = bReal[j];
                double bij = bImag[j];

                double a1r = (ari + arj) / 2;
                double a1i = (aii - aij) / 2;
                double a2r = (aii + aij) / 2;
                double a2i = (arj - ari) / 2;

                double b1r = (bri + brj) / 2;
                double b1i = (bii - bij) / 2;
                double b2r = (bii + bij) / 2;
                double b2i = (brj - bri) / 2;

                aReal[i] = a1r * b1r - a1i * b1i - a2r * b2i - a2i * b2r;
                aImag[i] = a1r * b1i + a1i * b1r + a2r * b2r - a2i * b2i;
                bReal[i] = a1r * b2r - a1i * b2i + a2r * b1r - a2i * b1i;
                bImag[i] = a1r * b2i + a1i * b2r + a2r * b1i + a2i * b1r;

                if (i != j) {
                    a1r = (arj + ari) / 2;
                    a1i = (aij - aii) / 2;
                    a2r = (aij + aii) / 2;
                    a2i = (ari - arj) / 2;

                    b1r = (brj + bri) / 2;
                    b1i = (bij - bii) / 2;
                    b2r = (bij + bii) / 2;
                    b2i = (bri - brj) / 2;

                    aReal[j] = a1r * b1r - a1i * b1i - a2r * b2i - a2i * b2r;
                    aImag[j] = a1r * b1i + a1i * b1r + a2r * b2r - a2i * b2i;
                    bReal[j] = a1r * b2r - a1i * b2i + a2r * b1r - a2i * b1i;
                    bImag[j] = a1r * b2i + a1i * b2r + a2r * b1i + a2i * b1r;
                }
            }

            FastFourierTransform.fft(new double[][]{aReal, aImag}, true);
            FastFourierTransform.fft(new double[][]{bReal, bImag}, true);

            int[] ans = PrimitiveBuffers.allocIntPow2(need);
            for (int i = 0; i < need; i++) {
                long aa = DigitUtils.mod(Math.round(aReal[i]), mod);
                long bb = DigitUtils.mod(Math.round(bReal[i]), mod);
                long cc = DigitUtils.mod(Math.round(aImag[i]), mod);
                ans[i] = DigitUtils.mod(aa + (bb << 15) + (cc << 30), mod);
            }

            PrimitiveBuffers.release(aReal, bReal, aImag, bImag);
            return ans;
        }

        private int[] multiplyMod(int[] a, int[] b) {
            int rA = rankOf(a);
            int rB = rankOf(b);
            if (Math.min(rA, rB) < FFT_THRESHOLD) {
                return mulBF(a, b);
            }

            int need = rA + rB + 1;

            double[] aReal = PrimitiveBuffers.allocDoublePow2(need);
            double[] aImag = PrimitiveBuffers.allocDoublePow2(need);
            int n = aReal.length;

            for (int i = 0; i <= rA; i++) {
                int x = DigitUtils.mod(a[i], mod);
                aReal[i] = x & ((1 << 15) - 1);
                aImag[i] = x >> 15;
            }
            FastFourierTransform.fft(new double[][]{aReal, aImag}, false);

            double[] bReal = PrimitiveBuffers.allocDoublePow2(need);
            double[] bImag = PrimitiveBuffers.allocDoublePow2(need);
            for (int i = 0; i <= rB; i++) {
                int x = DigitUtils.mod(b[i], mod);
                bReal[i] = x & ((1 << 15) - 1);
                bImag[i] = x >> 15;
            }
            FastFourierTransform.fft(new double[][]{bReal, bImag}, false);

            for (int i = 0, j = 0; i <= j; i++, j = n - i) {
                double ari = aReal[i];
                double aii = aImag[i];
                double bri = bReal[i];
                double bii = bImag[i];
                double arj = aReal[j];
                double aij = aImag[j];
                double brj = bReal[j];
                double bij = bImag[j];

                double a1r = (ari + arj) / 2;
                double a1i = (aii - aij) / 2;
                double a2r = (aii + aij) / 2;
                double a2i = (arj - ari) / 2;

                double b1r = (bri + brj) / 2;
                double b1i = (bii - bij) / 2;
                double b2r = (bii + bij) / 2;
                double b2i = (brj - bri) / 2;

                aReal[i] = a1r * b1r - a1i * b1i - a2r * b2i - a2i * b2r;
                aImag[i] = a1r * b1i + a1i * b1r + a2r * b2r - a2i * b2i;
                bReal[i] = a1r * b2r - a1i * b2i + a2r * b1r - a2i * b1i;
                bImag[i] = a1r * b2i + a1i * b2r + a2r * b1i + a2i * b1r;

                if (i != j) {
                    a1r = (arj + ari) / 2;
                    a1i = (aij - aii) / 2;
                    a2r = (aij + aii) / 2;
                    a2i = (ari - arj) / 2;

                    b1r = (brj + bri) / 2;
                    b1i = (bij - bii) / 2;
                    b2r = (bij + bii) / 2;
                    b2i = (bri - brj) / 2;

                    aReal[j] = a1r * b1r - a1i * b1i - a2r * b2i - a2i * b2r;
                    aImag[j] = a1r * b1i + a1i * b1r + a2r * b2r - a2i * b2i;
                    bReal[j] = a1r * b2r - a1i * b2i + a2r * b1r - a2i * b1i;
                    bImag[j] = a1r * b2i + a1i * b2r + a2r * b1i + a2i * b1r;
                }
            }

            FastFourierTransform.fft(new double[][]{aReal, aImag}, true);
            FastFourierTransform.fft(new double[][]{bReal, bImag}, true);

            int[] ans = PrimitiveBuffers.allocIntPow2(need);
            for (int i = 0; i < need; i++) {
                long aa = DigitUtils.mod(Math.round(aReal[i]), mod);
                long bb = DigitUtils.mod(Math.round(bReal[i]), mod);
                long cc = DigitUtils.mod(Math.round(aImag[i]), mod);
                ans[i] = DigitUtils.mod(aa + (bb << 15) + (cc << 30), mod);
            }

            PrimitiveBuffers.release(aReal, bReal, aImag, bImag);
            return ans;
        }

    }
}


import java.io.*;
import java.lang.*;
import static java.lang.Math.max;
import static java.lang.Math.pow;
import java.lang.reflect.*;
import java.math.BigInteger;
import static java.math.BigInteger.*;
import java.security.CodeSource;
import java.security.KeyStore;
import java.util.*;
import static java.util.Arrays.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;

// https://netbeans.org/kb/73/java/editor-codereference_ru.html#display

public class Main {

    private void run() throws Exception {
        err = System.err;
        boolean oj = true;
        try {
            oj = System.getProperty("MYLOCAL") == null;
        } catch (Exception e) {
        }

        if( oj ){
            sc = new FastScanner(new InputStreamReader(System.in));
            out = new PrintWriter(new OutputStreamWriter(System.out));
        }
        else{
            try {
                sc = new FastScanner(new FileReader("input.txt"));
                out = new PrintWriter(new FileWriter("output.txt"));
            } catch ( IOException e) {
                MLE();
            }
        }
        solve();

        out.flush();
    }

    FastScanner sc;
    PrintWriter out;
    PrintStream err;

    void MLE(){
        int[][] arr = new int[1024*1024][];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = new int[1024*1024];
        }
    }

    private int getBit(int msk, int pos) {
        return (msk >> pos) & 1;
    }

    class FastScanner {

        BufferedReader br;
        StringTokenizer st;

        FastScanner(InputStreamReader reader) {
            br = new BufferedReader(reader);
            st = new StringTokenizer("");
        }

        String next() {
            while( !st.hasMoreElements() )
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException ex) {
                    MLE();
                }
            return st.nextToken();
        }

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

    public static void main(String[] args) throws Exception {
        new Main().run();
    }

    //-------------------------------------------------------------------//

    final long mod = (long)1e9 + 7;
    int n;

    void solve(){
//        int p = 5;
//        out.println( new BF((1<<p)-1).bf() );
//        out.println( cleaver(p) );
//        out.println( getDP(0,p-1) );

        {
            n = sc.nextInt();
            int p = 31 - Integer.numberOfLeadingZeros(n);
            out.println( getAns(0,p) );
        }

//        for( n = 1; n <= 15; ++n ){
//            int p = 31 - Integer.numberOfLeadingZeros(n);
//            out.println( getAns(0,p) );
//
//            out.println( new BF(n).bf() );
//            out.println();
//            out.flush();
//
//        }
    }

//    long getAns( int cntOnes, int pos ){
//        if( pos == -1 ) return 1;
//
//        long ans = 0;
//        if( getBit(n,pos) == 1 ){
//            ans += getDP( cntOnes, pos - 1);
//            ans += getAns( cntOnes+1, pos - 1);
//            ans += getAns( cntOnes, pos - 1) * ( (1<<cntOnes) - 1 );
//        }
//        else{
//            ans += getAns( cntOnes, pos - 1);
//        }
//        err.printf( "%d %d %d\n", cntOnes, pos, ans );
//        return ans;
//    }

    long[][] getAns = new long[100][100];
    long[][] getDP = new long[100][100];
    {
        for (long[] ls : getAns) fill( ls, -1 );
        for (long[] ls : getDP ) fill( ls, -1 );
    }

    long getAns( int cntOnes, int pos ){
        if( pos == -1 ) return 1;

        if( getAns[cntOnes][pos] != -1 ) return getAns[cntOnes][pos];

        long ans = 0;
        // add vector
        if( getBit(n,pos) == 1 ){
            ans += getAns( cntOnes+1, pos - 1);
        }

        // don't add vector
        if( cntOnes == 0 ){
            if( getBit(n,pos) == 1 )
                ans += getDP( cntOnes, pos - 1 );
            else
                ans += getAns( cntOnes, pos - 1 );
        }
        else{
            if( getBit(n,pos) == 1 ){
                // set 0
                ans += getDP( cntOnes, pos - 1) * (1<<(cntOnes-1)) % mod;
                // set 1
                ans += getAns( cntOnes, pos - 1) * (1<<(cntOnes-1)) % mod;
            }
            else{
                // set 0
                ans += getAns( cntOnes, pos - 1) * (1<<(cntOnes-1)) % mod;
            }
        }
        err.printf( "%d %d %d\n", cntOnes, pos, ans );
        return getAns[cntOnes][pos] = ans % mod;
    }

    long getDP( int cntOnes, int pos ){
        if( pos == -1 ) return 1;

        if( getDP[cntOnes][pos] != -1 ) return getDP[cntOnes][pos];
        long ans = 0;
        ans += getDP( cntOnes+1, pos - 1);
        ans += getDP( cntOnes, pos - 1) * (1<<cntOnes) % mod;
        return getDP[cntOnes][pos] = ans % mod;
    }

}


import java.io.*;
import java.lang.*;
import static java.lang.Math.max;
import static java.lang.Math.pow;
import java.lang.reflect.*;
import java.math.BigInteger;
import static java.math.BigInteger.*;
import java.security.CodeSource;
import java.security.KeyStore;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;

// https://netbeans.org/kb/73/java/editor-codereference_ru.html#display

public class Main {

    private void run() throws Exception {
        err = System.err;
        boolean oj = true;
        try {
            oj = System.getProperty("MYLOCAL") == null;
        } catch (Exception e) {
        }

        if( oj ){
            sc = new FastScanner(new InputStreamReader(System.in));
            out = new PrintWriter(new OutputStreamWriter(System.out));
        }
        else{
            try {
                sc = new FastScanner(new FileReader("input.txt"));
                out = new PrintWriter(new FileWriter("output.txt"));
            } catch ( IOException e) {
                MLE();
            }
        }
        solve();

        out.flush();
    }

    FastScanner sc;
    PrintWriter out;
    PrintStream err;

    void MLE(){
        int[][] arr = new int[1024*1024][];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = new int[1024*1024];
        }
    }

    private int getBit(int msk, int pos) {
        return (msk >> pos) & 1;
    }

    class FastScanner {

        BufferedReader br;
        StringTokenizer st;

        FastScanner(InputStreamReader reader) {
            br = new BufferedReader(reader);
            st = new StringTokenizer("");
        }

        String next() {
            while( !st.hasMoreElements() )
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException ex) {
                    MLE();
                }
            return st.nextToken();
        }

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

    public static void main(String[] args) throws Exception {
        new Main().run();
    }

    //-------------------------------------------------------------------//

    long f( int n ){ return n <= 1? 1 : n * f(n-1); }

    long C( int m, int n ){
        if(!( m <= n ))
            MLE();
        return f(n) / f(m) / f(n-m);
    }

    class BF{

        int nMax, ans, sz;
        int[] ord;

        BF( int _nMax ){
            nMax = _nMax;
            ord = new int[100];
        }

        void f( int val ){
            if( val == nMax + 1 ){
                if( sz == 0 ) return;
                int[] arr = Arrays.copyOf(ord, sz);

                for( int a : arr )
                for (int b : arr )
                    if( Arrays.binarySearch(arr, a^b) < 0 )
                        return;

                ++ans;
                //show(arr);err.println();
                solveGaus(arr);
            }
            else{
                ord[sz++] = val;
                f(val+1);
                --sz;

                f(val+1);
            }
        }

        int bf(){
            f(0);
            return ans;
        }

        void solveGaus(int[] arr) {

            err.println( "ans: " + ans );
            show(arr);err.println();

            int[] jj = new int[100];
            int n = arr.length;
            int j = 25;
            for( int i = 0; i < n; ++i ){
                cyc:
                for( ; 0 <= j; --j ){
                    for( int ii = i; ii < n; ++ii ){
                        if( ((1<<j)&arr[ii]) != 0 ){
                            int t = arr[i];
                            arr[i] = arr[ii];
                            arr[ii] = t;
                            break cyc;
                        }
                    }
                }

                if( j == -1 ){
                    arr = Arrays.copyOf(arr, i);
                    break;
                }

                jj[i] = j;
                for( int ii = i + 1; ii < n; ++ii ){
                    if( ((1<<j)&arr[ii]) != 0 ){
                        arr[ii] ^= arr[i];
                    }
                }
            }

            n = arr.length;
            if( j != -1 )
            for( int i = n-1; 0 <= i; --i ){
                j = jj[i];
                while( ((1<<j)&arr[i]) != 0  ) --j;
                for( int ii = i - 1; 0 <= ii; --ii ){
                    if( ((1<<j)&arr[ii]) != 0 ){
                        arr[ii] ^= arr[i];
                    }
                }
            }

            show(arr);err.println( "--------------\n" );

        }

        private void show(int[] arr) {
            for( int v : arr ){
                err.printf( "%5s\n", Integer.toBinaryString(v) );
            }
        }

    }

    final long mod = (long)1e9 + 7;
    int n;

    void solve(){
//        int p = 5;
//        out.println( new BF((1<<p)-1).bf() );
//        out.println( cleaver(p) );
//        out.println( getDP(0,p-1) );

        {
            n = sc.nextInt();
            int p = 31 - Integer.numberOfLeadingZeros(n);
            out.println( getAns(0,p) );
        }

//        for( n = 1; n <= 15; ++n ){
//            int p = 31 - Integer.numberOfLeadingZeros(n);
//            out.println( getAns(0,p) );
//
//            out.println( new BF(n).bf() );
//            out.println();
//            out.flush();
//
//        }
    }

//    long getAns( int cntOnes, int pos ){
//        if( pos == -1 ) return 1;
//
//        long ans = 0;
//        if( getBit(n,pos) == 1 ){
//            ans += getDP( cntOnes, pos - 1);
//            ans += getAns( cntOnes+1, pos - 1);
//            ans += getAns( cntOnes, pos - 1) * ( (1<<cntOnes) - 1 );
//        }
//        else{
//            ans += getAns( cntOnes, pos - 1);
//        }
//        err.printf( "%d %d %d\n", cntOnes, pos, ans );
//        return ans;
//    }

    long getAns( int cntOnes, int pos ){
        if( pos == -1 ) return 1;

        long ans = 0;
        // add vector
        if( getBit(n,pos) == 1 ){
            ans += getAns( cntOnes+1, pos - 1);
        }

        // don't add vector
        if( cntOnes == 0 ){
            if( getBit(n,pos) == 1 )
                ans += getDP( cntOnes, pos - 1 );
            else
                ans += getAns( cntOnes, pos - 1 );
        }
        else{
            if( getBit(n,pos) == 1 ){
                // set 0
                ans += getDP( cntOnes, pos - 1) * (1<<(cntOnes-1)) % mod;
                // set 1
                ans += getAns( cntOnes, pos - 1) * (1<<(cntOnes-1)) % mod;
            }
            else{
                // set 0
                ans += getAns( cntOnes, pos - 1) * (1<<(cntOnes-1)) % mod;
            }
        }
        err.printf( "%d %d %d\n", cntOnes, pos, ans );
        return ans % mod;
    }

    long getDP( int cntOnes, int pos ){
        if( pos == -1 ) return 1;
        long ans = 0;
        ans += getDP( cntOnes+1, pos - 1);
        ans += getDP( cntOnes, pos - 1) * (1<<cntOnes) % mod;
        return ans % mod;
    }

    @SuppressWarnings("empty-statement")
    long cleaver( int pow2 ){
        long ans = 1;

        for (int msk = 1; msk < (1<<pow2); msk++) {
            int b = 0, e = 30;
            for( ; (msk & (1<<e)) == 0; e-- );
            for( ; (msk & (1<<b)) == 0; b++ );

            long curAns = 1;
            for( int pos = 30, cnt1 = 0; 0 <= pos; --pos ){
                if( getBit(msk,pos)==1 ){
                    ++cnt1;
                }
                else{
                    curAns *= 1L << cnt1;
                    curAns %= mod;
                }
            }
            ans += curAns;
            ans %= mod;
        }

        return ans;
    }

    void fff(){
            for (int c = 1; c <= 10; c++) {
            double ans = 1;
            for (int lp = 1; lp <= c; lp++)
                for (int cntBaseVar = 1; cntBaseVar <= lp; cntBaseVar++) {
                    double cur =
                        C(cntBaseVar - 1, lp - 1) *
                        //pow(2, (c - lp) * cntBaseVar);
                        pow( pow(2,(c-lp)), cntBaseVar);
                    ans += cur;
                    err.println( lp +" "+ cntBaseVar +" "+ cur );
                }

            err.println("ans: " + ans);
            err.println();
        }
    }

}


import java.io.*;

public class CF388D {

    final static long MOD = 1000000007;

    public static void solve(Input in, PrintWriter out) throws IOException {
        long k = in.nextLong();
        if (k == 0) {
            out.println(1);
            return;
        }
        int n = 0;
        while (1L << n <= k) {
            ++n;
        }
        long[] pow2 = new long[n * n + 1];
        pow2[0] = 1;
        for (int i = 1; i < pow2.length; ++i) {
            pow2[i] = (pow2[i - 1] * 2) % MOD;
        }
        long[][][] d = new long[2][n + 1][n + 1];
        d[1][0][0] = 1;
        long ans = 1;
        for (int i = 0; i < n; ++i) {
            long bit = 1L << (n - i - 1);
            boolean set = (k & bit) != 0;
            for (int j = 0; j <= i; ++j) {
                d[0][i + 1][j] = (d[0][i + 1][j] + d[0][i][j]) % MOD;
                d[set ? 0 : 1][i + 1][j] = (d[set ? 0 : 1][i + 1][j] + d[1][i][j]) % MOD;
                d[0][i + 1][j + 1] = (d[0][i + 1][j + 1] + d[0][i][j]) % MOD;
                ans = (ans + d[0][i][j] * pow2[(n - i - 1) * (j + 1)]) % MOD;
                if (set) {
                    d[1][i + 1][j + 1] = (d[1][i + 1][j + 1] + d[1][i][j]) % MOD;
                    ans = (ans + d[1][i][j] * pow2[(n - i - 1) * j] % MOD * ((k & (bit - 1)) + 1)) % MOD;
                }
            }
        }
        out.println(ans);
    }

    public static void main(String[] args) throws IOException {
        PrintWriter out = new PrintWriter(System.out);
        solve(new Input(new BufferedReader(new InputStreamReader(System.in))), out);
        out.close();
    }

    static class Input {
        BufferedReader in;
        StringBuilder sb = new StringBuilder();

        public Input(BufferedReader in) {
            this.in = in;
        }

        public Input(String s) {
            this.in = new BufferedReader(new StringReader(s));
        }

        public String next() throws IOException {
            sb.setLength(0);
            while (true) {
                int c = in.read();
                if (c == -1) {
                    return null;
                }
                if (" \n\r\t".indexOf(c) == -1) {
                    sb.append((char)c);
                    break;
                }
            }
            while (true) {
                int c = in.read();
                if (c == -1 || " \n\r\t".indexOf(c) != -1) {
                    break;
                }
                sb.append((char)c);
            }
            return sb.toString();
        }

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

        public long nextLong() throws IOException {
            return Long.parseLong(next());
        }

        public double nextDouble() throws IOException {
            return Double.parseDouble(next());
        }
    }
}


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;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
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 {
    static final int MODULO = (int) (1e9 + 7);

    public void solve(int testNumber, InputReader in, PrintWriter out) {
        int k = in.nextInt();
        int[][] ways = new int[32][2];
        ways[0][0] = 1;
        int[] p2 = new int[10000];
        p2[0] = 1;
        for (int i = 1; i < p2.length; ++i) p2[i] = 2 * p2[i - 1] % MODULO;
        int res = 1;
        for (int bit = 30; bit >= 0; --bit) {
            int[][] nways = new int[32][2];
            if ((k & (1 << bit)) != 0) {
                for (int cnt = 0; cnt < 32; ++cnt) {
                    if (ways[cnt][0] != 0) {
                        nways[cnt + 1][0] = (nways[cnt + 1][0] + ways[cnt][0]) % MODULO;
                        res = (int) ((res + ways[cnt][0] * (long) p2[cnt * bit] % MODULO * ((k & ((1 << bit) - 1)) + 1) % MODULO) % MODULO);
                        nways[cnt][1] = (nways[cnt][1] + ways[cnt][0]) % MODULO;
                    }
                }
            } else {
                for (int cnt = 0; cnt < 32; ++cnt) {
                    if (ways[cnt][0] != 0) {
                        nways[cnt][0] = (nways[cnt][0] + ways[cnt][0]) % MODULO;
                    }
                }
            }

            for (int cnt = 0; cnt < 32; ++cnt) if (ways[cnt][1] != 0) {
                nways[cnt][1] = (nways[cnt][1] + ways[cnt][1]) % MODULO;
                nways[cnt + 1][1] = (nways[cnt + 1][1] + ways[cnt][1]) % MODULO;
                res = (int) ((res + ways[cnt][1] * (long) p2[(cnt + 1) * bit] % MODULO) % MODULO);
            }
            ways = nways;
        }
        out.println(res);
    }
}

class InputReader {
    public BufferedReader reader;
    public StringTokenizer tokenizer;

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

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

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

    }


import java.io.*;
import java.util.*;

public class Solution {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
		int n = in.nextInt();
		int x[] = new int[n], y[] = new int[n], t = 0;
		List<Integer> s = new ArrayList<Integer>();
		for(int i = 0; i < n; i++) {
			x[i] = in.nextInt();
			y[i] = in.nextInt();
			if(x[i] < x[t])
				t = i;
			s.add(i);
		}
		System.out.print(t + 1 + " ");
		s.remove(new Integer(t));
		String str = in.next();
		double ang = Math.PI / 2 - 1E-10;
		for(int i = 0; i < str.length(); i++) {
			double m = 4;
			int im = -1, factor = (str.charAt(i) == 'L') ? 1 : -1;
			for(int j : s) {
				double a = dif(Math.atan2(y[j] - y[t], x[j] - x[t]), ang) * factor;
				if(a < m) {
					m = a;
					im = j;
				}
			}
			s.remove(new Integer(im));
			ang = Math.atan2(y[im] - y[t], x[im] - x[t]);
			t = im;
			System.out.print(t + 1 + " ");
		}
		System.out.print(s.remove(0) + 1 + " ");
		System.out.println();
		in.close();

	}

	private static double dif(double a1, double a2) {
		double d = a1 - a2;
		while(d > Math.PI)
			d -= 2 * Math.PI;
		while(d < -Math.PI)
			d += 2 * Math.PI;
		return d;
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * @author Don Li
 */
public class ContactATC {

    int[] t;

    void solve() {
        int n = in.nextInt(), w = in.nextInt();
        int[] x = new int[n], v = new int[n];
        for (int i = 0; i < n; i++) {
            x[i] = -in.nextInt();
            v[i] = in.nextInt();
        }

        Fraction[] one = new Fraction[n];
        Fraction[] two = new Fraction[n];
        for (int i = 0; i < n; i++) {
            one[i] = new Fraction(x[i], v[i] - w);
            two[i] = new Fraction(x[i], v[i] + w);
        }

        Fraction[] uOne = unique(one);
        Fraction[] uTwo = unique(two);

        Plane[] planes = new Plane[n];
        for (int i = 0; i < n; i++) {
            planes[i] = new Plane(Arrays.binarySearch(uOne, one[i]), Arrays.binarySearch(uTwo, two[i]));
        }
        Arrays.sort(planes, (a, b) -> {
            if (a.t1 != b.t1) return Integer.compare(a.t1, b.t1);
            return -Integer.compare(a.t2, b.t2);
        });

        long ans = 0;
        t = new int[n];
        for (Plane p : planes) {
            ans += sum(n - 1) - sum(p.t2 - 1);
            add(p.t2, 1);
        }
        out.println(ans);
    }

    int sum(int i) {
        int res = 0;
        for (int x = i; x >= 0; x = (x & (x + 1)) - 1) res += t[x];
        return res;
    }

    void add(int i, int delta) {
        for (int x = i; x < t.length; x = x | (x + 1)) t[x] += delta;
    }

    Fraction[] unique(Fraction[] a) {
        a = Arrays.copyOf(a, a.length);
        Arrays.sort(a);
        int sz = 0;
        for (int i = 0; i < a.length; i++) {
            if (sz == 0 || a[i].compareTo(a[i - 1]) != 0) a[sz++] = a[i];
        }
        return Arrays.copyOf(a, sz);
    }

    static class Plane {
        int t1, t2;

        Plane(int t1, int t2) {
            this.t1 = t1;
            this.t2 = t2;
        }
    }

    static class Fraction implements Comparable<Fraction> {
        long a, b;

        Fraction(long a, long b) {
            if (b == 0) throw new AssertionError();
            if (b < 0) {
                a = -a;
                b = -b;
            }
            this.a = a;
            this.b = b;
        }

        @Override
        public int compareTo(Fraction o) {
            return Long.compare(a * o.b, b * o.a);
        }
    }

    public static void main(String[] args) {
        in = new FastScanner(new BufferedReader(new InputStreamReader(System.in)));
        out = new PrintWriter(System.out);
        new ContactATC().solve();
        out.close();
    }

    static FastScanner in;
    static PrintWriter out;

    static class FastScanner {
        BufferedReader in;
        StringTokenizer st;

        public FastScanner(BufferedReader in) {
            this.in = in;
        }

        public String nextToken() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(in.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

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

        public long nextLong() {
            return Long.parseLong(nextToken());
        }

        public double nextDouble() {
            return Double.parseDouble(nextToken());
        }
    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author chaku
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskC solver = new TaskC();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskC {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
                int n=in.nextInt(),w=in.nextInt();
                bit=new int[100010];
                int[] x=new int[n];
                int[] v=new int[n];
                for(int i=0;i<n;i++)
                {
                        x[i]=in.nextInt();
                        v[i]=in.nextInt();
                }
                Pair[][] pr=new Pair[n][2];
                for(int i=0;i<n;i++)
                {
                        int[] den=new int[2];
                        den[0]=v[i]+w;
                        den[1]=v[i]-w;
                        //Arrays.sort(den);
                        int num=x[i];
                        pr[i][0]=new Pair(num,den[1]);
                        pr[i][1]=new Pair(num,den[0]);
                }
                Arrays.sort(pr,new Comparator<Pair[]>(){
                        public int compare(Pair[] p1,Pair[] p2)
                        {
                                Pair f1=p1[1];
                                Pair f2=p2[1];
                                Pair s1=p1[0];
                                Pair s2=p2[0];
                                int v1=cmp(s1,s2);
                                if(v1!=0)return v1;
                                else
                                {
                                    return cmp(f2,f1);
                                }
                        }
                });

                Pair[] list=new Pair[n];
                for(int i=0;i<n;i++)
                {
                    list[i]=new Pair(pr[i][1].a,pr[i][1].b);
                }
                Arrays.sort(list,new Comparator<Pair>(){
                    public int compare(Pair p1,Pair p2)
                    {
                        return cmp(p1,p2);
                    }
                });
                /*
                for(Pair p:list)
                {
                    out.println(p.a+" "+p.b);
                }
                */
                int ind=1;
                for(int i=1;i<n;i++)
                {
                    if(cmp(list[i],list[i-1])!=0)
                    {
                        list[ind++]=list[i];
                    }
                }
                list=Arrays.copyOf(list,ind);
                int[] d=new int[n];
                for(int i=0;i<n;i++)
                {
                    int index=Arrays.binarySearch(list,pr[i][1],new Comparator<Pair>(){
                      public int compare(Pair p1,Pair p2)
                      {
                        return cmp(p1,p2);
                      }
                    });
                    if(index<0)index=-index-2;
                    d[i]=index+1;
                    //out.println(d[i]);
                }
                long ans=0;
                for(int i=0;i<n;i++)
                {
                    ans+=query(n-d[i]+1);
                    add(n-d[i]+1,1,n);
                }
                out.println(ans);
                /*
                for(Pair p:list)
                {
                    out.println(p.a+" "+p.b);
                }

                for(Pair[] p:pr)
                {
                        System.out.println(p[0].a+" "+p[0].b+", "+p[1].a+" "+p[1].b);
                }
                */

        }

        public static int cmp(Pair p1,Pair p2)
        {
                long l=(long)p1.a*p2.b-(long)p1.b*p2.a;
                if(l>0)return 1;
                else if(l<0)return -1;
                return 0;
        }
        static int bit[];

        static void add(int x,int d,int n)
        {
            for(int i=x;i<=n;i+=i&-i)bit[i]+=d;
        }

        static int query(int x)
        {
            int ret=0;
            for(int i=x;i>0;i-=i&-i)ret+=bit[i];
            return ret;
        }

        static class Pair
        {
                int a;int b;
                public Pair(int a,int b)
                {
                        this.a=Math.abs(a);this.b=Math.abs(b);
                }
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void println(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

        public void println(int i) {
            writer.println(i);
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(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++];
        }

        public int nextInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public int[] nextIntArray(int n) {
            int[] array = new int[n];
            for (int i = 0; i < n; ++i) array[i] = nextInt();
            return array;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


//package educational.round68;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.InputMismatchException;

public class G3 {
	InputStream is;
	PrintWriter out;
//	String INPUT = "42";
	String INPUT = "";

	public static void trnz(long... o)
	{
		for(int i = 0;i < o.length;i++)if(o[i] != 0)System.out.print(i+":"+o[i]+" ");
		System.out.println();
	}

	void solve()
	{
		BigInteger n = new BigInteger(ns());
		long ans = 0;
		for(int i = 1;i <= 9;i++){
			for(int j = 1;j <= i;j++){
				if(gcd(i, j) == 1){
					if(i == 1){
						ans += n.mod(BigInteger.valueOf(998244353L)).longValue();
					}else{
						long lans = count(n, i, j);
						if(i != j){
							ans += lans*2;
						}else{
							ans += lans;
						}
//						if(lans > 0)tr(i, j, lans, ans);
					}
				}
			}
		}
		out.println(ans % 998244353);
	}

	long count(BigInteger N, int u, int v)
	{
		char[] s = ("0" + N.divide(BigInteger.valueOf(u)).add(BigInteger.ONE).toString()).toCharArray();

		int n = s.length;
		// u:2 v:1
		// u倍したときにt*uを含んでいるか
		// v倍したときにt*vを含んでいるか
		int w = 9/u;
		long[][][][] dp = new long[1<<w][1<<w][10][10]; // valid carry
		long[][][][] ep = new long[1<<w][1<<w][10][10]; // valid carry
		int mod = 998244353;
		ep[0][0][0][0] = 1;

		int[][] va0 = new int[10][10];
		int[][] va1 = new int[10][10];
		int[][] nextc0 = new int[10][10];
		int[][] nextc1 = new int[10][10];
		for(int d = 0;d < 10;d++){
			for(int c0 = 0;c0 <= 9;c0++){
				int v0 = d*u + c0;
				for(int t = 1;t <= w;t++){
					if(t*u == v0%10){
						va0[d][c0] |= 1<<t-1;
					}
				}
				nextc0[d][c0] = v0 / 10;
			}
			for(int c1 = 0;c1 <= 9;c1++){
				int v1 = d*v + c1;
				for(int t = 1;t <= w;t++){
					if(t*v == v1%10){
						va1[d][c1] |= 1<<t-1;
					}
				}
				nextc1[d][c1] = v1 / 10;
			}
		}

		for(int i = n-1;i >= 0;i--){
			long[][][][] ndp = new long[1<<w][1<<w][10][10]; // valid carry
			long[][][][] nep = new long[1<<w][1<<w][10][10]; // valid carry

			for(int j = 0;j < 1<<w;j++){
				for(int k = 0;k < 1<<w;k++){
					for(int l = 0;l < 10;l++){
						for(int m = 0;m < 10;m++){
							int d = s[i]-'0';
							int nj = j|va0[d][l];
							int nk = k|va1[d][m];
							int nl = nextc0[d][l];
							int nm = nextc1[d][m];
							ndp[nj][nk][nl][nm] += dp[j][k][l][m];
							if(ndp[nj][nk][nl][nm] >= mod)ndp[nj][nk][nl][nm] -= mod;
						}
					}
				}
			}

			for(int j = 0;j < 1<<w;j++){
				for(int k = 0;k < 1<<w;k++){
					for(int l = 0;l < 10;l++){
						for(int m = 0;m < 10;m++){
							for(int d = 0;d < 10;d++){
								int nj = j|va0[d][l];
								int nk = k|va1[d][m];
								int nl = nextc0[d][l];
								int nm = nextc1[d][m];
								nep[nj][nk][nl][nm] += ep[j][k][l][m];
								if(nep[nj][nk][nl][nm] >= mod)nep[nj][nk][nl][nm] -= mod;
								if(d < s[i]-'0'){
									ndp[nj][nk][nl][nm] += ep[j][k][l][m];
									if(ndp[nj][nk][nl][nm] >= mod)ndp[nj][nk][nl][nm] -= mod;
								}
							}
						}
					}
				}
			}

			dp = ndp;
			ep = nep;
		}

		long ret = 0;
		for(int i = 0;i < 1<<w;i++){
			for(int j = 0;j < 1<<w;j++){
				if((i&j) != 0){
					ret += dp[i][j][0][0];
				}
			}
		}
		return ret % mod;
	}

	public static int gcd(int a, int b) {
		while (b > 0) {
			int c = a;
			a = b;
			b = c % b;
		}
		return a;
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new G3().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


import java.io.*;
import java.util.*;

public class D {

	BufferedReader br;
	PrintWriter out;
	StringTokenizer st;
	boolean eof;

	static final int MOD = 777777777;

	int[][] c = new int[257][];
	{
		for (int i = 0; i < c.length; i++) {
			c[i] = new int[i + 1];
			c[i][0] = c[i][i] = 1;
			for (int j = 1; j < i; j++) {
				c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
				if (c[i][j] >= MOD)
					c[i][j] -= MOD;
			}
		}
//		System.err.println(Arrays.toString(c[4]));
	}

	int solve(int n, int kn) {

		int[] dp = new int[n + 1];
		dp[0] = 1;

		for (int i = 1; i <= n; i++) {

			int[] next = new int[n + 1];

			// who said i?
			if (i == kn) {
				for (int k = 0; k + i <= n; k++) {
					if (dp[k] != 0) {
						next[k + i] += (int) ((long) dp[k] * c[n - k][i] % MOD);
						if (next[k + i] >= MOD)
							next[k + i] -= MOD;
					}
				}
			} else {
				// liars
				for (int j = 0; j <= n; j++)
					// how many people said i
					if (j != i) {
						for (int k = 0; k + j <= n; k++)
							// how many people already said
							if (dp[k] != 0) {
								next[k + j] += (int) ((long) dp[k]
										* c[n - k][j] % MOD);
								if (next[k + j] >= MOD)
									next[k + j] -= MOD;
							}
					}
			}
			dp = next;
		}

		return dp[n];
	}

	D() throws IOException {
		br = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		int n = nextInt();
		int k = nextInt();
		out.println(solve(n, n - k));
		out.close();
	}

	public static void main(String[] args) throws IOException {
		new D();
	}

	String nextToken() {
		while (st == null || !st.hasMoreTokens()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (Exception e) {
				eof = true;
				return null;
			}
		}
		return st.nextToken();
	}

	String nextString() {
		try {
			return br.readLine();
		} catch (IOException e) {
			eof = true;
			return null;
		}
	}

	int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}
}


import java.util.List;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Comparator;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.math.BigInteger;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author AlexFetisov
 */
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 {
    private static final int MOD = 777777777;
    static final int[][] C = IntegerUtils.getC(1000, MOD);

    public void solve(int testNumber, InputReader in, PrintWriter out) {
        int n = in.nextInt();
        int k = in.nextInt();
        out.println(calcDP(n, k));
    }

    int calcDP(int n, int k) {
        long[][][] dp = new long[n + 1][n + 1][n + 1];
        for (int i = 0; i <= n; ++i) {
            if (i == 1) {
                dp[1][i][0] = C[n][i];
            } else {
                dp[1][i][i] = C[n][i];
            }
        }
        for (int i = 1; i < n; ++i) {
            for (int j = 0; j <= n; ++j) {
                for (int p = 0; p <= k; ++p) {
                    if (dp[i][j][p] != 0) {
                        int rest = n - j;
                        for (int am = 0; am <= rest; ++am) {
                            if (am == i + 1) {
                                dp[i+1][j + am][p] += dp[i][j][p] * C[rest][am];
                                dp[i + 1][j + am][p] %= MOD;
                            } else {
                                if (p + am <= k) {
                                    dp[i + 1][j + am][p + am] += dp[i][j][p] * C[rest][am];
                                    dp[i + 1][j + am][p + am] %= MOD;
                                }
                            }
                        }
                    }
                }
            }
        }
        return (int)dp[n][n][k];
    }
}

class IntegerUtils {

    public static int[][] getC(int N, int MOD) {
        int[][] C = new int[N][];
        for (int i = 0; i < N; ++i) {
            C[i] = new int[i + 1];
            for (int j = 0; j <= i; ++j) {
                if (j == 0 || j == i) {
                    C[i][j] = 1;
                    if (C[i][j] >= MOD) C[i][j] -= MOD;
                } else {
                    C[i][j] = (C[i-1][j-1] + C[i-1][j]);
                    if (C[i][j] >= MOD) C[i][j] -= MOD;
                }
            }
        }
        return C;
    }

}

class InputReader {
    private BufferedReader reader;
    private StringTokenizer stt;

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

    public String nextLine() {
        try {
            return reader.readLine();
        } catch (IOException e) {
            return null;
        }
    }

    public String nextString() {
        while (stt == null || !stt.hasMoreTokens()) {
            stt = new StringTokenizer(nextLine());
        }
        return stt.nextToken();
    }

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

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import javax.print.attribute.standard.Sides;

public class strings_kp2 {

    static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static int[] tableLong;
    static int[] tableShort1;
    static int[] tableShort2;

    static int[] createTable(int[] w) {
        int[] table = new int[w.length];
        int pos = 2;
        int cnd = 0;

        table[0] = -1;
        while (pos < w.length) {
            if (w[pos - 1] == w[cnd]) {
                cnd++;
                table[pos] = cnd;
                pos++;

            } else if (cnd > 0) {
                cnd = table[cnd];
            } else {
                table[pos] = 0;
                pos++;
            }
        }
        return table;
    }

    private static int kmp(int[] w, int[] s, int[] table) {

        int m = 0;
        int i = 0;

        while (m + i < s.length) {
            if (w[i] == s[m + i]) {
                if (i == w.length - 1) {
                    return m;
                }
                i++;
            } else {
                m = m + i - table[i];
                if (table[i] > -1) {
                    i = table[i];
                } else {
                    i = 0;
                }
            }

        }
        return s.length;
    }

    static enum Side {

        T {

            Side opposite() {
                return Side.B;
            }

            Side flip() {
                return Side.L;
            }
        }, L {

            Side opposite() {
                return Side.R;
            }

            Side flip() {
                return Side.T;
            }
        }, R {

            Side opposite() {
                return Side.L;
            }

            Side flip() {
                return Side.B;
            }
        }, B {

            Side opposite() {
                return Side.T;
            }

            Side flip() {
                return Side.R;
            }
        };
        Line[] lines;

        abstract Side opposite();

        abstract Side flip();
    }

    static int nextInt() {
        try {
            st.nextToken();
            return (int) st.nval;
        } catch (IOException ex) {
            return 0;
        }
    }

    static Side nextSide() {
        try {
            st.nextToken();
            switch (st.sval.charAt(0)) {
                case 'T':
                    return Side.T;
                case 'L':
                    return Side.L;
                case 'R':
                    return Side.R;
                default:
                    return Side.B;
            }
        } catch (IOException ex) {
            return Side.T;
        }
    }

    static enum Type {

        TL, TR, TB, LR, LB, RB;
        int count;
    }

    static int getType(int start, int end) {
        switch (start) {
            case 0:
                switch (end) {
                    case 1:
                        return 0;
                    case 2:
                        return 1;
                    default:
                        return 2;
                }
            case 1:
                switch (end) {
                    case 2:
                        return 3;
                    default:
                        return 4;
                }
            default:
                return 5;
        }
    }

    static final class Line {

        Side s1, s2;
        int a, b;
        Type type;
        boolean used;

        private Line(Side s1, Side s2, int a, int b) {
            if (s1.ordinal() > s2.ordinal()) {
                Side t = s1;
                s1 = s2;
                s2 = t;
                int ti = a;
                a = b;
                b = ti;
            }
            this.s1 = s1;
            this.s2 = s2;
            this.a = a;
            this.b = b;
            s1.lines[a] = this;
            s2.lines[b] = this;
            setType();
        }

        public String toString() {
            return "(" + s1 + ":" + a + "," + s2 + ":" + b + ")";
        }

        void setType() {
            switch (s1) {
                case T:
                    switch (s2) {
                        case R:
                            type = Type.TR;
                            break;
                        case L:
                            type = Type.TL;
                            break;
                        default:
                            type = Type.TB;
                    }
                    break;
                case L:
                    switch (s2) {
                        case R:
                            type = Type.LR;
                            break;
                        default:
                            type = Type.LB;
                    }
                    break;
                default:
                    type = Type.RB;
            }
        }
    }
    static int n, m;
    static boolean flip;
    static int shortCount;
    static ArrayList<Integer> theCycle = new ArrayList<Integer>();
    static ArrayList<ArrayList<Integer>> allCycles = new ArrayList<ArrayList<Integer>>();
    static ArrayList<Integer> cyclePoints = new ArrayList<Integer>();
    static ArrayList<ArrayList<Integer>> allPoints = new ArrayList<ArrayList<Integer>>();
    static ArrayList<Integer> cycleSides = new ArrayList<Integer>();
    static ArrayList<Integer> rotations = new ArrayList<Integer>();

    static boolean findSolution() {
        if (Type.LR.count > 0) {
            return false;
        }
        if (Type.TR.count != Type.LB.count) {
            return false;
        }
        if (Type.TL.count != Type.RB.count) {
            return false;
        }
        if (Type.TB.count != m - (Type.TL.count + Type.TR.count)) {
            return false;
        }
        shortCount = Math.min(Type.TL.count, Type.TR.count);

        int topSize = m - (shortCount * 2);
        int sideSize = n - (shortCount * 2);

        if (Type.TL.count == Type.TR.count) {
            theCycle.add(Type.TB.ordinal());
            cyclePoints.add(shortCount);
            cycleSides.add(0);
            allCycles.add(theCycle);
            allPoints.add(cyclePoints);
            for (int i = shortCount + 1; i < shortCount + topSize; i++) {
                ArrayList<Integer> newCycle = new ArrayList<Integer>();
                ArrayList<Integer> newPoints = new ArrayList<Integer>();
                newCycle.add(Type.TB.ordinal());
                newPoints.add(i);
                allCycles.add(newCycle);
                allPoints.add(newPoints);
            }
            return true;
        }
        boolean right = Type.TL.count < Type.TR.count;

        int l = Side.L.ordinal();
        int r = Side.R.ordinal();
        int t = Side.T.ordinal();
        int b = Side.B.ordinal();
        int[][] nextSides = new int[4][m];
        int[][] nextPoints = new int[4][m];
        if (right) {
            for (int i = 0; i < sideSize; i++) {
                nextSides[l][shortCount + i] = b;
                nextPoints[l][shortCount + i] = shortCount + sideSize - i - 1;
                nextSides[b][shortCount + sideSize - i - 1] = l;
                nextPoints[b][shortCount + sideSize - i - 1] = shortCount + i;

                nextSides[r][shortCount + i] = t;
                nextPoints[r][shortCount + i] = m - shortCount - i - 1;
                nextSides[t][m - shortCount - i - 1] = r;
                nextPoints[t][m - shortCount - i - 1] = shortCount + i;
            }

            for (int i = 0; i < topSize - sideSize; i++) {
                nextSides[t][shortCount + i] = b;
                nextPoints[t][shortCount + i] = shortCount + sideSize + i;
                nextSides[b][shortCount + sideSize + i] = t;
                nextPoints[b][shortCount + sideSize + i] = shortCount + i;
            }
        } else {
            for (int i = 0; i < sideSize; i++) {
                nextSides[l][shortCount + i] = t;
                nextPoints[l][shortCount + i] = shortCount + i;
                nextSides[t][shortCount + i] = l;
                nextPoints[t][shortCount + i] = shortCount + i;

                nextSides[r][shortCount + i] = b;
                nextPoints[r][shortCount + i] = m - shortCount - sideSize + i;
                nextSides[b][m - shortCount - sideSize + i] = r;
                nextPoints[b][m - shortCount - sideSize + i] = shortCount + i;
            }

            for (int i = 0; i < topSize - sideSize; i++) {
                nextSides[b][shortCount + i] = t;
                nextPoints[b][shortCount + i] = shortCount + sideSize + i;
                nextSides[t][shortCount + sideSize + i] = b;
                nextPoints[t][shortCount + sideSize + i] = shortCount + i;
            }
        }
        boolean[][] used = new boolean[4][m];
        int curSide = t;
        int curPos = shortCount;
        while (!used[curSide][curPos]) {
            used[curSide][curPos] = true;
            int nextSide = nextSides[curSide][curPos];
            int nextPos = nextPoints[curSide][curPos];
            theCycle.add(getType(curSide, nextSide));
            cyclePoints.add(curPos);
            cycleSides.add(curSide % 3 == 0 ? 0 : 1);
            curSide = 3 - nextSide;
            curPos = nextPos;
        }
        allCycles.add(theCycle);
        allPoints.add(cyclePoints);
        for (int i = shortCount; i < shortCount + topSize; i++) {
            if (!used[0][i]) {
                ArrayList<Integer> newCycle = new ArrayList<Integer>();
                ArrayList<Integer> newPoints = new ArrayList<Integer>();
                curSide = t;
                curPos = i;
                while (!used[curSide][curPos]) {
                    used[curSide][curPos] = true;
                    int nextSide = nextSides[curSide][curPos];
                    int nextPos = nextPoints[curSide][curPos];
                    newCycle.add(getType(curSide, nextSide));
                    newPoints.add(curPos);
                    curSide = 3 - nextSide;
                    curPos = nextPos;
                }
                allCycles.add(newCycle);
                allPoints.add(newPoints);
            }
        }

        return true;
    }

    public static void main(String[] args) {
        n = nextInt();
        m = nextInt();

        if (n > m) {
            flip = true;
            int t = n;
            n = m;
            m = t;
        }

        Side.T.lines = new Line[m];
        Side.B.lines = new Line[m];
        Side.L.lines = new Line[n];
        Side.R.lines = new Line[n];

        ArrayList<Line> lines = new ArrayList<Line>();

        for (int i = 0; i < n + m; i++) {
            Side s1 = nextSide();
            Side s2 = nextSide();
            if (flip) {
                s1 = s1.flip();
                s2 = s2.flip();
            }
            lines.add(new Line(s1, s2, nextInt() - 1, nextInt() - 1));
        }
        for (Line l : lines) {
            l.type.count++;
        }

        if (!findSolution()) {
            System.out.println("No solution");
            return;
        }
        int[] longCycle = new int[theCycle.size()];
        for (int i = 0; i < theCycle.size(); i++) {
            longCycle[i] = theCycle.get(i);
        }

        int[] shortCycle1 = {0, 4, 5, 1};
        int[] shortCycle2 = {0, 1, 5, 4};

        tableLong = createTable(longCycle);
        tableShort1 = createTable(shortCycle1);
        tableShort2 = createTable(shortCycle2);
        rotations.add(0);
        for (int i = 1; i < allCycles.size(); i++) {
            int length = theCycle.size();
            int[] curCycle = new int[length * 2];
            for (int j = 0; j < length; j++) {
                curCycle[j] = allCycles.get(i).get(j);
            }
            for (int j = 0; j < length; j++) {
                curCycle[j + length] = allCycles.get(i).get(j);
            }
            rotations.add(kmp(longCycle, curCycle, tableLong));
        }

        ArrayList<ArrayList<Line>> cycles = new ArrayList<ArrayList<Line>>();

        for (Line l : lines) {
            if (!l.used) {
                ArrayList<Line> cycle = new ArrayList<Line>();
                Line next = l;
                while (!next.used) {
                    cycle.add(next);
                    next.used = true;
                    if (!next.s2.opposite().lines[next.b].used) {
                        next = next.s2.opposite().lines[next.b];
                    } else if (!next.s1.opposite().lines[next.a].used) {
                        next = next.s1.opposite().lines[next.a];
                    }
                }
                cycles.add(cycle);
            }
        }

        int actualShortCount = 0;
        int longCount = 0;

        int[] rows = new int[n];
        int[] cols = new int[m];

        for (ArrayList<Line> cycle : cycles) {
            int length = cycle.size();

            int[] curCycle = new int[length * 2];
            for (int i = 0; i < length; i++) {
                curCycle[i] = cycle.get(i).type.ordinal();
            }
            for (int i = 0; i < length; i++) {
                curCycle[length + i] = cycle.get(i).type.ordinal();
            }

            if (length == 4) {
                int rot1 = kmp(shortCycle1, curCycle, tableShort1);
                int rot2 = kmp(shortCycle2, curCycle, tableShort2);
                if (rot1 != 8 || rot2 != 8) {
                    for (Line l : cycle) {
                        if (l.type == Type.TL) {
                            rows[actualShortCount] = l.b;
                            cols[actualShortCount] = l.a;
                        } else if (l.type == Type.RB) {
                            rows[n - 1 - actualShortCount] = l.a;
                            cols[m - 1 - actualShortCount] = l.b;
                        }
                    }
                    actualShortCount++;
                    continue;
                }
            }
            if (length != longCycle.length) {
                System.out.println("No solution");
                return;
            }

            int rot = kmp(longCycle, curCycle, tableLong);
            if (rot == 2 * length) {
                System.out.println("No solution");
                return;
            }
            for (int i = 0; i < length; i++) {
                int pos = allPoints.get(longCount).get((i + rotations.get(longCount)) % length);
                int value = cycle.get((rot + i) % length).a;
                if (cycleSides.get(i) == 0) {
                    cols[pos] = value;
                } else {
                    rows[pos] = value;
                }
            }
            longCount++;

        }

        if (flip) {
            int[] t = rows;
            rows = cols;
            cols = t;
        }

        for (int i = 0; i < rows.length; i++) {
            System.out.print((rows[i] + 1) + " ");
        }
        System.out.println();
        for (int i = 0; i < cols.length; i++) {
            System.out.print((cols[i] + 1) + " ");
        }
        System.out.println();
    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Mixture {

    static long[] favorite = new long[3];
    static long[][] matrix = new long[3][3];

    static void add(int to, int from) {
        for (int j = 0; j <= 2; j++) {
            matrix[to][j] += matrix[from][j];
        }
    }

    static void subtract(int to, int from) {
        for (int j = 0; j <= 2; j++) {
            matrix[to][j] -= matrix[from][j];
        }
    }

    static void reduce(int a, int b) {
        while (favorite[a] != 0L && favorite[b] != 0L) {
            if (favorite[a] >= favorite[b]) {
                favorite[a] -= favorite[b];
                subtract(a, b);
            } else {
                favorite[b] -= favorite[a];
                subtract(b, a);
            }
        }
        if (favorite[a] != 0L) {
            favorite[b] += favorite[a];
            add(b, a);
            favorite[a] -= favorite[b];
            subtract(a, b);
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer tokenizer = new StringTokenizer(in.readLine());
        for (int j = 0; j <= 2; j++) {
            favorite[j] = Long.parseLong(tokenizer.nextToken());
            matrix[j][j] = 1L;
        }
        reduce(0, 1);
        reduce(1, 2);
        /*for (int y = 0; y <= 2; y++) {
            for (int x = 0; x <= 2; x++) {
                System.out.print(matrix[y][x] + " ");
            }
            System.out.println();
        }*/
        int amt00 = 0;
        int amtPosInfty = 0;
        int amtNegInfty = 0;
        int amtMatch = 0;
        TreeMap<Rational, Integer> positive = new TreeMap<>();
        TreeMap<Rational, Integer> negative = new TreeMap<>();
        int j = 0;
        int n = Integer.parseInt(in.readLine());
        long[] xs = new long[n + 1];
        long[] ys = new long[n + 1];
        StringBuilder out = new StringBuilder();
        for (; n > 0; n--) {
            tokenizer = new StringTokenizer(in.readLine());
            if (tokenizer.nextToken().charAt(0) == 'A') {
                j++;
                for (int a = 0; a <= 2; a++) {
                    long k = Long.parseLong(tokenizer.nextToken());
                    xs[j] += matrix[0][a] * k;
                    ys[j] += matrix[1][a] * k;
                }
                if (xs[j] == 0L) {
                    if (ys[j] == 0L) {
                        amt00++;
                    } else if (ys[j] > 0L) {
                        amtPosInfty++;
                    } else {
                        amtNegInfty++;
                    }
                } else {
                    Rational q = new Rational(ys[j], xs[j]);
                    if (xs[j] > 0L) {
                        if (positive.compute(q, (__, prev) -> prev == null ? 1 : (prev + 1)) == 1 && negative.containsKey(q)) {
                            amtMatch++;
                        }
                    } else {
                        if (negative.compute(q, (__, prev) -> prev == null ? 1 : (prev + 1)) == 1 && positive.containsKey(q)) {
                            amtMatch++;
                        }
                    }
                }
            } else {
                int j2 = j;
                j = Integer.parseInt(tokenizer.nextToken());
                if (xs[j] == 0L) {
                    if (ys[j] == 0L) {
                        amt00--;
                    } else if (ys[j] > 0L) {
                        amtPosInfty--;
                    } else {
                        amtNegInfty--;
                    }
                } else {
                    Rational q = new Rational(ys[j], xs[j]);
                    if (xs[j] > 0L) {
                        if (positive.compute(q, (__, prev) -> prev == 1 ? null : (prev - 1)) == null && negative.containsKey(q)) {
                            amtMatch--;
                        }
                    } else {
                        if (negative.compute(q, (__, prev) -> prev == 1 ? null : (prev - 1)) == null && positive.containsKey(q)) {
                            amtMatch--;
                        }
                    }
                }
                j = j2;
            }
            if (amt00 > 0) {
                out.append(1);
            } else if (amtMatch > 0 || (amtPosInfty > 0 && amtNegInfty > 0)) {
                out.append(2);
            } else {
                boolean exists = false;
                if (positive.size() >= 2) {
                    Rational q = negative.ceilingKey(positive.firstKey());
                    if (q != null && q.compareTo(positive.lastKey()) <= 0) {
                        exists = true;
                    }
                }
                if (!exists && negative.size() >= 2) {
                    Rational q = positive.ceilingKey(negative.firstKey());
                    if (q != null && q.compareTo(negative.lastKey()) <= 0) {
                        exists = true;
                    }
                }
                if (!exists && amtPosInfty > 0 && !positive.isEmpty() && !negative.isEmpty()) {
                    Rational q = positive.firstKey();
                    Rational r = negative.lastKey();
                    Rational s = new Rational(-r.num, r.denom);
                    if (q.compareTo(s) < 0) {
                        exists = true;
                    }
                }
                if (!exists && amtNegInfty > 0 && !positive.isEmpty() && !negative.isEmpty()) {
                    Rational q = positive.lastKey();
                    Rational r = negative.firstKey();
                    Rational s = new Rational(-r.num, r.denom);
                    if (q.compareTo(s) > 0) {
                        exists = true;
                    }
                }
                if (exists) {
                    out.append(3);
                } else {
                    out.append(0);
                }
            }
            out.append('\n');
        }
        System.out.print(out);
    }

    static class Rational implements Comparable<Rational> {
        final long num;
        final long denom;

        Rational(long num, long denom) {
            if (denom > 0L) {
                this.num = num;
                this.denom = denom;
            } else {
                this.num = -num;
                this.denom = -denom;
            }
        }

        @Override
        public int compareTo(Rational other) {
            long d = (num * other.denom) - (other.num * denom);
            if (d > 0L) {
                return 1;
            } else if (d == 0L) {
                return 0;
            } else {
                return -1;
            }
        }
    }
}