package main
 
import (
  "bufio"
  "os"
  "strconv"
  "strings"
  "fmt"
  "container/heap"
)
 
var reader = bufio.NewReaderSize(os.Stdin, 1000000)
var writer = bufio.NewWriter(os.Stdout)
func NextLine() string {
  var line, buffer []byte
  var isPrefix bool = true
  var err error
  for isPrefix {
    line, isPrefix, err = reader.ReadLine()
    if err != nil { panic(err) }
    buffer = append(buffer, line...)
  }
  return string(buffer)
}
func NextInt() int {
  var n int
  n, _ = strconv.Atoi(NextLine())
  return n
}
func NextIntVec() []int {
  L := strings.Split(NextLine(), " ")
  N := make([]int, len(L))
  for i := range N {
    N[i], _ = strconv.Atoi(L[i])
  }
  return N
}
func Write(s interface{}) {
  fmt.Fprintln(writer, s)
}
func WriteIntVec(A *[]int) {
  S := make([]string, len((*A)))
  for i, a := range (*A) {
    S[i] = strconv.Itoa(a)
  }
  fmt.Fprintln(writer, strings.Join(S, " "))
}
func Output() {
  _ = writer.Flush()
}

type Item struct {
  Comparison int
  Index int
}
type PriorityQueue []*Item
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
  return pq[i].Comparison < pq[j].Comparison
}
func (pq PriorityQueue) Swap(i, j int) {
  pq[i], pq[j] = pq[j], pq[i]
}
func (pq *PriorityQueue) Pop() interface{} {
  old := *pq
  n := len(old)
  item := old[n - 1]
  *pq = old[0:n - 1]
  return item
}
func (pq *PriorityQueue) Push(x interface{}) {
  item := x.(*Item)
  *pq = append(*pq, item)
}

type Node struct {
  Index int
  Degree int
  Outbound int
  Edge []int
}
func Node2Item(N Node, f func(Node) int) *Item {
  I := Item{f(N), N.Index}
  return &I
}
func Eval1(N Node) int {
  return len(N.Edge)
}
func Eval2(N Node) int {
  return len(N.Edge) * p + N.Degree
}
const p = 1000000
func Solve(N int, E *[][]int, f func(Node) int) []int {
  G := make([]Node, N)
  for i := range G {
    e := make([]int, 0)
    G[i] = Node{i, 0, 0, e}
  }
  for i, e := range (*E) {
    A, B := e[0], e[1]
    G[A].Edge = append(G[A].Edge, i)
    G[A].Degree++
    G[B].Edge = append(G[B].Edge, i)
    G[B].Degree++
  }
  var PQ PriorityQueue
  for _, node := range G {
    heap.Push(&PQ, Node2Item(node, f))
  }
  for len(PQ) > 0 {
    s := heap.Pop(&PQ).(*Item).Index
    if len(G[s].Edge) == 0 { continue }
    deg := ((G[s].Outbound + len(G[s].Edge)) / 2) * 2
    for _, e := range G[s].Edge {
      t := (*E)[e][0]
      if t == s { t = (*E)[e][1] }
      if G[s].Outbound < deg {
        G[s].Outbound++
        (*E)[e] = []int{s, t}
      } else {
        G[t].Outbound++
        (*E)[e] = []int{t, s}
      }
      j := Search(&G[t].Edge, e)
      G[t].Edge = append(G[t].Edge[:j], G[t].Edge[j + 1:]...)
      heap.Push(&PQ, Node2Item(G[t], f))
    }
    G[s].Edge = make([]int, 0)
  }
  D := make([]int, N)
  for _, e := range (*E) {
    D[e[0]]++
  }
  return D
}

func Search(A *[]int, a int) int {
  N := len((*A))
  if (*A)[0] == a { return 0 }
  if (*A)[N - 1] == a { return N - 1 }
  high, low := N - 1, 0
  for high - low > 1 {
    med := (high + low) / 2
    if (*A)[med] == a { return med }
    if a < (*A)[med] {
      high = med
    } else {
      low = med
    }
  }
  return -1
}

func main() {
  NM := NextIntVec()
  N, M := NM[0], NM[1]
  E := make([][]int, M)
  for i := range E {
    AB := NextIntVec()
    A, B := AB[0] - 1, AB[1] - 1
    E[i] = []int{A, B}
  }
  D := Solve(N, &E, Eval1)
  undirectable := false
  directable := true
  for _, d := range D {
    if d % 2 > 0 {
      undirectable = true
      break
    }
  }
  if undirectable {
    D := Solve(N, &E, Eval2)
    for _, d := range D {
      if d % 2 > 0 {
        directable = false
        break
      }
    }
  }
  if directable {
    for i, e := range E {
      E[i] = []int{e[0] + 1, e[1] + 1}
      WriteIntVec(&E[i])
    }
  } else {
    Write(-1)
  }
  Output()
}

Measured memory_bytes: 27776