#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline bool checkmin(T &a, const T &b) {
  return a > b ? a = b, 1 : 0;
}
template <typename T>
inline bool checkmax(T &a, const T &b) {
  return a < b ? a = b, 1 : 0;
}
const int MAXN = 100000 + 10;
struct edge {
  int v, opp;
  bool used;
  edge(int _v, int _opp) : v(_v), opp(_opp), used(false) {}
};
vector<edge> adj[MAXN];
int dfn[MAXN], low[MAXN], num, wtf[MAXN];
bool solve(int u, int f) {
  dfn[u] = low[u] = num++;
  for (int i = 0; i < (((int)(adj[u].size()))); ++i) {
    int v = adj[u][i].v;
    if (dfn[v] == -1) {
      bool tmp = solve(v, u);
      if (!tmp) return tmp;
      if (low[u] > low[v]) low[u] = low[v];
      if (low[v] == dfn[v]) {
        return false;
      }
    } else if ((v != f) && (low[u] > dfn[v]))
      low[u] = dfn[v];
  }
  return true;
}
void dfs(int u) {
  while (wtf[u] < ((int)(adj[u].size()))) {
    int i = wtf[u]++;
    if (adj[u][i].used) continue;
    int v = adj[u][i].v;
    printf("%d %d\n", u + 1, v + 1);
    adj[u][i].used = adj[v][adj[u][i].opp].used = true;
    dfs(v);
  }
}
int main() {
  int N, M;
  while (cin >> N >> M) {
    for (int i = 0; i < (M); ++i) {
      int a, b;
      scanf("%d%d", &a, &b);
      --a;
      --b;
      adj[a].push_back(edge(b, ((int)(adj[b].size()))));
      adj[b].push_back(edge(a, ((int)(adj[a].size())) - 1));
    }
    num = 0;
    memset(dfn, -1, sizeof(int) * N);
    if (!solve(0, -1)) {
      printf("0");
    } else {
      memset(wtf, 0, sizeof(int) * N);
      dfs(0);
    }
  }
  return 0;
}
