#include <bits/stdc++.h>
#define Nmax 100010
using namespace std;
//ifstream fin("apm.in");
//ofstream fout("apm.out");
ifstream fin("ciclueuler.in");
ofstream fout("ciclueuler.out");
class Graf
{
private:
vector<vector<int>> gr; //graf -> lista de adiacenta
vector<vector<int>> gr_t; //graf transpus
int par[Nmax];
int dim[Nmax];
vector<int> topo;
int dist[Nmax] = {-1};
int viz[Nmax] ;
int n;
int m;
int nr_componente_conexe = 0;
public:
Graf(): n(0), m(0)
{
}
Graf(int x, int y = 0): n(x), m(y)
{
}
Graf(int x, int y, const vector<vector<int>>& v): n(x), m(y), gr(v)
{
}
//dezvizitatam toate nodurile
void nevizitate()
{
for(int i = 1; i <= n; i++)
viz[i] = 0;
}
//bfs
void BFS(int start)
{
int c[Nmax];
int pr, ul;
pr = 0;
ul = -1;
int n_curent;
dist[start] = 0;
c[++ul] = start;
while(pr <= ul)
{
n_curent = c[pr++];
for(auto i:gr[n_curent]) //verificam toti vecinii nodului curent
if(dist[i] == -1)
{
dist[i] = dist[n_curent] + 1;
c[++ul] = i;
}
}
}
//dfs
void DFS(int x)
{
viz[x] = nr_componente_conexe;
for(int i = 0; i < gr[x].size(); ++i)
{
if(viz[gr[x][i]] == 0)
{
viz[gr[x][i]] = 1;
DFS(gr[x][i]);
}
}
}
//sortare topologica
void sortare_topologica(int x)
{
viz[x] = 1;
for(int i = 0; i < gr[x].size(); ++i)
{
if(viz[gr[x][i]] == 0)
sortare_topologica(gr[x][i]);
}
topo.push_back(x);
}
//Componente tare conexe
void DFS2(int x,int ct,vector<vector<int>> ctc, int comp[])
{
viz[x] = 1;
comp[x] = ct;
ctc[ct].push_back(x);
for(int i = 0; i< gr_t[x].size(); i++)
{
if(viz[gr_t[x][i]] == 0)
{
DFS2(gr_t[x][i],ct,ctc,comp);
}
}
}
void componenteTareConexe(int ct, int comp[], const vector<vector<int>>& ctc)
{
nevizitate();
for(int i=1;i<=n;++i)
{
if(viz[i] == 0)
{
sortare_topologica(i);
}
}
reverse(topo.begin(), topo.end());
for(auto i:topo)
{
if(comp[i] == 0)
{
ct += 1;
DFS2(i, ct, ctc, comp);
}
}
}
//Havel Hakimi
bool HavelHakimi(vector<int> &grade)
{
sort(grade.begin(), grade.end(), greater<>());
while(grade.size() > 0)
{
if(grade[0] + 1 > grade.size())
return false;
for(int i = 1; i <= grade[0]; i++)
{
grade[i] -= 1;
if(grade[i] < 0)
{
return false;
}
}
grade.erase(grade.begin());
sort(grade.begin(), grade.end(), greater<>());
}
return true;
}
//Paduri de multimi disjuncte
int findd(int x)
{
while(x != par[x])
{
x = par[x];
}
return x;
}
void unite(int x, int y)
{
x = findd(x);
y = findd(y);
if(dim[x] >= dim[y])
{
par[y] = x;
dim[x] += dim[y];
}
else
{
par[x] = y;
dim[y] += dim[x];
}
}
void init()
{
for(int i=1; i<=n; i++)
{
par[i] = i;
dim[i] = 1;
}
}
//Arbore partial de cost minim -> folosim algoritmul kruskal
vector<pair<int, pair<int, int>>> kruskal(vector<pair<int, pair<int, int>>>& muchii)
{
vector<pair<int, pair<int, int>>> subgr;
sort(muchii.begin(), muchii.end());
init();
for(auto &muchie : muchii)
{
if(findd(muchie.second.first) != findd(muchie.second.second))
{
unite(muchie.second.first, muchie.second.second);
subgr.push_back({muchie.first, {muchie.second.first, muchie.second.second}});
}
}
return subgr;
}
//Diametrul unui arbore
void dfsParcurgere(int x, int d, int &dmax, int &nmax)
{
if(d > dmax)
{
dmax = d;
nmax = x;
}
viz[x] = 1;
for(auto k:gr[x])
{
if(viz[k] == 0)
{
dfsParcurgere(k, d+1, dmax, nmax);
}
}
}
int diamentru()
{
int nmax = 0, dmax = 0;
dfsParcurgere(1, 0, dmax, nmax);
int n1 = nmax;
nevizitate();
dmax = 0;
nmax = 0;
dfsParcurgere(n1, 0, dmax, nmax);
return dmax + 1;
}
//Fluxul maxim
//c -> capacitatea muchiei x y
//f -> cat flux este pompar pe muchia x,y
/*
bool fluxMaxim(int s, int d, vector<vector<int>> &c, vector<vector<int>> &f, vector<int> &parent)
{
queue<int> q;
vector<bool> vis(n + 1);
int current;
q.push(s);
vis[s] = true;
parent[s] = -1;
while(!q.empty())
{
current = q.front();
q.pop();
vis[current] = true;
for(auto &w: gr[current])
{
if(!vis[w] && c[current][w] - f[current][w])
{
parent[w] = current;
q.push(w);
}
}
}
return vis[d];
}
*/
void royFloyd(int c[][101])
{
int i,j,k;
for( k = 1; k <= n; k++ )
{
for( i = 1; i <= n; i++ )
{
for( j = 1; j <= n; j++ )
{
//if (c[i][k] && c[k][j])
if (c[i][j] > c[i][k] + c[k][j])
c[i][j] = c[i][k] + c[k][j];
}
}
}
}
void ciclu_Euler(int start, vector<pair<int,int>> g[], vector<int> &ciclu)
{
stack<int> s;
s.push(start); //adaugam nodul de la care pornim in stiva
while(!s.empty()) //cat timp avem elem in stiva
{
int n = s.top();
if(!g[n].empty())
{
int vecin = g[n].back().second;
int nr = g[n].back().first; //nr pentru muchia respectiva
g[n].pop_back();
if(!viz[nr])
{
viz[nr] = 1;
s.push(vecin);
}
}
else
{
ciclu.push_back(n);
s.pop();
}
}
}
void exista_ciclu_Euler(vector<pair<int,int>> g[])
{
vector<int> ciclu;
for(int i = 0; i <= n; i++)
{
if(g[i].size() % 2 == 1)
{
fout << "-1";
return ;
}
}
ciclu_Euler(1, g, ciclu);
for(int i = 0; i < ciclu.size() - 1; i++)
{
fout << ciclu[i] << ' ';
}
}
};
int main()
{
int n, m, x, y;
vector<pair<int,int>> grf[n+10]; //folosim grf ca si graf care retine in plus si numarul muchiei
fin >> n >> m;
for(int i = 1; i <= m; i++)
{
fin >> x >> y;
grf[x].emplace_back(i,y); // adaugam la sfarsitul vectorului
grf[y].emplace_back(i,x);
}
Graf graf(n,m);
graf.exista_ciclu_Euler(grf);
return 0;
//roy-floyd
/*
int n, cost[101][101] ;//={1000001};
fin >> n;
Graf graf(n);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
fin >> cost[i][j];
if(cost[i][j] == 0 && i != j)
cost[i][j] = 1000001;
}
}
graf.royFloyd(cost);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(cost[i][j] == 1000001)
fout << 0 << ' ';
else
fout << cost[i][j] << ' ';
}
fout << "\n";
}
*/
//Fluxul maxim
/*
int n,m,x,y,cost;
vector<vector<int>> c;
vector<vector<int>> f;
vector<int> parent;
int raspuns = 0;
fin >> n >> m;
vector<vector<int>> v(n + 1);
for(int i = 1; i < m; i++)
{
fin >> x >> y >> cost;
v[x].push_back(y);
c[x][y] = cost;
}
Graf graf(n, n-1, v);
parent.resize(n+1);
while(fluxMaxim(1,n,c,f,parent))
{
// Gasim drumul de la N la 1
// Gasim muchia cu cap - flux minim
int current = n;
int fmin = 1 << 30;
while (current != 1)
{
if (c[parent[current]][current] - f[parent[current]][current] < fmin)
{
fmin = c[parent[current]][current] - f[parent[current]][current];
}
current = parent[current];
}
current = n;
while(current != 1)
{
f[parent[current]][current] += fmin;
f[current][parent[current]] -= fmin;
current = parent[current];
}
raspuns += fmin;
}
fout << raspuns;
*/
//Diametrul unui arbore /////////////////////////////////////////////////////////////////
/*
int n, x ,y;
fin >> n;
vector<vector<int>> v(n + 1);
for(int i = 1; i < n; i++)
{
fin >> x >> y;
v[x].push_back(y);
v[y].push_back(x);
}
Graf graf(n, n-1, v);
int sol = graf.diamentru();
fout << sol;
*/
//Paduri de multimi disjuncte////////////////////////////////////////////////////////////
/*
int n, m, x ,y, cod;
fin >> n >> m;
Graf graf(n, m);
graf.init();
for(int i = 1; i <= m; i++)
{
fin >> cod >> x >> y;
if(cod == 1)
{
graf.unite(x, y);
}
else if(graf.findd(x) == graf.findd(y))
fout << "DA" << '\n';
else fout << "NU" << '\n';
}
return 0;
*/
//Arbore partial de cost minim///////////////////////////////////////////////////////////
/*
int n, m, x ,y, cost;
vector<pair<int, pair<int, int>>> muchii;
fin >> n >> m;
Graf graf(n, m);
for(int i = 1; i <= m; i++)
{
fin >> x >> y >> cost;
muchii.push_back({cost,{x,y}});
}
int cost_total = 0;
muchii = graf.kruskal(muchii);
for(auto muchie : muchii)
{
cost_total += muchie.first;
}
fout << cost_total << '\n' << n - 1 << '\n';
for(auto muchie : muchii)
{
fout << muchie.second.first << ' ' << muchie.second.second << '\n';
}
return 0;
*/
}