Problem: In the galaxy far far away is the ancient interplanetary republic of Bubbleland, consisting of N planets. Between them, there are M bidirectional wormholes, each connecting a pair of planets. Bubbleland is a very centralized republic, having a capital planet Whiteplanet, from which any another planet can be reached using these wormholes. It is also guaranteed that no wormhole connects planet to itself and that no two different wormholes connect same pair of planets. 

We call a path that begins at one planet, visits other planets and each of them at most once and returns to starting point a tour. Interplanetary Safety Regulations guarantee that each planet belongs to at most one tour and that there are at most 42 tours.

After many eons of usage, wormholes need to be repaired and each wormhole has the cost W_{i} which needs to be payed for reparation. Unfortunately, the Senate of Bubbleland is short on budget. Therefore, they have decided only to fix as many wormholes as they need in order to have all planets reachable from capital and to pay as little money as they have to for this repair. However the way in which the Senate calculates the cost is different. Cost of the set of reparations is binary xor of costs of each individual reparation, that is if reparations to be made have costs A_{1},A_{2},...,A_{k}, the cost of entire set is A_{1} ⊕ A_{2} ⊕ ... ⊕ A_{k}.

Now the Senate would like to know how much money do they have to pay and also the number of different ways to achieve that cost modulo 1000000007.

Input

First line of input contains two numbers N (1 ≤ N ≤ 100.000), the number of planets and M (1 ≤ M ≤ 100.041), the number of wormholes. Following M lines contain three numbers U, V (1 ≤ U ≠ V ≤ N) and W (1 ≤ W ≤ 100.000), meaning that there exists a wormhole connecting planets U and V, with repair cost of W.

Output

Output two numbers, the smallest possible cost of entire reparation and the number of different valid reparations with that cost modulo 1000000007.

Example

Input


6 6
4 1 5
5 2 1
6 3 2
1 2 6
1 3 3
2 3 4


Output


1 1

Note

We can repair wormholes 1,2,3,5 and 6, paying 5 ⊕ 1⊕ 2 ⊕ 3 ⊕ 4=1, one can check that this is the cheapest repair in which all of the planets are connected and the only valid repair with that cost.

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  os << '{';
  string sep;
  for (const auto &x : v) os << sep << x, sep = ", ";
  return os << '}';
}
template <typename A, typename B>
ostream &operator<<(ostream &os, const pair<A, B> &p) {
  return os << '(' << p.first << ", " << p.second << ')';
}
void dbg_out() { cerr << endl; }
template <typename Head, typename... Tail>
void dbg_out(Head H, Tail... T) {
  cerr << ' ' << H;
  dbg_out(T...);
}
namespace IO {
const int BUFFER_SIZE = 1 << 15;
char input_buffer[BUFFER_SIZE];
int input_pos = 0, input_len = 0;
void _update_input_buffer() {
  input_len = fread(input_buffer, sizeof(char), BUFFER_SIZE, stdin);
  input_pos = 0;
  if (input_len == 0) input_buffer[0] = EOF;
}
inline char next_char(bool advance = true) {
  if (input_pos >= input_len) _update_input_buffer();
  return input_buffer[advance ? input_pos++ : input_pos];
}
template <typename T>
inline void read_int(T &number) {
  bool negative = false;
  number = 0;
  while (!isdigit(next_char(false)))
    if (next_char() == '-') negative = true;
  do {
    number = 10 * number + (next_char() - '0');
  } while (isdigit(next_char(false)));
  if (negative) number = -number;
}
template <typename T, typename... Args>
inline void read_int(T &number, Args &...args) {
  read_int(number);
  read_int(args...);
}
}  // namespace IO
template <const int &MOD>
struct _m_int {
  int val;
  _m_int(int64_t v = 0) {
    if (v < 0) v = v % MOD + MOD;
    if (v >= MOD) v %= MOD;
    val = v;
  }
  static int inv_mod(int a, int m = MOD) {
    int g = m, r = a, x = 0, y = 1;
    while (r != 0) {
      int q = g / r;
      g %= r;
      swap(g, r);
      x -= q * y;
      swap(x, y);
    }
    return x < 0 ? x + m : x;
  }
  explicit operator int() const { return val; }
  explicit operator int64_t() const { return val; }
  _m_int &operator+=(const _m_int &other) {
    val -= MOD - other.val;
    if (val < 0) val += MOD;
    return *this;
  }
  _m_int &operator-=(const _m_int &other) {
    val -= other.val;
    if (val < 0) val += MOD;
    return *this;
  }
  static unsigned fast_mod(uint64_t x, unsigned m = MOD) {
    return x % m;
    unsigned x_high = x >> 32, x_low = (unsigned)x;
    unsigned quot, rem;
    asm("divl %4\n" : "=a"(quot), "=d"(rem) : "d"(x_high), "a"(x_low), "r"(m));
    return rem;
  }
  _m_int &operator*=(const _m_int &other) {
    val = fast_mod((uint64_t)val * other.val);
    return *this;
  }
  _m_int &operator/=(const _m_int &other) { return *this *= other.inv(); }
  friend _m_int operator+(const _m_int &a, const _m_int &b) {
    return _m_int(a) += b;
  }
  friend _m_int operator-(const _m_int &a, const _m_int &b) {
    return _m_int(a) -= b;
  }
  friend _m_int operator*(const _m_int &a, const _m_int &b) {
    return _m_int(a) *= b;
  }
  friend _m_int operator/(const _m_int &a, const _m_int &b) {
    return _m_int(a) /= b;
  }
  _m_int &operator++() {
    val = val == MOD - 1 ? 0 : val + 1;
    return *this;
  }
  _m_int &operator--() {
    val = val == 0 ? MOD - 1 : val - 1;
    return *this;
  }
  _m_int operator++(int) {
    _m_int before = *this;
    ++*this;
    return before;
  }
  _m_int operator--(int) {
    _m_int before = *this;
    --*this;
    return before;
  }
  _m_int operator-() const { return val == 0 ? 0 : MOD - val; }
  bool operator==(const _m_int &other) const { return val == other.val; }
  bool operator!=(const _m_int &other) const { return val != other.val; }
  _m_int inv() const { return inv_mod(val); }
  _m_int pow(int64_t p) const {
    if (p < 0) return inv().pow(-p);
    _m_int a = *this, result = 1;
    while (p > 0) {
      if (p & 1) result *= a;
      a *= a;
      p >>= 1;
    }
    return result;
  }
  friend ostream &operator<<(ostream &os, const _m_int &m) {
    return os << m.val;
  }
};
extern const int MOD = 1e9 + 7;
using mod_int = _m_int<MOD>;
extern const int CHECK_MOD = 2014437851;
using check_int = _m_int<CHECK_MOD>;
namespace walsh_hadamard {
bool is_power_of_two(int n) { return (n & (n - 1)) == 0; }
int round_up_power_two(int n) {
  while (n & (n - 1)) n = (n | (n - 1)) + 1;
  return max(n, 1);
}
template <typename T>
typename enable_if<is_integral<T>::value>::type divide_all(int n,
                                                           vector<T> &values) {
  for (int i = 0; i < n; i++) values[i] >>= __builtin_ctz(n);
}
template <typename T>
typename enable_if<!is_integral<T>::value>::type divide_all(int n,
                                                            vector<T> &values) {
  T inv_n = T(1) / n;
  for (int i = 0; i < n; i++) values[i] *= inv_n;
}
template <typename T>
void fwht_xor(int n, vector<T> &values, bool inverse = false) {
  assert(is_power_of_two(n));
  assert((int)values.size() >= n);
  for (int len = 1; len < n; len *= 2)
    for (int start = 0; start < n; start += 2 * len)
      for (int i = start; i < start + len; i++) {
        T u = values[i];
        const T &v = values[i + len];
        values[i] = u + v;
        values[i + len] = u - v;
      }
  if (inverse) divide_all(n, values);
}
template <typename T_out, typename T_in>
vector<T_out> xor_convolution(const vector<T_in> &_left,
                              const vector<T_in> &_right) {
  if (_left.empty() || _right.empty()) return {};
  vector<T_out> left(_left.begin(), _left.end());
  vector<T_out> right(_right.begin(), _right.end());
  int n = left.size();
  int m = right.size();
  int N = round_up_power_two(max(n, m));
  left.resize(N, 0);
  right.resize(N, 0);
  if (left == right) {
    fwht_xor(N, left);
    right = left;
  } else {
    fwht_xor(N, left);
    fwht_xor(N, right);
  }
  for (int i = 0; i < N; i++) left[i] *= right[i];
  fwht_xor(N, left, true);
  return left;
}
}  // namespace walsh_hadamard
const int BITS = 17;
struct edge {
  int node, weight;
  edge() {}
  edge(int _node, int _weight) : node(_node), weight(_weight) {}
};
int N, M;
vector<vector<edge>> adj;
vector<bool> visited;
vector<int> parent;
vector<int> depth;
vector<int> up_weight;
vector<vector<int>> cycles;
void dfs(int node, int par, int weight) {
  assert(!visited[node]);
  visited[node] = true;
  parent[node] = par;
  depth[node] = par < 0 ? 0 : depth[par] + 1;
  up_weight[node] = weight;
  for (edge &e : adj[node]) {
    if (e.node == par) continue;
    if (!visited[e.node]) {
      dfs(e.node, node, e.weight);
    } else if (depth[e.node] < depth[node]) {
      vector<int> cycle = {e.weight};
      int x = node;
      while (x != e.node) {
        cycle.push_back(up_weight[x]);
        x = parent[x];
      }
      cycles.push_back(cycle);
    }
  }
}
int main() {
  IO::read_int(N, M);
  adj.assign(N, {});
  int all_xor = 0;
  for (int i = 0; i < M; i++) {
    int u, v, weight;
    IO::read_int(u, v, weight);
    u--;
    v--;
    adj[u].emplace_back(v, weight);
    adj[v].emplace_back(u, weight);
    all_xor ^= weight;
  }
  visited.assign(N, false);
  parent.assign(N, -1);
  depth.assign(N, -1);
  up_weight.assign(N, -1);
  dfs(0, -1, 0);
  vector<mod_int> ways(1 << BITS, 0);
  ways[0] = 1;
  walsh_hadamard::fwht_xor(1 << BITS, ways);
  vector<check_int> check_ways(1 << BITS, 0);
  check_ways[0] = 1;
  walsh_hadamard::fwht_xor(1 << BITS, check_ways);
  for (vector<int> &cycle : cycles) {
    vector<mod_int> freq(1 << BITS, 0);
    vector<check_int> check_freq(1 << BITS, 0);
    for (int weight : cycle) {
      freq[weight]++;
      check_freq[weight]++;
    }
    walsh_hadamard::fwht_xor(1 << BITS, freq);
    walsh_hadamard::fwht_xor(1 << BITS, check_freq);
    for (int i = 0; i < 1 << BITS; i++) {
      ways[i] *= freq[i];
      check_ways[i] *= check_freq[i];
    }
  }
  walsh_hadamard::fwht_xor(1 << BITS, ways, true);
  walsh_hadamard::fwht_xor(1 << BITS, check_ways, true);
  int best = 1 << BITS;
  mod_int best_count = 0;
  for (int option = 0; option < 1 << BITS; option++)
    if ((ways[option] != 0 || check_ways[option] != 0) &&
        (option ^ all_xor) < best) {
      best = option ^ all_xor;
      best_count = ways[option];
    }
  cout << best << ' ' << best_count << '\n';
}