3 5
2 1 608591421 720962564
3 2 608591421 641991574
3 2 718110706 353409763
2 3 482786015 858341723
3 2 825397574 357507279
 2 1
2 1 317425595 636156322
 50000 1
20845 28516 904146168 997637433

Yes
641991574 1
2 
 Yes
0 0

 Yes
0 0


#include <bits/stdc++.h>
using namespace std;
int n, m;
struct EDGE {
  int x, y, c, t;
  void read() { scanf("%d%d%d%d", &x, &y, &c, &t); }
  bool operator<(const EDGE &p) const { return c < p.c; }
} edge[50010];
struct CC {
  vector<int> vD, vE;
  int c;
};
vector<CC *> chain, cycle;
int vis[50010], d[50010];
vector<int> e[50010];
void dfs(int u, int from, vector<int> &vecD, vector<int> &vecE) {
  vis[u] = 1;
  vecD.push_back(u);
  for (int i = 0; i < e[u].size(); ++i)
    if (e[u][i] != from) {
      int v = edge[e[u][i]].x == u ? edge[e[u][i]].y : edge[e[u][i]].x;
      vecE.push_back(e[u][i]);
      if (vis[v]) return;
      dfs(v, e[u][i], vecD, vecE);
      break;
    }
}
bool gao() {
  vector<int> p;
  p.clear();
  for (int i = 1; i < 1 + n; ++i) {
    if (d[i] > 2) return 0;
    if (d[i]) p.push_back(i);
  }
  int N = p.size();
  int u, v;
  for (int i = 0; i < N; ++i) vis[p[i]] = 0;
  for (int i = 0; i < N; ++i)
    if (d[u = p[i]] == 1) {
      if (vis[u]) continue;
      CC *cc = new CC();
      cc->c = edge[e[u][0]].c;
      dfs(u, -1, cc->vD, cc->vE);
      chain.push_back(cc);
    }
  for (int i = 0; i < N; ++i)
    if (!vis[u = p[i]]) {
      CC *cc = new CC();
      cc->c = edge[e[u][0]].c;
      dfs(u, -1, cc->vD, cc->vE);
      cycle.push_back(cc);
    }
  return 1;
}
vector<int> ans;
int col[50010];
bool zaigao() {
  for (int i = 0; i < chain.size(); ++i) {
    CC *cc = chain[i];
    vector<int> &v = cc->vD;
    for (int j = 1; j < v.size() - 1; ++j) {
      if (col[v[j]]) return 0;
      col[v[j]] = cc->c;
    }
  }
  for (int i = 0; i < cycle.size(); ++i) {
    CC *cc = cycle[i];
    vector<int> &v = cc->vD;
    for (int j = 0; j < v.size(); ++j) {
      if (col[v[j]]) return 0;
      col[v[j]] = cc->c;
    }
  }
  for (int i = 0; i < chain.size(); ++i) {
    CC *cc = chain[i];
    vector<int> &v = cc->vD;
    vector<int> &ve = cc->vE;
    assert(v.size() == ve.size() + 1);
    if (v.size() <= 2) continue;
    int l = 0, r = ve.size();
    bool lef = (col[v[0]] == 0), rig = (col[v.back()] == 0);
    if (lef && rig) {
      int d1 = 0, d2 = 0;
      for (int j = 0; j < r; ++j) d1 = max(d1, edge[ve[j]].t);
      for (int j = 1; j < r; ++j) d2 = max(d2, edge[ve[j]].t);
      if (d1 < d2) {
        for (int j = 0; j < r; ++j) ans.push_back(ve[j]);
      } else {
        for (int j = 1; j < r; ++j) ans.push_back(ve[j]);
      }
    } else if (lef) {
      for (int j = 1; j < r; ++j) ans.push_back(ve[j]);
    } else if (rig) {
      for (int j = r - 2; j >= 0; --j) ans.push_back(ve[j]);
    } else {
      if (r & 1) return 0;
      for (int j = 1; j < r; ++j) ans.push_back(ve[j]);
    }
  }
  for (int i = 0; i < cycle.size(); ++i) {
    CC *cc = cycle[i];
    vector<int> &v = cc->vD;
    vector<int> &ve = cc->vE;
    assert(v.size() == ve.size());
    int r = ve.size();
    int d1 = 0, d2 = 0;
    for (int j = 0; j < r; ++j) d1 = max(d1, edge[ve[j]].t);
    for (int j = 1; j < r; ++j) d2 = max(d2, edge[ve[j]].t);
    if (d1 < d2) {
      for (int j = 0; j < r; ++j) ans.push_back(ve[j]);
    } else {
      for (int j = 1; j < r; ++j) ans.push_back(ve[j]);
    }
  }
  return 1;
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 0; i < m; ++i) {
    edge[i].read();
  }
  sort(edge, edge + m);
  for (int l = 0, r = 0; l < m;) {
    for (; r < m && edge[r].c == edge[l].c; ++r)
      ;
    for (int i = 1; i < 1 + n; ++i) e[i].clear(), d[i] = 0;
    for (int i = l; i < r; ++i) {
      e[edge[i].x].push_back(i);
      d[edge[i].x]++;
      e[edge[i].y].push_back(i);
      d[edge[i].y]++;
    }
    if (!gao()) {
      printf("No");
      return 0;
    }
    l = r;
  }
  if (!zaigao()) {
    puts("No");
    return 0;
  }
  puts("Yes");
  for (int i = 0; i < ans.size(); ++i) {
    printf("%d %d\n", edge[ans[i]].x, edge[ans[i]].y);
  }
}
