/*
题意:给一无向图,现在要确定每边的方向,使得任意两点可达,一定存在。
思想:用Tarjan算法求双连通分量,将深入的边与使low值变小的边存起来。其它还没确定的随便选个方向即可
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=110000;
const int maxm=2100000;
struct edge
{
int u,v,next;
bool flag;
}e[maxm];
int n,m,edgeNum,top,top1,cnt,tnum,first[maxn],low[maxn],DFN[maxn],q[maxn],q1[maxm];
bool inq[maxn];
void Addedge(int u,int v)
{
e[edgeNum].u=u,e[edgeNum].v=v,e[edgeNum].flag=false,e[edgeNum].next=first[u],first[u]=edgeNum++;
e[edgeNum].u=v,e[edgeNum].v=u,e[edgeNum].flag=false,e[edgeNum].next=first[v],first[v]=edgeNum++;
}
void DFS(int t,int p,int e1)
{
DFN[t]=low[t]=++tnum;
q[top++]=t;
q1[top1++]=e1;
if(e1!=-1) e[e1].flag=true;
inq[t]=true;
int j,k;
for(k=first[t];k!=-1;k=e[k].next)
{
j=e[k].v;
if(j==p) continue;
if(!DFN[j])
{
DFS(j,t,k);
if(low[t]>low[j])
low[t]=low[j];
}
else if(inq[j]&&low[t]>DFN[j])
{
q1[top1++]=k;//绕回去
e[k].flag=true;
low[t]=DFN[j];
}
}
if(DFN[t]==low[t])
{
++cnt;
do
{
inq[q[--top]]=false;
}while(q[top]!=t);
}
}
int main()
{
int i,u,v;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(first,-1,sizeof(first));
edgeNum=0;
for(i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
Addedge(u,v);
}
memset(low,0,sizeof(low));
memset(DFN,0,sizeof(DFN));
memset(inq,false,sizeof(inq));
top1=top=cnt=tnum=0;
for(i=1;i<=n;i++)
if(!DFN[i])
DFS(i,-1,-1);
if(cnt!=1)
{
printf("0\n");
continue;
}
//DFS1(1);
for(i=0;i<edgeNum;i+=2)
if(e[i].flag==false&&e[i+1].flag==false)
q1[top1++]=i;//随便确定一个方向
// printf("%d\n",top1);
for(i=1;i<top1;i++)
printf("%d %d\n",e[q1[i]].u,e[q1[i]].v);
}
return 0;
}