#include <bits/stdc++.h>
#define MAXN 10005
using namespace std;
struct Tarjan
{
struct edge
{
int u,v;
edge(int uu=0,int vv=0):u(uu),v(vv){}
bool operator ==(const edge &p)const
{
return (u==p.u&&v==p.v)||(v==p.u&&u==p.v);
}
};
int n; //点的个数
vector<int> e[MAXN]; //图
int DFN[MAXN],LOW[MAXN];
int index; //编号计数器
edge stk[MAXN]; //栈
int top;
vector<vector<edge> > Ans; //记录答案
bool iscut[MAXN]; //记录点是否为割点
void init(int N) //初始化
{
n=N;
Ans.clear();
for(int i=1;i<=n;i++)
e[i].clear();
top=0;
index=0;
memset(DFN,-1,sizeof(DFN));
memset(iscut,0,sizeof(iscut));
}
void AddEdge(int u,int v) //添加边
{
e[u].push_back(v);
e[v].push_back(u);
}
void DFS(int u,int prt) //从点u开始搜索
{
DFN[u]=LOW[u]=++index;
int child=0;
for(int i=0;i<e[u].size();i++)
{
int &v=e[u][i];
if(v==prt)continue;
if(DFN[v]!=-1&&DFN[v]>=DFN[u])continue;
stk[top++]=edge(u,v);
if(DFN[v]==-1)
{
child++;
DFS(v,u);
LOW[u]=min(LOW[u],LOW[v]);
if(LOW[v]>=DFN[u])
{
iscut[u]=true;
vector<edge> ans;
while(!(stk[top-1]==edge(u,v)))
{
ans.push_back(stk[top-1]);
top--;
}
ans.push_back(stk[top-1]);
top--;
Ans.push_back(ans);
}
}
else LOW[u]=min(LOW[u],DFN[v]);
}
if(prt==-1&&child==1)iscut[u]=false;
}
void Solve()
{
for(int i=1;i<=n;i++)
if(DFN[i]==-1)DFS(i,-1);
}
}T;
int main()
{
int n;
while(scanf("%d",&n)==1)
{
T.init(n);
int m;
scanf("%d",&m);
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
T.AddEdge(u,v);
}
T.Solve();
for(int i=0;i<T.Ans.size();i++)
{
for(int j=0;j<T.Ans[i].size();j++)
printf("(%d,%d) ",T.Ans[i][j].u,T.Ans[i][j].v);
printf("\n");
}
}
}