#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <map>

#define MAX_N (100000L)
#define MAX_M (100000L)

using namespace std;

long prim(const vector<vector<pair<long, long>>> &adj_lists,
          vector<vector<pair<long, long>>> &mst_adj_lists) {
  const long N = adj_lists.size();
  priority_queue<pair<long, pair<long, long>>, vector<pair<long, pair<long, long>>>,
                 greater<pair<long, pair<long, long>>>>
      que;                // priority queue with (cost, (u, v))
                          // (u is always a used node)
  vector<long> us(N, 0);  // whether each node is used
  long res = 0;           // total cost of mst
  // initialize
  us[0] = 1;
  for (pair<long, long> p : adj_lists[0]) {
    const long nxt = p.first, w = p.second;
    que.push(make_pair(w, make_pair(0, nxt)));
  }
  // accept edges with low cost
  while (!que.empty()) {
    const long u = que.top().second.first, v = que.top().second.second,
               w = que.top().first;
    que.pop();
    // skip if both ends of the edge are used already
    if (us[v]) {
      continue;
    }
    // accept edge
    mst_adj_lists[u].push_back(make_pair(v, w));
    mst_adj_lists[v].push_back(make_pair(u, w));
    us[v] = 1;
    res += w;
    for (pair<long, long> p : adj_lists[v]) {
      const long nxt = p.first, wd = p.second;
      if (!us[nxt]) {
        que.push(make_pair(wd, make_pair(v, nxt)));
      }
    }
  }
  return res;
}

void dfs(const vector<vector<pair<long, long>>> &adj_lists, long cur, long par,
         vector<long> &num_outs, map<pair<long, long>, long> &edge_to_dir) {
  // ensure children have even number of out-going nodes
  for (pair<long, long> p : adj_lists[cur]) {
    const long nxt = p.first;
    if (nxt != par) {
      dfs(adj_lists, nxt, cur, num_outs, edge_to_dir);
    }
  }
  // ensure current node has even number of out-going nodes
  if (par >= 0 && num_outs[cur] % 2 == 1) {
    if (edge_to_dir[make_pair(cur, par)] == 1) {
      num_outs[cur]--;
      num_outs[par]++;
    } else {
      num_outs[cur]++;
      num_outs[par]--;
    }
    edge_to_dir[make_pair(cur, par)] *= -1;
    edge_to_dir[make_pair(par, cur)] *= -1;
  }
  // if the total number of edges in the original graph is even
  // and all of the non-root nodes have even out-going nodes,
  // then the root must have even out-goring nodes.
}

int main(int argc, char *argv[]) {
  // read inputs
  long N, M, as[MAX_M], bs[MAX_M];
  scanf("%ld %ld", &N, &M);
  for (long k = 0; k < M; k++) {
    scanf("%ld %ld", &as[k], &bs[k]);
    as[k]--;  // NOTE : modified input
    bs[k]--;  // NOTE : modified input
  }

  // false if odd number of edges
  if (M % 2 == 1) {
    printf("-1\n");
    return 0;
  }

  // create graph
  vector<vector<pair<long, long>>> adj_lists(N, vector<pair<long, long>>());
  for (int k = 0; k < M; k++) {
    const long a = as[k], b = bs[k];
    adj_lists[a].push_back(make_pair(b, 1));
    adj_lists[b].push_back(make_pair(a, 1));
  }

  // get mst
  vector<vector<pair<long, long>>> mst_adj_lists(N, vector<pair<long, long>>());
  prim(adj_lists, mst_adj_lists);

  // solve
  // choose directions of edges randomly
  vector<long> num_outs(N, 0);
  map<pair<long, long>, long> edge_to_dir;
  for (long k = 0; k < M; k++) {
    const long a = as[k], b = bs[k];
    edge_to_dir[make_pair(a, b)] = 1;
    edge_to_dir[make_pair(b, a)] = -1;
    num_outs[a]++;
  }
  // dfs on mst from node 0
  dfs(mst_adj_lists, 0, -1, num_outs, edge_to_dir);

  // print answer
  for (long k = 0; k < M; k++) {
    const long a = as[k], b = bs[k];
    if (edge_to_dir[make_pair(a, b)] == 1) {
      printf("%ld %ld\n", a + 1, b + 1);
    } else {
      printf("%ld %ld\n", b + 1, a + 1);
    }
  }
}

Measured memory_bytes: 41072