The fundamental prerequisite for justice is not to be correct, but to be strong. That's why justice is always the victor.The Cinderswarm Bee. Koyomi knows it.The bees, according to their nature, live in a tree. To be more specific, a complete binary tree with n nodes numbered from 1 to n. The node numbered 1 is the root, and the parent of the i-th (2 ≤ i ≤ n) node is . Note that, however, all edges in the tree are undirected.Koyomi adds m extra undirected edges to the tree, creating more complication to trick the bees. And you're here to count the number of simple paths in the resulting graph, modulo 109 + 7. A simple path is an alternating sequence of adjacent nodes and undirected edges, which begins and ends with nodes and does not contain any node more than once. Do note that a single node is also considered a valid simple path under this definition. Please refer to the examples and notes below for instances.

The first line of input contains two space-separated integers n and m (1 ≤ n ≤ 109, 0 ≤ m ≤ 4) — the number of nodes in the tree and the number of extra edges respectively. The following m lines each contains two space-separated integers u and v (1 ≤ u, v ≤ n, u ≠ v) — describing an undirected extra edge whose endpoints are u and v. Note that there may be multiple edges between nodes in the resulting graph.

Output one integer — the number of simple paths in the resulting graph, modulo 109 + 7.

NoteIn the first example, the paths are: (1); (2); (3); (1, 2); (2, 1); (1, 3); (3, 1); (2, 1, 3); (3, 1, 2). (For the sake of clarity, the edges between nodes are omitted since there are no multiple edges in this case.)In the second example, the paths are: (1); (1, 2); (1, 2, 3); (1, 3); (1, 3, 2); and similarly for paths starting with 2 and 3. (5 × 3 = 15 paths in total.)In the third example, the paths are: (1); (2); any undirected edge connecting the two nodes travelled in either direction. (2 + 5 × 2 = 12 paths in total.)

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

public class MainD {
	static final StdIn in = new StdIn();
	static final PrintWriter out = new PrintWriter(System.out);
	static final long M=(long)1e9+7;
	static int n=in.nextInt(), m=in.nextInt();
	static Map<Integer, Node> graph = new HashMap<Integer, Node>();

	public static void main(String[] args) {
		addNode(1);
		for(int i=0; i<m; ++i) {
			int u=in.nextInt(), v=in.nextInt();
			addNode(u).adj.add(v);
			addNode(v).adj.add(u);
		}
		for(Map.Entry<Integer, Node> nodeEntry : graph.entrySet()) {
			Node u=nodeEntry.getValue();
			for(int i=u.adj.size()-1; i>=0; --i) {
				if(!graph.containsKey(u.adj.get(i))) {
					u.s+=sts(u.adj.get(i));
					u.adj.remove(i);
				}
			}
		}
		long ans=0;
		for(Map.Entry<Integer, Node> nodeEntry : graph.entrySet())
			ans=(dfs(nodeEntry.getKey(), 0)+ans)%M;
		out.println(ans);
		out.close();
	}

	static Node addNode(int u) {
		if(u<=0)
			return null;
		Node node = graph.get(u);
		if(node!=null)
			return node;
		node = new Node();
		if(u>1)
			node.adj.add(u/2);
		if(u*2<=n)
			node.adj.add(u*2);
		if(u*2+1<=n)
			node.adj.add(u*2+1);
		graph.put(u, node);
		addNode(u/2);
		return node;
	}

	static long sts(int u) {
		long res=0;
		int l=u, r=u;
		while(r<=n) {
			res+=r-l+1;
			l=2*l;
			r=2*r+1;
		}
		return (res+Math.min(r, n)-Math.min(l, n+1)+1)%M;
	}

	static long dfs(int u, long ps) {
		Node node=graph.get(u);
		if(ps==0)
			ps=node.s;
		node.active=true;
		long res=ps*node.s;
		for(int v : node.adj)
			if(!graph.get(v).active)
				res+=dfs(v, ps);
		node.active=false;
		return res;
	}

	static class Node {
		List<Integer> adj = new ArrayList<Integer>();
		long s=1;
		boolean active;
	}

	interface Input {
		public String next();
		public String nextLine();
		public int nextInt();
		public long nextLong();
		public double nextDouble();
	}
	static class StdIn implements Input {
		final private int BUFFER_SIZE = 1 << 16;
		private DataInputStream din;
		private byte[] buffer;
		private int bufferPointer, bytesRead;
		public StdIn() {
			din = new DataInputStream(System.in);
			buffer = new byte[BUFFER_SIZE];
			bufferPointer = bytesRead = 0;
		}
		public StdIn(InputStream in) {
			try{
				din = new DataInputStream(in);
			} catch(Exception e) {
				throw new RuntimeException();
			}
			buffer = new byte[BUFFER_SIZE];
			bufferPointer = bytesRead = 0;
		}
		public String next() {
			int c;
			while((c=read())!=-1&&(c==' '||c=='\n'||c=='\r'));
			StringBuilder s = new StringBuilder();
			while (c != -1)
			{
				if (c == ' ' || c == '\n'||c=='\r')
					break;
				s.append((char)c);
				c=read();
			}
			return s.toString();
		}
		public String nextLine() {
			int c;
			while((c=read())!=-1&&(c==' '||c=='\n'||c=='\r'));
			StringBuilder s = new StringBuilder();
			while (c != -1)
			{
				if (c == '\n'||c=='\r')
					break;
				s.append((char)c);
				c = read();
			}
			return s.toString();
		}
		public int nextInt() {
			int ret = 0;
			byte c = read();
			while (c <= ' ')
				c = read();
			boolean neg = (c == '-');
			if (neg)
				c = read();
			do
				ret = ret * 10 + c - '0';
			while ((c = read()) >= '0' && c <= '9');

			if (neg)
				return -ret;
			return ret;
		}
		public int[] readIntArray(int n) {
			int[] ar = new int[n];
			for(int i=0; i<n; ++i)
				ar[i]=nextInt();
			return ar;
		}
		public long nextLong() {
			long ret = 0;
			byte c = read();
			while (c <= ' ')
				c = read();
			boolean neg = (c == '-');
			if (neg)
				c = read();
			do
				ret = ret * 10 + c - '0';
			while ((c = read()) >= '0' && c <= '9');
			if (neg)
				return -ret;
			return ret;
		}
		public long[] readLongArray(int n) {
			long[] ar = new long[n];
			for(int i=0; i<n; ++i)
				ar[i]=nextLong();
			return ar;
		}
		public double nextDouble() {
			double ret = 0, div = 1;
			byte c = read();
			while (c <= ' ')
				c = read();
			boolean neg = (c == '-');
			if (neg)
				c = read();
			do
				ret = ret * 10 + c - '0';
			while ((c = read()) >= '0' && c <= '9');
			if (c == '.')
				while ((c = read()) >= '0' && c <= '9')
					ret += (c - '0') / (div *= 10);
			if (neg)
				return -ret;
			return ret;
		}
		private void fillBuffer() throws IOException {
			bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
			if (bytesRead == -1)
				buffer[0] = -1;
		}
		private byte read() {
			try{
				if (bufferPointer == bytesRead)
					fillBuffer();
				return buffer[bufferPointer++];
			} catch(IOException e) {
				throw new RuntimeException();
			}
		}
		public void close() throws IOException {
			if (din == null)
				return;
			din.close();
		}
	}
}

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

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

    int N = 300;
    int MOD = (int) 1e9 + 7;

    Map<Integer, Integer> map = new HashMap<>();

    int[] num = new int[N];
    List<Integer>[] G = new List[N];

    int tot = 0;
    boolean[] vis = new boolean[N];

    void solve() {
        int n = in.nextInt(), m = in.nextInt();
        int[] fr = new int[m], to = new int[m];
        for (int i = 0; i < m; i++) {
            fr[i] = in.nextInt();
            to[i] = in.nextInt();
        }

        int d = 0;
        while ((1 << d) <= n) d++;

        getId(1);
        for (int i = 0; i < m; i++) {
            int u = fr[i];
            while (u > 0) {
                getId(u);
                u >>= 1;
            }
            u = to[i];
            while (u > 0) {
                getId(u);
                u >>= 1;
            }
        }

        for (int i = 0; i < N; i++) G[i] = new ArrayList<>();
        for (int u : map.keySet()) {
            int id = map.get(u);
            if (u > 1) {
                addEdge(getId(u), getId(u >> 1));
            }
            num[id] = calcSize(u, n, d);
        }

        dfs(0, -1);

        for (int i = 0; i < m; i++) {
            addEdge(getId(fr[i]), getId(to[i]));
        }

        int res = 0;
        for (int i = 0; i < map.size(); i++) {
            tot = 0;
            dfs(i);
            res = (int) ((res + (long) tot * num[i] % MOD) % MOD);
        }
        out.println(res);
    }

    int getId(int x) {
        if (!map.containsKey(x)) map.put(x, map.size());
        return map.get(x);
    }

    void addEdge(int u, int v) {
        G[u].add(v);
        G[v].add(u);
    }

    int calcSize(int u, int n, int d) {
        int t = u, c = 0;
        while (t > 0) {
            c++;
            t >>= 1;
        }
        int sz = (1 << (d - c + 1)) - 1;
        t = c;
        while (t < d) {
            t++;
            u = u << 1 | 1;
        }
        return sz - Math.max(0, Math.min(u - n, 1 << (d - c)));
    }

    void dfs(int u, int p) {
        for (int v : G[u]) {
            if (v != p) {
                num[u] -= num[v];
                dfs(v, u);
            }
        }
    }

    void dfs(int u) {
        tot = (tot + num[u]) % MOD;
        vis[u] = true;
        for (int v : G[u]) {
            if (!vis[v]) dfs(v);
        }
        vis[u] = false;
    }

    public static void main(String[] args) {
        in = new FastScanner(new BufferedReader(new InputStreamReader(System.in)));
        out = new PrintWriter(System.out);
        new TheOverdosingUbiquity().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());
        }
    }
}

//package round439;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

public class D {
	InputStream is;
	PrintWriter out;
//	String INPUT = "3 1 2 3";
//	String INPUT = "2 1 1 2";
//	String INPUT = "4 1 2 3";
//	String INPUT = "5 1 4 5";
//	String INPUT = "5 1 3 5";
//	String INPUT = "4 1 1 3";
//	String INPUT = "4 2\r\n" +
//			"2 3 1 2 ";
//	String INPUT = "4 2\r\n" +
//			"2 4 1 4 ";
	String INPUT = "";

	//    A1 A2 A3 ...
	// A0              An
	// A0*(A1+...+An)
	// A1*(A2+...+An)
	// ((A0+..+An)^2-A0^2-..-An^2)/2

	void solve()
	{
		int n = ni(), m = ni();
		int[][] ps = new int[m][];
		for(int i = 0;i < m;i++){
			ps[i] = na(2);
		}
//		for(int i = 1;i <= n;i++)tr(i, n, count(i,n));
		int mod = 1000000007;
		long ans = (long)n*n % mod;
		for(int i = 1;i < 1<<m;i++){
			int[] inds = new int[Integer.bitCount(i)];
			int p = 0;
			for(int j = 0;j < m;j++){
				if(i<<~j<0)inds[p++] = j;
			}
			int o = Integer.bitCount(i);
			do{
				// 0:0->1, 1:1->0
				for(int ptn = 0;ptn < 1<<o;ptn++){
					ans += go(inds, ptn, ps, n);
					ans %= mod;
//					tr("ans", i, inds, ptn, ans);
				}
			}while(nextPermutation(inds));
		}
		out.println(ans % mod);
	}

	long go(int[] inds, int ptn, int[][] ps, int n)
	{
		// collide?
		int[][] paths = new int[2*(inds.length-1)][];
		int p = 0;
		for(int i = 0;i < inds.length-1;i++){
			int f = ptn<<~i>=0 ? ps[inds[i]][1] : ps[inds[i]][0];
			int t = ptn<<~(i+1)>=0 ? ps[inds[i+1]][0] : ps[inds[i+1]][1];
			int lca = lca(f, t);
			paths[p++] = new int[]{f, lca};
			if(lca != t){
				int clca = t/(Integer.highestOneBit(t)/Integer.highestOneBit(lca)/2);
				paths[p++] = new int[]{t, clca};
			}
		}
		for(int i = 0;i < p;i++){
			for(int j = i+1;j < p;j++){
				if(col(paths[i], paths[j]))return 0;
			}
		}
//		tr("UM");
		int[] st = {
				ptn<<~0>=0 ? ps[inds[0]][0] : ps[inds[0]][1],
				ptn<<~(inds.length-1)>=0 ? ps[inds[inds.length-1]][1] : ps[inds[inds.length-1]][0]
		};
		if(st[0] == st[1])return 0;
//		tr("OK", st);
		int[] tops = new int[2];
		for(int j = 0;j < 2;j++){
			int top = 0;
			for(int i = 0;i < p;i++){
				int lcad = lca(st[j], paths[i][0]);
				if(Integer.highestOneBit(lcad) >= Integer.highestOneBit(paths[i][1])){
					top = Math.max(top, lcad);
				}
			}
			if(top == st[j])return 0; // collide

			if(top == 0){
				top = 1;
			}else{
				int otop = top;
				top = st[j] / (Integer.highestOneBit(st[j]) / Integer.highestOneBit(top) / 2);
				assert top / 2 == otop;
			}
			tops[j] = top;
		}
//		tr(st, tops);
		if(tops[0] == tops[1]){
			return calc(tops[0], paths, p, n, st[0], st[1]);
		}else{
			return (long)all(tops[0], paths, p, n, st[0]) *
					all(tops[1], paths, p, n, st[1]);
		}
	}

	int count(int x, int n)
	{
		int first = Integer.highestOneBit(n) / Integer.highestOneBit(x) * x;
		int last = Integer.highestOneBit(n) / Integer.highestOneBit(x) * (x+1);
		int base = Integer.highestOneBit(n) / Integer.highestOneBit(x) - 1;
		return base + Math.max(0, Math.min(last-first, n-first+1));
	}

	int all(int top, int[][] paths, int p, int n, int tar)
	{
		int[] lroot = new int[p];
		int q = 0;
		for(int i = 0;i < p;i++){
			int llca = lca(paths[i][1], tar);
			if(Integer.highestOneBit(llca) < Integer.highestOneBit(top))continue;
			lroot[q++] = paths[i][1];
		}
		boolean[] ng = new boolean[q];
		for(int i = 0;i < q;i++){
			for(int k = 0;k < q;k++){
				if(i == k)continue;
				if(lca(lroot[i], lroot[k]) == lroot[k]){
					ng[i] = true;
				}
			}
		}
		int all = count(top, n);
		for(int i = 0;i < q;i++){
			if(!ng[i]){
				all -= count(lroot[i], n);
			}
		}
		return all;
	}

	long calc(int top, int[][] paths, int p, int n, int t1, int t2)
	{
		int[] lroot = new int[p];
		int q = 0;
		for(int i = 0;i < p;i++){
			int llca = lca(paths[i][1], t1);
			if(Integer.highestOneBit(llca) < Integer.highestOneBit(top))continue;
			lroot[q++] = paths[i][1];
		}
		boolean[] ng = new boolean[q];
		for(int i = 0;i < q;i++){
			for(int k = 0;k < q;k++){
				if(i == k)continue;
				if(lca(lroot[i], lroot[k]) == lroot[k]){
					ng[i] = true;
				}
			}
		}
		int[] route = new int[100];
		int tl = lca(t1, t2);
		int r = 0;
		for(int z = t1;z != tl;z /= 2){
			route[r++] = z;
		}
		int or = r;
		for(int z = t2;z != tl;z /= 2){
			route[r++] = z;
		}
		route[r++] = tl;
		for(int i = or, j = r-1;i < j;i++,j--){
			int d = route[i]; route[i] = route[j]; route[j] = d;
		}
		route = Arrays.copyOf(route, r);
		int[] has = new int[r];
		for(int i = 0;i < r;i++){
			has[i] = count(route[i], n);
		}
		for(int i = or-1;i >= 1;i--){
			has[i] -= has[i-1];
		}
		for(int i = or+1;i < r-1;i++){
			has[i] -= has[i+1];
		}
		for(int i = 0;i < q;i++){
			if(!ng[i] && lca(lroot[i], tl) == tl){
				int hit = lca(lroot[i], t1);
				if(hit == tl)hit = lca(lroot[i], t2);
				for(int j = 0;j < r;j++){
					if(route[j] == hit){
						has[j] -= count(lroot[i], n);
						break;
					}
				}
			}
		}
		if(tl != t1 && tl != t2){
			has[or] = count(top, n) - count(tl, n) + 1;

			for(int i = 0;i < q;i++){
				if(!ng[i] && lca(lroot[i], tl) != tl){
					has[or] -= count(lroot[i], n);
				}
			}
		}else{
			int tlch = route[or == 0 ? 1 : r - 2];
			has[or] = count(top, n) - count(tlch, n);
			for(int i = 0;i < q;i++){
				if(!ng[i] && lca(lroot[i], tlch) != tlch){
					has[or] -= count(lroot[i], n);
				}
			}
		}
//		tr("route", route);
//		tr("has", has, lroot);
		long s1 = 0;
		long s2 = 0;
		for(int v : has){
			s1 += v;
			s2 += (long)v*v;
		}
		return (s1*s1-s2)/2;
	}

	public static int lca(long x, long y)
	{
		long xx = x<<Long.numberOfLeadingZeros(x);
		long yy = y<<Long.numberOfLeadingZeros(y);
		return (int)(x>>>Math.max(Long.numberOfLeadingZeros(Math.min(x, y)), 64-Long.numberOfLeadingZeros(xx^yy))-Long.numberOfLeadingZeros(x));
	}

	boolean col(int[] a, int[] b)
	{
		int l = lca(a[0], b[0]);
		if(Integer.highestOneBit(a[1]) <= Integer.highestOneBit(l) && Integer.highestOneBit(b[1]) <= Integer.highestOneBit(l)){
			return true;
		}else{
			return false;
		}
	}

	static boolean nextPermutation(int[] src) {
		int i;
		for (i = src.length - 2; i >= 0 && src[i] > src[i + 1]; i--)
			;
		if (i == -1)
			return false;
		int j;
		for (j = i + 1; j < src.length && src[i] < src[j]; j++)
			;
		int d = src[i];
		src[i] = src[j - 1];
		src[j - 1] = d;
		for (int p = i + 1, q = src.length - 1; p < q; p++, q--) {
			d = src[p];
			src[p] = src[q];
			src[q] = d;
		}
		return true;
	}

	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 D().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.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Iterator;
import java.io.BufferedWriter;
import java.util.Collection;
import java.util.Random;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

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

  static class TaskD {
    static final IntModular MOD = new IntModular();
    int n;
    int m;
    int[] end1;
    int[] end2;
    int res;
    boolean[] visited;
    BidirectionalGraph graph;
    IntArrayList points;
    IntArrayList pointCounts;

    public void solve(int testNumber, QuickScanner in, QuickWriter out) {
      n = in.nextInt();
      m = in.nextInt();
      end1 = new int[m];
      end2 = new int[m];
      in.nextInts(m, end1, end2);
      initPoints();
      initGraph();
      res = 0;
      visited = new boolean[points.size];
      for (int i = 0; i < points.size; ++i) {
        res = MOD.add(res, MOD.mul(pointCounts.get(i), dfs(i)));
      }
      out.println(res);
    }

    int dfs(int u) {
      visited[u] = true;
      int res = pointCounts.get(u);
      for (int v : graph.outNodes(u))
        if (!visited[v]) {
          res = MOD.add(res, dfs(v));
        }
      visited[u] = false;
      return res;
    }

    void initGraph() {
      graph = new BidirectionalGraph(points.size, points.size + m);
      points.forEach((point) -> {
        if (point > 1) {
          graph.add(points.lowerBound(point), points.lowerBound(point >> 1));
        }
      });
      for (int i = 0; i < m; ++i) {
        graph.add(points.lowerBound(end1[i]), points.lowerBound(end2[i]));
      }
    }

    void initPoints() {
      points = new IntArrayList();
      for (int i = 0; i < m; ++i) {
        addKeyPoints(end1[i]);
        addKeyPoints(end2[i]);
      }
      points.sortAndUnique();
      if (points.isEmpty()) {
        points.add(1);
      }
      pointCounts = new IntArrayList(points.size);
      for (int point : points) {
        int cnt = 1;
        if (!points.binarySearch(point << 1)) {
          cnt += calcSubtree(point << 1);
        }
        if (!points.binarySearch((point << 1) | 1)) {
          cnt += calcSubtree((point << 1) | 1);
        }
        pointCounts.add(cnt);
      }
    }

    int calcSubtree(int x) {
      int lower = x, upper = x;
      int res = 0;
      for (; lower <= n; lower <<= 1, upper = (upper << 1) | 1) {
        res += Math.min(n, upper) - lower + 1;
        if (n <= upper) break;
      }
      return res;
    }

    void addKeyPoints(int x) {
      for (; x > 0; x >>= 1) points.add(x);
    }

  }

  static abstract class AbstractBidirectionalGraph extends AbstractDirectedGraph implements BidirectionalGraphInterface {
    public AbstractBidirectionalGraph() {
      super();
    }

    public AbstractBidirectionalGraph(int vertexCapacity, int edgeCapacity) {
      super(vertexCapacity, edgeCapacity << 1);
    }

    public AbstractBidirectionalGraph(int vertexCapacity, int edgeCapacity, boolean initialize) {
      super(vertexCapacity, edgeCapacity << 1, initialize);
    }

    public void add(int u, int v) {
      super.add(u, v);
      super.add(v, u);
    }

  }

  static class QuickWriter {
    private final PrintWriter writer;

    public QuickWriter(OutputStream outputStream) {
      this.writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
    }

    public QuickWriter(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();
    }

  }

  static final class BidirectionalGraph extends AbstractBidirectionalGraph {
    public BidirectionalGraph() {
      super();
    }

    public BidirectionalGraph(int vertexCapacity, int edgeCapacity) {
      super(vertexCapacity, edgeCapacity);
    }

    public void createVertexStorage(int vertexCapacity) {
    }

    public void expandEdgeStorage(int edgeCapacity) {
    }

    public void initVertexStorage(int vertexCnt) {
    }

  }

  static class QuickScanner {
    private static final int BUFFER_SIZE = 1024;
    private InputStream stream;
    private byte[] buffer;
    private int currentPosition;
    private int numberOfChars;

    public QuickScanner(InputStream stream) {
      this.stream = stream;
      this.buffer = new byte[BUFFER_SIZE];
      this.currentPosition = 0;
      this.numberOfChars = 0;
    }

    public int nextInt() {
      int c = nextNonSpaceChar();
      boolean positive = true;
      if (c == '-') {
        positive = false;
        c = nextChar();
      }
      int res = 0;
      do {
        if (c < '0' || '9' < c) throw new RuntimeException();
        res = res * 10 + (c - '0');
        c = nextChar();
      } while (!isSpaceChar(c));
      return positive ? res : -res;
    }

    public void nextInts(int n, int[]... res) {
      int m = res.length;
      for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j) {
          res[j][i] = nextInt();
        }
    }

    public int nextNonSpaceChar() {
      int res = nextChar();
      for (; isSpaceChar(res) || res < 0; res = nextChar()) ;
      return res;
    }

    public int nextChar() {
      if (numberOfChars == -1) {
        throw new RuntimeException();
      }
      if (currentPosition >= numberOfChars) {
        currentPosition = 0;
        try {
          numberOfChars = stream.read(buffer);
        } catch (Exception e) {
          throw new RuntimeException(e);
        }
        if (numberOfChars <= 0) {
          return -1;
        }
      }
      return buffer[currentPosition++];
    }

    public boolean isSpaceChar(int c) {
      return c == ' ' || c == '\t' || isEndOfLineChar(c);
    }

    public boolean isEndOfLineChar(int c) {
      return c == '\n' || c == '\r' || c < 0;
    }

  }

  static interface IntCollection {
    int size();

    default boolean isEmpty() {
      return size() == 0;
    }

  }

  static class IntArrayList implements Displayable, IntCollection, Iterable<Integer> {
    private static final int[] EMPTY = {};
    public int[] values;
    public int size;

    public IntArrayList() {
      values = EMPTY;
      clear();
    }

    public IntArrayList(int capacity) {
      values = new int[IntUtils.nextPow2(capacity)];
      clear();
    }

    public IntArrayList(Collection<Integer> collection) {
      this(collection.size());
      addAll(collection);
    }

    public void clear() {
      size = 0;
    }

    public int size() {
      return size;
    }

    public void add(int value) {
      ensureCapacity(size + 1);
      addInternal(value);
    }

    public void addAll(Collection<Integer> values) {
      ensureCapacity(size + values.size());
      for (int value : values) {
        addInternal(value);
      }
    }

    public int get(int idx) {
      if (idx >= size) throw new ArrayIndexOutOfBoundsException();
      return values[idx];
    }

    public void sort() {
      IntArrayUtils.sort(values, 0, size);
    }

    public void unique() {
      size = IntArrayUtils.unique(values, 0, size);
    }

    public void sortAndUnique() {
      sort();
      unique();
    }

    public int lowerBound(int value) {
      return IntArrayUtils.lowerBound(values, 0, size, value);
    }

    public boolean binarySearch(int value) {
      int idx = lowerBound(value);
      return idx < size && get(idx) == value;
    }

    public void ensureCapacity(int capacity) {
      if (capacity <= values.length) return;
      int[] newValues = new int[IntUtils.nextPow2(capacity)];
      for (int i = 0; i < size; ++i) {
        newValues[i] = values[i];
      }
      values = newValues;
    }

    public Iterator<Integer> iterator() {
      return new Iterator<Integer>() {
        private int i = 0;

        public boolean hasNext() {
          return i < size;
        }

        public Integer next() {
          return values[i++];
        }
      };
    }

    private void addInternal(int value) {
      values[size++] = value;
    }

  }

  static class IntArrayUtils {
    private static final Random RANDOM = new Random(1000000007);

    public static int unique(int[] values, int fromIdx, int toIdx) {
      if (fromIdx == toIdx) return 0;
      int res = 1;
      for (int i = fromIdx + 1; i < toIdx; ++i) {
        if (values[i - 1] != values[i]) {
          values[fromIdx + res++] = values[i];
        }
      }
      return res;
    }

    public static void sort(int[] values, int fromIdx, int toIdx) {
      shuffle(values, fromIdx, toIdx);
      Arrays.sort(values, fromIdx, toIdx);
    }

    public static int lowerBound(int[] values, int fromIdx, int toIdx, int value) {
      int res = toIdx;
      for (int lower = fromIdx, upper = toIdx - 1; lower <= upper; ) {
        int medium = (lower + upper) >> 1;
        if (value <= values[medium]) {
          res = medium;
          upper = medium - 1;
        } else {
          lower = medium + 1;
        }
      }
      return res;
    }

    public static void swap(int[] values, int uIdx, int vIdx) {
      if (uIdx == vIdx) return;
      values[uIdx] ^= values[vIdx];
      values[vIdx] ^= values[uIdx];
      values[uIdx] ^= values[vIdx];
    }

    public static void shuffle(int[] values, int fromIdx, int toIdx) {
      for (int i = toIdx - fromIdx - 1; i > 0; --i) {
        swap(values, i + fromIdx, RANDOM.nextInt(i + 1) + fromIdx);
      }
    }

    public static int[] expand(int[] values, int newLength) {
      if (values != null && values.length >= newLength) return values;
      int[] res = new int[newLength];
      if (values == null) return res;
      for (int i = 0; i < values.length; ++i) res[i] = values[i];
      return res;
    }

  }

  static class IntUtils {
    public static boolean isPow2(int n) {
      return n > 0 && (n & (n - 1)) == 0;
    }

    public static int nextPow2(int n) {
      if (n < 1) return 1;
      return isPow2(n) ? n : Integer.highestOneBit(n) << 1;
    }

  }

  static interface DirectedGraphInterface {
  }

  static interface Displayable {
  }

  static abstract class AbstractDirectedGraph implements DirectedGraphInterface {
    protected int vertexCnt;
    protected int currentEdgeCnt;
    protected int[] fromIdx;
    protected int[] toIdx;
    protected int[] nextIn;
    protected int[] nextOut;
    protected int[] lastIn;
    protected int[] lastOut;
    protected int[] inDegree;
    protected int[] outDegree;

    public abstract void createVertexStorage(int vertexCapacity);

    public abstract void expandEdgeStorage(int edgeCapacity);

    public abstract void initVertexStorage(int vertexCnt);

    public AbstractDirectedGraph() {
    }

    public AbstractDirectedGraph(int vertexCapacity, int edgeCapacity) {
      this(vertexCapacity, edgeCapacity, true);
    }

    public AbstractDirectedGraph(int vertexCapacity, int edgeCapacity, boolean initialize) {
      ensureVertexCapacity(vertexCapacity);
      ensureEdgeCapacity(edgeCapacity);
      if (initialize) init(vertexCapacity);
    }

    public void init(int vertexCnt) {
      ensureVertexCapacity(vertexCnt);
      this.vertexCnt = vertexCnt;
      currentEdgeCnt = 0;
      Arrays.fill(inDegree, 0, vertexCnt, 0);
      Arrays.fill(outDegree, 0, vertexCnt, 0);
      Arrays.fill(lastIn, 0, vertexCnt, -1);
      Arrays.fill(lastOut, 0, vertexCnt, -1);
      initVertexStorage(vertexCnt);
    }

    public void add(int fromIdx, int toIdx) {
      ensureEdgeCapacity(currentEdgeCnt + 1);
      this.fromIdx[currentEdgeCnt] = fromIdx;
      this.toIdx[currentEdgeCnt] = toIdx;
      ++outDegree[fromIdx];
      ++inDegree[toIdx];
      nextOut[currentEdgeCnt] = lastOut[fromIdx];
      lastOut[fromIdx] = currentEdgeCnt;
      nextIn[currentEdgeCnt] = lastIn[toIdx];
      lastIn[toIdx] = currentEdgeCnt;
      ++currentEdgeCnt;
    }

    public int nextOut(int edgeIdx) {
      return nextOut[edgeIdx];
    }

    public Iterable<Integer> outNodes(int nodeIdx) {
      return () -> new Iterator<Integer>() {
        private int edgeIdx = lastOut[nodeIdx];

        public boolean hasNext() {
          return edgeIdx >= 0;
        }

        public Integer next() {
          int res = toIdx[edgeIdx];
          edgeIdx = nextOut(edgeIdx);
          return res;
        }
      };
    }

    private void ensureVertexCapacity(int vertexCapacity) {
      if (lastIn != null && lastIn.length >= vertexCapacity) return;
      int capacity = IntUtils.nextPow2(vertexCapacity);
      lastIn = new int[capacity];
      lastOut = new int[capacity];
      inDegree = new int[capacity];
      outDegree = new int[capacity];
      createVertexStorage(capacity);
    }

    private void ensureEdgeCapacity(int edgeCapacity) {
      if (fromIdx != null && fromIdx.length >= edgeCapacity) return;
      int capacity = IntUtils.nextPow2(edgeCapacity);
      fromIdx = IntArrayUtils.expand(fromIdx, capacity);
      toIdx = IntArrayUtils.expand(toIdx, capacity);
      nextIn = IntArrayUtils.expand(nextIn, capacity);
      nextOut = IntArrayUtils.expand(nextOut, capacity);
      expandEdgeStorage(capacity);
    }

  }

  static interface BidirectionalGraphInterface extends DirectedGraphInterface {
  }

  static class IntModular {
    private static final int MOD = 1000000007;
    public final int mod;
    private final int[] x;

    public IntModular() {
      this(MOD);
    }

    public IntModular(int mod) {
      this.mod = mod;
      this.x = new int[2];
    }

    public int add(int a, int b) {
      return fix(a + b);
    }

    public int fix(int a) {
      a = slightFix(a);
      return 0 <= a && a < mod ? a : slightFix(a % mod);
    }

    public int mul(int a, int b) {
      return a > 0
          ? (b < mod / a ? a * b : (int) ((long) a * b % mod))
          : 0;
    }

    private int slightFix(int a) {
      return a >= mod
          ? a - mod
          : a < 0 ? a + mod : a;
    }

  }
}

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

public class MainD {
	static final StdIn in = new StdIn();
	static final PrintWriter out = new PrintWriter(System.out);
	static final long M=(long)1e9+7;
	static int n=in.nextInt(), m=in.nextInt();
	static Map<Integer, Node> graph = new HashMap<Integer, Node>();

	public static void main(String[] args) {
		addNode(1);
		for(int i=0; i<m; ++i) {
			int u=in.nextInt(), v=in.nextInt();
			addNode(u).adj.add(v);
			addNode(v).adj.add(u);
		}
		for(Map.Entry<Integer, Node> nodeEntry : graph.entrySet()) {
			Node u=nodeEntry.getValue();
			for(int i=u.adj.size()-1; i>=0; --i) {
				if(!graph.containsKey(u.adj.get(i))) {
					u.s+=sts(u.adj.get(i));
					u.adj.remove(i);
				}
			}
		}
		long ans=0;
		for(Map.Entry<Integer, Node> nodeEntry : graph.entrySet())
			ans=(dfs(nodeEntry.getKey(), 0)+ans)%M;
		out.println(ans);
		out.close();
	}

	static Node addNode(int u) {
		if(u<=0)
			return null;
		Node node = graph.get(u);
		if(node!=null)
			return node;
		node = new Node();
		if(u>1)
			node.adj.add(u/2);
		if(u*2<=n)
			node.adj.add(u*2);
		if(u*2+1<=n)
			node.adj.add(u*2+1);
		graph.put(u, node);
		addNode(u/2);
		return node;
	}

	static long sts(int u) {
		long res=0;
		int l=u, r=u;
		while(r<=n) {
			res+=r-l+1;
			l=2*l;
			r=2*r+1;
		}
		return (res+Math.min(r, n)-Math.min(l, n))%M;
	}

	static long dfs(int u, long ps) {
		Node node=graph.get(u);
		if(ps==0)
			ps=node.s;
		node.active=true;
		long res=ps*node.s;
		for(int v : node.adj)
			if(!graph.get(v).active)
				res+=dfs(v, ps);
		node.active=false;
		return res;
	}

	static class Node {
		List<Integer> adj = new ArrayList<Integer>();
		long s=1;
		boolean active;
	}

	interface Input {
		public String next();
		public String nextLine();
		public int nextInt();
		public long nextLong();
		public double nextDouble();
	}
	static class StdIn implements Input {
		final private int BUFFER_SIZE = 1 << 16;
		private DataInputStream din;
		private byte[] buffer;
		private int bufferPointer, bytesRead;
		public StdIn() {
			din = new DataInputStream(System.in);
			buffer = new byte[BUFFER_SIZE];
			bufferPointer = bytesRead = 0;
		}
		public StdIn(InputStream in) {
			try{
				din = new DataInputStream(in);
			} catch(Exception e) {
				throw new RuntimeException();
			}
			buffer = new byte[BUFFER_SIZE];
			bufferPointer = bytesRead = 0;
		}
		public String next() {
			int c;
			while((c=read())!=-1&&(c==' '||c=='\n'||c=='\r'));
			StringBuilder s = new StringBuilder();
			while (c != -1)
			{
				if (c == ' ' || c == '\n'||c=='\r')
					break;
				s.append((char)c);
				c=read();
			}
			return s.toString();
		}
		public String nextLine() {
			int c;
			while((c=read())!=-1&&(c==' '||c=='\n'||c=='\r'));
			StringBuilder s = new StringBuilder();
			while (c != -1)
			{
				if (c == '\n'||c=='\r')
					break;
				s.append((char)c);
				c = read();
			}
			return s.toString();
		}
		public int nextInt() {
			int ret = 0;
			byte c = read();
			while (c <= ' ')
				c = read();
			boolean neg = (c == '-');
			if (neg)
				c = read();
			do
				ret = ret * 10 + c - '0';
			while ((c = read()) >= '0' && c <= '9');

			if (neg)
				return -ret;
			return ret;
		}
		public int[] readIntArray(int n) {
			int[] ar = new int[n];
			for(int i=0; i<n; ++i)
				ar[i]=nextInt();
			return ar;
		}
		public long nextLong() {
			long ret = 0;
			byte c = read();
			while (c <= ' ')
				c = read();
			boolean neg = (c == '-');
			if (neg)
				c = read();
			do
				ret = ret * 10 + c - '0';
			while ((c = read()) >= '0' && c <= '9');
			if (neg)
				return -ret;
			return ret;
		}
		public long[] readLongArray(int n) {
			long[] ar = new long[n];
			for(int i=0; i<n; ++i)
				ar[i]=nextLong();
			return ar;
		}
		public double nextDouble() {
			double ret = 0, div = 1;
			byte c = read();
			while (c <= ' ')
				c = read();
			boolean neg = (c == '-');
			if (neg)
				c = read();
			do
				ret = ret * 10 + c - '0';
			while ((c = read()) >= '0' && c <= '9');
			if (c == '.')
				while ((c = read()) >= '0' && c <= '9')
					ret += (c - '0') / (div *= 10);
			if (neg)
				return -ret;
			return ret;
		}
		private void fillBuffer() throws IOException {
			bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
			if (bytesRead == -1)
				buffer[0] = -1;
		}
		private byte read() {
			try{
				if (bufferPointer == bytesRead)
					fillBuffer();
				return buffer[bufferPointer++];
			} catch(IOException e) {
				throw new RuntimeException();
			}
		}
		public void close() throws IOException {
			if (din == null)
				return;
			din.close();
		}
	}
}

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

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

    int N = 200;
    int MOD = (int) 1e9 + 7;

    Map<Integer, Integer> map = new HashMap<>();

    int[] num = new int[N];
    List<Integer>[] G = new List[N];

    int tot = 0;
    boolean[] vis = new boolean[N];

    void solve() {
        int n = in.nextInt(), m = in.nextInt();
        int[] fr = new int[m], to = new int[m];
        for (int i = 0; i < m; i++) {
            fr[i] = in.nextInt();
            to[i] = in.nextInt();
        }

        int d = 0;
        while ((1 << d) <= n) d++;

        getId(1);
        for (int i = 0; i < m; i++) {
            int u = fr[i];
            while (u > 0) {
                getId(u);
                u >>= 1;
            }
            u = to[i];
            while (u > 0) {
                getId(u);
                u >>= 1;
            }
        }

        for (int i = 0; i < N; i++) G[i] = new ArrayList<>();
        for (int u : map.keySet()) {
            int id = map.get(u);
            if (u > 1) {
                addEdge(getId(u), getId(u >> 1));
            }
            num[id] = calcSize(u, n, d);
        }

        dfs(0, -1);

        for (int i = 0; i < m; i++) {
            addEdge(getId(fr[i]), getId(to[i]));
        }

        int res = 0;
        for (int i = 0; i < map.size(); i++) {
            tot = 0;
            dfs(i);
            res = (int) ((res + (long) tot * num[i] % MOD) % MOD);
        }
        out.println(res);
    }

    int getId(int x) {
        if (!map.containsKey(x)) map.put(x, map.size());
        return map.get(x);
    }

    void addEdge(int u, int v) {
        G[u].add(v);
        G[v].add(u);
    }

    int calcSize(int u, int n, int d) {
        int t = u, c = 0;
        while (t > 0) {
            c++;
            t >>= 1;
        }
        int sz = (1 << (d - c + 1)) - 1; // there are at most 2^(d-c+1)-1 nodes in subtree[u]
        t = c;
        while (t < d) {
            t++;
            u = u << 1 | 1;
        }
        return sz - Math.max(0, Math.min(u - n, 1 << (d - c))); // there are at most 2^(d-c) leaf nodes
    }

    void dfs(int u, int p) {
        for (int v : G[u]) {
            if (v != p) {
                num[u] -= num[v];
                dfs(v, u);
            }
        }
    }

    void dfs(int u) {
        tot += num[u];
        vis[u] = true;
        for (int v : G[u]) {
            if (!vis[v]) dfs(v);
        }
        vis[u] = false;
    }

    public static void main(String[] args) {
        in = new FastScanner(new BufferedReader(new InputStreamReader(System.in)));
        out = new PrintWriter(System.out);
        new TheOverdosingUbiquity().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.util.Iterator;
import java.io.BufferedWriter;
import java.util.Collection;
import java.util.Random;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

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

  static class TaskD {
    static final IntModular MOD = new IntModular();
    int n;
    int m;
    int[] end1;
    int[] end2;
    IntArrayList points;
    IntArrayList counts;
    IntArrayList covered;
    IntArrayList newCovered;

    public void solve(int testNumber, QuickScanner in, QuickWriter out) {
      n = in.nextInt();
      m = in.nextInt();
      end1 = new int[m];
      end2 = new int[m];
      in.nextInts(m, end1, end2);
      initKeyPoints();
//System.out.printf("points:%s\n", points.toDisplay());
//System.out.printf("points:%s\n", counts.toDisplay());
      int res = MOD.mul(n, n);
      IntArrayList edgeIdxs = new IntArrayList(m);
      for (int mask = (1 << m) - 1; mask > 0; --mask) {
        edgeIdxs.clear();
        for (int i = 0; i < m; ++i)
          if ((mask & (1 << i)) > 0) {
            edgeIdxs.add(i);
          }
        res = MOD.add(res, calcUnordered(edgeIdxs));
      }
      out.println(res);
    }

    void initKeyPoints() {
      points = new IntArrayList();
      for (int i = 0; i < m; ++i) {
        addKeyPoints(end1[i]);
        addKeyPoints(end2[i]);
      }
      points.sortAndUnique();
      counts = new IntArrayList(points.size);
      for (int point : points) {
        int cnt = 1;
        if (!points.binarySearch(point << 1)) {
          cnt += calcSubtree(point << 1);
        }
        if (!points.binarySearch((point << 1) | 1)) {
          cnt += calcSubtree((point << 1) | 1);
        }
        counts.add(cnt);
      }
    }

    int calcSubtree(int x) {
      int lower = x, upper = x;
      int res = 0;
      for (; lower <= n; lower <<= 1, upper = (upper << 1) | 1) {
        res += Math.min(n, upper) - lower + 1;
        if (n <= upper) break;
      }
      return res;
    }

    void addKeyPoints(int x) {
      for (; x > 0; x >>= 1) points.add(x);
    }

    int calcUnordered(IntArrayList edgeIdxs) {
      int res = 0;
      for (int mask = (1 << edgeIdxs.size) - 1; mask >= 0; --mask) {
        res = MOD.add(res, calcOrdered(edgeIdxs, mask));
      }
      return res;
    }

    int calcOrdered(IntArrayList edgeIdxs, int orderMask) {
      if (covered == null) {
        covered = new IntArrayList();
      }
      covered.clear();
      int source = -1, sink = -1;
      for (int i = 0; i < edgeIdxs.size; ++i) {
        int from, to;
        if ((orderMask & (1 << i)) > 0) {
          from = end1[edgeIdxs.get(i)];
          to = end2[edgeIdxs.get(i)];
        } else {
          from = end2[edgeIdxs.get(i)];
          to = end1[edgeIdxs.get(i)];
        }
//System.out.printf("(%d->%d) ", from, to);
        if (source < 0) {
          source = from;
          covered.add(source);
        }
        if (i > 0) addPath(sink, from);
        sink = to;
      }
//System.out.println();
      covered.add(sink);
      int coveredSize = covered.size;
//System.out.printf("\tcovered:%s\n", covered.toDisplay());
      covered.sortAndUnique();
//System.out.printf("\tcovered:%s\n", covered.toDisplay());
//if (coveredSize != covered.size) System.out.printf("\tno %d %d\n", coveredSize, covered.size);
      if (coveredSize != covered.size) return 0;
      int res = 0;
      for (int i = 0; i < points.size; ++i) {
        int u = points.get(i);
        for (int j = 0; j < points.size; ++j) {
          int v = points.get(j);
//if (u != v) System.out.printf("\t(%d,%d)->(%d,%d):%b\n", u, source, v, sink, isValid(u, source, v, sink));
          if (u == v || !isValid(u, source, v, sink)) continue;
          res = MOD.add(res, MOD.mul(counts.get(i), counts.get(j)));
        }
      }
      return res;
    }

    void addPath(int x, int y) {
      while (x != y) {
        if (x < y) {
          covered.add(y);
          y >>= 1;
        } else {
          covered.add(x);
          x >>= 1;
        }
      }
      covered.add(x);
    }

    boolean isValid(int source0, int sink0, int source1, int sink1) {
      if (newCovered == null) {
        newCovered = new IntArrayList();
      }
      newCovered.clear();
//System.out.printf("\t\t(%d,%d)->(%d,%d)\n", source0, sink0, source1, sink1);
//System.out.println("\t\tstep1");
      if (!addPathWithCheck(source0, sink0)) return false;
//System.out.println("\t\tstep2");
      if (!addPathWithCheck(source1, sink1)) return false;
//System.out.printf("\t\tstep3 %s\n", newCovered.toDisplay());
      int size = newCovered.size;
      newCovered.sortAndUnique();
      return size == newCovered.size;
    }

    boolean addPathWithCheck(int x, int y) {
      int sink = y;
      while (x != y) {
        if (x < y) {
          if (sink != y) {
            if (covered.binarySearch(y)) return false;
            newCovered.add(y);
          }
          y >>= 1;
        } else {
          if (covered.binarySearch(x)) return false;
          newCovered.add(x);
          x >>= 1;
        }
      }
      if (sink != x) {
        if (covered.binarySearch(x)) return false;
        newCovered.add(x);
      }
      return true;
    }

  }

  static class QuickWriter {
    private final PrintWriter writer;

    public QuickWriter(OutputStream outputStream) {
      this.writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
    }

    public QuickWriter(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();
    }

  }

  static class QuickScanner {
    private static final int BUFFER_SIZE = 1024;
    private InputStream stream;
    private byte[] buffer;
    private int currentPosition;
    private int numberOfChars;

    public QuickScanner(InputStream stream) {
      this.stream = stream;
      this.buffer = new byte[BUFFER_SIZE];
      this.currentPosition = 0;
      this.numberOfChars = 0;
    }

    public int nextInt() {
      int c = nextNonSpaceChar();
      boolean positive = true;
      if (c == '-') {
        positive = false;
        c = nextChar();
      }
      int res = 0;
      do {
        if (c < '0' || '9' < c) throw new RuntimeException();
        res = res * 10 + (c - '0');
        c = nextChar();
      } while (!isSpaceChar(c));
      return positive ? res : -res;
    }

    public void nextInts(int n, int[]... res) {
      int m = res.length;
      for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j) {
          res[j][i] = nextInt();
        }
    }

    public int nextNonSpaceChar() {
      int res = nextChar();
      for (; isSpaceChar(res) || res < 0; res = nextChar()) ;
      return res;
    }

    public int nextChar() {
      if (numberOfChars == -1) {
        throw new RuntimeException();
      }
      if (currentPosition >= numberOfChars) {
        currentPosition = 0;
        try {
          numberOfChars = stream.read(buffer);
        } catch (Exception e) {
          throw new RuntimeException(e);
        }
        if (numberOfChars <= 0) {
          return -1;
        }
      }
      return buffer[currentPosition++];
    }

    public boolean isSpaceChar(int c) {
      return c == ' ' || c == '\t' || isEndOfLineChar(c);
    }

    public boolean isEndOfLineChar(int c) {
      return c == '\n' || c == '\r' || c < 0;
    }

  }

  static interface IntCollection {
  }

  static class IntArrayList implements Displayable, IntCollection, Iterable<Integer> {
    private static final int[] EMPTY = {};
    public int[] values;
    public int size;

    public IntArrayList() {
      values = EMPTY;
      clear();
    }

    public IntArrayList(int capacity) {
      values = new int[IntUtils.nextPow2(capacity)];
      clear();
    }

    public IntArrayList(Collection<Integer> collection) {
      this(collection.size());
      addAll(collection);
    }

    public void clear() {
      size = 0;
    }

    public void add(int value) {
      ensureCapacity(size + 1);
      addInternal(value);
    }

    public void addAll(Collection<Integer> values) {
      ensureCapacity(size + values.size());
      for (int value : values) {
        addInternal(value);
      }
    }

    public int get(int idx) {
      if (idx >= size) throw new ArrayIndexOutOfBoundsException();
      return values[idx];
    }

    public void sort() {
      IntArrayUtils.sort(values, 0, size);
    }

    public void unique() {
      size = IntArrayUtils.unique(values, 0, size);
    }

    public void sortAndUnique() {
      sort();
      unique();
    }

    public int lowerBound(int value) {
      return IntArrayUtils.lowerBound(values, 0, size, value);
    }

    public boolean binarySearch(int value) {
      int idx = lowerBound(value);
      return idx < size && get(idx) == value;
    }

    public void ensureCapacity(int capacity) {
      if (capacity <= values.length) return;
      int[] newValues = new int[IntUtils.nextPow2(capacity)];
      for (int i = 0; i < size; ++i) {
        newValues[i] = values[i];
      }
      values = newValues;
    }

    public Iterator<Integer> iterator() {
      return new Iterator<Integer>() {
        private int i = 0;

        public boolean hasNext() {
          return i < size;
        }

        public Integer next() {
          return values[i++];
        }
      };
    }

    private void addInternal(int value) {
      values[size++] = value;
    }

  }

  static class IntArrayUtils {
    private static final Random RANDOM = new Random(1000000007);

    public static int unique(int[] values, int fromIdx, int toIdx) {
      if (fromIdx == toIdx) return 0;
      int res = 1;
      for (int i = fromIdx + 1; i < toIdx; ++i) {
        if (values[i - 1] != values[i]) {
          values[fromIdx + res++] = values[i];
        }
      }
      return res;
    }

    public static void sort(int[] values, int fromIdx, int toIdx) {
      shuffle(values, fromIdx, toIdx);
      Arrays.sort(values, fromIdx, toIdx);
    }

    public static int lowerBound(int[] values, int fromIdx, int toIdx, int value) {
      int res = toIdx;
      for (int lower = fromIdx, upper = toIdx - 1; lower <= upper; ) {
        int medium = (lower + upper) >> 1;
        if (value <= values[medium]) {
          res = medium;
          upper = medium - 1;
        } else {
          lower = medium + 1;
        }
      }
      return res;
    }

    public static void swap(int[] values, int uIdx, int vIdx) {
      if (uIdx == vIdx) return;
      values[uIdx] ^= values[vIdx];
      values[vIdx] ^= values[uIdx];
      values[uIdx] ^= values[vIdx];
    }

    public static void shuffle(int[] values, int fromIdx, int toIdx) {
      for (int i = toIdx - fromIdx - 1; i > 0; --i) {
        swap(values, i + fromIdx, RANDOM.nextInt(i + 1) + fromIdx);
      }
    }

  }

  static class IntUtils {
    public static boolean isPow2(int n) {
      return n > 0 && (n & (n - 1)) == 0;
    }

    public static int nextPow2(int n) {
      if (n < 1) return 1;
      return isPow2(n) ? n : Integer.highestOneBit(n) << 1;
    }

  }

  static interface Displayable {
  }

  static class IntModular {
    private static final int MOD = 1000000007;
    public final int mod;
    private final int[] x;

    public IntModular() {
      this(MOD);
    }

    public IntModular(int mod) {
      this.mod = mod;
      this.x = new int[2];
    }

    public int add(int a, int b) {
      return fix(a + b);
    }

    public int fix(int a) {
      a = slightFix(a);
      return 0 <= a && a < mod ? a : slightFix(a % mod);
    }

    public int mul(int a, int b) {
      return a > 0
          ? (b < mod / a ? a * b : (int) ((long) a * b % mod))
          : 0;
    }

    private int slightFix(int a) {
      return a >= mod
          ? a - mod
          : a < 0 ? a + mod : a;
    }

  }
}