Duff is one if the heads of Mafia in her country, Andarz Gu. Andarz Gu has n cities (numbered from 1 to n) connected by m bidirectional roads (numbered by 1 to m).

Each road has a destructing time, and a color. i-th road connects cities vi and ui and its color is ci and its destructing time is ti.

Mafia wants to destruct a matching in Andarz Gu. A matching is a subset of roads such that no two roads in this subset has common endpoint. They can destruct these roads in parallel, i. e. the total destruction time is a maximum over destruction times of all selected roads.

<image>

They want two conditions to be satisfied:

  1. The remaining roads form a proper coloring. 
  2. Destructing time of this matching is minimized. 



The remaining roads after destructing this matching form a proper coloring if and only if no two roads of the same color have same endpoint, or, in the other words, edges of each color should form a matching.

There is no programmer in Mafia. That's why Duff asked for your help. Please help her and determine which matching to destruct in order to satisfied those conditions (or state that this is not possible).

Input

The first line of input contains two integers n and m (2 ≤ n ≤ 5 × 104 and 1 ≤ m ≤ 5 × 104), number of cities and number of roads in the country.

The next m lines contain the the roads. i - th of them contains four integers vi, ui, ci and ti (1 ≤ vi, ui ≤ n, vi ≠ ui and 1 ≤ ci, ti ≤ 109 for each 1 ≤ i ≤ m).

Output

In the first line of input, print "Yes" (without quotes) if satisfying the first condition is possible and "No" (without quotes) otherwise.

If it is possible, then you have to print two integers t and k in the second line, the minimum destructing time and the number of roads in the matching (<image>).

In the third line print k distinct integers separated by spaces, indices of the roads in the matching in any order. Roads are numbered starting from one in order of their appearance in the input.

If there's more than one solution, print any of them.

Examples

Input

5 7
2 1 3 7
3 1 1 6
5 4 1 8
4 5 1 1
3 2 2 3
4 5 2 5
2 3 2 4


Output

Yes
3 2
4 5


Input

3 5
3 2 1 3
1 3 1 1
3 2 1 4
1 3 2 2
1 3 2 10


Output

No

Note

Graph of Andarz Gu in the first sample case is as follows:

<image>

A solution would be to destruct the roads with crosses.

Graph of Andarz Gu in the second sample case is as follows:

<image>
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
const int mod = 1e9 + 7;
struct edge {
  int u, v, t, c, id;
} e[N];
int n, m;
vector<edge> s[N];
bool cmp(edge a, edge b) { return a.c < b.c; }
struct TwoSat {
  static const int N = ::N << 1;
  int dfn[N], low[N], id[N], st[N], _st, _, cc;
  vector<int> g[N];
  int mark[N], n;
  void init(int _n) {
    for (int i = ((n = _n << 1)) - 1; i >= (0); --i) g[i].clear();
  }
  int new_node() {
    for (int i = (0); i < (2); i++) g[n++].clear();
    return n / 2 - 1;
  }
  void addedge(int a, int va, int b, int vb) {
    a = a << 1 | va;
    b = b << 1 | vb;
    g[a].push_back(b);
    g[b ^ 1].push_back(a ^ 1);
  }
  void add_set(int a, int va) {
    a = a << 1 | va;
    g[a ^ 1].push_back(a);
  }
  void add_then(int a, int va, int b, int vb) { addedge(a, va, b, vb ^ 1); }
  void add_or(int a, int va, int b, int vb) { addedge(a, va ^ 1, b, vb); }
  void add_xor(int a, int va, int b, int vb) {
    addedge(a, va, b, vb);
    addedge(b, vb, a, va);
  }
  void dfs(int c, vector<int> g[]) {
    dfn[c] = low[c] = ++cc;
    st[_st++] = c;
    for (auto t : g[c])
      if (!dfn[t])
        dfs(t, g), low[c] = min(low[c], low[t]);
      else if (!id[t])
        low[c] = min(low[c], dfn[t]);
    if (low[c] == dfn[c]) {
      ++_;
      do {
        id[st[--_st]] = _;
      } while (st[_st] != c);
    }
  }
  void find() {
    fill_n(dfn, n, cc = 0);
    fill_n(low, n, _st = 0);
    fill_n(id, n, _ = 0);
    for (int i = (0); i < (n); i++)
      if (!dfn[i]) dfs(i, g);
    for (int i = (0); i < (n); i++) --id[i];
    return;
  }
  bool solve() {
    find();
    for (int i = 0; i < n; i += 2) {
      if (id[i] == id[i + 1]) return 0;
      mark[i >> 1] = (id[i] > id[i + 1]);
    }
    return 1;
  }
} ts;
int p = 0;
void solve(int u) {
  sort(s[u].begin(), s[u].end(), cmp);
  for (int i = 0, j; i < (int)s[u].size();) {
    j = i;
    while (j < (int)s[u].size() && s[u][j].c == s[u][i].c) j++;
    if (j - i >= 3) {
      cout << "No\n";
      exit(0);
    }
    if (j - i == 2) {
      int x = s[u][i].id, y = s[u][i + 1].id;
      ts.add_or(x, 0, y, 0);
    }
    i = j;
  }
  for (int i = (0); i < ((int)s[u].size() - 1); i++) {
    ts.addedge(p + i + 1, 0, p + i, 0);
  }
  for (int i = (0); i < ((int)s[u].size()); i++) {
    int x = s[u][i].id;
    ts.addedge(x, 0, p + i, 0);
    if (i != (int)s[u].size() - 1) ts.addedge(x, 0, p + i + 1, 1);
  }
}
void link() {
  p = m;
  for (int i = (1); i < (n + 1); i++) {
    solve(i);
    p += (int)s[i].size();
  }
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cin >> n >> m;
  int L = 0, R = 0;
  for (int i = (1); i < (m + 1); i++) {
    cin >> e[i].u >> e[i].v >> e[i].c >> e[i].t;
    e[i].id = i - 1;
    R = max(R, e[i].t);
    s[e[i].u].push_back(e[i]);
    s[e[i].v].push_back(e[i]);
  }
  int ans = -1;
  while (L <= R) {
    int mid = (L + R) / 2;
    ts.init(3 * m);
    link();
    for (int i = (1); i < (m + 1); i++)
      if (e[i].t > mid) {
        ts.add_set(e[i].id, 1);
      }
    if (ts.solve()) {
      ans = mid;
      R = mid - 1;
    } else
      L = mid + 1;
  }
  if (ans == -1)
    cout << "No";
  else {
    ts.init(3 * m);
    link();
    for (int i = (1); i < (m + 1); i++)
      if (e[i].t > ans) ts.add_set(e[i].id, 1);
    ts.solve();
    cout << "Yes\n";
    vector<int> task;
    for (int i = 0; i < m; ++i)
      if (!ts.mark[i]) task.push_back(i + 1);
    cout << ans << " " << (int)task.size() << "\n";
    for (auto v : task) cout << v << " ";
  }
  return 0;
}
