
#include <queue>
#include <vector>
#include <bitset>
#include <fstream>
#include <cstring>
#include <deque>

using namespace std;

const int maxN = 1024;
const int maxM = 1024; 
const int INF = 0x3f3f3f3f;

int padure[maxM];

int grupa(int i) {
    if (padure[i] == i)
        return i;
    return padure[i] = grupa(padure[i]); // compresia caii
}

void uneste(int i, int j) {
    int gi = grupa(i);
    int gj = grupa(j);
    if (gi != gj)
        padure[gi] = gj;
}


class Graph {
private:
    int n;
    vector<pair<int, int> > G[maxN];
    bool orientat; // orientat = true daca graful este orientat
    bool ponderat; // ponderat = true daca graful este ponderat
    bitset<maxN> viz;

    vector<int> DFS(int s, bool first_call) {
        if (first_call)
            viz = 0;
        viz[s] = true;
        vector<int> ans;
        ans.push_back(s);
        for (auto it: G[s]) {
            if (!viz[it.first]) {
                vector<int> v = DFS(it.first, false);
                ans.insert(ans.end(), v.begin(), v.end());
            }
        }
        return ans;
    }

public:
    Graph(int n, bool orientat, bool ponderat) : n(n), orientat(orientat), ponderat(ponderat) { }

    void addEdge(int u, int v, int c = 0) {
        if (orientat || u == v) {
            G[u].push_back(make_pair(v, c));
        } else {
            G[u].push_back(make_pair(v, c));
            G[v].push_back(make_pair(u, c));
        }
    }

    vector<int> grad() {
        if (orientat)
            return vector<int>(n + 1, 0); // daca graful este orientat, returnam un vector de 0-uri (trebuie sa stim daca e grad interior/exterior)
        vector<int> g(n + 1);
        for (int i = 1; i <= n; ++i) {
            g[i] = G[i].size();
        }
        return g;
    }

    vector<int> gradInterior() {
        if (!orientat)
            return vector<int>(n + 1, 0); // daca graful nu este orientat, returnam un vector de 0-uri
        vector<int> g(n + 1);
        for (int i = 1; i <= n; ++i) {
            for (auto it: G[i]) {
                if (it.first == i)
                    ++g[i];
            }
        }
        return g;
    }

    vector<int> gradExterior() {
        if (!orientat)
            return vector<int>(n + 1, 0); // daca graful nu este orientat, returnam un vector de 0-uri
        vector<int> g(n + 1);
        for (int i = 1; i <= n; ++i) {
            g[i] = G[i].size();
        }
        return g;
    }

    vector<int> BFS(int s) {
        vector<int> ans;
        viz = 0;
        queue<int> Q;
        Q.push(s);
        viz[s] = true; ans.push_back(s);
        while (!Q.empty()) {
            int u = Q.front();
            ans.push_back(u);
            Q.pop();
            for (auto it: G[u]) {
                if (!viz[it.first]) {
                    Q.push(it.first);
                    viz[it.first] = true;
                }
            }
        }
        return ans;
    }

    vector<int> DFS(int s) {
        return DFS(s, true);
    }

    int connectedComponents() {
        viz = 0;
        int cnt = 0;
        for (int i = 1; i <= n; ++i) {
            if (!viz[i]) {
                DFS(i, false);
                ++cnt;
            }
        }
        return cnt;
    }

    bool isBipartite() {
        viz = 0;
        queue<int> Q;
        for (int i = 1; i <= n; ++i) {
            if (!viz[i]) {
                Q.push(i);
                viz[i] = true;
                while (!Q.empty()) {
                    int u = Q.front();
                    Q.pop();
                    for (auto it: G[u]) {
                        if (!viz[it.first]) {
                            Q.push(it.first);
                            viz[it.first] = true;
                        } else {
                            if (viz[it.first] == viz[u])
                                return false;
                        }
                    }
                }
            }
        }
        return true;
    }

    bool isTree() {
        return connectedComponents() == 1 && !isBipartite();
    }

    bool isCyclic() {
        viz = 0;
        for (int i = 1; i <= n; ++i) {
            if (!viz[i]) {
                if (isCyclic(i, -1))
                    return true;
            }
        }
        return false;
    }

    bool isCyclic(int s, int p) {
        viz[s] = true;
        for (auto it: G[s]) {
            if (!viz[it.first]) {
                if (isCyclic(it.first, s))
                    return true;
            } else {
                if (it.first != p)
                    return true;
            }
        }
        return false;
    }

    bool isDAG() {
        return connectedComponents() == 1 && !isCyclic();
    }

    bool isComplete() {
        for (int i = 1; i <= n; ++i) {
            if (G[i].size() != n - 1)
                return false;
        }
        return true;
    }

    bool isCompleteBipartite() {
        if (!isBipartite())
            return false;
        int cnt1 = 0, cnt2 = 0;
        for (int i = 1; i <= n; ++i) {
            if (viz[i])
                ++cnt1;
            else
                ++cnt2;
        }
        return G[1].size() == cnt2 && G[2].size() == cnt1;
    }

    bool isWheel() {
        if (n < 4)
            return false;
        int cnt = 0;
        for (int i = 1; i <= n; ++i) {
            if (G[i].size() == 2)
                ++cnt;
        }
        return cnt == 2;
    }

    bool isPath() {
        if (n < 2)
            return false;
        int cnt = 0;
        for (int i = 1; i <= n; ++i) {
            if (G[i].size() == 1)
                ++cnt;
        }
        return cnt == 2;
    }

    bool isStar() {
        if (n < 2)
            return false;
        int cnt = 0;
        for (int i = 1; i <= n; ++i) {
            if (G[i].size() == n - 1)
                ++cnt;
        }
        return cnt == 1;
    }

    bool isCycle() {
        if (n < 3)
            return false;
        int cnt = 0;
        for (int i = 1; i <= n; ++i) {
            if (G[i].size() == 2)
                ++cnt;
        }
        return cnt == n;
    }

    bool isBipartiteComplete() {
        if (!isBipartite())
            return false;
        int cnt1 = 0, cnt2 = 0;
        for (int i = 1; i <= n; ++i) {
            if (viz[i])
                ++cnt1;
            else
                ++cnt2;
        }
        return G[1].size() == cnt2 && G[2].size() == cnt1 && isComplete();
    }

    void topologicalSort_copilot() {
        if (!isDAG()) {
            //cout << "Graful nu este DAG\n";
            return;
        }
        viz = 0;
        queue<int> Q;
        for (int i = 1; i <= n; ++i) {
            if (!viz[i]) {
                Q.push(i);
                viz[i] = true;
                while (!Q.empty()) {
                    int u = Q.front();
                    Q.pop();
                    for (auto it: G[u]) {
                        if (!viz[it.first]) {
                            Q.push(it.first);
                            viz[it.first] = true;
                        }
                    }
                }
            }
        }
    }

    vector<int> topologicalSort() {
        if (!isDAG()) {
            //cout << "Graful nu este DAG\n";
            return vector<int>();
        }
        vector<int> grad = gradInterior();
        deque<int> C;
        for (int i = 1; i <= n; ++i) {
            if (grad[i] == 0)
                C.push_back(i);
        }
        for (int i = 0; i < n; i ++) {
            int n = C[i];
            for (auto it: G[n]) {
                if (--grad[it.first] == 0)
                    C.push_back(it.first);
            }
        }

        vector<int> ans;
        for (int i = 0; i < n; i ++)
            ans.push_back(C[i]);
        return ans; 
    }

    vector<int> dijkstra(int s) {
        vector<int> dist(n + 1, INF);
        dist[s] = 0;
        priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > Q;
        Q.push(make_pair(0, s));
        while (!Q.empty()) {
            int u = Q.top().second, l = Q.top().first;
            Q.pop();
            if (l == dist[u]) {
                for (auto it: G[u]) {
                    if (dist[it.first] > dist[u] + it.second) {
                        dist[it.first] = dist[u] + it.second;
                        Q.push(make_pair(dist[it.first], it.first));
                    }
                }
            }
        }
        return dist;
    }

    vector<int> bellmanFord(int s) {
        vector<int> dist(n + 1, INF);
        vector<int> f(n + 1, 0);

        dist[s] = 0;
        
        queue<int> q;
        q.push(1);
        while(!q.empty()) {
            int u = q.front();
            q.pop();
            for (auto it: G[u]) {
                if (dist[it.first] > dist[u] + it.second) {
                    dist[it.first] = dist[u] + it.second;
                    ++ f[it.first];
                    if (f[it.first] > n)
                        return vector<int>(); // ciclu negativ
                    q.push(it.first);
                }
            }
        }

        for (int i = 1; i <= n; ++i) {
            if (dist[i] == INF)
                dist[i] = 0;
        }

        return dist;
    }

    vector<vector<int> > floydWarshall() {
        if (!ponderat)
            return vector<vector<int> >();
        
        vector<vector<int> > dist(n + 1, vector<int>(n + 1, 0));

        for (int i = 1; i <= n; i ++)
            for (auto it: G[i])
                dist[i][it.first] = it.second;
        
        for (int k = 1; k <= n; k ++)
            for (int i = 1; i <= n; i ++)
                for (int j = 1; j <= n; j ++)
                    if (i != j && dist[i][k] && dist[k][j] && (dist[i][j] == 0 || dist[i][j] > dist[i][k] + dist[k][j]))
                        dist[i][j] = dist[i][k] + dist[k][j];

        return dist;
    } 

    Graph getTranspose() {
        if (!orientat)
            return *this; 
        Graph Gt(n, orientat, ponderat);
        for (int i = 1; i <= n; i ++)
            for (auto it: G[i])
                Gt.addEdge(it.first, i, it.second);
        return Gt;
    }

    vector<vector<int> > componenteTareConexe() {
        if (!orientat)
            return vector<vector<int> >();
        vector<vector<int> > ans;
        viz = 0; 

        vector<int> ord; 
        for (int i = 1; i <= n; i ++) {
            if (!viz[i]) {
                vector<int> v = DFS(i, false);
                ord.insert(ord.end(), v.begin(), v.end());
            }
        }

        Graph Gt = getTranspose();
        reverse(ord.begin(), ord.end());
 
        for (auto it: ord) {
            if (!Gt.viz[it]) {
                vector<int> comp = Gt.DFS(it, false);
                ans.push_back(comp);
            }
        }

        return ans;
    }

    vector<vector<int> > componenteConexe() {
        vector<vector<int> > ans;
        viz = 0;
        for (int i = 1; i <= n; i ++) {
            if (!viz[i]) {
                vector<int> v = DFS(i, false);
                ans.push_back(v);
            }
        }
        return ans;
    }

    struct Muchie {
        int u, v, cost;
        Muchie(int u, int v, int cost): u(u), v(v), cost(cost) {}
        bool operator < (const Muchie &other) const {
            return cost < other.cost;
        }
    };

    vector<Muchie> getMuchii() {
        vector<Muchie> ans;
        for (int i = 1; i <= n; i ++) {
            for (auto it: G[i]) {
                if (orientat || i <= it.first)
                    ans.push_back(Muchie(i, it.first, it.second));
            }
        }
        return ans;
    }

    vector<Muchie> kruskal() {
        if (!ponderat)
            return vector<Muchie>();


        vector<Muchie> ans;
        vector<Muchie> muchii = getMuchii();
        sort(muchii.begin(), muchii.end());
        memset(padure, 0, sizeof padure);

        for (int i = 1; i <= n; i ++)
            padure[i] = i;

        int cost = 0;
        for (auto it: muchii) {
            int u = it.u, v = it.v, c = it.cost;
            if (grupa(u) != grupa(v)) {
                ans.push_back(Muchie(u, v, c));
                uneste(u, v);
            }
        }
        return ans;
    }

    vector<Muchie> prim(int s) {
        priority_queue <pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > Q;
        vector<Muchie> ans;
        viz = 0;
        vector<int> parent(n + 1, 0);
        vector<int> cost(n + 1, INF);
        bitset<maxN> inMST = 0;

        Q.push(make_pair(0, s));
        cost[s] = 0;

        while (!Q.empty()) {
            int u = Q.top().second;
            Q.pop();
            if (!inMST[u]) {
                inMST[u] = 1;
                for (auto it: G[u]) {
                    int v = it.first, c = it.second;
                    if (!inMST[v] && cost[v] > c) {
                        cost[v] = c;
                        Q.push(make_pair(cost[v], v));
                        parent[v] = u;
                    }
                }
            }
        }

        for (int i = 1; i <= n; i ++) {
            if (parent[i] != 0)
                ans.push_back(Muchie(parent[i], i, cost[i]));
        }

        return ans;
    }

    static bool havel_hakimi(vector<int> &v) {
        sort(v.begin(), v.end());
        reverse(v.begin(), v.end());
        while (v.size() > 0 && v[0] > 0) {
            int x = v[0];
            v.erase(v.begin());
            if (x > v.size())
                return false;
            for (int i = 0; i < x; i ++) {
                v[i] --;
                if (v[i] < 0)
                    return false;
            }
            sort(v.begin(), v.end());
            reverse(v.begin(), v.end());
        }
        return true;
    }

    vector<int> euler() {
        vector<pair<Muchie, bool> > muchii; 
        vector<vector<pair<Muchie, bool>* > > gg (n + 1); 
        for (auto it: getMuchii())
            muchii.push_back(make_pair(it, false));

        for (int i = 0; i < muchii.size(); i ++) {
            gg[muchii[i].first.u].push_back(&muchii[i]);
            if (!orientat)
                gg[muchii[i].first.v].push_back(&muchii[i]);
        }

        for (int i = 1; i <= n; i ++) {
            if (gg[i].size() % 2 == 1)
                return vector<int>();
        }

        vector<int> ans;
        int cc = 0, root;
        viz = 0;
        for (int i = 1; i <= n; i ++) {
            if (!viz[i]) {
                int dim = DFS(i).size();
                if (dim > 1) {
                    cc ++;
                    root = i;
                }
            }
        }

        if (cc != 1)
            return vector<int>();

        stack<int> S;
        S.push(root);
        while (!S.empty()) {
            int u = S.top();
            while (gg[u].size() > 0 && gg[u].back()->second)
                gg[u].pop_back();
            if (gg[u].empty()) {
                if (S.size() > 1)
                    ans.push_back(u);
                S.pop();
            } else {
                gg[u].back()->second = true;
                S.push(gg[u].back()->first.u + gg[u].back()->first.v - u);
                gg[u].pop_back();
            }
        }

        return ans;
    }
};

class TransportNetwork {
private:
    int n; 
    struct Muchie {
        int src, dest;
        int flx, cap; 
        int cost; 
        Muchie (int _src = 0, int _dest = 0, int _flx = 0, int _cap = 0, int _cost = 0):
            src(_src), dest(_dest), flx(_flx), cap(_cap), cost(_cost) { }
    };

    vector<Muchie> father; 
    vector<Muchie> G[maxN];
    bitset<maxN> viz;

    bool bfs(int s, int d) {
        vector<int> cost (n + 1, INF);
        father = vector<Muchie> (n + 1, -1);

        queue<int> q;
        cost[s] = 0; q.push(s);

        while(!q.empty()) {
            int top = q.front(); q.pop();
            for (auto it: G[top]) {
                if (cost[top] + 1 < cost[it.dest] && it.flx < it.cap) {
                    cost[it.dest] = cost[top] + 1;
                    father[it.dest] = it; 
                    q.push(it.dest); 
                }
            }
        }
        return cost[d] != INF; 
    }

    void dfs(int src) {
        viz[src] = 1;
        for (auto it: G[src]) {
            if (!viz[it.dest] && it.flx < it.cap)
                dfs(it.dest);
        }
    }

    vector<int> bellman_ford(int S) {
        vector<int> bellman_dist (n + 1, INF);
        viz = 0;

        queue<int> q; 
        bellman_dist[S] = 0; q.push(S);
        viz[S] = true;
        while(!q.empty()) {
            int top = q.front(); q.pop();
            viz[top] = false;
            for (auto it: G[top]) {
                if (it.cap > 0 && bellman_dist[top] + it.cost < bellman_dist[it.dest]) {
                    bellman_dist[it.dest] = bellman_dist[top] + it.cost;
                    if(!viz[it.dest]) {
                        q.push(it.dest);
                        viz[it.dest] = true;
                    }
                }
            }
        }

        return bellman_dist;
    }

    bool dijkstra(int s, int d, vector<int>& bellman_dist, vector<int>& dijsktra_dist) {
        vector<int> cost (n + 1, INF);
        father = vector<Muchie> (n + 1);

        priority_queue<pair<int, int> > Q;
        cost[s] = 0; Q.push(make_pair(0, s));

        while(!Q.empty()) {
            int top = Q.top().second, c = -Q.top().first; Q.pop();

            if (cost[top] == c) {
                for (auto it: G[top]) {
                    int dist = cost[top] + it.cost;
                    dist = dist + bellman_dist[top] - bellman_dist[it.dest];

                    if (dist < cost[it.dest] && it.flx < it.cap) {
                        cost[it.dest] = dist;
                        dijsktra_dist[it.dest] = dijsktra_dist[top] + it.cost;
                        father[it.dest] = it; 
                        Q.push(make_pair(-cost[it.dest], it.dest)); 
                    }
                    
                }
            }
        }

        for (int i = 1; i <= n; i ++)
            bellman_dist[i] = dijsktra_dist[i];
        return cost[d] != INF; 
    }

protected:
    vector<pair<int, int> > matchingSearch(int dr, int target) {
        vector<pair<int, int> > ans;
        for (int i = 1; i <= dr; i ++) {
            for (auto it: G[i]) {
                if (it.flx == target)
                    ans.push_back(make_pair(i, it.dest));
            }
        }
        return ans;
    }
public:
    TransportNetwork(int _n): n(_n) { }
    void addEdge(int u, int v, int c, int cost = 0) {
        G[u].push_back(Muchie(u, v, 0, c, cost));
        G[v].push_back(Muchie(v, u, 0, 0, -cost));
    }

    int maxFlow(int s, int d) {
        int ans = 0;
        vector<Muchie> drum;
        while (bfs(s, d)) {
            drum.clear();
            int x = d; 
            while(father[x].src != -1) {
                drum.push_back(father[x]);
                x = father[x].src;
            }
            
            int max_flow = INF;
            for (auto it: drum)
                max_flow = min(max_flow, it.cap - it.flx);

            for (auto edge: drum) {
                bool found = false;
                for (int i = 0; i < G[edge.src].size() && !found; i ++) {
                    if (G[edge.src][i].dest == edge.dest) {
                        G[edge.src][i].flx += max_flow;
                        found = true;
                    }
                }

                found = false;
                for (int i = 0; i < G[edge.dest].size() && !found; i ++) {
                    if (G[edge.dest][i].dest == edge.src) {
                        G[edge.dest][i].flx -= max_flow;
                        found = true;
                    }
                }
            }
        }

        for (auto it: G[s])
            ans += it.flx;
        return ans;
    }

    vector<pair<int, int> > minCut(int s) {
        viz = 0;
        vector<pair<int, int> > ans;
        dfs(s);
        for (int i = 1; i <= n; i ++) {
            if (viz[i]) {
                for (auto it: G[i]) {
                    if (!viz[it.dest] && it.cap > 0)
                        ans.push_back(make_pair(i, it.dest));
                }
            }
        }
        return ans;
    }

    int minCostFlow(int s, int d) {
        int flx_max = 0;
        vector<int> bellman_dist = bellman_ford(s);
        vector<int> dijsktra_dist = vector<int> (n + 1, 0); 

        while (dijkstra(s, d, bellman_dist, dijsktra_dist)) {
            int flux = INF, cost_flux = 0;
            int x = d; 

            while(x != s) {
                flux = min(flux, father[x].cap - father[x].flx);
                cost_flux += father[x].cost;
                x = father[x].src;
            }

            flx_max += flux * cost_flux;

            x = d;
            while (x != s) {
                for (auto &it: G[father[x].src]) {
                    if (it.dest == x) {
                        it.flx += flux;
                        break;
                    }
                }

                for (auto &it: G[father[x].dest]) {
                    if (it.dest == father[x].src) {
                        it.flx -= flux;
                        break;
                    }
                }

                x = father[x].src;
            }
        }

        return flx_max;
    }

};

class BipartiteGraph: private TransportNetwork {
private:
    int n, m;
public:
    BipartiteGraph(int _n, int _m): n(_n), m(_m), TransportNetwork(_n + _m + 2) { 
        for (int i = 1; i <= n; i ++)
            TransportNetwork::addEdge(0, i, 1);
        for (int i = 1; i <= m; i ++)
            TransportNetwork::addEdge(i + n, n + m + 1, 1);
    }
    void addEdge(int u, int v) {
        TransportNetwork::addEdge(u, v + n, 1);
    }
    int cuplaj() {
        return TransportNetwork::maxFlow(0, n + m + 1);
    }
    vector<pair<int, int> > matching() {
        auto v = matchingSearch(n, 1);
        for (auto &it: v)
            it.second -= n;
        return v;
    }
};

int main() {
    ifstream in("grafpond.in");
    ofstream out("grafpond.out");

    int n, m, s, d, e;
    in >> n >> m;
    /*Graph G(n, false, true);

    for (int i = 1; i <= m; i ++) {
        int x, y, c;
        in >> x >> y >> c;
        G.addEdge(x, y, c);
    }

    vector<Graph::Muchie> ans = G.prim(1);
    for (auto it: ans) {
        out << it.u << " " << it.v << " " << it.cost << " \n";
    }*/

    /*TransportNetwork T(n);
    for (int i = 1; i <= m; i ++) {
        int x, y, c, cost;
        in >> x >> y >> c >> cost;
        T.addEdge(x, y, c, cost);
    }

    out << T.minCostFlow(s, d) << "\n";*/

    /*BipartiteGraph B(n, m);
    for (int i = 1; i <= e; i ++) {
        int x, y;
        in >> x >> y;
        B.addEdge(x, y);
    }

    out << B.cuplaj() << "\n";
    auto ans = B.matching();
    for (auto it: ans)
        out << it.first << " " << it.second << "\n";

    vector<int> v; 
    for (int i = 3; i >= 0; i --) 
        v.push_back(i);
    out << Graph::havel_hakimi(v) << '\n';
    v.clear(); v = vector<int>(4, 3); out << Graph::havel_hakimi(v) << '\n';*/

    Graph G(n, false, false);
    for (int i = 1; i <= m; i ++) {
        int x, y;
        in >> x >> y;
        G.addEdge(x, y);
    }

    auto v = G.euler();
    for (auto it: v)
        out << it << " ";
    return 0;
}