#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

#define MOD 1000000007
LL powmod(LL a, LL n) {
  // if(a == 0) return 0;
  if (n == 0)
    return 1;
  if (n % 2)
    return (a * powmod(a, n - 1)) % MOD;
  LL c = powmod(a, n / 2);
  return (c * c) % MOD;
}
LL inv(LL a) { return powmod(a, MOD - 2); }
LL fact[110000];
LL invfact[110000];

LL choose[210][210];

LL ncr(LL n, LL r) { return choose[n][r]; }
void init() {
  fact[0] = 1;
  invfact[0] = 1;
  LL inv2 = inv(2);
  for (LL i = 1; i < 110000; i++) {
    fact[i] = (i * fact[i - 1]) % MOD;
    invfact[i] = inv(fact[i]);
  }
  for (LL n = 0; n < 200; n++) {
    for (LL k = 0; k < 200; k++) {
      if (k > n) {
        choose[n][k] = 0;
      } else if (k == 0 || k == n) {
        choose[n][k] = 1;
      } else {
        choose[n][k] = choose[n - 1][k - 1] + choose[n - 1][k];
        choose[n][k] %= MOD;
      }
    }
  }
}

int main() {
  init();

  LL a, b, c, A, B, C;
  cin >> a >> b >> c >> A >> B >> C;
  if (A % a != 0 || B % b != 0 || C % c != 0) {
    cout << 0 << endl;
    return 0;
  }
  A /= a;
  B /= b;
  C /= c;
  if (A == 1)
    a = 1;
  if (B == 1)
    b = 1;
  if (C == 1)
    c = 1;
  LL gridhv[110][110];

  LL vnum[110];

  LL hnum[110];

  for (LL v = B; v >= 0; v--) {
    for (LL w = C; w >= 0; w--) {
      LL n1 = B - v;
      LL n2 = C - w;
      LL mult = (ncr(B, v) * ncr(C, w)) % MOD;
      LL pie = 0;
      for (LL j1 = 0; j1 <= n1; j1++) {
        for (LL j2 = 0; j2 <= n2; j2++) {
          // restart
          LL cmult = (ncr(n1, j1) * ncr(n2, j2)) % MOD;
          LL add = 0;
          if (n1 - j1 == B && n2 - j2 == C) {
            add = powmod(a, B * C);
          } else if (n1 - j1 == B) {
            add = powmod(a, B * (n2 - j2) + C - (n2 - j2));
          } else if (n2 - j2 == C) {
            add = powmod(a, C * (n1 - j1) + B - (n1 - j1));
          } else {
            add = powmod(a, (n2 - j2) * (n1 - j1) + 1);
          }

          add = (add * cmult) % MOD;
          if ((j1 + j2) % 2)
            add *= -1;
          pie += add;
          pie %= MOD;
        }
      }
      pie = (pie * mult) % MOD;
      if (pie < 0)
        pie += MOD;

      // pick grid
      if (v != B) {
        pie = (pie * c) % MOD;
      }
      if (w != C) {
        pie = (pie * b) % MOD;
      }
      // cout << pie << " ";
      gridhv[v][w] = pie;
    }
    // cout << endl;
  }
  // cout << endl;

  for (int z = 0; z < 2; z++) {
    for (LL v = B; v >= 0; v--) {
      LL n = B - v;
      LL mult = ncr(B, v);
      LL pie =
          (powmod(a, v) * powmod(((powmod(a, C) - a) * c) % MOD, B - v)) % MOD;
      LL p2 = (powmod(a, v) * powmod((powmod(a, C) - a), B - v)) % MOD;
      if (v == B) {
        pie = (pie - p2) % MOD;
      } else {
        pie = (pie - p2 * c) % MOD;
      }
      pie = (pie * mult) % MOD;
      if (pie < 0)
        pie += MOD;
      pie = (pie * b) % MOD;
      // cout << v << " " << pie << endl;
      vnum[v] = pie;
    }
    swap(b, c);
    swap(B, C);
    for (int j = 0; j < 110; j++) {
      swap(vnum[j], hnum[j]);
    }
  }
  // final stage

  LL ans = 0;
  for (LL v = B; v >= 0; v--) {
    for (LL w = C; w >= 0; w--) {
      if (v == B && w == C) {
        LL num = (b * powmod(c, B) + c * powmod(b, C) - b * c) % MOD;
        // cout << "NUM " << num << endl;
        num %= MOD;
        ans += gridhv[v][w] * powmod(num, A);
        ans %= MOD;
      } else {
        LL num = (powmod(c, v) + powmod(b, w) - 1) % MOD;
        ans += gridhv[v][w] * powmod(num, A);
        ans %= MOD;
      }
    }
  }
  for (LL v = B; v >= 0; v--) {
    LL num = powmod(c, v);
    ans += vnum[v] * powmod(num, A);
    ans %= MOD;
  }
  for (LL w = C; w >= 0; w--) {
    LL num = powmod(b, w);
    ans += hnum[w] * powmod(num, A);
    ans %= MOD;
  }
  ans %= MOD;
  if (ans < 0)
    ans += MOD;
  cout << ans << endl;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

#define MOD 1000000007
LL powmod(LL a, LL n) {
  // if(a == 0) return 0;
  if (n == 0)
    return 1;
  if (n % 2)
    return (a * powmod(a, n - 1)) % MOD;
  LL c = powmod(a, n / 2);
  return (c * c) % MOD;
}
LL inv(LL a) { return powmod(a, MOD - 2); }
LL fact[110000];
LL invfact[110000];

LL choose[210][210];

LL ncr(LL n, LL r) { return choose[n][r]; }

LL a, b, c, A, B, C;

LL powa[110000];

void init() {
  fact[0] = 1;
  invfact[0] = 1;
  powa[0] = 1;
  LL inv2 = inv(2);
  for (LL i = 1; i < 110000; i++) {
    fact[i] = (i * fact[i - 1]) % MOD;
    invfact[i] = inv(fact[i]);
    powa[i] = (a * powa[i - 1]) % MOD;
  }
  for (LL n = 0; n < 200; n++) {
    for (LL k = 0; k < 200; k++) {
      if (k > n) {
        choose[n][k] = 0;
      } else if (k == 0 || k == n) {
        choose[n][k] = 1;
      } else {
        choose[n][k] = choose[n - 1][k - 1] + choose[n - 1][k];
        choose[n][k] %= MOD;
      }
    }
  }
}

int main() {

  cin >> a >> b >> c >> A >> B >> C;
  if (A % a != 0 || B % b != 0 || C % c != 0) {
    cout << 0 << endl;
    return 0;
  }
  A /= a;
  B /= b;
  C /= c;
  if (A == 1)
    a = 1;
  if (B == 1)
    b = 1;
  if (C == 1)
    c = 1;

  init();

  LL gridhv[110][110];

  LL vnum[110];

  LL hnum[110];

  for (LL v = B; v >= 0; v--) {
    for (LL w = C; w >= 0; w--) {
      LL n1 = B - v;
      LL n2 = C - w;
      LL mult = (ncr(B, v) * ncr(C, w)) % MOD;
      LL pie = 0;
      for (LL j1 = 0; j1 <= n1; j1++) {
        for (LL j2 = 0; j2 <= n2; j2++) {
          // restart
          LL cmult = (ncr(n1, j1) * ncr(n2, j2)) % MOD;
          LL add = 0;
          if (n1 - j1 == B && n2 - j2 == C) {
            add = powa[B * C];
          } else if (n1 - j1 == B) {
            add = powa[B * (n2 - j2) + C - (n2 - j2)];
          } else if (n2 - j2 == C) {
            add = powa[C * (n1 - j1) + B - (n1 - j1)];
          } else {
            add = powa[(n2 - j2) * (n1 - j1) + 1];
          }

          add = (add * cmult) % MOD;
          if ((j1 + j2) % 2)
            add *= -1;
          pie += add;
          pie %= MOD;
        }
      }
      pie = (pie * mult) % MOD;
      if (pie < 0)
        pie += MOD;

      // pick grid
      if (v != B) {
        pie = (pie * c) % MOD;
      }
      if (w != C) {
        pie = (pie * b) % MOD;
      }
      // cout << pie << " ";
      gridhv[v][w] = pie;
    }
    // cout << endl;
  }
  // cout << endl;

  for (int z = 0; z < 2; z++) {
    for (LL v = B; v >= 0; v--) {
      LL n = B - v;
      LL mult = ncr(B, v);
      LL pie =
          (powmod(a, v) * powmod(((powmod(a, C) - a) * c) % MOD, B - v)) % MOD;
      LL p2 = (powmod(a, v) * powmod((powmod(a, C) - a), B - v)) % MOD;
      if (v == B) {
        pie = (pie - p2) % MOD;
      } else {
        pie = (pie - p2 * c) % MOD;
      }
      pie = (pie * mult) % MOD;
      if (pie < 0)
        pie += MOD;
      pie = (pie * b) % MOD;
      // cout << v << " " << pie << endl;
      vnum[v] = pie;
    }
    swap(b, c);
    swap(B, C);
    for (int j = 0; j < 110; j++) {
      swap(vnum[j], hnum[j]);
    }
  }
  // final stage

  LL ans = 0;
  for (LL v = B; v >= 0; v--) {
    for (LL w = C; w >= 0; w--) {
      if (v == B && w == C) {
        LL num = (b * powmod(c, B) + c * powmod(b, C) - b * c) % MOD;
        // cout << "NUM " << num << endl;
        num %= MOD;
        ans += gridhv[v][w] * powmod(num, A);
        ans %= MOD;
      } else {
        LL num = (powmod(c, v) + powmod(b, w) - 1) % MOD;
        ans += gridhv[v][w] * powmod(num, A);
        ans %= MOD;
      }
    }
  }
  for (LL v = B; v >= 0; v--) {
    LL num = powmod(c, v);
    ans += vnum[v] * powmod(num, A);
    ans %= MOD;
  }
  for (LL w = C; w >= 0; w--) {
    LL num = powmod(b, w);
    ans += hnum[w] * powmod(num, A);
    ans %= MOD;
  }
  ans %= MOD;
  if (ans < 0)
    ans += MOD;
  cout << ans << endl;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <string>
#include <vector>
//    #include <boost/multiprecision/cpp_int.hpp>
#include <functional>
#define int long long
#define inf 1000000007
#define pa pair<int, int>
#define ll long long
#define pal pair<double, double>
#define ppap pair<pa, int>
#define PI 3.14159265358979323846
#define paa pair<int, char>
#define mp make_pair
#define pb push_back
#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)
int dx[4] = {0, -1, 0, 1};
int dy[4] = {1, 0, -1, 0};
using namespace std;
class pa3 {
public:
  int x, y, z;
  pa3(int x = 0, int y = 0, int z = 0) : x(x), y(y), z(z) {}
  bool operator<(const pa3 &p) const {
    if (x != p.x)
      return x < p.x;
    if (y != p.y)
      return y < p.y;
    return z < p.z;
    // return x != p.x ? x<p.x: y<p.y;
  }
  bool operator>(const pa3 &p) const {
    if (x != p.x)
      return x > p.x;
    if (y != p.y)
      return y > p.y;
    return z > p.z;
    // return x != p.x ? x<p.x: y<p.y;
  }
  bool operator==(const pa3 &p) const {
    return x == p.x && y == p.y && z == p.z;
  }
  bool operator!=(const pa3 &p) const {
    return !(x == p.x && y == p.y && z == p.z);
  }
};

class pa4 {
public:
  int x;
  int y, z, w;
  pa4(int x = 0, int y = 0, int z = 0, int w = 0) : x(x), y(y), z(z), w(w) {}
  bool operator<(const pa4 &p) const {
    if (x != p.x)
      return x < p.x;
    if (y != p.y)
      return y < p.y;
    if (z != p.z)
      return z < p.z;
    return w < p.w;
    // return x != p.x ? x<p.x: y<p.y;
  }
  bool operator>(const pa4 &p) const {
    if (x != p.x)
      return x > p.x;
    if (y != p.y)
      return y > p.y;
    if (z != p.z)
      return z > p.z;
    return w > p.w;
    // return x != p.x ? x<p.x: y<p.y;
  }
  bool operator==(const pa4 &p) const {
    return x == p.x && y == p.y && z == p.z && w == p.w;
  }

  bool operator!=(const pa4 &p) const {
    return !(x == p.x && y == p.y && z == p.z && w == p.w);
  }
};
class pa2 {
public:
  int x, y;
  pa2(int x = 0, int y = 0) : x(x), y(y) {}
  pa2 operator+(pa2 p) { return pa2(x + p.x, y + p.y); }
  pa2 operator-(pa2 p) { return pa2(x - p.x, y - p.y); }
  bool operator<(const pa2 &p) const { return x != p.x ? x < p.x : y < p.y; }
  bool operator>(const pa2 &p) const { return x != p.x ? x > p.x : y > p.y; }
  bool operator==(const pa2 &p) const {
    return abs(x - p.x) == 0 && abs(y - p.y) == 0;
  }
  bool operator!=(const pa2 &p) const {
    return !(abs(x - p.x) == 0 && abs(y - p.y) == 0);
  }
};

#define ppa pair<int, pas>
class Point {
public:
  double x, y;
  Point(double x = 0, double y = 0) : x(x), y(y) {}
  Point operator+(Point p) { return Point(x + p.x, y + p.y); }
  Point operator-(Point p) { return Point(x - p.x, y - p.y); }
  Point operator*(double a) { return Point(x * a, y * a); }
  Point operator/(double a) { return Point(x / a, y / a); }
  double absv() { return sqrt(norm()); }
  double norm() { return x * x + y * y; }
  bool operator<(const Point &p) const { return x != p.x ? x < p.x : y < p.y; }
  bool operator==(const Point &p) const {
    return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
  }
};
typedef Point Vector;
#define pl pair<int, pas>
struct Segment {
  Point p1, p2;
};
double dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y; }
double cross(Vector a, Vector b) { return a.x * b.y - a.y * b.x; }

bool parareru(Point a, Point b, Point c, Point d) {
  //	if(abs(cross(a-b,d-c))<EPS)cout<<"dd "<<cross(a-b,d-c)<<endl;
  return abs(cross(a - b, d - c)) < EPS;
}
double distance_ls_p(Point a, Point b, Point c) {
  if (dot(b - a, c - a) < EPS)
    return (c - a).absv();
  if (dot(a - b, c - b) < EPS)
    return (c - b).absv();
  return abs(cross(b - a, c - a)) / (b - a).absv();
}
bool is_intersected_ls(Segment a, Segment b) {
  if (a.p1 == b.p1 || a.p2 == b.p1 || a.p1 == b.p2 || a.p2 == b.p2)
    return false;
  if (parareru((a.p2), (a.p1), (a.p1), (b.p2)) &&
      parareru((a.p2), (a.p1), (a.p1), (b.p1))) {
    //		cout<<"sss"<<endl;
    if (dot(a.p1 - b.p1, a.p1 - b.p2) < EPS)
      return true;
    if (dot(a.p2 - b.p1, a.p2 - b.p2) < EPS)
      return true;
    if (dot(a.p1 - b.p1, a.p2 - b.p1) < EPS)
      return true;
    if (dot(a.p1 - b.p2, a.p2 - b.p2) < EPS)
      return true;
    return false;
  } else
    return (cross(a.p2 - a.p1, b.p1 - a.p1) * cross(a.p2 - a.p1, b.p2 - a.p1) <
            EPS) &&
           (cross(b.p2 - b.p1, a.p1 - b.p1) * cross(b.p2 - b.p1, a.p2 - b.p1) <
            EPS);
}

double segment_dis(Segment a, Segment b) {
  if (is_intersected_ls(a, b))
    return 0;
  double r = distance_ls_p(a.p1, a.p2, b.p1);
  r = min(r, distance_ls_p(a.p1, a.p2, b.p2));
  r = min(r, distance_ls_p(b.p1, b.p2, a.p2));
  r = min(r, distance_ls_p(b.p1, b.p2, a.p1));
  return r;
}
Point intersection_ls(Segment a, Segment b) {
  Point ba = b.p2 - b.p1;
  double d1 = abs(cross(ba, a.p1 - b.p1));
  double d2 = abs(cross(ba, a.p2 - b.p1));
  double t = d1 / (d1 + d2);

  return a.p1 + (a.p2 - a.p1) * t;
}

string itos(int i) {
  ostringstream s;
  s << i;
  return s.str();
}

int gcd(int v, int b) {
  if (v > b)
    return gcd(b, v);
  if (v == b)
    return b;
  if (b % v == 0)
    return v;
  return gcd(v, b % v);
}

double distans(double x1, double y1, double x2, double y2) {
  double rr = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
  return sqrt(rr);
}
int mod;
int pr[2010];
int inv[2010];

int beki(int wa, int rr, int warukazu) {
  if (rr == 0)
    return 1 % warukazu;
  if (rr == 1)
    return wa % warukazu;
  if (rr % 2 == 1)
    return (beki(wa, rr - 1, warukazu) * wa) % warukazu;
  int zx = beki(wa, rr / 2, warukazu);
  return (zx * zx) % warukazu;
}
/*
double bekid(double w,int r){
if(r==0) return 1.0;
if(r==1) return w;
if(r%2) return bekid(w,r-1)*w;
double f=bekid(w,r/2);
return f*f;
}*/
/*
                    int comb(int nn,int rr){
                            int r=pr[nn]*inv[rr];
                            r%=mod;
                            r*=inv[nn-rr];
                            r%=mod;
                            return r;
                    }
  */
void gya(int ert) {
  pr[0] = 1;
  for (int i = 1; i < ert; i++) {
    pr[i] = (pr[i - 1] * i) % mod;
  }
  for (int i = 0; i < ert; i++)
    inv[i] = beki(pr[i], mod - 2, mod);
}

//   cin.tie(0);
//	ios::sync_with_stdio(false);
// priority_queue<pa3,vector<pa3>,greater<pa3>> pq;
// sort(ve.begin(),ve.end(),greater<int>());
//----------------kokomade tenpure------------
int m[300], x[300];
int n, ko, ans;
vector<int> ve;
void dfs(int r, int val) {

  if (r == ko) {

    int an = 0;
    for (int i = 0; i < n; i++)
      if (val % m[i] == 0)
        an += x[i];
    ans = max(an, ans);
    return;
  }

  if (ve[r] <= 17) {

    int g = 1;
    while (1) {
      dfs(r + 1, val * g);
      g *= ve[r];
      if (g > 300)
        break;
    }
    return;
  }

  int a1 = 0, a2 = 0;
  for (int i = 0; i < n; i++)
    if ((val * ve[r]) % m[i] == 0)
      a1 += x[i];
  for (int i = 0; i < n; i++)
    if ((val) % m[i] == 0)
      a2 += x[i];
  if (a1 > a2)
    dfs(r + 1, val * ve[r]);
  else
    dfs(r + 1, val);
}

signed main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cin >> n;
  for (int i = 0; i < n; i++)
    cin >> m[i] >> x[i];
  for (int i = 2; i <= 300; i++) {
    for (int j = 2; j < i; j++)
      if (i % j == 0) {
        goto lll;
      }
    ve.pb(i);
  lll:;
  }
  ko = ve.size();
  ans = 0;
  dfs(0, 1);

  cout << ans << endl;
  return 0;
}

#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <string>
#include <vector>
//    #include <boost/multiprecision/cpp_int.hpp>
#include <functional>
#define int long long
#define inf 1000000007
#define pa pair<int, int>
#define ll long long
#define pal pair<double, double>
#define ppap pair<pa, int>
#define PI 3.14159265358979323846
#define paa pair<int, char>
#define mp make_pair
#define pb push_back
#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)
int dx[4] = {0, -1, 0, 1};
int dy[4] = {1, 0, -1, 0};
using namespace std;
class pa3 {
public:
  int x, y, z;
  pa3(int x = 0, int y = 0, int z = 0) : x(x), y(y), z(z) {}
  bool operator<(const pa3 &p) const {
    if (x != p.x)
      return x < p.x;
    if (y != p.y)
      return y < p.y;
    return z < p.z;
    // return x != p.x ? x<p.x: y<p.y;
  }
  bool operator>(const pa3 &p) const {
    if (x != p.x)
      return x > p.x;
    if (y != p.y)
      return y > p.y;
    return z > p.z;
    // return x != p.x ? x<p.x: y<p.y;
  }
  bool operator==(const pa3 &p) const {
    return x == p.x && y == p.y && z == p.z;
  }
  bool operator!=(const pa3 &p) const {
    return !(x == p.x && y == p.y && z == p.z);
  }
};

class pa4 {
public:
  int x;
  int y, z, w;
  pa4(int x = 0, int y = 0, int z = 0, int w = 0) : x(x), y(y), z(z), w(w) {}
  bool operator<(const pa4 &p) const {
    if (x != p.x)
      return x < p.x;
    if (y != p.y)
      return y < p.y;
    if (z != p.z)
      return z < p.z;
    return w < p.w;
    // return x != p.x ? x<p.x: y<p.y;
  }
  bool operator>(const pa4 &p) const {
    if (x != p.x)
      return x > p.x;
    if (y != p.y)
      return y > p.y;
    if (z != p.z)
      return z > p.z;
    return w > p.w;
    // return x != p.x ? x<p.x: y<p.y;
  }
  bool operator==(const pa4 &p) const {
    return x == p.x && y == p.y && z == p.z && w == p.w;
  }

  bool operator!=(const pa4 &p) const {
    return !(x == p.x && y == p.y && z == p.z && w == p.w);
  }
};
class pa2 {
public:
  int x, y;
  pa2(int x = 0, int y = 0) : x(x), y(y) {}
  pa2 operator+(pa2 p) { return pa2(x + p.x, y + p.y); }
  pa2 operator-(pa2 p) { return pa2(x - p.x, y - p.y); }
  bool operator<(const pa2 &p) const { return x != p.x ? x < p.x : y < p.y; }
  bool operator>(const pa2 &p) const { return x != p.x ? x > p.x : y > p.y; }
  bool operator==(const pa2 &p) const {
    return abs(x - p.x) == 0 && abs(y - p.y) == 0;
  }
  bool operator!=(const pa2 &p) const {
    return !(abs(x - p.x) == 0 && abs(y - p.y) == 0);
  }
};

#define ppa pair<int, pas>
class Point {
public:
  double x, y;
  Point(double x = 0, double y = 0) : x(x), y(y) {}
  Point operator+(Point p) { return Point(x + p.x, y + p.y); }
  Point operator-(Point p) { return Point(x - p.x, y - p.y); }
  Point operator*(double a) { return Point(x * a, y * a); }
  Point operator/(double a) { return Point(x / a, y / a); }
  double absv() { return sqrt(norm()); }
  double norm() { return x * x + y * y; }
  bool operator<(const Point &p) const { return x != p.x ? x < p.x : y < p.y; }
  bool operator==(const Point &p) const {
    return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
  }
};
typedef Point Vector;
#define pl pair<int, pas>
struct Segment {
  Point p1, p2;
};
double dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y; }
double cross(Vector a, Vector b) { return a.x * b.y - a.y * b.x; }

bool parareru(Point a, Point b, Point c, Point d) {
  //	if(abs(cross(a-b,d-c))<EPS)cout<<"dd "<<cross(a-b,d-c)<<endl;
  return abs(cross(a - b, d - c)) < EPS;
}
double distance_ls_p(Point a, Point b, Point c) {
  if (dot(b - a, c - a) < EPS)
    return (c - a).absv();
  if (dot(a - b, c - b) < EPS)
    return (c - b).absv();
  return abs(cross(b - a, c - a)) / (b - a).absv();
}
bool is_intersected_ls(Segment a, Segment b) {
  if (a.p1 == b.p1 || a.p2 == b.p1 || a.p1 == b.p2 || a.p2 == b.p2)
    return false;
  if (parareru((a.p2), (a.p1), (a.p1), (b.p2)) &&
      parareru((a.p2), (a.p1), (a.p1), (b.p1))) {
    //		cout<<"sss"<<endl;
    if (dot(a.p1 - b.p1, a.p1 - b.p2) < EPS)
      return true;
    if (dot(a.p2 - b.p1, a.p2 - b.p2) < EPS)
      return true;
    if (dot(a.p1 - b.p1, a.p2 - b.p1) < EPS)
      return true;
    if (dot(a.p1 - b.p2, a.p2 - b.p2) < EPS)
      return true;
    return false;
  } else
    return (cross(a.p2 - a.p1, b.p1 - a.p1) * cross(a.p2 - a.p1, b.p2 - a.p1) <
            EPS) &&
           (cross(b.p2 - b.p1, a.p1 - b.p1) * cross(b.p2 - b.p1, a.p2 - b.p1) <
            EPS);
}

double segment_dis(Segment a, Segment b) {
  if (is_intersected_ls(a, b))
    return 0;
  double r = distance_ls_p(a.p1, a.p2, b.p1);
  r = min(r, distance_ls_p(a.p1, a.p2, b.p2));
  r = min(r, distance_ls_p(b.p1, b.p2, a.p2));
  r = min(r, distance_ls_p(b.p1, b.p2, a.p1));
  return r;
}
Point intersection_ls(Segment a, Segment b) {
  Point ba = b.p2 - b.p1;
  double d1 = abs(cross(ba, a.p1 - b.p1));
  double d2 = abs(cross(ba, a.p2 - b.p1));
  double t = d1 / (d1 + d2);

  return a.p1 + (a.p2 - a.p1) * t;
}

string itos(int i) {
  ostringstream s;
  s << i;
  return s.str();
}

int gcd(int v, int b) {
  if (v > b)
    return gcd(b, v);
  if (v == b)
    return b;
  if (b % v == 0)
    return v;
  return gcd(v, b % v);
}

double distans(double x1, double y1, double x2, double y2) {
  double rr = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
  return sqrt(rr);
}
int mod;
int pr[2010];
int inv[2010];

int beki(int wa, int rr, int warukazu) {
  if (rr == 0)
    return 1 % warukazu;
  if (rr == 1)
    return wa % warukazu;
  if (rr % 2 == 1)
    return (beki(wa, rr - 1, warukazu) * wa) % warukazu;
  int zx = beki(wa, rr / 2, warukazu);
  return (zx * zx) % warukazu;
}
/*
double bekid(double w,int r){
if(r==0) return 1.0;
if(r==1) return w;
if(r%2) return bekid(w,r-1)*w;
double f=bekid(w,r/2);
return f*f;
}*/
/*
                    int comb(int nn,int rr){
                            int r=pr[nn]*inv[rr];
                            r%=mod;
                            r*=inv[nn-rr];
                            r%=mod;
                            return r;
                    }
  */
void gya(int ert) {
  pr[0] = 1;
  for (int i = 1; i < ert; i++) {
    pr[i] = (pr[i - 1] * i) % mod;
  }
  for (int i = 0; i < ert; i++)
    inv[i] = beki(pr[i], mod - 2, mod);
}

//   cin.tie(0);
//	ios::sync_with_stdio(false);
// priority_queue<pa3,vector<pa3>,greater<pa3>> pq;
// sort(ve.begin(),ve.end(),greater<int>());
//----------------kokomade tenpure------------
int m[300], x[301];
int n, ko, ans;
vector<int> ve;
void dfs(int r, int val, int a = 0) {

  if (r == ko) {

    int an = a;
    for (int i = 1; i < 301; i++)
      if (val % i == 0)
        an += x[i];
    ans = max(an, ans);
    //	cout<<val<<endl;
    return;
  }

  if (ve[r] <= 17) {
    //	if(ve[r]==17) cout<<val<<endl;
    int g = 1;
    while (1) {
      dfs(r + 1, val * g);
      g *= ve[r];
      if (g > 300)
        break;
    }
    return;
  }

  int a1 = 0, a2 = 0;
  for (int i = ve[r]; i <= 300; i += ve[r])
    if ((val * ve[r]) % i == 0)
      a1 += x[i];
  //	for(int i=0;i<n;i++)if((val)%m[i]==0)a2+=x[i];
  if (a1 > a2)
    dfs(r + 1, val, a + a1);
  else
    dfs(r + 1, val, a);
}

signed main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cin >> n;
  for (int i = 0; i < n; i++) {
    int mm, xx;
    cin >> mm >> xx;
    x[mm] = xx;
  }
  //	for(int i=2;i<=300;i++)x[i]=100;
  for (int i = 2; i <= 300; i++) {
    for (int j = 2; j < i; j++)
      if (i % j == 0) {
        goto lll;
      }
    ve.pb(i);
  lll:;
  }
  ko = ve.size();
  ans = 0;
  dfs(0, 1);

  cout << ans << endl;
  return 0;
}


#include <bits/stdc++.h>

#define VARNAME(x) #x
#define show(x) cerr << #x << " = " << x << endl

using namespace std;
using ll = long long;

template <typename T> ostream &operator<<(ostream &os, const vector<T> &v) {
  os << "sz:" << v.size() << "\\n[";
  for (const auto &p : v) {
    os << p << ",";
  }
  os << "]\\n";
  return os;
}

template <typename T> istream &operator>>(istream &is, vector<T> &v) {
  for (auto &e : v) {
    is >> e;
  }
  return is;
}

template <typename S, typename T>
ostream &operator<<(ostream &os, const pair<S, T> &p) {
  os << "(" << p.first << "," << p.second << ")";
  return os;
}

constexpr ll MOD = (ll)1e9 + 7LL;

template <typename T> constexpr T INF = numeric_limits<T>::max() / 10;

using V7 = vector<vector<vector<vector<vector<vector<vector<ll>>>>>>>;
using V6 = vector<vector<vector<vector<vector<vector<ll>>>>>>;
using V5 = vector<vector<vector<vector<vector<ll>>>>>;
using V4 = vector<vector<vector<vector<ll>>>>;
using V3 = vector<vector<vector<ll>>>;
using V2 = vector<vector<ll>>;
using V1 = vector<ll>;

struct Data {
  vector<int> ind;
  ll x;
};

constexpr int MAX = 300;
constexpr int SQRT = 18;
constexpr int LP = 7;
constexpr int prime[LP] = {2, 3, 5, 7, 11, 13, 17};
constexpr int maxind[LP] = {9, 6, 4, 3, 3, 3, 3};

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  int pnum = 0;
  auto isprime = [](const int n) {
    for (int i = 2; i * i <= n; i++) {
      if (n % i == 0) {
        return false;
      }
    }
    return true;
  };
  map<int, int> mp;
  mp[1] = 0;
  for (int i = SQRT; i <= MAX; i++) {
    if (isprime(i)) {
      pnum++;
      mp[i] = pnum;
    }
  }

  vector<V7> value(
      pnum + 1, V7(maxind[0],
                   V6(maxind[1],
                      V5(maxind[2],
                         V4(maxind[3],
                            V3(maxind[4], V2(maxind[5], V1(maxind[6], 0))))))));
  for (int i = 0; i <= pnum; i++) {
    value[i][0][0][0][0][0][0][0] = 0;
  }

  int Q;
  cin >> Q;
  vector<vector<Data>> data(pnum + 1);
  for (int i = 0; i < Q; i++) {
    int m, x;
    cin >> m >> x;
    vector<int> num(LP, 0);
    for (int j = 0; j < LP; j++) {
      while (m % prime[j] == 0) {
        num[j]++;
        m /= prime[j];
      }
    }
    data[m].push_back(Data{num, x});
  }

  auto div = [](const int n0, const int n1, const int n2, const int n3,
                const int n4, const int n5, const int n6,
                const vector<int> &ind) {
    return n0 >= ind[0] and n1 >= ind[1] and n2 >= ind[2] and n3 >= ind[3] and
           n4 >= ind[4] and n5 >= ind[5] and n6 >= ind[6];
  };
  ll maximum = 0;
  for (int i = 0; i <= pnum; i++) {
    for (int n0 = 0; n0 < maxind[0]; n0++) {
      for (int n1 = 0; n1 < maxind[1]; n1++) {
        for (int n2 = 0; n2 < maxind[2]; n2++) {
          for (int n3 = 0; n3 < maxind[3]; n3++) {
            for (int n4 = 0; n4 < maxind[4]; n4++) {
              for (int n5 = 0; n5 < maxind[5]; n5++) {
                for (int n6 = 0; n6 < maxind[6]; n6++) {
                  for (const auto &d : data[i]) {
                    const auto &ind = d.ind;
                    if (div(n0, n1, n2, n3, n4, n5, n6, ind)) {
                      value[i][n0][n1][n2][n3][n4][n5][n6] += d.x;
                    }
                  }
                  if (i == 0) {
                    maximum =
                        max(maximum, value[0][n0][n1][n2][n3][n4][n5][n6]);
                  } else {
                    maximum =
                        max(maximum, value[i][n0][n1][n2][n3][n4][n5][n6] +
                                         value[0][n0][n1][n2][n3][n4][n5][n6]);
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  cout << maximum << endl;

  return 0;
}

#include <bits/stdc++.h>

#define VARNAME(x) #x
#define show(x) cerr << #x << " = " << x << endl

using namespace std;
using ll = long long;

template <typename T> ostream &operator<<(ostream &os, const vector<T> &v) {
  os << "sz:" << v.size() << "\\n[";
  for (const auto &p : v) {
    os << p << ",";
  }
  os << "]\\n";
  return os;
}

template <typename T> istream &operator>>(istream &is, vector<T> &v) {
  for (auto &e : v) {
    is >> e;
  }
  return is;
}

template <typename S, typename T>
ostream &operator<<(ostream &os, const pair<S, T> &p) {
  os << "(" << p.first << "," << p.second << ")";
  return os;
}

constexpr ll MOD = (ll)1e9 + 7LL;

template <typename T> constexpr T INF = numeric_limits<T>::max() / 10;

using V7 = vector<vector<vector<vector<vector<vector<vector<ll>>>>>>>;
using V6 = vector<vector<vector<vector<vector<vector<ll>>>>>>;
using V5 = vector<vector<vector<vector<vector<ll>>>>>;
using V4 = vector<vector<vector<vector<ll>>>>;
using V3 = vector<vector<vector<ll>>>;
using V2 = vector<vector<ll>>;
using V1 = vector<ll>;

struct Data {
  vector<int> ind;
  ll x;
};

constexpr int MAX = 300;
constexpr int SQRT = 18;
constexpr int LP = 7;
constexpr int prime[LP] = {2, 3, 5, 7, 11, 13, 17};
constexpr int maxind[LP] = {9, 6, 4, 3, 3, 3, 3};

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  int pnum = 0;
  auto isprime = [](const int n) {
    for (int i = 2; i * i <= n; i++) {
      if (n % i == 0) {
        return false;
      }
    }
    return true;
  };
  map<int, int> mp;
  mp[1] = 0;
  for (int i = SQRT; i <= MAX; i++) {
    if (isprime(i)) {
      pnum++;
      mp[i] = pnum;
    }
  }

  vector<V7> value(
      pnum + 1, V7(maxind[0],
                   V6(maxind[1],
                      V5(maxind[2],
                         V4(maxind[3],
                            V3(maxind[4], V2(maxind[5], V1(maxind[6], 0))))))));

  int Q;
  cin >> Q;
  vector<vector<Data>> data(pnum + 1);
  for (int i = 0; i < Q; i++) {
    ll m, x;
    cin >> m >> x;
    vector<int> num(LP, 0);
    for (int j = 0; j < LP; j++) {
      while (m % prime[j] == 0) {
        num[j]++;
        m /= prime[j];
      }
    }
    data[mp[m]].push_back(Data{num, x});
  }

  auto div = [](const int n0, const int n1, const int n2, const int n3,
                const int n4, const int n5, const int n6,
                const vector<int> &ind) {
    return n0 >= ind[0] and n1 >= ind[1] and n2 >= ind[2] and n3 >= ind[3] and
           n4 >= ind[4] and n5 >= ind[5] and n6 >= ind[6];
  };
  for (int i = 0; i <= pnum; i++) {
    for (int n0 = 0; n0 < maxind[0]; n0++) {
      for (int n1 = 0; n1 < maxind[1]; n1++) {
        for (int n2 = 0; n2 < maxind[2]; n2++) {
          for (int n3 = 0; n3 < maxind[3]; n3++) {
            for (int n4 = 0; n4 < maxind[4]; n4++) {
              for (int n5 = 0; n5 < maxind[5]; n5++) {
                for (int n6 = 0; n6 < maxind[6]; n6++) {
                  for (const auto &d : data[i]) {
                    const auto &ind = d.ind;
                    if (div(n0, n1, n2, n3, n4, n5, n6, ind)) {
                      value[i][n0][n1][n2][n3][n4][n5][n6] += d.x;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  ll maximum = 0;
  for (int n0 = 0; n0 < maxind[0]; n0++) {
    for (int n1 = 0; n1 < maxind[1]; n1++) {
      for (int n2 = 0; n2 < maxind[2]; n2++) {
        for (int n3 = 0; n3 < maxind[3]; n3++) {
          for (int n4 = 0; n4 < maxind[4]; n4++) {
            for (int n5 = 0; n5 < maxind[5]; n5++) {
              for (int n6 = 0; n6 < maxind[6]; n6++) {
                ll sum = value[0][n0][n1][n2][n3][n4][n5][n6];
                for (int i = 1; i <= pnum; i++) {
                  sum += max(0LL, value[i][n0][n1][n2][n3][n4][n5][n6]);
                }
                maximum = max(maximum, sum);
              }
            }
          }
        }
      }
    }
  }
  cout << maximum << endl;

  return 0;
}


#include <bits/stdc++.h>

using namespace std;

using int64 = long long;
const int64 INF = 1LL << 59;

unordered_map<int64, int> prime_factor(int64 n) {
  unordered_map<int64, int> ret;
  for (int64 i = 2; i * i <= n; i++) {
    while (n % i == 0) {
      ret[i]++;
      n /= i;
    }
  }
  if (n != 1)
    ret[n] = 1;
  return (ret);
}

int Q;
pair<unordered_map<int64, int>, int> vv[300];

int64 rec(vector<pair<int, int>> &conv, vector<int> &candidate, int idx,
          bool flag) {
  int64 ret = 0;

  if (candidate.empty()) {
    return (ret);
  }

  if (flag) {
    for (auto &j : candidate)
      ret += vv[j].second;
  }

  if (idx < conv.size()) {

    if (conv[idx].first >= 19 && flag) {

      vector<int> used(Q, 0);
      int64 calc = 0;
      for (int i = idx; i < conv.size(); i++) {
        int64 beet = 0;
        for (auto &j : candidate) {
          if (vv[j].first.count(conv[i].first)) {
            beet += vv[j].second;
            used[j] = true;
          }
        }
        calc += max(0LL, beet);
      }
      for (auto &j : candidate) {
        if (!used[j])
          calc += vv[j].second;
      }
      ret = max(ret, calc);

    } else {
      set<vector<int>> used;
      for (int i = 0; i <= conv[idx].second + 1; i++) {
        vector<int> nt;
        for (int j : candidate) {
          if (vv[j].first.count(conv[idx].first)) {
            if (vv[j].first[conv[idx].first] > i)
              continue;
          }
          nt.emplace_back(j);
        }
        if (used.count(nt))
          continue;
        used.emplace(nt);
        ret = max(ret, rec(conv, nt, idx + 1, flag | (i > 0)));
      }
    }
  }
  return (ret);
}

int main() {
  cin >> Q;
  map<int, int> mx;
  for (int i = 0; i < Q; i++) {
    int m, x;
    cin >> m >> x;
    auto latte = prime_factor(m);
    for (auto &p : latte) {
      mx[p.first] = max(mx[p.first], p.second);
    }
    vv[i] = {latte, x};
  }
  vector<pair<int, int>> convert(begin(mx), end(mx));
  vector<int> candidate(Q);
  iota(begin(candidate), end(candidate), 0);
  cout << rec(convert, candidate, 0, false) << endl;
}

#include <bits/stdc++.h>

using namespace std;

using int64 = long long;
const int64 INF = 1LL << 59;

unordered_map<int64, int> prime_factor(int64 n) {
  unordered_map<int64, int> ret;
  for (int64 i = 2; i * i <= n; i++) {
    while (n % i == 0) {
      ret[i]++;
      n /= i;
    }
  }
  if (n != 1)
    ret[n] = 1;
  return (ret);
}

int Q;
pair<unordered_map<int64, int>, int> vv[300];

int64 rec(vector<pair<int, int>> &conv, vector<int> &candidate, int idx,
          bool flag) {
  int64 ret = 0;

  if (candidate.empty()) {
    return (ret);
  }

  if (flag) {
    for (auto &j : candidate)
      ret += vv[j].second;
  }

  if (idx < conv.size()) {

    if (conv[idx].first >= 17 && flag) {

      vector<int> used(Q, 0);
      int64 calc = 0;
      for (int i = idx; i < conv.size(); i++) {
        int64 beet = 0;
        if (conv[idx].first == 17) {
          int64 beet2 = 0;
          for (auto &j : candidate) {
            if (vv[j].first.count(conv[i].first)) {
              if (vv[j].first[conv[i].first] == 2)
                beet += vv[j].second;
              else
                beet2 += vv[j].second, beet += vv[j].second;
              used[j] = true;
            }
          }
          calc += max(0LL, max(beet, beet2));
          continue;
        }

        for (auto &j : candidate) {
          if (vv[j].first.count(conv[i].first)) {
            beet += vv[j].second;
            used[j] = true;
          }
        }
        calc += max(0LL, beet);
      }
      for (auto &j : candidate) {
        if (!used[j])
          calc += vv[j].second;
      }
      ret = max(ret, calc);

    } else {
      set<vector<int>> used;
      for (int i = 0; i <= conv[idx].second + 1; i++) {
        vector<int> nt;
        for (int j : candidate) {
          if (vv[j].first.count(conv[idx].first)) {
            if (vv[j].first[conv[idx].first] > i)
              continue;
          }
          nt.emplace_back(j);
        }
        if (used.count(nt))
          continue;
        used.emplace(nt);
        ret = max(ret, rec(conv, nt, idx + 1, flag | (i > 0)));
      }
    }
  }
  return (ret);
}

int main() {
  cin >> Q;
  map<int, int> mx;
  for (int i = 0; i < Q; i++) {
    int m, x;
    cin >> m >> x;
    auto latte = prime_factor(m);
    for (auto &p : latte) {
      mx[p.first] = max(mx[p.first], p.second);
    }
    vv[i] = {latte, x};
  }
  vector<pair<int, int>> convert(begin(mx), end(mx));
  vector<int> candidate(Q);
  iota(begin(candidate), end(candidate), 0);
  cout << rec(convert, candidate, 0, false) << endl;
}


#include <iostream>
#include <vector>
using namespace std;

long long N, M, dpa[1 << 18], dpb[1 << 18], power[200], powerinv[200],
    power3[200], mod = 1000000007;
bool used[16][16];
int V3[16];

vector<long long> solve(int pos) {
  vector<long long> dp((1 << N), 0);
  for (int i = 0; i < (1 << N); i++) {
    int bit[15];
    for (int j = 0; j < N; j++)
      bit[j] = (i / (1 << j)) % 2;
    if (bit[pos] == 0)
      continue;

    int cnt = 0;
    for (int j = 0; j < N; j++) {
      for (int k = j + 1; k < N; k++) {
        if (bit[j] == 1 && bit[k] == 1 && used[j][k] == true)
          cnt++;
      }
    }
    long long res = power[cnt];
    vector<int> V1;
    for (int j = 0; j < N; j++) {
      if (bit[j] == 1)
        V1.push_back(j);
    }

    for (int j = 0; j < (1 << V1.size()); j++) {
      int R = 0, T = 0;
      for (int k = 0; k < V1.size(); k++) {
        if ((j & (1 << k)) != 0)
          R += (1 << V1[k]);
        else {
          V3[T] = V1[k];
          T++;
        }
      }
      long long Y = dp[R];
      if (Y == 0)
        continue;
      for (int k = 0; k < T; k++) {
        for (int l = k + 1; l < T; l++) {
          if (used[V3[k]][V3[l]] == true) {
            Y *= 2;
            if (Y >= mod)
              Y -= mod;
          }
        }
      }
      res -= Y;
      if (res < 0)
        res += mod;
    }
    dp[i] = res;
  }
  return dp;
}

int main() {
  power[0] = 1;
  for (int i = 1; i < 200; i++)
    power[i] = (2LL * power[i - 1]) % mod;
  powerinv[0] = 1;
  for (int i = 1; i < 200; i++)
    powerinv[i] = (500000004LL * powerinv[i - 1]) % mod;
  power3[0] = 1;
  for (int i = 1; i < 200; i++)
    power3[i] = (3LL * power3[i - 1]) % mod;

  cin >> N >> M;
  for (int i = 0; i < M; i++) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    used[a][b] = true;
    used[b][a] = true;
  }

  vector<long long> A1 = solve(0);
  for (int i = 0; i < (1 << N); i++)
    dpa[i] = A1[i];
  vector<long long> A2 = solve(1);
  for (int i = 0; i < (1 << N); i++)
    dpb[i] = A2[i];

  long long ret = 0;
  for (int i = 7; i < power3[N]; i += 9) {
    int col[15];
    for (int j = 0; j < N; j++)
      col[j] = (i / power3[j]) % 3;
    int pa = 0, pb = 0;
    for (int j = 0; j < N; j++) {
      if (col[j] == 1)
        pa += (1 << j);
      if (col[j] == 2)
        pb += (1 << j);
    }

    if (dpa[pa] == 0 || dpb[pb] == 0)
      continue;
    long long E1 = dpa[pa] * dpb[pb] % mod;
    for (int j = 0; j < N; j++) {
      for (int k = 0; k < N; k++) {
        if (col[j] == 1 && col[k] == 2 && used[j][k] == true)
          E1 *= 0;
        if (col[j] == 0 && col[k] == 0 && j < k && used[j][k] == true) {
          E1 *= 2;
          E1 %= mod;
        }
      }
    }
    ret += E1;
    ret %= mod;
  }
  cout << (power[M] - ret + mod) % mod << endl;
  return 0;
}

#include <iostream>
#include <vector>
using namespace std;

long long N, M, dpa[1 << 18], dpb[1 << 18], power[200], powerinv[200],
    power3[200], mod = 1000000007;
bool used[16][16];
int V3[16];

vector<long long> solve(int pos) {
  vector<long long> dp((1 << N), 0);
  for (int i = 0; i < (1 << N); i++) {
    int bit[15];
    for (int j = 0; j < N; j++)
      bit[j] = (i / (1 << j)) % 2;
    if (bit[pos] == 0)
      continue;

    int cnt = 0;
    for (int j = 0; j < N; j++) {
      for (int k = j + 1; k < N; k++) {
        if (bit[j] == 1 && bit[k] == 1 && used[j][k] == true)
          cnt++;
      }
    }
    long long res = power[cnt];
    int G = 0;
    vector<int> V1;
    for (int j = 0; j < N; j++) {
      if (bit[j] == 1) {
        if (j == pos)
          G = (1 << V1.size());
        V1.push_back(j);
      }
    }

    for (int j = 0; j < (1 << V1.size()); j++) {
      if ((j & G) == 0)
        continue;
      int R = 0, T = 0;
      for (int k = 0; k < V1.size(); k++) {
        if ((j & (1 << k)) != 0)
          R += (1 << V1[k]);
        else {
          V3[T] = V1[k];
          T++;
        }
      }
      long long Y = dp[R];
      if (Y == 0)
        continue;
      for (int k = 0; k < T; k++) {
        for (int l = k + 1; l < T; l++) {
          if (used[V3[k]][V3[l]] == true) {
            Y *= 2;
            if (Y >= mod)
              Y -= mod;
          }
        }
      }
      res -= Y;
      if (res < 0)
        res += mod;
    }
    dp[i] = res;
  }
  return dp;
}

int main() {
  power[0] = 1;
  for (int i = 1; i < 200; i++)
    power[i] = (2LL * power[i - 1]) % mod;
  powerinv[0] = 1;
  for (int i = 1; i < 200; i++)
    powerinv[i] = (500000004LL * powerinv[i - 1]) % mod;
  power3[0] = 1;
  for (int i = 1; i < 200; i++)
    power3[i] = (3LL * power3[i - 1]) % mod;

  cin >> N >> M;
  for (int i = 0; i < M; i++) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    used[a][b] = true;
    used[b][a] = true;
  }

  vector<long long> A1 = solve(0);
  for (int i = 0; i < (1 << N); i++)
    dpa[i] = A1[i];
  vector<long long> A2 = solve(1);
  for (int i = 0; i < (1 << N); i++)
    dpb[i] = A2[i];

  long long ret = 0;
  for (int i = 7; i < power3[N]; i += 9) {
    int col[15];
    for (int j = 0; j < N; j++)
      col[j] = (i / power3[j]) % 3;
    int pa = 0, pb = 0;
    for (int j = 0; j < N; j++) {
      if (col[j] == 1)
        pa += (1 << j);
      if (col[j] == 2)
        pb += (1 << j);
    }

    if (dpa[pa] == 0 || dpb[pb] == 0)
      continue;
    long long E1 = dpa[pa] * dpb[pb] % mod;
    for (int j = 0; j < N; j++) {
      for (int k = 0; k < N; k++) {
        if (col[j] == 1 && col[k] == 2 && used[j][k] == true)
          E1 *= 0;
        if (col[j] == 0 && col[k] == 0 && j < k && used[j][k] == true) {
          E1 *= 2;
          E1 %= mod;
        }
      }
    }
    ret += E1;
    ret %= mod;
  }
  cout << (power[M] - ret + mod) % mod << endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;
using lint = long long;
template <class T = int> using V = vector<T>;
template <class T = int> using VV = V<V<T>>;

template <unsigned P> struct ModInt {
  using M = ModInt;
  unsigned v;
  constexpr ModInt() : v(0) {}
  constexpr ModInt(unsigned _v, int) : v(_v) {}
  template <class Z> ModInt(const Z &a) : v((a < 0 ? P - -a % P : a) % P) {}
  static constexpr unsigned p() { return P; }
  M operator+() const { return *this; }
  M operator-() const { return {v ? P - v : 0, 0}; }
  explicit operator bool() const noexcept { return v; }
  bool operator!() const noexcept { return !(bool)*this; }
  M &operator*=(M r) {
    v = (uint64_t)v * r.v % P;
    return *this;
  }
  M &operator/=(M r) { return *this *= r.inv(); }
  M &operator+=(M r) {
    if ((v += r.v) >= P)
      v -= P;
    return *this;
  }
  M &operator-=(M r) {
    if ((v += P - r.v) >= P)
      v -= P;
    return *this;
  }
  M inv() const {
    int a = v, b = P, x = 1, u = 0;
    while (b) {
      int q = a / b;
      swap(a -= q * b, b);
      swap(x -= q * u, u);
    }
    assert(a == 1);
    return x;
  }
  template <class Z> M pow(Z n) const {
    if (n < 0)
      return pow(-n).inv();
    M res = 1;
    for (M a = *this; n; a *= a, n >>= 1)
      if (n & 1)
        res *= a;
    return res;
  }
  friend M operator*(M l, M r) { return M(l) *= r; }
  friend M operator/(M l, M r) { return M(l) /= r; }
  friend M operator+(M l, M r) { return M(l) += r; }
  friend M operator-(M l, M r) { return M(l) -= r; }
  friend ostream &operator<<(ostream &os, M r) { return os << r.v; }
  friend bool operator==(M l, M r) { return l.v == r.v; }
  friend bool operator!=(M l, M r) { return !(l == r); }
};
using Mint = ModInt<(unsigned)1e9 + 7>;

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  int n, m;
  cin >> n >> m;
  V<bitset<15>> g(n);
  for (int _ = 0; _ < m; ++_) {
    int u, v;
    cin >> u >> v, --u, --v;
    g[u][v] = g[v][u] = 1;
  }

  auto fn = [&](int r) -> V<Mint> {
    V<Mint> dp(1 << n);
    for (int S = 0; S < 1 << n; ++S)
      if (S >> r & 1) {
        int c = 0;
        for (int u = 0; u < n; ++u)
          if (S >> u & 1) {
            for (int v = 0; v < n; ++v)
              if (~S >> v & 1) {
                c += g[u][v];
              }
          }
        dp[S] = Mint(2).pow(-c);
        for (int T = (S - 1) & S;; T = (T - 1) & S) {
          c = 0;
          for (int u = 0; u < n; ++u)
            if (S >> u & 1 and ~T >> u & 1) {
              for (int v = 0; v < n; ++v)
                if (~S >> v & 1) {
                  c += g[u][v];
                }
            }
          dp[S] -= dp[T] * Mint(2).pow(-c);
          if (!T)
            break;
        }
      }
    return dp;
  };

  auto dp0 = fn(0);
  auto dp1 = fn(1);
  Mint res = 1;
  for (int S = 0; S < 1 << n; ++S) {
    int Sc = S ^ ~(~0U << n);
    for (int T = Sc;; T = (T - 1) & Sc) {
      int c = 0;
      for (int u = 0; u < n; ++u)
        if (S >> u & 1) {
          for (int v = 0; v < n; ++v)
            if (T >> v & 1) {
              c += g[u][v];
            }
        }
      if (!c) {
        res -= dp0[S] * dp1[T];
      }
      if (!T)
        break;
    }
  }
  res *= Mint(2).pow(m);
  cout << res << '\\n';
}

#include <bits/stdc++.h>
using namespace std;
using lint = long long;
template <class T = int> using V = vector<T>;
template <class T = int> using VV = V<V<T>>;

template <unsigned P> struct ModInt {
  using M = ModInt;
  unsigned v;
  constexpr ModInt() : v(0) {}
  constexpr ModInt(unsigned _v, int) : v(_v) {}
  template <class Z> ModInt(const Z &a) : v((a < 0 ? P - -a % P : a) % P) {}
  static constexpr unsigned p() { return P; }
  M operator+() const { return *this; }
  M operator-() const { return {v ? P - v : 0, 0}; }
  explicit operator bool() const noexcept { return v; }
  bool operator!() const noexcept { return !(bool)*this; }
  M &operator*=(M r) {
    v = (uint64_t)v * r.v % P;
    return *this;
  }
  M &operator/=(M r) { return *this *= r.inv(); }
  M &operator+=(M r) {
    if ((v += r.v) >= P)
      v -= P;
    return *this;
  }
  M &operator-=(M r) {
    if ((v += P - r.v) >= P)
      v -= P;
    return *this;
  }
  M inv() const {
    int a = v, b = P, x = 1, u = 0;
    while (b) {
      int q = a / b;
      swap(a -= q * b, b);
      swap(x -= q * u, u);
    }
    assert(a == 1);
    return x;
  }
  template <class Z> M pow(Z n) const {
    if (n < 0)
      return pow(-n).inv();
    M res = 1;
    for (M a = *this; n; a *= a, n >>= 1)
      if (n & 1)
        res *= a;
    return res;
  }
  friend M operator*(M l, M r) { return M(l) *= r; }
  friend M operator/(M l, M r) { return M(l) /= r; }
  friend M operator+(M l, M r) { return M(l) += r; }
  friend M operator-(M l, M r) { return M(l) -= r; }
  friend ostream &operator<<(ostream &os, M r) { return os << r.v; }
  friend bool operator==(M l, M r) { return l.v == r.v; }
  friend bool operator!=(M l, M r) { return !(l == r); }
};
using Mint = ModInt<(unsigned)1e9 + 7>;

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  int n, m;
  cin >> n >> m;
  V<bitset<15>> g(n);
  for (int _ = 0; _ < m; ++_) {
    int u, v;
    cin >> u >> v, --u, --v;
    g[u][v] = g[v][u] = 1;
  }
  V<Mint> ipw(m + 1, 1);
  for (int i = 1; i <= m; ++i) {
    ipw[i] = ipw[i - 1] / 2;
  }

  auto fn = [&](int r) -> V<Mint> {
    V<Mint> dp(1 << n);
    for (int S = 0; S < 1 << n; ++S)
      if (S >> r & 1) {
        int c = 0;
        for (int u = 0; u < n; ++u)
          if (S >> u & 1) {
            for (int v = 0; v < n; ++v)
              if (~S >> v & 1) {
                c += g[u][v];
              }
          }
        dp[S] = ipw[c];
        V<> a(n);
        for (int u = 0; u < n; ++u)
          if (~S >> u & 1) {
            for (int v = 0; v < n; ++v)
              if (S >> v & 1) {
                a[v] += g[u][v];
              }
          }
        for (int T = (S - 1) & S;; T = (T - 1) & S) {
          c = 0;
          for (int v = 0; v < n; ++v)
            if ((S ^ T) >> v & 1) {
              c += a[v];
            }
          dp[S] -= dp[T] * ipw[c];
          if (!T)
            break;
        }
      }
    return dp;
  };

  auto dp0 = fn(0);
  auto dp1 = fn(1);
  Mint res = 1;
  for (int S = 0; S < 1 << n; ++S) {
    int nS = S;
    for (int u = 0; u < n; ++u)
      if (S >> u & 1) {
        for (int v = 0; v < n; ++v)
          if (g[u][v]) {
            nS |= 1 << v;
          }
      }
    for (int T = nS ^ ~(~0U << n);; T = (T - 1) & (nS ^ ~(~0U << n))) {
      res -= dp0[S] * dp1[T];
      if (!T)
        break;
    }
  }
  res *= Mint(2).pow(m);
  cout << res << '\\n';
}


#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Tubtet(i, k) for (k = (i - 1) & i; k; k = (k - 1) & i)
#define Subset(i, k) for (k = i; k; k = (k - 1) & i)
using namespace std;
inline int read() {
  int res = 0;
  bool bo = 0;
  char c;
  while (((c = getchar()) < '0' || c > '9') && c != '-')
    ;
  if (c == '-')
    bo = 1;
  else
    res = c - 48;
  while ((c = getchar()) >= '0' && c <= '9')
    res = (res << 3) + (res << 1) + (c - 48);
  return bo ? ~res + 1 : res;
}
const int N = 17, M = 405, C = (1 << 15) + 5, PYZ = 1e9 + 7;
int n, m, g[N][N], f[3][C], c[C], d[C], Cm, p[M], ans;
int main() {
  int i, j, k, x, y;
  n = read();
  m = read();
  p[0] = 1;
  For(i, 1, m) x = read(), y = read(), g[x][y]++, p[i] = 2ll * p[i - 1] % PYZ;
  Cm = (1 << n) - 1;
  For(i, 0, Cm) For(j, 1, n) For(k, 1, n) if (g[j][k]) {
    if (((i >> j - 1) & 1) && ((i >> k - 1) & 1))
      c[i] += g[j][k];
    if (((i >> j - 1) & 1) || ((i >> k - 1) & 1))
      d[i] += g[j][k];
  }
  For(k, 1, 2) For(i, 0, Cm) {
    if (!((i >> k - 1) & 1))
      continue;
    f[k][i] = p[c[i]];
    Tubtet(i, j) {
      if (!((j >> k - 1) & 1))
        continue;
      f[k][i] = (f[k][i] - 1ll * f[k][j] * p[c[i - j]] % PYZ + PYZ) % PYZ;
    }
  }
  ans = p[m];
  For(i, 0, Cm) {
    if (!(i & 1) || ((i >> 1) & 1))
      continue;
    Subset(Cm - i, j) {
      if (!((j >> 1) & 1) || c[i] + c[j] < c[i + j])
        continue;
      ans =
          (ans - 1ll * f[1][i] * f[2][j] % PYZ * p[m - d[i + j]] % PYZ + PYZ) %
          PYZ;
    }
  }
  cout << ans << endl;
  return 0;
}


/**
 *    author:  tourist
 *    created: 12.12.2019 19:24:11
 **/
#include <bits/stdc++.h>

using namespace std;

template <typename A, typename B> string to_string(pair<A, B> p);

template <typename A, typename B, typename C>
string to_string(tuple<A, B, C> p);

template <typename A, typename B, typename C, typename D>
string to_string(tuple<A, B, C, D> p);

string to_string(const string &s) { return '"' + s + '"'; }

string to_string(const char *s) { return to_string((string)s); }

string to_string(bool b) { return (b ? "true" : "false"); }

string to_string(vector<bool> v) {
  bool first = true;
  string res = "{";
  for (int i = 0; i < static_cast<int>(v.size()); i++) {
    if (!first) {
      res += ", ";
    }
    first = false;
    res += to_string(v[i]);
  }
  res += "}";
  return res;
}

template <size_t N> string to_string(bitset<N> v) {
  string res = "";
  for (size_t i = 0; i < N; i++) {
    res += static_cast<char>('0' + v[i]);
  }
  return res;
}

template <typename A> string to_string(A v) {
  bool first = true;
  string res = "{";
  for (const auto &x : v) {
    if (!first) {
      res += ", ";
    }
    first = false;
    res += to_string(x);
  }
  res += "}";
  return res;
}

template <typename A, typename B> string to_string(pair<A, B> p) {
  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}

template <typename A, typename B, typename C>
string to_string(tuple<A, B, C> p) {
  return "(" + to_string(get<0>(p)) + ", " + to_string(get<1>(p)) + ", " +
         to_string(get<2>(p)) + ")";
}

template <typename A, typename B, typename C, typename D>
string to_string(tuple<A, B, C, D> p) {
  return "(" + to_string(get<0>(p)) + ", " + to_string(get<1>(p)) + ", " +
         to_string(get<2>(p)) + ", " + to_string(get<3>(p)) + ")";
}

void debug_out() { cerr << endl; }

template <typename Head, typename... Tail> void debug_out(Head H, Tail... T) {
  cerr << " " << to_string(H);
  debug_out(T...);
}

#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

template <typename T> T inverse(T a, T m) {
  T u = 0, v = 1;
  while (a != 0) {
    T t = m / a;
    m -= t * a;
    swap(a, m);
    u -= t * v;
    swap(u, v);
  }
  assert(m == 1);
  return u;
}

template <typename T> class Modular {
public:
  using Type = typename decay<decltype(T::value)>::type;

  constexpr Modular() : value() {}
  template <typename U> Modular(const U &x) { value = normalize(x); }

  template <typename U> static Type normalize(const U &x) {
    Type v;
    if (-mod() <= x && x < mod())
      v = static_cast<Type>(x);
    else
      v = static_cast<Type>(x % mod());
    if (v < 0)
      v += mod();
    return v;
  }

  const Type &operator()() const { return value; }
  template <typename U> explicit operator U() const {
    return static_cast<U>(value);
  }
  constexpr static Type mod() { return T::value; }

  Modular &operator+=(const Modular &other) {
    if ((value += other.value) >= mod())
      value -= mod();
    return *this;
  }
  Modular &operator-=(const Modular &other) {
    if ((value -= other.value) < 0)
      value += mod();
    return *this;
  }
  template <typename U> Modular &operator+=(const U &other) {
    return *this += Modular(other);
  }
  template <typename U> Modular &operator-=(const U &other) {
    return *this -= Modular(other);
  }
  Modular &operator++() { return *this += 1; }
  Modular &operator--() { return *this -= 1; }
  Modular operator++(int) {
    Modular result(*this);
    *this += 1;
    return result;
  }
  Modular operator--(int) {
    Modular result(*this);
    *this -= 1;
    return result;
  }
  Modular operator-() const { return Modular(-value); }

  template <typename U = T>
  typename enable_if<is_same<typename Modular<U>::Type, int>::value,
                     Modular>::type &
  operator*=(const Modular &rhs) {
#ifdef _WIN32
    uint64_t x = static_cast<int64_t>(value) * static_cast<int64_t>(rhs.value);
    uint32_t xh = static_cast<uint32_t>(x >> 32), xl = static_cast<uint32_t>(x),
             d, m;
    asm("divl %4; \\n\\t" : "=a"(d), "=d"(m) : "d"(xh), "a"(xl), "r"(mod()));
    value = m;
#else
    value = normalize(static_cast<int64_t>(value) *
                      static_cast<int64_t>(rhs.value));
#endif
    return *this;
  }
  template <typename U = T>
  typename enable_if<is_same<typename Modular<U>::Type, int64_t>::value,
                     Modular>::type &
  operator*=(const Modular &rhs) {
    int64_t q = static_cast<int64_t>(static_cast<long double>(value) *
                                     rhs.value / mod());
    value = normalize(value * rhs.value - q * mod());
    return *this;
  }
  template <typename U = T>
  typename enable_if<!is_integral<typename Modular<U>::Type>::value,
                     Modular>::type &
  operator*=(const Modular &rhs) {
    value = normalize(value * rhs.value);
    return *this;
  }

  Modular &operator/=(const Modular &other) {
    return *this *= Modular(inverse(other.value, mod()));
  }

  template <typename U> friend const Modular<U> &abs(const Modular<U> &v) {
    return v;
  }

  template <typename U>
  friend bool operator==(const Modular<U> &lhs, const Modular<U> &rhs);

  template <typename U>
  friend bool operator<(const Modular<U> &lhs, const Modular<U> &rhs);

  template <typename U>
  friend std::istream &operator>>(std::istream &stream, Modular<U> &number);

private:
  Type value;
};

template <typename T>
bool operator==(const Modular<T> &lhs, const Modular<T> &rhs) {
  return lhs.value == rhs.value;
}
template <typename T, typename U>
bool operator==(const Modular<T> &lhs, U rhs) {
  return lhs == Modular<T>(rhs);
}
template <typename T, typename U>
bool operator==(U lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) == rhs;
}

template <typename T>
bool operator!=(const Modular<T> &lhs, const Modular<T> &rhs) {
  return !(lhs == rhs);
}
template <typename T, typename U>
bool operator!=(const Modular<T> &lhs, U rhs) {
  return !(lhs == rhs);
}
template <typename T, typename U>
bool operator!=(U lhs, const Modular<T> &rhs) {
  return !(lhs == rhs);
}

template <typename T>
bool operator<(const Modular<T> &lhs, const Modular<T> &rhs) {
  return lhs.value < rhs.value;
}

template <typename T>
Modular<T> operator+(const Modular<T> &lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) += rhs;
}
template <typename T, typename U>
Modular<T> operator+(const Modular<T> &lhs, U rhs) {
  return Modular<T>(lhs) += rhs;
}
template <typename T, typename U>
Modular<T> operator+(U lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) += rhs;
}

template <typename T>
Modular<T> operator-(const Modular<T> &lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) -= rhs;
}
template <typename T, typename U>
Modular<T> operator-(const Modular<T> &lhs, U rhs) {
  return Modular<T>(lhs) -= rhs;
}
template <typename T, typename U>
Modular<T> operator-(U lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) -= rhs;
}

template <typename T>
Modular<T> operator*(const Modular<T> &lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) *= rhs;
}
template <typename T, typename U>
Modular<T> operator*(const Modular<T> &lhs, U rhs) {
  return Modular<T>(lhs) *= rhs;
}
template <typename T, typename U>
Modular<T> operator*(U lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) *= rhs;
}

template <typename T>
Modular<T> operator/(const Modular<T> &lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) /= rhs;
}
template <typename T, typename U>
Modular<T> operator/(const Modular<T> &lhs, U rhs) {
  return Modular<T>(lhs) /= rhs;
}
template <typename T, typename U>
Modular<T> operator/(U lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) /= rhs;
}

template <typename T, typename U>
Modular<T> power(const Modular<T> &a, const U &b) {
  assert(b >= 0);
  Modular<T> x = a, res = 1;
  U p = b;
  while (p > 0) {
    if (p & 1)
      res *= x;
    x *= x;
    p >>= 1;
  }
  return res;
}

template <typename T> bool IsZero(const Modular<T> &number) {
  return number() == 0;
}

template <typename T> string to_string(const Modular<T> &number) {
  return to_string(number());
}

template <typename T>
std::ostream &operator<<(std::ostream &stream, const Modular<T> &number) {
  return stream << number();
}

template <typename T>
std::istream &operator>>(std::istream &stream, Modular<T> &number) {
  typename common_type<typename Modular<T>::Type, int64_t>::type x;
  stream >> x;
  number.value = Modular<T>::normalize(x);
  return stream;
}

/*
using ModType = int;

struct VarMod { static ModType value; };
ModType VarMod::value;
ModType& md = VarMod::value;
using Mint = Modular<VarMod>;
*/

constexpr int md = (int)1e9 + 7;
using Mint = Modular<std::integral_constant<decay<decltype(md)>::type, md>>;

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int n, m;
  cin >> n >> m;
  vector<int> g(n);
  for (int i = 0; i < m; i++) {
    int x, y;
    cin >> x >> y;
    --x;
    --y;
    g[x] |= 1 << y;
    g[y] |= 1 << x;
  }
  Mint inv2 = 1 / Mint(2);
  vector<vector<Mint>> p(2, vector<Mint>(1 << n));
  for (int v = 0; v < 2; v++) {
    for (int t = 0; t < (1 << n); t++) {
      if (t & (1 << v)) {
        p[v][t] = 1;
        int u = t;
        while (u > 0) {
          u = (u - 1) & t;
          if (u & (1 << v)) {
            Mint cur = p[v][u];
            for (int i = 0; i < n; i++) {
              if (u & (1 << i)) {
                for (int j = 0; j < n; j++) {
                  if (!(u & (1 << j)) && (t & (1 << j))) {
                    if (g[i] & (1 << j)) {
                      cur *= inv2;
                    }
                  }
                }
              }
            }
            p[v][t] -= cur;
          }
        }
      }
    }
  }
  debug(p);
  Mint ans = 1;
  for (int t = 1; t < (1 << n); t++) {
    if (t & 1) {
      int u = (1 << n) - 1 - t;
      while (u > 0) {
        if (u & 2) {
          bool ok = true;
          for (int i = 0; i < n; i++) {
            if (t & (1 << i)) {
              for (int j = 0; j < n; j++) {
                if (u & (1 << j)) {
                  if (g[i] & (1 << j)) {
                    ok = false;
                  }
                }
              }
            }
          }
          if (ok) {
            Mint cur = p[0][t] * p[1][u];
            for (int i = 0; i < n; i++) {
              if ((t | u) & (1 << i)) {
                for (int j = 0; j < n; j++) {
                  if (!((t | u) & (1 << j))) {
                    if (g[i] & (1 << j)) {
                      cur *= inv2;
                    }
                  }
                }
              }
            }
            ans -= cur;
          }
        }
        u = (u - 1) & ((1 << n) - 1 - t);
      }
    }
  }
  ans *= power(Mint(2), m);
  cout << ans << '\\n';
  return 0;
}

/**
 *    author:  tourist
 *    created: 12.12.2019 19:24:11
 **/
#include <bits/stdc++.h>

using namespace std;

template <typename A, typename B> string to_string(pair<A, B> p);

template <typename A, typename B, typename C>
string to_string(tuple<A, B, C> p);

template <typename A, typename B, typename C, typename D>
string to_string(tuple<A, B, C, D> p);

string to_string(const string &s) { return '"' + s + '"'; }

string to_string(const char *s) { return to_string((string)s); }

string to_string(bool b) { return (b ? "true" : "false"); }

string to_string(vector<bool> v) {
  bool first = true;
  string res = "{";
  for (int i = 0; i < static_cast<int>(v.size()); i++) {
    if (!first) {
      res += ", ";
    }
    first = false;
    res += to_string(v[i]);
  }
  res += "}";
  return res;
}

template <size_t N> string to_string(bitset<N> v) {
  string res = "";
  for (size_t i = 0; i < N; i++) {
    res += static_cast<char>('0' + v[i]);
  }
  return res;
}

template <typename A> string to_string(A v) {
  bool first = true;
  string res = "{";
  for (const auto &x : v) {
    if (!first) {
      res += ", ";
    }
    first = false;
    res += to_string(x);
  }
  res += "}";
  return res;
}

template <typename A, typename B> string to_string(pair<A, B> p) {
  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}

template <typename A, typename B, typename C>
string to_string(tuple<A, B, C> p) {
  return "(" + to_string(get<0>(p)) + ", " + to_string(get<1>(p)) + ", " +
         to_string(get<2>(p)) + ")";
}

template <typename A, typename B, typename C, typename D>
string to_string(tuple<A, B, C, D> p) {
  return "(" + to_string(get<0>(p)) + ", " + to_string(get<1>(p)) + ", " +
         to_string(get<2>(p)) + ", " + to_string(get<3>(p)) + ")";
}

void debug_out() { cerr << endl; }

template <typename Head, typename... Tail> void debug_out(Head H, Tail... T) {
  cerr << " " << to_string(H);
  debug_out(T...);
}

#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

template <typename T> T inverse(T a, T m) {
  T u = 0, v = 1;
  while (a != 0) {
    T t = m / a;
    m -= t * a;
    swap(a, m);
    u -= t * v;
    swap(u, v);
  }
  assert(m == 1);
  return u;
}

template <typename T> class Modular {
public:
  using Type = typename decay<decltype(T::value)>::type;

  constexpr Modular() : value() {}
  template <typename U> Modular(const U &x) { value = normalize(x); }

  template <typename U> static Type normalize(const U &x) {
    Type v;
    if (-mod() <= x && x < mod())
      v = static_cast<Type>(x);
    else
      v = static_cast<Type>(x % mod());
    if (v < 0)
      v += mod();
    return v;
  }

  const Type &operator()() const { return value; }
  template <typename U> explicit operator U() const {
    return static_cast<U>(value);
  }
  constexpr static Type mod() { return T::value; }

  Modular &operator+=(const Modular &other) {
    if ((value += other.value) >= mod())
      value -= mod();
    return *this;
  }
  Modular &operator-=(const Modular &other) {
    if ((value -= other.value) < 0)
      value += mod();
    return *this;
  }
  template <typename U> Modular &operator+=(const U &other) {
    return *this += Modular(other);
  }
  template <typename U> Modular &operator-=(const U &other) {
    return *this -= Modular(other);
  }
  Modular &operator++() { return *this += 1; }
  Modular &operator--() { return *this -= 1; }
  Modular operator++(int) {
    Modular result(*this);
    *this += 1;
    return result;
  }
  Modular operator--(int) {
    Modular result(*this);
    *this -= 1;
    return result;
  }
  Modular operator-() const { return Modular(-value); }

  template <typename U = T>
  typename enable_if<is_same<typename Modular<U>::Type, int>::value,
                     Modular>::type &
  operator*=(const Modular &rhs) {
#ifdef _WIN32
    uint64_t x = static_cast<int64_t>(value) * static_cast<int64_t>(rhs.value);
    uint32_t xh = static_cast<uint32_t>(x >> 32), xl = static_cast<uint32_t>(x),
             d, m;
    asm("divl %4; \\n\\t" : "=a"(d), "=d"(m) : "d"(xh), "a"(xl), "r"(mod()));
    value = m;
#else
    value = normalize(static_cast<int64_t>(value) *
                      static_cast<int64_t>(rhs.value));
#endif
    return *this;
  }
  template <typename U = T>
  typename enable_if<is_same<typename Modular<U>::Type, int64_t>::value,
                     Modular>::type &
  operator*=(const Modular &rhs) {
    int64_t q = static_cast<int64_t>(static_cast<long double>(value) *
                                     rhs.value / mod());
    value = normalize(value * rhs.value - q * mod());
    return *this;
  }
  template <typename U = T>
  typename enable_if<!is_integral<typename Modular<U>::Type>::value,
                     Modular>::type &
  operator*=(const Modular &rhs) {
    value = normalize(value * rhs.value);
    return *this;
  }

  Modular &operator/=(const Modular &other) {
    return *this *= Modular(inverse(other.value, mod()));
  }

  template <typename U> friend const Modular<U> &abs(const Modular<U> &v) {
    return v;
  }

  template <typename U>
  friend bool operator==(const Modular<U> &lhs, const Modular<U> &rhs);

  template <typename U>
  friend bool operator<(const Modular<U> &lhs, const Modular<U> &rhs);

  template <typename U>
  friend std::istream &operator>>(std::istream &stream, Modular<U> &number);

private:
  Type value;
};

template <typename T>
bool operator==(const Modular<T> &lhs, const Modular<T> &rhs) {
  return lhs.value == rhs.value;
}
template <typename T, typename U>
bool operator==(const Modular<T> &lhs, U rhs) {
  return lhs == Modular<T>(rhs);
}
template <typename T, typename U>
bool operator==(U lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) == rhs;
}

template <typename T>
bool operator!=(const Modular<T> &lhs, const Modular<T> &rhs) {
  return !(lhs == rhs);
}
template <typename T, typename U>
bool operator!=(const Modular<T> &lhs, U rhs) {
  return !(lhs == rhs);
}
template <typename T, typename U>
bool operator!=(U lhs, const Modular<T> &rhs) {
  return !(lhs == rhs);
}

template <typename T>
bool operator<(const Modular<T> &lhs, const Modular<T> &rhs) {
  return lhs.value < rhs.value;
}

template <typename T>
Modular<T> operator+(const Modular<T> &lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) += rhs;
}
template <typename T, typename U>
Modular<T> operator+(const Modular<T> &lhs, U rhs) {
  return Modular<T>(lhs) += rhs;
}
template <typename T, typename U>
Modular<T> operator+(U lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) += rhs;
}

template <typename T>
Modular<T> operator-(const Modular<T> &lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) -= rhs;
}
template <typename T, typename U>
Modular<T> operator-(const Modular<T> &lhs, U rhs) {
  return Modular<T>(lhs) -= rhs;
}
template <typename T, typename U>
Modular<T> operator-(U lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) -= rhs;
}

template <typename T>
Modular<T> operator*(const Modular<T> &lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) *= rhs;
}
template <typename T, typename U>
Modular<T> operator*(const Modular<T> &lhs, U rhs) {
  return Modular<T>(lhs) *= rhs;
}
template <typename T, typename U>
Modular<T> operator*(U lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) *= rhs;
}

template <typename T>
Modular<T> operator/(const Modular<T> &lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) /= rhs;
}
template <typename T, typename U>
Modular<T> operator/(const Modular<T> &lhs, U rhs) {
  return Modular<T>(lhs) /= rhs;
}
template <typename T, typename U>
Modular<T> operator/(U lhs, const Modular<T> &rhs) {
  return Modular<T>(lhs) /= rhs;
}

template <typename T, typename U>
Modular<T> power(const Modular<T> &a, const U &b) {
  assert(b >= 0);
  Modular<T> x = a, res = 1;
  U p = b;
  while (p > 0) {
    if (p & 1)
      res *= x;
    x *= x;
    p >>= 1;
  }
  return res;
}

template <typename T> bool IsZero(const Modular<T> &number) {
  return number() == 0;
}

template <typename T> string to_string(const Modular<T> &number) {
  return to_string(number());
}

template <typename T>
std::ostream &operator<<(std::ostream &stream, const Modular<T> &number) {
  return stream << number();
}

template <typename T>
std::istream &operator>>(std::istream &stream, Modular<T> &number) {
  typename common_type<typename Modular<T>::Type, int64_t>::type x;
  stream >> x;
  number.value = Modular<T>::normalize(x);
  return stream;
}

/*
using ModType = int;

struct VarMod { static ModType value; };
ModType VarMod::value;
ModType& md = VarMod::value;
using Mint = Modular<VarMod>;
*/

constexpr int md = (int)1e9 + 7;
using Mint = Modular<std::integral_constant<decay<decltype(md)>::type, md>>;

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int n, m;
  cin >> n >> m;
  vector<int> g(n);
  for (int i = 0; i < m; i++) {
    int x, y;
    cin >> x >> y;
    --x;
    --y;
    g[x] |= 1 << y;
    g[y] |= 1 << x;
  }
  vector<Mint> pinv2(n * n + 1);
  pinv2[0] = 1;
  for (int i = 1; i < (int)pinv2.size(); i++) {
    pinv2[i] = pinv2[i - 1] / 2;
  }
  vector<vector<Mint>> p(2, vector<Mint>(1 << n));
  for (int v = 0; v < 2; v++) {
    for (int t = 0; t < (1 << n); t++) {
      if (t & (1 << v)) {
        p[v][t] = 1;
        int u = t;
        while (u > 0) {
          u = (u - 1) & t;
          if (u & (1 << v)) {
            int c = 0;
            for (int i = 0; i < n; i++) {
              if (u & (1 << i)) {
                c += __builtin_popcount(t & ~u & g[i]);
              }
            }
            p[v][t] -= p[v][u] * pinv2[c];
          }
        }
      }
    }
  }
  Mint ans = 1;
  for (int t = 1; t < (1 << n); t++) {
    if (t & 1) {
      int u = (1 << n) - 1 - t;
      while (u > 0) {
        if (u & 2) {
          bool ok = true;
          for (int i = 0; i < n; i++) {
            if ((t & (1 << i)) && (u & g[i])) {
              ok = false;
              break;
            }
          }
          if (ok) {
            int c = 0;
            for (int i = 0; i < n; i++) {
              if ((t | u) & (1 << i)) {
                c += __builtin_popcount(~t & ~u & g[i]);
              }
            }
            ans -= p[0][t] * p[1][u] * pinv2[c];
          }
        }
        u = (u - 1) & ((1 << n) - 1 - t);
      }
    }
  }
  ans *= power(Mint(2), m);
  cout << ans << '\\n';
  return 0;
}


#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define rep1(i, n) for (int i = 1; i <= (int)(n); i++)
#define all(c) c.begin(), c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) cout << #x << " = " << x << endl
#define chmin(x, y) x = min(x, y)
#define chmax(x, y) x = max(x, y)
using namespace std;
template <class S, class T>
ostream &operator<<(ostream &o, const pair<S, T> &p) {
  return o << "(" << p.fs << "," << p.sc << ")";
}
template <class T> ostream &operator<<(ostream &o, const vector<T> &vc) {
  o << "sz = " << vc.size() << endl << "[";
  for (const T &v : vc)
    o << v << ",";
  o << "]";
  return o;
}

template <unsigned int mod_> struct ModInt {
  using uint = unsigned int;
  using ll = long long;
  using ull = unsigned long long;

  constexpr static uint mod = mod_;

  uint v;
  ModInt() : v(0) {}
  ModInt(ll v) : v(normS(v % mod + mod)) {}
  explicit operator bool() const { return v != 0; }
  static uint normS(const uint &x) {
    return (x < mod) ? x : x - mod;
  } // [0 , 2*mod-1] -> [0 , mod-1]
  static ModInt make(const uint &x) {
    ModInt m;
    m.v = x;
    return m;
  }
  ModInt operator+(const ModInt &b) const { return make(normS(v + b.v)); }
  ModInt operator-(const ModInt &b) const { return make(normS(v + mod - b.v)); }
  ModInt operator-() const { return make(normS(mod - v)); }
  ModInt operator*(const ModInt &b) const { return make((ull)v * b.v % mod); }
  ModInt operator/(const ModInt &b) const { return *this * b.inv(); }
  ModInt &operator+=(const ModInt &b) { return *this = *this + b; }
  ModInt &operator-=(const ModInt &b) { return *this = *this - b; }
  ModInt &operator*=(const ModInt &b) { return *this = *this * b; }
  ModInt &operator/=(const ModInt &b) { return *this = *this / b; }
  ll extgcd(ll a, ll b, ll &x, ll &y) const {
    ll u[] = {a, 1, 0}, v[] = {b, 0, 1};
    while (*v) {
      ll t = *u / *v;
      rep(i, 3) swap(u[i] -= t * v[i], v[i]);
    }
    if (u[0] < 0)
      rep(i, 3) u[i] = -u[i];
    x = u[1], y = u[2];
    return u[0];
  }
  ModInt inv() const {
    ll x, y;
    extgcd(v, mod, x, y);
    return make(normS(x + mod));
  }
  bool operator==(const ModInt &b) const { return v == b.v; }
  bool operator!=(const ModInt &b) const { return v != b.v; }
  friend istream &operator>>(istream &o, ModInt &x) {
    ll tmp;
    o >> tmp;
    x = ModInt(tmp);
    return o;
  }
  friend ostream &operator<<(ostream &o, const ModInt &x) { return o << x.v; }
};
using mint = ModInt<1000000007>;

bool B(int x, int i) { return (x >> i) & 1; }

int N, M;
mint dp0[1 << 15], dp1[1 << 15];
mint p2[10000];
int x[10000], y[10000];
int in[1 << 15];
int _in(int S) {
  int res = 0;
  rep(i, M) if (B(S, x[i]) && B(S, y[i])) res++;
  return res;
}
int cut(int S, int T) { return in[S + T] - in[S] - in[T]; }

int main() {
  p2[0] = 1;
  rep1(i, 9999) p2[i] = p2[i - 1] * 2;
  cin >> N >> M;
  rep(i, M) {
    cin >> x[i] >> y[i];
    x[i]--, y[i]--;
  }
  rep(S, 1 << N) in[S] = _in(S);
  rep(S, 1 << N) if (B(S, 0)) {
    dp0[S] = mint(1);
    for (int T = (S - 1) & S; T > 0; T = (T - 1) & S)
      if (B(T, 0)) {
        dp0[S] -= dp0[T] / p2[cut(T, S - T)];
      }
  }
  rep(S, 1 << N) if (B(S, 0)) { dp0[S] /= p2[cut(S, (1 << N) - 1 - S)]; }

  rep(S, 1 << N) if (B(S, 1)) {
    dp1[S] = mint(1);
    for (int T = (S - 1) & S; T > 0; T = (T - 1) & S)
      if (B(T, 1)) {
        dp1[S] -= dp1[T] / p2[cut(T, S - T)];
      }
  }
  rep(S, 1 << N) if (B(S, 1)) { dp1[S] /= p2[cut(S, (1 << N) - 1 - S)]; }

  mint ans = 1;
  rep(S, 1 << N) if (B(S, 0)) {
    int S2 = S;
    rep(i, M) {
      if (B(S, x[i]))
        S2 |= 1 << y[i];
      if (B(S, y[i]))
        S2 |= 1 << x[i];
    }
    int Tup = (1 << N) - 1 - S2;
    for (int T = Tup; T > 0; T = (T - 1) & Tup)
      if (B(T, 1)) {
        ans -= dp0[S] * dp1[T];
      }
  }
  ans *= p2[M];
  cout << ans << endl;
}

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define rep1(i, n) for (int i = 1; i <= (int)(n); i++)
#define all(c) c.begin(), c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) cout << #x << " = " << x << endl
#define chmin(x, y) x = min(x, y)
#define chmax(x, y) x = max(x, y)
using namespace std;
template <class S, class T>
ostream &operator<<(ostream &o, const pair<S, T> &p) {
  return o << "(" << p.fs << "," << p.sc << ")";
}
template <class T> ostream &operator<<(ostream &o, const vector<T> &vc) {
  o << "sz = " << vc.size() << endl << "[";
  for (const T &v : vc)
    o << v << ",";
  o << "]";
  return o;
}

template <unsigned int mod_> struct ModInt {
  using uint = unsigned int;
  using ll = long long;
  using ull = unsigned long long;

  constexpr static uint mod = mod_;

  uint v;
  ModInt() : v(0) {}
  ModInt(ll v) : v(normS(v % mod + mod)) {}
  explicit operator bool() const { return v != 0; }
  static uint normS(const uint &x) {
    return (x < mod) ? x : x - mod;
  } // [0 , 2*mod-1] -> [0 , mod-1]
  static ModInt make(const uint &x) {
    ModInt m;
    m.v = x;
    return m;
  }
  ModInt operator+(const ModInt &b) const { return make(normS(v + b.v)); }
  ModInt operator-(const ModInt &b) const { return make(normS(v + mod - b.v)); }
  ModInt operator-() const { return make(normS(mod - v)); }
  ModInt operator*(const ModInt &b) const { return make((ull)v * b.v % mod); }
  ModInt operator/(const ModInt &b) const { return *this * b.inv(); }
  ModInt &operator+=(const ModInt &b) { return *this = *this + b; }
  ModInt &operator-=(const ModInt &b) { return *this = *this - b; }
  ModInt &operator*=(const ModInt &b) { return *this = *this * b; }
  ModInt &operator/=(const ModInt &b) { return *this = *this / b; }
  ll extgcd(ll a, ll b, ll &x, ll &y) const {
    ll u[] = {a, 1, 0}, v[] = {b, 0, 1};
    while (*v) {
      ll t = *u / *v;
      rep(i, 3) swap(u[i] -= t * v[i], v[i]);
    }
    if (u[0] < 0)
      rep(i, 3) u[i] = -u[i];
    x = u[1], y = u[2];
    return u[0];
  }
  ModInt inv() const {
    ll x, y;
    extgcd(v, mod, x, y);
    return make(normS(x + mod));
  }
  bool operator==(const ModInt &b) const { return v == b.v; }
  bool operator!=(const ModInt &b) const { return v != b.v; }
  friend istream &operator>>(istream &o, ModInt &x) {
    ll tmp;
    o >> tmp;
    x = ModInt(tmp);
    return o;
  }
  friend ostream &operator<<(ostream &o, const ModInt &x) { return o << x.v; }
};
using mint = ModInt<1000000007>;

bool B(int x, int i) { return (x >> i) & 1; }

int N, M;
mint dp0[1 << 15], dp1[1 << 15];
mint p2[10000];
mint pinv2[10000];
int x[10000], y[10000];
int in[1 << 15];
int _in(int S) {
  int res = 0;
  rep(i, M) if (B(S, x[i]) && B(S, y[i])) res++;
  return res;
}
int cut(int S, int T) { return in[S + T] - in[S] - in[T]; }

int main() {
  p2[0] = 1;
  rep1(i, 9999) p2[i] = p2[i - 1] * 2;
  rep(i, 10000) pinv2[i] = mint(1) / p2[i];
  cin >> N >> M;
  rep(i, M) {
    cin >> x[i] >> y[i];
    x[i]--, y[i]--;
  }
  rep(S, 1 << N) in[S] = _in(S);
  rep(S, 1 << N) if (B(S, 0)) {
    dp0[S] = mint(1);
    for (int T = (S - 1) & S; T > 0; T = (T - 1) & S)
      if (B(T, 0)) {
        dp0[S] -= dp0[T] * pinv2[cut(T, S - T)];
      }
  }
  rep(S, 1 << N) if (B(S, 0)) { dp0[S] /= p2[cut(S, (1 << N) - 1 - S)]; }

  rep(S, 1 << N) if (B(S, 1)) {
    dp1[S] = mint(1);
    for (int T = (S - 1) & S; T > 0; T = (T - 1) & S)
      if (B(T, 1)) {
        dp1[S] -= dp1[T] * pinv2[cut(T, S - T)];
      }
  }
  rep(S, 1 << N) if (B(S, 1)) { dp1[S] /= p2[cut(S, (1 << N) - 1 - S)]; }

  mint ans = 1;
  rep(S, 1 << N) if (B(S, 0)) {
    int S2 = S;
    rep(i, M) {
      if (B(S, x[i]))
        S2 |= 1 << y[i];
      if (B(S, y[i]))
        S2 |= 1 << x[i];
    }
    int Tup = (1 << N) - 1 - S2;
    for (int T = Tup; T > 0; T = (T - 1) & Tup)
      if (B(T, 1)) {
        ans -= dp0[S] * dp1[T];
      }
  }
  ans *= p2[M];
  cout << ans << endl;
}


#include <bits/stdc++.h>

template <class T> inline void read(T &res) {
  char ch;
  while (ch = getchar(), !isdigit(ch))
    ;
  res = ch ^ 48;
  while (ch = getchar(), isdigit(ch))
    res = res * 10 + ch - 48;
}

const int N = 20;
const int M = 1005;
const int S = 1 << 15;
const int mod = 1e9 + 7;
int ex[M], f1[S], f2[S], cnt1[S], cnt2[S], g[S];
int n, m, id;
bool vis[N][N];

inline void add(int &x, int y) {
  x += y;
  x >= mod ? x -= mod : 0;
}

inline void dec(int &x, int y) {
  x -= y;
  x < 0 ? x += mod : 0;
}

int main() {
  read(n);
  read(m);
  read(id);
  ex[0] = 1;
  for (int i = 1, u, v; i <= m; ++i) {
    ex[i] = ex[i - 1];
    add(ex[i], ex[i - 1]);
    read(u);
    read(v);
    vis[u][v] = vis[v][u] = true;
  }
  const int C = (1 << n) - 1;
  for (int i = 1; i <= C; ++i)
    for (int j = 1; j <= n; ++j)
      if (1 << j - 1 & i)
        for (int k = j + 1; k <= n; ++k)
          if ((1 << k - 1 & i) && vis[j][k])
            ++cnt1[i];
  for (int i = 1; i <= C; ++i)
    for (int j = 1; j <= n; ++j)
      if (!(1 << j - 1 & i))
        for (int k = 1; k <= n; ++k)
          if ((1 << k - 1 & i) && vis[j][k])
            ++cnt2[i], g[i] |= 1 << j - 1;
  f1[1] = 1;
  for (int i = 2; i <= C; ++i)
    if (i & 1) {
      f1[i] = ex[cnt1[i]];
      for (int j = i - 1 & i; j; j = j - 1 & i)
        if (j & 1)
          dec(f1[i], 1ll * f1[j] * ex[cnt1[i ^ j]] % mod);
    }
  f2[2] = 1;
  for (int i = 3; i <= C; ++i)
    if (i >> 1 & 1) {
      f2[i] = ex[cnt1[i]];
      for (int j = i - 1 & i; j; j = j - 1 & i)
        if (j >> 1 & 1)
          dec(f2[i], 1ll * f2[j] * ex[cnt1[i ^ j]] % mod);
    }
  int ans = ex[m];
  for (int i = 1; i <= C; ++i)
    if (i & 1) {
      int ti = C ^ i ^ g[i];
      for (int j = ti; j; j = j - 1 & ti)
        if (j >> 1 & 1)
          dec(ans, 1ll * f1[i] * f2[j] % mod *
                       ex[m - cnt1[i] - cnt1[j] - cnt2[i] - cnt2[j]] % mod);
    }
  printf("%d\\n", ans);
  return 0;
}

#include <bits/stdc++.h>

template <class T> inline void read(T &res) {
  char ch;
  while (ch = getchar(), !isdigit(ch))
    ;
  res = ch ^ 48;
  while (ch = getchar(), isdigit(ch))
    res = res * 10 + ch - 48;
}

const int N = 20;
const int M = 1005;
const int S = 1 << 15;
const int mod = 1e9 + 7;
int ex[M], f1[S], f2[S], cnt1[S], cnt2[S], g[S];
int n, m, id;
bool vis[N][N];

inline void add(int &x, int y) {
  x += y;
  x >= mod ? x -= mod : 0;
}

inline void dec(int &x, int y) {
  x -= y;
  x < 0 ? x += mod : 0;
}

int main() {
  read(n);
  read(m);
  ex[0] = 1;
  for (int i = 1, u, v; i <= m; ++i) {
    ex[i] = ex[i - 1];
    add(ex[i], ex[i - 1]);
    read(u);
    read(v);
    vis[u][v] = vis[v][u] = true;
  }
  const int C = (1 << n) - 1;
  for (int i = 1; i <= C; ++i)
    for (int j = 1; j <= n; ++j)
      if (1 << j - 1 & i)
        for (int k = j + 1; k <= n; ++k)
          if ((1 << k - 1 & i) && vis[j][k])
            ++cnt1[i];
  for (int i = 1; i <= C; ++i)
    for (int j = 1; j <= n; ++j)
      if (!(1 << j - 1 & i))
        for (int k = 1; k <= n; ++k)
          if ((1 << k - 1 & i) && vis[j][k])
            ++cnt2[i], g[i] |= 1 << j - 1;
  f1[1] = 1;
  for (int i = 2; i <= C; ++i)
    if (i & 1) {
      f1[i] = ex[cnt1[i]];
      for (int j = i - 1 & i; j; j = j - 1 & i)
        if (j & 1)
          dec(f1[i], 1ll * f1[j] * ex[cnt1[i ^ j]] % mod);
    }
  f2[2] = 1;
  for (int i = 3; i <= C; ++i)
    if (i >> 1 & 1) {
      f2[i] = ex[cnt1[i]];
      for (int j = i - 1 & i; j; j = j - 1 & i)
        if (j >> 1 & 1)
          dec(f2[i], 1ll * f2[j] * ex[cnt1[i ^ j]] % mod);
    }
  int ans = ex[m];
  for (int i = 1; i <= C; ++i)
    if (i & 1) {
      int ti = C ^ i ^ g[i];
      for (int j = ti; j; j = j - 1 & ti)
        if (j >> 1 & 1)
          dec(ans, 1ll * f1[i] * f2[j] % mod *
                       ex[m - cnt1[i] - cnt1[j] - cnt2[i] - cnt2[j]] % mod);
    }
  printf("%d\\n", ans);
  return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fi first
#define se second
#define mp make_pair
#define pb push_back

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef unsigned long long ull;
typedef long double ld;
typedef tree<ii, null_type, less<ii>, rb_tree_tag,
             tree_order_statistics_node_update>
    pbds;

vector<int> fact;
vector<int> ifact;
vector<int> inv;
vector<int> pow2;
const int MOD = (1e9 + 7);
int add(int a, int b) {
  a += b;
  while (a >= MOD)
    a -= MOD;
  return a;
}
void radd(int &a, int b) { a = add(a, b); }
int mult(int a, int b) { return (a * 1LL * b) % MOD; }
void rmult(int &a, int b) { a = mult(a, b); }
int modpow(int a, int b) {
  int r = 1;
  while (b) {
    if (b & 1)
      r = mult(r, a);
    a = mult(a, a);
    b >>= 1;
  }
  return r;
}
int choose(int a, int b) {
  if (a < b)
    return 0;
  if (b == 0)
    return 1;
  if (a == b)
    return 1;
  return mult(fact[a], mult(ifact[b], ifact[a - b]));
}
int inverse(int a) { return modpow(a, MOD - 2); }
void init(int _n) {
  fact.clear();
  ifact.clear();
  inv.clear();
  pow2.clear();
  fact.resize(_n + 1);
  ifact.resize(_n + 1);
  inv.resize(_n + 1);
  pow2.resize(_n + 1);
  pow2[0] = 1;
  ifact[0] = 1;
  fact[0] = 1;
  for (int i = 1; i <= _n; i++) {
    pow2[i] = add(pow2[i - 1], pow2[i - 1]);
    fact[i] = mult(fact[i - 1], i);
    // ifact[i]=mult(ifact[i-1],inv[i]);
  }
  ifact[_n] = inverse(fact[_n]);
  for (int i = _n - 1; i >= 1; i--) {
    ifact[i] = mult(ifact[i + 1], i + 1);
  }
  for (int i = 1; i <= _n; i++) {
    inv[i] = mult(fact[i - 1], ifact[i]);
  }
}

int adj[18][18];
int dp[1700000];
int reach[2][(1 << 16)];
int n, m;
int p3[18];
int cntadj[15000000];

int solve(int u, int bit) {
  if (!(bit & (1 << u)))
    return 0;
  if (reach[u][bit] != -1)
    return reach[u][bit];
  int res = 1;
  vi V;
  for (int i = 0; i < n; i++) {
    if (bit & (1 << i))
      V.pb(i);
  }
  if (bit > 0) {
    for (int j = bit;; j = (bit & (j - 1))) {
      if (j == bit)
        continue;
      int coeff = 1;
      vi VV[2];
      int bb = 0;
      for (int x : V) {
        if (j & (1 << x))
          bb += p3[x]; // VV[1].pb(x);
        else
          bb += p3[x] * 2; // VV[0].pb(x);
      }
      coeff = inverse(pow2[cntadj[bb]]);
      radd(res, MOD - mult(coeff, solve(u, j)));
      if (j == 0)
        break;
    }
  }
  return (reach[u][bit] = res);
}

int V[18];
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  init(1201);
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    int u, v;
    cin >> u >> v;
    u--;
    v--;
    adj[u][v] = adj[v][u] = 1;
  }
  p3[0] = 1;
  for (int i = 1; i <= 17; i++)
    p3[i] = p3[i - 1] * 3;
  for (int i = 0; i < 2; i++) {
    memset(reach, -1, sizeof(reach));
    reach[i][(1 << i)] = 1;
  }
  int ans = 0;
  for (int i = 1; i < p3[n]; i++) {
    int cur = i;
    int exv = -1;
    int firstv = -1;
    for (int j = 0; j < n; j++) {
      V[j] = cur % 3;
      cur /= 3;
      if (V[j] != 0) {
        exv = j;
        firstv = V[j];
      }
    }
    cntadj[i] = cntadj[i - firstv * p3[exv]];
    for (int j = 0; j < n; j++) {
      if (V[j] != 0 && V[j] != firstv) {
        cntadj[i] += adj[exv][j];
      }
    }
    /*
    if(!V[1].empty())
    {
            cntadj[i]=cntadj[i-p3[V[1][0]]];
            for(int v:V[2])
            {
                    cntadj[i]+=adj[v][V[1][0]];
            }
    }
    else if(!V[2].empty())
    {
            cntadj[i]=cntadj[i-p3[V[2][0]]*2];
            for(int v:V[1])
            {
                    cntadj[i]+=adj[v][V[2][0]];
            }
    }
    */
    /*
    for(int x:V[1])
    {
            for(int y:V[2])
            {
                    cntadj[i]+=adj[x][y];
            }
    }
    */
    // if(i%100000==0) cerr<<"FINISH "<<i<<' '<<p3[n]<<'\\n';
  }
  // cerr<<"HALFWAY DONE"<<endl;
  for (int i = 0; i < p3[n - 2]; i++) {
    vi V[3];
    V[1].pb(0);
    V[2].pb(1);
    int cur = i;
    int b2 = 0;
    int b1 = 0;
    for (int j = 2; j < n; j++) {
      V[cur % 3].pb(j);
      cur /= 3;
    }
    for (int x : V[1])
      b1 |= (1 << x);
    for (int x : V[2])
      b2 |= (1 << x);
    int pos = 1;
    for (int x : V[1]) {
      for (int y : V[2]) {
        if (adj[x][y]) {
          pos = 0;
          break;
        }
      }
    }
    if (!pos)
      continue;
    int cnt_edge = 0;
    for (int x : V[0]) {
      for (int y : V[1])
        cnt_edge += adj[x][y];
      for (int y : V[2])
        cnt_edge += adj[x][y];
    }
    ans = add(ans, mult(pow2[m - cnt_edge], mult(solve(0, b1), solve(1, b2))));
  }
  ans = add(pow2[m], MOD - ans);
  cout << ans << '\\n';
}

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fi first
#define se second
#define mp make_pair
#define pb push_back

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef unsigned long long ull;
typedef long double ld;
typedef tree<ii, null_type, less<ii>, rb_tree_tag,
             tree_order_statistics_node_update>
    pbds;

vector<int> fact;
vector<int> ifact;
vector<int> inv;
vector<int> pow2;
const int MOD = (1e9 + 7);
int add(int a, int b) {
  a += b;
  while (a >= MOD)
    a -= MOD;
  return a;
}
void radd(int &a, int b) { a = add(a, b); }
int mult(int a, int b) { return (a * 1LL * b) % MOD; }
void rmult(int &a, int b) { a = mult(a, b); }
int modpow(int a, int b) {
  int r = 1;
  while (b) {
    if (b & 1)
      r = mult(r, a);
    a = mult(a, a);
    b >>= 1;
  }
  return r;
}
int choose(int a, int b) {
  if (a < b)
    return 0;
  if (b == 0)
    return 1;
  if (a == b)
    return 1;
  return mult(fact[a], mult(ifact[b], ifact[a - b]));
}
int inverse(int a) { return modpow(a, MOD - 2); }
void init(int _n) {
  fact.clear();
  ifact.clear();
  inv.clear();
  pow2.clear();
  fact.resize(_n + 1);
  ifact.resize(_n + 1);
  inv.resize(_n + 1);
  pow2.resize(_n + 1);
  pow2[0] = 1;
  ifact[0] = 1;
  fact[0] = 1;
  for (int i = 1; i <= _n; i++) {
    pow2[i] = add(pow2[i - 1], pow2[i - 1]);
    fact[i] = mult(fact[i - 1], i);
    // ifact[i]=mult(ifact[i-1],inv[i]);
  }
  ifact[_n] = inverse(fact[_n]);
  for (int i = _n - 1; i >= 1; i--) {
    ifact[i] = mult(ifact[i + 1], i + 1);
  }
  for (int i = 1; i <= _n; i++) {
    inv[i] = mult(fact[i - 1], ifact[i]);
  }
}

int ipow2[1111];

int adj[18][18];
int dp[1700000];
int reach[2][(1 << 16)];
int n, m;
int p3[18];
int cntadj[15000000];

int solve(int u, int bit) {
  if (!(bit & (1 << u)))
    return 0;
  if (reach[u][bit] != -1)
    return reach[u][bit];
  int res = 1;
  vi V;
  for (int i = 0; i < n; i++) {
    if (bit & (1 << i))
      V.pb(i);
  }
  if (bit > 0) {
    for (int j = bit;; j = (bit & (j - 1))) {
      if (j == bit)
        continue;
      int coeff = 1;
      int bb = 0;
      for (int x : V) {
        if (j & (1 << x))
          bb += p3[x]; // VV[1].pb(x);
        else
          bb += p3[x] * 2; // VV[0].pb(x);
      }
      coeff = ipow2[cntadj[bb]];
      radd(res, MOD - mult(coeff, solve(u, j)));
      if (j == 0)
        break;
    }
  }
  return (reach[u][bit] = res);
}

int V[18];
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  init(1201);
  for (int i = 0; i <= 1000; i++)
    ipow2[i] = inverse(pow2[i]);
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    int u, v;
    cin >> u >> v;
    u--;
    v--;
    adj[u][v] = adj[v][u] = 1;
  }
  p3[0] = 1;
  for (int i = 1; i <= 17; i++)
    p3[i] = p3[i - 1] * 3;
  for (int i = 0; i < 2; i++) {
    memset(reach, -1, sizeof(reach));
    reach[i][(1 << i)] = 1;
  }
  int ans = 0;
  for (int i = 1; i < p3[n]; i++) {
    int cur = i;
    int exv = -1;
    int firstv = -1;
    for (int j = 0; j < n; j++) {
      V[j] = cur % 3;
      cur /= 3;
      if (V[j] != 0) {
        exv = j;
        firstv = V[j];
      }
    }
    cntadj[i] = cntadj[i - firstv * p3[exv]];
    for (int j = 0; j < n; j++) {
      if (V[j] != 0 && V[j] != firstv) {
        cntadj[i] += adj[exv][j];
      }
    }
    // if(i%100000==0) cerr<<"FINISH "<<i<<' '<<p3[n]<<'\\n';
  }
  // cerr<<"HALFWAY DONE"<<endl;
  for (int i = 0; i < p3[n - 2]; i++) {
    V[0] = 1;
    V[1] = 2;
    int cur = i;
    int b2 = 2;
    int b1 = 1;
    for (int j = 2; j < n; j++) {
      V[j] = cur % 3;
      if (V[j] == 1)
        b1 |= (1 << j);
      if (V[j] == 2)
        b2 |= (1 << j);
      cur /= 3;
    }
    int bb = 0;
    for (int j = 0; j < n; j++) {
      if (b1 & (1 << j))
        bb += p3[j];
      if (b2 & (1 << j))
        bb += 2 * p3[j];
    }
    if (cntadj[bb] > 0)
      continue;
    bb = 0;
    for (int j = 0; j < n; j++) {
      if (b1 & (1 << j))
        bb += p3[j];
      else if (b2 & (1 << j))
        bb += p3[j];
      else
        bb += 2 * p3[j];
    }
    /*
    for(int x:V[0])
    {
            for(int y:V[1]) cnt_edge+=adj[x][y];
            for(int y:V[2]) cnt_edge+=adj[x][y];
    }
    */
    int cnt_edge = cntadj[bb];
    ans = add(ans, mult(pow2[m - cnt_edge], mult(solve(0, b1), solve(1, b2))));
  }
  ans = add(pow2[m], MOD - ans);
  cout << ans << '\\n';
}


#include <bits/stdc++.h>
#define ll long long
#define rg register
using namespace std;
const int MAXN = 35000;
const int Mod = 1e9 + 7;
struct gao {
  int u, v, Next;
} Edge[MAXN];
int Ans, Meet, n, m, Es = 1, First[MAXN], Ban[MAXN];
int Vis[MAXN];
inline void Link(rg int u, rg int v) {
  Edge[++Es] = (gao){u, v, First[u]}, First[u] = Es;
}
inline void Dfs(rg int Now, rg int Mark) {
  if (Mark == 2 && Vis[Now] == 1)
    Meet = 1;
  Vis[Now] = Mark;
  for (rg int i = First[Now]; i != -1; i = Edge[i].Next)
    if (Vis[Edge[i].v] != Vis[Now] && !Ban[i])
      Dfs(Edge[i].v, Mark);
}
inline void Check() {
  for (rg int i = 1; i <= n; i++)
    Vis[i] = 0;
  Meet = 0, Dfs(1, 1), Dfs(2, 2), Ans += Meet;
}
inline int Dfs(rg int Now) {
  if (Now > m * 2)
    return Check(), 0;
  Ban[Now] = 0, Ban[Now ^ 1] = 1, Dfs(Now + 2), Ban[Now] = 1, Ban[Now ^ 1] = 0,
  Dfs(Now + 2);
}
int main() {
  scanf("%d%d", &n, &m);
  memset(First, -1, sizeof(First));
  for (rg int i = 1, u, v; i <= m; i++)
    scanf("%d%d", &u, &v), Link(u, v), Link(v, u);
  Dfs(2), printf("%d\\n", Ans);
}

#include <bits/stdc++.h>
#define ll long long
#define rg register
using namespace std;
const int MAXN = 35000;
const int Mod = 1e9 + 7;
struct gao {
  int A, B;
} Edge[MAXN];
int Ans, End, n, m, Two[MAXN] = {1}, A[MAXN], B[MAXN], F[3][MAXN];
int main() {
  scanf("%d%d", &n, &m), End = (1 << n) - 1;
  for (rg int i = 1; i <= m; i++)
    scanf("%d%d", &Edge[i].A, &Edge[i].B);
  for (rg int i = 1; i <= m; i++)
    Two[i] = (Two[i - 1] << 1) % Mod;
  for (rg int i = 1; i <= End; i++)
    for (rg int j = 1; j <= m; j++) {
      if ((i & (1 << (Edge[j].A - 1))) && (i & (1 << (Edge[j].B - 1))))
        A[i]++;
      if ((i & (1 << (Edge[j].A - 1))) || (i & (1 << (Edge[j].B - 1))))
        B[i]++;
    }
  for (rg int S = 1; S <= End; S++) {
    F[1][S] = Two[A[S]] * (S & 1), F[2][S] = Two[A[S]] * (S >> 1 & 1);
    for (rg int T = (S - 1) & S; T; T = (T - 1) & S) {
      if (T & 1)
        F[1][S] = (F[1][S] - 1ll * F[1][T] * Two[A[S ^ T]]) % Mod;
      if (T & 2)
        F[2][S] = (F[2][S] - 1ll * F[2][T] * Two[A[S ^ T]]) % Mod;
    }
  }
  for (rg int S = 1; S <= End; S++)
    for (rg int T = (End ^ S); T; T = (T - 1) & (End ^ S)) {
      if (A[S] + A[T] != A[S | T] || ~S & 1 || ~T & 2)
        continue;
      Ans = (Ans - 1ll * F[1][S] * F[2][T] % Mod * Two[A[End ^ S ^ T]]) % Mod;
    }
  printf("%lld\\n", (1ll * Ans + Two[m] + Mod) % Mod);
}


#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#pragma warning(disable : 4996)
#pragma comment(linker, "/STACK:336777216")
using namespace std;

#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define ldb ldouble

typedef tuple<int, int, int> t3;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<db, db> pdd;

int IT_MAX = 1 << 18;
int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const db PI = acos(-1);
const db ERR = 1e-10;
#define szz(x) (int)(x).size()
#define rep(i, n) for (int i = 0; i < n; i++)
#define Se second
#define Fi first

const int DEB = 0;
const int MX = DEB ? 1 << 5 : 1 << 15;
const int MM = 1000000007;

int A[MX], B[MX];

int G[15][15];
int pw2[MX];
int N, M;

void solve(int c, int A[MX]) {
  for (int t = 0; t < MX; t++) {
    if (~t & c)
      continue;
    int cnt = 0;
    for (int i = 0; i < N; i++) {
      for (int j = 0; j < N; j++) {
        if (t & 1 << i && t & 1 << j)
          cnt += G[i][j];
      }
    }
    A[t] = pw2[cnt];
    for (int u = t; u; u = (u - 1) & t) {
      if (~u & c || u == t)
        continue;
      int v = t ^ u, cnt = 0;
      for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
          if (v & 1 << i && v & 1 << j)
            cnt += G[i][j];
        }
      }
      A[t] = (A[t] - (ll)pw2[cnt] * A[u] % MM + MM) % MM;
    }
  }
}

int main() {
  pw2[0] = 1;
  for (int i = 1; i < MX; i++)
    pw2[i] = pw2[i - 1] * 2 % MM;
  scanf("%d%d", &N, &M);
  for (int i = 1; i <= M; i++) {
    int a, b;
    scanf("%d%d", &a, &b);
    a--, b--;
    G[a][b] = 1;
  }
  if (G[0][1] || G[1][0])
    return !printf("%d\\n", pw2[M]);
  solve(1, A);
  solve(2, B);

  ll ans = 0;
  for (int i = 0; i < MX; i++) {
    for (int j = i; j; j = (j - 1) & i) {
      int p = j, q = i ^ j, r = (MX - 1) ^ i;
      if (~p & 1 || ~q & 2)
        continue;
      int cnt = 0, tp = 1;
      for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
          if (r & 1 << i && r & 1 << j)
            cnt += G[i][j];
          if (p & 1 << i && q & 1 << j && (G[i][j] || G[j][i]))
            tp = 0;
        }
      }
      ans = (ans + (ll)tp * pw2[cnt] * A[p] % MM * B[q]) % MM;
    }
  }
  printf("%lld\\n", (pw2[M] - ans + MM) % MM);
}

#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#pragma warning(disable : 4996)
#pragma comment(linker, "/STACK:336777216")
using namespace std;

#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define ldb ldouble

typedef tuple<int, int, int> t3;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<db, db> pdd;

int IT_MAX = 1 << 18;
int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const db PI = acos(-1);
const db ERR = 1e-10;
#define szz(x) (int)(x).size()
#define rep(i, n) for (int i = 0; i < n; i++)
#define Se second
#define Fi first

const int DEB = 0;
const int MX = DEB ? 1 << 5 : 1 << 15;
const int MM = 1000000007;

int A[MX], B[MX];

int G[15][15];
int tmp[MX];
int pw2[MX];
int N, M;

void solve(int c, int A[MX]) {
  for (int t = 0; t < MX; t++) {
    if (~t & c)
      continue;
    int cnt = tmp[t];
    A[t] = pw2[cnt];
    for (int u = t; u; u = (u - 1) & t) {
      if (~u & c || u == t)
        continue;
      int v = t ^ u, cnt = tmp[v];
      A[t] = (A[t] - (ll)pw2[cnt] * A[u] % MM + MM) % MM;
    }
  }
}

int main() {
  pw2[0] = 1;
  for (int i = 1; i < MX; i++)
    pw2[i] = pw2[i - 1] * 2 % MM;
  scanf("%d%d", &N, &M);
  for (int i = 1; i <= M; i++) {
    int a, b;
    scanf("%d%d", &a, &b);
    a--, b--;
    G[a][b] = 1;
  }
  if (G[0][1] || G[1][0])
    return !printf("%d\\n", pw2[M]);
  for (int m = 1; m < MX; m++) {
    for (int i = 0; i < N; i++) {
      for (int j = 0; j < N; j++) {
        if (m & 1 << i && m & 1 << j)
          tmp[m] += G[i][j];
      }
    }
  }
  solve(1, A);
  solve(2, B);

  ll ans = 0;
  for (int i = 0; i < MX; i++) {
    for (int j = i; j; j = (j - 1) & i) {
      int p = j, q = i ^ j, r = (MX - 1) ^ i;
      if (~p & 1 || ~q & 2)
        continue;
      int cnt = 0, tp = 1;
      for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
          if (r & 1 << i && r & 1 << j)
            cnt += G[i][j];
          if (p & 1 << i && q & 1 << j && (G[i][j] || G[j][i]))
            tp = 0;
        }
      }
      ans = (ans + (ll)tp * pw2[cnt] * A[p] % MM * B[q]) % MM;
    }
  }
  printf("%lld\\n", (pw2[M] - ans + MM) % MM);
}