#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<queue>
#include<cmath>
#include<cstdio>
#include<tuple>
#include<bitset>
#include<map>

using namespace std;
#define rep(i,n) for(int i=0;i<n;++i)
#define rep1(i,n) for(int i=1;i<=n;++i)
#define ALL(x) x.begin(),x.end()
using P=pair<int,int>;
using lint=long long;
using ll=long long;
const lint inf=1e18+7;
const int MOD=1000000007;
struct UnionFind {
    int n;
    vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2
    vector<int> group;
    UnionFind(int N) : par(N) { //最初は全てが根であるとして初期化
        for(int i = 0; i < N; i++) par[i] = i;
        n=N;
    }
    int root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
        if (par[x] == x) return x;
        return par[x] = root(par[x]);
    }
    void calc(){
        group.resize(n,0);
        for(int i=0;i<n;i++){
            group[root(i)]++;
        }
    }
    int size(int x){
        return group[root(x)];
    }
    void unite(int x, int y) { // xとyの木を併合
        int rx = root(x); //xの根をrx
        int ry = root(y); //yの根をry
        if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま
        par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
    }
 
    bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
        int rx = root(x);
        int ry = root(y);
        return rx == ry;
    }
 
};

class Node{
  public:
  int no;
  int outdegree;
  vector<P> edge;
  Node* par;
  vector<Node*> child;
  void build(int i){
    no=i;outdegree=0;
  }
};
void DFS(Node& node,map<P,int>& memo,vector<P>& res){
  int num=node.child.size();
  rep(i,num){
    DFS(*node.child[i],memo,res);
  }
  int edge_num=node.edge.size();
  P last={0,0};
  P def={0,0};
  P par_edge{MOD,MOD};
  if(node.outdegree%2==1){
    last={MOD,MOD};
  }
  rep(i,edge_num){
    if(node.edge[i].first+node.edge[i].second-node.no==node.par->no){
      par_edge=node.edge[i];
      continue;
    }
    if(last==def){
      if(memo[node.edge[i]]!=2){
        last=node.edge[i];
      }
    }
    else{
      if(memo[node.edge[i]]!=2){
        node.outdegree+=2;
        res.push_back({node.no,node.edge[i].first+node.edge[i].second-node.no});
        res.push_back({node.no,last.first+last.second-node.no});
        memo[last]=2;
        memo[node.edge[i]]=2;
        if(last==make_pair(MOD,MOD)){
          node.outdegree-=1;
          memo[last]=0;
        }
        last={0,0};
      }
    }
  }
  if(node.no==1)return;
  if(last==def){
    memo[par_edge]=2;
    res.push_back({par_edge.first+par_edge.second-node.no,node.no});
    node.par->outdegree+=1;
  }
  else{
    node.outdegree+=2;
    memo[par_edge]=2;
    res.push_back({node.no,par_edge.first+par_edge.second-node.no});
    memo[last]=2;
    res.push_back({node.no,last.first+last.second-node.no});
  }
}
signed main(){
  int n,m;cin>>n>>m;
  vector<P> edge(m);
  map<P,int> memo;
  vector<Node> node(n+1);
  rep1(i,n)node[i].build(i);
  rep(i,m){
    cin>>edge[i].first>>edge[i].second;
    memo[edge[i]]=0;
    node[edge[i].first].edge.push_back(edge[i]);
    node[edge[i].second].edge.push_back(edge[i]);
  }
  if(m%2==1){
    cout<<-1<<endl;
    return 0;
  }
  UnionFind tree(n+1);
  queue<Node*> que;
  node[1].par=&node[1];
  que.push(&node[1]);
  while(!que.empty()){
    Node* buf=que.front();que.pop();
    int num=buf->edge.size();
    rep(i,num){
      if(!tree.same(buf->edge[i].first,buf->edge[i].second)){
        if(memo[buf->edge[i]]==0){
          memo[buf->edge[i]]+=1;
          tree.unite(buf->edge[i].first,buf->edge[i].second);
          int sum=buf->edge[i].first+buf->edge[i].second;
          buf->child.push_back(&node[sum-buf->no]);
          node[sum-buf->no].par=buf;
          que.push(&node[sum-buf->no]);
        }
      }
    }
  }
  vector<P> res;
  DFS(node[1],memo,res);
  //cout<<"answer"<<endl;
  for(auto& val:res){
    if(val.first+val.second>MOD)continue;
    cout<<val.first<<" "<<val.second<<"\n";
  }
  return 0;
}
/*
6 12
1 2
2 3
3 4
4 5
5 6
5 1
6 4
1 3
1 4
2 4
2 5
3 5
*/

Measured memory_bytes: 28912